Repository: matortheeternal/smash Branch: master Commit: 60c8b34bced6 Files: 708 Total size: 17.0 MB Directory structure: gitextract_wihtrx14/ ├── .gitignore ├── ESPs/ │ ├── SmashTestPlugin01.esp │ ├── SmashTestPlugin02.esp │ └── SmashTestPlugin03.esp ├── LICENSE.txt ├── README.md ├── design/ │ ├── code snippets/ │ │ ├── GetMasterElement.pas │ │ ├── Mator Smash v0.9.pas │ │ └── better build algorithm.pas │ ├── diagrams/ │ │ └── Mator Smash.vpp │ └── notes/ │ ├── algorithm problems.txt │ ├── handling.txt │ ├── high level design.txt │ ├── linking explanation.txt │ └── todos 1024.txt ├── frontend/ │ ├── MatorSmash.dpr │ ├── MatorSmash.dproj │ ├── MatorSmash.mes │ ├── MatorSmash.res │ ├── ModelSupport_MatorSmash/ │ │ ├── MatorSmash/ │ │ │ └── default.txvpck │ │ ├── default.txvpck │ │ ├── msEditForm/ │ │ │ └── default.txvpck │ │ ├── msFrontend/ │ │ │ └── default.txvpck │ │ ├── msOptionsForm/ │ │ │ └── default.txvpck │ │ ├── msProfileForm/ │ │ │ └── default.txvpck │ │ ├── msProfilePanel/ │ │ │ └── default.txvpck │ │ ├── msSmashForm/ │ │ │ └── default.txvpck │ │ ├── msSplashForm/ │ │ │ └── default.txvpck │ │ └── msThreads/ │ │ └── default.txvpck │ ├── lang/ │ │ └── english.lang │ ├── msAlgorithm.pas │ ├── msChoicePanel.pas │ ├── msConfiguration.pas │ ├── msConflict.pas │ ├── msConflictForm.dfm │ ├── msConflictForm.pas │ ├── msCore.pas │ ├── msEditForm.dfm │ ├── msEditForm.pas │ ├── msLoader.pas │ ├── msOptionsForm.dfm │ ├── msOptionsForm.pas │ ├── msPluginSelectionForm.dfm │ ├── msPluginSelectionForm.pas │ ├── msPriorityForm.dfm │ ├── msPriorityForm.pas │ ├── msProfileForm.dfm │ ├── msProfileForm.pas │ ├── msProfilePanel.pas │ ├── msSettingsManager.dfm │ ├── msSettingsManager.pas │ ├── msSmash.pas │ ├── msSmashForm.dfm │ ├── msSmashForm.pas │ ├── msSplashForm.dfm │ ├── msSplashForm.pas │ ├── msTagHelper.dfm │ ├── msTagHelper.pas │ ├── msTagManager.dfm │ ├── msTagManager.pas │ ├── msThreads.pas │ ├── settings/ │ │ ├── Fallout3/ │ │ │ └── Smash.All.json │ │ ├── Fallout4/ │ │ │ └── Smash.All.json │ │ ├── FalloutNV/ │ │ │ └── Smash.All.json │ │ ├── Oblivion/ │ │ │ ├── Bash.Actors.ACBS.json │ │ │ ├── Bash.Actors.AIData.json │ │ │ ├── Bash.Actors.AIPackages.json │ │ │ ├── Bash.Actors.Animations.json │ │ │ ├── Bash.Actors.CombatStyle.json │ │ │ ├── Bash.Actors.DeathItem.json │ │ │ ├── Bash.Actors.Skeleton.json │ │ │ ├── Bash.Actors.Spells.json │ │ │ ├── Bash.Actors.Stats.json │ │ │ ├── Bash.Body-F.json │ │ │ ├── Bash.Body-M.json │ │ │ ├── Bash.Body-Size-F.json │ │ │ ├── Bash.Body-Size-M.json │ │ │ ├── Bash.C.Climate.json │ │ │ ├── Bash.C.Light.json │ │ │ ├── Bash.C.Music.json │ │ │ ├── Bash.C.Name.json │ │ │ ├── Bash.C.Owner.json │ │ │ ├── Bash.C.RecordFlags.json │ │ │ ├── Bash.C.Water.json │ │ │ ├── Bash.Creatures.Blood.json │ │ │ ├── Bash.Eyes.json │ │ │ ├── Bash.Factions.json │ │ │ ├── Bash.Graphics.json │ │ │ ├── Bash.Hair.json │ │ │ ├── Bash.Invent.json │ │ │ ├── Bash.Lev.json │ │ │ ├── Bash.NPC.Class.json │ │ │ ├── Bash.NPC.Race.json │ │ │ ├── Bash.Names.json │ │ │ ├── Bash.Npc.EyesOnly.json │ │ │ ├── Bash.Npc.HairOnly.json │ │ │ ├── Bash.NpcFaces.json │ │ │ ├── Bash.NpcFacesForceFullImport.json │ │ │ ├── Bash.R.AddSpells.json │ │ │ ├── Bash.R.Attributes-F.json │ │ │ ├── Bash.R.Attributes-M.json │ │ │ ├── Bash.R.ChangeSpells.json │ │ │ ├── Bash.R.Description.json │ │ │ ├── Bash.Relations.json │ │ │ ├── Bash.Scripts.json │ │ │ ├── Bash.Sound.json │ │ │ ├── Bash.SpellStats.json │ │ │ ├── Bash.Stats.json │ │ │ ├── Bash.Voice-F.json │ │ │ ├── Bash.Voice-M.json │ │ │ └── Smash.All.json │ │ └── Skyrim/ │ │ ├── Bash.Actors.ACBS.json │ │ ├── Bash.Actors.AIData.json │ │ ├── Bash.Actors.AIPackages.json │ │ ├── Bash.Actors.AIPackagesMerge.json │ │ ├── Bash.Actors.CombatStyle.json │ │ ├── Bash.Actors.DeathItem.json │ │ ├── Bash.Actors.Spells.json │ │ ├── Bash.Actors.SpellsMerge.json │ │ ├── Bash.Actors.Stats.json │ │ ├── Bash.All.json │ │ ├── Bash.Body-F.json │ │ ├── Bash.Body-M.json │ │ ├── Bash.Body-Size-F.json │ │ ├── Bash.Body-Size-M.json │ │ ├── Bash.C.Acoustic.json │ │ ├── Bash.C.Climate.json │ │ ├── Bash.C.Encounter.json │ │ ├── Bash.C.ImageSpace.json │ │ ├── Bash.C.Light.json │ │ ├── Bash.C.Location.json │ │ ├── Bash.C.Music.json │ │ ├── Bash.C.Name.json │ │ ├── Bash.C.Owner.json │ │ ├── Bash.C.RecordFlags.json │ │ ├── Bash.C.Regions.json │ │ ├── Bash.C.Water.json │ │ ├── Bash.Delev.json │ │ ├── Bash.Eyes.json │ │ ├── Bash.Factions.json │ │ ├── Bash.Graphics.json │ │ ├── Bash.Hairs.json │ │ ├── Bash.Invent.json │ │ ├── Bash.Lev.json │ │ ├── Bash.NPC.Class.json │ │ ├── Bash.NPC.Race.json │ │ ├── Bash.Names.json │ │ ├── Bash.NpcFaces.json │ │ ├── Bash.NpcFacesForceFullImport.json │ │ ├── Bash.R.AddSpells.json │ │ ├── Bash.R.ChangeSpells.json │ │ ├── Bash.R.Description.json │ │ ├── Bash.R.Head.json │ │ ├── Bash.R.Skills.json │ │ ├── Bash.Relations.json │ │ ├── Bash.Relev.json │ │ ├── Bash.Scripts.json │ │ ├── Bash.Sound.json │ │ ├── Bash.SpellStats.json │ │ ├── Bash.Stats.json │ │ ├── Bash.Voice-F.json │ │ ├── Bash.Voice-M.json │ │ ├── Skip.json │ │ ├── Smash.All.json │ │ ├── Smash.ForceAll.json │ │ └── Smash.OverrideAll.json │ ├── smash.rc │ └── smash.res └── lib/ ├── Imaging/ │ ├── Imaging.pas │ ├── ImagingBitmap.pas │ ├── ImagingCanvases.pas │ ├── ImagingClasses.pas │ ├── ImagingColors.pas │ ├── ImagingComponents.pas │ ├── ImagingDds.pas │ ├── ImagingFormats.pas │ ├── ImagingIO.pas │ ├── ImagingNetworkGraphics.pas │ ├── ImagingOptions.inc │ ├── ImagingTarga.pas │ ├── ImagingTypes.pas │ ├── ImagingUtility.pas │ └── ZLib/ │ ├── dzlib.pas │ ├── imadler.pas │ ├── iminfblock.pas │ ├── iminfcodes.pas │ ├── iminffast.pas │ ├── iminftrees.pas │ ├── iminfutil.pas │ ├── impaszlib.pas │ ├── imtrees.pas │ ├── imzconf.inc │ ├── imzdeflate.pas │ ├── imzinflate.pas │ ├── imzutil.pas │ └── readme.txt ├── abbrevia/ │ ├── MPL-1_1.txt │ ├── Readme.html │ ├── WavPack License.txt │ ├── examples/ │ │ └── Delphi/ │ │ ├── Abbrexam.dpr │ │ ├── BaseDlgu.pas │ │ ├── Basedlgu.dfm │ │ ├── CabExt.dpr │ │ ├── CabExt1.dfm │ │ ├── CabExt1.pas │ │ ├── CabFind.dpr │ │ ├── CabFind1.dfm │ │ ├── CabFind1.pas │ │ ├── CabView.dpr │ │ ├── CabView1.dfm │ │ ├── CabView1.pas │ │ ├── ComCtrlsDemo.dpr │ │ ├── ComCtrlsMain.dfm │ │ ├── ComCtrlsMain.pas │ │ ├── CompPad.dpr │ │ ├── Contents.dpr │ │ ├── Demo.cab │ │ ├── ExCBrows.dpr │ │ ├── ExCBrowu.dfm │ │ ├── ExCBrowu.pas │ │ ├── ExCf.dpr │ │ ├── ExCf.res │ │ ├── ExFilter.dpr │ │ ├── ExFiltru.dfm │ │ ├── ExFiltru.pas │ │ ├── ExZipper.dpr │ │ ├── ExZippru.dfm │ │ ├── ExZippru.pas │ │ ├── FCITest1.dfm │ │ ├── FCITest1.pas │ │ ├── Finder.dpr │ │ ├── MakeCab.dpr │ │ ├── MakeCab1.dfm │ │ ├── MakeCab1.pas │ │ ├── SelfStbv.dpr │ │ ├── SelfStub.dpr │ │ ├── SlfStbv1.dfm │ │ ├── SlfStbv1.pas │ │ ├── Streams.dpr │ │ ├── Streams1.dfm │ │ ├── Streams1.pas │ │ ├── StrmBmp.dpr │ │ ├── StrmBmpU.dfm │ │ ├── StrmBmpU.pas │ │ ├── StrmPad.dpr │ │ ├── TpZip.RC │ │ ├── TpZip.dpr │ │ ├── TpZip.r32 │ │ ├── TpZip31.HLP │ │ ├── UContent.dfm │ │ ├── UContent.pas │ │ ├── UMain.dfm │ │ ├── UMain.pas │ │ ├── Uexample.dfm │ │ ├── Uexample.pas │ │ ├── Unzip.dpr │ │ ├── Unzip.dproj │ │ ├── Unzip.dproj.2007 │ │ ├── UsingApi.dpr │ │ ├── Ustrpad.dfm │ │ ├── Ustrpad.pas │ │ ├── Uunzip.dfm │ │ ├── Uunzip.pas │ │ ├── Uzip.dfm │ │ ├── Uzip.pas │ │ ├── ZipReg.dpr │ │ ├── ZipReg.dproj │ │ ├── ZipReg.dproj.2007 │ │ ├── ZipReg1.dfm │ │ ├── ZipReg1.pas │ │ ├── ZipView.dpr │ │ ├── ZipView1.dfm │ │ ├── ZipView1.pas │ │ ├── Zipper.dpr │ │ ├── Zipper.dproj │ │ ├── Zipper.dproj.2007 │ │ ├── dgAbout.dfm │ │ ├── dgAbout.pas │ │ ├── makesfx.dpr │ │ ├── spntst0.dfm │ │ ├── spntst0.pas │ │ ├── uCfGenDg.dfm │ │ ├── uCfGenDg.pas │ │ ├── uCfMain.dfm │ │ ├── uCfMain.pas │ │ ├── uCfNewDg.dfm │ │ ├── uCfNewDg.pas │ │ ├── ubasedlg.dfm │ │ ├── ubasedlg.pas │ │ ├── ucomppad.dfm │ │ ├── ucomppad.pas │ │ ├── udemodlg.dfm │ │ ├── udemodlg.pas │ │ ├── ufinder.dfm │ │ ├── ufinder.pas │ │ ├── umakesfx.dfm │ │ ├── umakesfx.pas │ │ ├── usplash.dfm │ │ └── usplash.pas │ ├── localization/ │ │ ├── AbResString.pas.afr │ │ ├── AbResString.pas.de │ │ ├── AbResString.pas.fr │ │ ├── AbResString.pas.nl │ │ ├── AbResString.pas.ru │ │ └── AbResString.pas.tr │ ├── packages/ │ │ ├── Delphi XE/ │ │ │ ├── Abbrevia.dpk │ │ │ ├── Abbrevia.dproj │ │ │ ├── Abbrevia.res │ │ │ ├── AbbreviaVCL.dpk │ │ │ ├── AbbreviaVCL.dproj │ │ │ ├── AbbreviaVCL.res │ │ │ ├── AbbreviaVCLDesign.dpk │ │ │ ├── AbbreviaVCLDesign.dproj │ │ │ └── AbbreviaVCLDesign.res │ │ └── Delphi XE.groupproj │ └── source/ │ ├── AbArcTyp.pas │ ├── AbBase.pas │ ├── AbBitBkt.pas │ ├── AbBrowse.pas │ ├── AbBseCLX.pas │ ├── AbBseVCL.pas │ ├── AbBzip2.pas │ ├── AbBzip2Typ.pas │ ├── AbCBrows.pas │ ├── AbCView.pas │ ├── AbCabExt.pas │ ├── AbCabKit.pas │ ├── AbCabMak.pas │ ├── AbCabTyp.pas │ ├── AbCharset.pas │ ├── AbComCtrls.pas │ ├── AbComCtrls.res │ ├── AbCompnd.pas │ ├── AbConst.pas │ ├── AbCrtl.pas │ ├── AbDefine.inc │ ├── AbDfBase.pas │ ├── AbDfCryS.pas │ ├── AbDfDec.pas │ ├── AbDfEnc.pas │ ├── AbDfHufD.pas │ ├── AbDfInW.pas │ ├── AbDfOutW.pas │ ├── AbDfPkMg.pas │ ├── AbDfStrm.pas │ ├── AbDfXlat.pas │ ├── AbDlgDir.dfm │ ├── AbDlgDir.pas │ ├── AbDlgPwd.dfm │ ├── AbDlgPwd.pas │ ├── AbExcept.pas │ ├── AbFciFdi.pas │ ├── AbGzTyp.pas │ ├── AbHexVw.pas │ ├── AbLZMA.pas │ ├── AbLZMAStream.pas │ ├── AbMeter.pas │ ├── AbPPMd.pas │ ├── AbPeCol.dfm │ ├── AbPeCol.pas │ ├── AbPeDir.pas │ ├── AbPeFn.pas │ ├── AbPePass.pas │ ├── AbPeVer.dfm │ ├── AbPeVer.pas │ ├── AbQCView.pas │ ├── AbQCmpnd.pas │ ├── AbQDgDir.pas │ ├── AbQDgDir.xfm │ ├── AbQDgPwd.pas │ ├── AbQDgPwd.xfm │ ├── AbQHexVw.pas │ ├── AbQMeter.pas │ ├── AbQPeCol.pas │ ├── AbQPeCol.xfm │ ├── AbQPeDir.pas │ ├── AbQPeFn.pas │ ├── AbQPePas.pas │ ├── AbQPeVer.pas │ ├── AbQPeVer.xfm │ ├── AbQView.pas │ ├── AbQZView.pas │ ├── AbQZpOut.pas │ ├── AbReg.pas │ ├── AbReg.res │ ├── AbRegClx.pas │ ├── AbRegLinux.pas │ ├── AbRegVcl.pas │ ├── AbResString.pas │ ├── AbSWStm.pas │ ├── AbSelfEx.pas │ ├── AbSpanSt.pas │ ├── AbTarTyp.pas │ ├── AbUnzOutStm.pas │ ├── AbUnzPrc.pas │ ├── AbUnzper.pas │ ├── AbUtils.pas │ ├── AbVMStrm.pas │ ├── AbView.pas │ ├── AbWavPack.pas │ ├── AbZBrows.pas │ ├── AbZLTyp.pas │ ├── AbZView.pas │ ├── AbZipExt.pas │ ├── AbZipKit.pas │ ├── AbZipOut.pas │ ├── AbZipOut.res │ ├── AbZipPrc.pas │ ├── AbZipTyp.pas │ ├── AbZipper.pas │ ├── COM/ │ │ ├── Abbrevia.dpr │ │ ├── Abbrevia.dproj │ │ ├── Abbrevia.res │ │ ├── Abbrevia.ridl │ │ ├── Abbrevia.tlb │ │ ├── Abbrevia_TLB.pas │ │ ├── Readme.txt │ │ ├── _GZipItem.pas │ │ ├── _TarItem.pas │ │ ├── _ZipItem.pas │ │ └── _ZipKit.pas │ ├── Win32/ │ │ ├── CarrylessRangeCoder.obj │ │ ├── LzFind.obj │ │ ├── LzFindMt.obj │ │ ├── LzmaDec.obj │ │ ├── LzmaEnc.obj │ │ ├── PPMdContext.obj │ │ ├── PPMdSubAllocatorVariantI.obj │ │ ├── PPMdVariantI.obj │ │ ├── Threads.obj │ │ ├── blocksort.obj │ │ ├── bzlib.obj │ │ ├── compress.obj │ │ ├── decompress.obj │ │ ├── huffman.obj │ │ ├── wv_bits.obj │ │ ├── wv_extra1.obj │ │ ├── wv_extra2.obj │ │ ├── wv_float.obj │ │ ├── wv_metadata.obj │ │ ├── wv_pack.obj │ │ ├── wv_tags.obj │ │ ├── wv_unpack.obj │ │ ├── wv_unpack3.obj │ │ ├── wv_words.obj │ │ └── wv_wputils.obj │ └── Win64/ │ ├── CarrylessRangeCoder.obj │ ├── LzFind.obj │ ├── LzFindMt.obj │ ├── LzmaDec.obj │ ├── LzmaEnc.obj │ ├── PPMdContext.obj │ ├── PPMdSubAllocatorVariantI.obj │ ├── PPMdVariantI.obj │ ├── Threads.obj │ ├── blocksort.obj │ ├── bzlib.obj │ ├── compress.obj │ ├── decompress.obj │ ├── huffman.obj │ ├── wv_bits.obj │ ├── wv_extra1.obj │ ├── wv_extra2.obj │ ├── wv_float.obj │ ├── wv_metadata.obj │ ├── wv_pack.obj │ ├── wv_tags.obj │ ├── wv_unpack.obj │ ├── wv_unpack3.obj │ ├── wv_words.obj │ └── wv_wputils.obj ├── mte/ │ ├── CRC32.pas │ ├── RttiIni.pas │ ├── RttiJson.pas │ ├── RttiTranslation.pas │ ├── W7Taskbar.pas │ ├── mteBase.pas │ ├── mteChangeLogForm.dfm │ ├── mteChangeLogForm.pas │ ├── mteHelpers.pas │ ├── mteLogger.pas │ ├── mteLogging.pas │ ├── mtePluginSelectionForm.dfm │ ├── mtePluginSelectionForm.pas │ ├── mteProgressForm.dfm │ ├── mteProgressForm.pas │ ├── mteTaskHandler.pas │ └── mteTracker.pas ├── superobject/ │ └── superobject.pas ├── xedit/ │ ├── lz4/ │ │ ├── lz4.pas │ │ ├── lz4Common.pas │ │ ├── lz4HC.pas │ │ ├── lz4frame.pas │ │ ├── lz4frame_static.pas │ │ ├── lz4io.pas │ │ └── xxHash.pas │ ├── wbBSA.pas │ ├── wbDefines.inc │ ├── wbDefinitionsFNV.pas │ ├── wbDefinitionsFO3.pas │ ├── wbDefinitionsFO4.pas │ ├── wbDefinitionsTES3.pas │ ├── wbDefinitionsTES4.pas │ ├── wbDefinitionsTES5.pas │ ├── wbHelpers.pas │ ├── wbImplementation.pas │ ├── wbInit.pas │ ├── wbInterface.pas │ ├── wbLocalization.pas │ ├── wbSort.pas │ ├── wbStreams.pas │ └── zlib/ │ ├── ZLibEx.inc │ ├── ZLibExApi.pas │ ├── win32/ │ │ ├── adler32.obj │ │ ├── compress.obj │ │ ├── crc32.obj │ │ ├── deflate.obj │ │ ├── infback.obj │ │ ├── inffast.obj │ │ ├── inflate.obj │ │ ├── inftrees.obj │ │ └── trees.obj │ ├── win64/ │ │ ├── adler32.obj │ │ ├── compress.obj │ │ ├── crc32.obj │ │ ├── deflate.obj │ │ ├── infback.obj │ │ ├── inffast.obj │ │ ├── inflate.obj │ │ ├── inftrees.obj │ │ └── trees.obj │ └── zlibex.pas └── zeosdbo/ ├── doc/ │ └── html/ │ ├── bugreporting.html │ ├── buildingtests.html │ ├── changes.html │ ├── ede.css │ ├── installation.html │ ├── knownbugs.html │ ├── license.html │ ├── overview.html │ ├── parameters.html │ └── readme.html ├── packages/ │ └── DelphiXE/ │ ├── ZComponent.dpk │ ├── ZComponent.dproj │ ├── ZComponent.res │ ├── ZComponentDesign.dpk │ ├── ZComponentDesign.dproj │ ├── ZComponentDesign.res │ ├── ZCore.dpk │ ├── ZCore.dproj │ ├── ZCore.res │ ├── ZDbc.dpk │ ├── ZDbc.dproj │ ├── ZDbc.res │ ├── ZPackages.inc │ ├── ZParseSql.dpk │ ├── ZParseSql.dproj │ ├── ZParseSql.res │ ├── ZPlain.dpk │ ├── ZPlain.dproj │ ├── ZPlain.res │ ├── ZeosDbo.groupproj │ └── events good.txt └── src/ ├── Zeos.inc ├── ZeosLazarus.inc ├── component/ │ ├── ZAbstractConnection.pas │ ├── ZAbstractDataset.pas │ ├── ZAbstractRODataset.pas │ ├── ZAbstractTable.pas │ ├── ZComponent.dcr │ ├── ZComponent.inc │ ├── ZComponentReg.lrs │ ├── ZComponentReg.pas │ ├── ZConnection.pas │ ├── ZConnectionGroup.pas │ ├── ZDataset.pas │ ├── ZDatasetUtils.pas │ ├── ZGroupedConnection.pas │ ├── ZIBEventAlerter.pas │ ├── ZPgEventAlerter.pas │ ├── ZPropertyEditor.pas │ ├── ZQuerySQLEditor.pas │ ├── ZROSqlEditor.pas │ ├── ZSequence.pas │ ├── ZSqlMetadata.pas │ ├── ZSqlMonitor.pas │ ├── ZSqlProcessor.pas │ ├── ZSqlStrings.pas │ ├── ZSqlTestForm.pas │ ├── ZSqlUpdate.pas │ ├── ZStoredProcedure.pas │ ├── ZStreamBlob.pas │ ├── ZUpdateSqlEditor.dfm │ ├── ZUpdateSqlEditor.lfm │ ├── ZUpdateSqlEditor.lrs │ └── ZUpdateSqlEditor.pas ├── core/ │ ├── ZClasses.pas │ ├── ZCollections.pas │ ├── ZCompatibility.pas │ ├── ZCore.inc │ ├── ZEncoding.pas │ ├── ZExprParser.pas │ ├── ZExprToken.pas │ ├── ZExpression.pas │ ├── ZFunctions.pas │ ├── ZFunctionsConvert.pas │ ├── ZFunctionsDateTime.pas │ ├── ZFunctionsMath.pas │ ├── ZFunctionsOther.pas │ ├── ZFunctionsStrings.pas │ ├── ZMatchPattern.pas │ ├── ZMessages.pas │ ├── ZSysUtils.pas │ ├── ZTokenizer.pas │ ├── ZURL.pas │ ├── ZVariables.pas │ └── ZVariant.pas ├── dbc/ │ ├── ZDbc.inc │ ├── ZDbcASA.pas │ ├── ZDbcASAMetadata.pas │ ├── ZDbcASAResultSet.pas │ ├── ZDbcASAStatement.pas │ ├── ZDbcASAUtils.pas │ ├── ZDbcAdo.pas │ ├── ZDbcAdoMetadata.pas │ ├── ZDbcAdoResultSet.pas │ ├── ZDbcAdoStatement.pas │ ├── ZDbcAdoUtils.pas │ ├── ZDbcCache.pas │ ├── ZDbcCachedResultSet.pas │ ├── ZDbcConnection.pas │ ├── ZDbcDbLib.pas │ ├── ZDbcDbLibMetadata.pas │ ├── ZDbcDbLibResultSet.pas │ ├── ZDbcDbLibStatement.pas │ ├── ZDbcDbLibUtils.pas │ ├── ZDbcGenericResolver.pas │ ├── ZDbcInterbase6.pas │ ├── ZDbcInterbase6Metadata.pas │ ├── ZDbcInterbase6ResultSet.pas │ ├── ZDbcInterbase6Statement.pas │ ├── ZDbcInterbase6Utils.pas │ ├── ZDbcIntfs.pas │ ├── ZDbcLogging.pas │ ├── ZDbcMetadata.pas │ ├── ZDbcMySql.pas │ ├── ZDbcMySqlMetadata.pas │ ├── ZDbcMySqlResultSet.pas │ ├── ZDbcMySqlStatement.pas │ ├── ZDbcMySqlUtils.pas │ ├── ZDbcOracle.pas │ ├── ZDbcOracleMetadata.pas │ ├── ZDbcOracleResultSet.pas │ ├── ZDbcOracleStatement.pas │ ├── ZDbcOracleUtils.pas │ ├── ZDbcPooled.pas │ ├── ZDbcPostgreSql.pas │ ├── ZDbcPostgreSqlMetadata.pas │ ├── ZDbcPostgreSqlResultSet.pas │ ├── ZDbcPostgreSqlStatement.pas │ ├── ZDbcPostgreSqlUtils.pas │ ├── ZDbcResultSet.pas │ ├── ZDbcResultSetMetadata.pas │ ├── ZDbcSqLite.pas │ ├── ZDbcSqLiteMetadata.pas │ ├── ZDbcSqLiteResultSet.pas │ ├── ZDbcSqLiteStatement.pas │ ├── ZDbcSqLiteUtils.pas │ ├── ZDbcStatement.pas │ └── ZDbcUtils.pas ├── parsesql/ │ ├── ZAdoToken.pas │ ├── ZGenericSqlAnalyser.pas │ ├── ZGenericSqlToken.pas │ ├── ZInterbaseAnalyser.pas │ ├── ZInterbaseToken.pas │ ├── ZMySqlAnalyser.pas │ ├── ZMySqlToken.pas │ ├── ZOracleAnalyser.pas │ ├── ZOracleToken.pas │ ├── ZParseSql.inc │ ├── ZPostgreSqlAnalyser.pas │ ├── ZPostgreSqlToken.pas │ ├── ZScriptParser.pas │ ├── ZSelectSchema.pas │ ├── ZSqLiteAnalyser.pas │ ├── ZSqLiteToken.pas │ ├── ZSybaseAnalyser.pas │ └── ZSybaseToken.pas ├── plain/ │ ├── ZPlain.inc │ ├── ZPlainASAConstants.pas │ ├── ZPlainASADriver.pas │ ├── ZPlainAdo.pas │ ├── ZPlainAdoDriver.pas │ ├── ZPlainDbLibConstants.pas │ ├── ZPlainDbLibDriver.pas │ ├── ZPlainDriver.pas │ ├── ZPlainFirebirdDriver.pas │ ├── ZPlainFirebirdInterbaseConstants.pas │ ├── ZPlainLoader.pas │ ├── ZPlainMySqlConstants.pas │ ├── ZPlainMySqlDriver.pas │ ├── ZPlainOracleConstants.pas │ ├── ZPlainOracleDriver.pas │ ├── ZPlainPostgreSqlDriver.pas │ └── ZPlainSqLiteDriver.pas ├── repl.awk ├── repl.instructions └── repl.txt ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # Uncomment these types if you want even more clean repository. But be careful. # It can make harm to an existing project source. Read explanations below. # # Resource files are binaries containing manifest, project icon and version info. # They can not be viewed as text or compared by diff-tools. Consider replacing them with .rc files. #*.res # # Type library file (binary). In old Delphi versions it should be stored. # Since Delphi 2009 it is produced from .ridl file and can safely be ignored. #*.tlb # # Diagram Portfolio file. Used by the diagram editor up to Delphi 7. # Uncomment this if you are not using diagrams or use newer Delphi version. #*.ddp # # Visual LiveBindings file. Added in Delphi XE2. # Uncomment this if you are not using LiveBindings Designer. #*.vlb # # Deployment Manager configuration file for your project. Added in Delphi XE2. # Uncomment this if it is not mobile development and you do not use remote debug feature. #*.deployproj # # Delphi compiler-generated binaries (safe to delete) *.exe *.dll *.bpl *.bpi *.dcp *.so *.apk *.drc *.map *.dres *.rsm *.tds *.dcu *.lib # Delphi autogenerated files (duplicated info) *.cfg *Resource.rc # Delphi local files (user-specific info) *.local *.identcache *.projdata *.tvsconfig *.dsk # Delphi history and backups __history/ *.~* # Castalia statistics file *.stat # Repository ignore *.ini *.zip backend/logs/*.txt loc/ test/ frontend/__history/ frontend/logs/ frontend/patches/ *.txaPackage frontend/profiles/ ================================================ FILE: LICENSE.txt ================================================ MOZILLA PUBLIC LICENSE Version 1.1 --------------- 1. Definitions. 1.0.1. "Commercial Use" means distribution or otherwise making the Covered Code available to a third party. 1.1. "Contributor" means each entity that creates or contributes to the creation of Modifications. 1.2. "Contributor Version" means the combination of the Original Code, prior Modifications used by a Contributor, and the Modifications made by that particular Contributor. 1.3. "Covered Code" means the Original Code or Modifications or the combination of the Original Code and Modifications, in each case including portions thereof. 1.4. "Electronic Distribution Mechanism" means a mechanism generally accepted in the software development community for the electronic transfer of data. 1.5. "Executable" means Covered Code in any form other than Source Code. 1.6. "Initial Developer" means the individual or entity identified as the Initial Developer in the Source Code notice required by Exhibit A. 1.7. "Larger Work" means a work which combines Covered Code or portions thereof with code not governed by the terms of this License. 1.8. "License" means this document. 1.8.1. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently acquired, any and all of the rights conveyed herein. 1.9. "Modifications" means any addition to or deletion from the substance or structure of either the Original Code or any previous Modifications. When Covered Code is released as a series of files, a Modification is: A. Any addition to or deletion from the contents of a file containing Original Code or previous Modifications. B. Any new file that contains any part of the Original Code or previous Modifications. 1.10. "Original Code" means Source Code of computer software code which is described in the Source Code notice required by Exhibit A as Original Code, and which, at the time of its release under this License is not already Covered Code governed by this License. 1.10.1. "Patent Claims" means any patent claim(s), now owned or hereafter acquired, including without limitation, method, process, and apparatus claims, in any patent Licensable by grantor. 1.11. "Source Code" means the preferred form of the Covered Code for making modifications to it, including all modules it contains, plus any associated interface definition files, scripts used to control compilation and installation of an Executable, or source code differential comparisons against either the Original Code or another well known, available Covered Code of the Contributor's choice. The Source Code can be in a compressed or archival form, provided the appropriate decompression or de-archiving software is widely available for no charge. 1.12. "You" (or "Your") means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License or a future version of this License issued under Section 6.1. For legal entities, "You" includes any entity which controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. Source Code License. 2.1. The Initial Developer Grant. The Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license, subject to third party intellectual property claims: (a) under intellectual property rights (other than patent or trademark) Licensable by Initial Developer to use, reproduce, modify, display, perform, sublicense and distribute the Original Code (or portions thereof) with or without Modifications, and/or as part of a Larger Work; and (b) under Patents Claims infringed by the making, using or selling of Original Code, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Code (or portions thereof). (c) the licenses granted in this Section 2.1(a) and (b) are effective on the date Initial Developer first distributes Original Code under the terms of this License. (d) Notwithstanding Section 2.1(b) above, no patent license is granted: 1) for code that You delete from the Original Code; 2) separate from the Original Code; or 3) for infringements caused by: i) the modification of the Original Code or ii) the combination of the Original Code with other software or devices. 2.2. Contributor Grant. Subject to third party intellectual property claims, each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license (a) under intellectual property rights (other than patent or trademark) Licensable by Contributor, to use, reproduce, modify, display, perform, sublicense and distribute the Modifications created by such Contributor (or portions thereof) either on an unmodified basis, with other Modifications, as Covered Code and/or as part of a Larger Work; and (b) under Patent Claims infringed by the making, using, or selling of Modifications made by that Contributor either alone and/or in combination with its Contributor Version (or portions of such combination), to make, use, sell, offer for sale, have made, and/or otherwise dispose of: 1) Modifications made by that Contributor (or portions thereof); and 2) the combination of Modifications made by that Contributor with its Contributor Version (or portions of such combination). (c) the licenses granted in Sections 2.2(a) and 2.2(b) are effective on the date Contributor first makes Commercial Use of the Covered Code. (d) Notwithstanding Section 2.2(b) above, no patent license is granted: 1) for any code that Contributor has deleted from the Contributor Version; 2) separate from the Contributor Version; 3) for infringements caused by: i) third party modifications of Contributor Version or ii) the combination of Modifications made by that Contributor with other software (except as part of the Contributor Version) or other devices; or 4) under Patent Claims infringed by Covered Code in the absence of Modifications made by that Contributor. 3. Distribution Obligations. 3.1. Application of License. The Modifications which You create or to which You contribute are governed by the terms of this License, including without limitation Section 2.2. The Source Code version of Covered Code may be distributed only under the terms of this License or a future version of this License released under Section 6.1, and You must include a copy of this License with every copy of the Source Code You distribute. You may not offer or impose any terms on any Source Code version that alters or restricts the applicable version of this License or the recipients' rights hereunder. However, You may include an additional document offering the additional rights described in Section 3.5. 3.2. Availability of Source Code. Any Modification which You create or to which You contribute must be made available in Source Code form under the terms of this License either on the same media as an Executable version or via an accepted Electronic Distribution Mechanism to anyone to whom you made an Executable version available; and if made available via Electronic Distribution Mechanism, must remain available for at least twelve (12) months after the date it initially became available, or at least six (6) months after a subsequent version of that particular Modification has been made available to such recipients. You are responsible for ensuring that the Source Code version remains available even if the Electronic Distribution Mechanism is maintained by a third party. 3.3. Description of Modifications. You must cause all Covered Code to which You contribute to contain a file documenting the changes You made to create that Covered Code and the date of any change. You must include a prominent statement that the Modification is derived, directly or indirectly, from Original Code provided by the Initial Developer and including the name of the Initial Developer in (a) the Source Code, and (b) in any notice in an Executable version or related documentation in which You describe the origin or ownership of the Covered Code. 3.4. Intellectual Property Matters (a) Third Party Claims. If Contributor has knowledge that a license under a third party's intellectual property rights is required to exercise the rights granted by such Contributor under Sections 2.1 or 2.2, Contributor must include a text file with the Source Code distribution titled "LEGAL" which describes the claim and the party making the claim in sufficient detail that a recipient will know whom to contact. If Contributor obtains such knowledge after the Modification is made available as described in Section 3.2, Contributor shall promptly modify the LEGAL file in all copies Contributor makes available thereafter and shall take other steps (such as notifying appropriate mailing lists or newsgroups) reasonably calculated to inform those who received the Covered Code that new knowledge has been obtained. (b) Contributor APIs. If Contributor's Modifications include an application programming interface and Contributor has knowledge of patent licenses which are reasonably necessary to implement that API, Contributor must also include this information in the LEGAL file. (c) Representations. Contributor represents that, except as disclosed pursuant to Section 3.4(a) above, Contributor believes that Contributor's Modifications are Contributor's original creation(s) and/or Contributor has sufficient rights to grant the rights conveyed by this License. 3.5. Required Notices. You must duplicate the notice in Exhibit A in each file of the Source Code. If it is not possible to put such notice in a particular Source Code file due to its structure, then You must include such notice in a location (such as a relevant directory) where a user would be likely to look for such a notice. If You created one or more Modification(s) You may add your name as a Contributor to the notice described in Exhibit A. You must also duplicate this License in any documentation for the Source Code where You describe recipients' rights or ownership rights relating to Covered Code. You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Code. However, You may do so only on Your own behalf, and not on behalf of the Initial Developer or any Contributor. You must make it absolutely clear than any such warranty, support, indemnity or liability obligation is offered by You alone, and You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of warranty, support, indemnity or liability terms You offer. 3.6. Distribution of Executable Versions. You may distribute Covered Code in Executable form only if the requirements of Section 3.1-3.5 have been met for that Covered Code, and if You include a notice stating that the Source Code version of the Covered Code is available under the terms of this License, including a description of how and where You have fulfilled the obligations of Section 3.2. The notice must be conspicuously included in any notice in an Executable version, related documentation or collateral in which You describe recipients' rights relating to the Covered Code. You may distribute the Executable version of Covered Code or ownership rights under a license of Your choice, which may contain terms different from this License, provided that You are in compliance with the terms of this License and that the license for the Executable version does not attempt to limit or alter the recipient's rights in the Source Code version from the rights set forth in this License. If You distribute the Executable version under a different license You must make it absolutely clear that any terms which differ from this License are offered by You alone, not by the Initial Developer or any Contributor. You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of any such terms You offer. 3.7. Larger Works. You may create a Larger Work by combining Covered Code with other code not governed by the terms of this License and distribute the Larger Work as a single product. In such a case, You must make sure the requirements of this License are fulfilled for the Covered Code. 4. Inability to Comply Due to Statute or Regulation. If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Code due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be included in the LEGAL file described in Section 3.4 and must be included with all distributions of the Source Code. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Application of this License. This License applies to code to which the Initial Developer has attached the notice in Exhibit A and to related Covered Code. 6. Versions of the License. 6.1. New Versions. Netscape Communications Corporation ("Netscape") may publish revised and/or new versions of the License from time to time. Each version will be given a distinguishing version number. 6.2. Effect of New Versions. Once Covered Code has been published under a particular version of the License, You may always continue to use it under the terms of that version. You may also choose to use such Covered Code under the terms of any subsequent version of the License published by Netscape. No one other than Netscape has the right to modify the terms applicable to Covered Code created under this License. 6.3. Derivative Works. If You create or use a modified version of this License (which you may only do in order to apply it to code which is not already Covered Code governed by this License), You must (a) rename Your license so that the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape", "MPL", "NPL" or any confusingly similar phrase do not appear in your license (except to note that your license differs from this License) and (b) otherwise make it clear that Your version of the license contains terms which differ from the Mozilla Public License and Netscape Public License. (Filling in the name of the Initial Developer, Original Code or Contributor in the notice described in Exhibit A shall not of themselves be deemed to be modifications of this License.) 7. DISCLAIMER OF WARRANTY. COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. 8. TERMINATION. 8.1. This License and the rights granted hereunder will terminate automatically if You fail to comply with terms herein and fail to cure such breach within 30 days of becoming aware of the breach. All sublicenses to the Covered Code which are properly granted shall survive any termination of this License. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive. 8.2. If You initiate litigation by asserting a patent infringement claim (excluding declatory judgment actions) against Initial Developer or a Contributor (the Initial Developer or Contributor against whom You file such action is referred to as "Participant") alleging that: (a) such Participant's Contributor Version directly or indirectly infringes any patent, then any and all rights granted by such Participant to You under Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice from Participant terminate prospectively, unless if within 60 days after receipt of notice You either: (i) agree in writing to pay Participant a mutually agreeable reasonable royalty for Your past and future use of Modifications made by such Participant, or (ii) withdraw Your litigation claim with respect to the Contributor Version against such Participant. If within 60 days of notice, a reasonable royalty and payment arrangement are not mutually agreed upon in writing by the parties or the litigation claim is not withdrawn, the rights granted by Participant to You under Sections 2.1 and/or 2.2 automatically terminate at the expiration of the 60 day notice period specified above. (b) any software, hardware, or device, other than such Participant's Contributor Version, directly or indirectly infringes any patent, then any rights granted to You by such Participant under Sections 2.1(b) and 2.2(b) are revoked effective as of the date You first made, used, sold, distributed, or had made, Modifications made by that Participant. 8.3. If You assert a patent infringement claim against Participant alleging that such Participant's Contributor Version directly or indirectly infringes any patent where such claim is resolved (such as by license or settlement) prior to the initiation of patent infringement litigation, then the reasonable value of the licenses granted by such Participant under Sections 2.1 or 2.2 shall be taken into account in determining the amount or value of any payment or license. 8.4. In the event of termination under Sections 8.1 or 8.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or any distributor hereunder prior to termination shall survive termination. 9. LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. 10. U.S. GOVERNMENT END USERS. The Covered Code is a "commercial item," as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer software" and "commercial computer software documentation," as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government End Users acquire Covered Code with only those rights set forth herein. 11. MISCELLANEOUS. This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. This License shall be governed by California law provisions (except to the extent applicable law, if any, provides otherwise), excluding its conflict-of-law provisions. With respect to disputes in which at least one party is a citizen of, or an entity chartered or registered to do business in the United States of America, any litigation relating to this License shall be subject to the jurisdiction of the Federal Courts of the Northern District of California, with venue lying in Santa Clara County, California, with the losing party responsible for costs, including without limitation, court costs and reasonable attorneys' fees and expenses. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not apply to this License. 12. RESPONSIBILITY FOR CLAIMS. As between Initial Developer and the Contributors, each party is responsible for claims and damages arising, directly or indirectly, out of its utilization of rights under this License and You agree to work with Initial Developer and Contributors to distribute such responsibility on an equitable basis. Nothing herein is intended or shall be deemed to constitute any admission of liability. 13. MULTIPLE-LICENSED CODE. Initial Developer may designate portions of the Covered Code as "Multiple-Licensed". "Multiple-Licensed" means that the Initial Developer permits you to utilize portions of the Covered Code under Your choice of the NPL or the alternative licenses, if any, specified by the Initial Developer in the file described in Exhibit A. EXHIBIT A -Mozilla Public License. ``The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. The Original Code is ______________________________________. The Initial Developer of the Original Code is ________________________. Portions created by ______________________ are Copyright (C) ______ _______________________. All Rights Reserved. Contributor(s): ______________________________________. Alternatively, the contents of this file may be used under the terms of the _____ license (the "[___] License"), in which case the provisions of [______] License are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of the [____] License and not to allow others to use your version of this file under the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the [___] License. If you do not delete the provisions above, a recipient may use your version of this file under either the MPL or the [___] License." [NOTE: The text of this Exhibit A may differ slightly from the text of the notices in the Source Code files of the Original Code. You should use the text of this Exhibit A rather than the text found in the Original Code Source Code for Your Modifications.] ================================================ FILE: README.md ================================================ # smash A tool for performing automatic conflict resolution between multiple Bethesda Plugin Files for TES and Fallout games. ## explanation Characters, items, quests, music tracks, leveled lists, weathers, magical effects, etc. are all represented in plugin files as records. When multiple mods modify the same records, only the last loaded mod's changes get used by the game (with some exceptions). This is known as the rule of one. Many plugin patches combine the changes of multiple mods to resolve conflicts, but there is no way to create and distribute patches for every possible combination of conflicting mods. This is where tools like Mator Smash come in. Mator Smash allows for conflict resolution patches to be generated following rules, known as "Smash Settings". This allows users to quickly and efficiently combine the edits of multiple mods. ## intended usage Use Mator Smash to generate a patch, then verify the changes in the patch in xEdit. Fix any conflicts that were not resolved correctly. Smashed patches should be usable without a manual verification step, but can in certain rare cases lead to crashes/unintended behavior in game. If you run into issues please report them [here](https://github.com/matortheeternal/smash/issues). You can safely disable or delete your smashed patch at any time. # resources If you're looking for support or want to contribute, join the [Modding Tools discord server](https://discord.gg/GUfRdpT). You can find additional information and discussion on the [Nexus Mods](https://www.nexusmods.com/skyrim/mods/90987) mod page, in the [STEP forum topic](http://forum.step-project.com/topic/6936-wip-mator-smash/), and in the [Nexus Mods forum topic](https://forums.nexusmods.com/index.php?/topic/3707015-wip-mator-smash-the-conflict-resolution-revolution/). ================================================ FILE: design/code snippets/GetMasterElement.pas ================================================ {for j := 0 to ElementCount(ae) - 1 do begin ne := ebi(ae, j); if (SortKey(ne, false) = sk) then begin Result := ne; break; end; end;} {for j := 0 to ElementCount(ae) - 1 do begin ne := ebi(ae, j); if (gav(ne) = sk) then begin Result := ne; break; end; end;} function ElementByKey(e: IwbElement; key: string; bUseSortKey: boolean): IwbElement; var i: Integer; c: IwbContainerElementRef; begin if not Supports(e, IwbContainerElementRef, c) then exit; // loop through children elements for i := 0 to Pred(c.ElementCount) do begin element := c.Elements[i]; // get sort key if bUseSortKey, else get values key if bUseSortKey then eKey := element.SortKey[false] else eKey := GetAllValues(element); // if keys match result is current element if eKey = key then begin Result := element; break; end; end; end; function GetMasterElement(src, se: IwbElement; dstRec: IwbMainRecord): IwbElement; var i: integer; path, key: string; mstRec, ovr: IwbMainRecord; mst: IwbElement; sorted: boolean; begin Result := nil; mstRec := MasterOrSelf(dstRec); path := IndexedPath(src); bSorted := IsSorted(src); // if sorted, use SortKey, else use GetAllValues if bSorted then key := se.SortKey[false] else key := GetAllValues(se); // debug message if debugGetMaster then Tracker.Write(' Called GetMasterElement at path '+p+' looking for Key '+key); // loop from override 0 to the second to last override // last override is in our patch, we don't want to process that one for i := 0 to mstRec.OverrideCount - 2 do begin ovr := mst.Overrides[i]; mst := ElementByIndexedPath[(mstRec, p); Result := ElementByKey(mst, key, bSorted); // break if we found a subrecord matching the sortkey if Result <> nil then break; end; end; ================================================ FILE: design/code snippets/Mator Smash v0.9.pas ================================================ { Mator Smash v0.9.6 created by matortheeternal * DESCRIPTION * This script will make a patch similar to a bashed patch. } unit smash; uses mteFunctions; const vs = 'v0.9.6'; settingsPath = scriptsPath + 'smash\settings\'; dashes = '-----------------------------------------------------------'; // these booleans control logging debugGetMaster = false; debugArrays = false; listOverrides = false; showChanges = false; showTraversal = false; showSkips = false; showTypeStrings = false; showRecTimes = false; verbose = false; disableStyles = false; // maximum records to be smashed maxRecords = 100000; splitChar = '#13'; var slRecords, slSettings, slOptions, slFiles, slSubrecords, slGlobalSubrecords, recordTree, subrecordTree, include: TStringList; lstSettings: TList; userFile: IInterface; global_records, global_subrecords, global_recordMode, global_subrecordMode, global_setting: string; makeNewLine: boolean; AssetPath: string; checkboxImages: TCustomImageList; {===========================================================} { SETTING FORM } const cChecked = 1; cUnChecked = 2; cPartiallyChecked = 3; var sfrm: TForm; meInclude, meSubrecords: TMemo; tv: TTreeView; btnOk, btnCancel: TButton; { SetChildren Sets the StateIndex attribute of all the children of @node to @state. Uses recursion. } procedure SetChildren(node: TTreeNode; state: Integer); var tmp: TTreeNode; begin // exit if we don't have a node to work with if not Assigned(node) then exit; // loop through children setting StateIndex to state // if child has children, recurse into that child tmp := node.getFirstChild; while Assigned(tmp) do begin tmp.StateIndex := state; if tmp.HasChildren then SetChildren(tmp, state); tmp := tmp.getNextSibling; end; end; { UpdateParent Calculates and sets the StateIndex attribute for @node based on the StateIndex values of its children. Uses recursion to update parents of the parent that was updated. } procedure UpdateParent(node: TTreeNode); var tmp: TTreeNode; state: Integer; begin // exit if we don't have a node to work with if not Assigned(node) then exit; // parent state is checked if all siblings are checked state := cChecked; tmp := node.getFirstChild; while Assigned(tmp) do begin if tmp.StateIndex <> cChecked then begin state := cPartiallyChecked; break; end; tmp := tmp.getNextSibling; end; // parent state is unchecked if all siblings are unchecked if state = cPartiallyChecked then begin state := cUnChecked; tmp := node.getFirstChild; while Assigned(tmp) do begin if tmp.StateIndex <> cUnChecked then begin state := cPartiallyChecked; break; end; tmp := tmp.getNextSibling; end; end; // set state, recurse to next parent node.StateIndex := state; tmp := node.Parent; UpdateParent(tmp); end; { CheckBoxManager Manages checkboxes in the TTreeView. Changes the StateIndex of the checkbox associated with @node. Uses SetChildren and UpdateParent. Called by tvClick and tvKeyDown. } procedure CheckBoxManager(node: TTreeNode); begin // exit if we don't have a node to work with if not Assigned(node) then exit; // if unchecked or partially checked, set to checked and // set all children to checked, update parents if (node.StateIndex = cUnChecked) or (node.StateIndex = cPartiallyChecked) then begin node.StateIndex := cChecked; UpdateParent(node.Parent); SetChildren(node, cChecked); end // if checked, set to unchecked and set all children to // unchecked, update parents else if node.StateIndex = cChecked then begin node.StateIndex := cUnChecked; UpdateParent(node.Parent); SetChildren(node, cUnChecked); end; end; { tvClick Event handler for when the user clicks anywhere in the TreeView. If the user clicks on a checkbox it calls CheckBoxManager to toggle the state of the selected checkbox. } procedure tvClick(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var HT: THitTests; begin HT := tv.GetHitTestInfoAt(X, Y); if (HT - [htOnStateIcon] <> HT) then CheckBoxManager(tv.Selected); end; { tvKeyDown Event handler for when the user presses a key while the TreeView is focused. If the user presses space we call CheckBoxManager to toggle the state of the selected checkbox. } procedure tvKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if (Key = VK_SPACE) and Assigned(tv.Selected) then CheckBoxManager(tv.Selected); end; { tvExpanding Event handler for when the user expands a node in the TreeView. If we haven't loaded the subrecords for the record represented by @node, we call LoadNodes. } procedure tvExpanding(Sender: TObject; node: TTreeNode; var AllowExpansion: Boolean); var i: integer; begin if not Assigned(node.getFirstChild) then exit; // if we haven't loaded subrecord data yet, attempt to // load it from the subrecord stringlist if node.getFirstChild.Text = 'Elements' then begin // find record signature in subrecords stringlist // exit if not found i := subrecordTree.IndexOf(node.Text); if i = -1 then exit; // load nodes from the subrecords stringlist // starting at the first subrecord LoadNodes(subrecordTree, tv, node, i + 1, 2); // delete 'Elements' placeholder node node.getFirstChild.Delete; end; end; { LeadingSpaces Calculates the number of leading spaces in a PChar string and returns it as an integer. } function LeadingSpaces(var s: PChar): integer; var i: integer; begin Result := 0; i := 1; while (true) do begin if s[i] = ' ' then Inc(Result) else exit; Inc(i); end; end; { LoadNodes Loads nodes from @sl into @tv as children of @node. Starts at index @i in the stringlist and adds children which have leading spaces matching @cws. If there are more leading spaces than @cws, we use recursion to add the list item as a child of the current list item @curNode. If there are fewer leading spaces than @cws we exit. } procedure LoadNodes(var sl: TStringList; tv: TTreeView; node: TTreeNode; var i: integer; cws: integer); var lws: integer; p: PChar; curNode: TTreeNode; begin curNode := node; while (true) do begin // exit if we reached the end of the stringlist if i > sl.Count - 1 then exit; p := sl[i]; lws := LeadingSpaces(p); // if lws matches cws, add as child of current node // (we're on the right level) if lws = cws then begin curNode := tv.Items.AddChild(node, Trim(sl[i])); curNode.StateIndex := node.StateIndex; end // if leading spaces of the current item exceeds cws, // recurse to add as child of the last added node // (we need to go down a level) else if lws > cws then begin LoadNodes(sl, tv, curNode, i, lws); continue; end // if cws exceeds lws, exit // (we need to go up a level) else exit; // go to next item in list Inc(i); end; end; { FindNode Finds a node matching @s as a child of @node. } function FindNode(node: TTreeNode; const s: string): TTreeNode; var tmp: TTreeNode; begin Result := nil; tmp := node.getFirstChild; while (Assigned(tmp)) do begin if (tmp.Text = s) then begin Result := tmp; exit; end; tmp := tmp.getNextSibling; end; end; { DisableNodes Disables nodes from @sl in @tv found as children of @node. Starts at index @i in the stringlist and locates children which have leading spaces matching @cws. If there are more leading spaces than @cws, we use recursion to find the list item in the current item @curNode. If there are fewer leading spaces than @cws we exit. } procedure DisableNodes(var sl: TStringList; tv: TTreeView; node: TTreeNode; var i: integer; cws: integer); var lws: integer; p: PChar; curNode: TTreeNode; begin curNode := node; while (true) do begin // exit if we reached the end of the stringlist if i > sl.Count - 1 then exit; p := sl[i]; lws := LeadingSpaces(p); // if lws matches cws, find and disable if lws = cws then begin curNode := FindNode(node, Trim(sl[i])); if not Assigned(curNode) then begin Inc(i); continue; end; if i + 1 = sl.Count then begin curNode.StateIndex := cUnChecked; end else begin p := sl[i+1]; lws := LeadingSpaces(p); if lws > cws then begin tvExpanding(nil, curNode, true); curNode.StateIndex := cPartiallyChecked; end else begin curNode.StateIndex := cUnChecked; end; end; end // if leading spaces of the current item exceeds cws, // recurse to find in the last added node // (we need to go down a level) else if lws > cws then begin DisableNodes(sl, tv, curNode, i, lws); continue; end // if cws exceeds lws, exit // (we need to go up a level) else exit; // go to next item in list Inc(i); end; end; { MakeBold Changes the style of @lbl to bold. } procedure MakeBold(lbl: TLabel); begin if not disableStyles then begin lbl.WordWrap := false; lbl.Font.Style := lbl.Font.Style + [fsBold]; end; end; { SettingFormResize Event to fire when the setting form is resized } procedure SettingFormResize(Sender: TObject); begin tv.Width := sfrm.Width - 48; tv.Height := sfrm.Height - 155; btnOk.Top := sfrm.Height - 86; btnOk.Left := sfrm.Width div 2 - btnOk.Width - 8; btnCancel.Top := btnOk.Top; btnCancel.Left := btnOk.Left + btnOk.Width + 16; end; { CreateIncludeList Recursively traverses a TreeView starting at @node adding node text properties to @sl, with @depth concatenated before each text item. } procedure CreateIncludeList(var sl: TStringList; node: TTreeNode; depth: string); var tmp: TTreeNode; begin if (not node.HasChildren) then exit; tmp := node.getFirstChild; while (Assigned(tmp)) do begin if (tmp.StateIndex = cUnChecked) then sl.Add(depth + tmp.Text) else if (tmp.HasChildren) and (tmp.StateIndex = cPartiallyChecked) then begin sl.Add(depth + tmp.Text); CreateIncludeList(sl, tmp, depth + ' '); end; tmp := tmp.getNextSibling; end; end; { SettingForm Used to create or edit setting presets. } procedure SettingForm(Sender: TObject); var lblName, lblRecords, lblSubrecords: TLabel; edName: TEdit; ini, template: TMemIni; usingTemplate: boolean; caption: string; node: TTreeNode; ndx: integer; begin // assign template include := TStringList.Create; caption := TButton(Sender).Caption; usingTemplate := caption <> 'New setting'; if lst.ItemIndex > -1 then template := TMemIniFile(lstSettings[slSettings.IndexOf(lst.Items[lst.ItemIndex])]) else usingTemplate := false; sfrm := TForm.Create(nil); try // set up form sfrm.Width := 400; sfrm.Height := 600; sfrm.Position := poScreenCenter; sfrm.Caption := 'Create new Smash Setting'; sfrm.Constraints.MinHeight := 400; sfrm.Constraints.MinWidth := 286; // make label and edit for name lblName := cLabel(sfrm, sfrm, 16, 16, 0, 0, 'Name: ', ''); edName := cEdit(sfrm, sfrm, lblName.Top, lblName.Left + lblName.Width + 8, 0, 200, '', ''); // make tree view tv := TTreeView.Create(sfrm); tv.Parent := sfrm; tv.Left := lblName.Left; tv.Top := lblName.Top + lblName.Height + 20; tv.Width := sfrm.Width - 48; tv.Height := sfrm.Height - 155; tv.Indent := 19; tv.ReadOnly := true; tv.StateImages := checkboxImages; tv.OnMouseDown := tvClick; tv.OnKeyDown := tvKeyDown; tv.OnExpanding := tvExpanding; // construct ok and cancel buttons btnOk := TButton.Create(sfrm); btnOk.Parent := sfrm; btnOk.Left := sfrm.Width div 2 - btnOk.Width - 8; btnOk.Top := sfrm.Height - 86; btnOk.Caption := 'OK'; btnOk.ModalResult := mrOK; btnCancel := TButton.Create(sfrm); btnCancel.Parent := sfrm; btnCancel.Left := btnOk.Left + btnOk.Width + 16; btnCancel.Top := btnOk.Top; btnCancel.Caption := 'Cancel'; btnCancel.ModalResult := mrCancel; // load record nodes node := tv.Items.Add(nil, 'Records'); if usingTemplate then node.StateIndex := cChecked else node.StateIndex := cUnChecked; LoadNodes(recordTree, tv, node, 0, 0); // if using template, load values from it for form if usingTemplate then begin edName.Caption := template.ReadString('Setting', 'Name', ''); if caption = 'Copy setting' then begin sfrm.Caption := 'Copy Smash Setting'; edName.Caption := 'Copy of '+edName.Caption; end else if caption = 'Edit setting' then begin sfrm.Caption := 'Edit Smash Setting'; edName.Enabled := false; end; include.LoadFromFile(settingsPath + edName.Caption + '.ini'); ndx := include.IndexOf('[Tree]') + 1; if (ndx < include.Count) then begin if (include[ndx] <> '') then begin DisableNodes(include, tv, node, ndx, 0); node.StateIndex := cPartiallyChecked; end; end; end; // set onresize event sfrm.OnResize := SettingFormResize; // if user clicks ok, save to ini and update lists if sfrm.ShowModal = mrOk then begin ini := TMemIniFile.Create(settingsPath + edName.Caption + '.ini'); ini.WriteString('Setting', 'Name', edName.Caption); ini.UpdateFile; include.LoadFromFile(settingsPath + edName.Caption + '.ini'); ndx := include.IndexOf('[Tree]'); if (ndx = -1) then include.Add('[Tree]') else begin Inc(ndx); while (include.Count > ndx) do include.Delete(ndx); end; CreateIncludeList(include, node, ''); include.SaveToFile(settingsPath + edName.Caption + '.ini'); if (slSettings.IndexOf(edName.Caption) = -1) then begin lstSettings.Add(ini); slSettings.Add(edName.Caption); lst.Items.Add(edName.Caption); end else lstSettings[slSettings.IndexOf(edName.Caption)] := ini; end; finally sfrm.Free; end; end; {===========================================================} { SETTING MANAGER FORM } var btnDetails, btnEdit, btnCopy, btnDel: TButton; gear: TPicture; lst: TListBox; { ToggleButtons Toggles btnEdit, btnCopy, btnDelete. } procedure ToggleButtons(Sender: TObject); var b: boolean; begin b := (TListBox(Sender).ItemIndex > -1); btnEdit.Enabled := b; btnCopy.Enabled := b; btnDel.Enabled := b; end; { DeleteSetting Deletes the currently selected setting. } procedure DeleteSetting(Sender: TObject); var s: string; begin if lst.ItemIndex > -1 then begin s := lst.Items[lst.ItemIndex]; lstSettings.Delete(slSettings.IndexOf(s)); slSettings.Delete(slSettings.IndexOf(s)); lst.Items.Delete(lst.ItemIndex); lst.ItemIndex := -1; DeleteFile(settingsPath + s + '.ini'); end; end; { UpdateSettings Updates the setting comboboxes for OptionsForm } procedure UpdateSettings; var i, ndx: integer; cb: TComboBox; s: string; begin for i := 0 to pnlCount - 1 do begin cb := TComboBox(pnlArray[i].Components[1]); s := cb.Items[cb.ItemIndex]; cb.Items.Text := slSettings.Text; if cb.Items.IndexOf(s) > -1 then cb.ItemIndex := cb.Items.IndexOf(s) else cb.ItemIndex := 0; end; // update global setting combobox s := gscb.Items[gscb.ItemIndex]; gscb.Items.Text := slSettings.Text; if gscb.Items.IndexOf(s) > -1 then gscb.ItemIndex := gscb.Items.IndexOf(s) else gscb.ItemIndex := 0; end; { SettingManager Used by the user to view, edit, and create settings. } procedure SettingManager; var ofrm: TForm; i, h: integer; btnNew, btnOk : TButton; begin ofrm := TForm.Create(nil); try ofrm.Caption := 'Advanced Options'; ofrm.Width := 400; ofrm.Position := poScreenCenter; ofrm.Height := 300; h := slSettings.Count * 15 + 85; if h > 500 then h := 500; if h > ofrm.Height then ofrm.Height := h; // list box of settings lst := TListBox.Create(ofrm); lst.Parent := ofrm; lst.Top := 8; lst.Left := 8; lst.Height := ofrm.Height - 105; lst.Width := ofrm.Width - 145; for i := 0 to slSettings.Count - 1 do lst.Items.Add(slSettings[i]); lst.OnClick := ToggleButtons; // new setting button btnNew := cButton(ofrm, ofrm, 8, lst.Left + lst.Width + 8, 0, 100, 'New setting'); btnNew.OnClick := SettingForm; // edit setting button btnEdit := cButton(ofrm, ofrm, btnNew.Top + btnNew.Height + 8, btnNew.Left, 0, 100, 'Edit setting'); btnEdit.OnClick := SettingForm; btnEdit.Enabled := false; // copy setting button btnCopy := cButton(ofrm, ofrm, btnEdit.Top + btnEdit.Height + 8, btnNew.Left, 0, 100, 'Copy Setting'); btnCopy.OnClick := SettingForm; btnCopy.Enabled := false; // delete setting button btnDel := cButton(ofrm, ofrm, btnCopy.Top + btnCopy.Height + 8, btnNew.Left, 0, 100, 'Delete setting'); btnDel.OnClick := DeleteSetting; btnDel.Enabled := false; // OK button btnOk := cButton(ofrm, ofrm, ofrm.Height - 80, ofrm.Width div 2 - 40, 0, 0, 'OK'); btnOk.ModalResult := mrOk; ofrm.ShowModal; finally ofrm.free; end; UpdateSettings; end; {===========================================================} { PLUGIN DETAILS FORM } { GetGroupOverrides } function GetGroupOverrides(f: IInterface): string; var i: integer; e: IInterface; begin for i := 0 to ElementCount(f) - 1 do begin e := ebi(f, i); if Signature(e) = 'TES4' then continue; Result := Result + GroupSignature(e) + ': '+IntToStr(OverrideRecordCount(e))+' overrides'#13#10; end; end; { PluginDetails Form which shows advanced details on a plugin } procedure PluginDetails(Sender: TObject); var f, e: IInterface; i: integer; fn, author, records, overrides, desc, masters, groups: string; pfrm: TForm; lbl: TLabel; sb: TScrollBox; memo: TMemo; begin // find file fn := TLabel(Sender).Caption; fn := Copy(fn, Pos(']', fn) + 2, Length(fn)); f := FileByName(fn); // get data author := geev(ebi(f, 0), 'CNAM'); records := IntToStr(RecordCount(f)); overrides := IntToStr(OverrideRecordCount(f)); desc := geev(ebi(f, 0), 'SNAM'); e := ebn(ebi(f, 0), 'Master Files'); for i := 0 to ElementCount(e) - 1 do masters := masters + geev(ebi(e, i), 'MAST') + #13#10; groups := GetGroupOverrides(f); // display form pfrm := TForm.Create(nil); try pfrm.Caption := fn; pfrm.Width := 400; pfrm.Height := 600; pfrm.Position := poScreenCenter; lbl := cLabel(pfrm, pfrm, 8, 8, 0, 150, 'Filename:', ''); MakeBold(lbl); lbl := cLabel(pfrm, pfrm, lbl.Top, 160, 0, 200, fn, ''); lbl := cLabel(pfrm, pfrm, lbl.Top + 22, 8, 0, 150, 'Author:', ''); MakeBold(lbl); lbl := cLabel(pfrm, pfrm, lbl.Top, 160, 0, 200, author, ''); lbl := cLabel(pfrm, pfrm, lbl.Top + 22, 8, 0, 150, 'Number of records:', ''); MakeBold(lbl); lbl := cLabel(pfrm, pfrm, lbl.Top, 160, 0, 200, records, ''); lbl := cLabel(pfrm, pfrm, lbl.Top + 22, 8, 0, 150, 'Number of overrides:', ''); MakeBold(lbl); lbl := cLabel(pfrm, pfrm, lbl.Top, 160, 0, 200, overrides, ''); lbl := cLabel(pfrm, pfrm, lbl.Top + 22, 8, 0, 150, 'Description:', ''); MakeBold(lbl); memo := cMemo(pfrm, pfrm, lbl.Top + 22, 16, 100, 348, true, true, ssVertical, desc); lbl := cLabel(pfrm, pfrm, memo.Top + memo.Height + 16, 8, 0, 150, 'Masters:', ''); MakeBold(lbl); memo := cMemo(pfrm, pfrm, lbl.Top + 22, 16, 100, 348, true, true, ssVertical, masters); lbl := cLabel(pfrm, pfrm, memo.Top + memo.Height + 16, 8, 0, 150, 'Record groups:', ''); MakeBold(lbl); memo := cMemo(pfrm, pfrm, lbl.Top + 22, 16, 150, 348, true, true, ssVertical, groups); pfrm.ShowModal; finally pfrm.Free; end; end; {===========================================================} { OPTIONS FORM } var frm: TForm; gscb: TComboBox; pnlArray: Array[0..255] of TPanel; pnlCount: integer; { OptionsForm Form from which the user can access the setting manager, plugin details, and set the settings to be used when smashing the loaded plugins. } function OptionsForm: boolean; var i, height, m: integer; btnSmash, btnCancel: TButton; optionslbl, fnlbl, gslbl: TLabel; cb: TComboBox; f: IInterface; fn, author, s: string; imgOptions: TImage; pnl: TPanel; holder: TObject; sb: TScrollBar; begin Result := false; frm := TForm.Create(nil); try frm.Caption := 'Mator Smash Options'; frm.Width := 550; frm.Position := poScreenCenter; frm.Height := 400; for i := 0 to FileCount - 1 do begin f := FileByIndex(i); fn := GetFileName(f); author := geev(ebi(f, 0), 'CNAM'); if (Pos(fn, bethesdaFiles) > 0) or (Pos('Mator Smash', author) > 0) then Continue; Inc(m); end; height := m*40 + 170; if height > (Screen.Height - 100) then begin frm.Height := Screen.Height - 100; sb := TScrollBox.Create(frm); sb.Parent := frm; sb.Height := Screen.Height - 210; sb.Width := frm.Width - 20; sb.Align := alTop; holder := sb; end else begin frm.Height := height; holder := frm; end; optionslbl := cLabel(frm, holder, 8, 8, 0, 450, 'Set the options you want to use for smashing the following plugins:', ''); pnlCount := 0; for i := 0 to FileCount - 1 do begin f := FileByIndex(i); fn := GetFileName(f); author := geev(ebi(f, 0), 'CNAM'); if Pos(fn, bethesdaFiles) > 0 then continue; if Pos('Mator Smash', author) > 0 then continue; pnlArray[pnlCount] := TPanel.Create(frm); pnlArray[pnlCount].Parent := holder; pnlArray[pnlCount].Left := 0; pnlArray[pnlCount].Top := 30 + pnlCount*40; pnlArray[pnlCount].Width := holder.Width - 25; pnlArray[pnlCount].BevelOuter := bvNone; pnlArray[pnlCount].BevelInner := bvNone; // or bvLowered pnlArray[pnlCount].BorderStyle := bsNone; // or bsSingle fnlbl := cLabel(pnlArray[pnlCount], pnlArray[pnlCount], 14, 24, 0, 0, '['+IntToHex(i - 1, 2)+'] '+fn, ''); fnlbl.OnClick := PluginDetails; MakeBold(fnlbl); cb := TComboBox.Create(pnlArray[pnlCount]); cb.Parent := pnlArray[pnlCount]; cb.Style := csDropDownList; cb.Items := slSettings; cb.ItemIndex := 0; if slSettings.IndexOf('default') > -1 then cb.ItemIndex := slSettings.IndexOf('default'); cb.Top := 12; cb.Width := 150; cb.Left := holder.Width - cb.Width - 40; slFiles.Add(fn); Inc(pnlCount); end; // create global setting controls gslbl := cLabel(frm, holder, pnlArray[pnlCount - 1].Top + pnlArray[pnlCount - 1].Height + 16, optionslbl.Left, 0, 70, 'Global setting: ', ''); gscb := TComboBox.Create(frm); gscb.Parent := holder; gscb.Top := gslbl.Top; gscb.Left := gslbl.Left + gslbl.Width + 16; gscb.Width := 150; gscb.Style := csDropDownList; gscb.Items := slSettings; gscb.ItemIndex := 0; if slSettings.IndexOf('default') > -1 then gscb.ItemIndex := slSettings.IndexOf('default'); pnl := TPanel.Create(frm); pnl.Parent := frm; pnl.BevelOuter := bvNone; pnl.Align := alBottom; pnl.Height := 50; imgOptions := cImage(pnl, pnl, pnl.Height - 40, frm.Width - 50, 24, 24, gear, 'Advanced Options'); imgOptions.OnClick := SettingManager; // create ok/cancel buttons btnSmash := cButton(frm, pnl, pnl.Height - 40, frm.Width div 2 - 88, 0, 0, 'Smash!'); btnSmash.ModalResult := mrOk; btnCancel := cButton(frm, pnl, btnSmash.Top, btnSmash.Left + btnSmash.Width + 16, 0, 0, 'Cancel'); btnCancel.ModalResult := mrCancel; if frm.ShowModal = mrOk then begin for i := 0 to pnlCount - 1 do begin s := TComboBox(pnlArray[i].Components[1]).Text; slOptions.Add(s); end; global_setting := gscb.Text; Result := true; end; finally frm.Free; end; end; {===========================================================} { SMASHING METHODS } var pb: TProgressBar; memo: TMemo; lbl: TLabel; { LogMessage Adds @msg to the log stringlist } procedure LogMessage(msg: string); begin memo.Lines.add(msg); Application.processmessages; end; { GetMasterElement Gets the first instance of an element (the master) } function GetMasterElement(src, se, dstrec: IInterface): IInterface; var i, j, ndx: integer; p, sk: string; ovr, ae, ne, mst: IInterface; sorted: boolean; begin Result := nil; mst := MasterOrSelf(dstrec); p := IndexedPath(src); sk := SortKey(se, false); sorted := not (sk = ''); // if sorted, look for an element matching sort key if sorted then begin if debugGetMaster then LogMessage(' Called GetMasterElement at path '+p+' looking for SortKey '+SortKey(se, false)); // loop from override 0 to the second to last override for i := 0 to OverrideCount(mst) - 2 do begin ovr := OverrideByIndex(mst, i); ae := ebp(mst, p); for j := 0 to ElementCount(ae) - 1 do begin ne := ebi(ae, j); if (SortKey(ne, false) = sk) then begin Result := ne; break; end; end; // break if we found a subrecord matching the sortkey if Result <> nil then break; end; end // if unsorted, look for the element using gav else begin sk := gav(se); if debugGetMaster then LogMessage(' Called GetMasterElement at path '+p+' looking for '+sk); ae := ebp(mst, p); for i := 0 to OverrideCount(mst) - 1 do begin ovr := OverrideByIndex(mst, i); ae := ebp(ovr, p); for j := 0 to ElementCount(ae) - 1 do begin ne := ebi(ae, j); if (gav(ne) = sk) then begin Result := ne; break; end; end; end; end; end; { nbsOverrideCount Non-Bethesda Override Count } function nbsOverrideCount(r: IInterface): integer; var i: integer; fn: string; begin Result := 0; for i := 0 to OverrideCount(r) - 1 do begin fn := GetFileName(GetFile(OverrideByIndex(r, i))); if Pos(fn, bethesdaFiles) = 0 then Result := Result + 1; end; end; { BuildSortKeyList Puts the sort keys of elements in a stringlist } procedure BuildSortKeyList(element: IInterface; var sl: TStringList); var i, n: integer; childElement: IInterface; sk, skAdj: string; begin for i := 0 to ElementCount(element) - 1 do begin childElement := ebi(element, i); sk := SortKey(childElement, false); skAdj := sk; n := 0; while sl.IndexOf(skAdj) > -1 do begin Inc(n); skAdj := sk + '-' + IntTostr(n); end; if debugArrays and (n > 0) then LogMessage(' Adjusted SortKey: '+skAdj); sl.Add(skAdj); end; end; { MergeSortedArray Merges sorted array elements } procedure MergeSortedArray(mst, src, dst, dstrec: IInterface; depth: string; ini: TMemIniFile); var i, m_ndx, s_ndx, d_ndx, n: integer; me, se, de, ne: IInterface; slMst, slDst, slSrc: TStringList; useValues: boolean; dts, ets, sk: string; begin // Step 1: build lists of elements in each array for easy comparison slMst := TStringList.Create; slSrc := TStringList.Create; slDst := TStringList.Create; slDst.Sorted := true; BuildSortKeyList(mst, slMst); BuildSortKeyList(src, slSrc); BuildSortKeyList(dst, slDst); // Step 2: Remove elements that are in mst and dst, but missing from src for i := 0 to slMst.Count - 1 do begin s_ndx := slSrc.IndexOf(slMst[i]); d_ndx := slDst.IndexOf(slMst[i]); if (s_ndx = -1) and (d_ndx > -1) then begin if debugArrays then LogMessage(' > Removing element '+Path(ebi(dst, d_ndx))+' with key: '+slDst[d_ndx]); RemoveElement(dst, ebi(dst, d_ndx)); slDst.Delete(d_ndx); end; end; // Step 3: Copy array elements in src that aren't in mst. for i := 0 to slSrc.Count - 1 do begin d_ndx := slDst.IndexOf(slSrc[i]); m_ndx := slMst.IndexOf(slSrc[i]); se := ebi(src, i); dts := DefTypeString(se); ets := ElementTypeString(se); if (d_ndx = -1) and (m_ndx = -1) then begin if debugArrays then LogMessage(' > Adding element '+IntToStr(i)+' at '+Path(dst)+' with key: '+slSrc[i]); ne := ElementAssign(dst, HighInteger, se, false); if debugArrays then LogMessage(' > '+gav(ne)); slDst.Add(slSrc[i]); end // Step 3.5: If array element is in dst and has subelements, traverse it. else if (d_ndx > -1) and ((dts = 'dtStruct') or (ets = 'etSubRecordArray')) then begin if showTraversal then LogMessage(' > Traversing element '+Path(se)+' with key: '+slSrc[i]); if showTraversal and debugArrays then LogMessage(' > Source Element: '+gav(se)+ #13#10' > Destination Element: '+gav(ebi(dst, d_ndx))); try rcore(se, GetMasterElement(src, se, dstrec), ebi(dst, d_ndx), dstrec, depth + ' ', ini); except on x : Exception do begin LogMessage(' !! rcore exception: '+x.Message); end; end; end else if (d_ndx > -1) and (ets = 'etSubRecordStruct') then begin if showTraversal then LogMessage(' > Traversing element '+Path(se)+' with key: '+slSrc[i]); if showTraversal and debugArrays then LogMessage(' > Source Element: '+gav(se)+ #13#10' > Destination Element: '+gav(ebi(dst, d_ndx))); try rcore(se, GetMasterElement(src, se, dstrec), ebi(dst, d_ndx), dstrec, depth + ' ', ini); except on x : Exception do begin LogMessage(' !! rcore exception: '+x.Message); end; end; end; end; // Step 4: Free lists. slMst.Free; slSrc.Free; slDst.Free; end; { BuildElementList Puts the values of elements in a stringlist } procedure BuildElementList(element: IInterface; var sl: TStringList); var i, n: integer; childElement: IInterface; values, valuesAdj: string; begin for i := 0 to ElementCount(element) - 1 do begin childElement := ebi(element, i); values := gav(childElement); valuesAdj := values; n := 0; while (sl.IndexOf(valuesAdj) > -1) do begin Inc(n); valuesAdj := values + IntToStr(n); end; sl.Add(valuesAdj); end; end; { MergeUnsortedArray Merges unsorted array elements } procedure MergeUnsortedArray(mst, src, dst, dstrec: IInterface; depth: string; ini: TMemIniFile); var i, m_ndx, s_ndx, d_ndx: integer; me, se, de: IInterface; slMst, slSrc, slDst: TStringList; useValues: boolean; dts, ets: string; begin // Step 1: build lists of elements in each array for easy comparison slMst := TStringList.Create; slSrc := TStringList.Create; slDst := TStringList.Create; BuildElementList(mst, slMst); BuildElementList(src, slSrc); BuildElementList(dst, slDst); // Step 2: Remove elements that are in mst and dst, but missing from src for i := 0 to slMst.Count - 1 do begin s_ndx := slSrc.IndexOf(slMst[i]); d_ndx := slDst.IndexOf(slMst[i]); if (s_ndx = -1) and (d_ndx > -1) then begin if debugArrays then LogMessage(' > Removing element at '+Path(dst)+' with values: '+slMst[i]); RemoveElement(dst, d_ndx); slDst.Delete(d_ndx); end; end; // Step 3: Copy array elements in src that aren't in mst or dst for i := 0 to slSrc.Count - 1 do begin d_ndx := slDst.IndexOf(slSrc[i]); m_ndx := slMst.IndexOf(slSrc[i]); se := ebi(src, i); //if debugArrays then LogMessage('Looking to copy '+slSrc[i]); if (m_ndx = -1) and (d_ndx = -1) then begin if debugArrays then LogMessage(' > Adding element at '+Path(dst)+' with values: '+slSrc[i]); ElementAssign(dst, HighInteger, se, false); slDst.Add(slSrc[i]); end; end; // Step 4: Free lists. slMst.Free; slSrc.Free; slDst.Free; end; { ListHasMatch Check if a list has a matching subrecord } function ListHasMatch(var sl: TStringList; input: string): boolean; var i: integer; ex: string; begin Result := false; for i := 0 to sl.Count - 1 do begin ex := sl[i]; if (Pos('*', ex) > 0) then begin SetChar(ex, Pos('*', ex), ''); if (Pos(ex, input) > 0) then begin Result := true; exit; end; end else if (ex = input) then begin Result := true; exit; end; end; end; { SkipRecord Returns whether or not a record should be skipped } function SkipRecord(rec: IInterface; records, recordMode: string): boolean; var s: string; begin s := Signature(rec); Result := ((Pos(s, records) > 0) and (recordMode = '0')) or ((Pos(s, records) = 0) and (recordMode = '1')) or ((Pos(s, global_records) > 0) and (global_recordMode = '0')) or ((Pos(s, global_records) = 0) and (global_recordMode = '1')) end; { SkipSubrecord Check if a subrecord should be skipped } function SkipSubrecord(subrecord: IInterface; ini: TMemIniFile): boolean; var subrecords, subrecordMode, subrecordPath: string; match, globalMatch: boolean; begin // load subrecord settings subrecordMode := ini.ReadString('Setting', 'subrecordMode', '0'); // path string subrecordPath := Path(subrecord); // result boolean match := ListHasMatch(slSubrecords, subrecordPath); globalMatch := ListHasMatch(slGlobalSubrecords, subrecordPath); Result := ((subrecordMode = '0') and (match)) or ((subrecordMode = '1') and not (match)) or ((global_subrecordMode = '0') and (globalMatch)) or ((global_subrecordMode = '1') and not (globalMatch)); end; { AddElementsToList Adds children elements to a stringlist } procedure AddElementsToList(element: IInterface; var sl: TStringList); var i: integer; childElement: IInterface; begin for i := 0 to ElementCount(element) - 1 do begin childElement := ebi(element, i); sl.Add(Name(childElement)); end; end; { IsValueElement Checks if an element is a value element } function IsValueElement(elementType: string): boolean; begin Result := (elementType = 'dtInteger') or (elementType = 'dtFloat') or (elementType = 'dtUnion') or (elementType = 'dtByteArray') or (elementType = 'dtString') or (elementType = 'dtLString') or (elementType = 'dtLenString'); end; { rcore Recursively Copy Overridden Elements } procedure rcore(src, mst, dst, dstrec: IInterface; depth: string; ini: TMemIniFile); var i, j, k, max: integer; se, me, de, sse, mse, kse, kme, kde, xse: IInterface; mv, sv, ets, dts, cts, cas, ctsrc, subrecords, subrecordMode: string; diff: TRecordDiff; slDst, slMst: TStringList; skip: boolean; begin // initialize stringlists slDst := TStringList.Create; // list of destination elements slMst := TStringList.Create; // list of master elements // copy elements from source to destination if missing AddElementsToList(dst, slDst); AddElementsToList(mst, slMst); for i := 0 to ElementCount(src) - 1 do begin se := ebi(src, i); // if the element isn't in the destination record // and wasn't in the master record, copy it to the destination // if it isn't in the destination but is in the master it means // that it was deleted and shouldn't be copied. if (slDst.IndexOf(Name(se)) = -1) and (slMst.IndexOf(Name(se)) = -1) then wbCopyElementToRecord(se, dst, false, true); end; // loop through subelements i := 0; j := 0; while i < ElementCount(src) do begin // assign source, destination, master elements // ensure index out of bounds doesn't occur by not reassigning // past the last element if i < ElementCount(src) then se := ebi(src, i); if j < ElementCount(dst) then de := ebi(dst, j); me := ebn(mst, Name(se)); // DefType and ElementType strings ets := ElementTypeString(se); dts := DefTypeString(se); // skip record header, copy record flags if Name(se) = 'Record Header' then begin wbCopyElementToRecord(ebp(se, 'Record Flags'), dst, false, true); Inc(i); Inc(j); continue; end; // skip subrecordsToSkip skip := SkipSubrecord(se, ini); if skip then begin if showSkips then LogMessage(' Skipping '+Path(se)); Inc(i); Inc(j); continue; end; // debug messages if showTraversal then LogMessage(' '+Path(se)); if showTypeStrings then LogMessage(' ets: '+ets+' dts: '+dts); // if destination element doesn't match source element if (Name(se) <> Name(de)) then begin // if we're not at the end of the destination elements // proceed to next destination element // else proceed to next source element if (j < ElementCount(dst)) then Inc(j) else Inc(i); continue; end; // deal with subrecord arrays if (ets = 'etSubRecordArray') or (dts = 'dtArray') then begin // if sorted, deal with sorted array if IsSorted(se) then begin if debugArrays then LogMessage(' Sorted array found: '+Path(se)); try MergeSortedArray(me, se, de, dstrec, depth, ini); except on x : Exception do LogMessage(' !! MergeSortedArray exception: '+x.Message); end; end // else deal with unsorted etSubRecordArray else if (ets = 'etSubRecordArray') then begin if debugArrays then LogMessage(' Unsorted etSubRecordArray found: '+Path(se)); try MergeUnsortedArray(me, se, de, dstrec, depth, ini); except on x : Exception do LogMessage(' !! MergeUnsortedArray exception: '+x.Message); end; end // else deal with unsorted dtArray else begin if debugArrays then LogMessage(' Unsorted dtArray found: '+Path(se)); try MergeUnsortedArray(me, se, de, dstrec, depth, ini); //rcore(se, me, de, dstrec, depth + ' ', ini); except on x : Exception do LogMessage(' !! MergeUnsortedArray exception: '+x.Message); end; end; end // else recurse deeper else if (ElementCount(se) > 0) and (dts <> 'dtInteger') then begin try rcore(se, me, de, dstrec, depth + ' ', ini); except on x : Exception do LogMessage(' !! rcore exception in element '+Path(se)+': '+x.Message); end; end // else copy element if value differs from master else if IsValueElement(dts) and (GetEditValue(se) <> GetEditValue(me)) then begin if (Assigned(me)) and showChanges then begin if (not showTraversal) then LogMessage(' '+Path(se)); LogMessage(' > Found differing values: '+GetEditValue(se)+' and '+GetEditValue(me)); end; // try to copy element value to destination element from source element try SetEditValue(de, GetEditValue(se)); except on x : Exception do LogMessage(' !! Copy element value exception: '+x.Message); end; end; // proceed to next subelement Inc(i); Inc(j); end; slDst.Free; slMst.Free; end; { IsSmashedPatch Checks if @f is a smashed patch } function IsSmashedPatch(f: IInterface): boolean; var author: string; begin author := geev(ElementByIndex(f, 0), 'CNAM'); Result := (Pos('Mator Smash', author) = 1); end; { SmashRecord Smashes @rec into @smashFile. } procedure SmashRecord(rec, smashFile: IInterface); var i: integer; fn, author: string; f, ovr, mr: IInterface; ini: TMemIniFile; begin // loop through record's overrides for i := 0 to OverrideCount(rec) - 1 do begin ovr := OverrideByIndex(rec, i); f := GetFile(ovr); fn := GetFileName(f); // skip overrides in bethesda files if (Pos(fn, bethesdaFiles) > 0) then continue; // skip overrides in smashed patches if (IsSmashedPatch(f)) then continue; // skip ctIdenticalToMaster overrides if (ConflictThisForMainRecord(ovr) = ctIdenticalToMaster) then continue; // if master record is not assigned, copy winning override to smashed patch if (not Assigned(mr)) then begin try mr := wbCopyElementToFile(WinningOverride(ovr), smashFile, false, true); except on x: Exception do LogMessage(' !! Exception copying record '+Name(rec)+' : '+x.Message); end; end; // look up setting for this file try ini := TMemIniFile(lstSettings[slSettings.IndexOf(slOptions[slFiles.IndexOf(fn)])]); except on x : Exception do LogMessage('Setting lookup exception : '+x.Message); end; // recursively copy overriden elements try if makeNewLine then LogMessage(''); LogMessage('Smashing record '+Name(rec)+' from file: '+fn); slSubrecords.Text := StringReplace(ini.ReadString('Setting', 'subrecords', ''), '#13', #13, [rfReplaceAll]); rcore(ovr, rec, mr, mr, ' ', ini); except on x : Exception do LogMessage(' !! Exception smashing record '+Name(rec)+' : '+x.Message); end; end; end; {===========================================================} { MAIN EXECUTION } { ShowDetails Enables the visibilty of the TMemo log } procedure ShowDetails; begin frm.Height := 600; frm.Position := poScreenCenter; memo.Height := frm.Height - 150; btnDetails.Visible := false; memo.Visible := true; end; { InitializeSettings Loads settings from files } procedure InitializeSettings; var i: integer; ini: TMemIniFile; s: string; info: TSearchRec; begin // create lists slSettings := TStringList.Create; lstSettings := TList.Create; // load settings SetCurrentDir(settingsPath); if FindFirst(settingsPath+'*.ini', faAnyFile, info) = 0 then begin repeat lstSettings.Add(TMemIniFile.Create(settingsPath + info.Name)); until FindNext(info) <> 0; end; // add setting strings for i := 0 to lstSettings.Count - 1 do begin s := TMemIniFile(lstSettings[i]).ReadString('Setting', 'Name', ''); slSettings.Add(s); end; end; { FreeMemory Frees memory used by script } procedure FreeMemory; begin gear.Free; slOptions.Free; slFiles.Free; slSettings.Free; lstSettings.Free; end; { Initialize Load assets, settings, display forms, show progress bar, perform main smashing procedure. } function Initialize: integer; var f, r: IInterface; i, j, k: integer; fn, rn, records, recordMode, logFileName, fdt: string; ini: TMemIniFile; tStart, tRec: TDateTime; diff: double; pic: TPicture; bmpChecked, bmpUnChecked, bmpPChecked: TBitmap; begin // load tree stringlists AssetPath := ScriptsPath + 'smash\assets\'; recordTree := TStringList.Create; recordTree.LoadFromFile(AssetPath + 'RecordTree.txt'); subrecordTree := TStringList.Create; subrecordTree.LoadFromFile(AssetPath + 'SubrecordTree.txt'); include := TStringList.Create; // load checkbox images checkboxImages := TCustomImageList.Create(nil); pic := TPicture.Create; bmpChecked := TBitmap.Create; bmpUnChecked := TBitmap.Create; bmpPChecked := TBitmap.Create; pic.LoadFromFile(AssetPath + 'Check.bmp'); bmpChecked.SetSize(17, 17); bmpChecked.Canvas.Draw(0, 0, pic.Graphic); pic.LoadFromFile(AssetPath + 'UnCheck.bmp'); bmpUnChecked.SetSize(17, 17); bmpUnChecked.Canvas.Draw(0, 0, pic.Graphic); pic.LoadFromFile(AssetPath + 'PartialCheck.bmp'); bmpPChecked.SetSize(17, 17); bmpPChecked.Canvas.Draw(0, 0, pic.Graphic); checkboxImages.Add(bmpChecked, nil); checkboxImages.Add(bmpChecked, nil); checkboxImages.Add(bmpUnChecked, nil); checkboxImages.Add(bmpPChecked, nil); // track time tStart := Now; // stringlist creation slOptions := TStringList.Create; slFiles := TStringList.Create; slSubrecords := TStringList.Create; slGlobalSubrecords := TStringList.Create; makeNewLine := showSkips or showTraversal or debugGetMaster or debugArrays or showChanges or showTypeStrings or showRecTimes; // load gui elements gear := TPicture.Create; gear.LoadFromFile(AssetPath + 'gear.png'); // load setting files InitializeSettings; // set up for saving log ForceDirectories(ScriptsPath + '\smash\logs'); fdt := FormatDateTime('mmddyy_hhnnss', Now); logFileName := ScriptsPath + '\smash\logs\smash' + fdt + '.txt'; // initial options form if OptionsForm then begin frm := TForm.Create(nil); try frm.Caption := 'Mator Smash!'; frm.Width := 700; frm.Position := poScreenCenter; frm.Height := 150; // make progress label lbl := cLabel(frm, frm, 20, 20, 30, 600, 'Initializing...', ''); // make progress bar pb := TProgressBar.Create(frm); pb.Parent := frm; pb.Top := 40; pb.Left := 20; pb.Width := frm.Width - 55; pb.Height := 20; pb.Step := 1; pb.Min := 0; pb.Position := 0; // make log memo memo := cMemo(frm, frm, 70, 20, 0, pb.Width, false, true, ssBoth, ''); memo.Visible := false; // make details button btnDetails := cButton(frm, frm, pb.Top + pb.Height + 8, pb.Left, 0, 100, 'Show Details'); btnDetails.OnClick := ShowDetails; // display form, initial logging messages frm.Show; application.processmessages; LogMessage(dashes); LogMessage('Mator Smash '+vs+': Makes a smashed patch.'); LogMessage(dashes); // create stringlists slRecords := TStringList.Create; // load global settings ini := TMemIniFile(lstSettings[slSettings.IndexOf(global_setting)]); global_records := StringReplace(ini.ReadString('Setting', 'records', ''), splitChar, #13#10, [rfReplaceall]); global_recordMode := ini.ReadString('Setting', 'recordMode', '0'); global_subrecords := StringReplace(ini.ReadString('Setting', 'subrecords', ''), splitChar, #13#10, [rfReplaceall]); global_subrecordMode := ini.ReadString('Setting', 'subrecordMode', '0'); slGlobalSubrecords.Text := global_subrecords; // see if a smashed patch is loaded for i := 0 to FileCount - 1 do begin f := FileByIndex(i); // if smashed patch found, break if (IsSmashedPatch(f)) then begin userFile := f; break; end; end; // make userFile if not found lbl.Caption := 'Assigning smashed patch.'; application.processmessages; if not Assigned(userFile) then userFile := AddNewFile; if not Assigned(userFile) then begin LogMessage('Smashed patch not assigned, terminating script'); FreeMemory; frm.Free; Result := -1; exit; end; // set userFile author to Mator Smash lbl.Caption := 'Adding masters to smashed patch.'; application.processmessages; seev(ebi(userFile, 0), 'CNAM', 'Mator Smash '+vs); // add masters to userFile for i := 0 to FileCount - 3 do begin f := FileByLoadOrder(i); if (IsSmashedPatch(f)) then break; fn := GetFileName(f); AddMasterIfMissing(userFile, fn); end; // loop through all loaded files k := 0; tRec := Now; for i := 0 to FileCount - 1 do begin f := FileByIndex(i); fn := GetFileName(f); // skip bethesda files, we're not patching them if Pos(fn, bethesdaFiles) > 0 then continue; // if smashed patch found, break if (IsSmashedPatch(f)) then break; // build list of records with multiple overrides lbl.Caption := 'Processing '+fn; LogMessage('Processing '+fn); application.processmessages; // load ini settings ini := TMemIniFile(lstSettings[slSettings.IndexOf(slOptions[k])]); records := StringReplace(ini.ReadString('Setting', 'records', ''), splitChar, #13#10, [rfReplaceAll]); recordMode := ini.ReadString('Setting', 'recordMode', '0'); // loop through records for j := 0 to RecordCount(f) - 1 do begin r := MasterOrSelf(RecordByIndex(f, j)); if (OverrideCount(r) <= 1) then continue; // skip records according to ini settings if SkipRecord(r, records, recordMode) then continue; rn := Name(r); if (nbsOverrideCount(r) > 1) then if (ConflictThisForMainRecord(WinningOverride(r)) <> ctOverride) then if slRecords.IndexOf(rn) = -1 then begin slRecords.AddObject(rn, TObject(r)); end; end; Inc(k); end; diff := (Now - tRec) * 86400; LogMessage(FormatFloat('0.###', diff) + ' seconds spent processing records.'); // test list of records if listOverrides then begin LogMessage(''); for i := 0 to slRecords.Count - 1 do begin r := ObjectToElement(slRecords.Objects[i]); LogMessage(slRecords[i]+' ('+IntToStr(OverrideCount(r))+' overrides)'); for j := 0 to OverrideCount(r) - 1 do LogMessage(' Override #'+IntToStr(j)+': '+GetFileName(GetFile(OverrideByIndex(r, j)))); end; end; // smash records that have been overridden multiple times lbl.Caption := 'Smashing records (1/'+IntToStr(slRecords.Count)+')'; application.processmessages; pb.Max := slRecords.Count; LogMessage(''); for i := 0 to slRecords.Count - 1 do begin tRec := Now; if i = maxRecords then break; // smash record r := ObjectToElement(slRecords.Objects[i]); SmashRecord(r, userFile); // update label, print debug message to log after smashing record lbl.Caption := 'Smashing records ('+IntToStr(i + 2)+'/'+IntToStr(slRecords.Count)+')'; pb.Position := pb.Position + 1; if showRecTimes then begin diff := (Now - tRec) * 86400; LogMessage(' '+FormatFloat('0.###', diff) + 's'); end; application.processmessages; end; // sort and clean masters SortMasters(userFile); CleanMasters(userFile); // finishing messages lbl.Caption := 'All done.'; LogMessage(#13#10+dashes); LogMessage('Smashing complete. '+IntToStr(RecordCount(userfile))+' records smashed.'); diff := (Now - tStart) * 86400; LogMessage('Completed in ' + FormatFloat('0.###', diff) + ' seconds.'); memo.Lines.SaveToFile(logFileName); application.processmessages; if (memo.Visible) then begin frm.Visible := false; frm.ShowModal; end; except on x : Exception do begin // smash failed LogMessage(#13#10'Smash failed. Exception: '+x.Message); memo.Lines.SaveToFile(logFileName); pb.Position := 0; lbl.Caption := 'Smash Failed. Exception: '+x.Message; if not memo.Visible then ShowDetails; frm.Visible := false; frm.ShowModal; Application.processmessages; end; end; frm.Free; end; // free memory FreeMemory; // call RemoveFilter() to update TES5Edit GUI try RemoveFilter(); except on Exception do AddMessage(#13#10'You''re not using the latest version of xEdit, so the script couldn''t update the GUI.'); AddMessage('Right click in the plugin view and click "Remove Filter" to update the GUI manually.'); end; end; end. ================================================ FILE: design/code snippets/better build algorithm.pas ================================================ procedure LoadElementData(var sl: TStringList; container: IwbContainerElementRef); var innerContainer: IwbContainerElementRef; element: IwbElement; begin // loop through container's elements for i := 0 to Pred(container.ElementCount) do begin element := container.Elements[i]; //if bOverridesOnly and (ConflictThis(element) = ctIdenticalToMaster) then //continue; index := sl.IndexOf(element.Name); // create new element name item if missing if index = -1 then index := sl.Add(element.Name); // traverse children of element, if it has any if Supports(element, IwbContainerElementRef, innerContainer) then if innerContainer.ElementCount > 0 then begin if not Assigned(sl.Objects[index]) then sl.Objects[index] := TStringList.Create; LoadElementData(TStringList(sl.Objects[index]), innerContainer); end; end; end; procedure LoadRecordData(var sl: TStringList; f: IwbFile); var i, index: Integer; container: IwbContainerElementRef; rec: IwbMainRecord; begin // loop through file's records for i := 0 to Pred(f.RecordCount) do begin rec := f.Records[i]; // skip excluded signatures if HasSignature(rec.Signature, excludedSignatures) then continue; // skip non-override records if bOverridesOnly and not IsOverride(rec) then continue; index := sl.IndexOf(rec.Signature); // add new record signature item if missing if index = -1 then index := sl.AddObject(rec.Signature, TStringList.Create); if Supports(rec, IwbContainerElementRef, container) then LoadElementData(TStringList(sl.Objects[index]), container); end; end; procedure StringsToNodes(node: TTreeNode; var sl: TStringList); var child: TTreeNode; i: Integer; begin for i := 0 to Pred(sl.Count) do begin child := TreeView.Items.AddChild(node, sl[i]); child.Data := TElementData.Create(0, false, false, false); if Assigned(sl.Objects[i]) then StringsToNodes(child, TStringList(sl.Objects[i])); end; end; procedure TTreeThread.Execute; var i: Integer; plugin: TPlugin; begin // ? // BODY sl := TStringList.Create; sl.Sorted := true; for i := 0 to Pred(pluginsToHandle.Count) do begin plugin := TPlugin(pluginsToHandle[i]); LoadRecordData(sl, plugin._File); end; rootNode := TreeView.Items.Add(nil, 'Records'); StringsToNodes(rootNode, sl); //? end; function GetConflictThis(element: IwbElement): TConflictThis; var mainRecord, master, winning: IwbMainRecord; begin mainRecord := element.ContainingMainRecord; if mainRecord.ConflictPriority = cpIgnore then Result := ctIgnored else if mainRecord.OverrideCount = 0 then Result := ctOnlyOne else begin master := mainRecord.Master; winning := mainRecord.WinningOverride; masterElement := master.ElementByPath(element.Path); winningElement := winning.ElementByPath(element.Path); end; end; ================================================ FILE: design/notes/algorithm problems.txt ================================================ 1. Elements with the same name ================================================ FILE: design/notes/handling.txt ================================================ Things to handle: ignoring deletions, treat as single entity, priority, linking Ignoring deletions: When applied to an element, ignore deletions in any of its children elements. -- boolean set to rcore -- leads us to not call "delete elements if missing" -- passed to HandleArray Treat as single entity: When applied to an element, any change in that its children's values leads us to copy the entire element to replace the destination element. -- boolean set to rcore -- rcore made into a function that returns true whenever a change occurs -- rcore doesn't call CopyElementValue when a value is different, simply returning true instead -- HandleArray also made into a function that returns true whenever a change occurs -- Array handlers return true when they detect an element has been added/deleted/changed Priority: Overrides load order on a per-element basis. When priority for an element in a record in a file exceeds the priority of the same element in other files we use that element in destination record. (remove?) Linking: ================================================ FILE: design/notes/high level design.txt ================================================ Smash Q: Do we want profiles? A: Yes, because a user may have multiple load orders or games they want to use smash with. Q: Do we want a backend? A: Yes. We want to serve up smash settings, plugin action recommendations, and program updates. Q: What will be the main actions of the user within the program? A: Create a new smashed patch, view/edit smash settings, view a plugin's record makeup, adjust program settings, update the program, download new smash settings, view the help file, submit smash settings, submit plugin action recommendations, build smashed patches, delete smashed patches, rebuild smashed patches, ... Q: What attributes will a smashed patch have? A: Plugins, plugin, date built, name, filename, smash setting, status, hashes, fails, files. Q: What attributes with a smash setting have? A: A tree of records/subrecord options (process [boolean], treat as single entity [boolean], priority [byte], preserve deletions [boolean]), applicable plugin makeup (record group breakdown), hash, and a name. All smash settings will be inclusive. Q: What functionality will smash patch generation make use of? A: - Recursive traversal of records and subrecords - Record and subrecord skipping based on smash setting - Single-entity subrecord handling - Sorted array handling - Unsorted array handling - Record/subrecord priority - Record/subrecord preserve deletions option - Subrecord/record priority handling - Subrecord linking (possibly) Q: What information should we expose on plugins and their record makeup? A: What record groups are in the plugin. How many records are in each record group. The breakdown of new records/override records in the plugin. The breakdown of new records/overrides in each record group. A plugin dependency tree. A breakdown of all record conflicts in the user's load order/between a selected set of plugins. A breakdown of the elements that conflict in the user's load order/between a selected set of plugins. Q: What attributes will a plugin recommendation have? A: Plugin filename, plugin hash, smash setting name, smash setting hash. Q: How will setting recommendations be computed? A: Each setting will be compared against the plugin to see how many of the conflicts from the plugin it takes care of, and how well it matches the plugin's record makeup. ================================================ FILE: design/notes/linking explanation.txt ================================================ 1. we have a set of plugins 2. each plugin has a smash setting 3. each smash setting has a definition for certain records 4. each record definition has a node for each element 5. we can link a node in a record definition to another node -- If a element's value changes in a record in a file, and another element is linked to that element, the element that's linked will be copied from the record we're processing to the patch (if it exists). MASTER: R2: R3: R4: SMASHED RECORD: A: 1 A: 2 A: 1 A: 1 A: 1 B: 2 B: 2 B: 2 B: 2 B: 2 C: 3 C: 4 C: 5 C: 3 C: 5 LINK A to C Whenever C changes, copy A ================================================ FILE: design/notes/todos 1024.txt ================================================ 1. Plugin recommendations "dictionary" 2. Plugin information form (and on main form?) 3. Backend ================================================ FILE: frontend/MatorSmash.dpr ================================================ {******************************************************************************* The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. *******************************************************************************} program MatorSmash; {$R 'smash.res' 'smash.rc'} uses Forms, Dialogs, Controls, SysUtils, // lib\mte CRC32 in '..\lib\mte\CRC32.pas', mteBase in '..\lib\mte\mteBase.pas', mteChangeLogForm in '..\lib\mte\mteChangeLogForm.pas', mteHelpers in '..\lib\mte\mteHelpers.pas', mteLogger in '..\lib\mte\mteLogger.pas', mteLogging in '..\lib\mte\mteLogging.pas', mtePluginSelectionForm in '..\lib\mte\mtePluginSelectionForm.pas', mteProgressForm in '..\lib\mte\mteProgressForm.pas', mteTaskHandler in '..\lib\mte\mteTaskHandler.pas', RttiIni in '..\lib\mte\RttiIni.pas', RttiJson in '..\lib\mte\RttiJson.pas', RttiTranslation in '..\lib\mte\RttiTranslation.pas', W7Taskbar in '..\lib\mte\W7Taskbar.pas', // lib\xedit wbBSA in '..\lib\xedit\wbBSA.pas', wbDefinitionsFNV in '..\lib\xedit\wbDefinitionsFNV.pas', wbDefinitionsFO3 in '..\lib\xedit\wbDefinitionsFO3.pas', wbDefinitionsFO4 in '..\lib\xedit\wbDefinitionsFO4.pas', wbDefinitionsTES3 in '..\lib\xedit\wbDefinitionsTES3.pas', wbDefinitionsTES4 in '..\lib\xedit\wbDefinitionsTES4.pas', wbDefinitionsTES5 in '..\lib\xedit\wbDefinitionsTES5.pas', wbHelpers in '..\lib\xedit\wbHelpers.pas', wbImplementation in '..\lib\xedit\wbImplementation.pas', wbInterface in '..\lib\xedit\wbInterface.pas', wbLocalization in '..\lib\xedit\wbLocalization.pas', wbSort in '..\lib\xedit\wbSort.pas', wbStreams in '..\lib\xedit\wbStreams.pas', // Smash msConfiguration in 'msConfiguration.pas', msCore in 'msCore.pas', msLoader in 'msLoader.pas', msConflict in 'msConflict.pas', msChoicePanel in 'msChoicePanel.pas', msSmash in 'msSmash.pas', msAlgorithm in 'msAlgorithm.pas', msProfileForm in 'msProfileForm.pas' {ProfileForm}, msProfilePanel in 'msProfilePanel.pas', msSmashForm in 'msSmashForm.pas' {SmashForm}, msThreads in 'msThreads.pas', msOptionsForm in 'msOptionsForm.pas' {OptionsForm}, msSplashForm in 'msSplashForm.pas' {SplashForm}, msEditForm in 'msEditForm.pas' {EditForm}, msSettingsManager in 'msSettingsManager.pas' {SettingsManager}, msPluginSelectionForm in 'msPluginSelectionForm.pas' {MiniPluginSelectionForm}, msConflictForm in 'msConflictForm.pas' {ConflictForm}, msTagManager in 'msTagManager.pas' {TagManager}, msTagHelper in 'msTagHelper.pas' {TagHelper}; {$R *.res} {$MAXSTACKSIZE 2097152} const IMAGE_FILE_LARGE_ADDRESS_AWARE = $0020; {$SetPEFlags IMAGE_FILE_LARGE_ADDRESS_AWARE} var bProfileProvided, bUseUTF8: boolean; sParam, sProfile, sPath: string; i: Integer; aSettings: TSettings; begin // set important vars SysUtils.FormatSettings.DecimalSeparator := '.'; Application.HintHidePause := 8000; //ReportMemoryLeaksOnShutdown := true; PathList.Values['ProgramPath'] := ExtractFilePath(ParamStr(0)); // get current profile if profile switch provided for i := 1 to ParamCount do begin sParam := ParamStr(i); if sParam = '-profile' then sProfile := ParamStr(i + 1); if sParam = '-utf8' then wbStringEncoding := seUTF8; end; bProfileProvided := sProfile <> ''; sPath := Format('%sprofiles\%s\settings.ini', [ProgramPath, sProfile]); if bProfileProvided and FileExists(sPath) then begin aSettings := TSettings.Create; TRttiIni.Load(sPath, aSettings); CurrentProfile := TProfile.Create(aSettings.profile); CurrentProfile.gameMode := aSettings.gameMode; CurrentProfile.gamePath := aSettings.gamePath; aSettings.Free; end; // initialize application Application.Initialize; ForceDirectories(PathList.Values['ProgramPath'] + 'profiles'); LoadSettings; LoadStatistics; // have user select game mode if not bProfileProvided then begin ProfileForm := TProfileForm.Create(nil); if not (ProfileForm.ShowModal = mrOk) then exit; ProfileForm.Free; end; // run main application Application.Title := 'Mator Smash'; Application.CreateForm(TSmashForm, SmashForm); Application.CreateForm(TProfileForm, ProfileForm); Application.CreateForm(TOptionsForm, OptionsForm); Application.CreateForm(TSplashForm, SplashForm); Application.CreateForm(TEditForm, EditForm); Application.CreateForm(TSettingsManager, SettingsManager); Application.CreateForm(TMiniPluginSelectionForm, MiniPluginSelectionForm); Application.CreateForm(TConflictForm, ConflictForm); Application.CreateForm(TTagManager, TagManager); Application.CreateForm(TTagHelper, TagHelper); Application.Run; end. ================================================ FILE: frontend/MatorSmash.dproj ================================================  {12317C9C-736E-45A4-8CB7-E43FF92DD93C} MatorSmash.dpr True Release Application VCL DCC32 13.4 Win32 1 Win32 true true Base true true Base true true Base true vcl;rtl;vclx;vclactnband;xmlrtl;VclSmp;vclimg;svnui;svn;bdertl;TeeUI;TeeDB;Tee;vcldb;dbrtl;vcldbx;vcltouch;dsnap;dsnapcon;vclib;ibxpress;adortl;IndyCore;IndySystem;IndyProtocols;inet;intrawebdb_110_150;Intraweb_110_150;vclie;websnap;webdsnap;inetdb;inetdbbde;inetdbxpress;soaprtl;vclribbon;dbexpress;DbxCommonDriver;DataSnapIndy10ServerTransport;DataSnapProviderClient;DataSnapClient;dbxcds;DbxClientDriver;DataSnapServer;AzureCloud;DBXInterBaseDriver;DBXMySQLDriver;DBXFirebirdDriver;DBXSybaseASEDriver;DBXSybaseASADriver;DBXOracleDriver;DBXMSSQLDriver;DBXInformixDriver;DBXDb2Driver ..\lib\Imaging\ZLib;..\lib\abbrevia\source;..\lib\Imaging;..\lib\xedit;..\lib\mte;..\lib\superobject;..\lib\xedit\zlib;..\lib\xedit\lz4;$(DCC_UnitSearchPath) false false false false false TES5Edit_Icon.ico false false None 3081 CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;System;Xml;Data;Datasnap;Web;Soap;Winapi;FMX;System.Win;$(DCC_Namespace) false 00400000 false false false false true DEBUG;NX_EXCEPTION_LOG_IN_APP_FOLDER;$(DCC_Define) 3 DetailedSegments .\DebugLite DEBUG;NX_EXCEPTION_LOG_IN_APP_FOLDER;LiteVersion;$(DCC_Define) 3 DetailedSegments true false false false false false 0 MainSource RC RC
smash.res
ProfileForm
SmashForm
OptionsForm
SplashForm
EditForm
SettingsManager
MiniPluginSelectionForm
ConflictForm
TagManager
TagHelper
Cfg_2 Base Cfg_4 Base Base Cfg_1 Base
Delphi.Personality.12 VCLApplication MatorSmash.dpr True False 1 0 1 0 True True False False False 1033 1252 1.0.1.0 Mator Smash 1.0 created by matortheeternal Embarcadero C++Builder Office 2000 Servers Package Embarcadero C++Builder Office XP Servers Package Microsoft Office 2000 Sample Automation Server Wrapper Components Microsoft Office XP Sample Automation Server Wrapper Components False True True 12
================================================ FILE: frontend/MatorSmash.mes ================================================ [GeneralSettings] MesVersion=4 HandleExceptions=0 LinkInCode=1 AppendMapFileToBinary=1 NoOwnMadExceptSettings=0 CheckFileCrc=1 CheckForFrozenMainThread=0 FreezeTimeout=60000 ReportLeaks=0 WindowsLogo=0 CrashOnBuffer=0 CrashOnUnderrun=0 AutomaticallySaveBugReport=1 AutoSaveBugReportIfNotSent=0 AutomaticallyMailBugReport=0 AutoMailProgressBox=0 CopyBugReportToClipboard=0 SuspendAllRunningThreads=0 ShowPleaseWaitBox=0 PleaseWaitIcon=plwait1 AutomaticallyContinueApplication=1 AutomaticallyRestartApplication=0 AutomaticallyCloseApplication=0 SendInBackground=0 SendHelper=196608 Send32Icon=send321 UploadViaHttp=0 HttpServer= HttpSsl=0 HttpPort=0 HttpAccount= HttpPassword= UploadToFogBugz=0 UploadToBugZilla=0 UploadToMantis=0 BugTrackerAccount= BugTrackerPassword= BugTrackerProject= BugTrackerArea= BugTrackerAssignTo= MailAsSmtpServer=0 MailAsSmtpClient=0 SmtpServer= SmtpSsl=0 SmtpTls=0 SmtpPort=0 SmtpAccount= SmtpPassword= MailViaMapi=0 MailViaMailto=0 MailAddress= BugReportFile=bugreport.txt AttachBugReport=0 AttachBugReportFile=1 DeleteBugReportFile=1 BugReportSendAs=bugreport.txt BugReportZip= ScreenShotDepth=0 ScreenShotAppOnly=0 ScreenShotSendAs=screenshot.png ScreenShotZip= AdditionalAttachments= AppendBugReports=1 BugReportFileSize=100000 DontSaveDuplicateExceptions=1 DontSaveDuplicateFreezings=1 DuplicateExceptionDefinition=1 DuplicateFreezeDefinition=2 ShowExceptionBox=1 OkBtnText=&OK DetailsBtnText=&Details PleaseWaitTitle=Information PleaseWaitText=Please wait a moment... BugTrackerTitle=%25appname%25, %25exceptMsg%25 BugTrackerDescr=error details: %0d%0a%25errorDetails%25 MailSubject=bug report MailBody=please find the bug report attached SendBoxTitle=Sending bug report... PrepareAttachMsg=Preparing attachments... MxLookupMsg=Searching for mail server... ConnectMsg=Connecting to server... SendMailMsg=Sending mail... FieldsMsg=Setting fields... SendAttachMsg=Sending attachments... SendFinalizeMsg=Finalizing... MailFailureMsg=Sorry, sending the bug report didn't work. VersionVariable= [ExceptionBox] ShowButtonMailBugReport=0 ShowButtonSaveBugReport=0 ShowButtonPrintBugReport=0 ShowButtonShowBugReport=1 ShowButtonContinueApplication=1 ShowButtonRestartApplication=1 ShowButtonCloseApplication=1 IconButtonSendBugReport=send1 IconButtonSaveBugReport=save1 IconButtonPrintBugReport=print1 IconButtonShowBugReport=show1 IconButtonContinueApplication=continue1 IconButtonCantContinueApplication=cantContinue1 IconButtonRestartApplication=restart1 IconButtonCloseApplication=close1 FocusedButton=4 SendAssistant=SendAssistant SaveAssistant=SaveAssistant PrintAssistant=PrintAssistant AutomaticallyShowBugReport=0 NoOwnerDrawButtons=0 BigExceptionIcon=big1 TitleBar=%25appname%25 ExceptionMessage=An error occurred in the application. FrozenMessage=The application seems to be frozen. BitFaultMsg=The file "%25modname%25" seems to be corrupt! MailBugReportText=send bug report SaveBugReportText=save bug report PrintBugReportText=print bug report ShowBugReportText=show bug report ContinueApplicationText=continue application RestartApplicationText=restart application CloseApplicationText=close application [BugReport] ListThreads=1 ListModules=1 ListHardware=1 ShowCpuRegisters=1 ShowStackDump=1 Disassembly=1 HideUglyItems=0 ShowRelativeAddrs=1 ShowRelativeLines=1 FormatDisassembly=0 LimitDisassembly=5 EnabledPlugins=modules|processes|hardware [Filters] Filter1ExceptionClasses= Filter1DontCreateBugReport=0 Filter1DontCreateScreenshot=0 Filter1DontSuspendThreads=0 Filter1DontCallHandlers=0 Filter1ShowBox=3 Filter1Assis= Filter2ExceptionClasses= Filter2DontCreateBugReport=0 Filter2DontCreateScreenshot=0 Filter2DontSuspendThreads=0 Filter2DontCallHandlers=0 Filter2ShowBox=0 Filter2Assis= GeneralDontCreateBugReport=0 GeneralDontCreateScreenshot=0 GeneralDontSuspendThreads=0 GeneralDontCallHandlers=0 GeneralShowBox=0 GeneralAssis= [Assistants] Assistant1=SendAssistant|Send Assistant|ContactForm|DetailsForm|ScrShotForm Assistant2=SaveAssistant|Save Assistant|ContactForm|DetailsForm Assistant3=PrintAssistant|Print Assistant|ContactForm|DetailsForm Forms1=TPF0%0eTMEContactForm%0bContactForm%07Message%0c%13%00%00%00Contact Information%08MinWidth%04%00%00%00%00%08OnAction%0c%1b%00%00%00madExcept.HandleContactForm%05Timer%04%00%00%00%00%00%09INVButton%0bContinueBtn%07Caption%0c%08%00%00%00Continue%07Enabled%09%0bNoOwnerDraw%08%07Visible%09%00%00%09INVButton%07SkipBtn%07Caption%0c%04%00%00%00Skip%07Enabled%08%0bNoOwnerDraw%08%07Visible%09%00%00%09INVButton%09CancelBtn%07Caption%0c%06%00%00%00Cancel%07Enabled%09%0bNoOwnerDraw%08%07Visible%09%00%00%08INVLabel%06Label1%07Caption%0c%0a%00%00%00your name:%07Enabled%09%07Spacing%04%00%00%00%00%00%00%07INVEdit%08NameEdit%07Colored%09%07Enabled%09%05Lines%04%01%00%00%00%08Optional%09%0aOutputName%0c%0c%00%00%00contact name%0aOutputType%07%09nvoHeader%07Spacing%04%00%00%00%00%04Text%0c%00%00%00%00%05Valid%09%00%00%08INVLabel%06Label2%07Caption%0c%0b%00%00%00your email:%07Enabled%09%07Spacing%04%00%00%00%00%00%00%07INVEdit%09EmailEdit%07Colored%09%07Enabled%09%05Lines%04%01%00%00%00%08Optional%08%0aOutputName%0c%0d%00%00%00contact email%0aOutputType%07%09nvoHeader%07Spacing%04%00%00%00%00%04Text%0c%00%00%00%00%05Valid%09%00%00%0bINVCheckBox%08MemCheck%07Caption%0c%0b%00%00%00remember me%07Checked%08%07Enabled%09%0aOutputName%0c%00%00%00%00%07Spacing%04%00%00%00%00%00%00%00 Forms2=TPF0%0eTMEDetailsForm%0bDetailsForm%07Message%0c%0d%00%00%00Error Details%08MinWidth%04%00%00%00%00%08OnAction%0c%00%00%00%00%05Timer%04%00%00%00%00%00%09INVButton%0bContinueBtn%07Caption%0c%08%00%00%00Continue%07Enabled%09%0bNoOwnerDraw%08%07Visible%09%00%00%09INVButton%07SkipBtn%07Caption%0c%04%00%00%00Skip%07Enabled%09%0bNoOwnerDraw%08%07Visible%09%00%00%09INVButton%09CancelBtn%07Caption%0c%06%00%00%00Cancel%07Enabled%09%0bNoOwnerDraw%08%07Visible%09%00%00%08INVLabel%06Label1%07Caption%0c,%00%00%00what were you doing when the error occurred?%07Enabled%09%07Spacing%04%00%00%00%00%00%00%07INVEdit%0bDetailsMemo%07Colored%09%07Enabled%09%05Lines%04%09%00%00%00%08Optional%08%0aOutputName%0c%0d%00%00%00error details%0aOutputType%07%0dnvoOwnSection%07Spacing%04%00%00%00%00%04Text%0c%00%00%00%00%05Valid%09%00%00%00 Forms3=TPF0%0eTMEScrShotForm%0bScrShotForm%0dActiveControl%07%0bContinueBtn%07Message%0c%18%00%00%00Screenshot Configuration%08MinWidth%04%00%00%00%00%08OnAction%0c%1e%00%00%00madExcept.HandleScreenshotForm%05Timer%04%fa%00%00%00%00%09INVButton%0bContinueBtn%07Caption%0c%08%00%00%00Continue%07Enabled%09%0bNoOwnerDraw%08%07Visible%09%00%00%09INVButton%07SkipBtn%07Caption%0c%04%00%00%00Skip%07Enabled%08%0bNoOwnerDraw%08%07Visible%09%00%00%09INVButton%09CancelBtn%07Caption%0c%06%00%00%00Cancel%07Enabled%09%0bNoOwnerDraw%08%07Visible%09%00%00%0bINVCheckBox%0bAttachCheck%07Caption%0c%25%00%00%00attach a screenshot to the bug report%07Checked%09%07Enabled%09%0aOutputName%0c%00%00%00%00%07Spacing%04%00%00%00%00%00%00%08INVImage%0aScrShotImg%06Border%09%09Clickable%09%07Enabled%09%04File%0c%00%00%00%00%06Height%04%00%00%00%00%07Spacing%04%00%00%00%00%05Width%04%00%00%00%00%00%00%08INVLabel%06Label1%07Caption%0c%15%00%00%00(click to edit image)%07Enabled%09%07Spacing%04%00%00%00%00%00%00%00 ================================================ FILE: frontend/ModelSupport_MatorSmash/MatorSmash/default.txvpck ================================================ ================================================ FILE: frontend/ModelSupport_MatorSmash/default.txvpck ================================================ ================================================ FILE: frontend/ModelSupport_MatorSmash/msEditForm/default.txvpck ================================================ ================================================ FILE: frontend/ModelSupport_MatorSmash/msFrontend/default.txvpck ================================================ ================================================ FILE: frontend/ModelSupport_MatorSmash/msOptionsForm/default.txvpck ================================================ ================================================ FILE: frontend/ModelSupport_MatorSmash/msProfileForm/default.txvpck ================================================ ================================================ FILE: frontend/ModelSupport_MatorSmash/msProfilePanel/default.txvpck ================================================ ================================================ FILE: frontend/ModelSupport_MatorSmash/msSmashForm/default.txvpck ================================================ ================================================ FILE: frontend/ModelSupport_MatorSmash/msSplashForm/default.txvpck ================================================ ================================================ FILE: frontend/ModelSupport_MatorSmash/msThreads/default.txvpck ================================================ ================================================ FILE: frontend/lang/english.lang ================================================ { TSmashForm } { ## QuickBar ## } msMain_QuickButton_Hint=Quick patch|Apply Smash.All to loaded plugins and #13#10generate a smashed patch.#13#10 msMain_NewButton_Hint=Create new smashed patch|Make a new empty smashed patch. msMain_BuildButton_Hint=Build patches| msMain_ManageButton_Hint=Manage smash settings|Click here to manage smash settings. msMain_OptionsButton_Hint=Options|Change the options that control how the #13#10program runs.#13#10 { #### DYNAMIC #### } msMain_NoPatches=There aren't any patches to build or rebuild. msMain_BuildPatches_Loader=You can't build patches until the background #13#10loader is done.#13#10 msMain_BuildAllPatches=Builds all patches that are ready to be built or #13#10rebuilt.#13#10 { ## Main Panel ## } { ## Details Panel ## } msMain_DetailsLabel_Caption=Details msMain_DetailsCopyToClipboardItem_Caption=Copy to clipboard { ## Plugins Tab ## } msMain_PluginsTabSheet_Caption=Plugins msMain_PluginsListView_Column0=Index msMain_PluginsListView_Column1=Filename msMain_PluginsListView_Column2=Setting msMain_PluginsListView_Column3=Patch { #### DYNAMIC #### } msMain_PluginDetails=Plugin Details msMain_Filename=Filename msMain_Hash=Hash msMain_FileSize=File Size msMain_DateModified=Date Modified msMain_NumRecords=Number of records msMain_NumOverrides=Number of overrides msMain_Author=Author msMain_Description=Description msMain_Masters=Masters msMain_ClearTags=Are you sure you want to clear tags from these plugins? { ## Plugins Popup Menu ## } msMain_NewPatchItem_Caption= msMain_OpenPluginLocationItem_Caption=Open plugin location msMain_AddToPatchItem_Caption=Add to patch msMain_ManageTagsItem_Caption=Manage Tags msMain_SmashSettingItem_Caption=Smash setting { ## Patches Tab ## } msMain_PatchesTabSheet_Caption=Patches msMain_PatchesListView_Column0=Index msMain_PatchesListView_Column1=Name msMain_PatchesListView_Column2=Filename msMain_PatchesListView_Column3=Size msMain_PatchesListView_Column4=Date built { #### DYNAMIC #### } msMain_PatchDetails=Patch Details msMain_Status=Status msMain_PatchName=Patch name msMain_PluginCount=Plugin count msMain_DateBuilt=Date built msMain_Plugins=Plugins msMain_Fails=Fails msMain_TooManyFails=Too many fails to display. msMain_DeletePatches=Are you sure you want to delete these patches? { ## Patches Popup Menu ## } msMain_ToggleRebuildItem_Caption=Toggle rebuild status msMain_OpenInExplorerItem_Caption=Open in explorer { ## Plugins Submenu ## } msMain_MoveItem_Caption=Move msMain_UpItem_Caption=Up msMain_DownItem_Caption=Down msMain_ToTopItem_Caption=To top msMain_ToBottomItem_Caption=To bottom { #### DYNAMIC #### } msMain_BuildPatch=Build patch msMain_RebuildPatch=Rebuild patch msMain_BuildPatches=Build patches msMain_RebuildPatches=Rebuilds patches { ## Log Tab ## } msMain_LogTabSheet_Caption=Log { #### DYNAMIC #### } msMain_AppDetails=Application Details msMain_Application=Application msMain_Author=Author msMain_Version=Version msMain_DateBuilt=Date built msMain_GameMode=Game mode msMain_Language=Language msMain_TimesRun=Times run msMain_PatchesBuilt=Patches built msMain_PluginsSmashed=Plugins smashed msMain_SettingsSubmitted=Smash settings submitted msMain_RecsSubmitted=Recommendations submitted msMain_Website=Website msMain_ApiCredits=API Credits msMain_xEditVersion=xEdit Version msMain_xEditCredits=xEdit Credits msMain_Testers=Testers msMain_Translators=Translators msMain_LoadException=Exception Loading Plugins msMain_PluginsNotLoaded=Due to an exception, not all of your plugins #13#10have been loaded. You can still use the program. #13#10See the log tab for more info.#13#10 msMain_Enable=Enable msMain_Disable=Disable msMain_AutoScroll=Autoscroll { ## Log Popup Menu ## } msMain_FilterGroupItem_Caption=Filter group msMain_FilterLabelItem_Caption=Filter label msMain_CopyToClipboardItem_Caption=Copy to clipboard msMain_SaveAndClearItem_Caption=Save and clear msMain_ToggleAutoScrollItem_Caption=Disable auto scroll { TOptionsForm } mpOpt_btnCancel_Caption=Cancel mpOpt_btnOK_Caption=OK { ## General Tab ## } mpOpt_GeneralTabSheet_Caption=General mpOpt_gbLanguage_Caption=Language mpOpt_lblLanguage_Caption=Current languge mpOpt_gbStyle_Caption=Style mpOpt_kbSimpleDictionary_Caption=Simple dictionary view mpOpt_kbSimplePlugins_Caption=Simple plugins list { ## Patching Tab ## } mpOpt_PatchingTabSheet_Caption=Patching mpOpt_lblDestinationDirectory_Caption=Patch destination directory mpOpt_gbDebug_Caption=Debug mpOpt_gbOther_Caption=Other Options { ## Advanced Tab ## } mpOpt_AdvancedTabSheet_Caption=Advanced mpOpt_lblCurrentProfile_Caption=Current profile mpOpt_gbLogging_Caption=Logging mpOpt_lblClientColor_Caption=Client mpOpt_lblGeneralColor_Caption=General mpOpt_lblLoadColor_Caption=Load mpOpt_lblPluginColor_Caption=Plugin mpOpt_lblErrorColor_Caption=Errors mpOpt_lblTemplate_Caption=Template mpOpt_lblSample_Caption=Sample { TSettingsManager } { ## Settings ## } msSet_gbFiltering_Caption=Filtering options msSet_lvSettings_Column0=Name msSet_lvSettings_Column1=Records msSet_btnSave_Caption=Save msSet_btnDiscard_Caption=Discard { ## Settings Popup Menu ## } msSet_NewSettingItem_Caption=New setting msSet_CloneSettingItem_Caption=Clone setting msSet_CombineSettingsItem_Caption=Combine settings msSet_EditSettingItem_Caption=Edit setting msSet_DeleteSettingItem_Caption=Delete setting { ## Details ## } msSet_lblName_Caption=Name msSet_lblColor_Caption=Color msSet_lblDescription_Caption=Description msSet_lblTree_Caption=Tree { ## Tree Popup Menu ## } msSet_ToggleNodesItem_Caption=Toggle nodes msSet_IgnoreDeletionsItem_Caption=Toggle ignore deletions msSet_SingleEntityItem_Caption=Toggle treat as single entity msSet_PruneNodesItem_Caption=Prune nodes msSet_PreserveDeletionsItem_Caption=Toggle preserve deletions { TTagManager } msTagM_Caption=Manage Tags - %s { ## General ## } msTagM_lblDescription_Caption=Description msTagM_btnAdd_Caption=Add Tags msTagM_btnRemove_Caption=Remove Tags msTagM_btnClear_Caption=Clear Tags msTagM_btnReset_Caption=Reset Tags msTagM_btnApply_Caption=Apply msTagM_btnCancel_Caption=Cancel msTagM_kbCombine_Caption=Apply combined setting { TTagHelper } msTagH_btnCancel_Caption=Cancel msTagH_btnOK_Caption=OK { #### DYNAMIC #### } msTagH_AddTags=Add Tags msTagH_RemoveTags=Remove Tags msTagH_PromptAdd=Check the tags you want to add msTagH_PromptRemove=Check the tags you want to remove { TProgressForm } { #### DYNAMIC #### } msProg_Closing=Closing msProg_Smashing=Smashing Patches msProg_DoneBuilding=Done smashing patches msProg_BuildingTree=Building tree ================================================ FILE: frontend/msAlgorithm.pas ================================================ unit msAlgorithm; interface uses SysUtils, Classes, // superobject superobject, // mte units mteHelpers, mteTracker, mteBase, // ms units msCore, msConfiguration, // xEdit components wbInterface, wbImplementation; procedure CopyLinkedElement(srcCont, dstCont: IwbContainerElementRef; eLink: string; obj: ISuperObject; dstRec: IwbMainRecord); function rcore(src, mst, dst: IwbElement; dstrec: IwbMainRecord; obj: ISuperObject; bSingle, bDeletions, bOverride: boolean): boolean; implementation var firstLink: string; bLinkProcessed: boolean; { ElementByKey: Gets an element from a container, @e, matching a specified @key. If @bUseSortKey is true uses SortKey, else uses GetAllValues. } function ElementByKey(e: IwbElement; key: string; bUseSortKey: boolean): IwbElement; var i: Integer; c: IwbContainerElementRef; element: IwbElement; eKey: string; begin if not Supports(e, IwbContainerElementRef, c) then exit; // loop through children elements for i := 0 to Pred(c.ElementCount) do begin element := c.Elements[i]; // get sort key if bUseSortKey, else get values key if bUseSortKey then eKey := element.SortKey[false] else eKey := GetAllValues(element); // if keys match result is current element if eKey = key then begin Result := element; break; end; end; end; { HandleElementLife: Called by rcore. Handles the creation/deletion of elements in the destination patch record @dstRec. } function HandleElementLife(srcCont, dstCont, mstCont: IwbContainerElementRef; dstRec: IwbMainRecord; obj: ISuperObject; bSingle, bDeletions, bOverride: boolean): boolean; var i: Integer; element: IwbElement; eObj: ISuperObject; process, bInDestination, bInMaster: boolean; eLink: String; begin Result := false; // handle element creation for i := 0 to Pred(srcCont.ElementCount) do begin element := srcCont.Elements[i]; // if the element isn't in the destination record // and wasn't in the master record, copy it to the destination // if it isn't in the destination but is in the master it means // that it was deleted and shouldn't be copied. bInDestination := Assigned(dstCont.ElementByName[element.Name]); bInMaster := Assigned(mstCont.ElementByName[element.Name]); if (not bInDestination) and (bOverride or not bInMaster) then begin Result := true; if bSingle then exit; // skip according to setting eObj := GetElementObj(obj, element.Name); process := Assigned(eObj) and (eObj.I['p'] = 1); if not process then begin if settings.debugSkips then Tracker.Write(' Skipping element creation at '+element.Path); continue; end; // copy element try if settings.debugChanges then Tracker.Write(' Created element at '+element.Path); wbCopyElementToRecord(element, dstRec, false, true); // if another element is linked to the element, copy it eLink := eObj.S['lf']; if (eLink <> '') then begin firstLink := eLink; bLinkProcessed := false; CopyLinkedElement(srcCont, dstCont, eLink, obj, dstRec); end; except on x: Exception do Tracker.Write(' HandleElementLife: Failed to copy '+element.Path+', '+x.Message); end; end; end; // handle element deletion if bDeletions then begin for i := Pred(dstCont.ElementCount) downto 0 do begin element := dstCont.Elements[i]; if Assigned(mstCont.ElementByName[element.Name]) and not Assigned(srcCont.ElementByName[element.Name]) then begin Result := true; if bSingle then exit; // skip according to setting eObj := GetElementObj(obj, element.Name); process := Assigned(eObj) and (eObj.I['p'] = 1); if not process then begin if settings.debugSkips then Tracker.Write(' Skipping element deletion at '+element.Path); continue; end; // remove element if settings.debugChanges then Tracker.Write(' Deleted element at '+element.Path); dstCont.RemoveElement(element); // if another element is linked to the element, copy it eLink := eObj.S['lf']; if (eLink <> '') then begin firstLink := eLink; bLinkProcessed := false; CopyLinkedElement(srcCont, dstCont, eLink, obj, dstRec); end; end; end; end; end; // GetMasterElement: Gets the first instance of an element (the master) function GetMasterElement(src, se: IwbElement; dstRec: IwbMainRecord): IwbElement; const debugGetMaster = false; var i: integer; path, key: string; mstRec, ovr: IwbMainRecord; mst: IwbElement; bSorted: boolean; begin Result := nil; mstRec := dstRec.MasterOrSelf; path := IndexedPath(src); bSorted := IsSorted(src); // if sorted, use SortKey, else use GetAllValues if bSorted then key := se.SortKey[false] else key := GetAllValues(se); // debug message if debugGetMaster then Tracker.Write(' Called GetMasterElement at path '+path+' looking for key '+key); // loop from override 0 to the second to last override // last override is in our patch, we don't want to process that one for i := 0 to mstRec.OverrideCount - 2 do begin ovr := mstRec.Overrides[i]; mst := ElementByIndexedPath(mstRec, path); Result := ElementByKey(mst, key, bSorted); // break if we found a subrecord matching the sortkey if Result <> nil then break; end; end; { BuildKeyList: Creates a list of element keys for elements in @container in a stringlist @sl. Uses SortKey if @bUseSortKeys is true, else uses GetAllValues. } procedure BuildKeyList(container: IwbContainerElementRef; var sl: TStringList; bUseSortKeys: boolean); var i, n: integer; childElement: IwbElement; key, adjustedKey: string; begin // loop through children elements for i := 0 to Pred(container.ElementCount) do begin childElement := container.Elements[i]; // use sort if bUseSortKeys is true, else use GetAllValues if bUseSortKeys then key := childElement.SortKey[false] else key := GetAllValues(childElement); // find a non-colliding key n := 0; adjustedKey := key; while (sl.IndexOf(adjustedKey) > -1) do begin Inc(n); adjustedKey := key + IntToStr(n); end; // add adjusted key to stringlist sl.Add(adjustedKey); end; end; { MergeArray: Merges a sorted or unsorted arrray element by comparing element keys. Compares a source array @src, against a master array @mst and a destination array @dst. Returns true if any changes are made. Exits before making any changes if @bSingle is true. Preserves deletions if @bDeletions if true. Tracks @dstRec and @obj for calling rcore on element containers in sorted arrays. } function MergeArray(src, mst, dst: IwbElement; dstrec: IwbMainRecord; obj: ISuperObject; bSingle, bDeletions, bOverride: boolean): boolean; var i, s_ndx, m_ndx, d_ndx: integer; se, de: IwbElement; slMst, slDst, slSrc: TStringList; srcCont, dstCont, mstCont, seCont: IwbContainerElementRef; bSorted: boolean; begin Result := false; // exit if input array elements can't be treated as a containers if not Supports(src, IwbContainerElementRef, srcCont) then exit; if not Supports(mst, IwbContainerElementRef, mstCont) then exit; if not Supports(dst, IwbContainerElementRef, dstCont) then exit; // determine if we're handling a sorted array bSorted := IsSorted(src); // Build lists of element keys in each array for easy comparison slSrc := TStringList.Create; slMst := TStringList.Create; slDst := TStringList.Create; try BuildKeyList(srcCont, slSrc, bSorted); BuildKeyList(mstCont, slMst, bSorted); BuildKeyList(dstCont, slDst, bSorted); // ELEMENT DELETION: // Remove elements that are in master and destination, but // missing from source if bDeletions then for i := 0 to Pred(slMst.Count) do begin s_ndx := slSrc.IndexOf(slMst[i]); // element from master isn't in source if (s_ndx = -1) then begin Result := true; // if we're in a treat as single, exit without removing anything if bSingle then exit; // if element is present in destination, remove it d_ndx := slDst.IndexOf(slMst[i]); if (d_ndx = -1) then continue; if settings.debugArrays then Tracker.Write(' > Removing element at '+dst.Path+' with key: '+slMst[i]); dstCont.RemoveElement(d_ndx); slDst.Delete(d_ndx); end; end; // ELEMENT ADDITION: // Copy array elements in source that aren't in master // or destination for i := 0 to Pred(slSrc.Count) do begin d_ndx := slDst.IndexOf(slSrc[i]); m_ndx := slMst.IndexOf(slSrc[i]); se := srcCont.Elements[i]; if (d_ndx = -1) and ((m_ndx = -1) or bOverride) then begin Result := true; // if we're in a treat as single, exit without adding anything if bSingle then exit; // add element to destination if settings.debugArrays then Tracker.Write(' > Adding element at '+dst.Path+' with key: '+slSrc[i]); de := dstCont.Assign(dstCont.ElementCount, se, false); if bSorted then slDst.Insert(dstCont.IndexOf(de), slSrc[i]) else slDst.Add(slSrc[i]); end // Special handling for sorted arrays // Traverses elements that may have been modified without their sortkey changing else if bSorted and (d_ndx > -1) and Supports(se, IwbContainerElementRef, seCont) and (seCont.ElementCount > 0) then begin if settings.debugArrays then begin Tracker.Write(' > Traversing element '+se.Path+' with key: '+slSrc[i]); Tracker.Write(' > Source Element: '+GetAllValues(se)); Tracker.Write(' > Destination Element: '+GetAllValues(dstCont.Elements[d_ndx])); end; // traverse element try Result := rcore(se, GetMasterElement(src, se, dstrec), dstCont.Elements[d_ndx], dstrec, GetElementObj(obj, se.Name), bSingle, bDeletions, bOverride); if Result and bSingle then exit; except on x : Exception do begin Tracker.Write(' rcore: Exception at '+se.Path+': '+x.Message); end; end; end; end; finally // free lists slMst.Free; slSrc.Free; slDst.Free; end; end; { CopyElementValue: Copies the edit value of @se to @de. } procedure CopyElementValue(se, me, de: IwbElement); begin if not de.IsEditable then begin if settings.debugChanges then begin Tracker.Write(' Unable to copy element value on '+se.path); Tracker.Write(' Element is not editable'); end; exit; end; if Assigned(me) and settings.debugChanges then begin if (not settings.debugTraversal) then Tracker.Write(' '+se.Path); Tracker.Write(' > Found differing values: '+se.EditValue+', '+me.EditValue); end; // try to copy element value to destination element from source element try de.EditValue := se.EditValue; except on x : Exception do Tracker.Write(' CopyElementValue: Exception '+x.Message); end; end; { CopyLinkedElement: Copies the linked element named eLink, and then copies any elements it is linked to. } procedure CopyLinkedElement(srcCont, dstCont: IwbContainerElementRef; eLink: string; obj: ISuperObject; dstRec: IwbMainRecord); var cObj: ISuperObject; le, de: IwbElement; cLink: string; begin // exit if we reached the first link in a chain if (eLink = firstLink) then begin if bLinkProcessed then exit; bLinkProcessed := true; end; // else try to copy the linked element try cObj := GetElementObj(obj, eLink); le := srcCont.ElementByName[eLink]; de := dstCont.ElementByName[eLink]; if Assigned(le) then begin if settings.debugLinks then Tracker.Write(' Copying linked element '+le.Path); if Assigned(de) then de.Assign(Low(Integer), le, false) else dstCont.AddIfMissing(le, true, true, '', '', ''); // follow chain cLink := cObj.S['lf']; if cLink <> '' then CopyLinkedElement(srcCont, dstCont, cLink, obj, dstRec); end; except on x: Exception do Tracker.Write(' CopyLinkedElement: Failed to copy '+eLink+', '+x.Message); end; end; { HandleElement: Wrapper function around the logic for recursing into child elements (rcore), handling an array, or copying element values. } function HandleElement(se, me, de: IwbElement; dstRec: IwbMainRecord; obj: ISuperObject; bSingle, bDeletions, bOverride: boolean): boolean; var srcType, dstType: TSmashType; container: IwbContainerElementRef; bCanAdd, bIsContainer: boolean; seVal, meVal: string; begin Result := false; // deftype and elementtype srcType := GetSmashType(se); dstType := GetSmashType(de); // other type information bIsContainer := Supports(se, IwbContainerElementRef, container) and (container.ElementCount > 0); bCanAdd := se.CanAssign(High(Integer), nil, True) and not (esNotSuitableToAddTo in se.ElementStates); // exit if srcType <> dstType, returning true if srcType <> dstType then begin if settings.debugSkips then begin Tracker.Write(' Source and destination types don''t match'); Tracker.Write(' '+stToString(srcType)+' != '+stToString(dstType)); Tracker.Write(' Skipping '+se.Path); end; Result := True; exit; end; // exit if master element not assigned and not array if not Assigned(me) then begin if bCanAdd and (srcType in stArrays) then me := de else begin if settings.debugSkips then begin Tracker.Write(' Master element not found!'); Tracker.Write(' Skipping '+se.Path); end; exit; end; end; // debug messages if settings.debugTraversal then Tracker.Write(' '+se.Path); if settings.debugTypes then begin Tracker.Write(' bCanAdd: '+BoolToStr(bCanAdd, true)); Tracker.Write(' SmashType: '+stToString(srcType)); end; // merge array if bCanAdd and (srcType in stArrays) then begin if settings.debugTraversal then Tracker.Write(' Merging array'); try Result := MergeArray(se, me, de, dstrec, obj, bSingle, bDeletions, bOverride); except on x : Exception do Tracker.Write(' MergeArray: Exception at '+se.Path+': '+x.Message); end; end // else recurse deeper else if bIsContainer and (srcType <> stInteger) then begin if settings.debugTraversal then Tracker.Write(' Recursing deeper'); try Result := rcore(se, me, de, dstrec, obj, bSingle, bDeletions, bOverride); except on x : Exception do Tracker.Write(' rcore: Exception at '+se.Path+': '+x.Message); end; end // else copy element value else if (srcType in stValues) then begin seVal := se.EditValue; meVal := me.EditValue; if (seVal <> meVal) then begin if not bSingle then CopyElementValue(se, me, de); Result := true; end else if settings.debugSkips then begin Tracker.Write(Format(' Skipping, "%s" = "%s"', [seVal, meVal])); end; end else if settings.debugSkips then begin Tracker.Write(Format(' Skipping, %s is not a value type', [stToString(srcType)])); end; end; { rcore: Recursively copy overridden elements. Recursively traverses elements, comparing between a source element (from an override record) @src, a master element @mst, and a destination element @dst. Tracks the destination patch record for element copying through @dstRec. Uses a json tree @obj to determine user settings for traversal. Uses @bSingle to determine when we're in a "single entity" as specified by the user, and @bDeletions to determine when it's ok to delete removed elements from the destination patch record. - Uses HandleElementLife to resolve element creation/deletion. - Uses HandleElement to handle arrays, recurse deeper, or copy element values } function rcore(src, mst, dst: IwbElement; dstRec: IwbMainRecord; obj: ISuperObject; bSingle, bDeletions, bOverride: boolean): boolean; var i: integer; srcCont, dstCont, mstCont: IwbContainerElementRef; se, me, de: IwbElement; process, eSingle, eDeletions, eOverride: boolean; eObj: ISuperObject; eLink: string; begin Result := false; // prepare containers if not Supports(src, IwbContainerElementRef, srcCont) then begin if settings.debugSkips then begin Tracker.Write(' Source element not a container.'); Tracker.Write(' Skipping '+src.Path); end; exit; end; if not Supports(dst, IwbContainerElementRef, dstCont) then begin if settings.debugSkips then begin Tracker.Write(' Destination element not a container.'); Tracker.Write(' Skipping '+src.Path); end; exit; end; if not Supports(mst, IwbContainerElementRef, mstCont) then begin if settings.debugSkips then begin Tracker.Write(' Master element not a container.'); Tracker.Write(' Skipping '+src.Path); end; exit; end; // copy elements from source to destination if missing AND // delete elements missing from source if found in master and destination Result := HandleElementLife(srcCont, dstCont, mstCont, dstRec, obj, bSingle, bDeletions, bOverride); if bSingle and Result then begin if settings.debugSingle then Tracker.Write(' Single entity change found at '+src.Path); exit; end; // loop through subelements for i := 0 to Pred(srcCont.ElementCount) do begin // assign source, destination, master elements se := srcCont.Elements[i]; de := dstCont.ElementByName[se.Name]; me := mstCont.ElementByName[se.Name]; // skip if destination element not assigned if not Assigned(de) then begin if settings.debugSkips then begin Tracker.Write(' Destination element not found!'); Tracker.Write(' Skipping '+se.Path); end; continue; end; // skip according to setting eObj := GetElementObj(obj, se.Name); process := Assigned(eObj) and (eObj.I['p'] = 1); if not process then begin if settings.debugSkips then Tracker.Write(' Skipping '+se.Path); continue; end; // set element treat as single entity / ignore deletions booleans eSingle := bSingle or (eObj.I['s'] = 1); eDeletions := bDeletions or (eObj.I['d'] = 1); eOverride := bOverride or (eObj.I['o'] = 1); // handle element Result := HandleElement(se, me, de, dstRec, eObj, eSingle, eDeletions, eOverride); // if we're in a single entity and an element is changed, break // we don't need to handle anything anymore if bSingle and Result then begin if settings.debugSingle then Tracker.Write(' Single entity change found at '+se.Path); break; end; // if the element we're processing has the single entity flag set // and we're not currently in a single entity, copy entire element if eSingle and (not bSingle) and Result then try if settings.debugSingle then Tracker.Write(Format(' Copying single entity %s', [se.path])); de.Assign(Low(Integer), se, false); except on x: Exception do Tracker.Write(' rcore: Failed to copy '+se.Path+', '+x.Message); end; // if another element is linked to the element being processed // and the element being processed has been modified, copy the linked // element eLink := eObj.S['lf']; if Result and (eLink <> '') then begin firstLink := eLink; bLinkProcessed := false; CopyLinkedElement(srcCont, dstCont, eLink, obj, dstRec); end; end; end; end. ================================================ FILE: frontend/msChoicePanel.pas ================================================ unit msChoicePanel; interface uses SysUtils, Classes, Controls, Dialogs, Graphics, Buttons, StdCtrls, ExtCtrls, ImgList, Types, // mte components mteHelpers, // mp components msCore; type TSenderCallback = procedure(Sender: TObject) of object; TChoicePanel = class(TPanel) public Selected: boolean; constructor Create(AOwner: TComponent); override; destructor Destroy; override; procedure ToggleSelect(Sender: TObject); procedure SettingChanged(Sender: TObject); procedure Deselect; procedure Select; procedure SetTop(top: Integer); procedure SetWidth(width: Integer); function GetSetting: TSmashSetting; function GetLabel: string; procedure SetSelectCallback(callback: TNotifyEvent); procedure SetLabel(sig: string); procedure AddChoice(choice: TSmashSetting); private lstChoices: TList; ColorUnselected: Integer; ColorSelected: Integer; lblSig: TLabel; cbChoices: TComboBox; SelectCallback: TNotifyEvent; end; implementation {******************************************************************************} { TChoicePanel A GUI component for interacting with a profile. } {******************************************************************************} constructor TChoicePanel.Create(AOwner: TComponent); begin // set up panel inherited Create(AOwner); Parent := AOwner as TWinControl; Width := (AOwner as TWinControl).ClientWidth; Height := 36; Left := 0; Top := 0; ParentBackground := false; ParentColor := false; ParentDoubleBuffered := false; Cursor := crHandPoint; Anchors := [akLeft, akTop, akRight]; Visible := true; // set local variables Selected := false; ColorUnselected := Color; ColorSelected := $f0ece4; lstChoices := TList.Create; // create components lblSig := TLabel.Create(self); cbChoices := TComboBox.Create(self); // set up lblSig lblSig.Parent := self; lblSig.Top := 10; lblSig.Left := 16; lblSig.Caption := 'SIGN'; lblSig.Cursor := crHandPoint; lblSig.Align := alCustom; lblSig.Anchors := [akLeft, akTop]; // set up cbGame cbChoices.Parent := self; cbChoices.Top := 8; cbChoices.Left := 75; cbChoices.Width := Width - cbChoices.Left - 6; cbChoices.Style := csDropDownList; cbChoices.Items.Text := ''; cbChoices.Items.Add('Patch'); cbChoices.ItemIndex := 0; cbChoices.Align := alCustom; cbChoices.Anchors := [akLeft, akTop, akRight]; // set event handlers self.OnClick := ToggleSelect; lblSig.OnClick := ToggleSelect; cbChoices.OnChange := SettingChanged; end; destructor TChoicePanel.Destroy; begin lblSig.Free; cbChoices.Free; lstChoices.Free; inherited; end; { EVENT HANDLING } procedure TChoicePanel.SettingChanged(Sender: TObject); begin if Assigned(SelectCallback) then SelectCallback(self); end; procedure TChoicePanel.ToggleSelect(Sender: TObject); begin if Cursor = crHandPoint then begin if Selected then Deselect else Select; if Assigned(SelectCallback) then SelectCallback(self); end; end; procedure TChoicePanel.Select; begin Selected := true; Color := ColorSelected; Repaint; end; procedure TChoicePanel.Deselect; begin Selected := false; Color := ColorUnselected; Repaint; end; procedure TChoicePanel.SetTop(top: Integer); begin self.top := top; end; procedure TChoicePanel.SetWidth(width: Integer); begin self.width := width; end; function TChoicePanel.GetSetting: TSmashSetting; begin Result := nil; if cbChoices.ItemIndex = 0 then exit; Result := TSmashSetting(lstChoices[cbChoices.ItemIndex - 1]); end; function TChoicePanel.GetLabel: string; begin Result := lblSig.Caption; end; procedure TChoicePanel.SetSelectCallback(callback: TNotifyEvent); begin SelectCallback := callback; end; procedure TChoicePanel.SetLabel(sig: string); begin lblSig.Caption := sig; end; procedure TChoicePanel.AddChoice(choice: TSmashSetting); begin lstChoices.Add(choice); cbChoices.Items.Add(choice.name); cbChoices.ItemIndex := 0; end; end. ================================================ FILE: frontend/msConfiguration.pas ================================================ unit msConfiguration; interface uses Classes, wbInterface, // mte units mteHelpers, RttiIni; type TGameMode = Record longName: string; gameName: string; gameMode: TwbGameMode; regName: string; appName: string; exeName: string; appIDs: string; bsaOptMode: string; end; TSettings = class(TObject) public [IniSection('General')] profile: string; newProfile: boolean; gameMode: integer; gamePath: string; language: string; simpleDictionaryView: boolean; simplePluginsView: boolean; simpleSplash: boolean; [IniSection('Advanced')] generalMessageColor: Int64; clientMessageColor: Int64; loadMessageColor: Int64; patchMessageColor: Int64; pluginMessageColor: Int64; errorMessageColor: Int64; logMessageTemplate: string; preserveTempPath: boolean; allowTagging: boolean; smashSound: boolean; [IniSection('Patching')] patchDirectory: string; debugPatchStatus: boolean; debugMasters: boolean; debugArrays: boolean; debugSkips: boolean; debugTraversal: boolean; debugTypes: boolean; debugChanges: boolean; debugSingle: boolean; debugLinks: boolean; buildRefs: boolean; preserveITPOs: boolean; constructor Create; virtual; end; TStatistics = class(TObject) public [IniSection('Statistics')] timesRun: integer; patchesBuilt: integer; pluginsPatched: integer; settingsSubmitted: integer; recsSubmitted: integer; constructor Create; virtual; end; TProfile = class(TObject) public name: string; gameMode: Integer; gamePath: string; constructor Create(name: string); virtual; procedure Clone(p: TProfile); procedure Delete; procedure Rename(name: string); end; TProgramStatus = class(TObject) public bInitException, bLoadException, bChangeProfile, bForceTerminate, bLoaderDone, bInstallUpdate, bUpdatePatchStatus, bClose: boolean; GameMode: TGameMode; Version: String; constructor Create; virtual; end; procedure DeleteTempPath; procedure LoadLanguage; function GetLanguageString(name: string): string; procedure SaveProfile(var p: TProfile); procedure LoadSettings; overload; function LoadSettings(path: string): TSettings; overload; procedure SaveSettings; overload; procedure SaveSettings(var s: TSettings; path: string); overload; procedure LoadStatistics; procedure SaveStatistics; var settings: TSettings; CurrentProfile: TProfile; statistics, sessionStatistics: TStatistics; language, PathList: TStringList; ProgramStatus: TProgramStatus; const // IMPORTANT CONSTANTS bTranslationDump = false; // GAME MODES GameArray: array[1..6] of TGameMode = ( ( longName: 'Skyrim'; gameName: 'Skyrim'; gameMode: gmTES5; regName: 'Skyrim'; appName: 'TES5'; exeName: 'TESV.exe'; appIDs: '72850'; bsaOptMode: 'sk'; ), ( longName: 'Oblivion'; gameName: 'Oblivion'; gameMode: gmTES4; regName: 'Oblivion'; appName: 'TES4'; exeName: 'Oblivion.exe'; appIDs: '22330,900883'; bsaOptMode: 'ob'; ), ( longName: 'Fallout New Vegas'; gameName: 'FalloutNV'; gameMode: gmFNV; regName: 'FalloutNV'; appName: 'FNV'; exeName: 'FalloutNV.exe'; appIDs: '22380,2028016'; bsaOptMode: 'fo'; ), ( longName: 'Fallout 3'; gameName: 'Fallout3'; gameMode: gmFO3; regName: 'Fallout3'; appName: 'FO3'; exeName: 'Fallout3.exe'; appIDs: '22300,22370'; bsaOptMode: 'fo'; ), ( longName: 'Fallout 4'; gameName: 'Fallout4'; gameMode: gmFO4; regName: 'Fallout4'; appName: 'FO4'; exeName: 'Fallout4.exe'; appIDs: '377160'; bsaOptMode: ''; ), ( longName: 'Skyrim Special Edition'; gameName: 'Skyrim'; gameMode: gmSSE; regName: 'Skyrim Special Edition'; appName: 'SSE'; exeName: 'SkyrimSE.exe'; appIDs: '489830'; bsaOptMode: ''; ) ); implementation uses Graphics, SysUtils, Dialogs, ShellAPI, Windows, Registry; { TSettings } constructor TSettings.Create; begin // default settings newProfile := true; language := 'English'; simpleDictionaryView := false; simplePluginsView := false; patchDirectory := wbDataPath; generalMessageColor := clGreen; loadMessageColor := clPurple; clientMessageColor := clBlue; patchMessageColor := $000080FF; pluginMessageColor := $00484848; errorMessageColor := clRed; logMessageTemplate := '[{{AppTime}}] ({{Group}}) {{Label}}: {{Text}}'; end; { TStatistics constructor } constructor TStatistics.Create; begin timesRun := 0; patchesBuilt := 0; pluginsPatched := 0; settingsSubmitted := 0; recsSubmitted := 0; end; { TProfile } constructor TProfile.Create(name: string); begin self.name := name; end; procedure TProfile.Clone(p: TProfile); begin name := p.name; gameMode := p.gameMode; gamePath := p.gamePath; end; procedure TProfile.Delete; var path: string; begin path := PathList.Values['ProgramPath'] + 'profiles\' + name; if DirectoryExists(path) then DeleteToRecycleBin(path, false); end; procedure TProfile.Rename(name: string); var oldProfilePath, newProfilePath: string; begin // rename old profile folder if necessary oldProfilePath := PathList.Values['ProgramPath'] + 'profiles\' + self.name; newProfilePath := PathList.Values['ProgramPath'] + 'profiles\' + name; if DirectoryExists(oldProfilePath) then RenameFile(oldProfilePath, newProfilePath); // then change name in the object self.name := name; end; { TProgramStatus } constructor TProgramStatus.Create; begin bInitException := false; bLoadException := false; bChangeProfile := false; bForceTerminate := false; bUpdatePatchStatus := false; bClose := false; Version := GetVersionMem; end; { CONFIGURATION HELPERS } procedure DeleteTempPath; begin DeleteDirectory(PathList.Values['TempPath']); end; procedure LoadLanguage; const langFile = 'http://raw.githubusercontent.com/matortheeternal/smash/master/frontend/lang/english.lang'; directions = 'Your english.lang file is missing. Please download it from GitHub. ' + 'After you click OK, a webpage with the file will be opened. Right-click the ' + 'page and choose "Save page as", then save it as english.lang in the "lang\" ' + 'folder where you have MatorSmash.exe installed.'; accessMessage = 'It looks like Smash doesn''t have permission to read files ' + 'from disk. Try running the program as administrator or disabling your antivirus.'; var filename: string; begin filename := Format('lang\%s.lang', [settings.language]); language := TStringList.Create; if (not FileExists(filename)) then begin if settings.language <> 'english' then begin settings.language := 'english'; LoadLanguage; end else if not FileExists('MatorSmash.exe') then MessageDlg(accessMessage, mtConfirmation, [mbOk], 0) else begin MessageDlg(directions, mtConfirmation, [mbOk], 0); ForceDirectories(PathList.Values['ProgramPath'] + 'lang\'); ShellExecute(0, 'open', PChar(langFile), '', '', SW_SHOWNORMAL); end; end else language.LoadFromFile(filename); end; function GetLanguageString(name: string): string; begin if language.Values[name] <> '' then Result := StringReplace(language.Values[name], '#13#10', #13#10, [rfReplaceAll]) else Result := name; end; procedure SaveProfile(var p: TProfile); var path: string; pSettings: TSettings; begin // get profile path path := PathList.Values['ProgramPath'] + 'profiles\' + p.name + '\settings.ini'; ForceDirectories(ExtractFilePath(path)); // load settings if they exist, else create them if FileExists(path) then pSettings := LoadSettings(path) else begin pSettings := TSettings.Create; pSettings.patchDirectory := p.gamePath + 'Data\'; end; // save profile details to settings pSettings.profile := p.name; pSettings.gameMode := p.gameMode; pSettings.gamePath := p.gamePath; SaveSettings(pSettings, path); end; procedure SaveSettings; begin // user saving settings from options form settings.newProfile := false; TRttiIni.Save(PathList.Values['ProfilePath'] + 'settings.ini', settings); end; procedure SaveSettings(var s: TSettings; path: string); begin TRttiIni.Save(path, s); end; procedure LoadSettings; begin settings := TSettings.Create; TRttiIni.Load(PathList.Values['ProfilePath'] + 'settings.ini', settings); end; function LoadSettings(path: string): TSettings; begin Result := TSettings.Create; TRttiIni.Load(path, Result); end; procedure SaveStatistics; begin // move session statistics to general statistics Inc(statistics.timesRun, sessionStatistics.timesRun); Inc(statistics.patchesBuilt, sessionStatistics.patchesBuilt); Inc(statistics.pluginsPatched, sessionStatistics.pluginsPatched); Inc(statistics.settingsSubmitted, sessionStatistics.settingsSubmitted); Inc(statistics.recsSubmitted, sessionStatistics.recsSubmitted); // zero out session statistics sessionStatistics.timesRun := 0; sessionStatistics.patchesBuilt := 0; sessionStatistics.settingsSubmitted := 0; sessionStatistics.recsSubmitted := 0; // save to file TRttiIni.Save('statistics.ini', statistics); end; procedure LoadStatistics; begin statistics := TStatistics.Create; sessionStatistics := TStatistics.Create; TRttiIni.Load('statistics.ini', statistics); end; initialization begin ProgramStatus := TProgramStatus.Create; PathList := TStringList.Create; end; finalization begin ProgramStatus.Free; PathList.Free; end; end. ================================================ FILE: frontend/msConflict.pas ================================================ unit msConflict; interface uses Classes, SysUtils, // mte units mteBase, // ms units msCore, // xEdit units wbInterface, wbImplementation, wbHelpers; type // States used in InitNode to indicate states a node shall initially have. TVirtualNodeInitState = ( ivsDisabled, ivsExpanded, ivsHasChildren, ivsMultiline, ivsSelected, ivsFiltered, ivsReInit{>>>}, ivsHidden{<<<} ); TVirtualNodeInitStates = set of TVirtualNodeInitState; // navnode flags TNavNodeFlag = ( nnfInjected, nnfNotReachable, nnfReferencesInjected ); TNavNodeFlags = set of TNavNodeFlag; // navnode data PNavNodeData = ^TNavNodeData; TNavNodeData = record Element : IwbElement; Container : IwbContainer; ConflictAll : TConflictAll; ConflictThis : TConflictThis; Flags : TNavNodeFlags; end; // node flags TViewNodeFlag = ( vnfDontShow, vnfIgnore ); TViewNodeFlags = set of TViewNodeFlag; // node data PViewNodeData = ^TViewNodeData; TViewNodeData = record Element: IwbElement; Container: IwbContainerElementRef; ConflictAll: TConflictAll; ConflictThis: TConflictThis; ViewNodeFlags: TViewNodeFlags; end; // collections of node datas TViewNodeDatas = array[Word] of TViewNodeData; PViewNodeDatas = ^TViewNodeDatas; TDynViewNodeDatas = array of TViewNodeData; // exposed methods procedure ConflictLevelForMainRecord(const aMainRecord: IwbMainRecord; out aConflictAll: TConflictAll; out aConflictThis: TConflictThis); function ConflictLevelForChildNodeDatas(const aNodeDatas: TDynViewNodeDatas; aSiblingCompare, aInjected: Boolean): TConflictAll; function ConflictLevelForNodeDatas(const aNodeDatas: PViewNodeDatas; aNodeCount: Integer; aSiblingCompare, aInjected: Boolean): TConflictAll; function ConflictAllForElements(e1, e2: IwbElement; aSiblingCompare, aInjected: Boolean): TConflictAll; function ConflictThisForMainRecord(aMainRecord: IwbMainRecord): TConflictThis; function ConflictAllForMainRecord(aMainRecord: IwbMainRecord): TConflictAll; function IsITPO(rec: IwbMainRecord): Boolean; function IsITM(rec: IwbMainRecord): Boolean; implementation procedure AppendToNodeDatas(var NodeDatas: TDynViewNodeDatas; e: IwbElement); var Container: IwbContainerElementRef; begin SetLength(NodeDatas, Succ(Length(NodeDatas))); NodeDatas[Pred(Length(NodeDatas))].Element := e; if Supports(e, IwbContainerElementRef, Container) and (Container.ElementCount > 0) then NodeDatas[Pred(Length(NodeDatas))].Container := Container; end; function ConflictAllForElements(e1, e2: IwbElement; aSiblingCompare, aInjected: Boolean): TConflictAll; var NodeDatas: TDynViewNodeDatas; begin // prepare node datas AppendToNodeDatas(NodeDatas, e1); AppendToNodeDatas(NodeDatas, e2); // compute the conflict level Result := caUnknown; if Length(NodeDatas) > 0 then if Assigned(NodeDatas[0].Container) then Result := ConflictLevelForChildNodeDatas(NodeDatas, aSiblingCompare, aInjected) else Result := ConflictLevelForNodeDatas(@NodeDatas[0], Length(NodeDatas), aSiblingCompare, aInjected); end; function NodeDatasForMainRecord(const aMainRecord: IwbMainRecord): TDynViewNodeDatas; var Master : IwbMainRecord; Rec : IwbMainRecord; i, j : Integer; Records : TStringList; AnyHidden : Boolean; IsNonOverride : Boolean; EditorID : string; FormID : Cardinal; LoadOrder : Integer; Group : IwbGroupRecord; Signature : TwbSignature; plugin : TPlugin; aFile : IwbFile; begin Assert(wbLoaderDone); IsNonOverride := False; AnyHidden := False; if aMainRecord.Signature = 'GMST' then begin IsNonOverride := True; EditorID := aMainRecord.EditorID; SetLength(Result, PluginsList.Count); Master := nil; for i := 0 to Pred(PluginsList.Count) do begin plugin := TPlugin(PluginsList[i]); aFile := plugin._File; Group := aFile.GroupBySignature['GMST']; if Assigned(Group) then begin Rec := Group.MainRecordByEditorID[EditorID]; if Assigned(Rec) then begin if not Assigned(Master) then Master := Rec; Result[i].Element := Rec; end; end; end; end else if (aMainRecord.Signature = 'NAVI') (* or (aMainRecord.Signature = 'TES4') *) then begin IsNonOverride := True; Signature := aMainRecord.Signature; FormID := aMainRecord.FormID; LoadOrder := aMainRecord.GetFile.LoadOrder; SetLength(Result, 0); Master := nil; for i := 0 to Pred(PluginsList.Count) do begin plugin := TPlugin(PluginsList[i]); aFile := plugin._File; if aFile.LoadOrder = LoadOrder then begin Group := aFile.GroupBySignature[Signature]; if Assigned(Group) then begin Rec := Group.MainRecordByFormID[FormID]; if Assigned(Rec) then begin j := Length(Result); SetLength(Result, j+1); if not Assigned(Master) then Master := Rec; Result[j].Element := Rec; end; end; end; end; end else if (aMainRecord.Signature = 'TES4') then begin IsNonOverride := True; Signature := aMainRecord.Signature; LoadOrder := aMainRecord.GetFile.LoadOrder; SetLength(Result, 0); Master := nil; for i := 0 to Pred(PluginsList.Count) do begin plugin := TPlugin(PluginsList[i]); aFile := plugin._File; if aFile.LoadOrder = LoadOrder then begin // header of .dat file, show only itself if SameText(ExtractFileExt(aMainRecord.GetFile.FileName), '.dat') and not SameText(ExtractFileExt(aFile.FileName), '.dat') then Continue; // skip .dat file header by default if not SameText(ExtractFileExt(aMainRecord.GetFile.FileName), '.dat') and SameText(ExtractFileExt(aFile.FileName), '.dat') then Continue; Rec := aFile.Elements[0] as IwbMainRecord; if Assigned(Rec) then begin j := Length(Result); SetLength(Result, j+1); if not Assigned(Master) then Master := Rec; Result[j].Element := Rec; end; end; end; end else begin Master := aMainRecord.MasterOrSelf; SetLength(Result, Succ(Master.OverrideCount)); AnyHidden := Master.IsHidden; if not AnyHidden then for i := 0 to Pred(Master.OverrideCount) do begin AnyHidden := Master.Overrides[i].IsHidden; if AnyHidden then Break; end; end; if (Length(Result) > 1) and ({ModGroupsEnabled or }AnyHidden) or IsNonOverride then begin Records := TStringList.Create; try if IsNonOverride then begin for i := Low(Result) to High(Result) do if Supports(Result[i].Element, IwbMainRecord, Rec) then Records.AddObject(Rec._File.FileName, Pointer(Rec)); Result := nil; end else begin Records.AddObject(Master._File.FileName, Pointer(Master)); for i := 0 to Pred(Master.OverrideCount) do begin Rec := Master.Overrides[i]; Records.AddObject(Rec._File.FileName, Pointer(Rec)); end; end; {f ModGroupsEnabled then repeat MadeChanges := False; sl := TStringList.Create; try for i := 0 to Pred(ModGroups.Count) do begin sl.Assign(TStrings(ModGroups.Objects[i])); for j := Pred(sl.Count) downto 0 do begin k := Records.IndexOf(sl[j]); if K > 0 then // >, not >=, never hide the original master sl.Objects[j] := TObject(k) else sl.Delete(j); end; if sl.Count > 1 then begin k := Integer(sl.Objects[0]); j := 1; if k = 0 then begin while (j < sl.Count) and (Integer(sl.Objects[j]) = k + 1) do begin Records.Objects[Integer(sl.Objects[Pred(j)])] := nil; Inc(k); Inc(j); end; Inc(j); end; while (j < sl.Count) do begin Records.Objects[Integer(sl.Objects[Pred(j)])] := nil; Inc(j); end; for j := Pred(Records.Count) downto 0 do if Records.Objects[j] = nil then begin Records.Delete(j); MadeChanges := True; end; end; if Records.Count < 2 then Break; end; finally sl.Free; end; until not MadeChanges;} i := 0; while (i < Records.Count) and (Records.Count > 1) do if IwbElement(Pointer(Records.Objects[i])).IsHidden then Records.Delete(i) else Inc(i); SetLength(Result, Records.Count); for i := 0 to Pred(Records.Count) do with Result[i] do begin Rec := IwbMainRecord(Pointer(Records.Objects[i])); if i = 0 then Master := Rec; Container := Rec as IwbContainerElementRef; Element := Container; if (Container.ElementCount = 0) or (Rec.Signature <> Master.Signature) then Container := nil; end; finally FreeAndNil(Records); end; Exit; end; Result[0].Element := Master; Result[0].Container := Master as IwbContainerElementRef; if Master.ElementCount < 1 then Result[0].Container := nil; for i := 0 to Pred(Master.OverrideCount) do with Result[Succ(i)] do begin Container := Master.Overrides[i] as IwbContainerElementRef; Element := Container; if (Container.ElementCount = 0) or (Master.Overrides[i].Signature <> Master.Signature) then Container := nil; end; end; procedure ConflictLevelForMainRecord(const aMainRecord: IwbMainRecord; out aConflictAll: TConflictAll; out aConflictThis: TConflictThis); procedure Fix(const aMainRecord: IwbMainRecord); begin with aMainRecord do begin ConflictAll := aConflictAll; if ConflictThis = ctUnknown then begin ConflictThis := ctHiddenByModGroup; end; end; end; var NodeDatas : TDynViewNodeDatas; i : Integer; Master : IwbMainRecord; KeepAliveRoot : IwbKeepAliveRoot; begin KeepAliveRoot := wbCreateKeepAliveRoot; aConflictAll := aMainRecord.ConflictAll; aConflictThis := aMainRecord.ConflictThis; if aConflictAll > caUnknown then Exit; Master := aMainRecord.MasterOrSelf; if (Master.OverrideCount = 0) and not wbTranslationMode and not (Master.Signature = 'GMST') then begin aConflictAll := caOnlyOne; aConflictThis := ctOnlyOne; aMainRecord.ConflictAll := aConflictAll; aMainRecord.ConflictThis := aConflictThis; end else begin NodeDatas := NodeDatasForMainRecord(aMainRecord); if Length(NodeDatas) = 1 then begin aConflictAll := caOnlyOne; NodeDatas[0].ConflictAll := caOnlyOne; NodeDatas[0].ConflictThis := ctOnlyOne; {end else if wbQuickShowConflicts and (Length(NodeDatas) = 2) then begin aConflictAll := caOverride; NodeDatas[0].ConflictAll := caOverride; NodeDatas[1].ConflictAll := caOverride; NodeDatas[0].ConflictThis := ctMaster; NodeDatas[1].ConflictThis := ctOverride;} end else aConflictAll := ConflictLevelForChildNodeDatas(NodeDatas, False, (aMainRecord.MasterOrSelf.IsInjected and not (aMainRecord.Signature = 'GMST')) ); for i := Low(NodeDatas) to High(NodeDatas) do with NodeDatas[i] do if Assigned(Element) then with (Element as IwbMainRecord) do begin ConflictAll := aConflictAll; ConflictThis := NodeDatas[i].ConflictThis; end; Fix(Master); for i := 0 to Pred(Master.OverrideCount) do Fix(Master.Overrides[i]); aConflictThis := aMainRecord.ConflictThis; end; end; procedure InitChilds(const aNodeDatas: PViewNodeDatas; aNodeCount: Integer; var aChildCount: Cardinal); var NodeData : PNavNodeData; Container : IwbContainer; FirstContainer : IwbContainer; SortableContainer : IwbSortableContainer; Element : IwbElement; i, j, k : Integer; SortedCount : Integer; NonSortedCount : Integer; SortedKeys : array of TnxFastStringListCS; Sortables : array of IwbSortableContainer; SortKey : string; LastSortKey : string; DupCounter : Integer; begin SortedCount := 0; NonSortedCount := 0; FirstContainer := nil; for i := 0 to Pred(aNodeCount) do begin NodeData := @aNodeDatas[i]; Container := NodeData.Container; if not Assigned(FirstContainer) then FirstContainer := Container; if Assigned(Container) then if Supports(Container, IwbSortableContainer, SortableContainer) and SortableContainer.Sorted then Inc(SortedCount) else Inc(NonSortedCount); end; if (NonSortedCount > 0) and (SortedCount > 0) then begin if Assigned(FirstContainer) then ;//PostAddMessage('Warning: Comparing sorted and unsorted entry for "' + FirstContainer.Path + '" in "'+FirstContainer.ContainingMainRecord.Name+'"'); SortedCount := 0; end; if SortedCount > 0 then begin // Assert(NonSortedCount = 0); SetLength(SortedKeys, Succ(aNodeCount)); for i := Low(SortedKeys) to High(SortedKeys) do begin SortedKeys[i] := TnxFastStringListCS.Create; SortedKeys[i].Sorted := True; SortedKeys[i].Duplicates := dupError; end; try SortedKeys[aNodeCount].Duplicates := dupIgnore; SetLength(Sortables, aNodeCount); for i := 0 to Pred(aNodeCount) do if Supports(aNodeDatas[i].Container, IwbSortableContainer, Sortables[i]) then begin SortableContainer := Sortables[i]; DupCounter := 0; LastSortKey := ''; for j := 0 to Pred(SortableContainer.ElementCount) do begin Element := SortableContainer.Elements[j]; SortKey := Element.SortKey[False]; if SameStr(LastSortKey, SortKey) then Inc(DupCounter) else begin DupCounter := 0; LastSortKey := SortKey; end; SortKey := SortKey + '<' + IntToHex64(DupCounter, 4) + '>'; SortedKeys[i].AddObject(SortKey, Pointer(Element)); SortedKeys[aNodeCount].Add(SortKey); end; end; aChildCount := SortedKeys[aNodeCount].Count; for j := 0 to Pred(aChildCount) do begin SortKey := SortedKeys[aNodeCount].Strings[j]; for i := 0 to Pred(aNodeCount) do if SortedKeys[i].Find(SortKey, k) then IwbElement(Pointer(SortedKeys[i].Objects[k])).SortOrder := j; end; finally for i := Low(SortedKeys) to High(SortedKeys) do FreeAndNil(SortedKeys[i]); end; end else for i := 0 to Pred(aNodeCount) do begin NodeData := @aNodeDatas[i]; Container := NodeData.Container; if Assigned(Container) then begin case Container.ElementType of etMainRecord, etSubRecordStruct: begin aChildCount := (Container.Def as IwbRecordDef).MemberCount; Inc(aChildCount, Container.AdditionalElementCount); if Cardinal(Container.ElementCount) > aChildCount then begin //PostAddMessage('Error: Container.ElementCount {'+IntToStr(Container.ElementCount)+'} > aChildCount {'+IntToStr(aChildCount)+'} for ' + Container.Path + ' in ' + Container.ContainingMainRecord.Name); //for j := 0 to Pred(Container.ElementCount) do //PostAddMessage(' #'+IntToStr(j)+': ' + Container.Elements[j].Name); //Assert(Cardinal(Container.ElementCount) <= aChildCount); end; end; etSubRecordArray, etArray, etStruct, etSubRecord, etValue, etUnion, etStructChapter: if aChildCount < Cardinal(Container.ElementCount) then aChildCount := Container.ElementCount; end; end; end; end; procedure InitNodes(const aNodeDatas: PViewNodeDatas; const aParentDatas: PViewNodeDatas; aNodeCount: Integer; aIndex: Cardinal; var aInitialStates: TVirtualNodeInitStates); var NodeData : PViewNodeData; ParentData : PViewNodeData; Container : IwbContainerElementRef; SortableContainer : IwbSortableContainer; i : Integer; begin for i := 0 to Pred(aNodeCount) do begin NodeData := @aNodeDatas[i]; ParentData := @aParentDatas[i]; Container := ParentData.Container; if Assigned(Container) then begin if Supports(Container, IwbSortableContainer, SortableContainer) and SortableContainer.Sorted then NodeData.Element := Container.ElementBySortOrder[aIndex] else case Container.ElementType of etMainRecord, etSubRecordStruct: NodeData.Element := Container.ElementBySortOrder[aIndex]; etSubRecordArray, etArray, etStruct, etSubRecord, etValue, etUnion, etStructChapter: if aIndex < Cardinal(Container.ElementCount) then NodeData.Element := Container.Elements[aIndex]; end; end; if Assigned(NodeData.Element) and NodeData.Element.DontShow then begin NodeData.Element := nil; Include(NodeData.ViewNodeFlags, vnfDontShow); end; end; aInitialStates := [ivsDisabled]; for i := 0 to Pred(aNodeCount) do with aNodeDatas[i] do begin if Assigned(Element) then Exclude(aInitialStates, ivsDisabled) else if Assigned(aParentDatas) and ((vnfIgnore in aParentDatas[i].ViewNodeFlags) or (Assigned(aParentDatas[i].Element) and (aParentDatas[i].Element.ConflictPriority = cpIgnore))) then Include(ViewNodeFlags, vnfIgnore); if not Assigned(Container) then if Supports(Element, IwbContainerElementRef, Container) then begin // if Container.ElementCount = 0 then // Container := nil; end; if Assigned(Container) then if Container.ElementCount > 0 then Include(aInitialStates, ivsHasChildren); end; end; function ConflictLevelForChildNodeDatas(const aNodeDatas: TDynViewNodeDatas; aSiblingCompare, aInjected: Boolean): TConflictAll; var ChildCount : Cardinal; i, j : Integer; NodeDatas : TDynViewNodeDatas; InitialStates : TVirtualNodeInitStates; ConflictAll : TConflictAll; ConflictThis : TConflictThis; Element : IwbElement; begin case Length(aNodeDatas) of 0: Result := caUnknown; 1: begin Result := caOnlyOne; aNodeDatas[0].ConflictThis := ctOnlyOne; end; else Result := caNoConflict; end; if wbTranslationMode then begin if Result < caOnlyOne then Exit; end else begin if Result < caNoConflict then Exit; end; ChildCount := 0; InitChilds(@aNodeDatas[0], Length(aNodeDatas), ChildCount); if ChildCount > 0 then for i := 0 to Pred(ChildCount) do begin NodeDatas := nil; SetLength(NodeDatas, Length(aNodeDatas)); InitialStates := []; InitNodes(@NodeDatas[0], @aNodeDatas[0], Length(aNodeDatas), i, InitialStates); if not (ivsDisabled in InitialStates) then begin if ivsHasChildren in InitialStates then ConflictAll := ConflictLevelForChildNodeDatas(NodeDatas, aSiblingCompare, aInjected) else ConflictAll := ConflictLevelForNodeDatas(@NodeDatas[0], Length(NodeDatas), aSiblingCompare, aInjected); if ConflictAll > Result then Result := ConflictAll; for j := Low(aNodeDatas) to High(aNodeDatas) do if NodeDatas[j].ConflictThis > aNodeDatas[j].ConflictThis then aNodeDatas[j].ConflictThis := NodeDatas[j].ConflictThis; end else begin ConflictThis := ctNotDefined; for j := Low(aNodeDatas) to High(aNodeDatas) do begin Element := aNodeDatas[j].Container; if Assigned(Element) then Break; end; if Assigned(Element) and (Element.ElementType in [etMainRecord, etSubRecordStruct]) then begin j := (Element as IwbContainer).AdditionalElementCount; if i >= j then with (Element.Def as IwbRecordDef).Members[i - j] do if (wbTranslationMode and (ConflictPriority[nil] <> cpTranslate)) or (wbTranslationMode and (ConflictPriority[nil] = cpIgnore)) then ConflictThis := ctIgnored; end; for j := Low(aNodeDatas) to High(aNodeDatas) do if ConflictThis > aNodeDatas[j].ConflictThis then aNodeDatas[j].ConflictThis := ConflictThis; end; end; end; function ConflictLevelForNodeDatas(const aNodeDatas: PViewNodeDatas; aNodeCount: Integer; aSiblingCompare, aInjected: Boolean): TConflictAll; var Element : IwbElement; CompareElement : IwbElement; i, j : Integer; UniqueValues : TnxFastStringListCS; MasterPosition : Integer; FirstElement : IwbElement; FirstElementNotIgnored : IwbElement; LastElement : IwbElement; SameAsLast : Boolean; SameAsFirst : Boolean; OverallConflictThis : TConflictThis; Priority : TwbConflictPriority; ThisPriority : TwbConflictPriority; FoundAny : Boolean; begin // if aSiblingCompare then // Priority := cpBenign // else // Priority := cpNormal; // IgnoreConflicts := False; FoundAny := False; MasterPosition := 0; OverallConflictThis := ctUnknown; case aNodeCount of 0: Result := caUnknown; 1: begin Element := aNodeDatas[0].Element; if Assigned(Element) then begin if Element.ConflictPriority = cpIgnore then aNodeDatas[0].ConflictThis := ctIgnored else aNodeDatas[0].ConflictThis := ctOnlyOne; end else aNodeDatas[0].ConflictThis := ctNotDefined; Result := caOnlyOne; end else LastElement := aNodeDatas[Pred(aNodeCount)].Element; FirstElement := aNodeDatas[0].Element; UniqueValues := TnxFastStringListCS.Create; UniqueValues.Sorted := True; UniqueValues.Duplicates := dupIgnore; Priority := cpNormal; try for i := 0 to Pred(aNodeCount) do begin Element := aNodeDatas[i].Element; if Assigned(Element) then begin FoundAny := True; Priority := Element.ConflictPriority; if Priority = cpNormalIgnoreEmpty then begin FirstElement := Element; MasterPosition := i; for j := Pred(aNodeCount) downto i do begin LastElement := aNodeDatas[j].Element; if Assigned(LastElement) then Break; end; end; if Element.ConflictPriorityCanChange then begin for j := Succ(i) to Pred(aNodeCount) do begin Element := aNodeDatas[j].Element; if Assigned(Element) then begin ThisPriority := Element.ConflictPriority; if ThisPriority > Priority then Priority := ThisPriority; end; end; end; Break; end; end; if aSiblingCompare then if Priority > cpBenign then Priority := cpBenign; if aInjected and (Priority >= cpNormal) then Priority := cpCritical; if (Priority > cpIgnore) and (not Assigned(FirstElement) or (FirstElement.ConflictPriority = cpIgnore)) then FirstElementNotIgnored := nil else FirstElementNotIgnored := FirstElement; for i := 0 to Pred(aNodeCount) do begin Element := aNodeDatas[i].Element; if Assigned(Element) then begin ThisPriority := Element.ConflictPriority; if ThisPriority <> cpIgnore then UniqueValues.Add(Element.SortKey[True]); end else begin ThisPriority := Priority; if not (vnfIgnore in aNodeDatas[i].ViewNodeFlags) then if Priority <> cpNormalIgnoreEmpty then UniqueValues.Add(''); end; if (ThisPriority = cpNormalIgnoreEmpty) and not Assigned(Element) then aNodeDatas[i].ConflictThis := ctIgnored else if ThisPriority = cpIgnore then aNodeDatas[i].ConflictThis := ctIgnored else if aSiblingCompare then aNodeDatas[i].ConflictThis := ctOnlyOne else if i = MasterPosition then begin if Assigned(Element) then aNodeDatas[i].ConflictThis := ctMaster else aNodeDatas[i].ConflictThis := ctUnknown; end else begin SameAsLast := (i = Pred(aNodeCount)) or not ( (Assigned(Element) <> Assigned(LastElement)) or (Assigned(Element) and not SameStr(Element.SortKey[True], LastElement.SortKey[True])) ); SameAsFirst := not ( (Assigned(Element) <> Assigned(FirstElementNotIgnored)) or (Assigned(Element) and not SameStr(Element.SortKey[True], FirstElementNotIgnored.SortKey[True])) ); if not SameAsFirst and (ThisPriority = cpBenignIfAdded) and SameAsLast and // We are not overriden later not Assigned(FirstElementNotIgnored) then begin // The master did not have that element ThisPriority := cpBenign; Priority := cpBenign; SameAsFirst := True; end; if SameAsFirst then aNodeDatas[i].ConflictThis := ctIdenticalToMaster else if SameAsLast then aNodeDatas[i].ConflictThis := ctConflictWins else aNodeDatas[i].ConflictThis := ctConflictLoses; end; if (ThisPriority = cpBenign) and (aNodeDatas[i].ConflictThis > ctConflictBenign) then aNodeDatas[i].ConflictThis := ctConflictBenign; if aNodeDatas[i].ConflictThis > OverallConflictThis then OverallConflictThis := aNodeDatas[i].ConflictThis; end; case UniqueValues.Count of 0: Result := caNoConflict; 1: Result := caNoConflict; 2: begin Element := aNodeDatas[0].Element; CompareElement := aNodeDatas[Pred(aNodeCount)].Element; if (Assigned(Element) <> Assigned(CompareElement)) or (Assigned(Element) and not SameStr(Element.SortKey[True], CompareElement.SortKey[True])) then Result := caOverride else if (UniqueValues.IndexOf('') >= 0) and Assigned(CompareElement) and (CompareElement.SortKey[True] <> '') then Result := caOverride else Result := caConflict; end else Result := caConflict; end; if aSiblingCompare and (Result > caConflictBenign) then Result := caConflictBenign; if not FoundAny then for i := 0 to Pred(aNodeCount) do aNodeDatas[i].ConflictThis := ctNotDefined; if Result > caNoConflict then case Priority of cpBenign: Result := caConflictBenign; cpCritical: begin if UniqueValues.Find('', i) then UniqueValues.Delete(i); if UniqueValues.Count > 1 then Result := caConflictCritical; end; end; if Priority > cpBenign then if OverallConflictThis > ctOverride then with aNodeDatas[Pred(aNodeCount)] do if ConflictThis < ctOverride then if ConflictThis = ctIdenticalToMaster then ConflictThis := ctIdenticalToMasterWinsConflict else ConflictThis := ctConflictWins; if Result in [caNoConflict, caOverride, caConflict] then for i := 0 to Pred(aNodeCount) do begin case aNodeDatas[i].ConflictThis of ctIdenticalToMaster: case Result of caNoConflict: ; caOverride, caConflict: if i = Pred(aNodeCount) then aNodeDatas[i].ConflictThis := ctIdenticalToMasterWinsConflict end; ctConflictWins: case Result of caNoConflict: aNodeDatas[i].ConflictThis := ctIdenticalToMaster; caOverride: aNodeDatas[i].ConflictThis := ctOverride; caConflict: ; end; end; end; if Result < caConflict then for i := 0 to Pred(aNodeCount) do if aNodeDatas[i].ConflictThis >= ctIdenticalToMasterWinsConflict then begin Result := caConflict; Break; end; finally FreeAndNil(UniqueValues); end; end; end; function ConflictThisForMainRecord(aMainRecord: IwbMainRecord): TConflictThis; var ct: TConflictThis; ca: TConflictAll; begin ConflictLevelForMainRecord(aMainRecord, ca, ct); Result := ct; end; function ConflictAllForMainRecord(aMainRecord: IwbMainRecord): TConflictAll; var ct: TConflictThis; ca: TConflictAll; begin ConflictLevelForMainRecord(aMainRecord, ca, ct); Result := ca; end; function IsITPO(rec: IwbMainRecord): Boolean; var mRec, prevOvr, ovr: IwbMainRecord; i: Integer; begin // get previous override mRec := rec.MasterOrSelf; prevovr := mRec; for i := 0 to Pred(mRec.OverrideCount) do begin ovr := mRec.Overrides[i]; if ovr.Equals(rec) then Break; prevovr := ovr; end; Result := ConflictAllForElements(prevovr, rec, False, False) <= caNoConflict; end; function IsITM(rec: IwbMainRecord): Boolean; const ITMConflictArray: set of TConflictThis = [ ctIdenticalToMaster, ctIdenticalToMasterWinsConflict ]; begin Result := ConflictThisForMainRecord(rec) in ITMConflictArray; end; end. ================================================ FILE: frontend/msConflictForm.dfm ================================================ object ConflictForm: TConflictForm Left = 0 Top = 0 Caption = 'Combine smash settings' ClientHeight = 377 ClientWidth = 709 Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'Tahoma' Font.Style = [] OldCreateOrder = False OnClose = FormClose OnCreate = FormCreate OnShow = FormShow PixelsPerInch = 96 TextHeight = 13 object btnOK: TButton Left = 545 Top = 344 Width = 75 Height = 25 Align = alCustom Anchors = [akRight, akBottom] Caption = 'OK' TabOrder = 0 OnClick = btnOKClick end object btnCancel: TButton Left = 626 Top = 344 Width = 75 Height = 25 Align = alCustom Anchors = [akRight, akBottom] Caption = 'Cancel' ModalResult = 2 TabOrder = 1 end object tvRecords: TTreeView Left = 301 Top = 8 Width = 400 Height = 330 Align = alCustom Anchors = [akTop, akRight, akBottom] DoubleBuffered = True Indent = 19 MultiSelect = True ParentDoubleBuffered = False ReadOnly = True StateImages = StateImages TabOrder = 2 OnCustomDrawItem = tvRecordsCustomDrawItem OnMouseMove = tvRecordsMouseMove end object sbChoices: TScrollBox Left = 8 Top = 8 Width = 287 Height = 330 Align = alCustom Anchors = [akLeft, akTop, akRight, akBottom] TabOrder = 3 end object FlagIcons: TImageList Left = 408 Top = 24 Bitmap = { 494C010103000800540010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600 0000000000003600000028000000400000001000000001002000000000000010 0000000000000000000000000000000000000000000000000000000000000000 0000D7D7F8FF7373E6FF3434DBFF2121BEFF2121BEFF2D2DDAFF6B6BE4FFD2D2 F7FF000000000000000000000000000000000000000000000000000000000000 0000E4F1E779D7D6B8CCD4BF91F3D2B683FED2B581FED1BD8FF3D5D3B5CCE3F0 E6790000000000000000000000000000000000000000D1D1D12E4F4F4FB01B1B 1BE42B2B2BD48282827DF7F7F708000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000F8F8FDFF7373 E6FF2020B5FF2020B5FF3434DBFF5B5BE2FF5B5BE2FF3D3DDCFF2020B5FF2020 B5FF6464E3FFF8F8FDFF00000000000000000000000000000000F2F8F33CD9D8 BACBDCAB6CFEE1974BFFE18F3DFFE18A37FFDF8835FFDD8A39FFD99044FFD4A3 64FED4D4B6CBF1F7F23C0000000000000000D1D1D12E0C0C0CF3000000FF0000 00FF000000FF000000FF3B3B3BC4F2F2F20D0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000F8F8FDFF4242DDFF2020 B5FF5353E0FFD7D7F8FF00000000000000000000000000000000E2E2F9FF5B5B E2FF2020B5FF3D3DDCFFEFEFFCFF0000000000000000F2F8F33CDBCDA5DEE3A1 58FFE69240FFE58F3AFFE48D39FFE28B37FFE08A36FFDF8834FFDD8733FFDB87 35FFD7944CFFD3C49DDEF1F7F23C000000004E4E4EB1000000FF4D4D4DB2D7D7 D728B2B2B24D1A1A1AE5000000FF3A3A3AC5F2F2F20D00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000007373E6FF2020B5FF8282 E9FF000000000000000000000000FEFEFE03FDFDFE0700000000000000000000 00009292EBFF2020B5FF6464E3FF0000000000000000DBDABCCBE6A35AFFE994 41FFE8923EFFE7903CFFE58E3AFFE38D38FFE28B37FFE08935FFDF8834FFDD86 32FFDC8633FFD6944BFFD4D3B5CB000000001B1B1BE4000000FFD7D7D7280000 000000000000D9D9D9261B1B1BE4000000FF3A3A3AC5F2F2F20D000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000D7D7F8FF2020B5FF5353E0FF0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000006464E3FF2020B5FFC8C8F5FFE6F3E879E3B273FEEC9846FFEB95 41FFEA933FFFE8913DFFEAA560FFF9F7F5FFF8F0E8FFE18B37FFE08935FFDE88 33FFDD8632FFDA8735FFD3A263FEE3F0E6792B2B2BD4000000FFB3B3B34C0000 00000000000000000000D9D9D926BABABA45EFEFEF10F3F3F30C000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000007A7AE7FF2020B5FFD2D2F7FF0000 00000000000000000000FEFEFE0D0000000000000000F4F4FC28000000000000 000000000000E2E2F9FF2020B5FF6B6BE4FFDDDBBDCCEBA256FFEE9844FFED96 42FFEB9440FFE9933FFFEBA562FFF9F7F5FFF8F0E8FFE38C38FFE18A36FFE089 35FFDE8733FFDD8632FFD88F43FFD4D3B5CC8383837C000000FF1A1A1AE5D9D9 D9260000000000000000C3C3C33C424242BD131313EC262626D97F7F7F80F7F7 F708000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000003434DBFF3434DBFF000000000000 0000B9B9F2FFB9B9F2FFB9B9F2FFB9B9F2FFB9B9F2FFB9B9F2FFB9B9F2FFB9B9 F2FFEFEFFCFF000000004242DDFF2525D6FFDDC89AF3F09D4BFFF09945FFEE97 43FFED9642FFEB9440FFECA663FFF9F7F5FFF8F0E9FFE48D39FFE28C38FFE18A 36FFDF8934FFDE8733FFDB8937FFD1BC8DF3F7F7F7083B3B3BC4000000FF1B1B 1BE4D9D9D926E3E3E31C060606F9000000FF000000FF000000FF000000FF3B3B 3BC4F2F2F20D0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000002323C6FF5353E0FF000000000000 00002121BEFF2020B5FF2020B5FF2020B5FF2020B5FF2020B5FF2020B5FF2020 B5FFC8C8F5FF000000006464E3FF2121BEFFDFC38FFEF39C49FFF19A46FFEF99 44FFEE9743FFEC9541FFEEA864FFF9F7F5FFF8F0E9FFE68F3BFFE48D39FFE28B 37FFE18A36FFDF8834FFDD8734FFD0B480FE00000000F2F2F20D3A3A3AC50000 00FF1B1B1BE4CECECE31444444BB7171718EE1E1E11EB7B7B7481A1A1AE50000 00FF3A3A3AC5F2F2F20D00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000002323C6FF5353E0FF000000000000 00002020B5FF2020B5FF2020B5FF2020B5FF2020B5FF2020B5FF2020B5FF2020 B5FFC8C8F5FF000000006464E3FF2121BEFFE0C390FEF49D4AFFF29B47FFF19A 46FFEF9844FFEE9743FFEFA965FFF9F7F5FFF8F0E9FFE7903CFFE58E3AFFE48D 39FFE28B37FFE08A35FFDF8835FFD1B581FE0000000000000000F2F2F20D3A3A 3AC5000000FF1A1A1AE5B8B8B847E1E1E11E7171718E444444BBCECECE311B1B 1BE4000000FF3A3A3AC5F2F2F20D000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000003D3DDCFF2D2DDAFF000000000000 0000F8F8FDFFF8F8FDFFEFEFFCFFEFEFFCFFEFEFFCFFEFEFFCFFEFEFFCFFF8F8 FDFFF8F8FDFF000000003D3DDCFF2525D6FFDFCA9CF3F3A14FFFF39D48FFF29B 47FFF09A45FFEF9844FFF0B172FFF9F7F5FFF8F0E9FFE8913DFFE7903CFFE58E 3AFFE38C38FFE28B37FFDF8C3BFFD2BE90F3000000000000000000000000F2F2 F20D3B3B3BC4000000FF000000FF000000FF000000FF060606F9E3E3E31CD9D9 D9261B1B1BE4000000FF3B3B3BC4F7F7F7080000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000007373E6FF2020B5FFD2D2F7FF0000 0000000000000000000000000000F1F1FA0FFAFAFD05F1F1FC32000000000000 000000000000E2E2F9FF2020B5FF6B6BE4FFDFDDBFCCF1A85BFFF49E4AFFF39C 48FFF29B47FFF5CBA3FFF9F7F5FFF9F7F5FFF8F0E9FFEA933FFFE8913DFFE68F 3BFFE58E3AFFE38C38FFDE9548FFD7D5B7CC0000000000000000000000000000 0000F7F7F7087F7F7F80262626D9131313EC424242BDC3C3C33C000000000000 0000D9D9D9261A1A1AE5000000FF8383837C0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000D7D7F8FF2020B5FF5353E0FF0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000006464E3FF2020B5FFC8C8F5FFE7F3E979E9B879FEF4A14FFFF49D 49FFF39C48FFF19B46FFF19F51FFF6DEC6FFF8F1E9FFEB9440FFE9933EFFE891 3DFFE68F3BFFE3903DFFDAA96AFEE4F1E7790000000000000000000000000000 00000000000000000000F3F3F30CEFEFEF10BABABA45D9D9D926000000000000 000000000000B3B3B34C000000FF2C2C2CD30000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000007A7AE7FF2020B5FF8282 E9FF000000000000000000000000000000000000000000000000000000000000 00008B8BEAFF2020B5FF6464E3FF0000000000000000DFDEC0CBEFAD64FFF4A0 4CFFF49D49FFF39C48FFF19A46FFF09945FFEE9743FFEC9641FFEB9440FFE992 3EFFE7913EFFE19E55FFD8D7B9CB000000000000000000000000000000000000 00000000000000000000F2F2F20D3A3A3AC5000000FF1B1B1BE4D9D9D9260000 000000000000D7D7D728000000FF1B1B1BE40000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000F8F8FDFF4242DDFF2020 B5FF5353E0FFD7D7F8FF00000000000000000000000000000000D7D7F8FF5B5B E2FF2020B5FF4242DDFFEFEFFCFF0000000000000000F3F9F43CE1D2ABDEEFAD 63FFF4A04EFFF49D49FFF29B47FFF19A46FFEF9944FFEE9743FFEC9541FFE996 43FFE3A158FFD9CAA3DEF2F8F33C000000000000000000000000000000000000 0000000000000000000000000000F2F2F20D3A3A3AC5000000FF1A1A1AE5B3B3 B34CD7D7D7284E4E4EB1000000FF4F4F4FB00000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000F8F8FDFF7373 E6FF2020B5FF2020B5FF3434DBFF6464E3FF5B5BE2FF3D3DDCFF2020B5FF2020 B5FF6B6BE4FFEFEFFCFF00000000000000000000000000000000F3F9F43CDFDD C0CBE8B778FEF0A75AFFF2A04EFFF29B48FFF19A47FFEE9B49FFE9A053FFE0B0 71FEDAD9BCCBF2F8F33C00000000000000000000000000000000000000000000 000000000000000000000000000000000000F2F2F20D3B3B3BC4000000FF0000 00FF000000FF000000FF0C0C0CF3D2D2D22D0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D7D7F8FF7373E6FF2D2DDAFF2121BEFF2121BEFF2D2DDAFF6B6BE4FFD2D2 F7FF000000000000000000000000000000000000000000000000000000000000 0000E6F3E979DFDCBFCCDEC99BF3DFC28EFEDEC18EFEDCC799F3DCDABCCCE5F2 E879000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000F7F7F7088282827D2B2B 2BD41C1C1CE34F4F4FB0D2D2D22D000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000424D3E000000000000003E000000 2800000040000000100000000100010000000000800000000000000000000000 000000000000000000000000FFFFFF00F00FF00F81FF0000C003C00300FF0000 83C18001007F00008E718001183F00001FF800001C3F00001DB800000C0F0000 3004000000070000300400008003000030040000C001000030040000E0000000 1E380000F03000001FF80000FC3800008FF18001FC18000083C18001FE000000 C003C003FF000000F00FF00FFF81000000000000000000000000000000000000 000000000000} end object StateImages: TImageList Height = 17 Width = 17 Left = 336 Top = 24 Bitmap = { 494C010104000800500011001100FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600 0000000000003600000028000000440000002200000001002000000000002024 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F 8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F 8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F 8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F 8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F 8EFF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFF8F8F8EFF8F8F 8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F 8EFF8F8F8EFF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4 F4FFF4F4F4FFF4F4F4FFF5F5F5FFF9F9F9FFF8F8F8FFF5F5F5FFF4F4F4FFF4F4 F4FFF4F4F4FFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F 8EFFF4F4F4FFF4F4F4FFF4F4F4FFF5F5F5FFF9F9F9FFF8F8F8FFF5F5F5FFF4F4 F4FFF4F4F4FFF4F4F4FFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFF8F8F8EFFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4 F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFF8F8F8EFFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4 F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FF8F8F8EFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FFCCCBCAFFDBDADAFFE9E2DFFFBA99 8CFFBD9D90FFF6F3F2FFEDEDECFFECEBEBFFEAE9E9FFF4F4F4FF8F8F8EFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FFCCCBCAFFDBDADAFFE9E2 DFFFBA998CFFBD9D90FFF6F3F2FFEDEDECFFECEBEBFFEAE9E9FFF4F4F4FF8F8F 8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FFCCCBCAFFD5D4 D4FFDCDBDBFFE1E1E0FFE7E7E6FFEBEBEAFFECECEBFFECEBEBFFEAE9E9FFF4F4 F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FF714E 21FF6A491FFF61441DFF593E1AFF553B19FF553B19FF553A19FF553A19FF553B 19FFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4 F4FFCAC8C6FFF0ECEAFFBB998BFF975F4AFF98614CFFD1B9B0FFF9F9F9FFF6F6 F6FFE6E6E6FFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F 8EFFF4F4F4FFCAC8C6FFF0ECEAFFBB998BFF975F4AFF98614CFFD1B9B0FFF9F9 F9FFF6F6F6FFE6E6E6FFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFF8F8F8EFFF4F4F4FFC6C4C2FFE9E9E9FFEDEDEDFFF0F0F0FFF4F4F4FFF6F6 F6FFF6F6F6FFF6F6F6FFE6E6E6FFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFF8F8F8EFFF4F4F4FF755123FFB89255FFAE864CFFA47A44FF996E 3BFF936532FF8F5F2CFF8C5925FF553B19FFF4F4F4FF8F8F8EFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FFD1CFCDFFE9E1DEFF955D48FF965F 49FF97604BFFA47361FFFAF9F8FFF4F4F4FFE2E2E1FFF4F4F4FF8F8F8EFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FFD1CFCDFFE9E1DEFF955D 48FF965F49FF97604BFFA47361FFFAF9F8FFF4F4F4FFE2E2E1FFF4F4F4FF8F8F 8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FFC2BFBCFFE5E4 E3FFE9E9E9FFEDEDEDFFF2F2F2FFF4F4F4FFF5F5F5FFF4F4F4FFE2E2E1FFF4F4 F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FF7B55 24FFC29D5DFFB38927FFAA8124FFA07822FF966F1FFF8F691EFF8F602CFF553B 19FFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4 F4FFE1E0DEFFAA7F6EFF945C47FFE2D4CFFFA77867FF97604BFFD5BFB7FFF6F6 F6FFDEDDDCFFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F 8EFFF4F4F4FFE1E0DEFFAA7F6EFF945C47FFE2D4CFFFA77867FF97604BFFD5BF B7FFF6F6F6FFDEDDDCFFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFF8F8F8EFFF4F4F4FFBFBBB8FFE1DFDDFFE5E5E4FFEAEAEAFFEFEFEFFFF2F2 F2FFF2F2F2FFF2F2F2FFDEDDDCFFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFF8F8F8EFFF4F4F4FF815A26FFCBA966FFBF942AFFB88E28FFB087 26FFA77F24FF9F7722FF9A6B34FF5C401BFFF4F4F4FF8F8F8EFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FFCDC9C5FFDDCFC9FFC8AEA3FFEEEE EDFFD5C1BAFF965E49FFA57664FFF8F8F8FFD6D5D5FFF4F4F4FF8F8F8EFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FFCDC9C5FFDDCFC9FFC8AE A3FFEEEEEDFFD5C1BAFF965E49FFA57664FFF8F8F8FFD6D5D5FFF4F4F4FF8F8F 8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FFBCB7B2FFDCD8 D5FFDFDCDAFFE3E1E0FFE8E8E8FFECECECFFEDEDEDFFEDEDEDFFD6D5D4FFF4F4 F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FF855D 27FFD4B36DFFC99E2CFFC4992BFFBE932AFFB78D28FFAE8525FFA6793EFF6546 1EFFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4 F4FFB9B3AEFFDDD9D5FFE5E2DFFFDCD8D5FFF4F3F2FFA1715EFF945C47FFD6C3 BCFFDCDCDBFFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F 8EFFF4F4F4FFB9B3AEFFDDD9D5FFE5E2DFFFDCD8D5FFF4F3F2FFA1715EFF945C 47FFD6C3BCFFDCDCDBFFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFF8F8F8EFFF4F4F4FFB9B3AEFFD7D1CDFFD9D4D0FFDBD7D4FFDFDDDBFFE3E2 E1FFE6E6E5FFE8E8E8FFCDCDCCFFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFF8F8F8EFFF4F4F4FF895F28FFDABB74FFD1A42EFFCEA22DFFC99D 2CFFC2972BFFBB9129FFB18647FF6E4C20FFF4F4F4FF8F8F8EFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FFB9B3AEFFD5CFCBFFD5CFCBFFD6D1 CDFFE6E2E0FFCFB8AFFF925A45FFA57765FFE8E7E7FFF4F4F4FF8F8F8EFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FFB9B3AEFFD5CFCBFFD5CF CBFFD6D1CDFFE6E2E0FFCFB8AFFF925A45FFA57765FFE8E7E7FFF4F4F4FF8F8F 8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FFB9B3AEFFD5CF CBFFD5CFCBFFD6D1CDFFDAD5D2FFDEDBD8FFE1DFDDFFE4E3E2FFC8C7C6FFF4F4 F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FF8B61 29FFE0C27BFFD5A82FFFD3A62FFFD0A42EFFCB9F2DFFC5992BFFBB9250FF7652 23FFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4 F4FFB9B3AEFFD5CFCBFFD5CFCBFFD5CFCBFFD6D0CCFFF1EEEDFF9D6A57FF925A 44FFD0BFB9FFF6F6F6FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F 8EFFF4F4F4FFB9B3AEFFD5CFCBFFD5CFCBFFD5CFCBFFD6D0CCFFF1EEEDFF9D6A 57FF925A44FFD0BFB9FFF6F6F6FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFF8F8F8EFFF4F4F4FFB9B3AEFFD5CFCBFFD5CFCBFFD5CFCBFFD5CFCBFFD8D3 D0FFDCD8D5FFDFDDDBFFC5C3C1FFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFF8F8F8EFFF4F4F4FF8D6229FFE4C87FFFE1C37BFFDDBE75FFD9B7 6EFFD3AF68FFCCA760FFC49D59FF7C5624FFF4F4F4FF8F8F8EFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FFB9B3AEFFB9B3AEFFB9B3AEFFB9B3 AEFFB9B3AEFFD0CCC9FFC0A79DFFAB8677FFE4DFDCFFF5F5F5FF8F8F8EFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FFB9B3AEFFB9B3AEFFB9B3 AEFFB9B3AEFFB9B3AEFFD0CCC9FFC0A79DFFAB8677FFE4DFDCFFF5F5F5FF8F8F 8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FFB9B3AEFFB9B3 AEFFB9B3AEFFB9B3AEFFB9B3AEFFB9B3AEFFBAB4AFFFBDB9B4FFC1BEBBFFF4F4 F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FF8D62 29FF8E622AFF8E622AFF8D622AFF8C6129FF8A6028FF875E28FF845B27FF8059 26FFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4 F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF8F8F8FFF9F9 F9FFF6F6F6FFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F 8EFFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF8F8 F8FFF9F9F9FFF6F6F6FFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFF8F8F8EFFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4 F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFF8F8F8EFFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4 F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FF8F8F8EFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F 8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F 8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F 8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F 8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F 8EFF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFF8F8F8EFF8F8F 8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F 8EFF8F8F8EFF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF424D3E000000000000003E000000 2800000044000000220000000100010000000000980100000000000000000000 000000000000000000000000FFFFFF0000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000} end end ================================================ FILE: frontend/msConflictForm.pas ================================================ unit msConflictForm; interface uses Windows, Types, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls, ImgList, // superobject superobject, // mte units mteHelpers, mteBase, // ms units msCore, msChoicePanel; type TConflictForm = class(TForm) btnOK: TButton; btnCancel: TButton; tvRecords: TTreeView; sbChoices: TScrollBox; FlagIcons: TImageList; StateImages: TImageList; procedure DrawFlag(Canvas: TCanvas; var x, y: Integer; id: Integer); procedure tvRecordsCustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean); procedure PopulateTree(sig: string; aSetting: TSmashSetting); procedure ChoiceSelected(Sender: TObject); procedure CreateChoicePanel(sig: string; var lst: TList); procedure FormShow(Sender: TObject); procedure FormCreate(Sender: TObject); procedure btnOKClick(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure tvRecordsMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); private { Private declarations } lastHint: string; public // slConflicts is a stringlist of record signatures // each signature has a TSmashSetting associated with it // in slConflicts.Objects // slConflicts may have duplicate signatures with different // TSmashSetting objects slConflicts: TStringList; end; var ConflictForm: TConflictForm; ChoicePanels, SelectedPanels: TList; implementation {$R *.dfm} procedure TConflictForm.DrawFlag(Canvas: TCanvas; var x, y: Integer; id: Integer); var icon: TIcon; begin if x < 30 then exit; icon := TIcon.Create; FlagIcons.GetIcon(id, icon); Canvas.Draw(x, y, icon); Inc(x, 18); icon.Free; end; procedure TConflictForm.tvRecordsCustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean); var e: TElementData; R: TRect; x, y: Integer; begin if Assigned(node.Data) then begin e := TElementData(node.Data); R := Node.DisplayRect(true); x := R.Right + 6; y := R.Top; if e.preserveDeletions then DrawFlag(Sender.Canvas, x, y, 0); if e.singleEntity then DrawFlag(Sender.Canvas, x, y, 1); if (e.linkTo <> '') or (e.linkFrom <> '') then DrawFlag(Sender.Canvas, x, y, 2); end; end; procedure TConflictForm.tvRecordsMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); var node: TTreeNode; e: TElementData; sHint: string; begin // hide hint and exit if shift is down if (ssShift in Shift) then begin Application.HideHint; exit; end; // draw hint if on a node with the link parameter node := tvRecords.GetNodeAt(X, Y); if not Assigned(node) then exit; e := TElementData(node.Data); if not Assigned(e) then exit; // get hint sHint := node.Text + #13#10'Type: '+stToString(e.smashType); if e.linkTo <> '' then sHint := sHint + #13#10'Linked to: '+e.linkTo; if e.linkFrom <> '' then sHint := sHint + #13#10'Linked from: '+e.linkFrom; // display hint if it isn't the last hint we displayed if sHint <> lastHint then begin tvRecords.Hint := sHint; Application.ActivateHint(Mouse.CursorPos); lastHint := sHint; end; end; procedure TConflictForm.PopulateTree(sig: string; aSetting: TSmashSetting); var rootNode: TTreeNode; item: ISuperObject; begin rootNode := tvRecords.Items[0]; for item in aSetting.tree['records'] do if Copy(item.S['n'], 1, 4) = sig then begin LoadElement(tvRecords, rootNode, item, false); break; end; end; procedure TConflictForm.btnOKClick(Sender: TObject); var i: Integer; aChoicePanel: TChoicePanel; aSetting: TSmashSetting; begin // get user selection from choice panels, add it to slConflicts // to be handled later for i := 0 to Pred(ChoicePanels.Count) do begin aChoicePanel := TChoicePanel(ChoicePanels[i]); aSetting := aChoicePanel.GetSetting; if Assigned(aSetting) then begin DeleteMatchingItems(aChoicePanel.GetLabel, slConflicts); slConflicts.AddObject(aChoicePanel.GetLabel, TObject(aSetting)); end; end; // close form with ModalResult = mrOK ModalResult := mrOK; end; procedure TConflictForm.ChoiceSelected(Sender: TObject); var i: Integer; sig: string; aChoicePanel: TChoicePanel; aSetting: TSmashSetting; begin tvRecords.Items.Clear; tvRecords.Items.Add(nil, 'Records'); // populate tree view with selected record nodes for i := 0 to Pred(ChoicePanels.Count) do begin aChoicePanel := TChoicePanel(ChoicePanels[i]); if not aChoicePanel.Selected then continue; sig := aChoicePanel.GetLabel; aSetting := aChoicePanel.GetSetting; if Assigned(aSetting) then PopulateTree(sig, aSetting); end; end; procedure TConflictForm.CreateChoicePanel(sig: string; var lst: TList); var aChoicePanel: TChoicePanel; i: Integer; begin aChoicePanel := TChoicePanel.Create(sbChoices); aChoicePanel.SetLabel(sig); aChoicePanel.SetSelectCallback(ChoiceSelected); aChoicePanel.SetTop(36 * ChoicePanels.Count); for i := 0 to Pred(lst.Count) do aChoicePanel.AddChoice(lst[i]); ChoicePanels.Add(aChoicePanel); end; procedure TConflictForm.FormClose(Sender: TObject; var Action: TCloseAction); begin FreeList(ChoicePanels); end; procedure TConflictForm.FormCreate(Sender: TObject); begin ChoicePanels := TList.Create; end; procedure TConflictForm.FormShow(Sender: TObject); var i, index: Integer; aSetting: TSmashSetting; sl: TStringList; lst: TList; begin // construct a new stringlist that has each unique record signature // paired with a list of all the settings that have that record signature // (retrieved from slConflicts) sl := TStringList.Create; try for i := 0 to Pred(slConflicts.Count) do begin aSetting := TSmashSetting(slConflicts.Objects[i]); index := sl.IndexOf(slConflicts[i]); if index = -1 then index := sl.AddObject(slConflicts[i], TObject(TList.Create)); lst := TList(sl.Objects[index]); lst.Add(aSetting); end; // create choice panels for i := 0 to Pred(sl.Count) do begin lst := TList(sl.Objects[i]); if lst.Count > 1 then CreateChoicePanel(sl[i], lst); end; finally // free memory sl.Free; end; end; end. ================================================ FILE: frontend/msCore.pas ================================================ unit msCore; interface uses Classes, Menus, ComCtrls, RegularExpressions, // third party libraries superobject, // mte units mteBase; type // SMASH CLASSES TElementData = class(TObject) public priority: byte; process: boolean; preserveDeletions: boolean; overrideDeletions: boolean; forceValue: boolean; singleEntity: boolean; smashType: TSmashType; linkTo: string; linkFrom: string; constructor Create; overload; constructor Create(priority: byte; process, preserveDeletions, overrideDeletions, singleEntity, forceValue: boolean; smashType: TSmashType; linkTo, linkFrom: string); overload; end; TSmashSetting = class(TObject) public name: string; hash: string; description: string; records: string; tree: ISuperObject; color: Int64; bVirtual: boolean; constructor Create; destructor Destroy; override; constructor Clone(s: TSmashSetting); function GetRecordDef(sig: string): ISuperObject; procedure LoadDump(dump: ISuperObject); function Dump: ISuperObject; procedure UpdateHash; procedure UpdateRecords; procedure Save; procedure Delete; procedure Rename(newName: string); function MatchesHash(hash: string): boolean; function GetTags: String; function GetCombinedTags: String; end; {TRecommendation = class(TObject) public game: string; username: string; filename: string; hash: string; setting: string; settingHash: string; recordCount: integer; rating: integer; smashVersion: string; notes: string; dateSubmitted: TDateTime; procedure SetNotes(notes: string); function GetNotes: string; procedure Save(const filename: string); end; } // SMASH CORE CLASSES TPatchStatusID = ( psUnknown, psNoPlugins, psDirInvalid, psUnloaded, psErrors, psFailed, psUpToDate, psUpToDateForced, psBuildReady, psRebuildReady, psRebuildReadyForced ); TPatchStatus = Record id: TPatchStatusID; color: integer; desc: string[64]; end; TPlugin = class(TBasePlugin) public setting: string; smashSetting: TSmashSetting; patch: string; constructor Create; override; procedure GetMsData; procedure GetDataPath; function GetFormIndex: Integer; function IsInPatch: boolean; procedure LoadInfoDump(obj: ISuperObject); function InfoDump: ISuperObject; function HasTags: Boolean; procedure ApplySettingTags; procedure SetSmashSetting(aSetting: TSmashSetting); procedure LoadTags(sSettingName: String; var sl: TStringList; var sTagGroup: String); procedure GetSettingTag; procedure WriteDescription; procedure Save; end; TPatch = class(TObject) public name: string; filename: string; dateBuilt: TDateTime; dataPath: string; status: TPatchStatusID; plugin: TPlugin; plugins: TStringList; hashes: TStringList; smashSettings: TStringList; masters: TStringList; fails: TStringList; constructor Create; virtual; destructor Destroy; override; function Dump: ISuperObject; procedure LoadDump(obj: ISuperObject); function GetTimeCost: integer; procedure UpdateHashes; procedure UpdateSettings; procedure GetStatus; procedure UpdateDataPath; procedure GetLoadOrders; procedure SortPlugins; procedure Remove(plugin: TPlugin); overload; procedure Remove(pluginFilename: string); overload; function PluginsModified: boolean; function FilesExist: boolean; function GetStatusColor: integer; end; TSettingHelpers = class class function SettingByName(name: String): TSmashSetting; class function SettingByHash(hash: String): TSmashSetting; class function GetSmashSetting(setting: string): TSmashSetting; end; TPatchHelpers = class class function CreateNewPatch(var patches: TList): TPatch; class function GetPatchForPlugin(filename: string): string; class procedure AssignPatchesToPlugins; class function PatchByName(var patches: TList; name: string): TPatch; class function PatchByFilename(var patches: TList; filename: string): TPatch; end; // Loading/Saving Functions procedure RenameSavedPlugins; procedure SavePatches; procedure LoadPatches; procedure SaveSmashSettings; procedure LoadSmashSettings; procedure SavePluginInfo; procedure LoadPluginInfo; procedure LoadSettingTags; // Helper Functions procedure HandleCanceled(msg: string); procedure UpdatePluginData; function CreateNewPlugin(sFilename: string): TPlugin; function PluginLoadOrder(sFilename: string): Integer; function PluginByFilename(sFilename: string): TPlugin; procedure PopulateAddList(var AddItem: TMenuItem; Event: TNotifyEvent); procedure AddAllRecords(currentSetting: TSmashSetting; var tv: TTreeView); procedure RemoveSettingFromPlugins(aSetting: TSmashSetting); function GetTagString(var slTags: TStringList): String; // Tree Helper Functions procedure BuildTreeFromPlugins(var tv: TTreeView; var sl: TStringList; tree: ISuperObject); procedure SetChildren(node: TTreeNode; state: Integer); procedure UpdateParent(node: TTreeNode); procedure CheckBoxManager(node: TTreeNode); procedure LoadElement(var tv: TTreeView; node: TTreeNode; obj: ISuperObject; bWithinSingle: boolean); procedure LoadTree(var tv: TTreeView; aSetting: TSmashSetting); function GetRecordObject(tree: ISuperObject; sig: string): ISuperObject; function GetChild(obj: ISuperObject; name: string): ISuperObject; procedure MergeChildren(srcObj, dstObj: ISuperObject); function CreateCombinedSetting(var sl: TStringList; name: string; bVirtual: boolean = false): TSmashSetting; function CombineSettingTrees(var lst: TList; var slSettings: TStringList): boolean; // Tag Helper Functions function ClearTags(sDescription: String): String; procedure GetMissingTags(var slPresent, slMissing: TStringList); procedure ExtractTags(var match: TMatch; var sl: TStringList; var sTagGroup: String); procedure ParseTags(description: string; var sl: TStringList); const // IMPORTANT CONSTANTS ProgramTesters = ' '; ProgramTranslators = ' '; xEditVersion = '3.1.1'; // CHECKBOX STATES csUnknown = 0; csChecked = 1; csUnChecked = 2; csPartiallyChecked = 3; // SMASH TYPE ARRAYS stArrays = [ stUnsortedArray, stUnsortedStructArray, stSortedArray, stSortedStructArray ]; stValues = [ stString, stFloat, stInteger, stByteArray ]; // PATCH STATUSES StatusArray: array[0..10] of TPatchStatus = ( ( id: psUnknown; color: $808080; desc: 'Unknown'; ), ( id: psNoPlugins; color: $0000FF; desc: 'Need two or more plugins to patch'; ), ( id: psDirInvalid; color: $0000FF; desc: 'Directories invalid'; ), ( id: psUnloaded; color: $0000FF; desc: 'Plugins not loaded'; ), ( id: psErrors; color: $0000FF; desc: 'Errors in plugins'; ), ( id: psFailed; color: $0000FF; desc: 'Patch failed'; ), ( id: psUpToDate; color: $900000; desc: 'Up to date'; ), ( id: psUpToDateForced; color: $900000; desc: 'Up to date [Forced]'; ), ( id: psBuildReady; color: $009000; desc: 'Ready to be built'; ), ( id: psRebuildReady; color: $009000; desc: 'Ready to be rebuilt'; ), ( id: psRebuildReadyForced; color: $009000; desc: 'Ready to be rebuilt [Forced]'; ) ); // STATUS TYPES ErrorStatuses = [psUnknown, psNoPlugins, psDirInvalid, psUnloaded, psErrors]; UpToDateStatuses = [psUpToDate, psUpToDateForced]; BuildStatuses = [psBuildReady, psRebuildReady, psRebuildReadyForced, psFailed]; RebuildStatuses = [psRebuildReady, psRebuildReadyForced, psFailed]; ForcedStatuses = [psUpToDateForced, psRebuildReadyForced]; ResolveStatuses = [psNoPlugins, psDirInvalid, psUnloaded, psErrors]; FailedStatuses = [psFailed]; var PatchesList, SmashSettings, pluginsToHandle, patchesToBuild: TList; ActiveMods, SavedPluginPaths: TStringList; ActiveModProfile, xEditLogGroup, xEditLogLabel, DictionaryFilename: string; implementation uses Windows, SysUtils, Dialogs, Graphics, // mte units mteLogger, mteTracker, mteHelpers, mteLogging, RttiJson, CRC32, // mp units msConfiguration, // xEdit units wbInterface, wbImplementation; { TPlugin Constructor } constructor TPlugin.Create; begin patch := ' '; inherited; end; { Fetches data associated with a plugin. } procedure TPlugin.GetMsData; begin hasData := true; // get data path and hash GetDataPath; GetHash; // get numOverrides if not blacklisted if (numRecords < 10000) then numOverrides := CountOverrides(_File); // call get data method GetData(PluginsList); end; procedure TPlugin.GetDataPath; begin dataPath := wbDataPath; end; function TPlugin.GetFormIndex: Integer; var Container, MasterFiles: IwbContainer; begin Result := 0; Container := self._File as IwbContainer; Container := Container.Elements[0] as IwbContainer; if Container.ElementExists['Master Files'] then begin MasterFiles := Container.ElementByPath['Master Files'] as IwbContainer; Result := MasterFiles.ElementCount; end; end; function TPlugin.IsInPatch: boolean; begin Result := patch <> ' '; end; function TPlugin.InfoDump: ISuperObject; var obj: ISuperObject; begin obj := SO; // filename, hash, errors obj.S['filename'] := filename; obj.S['hash'] := hash; obj.S['setting'] := setting; Result := obj; end; procedure TPlugin.LoadInfoDump(obj: ISuperObject); var aSetting: TSmashSetting; begin aSetting := TSettingHelpers.SettingByName(obj.AsObject.S['setting']); SetSmashSetting(aSetting); end; procedure TPlugin.SetSmashSetting(aSetting: TSmashSetting); begin if not Assigned(aSetting) then begin setting := 'Skip'; smashSetting := TSettingHelpers.SettingByName(setting); end else begin setting := aSetting.name; smashSetting := aSetting; Logger.Write('PLUGIN', 'Settings', 'Using '+setting+' for '+filename); end; end; function TPlugin.HasTags: Boolean; var regex: TRegex; match: TMatch; begin regex := TRegEx.Create('{{([a-zA-Z]{1,10}:){0,1}([^}]*)}}'); match := regex.Match(description.Text); Result := match.Success; end; procedure TPlugin.ApplySettingTags; var sTags: String; begin description.Text := ClearTags(description.Text); sTags := smashSetting.GetTags; // write tags to the description description.Add(' '); description.Add(sTags); description.Text := Trim(description.Text); WriteDescription; end; procedure TPlugin.LoadTags(sSettingName: String; var sl: TStringList; var sTagGroup: String); var slRecords: TStringList; aSetting: TSmashSetting; settingsToCombine: TList; i: Integer; begin // if only one setting present, use it if sl.Count = 1 then begin aSetting := TSettingHelpers.GetSmashSetting(sl[0]); SetSmashSetting(aSetting); end // else make a combined setting else begin settingsToCombine := TList.Create; // loop through found settings for i := Pred(sl.Count) downto 0 do begin aSetting := TSettingHelpers.GetSmashSetting(sl[i]); if not Assigned(aSetting) then begin sl.Delete(i); continue; end; settingsToCombine.Add(aSetting); end; // if settingsToCombine has 0 settings, set to skip setting if settingsToCombine.Count = 0 then SetSmashSetting(nil) // if settingToCombine has only 1 setting, use that setting else if settingsToCombine.Count = 1 then SetSmashSetting(settingsToCombine[0]) // else build a combined setting else begin Logger.Write('PLUGIN', 'Settings', 'Building combined setting'); slRecords := TStringList.Create; CombineSettingTrees(settingsToCombine, slRecords); if sTagGroup <> '' then sSettingName := sTagGroup + '.' + sSettingName; aSetting := CreateCombinedSetting(slRecords, sSettingName, true); SetSmashSetting(aSetting); end; end; end; procedure TPlugin.GetSettingTag; var regex: TRegEx; match: TMatch; sTagGroup: String; sl: TStringList; begin // get setting tags from description regex := TRegEx.Create('{{([a-zA-Z]{1,10}:){0,1}([^}]*)}}'); match := regex.Match(description.Text); sl := TStringList.Create; // set to skip setting if no tag is found if not match.Success then begin Logger.Write('PLUGIN', 'Tags', 'No tags found for '+filename); setting := 'Skip'; smashSetting := TSettingHelpers.SettingByName(setting); end // else parse settings from tag else begin Logger.Write('PLUGIN', 'Tags', 'Found tag '+match.Value+' for '+filename); ExtractTags(match, sl, sTagGroup); LoadTags(match.Groups.Item[2].Value, sl, sTagGroup); end; // free memory sl.Free; end; procedure TPlugin.WriteDescription; var Container: IwbContainer; begin Container := _File as IwbContainer; Container := Container.Elements[0] as IwbContainer; Container.SetElementEditValue('SNAM - Description', description.Text); end; procedure TPlugin.Save; var path: string; FileStream: TFileStream; begin // save plugin path := dataPath + filename + '.save'; Tracker.Write(' '); Tracker.Write('Saving: ' + path); Logger.Write('PLUGIN', 'Save', path); FileStream := nil; try FileStream := TFileStream.Create(path, fmCreate); _File.WriteToStream(FileStream, False); if SavedPluginPaths.IndexOf(path) = -1 then SavedPluginPaths.Add(dataPath + filename); except on x: Exception do Tracker.Write('Failed to save: '+x.Message); end; TryToFree(FileStream); end; { TPatch Constructor } constructor TPatch.Create; begin name := 'NewPatch'; filename := 'NewPatch.esp'; status := psUnknown; dateBuilt := 0; plugins := TStringList.Create; hashes := TStringList.Create; smashSettings := TStringList.Create; masters := TStringList.Create; fails := TStringList.Create; end; destructor TPatch.Destroy; begin plugins.Free; hashes.Free; smashSettings.Free; masters.Free; fails.Free; inherited; end; { Produces a dump of the patch. } function TPatch.Dump: ISuperObject; var obj: ISuperObject; i: integer; begin obj := SO; // normal attributes obj.S['name'] := name; obj.S['filename'] := filename; obj.S['dateBuilt'] := DateTimeToStr(dateBuilt); // plugins, pluginHashes, pluginSettings, masters obj.O['plugins'] := SA([]); for i := 0 to Pred(plugins.Count) do obj.A['plugins'].S[i] := plugins[i]; obj.O['pluginHashes'] := SA([]); for i := 0 to Pred(hashes.Count) do obj.A['pluginHashes'].S[i] := hashes[i]; obj.O['pluginSettings'] := SA([]); for i := 0 to Pred(smashSettings.Count) do obj.A['pluginSettings'].S[i] := smashSettings[i]; obj.O['masters'] := SA([]); for i := 0 to Pred(masters.Count) do obj.A['masters'].S[i] := masters[i]; // files, log, ignored dependencies obj.O['fails'] := SA([]); for i := 0 to Pred(fails.Count) do obj.A['fails'].S[i] := fails[i]; Result := obj; end; { Loads a dump of a patch. } procedure TPatch.LoadDump(obj: ISuperObject); var item: ISuperObject; begin // load object attributes name := obj.AsObject.S['name']; filename := obj.AsObject.S['filename']; // try loading dateBuilt and parsing to DateTime try dateBuilt := StrToDateTime(obj.AsObject.S['dateBuilt']); except on Exception do dateBuilt := 0; // on exception set to never built end; // load array attributes for item in obj['plugins'] do plugins.Add(item.AsString); for item in obj['pluginHashes'] do hashes.Add(item.AsString); try for item in obj['pluginSettings'] do smashSettings.Add(item.AsString); except on x: Exception do // nothing end; for item in obj['masters'] do masters.Add(item.AsString); for item in obj['fails'] do fails.Add(item.AsString); end; function TPatch.GetTimeCost: integer; var i: Integer; plugin: TPlugin; begin Result := 10000; for i := 0 to Pred(plugins.Count) do begin plugin := PluginByFilename(plugins[i]); if Assigned(plugin) then Inc(Result, plugin._File.RecordCount); end; end; // Checks to see if the plugins in a patch have been modified since it was last // patchd. function TPatch.PluginsModified: boolean; var plugin: TPlugin; i: integer; begin Result := false; // true if number of hashes not equal to number of plugins if (plugins.Count <> hashes.Count) or (plugins.Count <> smashSettings.Count) then begin Logger.Write('PATCH', 'Status', name + ' -> Plugin count changed'); Result := true; exit; end; // true if any plugin hash doesn't match for i := 0 to Pred(plugins.count) do begin plugin := PluginByFilename(plugins[i]); if Assigned(plugin) then begin if plugin.hash <> hashes[i] then begin Logger.Write('PATCH', 'Status', name + ' -> '+plugin.filename + ' hash changed.'); Result := true; end; end; end; // true if any plugin setting doesn't match for i := 0 to Pred(plugins.count) do begin plugin := PluginByFilename(plugins[i]); if Assigned(plugin) then begin if plugin.setting <> smashSettings[i] then begin Logger.Write('PATCH', 'Status', name + ' -> '+plugin.filename + ' smash setting changed.'); Result := true; end; end; end; end; // Checks if the files associated with a patch exist function TPatch.FilesExist: boolean; begin Result := FileExists(dataPath + filename); end; procedure TPatch.UpdateDataPath; begin dataPath := settings.patchDirectory; if not SameText(dataPath, wbDataPath) then dataPath := dataPath + name + '\'; end; procedure TPatch.GetStatus; var i: Integer; plugin: TPlugin; begin Logger.Write('PATCH', 'Status', name + ' -> Getting status'); status := psUnknown; // don't patch if there aren't two or more plugins to patch if (plugins.Count < 2) then begin Logger.Write('PATCH', 'Status', name + ' -> Need two or more plugins to patch'); status := psNoPlugins; exit; end; // don't patch if mod destination directory is blank if (settings.patchDirectory = '') then begin Logger.Write('PATCH', 'Status', name + ' -> Patch directory blank'); status := psDirInvalid; exit; end; // update the patch's data path UpdateDataPath; // loop through plugins for i := 0 to Pred(plugins.Count) do begin plugin := PluginByFilename(plugins[i]); // see if plugin is loaded if not Assigned(plugin) then begin Logger.Write('PATCH', 'Status', name + ' -> Plugin '+plugins[i]+' is missing'); if status = psUnknown then status := psUnloaded; continue; end; end; // check plugins were modified or files were deleted before // giving patch the up to date status if (not PluginsModified) and FilesExist and (status = psUnknown) then begin Logger.Write('PATCH', 'Status', name + ' -> Up to date'); status := psUpToDate; end; // status green, ready to go if status = psUnknown then begin Logger.Write('PATCH', 'Status', name + ' -> Ready to be patchd'); if dateBuilt = 0 then status := psBuildReady else status := psRebuildReady; end; end; function TPatch.GetStatusColor: integer; begin Result := StatusArray[Ord(status)].color; end; // Update the hashes list for the plugins in the patch procedure TPatch.UpdateHashes; var i: Integer; aPlugin: TPlugin; begin hashes.Clear; for i := 0 to Pred(plugins.Count) do begin aPlugin := PluginByFilename(plugins[i]); if Assigned(aPlugin) then hashes.Add(aPlugin.hash); end; end; // Update the settings list for the plugins in the patch procedure TPatch.UpdateSettings; var i: Integer; aPlugin: TPlugin; begin smashSettings.Clear; for i := 0 to Pred(plugins.Count) do begin aPlugin := PluginByFilename(plugins[i]); if Assigned(aPlugin) then smashSettings.Add(aPlugin.setting); end; end; // Get load order for plugins in patch that don't have it procedure TPatch.GetLoadOrders; var i: integer; begin for i := 0 to Pred(plugins.Count) do if not Assigned(plugins.Objects[i]) then plugins.Objects[i] := TObject(PluginLoadOrder(plugins[i])); end; // Sort plugins by load order position procedure TPatch.SortPlugins; begin GetLoadOrders; plugins.CustomSort(LoadOrderCompare); end; procedure TPatch.Remove(plugin: TPlugin); var index: Integer; begin // clear plugin's patch property, if it's the name of this patch if plugin.patch = name then plugin.patch := ' '; // remove plugin from patch, if present index := plugins.IndexOf(plugin.filename); if index > -1 then plugins.Delete(index); end; procedure TPatch.Remove(pluginFilename: string); var index: Integer; begin index := plugins.IndexOf(pluginFilename); // remove plugin from patch, if present if index > -1 then plugins.Delete(index); end; { TSettingHelpers } { Gets a smash setting matching the given name. } class function TSettingHelpers.SettingByName(name: string): TSmashSetting; var i: integer; aSetting: TSmashSetting; begin Result := nil; for i := 0 to Pred(SmashSettings.Count) do begin aSetting := TSmashSetting(SmashSettings[i]); if aSetting.name = name then begin Result := aSetting; exit; end; end; end; { Gets a smash setting matching the given hash. } class function TSettingHelpers.SettingByHash(hash: string): TSmashSetting; var i: integer; aSetting: TSmashSetting; begin Result := nil; for i := 0 to Pred(SmashSettings.Count) do begin aSetting := TSmashSetting(SmashSettings[i]); if aSetting.MatchesHash(hash) then begin Result := aSetting; exit; end; end; end; { Gets a smash setting matching a name or hash } class function TSettingHelpers.GetSmashSetting(setting: string): TSmashSetting; var sl: TStringList; smashSetting: TSmashSetting; begin // default result Result := nil; // parse setting name and hash if Pos('|', setting) > 0 then begin sl := TStringList.Create; try sl.Delimiter := '|'; sl.StrictDelimiter := true; sl.DelimitedText := setting; // if we have a setting name, use it to get a smash setting if Length(sl[0]) > 0 then begin smashSetting := SettingByName(sl[0]); // and return it if the hash matches if Assigned(smashSetting) and smashSetting.MatchesHash(sl[1]) then Result := smashSetting; end // else just get the setting from the hash else Result := SettingByHash(sl[1]); finally sl.Free; end; end // else just return SettingByName else Result := SettingByName(setting); end; { TPatchHelpers } class function TPatchHelpers.GetPatchForPlugin(filename: string): string; var i: Integer; patch: TPatch; begin Result := ' '; for i := 0 to Pred(PatchesList.Count) do begin patch := TPatch(PatchesList[i]); if patch.plugins.IndexOf(filename) > -1 then begin Result := patch.name; break; end; end; end; class procedure TPatchHelpers.AssignPatchesToPlugins; var i, j: Integer; patch: TPatch; plugin: TPlugin; begin for i := 0 to Pred(PatchesList.Count) do begin patch := TPatch(PatchesList[i]); for j := 0 to Pred(patch.plugins.Count) do begin plugin := PluginByFilename(patch.plugins[j]); if Assigned(plugin) then plugin.patch := patch.name; end; end; end; { Gets a patch matching the given name. } class function TPatchHelpers.PatchByName(var patches: TList; name: string): TPatch; var i: integer; patch: TPatch; begin Result := nil; for i := 0 to Pred(patches.Count) do begin patch := TPatch(patches[i]); if patch.name = name then begin Result := patch; exit; end; end; end; { Gets a patch matching the given filename. } class function TPatchHelpers.PatchByFilename(var patches: TList; filename: string): TPatch; var i: integer; patch: TPatch; begin Result := nil; for i := 0 to Pred(patches.Count) do begin patch := TPatch(patches[i]); if patch.filename = filename then begin Result := patch; exit; end; end; end; { Create a new patch with non-conflicting name and filename } class function TPatchHelpers.CreateNewPatch(var patches: TList): TPatch; var i: Integer; patch: TPatch; name: string; begin patch := TPatch.Create; // deal with conflicting patch names i := 0; name := patch.name; while Assigned(PatchByName(patches, name)) do begin Inc(i); name := 'NewPatch' + IntToStr(i); end; patch.name := name; // deal with conflicting patch filenames i := 0; name := patch.filename; while Assigned(PatchByFilename(patches, name)) do begin Inc(i); name := 'NewPatch' + IntToStr(i) + '.esp'; end; patch.filename := name; Result := patch; end; { TElementData } constructor TElementData.Create; begin self.priority := 0; self.smashType := TSmashType(0); self.linkTo := ''; self.linkFrom := ''; end; constructor TElementData.Create(priority: Byte; process, preserveDeletions, overrideDeletions, singleEntity, forceValue: Boolean; smashType: TSmashType; linkTo, linkFrom: string); begin self.priority := priority; self.process := process; self.preserveDeletions := preserveDeletions; self.overrideDeletions := overrideDeletions; self.singleEntity := singleEntity; self.forceValue := forceValue; self.smashType := smashType; self.linkTo := linkTo; self.linkFrom := linkFrom; end; { TSmashSetting } function GetUniqueSettingName(base: string): string; var i: Integer; begin Result := base; i := 1; while Assigned(TSettingHelpers.SettingByName(Result)) do begin Inc(i); Result := base + IntToStr(i); end; end; constructor TSmashSetting.Create; begin name := GetUniqueSettingName('NewSetting'); hash := '$00000000'; color := clBlack; description := ''; records := ''; tree := SO; tree.O['records'] := SA([]); end; destructor TSmashSetting.Destroy; begin name := ''; hash := ''; color := 0; description := ''; records := ''; if Assigned(tree) then tree._Release; tree := nil; end; constructor TSmashSetting.Clone(s: TSmashSetting); begin name := GetUniqueSettingName(s.name + '-Clone'); hash := '$00000000'; color := s.color; records := s.records; description := s.description; tree := s.tree.Clone; end; function TSmashSetting.GetRecordDef(sig: string): ISuperObject; begin Result := nil; if not Assigned(tree) then exit; Result := GetRecordObj(tree, sig); end; procedure TSmashSetting.LoadDump(dump: ISuperObject); begin name := dump.S['name']; color := dump.I['color']; hash := dump.S['hash']; description := dump.S['description']; records := dump.S['records']; tree := dump.O['tree']; end; function TSmashSetting.Dump: ISuperObject; var obj: ISuperObject; begin obj := SO; // tree obj.O['tree'] := tree; // normal attributes obj.S['records'] := records; obj.S['description'] := description; obj.I['color'] := color; obj.S['hash'] := hash; obj.S['name'] := name; Result := obj; end; procedure TSmashSetting.UpdateHash; begin hash := StrCRC32(tree.AsJSon); end; procedure TSmashSetting.UpdateRecords; var item: ISuperObject; sl: TStringList; begin // prepare comma delimited stringlist sl := TStringList.Create; sl.Delimiter := ','; sl.StrictDelimiter := true; try // loop through records and add their signatures // to the stringlist if they are set to be processed for item in tree['records'] do begin if item.I['p'] = 1 then sl.Add(Copy(item.S['n'], 1, 4)); end; // assign records the delimited signatures records := sl.DelimitedText; finally // free memory sl.Free; end; end; procedure TSmashSetting.Save; var path: string; begin UpdateHash; path := Format('%s\settings\%s\%s.json', [PathList.Values['ProgramPath'], ProgramStatus.GameMode.gameName, name]); ForceDirectories(ExtractFilePath(path)); Dump.SaveTo(path); end; procedure TSmashSetting.Delete; var path: string; begin path := Format('%s\settings\%s\%s.json', [PathList.Values['ProgramPath'], ProgramStatus.GameMode.gameName, name]); if FileExists(path) then DeleteToRecycleBin(path, false); end; procedure TSmashSetting.Rename(newName: string); var oldPath, newPath: string; begin oldPath := Format('%s\settings\%s\%s.json', [PathList.Values['ProgramPath'], ProgramStatus.GameMode.gameName, name]); newPath := Format('%s\settings\%s\%s.json', [PathList.Values['ProgramPath'], ProgramStatus.GameMode.gameName, newName]); if FileExists(oldpath) then RenameFile(oldpath, newpath); name := newName; end; function TSmashSetting.MatchesHash(hash: string): boolean; begin // result is true if hash is blank if hash = '' then begin Result := true; exit; end; // else result is true if the input hash matches setting's hash // starting at the first hexadecimal digit Result := Pos(hash, self.hash) = 2; end; function TSmashSetting.GetTags: String; var index: Integer; begin if Pos('Combined setting:', description) = 1 then Result := GetCombinedTags // else handle a normal setting else begin index := Pos('.', name); if (index > 0) and (index < 11) then Result := Format('{{%s}}', [StringReplace(name, '.', ':', [])]) else Result := Format('{{%s}}', [name]); end; end; function TSmashSetting.GetCombinedTags: String; var sl, slTags: TStringList; begin Result := ''; sl := TStringList.Create; slTags := TStringList.Create; try sl.Text := description; // parse tags from description slTags.CommaText := sl[1]; // return tag string Result := GetTagString(slTags); finally sl.Free; slTags.Free; end; end; procedure SavePatches; var i: Integer; patch: TPatch; json: ISuperObject; filename: string; begin // initialize json json := SO; json.O['patches'] := SA([]); // loop through patches Tracker.Write(' '); Tracker.Write('Dumping patches to JSON'); for i := 0 to Pred(PatchesList.Count) do begin Tracker.UpdateProgress(1); patch := TPatch(PatchesList[i]); Tracker.Write(' Dumping '+patch.name); json.A['patches'].Add(patch.Dump); end; // save and finalize filename := PathList.Values['ProfilePath'] + 'Patches.json'; Tracker.Write(' '); Tracker.Write('Saving to ' + filename); Tracker.UpdateProgress(1); json.SaveTo(filename); json := nil; end; procedure LoadPatches; const debug = false; var patch: TPatch; obj, patchItem: ISuperObject; sl: TStringList; filename: string; begin // don't load file if it doesn't exist filename := PathList.Values['ProfilePath'] + 'Patches.json'; if not FileExists(filename) then exit; // load file into SuperObject to parse it sl := TStringList.Create; sl.LoadFromFile(filename); obj := SO(PChar(sl.Text)); // loop through patches for patchItem in obj['patches'] do begin patch := TPatch.Create; try patch.LoadDump(patchItem); PatchesList.Add(patch); except on x: Exception do begin Logger.Write('LOAD', 'Patch', 'Failed to load patch '+patch.name); Logger.Write('LOAD', 'Patch', x.Message); end; end; end; // finalize obj := nil; sl.Free; end; function IndexOfDump(a: TSuperArray; plugin: TPlugin): Integer; var i: Integer; obj: ISuperObject; begin Result := -1; for i := 0 to Pred(a.Length) do begin obj := a.O[i]; if (obj.S['filename'] = plugin.filename) and (obj.S['hash'] = plugin.hash) then begin Result := i; exit; end; end; end; procedure SaveSmashSettings; var aSetting: TSmashSetting; i: Integer; begin Tracker.Write('Saving smash settings'); for i := 0 to Pred(SmashSettings.Count) do begin aSetting := TSmashSetting(SmashSettings[i]); if aSetting.bVirtual then continue; Tracker.Write(' Saving '+aSetting.name); aSetting.Save; end; Tracker.Write(' '); end; procedure CreateSkipSetting; var skipSetting: TSmashSetting; index: Integer; begin index := SmashSettings.Add(TSmashSetting.Create); skipSetting := SmashSettings[index]; skipSetting.name := 'Skip'; skipSetting.color := clGray; skipSetting.description := 'Special setting. Any plugin with this setting '+ 'will be excluded from patch creation.'; skipSetting.tree := SO(); skipSetting.tree.O['records'] := SA([]); end; procedure LoadSmashSettings; var info: TSearchRec; obj: ISuperObject; sl: TStringList; aSetting: TSmashSetting; path: String; begin path := Format('%ssettings\%s\', [PathList.Values['ProgramPath'], ProgramStatus.GameMode.gameName]); ForceDirectories(path); // load setting files from settings path if FindFirst(path + '*.json', faAnyFile, info) <> 0 then exit; repeat sl := TStringList.Create; try sl.LoadFromFile(path + info.Name); aSetting := TSmashSetting.Create; obj := SO(PChar(sl.Text)); if Assigned(obj) then begin aSetting.LoadDump(obj); if aSetting.name <> '' then SmashSettings.Add(aSetting); end; sl.Free; obj := nil; except on x: Exception do begin if Assigned(sl) then sl.Free; obj := nil; Logger.Write('ERROR', 'Load', 'Failed to load smash setting '+info.Name); end; end; until FindNext(info) <> 0; // create skip setting if it isn't assigned if TSettingHelpers.SettingByName('Skip') = nil then CreateSkipSetting; end; procedure SavePluginInfo; var i, index: Integer; plugin: TPlugin; obj: ISuperObject; filename: string; sl: TStringList; begin // don't load file if it doesn't exist filename := PathList.Values['ProfilePath'] + 'PluginInfo.json'; if FileExists(filename) then begin // load file text into SuperObject to parse it sl := TStringList.Create; sl.LoadFromFile(filename); obj := SO(PChar(sl.Text)); sl.Free; end else begin // initialize new json object obj := SO; obj.O['plugins'] := SA([]); end; // loop through plugins Tracker.Write('Dumping plugin errors to JSON'); for i := 0 to Pred(PluginsList.Count) do try plugin := PluginsList[i]; Tracker.UpdateProgress(1); if not Assigned(plugin.smashSetting) then continue; index := IndexOfDump(obj.A['plugins'], plugin); if plugin.smashSetting.bVirtual or (plugin.setting = 'Skip') then begin if index <> -1 then obj.A['plugins'].Delete(index); continue; end; Tracker.Write(' Dumping '+plugin.filename); if index = -1 then obj.A['plugins'].Add(plugin.InfoDump) else obj.A['plugins'].O[index] := plugin.InfoDump; except on x: Exception do Tracker.Write(' Exception '+x.Message); end; // save and finalize Tracker.Write(' '); filename := PathList.Values['ProfilePath'] + 'PluginInfo.json'; Tracker.Write('Saving to '+filename); Tracker.UpdateProgress(1); obj.SaveTo(filename); obj := nil; end; procedure LoadPluginInfo; var plugin: TPlugin; obj, pluginItem: ISuperObject; sl: TStringList; filename, hash: string; begin // don't load file if it doesn't exist filename := PathList.Values['ProfilePath'] + 'PluginInfo.json'; if not FileExists(filename) then exit; // load file into SuperObject to parse it sl := TStringList.Create; sl.LoadFromFile(filename); obj := SO(PChar(sl.Text)); // loop through patches filename := ''; for pluginItem in obj['plugins'] do begin filename := pluginItem.AsObject.S['filename']; hash := pluginItem.AsObject.S['hash']; plugin := PluginByFileName(filename); if not Assigned(plugin) then continue; if (plugin.hash = hash) and (plugin.filename = filename) then plugin.LoadInfoDump(pluginItem); end; // finalize obj := nil; sl.Free; end; procedure LoadSettingTags; var i: Integer; plugin: TPlugin; begin // loop through loaded plugins for i := 0 to Pred(PluginsList.Count) do begin plugin := TPlugin(PluginsList[i]); if plugin.setting <> '' then continue; plugin.GetSettingTag; end; end; procedure HandleCanceled(msg: string); begin if Tracker.Cancel then raise Exception.Create(msg); end; procedure RenameSavedPlugins; var i: Integer; oldFileName, newFileName, bakFileName: string; begin // tracker message Tracker.Write(' '); Tracker.Write('Renaming saved plugins'); for i := Pred(SavedPluginPaths.Count) downto 0 do try oldFileName := SavedPluginPaths[i]; newFileName := oldFileName + '.save'; bakFileName := oldFileName + '.bak'; Tracker.Write(Format(' Renaming %s to %s', [ExtractFileName(newFileName), ExtractFileName(oldFileName)])); if FileExists(bakFileName) then DeleteFile(bakFileName); RenameFile(oldFileName, bakFileName); RenameFile(newFileName, oldFileName); except on x: Exception do Tracker.Write(' Failed to rename ' + newFileName); end; end; procedure UpdatePluginData; var i: Integer; plugin: TPlugin; begin for i := 0 to Pred(PluginsList.Count) do begin plugin := TPlugin(PluginsList[i]); plugin.UpdateData; end; end; function CreateNewPlugin(sFilename: string): TPlugin; begin Result := TPlugin(TPluginHelpers.CreateNewBasePlugin(PluginsList, sFilename)); end; function PluginLoadOrder(sFilename: string): Integer; begin Result := TPluginHelpers.BasePluginLoadOrder(PluginsList, sFilename); end; function PluginByFilename(sFilename: string): TPlugin; begin Result := TPlugin(TPluginHelpers.BasePluginByFilename(PluginsList, sFilename)); end; function DefDisplayName(var def: TwbRecordDefEntry): String; var sig: String; begin sig := String(def.rdeSignature); Result := def.rdeDef.Name; if (Result <> sig) then Result := sig + ' - ' + Result; end; procedure PopulateAddList(var AddItem: TMenuItem; Event: TNotifyEvent); var i: Integer; recordDef: TwbRecordDefEntry; item: TMenuItem; begin for i := Low(wbRecordDefs) to High(wbRecordDefs) do begin recordDef := wbRecordDefs[i]; item := TMenuItem.Create(AddItem); item.Caption := DefDisplayName(recordDef); item.OnClick := Event; AddItem.Add(item); end; end; procedure AddAllRecords(currentSetting: TSmashSetting; var tv: TTreeView); var i: Integer; recordDef: TwbRecordDefEntry; groupName: String; recObj: ISuperObject; begin for i := Low(wbRecordDefs) to High(wbRecordDefs) do begin recordDef := wbRecordDefs[i]; groupName := DefDisplayName(recordDef); recObj := GetRecordObj(currentSetting.tree, groupName); if Assigned(recObj) then continue; if not BuildRecordDef(groupName, recObj) then continue; currentSetting.tree.A['records'].Add(recObj); LoadElement(tv, tv.Items[0], recObj, false); end; end; procedure RemoveSettingFromPlugins(aSetting: TSmashSetting); var i: Integer; plugin: TPlugin; begin for i := 0 to Pred(PluginsList.Count) do begin plugin := TPlugin(PluginsList[i]); if plugin.setting = aSetting.name then begin plugin.setting := 'Skip'; plugin.smashSetting := TSettingHelpers.SettingByName('Skip'); end; end; end; function GetTagString(var slTags: TStringList): String; var i, index: Integer; tag, sTagGroup, sGroup: String; begin for i := 0 to Pred(slTags.Count) do begin tag := slTags[i]; index := Pos('.', tag); sTagGroup := Copy(tag, 1, index - 1); if (index > 0) and (index < 11) and (SameText(sGroup, sTagGroup) or (i = 0)) then sGroup := sTagGroup else sGroup := ''; end; // generate the string of tags if sGroup <> '' then begin Result := StringReplace(slTags.CommaText, sGroup + '.', '', [rfReplaceAll, rfIgnoreCase]); Result := Format('{{%s:%s}}', [UpperCase(sGroup), Result]) end else Result := Format('{{%s}}', [slTags.CommaText]); end; {******************************************************************************} { Tree Helper Functions - BuildTreeFromPlugins - SetChildren - UpdateParent - CheckBoxManager - LoadElement } {******************************************************************************} procedure BuildTreeFromPlugins(var tv: TTreeView; var sl: TStringList; tree: ISuperObject); var i, j: Integer; plugin: TPlugin; rec: IwbMainRecord; RecordDef: PwbRecordDef; def: TwbRecordDefEntry; sName, sSignature: string; slRecordSignatures: TStringList; recObj: ISuperObject; begin slRecordSignatures := TStringList.Create; slRecordSignatures.Sorted := true; slRecordSignatures.Duplicates := dupIgnore; try // loop through plugins for i := 0 to Pred(sl.Count) do begin plugin := PluginByFileName(sl[i]); if not Assigned(plugin) then continue; if not plugin._File.IsEditable then continue; // loop through records for j := 0 to Pred(plugin._File.RecordCount) do begin rec := plugin._File.Records[j]; // skip non-override records if rec.IsMaster then continue; sSignature := rec.Signature; // skip record signatures we've already seen if (slRecordSignatures.IndexOf(sSignature) > -1) then continue; slRecordSignatures.Add(sSignature); // skip records that aren't defined if not wbFindRecordDef(AnsiString(sSignature), RecordDef) then continue; // get record def object if it exists sName := sSignature + ' - ' + RecordDef.Name; recObj := GetRecordObj(tree, sName); // build record def if it doesn't exist if not Assigned(recObj) then begin def := GetRecordDef(rec.Signature); if not BuildRecordDef(sName, def.rdeDef, recObj) then continue; tree.A['records'].Add(recObj); LoadElement(tv, tv.Items[0], recObj, false); end; end; end; finally tv.Repaint; slRecordSignatures.Free; end; end; { SetChildren Sets the StateIndex attribute of all the children of @node to @state. Uses recursion. } procedure SetChildren(node: TTreeNode; state: Integer); var tmp: TTreeNode; e: TElementData; begin // exit if we don't have a node to work with if not Assigned(node) then exit; // loop through children setting StateIndex to state // if child has children, recurse into that child tmp := node.getFirstChild; while Assigned(tmp) do begin tmp.StateIndex := state; e := TElementData(tmp.Data); e.process := state <> csUnChecked; e.singleEntity := false; if tmp.HasChildren then SetChildren(tmp, state); tmp := tmp.getNextSibling; end; end; { UpdateParent Calculates and sets the StateIndex attribute for @node based on the StateIndex values of its children. Uses recursion to update parents of the parent that was updated. } procedure UpdateParent(node: TTreeNode); var tmp: TTreeNode; state: Integer; e: TElementData; begin // exit if we don't have a node to work with // or if not is set to be treated as a single entity if not Assigned(node) then exit; e := TElementData(node.Data); if not Assigned(e) then exit; if e.singleEntity then exit; // parent state is checked if all siblings are checked state := csChecked; tmp := node.getFirstChild; while Assigned(tmp) do begin if tmp.StateIndex <> csChecked then begin state := csPartiallyChecked; break; end; tmp := tmp.getNextSibling; end; // parent state is unchecked if all siblings are unchecked if state = csPartiallyChecked then begin state := csUnChecked; tmp := node.getFirstChild; while Assigned(tmp) do begin if tmp.StateIndex <> csUnChecked then begin state := csPartiallyChecked; break; end; tmp := tmp.getNextSibling; end; end; // set state, recurse to next parent node.StateIndex := state; e.process := state <> csUnChecked; tmp := node.Parent; UpdateParent(tmp); end; { CheckBoxManager Manages checkboxes in the TTreeView. Changes the StateIndex of the checkbox associated with @node. Uses SetChildren and UpdateParent. Called by tvClick and tvKeyDown. } procedure CheckBoxManager(node: TTreeNode); var e: TElementData; begin // exit if we don't have a node to work with if not Assigned(node) then exit; // if unchecked or partially checked, set to checked and // set all children to checked, update parents if (node.StateIndex = csUnChecked) or (node.StateIndex = csPartiallyChecked) then begin node.StateIndex := csChecked; e := TElementData(node.Data); e.process := true; e.singleEntity := false; UpdateParent(node.Parent); SetChildren(node, csChecked); end // if checked, set to unchecked and set all children to // unchecked, update parents else if node.StateIndex = csChecked then begin node.StateIndex := csUnChecked; e := TElementData(node.Data); e.process := false; e.singleEntity := false; UpdateParent(node.Parent); SetChildren(node, csUnChecked); end; end; procedure LoadElement(var tv: TTreeView; node: TTreeNode; obj: ISuperObject; bWithinSingle: boolean); var item: ISuperObject; child, nextChild: TTreeNode; bProcess, bPreserveDeletions, bOverrideDeletions, bIsSingle, bForceValue: boolean; priority: Integer; oSmashType: TSmashType; sName, sLinkTo, sLinkFrom: string; e: TElementData; begin if not Assigned(obj) then exit; // load data from json sName := obj.S['n']; priority := obj.I['r']; bProcess := obj.I['p'] = 1; bPreserveDeletions := obj.I['d'] = 1; bOverrideDeletions := obj.I['o'] = 1; bIsSingle := obj.I['s'] = 1; bForceValue := obj.I['f'] = 1; bWithinSingle := bWithinSingle or bIsSingle; oSmashType := TSmashType(obj.I['t']); sLinkTo := obj.S['lt']; sLinkFrom := obj.S['lf']; // create child e := TElementData.Create(priority, bProcess, bPreserveDeletions, bOverrideDeletions, bIsSingle, bForceValue, oSmashType, sLinkTo, sLinkFrom); // nodes insert in sorted order for record nodes if (node.Level = 0) and node.hasChildren then begin child := node.getFirstChild; while (AnsiCompareText(child.Text, sName) < 0) do begin nextChild := child.getNextSibling; if not Assigned(nextChild) then break; child := nextChild; end; child := tv.Items.InsertObject(child, sName, e); end // else just add them in the order they were found else child := tv.Items.AddChildObject(node, sName, e); // set check state if bIsSingle then child.StateIndex := csPartiallyChecked else if bProcess then child.StateIndex := csChecked else child.StateIndex := csUnChecked; // recurse into children if Assigned(obj.O['c']) then try for item in obj['c'] do LoadElement(tv, child, item, bWithinSingle); if not bWithinSingle then UpdateParent(child); except on x : Exception do // nothing end; end; procedure LoadTree(var tv: TTreeView; aSetting: TSmashSetting); var obj, item: ISuperObject; rootNode: TTreeNode; e: TElementData; begin e := TElementData.Create; rootNode := tv.Items.AddObject(nil, 'Records', e); obj := aSetting.tree; if not Assigned(obj) then exit; if not Assigned(obj['records']) then exit; for item in obj['records'] do LoadElement(tv, rootNode, item, false); end; function GetRecordObject(tree: ISuperObject; sig: string): ISuperObject; var item: ISuperObject; begin Result := nil; for item in tree['records'] do begin if Copy(item.S['n'], 1, 4) = sig then begin Result := item; break; end; end; end; function GetChild(obj: ISuperObject; name: string): ISuperObject; var child: ISuperObject; begin Result := nil; for child in obj['c'] do begin if child.S['n'] = name then begin Result := child; exit; end; end; end; procedure MergeChildren(srcObj, dstObj: ISuperObject); var srcChild, dstChild: ISuperObject; begin for srcChild in srcObj['c'] do begin dstChild := GetChild(dstObj, srcChild.S['n']); if not Assigned(dstChild) then dstObj.A['c'].Add(srcChild.Clone) else begin // merge force value if srcChild.I['f'] = 1 then dstChild.I['f'] := 1; // merge treat as single if srcChild.I['s'] = 1 then dstChild.I['s'] := 1; // merge preserve deletions if srcChild.I['d'] = 1 then dstChild.I['d'] := 1; // merge override deletions if srcChild.I['o'] = 1 then dstChild.I['o'] := 1; // merge process if srcChild.I['p'] = 1 then dstChild.I['p'] := 1; // merge links if srcChild.S['lt'] <> '' then dstChild.S['lt'] := srcChild.S['lt']; if srcChild.S['lf'] <> '' then dstChild.S['lf'] := srcChild.S['lf']; // recurse into children if present if Assigned(srcChild.A['c']) then begin if Assigned(dstChild.A['c']) then MergeChildren(srcChild, dstChild) else dstChild.O['c'] := srcChild.O['c'].Clone; end; end; end; end; function CreateCombinedSetting(var sl: TStringList; name: string; bVirtual: boolean = false): TSmashSetting; var i, index: Integer; newSetting, aSetting: TSmashSetting; recordObj, existingRecordObj: ISuperObject; begin newSetting := TSmashSetting.Create; newSetting.tree := SO; newSetting.tree.O['records'] := SA([]); for i := 0 to Pred(sl.Count) do begin aSetting := TSmashSetting(sl.Objects[i]); recordObj := GetRecordObject(aSetting.tree, sl[i]); existingRecordObj := GetRecordObject(newSetting.tree, sl[i]); // if record object matching record signature already exists // merge the record objects if Assigned(existingRecordObj) then MergeChildren(recordObj, existingRecordObj) // else just add it to the tree else newSetting.tree.A['records'].Add(recordObj.Clone); end; newSetting.UpdateRecords; // set other attributes newSetting.UpdateHash; newSetting.bVirtual := bVirtual; newSetting.description := 'Combined setting:'#13#10 + name; index := Pos('.', name); if (index > 0) and (index < 11) then newSetting.name := Format('%sCombined-%s', [Copy(name, 1, index), newSetting.hash]) else newSetting.name := 'Combined-'+newSetting.hash; // add new setting to SmashSettings list aSetting := TSettingHelpers.SettingByName(newSetting.name); if not Assigned(aSetting) then begin SmashSettings.Add(newSetting); Result := newSetting; end else begin newSetting.Free; Result := aSetting; end; end; function CombineSettingTrees(var lst: TList; var slSettings: TStringList): boolean; var setting: TSmashSetting; sl: TStringList; i, j: Integer; begin sl := TStringList.Create; Result := false; for i := 0 to Pred(lst.Count) do begin setting := TSmashSetting(lst[i]); sl.CommaText := setting.records; for j := 0 to Pred(sl.Count) do begin if slSettings.IndexOf(sl[j]) > -1 then Result := true; slSettings.AddObject(sl[j], TObject(setting)); end; end; // free memory sl.Free; end; {******************************************************************************} { Tag Helper Functions - ClearTags - GetMissingTags - ExtractTags - GetTags } {******************************************************************************} function ClearTags(sDescription: String): String; var regex: TRegex; match: TMatch; begin // find tags regex := TRegex.Create('{{([^}]*)}}'); match := regex.Match(sDescription); // delete tags while match.Success do begin sDescription := StringReplace(sDescription, match.Value, '', []); match := match.NextMatch; end; // set description to the memo Result := Trim(sDescription); end; procedure GetMissingTags(var slPresent, slMissing: TStringList); var i: Integer; aSetting: TSmashSetting; begin for i := 0 to Pred(SmashSettings.Count) do begin aSetting := TSmashSetting(SmashSettings[i]); if slPresent.IndexOf(aSetting.name) = -1 then slMissing.Add(aSetting.name); end; end; procedure ExtractTags(var match: TMatch; var sl: TStringList; var sTagGroup: String); var i: Integer; begin sTagGroup := ''; // split tag on commas sl.Delimiter := ','; sl.StrictDelimiter := true; sl.DelimitedText := match.Groups.Item[2].Value; // trim leading or trailing whitespace from tags for i := 0 to Pred(sl.Count) do sl[i] := Trim(sl[i]); // if tags are presented under a group, append the group name // and a . to the beginning of each setting name in the tag if match.Groups.Item[1].Value <> '' then begin sTagGroup := TitleCase(match.Groups.Item[1].Value); SetLength(sTagGroup, Length(sTagGroup) - 1); Logger.Write('PLUGIN', 'Tags', 'Parsing as ' + sTagGroup + ' tags'); for i := 0 to Pred(sl.Count) do sl[i] := Format('%s.%s', [sTagGroup, sl[i]]); end; end; procedure ParseTags(description: string; var sl: TStringList); var regex: TRegEx; match: TMatch; sTagGroup: String; begin // get setting tags from description regex := TRegEx.Create('{{([a-zA-Z]{1,10}:){0,1}([^}]*)}}'); match := regex.Match(description); // if match found, put the tags into the stringlist if match.success then ExtractTags(match, sl, sTagGroup); end; initialization begin PatchesList := TList.Create; SmashSettings := TList.Create; SavedPluginPaths := TStringList.Create; end; finalization begin FreeList(PatchesList); FreeList(SmashSettings); SavedPluginPaths.Free; end; end. ================================================ FILE: frontend/msEditForm.dfm ================================================ object EditForm: TEditForm Left = 0 Top = 0 ActiveControl = edName Caption = 'Edit patch' ClientHeight = 151 ClientWidth = 333 Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'Tahoma' Font.Style = [] OldCreateOrder = False Position = poScreenCenter OnShow = FormShow PixelsPerInch = 96 TextHeight = 13 object PageControl: TPageControl Left = 8 Top = 8 Width = 317 Height = 104 ActivePage = EditTabSheet Align = alCustom Anchors = [akLeft, akTop, akRight, akBottom] TabOrder = 0 TabWidth = 60 object EditTabSheet: TTabSheet Caption = 'Edit' object lblName: TLabel Left = 12 Top = 13 Width = 27 Height = 13 Caption = 'Name' end object lblFilename: TLabel Left = 12 Top = 40 Width = 42 Height = 13 Caption = 'Filename' end object edName: TEdit Left = 102 Top = 10 Width = 202 Height = 21 Margins.Right = 8 Align = alCustom Anchors = [akLeft, akTop, akRight] TabOrder = 0 OnChange = edNameChange OnKeyDown = edKeyDown end object edFilename: TEdit Left = 102 Top = 37 Width = 202 Height = 21 Margins.Right = 8 Align = alCustom Anchors = [akLeft, akTop, akRight] TabOrder = 1 OnChange = edFilenameChange OnEnter = edFilenameEnter OnKeyDown = edKeyDown end end end object btnOK: TButton Left = 250 Top = 118 Width = 75 Height = 25 Align = alCustom Anchors = [akRight, akBottom] Caption = 'OK' TabOrder = 1 OnClick = btnOKClick end end ================================================ FILE: frontend/msEditForm.pas ================================================ unit msEditForm; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls, // mte units mteHelpers, // mator smash units msCore, msConfiguration; type TEditForm = class(TForm) PageControl: TPageControl; EditTabSheet: TTabSheet; btnOK: TButton; lblName: TLabel; lblFilename: TLabel; edName: TEdit; edFilename: TEdit; procedure FormShow(Sender: TObject); function NameValid: boolean; function ESPFilenameValid: boolean; procedure edFilenameChange(Sender: TObject); procedure edFilenameEnter(Sender: TObject); procedure edNameChange(Sender: TObject); procedure edKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure btnOKClick(Sender: TObject); private { Private declarations } public { Public declarations } patch: TPatch; end; var EditForm: TEditForm; implementation {$R *.dfm} procedure TEditForm.btnOKClick(Sender: TObject); begin patch.name := edName.Text; patch.filename := edFilename.Text; ModalResult := mrOK; end; function TEditForm.NameValid: boolean; var aPatch: TPatch; i: integer; begin Result := false; // return false if illegal characters present if not FileNameValid(edName.Text) then exit; // return false if edName is blank if Trim(edName.Text) = '' then exit; // return false if patch with specified name already exists for i := 0 to Pred(PatchesList.Count) do begin aPatch := TPatch(PatchesList[i]); if (aPatch.name = edName.Text) and (aPatch <> patch) then exit; end; // all tests passed, return true Result := true; end; function TEditForm.ESPFilenameValid: boolean; var aPatch: TPatch; plugin: TPlugin; loadOrder, highLoadOrder, i: integer; sFilename: string; begin Result := false; // return false if illegal characters present if not FileNameValid(edFilename.Text) then exit; // return false if filename doesn't end in .esp if not StrEndsWith(edFilename.Text, '.esp') then exit; // return false if specified filename corresponds to a // plugin that is in patch if patch.plugins.IndexOf(edFilename.Text) > -1 then exit; // check if there's a load order error patching into the specified file plugin := PluginByFilename(edFilename.Text); loadOrder := PluginLoadOrder(edFilename.Text); highLoadOrder := MaxInt; if patch.plugins.Count > 0 then begin sFilename := patch.plugins[patch.plugins.Count -1]; highLoadOrder := PluginLoadOrder(sFilename); end; // return false if there's a load order error if Assigned(plugin) and (loadOrder > highLoadOrder) then exit; // return false if patch exists for i := 0 to Pred(PatchesList.Count) do begin aPatch := TPatch(PatchesList[i]); if (aPatch.filename = edFileName.Text) and (aPatch <> patch) then exit; end; // all tests passed, return true Result := true; end; procedure TEditForm.edFilenameChange(Sender: TObject); var valid: boolean; begin // if invalid disable btnOk, show hint, and make font color red valid := ESPFilenameValid; btnOk.Enabled := valid and NameValid; edFilename.ShowHint := valid; if valid then edFilename.Font.Color := clWindowText else edFilename.Font.Color := $0000ff; end; procedure TEditForm.edFilenameEnter(Sender: TObject); begin // change selection to not include the .esp if (edFilename.SelLength = Length(edFilename.Text)) and StrEndsWith(edFilename.Text, '.esp') then edFilename.SelLength := edFilename.SelLength - 4; end; procedure TEditForm.edNameChange(Sender: TObject); var valid, exists: boolean; begin valid := NameValid; exists := DirectoryExists(settings.patchDirectory + edName.Text) and (edName.Text <> patch.name); // if invalid show hint and make font color red btnOk.Enabled := valid and ESPFilenameValid; edName.ShowHint := (not valid) or exists; if (not valid) or exists then edName.Font.Color := $0000ff else edName.Font.Color := clWindowText; end; { Save patch by pressing enter in edName or edFilename } procedure TEditForm.edKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if (HiWord(GetKeyState(vk_Return)) <> 0) and btnOk.Enabled then begin btnOkClick(nil); ModalResult := mrOk; end; end; procedure TEditForm.FormShow(Sender: TObject); begin edName.Text := patch.name; edFilename.Text := patch.filename; end; end. ================================================ FILE: frontend/msLoader.pas ================================================ unit msLoader; interface uses Classes, // mte units mteHelpers, mteBase, // mp units msConfiguration; { Initialization Methods } function InitBase: boolean; function GamePathValid(path: string; id: integer): boolean; procedure SetGame(id: integer); function GetGameID(name: string): integer; function GetLanguageFileSuffix: String; function GetGamePath(mode: TGameMode): string; procedure LoadDefinitions; procedure LoadBSAs; { Load order functions } procedure RemoveCommentsAndEmpty(var sl: TStringList); procedure RemoveMissingFiles(var sl: TStringList); procedure RemoveSmashedPatches(var sl: TStringList); procedure FixLoadOrder(var sl: TStringList; const filename: String; var index: Integer); procedure AddBaseMasters(var sl: TStringList); procedure AddMissingFiles(var sl: TStringList); function PluginListCompare(List: TStringList; Index1, Index2: Integer): Integer; procedure LoadPluginsList(const sLoadPath: String; var sl: TStringList; noDelete: Boolean = False); procedure LoadLoadOrder(const sLoadPath: String; var slLoadOrder: TStringList); procedure PrepareLoadOrder(var slLoadOrder, slPlugins: TStringList); var slPlugins, slLanguageMap: TStringList; UpdateCallback: TCallback; implementation uses SysUtils, StrUtils, IniFiles, ShlObj, Controls, // mte units mteTracker, mteLogger, mteLogging, mtePluginSelectionForm, // mp units msCore, // mp forms // xEdit units wbHelpers, wbInterface, wbImplementation, wbBSA, wbDefinitionsFNV, wbDefinitionsFO3, wbDefinitionsTES3, wbDefinitionsTES4, wbDefinitionsTES5, wbDefinitionsFO4; {******************************************************************************} { Initialization Methods Methods that are used for initialization. List of methods: - GamePathValid - SetGame - GetGameID - GetGamePath - LoadDataPath - LoadDefinitions - InitPapyrus } {******************************************************************************} function InitBase: boolean; var slLoadOrder: TStringList; psForm: TPluginSelectionForm; begin Result := false; // INITIALIZE VARIABLES LogPath := PathList.Values['ProgramPath'] + 'logs\'; PathList.Values['TempPath'] := PathList.Values['ProgramPath'] + 'temp\'; PathList.Values['ProfilePath'] := PathList.Values['ProgramPath'] + 'profiles\'+ CurrentProfile.name + '\'; ForceDirectories(PathList.Values['TempPath']); ForceDirectories(LogPath); ForceDirectories(PathList.Values['ProfilePath']); // SET GAME VARS SetGame(CurrentProfile.gameMode); wbVWDInTemporary := wbGameMode in [gmSSE, gmTES5, gmFO3, gmFNV]; wbVWDAsQuestChildren := wbGameMode = gmFO4; wbArchiveExtension := IfThen(wbGameMode = gmFO4, '.ba2', '.bsa'); wbLoadBSAs := wbGameMode in [gmFO4, gmSSE, gmTES5, gmTES4]; Logger.Write('GENERAL', 'Game', 'Using '+wbGameName); Logger.Write('GENERAL', 'Path', 'Using '+wbDataPath); Logger.Write('GENERAL', 'GameIni', 'Using '+wbTheGameIniFileName); // INITIALIZE SETTINGS FOR GAME LoadSettings; LoadLanguage; // INITIALIZE XEDIT wbDisplayLoadOrderFormID := True; wbSortSubRecords := True; wbDisplayShorterNames := True; wbHideUnused := True; wbHideIgnored := False; wbFlagsAsArray := True; wbRequireLoadOrder := True; wbLanguage := GetLanguageFileSuffix; wbEditAllowed := True; wbContainerHandler := wbCreateContainerHandler; wbContainerHandler._AddRef; // INITIALIZE DEFINITIONS Logger.Write('GENERAL', 'Definitions', 'Using '+wbAppName+'Edit Definitions'); LoadDefinitions; // LOAD SMASH SETTINGS Tracker.Write('Loading smash settings'); LoadSmashSettings; // LOAD PATCHES Tracker.Write('Loading patches'); LoadPatches; // PREPARE LOAD ORDER slLoadOrder := TStringList.Create; slLoadOrder.CaseSensitive := False; slPlugins := TStringList.Create; PrepareLoadOrder(slLoadOrder, slPlugins); // DISPLAY PLUGIN SELECTION FORM THeaderHelpers.LoadPluginHeaders(slLoadOrder); psForm := TPluginSelectionForm.Create(nil); psForm.slCheckedPlugins := slPlugins; psForm.slAllPlugins := slLoadOrder; psForm.sColumns := 'Plugin,Patch'; psForm.GetPluginInfo := TPatchHelpers.GetPatchForPlugin; psForm.GetPluginMasters := THeaderHelpers.GetPluginMasters; psForm.GetPluginDependencies := THeaderHelpers.GetPluginDependencies; if psForm.ShowModal = mrCancel then exit; slPlugins.Text := psForm.slCheckedPlugins.Text; psForm.Free; wbFileForceClosed; FreeList(HeaderList); // ALL DONE Result := true; end; { Check if game paths are valid } function GamePathValid(path: string; id: integer): boolean; begin Result := FileExists(path + GameArray[id].exeName) and DirectoryExists(path + 'Data'); end; { Sets the game mode in the TES5Edit API } procedure SetGame(id: integer); var sMyDocumentsPath: string; sIniPath: string; begin ProgramStatus.GameMode := GameArray[id]; wbGameName := ProgramStatus.GameMode.gameName; wbGameName2 := ProgramStatus.GameMode.regName; wbGameMode := ProgramStatus.GameMode.gameMode; wbAppName := ProgramStatus.GameMode.appName; wbDataPath := CurrentProfile.gamePath + 'Data\'; // set general paths PathList.Values['DataPath'] := wbDataPath; PathList.Values['GamePath'] := UpDirectory(wbDataPath); // find game ini inside the user's documents folder. sMyDocumentsPath := GetCSIDLShellFolder(CSIDL_PERSONAL); if sMyDocumentsPath <> '' then begin sIniPath := sMyDocumentsPath + 'My Games\' + wbGameName2 + '\'; if wbGameMode in [gmFO3, gmFNV] then wbTheGameIniFileName := sIniPath + 'Fallout.ini' else wbTheGameIniFileName := sIniPath + wbGameName + '.ini'; end; end; { Get the game ID associated with a game long name } function GetGameID(name: string): integer; var i: integer; begin Result := 0; for i := Low(GameArray) to High(GameArray) do if GameArray[i].longName = name then begin Result := i; exit; end; end; { Gets language file suffix } function GetLanguageFileSuffix: String; begin Result := settings.language; if (wbGameMode = gmFO4) and (slLanguageMap.IndexOfName(Result) > -1) then Result := slLanguageMap.Values[Result]; end; { Gets the path of a game from registry key or app path } function GetGamePath(mode: TGameMode): string; const sBethRegKey = '\SOFTWARE\Bethesda Softworks\'; sBethRegKey64 = '\SOFTWARE\Wow6432Node\Bethesda Softworks\'; sSteamRegKey = '\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\'+ 'Steam App '; sSteamRegKey64 = '\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\'+ 'Uninstall\Steam App '; var i: Integer; regName: string; keys, appIDs: TStringList; begin Result := ''; // initialize variables regName := mode.regName; keys := TStringList.Create; appIDs := TStringList.Create; appIDs.CommaText := mode.appIDs; // add keys to check keys.Add(sBethRegKey + regName + '\Installed Path'); keys.Add(sBethRegKey64 + regName + '\Installed Path'); for i := 0 to Pred(appIDs.Count) do begin keys.Add(sSteamRegKey + appIDs[i] + '\InstallLocation'); keys.Add(sSteamRegKey64 + appIDs[i] + '\InstallLocation'); end; // try to find path from registry Result := TryRegistryKeys(keys); // free memory keys.Free; appIDs.Free; // set result if Result <> '' then Result := IncludeTrailingPathDelimiter(Result); end; { Loads definitions based on wbGameMode } procedure LoadDefinitions; begin case wbGameMode of gmTES5: DefineTES5; gmFNV: DefineFNV; gmTES4: DefineTES4; gmFO3: DefineFO3; gmFO4: DefineFO4; gmSSE: DefineTES5; end; end; procedure LoadBSAFile(sFileName: String); var sFileExt: String; begin sFileExt := ExtractFileExt(sFileName); Logger.Write('LOAD', 'Resources', 'Loading resources from ' + sFileName); if sFileExt = '.bsa' then wbContainerHandler.AddBSA(wbDataPath + sFileName) else if sFileExt = '.ba2' then wbContainerHandler.AddBA2(wbDataPath + sFileName); end; { Loads all of the BSAs specified in the game ini and by plugins } procedure LoadBSAs; var slBSAFileNames: TStringList; slErrors: TStringList; i: Integer; modIndex: Integer; plugin: TPlugin; bIsTES5: Boolean; begin slBSAFileNames := TStringList.Create; try slErrors:= TStringList.Create; try FindBSAs(wbTheGameIniFileName, wbDataPath, slBSAFileNames, slErrors); for i := 0 to slBSAFileNames.Count - 1 do LoadBSAFile(slBSAFileNames[i]); for i := 0 to slErrors.Count - 1 do Logger.Write('ERROR', 'Load', slErrors[i] + ' was not found'); for modIndex := 0 to PluginsList.Count - 1 do begin slBSAFileNames.Clear; slErrors.Clear; plugin := TPlugin(PluginsList[modIndex]); bIsTES5 := wbGameMode in [gmTES5, gmSSE]; HasBSAs(ChangeFileExt(plugin.filename, ''), wbDataPath, bIsTES5, bIsTES5, slBSAFileNames, slErrors); for i := 0 to slBSAFileNames.Count - 1 do LoadBSAFile(slBSAFileNames[i]); for i := 0 to slErrors.Count - 1 do Logger.Write('ERROR', 'Load', slErrors[i] + ' was not found'); end; finally slErrors.Free; end; finally slBSAFileNames.Free; end; end; {******************************************************************************} { Load order functions Set of functions for building a working load order. List of functions: - RemoveCommentsAndEmpty - RemoveMissingFiles - AddMissingFiles - PluginListCompare {******************************************************************************} { Remove comments and empty lines from a stringlist } procedure RemoveCommentsAndEmpty(var sl: TStringList); var i, j, k: integer; s: string; begin for i := Pred(sl.Count) downto 0 do begin s := Trim(sl.Strings[i]); j := Pos('#', s); k := Pos('*', s); if j > 0 then System.Delete(s, j, High(Integer)); if s = '' then sl.Delete(i); if k = 1 then sl[i] := Copy(s, 2, Length(s)); end; end; { Remove nonexistent files from stringlist } procedure RemoveMissingFiles(var sl: TStringList); var i: integer; begin for i := Pred(sl.Count) downto 0 do if not FileExists(wbDataPath + sl.Strings[i]) then sl.Delete(i); end; { Remove smashed patch plugins from stringlist } procedure RemoveSmashedPatches(var sl: TStringList); var i: integer; begin for i := Pred(sl.Count) downto 0 do if Assigned(TPatchHelpers.PatchByFilename(PatchesList, sl[i])) then sl.Delete(i); end; { Forces a plugin to load at a specific position } procedure FixLoadOrder(var sl: TStringList; const filename: String; var index: Integer); var oldIndex: Integer; begin oldIndex := sl.IndexOf(filename); if (oldIndex > -1) then begin if oldIndex <> index then begin sl.Delete(oldIndex); sl.Insert(index, filename); end; end else if FileExists(wbDataPath + filename) then sl.Insert(index, filename) else exit; Inc(index); end; procedure AddBaseMasters(var sl: TStringList); var index: Integer; begin index := 0; FixLoadOrder(sl, wbGameName + '.esm', index); if (wbGameMode = gmTES5) then FixLoadOrder(sl, 'Update.esm', index) else if (wbGameMode = gmSSE) then begin FixLoadOrder(sl, 'Update.esm', index); FixLoadOrder(sl, 'Dawnguard.esm', index); FixLoadOrder(sl, 'HearthFires.esm', index); FixLoadOrder(sl, 'Dragonborn.esm', index); end else if (wbGameMode = gmFO4) then begin FixLoadOrder(sl, 'DLCRobot.esm', index); FixLoadOrder(sl, 'DLCworkshop01.esm', index); FixLoadOrder(sl, 'DLCCoast.esm', index); FixLoadOrder(sl, 'DLCworkshop02.esm', index); FixLoadOrder(sl, 'DLCworkshop03.esm', index); FixLoadOrder(sl, 'DLCNukaWorld.esm', index); FixLoadOrder(sl, 'DLCUltraHighResolution.esm', index); end; end; function GetPluginDate(const aFileName: string): Cardinal; const DateOmitYears = 60; DatePrecision = 100000; var F: TSearchRec; begin // Try to fit a meaningful modified date of a file into 32 bits integer value // For relative load order sorting only // Oblivion GOG version has dates from 1969 year and FileAge() doesn't support them if FindFirst(aFileName, faAnyFile, F) = 0 then begin Result := Round((F.TimeStamp - 364 * DateOmitYears) * DatePrecision); FindClose(F); end else Result := 0; end; { Compare function for sorting load order by date modified/esms } function PluginListCompare(List: TStringList; Index1, Index2: Integer): Integer; var IsESM1, IsESM2: Boolean; FileSK1, FileSK2: Integer; begin IsESM1 := IsFileESM(List[Index1]); IsESM2 := IsFileESM(List[Index2]); if IsESM1 = IsESM2 then begin FileSK1 := Cardinal(List.Objects[Index1]); FileSK2 := Cardinal(List.Objects[Index2]); if FileSK1 < FileSK2 then Result := -1 else if FileSK1 > FileSK2 then Result := 1 else Result := 0; end else if IsESM1 then Result := -1 else Result := 1; end; { Add missing *.esp, *.esl, and *.esm files to list } procedure AddMissingFiles(var sl: TStringList); var F: TSearchRec; i, j: integer; slNew: TStringList; fileSortKey: Cardinal; begin slNew := TStringList.Create; try // search for missing plugins and masters if FindFirst(wbDataPath + '*.*', faAnyFile, F) = 0 then try repeat if not (IsFileESM(F.Name) or IsFileESP(F.Name) or IsFileESL(F.Name)) then continue; if sl.IndexOf(F.Name) = -1 then begin fileSortKey := GetPluginDate(wbDataPath + F.Name); slNew.AddObject(F.Name, TObject(fileSortKey)); end; until FindNext(F) <> 0; finally FindClose(F); end; // sort the list slNew.CustomSort(PluginListCompare); // The for loop won't initialize j if sl.count = 0, we must force it // to -1 so inserting will happen at index 0 if sl.Count = 0 then j := -1 else // find position of last master for j := Pred(sl.Count) downto 0 do if IsFileESM(sl[j]) then Break; // add esm masters after the last master, add esp plugins at the end Inc(j); for i := 0 to Pred(slNew.Count) do begin if IsFileESM(slNew[i]) then begin sl.InsertObject(j, slNew[i], slNew.Objects[i]); Inc(j); end else sl.AddObject(slNew[i], slNew.Objects[i]); end; finally slNew.Free; end; end; procedure ProcessAsterisks(var sl: TStringList; index: Integer; noDelete: Boolean); var s: String; begin s := sl[index]; if s[1] <> '*' then begin if not noDelete then sl.Delete(index); end else sl[index] := Copy(s, 2, Length(s)); end; procedure ProcessPluginsFormat(var sl: TStringList; noDelete: Boolean); var i: Integer; begin for i := Pred(sl.Count) downto 0 do ProcessAsterisks(sl, i, noDelete); end; procedure LoadPluginsList(const sLoadPath: String; var sl: TStringList; noDelete: Boolean = False); var sPath: String; begin sPath := sLoadPath + 'plugins.txt'; if FileExists(sPath) then begin sl.LoadFromFile(sPath); if (wbGameMode = gmSSE) or (wbGameMode = gmFO4) then ProcessPluginsFormat(sl, noDelete); end else AddMissingFiles(sl); // remove comments and missing files AddBaseMasters(sl); RemoveCommentsAndEmpty(sl); RemoveMissingFiles(sl); if noDelete then AddMissingFiles(sl); RemoveSmashedPatches(sl); end; procedure LoadLoadOrder(const sLoadPath: String; var slLoadOrder: TStringList); var sPath: String; begin sPath := sLoadPath + 'loadorder.txt'; if (wbGameMode <> gmSSE) and (wbGameMode <> gmFO4) and FileExists(sPath) then begin slLoadOrder.LoadFromFile(sPath); // remove comments and add/remove files AddBaseMasters(slLoadOrder); RemoveCommentsAndEmpty(slLoadOrder); RemoveMissingFiles(slLoadOrder); AddMissingFiles(slLoadOrder); RemoveSmashedPatches(slLoadOrder); end else LoadPluginsList(sLoadPath, slLoadOrder, True); end; procedure PrepareLoadOrder(var slLoadOrder, slPlugins: TStringList); var sLoadPath: String; begin sLoadPath := GetCSIDLShellFolder(CSIDL_LOCAL_APPDATA) + wbGameName2 +'\'; LoadPluginsList(sLoadPath, slPlugins); LoadLoadOrder(sLoadPath, slLoadOrder); end; { Log Initialization } procedure InitLog; begin // INITIALIZE GROUP FILTERS GroupFilters.Add(TFilter.Create('GENERAL', true)); GroupFilters.Add(TFilter.Create('LOAD', true)); GroupFilters.Add(TFilter.Create('CLIENT', true)); GroupFilters.Add(TFilter.Create('MERGE', true)); GroupFilters.Add(TFilter.Create('PLUGIN', true)); GroupFilters.Add(TFilter.Create('ERROR', true)); // INITIALIZE LABEL FILTERS LabelFilters.Add(TFilter.Create('GENERAL', 'Game', true)); LabelFilters.Add(TFilter.Create('GENERAL', 'Status', true)); LabelFilters.Add(TFilter.Create('GENERAL', 'Path', true)); LabelFilters.Add(TFilter.Create('GENERAL', 'Definitions', true)); LabelFilters.Add(TFilter.Create('GENERAL', 'Dictionary', true)); LabelFilters.Add(TFilter.Create('GENERAL', 'Load Order', true)); LabelFilters.Add(TFilter.Create('GENERAL', 'Log', true)); LabelFilters.Add(TFilter.Create('LOAD', 'Order', false)); LabelFilters.Add(TFilter.Create('LOAD', 'Plugins', false)); LabelFilters.Add(TFilter.Create('LOAD', 'Background', true)); LabelFilters.Add(TFilter.Create('CLIENT', 'Connect', true)); LabelFilters.Add(TFilter.Create('CLIENT', 'Login', true)); LabelFilters.Add(TFilter.Create('CLIENT', 'Response', true)); LabelFilters.Add(TFilter.Create('CLIENT', 'Update', true)); LabelFilters.Add(TFilter.Create('CLIENT', 'Report', true)); LabelFilters.Add(TFilter.Create('PATCH', 'Status', false)); LabelFilters.Add(TFilter.Create('PATCH', 'Create', true)); LabelFilters.Add(TFilter.Create('PATCH', 'Edit', true)); LabelFilters.Add(TFilter.Create('PATCH', 'Check', true)); LabelFilters.Add(TFilter.Create('PATCH', 'Clean', true)); LabelFilters.Add(TFilter.Create('PATCH', 'Delete', true)); LabelFilters.Add(TFilter.Create('PATCH', 'Build', true)); LabelFilters.Add(TFilter.Create('PATCH', 'Report', true)); LabelFilters.Add(TFilter.Create('PLUGIN', 'Report', true)); LabelFilters.Add(TFilter.Create('PLUGIN', 'Check', true)); end; initialization slLanguageMap := TStringList.Create; slLanguageMap.Text := 'English=en'#13 + 'French=fr'#13 + 'German=de'#13 + 'Italian=it'#13 + 'Spanish=es'#13 + 'Russian=ru'#13 + 'Polish=pl'#13 + 'Japanese=ja'#13 + 'Portugese=pt'#13 + 'Chinese=zh'; finalization slLanguageMap.Free; end. ================================================ FILE: frontend/msOptionsForm.dfm ================================================ object OptionsForm: TOptionsForm Left = 0 Top = 0 Caption = 'Settings' ClientHeight = 447 ClientWidth = 584 Color = clBtnFace Constraints.MaxHeight = 485 Constraints.MaxWidth = 600 Constraints.MinHeight = 485 Constraints.MinWidth = 600 Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'Tahoma' Font.Style = [] OldCreateOrder = False Position = poScreenCenter OnCreate = FormCreate PixelsPerInch = 96 TextHeight = 13 object SettingsPageControl: TPageControl Left = 8 Top = 8 Width = 568 Height = 401 ActivePage = GeneralTabSheet Align = alCustom Anchors = [akLeft, akTop, akRight, akBottom] TabOrder = 0 TabWidth = 80 object GeneralTabSheet: TTabSheet Caption = 'General' object gbStyle: TGroupBox Left = 6 Top = 69 Width = 548 Height = 71 Margins.Left = 6 Margins.Top = 6 Margins.Right = 6 Margins.Bottom = 6 Align = alCustom Caption = 'Style' TabOrder = 0 object kbSimpleDictionary: TCheckBox Left = 12 Top = 20 Width = 205 Height = 17 Align = alCustom Caption = 'Simple dictionary view' TabOrder = 0 end object kbSimplePlugins: TCheckBox Left = 12 Top = 43 Width = 205 Height = 17 Align = alCustom Caption = 'Simple plugins list' TabOrder = 1 end end object gbLanguage: TGroupBox Left = 6 Top = 6 Width = 548 Height = 51 Margins.Left = 6 Margins.Top = 6 Margins.Right = 6 Margins.Bottom = 6 Align = alCustom Caption = 'Language' TabOrder = 1 object lblLanguage: TLabel Left = 12 Top = 20 Width = 78 Height = 13 Margins.Left = 6 Margins.Top = 6 Margins.Right = 6 Margins.Bottom = 6 Align = alCustom Caption = 'Current languge' end object cbLanguage: TComboBox Left = 265 Top = 17 Width = 274 Height = 21 Margins.Left = 6 Margins.Top = 6 Margins.Right = 6 Margins.Bottom = 6 Align = alCustom Style = csDropDownList Anchors = [akTop, akRight] TabOrder = 0 end end end object PatchingTabSheet: TTabSheet Caption = 'Patching' ImageIndex = 1 ExplicitLeft = 0 ExplicitTop = 28 object gbGeneral: TGroupBox Left = 3 Top = 3 Width = 554 Height = 54 Caption = 'General' TabOrder = 0 object lblDestinationDirectory: TLabel Left = 12 Top = 20 Width = 129 Height = 13 Caption = 'Patch destination directory' end object btnBrowsePatchDirectory: TSpeedButton Left = 519 Top = 17 Width = 23 Height = 22 Hint = 'Browse' Margins.Right = 6 ParentShowHint = False ShowHint = True OnClick = btnBrowsePatchDirectoryClick end object edPatchDirectory: TEdit Left = 168 Top = 17 Width = 345 Height = 21 TabOrder = 0 end end object gbDebug: TGroupBox Left = 3 Top = 63 Width = 554 Height = 146 Caption = 'Debug' TabOrder = 1 object kbDebugPatchStatus: TCheckBox Left = 12 Top = 24 Width = 200 Height = 17 Align = alCustom Caption = 'Debug patch status' TabOrder = 0 end object kbDebugMasters: TCheckBox Left = 12 Top = 47 Width = 200 Height = 17 Align = alCustom Caption = 'Debug masters' TabOrder = 1 end object kbDebugArrays: TCheckBox Left = 12 Top = 70 Width = 200 Height = 17 Align = alCustom Caption = 'Debug arrays' TabOrder = 2 end object kbDebugSkips: TCheckBox Left = 12 Top = 93 Width = 200 Height = 17 Align = alCustom Caption = 'Debug skips' TabOrder = 3 end object kbDebugTraversal: TCheckBox Left = 12 Top = 116 Width = 200 Height = 17 Align = alCustom Caption = 'Debug traversal' TabOrder = 4 end object kbDebugTypes: TCheckBox Left = 273 Top = 24 Width = 200 Height = 17 Align = alCustom Caption = 'Debug types' TabOrder = 5 end object kbDebugChanges: TCheckBox Left = 272 Top = 47 Width = 200 Height = 17 Align = alCustom Caption = 'Debug changes' TabOrder = 6 end object kbDebugSingle: TCheckBox Left = 272 Top = 72 Width = 200 Height = 17 Align = alCustom Caption = 'Debug treat as single' TabOrder = 7 end object kbDebugLinks: TCheckBox Left = 272 Top = 95 Width = 200 Height = 17 Align = alCustom Caption = 'Debug links' TabOrder = 8 end end object gbOther: TGroupBox Left = 3 Top = 215 Width = 554 Height = 58 Caption = 'Other Options' TabOrder = 2 object kbBuildRefs: TCheckBox Left = 12 Top = 22 Width = 201 Height = 17 Align = alCustom Caption = 'Build references' TabOrder = 0 end object kbPreserveITPOs: TCheckBox Left = 273 Top = 22 Width = 201 Height = 17 Align = alCustom Caption = 'Preserve ITPOs' TabOrder = 1 end end end object AdvancedTabSheet: TTabSheet Caption = 'Advanced' ImageIndex = 2 object gbLogging: TGroupBox Left = 6 Top = 72 Width = 548 Height = 190 Margins.Left = 6 Margins.Top = 6 Margins.Right = 6 Margins.Bottom = 6 Align = alCustom Anchors = [akLeft, akTop, akRight] Caption = 'Logging' TabOrder = 0 object lblClientColor: TLabel Left = 12 Top = 20 Width = 27 Height = 13 Caption = 'Client' end object lblGeneralColor: TLabel Left = 12 Top = 48 Width = 37 Height = 13 Margins.Left = 12 Margins.Top = 11 Caption = 'General' end object lblLoadColor: TLabel Left = 12 Top = 76 Width = 23 Height = 13 Margins.Left = 12 Margins.Top = 11 Caption = 'Load' end object lblPatchColor: TLabel Left = 274 Top = 20 Width = 27 Height = 13 Align = alCustom Anchors = [akTop, akRight] Caption = 'Patch' end object lblPluginColor: TLabel Left = 274 Top = 48 Width = 28 Height = 13 Margins.Top = 11 Align = alCustom Anchors = [akTop, akRight] Caption = 'Plugin' end object lblErrorColor: TLabel Left = 274 Top = 76 Width = 29 Height = 13 Margins.Top = 11 Align = alCustom Anchors = [akTop, akRight] Caption = 'Errors' end object lblSample: TLabel Left = 12 Top = 155 Width = 34 Height = 13 Margins.Left = 12 Margins.Top = 6 Margins.Right = 6 Margins.Bottom = 6 Caption = 'Sample' end object lblSampleValue: TLabel Left = 88 Top = 155 Width = 232 Height = 13 Margins.Left = 6 Margins.Top = 6 Margins.Right = 6 Margins.Bottom = 6 Caption = '[12:34] (GENERAL) Test: This is a test message.' Font.Charset = DEFAULT_CHARSET Font.Color = clGreen Font.Height = -11 Font.Name = 'Tahoma' Font.Style = [] ParentFont = False end object lblTemplate: TLabel Left = 12 Top = 109 Width = 44 Height = 13 Margins.Left = 12 Margins.Top = 6 Margins.Right = 6 Margins.Bottom = 6 Caption = 'Template' end object cbClientColor: TColorBox Left = 88 Top = 17 Width = 145 Height = 22 Selected = clBlue Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbCustomColor, cbPrettyNames, cbCustomColors] TabOrder = 0 end object cbGeneralColor: TColorBox Left = 88 Top = 45 Width = 145 Height = 22 Selected = clGreen Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbCustomColor, cbPrettyNames, cbCustomColors] TabOrder = 1 end object cbLoadColor: TColorBox Left = 88 Top = 73 Width = 145 Height = 22 Selected = clPurple Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbCustomColor, cbPrettyNames, cbCustomColors] TabOrder = 2 end object cbPatchColor: TColorBox Left = 392 Top = 17 Width = 145 Height = 22 Align = alCustom Selected = 33023 Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbCustomColor, cbPrettyNames, cbCustomColors] Anchors = [akTop, akRight] TabOrder = 3 end object cbPluginColor: TColorBox Left = 392 Top = 45 Width = 145 Height = 22 Align = alCustom Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbCustomColor, cbPrettyNames, cbCustomColors] Anchors = [akTop, akRight] TabOrder = 4 end object cbErrorColor: TColorBox Left = 392 Top = 73 Width = 145 Height = 22 Align = alCustom Selected = clRed Style = [cbStandardColors, cbExtendedColors, cbSystemColors, cbCustomColor, cbPrettyNames, cbCustomColors] Anchors = [akTop, akRight] TabOrder = 5 end object meTemplate: TMemo Left = 88 Top = 109 Width = 449 Height = 37 Align = alCustom Anchors = [akLeft, akTop, akRight] Lines.Strings = ( '[{{Time}}] ({{Group}}) {{Label}}: {{Text}}') ScrollBars = ssVertical TabOrder = 6 OnChange = meTemplateChange end end object gbSmashProfile: TGroupBox Left = 6 Top = 6 Width = 548 Height = 54 Margins.Left = 6 Margins.Top = 6 Margins.Right = 6 Margins.Bottom = 6 Align = alCustom Anchors = [akLeft, akTop, akRight] Caption = 'Smash Profile' TabOrder = 1 object lblCurrentProfile: TLabel Left = 12 Top = 24 Width = 70 Height = 13 Caption = 'Current profile' end object lblCurrentProfileName: TLabel Left = 151 Top = 24 Width = 89 Height = 13 Margins.Left = 6 Margins.Top = 6 Margins.Right = 6 Margins.Bottom = 6 Caption = '' Font.Charset = DEFAULT_CHARSET Font.Color = clGreen Font.Height = -11 Font.Name = 'Tahoma' Font.Style = [] ParentFont = False end object btnChangeSmashProfile: TButton Left = 392 Top = 18 Width = 150 Height = 25 Caption = 'Switch smash profiles' TabOrder = 0 OnClick = btnChangeSmashProfileClick end end end end object btnCancel: TButton Left = 501 Top = 415 Width = 75 Height = 25 Align = alCustom Anchors = [akRight, akBottom] Caption = 'Cancel' ModalResult = 2 TabOrder = 1 end object btnOK: TButton Left = 420 Top = 415 Width = 75 Height = 25 Align = alCustom Anchors = [akRight, akBottom] Caption = 'OK' ModalResult = 1 TabOrder = 2 OnClick = btnOKClick end object IconList: TImageList Left = 16 Top = 400 Bitmap = { 494C0101010008007C0110001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600 0000000000003600000028000000400000001000000001002000000000000010 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000075848FFF66808FFF607987FF576E 7BFF4E626FFF445661FF394852FF2E3A43FF252E35FF1B2229FF14191EFF0E12 16FF0E1318FF0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000778792FF89A1ABFF6AB2D4FF008F CDFF008FCDFF008FCDFF048CC7FF0888BEFF0F82B4FF157CA9FF1B779FFF1F72 96FF214A5BFEBDC2C44A00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000007A8A95FF7EBED3FF8AA4AEFF7EDC FFFF5FCFFFFF55CBFFFF4CC4FAFF41BCF5FF37B3F0FF2EAAEBFF24A0E5FF138C D4FF236780FF5E686CB400000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000007D8E98FF79D2ECFF8BA4ADFF89C2 CEFF71D8FFFF65D3FFFF5CCEFFFF51C9FEFF49C1FAFF3FB9F5FF34B0EEFF29A8 E9FF1085CDFF224B5BFFDADDDF27000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000080919CFF81D7EFFF7DC5E0FF8CA6 B0FF80DDFEFF68D3FFFF67D4FFFF62D1FFFF58CDFFFF4EC7FCFF46BEF7FF3BB6 F2FF31ACECFF256981FF7A95A190000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000083959FFF89DCF1FF8CE2FFFF8DA8 B1FF8CBAC7FF74D8FFFF67D4FFFF67D4FFFF67D4FFFF5FD0FFFF54CDFFFF4BC5 FCFF41BBF7FF2EA2DBFF516674F1E1E4E62B0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000869AA3FF92E1F2FF98E8FDFF80C4 DEFF8EA7B0FF81DEFDFF84E0FFFF84E0FFFF84E0FFFF84E0FFFF81DFFFFF7BDD FFFF74D8FFFF6BD6FFFF56A9D1FF8E9BA3A20000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000889CA5FF9AE6F3FF9FEBFBFF98E8 FEFF8BACB9FF8BACB9FF8AAAB7FF88A6B3FF86A3AFFF839FAAFF819AA6FF7F95 A1FF7C919DFF7A8E99FF798B95FF778893FF0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000008BA0A8FFA0EAF6FFA6EEF9FF9FEB FBFF98E8FEFF7ADAFFFF67D4FFFF67D4FFFF67D4FFFF67D4FFFF67D4FFFF67D4 FFFF778893FF0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000008EA2ABFFA7EEF6FFABF0F7FFA6EE F9FF9FEBFBFF98E8FDFF71D4FBFF899EA7FF8699A3FF82949FFF7E909AFF7A8C 97FF778893FF0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000008FA4ACFFA0D2DAFFABF0F7FFABF0 F7FFA6EEF9FF9FEBFBFF8DA1AAFFC0D0D6820000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000D8DFE2578FA4ACFF8FA4ACFF8FA4 ACFF8FA4ACFF8FA4ACFFBDCFD68D000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000424D3E000000000000003E000000 2800000040000000100000000100010000000000800000000000000000000000 000000000000000000000000FFFFFF00FFFF000000000000FFFF000000000000 0007000000000000000300000000000000030000000000000001000000000000 0001000000000000000000000000000000000000000000000000000000000000 0007000000000000000700000000000000FF00000000000001FF000000000000 FFFF000000000000FFFF00000000000000000000000000000000000000000000 000000000000} end end ================================================ FILE: frontend/msOptionsForm.pas ================================================ unit msOptionsForm; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ComCtrls, StdCtrls, Buttons, ImgList, FileCtrl, ExtCtrls, Types, // mte units mteHelpers, RttiTranslation, // mp units msConfiguration; type TOptionsForm = class(TForm) [FormPrefix('mpOpt')] SettingsPageControl: TPageControl; btnCancel: TButton; btnOK: TButton; IconList: TImageList; [FormSection('General Tab')] GeneralTabSheet: TTabSheet; gbLanguage: TGroupBox; lblLanguage: TLabel; gbStyle: TGroupBox; kbSimpleDictionary: TCheckBox; kbSimplePlugins: TCheckBox; [FormSection('DontTranslate')] cbLanguage: TComboBox; [FormSection('Patching Tab')] PatchingTabSheet: TTabSheet; gbGeneral: TGroupBox; edPatchDirectory: TEdit; lblDestinationDirectory: TLabel; btnBrowsePatchDirectory: TSpeedButton; gbDebug: TGroupBox; kbDebugPatchStatus: TCheckBox; kbDebugMasters: TCheckBox; kbDebugArrays: TCheckBox; kbDebugSkips: TCheckBox; kbDebugTraversal: TCheckBox; kbDebugTypes: TCheckBox; kbDebugChanges: TCheckBox; kbDebugSingle: TCheckBox; kbDebugLinks: TCheckBox; gbOther: TGroupBox; kbBuildRefs: TCheckBox; kbPreserveITPOs: TCheckBox; [FormSection('Advanced Tab')] AdvancedTabSheet: TTabSheet; lblCurrentProfile: TLabel; gbLogging: TGroupBox; lblClientColor: TLabel; cbClientColor: TColorBox; lblGeneralColor: TLabel; cbGeneralColor: TColorBox; lblLoadColor: TLabel; cbLoadColor: TColorBox; lblPluginColor: TLabel; cbPluginColor: TColorBox; lblErrorColor: TLabel; cbErrorColor: TColorBox; lblTemplate: TLabel; meTemplate: TMemo; lblSample: TLabel; [FormSection('DontTranslate')] lblCurrentProfileName: TLabel; lblSampleValue: TLabel; procedure FormCreate(Sender: TObject); procedure LoadLanguageOptions; procedure btnOKClick(Sender: TObject); procedure btnBrowsePatchDirectoryClick(Sender: TObject); procedure meTemplateChange(Sender: TObject); procedure appendBackslashOnExit(Sender: TObject); procedure btnChangeSmashProfileClick(Sender: TObject); private { Private declarations } public { Public declarations } end; var OptionsForm: TOptionsForm; slSampleLogMessage: TStringList; implementation {$R *.dfm} procedure TOptionsForm.btnBrowsePatchDirectoryClick(Sender: TObject); begin BrowseForFolder(edPatchDirectory, PathList.Values['ProgramPath']); end; procedure TOptionsForm.btnOKClick(Sender: TObject); begin // check if we need to update patch status afterwards ProgramStatus.bUpdatePatchStatus := settings.patchDirectory <> edPatchDirectory.Text; // General > Language settings.language := cbLanguage.Text; // General > Style settings.simpleDictionaryView := kbSimpleDictionary.Checked; settings.simplePluginsView := kbSimplePlugins.Checked; // Patching > General settings.patchDirectory := edPatchDirectory.Text; // Patching > Debug settings.debugPatchStatus := kbDebugPatchStatus.Checked; settings.debugMasters := kbDebugMasters.Checked; settings.debugArrays := kbDebugArrays.Checked; settings.debugSkips := kbDebugSkips.Checked; settings.debugTraversal := kbDebugTraversal.Checked; settings.debugTypes := kbDebugTypes.Checked; settings.debugChanges := kbDebugChanges.Checked; settings.debugSingle := kbDebugSingle.Checked; settings.debugLinks := kbDebugLinks.Checked; settings.buildRefs := kbBuildRefs.Checked; settings.preserveITPOs := kbPreserveITPOs.Checked; // Advanced > Logging settings.clientMessageColor := cbClientColor.Selected ; settings.generalMessageColor := cbGeneralColor.Selected; settings.loadMessageColor := cbLoadColor.Selected; //settings.patchMessageColor := cbPatchColor.Selected; settings.pluginMessageColor := cbPluginColor.Selected; settings.errorMessageColor := cbErrorColor.Selected; settings.logMessageTemplate := meTemplate.Lines.Text; SaveSettings; end; procedure TOptionsForm.btnChangeSmashProfileClick(Sender: TObject); begin ProgramStatus.bChangeProfile := true; btnOKClick(nil); Close; end; procedure TOptionsForm.appendBackslashOnExit(Sender: TObject); var ed: TEdit; begin // add trailing backslash if length > 0 and it is missing ed := TEdit(Sender); if Length(ed.Text) > 0 then ed.Text := AppendIfMissing(ed.Text, '\'); end; procedure TOptionsForm.LoadLanguageOptions; var info: TSearchRec; sLang: string; begin cbLanguage.Items.Add('English'); cbLanguage.ItemIndex := 0; if not DirectoryExists('lang') then exit; if FindFirst('lang\*.lang', faAnyFile, info) <> 0 then exit; repeat sLang := TitleCase(ChangeFileExt(info.Name, '')); if sLang <> 'English' then cbLanguage.Items.Add(sLang); until FindNext(info) <> 0; FindClose(info); end; procedure TOptionsForm.FormCreate(Sender: TObject); var index: Integer; begin // do translation dump? if bTranslationDump then TRttiTranslation.Save('lang\english.lang', self); // load translation TRttiTranslation.Load(language, self); // prepare sample log message slSampleLogMessage := TStringList.Create; slSampleLogMessage.Values['Time'] := '12:34:56'; slSampleLogMessage.Values['AppTime'] := '00:01:52'; slSampleLogMessage.Values['Group'] := 'GENERAL'; slSampleLogMessage.Values['Label'] := 'Test'; slSampleLogMessage.Values['Text'] := 'This is a test message.'; // General > Language LoadLanguageOptions; index := cbLanguage.Items.IndexOf(settings.language); if index > -1 then cbLanguage.ItemIndex := index; // General > Style kbSimpleDictionary.Checked := settings.simpleDictionaryView; kbSimplePlugins.Checked := settings.simplePluginsView; // Patching > General edPatchDirectory.Text := settings.patchDirectory; // Patching > Debug kbDebugPatchStatus.Checked := settings.debugPatchStatus; kbDebugMasters.Checked := settings.debugMasters; kbDebugArrays.Checked := settings.debugArrays; kbDebugSkips.Checked := settings.debugSkips; kbDebugTraversal.Checked := settings.debugTraversal; kbDebugTypes.Checked := settings.debugTypes; kbDebugChanges.Checked := settings.debugChanges; kbDebugSingle.Checked := settings.debugSingle; kbDebugLinks.Checked := settings.debugLinks; kbBuildRefs.Checked := settings.buildRefs; kbPreserveITPOs.Checked := settings.preserveITPOs; // Advanced > Profile lblCurrentProfileName.Caption := settings.profile; // Advanced > Logging cbClientColor.Selected := TColor(settings.clientMessageColor); cbGeneralColor.Selected := TColor(settings.generalMessageColor); cbLoadColor.Selected := TColor(settings.loadMessageColor); //cbPatchColor.Selected := TColor(settings.patchMessageColor); cbPluginColor.Selected := TColor(settings.pluginMessageColor); cbErrorColor.Selected := TColor(settings.errorMessageColor); meTemplate.Lines.Text := settings.logMessageTemplate; // set up browse buttons btnBrowsePatchDirectory.Flat := true; IconList.GetBitmap(0, btnBrowsePatchDirectory.Glyph); end; procedure TOptionsForm.meTemplateChange(Sender: TObject); var template: string; begin template := meTemplate.Lines.Text; lblSampleValue.Caption := ApplyTemplate(template, slSampleLogMessage); end; end. ================================================ FILE: frontend/msPluginSelectionForm.dfm ================================================ object MiniPluginSelectionForm: TMiniPluginSelectionForm Left = 0 Top = 0 Caption = 'Plugin selection' ClientHeight = 424 ClientWidth = 334 Color = clBtnFace Constraints.MaxHeight = 1500 Constraints.MaxWidth = 700 Constraints.MinHeight = 400 Constraints.MinWidth = 350 Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'Tahoma' Font.Style = [] OldCreateOrder = False Position = poScreenCenter OnShow = FormShow PixelsPerInch = 96 TextHeight = 13 object lblPrompt: TLabel Left = 8 Top = 8 Width = 311 Height = 26 Align = alCustom Anchors = [akLeft, akTop, akRight] Caption = 'Select the plugins you want to base the setting tree off of. Th' + 'is should be the plugins you plan to use this setting with. ' WordWrap = True end object CheckListBox: TCheckListBox Left = 8 Top = 45 Width = 318 Height = 335 Margins.Top = 8 Margins.Bottom = 8 Align = alCustom Anchors = [akLeft, akTop, akRight, akBottom] ItemHeight = 13 PopupMenu = CheckListPopupMenu TabOrder = 0 OnClick = CheckListBoxClick OnKeyUp = CheckListBoxKeyUp end object btnOK: TButton Left = 170 Top = 391 Width = 75 Height = 25 Align = alCustom Anchors = [akRight, akBottom] Caption = 'OK' TabOrder = 1 OnClick = btnOKClick end object btnCancel: TButton Left = 251 Top = 391 Width = 75 Height = 25 Align = alCustom Anchors = [akRight, akBottom] Caption = 'Cancel' ModalResult = 2 TabOrder = 2 end object CheckListPopupMenu: TPopupMenu Left = 64 Top = 64 object SelectAllItem: TMenuItem Caption = 'Select all' OnClick = SelectAllItemClick end object SelectNoneItem: TMenuItem Caption = 'Select none' OnClick = SelectNoneItemClick end object InvertSelectionItem: TMenuItem Caption = 'Invert selection' OnClick = InvertSelectionItemClick end end end ================================================ FILE: frontend/msPluginSelectionForm.pas ================================================ unit msPluginSelectionForm; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, CheckLst, Menus, ComCtrls; type TMiniPluginSelectionForm = class(TForm) CheckListBox: TCheckListBox; btnOK: TButton; lblPrompt: TLabel; btnCancel: TButton; CheckListPopupMenu: TPopupMenu; SelectAllItem: TMenuItem; SelectNoneItem: TMenuItem; InvertSelectionItem: TMenuItem; procedure FormShow(Sender: TObject); procedure CheckListBoxClick(Sender: TObject); procedure btnOKClick(Sender: TObject); procedure CheckListBoxKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); procedure SelectAllItemClick(Sender: TObject); procedure SelectNoneItemClick(Sender: TObject); procedure InvertSelectionItemClick(Sender: TObject); private { Private declarations } public { Public declarations } pluginsList: TStringList; selectionList: TStringList; end; var MiniPluginSelectionForm: TMiniPluginSelectionForm; implementation {$R *.dfm} procedure TMiniPluginSelectionForm.btnOKClick(Sender: TObject); var i: Integer; begin selectionList.Clear; for i := 0 to Pred(CheckListBox.Items.Count) do begin if CheckListBox.Checked[i] then selectionList.Add(CheckListBox.Items[i]); end; if selectionList.Count > 0 then ModalResult := mrOK; end; procedure TMiniPluginSelectionForm.CheckListBoxClick(Sender: TObject); var i: Integer; begin btnOK.Enabled := false; for i := 0 to Pred(CheckListBox.Items.Count) do begin if CheckListBox.Checked[i] then begin btnOK.Enabled := true; break; end; end; end; procedure TMiniPluginSelectionForm.CheckListBoxKeyUp(Sender: TObject; var Key: Word; Shift: TShiftState); begin CheckListBoxClick(nil); end; procedure TMiniPluginSelectionForm.FormShow(Sender: TObject); var i, index: Integer; begin CheckListBox.Items.Text := pluginsList.Text; for i := 0 to Pred(selectionList.Count) do begin index := pluginsList.IndexOf(selectionList[i]); if index > -1 then CheckListBox.Checked[index] := true; end; // reset OK button enabled state CheckListBoxClick(nil); end; procedure TMiniPluginSelectionForm.InvertSelectionItemClick(Sender: TObject); var i: Integer; begin for i := 0 to Pred(CheckListBox.GetCount) do CheckListBox.Checked[i] := not CheckListBox.Checked[i]; // reset OK button enabled state CheckListBoxClick(nil); end; procedure TMiniPluginSelectionForm.SelectAllItemClick(Sender: TObject); begin CheckListBox.CheckAll(cbChecked); // reset OK button enabled state CheckListBoxClick(nil); end; procedure TMiniPluginSelectionForm.SelectNoneItemClick(Sender: TObject); begin CheckListBox.CheckAll(cbUnChecked); // reset OK button enabled state CheckListBoxClick(nil); end; end. ================================================ FILE: frontend/msPriorityForm.dfm ================================================ object PriorityForm: TPriorityForm Left = 0 Top = 0 Caption = 'Change node priority' ClientHeight = 134 ClientWidth = 300 Color = clBtnFace Constraints.MaxHeight = 172 Constraints.MaxWidth = 316 Constraints.MinHeight = 172 Constraints.MinWidth = 316 Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'Tahoma' Font.Style = [] OldCreateOrder = False Position = poScreenCenter PixelsPerInch = 96 TextHeight = 13 object lblPriority: TLabel Left = 24 Top = 67 Width = 34 Height = 13 Caption = 'Priority' end object lblPrompt: TLabel Left = 8 Top = 8 Width = 284 Height = 39 Caption = 'Change a node'#39's priority to adjust how it conflict resolves with' + ' other nodes. Values from higher priority nodes will be favored' + ' over values from lower priority nodes.' WordWrap = True end object btnCancel: TButton Left = 217 Top = 101 Width = 75 Height = 25 Caption = 'Cancel' ModalResult = 2 TabOrder = 0 end object btnOK: TButton Left = 136 Top = 101 Width = 75 Height = 25 Caption = 'OK' TabOrder = 1 OnClick = btnOKClick end object edPriority: TEdit Left = 88 Top = 64 Width = 121 Height = 21 NumbersOnly = True TabOrder = 2 Text = '0' end end ================================================ FILE: frontend/msPriorityForm.pas ================================================ unit msPriorityForm; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TPriorityForm = class(TForm) lblPriority: TLabel; lblPrompt: TLabel; btnCancel: TButton; btnOK: TButton; edPriority: TEdit; procedure btnOKClick(Sender: TObject); private { Private declarations } public { Public declarations } priority: Byte; end; var PriorityForm: TPriorityForm; implementation {$R *.dfm} procedure TPriorityForm.btnOKClick(Sender: TObject); begin priority := StrToInt(edPriority.Text) mod 255; ModalResult := mrOK; end; end. ================================================ FILE: frontend/msProfileForm.dfm ================================================ object ProfileForm: TProfileForm Left = 0 Top = 0 Caption = 'Select Profile' ClientHeight = 467 ClientWidth = 475 Color = clBtnFace Constraints.MaxWidth = 491 Constraints.MinHeight = 250 Constraints.MinWidth = 491 Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'Tahoma' Font.Style = [] OldCreateOrder = False Position = poScreenCenter OnClose = FormClose OnCreate = FormCreate PixelsPerInch = 96 TextHeight = 13 object btnOk: TButton Left = 311 Top = 434 Width = 75 Height = 25 Align = alCustom Anchors = [akRight, akBottom] Caption = 'OK' Enabled = False ModalResult = 1 TabOrder = 0 end object btnCancel: TButton Left = 392 Top = 434 Width = 75 Height = 25 Align = alCustom Anchors = [akRight, akBottom] Caption = 'Cancel' ModalResult = 2 TabOrder = 1 end object ScrollBox: TScrollBox Left = 8 Top = 8 Width = 459 Height = 420 HorzScrollBar.Visible = False VertScrollBar.Tracking = True Align = alCustom Anchors = [akLeft, akTop, akRight, akBottom] Color = clBtnFace ParentColor = False PopupMenu = ProfilePopupMenu TabOrder = 2 object PaddingLabel: TLabel Left = 3 Top = 100 Width = 3 Height = 13 end object NewProfilePanel: TPanel Left = 0 Top = 0 Width = 431 Height = 100 Cursor = crHandPoint Margins.Left = 0 Margins.Top = 0 Margins.Right = 0 Margins.Bottom = 0 Align = alCustom Anchors = [akLeft, akTop, akRight] DoubleBuffered = False ParentBackground = False ParentDoubleBuffered = False TabOrder = 0 OnClick = NewProfilePanelClick OnMouseMove = NewProfilePanelMouseMove object NewProfileImage: TImage Left = 2 Top = 2 Width = 96 Height = 96 Cursor = crHandPoint Picture.Data = { 0954506E67496D61676589504E470D0A1A0A0000000D49484452000000600000 00600806000000E298773800000006624B474400FF00FF00FFA0BDA793000000 097048597300000B1300000B1301009A9C180000000774494D4507DF09170328 04B714DDE70000164A4944415478DAED5C7B6C96D7797FCEF90C18DB9870BF24 A13469CB754BD769092529104203E4D2402E840C02445DBB4CCAA6459A347DD9 A6558B97495BD6A228DDD6269DB6496DD2AEE9B4A9524AD5E68FFDB1A81A0182 0DBE703536181BDB800DBE7E7ECFCEF539CF39EFFB994C4DB0FF781F64FCBD97 EFFBCEFBFC9EE7F75CCE39663049E485D3025EBF83D153CCFE7C1C226E703C61 F2713DE0AF25AF09017FC4182CBCEF6FE6F3CA857B66D44C9B0D5A49428F4F5E 9207DC9C92430E07CDC22761F4C0DC3F564A92C1FEEE5FB5BFF787BFE01595A5 A43454824902C2A40040C9FC2FBE3C6FD1D2D5BFDCBEF5EED533675633218C86 C6E4FFEA77628F85BC90A863FDDA9CD7AFF58FC0E3C4DEABCE4BFD43D3E13363 270EBFFFB5333FFFE31FC953C3FAA3270108930680459BBEF7E2F3FBB6BEBA78 CE3476A6FD0A6BBF340A4962D4AA9469356C3466152BF037A02A137D4EB94C22 CF337D41140AA272C95C76FCBF3FE83BFA6F0F2D0503C020E4007859B6EDAD57 9E7F6E6BB1ABB3077E76B05FABC6508F271D1C6C403337780A7B6DE69D73456F 53233BF2E603B7C9C3EBF2477E89F6820995C902005BB6FD0775BFBFEFA1978E 347440FDD961A828301D0198FE4FFD561141900810713FB56504CEBE965E31E3 D373E17273131C7E73E31DF26C9FFCB92A7F4A13FEE0133D002B7CD9F6EFD77D 6DDFC3C50F25000DAD2350C1ADAA99A119C6EC502D20E675C69330130BD4BB15 35317B5BED1D73A0B7A9590270FF9DE001189DE8079F4400BC55F77B7BB7148F 345C84C6732350E06674698B171E0401E113301B2490BBCC45E5011A806609C0 1B390059C2974B0A7A6EEFD6E25109409302A0608787164F82423C7A771DFC75 C13C42D2172405E5008C277CF9E36FD5EDDBB3A578B4FE2234B72B0F307598E2 7DF4036AF1E3289DB9DFF6664549B53206F4280A7A63430E40864800DEAEDBF3 ECE66243830260540340E91E95EF141F518D671C611FCCBD5F476198B1740EF4 B44800BE9B0390251A80672500C7EA3BA0F97C09B80AC261411B8E38B67A9B2A 51C59B9020F4B102E0B2A4A043390099A201D8B5FBC1E271E9012D174AC60304 7810480C104ED9CC58B7FA8D292BB917C385BCA7460270A52507A09C48007E58 F78C04A0517AC0890EEB0138426C0B5944048E3EA61ACC7CC0274A9A823E9D7B C078A201D8B94B0170014E5E1C935990551F92BBB368A10F1930AC0F1CD580F5 9AE001993951F32909404B0B1CFACEFA1C800CE1CB9FFC51DD8E6736159BA407 9CEA940038F37754A2284740443731D5B8B7D8CCC93A85FA99B174760EC038A2 017872E7A66273C30538DD99486366965E5C80B59482ED09A3644A35CEDAB322 768D02A03907A09C68009E9000B44800CE740A1D039C8AB5255B40683A4A5B0D CEEA950801BE16602668D77CCA7AC03FADCB01C810BE4202B05D027042C680D3 5D42C700E6321F20D98E7D8340BA891FC72B9DF96E1C54E7008C2B1A80C79E7E 4002D001ADDDCA03406BD7E4F3427B80C96880F0BC7B04DBAEA6B46453566627 741405F5369F90007C29072043F88AA7FEBDEED1A736164F3548007A7442635B 093ED066D10D553EB57A16A4A4D6037200CA8A06E01109C0690B80CE8230E3B1 2D662C0C5C916694EC688891B6840BDAAE66A85E927BC078A201784802704652 505B2F90201C7496B1D6723CEF8AB1A0131D28DF80A582706F8B04E01FEFCB01 C81009C08FEBB63EB5A178B6FE22B45DB60516C49443E88664459AE7D10D2C08 C275518D0B552F99253DE0640E4019D1006C7E7243B1557A40FB158E561E0C16 B31BAF78A4297D83D03582B037E38C9A3C512501B89C03505634005F7EC20070 E12A971464D34E1107D928C04674636FB65E611F5100F1807B730032842F9700 6C9200B42900FA98AE8483F4329A13765531B769267A06104A22996AF5ED1280 1609C03FE40064095FB1E39DBA8D8F6F28B6CB4A587B80CE6E44D47063E071C1 D69C8F172E122318AE852D60BAA6A0531280B5390019C2574A00363CBEBED87E B4033AFA0B50E03EAF77BC8E198E9B980740AE17F1399A35410EC08D84AF7CFA 9DBA75DBD6172FC82CE8E235A9404EB21CCBFFD87A402B077D805C1FCC029319 357954A529E8341CFAF6177300324402F093BAFB24001DD2033A070C05218358 AB776B7D82202B3CF7BBBC55C706E6294A49D56DB7E4008C237C8504E0DEC7D6 172FCA207C69A0A0832BA6985AB1BEFB861E2100F37C7D2FC66A5F21BB385C7D DB2CE85114940390297CC5CE9FD4ADFD8A04E0E845E81EB4561D29DF9D334D39 F39A5BBA7131028B366C619BC05CA500501EF0FA9AC907C0CBF201FF22DDD7BD A9E0A82C68CD63F717BBA407740FCA428CBB600B80B35B8E7232AC9EC6098C0F C23FC4F4DB6F911E9002E0662ECECDDC24C25E3821E0F5CF325874EF2B0B60FA 825D336AA6CF658E495DB94FFBF2014610B8BA9F444FDF872939F31D4BD73453 8BFA7961EAFADF79F4DEB597640CE81E3285186011C6C0CD407A1D6729DF57BF CC7397FE8C4A15032400FDEDC75EAFA8BC65944FA91C912827F1768F68097674 6D7C9B0C7510CAD868928CF677BF7FF23F77BFC7A7549592D101BD4944DF2A95 3F7FFEED2B7EB1FDE1BB57CFACAD66B8E1C16E86A01B24127DCE3C7C623744E8 F3EE7E7AEC364C08BFA1427DA33966E4338D82A74E9F26DA7F7596F50E39BA71 E0BAF5A07E9E17E32EA990DD34A5EB8A7AC30198B6A816A6CC9A26872858608B 9152195564A450B21E23D4B13DC9C9C77116BD573E6CCF890B639DC70F3EDFFC CEDEB7C06E12D197176FFAE73F79FEB9AD7FBB68F61438DD76959DBF34824A07 AB38F7C26D88C0CD11B842CADF4FDFE340710311899F36349FC582E71818E3A0 361031176C496F9911570BAC9EB6A3093D9956865F3F84AB59620B4530FD051B 6ED0DB9C8233DE86EF65E4BD143445A750511085C5B5ECFCC1E6C143DF5E73AB 056050DFB662FBDBAF7C7DDFE66257572F1CF8DF7E92EA65D04A160B9120E806 9B7E9FEF68621F9FDA1BF3CD3586964E331F4829DF5093B0ED686772FE339CAB 382562F30E4745565530169CF34CC4BC356175475E6392409492C554F296A98B 6A456FD3197670FF6FE32611AD9165DBD4E6882D2F1D39DE899B234CB0A39B22 4835EABE5F10F707D226A6132310B693692BD94D35E21423A5998076FC9274D7 03C2E529602A650CD2C436CC1CB22FD8BC07D91A01C71DD215CB50BAEF3261F4 42E0D21E9161ACF2EEA90B6AA1A7E92C1CDCFF05B749E48ABA852FDBF6FDBAAF EFDD5A3C7CAC138E9F1B9601910117644908B8948EF0AFA607A754AA7C922A06 E36381E5864596B7AAF2B44366C41CDF471911A51C4F2744B1C22CDEF20313FE 3E62F53E98D20789362304C0645E0A1D407EF7D485B5D07D5C03E032310FC057 F76E291E3DD605C7CED9DD29EE0BD52FEE791B1729A8C10B6E4132F7B8E58182 FB192A35B98E3C6FD773224829E58F473BEE7BCDD8822C07A7C842E5A3228842 0409A52230D1B09D4DCFE13CB3C35EFDE3E5339E20E3241F35457A4077632B1C FCD66F85002C9714F4DC9ECDC50F2505359D1B9514E4D61BB3D48798EDBA21F5 18C5724F29A8D334EF9BECD67A0B71294317E568C77235373CCE04B9DFC50CA2 3805E2984A0A129B95099FC539A521B1069133B25EA47352143A6F26CEA83BB7 DCCC63ABD7BCE0EEF040080DC08CF200EC9500D44B0F686A531E60AD5E789E0D CA7C4203B83836E07DE2DA00BEAAC595CD2A33F093B886D769864369C7F22EF7 0FAEFE4F081B27B29C1A931A2E29C527C466ACB53A4043BA090374261D31EA01 01226190766B58A3DB1C186A7E5B81A300E8C90240ED50DCBB7B73B141C600B5 39C2206876A6BB20E603BFB0C0586B247387DEC2A2A09BC1FB1CC24C8606E060 ED0FF97CA768FDE3AC3A71F7F8C08B0AA7ED5317F8698A48A826503EDD9513BC 3FD430A619E31668DE1314055D3BD90A87F66700B067F78312802E68393F6A56 2627CAE589329C6251F924880AB27CC4D371D4CFF1994A2AE3092C9F2C35616A 97BB80911101A363103A358EC95190072B48674910C6EF20995190A6DAEC08BD 8E7A030523008FD0129E8ABB0E462A140027CE49003E9F0660D7AE2F171B1500 6E734480B8B7EA30ADE3E935F90C03853DCDC14D11BAEC0951C2CAD5BBB6DED1 224F0F9712181E71EB81986344C085BAD16BAC2B481CA5C193D251502BD8317B 85B2105CF76431A5A2E7048454DE23E4431524056900BE1501A036C83DF3BB0A 804E90D5B2D9204753611B78017C7B98A1399BEF1789E5753013E9DCCE687120 AB16B0BF13D603DAD24BD2D2E54F4992782971F743C62A694A2F0034E3F17428 D0FBF05A5435D3C4C0A7B7590A8E159FED25D45053FD252B857933A0FF446B1A 80650A80673669004E76247687A2370848A5A476E0998137B4302C5D0815D1E0 3A3C9AC0D0B06D5740A810CEDC83FA58C3A872C977D0EB22837E18B16ACAF329 6B8F0232557A66A61400169C8D1C437AC07C09408BF4806FDE9506E0E99D9B8A 4DC7BBE05487DD9D1277A4842DC618557476C19595EFAB19AAC4A6B64AA123A3 0206861293F7738E318633EEDB0BB1A2624B8E826DB074253AEF3E80B91E354D 5FDDF803A5471E10784FAC74E1F5E413D750E4737209405F16008A82F4E60819 034E775A0AF2898C573E005287AA9413869749C125F47C2EB85603F7D9894A11 8747A4C54BAB57AF39F30F867CCDDD0390DA21A55088BC216DF999E759567A9C 6DF154F1E9EB54E931E164A4AA606299A2A0ABCD0A80DF4C03A037473800087F 62F0650C4B79B743C55592E982CB17652E7E5C1F94417554E8FCDDA5838E86B8 CBF1319D24E9628642813304F5FFA57CEF4629BA89F93D1D0FFC58528A2FEB19 A1F0B935D02701F8200B80C7D5E688864E38DD95780082B4D3538FAB0BC26A97 6423181B4CFA78EDFA989E4760DC2B383B805A6504D73DE7FBAC26A4A0F16827 7C6F081A10C5FB401CBD97C6117CC8806D6E48478E829806A00D3EF8FBDF8801 78BB6EDB8E8DC513D203CE5EB20090CCC737C27DA0A281D7D2B85FC723FF8DCA 54666038915C9F780B4B2995281DC1737D169BF94414E529ABBCE56351C6FD78 C7B57AC2EFE355CB594A471EA0C0108FA1C0B0393570B5E95C36005F91009C94 00B45EB2595090F9388578EBC5F5F92E5010EBBD36380683C3495AD1C4B26320 7C800DCF395A0BB220EEDB17A1F29DA2984E8999A3CE98D6A86E18F128AAB71B C58432DE104844475C02704501F0EAEA34008FEC509B233AF5F6205707D0CCC7 59A7C3C47FBE1D8404A924E9A6EF5A49B70A629AA074A007C31D85510578EBD6 5739472BE419208E1B9CB92F1A694A9A05BC53B44B77D1E2036B0F535A37D672 0ACFCA8294075C2E07C0C34FDD5F3CA33CA047902CC80C4A3D3CB61C38E08E15 BD89C2763715DD0C0C26F621387A10AD6059A0386F3A2E0883FE4C0E411D81D9 11C9D799A78614A7A3B752CBF77DF4C09B52E929FDCCB4F2BDC1A567CDE83C9B FF1551D0EC6AE86D2C03C0430A00E901E77AC1FCB124D2F3711404A4DD4C5B0E 57A4D5974ABE6DE02D91BC17C0A7988C8211A6783E3B22C038160B2C399D0561 E196493BA425117B41AA728E0335F592280047055750B845C225003D8D3208FF DDAA0000B66CFBDB2F6FD9B1F1CF5A8F7589B69EC4EA290C5C8673216819ABF6 41DFF512B60E3CE5D88171FA404E814409E41C1ED3BF1141BD80280A15693DC3 6741F1E746B443A9251A8B319674A0A5B182B24CDC778AA9284541D262D9EC2A D6D3700E0EBEBA2A9892648B37BCF6C8E7EF5BFB1F33972E295CBC3CEAFA9429 22237F1D40AF5CE897C156F780822C23724B4C2B43B70D021DFE2F6B85F357A5 527986122920A44F4FF37CB4DC34EDF0AAA9C06B2B032BA5CDB954B68403231E 00D171A41F967A41CD9FC170FF10F47CF8E17BF56F6CFAAA523EB84979F95379 C783FB77D62C5AB6BF30BDAA96616B80051F2FC837A84A56E09785C1C9BD265D F5189DF4E74B9D57ADFE8CE83BD4C15881D9C04B3C2A553358C5A9B1BA40CC9D F243E529100B0B6B61B0A3538851F71431674769641C5059965623FA81EC5B94 24B2201AEA6E3BD0FAF36FFC75DFB9FF392D4F5D06BB2C85F18ACA8AA4343455 BE563F55F677E6E77D52F299C7DE7C71C1234FBCD077E422F00A1E29DE2A3A08 CE165EFCC34ED423D2E963C502D5086B8343FBEF5A65BF7204CC7AB19B252E30 A8EF557FB37400DCC22CABEC8255FC54FBFAA602B0FCE91FBF34E7818D2FF61F ED0456E0A1A563EDE0159D5276EA1E119C379D48DD0A56000C81599773B3D786 8E590046EC6B11728C11FB07236F2E002B77FFF4E559EBD6FEA906A0A2607379 37B113F2BD57366D7BFB8C2AAEBAF5DCACF280660DC067C158E0442CCED553D8 E4F8E62A791CE1AB9E7DB7EE962FDD53ECAFEFD2EB92C27AC1D5130C8189F3FE 4CCA2273BB6A36AAAF39980C993CCBD32781F095BBDFAD9BB57E4DF19AF6009E 997E0282C1D0473909C8B488E36401960EC2F36B2D0077E50064085F293D60D6 3A09407D1C0300698556C540BC218BA662F0540CB8DA9403504EF8CA3D8A82D6 1407EA6D0C204156DF402C9A93022F53E9B4CAB614A466A3AE2A0FF8660E4096 F0551680EB3206B08AB80E081B7BCC36864C0E4D6A90282BE2C483F8BC1AE301 3900992201F8990EC2030D5D7A8D9F563A516E9C6A066D6C17780B1C6B2A6C71 D8CF28CC33AD60321D9803404403304B02705D01608330AD846907352BF03AC0 C2C20DB091A7A603F564480E40A6200003C7BA4C3B965048565B22557C953DCF F43248A626C41B5B7300CA08023028011059851827FDA028F341CE0FCEBBDE90 C01870A531980ECC0120A20198BD4E0220292889EB0016CE0D640767C804C379 8F9A10CF01282F7CD55E0980F6804B200A2C9DD1706C92A782331E737F9DAE86 D0E7E6CE9000B4E6009411F4802109405261127D8E8A05927A523A722D0788E2 433A2D5513E2977300CA8A06608E05602C4541C4BA8965D39683B987643EC40B 74E12C29E8F2F11C8072C2575B0F183E7E094AA4158120901413832D673EE046 DEC083CCC82C09E9CD01282B1280031280BB43005C47131B701E009A7A62B54B 9B740898BD36B75A0210AC48C8012082008C2800D42E4167E9A4F8CA6C374485 186DD261E1A6E2460EC0B8A20198E33CA0A210F572209803707F575ABF91877D A1206B024A41D5D093035056108091C66E187593F2658A2FCE19C4D52E8B73FF 206DB56B727200CA8A0660AEF2000B80EFED40300993CE8EDC8C18F186A82DA1 B1C80118571000E50123156E81AD2FC8E2EA17F70D972BBEC8D21AB53B476541 DDC75A7300CA8806609EF2802609806D2B079C1ED704484D8C1467F41EF219E0 00501EB02A0720433400F3D71B0A1A2EF0A0FFE394AE8F303D85749794C40C4A 473A835214744C2F0BCC01C8100DC00209C0500C008B2826A3E00AD695A66286 054065410D3900E584AF92002CDA2001901434C4A807D0869B9D922C57F10694 E5E287C801F808C257ED3D50B758794073370C02F7696546038E171C32E0AB62 20F5415009E7007C14E1AB2D0083390013221A805B25050D347D8C00D8E58A39 001F611C2B9F7DF7AF96DC7FCF9F0F9CBA22064605730AF76D689F0971521FA4 0A2E7ACD774B059F5BCD2E1D3DABEA00B7394201509AF0079FE80158E1773EFA 2F9B177CE19EFFAABC7561C5D0F592EE396003144860D5770359F1403AA378CE CF1D68CCE47F43D786A0F7F0A103F5DFDBFC0760D6E6AB05BA3773716EA64C16 00D438A67DEE897FDD5DB5E073AFF1E9D3A79BF49368157FF9269BDF432BA2F3 8055B012912430D4DDFEDED9037FF98DFEB6F771730494DBCC75931F7C3208E3 53AA2A92D1814F6A93885B1AAE381F3747400E406A2C9FD42691CCCD1113FDC0 EEA12793B8F1F0E8F8D715A7EC243A9E70F93FC75BE04FE910CD930000000049 454E44AE426082} OnClick = NewProfileImageClick end object NewProfileLabel: TLabel Left = 167 Top = 37 Width = 219 Height = 25 Cursor = crHandPoint Caption = '< Create New Profile >' Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -21 Font.Name = 'Tahoma' Font.Style = [] ParentFont = False OnClick = NewProfileLabelClick end end end object GameIcons: TImageList Height = 96 Width = 96 Left = 24 Top = 416 Bitmap = { 494C0101060008004C0060006000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600 000000000000360000002800000080010000C000000001002000000000000080 0400000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000F3FAF81AD5F6F851B9F3F783A4F0F7A993EFF6C983ED F6E479EBF6F774EEFAFB74EEFBFB74EEFBFB74EEFBFB96D8CBFBFF943BFBFD9A 45F4FCA052E3FCAC66C9FDB87EA9FDC89A84FDDBBE55FEF2E71E000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000F9F9F9066362 62A8131111FF131111FE262321F9858169FA0E0D0FFA171515FA1B1919F61D1B 1BF48D8C8C7B0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000F3FAF91BC6F4 F66D9DEFF6B777EBF5FA71EEFBFF72EEFCFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF6FF0FFFFBCBF96FFFF95 3BFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFC953EFDFCB0 6EBEFDCEA575FEEFE32400000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000DBDADA271614 14FC141112FF141112FF181612FF8F8058FF0B0A09FF141113FF141212FF1411 12FF2E2C2CE2F2F1F10E00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000F2FBFB19BAF3F68385EDF5E272EEFBFF72EE FCFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF6EF1FFFFE3A6 60FFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFC9E4DEBFDC3928EFEEDDF2900000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000006F6E6E9C1512 13FF151213FF141112FF312B1CFF776337FF332D1CFF121012FF151213FF1512 13FF151213FFA2A1A16500000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000FDDDC150FCAC68C7DFA967FF6DF1FFFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF7AE9 F1FFFB9740FFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFCA356DDFDD3AF690000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000EAEAEA16151213FF1512 13FF161214FF151213FF403522FF6C5629FF413419FF111012FF151213FF1512 13FF151213FF2E2C2CE300000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000FDD0 AA6FFC9B49F0FD963EFFFD963EFFFF9236FF7FE6E9FF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF98D6C8FFFF9338FFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFDC5958BFEFBF80800000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000656364A7151213FF1512 13FF161314FF151712FF5F4F2CFF74592FFF2E2001FF1A160CFF131313FF1313 13FF151213FF151213FFA5A4A561000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FDD2AD6BFC9944F7FD96 3EFFFD963EFFFD963EFFFD963EFFFE963DFFBAC199FF71EFFCFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF6FF0FFFFC2BC8EFFFE953CFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFDC5958BFEFDFD020000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000DDDDDD24262324EC151213FF1512 13FF131212FF332C18FF745E2CFF584115FF382903FF2B2613FF151514FF1414 14FF151213FF151213FF353233DCFDFDFD020000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000FDE2CB44FC9F4DE9FD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFF39C4BFF6DF1FFFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF6EF0FFFFE8A35BFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD9740FCFDD3AF6800000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000088868782161314FF161314FF1613 14FF131610FF6C5726FF644C1EFF422E05FF463409FF3A2A15FF1D1917FF1414 14FF161314FF161314FF1E1B1CF6B6B5B64F0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000FEFAF60BFCB273B7FD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFF9338FF94D9CEFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF7DE7ECFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFDA459D9FEF0E4230000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000F1F1F10F383637D9161314FF161314FF1412 16FF382B0EFF463106FF412E09FF473209FF634D19FF4B3815FF564E40FF1110 11FF161314FF161314FF161314FF636162AAFAFAFA0500000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FEDCC052FD963EFEFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFD0B37CFF6FF0FFFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFCFF9DD3C1FFFF9338FFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFDCB 9F7D000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000B3B2B253161314FF161314FF161314FF1713 0FFF47320EFF382C07FF181411FF15120CFF292313FF41321EFF807155FF7B7A 7CFF0E0B0CFF161314FF161314FF161314FFE1E1E12000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000FDB9 80A6FD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFF943AFF74EDF9FF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF6EF1FFFFC8B886FFFE953DFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFDA862CFFEF9F50C00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000002D2B2BE5161314FF161314FF131113FF3629 13FF3F2D0BFF171314FF131415FF141414FF141414FF0C0C0FFF938D8AFF615E 5FFF100D0EFF161314FF161314FF161314FF7876779300000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FEF7F013FDA255E0FD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFF953BFFA9CBB0FF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF6FF0FFFFECA156FFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD9842F9FEEAD832000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000ACABAC5A161314FF161314FF151213FF181412FF4230 13FF231F17FF18191AFF141414FF141414FF161314FF100E0EFF171515FF110D 0FFF171415FF161314FF161314FF161314FF161314FFECECEC14000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000FEEBDB2FFD9741FBFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFE5A65FFF6DF1 FFFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF80E5E7FFFE953CFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFDD9B95B0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000393737D8161314FF161314FF141214FF2A210DFF513C 12FF2B2A26FF161515FF161314FF161314FF161314FF131111FF141112FF1512 13FF141212FF161414FF161314FF161314FF161314FF6A6969A2000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000FDE1C847FD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFF9236FF83E3 E3FF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF75F4FFFF78FAFFFF72EF FCFF6EE6F2FF74F1FEFF78FAFFFF75F5FFFF72EFFCFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF71EEFCFFA3CFB9FFFF93 38FFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFDCBA07C00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000B3B2B2531C191AF8161314FF161314FF121111FF2C2312FF644C 14FF1F1A0EFF151616FF161415FF161314FF161314FF131011FF131211FF1512 13FF121010FF151213FF161414FF171415FF151213FF272426EEE5E4E41D0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000FEDCBF54FD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963DFFBFBE 93FF71EFFDFF72EEFBFF73F0FEFF6FE8F4FF41888FFF1E3E41FF060D0EFF0000 00FF000000FF000000FF081010FF1D3C3FFF3A787FFF5FC7D1FF77F9FFFF72EF FCFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF6EF1FFFFCEB4 7FFFFE963DFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFDC4938D000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F9F9F906636162AA151414FF151515FF171513FF151513FF181514FF5640 10FF543E0FFF23211DFF222120FF282524FF171614FF151311FF12110FFF1614 12FF151412FF12100FFF171614FF2B2B29FF232222FF28241FFE9D978F760000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000FEDCC052FD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFF79A 46FF6DF1FFFF75F4FFFF367278FF000000FF000000FF000000FF000000FF0000 00FF090A0CFF020303FF000000FF000000FF000000FF000000FF0C1A1BFF448D 95FF75F4FFFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF71EF FDFFF09F51FFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFDC4948C0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000E7E6E71A161314FE161415FF221C12FF221B0CFF131411FF141312FF251B 10FF5B410AFF6F5C3CFF6B6B6AFF484644FF1E1D1BFF13120FFF100F0DFF1413 11FF171615FF141311FF131110FF231D15FF2E2715FF322610FF45413FCFF2F2 F20E000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FDE3CC42FD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFF93 39FF99D2C2FF13282AFF000000FF000000FF000000FF161A1DFF7D94A6FFBDDF FBFFCAEDFFFFC3E5FFFFB5D5F0FF8DA7BCFF556572FF101315FF000000FF0000 00FF070E0FFF52AAB3FF75F5FFFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF84E3E2FFFF943AFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFDCB A17B000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006C6B6BA1171515FF161515FF261D11FF29210AFF101310FF141412FF0F0F 10FF2D220CFF72571FFF989288FF1D1B18FF1E1D1CFF0E0F0DFF0E0C0AFF1312 10FF241B0FFF181814FF2D2212FF2E2311FF181510FF131213FF171515FFC2C2 C242000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000FEEE E028FD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFF9B 40FF361E0AFF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF121718FF46545EFFA7C5DEFFB8D8F4FFB9D9F6FFC1E2FFFF8BA5B9FF242B 30FF000000FF000000FF2A575CFF75F3FFFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF71EFFCFFA9CCB1FFFF9439FFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFDDABB590000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000E7E7 E71A171515FF171515FF171515FF1C170FFF2A210CFF0E0F0DFF11110FFF100F 0DFF101112FF48370DFF6A531FFF282722FF0D0D0DFF0A0B08FF090705FF0E0D 0BFF16120BFF211E10FF32240BFF171514FF141214FF121010FF171515FF3E3D 3CD4000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000FEF9F50CFD99 44F7FD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFE973EFF985A 25FF000000FF000000FF000000FF272C2DFF6E7B82FF96AEC2FFB1D1ECFFC0E2 FEFFC1E3FFFFBCDDF9FFB6D6F2FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFC0E1 FEFF7E95A8FF030404FF000000FF183235FF74F1FEFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF6DF1FFFFD3B177FFFD963DFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFEEADA3000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000006766 66A6171515FF171515FF161414FF2A2111FF2A200BFF10110FFF10100DFF1513 11FF131013FF342711FF6F540DFF1C190BFF0B0B09FF10100EFF0F0E0CFF0E0C 0AFF0B0B0CFF241C11FF42320AFF1A1B15FF161513FF110F0DFF151412FF1816 15FFBBBBBB4A0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000FDA65CD6FD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFF9C40FFB46B2CFF0D07 02FF030201FF646E74FFC4D8E7FFDFF4FFFFD7ECFEFFD7ECFDFFCFE7FBFFBCDB F6FFB7D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFB8D8F4FFAFCEE8FF15191CFF000000FF1F4043FF76F6FFFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFFF39D4CFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD9944F7FEFAF60B000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000DFDEDE232523 23EF171515FF181616FF131412FF604913FF2E2408FF151212FF121210FF1615 13FF242225FF3C2B0DFF735512FF16140DFF121310FF161614FF151412FF1110 0EFF151412FF151413FF403112FF212426FF191614FF13120FFF161513FF1816 15FF434141CE0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FDC18F93FD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFF9A40FFC2742FFF211308FF000000FF717B 81FFD9EEFEFFD8EDFFFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD7EC FDFFCAE4FAFFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFB8D8F4FFB8D8F4FFB5D5F0FF0E1113FF000000FF428991FF73EFFCFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF88E0DDFFFF9439FFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFDAA64CC000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000008E8D8D7C1816 16FE181616FF161517FF342B11FF725514FF3B2B0EFF140F10FF11100FFF1D1B 1AFF221E15FF664A11FF5D4B1BFF151613FF161715FF161715FF151311FF0D0B 09FF161412FF131313FF554319FF262421FF332714FF151514FF161715FF1617 15FF1E1D1EF6C2C2C24200000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000FEE5D03DFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFC963EFF543214FF000000FF43484BFFD0E4F4FFD7EC FFFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD3EAFDFFBCDBF5FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFBBDC F8FFBDDEFAFFC1E3FFFFBADAF7FF98B3CAFF000000FF000000FF70EBF7FF72EE FBFF72EEFBFF72EEFBFF72EEFBFF70EFFDFFAFC8A9FFFF943AFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFDCCA2790000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000F1F1F10F3E3C3CD51816 16FF181616FF161615FF52380CFF7E6624FF32230AFF120E0EFF0D0A0BFF1313 12FF3D2E09FF81661DFF3E351BFF151816FF161816FF171816FF0D0B09FF0C0B 09FF141311FF141415FF493814FF232018FF3B2A11FF141414FF161715FF1617 16FF161616FF73737399FBFBFB04000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000FD9A47F3FD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFE973EFFDA8236FF110A04FF000000FF8D99A2FFDDF3FFFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFBFDDF6FFB8D8F4FFB8D8F4FFB8D8F4FF96B2 C8FF000000FF0C0E10FF485661FFA4C2DAFF313941FF000000FF3E8188FF72EF FCFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF6DF1FFFFD9AE70FFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFEF1E62000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000B9B8B84D181616FF1816 16FF181616FF2A2012FF5E410CFF826823FF150F06FF0C0A0BFF0E0C0DFF251E 0FFF71561CFF684F10FF181A15FF181B18FF181917FF171715FF0F0E0CFF0D0B 09FF12110EFF121415FF4D3E11FF1C1D18FF382C0CFF191616FF151715FF1617 16FF161616FF242424EFE6E6E61B000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000FDBE889CFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFF97 3EFFC1722FFF000000FF050504FFB6C7D4FFD7ECFFFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD7ECFDFFC0DEF7FFB8D8F4FFB8D8F4FFB8D8 F4FFB8D8F4FF485560FF000000FF000000FF111416FF000000FF152B2EFF76F7 FFFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF74EDF8FFF69B48FFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFCA65DD500000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000032302FE2181616FF1816 17FF181716FF38290EFF6D510AFF6C561DFF0C0B0EFF19171AFF151616FF2C1F 0AFF846B29FF634A0BFF2C2821FF2C2F2DFF1B1C1AFF161614FF0F0F0DFF0604 02FF100E0CFF111013FF654E15FF595242FF543F0DFF48330DFF1C1A16FF1717 16FF171616FF161616FF8C8C8C7D000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000FEEDDF29FD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFE973EFFBD70 2FFF000000FF060605FFC2D4E1FFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD7ECFDFFBDDCF6FFB8D8F4FFB8D8 F4FFB8D8F4FFBCDDFAFF8DA7BCFF050607FF000000FF000000FF000000FF76F6 FFFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF8CDDD7FFFF93 38FFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFDD6B462000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000AAAAA95C1D1A16FF181616FF1918 16FF171715FF3A2C10FF6F4F0DFF594312FF121418FF1A171AFF181618FF251B 10FF806B1AFFA78D2AFF765F1AFF1C1D18FF171514FF161311FF131210FF0E0D 0BFF0D0C0AFF100F12FF634910FF755B14FF76570EFF70550DFF362C11FF1717 16FF191816FF171716FF161616FF000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000FDA862CFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFD37D34FF0000 00FF000000FFBACBD8FFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD5EBFDFFB8D8F4FFB8D8 F4FFB8D8F4FFB8D8F4FFB8D8F4FFB0D0EAFF1A2023FF000000FF000000FF62CD D8FF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF70EFFEFFB4C4 A1FFFF943AFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD9842F9000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000363635DB282015FF171516FF1717 16FF2E2612FF543E10FF72540EFF594313FF121417FF1A1819FF191717FF1515 19FF563E11FFB2952DFFB29224FF453A12FF171716FF161513FF171614FF1313 11FF11110FFF0F0F10FF3C2808FF70540AFF84651CFF73530BFF4D3C11FF1817 12FF191816FF171816FF161716FF838383870000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000FDE0C749FD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFF5913CFF090502FF0000 00FF99A6B0FFD7ECFEFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFCDE6FBFFB7D7 F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFBBDCF8FF2B3339FF000000FF0103 03FF60C8D3FF72EFFCFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF6DF1 FFFFDEAA69FFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFDC799850000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000B7B7B74E201F23F8342810FF151616FF231D 12FF5B3F09FF957826FF7E6210FF664D14FF171715FF1A1917FF1A1717FF1614 15FF353227FF7E5F12FFAA8C21FF83701FFF14151AFF1C1C1BFF121311FF1819 17FF141513FF0D0F11FF44300AFF6B4D08FF8D6F24FF6C4D0BFF5F4710FF1818 12FF151613FF1A1A17FF151817FF2B2D2CE7F0F0F01000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000FCA256DEFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFF9B40FF3D240FFF000000FF565D 61FFDBF1FFFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD7ECFEFFD1E4 F5FF8A969FFF828E97FFB4C5D2FFD7EDFFFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD7ECFDFFBFDE F6FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFBDDEFBFF2E373DFF0000 00FF000000FF5DC2CDFF72EFFCFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF77EBF5FFF89944FFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFEFC FB05000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000F8F8F807626262AA2B2D30FF3B2B0DFF171715FF342A 09FF6C4F10FF9E811EFF977C17FF977F26FF231A10FF181817FF181819FF1312 13FF2E2B2CFF433614FFA2831BFFA18219FF757360FF414341FF393A37FF1011 0FFF171715FF121315FF5E440DFF70540DFF8E6F1DFF745610FF64470BFF2F23 13FF171411FF241D14FF161817FF191919FCA3A3A36500000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FDE0C748FD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFE963EFFA46128FF000000FF0E0E0EFFD9EE FFFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD9EEFFFF7E8991FF0000 00FF000000FF000000FF000000FFCEE2F0FFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD2E9 FCFFB7D7F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFBCDDFAFF232A 2FFF000000FF000000FF5FC7D2FF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF91DAD1FFFF9338FFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFDC8 9A84000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000E1E1E0212A2C2CF927221EFF352912FF111314FF4D33 0BFF745410FF9D7F1EFFAD921DFFA08736FF2A200BFF141213FF161518FF1514 17FF171316FF343531FF806A26FF9F8518FFC8B675FFBFC1BEFF585A58FF0F10 0EFF1A1C19FF1C1A1AFF6D4E10FF71520EFFA48A23FF7C5B12FF694C0CFF4232 09FF2B2826FF221B12FF171717FF181717FF504E4EC2F4F4F40C000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FDA963CDFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFF973EFF070402FF000000FF97A5AFFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD7EBFDFF9EACB7FF9FAD B9FF95A3AEFF838F98FF8B97A1FFDAF0FFFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD7EB FDFFC0DEF7FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB7D7 F3FF101416FF000001FF020303FF68DAE5FF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF6FF0FEFFBAC199FFFF953BFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD97 41FB000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000077757498302719FF322711FF141113FF211C10FF5137 05FF8F7226FF9C7D17FFB1931EFFB09936FF4B360FFF1E1A12FF141317FF1918 1BFF141114FF1F1C20FF413919FFAC9421FFA08523FFD8D1A5FF3B3D3AFF1414 13FF151415FF29271DFF876214FF7E5F10FFB9A231FF8C6E19FF74560EFF5D43 0BFF3F2C06FF1F1D16FF171717FF181717FF191717FFCCCCCC38000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000FEEE E127FD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFE973EFF824D20FF000000FF252728FFDFF5FFFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFDCF2FFFFD7EB FBFFA4B3BFFF87939CFF8A97A0FFABBBC7FFDAEFFFFFDCF1FFFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFCEE7FBFFB7D7F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFA5C2DCFF000000FF000000FF0C191BFF75F5FFFF76F7FFFF74F1FFFF72EE FBFF72EEFBFF72EEFBFF6EF1FFFFE2A863FFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFDD6B4620000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000E9EAEA17191717FF2D2211FF39332DFF161316FF2A1F0DFF5F42 0AFF9D7F20FFA0841AFFA78B1CFFA38D34FF211E19FF1E1A1BFF141416FF1B1A 1DFF151115FF181518FF111112FF8A7721FFAB9326FFB29637FF534622FF0E0E 10FF131111FF141415FF614711FF80600CFF967923FF9C831BFF7E5D14FF7B59 0FFF593F08FF1C1A14FF171717FF181717FF191717FF595858B7000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000FDBE 899BFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFF993FFF050301FF000000FF9BA9B4FFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFDFF5FFFF9CAAB4FF393D3FFF0000 00FF000000FF000000FF000000FF000000FF000000FF3B3F41FF91A0ABFFDDF3 FFFFD7ECFEFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFDCF1FFFFD6EB FDFFD8ECFEFFB9D9F5FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFB9D9F5FF798FA1FF000000FF000000FF0D1B1DFF13282BFF2B595EFF5FC7 D1FF75F3FFFF72EEFBFF72EEFBFF79EAF2FFFA9842FFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFDA65DD60000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000007272729A181717FF261E13FF2C261DFF171716FF3F3111FF9479 1BFF9F8319FF876814FF9B811DFF7B611EFF222020FF1D1A1DFF181719FF1717 17FF181617FF131012FF131315FF3D361FFFC2A62EFFBBA13EFF967921FF0809 0DFF141212FF1A1819FF2D291AFF5D4814FF71530FFFA2842BFF876815FF7D62 14FF785B12FF231D13FF181818FF181818FF191717FF191717FFD7D6D62C0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000FD96 3EFEFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFA16028FF000000FF121313FFE0F5FFFFD6EBFDFFDAEF FFFFD6EBFDFFD6EBFDFFDCF2FFFFA5B4BEFF1D1F1FFF000000FF1D1D1CFF5958 57FF7A7A79FF8C8B8BFF8E8D8DFF81807EFF5F5E5DFF1C1B1AFF000000FF0708 08FF717C84FFD7EDFDFFD7ECFEFFD6EBFDFFD6EBFDFFCCE1F1FF616C73FFD7ED FFFFD6EBFDFFC5E1F8FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFB8D8F4FFBEE0FDFF44515BFF2B3339FF1C2326FF000000FF000000FF0000 00FF2F6268FF75F5FFFF72EEFBFF72EEFBFF96D7CAFFFF9337FFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFEF1E52100000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000E4E4E41D232323F1171717FF201D13FF5D4610FF131414FF68561FFFAB8E 20FFA28721FF715009FF846513FF382B10FF110E10FF161315FF191819FF1818 18FF191718FF0F0C0DFF110F0FFF0F0D0EFFB99C36FFB49B2FFF7D6417FF0809 0DFF151314FF161414FF141213FF0F1217FF382E14FF927323FF907321FF8D6E 19FFB09628FF544014FF191818FF181717FF191717FF191717FF595757B80000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000FDDFC44CFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFF9B40FF36200DFF000000FF6F7980FFD7ECFEFFD7EDFFFF6F79 7FFFDAF0FFFFD5EAFAFF454B4EFF000000FF5E5D5CFFD5D4D3FFFFFFFFFFFFFF FFFFFEFEFEFFFDFDFDFFFDFDFDFFFEFEFEFFFFFFFFFFFFFFFFFFD8D8D7FF6B6C 6CFF010202FF000000FF76838BFFDCF2FFFFD6EBFDFFD4E9FAFF131616FFDFF5 FFFFD6EBFDFFCEE7FBFFB7D7F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFB8D8F4FFB8D8F4FFBCDDFAFFBDDEFBFFC0E1FEFFB3D3EEFF53626EFF0000 00FF000000FF254C50FF76F6FFFF72EEFBFF6FF0FFFFC0BD91FFFF953CFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFDC7998600000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008D8D8D7D181818FF181818FF141616FF56400FFF6A5215FF8E731EFF9C7F 18FFA28824FF76540DFF5F4812FF08050AFF131013FF120F12FF151415FF1818 18FF1A1818FF131111FF110D0DFF060A0CFF88701DFFB19329FF514015FF1313 15FF161414FF141112FF181516FF1A1918FF191615FF33290DFF947423FFB293 30FFA98E1BFF8E7424FF1F1A14FF181818FF1A1818FF1A1818FF262424F0D6D6 D62D000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000FDB87DAAFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFF3903CFF000000FF000000FFC1D3E2FFD6EBFDFFD1E5F4FF0000 00FF666F74FF1A1A1AFF848381FFF7F7F6FFFFFFFFFFFDFDFDFFFDFDFDFFFDFD FDFFFEFEFEFFFEFEFEFFFDFDFDFFFDFDFDFFFDFDFDFFFDFDFDFFFDFDFDFFFFFF FFFFFFFFFFFFA1A3A3FF252626FF070A0BFF9FAFBBFFABBCC9FF000000FFCBDF EFFFD6EBFDFFD6EBFDFFB7D7F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFBBDCF8FF839B AFFF000000FF000000FF459098FF72EFFCFF72EEFBFF6EF1FFFFE7A55DFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFDA052E400000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000F0F0 F010434343CE181818FF181818FF121718FF4E3811FF856612FFA88F27FFB39A 27FF947716FF624912FF131214FF100D0FFF090608FF120F12FF171617FF1717 17FF1B1919FF161314FF121011FF272221FFB9A237FFA58B26FF413622FF1817 19FF1A1818FF191717FF161314FF161314FF151214FF191815FF655419FFB99C 2FFFB79C29FFAE8F2CFF3F3115FF171718FF1A1818FF1A1818FF191717FF7E7C 7C8F000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000FC9741FBFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFA56228FF000000FF191A1AFFE0F6FFFFD9EFFFFF575E63FF0000 00FF959493FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFEEEDFFC1C0BFFF9D9C 9AFF838281FF807E7DFF939191FFB5B3B3FFE3E2E1FFFFFFFFFFFFFFFFFFFEFE FEFFFDFDFDFFFDFDFDFFFFFFFFFFCCCDCEFF2E2E2EFF000000FF000000FF8796 A0FFD6EBFDFFD7ECFDFFBCDBF6FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFBBDC F8FF546370FF000000FF020505FF74F2FFFF72EEFBFF72EEFBFF7CE8EEFFFD96 3FFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFEF3EA1B000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000B8B8 B84D171717FF181818FF181818FF181817FF594110FFAD9021FFA4891DFFB69B 2EFF967D1AFF261E17FF18171AFF171317FF110E11FF100D10FF1A191AFF191A 19FF1A1818FF211F1FFF1F1E21FF8D8665FFAF992CFF997E22FF1A1911FF1313 14FF292626FF292727FF181616FF151213FF161414FF191717FF2F2A17FFAC91 22FFBCA133FFC2A633FF63561CFF151616FF1A1918FF1A1818FF1A1818FF3230 31E3EDEDED130000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FEEAD931FD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFF983FFF5F3817FF000000FF596166FFD8EDFFFFC8DBE9FF000000FF0000 00FFFEFDFCFFD0CFCEFF838281FF3A3836FF151414FF303437FF5C656AFF7C88 90FF8D9BA4FF838F96FF656E74FF393E41FF040505FF000000FF393736FF8281 81FFCECECFFFFFFFFFFFFFFFFFFFFEFEFEFFDCDDDEFF000000FF000000FF4A52 58FFDAEFFFFFD6EBFDFFC3E0F8FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFB4D4EFFF000000FF000000FF4DA1AAFF72EEFBFF72EEFBFF72EEFCFF9BD4 C3FFFF9338FFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFDD2AC6C000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000002F2F 2FE4171717FF181818FF171617FF302616FF896E16FFB79C28FFA78B18FFB398 2CFF826B1EFF18171FFF1C181BFF1A171AFF141114FF120E11FF191919FF1818 18FF2C2B2BFF4A4848FF979A9FFF9C863BFFBDA434FF7E681DFF12100EFF1111 11FF1A1819FF1B1819FF161414FF151313FF1A1718FF1C1919FF0E1013FF8E78 22FFB89F29FFBDA431FFBCA539FF13100FFF1A1917FF1A1818FF1A1818FF1917 18FFA6A5A6620000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FDCBA17BFE963DFFFF92 36FFFF9337FFFF9337FFFF9337FFFF9337FFFF9337FFFF9337FFFF9337FFFF93 37FFFF9337FFFF9337FFFF9337FFFF9337FFFF9337FFFF9337FFFF9337FFFF93 37FFFF9839FF241509FF000000FF8F9CA6FFD6EBFDFFC9DCEAFF000000FF0101 01FF000000FF40474BFF8A979FFFC7D9E7FFE1F7FFFFDBF1FFFFD7ECFFFFD6EB FDFFD6EBFDFFD6EBFDFFD7ECFEFFDBF0FFFFE1F7FFFFCCDFEEFF95A3ACFF5960 66FF101314FF000000FF535454FF737474FF0E0F0FFF010101FF000000FF9BAC B7FFD6EBFDFFD6EBFDFFC8E3F9FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFC0E1FEFF1D2226FF000000FF31676CFF73F0FDFF72EEFBFF72EEFBFF6FF0 FFFFC6B989FFFE953CFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFCB375B5000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000B4B4B4521818 18FF181818FF181818FF151515FF4C390EFFBA9F32FFB09422FFB29925FFBA9F 2EFF6A581AFF2F2E33FF1B181AFF1A171AFF1A1619FF151115FF181719FF1616 16FF373534FF4B4A48FFD6D6CDFFBDA947FFBBA031FF7A6723FF141514FF1414 14FF131111FF191717FF2A2828FF171415FF1A1818FF1B1819FF0C0C10FF937E 23FFBAA02BFFB89C2BFFC1A32FFF50481DFF1A1718FF191819FF1A181AFF1A17 1AFF262326F00000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FDB06EBEF89A46FF8BDF DAFF88E1DFFF88E1DFFF88E1DFFF88E1DFFF88E1DFFF88E1DFFF88E1DFFF88E1 DFFF88E1DFFF88E1DFFF88E1DFFF88E1DFFF88E1DFFF88E1DFFF88E1DFFF88E1 DFFF8DE8E6FF000000FF000000FFBCCFDEFFD6EBFDFFD7ECFEFF9FAFBBFF0000 00FF9BABB5FFDAEFFFFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD8ED FFFFE0F6FFFFC9DEEDFF6A757CFF000000FF000000FF040505FFAEC0CCFFD8ED FFFFD6EBFDFFD6EBFDFFCDE6FAFFB7D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFBEE0FDFF262D32FF000000FF2A585CFF74F1FFFF72EEFBFF72EEFBFF72EE FBFF6FF0FFFFEBA258FFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFC9843F6000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000003E3E3ED41818 18FF181818FF181818FF131314FF594B15FFB59C28FFC0A53EFFAF9627FFBAA0 2BFF574912FF211F23FF1A171AFF1A171AFF1B171AFF171216FF0E0D0EFF1212 12FF31302EFF7C7A78FFDED19BFFB69B30FFC7B044FF675D2DFF161616FF1717 17FF100E0EFF363435FF201E1EFF121010FF141212FF131212FF171410FFA793 25FFBB9E2CFFB99F2EFFBCA02CFFB19829FF554B1DFF1A171AFF1A171AFF1A17 1AFF19171AFF9F9FA06900000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FC9844F7FD963EFFE4A6 60FF6FF0FFFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF6ADCE8FF000000FF000000FFDBF1FFFFD6EBFDFFD6EBFDFFD8EDFFFF909F A8FF97A7B3FFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD7EDFDFF000000FF181B1CFFC8DCEBFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD1E8FCFFB7D7F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFC0E1FEFF030405FF000000FF39787EFF72EFFCFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF7FE6E9FFFE953DFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFEF5EE150000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000B8B8B84D1E1E1EF71818 18FF181818FF181818FF171718FF584A18FFC2A746FFD5BD6BFFBFA448FFC2A6 37FF64530FFF141218FF1A171AFF1A171AFF1A171AFF1F1B1DFF090709FF1314 13FF141414FF6E6A69FF867127FFC5AF52FFB8AA50FF544E39FF171616FF1916 17FF1C1A1AFF444343FF5B5959FF353233FF1B1919FF1A1819FF2B2715FFB4A2 49FFB4982CFFBFA133FFB49826FFC0A32FFF9E841FFF241F19FF1A171AFF1918 1AFF18181AFF363538DDFEFEFE01000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000FEF7F111FD963EFFFD963EFFFE95 3DFFD0B37CFF6EF1FFFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF5DC2CDFF000000FF0D0F10FFE2F7FFFFD6EBFDFFD6EBFDFFD6EBFDFFD7EC FFFFDAEFFFFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD7EC FEFFE0F6FFFFDCF2FFFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFF8B9AA4FF33383BFFD7EDFEFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD4EAFDFFB7D7F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F5FF778D9FFF000000FF000000FF63CED9FF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF71EEFCFFA1D1BCFFFF9338FFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFDDFC54B0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000FAFAFA05696969A4171717FF1818 18FF181818FF181818FF161617FF635724FFC7BB64FFD4C277FFC7BA6AFFC5B7 66FFB7A866FF181518FF19161AFF1A171AFF1C191DFF282528FF1E1D1DFF1313 13FF181818FF323331FF958953FFE1D69AFFD3C181FF38352AFF191717FF1917 17FF252323FF6A6767FFC0BEB7FFA29F9FFF4F4D4CFF181717FF3E3B25FFB8A4 51FFE1D59AFFC3B057FFBEAD54FFC8B350FFC1A632FF483E1AFF151719FF1918 1AFF18181AFF1D1C1FF9AEAEAF58000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000FDE4CE40FD963EFFFD963EFFFD96 3EFFFF943AFFB8C29DFF6FF0FFFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF55B1BAFF000000FF232729FFDEF4FFFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFA1B2 BEFF161919FF2F3537FFD6ECFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFC0D3E3FFDCF1FFFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFB6D7F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFB8D8F4FFB8D8F4FFB8D8F4FFBBDCF9FFBADBF7FFB8D8F4FFB8D8F4FF9DB8 D0FF000000FF000000FF47959DFF74F3FFFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF6EF0FFFFCCB682FFFE953DFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFDCCA27A0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000E0E0E0221C1C1CF9181818FF1818 18FF161616FF090B0DFF1E1E1BFFB2AA79FFE9DDAFFFE5DCACFFE4DFB8FFF1EE D3FFE7DFC2FF4B4947FF191617FF171516FF3D3B3BFF777677FF2E2E2CFF1013 10FF282A26FF1C1F20FFCCCAB8FFFAF8F1FFD4CA9FFF33312AFF282526FF1816 16FF282526FF343334FFFFFFE2FFFDFBEAFFAAAB9EFF0B090BFF313028FF9B94 70FFF1EDD6FFEAE5C5FFEBE1C3FFDFD699FFDCC87EFF908945FF101115FF1719 19FF161918FF171718FF606060AEF8F8F8070000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000FDD2AE6AFD963EFFFD963EFFFD96 3EFFFD963EFFFF9338FF9FD2BEFF71EFFCFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF51AAB3FF000000FF2F3537FFDDF2FFFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFDAEFFFFF090A 0BFF000000FF292E30FFDCF2FFFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD8ECFEFFB7D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFB8D8F4FFB8D8F4FFB9D9F5FF677B8AFF778C9EFFB8D8F4FFBADAF6FF88A1 B5FF99B5CCFF000000FF29555AFF75F4FFFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF70EFFDFFEFA052FFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFDBC85A00000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000078787894171717FF181818FF1717 18FF312D26FF9F9875FFCAC39AFFEAE0BDFFE1DDB3FFDDD19BFFE5E0B5FFF8F3 E0FFE9E8D1FF77736AFF141214FF323130FF1D1A1EFF8A8162FF0C0D0BFF1418 15FF18161CFF92855AFFE0D2A0FFE8E4B3FFDDD4A8FF4F4E4AFF262323FF1513 13FF151313FF0E090AFF757263FF999480FFEEECCDFF3B3935FF1C191CFFB3B4 A4FFEEEDD1FFEBE9C8FFDBCC91FFE3DCB8FF7C8375FF606D5AFF0E1311FF1619 18FF161918FF171818FF171717FFE2E2E21F0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000FDC4958CFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFF943AFF8BDFD9FF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF52ABB4FF000000FF33393BFFDCF2FFFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD8EDFFFF67737AFF0000 00FF000000FFC0D4E2FFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD7ECFDFFB8D8F5FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFB8D8F4FFB8D8F4FFB4D4EEFF040506FF859DB1FFBBDBF8FFB5D5F1FFB9D9 F5FF677A89FF000000FF000000FF5DC2CDFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF83E4E4FFFF943BFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFCAF6CC00000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000F0F0F010171717FF171717FF181818FF1718 18FF292D20FF5F6541FFD0BE72FFD4C06FFFC8B353FFD7C876FFCFC170FFD5C9 76FFE9DEB3FFABA074FF555048FF3D3C35FF3A382EFF887331FF0D110FFF0F14 15FF655721FFA88E3CFFD3C576FFDAC96CFFCCBF65FF9B9358FF17140FFF1515 13FF141310FF2B2929FF141315FF0C0D0EFFB0AA8AFFAAA47CFF1A1816FFD1C6 9CFFD7CA88FFD2C071FFC7BB58FFBBAF6DFF707E72FF757E70FF0D1110FF171A 19FF161918FF171818FF181717FF6B6A6AA30000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000FDB980A6FD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFA9842FF7CE8EDFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF57B4BEFF000000FF313639FFDCF2FFFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFC7DBEBFF000000FF0000 00FF667278FFD8EDFFFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD8ECFDFFB8D9F5FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFB8D8F4FFBFE0FDFF181D20FF44515BFFBFE1FEFF637584FF7F96A8FFB4D4 EEFF0C0F11FF4E5D68FF000000FF1B383BFF76F6FFFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF71EFFCFFA6CDB4FFFF9439FFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFDA559D90000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000006F6F6F9E171717FF181818FF181818FF181A 18FF344337FF324736FF686B3FFFAC9E4FFFCFBD5FFFCEBD59FFD2C062FFD0BD 64FFD5C063FFD4C060FFB4A054FF947F37FF8B731FFF9E8937FF131714FF181D 20FF665D29FFAC9035FFC8B258FFD4BD60FFC7B856FFC6B557FF3F391FFF1518 17FF1F1D1AFF151415FF171619FF1D1D24FF130F0CFF937C2AFF6D643FFFC7B2 4AFFCBB455FFD5BF60FFB2A155FF6A7048FF576657FF282C29FF161918FF1619 18FF161A18FF171817FF181717FF191717FFE7E7E71A00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000FCB171BAFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFEF9F51FF73EEFAFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF60C9D4FF000000FF262B2CFFDEF3FFFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFF909EA9FF000000FF0000 00FF8D9BA4FFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD8ECFDFFB9D8F5FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFB8D8F4FFB8D8F4FFADCBE5FFBDDEFAFF9DBAD1FF090B0DFFC2E5FFFF424F 58FF6D8090FF161A1EFF000000FF000000FF62CBD6FF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF6EF1FFFFD1B279FFFE96 3DFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD9D4CEC0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000E2E2E21F2A2A2AEA171717FF181718FF181818FF292D 29FF849184FF809081FF40523FFF404A37FF5E6C4FFF74703EFF98822CFFBFA9 45FFC7B34DFFCEB955FFC8B34EFFBAA640FFC0AB45FFCBB854FF9F8E4FFF3836 25FFB8A548FFC3AB48FFCAB74FFFCAB751FFBEAB46FFCCB756FFBEAA4BFF3D36 22FF24252BFF2D2C1DFFAD9E4EFF857A3EFFA39642FFC6AE49FFBEA847FFC9B2 52FFB9A545FF79763FFF36432CFF4C5B4AFF2F3831FF151917FF161A17FF161A 17FF161A17FF181A17FF181816FF191717FF676666A800000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000FCAB65CAFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFDFAA68FF6EF0FFFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF6DE4F0FF000000FF121415FFE1F7FFFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFDAF0FFFF32383BFF0000 00FF141718FFDBF1FFFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD7ECFEFFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFB8D8F4FFB8D8F4FFBBDBF8FF95B0C6FF000000FF8EA7BDFF96B0C7FF0000 00FF90AABFFF21292CFF000000FF000000FF2B595EFF74F2FFFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFCFFF29D 4EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD9742F80000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000008F8F8F7A171717FF171717FF171717FF161716FF4B50 4DFFA3B0A4FF5D6D5FFF6C7C6EFFA8B8AAFFA5B5A7FF90A195FF676129FF957C 23FFC3AF49FFC5B24BFFCCB755FFC9B550FFBEAB42FFC3B048FFD0BA5EFFCFBE 5DFFBDA844FFCCB653FFBBA441FFC7AF4AFFC0AA46FFC6B24CFFCEBB64FFC1AF 49FF81733AFFC7B44BFFC3AC45FFBFA940FFC9B34EFFCCB451FFC6B04BFFBBA6 41FF918439FF303D2FFF414F41FF606E60FF565F56FF1A1E1BFF1A201BFF1A20 1BFF171A17FF181917FF181916FF191717FF272525EFE0E0E022000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000FDA75FD3FD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFF953CFFC9B786FF6EF1 FFFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF77F8FFFF010202FF000000FFDEF4FFFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD9EFFFFF2328 2AFF000000FF69747BFFD8EEFFFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFDBF0FFFFDCF1FFFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFB7D7F3FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFB8D8F4FFBADAF6FF6C8091FF000000FF74899AFFBEE0FCFF0C0E10FF7A90 A2FF252D31FF738899FF000201FF000000FF000000FF73F0FDFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF86E1 DFFFFF9439FFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD9741FB0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000F3F3F30D3E3E3ED3171717FF171717FF161716FF1C1F1DFF171F 1BFF19231AFF0D1A0FFF4E5A4FFF303C32FF889489FF92A093FF374422FF655D 21FFC6AF4AFFC0AF4AFFBEAC48FFCDBC56FFC3B34BFFC3B14EFFC4B34EFFD6C5 6FFFC2B04FFFC9B552FFBCA744FFC5B14AFFC6B24DFFC5B14CFFD2BD64FFCAB3 4FFFCEB94EFFB9A440FFBBA440FFCCB853FFC9B354FFBFA842FFBCA13CFFBAA3 42FF645D28FF334237FF94A192FF9DAA9DFF637063FF5E6B5EFF7F8A7DFF878D 87FF222321FF1B1A18FF1A1816FF191717FF191717FE9090907A000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000FCA65AD8FD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFF9439FFB1C7 A6FF70F0FEFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF76F6FFFF162E31FF000000FFC3D7E6FFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD8EDFFFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD3E8 FAFF131617FF000000FFC1D5E3FFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFDDF2FFFF464D51FF393F42FFD9EEFFFFD6EB FDFFD6EBFDFFD6EBFDFFD4EAFCFFB7D7F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFB8D8F4FFB9DAF6FF7C93A5FF9BB6CDFFC1E2FFFF3C4750FF262D33FF98B4 CAFF353F47FF657786FF2B6E71FF000000FF000000FF499AA2FF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF71EF FDFFACCAACFFFF943AFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD9741FB0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000BBBBBB4A161616FF171717FF171717FF151515FF373D37FF545F 56FF323D33FF233124FF38453BFF657368FF27362AFF38493BFF6A806FFF6176 66FF5A6231FFBEAA48FFC7BA5AFFBEAD48FFD0BF62FFC7B855FFBFAF48FFCABB 5BFFCABB5CFFBEAB48FFBDAC4AFFC0AE52FFC6B553FFB4A141FFB7A043FFB097 3DFFCAB557FFC4AE4CFFCEB652FFC3B147FFCCB94DFFA9953EFF5C5A36FF404D 38FF42513FFF596858FF82917FFF515E51FF394639FF4E5B4FFF96A193FF98A0 96FF2D302CFF1A1816FF1A1917FF191717FF191717FF413F3FD2F1F1F10F0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000FDA55BD7FD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFF93 38FF99D6C6FF71EEFCFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF73F0FDFF32676DFF000000FF96A6B1FFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFCFE3F4FF5B656BFFBED1E0FFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFC6DAE9FF020303FF303639FFDEF4FFFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFADBECAFF000000FF000000FF748088FFD7EC FEFFD6EBFDFFD6EBFDFFD1E8FCFFB7D7F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFB8D8F4FFB8D8F4FFB8D8F4FFBFE0FDFF4F5E6AFF060607FFB7D8F4FF0F12 15FFA9C7E0FF2A2F35FF42ABAFFF1E4D4FFF000000FF1E3D41FF75F5FFFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF6DF1FFFFD6AF73FFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD9741FB0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000373737DA161616FF171717FF161616FF151515FF242922FF828F 84FF849085FF677669FF819187FF34443BFF3B4E43FF3F5546FF263B2CFF7D92 82FF485B4CFF656326FF9C8E40FFC4B765FFC2B454FFC8BA5FFFCDBE64FFBBAE 4AFFC6B758FFBEAE4AFFB7A845FFCABC5DFF8D7E31FF414B33FF2C3E32FF2935 2EFF83763CFFC1B34BFFD1C36CFFC3AD48FF988332FF3B3922FF556A5CFF6F80 70FF475645FF677565FF4E5C4CFF515F51FF334033FF243025FF8B9A88FF98A4 98FF353B34FF202420FF181715FF191717FF191717FF181616FFBEBEBE470000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000FDA860D1FD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFF953CFF86E1E0FF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF52AAB3FF000000FF616B72FFD8EDFFFFD6EBFDFFD6EBFDFFD6EB FDFFD9EEFFFF555E63FF000000FF101314FFDEF3FFFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFF9EAFBAFF000000FF9FAFBBFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFF87959EFF000000FF000000FF2D3134FFDDF3 FFFFD6EBFDFFD6EBFDFFCDE5FAFFB7D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFB8D8F4FFB8D8F4FFB4D3EFFF2D363CFF050607FFACCAE4FF52616DFF4856 60FFB1D0EAFF000302FF54DBE0FF3D9DA1FF000000FF000000FF72EEFAFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF74EDF9FFF59B4AFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD9841FA0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000B5B5B550161616FF161616FF171717FF151515FF1A1D1BFF39443AFF5663 58FF758278FF829288FF6F7F76FF90A59BFF98AFA5FFA5BBB1FF7F9289FF2237 2BFF556A5EFF758880FF6A7D79FF616C4CFFB1A85BFFC6BD5BFFCEC06BFFC7BC 5DFFBCB14DFFC4B955FFB0A43FFFC7BC5DFFB7AC58FF849272FF5C7A6BFF7F8A 5EFFD4C672FFC1B567FF8A7F3FFF5B5424FF455141FF3B493CFF4C5C4CFF8595 84FF444F44FF313B2CFF394738FF637164FF636F62FF576457FF617161FFBDC8 BFFF545D55FF7A827AFF1B1D1CFF181717FF181717FF181616FF383636DB0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000FCAC68C6FD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFF79A46FF79E9F1FF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EFFBFF000000FF212627FFDFF5FFFFD6EBFDFFD6EBFDFFD6EB FDFFDFF4FFFF202526FF000000FF000000FFA7B8C5FFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFDCF2FFFF474F53FF222729FFDFF5FFFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFF95A3AEFF000000FF000000FF171919FFE0F6 FFFFD6EBFDFFD6EBFDFFC9E2F9FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFB8D8F4FFB8D8F4FF697C8CFF2A3238FFB1D1ECFF7B92A4FF040506FFBDDE FAFF45515BFF2C7174FF51D3D8FF54D9DEFF000000FF000000FF50A8B1FF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF8BDED9FFFF9438FFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD9A44F50000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00003E3E3ED3161616FF171717FF171717FF141515FF191F1BFF6D7B71FF6B7C 71FF707F75FF364D3FFF395143FF5E776BFF9FB8ACFF3C5647FF546A64FF677C 7AFF5E726EFFC7D9D4FFD0DED9FF9FB2A8FF8C8942FFC6BE62FFCCC471FFC0B6 5BFFC2BA58FFBDB751FFB2A943FFCDC676FFC2B358FFC6B85CFF949A74FFC7BB 5BFFC9BE5BFF706D39FF38493FFF4E6257FF3D5144FF485A4CFF6E7E70FF5361 55FF656D4FFF626841FF49502FFF98A597FFBBC6BCFF8D9A8DFF879788FFAAB6 ABFF919E93FF5F6D63FF151816FF171717FF171717FF181717FF181616FFB6B5 B550000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000FCB375B5FD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFEBA258FF71EFFCFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF75F4FFFF1F4245FF000000FFC9DEEDFFD6EBFDFFD6EBFDFFD6EB FDFFDEF4FFFF222729FF000000FF000000FF83919AFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFCEE3F3FF000000FFA8BAC6FFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFCEE3F3FF000000FF000000FF2F3437FFDDF2 FFFFD6EBFDFFD6EBFDFFC4E0F8FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFB8D8F4FFB8D8F4FFBCDCF9FFBEDFFCFF90AAC0FF000000FF9BB7CEFF91AC C2FF000706FF53D6DBFF51D2D7FF53D7DCFF173C3DFF000000FF31686EFF73F0 FDFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF70EFFDFFB2C6A4FFFF943AFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD9F4FE80000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000B7B7 B74E1D1D1DF7161616FF161616FF171917FF1D211FFF87928DFFC3D1CBFF9DAF A6FF364C3EFF5C8E77FF538E7AFF3B8063FF31664EFF335540FF5E7870FFB1CA C5FFA6BEBCFF59746EFF708A82FFC5D4D1FF838850FFBFBA5BFFCBC672FFBEB9 58FFC0BC58FFC1BC5AFFB1AD47FFCEC87AFFC2B856FFC7BD5FFFC7BD58FFBCB3 51FFCABA5FFF757442FF586F64FF93A797FF798E77FF93A895FFC5D4C9FF97A2 8FFF43483CFF142220FF212C26FF484C2FFF1C2418FF213129FF54655BFF2E3E 33FF2A3C31FF1C2A26FF191C1BFF171717FF171717FF181617FF181616FF3E3D 3DD4000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000FDBC85A0FD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFE963DFFD9AD70FF6EF1FFFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF4FA4ADFF000000FF79858DFFD6EBFEFFD6EBFDFFD6EB FDFFD9EEFFFF505A5EFF000000FF000000FF8D9DA7FFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD7ECFFFF6E7A81FF3F464AFFDBF0FFFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD9EEFFFF6E7980FF000000FF97A6B1FFD6EB FDFFD6EBFDFFD7ECFDFFC0DDF6FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFB8D8F4FFB8D8F4FFB9DAF6FF90AAC0FF000000FF7E95A8FFACCBE4FF0200 00FF42ACB0FF51D2D7FF51D2D7FF51D2D7FF2D7577FF000000FF193336FF76F6 FFFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF6DF1FFFFDCAB6BFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFCA75ED30000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000F9F9F9066969 69A4161616FF161616FF161616FF181E18FF334036FF728278FF455A4EFF334B 3FFF284130FF617A77FF4490A8FF2AB1DEFF2FA0C2FF497164FF679C96FF5EB7 C1FF8FB0AAFFA5BDB7FF94B1A8FF638177FF497359FF848D42FFC8C267FFC8C0 6EFFC1BE5DFFC4C15FFFBAB651FFCCC76FFFCBC168FFC2BC5FFFBAB451FFC1B8 5DFFC6BF65FF4A532CFF6F8C7AFF506440FF5A6841FF73825CFF819170FF7781 5DFF444C47FF1B2D3DFF3B4C4CFF32412EFF3A4B44FF263530FF16251EFF2432 29FF2C3C32FF38443CFF2A352EFF151916FF181718FF181616FF181616FF1F1D 1DF7BFBFBF460000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000FDC89B83FD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFF953BFFC2BC8FFF6EF0FFFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF76F5FFFF040909FF1B1F21FFE0F6FFFFD6EBFDFFD6EB FDFFD6EBFDFFBACDDBFF000000FF000000FFCFE3F4FFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD9EEFFFF85949DFFD9EFFFFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFDAEFFFFFDAF0FFFFD8EDFFFFD6EB FDFFD6EBFDFFD7ECFDFFBBDAF5FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFB8D8F4FFB9D9F5FF829AADFF000000FF6F8393FFABC9E3FF070506FF368B 8EFF52D4D9FF51D2D7FF51D2D7FF51D2D7FF41A6ABFF000000FF04090AFF77F9 FFFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF76ECF6FFF79A46FFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFCB273B70000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000E9E9E9171A1A 1AFA161616FF161616FF121212FF343E31FF374837FF304333FF364D3BFF3553 41FF415A49FF6C7F70FF6D9B96FF51C7EAFF4CA4B7FF78967FFF5C7E74FF3C56 58FF333C39FF839C91FF8EABA0FF87A69AFF5E7662FF28351CFF9FA249FFD4CE 7DFFC3C062FFC6C262FFBEBC58FFC4C063FFC8C06CFFB8B252FFC6BE63FFC9C3 6DFF7A8B48FF536F5AFF688359FF637948FF9AA688FF3D4233FF3F4635FF2528 21FF495037FF545A4CFF838D72FF26392DFF394F41FF214C2BFF2B5534FF2D4A 32FF2E4432FF273E29FF2E4C33FF243928FF171515FF181717FF181616FF1816 16FF6E6D6D9FFAFAFA0500000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000FDD7B65FFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFF9338FFA9CBB1FF70EFFDFF72EE FBFF72EEFBFF72EEFBFF73EFFDFF39787EFF000000FFA9BAC7FFD6EBFDFFD6EB FDFFD6EBFDFFD7ECFEFFB9CCDAFFB9CCDBFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFB7D7F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFB8D8F4FFB9D9F5FF91ABC1FF97B1C8FF90A9BFFF000000FF348589FF52D6 DBFF51D2D7FF51D2D7FF51D2D7FF51D2D7FF4FCED3FF000000FF000000FF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF8FDCD4FFFF9338FFFD96 3EFFFD963EFFFD963EFFFD963EFFFDC08D960000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000007B7B7B8F1616 16FF161616FF161616FF1B1B1AFF6A725EFF505D42FF425239FF25341AFF3C4C 33FF4C6348FF567152FF3E5C3CFF3F623EFF668962FF222A20FF313A2DFF1514 14FF21231EFF57774DFF71966FFF516559FF39443DFF4E5B4BFF718E4FFFBEBC 65FFCACB74FFB8B85AFFB9B958FFC4C167FFC4C267FFC1BD5EFFD6CD7DFF6C6D 3CFF5B6F50FF49583BFF363A2DFF768070FF0C0D0DFF141413FF1C1F18FF0F10 0FFF4A5239FF22251BFF60674AFF24352EFF2B5C34FF284A31FF29482FFF2947 2FFF223A28FF243929FF203625FF263D2CFF181717FF181616FF181616FF1816 16FF242222F1E4E4E41D00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000FDE8D635FD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFF9438FF93DACFFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF5DC2CCFF000000FF393F43FFDDF2FFFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFCAE0F1FF8EA7BCFFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFB8D8F4FFB8D8F4FFBCDDF9FF576774FF000000FF3C9A9EFF52D5DAFF51D2 D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF56DDE2FF020404FF000000FF68D8 E4FF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF70EFFEFFB8C29CFFFF95 3BFFFD963EFFFD963EFFFD963EFFFDD0AA6F0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000646464A81515 15FF161616FF161616FF181817FF31352AFF2F3724FF2F3A21FF212D15FF2330 16FF2B3C24FF425837FF4D623AFF41582FFF52663CFF171A19FF2C3E26FF1717 17FF1E1F1BFF3C4D32FF3B4D2FFF182216FF1A1E17FF395035FF4A623FFFACB4 66FFC0C072FFB0B056FFC2C26AFFD0CE7AFFB7B75AFFCECC70FF939053FF1E23 1CFF4D594BFF2A2D29FF1E2120FF4F564FFF1E1F1DFF1B1B1BFF141513FF1717 16FF3A402EFF151713FF1A1D12FF313E2EFF32452EFF2F4830FF23412CFF2443 2AFF1B291EFF151415FF1D2920FF213629FF171615FF181616FF181616FF1715 15FF181616FFCFCFCF3400000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000FEFDFB04FD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFF82E4 E6FF72EEFBFF72EEFBFF76F6FFFF183436FF000000FF000000FFB4C7D4FFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFDDF3 FFFF96A5AFFF000000FF6E8192FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFB8D8F4FFB8D8F4FF74899BFF000000FF0E2324FF4BC1C5FF51D2D7FF51D2 D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF55DCE1FF091818FF000000FF60C9 D3FF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF6EF1FFFFE0A8 66FFFD963EFFFD963EFFFD963EFFFEE5D03C0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000C5C5C53F1515 15FF161616FF161616FF151515FF1B1B1CFF282D2CFF3C4C30FF354426FF2643 2CFF244935FF295038FF234530FF2B482DFF384F31FF1C1C19FF293425FF1717 16FF1A1A1AFF202220FF1A1B1AFF1A1A1AFF1C1D1BFF252720FF4D6B3FFF9397 51FF658156FF51795FFFA1A862FFC0BD6DFFCDC979FFA8AB61FF24241BFF252A 23FF1C1F1BFF1B1B1BFF191A1AFF34382DFF1C1E1AFF181818FF151415FF1919 19FF1B1C1AFF121212FF11170FFF162012FF232D18FF28301AFF295032FF3051 38FF2B4934FF171514FF243426FF1C1E1AFF181616FF181616FF181616FF1715 15FF403F3FD1F0F0F01000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FD9E4DEAFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFF49C 4AFF76EBF5FF72EEFBFF5CC0CAFF000000FF4FA5ADFF010101FF32373BFFDEF4 FFFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFDAF0FFFFC8DCEBFF4249 4DFF000000FF040505FFB8D8F5FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFB8D8F4FFB8D8F4FFBCDDFAFF8DA6BBFF0F1315FF000000FF3FA4A8FF51D3 D8FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF54DAE0FF0E2323FF000000FF5DC3 CDFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF78EB F3FFFA9843FFFD963EFFFD963EFFFEFBF9070000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000F2F2F20E4343 43CC161616FF161616FF161616FF151515FF1F2323FF131D10FF1B2515FF1B2E 20FF2A4632FF3B5C3EFF366143FF2F5240FF131E1BFF191A17FF282D25FF1C1B 1CFF191919FF191819FF191919FF191919FF181817FF222A1CFF465A36FF999A 50FFA0B877FFADC497FFC3C776FFC4C573FFB9BA6EFF373825FF171717FF1C1E 1DFF181817FF191919FF191919FF1B1C19FF1C1D1AFF181818FF181818FF1919 19FF181818FF121313FF223125FF253524FF262E1AFF1A1E0EFF0C1004FF1115 09FF0F1207FF191716FF1B1E1AFF191817FF181616FF181616FF181616FF1715 15FE999898700000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FCB87CACFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFE6A55DFF71F3FFFF2A565BFF070E0EFF78FAFFFF42898FFF000000FF9DAD B8FFD6EBFDFFC2D6E5FFB2C4D2FFA9BBC8FFA2B4BFFFA6B7C3FFDAF0FFFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFDAEFFFFF484F53FF000000FF0000 00FF000000FF849BAEFFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB9D9F5FF191E21FF000000FF42AA AEFF51D2D7FF51D2D7FF51D2D7FF51D2D7FF54DBE0FF0C1E1FFF000000FF5ACA D9FF6CF2FFFF6CF2FFFF6CF2FFFF6CF2FFFF6CF2FFFF6CF2FFFF6CF2FFFF6CF2 FFFF6CF2FFFF6CF2FFFF6CF2FFFF6CF2FFFF6CF2FFFF6CF2FFFF6CF2FFFF6CF2 FFFF8EDDD5FFFF943AFFFC9F50E6000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000009797 9771161616FD161616FF161616FF161616FF181A18FF293223FF262F22FF1622 12FF182314FF1A2614FF2A3820FF243527FF1C2225FF15181AFF191919FF1919 1AFF191919FF181818FF181818FF181818FF191918FF242B23FF272A17FFA3B3 56FFBEC474FFC7D078FFC4CA7BFFC6CD7DFF40422AFF111015FF181818FF1817 18FF181818FF181818FF181818FF181817FF1B1B1AFF191919FF181818FF1818 18FF181718FF171B1AFF35483BFF404A37FF2A301EFF101408FF0F1106FF2122 14FF363822FF181614FF181616FF181616FF181616FF181616FF181616FF2826 26ECE5E5E51C0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FDD4B067FD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFE953DFFD8BC83FF041013FF2C5B5EFF73F1FFFF76F6FFFF0E1D1EFF0F11 12FFDBF0FFFFABBCC9FF212527FF000000FF000000FF000000FF9FAFBCFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFDBF1FFFF41474CFF000000FF0000 00FF687279FFBCDDFAFFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FF9FB9D0FF000000FF0409 08FF53D5DAFF51D2D7FF51D2D7FF51D2D7FF55DDE3FF060B0BFF000000FFDB8D 44FFF39C4CFFF39C4CFFF39C4CFFF39C4CFFF39C4CFFF39C4CFFF39C4CFFF39C 4CFFF39C4CFFF39C4CFFF39C4CFFF39C4CFFF39C4CFFF39C4CFFF39C4CFFF39C 4CFFF29D4EFFFB9740FFFDBB83A2000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000EBEB EB15262626EC161616FF161616FF161616FF171915FF2A3526FF273324FF1A26 16FF212D1EFF192514FF21311CFF243F38FF161D21FF1A1D20FF191918FF1919 19FF1A1A1AFF191B1BFF191B1BFF191B1BFF191B1BFF18191AFF64733DFF8DA5 3CFF91A64AFF90A33BFFD5D98FFF4C5034FF131516FF181A19FF161918FF1619 18FF161918FF161918FF161918FF161918FF161918FF161918FF181818FF1818 18FF171717FF1B221EFF203025FF293221FF1F2416FF101409FF101309FF2424 15FF32331FFF171515FF161616FF181616FF181616FF181616FF171515FF706E 6E9D000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FEF3E91CFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFF983EFF000000FF377379FF73EFFCFF72EEFBFF5FC6CFFF0000 00FF5C656CFFDDF3FFFFDFF4FFFF9EAFBAFF1D2122FF000000FFA6B7C4FFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD8EDFFFF272B2DFF5A63 68FFD6EFFFFFB7D7F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFC2E4FFFF080809FF0000 00FF399092FF51D2D7FF51D2D7FF51D2D7FF52D1D6FF000000FF000000FFFF99 3FFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFDDABC57000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000076767695161616FF161616FF161616FF161516FF1E231CFF405040FF2939 29FF172414FF131F11FF415F43FF3E5F45FF1C2A2BFF141A1DFF191918FF1919 19FF1A1A1AFF191C1CFF1A1C1CFF1A1C1CFF1B1D1DFF141619FF8B9C63FFB4C6 7AFFB2C276FFC4D088FF7D874EFF1E1F1CFF191B1AFF181A1AFF181A1AFF181A 1AFF161918FF161918FF161918FF161918FF161918FF161918FF181818FF1717 17FF161616FF27342DFF3F5D4DFF435240FF293121FF12160BFF18190BFF2827 16FF1F2315FF161714FF161616FF181616FF181616FF171515FF171515FFF3F3 F30D000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000FD9F4EE9FD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFF9A40FF000000FF2D5C60FF73F1FEFF72EEFBFF70E9F5FF142A 2CFF000000FF495155FF8897A0FFDBF0FFFFDFF5FFFFA4B6C2FFD9EEFFFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFDEF4FFFFDAF0 FFFFC6E1F8FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8 F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFC0E1FEFF000000FF0000 00FF398E91FF51D2D7FF51D2D7FF51D2D7FF3E9C9EFF000000FF29180AFFFF9C 40FFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFEFBF808000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F4F4F40B151515FF161616FF161616FF161616FF1A1C19FF314032FF3348 34FF223122FF1F2C18FF315030FF426940FF406048FF26362FFF161817FF191B 1BFF191C1CFF181C1CFF1A1D1CFF1B1E1DFF1B1E1EFF17191EFF879569FFC6D7 8FFFCCD79AFFC8D49AFF5D6349FF191C1AFF1A1C1CFF1A1C1CFF1A1C1CFF191B 1BFF171A19FF161918FF161918FF151918FF1C1F1EFF171918FF181717FF1817 16FF212120FF2F4136FF74937FFF66795CFF414D37FF2A341BFF444C2CFF383C 20FF475245FF111111FF171616FF181616FF181616FF171515FF777676950000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000FDC29091FD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFF9D41FF190F06FF080E0EFF78FAFFFF5EC5CEFF000000FF2F60 65FF3F848AFF2C5D61FF000100FF090A0AFF9BACB7FFD9EFFFFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD7EC FDFFBDDBF5FFB8D8F4FFB8D8F4FFB8D8F4FFB9D9F5FFB8D8F4FFB8D8F4FFB8D8 F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FFB8D8F4FF7F93A4FF000000FF0000 00FF4CC1C5FF51D2D7FF51D2D7FF52D5DBFF1F4B4CFF000000FF8B5223FFFE97 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFDAB63CC00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000088888881151515FF161616FF161616FF151515FF1F2821FF273A 28FF253624FF20351DFF508250FF3C643DFF466E51FF243D25FF171A18FF1A1C 1CFF181D1CFF191F1CFF1A1D1CFF1B1E1DFF1A1E1FFF1B1D21FF485334FFCBDE 8FFFCCD89FFFCAD6A3FF5B624CFF1A1D1BFF1C1E1DFF1A1E1DFF1A1C1CFF1A1C 1CFF191B1BFF181A1AFF161918FF161918FF242827FF1A1B1BFF1E1E1EFF1B1A 19FF1F1F1FFF566C47FF799769FF6F8566FF293A1BFF506335FF59653DFF454D 2FFF3E463DFF151315FF161616FF181616FF181616FF191717FDE0E0E0210000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000FEEAD931FD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFF973FFF6F421BFF000000FF0E1A19FF000000FF64D1DBFF73F1 FEFF72EEFBFF73F1FEFF74F3FFFF356E73FF000000FF8F9FA9FFD8EDFFFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD4EA FDFFB7D7F3FFB8D8F4FFBBDCF9FF92AABFFF5A6875FF647381FF92A9BEFFBEDF FBFFC0E1FEFFBCDDFAFFBBDBF8FFBDDFFCFF9BB4CAFF030303FF000000FF142F 2FFF53D9DEFF51D2D7FF51D2D7FF51D0D4FF000000FF000000FFFA943DFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFDD2AD6B00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000E7E7E71A1D1D1DF7161616FF161616FF161616FF101512FF4557 4AFF152311FF416543FF6DA574FF5D965CFF2E5431FF1E3221FF1D231FFF191D 1FFF181E1FFF171E1DFF374839FF191C1BFF191F23FF1A1F23FF262828FFAAB9 87FFC3D799FFD0E0B0FF76845CFF21251FFF1C1C1CFF1A1F1EFF1A1E1DFF1B1E 1DFF181D1CFF181C1BFF181A1AFF151615FF25332EFF3E3F3DFF2E2E2CFF1C1B 19FF272826FFBCC7C1FFABBFACFF556C48FF77905BFF778E5CFF728258FF414C 2EFF1A1F19FF171617FF161616FF171515FF171515FF686767A5F9F9F9060000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000FC9D 4DEAFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFEC8C3AFF000000FF000000FF489399FF72EFFCFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF75F4FFFF3E8186FF000000FFA4B5C1FFD7EC FEFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EB FDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFC9E3 F9FFB8D8F4FFBADAF7FF728494FF000000FF122B2BFF286566FF0E2928FF0000 00FF1C1F21FF343B42FF434D56FF31393EFF000000FF000000FF010202FF4BBF C3FF51D2D7FF51D2D7FF51D3D8FF2C6C6EFF000000FF70431CFFFF983FFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFEFAF70A00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000FCFCFC036F6F6F9C161616FF161616FF161616FF131515FF232D 22FF355431FF669970FF6CAC6AFF64A267FF538B53FF213B28FF1E2926FF181D 1EFF1C1F1EFF2C4232FF4D7654FF151B1BFF192022FF191F23FF1F2224FF525F 3FFFBFD0A2FFCADE9FFFA7B48EFF9BA780FF535945FF19201AFF14191CFF191F 1FFF181C1EFF181C1CFF181A1AFF121312FF6B7B77FF72827BFF2C2E2CFF1815 15FF21251EFF8DA883FF516F3FFF354A27FF748E58FF96AB81FF4E6347FF343E 2EFF161916FF161616FF171616FF171515FF1D1B1BF8B6B5B550000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000FDCB 9F7DFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFF973EFF844E21FF070E0FFF77F8FFFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF75F6FFFF31666AFF000000FFB5C7 D4FFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD8ED FFFFD7ECFEFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD7ECFDFFBDDB F6FFBADAF7FF89A2B7FF000000FF0F2324FF54D8DDFF51D3D8FF53D9DEFF50CA CEFF30797BFF132C2CFF000000FF000000FF020101FF1D4546FF4CC3C7FF51D2 D7FF51D2D7FF51D2D7FF52D2D6FF020202FF000000FFF7933DFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFDB273B70000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000C5C5C53F202020F3151515FF161616FF161616FF181B 18FF426D43FF77B87DFF6EAD78FF417353FF467646FF294831FF172C20FF1E35 29FF24372DFF2D5039FF202B26FF182020FF1A2023FF1A2023FF1B2122FF1C22 21FF252C2AFF96A292FFDFEDCFFFCEE0C0FFC9D6CBFFA5B891FF404F35FF0F15 18FF1A1F1FFF191D1DFF171B1BFF18191AFF1A191AFF7C9A8CFF95B5A5FF6F8D 75FF618159FF55724DFF587343FF2F4025FF51663EFF566B41FF526E61FF252C 29FF151616FF171616FF171515FF171515FF343232DF00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000FEF9 F50CFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFF9A40FF462911FF366C70FF73F0FDFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF76F6FFFF285457FF0000 00FFBCCFDEFFD6EBFDFFD6EBFDFFD6EBFDFFD6EBFDFFD8EDFEFF84929BFF5A65 6BFF6E7A82FFACBECAFFDFF6FFFFD6EBFEFFD6EBFDFFD6EBFDFFD1E8FCFFBFE1 FEFF697E8DFF000000FF030505FF4EC8CDFF51D2D7FF51D2D7FF51D2D7FF51D2 D7FF51D2D7FF53D9DEFF55D9DEFF52D1D6FF55DCE1FF52D6DBFF51D2D7FF51D2 D7FF51D2D7FF52D6DBFF255A5CFF000000FF8D5423FFFE973EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFDE4CE400000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000003E3E3ED2151515FF161616FF161616FF1616 16FF42594BFF77B784FF71AC81FF2B5238FF3C5C4AFF396145FF203A28FF3F63 4EFF2A4033FF1B2522FF191F22FF1A2022FF1B2123FF1C2024FF1C2125FF1C21 25FF1D2226FF141A1EFF2C342FFF8C9885FFCED9D2FFD6E0D8FFE0EECFFF8493 79FF181D1DFF191D1EFF181C1DFF181C1CFF191B1DFF18191BFF6E8A7AFF5F87 65FF345432FF35533DFF9DB09CFF394C35FF43573BFF414F30FF546B5FFF1415 15FF161616FF171616FF171515FF171515FFACABAB5B00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FDB87DAAFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFF983FFF000000FF52A7AFFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF76F6FFFF2751 54FF010000FFB0C2CEFFDFF5FFFFDFF6FFFF91A0AAFF0A0B0BFF060F10FF2348 4BFF000000FF000000FF151718FF79878FFFADBFCCFFACBECAFF70828EFF161B 1EFF000000FF000000FF40A5A9FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2 D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2 D7FF51D2D7FF45AEB2FF000000FF261609FFFF9B40FFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFDA0 52E3000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000C6C6C63E151515FF161616FF161616FF1716 17FF28362BFF6FB180FF49774DFF2E4936FF2C4D34FF4B7C5BFF2C503BFF3357 45FF1C2725FF1A1F24FF1B2025FF1B2024FF1C2125FF1D2226FF1D2326FF1E23 26FF1E2227FF1E2327FF1B2025FF0F1419FF1D2424FF55615CFFA6B0A9FFE3F0 DBFF939A8FFF1D2121FF181D1CFF181B1BFF18191BFF18181AFF212725FF273D 29FF273C23FF365451FF2B4834FF557560FF577665FF3F5343FF28312CFF1513 13FF181616FF171515FF171515FF2F2D2DE40000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FEEFE324FD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFD47E34FF000000FF60C6CFFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF76F6 FFFF367176FF000000FF222527FF040405FF000000FF38747AFF75F4FFFF75F3 FFFF70E9F5FF336A6EFF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF307C7FFF52D5DAFF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2 D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2 D7FF4FCBCFFF050B0BFF000000FFE48738FFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFDD7 B75E000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000004A4A4AC5151515FF161616FF1717 17FF121213FF4C7A56FF284730FF2B4533FF518565FF70BA80FF3A725BFF3861 55FF1A1C1EFF1C2025FF1D2226FF1E2326FF1E2326FF1E2427FF1E2326FF1E23 27FF1E2427FF1E2427FF1D2226FF1C2125FF1B2024FF181D22FF1B2224FF8C95 81FFDDECC0FF3C413EFF171C1CFF181B1CFF1A191BFF1A191BFF151416FF2937 2AFF1A2B1EFF7FA294FF729A89FF6F9890FF375349FF4A635CFF101311FF1715 16FF171515FF171515FF171515FFB0B0B0560000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000FCB273B8FD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFC67531FF000000FF61C7D0FF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF74F2FFFF69DBE6FF41878DFF3E8287FF6BE0EBFF73F0FEFF72EEFBFF72EE FBFF72EEFBFF73F1FEFF6FE8F3FF2F6165FF000000FF000000FF000000FF0000 00FF2C7275FF53D8DDFF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2 D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF52D4D9FF49B9 BDFF081211FF000000FFBE712FFFFE963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFC9C4AED0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000C4C4C440151515FF171717FF1717 17FF161618FF2B362AFF21412AFF2B4E39FF79C397FF60AA86FF3A7457FF3968 59FF191A1CFF1F2225FF1E2427FF1E2427FF1F2528FF1E2427FF242A2CFF1D25 25FF1D2325FF1D2325FF1E2426FF1E2425FF1C2223FF1A2122FF1C2223FF2328 2AFFD5D9D5FF9AA095FF12161AFF191C1EFF191A1CFF18191BFF131517FF3C4D 3DFF606E66FFB4D5D8FF527F7EFF385A53FF45635CFF22322EFF161515FF1615 15FF171515FF171515FF373636DBF0F0F0100000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000FEF0E422FD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFDF8536FF000000FF52A7AFFF72EEFBFF72EEFBFF72EF FCFF73EFFBFF52A9B0FF4A959DFF5BBEC7FF76F7FFFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF74F2FFFF68D9E3FF2C5C60FF23484BFF3FA4 A8FF52D6DBFF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2 D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF3C9598FF0000 00FF010100FFBF712FFFFF973FFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFDD9BA5A0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000F4F4F40B484848C8171717FF1818 18FF181918FF171616FF2D4D39FF21402AFF6CAC88FF305D3FFF326446FF2C57 44FF1C2526FF1D2226FF1E2427FF1E2527FF1D2427FF2C3431FF98A591FF141B 1CFF1E2627FF1E2526FF1E2426FF1E2426FF1D2324FF1C2223FF1B2122FF2228 28FFA4AB9EFFABB2A2FF111417FF191C1EFF191A1CFF18191BFF28282BFF5967 5DFF8CB0AFFF5F908DFF2F4B44FF425D55FF4E7068FF181919FF161515FF1715 15FF171515FF161414FF86858584FEFEFE010000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000FDBA82A4FD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFF9C40FF080502FF316164FF73F1FEFF73F1FEFF50A2 A9FF010000FF000000FF000000FF000000FF0B1819FF5DC2CCFF73F0FDFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF74F1FEFF76F4FFFF56D7 DDFF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2 D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51CFD3FF000000FF7042 1CFFF6923CFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFCA357DC000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000009B9B9B6D191919FD1818 18FF181818FF1A1A1BFF1C291FFF2F5039FF294A33FF274535FF305C43FF3569 53FF293A34FF1B2225FF1D2528FF1D2528FF171E23FF707E6DFFC4DCB3FF2C38 30FF1C2626FF1D2627FF1E2526FF1E2426FF1D2426FF1D2325FF1C2223FF2429 2AFFA3B38AFF8C9B75FF13161AFF181B1DFF191A1CFF17181AFF424143FFA1B5 B9FF679A96FF4B7A71FF28453DFF45655BFF30463FFF161414FF171515FF1715 15FF171515FF232121F0D7D7D72B000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000FEFAF70AFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFF973FFF73441CFF000000FF6EE5EFFF65CFD8FF0000 00FF0B0703FF975A25FFD07C33FFBC6F2EFF4D2E13FF000000FF55B2BBFF73F0 FDFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF60DE E7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2 D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF53D7DCFF1F4E50FF5D3716FFFF9B 40FFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFEE9D734000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000EBEBEB152D2D2DE71818 18FF191818FF191B1BFF171E1CFF29523BFF223B2CFF274231FF264C38FF366B 52FF2A5348FF1A1F23FF1D2528FF1D2528FF171E24FF6D7E65FFCBE7AEFF7686 72FF1E2627FF1D2627FF1D2626FF1E2526FF1E2426FF1C2324FF1A1F24FF4A54 4BFFE2F3D3FF434943FF171B1DFF181B1DFF191A1CFF161719FF3E4F4FFFA8CD CEFF5E9C9AFF4F817BFF32524CFF364F46FF1B1E1CFF171515FF171515FF1715 15FF171515FF575656B700000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000FDD3AF68FD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFB953EFF0E0803FF1B3435FF469095FF0000 00FFC47430FFFD963EFFFD963EFFFD963EFFFF9B40FF895628FF000000FF52AB B3FF74F1FFFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF64E2 ECFF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2 D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF43A9ACFF000000FFFA943DFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFDB980A600000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000008181818B1717 17FF181818FF1A1B1BFF171C1BFF406A57FF3D7B50FF4E8071FF2C5A43FF2C63 48FF42705DFF172021FF1D2528FF1D2528FF1D2529FF21292DFFABC5A8FFCEE8 DFFF7B8D90FF263A3BFF121618FF181B1EFF15191BFF292E30FF6B7373FFDBE6 E1FF626C62FF19201FFF1A1E20FF191C1EFF191A1CFF161719FF3F6462FF6199 98FF5E9C99FF38625BFF53867FFF3F6057FF120E0EFF171515FF171515FF1614 14FF161314FFDFDFDF2200000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000FDA961CFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFE18537FF050200FF070B0BFF0000 00FFB86D2DFFFD963EFFFD963EFFFD963EFFFD963EFFFF9A3FFF6B4B29FF0000 00FF469299FF75F5FFFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF64E3 ECFF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2 D7FF51D2D7FF51D2D7FF51D2D7FF4FCCD0FF02090AFF8C5323FFFE973EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD9944F6FEFDFC0300000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000FDFDFD021717 17FF191818FF191A1AFF171B1AFF1B2722FF55A667FF58AE90FF3C8359FF5CA9 80FF489164FF283935FF1B2427FF1D2528FF1E272CFF1D262AFF587E83FF9DE9 EFFFD9F2F7FFC5DFE6FF8EBAC2FF6D9FA9FF82B5BCFF9BCDCDFF5F7C6EFF2C34 35FF1A2023FF1A1E20FF1B1C20FF1A1C1EFF191A1CFF1A1C1CFF355E45FF2D6B 54FF255043FF48807AFF426961FF171B1BFF161213FF161314FF161314FF1613 14FF605E5FAD0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000FEF6EF14FD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFED8C3AFF2B190BFF0000 00FF402610FFFF9B40FFFD963EFFFD963EFFFD963EFFFD963EFFFF9B41FF4638 23FF000000FF2E5F63FF75F5FFFF72EEFBFF72EEFBFF72EEFBFF76F7FFFF65D2 DCFF448E95FF65D1DCFF72EFFCFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF60DF E7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2 D7FF51D2D7FF52D4D9FF4CC3C6FF0A1515FF130B05FFFF9A40FFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFDE3CD410000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000008F8F 8F7B191818FF191A1AFF171A1AFF161718FF2F5A3DFF55A36CFF53A46FFF67C1 87FF6EC08EFF294B3CFF1E2427FF1F2629FF1F292FFF232F36FF83A0A3FFD2F7 F9FFDEF0F6FFE4F1F8FFBEE4E2FF7BD2C4FF5BA896FF182324FF191D21FF1B20 24FF1B1F23FF1A1D21FF1B1C20FF1A1C1FFF191A1CFF1B1F1DFF5D7F5CFF6289 68FF23503DFF3D6A62FF2C443DFF141011FF161314FF161314FF161314FF1613 14FFD8D8D82A0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FDDABD56FD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFF9B40FF9B5C 26FF0C0703FFC77631FFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFF9C 45FF40544CFF000000FF0A1415FF438B91FF52A9B2FF40858CFF162E2FFF0000 00FF000000FF000000FF5EC5CFFF72EEFBFF72EEFBFF72EEFBFF73EFFCFF57D7 DEFF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF52D6DBFF54D9 DFFF44ACAFFF275F60FF000000FF000000FFC47430FFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFDC18E94000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000E8E8 E819262626EF1A1A1AFF181A1AFF191B1CFF1B1D1EFF72BE9DFF7AC89CFF7DBD A3FFD0F2F5FF4E7163FF1D2226FF1E2629FF232E34FF2B3A42FF577176FFDBFC FFFFE7F3FAFFDFEDF4FFE0EBF4FFCEEEF3FF687C7BFF121418FF1B2224FF1D20 23FF1C1F21FF1B1D20FF1B1C1FFF1A1C1EFF191A1CFF262C29FFC7DCC5FFA9C7 92FF356642FF325B50FF151A18FF151314FF161314FF161314FF161314FF5755 56B7F7F7F7080000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000FDBD869EFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFE96 3EFFFF9C41FFFA943DFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFF8A04FFF62BDC4FF295459FF0E1E20FF070E0FFF070F10FF060B0CFF0000 00FF000000FF000000FF040707FF6EE6F2FF72EEFBFF72EEFBFF6FECF8FF4FD1 D6FF51D2D7FF51D2D7FF51D2D7FF51D2D7FF54DBE0FF3EA1A5FF1C4749FF0000 00FF000000FF000000FF010001FFA36128FFFF983FFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFCA65DD400000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000FDFD FD027474749A1A1A1AFF1A1A1AFF1A1C1BFF19191CFF516D62FFA1D7BEFF82C3 98FFBAEBBFFF7B997FFF1D2727FF1B2628FF243036FF2E3F47FF344D59FFACC0 C6FFF6FAFFFFF3F7FCFFF1F6FCFFF2F7FBFFF0F2F2FFB1B2B3FF1C2021FF1B1D 20FF1C1E20FF1B1D1FFF1B1D1FFF1A1C1EFF17171BFF505849FFD4EAACFF90B1 6EFF769A5DFF617561FF131415FF151414FF161314FF161314FF1A1718FAA9A8 A85E000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000FCA8 60D0FD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFE8A45BFF72F3FFFF77F8FFFF77F9FFFF77F9FFFF77FAFFFF76F6 FFFF62CDD8FF265054FF000000FF183234FF76F7FFFF73EFFCFF5EDDE4FF51D2 D7FF51D2D7FF51D2D7FF51D3D8FF44AFB4FF091818FF000000FF070E10FF1F41 45FF3C7275FFC16E29FFFF9A40FFFE973EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD9A46F4FEFBF70900000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000C9C9C93B232424F3191A1AFF191B1CFF1A1D1CFF2E2E31FFB9DCBFFF7AC3 8BFFBCE6BBFFABBDC0FF242D2FFF192326FF202B30FF2A3841FF2A3F49FF7180 86FFF0F4F8FFEDF0F3FFA0A3A5FF7C7F83FF7E8084FF9A9A9DFFCECED0FF4244 44FF191B1DFF1B1D1FFF1A1C1EFF191A1CFF131119FF8B9D67FFC4D88FFF91A7 79FF91AE66FF485034FF131212FF151414FF161314FF161314FF302D2EE2F3F2 F30D000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000FEFC FB05FD9E4DEAFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFE963DFFD5AF74FF6DF1FFFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF76F7FFFF29565BFF000000FF336B70FF6FEFFBFF50D1D6FF51D2 D7FF51D2D7FF52D6DBFF3C9B9EFF000000FF152B2DFF66D5E1FF77F9FFFF75F4 FFFF6FF2FFFFD6AF74FFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFEF0E5220000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000004F5050C2181A1AFF191B1BFF1A1B1CFF1B1F20FF799574FFB2E2 ADFFB8E2B8FFE2EFF7FF2E3539FF1B2326FF1B2529FF232E34FF253238FF5C64 6AFFECF1F4FFA8ABAEFF0D0F13FF181B1FFF171A1EFF12161AFF0D0E13FF4E4F 52FF212224FF1A1D1EFF191A1CFF19191CFF0D0C10FFDDEABCFFE2E1CDFFC6C6 B0FFB6B699FF141411FF141414FF151414FF161314FF161314FF8F8E8E7A0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FEF6F013FD9A45F5FD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFF943BFFBEBF94FF6EF0FFFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF75F5FFFF1E3E41FF000000FF2F7679FF54DADFFF52D5 DAFF53D7DCFF266264FF000000FF1A3639FF74F1FEFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF87E1E0FFFF9337FFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFEE7 D437000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000C7C8C73D161A1AFF181A1AFF181A1CFF18191CFF404F43FFA4D6 9AFFE2F1E4FFFBFEFFFF525559FF1D2124FF1E2226FF1E2428FF1C2529FF5961 64FFF1F5F9FF2D3034FF1C1F23FF1E2125FF1E2125FF1C1F23FF1C1D22FF1A1B 1FFF1C1D21FF191A1EFF18191BFF141517FF494C49FFFAF7E5FFE7E1C9FFD7D3 BBFF5E5A51FF110E0FFF161314FF161314FF161314FF1D1A1BF7000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000FEF3EA1BFD9843F8FD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFF9338FFA5CEB6FF70EFFDFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF75F4FFFF244A4EFF000000FF163839FF1F50 52FF020606FF000000FF30656BFF75F5FFFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF6EF0FFFFD5B075FFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFEE2CC430000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000004B4E4EC4181A1AFF181A1CFF191A1EFF0F0F12FFC1CB BDFFF5F7F7FFF2F3F7FFA0A2A4FF17191DFF1E2226FF1E2226FF1B2024FF6A6D 71FFDADCE0FF101217FF1E2125FF1E2024FF1D2024FF1A1D21FF1C1C20FF1A1C 20FF1A1B1FFF191A1EFF18191BFF0E1012FF9A9791FFF0E5D1FFEBE0C8FFD0CB BAFF040000FF161414FF161314FF161314FF161314FF908F8F79000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000FEF4EB1AFD9A45F5FD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFF9439FF90DBD2FF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF76F6FFFF4DA1AAFF183033FF0B17 18FF2B5A5FFF61C9D4FF74F3FFFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF85E2E1FFFF9337FFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFDE3CC42000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000C6C7C73E181919FF191A1AFF191A1BFF141616FF4E4F 50FFFDFDFEFFEFEEEFFFEDEEEFFF0D1113FF1D2024FF1E2125FF1C1F23FF6B6E 72FF96989BFF171A1FFF1C1F24FF1C2024FF1C1E21FF1A1D1FFF1A1C1FFF1A1C 1EFF191A1DFF181A1CFF18191BFF0F1012FFD3CEC1FFEFE7D2FFF2E8D1FF5754 4BFF141311FF161313FF161314FF161314FF272425ECEEEEEE12000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000FEF7F112FD9E4DEAFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFC973FFF80E6E9FF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF76F6FFFF77F9 FFFF74F1FEFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF6EF0FFFFD4B177FFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFEE9D83300000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000F4F4F40C4A4E4DC5171A1AFF161918FF181A1AFF0F11 11FFC8C9C7FFFDFBF9FFFAF8F8FF3A3B3BFF171B1EFF1B1F21FF1B1F21FF292D 2FFF898C8DFF131719FF1A1E20FF1A1E20FF1B1D1FFF1B1D1FFF191A1CFF191A 1CFF18191BFF16181AFF151719FF403F3EFFDBD6C4FFECE5D1FFD0CBBDFF2623 20FF161412FF161413FF161314FF161314FF7A797990FEFEFE01000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000FEFCFA05FCA961CFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFF39D4DFF75ED F8FF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF85E2E2FFFF9337FFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD9D4AEEFEF3E91C0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000A1A3A266161A19FD161918FF181A1AFF1719 1AFF4D4D4CFFFAF8F6FFF8F4F3FF959595FF111416FF1C1E20FF1C1E20FF1A1C 1EFF323436FF181A1CFF1B1D1FFF1B1D1FFF1B1D1FFF1A1C1EFF191A1CFF181A 1CFF16181AFF16181AFF161619FF64635EFFE4DFCBFFE9DEC8FF7A7567FF1411 10FF161313FF161213FF161214FF201D1EF3C6C5C53E00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000FDBE889CFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFE4A6 61FF6FF0FFFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF6FF0FFFFD3B178FFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFDAC67C8FEFCFA05000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000EEEEEE122C2E2DE7161918FF181A1AFF181A 1AFF202321FFC5C4C2FFF8F6F4FFD7D7D6FF0D0F10FF1B1C1EFF1A1C1EFF1A1C 1EFF191B1DFF1B1D1FFF1B1D1FFF1B1D1FFF1A1B1DFF181A1CFF191A1CFF1718 1AFF15181AFF161818FF171717FF93948EFFF9F8EAFFE3E0D5FF322F2DFF1512 12FF151213FF151213FF151213FF4B4849C40000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000FDDB BE54FD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFE95 3CFFCFB47DFF6DF1FFFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF84E3E4FFFF9337FFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFDC99C810000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000083838387171817FF141918FF1419 18FF121716FF727471FFEBE9E3FFE1DFDBFF454545FF18191BFF101214FF1D21 22FF181A1CFF181A1CFF181A1CFF181A1CFF18191BFF17191BFF16181AFF1719 1BFF131617FF111616FF222420FFCBCDC3FFFCFCEFFFACACA3FF0A0907FF1613 13FF151213FF151213FF151213FFCECDCD350000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FEF7F112FDA963CDFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFF943AFFB7C39EFF6FF0FFFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF6FF0FFFFD2B279FFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD9E4DEAFEEA DA30000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000171717FD151716FF1418 17FF141818FF272929FFDAD6D4FFEEEBE6FF888786FF1C1D1DFF848687FF2023 25FF151819FF16181AFF16181AFF16181AFF18191BFF17181AFF16181AFF1C1D 1EFF636361FF2A2927FF484642FFFFFEEEFFFEFFF0FF242320FF141210FF1613 13FF151213FF151213FF413F40CE000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000FDD4B166FD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFF9338FF9ED2BFFF71EFFCFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF83E3E4FFFF9337FFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFDC4948C000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000093939376151515FF1617 16FF151818FF0A0D0CFF8D8C8AFFECEBE3FFDEDDD6FFDBDAD5FF656866FF090F 0EFF141918FF161918FF161918FF161919FF181818FF171717FF171616FF1414 14FF4B4A47FFC6C1B1FFD6CCB8FFF5EAD2FFA4A39DFF090809FF141413FF1313 13FF131313FF121212FFC5C5C53E000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000FEFBF808FDBC85A0FD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFF943AFF8BDFDAFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF6FF0FFFFD0B27BFFFD96 3EFFFD963EFFFD963EFFFD963EFFFDAE6BC2FEF2E81D00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000E7E7E719272727EA1414 14FF151515FF151515FF141313FFFDFAF4FFEEECE1FFAFAEA6FF0E110FFF1218 16FF141817FF161817FF161817FF161817FF161616FF161616FF151515FF1515 15FF0C0C0EFF8C8780FFF7F2E1FFF0E7CDFF312F2DFF131313FF131313FF1212 12FF111111FF494949C3F2F2F20D000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FEF1E71FFCB475B5FD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFA9842FF7CE8EEFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF82E4E5FFFF93 37FFFD963EFFFCA75FD2FEE6D13B000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FCFCFC03777777931414 14FF141414FF151515FF101010FF7B7875FFFCF7EBFF757470FF111211FF1516 16FF161616FF161616FF161616FF161616FF151515FF141414FF141414FF1414 14FF0F0D10FF595855FFF6ECD0FFA39B87FF1A1819FF131313FF111111FF1111 11FF111111FE9494947200000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000FEF0 E521FDB980A6FD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFEF9F52FF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF6FF0FFFFD9C4 9AC5FEE6D13B0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000CACACA391C1C 1CF5131313FF141414FF141414FF292626FFF5F3EBFF4E4D49FF121213FF1515 14FF151414FF141414FF141414FF151515FF141414FF141414FF121212FF1212 12FF0E0D10FF44423DFFEEE8C8FF5D5B56FF101010FF121212FF111111FF1111 11FF1F1F1FEFECECEC1400000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000FEFBF709FDCDA378FDA050E6FD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFDEAA69FF6EF1FFFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FBFF72EEFBFF72EEFBFF72EEFBFF71EEFCFF76ECF7FCAFF1F697EFFAF9220000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000004A4A 4AC1121212FF131313FF131313FF151514FFABAAA2FF62625DFF101010FF1313 13FF131313FF131313FF131313FF131313FF131313FF131313FF111111FF1111 11FF0D0D0FFF44443FFFE7DDC0FF111113FF111111FF111111FF111111FF1111 11FF7E7E7E8A0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000FEECDC2DFDC4948CFCA152E4FD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFF953CFFC8B787FF6EF1 FFFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EEFBFF72EE FCFF71EEFCFF78EBF6F9A6F0F6A7DAF7F7480000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000C8C8 C83A101010FF101010FF101010FF0F0E0EFF474644FF20201EFF121212FF1212 12FF121212FF121212FF121212FF121212FF111111FF101010FF101010FF1010 10FF0F0F0FFF201F1EFF6A695EFF09090AFF101010FF101010FF101010FF1010 10FFF3F3F30C0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000FEF5 ED17FDD6B462FDBA7FA7FCA052E4FD963EFFFD963EFFFD963EFFFD963EFFFD96 3EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFD963EFFFF9439FFAFC8 A8FF70F0FEFF72EEFBFF72EEFCFF72EEFCFF72EEFBFF79EBF5F69BEFF6BBBFF4 F778E9F8F82E0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00003F3F3FC3040404FF040404FF040404FF000000FF020202FF040404FF0404 04FF040404FF040404FF040404FF040404FF040404FF040404FF040404FF0404 04FF040404FF030302FF000000FF050505FF040404FF040404FF040404FF7979 7989000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000FEFEFE01FEEBDB2EFDDABA59FDCB9F7DFDBF 8B99FCB578B1FCAB66C9FDA75ED4FCA55CD7FCA55CD7FCA75DD5FCAA63CCFFB1 6FB5B3EAE7A2B5F3F68AC8F4F769DFF7F83FF9FBF90F00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D2D2D22D000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF000000FF000000FF010101FE0606 06F9050505FA050505FA050505FA050505FA070707F80B0B0BF4191919E6E3E3 E31C000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000A2A2 A25D000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF101010EFE0E0E01F00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000FCFCFC03F6F6F609F3F3F30CF2F2F20DF3F3F30CF7F7F708FDFD FD02000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000002222 22DD000000FF000000FF000000FF000000FF1D1D1DFF000000FF000000FF0000 00FF030303FC7575758A00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000F2F2F20EF7F7F708FEFEFE010000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000F3F3F30CB7B7 B748888888776464649B4B4B4BB43D3D3DC2393939C63F3F3FC04F4F4FB06969 69968C8C8C73B8B8B847F2F2F20D000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000A0A0A05F0606 06F9010101FE000000FF000000FF121212FFBBBBBBFF000000FF000000FF0000 00FF000000FF2B2B2BD4E1E1E11E000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000A8A9A95E434445C19393926FE5E5 E51AFDFDFD020000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000EFEFEF1066666699171717E80A0A 0AF5000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF010101FE0B0B0BF4161616E95E5E5EA1DEDEDE2100000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000F6F6F609474747B80000 00FF000000FF000000FF000000FF8A8A8AFFEEEEEEFF383838FF000000FF0000 00FF000000FF000000FFA1A1A15E000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000BDBCBC43282F35FF14171BFF3737 37CCC5C5C53AF8F8F80700000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000F5F5F50A8F8F8F70000000FF000000FF010101FE0101 01FE000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF010101FE010101FE000000FF000000FF6161619EE2E2E21D0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000BEBEBE410E0E0EF10000 00FF000000FF000000FF0E0E0EFFE4E4E4FFF4F4F4FF959595FF000000FF0000 00FF010101FE000000FF3A3A3AC5F3F3F30C0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000EBEBEB143D3F42D23F474FFF1E23 26FF212121DF9A9A9968F2F2F20D000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000DCDCDC23454545BA000000FF000000FF010101FE000000FF0000 00FF273239FF435662FF556B7BFF5C7585FF5B7485FF546B7AFF465965FF313F 48FF181E22FF000000FF000000FF000000FF000000FF000000FF0F0F0FF08585 857AF9F9F9060000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000FBFBFB0466666699000000FF0101 01FE000000FF000000FF707070FFF0F0F0FFF6F6F6FFCFCFCFFF212121FF0000 00FF000000FF000000FF000000FFC1C1C13E0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000FDFDFD02ACADAD55262D31F9464E 57FF1E2329FF06060BF97676768EECECEC130000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D1D1D12E1E1E1EE1000000FF000000FF010101FE000101FF3A4A54FF9FCA E6FFAFDFFDFFB4E6FFFFB7E8FFFFB5E6FFFFB2E3FFFFB1E1FFFFADDDFBFFA9D7 F5FFA3CFECFF98C1DCFF617C8DFF12171BFF000000FF010101FE000000FF0101 01FE444444BBF7F7F70800000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000E1E1E11E050505FA000000FF0000 00FF000000FF101010FFBCBCBCFFF6F6F6FFF5F5F5FFF7F7F7FF5C5C5CFF0000 00FF000000FF010101FE000000FF333333CC0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000F2F2F20D7A7B7C8D232A 30FB414A54FF181D30FF040410FF5B5B5BAAD7D7D728FBFBFB04000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FEFEFE01FAFAFA05F5F5F50AF0F0F00FEEEEEE11EEEEEE11F4F4F40BFDFD FD02000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000EFEF EF10373737C8000000FF000000FF000000FF000000FF030405FF1A2126FF0B0E 11FF101418FF212A31FF40525EFF678495FF9CC7E2FFB0E0FFFFB0E0FFFFB0E0 FFFFAFDFFEFFB0E0FFFFB3E4FFFFBAEDFFFF799AAFFF1E262CFF030405FF0101 01FE000000FF333333CCF5F5F50A000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000006D6D6D92000000FF010101FE0000 00FF000000FF464646FFF1F1F1FFF5F5F5FFF4F4F4FFFAFAFAFFB5B5B5FF0909 09FF000000FF000000FF000000FF000000FFBFBFBF4000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000E3E3E31C4D50 51C12D373DFF313941FE0E1128FE010311FF393D4FCAC0BFC041FCFCFC030000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FEFEFE01F4F4F40BECECEC13E4E4E41BD6D6D629C0C0C03FACACAC539E9E 9E618F8F8F707C7C7C836363639C535353AC4A4A4AB54B4B4BB46262629D9191 916ED3D3D32C0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000007272 728D000000FF010101FE000000FF000000FF000000FF000000FF000000FF282D 2FFF4F575DFF66757EFF698393FF69889CFF86ABC3FFAEDEFDFFB0E0FFFFB0E0 FFFFB0E0FFFFB0E0FFFFAFDFFEFFAFDFFEFFB4E5FFFFAFDEFDFF7392A6FF2029 2FFF010101FE000000FF373737C8EAEAEA150000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000F3F3F30C000000FF000000FF000000FF0000 00FF060606FF9B9B9BFFFCFCFCFFF5F5F5FFF5F5F5FFF5F5F5FFFFFFFFFF2A2A 2AFF000000FF000000FF000000FF000000FF3B3B3BC400000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000FEFEFE01C1C1 C13E2E3337F74B545EFF3A4149FE090D1CFF040F42FF191B1CEBC0C0C03FFCFC FC03000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FAFAFA05F1F1F10EE8E8E817D8D8D827BEBEBE41A2A2A25D8C8C8C737878 78875F5F5FA0444444BB333333CC272727D81E1E1EE1151515EA0D0D0DF20909 09F6050505FA030303FC010101FE000000FF000000FF000000FF010101FE0606 06F9202020DF8383837CF3F3F30C000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000D4D4D42B0000 00FF000000FF010101FE000000FF000000FF0C0D0EFF707E86FFBACFDEFFC9E1 F0FFD2EAFAFFD7F0FFFFD5F0FFFFCAEBFFFFB4E2FFFFAFDFFFFFB0E0FFFFB0E0 FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFAFDFFEFFB0E0FFFFB1E2FFFFA2CE EBFF3D4E59FF010101FE000000FF515151AEF9F9F90600000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000067676798000000FF010101FE000000FF0000 00FF222222FFF6F6F6FFF3F3F3FFE8E8E8FFFCFCFCFFF8F8F8FFFCFCFCFFA3A3 A3FF000000FF000000FF000000FF010101FE080808F7C0C0C03F000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000FEFEFE01F9F9F906EEEEEE11F3F3F30CFDFD FD02000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000F9F9 F90687888880353B44FF414A57FF12162FFF080F30FE03032BFF2A2A2EDEADAD AC53F6F6F6090000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000F7F7F708EFEFEF10E9E9 E916DFDFDF20D8D8D827CECECE31B8B8B8479D9D9D62888888777474748B5A5A 5AA53C3C3CC3262626D9181818E70E0E0EF1050505FA000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0101 01FF020202FE030404FF050606FF080909FF0A0D0DFF0A0B0CFF050606FE0101 01FE000000FF010101FE6363639CEDEDED120000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000004C4C4CB30000 00FF000000FF010101FF181B1DFF7A8891FFDAF3FFFFDAF4FFFFD6EFFFFFD5EE FEFFD6EFFFFFD6EFFFFFD5EEFFFFD6EFFFFFD6EFFFFFC4E8FFFFB2E0FFFFB0E0 FFFFAFDFFFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0 FFFFB3E3FFFF35444EFF010101FE000000FF9999996600000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000E2E2E21D141414EB000000FF000000FF000000FF0000 00FF919191FFEFEFEFFF686868FF3C3C3CFF646464FFD3D3D3FFFFFFFFFFF8F8 F8FF1B1B1BFF000000FF000000FF000000FF010101FE5D5D5DA2000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000FCFCFC03D4D4D42B7C7C7B854C4C4CB5636466A7B1B1 B151FCFCFC030000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000E0E0E01F5C5F62C43E4859FF2D3541FE242A2DFF0F1110FE060609FF1717 23EDB1B1B250FCFCFC0300000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000F5F5F50AABABAB546161619E474747B83A3A 3AC5292929D61C1C1CE3121212ED080808F7000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0101 01FE040405FF080A0AFF0E1010FF161B1CFF202728FF2B3233FF343D3EFF3D47 49FF465456FF4F6061FF5A6B6DFF627576FF66797BFF66797AFF58686AFE2F38 38FE040606FE000000FF010101FE78787887FCFCFC0300000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000DEDEDE21101010EF0101 01FE1A1D20FF75838CFFCAE1F0FFDFF9FFFFD6EFFFFFD5EEFEFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD5EEFFFFD6EFFFFFD7EFFFFFD2EDFFFFC1E6 FFFFB0E0FFFFAFDFFFFFB0E0FFFFAFDFFEFFB2E3FFFFB9EBFFFFB9ECFFFFB8EA FFFFB6E8FFFFB1E2FFFF273239FE000000FF000000FFD8D8D827000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000007B7B7B84030303FC010101FE000000FF000000FF0E0E 0EFFFAFAFAFFA4A4A4FF000000FF000000FF000000FF141414FF878787FFFDFD FDFF949494FF000000FF000000FF000000FF000000FF1E1E1EE1D1D1D12E0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000F9F9F9069F9F9F65171717EA15181BFD2A3137FF262D33FC9799 996DFDFDFD020000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FBFBFB04A5A5A55E4D5660F74D5762FE2F3840FF0C0D10FF03031FFF0303 0FFF19191BEABBBBBC4500000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000E2E2E21D6161619E0E0E0EF1010101FE000000FF0000 00FF000000FF000000FF000000FF000000FF000000FF000000FF010101FF0405 05FF080909FF0F1112FF1A1F1FFF272E2FFF313B3CFF3E494AFF475558FF5769 6BFF65787AFF6C8082FF758A8DFF799093FF80989AFF88A0A2FF869FA1FF849C 9FFF88A0A3FF89A2A5FF89A3A5FF8BA4A7FF8AA3A6FF87A0A3FF839D9FFF819A 9BFF586768FE070808FF000000FF0A0A0AF5ADADAD5200000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000AEAEAE51171717E8010101FE434B 50FEC5DDEBFFD7F0FFFFD6EFFFFFD5EEFEFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD5EEFFFFD6EFFFFFD5EE FFFFD0EDFFFFB6E2FFFFAEDFFFFFB1E1FFFF89AFC7FF2D3A42FF28343BFF3F51 5CFF6B899CFFA7D4F3FF9CC7E2FF010101FE000000FF393939C6000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000E3E3E31C303030CF000000FF000000FF000000FF000000FF8C8C 8CFFEEEEEEFF3E3E3EFF000000FF000000FF000000FF000000FF000000FF2323 23FFBCBCBCFF141414FF000000FF000000FF010101FE000000FF88888877FEFE FE01000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F9F9F906A6A6A75C060606FA16191DFF525A6AFE67707AFF585B5FD1E1E1 E11EFEFEFE010000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000EFEFEF105E6062B657626EFF3F4954FE1E272EFF0F1317FF0809 14FE030303FF383837CEE4E4E41BFEFEFE010000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000CCCCCC33424242BD000000FF000000FF020202FE090C0CFF0D0F 10FF141717FF1C2222FF283131FF343E3FFF3E4A4BFF4A575AFF5B6B6DFF687C 7EFF708789FF768C90FF7C9597FF839DA0FF8BA4A7FF8BA5A8FF87A1A4FF8AA4 A6FF89A3A5FF88A2A4FF8CA5A8FF90A9ABFF8AA3A6FF849FA2FF88A2A5FF8CA5 A8FF8CA5A8FF87A0A3FF869FA2FF87A1A4FF86A0A3FF8BA5A7FF8FA7A9FF8CA6 A8FF89A3A6FF455254FF010101FE000000FF3A3A3AC5EBEBEB14000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000EBEBEB144E4E4EB1000000FF0A0B0CFF85959FFEE1FC FFFFD6EEFFFFD5EEFEFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD5EE FFFFD6EFFFFFD6EFFFFFBFE6FFFFB1E1FFFF99C3DEFF2E3B43FF0A0D0FFF0000 00FF000000FF000000FF252E36FF161C20FF010101FE0B0B0BF4BDBDBD420000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000A3A3A35C000000FF000000FF000000FF000000FF000000FFDDDD DDFFE4E4E4FF0B0B0BFF000000FF000000FF000000FF000000FF000000FF0000 00FF080808FF373737FF000000FF000000FF010101FE000000FF202020DFF0F0 F00F000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000FEFE FE01C4C4C43C252525DE00011AFF37475DFE5C6683FF525A66FEA7A7A75CFDFD FD02000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000C3C3C33C3D444BF4535F6AFF313C44FE1B252EFF0D12 25FF070702FE07060EFB8586877DF5F5F50A0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000C3C3C33C2F2F2FD0000000FF000000FF0B0D0DFE465353FF6F8284FF7489 8CFF7B9192FF7D9596FF7F999CFF849EA1FF839DA1FF859FA2FF8CA6A8FF8DA6 A8FF88A2A6FF87A0A3FF88A2A5FF8AA3A6FF8BA4A7FF8BA5A7FF8EA7A9FF8CA5 A8FF8CA5A7FF8FA7AAFF8AA4A6FF88A1A4FF8AA3A5FF89A2A5FF8AA3A6FF8DA6 A8FF8EA7A9FF8DA6A8FF8CA5A8FF8BA5A7FF8AA3A7FF8AA3A7FF88A1A4FF86A0 A2FF89A2A4FF7A9092FF1E2424FF010101FE080808F798989867FEFEFE010000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000BFBFBF40252525DA000000FF272C2FFEACC1CDFFDBF4FFFFD5EE FEFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFC7E9FEFFB3E2FFFFB7E9FFFF94BDD7FF576F 7FFF13191DFF000000FF000000FF000000FF000000FF000000FF68686897FCFC FC03000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F8F8F8073E3E3EC1000000FF010101FE000000FF000000FF000000FF9C9C 9CFFF7F7F7FF777777FF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF000000FF010101FE000000FF9D9D 9D62000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000E3E3 E31C40403FC600062FFF212B51FF4A526CFF464D5DFD8C8D8F7BF5F5F50A0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000F5F5F50A6E6F719F434B55FF283038FE1D262DFF0C0F 1EFF040C40FE03094CFF181819EDADADAD53FBFBFB0400000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000CACA CA352E2E2ED1000000FF000000FF141818FE5E7173FF8EA6A8FF96ADAFFF91AA ABFF7F989BFF839D9FFF8CA5A7FF8FA8AAFF90A8AAFF8BA5A7FF8CA6A8FF8AA3 A5FF88A1A4FF89A2A5FF8BA3A7FF87A0A3FF829C9FFF819B9FFF839DA0FF88A2 A5FF87A1A3FF809B9EFF819B9EFF87A0A3FF8CA6A8FF8DA6A8FF86A0A3FF839D 9FFF89A2A5FF8BA4A7FF869FA2FF859FA2FF8DA6A8FF8CA6A8FF88A1A4FF829D A0FF87A1A3FF87A0A3FF536364FF040505FE000000FF303030CFDDDDDD220000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009C9C9C63070707F8000000FF464D53FFCDE5F4FFD7F1FFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD5EEFFFFD6EFFFFFD6EFFFFFD0ECFEFFB4E1FFFFB0E0FFFFB0E0 FFFFA3CFECFF546C7BFF000000FF000000FF000000FF000000FF1C1C1CE3F3F3 F30C000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000C6C6C639000000FF000000FF000000FF000000FF000000FF000000FF0707 07FFDFDFDFFFE9E9E9FF393939FF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF000000FF010101FE000000FF1515 15EA000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FEFEFE01E5E5E51A6464 659F05061DFF0C1949FE5F6771FE737C83FE6C6F72AFE7E7E718000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000FEFEFE01B7B7B74A393F45F5353B44FF353F49FF1D27 55FF0A1C4BFF080811FE050414FF181818EEB9B9B947FDFDFD02000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000CFCFCF302E2E 2ED1000000FF010101FE15191AFF677A7CFF849EA1FF768E91FF556769FF3139 3AFF222829FF475455FF849D9FFF86A0A2FF8EA7A9FF8CA5A7FF859FA2FF87A1 A4FF89A2A4FF839DA0FF86A1A3FF8BA4A6FF8CA5A7FF8CA6A8FF8AA3A5FF89A2 A4FF8DA6A8FF8DA5A8FF8BA5A7FF8AA3A6FF89A3A5FF859FA2FF86A0A2FF88A2 A5FF829DA0FF839DA1FF859FA2FF89A2A4FF89A2A5FF87A0A4FF89A2A5FF86A0 A3FF829C9FFF839D9FFF799193FF202727FF000000FF000000FF8181817E0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000A0A0 A05F020202FD010101FE495257FFD4EDFDFFD5EEFEFFD5EEFEFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD1ECFFFFB5E2FFFFAFDF FEFFAFDFFEFFB5E7FFFF98C1DCFF242E34FF010101FF010101FE000000FF4545 45BAECECEC130000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00003C3C3CC3000000FF000000FF000000FF000000FF030303FF000000FF0000 00FF262626FFF9F9F9FFC3C3C3FF101010FF000000FF000000FF000000FF0000 00FF000000FF000000FF040404FF000000FF000000FF000000FF010101FE0000 00FF9E9E9E610000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000E7E7E71862625FA00505 25FF0B0C1DFE4F575DFE858E96FF666C72EEBABABA45FDFDFD02000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000DDDDDD224B5054D0424D5DFF27356DFF474F 5DFF383D42FF13171BFF101214FE080808FF2C2C3CD9D8D8D827FEFEFE010000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000C4C4C43B2F2F2FD00000 00FF000000FF1C2122FE6C8182FF859EA0FF506062FF151919FF010101FF0000 00FF000000FF242B2CFF829A9DFF87A1A4FF839EA0FF89A2A4FF8AA3A5FF89A2 A5FF8FA8AAFF8FA8A9FF89A3A5FF88A1A4FF8EA8AAFF8CA6A8FF8BA4A6FF8AA3 A5FF86A0A2FF88A2A4FF88A1A5FF849EA1FF819A9EFF839DA0FF88A1A3FF8CA5 A7FF8BA4A7FF89A2A5FF89A2A5FF88A1A4FF8BA4A6FF8BA3A6FF8BA4A6FF90A8 A9FF8FA7A9FF87A1A3FF859FA2FF5E7274FF070908FE000000FF131313ECC8C8 C837000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000ADADAD520808 08F7000000FF383F43FFCDE6F5FFD7F0FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD5EEFFFFD6EFFFFFD2EDFFFFB7E3 FFFFAEDFFFFFAFDFFEFFB2E3FFFFADDDFBFF607B8CFF030405FE010101FE0000 00FF161616E9ACACAC5300000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000C7C7 C738000000FF010101FE000000FF000000FF080808FF565656FF000000FF0000 00FF000000FF686868FFFFFFFFFF8A8A8AFF000000FF000000FF000000FF0000 00FF000000FF000000FF444444FF1C1C1CFF000000FF000000FF000000FF0000 00FF222222DD0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000F1F1F10E7C7C7D87040418FF0304 2CFF656D72FE818B95FE616973FF6B6C6DACF4F4F40B00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000F1F1F10E62646AA72B343FFF464E5FFF6068 74FF5B646FFF11151BFF101416FF0A0B10FE060610FD7575758DF6F6F6090000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000CDCDCD322E2E2ED1010101FE0000 00FF1A1F1FFE73898BFF849C9FFE394344FF060707FF000000FF000000FF0000 00FF040404FF556565FF8CA5A7FF8EA6A9FF89A2A5FF88A3A6FF8DA7A9FF8FA8 AAFF8EA7A9FF8AA3A6FF849EA0FF849EA1FF87A0A3FF88A2A5FF8BA4A7FF8AA3 A5FF87A0A4FF87A1A3FF8AA3A6FF8CA5A8FF8BA4A7FF89A2A5FF849FA1FF839D A0FF869FA2FF88A2A4FF8DA7A9FF8BA4A7FF8BA4A6FF89A3A6FF87A0A3FF8DA5 A7FF91A8AAFF8DA6A8FF8BA5A8FF89A2A5FF3A4546FF000000FF000000FF5555 55AAF7F7F7080000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000C8C8C837020202FD0000 00FF1F2326FED0E9F8FFD7F0FFFFD5EEFEFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD5EEFFFFD6EFFFFFD2ED FFFFB6E2FFFFAFDFFFFFAFDFFEFFB0E0FFFFB0E0FFFF90B7D0FF141A1EFF0101 01FE000000FF030303FC7E7E7E81000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000003B3B 3BC4000000FF010101FE000000FF000000FF343434FFA7A7A7FF000000FF0000 00FF000000FF161616FFC4C4C4FFFDFDFDFF191919FF000000FF000000FF0000 00FF000000FF000000FF505050FF969696FF000000FF000000FF000000FF0101 01FE060606F9A4A4A45B00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000FEFEFE01EAEAEA157E7E7F84030304FF03063EFF0A10 51FE777F84FE98A1AAFF50555BF4CACACA350000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000F8F8F8078586878123272DFB444B55FF4952 5BFF3D464FFF0B0D11FF0A0A10FF07070CFF040403FF2F2F2FD4DDDDDE220000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000C8C8C8372B2B2BD4000000FF010101FE181D 1DFE6E8285FF859C9EFF353D3EFF000000FF000000FF000000FF000000FF0203 03FF3C4848FF829B9EFF86A0A3FF849FA1FF88A2A5FF87A0A3FF88A1A4FF89A2 A5FF87A1A4FF86A0A2FF88A1A4FF88A1A4FF839DA0FF829D9FFF86A0A3FF89A2 A4FF8BA4A6FF8CA5A7FF8DA6A8FF8AA4A7FF8EA8AAFF8DA7A9FF89A3A6FF8AA3 A6FF849EA1FF849EA1FF86A0A3FF87A0A3FF849DA0FF849EA1FF86A0A3FF859E A1FF87A0A3FF8AA3A5FF88A2A4FF8BA4A7FF758A8CFF131717FF000000FF0C0C 0CF3A5A5A55AFEFEFE0100000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000E7E7E718141414EB010101FE0D0F 10FFBFD5E3FFD6EFFFFFD5EEFEFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFCFECFFFFB3E1FFFFAFDFFFFFB0E0FFFFAFDFFEFFB1E1FFFFA0CDE8FF222B 31FF010101FE010101FE000000FF515151AEF6F6F60900000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000BFBFBF400C0C 0CF3010101FE000000FF000000FF000000FFADADADFFA7A7A7FF000000FF0000 00FF000000FF161616FFC0C0C0FFFFFFFFFF060606FF000000FF000000FF0000 00FF000000FF000000FF474747FFF1F1F1FF1B1B1BFF000000FF000000FF0000 00FF000000FF4A4A4AB5F9F9F906000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000ECECEC136F6F6F94050503FF020230FF04105FFE2A33 51FF515B78FF5C6670FF7D7E8091F7F7F7080000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000FDFDFD029F9F9F662C3438F83C444EFE434B 55FF414A53FF182025FF0C0F11FF04040EFF03030CFF13131CF3B5B5B64AFEFE FE01000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000C5C5C53A303030CF000000FF010101FE181D1DFE6D81 83FF88A1A3FE3E4A4CFF000000FF000000FF000000FF000000FF080A0AFF4855 56FF829B9EFF86A0A3FF86A0A3FF87A1A4FF849FA1FF859EA1FF859FA2FF86A0 A2FF89A3A5FF8CA6A7FF90A8AAFF92A9ACFF8DA6A8FF88A1A4FF87A1A3FF89A3 A5FF8BA4A6FF8DA6A9FF8BA5A7FF88A3A5FF839DA1FF89A2A5FF8BA4A7FF8BA4 A7FF8EA7A9FF8CA5A7FF86A0A2FF87A1A3FF8AA3A6FF8AA3A5FF8BA5A8FF8BA5 A7FF8AA3A6FF8AA3A6FF87A1A3FF849EA0FF809B9DFF435051FF020203FE0000 00FF414141BEECECEC1300000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000FCFCFC035A5A5AA5000000FF010202FE8393 9CFFD7F0FFFFD5EEFEFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD5EE FFFFD7EFFFFFCBEAFFFFAFE0FFFFAFDFFFFFB0E0FFFFAFDFFEFFB2E3FFFFABD9 F7FF465864FF000000FF010101FE000000FF3F3F3FC0E8E8E817000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000595959A60000 00FF000000FF000000FF000000FF262626FFFFFFFFFFA0A0A0FF000000FF0000 00FF000000FF474747FFF4F4F4FFC5C5C5FF000000FF000000FF000000FF0000 00FF000000FF000000FF474747FFEEEEEEFF9E9E9EFF000000FF000000FF0000 00FF000000FF101010EFC0C0C03F000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000F9F9F9068E8E8E74040402FE02021AFF333842FE292E47FF5D64 78FF545D6FFF656A71E8C8C9C938FEFEFE010000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000FEFEFE01CBCBCB342E3439EF394049FE4951 5BFF454D56FF1B2227FF050608FF030303FF030311FF040406FF555556B1EDED ED12000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000CECECE31323232CD010101FE010101FE191E1EFE6B8081FF8DA6 A8FE7C9193FF111414FF000000FF000000FF020302FF212829FF65787AFF859E A1FF8CA5A8FF8FA8AAFF8BA4A6FF88A2A5FF8AA3A5FF8AA3A5FF87A0A3FF829C 9FFF809A9EFF86A0A3FF8CA4A6FF8DA6A8FF8EA8AAFF8AA3A6FF859FA3FF869F A3FF849EA1FF86A0A2FF87A0A3FF859EA1FF859EA1FF87A1A4FF8BA5A7FF8BA4 A7FF8CA5A8FF8BA4A6FF88A2A5FF89A3A6FF88A2A4FF86A0A3FF869FA2FF8AA3 A6FF8AA3A6FF89A2A5FF8BA4A7FF8DA5A7FF87A0A3FF778E90FF1C2121FF0000 00FF020202FD9595956A00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000B9B9B946000000FF000000FF3C4348FFDAF3 FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD5EE FEFFD6EFFFFFD8F2FFFFDBF4FFFFDAF4FFFFD6EFFFFFD5EEFEFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD5EFFFFFD6EFFFFFC8EAFFFFAEDFFFFFAFDFFFFFB0E0FFFFAFDFFEFFB0E0 FFFFACDBFAFF556D7CFF000000FF000000FF000000FF181818E7E2E2E21D0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000D0D0D02F1B1B1BE40000 00FF000000FF000000FF000000FFABABABFFF9F9F9FFA0A0A0FF000000FF0000 00FF050505FFA2A2A2FFFFFFFFFF717171FF000000FF000000FF000000FF0000 00FF000000FF000000FF474747FFEBEBEBFFE9E9E9FF1F1F1FFF000000FF0000 00FF010101FE000000FF6F6F6F90FCFCFC030000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FCFCFC03B4B4B34D0A0A0FFA020209FF070823FE394A75FF6C798BFF7C87 91FE333941FE7B7E8199F2F2F20D000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000F2F2F20D5F6161AF323B42FF444E 57FE525B66FF363E46FF14171FFF05061AFF040304FF030303FF040405FF9393 9370FBFBFB040000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D6D6D6293A3A3AC5000000FF000000FF131617FF697C7CFF8EA6A9FE8CA5 A7FF80979AFF353E40FF1B2022FF30393AFF5C6C6EFF80989AFF839DA0FF819C 9FFF849FA1FF87A1A3FF89A2A5FF89A2A5FF8BA5A7FF8CA5A8FF8BA5A8FF8AA3 A6FF839DA1FF839DA0FF849EA0FF829C9FFF87A1A4FF8CA5A8FF88A0A3FF88A1 A3FF8AA3A6FF86A0A3FF86A1A3FF8CA5A8FF90A9AAFF8BA4A6FF85A0A2FF87A2 A4FF8AA3A6FF8AA4A6FF8CA5A7FF8BA4A6FF8BA4A6FF88A2A3FF87A1A4FF8AA3 A6FF87A1A4FF839C9FFF89A2A5FF8DA7A9FF8DA6A8FF8DA6A9FF576668FF0201 01FE000000FF272727D8DADADA25000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000101010EF000000FF040505FED0E9F8FFD7F0 FFFFD5EEFEFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD5EEFEFFD6EFFFFFD6EF FFFFC0D6E5FF8C9CA6FF69757EFF707D86FFBDD4E2FFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD5EEFFFFD5EEFFFFBEE5FFFFAFDFFFFFB0E0FFFFB0E0FFFFB0E0 FFFFB0E0FFFFB7E8FFFF495D69FF000000FF010101FE000000FF131313ECB8B8 B8479898986798989867C8C8C837ECECEC13FEFEFE0100000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000FCFCFC038383837C000000FF0000 00FF000000FF000000FF2E2E2EFFE9E9E9FFF6F6F6FFA0A0A0FF000000FF0000 00FF2C2C2CFFF9F9F9FFFFFFFFFF232323FF000000FF000000FF000000FF0000 00FF000000FF000000FF474747FFEBEBEBFFF3F3F3FF868686FF000000FF0000 00FF000000FF000000FF090909F6E6E6E6190000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000F9F9 F906B0B0B04F2F2F35D802021CFF02021EFE232834FF8F99A2FF828B95FE6F7C 88FF5F676FEAC8C8C837FEFEFE01000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000A2A2A15F292F35FF424C 55FF424A53FF454E59FF191F32FF060C55FF060704FF050505FE030302FF2223 2EE1D0D0D030FEFEFE0100000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000D9D9 D9263D3D3DC2000000FF010101FE131818FE627476FF88A2A5FF859FA2FF849E A1FF89A2A5FF849C9EFF809799FF869EA1FF87A2A4FF8CA5A8FF90A7A9FF8FA7 A9FF8BA4A6FF88A1A4FF8EA7A9FF8BA3A7FF86A0A2FF869FA2FF8CA5A7FF8EA8 A9FF8CA5A8FF8AA3A5FF8CA5A7FF8AA3A6FF88A1A4FF89A3A5FF8AA3A6FF8BA4 A6FF8AA3A6FF87A0A2FF829DA0FF85A0A2FF8CA5A7FF8CA5A7FF8BA4A6FF859F A2FF849FA1FF849FA1FF87A2A4FF8BA4A5FF8CA5A7FF8FA8AAFF8BA4A7FF89A2 A4FF859FA2FF88A1A4FF849EA1FF89A2A5FF91AAACFF90A8ABFF8AA2A4FF2D34 35FF000000FF000000FF6565659AFAFAFA050000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000079797986000000FF010101FE82919BFFDBF4FFFFD5EE FEFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD5EEFEFFD6EFFFFFDEF8FFFF7E8C 96FF0E0F10FF000000FF000000FF000000FF282D30FFDFF9FFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD2EDFFFFB4E1FFFFAFDFFFFFB0E0FFFFB0E0 FFFFAFDFFEFFB0E0FFFFB6E7FFFF4D6270FF000000FF010101FE000000FF0000 00FF000000FF000000FF000000FF1F1F1FE076767689E4E4E41B000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000F3F3F30C191919E6000000FF0101 01FE000000FF000000FF939393FFF4F4F4FFF6F6F6FFA0A0A0FF000000FF0000 00FF757575FFFFFFFFFFDEDEDEFF0D0D0DFF000000FF000000FF000000FF0000 00FF000000FF000000FF474747FFEBEBEBFFF5F5F5FFCBCBCBFF1F1F1FFF0000 00FF000000FF000000FF000000FF787878870000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000FBFBFB04A7A7 A75A161615EE040405FF040406FE252A2FFF6D7781FF838D97FF75808AFE6973 7DFF85868684F9F9F90600000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000DFDFDF203B3F43E64851 5BFF404851FE384049FF323B3EFF101952FF061C81FF0A0807FF07070CFE0505 0AFD7A7A7989F6F6F60900000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000E5E5E51A4747 47B8020202FD000000FF131617FE687B7DFE8AA4A6FF87A1A3FF89A2A5FF8CA6 A8FF8EA7A9FF8DA7A9FF8BA4A7FF89A2A5FF89A2A4FF88A1A4FF869FA2FF849E A0FF819C9FFF839DA0FF89A2A5FF8CA5A7FF8CA5A7FF8BA4A6FF829D9FFF849E A1FF8EA8A9FF8FA7A9FF8BA4A6FF87A0A3FF809C9EFF839DA0FF89A2A5FF87A1 A4FF809B9EFF7C9699FF829C9EFF869FA2FF849DA0FF8BA4A7FF8EA7AAFF87A1 A4FF859EA1FF89A2A4FF8DA6A8FF8FA8AAFF8AA3A5FF8AA3A6FF8BA4A6FF8AA2 A6FF8CA5A8FF8FA8AAFF8DA7A9FF8BA5A7FF8EA6A9FF8FA8AAFF8CA4A7FF667B 7DFF0D1010FE000000FF141414EBBBBBBB440000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000E4E4E41B181818E7000000FF262A2DFFC7DFEEFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD4ECFCFF434B50FF0000 00FF000000FF000000FF050607FF101213FF84939DFFD9F3FFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFCBEAFFFFADDFFFFFB0E0FFFFB0E0 FFFFB0E0FFFFAFDFFEFFB0E0FFFFABDAF8FF42545FFF000000FF080A0CFF141A 1DFF000001FF010101FE000000FF000000FF000000FF191919E6CBCBCB340000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000009494946B000000FF010101FE0000 00FF000000FF232323FFCFCFCFFFF5F5F5FFF6F6F6FFA0A0A0FF000000FF0000 00FF535353FFFFFFFFFFFFFFFFFF464646FF000000FF000000FF000000FF0000 00FF000000FF000000FF474747FFEBEBEBFFF5F5F5FFF8F8F8FF595959FF0000 00FF000000FF000000FF000000FF000000FFFBFBFB0400000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FEFEFE01C9C9C9361313 14F2030303FF040403FE0E1012FF536068FF7B888FFF717D89FF727E87FF5D60 62C7E7E7E7180000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000F9F9F9067A7A7C8E3439 40FF404952FF3B444DFF424C53FF0C0E42FF0E1011FF0A0C1AFF05070DFF0509 17FF313A52D3E1E0E01F00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000E8E8E8174C4C4CB30000 00FF000000FF0F1212FE627375FE8CA5A7FF89A2A4FF869FA2FF8AA3A5FF85A0 A3FF839D9FFF849EA1FF89A3A5FF8DA7A9FF8BA3A6FF829C9FFF809B9EFF849D A0FF88A2A4FF89A2A5FF88A1A4FF88A1A3FF87A1A3FF89A2A6FF8EA7A8FF8CA5 A7FF8AA3A5FF8CA5A8FF8AA3A6FF8AA2A5FF88A1A4FF8BA4A6FF8FA8A9FF8EA6 A8FF88A0A2FF869EA0FF89A2A5FF88A1A4FF89A2A4FF859EA1FF87A1A3FF8DA6 A8FF8AA3A7FF8AA3A6FF8DA6A8FF8EA7A9FF89A2A4FF849EA0FF89A2A5FF89A2 A5FF8BA5A8FF8AA4A6FF89A2A4FF86A0A2FF839DA0FF849EA0FF859FA2FF849D A0FF3D4849FF010101FE000000FF525252ADF0F0F00F00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000008E8E8E71020202FD000000FF738089FFD7F0FFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFCBE3F2FF9BAEB9FFB3C8 D6FFD1E9F9FFE2FCFFFFE3FDFFFFE0FAFFFFD6EFFFFFD2EBFBFFD5EEFEFFD8F1 FFFFD7F0FFFFD6F0FFFFD6EFFFFFD5EEFEFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD5EEFEFFD6EFFFFFD4EDFCFFD6EFFFFFD5EEFEFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD5EEFFFFD7EFFFFFBDE5FFFFAEDFFFFFAFDF FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFA9D7F5FFAAD9F6FFB9ECFFFFB8EA FFFFBAEDFFFF94BCD6FF3F505BFF0B0E0FFF010101FE000000FF000000FFBFBF BF40000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000FEFEFE01151515EA000000FF000000FF0000 00FF000000FF656565FFFAFAFAFFF5F5F5FFF6F6F6FFA0A0A0FF000000FF0000 00FF0A0A0AFFCBCBCBFFFBFBFBFFE5E5E5FF111111FF000000FF000000FF0000 00FF000000FF000000FF474747FFEBEBEBFFF4F4F4FFFAFAFAFFBFBFBFFF0909 09FF000000FF000000FF010101FE000000FF7575758A00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000EBEBEB1449494ABC0202 02FF070708FE0A0C0DFF191E22FF414950FF555C64FF6C767EFF50585FEFBCBC BC44FEFEFE010000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000C0C0C0412D31 37EF2B3239FF363D47FF252E3EFF082189FF0C0F42FF07155BFF0A163FFF0808 0BFF1A1A1CEDC7C7C73900000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000E0E0E01F505050AF000000FF0000 00FF121516FE5E7273FE88A2A4FF869FA3FE849FA1FF87A0A3FF859FA2FF87A1 A3FF859EA1FF859EA1FF87A1A3FF87A0A3FF88A1A4FF8CA5A8FF90A9ABFF8DA6 A9FF8CA5A7FF8BA4A6FF89A2A5FF8EA6A9FF8BA4A6FF859FA2FF849EA1FF849D A0FF849FA1FF89A1A4FF86A0A2FF86A0A3FF8AA4A7FF8AA3A5FF8AA4A6FF7990 93FF799092FF8EA7A8FF8DA6A8FF89A3A5FF87A0A3FF849EA1FF87A1A4FF8CA5 A7FF8BA5A7FF86A0A2FF829D9FFF829C9FFF819C9EFF859FA1FF869FA3FF89A2 A5FF88A0A4FF86A0A3FF87A0A3FF839DA0FF809A9EFF829DA0FF869FA2FF89A2 A5FF73888BFF141717FF000000FF0C0C0CF3A8A8A85700000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F3F3F30C373737C8000000FF0E0F10FFBCD2E0FFD6F0FFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD5EEFEFFD6EFFFFFDAF3FFFFDEF8 FFFFDAF3FFFFAABDCAFF7B8A93FF5D686FFF515B61FF535C63FF5E6970FF7381 89FF90A1ACFFB3C8D5FFDAF3FFFFDFF9FFFFD9F3FFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD2EAFBFF616C73FFD9F2FFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD2EDFFFFB3E1FFFFAFDF FFFFB0E0FFFFB0E0FFFFB0E0FFFFAFDFFEFFB0E1FFFFB1E1FFFFAFDFFEFFAFDF FEFFAFDFFEFFB2E3FFFFB8EAFFFF8EB5CFFF2C3840FF010101FE000000FF0B0B 0BF4C7C7C7380000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000009090906F000000FF010101FE000000FF0000 00FF080808FFCACACAFFF9F9F9FFF4F4F4FFF6F6F6FFA0A0A0FF000000FF0000 00FF000000FF565656FFF2F2F2FFFAFAFAFFAAAAAAFF000000FF000000FF0000 00FF000000FF000000FF474747FFEBEBEBFFF5F5F5FFF5F5F5FFFEFEFEFF3D3D 3DFF000000FF000000FF000000FF000000FF171717E8EDEDED12000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000FBFBFB04A1A1A2610B0A0BF60F11 13FF0E1013FF0B0B0FFF5B646CFF7B8A93FF82919AFE6B7981FE7F82849FEFEF EF10000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000DEDEDE213C3D 40CF13181EFF1C2328FF2B3538FF0A1254FF1A263FFF101114FF06123CFF070B 25FF0A0910FFA5A6A75AFDFDFD02000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000E9E9E916525252AD040404FB000000FF0E10 10FE65797AFE8AA5A6FF8BA4A6FE89A2A5FF86A0A3FF8AA3A6FF8AA3A6FF869F A2FF849EA0FF87A0A3FF859FA2FF839DA0FF869FA2FF89A2A5FF859FA1FF87A1 A3FF8BA4A7FF8DA7A9FF89A2A5FF88A1A4FF8EA7A9FF8EA7A9FF89A2A4FF89A2 A5FF88A1A4FF87A1A3FF89A3A6FF8BA4A7FF8DA5A8FF93ACADFF7E9293FF6174 75FF859EA1FF8BA4A7FF8EA8A9FF92ABACFF90A9ABFF8BA4A7FF859EA1FF829C 9FFF88A2A5FF8FA9ABFF8DA5A7FF859FA1FF819C9FFF819B9FFF86A0A3FF88A1 A4FF87A1A3FF8AA3A6FF8CA5A7FF8CA5A7FF87A1A4FF839EA0FF87A0A3FF8BA4 A7FF8DA6A9FF4B5859FF000000FF000000FF2D2D2DD2E7E7E718000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D4D4D42B000000FF000000FF454D52FFDFF9FFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD5EEFEFFD6EFFFFFE1FBFFFF92A2 ADFF262A2DFF0B0D0EFF010101FF000000FF000000FF000000FF000000FF0000 00FF060607FF0E0F10FF191C1DFF566067FFA8BDC9FFDDF7FFFFD9F3FFFFD6EF FFFFD5EEFEFFD6EFFFFFD6EFFFFFDEF8FFFF080809FFABBFCCFFD7F0FFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD5EEFFFFD6EFFFFFC3E7FFFFB0E0 FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0 FFFFB0E0FFFFAFDFFEFFAFDFFEFFB1E1FFFFA2CFEBFF2B373EFF010101FE0000 00FF3B3B3BC4F3F3F30C00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000FEFEFE011D1D1DE2000000FF000000FF000000FF0000 00FF484848FFFFFFFFFFF5F5F5FFF5F5F5FFF6F6F6FFA0A0A0FF000000FF0000 00FF000000FF080808FFB2B2B2FFF6F6F6FFEDEDEDFF595959FF000000FF0000 00FF000000FF000000FF474747FFEBEBEBFFF5F5F5FFF4F4F4FFF9F9F9FFC2C2 C2FF000000FF000000FF000000FF010101FE040404FB8585857A000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000F2F2F20D595958AA030314FF1519 1CFF161A21FF191E23FF7B8790FF556874FF85939CFF6A7176E9C6C6C639FDFD FD02000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000E9E9E9164849 49BC13171DFF232C33FF363D46FF373E42FF101627FF10151BFF090705FF0908 10FE0D0D0CFF7777778EFBFBFB04000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000E8E8E8175F5F5FA0000000FF000000FF0B0E0EFE5667 69FE859FA0FF88A2A4FF869FA2FF849EA1FF88A2A4FF859FA2FF89A2A5FF8AA3 A6FF89A2A5FF87A1A4FF89A1A4FF89A2A5FF86A0A3FF859EA1FF86A0A3FF8CA5 A7FF8DA7A8FF8CA5A8FF89A2A5FF859FA1FF86A0A2FF869FA2FF88A1A3FF8EA7 A9FF91A9ABFF8AA3A6FF859FA2FF849EA0FF839DA0FF6C8284FF505F61FF88A1 A4FF87A1A4FF88A2A4FF89A3A5FF89A3A6FF8AA3A6FF8AA4A7FF89A2A4FF8AA3 A5FF8BA4A6FF8BA3A6FF8EA6A8FF8CA5A7FF8DA6A8FF8EA7A8FF8CA5A7FF859F A1FF849EA1FF87A0A3FF8AA3A5FF91A9AAFF91AAACFF8EA6A8FF8CA5A6FF8BA4 A6FF86A0A3FF789194FF222929FE000000FF000000FF7D7D7D82000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007171718E000000FF010101FEA2B5C0FFDAF3FFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD5EEFEFFD6EFFFFFD6EFFFFFB7CCDAFF31373BFF0000 00FF000000FF020202FF0C0C0CFF131313FF191919FF1F1F1FFF2A2A2AFF2727 27FF1B1B1BFF131313FF090909FF000000FF000000FF191C1EFF7F8E97FFC1D8 E6FFD1E9F9FFD8F1FFFFD6EFFFFFDFF9FFFF2A2F31FF66737AFFD6EFFFFFD5EE FEFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD1EDFFFFB3E1 FFFFAFDFFFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0 FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFB1E1FFFF86ABC3FF080A0CFF0101 01FE000000FFBCBCBC4300000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000099999966070707F8010101FE000000FF000000FF0000 00FFCCCCCCFFF8F8F8FFF5F5F5FFF5F5F5FFF6F6F6FFA0A0A0FF000000FF0000 00FF000000FF000000FF3F3F3FFFE9E9E9FFF6F6F6FFC7C7C7FF191919FF0000 00FF000000FF000000FF474747FFEBEBEBFFF5F5F5FFF5F5F5FFF4F4F4FFFFFF FFFF363636FF000000FF000000FF000000FF000000FF383838C7ECECEC130000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000E0E0E01F363635CD030857FF0D10 35FF1B2125FF646E76FF6D7984FF4C5D68FE70808CFF7576779DF7F7F7080000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000EAEAEA155153 56B8181D25FF1E262EFF2F3840FF434D57FF262C36FF090B24FF090B1CFF090D 23FF0A1434FF6566689FFAFAFA05000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000ECECEC136060609F020202FD000000FF070909FF546365FE8CA5 A6FF90A9A9FE8FA8AAFF89A2A5FF89A1A4FF8AA3A6FF87A0A4FF87A1A3FF8BA4 A7FF8DA6A8FF8CA4A7FF8AA3A6FF8CA5A7FF8CA5A7FF8AA3A6FF89A2A5FF88A1 A4FF87A1A3FF8AA3A5FF8DA6A8FF8DA6A9FF8BA4A6FF8CA5A8FF8DA6A8FF8DA6 A8FF89A3A5FF88A2A4FF8BA4A7FF8CA6A9FF728789FF3F4B4CFF758C8EFF849F A1FF87A0A3FF89A3A6FF8AA3A6FF88A2A4FF859FA2FF87A1A4FF8AA2A6FF89A2 A5FF88A2A4FF849FA2FF849EA1FF88A1A5FF90A8ABFF8EA7A9FF89A3A6FF8CA5 A8FF8CA5A7FF89A3A6FF87A0A4FF819DA0FF86A0A3FF8FA7A9FF8CA6A8FF839E A0FF859EA2FF89A3A5FF627476FF08090AFE000000FF1B1B1BE4C8C8C8370000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000101010EF000000FF0F1112FFDEF8FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD5EEFEFFD9F3FFFFD2EAFAFF6D7A82FF090A0BFF000000FF2323 23FF656565FF969696FFBFBFBFFFE1E1E1FFFAFAFAFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFDEDEDEFFB3B3B3FF868686FF575757FF212121FF000000FF0002 03FF475055FF8C9CA7FFD1E9F9FFDDF6FFFF2F3539FF1E2224FFCAE2F1FFD5EE FEFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD5EEFFFFD7EFFFFFC0E6 FFFFAFDFFFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0 FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFB7E9FFFF324048FF0101 01FE000000FF3F3F3FC000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000F4F4F40B404040BF000000FF000000FF000000FF000000FF4444 44FFFFFFFFFFF4F4F4FFF5F5F5FFF5F5F5FFF6F6F6FFA0A0A0FF000000FF0000 00FF000000FF000000FF000000FF9B9B9BFFFAFAFAFFFAFAFAFF787878FF0101 01FF000000FF000000FF474747FFEBEBEBFFF5F5F5FFF5F5F5FFF5F5F5FFF6F6 F6FFB9B9B9FF000000FF000000FF000000FF000000FF050505FAAEAEAE510000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000BCBCBB44191824EC03086BFF0505 25FF2E356FFF586670FF667580FF5E6D79FF565F64F4C8C8C837000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000E4E4E41B4244 48C9181D27FF1E2630FF293038FF353D45FF343C44FF101318FF0C0D12FF0405 09FF04060DFF6666679FF8F8F807000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000EFEFEF106565659A050505FA000000FF080A09FE536466FE8CA5A8FF8FA8 A9FE8AA4A5FF849EA1FF85A0A3FF89A2A5FF88A1A4FF88A1A4FF859FA2FF89A3 A5FF8EA7A9FF8CA5A8FF89A1A4FF88A1A4FF88A1A3FF86A0A2FF8CA5A7FF8CA5 A7FF859FA2FF819C9FFF849FA1FF87A1A4FF89A2A5FF8BA4A7FF8CA5A7FF859E A2FF829C9FFF86A0A3FF8BA5A8FF74898BFF252D2EFF687B7DFF86A0A2FF8BA4 A6FF91A8AAFF8FA7A8FF8CA6A8FF89A2A4FF89A2A4FF89A3A4FF8DA6A8FF8DA6 A8FF859FA2FF88A1A4FF89A2A5FF89A3A6FF87A2A4FF85A0A3FF89A3A6FF8FA9 ABFF8EA8AAFF8DA7A9FF8AA3A6FF859FA2FF86A0A2FF88A1A4FF859FA2FF8AA2 A5FF8BA4A6FF8CA6A8FF859DA0FF333D3EFF010101FE020202FD6161619EF5F5 F50A000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000D0D0 D02F000000FF010101FE5E6970FFDBF5FFFFD5EEFEFFD5EEFEFFD7F1FFFFD5EE FEFFD5EEFEFFD7F1FFFFBED4E3FF272C2FFF000000FF0B0B0AFFA5A5A5FFEEEE EEFFFCFCFCFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFEFEFFFEFE FEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8FFECECECFFD8D8D8FF8787 87FF292929FF000000FF15181AFF191D1FFF010101FF000000FF91A2ADFFD8F1 FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD5EFFFFFD6EFFFFFD5EF FFFFAFDFFFFFAFDFFFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0 FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFAFDFFEFFB4E5FFFF7B9CB2FF0000 00FF000000FF000000FF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000B8B8B847080808F7000000FF000000FF000000FF000000FFC5C5 C5FFF6F6F6FFF5F5F5FFF5F5F5FFF5F5F5FFF6F6F6FFA0A0A0FF000000FF0000 00FF000000FF000000FF000000FF0B0B0BFFE9E9E9FFF8F8F8FFEDEDEDFF2929 29FF000000FF000000FF484848FFEBEBEBFFF5F5F5FFF5F5F5FFF5F5F5FFF4F4 F4FFEDEDEDFF3A3A3AFF000000FF000000FF010101FE000000FF515151AEF9F9 F906000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000F3F3F30C616161A3040403FF030332FE0304 37FF11144BFF535F6BFF566774FE63717FFF626466B1F2F2F20D000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000E0E0E01F3B3C 41CF171D25FF1B202AFF242D35FF2D373EFF232C34FF0E1011FF0E0E0EFF0606 06FF040404FF505051B6F1F1F10E000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000F4F4 F40B7272728D040404FB000000FF070808FE4D5B5CFF8BA3A5FF86A0A3FF839D A0FF819B9EFF809B9EFF88A1A4FF90A9AAFF90A9ABFF8DA6A8FF8EA7A9FF8AA4 A6FF87A0A3FF8BA5A7FF8CA5A8FF88A2A4FF859FA2FF88A1A4FF869FA3FF829C 9FFF768E90FF627779FF5D7072FF73898BFF8AA3A6FF8DA6A9FF8EA7A9FF8EA7 A9FF8BA4A7FF87A0A3FF6B8184FF1E2323FF4A5859FF8FA9ACFF8CA5A8FF8EA8 A9FF8EA7A9FF89A2A4FF829C9EFF859FA2FF8AA3A6FF88A1A4FF88A1A4FF89A2 A5FF849FA1FF839DA0FF7F9799FF6A7E80FF546466FF4A585AFF475557FF5564 66FF677C7EFF7C9497FF89A2A4FF8DA6A9FF8AA3A6FF8BA3A7FF8BA4A6FF8FA8 AAFF91A9AAFF8DA6A8FF8DA6A8FF6C7F81FF0E1011FF000000FF101010EFB7B7 B748000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000008383 837C000000FF000000FFA6BAC6FFD7F0FFFFD6EFFFFFD9F2FFFF9FB2BEFFD8F1 FFFFD8F1FFFFB3C8D6FF15181AFF090808FF535353FFF1F1F1FFFFFFFFFFFEFE FEFFFFFFFFFFFEFEFEFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFEFEFFFFFFFFFFFEFEFEFFFFFFFFFFFFFF FFFFFFFFFFFFF2F2F2FF737373FF050505FF000000FF000000FF24282BFFDEF8 FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD5EFFFFFD6EF FFFFC2E6FFFFAEDFFFFFAFDFFFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0 FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFB1E2FFFFA0CCE9FF0000 00FF010101FE000000FFDDDDDD22000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F8F8F8076060609F000000FF000000FF000000FF000000FF484848FFEBEB EBFFF4F4F4FFF5F5F5FFF4F4F4FFF6F6F6FFFFFFFFFFA0A0A0FF000000FF0000 00FF000000FF000000FF000000FF000000FF848484FFFEFEFEFFFCFCFCFFA7A7 A7FF000000FF000000FF3F3F3FFFF5F5F5FFFAFAFAFFF4F4F4FFF4F4F4FFF5F5 F5FFF5F5F5FF9B9B9BFF000000FF000000FF000000FF000000FF000000FFD8D8 D827000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000C4C4C43C060606FF040317FF060618FE0405 55FF171A28FF1C212DFF3D4A55FF3E454BFF96979871FCFCFC03000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000DFDFDF20373A 3BD111171BFF181E25FF2A333BFF2F363EFF1D2227FF0E1216FF0F1012FF0E0F 12FF0E0F11FF212224EAE1E1E11E000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000F0F0F00F6E6E 6E91020202FD000000FF070808FE4A5759FF88A1A3FF8FA7AAFF8BA5A7FF88A2 A4FF8CA5A7FF8DA6A8FF8AA3A6FF8BA3A6FF8BA4A6FF8CA6A8FF8DA5A8FF87A1 A3FF839EA0FF849DA0FF87A1A3FF8AA3A6FF8CA5A8FF8DA7A8FF6D8183FF3A46 48FF191E1FFF080909FF040404FF2B3234FF829B9EFF86A0A2FF849EA0FF859F A2FF8AA4A6FF6F8487FF1F2425FF414C4EFF89A2A5FF88A1A4FF859FA2FF86A0 A2FF89A3A6FF8BA4A6FF89A3A5FF87A0A3FF87A0A3FF87A1A4FF86A0A3FF8BA5 A8FF7B9192FF414C4EFF141717FF010101FF000000FF000000FF000000FF0000 00FF020203FF161B1BFF424E4FFF788D8FFF8BA5A9FF89A3A5FF8DA5A8FF8AA3 A5FF87A1A4FF8AA3A7FF8DA7A9FF87A1A4FF404D4EFF000000FF000000FF4040 40BFF0F0F00F0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000003E3E 3EC1000000FF0C0E0FFFC4DBE9FFD5EEFEFFD8F1FFFFBFD6E4FF070708FFD4ED FDFF99ABB7FF08090AFF4A4949FFC4C4C4FFFFFFFFFFFFFFFFFFFEFEFEFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFF4F4F4FFE1E1E1FFD9D9D9FFD8D8D8FFDDDD DDFFE7E7E7FFF5F5F5FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFEFEFEFFFFFFFFFFFFFFFFFF1B1B1BFF000000FF000000FF000000FFDCF6 FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD1EDFFFFB1E0FFFFAFDFFFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0 FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFB1E1FFFFA2CFECFF0000 00FF010101FE000000FFDDDDDD22000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000E1E1E11E000000FF000000FF000000FF000000FF000000FFA2A2A2FFF5F5 F5FFF4F4F4FFF5F5F5FFF6F6F6FFB9B9B9FF191919FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF515151FFFFFFFFFFF6F6F6FFF2F2 F2FF000000FF000000FF000000FF000000FF6E6E6EFFEFEFEFFFF6F6F6FFF5F5 F5FFF5F5F5FFD6D6D6FF2B2B2BFF000000FF000000FF010101FE000000FF5252 52AD000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000FAFAFA057879798D010103FF05060FFE0C0D08FF0304 44FF0B0E5CFF070F8DFF0C115FFF22283DF4C2C3C34000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000E2E2E21D3C3D 41CF14191FFF191F27FF262E36FF2D3338FF2E3D59FF24292FFF0D0F12FF1013 19FF101218FF0E0F13FFC9C9C936000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000F7F7F708797979860A0A 0AF5000000FF030304FE485656FF819A9CFF819C9FFF839DA0FF87A0A3FF88A2 A4FF8BA5A7FF8DA6A9FF8CA6A8FF8CA5A7FF88A2A4FF88A1A4FF87A1A4FF85A0 A2FF87A0A3FF8DA7A8FF8EA7A9FF8AA4A6FF859FA3FF4C5C5DFF0F1212FF0101 01FF000000FF000000FF000000FF384244FF89A2A5FF88A2A5FF849EA1FF839E A0FF738A8DFF1A2020FF272E2FFF829B9DFF90A9AAFF8EA7A9FF87A0A3FF86A1 A4FF87A1A4FF8AA2A4FF8AA3A5FF859EA1FF849EA1FF89A2A5FF87A2A4FF5D70 72FF0D1010FF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF0E1212FF596A6CFF8AA4A7FF89A2A5FF8BA3 A6FF8BA5A7FF8CA5A7FF8AA4A7FF8BA5A7FF7C9394FF191E1EFE000000FF0000 00FF8D8D8D720000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000001D1D 1DE2000000FF2F3438FFCAE2F1FFD5EEFEFFDFF9FFFF5C676EFF000000FF1619 1CFF0E1010FFB0B0B0FFFAFAFAFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFBEBEBEFF6C6C6CFF232222FF100F0FFF0C0B0BFF0A0909FF0A0A09FF0D0C 0CFF10100FFF151515FF1A1A1AFF363636FF636363FF959595FFC6C6C6FFF9F9 F9FFFFFFFFFFFFFFFFFF818181FF030303FF000000FF000000FF50595FFFDCF6 FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD5EE FFFFD4EEFFFFBCE4FFFFAFDFFFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0 FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFB3E4FFFF81A5BCFF0000 00FF000000FF000000FF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00006262629D000000FF010101FE000000FF000000FF2F2F2FFFDDDDDDFFF5F5 F5FFF5F5F5FFF6F6F6FF9A9A9AFF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF616161FFFFFFFFFFF5F5F5FFFFFF FFFF000000FF000000FF000000FF000000FF000000FF4D4D4DFFE9E9E9FFF5F5 F5FFF5F5F5FFFDFDFDFF6F6F6FFF010101FF000000FF000000FF000000FF0000 00FFDDDDDD220000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000FEFEFE01DBDBDB242A2929DD020202FF0A0A0BFF0E0F13FF1C21 22FF3C4144FF1F2450FF161E5BFF474A49D3DBDBDB2400000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000EDEDED125457 57B1141A1DFF13181EFF141C23FF263037FF212C42FF262D33FF111418FF0C0C 0CFF0E0F10FF101115FFC2C2C23D000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000FBFBFB048B8B8B74070707F80000 00FF050606FE404C4DFF859EA0FF8AA3A5FF88A2A4FF89A3A5FF8CA5A7FF88A2 A5FF839DA0FF859FA2FF87A0A3FF88A1A4FF88A2A5FF86A0A3FF859FA2FF8CA5 A7FF8FA8A9FF8AA4A7FF86A0A3FF799293FF394445FF000000FF000000FF0000 00FF000000FF000000FF242A2BFF7D9395FF8CA5A8FF859FA2FF859FA2FF8097 9AFF1E2424FF090C0CFF6E8284FF89A3A6FF859FA1FF859FA2FF8CA6A9FF90A9 AAFF859DA1FF829C9FFF8BA4A7FF8DA7A9FF86A1A4FF869FA2FF5C6D6EFF0406 06FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF010101FF495859FF829A9EFF8CA6 A8FF8BA5A8FF87A0A3FF859FA3FF8EA7A9FF94ACAEFF5B6B6DFF030505FE0000 00FF242424DBD1D1D12E00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000E5E5E51A1515 15EA000000FF4C565BFFD1EAF9FFD6EFFFFFD0E8F7FF131618FF000000FF4848 48FFF7F7F7FFFFFFFFFFFFFFFFFFF9F9F9FFE9E9E9FFB7B6B6FF535454FF080A 0AFF0A0C0EFF343A3EFF69757DFF8898A2FF93A4AFFF92A3ADFF8898A2FF7887 8FFF647079FF4D565BFF32383CFF181B1DFF101214FF080A0BFF000102FF0000 00FF080807FF000000FF000000FF000000FF000000FF3F464BFFD2EAFAFFD5EE FEFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFC6E9FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0 FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFB6E8FFFF3D4E58FF0101 01FE000000FF444444BB00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000E1E1 E11E000000FF000000FF000000FF000000FF030303FF7A7A7AFFFCFCFCFFF4F4 F4FFF5F5F5FFAFAFAFFF0C0C0CFF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF8F8F8FFFFDFDFDFFF6F6F6FFEBEB EBFF000000FF000000FF000000FF000000FF000000FF000000FF5D5D5DFFF4F4 F4FFF4F4F4FFF8F8F8FFD5D5D5FF0B0B0BFF000000FF000000FF010101FE0000 00FF4F4F4FB00000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000FBFBFB049797976C060606FA040404FE070708FF080809FF272C 32FF474D55FF383D48FF181C2FFF4D4E58BAEAEAEA1500000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000F1F1F10E5E5F 60A813191EFF1B2229FF151B29FF303844FF2D3643FF2F383FFF1F262EFF1519 1EFF0F1013FF0E1015FFB5B5B54A000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000FCFCFC039191916E0B0B0BF4000000FF0101 01FE3A4547FF829A9CFF8CA6A8FF8AA3A5FF8BA4A7FF87A1A3FF88A2A4FF8CA5 A7FF8AA3A6FF87A1A3FF849EA1FF849FA2FF8BA5A7FF8CA5A8FF89A2A5FF87A0 A3FF88A1A4FF859FA2FF819A9CFF3C4748FF010101FF000000FF000000FF0000 00FF000000FF2B3334FF7E9495FF92ABACFF87A0A3FF86A1A3FF839B9EFF2F38 39FF000000FF536163FF8EA7AAFF88A1A4FF8BA4A7FF8BA4A6FF8AA3A6FF89A2 A5FF86A0A3FF88A2A5FF8BA4A6FF859FA2FF88A3A5FF6D8284FF0A0C0CFF0000 00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF000000FF000000FF495858FF89A3 A7FF8BA4A7FF8DA6A8FF8DA5A7FF89A2A4FF86A0A2FF80999BFF2C3435FF0101 01FE020202FD6E6E6E91FAFAFA05000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000CECECE311010 10EF000000FF67737AFFD7F0FFFFD7F1FFFF90A0ABFF050606FF080808FFBCBC BCFFFFFFFFFFEEEEEEFF9F9F9EFF504F4EFF1E1E1FFF31393DFF6D7B84FFA4B8 C4FFD1EAFAFFE1FBFFFFDEF7FFFFDCF5FFFFDBF4FFFFDBF4FFFFDBF5FFFFDDF6 FFFFDEF8FFFFDFFAFFFFE1FCFFFFE0FAFFFFCEE6F5FFB9CFDDFFA3B6C3FF8D9D A8FF586269FF000000FF000000FF000000FF32383CFFC7DEEDFFD7F0FFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD0ECFFFFB2E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0 FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFB1E1FFFF8DB3CCFF07090BFF0000 00FF050505FAC8C8C83700000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000005C5C 5CA3000000FF010101FE000000FF000000FF0C0C0CFFDEDEDEFFF7F7F7FFF5F5 F5FFE1E1E1FF151515FF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FFC4C4C4FFF9F9F9FFF9F9F9FFC9C9 C9FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF8E8E 8EFFF9F9F9FFF5F5F5FFFFFFFFFF555555FF000000FF000000FF000000FF0000 00FF101010EFD6D6D62900000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000EAEAEA15525252B2040404FF050505FF090A0BFF0E0E11FF0B0F 14FF141831FF333944FF343B46FF696B6DA1F2F2F20D00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000F2F2F20D5E60 62A8151A1FFF131B29FF181C20FF181E34FF373C43FF464E59FF232B34FF1B1F 28FF141A20FF0F1319FF8C8C8C78FEFEFE010000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000FDFDFD029595956A101010EF000000FF010101FE3C47 48FE80999CFF8BA4A7FF8CA6A8FF8DA6A8FF8EA7A8FF8EA6A9FF8BA5A7FF86A1 A3FF85A0A2FF8AA3A6FF88A2A5FF839DA0FF829C9FFF89A2A5FF8DA7A9FF8AA3 A7FF8BA4A7FF90A9ABFF6E8284FF0A0D0DFF000000FF000000FF000000FF0A0C 0CFF495758FF799294FF849DA0FF8AA4A6FF8FA8AAFF8FA8AAFF2D3536FF0000 00FF374042FF849EA0FF849EA1FF87A1A4FF89A3A5FF8AA4A7FF8EA7AAFF8CA5 A7FF8BA4A7FF8DA6A8FF89A2A5FF8AA4A6FF879FA1FF161B1BFF000000FF0000 00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF040606FF313B3CFF0F1213FF000000FF000000FF010101FF5667 69FF89A4A6FF8AA2A5FF88A1A4FF849EA1FF87A1A3FF8DA7A8FF6B7D7FFF0C0E 0EFE000000FF161616E9C4C4C43B000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000B6B6B6490A0A 0AF5020202FF7F8E97FFD8F1FFFFD3ECFCFF576168FF000000FF010101FF4A4A 4AFF5D5D5DFF0C0B0AFF1A1C1EFF7A8891FFC0D7E5FFCEE6F6FFD7F0FFFFD7F0 FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD5EEFEFFD6EFFFFFD6EFFFFFD6EFFFFFD7F0FFFFD8F1 FFFFDBF4FFFF2D3235FF000000FF272C2FFFCFE7F7FFD7F0FFFFD5EEFEFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD7EFFFFFB7E3FFFFAFDFFFFFB0E0FFFFB0E0FFFFAFDFFEFFB0E0 FFFFB3E4FFFFAFDFFEFFAFDFFEFFB0E0FFFFA8D5F3FF2F3B44FF000000FF0000 00FF000000FFC9C9C93600000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000DEDEDE210D0D 0DF2010101FE000000FF000000FF000000FF636363FFFFFFFFFFF4F4F4FFF9F9 F9FF888888FF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FFFBFBFBFFF5F5F5FFFBFBFBFFA8A8 A8FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0A0A 0AFFFFFFFFFFF5F5F5FFF7F7F7FFDDDDDDFF000000FF000000FF000000FF0000 00FF020202FD6D6D6D9200000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000BEBEBE42121212F2040404FF080807FF111315FF11161BFF353D 46FF2E333BFF373C46FF272C34FE6F707198F5F5F50A00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000F0F0F00F5E5F 61A9161A20FF0D143BFF13182EFF080A15FF181F2BFF252B33FF13171DFF0F10 13FF101317FF0D0E0FFF555556B1F7F7F7080000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000FEFEFE01A9A9A956111111EE000000FF020303FE384242FF849C 9EFF8BA4A6FF88A1A4FF87A1A4FF8CA5A7FF8CA4A6FF859EA1FF819B9EFF839D A0FF88A1A3FF8BA4A6FF8EA7A8FF8BA4A6FF86A0A2FF87A0A2FF8AA3A5FF8AA3 A5FF859EA1FF859EA1FF697F80FF171A1AFF0B0D0EFF191E1EFF3A4546FF7187 89FF8EA8AAFF8CA6A8FF849FA2FF839EA0FF859DA0FF384243FF000000FF1F25 25FF7E9598FF87A0A3FF8AA3A5FF8BA4A6FF819C9FFF839DA0FF88A0A3FF86A0 A2FF8BA3A6FF8CA4A6FF87A0A2FF8AA4A7FF414C4FFF000000FF000000FF090A 0AFF0D1011FF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF101313FF7B9395FF738A8CFF222A2BFF000000FF000000FF0C0F 0FFF6C8286FF819C9FFF809A9EFF839DA0FF86A0A2FF8AA3A6FF859FA1FF3640 42FF000000FF000000FF4D4D4DB2F3F3F30C0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000A2A2A25D0505 05FA070708FF94A5B0FFD7F0FFFFD5EEFEFF68757DFF000000FF000000FF0000 00FF1F2426FF92A3ADFFDDF7FFFFDAF3FFFFD5EEFEFFD5EEFEFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFE0FAFFFF0E1010FF202427FFCAE1F0FFD5EEFEFFD5EEFEFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD7EFFFFFC4E8FFFFAFDFFFFFB0E0FFFFB0E0FFFFB0E0FFFFA9D6 F4FF648091FFACDBF9FFB0E0FFFFB0E0FFFFA6D4F1FF313F47FF0C0F11FF0101 01FE000000FF030303FCE8E8E817000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000007575758A0303 03FC000000FF000000FF000000FF000000FFDFDFDFFFF7F7F7FFF5F5F5FFFAFA FAFF767676FF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF4C4C4CFFFCFCFCFFF4F4F4FFFEFEFEFF8888 88FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FFFFFFFFFFF5F5F5FFF4F4F4FFFFFFFFFF545454FF000000FF000000FF0000 00FF000000FF272727D8DDDDDD22000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FAFAFA057575748E030303FF080707FE080909FF0B0C0DFF181C21FF3239 42FF464D57FF282F39FF252C34FE77797B94F6F6F60900000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000F0F0F00F5B5C 5DAC11172AFF14171DFF131625FF0D153FFF101844FF0E1230FF0D0E1EFF0C0D 1DFF090904FF08080CFF323237D3E3E3E31C0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000A4A4A45B181818E7000000FF010101FE323C3CFF7E9597FF8CA6 A8FF8BA5A7FF8AA3A5FF87A1A3FF859FA1FF869FA3FF88A2A5FF88A2A5FF89A2 A5FF8AA2A6FF89A3A6FF8FA7A9FF91A9ABFF8FA7A9FF89A2A5FF859FA1FF8AA3 A6FF8CA5A6FF8DA5A7FF8EA5A7FF778C8EFF6C8082FF788F92FF849EA0FF87A1 A3FF89A2A5FF8DA7A8FF91A9ABFF8BA4A6FF3C4749FF000000FF060707FF5C6E 70FF849FA1FF88A2A5FF89A3A5FF89A2A5FF8BA5A7FF8FA8AAFF8AA3A6FF859F A1FF839DA0FF819C9FFF849FA2FF758B8DFF0C0F0FFF000000FF0C0E0EFF6071 73FF6C8082FF111516FF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF1C2223FF849EA0FF8AA3A6FF748B8EFF1E2425FF000000FF0000 00FF343E3FFF829B9EFF87A0A3FF8DA6A9FF8EA7A9FF89A3A5FF89A2A5FF7389 8CFF141818FE000000FF050505FA979797680000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000009494946B0202 02FD0A0B0CFFA3B6C2FFD7F0FFFFD6EFFFFFC8E0EEFF505A60FF000000FF0F10 11FFC7DEEDFFDBF5FFFFD6EFFFFFD5EEFEFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD7F0 FFFFCDE6F5FF090A0AFFB3C9D6FFD7F1FFFFD5EEFEFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD1EDFFFFADDFFFFFB0E0FFFFB0E0FFFFB1E1FFFF80A4 BAFF000000FF7FA2B9FFB3E4FFFFB5E7FFFFB0E1FFFFB2E3FFFF7B9CB2FF0000 00FF010101FE000000FF353535CAF9F9F9060000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000E0E0E01F2A2A2AD50000 00FF000000FF000000FF000000FF626262FFFDFDFDFFF4F4F4FFF5F5F5FFF7F7 F7FFA9A9A9FF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FFB6B6B6FFF7F7F7FFF5F5F5FFFFFFFFFF7171 71FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF3636 36FFFDFDFDFFF5F5F5FFF5F5F5FFF5F5F5FFCECECEFF000000FF000000FF0000 00FF000000FF000000FF9A9A9A65000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000EBEBEB14333334D2050505FF080808FE0A0A0BFF080807FF080808FF1214 18FF3C424CFF343B44FF1F262DFD7E7F8189F9F9F90600000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000EDEDED125354 54B411182DFF0C1132FF111428FF060B4CFF0C0F2FFF0A1051FF0D0D17FF0A0C 2AFF040F59FF06071EFF0F0F19F3B0B0B053FDFDFD0200000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000B0B0B04F181818E7000000FF000000FF30393AFE81999AFF8DA6A9FF89A3 A6FF86A0A3FF859EA1FF88A1A4FF8AA3A6FF89A3A6FF89A1A4FF89A2A5FF8BA4 A7FF8BA4A7FF8DA6A8FF8CA5A8FF8AA3A6FF89A3A5FF8AA3A6FF8AA4A6FF8EA8 AAFF8EA7AAFF8EA5A8FF8FA8AAFF8EA7A9FF8DA6A8FF89A2A5FF87A0A3FF88A1 A4FF8AA2A5FF8BA4A7FF89A4A6FF475556FF010101FF000000FF3D4949FF88A2 A5FF89A1A4FF89A2A5FF89A2A4FF86A0A3FF87A0A3FF88A2A4FF89A2A5FF8CA5 A8FF8CA5A8FF88A1A4FF859FA2FF4A5859FF010202FF010202FF465254FF8EA6 A8FF8FA7A9FF4F5F60FF020303FF000000FF000000FF000000FF000000FF0000 00FF000000FF434F50FF8DA6A9FF8DA6A8FF8CA4A8FF697E80FF0E1111FF0000 00FF050606FF758C8EFF8EA8AAFF8FA8A9FF8BA5A7FF87A1A3FF8BA4A7FF90A9 ABFF546364FF030303FF000000FF262626D9D9D9D92600000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000008D8D8D720101 01FE0C0E0FFFACC0CDFFD7F0FFFFD5EEFEFFD7F0FFFFD2EBFBFF808E98FF0303 03FFC0D7E5FFD5EEFEFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD5EEFEFFD6EFFFFFD6EFFFFFD5EEFEFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD3ECFCFFC1D8E6FFD7F0FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD7EFFFFFB3E1FFFFAFDFFFFFAFDFFEFFAFDFFEFF4D63 71FF000000FFA7D4F1FFB8EBFFFF627D8EFFAEDDFBFFBAEDFFFF3A4954FF1014 17FF000000FF010101FE020202FD9191916E0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000A1A1A15E000000FF0000 00FF000000FF000000FF000000FFD8D8D8FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFDEDEDEFF000000FF000000FF000000FF000000FF1D1D1DFF1D1D1DFF0000 00FF000000FF000000FF313131FFE8E8E8FFF5F5F5FFF5F5F5FFFFFFFFFF6C6C 6CFF000000FF000000FF323232FF060606FF000000FF000000FF000000FF7373 73FFFAFAFAFFF5F5F5FFF5F5F5FFF4F4F4FFEDEDEDFF535353FF000000FF0000 00FF010101FE000000FF313131CEF4F4F40B0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000CECECE310E0E0EF9050505FF0A0A0AFF0E0F13FF0F0F10FF111317FF3E43 4DFF2F343EFF272D35FF242B31F994949571FAFAFA0500000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000F0F0F00F5D5E 61AB12171DFF14171BFF121619FF121515FF0A0C25FF0A0D2FFF0C0C0FFF0707 10FF060627FF09090AFF0A0A0CFF606060A3F5F5F50A00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000BFBF BF40252525DA000000FF010101FE2B3234FF799093FF8BA4A6FF8AA4A6FF88A1 A4FF87A1A3FF8CA5A8FF8BA5A7FF8AA4A6FF88A1A3FF87A1A4FF8BA4A7FF8EA8 AAFF8CA5A7FF87A0A4FF849DA1FF86A0A3FF8CA5A7FF8EA6A8FF8EA7A9FF88A1 A4FF86A0A3FF85A0A2FF829DA1FF859FA2FF88A2A5FF88A3A6FF8CA6A9FF8BA5 A7FF82999CFF6E8486FF303A3BFF000001FF000000FF23292AFF8AA4A7FF8BA4 A7FF8AA3A6FF8BA4A6FF8FA7A9FF8DA6A8FF89A2A5FF839DA0FF829C9FFF88A1 A4FF8DA5A7FF8EA7A9FF879FA1FF282F30FF000000FF111515FF788F92FF89A2 A4FF8CA5A7FF819A9CFF1C2122FF000000FF000000FF000000FF000000FF0000 00FF020203FF687C7DFF8EA8AAFF8EA7A9FF8DA6A9FF8DA7A9FF526264FF0000 00FF000000FF3E494AFF8FA9ABFF8BA4A7FF849EA0FF819B9FFF87A0A3FF8AA3 A6FF82999BFF283030FF010101FE030303FC7D7D7D82F9F9F906000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000008B8B8B740000 00FF0E0F10FFB1C6D3FFD7F0FFFFD6EFFFFFD6EFFFFFD5EEFEFFD9F2FFFF91A2 ADFFC5DBEAFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD2EAFAFFBDD4E2FFBBD1DFFFC9E0EFFFD6F0FFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD5EEFEFFD6EFFFFFD5EEFEFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD7EFFFFFBEE5FFFFAEDFFFFFB1E1FFFF88ADC5FF0000 00FF516675FFB6E8FFFF8CB3CBFF000101FFB3E3FFFF9CC7E3FF050708FF6E8D A1FF20282EFF000000FF000000FF1D1D1DE2E7E7E71800000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000F3F3F30C373737C8000000FF0101 01FE000000FF000000FF5C5C5CFFEEEEEEFFF4F4F4FFF5F5F5FFF5F5F5FFF5F5 F5FFE6E6E6FF1C1C1CFF000000FF000000FF000000FF545454FF444444FF0000 00FF000000FF010101FFA7A7A7FFF5F5F5FFF5F5F5FFF5F5F5FFFEFEFEFF8787 87FF000000FF0C0C0CFF868686FF0D0D0DFF000000FF000000FF000000FFAAAA AAFFF7F7F7FFF5F5F5FFF5F5F5FFF5F5F5FFF6F6F6FFAAAAAAFF010101FF0000 00FF000000FF000000FF000000FFBDBDBD420000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00009D9D9D66050505FF030202FF0E1014FF0E1221FF21272BFF2E333AFF2D33 3BFF2E363EFF2A3039FF23282FF89C9C9D69FCFCFC0300000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000F0F0F00F5A5B 5DAC0E1013FF101116FF111419FF181D25FF161B20FF0D1018FF0B0C17FF0809 15FF0D0D0DFF0C0C0EFF12151AFF525353B5ECECEC1300000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000C5C5C53A2323 23DC000000FF000000FF242A2CFF7A8F91FF8AA4A7FF829C9EFF829C9FFF849E A1FF849FA1FF86A0A3FF88A2A4FF8AA4A6FF8BA4A7FF8CA5A7FF8EA7AAFF8FA9 ABFF8CA6A8FF859FA2FF839DA1FF839EA1FF85A0A4FF89A5A7FF8AA6A9FF8FAA ADFF8EABADFF93AFB2FF93AFB3FF8AA4A7FF81989BFF74888AFF607172FF3F4A 4CFF1B2021FF060707FF000000FF000000FF040505FF6D8183FF8BA3A6FF8AA3 A5FF89A2A5FF87A0A3FF8AA3A6FF8DA6A8FF8BA5A7FF8CA5A7FF8DA6A8FF89A2 A4FF87A0A3FF89A3A5FF7D9497FF0D100FFF000000FF323D3EFF86A0A4FF7F9A 9EFF849EA1FF8FA8ABFF6A7D7FFF0B0E0EFF000000FF000000FF000000FF0000 00FF101515FF81999CFF89A2A5FF859EA2FF869FA2FF8DA7A8FF839B9DFF191D 1EFF000000FF040505FF71888AFF859FA2FF849EA1FF8BA5A7FF8DA6A9FF89A2 A5FF8AA4A6FF627576FF080A0AFF000000FF1B1B1BE4C4C4C43B000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000008F8F8F700101 01FE0E1011FFB3C8D5FFD6F0FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFDBF4 FFFFD7F0FFFFD5EEFEFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD5EEFEFFDDF7FFFF68747BFF000000FF000000FF485056FFE0FAFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFC8E8FFFFAEDFFFFFB2E2FFFF7DA0B6FF495D 6AFFABDAF8FFAEDDFCFF3C4D58FF34434CFFB7E9FFFF617B8CFF050708FFA1CD EAFF090C0DFF000000FF010101FE000000FF6A6A6A9500000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000BCBCBC43000000FF000000FF0000 00FF000000FF060606FFAFAFAFFFF6F6F6FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFEAEAEAFF3E3E3EFF000000FF000000FF070707FFA8A8A8FF424242FF0000 00FF000000FF686868FFF0F0F0FFF5F5F5FFF5F5F5FFF5F5F5FFF9F9F9FFC2C2 C2FF000000FF0D0D0DFFBFBFBFFF2B2B2BFF000000FF000000FF000000FFD4D4 D4FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFE3E3E3FF383838FF0000 00FF000000FF010101FE000000FF333333CC0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000FCFC FC035E5E5FA6030303FF0B0B0DFE11151BFF313841FF525B66FF78838FFF373B 43FF1D242AFF1F282FFF1A2026FA98999971FCFCFC0300000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000F1F1F10E6061 62A6101519FF14181EFF191D25FF1A1F28FF1C2029FF191D25FF13161BFF0B0B 0CFF0D0E10FF111418FF11161AFF454749C3E6E6E61900000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000EEEEEE11434343BC0000 00FF000000FF212829FE728A8CFF89A3A5FF8FA8AAFF90A9ABFF8DA7A9FF8CA7 A9FF90A9ACFF8BA5A8FF8FA9ACFF90AAADFF91ABAEFF92ADAFFF91ACAFFF91AC AFFF8FABAEFF95B0B1FF99B4B7FF96B1B4FF8DA8ABFF859C9DFF798D8EFF6679 7AFF4F5F61FF3B4747FF2E3637FF1D2323FF111414FF080A0AFF010202FF0000 00FF000000FF000000FF000000FF000000FF111415FF789093FF86A0A2FF8BA4 A7FF8AA3A5FF839EA0FF7E999CFF839EA0FF89A2A5FF87A0A3FF859EA1FF87A0 A3FF88A1A3FF86A1A2FF687C7EFF010101FF000000FF5E7275FF88A2A5FF8AA3 A5FF8BA4A7FF89A2A5FF8BA6A8FF4F5C5DFF000000FF000000FF000000FF0000 00FF313B3CFF91AAACFF8CA5A7FF8AA3A5FF8BA4A6FF88A2A5FF89A3A6FF5767 69FF000000FF000000FF455254FF89A4A7FF85A0A2FF88A1A5FF8AA3A6FF8BA5 A7FF87A0A3FF859EA1FF353E3FFF000000FF000000FF515151AEFAFAFA050000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000999999660303 03FC0D0F10FFB0C5D2FFD7F0FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD7F1FFFFC6DDECFF000000FF000000FF000000FF8A99A3FFDBF5FFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD0ECFFFFADDFFFFFAFDFFEFFAFDFFEFFADDC FBFFB2E3FFFF87ACC4FF000000FF8DB3CCFFA8D5F3FF1F282DFF4B606DFF7B9D B2FF1E262CFF090B0DFF010101FE000000FF000000FFCFCFCF30000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000002E2E2ED1000000FF010101FE0000 00FF000000FF3D3D3DFFE9E9E9FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFEDEDEDFF575757FF000000FF000000FF4F4F4FFFE4E4E4FF2D2D2DFF0000 00FF7D7D7DFFE9E9E9FFF7F7F7FFF4F4F4FFF5F5F5FFF5F5F5FFF5F5F5FFF8F8 F8FF4E4E4EFF000000FFB5B5B5FFB3B3B3FF000000FF000000FF000000FFE3E3 E3FFF4F4F4FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFFCFCFCFF848484FF0404 04FF000000FF000000FF010101FE000000FFBABABA4500000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000F4F4 F40B5E5E5FAB040407FF090A21FF11151EFF3E4659FF19276CFF071767FF424A 67FF23282DFF22292FFF2F353EF99798996DFCFCFC0300000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000EBEBEB145151 58B50C0C11FF0E0E12FF11151CFF1A1F27FF1C222BFF151920FF0E1012FF0606 06FF0E1013FF0F1218FF111419FF343739D5DFDFDF2100000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000AAAAAA550C0C0CF30000 00FF242A2CFF7B9396FF8BA7ABFF8BA7A9FF8EA8ABFF93ADB0FF95AFB2FF95B0 B3FF98B4B6FF9CB7BAFF97B3B6FF93B1B4FF9BB8BAFFA5C1C4FFA0BDC0FF9EBC BFFF9CB8BCFF8EA8ABFF6F8384FF566667FF364142FF202728FF191E1FFF181C 1DFF1C2020FF1E2424FF1F2627FF252B2DFF2D3637FF343F40FF374243FF313A 3BFF2B3435FF1B2021FF0C0F10FF010101FF040606FF697E80FF8AA4A7FF8CA7 A9FF8CA5A7FF89A1A4FF88A0A4FF88A1A4FF86A0A2FF849EA1FF859FA1FF87A0 A3FF87A1A4FF8AA3A5FF536365FF000000FF000000FF778C8EFF8FA8AAFF92AA ACFF92A9ABFF8BA4A5FF86A0A3FF7F9799FF212727FF000000FF000000FF0101 01FF607274FF85A0A3FF88A1A4FF8DA6A8FF8BA4A6FF869FA2FF86A0A3FF7187 8AFF0A0D0DFF000000FF1A1F1FFF8AA4A6FF8FA9AAFF89A2A5FF829C9FFF839D A0FF869FA2FF86A1A4FF6E8488FF131617FE000000FF000000FF9C9C9C630000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000A8A8A8570707 07F80C0D0EFFA9BDCAFFD7F0FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFDEF8FFFF5D686FFF000000FF000000FF16191AFFE0FBFFFFD5EEFEFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD2EDFFFFB2E0FFFFAFDFFFFFB0E0FFFFB1E2 FFFF93BAD5FF000000FF3C4D57FFADDCFBFF81A5BCFF000000FF9CC7E3FF3543 4DFF536A79FF0F1316FF020708FF000000FF000000FF2E2E2ED1000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000B8B8B847000000FF000000FF000000FF0000 00FF050505FF8E8E8EFFFBFBFBFFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFEEEEEEFF5E5E5EFF000000FF373737FFEFEFEFFFD0D0D0FF676767FFC9C9 C9FFF2F2F2FFF5F5F5FFF4F4F4FFF5F5F5FFF5F5F5FFF5F5F5FFF4F4F4FFF5F5 F5FFE8E8E8FF6E6E6EFFA3A3A3FFF6F6F6FF999999FF000000FF010101FFE3E3 E3FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF4F4F4FFF6F6F6FFE9E9E9FF1010 10FF000000FF000000FF010101FE000000FF323232CD00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000E7E7 E7182E2E2ED6030305FF04062CFF090C38FF040B53FF101226FF272F39FF1117 49FF222749FF32393DFF1C2138F79F9F9F65FCFCFC0300000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000DEDEDD223234 3CD505061FFF101314FF111319FF111420FF161B21FF0F1114FF0B0C0DFF0E0F 12FF111418FF0F1115FF0E1013FF353739D4DCDCDC2300000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000F6F6F6096F6F6F92020202FD090C 0CFE718688FFA7C3C5FFA3C0C3FFA0BFC1FFA2C0C2FFA0BFC2FFA0BFC2FFA2C0 C4FFA3C3C6FFACCBCEFFB3D2D5FFB3D2D5FFAFD0D3FFAECFD3FFB0D2D5FFB1D3 D6FFB0D1D5FFB1D1D3FFACCCCEFFA8C9CBFFACCCCFFFABCBCFFFABCCD0FFB6D5 D7FFBAD8DBFFB7D7DBFFB4D7DAFFB5D9DDFFBCE0E4FFC5EBEDFFC9EDF1FFC7EA EEFFBEE2E5FFAACACEFF8CA7A9FF3F4A4BFF000000FF2B3334FF88A2A5FF85A0 A2FF89A3A6FF90A9AAFF8CA6A8FF8AA3A6FF8BA4A6FF8BA4A7FF8EA7AAFF8EA7 A9FF8AA4A6FF8EA8AAFF434F51FF000000FF07090AFF7D9496FF8EA7AAFF87A1 A3FF809B9FFF839DA0FF89A1A4FF89A3A5FF5F7173FF080A0AFF000000FF1013 13FF7D9496FF869FA2FF7F9A9DFF7F9A9DFF829CA0FF869FA3FF88A1A4FF8098 9AFF283132FF000000FF0A0C0DFF799093FF86A0A3FF859FA1FF87A0A2FF88A2 A4FF89A2A4FF87A1A3FF86A0A3FF515F60FF020202FE000000FF2C2C2CD3DADA DA25000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000BBBBBB440C0C 0CF3090A0BFF9EB1BDFFD7F0FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFC7DEEDFF131618FF000000FF000000FF8D9DA8FFD9F2FFFFD5EEFEFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD3EEFFFFB6E2FFFFAFDFFFFFB0E0FFFF84A8 C0FF090B0DFF0E1215FF94BDD7FFB6E7FFFF192025FF2D3942FFA1CDE9FF080A 0BFF82A5BCFF0D0E10FF225E61FF040C0CFF010101FE070707F8B0B0B04F0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000303030CF000000FF000000FF000000FF0000 00FF161616FFEEEEEEFFF6F6F6FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFECECECFF565656FF6D6D6DFFF6F6F6FFF4F4F4FFF6F6F6FFFBFBFBFFF6F6 F6FFF4F4F4FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFFAFAFAFFF8F8F8FFF4F4F4FFF7F7F7FFBBBBBBFF1A1A1AFFE0E0 E0FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF4F4F4FFFFFFFFFF7272 72FF000000FF000000FF000000FF010101FE0A0A0AF5B7B7B748000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000FEFEFE01CECE CD32141414EE030313FF020335FF0C0E19FF0D1018FF161A21FF1A1F2BFF2229 34FF14182DFF0D1165FF151A40F4AEADAB55FDFDFD0200000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FDFDFD02FDFDFD02FEFE FE01000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000D1D1D12F2626 28E4060611FF10131BFF141821FF121628FF1F232BFF171B22FF0F1015FF0F0F 14FF11151AFF14181EFF11151BFF323538D7DDDDDD2300000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000F0F0F00F575757A9000000FF0E11 11FF88A3A6FFB6D8DBFFBCDEE1FFBEDFE3FFB5D7DBFFADD1D6FFB2D5D9FFB3D5 DAFFB4D8DCFFBADDE1FFBADFE3FFC0E4E8FFC0E5E8FFB8DDE2FFBDE2E5FFC5E8 ECFFC5E9EDFFC2E7EBFFC3E8ECFFC1E6EBFFC1E7EAFFC2E7EBFFC4E9EDFFC1E7 EAFFBFE5E9FFC8ECEFFFD1F4F6FFCBEEF1FFC6EBEEFFC6EBEEFFCBEFF2FFCDF2 F4FFC7ECF0FFC6EAEEFFCDF1F4FFB5D4D6FF2B3333FF000000FF657879FF8DA7 AAFF8AA3A5FF8CA5A8FF8BA4A6FF87A0A3FF87A1A4FF8AA4A7FF8BA4A6FF89A2 A5FF8DA6A8FF8FAAACFF364041FF000000FF1A1E1FFF849C9FFF8AA3A5FF89A3 A5FF89A2A4FF8CA5A7FF8EA8AAFF8CA5A8FF8BA4A6FF222829FF000000FF1F25 25FF80989BFF8AA3A6FF87A1A3FF87A0A3FF8AA2A5FF8CA5A7FF8DA7A9FF88A2 A4FF435051FF010101FF050606FF637677FF8DA6A8FF8FA8AAFF93AAACFF92AA ABFF8AA4A7FF849EA1FF89A2A5FF80999BFF262D2EFF000000FF040404FB6F6F 6F90F9F9F9060000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000D1D1D12E1111 11EE050606FF8D9EA8FFD7F0FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD8F1 FFFF819099FF020202FF000000FF1C1F22FFC5DCEBFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD4EEFFFFBAE4FFFFAFDFFFFFAAD9F7FF3240 4AFF090C0EFF98C1DCFFB9ECFFFF5E7989FF000000FF7697ACFF587181FF1920 25FF9EC9E5FF0A080AFF359598FF1F585AFF000000FF000000FF515151AEF7F7 F708000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000B9B9B946080808F7010101FE000000FF000000FF0000 00FF828282FFFFFFFFFFF4F4F4FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF2F2F2FFE8E8E8FFFFFFFFFFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFFBFBFBFFF7F7F7FFECEC ECFFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF6F6F6FFEBEB EBFF040404FF000000FF000000FF000000FF000000FF5A5A5AA5000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000FDFDFD02A8A8 A85A0B0B0BF5090A0FFF111515FF13191DFF181E24FF24282FFF242D34FF1520 3CFF0B0D3DFF0E112FFF171A25F6A9A9A85CFDFDFD0200000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000F9F9F906D1D1D12E7979798A5C5C5CA9B5B5 B54BEDEDED12FDFDFD0200000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000C0C0C0401818 19F0080806FF050522FF0A1040FF1C202FFF20272FFF151C22FF101218FF1014 16FF111419FF101417FF14161EFF3B3C40D0E0E0E01F00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000F2F2F20D5D5D5DA2010101FE090B 0CFF829A9DFFBBE1E5FFC2E6E9FFC2E7EBFFC3E8ECFFC6E9ECFFC1E6EAFFCAED F1FFCAEDEFFFBFE5E9FFB8DFE3FFBEE3E8FFC3E7EBFFCCEFF2FFD0F2F6FFC9ED F0FFC9EDF0FFCBEFF3FFCEF2F5FFCCF0F3FFC5E9ECFFC6EAEEFFC8EDF0FFBFE4 E9FFBCE2E7FFC6EAEDFFCAEEF1FFCFF1F4FFC9EDF1FFC1E6EAFFBCE2E6FFBAE0 E4FFBDE2E6FFC1E7EAFFC2E7EBFFC1E6EAFF89A4A6FF101313FF222829FF829A 9DFF89A3A5FF8CA5A8FF8CA6A8FF87A0A3FF849EA0FF859FA2FF86A0A3FF87A0 A3FF89A2A5FF88A2A5FF2C3636FF000000FF1B2021FF889FA2FF89A2A6FF8BA4 A7FF8FA8AAFF8EA7A9FF8AA3A6FF8DA6A8FF748A8CFF0D0F10FF232929FF191D 1EFF58696BFF86A1A3FF8CA6A8FF90A9AAFF90A8A9FF89A2A4FF7F989BFF768C 8EFF343E40FF000101FF020303FF58686AFF90A9ABFF8DA7A9FF8CA6A7FF8BA4 A6FF8CA5A7FF8DA6A8FF8BA4A5FF859FA1FF607274FF0B0C0CFF000000FF1717 17E8C4C4C43B0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000E8E8E8171616 16E9010101FE77858FFFD8F1FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD1E9 F9FF4B5459FF000000FF000000FF1E2224FFC6DDECFFD6EFFFFFD5EEFEFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD5EE FEFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD5EEFFFFBDE5FFFFAFDFFFFFB0E0FFFF9DC8 E4FFADDDFCFFB1E2FFFF91B9D2FF07090AFF20292FFFABD9F8FF0C0F11FF6782 94FF8BB1C9FF050002FF43BEC3FF3BA7ABFF030A0BFF000000FF000000FFD9D9 D926000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000FDFDFD02565656A9000000FF000000FF000000FF000000FF0909 09FFF0F0F0FFF6F6F6FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFF6F6F6FFF5F5F5FFF4F4F4FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF4F4F4FFF5F5F5FFF5F5 F5FFF4F4F4FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF4F4F4FFFCFC FCFF727272FF000000FF000000FF000000FF000000FF171717E8CECECE310000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000F7F7F7087A7A 7A8907070DFC0E1114FF10151AFF151B20FF1D2429FF20262BFF181E3BFF111B 49FF121721FF1A2025FF1A1E23F6A7A7A85CFEFEFE0100000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000F8F8F8079B9A9B68282828DB040404FF020201FF1011 14F4565656ADCCCCCB34FDFDFD02000000000000000000000000000000000000 00000000000000000000000000000000000000000000FEFEFE01A4A4A45C0E0E 10FF101114FF0E1011FF080817FF101132FF2A2F3FFF24282FFF151920FF171B 23FF151920FF14181DFF101317FF484A4BC1E8E8E81700000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000F9F9F9067E7E7E81040404FB0203 03FE5D6F71FFBFE2E6FFC4E8EDFFC6EBEEFFCCF0F3FFCBEEF1FFC9EDF1FFC8EC EFFFC1E6EAFFBDE3E7FFC5EAEDFFC3E8EBFFC0E5E9FFC8ECEFFFC7EBEFFFC2E7 EBFFC5E9EDFFC6EAEEFFC3E8ECFFC4E9ECFFCBEEF2FFCAEEF1FFC4E9EDFFC4E8 EBFFC1E6EAFFC0E5E8FFC3E8ECFFC4E9EDFFCBEFF1FFCAEEF1FFC8EDF0FFC3E9 ECFFC7EBEFFFCBEFF2FFC4E8ECFFC1E7EBFFC5EAEDFF687B7DFF020302FF4A58 5AFF859EA1FF829C9FFF859EA1FF89A3A5FF8BA4A6FF8AA3A5FF87A1A3FF87A1 A4FF869FA2FF8DA6A9FF2D3535FF000000FF1E2425FF8AA3A5FF8BA5A8FF87A1 A4FF8BA4A7FF89A3A5FF849EA1FF849FA2FF4E5F60FF141818FF89A1A3FF687B 7DFF171B1CFF74898BFF687A7CFF4F5D5EFF3A4647FF313B3CFF212828FF0E10 10FF010101FF000000FF010101FF445153FF8AA3A5FF89A3A5FF849EA1FF839E A1FF8AA3A5FF8DA6A8FF8BA4A6FF8AA3A5FF8AA3A5FF3D4748FF000000FF0000 00FF4E4E4EB1F8F8F80700000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000001B1B 1BE4010101FE5F6A71FFD5EEFEFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD5ED FDFF6F7C84FF000000FF000000FF000000FF69757DFFE0FAFFFFD5EEFEFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD5EEFEFFD9F2FFFFC8E0EEFFDCF6FFFFD6EF FFFFD5EEFEFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD5EEFFFFC0E6FFFFAFDFFFFFAFDFFEFFB1E2 FFFFB2E2FFFFA5D2EFFF232D33FF020303FF95BED9FF6C8A9DFF07090AFFAFDF FEFF688496FF050A0AFF4FDDE2FF4EDBE0FF15393BFF010101FE000000FF5D5D 5DA2000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000CCCCCC33181818E7000000FF000000FF000000FF000000FF8282 82FFFAFAFAFFF4F4F4FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFDEDEDEFF060606FF000000FF000000FF000000FF000000FF8282827DFCFC FC03000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000E8E8E8174546 48C104040CFF101316FF141920FF242A31FF1E272DFF283037FF363D45FF262B 30FF182022FF181E23FF161A1EF4B0B0B051FEFEFE0100000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000FCFCFC03ACACAC57111211F0060606FF030308FF040411FE0303 08FF030302FF393938D0C2C2C23EFDFDFD020000000000000000000000000000 00000000000000000000000000000000000000000000FCFCFC03919191700E0E 10FF0F0F13FF101217FF15181AFF07092FFF272D57FF31363BFF1D242BFF1C22 28FF161A20FF12161CFF11141AFF646466A0F3F3F30C00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000B7B7B748101010EF0000 00FF232929FFB0D0D3FFBEE3E8FFBEE3E8FFC1E6EAFFC4E9EDFFC6EAEEFFC6E9 ECFFC5E9ECFFC7EBEEFFC8ECEFFFC6ECF0FFCAEFF3FFC7ECEFFFBEE4E8FFC0E5 E9FFC6EAEEFFC6EBEEFFBFE4E9FFBDE2E7FFC3E8ECFFC4E9ECFFBFE4E9FFC3E8 ECFFCAEEF1FFC3E8EBFFC7EBEFFF9DBABCFF647577FF708183FF99B2B5FFB9DD E1FFC3E9EDFFC6EAEDFFCAEEF1FFC6EBEEFFCBEFF3FFC4E7EAFF3F4B4CFF0A0C 0CFF748B8DFF869FA2FF8AA3A5FF8DA6A9FF8CA6A8FF8FA7A9FF8EA7A9FF8BA4 A8FF87A1A4FF88A2A5FF2F3739FF000000FF22292AFF8AA3A6FF88A2A5FF88A2 A5FF8FA8ABFF90AAACFF8DA6AAFF85A0A3FF374142FF242A2BFF92ACAEFF839A 9CFF0F1111FF0C0F0FFF070809FF020202FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF394445FF829B9EFF839DA0FF829C9FFF859F A2FF89A3A5FF88A0A4FF8AA2A5FF8EA7AAFF90A8ABFF7F9596FF151819FE0000 00FF0A0A0AF5C0C0C03F00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000003C3C 3CC3000000FF444C51FFCFE7F7FFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD4EDFDFF75828BFF000000FF000000FF000000FF798790FFDFF9FFFFD5EE FEFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD9F2FFFF8B9CA5FF09090AFF3A4146FFDAF4 FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFC3E7FFFFAFDFFFFFAFDFFEFFB0E1 FFFFACDBF9FF1E262BFF000000FF7C9EB3FFA9D8F5FF161D20FF597283FFAFDF FEFF38444EFF1B4C4EFF4EDADFFF4DD7DCFF3FAEB3FF000000FF000000FF0000 00FFEFEFEF100000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FCFCFC037B7B7B84000000FF010101FE000000FF000000FF0E0E0EFFE4E4 E4FFF4F4F4FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFEFEFEFFF666666FF000000FF000000FF000000FF000000FF1D1D1DE2EDED ED12000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000DBDBDB242F30 3BD60E1015FF12161BFF14171EFF12161DFF12171DFF1A212AFF1D212EFF191D 38FF0F1342FF0F1320FF15171FF5AAAAAA58FDFDFD0200000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000EDEDED12545454B1060606FF030305FF04040FFF03030CFF0404 05FF040406FE020216FF1F1F1EE7C5C5C53BFBFBFB0400000000000000000000 00000000000000000000000000000000000000000000FCFCFC0379797A8C0D10 15FF101115FE101218FF131421FF090A36FF0B0C27FF1F2328FF272D34FF1E22 2BFF141820FF111219FF0F1217FA83838483F6F6F60900000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000F0F0F00F444444BB0000 00FF000000FF5A6A6BFEBCE0E3FFC0E6EAFFC2E6ECFFC6EAEDFFC7EBEEFFC1E5 E9FFB7D7DAFFAECBCDFFB3D2D5FFBEE2E6FFC4E9EBFFBBE1E6FFBAE0E5FFBFE4 E8FFBCE2E6FFC0E4E9FFC9EEF2FFCCEFF2FFCAEEF0FFC6EAEEFFC5EAEEFFCCF0 F3FFCAEEF2FFCBF0F3FF96B0B3FF101314FF020101FF0E0E0EFF2A2A2BFF646E 6EFFADC9CBFFC9EEF1FFC9EEF1FFC7EBEEFFC0E5E9FFC2E8ECFFA7C7CBFF2329 2AFF3C4848FF8DA7A9FF859FA2FF859FA2FF87A0A4FF86A0A3FF8AA3A5FF8DA6 A8FF8EA7A9FF8EA7AAFF3E4C4DFF000000FF1E2324FF7B9496FF7B9294FF6A7E 80FF5B6C6DFF3D4A4BFF202628FF151616FF010202FF050606FF5F7274FF5364 65FF050606FF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF384344FF869FA2FF8AA4A6FF8AA3A5FF8AA3 A6FF8CA4A8FF8AA5A6FF8BA5A7FF8DA5A9FF86A0A3FF8CA5A8FF4A5758FF0000 00FF000000FF7A7A7A8500000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000007272 728D000000FF272B2EFFC8E0EFFFD5EEFEFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD5EEFEFFDEF8FFFF8B9CA5FF040404FF000000FF070808FFA4B8C4FFD6EF FFFFD5EEFEFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFDFFAFFFF0F1113FF000000FF000000FF555F 65FFDDF7FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFC4E8FFFFB0DFFFFFB0E0FFFFB6E8 FFFF222B31FF000000FF5B7584FFB3E5FFFF5F798AFF010101FFA2CDEAFF9CC6 E1FF040102FF399FA3FF4CD5DAFF4BD3D8FF4FDFE4FF0F2A2BFF000000FF0000 00FF8484847B0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000EBEBEB14171717E8000000FF000000FF000000FF000000FF707070FFF0F0 F0FFF4F4F4FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF6F6F6FFB7B7B7FF0B0B0BFF000000FF000000FF010101FE000000FF9696 9669000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000C6C6C6391E1E 20EA0C0C0EFF0B0C0FFF0D0F15FF141825FF161B26FF181D35FF171B3CFF171A 26FF0E0F1CFF090913FF101215FA90919273FCFCFC0300000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FEFEFE01BBBBBB441C1C1CEC0B0B0BFF030308FF05052BFF050517FF0303 1DFF03030FFF04040BFE050504FF3B3A3ACDDBDBDB2400000000000000000000 00000000000000000000000000000000000000000000FCFCFC03797A7A8A1012 18FF101419FF10131BFF0B0D24FF131618FF0D0F1FFF1B1F29FF32373EFF262C 32FF0A1138FF070816FF0A0B10FF5A5B5CABEFEFEF1000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000BBBBBB440F0F 0FF0000000FF030404FE5D6F6FFFC1E5E9FFC3E7EBFFC8ECF0FFC9EDF0FF768B 8DFF333939FF303232FF464B4CFF6D797BFFA5BFC1FFC4E9EEFFC7ECF0FFC6EB EFFFC5EBEDFFC3E7EBFFC1E5E9FFC6E9EDFFC6EAEDFFC7EBEEFFC4E9EDFFBDE4 E8FFC3E8ECFFC9EDF0FF4B585AFF000000FF000000FF040404FF0F0F0FFF2827 27FF545859FFA4BEC0FFC4E9ECFFC0E5E9FFC7EBEDFFC9EBEFFFCCEFF2FF8CA6 A8FF101213FF5B6B6CFF8FA9ACFF86A0A3FF849FA2FF86A0A2FF859EA1FF849E A1FF87A0A4FF8BA4A7FF4F5F61FF000000FF020303FF141718FF111414FF0304 05FF000000FF000000FF000000FF000000FF000000FF000000FF070808FF1418 18FF0F1213FF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF3C4647FF8BA3A6FF8BA4A6FF88A1A4FF849F A1FF839DA0FF87A1A4FF88A1A4FF88A1A4FF8BA4A6FF869FA2FF64787AFF0607 07FE000000FF575757A8FAFAFA05000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000B2B2 B24D000000FF030404FEC1D7E6FFD5EEFEFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD5EEFEFFD9F2FFFF99ABB6FF0E1011FF000000FF1D2123FFC1D8 E7FFD6EFFFFFD5EEFEFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD7F0FFFFD2ECFBFF000000FF000000FF000000FF0B0C 0DFFB7CCDAFFD6F0FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFC6E8FFFFB0E0FFFFB0E0FFFFAEDE FDFF3C4C56FF637E90FFB6E8FFFF8BB0C9FF000000FF546B79FFB6E8FFFF4D60 6EFF051B1BFF48C8CDFF4BD3D8FF4CD4D9FF4CD6DBFF379A9EFF000000FF0000 00FF292929D60000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008B8B8B74000000FF010101FE000000FF000000FF121212FFBFBFBFFFF6F6 F6FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFEEEEEEFF434343FF000000FF000000FF000000FF000000FF1212 12ED000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000A2A2A25F0D0D 0FFF0A0B14FF0B0B0FFF0E1012FF10151AFF15181FFF191D25FF1C2129FF1416 1CFF111519FF111317FF0E1012FB8B8C8D79FAFAFA0500000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000E7E7E7183F4043C5050513FF080805FF04031EFF08091BFF0D0D0EFF0607 24FF090A36FF09080FFF0A0A0DFF0E121FFF9D9E9F64FDFDFD02000000000000 00000000000000000000000000000000000000000000FAFAFA05818282801013 16FF0F1217FF101217FF0C0E13FF13161BFF131825FF11154AFF34384AFF0E15 63FF101522FF131419FF0F1216FF36383BD3E0E0E02000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000FEFEFE018484 847B030303FC000000FF0C0F0FFF8DA7A9FFC5EAEEFFBFE5E9FFA2C0C4FF191E 1EFF030303FF0B0B0BFF171717FF2B2B2BFF4C4E4EFF94A9ACFFC6EBF0FFC4E9 ECFFC5EAEEFFC2E7EBFFC0E5E9FFC4E9ECFFC2E7EAFFC3E8EBFFC4E9EDFFC3E7 EBFFC9ECF0FFC5E9EDFF3E494BFF000000FF000000FF010101FF050505FF1818 18FF373737FF646A6BFFB6D6D9FFC5EAEDFFC5E9EDFFC6E9ECFFC9ECEEFFC7EA EEFF66797BFF111415FF72888AFF89A2A5FF869FA2FF869FA2FF87A0A3FF869F A2FF829DA0FF849FA2FF637577FF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF000000FF000303FF617375FF7D94 96FF718587FF090C0BFF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF010101FF445253FF87A1A4FF8CA5A7FF8CA5A7FF8AA3 A5FF89A3A6FF8BA4A7FF8AA4A7FF849EA1FF849EA0FF8BA4A7FF708385FF080A 0AFF000000FF515151AEF8F8F807000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000FAFA FA05000000FF010101FE97A9B4FFD8F1FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD7F0FFFFBBD1DEFF0E1011FF000000FF292E 31FFDEF8FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD7F0FFFF000000FF000000FF000000FF0303 03FF83929BFFD8F1FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFC6E9FFFFB0E0FFFFAFDFFEFFB0E0 FFFFA9D8F5FFB1E1FFFFA0CCE8FF161C20FF101417FFA9D7F5FF90B8D1FF0000 00FF2B787BFF4CD4D9FF4CD4D9FF4CD4D9FF4BD3D8FF46C5CAFF0B1F20FF0101 01FE101010EFD1D1D12E00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000080808F7000000FF010101FE000000FF000000FF4A4A4AFFF3F3F3FFF5F5 F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFFBFBFBFF989898FF060606FF000000FF000000FF010101FE0000 00FF9393936C0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FAFAFA057E7E7E840E0E 12FF0E0E10FF0B0B0BFF0E0E11FF0F0F16FF11161AFF181D24FF1B1F28FF191E 26FF12161BFF0E1018FF111418FB898A8A7BFAFAFA0500000000000000000000 000000000000000000000000000000000000000000000000000000000000FBFB FB048080818408080CFF07071FFE060526FF060F46FF141511FF090B4AFF0B0C 27FF0F0F07FF060634FF03030DFE070814FF5E5E61A8F6F6F609000000000000 00000000000000000000000000000000000000000000F8F8F8075C5D5EAA0E11 17FF13161DFE11151AFF111318FF171922FF1F232EFF101335FF191D28FF2B2F 33FF1C1F29FF12161CFF12141BFF323336D8DADADA2600000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000F0F0 F00F585858A7020202FD000000FF3C4647FEB6D7DBFFC3E8ECFF8DA7A9FF0809 09FF000000FF020202FF060606FF101010FF282727FF464647FFA2BBBDFFCDF2 F4FFC9EDF0FFC7EBEEFFC9EDF0FFC3E9EDFFC1E5E9FFC3E7EBFFC9EDF0FFCBEF F1FFC4E8ECFFC6ECF0FF6D8183FF000000FF000000FF000000FF020202FF0B0B 0BFF252525FF434343FF91A4A5FFCAEFF2FFC1E6EBFFC0E5E9FFC1E7EAFFC3E8 ECFFBDE1E6FF495657FF3B4547FF8CA5A8FF8AA5A8FF8EA7A9FF8CA5A8FF8BA4 A7FF8AA4A6FF89A2A5FF798F91FF060808FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF000000FF1A1F20FF839EA0FF859F A2FF849FA2FF4D5D5FFF020202FF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF020202FF526164FF849FA1FF859FA1FF8CA5A7FF8CA5 A7FF89A2A5FF89A2A5FF8AA3A6FF89A2A4FF89A2A5FF8EA7A9FF59696AFF0001 01FF000000FF67676798FEFEFE01000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00002C2C2CD3000000FF4F575EFFDDF6FFFFD5EEFEFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD5EEFEFFD7F0FFFFC9E0EFFFC5DCEBFFD5EEFEFFD5EE FEFFD6EFFFFFD6EFFFFFD6EFFFFFD5EEFEFFD7F0FFFFC4DAE9FF1D2123FF0000 00FF566067FFDBF5FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD5EEFEFFE0FBFFFF131516FF000000FF000000FF0000 00FF69757DFFD7F1FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFC7E9FFFFB0E0FFFFB0E0FFFFAFDF FEFFB0E0FFFFABDAF8FF3C4D57FF000000FF7EA0B6FFB0E0FEFF181F22FF0D23 24FF4BD2D7FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4BD1D6FF1F5658FF0000 00FF040404FB9B9B9B6400000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000008383 837C000000FF010101FE000000FF000000FF080808FFA7A7A7FFFBFBFBFFF4F4 F4FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF4F4F4FFF5F5F5FFF6F6 F6FFF6F6F6FFF6F6F6FFF5F5F5FFF5F5F5FFF4F4F4FFF5F5F5FFF5F5F5FFF4F4 F4FFF5F5F5FFF4F4F4FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF4F4F4FFF5F5 F5FFF4F4F4FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF6F6F6FFF6F6 F6FFF6F6F6FFF5F5F5FFF5F5F5FFF4F4F4FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFF5F5F5FFF5F5F5FF1C1C1CFF000000FF000000FF000000FF0000 00FF1D1D1DE20000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000EEEEEE11434444C40809 09FF0C0C0CFF0C0C0DFF0E1013FF111418FF11172FFF181C27FF171D35FF1418 22FF090B31FF070820FF0A0A0EFD7E7E7F86F9F9F90600000000000000000000 000000000000000000000000000000000000000000000000000000000000E9E9 E916262525E106061FFF090926FF0F1014FF0D1339FF121F63FF081176FF0F0E 0AFF0B0C13FF0A0B1CFF0E0D0AFF0D1013FF323437D9E8E8E817000000000000 00000000000000000000000000000000000000000000F2F2F20D4D4E4FBB1012 17FF111319FF14171EFF13151BFF1B1E25FF1F2332FF0E0F28FF2F323AFF292C 35FF14171DFF14161DFF0F1218FF303037DADADADA2600000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D2D2D22D252525DA000000FF040505FE6B8082FFCFF3F6FFA6C2C4FF1013 13FF000000FF000000FF000000FF060606FF161616FF333333FF666D6EFFB7D8 DBFFC2E8EBFFC6EBEEFFC8ECEFFFC8EDF1FFC6EBEEFFC8ECEFFFC9EDF1FFC4E9 ECFFC5E9EDFFC1E7EBFFA3C3C6FF1D2122FF000000FF000000FF000000FF0505 05FF191919FF3A3939FF70797AFFC1E5E9FFC7ECEFFFCBEFF2FFCAEDF0FFCAEE F1FFC6EBEFFFA2C2C5FF3A4546FF81999BFF93AFB2FF8BA6A8FF8CA5A7FF8BA4 A7FF8BA4A6FF8EA7A9FF859DA0FF1B2021FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF000000FF3C484AFF88A3A5FF849E A1FF849EA1FF7D9698FF252C2CFF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF030404FF58696AFF89A2A5FF87A1A4FF87A0A3FF8EA7 A9FF8AA3A6FF86A0A3FF88A1A4FF89A1A4FF8CA5A8FF819A9CFF22292AFE0000 00FF000000FFA1A1A15E00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008585857A000000FF060606FED9F3FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD7F1FFFFC2D8E7FF24292BFF16181AFF8D9EA8FFDBF5 FFFFD5EEFEFFD6EFFFFFD6EFFFFFD6EFFFFFD5EEFEFFD8F1FFFFB6CBD9FF1618 1AFF020202FF97A8B4FFD7F0FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFDAF4FFFF6B7880FF000000FF000000FF0000 00FF66737AFFD7F0FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFC7E9FFFFB0E0FFFFB0E0FFFFAFDF FEFFB6E8FFFF576F7EFF000000FF526977FFB7EAFFFF475A66FF010505FF3FB2 B6FF4DD8DDFF4BD3D8FF4CD4D9FF4CD4D9FF4CD4D9FF4CD6DBFF31888BFF0104 04FF000000FF6A6A6A95FEFEFE01000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000F6F6F6091A1A 1AE5000000FF000000FF000000FF000000FF282828FFFBFBFBFFF5F5F5FFF5F5 F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF4F4F4FFF8F8F8FFEBEBEBFFC3C3 C3FFB7B7B7FFBABABAFFCDCDCDFFF4F4F4FFF4F4F4FFF4F4F4FFF6F6F6FFF5F5 F5FFF6F6F6FFF4F4F4FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF4F4F4FFF6F6 F6FFF5F5F5FFF5F5F5FFF5F5F5FFF4F4F4FFF5F5F5FFDFDFDFFFBDBDBDFFB8B8 B8FFB9B9B9FFD9D9D9FFF8F8F8FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFF4F4F4FFFFFFFFFF8F8F8FFF000000FF000000FF000000FF0101 01FE060606F99D9D9D6200000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000D7D7D7280D0E10FD0506 06FF070708FE0C0C0BFF0F1011FF101216FF0F1529FF101432FF111537FF161D 30FF060616FF0A0B0CFF101215FD7777788BF8F8F80700000000000000000000 0000000000000000000000000000000000000000000000000000FEFEFE01D7D7 D728232527EA0D0F1BFF04076BFF0B0C29FF171E24FF0A1E96FF0B134EFF1B1E 23FF10152AFF060F5CFF080930FF090C23FF121421F8D2D2D22D000000000000 00000000000000000000000000000000000000000000E9E9E9163C3C3ECF0E11 17FF171B22FF14181FFF11151BFF1F252DFF0C0D18FF11141AFF272A31FF252A 30FF16191CFF10121DFF090A14FF393C3FCFDFDFDF2000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000A0A0A05F080808F7000000FF121515FE9DBABCFFC2E7EBFF3D48 4BFF000000FF000000FF000000FF010101FF0D0D0DFF292929FF4E4F4FFF99B3 B5FFBADFE4FFC1E6EAFFC6EBEEFFC6EAECFFC4E9EDFFC2E7EBFFC0E5E9FFC4E9 EDFFC7ECF0FFC3E7EBFFC3E8EBFF859A9DFF0A0B0BFF000000FF000000FF0303 03FF151515FF353434FF697273FFC1E4E7FFC8ECF0FFC6EBEEFFC8ECEFFFCCEF F2FFC7EBEEFFC7ECEFFF89A3A6FF617274FFA0BEC1FF97B2B4FF8EA8ABFF8CA5 A7FF8DA6A8FF8AA3A6FF849DA0FF394445FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF000000FF607374FF8FA8ABFF8CA5 A7FF849EA0FF859FA2FF657779FF080A0AFF000000FF000000FF000000FF0000 00FF000000FF000000FF090A0BFF728889FF839EA1FF87A0A3FF88A1A4FF87A0 A3FF8CA6A8FF8DA6A8FF8CA5A8FF859FA1FF7D979BFF404D4EFF010101FE0000 00FF313131CEECECEC1300000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D9D9D926000000FF000000FF97A9B4FFDAF4FFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFDEF8FFFF636F76FF000000FF000000FF000000FFC2D9 E8FFD8F1FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD9F3FFFFADC2 CFFF000000FF2E3337FFCCE4F3FFD5EEFEFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFBFD5E4FF0F1113FF000000FF0202 03FF81909AFFD8F1FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFC6E9FFFFB0E0FFFFB0E0FFFFB5E6 FFFF6C8A9DFF000000FF384852FFB0E0FFFF678395FF000000FF349295FF4DD7 DCFF4BD3D8FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF40B3B7FF050E 0FFF000000FF404040BFF4F4F40B000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000008B8B8B740404 04FB010101FE000000FF000000FF000000FFA9A9A9FFFCFCFCFFF4F4F4FFF5F5 F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFD8D8D8FF515151FF1818 18FF0C0C0CFF0F0F0FFF1D1D1DFF898989FFF9F9F9FFF8F8F8FFE2E2E2FFF5F5 F5FFCCCCCCFFF8F8F8FFF5F5F5FFF5F5F5FFF5F5F5FFF4F4F4FFFFFFFFFF8A8A 8AFFFFFFFFFFEBEBEBFFECECECFFF5F5F5FFD8D8D8FF292929FF121212FF0D0D 0DFF0E0E0EFF2B2B2BFFABABABFFF3F3F3FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFF5F5F5FFF5F5F5FFF4F4F4FF191919FF000000FF000000FF0000 00FF000000FF434343BCF2F2F20D000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000D1D1D12E101217FF0707 07FF060608FF090A18FF090B1AFF0F1018FF0D101BFF0E1420FF080A48FF1315 19FF14171CFF14191FFF111519FB8585857FF9F9F90600000000000000000000 0000000000000000000000000000000000000000000000000000FEFEFE01CECD CD321F2226ED12151BFF141616FF0A0A2AFF040439FF242833FF131E60FF262D 49FF11163FFF141515FF101313FF14171CFE14181DFFB0B0AF53000000000000 00000000000000000000000000000000000000000000D6D6D629101114FA0F10 16FF151722FF141620FF171B25FF1A1E2BFF161921FF2B3039FF161B3FFF1115 34FF0D1035FF0F111BFF1A1F26FF45464BC8E5E5E51A00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000F6F6F6095C5C5CA3000000FF000000FF374243FFB6D9DDFF9AB7 BBFF141718FF000000FF000000FF010101FF080808FF212121FF474848FF95AA ACFFC4E8EBFFC1E6EBFFC0E5E9FFC2E7EBFFC4E9EDFFC6EBEEFFCBEFF2FFCEF2 F4FFCEF2F5FFCBEFF2FFC9EDF0FFC3E9ECFF748A8DFF151818FF020202FF0303 03FF131313FF373737FF899A9CFFC9EDF0FFC8ECEEFFC8ECEFFFC9ECF0FFC5E9 ECFFC5EAEDFFCBEEF2FFC2E6E9FF809799FFA1BEC0FFA1BFC2FF93AEB1FF8FA9 ABFF8CA6A8FF8FA8A9FF8DA6A9FF617274FF040505FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF0E1111FF718889FF87A1A3FF89A2 A4FF8AA3A5FF8BA4A5FF8CA4A7FF384343FF000000FF000000FF000000FF0000 00FF000000FF000000FF161A1AFF8DA5A6FF8BA4A7FF8DA6A8FF8BA4A6FF849E A1FF87A1A2FF85A0A2FF86A0A2FF869FA2FF536364FF070808FE000000FF0808 08F7A4A4A45B0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F0F0F00F303030CF000000FF3B4146FFDFF9FFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFE1FBFFFF3D4448FF000000FF000000FF000000FF505A 60FFDFF9FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD5EEFEFFDBF5 FFFF83929CFF000000FF83939DFFDAF3FFFFD5EEFEFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD7F0FFFF90A1ABFF181B1CFF2A30 33FFC9E0EFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFC5E8FFFFB0E0FFFFB0E0FFFFB2E3 FFFF90B7D0FF597181FFADDCFBFF708FA2FF000000FF215D5EFF4BD2D7FF4BD3 D8FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4DD8DDFF091A 1AFF000000FF1A1A1AE5EBEBEB14000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000007171718E0202 02FD000000FF000000FF000000FF000000FFE4E4E4FFF7F7F7FFF5F5F5FFF5F5 F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFEFEFEFFF6B6B6BFF000000FF0000 00FF000000FF000000FF000000FF787878FFFBFBFBFFCFCFCFFFB2B2B2FFF0F0 F0FF797979FFFEFEFEFFF5F5F5FFF5F5F5FFF4F4F4FFF7F7F7FFE2E2E2FF0E0E 0EFF9E9E9EFFCFCFCFFFB9B9B9FFF5F5F5FFE0E0E0FF000000FF000000FF0000 00FF000000FF000000FF111111FFE5E5E5FFF4F4F4FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFF5F5F5FFF4F4F4FFFEFEFEFF434343FF000000FF000000FF0000 00FF000000FF333333CCE7E7E718000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000DCDCDC23242629E9090A 0BFF0A0C10FF0D0D18FF0A0B34FF0B0E26FF0A0C16FF080C2EFF141817FF1B21 26FF191E23FF141817FF121617FB8687877EFAFAFA0500000000000000000000 000000000000000000000000000000000000000000000000000000000000CDCD CD3223262CEE171C24FE1C2129FF191E22FF10151DFF060953FF2A3371FF0517 84FF213477FF303346FF353A47FF3B414BFF282C34FFC7C7C738000000000000 00000000000000000000000000000000000000000000B2B2B14E0D0F12FF0C0E 14FF0A0E23FF0D1021FF0F132BFF0D1139FF262A38FF1F243EFF161823FF171B 22FF181C20FF171A21FF131720FF65666BA6F0F0F00F00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000D7D7D7282B2B2BD4000000FF060707FE728789FFC5EA EEFF94AEB1FF202626FF000000FF000000FF060606FF1C1C1CFF48494AFFA4BC BFFFCCEFF3FFCEF1F4FFC8ECEFFFC6EBEEFFC5EAEDFFC0E5E9FFC1E5E9FFC4E8 EDFFC4E9ECFFC7EBEEFFC4E9EDFFC0E6EAFFC5EBEFFF9FBCBFFF5F7173FF3B46 47FF455051FF7C8F90FFC3E4E7FFC9EDF0FFC4E9ECFFBFE4E8FFC3E8ECFFC5EA EEFFC6EBEEFFC1E6EBFFC5EAEEFFBEE0E4FFA6C2C5FFB1D1D4FF9FBDBFFF91AB AFFF8AA4A6FF88A2A4FF8AA3A6FF859C9FFF181D1DFF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF242C2DFF81999CFF88A2A4FF88A1 A4FF8DA7A9FF90A9AAFF91A9ABFF7F9799FF191E1EFF000000FF000000FF0000 00FF000000FF000000FF3C4849FF90AAACFF8BA4A7FF869FA2FF86A0A3FF8AA4 A7FF89A2A4FF8CA4A7FF89A2A5FF607275FF0D0F10FE000000FF050505FA7171 718EF4F4F40B0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000007F7F7F80000000FF0C0E0FFFB7CDDBFFD7F0FFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFE0FAFFFF474F54FF000000FF000000FF000000FF1619 1AFFD5EEFEFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD5EE FEFFD4EDFCFF485156FF030303FFC4DBEAFFD7F1FFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD5EEFEFFDCF6FFFFCCE4F3FFD4ED FDFFD8F1FFFFD5EEFEFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFC3E7FFFFAFDFFFFFB0E0FFFFAFDF FEFFB2E2FFFFB8EAFFFF5F798AFF000000FF194648FF49CDD2FF4CD4D9FF4CD4 D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4BD3D8FF4FDFE4FF1845 46FF000000FF000000FFE1E1E11E000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000D6D6D6291010 10EF000000FF000000FF000000FF000000FF606060FFFFFFFFFFF5F5F5FFF5F5 F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFEBEBEBFF484848FF000000FF0000 00FF000000FF000000FF191919FFE3E3E3FFE2E2E2FF656565FF9B9B9BFF2A2A 2AFFC1C1C1FFF9F9F9FFF5F5F5FFF5F5F5FFF5F5F5FFF8F8F8FF686868FF0101 01FF070707FF999999FF4F4F4FFFC0C0C0FFEDEDEDFF717171FF000000FF0000 00FF000000FF000000FF000000FFDCDCDCFFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFF4F4F4FFF8F8F8FFD6D6D6FF000000FF000000FF000000FF0101 01FE020202FD7777778800000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000E8E8E81726292CE7141A 1EFF11141AFF0C0D13FF10131DFF1A1F26FF181F22FF0D101DFF232A34FF1B22 3BFF0A0B34FF05054AFF080832FB7E7E7F87F5F5F50A00000000000000000000 000000000000000000000000000000000000000000000000000000000000DCDC DC232C2E32E21A1D26FF1B1F27FF1A1F27FF282E35FF2C326DFF4E5B7FFF3A3F 51FF08143FFF001675FF616983FE818892FF585A5FCEECECEC13000000000000 00000000000000000000000000000000000000000000828282840B0C11FF0F0F 15FF0E1316FF111419FF0E1125FF0B0F37FF22272CFF232836FF32353EFF2A2F 37FF292D36FF262C31FF191D25FF68696C9FF4F4F40B00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000FDFDFD029595956A080808F7000000FF1A2020FFA0BF C2FFC2E7EBFF98B6BAFF445354FF141718FF0B0C0CFF2A2D2DFF839495FFC6E8 EBFFC0E5E9FFBCE2E5FFC4E9ECFFCFF2F4FFCFF3F6FFCDF1F4FFC2E7EBFFBFE5 E9FFC1E6EBFFC0E5E9FFCCF0F3FFCAEEF3FFCCF0F3FFCAEFF1FFC0E4E8FFB3D6 D9FFB5D7DBFFC0E3E7FFC3E8ECFFBCE2E7FFC2E8ECFFC4E8ECFFC1E7EAFFC8EC EFFFCDF0F3FFCEF1F4FFD1F4F6FFCAEEF1FFBDE0E4FFB6D9DDFFAACACEFF95B3 B7FF88A3A7FF849FA3FF8CA5A7FF8FA8AAFF566668FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF394546FF839DA0FF87A0A4FF89A3 A6FF8AA3A6FF89A2A5FF89A2A5FF8BA6A8FF607274FF030404FF000000FF0000 00FF000000FF010202FF6F8588FF87A2A4FF8CA6A8FF8AA4A7FF8DA6A9FF8EA8 AAFF86A0A3FF8AA3A6FF6C8083FF141818FE000000FF000000FF585858A7EDED ED12000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000D0D0D02F0F0F0FF0010101FE717E87FFD7F0FFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFDCF6FFFF7A8891FF000000FF000000FF000000FF1113 14FFBED5E3FFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFC2D9E8FF131617FF78878FFFDDF6FFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD5EEFEFFD5EEFEFFD6EFFFFFD6EF FFFFD5EEFEFFD6EFFFFFD6EFFFFFD6EFFFFFD5EEFEFFD7F0FFFFD8F1FFFFD5EE FEFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFC1E7FFFFAFDFFFFFB0E0FFFFB0E0 FFFFB4E5FFFF556D7BFF000000FF010506FF42BABEFF4FDCE1FF4CD4D9FF4CD4 D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4EDBE0FF2975 77FF010101FE000000FFBFBFBF40000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000005151 51AE000000FF010101FE000000FF000000FF0E0E0EFFDCDCDCFFF7F7F7FFF4F4 F4FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF1F1F1FF797979FF000000FF0000 00FF010101FF2C2C2CFF9E9E9EFFA3A3A3FF2E2E2EFF000000FF000000FF2C2C 2CFFFFFFFFFFF4F4F4FFF5F5F5FFF4F4F4FFF7F7F7FF959595FF090909FF0000 00FF000000FF000000FF040404FF000000FF7C7C7CFFB6B6B6FF545454FF0606 06FF000000FF000000FF121212FFE5E5E5FFF4F4F4FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFF5F5F5FFFFFFFFFF505050FF000000FF000000FF000000FF0000 00FF111111EEDFDFDF2000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000EEEEEE114D4E4FC0171C 24FF171C24FF141820FF161A24FF1F272EFF15192DFF12152BFF050948FF0405 3CFF0A0B11FF070719FF040518FF38393FCFDADADA2500000000000000000000 000000000000000000000000000000000000000000000000000000000000EBEB EB143D3E41CE191F27FF20252DFF4A5059FF646E86FF6979A5FF8F969FFF7881 8CFF6E7581FF757A7EFF2D365BFF384059FF9797986DFCFCFC03000000000000 000000000000000000000000000000000000FBFBFB047E7E7E850C0D0FFF1012 17FF11141AFF12161BFF0D1016FF060A45FF08104FFF363941FF383C45FF262B 33FF171C32FF0D144AFF1B1E24FE6C6D709DF3F3F30C00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000EDEDED124C4C4CB3000000FF000000FF4855 56FEBBDFE2FFC3E8ECFFC5E9ECFFA9CACCFF94B0B3FFAAC7C9FFC9ECEDFFCFF2 F5FFC9EEF2FFC3E8ECFFC0E5E9FFC6EBEDFFD0F3F5FFCAEDF0FFC4E9ECFFC6EA EDFFC6EBEEFFCAEEF1FFC5EAEDFFC2E7EAFFC6EAEDFFC8EDF0FFCCF0F4FFCDF1 F4FFCDF1F3FFC8ECEFFFC7EBEFFFCCEFF1FFC8ECF0FFC9EDF1FFC6EBEEFFC4E8 ECFFCBEEF1FFCDF1F3FFC3E8ECFFC2E6EAFFBFE4E9FFC4E9ECFFC0E1E4FFA9C7 CAFF97B3B6FF90AAACFF88A2A5FF849FA1FF87A1A3FF212728FF000000FF0000 00FF000000FF000000FF000000FF020303FF546364FF8BA5A7FF8AA3A5FF8CA6 A8FF86A0A3FF849EA0FF839DA0FF86A0A3FF88A1A4FF374344FF000000FF0000 00FF000000FF323B3CFF92ACAEFF88A2A4FF86A0A2FF88A2A4FF8CA5A8FF89A2 A5FF89A1A4FF778D90FF1E2323FF000000FF000000FF3E3E3EC1E8E8E8170000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000484848B7000000FF272B2EFEC8DFEEFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD7F0FFFFD2EAF9FF000000FF000000FF000000FF1113 14FFC1D7E6FFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD5EEFEFFD6EFFFFFDCF5FFFFD7F0FFFFD5EEFEFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD5EEFEFFD6EFFFFFD5EEFEFFA5B7C4FFAABFCBFFD6F0 FFFFD6EFFFFFD6EFFFFFD6EFFFFFD5EEFFFFBFE5FFFFAFDFFFFFB0E0FFFFB0E0 FFFFB5E7FFFF3B4C56FF050708FF000000FF000000FF276F71FF47C7CCFF4CD5 DAFF4BD3D8FF4BD3D8FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4DD8DDFF3698 9CFF000000FF000000FF9A9A9A65000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000DFDF DF20000000FF000000FF000000FF000000FF020202FF747474FFFCFCFCFFF5F5 F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF6F6F6FFA8A8A8FF000000FF0000 00FF010101FF262626FF2B2B2BFF000000FF000000FF000000FF000000FFABAB ABFFF7F7F7FFF5F5F5FFF4F4F4FFFFFFFFFF9B9B9BFF080808FF000000FF0000 00FF000000FF000000FF000000FF000000FF000000FF191919FF343434FF0707 07FF000000FF000000FF515151FFECECECFFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF4F4F4FFF8F8F8FFCCCCCCFF0B0B0BFF000000FF000000FF010101FE0000 00FF5F5F5FA00000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000F5F5F50A505152BC1518 1FFF141721FF0E1123FF0F1240FF151935FF171B28FF1E2227FF151718FF0A0B 3CFF191D23FF14171CFF101316FF0E1013FFA2A2A25FFEFEFE01000000000000 000000000000000000000000000000000000000000000000000000000000F5F5 F50A4D4E51C5252932FF383B46FF596484FF567EB6FFCACFD4FF959DA8FF9097 A3FF99A2AEFF747D8BFF4A505AFF4D5159EEC9C9CA3800000000000000000000 000000000000000000000000000000000000F6F6F609525354B70D0F12FF1012 18FF101419FF0F1215FF12161AFF14181AFF11131FFF282A38FF3A3C45FF1418 2CFF141730FF11173AFF161825FF656669A4F4F4F40B00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000D0D0D02F1D1D1DE2000000FF0304 04FE7C9193FFCBEFF2FFC9EEF0FFCBF0F3FFC7ECF0FFC5EAEDFFC5E9EDFFCDF1 F2FFCEF1F4FFC7ECEFFFC3E8EBFFC3E8ECFFC6EBEFFFC4E8EDFFC7EBEFFFC8EC F0FFC4E8ECFFC1E5E9FFC0E5E9FFC3E9EDFFC3E8ECFFC8ECF0FFCAEEF1FFC4E9 EDFFBFE4E8FFC1E6E9FFC0E5E9FFC5E9EDFFC5E9ECFFC3E7EBFFC1E6E9FFC0E5 E8FFBFE5E9FFC0E5EAFFC0E6EAFFC4E8ECFFC7EAEDFFC7EBEEFFBEE3E7FFB1D3 D6FF9FBEC1FF93AEB0FF89A3A5FF859FA1FF89A2A4FF6B8082FF080909FF0000 00FF000000FF000000FF000000FF08090AFF6E8284FF91AAABFF8EA7A9FF89A2 A5FF89A3A6FF8CA5A7FF89A2A4FF89A3A5FF859DA1FF354142FF000101FF0000 00FF050606FF708486FF8CA5A7FF8AA2A5FF859FA2FF88A1A4FF8BA4A6FF89A3 A5FF7A9294FF2D3638FF010101FE000000FF2D2D2DD2CBCBCB34000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000E0E0E01F000000FF000000FF8D9EA8FFD9F3FFFFD5EE FEFFD6EFFFFFD6EFFFFFD5EEFEFFDBF5FFFF7C8A94FF000000FF000000FF2226 29FFDAF4FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD5EEFEFFD6EFFFFFD6EFFFFFD5EEFEFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD8F2FFFF6D7A82FF000000FF8A9AA4FFD7F1 FFFFD6EFFFFFD6EFFFFFD6EFFFFFD4EEFFFFBCE4FFFFAFDFFFFFB0E0FFFFB0E0 FFFFAFDFFEFFB2E3FFFF88AEC6FF506674FF050607FF000000FF102E2FFF3DAA AEFF4EDBE1FF4BD3D8FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4DD7DCFF3FAF B3FF000000FF000000FF8181817E000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000565656A9000000FF010101FE000000FF000000FF2D2D2DFFD8D8D8FFF5F5 F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFC8C8C8FF1D1D1DFF0000 00FF000000FF000000FF000000FF000000FF000000FF000000FF040404FFE1E1 E1FFF5F5F5FFF4F4F4FFFDFDFDFFABABABFF010101FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF8A8A8AFFF4F4F4FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFFDFDFDFF656565FF000000FF000000FF000000FF000000FF0000 00FFEBEBEB140000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000F9F9F9066F6F7099181B 23FF191E24FE10151FFF0A1256FF1A1D2BFF131614FF161B27FF0B0F51FF0C0C 27FF151924FF13161CFF0F1114FF060607FF5F6060A8F6F6F609000000000000 000000000000000000000000000000000000000000000000000000000000FDFD FD027A7A7B8D3E414BFF848A96FE939DABFF6A7588FF75839CFF7A8494FF94A1 B3FFACB4BEFFA8B1BCFE959EA9FF7C7F84B4EBEBEB1400000000000000000000 000000000000000000000000000000000000EBEBEB14343637D4101217FF1216 1DFF0F1116FF0F1114FF111519FF14191CFF0D1033FF282C53FF2D323FFF262B 37FF2B2F36FF222831FF13171CFF6E707297F7F7F70800000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000009595956A030303FC0000 00FF1D2223FF9BBABEFFBEE3E8FFC7ECF0FFCBF0F2FFC3E9EDFFC0E5E9FFC0E6 E9FFC5EAECFFC9EDF1FFCEF1F4FFC3E8ECFFBFE5E9FFC6EAEEFFC8ECEFFFC7EC EFFFC4E8ECFFBEE3E7FFC0E5E9FFC3E7EBFFC5E9EDFFC4E9EDFFC1E6EAFFBEE3 E7FFBCE1E6FFC3E7ECFFC6EBEEFFC4E9ECFFCDF1F4FFCFF3F6FFC2E8ECFFBBE1 E5FFB8DEE4FFBFE5E9FFCCF0F3FFCEF1F4FFCCEFF3FFCEF2F5FFC8ECEFFFC2E4 E8FFABCBCFFF93B0B3FF87A2A5FF869FA2FF86A0A2FF859EA0FF495658FF0101 01FF000000FF000000FF000000FF0C0E0EFF7D9395FF8EA8AAFF8DA6A9FF88A2 A4FF89A2A5FF8DA6A8FF93ACAEFF809597FF374243FF020303FF000000FF0000 00FF3E4A4AFF89A2A4FF86A1A3FF859EA2FF8BA4A7FF8CA5A8FF87A1A4FF859F A1FF3D4747FF020202FE000000FF141414EBB3B3B34CFEFEFE01000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000007474748B000000FF0D0E0FFEDBF4FFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD1E9F9FF717E87FF2A2E31FFAFC4 D1FFD9F2FFFFD5EEFEFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD5EEFEFFD5EEFEFFD7F0FFFF5F6A71FF010202FF0C0D0EFFAEC2CFFFD7F0 FFFFD6EFFFFFD6EFFFFFD6EFFFFFD3EEFFFFB8E3FFFFAFDFFFFFB0E0FFFFB0E0 FFFFAFDFFEFFB0E0FFFFB1E1FFFFAFDFFDFF92B9D3FF171D21FF000000FF0612 13FF389EA2FF4CD5DAFF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD6DBFF43BB BFFF000000FF000000FF7474748B000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000DCDCDC23000000FF000000FF000000FF000000FF000000FF9B9B9BFFF5F5 F5FFF4F4F4FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFE5E5E5FF393939FF0000 00FF000000FF000000FF000000FF000000FF000000FF000000FF1C1C1CFFE6E6 E6FFF5F5F5FFF7F7F7FFDADADAFF0C0C0CFF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF060606FFB2B2B2FFF6F6F6FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF5F5F5FFD1D1D1FF252525FF000000FF000000FF010101FE000000FF5D5D 5DA2000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FCFCFC038A8A8B770F11 14FF09091CFF090E4EFF151C2DFF15192BFF04065DFF021083FF151936FF2126 2CFF0F1427FF161C23FF111419FF0E0F12FF232426E6E5E5E51A000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000C7C7C738525963FFC2CAD1FFC1C9CFFE98A1AFFF22306EFF303F87FFB7BE C1FEB0B8C0FFA1AAB5FF75797ED7CCCCCC33FDFDFD0200000000000000000000 000000000000000000000000000000000000DBDBDB24242428E70E1114FF0F12 15FF0E1017FF0E1115FF0F1115FF0D1017FF0C0C1EFF181A1BFF292E34FF2E34 3CFF252931FF222A31FF1F242CFA8A8B8C7BFAFAFA0500000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000EEEEEE114E4E4EB10101 01FE010101FE4E5C5DFFC5E8EAFFD2F4F7FFCDF1F4FFC8ECF0FFC8EDF0FFBFE5 E8FFBFE4E8FFCDF0F3FFCEF2F5FFC8EDEFFFBEE3E7FFC2E6EAFFCAEEF2FFCAEE F2FFC9EDF0FFC1E6EAFFBFE5E9FFC1E6EAFFBCE2E7FFBAE0E4FFBDE3E7FFC1E6 EAFFC6EBEEFFC7ECEFFFC0E6EAFFC3E8EBFFCAEFF1FFD1F4F6FFD3F5F8FFD1F4 F7FFC9EEF1FFC5EAEDFFC5E9EDFFC5EBEEFFC8ECF0FFC5E9EDFFC9EDF1FFCDF0 F3FFBFE0E3FFA3C1C5FF92ACB0FF8DA7AAFF8DA6A9FF8BA4A6FF8DA6A7FF3740 42FF000000FF000000FF000000FF010101FF262D2EFF57696AFF73898CFF778C 8EFF778C8EFF708688FF465456FF0D1011FF000000FF000000FF000000FF1E24 25FF7F989AFF87A2A4FF8BA3A6FF89A3A5FF8CA6A8FF8EA7A9FF88A1A3FF4D5B 5DFF010101FE000000FF0C0C0CF39393936C0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000EEEEEE11191919E6000000FF5D686FFFDCF6 FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFDAF4FFFFDEF9FFFFD7F0 FFFFD5EEFEFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD5EEFEFFD6EF FFFFD7F0FFFFCBE3F2FF4C555BFF000000FF000000FF2C3135FFDEF8FFFFD6EF FFFFD6EFFFFFD6EFFFFFD5EFFFFFD3EDFFFFB4E1FFFFAFDFFFFFB0E0FFFFB0E0 FFFFB0E0FFFFB0E0FFFFB0E0FFFFAFDFFEFFB1E2FFFF8AAFC8FF090C0EFF0000 00FF071616FF44BEC2FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD6DBFF41B7 BBFF000000FF000000FF7575758A000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F9F9F906535353AC000000FF010101FE000000FF000000FF393939FFEBEB EBFFF4F4F4FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFFDFDFDFF5C5C5CFF0000 00FF000000FF000000FF000000FF000000FF000000FF000000FF181818FFE6E6 E6FFF4F4F4FFFCFCFCFF898989FF040404FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF252525FFD0D0D0FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFF4F4F4FF909090FF000000FF000000FF000000FF000000FF000000FFD8D8 D827000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FDFDFD029494956D1114 19FF111619FF14171AFF12182FFF21283CFF202432FF1B1C2CFF33383EFF2325 33FF111421FF0E1021FF0F111AFF0E0F14FF0F1013FBC3C3C33C000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F5F5F50A888A8D9899A1A8FFB8C0CAFF909AA6FE3D4975FE5C6986FEB4BC C3FF9DA5AEFF767B7FCBC4C4C43BFDFDFD020000000000000000000000000000 0000000000000000000000000000FEFEFE01C0C0C041191A1EF10F1011FF0909 0DFF070716FF070810FF08090FFF0A0B19FF292E43FF32406BFF283A78FF2932 47FF22292FFF21272EFF1E242AF89C9C9D69FDFDFD0200000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000BEBEBE411818 18E7000000FF0B0D0DFE869FA2FFC8EDF1FFC7EAEEFFC4E9EBFFC4E9EDFFC6EB EFFFC8ECEFFFCBEFF2FFCAEDF1FFC7EBEFFFC3E8ECFFC1E6EAFFC1E6EAFFC4E8 ECFFC5E9EDFFC9EDF0FFCCF0F2FFCDF0F4FFC9ECF0FFC9EDEFFFC6EAEDFFC7EC EFFFCAEEF1FFC2E7EAFFC2E6EAFFC0E5E9FFB9DFE3FFC0E4E9FFC9EDF1FFCCF0 F3FFCBEFF2FFC7EBEFFFC1E7EBFFC2E7EBFFC6EAEEFFC1E5EAFFBFE5E9FFC3E7 ECFFC5E8EBFFB7D6D8FFA1BDBFFF90ABADFF8CA6A9FF8AA3A6FF8AA4A6FF89A1 A4FF414D4EFF020303FF000000FF000000FF000000FF000000FF080A09FF0B0D 0DFF0B0D0DFF070909FF000000FF000000FF000000FF000000FF212728FF7A91 93FF8DA7A9FF8BA4A7FF8BA4A6FF88A2A5FF89A2A5FF86A0A2FF5A6B6DFF0C0E 0FFE000000FF040404FB7F7F7F80F9F9F9060000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000009292926D040404FB060607FFA6BA C6FFD7F1FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD5EEFEFFD6EF FFFF8C9CA6FF1F2224FF000000FF000000FF000000FFABBFCCFFDAF3FFFFD5EE FEFFD6EFFFFFD6EFFFFFD6EEFFFFD1EDFFFFAFDFFFFFAFDFFFFFB0E0FFFFB0E0 FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFAFDFFEFFB9EBFFFF3C4D57FF0000 00FF000000FF226062FF4DD9DEFF4CD4D9FF4CD4D9FF4CD4D9FF4DD7DDFF3BA4 A8FF000000FF000000FF8C8C8C73000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000B2B2B24D070707F8000000FF000000FF000000FF000000FFB8B8 B8FFF7F7F7FFF5F5F5FFF5F5F5FFF5F5F5FFF4F4F4FFFCFCFCFF939393FF0606 06FF000000FF000000FF000000FF010101FF000000FF000000FF000000FFDDDD DDFFF5F5F5FFFBFBFBFF9E9E9EFF010101FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF060606FF000000FF000000FF0000 00FF000000FF414141FFEFEFEFFFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF4F4 F4FFECECECFF2A2A2AFF000000FF000000FF010101FE000000FF595959A6FAFA FA05000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FDFDFD0299999A691418 1EFF15191DFF111426FF1A2029FF2F3237FF363C42FF1F2359FF07158AFF1619 23FF1E2229FF161922FF0F1115FF0F0F11FF090A0DFF8F8F8F76000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FEFEFE01EAEAEA159B9C9D7463686DE68E95A0FFA8B3C2FFA4ADB7FF7983 8BFF727579C0D1D1D12EFCFCFC03000000000000000000000000000000000000 0000000000000000000000000000FBFBFB049F9F9F660F1012F708080EFE0303 17FF05050BFF060619FF040421FF0C0E19FF161A25FF121627FF06166BFF0A0D 2CFF0F1322FF13151DFE1E1F26F2BDBDBD44FEFEFE0100000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000008484 847B000000FF000000FF22292AFEA5C5C9FFC2E7EBFFC0E5E9FFC5EAEEFFCCF0 F2FFCCF0F3FFC7ECEFFFC3E7EBFFBDE2E7FFC2E7EBFFCCEFF3FFC4E8ECFFBDE2 E6FFC0E5E9FFC9ECF0FFC2E7EBFFBDE2E6FFC8ECEFFFCAEEF0FFC6EBEEFFC5E9 ECFFC5EAEDFFC6EBEEFFC9EDF0FFCAEEF1FFC5EAEDFFC0E5E9FFC3E7EBFFC7EC EFFFC6EAEEFFC0E5E9FFBEE4E8FFC1E6EAFFC6EBEFFFC6EAEEFFC0E6E9FFBDE2 E7FFC0E5E9FFB9DBDFFFAAC8CBFF9BB6B8FF91A9ABFF89A2A5FF859FA1FF86A0 A3FF829A9DFF5A6B6DFF0A0B0CFF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF000000FF333D3EFF7B9295FF869F A2FF839EA0FF839DA0FF859FA2FF869FA3FF849FA2FF64777AFF111516FF0101 01FE020202FD5E5E5EA1EFEFEF10000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000E0E0E01F141414EB000000FF3C43 48FFCFE7F6FFD5EEFEFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFDAF4FFFF707D 85FF000000FF000000FF000000FF000000FF606B73FFDBF4FFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFCBEAFFFFAEDFFFFFAFE0FFFFB0E0FFFFB0E0 FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFAFDFFEFFB4E5FFFF7595AAFF0000 00FF000000FF0C2223FF4FDDE2FF4CD4D9FF4CD4D9FF4CD4D9FF4EDADFFF2D7F 83FF010101FE000000FFBCBCBC43000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000EFEFEF103B3B3BC4000000FF000000FF000000FF000000FF2F2F 2FFFFFFFFFFFF4F4F4FFF5F5F5FFF5F5F5FFF5F5F5FFF8F8F8FFCFCFCFFF0D0D 0DFF000000FF000000FF080808FF6D6D6DFF000000FF000000FF000000FF7878 78FFFCFCFCFFF5F5F5FFF8F8F8FF565656FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF1A1A1AFF5C5C5CFF000000FF0000 00FF010101FF6A6A6AFFFDFDFDFFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF7F7 F7FFA9A9A9FF000000FF000000FF000000FF000000FF040404FBB3B3B34C0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FEFEFE01A7A7A8591116 19FF0E132DFF0E0F21FF111734FF11164BFF1A1F3FFF23283CFF232832FF4146 50FF171C23FF191E25FF0F1115FF0F0F0FFF0A0A0BFF6B6B6B9FF8F8F8070000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000FBFBFB04D9D9D92687888987808284C07C7D7D95AFAF AF50EEEEEE11FEFEFE0100000000000000000000000000000000000000000000 0000000000000000000000000000EDEDED125D5D5DA70A0A0AFE0C0C0DFF0D0E 0EFF0E0F11FF111517FF1C2124FF434752FF454B57FF30353DFF2A2E31FF252A 2FFF21292EFF1B1F27FF303235DEE3E3E31C0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000ECEC EC133B3B3BC4000000FF000000FF49595AFFB8DDE1FFBEE4E8FFC4E9ECFFC6EB EEFFC6EAEEFFBEE3E7FFBBE1E5FFC2E7EAFFBDE2E7FFB9DFE3FFBEE4E9FFBDE2 E7FFC1E6EAFFC8EDEFFFC9ECF0FFC5E9EDFFC2E7ECFFC3E8EBFFC7EBEFFFCCF0 F4FFCAEFF2FFD0F3F6FFCCEFF3FFC6EBEDFFCCEFF3FFC6EBEFFFC3E7EBFFC2E7 EAFFC7EBEEFFC7ECEFFFC5EAEDFFC2E6EAFFC4E8ECFFCAEEF2FFC8ECF0FFC4E8 ECFFBBE1E6FFB7DBDFFFABCCD0FF97B4B7FF8DA8AAFF92AAACFF90A9ABFF8CA5 A7FF8BA5A7FF8EA8AAFF819799FF3F4A4CFF121616FF060808FF030303FF0101 02FF020202FF030404FF080909FF1E2324FF5B6C6EFF87A1A4FF839EA1FF88A1 A3FF8AA3A6FF87A1A4FF879FA2FF8AA3A6FF7A9092FF1F2626FE000000FF0000 00FF404040BFE0E0E01F00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000009C9C9C63040404FB000000FF0000 00FF8798A2FFDAF3FFFFD5EEFEFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD5EEFEFFD6EFFFFFD5EEFEFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFBBD1 DFFF101213FF000000FF000000FF212427FFCBE3F2FFD5EEFEFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFC2E7FFFFAEDFFFFFB0E0FFFFB0E0FFFFB0E0 FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFAFDFFEFFB4E5FFFF7798ADFF0000 00FF000000FF0C2323FF4FDDE2FF4CD4D9FF4CD4D9FF4BD3D8FF4FDEE3FF1A49 4AFF000000FF060606F9E8E8E817000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000008E8E8E71050505FA010101FE000000FF000000FF0000 00FFBABABAFFFAFAFAFFF4F4F4FFF5F5F5FFF5F5F5FFF5F5F5FFFFFFFFFF2222 22FF050505FF0F0F0FFFAAAAAAFF666666FF000000FF000000FF000000FF0000 00FFC3C3C3FFF7F7F7FFF5F5F5FFFFFFFFFF9E9E9EFF1F1F1FFF040404FF0000 00FF000000FF000000FF000000FF000000FF101010FFC7C7C7FF383838FF0606 06FF0E0E0EFFAEAEAEFFFAFAFAFFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFFBFB FBFF242424FF000000FF000000FF000000FF000000FF3D3D3DC2EDEDED120000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000B9B9B9471518 1FF80C0E17FF0B0F34FF12163BFF202B4CFF2E353EFF3A4049FF3D434BFF4A51 5DFF171D22FF191E25FF12161BFF0F1012FF0C0C0DFF333334D6E5E5E51A0000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000FEFEFE01FAFAFA05FCFCFC030000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000C8C8C83819191AEE0C0E10FF0F1217FF0F13 18FF12161BFF161B23FF2C3239FF4C5460FF494E5BFF3D424CFF3B3E48FF252A 31FF191B22FF191C23FF4E4F51BCF3F3F30C0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000BFBFBF401B1B1BE4000000FF0A0D0DFF89A1A4FFCBF0F3FFC9EDF0FFC5EA EDFFC5EAEEFFC3E8ECFFC3E8ECFFC8ECEEFFCDF1F4FFCAEEF1FFCAEEF1FFC6EB EEFFC4E9EDFFC6EBEFFFCDF1F4FFCEF1F4FFC7EBEEFFC5E9ECFFC4E8ECFFC4E8 ECFFC4E9EDFFC7EBEEFFCCEFF2FFCEF1F4FFCBEFF2FFC3E8EDFFC0E4E9FFC1E5 E9FFC5E9EDFFC9EDEFFFCEF3F4FFCCEFF1FFC6EBEEFFC5EAEEFFC6EBEEFFC7EC F0FFC8ECF0FFC8ECEFFFB9DBDFFFA3C2C6FF91AEB1FF8DA6A8FF8CA4A6FF8CA4 A6FF88A1A3FF849EA0FF87A1A3FF8BA5A7FF7E9698FF65797BFF546465FF505E 5FFF576667FF5C6E70FF728688FF87A0A2FF8DA8ABFF8AA3A6FF8BA4A7FF8AA3 A5FF88A1A4FF88A2A4FF89A3A5FF7F9698FF2D3636FF000000FF000000FF3030 30CFD7D7D7280000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000F9F9F906575757A8000000FF2D6166FF0000 00FF030304FFB2C7D4FFDBF4FFFFD5EEFEFFD5EEFEFFD6EFFFFFD8F1FFFFDBF4 FFFFDEF8FFFFE0FBFFFFE2FCFFFFDCF6FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD5EEFEFFD7F0 FFFFA5B8C4FF181B1DFF060707FF9BAEB9FFD7F0FFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD5EEFFFFD7EFFFFFB8E3FFFFAFDFFFFFB0E0FFFFB0E0FFFFB0E0 FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFAFDFFEFFB9ECFFFF475B67FF0000 00FF000000FF163F40FF4EDBE0FF4CD4D9FF4CD4D9FF4CD4D9FF4CD5DAFF0919 1AFF000000FF3B3B3BC4F2F2F20D000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000F2F2F20D1A1A1AE5000000FF000000FF000000FF0000 00FF393939FFFCFCFCFFF5F5F5FFF5F5F5FFF5F5F5FFF4F4F4FFF9F9F9FFC5C5 C5FF909090FFD4D4D4FFD6D6D6FF1D1D1DFF000000FF000000FF000000FF0000 00FF0B0B0BFF959595FFDFDFDFFFFCFCFCFFFFFFFFFFF3F3F3FF959595FF3B3B 3BFF000000FF000000FF000000FF000000FF050505FF838383FFEDEDEDFF9E9E 9EFF979797FFF7F7F7FFF5F5F5FFF5F5F5FFF5F5F5FFF4F4F4FFFCFCFCFFADAD ADFF000000FF000000FF000000FF010101FE040404FB8C8C8C73000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000C8C8C8381D1F 32EB10131EFF181D24FF262C32FF383E48FF434954FF454D57FF3C404AFF555E 6BFF232930FF15181EFF101318FF0E0E10FF0D0D0DFF131313F2B5B5B54DFDFD FD02000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000FDFDFD02909090730E0F10FF0E0E0FFF0F1014FF1015 18FF181E23FF1C2527FF232B2DFF41474CFF43494FFF3F444EFF393D45FF262B 31FF20272CFF1A1F27FF6C6C6E9CFBFBFB040000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F9F9F9067B7B7B84030303FC010101FE2E3637FFB5D4D6FFC8ECF0FFBCE1 E6FFC1E6EAFFCCF0F3FFD0F3F5FFCFF2F5FFCEF1F4FFCAEEF2FFC1E6EAFFC1E6 E9FFC7EAEEFFC6EAEEFFBEE4E8FFC5EAEEFFC8EDF0FFC2E6EAFFC7EBEEFFC2E8 EBFFBBE1E6FFBFE5E9FFBEE2E6FFC1E6EAFFC2E7EBFFC5EAEDFFC5E9EDFFBBE1 E5FFBAE0E5FFC2E7EBFFC9EEF1FFCDF1F4FFC6E9EDFFBEE3E6FFC1E6EAFFC5E9 EEFFC8ECF0FFC7ECEFFFC7E9ECFFB2D3D6FF98B6B9FF8EA9ACFF8CA5A7FF88A1 A4FF89A3A5FF8AA4A6FF86A0A3FF88A1A5FF8CA5A7FF8CA4A6FF839DA0FF819B 9EFF8CA5A7FF8DA7AAFF8BA5A7FF88A1A4FF85A0A3FF89A2A5FF8CA4A7FF8BA4 A6FF8FA8AAFF93ABACFF8CA3A5FF3F4A4BFF020303FE000000FF1C1C1CE3C0C0 C03F000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000EBEBEB141A1A1AE5040809FF72F2FFFF2957 5CFF000000FF202326FFCBE2F2FFD6EFFFFFD6EFFFFFDAF4FFFFBCD3E1FF92A3 AEFF67747CFF3F464BFF1E2123FF7E8D96FFD5EEFEFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD7F0FFFFC5DBEAFFC0D7E5FFD5EEFEFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFAEDFFFFFAFDFFFFFB0E0FFFFB0E0FFFFB0E0 FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E0FFFFB0E1FFFF9FCBE6FF101518FF0000 00FF000000FF2C7D81FF4DD7DCFF4CD4D9FF4CD4D9FF4CD5DAFF3CAAAEFF040C 0CFF000000FF7878788700000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000008383837C000000FF010101FE000000FF0000 00FF070707FFB4B4B4FFFAFAFAFFF4F4F4FFF5F5F5FFF5F5F5FFF4F4F4FFF8F8 F8FFFDFDFDFFCACACAFF232323FF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF303030FF656565FFA9A9A9FFF0F0F0FFFFFFFFFFE5E5 E5FF858585FF000000FF000000FF000000FF000000FF040404FF848484FFFEFE FEFFFBFBFBFFF5F5F5FFF4F4F4FFF5F5F5FFF5F5F5FFF5F5F5FFFAFAFAFF2B2B 2BFF000000FF000000FF000000FF000000FF151515EAF3F3F30C000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000D3D3D32D2628 30E415191FFF1B2128FF22292FFF252B32FF343B42FF404750FF3E444DFF4F58 64FF333942FF161920FF121519FF0E0E0FFF050505FF040404FF575757ACF0F0 F00F000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000F4F4F40B565657B30B0C0DFF0D0D0DFE0E1115FF1114 1EFF121731FF0E1140FF0C1759FF1D2C6BFF2C3761FF383E46FF343A42FF242B 31FF1C2128FE13161DFF90908F74000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000E1E1E11E333333CC000000FF000000FF5D6E6FFFC8EDF0FFC8ED F0FFBEE4E8FFBCE2E6FFC0E6EAFFC5EBEEFFC4E8ECFFC3E8ECFFC8ECEFFFCBEF F2FFC4E8EDFFBFE4E8FFBDE2E7FFBEE5E9FFC5EBEEFFC7ECF0FFC3E9EDFFC3E9 ECFFC4E8EDFFC0E5E9FFBFE5EAFFB8DEE3FFBDE2E7FFC8ECF0FFCCF0F4FFCDF1 F4FFC6EBEFFFC8ECEFFFC6EBEEFFC5EAEDFFC1E6EAFFBDE2E7FFC3E8ECFFC9EE F0FFC8ECF0FFBFE4E9FFC0E5E8FFBFE2E5FFACCDD0FF95B2B5FF8CA6A8FF8DA6 A8FF8EA7A9FF8CA5A7FF8CA6A8FF8DA7AAFF8FA8AAFF90A9ACFF8CA5A7FF85A0 A3FF85A0A3FF8DA6A8FF8AA4A6FF89A2A5FF8BA3A6FF8EA6A9FF8BA4A7FF87A1 A5FF88A1A4FF89A1A4FF506060FF030404FE000000FF121212EDA4A4A45BFEFE FE01000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000D2D2D22D000000FF275357FF75F7FFFF66D8 E4FF0E1D1FFF000000FF566067FFD3EBFBFFCFE7F6FF4A5359FF020202FF0000 00FF000000FF000000FF000000FF2C3134FFCAE1F0FFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD7F0FFFFCDECFFFFB0E1FFFFB1E2FFFFB1E1FFFFB1E1FFFFB0E1 FFFFB0E1FFFFB0E1FFFFB1E1FFFFB1E2FFFFA7D4F2FF40515DFF000000FF0000 00FF03090AFF45C1C5FF4BD3D8FF4CD4D9FF4CD4D9FF4CD5DAFF2A787BFF0101 01FE0B0B0BF4BABABA4500000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000FCFCFC03050505FA000000FF000000FF0000 00FF000000FF535353FFF6F6F6FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFDFDFDFFF171717FF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF080808FF1A1A1AFF8A8A8AFFF8F8 F8FFF1F1F1FF818181FF000000FF000000FF000000FF000000FF000000FF8888 88FFF9F9F9FFF5F5F5FFF5F5F5FFF5F5F5FFF4F4F4FFFBFBFBFFA7A7A7FF0808 08FF000000FF000000FF010101FE000000FF7B7B7B8400000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000E2E2E21D4144 45C914191EFF161D21FF1C252BFF252F33FF272E34FF282F35FF2F363CFF4048 51FF343B44FF0F1315FF0C0D0FFF0A090AFF040404FF040404FF242424E0D1D1 D12E000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000D2D2D22D232323E7050505FF080808FF0E0F11FF1317 1BFF1A1E21FF222A2BFF464E51FF4C5259FF3D4552FF303748FF282F3AFF1F26 2EFF20262DFF13171CFFBFBFBF40000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000AEAEAE510E0E0EF1000000FF0A0C0CFE8FAAACFFCBF0 F3FFC4E8ECFFC5EAEDFFC3E8EBFFC2E7EBFFC7ECEFFFCCEFF2FFCFF1F5FFCBF0 F3FFC2E7EBFFBEE3E8FFC3E8ECFFC5E9ECFFC6EBEEFFC9EEF0FFC4E9EDFFC9ED F0FFD0F4F7FFCBEFF2FFC9EDF0FFC9EDF1FFC6EBEFFFC9EDF0FFC5EAEDFFC3E8 ECFFC8EDF0FFC4E9ECFFBCE3E7FFBDE2E7FFC0E5E9FFC3E8EBFFC1E6EAFFC4E9 ECFFC5E9ECFFC0E5EAFFC1E6EAFFC8ECEFFFBEE0E2FFA2C0C3FF8EA9ACFF849E A1FF819B9EFF829C9FFF87A0A3FF8DA6A8FF8BA5A8FF89A3A6FF8CA6A7FF8EA8 A9FF859FA2FF839DA0FF8AA3A5FF8DA7A8FF8CA5A8FF8EA7A9FF8AA3A6FF8AA3 A6FF89A3A6FF566769FF090B0BFE000000FF030303FC88888877FEFEFE010000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000098989867000000FF428B93FE73F3FFFF74F6 FFFF5ABFC9FF030708FF000000FF77858EFFE0FAFFFFDAF3FFFFAFC4D1FF7380 89FF373D41FF000000FF000000FF222729FFC8DFEEFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD5EE FEFFDAF4FFFFB3C7D5FF758C9BFF607A8BFF698597FF7B9CB2FF8AAFC8FF91B9 D2FF90B8D1FF8CB2CAFF85A9C0FF6F8EA2FF303D46FF000000FF000000FF0000 00FF276F71FF4BD2D7FF4BD3D8FF4CD4D9FF4BD3D8FF49CDD2FF174042FF0000 00FF232323DCFDFDFD0200000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000088888877000000FF000000FF0000 00FF000000FF191919FFC4C4C4FFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFFAFA FAFF7B7B7BFF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF3E3E 3EFFF1F1F1FFDFDFDFFF323232FF000000FF000000FF000000FF000000FF0303 03FFFFFFFFFFF5F5F5FFF5F5F5FFF5F5F5FFF5F5F5FFF3F3F3FF4A4A4AFF0000 00FF000000FF000000FF000000FF040404FBFBFBFB0400000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000F0F0F00F5F5E 60A70F1317FF0F1319FF161B20FF192026FF20282EFF272F34FF353D44FF444D 59FF343A45FF101417FF0C0C0DFF040404FF040404FF030303FF060607FF9F9F 9F62FEFEFE010000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000FCFCFC03757576900A0A0BFF0C0C0CFF0D0F10FF0E0F12FF1317 1CFF1B2329FF303940FF565F6CFF5C6674FF4D5460FF494F5AFF2D353AFF242D 33FF181F25FF333536DCE1E1E11E000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000FCFCFC037B7B7B84000000FF000000FF293133FFB0D1 D4FFC9EDF1FFBFE5EAFFBCE3E7FFBFE4E9FFC9EDF0FFCDF1F4FFC5E9ECFFC4E8 EBFFD0F2F5FFD0F3F5FFCCF0F2FFCAEDF1FFC3E8ECFFBEE3E8FFBEE3E7FFC2E6 EAFFC7EBEEFFC4E9EDFFBFE5E9FFC3E8EBFFC6EAEEFFCDF1F4FFC8ECF0FFC6EC EFFFC8EDF0FFC1E6EAFFBDE2E6FFBDE3E7FFC4E9ECFFCBEEF2FFC9EDF1FFC4E9 ECFFC4E9ECFFC9EDF1FFC8ECF0FFC5EAEDFFBBDEE1FFB0CFD2FFA0BBBDFF8CA7 AAFF88A1A4FF89A2A5FF89A2A6FF89A2A5FF8AA3A5FF86A0A3FF839DA0FF8BA4 A7FF92AAABFF8DA6A8FF8CA6A8FF8BA4A6FF89A2A5FF849EA1FF839DA0FF869F A2FF66797BFF0F1212FF000000FF010101FE7272728DF8F8F807000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000079797986000000FF499CA4FF72F2FFFF70EE FBFF72F2FFFF53B1BBFF000000FF000000FF7B8A93FFE3FDFFFFDAF3FFFFD7F0 FFFFCCE4F4FFBDD2E1FF6D7982FF7B8992FFD2EBFBFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD5EEFEFFDCF6 FFFF77858DFF090A0AFF000000FF040A0BFF040909FF020000FF070507FF0A0B 0DFF0B0E10FF0A0D0EFF080A0CFF030304FF000000FF000000FF000000FF266C 6FFF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D8FF44BEC3FF010303FE0000 00FF8B8B8B740000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000EBEBEB14101010EF000000FF0101 01FE000000FF000000FF7A7A7AFFF2F2F2FFF4F4F4FFF5F5F5FFF5F5F5FFF9F9 F9FF7D7D7DFF000000FF000000FF000000FF000000FF000000FF010101FF1F1F 1FFF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF666666FFFFFFFFFF696969FF000000FF000000FF000000FF000000FF0101 01FFFFFFFFFFF5F5F5FFF5F5F5FFF5F5F5FFF6F6F6FFBEBEBEFF121212FF0000 00FF000000FF010101FE000000FF7F7F7F800000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000F8F8F8077173 749613181DFF20252CFF262F34FF252E33FF30373CFF343941FF3A4048FF4349 53FF464E59FF181D23FF0B0A0CFF050505FF040404FF060606FF040405FF6868 689BF1F1F10E0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000E3E3E31C29292AE00C0C0CFF0A0B0BFF0F1115FF13181EFF151B 21FF252C32FF363D44FF4B535EFF4F5865FF4B535FFF3D444CFF2A3138FF1A1F 25FF13171DFF444546C6F1F1F10E000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000E4E4E41B343434CB000000FF040404FE5F72 74FFC6E9ECFFCCF0F2FFCBEEF0FFC2E7EBFFBFE4E8FFC1E5EAFFBEE3E7FFC4E9 EDFFCDF1F4FFC8ECEFFFC1E7EAFFC4E9EDFFC6EBEFFFC4E7EBFFCAEEF0FFC7EB EEFFC4E8EBFFC9ECEFFFCBEEF0FFC4E8EDFFBDE3E7FFBBE0E5FFBFE5E9FFC1E6 EAFFC3E8EBFFC8EBEFFFCCEFF3FFC8ECEFFFC9EDF0FFCAEDF1FFCAEEEFFFC2E6 EAFFC3E7EBFFC5EAEDFFC4E9EDFFBDE2E7FFB5DADFFF9EBEC0FFA0BFC1FF92AC AFFF8EA7AAFF8DA6A8FF859FA2FF819B9FFF839EA0FF86A0A3FF88A2A4FF869F A2FF87A1A3FF86A0A3FF839DA0FF7F9A9DFF7F9A9DFF7F999CFF86A0A2FF7186 89FF1B2021FE000000FF020202FD4F4F4FB0E9E9E91600000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000007B7B7B84000000FF3D838AFF73F3FFFF71EF FCFF70EEFBFF71EFFCFF367379FF000000FF030404FF636F76FF8797A1FFB7CD DAFFC9E1F0FFD6EFFFFFDBF5FFFFDAF3FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD5EEFEFFDAF3FFFFABBF CBFF000000FF000000FF2B797BFF51E3E8FF50E0E5FF47C5CBFF318A8DFF1B4B 4DFF091C1CFF061212FF050E0EFF050E0FFF071314FF133435FF3DADB1FF4EDB E0FF4BD3D8FF4CD3D8FF4CD4D9FF4BD3D8FF4EDADFFF225F61FE000000FF0303 03FC000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000FCFCFC037A7A7A85000000FF0101 01FE000000FF000000FF131313FFE7E7E7FFF4F4F4FFF5F5F5FFF5F5F5FFF6F6 F6FFC3C3C3FF000000FF000000FF000000FF000000FF000000FF5F5F5FFF9E9E 9EFF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF121212FFFFFFFFFF838383FF040404FF000000FF000000FF000000FF4949 49FFFCFCFCFFF5F5F5FFF5F5F5FFF4F4F4FFF0F0F0FF707070FF000000FF0000 00FF000000FF000000FF0F0F0FF0E6E6E6190000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000FBFBFB049F9F 9F6723292CF831383FFE3B414AFF3E424CFF383F47FF383E46FF33393FFF2E35 3CFF373E47FF101317FF080707FF030303FF040404FF050505FE030303FF1919 19EDA1A1A161FCFCFC0300000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FCFCFC03A4A4A45E141314F40B0B0CFF0F1012FF12161BFF14181EFF1A20 25FF1B2026FF3D434DFF525965FF434954FF434A55FF3F4753FF31363EFF1C23 33FE11141FFF6667689FF8F8F807000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000FEFEFE01A4A4A45B0E0E0EF1000000FF1317 17FE9CB9BBFFC4EAEDFFC4E9EDFFC7EBEFFFBFE5E9FFBDE3E7FFC8EDF0FFCDF1 F4FFC4E9ECFFC4E7EBFFC4E8ECFFC2E6EAFFC0E5E9FFC3E8EBFFC4E9ECFFC4E9 ECFFC0E5EAFFC6EAEDFFD0F3F5FFD0F3F6FFC8ECEFFFC0E5EAFFC6EBEEFFC8ED F0FFC3E7EBFFC4E9EDFFC8ECEFFFCCF0F3FFC8ECF0FFBFE5E9FFBFE4E9FFC3E8 EBFFC3E9ECFFC6EBEFFFC9EEF1FFC7ECEFFFC8EEF0FF88A2A6FF91AEB0FF9AB6 B9FF8DA7A9FF839DA0FF849FA2FF859FA2FF849EA1FF859EA1FF8BA4A6FF89A2 A5FF87A1A3FF86A1A2FF869FA2FF8AA4A6FF8CA5A7FF8EA8A9FF7E9495FF252C 2CFE010101FE000000FF383838C7D7D7D7280000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000009E9E9E61000000FF1F4246FE76FAFFFF70EE FBFF72F1FEFF65D6E2FF21474BFF000000FF020606FF000202FF000000FF0000 00FF282B2EFF6A777FFFC1D7E5FFDCF5FFFFD5EEFEFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD7F0FFFFCAE2F1FF2226 28FF000000FF1D4649FF4BD2D7FF4BD3D8FF4BD3D8FF4CD5DAFF4ED9DEFF4FDE E3FF4EDBE1FF45C2C6FF40B2B6FF40B3B7FF47C8CDFF4FDEE3FF4DD7DCFF4BD3 D8FF4CD4D9FF4CD4D9FF4BD3D8FF4CD6DBFF45C1C6FF010101FE000000FF8D8D 8D72000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000C6C6C639151515EA0000 00FF000000FF000000FF000000FF868686FFF9F9F9FFF4F4F4FFF5F5F5FFF5F5 F5FFE4E4E4FF0F0F0FFF000000FF000000FF000000FF000000FFA7A7A7FFF7F7 F7FF151515FF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF303030FFFFFFFFFF6C6C6CFF010101FF000000FF000000FF000000FF9696 96FFF8F8F8FFF5F5F5FFF5F5F5FFF4F4F4FFE4E4E4FF080808FF000000FF0000 00FF010101FE000000FF6F6F6F90FBFBFB040000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000FEFEFE01C4C4 C43C1B1F22F0181F24FF242A32FF353C44FF343B42FF32383FFF33363FFF3038 3EFF21272CFF0E0F11FF070707FF060606FF060606FF050505FF040404FE0404 05FF1B1B1BE9B8B8B84AFCFCFC03000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000ECECEC13515154B50E1013FF0A0A0DFE060616FF0E1119FF151A21FF2A31 38FF444953FF616A76FF5B636FFF424952FF4A4F5BFF0F1242FF0E0F23FF1A1D 29FE1A1D24FF8686877FFCFCFC03000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000F8F8F80766666699000000FF0101 01FE394344FFBFE1E3FFCFF3F5FFCDF1F4FFCFF2F5FFCDEFF2FFC8ECF0FFC6EA EEFFC6EAEFFFC7ECEFFFCCF0F3FFC9EEF2FFC5E9EDFFC7ECEFFFCEF1F4FFCEF2 F5FFCDF0F4FFC9EDF0FFC4EAEDFFC9EEF1FFCEF2F4FFC9EDF1FFBFE4E8FFBFE4 E8FFC1E6EAFFC1E6EAFFB9DDE1FFACCBCEFFADCCCFFFC4E7EAFFC5EAEEFFCBEF F2FFC7EBEFFFC4E9EDFFC8ECEFFFCAEEF1FFC6EAEEFFA6C4C7FF67797AFF9DB8 BBFF8CA7AAFF89A3A5FF8AA3A6FF88A0A3FF85A0A2FF87A1A4FF8BA4A7FF89A2 A5FF89A2A4FF8AA3A6FF8BA5A8FF8BA5A7FF8FA7A9FF859C9DFF323B3CFF0101 01FE000000FF262626D9C9C9C936000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000DBDBDB24000000FF000000FF68DBE8FF73F4 FFFF6DE8F4FF0B1617FF122629FF56B6C0FF66D8E4FF66D8E4FF61CDD8FF3C7E 86FF060F11FF000000FF1B1E20FFADC1CEFFD8F1FFFFD5EEFEFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD5EEFEFFD5EEFDFF576167FF0000 00FF040A0BFF57BAC5FF68E9F4FF4BD3D7FF4BD3D8FF4CD4D9FF4CD4D9FF4BD3 D8FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4BD3D8FF4CD4 D9FF4CD4D9FF4CD4D9FF4CD4D9FF4FDDE3FF163D3FFF000000FF232323DCEBEB EB14000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FEFEFE01515151AE0000 00FF000000FF000000FF000000FF0E0E0EFFF5F5F5FFF5F5F5FFF5F5F5FFF5F5 F5FFECECECFF4D4D4DFF000000FF000000FF000000FF000000FFA4A4A4FFF6F6 F6FFD1D1D1FF0C0C0CFF000000FF000000FF000000FF000000FF000000FF0808 08FFC9C9C9FFF1F1F1FF404040FF000000FF000000FF000000FF000000FFDADA DAFFF5F5F5FFF5F5F5FFF4F4F4FFFAFAFAFF7A7A7AFF000000FF000000FF0000 00FF000000FF0E0E0EF1C2C2C23D000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000E9E9 E916343638D511141AFF161B1FFF21252BFF2B3337FF2A3036FF2E333AFF373F 47FF454C58FF2C333BFF0D0E10FF090909FF050505FF040405FF030309FF0303 07FE040404FF3F3F40C7E0E0E01F000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D4D4D52C2C2C2FE10E0E0FFF0E0F10FF060608FF050409FF090B0DFF181E 23FF545B67FF515A65FF363E48FF444B56FF2D343DFF2F343AFF353740FF3335 3CFF1B1C22FDB3B3B44DFEFEFE01000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000DDDDDD22232323DC0000 00FF000000FF657778FFC0E5E8FFC1E6EAFFC2E6EAFFC0E5E9FFBEE3E7FFB4D6 DAFFA7C5C8FFAECBCEFFC0E0E3FFC7EBEEFFCCF0F3FFC9EEF1FFC1E6EAFFC4E9 EDFFC5E9EDFFBDE2E7FFBADFE4FFBEE3E8FFC3E8ECFFC5EAEEFFC8EDF0FFC8EC EFFFC7ECEFFFABCBCEFF455254FF151717FF262A2AFF586162FF98AFB2FFBFE2 E6FFC8EDF0FFC3E7EBFFBDE2E6FFC2E7EBFFC6EBEEFFBBDFE2FF465455FF7288 8AFF92ADB0FF92ABADFF8EA8AAFF86A0A3FF89A3A6FF8BA4A6FF8AA3A5FF86A0 A2FF859FA1FF8BA4A7FF8BA5A8FF8BA5A8FF869EA0FF424F50FF030404FE0000 00FF151515EAB2B2B24D00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000F0F0F00F323232CD000000FF14292CFF61CD D8FF173235FF102426FF6DE6F2FF72F1FEFF70EEFBFF70EEFBFF71EFFCFF73F4 FFFF72F1FEFF2F646AFF000102FF0B0C0DFFA6BAC7FFD7F0FFFFD6EFFFFFD5EE FEFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD5EEFEFFD5EE FEFFD6EFFFFFD7F0FFFFD7F0FFFFD7F0FFFFD6EFFFFFD6EFFFFFD5EEFEFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD7F1FFFFD1E9F9FF6E7B84FF000000FF0000 00FF2D5E63FF76FBFFFF71EFFCFF68E9F4FF4CD4D9FF4BD3D8FF4CD4D9FF4CD4 D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4 D9FF4CD4D9FF4BD3D8FF4CD5DAFF339194FF020606FE020202FD9292926D0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000B5B5B54A0707 07F8010101FE000000FF000000FF000000FF868686FFFFFFFFFFF4F4F4FFF5F5 F5FFF3F3F3FF848484FF000000FF000000FF000000FF000000FF2F2F2FFFE6E6 E6FFF7F7F7FFBFBFBFFF3A3A3AFF111111FF0D0D0DFF1E1E1EFF494949FFC7C7 C7FFFFFFFFFF979797FF070707FF000000FF000000FF000000FF252525FFE8E8 E8FFF4F4F4FFF5F5F5FFF6F6F6FFEBEBEBFF070707FF000000FF000000FF0000 00FF000000FF4C4C4CB3F8F8F807000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000F8F8 F8076D6D6E9A10161AFF292E35FF3E444DFF3B4048FF3C424CFF444A55FF4148 52FF444B56FF31373FFF121418FF0D0E0EFF09090CFF050512FF03030BFF0404 0FFF040406FF060607FFA0A0A061FEFEFE010000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000FEFE FE01ADADAD541C1D20F60B0B0DFF0C0C0CFF060618FF0A0B0BFF15181CFF2429 30FF676F7CFF6A737FFF5D6574FF5E6674FF404552FF3E4655FF2D323DFF3236 3DFF3E4044D5DADADA2500000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000A5A5A55A0C0C 0CF3000000FF131818FF94B1B4FFC5E9EDFFC0E4EAFFC8EDF1FFA4C0C2FF3E46 48FF2E3030FF3F4243FF5F6667FF8FA3A5FFC0E1E4FFCAEDF1FFC3E8EBFFC1E7 EBFFBCE3E6FFBEE3E7FFC0E5E9FFBFE4E8FFBFE4E8FFC2E7EBFFCAEFF2FFCEF2 F4FFC8EDEFFF556566FF000000FF000000FF050505FF121212FF343434FF7584 86FFB7D9DDFFC5EBEEFFC7ECEFFFC5EAEDFFCDF0F3FFC9ECEFFF6B8082FF1C22 22FF80979AFF8DA8ABFF8EA6A9FF8EA7A9FF88A2A4FF87A1A4FF89A2A5FF8CA5 A7FF89A3A5FF88A1A3FF89A2A4FF869EA1FF4E5C5EFF050606FE000000FF0D0D 0DF29191916EFCFCFC0300000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000008B8B8B74020202FD010101FE0000 00FF000000FF5EC6D2FF73F4FFFF70EEFBFF71EFFCFF71EFFCFF71EFFCFF70EE FBFF71EFFCFF76FAFFFF47969EFF030B0CFF020101FF7D8C94FFD9F2FFFFD6EF FFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFD6EFFFFFDEF8 FFFFC2D8E7FF9FB2BEFF96A8B3FFA3B6C2FFC0D7E5FFDEF8FFFFDDF6FFFFD9F2 FFFFD9F2FFFFDBF5FFFFDEF8FFFFA8BCC9FF41494EFF000000FF000000FF0D1C 1EFF70EDFAFF71EFFDFF70EEFBFF71EFFCFF5FE2EBFF4CD4D9FF4CD4D9FF4CD4 D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4 D9FF4BD3D8FF4DD9DEFF40B4B9FF091B1BFE000000FF454545BAFAFAFA050000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000003535 35CA000000FF000000FF000000FF000000FF1B1B1BFFEBEBEBFFF6F6F6FFF5F5 F5FFF6F6F6FFAEAEAEFF040404FF000000FF000000FF000000FF000000FFCECE CEFFF6F6F6FFF9F9F9FFE2E2E2FFBDBDBDFFB9B9B9FFCFCFCFFFFEFEFEFFF8F8 F8FF7F7F7FFF111111FF000000FF000000FF000000FF000000FF5D5D5DFFEEEE EEFFF5F5F5FFF4F4F4FFFFFFFFFF747474FF000000FF000000FF000000FF0101 01FE070707F8A2A2A25D00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000909090751F272CFF2F353EFE3F4650FF424B58FF404A57FF394049FF444F 59FF363D46FF3E444EFF191E23FF0C0D0FFF0A0A0AFF04040EFF040316FF0404 12FF080808FE050504FF5C5D5DA7F4F4F40B0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000EBEB EB14414142C60C0D0FFF05050AFF050506FF040424FF050746FF12141EFF3D42 49FF89909DFF848B98FF6E7582FF535866FF4C5161FF2B303EFF2C3341FF252A 30FE6B6D6E9DF2F2F20D00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000F2F2F20D5F5F 5FA0010101FE010101FE3E4A4BFFB5D7DBFFC4EAEEFFC4E8ECFF465354FF0101 01FF0A0A0AFF161616FF252525FF3D3E3EFF6D7879FFBEE1E3FFD1F5F8FFCBEE F0FFCAEDEFFFCDF0F4FFD3F6F9FFD7F7F9FFD1F5F6FFC5E9EDFFBCE2E6FFBEE4 E8FFC3E8EBFF303839FF000000FF000000FF010101FF070707FF191919FF3A3B 3BFF808F90FFC4E8EBFFCCF0F3FFCBEFF4FFC7EBEEFFC9EDF2FFB3D2D5FF161A 1AFF323C3CFF88A2A4FF8AA4A6FF8AA2A6FF8AA3A6FF8DA6A8FF8DA7A9FF8CA5 A7FF8DA6A9FF8BA4A6FF87A0A2FF576768FF0B0D0DFE000000FF000000FF7E7E 7E81F7F7F7080000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000F6F6F6091C1C1CE3000000FF0101 01FE265156FF74F7FFFF70EEFBFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EF FCFF70EEFBFF70EEFBFF71F0FDFF55B4BEFF030607FF020202FF5D686FFFD7F0 FFFFD5EEFEFFD5EEFEFFD6EFFFFFD6EFFFFFD5EEFEFFD5EEFEFFD7F0FFFF6772 7AFF121416FF080708FF070708FF0A0C0CFF111314FF2B2F32FF798791FFAFC3 CFFFB3C8D5FF8C9CA7FF353B3FFF08090AFF000000FF000000FF000000FF57B6 C1FF72F1FEFF70EEFBFF71EFFCFF71EFFCFF70EEFBFF51D7DEFF4BD3D8FF4CD4 D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4BD3 D8FF4DD8DDFF3DACAFFF040E0EFE000000FF191919E6F8F8F807000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000B2B2 B24D000000FF010101FE000000FF000000FF040404FF8A8A8AFFFDFDFDFFF4F4 F4FFF5F5F5FFCDCDCDFF222222FF000000FF000000FF000000FF000000FFDADA DAFFF5F5F5FFF4F4F4FFF5F5F5FFF6F6F6FFF2F2F2FFB1B1B1FF666666FF1616 16FF040404FF000000FF000000FF000000FF000000FF000000FF969696FFF5F5 F5FFF5F5F5FFF6F6F6FFE7E7E7FF141414FF000000FF000000FF000000FF0000 00FF1E1E1EE10000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000DFDFDF202C3033E6293135FF3A3F4AFF3C444FFF434C5AFF444F5AFF4A53 5FFF474F5DFF424957FF2D3239FF0E0F14FF0C0D18FF0C0C16FF080A33FF0B0B 15FF080809FF030302FF191919EFC5C5C53A0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000FDFDFD029A9A 9A680C0C0FFF0E0F10FE0F0E12FF0E1012FF0C0C14FF080916FF070726FF0D11 30FF252D46FF677183FF8B95A2FF9FA8B5FF808996FF323844FF2F323BFE2F35 3AF79F9F9F64FCFCFC0300000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000D1D1 D12E212121DE000000FF040505FE758C8DFFCBEDF0FFB8DADEFF252C2DFF0000 00FF010101FF040404FF0D0D0DFF202020FF3A3939FF788586FFC2E6E9FFC5EA EEFFC3E8ECFFC7ECEFFFCCF0F2FFCBEEF2FFC5EAEDFFC9EDF1FFC5E9EDFFC6EA EEFFC8EBEEFF434F50FF000000FF000000FF000000FF010101FF0C0C0CFF2929 29FF4E4F50FFB0CACDFFC7ECF1FFC3E8EBFFC5E9EDFFC5EAEEFFC9F0F4FF697D 7EFF000000FF526163FF88A2A5FF8BA4A8FF8EA7A9FF86A0A2FF839DA0FF89A1 A3FF88A0A3FF87A0A3FF677A7CFF111314FE000000FF020202FD6262629DF9F9 F906000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000D4D4D42B070707F80000 00FF57BAC4FF71F0FDFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EF FCFF71EFFCFF71EFFCFF70EEFBFF73F5FFFF61CEDAFF0C1A1BFF000000FF464E 53FFCAE2F1FFD7F0FFFFD6EFFFFFD6EFFFFFD7F0FFFFCAE2F1FF444C51FF0000 00FF0E1D1FFF265256FF142C2EFF070F0FFF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF000000FF000000FF2B5B61FF6EEA F7FF70EEFBFF71EFFCFF71EFFCFF70EEFBFF71EFFCFF66E7F2FF4BD3D7FF4BD3 D8FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4 D9FF45C2C6FE040D0EFE000000FF272727D8E7E7E71800000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000292929D6000000FF010101FE000000FF000000FF3C3C3CFFE9E9E9FFF5F5 F5FFF5F5F5FFEAEAEAFF404040FF000000FF000000FF000000FF000000FF5555 55FFFAFAFAFFF5F5F5FFF4F4F4FFF5F5F5FFF0F0F0FF717171FF000000FF0000 00FF000000FF000000FF000000FF000000FF000000FF0F0F0FFFBBBBBBFFF6F6 F6FFF5F5F5FFFCFCFCFF838383FF040404FF000000FF000000FF000000FF0000 00FF9A9A9A650000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F9F9F9068586867C1A1E24FF282B33FF272933FF2F323BFF31343CFF3537 41FF3D3F4CFF3F414CFF2F333AFF0F100FFF080818FF030319FF040405FF0707 09FF040410FF05050CFE030306FF4F4F50B5E6E6E61900000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000E6E6E6193A3B 3CCF0E0F13FF0F1014FE0F1014FF101214FF11121BFF101331FF171C2DFF545D 64FF374358FF1B3677FF636C7AFF6F7989FF6D7886FF383F4AFF242831FE2729 2FF0C5C5C53AFEFEFE0100000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008E8E8E71020202FD000000FF181D1DFEA5C2C5FFCCEFF2FF3B4647FF0000 00FF000000FF000000FF030303FF101010FF2C2C2CFF505252FF9AB2B6FFBCE1 E5FFC3E8EDFFC7EBEFFFC2E7EAFFBBE1E5FFBAE0E4FFC1E5EAFFC4E9EDFFC4E9 ECFFC3E9EDFF839C9EFF040505FF000000FF000000FF000000FF060606FF1F1F 1FFF3F3E3EFF839193FFC5E9EDFFC4E8ECFFC3E7EBFFC5EAEEFFC7EBEFFFC4E7 E9FF161A1AFF131717FF7B9192FF8EA8AAFF87A1A3FF859FA2FF859FA2FF8AA4 A7FF8AA4A7FF6F8385FF1E2324FE010101FE000000FF4D4D4DB2E1E1E11E0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000007575758A0811 12FF68DBE7FF70EEFBFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EF FCFF71EFFCFF71EFFCFF71EFFCFF70EEFBFF72F3FFFF69DFEAFF2A585DFF0000 00FF1D2023FF8C9DA7FFC7DEEDFFBBD1DFFF808E98FF1C1F21FF000000FF2D60 66FF6DE8F5FF76FBFFFF74F7FFFF5DC4CFFF3C8087FF1F4346FF020506FF0000 00FF000000FF000000FF000000FF000000FF000000FF142A2DFF67DAE6FF71F0 FDFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF70EEFBFF72F0FDFF55D9E1FF4BD3 D8FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD3 D8FF276D6FFE000000FF7373738CEAEAEA150000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000B4B4B44B000000FF000000FF000000FF000000FF070707FFACACACFFF5F5 F5FFF5F5F5FFFEFEFEFF656565FF000000FF000000FF000000FF000000FF0000 00FFB4B4B4FFFAFAFAFFF9F9F9FFF5F5F5FFF4F4F4FFFBFBFBFFA4A4A4FF3535 35FF000000FF000000FF000000FF000000FF000000FF2F2F2FFFDBDBDBFFF5F5 F5FFF5F5F5FFE3E3E3FF333333FF000000FF000000FF000000FF000000FF1616 16E9000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000B7B7B849181C21FB14161EFF0F1215FF171A1FFF20242AFF3135 3CFF2A2D33FF212332FF0F1025FF080826FF040427FF040400FF050518FF0404 0EFF030318FF060607FE0C0C0DFF0B0B0AF98A8A897BF4F4F40B000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FBFBFB04A0A0A0620F0F 13F6070813FF080917FF080911FF060616FF0B0E28FF1E2125FF1B2047FF8388 94FF797E8BFF43465BFF313042FF545665FF686D7BFF7B8391FF666E7DFF3C3C 42D9EBEBEB140000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F4F4F40B5A5A5AA5000000FF000000FF3A4748FFB6DBDEFF849D9FFF0000 00FF000000FF000000FF010101FF090909FF222222FF454545FF7E8C8DFFBFE3 E6FFC4EAEEFFC4E8ECFFC0E6EAFFC2E7EAFFCAEEF2FFD1F3F7FFD1F4F7FFCAED F0FFBFE4E9FFB7DADDFF465353FF000000FF000000FF000000FF030303FF1919 19FF3A3939FF6F7878FFC5E9ECFFC8ECF0FFC1E6EBFFC5EAEDFFC7ECEFFFCCF0 F4FF6D8081FF000000FF2F3838FF849D9FFF8BA4A6FF8BA3A6FF8BA5A7FF88A2 A5FF728889FF202627FF010101FE000000FF363636C9D9D9D926000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000002D2D2DD21731 33FF6AE1EDFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EF FCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF70EEFBFF71EFFCFF70ECF9FF4DA3 ACFF010202FF020000FF121415FF101213FF010000FF000000FF4898A1FF70ED FAFF71EFFCFF70EEFBFF71EFFCFF71F0FDFF71F0FDFF6CE5F2FF66D8E4FF3D81 88FF081112FF000000FF000000FF000000FF162F32FF6AE0ECFF72F1FEFF70EE FBFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF70EFFBFF71EFFCFF67E7F2FF49D2 D6FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4BD3D8FF47C6 CBFE0B1F20FF555555AA00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F5F5F50A333333CC000000FF010101FE000000FF000000FF575757FFEFEF EFFFF4F4F4FFFBFBFBFF9C9C9CFF070707FF000000FF000000FF000000FF0000 00FF3B3B3BFFFFFFFFFFC8C8C8FF515151FF484848FF4F4F4FFF717171FF8E8E 8EFF696969FF000000FF000000FF000000FF000000FF505050FFF8F8F8FFF5F5 F5FFF5F5F5FFA7A7A7FF020202FF000000FF000000FF010101FE000000FF9D9D 9D62000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000D0D0D0302C2D30E11B1D25FF353640FF3E414CFF30343CFF1E21 32FF1B2136FF1F2131FF171B27FF0A0A2EFF040437FF040437FF03031DFF0303 06FF070712FF0A0A25FF060609FF070714FF0D0D1FF8A3A3A35EF9F9F9060000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000E5E5E51A4C4C4CB80909 09FF0A0A09FF0C0D0EFF0D0E0FFF111418FF131517FF090D3EFF15194DFF686F 7CFF818A97FF6C7483FF444B5AFF212631FF23272FFE4D5563FF515B69FF8F90 9177FDFDFD020000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000D2D2D22D212121DE000000FF070808FE788E90FFCAECEFFF4B58 58FF000000FF000000FF010101FF070707FF1E1E1EFF414141FF767F81FFC1E4 E8FFC8ECEFFFC7EBEFFFC9ECF1FFC6EBEFFFC3E7EBFFC0E5E9FFC5EAEDFFCBEE F1FFC6EAEDFFC9ECF0FFB0CFD2FF2E3637FF020202FF000000FF030303FF1515 15FF353434FF7C898BFFC5EAEEFFCBF0F3FFD1F4F7FFCDF1F3FFC6EBEEFFBFE5 E9FFB3D5D8FF202627FF000000FF4D5C5DFF94ACAEFF94ABADFF8DA6A8FF798F 91FF293132FF000000FF000000FF282828D7C9C9C93600000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000FF1E40 44FF6CE4F1FF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EF FCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF70EEFBFF72F2 FFFF6EE9F6FF397980FF152E31FF0D1B1DFF204549FF63D2DDFF73F4FFFF70EE FBFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF70EEFBFF70EEFBFF73F4 FFFF74F5FFFF50A9B3FF31676EFF47979EFF72F2FFFF70EEFBFF70EEFBFF71EF FCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF70EEFBFF6EECF9FF4FD6 DCFF4BD3D8FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4BD3D8FF4CD6DBFF3594 98FF000000FFDFDFDF2000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000009A9A9A65000000FF000000FF000000FF000000FF000000FFD2D2 D2FFF5F5F5FFF7F7F7FFDADADAFF0E0E0EFF000000FF000000FF000000FF0000 00FF4A4A4AFFFFFFFFFF707070FF000000FF000000FF000000FF000000FF0505 05FF6B6B6BFF0A0A0AFF000000FF000000FF030303FF818181FFFDFDFDFFF4F4 F4FFECECECFF484848FF000000FF000000FF000000FF000000FF1F1F1FE0EEEE EE11000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000D8D8D828303235DC181B22FF22282EFF2A2F36FF2B2F38FF1E25 51FF282D4DFF323745FF25283DFF0A0A25FF040428FF05050BFF05051EFF0404 29FF06061DFF050525FF03030AFF030309FE020204FF202020EAADADAB55FCFC FC03000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000FBFBFB049696966C070707FC0405 08FF050405FF070809FF070705FF0E0E10FF111211FF050623FF59627DFF767F 8CFF828B97FF7B8290FF5E6677FF4C5571FF2A2E39FF14161DFF5D5D60AEEEEE EE11000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000FCFCFC0389898976070707F8000000FF242A2BFFA9C8CBFFAFD1 D5FF445153FF030304FF000000FF050505FF1B1B1BFF414040FF7F8E90FFC2E5 E8FFC7EBEDFFC7EBEFFFC5EAEDFFC3E8ECFFC3E8ECFFBEE3E7FFC2E7EAFFC8EC F0FFCAEEF2FFCBEEF1FFC6EBF0FFAFD0D4FF5E7173FF222929FF0E1011FF1E20 20FF545D5EFFAFCDD1FFCAEEF1FFC6EBEEFFC8EBEEFFC5E9ECFFC3E9ECFFC4EA EEFFC4E8EBFF697C7DFF010101FF0D1010FF667A7CFF8BA6A8FF7E9598FF333E 3EFF010101FE000000FF242424DBBDBDBD420000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000EFEFEF10000000FF1F42 46FE6CE5F1FF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EF FCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF70EE FBFF71F0FDFF75F7FFFF77FCFFFF76FAFFFF76FBFFFF72F1FEFF70EEFBFF71EF FCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF70EE FBFF71EFFCFF73F4FFFF75F8FFFF74F5FFFF71EFFCFF71EFFCFF71EFFCFF71EF FCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF6FEDFAFF56DB E2FF4BD3D8FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4CD4D9FF4EDBE1FF0B1F 1FFF4B4B4BB4F7F7F70800000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000DCDCDC23292929D6000000FF000000FF000000FF000000FF5D5D 5DFFFBFBFBFFF5F5F5FFFFFFFFFF242424FF000000FF000000FF000000FF0000 00FF7E7E7EFFE7E7E7FF313131FF000000FF000000FF000000FF000000FF0000 00FF1F1F1FFF000000FF000000FF000000FF0B0B0BFFBEBEBEFFF9F9F9FFF6F6 F6FFCBCBCBFF000000FF000000FF000000FF000000FF000000FF8282827DFCFC FC03000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000D5D5D52A313233D70F1012FF13161BFF17191DFF191F34FF2F33 3EFF3D3F49FF3E414AFF343840FF0F1111FF040438FF030300FF040403FF0404 01FF04054DFF04030AFF040407FF030307FF030303FE06060CFF26274CE0C8C8 C639FDFDFD020000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000D9D9D9261F1F1FE9060609FF0404 0AFE060606FF05060CFF080926FF090A1DFF0B103CFF040B3EFF30477DFF5661 79FF767F93FF505979FF1E2139FF11122CFF161A24FF323337D9CBCBCB34FEFE FE01000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000ECECEC13444444BB000000FF010101FE475759FFBBE1 E4FFB3D6DAFF697D80FF272D2EFF0F1011FF252727FF636E6FFFB3D2D5FFCCF0 F4FFCDF2F4FFC5EAEEFFBDE2E7FFC6EBEEFFCDF0F4FFC5EBEEFFBFE4E8FFBDE3 E7FFC0E5E9FFC0E4E9FFBFE5E9FFBAE0E5FFB6DBDFFFAACBCFFF94AEB1FF94AF B3FFADCDD1FFC4E9EDFFC4E9EDFFC2E6E9FFC4E8ECFFC4E9ECFFC4E8ECFFC7EC F0FFC5EAEEFFA8C6C9FF101313FF000000FF1B2122FF57686AFF283031FF0101 01FE000000FF121212EDA5A5A55AFCFCFC030000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000EDEDED12000000FF1936 39FF6BE2EEFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EF FCFF71EFFCFF71F0FDFF71EFFCFF70EEFBFF71EFFCFF71EFFCFF71EFFCFF71EF FCFF71EFFCFF71EFFCFF70EEFBFF71EFFCFF70EFFCFF71EEFBFF71EFFCFF71EF FCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EF FCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EF FCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF70EEFBFF5CDF E8FF4BD3D8FF4CD4D9FF4CD4D9FF4CD4D9FF4BD3D8FF4EDBE1FF2E7F82FF0404 04FB9A9A9A650000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000006F6F6F90020202FD000000FF000000FF000000FF0000 00FFD9D9D9FFF8F8F8FFFFFFFFFF6C6C6CFF000000FF000000FF000000FF0000 00FFA2A2A2FFB1B1B1FF010101FF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF131313FFEEEEEEFFF6F6F6FFFDFD FDFF4A4A4AFF000000FF000000FF000000FF000000FF181818E7CFCFCF300000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000B8B8B848131314F90E0F11FF0E0E11FF0F0F17FF181A20FF2124 2AFF2E3036FF32353EFF41434BFF252726FF040764FF05061EFF040409FF0303 0BFF040323FF030311FF040403FF070708FF070706FF04041AFE08080CFF4C4C 4DB8EBEBEB140000000000000000000000000000000000000000000000000000 0000000000000000000000000000F8F8F80777777890050505FF050505FE0303 03FF060606FF0A0A0BFF0C0D0DFF101114FF252944FF686E82FF797F8BFF3C45 6AFF2B326BFF343C5FFF0D1E7BFF202A3EFF141622FD72727595F3F3F30C0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000C4C4C43B151515EA000000FF030303FF829A 9CFFCCF1F5FFC9EEF2FFB8DADDFF9BB8BBFF9AB8BBFFBADCDFFFCFF3F5FFC6EA EEFFC0E5E9FFBAE0E5FFBDE3E7FFC5EAEDFFC2E7EBFFC6EBEFFFC0E6EAFFBAE0 E5FFC7EAEEFFCBF0F2FFCCF0F2FFCBEFF1FFCCEEF1FFCBEEF2FFC4E9EDFFC0E5 E9FFBBE1E6FFBBE0E5FFBFE4E8FFC0E5E9FFC0E5E9FFC4E9EDFFC7EBEEFFC4E8 EBFFC2E6EBFFC8EDF1FF596A6CFF000000FF000000FF000000FF000000FF0000 00FF131313EC9B9B9B64FEFEFE01000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000FF0C19 1BFF68DCE8FF70EEFBFF71EFFCFF71EFFCFF71EFFCFF71F0FDFF6DE7F4FF66D7 E3FF5DC4CFFF59BCC7FF64D3DFFF6AE1EDFF71EFFCFF71EFFCFF70EEFBFF71EF FCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EF FCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EF FCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EF FCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF60E3 ECFF4CD4D9FF4CD4D9FF4CD4D9FF4BD3D8FF4CD4D9FF44BEC3FF050F0FFF1818 18E7EAEAEA150000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000DCDCDC23090909F6010101FE000000FF000000FF0000 00FF515151FFFFFFFFFFFAFAFAFFB7B7B7FF000000FF000000FF000000FF0000 00FF858585FF999999FF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF3E3E3EFFFFFFFFFFF8F8F8FFCBCB CBFF000000FF000000FF000000FF000000FF000000FF5A5A5AA5000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F8F8F8077B7B7B880E0E14FF0B0C1AFF0A0C22FF0D0D11FF10111AFF1517 1DFF1C1F24FF1F2226FF303239FF1E1F33FF060616FF04051AFF040532FF0303 08FF030302FF030327FF050520FF06060FFF06060AFF04040DFF03030AFF1A19 1BECBAB9BA460000000000000000000000000000000000000000000000000000 00000000000000000000FDFDFD02C3C3C23D18181CEC030302FF030305FF0505 05FF090A0BFF0E1114FF101218FF242831FF7A808BFF9FA9B2FF7C8591FF707A 84FF97A1A8FF6B727DFF282E44FF0C1A67FF171B31F991919275FAFAFA050000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000089898976010101FE000000FF272E 2EFFA4C2C5FFC4EAEFFFBEE4EAFFC1E7ECFFCAEEF2FFC8EDF1FFC3E8ECFFC3E8 ECFFC3E8ECFFC7EBEFFFC8EDF0FFC1E5E9FFC0E5E9FFCAEEF1FFCDF0F4FFCFF2 F6FFCEF2F5FFCBEFF2FFCDF1F4FFD0F3F6FFCDF1F4FFCAEEF1FFC5E9ECFFC4EA EDFFC4E9EEFFC2E7EBFFBEE4E8FFBCE2E7FFC2E8ECFFC4E9EDFFCBF0F4FFCCF1 F3FFCBEFF2FFCFF5F8FF869FA1FF000000FF000000FF010101FE000000FF0E0E 0EF19F9F9F600000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000292929D60000 00FF5CC3CEFF71F0FDFF71EFFCFF70EEFBFF72F1FEFF5BC1CBFF254F53FF050A 0BFF000000FF000000FF000000FF152D30FF3D8088FE6EE9F6FF73F3FFFF70EE FBFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EF FCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EF FCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EF FCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF63E5 EFFF4CD4D9FF4CD4D9FF4BD3D8FF4CD5DAFF4AD0D5FF163E40FE000000FF6565 659A000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000575757A8000000FF000000FF000000FF0000 00FF0E0E0EFFCCCCCCFFF9F9F9FFF8F8F8FF000000FF000000FF000000FF0000 00FF1B1B1BFF898989FF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF838383FFFEFEFEFFFFFFFFFF4444 44FF000000FF000000FF000000FF010101FE0A0A0AF5B7B7B748000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000CDCDCD32212122E90A0A0FFF080819FE0B0B0FFF0D0D10FF0F1217FF1213 18FF12142CFF13162AFF161827FF15182FFF0E0F14FF070709FF040521FF0404 06FF07070AFF04051EFF030309FF030305FF030304FF030307FF030303FF0303 03FF3C3C3BC8CACACA35F7F7F708FEFEFE010000000000000000000000000000 0000FEFEFE01F6F6F609C3C3C33C434345C004040BFE04040FFE030305FF0606 05FF070707FF0A0B0DFF0F1114FF101115FF4E565DFF8895A1FF9AA6AEFF8895 9FFF6D7B88FF5E6875FF5C6774FF2B3240FF13191FFC74747491F4F4F40B0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000E9E9E9163F3F3FC0000000FF0101 01FE242A2AFF75898AFFAFCED1FFC7E8EBFFC9EDF0FFC8ECF0FFCAEEF1FFCEF2 F5FFD5F8F9FFD3F5F7FFCEF2F5FFCCF0F3FFD2F3F6FFCEF0F3FFCBEFF1FFC9EC EEFFBFE2E6FFBCE0E3FFBBDFE3FFB5DADEFFBCDEE2FFC3E5E8FFC0E3E6FFC0E2 E5FFBCDEE1FFB7D7DAFFAFD0D3FFA9C7CAFF9EBCBFFF97B5B8FF99B6B9FF9FBE C1FFA2C3C7FF88A3A6FF202526FF000000FF010101FE000000FF090909F69090 906FF9F9F9060000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000979797680000 00FF2A5B60FE75F8FFFF70EEFBFF71F0FDFF5DC6D1FF060E0FFE010101FE0000 00FF0E0E0EF13E3E3EC1333333CC000000FF000000FF142B2EFE63D2DDFF72F1 FFFF70EEFBFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EF FCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EF FCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EF FCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF65E6 F1FF4DD4DAFF4BD3D8FF4DD8DDFF4BD2D7FF133335FF000000FF000000FFF2F2 F20D000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000E0E0E01F000000FF000000FF000000FF0000 00FF010101FF6D6D6DFFFCFCFCFFFCFCFCFF464646FF000000FF000000FF0000 00FF000000FF161616FF131313FF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FFCDCDCDFFFCFCFCFFC6C6C6FF0A0A 0AFF000000FF000000FF010101FE000000FF2E2E2ED100000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000FEFEFE01E5E5 E51A434343C2070707FF0B0B0CFE0A0B10FF0F0F0FFF0F1012FF111213FF0D0E 23FF0C0D2AFF0F1014FF0F1015FF0E101CFF11121CFF080816FF030957FF0305 23FF030417FF030432FF040302FF040403FF040404FF040435FF030309FF0303 02FE08080BFF272727DE616262A4A2A2A25ECECECE31E3E3E31CE2E2E21DD2D2 D22DAFAFAF50646464A0101010F4040408FF030314FF03030AFF04040DFF0404 04FF040404FF111418FF1B1F26FF49515CFF9AA5B1FF9AA6B1FF85919CFF7984 91FF5B6776FF555E6BFF434853FF282F37FF13161DFF2B2E30DFC7C7C739FEFE FE01000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000BFBFBF40202020DF0000 00FF000000FF000000FF121514FE2A3233FF3A4748FF4C5B5DFF556566FF5666 68FF546364FF4E5C5EFF4A585AFF485656FF424E4FFF3C4849FF394345FF353F 40FF313A3BFF2C3536FF273031FF272D2EFF252B2CFF212828FF1F2324FF1A20 21FF191D1EFF151819FF111413FF0D1010FE0A0C0BFF070808FF040404FF0506 06FF060808FF000000FF000000FF000000FF000000FF050505FA68686897F9F9 F906000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000EDEDED121717 17E8000000FF60CAD5FF72F3FFFF75F7FFFF0E1F21FE000000FF0B0B0BF4A7A7 A758000000000000000000000000F6F6F609585858A7050505FA050B0CFF55B6 BFFE70EDFAFF71F0FDFF70EEFBFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EF FCFF71EFFCFF71EFFCFF70EEFBFF71EFFCFF71F0FDFF71EFFCFF71EFFCFF71EF FCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EF FCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF67E9 F4FF4DD3D8FF46C4C8FF328D90FF030A0BFE000000FF000000FF898989760000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000585858A7000000FF010101FE0000 00FF000000FF252525FFD5D5D5FFF9F9F9FF909090FF000000FF000000FF1010 10FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF010101FF090909FF000000FF101010FFFFFFFFFFF8F8F8FF616161FF0000 00FF000000FF000000FF010101FE000000FFBABABA4500000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000ECECEC137272 7292080808FC070707FE0D0D0BFF07071BFF0E0E0BFF0F0F11FF0F1011FF0C0F 22FF121214FF111215FF101115FF1C1E21FF0E0F36FF06064EFF040328FF0304 19FF030358FF030441FF040413FF040405FF040405FF040405FF040300FF0304 0AFE050720FE030205FF020200FF05081CFF201F1CE3424244C239393BC92525 25DF0A0A0AFA030303FF030304FF03030AFE040419FE030313FF040405FF0606 06FF0B0C0EFF272D35FF49515EFF6B737EFF96A2ACFF6D7987FF657281FF4F59 66FF3F4652FF313640FF20262DFF1A2025FF11141AFF12161AFF4A4B4DBDE3E3 E31C000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000BBBBBB444242 42BD090909F6000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF050505FA151515EA414141BE9292926DF1F1F10E0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000FEFEFE018383 837C000000FF122628FE68DDE9FF64D4DFFF000000FF010101FEC2C2C23D0000 00000000000000000000000000000000000000000000A0A0A05F121212ED0000 00FF336D73FE6ADFECFF73F4FFFF70EEFBFF71EFFCFF71EFFCFF71EFFCFF71EF FCFF71EFFCFF71EFFCFF74F5FFFF71EFFCFF5DC6D1FF6BE3EFFF73F3FFFF70EE FBFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EF FCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF70EEFBFF72F1FEFF75F7FFFF53B9 C2FF225C5FFF091B1CFE000000FF000000FF000000FF6161619EF9F9F9060000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000D6D6D629000000FF000000FF0000 00FF000000FF000000FF959595FFF5F5F5FFD0D0D0FF000000FF252525FF4E4E 4EFF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF0C0C0CFF5F5F5FFF000000FF5C5C5CFFFCFCFCFFD0D0D0FF202020FF0000 00FF000000FF000000FF000000FF303030CF0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000F3F3F30C8484847D0707 08FD0A0A0AFF0B0B0AFE0C0C0FFF0A0A11FF090912FF0E0F10FF0E0E0FFF0B0C 15FF0E0F0FFF101217FF131519FF22252CFF3B3C3FFF0A0B35FF0D0E33FF0100 1EFF090A14FF030304FF020219FF030316FF030315FF04031AFF03094AFF0307 85FF040419FF04040CFF030305FE040954FF040530FF030312FF030304FF0303 03FF030303FF040404FF030303FF030404FF030306FF050505FF060707FF0E10 12FF475159FF808A95FF909BA4FFA7B1B7FF798491FF555C6BFF323B43FF3135 3DFF353A40FF252D31FF262B33FF14181EFF16171FFE15181EFF0C0D10FF696B 759CF4F4F40B0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000EDED ED12ADADAD525E5E5EA12A2A2AD50E0E0EF1050505FA010101FE010101FE0101 01FE010101FE020202FD020202FD030303FC040404FB050505FA080808F70A0A 0AF50C0C0CF30F0F0FF0131313EC161616E91B1B1BE4212121DE272727D82E2E 2ED1353535CA3A3A3AC53E3E3EC1414141BE474747B84B4B4BB4515151AE5757 57A86464649B7E7E7E81B5B5B54AD6D6D629EDEDED12FDFDFD02000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000FDFD FD023F3F3FC0000000FF1A393CFE5BC1CBFF000000FF0F0F0FF0EBEBEB140000 0000000000000000000000000000000000000000000000000000CCCCCC330D0D 0DF2000000FF0F2122FE56B8C1FF76FAFFFF71EFFCFF70EEFBFF71EFFCFF70EE FBFF71F0FDFF74F5FFFF4FA9B2FF102325FF070F10FF0C1A1CFF54B4BEFF73F5 FFFF70EEFBFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EF FCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF74F6FFFF67DAE6FF244C51FF0409 09FE000000FF000000FF000000FF4F4F4FB0CFCFCF30FAFAFA05000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000F8F8F807575757A8000000FF0101 01FE000000FF000000FF2F2F2FFFEAEAEAFFEFEFEFFF8F8F8FFFCFCFCFFF3333 33FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF0C0C0CFFB2B2B2FF878787FFDEDEDEFFF4F4F4FF8A8A8AFF000000FF0000 00FF000000FF010101FE000000FFBDBDBD420000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000EFEFEF107F7F808509090AFF0707 09FF07070AFE0D0D14FF0B0C21FF0E0E0FFF090A33FF0D0E15FF0A0A2AFF0E0F 10FF0D0F1FFF14161EFF292F3DFF646B72FF444F91FF5A6790FF414C8CFF4B64 7EFF53596EFF5A626CFF20232CFF08092FFF060606FF040403FF040527FF0606 16FF040407FF030317FF030640FF030637FF03030DFF030300FF030303FF0303 03FF050505FF040505FF040404FF030302FF040505FF0C0E10FF1D252AFF3942 4BFF737D87FF7E8993FF929BA3FFBEC7CEFFA8B2B8FF7D858DFF75808AFF525B 64FF484D56FF4F545EFF3C3F48FF31373DFF1D2228FF131727FF0A0D3FFE1011 1BF8A0A0A062F9F9F90600000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000FCFCFC03ECECEC13D0D0D02FBDBDBD42B3B3B34CB0B0B04FB1B1 B14EB1B1B14EB3B3B34CB5B5B54AB9B9B946BBBBBB44BEBEBE41C3C3C33CC6C6 C639CACACA35D0D0D02FD4D4D42BD9D9D926DFDFDF20E5E5E51AEBEBEB14F1F1 F10EF6F6F609F8F8F807F9F9F906FAFAFA05FBFBFB04FCFCFC03FCFCFC03FDFD FD02FEFEFE010000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000494949B6010101FE0A1718FF010101FE000000FFACACAC530000 000000000000000000000000000000000000000000000000000000000000E3E3 E31C1E1E1EE1000000FF000000FF244E52FE5EC6D1FF6AE1EDFF6BE4F0FF69DF EBFF5BC1CCFF214548FF000000FF000000FF000000FF000000FF000000FF4BA0 A9FF72F1FEFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EF FCFF71EFFCFF70EEFBFF71EFFCFF6FEBF8FF418A92FE000000FF010101FE1010 10EF2F2F2FD08F8F8F70F2F2F20D000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000B5B5B54A030303FC0000 00FF000000FF000000FF000000FFB5B5B5FFF7F7F7FFFEFEFEFF9A9A9AFF0505 05FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF484848FFF1F1F1FFF6F6F6FFE6E6E6FF272727FF000000FF0000 00FF010101FE000000FF313131CEF4F4F40B0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000F7F7F7088D8E8F760F1117FB0F1117FF1416 23FE1B1D29FF212352FF1D224CFF2A2C42FF181B49FF0C1458FF1A1C23FF1D20 29FF191D3FFF4D546BFF788199FFAEB6BCFFA7B1B4FF939EA5FF99A2A4FF536A 8DFF546485FF606B76FF515863FF2C324FFF272E4BFF222729FF0C0E23FF0B0D 38FF141632FF12151DFF151715FF161819FF0A0D10FF0B0E11FF2F3338FF5159 5EFF51585FFF5C646BFF50575EFF4C5258FF576068FF4E555FFF5D656DFF8A95 9FFFADB6BEFFB9C1C8FFCAD1D5FFC6CDD1FFAAB2B8FF9AA5A9FF7C878EFF6B72 7CFF565D64FF676F78FF5F666EFF4C5158FF202630FF101626FF101413FE0F0F 11FF2C2C2DD8B2B2B24EFCFCFC03000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000009494946B1C1C1CE3000000FF000000FF121212EDECEC EC13000000000000000000000000000000000000000000000000000000000000 0000F2F2F20D7070708F080808F7000000FF000000FF162F31FF1C3C3FFF1021 23FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0001 01FF47979FFF72F1FEFF70EEFBFF71EFFCFF71EFFCFF71EFFCFF71EFFCFF71EF FCFF71EEFBFF70EEFBFF75F9FFFF346F75FE000000FF1F1F1FE08C8C8C73D7D7 D728000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000EFEFEF103E3E3EC10000 00FF000000FF000000FF000000FF2E2E2EFFFAFAFAFFE5E5E5FF343434FF0000 00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF020202FFAEAEAEFFF9F9F9FFA5A5A5FF000000FF000000FF0000 00FF000000FF000000FF96969669FEFEFE010000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000BBBBBC4A202229FB363A44FF5B626CFE848A 93FF898F9AFF8D919CFF444C6AFF404652FF252C57FF22272DFF262A2BFF242C 63FF7C8293FFBFC5CAFFA0AAB1FFB1BAC2FFAEB8C0FF99A4ABFF546786FF1726 69FF394574FF585E65FF484E4DFF111B62FF14205FFF2A3353FF112069FF6268 74FF737B83FF646E78FF525B65FF4F565EFF6D747CFF929CA4FFA9B2B9FFB9C3 C8FFA3ADB4FFB5BEC6FFA7B1B9FFB8C1C8FFBCC4C9FFB9C1C7FFBDC6CCFFBEC6 CCFFC2CCD0FFCAD2D6FFCBD4D7FFC5CCD2FFBCC6CAFFBBC6C9FFB2BCC0FF8F99 A0FF5D646DFF373F46FF2D3238FF1E2328FF141926FF1A1F29FF15181DFF0808 09FF0B0B0FFF171717F09C9C9C67F8F8F8070000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000EFEFEF109292926D0A0A0AF5000000FF3A3A 3AC5000000000000000000000000000000000000000000000000000000000000 000000000000FCFCFC03E7E7E7189393936C464646B9222222DD2D2D2DD25353 53AC7B7B7B849D9D9D62B6B6B649BDBDBD42A8A8A8575C5C5CA3000000FF0000 00FF010202FE51ACB4FF73F4FFFF70EEFBFF71EFFCFF71EFFCFF71EFFCFF71EF FCFF70EEFBFF77FBFFFF3A7B82FF000000FF141414EBD8D8D827000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000008F8F8F700505 05FA010101FE000000FF000000FF000000FFB0B0B0FFE1E1E1FF303030FF0000 00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FFA1A1A1FFFDFDFDFF1D1D1DFF000000FF000000FF0000 00FF000000FF262626D9DCDCDC23000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000F2F2F20D9FA0A16A676B73E07E8590FB777E 8BFF717987FF69707DFE555C69FF3C424EFF2D3243FF3A4068FF1E2474FFB9C1 BCFFC3CBCEFFA8B1B8FFAEB7BDFFABB5BCFF9CA7AFFF7D8994FF757E89FF6672 79FF2E385EFF384264FF233055FF2C3775FF666F75FF878F98FF9CA4A9FF929B A5FF969FA7FF939BA4FFCCD2D6FFC4CCD1FFB1BAC1FFA9B2BAFFABB4BCFFC7CD D1FFCED6DAFFC8D1D6FFCBD4D8FFC6D1D4FFBDC6CCFFBFC7CDFFB4BFC6FFC9D2 D6FFD4DADCFFD5DDDFFFD2D8DBFFCED5D9FFD1D8DBFFCBD3D6FFB6C0C5FFC3CB D0FFBAC4CAFFBEC8CCFF7F8A8FFF475156FF1D202EFF151619FF111113FF0504 05FF0C0C0CFE0E0F11FF121215F7A0A0A062F6F6F60900000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FDFDFD02A3A3A35C6161 619ED3D3D32C0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000D4D4D42B1515 15EA000000FF000000FF53AFB9FF71F0FDFF71EFFCFF70EEFBFF70EEFBFF71EF FCFF71EFFCFF4A9DA5FE020404FF060606F9A0A0A05F00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000F9F9F9061616 16E9000000FF000000FF000000FF000000FF2B2B2BFFEAEAEAFF313131FF0000 00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FFB3B3B3FFA0A0A0FF000000FF000000FF000000FF0000 00FF010101FE6969699600000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000FAFAFA05D6D6D6298E8F90807173 78CD636A71FE636B76FF5F6571FF606671FE454B56FE596073FF869092FFD9DF E2FFC0C9CEFFCDD3DAFFB3BDC3FFA2ACB4FF89949BFF7B8792FE5F6E85FF5564 7EFF6E788CFF79848FFF929DA3FFA7B0B4FFAFB9C1FF9EAAB2FFA5AFB6FFBEC7 CDFFC2C9CEFFD1D7DBFFC4CBD0FFB9C0C8FFC2C9CDFEBEC7CCFFBDC5CBFFBCC7 CCFFBBC5CCFFBCC6CDFFBDC8CCFFB9C3CAFFB0B8C1FFB6BEC6FFB7C1C8FFC0CA CFFFCBD4D9FFCCD3D9FFBEC5CAFFC0C6CBFFC9D0D4FFD1D8DCFFC4CDD1FFADB6 BDFFAEB8BEFFACB5BCFFB0BAC1FFA6B1BAFFB6BEC4FE8B96A1FF6F7782FF3C42 48FF0B0B0EFF020100FF0A0A0AFF212122E6CECECE3300000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000E2E2 E21D3B3B3BC4000000FF010202FE3C8087FF71F0FDFF74F6FFFF75F9FFFF6DE7 F4FF38787EFE030707FF000000FF8484847B0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000008383 837C000000FF010101FE000000FF000000FF090909FF8D8D8DFF2D2D2DFF0000 00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FFA6A6A6FF232323FF000000FF000000FF000000FF0000 00FF0E0E0EF1CECECE3100000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FEFEFE01F8F8F807DDDE DE22A0A1A16453575AD7474E55FF545A63FF8E969CFFB2B8BBFF7F8589FF8B91 95FF8D959AFF696F74FF62686EFF73797FFF879096FF909BA2FF9CA7B0FF939C A4FFA6AFB3FF868C90FF787D7FF666696CDD75787BEF808588FE83898BFB9BA1 A4FFBBBFC1FFC1C9CDFFBFC9CCFFC1C9CDFFC2CACDFFBDC4C7FF93999DFF636A 6DED7B7F83F48A9194FF777E81F5616567E17F868DFF9DA6AAFF899196FFA4AC B1FFA9B1B6FFA7B0B4FFACB4BAFFCBD1D4FFC3C8CDFFBAC0C5FFCBD2D7FFDDE2 E5FFD0D7DAFFC3C9CEFFB1B7BCFFC1CACEFFC4C9CDFFB4BABFFF90979BFF7277 7CFF555C61FF505961FF1F2224FF555555ACECECEC1300000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F5F5F50A575757A8000000FF000101FF152C2FFE47979EFF3B7E85FF0E1F 20FF000000FF000000FF9A9A9A65000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000FCFC FC030B0B0BF4000000FF000000FF000000FF000000FF161616FF0C0C0CFF0000 00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF212121FF020202FF000000FF000000FF010101FE0000 00FF4A4A4AB50000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FCFCFC03E5E5E51AA7A8A75E8B8B8A7E9292926D9A9A9A65B8B8B847BABA BA45B5B5B54AC2C2C23DBFBFBF40B2B2B24D9A9A9A65858485968080819C8383 839097979768C2C2C23DD7D7D728DFDFDF20DCDCDC23D2D2D22DC8C8C837B7B7 B7489393936C838383838080808C808080888484847B8C8C8C73BABABA45D2D2 D22DD4D4D42BD1D1D12ED6D6D629D9D9D926C2C2C23DABABAB54B6B6B649ADAD AD52A4A4A45B9E9E9E61868686797F808091868787A67B7B7B9B7E7F7FA28485 86AD8282839F808181889090906F89898A868585857A90908F71B7B7B748C7C7 C738C4C4C43BB0B0B04FB9B9B948E9E9E916FDFDFD0200000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000A0A0A05F181818E7050505FA000000FF000000FF0808 08F7202020DFB1B1B14E00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00008B8B8B74000000FF010101FE000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF000000FF000000FF010101FE0000 00FFD5D5D52A0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FEFEFE01FBFBFB04FDFD FD02000000000000000000000000000000000000000000000000000000000000 00000000000000000000FDFDFD02FDFDFD02FEFEFE0100000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000FDFDFD02FBFBFB04FAFAFA05F9F9F906F9F9 F906FBFBFB04FDFDFD02FEFEFE0100000000FEFEFE0100000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000EEEEEE11A2A2A25D7F7F7F808484847BABAB AB54F5F5F50A0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000ECECEC13191919E6000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF0000 00FF000000FF000000FF000000FF000000FF000000FF000000FF000000FF5050 50AF000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000424D3E000000000000003E000000 2800000080010000C00000000100010000000000002400000000000000000000 000000000000000000000000FFFFFF00FFFFFFFFFC00003FFFFFFFFFFFFFFFFF FFC007FFFFFFFFFF000000000000000000000000000000000000000000000000 FFFFFFFFC0000003FFFFFFFFFFFFFFFFFFC003FFFFFFFFFF0000000000000000 00000000000000000000000000000000FFFFFFFE000000007FFFFFFFFFFFFFFF FFC003FFFFFFFFFF000000000000000000000000000000000000000000000000 FFFFFFF8000000001FFFFFFFFFFFFFFFFF8003FFFFFFFFFF0000000000000000 00000000000000000000000000000000FFFFFFE00000000003FFFFFFFFFFFFFF FF8001FFFFFFFFFF000000000000000000000000000000000000000000000000 FFFFFF800000000000FFFFFFFFFFFFFFFF0000FFFFFFFFFF0000000000000000 00000000000000000000000000000000FFFFFE0000000000007FFFFFFFFFFFFF FF0000FFFFFFFFFF000000000000000000000000000000000000000000000000 FFFFF80000000000001FFFFFFFFFFFFFFE00007FFFFFFFFF0000000000000000 00000000000000000000000000000000FFFFF00000000000000FFFFFFFFFFFFF FE00007FFFFFFFFF000000000000000000000000000000000000000000000000 FFFFE000000000000003FFFFFFFFFFFFFE00007FFFFFFFFF0000000000000000 00000000000000000000000000000000FFFF8000000000000001FFFFFFFFFFFF FC00003FFFFFFFFF000000000000000000000000000000000000000000000000 FFFF0000000000000000FFFFFFFFFFFFFC00003FFFFFFFFF0000000000000000 00000000000000000000000000000000FFFE00000000000000007FFFFFFFFFFF F800001FFFFFFFFF000000000000000000000000000000000000000000000000 FFFC00000000000000003FFFFFFFFFFFF000001FFFFFFFFF0000000000000000 00000000000000000000000000000000FFF800000000000000001FFFFFFFFFFF F000000FFFFFFFFF000000000000000000000000000000000000000000000000 FFF000000000000000000FFFFFFFFFFFF000000FFFFFFFFF0000000000000000 00000000000000000000000000000000FFE0000000000000000007FFFFFFFFFF E000000FFFFFFFFF000000000000000000000000000000000000000000000000 FFC0000000000000000003FFFFFFFFFFE0000007FFFFFFFF0000000000000000 00000000000000000000000000000000FFC0000000000000000001FFFFFFFFFF C0000007FFFFFFFF000000000000000000000000000000000000000000000000 FF80000000000000000001FFFFFFFFFFC0000003FFFFFFFF0000000000000000 00000000000000000000000000000000FF00000000000000000000FFFFFFFFFF 80000001FFFFFFFF000000000000000000000000000000000000000000000000 FF000000000000000000007FFFFFFFFF80000001FFFFFFFF0000000000000000 00000000000000000000000000000000FE000000000000000000007FFFFFFFFF 80000001FFFFFFFF000000000000000000000000000000000000000000000000 FC000000000000000000003FFFFFFFFF00000001FFFFFFFF0000000000000000 00000000000000000000000000000000FC000000000000000000003FFFFFFFFF 00000000FFFFFFFF000000000000000000000000000000000000000000000000 F8000000000000000000001FFFFFFFFE000000007FFFFFFF0000000000000000 00000000000000000000000000000000F8000000000000000000000FFFFFFFFC 000000007FFFFFFF000000000000000000000000000000000000000000000000 F0000000000000000000000FFFFFFFFC000000003FFFFFFF0000000000000000 00000000000000000000000000000000F0000000000000000000000FFFFFFFFC 000000003FFFFFFF000000000000000000000000000000000000000000000000 E00000000000000000000007FFFFFFF8000000003FFFFFFF0000000000000000 00000000000000000000000000000000E00000000000000000000007FFFFFFF8 000000001FFFFFFF000000000000000000000000000000000000000000000000 E00000000000000000000003FFFFFFF0000000001FFFFFFF0000000000000000 00000000000000000000000000000000C00000000000000000000003FFFFFFF0 000000000FFFFFFF000000000000000000000000000000000000000000000000 C00000000000000000000003FFFFFFE0000000000FFFFFFF0000000000000000 00000000000000000000000000000000C00000000000000000000001FFFFFFE0 0000000007FFFFFF000000000000000000000000000000000000000000000000 800000000000000000000001FFFFFFE00000000007FFFFFF0000000000000000 00000000000000000000000000000000800000000000000000000001FFFFFFC0 0000000007FFFFFF000000000000000000000000000000000000000000000000 800000000000000000000001FFFFFFC00000000003FFFFFF0000000000000000 00000000000000000000000000000000800000000000000000000000FFFFFF80 0000000001FFFFFF000000000000000000000000000000000000000000000000 000000000000000000000000FFFFFF000000000001FFFFFF0000000000000000 00000000000000000000000000000000000000000000000000000000FFFFFF00 0000000000FFFFFF000000000000000000000000000000000000000000000000 000000000000000000000000FFFFFF000000000000FFFFFF0000000000000000 00000000000000000000000000000000000000000000000000000000FFFFFE00 0000000000FFFFFF000000000000000000000000000000000000000000000000 000000000000000000000000FFFFFE0000000000007FFFFF0000000000000000 00000000000000000000000000000000000000000000000000000000FFFFFC00 00000000007FFFFF000000000000000000000000000000000000000000000000 000000000000000000000000FFFFFC0000000000003FFFFF0000000000000000 00000000000000000000000000000000000000000000000000000000FFFFF800 00000000003FFFFF000000000000000000000000000000000000000000000000 000000000000000000000000FFFFF80000000000001FFFFF0000000000000000 00000000000000000000000000000000000000000000000000000000FFFFF800 00000000001FFFFF000000000000000000000000000000000000000000000000 000000000000000000000000FFFFF00000000000001FFFFF0000000000000000 00000000000000000000000000000000000000000000000000000000FFFFF000 00000000000FFFFF000000000000000000000000000000000000000000000000 000000000000000000000000FFFFE00000000000000FFFFF0000000000000000 00000000000000000000000000000000000000000000000000000000FFFFC000 000000000007FFFF000000000000000000000000000000000000000000000000 000000000000000000000000FFFFC000000000000003FFFF0000000000000000 00000000000000000000000000000000000000000000000000000000FFFFC000 000000000003FFFF000000000000000000000000000000000000000000000000 000000000000000000000000FFFFC000000000000003FFFF0000000000000000 00000000000000000000000000000000000000000000000000000000FFFFC000 000000000003FFFF000000000000000000000000000000000000000000000000 800000000000000000000000FFFFC000000000000007FFFF0000000000000000 00000000000000000000000000000000800000000000000000000001FFFFE000 000000000007FFFF000000000000000000000000000000000000000000000000 800000000000000000000001FFFFE00000000000000FFFFF0000000000000000 00000000000000000000000000000000800000000000000000000001FFFFF000 00000000000FFFFF000000000000000000000000000000000000000000000000 C00000000000000000000001FFFFF00000000000001FFFFF0000000000000000 00000000000000000000000000000000C00000000000000000000003FFFFF800 00000000001FFFFF000000000000000000000000000000000000000000000000 C00000000000000000000003FFFFF80000000000001FFFFF0000000000000000 00000000000000000000000000000000E00000000000000000000003FFFFF800 00000000003FFFFF000000000000000000000000000000000000000000000000 E00000000000000000000007FFFFFC0000000000007FFFFF0000000000000000 00000000000000000000000000000000E00000000000000000000007FFFFFE00 00000000007FFFFF000000000000000000000000000000000000000000000000 F0000000000000000000000FFFFFFE000000000000FFFFFF0000000000000000 00000000000000000000000000000000F0000000000000000000000FFFFFFF00 0000000000FFFFFF000000000000000000000000000000000000000000000000 F8000000000000000000001FFFFFFF000000000000FFFFFF0000000000000000 00000000000000000000000000000000F8000000000000000000001FFFFFFF00 0000000000FFFFFF000000000000000000000000000000000000000000000000 FC000000000000000000003FFFFFFF800000000001FFFFFF0000000000000000 00000000000000000000000000000000FC000000000000000000003FFFFFFF80 0000000003FFFFFF000000000000000000000000000000000000000000000000 FE000000000000000000007FFFFFFFC00000000003FFFFFF0000000000000000 00000000000000000000000000000000FF000000000000000000007FFFFFFFC0 0000000007FFFFFF000000000000000000000000000000000000000000000000 FF00000000000000000000FFFFFFFFE00000000007FFFFFF0000000000000000 00000000000000000000000000000000FF80000000000000000001FFFFFFFFE0 0000000007FFFFFF000000000000000000000000000000000000000000000000 FFC0000000000000000003FFFFFFFFE0000000000FFFFFFF0000000000000000 00000000000000000000000000000000FFE0000000000000000003FFFFFFFFF0 000000000FFFFFFF000000000000000000000000000000000000000000000000 FFE0000000000000000007FFFFFFFFF8000000001FFFFFFF0000000000000000 00000000000000000000000000000000FFF000000000000000000FFFFFFFFFF8 000000003FFFFFFF000000000000000000000000000000000000000000000000 FFF800000000000000001FFFFFFFFFFC000000003FFFFFFF0000000000000000 00000000000000000000000000000000FFFC00000000000000003FFFFFFFFFFC 000000003FFFFFFF000000000000000000000000000000000000000000000000 FFFE00000000000000007FFFFFFFFFFC000000003FFFFFFF0000000000000000 00000000000000000000000000000000FFFF0000000000000000FFFFFFFFFFFE 000000007FFFFFFF000000000000000000000000000000000000000000000000 FFFFC000000000000001FFFFFFFFFFFE00000000FFFFFFFF0000000000000000 00000000000000000000000000000000FFFFE000000000000007FFFFFFFFFFFF 00000000FFFFFFFF000000000000000000000000000000000000000000000000 FFFFF00000000000000FFFFFFFFFFFFF80000001FFFFFFFF0000000000000000 00000000000000000000000000000000FFFFFC0000000000003FFFFFFFFFFFFF 80000001FFFFFFFF000000000000000000000000000000000000000000000000 FFFFFE0000000000007FFFFFFFFFFFFF80000001FFFFFFFF0000000000000000 00000000000000000000000000000000FFFFFF800000000001FFFFFFFFFFFFFF 80000003FFFFFFFF000000000000000000000000000000000000000000000000 FFFFFFE00000000007FFFFFFFFFFFFFFC0000003FFFFFFFF0000000000000000 00000000000000000000000000000000FFFFFFF8000000001FFFFFFFFFFFFFFF E0000007FFFFFFFF000000000000000000000000000000000000000000000000 FFFFFFFF00000000FFFFFFFFFFFFFFFFE0000007FFFFFFFF0000000000000000 00000000000000000000000000000000FFFFFFFFE0000007FFFFFFFFFFFFFFFF F000000FFFFFFFFF000000000000000000000000000000000000000000000000 FFFFFFFFFE00007FFFFFFFFFFFFFFFFFF000000FFFFFFFFF0000000000000000 00000000000000000000000000000000FFFFFFFFFFE003FFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80FFFFFFFFFFFFF FFFFFFFFFFE003FFFFFFFFFFFFFFFFFFFFFFFF1FFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFC001FFFFFFFFFFFFFFFFFFFFFFC001FFFFFFFFFFFFFFFFFF FFFFFF07FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00007FFFFFFFFFFF FFFFFFFFFF8001FFFFFFFFFFFFFFFFFFFFFFFF03FFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFC00001FFFFFFFFFFFFFFFFFFFFF8000FFFFFFFFFFFFFFFFFF FFFFFF01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8000007FFFFFFFFFF FFFFFFFFFF0000FFFFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFF0000003FFFFFFFFFFFFFFFFFFFF0000FFFFFFFFFFFFFFFFFF FFFFFF803FFFFFFFFFFFFFFFFFFFFFF00FFFFFFFFFFFFFE0000001FFFFFFFFFF FFFFFFFFFF00007FFFFFFFFFFFFFFFFFFFFFFFC01FFFFFFFFFFFFFFFFFFFF000 07FFFFFFFFFFFFE0000000FFFFFFFFFFFFFFFFFFFE00007FFFFFFFFFFFFFFFFF FFFFFFC00FFFFFFFFFFFFFFFFFF0000001FFFFFFFFFFFFC00000007FFFFFFFFF FFFFFFFFFE00003FFFFFFFFFFFFFFFFFFE0FFFE007FFFFFFFFFFFFFF80000000 00FFFFFFFFFFFFC00000007FFFFFFFFFFFFFFFFFFC00003FFFFFFFFFFFFFFFFF FC07FFF003FFFFFFFFFFFFFE00000000007FFFFFFFFFFF800000003FFFFFFFFF FFFFFFFFFC00001FFFFFFFFFFFFFFFFFF807FFF003FFFFFFFFFFFFFC00000000 007FFFFFFFFFFF000000003FFFFFFFFFFFFFFFFFF800000FFFFFFFFFFFFFFFFF F007FFF800FFFFFFFFFFFFF800000000003FFFFFFFFFFC000000001FFFFFFFFF FFFFFFFFF800000FFFFFFFFFFFFFFFFFE00FFFFC00FFFFFFFFFFFFF000000000 001FFFFFFFFFF8000000000FFFFFFFFFFFFFFFFFF000000FFFFFFFFFFFFFFFFF E01FFFFC007FFFFFFFFFFFE000000000001FFFFFFFFFF0000000000FFFFFFFFF FFFFFFFFF000000FFFFFFFFFFFFFFFFF803FFFFC003FFFFFFFFFFFC000000000 001FFFFFFFFFE00000000007FFFFFFFFFFFFFFFFF0000007FFFFFFFFFFFFFFFF 803FFFFE001FFFFFFFFFFF8000000000000FFFFFFFFFC00000000003FFFFFFFF FFFFFFFFE0000007FFFFFFFFFFFFFFFF007FFFFE001FFFFFFFFFFF0000000000 0007FFFFFFFF800000000001FFFFFFFFFFFFFFFFE0000003FFFFFFFFFFFFFFFC 00FFFFFE001FFFFFFFFFFE00000000000003FFFFFFFF0000000000007FFFFFFF FFFFFFFFC0000001FFFFFFFFFFFFFFFC00FFFFFE000FFFFFFFFFFC0000000000 0003FFFFFFFE0000000000003FFFFFFFFFFFFFFFC0000001FFFFFFFFFFFFFFF8 00FFFFFE000FFFFFFFFFF800000000000003FFFFFFFE0000000000001FFFFFFF FFFFFFFF80000000FFFFFFFFFFFFFFF001FFFFFF0007FFFFFFFFF00000000000 0001FFFFFFFE000000000000007FFFFFFFFFFFFF00000000FFFFFFFFFFFFFFE0 01FFFFFF8003FFFFFFFFE000000000000000FFFFFFFC000000000000003FFFFF FFFFFFFF00000000FFFFFFFFFFFFFFC003FFFFFF8003FFFFFFFFC00000000000 0000FFFFFFF8000000000000001FFFFFFFFFFFFF000000007FFFFFFFFFFFFF80 07FFFFFF8003FFFFFFFF80000000000000007FFFFFF8000000000000000FFFFF FFFFFFFE000000007FFFFFFFFFFFFF8007FFFFFFC003FFFFFFFF000000000000 00007FFFFFF00000000000000007FFFFFFFFFFFE000000003FFFFFFFFFFFFF00 0FFFFFFFC001FFFFFFFE00000000000000003FFFFFF00000000000000003FFFF FFFFFFFC000000003FFFFFFFFFFFFF000FFFFFFFC001FFFFFFFC000000000000 00003FFFFFF00000000000000003FFFFFFFFFFFC000000001FFFFFFFFFFFFF00 1FFFFFFFC001FFFFFFF800000000000000001FFFFFF00000000000000003FFFF FFFFFFF8000000001FFFFFFFFFFFFF003FFFFFFFC001FFFFFFF0000000000000 00000FFFFFE00000000000000003FFFFFFFFFFF8000000000FFFFFFFFFFFFE00 3FFFFFFFC001FFFFFFE000000000000000000FFFFFE00000000000000001FFFF FFFFFFF0000000000FFFFFFFFFFFFE003FFFFFFFC001FFFFFFC0000000000000 000007FFFFE00000000000000001FFFFFFFFFFF0000000000FFFFFFFFFFFFC00 7FFFFFFFC001FFFFFF80000000000000000007FFFFE00000000000000003FFFF FFFFFFF00000000007FFFFFFFFFFF8007FFFFFFFC001FFFFFF00000000000000 000003FFFFC00000000000000003FFFFFFFFFFE00000000007FFFFFFFFFFF800 7FFFFFFFC001FFFFFE00000000000000000001FFFFC00000000000000003FFFF FFFFFFE00000000003FFFFFFFFFFF8007FFFFFFFC000FFFFFC00000000000000 000001FFFFC00000000000000003FFFFFFFFFFC00000000003FFFFFFFFFFF800 7FFFFFFFC000FFFFF800000000000000000000FFFFC00000000000000001FFFF FFFFFFC00000000001FFFFFFFFFFF0007FFFFFFFC000FFFFF800000000000000 000000FFFFC00000000000000000FFFFFFFFFF800000000001FFFFFFFFFFF000 7FFFFFFFC0007FFFF0000000000000000000007FFFC00000000000000000FFFF FFFFFF800000000000FFFFFFFFFFF0007FFFFFFFC0007FFFE000000000000000 0000003FFFC000000000000000007FFFFFFFFF000000000000FFFFFFFFFFF000 7FFFFFFFC0007FFFC0000000000000000000003FFFC000000000000000007FFF FFFFFF000000000000FFFFFFFFFFE0007FFFFFFFC0007FFF8000000000000000 0000001FFFC000000000000000003FFFFFFFFF0000000000007FFFFFFFFFE000 7FFFFFFFC0007FFF80000000000000000000001FFFC000000000000000003FFF FFFFFE0000000000007FFFFFFFFFE0007FFFFFFFC0007FFF0000000000000000 0000000FFFC000000000000000001FFFFFFFFE0000000000003FFFFFFFFFC000 7FFF8FFFC0007FFF000000000000000000000007FFC000000000000000000FFF FFFFFC0000000000003FFFFFFFFFC0007FFE03FFC0007FFF0000000000000000 00000007FFC000000000000000000FFFFFFFF80000000000001FFFFFFFFFC000 7FFC01FF80007FFF000000000000000000000003FFE000000000000000000FFF FFFFF80000000000000FFFFFFFFFC0007FF800FF80007FFF8000000000000000 00000003FFE0000000000000000007FFFFFFF00000000000000FFFFFFFFFC000 7FF8007F80007FFF800000000000000000000003FFE0000000000000000007FF FFFFF00000000000000FFFFFFFFFC0007FF0007F80007FFFC000000000000000 00000001FFE0000000000000000007FFFFFFF00000000000000FFFFFFFFFC000 7FF0003F80007FFFC00000000000000000000001FFE0000000000000000003FF FFFFF000000000000007FFFFFFFF80007FE0003F80007FFFE000000000000000 00000001FFF0000000000000000003FFFFFFE000000000000007FFFFFFFF8000 7FE0003F80007FFFF00000000000000000000003FFF0000000000000000001FF FFFFC000000000000003FFFFFFFF80007FC0003F80007FFFF800000000000000 00000003FFF0000000000000000001FFFFFFC000000000000001FFFFFFFF8000 7FC0003F80007FFFF80000000000000000000007FFF0000000000000000001FF FFFFC000000000000001FFFFFFFF80007FE0003F80007FFFFC00000000000000 00000007FFF8000000000000000001FFFFFFC000000000000003FFFFFFFF8000 7FE0003F80007FFFFC000000000000000000000FFFF8000000000000000001FF FFFFE000000000000003FFFFFFFF80007FE0003F00007FFFFE00000000000000 0000001FFFFC000000000000000001FFFFFFE000000000000007FFFFFFFF8000 3FE0007F00007FFFFF000000000000000000003FFFFC000000000000000001FF FFFFF000000000000007FFFFFFFF80003FE0007F00007FFFFF80000000000000 0000003FFFFE000000000000000001FFFFFFF00000000000000FFFFFFFFF8000 3FF0007F00007FFFFF80000000000000000000FFFFFE000000000000000001FF FFFFF00000000000000FFFFFFFFF80003FF000FE00007FFFFFC0000000000000 000000FFFFFF000000000000000001FFFFFFF80000000000000FFFFFFFFF8000 3FF001FE00007FFFFFE0000000000000000001FFFFFF000000000000000001FF FFFFF80000000000001FFFFFFFFF80001FFC03FE0000FFFFFFE0000000000000 000003FFFFFF000000000000000001FFFFFFFC0000000000001FFFFFFFFFC000 1FFF1FFE0000FFFFFFF0000000000000000007FFFFFE000000000000000001FF FFFFFC0000000000003FFFFFFFFFC0000FFFFFFC0000FFFFFFF0000000000000 00000FFFFFFE000000000000000003FFFFFFFE0000000000003FFFFFFFFFC000 0FFFFFFC0001FFFFFFF800000000000000000FFFFFFE000000000000000003FF FFFFFE0000000000007FFFFFFFFFC0000FFFFFFC0001FFFFFFFC000000000000 00001FFFFFFE000000000000000003FFFFFFFF0000000000007FFFFFFFFFC000 07FFFFF80001FFFFFFFC00000000000000003FFFFFFE000000000000000007FF FFFFFF000000000000FFFFFFFFFFC00007FFFFF80001FFFFFFFE000000000000 00007FFFFFFE00000000000000000FFFFFFFFF000000000000FFFFFFFFFFC000 03FFFFF00001FFFFFFFE0000000000000000FFFFFFFE00000000000000000FFF FFFFFF800000000000FFFFFFFFFFC00001FFFFF00001FFFFFFFF000000000000 0001FFFFFFFE00000000000000000FFFFFFFFF800000000001FFFFFFFFFFE000 01FFFFF00001FFFFFFFF8000000000000003FFFFFFFE00000000000000001FFF FFFFFFC00000000001FFFFFFFFFFE00000FFFFE00003FFFFFFFFC00000000000 0003FFFFFFFF00000000000000001FFFFFFFFFE00000000003FFFFFFFFFFF000 00FFFFE00003FFFFFFFFC000000000000007FFFFFFFF00000000000000003FFF FFFFFFE00000000007FFFFFFFFFFF00000FFFFC00003FFFFFFFFE00000000000 000FFFFFFFFF80000000000000007FFFFFFFFFF00000000007FFFFFFFFFFF000 007FFFC00003FFFFFFFFF00000000000001FFFFFFFFFC000000000000000FFFF FFFFFFF0000000000FFFFFFFFFFFF800003FFF800007FFFFFFFFF00000000000 003FFFFFFFFFC000000000000003FFFFFFFFFFF0000000000FFFFFFFFFFFF800 001FFF800007FFFFFFFFF80000000000007FFFFFFFFFC000000000000003FFFF FFFFFFF8000000000FFFFFFFFFFFF800000FFF00000FFFFFFFFFF80000000000 00FFFFFFFFFF8000000000000003FFFFFFFFFFF8000000000FFFFFFFFFFFF800 0007FF00000FFFFFFFFFFC000000000000FFFFFFFFFF8000000000000007FFFF FFFFFFFC000000001FFFFFFFFFFFF8000007FE00001FFFFFFFFFFE0000000000 01FFFFFFFFFFC000000000000007FFFFFFFFFFFC000000003FFFFFFFFFFFF000 0007FC00001FFFFFFFFFFF000000000007FFFFFFFFFFC00000000000000FFFFF FFFFFFFE000000003FFFFFFFFFFFF0000000F000001FFFFFFFFFFF0000000000 07FFFFFFFFFFC00000000000000FFFFFFFFFFFFE000000007FFFFFFFFFFFC000 00000000000FFFFFFFFFFF80000000000FFFFFFFFFFFC00E00000000001FFFFF FFFFFFFF000000007FFFFFFFFFFFC00000000000000FFFFFFFFFFFC000000000 1FFFFFFFFFFFC01F80000000001FFFFFFFFFFFFF00000000FFFFFFFFFFFF8000 000000000007FFFFFFFFFFE0000000003FFFFFFFFFFFE01FC0000000003FFFFF FFFFFFFF00000000FFFFFFFFFFFF0000000000000003FFFFFFFFFFF800000007 FFFFFFFFFFFFF81FE000000001FFFFFFFFFFFFFF80000000FFFFFFFFFFFE0000 000000000001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC0FF00000000FFFFFFF FFFFFFFF80000000FFFFFFFFFFFE0000000000000000FFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFE0FF80000003FFFFFFFFFFFFFFFC0000001FFFFFFFFFFFE0000 0000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF87FFFFC0007FFFFFFF FFFFFFFFC0000003FFFFFFFFFFFF00000000000000007FFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFE000FFFFFFFFFFFFFFFFE0000003FFFFFFFFFFFF8000 0000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF001FFFFFFFF FFFFFFFFE0000007FFFFFFFFFFFFF0000000000000007FFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFC03FFFFFFFFFFFFFFFFF0000007FFFFFFFFFFFFFFFF 8FFC7FFE017FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE07FFFFFFFF FFFFFFFFF000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000 000000000000} end object ProfilePopupMenu: TPopupMenu OnPopup = ProfilePopupMenuPopup Left = 48 Top = 136 object NewProfileItem: TMenuItem Caption = 'New profile' OnClick = NewProfileItemClick end object DeleteProfileItem: TMenuItem Caption = 'Delete profile' OnClick = DeleteProfileItemClick end end object GeneralIcons: TImageList Left = 96 Top = 416 Bitmap = { 494C0101020008004C0010001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600 0000000000003600000028000000400000001000000001002000000000000010 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000075848FFF66808FFF607987FF576E 7BFF4E626FFF445661FF394852FF2E3A43FF252E35FF1B2229FF14191EFF0E12 16FF0E1318FF000000000000000000000000000000000000000000000000C4C4 E3FF2313C2FF7663D6FF00000000000000000000000000000000000000007663 D6FF2313C2FFC4C4E3FF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000778792FF89A1ABFF6AB2D4FF008F CDFF008FCDFF008FCDFF048CC7FF0888BEFF0F82B4FF157CA9FF1B779FFF1F72 96FF214A5BFEBDC2C44A00000000000000000000000000000000C4C4E3FF2313 C2FF3631EEFF2313C2FF7663D6FF0000000000000000000000007663D6FF2313 C2FF3631EEFF2313C2FFC4C4E3FF000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000007A8A95FF7EBED3FF8AA4AEFF7EDC FFFF5FCFFFFF55CBFFFF4CC4FAFF41BCF5FF37B3F0FF2EAAEBFF24A0E5FF138C D4FF236780FF5E686CB4000000000000000000000000000000009D9CDAFF2313 C2FF4A3DECFF4A3DECFF2313C2FF7663D6FF9D9CDAFF7663D6FF2313C2FF4A3D ECFF4A3DECFF2313C2FF9D9CDAFF000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000007D8E98FF79D2ECFF8BA4ADFF89C2 CEFF71D8FFFF65D3FFFF5CCEFFFF51C9FEFF49C1FAFF3FB9F5FF34B0EEFF29A8 E9FF1085CDFF224B5BFFDADDDF27000000000000000000000000000000007663 D6FF2313C2FF4A3DECFF4A3DECFF3737D8FF2313C2FF3737D8FF4A3DECFF4A3D ECFF2313C2FF7663D6FF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000080919CFF81D7EFFF7DC5E0FF8CA6 B0FF80DDFEFF68D3FFFF67D4FFFF62D1FFFF58CDFFFF4EC7FCFF46BEF7FF3BB6 F2FF31ACECFF256981FF7A95A190000000000000000000000000000000000000 00007663D6FF2C26C4FF4A3DECFF4A3DECFF4A3DECFF4A3DECFF4A3DECFF2C26 C4FF7663D6FF0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000083959FFF89DCF1FF8CE2FFFF8DA8 B1FF8CBAC7FF74D8FFFF67D4FFFF67D4FFFF67D4FFFF5FD0FFFF54CDFFFF4BC5 FCFF41BBF7FF2EA2DBFF516674F1E1E4E62B0000000000000000000000000000 0000000000002C26C4FF3631EEFF4F4EECFF4F4EECFF4F4EECFF3631EEFF2C26 C4FF000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000869AA3FF92E1F2FF98E8FDFF80C4 DEFF8EA7B0FF81DEFDFF84E0FFFF84E0FFFF84E0FFFF84E0FFFF81DFFFFF7BDD FFFF74D8FFFF6BD6FFFF56A9D1FF8E9BA3A20000000000000000000000000000 0000000000003737D8FF3737D8FF655BF1FF655BF1FF655BF1FF3631EEFF3738 BBFF000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000889CA5FF9AE6F3FF9FEBFBFF98E8 FEFF8BACB9FF8BACB9FF8AAAB7FF88A6B3FF86A3AFFF839FAAFF819AA6FF7F95 A1FF7C919DFF7A8E99FF798B95FF778893FF0000000000000000000000000000 00007663D6FF3738BBFF655BF1FF655BF1FF655BF1FF655BF1FF655BF1FF3D47 C8FF7663D6FF0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000008BA0A8FFA0EAF6FFA6EEF9FF9FEB FBFF98E8FEFF7ADAFFFF67D4FFFF67D4FFFF67D4FFFF67D4FFFF67D4FFFF67D4 FFFF778893FF0000000000000000000000000000000000000000000000007F86 DAFF3D47C8FF7774F3FF7774F3FF5B61E0FF3D47C8FF5B61E0FF7774F3FF7774 F3FF3D47C8FF7F86DAFF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000008EA2ABFFA7EEF6FFABF0F7FFA6EE F9FF9FEBFBFF98E8FDFF71D4FBFF899EA7FF8699A3FF82949FFF7E909AFF7A8C 97FF778893FF00000000000000000000000000000000000000009D9CDAFF4656 C8FF8586F0FF8586F0FF4656C8FF5B64CEFF9D9CDAFF5B64CEFF4656C8FF8586 F0FF8586F0FF4656C8FF9D9CDAFF000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000008FA4ACFFA0D2DAFFABF0F7FFABF0 F7FFA6EEF9FF9FEBFBFF8DA1AAFFC0D0D6820000000000000000000000000000 0000000000000000000000000000000000000000000000000000C4C4E3FF4656 C8FF4F4EECFF4656C8FF7F86DAFF0000000000000000000000007F86DAFF4656 C8FF4F4EECFF4656C8FFC4C4E3FF000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000D8DFE2578FA4ACFF8FA4ACFF8FA4 ACFF8FA4ACFF8FA4ACFFBDCFD68D000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000C4C4 E3FF4656C8FF7F86DAFF00000000000000000000000000000000000000007F86 DAFF4656C8FFC4C4E3FF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000424D3E000000000000003E000000 2800000040000000100000000100010000000000800000000000000000000000 000000000000000000000000FFFFFF00FFFFFFFF00000000FFFFFFFF00000000 0007E3E3000000000003C1C1000000000003C001000000000001E00300000000 0001F007000000000000F80F000000000000F80F000000000000F00700000000 0007E003000000000007C0010000000000FFC1C10000000001FFE3E300000000 FFFFFFFF00000000FFFFFFFF0000000000000000000000000000000000000000 000000000000} end end ================================================ FILE: frontend/msProfileForm.pas ================================================ unit msProfileForm; interface uses Windows, Messages, SysUtils, Classes, Controls, Forms, StdCtrls, Graphics, ImgList, Menus, Dialogs, ExtCtrls, pngimage, // mte components RttiIni, mteHelpers, // mp components msConfiguration, msLoader, msProfilePanel; type TProfileForm = class(TForm) btnOk: TButton; btnCancel: TButton; GameIcons: TImageList; ProfilePopupMenu: TPopupMenu; NewProfileItem: TMenuItem; DeleteProfileItem: TMenuItem; GeneralIcons: TImageList; ScrollBox: TScrollBox; NewProfilePanel: TPanel; NewProfileImage: TImage; NewProfileLabel: TLabel; PaddingLabel: TLabel; procedure FormCreate(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure FormDestroy(Sender: TObject); procedure RealignPanels; function CreateNewProfile(name: string): TProfilePanel; procedure NewProfileItemClick(Sender: TObject); procedure LoadProfiles; function ProfileExists(gameMode: Integer): Boolean; procedure CreateDefaultProfiles; procedure ProfilePopupMenuPopup(Sender: TObject); procedure SelectionChanged(Sender: TObject); procedure DeleteClicked(Sender: TObject); procedure DeleteProfileItemClick(Sender: TObject); function ProfileNameTaken(name: string): boolean; procedure NewProfileImageClick(Sender: TObject); procedure NewProfilePanelClick(Sender: TObject); procedure NewProfileLabelClick(Sender: TObject); procedure NewProfilePanelMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); private FOldWndProc: TWndMethod; FMouseInPanel: Boolean; procedure PanelWndProc(var Message: TMessage); public ProfilePanels: TList; end; var ProfileForm: TProfileForm; SelectCallback, DeleteCallback: TNotifyEvent; MouseOverProfile: TProfilePanel; ProgramPath: String; implementation {$R *.dfm} procedure TProfileForm.DeleteProfileItemClick(Sender: TObject); var bApproved: boolean; aProfile: TProfile; begin // get user verification aProfile := MouseOverProfile.GetProfile; bApproved := MessageDlg('Are you sure you want to delete '+ aProfile.name + '?', mtConfirmation, mbOKCancel, 0) = mrOk; if not (bApproved and Assigned(MouseOverProfile)) then exit; ProfilePanels.Delete(ProfilePanels.IndexOf(MouseOverProfile)); aProfile.Delete; MouseOverProfile.Free; RealignPanels; end; procedure TProfileForm.RealignPanels; var i, vPos, pCount: Integer; p: TProfilePanel; begin // just some aliases vPos := ScrollBox.VertScrollBar.ScrollPos; pCount := ProfilePanels.Count; // adjust tops NewProfilePanel.Top := 100 * pCount - vPos; for i := Pred(pCount) downto 0 do begin p := TProfilePanel(ProfilePanels[i]); p.SetTop(100 * i - vPos); end; PaddingLabel.Top := 100 * (pCount + 1) - vPos - PaddingLabel.Height; // adjust widths NewProfilePanel.Width := ScrollBox.ClientWidth; for i := Pred(pCount) downto 0 do begin p := TProfilePanel(ProfilePanels[i]); p.SetWidth(ScrollBox.ClientWidth); end; end; procedure TProfileForm.FormClose(Sender: TObject; var Action: TCloseAction); var i: Integer; p: TProfilePanel; aProfile: TProfile; begin // save all profiles for i := 0 to Pred(ProfilePanels.Count) do begin p := TProfilePanel(ProfilePanels[i]); aProfile := p.GetProfile; try SaveProfile(aProfile); except on Exception do // nothing to do end; end; // set profile if user clicked OK if ModalResult = mrOK then begin for i := 0 to Pred(ProfilePanels.Count) do begin p := TProfilePanel(ProfilePanels[i]); if p.Selected then begin CurrentProfile := TProfile.Create(''); CurrentProfile.Clone(p.GetProfile); break; end; end; end; // free memory FreeList(ProfilePanels); end; procedure TProfileForm.FormCreate(Sender: TObject); begin ProgramPath := ExtractFilePath(ParamStr(0)); ProfilePanels := TList.Create; SelectCallback := SelectionChanged; DeleteCallback := DeleteClicked; LoadProfiles; CreateDefaultProfiles; FOldWndProc := NewProfilePanel.WindowProc; NewProfilePanel.WindowProc := PanelWndProc; end; procedure TProfileForm.FormDestroy(Sender: TObject); begin NewProfilePanel.WindowProc:= FOldWndProc; end; procedure TProfileForm.LoadProfiles; var path, settingsPath: string; info: TSearchRec; p: TProfilePanel; aSettings: TSettings; begin path := ProgramPath + 'profiles\'; if not DirectoryExists(path) then exit; if FindFirst(path + '*', faAnyFile or faDirectory, info) <> 0 then exit; // add found profiles repeat if IsDotFile(info.Name) then continue; settingsPath := path + info.Name + '\settings.ini'; if not FileExists(settingsPath) then continue; aSettings := TSettings.Create; TRttiIni.Load(settingsPath, aSettings); if aSettings.profile <> '' then begin p := CreateNewProfile(aSettings.profile); p.SetGame(aSettings.gameMode); p.SetPath(aSettings.gamePath); end; aSettings.Free; until FindNext(info) <> 0; end; function TProfileForm.ProfileExists(gameMode: Integer): Boolean; var i: Integer; profile: TProfile; begin Result := False; for i := 0 to Pred(ProfilePanels.Count) do begin profile := TProfilePanel(ProfilePanels[i]).GetProfile; if profile.gameMode = gameMode then begin Result := True; break; end; end; end; procedure TProfileForm.CreateDefaultProfiles; var i: Integer; path, name: string; p: TProfilePanel; begin for i := Low(GameArray) to High(GameArray) do begin if ProfileExists(i) then continue; path := GetGamePath(GameArray[i]); name := GameArray[i].appName; if path <> '' then begin p := CreateNewProfile(name); p.SetGame(i); p.SetPath(path); end; end; end; function TProfileForm.CreateNewProfile(name: string): TProfilePanel; begin Result := TProfilePanel.ICreate(ScrollBox, GameIcons, GeneralIcons, name); Result.SetSelectCallback(SelectCallback); Result.SetDeleteCallback(DeleteCallback); ProfilePanels.Add(Result); RealignPanels; end; procedure TProfileForm.NewProfileItemClick(Sender: TObject); var name: string; i: Integer; begin // find profile name name := 'NewProfile'; i := 1; while ProfileNameTaken(name + IntToStr(i)) do Inc(i); // create a new profile name := name + IntToStr(i); CreateNewProfile(name); end; procedure TProfileForm.NewProfileImageClick(Sender: TObject); begin NewProfileItemClick(nil); end; procedure TProfileForm.NewProfileLabelClick(Sender: TObject); begin NewProfileItemClick(nil); end; procedure TProfileForm.NewProfilePanelClick(Sender: TObject); begin NewProfileItemClick(nil); end; function TProfileForm.ProfileNameTaken(name: string): boolean; var i: Integer; pName: string; begin Result := false; for i := 0 to Pred(ProfilePanels.Count) do begin pName := TProfilePanel(ProfilePanels[i]).GetProfile.name; if SameText(pName, name) then begin Result := true; break; end; end; end; procedure TProfileForm.ProfilePopupMenuPopup(Sender: TObject); var pt: TPoint; index: Integer; begin // get profile user is moused over pt := ScrollBox.ScreenToClient(Mouse.CursorPos); Index := pt.Y div 100; if Index < ProfilePanels.Count then MouseOverProfile := TProfilePanel(ProfilePanels[index]) else MouseOverProfile := nil; // can only delete profile if mouse over a profile ProfilePopupMenu.Items[1].Enabled := Assigned(MouseOverProfile); end; procedure TProfileForm.SelectionChanged(Sender: TObject); var i: Integer; p: TProfilePanel; bSelected: boolean; begin // deselect all panels except the sender for i := 0 to Pred(ProfilePanels.Count) do begin p := TProfilePanel(ProfilePanels[i]); if p <> TProfilePanel(Sender) then p.Deselect end; // enable and focus ok button if profile panel is selected bSelected := TProfilePanel(Sender).Selected; btnOk.Enabled := bSelected; if bSelected then self.FocusControl(btnOk) else self.FocusControl(btnCancel); end; procedure TProfileForm.DeleteClicked(Sender: TObject); begin MouseOverProfile := TProfilePanel(Sender); DeleteProfileItemClick(nil); end; procedure TProfileForm.NewProfilePanelMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); var mEvnt: TTrackMouseEvent; begin if not FMouseInPanel then begin mEvnt.cbSize := SizeOf(mEvnt); mEvnt.dwFlags := TME_LEAVE; mEvnt.hwndTrack := NewProfilePanel.Handle; TrackMouseEvent(mEvnt); NewProfilePanel.Color:= $f0e8d8; FMouseInPanel:= True; end; end; procedure TProfileForm.PanelWndProc(var Message: TMessage); begin if Message.Msg = WM_MOUSELEAVE then begin NewProfilePanel.Color:= clBtnFace; FMouseInPanel:= False; end; FOldWndProc(Message); end; end. ================================================ FILE: frontend/msProfilePanel.pas ================================================ unit msProfilePanel; interface uses SysUtils, Classes, Controls, Dialogs, Graphics, Buttons, StdCtrls, ExtCtrls, ImgList, Types, // mte components mteHelpers, // mp components msConfiguration, msLoader; type TProfilePanel = class(TPanel) public Selected: boolean; Valid: boolean; constructor ICreate(AOwner: TComponent; GameIcons, GeneralIcons: TImageList; name: string); destructor Destroy; override; procedure ToggleSelect(Sender: TObject); procedure Deselect; procedure Select; procedure SetTop(top: Integer); procedure SetWidth(width: Integer); function GetProfile: TProfile; procedure SetSelectCallback(callback: TNotifyEvent); procedure SetDeleteCallback(callback: TNotifyEvent); procedure SetGame(i: integer); procedure SetPath(path: string); private aProfile: TProfile; ColorInvalid: Integer; ColorValid: Integer; ColorSelected: Integer; GameImage: TImage; lblName: TLabel; lblGame: TLabel; lblPath: TLabel; edName: TEdit; cbGame: TComboBox; edPath: TEdit; btnBrowse: TSpeedButton; btnDelete: TSpeedButton; GameIcons: TImageList; SelectCallback: TNotifyEvent; DeleteCallback: TNotifyEvent; procedure Browse(Sender: TObject); procedure Delete(Sender: TObject); procedure NameChanged(Sender: TObject); procedure GameChanged(Sender: TObject); procedure PathChanged(Sender: TObject); end; implementation {******************************************************************************} { TProfilePanel A GUI component for interacting with a profile. } {******************************************************************************} constructor TProfilePanel.ICreate(AOwner: TComponent; GameIcons: TImageList; GeneralIcons: TImageList; name: string); const GameItems = 'The Elder Scrolls V: Skyrim'#13#10 + 'The Elder Scrolls IV: Oblivion'#13#10 + 'Fallout: New Vegas'#13#10 + 'Fallout 3'#13#10 + 'Fallout 4'#13#10 + 'Skyrim: Special Edition'; begin // set up panel inherited Create(AOwner); Parent := AOwner as TWinControl; Width := (AOwner as TWinControl).ClientWidth; Height := 100; Left := 0; Top := 0; ParentBackground := false; ParentColor := false; ParentDoubleBuffered := false; Cursor := crDefault; Anchors := [akLeft, akTop, akRight]; Visible := true; // set local variables aProfile := TProfile.Create(name); self.GameIcons := GameIcons; Selected := false; ColorInvalid := $d8d8f0; ColorValid := $d8f0d8; ColorSelected := $f0e8d8; // create components GameImage := TImage.Create(self); lblName := TLabel.Create(self); lblGame := TLabel.Create(self); lblPath := TLabel.Create(self); edName := TEdit.Create(self); cbGame := TComboBox.Create(self); edPath := TEdit.Create(self); btnDelete := TSpeedButton.Create(self); btnBrowse := TSpeedButton.Create(self); // set up GameImage GameImage.Parent := self; GameImage.Top := 2; GameImage.Left := 2; GameImage.Height := 96; GameImage.Width := 96; GameImage.Cursor := crDefault; GameImage.Transparent := true; GameImage.Align := alCustom; GameImage.Anchors := [akLeft, akTop, akBottom]; // set up lblName lblName.Parent := self; lblName.Top := 11; lblName.Left := 112; lblName.Caption := 'Name'; lblName.Align := alCustom; lblName.Anchors := [akLeft, akTop]; // set up lblGame lblGame.Parent := self; lblGame.Top := 38; lblGame.Left := 112; lblGame.Caption := 'Game'; lblGame.Align := alCustom; lblGame.Anchors := [akLeft, akTop]; // set up lblPath lblPath.Parent := self; lblPath.Top := 65; lblPath.Left := 112; lblPath.Caption := 'Path'; lblPath.Align := alCustom; lblPath.Anchors := [akLeft, akTop]; // set up edName edName.Parent := self; edName.Top := 8; edName.Left := 177; edName.Width := 227; edName.Text := name; edName.Align := alCustom; edName.Anchors := [akLeft, akTop]; // set up cbGame cbGame.Parent := self; cbGame.Top := 35; cbGame.Left := 177; cbGame.Width := 227; cbGame.Style := csDropDownList; cbGame.Items.Text := GameItems; cbGame.ItemIndex := 0; cbGame.Align := alCustom; cbGame.Anchors := [akLeft, akTop]; // set up edPath edPath.Parent := self; edPath.Top := 62; edPath.Left := 177; edPath.Width := 227; edPath.Align := alCustom; edPath.Anchors := [akLeft, akTop]; // set up btnBrowse btnBrowse.Parent := self; btnBrowse.Top := 61; btnBrowse.Left := 410; btnBrowse.Width := 22; btnBrowse.Height := 23; btnBrowse.Flat := true; btnBrowse.Transparent := true; GeneralIcons.GetBitmap(0, btnBrowse.Glyph); btnBrowse.Align := alCustom; btnBrowse.Anchors := [akLeft, akTop]; // set up btnDelete btnDelete.Parent := self; btnDelete.Top := 4; btnDelete.Left := 410; btnDelete.Width := 22; btnDelete.Height := 23; btnDelete.Flat := true; btnDelete.Transparent := true; GeneralIcons.GetBitmap(1, btnDelete.Glyph); btnDelete.Align := alCustom; btnDelete.Anchors := [akLeft, akTop]; // set event handlers self.OnClick := ToggleSelect; GameImage.OnClick := ToggleSelect; lblName.OnClick := ToggleSelect; lblGame.OnClick := ToggleSelect; lblPath.OnClick := ToggleSelect; btnBrowse.OnClick := Browse; btnDelete.OnClick := Delete; edName.OnChange := NameChanged; edPath.OnChange := PathChanged; cbGame.OnChange := GameChanged; // call initial events GameChanged(nil); PathChanged(nil); end; destructor TProfilePanel.Destroy; begin aProfile.Free; GameImage.Free; lblName.Free; lblGame.Free; lblPath.Free; edName.Free; cbGame.Free; edPath.Free; btnDelete.Free; btnBrowse.Free; inherited; end; { EVENT HANDLING } procedure TProfilePanel.ToggleSelect(Sender: TObject); begin if Cursor = crHandPoint then begin if Selected then Deselect else Select; if Assigned(SelectCallback) then SelectCallback(self); end; end; procedure TProfilePanel.Select; begin Selected := true; Color := ColorSelected; Repaint; end; procedure TProfilePanel.Deselect; begin Selected := false; Color := ColorValid; Repaint; end; procedure TProfilePanel.Browse(Sender: TObject); begin // have user browse for folder BrowseForFolder(edPath, ''); // then update in profile aProfile.gamePath := edPath.Text; end; procedure TProfilePanel.Delete(Sender: TObject); begin if Assigned(DeleteCallback) then DeleteCallback(self); end; procedure TProfilePanel.NameChanged(Sender: TObject); begin if FileNameValid(edName.Text) and (not DirectoryExists(PathList.Values['ProgramPath'] + 'profiles\' + edName.Text)) then aProfile.Rename(edName.Text); end; procedure TProfilePanel.GameChanged(Sender: TObject); begin // set in profile aProfile.gamemode := cbGame.ItemIndex + 1; // clear the GameImage, then set it to the image of the // game the user selected GameImage.Canvas.Brush.Color := clBlack; GameImage.Canvas.Rectangle(0, 0, 96, 96); GameIcons.GetBitmap(cbGame.ItemIndex, GameImage.Picture.Bitmap); GameImage.Repaint; end; procedure TProfilePanel.PathChanged(Sender: TObject); begin // set in profile aProfile.gamePath := AppendIfMissing(edPath.Text, '\'); // reflect validity in the GUI if GamePathValid(aProfile.gamePath, aProfile.gameMode) then begin Valid := true; Cursor := crHandPoint; GameImage.Cursor := crHandPoint; Color := ColorValid; end else begin Valid := false; Cursor := crDefault; GameImage.Cursor := crDefault; Color := ColorInvalid; end; // repaint to update GUI Repaint; end; procedure TProfilePanel.SetTop(top: Integer); begin self.top := top; end; procedure TProfilePanel.SetWidth(width: Integer); begin self.width := width; end; function TProfilePanel.GetProfile: TProfile; begin Result := aProfile; end; procedure TProfilePanel.SetSelectCallback(callback: TNotifyEvent); begin SelectCallback := callback; end; procedure TProfilePanel.SetDeleteCallback(callback: TNotifyEvent); begin DeleteCallback := callback; end; procedure TProfilePanel.SetGame(i: Integer); begin cbGame.ItemIndex := i - 1; GameChanged(nil); end; procedure TProfilePanel.SetPath(path: string); begin edPath.Text := path; PathChanged(nil); end; end. ================================================ FILE: frontend/msSettingsManager.dfm ================================================ object SettingsManager: TSettingsManager Left = 0 Top = 0 Caption = 'Settings Manager' ClientHeight = 582 ClientWidth = 1024 Color = clBtnFace Constraints.MinHeight = 520 Constraints.MinWidth = 960 DoubleBuffered = True Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'Tahoma' Font.Style = [] KeyPreview = True OldCreateOrder = False Position = poScreenCenter OnCreate = FormCreate OnDestroy = FormDestroy OnKeyDown = FormKeyDown OnShow = FormShow PixelsPerInch = 96 TextHeight = 13 object Splitter: TSplitter Left = 650 Top = 0 Height = 582 Beveled = True Color = clSilver ParentColor = False OnMoved = SplitterMoved ExplicitLeft = 857 ExplicitHeight = 682 end object pnlEntries: TPanel Left = 0 Top = 0 Width = 650 Height = 582 Align = alLeft Caption = 'pnlEntries' Constraints.MinWidth = 650 TabOrder = 0 object lvSettings: TListView Left = 2 Top = 1 Width = 642 Height = 573 Align = alCustom Anchors = [akLeft, akTop, akRight, akBottom] Columns = < item Caption = 'Name' Width = 238 end item AutoSize = True Caption = 'Records' end> DoubleBuffered = True MultiSelect = True OwnerDraw = True GroupView = True ReadOnly = True RowSelect = True ParentDoubleBuffered = False PopupMenu = SettingsPopupMenu SortType = stData TabOrder = 0 TabStop = False ViewStyle = vsReport OnChange = lvSettingsChange OnClick = lvSettingsClick OnDrawItem = lvSettingsDrawItem end end object pnlDetails: TPanel Left = 653 Top = 0 Width = 371 Height = 582 Hint = 'The search clears any previous selections, be aware of that!' Align = alClient Constraints.MinWidth = 300 ParentShowHint = False ShowHint = True TabOrder = 1 object lblName: TLabel Left = 8 Top = 12 Width = 27 Height = 13 Margins.Left = 8 Margins.Top = 8 Align = alCustom Caption = 'Name' end object lblDescription: TLabel Left = 8 Top = 93 Width = 53 Height = 13 Margins.Left = 8 Margins.Top = 8 Align = alCustom Caption = 'Description' end object lblTree: TLabel Left = 8 Top = 234 Width = 22 Height = 13 Margins.Left = 8 Align = alCustom Caption = 'Tree' end object lblColor: TLabel Left = 8 Top = 39 Width = 25 Height = 13 Margins.Left = 8 Margins.Top = 8 Align = alCustom Caption = 'Color' end object lblHash: TLabel Left = 8 Top = 63 Width = 24 Height = 13 Margins.Left = 8 Margins.Top = 8 Align = alCustom Caption = 'Hash' end object tvRecords: TTreeView Left = 8 Top = 261 Width = 354 Height = 282 Margins.Left = 8 Align = alCustom Anchors = [akLeft, akTop, akRight, akBottom] DoubleBuffered = True Enabled = False Indent = 19 MultiSelect = True MultiSelectStyle = [msControlSelect, msShiftSelect, msVisibleOnly] ParentDoubleBuffered = False ParentShowHint = False PopupMenu = TreePopupMenu ReadOnly = True ShowHint = True StateImages = StateImages TabOrder = 0 OnCollapsing = tvRecordsCollapsing OnCustomDrawItem = tvRecordsCustomDrawItem OnKeyDown = tvRecordsKeyDown OnKeyPress = tvRecordsKeyPress OnMouseDown = tvRecordsMouseDown OnMouseMove = tvRecordsMouseMove end object edName: TEdit Left = 152 Top = 9 Width = 210 Height = 21 Margins.Left = 8 Margins.Right = 8 Align = alCustom Anchors = [akLeft, akTop, akRight] Enabled = False TabOrder = 1 OnChange = edNameChange end object meDescription: TMemo Left = 8 Top = 112 Width = 354 Height = 100 Margins.Left = 8 Margins.Right = 8 Align = alCustom Anchors = [akLeft, akTop, akRight] Enabled = False TabOrder = 2 end object btnSave: TButton Left = 207 Top = 549 Width = 75 Height = 25 Align = alCustom Anchors = [akRight, akBottom] Caption = 'Save' Enabled = False TabOrder = 3 OnClick = btnSaveClick end object btnDiscard: TButton Left = 288 Top = 549 Width = 75 Height = 25 Align = alCustom Anchors = [akRight, akBottom] Caption = 'Discard' Enabled = False TabOrder = 4 OnClick = btnDiscardClick end object cbColor: TColorBox Left = 152 Top = 36 Width = 210 Height = 22 Margins.Right = 8 Align = alCustom Anchors = [akLeft, akTop, akRight, akBottom] Enabled = False TabOrder = 5 end object edHash: TEdit Left = 152 Top = 63 Width = 210 Height = 21 Margins.Left = 8 Margins.Right = 8 Align = alCustom Anchors = [akLeft, akTop, akRight] Enabled = False ReadOnly = True TabOrder = 6 Text = '$00000000' OnChange = edNameChange end object edSearch: TEdit Left = 152 Top = 234 Width = 209 Height = 21 Align = alCustom Anchors = [akLeft, akTop, akRight] TabOrder = 7 Text = 'Search...' OnClick = edSearchClick OnKeyPress = edSearchKeyPress end end object SettingsPopupMenu: TPopupMenu OnPopup = SettingsPopupMenuPopup Left = 56 Top = 40 object NewSettingItem: TMenuItem Caption = 'New setting' OnClick = NewSettingItemClick end object DeleteSettingItem: TMenuItem Caption = 'Delete setting' OnClick = DeleteSettingItemClick end object CloneSettingItem: TMenuItem Caption = 'Clone setting' OnClick = CloneSettingItemClick end object CombineSettingsItem: TMenuItem Caption = 'Combine settings' OnClick = CombineSettingsItemClick end end object TreePopupMenu: TPopupMenu OnPopup = TreePopupMenuPopup Left = 672 Top = 504 object BuildItem: TMenuItem Caption = 'Build' object AddItem: TMenuItem Caption = 'Add' end object AddAllRecordsItem: TMenuItem Caption = 'Add all records' OnClick = AddAllRecordsItemClick end object BuildFromPluginsItem: TMenuItem Caption = 'Build from plugins' OnClick = BuildFromPluginsItemClick end end object AutosetItem: TMenuItem Caption = 'Autoset attributes' OnClick = AutosetItemClick end object SelectSimilarNodesItem: TMenuItem Caption = 'Select similar nodes' OnClick = SelectSimilarNodesItemClick end object ToggleItem: TMenuItem Caption = 'Toggle' object ToggleNodesItem: TMenuItem Caption = 'Toggle nodes' OnClick = ToggleNodesItemClick end object PreserveDeletionsItem: TMenuItem Caption = 'Toggle preserve deletions' OnClick = PreserveDeletionsItemClick end object OverrideDeletionsItem: TMenuItem Caption = 'Toggle override deletions' OnClick = OverrideDeletionsItemClick end object SingleEntityItem: TMenuItem Caption = 'Toggle treat as single entity' OnClick = SingleEntityItemClick end object ForceValueItem: TMenuItem Caption = 'Toggle force values' OnClick = ForceValueItemClick end end object LinkItem: TMenuItem Caption = 'Link' object ChainNodesItem: TMenuItem Caption = 'Chain nodes' OnClick = ChainNodesItemClick end object LinkNodeToItem: TMenuItem Caption = 'Link node to' end object UnlinkNodeItem: TMenuItem Caption = 'Unlink nodes' OnClick = UnlinkNodeItemClick end end object PruneItem: TMenuItem Caption = 'Prune' object AutoPruneItem: TMenuItem Caption = 'Auto-prune nodes' OnClick = AutoPruneItemClick end object PruneNodesItem: TMenuItem Caption = 'Prune nodes' OnClick = PruneNodesItemClick end end end object StateImages: TImageList Height = 17 Width = 17 Left = 752 Top = 504 Bitmap = { 494C010104000800000111001100FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600 0000000000003600000028000000440000002200000001002000000000002024 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F 8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F 8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F 8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F 8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F 8EFF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFF8F8F8EFF8F8F 8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F 8EFF8F8F8EFF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4 F4FFF4F4F4FFF4F4F4FFF5F5F5FFF9F9F9FFF8F8F8FFF5F5F5FFF4F4F4FFF4F4 F4FFF4F4F4FFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F 8EFFF4F4F4FFF4F4F4FFF4F4F4FFF5F5F5FFF9F9F9FFF8F8F8FFF5F5F5FFF4F4 F4FFF4F4F4FFF4F4F4FFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFF8F8F8EFFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4 F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFF8F8F8EFFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4 F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FF8F8F8EFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FFCCCBCAFFDBDADAFFE9E2DFFFBA99 8CFFBD9D90FFF6F3F2FFEDEDECFFECEBEBFFEAE9E9FFF4F4F4FF8F8F8EFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FFCCCBCAFFDBDADAFFE9E2 DFFFBA998CFFBD9D90FFF6F3F2FFEDEDECFFECEBEBFFEAE9E9FFF4F4F4FF8F8F 8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FFCCCBCAFFD5D4 D4FFDCDBDBFFE1E1E0FFE7E7E6FFEBEBEAFFECECEBFFECEBEBFFEAE9E9FFF4F4 F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FF714E 21FF6A491FFF61441DFF593E1AFF553B19FF553B19FF553A19FF553A19FF553B 19FFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4 F4FFCAC8C6FFF0ECEAFFBB998BFF975F4AFF98614CFFD1B9B0FFF9F9F9FFF6F6 F6FFE6E6E6FFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F 8EFFF4F4F4FFCAC8C6FFF0ECEAFFBB998BFF975F4AFF98614CFFD1B9B0FFF9F9 F9FFF6F6F6FFE6E6E6FFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFF8F8F8EFFF4F4F4FFC6C4C2FFE9E9E9FFEDEDEDFFF0F0F0FFF4F4F4FFF6F6 F6FFF6F6F6FFF6F6F6FFE6E6E6FFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFF8F8F8EFFF4F4F4FF755123FFB89255FFAE864CFFA47A44FF996E 3BFF936532FF8F5F2CFF8C5925FF553B19FFF4F4F4FF8F8F8EFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FFD1CFCDFFE9E1DEFF955D48FF965F 49FF97604BFFA47361FFFAF9F8FFF4F4F4FFE2E2E1FFF4F4F4FF8F8F8EFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FFD1CFCDFFE9E1DEFF955D 48FF965F49FF97604BFFA47361FFFAF9F8FFF4F4F4FFE2E2E1FFF4F4F4FF8F8F 8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FFC2BFBCFFE5E4 E3FFE9E9E9FFEDEDEDFFF2F2F2FFF4F4F4FFF5F5F5FFF4F4F4FFE2E2E1FFF4F4 F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FF7B55 24FFC29D5DFFB38927FFAA8124FFA07822FF966F1FFF8F691EFF8F602CFF553B 19FFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4 F4FFE1E0DEFFAA7F6EFF945C47FFE2D4CFFFA77867FF97604BFFD5BFB7FFF6F6 F6FFDEDDDCFFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F 8EFFF4F4F4FFE1E0DEFFAA7F6EFF945C47FFE2D4CFFFA77867FF97604BFFD5BF B7FFF6F6F6FFDEDDDCFFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFF8F8F8EFFF4F4F4FFBFBBB8FFE1DFDDFFE5E5E4FFEAEAEAFFEFEFEFFFF2F2 F2FFF2F2F2FFF2F2F2FFDEDDDCFFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFF8F8F8EFFF4F4F4FF815A26FFCBA966FFBF942AFFB88E28FFB087 26FFA77F24FF9F7722FF9A6B34FF5C401BFFF4F4F4FF8F8F8EFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FFCDC9C5FFDDCFC9FFC8AEA3FFEEEE EDFFD5C1BAFF965E49FFA57664FFF8F8F8FFD6D5D5FFF4F4F4FF8F8F8EFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FFCDC9C5FFDDCFC9FFC8AE A3FFEEEEEDFFD5C1BAFF965E49FFA57664FFF8F8F8FFD6D5D5FFF4F4F4FF8F8F 8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FFBCB7B2FFDCD8 D5FFDFDCDAFFE3E1E0FFE8E8E8FFECECECFFEDEDEDFFEDEDEDFFD6D5D4FFF4F4 F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FF855D 27FFD4B36DFFC99E2CFFC4992BFFBE932AFFB78D28FFAE8525FFA6793EFF6546 1EFFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4 F4FFB9B3AEFFDDD9D5FFE5E2DFFFDCD8D5FFF4F3F2FFA1715EFF945C47FFD6C3 BCFFDCDCDBFFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F 8EFFF4F4F4FFB9B3AEFFDDD9D5FFE5E2DFFFDCD8D5FFF4F3F2FFA1715EFF945C 47FFD6C3BCFFDCDCDBFFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFF8F8F8EFFF4F4F4FFB9B3AEFFD7D1CDFFD9D4D0FFDBD7D4FFDFDDDBFFE3E2 E1FFE6E6E5FFE8E8E8FFCDCDCCFFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFF8F8F8EFFF4F4F4FF895F28FFDABB74FFD1A42EFFCEA22DFFC99D 2CFFC2972BFFBB9129FFB18647FF6E4C20FFF4F4F4FF8F8F8EFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FFB9B3AEFFD5CFCBFFD5CFCBFFD6D1 CDFFE6E2E0FFCFB8AFFF925A45FFA57765FFE8E7E7FFF4F4F4FF8F8F8EFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FFB9B3AEFFD5CFCBFFD5CF CBFFD6D1CDFFE6E2E0FFCFB8AFFF925A45FFA57765FFE8E7E7FFF4F4F4FF8F8F 8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FFB9B3AEFFD5CF CBFFD5CFCBFFD6D1CDFFDAD5D2FFDEDBD8FFE1DFDDFFE4E3E2FFC8C7C6FFF4F4 F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FF8B61 29FFE0C27BFFD5A82FFFD3A62FFFD0A42EFFCB9F2DFFC5992BFFBB9250FF7652 23FFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4 F4FFB9B3AEFFD5CFCBFFD5CFCBFFD5CFCBFFD6D0CCFFF1EEEDFF9D6A57FF925A 44FFD0BFB9FFF6F6F6FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F 8EFFF4F4F4FFB9B3AEFFD5CFCBFFD5CFCBFFD5CFCBFFD6D0CCFFF1EEEDFF9D6A 57FF925A44FFD0BFB9FFF6F6F6FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFF8F8F8EFFF4F4F4FFB9B3AEFFD5CFCBFFD5CFCBFFD5CFCBFFD5CFCBFFD8D3 D0FFDCD8D5FFDFDDDBFFC5C3C1FFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFF8F8F8EFFF4F4F4FF8D6229FFE4C87FFFE1C37BFFDDBE75FFD9B7 6EFFD3AF68FFCCA760FFC49D59FF7C5624FFF4F4F4FF8F8F8EFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FFB9B3AEFFB9B3AEFFB9B3AEFFB9B3 AEFFB9B3AEFFD0CCC9FFC0A79DFFAB8677FFE4DFDCFFF5F5F5FF8F8F8EFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FFB9B3AEFFB9B3AEFFB9B3 AEFFB9B3AEFFB9B3AEFFD0CCC9FFC0A79DFFAB8677FFE4DFDCFFF5F5F5FF8F8F 8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FFB9B3AEFFB9B3 AEFFB9B3AEFFB9B3AEFFB9B3AEFFB9B3AEFFBAB4AFFFBDB9B4FFC1BEBBFFF4F4 F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4F4FF8D62 29FF8E622AFF8E622AFF8D622AFF8C6129FF8A6028FF875E28FF845B27FF8059 26FFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFFF4F4 F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF8F8F8FFF9F9 F9FFF6F6F6FFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F 8EFFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF8F8 F8FFF9F9F9FFF6F6F6FFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFF8F8F8EFFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4 F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FF8F8F8EFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFF8F8F8EFFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4 F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FF8F8F8EFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F 8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F 8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F 8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F 8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F 8EFF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF8F8F8EFF8F8F8EFF8F8F 8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F8EFF8F8F 8EFF8F8F8EFF8F8F8EFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF424D3E000000000000003E000000 2800000044000000220000000100010000000000980100000000000000000000 000000000000000000000000FFFFFF0000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000} end object FlagIcons: TImageList Left = 824 Top = 504 Bitmap = { 494C0101050008004C0110001000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600 0000000000003600000028000000400000002000000001002000000000000020 00000000000000000000000000000000000000000000D1D1D12E4F4F4FB01B1B 1BE42B2B2BD48282827DF7F7F708000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000D1D1D12E0C0C0CF3000000FF0000 00FF000000FF000000FF3B3B3BC4F2F2F20D0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000004E4E4EB1000000FF4D4D4DB2D7D7 D728B2B2B24D1A1A1AE5000000FF3A3A3AC5F2F2F20D00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000001B1B1BE4000000FFD7D7D7280000 000000000000D9D9D9261B1B1BE4000000FF3A3A3AC5F2F2F20D000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000002B2B2BD4000000FFB3B3B34C0000 00000000000000000000D9D9D926BABABA45EFEFEF10F3F3F30C000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000008383837C000000FF1A1A1AE5D9D9 D9260000000000000000C3C3C33C424242BD131313EC262626D97F7F7F80F7F7 F708000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000F7F7F7083B3B3BC4000000FF1B1B 1BE4D9D9D926E3E3E31C060606F9000000FF000000FF000000FF000000FF3B3B 3BC4F2F2F20D0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000F2F2F20D3A3A3AC50000 00FF1B1B1BE4CECECE31444444BB7171718EE1E1E11EB7B7B7481A1A1AE50000 00FF3A3A3AC5F2F2F20D00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000F2F2F20D3A3A 3AC5000000FF1A1A1AE5B8B8B847E1E1E11E7171718E444444BBCECECE311B1B 1BE4000000FF3A3A3AC5F2F2F20D000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000F2F2 F20D3B3B3BC4000000FF000000FF000000FF000000FF060606F9E3E3E31CD9D9 D9261B1B1BE4000000FF3B3B3BC4F7F7F7080000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F7F7F7087F7F7F80262626D9131313EC424242BDC3C3C33C000000000000 0000D9D9D9261A1A1AE5000000FF8383837C0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000F3F3F30CEFEFEF10BABABA45D9D9D926000000000000 000000000000B3B3B34C000000FF2C2C2CD30000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000F2F2F20D3A3A3AC5000000FF1B1B1BE4D9D9D9260000 000000000000D7D7D728000000FF1B1B1BE40000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000F2F2F20D3A3A3AC5000000FF1A1A1AE5B3B3 B34CD7D7D7284E4E4EB1000000FF4F4F4FB00000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000F2F2F20D3B3B3BC4000000FF0000 00FF000000FF000000FF0C0C0CF3D2D2D22D0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000F7F7F7088282827D2B2B 2BD41C1C1CE34F4F4FB0D2D2D22D000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D7D7F8FF7373E6FF3434DBFF2121BEFF2121BEFF2D2DDAFF6B6BE4FFD2D2 F7FF000000000000000000000000000000000000000000000000000000000000 0000A0AE9D666A9161AA31881DFF31881DFF31881DFF31881DFF6A9161AAA0AE 9D66000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000E4F1E779D7D6B8CCD4BF91F3D2B683FED2B581FED1BD8FF3D5D3B5CCE3F0 E679000000000000000000000000000000000000000000000000F8F8FDFF7373 E6FF2020B5FF2020B5FF3434DBFF5B5BE2FF5B5BE2FF3D3DDCFF2020B5FF2020 B5FF6464E3FFF8F8FDFF00000000000000000000000000000000EEEEEE115189 45CC31881DFF31881DFF31881DFF31881DFF31881DFF31881DFF31881DFF3188 1DFF518945CCEEEEEE110000000000000000000000000000000000000000232D 3A00232D3A00232D3A0000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000F2F8F33CD9D8 BACBDCAB6CFEE1974BFFE18F3DFFE18A37FFDF8835FFDD8A39FFD99044FFD4A3 64FED4D4B6CBF1F7F23C000000000000000000000000F8F8FDFF4242DDFF2020 B5FF5353E0FFD7D7F8FF00000000000000000000000000000000E2E2F9FF5B5B E2FF2020B5FF3D3DDCFFEFEFFCFF0000000000000000EEEEEE113B8629EE3188 1DFF31881DFF31881DFF31881DFF31881DFF31881DFF31881DFF31881DFF3188 1DFF31881DFF3B8629EEEEEEEE1100000000000000000000000000000000232D 3A00232D3A00232D3A0000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000F2F8F33CDBCDA5DEE3A1 58FFE69240FFE58F3AFFE48D39FFE28B37FFE08A36FFDF8834FFDD8733FFDB87 35FFD7944CFFD3C49DDEF1F7F23C00000000000000007373E6FF2020B5FF8282 E9FF000000000000000000000000FEFEFE03FDFDFE0700000000000000000000 00009292EBFF2020B5FF6464E3FF0000000000000000518945CC31881DFF3188 1DFF31881DFF31881DFF31881DFF31881DFF31881DFF31881DFF31881DFF3188 1DFF31881DFF31881DFF518945CC00000000000000000000000000000000232D 3A00232D3A00232D3A0000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000DBDABCCBE6A35AFFE994 41FFE8923EFFE7903CFFE58E3AFFE38D38FFE28B37FFE08935FFDF8834FFDD86 32FFDC8633FFD6944BFFD4D3B5CB00000000D7D7F8FF2020B5FF5353E0FF0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000006464E3FF2020B5FFC8C8F5FFA0AE9D6631881DFF31881DFF3188 1DFF31881DFF31881DFF31881DFFFFFFFFFFFFFFFFFF31881DFF31881DFF3188 1DFF31881DFF31881DFF31881DFFA0AE9D66000000000000000000000000232D 3A00232D3A00232D3A0000000000000000000000000000000000000000000000 000000000000000000000000000000000000E6F3E879E3B273FEEC9846FFEB95 41FFEA933FFFE8913DFFEAA560FFF9F7F5FFF8F0E8FFE18B37FFE08935FFDE88 33FFDD8632FFDA8735FFD3A263FEE3F0E6797A7AE7FF2020B5FFD2D2F7FF0000 00000000000000000000FEFEFE0D0000000000000000F4F4FC28000000000000 000000000000E2E2F9FF2020B5FF6B6BE4FF5D8C52BB31881DFF31881DFF3188 1DFF31881DFF31881DFF31881DFFFFFFFFFFFFFFFFFF31881DFF31881DFF3188 1DFF31881DFF31881DFF31881DFF5D8C52BB000000000000000000000000232D 3A00232D3A00232D3A0000000000000000000000000000000000000000000000 000000000000000000000000000000000000DDDBBDCCEBA256FFEE9844FFED96 42FFEB9440FFE9933FFFEBA562FFF9F7F5FFF8F0E8FFE38C38FFE18A36FFE089 35FFDE8733FFDD8632FFD88F43FFD4D3B5CC3434DBFF3434DBFF000000000000 0000B9B9F2FFB9B9F2FFB9B9F2FFB9B9F2FFB9B9F2FFB9B9F2FFB9B9F2FFB9B9 F2FFEFEFFCFF000000004242DDFF2525D6FF31881DFF31881DFF31881DFF3188 1DFF31881DFF31881DFF31881DFFFFFFFFFFFFFFFFFF31881DFF31881DFF3188 1DFF31881DFF31881DFF31881DFF31881DFF000000000000000000000000232D 3A00232D3A00232D3A0000000000000000000000000000000000000000000000 000000000000000000000000000000000000DDC89AF3F09D4BFFF09945FFEE97 43FFED9642FFEB9440FFECA663FFF9F7F5FFF8F0E9FFE48D39FFE28C38FFE18A 36FFDF8934FFDE8733FFDB8937FFD1BC8DF32323C6FF5353E0FF000000000000 00002121BEFF2020B5FF2020B5FF2020B5FF2020B5FF2020B5FF2020B5FF2020 B5FFC8C8F5FF000000006464E3FF2121BEFF31881DFF31881DFF31881DFF3188 1DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFF31881DFF31881DFF31881DFF31881DFF000000000000000000000000232D 3A00232D3A00232D3A00232D3A00232D3A00232D3A00232D3A00232D3A000000 000000000000000000000000000000000000DFC38FFEF39C49FFF19A46FFEF99 44FFEE9743FFEC9541FFEEA864FFF9F7F5FFF8F0E9FFE68F3BFFE48D39FFE28B 37FFE18A36FFDF8834FFDD8734FFD0B480FE2323C6FF5353E0FF000000000000 00002020B5FF2020B5FF2020B5FF2020B5FF2020B5FF2020B5FF2020B5FF2020 B5FFC8C8F5FF000000006464E3FF2121BEFF31881DFF31881DFF31881DFF3188 1DFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF FFFF31881DFF31881DFF31881DFF31881DFF000000000000000000000000232D 3A00232D3A00232D3A00232D3A00232D3A00232D3A00232D3A00232D3A000000 000000000000000000000000000000000000E0C390FEF49D4AFFF29B47FFF19A 46FFEF9844FFEE9743FFEFA965FFF9F7F5FFF8F0E9FFE7903CFFE58E3AFFE48D 39FFE28B37FFE08A35FFDF8835FFD1B581FE3D3DDCFF2D2DDAFF000000000000 0000F8F8FDFFF8F8FDFFEFEFFCFFEFEFFCFFEFEFFCFFEFEFFCFFEFEFFCFFF8F8 FDFFF8F8FDFF000000003D3DDCFF2525D6FF31881DFF31881DFF31881DFF3188 1DFF31881DFF31881DFF31881DFFFFFFFFFFFFFFFFFF31881DFF31881DFF3188 1DFF31881DFF31881DFF31881DFF31881DFF000000000000000000000000232D 3A00232D3A00232D3A0000000000000000000000000000000000000000000000 000000000000000000000000000000000000DFCA9CF3F3A14FFFF39D48FFF29B 47FFF09A45FFEF9844FFF0B172FFF9F7F5FFF8F0E9FFE8913DFFE7903CFFE58E 3AFFE38C38FFE28B37FFDF8C3BFFD2BE90F37373E6FF2020B5FFD2D2F7FF0000 0000000000000000000000000000F1F1FA0FFAFAFD05F1F1FC32000000000000 000000000000E2E2F9FF2020B5FF6B6BE4FF5D8C52BB31881DFF31881DFF3188 1DFF31881DFF31881DFF31881DFFFFFFFFFFFFFFFFFF31881DFF31881DFF3188 1DFF31881DFF31881DFF31881DFF5D8C52BB000000000000000000000000232D 3A00232D3A00232D3A0000000000000000000000000000000000000000000000 000000000000000000000000000000000000DFDDBFCCF1A85BFFF49E4AFFF39C 48FFF29B47FFF5CBA3FFF9F7F5FFF9F7F5FFF8F0E9FFEA933FFFE8913DFFE68F 3BFFE58E3AFFE38C38FFDE9548FFD7D5B7CCD7D7F8FF2020B5FF5353E0FF0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000006464E3FF2020B5FFC8C8F5FFA0AE9D6631881DFF31881DFF3188 1DFF31881DFF31881DFF31881DFFFFFFFFFFFFFFFFFF31881DFF31881DFF3188 1DFF31881DFF31881DFF31881DFFA0AE9D66000000000000000000000000232D 3A00232D3A00232D3A0000000000000000000000000000000000000000000000 000000000000000000000000000000000000E7F3E979E9B879FEF4A14FFFF49D 49FFF39C48FFF19B46FFF19F51FFF6DEC6FFF8F1E9FFEB9440FFE9933EFFE891 3DFFE68F3BFFE3903DFFDAA96AFEE4F1E779000000007A7AE7FF2020B5FF8282 E9FF000000000000000000000000000000000000000000000000000000000000 00008B8BEAFF2020B5FF6464E3FF0000000000000000518945CC31881DFF3188 1DFF31881DFF31881DFF31881DFF31881DFF31881DFF31881DFF31881DFF3188 1DFF31881DFF31881DFF518945CC00000000000000000000000000000000232D 3A00232D3A00232D3A00232D3A00232D3A00232D3A00232D3A00232D3A00232D 3A000000000000000000000000000000000000000000DFDEC0CBEFAD64FFF4A0 4CFFF49D49FFF39C48FFF19A46FFF09945FFEE9743FFEC9641FFEB9440FFE992 3EFFE7913EFFE19E55FFD8D7B9CB0000000000000000F8F8FDFF4242DDFF2020 B5FF5353E0FFD7D7F8FF00000000000000000000000000000000D7D7F8FF5B5B E2FF2020B5FF4242DDFFEFEFFCFF0000000000000000EEEEEE113B8629EE3188 1DFF31881DFF31881DFF31881DFF31881DFF31881DFF31881DFF31881DFF3188 1DFF31881DFF3B8629EEEEEEEE1100000000000000000000000000000000232D 3A00232D3A00232D3A00232D3A00232D3A00232D3A00232D3A00232D3A00232D 3A000000000000000000000000000000000000000000F3F9F43CE1D2ABDEEFAD 63FFF4A04EFFF49D49FFF29B47FFF19A46FFEF9944FFEE9743FFEC9541FFE996 43FFE3A158FFD9CAA3DEF2F8F33C000000000000000000000000F8F8FDFF7373 E6FF2020B5FF2020B5FF3434DBFF6464E3FF5B5BE2FF3D3DDCFF2020B5FF2020 B5FF6B6BE4FFEFEFFCFF00000000000000000000000000000000EEEEEE115189 45CC31881DFF31881DFF31881DFF31881DFF31881DFF31881DFF31881DFF3188 1DFF518945CCEEEEEE1100000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000F3F9F43CDFDD C0CBE8B778FEF0A75AFFF2A04EFFF29B48FFF19A47FFEE9B49FFE9A053FFE0B0 71FEDAD9BCCBF2F8F33C00000000000000000000000000000000000000000000 0000D7D7F8FF7373E6FF2D2DDAFF2121BEFF2121BEFF2D2DDAFF6B6BE4FFD2D2 F7FF000000000000000000000000000000000000000000000000000000000000 0000A0AE9D666A9161AA31881DFF31881DFF31881DFF31881DFF6A9161AAA0AE 9D66000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000E6F3E979DFDCBFCCDEC99BF3DFC28EFEDEC18EFEDCC799F3DCDABCCCE5F2 E87900000000000000000000000000000000424D3E000000000000003E000000 2800000040000000200000000100010000000000000100000000000000000000 000000000000000000000000FFFFFF0081FF00000000000000FF000000000000 007F000000000000183F0000000000001C3F0000000000000C0F000000000000 00070000000000008003000000000000C001000000000000E000000000000000 F030000000000000FC38000000000000FC18000000000000FE00000000000000 FF00000000000000FF81000000000000F00FF00FFFFFF00FC003C003E3FFC003 83C18001E3FF80018E718001E3FF80011FF80000E3FF00001DB80000E3FF0000 30040000E3FF000030040000E01F000030040000E01F000030040000E3FF0000 1E380000E3FF00001FF80000E3FF00008FF18001E00F800183C18001E00F8001 C003C003FFFFC003F00FF00FFFFFF00F00000000000000000000000000000000 000000000000} end end ================================================ FILE: frontend/msSettingsManager.pas ================================================ unit msSettingsManager; interface uses Windows, Types, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, ComCtrls, Grids, ValEdit, CommCtrl, Menus, ImgList, StrUtils, // superobject superobject, // mte units mteHelpers, mteLogger, mteProgressForm, mteBase, RttiTranslation, // ms units msCore, msConfiguration, msPluginSelectionForm, msConflictForm, msThreads; type TSettingsManager = class(TForm) [FormPrefix('msSet')] Splitter: TSplitter; [FormSection('Settings')] pnlEntries: TPanel; lvSettings: TListView; [FormSection('Settings Popup Menu')] SettingsPopupMenu: TPopupMenu; NewSettingItem: TMenuItem; DeleteSettingItem: TMenuItem; CloneSettingItem: TMenuItem; CombineSettingsItem: TMenuItem; [FormSection('Details')] pnlDetails: TPanel; lblName: TLabel; edName: TEdit; lblColor: TLabel; cbColor: TColorBox; lblHash: TLabel; edHash: TEdit; lblDescription: TLabel; meDescription: TMemo; btnSave: TButton; btnDiscard: TButton; [FormSection('Tree')] lblTree: TLabel; edSearch: TEdit; tvRecords: TTreeView; StateImages: TImageList; FlagIcons: TImageList; [FormSection('TreePopupMenu')] TreePopupMenu: TPopupMenu; LinkItem: TMenuItem; PruneItem: TMenuItem; BuildItem: TMenuItem; ToggleItem: TMenuItem; AddItem: TMenuItem; AddAllRecordsItem: TMenuItem; BuildFromPluginsItem: TMenuItem; AutosetItem: TMenuItem; SelectSimilarNodesItem: TMenuItem; ToggleNodesItem: TMenuItem; PreserveDeletionsItem: TMenuItem; OverrideDeletionsItem: TMenuItem; SingleEntityItem: TMenuItem; ForceValueItem: TMenuItem; ChainNodesItem: TMenuItem; LinkNodeToItem: TMenuItem; UnlinkNodeItem: TMenuItem; AutoPruneItem: TMenuItem; PruneNodesItem: TMenuItem; // TREE METHODS procedure DrawFlag(Canvas: TCanvas; var x, y: Integer; id: Integer); procedure tvRecordsCustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean); procedure tvRecordsKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure tvRecordsMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure tvRecordsCollapsing(Sender: TObject; Node: TTreeNode; var AllowCollapse: Boolean); procedure tvRecordsKeyPress(Sender: TObject; var Key: Char); procedure tvRecordsMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure LinkNodeItemClick(Sender: TObject); procedure TreePopupMenuPopup(Sender: TObject); procedure AddItemClick(Sender: TObject); procedure AddAllRecordsItemClick(Sender: TObject); procedure BuildFromPluginsItemClick(Sender: TObject); procedure SelectSimilarNodesItemClick(Sender: TObject); procedure ToggleNodesItemClick(Sender: TObject); procedure PreserveDeletionsItemClick(Sender: TObject); procedure OverrideDeletionsItemClick(Sender: TObject); procedure SingleEntityItemClick(Sender: TObject); procedure ForceValueItemClick(Sender: TObject); procedure PruneNodesItemClick(Sender: TObject); procedure UnlinkNodeItemClick(Sender: TObject); procedure LinkNodes(node1, node2: TTreeNode); procedure ChainNodesItemClick(Sender: TObject); function DumpElement(node: TTreeNode): ISuperObject; procedure DumpTree; procedure DeleteNodes(var aList: TList); procedure DeleteChildren(node: TTreeNode); function CanPruneRecords: boolean; procedure AutoPrune; procedure AutoPruneItemClick(Sender: TObject); procedure Autoset(parentNode: TTreeNode); procedure AutosetItemClick(Sender: TObject); // SETTINGS MANAGER EVENTS function GetGroup(name: string; var group: TListGroup): Boolean; procedure AddSettingItem(aSetting: TSmashSetting; bSelect: Boolean = true); procedure FormCreate(Sender: TObject); procedure FormShow(Sender: TObject); procedure SelectSetting(index: Integer); procedure lvSettingsChange(Sender: TObject; Item: TListItem; Change: TItemChange); procedure lvSettingsDrawItem(Sender: TCustomListView; Item: TListItem; Rect: TRect; State: TOwnerDrawState); procedure SplitterMoved(Sender: TObject); procedure NewSettingItemClick(Sender: TObject); procedure DeleteSettingItemClick(Sender: TObject); procedure CloneSettingItemClick(Sender: TObject); procedure CombineSettingsItemClick(Sender: TObject); procedure SettingsPopupMenuPopup(Sender: TObject); procedure btnSaveClick(Sender: TObject); procedure btnDiscardClick(Sender: TObject); procedure edNameChange(Sender: TObject); procedure edSearchClick(Sender: TObject); procedure edSearchKeyPress(Sender: TObject; var Key: Char); procedure NextSearchResult(); procedure ResetSearch(); procedure FormDestroy(Sender: TObject); procedure lvSettingsClick(Sender: TObject); procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); private { Private declarations } lastHint: string; bSearchActive: Boolean; slSearchResults: TStringList; public { Public declarations } FilterFilename: string; end; const collapseHitTestDelay = 0.1 * seconds; var SettingsManager: TSettingsManager; NewSettings: TList; currentSetting: TSmashSetting; currentSettingItem: TListItem; pForm: TProgressForm; LastCollapseTime: TDateTime; SearchIndex: Integer = -1; implementation {$R *.dfm} procedure TSettingsManager.edSearchClick(Sender: TObject); begin // On search field click set bSearchActive to false if (bSearchActive) and (MessageDlg('Start new search?', mtConfirmation, [mbyes, mbno], 0) = mrYes) then bSearchActive := False; // Empties the search field when clicked and a search is active if not bSearchActive then edSearch.Text := ''; end; procedure TSettingsManager.edSearchKeyPress(Sender: TObject; var Key: Char); var i: Integer; node: TTreeNode; begin // Exit if no records are available if tvRecords.Items.Count = 0 then exit; // Exit function if input is not "Enter" if Key <> #13 then exit; // Tell the user to enter search term if (edSearch.Text = 'Search...') or (edSearch.Text = '') then begin ShowMessage('Please enter a search term!'); exit; end; // Do a search when bSearchActive is false if not bSearchActive then begin // Clear old results slSearchResults.Clear; for i := 0 to Pred(tvRecords.Items.Count) do begin node := tvRecords.Items[i]; // Check if search-string is contained in node-text if ContainsText(node.Text, edSearch.Text) then slSearchResults.AddObject(node.Text,TObject(node)); end; bSearchActive := True; // Show result NextSearchResult; Key := #0; end; end; procedure TSettingsManager.NextSearchResult(); var node: TTreeNode; begin // Notify the user of an unsuccessful search and reset search if slSearchResults.Count = 0 then begin ShowMessage('No results could be found!'); ResetSearch; exit; end; // Exit the function if there is no search active if not bSearchActive then exit; // Increase the SearchIndex Searchindex := Searchindex + 1; // Display the amount of results and the current position in the search field edSearch.Text := ('Result: ' + InttoStr(Searchindex+1) + ' / ' + InttoStr(slSearchResults.Count+1)); // Go back to the beginning if end is reached if Searchindex > Pred(slSearchResults.Count) then begin Searchindex := 0; end; // select the node and set focus node := TTreeNode(slSearchResults.Objects[Searchindex]); tvRecords.SetFocus; node.Selected := true; node.Focused := true; end; procedure TSettingsManager.ResetSearch(); begin bSearchActive := False; edSearch.Text := 'Search...'; end; { Tree methods } procedure TSettingsManager.DrawFlag(Canvas: TCanvas; var x, y: Integer; id: Integer); var icon: TIcon; begin icon := TIcon.Create; FlagIcons.GetIcon(id, icon); Canvas.Draw(x, y, icon); Inc(x, 18); icon.Free; end; procedure TSettingsManager.tvRecordsCollapsing(Sender: TObject; Node: TTreeNode; var AllowCollapse: Boolean); begin LastCollapseTime := Now; end; procedure TSettingsManager.tvRecordsCustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean); var e: TElementData; R: TRect; x, y: Integer; begin if Assigned(node.Data) then begin e := TElementData(node.Data); R := Node.DisplayRect(true); x := R.Right + 6; y := R.Top; // this fixes a bug with drawing flags when expanding a node if x < 20 then exit; // draw flags if e.preserveDeletions then DrawFlag(Sender.Canvas, x, y, 0); if e.overrideDeletions then DrawFlag(Sender.Canvas, x, y, 1); if e.forceValue then DrawFlag(Sender.Canvas, x, y, 2); if e.singleEntity then DrawFlag(Sender.Canvas, x, y, 3); if (e.linkTo <> '') or (e.linkFrom <> '') then DrawFlag(Sender.Canvas, x, y, 4); end; end; procedure TSettingsManager.tvRecordsKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); var i: Integer; begin if (Key = VK_SPACE) then begin for i := 0 to Pred(tvRecords.SelectionCount) do CheckboxManager(tvRecords.Selections[i]); // repaint tree view in case a single entity flag was unset tvRecords.Repaint; end; end; procedure TSettingsManager.tvRecordsKeyPress(Sender: TObject; var Key: Char); begin if Key = #13 then NextSearchResult; Key := #0; if Key = ' ' then Key := #0; end; procedure TSettingsManager.tvRecordsMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var HT: THitTests; node: TTreeNode; begin // this allows right clicking to be used to select nodes if Button = mbRight then begin node := tvRecords.GetNodeAt(X, Y); if Assigned(node) and not node.Selected then begin tvRecords.ClearSelection(false); tvRecords.Select(node); end; end; // this prevents a bug that happens when collapsing a node // would cause the control to scroll up, putting the user's mouse // above a checkbox // the tree view collapse is triggered prior to this mouse down // event, so the hacky solutin I came up with is to use a delay // to exit this event if we collapsed a node within the last 0.1 // seconds if Now - LastCollapseTime < collapseHitTestDelay then exit; HT := tvRecords.GetHitTestInfoAt(X, Y); if (HT - [htOnStateIcon] <> HT) then CheckBoxManager(tvRecords.Selected); // repaint tree view in case a single entity flag was unset tvRecords.Repaint; end; procedure TSettingsManager.tvRecordsMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); var node: TTreeNode; e: TElementData; sHint: string; begin // hide hint and exit if shift is down if (ssShift in Shift) then begin Application.HideHint; exit; end; // draw hint if on a node node := tvRecords.GetNodeAt(X, Y); if not Assigned(node) then exit; e := TElementData(node.Data); if not Assigned(e) then exit; // get hint sHint := node.Text + #13#10'Type: '+stToString(e.smashType); if e.singleEntity then sHint := sHint + #13#10'Treated as a single entity'; if e.forceValue then sHint := sHint + #13#10'Forcing values'; if e.preserveDeletions then sHint := sHint + #13#10'Preserving deletions'; if e.linkTo <> '' then sHint := sHint + #13#10'Linked to: '+e.linkTo; if e.linkFrom <> '' then sHint := sHint + #13#10'Linked from: '+e.linkFrom; // display hint if it isn't the last hint we displayed if sHint <> lastHint then begin tvRecords.Hint := sHint; Application.ActivateHint(Mouse.CursorPos); lastHint := sHint; end; end; function GetSiblingNode(node: TTreeNode; text: string): TTreeNode; var aNode: TTreeNode; begin Result := nil; aNode := node.Parent.getFirstChild; while Assigned(aNode) do begin if aNode.Text = text then begin Result := aNode; exit; end; aNode := aNode.getNextSibling; end; end; procedure UnlinkNode(node: TTreeNode; bTo, bFrom: boolean); var linkedNode: TTreeNode; e, le: TElementData; begin e := TElementData(node.Data); if bTo and (e.linkTo <> '') then begin linkedNode := GetSiblingNode(node, e.linkTo); if Assigned(linkedNode) then begin le := TElementData(linkedNode.Data); le.linkFrom := ''; end; e.linkTo := ''; end; if bFrom and (e.linkFrom <> '') then begin linkedNode := GetSiblingNode(node, e.linkFrom); if Assigned(linkedNode) then begin le := TElementData(linkedNode.Data); le.linkTo := ''; end; e.linkFrom := ''; end; end; procedure TSettingsManager.UnlinkNodeItemClick(Sender: TObject); var i: Integer; node: TTreeNode; begin // unset link element data attribute for each selected node for i := 0 to Pred(tvRecords.SelectionCount) do begin node := tvRecords.Selections[i]; UnlinkNode(node, true, true); end; // update gui tvRecords.Repaint; end; procedure TSettingsManager.LinkNodes(node1, node2: TTreeNode); var e: TElementData; begin // exit if nodes have different level if node1.Level <> node2.Level then exit; // unlink nodes as necessary UnlinkNode(node1, true, false); UnlinkNode(node2, false, true); // link nodes e := TElementData(node1.Data); e.linkTo := node2.Text; e := TElementData(node2.Data); e.linkFrom := node1.Text; end; procedure TSettingsManager.ChainNodesItemClick(Sender: TObject); var i: Integer; prevNode, node: TTreeNode; begin node := tvRecords.Selections[0]; for i := 1 to Pred(tvRecords.SelectionCount) do begin prevNode := node; node := tvRecords.Selections[i]; LinkNodes(prevNode, node); end; // link last node to first node prevNode := node; node := tvRecords.Selections[0]; LinkNodes(prevNode, node); // repaint tvRecords.Repaint; end; procedure TSettingsManager.LinkNodeItemClick(Sender: TObject); var item: TMenuItem; targetNodeText: string; node, targetNode: TTreeNode; begin // get the target node to link to from the menu item clicked node := tvRecords.Selections[0]; item := TMenuItem(Sender); targetNodeText := StringReplace(item.Caption, '&', '', [rfReplaceAll]); targetNode := GetSiblingNode(node, targetNodeText); if not Assigned(targetNode) then exit; // link the nodes LinkNodes(node, targetNode); // update gui tvRecords.Repaint; end; procedure TSettingsManager.TreePopupMenuPopup(Sender: TObject); var bHasSelection, bTreeSelected, bHasMultiSelection, bSubrecordSelected, bHasChildren, bRecordsSelected, bSomeUnChecked, bIsContainer: boolean; i: Integer; node: TTreeNode; MenuItem: TMenuItem; begin // clear link node submenu LinkNodeToItem.Clear; // get selection booleans bHasSelection := tvRecords.SelectionCount > 0; bTreeSelected := (tvRecords.SelectionCount = 1) and (tvRecords.Selections[0].Level = 0); bHasMultiSelection := tvRecords.SelectionCount > 1; bSubrecordSelected := (tvRecords.SelectionCount = 1) and (tvRecords.Selections[0].Level > 1); // get multiselection booleans bHasChildren := false; bRecordsSelected := true; bSomeUnChecked := false; for i := 0 to Pred(tvRecords.SelectionCount) do begin bHasChildren := bHasChildren or tvRecords.Selections[i].HasChildren; bRecordsSelected := bRecordsSelected and (tvRecords.Selections[i].Level = 1); bSomeUnChecked := bSomeUnChecked or (tvRecords.Selections[i].StateIndex = csUnChecked); end; // enable/disable menu items bIsContainer := bHasSelection and bHasChildren and not bTreeSelected; AddItem.Visible := bTreeSelected; ToggleNodesItem.Enabled := bHasSelection; PreserveDeletionsItem.Enabled := bIsContainer; OverrideDeletionsItem.Enabled := bIsContainer; SingleEntityItem.Enabled := bIsContainer and not bRecordsSelected; ForceValueItem.Enabled := bHasSelection and bRecordsSelected; AutoPruneItem.Enabled := CanPruneRecords; PruneNodesItem.Enabled := bHasSelection and bRecordsSelected and bSomeUnChecked; UnlinkNodeItem.Enabled := bHasSelection and not bTreeSelected; ChainNodesItem.Enabled := bHasMultiSelection and not bTreeSelected; LinkNodeToItem.Enabled := bSubrecordSelected and not bTreeSelected; // build LinkNodeToItem submenu if bSubrecordSelected then begin node := tvRecords.Selected.Parent.getFirstChild; while Assigned(node) do begin if node = tvRecords.Selections[0] then begin node := node.getNextSibling; continue; end; MenuItem := TMenuItem.Create(LinkNodeToItem); MenuItem.Caption := node.Text; MenuItem.OnClick := LinkNodeItemClick; LinkNodeToItem.Add(MenuItem); node := node.getNextSibling; end; end; end; procedure TSettingsManager.AddItemClick(Sender: TObject); var item: TMenuItem; groupName: string; recObj: ISuperObject; begin item := (Sender as TMenuItem); groupName := StringReplace(item.Caption, '&', '', [rfReplaceAll]); recObj := GetRecordObj(currentSetting.tree, groupName); // build record def if it isn't already present if not Assigned(recObj) then begin if not BuildRecordDef(groupName, recObj) then exit; currentSetting.tree.A['records'].Add(recObj); LoadElement(tvRecords, tvRecords.Items[0], recObj, false); end; // update gui tvRecords.Repaint; end; procedure TSettingsManager.AddAllRecordsItemClick(Sender: TObject); begin AddAllRecords(currentSetting, tvRecords); tvRecords.Repaint; end; procedure TSettingsManager.BuildFromPluginsItemClick(Sender: TObject); var slPlugins, slSelection: TStringList; i, mr: Integer; plugin: TPlugin; selectionForm: TMiniPluginSelectionForm; begin // build list of plugin filenames slPlugins := TStringList.Create; slSelection := TStringList.Create; for i := 0 to Pred(PluginsList.Count) do begin plugin := TPlugin(PluginsList[i]); slPlugins.Add(plugin.filename); end; // prompt user for plugin selectcion selectionForm := TMiniPluginSelectionForm.Create(self); selectionForm.pluginsList := slPlugins; selectionForm.selectionList := slSelection; mr := selectionForm.ShowModal; if mr = mrOK then BuildTreeFromPlugins(tvRecords, slSelection, currentSetting.tree); // free memory selectionForm.Free; slPlugins.Free; slSelection.Free; end; procedure TSettingsManager.SelectSimilarNodesItemClick(Sender: TObject); var i, index: Integer; node: TTreeNode; reqSmashType, currentSmashType: TSmashtype; slSelection: TStringList; begin // Create StringList slSelection := TStringList.Create; try // Add "Text" and "SmashType" of selected nodes to StringList // Note: "SmashType" has to be converted to be used in a StringList for i := 0 to Pred(tvRecords.SelectionCount) do begin node := tvRecords.Selections[i]; reqSmashType := TElementData(node.Data).smashType; // "SmashType" converted into TObject slSelection.AddObject(node.Text, TObject(reqSmashType)); end; // Go through all nodes and check if their "Text" is in StringList for i := 0 to Pred(tvRecords.Items.Count) do begin node := tvRecords.Items[i]; currentSmashType := TElementData(node.Data).smashType; index := slSelection.IndexOf(node.Text); // If a "Text" is found, get associated "SmashType" from StringList if (index > -1) then begin // Convert "SmashType" back to TSmashType reqSmashType := TSmashType(slSelection.Objects[index]); // Check if node's and saved "SmashType" match and if node is selected if (currentSmashType = reqSmashType) and not node.Selected then tvRecords.Select(node, [ssCtrl]); end; end; finally // Finally free the StringList slSelection.Free; end; end; procedure TSettingsManager.ToggleNodesItemClick(Sender: TObject); var i: Integer; begin for i := 0 to Pred(tvRecords.SelectionCount) do CheckboxManager(tvRecords.Selections[i]); end; procedure TSettingsManager.PreserveDeletionsItemClick(Sender: TObject); var i: Integer; node: TTreeNode; e: TElementData; begin for i := 0 to Pred(tvRecords.SelectionCount) do begin node := tvRecords.Selections[i]; if not node.hasChildren then continue; e := TElementData(node.Data); e.preserveDeletions := not e.preserveDeletions; end; tvRecords.Repaint; end; procedure TSettingsManager.OverrideDeletionsItemClick(Sender: TObject); var i: Integer; node: TTreeNode; e: TElementData; begin for i := 0 to Pred(tvRecords.SelectionCount) do begin node := tvRecords.Selections[i]; if not node.hasChildren then continue; e := TElementData(node.Data); e.overrideDeletions := not e.overrideDeletions; end; tvRecords.Repaint; end; procedure TSettingsManager.SingleEntityItemClick(Sender: TObject); var i, expectedLevel: Integer; node: TTreeNode; e: TElementData; begin expectedLevel := 0; for i := 0 to Pred(tvRecords.SelectionCount) do begin node := tvRecords.Selections[i]; if expectedLevel = 0 then expectedLevel := node.Level; if not node.hasChildren then continue; if expectedLevel <> node.Level then continue; e := TElementData(node.Data); e.singleEntity := not e.singleEntity; if e.singleEntity then node.StateIndex := csPartiallyChecked else begin SetChildren(node, csChecked); node.StateIndex := csChecked; end; UpdateParent(node.Parent); end; tvRecords.Repaint; end; procedure TSettingsManager.ForceValueItemClick(Sender: TObject); var i: Integer; node: TTreeNode; e: TElementData; begin for i := 0 to Pred(tvRecords.SelectionCount) do begin node := tvRecords.Selections[i]; e := TElementData(node.Data); e.forceValue := not e.forceValue; end; tvRecords.Repaint; end; procedure TSettingsManager.AutoPruneItemClick(Sender: TObject); begin AutoPrune; end; procedure TSettingsManager.Autoset(parentNode: TTreeNode); const disabledElements: array[0..2] of string = ( 'Record Header', 'Unused', 'Unknown' ); disabledRecords: array[0..5] of string = ( 'DOBJ', 'LCTN', 'IDLE', 'NAVM', 'NAVI', 'RACE' ); var i: Integer; node, nextNode: TTreeNode; e: TElementData; bParentIsRoot, bParentIsRecord: boolean; begin // get parent booleans bParentIsRoot := parentNode.Level = 0; bParentIsRecord := parentNode.Level = 1; // loop through children node := parentNode.getFirstChild; while Assigned(node) do begin node.StateIndex := csChecked; e := TElementData(node.Data); if Assigned(e) then begin // if parent is root, preserve deletions if bParentIsRoot then e.preserveDeletions := true; // if parent is record, perform case statement on type if bParentIsRecord then begin case Ord(e.smashType) of Ord(stStruct): begin e.singleEntity := true; node.StateIndex := csPartiallyChecked; end; Ord(stUnsortedStructArray): begin e.singleEntity := true; e.preserveDeletions := true; node.StateIndex := csPartiallyChecked; end; Ord(stSortedArray), Ord(stSortedStructArray): e.preserveDeletions := true; Ord(stByteArray): node.StateIndex := csUnChecked; end; end; end; // if we're not on the root, disable elements that match // a string in the disableElements array if not bParentIsRoot then begin for i := Low(disabledElements) to High(disabledElements) do if Pos(disabledElements[i], node.Text) > 0 then begin node.StateIndex := csUnChecked; e.singleEntity := false; e.preserveDeletions := false; end; end // else disable records that match a string in the // disabledRecords array else begin for i := Low(disabledRecords) to High(disabledRecords) do if Pos(disabledRecords[i], node.Text) = 1 then begin node.StateIndex := csUnChecked; e.singleEntity := false; e.preserveDeletions := false; end; end; // disable count elements if bParentIsRecord then begin nextNode := node.getNextSibling; if Assigned(nextNode) and (TElementData(nextNode.Data).smashType in stArrays) and (Pos('Count', node.Text) > 0) then node.StateIndex := csUnChecked; end; // recurse if (node.HasChildren) and (node.StateIndex <> csUnChecked) then Autoset(node); // go to next sibling node := node.getNextSibling; end; // update parent node UpdateParent(parentNode); // repaint tvRecords.Repaint; end; procedure TSettingsManager.AutosetItemClick(Sender: TObject); const msg = 'This will change all nodes in this setting, are you sure you want to continue?'; var mr: Integer; begin // confirm with the user that this is what they // really want to do mr := MessageDlg(msg, mtConfirmation, [mbYes, mbNo], 0); if mr = mrYes then begin Enabled := false; Autoset(tvRecords.Items[0]); Enabled := true; end; end; procedure TSettingsManager.PruneNodesItemClick(Sender: TObject); var i: Integer; node: TTreeNode; nodesToPrune: TList; begin nodesToPrune := TList.Create; for i := 0 to Pred(tvRecords.SelectionCount) do begin node := tvRecords.Selections[i]; if (node.Level = 1) and (node.StateIndex = csUnChecked) then nodesToPrune.Add(node); end; DeleteNodes(nodesToPrune); nodesToPrune.Free; UpdateParent(tvRecords.Items[0].getFirstChild); end; function TSettingsManager.DumpElement(node: TTreeNode): ISuperObject; var obj: ISuperObject; child: TTreeNode; e: TElementData; i: Integer; begin obj := SO; // get name obj.S['n'] := node.Text; // get data properties e := TElementData(node.Data); if (e.priority > 0) then obj.I['r'] := e.priority; if (node.StateIndex <> csUnChecked) then obj.I['p'] := 1; if (e.preserveDeletions) then obj.I['d'] := 1; if (e.overrideDeletions) then obj.I['o'] := 1; if (e.singleEntity) then obj.I['s'] := 1; if (e.forceValue) then obj.I['f'] := 1; if (e.smashType <> stUnknown) then obj.I['t'] := Ord(e.smashType); if (e.linkTo <> '') then obj.S['lt'] := e.linkTo; if (e.linkFrom <> '') then obj.S['lf'] := e.linkFrom; // exit if no children to dump if node.hasChildren then begin // dump subrecords (children) obj.O['c'] := SA([]); child := node.getFirstChild; i := 0; while Assigned(child) do begin obj.A['c'].O[i] := DumpElement(child); child := child.getNextSibling; Inc(i); end; end; Result := obj; end; procedure TSettingsManager.DumpTree; var i: Integer; obj: ISuperObject; node, rootNode: TTreeNode; begin obj := SO; obj.O['records'] := SA([]); rootNode := tvRecords.Items[0]; // loop through records node := rootNode.getFirstChild; i := 0; while Assigned(node) do begin obj.A['records'].O[i] := DumpElement(node); Inc(i); node := node.getNextSibling; end; currentSetting.tree := obj; currentSetting.UpdateRecords; end; procedure TSettingsManager.edNameChange(Sender: TObject); begin if Assigned(currentSetting) then btnSave.Enabled := (currentSetting.name = edName.Text) or not Assigned(TSettingHelpers.SettingByName(edName.Text)); end; procedure TSettingsManager.DeleteNodes(var aList: TList); var i: Integer; node: TTreeNode; begin // delete nodes in reverse order for i := Pred(aList.Count) downto 0 do begin node := TTreeNode(aList[i]); if node.HasChildren then DeleteChildren(node); tvRecords.Items.Delete(node); end; end; procedure TSettingsManager.DeleteChildren(node: TTreeNode); var nodesToDelete: TList; child: TTreeNode; begin nodesToDelete := TList.Create; child := node.getFirstChild; // get nodes to prune while Assigned(child) do begin nodesToDelete.Add(child); child := child.getNextSibling; end; // delete nodes DeleteNodes(nodesToDelete); nodesToDelete.Free; end; procedure TSettingsManager.AutoPrune; var mr: Integer; nodesToPrune: TList; node: TTreeNode; begin mr := MessageDlg('Your setting tree has records that can be pruned. '+ 'Would you like to prune them?', mtConfirmation, [mbYes, mbNo], 0); if mr = mrYes then begin nodesToPrune := TList.Create; node := tvRecords.Items[0].getFirstChild; // get nodes to prune while Assigned(node) do begin if node.StateIndex = csUnChecked then nodesToPrune.Add(node); node := node.getNextSibling; end; // prune nodes DeleteNodes(nodesToPrune); nodesToPrune.Free; end; end; function TSettingsManager.CanPruneRecords: boolean; var node: TTreeNode; begin Result := false; node := tvRecords.Items[0].getFirstChild; while Assigned(node) do begin if node.StateIndex = csUnChecked then begin Result := true; break; end; node := node.getNextSibling; end; end; {******************************************************************************} { Settings Manager Events } {******************************************************************************} function TSettingsManager.GetGroup(name: string; var group: TListGroup): Boolean; var i: Integer; begin Result := false; // get the group for i := 0 to Pred(lvSettings.Groups.Count) do begin group := lvSettings.Groups[i]; if SameText(group.Header, name) then begin Result := true; break; end; end; end; procedure TSettingsManager.AddSettingItem(aSetting: TSmashSetting; bSelect: Boolean = true); var index: Integer; item: TListItem; sGroupName: string; group: TListGroup; begin // add item to list view item := lvSettings.Items.Add; item.Caption := aSetting.name; item.SubItems.Add(aSetting.records); // get group sGroupName := 'Ungrouped'; index := Pos('.', aSetting.name); if index > 0 then sGroupName := Copy(aSetting.name, 1, index - 1); if not GetGroup(sGroupName, group) then begin group := lvSettings.Groups.Add; group.Header := sGroupName; group.State := [lgsCollapsible]; end; // assign group item.GroupID := group.ID; // set selected item to the new setting if bSelect then SelectSetting(item.Index); end; procedure TSettingsManager.FormCreate(Sender: TObject); var i: Integer; aSetting: TSmashSetting; begin // do a translation dump? if bTranslationDump then TRttiTranslation.Save('lang\english.lang', self); // load translation TRttiTranslation.Load(language, self); // initialize list view, SmashSettings list NewSettings := TList.Create; lvSettings.OwnerDraw := not settings.simpleDictionaryView; lvSettings.Items.Count := SmashSettings.Count; // prepare groups and load items for i := 0 to Pred(SmashSettings.Count) do begin aSetting := TSmashSetting(SmashSettings[i]); AddSettingItem(aSetting, false); end; // Create the StringList for the Search slSearchResults := TStringList.Create; end; procedure TSettingsManager.FormDestroy(Sender: TObject); begin // Free the Search StringList slSearchResults.Free; end; procedure TSettingsManager.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if (Key = 70) and (Shift = [ssCtrl]) then edSearch.SetFocus; end; procedure TSettingsManager.FormShow(Sender: TObject); const TVS_NOTOOLTIPS = $0080; begin // disable tool tips on tree view SetWindowLong(tvRecords.Handle, GWL_STYLE, GetWindowLong(tvRecords.Handle, GWL_STYLE) or TVS_NOTOOLTIPS); // build AddItem submenu PopulateAddList(AddItem, AddItemClick); // force lvSettings to autosize columns lvSettings.Width := lvSettings.Width - 1; lvSettings.Width := lvSettings.Width + 1; end; // selects the setting specified by @index procedure TSettingsManager.SelectSetting(index: Integer); begin lvSettings.ClearSelection; lvSettings.Selected := lvSettings.Items[index]; lvSettingsChange(nil, nil, TItemChange(nil)); end; // update setting data whenever user changes their selection procedure TSettingsManager.lvSettingsChange(Sender: TObject; Item: TListItem; Change: TItemChange); begin tvRecords.Items.Clear; if (lvSettings.ItemIndex = -1) then begin currentSetting := nil; edName.Text := ''; edName.Enabled := false; cbColor.Selected := clBlack; cbColor.Enabled := false; edHash.Text := '$00000000'; meDescription.Text := ''; meDescription.Enabled := false; tvRecords.Enabled := false; btnSave.Enabled := false; btnDiscard.Enabled := false; exit; end; // set current setting values edName.Enabled := true; cbColor.Enabled := true; meDescription.Enabled := true; tvRecords.Enabled := true; btnSave.Enabled := true; btnDiscard.Enabled := true; currentSetting := TSmashSetting(SmashSettings[lvSettings.ItemIndex]); currentSettingItem := lvSettings.Items[lvSettings.ItemIndex]; edName.Text := currentSetting.name; edHash.Text := '$' + currentSetting.hash; cbColor.Selected := TColor(currentSetting.color); meDescription.Lines.Text := currentSetting.description; // load tree if assigned if Assigned(currentSetting.tree) then LoadTree(tvRecords, currentSetting); end; procedure TSettingsManager.lvSettingsClick(Sender: TObject); begin if bSearchActive then ResetSearch; end; procedure TSettingsManager.btnDiscardClick(Sender: TObject); begin // reload the setting lvSettingsChange(nil, nil, TItemChange(nil)); end; procedure TSettingsManager.btnSaveClick(Sender: TObject); var index: Integer; group: TListGroup; begin // adjust the current setting's attributes currentSetting.Rename(edName.Text); currentSetting.color := cbColor.Selected; currentSetting.description := meDescription.Lines.Text; // prompt user to auto-prune the tree if it's a new setting and // we can prune records, // then dump the records tree index := NewSettings.IndexOf(currentSetting); if (index > -1) then begin if CanPruneRecords then AutoPrune; NewSettings.Delete(index); end; DumpTree; // save the setting to disk currentSetting.Save; // update edHash edHash.Text := currentSetting.hash; // adjust the current setting in the list view GetGroup(currentSetting.name, group); currentSettingItem.GroupID := group.ID; currentSettingItem.Caption := currentSetting.name; currentSettingItem.SubItems[0] := currentSetting.records; // repaint list view lvSettings.Repaint; end; procedure TSettingsManager.lvSettingsDrawItem(Sender: TCustomListView; Item: TListItem; Rect: TRect; State: TOwnerDrawState); var i, x, y: integer; lv: TListView; aSetting: TSmashSetting; begin lv := TListView(Sender); // get color aSetting := TSmashSetting(SmashSettings[Item.Index]); lv.Canvas.Font.Color := aSetting.color; lv.Canvas.Font.Style := [fsBold]; lv.Canvas.Refresh; // draw selected rect if Item.Selected then begin lv.Canvas.Brush.Color := $FFEEDD; lv.Canvas.FillRect(Rect); end; // draw item x := Rect.Left; y := (Rect.Bottom - Rect.Top - lv.Canvas.TextHeight('Hg')) div 2 + Rect.Top; lv.Canvas.TextOut(x, y, ' '+Item.Caption); // draw subitems for i := 0 to Item.SubItems.Count - 1 do begin Inc(x, ListView_GetColumnWidth(lv.Handle, lv.Columns[i].Index)); lv.Canvas.TextOut(x, y, ' '+Item.SubItems[i]); end; end; {******************************************************************************} { SettingPopupMenu methods Methods for dealing with the popup menu for the settings list view. - NewSettingItemClick - EditSettingItemClick - DeleteSettingItemClick } {******************************************************************************} procedure TSettingsManager.SettingsPopupMenuPopup(Sender: TObject); var bHasSelection, bHasMultiSelection: boolean; begin bHasSelection := Assigned(lvSettings.Selected); bHasMultiSelection := lvSettings.SelCount > 1; DeleteSettingItem.Enabled := bHasSelection; CloneSettingItem.Enabled := bHasSelection; CombineSettingsItem.Enabled := bHasMultiSelection; end; procedure TSettingsManager.NewSettingItemClick(Sender: TObject); var newSetting: TSmashSetting; begin // create new setting newSetting := TSmashSetting.Create; NewSettings.Add(newSetting); SmashSettings.Add(newSetting); AddSettingItem(newSetting); end; procedure TSettingsManager.DeleteSettingItemClick(Sender: TObject); var i, index: Integer; setting: TSmashSetting; begin for i := Pred(lvSettings.Items.Count) downto 0 do begin if not lvSettings.Items[i].Selected then continue; lvSettings.Items.Delete(i); setting := TSmashSetting(SmashSettings[i]); RemoveSettingFromPlugins(setting); SmashSettings.Delete(i); index := NewSettings.IndexOf(setting); if index > -1 then NewSettings.Delete(index); setting.Delete; setting.Free; end; lvSettings.Repaint; lvSettingsChange(nil, nil, TItemChange(nil)); end; procedure TSettingsManager.CloneSettingItemClick(Sender: TObject); var setting, clonedSetting: TSmashSetting; begin clonedSetting := TSmashSetting.Create; setting := TSmashSetting(SmashSettings[lvSettings.Selected.Index]); clonedSetting.Clone(setting); SmashSettings.Add(clonedSetting); // add setting to list view AddSettingItem(clonedSetting); end; procedure TSettingsManager.CombineSettingsItemClick(Sender: TObject); var i: Integer; ListItem: TListItem; settingsToCombine: TList; setting: TSmashSetting; sl, slRecords: TStringList; cForm: TConflictForm; begin // create lists settingsToCombine := TList.Create; slRecords := TStringList.Create; sl := TStringList.Create; sl.StrictDelimiter := true; sl.Delimiter := ','; try // add selected settings to the settingsToCombine list for i := 0 to Pred(lvSettings.Items.Count) do begin ListItem := lvSettings.Items[i]; if not ListItem.Selected then continue; setting := TSmashSetting(SmashSettings[i]); settingsToCombine.Add(setting); sl.Add(setting.name); end; // build a list of the record objects in the settings // if conflicts found, have user resolve them if CombineSettingTrees(settingsToCombine, slRecords) then begin cForm := TConflictForm.Create(self); cForm.slConflicts := slRecords; if cForm.ShowModal = mrOK then CreateCombinedSetting(slRecords, sl.DelimitedText); end // else just create the combined setting else begin CreateCombinedSetting(slRecords, sl.DelimitedText); end; finally // update lvSettings if we created a new setting if SmashSettings.Count > lvSettings.Items.Count then begin setting := TSmashSetting(SmashSettings[Pred(SmashSettings.Count)]); AddSettingItem(setting); end; // free memory settingsToCombine.Free; slRecords.Free; sl.Free; end; end; // repaint when splitter is moved procedure TSettingsManager.SplitterMoved(Sender: TObject); begin Repaint; end; end. ================================================ FILE: frontend/msSmash.pas ================================================ unit msSmash; interface uses Windows, SysUtils, Classes, ShellAPI, Controls, Dialogs, // superobject superobject, // mte units mteHelpers, mteLogger, mteTracker, mteBase, // ms units msCore, msConfiguration, msConflict, msAlgorithm, // xEdit units wbInterface, wbImplementation; procedure BuildPatch(var patch: TPatch); procedure RebuildPatch(var patch: TPatch); implementation procedure BuildPluginsList(var patch: TPatch; var lst: TList); var i: Integer; plugin: TPlugin; begin for i := 0 to Pred(patch.plugins.Count) do begin plugin := PluginByFileName(patch.plugins[i]); if not Assigned(plugin) then raise Exception.Create('Couldn''t find plugin '+patch.plugins[i]); lst.Add(plugin); end; end; procedure SetPatchAttributes(var patch: TPatch); var patchFile: IwbFile; fileHeader: IwbContainer; begin patchFile := patch.plugin._File; fileHeader := patchFile.Elements[0] as IwbContainer; // set author fileHeader.ElementEditValues['CNAM'] := 'Mator Smash v' + ProgramStatus.Version; // set description fileHeader.ElementEditValues['SNAM'] := 'Smashed patch:'#13#10 + patch.plugins.Text; end; function GetPatchFile(var patch: TPatch; var lst: TList): IwbFile; var plugin: TPlugin; bUsedExistingFile: boolean; patchFile: IwbFile; i: Integer; begin // get plugin if it exists // else create it plugin := PluginByFilename(patch.filename); patch.plugin := nil; if Assigned(plugin) then begin bUsedExistingFile := true; patch.plugin := plugin; end else begin bUsedExistingFile := false; patch.plugin := CreateNewPlugin(patch.filename); end; // don't patch if patchFile not assigned if not Assigned(patch.plugin) then raise Exception.Create('Couldn''t assign patch file'); // don't patch if patchFile is at an invalid load order position relative // to the plugins being patched if bUsedExistingFile then begin for i := 0 to Pred(lst.Count) do begin plugin := TPlugin(lst[i]); if PluginsList.IndexOf(plugin) > PluginsList.IndexOf(patch.plugin) then raise Exception.Create(Format('%s is at a lower load order position than %s', [plugin.filename, patch.filename])); end; // clean up the patch file patchFile := patch.plugin._File; for i := Pred(patchFile.RecordCount) downto 0 do patchFile.Records[i].Remove; end; // set result Result := patch.plugin._File; Tracker.Write(' '); Tracker.Write('Patch is using plugin: '+patch.plugin.filename); end; procedure AddRequiredMasters(var patch: TPatch; var lst: TList); var slMasters: TStringList; i: Integer; plugin: TPlugin; begin slMasters := TStringList.Create; try Tracker.Write('Adding masters...'); for i := 0 to Pred(lst.Count) do begin plugin := TPlugin(lst[i]); GetMasters(plugin._File, slMasters); slMasters.AddObject(plugin.filename, patch.plugins.Objects[i]); end; try slMasters.CustomSort(LoadOrderCompare); AddMasters(patch.plugin._File, slMasters); if settings.debugMasters then begin Tracker.Write('Masters added:'); Tracker.Write(slMasters.Text); slMasters.Clear; GetMasters(patch.plugin._File, slMasters); Tracker.Write('Actual masters:'); Tracker.Write(slMasters.Text); end; except on x: Exception do begin Tracker.Write('Critical exception adding masters!'); Tracker.Write(x.Message); raise x; end; end; finally slMasters.Free; if Tracker.Cancel then raise Exception.Create('User cancelled smashing.'); Tracker.Write('Done adding masters'); end; end; procedure BuildOverridesList(var patch: TPatch; var lst: TList; var records: TInterfaceList); var i, j, recCount: Integer; plugin: TPlugin; aSetting: TSmashSetting; aFile: IwbFile; rec: IwbMainRecord; recObj: ISuperObject; begin Tracker.Write(' '); Tracker.Write('Processing files'); for i := 0 to Pred(lst.Count) do begin if Tracker.Cancel then break; plugin := TPlugin(lst[i]); // get file and setting for later use aFile := plugin._File; aSetting := plugin.smashSetting; // loop through file records Tracker.Write('Processing '+plugin.filename); recCount := Pred(aFile.RecordCount); for j := 0 to recCount do begin if Tracker.Cancel then break; rec := aFile.Records[j]; if j mod 500 = 499 then Tracker.UpdateProgress(500); try // skip non-override records if rec.IsMaster then continue; rec := rec.Master; if OverrideCountInFiles(rec, patch.plugins) < 2 then continue; // skip records according to smash setting recObj := aSetting.GetRecordDef(rec.Signature); if not Assigned(recObj) then continue; if (recObj.I['p'] <> 1) then continue; // skip non-conflicting records if ConflictAllForMainRecord(rec) < caConflict then continue; // add record to overrides list if records.IndexOf(rec) = -1 then records.Add(rec); except on x: Exception do begin Tracker.Write(' Error processing ' + rec.Name + ', ' + x.Message); continue; end; end; end; // update progress bar for file Tracker.UpdateProgress(recCount mod 500); end; end; procedure UpdateCounts(var rec: IwbMainRecord); var container, arrayContainer: IwbContainerElementRef; i: Integer; element, nextElement: IwbElement; begin // if reocrd is not editable, exit if not rec.IsEditable then exit; // if record can't be treated as a container, exit if not Supports(rec, IwbContainerElementRef, container) then exit; // loop through top-level elements for i := 0 to container.ElementCount - 2 do begin element := container.Elements[i]; nextElement := container.Elements[i + 1]; if not Supports(nextElement, IwbContainerElementRef, arrayContainer) then continue; // if next element is an array element and current element has the // word count in its name update the count to be the number of elements // in the array if (GetSmashType(nextElement) in stArrays) and (Pos('Count', element.Name) > 0) then try element.NativeValue := arrayContainer.ElementCount; except on x: Exception do Tracker.Write(' Exception updating count at '+element.Path); end; end; end; function HasPartialFormFlag(rec: IwbMainRecord): Boolean; begin Result := ((rec.Signature = 'QUST') or (rec.Signature = 'LCTN')) and (rec.Flags._Flags and $00004000 <> 0); end; procedure SmashRecords(var patch: TPatch; var records: TInterfaceList); var i, j: Integer; incProgress, currentProgress: Real; rec, mst, ovr, patchRec: IwbMainRecord; f, patchFile, forceFile: IwbFile; plugin: TPlugin; aSetting: TSmashSetting; recObj: ISuperObject; e, eCopy: IwbElement; bDeletions, bOverride, bForce: boolean; begin Tracker.Write(' '); Tracker.Write('Smashing records'); patchFile := patch.plugin._File; // loop through records to smash currentProgress := Tracker.GetProgress; incProgress := (Tracker.GetMaxProgress - Tracker.GetProgress) / records.Count; for i := 0 to Pred(records.Count) do begin if Tracker.Cancel then break; if not Supports(records[i], IwbMainRecord, rec) then exit; Tracker.StatusMessage(Format('Smashing records (%d/%d)', [i + 1, records.Count])); currentProgress := currentProgress + incProgress; Tracker.SetProgress(Round(currentProgress)); // loop through record's overrides patchRec := nil; forceFile := nil; for j := 0 to Pred(rec.OverrideCount) do begin if Tracker.Cancel then break; ovr := rec.Overrides[j]; f := ovr._File; // skip overrides that are in plugins we aren't patching if patch.plugins.IndexOf(f.FileName) = -1 then continue; plugin := PluginByFileName(f.FileName); if not Assigned(plugin) then continue; // skip ctIdenticalToMaster overrides if (ConflictThisForMainRecord(ovr) = ctIdenticalToMaster) then continue; // skip plugins that have the skip setting if plugin.setting = 'Skip' then continue; // skip overrides according to smash setting aSetting := plugin.smashSetting; recObj := aSetting.GetRecordDef(ovr.Signature); if not Assigned(recObj) then continue; if (recObj.I['p'] <> 1) then continue; bForce := recObj.I['f'] = 1; if bForce then begin if Assigned(patchRec) then begin patchRec.Remove; patchRec := nil; end; forceFile := f; end; // copy record to smashed patch if it hasn't been copied yet if not Assigned(patchRec) then try if bForce then e := ovr else e := WinningOverrideInFiles(rec, patch.plugins); Tracker.Write(Format(' [%d] Copying record %s', [i + 1, e.Name])); eCopy := wbCopyElementToFile(e, patchFile, false, true, '', '' ,''); patchRec := eCopy as IwbMainRecord; if bForce then continue; except on x: Exception do begin Tracker.Write(' Exception copying record '+ovr.Name+' : '+x.Message); patch.fails.Add('Exception copying record '+ovr.Name+' : '+x.Message); continue; end; end; // skip if we're forcing and plugin doesn't require forceFile if Assigned(forceFile) and not bForce and (plugin.masters.IndexOf(forceFile.FileName) = -1) then continue; // finally, recursively copy overridden elements try bDeletions := recObj.I['d'] = 1; if (wbGameMode = gmFO4) and HasPartialFormFlag(ovr) then bDeletions := False; bOverride := recObj.I['o'] = 1; if bForce then mst := e as IwbMainRecord else mst := WinningOverrideInFiles(rec, plugin.masters); Tracker.Write(Format(' Smashing override from: %s, master: %s', [f.FileName, mst._File.FileName])); rcore(IwbElement(ovr), IwbElement(mst), IwbElement(patchRec), patchRec, recObj, false, bDeletions, bOverride); except on x: Exception do begin Tracker.Write(' Exception smashing record: '+ovr.Name+' : '+x.Message); patch.fails.Add('Exception smashing record: '+ovr.Name+' : '+x.Message); end; end; // update any count elements on the record UpdateCounts(patchRec); end; end; end; function IsChildGroup(group: IwbGroupRecord): Boolean; begin Result := group.GroupType in [1,6,7]; end; function NativeContainer(element: IwbElement): IwbContainer; var group: IwbGroupRecord; begin if Supports(element, IwbGroupRecord, group) and IsChildGroup(group) then Result := group.ChildrenOf as IwbContainer else Result := element.Container; if not Assigned(Result) then raise Exception.Create('Could not find container for ' + element.Name); end; procedure RemoveEmptyContainers(aContainer: IwbContainer); var container, nextContainer: IwbContainer; rec: IwbMainRecord; bITM, bITPO: Boolean; begin container := aContainer; // traverse up container until we find an IwbMainRecord while Assigned(container) and not Supports(container, IwbMainRecord, rec) do begin // break if container still has elements in it if container.ElementCount > 0 then exit; // else remove it and traverse up to next container nextContainer := NativeContainer(container); container.Remove; container := nextContainer; end; // exit if record is not ITM or ITPO bITM := IsITM(rec); bITPO := IsITPO(rec); if not (bITM or bITPO) then exit; // else remove MainRecord and recurse if bITM then Tracker.Write(' Removing ITM: ' + rec.Name) else Tracker.Write(' Removing ITPO: ' + rec.Name); nextContainer := rec.Container; rec.Remove; RemoveEmptyContainers(nextContainer); end; procedure RemoveITPOs(aFile: IwbFile); var i, CountITPO: Integer; e, m: IwbMainRecord; container: IwbContainer; ITPOs: TDynMainRecords; begin Tracker.Write(' '); Tracker.Write('Removing ITPO records from patch'); CountITPO := 0; // loop through file's records for i := Pred(aFile.RecordCount) downto 0 do begin if Tracker.Cancel then break; e := aFile.Records[i]; m := e.MasterOrSelf; // skip master records if e.IsMaster then continue; // skip records that have elements in child group (WRLD, CELL, DIAL) if Assigned(e.ChildGroup) and (e.ChildGroup.ElementCount > 0) then continue; // remove record if no conflicts if IsITPO(e) then begin Tracker.Write(' Removing ITPO: ' + e.Name); // add ITPO to list of records to remove SetLength(ITPOs, CountITPO + 1); ITPOs[CountITPO] := e; Inc(CountITPO); end; end; // remove the records for i := Pred(Length(ITPOs)) downto 0 do begin e := ITPOs[i]; container := e.Container; e.Remove; try RemoveEmptyContainers(container); except on x: Exception do Tracker.Write(' Exception removing empty containers: '+x.Message); end; end; // finalization message Tracker.Write(Format(' Removed %d ITPO records', [CountITPO])); end; procedure CleanPatch(var patch: TPatch); var patchFile: IwbFile; begin patchFile := patch.plugin._File; // remove ITPOs try if not settings.preserveITPOs then RemoveITPOs(patchFile); except on x: Exception do Tracker.Write(' Exception removing ITPOs: '+x.Message); end; end; procedure SavePatchFiles(var patch: TPatch); var patchFilePrefix, patchPath: string; begin // update patch plugin hashes and settings patch.UpdateHashes; patch.UpdateSettings; // get path to save file at patchPath := patch.dataPath + 'smash\'; ForceDirectories(patchPath); // save patch plugin patch.plugin.dataPath := patch.dataPath; patch.plugin.Save; // save files, fails, plugins patchFilePrefix := patchPath + ChangeFileExt(patch.filename, ''); patch.fails.SaveToFile(patchFilePrefix+'_fails.txt'); patch.plugins.SaveToFile(patchFilePrefix+'_plugins.txt'); end; procedure BuildPatch(var patch: TPatch); var patchFile: IwbFile; pluginsToPatch: TList; recordsList: TInterfaceList; time: TDateTime; msg: string; begin // initialize Tracker.Write('Building patch: '+patch.name); time := Now; patch.fails.Clear; pluginsToPatch := TList.Create; msg := 'User cancelled smashing patches.'; try // build list of plugins to patch BuildPluginsList(patch, pluginsToPatch); HandleCanceled(msg); // identify or create patch file patchFile := GetPatchFile(patch, pluginsToPatch); SetPatchAttributes(patch); // add masters to patch file AddRequiredMasters(patch, pluginsToPatch); HandleCanceled(msg); // build list of overrides recordsList := TInterfaceList.Create; BuildOverridesList(patch, pluginsToPatch, recordsList); HandleCanceled(msg); // stop smashing if no records to smash if recordsList.Count = 0 then raise Exception.create('No records to patch!'); // smash records SmashRecords(patch, recordsList); HandleCanceled(msg); // clean patch (ITPOs) CleanPatch(patch); // save patch and associated files SavePatchFiles(patch); // update statistics if patch.status = psBuildReady then Inc(sessionStatistics.pluginsPatched, patch.plugins.Count); Inc(sessionStatistics.patchesBuilt); // finalization messages time := (Now - time) * 86400; patch.dateBuilt := Now; patch.status := psUpToDate; Tracker.Write(Format('Done smashing %s (%.3f)', [patch.name, Real(time)])); except on x: Exception do begin patch.status := psFailed; Tracker.Write(Format('Failed to patch %s, %s', [patch.name, x.Message])); end; end; // clean up TryToFree(pluginsToPatch); TryToFree(recordsList); end; procedure RebuildPatch(var patch: TPatch); begin BuildPatch(patch); end; end. ================================================ FILE: frontend/msSmashForm.dfm ================================================ object SmashForm: TSmashForm Left = 0 Top = 0 Caption = 'Mator Smash' ClientHeight = 682 ClientWidth = 1264 Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'Tahoma' Font.Style = [] OldCreateOrder = False Position = poScreenCenter OnCloseQuery = FormCloseQuery OnCreate = FormCreate OnDestroy = FormDestroy OnShow = FormShow PixelsPerInch = 96 TextHeight = 13 object Splitter: TSplitter Left = 670 Top = 45 Height = 615 Beveled = True Color = clSilver ParentColor = False ExplicitLeft = 637 ExplicitHeight = 637 end object QuickBar: TPanel Left = 0 Top = 0 Width = 1264 Height = 45 Align = alTop TabOrder = 0 object NewButton: TSpeedButton Left = 52 Top = 2 Width = 48 Height = 40 CustomHint = bhNew NumGlyphs = 2 ParentShowHint = False ShowHint = True OnClick = NewButtonClick end object BuildButton: TSpeedButton Left = 102 Top = 2 Width = 48 Height = 40 CustomHint = bhBuild NumGlyphs = 2 ParentShowHint = False ShowHint = True OnClick = BuildButtonClick end object OptionsButton: TSpeedButton Left = 202 Top = 2 Width = 48 Height = 40 CustomHint = bhOptions NumGlyphs = 2 ParentShowHint = False ShowHint = True OnClick = OptionsButtonClick end object ManageButton: TSpeedButton Left = 152 Top = 2 Width = 48 Height = 40 CustomHint = bhManage NumGlyphs = 2 ParentShowHint = False ShowHint = True OnClick = ManageButtonClick end object QuickButton: TSpeedButton Left = 2 Top = 2 Width = 48 Height = 40 CustomHint = bhQuick NumGlyphs = 2 ParentShowHint = False ShowHint = True OnClick = QuickButtonClick end end object MainPanel: TPanel Left = 0 Top = 45 Width = 670 Height = 615 Align = alLeft BevelOuter = bvNone Caption = 'MainPanel' Constraints.MinWidth = 200 TabOrder = 1 object PageControl: TPageControl Left = 3 Top = 7 Width = 664 Height = 605 ActivePage = PluginsTabSheet Align = alCustom Anchors = [akLeft, akTop, akRight, akBottom] TabOrder = 0 OnChange = PageControlChange object PluginsTabSheet: TTabSheet Margins.Left = 4 Margins.Top = 4 Margins.Right = 4 Margins.Bottom = 4 Caption = 'Plugins' object PluginsListView: TListView Left = 3 Top = 3 Width = 650 Height = 571 Align = alCustom Anchors = [akLeft, akTop, akRight, akBottom] Columns = < item Caption = 'Index' Width = 45 end item AutoSize = True Caption = 'Filename' end item Caption = 'Setting' Tag = 300 Width = 161 end item Caption = 'Patch' Width = 150 end> ColumnClick = False DoubleBuffered = True MultiSelect = True OwnerData = True OwnerDraw = True ReadOnly = True RowSelect = True ParentDoubleBuffered = False ParentShowHint = False PopupMenu = PluginsPopupMenu ShowHint = True TabOrder = 0 ViewStyle = vsReport OnChange = PluginsListViewChange OnData = PluginsListViewData OnDrawItem = PluginsListViewDrawItem end end object PatchesTabSheet: TTabSheet Caption = 'Patches' ImageIndex = 1 ExplicitLeft = 0 ExplicitTop = 0 ExplicitWidth = 0 ExplicitHeight = 0 object PatchesListView: TListView Left = 3 Top = 3 Width = 650 Height = 571 Align = alCustom Anchors = [akLeft, akTop, akRight, akBottom] Columns = < item Caption = 'Index' end item AutoSize = True Caption = 'Name' end item Caption = 'Filename' Width = 175 end item Caption = 'Size' end item Caption = 'Date built' Width = 150 end> ColumnClick = False DoubleBuffered = True MultiSelect = True OwnerData = True OwnerDraw = True ReadOnly = True RowSelect = True ParentDoubleBuffered = False ParentShowHint = False PopupMenu = PatchesPopupMenu ShowHint = False TabOrder = 0 ViewStyle = vsReport OnChange = PatchesListViewChange OnData = PatchesListViewData OnDblClick = PatchesListViewDblClick OnDrawItem = PatchesListViewDrawItem OnKeyDown = PatchesListViewKeyDown end end object LogTabSheet: TTabSheet Caption = 'Log' ImageIndex = 2 ExplicitLeft = 0 ExplicitTop = 0 ExplicitWidth = 0 ExplicitHeight = 0 object LogListView: TListView Left = 3 Top = 3 Width = 650 Height = 571 Align = alCustom Anchors = [akLeft, akTop, akRight, akBottom] Columns = < item Caption = 'Time' Width = 80 end item Caption = 'AppTime' Width = 80 end item Caption = 'Group' Width = 80 end item Caption = 'Label' Width = 80 end item AutoSize = True Caption = 'Text' end> ColumnClick = False DoubleBuffered = True MultiSelect = True OwnerData = True OwnerDraw = True ReadOnly = True RowSelect = True ParentDoubleBuffered = False PopupMenu = LogPopupMenu ShowColumnHeaders = False TabOrder = 0 ViewStyle = vsReport OnData = LogListViewData OnDrawItem = LogListViewDrawItem end end end end object DetailsPanel: TPanel Left = 673 Top = 45 Width = 591 Height = 615 Align = alClient BevelOuter = bvNone Constraints.MinWidth = 200 TabOrder = 2 object DetailsLabel: TLabel Left = 6 Top = 10 Width = 32 Height = 13 Caption = 'Details' end object DetailsGrid: TStringGrid Left = 3 Top = 27 Width = 581 Height = 584 Align = alCustom Anchors = [akLeft, akTop, akRight, akBottom] ColCount = 2 DefaultColWidth = 150 DefaultRowHeight = 22 DoubleBuffered = True RowCount = 1 FixedRows = 0 ParentDoubleBuffered = False PopupMenu = DetailsPopupMenu ScrollBars = ssVertical TabOrder = 0 OnDrawCell = DetailsGridDrawCell OnMouseMove = DetailsGridMouseMove OnMouseUp = DetailsGridMouseUp end end object StatusPanel: TPanel Left = 0 Top = 660 Width = 1264 Height = 22 Align = alBottom BevelOuter = bvLowered TabOrder = 3 object StatusPanelMessage: TPanel Left = 3 Top = 0 Width = 951 Height = 22 Margins.Top = 0 Margins.Bottom = 0 Align = alCustom Alignment = taLeftJustify Anchors = [akLeft, akTop, akRight, akBottom] BevelEdges = [beRight] BevelKind = bkFlat BevelOuter = bvNone Caption = 'Welcome to Mator Smash!' Ctl3D = True ParentCtl3D = False TabOrder = 0 end object StatusPanelMerges: TPanel Left = 960 Top = 0 Width = 30 Height = 22 Margins.Top = 0 Margins.Bottom = 0 Align = alCustom Anchors = [akTop, akRight, akBottom] BevelEdges = [beRight] BevelKind = bkFlat BevelOuter = bvNone Ctl3D = True ParentCtl3D = False TabOrder = 1 object ImageBuild: TImage Left = 4 Top = 4 Width = 16 Height = 16 Picture.Data = { 055449636F6E0000010001001010000001002000680400001600000028000000 1000000020000000010020000000000000000000000000000000000000000000 000000000B0C0C000808080000000000020203000B0911000D0912000D091200 0D0912000D0912000D0912000E0A14000F0C1714121222A20D0C16BE0200004F 000000000B0C0C00080808000000000000000000050103000D0309000C030800 0C0308000C0308000B0207000E030700162043B9194C96FF1D4A92FF151E3BF1 020000590B0C0C00080808000000000000000000060205000E050C000D050B00 0D050B000D050B000C0205000C091C6D2E5EA1FD4E98DFFF156DDEFF1556BEFF 0D0F1EBE0B0C0C000808080000000000000000000B070D001A0F1F00170E1C00 170E1C00170D1A00150A1712163369E55CA2E3FFB6DFFDFFBEDFFFFF4B73B9FE 0506177F0B0C0C000808080000000000000000000302030012091500160A1A00 150A190014061200100E2A813976BDFF97D0FDFFDDFCFFFFB4BECFFF25222EAB 000000000B0C0C00080808000000000000000000000000000C050E0014071600 13071500110210191E3F76EC7ABEF7FFC7F3FFFF95B9D8FF1A223ABB00000000 000000000B0C0C0008080800000000000000000000000000060309000F040D00 0E0105000E1C41BE5298DBFFADE7FFFF72A8D7FF12203EC30000000200000000 00000000090A0A000505051B000000480000000C00000000060308000E000200 0C0C24982A6FB8FE9BE1FFFF7CB5E3FF081C3ECC000000080000000000000000 000000000405052E494847E34F4F4EFC0404049C01000000070001000F0D2497 2466AFFE7ECDFFFF9FDBFEFF24436EEF0000002A020000000000010000000000 00000000535252D7D6CFCDFFB8B4B2FF3B3C3CF8000000610A0F21971F67B4FE 6AC2FFFFA8E6FFFF4D7CACFE00000D7600000000000000000000000000000000 00000000797676ECD7D2D3FFCBC9CAFF8E8F8EFF44413FFB6E6F75FE5395C9FF 80D3FFFF76B2E0FF0C1735C40000000000000000000000000000000000000000 000000002828283A434343CB888888FDACACABFFAAA9A7FFBEB7B1FFB6B0AAFF 729DBDFF254468EA000000210000000000000000000000000000000000000000 00000000262626001D1D1D00313131ADA4A3A0FFCCCAC7FFC5C1BFFFCDC6C3FF 7A7270FF090809A3000000000000000000000004000000140000000C00000000 0000000027272700262626002222222A676665F1D1CFCDFFE6E3E1FFB3B1B0FF 6F6E6CFF444443F92D2E2EE4333333DB494949E83A3A3AE50606064804040400 05050500272727002727270026262600232323465D5D5CE7C2C0BDFFD6D3D1FF ACA9A9FFA8A7A6FFAFADACFFBBB9B8FF999998FE393939B80303030C05050500 06060600272727002727270028282800252526002020201937363698737170E5 999595F99F9B9AFC8F8B8AF6686565D929292871010101000505050006060600 06060600FFF30000FFE10000FFE00000FFC10000FF810000FF830000FF070000 FE0F00008C1F0000083F0000003F0000807F0000C07F0000E0070000F0070000 F81F0000} end end object StatusPanelLanguage: TPanel Left = 996 Top = 0 Width = 130 Height = 22 Margins.Top = 0 Margins.Bottom = 0 Align = alCustom Anchors = [akTop, akRight, akBottom] BevelEdges = [beRight] BevelKind = bkFlat BevelOuter = bvNone Caption = 'Language' Ctl3D = True ParentCtl3D = False TabOrder = 2 end object StatusPanelVersion: TPanel Left = 1132 Top = 0 Width = 130 Height = 22 Margins.Top = 0 Margins.Bottom = 0 Align = alCustom Anchors = [akTop, akRight, akBottom] BevelEdges = [] BevelKind = bkFlat BevelOuter = bvNone Caption = 'v0.00.00.000' Ctl3D = True ParentCtl3D = False TabOrder = 3 end end object XPManifest: TXPManifest Left = 1120 Top = 8 end object PluginsPopupMenu: TPopupMenu OnPopup = PluginsPopupMenuPopup Left = 56 Top = 112 object AddToPatchItem: TMenuItem Caption = 'Add to patch' object NewPatchItem: TMenuItem Caption = '' OnClick = AddToNewPatchClick end end object SmashSettingItem: TMenuItem Caption = 'Smash setting' end object TagsItem: TMenuItem Caption = 'Tags' object ManageTagsItem: TMenuItem Caption = 'Manage tags' OnClick = ManageTagsItemClick end object ApplySettingTagsItem: TMenuItem Caption = 'Apply setting tags' OnClick = ApplySettingTagsItemClick end object ClearTagsItem: TMenuItem Caption = 'Clear tags' OnClick = ClearTagsItemClick end end object RemoveFromPatchItem: TMenuItem Caption = 'Remove from patch' OnClick = RemoveFromPatchItemClick end object OpenPluginLocationItem: TMenuItem Caption = 'Open plugin location' OnClick = OpenPluginLocationItemClick end end object PatchesPopupMenu: TPopupMenu OnPopup = PatchesPopupMenuPopup Left = 160 Top = 112 object CreateNewPatchItem: TMenuItem Caption = 'Create new patch' OnClick = NewButtonClick end object EditPatchItem: TMenuItem Caption = 'Edit patch' OnClick = EditPatchItemClick end object RemoveUnloadedPluginsItem: TMenuItem Caption = 'Remove unloaded plugins' OnClick = RemoveUnloadedPluginsItemClick end object DeletePatchItem: TMenuItem Caption = 'Delete patch' OnClick = DeletePatchItemClick end object MoveItem: TMenuItem Caption = 'Move' object UpItem: TMenuItem Caption = 'Up' OnClick = UpItemClick end object DownItem: TMenuItem Caption = 'Down' OnClick = DownItemClick end object ToTopItem: TMenuItem Caption = 'To top' OnClick = ToTopItemClick end object ToBottomItem: TMenuItem Caption = 'To bottom' OnClick = ToBottomItemClick end end object BuildPatchItem: TMenuItem Caption = 'Build patch' OnClick = BuildPatchItemClick end object ToggleRebuildItem: TMenuItem Caption = 'Toggle rebuild status' OnClick = ToggleRebuildItemClick end object OpenInExplorerItem: TMenuItem Caption = 'Open in explorer' OnClick = OpenInExplorerItemClick end end object IconList: TImageList Height = 32 Width = 64 Left = 1048 Top = 8 Bitmap = { 494C010105001400CC0240002000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600 0000000000003600000028000000000100004000000001002000000000000000 0100000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000E2E2 E21D8F8F8F705F5F5FA03F3F3FC0303030CF303030CF3F3F3FC05F5F5FA08F8F 8F70E2E2E21D0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000E5E5 E51D9E9E9E70747474A0595959C04C4C4CCF4C4C4CCF595959C0747474A09E9E 9E70E5E5E51D0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000009898 9867050504FF332E27FF473F36FF50473DFF50473DFF473F36FF332E27FF0505 04FF989898670000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000A6A6 A667272727FF4A4A4AFF595959FF606060FF606060FF595959FF4A4A4AFF2727 27FFA6A6A6670000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000A4A4A45B5C5C5CA3F9F9F906000000009898 9867161411FF918171FF918171FF918171FF918171FF918171FF918171FF1614 11FF9898986700000000F9F9F9065C5C5CA3A4A4A45B00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000B0B0B05B727272A3F9F9F90600000000A6A6 A667343434FF929292FF929292FF929292FF929292FF929292FF929292FF3434 34FFA6A6A66700000000F9F9F906727272A3B0B0B05B00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000F4F4F40B575757A8040303FF0C0B09FF4B4B4BB4F9F9F9069393 936C171412FF948575FF948575FF948575FF948575FF948575FF948575FF1714 12FF9393936CF9F9F9064B4B4BB40C0B09FF040303FF575757A8F4F4F40B0000 0000000000000000000000000000000000000000000000000000000000000000 000000000000F5F5F50B6E6E6EA8262626FF2D2D2DFF636363B4F9F9F906A1A1 A16C343434FF969696FF969696FF969696FF969696FF969696FF969696FF3434 34FFA1A1A16CF9F9F906636363B42D2D2DFF262626FF6E6E6EA8F5F5F50B0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000ECECEC13343434CB151311FF7C7064FF817567FF0F0E0CFF252525DA0404 04FB23201CFF98897AFF98897AFF98897AFF98897AFF98897AFF98897AFF2320 1CFF040404FB252525DA0F0E0CFF817567FF7C7064FF151311FF343434CBECEC EC13000000000000000000000000000000000000000000000000000000000000 0000EEEEEE134F4F4FCB343434FF848484FF878787FF2F2F2FFF424242DA2626 26FB3F3F3FFF999999FF999999FF999999FF999999FF999999FF999999FF3F3F 3FFF262626FB424242DA2F2F2FFF878787FF848484FF343434FF4F4F4FCBEEEE EE13000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000F4F4 F40B343434CB1D1A18FF8F8274FF9B8D7EFF9B8D7EFF84786BFF342F2AFF7369 5EFF9B8D7EFFA49789FFAB9F93FFAEA296FFACA094FFA79B8EFFA09385FF9A8C 7EFF73695EFF342F2AFF84786BFF9B8D7EFF9B8D7EFF8F8274FF1D1A18FF3434 34CBF4F4F40B000000000000000000000000000000000000000000000000F5F5 F50B4F4F4FCB3A3A3AFF939393FF9D9D9DFF9D9D9DFF8B8B8BFF4C4C4CFF7E7E 7EFF9D9D9DFFA5A5A5FFACACACFFAFAFAFFFADADADFFA9A9A9FFA2A2A2FF9C9C 9CFF7E7E7EFF4C4C4CFF8B8B8BFF9D9D9DFF9D9D9DFF939393FF3A3A3AFF4F4F 4FCBF5F5F50B0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000005757 57A8161412FF928578FF9E9182FF9E9182FF9E9182FF9E9182FFA19486FFB6AC A1FFC9C1B8FFCBC2BBFFC7BEB6FFC2BAB1FFBFB6ADFFBBB2A8FFB8AEA3FFB2A7 9BFFA79A8DFF9F9183FF9E9182FF9E9182FF9E9182FF9E9182FF928578FF1614 12FF575757A80000000000000000000000000000000000000000000000006E6E 6EA8343434FF969696FF9F9F9FFF9F9F9FFF9F9F9FFF9F9F9FFFA3A3A3FFB7B7 B7FFCACACAFFCBCBCBFFC7C7C7FFC4C4C4FFC0C0C0FFBDBDBDFFB9B9B9FFB3B3 B3FFA8A8A8FFA0A0A0FF9F9F9FFF9F9F9FFF9F9F9FFF9F9F9FFF969696FF3434 34FF6E6E6EA80000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000A4A4A45B0404 03FF847A6EFFA29587FFA29587FFA29587FFA29587FFAFA498FFCFC9C2FFD2CC C4FFCEC7C0FFCBC2BBFFC7BEB6FFC2BAB1FFBFB6ADFFBBB2A8FFB8AEA3FFB4AA 9EFFB1A69AFFACA094FFA39789FFA29587FFA29587FFA29587FFA29587FF847A 6EFF040403FFA4A4A45B00000000000000000000000000000000B0B0B05B2727 27FF8B8B8BFFA4A4A4FFA4A4A4FFA4A4A4FFA4A4A4FFB1B1B1FFD0D0D0FFD2D2 D2FFCFCFCFFFCBCBCBFFC7C7C7FFC4C4C4FFC0C0C0FFBDBDBDFFB9B9B9FFB5B5 B5FFB2B2B2FFADADADFFA4A4A4FFA4A4A4FFA4A4A4FFA4A4A4FFA4A4A4FF8B8B 8BFF272727FFB0B0B05B00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000005C5C5CA30D0C 0BFF8C8176FFA5988BFFA5988BFFA5988BFFB8AEA4FFD8D3CDFFD6D0CAFFD2CC C4FFCEC7C0FFCBC2BBFFC7BEB6FFC2BAB1FFBFB6ADFFBBB2A8FFB8AEA3FFB4AA 9EFFB1A69AFFADA296FFA99D91FFA5998BFFA5988BFFA5988BFFA5988BFF8C81 76FF0D0C0BFF5C5C5CA300000000000000000000000000000000727272A32D2D 2DFF929292FFA6A6A6FFA6A6A6FFA6A6A6FFB9B9B9FFD9D9D9FFD6D6D6FFD2D2 D2FFCFCFCFFFCBCBCBFFC7C7C7FFC4C4C4FFC0C0C0FFBDBDBDFFB9B9B9FFB5B5 B5FFB2B2B2FFAFAFAFFFABABABFFA6A6A6FFA6A6A6FFA6A6A6FFA6A6A6FF9292 92FF2D2D2DFF727272A300000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000F9F9F9064B4B 4BB4110F0EFF8F847AFFA89C90FFB6ACA1FFDCD7D2FFD9D4CEFFD6D0CAFFD2CC C4FFCEC7C0FFCBC2BBFFC7BEB6FFC2BAB1FFBFB6ADFFBBB2A8FFB8AEA3FFB4AA 9EFFB1A69AFFADA296FFA99D91FFA6998CFFA79A8DFFA89C90FF8F847AFF110F 0EFF4B4B4BB4F9F9F90600000000000000000000000000000000F9F9F9066363 63B4303030FF959595FFAAAAAAFFB7B7B7FFDDDDDDFFDADADAFFD6D6D6FFD2D2 D2FFCFCFCFFFCBCBCBFFC7C7C7FFC4C4C4FFC0C0C0FFBDBDBDFFB9B9B9FFB5B5 B5FFB2B2B2FFAFAFAFFFABABABFFA7A7A7FFA8A8A8FFAAAAAAFF959595FF3030 30FF636363B4F9F9F90600000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000F9F9 F906252525DA393631FFAEA397FFDAD5D0FFDDD8D3FFD9D4CEFFD6D0CAFFD2CC C4FFCEC7C0FFC8BFB7FFBBB1A7FFB4AA9FFFB3A89DFFB5AA9FFFB7ACA2FFB4AA 9EFFB1A69AFFADA296FFA99D91FFA6998CFFA39689FFAB9F93FF393631FF2525 25DAF9F9F906000000000000000000000000000000000000000000000000F9F9 F906424242DA515151FFB0B0B0FFDBDBDBFFDDDDDDFFDADADAFFD6D6D6FFD2D2 D2FFCFCFCFFFC8C8C8FFBCBCBCFFB6B6B6FFB4B4B4FFB6B6B6FFB7B7B7FFB5B5 B5FFB2B2B2FFAFAFAFFFABABABFFA7A7A7FFA4A4A4FFACACACFF515151FF4242 42DAF9F9F9060000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000E2E2E21D98989867989898679393 936C040404FB827A71FFC8C0B8FFE0DCD8FFDDD8D3FFD9D4CEFFD6D0CAFFD2CC C4FFC1B9AFFFAFA498FF7D756DFF554F4AFF554F4AFF7D756DFFAEA397FFB2A7 9CFFB1A69AFFADA296FFA99D91FFA6998CFFA29587FFA79B8EFF827A71FF0404 04FB9393936C9898986798989867E2E2E21DE5E5E51DA6A6A667A6A6A667A1A1 A16C262626FB8C8C8CFFC9C9C9FFE1E1E1FFDDDDDDFFDADADAFFD6D6D6FFD2D2 D2FFC2C2C2FFB1B1B1FF888888FF676767FF676767FF888888FFB0B0B0FFB3B3 B3FFB2B2B2FFAFAFAFFFABABABFFA7A7A7FFA4A4A4FFA9A9A9FF8C8C8CFF2626 26FBA1A1A16CA6A6A667A6A6A667E5E5E51D0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000008F8F8F70070606FF1C1A18FF1C1A 18FF292724FFB2A79CFFDEDAD5FFE0DCD8FFDDD8D3FFD9D4CEFFD6D0CAFFC5BD B4FFA2988EFF282623FF070707F8404040BF404040BF070707F8282623FFA298 8EFFB1A69BFFADA296FFA99D91FFA6998CFFA29587FFA19485FFB1A79BFF2927 24FF1C1A18FF1C1A18FF070606FF8F8F8F709E9E9E70282828FF3A3A3AFF3A3A 3AFF454545FFB3B3B3FFDFDFDFFFE1E1E1FFDDDDDDFFDADADAFFD6D6D6FFC6C6 C6FFA6A6A6FF444444FF292929F85A5A5ABF5A5A5ABF292929F8444444FFA6A6 A6FFB2B2B2FFAFAFAFFFABABABFFA7A7A7FFA4A4A4FFA2A2A2FFB2B2B2FF4545 45FF3A3A3AFF3A3A3AFF282828FF9E9E9E700000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000005F5F5FA0423E3AFFB6ABA1FFB6AB A1FFB6ABA1FFBFB6ACFFE4E0DDFFE0DCD8FFDDD8D3FFD9D4CEFFD2CCC6FFB6AC A1FF292724FF343434CBE3E3E31C0000000000000000E3E3E31C343434CB2927 24FFB4AA9FFFAEA297FFA99D91FFA6998CFFA29587FF9F9183FFB1A69AFFB6AB A1FFB6ABA1FFB6ABA1FF423E3AFF5F5F5FA0747474A0595959FFB7B7B7FFB7B7 B7FFB7B7B7FFC0C0C0FFE4E4E4FFE1E1E1FFDDDDDDFFDADADAFFD3D3D3FFB7B7 B7FF454545FF4F4F4FCBE6E6E61C0000000000000000E6E6E61C4F4F4FCB4545 45FFB6B6B6FFAFAFAFFFABABABFFA7A7A7FFA4A4A4FFA0A0A0FFB2B2B2FFB7B7 B7FFB7B7B7FFB7B7B7FF595959FF747474A00000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000003F3F3FC05C5752FFB9AFA5FFB9AF A5FFB9AFA5FFCAC3BBFFE4E0DDFFE0DCD8FFDDD8D3FFD9D4CEFFC9C2BAFF857E 76FF070707F8E3E3E31C00000000000000000000000000000000E3E3E31C0707 07F8857E76FFB2A79CFFA99D91FFA6998CFFA29587FF9F9183FFAEA296FFB9AF A5FFB9AFA5FFB9AFA5FF5C5752FF3F3F3FC0595959C06E6E6EFFBABABAFFBABA BAFFBABABAFFCBCBCBFFE4E4E4FFE1E1E1FFDDDDDDFFDADADAFFCACACAFF9090 90FF292929F8E6E6E61C00000000000000000000000000000000E6E6E61C2929 29F8909090FFB3B3B3FFABABABFFA7A7A7FFA4A4A4FFA0A0A0FFAFAFAFFFBABA BAFFBABABAFFBABABAFF6E6E6EFF595959C00000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000303030CF69645FFFBCB3A9FFBCB3 A9FFBCB3A9FFD1CAC4FFE4E0DDFFE0DCD8FFDDD8D3FFD9D4CEFFC6BEB6FF5C57 53FF404040BF0000000000000000000000000000000000000000000000004040 40BF5C5753FFB6ACA2FFA99D91FFA6998CFFA29587FF9F9183FFADA195FFBCB3 A9FFBCB3A9FFBCB3A9FF69645FFF303030CF4C4C4CCF797979FFBDBDBDFFBDBD BDFFBDBDBDFFD1D1D1FFE4E4E4FFE1E1E1FFDDDDDDFFDADADAFFC7C7C7FF6E6E 6EFF5A5A5ABF0000000000000000000000000000000000000000000000005A5A 5ABF6E6E6EFFB7B7B7FFABABABFFA7A7A7FFA4A4A4FFA0A0A0FFAEAEAEFFBDBD BDFFBDBDBDFFBDBDBDFF797979FF4C4C4CCF0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000303030CF6C6762FFC0B7AEFFC0B7 AEFFC0B7AEFFD2CCC6FFE4E0DDFFE0DCD8FFDDD8D3FFD9D4CEFFC8C0B8FF5E59 55FF404040BF0000000000000000000000000000000000000000000000004040 40BF5E5955FFB8AFA4FFA99D91FFA6998CFFA29587FF9F9183FFAEA397FFC0B7 AEFFC0B7AEFFC0B7AEFF6B6661FF303030CF4C4C4CCF7C7C7CFFC1C1C1FFC1C1 C1FFC1C1C1FFD3D3D3FFE4E4E4FFE1E1E1FFDDDDDDFFDADADAFFC9C9C9FF7070 70FF5A5A5ABF0000000000000000000000000000000000000000000000005A5A 5ABF707070FFB9B9B9FFABABABFFA7A7A7FFA4A4A4FFA0A0A0FFB0B0B0FFC1C1 C1FFC1C1C1FFC1C1C1FF7B7B7BFF4C4C4CCF0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000003F3F3FC0615D59FFC3BBB2FFC3BB B2FFC3BBB2FFD1CAC4FFE4E0DDFFE0DCD8FFDDD8D3FFD9D4CEFFCEC7BFFF8C86 80FF070707F8E3E3E31C00000000000000000000000000000000E3E3E31C0707 07F88C8680FFB6ACA2FFA99D91FFA6998CFFA29587FF9F9183FFB4AA9EFFC3BB B2FFC3BBB2FFC3BBB2FF615D59FF3F3F3FC0595959C0737373FFC4C4C4FFC4C4 C4FFC4C4C4FFD1D1D1FFE4E4E4FFE1E1E1FFDDDDDDFFDADADAFFCFCFCFFF9797 97FF292929F8E6E6E61C00000000000000000000000000000000E6E6E61C2929 29F8979797FFB7B7B7FFABABABFFA7A7A7FFA4A4A4FFA0A0A0FFB5B5B5FFC4C4 C4FFC4C4C4FFC4C4C4FF737373FF595959C00000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000005F5F5FA0484542FFC7BFB7FFC7BF B7FFC7BFB7FFCDC6BEFFE4E0DDFFE0DCD8FFDDD8D3FFD9D4CEFFD4CEC8FFC6BE B6FF2D2B2AFF343434CBE3E3E31C0000000000000000E3E3E31C343434CB2D2B 2AFFC5BCB4FFAFA499FFA99D91FFA6998CFFA29587FF9F9183FFBFB5ACFFC7BF B7FFC7BFB7FFC7BFB7FF484542FF5F5F5FA0747474A05F5F5FFFC8C8C8FFC8C8 C8FFC8C8C8FFCECECEFFE4E4E4FFE1E1E1FFDDDDDDFFDADADAFFD5D5D5FFC7C7 C7FF484848FF4F4F4FCBE6E6E61C0000000000000000E6E6E61C4F4F4FCB4848 48FFC5C5C5FFB1B1B1FFABABABFFA7A7A7FFA4A4A4FFA0A0A0FFBFBFBFFFC8C8 C8FFC8C8C8FFC8C8C8FF5F5F5FFF747474A00000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000008F8F8F70080707FF1F1E1CFF1F1E 1CFF2E2C2BFFCAC2BAFFE1DDD9FFE0DCD8FFDDD8D3FFD9D4CEFFD6D0CAFFCFC8 C0FFB9B1AAFF2E2C2BFF070707F8404040BF404040BF070707F82E2C2BFFB9B1 AAFFBBB1A7FFADA296FFA99D91FFA6998CFFA29587FFA49789FFC9C1B9FF2E2C 2BFF1F1E1CFF1F1E1CFF080707FF8F8F8F709E9E9E70292929FF3D3D3DFF3D3D 3DFF494949FFCACACAFFE2E2E2FFE1E1E1FFDDDDDDFFDADADAFFD6D6D6FFD0D0 D0FFBCBCBCFF494949FF292929F85A5A5ABF5A5A5ABF292929F8494949FFBCBC BCFFBCBCBCFFAFAFAFFFABABABFFA7A7A7FFA4A4A4FFA5A5A5FFCACACAFF4949 49FF3D3D3DFF3D3D3DFF292929FF9E9E9E700000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000E2E2E21D98989867989898679393 936C040404FB99948EFFD8D3CDFFE0DCD8FFDDD8D3FFD9D4CEFFD6D0CAFFD2CC C4FFCEC7BFFFCDC6BEFF95908AFF65625EFF65625EFF95908AFFCCC5BDFFBFB5 ACFFB1A69AFFADA296FFA99D91FFA6998CFFA29587FFB8AEA3FF99948EFF0404 04FB9393936C9898986798989867E2E2E21DE5E5E51DA6A6A667A6A6A667A1A1 A16C262626FBA3A3A3FFD9D9D9FFE1E1E1FFDDDDDDFFDADADAFFD6D6D6FFD2D2 D2FFCFCFCFFFCECECEFF9F9F9FFF787878FF787878FF9F9F9FFFCDCDCDFFBFBF BFFFB2B2B2FFAFAFAFFFABABABFFA7A7A7FFA4A4A4FFB9B9B9FFA3A3A3FF2626 26FBA1A1A16CA6A6A667A6A6A667E5E5E51D0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000F9F9 F906252525DA464441FFD2CCC4FFDFDAD5FFDDD8D3FFD9D4CEFFD6D0CAFFD2CC C4FFCEC7C0FFCBC3BCFFCBC4BCFFCBC4BCFFCAC3BAFFC5BDB4FFBAB1A6FFB4AA 9EFFB1A69AFFADA296FFA99D91FFA6998CFFA89B8EFFCFC8C0FF464441FF2525 25DAF9F9F906000000000000000000000000000000000000000000000000F9F9 F906424242DA5E5E5EFFD2D2D2FFDFDFDFFFDDDDDDFFDADADAFFD6D6D6FFD2D2 D2FFCFCFCFFFCBCBCBFFCCCCCCFFCCCCCCFFCACACAFFC6C6C6FFBBBBBBFFB5B5 B5FFB2B2B2FFAFAFAFFFABABABFFA7A7A7FFA9A9A9FFD0D0D0FF5E5E5EFF4242 42DAF9F9F9060000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000F9F9F9064B4B 4BB4151514FFB5B0AAFFD5CFC9FFD8D2CCFFDDD8D3FFD9D4CEFFD6D0CAFFD2CC C4FFCEC7C0FFCBC2BBFFC7BEB6FFC2BAB1FFBFB6ADFFBBB2A8FFB8AEA3FFB4AA 9EFFB1A69AFFADA296FFA99D91FFA69A8DFFC8C1B8FFD5CFC9FFB5B0AAFF1515 14FF4B4B4BB4F9F9F90600000000000000000000000000000000F9F9F9066363 63B4353535FFBBBBBBFFD6D6D6FFD8D8D8FFDDDDDDFFDADADAFFD6D6D6FFD2D2 D2FFCFCFCFFFCBCBCBFFC7C7C7FFC4C4C4FFC0C0C0FFBDBDBDFFB9B9B9FFB5B5 B5FFB2B2B2FFAFAFAFFFABABABFFA8A8A8FFC9C9C9FFD6D6D6FFBBBBBBFF3535 35FF636363B4F9F9F90600000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000005C5C5CA31111 11FFB8B3AEFFD8D3CDFFD8D3CDFFD8D3CDFFDAD4CFFFD9D4CEFFD6D0CAFFD2CC C4FFCEC7C0FFCBC2BBFFC7BEB6FFC2BAB1FFBFB6ADFFBBB2A8FFB8AEA3FFB4AA 9EFFB1A69AFFADA296FFAA9E92FFC7BFB6FFD8D3CDFFD8D3CDFFD8D3CDFFB8B3 AEFF111111FF5C5C5CA300000000000000000000000000000000727272A33232 32FFBDBDBDFFD9D9D9FFD9D9D9FFD9D9D9FFDADADAFFDADADAFFD6D6D6FFD2D2 D2FFCFCFCFFFCBCBCBFFC7C7C7FFC4C4C4FFC0C0C0FFBDBDBDFFB9B9B9FFB5B5 B5FFB2B2B2FFAFAFAFFFABABABFFC8C8C8FFD9D9D9FFD9D9D9FFD9D9D9FFBDBD BDFF323232FF727272A300000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000A4A4A45B0606 06FFB3AFABFFDBD6D1FFDBD6D1FFDBD6D1FFDBD6D1FFDBD6D1FFD6D0CAFFD2CC C4FFCEC7C0FFCBC2BBFFC7BEB6FFC2BAB1FFBFB6ADFFBBB2A8FFB8AEA3FFB4AA 9EFFB1A69AFFB2A89CFFCFC8C1FFDBD6D1FFDBD6D1FFDBD6D1FFDBD6D1FFB3AF ABFF060606FFA4A4A45B00000000000000000000000000000000B0B0B05B2828 28FFBABABAFFDCDCDCFFDCDCDCFFDCDCDCFFDCDCDCFFDCDCDCFFD6D6D6FFD2D2 D2FFCFCFCFFFCBCBCBFFC7C7C7FFC4C4C4FFC0C0C0FFBDBDBDFFB9B9B9FFB5B5 B5FFB2B2B2FFB3B3B3FFD0D0D0FFDCDCDCFFDCDCDCFFDCDCDCFFDCDCDCFFBABA BAFF282828FFB0B0B05B00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000005757 57A81E1E1DFFCDC9C4FFDFDAD6FFDFDAD6FFDFDAD6FFDFDAD6FFDEDAD5FFD9D3 CDFFD0CAC2FFCBC2BBFFC7BEB6FFC2BAB1FFBFB6ADFFBBB2A8FFB8AEA3FFB9AF A5FFC9C1B9FFDCD8D3FFDFDAD6FFDFDAD6FFDFDAD6FFDFDAD6FFCDC9C4FF1E1E 1DFF575757A80000000000000000000000000000000000000000000000006E6E 6EA83D3D3DFFD0D0D0FFDFDFDFFFDFDFDFFFDFDFDFFFDFDFDFFFDFDFDFFFD9D9 D9FFD0D0D0FFCBCBCBFFC7C7C7FFC4C4C4FFC0C0C0FFBDBDBDFFB9B9B9FFBABA BAFFCACACAFFDDDDDDFFDFDFDFFFDFDFDFFFDFDFDFFFDFDFDFFFD0D0D0FF3D3D 3DFF6E6E6EA80000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000F4F4 F40B343434CB2A2A29FFD0CCC8FFE2DEDAFFE2DEDAFFC0BCB9FF4B4A49FFA8A5 A2FFE1DDD9FFDED9D4FFD8D2CDFFD3CDC7FFD2CBC5FFD4CEC7FFDAD5D0FFE1DD D9FFA8A5A2FF4B4A49FFC0BCB9FFE2DEDAFFE2DEDAFFD0CCC8FF2A2929FF3434 34CBF4F4F40B000000000000000000000000000000000000000000000000F5F5 F50B4F4F4FCB474747FFD3D3D3FFE3E3E3FFE3E3E3FFC5C5C5FF636363FFB1B1 B1FFE2E2E2FFDEDEDEFFD8D8D8FFD4D4D4FFD2D2D2FFD5D5D5FFDBDBDBFFE2E2 E2FFB1B1B1FF636363FFC5C5C5FFE3E3E3FFE3E3E3FFD3D3D3FF464646FF4F4F 4FCBF5F5F50B0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000ECECEC13343434CB1F1F1EFFBBB9B6FFC3C0BDFF171616FF252525DA0404 04FB353433FFE5E2DEFFE5E2DEFFE5E2DEFFE5E2DEFFE5E2DEFFE5E2DEFF3534 33FF040404FB252525DA171616FFC3C0BDFFBBB9B6FF1F1F1EFF343434CBECEC EC13000000000000000000000000000000000000000000000000000000000000 0000EEEEEE134F4F4FCB3E3E3EFFC3C3C3FFC9C9C9FF363636FF424242DA2626 26FB505050FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FFE6E6E6FF5050 50FF262626FB424242DA363636FFC9C9C9FFC3C3C3FF3E3E3EFF4F4F4FCBEEEE EE13000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000F4F4F40B575757A8060606FF131212FF4B4B4BB4F9F9F9069393 936C242323FFE9E6E3FFE9E6E3FFE9E6E3FFE9E6E3FFE9E6E3FFE9E6E3FF2423 23FF9393936CF9F9F9064B4B4BB4131212FF060606FF575757A8F4F4F40B0000 0000000000000000000000000000000000000000000000000000000000000000 000000000000F5F5F50B6E6E6EA8282828FF333333FF636363B4F9F9F906A1A1 A16C414141FFE9E9E9FFE9E9E9FFE9E9E9FFE9E9E9FFE9E9E9FFE9E9E9FF4141 41FFA1A1A16CF9F9F906636363B4333333FF282828FF6E6E6EA8F5F5F50B0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000A4A4A45B5C5C5CA3F9F9F906000000009898 9867242424FFECEAE7FFECEAE7FFECEAE7FFECEAE7FFECEAE7FFECEAE7FF2424 24FF9898986700000000F9F9F9065C5C5CA3A4A4A45B00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000B0B0B05B727272A3F9F9F90600000000A6A6 A667424242FFEDEDEDFFEDEDEDFFEDEDEDFFEDEDEDFFEDEDEDFFEDEDEDFF4242 42FFA6A6A66700000000F9F9F906727272A3B0B0B05B00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000009898 9867090909FF565555FF777675FF868583FF868583FF777675FF565555FF0909 09FF989898670000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000A6A6 A6672B2B2BFF6C6C6CFF898989FF969696FF969696FF898989FF6C6C6CFF2B2B 2BFFA6A6A6670000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000E2E2 E21D8F8F8F705F5F5FA03F3F3FC0303030CF303030CF3F3F3FC05F5F5FA08F8F 8F70E2E2E21D0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000E5E5 E51D9E9E9E70747474A0595959C04C4C4CCF4C4C4CCF595959C0747474A09E9E 9E70E5E5E51D0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000FDFDFD00DAE6D600C9DBC400CBDBC500DDE8DA00000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000FDFDFD00DEDEDE00CFCFCF00D0D0D000E1E1E100000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000E3E3E31CC5C5C53ACBCB CB34E8E8E817FEFEFE0100000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000E3E3E31CC5C5C53ACBCB CB34E8E8E817FEFEFE0100000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FEFEFD00D0E0CB0093B7 8700578F4600397B23003C7E27003E7F29003E7F29003C7D27003A7C25005E94 4D009DBD9300D6E4D20000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FDFDFD00D5D5D5009F9F 9F006A6A6A004F4F4F0052525200545454005454540052525200505050007070 7000A8A8A800DBDBDB0000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000DEDEF324A3A3 DF668787D5858484D4888484D4888484D4888484D4888484D4888484D4888484 D4889C9CDC6DDADAF22800000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000E3E3E324B1B1 B166999999859797978897979788979797889797978897979788979797889797 9788ABABAB6DDFDFDF2800000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000BABABC4857576DC043435CD45350 5DB989898976CFCFCF30FBFBFB04000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000BABABA485A5A5AC0474747D45353 53B989898976CFCFCF30FBFBFB04000000000000000000000000000000000000 0000FFFEFE01E1D2C73FE9DED62FFFFEFE010000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FEFEFE01FDFDFD02FDFDFD02FEFEFE010000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FEFEFE01D1D1D13FDDDDDD2FFEFEFE010000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FEFEFE01FDFDFD02FDFDFD02FEFEFE010000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000D9E5D600548E4200478533004684 3200468432004684320046843200468432004684320046843200468432004684 320046843200488534005F944E00E7EFE4000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000DDDDDD00686868005C5C5C005B5B 5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B 5B005B5B5B005C5C5C0071717100E9E9E9000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000006767DFAC2424 DDFA2828DFFF2828DFFF2828DFFF2828DFFF2828DFFF2828DFFF2828DFFF2828 DFFF2828DFFF5353E1C300000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000838383AC4E4E 4EFA4E4E4EFF4E4E4EFF4E4E4EFF4E4E4EFF4E4E4EFF4E4E4EFF4E4E4EFF4E4E 4EFF4E4E4EFF747474C300000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000CBC9CC373D4878E526508EFF255293FF2A45 83FF353656E66A6A6A96CBCBCB34FDFDFD020000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000CACACA374E4E4EE54D4D4DFF4F4F4FFF4848 48FF3C3C3CE66A6A6A96CBCBCB34FDFDFD02000000000000000000000000C6A8 947C9E6947DCA5714BF2A6734EEDA8795AC2FCFBFA0600000000000000000000 0000000000000000000000000000FBFBFB04F6F6F609F2F2F20DEFEFEF10ECEC EC13EAEAEA15E9E9E916E9E9E916EAEAEA15ECECEC13EFEFEF10F2F2F20DF6F6 F609FBFBFB04000000000000000000000000000000000000000000000000A6A6 A67C666666DC6C6C6CF26E6E6EED767676C2FAFAFA0600000000000000000000 0000000000000000000000000000FBFBFB04F6F6F609F2F2F20DEFEFEF10ECEC EC13EAEAEA15E9E9E916E9E9E916EAEAEA15ECECEC13EFEFEF10F2F2F20DF6F6 F609FBFBFB040000000000000000000000000000000000000000000000000000 00000000000000000000FCFDFC0086AE79003D7E270045843100468432004684 3200468432004684320046843200468432004684320046843200468432004684 320046843200468432004583310041812C0096B98B0000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000FCFCFC0093939300525252005A5A5A005B5B5B005B5B 5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B 5B005B5B5B005B5B5B005A5A5A0056565600A2A2A20000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000002F2FE0F0DDDD FAFF9B9BF0FF9090EFFF9090EFFF9090EFFF9090EFFF9090EFFF9090EFFF9090 EFFFE1E1FAFF2828DFFF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000565656F0E4E4 E4FFADADADFFA6A6A6FFA6A6A6FFA6A6A6FFA6A6A6FFA6A6A6FFA6A6A6FFA6A6 A6FFE8E8E8FF4E4E4EFF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000F5F5F50A5D5F81C10C52A8FF1357A6FF1B58A6FF175D B2FF2251A1FF353555E98181817EE4E4E41B0000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000F5F5F50A646464C14D4D4DFF505050FF535353FF5757 57FF515151FF3B3B3BE98181817EE4E4E41B0000000000000000C2A08A86A672 4BF1B0794EFF8D5A32FF8F5B33FFAA754DFBB68F74A000000000000000000000 000000000000FEFEFE01F8F8F807F2F2F20DEDEDED12E7E7E718E2E2E21DDDDD DD22D9D9D926D6D6D629D6D6D629D9D9D926D5D5D52CE2E2E21DE7E7E718EDED ED12F2F2F20DF7F7F708FDFDFD020000000000000000000000009E9E9E866D6D 6DF1747474FF555555FF565656FF707070FB8C8C8CA000000000000000000000 000000000000FEFEFE01F8F8F807F2F2F20DEDEDED12E7E7E718E2E2E21DDDDD DD22D9D9D926D6D6D629D6D6D629D9D9D926D5D5D52CE2E2E21DE7E7E718EDED ED12F2F2F20DF7F7F708FDFDFD02000000000000000000000000000000000000 000000000000F0F5EE00508A3D00458331004684320046843200468432004684 3200468432004684320046843200468432004684320046843200468432004684 32004684320046843200468432004684320045833100699B5900F9FBF9000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000F1F1F100636363005A5A5A005B5B5B005B5B5B005B5B5B005B5B 5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B 5B005B5B5B005B5B5B005B5B5B005B5B5B005A5A5A007A7A7A00FAFAFA000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000002F2FE0F09B9B F0FF3737E2FF2929E0FF2929E0FF2929E0FF2929E0FF2929E0FF2929E0FF2929 E0FF9494EFFF2828DFFF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000565656F0AFAF AFFF5A5A5AFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F4FFF4F4F 4FFFA7A7A7FF4E4E4EFF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000094919F79144594FF418CD4FF3B82CCFF0854B9FF115D C2FF0E65D2FF224DA1FF4E4C5ABFC9C9C9360000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000095959579464646FF7B7B7BFF747474FF515151FF5959 59FF5F5F5FFF505050FF4F4F4FBFC9C9C93600000000F1ECE61BA16E49E7AD73 47FFA46534FF8B552CFF774926FFA16A3FFFA26F4AE9ECE2DA29000000000000 000000000000FEFEFE01F8F8F807F3F3F30CEEEEEE11E8E8E817E4E4E41BDFDF DF20DBDBDB24D8D8D827ACAAAA676E6E6BDF7F7F7AEC6F6F6AD2BFBFBE4EEDED ED12F3F3F30CF8F8F807FEFEFE010000000000000000EBEBEB1B6A6A6AE76E6E 6EFF5F5F5FFF505050FF454545FF656565FF6B6B6BE9E1E1E129000000000000 000000000000FEFEFE01F8F8F807F3F3F30CEEEEEE11E8E8E817E4E4E41BDFDF DF20DBDBDB24D8D8D827AAAAAA676D6D6DDF7E7E7EEC6E6E6ED2BFBFBF4EEDED ED12F3F3F30CF8F8F807FEFEFE01000000000000000000000000000000000000 0000F4F8F300578F450045843100468432004684320046843200468432004684 31003E7E29003E7F29003E7F29003E7F29003E7F29003E7F2900468432004684 3200468432004684320046843200468432004684320043822F0064985400F9FB F900000000000000000000000000000000000000000000000000000000000000 0000F5F5F5006A6A6A005A5A5A005B5B5B005B5B5B005B5B5B005B5B5B005A5A 5A005353530054545400545454005454540054545400545454005B5B5B005B5B 5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005858580076767600FAFA FA00000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000002F2FE0F09E9E F1FF3B3BE2FF2F2FE0FF2F2FE0FF2F2FE0FF2F2FE0FF2F2FE0FF2F2FE0FF2F2F E0FF9696EFFF2828DFFF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000565656F0B0B0 B0FF5D5D5DFF535353FF535353FF535353FF535353FF535353FF535353FF5353 53FFA9A9A9FF4E4E4EFF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000DBDBDC243C4A80E41667BFFF7CB3E4FF92C5EEFF448DDFFF035E D7FF005EE2FF0B65E4FF444864D2CDCDCD320000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000DBDBDB24505050E45D5D5DFF9C9C9CFFABABABFF7F7F7FFF5C5C 5CFF5F5F5FFF646464FF4C4C4CD2CDCDCD3200000000C2A28D84AB774FFDA465 34FFA46534FFA16333FF7A4B27FF7F4F28FFAD794EFFA2714ED0FCFBFA060000 0000000000000000000000000000FDFDFD02F9F9F906F5F5F50AF1F1F10EEEEE EE11EDEDED12B4B4B35E898985F0C3C8C6FFA9AFADFFC8CDCBFF6F6F6AD2F9F9 F906FDFDFD0200000000000000000000000000000000A0A0A084727272FD5F5F 5FFF5F5F5FFF5D5D5DFF474747FF4A4A4AFF747474FF6D6D6DD0FAFAFA060000 0000000000000000000000000000FDFDFD02F9F9F906F5F5F50AF1F1F10EEEEE EE11EDEDED12B4B4B45E888888F0C7C7C7FFAEAEAEFFCCCCCCFF6E6E6ED2F9F9 F906FDFDFD02000000000000000000000000000000000000000000000000FDFD FC00639752004684320046843200468432004684320046843200468432004B88 3700C0D5BA00CADBC400CADBC400CADBC400CADBC400CBDCC5005F954E004583 30004684320046843200468432004684320046843200468432004684320085AD 780000000000000000000000000000000000000000000000000000000000FCFC FC00747474005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005F5F 5F00C7C7C700CFCFCF00CFCFCF00CFCFCF00CFCFCF00D0D0D000717171005959 59005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B009292 9200000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000002F2FE0F0A0A0 F1FF4242E3FF3434E1FF3434E1FF3434E1FF3434E1FF3434E1FF3434E1FF3434 E1FF9999F0FF2828DFFF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000565656F0B1B1 B1FF606060FF565656FF565656FF565656FF565656FF565656FF565656FF5656 56FFAAAAAAFF4E4E4EFF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000007A788D9D0B4DA2FF579FDFFF8FC1ECFFA3D0F4FFC9E7FCFFB4D4 FAFF5DA6FFFF2F67C6FF6D6B7CA1EFEFEF100000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000007C7C7C9D494949FF8A8A8AFFA9A9A9FFB5B5B5FFC9C9C9FFBDBD BDFF979797FF666666FF6F6F6FA1EFEFEF1000000000A2714FCEAF784DFFA465 34FFA46534FFA46534FF935A2EFF764926FF8C5931FFAA754DFAA97D5FBAFEFE FD02000000000000000000000000000000000000000000000000000000000000 0000C7C5C54B868682EEC1C7C5FF9EA3A1FFA3A7A5FFA8ADABFF80807DEBF2F2 F21000000000000000000000000000000000000000006D6D6DCE737373FF5F5F 5FFF5F5F5FFF5F5F5FFF555555FF454545FF545454FF707070FA7A7A7ABAFDFD FD02000000000000000000000000000000000000000000000000000000000000 0000C5C5C54B858585EEC6C6C6FFA2A2A2FFA6A6A6FFACACACFF7F7F7FEBF2F2 F210000000000000000000000000000000000000000000000000000000009EBE 930044822F004684320046843200468432004684320046843200468432004684 320062965100FDFDFD00F7F9F600F7F8F600F7F8F600F7F9F600EDF2EB005D94 4B00468432004684320046843200468432004684320046843200468432004181 2C00B0CAA900000000000000000000000000000000000000000000000000A8A8 A800585858005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B 5B0073737300FDFDFD00F7F7F700F7F7F700F7F7F700F7F7F700EEEEEE006F6F 6F005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005656 5600B9B9B9000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000002F2FE0F0A0A0 F1FF4747E4FF3B3BE2FF3B3BE2FF3B3BE2FF3B3BE2FF3B3BE2FF3B3BE2FF3B3B E2FF9B9BF0FF2828DFFF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000565656F0B2B2 B2FF646464FF5A5A5AFF5A5A5AFF5A5A5AFF5A5A5AFF5A5A5AFF5A5A5AFF5A5A 5AFFACACACFF4E4E4EFF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D2D1D331253F7EF42A7FCEFF84BDEBFF98CAF2FFAFD8F8FFD9EEFEFFFFFF FFFFCDD4E0FF585774D2D2D2D32D000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000D1D1D131444444F46E6E6EFFA3A3A3FFB0B0B0FFBCBCBCFFD0D0D0FFE1E1 E1FFBDBDBDFF5B5B5BD2D2D2D22D0000000000000000C3A38C85A7724CF5AD75 49FFA46535FFA46534FFA46534FF89542BFF764926FF956137FFA8754DF7B38B 6EA700000000000000000000000000000000000000000000000000000000CACA C846838380ECC0C5C3FFA9B0ADFFAFB5B2FF9CA19FFFBEC3C1FF797975CA0000 00000000000000000000000000000000000000000000A0A0A0856D6D6DF57070 70FF5F5F5FFF5F5F5FFF5F5F5FFF4F4F4FFF454545FF5C5C5CFF707070F78787 87A700000000000000000000000000000000000000000000000000000000C9C9 C946828282ECC4C4C4FFAFAFAFFFB4B4B4FFA0A0A0FFC2C2C2FF787878CA0000 0000000000000000000000000000000000000000000000000000E2ECDF003D7E 2800468432004684320046843200468432004684320046843200468432004684 320043822F0062965100EFF4EE00F6F8F500F6F8F500F6F8F500F6F8F500EFF4 EE00639751004584310046843200468432004684320046843200468432004684 32004B883800F3F7F20000000000000000000000000000000000E5E5E5005353 53005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B 5B005858580073737300F1F1F100F6F6F600F6F6F600F6F6F600F6F6F600F1F1 F100747474005A5A5A005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B 5B0060606000F4F4F40000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000002F2FE0F0A4A4 F1FF4C4CE5FF4242E3FF4242E3FF4242E3FF4242E3FF4242E3FF4242E3FF4242 E3FF9E9EF1FF2828DFFF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000565656F0B4B4 B4FF686868FF5E5E5EFF5E5E5EFF5E5E5EFF5E5E5EFF5E5E5EFF5E5E5EFF5E5E 5EFFAEAEAEFF4E4E4EFF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007777909E125CB2FF69AFE8FF93C6F1FFA5D3F7FFC5E4FDFFF1FEFFFFC2DA ECFF4B5279E9BCBCBE4300000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00007C7C7C9E555555FF979797FFACACACFFB8B8B8FFC8C8C8FFDDDDDDFFBFBF BFFF555555E9BCBCBC4300000000000000000000000000000000C2A08A869F6B 47E9AE794FFFA66939FFA46534FFA36534FF835029FF774926FF99643BFFA674 4DF4BC9981920000000000000000000000000000000000000000CECDCC417F7F 7CEBC2C8C5FFA1A7A4FFA7ADABFFA6ACAAFFC2C8C5FF898A85ECDBD9D92F0000 00000000000000000000000000000000000000000000000000009E9E9E866868 68E9747474FF636363FF5F5F5FFF5F5F5FFF4B4B4BFF454545FF5F5F5FFF6F6F 6FF4969696920000000000000000000000000000000000000000CCCCCC417E7E 7EEBC7C7C7FFA6A6A6FFACACACFFABABABFFC7C7C7FF898989ECD9D9D92F0000 00000000000000000000000000000000000000000000000000008CB380004684 3200468432004684320046843200468432004684320046843200468432004684 3200468432004684320062965100FBFBFA00F6F8F500F6F8F500F6F8F500F6F8 F500ECF2EA00508B3E0046843200468432004684320046843200468432004684 320045833100B2CCAA0000000000000000000000000000000000999999005B5B 5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B 5B005B5B5B005B5B5B0073737300FAFAFA00F6F6F600F6F6F600F6F6F600F6F6 F600EEEEEE00646464005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B 5B005A5A5A00BBBBBB0000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000002F2FE0F0A5A5 F2FF5151E6FF4747E4FF4747E4FF4747E4FF4747E4FF4747E4FF4747E4FF4747 E4FFA0A0F1FF2828DFFF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000565656F0B5B5 B5FF6C6C6CFF626262FF626262FF626262FF626262FF626262FF626262FF6262 62FFB0B0B0FF4E4E4EFF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000D3D3 D32D2E4683EC4194DDFF8BC3F0FF9BCEF5FFB7DDFCFFE9FAFFFFB3DCF4FF4452 85F8A4A3AA5D0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000D3D3 D32D4B4B4BEC808080FFA9A9A9FFB2B2B2FFC1C1C1FFD9D9D9FFBDBDBDFF5353 53F8A6A6A65D000000000000000000000000000000000000000000000000EADF D92BA16F4DD4AB7751F6AA6F42FFA46534FFA16333FF804F29FF774926FF9965 3DFFA7724EF0C7A9947A000000000000000000000000D1D1CF3C7C7C76EBC3C8 C6FFA1A7A5FFAEB5B2FFA0A7A4FFBBC1BEFF91918FEEC1C0BE54000000000000 000000000000000000000000000000000000000000000000000000000000DFDF DF2B6B6B6BD4737373F66A6A6AFF5F5F5FFF5D5D5DFF4A4A4AFF454545FF6060 60FF6F6F6FF0A7A7A77A000000000000000000000000D0D0D03C7B7B7BEBC7C7 C7FFA6A6A6FFB4B4B4FFA6A6A6FFC0C0C0FF909090EEBFBFBF54000000000000 0000000000000000000000000000000000000000000000000000498636004684 3200468432004684320046843200468432004684320046843200468432004684 3200468432004684320043822F006A9C5B00F8F9F700F6F8F500F6F8F500F6F8 F500F7F9F700ECF1E9005F954E00468432004684320046843200468432004684 3200468432004C883A00000000000000000000000000000000005E5E5E005B5B 5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B 5B005B5B5B005B5B5B00585858007B7B7B00F8F8F800F6F6F600F6F6F600F6F6 F600F8F8F800EDEDED00717171005B5B5B005B5B5B005B5B5B005B5B5B005B5B 5B005B5B5B0061616100000000000000000000000000DADAF2289C9CDC6D8484 D4888484D4888484D4888484D4888484D4888484D4888484D4882727DFF7A9A9 F2FF5858E7FF4E4EE5FF4E4EE5FF4E4EE5FF4E4EE5FF4E4EE5FF4E4EE5FF4E4E E5FFA7A7F2FF2828DFFF8484D4888484D4888484D4888484D4888484D4888484 D4888484D4889C9CDC6DDADAF2280000000000000000DFDFDF28ABABAB6D9797 9788979797889797978897979788979797889797978897979788515151F7B6B6 B6FF707070FF676767FF676767FF676767FF676767FF676767FF676767FF6767 67FFB3B3B3FF4E4E4EFF97979788979797889797978897979788979797889797 978897979788ABABAB6DDFDFDF28000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000007171 8AA32069B8FF78BCF2FF94CAF4FFADD8FBFFDCF3FFFFA7D8F8FF415B8FFA9592 9D71FEFEFE010000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000007676 76A35F5F5FFFA2A2A2FFAFAFAFFFBCBCBCFFD3D3D3FFB9B9B9FF595959FA9595 9571FEFEFE010000000000000000000000000000000000000000000000000000 0000FEFDFC03BA967D96A8744FF1AA7042FFA46534FFA16333FF804F29FF7749 26FF9C683FFFA26E48EDDFD0C64200000000D3D3D138787874EAC3C8C5FFA1A8 A5FFAEB4B1FFA1A7A4FFBAC0BEFF999A95F0B4B4B26500000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000FCFCFC0393939396707070F16A6A6AFF5F5F5FFF5D5D5DFF4A4A4AFF4545 45FF636363FF6A6A6AEDCFCFCF4200000000D3D3D338777777EAC7C7C7FFA7A7 A7FFB3B3B3FFA6A6A6FFBFBFBFFF999999F0B4B4B46500000000000000000000 00000000000000000000000000000000000000000000BDD3B6003F7F2A004684 3200468432004684320046843200468432004684320046843200468432004684 32004684320046843200468432004483300065995500F5F7F400F6F8F500F6F8 F500F6F8F500F6F8F500EAF0E800508B3D004584310046843200468432004684 3200468432003F7F2A00CFDFCA000000000000000000C4C4C400545454005B5B 5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B 5B005B5B5B005B5B5B005B5B5B005959590077777700F5F5F500F6F6F600F6F6 F600F6F6F600F6F6F600ECECEC00646464005A5A5A005B5B5B005B5B5B005B5B 5B005B5B5B0054545400D4D4D40000000000000000005353E1C32828DFFF2828 DFFF2828DFFF2828DFFF2828DFFF2828DFFF2828DFFF2828DFFF2828DFFF9696 EFFF5E5EE7FF5757E6FF5757E6FF5757E6FF5757E6FF5757E6FF5757E6FF5757 E6FF9696EFFF2828DFFF2828DFFF2828DFFF2828DFFF2828DFFF2828DFFF2828 DFFF2828DFFF2828DFFF5353E1C30000000000000000747474C34E4E4EFF4E4E 4EFF4E4E4EFF4E4E4EFF4E4E4EFF4E4E4EFF4E4E4EFF4E4E4EFF4E4E4EFFA4A4 A4FF727272FF6C6C6CFF6C6C6CFF6C6C6CFF6C6C6CFF6C6C6CFF6C6C6CFF6C6C 6CFFA3A3A3FF4E4E4EFF4E4E4EFF4E4E4EFF4E4E4EFF4E4E4EFF4E4E4EFF4E4E 4EFF4E4E4EFF4E4E4EFF747474C3000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000B5B4B94F1D45 8AFE53A5E8FF90C8F6FFA3D4FAFFD0EEFFFF92D1F9FF385B96FF8A879480F9F9 F906000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000B5B5B54F4646 46FE8D8D8DFFAEAEAEFFB8B8B8FFCFCFCFFFB2B2B2FF575757FF8B8B8B80F9F9 F906000000000000000000000000000000000000000000000000000000000000 00000000000000000000BB987E94A7754FF2AA6F41FFA46534FFA16333FF8350 29FF8C562CFFAF784EFF9F6D48D8D6D6D434757471E9C3C8C6FFA2A8A5FFADB4 B1FFA1A7A4FFB8BEBBFFA0A19EF2A9A9A5770000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000095959594707070F2696969FF5F5F5FFF5D5D5DFF4B4B 4BFF515151FF737373FF696969D8D5D5D534737373E9C7C7C7FFA7A7A7FFB3B3 B3FFA6A6A6FFBDBDBDFFA1A1A1F2A8A8A8770000000000000000000000000000 0000000000000000000000000000000000000000000072A16300448330004684 3200468432004483300044833000448330004483300044833000448330004483 30004483300044833000448330004583300043822F006D9E5D00FEFDFD00F6F8 F500F6F8F500F6F8F500F7F9F700E7EEE400548D410046843200468432004684 3200468432004483300095B88900000000000000000082828200595959005B5B 5B005B5B5B005959590059595900595959005959590059595900595959005959 590059595900595959005959590059595900585858007D7D7D00FDFDFD00F6F6 F600F6F6F600F6F6F600F8F8F800E9E9E900676767005B5B5B005B5B5B005B5B 5B005B5B5B0059595900A0A0A00000000000000000002828DFFFE8E8FBFFACAC F3FFACACF3FFACACF3FFACACF3FFACACF3FFACACF3FFACACF3FF9B9BF0FF7676 EBFF6161E8FF5E5EE7FF5E5EE7FF5E5EE7FF5E5EE7FF5E5EE7FF5E5EE7FF5E5E E7FF7373EAFF9B9BF0FFACACF3FFACACF3FFACACF3FFACACF3FFACACF3FFACAC F3FFACACF3FFE8E8FBFF2828DFFF00000000000000004E4E4EFFECECECFFB7B7 B7FFB7B7B7FFB7B7B7FFB7B7B7FFB7B7B7FFB7B7B7FFB7B7B7FFA8A8A8FF8686 86FF737373FF717171FF717171FF717171FF717171FF717171FF717171FF7171 71FF838383FFA6A6A6FFB7B7B7FFB7B7B7FFB7B7B7FFB7B7B7FFB7B7B7FFB7B7 B7FFB7B7B7FFECECECFF4E4E4EFF000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000DFDFDF21444D79D82983 D3FF83C3F6FF9BCFF9FFC4E9FFFF74C4FAFF28579AFF83808C88F8F8F8070000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000DFDFDF21535353D87171 71FFA9A9A9FFB4B4B4FFC9C9C9FFA5A5A5FF535353FF83838388F8F8F8070000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000B8947B99A8744EF3A96E40FFA46534FFA465 34FFA46534FFAE764AFF986541E671716DE8C3C8C6FFA2A8A6FFADB4B1FFA1A8 A5FFB7BDBAFFA7A9A6F49D9B998A000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000091919199707070F3686868FF5F5F5FFF5F5F 5FFF5F5F5FFF717171FF626262E6717171E8C7C7C7FFA7A7A7FFB3B3B3FFA7A7 A7FFBCBCBCFFA8A8A8F49B9B9B8A000000000000000000000000000000000000 000000000000000000000000000000000000000000004E8A3B00468432004684 3200518B3E0089B07C0085AE780085AE780085AE780085AE780085AE780085AE 780085AE780085AE780085AE780085AE780085AE780081AB7300AAC6A100F8F9 F700F6F8F500F6F8F500F6F8F500F7F8F600E7EEE500548E4200468432004684 3200468432004684320075A367000000000000000000626262005B5B5B005B5B 5B00646464009696960093939300939393009393930093939300939393009393 930093939300939393009393930093939300939393008F8F8F00B3B3B300F8F8 F800F6F6F600F6F6F600F6F6F600F7F7F700E9E9E900686868005B5B5B005B5B 5B005B5B5B005B5B5B008585850000000000000000002828DFFFB0B0F3FF6666 E9FF6666E9FF6666E9FF6666E9FF6666E9FF6666E9FF6666E9FF6666E9FF6666 E9FF6666E9FF6666E9FF6666E9FF6666E9FF6666E9FF6666E9FF6666E9FF6666 E9FF6666E9FF6666E9FF6666E9FF6666E9FF6666E9FF6666E9FF6666E9FF6666 E9FF6666E9FFB0B0F3FF2828DFFF00000000000000004E4E4EFFBABABAFF7676 76FF767676FF767676FF767676FF767676FF767676FF767676FF767676FF7676 76FF767676FF767676FF767676FF767676FF767676FF767676FF767676FF7676 76FF767676FF767676FF767676FF767676FF767676FF767676FF767676FF7676 76FF767676FFBABABAFF4E4E4EFF000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000F7F7F7086E6C83AA105EB1FF64B6 F4FF92CCF8FFBFE5FFFF67BDF8FF164C95FF807E8B8DF6F6F609000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000F7F7F708717171AA555555FF9B9B 9BFFB0B0B0FFC7C7C7FF9F9F9FFF484848FF8181818DF6F6F609000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000B992799CA9754FF3AF784CFFC49B 7CFFAA7042FFA9754FFF835C3FFEABAFACFFA3AAA7FFACB3B0FFA2A8A5FFB4BB B8FFACAFACF7908E8B9D00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000009090909C717171F3737373FF9797 97FF6A6A6AFF717171FF595959FEAEAEAEFFA9A9A9FFB2B2B2FFA7A7A7FFBABA BAFFAEAEAEF78E8E8E9D00000000000000000000000000000000000000000000 000000000000000000000000000000000000F4F8F3004E893B00468432004684 32006598540000000000F7F9F600F7F9F600F7F9F600F7F9F600F7F9F600F7F9 F600F7F9F600F7F9F600F7F9F600F7F9F600F7F9F600F7F9F600F7F8F600F6F8 F500F6F8F500F6F8F500F6F8F500F6F8F500F7F8F600E4ECE100488635004684 320046843200468432006A9B5A00FEFFFE00F5F5F500626262005B5B5B005B5B 5B007676760000000000F7F7F700F7F7F700F7F7F700F7F7F700F7F7F700F7F7 F700F7F7F700F7F7F700F7F7F700F7F7F700F7F7F700F7F7F700F7F7F700F6F6 F600F6F6F600F6F6F600F6F6F600F6F6F600F7F7F700E6E6E6005D5D5D005B5B 5B005B5B5B005B5B5B007A7A7A00FEFEFE00000000002828DFFFB5B5F4FF6D6D EAFF6D6DEAFF6D6DEAFF6D6DEAFF6D6DEAFF6D6DEAFF6D6DEAFF6D6DEAFF6D6D EAFF6D6DEAFF6D6DEAFF6D6DEAFF6D6DEAFF6D6DEAFF6D6DEAFF6D6DEAFF6D6D EAFF6D6DEAFF6D6DEAFF6D6DEAFF6D6DEAFF6D6DEAFF6D6DEAFF6D6DEAFF6D6D EAFF6D6DEAFFB5B5F4FF2828DFFF00000000000000004E4E4EFFBDBDBDFF7B7B 7BFF7B7B7BFF7B7B7BFF7B7B7BFF7B7B7BFF7B7B7BFF7B7B7BFF7B7B7BFF7B7B 7BFF7B7B7BFF7B7B7BFF7B7B7BFF7B7B7BFF7B7B7BFF7B7B7BFF7B7B7BFF7B7B 7BFF7B7B7BFF7B7B7BFF7B7B7BFF7B7B7BFF7B7B7BFF7B7B7BFF7B7B7BFF7B7B 7BFF7B7B7BFFBDBDBDFF4E4E4EFF000000000000000000000000000000000000 000000000000FBFBFB04EBEBEB14F1F1F10E0000000000000000000000000000 0000000000000000000000000000FBFBFB0487829088154C99FF339BEDFF8AC8 F9FFABDAFEFFA0DCFFFF185CA9FF726E7D9AF3F3F30C00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000FBFBFB04EBEBEB14F1F1F10E0000000000000000000000000000 0000000000000000000000000000FBFBFB0486868688494949FF838383FFADAD ADFFBDBDBDFFBBBBBBFF545454FF7272729AF3F3F30C00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000C2A48D83A26F4BE7B88A 69FF9C6942FA9E7659FFE0E3E1FF797975FF989E9AFFA2A8A6FFB3BAB7FFB2B4 B2F9868682AD0000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000A1A1A1836C6C6CE78686 86FF656565FA737373FFE2E2E2FF787878FF9D9D9DFFA7A7A7FFB9B9B9FFB3B3 B3F9858585AD0000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000F0F5EE004D883900468432004684 320065985300FFFEFF00F6F8F500F6F8F500F6F8F500F6F8F500F6F8F500F6F8 F500F6F8F500F6F8F500F6F8F500F6F8F500F6F8F500F6F8F500F6F8F500F6F8 F500F6F8F500F6F8F500F6F8F500F6F8F500F6F8F500F8F9F700E5EDE300558E 4300468432004684320064985300FEFEFE00F1F1F100606060005B5B5B005B5B 5B0075757500FEFEFE00F6F6F600F6F6F600F6F6F600F6F6F600F6F6F600F6F6 F600F6F6F600F6F6F600F6F6F600F6F6F600F6F6F600F6F6F600F6F6F600F6F6 F600F6F6F600F6F6F600F6F6F600F6F6F600F6F6F600F8F8F800E8E8E8006868 68005B5B5B005B5B5B0075757500FEFEFE00000000002828DFFFB9B9F4FF7878 EBFF7878EBFF7878EBFF7878EBFF7878EBFF7878EBFF7878EBFF7878EBFF7878 EBFF7878EBFF7878EBFF7878EBFF7878EBFF7878EBFF7878EBFF7878EBFF7878 EBFF7878EBFF7878EBFF7878EBFF7878EBFF7878EBFF7878EBFF7878EBFF7878 EBFF7878EBFFB9B9F4FF2828DFFF00000000000000004E4E4EFFBFBFBFFF8181 81FF818181FF818181FF818181FF818181FF818181FF818181FF818181FF8181 81FF818181FF818181FF818181FF818181FF818181FF818181FF818181FF8181 81FF818181FF818181FF818181FF818181FF818181FF818181FF818181FF8181 81FF818181FFBFBFBFFF4E4E4EFF000000000000000000000000000000000000 0000ECECEC139898986D707072979D9D9D62E3E3E31C00000000000000000000 000000000000000000000000000095939C751D4487FB218DE5FF7CC2F8FF98D1 FCFFC1EBFFFF398ED6FF41496DD2D8D8D8270000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000ECECEC139797976D707070979D9D9D62E3E3E31C00000000000000000000 000000000000000000000000000095959575444444FB767676FFA7A7A7FFB4B4 B4FFC9C9C9FF7A7A7AFF4E4E4ED2D8D8D8270000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000F2EBE61CBCA3 917F6F6458E96D6D68FFC8CCC8FFDFE3E1FF777873FF9EA39FFFB7BAB7FB7F7F 7ABAFDFDFD020000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000EAEAEA1CA1A1 A17F626262E96C6C6CFFCBCBCBFFE2E2E2FF777777FFA2A2A2FFB9B9B9FB7E7E 7EBAFDFDFD020000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000F0F5EF004D883A00468432004684 320065985300FFFEFF00F6F8F500F6F8F500F6F8F500F6F8F500F6F8F500F6F8 F500F6F8F500F6F8F500F6F8F500F6F8F500F6F8F500F6F8F500F6F8F500F6F8 F500F6F8F500F6F8F500F6F8F500F6F8F500F6F8F500F7F9F600D2E1CD004382 2F00468432004684320065985500FEFFFE00F2F2F200616161005B5B5B005B5B 5B0075757500FEFEFE00F6F6F600F6F6F600F6F6F600F6F6F600F6F6F600F6F6 F600F6F6F600F6F6F600F6F6F600F6F6F600F6F6F600F6F6F600F6F6F600F6F6 F600F6F6F600F6F6F600F6F6F600F6F6F600F6F6F600F7F7F700D7D7D7005858 58005B5B5B005B5B5B0076767600FEFEFE00000000002828DFFFBCBCF5FF7F7F ECFF7F7FECFF7F7FECFF8686EDFF8D8DEEFF9090EFFF9696EFFF9B9BF0FF9E9E F1FFA0A0F1FFA2A2F1FFA4A4F1FFA7A7F2FFA4A4F1FFA2A2F1FFA0A0F1FF9E9E F1FF9B9BF0FF9696EFFF9090EFFF8D8DEEFF8686EDFF7F7FECFF7F7FECFF7F7F ECFF7F7FECFFBCBCF5FF2828DFFF00000000000000004E4E4EFFC2C2C2FF8686 86FF868686FF868686FF8C8C8CFF919191FF979797FF9B9B9BFF9F9F9FFFA3A3 A3FFA6A6A6FFA8A8A8FFA9A9A9FFAAAAAAFFA9A9A9FFA8A8A8FFA6A6A6FFA3A3 A3FF9F9F9FFF9B9B9BFF979797FF919191FF8C8C8CFF868686FF868686FF8686 86FF868686FFC2C2C2FF4E4E4EFF00000000000000000000000000000000E9E9 E916707070AB686665FE605F5EFF494949CE9C9C9C63F0F0F00F000000000000 000000000000FBFBFB049D98A06C24437FF81B84DCFF6EBCF8FF8CCBFBFFB6E3 FFFF78C4F8FF20437FF8A4A2A75F000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000E9E9 E9166C6C6CAB5A5A5AFE545454FF464646CE9C9C9C63F0F0F00F000000000000 000000000000FBFBFB049B9B9B6C454545F86F6F6FFFA1A1A1FFAFAFAFFFC3C3 C3FFA6A6A6FF444444F8A4A4A45F000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000FDFDFD03FDFDFD030000000000000000E4E4E3226868 64E3C3C7C5FFA4AAA7FF656661FFCBCFCDFFDEE2E0FF787874FF6D6C68CFFBFB FB05000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000FDFDFD03FDFDFD030000000000000000E3E3E3226767 67E3C6C6C6FFA9A9A9FF656565FFCECECEFFE1E1E1FF777777FF6C6C6CCFFBFB FB05000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000F7F9F6004E893B00468432004684 32006699550000000000FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFE FF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FFFEFF00FDFCFC00F6F8 F500F6F8F500F6F8F500F6F8F500F6F8F500F9FAF900C9DAC300468432004684 320046843200468432006D9E5D00FFFFFE00F7F7F700626262005B5B5B005B5B 5B007777770000000000FEFEFE00FEFEFE00FEFEFE00FEFEFE00FEFEFE00FEFE FE00FEFEFE00FEFEFE00FEFEFE00FEFEFE00FEFEFE00FEFEFE00FCFCFC00F6F6 F600F6F6F600F6F6F600F6F6F600F6F6F600F9F9F900CECECE005B5B5B005B5B 5B005B5B5B005B5B5B007D7D7D00FEFEFE00000000002828DFFFC5C5F6FF9696 EFFF9D9DF0FFA5A5F2FFABABF2FFABABF2FFABABF2FFABABF2FFABABF2FFABAB F2FFABABF2FFABABF2FFABABF2FFABABF2FFABABF2FFABABF2FFABABF2FFABAB F2FFABABF2FFABABF2FFABABF2FFABABF2FFABABF2FFA5A5F2FF9D9DF0FF9696 EFFF8D8DEEFFC1C1F6FF2828DFFF00000000000000004E4E4EFFC8C8C8FF9999 99FFA1A1A1FFA8A8A8FFAEAEAEFFAEAEAEFFAEAEAEFFAEAEAEFFAEAEAEFFAEAE AEFFAEAEAEFFAEAEAEFFAEAEAEFFAEAEAEFFAEAEAEFFAEAEAEFFAEAEAEFFAEAE AEFFAEAEAEFFAEAEAEFFAEAEAEFFAEAEAEFFAEAEAEFFA8A8A8FFA1A1A1FF9999 99FF919191FFC5C5C5FF4E4E4EFF000000000000000000000000F9F9F9067777 77A28F8B8AFFC3BEBAFFA5A19EFF5A5959FF525252B6BDBDBD42FDFDFD020000 0000FDFDFD02918F9979244380F81D84DCFF67B8F7FF85C8FAFFA2D8FFFFA7E0 FFFF2265AFFF706D7C9BF4F4F40B000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000F9F9F9067373 73A27C7C7CFFA8A8A8FF8E8E8EFF4F4F4FFF515151B6BDBDBD42FDFDFD020000 0000FDFDFD0292929279454545F8707070FF9D9D9DFFABABABFFBABABAFFBEBE BEFF5B5B5BFF7171719BF4F4F40B000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000DCDBD92D8A8886A26A6A65E27D7D7AE2777773CC9999968A666563E2C2C6 C4FFA6ACAAFFAAB1AEFFA0A7A4FF666762FFCFD2D0FFDDE1DEFF7C7C78E7E1E1 E025000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000DADADA2D888888A2696969E27C7C7CE2767676CC9898988A646464E2C5C5 C5FFABABABFFB0B0B0FFA6A6A6FF666666FFD1D1D1FFE0E0E0FF7B7B7BE7E1E1 E125000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000538D4100468432004684 32004B8838006598540063975300639753006397530063975300639753006397 5300639753006397530063975300639753006397530061965000A3C29900F8F9 F700F6F8F500F6F8F500F6F8F500F7F8F600D1E0CC003E7F2A00468432004684 320046843200468432007CA86E000000000000000000676767005B5B5B005B5B 5B00606060007676760075757500757575007575750075757500757575007575 7500757575007575750075757500757575007575750073737300ADADAD00F8F8 F800F6F6F600F6F6F600F6F6F600F7F7F700D6D6D600545454005B5B5B005B5B 5B005B5B5B005B5B5B008B8B8B0000000000000000002828DFFFD5D5F8FFB0B0 F3FFB0B0F3FFB0B0F3FFB0B0F3FFB0B0F3FFB0B0F3FFB0B0F3FFB0B0F3FFB0B0 F3FFB0B0F3FFB0B0F3FFB0B0F3FFB0B0F3FFB0B0F3FFB0B0F3FFB0B0F3FFB0B0 F3FFB0B0F3FFB0B0F3FFB0B0F3FFB0B0F3FFB0B0F3FFB0B0F3FFB0B0F3FFB0B0 F3FFB0B0F3FFCFCFF8FF2828DFFF00000000000000004E4E4EFFD7D7D7FFB2B2 B2FFB2B2B2FFB2B2B2FFB2B2B2FFB2B2B2FFB2B2B2FFB2B2B2FFB2B2B2FFB2B2 B2FFB2B2B2FFB2B2B2FFB2B2B2FFB2B2B2FFB2B2B2FFB2B2B2FFB2B2B2FFB2B2 B2FFB2B2B2FFB2B2B2FFB2B2B2FFB2B2B2FFB2B2B2FFB2B2B2FFB2B2B2FFB2B2 B2FFAFAFAFFFD3D3D3FF4E4E4EFF000000000000000000000000B1B1B1557571 71FFE2DCDAFFCCC5C3FFB1ABA8FF979695FF484848F17575758AD8D8D827FCFC FC039D9BA36C1E4488FD1C84DCFF5EB4F6FF7BC3FAFF8FCEFFFFB9E7FFFF469A DEFF3A426DDBD0D0D02F00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000B0B0B0556565 65FFC3C3C3FFB0B0B0FF989898FF848484FF414141F17575758AD8D8D827FCFC FC039D9D9D6C454545FD707070FF999999FFA7A7A7FFB2B2B2FFC6C6C6FF8484 84FF484848DBD0D0D02F00000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000C8C8 C747757572EBBDC0BEFFC7CCCAFFC2C8C5FFC7CCCAFFB9BCB9FFC3C7C5FFAAB0 AEFFA9B0ADFFA4AAA7FFAEB5B2FFBCBFBCFF5A5954F7D1D5D2FEDCE0DDFF7C7C 76E6E3E3E2230000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000C8C8 C847747474EBBFBFBFFFCBCBCBFFC7C7C7FFCBCBCBFFBBBBBBFFC6C6C6FFAFAF AFFFAFAFAFFFA9A9A9FFB4B4B4FFBEBEBEFF585858F7D4D4D4FEDFDFDFFF7B7B 7BE6E2E2E2230000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000085AF790043822E004684 3200468432004583310045833100458331004583310045833100458331004583 31004583310045833100458331004583310042822E0096B98B00F7F9F600F6F8 F500F6F8F500F6F8F500F9FAF800D7E4D3004A87370046843200468432004684 32004684320043822E00A5C39B00000000000000000094949400585858005B5B 5B005B5B5B005A5A5A005A5A5A005A5A5A005A5A5A005A5A5A005A5A5A005A5A 5A005A5A5A005A5A5A005A5A5A005A5A5A0058585800A2A2A200F7F7F700F6F6 F600F6F6F600F6F6F600F9F9F900DBDBDB005F5F5F005B5B5B005B5B5B005B5B 5B005B5B5B0058585800AFAFAF0000000000000000002828DFFFD8D8F9FFB5B5 F4FFB5B5F4FFB5B5F4FFB5B5F4FFB5B5F4FFB5B5F4FFB5B5F4FFB5B5F4FFB5B5 F4FFB5B5F4FFB5B5F4FFB5B5F4FFB5B5F4FFB5B5F4FFB5B5F4FFB5B5F4FFB5B5 F4FFB5B5F4FFB5B5F4FFB5B5F4FFB5B5F4FFB5B5F4FFB5B5F4FFB5B5F4FFB5B5 F4FFB5B5F4FFD8D8F9FF2828DFFF00000000000000004E4E4EFFDADADAFFB5B5 B5FFB5B5B5FFB5B5B5FFB5B5B5FFB5B5B5FFB5B5B5FFB5B5B5FFB5B5B5FFB5B5 B5FFB5B5B5FFB5B5B5FFB5B5B5FFB5B5B5FFB5B5B5FFB5B5B5FFB5B5B5FFB5B5 B5FFB5B5B5FFB5B5B5FFB5B5B5FFB5B5B5FFB5B5B5FFB5B5B5FFB5B5B5FFB5B5 B5FFB5B5B5FFDADADAFF4E4E4EFF0000000000000000000000006D6A6AC7DFD9 D9FFF0EAEAFFC3BCBCFFB7B6B6FFB7B8B7FF7E7E7DFF424242DC7A7A7A858583 82894E4D66F41671BDFF43AAFBFF78C1FAFF86CAFEFFAEDEFFFF7DC8FBFF2045 82F99F9CA0660000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000656565C7C1C1 C1FFD0D0D0FFA8A8A8FFA1A1A1FFA2A2A2FF6F6F6FFF3F3F3FDC7A7A7A858282 82894D4D4DF45F5F5FFF909090FFA6A6A6FFAEAEAEFFC0C0C0FFAAAAAAFF4444 44F99D9D9D660000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000E3E3E2237979 77E7C7CCCAFFB7BEBBFFB6BDBAFFB6BDBAFFB6BDBAFFB7BEBBFFB8BFBCFFA9AF ACFF9EA4A1FFACB3B0FFC3C8C5FF73736EDCE5E5E51F767570D1D4D8D5FEDBDF DCFF7A7A75E5E4E4E32100000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000E2E2E2237878 78E7CBCBCBFFBDBDBDFFBCBCBCFFBCBCBCFFBCBCBCFFBDBDBDFFBEBEBEFFAEAE AEFFA3A3A3FFB2B2B2FFC7C7C7FF727272DCE5E5E51F747474D1D7D7D7FEDEDE DEFF7A7A7AE5E4E4E42100000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000D9E6D5003D7E28004684 3200468432004684320046843200468432004684320046843200468432004684 3200468432004684320046843200448330008AB17E00FDFCFC00F6F8F500F6F8 F500F6F8F500F7F9F700D0E0CC0040802B004684320046843200468432004684 3200468432003B7D2700E5EEE3000000000000000000DDDDDD00535353005B5B 5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B 5B005B5B5B005B5B5B005B5B5B005959590097979700FCFCFC00F6F6F600F6F6 F600F6F6F600F8F8F800D6D6D600555555005B5B5B005B5B5B005B5B5B005B5B 5B005B5B5B0052525200E8E8E80000000000000000002828DFFFDCDCF9FFBCBC F5FFBCBCF5FFBCBCF5FFBCBCF5FFBCBCF5FFBCBCF5FFBCBCF5FFBCBCF5FFBCBC F5FFBCBCF5FFBCBCF5FFBCBCF5FFBCBCF5FFBCBCF5FFBCBCF5FFBCBCF5FFBCBC F5FFBCBCF5FFBCBCF5FFBCBCF5FFBCBCF5FFBCBCF5FFBCBCF5FFBCBCF5FFBCBC F5FFBCBCF5FFDCDCF9FF2828DFFF00000000000000004E4E4EFFDCDCDCFFB9B9 B9FFB9B9B9FFB9B9B9FFB9B9B9FFB9B9B9FFB9B9B9FFB9B9B9FFB9B9B9FFB9B9 B9FFB9B9B9FFB9B9B9FFB9B9B9FFB9B9B9FFB9B9B9FFB9B9B9FFB9B9B9FFB9B9 B9FFB9B9B9FFB9B9B9FFB9B9B9FFB9B9B9FFB9B9B9FFB9B9B9FFB9B9B9FFB9B9 B9FFB9B9B9FFDCDCDCFF4E4E4EFF0000000000000000000000007C7A7AA6B2AF AFFFEBE5E4FFC3C1C0FFC5C6C6FFB5B5B5FFA1A09FFF6C6C6CFF454546F25D5C 5CFBA39D97FF7A848AFF2381C9FF68C3FFFFA5DBFFFFA6E1FFFF2670BAFF6260 74ABEDEDED120000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000777777A69B9B 9BFFCCCCCCFFAAAAAAFFAFAFAFFFA0A0A0FF8D8D8DFF5F5F5FFF3F3F3FF25151 51FB8B8B8BFF747474FF6C6C6CFFA3A3A3FFBCBCBCFFBEBEBEFF636363FF6565 65ABEDEDED120000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000787872BBC4C8 C6FFB7BEBBFFC6CBC9FFCACFCDFFC8CDCBFFC7CCCAFFB7BEBBFFB6BDBAFFB6BD BAFFB6BDBAFFC5C9C7FF757570E0E9E9E81C00000000F3F3F30F757370D6D5D9 D6FFD9DEDBFF797976E4C5C5C348DCDBD92DF5F5F50B00000000000000000000 0000000000000000000000000000000000000000000000000000777777BBC7C7 C7FFBDBDBDFFCACACAFFCECECEFFCCCCCCFFCBCBCBFFBDBDBDFFBCBCBCFFBCBC BCFFBCBCBCFFC8C8C8FF757575E0E8E8E81C00000000F3F3F30F727272D6D8D8 D8FFDDDDDDFF787878E4C5C5C548DADADA2DF5F5F50B00000000000000000000 00000000000000000000000000000000000000000000000000005B9249004684 3200468432004684320046843200468432004684320046843200468432004684 3200468432004684320043822F0085AE7800F5F7F400F6F8F500F6F8F500F6F8 F500F7F9F600E0EADD0048853400468432004684320046843200468432004684 32004684310067995600000000000000000000000000000000006D6D6D005B5B 5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B 5B005B5B5B005B5B5B005858580093939300F5F5F500F6F6F600F6F6F600F6F6 F600F7F7F700E3E3E3005C5C5C005B5B5B005B5B5B005B5B5B005B5B5B005B5B 5B005A5A5A00777777000000000000000000000000002828DFFFF2F2FDFFD1D1 F8FFD1D1F8FFD1D1F8FFD1D1F8FFD1D1F8FFD1D1F8FFD1D1F8FFCACAF7FFCACA F7FFC3C3F6FFC3C3F6FFC3C3F6FFC3C3F6FFC3C3F6FFC3C3F6FFC3C3F6FFC3C3 F6FFCACAF7FFC7C7F6FFD1D1F8FFD1D1F8FFD1D1F8FFD1D1F8FFD1D1F8FFD1D1 F8FFD1D1F8FFF2F2FDFF2828DFFF00000000000000004E4E4EFFF3F3F3FFCFCF CFFFCFCFCFFFCFCFCFFFCFCFCFFFCFCFCFFFCFCFCFFFCFCFCFFFC5C5C5FFC7C7 C7FFBDBDBDFFBDBDBDFFBDBDBDFFBDBDBDFFBDBDBDFFBDBDBDFFBDBDBDFFBDBD BDFFC5C5C5FFC3C3C3FFCFCFCFFFCFCFCFFFCFCFCFFFCFCFCFFFCFCFCFFFCFCF CFFFCFCFCFFFF3F3F3FF4E4E4EFF000000000000000000000000F8F8F8088080 809A706D6DFF989898FFBEBEBEFFB4B4B4FFA4A4A4FF969595FF90908FFFA4A2 9EFFB2AFAAFFB9AFA8FF8A898AFF3283BFFF88D6FFFF4DA1E3FF35416CE9C3C3 C33C000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000F7F7F7087D7D 7D9A616161FF868686FFA8A8A8FF9F9F9FFF919191FF848484FF7F7F7FFF8E8E 8EFF9A9A9AFF9B9B9BFF7A7A7AFF6E6E6EFFB2B2B2FF898989FF454545E9C3C3 C33C000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000071716CD5CBD0 CEFFC5C9C7FF787974E874746FCE7B7A77B8787874E7C7CCCAFFB7BEBBFFB6BD BAFFC1C7C4FF848481EAE1E1E126000000000000000000000000F0F0EE137675 71DAD7DBD9FFD9DDDBFFB6B8B6F7A8AAA7F1757571D0FDFDFD03000000000000 0000000000000000000000000000000000000000000000000000707070D5CFCF CFFFC8C8C8FF787878E8737373CE7A7A7AB8787878E7CBCBCBFFBDBDBDFFBCBC BCFFC6C6C6FF848484EAE1E1E126000000000000000000000000EFEFEF137474 74DADADADAFFDCDCDCFFB7B7B7F7A9A9A9F1757575D0FDFDFD03000000000000 0000000000000000000000000000000000000000000000000000A3C29A004583 3100468432004684320046843200468432004684320046843200468432004684 320046843200448330008CB27F00FCFCFC00F6F8F500F6F8F500F6F8F500F8F9 F700D6E3D2004886340046843200468432004684320046843200468432004684 320046843200CDDDC80000000000000000000000000000000000AEAEAE005A5A 5A005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B 5B005B5B5B005959590098989800FCFCFC00F6F6F600F6F6F600F6F6F600F8F8 F800DADADA005D5D5D005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B 5B005B5B5B00D2D2D2000000000000000000000000007E7EEC962828DFFF2828 DFFF2828DFFF2828DFFF2828DFFF2828DFFF2828DFFF2828DFFF2828DFFFCFCF F8FFC8C8F7FFC7C7F6FFC7C7F6FFC7C7F6FFC7C7F6FFC7C7F6FFC7C7F6FFC7C7 F6FFDADAF9FF2828DFFF2828DFFF2828DFFF2828DFFF2828DFFF2828DFFF2828 DFFF2828DFFF2828DFFF7E7EEC960000000000000000969696964E4E4EFF4E4E 4EFF4E4E4EFF4E4E4EFF4E4E4EFF4E4E4EFF4E4E4EFF4E4E4EFF4E4E4EFFD1D1 D1FFC3C3C3FFC0C0C0FFC0C0C0FFC0C0C0FFC0C0C0FFC0C0C0FFC0C0C0FFC0C0 C0FFD7D7D7FF4E4E4EFF4E4E4EFF4E4E4EFF4E4E4EFF4E4E4EFF4E4E4EFF4E4E 4EFF4E4E4EFF4E4E4EFF9696969600000000000000000000000000000000F9F9 F906B8B8B855757575A8656565FEB2B2B2FFA2A2A2FF9F9E9BFFAEACA8FFB5B1 AFFFB6B2AFFFB9B5B3FFC4BAB4FF9E9895FF4183B4FF284D89FB96959675FCFC FC03000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000F9F9 F906B6B6B655727272A8595959FE9D9D9DFF8F8F8FFF8B8B8BFF979797FF9D9D 9DFF9D9D9DFFA1A1A1FFA5A5A5FF878787FF6E6E6EFF4B4B4BFB95959575FCFC FC03000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FDFDFD02787873E5CACE CCFF706F6BE1DFDFDF270000000000000000D7D7D63271706BE5C5CAC8FFB6BD BAFFBFC5C3FF81827FE7FDFDFD0300000000000000000000000000000000ECEC EB1781817EE7DBE1DEFFD0D8D4FFD4DBD7FFC1C4C1FB97959394000000000000 00000000000000000000000000000000000000000000FDFDFD02777777E5CDCD CDFF6E6E6EE1DFDFDF270000000000000000D7D7D7326F6F6FE5C9C9C9FFBCBC BCFFC4C4C4FF818181E7FDFDFD0300000000000000000000000000000000ECEC EC17818181E7E0E0E0FFD7D7D7FFDADADAFFC3C3C3FB95959594000000000000 0000000000000000000000000000000000000000000000000000F9FBF9004583 3100468432004684320046843200468432004684320046843200468432004684 32004483300076A36700F7F9F700F6F8F500F6F8F500F6F8F500F6F8F500E2EB DF0043822F004684320046843200468432004684320046843200468432004684 320059904700FBFCFB0000000000000000000000000000000000FAFAFA005A5A 5A005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B 5B005959590085858500F8F8F800F6F6F600F6F6F600F6F6F600F6F6F600E5E5 E500585858005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B 5B006B6B6B00FBFBFB0000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000002F2FE0F0D8D8 F9FFCFCFF8FFCCCCF7FFCCCCF7FFCCCCF7FFCCCCF7FFCCCCF7FFCCCCF7FFCCCC F7FFE6E6FBFF2828DFFF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000565656F0DBDB DBFFC6C6C6FFC3C3C3FFC3C3C3FFC3C3C3FFC3C3C3FFC3C3C3FFC3C3C3FFC3C3 C3FFE1E1E1FF4E4E4EFF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000909090856F6F6FFFABABA7FFB6B4B0FFBAB8B5FFBCB8 B5FFBEBAB8FFC0BCBAFFC7C2C0FFC3BBB8FF76706FFF706E70A8F0F0F00F0000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000008E8E8E85626262FF969696FF9E9E9EFFA3A3A3FFA3A3 A3FFA5A5A5FFA7A7A7FFACACACFFA7A7A7FF656565FF6C6C6CA8F0F0F00F0000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000FEFEFE0180807BAE6B6B 66DAE9E9E81C00000000000000000000000000000000AFADAB69AFB2AFFFB6BD BAFFBDC4C1FF8F908DECEAEAE81B000000000000000000000000000000000000 0000878783DCD9E0DDFFCFD7D3FFCFD7D3FFD8DEDBFF9E9F9CF0CFCECD400000 00000000000000000000000000000000000000000000FEFEFE017F7F7FAE6A6A 6ADAE8E8E81C00000000000000000000000000000000ADADAD69B1B1B1FFBCBC BCFFC3C3C3FF8F8F8FECE9E9E91B000000000000000000000000000000000000 0000868686DCDFDFDFFFD6D6D6FFD6D6D6FFDDDDDDFF9E9E9EF0CDCDCD400000 000000000000000000000000000000000000000000000000000000000000D1E0 CD00448330004684320046843200468432004684320046843200468432004583 310089B07C00FBFCFB00F9FAF800F9FAF800F9FAF800FAFBFA00E2EBDF004F8A 3D00468432004684320046843200468432004684320046843200468432004180 2D00E5EEE200000000000000000000000000000000000000000000000000D6D6 D600595959005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005A5A 5A0096969600FBFBFB00F9F9F900F9F9F900F9F9F900FAFAFA00E5E5E5006363 63005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005656 5600E8E8E8000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000002F2FE0F0D8D8 F9FFD3D3F8FFD1D1F8FFD1D1F8FFD1D1F8FFD1D1F8FFD1D1F8FFD1D1F8FFD1D1 F8FFE6E6FBFF2828DFFF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000565656F0DBDB DBFFC9C9C9FFC6C6C6FFC6C6C6FFC6C6C6FFC6C6C6FFC6C6C6FFC6C6C6FFC6C6 C6FFE2E2E2FF4E4E4EFF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000F1F1F1115F5F5FCFAFAEAAFFC5C3C1FFC1C0BDFFC4C1 BEFFC6C2C0FFC9C4C2FFC9C3C1FF928F8EFF555555F97E7E7D82DDDDDD22FAFA FA05FEFEFE0100000000000000000000000000000000FCFCFC03FBFBFB040000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000F0F0F011595959CF999999FFACACACFFA9A9A9FFAAAA AAFFACACACFFAEAEAEFFADADADFF7F7F7FFF4C4C4CF97D7D7D82DDDDDD22FAFA FA05FEFEFE0100000000000000000000000000000000FCFCFC03FBFBFB040000 0000000000000000000000000000000000000000000000000000FEFEFE01F3F3 F30F0000000000000000000000000000000000000000A1A19E80B6B9B6FFB6BD BAFFC0C6C4FF90928FEFD9D9D72F000000000000000000000000000000000000 0000767671D5D6DAD7FFD2D9D6FFCFD7D3FFCFD7D3FFDADFDDFF7D7D78E3F2F1 F111000000000000000000000000000000000000000000000000FEFEFE01F3F3 F30F0000000000000000000000000000000000000000A0A0A080B8B8B8FFBCBC BCFFC5C5C5FF919191EFD9D9D92F000000000000000000000000000000000000 0000757575D5D9D9D9FFD8D8D8FFD6D6D6FFD6D6D6FFDEDEDEFF7C7C7CE3F1F1 F111000000000000000000000000000000000000000000000000000000000000 00008AB17E0042812E0046843200468432004684320046843200468432004A87 3700B4CEAD00B1CBA800B1CBA900B1CBA900B1CBA900B2CBAA00468432004684 320046843200468432004684320046843200468432004684320043822F00AFC9 A600000000000000000000000000000000000000000000000000000000000000 000097979700575757005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005F5F 5F00BDBDBD00B9B9B900BABABA00BABABA00BABABA00BABABA005B5B5B005B5B 5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B0058585800B7B7 B700000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000002F2FE0F0DCDC F9FFD6D6F9FFD5D5F8FFD5D5F8FFD5D5F8FFD5D5F8FFD5D5F8FFD5D5F8FFD5D5 F8FFEAEAFBFF2828DFFF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000565656F0DCDC DCFFCCCCCCFFC9C9C9FFC9C9C9FFC9C9C9FFC9C9C9FFC9C9C9FFC9C9C9FFC9C9 C9FFE4E4E4FF4E4E4EFF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000082828296918F8CFFD3D1CFFFCAC8C6FFCBC9 C7FFCECBC9FFD3CFCDFFA9A6A4FF7E7E7EFF636363FD49494ACD707070919999 9966ADADAD52B5B5B54AB5B5B54AB1B1B14EA5A5A55B99999968B9B9B946F2F2 F20D000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000007F7F7F967E7E7EFFB9B9B9FFB1B1B1FFB2B2 B2FFB3B3B3FFB8B8B8FF939393FF6F6F6FFF585858FD464646CD707070919999 9966ADADAD52B5B5B54AB5B5B54AB1B1B14EA5A5A55B98989868B9B9B946F2F2 F20D000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000F0F0EE13696864D7C5CAC7FFB6BD BAFFC9CECCFF676661DCFEFEFE01000000000000000000000000000000000000 0000EAEAE81B70706BD8CDD0CEFED4DBD7FFCFD7D3FFD1D8D4FFD2D5D3FE7D7B 78B7000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000EFEFEF13686868D7C9C9C9FFBCBC BCFFCDCDCDFF656565DCFEFEFE01000000000000000000000000000000000000 0000E9E9E91B6F6F6FD8CFCFCFFEDADADAFFD6D6D6FFD7D7D7FFD4D4D4FE7A7A 7AB7000000000000000000000000000000000000000000000000000000000000 0000000000008AB17F0045833100468432004684320046843200468432004684 3200448330004483300044833000448330004483300044833000468432004684 3200468432004684320046843200468432004684320040802B00A2C199000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000989898005A5A5A005B5B5B005B5B5B005B5B5B005B5B5B005B5B 5B005959590059595900595959005959590059595900595959005B5B5B005B5B 5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B0055555500ADADAD000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000002F2FE0F0DDDD FAFFDCDCF9FFDCDCF9FFDCDCF9FFDCDCF9FFDCDCF9FFDCDCF9FFDCDCF9FFDCDC F9FFEBEBFCFF2828DFFF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000565656F0DDDD DDFFCFCFCFFFCCCCCCFFCCCCCCFFCCCCCCFFCCCCCCFFCCCCCCFFCCCCCCFFCCCC CCFFE5E5E5FF4E4E4EFF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000DEDEDE265B5B5AD4A2A19DFFDDDCD9FFD6D4 D2FFD6D3D1FFD6D3D1FF908F8DFF808080FF8A8A8AFF707070FE5C5C5CF75353 53EC565656E4585858E05C5C5CE1626262E66F6F6FEF616161F98B8B8B80F3F3 F30C000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000DEDEDE26555555D48D8D8DFFC1C1C1FFBBBB BBFFBABABAFFBABABAFF7E7E7EFF717171FF7A7A7AFF636363FE525252F74C4C 4CEC4E4E4EE4515151E0555555E1595959E6646464EF575757F989898980F3F3 F30C000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000EBEBEB196A6866DBBEC3C0FFBCC2C0FFC6CB C9FF9FA39FFAA8A7A37600000000000000000000000000000000000000000000 000000000000F6F5F50C777773C5C1C4C1FAD8DFDBFFD8DDDAFF7E7E79E4D8D8 D633000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000EBEBEB19686868DBC2C2C2FFC1C1C1FFCACA CAFFA2A2A2FAA6A6A67600000000000000000000000000000000000000000000 000000000000F5F5F50C767676C5C3C3C3FADEDEDEFFDCDCDCFF7D7D7DE4D7D7 D733000000000000000000000000000000000000000000000000000000000000 000000000000000000008BB17E0042812E004684320046843200468432004684 3200468432004684320046843200468432004684320046843200468432004684 32004684320046843200468432004684320043822F00A2C19800000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000097979700575757005B5B5B005B5B5B005B5B5B005B5B 5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B 5B005B5B5B005B5B5B005B5B5B005B5B5B0058585800ACACAC00000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000002F2FE0F0DDDD FAFFDFDFFAFFDDDDFAFFDDDDFAFFDDDDFAFFDDDDFAFFDDDDFAFFDDDDFAFFDDDD FAFFEDEDFCFF2828DFFF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000565656F0DEDE DEFFD1D1D1FFCECECEFFCECECEFFCECECEFFCECECEFFCECECEFFCECECEFFCECE CEFFE6E6E6FF4E4E4EFF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000E2E2E2225B5B5BCD959490FFDFDC DBFFE3E1E0FFE0DDDBFFAAA6A5FF7B7B7BFF8A8A88FF8F8F8EFF969694FF999A 99FF9E9E9DFFA6A5A5FFB2B2B1FFC3C3C2FFA6A6A6FF808080C3D5D5D52C0000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000E1E1E122565656CD828282FFC3C3 C3FFC7C7C7FFC3C3C3FF949494FF6D6D6DFF797979FF7E7E7EFF848484FF8787 87FF8C8C8CFF929292FF9D9D9DFFACACACFF939393FF787878C3D5D5D52C0000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000EEECEC1662615CE2C7CAC8FFCBD0CEFFCCD0CEFF8D8E 8AF07E7E7BAFF9F9F80800000000000000000000000000000000000000000000 00000000000000000000FDFDFD03878783A8A4A5A3F6747471DFE4E4E3210000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000EDEDED16606060E2C9C9C9FFCFCFCFFFCFCFCFFF8D8D 8DF07D7D7DAFF8F8F80800000000000000000000000000000000000000000000 00000000000000000000FDFDFD03868686A8A5A5A5F6737373DFE4E4E4210000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000C5D8C00043822E0046843200468432004684 3200468432004684320046843200468432004684320046843200468432004684 32004684320046843200468432004B873800DFEADC0000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000CCCCCC00585858005B5B5B005B5B5B005B5B 5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B 5B005B5B5B005B5B5B005B5B5B005F5F5F00E3E3E30000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000002F2FE0F0DDDD FAFFE1E1FAFFE1E1FAFFE1E1FAFFE1E1FAFFE1E1FAFFE1E1FAFFE1E1FAFFE1E1 FAFFEFEFFCFF2828DFFF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000565656F0DFDF DFFFD3D3D3FFD0D0D0FFD0D0D0FFD0D0D0FFD0D0D0FFD0D0D0FFD0D0D0FFD0D0 D0FFE8E8E8FF4E4E4EFF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000EEEEEE13787878A26B6A 68FFC6C2C0FFEDEAE9FFECE9E7FFBFBCBAFF9E9B9BFF979494FF9B9A99FFA4A3 A2FFACAAA9FFB8B6B4FFBDBCBAFF8A8988FF7B7B7BA3EBEBEB14000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000EEEEEE13757575A25E5E 5EFFACACACFFD0D0D0FFCECECEFFA6A6A6FF8A8A8AFF848484FF888888FF9090 90FF969696FFA1A1A1FFA6A6A6FF797979FF787878A3EBEBEB14000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000FEFEFE01898884A4787872E170706AD9686662D3BDBD BB58000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000B4B2B064EFEFEF14000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000FEFEFE01878787A4777777E16F6F6FD9656565D3BCBC BC58000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000B2B2B264EFEFEF14000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000F3F6F100A2C19800538C40003E7F 290044822F004684320046843200468432004684320046843200468432004382 2E003C7E27005B924A00ADC8A400F9FBF9000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000F3F3F300ACACAC00666666005454 5400585858005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005B5B5B005858 5800525252006E6E6E00B6B6B600FAFAFA000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000003030E0EDE3E3 FAFFE4E4FBFFE4E4FBFFE4E4FBFFE4E4FBFFE4E4FBFFE4E4FBFFE4E4FBFFE4E4 FBFFEFEFFCFF2828DFFF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000585858EDE0E0 E0FFD5D5D5FFD2D2D2FFD2D2D2FFD2D2D2FFD2D2D2FFD2D2D2FFD2D2D2FFD2D2 D2FFE8E8E8FF4E4E4EFF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000B7B7 B754696969C17A7876F8B0ADACFFD4D0CFFFDED9D7FFDAD4D3FFD5CECDFFC9C1 C0FFB6ADADFFA19B9AFF858282E197979780F2F2F20D00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000B6B6 B654636363C16B6B6BF89A9A9AFFB9B9B9FFC1C1C1FFBDBDBDFFB8B8B8FFACAC ACFF9B9B9BFF8B8B8BFF787878E194949480F2F2F20D00000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000C9DA C2007AA76C00548D4200518B3E004F8A3C004F8A3C00518B3F00568F440084AC 7700D6E3D1000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000000000000000000000000000CECE CE00898989006767670064646400636363006363630065656500696969009191 9100DADADA000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000003A3AE2E5E8E8 FBFFF2F2FDFFF1F1FCFFF1F1FCFFF1F1FCFFF1F1FCFFF1F1FCFFF1F1FCFFF1F1 FCFFF9F9FEFF2828DFFF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000005F5F5FE5EEEE EEFFEBEBEBFFE9E9E9FFE9E9E9FFE9E9E9FFE9E9E9FFE9E9E9FFE9E9E9FFE9E9 E9FFF9F9F9FF4E4E4EFF00000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F8F8F807C7C8C74293939187727272BB706E6EDD727070EA757474E37D7C 7CC49090909CB1B1B160E2E2E21E000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000F8F8F807C6C6C6428F8F8F876D6D6DBB666666DD666666EA696969E37474 74C48A8A8A9CAEAEAE60E1E1E11E000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000F4F8F300EFF4EE00EFF5EE00F5F8F400000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000F5F5F500F1F1F100F1F1F100F6F6F600000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000009797EF783D3D E2E12828DFFF2828DFFF2828DFFF2828DFFF2828DFFF2828DFFF2828DFFF2828 DFFF2828DFFF7E7EEC9600000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000AAAAAA786161 61E14E4E4EFF4E4E4EFF4E4E4EFF4E4E4EFF4E4E4EFF4E4E4EFF4E4E4EFF4E4E 4EFF4E4E4EFF9696969600000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000000000000000000000424D3E000000000000003E000000 2800000000010000400000000100010000000000000800000000000000000000 000000000000000000000000FFFFFF00FFE007FFFFE007FF0000000000000000 00000000000000000000000000000000FFE007FFFFE007FF0000000000000000 00000000000000000000000000000000FE20047FFE20047F0000000000000000 00000000000000000000000000000000F800001FF800001F0000000000000000 00000000000000000000000000000000F000000FF000000F0000000000000000 00000000000000000000000000000000E0000007E00000070000000000000000 00000000000000000000000000000000E0000007E00000070000000000000000 00000000000000000000000000000000C0000003C00000030000000000000000 00000000000000000000000000000000C0000003C00000030000000000000000 00000000000000000000000000000000C0000003C00000030000000000000000 00000000000000000000000000000000E0000007E00000070000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000018000000180000000000000000000 000000000000000000000000000000000003C0000003C0000000000000000000 000000000000000000000000000000000007E0000007E0000000000000000000 000000000000000000000000000000000007E0000007E0000000000000000000 000000000000000000000000000000000003C0000003C0000000000000000000 0000000000000000000000000000000000018000000180000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000E0000007E00000070000000000000000 00000000000000000000000000000000C0000003C00000030000000000000000 00000000000000000000000000000000C0000003C00000030000000000000000 00000000000000000000000000000000C0000003C00000030000000000000000 00000000000000000000000000000000E0000007E00000070000000000000000 00000000000000000000000000000000E0000007E00000070000000000000000 00000000000000000000000000000000F000000FF000000F0000000000000000 00000000000000000000000000000000F800001FF800001F0000000000000000 00000000000000000000000000000000FE20047FFE20047F0000000000000000 00000000000000000000000000000000FFE007FFFFE007FF0000000000000000 00000000000000000000000000000000FFE007FFFFE007FF0000000000000000 00000000000000000000000000000000FFF83FFFFFF83FFFFFFFFFFFFFFFFFFF FFFFFF83FFFFFF83FFFFFFFFFFFFFFFFFF8003FFFF8003FFFFC003FFFFC003FF FFFFFF01FFFFFF01F0FFF0FFF0FFF0FFFF0000FFFF0000FFFFC003FFFFC003FF FFFFFE00FFFFFE00E07E0007E07E0007FC00007FFC00007FFFC003FFFFC003FF FFFFFC00FFFFFC00C0780001C0780001F800001FF800001FFFC003FFFFC003FF FFFFFC00FFFFFC008038000180380001F000000FF000000FFFC003FFFFC003FF FFFFF800FFFFF800801E0007801E0007E000000FE000000FFFC003FFFFC003FF FFFFF800FFFFF800800FF00F800FF00FE0000007E0000007FFC003FFFFC003FF FFFFF001FFFFF001800FE01F800FE01FC0000003C0000003FFC003FFFFC003FF FFFFF003FFFFF003C007C01FC007C01FC0000003C0000003FFC003FFFFC003FF FFFFE007FFFFE007E003803FE003803FC0000003C00000038000000180000001 FFFFE007FFFFE007F001007FF001007F80000001800000018000000180000001 FFFFC00FFFFFC00FFC0000FFFC0000FF80000001800000018000000180000001 FFFF801FFFFF801FFE0001FFFE0001FF80000001800000018000000180000001 FFFF003FFFFF003FFF0003FFFF0003FF04000000040000008000000180000001 F8FE007FF8FE007FFF8007FFFF8007FF00000000000000008000000180000001 F07E00FFF07E00FFFFC007FFFFC007FF00000000000000008000000180000001 E03801FFE03801FFFCC00FFFFCC00FFF04000000040000008000000180000001 C01001FFC01001FFF0000FFFF0000FFF80000001800000018000000180000001 C00003FFC00003FFE00007FFE00007FF80000001800000018000000180000001 C00007FFC00007FFC00003FFC00003FF80000001800000018000000180000001 C00007FFC00007FFC000807FC000807FC0000003C00000038000000180000001 C0000FFFC0000FFFC001C03FC001C03FC0000003C00000038000000180000001 E0000FFFE0000FFF8301E03F8301E03FC0000003C0000003FFC003FFFFC003FF FC001FFFFC001FFF8781F01F8781F01FE0000007E0000007FFC003FFFFC003FF FC00079FFC00079FCF81F00FCF81F00FF000000FF000000FFFC003FFFFC003FF FE00000FFE00000FFF01F00FFF01F00FF800001FF800001FFFC003FFFFC003FF FE00000FFE00000FFE03F80FFE03F80FFC00003FFC00003FFFC003FFFFC003FF FF00001FFF00001FFC03FC1FFC03FC1FFE00007FFE00007FFFC003FFFFC003FF FF80003FFF80003FFC0FFF3FFC0FFF3FFF0000FFFF0000FFFFC003FFFFC003FF FFE0007FFFE0007FFFFFFFFFFFFFFFFFFFE007FFFFE007FFFFC003FFFFC003FF FFF001FFFFF001FFFFFFFFFFFFFFFFFFFFFC3FFFFFFC3FFFFFC003FFFFC003FF FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000000 000000000000} end object TaskTimer: TTimer Enabled = False OnTimer = OnTaskTimer Left = 984 Top = 8 end object LogPopupMenu: TPopupMenu OnPopup = LogPopupMenuPopup Left = 264 Top = 112 object FilterGroupItem: TMenuItem Caption = 'Filter group' object TMenuItem end end object FilterLabelItem: TMenuItem Caption = 'Filter label' object TMenuItem end end object CopyToClipboardItem: TMenuItem Caption = 'Copy to clipboard' OnClick = CopyToClipboardItemClick end object ToggleAutoScrollItem: TMenuItem Caption = 'Disable auto scroll' OnClick = ToggleAutoScrollItemClick end object SaveAndClearItem: TMenuItem Caption = 'Save and clear' OnClick = SaveAndClearItemClick end end object DetailsPopupMenu: TPopupMenu Left = 720 Top = 104 object DetailsCopyToClipboardItem: TMenuItem Caption = 'Copy to clipboard' OnClick = DetailsCopyToClipboardItemClick end end object bhBuild: TBalloonHint Style = bhsStandard Left = 128 Top = 24 end object bhNew: TBalloonHint Style = bhsStandard Left = 80 Top = 24 end object bhOptions: TBalloonHint Style = bhsStandard Left = 232 Top = 24 end object bhLoadException: TBalloonHint HideAfter = 12000 Left = 112 Top = 168 end object bhManage: TBalloonHint Style = bhsStandard Left = 176 Top = 24 end object bhQuick: TBalloonHint Style = bhsStandard Left = 32 Top = 24 end end ================================================ FILE: frontend/msSmashForm.pas ================================================ unit msSmashForm; interface uses // delphi units Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Buttons, ExtCtrls, ComCtrls, XPMan, StdCtrls, ImgList, CommCtrl, Menus, Grids, ValEdit, ShellAPI, StrUtils, Clipbrd, // indy units IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient, // third party libraries superobject, W7Taskbar, // mte components mteHelpers, mteTracker, mteLogger, mteLogging, mteProgressForm, mteBase, mteTaskHandler, RttiTranslation, // ms units msCore, msConfiguration, msLoader, msThreads, msOptionsForm, msEditForm, msSettingsManager, msTagManager, msSplashForm, // tes5edit units wbBSA, wbHelpers, wbInterface, wbImplementation; type TSmashForm = class(TForm) [FormPrefix('msMain')] XPManifest: TXPManifest; IconList: TImageList; TaskTimer: TTimer; [FormSection('QuickBar')] QuickBar: TPanel; QuickButton: TSpeedButton; NewButton: TSpeedButton; BuildButton: TSpeedButton; ManageButton: TSpeedButton; OptionsButton: TSpeedButton; bhQuick: TBalloonHint; bhNew: TBalloonHint; bhBuild: TBalloonHint; bhManage: TBalloonHint; bhOptions: TBalloonHint; [FormSection('Main Panel')] MainPanel: TPanel; Splitter: TSplitter; PageControl: TPageControl; DetailsPanel: TPanel; [FormSection('Details Panel')] DetailsLabel: TLabel; DetailsGrid: TStringGrid; DetailsPopupMenu: TPopupMenu; DetailsCopyToClipboardItem: TMenuItem; [FormSection('Plugins Tab')] PluginsTabSheet: TTabSheet; PluginsListView: TListView; [FormSection('Plugins Popup Menu')] PluginsPopupMenu: TPopupMenu; AddToPatchItem: TMenuItem; RemoveFromPatchItem: TMenuItem; TagsItem: TMenuItem; ManageTagsItem: TMenuItem; ApplySettingTagsItem: TMenuItem; ClearTagsItem: TMenuItem; OpenPluginLocationItem: TMenuItem; SmashSettingItem: TMenuItem; [FormSection('Patches Tab')] PatchesTabSheet: TTabSheet; PatchesListView: TListView; [FormSection('Patches Popup Menu')] PatchesPopupMenu: TPopupMenu; ToggleRebuildItem: TMenuItem; OpenInExplorerItem: TMenuItem; BuildPatchItem: TMenuItem; EditPatchItem: TMenuItem; RemoveUnloadedPluginsItem: TMenuItem; DeletePatchItem: TMenuItem; [FormSection('Move Submenu')] MoveItem: TMenuItem; UpItem: TMenuItem; DownItem: TMenuItem; ToTopItem: TMenuItem; ToBottomItem: TMenuItem; [FormSection('Log Tab')] LogTabSheet: TTabSheet; LogListView: TListView; [FormSection('Log Popup Menu')] LogPopupMenu: TPopupMenu; FilterGroupItem: TMenuItem; FilterLabelItem: TMenuItem; CopyToClipboardItem: TMenuItem; SaveAndClearItem: TMenuItem; ToggleAutoScrollItem: TMenuItem; [FormSection('Status Bar')] StatusPanel: TPanel; StatusPanelMessage: TPanel; StatusPanelLanguage: TPanel; StatusPanelVersion: TPanel; ImageBuild: TImage; bhLoadException: TBalloonHint; // SMASH FORM EVENTS procedure UpdateLog; procedure LogMessage(const group, &label, text: string); procedure ToggleFormState(bEnabled: boolean); procedure FormCreate(Sender: TObject); procedure InitDone; procedure FormShow(Sender: TObject); procedure LoaderStatus(s: string); procedure LoaderDone; procedure FormDestroy(Sender: TObject); procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); procedure SaveDone; procedure ProgressDone; function ShouldDisplay(bh: TBalloonHint): boolean; procedure DisableHints; procedure HideHints; procedure DisplayHints; procedure RefreshGUI; procedure OnTaskTimer(Sender: TObject); procedure UpdateStatusBar; procedure UpdateListViews; // DETAILS EDITOR EVENTS procedure AddDetailsItem(name, value: string); procedure AddDetailsList(name: string; sl: TStringList); procedure PageControlChange(Sender: TObject); procedure UpdateApplicationDetails; procedure DetailsCopyToClipboardItemClick(Sender: TObject); procedure DetailsPanelResize(Sender: TObject); procedure DetailsGridMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure DetailsGridMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure DetailsGridDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState); // PLUGINS LIST VIEW EVENTS procedure UpdatePluginDetails; procedure AddPluginToPatch(var plugin: TPlugin; var patch: TPatch; i: Integer); procedure AddPluginsToPatch(var patch: TPatch); procedure ChangePatchSetting(aSetting: TSmashSetting); procedure PluginsListViewChange(Sender: TObject; Item: TListItem; Change: TItemChange); procedure PluginsListViewData(Sender: TObject; Item: TListItem); procedure PluginsListViewDrawItem(Sender: TCustomListView; Item: TListItem; Rect: TRect; State: TOwnerDrawState); // PLUGINS POPUP MENU EVENTS procedure PluginsPopupMenuPopup(Sender: TObject); procedure UpdatePluginsPopupMenu; procedure AddToNewPatchClick(Sender: TObject); procedure AddToPatchClick(Sender: TObject); procedure ChangeSettingClick(Sender: TObject); procedure RemoveFromPatchItemClick(Sender: TObject); procedure OpenPluginLocationItemClick(Sender: TObject); procedure ManageTagsItemClick(Sender: TObject); procedure ClearTagsItemClick(Sender: TObject); procedure ApplySettingTagsItemClick(Sender: TObject); // SMASH LIST VIEW EVENTS procedure UpdatePatchDetails; procedure UpdatePatches; function NewPatch: TPatch; procedure PatchesListViewChange(Sender: TObject; Item: TListItem; Change: TItemChange); procedure PatchesListViewData(Sender: TObject; Item: TListItem); procedure PatchesListViewDrawItem(Sender: TCustomListView; Item: TListItem; Rect: TRect; State: TOwnerDrawState); procedure PatchesListViewDblClick(Sender: TObject); procedure PatchesListViewKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); // PATCHES POPUP MENU EVENTS procedure PatchesPopupMenuPopup(Sender: TObject); procedure EditPatchItemClick(Sender: TObject); procedure BuildPatchItemClick(Sender: TObject); procedure RemovePluginsItemClick(Sender: TObject); procedure RemoveUnloadedPlugins(patch: TPatch); procedure RemoveUnloadedPluginsItemClick(Sender: TObject); procedure DeletePatchItemClick(Sender: TObject); procedure OpenInExplorerItemClick(Sender: TObject); procedure ToggleRebuildItemClick(Sender: TObject); procedure UpItemClick(Sender: TObject); procedure DownItemClick(Sender: TObject); procedure ToTopItemClick(Sender: TObject); procedure ToBottomItemClick(Sender: TObject); // LOG LIST VIEW EVENTS procedure LogListViewData(Sender: TObject; Item: TListItem); procedure LogListViewDrawItem(Sender: TCustomListView; Item: TListItem; Rect: TRect; State: TOwnerDrawState); // LOG POPUP MENU EVENTS procedure LogPopupMenuPopup(Sender: TObject); procedure ToggleGroupFilter(Sender: TObject); procedure ToggleLabelFilter(Sender: TObject); procedure CopyToClipboardItemClick(Sender: TObject); procedure SaveAndClearItemClick(Sender: TObject); // QUICKBAR EVENTS procedure UpdateQuickbar; function GetSmashedPatch: TPatch; procedure StartPatching; procedure QuickButtonClick(Sender: TObject); procedure NewButtonClick(Sender: TObject); procedure BuildButtonClick(Sender: TObject); procedure ManageButtonClick(Sender: TObject); procedure OptionsButtonClick(Sender: TObject); procedure ToggleAutoScrollItemClick(Sender: TObject); protected procedure WMSize(var AMessage: TMessage); message WM_SIZE; procedure WMMove(var AMessage: TMessage); message WM_MOVE; procedure WMActivateApp(var AMessage: TMessage); message WM_ACTIVATEAPP; private { Private declarations } slDetails: TStringList; public { Public declarations } end; const MessageDelay = (0.1 / 86400.0); var splash: TSplashForm; SmashForm: TSmashForm; LastHint: string; LastURLTime, LastMessageTime, FormDisplayTime: double; bPatchesToBuild, bPatchesToCheck, bAutoScroll, bCreated, bClosing: boolean; pForm: TProgressForm; TaskHandler: TTaskHandler; implementation {$R *.dfm} {******************************************************************************} { Patch Form Events Events for the Patch Form. - UpdateLog - LogMessage - ProgressMessage - FormCreate - FormShow - LoaderDone - FormClose } {******************************************************************************} procedure TSmashForm.UpdateLog; var bLogActive: boolean; begin LogListView.Items.Count := Log.Count; bLogActive := PageControl.ActivePage = LogTabSheet; // autoscroll if active if bAutoScroll and bLogActive then begin //LogListView.ClearSelection; //LogListView.Items[Pred(LogListView.Items.Count)].MakeVisible(false); SendMessage(LogListView.Handle, WM_VSCROLL, SB_LINEDOWN, 0); end; // correct width if active if bLogActive then ListView_CorrectWidth(LogListView); end; { Prints a message to the log } procedure TSmashForm.LogMessage(const group, &label, text: string); var msg: TLogMessage; begin msg := TLogMessage.Create( FormatDateTime('hh:nn:ss', Now), FormatDateTime('hh:nn:ss', Now - AppStartTime), group, &label, text); BaseLog.Add(msg); // if message is enabled, add to log if MessageEnabled(msg) then begin Log.Add(msg); // if patch form is created, update log list view if bCreated then UpdateLog; end; end; procedure ProgressMessage(const s: string); begin if s = '' then exit; Logger.Write(xEditLogGroup, xEditLogLabel, s); end; procedure InitLog; begin BaseLog := TList.Create; Log := TList.Create; LabelFilters := TList.Create; GroupFilters := TList.Create; // INITIALIZE GROUP FILTERS GroupFilters.Add(TFilter.Create('GENERAL', true)); GroupFilters.Add(TFilter.Create('LOAD', true)); GroupFilters.Add(TFilter.Create('CLIENT', true)); GroupFilters.Add(TFilter.Create('PATCH', true)); GroupFilters.Add(TFilter.Create('PLUGIN', true)); GroupFilters.Add(TFilter.Create('ERROR', true)); // INITIALIZE LABEL FILTERS LabelFilters.Add(TFilter.Create('GENERAL', 'Game', true)); LabelFilters.Add(TFilter.Create('GENERAL', 'Status', true)); LabelFilters.Add(TFilter.Create('GENERAL', 'Path', true)); LabelFilters.Add(TFilter.Create('GENERAL', 'Definitions', true)); LabelFilters.Add(TFilter.Create('GENERAL', 'Dictionary', true)); LabelFilters.Add(TFilter.Create('GENERAL', 'Load Order', true)); LabelFilters.Add(TFilter.Create('GENERAL', 'Log', true)); LabelFilters.Add(TFilter.Create('LOAD', 'Order', false)); LabelFilters.Add(TFilter.Create('LOAD', 'Plugins', false)); LabelFilters.Add(TFilter.Create('LOAD', 'Background', true)); LabelFilters.Add(TFilter.Create('CLIENT', 'Connect', true)); LabelFilters.Add(TFilter.Create('CLIENT', 'Login', true)); LabelFilters.Add(TFilter.Create('CLIENT', 'Response', true)); LabelFilters.Add(TFilter.Create('CLIENT', 'Update', true)); LabelFilters.Add(TFilter.Create('CLIENT', 'Report', true)); LabelFilters.Add(TFilter.Create('PATCH', 'Status', false)); LabelFilters.Add(TFilter.Create('PATCH', 'Create', true)); LabelFilters.Add(TFilter.Create('PATCH', 'Edit', true)); LabelFilters.Add(TFilter.Create('PATCH', 'Check', true)); LabelFilters.Add(TFilter.Create('PATCH', 'Clean', true)); LabelFilters.Add(TFilter.Create('PATCH', 'Delete', true)); LabelFilters.Add(TFilter.Create('PATCH', 'Build', true)); LabelFilters.Add(TFilter.Create('PATCH', 'Report', true)); LabelFilters.Add(TFilter.Create('PLUGIN', 'Report', true)); LabelFilters.Add(TFilter.Create('PLUGIN', 'Check', true)); LabelFilters.Add(TFilter.Create('PLUGIN', 'Tags', false)); LabelFilters.Add(TFilter.Create('PLUGIN', 'Settings', true)); end; { Initialize form, initialize TES5Edit API, and load plugins } procedure TSmashForm.FormCreate(Sender: TObject); begin // INITIALIAZE BASE bCreated := false; AppStartTime := Now; InitLog; Logger.OnLogEvent := LogMessage; //bAutoScroll := true; InitializeTaskbarAPI; SetTaskbarProgressState(tbpsIndeterminate); xEditLogGroup := 'LOAD'; xEditLogLabel := 'Plugins'; wbProgressCallback := ProgressMessage; StatusCallback := LoaderStatus; if not InitBase then begin ProgramStatus.bClose := true; exit; end; // CREATE SPLASH splash := TSplashForm.Create(nil); try InitCallback := InitDone; TInitThread.Create; splash.ShowModal; finally splash.Free; end; // do translation dump? if bTranslationDump then TRttiTranslation.Save('lang\english.lang', self); // load language TRttiTranslation.Load(language, self); // finalize bCreated := true; end; procedure TSmashForm.FormDestroy(Sender: TObject); begin // free lists FreeList(GroupFilters); FreeList(LabelFilters); // free other items TryToFree(TaskHandler); TryToFree(slDetails); end; procedure TSmashForm.ToggleFormState(bEnabled: boolean); begin // show/hide hints if bEnabled then DisplayHints else HideHints; // disable/enable form Enabled := bEnabled; end; procedure TSmashForm.WMSize(var AMessage: TMessage); begin if bCreated and (Now - LastMessageTime > MessageDelay) then begin LastMessageTime := Now; if (AMessage.WParam <> SIZE_MINIMIZED) then DisplayHints; end; inherited; end; procedure TSmashForm.WMMove(var AMessage: TMessage); begin if bCreated and (Now - LastMessageTime > MessageDelay) then begin LastMessageTime := Now; if (AMessage.WParam <> SIZE_MINIMIZED) then DisplayHints; end; inherited; end; procedure TSmashForm.WMActivateApp(var AMessage: TMessage); begin if bCreated and (Now - LastMessageTime > MessageDelay) then begin LastMessageTime := Now; if AMessage.WParam = 1 then DisplayHints else HideHints; end; inherited; end; procedure TSmashForm.InitDone; begin splash.ModalResult := mrOk; end; // Force PluginsListView to autosize columns procedure TSmashForm.FormShow(Sender: TObject); begin // CLOSE IF PLUGIN SELECTION CANCELED if ProgramStatus.bClose then begin bClosing := true; Close; exit; end; // DISABLE GUI IF INITIALIZATION EXCEPTION if ProgramStatus.bInitException then begin StatusPanelMessage.Caption := 'The application failed to initialize'; Logger.Write('ERROR', 'Load', 'There was an exception initializing the application'); Logger.Write('ERROR', 'Load', 'Review your log messages to resolve the issue'); Logger.Write('ERROR', 'Load', 'You can also change the program''s settings, if necessary'); PluginsTabSheet.Enabled := false; PluginsTabSheet.TabVisible := false; PatchesTabSheet.Enabled := false; PatchesTabSheet.TabVisible := false; PageControl.ActivePage := LogTabSheet; end; // QUICKBAR QuickButton.Flat := true; NewButton.Flat := true; BuildButton.Flat := true; ManageButton.Flat := true; OptionsButton.Flat := true; IconList.GetBitmap(0, QuickButton.Glyph); IconList.GetBitmap(1, NewButton.Glyph); IconList.GetBitmap(2, BuildButton.Glyph); IconList.GetBitmap(3, ManageButton.Glyph); IconList.GetBitmap(4, OptionsButton.Glyph); // STATUSBAR VALUES StatusPanelLanguage.Caption := settings.language; StatusPanelVersion.Caption := 'v' + ProgramStatus.Version; // UPDATE GUI slDetails := TStringList.Create; PluginsListView.OwnerDraw := not settings.simplePluginsView; PluginsListView.Items.Count := PluginsList.Count; UpdateLog; UpdatePatches; UpdatePluginsPopupMenu; UpdateStatusBar; UpdateQuickBar; if not ProgramStatus.bInitException then begin // START BACKGROUND LOADER LoaderCallback := LoaderDone; SetTaskbarProgressState(tbpsIndeterminate); if settings.buildRefs then TLoaderThread.Create; // CORRECT LIST VIEW WIDTHS ListView_CorrectWidth(PatchesListView); ListView_CorrectWidth(PluginsListView); // LOAD AND DISPLAY HINTS bhLoadException.Title := GetLanguageString('msMain_LoadException'); bhLoadException.Description := GetLanguageString('msMain_PluginsNotLoaded'); DisplayHints; // initialize task handler TaskHandler := TTaskHandler.Create; bLogTasks := false; TaskHandler.AddTask(TTask.Create('Disable Hints', 12.0 * seconds, DisableHints)); TaskHandler.AddTask(TTask.Create('Refresh GUI', 3.0 * seconds, RefreshGUI)); TaskTimer.Enabled := true; end; // ACTIVATE WINDOW FormDisplayTime := Now; ForceForeground(Handle); if ProgramStatus.bInitException then PageControlChange(PageControl); if not settings.buildRefs then LoaderDone; end; procedure TSmashForm.LoaderStatus(s: string); begin StatusPanelMessage.Caption := s; end; procedure TSmashForm.LoaderDone; begin wbLoaderDone := true; SetTaskbarProgressState(tbpsNone); xEditLogGroup := 'GENERAL'; xEditLogLabel := 'xEdit'; FlashWindow(Application.Handle, True); UpdateQuickbar; end; procedure TSmashForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin CanClose := ProgramStatus.bClose; if not bClosing then begin bClosing := true; Enabled := false; // show progress form pForm := TProgressForm.Create(Self); pForm.pfLogPath := LogPath + 'save\'; pForm.PopupParent := Self; pForm.Caption := GetLanguageString('msProg_Closing'); pForm.SetMaxProgress(PluginsList.Count + PatchesList.Count + 2); pForm.Show; // start save thread TaskTimer.Enabled := false; SaveCallback := SaveDone; TSaveThread.Create; end; end; procedure TSmashForm.SaveDone; begin // clean up pForm, close form pForm.SetProgress(pForm.ProgressBar.Max); pForm.SaveLog; pForm.Free; // restart program if update applied if ProgramStatus.bInstallUpdate then ShellExecute(Application.Handle, 'runas', PChar(ParamStr(0)), '', '', SW_SHOWNORMAL); // restart program if user wants patch profile change if ProgramStatus.bChangeProfile then ShellExecute(Application.Handle, 'runas', PChar(ParamStr(0)), '', '', SW_SHOWNORMAL); // allow close and close SaveLog(BaseLog); ProgramStatus.bClose := true; Close; end; procedure TSmashForm.ProgressDone; begin xEditLogGroup := 'GENERAL'; pForm.SaveLog; pForm.Visible := false; FlashWindow(Application.Handle, True); pForm.ShowModal; pForm.Free; Enabled := true; ShowWindow(Application.Handle, SW_RESTORE); SetForegroundWindow(Application.Handle); // free lists if Assigned(timeCosts) then timeCosts.Free; if Assigned(pluginsToHandle) then pluginsToHandle.Free; if Assigned(patchesToBuild) then patchesToBuild.Free; // update patches and gui UpdateListViews; UpdatePatches; UpdateQuickbar; UpdatePluginsPopupMenu; end; function TSmashForm.ShouldDisplay(bh: TBalloonHint): boolean; begin Result := (Now - FormDisplayTime) * 86400 < (bh.HideAfter / 1000); end; procedure TSmashForm.DisableHints; begin HideHints; TaskHandler.RemoveTask('Disable Hints'); end; procedure TSmashForm.HideHints; begin bhLoadException.HideHint; end; procedure TSmashForm.DisplayHints; var pt: TPoint; begin if ProgramStatus.bLoadException and ShouldDisplay(bhLoadException) then begin pt.X := 126; pt.Y := 16; pt := MainPanel.ClientToScreen(pt); bhLoadException.ShowHint(pt); end; end; procedure TSmashForm.RefreshGUI; begin if not bClosing then UpdateStatusBar; end; procedure TSmashForm.OnTaskTimer(Sender: TObject); begin if not bClosing then TaskHandler.ExecTasks; end; procedure TSmashForm.UpdateStatusBar; begin ImageBuild.Visible := wbLoaderDone and bPatchesToBuild; StatusPanelLanguage.Caption := settings.language; end; procedure TSmashForm.UpdateListViews; begin if PageControl.ActivePage = PluginsTabSheet then begin UpdatePluginDetails; PluginsListView.Repaint; end; if PageControl.ActivePage = PatchesTabSheet then begin UpdatePatchDetails; PatchesListView.Repaint; end; if PageControl.ActivePage = LogTabSheet then LogListView.Repaint; end; {******************************************************************************} { Details Editor Events Methods for helping with the DetailsGrid control. Methods include: - AddDetailsItem - AddDetailsList - PageControlChange - UpdateApplicationDetails } {******************************************************************************} { Adds a ListItem to DetailsView with @name and @value } procedure TSmashForm.AddDetailsItem(name, value: string); begin slDetails.Add(name + '=' + value); end; { Add one or more ListItem to DetailsView with @name and the values in @sl } procedure TSmashForm.AddDetailsList(name: string; sl: TStringList); var i: integer; begin if sl.Count > 0 then begin for i := 0 to Pred(sl.Count) do slDetails.Add(Format('%s[%d]=%s', [name, i, sl[i]])); end else slDetails.Add(name + '= '); end; { Switch details view when page control is changed } procedure TSmashForm.PageControlChange(Sender: TObject); var ndx: integer; begin ndx := TPageControl(Sender).ActivePageIndex; case ndx of 0: begin UpdatePluginDetails; ListView_CorrectWidth(PluginsListView); end; 1: begin UpdatePatchDetails; ListView_CorrectWidth(PatchesListView); end; 2: begin UpdateApplicationDetails; ListView_CorrectWidth(LogListView); end; end; end; procedure TSmashForm.UpdateApplicationDetails; begin // prepare list view for application information slDetails.Clear; DetailsLabel.Caption := GetLanguageString('msMain_AppDetails'); // add details items AddDetailsItem(GetLanguageString('msMain_Application'), 'Mator Smash'); AddDetailsItem(GetLanguageString('msMain_Author'), 'matortheeternal'); AddDetailsItem(GetLanguageString('msMain_Version'), ProgramStatus.Version); AddDetailsItem(GetLanguageString('msMain_DateBuilt'), DateTimeToStr(GetLastModified(ParamStr(0)))); AddDetailsItem(' ', ' '); AddDetailsItem(GetLanguageString('msMain_GameMode'), wbGameName); AddDetailsItem(GetLanguageString('msMain_Language'), settings.language); AddDetailsItem(' ', ' '); AddDetailsItem(GetLanguageString('msMain_TimesRun'), IntToStr(statistics.timesRun + sessionStatistics.timesRun)); AddDetailsItem(GetLanguageString('msMain_PatchesBuilt'), IntToStr(statistics.patchesBuilt + sessionStatistics.patchesBuilt)); AddDetailsItem(GetLanguageString('msMain_PluginsSmashed'), IntToStr(statistics.pluginsPatched + sessionStatistics.pluginsPatched)); AddDetailsItem(GetLanguageString('msMain_SettingsSubmitted'), IntToStr(statistics.settingsSubmitted + sessionStatistics.settingsSubmitted)); AddDetailsItem(GetLanguageString('msMain_RecsSubmitted'), IntToStr(statistics.recsSubmitted + sessionStatistics.recsSubmitted)); AddDetailsItem(' ', ' '); AddDetailsItem(GetLanguageString('msMain_Website'), '-'); AddDetailsItem(GetLanguageString('msMain_ApiCredits'), 'superobject, TurboPower Abbrevia, xEdit'); AddDetailsItem(GetLanguageString('msMain_xEditVersion'), xEditVersion); AddDetailsItem(GetLanguageString('msMain_xEditCredits'), 'zilav, hlp, Sharlikran, ElminsterAU'); AddDetailsItem(GetLanguageString('msMain_Testers'), ProgramTesters); AddDetailsItem(GetLanguageString('msMain_Translators'), ProgramTranslators); // update gui StringGrid_CorrectWidth(DetailsGrid); DetailsGrid.RowCount := slDetails.Count; DetailsGrid.Repaint; end; procedure TSmashForm.DetailsCopyToClipboardItemClick(Sender: TObject); var i: Integer; name, value, previousName, previousValue: string; sl: TStringList; begin sl := TStringList.Create; // build stringlist of formatted name value pairs with special formatting for // empty names and empty values name := ' '; value := ' '; for i := 0 to Pred(slDetails.Count) do begin previousName := name; name := slDetails.Names[i]; previousValue := value; value := slDetails.ValueFromIndex[i]; if (name <> ' ') then sl.Add(Format('%s: %s', [name, value])) else if (value <> ' ') then begin if (previousName <> ' ') then begin sl[sl.Count - 1] := previousName + ':'; sl.Add('- '+previousValue); end; sl.Add('- '+value); end else sl.Add(' '); end; // copy to clipboard Clipboard.AsText := sl.Text; sl.Free; end; { Resize StringGrid columns when parent panel changes size } procedure TSmashForm.DetailsPanelResize(Sender: TObject); begin StringGrid_CorrectWidth(DetailsGrid); end; { Make cursor pointer if mouse is over a URL } procedure TSmashForm.DetailsGridMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); var ACol, ARow: integer; value: string; begin // don't change cursor if in help mode if Screen.Cursor = crHelp then exit; DetailsGrid.MouseToCell(X, Y, ACol, ARow); // use default cursor on cells in column 0, or at an invalid cell if (ACol = 0) or (ARow > Pred(slDetails.Count)) then begin Screen.Cursor := crDefault; exit; end; // test if cell is a url value := slDetails.ValueFromIndex[ARow]; if IsURL(value) then Screen.Cursor := crHandPoint else Screen.Cursor := crDefault; end; { Handle user clicking URL } procedure TSmashForm.DetailsGridMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var ACol, ARow: integer; value: string; begin // only process left clicks if Button <> mbLeft then exit; DetailsGrid.MouseToCell(X, Y, ACol, ARow); // skip clicks on cells in column 0 if ACol = 0 then exit; try value := slDetails.ValueFromIndex[ARow]; if IsURL(value) and ((Now - LastURLTime) * 86400 > 1.0) then begin ShellExecute(0, 'open', PChar(value), '', '', SW_SHOWNORMAL); LastURLTime := Now; end; except // invalid cell end; end; { Handle drawing of a cell } procedure TSmashForm.DetailsGridDrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState); var sText, sNextVal, sNextName: string; iHalfBottom, iPadding: Integer; begin // initialize stuff sText := ' '; iPadding := (Rect.Bottom - Rect.Top) - DetailsGrid.Canvas.TextHeight('Hg'); iHalfBottom := Rect.Top + (Rect.Bottom - Rect.Top) div 2; DetailsGrid.Font.Style := []; DetailsGrid.Font.Color := clBlack; // draw name if ACol = 0 then begin DetailsGrid.Canvas.Brush.Color := TColor($00f6f4f3); DetailsGrid.Canvas.Rectangle(Rect); DetailsGrid.Canvas.Brush.Color := clWindow; DetailsGrid.Canvas.Rectangle(Rect.Left, Rect.Top, Rect.Right, iHalfBottom); if Assigned(slDetails) and (slDetails.Count > ARow) then sText := slDetails.Names[ARow]; // handle lists sText := RemoveFromEnd(sText, '[0]'); if StrEndsWith(sText, ']') then exit; DetailsGrid.Canvas.Brush.Style := bsClear; DetailsGrid.Canvas.TextOut(Rect.Left + 4, Rect.Top + (iPadding div 2), sText); end // draw value else if ACol = 1 then begin DetailsGrid.Canvas.Brush.Color := clWindow; DetailsGrid.Canvas.Rectangle(Rect); if Assigned(slDetails) and (slDetails.Count > ARow) then sText := slDetails.ValueFromIndex[ARow]; // handle special drawing of urls and master files if (Pred(slDetails.Count) > ARow) then begin sNextVal := slDetails.ValueFromIndex[ARow + 1]; sNextName := slDetails.Names[ARow + 1]; // urls blue and underlined if IsURL(sNextVal) then begin DetailsGrid.Font.Style := [fsUnderline]; DetailsGrid.Font.Color := clBlue; end // esps and esms red if not loaded else if Pos('Plugins[', sNextName) = 1 then begin if not Assigned(PluginByFileName(sNextVal)) then DetailsGrid.Font.Color := clRed; end; end; // draw text DetailsGrid.Canvas.Brush.Style := bsClear; DetailsGrid.Canvas.TextOut(Rect.Left + 4, Rect.Top + (iPadding div 2), sText); end; end; {******************************************************************************} { PluginsListView Events Events involving the PluginsListView control. Events include: - UpdatePluginDetails - PluginsListViewChange - PluginsListViewData - FlagNotSafe - DrawFlag - DrawPluginFlags - PluginsListViewDrawItem - PluginsListViewMouseMove } {******************************************************************************} procedure TSmashForm.UpdatePluginDetails; var plugin: TPlugin; index: integer; begin // don't do anything if no item selected if not Assigned(PluginsListView.Selected) then exit; // prepare list view for plugin information slDetails.Clear; DetailsLabel.Caption := GetLanguageString('msMain_PluginDetails'); // get plugin information index := PluginsListView.ItemIndex; plugin := TPlugin(PluginsList[index]); if not plugin.hasData then plugin.GetData(PluginsList); // add details items AddDetailsItem(GetLanguageString('msMain_Filename'), plugin.filename); AddDetailsItem(GetLanguageString('msMain_Hash'), '$' + plugin.hash); AddDetailsItem(GetLanguageString('msMain_FileSize'), FormatByteSize(plugin.fileSize)); AddDetailsItem(GetLanguageString('msMain_DateModified'), plugin.dateModified); AddDetailsItem(GetLanguageString('msMain_NumRecords'), IntToStr(plugin.numRecords)); AddDetailsItem(GetLanguageString('msMain_NumOverrides'), IntToStr(plugin.numOverrides)); AddDetailsItem(GetLanguageString('msMain_Author'), plugin.author); AddDetailsList(GetLanguageString('msMain_Description'), plugin.description); AddDetailsList(GetLanguageString('msMain_Masters'), plugin.masters); // update gui StringGrid_CorrectWidth(DetailsGrid); DetailsGrid.RowCount := slDetails.Count; DetailsGrid.Repaint; end; procedure TSmashForm.ChangePatchSetting(aSetting: TSmashSetting); var i: Integer; ListItem: TListItem; plugin: TPlugin; begin // loop through plugins list, adding selected plugins to patch for i := 0 to Pred(PluginsListView.Items.Count) do begin ListItem := PluginsListView.Items[i]; if not ListItem.Selected then continue; plugin := TPlugin(PluginsList[i]); plugin.setting := aSetting.name; plugin.smashSetting := aSetting; end; // update and repaint UpdatePatches; UpdateListViews; UpdateQuickbar; UpdateStatusBar; end; procedure TSmashForm.AddPluginToPatch(var plugin: TPlugin; var patch: TPatch; i: Integer); begin Logger.Write('PLUGIN', 'Patch', 'Added '+plugin.filename+' to patch '+patch.name); if not plugin.hasData then plugin.GetData(PluginsList); if plugin.patch = patch.name then exit; patch.plugins.AddObject(plugin.filename, TObject(i)); plugin.patch := patch.name; end; procedure TSmashForm.AddPluginsToPatch(var patch: TPatch); var i: integer; ListItem: TListItem; plugin: TPlugin; begin // loop through plugins list, adding selected plugins to patch for i := 0 to Pred(PluginsListView.Items.Count) do begin ListItem := PluginsListView.Items[i]; if not ListItem.Selected then continue; plugin := TPlugin(PluginsList[i]); if plugin.patch <> ' ' then continue; AddPluginToPatch(plugin, patch, i); end; // update and repaint UpdatePatches; UpdateListViews; UpdateQuickbar; UpdateStatusBar; end; procedure TSmashForm.PluginsListViewChange(Sender: TObject; Item: TListItem; Change: TItemChange); begin UpdatePluginDetails; end; procedure TSmashForm.PluginsListViewData(Sender: TObject; Item: TListItem); var plugin: TPlugin; begin if Item.Index > Pred(PluginsList.Count) then exit; plugin := TPlugin(PluginsList[Item.Index]); Item.Caption := IntToHex(Item.Index, 2); Item.SubItems.Add(plugin.filename); Item.SubItems.Add(plugin.setting); Item.SubItems.Add(plugin.patch); if Assigned(plugin.smashSetting) then PluginsListView.Canvas.Font.Color := plugin.smashSetting.color else PluginsListView.Canvas.Font.Color := clGray; PluginsListView.Canvas.Font.Style := PluginsListView.Canvas.Font.Style + [fsBold]; end; procedure TSmashForm.PluginsListViewDrawItem(Sender: TCustomListView; Item: TListItem; Rect: TRect; State: TOwnerDrawState); var i, x, y: integer; ListView: TListView; R: TRect; begin ListView := TListView(Sender); if Item.Selected then begin ListView.Canvas.Brush.Color := $FFEEDD; ListView.Canvas.FillRect(Rect); end; R := Rect; R.Right := R.Left + ListView.Columns[0].Width - 3; x := Rect.Left + 3; y := (Rect.Bottom - Rect.Top - ListView.Canvas.TextHeight('Hg')) div 2 + Rect.Top; ListView.Canvas.TextRect(R, x, y, Item.Caption); for i := 0 to Item.SubItems.Count - 1 do begin R.Left := R.Right + 3; // fixes drawing bug R.Right := R.Left + ListView_GetColumnWidth(ListView.Handle, ListView.Columns[i + 1].Index); x := R.Left; ListView.Canvas.TextRect(R, x, y, Item.SubItems[i]); end; end; {******************************************************************************} { Plugins Popup Menu methods Methods for dealing with the popup menu for the PluginsListView. - PluginsPopupMenuPopup - UpdatePluginsPopupMenu - AddToPatchClick - AddToNewPatchClick - CheckForErrorsClick - RemoveFromPatchClick } {******************************************************************************} procedure TSmashForm.PluginsPopupMenuPopup(Sender: TObject); var i: integer; bPluginInPatch, bHasSelection, bAllPluginsInPatch, bAllHaveTags: boolean; ListItem: TListItem; plugin: TPlugin; begin // initialize selection booleans bHasSelection := false; bPluginInPatch := false; bAllPluginsInPatch := true; bAllHaveTags := true; // loop through selection for i := 0 to Pred(PluginsListView.Items.Count) do begin ListItem := PluginsListView.Items[i]; if not ListItem.Selected then continue; plugin := PluginsList[i]; bHasSelection := true; bAllHaveTags := bAllHaveTags and plugin.HasTags; bPluginInPatch := bPluginInPatch or plugin.IsInPatch; bAllPluginsInPatch := bAllPluginsInPatch and plugin.IsInPatch; end; // disable/enable menu items AddToPatchItem.Enabled := bHasSelection and not bPluginInPatch; SmashSettingItem.Enabled := bHasSelection; OpenPluginLocationItem.Enabled := bHasSelection; RemoveFromPatchItem.Enabled := bHasSelection and bAllPluginsInPatch; TagsItem.Enabled := bHasSelection and settings.allowTagging; ClearTagsItem.Enabled := bHasSelection and bAllHaveTags; end; procedure TSmashForm.UpdatePluginsPopupMenu; var i, index: Integer; patch: TPatch; aSetting: TSmashSetting; MenuItem, GroupItem: TMenuItem; sGroup: String; begin // clear submenus AddToPatchItem.Clear; SmashSettingItem.Clear; // add option to Plugins popup menu MenuItem := TMenuItem.Create(AddToPatchItem); MenuItem.Caption := GetLanguageString('msMain_NewPatchItem_Caption'); MenuItem.OnClick := AddToNewPatchClick; AddToPatchItem.Add(MenuItem); // add patches to submenu for i := 0 to Pred(PatchesList.Count) do begin patch := TPatch(PatchesList[i]); MenuItem := TMenuItem.Create(AddToPatchItem); MenuItem.Caption := patch.name; MenuItem.OnClick := AddToPatchClick; AddToPatchItem.Add(MenuItem); end; // add smash settings to submenu for i := 0 to Pred(SmashSettings.Count) do begin aSetting := TSmashSetting(SmashSettings[i]); // parse setting group sGroup := 'Ungrouped'; index := Pos('.', aSetting.name); if (index > 0) and (index < 11) then sGroup := Copy(aSetting.name, 1, index - 1); // get group menu item or create it if missing GroupItem := SmashSettingItem.Find(sGroup); if not Assigned(GroupItem) then begin GroupItem := TMenuItem.Create(SmashSettingItem); GroupItem.Caption := sGroup; SmashSettingItem.Add(GroupItem); end; // create MenuItem MenuItem := TMenuItem.Create(GroupItem); MenuItem.Caption := aSetting.name; MenuItem.OnClick := ChangeSettingClick; GroupItem.Add(MenuItem); end; end; procedure TSmashForm.AddToPatchClick(Sender: TObject); var MenuItem: TMenuItem; patch: TPatch; name: String; begin MenuItem := TMenuItem(Sender); name := StripHotkey(MenuItem.Caption); patch := TPatchHelpers.PatchByName(PatchesList, name); if Assigned(patch) then AddPluginsToPatch(patch) else begin ToggleFormState(false); ShowMessage('Error: Could not find patch '+name); ToggleFormState(true); end; end; procedure TSmashForm.ChangeSettingClick(Sender: TObject); var MenuItem: TMenuItem; aSetting: TSmashSetting; name: String; begin MenuItem := TMenuItem(Sender); name := StripHotkey(MenuItem.Caption); aSetting := TSettingHelpers.SettingByName(name); if Assigned(aSetting) then ChangePatchSetting(aSetting) else begin ToggleFormState(false); ShowMessage('Error: Could not find setting '+name); ToggleFormState(true); end; end; procedure TSmashForm.AddToNewPatchClick(Sender: TObject); var patch: TPatch; begin patch := NewPatch; if Assigned(patch) then AddPluginsToPatch(patch); end; procedure TSmashForm.ManageTagsItemClick(Sender: TObject); var i: integer; ListItem: TListItem; tmForm: TTagManager; plugin: TPlugin; begin for i := 0 to Pred(PluginsListView.Items.Count) do begin // only process selected list items ListItem := PluginsListView.Items[i]; if not ListItem.Selected then continue; // create a tag manager instance for the plugin plugin := TPlugin(PluginsList[i]); tmForm := TTagManager.Create(self); try tmForm.plugin := plugin; tmForm.ShowModal; finally tmForm.Free; end; end; // update UpdatePatches; UpdateListViews; UpdateQuickbar; UpdateStatusBar; end; procedure TSmashForm.ApplySettingTagsItemClick(Sender: TObject); var i: integer; ListItem: TListItem; plugin: TPlugin; begin for i := 0 to Pred(PluginsListView.Items.Count) do begin // only process selected list items ListItem := PluginsListView.Items[i]; if not ListItem.Selected then continue; // create a tag manager instance for the plugin plugin := TPlugin(PluginsList[i]); plugin.ApplySettingTags; plugin.Save; end; // update UpdatePatches; UpdateListViews; UpdateQuickbar; UpdateStatusBar; end; procedure TSmashForm.ClearTagsItemClick(Sender: TObject); var i: integer; ListItem: TListItem; pluginNames: String; plugin: TPlugin; pluginsToClear: TList; bApproved: Boolean; frmDialog: TForm; begin // initialize variables bApproved := false; pluginsToClear := TList.Create; pluginNames := ''; // use a try-finally to make certain the list is freed try // add selected list items to the list for i := 0 to Pred(PluginsListView.Items.Count) do begin ListItem := PluginsListView.Items[i]; if ListItem.Selected then begin plugin := TPlugin(PluginsList[i]); pluginsToClear.Add(plugin); pluginNames := pluginNames + #13#10' - ' + plugin.filename; end; end; // prompt user if a plugin was selected if pluginsToClear.Count > 0 then begin frmDialog := CreateMessageDialog(GetLanguageString('msMain_ClearTags') + pluginNames, mtConfirmation, mbOKCancel, mbOk); frmDialog.PopupParent := self; ToggleFormState(false); bApproved := frmDialog.ShowModal = mrOk; ToggleFormState(true); end; // exit if user didn't approve clearing tags if not bApproved then exit; // clear tags on plugins in the list for i := 0 to Pred(pluginsToClear.Count) do begin plugin := TPlugin(pluginsToClear[i]); Logger.Write('PLUGIN', 'Tags', 'Clearing tags on '+plugin.filename); plugin.description.Text := ClearTags(plugin.description.Text); plugin.GetSettingTag; plugin.WriteDescription; // plugin.Save; end; // update UpdatePatches; UpdateListViews; UpdateQuickbar; UpdateStatusBar; finally pluginsToClear.Free; end; end; { Remove from Patch } procedure TSmashForm.RemoveFromPatchItemClick(Sender: TObject); var i: integer; ListItem: TListItem; pluginName, patchName: string; patch: TPatch; plugin: TPlugin; begin for i := 0 to Pred(PluginsListView.Items.Count) do begin // only process selected list items ListItem := PluginsListView.Items[i]; if not ListItem.Selected then continue; // get plugin associated with patch item and remove it from patch plugin := TPlugin(PluginsList[i]); pluginName := plugin.filename; patchName := plugin.patch; if patchName <> ' ' then begin patch := TPatchHelpers.PatchByName(PatchesList, patchName); if Assigned(patch) then patch.plugins.Delete(patch.plugins.IndexOf(pluginName)); end; plugin.patch := ' '; end; // update UpdatePatches; UpdateListViews; UpdateQuickbar; UpdateStatusBar; end; procedure TSmashForm.OpenPluginLocationItemClick(Sender: TObject); var i: integer; listItem: TListItem; plugin: TPlugin; begin for i := 0 to Pred(PluginsListView.Items.Count) do begin // only process selected list items ListItem := PluginsListView.Items[i]; if not ListItem.Selected then continue; // open plugin location in explorer if it exists plugin := TPlugin(PluginsList[i]); if DirectoryExists(plugin.dataPath) then ShellExecute(0, 'open', PChar(plugin.dataPath), '', '', SW_SHOWNORMAL); end; end; {******************************************************************************} { Patch List View Events Events involving the PatchesListView control. Events include: - UpdatePatchDetails - UpdatePatches - PatchesListViewChange - PatchesListViewData - PatchesListViewDrawItem - SavePatchEdit } {******************************************************************************} procedure TSmashForm.UpdatePatchDetails; var patchItem: TListItem; patch: TPatch; begin // don't do anything if no item selected patchItem := PatchesListView.Selected; if not Assigned(patchItem) then exit; // prepare list view for patch information slDetails.Clear; DetailsLabel.Caption := GetLanguageString('msMain_PatchDetails'); // get patch information patch := PatchesList[PatchesListView.ItemIndex]; AddDetailsItem(GetLanguageString('msMain_Status'), StatusArray[Ord(patch.status)].desc); AddDetailsItem(GetLanguageString('msMain_PatchName'), patch.name); AddDetailsItem(GetLanguageString('msMain_Filename'), patch.filename); AddDetailsItem(GetLanguageString('msMain_PluginCount'), IntToStr(patch.plugins.Count)); AddDetailsItem(GetLanguageString('msMain_DateBuilt'), DateBuiltString(patch.dateBuilt)); AddDetailsList(GetLanguageString('msMain_Plugins'), patch.plugins); AddDetailsItem(' ', ' '); if patch.fails.Count < 250 then AddDetailsList(GetLanguageString('msMain_Fails'), patch.fails) else AddDetailsItem(GetLanguageString('msMain_Fails'), GetLanguageString('msMain_TooManyFails')); // update gui StringGrid_CorrectWidth(DetailsGrid); DetailsGrid.RowCount := slDetails.Count; DetailsGrid.Repaint; end; procedure TSmashForm.UpdatePatches; var i: integer; patch: TPatch; begin // update patch count PatchesListView.Items.Count := PatchesList.Count; for i := 0 to Pred(PatchesList.Count) do begin patch := TPatch(PatchesList[i]); // sort plugins in patch patch.SortPlugins; // get status of each patch if not ((patch.status in ForcedStatuses) or (patch.status in FailedStatuses)) then patch.GetStatus; end; end; function TSmashForm.NewPatch: TPatch; var patch: TPatch; EditPatch: TEditForm; begin Result := nil; patch := TPatchHelpers.CreateNewPatch(PatchesList); // edit patch immediately after its creation EditPatch := TEditForm.Create(Self); EditPatch.patch := patch; if EditPatch.ShowModal = mrOk then begin patch := EditPatch.patch; LogMessage('PATCH', 'New', 'Created new patch '+patch.name); // add patch to list and update views PatchesList.Add(patch); UpdatePatches; PatchesListView.Repaint; UpdatePluginsPopupMenu; // set result Result := patch; end; // add and update patch EditPatch.Free; end; procedure TSmashForm.PatchesListViewChange(Sender: TObject; Item: TListItem; Change: TItemChange); begin UpdatePatchDetails; end; procedure TSmashForm.PatchesListViewData(Sender: TObject; Item: TListItem); var patch: TPatch; begin if Item.Index > Pred(PatchesList.Count) then exit; patch := TPatch(PatchesList[Item.Index]); Item.Caption := IntToHex(Item.Index, 2); Item.SubItems.Add(patch.name); Item.SubItems.Add(patch.filename); Item.SubItems.Add(IntToStr(patch.plugins.count)); Item.SubItems.Add(DateBuiltString(patch.dateBuilt)); PatchesListView.Canvas.Font.Color := StatusArray[Ord(patch.status)].color; PatchesListView.Canvas.Font.Style := PatchesListView.Canvas.Font.Style + [fsBold]; end; procedure TSmashForm.PatchesListViewDrawItem(Sender: TCustomListView; Item: TListItem; Rect: TRect; State: TOwnerDrawState); var i, x, y: integer; ListView: TListView; R: TRect; begin ListView := TListView(Sender); if Item.Selected then begin ListView.Canvas.Brush.Color := $FFEEDD; ListView.Canvas.FillRect(Rect); end; R := Rect; R.Right := R.Left + ListView.Columns[0].Width - 3; x := Rect.Left + 3; y := (Rect.Bottom - Rect.Top - ListView.Canvas.TextHeight('Hg')) div 2 + Rect.Top; ListView.Canvas.TextRect(R, x, y, Item.Caption); for i := 0 to Item.SubItems.Count - 1 do begin R.Left := R.Right + 3; // fixes drawing error R.Right := R.Left + ListView_GetColumnWidth(ListView.Handle, ListView.Columns[i + 1].Index); x := R.Left; ListView.Canvas.TextRect(R, x, y, Item.SubItems[i]); end; end; {******************************************************************************} { LogListView methods } {******************************************************************************} procedure TSmashForm.LogListViewData(Sender: TObject; Item: TListItem); var msg: TLogMessage; begin if (Item.Index > Pred(Log.Count)) then exit; msg := TLogMessage(Log[Item.Index]); Item.Caption := msg.time; Item.SubItems.Add(msg.appTime); Item.SubItems.Add(msg.group); Item.SubItems.Add(msg.&label); Item.SubItems.Add(msg.text); // handle coloring if (msg.group = 'GENERAL') then LogListView.Canvas.Font.Color := settings.generalMessageColor else if (msg.group = 'LOAD') then LogListView.Canvas.Font.Color := settings.loadMessageColor else if (msg.group = 'CLIENT') then LogListView.Canvas.Font.Color := settings.clientMessageColor else if (msg.group = 'PATCH') then LogListView.Canvas.Font.Color := settings.patchMessageColor else if (msg.group = 'PLUGIN') then LogListView.Canvas.Font.Color := settings.pluginMessageColor else if (msg.group = 'ERROR') then LogListView.Canvas.Font.Color := settings.errorMessageColor; end; procedure TSmashForm.LogListViewDrawItem(Sender: TCustomListView; Item: TListItem; Rect: TRect; State: TOwnerDrawState); var i, x, y: integer; ListView: TListView; R: TRect; msg: string; map: TStringList; begin ListView := TListView(Sender); if Item.Selected then begin ListView.Canvas.Brush.Color := $FFEEDD; ListView.Canvas.FillRect(Rect); end; // prepare map map := TStringList.Create; map.Values[ListView.Columns[0].Caption] := Item.Caption; for i := 0 to Pred(Item.SubItems.Count) do map.Values[ListView.Columns[i + 1].Caption] := Item.SubItems[i]; // prepare text rect R := Rect; R.Right := R.Left + ListView.Width - 3; x := Rect.Left + 3; y := (Rect.Bottom - Rect.Top - ListView.Canvas.TextHeight('Hg')) div 2 + Rect.Top; // draw message msg := ApplyTemplate(settings.logMessageTemplate, map); ListView.Canvas.TextRect(R, x, y, msg); // clean up map.Free; end; {******************************************************************************} { Log Popup Menu events - LogPopupMenuPopup - FilterInitItemClick - FilterSqlItemClick - FilterServerItemClick - FilterDataItemClick - FilterErrorItemClick - CopyToClipboardItemClick - SaveAndClearItemClick } {******************************************************************************} function EnableStr(var b: boolean): string; begin Result := IfThen(not b, GetLanguageString('msMain_Enable'), GetLanguageString('msMain_Disable')); end; procedure TSmashForm.LogPopupMenuPopup(Sender: TObject); var i: Integer; item: TMenuItem; filter: TFilter; begin // rebuild group filter items FilterGroupItem.Clear; for i := 0 to Pred(GroupFilters.Count) do begin filter := TFilter(GroupFilters[i]); item := TMenuItem.Create(FilterGroupItem); item.Caption := EnableStr(filter.enabled) + ' ' + filter.group; item.OnClick := ToggleGroupFilter; FilterGroupItem.Add(item); end; // rebuild label filter items FilterLabelItem.Clear; for i := 0 to Pred(LabelFilters.Count) do begin filter := TFilter(LabelFilters[i]); item := TMenuItem.Create(FilterLabelItem); item.Caption := Format('%s %s, %s', [EnableStr(filter.enabled), filter.group, filter.&label]); item.OnClick := ToggleLabelFilter; FilterLabelItem.Add(item); end; // toggle copy to clipboard item based on whether or not log items are selected CopyToClipboardItem.Enabled := Assigned(LogListView.Selected); // rename toggle auto scroll item based on whether or not auto scroll is enabled ToggleAutoScrollItem.Caption := Format('%s %s', [EnableStr(bAutoScroll), GetLanguageString('msMain_AutoScroll')]); end; // toggles a group filter for the LogListView procedure TSmashForm.ToggleGroupFilter(Sender: TObject); var index: integer; filter: TFilter; begin index := FilterGroupItem.IndexOf(TMenuItem(Sender)); filter := GroupFilters[index]; filter.enabled := not filter.enabled; LogListView.Items.Count := 0; RebuildLog; LogListView.Items.Count := Log.Count; ListView_CorrectWidth(LogListView); end; // toggles a label filter for the LogListView procedure TSmashForm.ToggleLabelFilter(Sender: TObject); var index: integer; filter: TFilter; begin index := FilterLabelItem.IndexOf(TMenuItem(Sender)); filter := LabelFilters[index]; filter.enabled := not filter.enabled; LogListView.Items.Count := 0; RebuildLog; LogListView.Items.Count := Log.Count; ListView_CorrectWidth(LogListView); end; // toggles auto scroll for the LogListView procedure TSmashForm.ToggleAutoScrollItemClick(Sender: TObject); begin bAutoScroll := not bAutoScroll; end; procedure TSmashForm.CopyToClipboardItemClick(Sender: TObject); var i: Integer; sl: TStringList; msg: TLogMessage; begin sl := TStringList.Create; // put selected messages in stringlist for i := 0 to Pred(Log.Count) do begin if not LogListView.Items[i].Selected then continue; msg := TLogMessage(Log[i]); sl.Add(Format('[%s] (%s) %s: %s', [msg.time, msg.group, msg.&label, msg.text])); end; // put stringlist in clipboard, then free Clipboard.AsText := sl.Text; sl.Free; end; procedure TSmashForm.SaveAndClearItemClick(Sender: TObject); begin SaveLog(BaseLog); LogListView.Items.Count := 0; BaseLog.Clear; Log.Clear; LogMessage('GENERAL', 'Log', 'Saved and cleared log.'); end; {******************************************************************************} { PatchesPopupMenu methods Methods for dealing with the popup menu for the PatchesListView. - PatchesPopupMenuPopup - EditPatchItemClick - CheckPluginsForErrorsItemClick - DeletePatchItemClick - RebuildPatchItemClick - ReportOnPatchItemClick - OpenInExplorerItemClick - ForceRebuildItemClick - IgnoreRebuildItemClick - PatchesListViewDblClick - PatchesListViewKeyDown } {******************************************************************************} procedure TSmashForm.PatchesPopupMenuPopup(Sender: TObject); var bNeverBuilt, bHasBuildStatus, bHasUpToDateStatus, bHasSelection, bIsNotTop, bIsNotBottom: boolean; patch: TPatch; i, patchesSelected: Integer; sBuild, sRebuild: string; begin bNeverBuilt := false; bHasBuildStatus := false; bHasUpToDateStatus := false; bIsNotTop := true; bIsNotBottom := true; patchesSelected := 0; // loop through list view to find selection for i := 0 to Pred(PatchesListView.Items.Count) do begin if not PatchesListView.Items[i].Selected then continue; patch := TPatch(PatchesList[i]); Inc(patchesSelected); // update booleans if i = 0 then bIsNotTop := false; if i = Pred(PatchesList.Count) then bIsNotBottom := false; bNeverBuilt := bNeverBuilt or (patch.dateBuilt = 0); bHasBuildStatus := bHasBuildStatus or (patch.status in BuildStatuses); bHasUpToDateStatus := bHasUpToDateStatus or (patch.status in UpToDateStatuses); end; bHasSelection := (patchesSelected > 0); // change enabled state of PatchesPopupMenu items based on booleans EditPatchItem.Enabled := bHasSelection; DeletePatchItem.Enabled := bHasSelection; BuildPatchItem.Enabled := bHasSelection and bHasBuildStatus and wbLoaderDone; ToggleRebuildItem.Enabled := bHasSelection and not bNeverBuilt and (bHasUpToDateStatus or bHasBuildStatus); OpenInExplorerItem.Enabled := bHasSelection; // move submenu MoveItem.Enabled := bHasSelection; UpItem.Enabled := bHasSelection and bIsNotTop; DownItem.Enabled := bHasSelection and bIsNotBottom; ToTopItem.Enabled := bHasSelection and bIsNotTop; ToBottomItem.Enabled := bHasSelection and bIsNotBottom; // one or multiple patchs? if (patchesSelected = 1) then begin sBuild := 'msMain_BuildPatch'; sRebuild := 'msMain_RebuildPatch'; end else begin sBuild := 'msMain_BuildPatches'; sRebuild := 'msMain_RebuildPatches'; end; // handle build patchs menu item if bNeverBuilt then BuildPatchItem.Caption := GetLanguageString(sBuild) else if bHasBuildStatus then BuildPatchItem.Caption := GetLanguageString(sRebuild) else begin BuildPatchItem.Enabled := false; BuildPatchItem.Caption := GetLanguageString(sRebuild); end; end; procedure TSmashForm.EditPatchItemClick(Sender: TObject); var EditPatch: TEditForm; i, j: integer; plugin: TPlugin; patch: TPatch; begin // loop through patches for i := 0 to Pred(PatchesListView.Items.Count) do begin if not PatchesListView.Items[i].Selected then continue; patch := TPatch(PatchesList[i]); Logger.Write('PATCH', 'Edit', 'Editing '+patch.name); // create EditForm EditPatch := TEditForm.Create(Self); EditPatch.patch := patch; if EditPatch.ShowModal = mrOk then begin patch := EditPatch.patch; // update plugin.patch properties for j := 0 to Pred(patch.plugins.Count) do begin plugin := PluginByFilename(patch.plugins[j]); if Assigned(plugin) then plugin.patch := patch.name; end; end; // free and repaint EditPatch.Free; PatchesListView.Repaint; end; // update patch details and popup menu UpdatePatchDetails; UpdatePluginsPopupMenu; end; procedure TSmashForm.UpItemClick(Sender: TObject); var i, max: Integer; begin max := Pred(PatchesListView.Items.Count); // if patch at index 0 is selected, exit // we can't move it up! if PatchesListView.Items[0].Selected then exit; // loop through patches for i := 0 to max do begin if not PatchesListView.Items[i].Selected then continue; PatchesList.Move(i, i - 1); PatchesListView.Items[i].Selected := false; PatchesListView.Items[i - 1].Selected := true; end; // update gui UpdateListViews; end; procedure TSmashForm.DownItemClick(Sender: TObject); var i, max: Integer; begin max := Pred(PatchesListView.Items.Count); // if patch at max index is selected, exit // we can't move it down! if PatchesListView.Items[max].Selected then exit; // loop through patches in reverse so we don't move the same patch // multiple times for i := max downto 0 do begin if not PatchesListView.Items[i].Selected then continue; PatchesList.Move(i, i + 1); PatchesListView.Items[i].Selected := false; PatchesListView.Items[i + 1].Selected := true; end; // update gui UpdateListViews; end; procedure TSmashForm.ToTopItemClick(Sender: TObject); var i, max, iIndex: Integer; tempList: TList; begin max := Pred(PatchesListView.Items.Count); // if patch at index 0 is selected, exit // we can't move it up! if PatchesListView.Items[0].Selected then exit; // create tempList tempList := TList.Create; // loop through patches to build new list iIndex := 0; for i := 0 to max do begin if not PatchesListView.Items[i].Selected then begin tempList.Add(PatchesList[i]); end else begin tempList.Insert(iIndex, PatchesList[i]); Inc(iIndex); end; end; // set PatchesList to tempList PatchesList.Clear; for i := 0 to max do PatchesList.Add(tempList[i]); tempList.Free; // update selection for i := 0 to max do PatchesListView.Items[i].Selected := i < iIndex; // update gui UpdateListViews; end; procedure TSmashForm.ToBottomItemClick(Sender: TObject); var i, max, iIndex: Integer; tempList: TList; begin max := Pred(PatchesListView.Items.Count); // if patch at max index is selected, exit // we can't move it down! if PatchesListView.Items[max].Selected then exit; // create tempList tempList := TList.Create; // loop through patches to build new list iIndex := 0; for i := 0 to max do begin if not PatchesListView.Items[i].Selected then begin tempList.Insert(iIndex, PatchesList[i]); Inc(iIndex); end else begin tempList.Add(PatchesList[i]); end; end; // set PatchesList to tempList PatchesList.Clear; for i := 0 to max do PatchesList.Add(tempList[i]); tempList.Free; // update selection for i := 0 to max do PatchesListView.Items[i].Selected := i >= iIndex; // update gui UpdateListViews; end; { Remove unloaded plugins and plugins with errors } procedure TSmashForm.RemovePluginsItemClick(Sender: TObject); var i, j: integer; plugin: TPlugin; patch: TPatch; begin // loop through patches for i := 0 to Pred(PatchesListView.Items.Count) do begin if not PatchesListView.Items[i].Selected then continue; patch := TPatch(PatchesList[i]); Logger.Write('PATCH', 'Plugins', 'Removing plugins from '+patch.name); // remove plugins that aren't loaded or have errors for j := Pred(patch.plugins.Count) downto 0 do begin plugin := PluginByFilename(patch.plugins[j]); if not Assigned(plugin) then begin Logger.Write('PATCH', 'Plugins', 'Removing '+patch.plugins[j]+', plugin not loaded'); patch.plugins.Delete(j); continue; end; end; end; // update UpdatePatches; UpdateListViews; end; procedure TSmashform.RemoveUnloadedPlugins(patch: TPatch); var i: integer; plugin: TPlugin; begin Logger.Write('PATCH', 'Plugins', 'Removing unloaded plugins from '+patch.name); for i := Pred(patch.plugins.Count) downto 0 do begin plugin := PluginByFilename(patch.plugins[i]); if not Assigned(plugin) then begin Logger.Write('PATCH', 'Plugins', 'Removing '+patch.plugins[i]+', plugin not loaded'); patch.plugins.Delete(i); end; end; end; procedure TSmashForm.RemoveUnloadedPluginsItemClick(Sender: TObject); var i: integer; patch: TPatch; begin // loop through patches for i := 0 to Pred(PatchesListView.Items.Count) do begin if not PatchesListView.Items[i].Selected then continue; patch := TPatch(PatchesList[i]); RemoveUnloadedPlugins(patch); end; // update UpdatePatches; UpdateListViews; UpdateQuickbar; end; procedure TSmashForm.DeletePatchItemClick(Sender: TObject); var i, j: Integer; plugin: TPlugin; patch: TPatch; patchNames: string; bApproved: boolean; patchesToDelete: TList; frmDialog: TForm; begin // see how many patches the user selected bApproved := false; patchesToDelete := TList.Create; patchNames := ''; for i := 0 to Pred(PatchesListView.Items.Count) do if PatchesListView.Items[i].Selected then begin patch := TPatch(PatchesList[i]); patchesToDelete.Add(patch); PatchesListView.Items[i].Selected := false; patchNames := patchNames + #13#10' - ' + patch.name; end; // show multi-patch prompt if multiple patches selected if patchesToDelete.Count > 0 then begin frmDialog := CreateMessageDialog(GetLanguageString('msMain_DeletePatches') + patchNames, mtConfirmation, mbOKCancel, mbOk); frmDialog.PopupParent := self; ToggleFormState(false); bApproved := frmDialog.ShowModal = mrOk; ToggleFormState(true); end; // exit if user didn't approve deletion if not bApproved then Exit; // clear details grid slDetails.Clear; // loop through patches for i := Pred(patchesToDelete.Count) downto 0 do begin patch := TPatch(patchesToDelete[i]); Logger.Write('PATCH', 'Delete', 'Deleting patch '+patch.name); PatchesListView.Items.Count := PatchesListView.Items.Count - 1; // remove patch from plugin patch properties for j := 0 to Pred(PluginsList.Count) do begin plugin := TPlugin(PluginsList[j]); if plugin.patch = patch.name then plugin.patch := ' '; end; // delete patch patchesToDelete.Delete(i); PatchesList.Delete(PatchesList.IndexOf(patch)); patch.Free; end; // update patches UpdatePluginsPopupMenu; UpdateListViews; UpdateQuickbar; UpdateStatusBar; end; procedure TSmashForm.BuildPatchItemClick(Sender: TObject); var timeCost, i: Integer; patch: TPatch; begin timeCosts := TStringList.Create; patchesToBuild := TList.Create; // get timecosts for i := 0 to Pred(PatchesListView.Items.Count) do begin if not PatchesListView.Items[i].Selected then continue; patch := TPatch(PatchesList[i]); if not (patch.status in BuildStatuses) then continue; // else calculate time cost and build patch Logger.Write('PATCH', 'Build', 'Building '+patch.name); timeCost := patch.GetTimeCost * 2; timeCosts.Add(IntToStr(timeCost)); patchesToBuild.Add(patch); end; // free and exit if no patches to check for errors if patchesToBuild.Count = 0 then begin timeCosts.Free; patchesToBuild.Free; exit; end; // Show progress form self.Enabled := false; xEditLogGroup := 'PATCH'; pForm := TProgressForm.Create(Self); pForm.pfLogPath := LogPath + 'patch\'; pForm.PopupParent := Self; pForm.Caption := GetLanguageString('msProg_Smashing'); pForm.SetMaxProgress(IntegerListSum(timeCosts, Pred(timeCosts.Count))); pForm.Show; // start patch thread PatchCallback := ProgressDone; TPatchThread.Create; end; procedure TSmashForm.OpenInExplorerItemClick(Sender: TObject); var i: Integer; path: string; patch: TPatch; begin // loop through patches for i := 0 to Pred(PatchesListView.Items.Count) do begin if not PatchesListView.Items[i].Selected then continue; patch := TPatch(PatchesList[i]); // open in explorer path := patch.dataPath; ForceDirectories(path); ShellExecute(0, 'open', PChar(path), '', '', SW_SHOWNORMAL); end; end; procedure TSmashForm.ToggleRebuildItemClick(Sender: TObject); var i: Integer; patch: TPatch; begin // loop through patches for i := 0 to Pred(PatchesListView.Items.Count) do begin if not PatchesListView.Items[i].Selected then continue; patch := TPatch(PatchesList[i]); Logger.Write('PATCH', 'Status', 'Toggled rebuild status on '+patch.name); // if forced up to date, set to Ready to be rebuilt if patch.status = psUpToDateForced then patch.status := psRebuildReady // if normal up to date, set to Ready to rebuilt [forced] else if patch.status = psUpToDate then patch.Status := psRebuildReadyForced // if force rebuild, set to Up to date else if patch.status = psRebuildReadyForced then patch.status := psUpToDate // if normal rebuild, set to Up to date [Forced] else if patch.status = psRebuildReady then patch.Status := psUpToDateForced; end; // update UpdatePatches; UpdateListViews; UpdateQuickBar; end; { Double click to edit patch } procedure TSmashForm.PatchesListViewDblClick(Sender: TObject); begin EditPatchItemClick(nil); end; { Shortcut to delete patches using the delete key } procedure TSmashForm.PatchesListViewKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if HiWord(GetKeyState(vk_Delete)) <> 0 then DeletePatchItemClick(nil); end; {******************************************************************************} { QuickBar Button Events Events involving buttons on the QuickBar. Events include: - CreatePatchButtonClick - RebuildButtonClick - ReportButtonClick - OptionsButtonClick - DictionaryButtonClick - UpdateButtonClick - HelpButtonClick } {******************************************************************************} procedure TSmashForm.UpdateQuickbar; var i: Integer; patch: TPatch; sTitle: string; begin // DISABLE ALL BUTTONS IF INITIALIZATION EXCEPTION if ProgramStatus.bInitException then begin QuickButton.Enabled := false; NewButton.Enabled := false; BuildButton.Enabled := false; ManageButton.Enabled := false; OptionsButton.Enabled := true; exit; end; // BUILD BUTTON bPatchesToBuild := false; bPatchesToCheck := false; for i := 0 to Pred(PatchesList.Count) do begin patch := TPatch(PatchesList[i]); if (patch.status in BuildStatuses) then bPatchesToBuild := true; end; // enable build button if there are patches to build BuildButton.Enabled := bPatchesToBuild and wbLoaderDone; // swap hints sTitle := GetLanguageString('msMain_BuildButton_Hint'); if not wbLoaderDone then BuildButton.Hint := sTitle + GetLanguageString('msMain_BuildPatches_Loader') else if not bPatchesToBuild then BuildButton.Hint := sTitle + GetLanguageString('msMain_NoPatches') else if bPatchesToCheck then BuildButton.Hint := sTitle + GetLanguageString('msMain_CheckPatches') else BuildButton.Hint := sTitle + GetLanguageString('msMain_BuildAllPatches'); end; function TSmashForm.GetSmashedPatch: TPatch; begin Result := TPatchHelpers.PatchByName(PatchesList, 'Smashed Patch'); if Assigned(Result) then RemoveUnloadedPlugins(Result) else begin Result := TPatchHelpers.CreateNewPatch(PatchesList); Result.name := 'Smashed Patch'; Result.filename := 'Smashed Patch.esp'; PatchesList.Add(Result); end; end; procedure TSmashForm.StartPatching; begin // make and show progress form self.Enabled := false; xEditLogGroup := 'PATCH'; pForm := TProgressForm.Create(Self); pForm.pfLogPath := LogPath + 'patch\'; pForm.bDetailsVisible := false; pForm.PopupParent := Self; pForm.Caption := GetLanguageString('msProg_Smashing'); pForm.SetMaxProgress(IntegerListSum(timeCosts, Pred(timeCosts.Count))); pForm.Show; // start patch thread PatchCallback := ProgressDone; TPatchThread.Create; end; procedure TSmashForm.QuickButtonClick(Sender: TObject); var smashAll: TSmashSetting; smashedPatch: TPatch; i: Integer; plugin: TPlugin; begin // STEP 1: find Smash.All setting smashAll := TSettingHelpers.SettingByName('Smash.All'); // STEP 2: if Smash.All setting not found, exit if not Assigned(smashAll) then exit; // STEP 3: find and clear or create smashed patch smashedPatch := GetSmashedPatch; // STEP 5: apply Smash.All to all loaded plugins except game ESM // STEP 6: add all loaded plugins except game ESM to smashed patch for i := 0 to Pred(PluginsList.Count) do begin plugin := TPlugin(PluginsList[i]); if SameText(plugin.filename, wbGameName + '.esm') then continue; if Pos('Smash.', plugin.setting) <> 1 then plugin.SetSmashSetting(smashAll); AddPluginToPatch(plugin, smashedPatch, i); end; // update application state UpdatePatches; UpdateListViews; UpdateQuickbar; UpdateStatusBar; // check/fix smashed patch status if smashedPatch.status = psUpToDate then smashedPatch.status := psRebuildReadyForced; if not (smashedPatch.status in BuildStatuses) then exit; // STEP 7: build smashed patch Logger.Write('PATCH', 'Build', 'Building '+smashedPatch.name); patchesToBuild := TList.Create; timeCosts := TStringList.Create; patchesToBuild.Add(smashedPatch); timeCosts.Add(IntToStr(smashedPatch.GetTimeCost)); StartPatching; end; procedure TSmashForm.NewButtonClick(Sender: TObject); begin NewPatch; end; procedure TSmashForm.BuildButtonClick(Sender: TObject); var i, timeCost: Integer; patch: TPatch; begin // exit if the loader isn't done if not wbLoaderDone then begin Logger.Write('ERROR', 'Patch', 'Loader not done, can''t patch yet!'); exit; end; // exit if there are no patches if PatchesList.Count = 0 then begin Logger.Write('ERROR', 'Patch', 'There are no patches!'); exit; end; // calculate time costs, prepare patches timeCosts := TStringList.Create; patchesToBuild := TList.Create; for i := 0 to Pred(PatchesList.Count) do begin patch := TPatch(PatchesList[i]); if not (patch.status in BuildStatuses) then continue; Logger.Write('PATCH', 'Build', 'Building '+patch.name); timeCost := patch.GetTimeCost; patchesToBuild.Add(patch); timeCosts.Add(IntToStr(timeCost)); end; // exit if no patches to build if timeCosts.Count = 0 then begin Logger.Write('ERROR', 'Patch', 'No patches to build!'); timeCosts.Free; patchesToBuild.Free; exit; end; // make and show progress form StartPatching; end; { Edit smash settings } procedure TSmashForm.ManageButtonClick(Sender: TObject); var smForm: TSettingsManager; begin smForm := TSettingsManager.Create(self); smForm.ShowModal; smForm.Free; // update UpdatePluginsPopupMenu; UpdatePatches; UpdateListViews; UpdateQuickbar; UpdateStatusBar; end; { Options } procedure TSmashForm.OptionsButtonClick(Sender: TObject); var OptionsForm: TOptionsForm; prevLanguage: string; begin prevLanguage := settings.language; // Create and show options form OptionsForm := TOptionsForm.Create(Self); OptionsForm.ShowModal; OptionsForm.Free; // update owner draw if changed PluginsListView.OwnerDraw := not settings.simplePluginsView; // rebuild log because some messages may have been enabled/disabled RebuildLog; // if user changed language, update language displayed if settings.language <> prevLanguage then begin LoadLanguage; TRttiTranslation.Load(language, self); end; // update gui UpdatePatches; UpdateListViews; UpdateQuickBar; UpdateStatusBar; // if user selected to change game mode, close application if ProgramStatus.bChangeProfile then Close; end; end. ================================================ FILE: frontend/msSplashForm.dfm ================================================ object SplashForm: TSplashForm Left = 0 Top = 0 BorderIcons = [] BorderStyle = bsSingle Caption = 'Mator Smash' ClientHeight = 300 ClientWidth = 600 Color = clBtnFace TransparentColorValue = clWindow Font.Charset = DEFAULT_CHARSET Font.Color = clBlack Font.Height = -11 Font.Name = 'Tahoma' Font.Style = [] GlassFrame.Enabled = True GlassFrame.SheetOfGlass = True OldCreateOrder = False Position = poScreenCenter OnCreate = FormCreate PixelsPerInch = 96 TextHeight = 13 object imgSplash: TImage Left = 0 Top = 0 Width = 600 Height = 300 Picture.Data = { 0954506E67496D61676589504E470D0A1A0A0000000D49484452000002580000 01520802000000A1773670000000097048597300000EC400000EC401952B0E1B 0000000774494D4507DF0A1216092FFDA4DA3D0000FFFF4944415478DA7CBC07 9C5D57792FBADAAEA74F2F9AA62E4BB62C5BEE4DB8601B83E9840448203790F2 CB4D7909099740CA0B2FEF92040381000910724320A10730C536EE96AB6CB948 569DD16846D3674E3FBBAC7ABFB58FECC7CBBBEFCE4F1E8D8FCEECB3F65ADFF7 2FDFFAD6C613A3B950E65DC3DA446C18CEB4DA49D1A5341CD6419B2D4CDC5E78 CF5FBC918785021B7FE61F7EF4BDBF7B30257D6749FE44A7B554AF2B62142648 615F13C618A7284913A33542C82024047C430A21429036C8C0FF6164FF333840 9AC33FF9148982AB90224DC2F4B6DE812D61D8CF577BA368DFEE2B9E6DADBED0 6AC4AA32BBB4B091248262A54DF7D769F6175C122E8EB24B62837EEE8B74DF07 A3800F241413820D0C4BDB91C0AF51027F08C3149BECD70CBC87B8AE6B8C9152 6A6342C5538304258A328CA9671043063E5F52C38D329462CC7C3740B22CF89A 83DA9B4BEE046213B4EC09E20FA7EFF9F835FD577664E030354063AA88768867 6442184C8E87754E9246D28CBFF1E183B33F210D9F9CCEB766D6F28970B15F87 81DBF93376AA60C48EE3C077957D99EC7631228CB2BA6A516676F9C37B69D189 E6872F951FFA875F33BD31F69C8597D32FFECE7F242F87C7FAD9CC46ED6CB5A5 357608C6462B6C2F6B301618C3D5877C7F7BFFE076966E49DDF1ADC5DBEFFA45 7A61C574B48B50C75FF5195AFCD1FC437FF9705115965B67E631598BC94C4CE6 0C6A514589743576B1132232E5E9711255503A38B8E9F6778ECF4FBFB46B64B4 520E8C2B5347609FC0FC53EA60C60C71612EA356F3EE7F6BD66688871A738D95 15A7B78906A488096E484A53E26ADA41BC89A212423D79AF3964E21167D0A724 189E7DDB5FDEDCB37F8CCBD4950DC4584A2AB0181473091F6317DC906EA84140 C0EDC28A1A8D8554EDB64E39D606F38E34867A0EF55D985798698C094C38A32E E7228ED3E75F3AB27FFF657E8F5D770CAB0FC3C60E0408222E218E368E21107D 046166D788BA367C605D6C604390C1FFC270608221FA88D2140681498A751F4C 3EC212961E3E0F91B6FD25E3210A7FC5067ECB14115188D68DD4D854082E2123 106A20DAC64820E3DBF740A29914A114316CEF526781DE8D6102835159C0C305 E1838CFD5CF88147F6FDAAA94493180E516F243112C29A19980A25CE9D3A565D 5FDD7DE965D473A552D4F1E2947B61005900B78DB5549C2391521B38DAC4AEF6 620841B78310531AB3EAE11A5A8983716E064528F290C4C2AB6135C47595E88E 2B8A11721491A57679F970E35C45EFFDD33B134FE67800975EF89BA3877EF862 0BE0C329001694425EEA59D975F17027CA3FF978ADCA9D73F1C692E1D3296BD2 22CC86921C6E49C24F5AC14230E6424608CE15BC625F8374C552499D7DD96537 0856D7663A257639B219B7C98D2C162146B8D2FDBDF97D83035B1231D0EA4C8E 84E5AD4167A0FEBA0FDC521972EBC13A2E4C3BD5FE473F964E7F7B362C88651A AEA99E4EEBE448980CBA2328F2774C96AEBE2B70FBFA61AD4DE8631F0660338C 6A6A5F814FC5CAD86580A0384D6B5B7EFAA917FA23B17733456993ABF242153F 7AF04CD4CC99247DE36DBBFB7A164DECBF34D37C79235AE9141AEBD8373AF485 EB3986E93BEED83AB1654E9379E60C27ADD0CF169A421ABA42A1C410662C0613 02608A0473F3A2EDFCE8EE97D7AB95F68A68B6D98A22B3C63DDD501B9D98CBB6 17602728281C3854C9B4A1B816307318268AA12C768D862881498279B3A06BC1 9DD298F9BA13391C700A4190694219F3FA82FC783EDCE4CA926E8EF5D09B0E5C 72F091A766669AB8585830C191B87DBA1535530489D1E716B6549CA99CE88FD3 5DE56D774C68265A7E508E056754629E042690C68B29CC9CF41DE7A9134B2FA3 BC9B2FE678CB71CC0B4BF38BF9F0ACCA9F5E4E56DA9182F4A61AC661B31E7930 1EC6120B6E123990BB984056AA0CDD61FD5D06E9EE12A9A32895C6DD5C92BB8A FD03D81D1AABFEC65F5CDB7BE9AEEDDB3E87378F965C0EA0473B4C36549A77C8 45BEBF53E21E21D86074C707AFD879C7F6A65185FAE8573EFA85930FAD24B46F 16872FD7AB0D91509701D99954390A4083A60CA54902F0020381314809E98632 ACC972B4CB56C4A2BCA381208D455C5586687168B3BF60B6F68C0D32B7275EBA A892EBEF1BFBC1F1132BB97C33CD9D595EA8F3543278237C18B137FF0ACFFDFF 1061F7B3CE7F1A651688E1CD598E007664E901E44800D232A8045C81DC726CEE 4376C16F393CE1804014429A3A88798478766E95402A35905F8452D7A36E227C 86DB05DCDCD5931F56C130AB60537FCD2FECB8FEFDDB7965853314B01E003A65 80CF3C8400892452C0AA4009AA35DFFEE70FFE6CF990570FD849DC98A97A89A4 D86D53005F1B8C304C60441BDB16CB33D2EF2639C02C73DCA682E040BB82A18B 5081256777BDB6F8FEFFFE365D8C8008CF1D8D3EF3FE6F3867065FE8D3B3D5C6 7CBD0DC80FB181B0B25103C16330F00D366AC0F5B654FA77387CABF0C6B6155F F7895F24179571C7C0EA2461CDA778E581B3F7FDF97DB44A5BB2BAE1F86BB199 4ECC598D9B1406A68008A92121C213AEDACCD23249B76EDB7EFB2F6D79F1A987 770C0FF7E47DE54A13628E387320691C3B0A500F860AC1EFFF4675E1251E1231 D75A3D83C2255950463AB403294768E092C443314DCAA9F094591BF7D0B033E8 005D6C597DF3FF7573B8BD47CAD4534DC45C41CAC0100C7345FC0CFF8DD51119 F87405858D1398BF3851ED480B4165A2316281870103B4E5CC8C0D6D404156C3 8FE716971CD71BDEDC6F89D06A28176000B4130405C004A0BFB154078163C518 2C85A5A12CBA2C055ABD04539C6120B08EA1360889403AC0A016ADB4C965249A 66BFEB2B9ED01090129602325910604AF82DCD6C70EB941009F201180D1B9669 20715EE0018DC0D580A1E17A1214099512341BB5F80557B56FB1F765795A2708 FE5822EC10F8C1860055DCD8CF81200632A8AE9F3C766462EB8E7CA9083146FC 504A8E999508709FA07235E7580A0C3C039F1931E3C0EC199ADACCE3ADB87EBC E3A714F5B48351E2701777A8A035A4FA84AE53153BA21021081451EC54160F37 4F7BD1151FB953F73981CC25EDD68BFFEDB1D5176A1D4D003CE0CE067A50FF70 737C5B51A4A5C71FDF58EBD073BCB1AC93E99454491E26488346C8D85EEA0C51 409D6863D52106220406544882E0115D16ECD29E4D7F42BA3AF25511AC6C8C58 790259592CB8BBFB7BB71B3AA194231B3BAF186D159BF92DE8EDBFF686762009 3EE752CC1687BFF9E107970E35692EBF24DBA04A705B4D56467C24CA9E7FCB17 CAF9C1019839E33940840A3E027432CE52D84E77168EB05E64895507961F4F17 0E3EBF6B20C8016AA426D6E1634F2ED656031DF38B7607BBB703CFB346DB7DFC E86235296D34D284D7E1B699DBAF052FE7D66FB9B16FC7CE52A2DB3076172B87 84102A3007D4D502B81066DA73EDADC132FA21A8AD170E9F3E7D6A536FB178DF 7DCFEB70702E7197119B595BDB88DACCC361BE0490CD00929228494151081827 030E41704D006E4BE68C6140456B663213638803F88825B710EA394253296481 BA3B7A7A8689ECA3919B560F5CBB6F6424F8C1F70E6D74825611CFA86826F256 EA700771C9D19395DCD65C7E5824638EFFE62D418F0F00EBC145084AA9548E01 1A07E16CAC34A5CEE3A7164ECAC075BD4117980CCDB4375E96EA2C2ECC6EA885 6A8B23A9201D35722C2704D28A9E38CB75E4808205884716EAE08EC03600867A 0E801093DCE6CA964ABAD5ADE452B46D4FFA818F5D97DB3EBE65F33FE2CDC33D 4C30583FEE9A18A57D81B7C70D367391D7F53DAF1DBBF38F6EE4FD29CBBBF33F 919FFD937FA24DBFA62B6790FB72633DD60294284498E69229421DC61DC83B1B 8B282342083FA93346A219DF58B8E91AB08C7B327411288070EDCBA53B07DC01 185CA24750ED0D97EF9A5F6FFDE4C4F27ABE7731D2732B8B2D017A157745302C 8BF579FF5B223C6F3E33336A69D0BE011617A63853E41951DB64228056369DBA 4468D3C64A65ECA9540280519869C07A1C5006760404A580D907B90270481D08 BCB64425576EF2D349CF99F08665331EDF8D7EF5CFAF0BB6C06C6BE482BB96D4 0A2717221690CE313ED22ED7DC25C1A9FBE6FEFD630FB7D64B55DF3919351762 1A4B9821EE382EB503A6D98C9D27EA2CF3BB446E531A5127D689EFA85D616597 CCD3F4DC35EFDEF4F60FBF56172404F3F2C9CE277FF96BDED94D877BD333B5D6 7C3382E0661679853533F67A4C6544D8CFDCA94AEF2E924E297FD38ED21D77BD 93EC2EE0083B92A661131C3E7FB17EFF5FDE174D831FEFD40C594BF5742C4F4B 55CF160F1C8D4B58CE980966B6B8B2485A975DB36FDF6BFA9E7DECC18B27A78A 8193E214E7001DACAF06F2061423410864034AF3F03D9DE30FADBB98CE775A27 0C9EE51E64B6EBC49E9D7C168A78306065678063BFADD77A715A31BD2EC3953D AD5BFFE42A36E603B679BA0DE9A84805169512AE337B8533A8CBA60C022C2342 5868485CB00EED4EDAE9B800EB0EA3393F8B476CB1558045348EE35BA563611E C88F211F56DE0685FDD9D21EC00104829B7DA7D60E5A4105D7766CEC596EB3CC 674B11C64A514B84D6C0D1F305073B084B72E0EDE0C58CA460B0148C8DE46DE2 BAC6F21AD112860FBF1883A7B0590386129095D870B5E16E5416093A0B770A41 6BB31D4294A7D6F498AECE3CCF01F87C3E80DA4C90EC18D9D20A8C297C00E231 0748736DEA82AAD68B33331BEBEB3BF7EC76021F78C48A44902CA0B6B388C382 1BC1ED3B91554F46274ADB6150442250A78BDC75BC48AFF54F5650C211AC348A 902C0905DE3065407890744414E2CAF28BEDA3A279E51FDFC126434F061B736B CFFDB787C98AB3012E1C0C8CA1E323605196C7B6968DE97BFCE0CA4A032DAB74 4925A762BD8A434B84D95A82C7D799D4C776AA6D72805C11200740BF2A2484E8 0AD9AE05EC4EC52B44787E72949D4102360A28C375F06431B72B5F18C7284C9B 855E75D92D3BCFB45EBAE18EAB761ED8041840F329729CA547D0F7FFEC39B328 712E5E4E138C4B39242A3ECDA3DEEBFFCE1F1E1D862101549B80608F2512BC14 0583D6754D3050659345A21A330BECF96F3E34E15506F2857652C561E189A76A 8D8D1E0770519DBAE986ED0E16498CE617F5F169B19EA473ED731D1C68351E52 C292D98A135FBC67ECA24BFA7A46DB52AFA9D47369099B5083BCF63A9A360C5C 08870685109A7E11D7ABED877FE65D78E1E8C183479E7FAE8DF2634B4A4E775A 338D66930BDF63A1E3BAB6E0042A31069D0ADE19E64A886C322D7D1BD7A1BE1F 40FA4865438A8112B36E84438CD3D0078814510A44B8290886B01960BC8CD2A2 6BEE7CF3E58BB39D7BEF7F9E17BC5ACE9989C27335BCDED8F09C64BC124E857D A35A0C90C61B37E537F7F50131D90511A96F099868F880CC9AAE29F3E899A5C5 D4CD31676B6FC1256855C58FAE6F9C65C5D9263AB7D68A0D2C8D763279AF902B 6C7C7066B5E179E487FC731CE6853E50A1E220B269E0BB10C80E72B6163B93A0 AE9A62DF75FE7B3F7A1919EA99DAF62F78CBD0A063700A41E480B830239EBF83 84C349B354DC78DBEF1DD872E72E4E1A6EC979FCAEEAD73FF7C300F5ACA1E2C9 549E6E5705C84B6A81C6704D14D10CA70079A0B73324B210939528326D4415EA 5A2F8B54D6E1604B84608E38F21CCFDD52D1DB73A4D7C9055174C548FEF28BA6 EE7EFAC52355B68CF3D3095F5C5B8D80A06C450877B3DB169E5E09EBEE7DFF7F 89D08253569FA05D69960108B5B042BAA962553DA5DD72A87581408494D87701 FE2901A8CD6192ADF5362171FCACB62841DB398EB0B3E95A054A4585C95D053A 2C7519979113BFE1D7775CF68EB2642DAECAAEEB132705AD4A9D40B34818E5EB 32D2A09A85AB077EF4170F3CF19DE9D82D2D613CDD48EBD8440AC410784DFB95 A1AABD25ADCE2BDC4C509CFF824170AD736EBA2B97DB96E6995EBEE9D7275FFB 1B979B1CA0B6B73E5DFFD47BFEDD9FDF7CB83F9E0647D8E818ECB8049680C3F5 88B1051070BAE0398008B7F4F4EF26E9B8F24777946EFBC43BC805791C114FF9 328CB959F7D6F1137F756FF5702369F33AD735AE66787A5A8A356CC7C0809011 2A1A34E5D02957F878FDC0EDFB2FB866E0D0A30FED1C1C2DFB2E4C12A73C2B8D 02D3407861C81FAE94EF79271EAE3FF79373211E5895EA85B8732A552AF49568 16B0EE47C1A0C6FDA0B05D8F6387B304C8D4EBB8200F7AAF94AFFDC8357408C4 88622805BB66708FCD1B705D26130D56829B2E00669C90A17657064571D46E92 38717D9FE543AD25B84F6B1E81516C0C418613EBE5AC1EA2CAC9A80C6C165020 D83EFB1DDEE59AF35ED04A7E20606C9CAC92943125C6D94A753558B7C0042F51 1BB454644591CC255822CCEC96E543ABE84810182EAC4CB3554D100D10AB102C 24FB68FB39526A467DABE96005690C4C4474415B84175D1F48B2EB5A4830AF48 C2CC988271B42E53A55AB795888C4CEC9521DA8DF199ABA20482013CDF4BCF3F 57EEA96C1A9FA00EF86F8023984F9C8D1B1921B448485664E620E8E254E93461 263461726215C54687AC5E5D19991A41B2293140A321103C3A2260D179902200 289E4F4B2B2FF3E39DE6E5FFC7EBDC6D3E4DE9D2D195E7FEF4A05375DA0873E3 61A12EBCA0A2E899DEC1D0F3879F7C627171DD54115BE29D63A9584670416505 30EA428BDD32B0363A9332F007B819B2CCD8BF14E4327CCFD68E74EDE0F9F479 E50BEC39FC7B9AF973B09745876C2D855BC2FC20067313EDBE7870FBE5433F7A E4C93FFCF855DEC4681AD7B513E4FC1D87BE78E4B14F3F334A06D6D05A95820E A4155C2CE1D2D59FC84F6E19577104008E73AEC9FB300926ABB6536D23123C0B A49C40AE9B2A1092C77FF8123A47B7F40D3A7E3DD1FA85A3E8ECAC3F31DE77FC D823575EBA79FB44256E2D51D37FF8700B38F0647BA58673ADB857C5ED817CBD A010EDE03DDB7BF75F57EC9F6CC6919089CA79FD405BD84D94DB06AB6EA84B69 5E28E9E7AD9EBFEFC7D82B36766FDDFD4F9F7B20059789DDB398BCDC8A96DA4D C8DE821B1080230E18CCE00B64509426DDD9CBF64F20675DCFF320446DCD19A1 9CAD8858C5611C5B2C05C7231289B92E61B2ADB7D4ABC5908369DC1A1FEDB9F6 DA6DCF3CF9F4C933A8E50FACBBE85C9CCCADC4B18C072B6CAA5CDEA44DAFA9DF D61BEC9B18533CB24556AE7CECA7B6206B021085C43B1AC50797C06B857DCC9D 2C873E366B32797875E58C579E6EA833AB8D1449D7370EA0778A5250BFC42A3B 08114AEDDDD8ECC7C80DFC6E9D4F72018630177A58630F3993FEEA1656320D75 DD1BFADFF2FB5B75B977EA82AFE3ED83C3104EA996D224B9104FB8B929E9E5DA 2BFB0FE4DEF47BD7F83BCA90EC88A58FFC79FD87DF7C20D5E5AA537AB1519F8B 1B86210F23800D887F2B06198A89A4F667D3D5653A2BE864760C02C3FAED4CA0 657468F118315B5127FD456F67AF3FCA4891A7DB7CF3BA4BB73514FFF6B3A756 D270C3E49F6D77366AB5C4D67AD1F982A8C6AFEEFF9D977919F6FCA7E2A8BDBE CD87AE3A3C4F8AB674967D5955CF6CCDD4E68610DDDD38307A5D2D8FAD4DD0D9 AD2018BA8F8907130C3809269B80CF831B071065AE2BFA5DB5CDA5A3C89551F3 92D74EBCF9F776CBFEB3B02A54962980178500D2802B92B525882E5E924ABB25 46D607FFF17DDF5E7C99D78BCEB4347335193B22D560F7EDB25922CC1C61B72E 8A50775B23D3C4F6159D6870AE5EC16DEEC9BB9B13C8E58D5FFEABCB76BE692C C1D463003A0B7FFFABDF71CF6C7961309EA935CE343A12CC879D0405EBE0C0AC C02DC00C4A18BCBBB5B7EF422CC67430B0A378FBDFBE15889024C84BF3A91B27 78B598B2239F7B78F6C12516E7D6D6EA4DADCE297152264B1AA5D4B39B085A96 90D94A9D09477A74E9E6B7EE1FBDA074E4A9A7F68C4EE428663EEBA8C8CB3318 337318CC1E0E80DBB4E7BBEB27F913DF3D992E97635238A13BA7056FD8BA74BB A0F804CD6DF38B81E634A72178E338A5889BAAE3FA4EE57A7CE347AF2265505C 8A1A011C824CC95669896059C5AC6B0A4D06E216BC61DE9420192C229E269D8E 6EB6BD5C087C0C3E01740F4C2B4F12C7F34033423C20302756278143F44986A6 8838D6D8C1F76CDEC04CC30F19296644A86D88195B0565D6A358AC062DC3B22D F1CC1F5AF9E66A4028882D98749B2AC6FA425B688294001EF357D75607470791 041106865EDA418324A2C27E9A840FCA2BE5C2CA27A201BACA09B02DC0F21069 01A027D298398053C2C9C2DB526B46E7F616C0F700ADDAFF9748464A76A48AB4 8A61CDB4E4441950015944E0A8BADE68B77A7A7B5D3F07696933D3528CDDDE32 924332839584EF1D820B31647412F93ACF0BD1B3E74051A415BC31BDB8697433 CAB513DA729ACCCE8A0491C8A860898E354EC334BF76DA9C5A6B5DFA3BB77917 B898E3734F2C1FFBEB17C42A8FECD645116B71F9FE817AFB48AEECF7F56D79FA A9B373CBA665F20B49FB789ACC6347C2159903AA05682EDBFD345D8B87B3D166 DBE7B000E4E776D36DEE405E4BEB65347EF50B42C5EE325A816B174ED92DD3A1 9237952F4C79FE08E244AFBEE55D375593A59A5A78EB1F5F2782B6E43DD42BA0 583D71D7F3D35FAB865E7E23DC88352D93A22F934BFFB2B26BEF4E5D5F87ABE2 C0C13D65000BAB47C052779519B694284989E994AC556BCF36971EAF6FEDED77 FD0DA9F5DCB9DE470E2EEEBF72C7B1971FCA7B43375DBDC5358B7123595E715E 5E50A7DB7CA6014BD5C3752AE552AF170C93813270704FFDA2ABFDAD5B07A2CE AA2D65525F694203988A4E8A236C1523ACADE37B959933F2B1278FBCFB3D6F7D E9B1633FFECECBA9D3B7E8955FE6EDB97615245DDE098D546922148300569CF3 6E6D0C0606DA0B500858D0755D9C293C5B81605469983CDD2DAAC12A0012C6A0 2C311A2EE6C7C26010A10AE8B846EDCAAB725B4673071F6C4EAFE4453F5E40D5 85863FBF2EFD406C1F0EC6992946E975797ADDE6B11C4914E80401581944109F 0E385CF8B4DC63EB8D831B358FE6861D7F24E716295DE7D163D5F53341F96443 4E2F573943BE9B154652C4216019B87146323DABA5BD8B42A14019E35ADA2A9A 92E07D03CFA78815309B74E63793224B9DD7BD6FDB35EFED1541CFE60BFE1DEF 1C1C514052109F22AAB87A9B5FD8C4FD3C5A7DEB6FEEBCF82DE3B2EC51B72492 EADDBF3DF7F8E34712AF6F56D1139DE686E61A0BC7C0BA33C021083C486AC027 0C86B92BDB88DDE29259BCDAC9B57ACDD61DBBC54C0DB4821DA09A7E8F4E55E8 E6625842AC8F37DEB0B3E7C289BEFB4E2DFE74B693A87043E1838D4EB3D591DD EDBE2EE5E9EE5FE79B6FBAFC4731F97F19C26CB3C456186926FD882D9F598251 B2FB069259AF2ED34829606C148C74468DF675C0240DEB636537B1318DED1C53 22014E21440CF1895B7073439EE8676A98D01E830746D49DBFB17BE84A9AE01A E0A68B03E0096B201C70A15C308EA9AF4508F0076E7DE9C1CEBF7DE8B1F67AB0 9017A70C596A12039A4E274A7890A0D4566891CE38DBA2B3AD29DB99CB4A5E56 F27760A165AEE86EEC2E90F138EF3AB50F7CE6FAC95B7BDAA9E7B3527376E9CB BFF5FDD63343A746E44CAB3D5D6FB5B985467085AE0B716A67C512A192030E9B ACF45E8CE588F60776946EFDDBB7B00B0292104F94A52738590993F8DCF75F3C F895E79C66256DA729C62B9A9F48A359A95BDAB30D52589595DAE2781398FBE1 EA6DEFDA5718098F3F73E8AA1DE033216700BFB4EB037348F02E20958CEB6866 5C0FFECA3FFADD53679E5606F7CFABF602D12B1C942DCF997802799B59C921C9 E085C5A19191971E396AA16FDD56390A37D01B3F7C09E9E5B67DC39A260F9B22 101A07F79119E6CC0EE157C2C4AA07ABFF0DE430434AF24E8C5AB1930F80956C C122AB27DAE23EB345255B71035999F55621E25AA0B43A1F064F4C561A45E070 41A0587DC54CB6570786CFC6A5CEFEC9D61A94B56510D8B61C26B1DDF6031ECD 192A00A88D0DFAD806B20E2171C136311A9C3CB9D06ED52FBD622F88E138020C E0610E90A643508C815051A0856FCB547677126478706E6EE5E0A38FCBA47AD3 2D070607FA01FC0D00BB915656673553D4F59DC86E4F8ACCABDA4D75931A4019 037F3A48C5C8709382E66240BB76EFD25A47F054CA9283ED0FA29992B0E807F9 62C5A3DDE4104DAC2BDC51286AFB6931AA248FCF05C37ED4A7579F9A9B284F9A 09D9766B4135444C00F3520184602145EBC8D561ED2C79F9F4FAFEDFBC33D8EF 01549DFDD1DCD97F3C9356D30E4421CAF94CEFBFBC6765E3B09FCB4D4CED7EEE D0CCA933BCA57B56D3E8B888660D4D6015990332412402160306ABB35293DD73 B195BB6C6B0CC96E9F4C77733DABF28957CBA4964111CA321BDE4EB212301076 0262250C9DA19C7F41501C156919B52636177EF583BFFEE92FFDF3C577901BDE B5477316C3F487529C8A9FF9EBB9B30F22EC57AA7A3574A51F99893FC4076EBC DA3456B0B6DD7CA45CC2E5BC04050251627785882D875395B2BC6712B5BE61CE 90999F2D4EE62AD42C12E66DD4C77EF6F0C9C9ED65835A332FB76FBA72D7705F DC69ACA4893E36C74FADD1E975D3447EEC98164E61218648BE9F131A37CA03E2 B2FDA35353D4F75A14D49506CD6D675E3A4DC312C27CA38A8E9B4F90FAC1F7CE 5CB26F72C7B6D2D73FF7D889D33DF55CEF59D638DDEAD412EC38303E704B3EE8 1598329053C6763330982B70068C5A0A042CF21DD701F5048C032E32ABC8D9DD 6F69CB1A30A7B112114F40878D86F98930DF8BBC025E2EB1F435976C936DF2E4 732B0D37BFEEC56B989C5DA78D584C0E93C950143AF402C36FD9323216AA5446 8484BE0C1211915032FBE9C57B17AB4FD61B399A1B626428F406FCB02ED34757 96CFE68BA7DA6A66AD114346019280048024863163DB40C52074791A7738AC7A 7F1F90324B786283396BD7CC5A68F000F576E5D6C751E020EFEDBF77C9AED7D3 D8EDDFBEE79B78CFD0A6D424048251C4FD8EDCEEE447A5DF5B89DFF5C77BCB97 21532C3B78B0B634F7ADF71D3E75AED629F49F8CF92C7C164091E630551EA4B7 20DCE20DE6D4E637CAAA799874FB6524975929D3D84AA9AD34667169751A5004 63170EE436BBBCCF0D49CC2F1F64BF70C9A092E9D70E2F3F59F500E0963AEDA7 3BAADD894DD7E2BD5AE530E815C03B4F84CC56B16C02C00BB633447777CB4DE6 47B30A0AB1AD4F4E66F9BA8CF2EA4642574802019EAF4B52DB24A3EDC608F020 0499F55F161E3D978381E09C199247AC922BED66A24875855107356F7DF3D8E5 6FE991418DD39050603FF0312E7640C081228D99D55C0EC70EF141DF060F7DFA B9A7FE7539E1A569969C347435252EE813B039B67D28CB5BA584B20EC22E2EEA 96F66CD5CAD6C0A916D8A7B298672BBBF362B49D2F14D3F77DEAF24D3717DA51 CE65251627DFFED0FD2F7F4B9C1D44B3517C7CA3DE4C2D4078A1E37A607988C9 441DE8E15E4627CA958B7532827295CDB9DBFEE66DC1DE0211C8498B9C88C45D 298A66F3C58D07EF7A50CC072C31A9321B4A9C1611C440CD04C23652CAA24CB7 136F0CEBB0B072DB2FEFED9FE879FEB1272FDFB28B718988341E5548B8A023EC 86351837E014BB69EBE58A2F3DBC7CE49E0E16038B496319CB756552244B944F 527F54E71569EE78C3A6894DA30F7CF911E6E5CD3A4C260DAF2737FFE9E5B4B7 8D15CFF6E5800873B62F938A40751B4448B7AE9311A12DF2E84CB8DACE4188C0 94A39883D0B5FC6085A3CCB08A80FF67800AC876819AAE11C481554F38E311E2 D8AE615B0E85D1DB1FECC694155E59478CEDC2023CF62C6F51BB6E804A3030DB A502A2C8026101510E0863AD244AB2B6A702FC0C0E07F0EE91879EDEB173626C DB908AC5CFEE7D09E0F9FAD76CF18A467620DACBD6E03A4DEC240679CB0BE6C8 F31B5FF9F2F75E3C72F8231FB9E31DBFF45664918B5BBEA6C8CAB66EAB6216EC D98FC0477694F627C3914980053149785A074567B80016A4B6E7DBEA345047C0 85700B32F304E78B63C6268175BCB69E235B88171347D0A8E325A57A8F7A6A91 6D76D201BD78CFF4241DD3173BF5B05A5C2B68A74194EFC81054B0E42DDBF583 BDCEAA7BF8A9854B7FF1D6E2AD7D48A6D3DF38B3F0AF4B3A1231D5090F3C262E B93CDF8CA6857676ECDA7BE4C553478EB46233B696B68E8BD61943DB407D8E23 607EB9B40C9FD546A5DD20B17D03386B1A00630168D3CDEBF3EDDF5A77B3D9F6 9766559F6E6D48DAF9B1151EA3C10C4136E9E162719B17EEA2DE80898C587BE7 BBDFC8F79A27EEBEFFEDBF7E5DF10296F816467C87252FD0EF7FE444F31821F9 0D435B5E75A4F281E5D7BFF946D45E4628E5E05283BCD35F524E5613B79B55D6 1F23AA9BE0715C6CEA0DB4884FDE333BA8F33DC03EDAB4A3E1279E9B8B546DC7 AECD4F3D7CE6C29D43BBB797198469BCB1B4D13A394F561AC533F5A81EE03925 5BDC2922334AC500C04B64F2B9E89AAB86F6EC06C1BD41AC2E0B142CBD2715EB 007D3110E7A0DF0BFCD003BDADF8F4CDBF3072F4C1F51F7C03D794B31C54E7B8 7FB689B85B073451D1A0716A00995CA4902B94657B4AD46E108041D0DC2E4F00 9C0384C73CDBEF01F3990A08772C2D667262AA69DB7148A0D1A6B03418964782 69B7E18F79A5EBF60F9E3C3B73741647F99E35DA5C55ECECB2C8FB665B1FED91 FE505CBF79B4677F9F1F9BB666B9200DB04AA40F2A0D70A674CF42E3703B0A99 5FD2B2D76763F9524BA44FAE2ECFF9F9338999ADB6DBB61345FB5696DA31295B CECF5A23B3FD7150A6611052D7E14290AC59520A01690EDC3415162F2CB647B5 753DEFF8E0E52307347746B6EEFE3ABE68788CE3046C0E48B531078D6B32A89D A131F99E3FBB4A4FD682DE71A6C7A69F7EF1EEDF7D7A99A373CC3F9D8A4591A4 40BD220584702401A9CFC154DA5A24F240A3DA2ABDEA6A530847BBFB8A2D51D9 F652AE60CAEC6E86D002E1FE726E5FC51D27DA95B8CF676FDADDBFA797CF37E2 6FBC509F917D5591CCB6AA473A8673715EE9FE6F89D01643A4DD8CF16DA753B6 3F69F13F7B27B662D071DD00440DE9EEDE647CACD4AB5B08DD2A6AF7756ACB99 B6B5D4762864F21E2C247219B27CA64178E515EDCD972E5569DE0575D9DCB937 F7A6F76E0D06D680A10C2A669E81DB86430CE6030B9652D0DFCA4D43835D8ACF B1AF7DF49EA517E1D5BE13697C54E92A62392C20A225A8DD57B60265667C6D1E 5B9368256F4684804C2A358EABFB8A646977490EB7F38323EC039FBB32778949 45D97016B8F4F14F1FFEDE5F1DED0C14CF7271BCD16C091C718E332B16321728 42DADE475D2178BC54BA58A763B4E8F599DB3FFEB6BEEB47818469E40BA212B6 9A230DBA669EFBD233CBCFC6E95A236A0B30A3F32A3995A46B2817615FE3B46C D29D243741901F2EDEF4AE3D9591FCF143CF5F343A15DAFD362308C08F72EDDE AC0161A05D92956921F29DB559F4C05767713C089261298D16B96C229527F176 BF30620072EB7BDEBD6972D3D0FD9F7E5C4A27887A6131BDABF08D7F7A993BD0 34320691406D3DC8B54DB00C3999C13BBFAE992F54DDAEAAAC65C2927F662150 92D589B3ED665039C676E176ABF7D426914D26DBAB84703EEBA6EABEEE5AAAB1 45D1EE36614690B6400A960281EAB22D33CAB1B847ED05092A6A05CE1E2C5DD3 5A1059C44C086E18F590B586C8C83CE86CC8F7F5F5C6638F1CBAFD8E9B8240AC 576B9FFFCCF7EE7CFD9D7B2FEBE76283C145741EE417F5DA9D56F5473F7AEA2B 5F3C343FDB6AB5D42DB7EEFAE4A7DF9A2B54EC698A4C6DDA6031EA95A630DCAD 8E1A5B57A0A8DB5666BB5D800BE36C8BB1A364078914D890D82D55BB819E6D47 67078CBA9B9CDD0BD909B3449855F8548AB9D7A1605C63A793DFA8E86756CC14 D6E3B8F1B3A5F25A485F33D80C57F2AB81F49A94FB182C3ACC8E48904C242C7D 523AFCC0B9AD575D32F0DE1D2A6D9CFAA799E64FE24EB31E811C3365D74D2EBB 326827F38D26DABDF7E2B9B9B34F1E5CE66A5B95B74E8AFAB4664D2563E67018 AF322E386A0B294A902E4BDB72A775FEC4EEBD74456D57E9763768BA4AF7FC66 A1DD4F855B62D4FE811F758AD3049BD0619BFDF26E371C07099CAC968BFE1B3E 7541F531B4BABA7CD31F5C0C08251A0A74BBEFE5E6EF693D74D753F17A2BEF95 D06A5FEF07966F7DC3B5862F60D5D6C44BB14B4A795674ECCE06402060AA9D7D 7084160B5D9992AA3A79EF2C9F8EF74C8C2AD130A4F7A513CD432F9E3870E0BA E32F9E49C9DA0D575F1C260627F5248DCECCA727E7F17C249668344FE9725456 82F6858D21628644BF886B43BDFAC0D5C3BB763025562DFAB29C0067E4DA3824 1E216E62F268E9E8DE479FBEFFE6B780ABDBF2B5CFAD9E3B17C7815CC29553B1 A892358D42D5DE64E882CB6C671F20234028041328425B18D1B61BA527B42689 612DB497221449D58A53984A172C2D780330DEC4D6FA9080E475FA8BBD9B0B0B 61AB30A8729B07E2EDBBFA0F1F5D3C32AF516FAECAD46AA4D737DA93E59EA130 28C5D56B0BEE2DE3BDC64B3AC60912370731E6B425C3D524B87FBE792C058189 60D27A1C676BA5B7D66A1D8F9A8B5E3097E8A5B6AC0A90B13006AC39B00AE421 02999FF33C0F242D06EEC38CB0AC59535B8D9B55381CD09E528D61E782201E50 CAC9E9B77DE88A41307BFED6F15D5FC6FB8687532C206572586F76D924C2659D 6EDB57B8FD772F32E371501CA59D4DF77FF5A7CFFEFDA946989B61EE917AA306 A1E6D24ED48210F400E28D75A6CAB6B0D9BE82EE36A06D96C922D2D628409203 9E1B6CF9D9D62490E638F0BC2D83DE362A4799235BF10DBB276EDE16A064E368 9DDE7DB4B920826529A63B8D53F5343B16F6EAB1889FDB1844FF0F1D765B606C 0B3881D9B185529BD5AF901C4409CC820B5F8C6408A8BBADD5DDE19DEF9DB155 54DC4D1B660B1BD6057631D3767C6AF020867AF0FB3A27740591A162E59224F6 3DC8FA95B77D60F7AE2B3C60073FD7630B9910F7F0467BF2C25666B98758027E CF4F7382F8FED243F51FFCF5A3ED5AB16AC293B1396D709DEA9C017563120522 4C827705A9959D96C888303BF5D83DFF416CBD4B742472454FC5DDD85DD4C351 38384A7EF99397F4ED073952318A792199F9CED217FFF0C118E517889949552D 552DCE6311C3FD876E002393D63D890A369B8AE54BB118C739944B5FFF7FBF73 F0D67190072C7621A323B64AE4AADF21A77F7C76F6FE05548D57E7EA42782B3C 9D51FC2C670D1C0ACA7B51BA93065B0873FCD5ABDEBC757C67FFEC91639B4BBD 9E32CC23B10607C6DCAC5F05C40FC9799D240E83C0F1898EF28F7CF7ECF26944 FDC23A4FCE71BD92763C27DDEA16C65159E61A97FED7A9ED7B267FF467F7AF2D 24E564288D44F9DAE0863FBBC219AA2A1531309B8E3D8C016250674DDFE7AB82 D635E36EF374762053E16CB70E671DA4D9AE2FE936619E5F7AFB7AE6EDECFB98 E9D2092A6417CB3A3F33DACBA427ED76CD58C56721185B674DBBDBD70180412A 22D7F544923FF2C2ECD0687E6CC2D386135DCEAEECC22A02F629C01456A02C07 4B7DECE8F4E1E74EFCC23BDF013EFD91871E79F9C8DCFBFECBAF61DC666E8C74 6449D8EFBDEF3F1EFFFBCF7EE7E927E7D2D408832A95E0339FFFD09D6F9B5471 6C5B9F8082454A198524CB8C30E92604D110E7F62023C98E37A2AC0D07618E88 30AA23451B740E503492D99FAC3B3EA389EE8923DC4D2ADB82605BF850B7DA08 F08C53B0651D4E3BE146451C5A9653C69962FCF15AE7D966FFEB76B68A1BB9A6 AFBC1A8E7C948262D0940B10BF11EB04A477E691666E70D3A6DFBE384D565FFA E451F394DB8AEA1C64A22A074172E5F5B946E7DCD28ADC7BC9DE5663F9A9C7D6 D6D7065B283DA31AD392D4C00F3127D1F6C8728841E6839C91DC1E8DCC24AACC F6856DCAA24C798BEE1E61B771E6E7CB3FB63DD8522FED760CC3A45913E4DA59 DB1496B7BAB9CDBED34712D9D998B8A9F8BEB7BFF7DFBFFDEDC28EE8CEDFBC45 1391706E0294738A47BFF2D2239F9B099B432EC7EEEB97DEFA8B0750AE619275 CC82543ACA63615F681CB838A0906F3BDB90140E2C10F75DA99BF1B947974FDF B774FD9EDDD4AC602F5858CDFDC7F79FBDEEFA6B34AF1F3C7AF4B6DBF76F721C BDD6809B5A6BF0974EB7CEC564365D5F72F462DABF58F734AB0D797C4A578AAE E7A94E7F981CB866F4826D1EE70B0E73B5721DB7A04842DC16F1810843DDDCF1 CDEF3CB2F51274D58D37DCF7BD9987EF9EA3EEE039A966693A933605EE31BC42 D01AE96EA8236B9D21456C13B5C63EA3058FF4FB6E08624BA64594AFF2B44AC8 6227AEF3D4A14EE8F91A241EB23D4AA9E08097857C796BDE94941CA381DF695E B26F7064BCF4E3075E6A8ADE34A4EBB8516F525F577A3C5AA6ED7DC4DC3A562A 94495BA15CE2414A70D68C7DB6D4711F9CA9CF23C601F15452266457DFC87A6D 6D498B0DDF3F17C9358E57B86A6849B34E1E905CDAEE66D0D0F502E6DAAA8E3D A990F56F339A45820024F75D0F1CE1B8413B5C5416516E94BFE38FAE2AEEA028 D835BEFB0B78DFC83047C09CB242C956C799242A87EA57DDB1F5AA776FE703B1 17F69BE5BEAFFEF7EFACDC5F5B0BFC93AE73BA93345301F92F6D4735586B6AFD 350613651B036C1525B36FDD1A7DB73E0B73F44A2B735796837EA75B077B47BD 64CAD561A2464BC5D7ED1B1D736B4D8D1F3A2B0F9EAA6F18671EE1D39158A8D6 6DA1DA1E8F3D5FD9F84F6D605D2EC4AF1C1CA4191CDA4D1F93758A66C7BBBA8E D09E37052A009B9FEDFDE26C0B8EBE6234B3CA89FDA8AC6B9349092E57658DEB 5967294CB6AD7218CFA80AC240DEA3F9E26EC553D5D87175F1965F1C744B0D8C 7214F9C8E5868216CF6B6A0FAEC0D01397BA128CBF93D03808870FFD8F938FFE CB915817CE19369DD005E4C4847B5A7A80345A726B6A6D91566724DD6D7E736C 1FA9DDD6C356F9CB04602D29569CE60505331CF9FD23FA7D9FBCACE79A5CD2A4 9E9F239E387BEFC6FFF8D0C3F18ABFE4D15985169A9D58EB48DB550BA8CF88A3 6DCD5C14B4992816F762BE99E4B01BBFFE63EF1EBE634AE114462DB1EAE8658F B67C49EB2F452F7EF7C5419A7FE1A193BA1D823C9FE19D93295ED17EEACA3E9C 6C47EE361AB8CEDA45378F5D74EDD4E9E75F180E0A15C853046825890B214A6D 01D17315C56B1BEBA11B967B0BD8EB3DF5F0CAB38F4102F7D653B56AF0994E9D B2740B2B8CC8A22C6E5CFBA1A9CD576D7FF253CF1F3B7836ACF6634E833DE6C6 FFF3DA704B5BE8C8B6ABD3C01E767BB547B37B90DDEAC80CD86D3FCBF902023E 7F64E1FCCB5654A0EC790C962049D6E7D2F579D6536ABBA15CC82216774F4A00 7E6687301C5B1ACDAAA3D9895D78AF8F400903E6B13C606F2A3BBE57DC5875BE F4856FDE7060DF55374E195133BA88ECA620B0B34024B67556048BCB40F03CFA F0B30E2D5E79C5F5605DFEE44F3E7ACDB5D72A232EBF72F7A6910A73D0FCECCA 57BFF4C3CFDE751FF8CBFEBE711033F5D6F29D6FBFFAAE4F7EB0545EE9BA1F64 B2CE05DB30F2EA7E5897D9BB1BE54EC68DBAAB0E90ED8916B6462A3A482758C7 582446717B0D73BEE315BF325D192F5AA59F99E4CC6C930825AE3491206DBF51 8C9F5B439B883341C8B164F5E1D5A1CBA6F826C1529490752FCD53E149939248 526EDA411BA2B6FE246D74D89E8FBE26F59AD31F3FC29F71EBF13A7770C2CB81 1F5F7DC06FA56B3333E9BEFD7BB4D978F6F1B57367073A389997B5B3D25991A2 462807FDA159CE96A3652C93B606BF09A0CD98AD7CDB9D2BC063F34A2E773B48 6DD3B5A54AD295B93065CC2EB5AB34521C7832B595550703C7157D6F2CC88F39 6432C78A480669F9B51FDCBE6937FBEE177EF0FA77DC34764B9F24CD3455C453 A4E61CF952EDE4B7AAB843F8DE995FFEED37A2C29A414D99C22C8600147E9F47 4A9EDD9382F85476835662668B3AB449D2884FD3E7BE3DBBB377A4925F97246D B647EFBB77A1B7B774E19EDC8F0E1EDBBC6DE2AA5D1E5D8B51C7EFA462AE2A8F CF9B9966BBEA264B3A3C59759679540EE56637F48C1974DDBC16C3617AEDE543 DB3633A3EBD81EE70E14E64E101B92E05CD1719D871F9C5FAAE33BDF7545ADBA F8CDCF9E6CAF4FD658EBACB371ACEE6D8822F64C48B23D20637503F8415B39F3 733CE1058A2D6331351038266AE5C03E7B5EDD0DCE44E9B976142913F83E02E2 8C3BB6DC42ED232100BC260BA5F1222B763A83D4276AE935077662E3FFEC67A7 4D3E58D3B50EF6755AF129E9F1F566DEBA69B8303E944BA50CB81BC0925090C9 CE744D3D7CA6BEC6722D9E860C5510DD39345CDD586D505DA7743D318B895E10 664549633B4D209D24E015E033D8308FD09052D0C8B62A07E04B332726EDC334 324F61B65133857245D3D874297AF3EF5DCE7A10CA5D34B1F773F892D161FBDC 0825FA18DEE6B8E324CDFBEBB7BE67DFD4CDA3A2C2F3F9FED6A9E02B7FF6BDE4 889977C9CB0C2F7019735B4F01B969CBC9D2969DEC5E0356CCD8AA323A7F9AD8 70CEAD4563346BDF92E70B2F5991B3CF732FE8AB8CEAB41F2779C50F5CB4E3B2 4D8E4E966AB4EF1B4FAD9C6A9996CB8EB7C4C97ADCE24977ABD3AA3C84F57F6E 0E7D9508B3B3E2E8BC24660C2C20CB0A9BB612F6AAF90BC3B0DB29DA85BCEECF 2CFBAEB33D4C982CD77A6B10AA202352B880F58A8482DB05F4538A87464EF8DE A4E30DFB7EBF6AB9C5F61B7E65D7C08E86A12963832AE6340F961EB47A1933B0 A61C036FB92E96AE7D860026BCD5F383BB9E5A7A26114E78528B1329AE6B5761 C9807EA815D0C2229A45AC6E31C79E79CD5634EB06B2CDD8F0E614FEA193ABB8 9D5D45329A867D43FCBF7CE28AF2D5816811E2B9209D375ED4FFF8473F9547FD E59C3BABF1F446B329055877B8A24B1C87BAD861205141826D2A16F661B995E6 3C4FDEF6D1B70FBE69A7400D07A114EE44D75C27A242B375EF9E2FDEB3253F74 ECC1B9CE9CED84382B9BA7243D239C98A95E166D9578172BB84E7BE7B52397DD 3271E8D18787BDFCE4D040C463E45390052C93417E2E9F4891C4BCDD680F0EF5 7BE5DE8DE9CE63F79C4669A51DA35569CE8A8EA27C332B0CA421EEAB5DF7E1B1 B11BA6E67EDCBCE70B0F94EAA39E0A555FE3A63FBBA67409CC51C2740E804640 EAD923845687D90E424B73E74F9DDB3E7B82CE1F25B46D9AAF365965988F75B7 B9B4BBAF963D8D283BAB6E3BEE2024427B42C7F24AD6236A4F233819053A9616 2C166781661B8AED6173A35DD04D9E47A3043FFFF4FA173FF79DFFFABBEFDA7F 75C5A0861139834A00D41AA7104712E09B4362D2D9B9C60FBE77DFEDB7DDD953 197AECD1A78E1E7DF9C65B0E1C7AEEA13FF8E3F7761A9D7B7FF0C2173E75F7B3 47A7C77BC37CC9CDE57ACE9D5B0709FAAD1FFEF5F5376DE79D69429DACC7CF26 9E5492521B27AF7650A3F3FBA49E6D0CED76979DBF79E07E3050407E6D241A48 B7AD51579944E83E91C7D68ABB9731D9A1556B2A09CBE691B570021492081AF9 51B17668D91F666C14B1BADF7EAC265D54B9B857AB4642EA4E9427124089D398 614E3A008046ABE78AA78FB72EFDE80131ACCEFCD5D1D613B8AD6BF6111CBCC7 715A571E7030E3875FAC5D7CC9CE30D77CE1C9FAF4F1724AF8825A9F13FE529A AE1322684011F3602D144F0C6FD9C2AB257A5B8C5288DB5DD2EE3E08CECE53A8 574E109E57935D04C854B2675B6A05DCB8CCFA3F30975A1ADC9BCF8F05CE1478 2086A71ABDEADA63BFFA9137AF3E1EFDE4C78FBCEDC3370D5FE4A248344CE4E5 343DAE1EFEEB938B877BE9A633BFF45BB793D186D4EB7031AA439926B4609CC1 0272A8449EDDD7D0890521C789F5060357BDEA9FFA492DD7D09BFA3B915C576A D74B2FA0E5C5B3B7BF6EE48967D4E2EAF2EB6E2B1461999A4C71B4D6C22F9D22 7355BC665A1B549D49BD39AE231917A92E103C1C04E3418136AA43B9E4A60393 93E33E322D10B876370590C7C5C0694E61697D75FC07DF3F77F5EDA3BB2E727E FCF585170EE68497CEEBD513CDF26CC75385A480DDCC3DF394A79008B942094C A011DC15E9708E8D7864204017EFDAFAC2938F4B16D4B1BBA6BD997ADC711C61 9598149D0E049FE3F9202BA254145C365EAC8C38B40FC78C57CBAEBA7ADFA5EB 8B1BC766E622D76D33AFD6E661D053F1586F5CBDA2D7B978AC0F6C87AB98A339 2883D4758FACC707E7EA75BF5C8B79D973FA10DE393454AFADA52EAAA6BC29D0 626ACE2832AF1504806B1F73042E56A7361334B06029C8E55D8F663534DB6B61 6B6CE71FA71230B205F331D95B721BFBDF5CBCEADDDBEC667A78F1E47E4B8443 B6594E8A2146B6B9EE26160F0ED55FFF1B57E676E6799E178A7D0B4FC4FFFAB1 07F1626EDE2787355F003B68DBE4906D0EB3BB901667ECC15FA25D611B24B2E2 93D59190EFD23E0FC9B635DB673F48D56D25F5FC60AA4CA688338EFD926AED1A 09AFDB3A34E4B522142D8ADE6F3DBAB480BD65479DA8A5A757DA69D6F782FFD7 65D19FE7425B3CCC4E48234B5B04BB36C6B3C4B632C99A5529841F065D1C2499 43EC928D93FD9C1590EC0731CA404764A964B7999875898EDD5C8777589F8EB6 E582294AFB8195C8C6150706AF7F7DAFF156ECEE032B82F2334E6ACFFE938038 9EFD5498063F4CA5F290719CBE630FD7EEFEFC8BACD617617644778E4B9D6A90 5B1C398995B660A0B223F3CA741BC48DDDD2CD7C2ACBDAFAED8222613BF9A2B0 E4A43B423C2AFC524FEBFD775DD77F850B5CA3605DBD843687BEF2A11FAD7EAF B35C70E7997BA6DE5EED74B86DB133A0105C6068CF818409241FCEE5F711B19D E403965EF3BBAFDFF29E2BA4534328019907F645A986035655F53EF4CFF7E8B9 5A4F676AFAE12529D132894E1B728ABB0D22FADC782A953B6DEF5F3279E9F081 5FDAFDDC03F781D7DC313919F1C80476AFEE7CCF89E3728D5DD75B5F5E7783A0 D4578A9AFAF17B4FB54061E9E29A14B332497132E9F6F4265E6E2ABEE62343BD 9714D213951F7EE23E79DC0B554915366EFCD09595EB5C4EC18B16011539B5DD 4C8EA6CA3E32203B3CDA3D59937544995759F19597B2033876CBEB3C66668DA6 D9A65AF6E43E42BBBE8991DC2B8506482827A3C9AC53C66447EC2D2FDAB75152 96B295EDC7055201D3FB8F3DF2DC57BFFCD823F71FFBA77FFE9BAB6E2809B542 50414B977AC6EEC1E03CF5CAB56A73667AE31F3EF7ED8DB5164CCCC2E2FA9933 A73FF9A93F9F9E99DBB56747FF20FDCC5D5FBAFF47A790E8EF2BE60BBD0DCCAA 5AB9F3F3F17BDEF7BA8F7FF2B7305DB104665BC332CDA9B3C69B0CE2CF2BBCF3 E60E06FF0A119AEED37368F62BC81E47D12DA46A483530681E99E597ED0D53F6 A2BA9B6EDD7D356DB9D6820AE60C6C8907F29AD3C497F9E543E78A3D813B4608 0FE4F3E9C2CB7393578FA73DB1310DDA0C6CC3AC2B9C348F12DA72E70D1385E3 632F3EBE36F5FB97063BFD131F79A6F104E67E9C5070147D84D6F65FAB7B06CB 4F3EB932BEB97F6C4C4F1F91CF3FE3C5BAB3411AF3B1339726AB9809EADB9D20 05EBA422CC239098247B2A408A34D78228D0BE38EB4BE8EE0E7659B05B1AED16 8132E900A04DEDE332C00329619B7DC19E7B61C74E0FEE77F1AE5C38EAB0DD9A 2D3A736F78FFCEEBDEFAFAFFF8F47796EBF577FFC1EDB9E14E83B73C9F065C2C DEDB7AE01F1A8DEAECF56FDABDE7759B38D9404084A987C10B903AEDF749A990 821AB74193207B6AC94F7044599B2FA9EAD39ACF34370FCB4EBACE9CDD67A783 A32F3C73D3CDFDCB67071E7FE6E80DB7F58E0CBB7CBD638FD0C6DECC229B5E52 73CDC6BA11ABD4994FF1B924AD89A488F468E04DE6C23EAD8B2A9A1C74AEBB72 73A99C50B763CFD129E3FA2102FF5A58A6EC827FFFEAE9A109F69A378E9D391E FDE06B4B1B555343E96CEA9F4E58CB070D0FEE18CCB44839771C2F5F2C3BD4F3 01CF92CEA0678688EC67FC377FE55D67AA47BFF5ED2782306C1BC85677B69DD6 4091E0AC5866452101944BB9359415E68F876C30E0BD9095F5F6544F78D59EED 475E9E39B5D2427DBD1B691471F042C5BC68ECCAA9EBC6077B49A665C1B9817B 66CEF32BCD27573B35B7D488449FE70D20BCA5AF37EAD468CEDD68B7EA915C16 6486B2D35AB78CF130784CDB3C15530CD91B109267B044B6E59A760FDA28C128 40BDEDF6085CBA8D7486E24DE55CE3D6DF1C9C3C90D3C227B97D53577E1EEF1D EC234E48951871E956E68D79D1D864FB8EDFBA928DBB919F14C3DC897B56FEE3 B3479CB5BE69A69ED1C9AAB04F83A2B6E1C148FB200F2B3835B55D449E3D60E9 758910B01B74167061F7A003CE8CB7EDF552BA50E9D95E4EB721D6D3290C05E2 F6CB47B7BA6D47ACA705EFF09CBAFF706B29AC9C409D73757E76B595583D9E29 FB570E0EEA9FDF2C44AFEE1EDAC76B741F3E633BC06D474CB63D6E2B14F6B03C CB1E2263FBA9EC316ABB97609B1BEC2FD97E53D43D5F9F6D6012FB7C4691F561 C3F2D85D239D1586E0BA2E52032EDA990F3629556AA5C5ADF937BF6B2AEC3BE9 B8D2AE884B2551C8F504B10FF7A4D4B72E92A41DEA09AA807A3C3570EF978F3E 7977BDC4C7AAEDCECB6E72C2966673013866B709CBA5631059D2B6C0819EE8EA F1ACA4C36CB1EE7CABA282B1D9EE835C898A6D011991AE5F587BFFDF5E377A75 DE8027F789F612966C7AF8EF9E7FF6E3C7CE159D737EB822CC62BD0A702101C8 896BE7207095911E4F4672B98B30BF80E4B168EE7DEF0DFB7FFF76936B1A1325 BCAD4DAC7403C8DC477D67EE3FF2C8BFDDF3CE6B3FF0D8179F6C373B2BAC7D54 9A691D54C1D3877C2A4E76E122C4D0D8DE81EBDEBBF7C4A3F7F3EAC6EEA9CD12 989D59DC825560C0E9AE679F49661F93651637D6FB467A73F9CAE107CF9E3CB8 5EA4836B42CEE1B4A53AE36E6F2972FB2F3457FD693FDE9214E2BD2B3F5C7DEC 9F9F7363AF85E7F7FECAF885BF7A21CCA72B4AC809524B85862A0AAFD8DDBC57 3608336223D9FFD967BDBCFA943F83BB8F8BC25D27685F54DD2A62F6BC18921D AE83D046B9AC5BC4AE7FD6ED49B3A7A9757B641C20C2EC317FF0CF3D5CB6A895 494127497239FF4B5FFCF637BF7AE8B927563FF1993FFE955FDB67C81A567920 11600504D7343DCF3D79E6BBDFFDE9A143F34F3C7A46511AF3165C68EF85939F FDFC47BFF8A57FDB58C7870E1DAAAE3643CF0F3D9CF7ADCACD79B995D566A142 BFFDC3BFDBB52F9FA44BD9136B0840AE639F024314C835963D3430DBD1B67C96 9D0554D8B575D1ACCF12DE664CB7E507A208D4731B999A51555B0297DD1E51AB 1AB3521ECA7657BBED66D25E9659A190781B7E121829B913BB26B7F0D4424F29 703701917864A9FFDCBD878BDB7CB29751DE719A21B1FBEC09890A60DDE3C2BC 6051F1E8E4C1BB677B7F7DDB961B364D7FF4F9EA1388E7E284682106355ABDF8 0A39B16DE2D9676BD8ED5C7461A1BDDCF7D803623D598EDCE45CE2CFA5D1A236 6DE550E3780AE8054528E95099C0C04065710017FB14D5576571970BBB0FCAE8 9E01B0BB1BDD62294C87C22ADBDE0537EC0AE5DA664B3FF63C604597B72F025F 88F05627EF24BAB877E917FE765B31B7F7BE8F1D63C3D14D7FD82774ECB73653 E4A23679E9DF4E3FF5ADA3E144FA9AF75E50992A1AE1B89147254FCD9AC88BDC D84802B0A8944704B688100A1FF4714DAF8BF4985B7B6179CBA817755610DD56 5BE979F2E00397EEC37DEEFE9FDE7778684F70F15513C9FAAADB428EC8AD34D0 91738DE98D4ECD3875E49E8BD5F1849F88DB412CC67C72617F7100CB8AD29E8C B66D2E5E79E5484F2FA0493B0C7BEC9391BD06CA77BC70CB23F7AE74A2E6CD6F DCE6578AFFF2F9678E3CA3905F9E339D19E32EC9C04791E4DC1E2FE582DA53F4 79404215758A586D29FABDA65D94C96BAFBEF8E6DFB9F3EB9FFDD7679F98F182 C10D19CEC640CC6A8377ECC3076DCB814E12213952AC5462F158C1F413DA8383 016AFC68F9A2F1E14DC3534F9F3C77AAB921F27E2C505EFAA189C6BDCE4D6383 534E008B94687B4444207278B5F6742DD9A0A556620698334CC8444F59C48DB0 B7506D37D76A9D35E39D22E4A856EB52040685D9B30B3A0C12D1B8F6C83C0E90 EDF6713DE63106633259851F0619B8643BAD0FB6B7944BF537FEC150697722D3 B293DF3775CD17F0256383BE741C94F4FB6A2BF6C71C357C317FCDEF5E40FB60 09CB546CBAFFF3878E7C7365B18867859CE1A4639FD4216D873FB5FDDB4C58A7 024E46D82614EAC2CD6022A82BAD3B9354713FCDB6DB58D0024B0616C4C3DB0B B9B1C0EB4B486FD4B86A7FB86373319796B50C37FCF8B153B3C74EA76D929F63 E8B9AA335B83ABD58CD1E87FFD855F3D5D681FC9614BB5B627DAEEA8656510CB 7E94AAEC442D2C70973203DF0A88763B02240C82C0C95EB74798B3B679F8DDEC C082073704C628B159567078CE9751E8ADFB24DAEC0F0CC6DE580E8CC1F28DEF 2C4E6EFB9F7CBD07B85D577926BCEAAEA79F7B6EEF55BDD82AB625D9C215830D 849E84244098B40990CC4FCA240C102613480833C00C6993022484E200066CDC 5B6CC996255B5DBABABABA57B7B7D3CFD97DEFB566AD7DAE4C9EF9F3FF57B69E FB48BAE79CBDF75ADFF77EEB7BBFF74D72E8C8C96E60629545B48A351198158E 4C445448E3D61E232E6C8805E64C773CFAE5C9EA225A62EC1241D7A52C799460 8A1291103B9E802E3E6E0D496C120125311849AD0F117DA5642A8CA774230EB5 3A2086B2B1578D46ED9CCAFD77FCC1CE6D1F686BB2868037444E1F27E6E6A21F 7FE8C9CA9A13727301800B1E5813753C7689E7AADC008AB8358E08CE6D5AEF7E B8D69BC8EA7E63FF0337EFFEFD77BB6D0E0455D5ABB3A0E98AC24B444ECF2D95 8BC77EFB897BDFF6AEE32F2ECDBE762DCDE8723DBC04C834F74C8D0D857C9B9A 3408EB19EFBDF3E3C699674FE159B47374D42315660418AA3454C2486A4F513D E5BA9E4ED9D20A245AA36F98D4E68C177F52771BC866561390AA15752492AA58 9EC3D15B3EB51BF6D5FD9AAF9ADDDFFDDC71EFE95C21EA053B96EEF8E33E30EA 2A282F0038173B2FD1165A10696E4B7D2CAE85D0A6D6D0E6ACE91B542BB13C28 03E2790532CF853123543C2429FFE172ECCBB3D5783A82781949FA15FF98CBA3 512CE708E52815A4AA54D9937A5452D004F10413A80988659EA6B85D248DCFFC C9979E7CEACAD4F9A5DB6FE9F9C6373F9EEDD41C90D3DD9ED74E4CBD7CFEDAC9 8B93CFBC7062EDFA6A1405060BDB18E8EB6E3FBFBEFEE18F7F70FBC89EFFF207 7F54AE543A0D2D4D685B2A59AC882896AA84A8EC389655BEED4D438F3CFCE786 BA28DE1BD8DD5C0D02E88548CEC86B2A91C418D92513D99C8ADF449547A48A3C 8C1910AD9EA14CFEF21055A5527A14CB1930711F5CBB4160396E3DCB235E9954 99947064F13722E30B0CD63A068E140B795283542C4014AAA5572FAB49138EE4 9B242804343CB954BFDE68DB73CB7A6AAA5D5399D3B4800B2D25E1A71D60850A 4F1693579FB81076695BDEFDC0E96F9D744EDA0CFB6E64E05ABF07967BEF5C1F BFA9F7FACB5173AD3C719432039FF889539C12E027B8CEADC5666EC5D3EAA2E4 C0351157A2400B23C347A2D27622E0C95669885A72842DBCCCE2F16551DF482D 85782C12DCE0C7C9D64214B24D4166394D2A0F7CE269FD16B9D4D0D4CEAEAE5B 9BB4DD6C2267F94DEFDE7DEB4777D69DA99FFCAF976EDFFF40F73D8545E594C6 D44CBD03DAD1337F5C3E7F6EF2E623BD47DED91EEAEB1426B9C598DF600AF1D3 59AD900A438BCA315091B09578A0CC1259D25BD22E1E3F3F3690212CE09E8E41 E6E9674F6452FD7B6EEAFED763178BC5D4DBEFDE9E423328E2C5AA2730F1DA12 B87C852D733C43CB6B913259F467C45E09795233DB72E9CE04EF45DE6044332E 1C1FCEDD7257A71F4CA655AE221C5287D0828F93F5263CF5CAC9C3F70E27B798 2F1E2BFDE06B9514EFAD83D549DF5DC39D02F50684D43CC7713D4315114451A5 42B31C106FD7E8A00ADB9C6A3B40EFFCE78299D8FA8DCFBFD478D1EE30DAAE44 F66C642E3BA4062D0FFBCCD541C45D5A52004544D74D5380EB4E04BA80AA5A56 426D1EBAB92FB29BE7CFACF82459E3C4D5B404300B5678A053DFD38F312B4942 22D65C923E35599E6F2AEB9095F14602A9FD30D3A1090C67F716D26600AFCE2C 2EA8EA826A2C34FCB2ED3534EC1AF1D16C53C437F1584546F7096406C209ACE8 1C51C6B458C85B60395D215BB81470280CD8EFFAF51D5A9F081A2A30778C1FFE 3A3C38DC431C40995330D85625D94BA3893B945B7F75C4D1EA49A5DD5A4B7FFF 0BCF975EE48B1930EB07B33EB6A588861C608A6479226EB63CAE0B0997EE1021 C4A12789CB628789DF41A8B0908672B6B8620781024D0DF4A9642291E95268AA E98E25A24307B2A984A35AA600D773A1F5ECE4F4EA06AA337D51C5AF95F8F58A 03A1FDEF24C2CD72F0DF244229B2130F12CB732DD954931241449452281E1793 FB41B603A5E29C26BE69D405108E0C5D575515C5DCFE9858B6493D904CFFC895 E52B410C8B07AAD1D04ED26A4F1A16027D0066745E1E1BD76F7B504FA42337AC 529A442809459545AA38A64B026CCA2446A5069D28826566E4C9CB4F3B2FFCE3 2C130819B0CB102EC85BC4F4002AA2E21508228A7C5F0A23C80804E066DF3F16 CE40D21EA135FF2FF5D539529A504FD28DEDD41B77721A0F8FFC6AEFED1F1389 27203E228A88F666D34D3DF1FF3C7FF69919CA334BC0BB4AE88C2BC7DCB0DB90 E2F144C114A821C8D3DC3E5CE93333A6DFDC7264F4F0A73E100CA228D8D0AC52 C89C50930AF7549E9BB0A92FBCC050CE7773E79F99A49652B4F915C866908FB1 3FC4E8569252B95B18CADCF7FB99F5CB45EBAC3BDAD116E9A54080342625AE19 F3E2F91343244255948551667E65AABD0072B99DAF3F539CB95C16D1B528DD04 500A6B6AE86746C37BFFF3566D2064A11628CAF2C9C6B1CF4F164A2396B972CB 27FB3BDF9169FA7E927641296709816630666D9A9BC8AA08C116DFE38DE57143 7C814B226F14CFD571A914C3E2F3E2D8CE21CE1498C54D07222BF25096E1C410 55AD78B85C8EA811790CA76BA1234A2E0185122C28894C2A13274C453EB53DF4 91DFFCE4D933F585994A5E775F3FF34D92C2C75E9D7AE8EF1F3E76ECDCEC72EB 0852801A53D42229EE1FDD39D1D3D5FFE4B913BFFA3B1F3DFECCC9E71F7D3A6B 9AED998CD848A1B84D3CF2A0B8CF414352F2AC5B6FEB7FECB1AF98C61A9403C8 1D9E1730E939200775586089F5AA88C526002A94C31E023AC9D13BB9195BE2A8 E2F756C30FFABEA78A742ED942611438585742F76AAC56ECCB5A49948061CC32 8B6E28F4C096C8BDB855360E65BF4DBA3A30AD72FC826618CA44570D399910B1 E570E1D9736D8571E5361AD62ABAD42415918D4ADA2C94C5BA1A14D64ECD4FCE CEDFF1C0FD17CFCF39AFD98EEBD41DAA3AFD9C540AB7AE8CED6DAF4E2B731796 B6DD9EA6797EE554387D1CDA285A06F5F96666C1D5CAD8F568138B8FE89320D2 04C80FB1CB782069A08086A0C51FBA71B01B1F03BC314D817E1A3988F8B33708 A5AD9E486BD6A235B6A4695AA1A3E3266E0F13236505B4DFFBD93FBFB97D9F7A F15B93574FD4DFFA5B6F6A765CC7A1A1DB694A1B8D67DABFF6954744587BF023 1385095A2B078A8F74EAB8E2019A69B54B27D423AE1960A9344BE5A2B4A38DC0 5D22974F5D4ED3B0AFA310391401E3E5572E62D079F3BECE99F9F22B2F576E3F 38B0A5CF06B655F7A8E34756855EBAEC4FDBD19C622F0760BA1A5EF75DE88BB5 AB983AEDCCA83D3818C146678448583B70A863DB8E048AAA20120F5700BE1C32 9321578F3F7F6AE78181F63DFAE206FEA7AF2E05CBF9506D4E85F55947F3086A 064143E003C907638A94E9911C311592765D1B50406FE4647DAFF04EFF177EEF FD2B97977EF099571A73C93261454AD76C72AD56AC00D730DA9080936C8D0590 A8AAA69B4A04F21CF72A38059C34698A7576F4E04D56C37DEDDCB4CB951A5635 6CB447B43DAADCB9BDBD3DE10781E741BDE82927A6D63722BD4CD006A8985019 A0D934F079D4182864FA8CF4ECDCDA34677384967C5471FD0A64962EF5814D5B C4D150F2FD812F702BE5722728F277A0884F265E81073A25A3A12696F0C056FE E08747457E63A29E4DEE1A3FFC4DB8BFAF5309A08182EE141A434636AA1F7C7B E7CDBFD4D7206513154AD3F05B5F78014DE5A60C6FDE0BAF07221162E97C1227 42A9EF13C8A5C4C446C4482442193E5A224852534D52F0C42E0C5C28424700EC B6249F48A406782AC5837454BBFFA6C189211285EBA8191946FFB935EF854B73 3ED0571AEE22D5CF34826BC53ADC546AFBFFA908374FB8641B1CC5847708E3C2 4E1ECFBE010FC18D168A48840AA58EED454128BF5714DCE295C96D13C5B25722 52621679A8259785F4508A1838796C8F1A4A17D70A0425B5C6A123A3433B3DAC 36FDB04E1413A18400DC5077000945F4E448931F4DD2EC31A70E446A58EB78FC 6B9333271A009933BE3FC9D03A52C56E15A5BB88C7A28617B7CB0FA41782F815 C6AA0DB14701884FB7796C85D09AEF0A445E75412A49CA5B60630B6BA3CCDFFD AEF4DBFF608FD8853850B00A5D713D7AC785AF5FF9D17F7F456FE6379075857A 9396EAFA2AE54D829D4882E0A411C10CC17BC2C650269F8A1CB34F7BE0BF7D58 3DD01944EB6AA318328B6951C43C85455857DDEF559F78F2B16D437B4F3D761D D6331B4D7F06DA53BC2162E0304A6D23D9047072DDCA7D7FD2C657D42B8FCC8E 75E846D6B6E4A976563A3D7049698D806259B6B8BC7426B7512A558A1B3B76ED BF7A76F5F2EB2500F21B962DA5FA3C44FC20BF03DCF53B634A2FF4DD244B466A 0026BF796DFA1B55E2260B6F350E7E768F97B788A3E12829B13F1418B0E5F980 DE981C6DF1276F24C2CDF142B92964632990C38768335BCACE2978636A5ECAD1 4A5D3122966F241F1F3081C097C88C6D22E4313956E49F5C387B7561F5CA3D6F BE5F3C2020F290AA4E5E5EF8C50F7FF6FA2CB1AB107AB507EEDFBF512B9EBC38 DBACCB8FA02AC0541451C16A7AC6751A1D0974F7C103A54AF3F1D74F760C77D6 966A1D40CBE97AFFC860C56ECE2D2F3861C020F502B056AF8925B16757C7534F FF553A17B0A0CA5162EEFAF2430F3DF2D6B7DEBF6DFB30600D394F8288D41685 D80F5C6288C8EE29508FF3180C642F5494162196825F58926842A99B234709E4 40EFBCE48E721B720F714921971B4EE4C4289E53974561DCFAC72109A4ECB507 A08E52D64B17A8AAA9E31DF5A84E20D42263F9A52BCA9C9FBDB74FC06ADC74C4 6EF098EB92509E263799820B8DE5E895474EDF79E4AE95A0B4F6F286530B9B3E 5682AE0834CCD185AD87B3C46B3B776C69746747662058B96EBFF684F879A542 CAD7EDD48C4F5680EF5087CB4904918C955811476ABF21F90EC88341AC5EB5C9 C86B09AA89E0EA8BE81ACFE36E2645B63928F5C664C5665B556AD2E25657DE4C 2477A62AC34EB6D76B77F5E2FE5FD7EFFEE521DECC3CF377AF6DD9D13BF0E681 6AB328EE8719ADE060FBB96F2F3FFF9DE347EEEDDEF3C044CD16E02332585D6C 59DBD078C1D353E211F6F8A2D4005C7C621005ACE2871B68FED2925FA98EF4F5 32392D9778FDF44C7115DF7A5B47C8F5C79F5C1CEDD50EDD6472A7D1F434CB0A 61A0CCCD45A7171B7304AE233EE344534D87B902FAD08805490515281ED18D21 45A1CD62670EDD7E78B4B3938BB7D174F1E0322232613571EAD8623A9B1AB99D 90F6ECB7BFBA34F91CE6842FA0F212C77560946CF1C044025340184899752EEE 2650B15AD09421058D1198749A511B7EF7A7B68E1FCD4D7E6FE59B5F9872DD6C 44DC66E8CE7B700E204B1E3AFB4C0A18214513F14CE7365519E94A446D4A2327 B65BD3EFEFE83878D3F6AB53932BF31B559212D59ACA783672F7F7A6B717141C 3A02452C3BF4E4ECDA2A076B5158649189F57ED54C330F03AB3F97DADAD6B1BA BC71B15E5B56D47A448B0DB70C225BA78128FB028A622D2F88625A49C455A228 4C4A736129FB29968174C61BF4B842E1DEDBB247DFDF03126B5C20DAD4CE8923 FF0C6F1DEA51BCC81489D02443484987D5BB7E617CFC1D19DFB0A19BDC9804DF FBD231782D379574E73C361F274224C3B52B09321C132629650191EA1D808910 2BCA97406581C08081406B52FD417C34D316608EDA7D4936AE9A037E5E07CDE1 8EE0815BC729A8B2B08A7C8728BD27AFF31357D7B842966ACD152D7FBA529FDE A8C07F6F5EE28D832EB0292B1553C764FE8BAD56E2D3514CD1E63CD48D19EBD6 4B1122A2BA21B93B7E4029556477450EEAC5D3F38CC56AC7F1B9AEB83091A9C4 C2E6BE84DB610FE4DB15735055027B79C79EB603B70C23754D333D240567B0D4 7D17B843F144444532112A92C748A5965BA49631ECAC4D75FDF0EFCE9457C5A5 A2D9C0BFE2443590900618A12B0390A819A5C6B7884CB247253532811C8FFBE9 E5C7A4D9D84C83F91CFA513A4DEAE3A4B90566B0EF8DDFAB7DE0B3B787026641 9180A14D194C24BDABF05FFEF058F9558FE9E032AA4CBA7AC54922E862B522C9 61206F842049FC7D8C0D65B26D307469FDC1FFFAE1F6B76C0DA222B54A11AB85 54C4479F8A672B20D685EE1FFEDD97B7768E5E79C9F28A85861FCD46C5734ED1 41B88F66B7C174967B993670E7E713A6DB77EA5B17C7DA40BEDDAB3B3AD5BB19 6C22541105B288A66E10558A76B69054B0B1BA524F650C1180CE1E5FD1F0D8C2 7AC9F62D2AAA48C7EFDC47EEFA83092F6D21B723547DA094F586F2DA9766AE3D 6AF31CBCE78F6ECDDF570879802371BD3894B33C81D8C8376E17846F0C02FC5B 66B16C30AB9B0911FA3241885427A7ED35C40DC96890DAF5BE08AA5190410A8A BB649898B9E5F9F56CAE5D51449A944C78819B8B6BF58BE7A71E79ECD574A6F3 631FFFA8917008F14E9F9E7EFFCFFFF1C65AD26D32103850CEE889E4A3E9095F EC51852B05D314401E107D756DB123AB1FBDE5E0ECC2CA85F96B75D7CD607D44 4B6F1F19C6B9F4A3C75EF0892CC9928954AD6AD59B960BF8CE1D9D4F3FF3F5AC 00AAB5FADF7FEDB1BFF9EB6FFDEEEFFEDC2F7DF067C2B08C90F43E435C8B4D23 C475DA3829009405FC2E810DC5E2F661180117029140422AB2A3C501D2823084 AAD8C14C894A3CB4A2B00AA4BF9627F927B2ED41E2BEA1B470949AE6E235B014 1309C4EB429886C9E095AB9E1F26B77607C413F75F0E72AFF8E5C72E902EBD70 704B50AF53295168399A1DBA513230A200332771FE07D7B614B6D4DAADC513E2 5F8B7A9E509CF35C8764970EDCDFA618E6D429DFD4D203BBC26275F5E4E3C42A 1AB652BDEE6A577DB4C0833A0E189593FAB0E52C26F0B604FA520CC153BC9642 3D8FD9419B13CCA13C927F43805B760D99E42FBC3131FC069546060C425AE142 408A7EAD36A1E58683BC2E00427EF29D7FBC73EB7DDB56FFB578FC1F5E7EE023 6F8BB65B0E5B4D5742A6E878BEE7D8DF9EBF3E35F9F68FDCA314B0DD28EA8114 5E0913A1976A6AB914853D01B5E49195842411B0225E65D545BBB6582BA45202 79686AF2CAC5D295CBCDC3870A8A9E7AE1C552E415EFBDA35343A11F265C1740 C76F36E80BE736261D5E33F03C63176A5EBDD250759589470551C14CF76AB41B BAFD0469963DD2973E787B1FD5370CD28434EFD13235F0D573B45C057BEFA7E9 DDE6E947F9A37F254A296D89AD547478B5A908D425D03354A81CC096B4468178 A8B8794906B798FA28816D2CF01AE88EDFEC7ED36FF600CB7DE521EB877F3F03 9AA2EC696E606516A6577C37E22E168F1C051A226AA8458E221E8869066DAAD3 89603E5288EB8DF6E5766F1D5CBE327D795D94BB0A403401E92081B7F52413E2 E580B21A26CE2C17E7037B3170EB4C57A8DE895126F20C11084C7A73776FE486 AF2F2FAD4AFB417DBDE66C44811D9B7E08682290404C29617E14724922D3B044 7B22438B0227402032153ACA434DC1B7BF7960D75B529CCE73921415E1C4916F C13B4606B0E709F8D1AB2BFD58CD2BD6FD1FD9D5790764864BFCECCA79F6D097 5E820BD92B097FDE6773011608462658E049551B690323AD985C18C838C4892D CDA47C83F9AAD8401C58024CCA196435F49CBC198EA4D000435DCD642ED53C7A A87D34AF068EC5023BA9F1866B3CFE7AB318681E74E62BF545D276A666CF16CB 10FC7F26C21BADA05848538A0EB686F5255DACE5C1D1FA41A933197B91B56020 96C27606946AB84CE44025E69DE34D0F399944C5657902154B9550450948E809 E8E5991A1FE4FA1E9ACE86352D593A74F74857B7C181835597AA9EC85B4449C4 82540ED515883539D88F4324C7CF48A0AC2B70EBD987F92B4F2C35C3A048DCAB B6B312113B4A48A343EE0A5421E9881CC9E134294F12ABFE7119DDC10DB1C4D8 8990B5F8ADE2C67AA191C4CE16CD1B07AA1644ED3BE17FFCEFF7F3F62AF00206 3498566C2C9E69DF73FFE3F5E37F719E1273913833E2B1D744A2665CAFB940A0 E8BC19E10C0D0E22D2A92B5D08F8A071DF1FBEB7E77DFB025624769945D5883A 2280C8FB183AB03EF6E2DFFE6D3BCF36E7B353AF3700A633CDD569E66D30D446 CC71463AC43AD3C9A1FF867AF3FB5FF9C6E9ACB7323E916251C6E219A08A32B4 1A9B3C4842CADABA6368349FCB576BC1DCF2EC962DE357CFAC78F5C2F29A572A 9752D8085DBF7D9F76E7A7C66CB1999D3EF9389255A47AE07AFEB5BF597CEDF1 8B134707EFFDF43B782F73C5E350138115001C7BF2C5837471748B69C0E00D96 D51B9C2AC9A6968417393B15A0968610D72037B924FB86D22C502AA20D844103 51D95FAF94C9430F3D274AD8F7FDFC7D0CAF20540D02E0D4124F3E7272A39AFE EA5F7CE367DEF98EDFFE4FEF6EEF525F78EEB5F7BEEF8F8A25552C2A183814A8 F26832A900DE107751075A474265227B40A558591FECCA1ED87BF3990B93C8C0 B5F595829E1B4816C627465EBA72E9B56BD33865789E9B36138EE5559A4E08C1 C4B6AED75F7DBCBA31FDF9CF7DF96FBEFE6A2AE1FFE847FF73FFAD8391BB2A8A 40CFF5083108D021D5C45A2CCE4E9F7DED74B3A476F475740EF5640A494DFC0D 905D5AE089E0293DE79001C40E6734307CCA4351C414235611B83B3659117998 40D92B944D17515901CC5A70D2474C44CCA4A3B2B38B8B0B0BFD4776413572FD A68FA0EA50746E75F5D46CEEC0B03ED2C1EA0D029D80D74240B88583C04BC2FC E213157B8E2776E7EBD71AF505AF1130A46AD2221197F7DE6BA4FA94A529B33C 1BEDB84509D4D5F32F698B97B0879D4586AFFAEC7A1494E59868DCF9652D1955 24D919D2F38C472460374EC159AC52DF22CBB45A83E086259374A00DA39864DB 12638B1B85B1B05C3C6221497762CB7512349C527A237F18E745B9DCF3367ACF 1F8EE68CE4B1FF7AC66D44777DEE904DAE2AEB091704095F5B7F35FCEE9FBEB4 77DFF86D0F74D7FD15E4259548E09F12372069EB0266C2C396547D10A5B50F05 C80B4A35AF042B737E2195014C80575C5AC3674F57F6EE32DA0A6DAF9E69CE5E 9B7ECB3D138622B0542AF2A157167B473B71B17E72D9291B648179576CB4516D 7822B92AF2FC8B42A5D3547A49304A687B206E6873DFA1CEB1AD5A8A6C4428CB F43564848BD3ED33B3E18107B4DCBEB03C95FF87CFCC113B5BE41BABDC3AD390 BEE402E908E88262674B49F850B4A6ED40C71D358C21CEBB2848D753E923F6DB 7E774BE7A8CA59E1C9BF3CF5CCD72FA7A37C1DBA2B2A28A1F46ADD73C27A2309 8C40331D4D247EF9D8094B523AA8D06E16B40166B070A2B77DE778F7CB67CE4F AF9770260F43331FF09B737877AF2996F17A609C5C2ACF85CE06086AA11A315C 40F271A48857D0C0DECECE0C56CE2C2FCEB94E4453568467ABF59A7882728A31 54156912E485912FE76A65BF3FF6AC9692C1A278133837A1D271E8692A79D35B 86C7EE520238C35082A4F76CB9E32178A8AF4BE5410E05039AD105503EE5BC59 24C243D045750D76CF1FF7BEFF172F9362F6BCE6CC7B6CC1C79EECA04402214A 62B5547913E936F4A492ADCC3EAE5847819F083C15421742114B7CA87A8E95D7 518F8EFB08E863A8238063C3D1A1836D8AE720A6F8AE974A90D5067EF495D574 DF96B5F2DCD58DF274989D6C848BD5EAA6BBDCFF9D02618B25DECA85F1B103BF 61342177483C2D845B2CEA587307B5FA1D3CE661EA9A8E63F9161A4F51C0B82B 17736DE42CA2B87F1E0A3DF19A58A3B2C9D134742FA7C17E961C0E14235CDFB9 4FDF7D5B4710D5742D13F13A11011A09309210409AA100AB12E6C8552FB54565 454C5281BDD0F9E3BF5CABAD1A0D3598891A971A0D076921530931456C117135 161F93B3FEE26A02197EE2D35179001DDE38B989E53363DF0E8EA82DB20E6263 3A1F959E260499CD0FFDD19B7A8F42EE5B0CE6B90E7C5C035A7FF5C5CAF73EF5 4C6D96D8842CE3E09A8DD60264112740AE8E5309A66628DE0759874E7A218AA2 FAADBF76EF96FF7024325C6495202B8752E224C2222F3381F33AAF3FF19A75DE 6EA7134F3D7A42545165CFBBC6E0BC0F4C0CC7603420307564EEFACFF68E9BEF BDF2F0E5CAF9537BB776A9665B2D404C0B15685110EB8152D57168BDE8747665 43185C9A9AE9E8E851997AF59C78BDFCF252C9002472237327BEF353A33C5F54 2A794E0D9E702D584AA4FAD94CEA85BF7EF1CA6B7347DEF5A69D3FB7C76FAB2B B221A6FAD022B24868391FB14D2D50FE462244AD71718EAB2CD21897B2D7F200 0D051047F1DCAB9CBA8A6D9FA124D4479D7EB8A6E8E2EEEBAB8BFA37FEE1956F FDF3E3EF7CDF5DBFF2D13BDB3A5C22B7C0F037FFFAF1E945F4F4B3275F7FFDF4 C73EF6B6DFFFFD8F9C39337BF49E8F51812E48402391BE898C7B582A1162AE89 E49356986441A9BAE7BBDB077B867BFAA76796A4B2AD5DEF4976B675B4DB983D FCC24B249B6E8AAD0158219D162BA16435EB8D60DF915D7FF49F7FEB9B7FF357 DF7DF855B1260E1F1AF9F6B7FFACBB43ECBEA654AB5104FCA2A1CF56E74BD727 CB3FF8D693C79E3DD19EA27A92E6F27A4721D9D556C8A7B30A971D03A889CF64 0FEEEE1FDA3B90CAA5A06B72684356895899B306944D815882474E1105F29014 8752BD37D6F6742569991A0D142D34CF1F3F3671F72D4A0AF86E132039DFA044 BAFFC8D4A25BEA3DB283EB0C785524FD2E92BEC77964AB22429E67A79F5BC1E9 ACE96BCD95C0E2812BEE15508067F7EF0E070FA7CA2BC96BAFD4C77628D99168 714A3BFD5CD3F2C13A64B3A17F5D64903016579573CF2D7B5E1C71E487B1F324 8F770A8B0515C0A687676BEC586265B63956E2FA5E6B8EE28D04B929351C8788 28625216180003E0ADF9EC98E1F70094E59D6EA27ED7EFE5F73E908FA6CDEF7D F1B9036FD93178674E00D6660DA7B50DB6049FFF9BD2CCC9EBEFFA85F1EC3069 583A0E4395AD13A2F06C6750405C0D04A094F38ED2F4D5B28B6BBCA114A75147 B68DC05210D86E33F7CAB1F56DA36870B87D76099F397765F7CEDE8E36A9210B 5C1AD6AB94C3C5A2766CCA9A63DE1208E70275B1DE5873AC8888B79212406D49 6D204187B136C40DCDAD7576B17D073B463B9D10A590B982F4A0B43674F67CFD E6FB8C8E838EDBECFECEE7E6AB53A26E7117DCF205A6114D9325A01C9E9182FC 1E043E218D208C1CB713A101918A143C1EF6ADA54FBEE7934776DFB525F0AE8B 9DF2F857265F7F380ABDD0D3AB759299B7D455AFB9920812819EB491417883F8 4506284AF4503C0CED1115A34ABD3D65ECDCD1474870FAD2E4AA85B1D26984A8 0F5B776CCB9920AA78FA89B9F24C105409A87961CD72DA54636BCA4CD2B05D83 5BD3A92C218B8DDA956AC566223CA7E61B4ED1F17DCC1DE450A2C6D50EF7A4F6 AE34B696CC119908251D9C729654E818B234851C79F3E0C451E2A379461238B5 67EB9DDF8747FA7B35EEB4A17048313A10CCB579F7FEF2CEF6DB88175615D67D E5A9FA4FBEF63AAEA5CF29F6BC172D86246484CAF385402461399B104857E630 161513A1DC01D28042F57D0541878086A805814243AB430DC712C9F688665D6B 7B8771CB2D7A47C683B60810BAEBF80A5596EAECD8B54AFBF08EF317CE2D349C 19983C5F0E172BD5960FDFBF97085BF0AF65C622328E3C2B9134B7F8F0536C76 91555AF2F39BD6F37145485BF94F5104EA13B05D3AA7C7DEEF5C8E242329FF10 AB7588F8E54B9B1E8D40450D9D9C66772BA487A7DA7C9437AA070E99435B3437 6822D21E44553DC1E4008B487EE2B648839D989E20D0956C76890FA8D04462FA 58F4C23FD728EE58E0B5CBBE332729BDA2C2936EEC02C8887C80B81EA7F240B2 7BB854748B62E2A8642DB0168095E77DF168238EC17743DCEF614D1D09ED416C DA8DC67DFF61E2E8AFE59861033828D037312A16E94EB9EA239F7FFECCC35512 A62AD89E656CC65356048207AE0E4552270945BD19853D69750892B059DBFEBE 7DFB3F71BF48ADDC2AA36883534B1450584EA4BA2106E1057AE91B17C73B271E 7FFC39E60AB89B3F5F73269D40C1C138F587A982AD7CE72FAEBCE9BD3F639DAF 5C7EFC5FC73362D99A8E0A3C225661A47051CA8611229866E626ABAA1EF48D65 5736AC5A3518EDED3F7F729A05BD8B73156E07918B945174C7A77BF5BEBA52CD 07AAD499976D0BACA87A06DBE957BF73F6E16FBD7AD35BC7EFFF8DA3A62E6EA5 168837C152E3389693E4B1F24BEC8EBBA9A027355862EFA43A006A142AD25909 8BADE202E48A7418B3ABA51E2CE42A064A10E89034B06A4BFB2438F0FA29E7D7 7EE54B274FAF6C9DD03FF9C95F79FB8377983ADD5859FDC3CF3E72F9F2D26BA7 CEF030FC8FBFF1969BF61EFDE0473EC9B09934455071401021532FB90231CB16 A1F808A61C73E61EA2911F1C1CE9EFCD772EAF56A4677CBDD49FEB1ED8B7F7E1 E3CFCF6D54C4BB867ED8661A0A0875535B6ED444AECBB465D428AAAE34F24975 B9113EF8F65DFFF8F5CFA69341E8F97EA4D5CAEED599B9E3C75E79E6B1178AF3 4DEEA43A33DD1D5A5D21E2E9D838F0A858CE52F355B123D7539C9BEFDA7DF8C1 43E3378F49B9D678C00388DDC86A2CAC31017A444920D7673CD02ACDA1E2237A B9DDB9488458949C368E9AF0EC8F1E1BBA657BA22785802BE2B19C4EA42A9E46 579FF9D74C773E7B60A409AA525EA219C69E0FB614A3B693979F2DAE5F6226D7 031B314A1AA4AA8A8DD644B9616FCB9B338E0BA75E2C6732DAC8FE5CB51A1C7F 74A3524956A0BB10B973AEBB211EB3947B259E344890AC2651DE07F1C8231189 A6E5CD0461CBA131567A6CD9146EBAF5B652E31B83F66F64440997E373511131 241B288A14130D91F6111D74E88D4E96D77C65E21E78E71FE4D5C1CCC56FAE9F F9FEF4CFFEEE83D6D01CAAE423724D3CEDC6A9C2F73EFFFCCE6DE681FB47AA91 4B18367C17062C4868618FAE24318681ACB4A50AAB659517B1935CB90832462E 91ACB2B0E935F32F3EBFBA65800E8E266BAEFECAABF36281EDBFB997057512A9 D0F622DB0E59EED8E5DA998D6A8928ABD0BC542ECD3464212EEE43C2D04C5DC9 2232A4EAC322B108181C962746D247F7A5A0A172BA405460B963C75F5DDCF3A6 64FFA1204A0C1DFF5AE5CC8FD79B56B816D6261549710748E522B78B125BAC29 2427551D44C2284C86D1804A73184D38692B3B73F483DB8FBCFF005417312937 57520F7DEEEAF249A6845E352AAF92E44CDDB866849A48396168506073560C60 289053104EE8B89FB9DD0A4A29725AFAF09EFE200C8F9D9A64A48DD05406B9A3 497F6B678A71F2FA4273AAC19AAA5A776B65CB6AD333DBD2492DB23B12784B3A 9141A829A040B3B154B67D9AAC217DCDF2ABAE55074D14EB0047B2A70D3C0E23 010DE3F36FA982117191E74D856E21AEAAE03BEE1F1CBF83FA640E286998DCB3 4D24C2A3C3834A586D07E1A89212F844CF56DFF55BB7A6B6BA8CB8281A3CFBD0 E233DF9D247EF20CB6E6BC688349E6882811A47E1B8E6DBD2439269207B45260 18331249D75797231CDA14D49922105A32AC8E26C21135D309B34A7363DF4EED E8E12CF29A6E892142032F5269E1D4B5E5CB356B7CF76DCF3C715C8088AB089E 5F0F36AC9043EFFF3D42DF628DB474A062A96C20FDD8E203D0966E1AA19BAAF3 E28BC45F28EE90D3588258D47D040295521C7706E589664B4132AE09C5D67165 AB4EBC9E22F28FCEBD513D1CA534CF4C03F1A17E7E60BF89D522A228E005443D ACBA7246510EFA894C18CA69432C8A360F2B9E1480C229B79178FABBD3F56B79 8725A683EA34C0AB91880B8EA801039F8B0045750530550447CE3D2E5B833066 EDB158B3A4E5E3D80AE7B1D35028AE55B3F45551667461632B0A46A0618666DF FEE867FF7C22481679348802263EA1A3F71A0AAF9D077FF99B8FC3653D44C112 892EF864C6136046446AC91AD508DA4BE1404E9BA0BA80B27D778FDEF6C7EF8E B21174EB285C8B6059DE068139A3BAA5D7F49991135F39D19FCECFCDCC2E4D39 3C6ABB1EF24B9E805FE1B829DE15E37A3E75EFEA831F7B8757B6AE3D7AA627D4 D399A0492D0F1B1A54156663CA1C110E388D9CF4EAF26CDF7892E899C9CB0B85 549E3BCAFC9C532979DE4614347563AB7AC7A7F3E6801B95D261D21748460522 5EAB9EEE331D1AD1E0EB8F5E3FFDF2C9EE31EDE63B76B78F0D47386C918B65B7 3776D393A848B240613C90127BEC49117DF12B8CB54711C09423D56EBA4DC716 E1922225265568A69196BD445562122F121588A9A8FDDF7BE8CCEF7DE22FAFCF D7337AE23DEFBAEDD77FE3DEBDB70EFEE9E79FF9EE777F5C2DD737564B14839E AE81C96BABE2054C15F617D2AB8B4B5837EA20726B6EC862935FECCA0E9DCFD3 181E191EC9AA899A88E88D46542F1DB8F9D66A42FDF6334F3643EE7A4CC54A9B 46B5C83793C67AB3B96A8BEC8992BAD9A6EBAB6B258B834F7CE2677FE777DEDF AC2F5DBB3AF7C4E3A72E5DDA98BA3AB7BA52CE24947C4233B1010390417E2681 721A20BE9754D2A1088F18D9A871E481036FFFF0DBB5BE3C97DA4FB22C9633D1 B232F658509345217091D87732C5C40647125ECA8E0193A452C937A101157973 F9D869B32393DADAEE0B942D5EA966352932412E7A6D79F5F8D9B6FD6368A2E0 D6EB4911AA1DBBA50F1E01B27E912DFED0A3CC8C18F644D6A535455154DB50B2 FEF87D86910917CF5657E7AD7D77DFE4B2B5B32FD596AFE52A616303F98BBEB7 E244354E3C4E4210A765910670E88B84C3C4F3D7624D55BE290410F742A4D576 2C90133BB2C5127AF1D18094968EADD85B94999649450B31B3F80702D848B26C 9F961C4BF8FD90B785092557BFEF33831D77415E6C7FF60BD7DA3AB27B3F9011 91CF611584FC84DDFDFAD7662E3C33F5F6F7DFA2F6D65CCF4B8419CC3C1BD640 5B5ECBE922A7C4632746E0D4BDE632F5330BE719F4958ECE8060C7B333AF9FB0 BAD261FFA05822F4ECB97A69C33DFAA60995948107149FBAD58A4A3353ABE089 B3330D355D42898B767DD2766D0E445857B1948314C1B74BD1C774D047822C63 0688EE3D58E89E30115E5435BD6275BF72767EEB416DF830E26D5D179E824F7F F5B2DF4496E29F17DB4AAE5045E0555136C130F45864135C47E2918709425261 90D7D5DD0EF70DB6E3FEC25B3FBE5BCB36A2C041882E9C0FBEFDE9D37431C359 7915FAF36EC7852810774FA53EC54A18D150AADFC9A7958DF00081DDD433801F 066434CF6FDBB37B63BD76F2FC558F9A22661750706454C03C7069B9FEFAA2EF 9B5937A895DC465ECD8C1B22F6066935DAD196357D2FD4500DA24B73CB9550B1 9464D5831B56A3495D112223269D914379D423699381C0F110C59286F2A9A735 632BF5C51DBBFBC1B1BEFD0289CD12230F127B76DEFB30BC636848E3956E188E 82645601E901EF1D1FDDAF0F34982868FC8133DF5E79FE075779A09CA5EEA2CB 36B8C180A2C8A9BB402043A91523CFECC5360AA46C8C2856488042C47DB9401D 0A5CA0E9807481C6B06A75733DCB33EDA9E0C891D44087032DC83DCD0DEB44BA C3F5FCE4D58B5E5B7274E2C08FFEE5C40687D3AA7D66A55173089324B5FF5B4E 26AE8EE2138FF83B5911C68787B19FA01462135B8B121A93C4E4F78AAAB48A48 12C55D4519226539161B5C4BBD2C187332D1E6D035904D3FA90B40059648C360 9B02262035C5156AE181DB3A47FAC44D2E8BCCE7F1BC2CFB145716DEAD4E2366 A2DE946F401CAA46AEC34CB367FAF5E895A7E682AAD8CF608687D7A15A16DB36 B21439F222FB7E5C54F45CC031B127E53BC7ED0B099AFC886D2A63C29F2AEA88 8C200A174B5B1088248F12E324D886928695C80D373EF4C5513C6C797EBB29C2 2D5F65A97EAEB884F73CF58593C7FFFEB4C6CD22469310CE0491D4780FA43E80 C0217B30EDCD91ADC8301A5EDFD1C1DBFEE43D4107004E83842B0C9564C69004 A86A452B6637764E7E63128A6F9976EAA9598ABA6782E6155F4A30F611D64FA1 E6A5E9B6DA3B3E7A1876E2CBDF3F975812B881DAA4E8A2B4CA931AB411956604 4CEA95B557CBB5627D7E64DB70B9545F9FABEFDC7AF08563279D66189552A0D9 C67AAC3B3F5D486D817E2519190D807D113A09C8709D3549454B7550BBAF7EAD BE327B89168CFE9DDB80E64B7B3A74E32C348E8202D320E9AC1B9BF58848EF07 445463520B2320C902E0E9575EBCF6CD7F7A6261B1EA072C165DC09A6666336D 89943C6611753D259A2FF00849A85AC7B7BFFDF495CB4BB23B05EDE1A1F4877F E19E5DB73CF8A9CF7C6A7979452CD246D50B036E716E26526D996467C2C0E259 2FAE27DA076717667C293DC154552458E6F92C158207B76DD3316D723C3F33DD D9963A7CCF9B7FF4F2CBC7CE5D644415F85245C888FC0CE77D5D1DC5A65593B2 A686408D56B566B90D48D081FDDBDBDAF4E5E5858585F2FA86137260EAAAA661 910871E4664C85870296D2A4CA13284C2BAA2C4720AAB3FABDEFB9FDDD1F7A4B B63FE5B9620727093419DF88A1B434A4E64C5C4153FC87902DCB3F5914C69E0D A2E2620DA060795C82891301D5C1EEA5E5A8B4913E34D2D05DAD6E532BB40448 4361A29CB09E9AAC54CB5D077744290CA883ED0676A5187D1D5B6A35B7FA1DA7 BC2CD20DF582C0260DA4609365DDD0EEBF050DDF44AC75FBD5E7964677EEEA19 E733E76BE75F123F1AAE077E11B079CF5BF1798329416C982CBD78A12FB0B26C 0647466C9C18853105465A82E396107F4B1920760D91221A50BCB11CA9E2B1BC 54AC1520B53EFE0D8954BC00E60D8BEBED347B73421906564E9E7E393BEECFBE E97726601216CF93E7FEF1C5077FE69EC4F6B980253DE6A9A143D6067FF0A7A7 75ECDEFDCE8E085ACC35A81C942C62DA46F2096AC473593E719BD5C82B692037 773EB02B4C445F44AAA19BB9783A4A127F6454F6672F5D09A7AF340E1F1A6ECB 3603D75359326A34C4B2DD68EAC7A6CA73355E42C664E85EF1C275D7C728A492 F685294A2710EA35DC2125E808D56CA44F74F203F7E44D7D8570D385C3AF5EBC 3AB0958DDC6580BEAE6B2F298F7DF122ABE10AA85D0466B5D60402C1E909F131 B9277674E06254C758A43B812B0D1E6574F5162F006AA27D0F7EFF2777A6FA6D DF134F56BC21B9F6D4CA135F3CE32D69A1AEAF07F6B530B9EA175D53D41146D0 14EBC657447823F28824CD41B716B5897DC5718135C60AB9AD8303F3AB0B9756 8A21C919011B4FB36D03C9E9A5B5AB65A5ECEB81C0E3CC4E617D9818024B2475 3E914BA598EF81C0A6A86847332567C5853E32CBB6DDD4FC20E24E10F9322949 EEB77CCA2052E524A91C8712415A14E03B743966BEE7506EFC08F4D565AEA440 72F7EEFB7E048F0C0C68B03C00A3AD3097D240DB96E82DBF7E13ED2A33ECC366 DF2B5F9B3FF1C402C7CAEBCC5AF26009E800A844604BC98E91E299526A5B2C2D 39882BAB430E5CC890A81823CC5DE9BC8B33808EA9611FB0F3222163E5A6BDDD 3B6F5275560255B1690C8F6F28129577FEE8D89981C33BCC44CF0FBF756E1D91 AB6AE9EC7AAD618B04176C76C0FF6D1AE49B8361ADB13F8C908AE4F055AB5844 0468AA26AABDD824114A6AA8A2C40912686CF3982CD61A8031D005342E2A63B5 7216BFA600D3586A29CB535656A0601BC66392E9EB667AE8FE43BDA656465CA0 21E2416935870412C1B135B09CBDE6884A6B49485D9188596812D875EC27A5B9 CBF590E94B8E7F2DE44B40AD4BB2A80FC2A63CF894665A04322D96F8F7631345 D9DF92E3A59275485A3A60B119455C17CA6EA2E2A96B012049A00FA068BB92CC BB3A32577FEED363036F4A5B1E348909598325330E7735B5E05E817FFDDBFF1C CC6B2E4ACD2177360A566DEA07062621519AE38CF665F14E6CE61AA0F360C7E1 2FBCD7EFA1D07748B8C4D89A9C92933C9DB20876C9CAC0F2534B8BAF5E1CC98C BEF8C3498D7688F43EED3B75977620DAAB4193D3406FBEED13FBB28793D79E9C 2A3DB7BC6B208DD3AE8353245415607312888C238DC2C50706C6D2CA9C9187BD BDDD7357CA2AC9ADD78A0BF3ABB8DAEB6FA4C342F5D07F4A771C4C065692880F AB35238208CF481550518C889C8832303039172B44176818D18AD4DE91260B60 D384413C5B69160F3C112C309136F45205DE43584734F7FCB3975E7C76F6D11F 5FB830B91AC9297B7972CAA4228BAA1293A15529C9122B842AC870A388A89A62 085869FBAEA52279DA1B06EC963B6E9A5B989E5F5C4BAA9AD70CC45AB459200A CBF67486B8EEF6B1E1EBF3AB21C92F541645D8001271FB32A1709473D97B76EF 520999AE56AF5F9F79EB5BEEC585C2DF7FEF87B5BA1DC298F8C5830CE023F95C 219D6E389E258015A6A566BD5CAF690A4092A10714350909B57D3B91D6D78A95 AE8E4C24EA1C47D456209B5403CFD3B4AC8A5921A9875218127BC0DE77E7AE8F FDC187735D4A002CCC351A25042A86B42ADB0272114BBF77062C1E89A2B0298B 42EECB517486A4300D73A4D840EC58DF145BCEC5C6B2577DF964F6F62D4E17C1 96A5DBDC91A5585D11396005578E5D025E943D7A7319AEEAC8D36A72B3955123 07F2CD6782A9933502939E13DACC610A3048D675FD54AFBDF79E04A2DE99974A 7653BDF5BEFE7AD13FF35C63A3E236195E8BA285C0BDEE0765A67A488F6D4444 96F690345E240CE9201617DE2C0741DC5FB871F2B9793A2AADA9D80DB37AD472 5E949EA941E0077E8B41132B600085F836482690B25DE543C4EB31CC14A766D6 79CF67EE300F3ABED7987C7425BAD6BBEBE7D7696E8B5D137871230147A77F04 7EF2F547DEFDBE5DF94E971112701B4BAE0B094D5D4B60C510153E739A75C02C 0D6656A7D9DA5C7DCBD602528A9197B8764985BE35322672BBBBBE669E3E5DDA B5A3B3ABD3165586025291E5B2669DE1DC99F9E0D5ABC53234E610BF1AF0E94A 2D942A9B3C61AA9466C4A5B429CE98090640AA0B65B3BCB1F70E323610A89116 A84367A6AE750C3487EF4EC3A1AED50BD9473E7726DC001B7EE9324B349D806B A64254148654A204EE4251CCF24A103251D404BEA9D1BB20157BC0E80FDEF7A9 9BDBF7B8BE5432E8029469DCBDF6BDD91F7C652EB4F390AE9460DB4CD35A5505 C00191E59862A162EC4150F7E548693BD13A1594A45147149ABE3BDE911A1DED BEBAB631BDD8D071C60C2ABBC732018F2ECF376B2C55B19ABEC2D3541D465A5A 43BACAC6326646149491400738D21233457BB6E2853069076C85379AAEDFF03D 17CA26BE64AC480562A688471A86520B0AA15C32BD4DAA3747E37BF49D6F36B9 B91288A095D8B9FB2D8FC0DB074714B03A04D80ED29EA0616E27BBE7C3DBD5CE AA0817DCEA7DF1ABD74E3DBB1250708E05CB1E2F030372459E46004FD49C2256 C4FE72026EC6804ADA47FBADF9E40843579AA484ED006F51956112A65853A7CE 7DF76FEBE84058A0DAA61232C5F3570C25595E2FFCF8D5D76F7DCF6D0BF3F563 4F963670E22259BD58AC59762CA60DE2B34278A325C8E14F2543E4E483C841D2 6D43B2C582086351B18ADC4759FC380951E428BA649462F14D72B38D14133CE1 A63F999498447294B0851DE52D54B4D00B01F34D1CF62A789C183D00A53477C7 FEF6429FF8E93A8949394CD1248F007B7CD3F957EA70C9E02BAE9E8A2CE6A96A CFF21C38FEA3926DC1260FE7058489C006C222FF3081E17C81BAC427669E7495 50E08D535F91A265451AC90B909B3306B6517CC213D30150ECF424D0BA40C54A 3BE4E39AD62F89F08B777D60E8D02F4E84B1C482EC9450105011F431F113CFFE D58967FF6E5687851277E6993D6B2BD520019408D2C678A4F4E5C12E9CEA6D2A E91DC9A35F7A9F3F94849147FC391EAEF2D8AF0E09304A70C24B362E34CEFCCB C90963C795E3F3F586B816FFBAE7562D9002891E534D2A0EB0945B7F7560E8E7 F3952BAB97FFE9DCB8994D77681E55448212157004C240C45C8E58A8EA6AB6D9 ACCFAF4C0D8F0E7157BD74F9DAE8CE89A9C96558EA5AB9E407E9F5FDBF911DBE AB10843A412AD32DCF740130B5208BE442F745ACE252F6C5003C6BFBC4D0EB60 931AD33A25A7BE1F4AF6118BA7C808959A798A54C3AD96E123DF3FF5279F7D78 BD28C70A0D2A3EB7A80499E5342CD9CD52314A84D0F25DC750142E10B1089744 5279A146ECA627DE21A92B4414C93EB3C288C430219F4E193435BFBA48750176 B989C9685B7BC6505C9F5D9D2B195DA9ABF34B8818486A108ABB49DBC3E8FD37 EF8DB87FE2FA759178DFFFDEF7FEF0D553CFBCFC9A0225E35C64A42422836DE9 DE7CD673AC90E3E56AA3E64735D7F6409820A84B25635B77D5BC60A9542C3536 A4AC395511539CBAF486EBEDCE59CD5533A1462EE9CAE75502EC6695287EB6D3 F8932F7D72604B3B518320B022D787A2B0A206577D18D756502E5E3968CF4451 283B850E888B4228F38DC49F51E460917922DF3715E8E144892D3EF94266678F BEA38B393695D91E2A8115508A3C4CCE6EACBF744DEBEE4AEE1FB48312B55D69 E0A8301A28DE4C70E9271B4A901199D365C812A043A05511BDD4E6C461921D84 A52570EE95C5F1BD031D3DD96B674B675F5D12F7B8E4B365E85FF39D554E1B5C 8B6D872349E78964F51FA11B5623B16C6ADCE210F120E437E6E563997DCC62A7 72794C8A361D49D98D2FD862984BD229F7B8A3C282128505BDDE67E251DC3620 4083B37AF0835B0EFC668F0BCE464BE9EFFFD9FC03BFDC9D1D190AA3B2139595 280596BABEFBC5A77A92FAE1BBFAB856B25D11C6552A561255904674034BDAAD EF022934A0D6D6F1F5CBC52D5B7AB0B221B2CFC274DAB7ACB111115C9BB6953B F5EA725F4F7A6C084722897003D83EABD7159A9D29D3A7CECCAF31A5A2E9D723 74493C7F29B0208720A5257DE82748306428A3D4EC57F3393FE818A9DE732897 C2A2D2CF4D2D6DB4755AFD4745222C5416BA1EFBB353CD59AFECD957A3643508 3C2A597F28F0339AE4503821AB315E0DA50A04F31D4AF0DD54C9A3A45170EEFB C4D6C1BBF5D85F3619A0C09453375DAFFEDDD4D3DFBE940AB5861B6E20733A00 B3760D293C451291CD3D18D9D01340D300661B8239D5ED61B04DA10966F715CC 9EDECEB397668248942F24ADF1FEBECED7CF5EF1D554354255667768E6A89248 88388FDDE18CD101038C0317463ED1361C70AD68351C91F4B415EE6E34AD0DCB F5A48BA746246E8E54CE4C8A551197E3591A5DD327B82212D5C07678CBDBF381 B9EA89BA2E73D39EB73D0A8F0C8E52B63482A25DA44B277E611FBAEB835BD4F6 2A5601AFF53DF5E52B178E973D859D63E1AA48845C26421AF8F28689808C2994 71399EA417C13B9007A5504EE48A70AD0472CEDEEB4670BB9E6BF7C3ACBA3132 E11F3E322A7B349647432D889065AFA594C2CA62E2E98BE78EFEE291E32FBD76 F58C52C46D67F8DAC572D9119B11B5CAA0B80C7CE3FF38114A2F4AB839282F25 7363BA174502D24BEE10937E4690482F3CD49AA8250232B548D22DE165C064F6 8CE70E658F10C7BC6C29148F422C2B5C85791D381AD4D55E64A618EB2DF083B7 B501BD1C49151B4DBAADD390A3104A87D358B794B45CA010A6008B901B887FD1 7BE2C5D5D953A22C5557A2EAAC03E603D0A43C1201DA53653397388C785E003D 5FD2F2A41C4E8BC9165F61140BB4C6A68890DFF812EF1E08101F511A370D0D0E 870D3A44BD24AF8DECCABDED6307CDC16A24D93719A6BA88E442E0D0A4B6FE9A F7B7BFFF7C386F8ABDBFC2BCAB3E5994B05A7C787F8CE3EE2CDB8B52838E698E D0BBFED7CF796352DC840673205C8C051222C8D79A2C91C00CAC83935FBBD867 0FDAF3D5CB57AF5B7A66C9F336EAB6C2CD0E2391312DA3982BDC0F0EFD9761EE D6CEFFEF73C93532383A60010702DF10172DED3D110C49A5EC8B122B9B37AF5E B96E18A9A1A1EEC9AB974832D7A827A3D58478F67565E5D0AF0EF4DFDF1906A2 9E4B00D50B55972395C00C94C6A1186866144B8302A061A6CBA1929F8E4960D0 F25492521370D387373E0A7BE965FF7F7EF96BCF3DB918C8329E2693A9B6F684 CFEB965BAB37991C888B44A86A7592A4BD3DC572225D1E359098521A49834F10 F9A60A4C1D004FDC5EDB91DC02D0DFDB572CD58BCD6A22A189BF19CEE74D0492 E9F485E9D98E91EEAB0BEBE58AADC90313811A7101F077EDDEEE03F7C5AB5307 F6EFDBBF6BCF97BFF3D0EC5A154205336E4238946BEB2EA43DBF2E6E7DC367B3 2B452B9416130249A4003A3C3432B06DEBC5B999335397B48C596D362936EC9A 8F813AD43B603537342D64CCA1504F1A66B3562FE413AAE67FECE31F3A74F7A1 DAC6DADCDC4CA9BC313F7F399160FBF6EFDC7EE470B4396920179ABC6CE60329 152D12A12D7321F063397B9585361600404421536701569B7CF1C4698CBCCE83 DBA06CA7068182D42673A37280BD8463B0D3F5A917A63A47C672DBDB43A3E604 95244A8882D366D6FCA3AE3B1B415FA0BC4C290C1DECA78846B99B9B08060F0A 0C8E2E9DD8A8D97CFF9D5B9AB5D2C92756DC62C60E69898AA56BCD476823420E 8BED4058DCA491B57CD012928B1DAC5978C3C434BC61387AC3AD3736F1453FDD 53F18FB07F732E2ABF3CCC922C45604835ABC73446037D285495A8991947EFFE C39B12BB3600538FFDCB52B4846E7FF70EDE5E6D7836B7FDB43678EE9BD75EFE C9D45BEEDF91EF92FEEF28D415A5216A5E91B1A906A44A83EC4E4B1415D9DAD4 85F581BE0E2D598A42B4782DD3A8D5B68F2580404B41F6C42BB3299DDEB4B7D3 87CD0812E4315CB740A49582D4331716A71BC0A6C6220797CAE565D7914409CE B022A30F45A443A02895F6A94A0FD3D554FDC13BF2FD6DAE83F4D995467B3BEB 3A9C86C3ED56B5E3F9FF7172F5B4D508C8454752579BAAEAC8B0295229D463FD 208B49330B11D958E889307A8B82FA83ACA9570EFE7AF7AE5F186304789E8F04 B21161B71E30967EF2ABAFCC3C1691282C8770D60DE759B8C102CE056C4C8681 27E75B909CB516312885F80062794D238ED3AEC0F18E4C6767EAB58B97EB2125 30D9154B6CAF3B4D01F12AA1DFA5E85BB44C82221635C7B2469F0AE56005E58C 280E36961BD1E2A2D8266A59C31B5663C5F12C11CD154515283814A57098A262 6149DE86B8ADBA6A8C319D33B730E8DEF28E3C4B6D044803E93D37FDCC4FE01D C3130A5A1E03E1565650B0DF7FBB7EE787264072152B1056071EFFCAE4E51355 1BFB97205FF24095E990ABAA80F5C817CB2F9227EE28D62894805BA217E9E16E 73E98B21A7A74DE2F46B781C15B216EBCCADDFF360B2B30B780D0359E2AFA12D 8A6BE82540C7F42438B5347DD72F1F7CFCF16767CF191BB0E334AF5E2C957C5F 5CAED7B25A8D0B38148FBFB25683504A83A24D61085996C667A4A234545B02C4 71CD2805A663F8272DFE083299B4858A0F57238262A3B5587049BC8A42286FD1 CF1071054E84A2F80D066934A26A192E4D2BF66DCB6C19F3235A74298D221109 54861D188F58C9B01B734E25273F5EE710B9E20F03BBFD99C7E6DCC5F60085F3 51E99A0D5718F64D91A219F2F340840DDCE0C4168592CF684C5D962950EE5249 E6967D7B9F85B15E0A7C63102A44BE478061A51569C9E48A6CDC9F40C36AA547 E5BA4EDEF1F15B076EB3A4AE5DD8C6759B4439462DA6DA38187BE1AB2B27BF79 41098222E49390CE44BC16F922F18F41DE990E77C3E4A89D5207F87D7FF98BDE 448E47BE1A5C87E1B26C363351ED2FFBF2306329112427BF53D6AEEA9A659FBB 74B5AE76ACB370BD528C1CA56064B2E94647697463E4CAD12F0CF5F4D2CAC36B 8B4F1647C6B6B2840D795DA7C095270694866465C5B5DD8D6DDBBB375648A5E8 0F4DE890D65E39B792346EB2E6195BB3D6DDB91DEFEBDEF69EE110DA5C31A59C 9684336A64A8AE1250246AF5360E75F908B84DA4D07C62D35A5D9AE8C216BC91 2A6AB1A29E406CE5B5E5471F7DF98B7FB67EFECA9C0E70269DD054A46902F184 9613881DCD4465148A20E48865105001E7108C68AC542DD6790865D38DC5A2D5 524949A42B9DF2A496D64CC46950DCA888BA52D3324B1B4588614621E9281AEA 6CA71A2D362A1EF448B270F6F2355D8ABD525FFC033FF8D983BB974A4B972A1B 1FF9C02FAD5F5FFCDF3F7AB24124DB4A8D483B56760CF48A2454F52A1661B3EB 755188524A74853AF6FFE1EA3DA3243BAE33C18878F1FC4B579959DE7555B5F7 DD68784B10044582A0445214ADC8114569B5D248943B3A33DA5D8923696734A3 196966CE4A3F2869E4471297144990201C0D3C1A40A31B68DF5DDE57A577CF85 DB1BD9E0FC581C9CD364A1AB2ADF8BB8F77E5FC4BDDF17CF1432EFDF7F2CC4F8 C5B7DFA9739E521C0BAD06A2989A182E798E53AFD582C04BD3C8CBD9512776A8 E55A6AEF9EF23D771EAF6EEDAC2EECDEBCB1962FE51EFFD87DF7BE67CF815363 DCCCDD72998000E95F95C9FE76634A4452FB34F5FB07B55221706500D321823D 699931430E763A2B5BEB6FBD71E0FE3BB0039B1EFE36CF741C99AEA766851337 680D779FAEB4CFAE7BC7069D879D9EDC29B57200CC9AF91DFCC6D0FCB38B3821 1E99DC8C19D07D58633751C6506FF6612F9741CD0574F65CE3D823E3B9626FE3 AC77FDE56ECAAC068DD74D763349D713D4E2C2B0B5187A92D810CD16EADCF21D B975342A6F09EAF5072DB419DC8FDC66600D39E77D256E9D077EF4C5FE04957C B79FB42FA390B50DC8F28A333949B3B34A4C5A6A3C9BEDB6D6EEFBD4D8997F3D 1D9B0DD4B1BEFB1BE1D1C7D5ECFBFD76C86D898D4E98AE8DFFE31FBD313268BD F7E121138A6E6A736B1BD11C8004F8A4C09709817AE5F28453E95F797B63A834 902B75E177AEDCC8D62BD523FBF39682B4563EF7C6128F7BA74F4E4A2762D8B0 04BCEB246AF3D81D7A61B1F6D66637C6CEAE4037A3CE52378AA0089AB07C007C 4DCCFD0CA7D32E1FB7D9A4CC439EBDEB00BBE7242259FFDA52AB9CA7E3F796F1 A111D62BBFF85F5F5D78B116A3F2D54442AAAD51A3A10574538F00BCD6E02156 4628756E958C399679DCC44744DE659BA7BE387EF257EF498DBA9EB3804A0994 151291C17B3706BFF11B37C2ED2AD4FDB5A8BB22AD65A8DCA23FB79D6A2B6565 26D84C2CC0B369308DBA45CFB6953D8469396D9C3E5268E1E8EC62A7D32B0FF9 058F3677A2ED3585EA4C8C60FBA03750F05CC6DA33596B5F6062D642142A8C19 123732B21B6BED6AA3577148488C8A2EC33255DAFACD11C2112C4B4D0B102481 30118EEDEC93816188DC58EBCCE305ABDC8EB12D8223673EFA14FEC0F40165EE ECC1E428CF186477EA3DD9F77CF60E946912BF87EAA5EFFF97D5F9B3C996519B 47EEB66075ADE6406DA6DD6E63AD547FCBA85BF1BE4B3841D4142C45B8C10533 6840F8984A0FB9DE08175912EE3FE4BCE7037BC3DE3AE52689430E083FF2B384 216E3D7BBEBEEBFB1FF9E907FEF12FFFE1EA257B9B14AFA695EBB52E07F4ADD2 FFA592F5AE5423BA65AFAADD510DEDB8D41FFF2334A72F8C55E4E8117EC74496 9550A05C6A4058847BA18FCCA0979566CD61C4D4255B0B30EB3641A49886893A DFD9BABD89A4C4E8924626F1C75274C0C7A3B683052E0CA19367DCC102D37D9D C004FB5DFA0488BBB2B40FB5A6ED0985E2A7156E5C20949C24815DD8BE822F3C D76DA6A465246B696F8DCB26B5C2BE6E95FE2E41848A80CA5850F63867022548 635BD4F710167DB9C73EBC45FD3F75E5D7069AC012B554880589891B4080DBFB 72728EE33DB848CDEEBD9F2E9FF9581EB6001239E175754D20196EEB8BE6CAC5 CE37BF7CAEF78E494C342FABD799BB85FD6ADC9D31F18CCDCFE0605AB9725AFD F857BE984E67A0325BB2C1E522924D43DB3633F8813D7BDD88EDD613ACFB56D3 1FA42F3D7F21E8CD84227735DCAC87EDB21D94F3E440A7BCE56CEEFDC2E8898F EE479BE19B5F3937828BE569B74BEA16415EFF8442114F84C5CDEDDDFC84E365 9DC51BCB39C71D9B9A585ADB64A915569CFABADAEAECECBB3F7FE6F3FBD26204 A546E9E30378660F9BBE56F0B61C5B0E4A6C03F380B822CC93C8134A6B88E896 25A1DB8089EDB52B5DDB2C361AF8DCB9857FFEA7275F7C71BE121A9E6B3ABA97 8AE8DB04AC9F0C23F88946C2719ACA5468631F62F444BFDD422BD76A351AE1EA FB474021525A462F82F5377C2F4321B0E364AE54F625D969B77A96510DC33886 046D0E01BB76338385DC2EE96D6D6DCE4D1DBD72F166236E329BA686998BD39F B8FDD8A585EB6A70F8A73FF7D3FFF0D77FF3D2E545E458284E071D63CFE090E3 98A110ED90D55B612B4C18418E47511A054ADD7D78E6C0E8C82B576EDEDC6E53 BFD4AD75E1C576646B60B050CED8B8D6A5D85C8B427BA444C26D292CC07E4160 667D64638E639974A3C280FF4BBFF6B9F73E769F55F2A22436E90ED286AE96BE BF355D9600F534FB05056A5E5B62E0A95D3D15CCCD7E7F3807040C0405A28039 AE1DAAAD6FFD70AA34A86E9F0CAD164DA234B4332A559D5D28FFD2CA5B753F7E 7173F7E2DAE0C1616B26802D46E0BF8AA66CECB9F2CC35BCDC72D1501DC3F610 9E5236E32860B3F70E0E4C93A81E9D7F637760BC3C77DC89EACDCB3F0C57AF50 62D15D555DE6648179DBFA1A53AF9DA5304BDB4A8BEC699F293DE4ACA917AC9B D64E80E8E61ACD10404B063C89E4E847531658B31DE35D43E6FEE5A2CE24BA22 2ADB6494D85CF9ED1ECF98C96C2E99C17C06953C69DA63EDC77FEB74F1A8803C 77F1BBC3EFBCF2E4677EFEEE78809A54B1ED8A29475EFCCEE6CD1FCE7FF47DA7 FDD15E84DB7EE81A8E6222151C6BD7582DA7D2E57A5E337FED423797C90F8D41 228D3617ACEDCDE6C963632AA9536CCF2F749716DBA74E1CCD0611355B482610 F2715D59C29F6FA74FCFEFF0C4D954E615992EA6BA6FC544B66E7FB7F4BD0AD4 889CEB0DFACEA1341C219992B1FEE0C3A393D3130B5757827C38FEFE71345748 B875EEEB17DFFAFB8D4C7C6427AA5F34D3150387B1263540A00C85A88445268C 73DD696DF0D441C7ADF08898B2C2E6ED3F3B71E7AFDFC6511DF22FA4BEA81765 1D57724E22FAEAB36FBDF6478B380A2CA3B0DD034C9B2E4ADCB1F39238864C29 EB118DECB5CA0EC569C9F2A6EC4C49C80199647078FCC01E16B12B375784EBB7 09EE411E8ED0360B2D9BECB5BCC399ACD76B16289F1CCC230C495A2F23AC81E1 F851C296365B2B1DDB70494CF84ED46B497D8E026B99B72DDF248E4521CA9BB1 1653DD87644E15DD62F3AE8F17EC8926422E728FDCF6F127F1E31373DCAE4D1B F404CF50BA3DF93014C27BA4D7C47E5B56B2CFFDC7D595B7D48E59BD2E835D95 3475FB00B198B60462FD5E94BEB4BB6206E93B9E1147A421C26D6C434ECA9268 96C83985C7082E04F103EF9D9E9C75D3A44E9822512BE19E60850C0B93487CFB 9D5AFEF6DBEE7BF0C09FFFD19FDF5CF0B669F16AB475B31E42A65322E9B77EFD FF6627F495B6BEDFEFDBCF6BAF1A420ABA25028580F10D6A51E5D0148A928573 C2C0C28A32C4CA2659E9B69D54CF0EEA4E1F24B56D07868DA395810DA62CA93B 5E128A13AB33980413093AE89B65C705D230328B0F9E343C9A90C4A6D2E428D1 F62DA8ADA4AB6FE90D699090E2486A751D97E93E502B6E5B975EA8D76FB87524 1A245D4BA20A46A1EDB6E19BB9BED5E07D82472105C06388346110B4BA6B43F5 6FB9A4BECBD4D650DA5992E91B58A43F783F5475BF38E1D26314284B63D6E7FB 953716672CAB7BE041FCBE5F3CEC0491EE70B57B06C0395A82E04D9D8E1939CF FFD9C65B7FBBED1AD696DA5931FDCB6DD244F690EAEC77D1EDCA9DC04E34297E F2CF7F8E4FE700E698A8C3D5A212DB86AE41B0F07E9DAE38CC12CF9185EF2FCC 9C997AE1D9B3686188C9A14B6CAB1A374AA65BCEDBB349BE25EA43F7BAF7FECA 5D38636C3EB378F38977EE3C7128713BD24A00D459803453C32623CBCBBBD215 93FBF28DDDCDD6361B1D9DB37DBCB8B484E2C185AB511B20EB5EFAF02FDF168F 35ACD45201E4E1D4942E8180B711A7BE418AC00652923AC2C222A360FD743F3D BD65DA085842A4F28DD72F9E3BBBF0DA6B8B17DFE92CAFEB46606C9152A96000 2E8D933465FDDCA7DB25123D2B496045528867600F5C0F6C133D5F419964C081 6C824BBE6703CC74EC04E1CD662BE23C708CA15C41345BB3A3E3B06495B0B7D4 A8E9911F89F2C4C8D9D681D9290BAB959DADD9D9C3F5EDD69BF397605F12D773 C3F081437BAF2D5C3FF9E0234363A37FFF4FFFB8D1021465945C52B29DF152A9 D26CF4A4EA46BCD7E6296CF52080641AD5EBA7268A0F9D38B553DB79EEC26566 D832350DC3A9F59A86E2771C39D8AB578DC05EDDDE1ECE0FB6776ACA4FA5B42D EA17E191098B7A4D48118EADFEE88F7FE7C18F3C2092DDBE243F90AA96D0F09A C65A9EC682AA6199B636600252A8AF09816969C93813F7F439233158DF8D155E 71625B01B393A7DFEEAE6D0E7FE2FE0EDDF558CF48BD340E298F0C06A95FC6CC 323BF6EEF76FF2EB95C1C921E7D8B0284B16555D67A8F27A77EBB96D2BF6800A D775FF39CA00D430E2D2017FEF1D3929C3AD9BACDEE07327B37EC0EBABE4D5A7 6A69D78C4DB6A5C4F588AC135A955CF740A402A0780ACF019F0DD60DEA8DD25D 318012F54D2E56B75AC521B30307ECA25BFD34BAE6E903A4FE3FB74E5FFA5FBC 359BAFDB9E34FC927E2F11F0BF27B26C0EF329E195CC6C6AD64F7CB0F4F067F6 8B6033EA1D7BFD1FBF5B70D4C99F3CD253CC6A0292B05B55FB9B7FF2D6AC3F70 DBFB4862ADBA8DFDC481CA1709200024635013D1A6221D24F217DFECBA566E7A D610AAB7B34CD7571AA78F4F2351A1C4585BE76FBF5D3D7AF8F868995363476A 19583FAE233B86A7369F9EDF6AD4D50E76AE1B683EE9369BA94B33B096D214B6 3EAB84B0B71C62DE69B171E115F1D6B1D303878F1DDA5E58C90C86238F0CA3A9 0CB7DC85E7579FFFD39B5EF55003375F559D05DD3E0B05D5D44D2052628E5241 184B03821D17B7697A10358EA8FD4ED2BDED5F8DDCF36B2761DB403869832140 AFDC5009B35D87F1E8C29FACFEF05FAE16F0742FEAD62C71A993AE612BEAEB7B B97AAA3D5418A0960D30C4476AC2F5F2A918A1282BD382A9F68D8F85697C696D 8DF9B97A8C7B09AEA8180AFB7E373896CBE7A36EA0E291C1BCA147F46E498AE9 F9750C50AE95DEDC4161D20308034CA321653D8A2396665C28827AD632110290 25ACF72C14425E70BCF6C98F05C5FD890141641D3EF5C9EFE20F8DCF32B33A63 5A2754D6362AC0081FF8CC9DDCADE2A02B7633CFFEE1E2FADBA4E674AE316B57 F126859C4068AAB56BFA3B4C5BF462ADCFD8BF4F97C4467128516CE5E0CB4560 81B62C87E9A4E78D8EF0F77F782F351B2AD5673828EC72E14AE9DBBDA45D67DF B8B87EF7E73EB1673AFFDFBFFCA79B3BC55DA770A9B77BB3D2C6D445B081FA67 86B7405C5FFC5E9B6853A3EFCF47F4F083D462A728230C0B19C0FF84AD0B8B67 4089D1C3E71E355D85E16B1029D25256BFB734265A6512AAA0A57576A5968BE3 82422E354C661A12476569CC2863C6748A966B5AE9DC097762165E679B32CF26 6E0CCB096513D284042202BF966323EADBAC008E84AA281CA7387FA977FEC52D 9B0D6E2BBECBE2CD386A188839410F6860AAB18CB64544C2329403081CB0B602 1E690A48CA9C690C4BCDBE773AD17289A21F9EA4DFA3A38938144753574DC001 AA3D62B039E48C49BFE42A67B0F6B15F3C357298482F8A010AA91C911965B1D0 ACFAC1F0F2F7D0D7BFFC9AD5F15ABCBEE3A2ABA1B31A7A83B4BEDF336E53DE28 B6BB23C94F7EE5E7F1DC80161AC3C08A1605DBA25CDBA9A1D46D391BAE70F08B D69BFFF2FA6DEF39F5E6CB976AAF1B4C96AFF2EA4EDCC812ABEC9BC366218078 CC354FFFFCD1FCBD05D444AFFF3F2F0D47D9C1A9200C1A3EF067080420F3D26D 34D56EAB3135EB3B365A5F88939EB1FFE8C4C6FACDB49B5BBA9EB6C2D0CACA87 BF741B3ED9B4BB1672DDBEAAA8F9AE9C9199C324AF8F40516A0A47491B5B5D2D 9CADFAFEAAFAAA56AB0737ABBDC5A5EAEE26AB55F185B757E2D878FBE6EA8D6B DB296381E72A64B3542B288449CC0184BC3B73A8019DC96EB56261CBCB588117 B228E9B57DA5863C3F302CCBF39B095BA9563C8C0B99AC619188C5A3859243EC 1A4BE777B670AC818397F1E746478E906081D583C2403633F0E4F77FD035941B 7846141F181FADEC6C7FFE0B9F7FE3FC3B4FBDF83AEB4FBC4D943259443296B3 D3AC71D394CA6CB7A3081E2F9749716C46F127EF7F0075A3B7166E34795AEF86 D8B47B50945271FB8123A8D26C276158B462168D866A5279F36EA2223C902DB5 9A1D008B116F7A79F56F7FF7973EFEB90FB2645B888EED00BF8B0C52427AF28A A73CB66DAD30A92729FAD18675D948A488754F8ABD6E700AA01236202369EC24 8222AF6B59375AE7BFF7D2B1C7EFC22358A51543069D30845DEA45294D7857C4 342846171BD1538B7433CCEC1F714E0D267920E36B5E6572F55B3C598990479A 922642DA94C3E7C1057EEA03436EAECDEA990B2FAD4ECE8D8CCCDA5CA89B6FC7 57CF86423A4DD25B576831251B69CC2D28AB14C20819293C8378D79159CB4569 734543435ED9BF6FA75CEB5E74A9D68FB965C10D29C1A2E6ADAB419DBED02D71 19D13F5CD5461C14702DD29D4539AD078266089EA490BD537B24FAF86FDD973F D04D4DABF5227AE5C9171EFEE231913172BCA4E22D1CE4BFFF978DADD76A1FFA 30F5C736BBDB876CA7A9ED64A4169BC4C4246648684F71FFC2D9AE62F6A1E381 92ADDDB5606569F7E4B149AA5AD490BB557AF6D58DD9997D735394922A4077D3 C844F5D408694A73CF2F6E2FAEB7778D60C9C28B71B4D5E8419E2390F1B4914D AA2DF2B0E552F3B4ABC6B83D62B6CAC3C91DB7DFDEAB5706467A430F95D19E9C 74BCDD0BF527FFC379BA7960D3ACBE85E20DF87EA0C1024748244AF4BB450DF8 BF598C03D768B0F62C6E1D56731E0B8F7CA2F0C86FDEAE9C1868430C01A8DBF1 0C99A47A7A9712B4E47DED8F5F5A7AA5039152499315692EF2749B770D5AF088 4FC9AE52C01F462C7DCCDECBD9E6A041C6091DB3896CD5CBC5CCC4D4C4EAC676 AD1DF7905509D38E8D63164EBBC1DE4CB6287920E2E1013FEF5B5A47A1DFE101 A9D4F1FC141B4BB5DED64E4B015241662B4D7B22E9B2A8DFC1A1CF0F75273F56 9E630E23ABACF2BED39D7B884EDE66C04E16EEA1539FFC1E7E7C7C8F30ABD3D4 3A86F236D99D7A20FBE067CEA45E156722D2287CEF3F2DAF9C174D3BBC92D08A 640D536BD2D304E9C2D12F7EB4BF8D1840B27EB716255A2436C690F1E8B811CF D26458E282430F1F75EE7AA04051173E9DBE8388002D1A8C4349B12A3BE29B97 173EF25B5F3450F2A75FFE9B56B7B84EFDAB61FD66ADABB55D905650127DF540 DC9F7612FAE00BF565423576079407FB3A36B8ABF9A86E180592A6BD7F52CBA1 2A08F80031B35D8742480491368A171AE8C2C68108015267F75B7154DF2099EA B1547D7F6F095C86EA6219A3CA0F9031344E8EDC997582160F13C2ECFE2C5A0A E08BEA3B3D579BC050AD2383E1E769FDB3C8F68CB8E39F7BA5BBB9AA95B23790 AC2431FCDBC184512B963885BC8BB4F2A3E84FCF3BC870B4781A517AE4420257 81428774E1267DD6A811AA6E76EDD36F2091503499A44C9704A6782F1072CA72 A0668FB9AE12D5071E9FB9FB3363DCB819F9E52C2EE144A08033DAC64E5E554B 5FFBBF5F59F9612B30832DD45C26FECD56E0E39D0301C020775859BD09FE913F FBA23157D285104A965A6110204CF70A62E074CE3649887FAD74E55BE7E68ECD BEF3FAF5DDD71493833765733BE93802173C3367047B9C8CE86D161FF60FFCC2 011AA0E8E5E4F2DF5E3A716C7FE26F98AE3E0CF66CA7D7EBF9CEF0F2CA4EBE28 8A25BFB96BAD2FB767F61691D1A9EF0AD62B5EBAB808E4EF8E9F3B987B2C327B B04A9E722C5859830280F18451E0348389A4DA995C8FF4201269CF3C4DA48916 54D2BA69803A3D64067ACC8463DE4BA422405D373777DF3A77E3896FBDF0CAAB ABFDB66A5B232B9DA880E90166445AC8A02F5A2B39720D5ACC1502CB8AD3B0DE 6E6253950A858CE90E3AB9F6766DB7DD1686CA0D956ADD168F93F1FCE07879A4 D6EE5E5E5F69A3C4B7CDDB46A6EE2E8C5D16B5959DD583878EBC7E6DF9E6C6BA E7E81B6CDFF18783CC677EFCB1AF7EEBC9B7963724E4398B0CB82E663CE9C5DA 9F2B9749B8ACB77A0A369C0391AF8E4D4FCF0E94AF5DBFB1D46E03B68B6D5545 0924AD9313537969ED74DB743057DBDDCEC47C2297755CEF6A14A7ED76D6F254 AC92247233F2677FE5C3BFF01B9FE0B49D023432E029B90581C48B3CEDDE527D D78C5A68656A6DC4A165EAB4CE2CD25B4E327AD3E4A691F623C8ECC51EEC0A61 7531E5C1CD97CEE3A43777FF81D8DAE57A5A92C8760FA5B10974388E59A200F1 77AEB6E21757CCD596379E2767A6D1F4961317775E30B75FA90538578F786C31 C02486A2A9C90EBE2F33B42F5511BDFCBD1D8A33FBEE2CF67003B3F2D9A72B8D 352DA256411CB0D336651BDD4EC2B304E5080E39042FE98365AD28A467E6B5FE 63FF6445B733E83AA912AB7FB6720BF2F48F936ECDD46B5ED83F0EEEE34EC1B1 696912CC4CD349B8B6CF1EF5F85E37DD23490967B911DEF19363A73F3258CF2D 15778FBFF12F1732FBF0DC5DB3AA0EFBAC6AE69DDDEBA527FEF3CBC7A7CCDB1E 1CE84ADF1035AD23DC6F2BD1F2568060AD4871EBD29B51BB264EDE59020253DB 2840213C7E64CC441D8C925E14BCF2D2C6F0F0C4BE69D3B15B9AEC192EEB0AD5 821C937B67AB7171B5B6819C55855779BA9B8A1EA32907962E6C0A150C9E9BBA D4D967CB3D863F66776DA379EAC4091727F9D1C6D8C3C368A628296A5E6F7FE3 DF9DA76B4756ADD5AB586E1B54A514B37E479B01584E484C2C626510CA58462F ED0C92FA21B937E0D1CCE3D687FECDDD24A78F00533DBFAEFD540D046F32D56D 1AC8D97EA1FBF75F7E2697E4BB5DD5B49DEB497595470919340CD7203B48B431 9FB0894A39E0333EEA792526663C376B08C9C3E1C172295B5C9C5F6AC682077E 4BF156D8CD283CE4FA238E9D531CF0E66811D888D6D9177AB32AD3B69145DB22 DDDE8D7BB19B72331140249346D2ABC4511BE090E35A1441A9F54D2387DD21E5 F9665A3C901E7CD0135E9804FB4F7FF205FCF1E939665426A87904E52D5599BC 2F78F0D327D3A046B289D11B7AF5BFAD5C7DB9DBA2F195C8D851AC69E9892223 D5699B19FA52FA1623E4FA90453B5F201A0B6C85899107126AF149148D393EA5 DD07DF3FB6672E31582C622B6182265AFF4CCFD9C5C585C5F8C5EAF2677FFF97 D7AE2EFEDD7FFA4627292E627A3DEC2ED67B08D037D15A4A5C17805BBDD1F896 6AA8D997D5A67A004A03832E4A008B78C286CC07244D2014A46EC192E5423A64 58A57616367C27A87139C0B8680BD102CEA87B0390F3AE86A730B19EA5823A14 6231840A45B33DE39803A9EB227EF0643077DC8ED21A5036994012D3A3C10C52 82DE72B66E283481234B81FA026BA8ED65BD95CBF15BAF41C51EECA43BCB9255 198F000061124128725840DD87C74C00A91A81427C78BA010EF79BA04D80178C 4BD63785127D7138D9BFF7577DC4AAF41D964AA4C90C8EA05671662468C4B567 3C738AD8198E27F6999FF8B7475571BE6DE573284F606367E0C7A5C22F986E7E FE99CD7FF977670BE14444926B3C5C650152CD19C7388ABC22E48C03EEE37FF2 0539954590BC3477DBE2F1264EDADAC020F13BE6160A65666B6CFEA9B787C606 972EAC6DBC923239B48C7B5B71172732706999E48689E1E1381A6DDEF35BB7F9 739256DCB7FF7AD90BE9F80412A4DE1F6680A08D5D331701CE6C5547278711CE 6CADB7A48C26A673954A4DB1F2B50BB5CEB6D8FFF8F0F4177DDBD6FAD0D2F1B9 971A342128AB5029B55D60CB40DD90EC5FD3F6FDA2557F04540F01E856171B72 4DB31EF6A2348E81F3E917D98A5414C96A357EF1A5CB4F3CF14AB58EE2144BED 3BD1EF25D613695A6B51F7C4089D2E8125DA0807A695C9F892AA4826B0DF5C64 8C589992E5AF351B2991CDB0ED65826E9290444C5AF989B1C917B71656E27A20 F111B778787422CA9A576E5E983D72A8269D975E7DC3A53CD29143DE77C71DC7 C786FFE66BDFDE49841B383E92191FE23269367B9649F3F9CC6EBD992A5580FF 84CD91C2C0F8F0E8FAC6C64EA7D566128A7F8FF27A124D1672C78B633578A4A2 B755AB8C306B847849C6786377B313AB8C0BA9863BC4B04DFA852FFEF8BFF9F2 E7B9B5430C662017EB5B25A5DD4552AAAF57A9D25A2110CC14E2E0568FECADDB 7886F42CAF8AD08A9512FDFA91BEDFE734B285600233C0E32BF5ED6FFEE0E0BD 27BAC7FC388A4BD812B56AAC47D1909B10550B996347D461EFECE2E716D026C3 23A3D6192F18F7E2AAB8F154D5DB1A53290EAD4A93353C73A8CB9381C3FCF823 45866BAD6BC6F5D76A07EE1FF2464D0894CA82B8FCFC6EDA09606BAE8AFA8E9D 5C87F525C34C3B0AA4290636D49F17D3565B90C8B97E08A3DF8FADE9A076234E AD5BF2433AD4B561BDBCA5DBA4D1931EF652EF4EEBA608D8B28005A78430E2A4 927A34DDEB2507149EC145132B67B6FDE12FDD450F6D3A9D60E342F8EA2B57DE FFB107DC62A27A75A9EFA04B3FF8B357765F151FFAF04362E41D9A865806FAE8 09C53A5DE80BD9D024D6C265B2BE14DE765751E14A6373706961EBC4B1095385 18F752917BED955DDBF00EEDF7033FD22D7E525F47A535C834C1768FBFBCB83D 1FA91D65AC71BECE6555E024E6AE817340BAA46209543A3AE1A8FD6E6E9C860E EAEE99981CCCE3C1A9C6C47BC7D4745E50C1B6D8777EFF5272656FD3597F9BC7 EBF08604140B23C500AE781843A6335DCB73349315A9884B0E30C2BD79C5461F 451FFEEDFB6841B7806BF00FC54077532BC9536D2A6E2476A7F0DA5F5CBCF0FF 2EBB69B9A3D812AF2C0B544541AC5F729B08A0F105DD0B4F7814F5F28E3520C4 A845075D3B63C0C656A303252873EBDB3BCC3213D368F6429602ACF446B3F922 56F001C6F34EDEC3BA2B539B8B116C18FA5AC943A9F01A7504E85470C0CBA41A 415E0AB524B70D455E5FAB006BB6A833248D2CC1F640EFF0C38E339976FC3DA7 3EF52AFEE4CC0CC3F5316A1CC2795BD4F7DCEDDFFBD9633C5F974E64B3890B5F D938F7DC4E8FF07762BC23D396A9453A69AABBB29816A2E046DFF286EBE17A28 86B0D680BB4DC98D41A2F6D96812A39C850727C4031F1C0D823A6F774D99ED26 CC4A7D2E228142B737FED685DA82D7FAA97FFFBFCDFFF0F257FFF8D9569C5DC0 F84AB7079040CB820275D5E7157D11E07EAEEABBC8E9C10908584BDBD51A8AC8 50E9C32C5F9A2EB2A42520A58F5AC5119C0EB9DD61DB1A94030AF19ADC66A4D4 65AC2A789B12A119A3BE02227A44405143CF14425C3022A7657EC08E606DB2DC CE07C9A93BF399619D4C4DF8E1A9D6D3967AC42205E20859587F22936BBD7EEC C0A6F01C811276F1B5D6DA4A91D9C56ABA7A9DF5AA89D0A38ED44A13809BFAB3 4608C506D1535A02BE15BB5AF740FBDFD0BE401C54C118A2544F5350AD04D5EF 26D52777FAD8478F0BC7CAE4DAFC38842DC852C3A7723647F721675C64A9517B DFCF8D1DF860A6093B12651C9A621A4B6EAB5C59D889D5F3BEF3FBE7E79F0042 965F55ED8530960E1DC1FC30F1720215EF1E7BE80F3F9B966C14739324885645 BC83E29A41A0CEF93D5A25897477CA979F78B35C2A265BE2FAB3D554965751B4 D2EB449DC4368D396BB8E88A8C8B5BAA72E04363077F6ACCB071E51CBAFCCF97 8E8D97B303495700F9A0B04286E4C0F216AE6C96C6C70746B38D7A6B6DB13233 37CC507B7333A1D1F4D6953A1EEE1DFFD793F943033CE18637C09C189B099539 244BCCB120FE2C6EEA79067D606AF55DE8B4D74DFF8E87E8291D643DF59D175E FAE1F9F9F99DDA6E025031040C11AB5A0B85897674B55D3F4A045070AD4163DC 5273ED0F964321E0C8C104228869AB1F7DC30FBC703008B2909324248634C864 8481DB712FE2699AA4B95C4E8669D4E8ECDD77300CE84BD7DF81B49593E6897D 33137E7661FD863739EA8FCE3CFFFD972D9456A3D0F0B39FFDF0873BCBF34FFC E0D5C2D8B8BEECDDDD713CAF1B4551C2DC8C6F00666FF60A1E29994ED90C4A41 7EBBD36E20BE5DAF677C3F76A9D61CE9C4B7CDED6DF79A5ED1EFB65A3EB26C62 F7103ABFBA160A7D54E1F85A5D1772A8E3D85FFAD59F397366AA5C5258A6896E B9778320989C187361EB69534E96C6DD7E8335ED57068AFA33A40838823EBF90 09AE9A29A3498C081316D39D43901D0D59CFD07C4FA6DF78C5364CFAD849EDAA A6520190374D69C82C4D2E1860BF8E880214180BC9D6938BE62A0E0B99C21D6E 6E9FB5FA66547DC12970BF2DD76233C5A4A4554BBDE689474BF644C30CB3179E D9145E72E4CEC3DCE859C8B8FE6A63F91CF0B66C03D7D750635DF93B3CDF8814 3038484BA9FECC7DEF29E07622D12390FA9C00B605D0309DBC127DC5D9B7F5EC BB32E90651532B6A306D3E24F4B83DD28900A88DA97784AEAD524B8D5BF0F7C7 2C79CCA0079453B2ADD8DBBDE763A70FFD84859C65DE09BEF395CDD1C181DB7F AAC4C2AAE2039615D7AFB6BEF6EFB7EE3AF2DE3DF79D27AC87645ECF27921EE4 4FA45C62746DDBD85ACE5EBB583F73E78061D52A6BA585F9CD93C7262C1561A3 C765E6DC9B8D6E83DD7966CCB13BB6EB329E02654A6BCA8CFD44993F5CDEBE58 87AA6BADA66C818B0DAE0C6A6729B5303C072302DE879933D9ACED4D1871C150 E520375C963347D3A987C7D4A8C73C413BE4B93F9CDF7E6188B8DBE779BC44CD 185B4A778DA561DCC3A9D20AA69E0FA42B4A3A511CCD14D9413E972762F021F6 D1DF798896A806F5A602946D6A4F3E78737A80B381DABEB4D225FB99DF7F65F7 BCB68E6C1A7C89C915C8260A4A2C7680AD6AB90BC8EE661A87A6929EA10A1497 092E233200E50AF8F7F010A4FAF5D57502100AA19676ECA639D71FB4EC01168F F974B4601B462C485F711C1805801E4B7A41BE1789C66EDC6DC13608BA925479 D2A3AA2313F8C7D57B9A529B0E1352A6BE229DD9BB54FEB86A0463A73FFD06FE E4D40447F511D33840066CDE9ABDC3BFEFF34778A9C168CFE39397FF6EFBEC53 EB09A1EF446853842D0B00B1D6A880E74831A4126EF47DF238A4353DBB870197 00700BB03588BAFB4D63DA2E2259B9F3D1E291BB5DD822428F7FB811E738F485 EC0A7865C9C197CFEE36A7E2C77FEFD38B4F5EFDEA7F7EB11E9A8B545E68C66B 4D466DD3D43A6480EE342314FDB109D2AF8444C33AE085DA7D574B7D6A420699 CBB2B0A9A702A931E90407A831E770172500F7B45BBD104D6E5459B2C5799352 695A581A50C24C6DEDA2ED14FB8E339A4FEC135EC14565C3CA18687838BEEDDE 814475D298F64F8B186C33A9BD4739D428A2AB1846261614F5252C49D6A2DBF3 BB97CEB505DE5711B42AB7E645D44A859E33342CA98FEF4D8084B0B45D02285B B3515318960E4E09CBC9A5C05A9B46AB9D020C88FA8A3DA87F70DA3FB7D1E5D2 00EAA401AE96D5309415737D9F38E2F103D23C48F224A98EDD2E3EFEAB0F2623 0B489509944AD1A276815B99C889327666F95B8D6FFFFE39AB37105A6423E9D6 291A10E941D3F3859A7874DFDDBFF799348321A7DB3441465B255519ED18A48E 45A69D6EC1D3677BC3F3CF5CF4A967B5820B4F2CA5B2B88EC46AB7D3EAC6F084 B3A4502E9A806A6D8C9D3179FF6F9E56132DDCF32FFCD54D6F4BEDDB5F48680D B22D83C22C7A0E938D4D3356D6F03E9398ECC6A5AAEFE5C6F6669696373DB1BF BD186E6D2F1FF9F4BEE1C7065AB89BF307B92594C5A866B105695309D452EAE9 087815DA058540E5F2FA5B4550ED04A905092055445DAF5E71966E84FFFC4FCF BC746E2349E366A715E9A141A13B91353485BF092004F92E85641945B048C401 38126B87D2C2600982A7DBEB46CDB6A7F0F8C0C080EF035C89196BF20E5468E2 5A26AC54AD35942D2ED52A4DA4EE3C757C7D6DFDCAFAB6E1E3FD63638F95F7AC 57B7EA396B6876FFF79EFC018B7A95981586073EF3D18F3DFFE4776F2EAF9DBC FDB6CAC6E676ADE2F89966AD059B3B33586CB69A58A4138EB3C7CD16DDEC4EBB B9CB590DD0B46D519ED4B0E2CDE8917D474D05C8425B061E280CC69DF0B59DF5 2BDD2EEAA11CA2C24E8965C0D3948746A2301C2AE559BBE2C39B91A9655896E3 50CB02AAE8FAC9DE7D7B3EFAB1C74EDF7D9CE8939D446B2EBD6B6084FB26285A AA8A911EE6A1C99ABA61DCD2222E3841DC9431946C151BE75637CE5E1EBBFF41 32D9EEA45DD3B4CD2E372151681DD74497D6388A424E6591ACE2DAD3D7D31DBB E936C7EF1B7682C1B7BFB5E8773286852A6937E1E6805B8A7BD5F11374F201C8 2AAC72035FB8B87AFCD4F1DC5044AC8E6CFB6F3CDBD9BE2989EBEFE2F63C67D7 9B4664661315319D91349F33B53B22D2B6C3FAD6A66F5F0821A70C0303864F6F F5C5FCC88C9050AA2772B57E05FC2B455FB81190AEC599B635850790FA0E8726 CC2819EE0142F609319B05BCDFCA8E0FFEE46F4DD223DB611487E7F7BFF48D97 EFF94871E840266E03D2838C38F0F47F5FEDDC440F7EC0CC6562C53DED9A495B 18B294CC2AD2B26C55DB2C5D7A630718A1E536B796F2CB4BDBA74F4E1BBC0B65 3295EEC5B7C3CA46FBA1FB0F29550D7299948788A5A2898C0EC033FFE5EDFA5B 9BAD26B7D6E2F406566B7A42C4215A7DAC6752D325808D896527138A4C997298 D2BC952917E3A3B7AB3DEF9B544366EA2546177FFFBFACAC3E95CFE55A5008AF 125293506A35620754E060C32616BCB7149201EBA63C3DE04573F19E2C6285FB A34FFCDE23EE5806454CC0AF0120C1E1D5270C6B71A5C48A3063811858FEEEEE B3FFF5E56C54EAB4E34DC46F22BE2251443C07591E8EA0A600E834B5A500B083 30B08C11834E6B812A5786DD7CC6191D2CF3766767B78AB24135E12D6D924846 3CBF84E4A88DF7943DDBD62E9B294F1CD3849D1C6BE4CB1DD7C2CADCDD895B2D 2248D04E45444487C751A25D6361CF1A012D0A56C6791EB5A64EF3B107ECC6C0 F8A94FBF867F7A0FBCAB6689A059355030D2F1E3C6FD5F38120DEC4A9A7A786E FE9F375FFEE60257DE4581375858D76E9DA6A1EDAA002CF5C5AAA5EEB865BA08 EA96E558C6360AF24A4CD9BD39EA166496FAB50FFDAB71BF54635DD80B411C86 DAF63B2C28D54C448D34F73DF5C25AF9FDE5877EE5D12BDFB8FC9D3F7EB31E1B D731BBD8116B0DDD23EBE9A1759A2429E37AEC4F37EC4A796B02D6D0223A8042 8DFEC43944F02D1B605816D777ED3D013D18A7C75C9FA1666EAE4805ED2DB61B 185544BA2179157E82E9E88E6AA16CA0759ADDA68E6DC2A250621C9634EF058E C0C59C3873A7579C88819DAB24D0D6A63881342B840BA5D7602125A6D63BD7E3 C71C00769A32D54557DF5CAD6D9BA93552116857B45614E06F7D040A20C2316C 031BB0801DC1DA4A44FD11377D68C3FA032196BEDA8D6163E8A94C432A432B5C F5954645BF79E1D6101B1122A6880108D2EEF6B6D093CDF190AD0E1372183925 8BB5C8F6A77EED43E38F2C44710930AD6725B053047645CE011AE455724FFDC1 D91BCFD51C77B09674374C9697C9914C316D35F77FE4D49DFFD74FC5AE228930 498ACC9E8C5B325CA7781331BF9BD630302139B2FAD24DD594A574E48D6F5C65 BCB0A6C45A1CB62288733A2470D65165DFC9007950BD933F3D3BF1C92213ADDE 797AE5AB37C607722363C0BA9A0A0F48D6F6088EAAC59D4632301B3BB9B85373 D756BAD38706198A2B4B49869797DF5819383278E0B7F7C7433D53233F0A488A 0A9F0099B41C0501255D7D3C4239E690B32CA91C3DAF651A3B3BEB7E0041E118 56A1D3A06BF3DDEB971B2FBC70FE89E7D65AAD5AC2637D34C4B57F16020C03D0 0A369540793FE35B6EB7D30D814CDBFAE410600E104FDF748084852CA9769AB0 0883F9CC6090293A5E8747CD56A7DDEDC162397A7E115E9279637B7B3893BFEB F8C9B7AE5DBAB15ED9333BFAA9E27853A4EF24ADFD278E5D79E3EDE5D59D5A14 8D4F941F7ECF7BBEF59D677CDF3971E4E0EB2FBF99120A5C30ED85806BAC814C B3591B0DFCBD7E76CCF27B2CB9D9A8340C7DB296753C8B25F07B0FCCCC16FD4C B7D138BA7F2F6440C82867176FBEB1BB9B1A860F958150AFA8E0CB491C0F950B 59287B4285F5AE6B38AEEBD53AB59E88153C23B50E1E291C3D7EF0FD3F76CF1D F71E83140C410C1C98E83173C08FDA28438B354A8D7A314D086048D6552216B6 A95D3B75318921FB0298BBFCF517CABC38F4A99128893D661B71FFBA31AC0BDE D1C88E4361B2A30EF2A59B6CB59BDFDB6C6F43C859D3C7C676B7B66AAB5CA685 AE144C2481F4324AD9A5C6FE4707F94003A9810B2FB4D2303C75575938BB8E9D AD2E9BAF3DBD1DD5062293AC1BDD1B9DB4865C003CFA0017C0AA5416C28E6681 5A120910285447266FF56143727C57B2F15D4B5E883F0DE2951E20BCD52FD3BF 17858CC9FB7AE30681B710330C65D1B198BF87DA471D36229A79C7112CF763BF 9C4CBD7FB2495A85DEC4F7FFFA4512A8073F7A1B623B929A529676DE499EF98B 97EE3971626A965383721429A321A58D554EA1B669ABCA6A76E95AEFD8C9C0F2 DB9BF39995D5DD13C7276C9448D99028D8DEB22E5E58387D6C4F26A73C9FA65A B04D880E800140F0D65BF5F0FC46BB96E02D81AE2B341FA7B12250574CC46CCB 0ACC8CEED9A3BD5189F6186A8C5A3962978BE9C97B8DE90787D18829F38244F8 077FB2BCF674DE761AEF307651C92DA1E7FD0C8A6DCBC0A98035855C1D1A32ED 7B1FDFEEC553BDF10CE2C38FA00FFD1FF7FBA381D68FB7FB53DE123880D07DA6 B051AC50CBA94887769D67FFE899A527EB7E52EE50B544F83BBDB4852DA0C2C0 0481E5006DD0633A88473C36102F613249EC49C709009EA6BDE15C76249BEDB6 5BEB8DA6CC64EA52B53BF180ED8DB9AE1336274BDEE000008244F2D4A17A709B 693FA1D83013CFF398B2EA75D56CA8243652A10F343A8C75B515295156EAA6C9 983DE248941FDF9D7AD0AD8F4DDDF6F917F1CFCC8C4BDC1A348D19A39895C9F8 4172DFCFEE4F86ABF0ED2EDA33FFF58D97BEB1A0440085709D450D7D77601A1C 3E3E8EF511B1A07D3B5BDEBF0586BAC2891E259FA0688FDD1B46407DAD93F796 CE3CAA24DD165DCF666E1A77F4D05E58E2A28A69D4D99878E6E5D5E99F9AB8EF 67EEBAF19D956FFD87B3F584DCB4E4C58E5AAAC400EA7D40F9507C522D90D317 09C19CF75D34FB5E735A6E5B8B671B10A450CB84A9CDB92C150C17F2337E7A86 5A5321AC3F9A7BF4E0C5D7AED82BD6360E77241442510740D8771BC05C3848F9 B6A99913C4501C7BD43E6118819D87701A1C4EEE78D0277437895DCC0B18000D 8914EC10EE429A30710FE2432B3D01DB73AD146014F537E6DBF3976AF063BA86 5B5162A5DD6A6A4D5CA5C778213EB5D20DEC6714427A4040EC889EF0D732E990 C7445FF1916864DA1F13E95F79217DD7A1D5B7B55FA88E5EA960F744549F9752 602ECA84C41762E62179C4320E2336683046F8D1FB8E3FFAEBAD849653A88194 F77DD9DD08129F273CEE5DFCDBC517BFB264F4F280D66FA8B0EC9069D3456978 F8E3B79FFC8D0F471EA2A9A4FABE2D154907856B065E9689AD7028E3D412B9CD 375692F57498CCBDFDF577A2D85B97629DB37AAC2D96ECA43114E4CA9657A60E 8F136F0E3FF09B47D46485F0F25BFF6301DDE89C3A3A14C90DA9FD6AB1086353 8C2EAED5E84073629FAD58E6EAA526F59D3D078A8BD7E7699495F3507DD9DCEF EE0DEEB00C91021C10DA47DCC3DC42D445668E23B77F431D13E92B8C12261C2B 8863F1CE85ABE7CE5EE934B04932D7AFAF5DBFB1DDEAB0EDEDB89AD85A6C448B 72CB5B221F96895D084D60DA09872AE8590E876410D0244DC250F79302E52C66 F3BEED1A40737CB7D9AEB73ACD6CE08C0C97F76406639656AA8D4AA5DA8C6323 E30DE40BAD76B3D26EEEDD33776272EFF33F7CBE93733F5E1A7406CBAF553747 A787E0B7BC71FEE64EBD3E33593A76FAF66F3CF7FC830FDDC39AD5375E3AEFFA 05C0B7BDA417F881EEA6C1686EA034E8799C27F395CD9EAD051B85C005D7EFEE 5487F2D9A191C16EDA3BB46726C769C2C5936FBF79B9D586D2356807AACB7CC7 E5A4957452C8264305ABE0A0A9918934A2D57ADAE1A2ADC2ED5EA31E333F5BFA 85CF3FF2131F7B6C7C326FD83D6C41A90D11D1D6465A055E0BCDE83352C69901 AC4B74A991902E54E434A5297688D905F80FB0D0E84026BB596D7EF56CE92393 F97D33AAD1D16D84498815B0C2444FA202476236E93222995031BE1957CFF2ED 4BB23CE45B83ECE64A45A663496A72D1CD12D3838CE5B626EFCA3A47584254EB 867FE1C54B773F74203FC953DA91A93F7F969FFF7EDBF5277649BCC63B6B51B2 0DBF46FB6E537DAAABE7AE741B8C0E2203255A68A63F8CD4EF3BBEA54DD17727 7D578948F4A708E52DC7CA7E9DD46E16483762E8DE1B885D923065C8D82D23FB 60C067CC68847866581C7DE8ED0F7CE9933D6FC764EB7C2378E61B0B0F3F7232 33536348247882D6D9F37FF57DA77BE49E078184B4901549542324903C40A447 4D5159F596AE87478E078EDFDB5AF657962A274E4D50A8753856D8AF54E8D997 AF1CDE373D3A9A71B2DAF41B3181631343314DE87C88DE5AAAD612731B1B37A4 BCD8E802C7D28D7C069420EA601F0174377A65AE0E4074DB764139E54179EA3E 7BFCCE8C1AB7D24CECD0E0F53F5BBFF175C448FB5AC2AE22B403C9443FBF9E02 4B93D8016A6DD91DC5A2A817607A4F9E4D47D301627B3EEC3DFA5B775B456DF2 AC685FC640DCD2ABE4F02786CD453DA0462EC59D73BBDFFD8317C2CBB6610CAC C86899A00DE00A185B02E9AE0A43EB11EA714F960283CF6B6D4351C4642AF00B 4A3A221D2F1702C7B9B1B824A12262A315A6C0530BD4F2251B70D050C11E28D8 FA43A4A16D7B09B611EC4F2B350343413A37B33BEB9DA841640850D6E92A0017 5128D3888581690C39C38134BCCCD6C43D7E7AF8D091CF7E077F617A18E049D9 B1F6D001603493FBF17D5FDC978CEE702C3D35BBFEF4EE0FBE7A45C6D92BDA82 35AC69E33D4B8FA36B2B4FADD9AEDDDFFB474B5AE30CB8A761B8099FC262DA8E 07605D2CF4D8270E0EEFAFA6BD6D15E5096C74DE1650AF93622AEA98B2C6D2D0 F317B66EFBE513FB7F6C7AEDD9EAD7BEFCC26E57DE70F0E51E5EAA464831CF14 581B2AC994EB36AF1F4905EA13D1BE7016EACBC8E87E2793706E45314719E4EF 2B0DEECDF37D3C196374F04071F0F6D197BFFBE65063744D353679B2A90DB9B5 998C1E8384EA2985676B6753CE533B15653B73D42216F580E5CF1D2287CFD871 BCA3359059A02B178EF475147721EB9B24D47D2C10E05258B6C5F44561F6EDB3 EBEDBA192367B3D7DAE2ACC9516269EBE754F69BD3F4AD37A4029D1EB4BCBFF6 913561E3293D9509604C3F9B9615ED9B31E9997AAC675AB538865605EFDB0BEB 636195E81E22805D800D4984644FBB0388398A8E9AE998A96CEA5941E6F15F49 C6EF3814BA896E4CE53626416A91D4EF7AD8A8BD869EF883B7F9BA6BC8E82A8F 4BAE3166DA14A7F7FFE207C63E7F5FCF482020A07C2B00D56982E3552CAFA3D8 D0F3CA5164707BFB9D9DCA85FA81E0F8D5A7AFB73B649DB1752176E224458683 5B01F607ED42D97532F0A4A2BDEF83993D5F9C649E1297FC6B7F716E7F294B86 63EDE8901A549A82D9D56658EBAECF1CCA1383B6EAFEE64E7BFFD1529CECB476 B0BD39B278652DFFF9A1C39FDAABCC0E50130EDB1DD97D637920E545417CC8DA 005F15CF602AFBC45B9F5D639459BA52F9E77FF8C1534FBEDED50775C55AB3D7 8B445B3BACE9CB208D340C2DE34A09724CC3A5D43608E0218B1A3C4D7DA98DFE 5A61B709093F7008542326B28655B2FCAC65A62CDAED5470609E18982A168B8C A356B777796375A3559F1C1ACA9876B5D36EB65B8F9CB9AF94297CFDA5E7DF3F 5AF64BA5159144BCB567CF9EB36FDFBC787DF1CCC1092B53B8B8BAF3898FFFC4 F7BEFDF5A5A56AC1F6C338696136323C980DD3A3D9F278B118DBF2F5A56B6D11 D9A6AD8D9C609B0A6C736364B4D48BEBE3E343C520D7EBB257AFDE98EF767AC0 23102D6B7164DDFFA25852CA1607026F286FE5F266ADD9BA786D473341D84AAE 6E050923E6FB85BC9D7A817DE8C8F4DD771FBDEB9E13834303B68D837C1641F4 264D442151C53C8D2C23C3756D496CCA55B7821DCE708F70463522C500E96D66 AC3FF1B2B1BC32FA130FB031A205D5C2180369308C9EC032115A1E14DE41DCB2 8850C2536B7EFA62BA757EC72AD99514DE7456C619CE63D79236B2184933337C E2818C087A66CBBFF8FC86EFE5E7CE04CC5FC7C4978DE1379EDDDA58C4291DA8 A9F68EAC2DA57607C82F1441DD2A639AFD4B75AD20A54D3EF50544FF2EA52F84 D5AF7EB86F4CD19F4692B7BCBF6F199FF64796A12E9A92245A53014216A8A1C1 38605966F9D89E70C42C4DA69533C08A78F2E2E3BFF458F6583761973C7EE0E5 AFEDBAAA7DEAD18124502A98B43BECEAB7CF5F7BD17AE88159CF4D94D560A26E 1A79211CCD5D0CB9BBE62C5C6B9C3C5DA276178AE2C2E2EEA9D31386681A58E9 D6C7D43FFBD295F1F2F8DCDE41EA773940F014D9D261B590F54813056F5CDB59 EFC98A612F30B918890E7081FE29AFBE29E2DAF120B5A23223873CBCD731F3C8 2E0D90C377D2B97BB2687F8EB95DCBC95EF88BF5F37FDD24B6B110B3EB026F2B 432B25282E750BB174B5571B6E017009A380A113F9DE6C32EDA0F4C867461FFE F5DB912F3037953E0ED3C2697D7D2F017F1A698A5CB3CD22C9C33C0D769F987F E23FBE45BB7B2213CFC71BBB9874B9A308406CD2E3694F26004D3CC0277A9094 9B58164D73949893F09AB0F26C3238908395DA6C345A90210D330E1950AF82E3 D82A2D38640240B7A344DC766C27352C24990544CF615A67C377811B37D693D6 862028E096DD96BDAE08F5D122A62EC9960CC731B7864F66B20FDC7DF0B3FF13 FFDCCC1052ED92634D5AA57C2C27F7ABBBBEB0271ED9615866D44CE5A5CE33FF F33CEA16AE0ABC927477A1E41113F217A4E944F799EBA44C741B2D96FA9851AB ED94899A16E93420779296F6181FFCE43E3FD8E6BD180A49AA559753957023CE 4AD9152AAD2C955FB9B1F39EFFF3FED1DB0B1BCFB5BEFEBBDFDFEEF0EBB67139 34D66A91D2CD38A99E0A44FD4E12C87312F6785F2E8910E396EEB6C67150223C 3DD567C640CE07CDCCB181C1692B9D32B9257A87CEECE33E9A3FB7EA3572DB84 C1536C2316E97A6A69A71E284A0C90AAB23C0B223ECBF1989D3B6251887F2BD3 3B7D5FBE301C416E5589236313D8BF925A504809470A1BAB9E96A5D00A9029D1 038BD9CA86BA787E3B915E43F00617DB691C2A22B42615543EF8E63EC2D4134A 50868D04293DCEA8A703354AE640520D7D5693DE0ACD7E371414425D17D52D4F BDBE9680D68F12FDAE65640B288418E2A3A76DD549398D4E66F08C4D02D327D8 BEFD317CC7670F75EC35C3323D5446D8E776927A5D404BE962EE9BBF7BB67949 B8822CC8346BA251C755B2F3D1DFFB9CFBF8911025C0086D6D2C4BB50A4EBC22 F9DB04529D60529BAF58BB576A0BDF5B3E9D3DB3F4DA7ABBAD36195F4EE3B528 D2EAE3AA1D90EC50A69C314909A1022C78B17AD76F9F52474D3B2E6DFDC55BF5 0B2B532727A911195008CD6C2F82D740D6D73747C733B972C052677DAD3938E6 50A7B753114E6B70F3EA466384BDE7371F51631D64498903A5E722A4A64C4649 120768B3010049041250381000D34026E5DDC4503E9385EF7DF395FFF1D7CF5C B9DE68B78D30C21D802BACDF2E81495FB900E92902580DC93C8B948BD9817CD6 B18C52DDD006B686DAEA36B7A21E774C45CDA81B67093D383A01A851B69A2A8E 604F17DC6072645ABA764B8AAD66F5E6D2E2E4E0A0CDD1C6CE56ECDB1FFBF4E7 562EDF5C7EFDD5E3A74FC387DB696ECD1C3EB0B85DB9FACEE58373338B6B9B23 33FB0E1FDCFF577FFE9700A732D86F27DDC4C153634313113AE11773D9EC9B3B 4BF3713DF0BC9232691C01F24931192E4EE40BAE97B1C2B86D38EE9B17AF8588 26CA6ED4DB63D97CC1A442845C2493B921DBCD04B96C4AD1FCD6DA3B8BCB3B21 B3B2454C49D4ABC36EF63082526D7A9E41A028B61066816B964A0307F6EF3F78 60EFA9D3C7C727CAE35343C8D477E25AF34831647216D7288D506737256DEC21 92A6C09E9056282461A36DFCF153E9815CE613C7ABB86275233F22445A4297C0 040BC06C29EBB5AD44749C8C1F6373CDEB3ED75DB9D1307C1EA788435AD0071D A1492110ADD4DB9D7BA0144C4536EB849B43E7CF564E3F34448AEB4239A62C35 D63BAF3CB3958473296275BE7E23B6EB71D4D2FD63908E4C8229D62D664A83F6 BE5D8D16A142DA7191FCC8D6BB7FA0D72734FA6607F5853BFAAD6852C65A734A 1ADA054D8F2B033F4C918875EBA92A513463A17DCA9E2459E1B1838FCA7B7E26 2F540B4733CD79E3856F3FF3BE0F1F70A60A69C670A4D1BE923CF79757F68E95 8F1C9F60683D152DA232483990D2A16C55D6CC1B97B7EEB87B0A917665D55A5E 6B9C3C354E658D40CCA540EEB26FBC723DC0A54347268D4037C928C8F3C88A1B EDA4AD903178E146E5F26EBB4A9D754ED61354C728357583AC9E9F067C0295DC 4E4B9CCE91789FA5060CB738E01CBEDDDEFB401ECD3991DDB69DECD57FAABCF2 95D5E2C0D872C42F4510C502F2A7569DEBCFD2D8507B19EF60694B34889C2977 7396ED31587CE6E767EFF9D22965A54439BAB11D71C2FBEA3C944B80F911C0D4 8EF04994A4166BBBB173F6BF5DBEF0CDD433FDF570BE02E5360E9A2AA1761001 2BE211148A1C1436F8DC0082D238A0649C5A33A69D47DCA1A89CF586070AB556 7BBB5A65FA24D4D0C24112B9C0AC0D3E51704773A60FD90AF08CA5071A89A915 C252D2858DEAD93E15416B4BEE6C74A1EE62CB6488757B51171E4F98A39EE78A AA3BEE141FBEEBAE5FFF2AFEDF678730EA1474212C17523C3A95DEF533E36CBA 1609951393CDB7D8D37FF726EE166F08BC14B6A18428025BDE043A921A12320A 603B0D060C7D798838302635662507909A30F23D5E3FFCB07DFF63C3326A99B1 ADF411326C5AA57B6DBA16061EA5D0EA35EFECD2F67B7FE7C191D3F9CD67EA5F FB9DEFEF86F886675D0EC94A152813BCEB5BB3CD4437CBF425716FF9A7E89BC1 BEE076DF998248EC1A2AA406946F09CCFA845F9A50AA984BDAB2FAD18FBF77ED D2E6F2C51D43B99B1C2DA7ED5DA824B7C800300C803F49A207F00317713688AC 319AD96BD8C8EE94F6C4271F1894AA4590A50029E9634AAA3B86E12369A1A8AC 61248C6BC8A85B19018526854B6FD677ABB0C8E64E1A37106E323D7AAC127869 382238965051F5C1833E11E85FC5245A92CD90FD99085DE6FB66C2A9E0E2D6B1 1D50A63E90D5974FBC3F557FCB7C4341BE87DA8A4D6D7781203E62037092E975 E3A3193A4D659152DF760A93C6635FDA67CDEEC0F7D9A48C0C57DA4962412137 9C4EF9D53FBF74E53BBBB4935F576D7877658B2823FAD41F7E913C34151ADC84 65D2F3960E9186912EF3E49C6EB9875CA515926873A173F3BB4BC09637CFEFF4 42B42BD4521A2DF53A912209BC17EA65B10D44A444CD926E476F8C3F3EB4FFF3 FB2514BFEBFF1F4F6F1A6DE9759607EEF19BCF78CF9D87BA43CD2A55A94A2A95 465BB66CE3916634100289437A258B4E62C001BA21B40349562F92D064EEAC86 054E3A6E020E84366063CB9235597395AA4A55AAF9CEF3B967FEE66F0FFDEE53 22F21F5925DD7BCEF7EDFD3ECFB3F7FB3E8F78E1DF7E6B69F6E8DC34F03FD58B B5EDDA9CF09DB556BFDF3B7966019652E7A01786EDF913731B7B032439E9E677 EEB49EF9D94FEA67EC82772807E1E81A06A60382AAC8B46DC032847F6011C755 A988FA7D0036AB5C42CCD629E2FEE4F6EDEE6FFD9FFFF5D5D76F6F6D0FF6D214 0D0752B549FC50C30C02ED32BBE4DBF743312C8B32461F6036F75DE6D9519135 BB9D5698B4D254D936F5ED12216727670EDB1E6D76F6D481D3075DE021D7B726 461287AE6FAEB1242F09DCC3F2B9FDF6E967CF7CFCD4853FF9D33FA7423CF5F0 A377B6D68299F150A6FBBBCD23F3475EFFDE5B1FFBD8B33B3BFB7FF2ADE74746 FC2C2CE22CB75D3657293D58AECDB9E5EE60F0DECE3A0EDC09AFE4874980756D BC9C60E4D6A76C9BC5B4E8A36CBFD7DF58DEAA078DF64E676A720ACB1CC85198 76ABD5EA6C794AD93CC4E4D6CEC19BB7EF0E0813C0F0CCE44081F2DC36054E41 AD912C6014CFCE4C2860E851DF44DE67198049B5569A9E193B72F4D0C4646D7E 61666AA426B2D01FE1C7CFCD976B364ADBCA1139546D15033F81BD2DA176562A F673CBEF3CFFF5239F7DA4FCF05C2B6DE35456A080C5004089141137EDA74080 55089A203E68E88ADA9ADAFBD6467BFBC0768241682B0D3C1036724DE152AC77 671E2ACD3F0208BBA1A2C3AF3F7F70F45CA33CD166D41932F0E8FDB7BBF72E56 88A886456B5DA1BD2CDD43AAA510A80CD3F56938E83007521B2F6436CCF62CEE 2BC2FBBE6A1FA4BB91FB06027AB88CEE8717C64E6EE5B6258CBBAA6612CA4AAA 74989BA1C80AD3C7BCE038B516A8458A8989C7EF7CFF9766010D4831A653F5F2 375F9CAC1E3AF6A193215F762B35B43FFECAEFBF25F6D3673EF22071760A1D8B CCA166002702A8DE5BC3ABF7762F3CBEA8557F670DAF6F0E4E3F346EE916319E 7F9E22F49DD7EFEAB072F6E1236E631FDB20F5CAAC5069D40B0F0A4B36967792 D757769B967B50F0AD5437B18E6D28C582169243A5425404B812E143AA7FD4CE C72DD0FEC1C9F3FE91672A684E47A5D4F12AEBDF1C7CFBB72E05D6EC468EAE24 F9EDDC3016871166295DE4656D69460F24BCBB6296579682ADA57C4965E1F99F 3DF2F8171F2E50CC906B5C94A06E49337FAA2954674D73AF50FBC89185B1F619 D8482617D97FF9D5D7D40E6898742F17CB11DDC342DA2593F9AD4D83E0D01CC6 34399ABEDA3CAB6372C8B62738AD73E65159B2F0C4E858B3D9DA3E6809DB8D11 07582B594E95E17147CDD6ECB132BCA150030960C6638438B0F581BA0963FF4C 2DACDD5EAB68AEF7458C5DDB4B8A7427E1512AC65D36820B5462F2C1F9CFFF87 17F1CF2E8E21D4AFDA7CC19DAC65B83ADABDF0D3E3EC81148A7709CDF7AFEBE7 BEF2A6EA56D7B07D2FEA6ECB44626EC1EF44343166CCC34C20B3C08CC51AC8C5 8CA369D67D00D3293DA982F889BFEE2C9CCA7507B3A8A454A468960D80457012 026B8052EEDC794F5F6F0D3EF42B4F8D9FAB1D3CDFFDDA3FFAD6EE00DDF69D6B 0084FB036C2E698BFBF5DFCCFAE9FB2E482651DACC100EAF27870DDF5CB29285 420EF251A44B95E00CAD2E2017F92D76A4F8C24FFEC4ABBFFB527315B836D988 C86AD66F99467966C60187CA0204B539F5701848C3395E9EB7CA0BD815F6CEFC 99FCD8C36581407021AA04BC652A3D09DF1045A6E72CAD99080E000BD3A91ADA 18B5D7F1CD7733C246FA34DFC8C28D9EC86143DA194D81C40308A09E96B9D250 F719B16406D5C88C700B00617304294DB032802202E50868FB01166A1390614C B7CDA99FB9B5916650CABC64D3196E196F59E3AD90C33BD1764992A38E3DA393 095E541D2BD6FC537F77ECC8A7AD5CF6392E61C78362900DFD331D545E7B6EE3 DBBF7DD51A9CDC555B0E9325240F2D8C3CFB4FFF863CE94696720A3D9C2CB7A8 B649B692256FD8821B2034074832DE92ABCFED4CB627B6DEDD061601E8B489F2 7BD1208662413C3B4B4A793112D446CA5ED58C150DCA87BD0BFFE021BCD4B748 E5CEEFBFD77F337AF0A467557437250229075B4094EFDDD9593A3E5BA9EB3CEE ADAD6C2C9E3C1369B297AE4F58C1E64B45FDE1D9F1BF7F24AB74B00E28F37300 2D5DB274C574081A826486FE90843250CAFBE295E75FEF77E26EABBFB7D7212C 40BC76E9DACA1BEFDC3EE8CBC4D8AC9B55048BC766CC1C4A4B6171665BE67EC5 FC13A4D22C1DB751BD54F210ABF9A54A50EDC7C9EE20EC1705E6D4E1C4A3F8C4 EC944F6935DC990C497D5F08455A234EBFCC5C89EC660F88ED8A55BC2B3A4550 FEC4C73EBECBAB7FFE95FFFCE8E46C7566760B2599B9D2D595D2F47BEFBCFBA3 9FF9D46B6F5E7AE7FAAD02EA5F9A81AA3A5AAB369438BD340FAFFDCEF23DD729 8FF0A02A098FC3B9B1AA9271A66511D445236812D52BB2E57B2B53A551BB9F99 8E705D4440EB48512EF9E3F5462C5846C5B5B58D8BCBDB39F304B712110B91BB 961970326DD6A83017D466765EDA36290776A5E40D6F3C4007F170100E933BCD BCAFE7711B3B254F9E3937FB0F7FF5EF4E9D5A4CE20362012BEA70D5C2220232 16533FF2EB23517FF7DBAFC9F5D6DC879F2826791FB54A3A67ED36313681F07B 407B2369B2DA3349D28370509713CE567DF7F9B5FD5D9910AE4962E2C9441DCB 8090988E27473E429DDA5E914EDD7A0FF67CBE74DCA136FC8C085BBDACE75DFB 0E6DBEEF20CC77ADC1AE10DB486D1645D704A159CA14A5A121A592C02841D302 1666EC033948EF3B359A2396FB391564786F7CBFD8E09ED775C28A0F328616C6 3D80A24C5999196AEA3B44CE73E7A8B68EDABC544CB213773EFC372726672A58 E5509B7637D8EDD7F72E7C64894E6DE0FA28E9CE6F3CB772EDF91BE7CECF8DCD 9AF9E13CB12DCB916A00CB6D73B9E8B59393A7C680246FAD8AD5D5FE9973130E 6DEAC291DA9744DDBCBCDDD9B2CE3F7AC21BDF07854C558D1402C9A8BB979141 D08EECE76F2E372DAF95B176C13644DEE68564052F9403D58FF2CCD1FE001D65 F1293FAF63C7F7DDE38F944F3C5B4387645C11B65F4EDFB2FEF25FBCD13E7037 057E3BCDAE17B9061D4A894595A3E418711463DB3A87BF26897FBABCB3541C96 8901C247BF782EC73116D6FD1C576AE2D9B51A5EA61055C67450888E31D2B114 CE12D21DBDF47FDFB9F6C7B7AD8C000DB89DE61B0477E00D111BA8589EC6A0B6 8DBF3DA158684B2A17A93A414B41300B4A51265A444BD35325DBBBB7BE09383A A0768E6DF83D2336ABCA68DA97B3A31E67A2C039942B73366B99D3486A6B62EB 4885CCB53C5A1D6CAAEE4AAA42C402BD990507493242B349501A8C6FD6F9CF7D F37DFCF71603E084556A1D2E976A4ABA7EF8C88F4F078F8898A415BA14BE4F5F FC9D37D4416DD5CFD606E956A20B6213061A18D428103B6D5A59F0D0A3019699 648EA4D3567789AA8A2E5516E8335FA8DB956DD67778144814E6241711750B46 12941BA6E6BDF77AB7ADE9D3BFFC74E9C1A0FF4EF207BFFAEDED5DB5E6D8D762 71A7D935178F202487D12A436430CBD50C47007F606C982B685A492D3A74F971 B153905A912CD6F549141C4DEB1DBE76EC67A61F3A7DF6AD7FF2B6ECF19DA0D5 EA5556F24E8F1B0A48CD052F22CC0C5F40F5307EA148020A2EDAA559349197EE 2D3C2E0E1D712DE4247DD82B20FD4086D95830A13369D27A3C946973D96B49CC 10CEBC3B97C3CE0E47B6DF46FDD5B0BD1DE6C80A606BE334A184498A13357C62 D8A4C49AF61F6D0CC5A5997132F61699C97334F11AF035815E170AFE05E3353A 143064E824608AF8301DC05C6298011A651A8F04503FA4B9CEE76D679138D30C 7974E0C14648468F7C4A3EF5B7E6306B13C74336373D3856496AC7E264F78DD5 3FFFF2C55AF3C9F5D26A2D26A0798F7DDF91F3BFFAC3AAA10D59D5D2363CC729 A885F235D67DDB9C0444A939D96624DE172B7FB936B237BA79B99D653C267C4B C47B0268BFCEB4338853A174D9B3A64A6486DA5EAEA99B3EF2B78FD63FEDA75C D39BC1957FF7EE7C55D526B5E64EB72B61EF96CBA5D6C6BEC5E9C8A28D593F5A CD5136669F185B0BAFCDC94AFC3EDF47BD13FFF03179926505B6AC0A7012AD6C 0BD7307533243033EE595088180F5484DF7AE9F2C6ADFDB8A957565AEFDC5CBB B9D73E4872457D78681E4F3177409D5B8E53E65C8661D8EB8370A87825E45899 AD3DA2EC5E143BEE2CF62BC6C43E67A3762508CAB03DA9BB2F92F4607749B353 338752106A9D7BF3C85E082D1A926689EF7A1949E229ED8592DD4069CB966D99 B1B171D729BDBF7A6B5B45D3A71FEA0FE20950AB9CDFDDDD6B35F73EF7F4875F FDEE9B779BDDD5688080262074666C7234D7E38DDADEA077B0D33C5D9F1A37B4 A93F510D0E797E7F79CDAF54F747FC83527EC08AB55B6B8D3838DA980766BD1F 1E00BA45B02D2AEE48AD02047233B56EADDEDCE9F404E2B6ED7593AC25536339 62B334CA601DE6A830169C85AAD9663428C38539E3A408344BE09731B26CCD3C A0F1323316B1DDDD9FFEDB9FFBA99FF981EAA4ADADC2B218968214091603A4FB 85EE0BAE629117A08DBBB8FDB557655E8C3EFB603EC98B689F2603E0E8A6B9AE 90441292499CE6E6240C7E46A2BCBCC6F6F9CDEFDEEB6F4B8FD68AE283290807 01FBEA1F7ABA549A07A6A13BABA2B3D93B7AE630720A2869CC4E8082EEDE11EF 7F570EF682D45207526C6BBC12CB032C239A1746CD39A09F41FE33E3160BDFCC 8C4B1AB31CA5869D33E64440DE371E35B04887B783E668B4EBA54EE63919A750 DC696AAEDD8CE2C0A05FA82EEA5A2F527634702AA241BCB5731F1B39F599F9CC 5A3692A8B7F8E69FDC3A7DD41FB9C0D2468392D9F4BD1B6FFCDE46AD649D3B3F A6C8A080476EBB89EC5996B5762BC459B0303F4249B6B116AEACED9F7B78C135 E9CE08D62B60F7E69D68F36E7CEEFC4269BAAD788A74850C4FE192839CAECB54 D59E5BD9DCCA59B7E0EB85BA23921E960EA3368815CD2C6EA72CB512BAE414A0 081BD2A9FBCED90BDEFC4703759877BDCC67B6B3D578EEDFBDB979C5DF66E9DB 517835CC63E4B89CBAC6D01703CF1152E4B04234ABF0CAC3CEF652318D8BC185 5F387DE6EF9E116A60493EF438A1C4D81618DD0D129A250CD9456675304D516A 910C7E1210C3F87BFFEC0DF11EC97D720F479B836005BE2437231446AC9B0E41 50DD188A3DA3C61C94897894CB19DFAE61C055EE137EECD04C1477D7F6DA0365 C7C82A242C15E44B39EEB0F1808CD600FF7A40EBB0E708D3EAAB19C7DC2339CF 8CF52A81FAE6152DB1BBBC4F223BA7B55E0230AD4B8CC6446D55DC5FFCD67BF8 1F2C5126C72AC49EB6B331AE7D1F3FFCC3872A17D2010B4B6836BDC3DEFE836B 627DF4A6BBB53D50DB913500FECEA020A726C9DDE4D3DCB7F63317B580098D18 CF3AE9BC2FE1FFCC9E2D3FF9E36342AF5B11E3A90772D1D4AC8CB3189154E704 09EDBDF3C2A6B0BCA77FF923EE493EB821FFE8D75FDC5C55DBCCBADCEBDFE90D 10089D34FB2BC36D6CA2C484A2CC58E58228547FE53E06B8E688BC5F0BFCC23B C2F4523D398AFCF94E351BDD7FE6FF7838EEA6D7FFD9AA9557972BCB61677C45 B4FBA0F80925F27E7E99399AA4E66AA2703999B3DC79DB9B51F3D9D8BDA31FA5 6363F05E894A79AECC501A36D3F7C6F64C004649C612604CA176724282BD357A F76A040420464517C71B71BB0B3FD38CD8DB52C496E955A3A6877C78C24AA805 DF2A93C3433D6C7A7FCD48A034D038BC6D45B936FEC6A6817BA8B687798B262A CEB888619CE3C2A49F989840F8779C02395A6715D43FC6E9111A8C71EE954100 40212CD5CFC79FFCE229A7DAD58E999BD4B0AF59299196E3A3F06EF3DBBF7AC9 B97AEA4663E5685403BD3EF9F98527BEF439E9B1089E09293C33B8E3C50E6CFC 75FFE04A4CA437C8604923D7EEED26F7BE7167AC35BD7E25CC323BD5782FEDF7 80ED6AC515DFC9D4AE86D29BCD58EAB05D99C435CEA291B3C5B1BF734C349093 4D6E7DABD37EE9ADC38BBEEBB3240CDA29AA8C5B59ABD5DE3E183D5E774714D9 713A6BC83E53EBAB9D910347C7F6DD9DD5E9CF1C697CEE48EA2A93B5897D4C39 946BA402E30E621B59EC620BAA1C963C8DF5D6ADBD5B6FADBCF1F2B5AB779BEF ACB59B001196078FBB62470E71FA5264547984068574340D980BACE840A65B3A 1AAB78473D7F3729AACC1FB16C4BC43649A7993D872A416524ABF2A0088FF5F3 B1420D38AEF3B420A014500D5416B35296B13CB40166EDEA9E06C993028CECA2 22DFC73B63C1AB2322996DF008BB090E461BD7B6EF59161F2D57DE78EBD25E2F CA1235E5FA80D547E6E6AACC1A743ABB3B5B8B95FAE3D58972F3609CAA995A99 2315853DBB566F5BCE7AD15D35429F9D44953AFC62603645D40CA376E074A746 DA4AF75A832B7BED6ED20FEA654679D28FE35CF68158964ACD5607DE231F9ED1 4B862683928DAD4198B4B2589891240042E3998B040F4035B876220711CE7EE3 577EE8AFFD8DCF0F7BDB434CB32C4D3C3B303307B0CE4557890EE72196BD03A6 C7B4ABDF6F6D3DFF3D7F71B4FED4D144863C4D9548418FBAC0A712D065C61A5B A6E9F0F88398401B2099ABE9FA8B6DBD5B91C88BED3016031F977391D61F0866 1E0D88DF927BC9C6D5C1FCF153A9DBB77CF8A480617D6E591B57F0FB6F4409FC 3788EC66782B23EB69AF4BA39CC35BF5092EC1B7A443771166AE70CC1D83193D 3203E06478EEF2818FF17D89388C65137D8B5A66CAED7ED00D40B71CCE109B02 0B7BAE248B43365B089C515272B2EEFC51F6E8CF1C8E46EF9A23CFEEECE66B07 A8B7B7F4B1A3E95C593916DBB97BF977F3D65AEBD9674ED941AF5089C05C0009 61626739B58AC6E46819A1646B3BDCDCDE3B7BFA08D719369D0B263564F34EB6 79A775FAE1A9DA5C281D2818255250A0D40A58C72DE09DD5EF6E1DDCEBA89EB0 EE68F95EDE8B941AB1CB3E1043E0AB50483C450B67D612B3B0B0B537E93B171E B7A73E11E8234EC7CA02D837BDB1E77FE77B5B2F349ADEE0461EDDECEBAE7091 4D6C0741B18AA3048A93E7824000EA5D7EC26B1E4E46023B7DE6D73FB4F0E34B 59D60E0CC80029E54472D3C74854C66C3BD4C8C923B70BCCCA8BAA38837DB1CF 5171EF2B2BABFFEF5E9EF33594EC76AD7BB848A0B4A8E1592621540833346A06 565C8ACD646A85C635174D5336C12BCCEC5C323F5DDB3F6835FB00B77E07368C 1401F5465DBBCCF2F19AAA95C38273653363C36D8C9B30B559C164015501E7A0 866D8A3BBBAD64D9E977534E46F284A4452A3CDC1E19F9F96F5CC43FB768133D 52E57CCACEA7B8677171F45967E6A356646B005A71A0AE7CEDF6DEC5C6AEBBBF 1BE3CD84B731BCA8DC7029C481F89B730E637BC229285B8247120DE56FA90A4C 2F7CF02353A73E5ECAF5A6052B34B1A1EC1744E2DCA2B126892A1820817FE9BB 1B39F73FFC4BCF38C769745B0110AEDECA9AAEFF5E9CDD19844671996E51D30B 68D49B311735F847877FFD8F60696A72B1F3B0E494B4732AB08F968B05614FC6 6EE361EB13FFFCD9D7BEFEF2EA7F6C56ADF17BF672B353DF927D60A7C00E2D33 CE60E4978D313707AEC065E9BCE34F537B868E91B99D939FF0B8D5C303E0819E 31D297C238706A20D0C69A1F83B41741AADACC1722F76F821CDC26965D8E94DC CFD3AD6C10E37C7802C41416B66B4CBC52A031A6D3D858031B1404F8028D6894 9D61A6C354600376CA9C311B573933CC642E39F07D4B1D3330A287B489DC37DA 198E8E9BC82513F85A25F112C52779A5A2C4EC21BF54675B5763BED0FD812F3D 1CCC27DA5266F00EB08378C06FB98750A778FECB97D3E7A736A777E7065E2AFA 87BF70E6ECDFFF0CD48C183E10C95D137B609BB00DB9E676AEC61250B1C0458A 383BD8186C7D7B63EC606AFB561A2650DB515BA4A1498E42322ADA52761801B4 0EB458F4EB93A45C929970D7CFFDD452ED137340D5C2A6FDDEBF7AEE70AD3232 616721ED74F2A06E957C7EE3DDDB8DE989C67405E568677DDF9DF17CDFCBB673 BF52BF71F5B63DEB1DFB3B8F89592EA46D235F58B8A0DCCE7D9A0293C88B3A7C EEC202DD665C7A5C1329D2D3B7DFBAF38D3F7FF5CFBF7BED9D9528A266E28260 514D1595590454C2A60DB73CE197C74AD538023A29BA22A21A8DD901A07FD344 079213DA3B9BF2632999D45639B052BB4865BF4A8B0AD22E37DDB86B2E494A6E 058470181178B80A5B119050443C5BB7064488C48E457FB6D3187FA994BE5FE7 89EDC68374647272737767BC5ADDDED8B8B2B17AD0191C76C7C72DDB35BEDE15 814496742A51EFD985F92396EBECB4C62465799E397956C1DC0676E8F7088F7D 0F449D1F87BE543D280202D8375EF7D09B25F2569C6FB6932DDE670EC8D1D220 4A1AB59195BB6B5629E8665132885CA94A463FDB6EA33A82FCD576EB20C9923C 5379715F1939043BF0790237816FC0C53FFE5F7FFEAFFDFCA749123918C4670A 8A4B07D6C0C4441BB75E2E128E43AD07B98EAC7C3B03AD9EB9E4CACEFA9B17A7 3F74D439DC509D7D414442F2522848480CEDD44227B012CDFC8F8A805AC30EA8 E697A3E56FEFB0BC145331A0A9431D01A050CE1EFC54D91BEFA8BE7BE3A5B831 353572222EE83ECE6D55D85EA95CF4E8DAB5DED5CB830201A9621D24B7D3783B CB7B263B0A1B9AAC30A81A1B33330E0995E97ED2D2F094BF18869B0E47BF8619 8568E8B208CFD356E68E69E81C06347998DB464C6F1D140059F8329F6368CEB3 27B80EA45F6B144FFD8323646A13F8B58A3DD26197BE7EF1D45317F8239EF007 4128EFFD7171E93B573FF6F4D9DA84CC54CF14301B673A5FBFDBADE0A989B1B2 42F1FA6A74D0EB9C7EE010CE136AF82EE89860EB6EBE71B775FAA1A9DA7C2CED 1C2802C94DAE004B11B9398873FFD58DCECDA609F75A23E4268A3B99F04C2F00 E5261F552B4FB3C299C1F9024EC6895B75F9D947DD639F1B55F3AAC7B200114B CD7CEFAB6F6E7CCDEBF9E906D66B11EA155017A1B864C0CB0169A525A90D85DA 18B53C8E9B87B391F106FDE4BFF854FDE3F524EB7BC25CAC0ACA19F0842110C2 96E4B082682C4D94A1E10FD47883C4C6107C03FDD93FFA8BF476A917D32639D8 C678204964CCEF88E97419B66C48D3BD4180DE5945E1174985CA59DF9FB2031F 5EC5A073F2C821C4F4CACE4E4ABD4EA2CDDDA252759B96EDA2E28AA951CE7D2B 93B1E3B261C21642163C2B2A188818E13B265DCA74A924A5DD9583FE9EE42AE0 0A473A6F96EA5FFACE25FCA523252D7C732169C9434E9DCA74FC7476FA872707 6E613BBE95ABEBFF7DF5F60B35E5C89D54AD667A5BC403040494E2A1E1768EA5 307E469699DDA1C50C21A3881CF23921CD0B9F5B9C39C3306993B8602913C6A9 C97819811CA5A008296820EF9D97369453FAD02F7ED43E8CA27BF2BFFFE31757 6EE6BBCCBDADE4DD24DBEBF5BDA1D3F4D0650C9E2BE19C0B13D56DFEBA1F273D CC234796464050CB849E09ACE31E9E93362CD6E39F9E3AF7B34F7CED37BFAA5F B203565FB3B7B606E5DD621072232BCDF1B6B1C3C13EB7801D8B3C09185A7082 71CD471D36F9085E788A89E2804480D88E313B2D24C9A0D2134029A3E3A036C1 2ED05D45F27EC75A7B5FC82C488A0C96F956941F8824A7A939D8CCEC44A40084 1A8A96B98A6699500948696EC1CFC8813501995068D8136A8627CCC23245C220 9DB9FB3283CCEA7EF886B1121E468FEA0FDABDE5B0C9C62E4009E9AC8EA2A38C 1EA3415989F9C5D2C2D1D16B6FEDF5D1EE0FFEDCF9D1A72DCC42D820C24C3C1A B708C57356F0977FF366FFEBB5DDB1BD7A53092B3DFF8BDFB7F0138F19BB3164 339A73C03CCD608516C5AAD5793757CC49CCFD14B69DFE7AD27BA919ECD697AF B463E97415C8A92425802C2C1DA43D95241CC5A09E2519F5CA13D899060D8F3A 638FD2635F3CAFCADD98EADDAF769A6FAD3C786A860AD5EF26A9882727465A3B 3D58B16387A633DA1FA47BA08DC746169A3BDD60ACB4FF7E3B0FE3433F73863F 5D4F52EAE08A7464C8A427472C04043D35114D40698807A428C951BB190EB6C3 A4295E79E5F273DFBB7EF1E6462B54458E911594F3CC4369465062D6806D17B0 03E1118AB9B1DAB415589D0C0F54D9B749400A198E497DC16D9CA3CE24946492 A940EF7B34B65889F020974054B72C8682B21B46DDA8B3E1B136E23E944D1C57 037FBC701BB92EACB0BC97CB44DFB3AD6B557F63A41295FC182B29B31AB7B697 D7AFDC596EC6E8D8E107741E4FA46231A2633E0F7C359947C73429539EBA7E93 E10391367C7BA4177A69AE2A4E6C0CC7B55F0066AACCF673CADD4C06850E7576 55A6EF5B7CD7B5DE89F605C08D24E591B1D58DADCA48FDA0DB0A93A406EC1884 BDE5AAC0850A31D8EBACF57BA1B9A986A2077B02FEA302E4B2070ACA4609C97E EC079EFC975FFE15674A9A61891CA86F6E7C347C07382AA780BE39CA23C38A41 8491CC16F7A4CC23EC04BADCFECE45B1BE39F9CC03D938CAF27E4952D58D4C1F 26ACEF6C606E24243146DE056C819C12071FB8FB7FB91E2FEB02E89A4D615530 528EF3C1FC8574F631AE12EFDEEBB01AD5898FB9A1B86E8B11528CE65AD8F0FE 42FAC62BFBEB2B05A58DB0C85A4A6E446A57A01E4905BC60CC8025C057A380E1 94DDEF87318313D89C84DEBF841F9691A1D7FAD0333976CCEC3D93261F5B5221 B11C5E2D5283D75A060608F5ACEDCC55623B1EE75EFAF84F9646CFB2DC02B69A 3A92BFF5476B5EF9F0D2FF3442A79B5658EBBE895EFDC3374F4E2DCD9DF05274 6019877F0DBCE5CECDBD3167726A34807778FB560815E4E489719426D8C42203 7A97B6EEA51B773A67CE4E0310160E10D312D450C941AA620C40183A6FEF8537 B6A37661AF607457170759420AED61EE1AF749046496276C4E8B234C4E790114 A1071EF6CEFCE0B49E89FB24F691C3DD994BDFBC78E7B74918E4FB4020329A68 07D8107C12690C9431282A49B35C149896CEA1DE92AC8D4D589FF8CD4F584F78 48E5A6F1CEF8DB33A6D8D0F9C3041D99DB1D141ABA01A58941C58B786E2C2CB1 C5AEFC974BEFFEABED5A3ED32B2FEFA44533252D4C2366178569C107FE0F3F46 68339E1A08E4246985D029C799F49CB2C57896825039B4307A103597F7DA051E 95BA92447D9B24F51202A1315671471A1ED231368517F09B21DB428E5D986A2A 2C8A2C2C08A7A965AB1E5A7BAF29DBB4CA8254C83DB7F60B2F5EC6BF74B82634 B3B1AA23B9E8D72A1CFB53D1991F5942E349CEBA1527D87CB578E7CF8415DA7B 99B893276B32EA6131CC0702DD804C370BB2A4B498141E4B966C3CC92A35A2DD F2CE473E7FB4B66829D92751CC042EA46546010B4133C2539C139D28F7E2CBEB D8AB3DF5A567F96291ADC93FF9F2F33BB7D936B6AFC4837542773A3D470DDD1F A889C13533627931BC8FC4438D64581C679C3320584C384E8DCB073D7C8ADBB3 DA4DF1DEA77FE1E991C717FF9F7FF87BD5E571A4D81E6F2F6741B3E887469511 8B0EEFDF342AD946F5E82CA971B2E005A3F03468EFCCE7A6461E8845D676B252 363017B9B03C8071E3C25018D847C667567998245AE7071B64F32EAC02A79376 5A45B197B28802191A0C2DD9E1351B5B2CF3F90DE0D1382FA234D3CC920CD633 01D56BD4A13947353E99E68602DFD782E65C3437B3F406F1865FF67EA79BFEAB 8046733C2A342F4CC388A8E3F801C759D2F6089653B3FCECE3472EBEBEB2B6BE F9F44F9D3CFD53E3C8ED69ED2962AE45B001427807DE6BBF7567FFAB56B7D2AA 858A8EA2277EEDFBEBCF3E989BA84633610194C8E82A8E55B12ABBEFC22A6269 6AB43077BBB7C3FE8B4DB6E6EEACA409F13B126DE5837E96D8C6D3B29AA23852 F015E16B58F06CEB044F11CF15A268B49EF8E299E0A3419F6FF3CB33AFFCFB57 17CAFED1A5E95EBFBDBBBD3F3136EE59DEF6727B746E41D422C1F7B3BDFEE4C8 89DDB407ECB231185BBFBEE57DB231F9D30F80BCF56545F822061A664C0ACBED 5EAF58CFEB23A3C4F6F7773B6F5DBCF9E62BD76FBDB779F3767BA0516C5A6318 CD14ACA526773C8010917DE028A3A84358AED260C41AE3EC240A1672B78AEC51 6C4FD41D2ABA54C4A37E5067A4A4239AF7A5E7EE56ABD7E3CC2BE892706768DC 057A4F6C2A8B6531782E0BDF6A87E5FA48E05932CBE64869D1A9942AD651B555 2F148E592F256BB6B5B53076D74709F057EAEEACEEBD77E34EB53E5673AA7EAB B9901527A9FD80E77A38E536144B1D296BCDF1DF24D9B5F6CEC35EEDB3BA3AA1 8B5E2347C84C7C29E516A9C305A32241D82809938992EB0489D8D21BA5DA5A1A DF1CF4767390F3C1EAEE6E69A4323EDAA012C7A9E8153AB59DF5E6413B6EF613 E3646923E6502B2545A281559A4C4285E447BEEFC2BFFAAD9F9F9B1DCFB2356E 32508C7FA134CDDB6C18783BEC414505E1B02113A9010A5788F167CADA184DB4 EDDED7BE27591A7CFF490180DEC9813E0207F78CDB47CF347402A3860AA20A20 8BA061ECC82A6E64DB2FEE01BF8F306BC90EA39E86DA3CBA7FFAC76614579DDB C1CA8DEDD3CF567367DD2E3C266AA67D9A6A2A9DFD5DF6E6732BC5A02CB4D54D F3A6A2AB49BE8F93D8B80933AA80002A8A448E5C8D86F479E8D7783F80820CA7 920C04DEF733542862B971AB3039E74850D3623C1C3324CAF4698B8A16F35C1F 729C31675075172B63CC5DBCF7D0678E694B4478DBD3B8FFDED8FB5706177E72 862DB4493E81B7E9EB5FBD9A2C17E79F3D8CFDA6576078C4C2B53677BA23B45A F1B524E4BDAB91EDA2C38B659C9B96DD14DE8755DA5ECE366EB7CF9C9BAD1ECA 8403A5CF876A0BE86292326EF6D281FD7E4B5CDF0A9BB9753B2BEEE8A2996736 E615CBE3669E2017AEB2326B5EA3530E9EF06D8CB2C593FE851F3D440E037901 1A6953B771E5EDABB7FE77D4E7E99E2CF6A136732B1EFAF060E4E5F0E4CCDC50 A1B28C2167C98A17707D6CCEFED03FF928798851F85F62DC0DCD52904320840A 0DA219988E023C6648DBC21EE47460672E9656CA7A4EE4BFF0CB9792D725AEB6 3AB95C1F14AB0A75810B01F53607619984878BB5C79CB2B4BC4C95286F587CC4 013A884A405692787AA6541DA35BADFE5EDBCEE03DE8A2C85B1E07C8E31EA7D3 93D5911ACEF303C5403432C00666FA92CCB537E5DA643A5AC47C9AC2C783E0E0 4E37DD0D09B5F7BDD12F7EFB32FEE5A5915C660CD351CB39E4D935509B2C3BF9 B143D31F26A9BB6CE37A786FE2B9FF7A23B837D641C51D355856697F98106482 CB4D4C19809A23000C5556E1D9A295CF7AD396C80F1D8B9EFAC1195EC15916B3 7CC04CB0BA2724C066668EC70D10A24839EFBEB24EBDFA535FFA045E00E4D27F FAE5E7EFBE990C82C6A5A8BF8CF07E1859C3F445D044F7D397CC61B2499C3696 486696DD04549BE825407FCAF8B82F8FB1F42CAED6351193CD9FFE173F9A2AF2 87BFFC27D583316053FBA27B4BBB912E622C8676E1D4B80120ED526A9B11D46C DCB517BCD28886EABF76E1870E978E8432EFF32410A1B96F9545815313A4A48C 9457A6DF513A940A91E89D6579B045A34C85386E29DD2E9C8CB3B4E8689D58DA 0192330C431CC6C1806632EE21A08B99A0AC3040A8CC688639E404881D1A3498 14382486778285FAAB96EEA1ABCEFDDE6E3CDCB06AE88D521817102825F9042D 4EDACE61EDD449313BCF1F7DE6F8BB97EEDDBEB4BFF891C98FFED21154ED006C 2BA3E373C05BED4BE494BEF7DB77B77E47E25A6647213F449EFE8DCFFB178ECA C242193581362A26D24216017A5D84D76914912237890C5639B91E0E5E6CAB65 B2BB95262CD8177A2B0DDBD1C0363EE101B164AE636186222D8E658DE371EAD7 7979275D3FF4C9EA852F9D4BBC65373DB2F1C7FBABDF78F7E9C74F0C74FB603B 6EB88D20E06BAB9B4EA911CC82BEEB7656DBE3E5B9BC5AB40E7616FCD36B97D7 9A0BF989FFF982373B8B330A6B1D7620E6D302797BEDBE7ABB75E5D2B53BB7B7 6FAF1CDCDDEEB60724570E94E7FD38C18EA59288A75905B170D4168C6521C83E 616A1E239C6187B1CA68C9D1B078FC05C56BDC996FB5162BFE38CE2BB095B805 8C20F7CCED2D454E13DB179B4D9AE68F95C70FB12C5719D4E2C2E6A1EBED49B2 1BCB3D8936D328CFB2C35EA9246552646DDE9DAAD78E707FA6AF6C44AFFAFAAD E9D2665023D25FBEB9D14D7A0F4D4F4E6CB5CEB5C2699F3A55520F4337135B65 E70D912DB7121522AF52727C7A7AB47E1CDE47116656369A95D76CFBEB9D8DDE C1C1674B23C76181BAACC7AC2CA565C1AAF0A6B23CE6C1AAABAFA16C57A3B5EE 40943DA75EE32618D6BED16C6EE6453F55592C77F34DD14725E2FA4EB99F4603 1563AE3937F34D0F3D30F795FFFCAF0F3F3091E52DC67A86892A282F0E27663E 01569FC23243B9401991992D2537D7243D22FB89DA8BADA29439D686DEFCE60B C1E191EAC3F3321D2080400960098223D185E60987959C15712E0B973B80A4A8 8DD7BFB5C956EBBAF07B7E91A2C28D5DC5C2A54F95BC6338DDB7AFBDB672EAC9 795469B1A4B0092F58619CFDB4AF0A7BFD7AFFE61B9D3CF415F10E54B625D22D 21BA9A99A03C80336CF272B07686394C46B79870A961CB0C36D1AD1FC4DA0CFB 47813C45148892E2E61E910C5D8E0DED34FBCED2BA8E8A05A6E71D6E0ADDD2A1 A3671A57565E78FAB30F7AD328F37751AEFDCEC9B75FB83373DE9B385F96BCC6 12B1FDADFE6B7F78FDC2478E8DCCA54E94E9CC8A28DDDA6B8FD9A55A097E8F7D F1ED7EBD618F8F635614B02A93028889BF7577A808CF1DAACE67CA8592EE8398 CE49CEA06CDD1CE45DB636A0EFAE75B713BA5CA065AA5BC2F4D278D80C756A2D 0A10E8D23A4CAD076C320E6A9514E531F5E1CF2F961F05993C0070624E7077FD DE8D5FB1F7D27617D1A6422D5D0C4CBC118804574BCA91B449E6085166FE8493 CE90F2D4F1E0FCAF7D889CC4C6AE3C1B1A79801A0104D3C3740C038466E89B0A 363C550E139E024D21204D713FB0BCE885E83BBFF11CED99EAB7958B1B45B16F 729381EF284684B1010091899897530F4421B07586CA9C8C78BC4EED32065CEE 4E4CF352ADB1B6099F98188BD1AC67DAEE3183DA36526353138EE524391E10D7 044CF361C4101DBEC9021B5FE982F578E139B246B3A0BBBADFEA84ED60FAEFFD E915FCBF2D8E434D419A969033C1D229CFC2D2AB2DB98FFCB487C7EF26518574 8F7FE74F5F29BD752CB4B2BBAA753B4B0F909D836AD0C6C03F477E8CE11515AE 8A472C7CD24FC7ED3952648F7DDC39FE8C9D64315294AB5017992C02A52DD830 38913425B03A63655F7A7985078D277FE1937A3EE49973E9DF5E79E98F96FBBC 7A398D6E89A2051BAD10F74DE2EFE767DE9F9DC07F35123B3C22345103143B2E B1E76AE204CD1E41A3B614EE93C90FFEA34FDF796DFDE57F7DB59C3584198E6E 5F35914943319A65F01F9BFED7E155AD8514ECA469C79D73BD8A19D7B9F7F0E7 16ABC70B73F3D57370EE98442410A309E860662204E17DC1369214AA68D494EB B7435554FA59D1C3795BE9AE043DC5FB5157E7916F71339DA1CDF730579CCCCE EF67F01A47029C0EAF090B7C5FFF99BB0834D47F26026EE8C7AD3F8861D2C363 1B622C6ACD9635F719667EC20CE9EB5C532847B3B63E4AADE3CC2FC9E8D883E5 879E3874E3E6F2CD57069553D5CF7CF9946834A104106E231337A66091E7CC7D F33FACB7BE02DA36B570BF7ABE7CFED77F544F9791086C05AC193E664C010819 D57A2F4BEE58DD7DAD12A5017D4AC995B8782D14AB686D7B30C0663C6AA748A3 2C0F00CB4365F95654F452694EFB391553256F943A25EDC7229533D1C77EE1BC FB709E0AEDACCCDCF837DF6B04796D3138D8964507CDCCF883B8DDEE648D4323 D6886AAEF64C2AEEB868EEB6A6CA479ADB8315B97FE287CE078F1C461C1E912C 06C2A3D3289841CA8EDF5EFED3DFFB9337DEB8B31BD126F1FAD4228E15450332 34620EE3240D53973942465D0EE40CD9B07509057873299EF64B711C45FDE8B0 CF4ED8F6A172F068053D2A4B0D808580E665DB4E940F0FDA651D8CFA1A2BBF02 5F169E4BE038E5B4EF64830C0427B64B3971258B30DFF4AC5827957CE098E474 FE8E62BD242EDBD4CBD3B38DF1224937C64AEF97EC5CF8DDAB1B44488717277D F788E6B699FE4ABD24B1987F29172FC711714AC7A97D4CE54B3E7780C8C683AC 4C8B548D6FFB1BC4F98ED3CA7D71810787523307618E16B2CCCCDA521B388215 E73D078512F506496CB1DD80772BCE5E96EE747AFB18AFC5F0540ADBD8D0F746 831191A18324098BC4F445583428FB08C9119FFFAD9FFA911FF9C2E726176724 EA82E084656921BEBBB212EDEC3B8668CBCA4CD51D2D99352BA439F324315040 660DB2680BFE948232B8DDEDBF75AB766C9A1C09E2ACED01B91324028E180B0B 088D3646D15812AB20F05AB338EF5F4DFBDF8E47F5C23E4DDBAA5B4E7D33C87B BC7DF4D32322466B573A76DD195B0276135153EBF3586AAE03CBE4CAFAEFBF7E B07C39C3A811E27C5F0E36527D50381160BA694C30195B5E6ED414A6401F712E 0AD39E4A4180D1E1B98BBADF3D474C7B4C4AC4B07C125A98B63E391CCB37C68E A05D1A58CC133DCB5040C76A73F1F98FCDBD7DF1F5273F72CE5F8CE2D2012A6C 7F3076EFE2EA4EDC7BEA0B9FCAAC98162DB232FD97FFF28D99C3B5C507881BC5 24F77A1AAF6E6F1F199BF03DDCEEA737AE8BA523A34129C4A9B018C89D9C5077 F5CE6067253C7D6EAE3E07156DD87C078A82806CA3C58DAE6A5B3B03FAF64A7B 3524BB9677238B3712731D53E2B6034008358A02B2F0456A9DE078D2D6A00999 1B3FF9C347EA1FAD08D59605B503F760B07FF917E966A755107F5F8B7B838303 5803B6AFA49B26C2E2BAEED1404A5FB3133EAD203A75AAF4F0AF3D4D8F5210B5 1680800DF29A7073340A5C2C1F5AD2E1020AA371764D114ACD151D68F6C25862 A93C7273FADE7F7CFBCE1FF539F65A1CBD0FAB51980064BBC81D66D601146720 9CB6C0AEC2B699755116C6A3AE33E17815845D14F976363B3B094A627B7790A4 F0FE38C6161052051F42C5E375363D5B2E581F3919F34CD2829948838A6D3161 2CD1A06836B1B06D5C65DA85CFDB6C0DEEE6EEFFF2D51BF8CBC766051A80ACB5 041F77F24987F96822C5FD477F8C8E5D08C3D8F1D08317DFBC947D6D2AA5E116 EBDE88E57AC64C171E4D88A2511AC4C6EC2A75647F84D8A783A48C4619C51FFF 7C65F274A824910943A203E54816A0644121C42082704C0A4A63C9DF7D65C5F6 1B4FFCFCA792B9B64FFCBB5FB9FBCDDFBDD62982750B5F0EA3EDB4B83FF33A4C 0E33A3F4F79BBBEECFD4AB0F0C5886269C92B9053E368E1FB48B87C498D6D1D4 8F3BCFFCC2C7DFFBFDF7AEFCFEBA834A0392B57BD1BB068B50A665268CF72E50 3A7377A7944350151B6BDA19CBAE01AD2EDFBDF0834783C554A431EB7BA47073 D8AD50D9A14A082687B7EC186010DE57E8AC5C1BA45D52089A506B2789F645D6 932237731F18DEAC67E95402671E2A5A7863960B2B04CA282C0EA85819E83902 AF0399A47481CD910D1430CE1526A91CB6090D831E01028782D2DC16E261F686 D9D3E67418B497319F835FB4E0D9C7083F42DC40F58F9DF68F3F321E86FD4B7F D1EF3AD98FFCE6E3CE2214700E02941A6A6CD2244975EAD5DFBED5FA4F192081 B29B277FE2E8DCDF7C2C2ABB1E1D95319029551429D4437327895A49B2E6F496 F33C62162579202E17DB7FB626F7D841287A986F2505903B90F8154CCAD836BA C134D4470399780EABD96C82D9E3AC0A68BF5F341FFCFCC2919F9C6B7BDB65F5 00FA83CDF75EFAF6E9278F473D6FEB4E7372D686C7D56BA6A589B2044EA8AABD DDDDC63CEB3605E6BEE7F82B77D70F3DFEA0F7C9A3A25160EE346FB757BFB7BC 601F9207FA8517DEB97B77A7953BBBDA59CE8BAD410F1BE714EC18D7412BC32C 02959A666359B26704BD83251B208160C321E1666876A454B5C983B6F308E627 7CBF5CCB8FEF390C979F2FF52FF1C1396C3F1D31A788E31AE96115E674355697 9AED2D95FDE4830F9DEC27762A4929100AFE26CE401DD5EABAC41D9CCA6CD04D 4552583E7257E3E8BBD166DD733FED8E3508DE19A1FB52D96B69B81D0E26AAD9 4CF57A73BB51E8C758304268AB907DE069DC032913F064A94650BF1994ABE120 5316E0726A274EACD99E453A166DE6723048792F5CB2AD724037A8BA9EEB1EA6 C7CD92F60F65DC1DE411969B6576C316170F7652D7EE4AD9ECF72DC2F328B5C6 2781ADAEB45ABBF14073E429345FAA56CAE5448A348D7AEDDEF9678E7DEEAF7F 7F6FD01F8411D4E8ADDBAB83D59D64757DC1775C9C8F4ED71EFAF0234B174E8D 1E9E6395528EBBDC84FD8652EC0DF4BA46494DD4A257D73BEFDF9A786A89CD90 AC48751790463B40737B21B64C162C2B1C9280CE8F439AD6E3D1EDFFB6A3EF38 DAF53BB267172E434E6F7463E9B38D4A63E4EE5BDBDD243AFBD4022ADAB073A5 8970918C9AD9209DE74C8C5D7EB173EFFD145670428DC5F3F27ED652246242BB C6AFB82A89B1D8362CD3C4899BA65762BABC4CDF19FEA0FFDD5CC310286E8C0E 3B66000887ADFDC380466D9CDD47B058A06AD6C215B9543DBEFAD4F72FBCF6E2 F5B30F9DAC3DAA42B2AA44B994D8D97EF4F2CB9BCFFEF4F7AB433D25379DD603 6FFDCECDB07F70FEB186678267CADD146D37F70F4F35A02AEF37A36B57C3D367 677D3F368E53D2340A50EEACDD19ACDE6C3D7CE1486389C480E5C8650033C88C 6339BBAABF1C7563EFCDD5F6724A570AB286F4DD4117BE4ECD76B994362796A1 16644CA263544F7235DD28592C3EFA647DF2B3B3293930ED02546047DDF867D6 A58BB7291D692371BBB7D30175E7D406B1CACC4130D4C63C506AAA547B84609A E7279E9D3AF5CB4FA655A0989E05C28F9AB65F2E2C539F4CFA8431D156CA3333 6128324F9A90CC7850665666629A11EB0F2E86DFFB8D15D4B237E3FEBE67ED4B 3988C28AC5013133699A6508A23EE5558B519447B9B91DAA5167D2F31A8C54A8 76B0A856ADE91973E1BDB1D593BAAA851F1643F739550496AAD55863CE475EAA ED9C591229287B4C3390AFC069B053F4187194B23805DE690364B7BDA98FFCD2 37F1978FCE49DC3797578A351C5C6774848C0A9D8C9D6A3DF24323A8EC623C71 F7F6CAE6FF650B1E6D26075BD2DF10DE00C508F7A8B6E2AC12135BD3BE25060D 1A3CE48625326E07ECA39F0FC64F746406B0E32AA896C643ACA41527D2245D19 206416108ECB2FDFB2BDF1C77FFE93E15CA76CF3ED3F3BF8FA6F5DECC4DE1A91 D7D37435CC336DD6E67D454887DE6A4551DCBF1DBCAF0887878550AD5983B8A7 C6F131941CCFEADA8BCEFEE2FC033F76EED23FBF74FBBF1E60EE765034188877 007F95E180820E6D4B814E68E336E9125DD3648EB119C7A9598E68DC7BEC078F 93C95025090B5D6060E63C16D8A7017566D23B518E44C111C84167F55A92C726 112AE57CB59B7654D1CADAA0785C56732CA06E5166E6E22D5914499C18F34273 A82C1378BD8CE788244AE5DA38229A7BE7617A2C6666E0DFF4C860D3C43C6C1C 45E6287A88846838B629B509A25680C640FC9409059B77F9716C1DA15E09F58F 9FF30E3F54957978F11BE9DA60F0895F3A3BFD615B9122373F5A19C77710A2D6 D8777EF3BDF84F518D3B5175E3B12F5E687C6261C09C92336B5CE49810B26018 C83890A85E1CAF3BBD1B00DCC6EE262D27AF46EB7FBE6A857E2BDA07DB3E0000 FFFF49444154174D73D69F6DE4C0EB588D310BA518FE0EDBC014429D2A138BA5 AB44CF39A5115D360DB073D1133F77BE776AE0652576595FFE83FF363F39E9B9 B3DB7B3D6627634E29879FE80B3E6931540FF7F64A355490D183AC3D335ADBBB B4E34F4D96FFC619B95448E4DA69F5EA73EFBCFABBCFA315D12F46BA1A352DEB DAA0DF94288A0B4F5B35CBE38E95101D993154D3FC8EE3FE4152A41972B52F19 4F50512162C6257325E7C1C0FD905D3E235939CE6929ED8BD28B82FEBBDECA9B FDEEB9BAF31363F3E7316D643DDF5179C95B8F50224A5B79DBE1784A92B35699 8B3CAC0EA7C0BB45A08CC96FC631E304C8562D2FF0F640D7C75EB3E3BDA2FF68 8AA70EC2DC92BB8D4A1379C21FBD99657F71F99DB2CB3FD6987928C33CE943F9 B1141D651E3017E0E1094F54D94D0BEA44765DDB326E5DF7F05FEEED24A9E577 8DD59373C89B2C5BF59CBC9FE6FF796DA5235835A58B2A7E78A47EAE3159866F 5A24CD34DDD1AA35527A3FEC6C77BB35BF94F5FBE54AA9472B1BE6703A1A6850 00FC50A352632EA0F77E3704E02964B6DFD9010828C15746C8E6A8512D79A01A 8BAC46D568CD7FE0DCE2939F797AFACCD1D2C2A46094F01E2C7764DC877B05DA 4AD4969D65EE6ED17DF3769EF41A1F3A295C9487805818D62397C02F139D4B5C F838C339CF222B2C15E5E48D62FBF9A6AFAAA902E5661165B5EDCDD127AC4367 97366EB53737F7CE3FB14879DF2C7D6415D4DC0FF0CC32A34EDADDBEA92EBED2 CFA24023DACF93B6D05B911A70BB2D535682A2930DAD994C27DA70706228F386 D3E0E6065F7FD09246756A8E443593268A5867D898220EEF08812A18205CB4E8 BC8DCBF142E9F4FB1FFFF193AFFEC5F2C2F4A1431FC731DFD0AAE4165436E3B7 5F6F1F79FA23C1B901529BAE7C60F7DBF1E5972F3D767E2AA021A5E5CDEDB0DB EB2ECE8EF8B6B5B2DEDA5A970F9E031E1EA214E102032B26CCDEDD4897AFEF3F 786E617489E636C86D879AF0E1980048EEA9F06E34889C3756DAB753BA9AA075 4AD6F35410ED23E268E9BB36940FA6F40CA547391B67722AB0A61A1C8D0C4EFE D4F9BCD4D72C67CC9C7E36FF70ECD56F5C5271A59517F7B2FD3607A40DC29C98 6E01D37499BA4531EE054F1187A2F4F827A71FFCA547D372C855896A5BD0D478 AB491B0DE9B5C934A6052B5CE378418A613A28B0AC50E99416AE828F67C7565C 7AEFDFDC78FF8F96915BDEC77825EA27B2009EAB445E0037C266B41E5E54C363 3E5351514499F614AD713662A38A663EB1EA55DC98D4CC135B3B51BB03FBC28B 8B1C48CB08733C252D9257C7EDF214D3A54C39A9C28509EBA3C0BB8C9F173786 59E675C33F73385284F74B731FFDD20B0084B34A8766612852B29D2AE56316C0 AA54EEDEE33F74A876CA4194B67BD97BFF36CC925E2F4DF765792563073A1438 02299115E5D81866F6411C8DB2EA591E9779C31DB19EF97C6964695F26186525 2D07CA0CD306C8B02F207E1A0149A0765AF02B2FDD0882C947BEF8E9DEC2816F 89F06DFEF57FFC6AA7ED6CA2E2FD34BDD9052032E877BF3BF47F08C10F8070F8 858616CAA60D658E571F1A638765B4202AD68CF8F03F7970F4DCE4F77EF5ADDD 6F15C2E3BBAA1B0FC8459AB10CEA34830D9D9B9487829BF407EC12D440688EF2 59D7AB02439B597EE287CF6495039DE6F6C01131D01C2301496AA1DC00A1D000 84994FCA3B77D5C60D51C01FDA207DAD7BAD4479568AA3FE60200B17BEAFE3E6 C4B229734012A671025B977186B9D58F63D8633946E970826278104A0AB3D994 E99A191AC701F2837295C3694234F4EE19FE2992E47EA8BA19AD340DC75A3A48 1EB2D909E62D22AB620D4E9E0F664FD854A6D75FC1EFDED97BF0470F5DF8C211 C9BB85091FA7F6D0BA354FEBDFFAA76F93577D1047F8E4E0C95FFB1099A7392A FBEE828652ABB3613B92F16CA47A90F43768F72A942EC0622BAA77BEB1BBF597 DB8135DAD76A7B10AEB493F55CA79C00104A6BE028A74ECA8002A14A7B424645 66D3620E7E2EAD55B1DBA7BBA7FEDA03951F3793786E5A5AFB83EF58BB6A6AEA F86ED8DD696E1D2DCD5B03BC9F6F578ED438A9242D338D549A3C79A7756771A2 965D8FF6937CFEEF9C468F95F214B6F01892BC7565EBB9FFF09DE5AB49C8E88E C6F7E2EC005E47418DFF4F92F78B3882AAC21137FE5A50101D244460052A364E 270DB7341958876C7512E71F2F558EC62A709C0E50C23CFDE3A8F3DF9270973B 5AB05E9820AA9E284FFE4830B68806D81A8C5682D1DC5183F825277A31DAFFCC F8FC79600F234E67C429C112D81CEC84D91D84ABB5DA51D83F1C704C31D7A59E A5781175774AEDD896DE2589FED360FFADB8B0A3F8E1D2E8E71B938745E1049A 592990189F5A05AC33CA6929209C83D2844D8B60B5464A44FAABEDDDDFEFB50A CBFEB1CAD84F809C0DC23D2EDE0DD9BFBFBA763996E7AB8D0FF9959365E94845 5CDCE7799664D59479A8B4C5E90D249A454E61BD891C18E1DD4ED885958999CF 79B5E20DB2A897C6793C1CA3AE8EF54DBA7A6A6B728A83DA0779041F8F58F042 27AA1FFFBEA74E3D7E62EEECA22821C10D97335A5BA785B94F639600F21A8678 B388976B5984F6E28D4B2B501BA7CF9E886B290DA58E1360E4288D58021BC083 A21BE358F2CC5696D5A9DCFBFFEED155732D9B638AB53D205D3AD77FE073A7DA 07D1AD2B9BE7CE2F7A8D18188D56F0BC0A8D539A395085B099B3ABDF7E47DC7D 57EBD45138696583FD8CEE0BB7A984B46033198F3DE3DC6B2C49CDF192567FD5 35A3EE5B8398E262196F60F8ED4C1841A352949BA1294D4D4A2852A31C1F75D9 AC4D834EA374EED6A7BFF0F01B7FB15166D5933F504FC82DE308AA3989D9F275 9197EAC73F5DCBD11613E3D97AFDD5DF7BE1D47CA35ACFECA0BA72AB03856366 B6EC5ADE8DAB1BC00A8E9E9942BA8F3FE8C853B0FD3BFBE8EEB59DC3C7A7C60E 735482B26063540863376BD950826FF6B3D07D7DADF37E8CD653B28DC96A1EA7 5A045A9731763D1718B695E78B9675C4B5C66CD6B0D599F9EA5AF3DA033F7CC1 79A85ED003467342ADF0D2E4CB5F792DDF2B0D245A539D1D22FAD2890B62824F B1B0B5A80A3DE5F8C73425767AE2B393677EF1D1CC0D39AA52644B1C9BEE3BE9 9827673C6775CA0A3BE7C6A99419F34D06EC195413E0A5C03291CAB6405724D7 F6DFF8CDABADAD22C474372F7A5A2466C4DA8CE358D81E268BE2BA85CB4C53C7 96C44389F490A8C19F15A4649C9DFA6353FF3F4FEF016DD7715D09DE4A37BFFC DECF191FF8200082044990600283288992AC60A92DCB6ADB6AB9ED716CCB961C 24BBBBEDB667B9C76ECF2CAFD6F2B4C7331EB79CE5A064258A12299262264190 C8F8007E0E2FA79BAB6EDD39F520CDA248710120F0DEBD5567EF5D75CEDED1F8 9C15C46C7B2FDB6FC61AD3418C5A1C39207151CA4C919F64EE0CCBDC3821A104 2C463A7C5A25824106A4C948794A03180733BCFCC2A3BFF62CFA8FCB135425F9 09AEE4A29963C6A46E96958D79347618DFF28E121D53A5F9DCDF071BE76E98B8 D48EACAB41BC9B85C0A63509ABDD802DC50122785C63EE49CC4DEA5AE3F4911F 2D96E60008810AE434D01F2A65C8541A4626481D05EA09022024179EBE542C4E 1EFFA5F70C0F7632DC43D7AA5FFDEDEF3537B336D12E87F1F96E30B47472B35F 94F39B1784FFBFDDA83ACD50C10C5299EBE26C81E66F2FEB47B4743A33CD63E4 D1DFBBCD9DB09FF9F557BADF23411EEDA5FDC023E718A7216798A48C0482834E B088BA4F25A91843DA41DD9CB19499149DBF7AFF474E46F63E8A53363413D558 A16C80686C65C0E49533458C64ECC8DA8DB7FA8D4D2A2519645E5F435B432E75 2A69301C0E9074E0892A972200EF54D937C117D1D48727BA658571021F00F46E 4A2990DE20E1412A85F2B901DDA27A6794F48375CA53555690EA4EBAE91695DD 3CCFC90CE53A8E46C3C132B533B960E947993B9B92823138FE40AE7600A8B258 BFE07CEFB5EDCA71FBFDBF759F28B504F07964E8CA678D067BCE77FED7579D4B C541B0BFF0A363B7FDE22D43C337E89C4EE7339A5757892813CAF91B567937E9 6C22EF3AA16A7291F40AF57F5CEFBFE05976B523A3FAD0DFEEC65B0277516A4A 1EDA711E5BD3A4602350FC693FE25D1E4A43966DBC489C59CD617A0C9078F433 7707937D03A3F8F566EF9BD727C7177ADCBBBABABD9C5B2C636BBB7BA3B854D5 4D33F64328D213CBB76C0ED71D82CAC3F28D9D9DE98F1FB54F4F88106151D49C 9C88586775F0C53FFEFC2BAFAD0106F5B4FC562077BBDE28B22A8E41D168A3A4 AC51D65CC4F25A12E94C996FC10FE6081D97E2A14AF1877385FB043584D8A818 6FDAC9B75FBC5ECAA1A3870F19F03A80A7726BB5C55FD8DA8727FFEE837377B3 78910EF3B92CB78B2E2D57FE68FDF2619CFB78752A67A26E9938892C74D2B56E F08DA09BB7DDF7E27C68B0B3246C67C903E5B9699D75F42E46C2DA4F5BC8FE36 0FD6BBDE6298DE355699E75A41131D3348D57C966ACC0175DA65C6C56127E874 6E4BAD25DB6E15E45B443EB3C65FBBB6A119C6630FDEF650911DD9A91733EB1B 52FCDEC54B83883C56A83EB43263156591009550D78603C2FB9EAF35234BBA6D 6C5E43722FCB3AA9ECD9F46AB7DEEC0C605FAE4CCF323F09E38017D9FAB0EBFB B2401CD729B407BD7CCE9829179C380D456CE75834684F14ACFBEE3C72F29E63 D50363F3771FD2C772BEB219160642460C953CCA28D6A11AAAD6DC411A5FA1C1 35D86BA8A56F7FE76ADE35DCD313207479AF0FB480C6B11E618D2B2B50954B87 55AFAC492BDED9FEDE13EBCC3781F00861289F14677BE5476613462F3EBF73F8 D05C612988F91045254481887B4696F7E336546A83DA49AB72FEB960E76A6812 3C4806FDCCD8F27157439DC44F8C51FFA76A4953D35F233E3DEA1C55BE15048D 7CD835E5F31B6309EF5EC59CC444E956E53BA702D4E0A7E4984E561C7D8611D6 754AF76F3CF693B79DFDE62EEFD2933F321FE38B1914978432CDE8EC6497361A 77BEFF2EB3E2F971A40793AFFD3F6727913E710B506FB67EBEEF50AB3CA96364 BEF5D2F56231377BB80C1B88A8B61E50A28AEF073D7AE5DCF6FC526D6CD9A025 5D201D29F91C0352987DE49FEFF081F5C266F7822F7762BAC3B3AB7E9F230945 AC6CA8ABD0BD541613BE8CD192658CE5734516DFB35CD8DD5B4D17ABB7FDF829 91DBC35994A556B26F3DF3E76706574D621537447783079E34FD04F134424414 A95E13649A99799961275A79DFF89D9FBA33027D9055E093C393578C5D75158C 5C33511A831E4C28301B4E0D85A33250E1C6AA9E08A499910F2403E444E3C2FF B176FEA9353737B1D78F770590D798ABFB3C80403D5393D4C2CAD2021E395B53 030A628EE2B19C0DB5A5E61412BF6EE77A73070A969B6FF4D21B1BCD98131DE5 841F0320E50DD36082984975C1312B5A66834EE1AAA755F5D6C0EB87979848A9 4CBD9896606A0EDDC5C73EF31CFA8F076A861A47482391688C998C4CB1DC34CE 5B480664EFE8E39333A7725ADEDF7B81BDFCAFE74CBF1A097B3D0DD644DC8980 54318965026A53033C1425C64EA9830CDD9CD44E7FA4529A6AC26FAA45D66854 5C75128DA672220C3A48180932E3045F7CFA7CC19D3CFAF38F87B787A1DC7777 279FFCBD37AEBED68A2DFD5AC4CF0D925D865554A01049A2A2A5755D57A163A3 2C5E85AD697A334F07806A91154FB8EC1841A50C1B77A2B7FFC129C7309EFDE4 8BED97713F2776B36134A497746EC5CA6A39212A4B10E005602F53BE4BD16446 0E9BF6B46D817CD3972E3EF0D17B13B39EC5827996F0D483C32A2717D4BDC953 A402D580F8B5F2372E76C3410E5EDF7ED46EA5BC97E25437D2D40FFD01D058A9 6E4FE1BDF224061E9AD9860E54E007A2907A7112A9A3163581EA85A127559716 BE69373A323D94EA3854A9DD914054CD9E239B4C6562A080903028F4C06EE097 BB589BD3D931A330996445C7BBFDA1627E268095B8BB957FE67B3B599EFFDBDF 79101D0D63A665D822323090DE3A9FBDF04767731BA5AC3CBCE337EF341F4581 1814D0B214F3C88412AA2625474E549C266DD1DCC8927DA0DBCA637DCFDCFCDC B5F42A7C855C23059C8A3A11DD96A491C6593CEC2169633A6E5A0EC817A92B0B 7C9974C5C0B0E8B46EAE58AE9509500F277FFB24BA37F5A597EB16F73FF76A91 2B53AFF58D7E0ED99365B7D36A198EADD754AC477F2F2CCFD4023DE8B7860BCE C18DED35EBE1B1B11FBD27EC46F16654B04A68FAA0A639BD8BD7BFF8675F78E6 3B978659A58DEC06887D0442019EBCDFF7633F520C84A8D414EA8E362E1B775B DD6621D2DEBF34F6DEE2C41D5E5AE3D9A0607E3BD87F6263D75A9EFCB9D2E289 664723C3B462644382A3FC2B06FB7C54878DF2B8348FBA289A928B03B467E65F E1E8B58B57DFBDB4727BD98DE9005ED7A496BBB8DD794E0641ECFDA4359967DA 5364F0E47EFDAEC2E26353CB9A1B66A85BF055E7AB202E0909EE78A84CE39C72 32198AE12826C14A6367B7113EBBBEDAACA28589C269E9CCA5C6F73A1B7FBAB5 FFB2863E3031F189C387E79296E481C6CB573AF667376F3C13EDFCDAC2F2C731 8D6BE1FFB9B6B652B6EE2E4E560692A628D38D486AC3286D87698B9AAB9C5F90 FCADA07FB5DF45182F2DCC062D8F8A2C57CC5DD8DDE84A6D76769C806468749C BCC5B3D0B51853A66A82C6E13BEFBB7377F5DC4C35F7918FBCFFC0B103F9E569 CDD4B41C2CFB482DE18C22D5F22CB8323EA2BA3AEC6870B911456DA72351536E 9E7DCBAAE9E387A7B314E40BC7893438919C4B0DF615AC3B1227216506F1ACF5 7FB9906E1181ED806B65AD1691EDA9F71AF6726DF5856E2D6F556F8D221490C1 989A6C22032A0B3C0D4D789C7ECFD08AE16EE1CC939B83BAA4A6D513492391FB 211FA4B24D14D42959308A1FB9E9D9AF0E5C547EFD480D8E26EDD55AC9545C9E BA9E00BAA946BD95AE50AE1E6936A933D0589318A4796EF65DAD931F9CBCF89D D6E6F9C1231F3E820ABB0C184C088A384DFCF4D5339BCBA7DE3EBE920DB51DC6 F3EB7FD330EB72FEC1428777EAE7FCF1DCB835064FCAB876667B61A1608F210E B4400915D0D742C0DEF68D4B6F6CCD1F181F3F6890A2CE01BCB338C589C0A6E3 13FFCD8EE8B297367BE77DB91FEBDBA1B8110F894E968BE52A23431E9F0DC3B9 343B4AB4094C0A8542D10A4F2D38380E2F7883DB3F76AA704B08855026F92419 9EF9BB9DEDA7635BAFEE64BDCD28F033278C450CD293C176D68BB11C23FA38CE 73A7BFF443A5539FBC23D23D6B048412078A4F80224486EAA4579A24561EDC20 03325DAA5B391F8F6CEB34A2F2C6A58F0C35B7D9E97D5D7EE3CFBF5390353F34 7712581FC3489984EB5453FE32F0DD99D4F2CAFC071680A6C86B268B865335DD A942DE21DC1F6C2F2D574A35E530D4EA0DD7AFB7493281191DFABE0E10E09826 4E0A2E2A8DE96615746196E02881C209C2505D10AA9E8D2CE3A05B11313DE7C0 63BFF50CFA9D9509956BACC2E5136EA8E8AEF1AC3A4F2A050C90D5B00FA03BDE 3F6DCEEDA4F58367BFB6D97A03CA89B5990DAFA569D337D4311DF1A0AE89CCC2 912810F920B641AA1873E9E91F1DCF8FD5659CA0D802E8558E41AA9F5E50805B F843521314612ACCF34F9E61A472DBCFBE3D399D797267BCBBF4C69FEE3EFFE5 F38945AE87E9A558BB9AC64481687AB37754E54E2867644DFBC1309D92860A13 8315AB76AB4E8F61ECA234F7B0F1C8EFDE6D87D9339F7C7170CE6CBAD196E8FB 7DB6AA27F914EB0803F35439CA6966121DB01C80703CC3474C77C6B118A5C6C2 C5077FE224371BA9CFF5404D328934803F0E477616A93B7EA1E67F457059AB6F 845A5AE5D8DC0DBA7BB13754DEA1A3CCB8248C543E9FC9EC6A900C121E817C53 F262E49AAA960EA589F21ACD1235A72D47B7C4B0EED4D59C923284DE043FA88C EA4C4625C6E0F4FB93C09267A9D29ACA08436880D06A89D019428EEAF9F124AB 1482138F14F54AC791CECEBEFDF20B9D81F03FF49B77E61FD242CC2575A916C2 FADD7CDA7BF54F2F97F60AE62DDA7DBF73AA7B741F1E72991FD6B4435277E1A3 296EAE0958E8C4DFCF9AEBA91882BA37A08CAC6AD73EB79A6B56BD9436E42012 32946E9D5A7B6918879DE150D750CCF404136260A7840D9AA60311489DD46CB6 EC58340825CE1DFED9E9DAFB9D961E4C44339D2F5F4DCE5D1BAFCE0F87AC3ED8 9B9C3294074357CB1DC21A108F1D41731199C8EDEC07D3F67C6BE33ABBBB52FD E84389A6FB2FACBFF1774FCD1DB87DFAF85DB4500C3BC93FFEFD379E78F95C5F B3434CFBBE0F92A1ED077D955C0E64C7528B050DDD8C2AAF3E0BE5B4F46D05EB A3D59907511E7783CE44F189B0F1C2956B8FDD716AC5EE03E39BC9100BB94F80 DD32ACFCD2F42D9A5E6BF5AD409F732AF95261686ED4EA34CD2DFE5FADAD7634 FC85A50313D9A06DA77A5A1E5E1FAEA5DE9EECDC539A9CF3C3D5A2F16DCF0B77 F93B6A07A68A985678A18429611C38B76668861ECAA1A6A6DDA0A4608B5AE166 DCA8CB272E5DDCCD060F9C3C340FD435966FEC0F9EDBEEB74C776E6EECDF1F9D 2D77AE5680EC76EDEB41E1AFFAFDCFEF5CFCD881859F2DD4269261CB8ED69037 2174E51BE3715069B08A86294F41180B7AA95E5F75AC9779B40EC547D3E97C6D 736327D54D5ACA5DB8B1E6323257AB245CEEB715A89B36BCCB90E47199146A18 AFE4DC9A91D905F2BFFCA75F9A397D321C36002EA865E330540B13ABF6715D65 F701CD548B9301C0518D9318C78DA47ED532B478BD3D7CBDE11C60D69C034824 62ACB25C548B7242D5E19295A80BDDC04285C18BFBCD97A334B102C40B7E3595 2DF6D070F6A195E6399EF9BDCAED51A267AC3FC540B1B1469614544F0481FDE5 D30C2858A5F926BFF0D2200EAC84254DDE6FC7593F227BF866EA849227224B47 B615A3E8A591D1E8F7A727401132D530CDA46AC719B9A3A6541DCB10151FCA01 08E941431F539107B5E50FB58FBDCBDA7D237DE3BBFBA7DEB5589C0EB3804910 747A9D217EF942E8561E993F65F6ED559A1ABD7F12E1B9C1D23BCBBBF15EB48A E78AD3B2900C3D6DE77CE3E0720EE59593A3291D0E0A4AD98F71119A17CE6C1E 38343576C8D2F2584D27A896CC8413231799C333F5B44D5F024518688DC4A847 B209DCCAA06308E5793248C5EB4C3F9A91BBE1C582A065AC54E0F7CEB31231DF DCEF9313D6F1F7953523CD92F1B858AF7F135DF8BB3A0AF42189B7C2A09750A0 4DB1211253F5B89BA198349D236C3260ADB977BBF77FF27690B796AC11AC4B1A AA2E19E164584FA9BA732132CED445848D24908E04243F5507763A576E353D1B AA98E7A736D2B767BFFB275F6D9E69DB74A62ED815AF1368892E95695B4248A8 CABAE648AC2B9F198935581E9A29E898654D17ED8AC1825EAB5C60F3078A462E 4D52BEBB167ABBE5C090BD2C06202B125A415819B75B9959266C9C6A55143010 9DBC90981A518E8CA996EAEA9A098070F9B1CF3C897EEFC81403C12F89BAF562 1150B3B22C2D92EA9809EF3CE8D0C6ADEF9C1EBF2D0160ADBFC4DFFAF29E4E4A 9B72B821642324A1C8841E730AA59AA14858843F480B1621EE4CFAC0BF1973C7 EBCA7E32B190CA045138A2A51C5814D47B8D031002B532CE7FEB327CDAE33F73 1F7ED4F064A79ACCDDF8D7DE937FF6A296E6AF85834B32BBAC528C46E145B08B 53A99ABA984AF85307A4CA8B65E47BA426EEFC5BCCDAAD08DFAA030EC513EF29 DFFB1B278C56F0D4A75E0A2EB96D57ACF16EAF2BD659064A85294B33C5F19463 0D6849AA1121A7327CCC72676CC3A4182F5E3AFDD153C26AA9EC34904F310345 0AE887133B8E6039AACE3392D0F61B41BF075B281F68FA5E30DC8F86C30C7E3F A642E8B574100CBD04D0AF14ABB6A5948E86912956F2151026862703850FE030 95911A82D00461B1D4A244A56DC067D446839A524D3B8DF2A7460476B463D577 17A935F25C03A199181A1937F5192D3DC49C9AA0B54A7AEB230E29EDBB49A1DE B65E7DA1D70DBDF77EEAAEE26359A4F5B15100A26E84E6EA97F72FFED58D4237 977B37BDF353F70E6ABB24D39D6429D397536481EEA100D3F0C670AC0DD6B5EE 2A113A2703028BE8ACDCF8ABEBE568AA19260D1104F0F198E311B7C54358E8A2 9FF39241C4BC484D23EB1564982A7B916283E5099AC099A9DC03AC991FB10E7C 6C317085919592D7BBFDAFBF3E9B5B94445FDBB9502BBB4652D8DBEF8FAF98C4 C1690B1E69CF9A2CB77AC24479BFB1DB2A24C73EF59341DEB21B59F71F5FFAEA 3F7F9BDBE350459D7C59CB55BEFDC65B979AFD81C461321A1B07F486FA050F5E 65AC41811C3A52CD858352B97FAAFCC1E2D8DD033ED509B562E57B2EFADCFA85 BBA767DF5F5E38145F6BB084DB7659E45241F66DC1F5C15C123A410A64BC492C 8396DC21DE762E2DA5F956643D3F39FE9517CFFEBBA9C9BB67AD3E1B225E929B 623DE86F93C181B1C943A976B95B7F8B996FED0447CDF1B7D5F279E6CB3C43B9 3CAAB87E5E0A1DE70228FC3163B283430C54618B7752F72D9CDE685DBFAB681E B1CD1D3FF9DADADEE4D1D3244CA7BCDD5BE6EDD40A815FF375F2E620FB8BFAB9 034BE59F294EAD84BC6F67D2764D2FCDF3F862EA7550B6589C2C4860D581AA45 C3B42EB20B0C5D027141741EA62F0EEA31A643A6AFB79B868667C76AA013F6DA 1D1FB618A5A98C4D17D92536810A8773851385E2C6B5373FF08B1F7EFB677EB6 A3F553354D288C84E7333554A4C2C62DA80704CAA746B99AC7E32243B6A276A2 45D2CD60B06643C938D369F4B727560A346771D5016F621192340021A569B6F2 AB10002666BC93EC7FA3293B8E6F64B99E4BD3417C5B6FE13DC703900FCDEDCA 71451A8C61053E63C27A584DB8E024D680C962D11F8DB2CD5E78AA7FFDBCEFD8 5637E90C32D4E8895DC2A0680942B86A641FC9BC9B119F23573339EA4B1B99CE 644C53CE53AA8353CB54C6A5B261831D8B60014F517240D76B998C4969E1875B 47DE6985EBB957BFB179F4FEE9CA629246C05B99D01A8445F51D238C8F2E3D92 F3CCAB581AC113C6FEF7B6564E97DABCD5BCC297A766359777F7D060972F1D83 0D038F5C27524F7DE0BD19876717BA97DED85E383451BBC5D480364835DD09B0 C3117352367C6B8FEFEAAFAF87973DB92F643DCB86864D11D27D80FFA1AFEB7D BB7004D37BF2AE93A6611A150BFCD48259A5D67A375DA5FB0FFCC421BD2A9419 7D25E66F59AFFEDF6BC99A11516D4774EB01573BC842A1A18E9C8C38192B9AF7 64733EA92F3C9EBBF713B7459667A42E436EA6ABE344453C46A783F0EAA0C26B 581F0D0840214BD4F07FA63C7A60DF0BECA3D8D3B9EA75C74975EB9F2FBFF957 E7493ADE44782F0A3B114F54004FCAD4E026538DF7E9C81A121EBECE31ACA358 2B5136E11AF38522D44D24BC8347CAC571CD8B7B32301BABE6AEEF25B6E5F304 7351D2D038437924889E1835A2CF5A693153A91C812219115658680289D38CA1 79E0EDFFF149F4FB47414BA8C1B89827499AB28CE68959947842D7CB66C6495F AF923BDFF6203A7E56EED1D7FF667DD8A8F82CBF1B761ABEDF48C850B70555E3 2D44C0B64277E8053765959ABCFFFD3977AE9D4AE0010EE5EA7A2CCD68225533 2B8D544088477C8ECCD5EF783CD06EFFB915E7FEBCCA4546B4B3D5FDDA7F7A89 5D9BDFA1CDB3A479B55F6CC4BE3A01E6C8E6AAEB91D334620A1DD4A4243C76D8 8A04B9383A464A2734B262616E74163E327FEF2F9F243B83A73FFD9CF796D337 0DA8E5BB837697E43894448C8A1929088D6BA289F9801126E95266DE6639B316 36B3482CDF78F8C3EF48CD3A8FB6403CA220A70EEE137527DA8F43810327C9E1 9DDADEF97E225180484F43AD24EDC57124D4AC2B5391BAD407391204AA72AAE8 5DD898CACCC9B62CC3B04426832882F7AE62349832AE05013948D300337516AA 780A494763F500FB1216FEE8A474445D11FC3F051C15058135CE86990C8B99BD C0F4052D58628693D9E549F39607192A6D16E2CA70E8BEF4F46ED3F37FE8B71E 293C14896C93100B65E5B43E71E6B3E73A2F347299E1FC01BDFD91E34932A480 53C6ACD4F331A0964849E4230AF20E45BDF33279D36ECF46C5164076FC2DDEFA 62DDC99C2EEC3D5F6B08E5036F22430B79C2BC1C2A35068321CB128A86C3814C 3305EA1AA9985685E3314C73068385C6EEEADFF51FDEA14FA26661A8F72DFFEF 370A0D6155796B6B3B17D6D058EDCDC195A542BE62157B32C45154748A50C703 25EDD87EABB5F2B1F7C427A7815C3A2DB4FECD97BFF82FCFDA5B0E2853D0085D CB7DCD1BBCDE6D7B84865EA48991135196D91A550C04488F410F826C4AD33C8A 4E8E55979BFE9255BCE1B02F6DAF5518F9D8DCE48AF4B9FACCDAA82F2993948C D8CBF76340D4E9045452D5AE844B09EE98DE1E8F86C1D85AD7BCD2DD7DF7C9E9 15DE2E0BB61DB0B5307B6B6F47AB960EDF5ACD773AD737BA7F598F8746EE1313 95877CD8AD56EC56592ECA8A7D51CCD972DA813D14B5F53064432FC6F2829D3B 5357A0962F704F0E8E97169662C729D176D22A519BEBA6B7DFEB85E4AD28796E 7373A15A7B68BC7A280F3AA297A9A46F0B36467D103F2FC3D52058320B8F4FCF 8E457D4D190065436EEF0EB54D217672722DEB9D0F027889EBCD60DC8102630D 92682B1A4484C282A394697158B5C99863B879B620F0A241A78FCF7CF88F3FE5 CE9665C67555A9D44923CD84AA809A72A51C05960379E5EA325D193FA8084FD5 481AF5D2B0A9252D3FD8E7E702ADDFAA1E2B098322EE907EACC9C8B380636A76 C499C6C2444B8364F0CD5D71D9ED1BAEEB937CE6FBD3F1D4076E8FBABBC35673 FCF0546A0FB2C80372858895614FAA6E558302AD802D8C07C830FCBA7BE3F9B0 7B4590CCEC89A89FA51B5CD683416060AE33D891AA19462A8FE604EA970A1180 6DA72676796A28B3DFD138856A571FB5926AA3F1F1822627095D34AC316AE689 3FF5437CF96D8574C37EF54B6B87EE9A2D1E8722D065B10DC41188762CCDFD66 3673BAAA17BC3434C2D5F2E56F9EBD6D2EDFAA377A315DBE65D24CF9E5EF7986 3351BBB38D123F4BF3B1726141462A1310D4C3C29537EA53876B951384188929 1C902C29208C20D410C1FA7EEF0A5BBD6CAF0DC486B6BB6B8AAE2CD889E1CA78 837B71A13ADB4F72325A2A974BA6A9F141D91ADEB15CACD966109B6FEEB4661E 5C587AB7CBD965AC1FA05C9CF9AB8DDD6F5A52E61AE6FE8EE8EFC5B40E2A19B3 3277F4A4675687F7680B326B1D7BE7CCF15FB835CA6FA3949B78522355A986F5 38BC3820FABA32C832B4EC6663E60FAC7B46A6CE6A345AF09BB139224E6479C0 BF13BDFCBB9786BE3BB4E370C8F7FAC686A503E31C8B8676423D6AFA8666A76A 224B8DB869F03CA42EB41ACB4F5A79371336898BB5ECC0B1AA603D9034839D74 7F2709C35CAAE5FC24CAB4A864C8B9BC5D20B065FDD414A446ADAACD4C01EC2C 3480E900A9484C62C7CEF2DB4011FED1F1F98447A9720C55E2032A9709C5516A 6542270A06C6BE40839523CB73EF5549423B2FB55FFB76D730E71AC97027E86D 47A803859BC14AB440BF1894DF6638394D2F55D37BDF93CF2F76B8007A980399 833550604066848A7AE050A2749F015377D69EF5FBEDF8F8BF3FE43CE06ACC96 00AA81F6E41FBFBEFEAD3874D0C5ACB11AE477405A293327C310CA0413702061 99BA4F5049A048AA201999A3C9315AB883B0159D46AC39FF63B3F7FCC2EDB41E 7DF7379F0FCED96D03AF67FDA6EFB7B01D6375B09843B4A23AC7B26696F40982 FD302BD951C35A70A94533B978ED911F7BBBB0EA22DC199DA2BA48A8AC0DC919 14B0440210BA62C3DD39D703DE1B62DACD801BCB01073211C3DB37998E29C865 80C66418033FD0611924710C3F6D9BA6AE1B5CE183020E20CA4C678CD2388E3D 9E461843FD50650361D50333727542CA158DA85426E53E336AF6565EE796BA72 C5C06BE30A62331A5EA268CE30615FCD2FE7E7EFA0D2DACF897C14E45E7FAEB1 371CBCFD37EE2F3F2463BE070FD2308AFE56E5C5FFFC92D84C27170B47FFE430 2B8B44C40C80D09A9534176B0424AF0E22980271F293F625C45759584D6D1FC7 B4F1CFCDF0D900A85557886680778308D8BBAB3BBA46826CA87313BE38D07235 B7E0873D156A97F679E298E694E94E6156C24029D2D6D8E6DB7FFEB47DFF74DB 6C1580917EB5517FEEC2E2C172D8EA6A5DC3181FBF166EE68498AC4EF631F73A CD996299C35A8C79C1CA6FEFEDCDFEF003F1C32B61E017421B73F3C64BE79FF8 EC53BDFD1E61A5AB1D7FD7342EF4877BFD6014B603E0454CDD70894E856449C8 6AD6C1901C122E5A706D37397CA57562FCE867F7CFEDE9DEA7E70F9F48C9AE9D 113D2640CA94F38C3A3C9084AA26338975A2AB8333D57C0D888CB561B26FFAF0 0B9AEBE16BC4FDD260F3B189F19FB20A653510E5E0EBC985EEE0B7F96AEBA0F1 D3D32B2783C2572FEF5E36F101872F6A9E27493FB3A50722DB8F613B16A65C9A CB136C0643534672A2F8C4EECE7ADBBB6F7A7A2E6A1EAC999315A838F65B8D9D 85F9B9A34DC9B6A30D913C93E32F6F6FAE60F791B9C5B203C25BA83DAE816AA1 9CA7E786BCD30ECF127E39ED7DF4D6630F40F5F1EA9D3472229766D53752F4BD A8BB11798382114459C74B34E674C3B0150E3C007BF8A2506D559A816138482F 9A73822F99CE6CCEFEE8A77F7AF97DF734C356295FC02A9465749E083B528DD3 DF6CC11CFD3B481A6DF4232A4A1336769AC50362F1B4B39D443DB3D3DB3F7BC3 36DDC2D1C92CE9A1815ADAB123618D9ABE6AA10F640422287E79B8F76C27E579 3BB090F4FA13EDA5F71D1652AEBDBABAB8B2602E6B43DC3424EC284BA54929BF 2535CAADCE5714AA49CBA8FAD7F199AFAEA77E5150DA83AA25B27A38EC93CC1B 5D67E9D820AAAB1E648FCAA09723F318A24E5AA8547102D9CDD8DE9B26BF0AF1 B3242FB319DD3860DA258D964CFFF0479CB13B71B69B7BE1F317668E8DCFDF0F 38DE05112263758F936AEEFA7658B973AC3C07FC24A6CDA98B5FBC30CE58B3B5 EBD6AAB5C962D2F12EBF525F3E7CAB31D7062690498BE34C4F0853CD8140058A 175FDF9B3B365EBB9D662C618991291D0F759A3A4C4BAED7F757C995EBF6B62F 9B5AE75ADC69A47611E5AB710432CC9A984B501C34D61DAC556C581D68CC09EE 3B9C7765405975D3D7B668FB818F1FC5A5BDC472758DF65F174FFDF74B05B930 90F17638D8E4C9760A128D14856BF1305F90C701F77178CBDB266EFDF995B8B8 03955CD7263292CB1868D99B8396A04CB25184810240D5D77733366814FD9A29 6417F050D3541D4C1206B5A370E5B3572EBFB8AF31AB1FC21F8AB635D06A7141 C646A685888494D988DACAC88FDF4C9D83975CC0664D77276DCB213133860B87 4AF949E02731F1F59D9D786F575056EA07A11051C9D1C75C96836D9C265C46C2 0895E5F478257391CF62DD45693CD09185AAC74F7FF21BE8F70F8D8F3CA4957B 59A206D7E15F99A9D13C63799A158DCC42406FF0D2070A138BB9A0CD5FF9CA7E B49B9716BD11763693B4C1556C39D140F61187F1A33ACB13A35012F7BCB3505D 0942EE91CCCE624195CF2C5479654DA76C7603A6E6434D6BFB0559DFF66FFDA9 03B987ECD48097EB10649CFB87AB4FFFD92584DC35DEB92EF4ADC86F21E54488 22C432ED6622AD7A38F0773A3222D350CE488E60F34E622E1B2CD23B8B3F3E7D E7CF1CA50DF1D4AF3D1F5DB0DB2C03E6DBF6E37D66C79932672B22525676A3A8 21823ED2F48C8E73BC4C8D7987C227202B6B8F7EF431E13464B8874200424739 230010C544A5E9CAD80ADDC155AD7B5D798EF545D68CE20058A36E00A3F43D4F 803482BD89692F54F9C6881115FA14277110508218D3A13644F0A415DCA86742 543F104E6496A84E994C59376ADAF7FB41534D19B7AB7E4D9428552947664F59 8232A162B541CBF29A4A0A6573CC99C0D8A2836377D4AA4BF0DBF6199010E1BC F94273BBE73FFAEB276B8FB224E8126612A8082F662FFFE1AADFF7EFFB89A313 BFBC9C2675D09C54CE207332A386724216986619052D3F6CF0E62A11BB4498A9 2549D7DAF8DC1ABDACFCC15B116F06A80B541CC81A50C7143E766460DBB65D85 EEAA3F5D1B44D16EECAFF6EBC860E3767E42C393C42C117D07ADDDF363B74EFD 9BE37D6B876905FC5270ED2B2FAF2C4EE0281EEE44D6D8780F4115EF4E4DCF80 4AE8EEEFD67279C3CDF57AC3925958BF7C75FEFD0FA4EF3E9E4119EB021BCA41 5958FBF2D5AFFDED9776D63B03EA6E6478B50F5F8EF3381D440970D542DE9DCC 57AAA68DF88013996F7BA74BD3D3D3D59DFE7ED20BD38CAEB6363E7AF7F14707 9C05F1DE443185E24AB045B0CE94225053A76A9E5257068B4405D90A1D495DD2 3E55A92AA1877BFCD966F76BBD5EB0DB7BEFD8E4E1995CAE52417D63B7113C93 B69F1E6EDCBE17FCDB8327BEA727AF22FF1D63E34722BF9186BB94D18E60C360 A00532670D048D3A41D9D0F28B534F6D6D5EA90FEE3C78EC1431DE679B256D70 A3A67DB3BB034FF31D8BC74977E8737C1D6BAF34D7AD28FAE82D07E7B1344CE4 C3D6561D96167CD6204EFAA2842FB45F2BD2BF959BC76DFB9395A5A218EC040D DAE0453476D6A45FF2EA37FAFD6CA2624B7BE0674921FFDACE7A2BF090B2C752 17D433A6EB024BD3391FB3EE0CF854CEBEF3C4918FFCFEAF6A554D98C8C49872 75957DB3E944792E9394A8D13C78295C1BF9297DDF1F1E81384C30EC1F166B5A 1475EAC4BF417792ADD71B1347AAB412C81096BCC9694A83847958B3F421902A 6AB14DB2FBC416DAD1D9309FD0B855DAACDE57AE4ECFBDF285D727DDE2C1F71D E8D69A20D58DBE0AF904A584552E9CBA6803869A6611011516B9BB6FA14B2F0D 192E0449D81250B2FC6696B6A58C32A9C34B5687BACACB498E4E5C46B1720036 A3286C35C0ACFC3AD0A8C346D59E1444999CB3AC03A69317B896EF9FFCE919B6 E0D166FE857F385F3C5038FC5035113D5D501E014905F6EFAE6D75DD23F33347 2CA0A1563076F58B7B728FEB4638BE5C0588ED6C0F86757FE5F84A60B4B49185 0640B9CE35049523A3C2CFDFB8D89E3C5C2A1CC11A4D9834548F81A52548CBA7 A0FBBAF51BECDAA6536F734F74D793C1566A30668D4951CE743B5FED9B3C0AEA 8137747061D22CCDBAD189F9ACAA0704153A59F1427F67E1E1EAE2E9C9216B30 CACCA8F2F25F5E6CBE9C3AD9E4BE1F5C15BD1BC2F732C021C74AE2924D8E1A2A CA6AF1DED2895F5ECAC6F6B04A3CAA0167D474A2A94E0BD56C84D5AD2BBD39DB 26470DB9A3A1CC510352AAFCB284E0A9BA16D6280F101A0F9F1D3CF3672F91B6 11317D43261B61E8F314E8B7A96B02749CC6407D9952393D53952E0932191E01 99768AD38E53D6252383DA349B5C2C093930A5E6F7EDDDADA8DD0D09757C3FB6 1D83616152656E61A86AE4AB6C5844A7966B598187B8EB5A2A5288976E7DE4D7 BF83FEF8C8AC6A27D5A0EA8D6487B234D0B948692ACB2A6784950077A2C4381A DEF3A13B048EDEFCDAF5F61BF0C54A0D9AAC89612309A0B4A86619AE9558768B C1CACCB49DE0CE47F3D32770C83B12BE02D780CF809CE15260A931A192FC22EA 279435CFD2DD6BDEF19F3A987B9BCD99C5321B33EA5F8A3FFFBB4FF91B1A50C3 55915C4FFC6D35666066B19A54516B858DF2A694FB235637D90857DDEC08C3C7 357D56635A3E3CF96B47E63F38A6ED64DFFAC433E2B2D535D01AEF3786D18E6E A9B02F999608AB216252D415C110905F6395942C223A090C0167F6E19D477EF2 6DA95B4FA306F581B2EB598A01CE476F90A559428756FD6C10B474814827E68D 30883121A60980D7EF76E1556315FE67045C0609E059A2FC50111651980AAE26 40300A782C47FD3211176A9451C59F2901A30CFBB411BB56A91437AF2C942D7E A674A1D28BA95A0E32468150A95DB623F814130B863143F3AE96542BDE895355 AB80630E6C414D18BEF17C7DBD3D38FDC9BB271ED681164171D18879FD73D72F 7FAE2DF3E9DBFFCB5DF89E3C923D0D281A3B80584D3516332B494D159083FA59 7B23EB6C2119A8219DD4E457F08DBFBC56EAE7412BB5056F79C427A607CB2B8E 553C3556A2C0D04D06DB99A70EB5004F7A38BBD26BF492C090684CC3736EBE62 D8A1DC9F7F64FE965F3C15BA3B94E5D81A3BFB774FCD5A769998EDBDA1592C63 03797BF5CAD48428D14EA7A16BA854AB75FAC3823486FB4DFB9E65FAC1534319 E5A58D9D522FE0B9BDDCF62B97FEE97F7EE5D25E770F9B7BA14ABB838AA86656 6926D2147B311359B190E56A13E31ABA37430724BD92CABFDF5D033EFC89A583 1FB07249AF1399D429E535771CAB43F7543384A4428C8A214807D88F2A85D4A0 09D502CC4B694D86404B39275124D095CDF8C9F36B3B5EFBD6C313EB8D0DBF58 1CD3ABEF32A690E93CF7D4933553970F1CFCD685B31F9ABCE511C3C2A43F2092 F11C8DB4844400A7A96952CC86FD6E501AFB6E27FCC6C5B55BE70FBD472F1FDB 6AE3BCF6ADE9F89F56AFFCD4E489E53DF1A6D5399327F5C1F0C810FDE4EDC7AB 2608D08ECA740085431C8C8D28153E1732708D0BAD574DF9F952BFBFB5FFCB95 956385521B0571DFD34374838A9745AF4DE4456F389B9FC968E1A5EDAD6BD120 3355DF9E85B48A6E4D183914C7F664B1A1790F6A9A6EE08FFFDACF9FF8F0DB84 954659ACA7999A1E1C39B5007DCEB00A71D5D5D1BE32D7072054A7FB37275F95 86068014A0056D53F90F8BF659DBCBDA671AA908C757DCC48882303233D38853 58DA9A612504D85E640646E3895D72064A506D608896B53673EF5879666AFDF5 BD68CF9B3939A39FD043DA3633CC2293A482A8A041C9353DC90CAA6B326E9850 6F7AD5B7BEDD6EAF6B8E5E0879BCED7BDB32696B2A805AA83B1620D46A1C4B6D B491490754EF301B252DA29191C74DBB63F505E09B0857CA59D35A301D37D16A 95C6E99F3BC22B0DBD5D38F3B5556BDC58393DCD4557D9ADA81E047818E67E63 E857AA87EFA9A5648B46C5F52FF56F3CB7BD74C099BFB518046CF3E2A068D3C9 03964722353E28940D0A151A8EA1D2E961CFDA59EF4D1C2CB9CB998A179386EA 1A743127593EE1C99AB77D8D6C6F395E37E3C9B06568E785EC495EA6D2965AE8 7189626C02A3A1055C9C66B93933393E874AEAA21B25B8B41979BB72F7D11F7E 80DC3A805F4A89E35FCFBEF2074FD782E538B356B3C12A1FD6950F956101DBB6 F4139A07246DEC28BDEF5767C8420FAB81FA62A6DC6B88EAC5C6BA328E54E626 E40786E66A2C13DD8C0780259272B550A0F882CE048EC00110881C3AAFFFD18B FC759E5AB9EB59BF1D278D9EEC67821909CD529ED92AED30E5B6CE00D3521515 9952894AD49AB1ED9A8E4DE239F9F4C0D1292B2F44B88FD3C9618FACDFD8CD52 432446AC225D438AA5ABBB256ABB3465286A41CD051672A864D7B4286E588E33 740F3CF2E967D1676F5D4C441CF1048FCE008094484C130D41B575099964FAAC 6ED9619A9476A74F4E1F7A60BE7175E3F2D7F7447F6240F0B6D6DC4B924668F8 191465015AF0162009B6C9E8E0F8BDF6F27D8540B6546B67A2FC09D5553A2044 8AA82024B638F16228A617ECF58BBD3BFFDDE1FCE36E022A2A203A20882C7EF3 0F9FBBFCD53D8B55D6A4773509000E078AA6322694A39A52E254515024945335 CD70CDD196497C8298F3A49895BC53BF79CBC4BB0AA8613CF94BDFE5978D8189 3684B7DF8DD74C43A84BF2D4CDB46AA6D938F3258FE0BF477A25A38BBA3D6560 2BCBACE5ED873FF6B028ECCBA845038C3C5D9D6FC3A351E7AA1464A86CE3FDB3 5E1AE5E30C7793A413C7911A4C026107AC182A901C46518A18D6AD289161E433 95EEC6887A02895A231447321D721EDD3C3FC2C03A4646DE1867781403AA8D62 98464E326A5212B62251FED02A3E58D9804A8E87A0510CE996A436678A694C6A 24A76BDE811579F8365BE1A774180D91B4CEBCA0E2B71EF9E47D9507492C03A6 5924745FF96FAF349F938BEF9C39FAABE3BD3CB6341F0B83B947355A92A9071A 566805A0C22CDDCD9A97919A8940B103B4AD1C3C9FEE7F61BB228B018ABB42B6 877820694CE15B01C8A6B0328728861DEA60E612A6582261C23436071DA95C66 23168BAAAEBB3A6867EE1E73EFFE2F8F65A56D7578E2972F7FF15563BBB790AF B63B4344F492E50C9A5DBBE8A271CB0FFBA1EF5527274061BB31891B5D7AFB9C F363A7039C5829707FB6E725BD57F76F3C7F71F3CD9DABBBFDEB315A1B84835E CC03352E1453454E8165EB9A366152A0EB0FB9B98F5A3544F5AFA2E8B9F5F59F 5F3EFCA3B68B878D386FD8F99C93693A2BA62AAE9D0BC653A65AB9558EAB22A6 407574AA14BCEA905357718344E4B5680E519BD849EDE27EFA8533AF4E148DC5 BC5BF7FA837E6F25C8F274BC5329BDBC79E981A583F56B5BCFAF6DBCE381A3A7 58581E0C12A31813CBD438E543A2EC8462452178F98936FEDF36576B0BE50F99 E5E5903EEF35CEEAA139F0DF979BAF0D934E3ED92BE9B542F1DE5CADAA2509F5 352B55F3E29941A433ECF2FDD6B013C52D219D4E7C8326E7A6F59D66F358681F 300ABE897D28A8AA2359F6781893EC0DD18BA05CE4AABB425EEFB79238722D32 67DB344C0A56DE023DC0036AD0C5A83D7774F967FEF03395A3D391F21D93C013 9824DFB769012024326119E34A24A211102A4DA5CE1BD59591BAFC4E8105AAAB 6DD5373654048BB6C3C6B92DB7EAEAF3284A0756642A1FE73840D844CCF2D140 A7CC7BBA2B9FF2ACA8DC3092BAB677FCD4B235976BB65AE980B6B6DA471E3B12 CD3487B4950B8A40F4C8C82F2AC284C36E242ADF55C520A666B0937BFD5B8DA4 E1E6A9D610623B159B71D4D3846A600792A4860AD5CDFE28A557C50825203DBE 3F6A8F7E10083A0AC6CEA48BD0ACE9CCEA660E807062EFDE8FAFC8725FEFE52F 7EE73A29E8871E9CE3BC4B406F4071021449739D8EBF4BE96D8F1CCCD80E4EEC 9DAF8797BEB97AD75D938539B9BF8FF7AFA6CB4B4577623084C7C2F591751455 868D1C9EADD3DA4DEB7B839923D5FCB21ACAD00005A04A147401BBCA17DA5AB8 F656B2B769C531F5707231EE9F4BA2886A391155818C82848C7BFD48E472A531 5A982574C610470FB896190091A6961B23E3FCC69A55CE1FFBF8B45970135BFD F0EB7F7DBEFE9D806613FB28BE9E0CD7A2644075A6A56396F1800C2C39969BCF 1EFA54CD5C19625946D2CD4C9EE9046BA58C9A48752001C461EDFBB60464741E A0FE92F0A4E568224C8E2C40609547598B8696596EFFCDE6DEDFEE44426F1861 374EF606A4A96A6964C8241566AC6129626507CD54B2A1B21691C8D1E8A29B9F 34689EC6191ACC2E5767975C9EAECB642C4B9C4EB3B7BFD5CB4431CD8C613280 A2A7676E85E62B3AE8090FB896662421F12BB3F6D8940D85CB2B2E3CFCE9A7D1 678F2DC2070C7938727806E99FAA6B2ACA54D2124F6BBA3167E4CAA07EF59DD8 25C7DEB1589B4ECFFCEBB9C1F5292E9CA6D680F5B4E141F9838F1E9AC83E8CF0 ACEBE0AC7DF836EBD8C3133E6D64F0EE4269401552B7E6F03830E30447262743 CEB4C625FBCAEB9DFB3E762CFF43796E1B22A28011CC295EFAC2FAD3FFFB1BB9 B85A47C9C5C4BB9426FBCAD4C1A4001ADAC8C249DD39482D01660172531BB7D9 21DDBB9DB933B8A255BC7BFFF391CAA31669E79FFAA5EFC6E7F140D736D3A0D1 89AE9A500F15903832AB685A8140E911D1C86DADA0B105CB99B1982D33736EF7 918FDF2F8ABB3C6AEB3ED53C50FC008429127A1A293B27D124AD8BA057ABDD30 6A78FE10B88AF20F517B0F584892897E04920C249BADC6D734D55DC1B01A2607 2AC405EC57D48FA27E1287D9C8502923894C6F264C648A61ABFFA53737618638 4F01B9112118905485FA028802E7F5E0A79CCCAEA6DAA285C7355C326C847BC7 EF36E79668E40B03573169535978F9C5BD8DAEFFF8AF3CE4DC9F0ED3469E4ECA F3E8A9FFF6623A70EEFD0FC70BEF0983D4D2339FA2A2340F7362594026635805 05A946BAD664F3228E229439037BABD89FEA7F2D683DD92A19F981E60F32D4EC 653EEC760798531279B143739E9DFABEA7A29281630A4DA7BA3282C3C476ECC0 1B6622CE5906A55A2536FC4A70C7A7EF2A9C6459D841FA54FBA59DEE3397970B 939D613F0C9229AB9C78516A627DDC48B264D0EB9627C77B5164868806B13C32 6E7EE8DEC4D02CE5C90F9BC62575F2C63F7EE7857F797EB7C7D7B179A51FA429 E343917031CCA0A8509BE9A91F9768696C227D8CEA0FD389CB49F89DE1E629A7 F853F64C5E243BA4A5E55959776502D276A8AE1725EC6935E89DA9E402143360 AACAB099A94E3B66657A52D2F4A1A277DE24A1F339C72C4603F6AD6FBF186CED 3D7E68C5B198AF797597B757FD73A5D2A594BF4DE65748F1BFBEF45CE560E557 0F4ECFD51B91E986BAC507FD5804507A63A0B02069D2892FECF4FEDFEE8DD971 FCCE423E10F29A9B633DFE7EB75666DCCDB323A0DAE28816685024432D712C3B 4BB1AD3BC950EEECF4B77AF1BE2FDA61D236791C45B1818626AC2B6C7ADC8E51 A46B3D4BA5A014435C5036C1EC5AAE73BDEDFB664ECB972FAFDF2816EC02C99C 98171D07E7EC6630704576205729C9FAFD1F78C7477EE7136991C429C86C353F AD0CC940728CD26D339C09AAFE0168814777842A4F6CE465360A99CE8414CA34 49D9AF499A0659B2933636C46AAFB3D3CB1D2A9825AE872AC78243B9E3CA6933 4643285BE2155F7CBD83016B5CDC4BFDE5A549E7167B27DBA856966E7C637BA2 502CBDCB69E437CDD0B58546542A2CE254A4CA4888D2940A396016A769A579C6 3CFF74DB1D88C0301B88AEFBC15E1A0E650C1540CD2A2BC718A282B3D529934A D553FD12A3B837E502A2C679D59684B550A464DAB467A991E3746C69E7B60F2D 18E309E9BA17BFBD9AE5C92D0F2E4BD1C7899A0A06383371B9D719DE48A23BDE 7332D340B2D8BB4FF637BFBB71F75DD399E3ADAD2728185B58B039BDCE6DAA71 53E579609A25B19102852CECAE058D5677F1C46471D98C88CAF566BACEAA6E9A 00F407724D00106E6FD19E465645FF4216DDF03C78B74B84AE142B2CD336E256 AB27F26E655A370F9AB886E2A5B98AE166CC8E651A20CD90327F6DADAEDDA3DD F5E8ED7135882D8177E8B3FFFDACD8A8A4C86AF0D66AD8DB06504A5145D7EF26 7E215D72A6C423BF5EB16F1942F5D360F799DEE822BD96110B36BC6A4C6337C7 DB6EC69E67238AA41680AAB2F05A405264CA1E051851D78E2321C7DED0D7FFC7 6AF3861F985A87F3DD58DF5323A55C6572204016AD1FC01A4F74AC4C6211E8A4 0C81CA5D708B63048DDB0093BDF298BD72BCAAD99B5150C099CD8364E77A3B68 41B17539E1B126420F99D2A8D9BA4962E048B9A29DA816E4D6D47C293F99EF16 261FFACCB7D09F1E59569EDF800EEAB20A962EBC41C02B2D569D199A8B4895D9 15D399348350A0CA217AE4EDEEDE8D9D734FF01C9FEF259D06469707A82EBC54 8F08B10F0B3AEDE8393DA8D49293EF5ED28ABD942538513DB12369C33535A84D 69A46724F4A4EFED8C5D7AAD73FCDD0BB50FD644C9105C47D2335C1A5E37BEFC 5BCF4697529FB11B925FD1C47A9C80CE1FFDE7CAFE2105B6414689D18906E47C DC20872DEF18CB4FA372561D3CFC0727720F50D2CC3FF32BCF0567B86FB06D19 35BAE1251D3E0D941B69C9ACA4A1829AA64D634D0D583A1A0196B1E858391004 937BA77FFCF674B293F84DC3D3718446D3FC485376EAC444C5EE6AD0BE0A75DA 0D65D608825E021F42457E409D542DB8140FA1022552DDB469CC465A29E70027 A2B0C984A0A6DEF3BD408A012C6CC3F085EC47AAF48689728E27B079B18A7E50 E08C47043723F0269446C48A9302C18EE009100188EA0ABCE4E667A81A9A7174 4DB7BB27EE2FBB85040903A516A62D26C75F7E1956C5E0839F7C877E4F30203B 45E3E8CE5F6CBDF6F7579CF9C2FDBF7ED43CDEC9926A9A74091BCFE0ED592EC9 FA0CFE4C5ED450E235CFB070D3D068CC9DD8D9C9EF4DD5FFB6E5BDE999840A3B EB2469A3CD536232C7E228F287315673B609D1095287F12196996558163165A4 46B654D3974E5CD784D736EE3975A3B9F88B4B73EF1C97BC8DF3E3E195B0F995 B7A6512E20B25B6FCDE66778CFF719CF4D3B1A927EBF6F978BEA7EA93E0491E6 DE7B107DF09E484BA03C20EA04C4B07A06BEE1EDBFB8FEB97FF8DA4BED5ED3CE 6DEEF7F830A1198B473D8B20E5A230165A6E49F44E2F8D95CBC5AD37AE3F3E39 FD58B9540D42AADB898C025B19A1A57E36301B5C50C5AEB9692187019BCB9248 E73C97C54C9DF300F2EB31EA54E34956CE0514767D6EA66896DD2C91175EBEEC 6FED1F9B1FB36B2470B50EE8FBABBD979DC25F3476A8177DF8B6DB5064DB31BE 251D4E33D11A7AA9204992744CD2B1DD3425BDE170175BCF6F6F5768F2AE31C3 4D06C69DB75FF4925A23784F759CDAC0DBE2DC56D72422A9A05E45C756CE8C4D 11925E2F0631BD36F0D731DA1600FAB04642BF60FA1AA8619C4B2953ADEC02B3 14E4FF400255B2723E2BC4CCAF78DB5C3BD7EA47C0EA41E81854E7C178211F61 79A55F8F8976D82D1E446EC9EEFEF0AFFCCCFD3FFD612FEADA8621C290315DCD FD6450B9B5EF9F80619402ED5131B642DD148EFC3B7E1032ADB45A365AC80A34 458CA99F76D7D1E67EFB5A83D9767E1C2020845A1FC52AE181028E00E7D44D7D 07797F775DB4B4A8E0F4C3E4C0ECB8718C5CA3E70EDC76CAFB6EB2FDDCEAF4DB 4AF6BD66042F2CE006B19411BD01CC33C28905BB2001CA68F70C6492FEFCB567 7B83979AA1EE7624DB0AF91E0FBA328889423F654FAD387BAA82B1091AE5816B DFF7D91E65848EBAB8951EC91132A59B002DC5944E1C6DDCFE8145E1F4CC61E9 CD6F9E4325F3E8E9C3B1DF6469A8C2F924D371917BD955BF79EBE3770BD164B4 D078B6BDF9D4A5BBEE381A63EFDAD5CE4465A95CE4A9B1EF2B1F723B834A0044 5FC02A634652DABCD6EF86FDC53BA6727306A870AE212094A46089A0CFDA89B6 4D2EBED2BFBE957408BD18F6D6B4149ECFBCE9DEEAE60A7EE4F50757989708B3 68171773CEB29D15D2687AB296B2C8B0231599C035C798EA0DC8455ABFFDC145 F776D6B29A26327BCFC667FFBA554AC60C235C8FEBE702AD1110008205AB5345 878D4AF4C02FE52BA740F35B5966486BA8DA2FE5780A2F8DA574142C908D9211 D4B9A86293EA822753137A6ABA46896BA95AA810D78624802552DC2BB5FEE75A E785A624E62E4F6EF074B50F8428B340D0E998948B11D4DDC180C3B220EA602D 1BB523D4289DB6CC31860C2DCAB9F4C0AD656BBA1D0446CCA54D2CBF1E35AF85 DC5769C03196431FB88C91B79841B88D7CF850E333D34132680F76A75666F9E2 C1D3BFF555F42787E601D2639082502E541BB4A6DCC33380AC91DD356006C679 CB5D02A4CFCCD4EC1E79A75159C8BFFAF5DDC1798364768366D762B1CBC30027 5CC74B213D50C8955944F5DE3D8F1F2C2CF104F7350E85138050357FA8052529 89754DF3054B87F5EAF9573A07EF1D9B7E6F552E1484B4287C50969068E2B5FF 71E1C23F5DD3B2C27A1A5F49D335CEFB1A919A1A1B540380AAF946B9660322B0 144D1BC64173702B73A750154D7AA7FFEB6DC649A4B7F22FFCC60BBD1782D871 7645D4E80D2EC0EAD290AF5CAAB53226056D94D509EB8EA72CCD664DFB50A130 A61BB4BC7FFF8F1FCBE63A49D03106188030E25C69BB98E098325EAC9FEB0D36 826162085D6F43150B558B9889A9AE220ED56F98A8E32096F8CA34B062E93978 A5EAC238A304504DEB45A12FD3811009A36186FA2006308E450CAF6B847923FE 3C6A3A1E312B05FDE928507B44A74193180A63E3A466B019A64F310BA42DC1C3 A965B4744B4EF93782E696F059DA59507BF5B57A47CAB7FFEC7DF45410D32DA7 3D7FFE4F76AFBFB23FF3EEDA6D3F3DA7E5F6A918976988CCC9D459E1A689D296 A9BA90721A0F82D619CAF731D2E32CA7D31EB956DDFBEBED6C1796229463DE8A C400CAA4B295A6294983304E3D364C07CCC4A66EF04C864220F8ACD480456F60 22A208B678C955063B135E7EDF6E577F62FCE0070EA4B8231C17D5C9F53F7FF6 00ABC4A656DFDA3B503B28FA7E2BF3CA8B2592C9A0DDCA95AAF0B4BDB53A4E45 EEE1A3D9074F063271628A683EA44CDB16AFFEF537E255AF3B40DFBEB1712DC3 CD9087BD6434A4A9F992C71827207491B12CC9E1DB16AE772E3DCE8D4FEA0B93 0CB7414D60C43CBC87D16E16A581DF40C910EB5D6C0DB821135CCA8C126CE8A4 C7919741F1A7088A88898D8E012F0E78359923A5292797B23851D3418C0FC289 83C5FC0268699F79967F6EEF494C3F170FE264F870CE9CF09C596B166A7528BB C4A4B94C591FDF48F8BA072A5FFBFF987A0F60CB92B34C30FDF1D73EEFCAFBAE 5275B5F72DB5A49607212184194130046207378819D8DD89985D860566779960 2016CD32C20C6218564220346AF916ED5B5D6DABCBFBF7EAF97BDFF5C7E7C9CC B399B79A882955AB3AA2DFAB77EE3927FFEFFB32FFFFFB46426DDB60F75CE3D3 F3D3F7229192F21C26E76EAD1E72EC8776EFC9D65B9D61A4A6A8312176B047A9 05BD2482B7B6C32B9B3BCBA3C110C394A0BED4928A4C0A7299C89BB92C53DC14 ACE1FB9E4F0298C16428B4BAF52C95884ACEB40E492DF7CCDA663713F3CDC90A 042E2C5399AE64C391267D357F1FF517386ACE64BFF0DBFFEB9EC7EFC9786221 020B2D4F5081C6C945E6B0706CCAA265A0B1B1D1D55C20F3226B2014065A4CF0 B81C473EFCD3FC3A2924D714790893EDF8D272EF4A7B71CF5C399573C8955E65 454261A1918C330FC74CFDEDD5D1F524F56A592A76ED6EB27DD94A7D657ADF7E A735B9FABDAB80658B8FEDC967B93906261894B9349ED518725BBFBA1CC6058B 50A945F44CBC9C2D7FA537CCC020B7B95D5B8F473B2AEE151137AB4D5758625A 514081880CF473C7FF945038B66193E3D4F8528900EA12EC2C596E55D0A9933B A73EBE3F675D6B10BCF6D4DB64CA39F1F8913CD4AC46578B5C2F081BD4F39EDC 84F18127EE32275256D07E697DF5E96B77DFF55038E8AE77BABB16672D3B5138 8AB41484161DEF254BC589A20E9FBA767153D86AE964D39963237D61BE5569D4 25C372D4A71B69BCACDE7C63B0B299250A6E44C948239289956575E3CE676EFB 1A28132E2C42661CBAC74633169E9B6920A6CB71CCB0E639D07126328EF4ADD5 0F77EE8307C47C51B809ED56DFFAFC8A3C83F7D7DC8E1CBD1DE16B1DAEDF97C9 E9B456EC566C70EA336CCFFB02006C406C610D74E921AA21A1AB9786310F43CC 2408980DD2F16F35DE1FBD1D10605C0F4569066E345BD2322FD4E068E793E17F 5FDFF9DA32E5F516451755B69E97BCC092E78A0F53130F629835302105D48442 CB9294AA8AC89C06428BB840040CCEEE71A64EC85CD1ACE058429AB0FECD386E 1748BF67080D4C25625AE6232826A0AECDD276D9FCE2ECCE6023C2DC39F5C093 FFEE1BF03FEC9DD73F28D3B55BDF7DAC0BB90991378654140362FA48F507B15C F76041265820E1C0D9179EF8E0C1783D79F3AB6BB65CEC01B109D3D528EFCA32 F68ADDB9B3645B4DC63D9A9D7C6CD7CC09D0CBD72CEC91822269CCA595C4C67A BBB0B5F28354F47726CE9EEE2C1EAAECFDE8143EB5A859AC0D8BA21CEA67D77F 2EF987DFFD16099B3B005C4DF9B2505B4215188FCFACF58D34737966A34A95B6 420B84ED65833B586D0A04F63EFEF06F1F47274B3B9CB8F45BAF2F7F638B5BF5 4D990EA2E139C41200C271D05F8050C3E44EC0F1B88F805C4E2074C0F5165C9F FA9DFB3F73801E888A74E88404662217E6141E66A5A5B5EC20587DB3530EC1A8 302AB89DE7C34258CCD64048C68D4DB90622C72288F090DB26D38300A51F8979 6128B3C2340D8B22924A7F57A8CC566BCC0B05B1867661FA7C8551E226234D3F 36A308C7B9C4E5580EC2DBBD6D943A9AB9509E2DF86C12E139AFA661883AFD77 DD37EB350C392FF41BA1E529EAF3A156846B21510FFFCC5D8D2734687593D3E4 07FF7125CACB87FED51D130F6A99DAC7A20134B9F017A5B3AF2044C91D1B4024 6C90F4A2DE79A206B07414A93885C85E2C36FF61DB33569859AA5427E691C104 8B522234346A240FB1B1663457481123A11423933C688CE87DC735B9E56539EB B924E733B1D70E06E4A3DE9D3F7D9F7246B1530679E3EA7FFCDE020F609D6DAE 6DEEADEE1549BEADFAF55D4D1BC36CA7E3380176FDE8E67691A595F71E571FBF 3742B99F332D86136A557875E59BAF3EF5875F12857F75945DE1C57A94171CD8 C445C84A8DB566360823CDF3ABA8EE33D094A37F7DE7E22321A9162073410279 21D95A2857B9968745EECF9F696F9D8DE36D0073210281761376A85699B6A8CA 53A5BF143A601CB3D5AA8A014E1B7169CE542DE0626B024CC45951698A3B67AD BDBE37E0E4D25BEBCFD583BFDD5CFB28F57FCCF7AF668397F46A2EE89CAB514C 109E36A4A3892C2C46BED6F5CDD9B8D7BFB3E91F99C4966F6D40E7BB17AEAA22 7AEFBEF95D92F457D20C33B48F59F54A8DDA560AD77BE1D956E752BBB7998B84 1106B0278C63B4F259AF5FBC12F56E08739AC9348FD6FFB34AAD2117B0990B24 B6AEEAA90DA199E3B7835BFDD1F55EEFF0DCFC142261BB1D62D9F5495FA4735A 4CD8CE64490EDF37F1EB7FF0EF65C3D53086F978500C4341C67BA2C6AEBA3451 030A14C631B03483D563FC1B076B0AD32600C71C0FCAB1215429CC6EBA11DA25 EA8BE58BED17CE56BD8677743E063B4C695AAE79276699A56927062E7D6A79EB B5AEA49340143307AB6857B4167466F6CF33502F6E24CBCF5E5DDA35CFDE5B07 590E510C09D715849415D35262B2A41341CCB5B8164559DE7DB67AF9DC2D5934 4ADCD818856D39DA4AFB892E90FAE14132D6839944A25AB812AA779C668C5E34 3CB630A68EC24368C9F3972CAF2A7070AC7DCF27F716A4677583979F3AEF2DD9 1A08F9B0AF355249D238CFECB2D15F4976ECF4D807EF1360A097FFF6F3CBABDF BB79EF8927D757578595CE2F5A008CCC7907F0F48F611201632F9C12C59C6CEA DC5B2BD62CDD7DD704AAC3A12E9A9355BF59CFB9C877FAEEAD51EB9278FB6CD8 1B986DB6C204D87B424ACD46312B3DDF6214859A4611AE159A0F35998313142C 4D7BBEA7C1361D3F0B60BA323571C095D6CEC59977ED6A3C792276D799AED417 83737F7EB932D0B223B81E791D8543BEE5B8D914DC2DC160DFC7C0F11F9E31C1 88FAAFF63223D4CA9A4236A0267B49C1DB6179BAE091DB263E6367AC716AC2B8 335799AE197DA3B3DB2EED1A07E439BEF9DFAEC36E6D45CA37796FA3D0C5D6D7 60A4E4108A42EB08ACEB92FE6CA65746F12CB33071316A323AEFFB4D0C2B08BA 9562E911073B342E92222DAAB8966FF1F6D51DA83FBDE50FF33CD6C2CB481936 6F699150C0229B9B6F921AD90C3B5BFEEC4FFF9737E11F1E5A307B7E666C45AB 718DE8C074F5985D2C4A980658CD5B0576EC03D2AE21145830219DDDF756F71F 9879FDBB37A2F5BA16B711C96F0DD34D0EFB2E9F55955904A6A9AC30B5E778F5 C0C34E6EED801C5361697A589A3E15A30895D09F2C214844E9DC9957DAFAD9EC FFF04CE5894319A696991A0801F164CBFBFAFFF1D4E82D286CEF46648070998B D0B424E97F4C23B3D2E51B6B22875849E695DA6FA747AD4A4DB0E0B07CF4774E AA3B4A279D6AFDD1A5B7BE7831C3133B653E4AFBE74A1696606046214C73DC04 46BE693ED53A4C8B4DD900702FD177CAC156EFBECFECF54F68004C9C2106B928 446182E053E9A64EBE69DD3AD3F3A417216BC08B5BA361025025A8BB9842CEA5 892C97C82240962855755DBC899045AE1F61ADD2D034BA1BC62930477CDD34EB A669660C138CAD36D4FC5ADF7B29C6298BFA45C21812333F014C068CE94536A6 67C6854F43AC0FACAA52B30E9AB2EC0A653CDF99DB4B0EDE310188D63FA6FB57 63320349DA9B7EFD95D5D4491FFBC5FBBD53422F97E52FAEBDF1F79B33F7EE7E F873476473477F699132E43AB8B24BD105639A0B0616D47456CAFE4632BAC94C EF8E5EFB36DEC69B5FBA595C2899B1AC4F35911CE526BEAB34BE904C2BA130D3 B78B555C2D0FA53155223846AA97A7C33CD3BAC5716DD3315B14F3AE3B459DE9 985E07ABEA09E7FE5FFC80B4FA915F54CA89D69F9C76B7B83313EC6C7726CB26 A4743B6BFB73D5C0A2A2D7D7ABDDAA37F9663F198DDCC78FA14FDE975265A5FA F939B9EDBAA20A37E36FFDE1FF77FEF4D5B06037A37C231791301DFD428050C8 9EE0619A68C1EE13EF30F39F6C54EE0FD47EC61BC2D8D67700DA2CD28D240BED EAB62A9FED779687C355CD029D31AFD56554825DB6BF14D45CC814D7929941CC E68A785857294C2A49C1308A594905F3123F94A58393FB51F1EEC5F99E8B2F5E E97D93A9677B9B9F25933FEF05BD7DEE9FE63BEBDBE90F1FB863828E0888ABC0 A9DB734D15732ACFC76AF9AD4BEFD9B7182CB8373DEBD96BDBDBAB9D07679B0F 4F04E95A7B25A5C40B4E4ED94E738A17E5E556E7D5ADF6DB51D2C1FAC9E12981 2A121716BEA1E20D99DEEA49E396AB97F1780AD244C7D9B8CC332CE004217B3C 7BCF6C759CD268DB8EB7DE1F6C0EFB0DCF9BC3164C8B21832D566A2A315996F3 A89CF59D077EE29E9FF9AD7FA35F65E34F2D4D8365894B89C775CEC0A2993AD0 64BCA0DC4CF3298385665FD458079AE1FA774CCDCC4882D96DCC016726FF5C8B C418766E94D7AF6E5FD99CD87F18D672A836B53E973220A9CC8CB799CB5ED85A 7F669B8059088AC9636ED2EC8F26C4DCC97D51B8E3C37AFFFBED742DAE3D31E7 4E698AD6D60211080BCBAA117144ABB218404F5F2842210231E8DC71F9B94BC9 9625123F11B0C5A34D6EECA11245B4D2309D745A0CC3CC911575DB7666BC16C9 78A3CFF4812A7D5968C1721798A381901E6EDFF7893D25EBDA3BD557BF7BA97E B8BEFF9EB97C1853810A9A08C05DD0DC3A3FEAF8F9898FDDAF982E25B0F5E2DA F2B7D6EEDEFFEE95B5E5E61EEAD66225469A280A680C0A6C65CE69044AB12EC6 D1F49937AFD70FF97BEE9BCA68AE1A8E3D532516CD4645D90A9DD5B47D26B974 292DB8019E14FA3D4EBBD13057515075AB0E05795EEA958B736A8E492813A061 9593153955D772DE38888F8D5D33CD151CBB368A3A3BA33438B267F1470E66E4 A616B21BDFEB5EFAC615D10DB075B057169BF9755BAA59BC085134F9507EFF3F 3B54C218D80878A66B1F025F4B989202E37F654AB431FCBAED41319EADD76BE8 B68FEB78E6547323058488D17870C56CF8AEC873FFEF9B64ABB959E0B3C5E05A 186A8E013145625841D8278142BA62EBBA8799D937D6DF2E09862E82D3AE3B8B E98456A470B4F090579B66890C0B5E3AD0B339D9B9DA2ABAC8654D01D540643B 49A1903749990D848D789A74F6DCB19805F61BDDFCE7FFDB05F8C7C777E9226F 7C314D7CBAA530280A336BC7CC4741991099466242CCDC0C2D7D051984AC1E9D 7C6446AFB0579E592F23572B9DCD2859CEE43692155059F0D01C963E282777E3 934FD658334C43C1A48D4AAEF9A290FA5611CD096C33E5A375ECAEF36F0E787F FBE00716EA1F3E029A3514C650C6DC61844E9EFD8BD7CF7FF196E61A5B915C56 E86A2E7634BDA50C8D4F5F0DAF40A549375670499507BCE218AB68D1EA1DE28F FDEEDDC551E80F2BD15FADFEE03FBF5DE0F92EE2DD68EDB2F2FB4AF5014EB53E 13AA0E60808DFAD2B4486BF6298435D55ED03CC7494EFDE442ED6E2D82527B08 40C275A1CFCDD668E9E57E7C036E5D8C02E0B50BD9CBF86A14460ABA4E2520B6 6D280ECF405612D3A35805AC815D3AEE6E91AA6C34A67BC3789415B12A35D56D C749374922298CBBAF998A84C644CE9CD2C2B1D53D300672E615321DBC1A1ECD AE09187BB69A68506BD1B5A728ABEB8591F42B4D79F4CE89A031FE02D3A7A215 A6BEE7C56867E2E2E975D8148FFC2FF7F185A1D5F6DEF8DD1F6C6D8BFB7FF9E1 E68312B048C4269D9604155AD905CA690DB4050AA92E9C71CC7B3745DCB28985 4ADF58E5BDC4AFFEC3CDE97C2647514EF23CC289B486CC1C27DBC8CE78DE4B63 507A848280501F107DA19A91874057F73C4933470B418B94D23842CEBBDE5EE5 DE942BFC11E7CEFFE963056E4795AC26AB83BFBE08AF0FDC297F3088DCD475EA D5F66843EB048B40986546994D4CA7DBC37818068F1DC11FBF37B7A01D1A53AE C2F380B4EDD2DD7AEEE25FFECE9FAA980C38DA29D1CA703448B59A479D30EE6B 324F08E4E2BEF9853D02DEE354EF61E8A0066B1196C1748FB3EBED7687C15EB5 F1F28D8DAF663B686C50AAC6BB3B7AA133008DE7B12A5D805C0DA79AC75B7829 57AE8F2748AD5930BD86865AE5388E52D64E9C6A117298D12525AA0E0EBBE252 853E977616A1F59B870FF871FF4A603FBFBCFDF0F4F4076AD8038358008AEB20 8CE2A9DAF7E3FCCD8B571F39704062753649D687E95C863F343D3701E495EECE E53C9FB6BD9F98998BEACE0FDAEB2FB63A9B9C867625157C41C913C66B81BF45 B25779D22ECA7064C7669E9D980674E3F00B8CD7BCC621B7CA72352DF85D0776 719256131A61B095479D68B050AF5538484729AFFA6D257BDDEEA166E58E6685 8483477EE5FD9FFEA55FE0FAF59366134F4B0A65120EC0D83FD738C2E85FC6C5 9568B561C28DE0B85B70DC2F63A67ECC64219463D4345AAB34792E39A418E705 4A5A70706BF5F45B30238B27772BB89317D256955266A9CAB5E8A0E786EBDF5C F3B259A9F1ED00195576FC634DB4541915BD1A0CE096BBFADC55EAD3D98776C3 CA8083082AADDC7DAD1F10D3F533539C4193C2A95765568A89E886B8F4DD5B56 3CA9C9705764ED326BF1A29F83DC7C320384A24C306C1AE76733C46DFA8509B8 3D526F6A4580D01CB366895515C83E3ABAFBE30B9075F1BAFBF68B2B73A766EB 7B71194B563A390E05493D51DFB920FB8DFCE087EE94B4AFF161F8FAE8E297AE EEAAED972499D9EF013A042A29A1CD415DD73493F75E941C4504D8622BB87E6D 6BFACEDAFC5DB5B08C9DDD3378CAD177BA6867702D661BD9D66BF1FA0D694396 42B14CECB77A512F1A4E3874B15A6B6AE4D68491A20AC46E093C626B4565113E 51150B530E415A71234531A285790EC8214C0E7692D6A0587AE270F3513FB306 96A85CF8E6F295EFB4DC649E63B2A9B66086E660D334331E1EBDE7E78EE33A2F 355D61866200FD3E605B195F48098903C663E9E6D518C77C94EFFC3106C3F14C E938504E486E8C5C74FD666DFAFAE75FC9AFB06E64AD2175238D0AA6AF1AE222 B6F42391D0F8299B315EE242C24A40A9391FD3E5708259F3D89AD3AB11C68DBB E8FC5E5B8048289AA7B242EDA25784370A1051C7A3A1CA36BABC9F10CFB29A16 0E740D1583EA04F3F74F6FF88D0FFFFBEFC3CFBF6B49EAF76EDCADA44C7E88D9 0A0752AB1AA5158A30B1B1C61C74DA52814727A03F092A40EED48F15FB1F39F0 8367AFA7CB16CD59378F568A6239D55CC39DF7E102510DC2EC7A72F871565D12 3287960642904B2DFB1531B64B25F55456F234470BCBD765FBEA95E34FEEAAFD D0113CD744C30C8A94FB887AC1E8B5F095FFF3ECF6663F2CAC35C02E647C2DD7 AFABBE0D86E016633732829005F15EA50EF8A506C24A89ECFDE123BF73AF388A 83815D7C273EFD1F5E0DF9D48014DD70F972E9F765D9C33481A4E4DCD35848B1 A53FB596A179364DC961CB9D03C471C5BB7E62AA719F5E44FA9528CD70B27E68 25A41CBAB937D46FF64DE928AB5588A1285A5AA79AAE5EAA5F6A8F11CE93A44C 35D9D5E27D927993BAD0C164BCEDCC08733BC35873B07E2E7284DB49124B156A DA614059CA719F3640E3DC5D43470D7B22868D98F423AD144DFCD3F8557234C9 D08CDEA94C3387EA6B149D03C7EB0BFBED12A60A982C66A32035D12BD1CEBA77 F3F466F58075C76F1CE633C27949BDF67FBD51BB73CFC1CF9DC8EC6B448882EB 35EBE26A5D735C50D40DCCEA7B43A518B545F73AE411439E6635696B6BF4373D 7EB19C623321EA0A4BC8D80B0BDAB3F2B414545A8571D6CE941667B8F420AA18 F37DD32F319E76311192A3384A4D291401237395DA61E074E9567ABF77E49F7F 985BFDD01B35A41FFFDD757EB61DCC0461C251488246B53BDCAE041A8BB5F4E0 C32C0D66E6E2D630E90D279EB8137FE4CE0C2B2F25B074B96367D8B60B6671F7 A53FFEEAF35F7A3A1EC9C40D6E2471A750A980DBBD5157CB7A04E6A173DFDE45 BAB1F1D8E4DC4964EFCEB300F041C02E42B9DCE719F2DE4CA267069BAB846996 86C70456E87FF41B06B0958B3A00A79AE4F02EAFD610C8CD505BB677C0A81DD4 E0A46F59198E462CCD2CD1093501D034659226B18BE31CD314A041109CDDDE7A F7C4E4632589217DB5C86BD9E05F2C5516613644B42C5C5BE04B81FD85D6EA6A 273E39B970B3BDBDEDA33D8DE6C14E3CABE92DA43725F77D76C4724FD8CE32E8 BF325CBF0531C4334D515B9062D6EE36A74239590E6C676B87C43DB81DE16BBD E8A650DB5C50207C73FA5F4686F659F6784761EF42530B887D6D41F62CBCDEBE 298058AA54A87E8CD45A0D938D3002183C7074DF1E0B909DAD477FED239FFEE5 5FE04299217A44CCD83C2A0D83337EBDA5C066F79E4AFDFE1AA87D67DA604C58 0D9898AD5163C006C7D0A2BF40174C936DCC64A06B80149C77C2CB6F6467CECF 1F3A92371CC173CF1C7FF0D4F4B5B9785D6E7CF94AA557179605670A341D050F CF0D835C5F45905100BCCED9ADFCAD68E2812A3B80B524D56C4E2F03BDA4D478 121EE57CDCD7CAF40A1ED8FDC668F6E6775BFD0B192DABC3B2E800B925643B96 69A1A5B22ECC1A0853459BB7BBFC4D83EBD8907B6C1456625456099D65F61CA6 15CDE6EF48EEF9D80CB4BAF93572ED8DF6C1C7F6A8DA90A488C26A02FAC08A59 56E95DC0D952B1F8C4B1820E0961D19BE28DBF383343ABBB0E57ADA6A6069ACF A75AE314A0662C3B35B800AD5B47143A836BB0DD4A961E9EAA1DC426667AF78C D02AB7106A3D716F15C5FAE0E69B49BCE94C30A7958F5EE2F9F38350887CAFE3 EEB1AA0BD4C22A1906AA9A10DA971563ACA49C8AB2ED6466C2A51415E6B9949A 62EAA292001FD341056096342E0F07F31F3FE0DE5D4A3A52DB74ED1BADCDA7DB 04357B0CF7E26C525A3693F94CE7B19F3EEA2D6A45930933A4A2E90136D9E314 61220076C621F3F49DC6516596FFED6475D376325E5366DE9E17FA7D4845A6A9 87CB2756FEF65AFBC5611157D7B95A5769A7C83569F04B901579AC173F316EE7 44734CA9D51E61BA6223A17176C2B276537F4610574BE9BDC981E31E66B92CD9 28CE0852411924CB60B49A7B146630ED8664BD2551C0A66CBB026023C099683B BB0372F2C4BDBFF175F89F4FED965A9D161AA9CD705086A0B14133914366E359 BFDB637F11C0545FBFC48B95990555736492D4D78E7D74CF60506EBF2240970E E4F05699AF8CEC0C9A76F7050AA6B097A8F5BD0F81A3F74FE862C924C3A5C9DF 342CA234B9268E4859291338D3DE66D74EBF79E4B1F9E94F1D5733554BFF4CD3 3555941674FACDD3BFF7E6E5D39785AC6C21F75C9A2EE7792CC73E05B73BB221 A204DB10ED52C57EA73CCE9A7504E8BEE143BF7DAF3C4683D897AFA333BFF5FD 8DB6175139CA37CE17764FCA01B153CC445E38A2A822E4506CAC238B6C8ED0A3 AE3F07B185C5D11FAB4F3E0C65165B7D50A626B683EBB59D99ADD1EE5991AE6B 194AB6B81829D9112A35062F9068494E10A19A37E484695DA61A90CD5A81A2FA FB73DFABC4091FC43C83B49B168342F4F2AC2034CE332D35B3829B8E35831AE8 9DE0ECF276F341894C6FAC7E71C56D5F60FD2535C266195DB0EC49EC1669E437 E581934D2B30BE0940D1925A1C6AC257F8C05DB90236CF740E3D3637FDD989D4 CFFB7FDE5EFFF2C6A9CF3E4A7FD42BF8B21A15D46B2494D9D526B5A641EE995C 2B26202DB2EE5A3958213223CAA5DCEB5DBD3AF8AFC31A9F71B11BCAB6E92ECF 1BFDACECB12C511C99C814986B36AD68663206B9932BC71C3C6AD5A0B50EF16C 6F100D07459288D8A268BEDE3CA48543304AEF768FFCCCFB792D1B59DD06A8A9 AFDFEABFB23C31DFD4A528DFE1412D18C51DDF61B4E22A91B74683CAC242B233 8A7AC38527EF051F3891CBC2D7524759DC6619F1901930AAAA33DB5FF8D7BF3F DC8CB78B72B928D6D26C7B94271CE815CB013882E8FD274F95172F3CE2787B3C 7F06D85349B14386DFB187CBB88E06B567DBD7DFAC6462E413AD6D4C979B197D 35B1E5259A02E03DB3C1BF78FF9DA7F653CB1EA21907B4E5B95BEA1F5F1BB557 4A0A498ED248B60A35C02E561A7742CF75DD3ED9D9F15C3B2E7D5CBD31E47694 3CE4F982B0F3FA6FEEDCFCD985E064CD45AC9AF70B2F23AF58E22FD256398247 58F3D99D75BEBF760725F786224CC58DA011497A18D26034D0E4A42D5A3D9CE6 C104E2C1D1D4BF1F89237711F7492696CA3AAF800B505DE7A75BD16BADD17712 FE8F834116A554D3ABA22C997E4ED841361069D50114CA4F913DE7487476D49E 9DF427212318B7A2B4ABA935C01CABF980ED26621790F7FCC27B7FE6373E97E6 5C5704E32A8FC6417E72DCE0A54B9A19B585664B1CC4E3C8ECDBB622E3BC14BD DC812891699F31FD5E6AEC1CA851D7850988FC28C2C45138936B67C50B4F131C 88FD4721E216EF290B1B6E25301AD89B7F7536D80E941BA4415CD92BDCF7CC67 D320ED27BAD04307E62148BED6E3F351EDCE3A6A32331F687A2B589A0AA23FB1 3261A282BBAAF487F55BC168C65EA9BCF2A5B77DD8CC316BC97C5BC8AD50461C 8E4DA3B3422539698EC3D0C65152C0D8D442A341CC7FAF32B2E8980D642F07F6 E1F0EE1F9AD640185D44EB17C3234F1EE4F6264CB504F792B287BC02476EEB6D 484EE2E9870FE7B283210BDF1467FFFAE2DEC6E4D2098DA49A34D0B28CCDA92E A9092DB5D3C2C124945D06FDCD73591497C73F74002E269A68C1F9A63002B7E0 5707C19AECDC685D3B13C1E1C434725787DBDF1E0DCF63EC5874578917B03343 AD528571B598C96AAC5BD6986B6CF77C0E61383D197855568CB7A92D82B5101E E2A6E50F3C3E64A13F2A1AE7E8F6F1CF2CC1D95ED59E02372BFD2F5DB9716620 BD850DA1EFBD2424EF051B8FFEE491A9A3B4C4B960188D7D0835508D8150AA31 101AAA3426C163F987DEE97430CD32723C5B51A242930C2120C792A02858FFFA 4AEBB9014D9B1B51D1226035EA5808D7A0D5CFD3817EB530301B6619D7D8E523 466D2D490A5D609A96BD849CE91C567C1A375AC7EFA93875FDC16C6E06D6629F 54D14EA57F7544782600CFCBFACA9618E1B4499C3A618109F4DB21B3B4FAE8FD F7FCE6D7E17FBA63B718E7DB8E2D859171F53226976677DF5C30C1B7ED72AC3C D33FAE5A73661D112496FE48938787C74E55AF3FCFBB376752D6DF022BBDA876 4DF99A3AEC2664175CA232A333371FFEC4616E6CB133986D59C0D654AFD06C4D F3835C0922B58C95B173FEC5AB733333FB3E74043C369D560B2D427DC5409E95 35EFEACB2B677FEF1577ADD153F64520AF9562990F873895185AAA46B96B41E8 32DE84ED5D3478102F4D694C3FD8BDE7B71EAC1DF3405EE45BFCE9FFEDEBF8EA 24281BABE9CEDB301FEA2AA7215FBFABA6DB4658D8546B1B230FA0DD16DB43D1 2C635ED698F858BAF7E3208F5A2C7445346EC533D66C198A697C06A4CB505F7C 1790912A37A288381593E89E498C2073196350C5A32623138E636B90638945C9 8457EB6D0D06110F111E31BA99E4DB03AD04F4D328E53875B0D0EFA4398F97D4 E4C843138C516AF50C30D602787C2A6A56A9D4327D0635677D3A6D211B0A2187 7B8E4D4CEDD6A43D1A5B365800138E0A49B857AA8DD72A2BB792133FBF587B7F A456E05BBFBDDE986EEEF9CD2099DE74FB4BB86826D56E5A39D5643E28E392E5 51A1156855155DD1BE544B33A32B5561A5935B5FBED2784DAC3F2AC849A7FCD6 D6FC65FDFACDAEC1ED120CF2020D61B5286D2C0A0193B4A4E376692D3BF4BA40 6118EACA5A09020C411C26D0348E01DB71E791CD59888FD343FFF2F1B8D91F5A 5AAFD6C073ABDB2F5EAACFED629A26AE77C87463900E1DA8E84C032682F7437B AA3E48C2300E77FFD0E3FCFE43E6082FC18059A9455D311959D2D5AB3B65DFFF FD2FBEF4DF5FCF066C1358AFF1F84AA74D15F124AED76B20E93F72F08075E3E6 FD95697BDFCCF5D6E6C1B2E2DBEE53C9CA55927B09B9BADEBD614196D312901C F092E9826DE2609AA07E7760FFD27BD8BB3F26E2A532DFFDC3B5EACFEDD4CEA3 E842FED2D39BDFBEF4FD57E30BA3F9C9B476649466D9CEB51A6C7B6E1E8F263D 02B9A3976166B175B776AB3798CDD2239E560CEA427FF3C852F52E3A6DF721F5 71272A2E59F46D3BDEB9B472FFDCDCA57830E5061F620BA0DD5A990EAFCAE151 569DEC0761E9ADD634436EE9B7771A352792F8CEF9E1234F38D5FBEA7CBE16DB 7A5DA46E34509D8C5FDFB7FAFAFAE99BE95737D2A7B733A1F1731C53A40913A7 4A3F91F9123FB4B0A72ABA17BBA383F5FA71E6AF0F46AF88AC0521A15617883E 2FF6D3E0FE069BC4BDA39F78EC27FEEDBF1A605DE9B0576262A6618D31B7413A 3876E23458A1FF3FFFA73CA3DB3AC08C51DF1EFF298DBA56E3698A1299786E69 4C244C57A006E8848D46C96B6FF76E5C5938B6A06CC079C62C0B18FF5D598EAC EB7FBB5CBFE254B1BDE1751AEF9F0BEEF352DA2943A48B8096A8390CC599247B 11CC9C380CEE97395EA38A62A5A949A97233F30D956948D34C49C24C612DFD9C F517475BCFC775303928B216401B05ECC4B15409445A36A31C3A26FCAD343BBE BA428CCF089131362EA58FF02EBFB260394EA6A6EFE81DFCD0B4B4C4ADD3890C E181879B1CF6F211D2C21539A3328170347DF362443F0A771F3A08471C30DC7A 63EBFADF5D3E75E8B8B504D27280336CDC2FB0A0855608CDACD44CB127E284E5 B317DF6A55179B7BDEBBD09F18548F2E4AEA994CF58847176FD44664E5ADCD5B AFB62A7071907937527129EC0C455477AD39475779AA84899D83A40C98AB926C DAAD4ED99E872585A95F85CD0957DF34A9098ABEF9040155C91147D5BEC0FD72 34315A77AC7ABCEB47E6F32594BA1476F9E0AB5BC5B3A897370B8962FD6E3937 4FDD5F3FF0C811E5C422C8A9F10CB200B500CB011E956042D72CB3B3358E1347 E6B010DE8ECC03E3B942707B9F14987473D3CEA4060C566E7D7B78F5EFD6CC4E 7259AC14A295A5E6544812FDB2C9B2D07590993D6A284D62720999E66FA6C1AC A1E014A6F3956A409C4C868B8FC0E661C04586733CDE0F9016F48737E262ADA8 E0C9418CB77A7157F4805B8518EF6664A6485DD7CBEE38F1E0E7FF1EFED1E1F9 77D2DE35169A734F63EA7CFB5CEAF69EAED99193425F0FC1BE8D481DC959C787 2A856EF7D8BB66B321B97976A490136139E4E8729E6469B46055E768502542B2 CDC30F4D2CDCD12C449FE489394B17544B225C9886319358A03941565979ABAD 19C4D2BB172BEF9E11736EAA619F306C4C6A152C6AAFFCDB67D6FEB1E7064B57 C2C1B2CCAF69E1ACAFC8A402DBA2C48EA455806A786BBF5DB917CD36398866B7 EEFCB5638BEFDB034456B4E06BBFFF7C781A97AAB25E74DE067290F1BEE69FFA 1168A18D804B4D50755968D880F314EFB7E8AC4583BC597B323CF62957573432 C422A638A34068D4494862856F817C55CB3ED12FAD4E967595D08A4A24C201C4 A2946B72078A320D9B94CE5602CD90321A19FFF792EE6C6AD88021A22B51D82F 41274A10D1AAD8744E999BAC9FB1995BD1B7FA76B7B07110D00C8558CCEC2E4A AE5F58DB662E660D6E375D6BD66779D29A9CA54B8726906B4C99A012089B33CF 1C940A9794C2ED97ACADD1E8AE5FDDE51C11CB5FDFB8FE0F9DC77FFEFDF4E1EE 285FF7F942095D30034BFB0E0DB5663453E6B7CFB4A39D353AEA3A6591170963 BE3C273AFFB00E7786533F7E1CDEE1673F584B9E8E7058150E0C654F401C293F E39632A602595EE2A29063230EE53A2E2F7891E71ADAA9BE9A52F3219473AE5F F1D992152C0227C8D15F797732311CD97C4A03E14B5BAD67CF0793332C837CBB EBCC4D0ED3D0521C4F35CCE84398D8F54A77D44B8158FAD8E3C5A97D4A942CA5 80D0CC66B69814C6CFC02A23D53DBFFC95DFFFB3B52BEDB5049D4BF8F541A8B2 62D1758FEDD9FDE6CEFA870A7F4AF26EA0FFDA60762B3FB803F61D38F072D47A 2BEBEF407AB63BD832F59C8BDB311FC418BF32A989A6FBE452F5977FC8BBFB43 58EEF2D5FE9F82E4132174EBE202D8F8D260FD3BFDCB9DE7FE6AFBB9B3D6A031 3F0BDDE968D82BC34BD9A8EE4EF9FAB36AF82958EE4E9E6B6F71DE5F9AAA6A66 7579BBFFAEA9E0CE6C8A96C1693A58C3A156A873C8DDD858EF68CABE545F6F8F F6BBF5FD7A91C79D8155B80D9FF6CA69419D3422B63BA8575ABC7FEF94F8A9F7 CE2E3E38171DB80B4D3E0AE9244037ACC10BFCFA69779DB69FDDBEF2067FA685 FFB2DDBD894DF3879DF2BD80CD58CE5CA5E232AAA9FC41954CB1CAB45BE981EC A5C1E64521FBC238CAADF77BDC76774F4E1D04F151A758383AFFC9FFF997AA77 9FC8CBCC305B5D4891E1FB701CD351181308337F0075791B07358CFD646E7BB3 FC13101A9CBC3D136BDCAB8DB78D09F328C6F5AD803C912B2BADD3A727E69B56 C38E64A2E9A9415AFD3BF537BEB6C6CE40AF2CFB53E1DC8F1E2D161241426384 2C1D13080C33BA656D7E7B9D6136F5C4A29A4B0B1E11C010B6352494C63FC7B4 62E75AE0C1B41028A081EA58579FDA18DC84C87206A45C8FD5F6284EC5501AC7 7B8F8F7DC24CBD566351380E7C53E31C131FA379DB5BB06C3F07CD0792438F4F 4A195D7BB5EFB0EAAE933E171DA46A9948A9DDD3D2B9E84EDC7A3BF33E65CF1D DC03C30C30D27A7573ED9B2B771D3A216AA3B81C32C18C1D151298EBEAEEE7A6 113B2B11CB76EC4BAFDF3AF5E4BBC81D4A2D50677E36338DD824BBBA01D7B83D F0CE3E7FBE7D295479752725D7F3EC661E722427293D50A9D7B47C2150AB000D E82E7148517A90E8CB6EBAD4B701A559A055AD6D7A0DF4AA4218215E05DE2647 8A90192D115596DC5C0E6B0716973EE48AC588264DB05D5BFDD6F7DA671A5A52 EBB29B83753AD3BDF73377CB7AA45F6A8CF48372A0116D72DC62CB4C3280D9D9 42634019DFB831FCBD13230BC64E591A83B524329D3311517EF492BAF1E55BB8 434614DF10FCF2A097E825832DD36B5F9A5C648AA067D92502A33C05261006EA 42535370D10D665DCFD57802A38913E59E7B2B0588F40793FA6103ECB38AD851 C31B911C5A594A4789E8CA487F3F2274C9A3F340572F34DC7BF0037FF91DF8F9 A34B98105DB0F42FD3B14FD0EDF13593FC838C298052C6E22DB331E62A804E8D 301FE7554B545C97BAE0E0BBA6AE5EBE12EDD479361116BD1B72A31FD2AA333D 69C9092AB0E4CD5DF0D8E335E8463803B430A7E731F4B10973C84DA316145455 B72E8B566BB0F4E0947DA75539BEC4996DE6F1C651E6D499D8FACADAD3FFF70B 1531170AB1A2C2CBA2D8CA51A460EE9429146E61374BA7C13A076DE764D99C94 A417AC1FFEE9A53B7EF204B0441939D73F7FF6D657DBA50C5A60F8AA2C865C8C 4A9243333C4B4B6553ACCB7491253E4053401EF2DD39D7AAE74D7A5FFBD43F33 59A072A0CA98A29C68202C6581423678438A2DA3CD87A5DB4E929E7EB2CC4A86 E9845FF77D47637D120FDCB2683236E1583EA52330F02BBE8A449E98D2DD5770 6530DA48D254416AD91AEF8A4298DE608C0B73CA2CC75D06C6BC5633116E12EC A999E5E55CFF5173ED9AE54F4AC726C80209B67B47EE9CAACE38719E1B008486 AF28CDA2358B2536AA78ABDF0BE36074F7E70E16A3E14B7F70AED15C3AF1D9FD E9C4BA9D53985555D5C533FA4AF7E4562E28B5F29216894AB7D34EC74E4BE3D3 E9967464B5BEBACE4E4BB97B38FDFE636089800446FFB83D78A5EFE16A4E45A4 649C5929F79431130889E5A569CE35182AE1D8B6E338A6EB592B7FC3A5B0FE2C 456E5CFC16344DB712710C1CFD95F766D3616CF14651295F6EB59E39EB37A6AD 1CA45B1D7F7E3AE2092E323ADD304719B1A66F7667D82F2AF6EC471E1207174B 0169CE4A4273DBB6C5442158C9AA5C97AA2C3FFD177FF3B5BFF8F2DA88DC48E9 B57E2A727EA0EA1E99695C4CC487516DBF435FDB38B7EBE0EEC3B8369DE04CF3 255CBE9CF55F29F999CE208E948740AC2BB54641AAEB30058585147FFF02FDDC C7A7DFF7B10570682F9F7E6F24EFAE46FBB07BAD0CFFABD8FC3AEDC8B5E78BCF 7D69F9E90D7290344EDA484DC9151ECB75B96F56CB0C0DAC7E62D5DFDCD8442C 3DB838D3DD19686DB234B918A4F6E676FB6CB621CD9C0A385E9D692E4C5FDABC 547761949717BA1C3BF540667B17DCC041AC9DCC001A3025D1D49BDD6E66F77F EEC9CA8F7D72891E9C93077F3C273F92F28A45D73DF8A26A3F27DF7A61F08DDE DA79EF6BDBEACFAEDEEC4AB0E4D0BD7EF5C4D4FC14B6592A70126329F7C5A37D F5B991121B93E4C5A47D332F5747A97EE5B7632D91E0FEC5A57D62F44000AB32 39F5E31FB9E7177E1C54DD7143E538197AEC33A1FF35375974C032EDA9D9D867 F236FE8D21D01856AB71C69FFE36613A050D407238565B99E24416C6054F4BB1 A8D77FE1071AE6DD3D1321E3B4288CB4D1775F363ADFEA88573257E4F288A87F E2501284CC810432AE495F9A505520EE8D5E6B772EB4668F2D38770789354442 5768D78C346A79C1E1F87C41975E896020F3D4425E72AE7CFB7B5AF7DAFAC76F C67C3BCAE23289B9BE7E5F1ADBC5B10454C6806DDC0F62540CC1B042C90CB326 017113E93E91DE75DF7C918D2EBCB135BD343FBB4B2BFF10E3992CD77477CB66 56DAAAF72E12EF335E7DA1A9D709C6F6D6CB6B9DE7368F1F3ECE9D5E5A8EA8D9 93820528B064B6D43F310F7525808DE16AB9DDE99EF8D841B927769626A45F17 445A651A9D590B06539B6792332F9C4169301C812EB42F26C3A4625306DC309F 57D82BCA6AA50A354544914D5C0B510F531B82AA4318E49A54D90E684CF8D425 A6E554DF446515A82301B32BF366A42B4B6DB57873BDCB0E8CF67D78D638CE0F F5EDED24A76B376F0CE18EE31632A96FEFF9F48C7702673245C42F89AD298B09 2B852E2285692DC2C606CB0C4383775298E03B0EA4E0B683AB86310D84C64192 E548B8E86DE7EA17AFBB233B77DC4B59FC666BA3A3F98DED1AEB3BCE09820E33 D18869929B3944D33FCA48595610D640386359BEC20CA6602A3CF6F80CAE844A 83A8AE88B99926229C0E6E65FD5B5CC536D7976BE3A130E7D50DA4E688648EBD 3D3DFBA92F3F6F80901062AA951266530E21F393C6CECE63E7F0715AA5549AF0 9034F152E492A01AE4934EE91515FDC5FB1FA412B62FFFA090830564A7B7D48D EDA1C741AD1664B3444D93A640BD838FE0E97D44A6804A73441083001BAFA59C 2B133762C1CA60C37DFDB5AB07EE99A91D27CD070FC989AAC9612C53CA90A167 A3E937FF9F37AE7CE51A731AEB205C4BF9666ADDD2DCD0D6C091BBD209801BA8 F621C73E012BB3D08BDDCEDE1F993AFED9BB333F64215BFFAB8D1B5F5C81C25B 953B6F41D44F8B914664CCF412D6A2938292315A8AC22D4143F2FDBEB3E43BF5 AC561C5ABFE7A734518E55A860A26F3236D8A40A38B05A2FC765CFD5201F96DE 761C0DF45AC5AC48F2C0F18C6380C9B12EA63CAB499039BFD2373010B6EBC43B 115676AE68272F6F0CC38D51A49F1DB1ACC24C66680D25B49E2C0D0D31EDC526 7A57FF01613EE6D49A8F58A5AA12D470DD9AA606FA6F4502E0D1FC016B76AF93 C3D4A0A86966D4AC3CCFCD4031655E2555B5F3CF9E3FF2FEF9A947FDAD17B72E 7F6DE79E4F3F98DFB745BCB41A4D68150D161A9C091A4D4555555056CB11EC6F 64DD1B8C97B8D47F6DA25F8CC1E970F4ED6EB06925F7AD2DBDFFC1DC4EF5FBEB F79CEE3756D54D65F9DE108A28B6B2D8D55857D2482F75B3E74C8C29629AA566 770B48642C72D438D3CD64215B9635AB7FAC1CA447CB93BFF63E3E9725ACA8F2 40FD60ABF5DC856ADD98AA8DD65BC1C27452E4846774B6A151BE084397B25E32 044BCDE6FB1F5253F552525C582561DC72ACA25A4A3FC59EA4C89671FBA597FF E6DFFDC15A175C4BDC0BED280DA37DD395F9A617EF80876667277BDD7D8CEE5A 9A6E8BB4A5928D4E27A7F42605E71158EB64B223369242E9C542B5CE26A0107A 7D1FAEDB1F3950FFF18797F62FDAA41A8CCA89EDD0767782A4D143CE8DF9E136 DE2E5FB8A5BEF0F27267407C2D72EA7858D17795F829DD4B731A0AE835DF48C3 2B83E191667DBF06EC8817C8EB94F072F7E6822B3F58A91FA9386FF47BDF6CA5 CEC4E4D166A599F50987ADDC796518AFA9E181A6F390E3ECCA19B4E9599F5FDB E6BD6E74670DFED28F2EBDFB93B3F0C812987E1F484E023C0D580FB65ECAB6DE 2C76DE5AF94F672FDC204F2BBB9B8213D239160476D56E15E9C54E7BC8D383A5 F3C1C903CD615722D6A76AD5126F44FDEB0A5E2DF25B59DC2DB8C276855A0F04 ECF109EF242EFB33FEBDBFF293BB1EBE5B536462DC854D078482EF2842CDC9F5 0D33DB8AB773330DA11B0719C1B155D9EDD9097352A4C65D13391C6775C74030 93FEA74A83A2597EF6E2E8F4EBCDC373F114D60C8508A1DFE7A09CD8F9CE207D 7EE481D87EC8F23EB810D985EF38FAFB8DA14C9CE24CB36A8BF661F7D9D53206 138F4CA7BB782994AB498C67E9759B8D8409992339E5E3C3C992E3B290F1D4F5 EFF5BBCB5A97E201CFBB85E8CB629068A246C79E98E35426D38E87A9D91C1D03 BB14554A662D6B12523F87E803E1BDEFDA9B7477CE9D5DDE7B7CCFE4AC3907E3 BCA66B7029D72025830D0F6D34BD9FADB149AB08130BF99B2FAC0E5F6D1DD9B7 8FBB5151EA0FA8C14099DA0B6C3BCD0BC6BB0256D2B98D0B11DAE334DFE3B15D C25D589466C03751AD6EB91CA1D5DA9B4F6D767BFA42D9462F6BCBF26611C349 CFF31C374C67A4495AAD552A52F08A1A5A8EA7C50D85582B304D1734A773B0A8 54A8E311E632A96F0A34830F50F8888854F5985DD302D136E5395CDEDC7276FB 73279D81DA2424A8648DEDE561F7753E959806F4DA4760E50122CC19826D260E 342135AD204C1313D343301685D0A40860D358356E96B98D84E3E3638805871C 6BAC81760EA58B2E786F7DE13C1BB1DCF6AEF2EC5C7B33D2CBDBD81C5926B649 8B7282645E146966224F4CF681399BF4309EC46C8E3953D4AA2011A2CEE147A7 6AFB4449539839658C459C39CC8EDA6AEB628C470C17788890C91CD62AA848A6 A9460E6FAB39F9CFBF761AFE895184F8B60A44D8B42F9A2D407368651E2ABCAD 0E95EC6A76CF538F63CDA42C87CF38B092F994307B69E7E0A9DAA5D39DE856C5 63AC03B75743B29D12C7970B3659625369B8BD7452EEBBABAA2B0B34C5127060 2CF59896D244CBC28146D62C6C3CFBCCF9C939FFE84353C1030B6AB1AE05A850 8903458E4ADB9BC6A7CBAFFFE6D7C2BE35A27014275B39B900D13611B614AEAE 91D8AAA9643F2D8F117F91540B16CE3E5139F1ABA746134392DBD1DF0D2FFED1 3952B89B387CBB24ED30D5D498538D3A1A98CD783FD34F1141266455647B1CB6 18B8B3A2992DAC9DFCB1A9DA12E0718A620C132D6E336386DD77D65F18D1A45A B2B297D33ECF0652731BFD5FCBC0F5F33C2F54E63BB48E81FEED1ADFC5C29DB6 5CCF0EDB91284C3F4D4FC0EBDD519F8B7C3C67A381C19C1A4BAD3FD8D85A16AB 420B7B331C52981D4EC48DA7BFAA103C61D94D6655A9D5D0CA0D0EFC49B1E758 BD74B2DCF877300C3545D22587677A75792C684CB436A65E79E3EBEFFBEC83DE 4470E64F5F43BC7EE2B37775262FB8183AC924AC4C88BA9665D8EE7B26249DC0 4A2C606BB5E86D32E298644A2A681AECFCCD7A722EA17A613CB1B5F8C0BD09D4 22226EB089F2E5E1F0991D9252EE7B21B7B23ED24A2F61230BBBFA0D755C47BF 3ADDDE401AE0135AB039AED6DE388E469CF320F0660A3694FDE488BCF3D79F2C E634D6093FF7D4ABEDD633E7EBB5295D127BEBDBC1CC442638CE73676E32B74A 0D84BE824311B377EDF7DF7DB7A2142807959ED0658A39843B00D7A4B2B5C0B6 2CD579F9E557BEF095B3E7B79F6B673713948579B56903BF9C6FA91FDD7D6429 1CED9DA9F5E29DB5A85B345D77B61126716B140F0A5D133402D97FBCB5B399B6 F5DB3A0DF0E15AE39E5D8BEF39B4EB90AFF40DCBF390E9FA1DE97A5AB68DFF41 CAE348EABA87EA1737FA3B79599D99940C76A2E88DE55B1723BEE6C30782EA92 AA44AA7C4EF3D22A7D706AB139824329AE8BF2F2CED6B199E0171F3CF0414AAA C3EC3C2F9EEA0E9EB9D802FE647DB1095BEB7B6499D5BCAFF73AA361FAA9A583 FB40B996749FCAA2E5983BC2BE13969FBC7FE1FEF74C556BB89257BB3D25E79B 6C8A34D370B6C4607363E7F9CD8DA1B3829C2A721BFD50A5C311545D00AFD6AD 3370C45AA38F56F71CB53575D275498682BF968DBE97876B9E9D41301A6AA151 D4AAB57B6AEC2E1F7EA2367989C6F77CEEA70FBEEFC1C224A96BFA68FA46CD54 A0390954441AAB6DC0B8813DF53F60A109FE2BC16D7324D30CADBFAE34C10863 43B3982A5B484B333E2672FD9136DBADAF7E2B98F5D0A11A280C10725878A2DE FA46277976E8B949ED833E7D7C2652C2A71545B5A800B81792984B0B1081E2E7 DBFDB787132727ED077CC104880BE27BA56B67230EB2148094C5A6126B299B67 3163CDCD37B35B2FA630B215E203283663D4CFF583E5528902186B0BB38D314E 042DC79901FA73D51D7BC6B62700F6F2127D6070F78923D1566F65756DEF1DD3 6E9069F6944B2DDD39E0DBB9B2366EC84AB9D8F8D9295881324A9970D7FFF166 7AB1BF77F74261C5BA249A7E24B3F7A6F933256996E12429A9D39BBF7EA635F7 C43C79047B4B1E0D3C4DC60D8D5CC98AEBE9FA0B835B2F7051F16E8DE2BE402B FDE17611E5B696E4CA11C56EDBDFE554A6FC0AE67C89A64E50D38099E57996A6 A0E0D335BFE9598CC82C1FD51A81A51FB4C8B8A75C5093454F2B1901AB145699 E8594CE65D7C7D63C0E6C5D2D106B5825C93DEBCDC794BF04B558B62706867E1 43CDB4A9E92F347313A56582221C81C7F4A81C5B8228136A8CE16DBA34FE55DE E6F5E3E3E452185F2289235AFAC505EBF49F9EC3433AC4784588D5FE4863904D 3C8C4CFB79AA725D475C6AF9D4925CA54A4426CC423158D6009E67DE82634FA0 3229E38593EEC2BDA474A292331C5A22E184E23C413B5712B8811DCE3A0A0C05 1AE9CA5FE675AAB0C5B62A8D5F7FFA2DF88563BB6E678621334C6FCEAB848642 73D4684E0ADFC9A45472443C1768903589DDA0E4F315BBA9EC0A7362B479F0DE 4902C995D3EB561EC410B638DFE032036082B0398D9422A94DCBFD7755ED49A5 8B3F84BADC23208DDF88C96E8D868EFE6CB2F2F6999D6CC84F3D38E7BDCBC2F7 EE896D334D4E351D346D36BC92CCDCF8F3EBCFFFFD15ACF1378A5A4A9C2BC17A 0135A5615019270884F6E2FC18F3E669B52CF3E63DECCE7F735F6FA163810A78 BABCF87BA7E59074497A46A25694B405484CDC1EA4B064E37D7FD32AC78B2610 4B1699F3ED99BC0AE63A477E6472F228C9A2014A084DCDF669C94BD0F16EBD30 B08BBAE65751698F8ABC2F8CD128CFB514A15A036962AAA12C28C58C63796656 47793354AFA36490E9759D296B54B2E5413452202D34E990E66E60909A486548 A96599A12F6EF64AB5B8D3379E9282E71A082799356D59139A23114AB5920E86 B307DD604A23AB197CD10FD0B46E8D239C32987B93C49B9DD9FAAE7F953D73FF 0FDF056E80B7BF75F9C887EE72EF069CEDB0929630C093D385E71610BB19E324 47A0403B6D3C1C99CBA256A652478BA17370F3AF571C5CC9A6B8F77058DDB390 229E11AED75CB51F44DF5857CB5238B5A8B45064924437E110096A1C4CA8160C 344953631C11459ACDD5AB15CFB1789E99B0464AE7248B50181D2D8FFDCBF716 53698E0AAF08D499EEC677DF6A7A139ADCF45A6D6FAAC94581F3C29A6D640E28 C25155947D99BA8F1D771E3C257385A4079197637DA596264582384432D3E949 45EFB5372EFED95367CF6D7D7F985FE364B43D023E6993F4E3C2FDD5D93B16CA E292DDBB36583BE14D1C72EBC441D206AA50F12025397322F8952A5B6DAD346C BCA4EC03959929D7ADA202ABC188240981BE621569C3920CAA853B2A3561E698 6E21B9A1B8446E5C4846A1976BEAED3E3D1CFC49D86E48363FBDEBEACE6A22BB 87666A73B95D8EB25E15BE381C36A1FD5B274FBD8F15306DE5CC8671E9B0FA33 DDF82F5BBD8B399FC6F25055713BBD168B7E4BBE7BFF21AB88AF6FAFB7A0A745 B7323B04F4A4454E0468168B59E64C78B67F782AF144D91B7A2325D7449EA338 4669526A12DD855948C7B9938AAE96F212C9B6324D92F1A78D479E4F2489D26C 99C0A73ADBDD7AA5371C8D7A19B0B474708FB8E0D199CA47DCEA5A133DFEBFFF 52E3C401610E980035073DA641549733E3696646E78DB1E9B8E0C97772786EDB AABDF32F46148ECF8A34046A4D66C204326A4CEB686ED2C763BB0886E1E0DBCF 2239F4EF98CDE5687CBD80097FE7AB2DFE62E44DF3CA8FD6C0513749351FAF97 555692526EF6585E6668644AEE15387AB6A331B9FA6883EEB575AD60960FEBB5 ACE0208A5512BA857E709131FF07FA2D55A24FAE7F378F2EEB9A166B486E6581 2643C3AC65B01A0185C7FD8FA5B10A37E1C242D345507734B3650DBD8424A64F 6CDD71C7A9C1FACE30EC2E1CAB6230C8A023A1C764488BBC90CD2BE7B6666666 2B3FB1042B40C5B9153AABDFBDC65746BBF6CC143836B782A3F1CF00E67D2EF5 628E71E9849BC1C67AFFF08777D37B2CB958251E222402DD5C5E21C3D78737BE B3225BB5755ADE02A0CD652F32B9E7858D7A49D7C6400BE9594867A85303E044 4090E326426AD6A84B9326DDB38D9A631C44F282C75E60D9BEAD974E6CE9EA96 20D39360155AA0104EA1605C1734776727DB6EC7933393B333D5D1EE551F5BD9 80AD9F937213533CDCFB911975426945EF681AA29FBFA30A37B7A45B9A7B66F6 09C03BC62008DC6E247E6790F09DC91A20B48681A9EC39A4222F3867FECB4516 BBED9C6F946027D35C04404D734A94832232C7C0AA62DB3E76C01808074A845A D603A581708E79D3942D5A44E2A2B2A8F6BFBB22AA435C222B76418E221EC3FF 9FA9F780B62CB9AEC32ADFFCF27B3FFFDFBFD3343A4C0E1CCC0C060302182482 2412339896694990442E4AA2B424D91497685BB424DAA268DAB24D9322089206 184000440E33180C2677989EE9FCBBFBE7F0F27D37D6ADAAEBAAD7432E63CDC2 EADFEBF70B754F9DBD77D5396763BBD847F185988C48CA9C2147DDD44C12F0B1 D40A62CB097EFDBB97E0EF9F5E016F75C998992DE6505F4D1D12CC2D3744C458 690851648231C35D78CECD14D2B9AA3B4B59033B5ABAF88BF0C8BDADF52B37C3 5B9AE3CD0DCBB00F8B830970A8D7A17CCE42B8C8164F04ED9394D38C6B2AC34C 8B8E99D2A817C9F899714570EFC0BA797E74EA44C73F1939EF3AAA961633A163 22C766D058260B26F767BFF06B5F2AD72DFDB1465671259CEC0A7B2C11A13AF5 4D1C488F90FC8465CFD38A0349F3143EFDDF3F3C3ED6D718E7BEE05CF8B7CFC9 2E9A40F186847B49BAABC9AFA68F5A910260567ADABAAEF74745E4875CB65CF1 E7B99FDABB777DA0B1F8763FD3101A23AC11208988B2F375B2FD6262A9DAA488 26258A344C61A4159FDEF84952C4694A99CE676503C145DF2120279A5FCDD124 8EF248670F27CCE050E2035E8E72999B8BBF82985AF432C935106A4E48891952 549AE2D1121610258253846D003AB63367DBFAA95B7ACFE0F1CC213A73DC9530 932536B33B4C8996E944D4C10EBDB27A58CB5175E30F4BFCAEC1E13347CEFDC1 05BFD639F6C9B72564DD2EA9166C85DE0EADA6406ECA554D3F74AD6826FB6AB0 CB382C4B2FD7744F493B74C2CFAD8D2E460BF7DFD5A53DEBC4B87E7821D79FD4 5C96AA9AAAC8B351FEC29827BE7E1D4DAD74FEDB9071361166074064AC8985A9 47D6B104A733E36A9EAB5FB834A373E4AC62999D4D4E97A77EF5BD4565922361 80F0D264F36B679BD48C2638D8DDADCCB675E099EAB67690D85A42E4412EFB20 A97FF0517CF228341DAF2EA0951C326AA08CA51039C885790268313877E9D2EF FDD5B54BDD2F8D920BA92C7A99C654E082FFD45A7DC46F8974F806E8928AFD10 6ECC0C841990414C3315A04C63D968A833567338EE0742F96111047E4C34ED2D B0668201E296266E0C99323B4C781A21E087A03521D14CF069B0FFFC85FD9F98 3F7E88B20C874DDFEF51E7D3E3EEADCDFE55286E5BD9E34BAD07811B6E8CD392 A316BC7D103DB9B4F08BC1FC6218162E3A086873ACEC11B86E8BD75C34199B67 71BD5A3EBFF7FA09821E718256D0D02CEAC04C6347F5EE2438D6E173B413C60F F4F2A630730BC174BE7F487084619CF15DE90166644694EAA76477850ED9B8D0 2926CFDA1CD57446580A768ED43F7EA3BF319CEC31709B476ED0DE1F1457D289 A64B07A348EF8C8AEF1F65E2878F2F9C0178BC52FDE0FFF0AB70A5658A61729D 33C994464E676CEB445802339A458B21F896738A497EE88EDFED5BCEF5778A65 A6C43B9FFAF76AFE05A6A3F3353AAB9416AEE69B2FBC9ADDBCDA3CBD909189B1 B4D6F194B3C15F1EC89713EF04F43E5651B3301D13A73A833AAEC1E28350F647 90C5290195A8917EF320BE3964C769F0CE4E2627845471ADAA737419A7AA17D3 1C21390082291814746C413239E7AD7D352C135EBA6C27B68705EA27DB99FE90 A6DF9C98865EA1E9F274409DB9B528024A1A14CF691011D87F6AEBD0890736AE 6E9BF1632B50A844EA9C6E0AED43475644AF7DF9D28DC38FB59DF71DCD690E12 EE0CBC9B5F7C130CE29523B3A99A20FDABC6A1757A735698AE943C4E2DD058BF 1D27343FF59153EC849FD7B0513D6242F768FCCDE4DA97AECB4D8955FDF522BC 8ECAAD540C4631B35DA71EC442E3C5A45264C73C7FD5F25682CA924CA465A5C6 501C85492AB8DEF72E16C2D74FCE5C824ABFE2D8BEC5EA9A22C458EB49E008B7 28985E488214D3ACBC28C4C156D15D1F2F35668287FB81D7123E19C4E9FE6B19 BE2916EF0F2AEF65A9A7696A00B4680BB8B9A6073E34FD14531739634F3FE512 A60D0C4D51E6ADAB63D35C2ACD5C5A41260CB8F85270F90F2F07A13312E5ED42 EC16223653B574E643459144C6185D31842D8D17422F158C298AF49F949640A4 A5819FB055DFA5ACC4B5E4F4FB178A56AF5499C37D98D911CF04115664A5AF8B E4064741B51BA98344838E699B8FA5D8B6FCFFF8CA0DF84777AF4E2B79A63CAD 2CA7331F0C4999D6B79A6352230C31F2959BC8586F60E3B129A5EFC01987CDA3 AA251C50E1FE613E3757B9F1F28D6CB81A8A51828B83844D723057876DC0DD0C D45AF691C7DAA29E28993A720C4DDD0C111A8F4B571431B07351B4DF7876DCA9 D88B0F4B727FC0EEBDA7A0AAD0CA4D2A9BA104152A6FBEF1BF5DDAF8EC36638D 018EF7C3C1568AD721138CA022B5105C45F9519B2CB24A15D8D55578FA5FDD97 3C18CB92F9E7AD73BFF9ACDC82B9446B106FC5F14656980E0AFD609499864ECC FC52E022E8E6F1B2C316036F4538828D0F3FEE2FBDBF91A33E1C973AB1F134A6 C21DBEA1765E4B1CD2D41C342AE1A4C873FD3C2DDBA2769216C3F1443FEC96EF B7089A712CA4126281A045C2D158701D79DE202EBB793906749C17D9D481DE75 3D9D33529ECA5214456EEC29B08509CE95993E5048133175CB9AF5BC3AC61573 5D5FD076BE72A2893DCE554C892B8DBF9B86C4486F794EB93B5F63F3B5AD372E 75FFAA3CF653AB659ABFFA954B8F7DF4A9F29E1480A195554BDB054B41517179 8621B0AC7C8C92A40C0F54D8A53410C88B31F4B98F5F496F7FE5220ED0D2930F EC5EB94DEF2D5A2B33653131FD825007BE256F67C3677B60CFB3412597698A51 5F82BC405AD026A9F1ACB71D47EB42C98519E22F0545A5F1A262A61FB6217064 45F17DF4D83F7A4FE10E0AA41C555197275B5F39DB807E6039077BBB41BB6E4A 88746A6FB8990B212F689C8EED72F647DF592C7774CE84852B59C0A16D411B40 5B94844022915EB9383B77F9E2EF7EFE8D0BBB5F1FF117A33CEB47A7307BE2D0 EABFE0B45F857D94489ECD21DF16183A9436AD221B7A1630D3D26D1A4265ED3B E3B4A08232A109600E505CA5E6A5238004A33AA9522012C25DE56F1381249D93 ED1778F2CFAEBCFEBEFB577F315851FBFBDB3EB8BEB5E7B9D5E18C7F085706AE FDE52B17E28DFEA3879741733E75409D0F17D2F8B8EB2F2AD934885019DB4696 7831EC02716BD20B503D229D3FDAB832B334F33E0FDC8765E9D82F8CE4F544D4 EA6C81A0448DCE6D6D372DEBB19996AF046602202BC9DC7DE9DF48E495F1E8AB 61D751BCD4294A2753C7D14CF8A1EAEC7CDD6A04E03EE62E44FAA586E759FED1 62763D8E5F23D9F7D5B0BB973FBA74E6D5DBB7AFB324446A128AB97AED6E177D 6C65161651EB897B9FFE8D5F4998B02885F24E839839E712D8CCD8D6198E98CA 98A29C66F669D125342809DFC2C269279E98AA0109B528338E53E616C9684735 3D8DC29A1DE7F995AB83EF3F37BFD22EE634BB922E222025C3CF6E95E727DEDB 2BD647EA5C8DF33E6573F370CEA5FA7D52210743C8BB91457C55C9BFD78F5FE8 E2AAAA3D3D0BDA28CB905D6FA8BA891F340445181211226109616774C4B0C6D8 851B5F184E6E6AC24542C5F6F52ECEC763959BF2088AD574040AD39A0253629C 654A8FA016251DCD8732D079CF6EFBC803575FBFBE70C80BAA63C488269082E6 D2C9F1A806D7DA3BA39DE58F06F0EEA3192D6414F97BC1FA5FBF49F2BCB51214 2AD55B194A53CB2B8D398306A6A4CC1D2CE6D7D66F3A27D9EA87EF412B554ED3 94642EAE10BD1F7FFFE2FEB908499B637845F2D7D37833E78920CC72B9A947CB 1D991EB1ADFB9ACD59803A36ABF0107B81A02496F260146659E15A2E85D0D7CC 91691E922252BAAE556D8F7CDA120265B09076699ADB80F1D1914861DB8C4FDF BF3AE23DBCB0386E2C1F299761540D471B72F45C6497E9A10FB5E8296F1CC7D5 8A0B40C409A1A6D4F3ADA2CBA949FDF446F82D14C4536F2663C5A4C31969A9AF F3821D93D22157EBBB7F70AD11BA0562B74579234DB6E3C93057D3C325A88972 AEB8CE841EA496B989863D91C7D0345E7B0A689EB0E855966C16B0B22083D31F 388C0F45051EB19C91BC9A97E5440CED1CE33537BC9469000C73D2D30960CABF 2229769DCAFFF2E215F899BB0F4D47BE4D4DC3C09DE93753E90A8066F45C9862 3FCD0D6A820E8B486BB4A9555346B1A859F62CA835A0A76816BBBD879F38B17F F3C6CE8D402B80846761E9DD1E24F53A6E623E075D5CC2CEA95AE304A16C4CF2 7E095D535AA40451FAF763C926AEB570EB2C18EF0C4E3D1E64CB71FD917BE062 2B278996A72E248916EAC42517F0F3FFDD33D99E950219A9E856945D2BE98468 1084B6E28B6571D8062B4EB52E1DA723CEFC8BBBC153A540D8BBE15FF8F7CF46 6FA498071B406C4ED2DBBC18609CEBDD6726792A33BD05424FFF57E48B0C2DD4 FC15C11C269BA7E1EA27DA29392051C962248A14A5CEFED962F72C7758435291 2214A6A657DBCCD2264C4B0E4DBBA2386D07411BE396659C7FB444A954691CC6 E6401CFBC344EE676228602F8A25205A9D79AEA73460662980B2C8B39C7366DB C621B950D331338828D5749D966D571070752C91B47E027516DB111F20A4CC54 07BD2DB04EDA0567A13747593B00D8BDF8CA1BF8223DF9C1475E79E6BB5EBB71 F2630FE46C130B8EB502AC55CB19AFB0B0D2624AE359B85DF4C77A01B5E62DB1 9D222CA055D9AEEC7EF6DAA87F30F3F45C6369AEF7D75BF0FD7673A602F23033 55035A1D95602CC237797E4E54622F2AB3112EB31CC73930F301F49E134AE706 8A58922495C0D35F8E4E5BD46D067DD7A97030C0E3E4617BF5BF7982DB039D29 2D582F6FA6DB7FF35A2DA7811774F777DD46D5DC3069FC6B06DC272AD51C3A2A E76BB50FBD23AFFB4C78487A05D1ABE7626095D8231916364B708AD5509DBBFC FDDFFD8B73AFEDBC10E297E334EB859F5A58FEB9B9C38777B7AFB2A8678936AB 2CD2FA189357F17887C68B08DEABF791E03270F692D18B7DB03D96636169943C 52852735C78A4533B335E127958021AEBF2E40C9C56056F423E5572E3AF45B6F BEF9AE432B4F1F5F188C6E5E1B0CAEED68463AB7918CA52FFE7EE7D011AF111E 74C3B0BF0EC15706DDDC634FCDB51E506A2920D2E210E3403575CECD65287B11 4DE1760C5F188783B23C51693C1004F3D8345171CB7E2D0F6386E6ABD517BB6B 6F5CEFB73D9D6E586A59334B758FE6BC543733F2E2567CB91FA65AE442D738D3 6A0D5DF76B8D4A6D983EA0F0C37576A4AE8910EE4027E378C8150BA992E4F578 7CA1A29EDDDD2A58DD6AB6D6F6371220FA69E1D8D61355EF23CD7A1F4FEEFBF8 07DEF52B3F9F8382A0A93FF6B4BF603A5B0D16D81C7E1173085AFCED6D5039BD 255453279569F9E8B494B4BCE3C2A3A63E0BE662EBCEB81153740A346C6B9130 D8DFFEE297676D59DEBF98C56317EA64630FFEECA6BC32F1DF3BE3BCB79A0C07 7C00C9CA3C5E086C0D939A8AA411EC6FA4B64D08416FA6F137F65552580FDAFE 039D480345D5C7B38C400A22CA7B7B3049A8D6224599C304E1DC2E9BE317E59B 5FEB3255292D7690E593BC3C9061AEB38329D23795B1FA4311730D066C86B59C 6ADB560D419ACAE50FC56E6DE9CAF51BC7EF5F00A8670A370B1D8651E24ADA6B 452F296BC1F27F9CD0C5230593621C7AEBDEF617AF58B870668C71002B2C65DC 038CE79A19F208425FCC4FD6BD8DECC6EA4F1DF11F5ACD7C1283BEADB9D74E6D F2171B6B9F3BC7E46CC841AF1C6D2A79319A6CE702FA75CDD4D238D59BEDA8EB DC5FA91E65168B4636105517F98DFA20C922215205E3AC489342C33943B011F8 0E29154F3CCF7603EEBAA60181E342202D103096D8A22C475AF56B49E9CA1118 AC8F6A070237A875970DEE42C077A2AB71EF95CDA5D333DEDB9D3D6BD00EEA38 55805133970EA392682CD46B7667A80230C53AD38A9329B2E898D0A94BA29209 24388B28B0E95AEBE0336B6453AF9F7540AC9E19BC95EE0C26499A63AD4E49C9 4B9DB1A8AF132D245A8D851A65CC002E6949150032EF07F384361C9817DD234F CE35EEA385D3071C91A2A6E961947769AEFCFD6678ADD8DF1E09158C723CE179 01794A61D7ABFDF6F36FC2CFDCB37AA7D3B17CEB20DF9CEE8B3B05EF72DA5968 581BF433A5053367E66E1C14B166841EB5ABC299632EA142235673C99E9D05B7 2EE77954A6318C4B7B2BC993329DADE03962BB8AE9353DFA7023688E991C1725 D54B41F41B0A2A8C08322718D97EEDEAD9CDE5E3BE7D58D8A79AFEC3A7A46BCC 025949335040E337D35CFB83CBE7FFEB1B01AE4F50BECE93EBB1D82B694EA90F F84259AE58E09013B4948BFDF4EE7F7AC6F98095C2C2DBADBCF97FBEBCFBAD83 1AEF6C8964372F6E09B15F8218A2424E27E54FD98B8761B5940B14AD342ACB1A 0A14AC1D2F577F4A7FDC2D5F7FEDD0A014CB83DE6B60EF6201B57A0469A66345 681D02A84E0B423F67ACC16B1C4EAAD49A61A469E91D9E92C0182FE451A6CC78 347B24C041260E923C3553E28C7832F3B43106C6C8CB9CC2A8E919BA2923D541 85A9DE2515CB0928AA326C43C190ACB668ED847E2B1D4325266678AD093A42B4 16E4CEB0B2EC52DB93B1FFADAFBC7C62EE50CB9DB976FDF5D39F78182E295E8C 549438AD59D4E948AAF73131F5C151910ED77066C64F6986AE5722475AAD57A2 67A3F5AFAED54EFB4B1F5BE85F3FB0BE04F34FBACD8A07B2382586E6D9A28005 C887F6E05B07EE2604AE3BD0C4362E95E5E9CF1E4EA230CA0C53F57C4699D6CB 224D2C2DAA80004556A978F59276D13079C839FA4B8FE7D6582F9E5B56CA2EDE FFC22BC158F95E70D0DB73EB01D1328173D2F28167E571C235A69E39C29E7A20 371D663ED44088B560A8204938F61D4E3324339B57411EBD72FECBBFF39997CF F72FF4F16B49C444F46F974FFE746E87A01B1BD757E8D220719C4B59B4964F7C 8F1DAB548E601A98FA7A78ABBBFB191BF642702B82B77BC31A510F39EEBB9AF3 87ECA09472908C75C4E82D1FF2FCCB3AD70CCD6DFCAE9FBCA359FBA7F3772549 F7FF185EFBDE30E5632F0B3AEB300BFBFB1F762A8FCFCD3CE007CB1264B0BCE1 63D1F05A9968F4BB364C33C295EBB1A05D2BDD496F378BBBADDCDE2EEC376A6E 2293BB748203F8222FF7527066B6D3A9178D3AE15D799EB1B5C0DDE8F717AC16 99A8B58DB5811ABDB1175D0320B3883147A50C468EEDAB5A1A1E360F82817CF2 FE99D97707CEBC9DEBE74C2595B91B0B06273C2D5037113740F63DA7FCA3DDAD 60AE25FB432EE50841CF71DF6E5B1FEED4D7D5C1CFFFFAAF9DFC91A74159286E 8C06D51403B198DEAC2043FC4DDF349AA2DD94504F19B599C5369D0C79E780F4 4EEF848E5B39150512EB6C66C6F798C66250187351A8E2FED7BF0577376A6F3F 9A96A9E6C13061FB7F7209ECE6D50FAFD207EC78B7C752A75CAA8339DF66AE4E BC691E59DDAD4CEF630AAC83523E9FA4D786692399796219B4DC0C15D66C806C BFCC6931DE2D7A999D7358641ABCA529762DAD5EE3D5CF6EC34180098C603948 D0AE48529EE75AA6693DA2799F2C4D716721F4FB555DD6762CAF148122477E84 F6C389D671ABA73A291896A9709957C034D1C46550DF79B17BF81DC7D3A795D7 382251C227A17FC5E97EF9BA5301A899964252EE0253CA6F142130C5E9713B5D EEBE1C4E4EF3C37FEF046C556244B82FED583A5FE3D7FEF0FCA49F23D99864E5 0E0EB7D2643D49268869E29CA85273F16A210E0174B7E76B511820A5D5698973 BF52EB8EC7132E0B44C34C26DCDCEA6A5156B569DD654C6F79253248DBB3CCA9 72A565ABB1444096942E231C89546B04A253BC9D876374DE114134A1B173B4E1 DC65114B6517F36C90B5DF5D1F2D0C1070FCB482299F761322404CB14C39F501 357F505343AB29C498EBC369C33254547F7BA981105AE456EBF69FDCCC6FA589 C29B0518035218232BAD31453E1D22A31989E76814D4909FA585205A3F509467 A9A6127689DB8EB3C0EC36D34975503FC10EBD6736F706260A339B6092172188 0B7B584D37D4D61B3DCE6D2EBDA1B1469FA40CF7AACDDF79E92AFCD37BEE1C8D 9A8E4173B061EADCCD1D8F343DF6E5D4824B99021E698AD585312D32F36E8C31 5449AA94B66D0D429A076859345E3D534FE27CFDCA00F146C4E9AEE04399DA4C 752CAD0B031D5441BB387AC671FD547F13CD17CC28249E2B44CD35B131B9ABDC 787DA809E591FBAA62396ABCE3B49A69E887A1CC7BE905E40807688DFCCD3FFF 73F7209800DCC3EAD678B22BC018EA5C542E02B260AB15CB99918E62F1DDBF7C AAF6B1062F5316D5363E7FE5CA1F5F994F9777B3E1AE54D779B12564681CC8E1 B451D26C5E1B8006541D581E6A540E036C71DC38060FFD642D6EEC6920047D2E 8A9CA47EFF35BCF3BAA6F03A838429B1CD732666C234D51F5F8149966459DEF2 BC05D77261A6E0C49F71A972F8C4B8737385260A0E64B91BC699993F6686B1A8 69CBBCD6E25A7F1BFF47AC5384B946D3C8C88C5502AB516A4359717191878E83 8F9C98C3B3616E9A4D6D210B63D385B1C2658207D565FD307440CE0D2E25AF3E 77FDE10756FBB77BED933395C71B311E82989B0A96F986AA3574B4EB900249A2 B5204FB6B44883E6CA0B48CCB106DC3DEFFAE72EEA1CB5FC81657A04EF3DBB5E 7FD1CF7E91542D0D8459C6CC9A59496E2804AA8D5E1A8AB391835BB11992AB62 0533CD2FA429AD4F79519889E258B34E0D6886D869E203A563B306B47A64923F 1E1CF9F947726BA21FBE257CE387FB972FF9439D6EDCBDE15ED0A8522D8334FF 6855814DF22849046FBCFD1EFAE049630E09FC526B78E43114E890E434700DB9 4E4D41FECD8D9DE72F7CE92B2FBC783DBCDC55AF87238D8FFF72E9D07F8B9A09 1D14AA689B734474D502D7ACB221D8BDACE6797820C73EC63A2A0F78FAC57212 1EE4BDC23A1FA55D8CC7E3B0E5B936292B5403A5D81EAA7D80FBC8E2F15067DE 590A3FB5BCF4A9A5D9BA2A3EDFEFFF7E37BC3C2933CEC7229536801CBABC5C5D B44F55E9879DCE63A44661C16DA2094B391A001E95B685E616E356D51996EE38 DD8B36CB4CFF7B910A8DCA6CBB10DF29F2AFC4C9605CFCF243277FF668D3CBBA FB43F5DCD5F0FF9D8CCFA3E48946F583658B4A6BDD472FEFEFDD1EC4FD124D48 563A80C56876C63F5CAA39219847679AC1A34EED04D6998D6325FD10E639E9DB 566B2FBE2A7961059B83F10BA8F8928AAE8D269E4D74A249F3A25E6B9F2CC57D 0DD699F37EF97FFCF5CA99A3A6BD520AD3128FA499B12BA67887A605113A8F90 E951E7349F4C270496D301DC7F8B82D31FA746B7C652D4983428938B85096180 72617223CCC5850BFDF3AF364FCD950DDBE4D17D75FB73173C415B3F7C57BE58 0EAE6C2CD6178B39473628736A00B394C7566F4F8B04444A9C60B946C36736B2 3CAEDE53091E5DE020C2B5060EEAB9191734E67B291A0C9898E8CC9398A3DB22 286AF139EBFA37773439C8101A16785788284B3458C1E9BD0911A585A899D686 41E0B296451C255A96BBF82E7663EFC6E29959AF890B9E698DE1F8AE567858BA FD6BA3AC28973E784F7A125AD662A60ECA38666749F8AD8D4A1B14F589E2D2CA FDD2344E955320043982D549F5E6C5DBF3BF70377DBAA5F331031E67145F1FEF FCEE4B789D0E81D3EDA625747689D81C0DFA5926A915E742A702CFF76DAE035B 1CB3EC45467C630421B12D2CDB8D922C15201130967898E91D09196354163A55 D41D22629D17822050ED79E0D564CA0501CC4119D29A5A1357B7AE68A963014A 2E369AFBFD5BD8D8EF32EB309C7DB02943B4FDCAADEA69DFBA9B6484D2DCF254 0C5C0ACC30AC69893004A6EC414B43D38C37356F36D724D30E05132FD44CB7B1 63821C7CBB79E3D3D7500FC78A5E1DC55BA338CD1585BED4145FC786B92836A7 5F6529E324334556949A095E1A7A94F1BA69BACEB2E53421B6510C67C7273E7C 8437522D22359A58D0B870C9B85003CD2041F8663A3C1025A84D0AD94B472141 FB7EF5775EBE06FFF4DE4346954F673C4F8FF6D19D617010E9B4A25FC014F79B AA266AECE575E6D54A06431B731B2A6E3B7985D2395AF124C76E4A66F1C2B275 FDE23EEF3753ADC4F27880B2884F3A813383DD4A69733E3C7C3A98398A940564 2E6D2DBDE5444007820A2813A6C179C7D978333E79A62657B6D5E956E5F4BD38 605C68118230659211927B57FECB0B57FEF41A569D01453B3C1AE672CCCB212E 17009BA76AD5B5E694CB5134F7F1C6F19F3F625C428AFAF0A5DE2BBFFDFCCCC1 E2044C76647935CB6F1BB65B2A33524E03A1B9EAA0523681AA896CB95E799B6D 55858767A2959F0C9CB7493C1268A43532A769A5F70A5E3F1B61E6C76A322C98 5E31AA853DD22B4234928599FE166CB6E2CF3AFAE750922858F4CB31CB06DC74 4E4938126508C0A828C38CA72937268708D9B60D2D9A6B75A9FF62EAE4561AE7 0360C972C60B1C9DB334CF653AF784CD4E75E1E8AC64FB3A71488C84F145A546 A0790969E6560B01EC81B871EE6B6B0BCDE3251B73315A7AC7A1A2A97137B7B0 AD11A5A89094DAB4A04E5280D1482531A09322351B5CC37AC40FFC2208BF17ED 9EDF597AC7A2FB680324E5F89903F72A2C7E01B8D02B73915153EF8013A9738E 828EDA2E0FBEDBA5073E2D1DFD341309CCC411C210B5B902519AA5C6254E05BE E3E85C0285C58CF4AC4AD66791F343ABF51F3D9E93B17EBC4CF8AA4FF73EFF52 6D0C3D42B747FB8D998629E3C933ABDDC094F0348B91AA3FF9203EBE6C1AD080 ABB02FB1CF4C970AE5D4B78A09E4E3ECECF9DE37CEDEBAB2FFDC7EFAD23E5F1B F26B939E06E41F6B55FFD9EA7D2BDBB75256361D477F89A11489EF3A9A8668C0 261927BC6A3B9A8924A5BAEC91D17AAF2BC09AE35E8AF28DC14438ECF678DFF3 8966FD99446C66AE9797F7EEEEAC2C37DFBEB0F813F5F652115F0AFB7F329C3C 9FB0DBBBBD4595DEDFAC79F39D6F8E86DE78F433EF7D074CFAA3F5DDC30A3F68 DBBEA69C954A948635A8ECFA6CB8B0C81E7D1BB87D802FDC1AF6377231C1E3A4 91D25D095E75D156ABEEAE1C7D6EEDCDEB576FFDEA8347DEB738737DFDCAB32F 4DB61BF3B768A886BD93045BC06FAF1EEB67C9767F481A756866FCF5876072D4 F696207489EC2CB617ED6021C33E282363FCC5FD091789391AA223B443C8A8A4 7D095E2BF2EF66C9C55E976B9C33CE5F56DDF28FD569DD49EFB1C87D3FF844E7 6D871EF8818783434BA50D629542866951326363766710C7DF4EC8BD73283A9D 2E33BD2C940608A72533D3BFD151529A711B4430C149A939A0391A35D3CD4CAF 7302376E6FBFF2BCDF719C434DAD2BADAD72F3AB97EBCD86FFE4D281EC0EAFEF DD75E484AC295181C06B122FE0456A8D86657480A4FEE7B61C38832FDF22FB4A B493C67BEAB0A5BF640B363A59809C2C55BD54EC6C503E018AC6A58662680B6A 0F3A6B7F7E23DBC1396109565B39D1A43635260DD0140195C0453AC2CC8D9983 419D2157890673AC133CF606CB8FB46599910C698990385A8651BF6B6FBC7163 E1DD77C147E6452360A03529B708E7F2DB71F1E2A8B68463BF0B3870F2408B0F 9D56F59ED1EB61679D83FD6EBC248EFFE40FE42B241161350EE0A875E3F73F6F 877ACBCCBEF6E216F31B7B19EF4B6B77DC9DF0CCA616D6204D7522520EC37E59 B631AC63D4AAD81803DF2D7D37E8760709073A0147806E6AE2AB593E63165401 50BEE9B7E25ED5AF3B961403A7A6EAF375ADC18A2246A67A82140C6B6AA2FFCF 232C27D5703B99AC4DEAB89682B19CCF971F5A9EF4BA5B37B74EBEEBFEB09596 24F1B546B09919B166BC74A67781046A7639BD739BDAD6EB383127E33A250858 6A0924B9136920D48A70FD8FAFBB033B416C2D2E36E2BC9FF13883F9F48C019B EA3D536467941A400A226E068C5097326CCA95CB866F2F53BB03DD0A4D41B377 E4832B6A81642027D0D8B011E37B4EB9CEE19A7E5CC63B374399FBA9CEC62AED 43B9ED547EE7A52BF0F30FDFA5D1AED01037751006D32A7C13B653EB1F038958 E76A246C2512A553AF19ACAB7C92570949F507D6F2FA546D354842EC44A1074E 3F528DF6E4ADF3B2449DFD6CB2910F6298BA18AEFAB520853E65C2E9CE9DA1AD A5461AA63A750134C9A5CE3E6D002780C445BC70E9FBF1F1439677667F7B46CC 3EF28ECA4C1DE8DCA35781389C61977AE88AFC8BBFF75F2BFCE89E54BB289E24 4934E11B365E282D0D84C7026F017819189327D5A3BFF2009ED15AA4A2AEF2E7 FECD379BB76662A81521BC6A26D4883E90A999DF620EAD09A28E540D5856F278 A916DC65B30EA80FE0EDE59FF2179FAC899DC88AB57A4DA9E884AFB1B59746FA D743311E645A17A5BE6BD57D47E5995E46EADACCA24D8B0565468B110EA4D522 72609B19C6081725EE25598410B7EC5073000E5CCBD1E922CEB362AAC4CD8581 A964C5E624A32834C96833D70345C5D60B1F5A015A39324FEB4C4B4A6EA6ADEA F8A895C2E12A759AA9B5AC144E4B501FDF22B75EEC1D9D3BB913DD3AF4D88273 0484B28B10F39B6DE0405EA731B1D538730F623B4EF4A3166484E18CCAED1484 D4C9E001B9FEFB9796968F56DE17A4CD89BD5F1B7FABE70DA4FA19C5806F5A1C B1FE2E12256628BAE41265F6CEB30378D56EE25A3FDECEA0B95196A58E60C43C 5F6F82384DBAC3BEEFB17AC5A35868ED4EB1AA08AB4BE2F99FB9BB7CE76C8606 1A3A2D59D53A6BEB8BAFB4636A23BC33DC6DCDB6745E4BF3D4ED3429B378CE73 0B05EF7C08CCB74B34F563A615802B5459A5D41AC7A160185F3B77F17FFFE3E5 03B237B63F7BBBFFC258DE9E645BF91860F000427FFFC403BFB0358C2D35F655 0AF87CC65C5C59A7F1B37CBD56B1EEF1EA6D4DF415F2A9FBAC0B612A63DBFDE2 F54BC3542DFA0B1BDBFB03CFEE291947B94D88C8E3854EF31FB4DDC7ECF946A2 C24076BDF2E5CB379FDF1EBC5177E7665AFFB87EE8913DFE4CFFE01F86D73EB5 B4FCA92377C324BDB1587925DE3E15258726E2663451015CC6B831B3BA796869 E967DFBBFBEA6BDE77CE7B6B9BA61755E75BEE0D6A56BCE49CAE36E83E7FB522 7EE26FBEF836CFF9778F3F5125BB2FEFD4B737814A47FBDEE83C4C6F6FF57F20 983B3DD348EA60278D3B113AE9D40F2A93BBB9BD52F1BA794FA7A07A0A750468 E09F8844A70505532B1AF951BA6E2FA28CEEF4E38B697CBDEA5F81F8F5ADADC2 F8C4E91C6D69F133D3C46E357F22CC68A70A9BFECAB1C38FBFE7C9BBDFF59868 B849C94921CD1CFDE96C3FE33C0FDEB2DE995EB84873E302D5FF1F08A748A94C F2A79AE116962CA8F1BE31F9CDA0A1CA3527863B9B7BE75EA19EAA1C9BD3AA82 DE12DBDFB9D1599AB31E9DDDE8DE2C0FF295D5E38A8D64C3529516F52B5996B8 690C065B20CB8C0D0CF7875FDBB56F687EBC8D1E2B9A671690EA94AD593E6F7C B17194CB5B377116950AE7A5DE0E38A036DB54C9CBE2C6F747C00EC630DA2B82 284F8C05B3E9892C6D63188E6B41056995AE8A2A81FA4F01C1597DB0F8589B1E 2DA466C0DC050EEA5A999DFAFEEBC5607FABF50FDF9E2F6A09316B297FA4B61C A0A2CF1FE08B79ED101D595B96A2561A68165E985336A391BD8DD99737CE9FF8 8DC7AA6F9B4B40163A51472DC5BFF9D2F8EA5EF0D0ECB9672F2F0E8F6CE7F926 91FD3E3E88860288A6EBB5A9C3A358A802598431D0F6ECA645ABBEA5785AB535 105686BD61A8E56DC9E2926C0E27A9190185E6EAF5C58AC734CB34B310A2866B B9D84516282B21AA724C6A42B0D22A5232A20E834261950DDB5663B252DE04D1 B56D33FFB596E37BD2C36766765EEC76968F8BBB335EED06A1ADB59A01427A47 14CAA9BC9A1AF59A7A993B33484D2820A18190954464568835CFBFD5DAFBCCAD C6D84B147D234C2F8793DDA298683960A6C097041AFB29535BA8E912265C1853 76330C5F985A49FD4B150BAD607BC96E5769C6E6BBB34FCDA0653F8269C54320 892027B4ACA828174921DE7036AE74E3313573F9303800C5B65BF94F1A083F77 FF2AE7059CE29DB863B0695C81D49DD1DBD36E598DE22835079498992B5E654A C130D002D5E066095B9E53D729596710895A4707B595D9172FACAB48E742EB20 B5D77232527CA90E6670D1B1FC32053EB5EFBA1F3975A9A15A920380322DD3CD 52910994B5F5EB4E9864A7EE777440662D41DE7BDA52F3C612DBD7E05A292D07 64C9777EF32BC95F88197BF53A5ADF07F16028F61965B975C85747DD7496D68A CC7696C943FFFC21F09088ECCC1BFBE77EFD39FC6D11E1858CAFEF92F0520EC6 454566322162E850AD4AAB12B4415E073C00F890861C300F41547934BFEB132B 40C3F968CC90646329AF79E79E494AD80132BB5D8EA04215E6552DCFCCB62B13 07C300D380B0AAC30A147167E22CD072878A114A0A95709C4B2410D6D1C1CDE6 979EEB722E782634311C8B6C6C266E7BA6982A995435EA3AA40AA94F7C1D0211 1AB54ED0FA31928048658DBA8ECC6292B34C1268F93E6982A436D28FA89A1EDB FBFAB8D845122BF5BEC1E24AB574634DCDAC4A13353A1C08E65018E560770432 6554A726215C7F20674C0E5277349BAE669F1B0FBB07FE8F75F2C392C456B55F DD7EF6527B44C29FEE54326E158695155AD899CB647754022DFC8AB3DBF2DBAA 921F193A2AD181116665CA6D629506F7286634CF92A9E3A2B419B16D0BE0B231 4AD6DBFB0BBFF1945AAC38A59583D88608F482FE9FBFECEBD857F9A83BF2E767 8DE78648AD4E53D3CA284AC47CADFE830F25359F71BDE5ABB97253A609591D15 C02DD2F28D575EFFC657362F6F3E841702AEBED8DFFB8F97762F1D202599261B C77CF0FE9367EE4DED6312C1EE9EB21499695CA1E225D127E3F0C7ACF6494CC3 86CEEBE56C4C344864B6DF5768978B0BD1F085A8BB5912597A93A191BB33967C BAEA7EA2AD034DCA705263AEA619E76EF69EEFEAE868C6C9F62757F0BB1BAD73 63EBCFFAD173935BFFF789D5150706333E9E28D077B654F50B717873FFF6C71D EF4124C032BBB510748E3FE8EFEFF183EDEE3887A3B4AA347D9994ED9A3DD7E1 9A8F434442F0D5D7B7FEE5A59B4F3FFED06FB65436186D0DF763A51941FD5A46 3E77B03F81F9473BED1F9AADD12A7EB9DFEDE9FCE6A10597DE85D112C65D5C7E 75345CCBE18960E6942A57B0D09FDC93759CD8D7D2D1752EDF10D97E196BE0BB 05C8F7FA23CDCD5AD2D4FF0D209F59704FB598A6DA2EA5C766838E18CDD8F689 A77EF0F0C7DF07571720C7566E0398283B4F09768A69F7FC140EFFF646F06FCB EF8C62BCE3C203E4D4FB0F0B3EAD26C5E68A0C46AA1094348086A8F8FCC1856F 936D891E3EC53CE43DD33BFBEAB3733FFEF05CA529AF8CF1F25C51CF284800A4 797BA1F0AA4C0A960D8D8B44D147C18448969C1D152FEF3B5D44E617D97BE727 ED8D72B605FDD5B2889DA82C6EDDC2F10173351094B8D0CC3441D0EEAF8137BF D2AB8CDB764A6ED9A33483DD4C273A1F1482305E5851D546ABD0B3D21CB94CD3 DFCA58C187F8EC0375E16F453660455D635BA1A222777BAF65871E3CADDE4B7A 9DC42A8F056307E02E9C1CDCFAE21B41DFEAB4DD42F4F5A298834DAD74425515 1E8528BE22464769E7574F080F5B232D76ACF8BB6F6C7CEED2DB0E3F796B7D7B 7873D8CE1AE3707CC0C473423E934F3C62FD80740F5B95C49806A76D15D6A868 741680B403ADB640A21A2394B3D1444419C905B9C2E3EFA1F14699CD16F47EDA 9E47BE2BD152A5818B3D9DB89A95AC12C8C99858DE12AB2ABB36CC8A5D634F60 3145E6B374DEB12EEA9DA4E9EDCE06E85FA7D5A252A569FD14630BE2DAE6C543 0FDD45DB4A3A07A6130D103386BBF0B460CF8146E818E10469C02A3D5315474B 730A05BD52C3691961AD3C651B5CA5B73FBF51F6DD092A6FE5E9B59D389556E1 9532CF1CE4C4922B665C5A415E38841270A747DFF8A441AE457DC940D969C2D5 365D8CAD7AE9068F79D6934838599114C48C09CAB01690251E4DC662171D5C2A F8BA0B126F9CE53D067A73EDDFFAF6CBF04FEF5E32BE7798628CD574D0C9D4E5 08DD719F90A6A1CD347D9B8646212C64A6CF8A421AB769689CD3F5C7AA305687 A8AA1913A2CA5B5B397D6CAB17F736C65804FB31DE50646BD2ABB262D1A50D62 64B30E8AA696D5C7347CE04CF4088305C7D3654A29F6F3B479F1F5F595A3F5D6 421A577AEE13A79DB9930529002D905E5C9B62A4865FDD7DE57FBA580E2B6150 7479381ECB9BA8A09CAE78E5618FCFD22A2C5CDA910F7DEA0C78B733B6C26ADC B8FDBB6FEE7DEE368147F2F26043F5DFE4653FB1A5E95F1523A6B5B55D51A00E F29ACA6A90ADFA6885CE5294790FE66FFBC882508322E390A7B696DA372BE7BE 3E52B20501DF61DC4C312EA95E046CDA8152ADF73D889B965DF56D0E2350E356 07973B840FC1242B72A945212DB4AE2F4BFD1397DCB6ECE9185A63E815F27454 145C6896833C522E54AC0629592E6DEA262A636DD839EEA2208A644C40CDD3BF 06928CA4C8A2B6EBD26619BA438D67D6E6CCB5AFEE0C86E1E9779E70DF999949 C85A12DB250C2CE4B918DB1AA2CA7002D3D454316B44429AD6025153B1886AAA 95BE14AE9F5F3BF4F00A3BCDC64E6EE18ABD4B0F9E5B6BE441FA31CFE3053133 DFA04E609A34E9FC1C69B6AE45FE7E997E2D2E76FCCC821335B5DC29CCA540A6 D98119B58C08C166B8B9D27210BA9EAD85821F46F9DDA4FEAFDEC9034D7280C0 39D5A972831CFCF5D99AC64E9985BD71B0305F1897D2D459688BACD0D29FDDB5 1C3C712F775C9211545605F5956DB08BF2526C5DBEF1CD6FF6CE5F9CC3D53AB7 DD10F0D2792153FFF9B537BF77302C8CFD183B7668FE23FB38F3D468F3E63BEE BFE7EAE8E0D278600BF8CEE52373E6685DD4FB63DBB3272D17AA54512FA3FE8D 2879BEB773A5C84625298566C8A55709169CF221289E0EEA9E56FB8ED25B4D6C C53737C2B35E75B3569DE1831F99C1F373CD4F5FEB7DEEFCEDC30BED5F5AB296 6CCD406C9601BDA81B61FEDB572E86CBFE03C1CC0F8BDA925E90197C10E44DE6 E407114F248832AC724600B62CDCEE88468070996E753792E2B7CE9DB7ABF6FF 7AD71956619A8E6806250A3C4CD973BDE80BD76F367CEB8797DA4FAD747AE5E4 26C838711A395F2E8A59E390554C8875332ABE7F7DCDF2D463CBCBC7A497F58B CD617A7534BA6EA16D4B318F75D3FC064757FA91A1E2B0CC353996C5A98EFFD4 C985A7899D8FD283AC2F5AAA6E393E7416DEFDE8B14F7EC86F2CA35847AAD4E8 234D111778AB52F00E049AC932A0FCBBC922D36A0463AE828D5BA50142A44C31 0A500825A63FBF7034C584C9C5F0EA0BF19B5DEF91D3B4EE3A5FB876E5E0F6C2 8FFF80EA85F876E49D3C96573995130C58DE99959536D358C58745AF10791FD9 135AB2EC8D28FDFE8EDBA3A0E23A4FB6D3E3B99C695AC10A178913976A7B5B0D 770935D539FA8360C9B53AE107C195AFF7D506B153BA41FB1167BD0C16880255 300A00150E2A16895D2B31D5C18C796091D6BB95BDE001140B4B8E55A4BF5593 CF0E6EC479D39979FA6DA59FA35A7D62EB5CA0583E29FA93DB5F7CA5031A558F 7030501828CE64AE318CA30CE290AEEDED9FF8E4C7D9BDC141E59A276CF65DF2 CAFFF5C5A3F7B574A877FF26235965688D53207643F46221CF450356C893AEAF 577344C0A156F52492333CADB38ACA84062F3F009E2335CD1DA56594A13051BB 857C331F279A9E66790E544E71033B773716EFE113CF75A0CEA735EC541AB70F 86194C1796ABE604A7E4A08C317301A82A1A62E3EF5C6050EBDE28BAD7263EA2 AE93B54ED626B437B247C71E5B953402542A8109F43538987A5B9D0B68864D79 092A253561C58CE31F006C5A3D9A2BA45FB0092F7B9B9FDF123B653F8B7774C2 15EEB86403309964B1D6D4A67901192AAA31D4B71C2DDA0A64EA1CA47EAB84DB 8054A6C5F2F335B894D98144F8946C7DB85538B9E05A324AA4E572414189B33C 163B60FFCD6C7C1538A2992BB021E2DD46EDB79E3B0FFFF2E1A3D3DBEBE9A9FE B4F3514D4F48A7516CDE484EBB400ACD5F8AC2668C219CEBFF2933BC3633BE5F A50BC162A5DEB2182B14203B7377CD20D7BE75791765B5DDB0DCA7E8D6E840C3 F19C5EEC525499D5A09AE046CDC5F2D0D18A86CE2C4F4D636E8930B6202C2064 972E8CCAD2BDEF916A6ADF90AB33FE838FA455FD488C4F498173CB83E586FDEA BF7969EF82C62F6792679358BC594E74E69B77D161B76C33DF03BEC4E3FB7EE6 A8FD732B23AB1B8859F0E5F1F3BFF3ED4A7755B9935BC5E07A51EE4566185088 F221023AC7550109705E55BC8DADE315B70D3CA026C11971FAA78E88729FE739 4A735B03F65EEDF2376311D7F2225C133136036D6DD3F70705450503CAC7B86E 3BBE4D6239B666883D87D3EBB9087161BADF712A8071A74548F3E19C733CAD2A 06526F48999B3232AAB3579215350B2DD7AC3A544CC144FF9E5B748E372B3338 2F87C0D49B3326359D2C329632DFD10F45D9694A3317CC74BF9BDF7A75D75BA5 A73F78182CF58B48533807362DD6B6041034C745375559426C4DA7A65EF71C52 608DFC03066AEED9DACDE7AFC3BBC4CAE30DA9D2426F77E2E36D397AB557551D F181C2E642F32F094DEFD374429295EAD0B4A49339E2BBD9F0B214004D5BC334 1F98D61E03C495B97060C6525A696DE75AB45E714D8BF278ECBD67D1FEC70F66 2865021584E342A14BC5F6572FB6AA3E954532089DD91903842263734D9EA549 21AA3F70069C5805D863DC29919F5117535F1320D41BED7DE3CF77CE5E3B5268 08CC232EB5D26FA44E86F09F2683FF706DED5A64065BDA54FD62B0B2A6FA3507 EA805A8B475EBB33B793FEF8CA6931DC6D7AE088D22C4D0D2D85ABD0855E9CE3 57C7E1F3C978D7A2DBE34427CC7A10548BEC0CA34FCCB7DA806BEDCE7C7B308C 37B6C657737516A8B8141F9EA97C70CE19B56AFFE47B6FBEB035F991A3477E32 3BB07DE796A071CE4CAD5C1DBF1EED5D1B0DAAD03B09DBC7905D7772D5882BC0 4A0660B340B1225AAC0B103B44752CBB4DDD23F5062DE4EB7CF27B7BD70F2F2F FE6B6B46D4F4D6E3CA4C440544D29BFDF20F6E0F9E8FA38FAECCFF6CDD4E68F7 25D00B27F51356F5985FD3816D8908C7594EDC35A86E8C86735E958EE52D2D2B CB5227D7AD0ADE55938A6B6B41DA47DEE62022661C99296DD251FB94E7FEDC3D 777D148532B387817D56ED65225F6435D1B4EFFAA51F9D7BE229A00263250122 5364AED0DF01E1B4856C2A0AEF540BC2BFC3428D7BC67A1C496E2C0D01360EBA 302E35C1D67083B4CE3E2B36CEF75E59AF3E709ACC36ACBF3CD7738BDA07EEEF 5FBAD688283BB61CB9FA1B259AEBF3CE2C0C6689DEC9A22B4359447D04270CA2 E2B6E87FFB76D0B374C8D20703EBB176D1AAD995F90C70969468D0CBF637A0CA 90205387D7C28C8CCE67D6BF33E8BD3AAE15FE263E1871AF97EAFC6D2EF775D2 A39AC163D1B2D00C0D7C09523A6E9EACB59F8C752287C487729C912EC335B23D BB7773D4FAC461759F4D65934435518500EFE29112BB65F71B2F74824651E6CA D18CB240B9870B0BCA380FA3C90EE9CD5B6FFBE4FB919FE68D10AFA9B5DF7AB5 E3B51AF7B017BFFED2DCFA6952B4DFC49B37B3BDB5097A1378992C66019AB3E9 463EDA2B9293BEFF8156FB0802BE22398F6153B96DD249582E409A9124055986 2684451845619C66F9061317F9904878DA9B7B1CF36AA5C69321B38B99439D49 996D7777358199A92F2C763A088CB8ECBA01C9A07E6D5E5A9C69FA9E58BDB52C D91658C35C203A27FD03B8593DEE078B354EBA9A9C1154D5D9C3A0846904E6D3 BE092CA7F7C3881A39854D378D663250B20888009DB56F7C6ECB499D02A92E87 DB09BE9D645D31CA98D6084CE4DC52A50B70855855CF8BF22C543C45A569C4E1 8503AD2AA13376D976D53152AF029C2E0C673FB220AB5C698634EDDAA705D53A 958B420D54BC06765F8B48EC6AACD95362B352F98D67CEC23FBF6F15BC15A1E6 F4D6A4E5E994D1B7E61D2853F73A9D92C344317533999646034AB5284C389F4E E9E62D66B72DDB851A0173AB2E3A871AB7AEEEA43D3F96EE864C76C4244A0B1B E22A454D1BD7806DE96FE70C5756FDD9A59942448824A064582F341C409CF1C9 DCD537A363A7FCFAC241CF4ADD271E25471754915BA61177C23C0546EE8D4F6F 5EFCEC869B9B36916E9E5C15519E670D0B2E7956DB38D67A3CEA1FFDF0C2CCBF B837F4F76DD1B6AEB8DFF99FFFACF6CA2CAACA0D196E08B41DA908C811E67169 76840F8C1F6F158A59E21CB79D8EFE3672C296F27B7EFA28A8F6B324255A2464 02F582EBDFE1C5A09215830DA059B7B410ABFB816321A4125AF20AD240E832AC C6C5C05D706807F31B054AA85650B116A0B9716932CE41453E6D4D991A6009C9 3373A2042D271144ABC22AC3F30EAC21335D7BA4D16CDEA9ACB8500B1F250CE4 026ECEDE5D2C5C695519D41C41C40EAB881DE7D237373166777D6811AF445A2A 1439B32B33A455CFB47E9019093330307E5ECAD6385A629DBC3847D3297EECA0 BEF3E5BE64C5EC07AAAA11A289A4661A7E5976E1E0E549BD582ADF3B30FEE3C2 6435C9A651A0711F522D6E2D69AB1B6CEFC5319C08046C21CA38E7C628DA7509 B1A42AD234716DC2CC58576933E3DA926451F5478F939F3896408DA2A4B00453 447D6F7FFB992BAD4E0D15851AE7B4D348646E6BC86DB85AD0C404CEBCEBD16C 562FA8CD544D616F4210D3723C27F18BAF46DFF81289ACEA04A271A49732E2B0 A23F7D9C6E54ABBFB5BEF7C79B3D9EABA6E487E7E6DC246DD6DC8BBB5BF32796 0E6EEFDDDF5CBE97936399589C7195C7AB45B1CA69DC507658163078214F9E49 A3F55C24369DB82501F13B2CFF13F5F9861658BEC8A4EF7493613FFE9EC8CFEA 672FE5215E7C7CB979D215FDDAC2BFBEB0FBF99B9B772F07FF01BA11B3FFCBE6 E6852C8B019A59AD9F9AA936C32C0EF39B496C31B242E04A8355477C50785F8F F8E5B848F52EB4B54A16F3397C4F09DF5D6BCFADAE7CA5B7F19F77F73EF4D0E1 7F57F5532F6659814A3B87DCE1B9CEFF5FCD834FEF0EEE76AD7FB2DAD60FFC32 0BFBA3F9B81B422EDB013C14205FE74733FB45BF8FF5F2D6E6EBD96407035CAF A7C362A0F211E2B9C810A4BBBD64A237A1694F3575F05551FE83F9857F34BB38 276E8C6830AE34739F6EF4F60494769DB69FBCE7D8CF7EB2A82DBA0587452C19 40775C6CDF02C229BD2EE59D396CD31FCD31931946F37740A8BF29344008400C CDA8794F07783678850DAE0C5EDDF40F1FA18B8DFEE7BFD77EE0A458F20EAE5C 6BD7E759238849C14A4E8092B5260E96A04E46B0572645DEEF524D4FB152FBE5 DED737ABFB7ADF8DB32365EB3DA740A78EEA0D0D7C3891288ED2EE2D158D6D65 9A42211045A137C4CCCE4BD1E6337BB345750FF7BB59B5CB89A1AF24D3301928 BFE16097890EB22BC2F852CFBC6F8ECDAF4B58D5BF41616CE75AD62DDF7C65BF 72DF6AFBE999ACAEC5FAAC9537A8CA957B0546AEB8CCC3EFBDDA9CAD0C440A2C 1DEE451E431F35EC382FE2F4EAC6F8F04F7F403E08B19F380773EBBFF73219F7 96DE7E7AF4D2D6F6B9411E6AF6DBBC36E617F3CD8B19DFC4D5A66B9DC0C44B92 C84612A1FB2CF7F15AC517A919A0679770B51CDBE1C2B09AF3B2D47F97D2512C 37443E2688A4E5A1DAEC6E16BFD4DF425AE00A7CBC097DE6C224B534D8CE91E6 82AB3FD1EE763CEA16B3EDCEC26200DD01B4075204BCE4A6DB1670CFF6416CEF 5F1922CD4B10663555D4A289379E3F7384CCED179AD6729769C9823961625A97 6F4D0DEB8599384DB0164CA675855B9AFEE4F6080317BD106C7F6940B996A4F6 28273787F25A34DC4F0739A3B90E0F2EF4BFF730AD60CBB1689AE71A0843CDB1 4B4521D23AC42BF1A2A5132F386EB7EA088E5BDD851F9A458B64DAE3504025F1 745A9BE63BE544A25D7BE7C57EB253D0D24A98BD11D47EED9BAFC2BF7AF0E85B 2A707A9C8F10D140580831B5947B8BC2DD39359D6A97D2943A4FBB94520D8C42 6B70A6A58DA364D3B69A9EC78444F6E4F099E6FE66AFBF81A0D5B9990CD7F3E1 80EB98D54C1ED571D904B8ED793A19525B1E5AEDCC2CD8B9D8259A6FC14A5E76 89155B68E5F285848BE1BD0F3727EE3EBBFFA47BDF8958700D3596DEC8E6288D ED7F3F7EE1DFBFDCDCAB09C23665B427E4301BE9C59AAF54DA169D439695C4FE 7DECF86F3C94AC6AD5E1DBFDDAF7FF9FBFAE7CC6292BE53E28B638D84E445765 7D626CBB588A8C618705AAB89C27F68AA2ED80389A4BD6F9E91F5B8547E264D8 7372067536EDB15BDF2EF21D1793EC3664719C4BA13CC7712CE862E9615181B8 E1385AE9A530B266EDB2AEE49A00914E4720D1FB472105A92228157AF7109D23 FE3FAEDE03C8B2E4BA0E4CFBFC7BDFD72FDBD5AEDACD748F37F0437810A02452 E4D282945614E5B9322B51A2A895960A29184B29C40DADA80821965A0A028D68 9610810106C080C00098194C8FEB9969DF5DD5E5EB7BF76CBE349BF91B5CADB6 BAA33AA2EA77D57FEFDDBCE79CCC7BCF35BEAEF301145A3651DB9DA5A66FA5E6 59356392CF4A91D096ED1DAF705F6B65E9204B944C99835E885D02224B062547 B95560A73CB6F3F5EDFD83E1C6BB4F349F0E52B1072D407C8F54EBD0894CEB69 12A3E9D8D8F9488B49C2B5EAB0538813AD72C3FE4AF75B83513CD9F8C83AAFCF 941914AA3353466C594EBDCEB727EDFC14FAD0A11993289199126CCD27EC6ACD A8102F53425C356B1E7C6D0FEC2428B725A2195089943A9628B6F40B599146BE ED397A357002F4C2288B40D53FFD98FC504B4331C9B816782E0AE4F3BBBD176F 5516AA3C4DED02E185FA94CD7C63BA426788E5F5B0FDFEA7647D91A42E123581 ACC4A7AE5E52770F6FFEFE1FDBDB77158FDEDEED12E45CB01B419C16C5A8A280 5DD6BF81A2BF7BEB9D6BF1B45A8A292517A41B7A641724D556D31EB33A7559E7 F0CF9D3BBF00182B7A176B8D739A3BBB45A88551523C3F9B7E6D3070DA6B4E18 F678AF62C57FA6D2FC988A2A424BA8641CFB47C9F89AC85E9C4E9965BDABBDF6 28914FD4A08FD2BEB3F4EB57D367FBC3BD64FBCF5AB5F5D367AF51F1CAB877AF 736425791B8063AEBDB4B13E2D1234995458B1E0D35AD07AED68FCB5D124C11E 10BCD9B0954C5611F8F8B98B6D6175F73BD78F7637117CFFF995BFB314C0AA94 69414BD7522204B98DFDEF1CE1AF4C547FD6FBE1B34B0F79C225F0666E6F695C F2AA76E7E814CA9B8E12A5CA5870796FF8FC68B05BF398E63FF70E8FAD1E9BA4 2C466A7FD2D30C844B904190CF353C96E4E1C0F95FCF9CFE689C7277FC4EBDF1 D2685285B4E5F933310B2250D9587EF87FFE1B7CED4CA819559E315F51735E33 B76CBCDF2601FF7B2054DFEBADF853202CCDF1967176D49F53A25738D37CA9C8 27AFBAE96EFAE6AE152EC108EFDDB871FCA9C7F322EDEF6DB64FAD138B140210 079911BB6658EF3193EE9C012859B9D7B558062C260672F0954ED4C1C88DF79C EEF27B1E754E2DABB6CF6D0F6702F19C8D0EF3DE915F025C9AF6A9342F6C509F DE02DBCFED3666FE98643D56E9E55A064D393536240B3AF20297D23CE028D478 709E859F0A4AD4A38CE85F2E4019E46D75B5D8B5CA637FF971DE2620770008B1 4E6B3399576EDA59C49FDB19DFBA553BE6E76A3E9018C91294EE94FA7973FFCE E678DD3FF7D7BE7F5A19D6323CFDEDD1E67357CF7F622D1F0FBA5F12B2E30E82 D1ED78324A5B23575E1F1D16A4817CB12805E94F6958092CF7C94A6DC3478CCF 54512E57ACCA5967171C2E8876D68D49EE62E51D65E5D5647CA748B224BBB87C 1A2B7CF3A8A341C4362366B35610F80A785A9AD5F2E68AE64B44F2A8DFCB079D 5154F11774F8D7CD481A535B48A8C4803AC4A1442432D98ED940E90C807C3CA2 DDF69996FB78AA80954CB8164B88148E635A664C35BB32F67B26B3189E624398 A03232F679DE8800AFFCAADD7D3E333D12018967D6D6A8EC6226889CE6FC681A 9BF8A1C43163EF819958814CC54A264D89A783A94F6D2D631629AD38701506BE 2866B5DEDA9F59B1CEB8468CAA126B355712C5E763A439B33BEEF0CA747A6706 33C449B417367EFE6B97E11F3C7A5CE7625323336F7B44E62412B3B2342D4066 FCE1BCB342CDBF0F8D05CBBC8615991A67C64D75AC96359C135EEAB5510B3C27 D77778B0BEE10209766FA780B60F8A782B1BEF6B89005D0A601D8A050B2FDAC4 8C4E2E511095A7CF5A5E5494826B06A1C102D002016FD4433BF726671F587156 066A29F41EDD285BC6D1DB87909AAD75C43BE4EAAFBC8CBE95E96CBD45E28C79 87E9A116BEEDA8D1F6AD6585DA9CCC2ABD33BF78C9FA50538392C51AD79EFF36 FAE733BDD06690ECE6BC53967B3CED99267862179828045C1C20B908C8096155 2BAAA2A102971B9F5CF0DE43D369C7CE2D5C14728C8F5E04E91DAA49F30EF4F3 42649A9798DA655873618D801082909AF965DC17EEA2C7FCB2BC9DA2D85871E6 9A5E6A690389348A9059B63D27CE6AEEE6AA392DB6A82D78A96953A4E5B51218 A7991C34366A74D1C98D5515211003C9919D23FDFB6D47FA6466270C662DB1A8 6E586F7DF34678BE72ECFBDAC08935D6601D177547EA8C086C2A6CD11F2A9D76 B16902143A10115434414EC104C52FC0D1DDA9F55ED7BF64E114202DD2001368 E45A341F83FE1B593B3F4BDFB7AD4C59A07E0B186A1AAD1FB066C0F9DC8D9850 8D4C831707EC8DBE97574A42A65003E1BC04D958174BD7B57486D3F1A9112C08 2CD3B472228CFEE2D3D979840527A9A68FD8E536FBE29DC95B3BD15A3D1DCF42 EEA0766D564C43AE548075BEF11E3AE53F78815B0D9B55210B19A21A102B044E BEF2C2F697BE9EE7D3EDFDECAB836C33874FA1FA0F576BCB60DCC819E95BD783 C5BF7EEFDAB7F2899569F5EAB89AF902206D4A2CDA16B6C74554F72B758BECDE FB985BFD487BD966396A7879C16F67E99B367A4B82DE84451C2C51F6C46AF058 C55F893593A4A349BE3DC22F3993AF94072DAFF534AA9FE0EC5C3B6C875CB3A0 1D54FD8DD7BA3B6E7D023A6F77C7AE65AF2E5681A76477B26CA6C807CF0E3619 057F7669F5A3B4E60AD125EC75C99EBFB7EB47C19A570D338DFB36AE6A6A16DC 1A0CF73A1D7FCC2FFAB5A5206C12F1B1157FED5895B18C14D4D69800922910E3 2C7A6BBFF8C2D1D6E283B59F5D3F71AAC76E59D3E7F60F3A983EDA5C7E94CB3A CB8F3078613CFDFA7E5F2C1DDBEC0F5B7E233F1C7935EB40A0FD8439AED51B77 C5BC215087572960208B1F6935FFEE89D573D3A39BB595CFEEDE7D19A40B15EF 89A071963A36C9F215EB99FFE517C8FA49D7542EC49A2B5A82A2EF992BDF9F4D 6F864CCFDBB2BE37CBFEBEEBCC7F0342302F96318584C9FC9CC0132CE1E95B6E BE535EEFF1993DC559EC17A7D64E26F78E725A54CE2D81DCEC77C29A5FD8FA1F 87E055530FE50FA548C0F6C0D28BD449C5508EBED8AD0E093C85B787D7DB272F 860FAECB1354856D949BA1CB2A1B4EEFDDF693926AE4C7302D730C22D8F737BF 70D7DBC599638F58D0CFE1444C4A92E8B5B88C5B6DCBF1894EA8A5E5E6CDF751 F978AA591C2D33C50BCB5B185F97DDBDECEC5FFE003B5B661A26E2BA4735A867 9AFB25DEA186D6FE67BFA35520691B9320927B99BE614E162416DA0A6EF747AB 7FE562FA3869B065F987C3B77EFF1BC79F5A6EB4DD2BBF7F1D6D5525720EE8E4 4E961DA5568148D3D6B941DD100701861BD5A5A986E959BCE13B2BBEE62DDC29 D5D9D06B9FAD0C4017424FED4CADDC9D0ABA1567079C0D91DA1A7635D189AAAD 59A225296F468D0798A804A866367054B5C52BCB82418EA16F617BDC198F8E0A BD94DB4B41FDB85E33D834D4110D2F05A02CF41D3853076F0DACACE97895140C BD06F43E90C15A2D8B136861890A0BEB1F8591D66C9AFD40AE8899D1869413E3 41205AA6B83EEC53EE8C7F5F765F94339215B42862EF602462E3C9A59721D81B 4ECC79F2FCAF31032BCD5E3621C6A9D145B8026905530FE1D0588EA065EC3865 9A45C3C58F2FBA0FF885BE6142AF336CAAB30A531E2801737BAED856A36BDDA2 67CAECBB95959FFBF24BF00B4F9EBE7F3AA8AFB060A5216C18DFEFFA9817409B D835E007A89C5B4918673C29B8295E35C7011813C91864ACEADA55CFAB8350F1 41B5C59ACD70E7EE38C98319A4072ABD391D4CA103380D956C50B64CF8A2B762 69585483467BB27E2A84B450FAF652DB54D6EAD814786F4B2302397E49A180D3 3375FCD8C9B16BBBDC7504CA3D4194DDFDBF6EEEFDFBB7B52CBF8B125E0487C5 D12C17CD706121A4CB421E936E5FED2FFEDCFACACF5C28CD296DB87FE366F23F 6902A3259C3760702F4F77547A000A8DAD06BFF51DB28125795BA00768B5D6D4 EF13F1346B3FE5AFFE60958331D4D99D1538A3A357D1E82DFD4CB30318254CAF FE926B56EE5B4D9F84A068EA046BE6CB7054C1EE9257041C6C329C6080482ED4 28CDB2D20CF22D85865F3A2FBB356068264E304009F1A8741474915EDE88E1A9 DDC8A213AE7240218898DB51110A2C8713DF34C41744159E612CD1ACB1F3DC76 C6D8B18F2ED30D99CD66155A030D54BA44388494024D733589359B13C8F85C61 33E39968358A5D27BB95EE5DDE593AB3E83E8146605803CBA0B0389C62C23462 17FD627CB76816A7F1BB7724B294C64003841A96158B4B2735B64966C71C85E2 06CFFEE42060AD6CEE0438CC8DF39B6B79D84065E959C886A50E46CB51252CAD A7572B9F7E62DA2E282BED52CAD0D6E0D9FF9DD7D5CEA87ABC391D4D83D2211A 08CB695428AD163B75D8FEC8D3A8B958B0008B1A2A43413418898A8D3ABFFF47 D3E75F99C9F2EA61F6FC00BC3410AC33FBA1B60683C6D9F14894F4F348FDD2F6 C1AD94D9B957D07CDE2AABE6B542CA5778115A6BCBAD5B475BEF3AD1FA21AF71 699C6E04D1C045296377787A23B25E8DB378569E97F6C7975B673D018B01C2EE 2873F687E232CB362707D5C5E671373A3E4D2F848E1F20E228C7863DE47DF6AD 83776660B1E2EA5C7867DAD3A9F7825F5BC82D069DBB32DB117114B80F08F450 4C97ABEDEBB4FC2FDDAD9B49727AA1F100708F016B8ACBBB24DB8E6785D9CBAA 9EB06AABDC0D180C40FCD4B23ABDD4E030D7310133A145F89125225E3DB83DFD BC9C7CCB1EFCC34B8F3CD363A3BA265295EF0CFA63CE3666F2BC53FFE6ACFF1C 28B6671C6590F895DE64DAF06A3BBDEDC3D09B082B8484B16101CD383ECE29A1 F68A487EE9C1739FB055B5E8FE1A3AF9FC95D7F3850AA8F38BD8FEB8D30E553A 3A463EFC4B7F3F3A710A44A440B952582FCF3F9DB8336F96B83F8FF07E11FD9F 5A8BCC8150DE77A085802BD392A5A332015A23A940CA8CA7579C7853EC65ECE6 6CAA33C303D525B736FDEE35FB5C9B9FAE6891E689503682CCCD6D4EB05A92C2 D3F914C8986E4F509A9751AC8622F9BD4E9850F8AE60F3CE9545BA1E3D7D3E3D AFECCABAE9E7257AC5CDE2CD9BEE68667A3F28CACA0200DB4E2BBB5FDAE16FC4 DC5F9865745CC281986AA9AB574B9B56DAC8A999B3DB58ADE4AB1F0E8BD5AE3D AD2BBB24806677CABDC37CFD879F81E75DA017AB0CA9BF60C828CCF545E907E4 EDC69B9FFDD2DA42C398C902E1E511973827B390445BDF1E341E7B24F84B2BA9 D5755FA9DCFA67DFAE2EA1A54F2C6CBDB2977E1D05A2D275665BAAD89F5A3BBD D8AD7A275D3F92E23579A875CB31AB5D30C04571A6E254314BCBC452EA81566B F94465A84616216A3BB6583092F46677980915351AFBF9ECFAA8A3BC805AC168 927951E5FDCA23280E108E3CA7B2C02BAB5ABF690E9E0391DA82A63DBBB39BB0 220FD6DDC576D5F7A5A24549454672EA80C08AE2CDE2F0CAAC4AB5C0911815F2 FD71E5D452A9693FE5FAC122213468999E0AE3A105CDA479E3CF87A664148836 C868E1F69CCC3AFA5C9EDD08BB743A867139F33A133EC685E6D014FB895E39FA 1E1A533E787F76A3980F70AABAEEA2262080D4C57C2EB0E9C5408B961B21C6FC 71ED7D0DEF895A46A7589AEF1815C90D2B2B30F3472EEC91F8EAC1ECDE0497B5 71E5D4CF3CFB02FCE2E3A78C1180547CEE6DA93FF1B9F7DDF73E80340DFC1096 C62657980D7D332B44284490658EA88D478034632C312F23DF5BA2752213CF4B 1797BC4E77369CD05486872ABE95F5BA252A73C758C391C91292C7FDF5C8693B 582B8783E515727C4373FC11D7624539D8CBF57D9BF66A37AE772E3C5C6B2CD2 4975147E7023693608AF3B82964EA11C52BC307AE59F7CC54B2B33A46246FB6A 3229A486E3864F96A506422D8BFACEC7C2337FFF3D85976B21934FA7C92F6E6F 5EDDC7AC56407B2F4F6EB3E99E349D6FAE198E06134B3F38BE8CE843EE425449 1A3AE34F85BD21CEFC785346B1984A559416B747AF89EEE59494AA27BCA90642 0932200397ACD4DC1A14750C09D72C5D802A76967CE696785BC8A932071110CF 8A5203A734B32FCC8012036240B31BACD765A9BF0D61CD919E5436F1353E337F D63A4349A3E48CB1C291C82E21D360E439843A8A81943BB85456285B876F76BA 9B7BA79F3AE15F702670684BEA393559D7FCCB631A71CB02CDA6B8E080B8A556 F8662F47426163B4303B2847DFD8A267C8E253D5540D6DAB560A47942945B905 286484F5F2C96EEAE363DE131D816CAE239A58480B3C0CF2716A25661CAB0624 451C779FCE9E3B208348D8CE0C81CE6CC67216B9BE633B9A1668E88C6C68E2D5 16339E443F70DEFFE4996990D805273A1345361AC0C3CFBEEC8F736F351C0E66 15189146A81561247081587AB6D5F8D0938246B0884A5995A56B3B510A53DF06 933FF8FCE88FBE8994FFF9EEE0BB5AE983957BA3AC3BDAFFF9874EFF0C422E60 BF56F47FE5DE60CAFC6A6A8F1D33B81C9B1A46B363A2A337B22D97AB06414FAC B536D2EC07975783FD0E21210FADAB38F96ADC1948FC70B0F618701F089103C7 3A3BCCB87555047FBC37B8921E7E7261FD7C0E1C47ADACF90B2A773816583369 3523F0F9FDF12B7BB18B9D8B79D9AD826D592CC516CEC14E9D7651B154809645 A72C0BA0BBE8B7F684B8CCA71D5C365C7A3C5655860F6C708B16A4949784730E 068E16E95CE512F830F9C8B9A0BD762C4631D5773231A7CD63A2EA0599EC665F 21E2335B5B7FF3B1E33FEED772D183853B76C2031BDDDEDCA620E810EFF337AE B757370E0F0F84E774F2BC9FE51960133359C1A54273559671A60305401F8AE4 2301F98767D61ED36C374FDEA7E5CA1B373FBA7A5A3AA3E682DBC8444D32B068 7FECEFFD8DEAD34F98C1638AE9D5814C35D59F02A1395086F70F05E746A3F7FD 47E76398E0DC63C48C6F328AD0BC1C19209426FCF332BDE22577791F0CBF7EC3 5E08C2F79E02DDF1F4F65EEDD193E3AAB24AEAE1BA08ACC2C92D49086F091530 AFAFE0CCDD8DC12CC96A0919CAF273079EB2C4275B5B6FBEBEB0E5563EFCE8E4 69EC792788BE8F149A0E997B77AC4E8FEA8C863193660FCC66D1F05BA3C9378F 727C8C65325568208B4231C701154257A817951A1C46F431BBF1948D9C23CA8E 69986731DE7FB3B7F8E1A7DD675A03300BF3BAC53D1059319498E78EE8317F09 BFB9DD7FEE85D6526DE66438CF3DE6EA44A7A1A1BBD32DC2C6E91FFD70726CEA 779C97FFC5736E277BE85D2713ABB8FEC2A1B515B582E8AE185C17607B6CF506 4954B3CE444143F157D3FD6C562E825ABDB96851793EA22B58F527DD89981E3B B6545FA9C465EAE579E75EDF81758DCA9D713E98A59062BB127607FD6C5AB8D5 C6DB93E111961F096B0ECA03A94244A93D5D38E1440B3ED65FCABA652E1CB05C A45EAF37E88E26F50A595FF3FD054D7A66B1FEA4F92B76EDC4ED5D1BC8231149 1F1770F060E7D8A535B080188A8D7DA5497302D2B9B31AB1042660EE399CD3D4 2D9B3A1D94CE1876D4DE7F4E686F694F8D7A4A8353352EF1C42E9324E5054EB9 48353AE9F044606EBFA5B42C74096CB85E1B5B2D811ACA3411C7B8A0C235C328 746EA4A3E8E986F7BE56660DB1E6744A4B8E79AF85523165C1C44643586C0D46 D7FB701CA4D50B3FF9A517E0B38F6F6872AC7F8134F61E5487252B8D3CD1E161 53736E359F5FCF852189668A8A197DA19152C733A6392BF5375CCB32163A455E AB440B34F2A570F07461D19DB0A23FC459E91F94F126EBED15FABF56CD511C1C E9C85DA68D5AE007580B0566D1C9C973B8D68299E6A156A4F50B30C63A4B77AE 6B5223CE3CBC32F677C9A3AEFBE039AE5AB670059EC080A003FBA5FFED5BC9B7 862DAB79248A014807855656A415D8AB165E347670B9B8C81FFCA50F156BACD4 2901E0FC3F4D2E7FEEC530694BE0F541796DDADF337B805427F882C304490B81 658B9EB75A95205E80D0CE08AB8E2FFC641B9D106296AB4C2F2C7B768DEFBF34 F4326BA22A939C0FA44C94A4165CF0689BC09686097D87308755E22C7AA99620 5B0CCE4C79B8306395F82C6379698631AAB9F98666473631AA5B3F008A50DB83 B860C4F227AAB45661FD1406F69425A52C03401C6695C4812EB4048AA59B9654 73F856B14936DFBAB3FA703D3A6F335A408E09A676DD1721802562D35C8B7DAD CA88F17454C0D11928CB397750138C6B575FDA6E4E79F3130DBE9C23BD4CBC56 0AB3AC18453A740B1D725EBE3B191F312F5AF71FDA9758C32AB15D1B59A61552 26191A17145AB1E6D84455C6E1E4D92ED87319C1B1A6263AA472AEA99FC64DC7 77229B84483F7B9158E59896CB9F7E923ED998C19967DAACA5BE05B80FF73FF7 DDBAFE494D3298A40BDE92F2709C8D43E88C54EABFFF417CE98C925A30D738A8 9B916F7A6D1957FAD9C16FFD1EFFFA9B442DFEDBDED65BDBBD47E989DED0FADD CEDE4ACBFDF58D93EFE5EC33C3835F1C0F8789D7C8C0984C1D6E0829334D20C6 0353D95A59CB332BADA5EEE8478E9F6EB399838A47F3F6514D3D97ECECB8E064 75F5C4A178DC8B6A0D8D9DA388E87C04BEDC17FF6E67F7FBDBAD4BA1DF2EB2E5 C530A87131EED549039028274C787C735CBCF0CE4166858BCACB5419CF9B2F73 C97B1E909A1D4C4AFD2AE65A99E41E31DE1BAF65ACEBA19315DA4C26812431B2 0B405BC06BA62C28992D4BCB4776D3AFD7BD45DF796532DB53C95AD3BD685556 4584E3B40E55779ABE595A5FBDBBFBD84AFD936BED46B9D71738E0AE56FEDF86 D9372693163D7EEFEAC135908A5395C1C191CE2A77D344F8F3BA16415D445491 1B43193714196FC9F46FAFB73FDDAA68422504AD88E1C9BBF1CF05AB0F0572DF 4FEED122C472C1B13EF857FEC2DA8F7F8A114919431A0028BBEFA5F5FF01C2FB AD14F7B110FCA92234908844690AE0B440D30F02E974C701F295CCCA4C2BC23B E598DCFCA36FAF3F7436BA7862F8D615127AD1E995441594FA16A9481B339213 A04959032847E75301A6EE5EACD2595C4D9CAE92BFB5EB789EFC891347AFBEE9 7C7D52FFC8A3A30FD9BE77DA2AB5A05080967C6F93EEEF03CE4DB5BF51AC8CA8 307FADE83EB79795C7405EC6A5184A338D37F06168CB48C8A64DE2606ABFBF56 7BC02649075827C420DDBABAD77AF77B2BEF3F23A3693A8D1D55234E8B1B0F39 C8E5C8A303699F94DFB88ADEBC562EE018E795992958CB6864C7D1CDEFBE79FE EF7C327B38B40A807F3FF9CEE7BEF4E0FB56740E2D34085ECEF994BBBE3C48C4 9B137A93AB51395A0C6BA791DFB6E421E57BFB83A6D3744347A4BD272BD163D5 6A9CF53B64DC38D908A24A91164E290F8731458D2C268793EC5AEF28A760B15E C3E3B4AD2FA856FBE3FD3B3749FE84BE2ED73AE157966DCDE7B38AA6FD1A0803 5C8A49AE3934AC22126AA210F7CA716FE0DBB8BD64BB8BA0F08A187327A8E3C2 141B0CDF3EA463C72F1AB7DCEB0BE7AACD27164B3A2D94B2209EDBB070A09306 7539C05072ADA110D504290282408FA7778BD11F316FBC727B7670544E3CBB9D 4838A4F99069B6AF630F0C649E609D524A2D1B6AB6EB095527A466D196EB5420 0E94D6F2A6CA1A9421E572C157A51ABB976AD1C796337F48B94E7D54CE270123 09A7B40C638CA72A3F8A27EF74C081CB828B3FF1A56FC22F3F7E4A9A893FE6A0 D0744A5003E14551F0B2B41D47032132EE235C002CC4FCA7999D2E6966A89B5D 31B389AA430503E8521CF86E2051156BDD31AB344D0B636F02B2CCE964E90EEF 6FA7B956B1985026C7156137206D0420825ED3AA503574C3CE99079690E922B5 189C943C8BFCE574026FBE7DEFF4C31BFE2936AADD6BBFEF51EEAFCD8DCD673A 8B11BCBCF9473B77FEDDE5E371F3C8CAC7821D31364B78C3B157032D88B42443 5934B9F0779EE4CF848C642120E9778A97FFD557ABBD3652C1109677D3E9362B 627DFDC6FB50A5484B1DD0A0F0248CDA55BEA29F7FE9CD48E7EC8F349C877091 C52A814EE9E6BB7CFFE5A13F7073190CB91848305666C47C95AA4502577CDBC7 6623597348AB6DA734E5B70B92CF1D1E9548199F66655EE838708DD9B7BEB91A A2CC96B76911D539B96661CDFCCD7E4A0882532EAE671A3D75CE26201418739B 1BBD2128C7938C4E2071C362EDDE0B073480AB1F6C8CAC4391812A696117813A 6608A32451B34C961060D7D8E4810299D2D3B2841EE4B5BB2FEE58857BF29135 16F573E3CFBB0C2D18E37199656166934C2F4D27B99B4C07A8D15A41E7EF49E8 171C7BA1AF79A50E15C80A30CAE695573AD26795A436FCCA186D5925841351CE EB0120E765A124B650DD771A6664AF3A22055BF24FFDDC7BCB7558E433DFC833 53488677E5EE1FBEBA426CE115BD69BA543F29519926232071B918D63FFC44D1 AC9AF650D010A802ED48A4A565C3F2CEB5777EF3B7A34E12F3D5DFBBF94E87C5 1B56F5705BFE5637EF7AEAAFB72BBFDA5CFD52AFFF37279DA34CAC64AA07B379 BB379A8F42305B76C278D9012DC61F56EE076CF7B483D74FB6CFF7C95B6A781D 4FED30D2E17B3E5A888CADECB4698B45A77A6F087FFDE6EE9781FDEF833671B3 5ADBAADAFAD64C1D2C4A1094B422ADD276CB3C072FDFEADD982507CE922B6905 C842A50C1A7E902BC0CC163AF2111AF029836C4990CB09DBB2C1BA2BDA905789 454BA755BA9598458165D5483B7256AA961D296C839C595F3E9ABE7178546445 9B90C7EB4B0FFBB50597CDCAE27064DD3E94B761FCF0471FFE687CD8517C650C DCA9BCD9B47E636FE7708B9D5ABEF49BDBDFC9972A9AA24E4669E9B984334D85 5D485256E61A9D6CA2A1629D049F3CBEFA833E7D9C19A7CA03DBBB78F3F53341 F46395D5A7D23C77D9AB640C7CB06CD3873FF2E1F7FCC2DF928EC25A6929D7B4 887D0F08E7F8F7BD4A51F9DF442198CF614286FC99334283914419531AB367C8 988575322BDE46C3EB72426F7FFB8DB5271F8A10DDBE7A79F55D0F2A9D65B45A 756AC2764DF1BC2A852686B086049574CC61EA1C4D553A990589DF47C57FBA45 AA36FDF499FED54DFCC79DC67B2E8C3EECD2702310D090644B80C37B68E79E99 7E864D9AD3AB132317DEB476FFE86E91ACA052C48CCFE6F81DB848A72557078F 9C4617ABE107560B127B040D06A47B6D7BEDC1F3E1C79E9A0630D22F4EC6D2A6 CA5BCAC6D04525B2C7828E48BE3CF9FAEBF6DE2E8E642C99A339433EA9D48E75 6E155A9F557FEAF4D81DFB77BDDBBFF2D262A3E69DE0793C229DFAFEEB2CCF19 8EF8D10CBDDA85D751D153838AF44EC0CA5A434B4A7BEBB0A710765D1095E34B D07A4F6B59E259D2CC83E3A1CD6D61EAC3C9E1AC2879D03D623B59B1CD336EC3 A52010BDA1CD34E508AE6493230F5DC8F3D5A8DA1468A35EAF05C87632BF6103 4B33801C9A6902A6B54E2F616306947893237DF3CAFA31485AC514177EA3A121 DF2D95EC15F9A6F0D28583725F56B2E31F3CC6C3143888E7A5438904660F4F10 5A1ABF19666333D04301D76C3DB8CEF0AD3CFFBA7286B57B935E1F09C6AD6196 1EC8E908A22AF44C49BB2AF68B692C4448EC26A44B802E601240D8885CC7C17A 2187217441964C5D4BC20AC9B56AA167A3C60F9ECCA211D58A50FF31E57D5ACC C11955514E512EF3513C79BB0BEFB9393EF713CFBE009F7BEC94C959846A19CB CC3924B26C3352354B5333B6DE8CE635353225A45A260A9D3774F6C63A48D47C 340535358179A161C4CC9725A04ADD25CB7259E286A0F49DFE8C97DC1A67E53E 9BDD8BA7A59641D48E450E0BEA4BB65A054D1C35542DA205C6DD95D5CAC2725D 5909D06C9862AAB304A0B7AE1F4855B9F0EE8559ED96FDE0BA7DEA2243C2C289 D970F657876FA6AFFE932F2FDC73520FCC14E84A314959155B7597341C52D1AB 0C4CDB3FBD11FCC563A597FACC290FCAB77EF52570195AB23200F9A128EFC469 5FDF7963224C35DC60A4349F58C3C1E93A5D06A822FC828E973E48AB1FB09252 0B18CB63361B8883CB23BAA5432318297524415F484D9D2228961DBCE25A1587 282A94D6326D47BF7CDE3E014CD130425A68C74519A725D30C89BA6613DFE482 9252ACE3C4324DA3540BF3991807275C7FDD2A69667C8DCD34019D60A4A00221 622B3B77C60CC455DCEE5D4DD8942F3FD8E2ED38B733286D1B7AB4E12999E49C A06C62698497A4D47182B0714D2F66C68C5145BBD70ED25172E1DC45B1AE4524 539AA9057E61E59894F9B8B075ACE62926CEF8769C4FED7663999FBD2D956F3A 37ABA119D5A655152F597F0AB9A55C4DE7674E1A8EBFCDE13546F423969C1585 85A8009241FDD7CC7FABE9DFEFE0439FFB4F9D5BFC898B4590E22CA59A2F8252 8719BB1E77BF76ED58141662344ECB85F6695ECC8A741C436C8CB61F3BC7B49E 5421069A9707CAF18DDB78C107CF3F7FF7B9AF80946D1E5AD621286BCE3BECE8 BBB746AF4CF084968F94E0B7DEFFF82B63F6F377AF4F14D9986577E17D6B683C 3FB1E2A62E645EDAA125493BF09620FF48A3F118741703FF10E5339E79895C0A 1A9B6967E8241B0DEF09E23780FF4686FEF1EB57AF2FAEFDA66D9DADD1C8037A 519B7932A6C5C71D9AE619D6D4C21C7B7733F0E2F5DB7798CF39A160EE406D6C A1548E944550981702C9BB381E94EC3CAA6F15F21D94F9889FAC362A9A9017AA 962617017F78216A3403CF773D4B5FF14C8AD8A2A40F6B59810B287778D219C5 4D292F2EF94D2CE2CDF488B77EF1DE3B070F2FFC63EA56387AD0D3F794C504BE 92E4FFE1CD9BB368418595B7766E43074D341320A46A2CF01535552B78AA7930 281E93F0A74E3F70A2DE103BF79E722318059FDBBDF91555EC264980E9279B0B 67909D627E840756052D9D38FD63FFF017C8994565B28DA3C9CF9F6E8DFEF740 38EFAB37FDC9F3DDD1797F353085930608F17C7A7962C650941622BCCCDEB092 BBE2501CEC1FB62F9DA357B6877CD87CFFB994150EAE61BF5E124C44098596C9 1E401E2EA1C271A9D34A7FA8B251E616C1111EFEE72BFE5A447F68BD77F3C87B 7E1C9E5F9C3E13C085F39149C2408B04D8DD81BB9B9AE5EBE466EAA7F8442F3D B21B6DFFDE66398EB0B28C19303153726C051CC2001D88DAECF8472FC9BAAD1F 5C7C6F67670CDB971E587CEF451DFD360D2DD350942B5A6422542CB45082E854 2A46EFE1779E7FB6E2AA1563B249BB0E09740EEDB1DD83F1FACFFE006D242816 5BFFE7E5C9ADE9D90B2BC8D58B251CDC48BA5B9A32EBBCE16E67ECC5D16857F3 7813B88A987D1EEE608B436363BF5EC11B04ACA4EA74A505EC849C10EE32115A 1EF72121DEEDAD4E3CB546C2D9926A62219865AB816F5B28CEE2342DA6006840 5D09C315BF96DEDB5EF1703D20C4918D65CFAD40CD9835EFC0A00066F432E624 2572311D78A25049B1172D81DAF146A2497A80B27452B782745B0CEF6475104D ADA97FC10ACE7AD220A430AC1399B24D61DC5D4CC7A9860DA841D6D17A5E73A3 B0FBDDAC7849A19EDB17E5D0B376873A0114876CD2D519183A114053070D6599 8BD2074413E16396BFA0AF0D4AC7365D0E1AAD1B4DD2F065EF705E44C8A75495 E064D8FEE1536963EC08731664F6004C71164A097033A9C35014657A635CBCA9 26C5F19FFEF2CBF0CB0F1FE75262CD406D6ACA1FCD682C680A4A343AEAA7A61F 044152071CB10A96975AAB2280B1B1795386EF9B28275AFCEAC0124CFF1339CE 12265199601B15A13FCCB5A48693A43CCAD99E566B50C7B93DD5F75473309ED5 083FE6569648D4A4C4C51C82FCD4D956B49071D427C64D555FB59C6562F74AB9 7A2AA83D94CDDAC47FE4715681448D2DE402DAC8F7C42BBFF275F862EC86D519 8747653E2BB594B22BBE1506A816F31A84D6F7372A7FEF74EA8EA32191A133FE CD83C3CFEEC2DC99227954B2AD34DF2F75E01666A4DFDCD70EF3E41809CED6BD 55802BCA874E0ECF74D77EA05A780C8F5D0D412215A3AB317B4D3AD09B40BC5B 8A3D56660608D5AA433410565D0234AB0D80BBE87287959B4225668C8832CC08 26054F73599859409631A411A512850E4D8F168E664BBC22A9C59C49F39C451A CAEC05484ACC6962CE65AE8C018FA3E1B2A88C1CE21677E16477D63E5F45CBA5 005CF3791D0E2A32699D9448CB052D426C729F809B026429B0257D98D9BDAD6E 7767E7D423679C88A68D824A423D475A3A27992AA4629671637FA7858DDFB9D1 01096D55D7E4837705F7915EED75038466B40ACB8AFE44A7220DAC844CAC229A BC61952F0D6CDB2934BA9B5D7DCBF806584067599AF3508044E6875578EAA73E 253E50136AE067669D68BA46243AFCF63D7175B4560DD2783FE5A4B1B8914F7B 229DF28585E8E34FAA768333CD8DF4EAF401F0997E528E8D0F7B87BFFB5F7BD7 DE8E8B14F6BCE3E9EADB65F9BFEF5DF9F67EEC0AF0E852F5536DEB83CB4B5F3C 18FDF2AD9D2927C798D8C3CA1C4F19209C6767E37E096AC8518233045A0BDEC5 ACF8E1FADAC98AD7D538084DAB6CE0B80793A3C593CD33AD70619685C0BFCAE8 DF7BF1F295B5D5CF2E3B8F63D0E4E50842EE7881E997C2534F274EEEF15C4A27 B5AA47BD71773A9BE46C166B4A4093420EB148A0A005AF23BB8FC5359203373C C9837B797E4D18ABB9965DF789FE29E512EB7DAC46DF530F2BC6BED5D64F3051 1924CC330D519625CC709ADB4ADDD4DADBB2DBA4D880A97794DCCABC5FDC3DF8 76CDFEB97A7D695C9CAF7AA72A7693F104B9FF66F3DEE78E86CBC78E1D6EEF0D 802C7D57E76DC7D4BE95546ABE15CE407ED1867FFFE4CAC3C8B9A7E0B3D7AE3D DA5E3BBEB2FCFCC18DC66AEBC5A3C126530B0AFC48FDE46ACEFB76B713CEACB0 FAA99FF8E9133FF931E631CD250D45BA8F84FF7F209CCF38FDDE4921F81E102A 6341A4CC1032FDF51498B1BDBE824536BDEC8BDDE2FA20D1F0B25C9F7EF35AED 545B9D0913206D58B79CD63C9FE6662481E5030DE9A5E9BEE090F1410FF22120 DCDEE4DDFF7A75E1D2AAF8606B70E3A8F2A6C21558BE3792271E0E4A3329CADC CEDE2EDCDFCC592EA0E30A9DC0065AF7E14EF3E00FEEB123FD1A3F4E4A88B963 534FEB2E8D7CD6BDFAD39EFFF871C5ACDD1B7B90B1DA33EF0D1E3A97D05C803C 2408943ABCF4B598E209E4594C4BCCD2182483E7AEBCFDCEB7564FB7C2C4B47E 4E2CA746C2FDD7DF71DEBBE17EF4BC1BC3F2D9CDCD3FBCBC7A69CD6AE95555D2 6469EBA5435EA0B8101908EE65F93BC9A057DAB970B855264EA6554065222C9D A07CFCBED5C60316C98F26A1DFD440583BC5ECB6623355F4A11F34766F762723 BC0BACCB5932165A0E141796165C9F98374FFD0917D77B875389CF3496C264BC EAAA9000CF23B5366E2CD9E604579484E8BF94332AAD18A9201E0333E52E36D5 0E76CDADAC55CB20CFD1446B759ABBFBB7062B07ED3210A3DA64E9E956E927FA 8EF2444B0C8F6906E894D83213F87049588E90C781CD4112EE3D1F176F4830B6 26D4D9257073D423361C17D9BEE6DD02054248DB2A957ECBCC53A84EED1AB122 0BBB44F904F8FA3D1154AD82F631FB60071719B3CB91A323ED78B4F83F9C4E16 46A6C3AAD45028E6D6A7982188E302D3795CEEF2F8C5E4A8BBF0335FBA0CBFF6 F86960AC2F858E476C990E479D044B2EEE8F1546A6A5C4941726666B540B45E3 90A9BFAC332D987B88C0B95F8499D66BAA5B65C50B5A48D44D2B0F2EA2EA50A3 382BE3987752D5E1C9481A839F090C33052B36C6D37885E0135ED8C06EA4AF0B 4B378A4F9C877630D5ABC3428DD22E5180C797A359BC77FC23CE74D942171E74 376ABC380850A8053160C1E6675EDDFADD6B21A9E7C03E1259CAB9CB88E75B5E 052CE6A82DE8E49162F95F3E5CD659B42F470BB8F64275E757DF48873AACD57E 9A1D7078379F253ADE4CB3B8861C2D9F674BD83B5F0B4E53B7AE578F5374C2B7 CEFED8026C5964E4DA990334ADD8E4C9B75294C1C4B277843240C835008B559B AE7834B2A1D4FC3180FE92AF9F7D7EC718A7204A74D69FE4F36E0B9DC769C04B 33F8D18C6BD67065139FCC7CA2A9ED52A2C5623BAF9D2A4150143A6C84266950 427D4F520028620EA5D6ACDE115338F94EB1BE7E1A5D4886602B2A6B165C2E1A 3CAE8F1C86FD817E944C20338E54CA099D97CA30D6B0E5DA7873DCBF717B7D63 D95D77A51CB24695014123E9B83A0545207559364EF1D442156BE21DBCBDA589 68BB72423DB6CB72DB721BA411999E6984401E17E358AF108E329B6AE6559B5C 8DF26FECFBAE6B7C453507CA188325AC0505E09142156497AA3C685BEB7FED27 26A753287A51CA4D2BB3ABD939BEFE85B7A243B052F566FD4DAE93EBE2463A38 54F1C87BE461F47D97128AEDD226B4A264A889A0C49411E01C8CF63EF3DBBBD7 AEF835EFF881334A9ABFBB3FFD0FFDBDDDB2FC54BDFDF3ABF5A7689CA1E21BD0 FB67AFDDBB16E773F3F83237932BC8FDF65E9D4D2DA96110716429AC961C7CDE A5EF3EBFF1D15E72A08A6B6C2C1B41AD50ABFBC933EBEBC42F45A4350CDEEDCB 5FB972EDC5D5D66F34C08315EC4A962BCD7A2A4EC13C2E3985D3B0281CCD433D 5CF8145B8764D840AED52DB5003CE2695FB1CD64766B304D852BEC4AA7CCECD0 5E96EACD2CBE55E4A79D3AD65ADEC60DCA1F28463F797EBD11C20462223D4FE0 18CC32AD3A800B710E92912DADA9AC5D4D9C1D1DBBC5E0619A9E71ACADDCFD83 99FFD95B774E7AF9838BEDC562FC24814F84915D5BF81A21BF7CE59DD7A72930 7BF28470E82967E82748E804AB395965D9AFFFEC7AF567BD1C4CFBAF541B9FB9 7A57279C8F9F3F4B5D7167B023FCD5573B1355888FC0DA93252EC2C15665C05C EFECD3EFF9D8BFFCDBA915DBA506670F188C338509DF2B1CBD6FAA767F77745E 5C67469A2243EE34993276A4C09AFB30270A08C16DCD4893C9E540ECF45FDAAA 6C1C9FA0347B6D6FEDA133BC2D520A295D2620A2A67A5DCB25AC68685CBB5809 505102568CBA048C759A976FCD7A5FB9B5F2DE0DF68437B8D56FED540A3E824F FAE0817779E9FC9D78080CF6C0EE9D42E728E8BA8C97AC875D1B77177A9F3F98 DC19607F29CB74166204435BFABE9464A5EF7E22002BDEDE3B1334A42BCF7C00 5CAA2B8259100A94037EA0AF5CB155286A8C0C73BB631197A661A993CB7F79D6 29FB7683A41470665564BDF7CE41B1EAAFFED4C5C24F9DFDE0D6AFBDBC3AF1D0 0332C107B5706970131EBC9259B9D387C93BD9682CDC2CF78608777426D6784C 18B7E089313D5EA97B303D23E28B96951418D4961CA7682FCFBC8532CDD06C80 EDA87E74ED7034B5AE49FC1D9E1DE653321E3D76EA24CEE3A03BDDF09AD3BAF7 B6C3AEDE18AE60FF4284CF545003E076BD819C61A5ADB58F19332960A1B00B41 8B98075474BB075A6534A2F5620836EF6D554F57162E566272A460E9233F1997 FEF36E6AF3713BAE5CF2FC25FD8C19551E42410A4AEEA59ABE591263E664C091 4E821D86FAE1E61706C55B1AF32A07025DE56C371F7B0E98A57947AF49CE5BB6 5D09AA8899F13D01B11C63B60634AF732858F29D633A25491DCAB3D693EDFE3D DAEF745D35B31857C72AAB9FBE90B4479A139302315442E34D86724C695E200B 6A7DE90E6CF92ADCBBEDFFF817BE0DBFF2E486C909D0589A3226EE371402335E 984C6709C69A0BB9854EC8C2D4940A0D86829BD341329FD84BA8A66205D7516D 6636E9E4B80061C3D5040A7B5AB9601D9B3C133045742F4D8FD27CA464A27426 E266230EA182E75889253F386E87ABC4AE6BB1A992A51361B4A425730CAC4C03 05F1828C93AB97772E9D7BC05B67E05C8E1F39A9FC5566663DCC1CE214AFB22F FCEA574FBF63A96AD4817C8AD1745284542C38628D853E0B930DBEFE8F4EC34B 8A173AE588FA4E63F3DFBCC0DE9EE5AC9690DA68363E8887DBCA9A98F2FE990E F901464BA5B8E82E6C84AA6EE7F5A28189AAFD39965DEAD9690D8F2B31EA8009 8B9FD54F5B70E0C5D21942D1E753BDBC35255BF79C8A0F329C810AA92EB9B617 8B3B6236829AC19B994F5996EB38F0EB851044305B533900B234AD605E770982 6637666CCF820B2EAE4B9D128C8701D5C1207DE9E9C4515863A6659470C3596B 70655C0B42E74137767784AD9F6ED5C33E088B0C0E78065C9DB3B572D72AAF1C 035C80D033732D844CAF89A3CB45B8E82E7DD849D10C95EDC2D9A78EED855189 284444966531EEBB12614DBF58B87F7D9FCF92955A153DACA30BE27A0D3722CD 6E1C6A954529E31C0EFA7A75733324BE91DE988CBFD06F064D427102CBA9647A 1979C0ECAF983632227A6A643F737AF92F7C98FB63128F9165E7BC24D8A67BD3 DDE7BFEB688DEF86D9D148F3047779B9ECF4FA50F89F7AAF776CADE08E0F1B66 034FE755E24CA9431171B7B6F63EF33BD3AD816B5716FBC58BBCF66FAEDDBEDC DDFB50C3FAEBCBAB0F02AB4A6881C5ED40FDF3D7EF7DBE9715B45D2F3BD93C37 0BA073B141436C2CCA80E979526E50AA0FB4A28B0D782A5A6B6DDFA8BA953717 4E7D79EFEE59D8F9F489F692E5FAB603927CB3CBFEEDBDDE171A2BBFD34ACE37 ABAE0E456C8DB1CD5CE3C603F9D836F3166C21A9BE688C6538D1628B952453A6 EB0F49850F86C32BDBDDBDCC1EB9D15E3A2D2D5A0B176FE5F88DA3BD95D0AA62 792288BC243EEECB8F3E7E72C9D7CBA2D0241A016A0CE72C63B1C834F84A93D0 7D6499A610095F93F1CB59DFB6BD53B5E5BBBDC3DF7A75FBB26BBFAFB6FA140D 572DE189C107EAC186E5FF6167F05777777B91A146D554326974B180616E956D 95FD62DBF94BD573969657E9A804EEFF2DAD5F3EBCFB031B6BBF2AED3DD4D9E5 F5E7F3E23BF9CE31DF7B1255576AF6B81C9A1EA7773FFEB17FFDB78C4D4BE93B DF3394B93FEB5BC2FBB3DDFEDF6299EF7550E82F6B38728429141B9BAA031019 E094130E2D7D5916BB51DC7A6E6F343B7EE1E9EE1B6FFB328DDEF548AC03AAB6 E0A12AD64FCE8C8198575CEB5B2B68091427B19B166074245186F5E3B8BAD77D F9D699A71EE575BBBF79B75E698D6FEDB64E1E4F7EE049AD8A4ACB2E74669B76 C9AD376192E4B806B1479303243390575FFA93ED632F850EB2B966A15EE6A382 48D18940F4FE13CDB34BC3CB6F0D4BB1F6A3DF3739E387C21C4E22E940A0F9B1 0D106114649A9E9BE45BEA370785EA7DF75AFFC567CF9D3D5F26B3A96343153A FB7CD8D95FFBABCFC4C7889BB566FFFA05B0B5479FA2CCD2D1AA717D6170653A B83A82B431D6CA7612EFAA6C48B2324F90FED128C82C8C8BF152CA97A3BAA044 2FC6AAEF2C116F1D58C7AB283C21E5A29A256CBA3B5CF7EB57EEC038F7FA69EF 168BAF15CEE11445B6F2227654A418378FFBD545046F4DEE52269F39B971C985 617CB8D2F412AD171716802BA764842A5AE3140E74082F01690E3A5AFDC60B2B 0C2FE15E1CECDD488ED5FDE689888314688146878397053A700871E3E393D6D3 559DBC5CE22AAB507206039FE32C0639844E089A88C49C33D059DEFB5ACAEEA5 42A2ED5C5C9D4E76D884595E093DAE535E365D72DD453BF434F945F391791A77 8CDBB566EF452BF2D642BFA6BF68C7957735E9C4DA7DFBB65B7A66E250931CFB F32DF440C2658E4B8AB416941A0C6D475373D300AF34E7A2000E3AF15BBBE067 FFC51DF8E5274E6978BB0F847C3E465527506E0EB38919D336FF98BFC034BC19 F735309FA16BC643993A530D8AA569B7980F5E84B82A79C5A29E853C235E0017 52A359819D6EC1BA39D3DA7C26586106586085B5022B81E4756CAD5177D5F296 5D87C82CA8AAE631CFAD498E6282B13085DC60D271BA7767973EB0305BDCB22F 6CD0950799A39164EAA8100D9ADFFD3F9E0DBF9816BED3557C2C15334392D3A6 A38EC37A450493A578F517CED98F514EF4DB115E5C3BF88F6FF43FBFE588E531 F6FB79DC998EF71518012A4AADDCC1049741513E6035CF44B06EB326AF13C8C3 8F17F0E918A4A1358D12D4C109C8FFC4611D21809F94D610F26E392B4B1670B4 EEBB351F2A57C02AAD2D6B1418A94D994CB42427A6CF841585C4306C24498685 5658FA022D2DC1235038481903224DD5178177CA020E4766134FE6A4648ABBD0 7791C34152A242AB85831B1D55C0F50B6BCA8E4B9CE51890D0D70B0465DC5400 13AD4B8493626039D04D018E31D7EAB9D9DFEEF46F76AA601947A4F9B4272B66 747311CC6CD7B583809B4D6E33BD251B0D3C0989AAC809E9DE1B68B253AB84EC 8C693CB61A2D5575750C502D51F417D242763B9666E21051554BAF8FA75F1C84 6E156228259FCD1BA97C64D790D688728AB281939DFBCB9FCC9F5E13EAD01539 30D39A84051D70637FF7C52BCBB596C5D1E4B0E7552BB8593DB8BB553D7FCAFD C8D3929A998C36AEABF9D91E444E8C2C4CA07BEBD6ADCFFC8ED84BAAFA6DED25 DF9CC15FDEBBFB969C7DBABAF0F35EB301186C78302B81E7FCF6E0E057AE760E 5050D2194C283513994509CA79D002640173A70BB4E2541E89E89233FB07E07C 86277B54FDF1C13096F047CFADBDC73127BC231B4E0F475656F92F9DC1EF5583 FF78CE3F85AD0AD3E1EC949ADF284D0F19D0E282F059C143A7CAB97EC63ACC8D CF6201F583810C60B40000FFFF49444154204059A67A17E36B3BFD37F7A61327 1821392E7229ED7B0ADE1D7596283841F1BAB44E22F2D84AF5D1F52ACE872E75 40A9C19403930318A2B6E63499E4CA774A53F3E8645C596ED499A437462351A9 6A0A7CF5DA9D7F0A8B63D27DA2D9BEE0DBFEF0E0C3CDE8012F7807D8FFE8E6EE 73D3A16D4BBB504A9A596F6363A559FEF92AF9A7C7CF2C4F4B402D2B4D5089FF 24A8FD8BCEF61296BF50699C71271DB2F81FFAC33F169D3341F4DEBE7C6C6D65 BB1CA64A5C7CCFA31FFCB59FCF3CA51871E7DBCEEA7BF3E7E4FD8D50F8DF558D DEDF2BCD94E60AC8C6706C68898CE6D3EDE3DC5495635ADC1A7CEB3FCB46A3B5 7CE1E0F26BADB64F365698CE397ED3211130E96A7EE0033477A450AF2A20182D 82C94C658304A45EC2BB2FDF9CF62667DEF32413A27BE7DAE2D9B37BAF5D3BDE 5A8F7FE4DD6EC124B14B00ED594F6EBD49727D23AB183AB2EC0092A169E3ED2F 6E59B7A3A68E89922B8F52900A35B01F6EFA1F7864FBFAAD4EB7F3E88F7F429E A91BF35ECCE7A5563A719984A7993C337205EAB43865A9A39764C2777FFB59AB 7FB775BC996133C98D8E83CDEBF7363EF1A0FDD1752D24F84BD3D77EFD4B174E B4F12A93320120446A61F8C6747473CA50E588930E0737927E0FC6C60043D909 740B026B65BE90F14654D1709EA5B315D76942D250A05D576B0F06AA26B3299F EE8C8F2D2C5CB9C3C6533229926D51BC99838379073241592ACB946B8C7356BD 90F32E2DD1C546EBD18AE7C79D56D5D2FCA552AF3B552B45036665C6FC51A386 61717E3AA6B3FE64EDB4A5161877A37CA02F6EDFB6D0F2D97541324C072469EF 7CF7D0CABCDCCFDA4F35508B0154124D5700A381C5A12C91A4668890CDC1D4B4 A86FD5779E8BCB1E2F10DACDC5ADD1A4C7D39C380CBBC2462A9D2ED8CEA21785 1A4F308CD384152C742C5472DF2135CF5AA0B84D087672EF218F14D69D376E34 400BF16A978C1EF8F115FA882C41AE732114C86C89414A7886CC005A33905D83 5D3C2C6E75E88FFC83D7E1D7DE75768E6273BB07733EA8D14D2B39FD61B64031 21F7FB098DCB9A3440A8691846A49452AB3D392FBCD3FFB9E4A5D19100855005 84543D33C2124A338D2C2DC598C951C987AC9C089DFC34F0239D020BB33E2482 D2536091B8A7FCA88549609ABC92F69A5B5F714B922064294BABA18E47CFBDF6 FCC1C9079DF0C24CACAF901317654D68F964B11A94EDDBBFFDD5FCDF1F94AE97 40DC4DD2D26857DEF4E8A2F22B9C8EFDFED2FF78AAFEC985A99F59C67A15A1D7 D39BFFEA35AF1B8EA13580B09BC4FD32EF4B95321B1250E29156321768FD4C44 1A8E68AA484B39FBE93878068A12E3C42FC0580B0DF9863BBC36433288993501 7204D2A4C87D45DA94D45C69050454507D252871176CA37C4ACDF99ED2F02452 0D776E3D2F392C530215B45C7D27ACF9E150699CF78A7023B017F4ED94C69716 81319F480F11ADB153EC20473388D1BE5EE3A395730BB42194CCB4D8849E93F9 A554851D6BB4F4251139CD5D4DA73C7B4A8766A2E1E4587A058E3A3DBF158556 D465D3FA258F56733E2BD36A190401715D667C8B1CCEB2746814A1052A620087 07539F52CFB5E2533ACA3DAFA51524C636C2A6361EC938E347870EE60584E4FF 21EC3DC324CDAE32C16B3F1F3ED2DBF2D5E5BBABBD915A6A879118248411CCC0 620666805DCCC0206606333CB0C3B3CB32830637A2F148C208249090412DD34E 5DEDBB4C97AFCAACF491193E3E7BEDDE9BDDDA65777F6C3DF95465656644647C DFB9E77DDF7BCF39AFACA497FBF15349404B06F2A95243590C08F088213A6551 E45B241507CA8B3FFEBEBC26B96CF9501A8D6E42CCD174F0D2A5E2EAC6786D4C A445DA1D46539389CC5BC970FF230F81837345A628AE435A378083ECF9A4CB8C 7C3777F2CAC54BBFFF517F2D6FE266695DFC2D1BFCF2F2B50E751F61CE4FCC2C EC8F4C7E2C4242CD025A0BFC8FB7B6FFE8D56B2B0EC5DC037628BEC973E67698 F56DB7F3B86B4099841CEF51C5379D9CFD2F6BE5D723F965925D8B478751F93D F5C96994FA557C636B27C361CF093E73F172B06FDF8F4F953CCD659E488180F2 1CA3E04522694E4A768FD0B58364B4B910B166B6A4C3F030265D1CD8C18981DF C9D4C58DE1B5CE70472685E5F5E8A6622D964C027CEF64ED6469FA605819A7C2 77336812B17966694FF1AC85B6B65522C49051EB5FC21C627532E3856F141C8A DAC4DD56A85484A356FC13F1D276C107597EFF4CF3705C3C562D9F28BBB153FE F3B5E4FFB876A96B10470A1F580BE99EC38F45DE7F99DBFF2887439165148E25 392DD0B96AF3CFD3E4D59B973F70E7A91F1A2E9FF76A7F5AA8CB0E3D302AEEEB 1787F6CF9F1D6C335D1CBFFFE8BB3FFC73BCAC01DBF526076F8D5803E0FF0B84 6F99305920CCB57624A41A8F0C5E621EDAB23E34CA7C134DCAB9F562E7EC3F34 4E9F4C466474FDE6E489191D218D424DC73409EC4EB679881584AE9D34054C56 6102B168A7CD7152383ADAC8573EFFAC1EAB2C3C701F5BDFE92C5D99BCFFD4D5 AFBC72A8B4987DFBFD365AB10319C0693B5D3F4F59E6E49149F585DEE49E2AB5 1A373F7673D4F5A61CD737812730737338CF4BF7CE0C936CAD934C7FC383E57B E64DB6205D938C0B681B922200FDDD893C12698921E1128AC068442ECF5E4B3E F3CCF824CECB45ECA8C6A8397A35EE57C0C2CFDD3708FB955B959BBF7DA6B3B9 72FCD1C3204B9148CD12447973FBE56E728B27305CE56807E2AB2323C386D69E 47931DEBE6800E5077D6F18CA2482972393BEC7863401BC916D5D9813BC694C9 AF43A77BB35F9D2EDF584D773A5068770BEA17E3E155C1433722C3A1E13D3981 90539AC3DB6BC4A7514DE123E5B026860E615EE8964A416522046E365403073B 0E37CB34E6D654DBDF58EA4D2FD6D174061ADC4355DD0B6E5DD9C8155BDC5F0F 9C4485D57825E99E1D365403CF2AFF5E985546D4245643003D3B8A1618600908 CB75A1E300F9EC82B7F2C511E0619FA24B3BBD41CA95837B5AF734B2623B8D9B D4AD50175B3B2499096EC8A6239567847325AAB8A80AE4B4E3639AD1E3746C6E F6CA7367E976E4F05ACB691FF8AEA9F23D8ED0467278D03C9B79CFE6C61B5167 F7D9CC6234D91CE7A96EA58D77FFC053F0CBF71FB6F3BDAC8D30DDF55D32B16B 955CCED8DB5346EDE851BE3B70065BCB012B040D9A10697B06B4F5D503766E33 A6C4B61E6AE561548D420F1BF26ACDDB522E52A1BB39331FB194852DF744B99D B820AD4935348B5BD530DD13D54CF26F1223AF595856F579DFAD62231891A1DA C156142EF6D7C2CDB5CB07EE6D889950EE9FF3F7D634D194855079A373CB9BBF 70B15F18DC8872097BF990435EF1C2867226284D540B9FA67B7EE29EC15CEAE7 3E77D2D2B0BCF9E1CBF95707427AEB1076B518E4C34E6EA03A308405A3CE0838 8749ED50E4D57CD9007E48343A34A83F1A28476B13AE32C30546CB7EE7D521CA 43C6DCBE1003C4FA3CF3913B4670855AA720EDEBDA42897B5D7D0B653DCC6CDB B032F96C989B3B10D8F63A9113DBAFE2134C1C95508832AA5925AB1FA86A8F9B 2C45F1EEB9AC63EB51B804818C9CCC4BDBD970D02FCD56834913C3038073C356 1CAF22B42A6026606AF47F5894112817D58D5809AFEAD30E66AF90E44AAAA274 FADD77F1D5C1ADF6DADC3D656A60BA887A957EA952218E1D138B1015795E0C7B 86AB5311E911EDAD0F4C82F75DD43F24C252D51D1BE726963D07DA99A5800F62 BEB5E162216CF55625BB3C183CC32A3A20B60ED100211B61458953D1C487E0BA 684F7DE0EEEAB73F28D440E981411F43AC30C03A669DAF9DAB8E00A1C1B0D7D5 5257A7E7765AEBF0E04CF3DEDB4118086610BAA9B16D6EB46CCB2A091F985FE1 EA9BE7FFFB1F55D7F884AC82BE7AD21FFDE66BD7247783983FBA30F93DD31327 4CE8523EF048DFE04CA5FEC2F59B5F5A4FAE0CE337B500818976C7CB80AF7317 A802EB217524E7A780FAE97B8FBF677370B6DAF89B6CBB57F4EFEAAAF7D4F6EC 9DABE58336EAE38BAEF31BDD8B530DEFA7FC6393025DD5BDAB74D4CAB224E619 86CC13250AF63AD5C8809DB9F4D0A96A24790F81A4E413C294ED0295B69351D3 A09BA2F561BC1AB7DB3CCD35E9459E88F0A1A9C9FDCDA92A0E0C30F4D3CE088E 7A3A6925452AEC906D614B9020E3C3B05ADE1B36A613B1E83B914AA918112369 7C64E82B4E0C4D287562F67C5BFD61EBC62B209DAB04EF2A8DDFC9D8BB67CA50 A81759E9432F5F7CD31EB3E1AA36D42E1FD3EC270E1FFC3EAFDC18C63D69B706 A23C338967CD299F61F8634B57FD3B0E3E99F49FF6F1DF18DE276B77F7B2DB3D 06662B3738E37972E0C1C30FFDD62F32D77132A8710E1078BB2EE66D1BDE7FAE 08DFFE06D4B99D050229A7B658D4297C60128A6BD000054C76CF7CB20256F0D1 C35B17367CA8AAC7C7725038B08EC924773C8E33471BD54DADBF9D415E8B82B6 6783F64DC00F2020FE8D7EEBB933E1A97DE5A347D337AE66ACD7B8F3E0952FBF 7E88EE111FB8CFDA3C61820A0D926EB179D1C00F295C04490CDA8652464BD5D5 8FAF88A1F65C3F626611B36185D51E3912C3516B6D65EFFB9EA0C7E6131FE151 EA492CDD0459F79D9282AE75585466451B9E4B32E819400C0B7DE5C93F1AE3B2 310B329A65DAF5969DE26652FDFEFBE307652A8BF12FC0E58F3C3F7E778DEF01 A4E51801221CAD5A41EB6B6DDDA6231C6C48B29EF3F522EDC90422936CE1B682 1CE06341753AF42EB7D7FB2E1CC7EE9DD8DFE36227E4A0323A7CAA69674C27A5 F5AB9DEA94D7E9C8B5F514EAF2B6045F8BDB1740E1BB95BD380AB0BC39DC3241 88523CC5772AA5F12A70F6FA41030BAD63BF441C2C9A0DBF3E17A63035CAC2B5 DD0F4219328EE9CE2A836ED83846D558C7B6DBB0591D7BCB37AE1459F7D0C23E 3586B2385137347B436A2A4B8F60F70E6C3D0604064805D847867852260D0F11 698954872FAACDAF260A96D790D84CAD251BF59D9578B49E668EEF9A172D13CF B06A61024DF3420BCF750DCD2C433C598D4C9A6B2060923C17437A0CCF3D7878 E5CC65768194D8F84EB833F3BE46ED1D752D8686376A232B1032398B0ABB9D00 859005335120B993C0F93BDEFF09F8C5BB0F14057F0BF3F4EE9E06DC55824612 0ABBC56FE1D344BB59349EE7218C99E076BA0C441611212A6C95CDEEF1A07DB8 6D2A34E1E93AF69CD5EE5E58135A382A4462D043D93ADCC21A1C821150B1E2D2 E02B5404985042D35EB8E047E3108EBB864E0ECB934E63B10E032E704202C321 8483AA975E5EAD37AA5377D7E2BDC0BF6D2F3044C1A8AC3CC529DDF8D0B9D59B 3B1EAF62EA1A0E3402A2EC54222E6702E4A22CADE78BFFE91DC3A389ED6D8459 E48CE9AFC4AFFCCA9766C54C9BD24D472469DAEBB32D4E63205C351A84DE1E10 1DF0828A272B00D629069383E623653265429D71C670EE989CD8FF5A260684AA 72CC640FE43B2C23C869FA4E0D09DFDC3A5755E623D428D41A1E6D1B7E61AE89 4450C6391F1A4A4A0C7160B6C80C0776EC25327A8EE59E74E69CEA62856973B5 72DB316167161BFE41CC1DA18AA62BC9A035681C180B9A6152F43DDF64834C79 E6E204469B0A9076E906C0AA3E9AC0C36A67FA668D8CE1846EBDD6934BB4562E C5D5ADB1538793A56CA3BDBAF7C13231973A698EC6BB61B9647BDDED86356569 2292C49310B300F4D1A0156B2C82100F4ED2667D02D51B962B3846721B7E06C5 30E69BEB0EE41C43AA2AC9C57EE71936C6029CE4069013A3AE0D7D3392D78E4D D08350CCFCF4B7F023659D9BE74F95016E64A043F46F6E8C2E2CCD908A21459D 611FFB7E0D87ADCECED8BF78402D4E22EB61E6225DD33A02881AB16FFECB908F 319057CE9FFDF01F8E6D8AAA2A33963FCBC16FBD76E995A1917751251DFDE8A1 C51F986B9655B644E1AB6B1BF7D5A70E03E732149700FE6A7F78E6E6EA4ACC0D C2723B6B1D0061960BC650BF3FF27F6A7A6E7FBCF35771F6142E9A55F721451F ADCC4D856EA73718C2EA5F6F2D5FAEF6BEEBB6DB1E39CFDF2063FFD4BDFA026A F3B13272FC5BDB5BBD941F9C8E1654C0D686018E2413A1D0B5B21107A3D95A79 32AA7B46CBD969D485E7970AEE3044062AD96623E54509D06B9B6B7877B48221 757D5E249A0D80E8497B9E9649103A55CF09F3B843609E43507783398D8FF8CE C37B674E2FD63D140339A8F9548F32C625754B830BF423FDCD67AA703D1D9CA8 4EDCA5D4B74EFB93BAB8044AFFE1DCEA97FA0970A26AC66337FE815AED6716F7 348BA1D1C5864839B65138B6076FA8749D797F97C79F92F147034FCC4EFEF6B9 CB3BD4FDE0DCFC8359CC893A07781F8CEEFE17EFBCFB3FFFAC49DCE148401AEF DAF0BE057B6F374B582084FFBC7DC2C44E615DCB8CB873338E9557784849E116 D6E566756BF98D4F1D3ADD641AB55F5D193B30ABA6A1D159AEAC623426EDF15E 4AB561380E5021B02E3BB921DD46AAC864A50079C03DF6CA72FFD2B9E637DF87 9D60E7F5EBB5C52AD95B5DFDD2F979BE203F700F56B93279C368F6614F6F5C96 22B65DDEC408D111052EBEE0AFFE43CB4D44B930E098B7C79299771E5795C69B 57AEED79E2F6CAD18AB2068A56021244B48CCD859630346B73777A78818D3020 C4B09212C3C9DF3F1BBFF8C2D8F149E1AC6219C0747CEDF5F5FAA9BDE5EFDCD7 2A6F54E3B1D11FAEF8B7FAE131B543DAA56C9123AB4093EBC000A1934631F437 355949F22ECBBBD990B80412AF0D60CAD48CC21381B394767B26CD717082E363 D5C80D990CDBC76F9F28F99E48CA372EB5A6A67D9EB8D7AEB6808C061CBCC1D2 E78ABEE4E08EA05906E046DAF3C79B28D119ED436EA495378BDC06E4B588443E 80F9A05E028B87274009669C11830FCC454E62D2503A70B6BB6AEECE0938B505 5C81D29AABCB9C0DB7AEDE4A37E8DCF1716FCCD3033578AEC3B798DAC3C71F6B 8CC2D8901F87938038D68A592790B88912BEAEAF7DA9DB7FD5607CB8AAF936E7 143A8EE7DE1A0D3646834A601DEE90C69215B6DACA271CEAC0C853C6EB008D45 7E85803A81E673CEE2F09433F1C4E2F61BB77A5F52D1A8BEE16F4C7D607CF6F1 39C07B401AD9662839B4455A8CD881A3D6ED9E13CBD03C191C3AF4D89F5A2094 72D77AC27ECFC09AB98F943AAEC9F7B6C86EB7D17EB7D35E1B243618C9779D7B A5B54CB0C5E2B62347DBE995767FD5646D65EBA2774DC96C19B57D3E6422CC24 75909BC52C646A50D74A2AC40C26286667D2236D50B38E9D45BF3C6B70DE810E 4A9D8A6CCED78369C8E800AB0A77B6912746EBD5F6123FF2AEF16C4F571DDCE3 8EED715C55F09ECBFDED0FB7D69EBD5A1E94A526EBB8D796BC84EA91924D27AD 1BE91180A91F3D913C6284802A3140DD10F6FD73BFF26CE525ADBD683960A34C A56DBE218A0E1444A251098DE5649F17353C58827CCC77A4D79B78A81A1DA34C 272AD3A4301A4DA45F93835516E906E76080C40ECF0B8D2A2E19778067AE38D6 DE8CEBCD41B0E3F6D6ADD73541CA4E7507A41B4B9B274462208E6A9752838A46 5465CA64F4FD755A730DC8E428C9C9C8300A30A081AA988BD2ED6C8B5E1605A5 60C1609ED16FD2B62859AB3423C71C935C382C382A8C3E479C2A0E6580CAE954 F7FC7A7FB33B3F7B5856BDB6B83A796031B934C8F9A87E870FA822836AB620BC C0B353B014021217A3581599AF281651B26CEB5DAC6CAC7ADD13646272161AB5 4E909D16270D782895646C731D9B30C6D0D1D5D185CEF01939254B282B868417 5096B58DA6D401239E8CBFE336E77B1F346B3EE2DC37FC98AA1C6B67C8B65E7A 93F6F3B1A0AA33DE19C54158E2C3DC9B1A73BEE16E163AB820CA0911A8505DB1 DDEFF6D8DB61D8B3759F572EBEF1DB7FD0DC017E4141DC8583DA9FADB57F6D6B 6D442AF3A874D724F88EBDEE43AE7769277E55168F8C354FAE6F7767714EEB49 11747AE295F6E02F77365EC286F119A245150A7C96FE586DEC27AB635E31FC54 A0CFBAA836189D76C95DE36313885E63F0CF069D0B5BCBBFFAF083139BFD4B3B C96FC6E06C7B39F15065763C8B33430B0ECDCD4D4F4CB4B7B76FDD58352B0842 3707AA0BB8A11C650C2AC8A5929A18B02A9171A87CC3256D9F4A4863131D69A1 F25498EBBA2BA842E24F4D4D4C8DD7B41404D25E3BC7D0F7FC30DEDEF65806AB 958EABB747FD516BA30EF8F1C9D2779F3EF640E8D3D10EF224355A6BC8C4A0F2 EA40FFC5C6EA97D376AD5479A231F68129749CA49DC2FB8D9BC3DF6975047582 4C2E46F2370E1D7E97629AA876CCC748498B7404520290C3DC65E27F89BABF7F F5C6CFCC46EF6E2EBED86FFDC2FACD8931F24B53C71B5BF10BAADF9E02DFFBEF 7E78F17DDFD4C3A8C438B5677D7AD76EC2F2E5DDC132BB40F8D6A6E8D7B1B0C0 CC3177CD04B16F82D600A1F5104C481E4A6FE7C59705BA3E75775D5C5867DB22 B87D4FE6E44E58C26619AB92B97EC2243325B03021E0DB1D6760C41D372B26CF 975D07397D9A7CF90D297BE5476E6FADEEB0CDC1DC1D0B79896F7CF1D25EBE97 7FCFFD54E60A0343F4DDC100AC5F977CC03C2AB01D87E6B348BC04369FEA8582 34443E243BF13D6393F79D7CE973CFED7BECE1F0E1831A8F42C68159144153C2 C0CD13119098BA01C3B6C8C7AC0B9362113637DEB9B573E377FEECC0447978D8 83C56629A96757C1903A63DF7B2499EF79C033E1B5F9D7E726E7CAD05B4F79E1 E8590E33930B3A178AAD577A8EA88D34DD90BA8B5057C8ED61C7C0AEE3477DA1 87392FE572C6A12DD61F46AE27E061E8ED2D877E5004D1E0E4C94658F6D2245C BED11EAB528FD52F5E5A05DAC919BCCAC10B2CC114DE1136F39DE1B522A98C37 232ECE06B94A98F96B0E9009A867AA61C3C735C8CB386F4CFAA5F9C0C8716B50 64F72399895E99BB4BABF1E4D189CA612E8311815562F73986BC23AF9E890329 E78E4E8080931877CE0C925E4A8FE2CA7DA1F2B45390DD9D7CA6458EECFE8801 98E6A54FAF65371CC5A31E064BBD9EF91AF2DC2E4B3B8361CD90E83002C4CD53 EB312A1DB33474486859E12621638157A63002B2643BFDB877048EBF777CB83C 6CFD1D2B771BDDCA96FF58B0E79B0F003534F024AC6DA409CD1C2AD7502E5B76 63849C52DA68F0F2D103EFFA63DB3E616D25881DB997B3C20E3841D62FDE040A C476CF5370AB4B24D41893DD7A19699D380C9F1756199A075ABFA9DD6D52DB56 219575D97DBBA1566645612B6B90752C2F144839CF0A237DA0701C85911D6BAA AD070A022082649AF87BA8374D60CDD3D0C9C3093F5AC0BA3440699956535D31 776B6CE9C5E1F49CEBDFA1E4F17177E190A666B5F629C6DDBF03B7FEFCF9DA66 0900BA1A24B792C46795A9D0A9F9A320CF254013FFD321FFBB1B436754CD4AAC 2860A9029E496FFDAF2FA021EA35FC212371A7D816A316D44C94936064F8D882 6B283C2D6336E93B0A8C1A7784B5FB43467A3A8584518973F07AB87DA953160D CD2C1B6F29162BE06130E5D3C8F02EA3C59B30DAE7AAA1D7B91943615591592E D0F1FB0608AD8B6062BD17A04BEC046C219D044FA2D262D5A82BEB1B4F928C8C 90C0B5621217A524E9B446AB95C86B4C4C315028A3F6CB305131663884154326 0A6B2505A908542ED260A0EAB2BC7CDBE88D769CF7CAFB50B83033ECF3D6F6DA DEA347E317AFA112744E38D2957E5A12730E76F0EE2018DB3B9B0F8D2AB65E97 4894FA6F6EF86E54D02298F4DBB7B9136333D00B6DA394E470F76458158CADAF 21F3922649C3FAE0FC4EFAD9B441AB421910B0AE99BE89778846508C9A64FA83 0FE3DB277234748C161CC4B8E42554F9DBE9E8E93702C7279572BEDD8F97771C 3F18B864FED187D49E7143A1080CB91368547655151A9D4C00B39AC07381A237 6FBCFABB4F86EB2C1C819924CDDB7415943ED98BFF7EBBBB2606A71BF45B66C8 43E3E3176F767865ECE4B837136F71437D4114309F90A0E390CF26FD4F6E6D3D BF35687BE60D799511FBD9E9C5EF77FD730DFDD9B8BB9DB0135DF9F878F9E09E 6AEAB87FBBD6FBD8B5E51F7EE0C4070772A533FCE5A2FBD19DD440D65CADB6BF 3971DBE4CC74581A2F5724326FDBEDF2E2F9B3677BAC600E311F33130D98C522 368437A0BE3DBC34B7DC43813D56444506C5D5F52D5FA34373B39572CDF37CAC CDF5043587946C6814E692F7BA8357CE5DD832503E3935E31BC5EE6C4BB90DC0 40F0EDD646B7BB5313D907F6CDFFAB2387E74DAA2AFA392E128FA81BCE3F6E6E 7F94B5521C9D10F8FB6EABDE4D7B61EEFFC52AFBD0FA7A8B9A8B8B3E343BFE9D 7BA726FBADD08BFA035B06C550CA212B09572772D3759F96E0D36B2DDF19FEFC 6D7757D2F82FF38D2FC4D951AF7C5255BA4E2C4F4FFCD8AFFF7C657E36E78972 95C75DF8F56340FD1612DA39BB5F9F35F3F56219863965D844B170995173AE75 D6292495CE56B2F3CA6B8DBBC2CC598BCFDC9818DF030E4E58BBB7524D6807EC CEEC836F0D2755BB9616C8D00A6BE9897196A815238AE4C5C1F20B6F4C9C9A2D ED9FD878ED1A892AF5E3E3520CB6BE7079C13D927CF09EC0242568F31A1E76C1 E692E243ED516ED6A78980344CBF92A4CF263E0223B8553DD6F46EDB7F69E946 E5C49EE9476ECF026A67FBCA42795820AF90959251EF08A4D4B69445E657C8AD 3B8B417AB8D35FF9CBBFAB1683D2B49F4459C023B503975EBB35FBBE77A827CA 7DDA9A49E7E38FDE6A9D7D73FA8E9AC9B28E70CC0ACA8B24D2B5D6D964ED6C4C 61B5C7D596E4DB66F920B433EA9A9C6D60242F54A650D50B4F8ED50A96F6A52A D2C2CFE544A55437F4BD1C1FBB2D74229DE7DEE6FA889A678193972EAF700558 0C9672F286624C67079C92D6CE92B57D57331A7C89A7254A0C22EEF5C2852034 B01601B510FA1E1B62376F1EAC69F33DEBE063F80636A259147875AD174E95E6 4E07BC3C508E6FEE308519117EBCEE775FD848747FE18119BFE2C7AFE4C9EB22 754663DF58259376841426E62A3362CBA824346A2C1E7FED53D7F30D17C8728E 494FB19D2C1E6A21A464A361D9D07C3FE484DA9D4C25336DAB452BD4A921A741 683370230F539E854A441EF58F80DA136EDA531B1F679556AD1DB5DC87FD7DDF 7A14C081AD19B1A6704008BB958D8C20B26588BB736EA5A74BB7ED7BC72E10DA 78056F0DE5B7640DEEBA2F199A0CADB704328868D113690390BB8788B61605EE FE70CE4CA6B25F114A825D04A5C03656D8FD156B37BBDB25B7CBD69852B99499 3029D3022624CEEEDC63F3308BCBE6A18E5063D8DBE304D3044F44C4C4140961 79AFE34C676E8681AF79D5FC98CB56F1AD376F1D7E620FBAC3C387F7328306D8 DCEF347DB1FAE67F7D6A6229244E7015F57634A249D07074B392F989815E3CFB C183DE7735E3A8130D03459D2191D561ADF7DF5FE93DB7C549B9AFBD61910F45 BA21C04E1170DA73733C49C2B9925775590D197A0EC345507FAC0ACA033614C4 7AC926FED2C4E66B1BEE2074A59B70B1A355CFC019414D0735ECF034CECBBC7A 281499D75D8D51A23C846C811BF5F382EC4E97CCCD0DB6B3AD91CE408A2ABCB6 BF62DE66AE84EF05394F4DC81A0AE0A68DA2C3FA790B3544B9E218B852126B5F 298F716494210CECADB5E3CCB04B6CEFBAD1756E312A06C157F674BA6BE1ED6E 74CAE45235BAC5E35E31B77082BFB62ACB05BC5BE77E5E634D3053D20470C6EC 90D44466FDD8087A1F79BA2D76AEECD41BE3A9977BD39EB86736704B00BB92D8 F116E6CD596FC2A2C85696B1B6C636216AF4CE6EE37FC870581AEA9C4A697202 35145DC8A166EEA347ABDF711F331A57E5DC70883C570EC6253F3F73195DDEF2 AAE5D4C37AADEFAE2599EFA0FB8F06F71C5546DD83409392249E8211E1816D8A 4556052BEC5343B9E2F6F93FF9F3F52F9EAFECA805855939A876A8CC6A7FC907 9F1FDDB82700EFAC862602963687778533559AA5D5D1BE5E89D9523F13853943 A040FE40BB9FBCB5F2DF373B2D078C51FFDFCFED7FB8DFFBAD26BFBAD5DD5B99 7AE7887CB30F9A73EE7325FFBF3D7BF1C199F91F196F8095D54F32F99F3A6D14 D67156BCFBC4E9DBA7661CC9C2807A9E4154437502DAAC6CF1F41F9FFEEAFAE6 F6373CF0C054AD2C8B1C985CE944C8A7C0B3D5D78EF21CBBF20A8DC5D32FBC1E 46FE9D779ECA32932DA83D86174CF3C27ABE4866292346E7AF5C5F6F771E78E0 814648F5486CDFDC340858603761B29DA7673BCBA3E1CE37572A3F73E4E86DB5 A8AB3AC28B2B979D1772FEE76474E6C6CE5DA4F1BE83A5FBCBF10C0FCE64E57F 73E5EA59994CA2E8AF171716A6489474DD11361448BB066E126D272A504792A1 8617307C2ECE3FB6B5F2A113C73F50C88017AF8C55FE646787205DE29D3BBFE7 89F7FDE2CF1864412257AEB61D0D6F994DBC5532F3F64499B7FAEBF5D74B6580 C2125AE58B14D612486AC8952E3014D98D4D9874FD43A8B3F55AE7DCAD83A7EF 51751F19D20F3D660791202A002EA8ED63B6D6F2C256B32B136B26AB75FA706D A220E27397967BED85274E38DDCEF0FA4E70FB6DC36A514D8BF6E72E8E4D9E8C BFEDAE30CFA034AFCDB3ED75D4DF24C2AA719BC090536C8ACE67369A57FD0CB6 F2D3D3D5230BF1E5A5F0D062F0DE3B64A4516EEE0ACD2D67D2545381CC8A0969 921B4E1B1B30838E9B533B2C318DB73FF14974E95CF3CEB9D84F4CAAF3D61657 2F5D8453DEECB73FD4991E211FD52E04DD275F77CB855C6494077E12F26A9F0B 11E4531BE79395F309C4954196B78AA20D754FA891C9062C352BC653B830D81F B8FB5DA744C828CDEDC8490D3C3FACF9A486BB478F07E1A42DEBDB5E1B32ED4C 473397AFAD7663A632A7C5C89B2CEFE6239F83DC0B9654D1A4EEDDA5F13371BF 48FB75A217FDE8D0E43428B84EB23D41A92A4DE61C95E66869C670652E9C1615 4D57950C776F77E26EDA5B3C5D751758EE218989B59E50D6EC8F9EF76F5CBD22 AA6CE1E462908F6FFDE346DECFC86D6AE2FE8AF219571924DA235E02FB253821 D6AAAF7DEE463CF49428C599CC5CBDC14683BC285137B4FB963C812865D2706E DBA98E8DB443BE84136E58C5864F2ADF01910B0C6CBB18048765ED1B2890FEF2 5FC4FECD30AD0CD103CEDE6F3B05C8D06094041861834609C0256882C50A3A69 BD26800FA2238B0F3C099FBDFFB059948C31A9DE72D1B4FBA08EEBED323A5B5C 6E0F01776D536C49B4893B0B8770D787426579C14C4244D681155AE70A6DCB82 0C462AC50CD6EEF24006645A6486A87108126ED5A5814BDB89A877A75B41BD3B 66D06857DD20DE0CF5C6119A0CA88B72C7D195C530D8530420E7C8E1E5107879 209CEB2FACD25A30F3C4343A36A66AE30642114DF98DF28DDF3AE3BDC41C1ADE 72921D4950E29431AF9759D5846CAEC2FB4B933F741B9F68EB9C186DCD097239 2A5EEE6C7CE49CD7AB6F17A287B354EA959EDCC181D27DC5511D078BA1D3F078 99C09286D1A46EBC7702D6062C3659DEA89C7E79B0D83DB75DAC88B20C5921BB 76E8A8DD11AE12D0805688CB8A08F77B4CD374ABD03D166054184A809C3CB72E 1F98080782B21798BC9CA02498F24A8B51516299CE410149AE3CE052508A3792 DE7060BEE54E11CE12642B083DE164C03A0BDA3D68E4DADCE32ADFF6277B05F1 1CB10E7B6FF69DF52A6BF6A2071D364BBC81C7AE8EB27834B9E701F66C0B5485 7E304DA3611DCFE92A35F9C5FA41DAB151B218A6E6A6B8D0532DB6737DA7313E 31F4E2EAA1863AB9E8504F69C2B1EDE6B399031095A40608CD3FD63E078E8D2E 749D4FC7CCF5524F11268C32A1BE21FC3C8BC8D80F3EAEEE9E86799F0E7AA262 C8BF817B551268E30B671A92A26A293624763DA19D1CEC9BC1EFB93F192FC34C 1A2EA40CD701865F454A7BC89E4A2B3BCADE900A5B4253B45E38F3B5DFFD3B79 3D161A1FA8E2F96D1E14F595AA3F20BD69A3ED83F2B3799EF5E2EF28CFF8C560 BBA226E25A6ECB6FD3947708CF1B22F04569BD52F9D5A5CB7FDE1A18B8FAE983 874E77B73E518A96D6372B287CDC0DBF39D4CE64F047A3F4B337B73E74C7A9BB 37575707F99339FE38E363157F42B877CD2C4E4CD748D3683BD688AA01350F30 0882C228DAD8DEF9D2D75E7CE8D8F1662530FAB8569F71CB4D183A6ECD310B29 1F319DE614F1341E7DFE0B5FA934FCC71E7F6721A8091169382C54460971EB62 835D8A3DC7FDCCA73FCF33FDAFFFE71F9B3A34450A79E3B9979FFEFBCFB79636 0DF674B27C18924BFDE5B5E55B77B9E897DFF9E061057DBE4AB3C6352D3E3A6C 7DEAB5F5BB6A730F4F3AEF9A2635012F92FA7F7CF3CA53ED0E81C15FCD368FEF A995473D9A528DCB1A9AD41C9B5CCFA08B859DEF7E0DC8E765FCBB297C67C17E 7DEF42797DB5B3B8EF0F86C36D3DF0E4E6B7FCF8F7DEF3633F222C66DB54B0BB 9C35F8677F2078CB92F72D4508DFB664523635155694608C0CDB4E29512A49B6 6E2C55C783D06DB72FBD08DDA076FCB0CD3983B000916CB8DA152ED738730D68 296258788C7777910D96666C39F37ACDAD6CF08FE7F9E258FDCEF9E199572BA4 CAEFD8D723C3F176DE79EA72E3C0E9D137DE1E6629B6343D4B5BB7BCB8038A21 F53D6D7E77E60DAE0DDBFF74ABB6EEA2DBB477E2E4FAA03DB1B719DD7B18D4CA DA3A5670EEAA8C528F47D44ECDCE346A7AAC0045AC28C8102D3B15D02D86CF9F D97CE633070ED451136576720FF65E9C3CB775FED40FDF2FF795796020D31FFD C35AF773B7F69C6A64E56D38A09EA8C6D55621418D2DAC5FC8AE9F1B2A10A679 3114A2C50B230DA51D713FAC06C1FEEA4426F595EE76496591E74A267D40EBA5 6A18547CA9CBA077E894EFCDD99F1F6C65C5309A1AAF5DB8B2DCEB63C42B1D21 AE8978C3DADFB8DB015A96FD314EF6A77EE2988BCF6A5447524686742A54714A 872A137B68C8463BDA4B660E446105F5834D87578C02701C570BF7C6D27A6D3E 18BFCB2BCA23E97B86ADB9C4C8EADCBB55173DB6747D8DB864CF81DBF8B56CFD B52D14A8DA7D9E7B04163CF5718821E978DB4D3121CF86E79E5E1DC970543883 A468F338768D3A5075E83643A305D5363318A38C4C02B607C1363C04BB068475 E250BBB1A8C7CB7E64804624D15155FDC64873D8FA871C5CC0CCCFE19D64FE3B 4EE92085B6D610DAE9B6B290D0DD3564321825AC2185F67574F46D20B4FB9F56 8CDA39966AF7B0D01079886CFBE05B3B10F65150EF4E5FB31EF672F75FF33DF3 3BDAD9A48EA3EC0445616B6CAC9B89D1A1DA36EAEE4E9E31AF99E599353C2738 66ACD0D68DC8BCDAEE39BA2DCFB0BCD1684F80CB90D6301D27642A7442CD1CCD A371A77E94447ECAB0C37C0382A3D087A4EBBCFCD2B585070E8CDD3F0E0F8D0B A4881FC2C26FFD8FCBC34F2D1B706901D6958EC8804B8A5A04C6B1AF8464F3D9 E11F7DA7BA6D9849E6A20AE618905C0FC1CDDF7C3938EBE7126CE0B810EED600 6CD9F38C7C248D0A75F6BA64320255975600F6A2BCF1E8185E28783142420D74 5A2D668BA564E77CBF5CF858E044E38E34812F4A18D411768CF62EF1608FA150 BEE8C96275186293BE0A8DFC2C35774611875BA0738291484424EAFBEA4ED331 AB6BC807BEA225554109DDBEBA6A545075EF189920B18C0D6D3054D4FAD7D8E1 658645BBE66A4BCA6920B0A3139E21CF5566DDBF9AB83D7FECD8D8506CB1032A 0FE12C9B8DAF76B362BBB9FFD4F04B2DBF5AD2F7CBB4B25D0D67948FB5DD3D37 4F03D5C0406D614F039C40AD67C5664A6A95A13368DC390B0E2C60E04965FBD0 A9E1F146D163AC8671B272D38E0C43E62AD792B32DF854667BA20364BD4F1933 FC98F9941D9C98FAFEC70765E6B1D8B5FBA86C8858457BC50B17F3A5AD52A35E 98271B30BDDC31723978D7DDEAD4BEA1471CED525B835C319C57EB70D70DD108 4261E71532D7B6519021CCD2D7FFE8F35FFBE857B772780FCE4E46554F95FD61 1EEA0456C819E2FCFD66FB50507ABF1706FD3E88AA43D7E808CC7501754A24A3 46C04B17D526CF61FAE1372FACF0E25FDE76E0F0DAD2E77B24C560BE5EBFDB15 279B68CD41BFF2ECC5F92347BFDFE4A1CB17FB49FD8F07E0D9B95A3FDF5EC8DD BB26E7EB73D5E6A9A95AB33C11D483DA389E6C204A2A0277B73A1FF9F8DF1C3F B2EF9E7B4E8DCF4C07B50914358551F550DA46768DCD9A3468D35AB9F5E4EFFD B14BE58FFCDB1F288D2F02EDDA4D16649419B687A2B64E80C3247EF2B7FEC7FA 958D9FFBA55F8CF64E59F333115F7FF5D517BFF0E52BAF5D70842B633620E2F3 9D8B5756B61E76E12F9C78F0DDA53C8538A6F0F9A5D5A7970746291C41EC5D63 7EE8D335BFF237EB9BBF77F1E60EA23F42F4F71DDB7F542A964AE1054683462C 356A3F83D48E18D6E8962C2E8AD15F0433D56B177FF2C8E15A499FE7E8CBD73B 6EC548F4CDEFFCE91F3AFDDDDF01CA8ED619526F37CCFFBFFEBC7D46F87520B4 9F729391B07900E176D2A85076E80A6FB56FB537F61C1E27EB6F6EBCF2FCD4A3 0F14150F6798B5BDA03A9B5790A205E5929ABB0F5D450A05467673427B4C2828 571CCCDBCFBCD45FEEEFFFC6770FB2EDF4DAF5A94347E45864048ED74E96BEF8 E69E130F250F1FF6D20C00911503B9B55C4A06C0B0B2D09129F1E252FBA94BDD 0B3B8B8D7972ACBCB1DEF28E2F54DF7B3A2F39EE0019B226A9C89CC2D398C8C0 DC3B6642A9701DD7C8CB518A18F1023F26E2858B9DAF7C31DA43D08CC989A96B D6B3D0EDA7737AB43CF6FEFD79C368664C46DE8D3F3AE375DDC9831569645641 8008DA4ECF24EBB17C6AF31CBB7A61084925E77CA4D89A01402396ED89140792 EF89EA938DC9B57E8F8B9111B64551444C8E2367A2D46820BFE6B1B1831A2C70 E5E9C210F3D5686CC13B7F6DA5B341A968ECE4836510AF24704706B768BEA2DB 8BA8B2D8F7EF9D2553F34D9EECB4D7D60DE934F79D40675F69FC50A989D22C2D 5A6353686A36ECD518B5EE8F52414640A5754B186D37F7AE465AB9054A861B07 C884B39B3A46DDEE48B982DACBDDA0E68E4FCF0E5FEFEF5CEF807DC5D4130DE0 085F8586BD6C945627F3B9F42BF0EA99AD110DBBD21D71B931DC1E61E9E3A02A 49D9A322202383208CC3B4B0D3B95DCF0D3C9F509C715230DF815180CB1494ED 20E7C23D21EA8F35B514C9F362F4422EA044C7D0EC779D32E442DB8EE1DD41BF 5602DA517816E504B72CCA5CA9E8E8C27D7F009FBFCF02E1EE763E78ABA15083 5D33693B4746604C217CFBBF1608773D984C12B7E78818F3B7DBE8B179062329 AD3414B96D2044C4F6869BF8B753AD74C672EBEF4069CC590E90DDB0666F9D2A DB794BB6A319206292B1B01374C63C67260C6A5086BCF0223D712CF4C6CC6F2B 19C212F3302C28C637DF18705839F8D8023CED70DFD5BEC90B22F9D8D6F29FBE 1E70B700EE304523C180CB6B2E6C6A9F10352AB78F7FDFBBD4E33235EA5DF9C4 00B2939BF7DDFAC4ADD1275A255DE94039104E2F815D91E7927500A680EEA760 26C4A1EF56ED26F8A07667899E8E001CAA3C1D69119964DEA5ADD7DB6E0F46DA CB84DB2E640675E0D8A909480A15727FD151631E4C607275DB906B8DCD950B58 4E0530C2863B54BBC840C080CE798DFD8D4225462821023CEA93111CDD689B4B 5EDE5B4753DE30EB1B5A12184DC699B6E3BB6D0502D00E9591C923AA3C8AC31D 5B84B95DEA9DB56617D3FB67F8FC70E7DA76695F1384B0342C27D7BBB1D31BDF 3BBBFDF47AB3B9286EA745A5530A4BC00F392CCC5D200CEA3E2BEC560FF268D8 BEB05662816113C33AABDF3905E6F76148A54296421868B2A392911825E9F24D 2A53873A380F8767568A5744807D090CAB52D8D6D81683317FE65F3EE69F5E2C C400EB8C181990F5B41FD0ADB4FBF917AB51598C957992CBE5763164E513B779 0FDD99FA2E70FDDD2AA09088B25519C8E3C800883D15879240EE1A5E65EE95EB 62746574FEA3CF7EE9534FB7064BF7EF3D38BF23F673185131F4C08B61E9AFCE 5EF8E0ED27EEEA0DCA06E04B95BE974069789B1DBA8395CA0DCFF3025750214A 9FD8DAFA44EFD6E347F6DFB5BEF9C7196DFADE41C0EFF1C4E2FEF1E710FD95CF BEFAC1874E7C5B8984D76E6DC8F1DFDFEAF51F39353B3775FE2BCF1FA84E3CFE 8E7BF61F9BA10D577A7E65F1406D7E01630703D05DDDF9C8AFFFCECC94F7DEF7 7F43EDC03EAD8C520CB93D32372CD5E0B90300F70D79DF5EFFBDDFFC0813D94F FDECBF2B37F7D889D4D4BE69B1FB5991E7818F572E9DFDEB3FFE58DACD7FEA43 BF5C9A9FCFC5C0CE05C0BA686D5D39F3FA9B5F7CA9756DBDA3E43F2DBD7965B0 91F5D5015FFFC13D27B20A9825AACADDD75BC5D9D6E020C67751546F943A08BC 1127BF78EEC6EB95D26277F0CBFBE7BFA554112C158406869D0AC3662451C416 4A39B4A5587B38FAFB6A75FBCA95DB0F2E4EEE9FFFCCD94B2B3DB6D8AC0568F0 F8B73FF6FEFFF81366AD7194174886C243FF77DBFC3F9BBEFDFF044243931416 9C106084BD6DCD2A40AFD35D5973A6EB51436D3DFDD986CCE1BD470B17F08D82 E88968E2608E99A49903351176BEA34D30C8641BC5052C7481C176B031587AF6 1939DBDC7FF2EEF66BAF3B1351B47F562789216DC36E7FEDF59523A7DE9D1DAF 39998604A6D9365A5B0EF20170555B8B8057E90D78E3AF9E6956C71B771C5FB9 7905ED2BCF7DF0B161401361745F99885DB70C6DD6987548B7DDEDC216B8C3A2 E0811EBA59157AE0A937B63FFD4FE585D03D1CF674170B5D538DF85CA73DECEF F9F6778EA60A5E9315E9E1ABF2DAC79F9F9C593492D145239C32CD51D7B57AA0 9154365FCE962E26D06FA69CB579BAC68B3E874C1A5E22121E8F536FA63C5608 E5FAB4AF5892C50D9E9DAA56EBC0AD7951BD44497D0816042FA3ACCFDDEB7E69 9FB3B6D9D9BE0668DED8C8BABD32BE369037137213A71DDC3F144ECC0CC3C7BC 6272BEE11216F787BD425D6E6F675ACE45D579B75CB7B390068076F7ED6D7853 752A0BD7E5398815A37AD4DC5C192D3C34E31EE830AF8F8D5830284733EABAC3 D5A1DF29397D7765F57AB559ADE8B9B5E76EF6706FEC9DB5897D0D9E168E4FBA CDED463AB7FDC9AC757E9085D18E723A051FC87827E9F9B8D4A081918D05857D C98C8EB2938A3DBF54B1D3B2F22C0B11054551F249C94181664D48A85704F7E2 DA83D31A64F20AD8F952DF0EE03BA0A7BFFBB89E001C98AC0CB01D7944766B98 8575093699D6E297AFC3DBE6EF354078FFA1B726CBD82D4D0B88CAB6C6DB9D77 CDAD67A6DE2D8501D81074BB6BAA6CA7BDD28810F3614DEDB9B09B1F46FCD91F 352F11DB748C1CA191D86DAD05F60810D8EA09A50C101610718D989DB369BD12 DF3A45B768A8EDAB3B08D77C7736F2A731AE2B69B4443847BCC532329A01727B DC1965808C483E73E1F99DF93B26EA8F7960CF6CA24D40C5E073ECECEF3D53CA 68A86BC321DA8171EEE50DEC3705757CDE77B64F7CD33DFC07ED4E860950471A 9894B9C1941B70E5C937DC250A70B52D613BCDA5D05DC6371D6B25B91F8869CF 503DA70AA0C7FB683F6E3E360B7CA306E3D8E03EA37E51EA5D1C89E5A42203C6 68975B9B6DCF85354C30E7CAC0F2341433AE217DECE6400E0CED7480B97766DD 996B490A841852B2C04570B0EACD51CD72575724D7FD418F8F722CC0D8E29868 E891EC034123C3438BDD4E75C7F075695295B23C253480CDF500FBD6B1BC7536 53233A75640CCE8251B1952EF1B1C5691D0927F187975AAC2E1B33959D9737C6 17F6A48780AA881035400098CE11814621AB6EC1530E09A28AB42F6F8DFB5359 36640BA474E72418DB8B4CCE30B789584B55AC842DD84B92FCD6B263B78B1C38 A0BDAF5E4FAFC2B213C922B7F3FD29EA23C1EF5858F8E16F496981790A55AC41 8A2127394DBE7651AF77A2664D841E1816ADEBABCEF464E31DF7A299692120F6 C2826BD7AD4111585F14E868E43892EFB23943CA42202DDF4E61D194E3E2C58D 8FFDCCAFFE5567AB16D41F4AF0E9C01B11BEEE389756B79A1E7A62667AB63F24 48F5A91D5B5D666545BDDC247ADB178592108E515F6DC9A746C5877BB7EEBBF3 E8E96B1B7F816A13203B25BBEF996DFAA5F17FCCF47FFBDA4B3FF0F091EF305A 6DA9F71276FFB688E71F7DE7F13D07FFEA537F8F11F8FEF77ED3DD47E665096D 1258D97BDBC4F41E429D8C6772C83FFE1B7FE689CDF7BCFFB1E66D87010E01AD DAD12BB645961B22ABAD3947CA77DA7FF23B7FD2E9777EF4E77FBE3CB90F70A8 4DBE87CCAE2C6527DA03F376AE5F78F2777F7F30E03FFBEF7F69EAC06DDCB2D0 98F21C9925DE1D6DBC7EF9B967CF9C79E3CD0B2F5F2C85F55EC57D75FDC6E350 3CF2D0A1C5FEEADD95C99DDC7FF6EAAD71884E574A33A5201BF5BABEFB6B57D7 FFA0976017FC2F41E3DFCE4C96506E56A4C3354332A7D267DA29504A9D1E8071 7B782620CFF737379C20F42BAF2FAFB893FE5CADB24FC05387677FFC0F7E0DD4 88C08A193A2FC8FF2F10EE16D1982CC4045012380E75311B16AB37FBC378E2F8 81D1D6A5C1C517660F4CAB890A2B64FFD6B0317B1C07E326F968CC916BB31091 26AF1905256C204AC1544E759B7EF5CD95D56B73EF7B44F4D3F4D272F9E4DE6E 0D045C84DC59BBB1510CC5BEA3F7E413D4F03942B0EC6FC2AD252C06192904F1 A35EA9F54F4B7C359DDD373FD859614767C7DF7B8FAC87588685224357041006 A90795CB1C1B8FC4564D5365544956406AA7D40DCEBCD4FEE233537527385C66 C8A4079967388CCBA3A796F53BBCE683B7A7A5222F6595BC84BFD8DF7EE966ED E478E29910D626CB030273EB91202BACD479215B3E9F02B73160D9264BB621EC 16E6C2D11D362AA8AA3A0E8F0DBD944DB7C421F023770117EF5A180FAD411E2D 975C815AD1BC618F643464E83A26FBBCBC509D0B1919953692785076DEEC6797 066C83C021C8E6BD4A3D83B56414456861B21E98571965CBA3BE725583E219E0 4E86156A3438E8CC4C479393914F11C02C4323030E153475E3EC209CADCE3E1C 717F1D6817D3886166B29347DC74AD1F265E6FB93BD81CCDD6F78DD6D9E6E60E 6E8203EF5C04A54C6311975B1576A0F569D6BB92A610B595B3C37986F3547129 0DDF279EA1FB1A0D25E3C0A600AA0C8A214B84954442F90896031A403041D024 36FCB21F3D12D64E4E2A1AAB4DD4FADC8EEC61EF001AFFEE236A1A1526339A85 C4CC4AF2B5CA913DFD93D61CDAFCAD03101D99BBF7231608771B274C52B5C6A9 BB5BA3B63BDE2C44B53B47D4A86FB8DB6F6FFEB29BA80635D1AE28308253EC76 11DAEDD2DD3E4213213ADDED5774843DC2B26E85760E86C147435EF23CD39A41 6C9E4E5894B58609DA565C989F43F6B5A9C794F0099E099CBD86F8601CC23C0B 46D1C9793A9187C41043A7F063190ECA7AFFE68BBAA7D60F7C67939EDC9FD259 E80EFC572AAF7DF80B783DAB170DCEFC4D3A6CE3FE24AD4D198AEAC53DDC3A7A DFB1E17F68784347E50971324B44994F44B5FB9767479FDD71C554CFC5ED2286 896A29B04C0C5A8B7D793CE311A7143530AAC1249D6493DFB007F85D93D313E1 28A97C512F966472B95D295C9EE2048786A611ACAB66A9991BEAE74E538A45AF 8422B492253B1DEC3942FA44558C1CE034E5620004A71587EE33F9B8204280ED 28E9982BCEC2AA1FD523E62703BFAFB00EE3529846D03251213C0590DDC01418 31D750EAB4A64377CDEFBC3A302BA3727A42D67BC24DD2B646EBA3C6FE491541 983ADDCBCB64D2AD541BDDB3ADFAB1B1DEDEB6531D0B06FB41B5C33423466827 42B61365B532C946C5F0EACE6C75314DFBE458D539DD04A5452340EDA924B526 65B6DC00192998B2D55B8E3572C3BA0D77BE72556D46402247DA51A7799E6653 51FDC7BE0D1C6A8CE4C8113911B1F9B2829973B63B78F9BA5F3652DC2746816C 0E86ACA8BDFB1EB4774E93100B0A8867821F5AD25D120466262201F5CDA2305C C08036883417CCC953AADC11597FEAFC277EF57FFB62BF7C3956F36A74B7437A 4C5FC448B6BAFFF5C4D1FB72C51CD02D4B73C1CD1ADAD38D30F4078E7485619C BC53290C9D6BE695D761F93F6E5E5E3CB4EFE8B995813E169687D3C1EAFDE570 C639FC721EFCEA99CF7FDBBB16BF058FA52BC517757CD6570FDFF7E8F8D8F457 5E7D65B5B3F59EC71E7CF0D47E3F2403EC54F61DAFCCEE959263C7EDACB59FFC EDBF20F9D67BBEF5B1C593C7B4DF206E5DDB6AEF02683BC9C74E9EE643B6B3F3 D74FFEE5D2F2859FFC0F3F555B3861F2A279CBD6F05D9B28C2986973BBB3FEE6 2FFDD22F6910FDD4CFFDA7897D7B0B9D0B62282DB3836AE261A7D7DE5EDF7EE6 E35FB8F08557C7EB735DA1B7B2ECFCADB3DF7E6A66CFE8C60142F72F9E3C7B63 7BD8DFBE636E72119AF01FF0B2FF37A9F38B2F5DBF5177BF2DD5BFB06F7E2A14 2E17410687547642E133594BB03417D8093ABDC132539F8F8ABFEB0D06034040 31BFD75D888285B65A2C910FFEE2BF5EF8EE6FE5C2EEF81AC5BFDB7BBCDB2BF1 7F55896AF5B621EFD70F09E5AE7F09108261D72093DE594B3697A3F9794CC1F2 D9AFDAC18947E784EFEC5CBC159266B47804BA63B664148A82A41C33B302A861 E0267359BF69A175566CBE39F8C22BCD83FBC8893DEB67CFD62BD3E14CB34DAD E0ABF6F4FA4B3782DAE4D85DA73505D25A0F28BDBE4CDA2BDACF12973BD2E367 D3ED57BAE3F5F9E1C67265AA49FFCD314D27312F61E4B2088C605E968432A3C1 5DB3C63D6EB02F05CE40AA72CF07A033249F7E313B7BD63B55710F1991BCE10A A900D16930BC98E4D745E507C360623C2F93BCD62F6FB9E99FF5FC0CA353C500 EF38A39A14BEA63CC8C1C029225D4ABEC657CFA50257863CDF96C5BA54B99DA9 410648F47106394F0D1D0CA303A03A6C0DAA357F0EC5F74ED272190F10A8D5AB 2ADD684C3BB81E64058E97D2623608BCB0F7CA36EA06EB89DC20EA6A962C17B0 E784FD38A9685D52FACD7A05E7FD3102BD58F9D8487AB3D88A3159ECD3CE0C8D CA2E0A03E691A23C1B2F4CEF630A24740449BF2CFDCE92B395A9838F4C0533B1 E205C401F091F6A9E12B2C6F8B761CEDD4F8AA376CF534F6581BE5714E0EF0F9 87EB793154612F2A0E2CFD238B97592E81C1DEEDBC48719C0131CC21862442A0 AC5D602EB659068614E705834639DBF21496E70141F552580170DAA5D3880ADC 0DBFA952393006BC54F4F5E66736558B46079CC6771E90F32481991D2D63D8BE 8E6C0BA36DE4357C7AB7D041DB6299B97B3E029F7BE0083422D13A98DBDA2DA3 E60AA173EBC763EE3AB583B424DF9D10B15BB1ACAC2234FCC7FA5210F315940B 83176A37A86D9463BB5F673DEEB51DDBED3243D62C72DAAD592347F3A2B04D88 10E5BB655B42D86C2A891D6640B8A8201A4AEBC957F29D66108CF9514D432276 CAA76838EF1A09E5798149112ACCB5C7649B779FED4F9FB89FFEAB834BFBB6C7 8C60BA1E5CFEAF2FF00BB281A2CC5A231531D52502A7092D437325BBB3872706 BF315DCA8DFE4C844E3CC3EE899BB9805C179BBF7EA5BE3AD6F5F40E4AC476DE 1378138B1DA93C01F7978219973530AB395E868BF147E7D5DE34612D2088CCEB 088D683B67AF08A75BD79E3FD24592700251E8D8FA1A8979360EC18CC9890666 5C7693978A90E374E48F0AAD1A70C24911C7B17FC805734E9E0FE3AD814A40B9 5C23554FD0C20D0CE2D839E8761EA941573B72881364AB0A0DF366C8DAE54951 4472DADDF2D6DEB8213C307E68C29F701919709D905BF5221FE9031A3541B051 8B5F8EC37DD180B4D26E317F686FBA90A2BAEBA64D3BBFD0DE51878DE251C648 01CBDC4976E2FE6034539F60F188DEB1D0B96BAA2142006DF387AD5213765EA6 7095CCBAFAD62DCF3AFDBA781DF2CFDD8C77A0F44C9AE001031B5AE16FBE6BE1 7B1E61591B2B0E91CE89C62CC5468E3CF522CA553033A13930F7B3BDBE8D6F3F 183D7C9A49E2E71E44511A968C00756C2D852BDF9A54A2760F9F20240A5ACD84 510C729FB87875F495FFFD23CF7DF572BB05CFE1FC6CD27632EBE068EED08335 E737668F1EE5C37E33D19236BBA5ACBCAE514948D7A7AEEDFBA38688B9D52CAF 3AE81C2DFDF6F5EDF1FD8BE5D18D1B6FA4C7F74EDF5981C7425978A55799FFD1 A75F7ADF3D879A15FFCD766F13901EC077BEFBF17D8DC9372E9F7FE3EAC5C79F 78F4FE3B6E370441FA5E65FFDECACC9CA1E78634B054FCE1EFFF617BE9E2B7FE 9F3CBD07B46D57561DB8E3C9E7E6775F8E3F27FD2FD557AE1212525155504525 5780A21A30C66043DB18B703668CEE368341F76863D334C6B919DD0D8DC10497 8B52259554AAA41C7ECE2FE79BEF3D39EC7D7AEDFB45FF21BDA1FF74DF7DF79C B3D79A73EEBDD65C9FFAD899871E2C2C879B15A16289FDF57022908661DC6D7F F31B5FEBF6FA9FFEDCE74A93736310E1E8FF2FBE9412D8D2E6BDBB7FEFEFFED2 03671EF8957FFC6BF5C5A3E3762455914D80AC7AA3E1D6561E255FF9F25FBDF5 D22B53462D4CD2BD38BCD60A8F7B870F1D5F5CDFBBF58B1FB838B7B63F3CC8B2 89F9890AB5C27564D035567FFED2FA3FF5074789F1CF4E1DFD519CB801886C13 82978BA050A33235024152508AC84BA3FC6EE2FDA9885E4F3DCED1472B6CD1AC A7096B66F1C7BEF0DC83FFE21FB4515A0F1375C054DC6FA9578EE6B9AA55575B 8AE3E6C9B1A50C51557212C7341298BB1E160549C39B371B96C16627C2EE7EFB D69B33C76B854B78AA75D7FACECA49BD564D7302D14C0448B23C233ECB639A32 5450C193C88C64E465DF7C6B3F3A38FDEC53F9FEEED6F6EACAC3E7A4F2A3A411 C0798B765FBA665F3C1F5E3C61E5484B639265F1E12E8EBB7971A857DCF46ED1 FEF2EE2CAD1F9AA3C1223EFD89A73DB76A884253E7D134E526A62E445C08845E C74484E591409CC70E5287DD7787D99F7ECD1BAC573EB0C4171BA2D391693FD6 4132B8257F72EBD56BE50AAD7E76616024D8E42E992297B3CDAFBCD25871E914 C589C623BB404942235D68218D0046BC2B64E7ED40A7B59E4CF792A83B8C6255 7FC63353622A6BCCD505AC65268DE6FE76B74282D972747472D2D64A87C96E7D 594BC2B86935AB735624BABD35436FF60DB7BA71294F0FF830497648BC1678DD 580CDDD23D00584CEA240F784AD504456E084E98EE2721A3B844D004C6733A9F 52E37428C47CC531669669B5847281B25216098F1E940F6FC6B38FD79DF72365 5692DB9CCBC24EA238B72C371D86C95E5B8F71DE95EDBBD2F4E6C203C8DEFEF2 736539D70DEDD0EC2C6C7F294687A8C7BC6D5DAE856CE81322010D72104926A5 655D9552467952D6B4AA56CA530CC4AC9DF824230D62D68CAC64FB33F0A9A24A 0C99F427E8D4F4548AFB454A7BCF778BDB881C23533F77A69802EDA79A1A94C7 83B83F094555BC2021C6C7731671CE2C9FFBB7F83B0F1FD718312143A94EFB71 193E307644834C9DA0A0717B3CBC499A89F76A4AC7278AA0FFEE37D783524C95 C7CCB8489A28778871518D1C7B96AAFD8344A19D1A260D311026B19A728F810F 4B49B1805FA10E5EC9B87607D531AD716E80E4A0C85213A7F406D14AD8A747C2 C671177E84E99022913463548E7549BD37D37860D57FF162FFC9C214D2ED340E FFFDB5F637F6CA052461B49FE51EC536CBA7E086220E2F9D5DA90CFE8FE55A0E 047290915C170E04A6AF47AEA892FF7778F0A7BBC830BB3846921F0EE31D91B4 0A55E0BE6CEB735AD8D04485996111D51E2EF3F324247D9212913610EA1BA358 5CA2D99655E8862F82345595E0A646CAA8C8A80C001F970BA423141AC9BDDCF5 CD420BFB20F21875E2AA1650AD2AD9697D50747C3FAAEA65DD34A8863296C2EF E68C275ECA302B401F004F515ECD88710252A7284C88E69CA515E22477D2C1EA 8056B4D2F1BA5E37406A248597C954DCE2CC65723189EDB87CD8482EE5CEF1FA 7E743B4FC4C2A9E3E97C862A8C87363633A04758D2C40FFC3885EBAAE6C660BB 9324B96D9832CF4A4F9F1F3D30ED844086F4FBAE00CAEE18AB7185B9DF915B6B 008839B3D17691FDD52A1A6901531B985A4646CDEAD4DFF9647EACAAC5439034 C2A4519698C35178EF6E7C77D3A9D6428AEBDC4E0E461E95A5E71E930B3314A4 5F6A0ADDC97487AA62192AFFFAC47A3CD1512D67D5AB4AF5224BE1D76805DDFC F36F7DE977FFE0DA3EDC9219B9D478E7DE65E20164BAFB839D9F3D75FC17586D 517807561B585DDD77B0E5C142F629CB282A1150995A982007A70649EE51FB3F 6E0DF5E949E3E0968526266CE7E1AABE808743537BB370BFFCE29B9F7FFF058E D3D70F5B1B98E372ED879EFBD19A5BDA3CD8FDDAB75F78EE479E7BF8810B33D3 D3C2D626CF9CC225275327F4F8F5EFBFF61FFFC31FD468FE535FFCFC233FFCC3 A338D96975AEDEB8FDF63BEF64715C2FBB678E1D7FFF138F8C06ED5FFB67FF34 CD8A5FFAFBBF7AF6ECD9DD83C36B37AE43C8ACAC1C99999A86CBAF972B6FBDFA C63FF87BBF0C7FFDE55FF9D523172E6A0C37CBAEEB18898C7488B8DE30180DFE FC4BFF550EC26577E2DEEAFAF5DDED3B9B61BC7DE3D4034B32E97D7ABEF11CD2 466BF18094CB4DAEE35DD0529E36796DB3FF63BB5B5359F1F78F2FFF94416A61 E8A9361FE28810C8468475C81D7A8E39E5DFCCF046B7F586C3FF2A19AD948C4F 5BD6B2E16E8EE25CC4471E5EFECCEFFDD3A45976FC00083450368AEE0361016F 928F9B7BD4F1F25F03A184E55384AAB22214CCA581D7090FDA334BCBA808DA37 DE51FE1193A860B97F6740D8A475E228358D2C0154B5940F1585E70E0426C5B1 1A3E21599C9B41BEBF137EF54D7A7EAE3A3FD3BB7A1DB2A6B3320131AE8EA981 A36DC7BD5757EBCF7EA073BC697B40AF20EFFBB2DF8D83AE062CAB15B65EDE12 BBB4308CCAC545E7E9E3C204913685D5DE35E431CAA443A48D888980CD2603AA 818CC879C1694AE48DB776BFF23DBDDD6D3C7B829C71837E571B2807AD84E786 67D35D7BEFD66AFD42CD7CA2123A19771CAD5F4E7FD0DD7DFBCAD2C3D3911E01 96F2C092244C19C005173461C81E5C27BB6F0C7554ED23B9138752F2344CFBC3 4E69C68D92B84E9D134797DFD95F5FEF42FEE5739A776612C472C9926E800FAC 2370C95A16F0C5F3650F1FC677AA31B937BB7474F306EEAD6671263A66B11D47 DBFD414B33D6250400AB15422F7CE57C9601DD2AB8E904690C0167605141859A 2B67EA758DDB8C69346BCEB3C9A66A9F4ACD8898980FDD836B23DFF0973F3A8F A6002BC619DF8E33B5D7A1E34486ED361A80E4B6467771F70636D3AA20A17B3A A9BF8F048D88EE37F7FF5B260E508F8F56B564D5D7BC08325D4AA9005ECE0833 8A284D42A0659325A7CC6DD09C3E12AD78A4617D128352CA2A257FCAD21A4925 7772FCB962A254CD742F0D71F2ED387A27E027F5E6DF3A87267365FDA12A3795 07889A2EA80A35552B291A0321764E1F39FB6FF1B71F5AB40DCDD128C86FB503 0C222F959154038423A10E82E0B1A7697ABF79B0181B0C8CED21D45F21563930 A33C93639DA78E02F24CCD7465AC5086A520E86836B6EA16AA42B44885AAB501 7C8E95231F559459027E2B62EC503241F9BCEB5AAACA2486987128AD50B3C4F3 CC3D9C79A002792B578ECB141B22B7469A6D92B67BF3CDADD91F7DB0FAA34B3E 1BBAD944FC97BBB7FED3BB75514E49D192680400C4C504433544F338A8344DFF 7717A70D23CF3B52E7F0A08B5466E6D0809C7BD9D9FA17EF181D9C72DA831F14 62330A5B39658536ABE15923993241AA1B7111A38568EA0365E96612347CEE22 09482AC9AA36BA9E126A877924946B886AAB37010FB90C6CE91C6340B2716AA6 1B39EF51CAC5800D042115543724E8BE51D208204E2A76CD61A5D448423CA434 D7B856482D8E0076984E240160537E74062821CA03F8DFF0180D6089DB59E7D6 A151362BE76A6945392E6A980321C964E2DD10A5F9926CC64911691D37BE9556 8ECE6C1F5EA1269B3973044DD3DC027DC655C5863287CA332F0A9304C0C51146 7FF5A064BA9117E189B2F3F4F970DE357DAA4E91991AE6479547AC52F1497F57 6CAF6AB0108C12C07CF8FC6A29B321FB643287255DFEE0E3D6679E0DD1D0083C 2CA3DC24D2F3F19D8DCEDB975C6A68D37578F4AE2782561F5D3C411E7F400A66 472642566A3A92599A6000FD6AA5C1A251BDD79092D4B67B9001DF34E10363DD 08EE6EFED7FFF5F76F7FFBED2D327933D5461C392C36A9D5EE85AE3FF8B5D3E7 3E183343841DD3235AD1C0D67800A21F1A05E2548B88519404A1AE058C257C37 127F11E3A9C523F4EAD5195CD52D7676426B16A3B669BE4ECAFFEDA5577FE6E2 293B4C6F20F4F55EABB2B0F4B90F7D32B7ED3F7FFECBAF5F79E76FFEECCF3CF6 E0FB1617E64178AE760F575BAD9BB7EE7CF7A5EF5FBF741322E3A9F367965796 B865BD75EDDAE59BB755B4E4EF555682EE9B99AC38AEBDBABA0BDF334DE5261A 67F77B0E9061F024C96C433F7FF61CACA64BEFBC9D4A443901C60ECC7469767A 71760673747C71E1871E7AA85AAB3EFFCDAF3D7EF28145ADB27E77F5EAEABDF5 0DEFADADCBD30BE547661A477BBB9F3F7EBCD88C86FB99E550A31126C06370A5 BD9F3ED53AC043FF6716267F65A636E7C531022D54C04DCB3124012065E39E62 CADEE4DACEDEFEBD8AFB67077BE7CAD59F6BD4E71DF4C6A8BBED4546DDFAD9FF FD9FCC3D7B5102C9CA252B888A7F8579F0E09018CFE0A59073C6694215E52920 4C103622D5053BDCDFBA6D4E2C554AA5BCB5B677E5D5A90716F5860C0F76B6AF F847CFFD109DADA1F1A800100904642102AA3AA244AAFE1DE534AAE6FBF42FBF EDDFD998FDE8336277F7706D75FEC90B8999E545CC21D7A7C4BBB2877AB2F4F4 FBBDBA61FA48DA7916EC8BDE01857BEBD1C18B37F95EBC99FA95A71F9CF99127 A406392AD3B4A95C029EC1EAE3CA1021E7B830400440B0242C143AB2F647C5B7 2E6D7EEFABDCD4671E3D85CF54C272927587A4EB6391989AC1DAA67873380C87 F673B3FAA296D969AE31ED408F5EEB8EB6F7672E4E4434A4B1ADC5468EE38C26 05C8109A706CC5778D8D1F7479EAF8941EA4C928118EE16628818428F29CFBB9 E4F2ADE1CE8E6FD5EDCAF18A7868CAE107B85934A93DCC6AEDEACCF4D65E77E1 6229B7BBF24EB3D5BB71EAFC859D35B17375880AA3C7D17A345AEBF60F0AB205 28CFF99C634F2BAB1DB81932482536CC304DF24268E3C99FD38C2D68FAACEAF7 8194D6B55C736ADE712724F008BBE2706178BBC9ADDBDBA79F3B577EC44A684F 5961EA02286BA6F6F674D98FBD9D435B5AC4B3F7DF1A65873AE09198E8CF3DEA 882389DCABEC7F55A4BBC433E255146CC73C48A828401C65CAA7AEE08E42ACD4 B2F4AAA9F30C47B180CCEC894C2BC8AC66CC3A909CF29AC1CC58C7D3887E0257 2041958B3828B4B78DFEF7DBE8186FFEAD33A8AE06F2405252B94321202364EC BBADF645DF53842B677E1FFFE0E1658B138B631D019D65F02AB8232928428106 11D078A40E0EC7937BC7E530E329630AF5986A1C1C7719C2358F1D20D5A921BC 759226808E201F922C238C2933529569956FA99A082EE1F55904E1AE4A7054B9 754A54536C956B4D46E72025709A03FD13C2C0D451EECE22C787CDD37A69C50A 0B806AE021B97462C8611A6DDCBD7E906BDAA94FFD48BAE431A1C9EFF6AFFEF6 EBD369C32F644B4A2F4354CB1B46D1544325326E72FF37ABCB739379D696A625 8B1A071CE69D0445B637177F6530FAD24D4D3A6DA20F51BC97E48731491354D7 E4B4994F5B7A099B88C991BBBFF054C598D2B3308F254040ACC788779CDE658F 67765EE409807ECE0C06B720CEB51480C65AA2850B89D7120745BEABEA80958F 2DA16A3B1E8443293697F5A2847456950990F47EAE4790E8801F8236051ACD29 53CE9F4265C60C240953D33B30A86369079B89B7E5998E563E6A159362243D42 741D8255A6FE688806A5F292EA3864DC8CF6F2703B6C2E2C6FAE5E7216DDFAD9 0554350AA61E18E82A0A123F4C8B7E982519D6D470F568B3572F35F737B7EAEF 7F50BB783CB4A499D8888EBBF9D5F02DD085F0C4B362B42F76EE609A63B332BA 1A24DFDA85BBE162DD4FB2D1D9D9C92F7E18CF5451968A3C2C74080C41B7F7BB 3F788BEC75DDC9A6744DCDD4BDB56DDCAC3BCF3CD4AE38A6B09DC841D44E4C0B C1152A8A0440381EEB03BF0CABB36445C84C3D111950792AE86BFFF79F7EFDDF FDA119E2B8BCF8C79B833BED96A5175AC54ABCE467A767FEB6632C265940A866 DBAE480C895AD44E8B012789CB351F9B5D6E9BAC98CE7D5924CF8FFCAF0CB223 330BC5E57BCF9913E6943B5796359AB4CA8DE723F9C6BBD77E72694EEF8587F3 0BFFE7BD9BB3C78FFF9D8F7DF6C5B5CDAF7EFB5BFDC47FE2B1C71EBDF0601284 AFBCFDE6375E7F7DB735B88F734C09239012221ACF69B91F39701B8199AAFF50 930A94D7347C5B5745D32A4C287ECF9A5A95ADA9ED1C35318629D229354494D3 84CC851A7488D4D88C711713FCA969C42E19F0F07FFD177EF1426DBEBBB7FFEA DBEF6CACF7BEB37703E1E8C78F2DD50F563F72E1E464A4A537FAC0CAEC399654 20DD18C3FDF423ADC141BFF799D9C6AF2F4CAE0C418218E35B1DE7B0DE0A1DC8 2230DA089232D5F65BAD2B8EFEE783EE79ADFE3F2E2DD7C9E12BA8FFFACEC0D6 CB1FFEBB9F7AF8EF7DDA370D0A4B5E8DB554C721EAE2C6FA4F9DACC0E5147F0D 8458CD978F8AF11C93FE5A1C75F5F9939AC4E1A56F63E6EBCB0D6CC4AD4BD734 7EAA7AEA51C922AC4E14F5B40001CFA98C49EE09190B43871462E619DADFDE79 E53BFACA6C737E71F78DD74BF592FBBE6311447F91DA0547BD6CFF8D3BD58593 F6A993A9C598EAE20F86F14E30DA9EC9DDFCBBADE4D59DC2A68313C6CCC7DF2F 6A3535A5D7B2B5C056928102F96359061F9932AE2BF70F4841AC28B677BB5F79 995D5E2FF44E0538DC83F3A222D51C98AE87BAA1C853CE4CBACF862FAF398BCD E8FD13A68B989502D6E16DE2BFD1C359543DEBC62CA6AAF201163224CAB45033 D4639DD868CFD9FC6E2BEFD1981BDD027482C6B9158AF830EC8084B05226807F 1A7247F59BE2A61937793691B947CC454B17A1B67BF4E462BBB5E7CE0973AAC8 0E1B87BBAB8B478F07237AE7AD039CBA40B177B2607D34DA4DF2ED24CD299D99 68AE44FE004214E38000F3D46275C1F0BC7213C9094AE7315BE2E694EE948C0E 42AE3BA94D1E81E08CD5BC3E1B6531B9F9FDB659AE1FFFE47436D31B1FF95285 2545CA8841622DDAEE2603BF42CBE9266A5D0E48A607B4D73869588F15A253DA FC6A9AECB1C42CB670DCCAF930543BAE0901E1A519D8B6D440ABD8D469097029 CF935C7A90B199CEA49835D992CDA66C6A5009B0ED9E738D0FC212C95327CD52 4DBFE4F65ED84127B4E6CF9D2D1A7991AAC24D40190584888F7DD2D4C3042C94 C4565BA367FF357EFDD16593018F26AA519F29D84C548F9B9E223E8CB24194A9 DDCBE27E4BC57D5BA3FB7F147C65CA3746B55B884224E3E1850470145485EA91 6590FF2426B90A080C6F99AA5A402AC7078D39E4DF5C08D5285A2823454EA62C 6B029326030821AA953FCF4065EB1C163E5083C09A89261F722396716E8B22D1 4A38A6092997BC91B8F1E2EDA73EFED9E243366211BA1CDFF88D571BED524071 BB40C3186024AF18799352B350A817FC2A3A7EF19CC87B09C06D61ABD9A9A81F 15A1C1A6C9BA36FCC337D3EBA9A92DEDE07E27270711EA7B894D8B26A08CA555 89651978C8B7262EBAEE11374D13D5D99DE42CC63C347A573DDCE12058A30244 956E325B16BE34D4C83D6391E76E41218046D85FF359042B88403C6ABA9690C0 9CA1CE91528AD3D807CDC3A5A3A6D9A97BAA4E66C7B707EE008829A10136A640 08496A912A4BD868DDEBEE7895995AF58C9B59FDF143D0929CA899B038EFEDB7 4D7DCA9E57FBED3AAD1F6C1C14824D3B33BBAB77AA0FD5AC53134877E189E65C B5FD7178A84124DB43124BA41BBD7EC087A22C9D8DF6C1E2A79F2B8E4CC10233 505D01A61A3401D99731906B0560CA963CBC53909CF2CAC1EB6DFCDAD0868C31 CC434D777FE1C7D3278E6849C6E32CD6646866D52C0EBFF7FAE0D28DC9D2046D 36600565BD7EA8A3D2931764B391809095AE264B18DB82293B6696291F07C4C6 3B6D6AB74115344B8DA926A03C77100F6E6FFF97DFFC9DED376E5E5C59E15AFD 97DFBAB91A610422DA2CCA08FDD6DCE24F7210D491A7D71DCFAE97DD8E16F6FB C2D67196F6F489D2ED38DE8DE2F3D38DE9220AA8F672D77FA7359A6D4C47ADE1 4F6426AAF32957DA38DF9898F937B7574D827FCC291D6EED6FCD2D3F7FB07FE4 C8911F7BE4F17FF3C2F76E6EAD778211E42A573792D1A81F81A242440D31CD39 D5957F0568B842B2F1CE8A527A6AAED9F8D86FBC5583EF177C70AC4C7909DCDC 4C752BA9EA33AACC9B001BF17D7108200299DF8417A8B91E4CE1AAA6D825E44F 25BE54DD960552453C73EEFCAF7EFA27C4C87FEBF2E5DDF5F6E561ABB5BFF6DC 5463454F4FCC57CE95EADAAA570C85D6E0AC0EF48AFA23F4C98DE19DF6C1C7E7 9BBF3ED73CD90F0AC953550A170B8002E02F098811E96B9A88C5DAA8FB9A81BE 0BCFA613FDC6D289F7B3C19A1DFE497FD445D663178EFDD46FFEF79D937306CE 7589813BAB8A38F5C4902AA15317707F48EF18E3B172DB4680B25E9E79BB7A4D C35669B476373EB83E79A45A54CCFEDDD5707F3477E1C3F9C40CCA02AA3C4520 232120532C87D59424A997BA9628B25210156FBE7DB076ABF2A9A7F9F58DCEEE D6CCD30F17868CF210D2999E61B9EEED5F599BFDC053B431A15AC22013A7799C B765DA316FB6DB7F7A3D0B79FDA317F8234D3C554DA853305310E94425657901 382AD5A391CAE4BB609C69A988AEDDDDFBD6CBC6E1A1EE79F65375FDF8BCE762 C76274E817074314C1AA85946B8E36C283CB5BC71F39DB5F668EC8B99B263823 3BBCF746AB52D3B493662C7C9A5824D5243C67581D194958A451CB18D477BE77 E86DC519B687940D0B1C02291F750143F25C38529F74EA21451B29A4E7BCCAC9 B483A6187742C3355C60D58BC74A85ECFB597BF2E814C9CCBDDBBB957ABD549F B8F6DA667408F065B571BA19007F0E07EA941D32395FCC825453B3E43CD0DD86 25145AA806000DA12A01AD8916A8316DB84DDE3668336551792E39B25C01A553 D4E0F5E6C1DBD9FECDD1ECD3D5E98FD447D9C042B6A4A954870F90F22A68987B 7BBB2888DDAC1ADEC87B6B11F019B8CDA56772034FDEFCCA286D19A98E3A24EF E57410A7C3BCEFA1282974D525982356A841AD1A703F800E0AB1AF97EC1AC9A2 8696CC733C058982659193CE3E33AB3D98A338F1B41064077FCB3AF8C6967EC6 0120448D4C6D452AFE39368B5140A8149C229E8AA8D9D83EBD7CE65FE3371E5B B428AD1A0CB22783B0A248552503AAE47810E6835884480D8F2D448AC6CE81AA 83F0FE905E755EA81687AA5DC8B2308AB172986199EAAC5763E6C6166B6A2E85 9AC1ABE63A8140230A05C725AAAA3D231340373394EB1A9D2F95A60885D5676B 54D7589EA732C9D47C226EDA05936EB7F12045555891F0742457A592996C0205 B6EEFDD5ED079A0F163F7F349D8CF56DB9F93FBDA35DC789A9750B320C01E884 6D44D38C9488EB8579F485F6C90F3D9D523F25003208E4A69EC7A05253A2B158 CBDFE9F6FE62ABBC37DB73B35E5E7472DA0960ED65258E666CBD41A8A3CB8875 AC13A47A7E22267E01191A1035818CA5797783F8566A1023C2092091C5CA2919 1133A3293296F4D4056E2178A10DEF0D711719B404A2D913BE3645CA479C448F 2388CD5C58969A529F2B8B73A628B40CA94C346E08017458D9EF23E6C17A30FC B9833B1BDE81BF78FC283BA9F7AD4DC1622776ED6202583CE4AE74140CF6BAD5 A5055CF3016C6958DEDADE7026EBCEC0181E761BCF34D151E0722E3CE9CCF625 32D578E5201287035D45246DEF75CABC06DC16CF4EE9CFBE2FAB5AC48F086D12 92150C1833BC46E3CAA7302E069BA8B78E14DB291FBEB8615D171A155E90590F 5E707EE6C37E8D5861A2BCEB5DB8BB1959BB1B7DFF3533CEDCDA24B21CE187A3 60547AFC343EB150C0DAC16541DC8CDA549AB85045CB4C45A4AA2656BBFA635B 2335F34463419E9498810EBC57FEF0CF5EFA7FFE722AA31F3A754163FC17DFBD F2CDF58146D4689CB396FEFB2BCB4F86073E1AC4F6AC9135762CF982587FAA6D 4D4ECE779DFC2BBB97BC4C3C519DBA50317155DBC7F6D54B073C41B4E1AE11F1 B94E82AB74D6068EA07D8F1AFFF6FAAD8766A69F75CC7776F72E57A6EE0CD2B9 46ADD92CFDC7AF7DDFCF6502549E3114035750735E7288338D41EC291D84A992 84EA641B290780716FAE3216046887A4C3D8FDDE5CE07B10359C33A19EFD986A 8EAB2B2182C6C62B3497B99442E3CA0A5FA12210AEB191B002158028999B5C0B 521FE9C408E5471F38FFC0B1139D7ECF3B08B6315ABDF5F6FB1CF3FCD1464906 1F6A4E1AED74ADE361475B29211B17C0003EBBEE5FDEDDFDF8C2D4AF4D4F9CF7 4026E090632962D50A9C6BC056138C469ACE92F086882FA17CDDB2AE6EEE7FAA 39FB6BF50A4DBB7F64C86F86C10395F23FFCE7FF28FDF0E30C797055341774DC 7B558CDB848B71ADA8C2C2625CAC50A090273C94D4573B5D56DDE0223878F77B E50513D7B01E8BC377D727A64F93A513996D6360D885A6461BE32262524BD5E8 09101CBE097A382F1FB63ADF7AB95AB3C86327462FBDEDCED6C94347A5DF53D6 948E6626A4786B2B49A9F981F765BA69FA8530238A28F23D7CFB4EF7C5D782C3 B8FAD843EE871E8C2B905734208DA6DDF0F2BE4B27D494F21C9E1081A72A4922 39669DD1E14B6FF42EDD986E58391EB90D533B63FB3A250EB70D43EE76A2D6C0 8627937324DCDD2BDB61E01F7BE8E8504BED58A45618A3A43CAC0EAF0CD5509A B934141148219A7149551D58919398A90EC7523471F84677743BCC7373A08693 E0BDFEA09F040193D56AA342ED7098B6417868098DF325D33D375B61034065C9 CD1A9D31703DAA34E8566B6B627E7AD2A187770220C88BC7E7D6AEB50E6FC1C3 B4F7F2F0204BF6C33831B4AE10DD404EF00C5B36DC1B3F8C35D356B54E72DC22 45D414C812245AC294F13309AA763347093587C756CA95091697435C3679BFBC FEFDDDD8C84F7EEE783ADBD7534B3D7EC02C89355C21B99EF7DBBDADED0A76B5 3D63FFF290A44E1849ED89DEECD4B14BCF1F4ACF89901811D18D5020655F8EDA B907B8C30BB3CA8D8AC12D55C09916021014D471A962367811D558308DB22632 521E8733F9F24797E5E4085E36D0028D54E91B66EB5B3BEC943DFD73E7102842 D0921030807F109F58A36AF4A5C0F7772A01089DD3CBA77E0FBFFED8A2CD68DD D440CED222551310910CC22C475A9CB37E2A8700B498703CDEF557166BE33678 35A450052726CA891BA8563E36A7A1948E3B079152847996E6921B7AAE8AA769 A65696D28B913AF862E3AD2135922E486320A073257751D34B42562CCD2D5949 9AE6513C1EE3A8BB4535612DF76C62CCE2840BA9219BC1EAD37C272E1C8A6FC9 FCA6ACFED245EF6CE60E68FBB76EE2D7D2C430DB420E432998308C6086D31AAF 0FFDD47B66F3CC673E985880B12925E329A241C6120EBF267708EE8BEE9FECD9 3FA0F0A8FB69D4C7B4939161247542665DD6248943124163BE48AB8F4F04764F 26B99994945122A1F156ECBDE3DBC88C8B145296414AA0DE989DF288E88B4656 C9129A389633DC18A5DBB2242A12D8AC9D182B8C4CA14078AEEB2642F5B9584A 8400B626197CA15247847323A57900EB8F120BE974480697E256DE9D3932EDCE DAB1D3F59C013C1F7358B245A5A069A189A0938811D356686A01A6BBB453DEE9 6F4F1C6D8677E322CC6B1F9A924BBCF02C9CE1C4F609B6E1D9C8384E3A0337D3 655A74D677CAE5A9FDEDF6D20F7F207F6039B7743D94992C731A639AC0C3CD01 CA25A32212BDBBD2DF61F02043B7F7FC5D731D239E0EAACEEC173E139E9C65A0 DFFCA0A045C8E1AAE4FE0BDF60FB3B8D89891431BD30B7F6778CB3F3CDC7CF27 19A84B9708BBD06B29B631D20BA5A20AAEFA78185C1AE06FA1C695C077407BE2 00E7A5040F5FBDF517FFF2F70F36B79E6AAC3C519DF30AFF8AE4BFF39D37BFEB 6520BC3E3537F72BB5EA839E221D7DA21D94AA6F2687F792F62F93A58D5AEDAB 7B37F682E18F9E3BF1B45973811A54B47B45F9F0DDCE29C137E4E0ED39F7F37E 5CAEDBA5222E4CF32F06C90BFB9D47EA9547EBD6CBBDD66B5A63773F9A71DDC8 4EDFB9DE0E911CC51ED2D4C4482E90AE696136B617246A4B4BD9BB2BEBC1F14E E6F8601D808F012FCCD3F7CE083523533D217047F43C89EFF71C504641E1DDDF 78B93F1666BCC542F2FBE3AF41108288441C542190A3A048553B93CCB9C1F322 5BAE35AA613E53ABD5669A24A65B92DDB8F6CA494A1EBC78B43AEA7DB1DAA05E F88D7E4F73CB3FAA9B3519F7CAFCF35BD19BF7363F3E37FB4F9AF553710ABCC5 535BAF194A4992934C15CD91C03031F66EA7F9B5C0F71BB5EFB4DA3811BF76F4 E8331CDF94E99FEDEDD835F7A7FFF1CF2DFDF4C7300E894277C1941FE818D08B F7FC4655A99E6AA850F722E3902A6331C832AB66B022BEF11D490FC8C906AC79 717D2B6E93FA233F224C7DBC49CB546B3F002BB00B0E9F2982DB0A526DA44993 08BEB9B5FAE20BC71EBF1890D4BB766FF2A90BC2564DEEA0A83B543452237AF9 9675ECC4E0DC12E8E77A578A926A14E69BBDE84B2F1DDCB93EF3B1C78C1F7E60 40E1FE577161E985EA4F0548645A05D2552AC64C46973C0BD97EB7FBD2EB07D7 EE9C3CB22C5010B25EE9C1399179D231F5E9BA88BCAC1B88202379C642C447B5 8DEF5DE5353C7B615ECDA28B50688E1219554713DD2BDDCAF172DE1C8106E089 A9E64BD1F190CD1CA534026EE3A6F5E1A5917F3B12B1392CB4762EBA6130C892 C3C8B3DD5A95DBBD51B04B4160703D8C8E18F464DD69C8A2C99D9CE6684E1B92 D1FCE2F4C6F6A65EE6D37334DDB73B9DC3F913B5E161BEF176C8507D3B18B651 31C8F2A148F653001E3D33F2F7FA0204E240C1C7366228CF75521804EB59EA50 5276EC33052B9B46D5368518959DE4E8A989A494CA26D530D97879DBDBE72B1F 3EE13E132BCB5803E254557F72458C192C86C1F656D1F6AAA299DF110737D33C 28F307DBF3478EBFFBC22649DD200312577402C0C2B427BD014E20D118C4B424 76755AD60D1320AC88C6EEC6A6298CA643AB9A37838A06323DEE0F8FC6473F7E 5CDA20C713DF4CB070E81BFAE1B7F6F5D3A599BF750ED58135E5488D43528D36 6AB83716CAE252ED4B42689AD83EB772E677F10F1E5D7419AB6A4C8D9F2D32AA 63C6E9C80B8500A9670D73DCCD8A501D0BA93918109F4C6DD5B171D18DB87FE2 0F08C7B806D095C15B638862B5FEC31814202849C67513B4979AB69726683CD4 428DFC65209E2195B282915E3004123563D9471D6782604BA38E6B02410A469E AE5394103DAD456C641F092BC758E884C4D6B41832A991B851E2E4E56862F7A5 EDCAA72FC8E72C3BE6C3FFED66F8C208D9A5B64449CABC7C6459E9B4A695B113 86227E72FFE8DF787F544B0A1271D0B854F9FD825A01899BEB91E066F2DDA0FF 671BA57E3325C223453BE3AD5039ED4E18D99C1157096422E93B69F5C96ABAE0 11E5226A1799A6EAE2FA85F78EC70306D7283358529AB44138C50608EA798D4E B2808C34E5954C46D703CB73392C927A5C3AE706A6A7DA8325564DEC00EFA234 E61121505FA1069E69F0C432EA4BF8C0B90D01D6BB3120BDDC7AB8AC1DE561DA 212442264973AE656503DE4003FA2E3B5B892927E8A920C683525EC307FA567F 63F6DCDCFEA556B33EA53DD34C2B3EF26D1DDB01EF72E4680225C3A13F1CD652 AEBCE3763B85556A6762E5834F672B5389282C90CDAC8A50C0544131DC350B80 512371D2BF950EB71D6C16F7B2CE0BABA5913B042C7DF481D24F7E728472DB8F 79120A9B8052D6EE6C7A2FBCCCAC0CCDD63569249BDD4E89353EF6A4EE3ACC57 5B49C2ACA2C226C21254135C6D1D405E4F951BADC66351A8697B92274A45C5B0 D207E2DDDFFE8397BEF2B5FA64E343CD13139DB46BC74D0FBF46E56FED6DAE6F 0D7F7E6AE953E5DA841700A06ED4B46F253B2045002FDD20FECF83FEDEC8FBD9 F30FAE308CE3A143B3A1A65D8AF5DD9BFB3F6CD5AFECADDD7E70E56F6441CDD2 0D99760CF32FF746FB393D41D20716CA5FDE3DB8EECEAD6D0D46BDC3E6E9395D 36DEB973B39F84D4D06526003700AFEE0F6351851C637B4375223FF6B157C3AB 158B54A715F2BDBE3A342E1F51BA1338236324CD12B5C53246417514A1F8A5D0 342D859021EF7D87AA6266343E3256DBE752A120E082FAFFA6A3FFF8534FCF11 E3BBDF7EB132DBE46EFDF5F5BDACBB3FC7E5D2030B4764F60B66D549E3E7633F 4DF16779ADAEE5BD6AFACBEDE295AB6B1F999DFB954AE54412018E8D0C5AC400 8448CD5A404558A08818840FB6137E6D346895E8BB99BC72383AA1B12F2E4C9C 34DD0D2F7EB5BFF3C4173FF253FFE897C699912622862CA12ACBD5BE911C5BCC 17E37114C5B8970AAB1B43D42C1AC2AAFAC8F757BFEF1C415193CB5ECF7B67B5 31F32039FA3ED0A4CA9E8770354A4E401ACB5216735814B11AFB956A52CFD3E8 EAA5EEC1DAC26317FB576EDACD0A5F6E006BD463086D9A997A74732FBE7ED87C F6E983A60148331DEA85E6E14178F8D557C2CB77661E5AD09F5B0E267901A933 AD615621F0284481C719121B90665435A78973EDB0D57AFEC5F0E070F9A1B3BE 378A37EE35CECFC64D085CC22A95C261AA25BA1D661D2F065A2D74EB1AEABEB5 DE385FC1272D55D81068A133002DE5B6AAA3BBBE7BDC1C945A5C9D829BEA0455 F9ECA86A094C335555E86B781BF5DF1DA0C0E9C5905764611AFD34390C43B7D2 D0113FEC1DAEC7412CAA2C8F4A456BA662CF6B93339A49B476F34C3545858B1D 83916EB06D9F3098D7DCDFDDAC4C514E2B9BEF46495FF3407561D20A8284A2BD 44DE6C7B9D3AB70156954186DAEB537E2AB99A106C4820E240F30B8A0BD335CF 9292CBD0846E582863C4AF4D99F5230DAFD2B667F27413DFFD7A545E6E2C7DD1 52A351351EA92145CAB193A96602960751777D1BF238DDD55A978BA435914C6F 2D1E59DA5F0BDBAD10F8EE28CD5AC304D25C378F472445860EB2DF25A45E7641 CF696ABF19504335DBB98535E9B0492B9D40C2CC8BBEE9993F54AD3CD910790F A260C07C221CE36DF3E0C57DEDA43BF50BE7911DAA4EF571F32A51131E40B708 65752B72453301089D738B277F07FFE0F16587D08AAAB4871B901050471A4962 90A244164627129D1441A622AA1E4C30AAFE8C27DA6388CFB1B99A4C33004236 EEAAB86F4583EE9F0608D55008B211F49199E4791826623C9105DE242738005D A8ACEA01AB624E8B39CB5E56C784D8A25233A861E9E16848B184952B93722242 732EAD9EC051C307D162A6965DB8859D266E6CE07AE7DD0E3D326B7F769227C8 FBD7F7FC6FF489596D4914A5244C3DCBCA2775A382AD208CD2C7D3E5CF9C4B1A 03ACE00BC1FD5193400B13527A816361B9B46B6C7CF5AAFB9201809760DC93FA 41A8877131E5E219D3AB026913C43372FD7D3A399F42DEA2B0148521B1721AF5 AE8EC47EA163081C9A4B96EA29D5720B80699E6B335AC243EE629CB2C1B548DB B774C2B35A689FB5623BBA4F55382BB8F2B383B5070C232D9832B84B54FF0A7C D858814D871DDE8A0A9FCF9EAAA313790BEF6804F10C92B01DE7AABC8D164299 BDA6A2BDE6CF4F9E88E7F729C7BCAFF96B516C64F66275FBEAD6CAC58BF4B41E 6B3D969768CE216730C83251160C06611835B12DD7874584E0EEA1A5D9A9C7DF 17978123232394B95107694750A8BCB691A1B6B7456FD8B9A621DF4ADDFC7BBB DDD7F68DDCEA9D2CAF7CFE93D9CAFC10C94A2C59EC439211B11F7EE315F3DEBA B6E08413AEB7E7E982B83FF460BC32214269871A73261288E4DCE2AA220CBE28 2355AE6638C3E5ABD1ABEA105A9D1D832AC09C68FE4B6FFFE56FFC4E34F4CE9C 387E56BAD630EB59E174CFDF9DA8FD5E18BEF9DD5BFFF3F49147B5F280A37D97 5CF1B7E0F24FE98D53C2FD667C6F90D98F4E1C3B9D4B9274434B00D3081CE76B ABDB3CA64F58CDEBDB1BAD874E7EC23F740870387E0FD3970E02DDAA4EA5ED13 4BB52FDFD9B9A2CFBCBBDFD9EF1FCECED7A9CFEF750E121D12889AE608C4733C 13617C825008369E4B5B8C6BCA0AA1365418421A55877FCA6E21CBDD920B3A3C 1F5BFD964B6508AB344F9224354D33CD8146AA0378659BCF202FA9C9430A5ED5 461DC8E5F74A6F94BE82B015855E00EECA132BC73EFCD8E340B0B7D657DF59BB 1994CA234FA65E07A374FEE8C405D3F8B1247F6872E2CD210079FE23A5A94933 EC39DEFF32D05FB8BCF19195A33FABF15379ECC173E55875F1C7008534C31262 2321A643465B9976330E37C868D3765EDDF06AD438C7E2E526E7B5EA7E77046B FA339FFBF8FB7FE5B319E464534F45AAB44EA11A6DD8D8A9EAAF9BEBC73708AE 9F65B98EF51025AB9BBA138A6622F028DED945012A2F3D981AD394B958A88E64 8234353E0BC7398B80ACE354B5F10992B3243CF8DE8BAC4EABF333C9BB6BFA03 8B78D28A85F262D3E0AEC5C5C60FAE9A4669F2C9C77A2604342DA58CE491FFEA 5BDB3F786DF6E173A50BF3A93922362CAC0695D308AB8267A40A28F5CCF4001A 122C41A0EA37D6875F7F7110B4163EF868301CEE5EBDB1786A81CF5A4936C8EA 4DD728610D787B42F6E2A2358C2C00618DBC9EA31B87A5274AD9115984160BAC C81D4892DA7B15EF5EE09CB3BC529724C8CA0C55868F2801BDAB3473A64E9D62 825BB4FF7A170D9C28D7BB695A18C6304BF7463E366C9D1A61D0E964612BAC49 9299CEC836F4593EDF4873D7DA9F3965D9A56ABCEFCFCE4E1FECDFC22B56DD58 D8DB5A6746D49C5ADAB8EA85FB384CF15062BF902921FB825C6F0F2F4316C3DC 522758EA68458D4705199C6725CAE09F2C0E01E6CD8AB3444C1B9139C36A0013 2E02AEEB13F355E3849FCD1D9A79F3E0EBA8DD191CFDC28C7D067E54A40C0219 243D126AC3CF929278078762A7554FEA873F88C3AD66C0779DAA5548ABDB532D 37FD281BC4852F68378D7C9C27450E22A0EE58B661A4610A9C5855916AF009B1 959185AA3D65171594C0BB078DB8F9B145B48265E433243C4395AB5B37EAEDAF 6DCA153E098AD089A5E2192A8F02FB12EA684F821C244AFA17E3AAD1B30A085F 7FEA98599032212EB02F58626AF80A8040A6FA6073AD1B8AC3540C0BCC8A5CE3 9C00F2E563EB19E52443F3F1205FF80237655C3E83B331E91BFB49C0B2CD942A CCD5CE10D3F471BD4C060941D7B4820110C67196A5980432857899B5AC45A64D 690CB412A6A2522FF9A341114765D34D13035E6A5445E52449A6FD444F8DCC72 480919A9B022EAD4C2EDB03740537FF33848CCE8FF5AEF7EA5C578A58B799416 71EC997A5137AC326671344A1FB3173FB794D60EE1C6B0D4848F91B09C828A55 4D5320984D4ACCF6FE36FD0F49D4852CAAC7D83E04D0F0F2B285679C046E3DCF 4804E87F5296DE6FCA2260A9A380B0C87986C3D570742BB4739748550B937149 18327399CD216BD62E8C94B82068F4C1F550DEC126D24423B61F70622356F63A 12A2072822BC912A1E54F3CDB09AF5244C01C0E6E6F56C130DEE7944F0C6D169 722CC9703F2D468C189C96D5786419A93E66E5016BC072F4BBFECAB1E349E980 16161B697B37769B8B539E21F777768F7FF8593A29323CA0D450FB53488DD62E A2CC3B6C81E6AF4A23BEDD31B4F246124D3FF3A4766431013A27308D3261D540 E753912004A4192058E4F15E30BCCD44647B6EF6C256EB5A5BDA56E3733F6C5D 3C1BB996541E9290432307CBF4C69DE0D5B7AA26271683C4BFE7FB338F5DD08F CE0759CE7919273AB7EB614E346AC1EA43EF190740E602324054173157C5DDB0 AC025E98008487E9CDDFF94F3FF8F6776BB6FD4873A9E117459605CC6B8CC22B A5F2BF3CE8A5377BBF3D7D7456E27B13DA9BA8C74478C2283590130E939B93DE 39313707778B805CF672E551E36CB3ECEDDDFD1A2F37426DBDDD4A8ECD7D82FA 3AE426D378D38BAEF9A85EAAD4D3C3F909FBD52DEF0D5CFB66679738FCCCE49C 95F156E2BF72F7664C15D429AF987197D138DD0B65248AC6CDE3E3F1ECAEA573 858AEA15A552298A63C3B6A22084B0EA777B3393535EE05B8ED3EFF74BD5F2D0 1F41B07AC1B8F4828EC1A3B83FB5E13DB7CEF7FE4AC74A30C746810C84579696 3EF181A72D2FEAF73A9BFD7687711EA05BBBAB1B4977BE643D576B3C28C2A74F 2E1DEE74B677FC85D9A923D5A29475FEB868FCC93BB7CECF2D7F1E938789F098 EC43782B20845C5D28F71A84626C9A517BCB2AEF09B91776779AA5570EE26664 7D66E9E8DBFD37EE59C134AE2D2754D3B2C77EEE833FF6777FBE60521A14D204 05669026BA92ADE8BDA914633D08FF66CAD23B27FBADACDF237325C93DDEDF6E 6FAE958F9D42C6A44E260B560202A4A6BA15868AA822143C00294900A0202F02 7A743B1B2F3E3FFFE4C92E8AAD5B5DE79113C206188D242EDC8CD18DE1EAE55B 4B1F7A3A712C5668B0A032B8AE7B87DBDFF8727DA1E23E71AAA30B4BC0FAD411 9B44AC09345295E13250694E64F68156EA5946EF6C0EFEEADBC5B057FEE8C399 25DB6F5D6E56EAEC58CDB773341C85730B35646848558BE39D047586C20A40CE 042F87D65E643EE7F8CD1E0BEACCB7A2521FE3C45A2F8FD623E7823DAAF6F410 723AB071A03B9443D8438E8784CD789A49C3333BAFB6E5812E8433CA32C1693F 8A575BFD5014AE5331594A34B21318832CE69624449F668D1991B95ADB5D66F3 A7A67756EF1E5B39D63EE844D85B5A3AD16BEF0DBA7B2B274E76F6C5E12D3FF3 583FCE86790A5FFBDC5EF3931B2C7320F7A84334A9EC530802F8B111B6408B0A 65A8C23560CBA42493096312B465B518981AA1855DAA68930F26D94ADBB2A7E2 CBF6EAE5ADC547A7DD6735487C42D733A98C8529AC4EE6226AA942F6D5D58667 8FAEE0EE4D238D47B0B035B3E4277954E04122865931CA8A96EFA946E5223738 B135067C09235A366C0D9679166BA898D0CD69CB686AD822E948B6F9697DE283 0BA1137289A84C7DB57965BB6BD3875FBE8B8F6ACD9F7FA0B0957F73A1FC3E95 A767AE063C289F18A2BAEC81695BD83EBB78E25F292004455326B4A433503652 4B19274592925819180044B705EAE6428EB768886AFC17634B35AA3659B37C0C 7CAABF7E9C03D0F81B4859605212A78902C2F1D441A66B18983D646AD0834037 65166549986491446A087A21661C779E69B31AADE8CACEAEDE28890C90CB770D 4BB558F8F00EC439CAE442906920183483009464424FA86BA7213AB816D73F33 6F371AF2BFEDECFCC51A2DAA436E42F6CEE35067B8A499158645DC891EA92DFC 2448CB7DD06B2457C5D58060C0C775B51FC285303299A08AE47F526CBC76AB12 5B94B89D947622B59F53770A1727B69A508CA2D9ACFE816A6676B134A9B024B0 5B5C240769F772E00E1D8ED48878D5F7468081C6D14C569A2F632D29AA821BC6 E84E1A5D4E35C08929E93EE0FA2C5693B608D2013679969A7106A10ECB001918 5003FB0673E25D63EBCD7E8994668ED6F2A3DAA8BCEBFAC098B8480A61A97343 2483718522E8A5D2CECE7EA9AC5767CA19EAB2B49A75E5CEFAE6CAE9B39DD65E 50C6F34F5F205A067A5530C01AC80300A0591E27FE6ECBA526E9A5C3F52EA24E 5872A73FF274EADA70B5C04CB23C239A0B3C894860E68654E550220F56E36843 03C5BF4EBDAF6FB55BBEF5C8D1A9CFFFF80808B26E94332D222234487DD0CDBE FA6DBFB55D3A318BBBD170A76D3C71565C5CE239D33233674EA2954D56251929 944B1F56559004674A4C50A01719302A13D9CA47457A06B681D1FDD7D7BFF66F FEA025FCB3B3CBE76303F9719B46340B277DFA0D66FEA3B5DB1FAE2FFC7AE198 B177A5C10E13EF04E10D04ACC50091E6598306299B390AB3A15F844EA59AE5A4 17790193C498DCDD0F87A3EEF24AE324F139B383427BB3353CD49C82E5E7EAA4 81E4A543F95DADF2EFAFBF71F2F8CADFB8F02C4FC280933F7AF16BF70E3B68DC E43A1E6B37DEC3047E841924AC304F8187DA3AAF38AEA559699C8834AF561BE3 53F614C460B552DDDD589B9A981CF9A153AD1C760E1B13CDCEA023091E458154 B37FC65531F7C7A28DFB2F947F8544EF19965165DAA48D3D1B74D3FAC4079E39 596A6CAFAFF581B258551EC42FEE5EDF883B7399FE85D9C5255B3E3457A17BFD EB3BBDD15CE3C949FBC2FEF68BFADCBFBB7D875BE52F58CED31A81681C020D4B 0BB507091C836409C11132CC7C7060BB8789680FBAF7AAF4A6E5C4B7FDFFE1C4 5373F5E26BED4BB7875D8769869E345DF4C9FFEE27DEF7C5CF081B7E3C83C007 DEA436FEC683EBC71279DC5302F91F685F3C4C0F76AD929D56398EBAF9BDEB31 498DD3A7D3C42D9309818D9CAAD6115418148010F9B916C065B394E66A943846 ABF7DA6F7EBFF1DCF9B5FE6EBD872B27E705CF7C532444D47D465E5B3F0CFD89 4F7CD89749C953D3AE556DF6975EEED0CEE2074E01AAF99026EC0AEDC35BD691 5D53FA1B7E153332AA17C1BE6D9BE995EB075FFEA65BD2EC8B47B4D9DAC19BEF 1848564EAD44A30E295B89C34975CA86CC9A833449D05E54B4FAB91990C21EBC 10D981D49EA50367CF8EE68867054E8B9154BBED781BA979D11A957B4EAAD989 96A94377F8646ACEA052108C7A59E266EEE81D3F5A05226945795A101223D20A B35186344B9516591CDFEE0C3B9E2FA9013264CE72E6686EF3B4688AA38F4F1F 1C5EB378AD6C2F1CDCBB3973729EC974FBEEEAE4E23CD12AB77FB0898786C0BA 57485802235E3A94C58DC463E3BE1DB5610D74580A4B0DD5207A2EA9AA324196 6D020FE579AF6E01F0B33AE98310D6721780A27AC42F3F84B466291F383B6FEF 3BD2767E1C22A99A8D1D3981CB31C302EA9C53A01759727890DEE99A0795BD77 13DC53E7E56AD420D387A91C6132CC852FF3813FD20C83216480202B20B823D5 5CA4C003604C946D365BB19B58038AC458DCE23B731F9C37CED83E4B4CC919CA 46A62F72BDBA39B3F3A55BDA09ABF9B72F146608F252DE6F4342CA3B1D721751 25D1CA30610C8467168FFF2BFCDA934B3A0021A0B6C99509922E3480A224C641 46254822AD876937CFA3444DE755356CAABFF6FED6A8719FFC8AFBBE6BE3FA37 80C47CEC676398A690CA1840D5856B3C563D19023E0DD7347865944084A35460 1FC991501961D672560C7392A02ABC2BCF4A15BD645BA3EE10EE05B7841881C8 B2B425CE56F2C24C41DD42E863AED442619282B0FE3B043FCA1A674E14DF6E6F FEF1352AAB1EB7C33C2BA2D0A2BAABBBAE96CA682FBD589BF9E985B002744CA7 A9250D78CE8264853A23149215AE48135CCEC9B5D2F6F397F50DE4607728E013 B241240C8396A96828D355195482F2C39372FA102085E6264D552F4911A0E195 84EF982626A91E4B02100C0C261C4C85F539583F096916C4E4E90E89DE4D443F 36E6B07BB6ECA308814A0682CB55398004E5AC8C63007E3425C510CB7AE9C68D 7D5A38CBA7960B3B0AF59ED74C9B61998420B4F35CEDC85365E89A27ACD0530F 775A83D9E333991632E6D160A1BDDE4A336F66FEF8FEEA5AF9C945E3743DCF15 9F8E585FD74BD4AB103488865EDA0D4AB49C6D77C351E6A7A474EE6CE97DE763 AE1AC22810132434AA090CFA047169A4A92A1BCD87B79360D5301CF1CAE0F06B 1BA8D698F8E91FD2578E67064D93D4519B5E9819845CBDDAFBEAD79BF395A86C 0CF786D5DA84FEF4F95183D1405A45252B9CDC6982D43481D90067E2AAB41EB2 3B96AA1E4035D4ABF97852232C865CA331637BB8F63B7F78E78DB7F7F3E0A923 A797E1E20AD1AB1048028E6FFE513FFEADCB977EF1E1D33F9524A0493781BE18 662392A100260801AC15CC1B32B53DA2A97D479995CD304DAB71C205BB6D36BE 7A302C45BDCFCD99201288591EF6E5FA41B85B725BA4FBCC52C5DDEF7D7B3F7F 796AEA3F5FBBF6F4D9131F597C8C8AA0B438F3DAEEEA7F79E1053F4A29553EDE F75D3601AD0CA6956AA59E3F04A26969A6CD8D8A5D8E43B80E01A10E01A23A6E 09AE96CB87DBDB8D4A3556A37670A7DF6BCC0010F6125892B8C884E80EFAE35A 4BA4A67F80F054BD35EA0BFEEB2214548C7DBC958A93E766E63EF6D09354A2F5 D65E9CD3DEFEE6F7DA1B99512C46FC27E68F4C95F1E92A9D0BB2B7F6FA776BCE 879BEEE39B6BD7C9CCBFEAB4B730FA42ADFC113535A5F0280325A80AFAB14849 9A10E4AB3D80C8E75A2FC107817F9B0F37A79D6B370F3E6A9EFEC70FBD3F4D3A DFF1B65F6EDD660DFA8894CE64EDC7FFE12F4E3FF74446B3200E2B965B64F7FD F1C60461AC68D51C079278FB1B408D9DC93A42BDE1E64D31EC3696E642B7A2B3 399ADA826688A9E67E2275AA769CFD54F395997BAA2705D1752CAE5F11776EF1 C78EDD69AFCFD9534ED3153409011A4851EA66AD172F378F9D481F581C115A8F 29457AEFD60DEF95EF4F3C7B164D100ECB4A376369D1ACC4680519A05AF8F8CE CA8449AB13F96B375BAFBCDAD40BE703A77A0D9CAFEF4757EF4E9D5EA0D36506 C916D6CD5C4D2F5555B0165121337190C876172086674EF76551929AF64438D4 B7AD68458B9DC03D0040C2D79D6C5F6A178D9ED52A25A699F294C66AB9E77AAE C4133C373C28A2525112B7C4F0AA6A2B5686632247CC08A9D58A523F4E6091E1 540C646695ED0269C3613EA16B53456C41DC4DE0A547CB49BEDED9F6CF1E7B76 EFCE2D3A994DD6AA9DF57DB885D5D9D9F5B70ED32D35DD7684F2ED7ED4857B52 E0ED3848453EDE86226AFA41A10EE3F098B1286854AD0B0C162C156D5DD6AABA 3D572A66F4C2C838842873FCA5474AC67937E36CF78D967E59639F9313276712 927303D4458C751B9675AAEB6A187C14F5AEEC963AF6FED59E5C378069794992 31AB93140165FD22F1440850E2E806CE61C1514A95DF5B8E24C09789350B17F5 326B38A421B91353C18260AEBFF0B105519799F26EE4206E7CD303C956D99CDE FFF26D76CC98F8DBE79195085084638F2A0E3A90227558019F4915CB140A08AD D30B27FF257EF5C9255360075357E70553A70DA649689692405D4B24690FB12E 8079A1C9FB9C4E0D72CA15BA32C601B4C73D5E899A2D21D5E443C69204C864C1 555537AC7F5577053430CED5D40A105F9C69CA6011B23687DC85438201698228 9CE4FAB26E34B16C381A539E4ED9DCF444BF3584946A57223CC045EC9239D33A 8E8991480D8546CCF5C2FAFF887A0F70CBB2B33A70E7136FBEEFDEFB62D5AB1C BA3AAA5BDDAD6E05D44A080122088381218C8DB1C1603C0EE300FE00631BCCCC 980F0FC21E92E11B10C922B4004B6A49DDA883D4A1AABBBABA2BBCAA97C3CDE1 E4B3F73EF3EF5BC2F37D52A9D47A7AEFDD73F6FED75A7BFFFF5A4C0085448E15 5C2D4D160E8FBFE75DF8A5C1ADDF7AC5295A130A8F2441C1AC22AA65BF51E261 1E6EE8072B0B3F786A5C0E4B0128399AD92920294B601DAAD0D2A02B7CC981C5 20BD38FD8BCDE8B97EA570804E06D4EB018322ACEA914506353409ACC8BFD4A2 17E10D02E83902286811516245D7307A13BB0CC756A400C9B45DB068BC183657 1B08FED912EC3042877E7225097647F632295DA884261B0F0B6E9206CD202165 D298482500EF6E5AC1C3F2E8C651A467ED0B956201A5540632B43C54CE17E021 223701EC036AAD313C941404EC747300BCB37AFAF844CD7CAB4B87276EBE7173 F5F4024FACE920AC7EFC7CB4083C1F96A84CDC01500C67BAACD5E170D0B763E2 CFC8E8D6A1D75A1E67A8F6D863BCD35442A038A79CC7BC70CC45286C7ACCB493 25DAE269367853CB3D1B3B83BFDA4B5F9874DEFB2EF9898BB9A87989A9273150 706459FBA3BD2F7D4EA8EE42C59AEC0FF0CA4AF9F107545920BB487220FB3546 DAB9F280F25BC6FBC174C8A40C480E147561FCB4E61367E64CC1A5239A961563 5F7CF3B55FFDDD3B5B1B392E9E5839BD3C96B0000E507A14E19BCC7EEE7638D9 1FFDE0FDC72FE54775D023CA460E87B2A8526C723879A6CBC6512E4D9126DCB3 AC9953C425B610475E5FFD852AFFBBA3FE136DF1536438AA5413A732DB49B311 7BD3439BD5D947562B8B5BD34FED8E3FB3BEF2CC95B73F78FCC4B75CF8902392 D8635FD8B8F6A72FBE10E7F3D81628237328846A023C687165697FD8AD20E131 CBE29627BC2C4C617D839E6182037384FF43C9716414DA946166CDD224D1923B 40A3F26912C62A836FD61DF4CC9195E988A126C59098B117AC8D2310604AF237 E1B70537851436D587CE3F78E1C4A937EF6C5CDDDD0FA64713ACA1BE1D97F443 27CE9451F848CDBA20D80BBB835B96F3C18AFDF8E4607F5AFF3919BD82B36FAF 94BE41A2724103D30A6ECE348000E52C4D802B214E481EA559409C3B79BECB86 8352F6DA4194CE9C8F754EFDD0B9FB5A887DF1E0EDCFA46F3E01CFA162AF3EF5 CE0FFCE8F75BABAD1CA9B9D128BE7B98ABE9DC010083F2E1C564371CEC392B17 E0C189D9B5EEE6ABFEE2925DAE23F864E27888CA0E1B321DE7A88691C3A0C0E0 596207F0C478040AC32242156F5C611BB7D1BDAB3747DBC7564E8932BC6B2046 89499CDB1F8DDEDC5EB9EF9DAA628D7CE11321766787CFBD642DC48D4B17D262 488DB12749F30A2E1F57C207AD60CEDD11D114C87F2C5F383A78F60B7E59379F 388DCA78361CEC5FBB51AFFA0BCB4D90959252509D25B7552CD850DF73120B5D E0FD54757B544C51E61EBDC87CEEFAF78F53B1C3C3759A9523679741E1BF5A42 7D411FE65DEBA09A7A16485B1699611A097F8DB9E650A28DB8293CBA29A6AF46 C5946B8D9224CA350DB17D1427F17C266D1ACB4A73A1ECA06838C863DA12A50E C82F9A06F562F1C14AA51A6FBCB175E1D47B26A3D95E7AE5CCFA5A31C147D37E ED58471EB2FE2BD3385433AC063937223607F2AC13959BE34346A8410022E061 509280FE51122A9C19A7C3CC45871C374A7665C92F56ECCCCFA54D7D00CCF649 D27CAA9CAF8AF195C4FB2CEF7EE468FD1D27B565525DE7C3A34063ED443089A4 93697A98A9B726C3DBA3EC75279D69EAD8BDB0E8A5A8275528B2713606615536 B33AA0FF04A2760C6ADBF408902A2D952929FBB26C6595942EE27A4CA7D6A3AC F4849D7809324DECB6201900A12EACF24673FFCFDFA6A7ECF6DFBDDF9C264958 CF068F4018C23631A7EBF0588DF5A7328130DE85B533BF88AF7CDD593B2F3C20 5D6C1E9BC434AB9A71283283F5C06294F5959A643CC1B6999707E8323E5C9910 A6661BEB3463C06D66678D1781E90B3367A5994964352963F0E208005E0EECC0 56261ED1E43CC15F6C4A0135CD901EEC3AAD2732F238038C59A478C1E3654064 9C95EBA53C29E269C4DB6936CB79E853DFF6CF73D90C35881373B307DA116B58 FC82C53BF2500F4F3DF551F2F2F0CEFFFBB240F57EC14168032CD7A95DF75D8E A324EA668F596BDF795F501ADAA663942B33BC8C8DE7373573FD325702A49D4C C34A6EBF668FFEFBA07C8080114D30DB452C2C509B48C03249656491EA52473C 39CB5040324CCDD9B5220CCD6EABF8725193BE62512A0A898C582B5ACA5F292B 37735A44FB4A479CDEA1E3D7FBA2C9C5392B15C9DC148D8136054901644DE250 D3298322DEAD8C37801348EFB4D49D28C9734FD74D84943DF58D6F15496D1309 2DCC45B09761D3B0946EF45CAF8E4E38474E6F61C2F5A137DA1D2F3E70F2E8F6 4DD2692EBCEFDC544C2DD8F30946B6599A85C4228866A389A378B4D10D8EA2D6 C90B49B5EADD7729772C78BE3433F7C1802548E4C81868DA5A978021D17C3F8C AF80E8B477F1E0335B296D2C7DE7370D973C8FD96C1421CF0984F225CAFEC7B3 F9C60D67D99B0C7ACC2E951EBB2F3C5E351A3EF773E4525162C8875A4BB98F14 BEABA4E68E5CD8B83C9A242F6146688A91C6DEB4702A3AED3EFDD9CFFCD7CF74 8FC6F737D9938E6DA7D52F26FCB9EEC1059DFD19715EB979E76FD98BDF71AEE1 A4C0B885C3AA0393D200345D1B573207DE51024514512743CC18C5BB11AD4A94 584783C6A70EA2CFCBCD1FBCB0F8BDD9EC48088C6A1B7DDCB5FDCDE9EEF915EF 9C2D8E8E92DFDEECBE75AAF3CC9B6FAD55EAEF5F7F4FA92C8FA6E3E7DF7AFD28 9A496DCCF04CD1478087BA6C1B8B8BF6F2527F3A8255DEAEB739A616005FA2AA C64F1C3EA786070BFA86192E894D39653C963930C854A68AA0511C8EE2A955F2 66699CE7591804599694850F58D2CD036C46844D97D5BCBF14982110DDBB0EDC BAE6BA0B2B4BBD83FD71945B50E01CF8A0BA9CA0F72DAF961CF244C5FE001757 B68F9E23E4C976F3A341703BB17E2DE9BF8CD37788F20791B76CA4BCCE4D9028 6CD64C9ACE057811CE08A867AA0244AEE9649FE539A53B41F695E13057E8DB96 D6FFC93DEF6D11FEC58D57AF26D78E554B4BEBED077FE0E38BEF7F9C7047A689 32ED83949AD0066AD836CD75164E0E0755B74D6A751D6DC6832B0A85E5C5E339 AC4B5251A85E508FE329D07690D346FC2AE395AC494C508A73738652601D6C5E 15A33D67C13BEC1F544E9D705C40B2424AD0D96470F30E4951E5C4695C2E6704 A480EE7DF9453299551E6D1BEB2592663AE58585ED76E42E28E65B11818A92DA 52E409BBB9F3F297FFB455F157EE3D0E12010109BEBE77188C6B0F1C07596C83 3EA62A41A2EEB4B2B61011280428D693E2604C0F22F868AAB0FB2FC40D5611F7 C5337BDF09DB7C6605E5718673FEB6607D665F7246EEC0CB2C9ED3944B5C302B 83FF9819E37B94480B48BEC70E2B93AB111E709EB0244F8ED24920FD28754749 1E726381D67116822CDD9F1ED61C76A154EB50374E93993BABDC4796CF7A8737 BB4DB142AB7C63E7CE6ABB51B2C4F6D15EA9B558C96B5B2FEE4C4754639E283D 90D6C6389E8A59AA556A482E375DCE4AF9966359224ED230498C8B3A66496A72 6EA0EC8392A952FB38676D9A7B96B9AA657EB8F20D15FAB01BDED2FE67EC1B8D ED7BBEE1A25A8DA322B490CF954016CAE1DD134C158829916E4CE26B43EB7932 DC8F79A9310A64374CB7D2A8CF8B50E56E811AA61B051429CB6250862465C6A6 B346FC1A43F552DA62A811D996671DD50E5A1F58B0D60848190C8AD0248C5B91 9B68854A376A7B7F7ECBBAE835FFCE7DD28672CA4DC61FE07C6615A603D5D8CA 90B9D5111416E25D3C76FA17F0EBEF3B0B1CD983EA2A0A61DA4C55512F4C2ED9 4838210061D053D92CB2636AEEEE8C714C9281B8B36C508354CA0CBE2565E616 80506E6E1233C350D334B58001336B1ACC72A530D05FDBC94C9E486E8C66082A 53400E1C2B93CE99283506FE6FD136C52D829A366D50E4316D556C429CB037D5 1DF81E8A0C0DE32D5F74B215404569692346B5A59033B7E4184DB746C1E9777F 945E0BB6FEE015A66B03C2406BD2246B10046B4510A55516BEB738F6F51753A7 4B8962B96322379871BF23E6BC861A13097355A5A6D57E6DAF133C9DE6CF8F6A 859820B98979A8494BC76DCBCCF746DC6A5417C487F3140D98F1BEF661C32250 33876AF22AAECC7C4292C8C9418300BED1B2B457FDA289AC6651B8B9CA90E87B 83170E81E7D41F6A04D6147E35C7AACCEBA156BC403487F786C66CFFAD19E896 DAC912590CA262C872E1AA3A2882C40E1D0545054933A3894C5C2DA3C0BCF26E 26BB5179AD2997937DDC5B1DAF8CF6028F19DBCCC3E8D07D70D53BDD8E64689B 4C0F0039D09231B135E9A7B3A3BE57D84737F6DBD5E55E246B0F3DC0D78F9B93 066DDAE7F1BC4723B11201EC9CD8392A0962A1C9ADA97C43E884BC30E8BED85F FA968FEB47CE02187BA99AC9DCAD80F60882B7AEC56FBED181CA1E07BD3C6CBF FB51DCAA629B22A164D6A4A44109C7849B845AC41116C57CD8C77446CEA7AFA1 D2C9C235ED97A49BE9AA660D3BEABFF9EBBFF7C5DF7E8987F27D27E89ACD5F3B B07F7B73B4F4E099EF5E59FAC5EEE4853FF9C2CFAE9DBEC847DA4AAD1084AFBB 67CB80A9FA149511CD1C5223A962734F7BC23358636C5261518F377EEFC0FEBD 1B379E6A35BEE77CAD31EBCEA00E749DB794FF175E12853B3FBE72BC364AFE32 50BF3B9EEDFBE28DDD5DC5B0D0354A22D8A2C0D10581CD6A3AEE4A76099B564F D3051A4551BDD94863D07878A9B3647A3BB5C939F3E03566D278A7CF33AF91F1 0D3047868A4285D71665456EEE60C33C99E6092A5B53991A17D804F8CAC81C33 0ABA3D1B20FDB59E13D3880D74D75C1298910C264492A7D484C899195F3BCF12 D0D59E584CF4838D66B3513E9F851FB7FDDD71F06759FC507BF1DBD2FC664E3E 1D1F5ED6E9A276DE45AB4BF0CE4D2F19ACAF9CC16F44B1944C6776E024B077BB 28BF95470313FB50DA51EA2B7D50CD7AB5409F38FFC0379DB8D49EC84F065F5A 94F9F19ABBF6F1272FFCC0DFA2F00B2B1315610EBA52A2F282D9B0D3825E77C7 B3DB9EB5846814765F8CE5410D1E112D6BEA17049EA10780498A786EC9C60A9C 2923B719D11946A199A7042ECDD8F8E86D4F0F184EC787FBD6B9932E2C4B6333 002F070FAE6FD896EB1C5B437EB548151D4FB75E79BED92CD9F734292C63738B 03EACF425E2BB14071FA56CEA00A28168BC3A383DFF9B3C9C9E0F4439734D720 8AF1F674E785AB2BEFB894ADB89A04A6AFDFCC413A4E7921A892D2C431CD12A2 ABBB3DB10F7218E4131F7F79BC802BE88162E8ED97831A90CFA0120654FA9B36 D9CBEC336E5C8E580EDB90C6F0390B0B787981022894110DE7C5DCE3E385E056 4C873CD989814BF7513A4BDD28F58F66E150070E638B5673248B5B71CFB5D2B3 8ED3297C873B01E979A7C2130FB6E5240FBBC9C299D6C1CEB428D2A5E38DADDB 3BA870579AAB8737FBDD1B914DCAC0B466D83D9C12A846499A87E66351133AAC 35881EE394A68D534A61928F689A67B6E5609240B92CE9D20A71161D094FCD27 56A6C7AD0F7AAD8F2D81CC1E7E6A70D0ED5EF8C405FDB815E891234B42722432 130638D74CE690698CA6970FC55F8593ED14EAE824D4A324D94CE30382809E96 30A99BA64CD8FB340F61739810254D7595B8755AD4ED7089F216AA8EF130B92F 5D7CEFA271EF2289B103029093E5AC52187BCE37BCAD3FBDB9F0E4A2F77DE773 3CD19CC922750B07C58EE6A1F10B0014BA1B6D8EFD3910FE3C7EF5C993AE2ACA 16761D6C994B881CD5740A8038127640131C0D741EC456842D69DA64CCE03CE8 3A0EF861E6A4CCD51A9AD3776452E260374AD3103CBFB830D97573B7A87CDE03 9E80068FCD8138B32D7B7EEB9FC2BF158E53392A124BD0158B3748D1B0709D03 91C06EDD67CC1D1F0CF266E27A4EB20BF2A5289DB3C9099930738C00FA09DB85 416F20E1497E63BB77EADE27D9406CFEFE4B42D686440C40B0C6699DE08A5378 8C00D0271F559D278E25F61154212E414F5173178CE706880A6B9C1BEF0158D7 EECCC96AF235D6FFC39D5A2C52AA0E621CA6B64BD36619EAA78E25B541367D0C 6B3A2252715DCE920CB39CCEECC157A5D317A098229168CB61A058AD997DCCB3 561CD6CC15205721D8AC3C7BF5B0BB73B4F6F0C9C41D6B1497BC063054E2A809 E90A2ABC6C61F0DA5190C6F57B5AEE9AA38A4C4F42414D327D6AFABBE1010BCA 13C14163FB2915A68724C882B722223CFF8C48AC0098943FAD1F6EEDB4974FAB FE24F465E3A9B37125E388D0D0446449E36AA23815C5FE201E05A0116707937A E7C49DEEF0C4D7BD5F55EB66984399FA7A375D19781437475BCCD4579D67C186 4C76BC49BCFBF475CF3E56FB5FBE33B4338A01588DF335942EF7607AF8977F55 A90044C4FDA3FDCA8317F9BDA78111E1420071D0B4457505DEA0B9DE32FD100C 99FBD4B995E8DCBDDD947963D42060C199591B0622BBE46D6F7EEE673E79F0FC DE2AD60FAC39776CFF17BEBC79EFA57B7FF0F107A783E087DE783178E1C6EF5F 7AB7DBBB36AB147C4A9C846F34C9AEA516A7B895616D630790DBB1012B2C6E85 2E75515A2AB2CB8EFD0FAF6FC611FB95330F3D84C6B7AC81E3BA7CDFFBAAB67E 6EF78DB38BF9CFAF9FF7BAE9AF8EA69FA6D6DBFB07B934D76631C8594305730B 08599ACDAFEA8A566D0133605FA9E338711056FC1270B83AF6166B0BF0170B9B 1602A0934962460B8C209CB75212E36581536A4E56E089807CE1A69BA448A0F0 D3629445E3686AA0713A337CA1E4DDE86ECF0D6BF0DD56353341017B1A889471 5202ADA4EAAC94CBBC0B5CD9449114CBAD85AA5225A4EF5D5B69EF6C7D78A11E 30F6B9EEE864B9FC21574C42F274DABF22533FC3E7A95731291F08A85CC3129C A4B053808AC88C21994D6C7CC0D5519A266931E4F61D07DFE81FAE399565CF8F A3D107D6CF7F57E9F4E7F05BFD8D1BED8A683E7AF1919FF8217B6DC9A4A6983B 6C052B7F667CB7341F76A7C1A4B6B046B09D47BB83EE57EB8B65219A05AB2BE2 22C03373AD60F2DCEEBAF368D86386343033D38422733F23CD24D7E8F0AD320F 493619F5BAA5FBCE99730E36BF60976AB2B1EDD66A7C71B1E06E9115B27B38D9 BFBDB0B89035729E9BDCC41C6A93F099D5C4BC9E66943BAEF1CD1CF56F3DF397 228AD7DE7F32B3711A4EFC9C8FBF7A3D8EE5D2E3F74B01226A8655563041CB0D 566A4676E64E4D77B066037D386007B1820AAEC5E4CB4153B9E8513AB2F74A41 5D84F6CC99C442370ECBE99D40AC5BB2A908E86449227847C85866201242954C E077E520F9981537833B190DE9647B548C894D6A66924DA1512E8FC218F8689D 3AA1549B095479B96C8B256DAD546A091A94DAE9C9FB3BC422DBB76E55563B56 E6DCDCBE76F6819379373FB8D35FB9740AA06DE7D9432BF6FA2A9D112B9A896D 318AE224CE8B5403CD66665CA530CDE4C2CC81426595A969F6373D974A251CF1 1A2DB799D5F14160A06A6103495627C313DFB12E3AADBD2FEEC8A777BCF777AA DF7B6E56F4FD8C31250AE0F53447F35928B3FC0B27DA3CCAFFA43FBB1A94496B 3449C758EF257157D1581750F47DA082854C95E90E6084C750FD68DEE07E9DE1 1A4FDB8C97193FD4070B1F5EF4EEF55334412C272463B901C2A8949A09BF2F8B 9DBFB87DEC5B4FD14F1C83656BFA7E586AC1678A6C0081BF01C27958342A61EF C2B1533F8F5F79E2A45F00EF44B60DA5C86465A22649411D0DB81319CBEF51A1 82D48901384C809309C486ED47EF668E6194C15332065066BD526699F929999B 290BD3E5A718B780A8265249AD33A566716C1E84E06C9EC694194F7A924A39D3 A9A0A8456947E09A05FF220E2E9C86E7F995DE4E377047EDC54EB4930069B1D7 B9739E19BF1664ACA7B0699503710EE2BBD8B8315A5A3A6B91DAD61FBC6C2546 1176E1C565B84255CD551EBCE154C8EF94CBEF5C4D594F83802D5C737B89CC1E C3DA84A8CDB3520D6873112A4AC5B0DEFFEFDDF8CAA0E279D3198E63809CAC5C 4ACB0A109328DF773F468817A23CA3D233263A24E3893F7E2D63BBC811384011 3C538780981ED82B9E7BBA5C34336941ADB3ADC4D1BB6AFFE5ADE66A872F6745 29E4852713AB70A0C2F66D65675BD6643758B85043EB12BE1605859759405803 E0C816A03F4D994D456C5358306E2A7C644931CD466F0ECBCBED625906D9B4CE 5BC12E1A0EB657D7CF1EDDDCF3CF76EC7777026B5C1635D297A0209292A9B964 AC8BA33E7C9CD9CEC4A5FE58D2F2F98BF6FA0965A6A285F1C72C4C279126F09E 2C1365621C86924CF5F278CF8FC2E0F2CEF04AFFD8377D42AF2FC72024F22866 5E895A62308B2FBF21760F28915BC31D7DBC71ECB10773610BAB5C1801CF0AD2 C0C49D0FC7991D06406862783529E613BD737C30BA50CFE39EA82C946B12DE82 67AF3CFD1FFECBE460D852C543672EFCE6D51BC9897BFEC183EF397E73F71629 7EE0D94F9FB44AFF6A61AD7CB03985B29681E8A3FB42F73DE6A4B40D820B6085 817CC3F52C5DA476CC68E1D89A15FF6DB4FF337BC36F3C73F267646D65DADF3B 53B127C9EB01FB5477F8D2E8E05F3E79E69B6D6B7314FEC7ADEE1BF6C25B3B7B B0B48150741697A1B6EF1EECCDD3C7E081719DC99556C7414C46B1C3ED244D5D D795855E607ECD2F63A3B2C85D8326D81AE653DEB5C12FE68DA6F3E15E743716 7B2EEF0C2B008DA854AAF2C974624E16D32C4F63A75A7EE37083DEDDCDF35145 056289981B3813CE90E52DBB74CFC933A3FEF0DAD16E4E80F0148F1C3B9BE5E1 E1E8E84367CF2C6EED3CDAA9E5BEF7E29D430FA9274FB4AB63F19769EF0D09AB 1BADF865A2321D67AD421C2B977D66DAE7617700F04CE2B8B07860D3FD241CC6 E958F06EC5DEE8F7AB123F7ECF85EDBD5B1DD085CB174B6DFBE5AB5F112E699F 3DF6E83FF801EFF17B22A27DE0D0719E739639164A02D43DB4FD3275CB80F593 C3D7993D76AB35AC17906815E68218CD8F8ED13C40DC74CA0210CE2D06FE7F20 943965840C0FDFAEF219C96693F1B074FF451AE600B3E6942988C71BDBFECA0A 6DB57205EC9E46FD43D08DEE4225250362263EE1E7D8A6AB9654715136A93850 73E278F8FC8BBD1B57CE7DFDE31A87110A6DDBD5370F0EAEDC3EF68EFB74CB95 725CC8501B972ECFAA2F69BB2A696899D1994C93093E1CA18340F14C2A2B782E 2CA7367BB73575F6DD4959246EE04C12AE1ADD72B431B58E7BAA91E30C8A0810 0DA051CC36330219A09029942080546AE5B578B750B1096318BD3E6E67ABD344 1D5AC904E1C3941D005CC6012CF1313C09DBAE736B15E125072859EA558B53F7 766847DEEADDAECCDCF6F2D937DE7ABED4B48E37EEDDBBB6CDD600C42AA397E3 F1B558B92426D66840B6E83449A06AE3697EB7D90BAB3C8382E870C188B9FF9A 8F02E05C00039436B22AC47789AEB9A865B17A2A6A8E73C0B7563ED659FCBA33 836050FDD9C33BEBF9897FF1BEC01A7971064B3C354EB173037A0010003513D6 14E59F9DECFED9EDD6AC9164F4A848FAA99CC62446146427140D582CB1248048 1613B9CE31CA2B0E6F525645A8CA7186C7AA23979E5AD31D58B5A17059968476 E1105C1F5B230195E40B62FF0B3BC7BEFF1CFDC6A68A5280DE5C8442531CBB05 4FD0DDAD63E41A7C2E0FBB170D10BEF6EE5325444A4657490A8B8F156C619E79 D9274EC8244E860084B13D310EBA003ED490CF627EA008DF0C1BE35043F53099 07D70B44CD0521312EF92640079E6A142505A5A93479868085E62B4D6E01C086 E98CE7C681112708687551CBE592C3CB0EA908F8A2D4AAC2EE6876770E07A4BB 726C490F009313DE21DE799EB9B1996384DD0F02C72E8041028E766F6BE06995 726BF34F2F97C246AF207BD830F512C99B25ED178C4FADFCEF456BF71DCBC9C0 5C1B140E9B1FBF4962FC5C4165514313356C311BC711496C2898AFA98D3FB9DE CA2A3CB4B2A2D2CD61D5650D92708D725EE21F525E8B64D9AC481932869B9264 767CAD409BCAA72CD421B22D07F61719B045AB74A1AE3A266BDA045227859797 7ACFEED9C82BDFC793D201CBE16394254D9C82A5DBC1DEED41E7D48A759C457C 64A691536A030469994AC5984590CE405611636E04EF4C315B283FDE9F26F1B8 71AA539823EB1CA4DEE8B531AEF0925FDADADE3EF1A187B39334A6D312F5C958 6A9747967139C4C38C77276A968FB606C26B465E79F189F72A6E23C44133CF87 A04D4556C05B239132AA6D66159338DB349EC55BA3DDCFBF595DBFA7F2D4FBCD 9DB06DA56A3663763BC6EAEDDBA357BE521356BCB71BAF56BCA71E50B6F0ED06 6803D87BB6F1512BC39A2FBE361407F807E4930246CEFB1FC9DC9A99CEE7E44C 9B2443AE5923697AF5379F7EEEB73E9D059353172E6D6C05BD507FE07DEFBB47 2CB09E7AE6F6E55F7EE5F31FB8E7CC0773DC9E0663A48726924A1CC4B1767CA2 68091E8B8A5DD88C022F2279064A4F82A7EDD65FD3F0172FBF917AF4EF9FBFFF 9B67510D8A4BC59FF4833F60F8D7EE6CBDC7E13F7DFE44054F3FABE5FFB33DDD 291A6FEFEF6548B73BD58F3CFAD8EB37B7AEBEF5568CE41CD58C925D5E588437 88C2D4179656DA761DA88B25CB29DBC6B889409593A6CAC3EE302799D424712A 0367F35979E3503DEF8E146CCE2D0BF3650A0A149ECCA677BBDCA671C87CFBC6 E11D35372DBDDB276334A1695895773D5939E38D4603FEE1E8A817535955ECA9 330F8EF2F1D5BD1B1F3E75EA646F7CA1E913DFBF7EE7683CE9DFF7E0897BC7DE 6783DEEB99F1F76A346A411AE2245FD4D61265CB350F7E03102E59A85F47B345 EA95B8BB934737B3E9D402547336C6A383DEE4DB1FBAFF14289AC36D5A151F6F ACBF19ED1FD170A9D678ECBBBEADFE5D1FECA9B0A94C376268C29930198C30CD 45B50A2B2B1AEEA6F95E6DC1CE12222A67505E3221CC800E26CB777E666E9E4B 6EFC264C3F235425038426F4145639E393A31B567E6401F1980CC5B9532CD6C8 E4DE68D49FF66FDEAE9E3E41173B2823342B86BD5DCAD272D9962C80E7A80B4E AC1273EA543948D9D2487299DFBCD57FF64B6B97D68A15972441649996E9C94B 372A201C2FAD87C5647ED51529A87D5E5D5417135A6264CA126D4C4F508CF626 456F988BB85056F85C2A26C87B5F79EA1F38235F644EEC8609D0E89E1B6ECCFC 636559CF0161B09A37C5E5D8CA81C5E426BD0ADE36CA321470ED98A8D34958AE 540FBEB4DFD85DC8B262DF098714F5A57B3B8C6932A999F3143BE6BED0E21823 0D9A5002FF7F79EAFE657536EBF17EF5AAF04F1D9B0E777B77B64F9F797C340B 0EA7D78F9F5ED5637FE3B95D4FB919B60EB3E2C8043BA89CF3699A4ED3CC9CF9 410121C462266368EE1466B6642FEFCB1C7445A9223C60688E5D74985892EE82 ED0E71B7FC88BFF61DA7466BD3DAFF367D5DED9CFFB7DF4A57349EF68BCC18C9 4311A3C6FD83602D8A22569598BC45B67FFD4AF52AE5BCBCA38348D12C109272 ED02EE65B34C82B8764C6268A13240655976709D8886B22C4BF5D94EF3915AED 5253959290C59663C14F0110C0B832B07A1EF58AFF61ED3C73FBC48F9EA71F29 CB00349C9F5913A8293CF1A0BEDEE59026D9CB40B34B9D7B0C10BEFAEE935093 4AC204353005D255B3163C51584CD40DE68A50E741624F0B730E6378E8BCDFC6 E86713124BCD50053C26CC930C56A7E9AA30FF000AB4319A31DA4A9A53089D99 C56BFA2180E3810464C68803CF67B391197224CAA5785588A6851DAE7D01942D 112551AD2FF40FBA3D74B0BCB6EC24DEE4604A6A857FDE4E4B213C5766EA062E 6C8D84661CA93D7F3A4C1716DABBCFDCAC4C1B3D856FAB34C88A1A2F9A7E5641 8E9FD6937F3C5A5CEEC8620AFA0ADEAE49CE52853144A366E8854B7338273901 099DCD671E5964753FDB475F9195D892DC3D4C28FCC00A1F7333505047EF4BAB C7EC5406CA38219BDE13E3ABB649A36B91673AEE520DEA1759091FB345BB725F 537522E3C79B5B6996D44869F67CA8BBA4F24E67E45D7770495397712136C9E0 ED03D224EEBDF033932253250A1CD964CF18D71900B85C48912B31E5F0BF602F B2279C1131686D5EDBF64F15CD13B562EC620C346A387A63DA5A3F79B4BFC397 9CFABBCEC806C8FC8CC3C70202EC38C0AB6D78D9E340EC4ED241988568AA45FD 9EFBC4DA7AC13D63948E855931C61CFA6E5A00CB29084F46655747B7C9B83B7E 65331BC8958F7E24AA542829C1030418B780456C6EF59FFBEB16C2D1B09F9458 FD917B74A786400A60DB9043D1D0D467B484E7E652F3593863233D1FE7BD3B16 C78AAF053300B498B1266497AD74126D6D3CF79F3EB5FDB9B7D6CA4DDDA8BFB0 D5FDC0E31F68D9DEE76EBCF9ECCECEC1EE418944DF77F1FCE9FE44A43A70DDAD 3018507DA0F204D669CEA1986B8F74526C09DEC1F9258ADBD2DB6A2CFCD26CF3 8FAEEF7EA45AFDFB2BABA7E8D861C44A2B7F5DA85F1FF65EE9F67FFA814BDF26 F20C87BFAFD17FDD9E5C19299917AE218349AD52EA85599AA47747FC2C900FAE CB99B06C4B2699673BF0EEAA8E2FD3BCE6F836E5E6CCF76B6964C6BC23498171 C14E344E31C6C2B728E61EE3461432CE01D5CC640414B61CC83F0E6566463819 0AB2B860786FBC1FA69971EE85DF06CA2632B94E0E6080D97BA6DB08F61C3697 F624A37241DB1F39F7D084445FD9B8FC5867F9CC3838532FD7ABB5839DDE667F BF75EFEA53B3CAB3D3FE952C9AE8BCBE509BC521EC2D33F23A9E5C5A5DB28119 E7548EB267E8609597D6453DD0FA9A9A1C808221D684165777F79F6C74BEB772 4C4E8E5EAA0EBF3B6DF73BE2CDBC57C6EC9DDFFCD1F51FFFDBC32284B28F2D36 A5120F433FC8D0828B1D167481A50CEA0DD03150392A18B70A6CAE7A60E10000 12650344CD8F066233D6F53F81B0084D8E0094105D8C0EAFE7E38DCE42399E0C F1E9755B52399F66C6FD59EFC6CDCAD993B4D3615021E3BCDBDBC222AB571CA9 2758F39CBA8553B17099197F44A0FBCACEE2CD673EEF90B07371458B047E2C28 97607B307E7D73EDF4C9E2C2D234EEC2BB344E9396CD2A9DC25D302603C504F6 7381CD9809DE0D8A7E37B526447BF1F34AED45B5F79527D5811B9444EE244E98 E0B43C74A6B7A6E5B5BAAEE6C607A12019BC7B13D560C64AE1ED935C0025CF49 606CBC22676F6FB8B4BC92DFCCD0654966B44BD301C1A3540CC2D4E5D94219D4 3EE9675C6662D5154D01EF29D149DA3A59668FE84965265EB367F570B1B2327C F548D45DB66CEFDCBABDD45E14357FE74A9743D5C16ED70D0FC62C452A4664A6 D4288E3313B74E384102649169FCFA5AF4DEB808A5A41E714AC6D627670C2D62 EB94552D8324A179560FDA1F6FDBDF5AB57E51BFF8DA978FFFC8D777DE7D1CE5 5D94A55A17719E820E7381842273C0352D0DBDA8A9FF702FF9D4B6454A07A69F 92D199035F14D979A0A369063F8C0A33AB97F1027B1C953CBD40EDBA2C6B1E8F DBFB2BEF6BB305513832A02123B6458489DDD1D6A434720B5FFF85BDFBFCD6F1 7F7412BFDF9563DBCAAAB93328A03E679582A666E26F7E6F37BF6077897B71ED D42FE057DEB55E42B8649BA302C3D840B0358D750319723FE405CBC64885B13D 0618CB73F34824283A09AFCB640E99DC5D9315035B3188E777888216FFD3F962 9E50683A7ECC3C7F91E6C62727CBF35419BB2473DD05CA5299AB70C68A326767 2AE59221CC89CB49912796272ACDF6F0A83724BDD662D32B2AA3CD113CC6C6FD 95C09B144271D3C84AB589E8C8103C93C3FAC1F6A8DDEE745FDC2B8DAB6344AE C7612449DBE3353B2A13A7499666FFE2B0CAEB501B55B9904871C53830112673 D39F42456E999222A006C534F7E274C64A946F785BBFB1D7081C49F534F54C54 86DD67F64CA44DF578563FE9A708D6CFDCCD1C135794F51E9DBC3CB06366CE73 9031764A450840587F475B2D0626A734B3421954B82D2FB3E47A5A7B27A0D81D 4B394C9698B4A7AF4C509AD51F2CA72B12B6A397D95032B5C8620B882E7733D3 7A272D0D4ADFCA7D8C3D783382F1EC3A1B76A70B0FFB8998FAD902658DC1CE75 148B4675716BFBFAE2BB4FB18B8D8840F111344F7491C6B0CE59D561D6EC60DB DF9C4C7B13E2D413BFDE7CE811ED5630B28C0103D4A7393327F3204AA41259F8 196599DE2FC5DB78F360FBE58DF63BDFC5CEAD4B5888B9672A96501E148C97BE AC0E77168B62904CEDC72F586B2B0C6AB9E72588581AB4603DB36A50ADB99EFB 0F997482BBCD8F64EEC0424DFACDBC9A19EBA93403A6143AACA266D34F3FFDCC 27FFB2BF5B744A8D60365EB9FFA1A2B5FEAB7FFC07CF1FED74790164E1137EF9 7BD696FD381AC8E23AA020425395A5D43A8AB3DC766669D06A54EC28B7915592 93C7AACE057FF135497EFACEF509927F6FE1F453F96CA99D624AEBD3CA7FE0EA F3576F741AF59FB8EFD42372789444BF1BD3FFEBD6DE81E29756D68B5970ABB7 131965C7808D29133A897C6A2FB516B1F1F435A749405CB354964BA5344D9739 ACEBF9911331F92CB1CAE6B601866C93B9E4A677E7CD91C91B84FACEA03602FF D7AA009DCCA1489A7C3833EB8D549426A02326E9781206DCF7C6D1AC3F9B09CB 9C1B6BE38F85E7C73DF3C1FBF974363CF8B6B23F7CE681C4D15F78F38507AA8D D5C1F4EC42E3747B71B633787BBC9F9D697DCBCC7B359CBD9E875D95759A2089 F3DC16C6C874F7E091D3EB160120C4F6A4781E7781D8B678B9949103141FDA3A 036547F9AB7B7B6B19FADF574186E4CF7B87EF9AF264B57C393C82D7FAC0C79E 7AF027BE1FD6358F00358B10C4407F5AA15651B1B370904413CBA2B603D59C62 0640E817462843318C0D0F520229CF180798F04EA58DE0E6C8F81E46A60A2906 1F713AB83D3BB8B6B2D24C46030042ABE0505B8C97C7249EDCBCE59E3EAECA25 BB7081800F463B9867F5B293A57D33086B5732ABE229782F3C64DA0C8EDDB8B5 FFFACB8BF72D922A42C164665B256D1FBDF4368EE5C203E72736B0A9DCCB22A6 B5B47DD65CCE691DB8874306854AE725A4C03BD3A27F90B81328DAC90B2AD898 2CBCBB1C34666E5EE6999D88598AB272E00CAF0FABCB4D5283C2189A2E3F784C 12B8697E37EF9C0206314B1B9A3413BA74E7ADC35AA5531795F18BFB6EDF8D02 36B6C424913863024867191DCD86BBC32C4F9DBAE7343C552954057152CE6AEF 71C35A80EFF03DB9797AE921BC4576A35BED7B6A93DD14E5ACBA66C7DD78F825 E4E3C6D4E9ED067E2CF3512667480F63E3AE09AC8E6805A2D0052523B33C939C 0BE0E2A9C482309B12902E8CF20E128B489718AAFBE5500ED923F8D88F9D67B7 565FF8B5DF5978E2E153DFF1882ECD884E8B08785C04506069DB58B23B6AE01C 79F682FB5231FAD92FD3C89A95589E1476E04A22263C1EE6B3694E2739A626CD 5D96B85DB758C9C96AC4AA66A5800CD50351E73D2D44CC383E5494C278DE8B79 1E120B4A330B6AE567DDC1CDE1C20F778A27B81E94ECACAABC518E52F80B6076 3137003669E4A6AE39D8B90B844FAC97112E833A006E24917039AAEB98E8A28B CBB1AD713C453A4CBD99696B93783EA0CF8C0DAB394CA4E6CA03E7C61591E673 636F6CDB20AD67B319AC5F61C265CC2049264D78AF9C4757C8BB1724001D5C28 60DF8899DCE5346EBBCE8A2D7C58FE76C10144B42416AD34162683E108F79BCB 0DA7288D37C6003795B32E3EA6231458D8E2005EF0C1DC4C0BEC8F1B3B57F757 3AABFD57BB02785841B795E1214D0B04486015B8EDAD4CFEF5A11B3650AAAC36 0FF2A1472B0838334F731E412DE569C9586371A09C884E3D8493C81A3A613BFC 8C1ABF7050F5DD59C818A9A4A427EC00F85A7C6FB474EF620E5F6FA6505922B5 EB54D47E31FC6A1F049BB1D6828F43BD0005B46335DED140C7329305998A5CA4 166CEC8D52FFF9AE7F0947C7BB9EA83AD3C6E8D668BC3F38767A811C63118F0B 6A0155B34C2F156C7C9E8154D0CAC434992E09336961CC7A6DAB48D9D6953BEB A7CF2B37926565FA220377FFEDBDE5D32BD36148BD42DC5347EB9584300F39A0 B5F33C48A923784324321A1C8AB70EFB9390D4DAA5D317EC53671476745C7078 C31C44A0996B67DAD0F4CC4D78EE67B94AF041A9BFA15EBAAECACBF43D8FA7A0 84A0F8C047D2D22C8937AFA69B1B561E1E8D776B0F9E15A78F25C2B509FC5CE0 97405E4A84D614142045E709B4F3EBB1BBDD385007089B5B8F60736558CCC552 9C13DB8DEDC4DFD9D8FAA94FBEF56A783954924C1F595DEF9C7AD74FFDE99FBF 7670E7C9F555A1ECCFCD7A3FE9369FF0F8969EDE90723B5121C759902CF2C6F5 C9F4B0E3A679D28E95B6AC31266D22DFCF8B0BB5852F06F97FBE7973C5ADFDAF 8B27DE21878B0B8965D940BC7FA4620597EF7CE8C4B10F1DB757D4743765FFF6 46F7F7BAA39653FBF0BD0FBE79B0F9C2F60632A94B06B70A33C980AAC23DDEE8 D839F60807C2211CFB6832A4654F5BA294A2B2ED9A9C4E40975C9A7307CE3013 699E11369F9E9847C011A98C2A84D74A8CF831DDD7715A2BFBE12C30E7549C19 EBEDB93F7324C3A36E1764DD61BF1BA92C4645A25576174BE727CB646EBE969A F635B25CF8DF78F1918362FAF9375FBEE4BBF74209D5FAD1F5D374A777797A78 E754E3FBA6CEF534BD56245BD178AD0404DFDA2DF26BA3DE5AA97CDCB127E3DE B9B553A29BDEC9BA61DDCB357207A95F297531EC2D1A15FC2B83233BCCFEF5E9 87EF0FD31E1954B2041D6BBD363D4A5D76E2FD8F7EF0277F44BA8C25C61921E7 85849A8D8CA3F774D6B33D2E1C6BCE85E04F5B9B5B17A87CE69CD264F76AD345 65F2063000EEFCD809D6A401C218991909D36B94CDF6BAB7BFBAB6D20A864764 FDB82B1C73B198E52C2B665B5BB85AF28F9DD0938458F660B49F25FDC5A59606 4D950AED3632A7862326300FCDD57C3878E64B154F93FB9BA99AF8B364ECBBE5 837CF6F24D7F79915C5C497080F2D0CA12E3DA5CAEEA6A5B92322F3C2C811CE4 393656376C67ACFA3BA93D66ACC2DF760E5F36C7777A459214F11488718280ED C6D6E8EDA157A9F016D0ED99B92782B560AC048D9C30A125665AD4866A9A9318 403AEF3BD36EDC596F0F6F6CCA2BAA161DDB0FF3C84232011E2F431EF5B2519E 505E34E1DBF81EAE15599390008F3A4F56BD130C4D937030AA3BCBD8AA1D1DDC 74CBF035B5CD3BDBED4EC321E5C3CB1379806AC2BBAD71AA8B00E3EDD1B8078A D01C5B6807D6ADE372636C96CF4521BC02135306A8AB01C285F0AD4AAB600D9A 945D5D86529CE9A83D5DFFB177BAE74FBEFD4B7F840BFFEC0F7F74DA49A03C59 B0EF74042B9466B0B24116CA808F946BD76E78F1FFF172787D8A6A3EE8462B64 C2F27B320890EE2712E8BF329D9DB96758122959498581CE280D69B7FA7EDBBF C7C4D46106944051E21258423831FFBD8171200E7FE30800A1F1CFCF8D5BFB4E D4B29292B447406558E21A177073FF8C0C700270118F3A97D64EFE3C7EE3DD27 4A98F9B609420590140E55C65B5AE33EF503106C0608A3D899CD334429C2E6EE 08B8A6910C869801FDD2F3D9994C9AA3AD5C70591461181A431973B80CAAD18A 61079B0352038AA6B3609E4CA3058FA0A649E5987637D914B443695960133DCF 8B224BB0A0D5566BDC1F4EE9B8BDBA006A69726B0ADFC539C1D9E9221111539C 436D65803F4059991B94861B6327F366B74211FA5141BB66CCB1A852E4511057 796B796DF61387D6A039DA1D358EB9A402E86599E34C16491A60E08579D90C42 D289C9DBCB804802A48CA9F6E357F9E0995E3516798A41AF67F06AADB44892F8 6CBEFAC06A6E87B057091240A56067E3A19EBC3273C62ED612BE52303F46296E F3DA23757ACC645DA34C980C709D91FD4AFF2BBDBC31AD3FC06191B0CD4AEF66 57B4F3E67920A3DAF4AD2366F240A03400422061A6BA0C834C051524A9656482 5C69A9DA702B907ADA5AEF68ECA43AB4ABEAF08D6E3958B24E59FDBD3BF5734B E26453379C1003F9B1A04640CDCD807E50614758ED8D465FBDEC2DAD8E2DB7FD D03B812953E682E8348E79B0C82CA84985303407856E62836286DF2B0239F876 76E7C8BEF4587CF66210ABBAE2D4B28A2289F777A6CF7FA9C34438E98EABC5C2 BB1E4885EDD5DA4A512EADB92588A778DD36C29A98523DEFD8BDEB4C6B96A72A 602BCCEFB0B1B9B5070E298BDC11169DE13F7C7AE3579E7971536E7AEAECBA7B 6CF1FC2FFFD5F597B7EF7CCBB9950745EBC641FA5FE25BFFAE73FC741EDCC826 6F14A80F7296F37C9632258616BB120F6063A3FEB8596FBE4AD2EA70F6CFEBD5 77AC9FF8E4E1DE1FED1C3D6AB5FEF6F2F163EAF0F4A259DBE3BEFA04D5176EF7 7FE0E4F1FB3AC6EBE07222FEE94BD75EC9D4C395C58F3CF0E09FDD78F5B5EEFE FC44D4FCEA20DB5CCB76A9586BB6E159D56C3F8B922089467168E60F1872B86B 33E10BDB0024A615DF8F03D34086E66D74F0888D3FE9DCC09E980E7220148076 459EE78E65CB2432F734981A5B0046A22C4974465D3A198E6D61455138188F32 5204E60855DD75F29C0FA3983F41CB27142F49F75B2F3EDAF5E49F5E79FEA152 E93461FDF1E8BDC74F9E9BA92F8FF75F3ED7FCE1D0BE31996D503542F912E26E 5AECB9FCABB371B364350A340B66E78EAF47B77ABE571C719471EEE420148CFF 294D7462F92FE4E36E6FF023CBE7BF03FBE5788278DC5D702ECB09C8CADAC5E3 DFFEEFFF49D6F4193055280E383117DCB98A76FB9A0BAFE6C2E39E3F436B7EC9 6AD26C8CDBA019A781F292C39FC60A17B629905D73674C01E5BEA6088D028075 DCDFBFF1D26AAB341D0CD0E262B9D100E26DB2A3A48ABA3D5893D6C2A2415546 87E3C374D25DECC0520D696223DE504ECD442C9825A7D5C1D6F6B3CF9C7EE46C B488A40C4A814C2A6572793F7A63ABF2F03D72CD07EEE8A4B17100A71C971AAA D254D8159928701FB64A06220BAAF1CE400D76949851EAA11B6CE7A5ADC57BDB D67957E7E6272604CA74EAE6D6E0E68433A7BC5A966422E773A41C5E38C87F25 94B14CCC84B1352292A65089E8B0D2BF33A99C7499930FBE3024576B8856FA38 34E3DE9AF6F5742447E5C2A990768444AA924A91B45C963AB362499D78B893D9 47D666651A8EABE717A6BBA3E0285E3CDDE88D8EC8D06BAD9CEC1EDD9EBE395D 999CD8ABA8DE6436D5786446BA55529895444D109060042B53BC4D87B9CC78CE 400B66B28840109550A551B0AA1302312849BA4CEA33326E7DDD9AF38FCE057F F87AEF85DD533FF15DC15981E2A19F83BC880A159BCB30787136C94912B879BD 5B91BF71BDF7C55D2E2CDBB16520811F4BC6474916E4C804EE689D1300425A27 DCC5719913331F508B5A1FAC9095CC9C2001A912409504C61CB1CC60920D6FB8 7CF07B7B4EA55AFB87A7A78DBE1DD6445252F6081620CF1C6482B1D5D7EED6E1 836217BBF7ACADFF02BEF69E5365CA3C335B9519670F97C98ACA186243E64E01 B49280A069206242E15D9953584A401A5BF03B01024259848A03C43055590E2B 5C8F0DA5A573B73574D78514336AFE6E92591428D2BB8EA30615399FC9348BA2 326C09018F552D5256F3810F01BE111987CC629585D6B03748ACA87D7C0134E0 6C23D451C196917B89C56E4033269003D5553A923AB62D45B29DC51B99EC6222 BD108483CC41C4D738F5890A51D879603DFDEEBE356E6F5FD95A58769DE315C3 298C571B68AFD8F4DE296F3EB71B19031C135108CF2B350315E352EF2F87D64D 201324621AD8A86BDAF986E1B1F4F8C3A754395245400B3B31466B984724B81C 899E8B954EF2808A520EFBB94DABEFACB063269C43E79C58A00B2336ABF45F1F 8DC3DD534F9E8C7AD3E01A4A86B3A57795E92A8E9284988C66F8EA79CAB1A9CF 5A619919276EE33F61CF9AC0A0423F7767A5E0D6D85DE57881A1AC04D5222EBA 375EDCBCFF9EAF9F4437C77CB4F2C0495AAD148E1D71001F622716D64C195FC2 C4499CFE73D76930410B0BA8B35C3E7F092AB76795E6BE8EE6423863A65DCCDC E3C21275482C63574778FBC6E4EDD7BDA51576E19DB96817856B3AA7F200C783 DE1B5F294DC7C56C36C9C2C5C7EF4F6AAEF47D78FC423BF02BE744C093B37099 E666B5CD93D88DF9F23CB5157F2DC39CD12237C7B2734F7E1AC1FB4371F9F6ED 3BBFFCE9B7BEB4B99FC965905D8B9DFFF6D5B79FBE71F0D19367DE9B903493CF 04D32F8AF8EFAE1FABEFEE1E8C835EBDBE0BDC0DE87EB9F495DE3EAB5647FB47 CCB6F793A0A9C9BE83CE4BF44B2BEB2BB5DACF0D0E7EFBF6EE93BC0640785C1E DDB75A0EB36C6726BF47451FE9CEFEE5E9932B1EDAB3ED3F1AC4BFF0EA5B7D44 BFF9A147D7176ABFF5F9CF1C8174C5FC6E972714F0B2E3352BD595C5E5DEE1E1 6C32B5B900E4E366839AEEB20469732390248270509C734B7DDB757CD808E67C 466AA68D19B7D4B905EF9CE04CE666301CAA07286CA06704D0687A34ECC649CC 0B66B99666C5340CDC4AC91818723A9E4DA33432BBFB6EF7CCDF602108C219A3 AD9C7FECD8FDF18AFFC7979FBB5788D37EF9ADDDBD0FACAEBD1FB94FEF6D7CE6 4CFD1F276237CE0E61BD5BA41EE7AE243B367F9BE5C079670787366C43A7E4A5 D6825B6CF7477EA3912B099FC08A132F2791F02E73756D7BF35BAA4B3FDE58BD 309CB83CBDB2C8BEA42645AE17D616BFFBFFFE37F14A05E80F4912694BD07449 7F04EBD82DB7A9230A122358D7C89ADF46A7F3EAE4226D1914242122F0A10402 5668AED298493DC5192A22F884528B799AC76470E7D532C9F23891E58AB7D892 A6D022AC54321AA5D3A8D2592DBC9244791C0C83ED3B4BED0668271C8300AD23 BB1111D38A0108377CED451975DBEF3811B150E59963AE6A59F8C2CD6292951F BB67E6A52C091D2065486BDB077AAE9DB28996CA8926236C625EB569FFDD3B42 FD5D64CE876CD6F576FEFAB6D72AD5DFD196B887130F049CD29153F0E1ED591E 91CE9976CE46B0D01170449D9B0C40ED6963F01213100254289A43D9E4B37AB8 13E6B5C45BA5D1D52C7C96E2D0C93830228E241BA324E15903D94E5E0A0AEB60 3C2CA964B9CA59598ED4E0F8432BE1D9A1BFD3D93DDCB4D76855B40637864E13 719B8E6FCB6667397567E32BFDE6EED2AC661D0C8C3342CCC4486AA0D5B94952 508C9A442625E7F699B0D033812C2A854A113068EA655E9DF24A2575BDD8CBF0 497B290BA7A24EF4272FB46F93BDDFFCEB951FFD8ED98355924EBC34332DD02A C1292C6CA284E94E1C5BD3AAACE9CF8E767FE7552B20F57635C56930082D5C8D 9322967A92ABB1420914654A5AC4F1740A0B3F67917FC12E3F5691EE94CE7B5D B06DCD033C04D429D3A1026A6D52D9FAE35BF573C7AADF737CE60F455CB2325B F300C1EBCA9839CCC46A4EBE4D1B6B0140E85C9803E11327AA427836F047A03C 58F8DC0021ECC001B5A698D03CA26832E58324855D6F31D08EDC6120493435ED 9F7783D7580C40A88994C55162CCD68C78348F6EDE04605A5A18A50C38303C51 732C0EE42296F0BA43ACD23028715E732D5FE66D4E6A2ED44C0DF826A3D0726C AFDE1876FBCACF5B6BF50878C24E814382DBDABE9F45EE8866DC2325C9CD4C82 B05DCC547E278F5FCBD5D44A40C5171614644FC8051BD40A19F2E1CA074EE5EF 19F3B4B3F5D5DB154754EF5D36D70F730B93BB1359007CD41CD098F47A693A78 CC04535E4C397527CFC6E197121F899C4B99330783F01D05ABC9DAC32775DD58 0230EDE4C0E9502E1212BC9EA05DCE0BC0FEB0A06E6192D048E5B1BB40082AC7 38905095E1D83E7AB33BD8DEBDF08EFBB34178F076D72DD1E663CDC29DC5A671 1C0B000B0908C8312388A77325EF6922109AB87105D974C28AF1CD5E4D8AF2E9 FAC40A69E1F8ACBCF5E6EB4C92E593F76FDFB95A7BA4E3AFD79130B35999F1C8 03B876B0320F59B32CDD184D5EDC6FAC75BA52B61E7E272A35726479C0BDA49E 4FE94B73525300F904D50F845DC46CCAA747E9575E8982E9C2534FE6A50E4B6A 8A97429C95E3517EEB4AD0BFEDE5D94EEF70FDC1FB68A723294DA0B4F312CF6D 4DBD54B80400590A73BA478D33CEFC248FCE5D28E9DD648579B3BC199E564037 A8C9A123BBBBD16FFED9AB7FBDBD3588CEF87AA9B1F0EBB746BF73E3FA074F74 9EA2F5FE6682D75B2F75DF3C40D5733E42B3D158D3D4AEC0AFDD1FF5C37AF9CB 7B07EBAD160FA3C3301C39C4494C0FD7DF5959FA67ED9654EA57A2E83FDDD8B8 C7297DCFF2DA7DE1F462A77C27093614FA8F38F9C62CFDB14EA75AB0ABC2FFC9 B76E3EDD1B54FDCA479E7CD7D1D1DE33AF5E8152991B4FB87900A152CD4A0D04 9F8D49D01B9C595C3DB774BC4A2C1FF65C942E546A5ACB02D86496F483C9C6E1 DEC6781FE00CB920149D5AAD69814A94C6DD51C0F74C1313F08BE19B4B909989 C07BA3FED1F04886F19A573D596A3CB87CAA51AA0CF2707F3ABA393E7C75FB76 F9F8522F9C0E470383827727A3EEEA428C1C8402C1A1C03C513FE15D3CF6992B 5F5E4EE38BCB2B5777773FD0687FC26B7EEAF65BBFDEC0FF8A97668C0FA58465 69A7994DF921A16F4441EE893C8D81F745D3FCF8D271474F7BDDC9F2F25A1CC7 6E495095F058878A6F337CFD68FFD152E59FAE9E7CB83B6ECBF4F575EFD3B29F 8DC3B5E5C5EFFC3FFF99FBF07933D2AE15B26432EAE9716A3517886861731D3C 2D4C1C87652E445168062BCDB8A36B9A0A68500016C2C35056C1726D98BC11CC 18AA30C1498AB931BA9A64C39B4977CF1CBE82DA5E6D213C1FE142D238F1DC39 6AB4D754A316B3DC2D54FFD5D75A504A2F547504DCBC89456D0A786231676BE7 E0852F761E5A554D9CE529F0FA02166D2F1ABEFA76A9B3C4D71B118DED28606A DEEB50A95BB54E414CF1254AE52480CD6C1AE675210FF748779F10D3244F93EA E0853D99EAF6A36BB2DC2D427B7EAF19C12B1E6FC5C151B67A715559E30C084B CEB802DD0E8FC1377D374639518685341E9F0A102E3E88631C95D64B3CF5C62F 8583AB9312F6D03CFB391238E5C60D4FA7A41B4858448BBED302E2A426526776 C7CDDFABAB893B194483383971EEE4646F3F389C2DADAE47E1B8178E97564EA6 DBB3E0C61ECE5702254D063B2643F833CB7255CC2FB58CF1406EBA3ECD4D18E0 2F14A294C918674CD2B2744D66851B83A25960F62AAB3B20829278F8EF5B671A F74D7FF3AFC4B73D55BC6B95E4130B38049DEF6B7353986648B18CE54EC4B045 EE587BFFF945B111F91DD75973F76EEDF23160512988A371968FB03B2B329BE8 45ECD51163561C54FA4BEF6EB3632223017778614E966D733669CECD4CCB89E9 24DC73DE7EFAF2EA53EFA87DFD5208023D179682629C98C93FD3A6691AB1EE5A 51986E6DF2FFB1F51ED09A5D5979E009F79C1BFFFCFF2FBF57394815A45256AB D5916E846968A0A15960C0064CB2978D5963CF78ECB107B0595E06838119184C B0C1188C8176B3A01DBA69E8AC56E852A924554EEFD5CBEFCFE1E673CE9DBD6F A901AF6549AB54F5AAEAFD379CB3F7F79DBDF7F779D439B376E4A7E9D5E70EB5 009E42B2A531BC173B70540DF59B01C7D8234A7906A87C32E353749429800E7A D27238405D0D20965B78AE0DB79F2A9A01F3CCCD102B98E64177059A4CC296CE CB096CC6A224CB30BA59A8A81C6367526AD33C8903CE1ABE53257A1E2DA26117 A021A20A432FF0A51F0CFB43D620F5956A6F6B200EA49DF8BA9DDBE74958190B 2D7C52D5569ECBCC1141164CF25B4ABF04DF3CE8A268B09B8DC7553B6903C1CF AD7E73B6F20D4BE6E1DC8AFDCDD7364944569F3A5D54A69A8500C19891103F53 924A60BC39AA2D2A0A59DB921A60C6D81224BEC6BB9F9CF8630F7BBCF02C5700 331C2E0ED69E3AA6DB49AE7A9692A6F0739A49C04B57547E97FADCC96802A9A5 C813BA422BEF00AA57E0BE868F80189A2B5958837BFDF1B5DE91CEF16C98DEDF BF3BF770A37ABC915A13E2C24653B0EE082E424C9B048F9F815B07682C590C71 D292D6B2C8BAF3E69B878FADB86D6F64C6AE1F982939786B63F5A187FA3BB7B2 A0B6FCEC91BC4984E7153910068B329B02C58585A123F8A61B5F786395B606F0 C54EA7F5F03923037C570556EF4AF95F4D8C2A67FB2038A0ED842567E9DD2B83 8B571BA74F59E71E2A8C2D633B76FC5CEACA606FF2C54F563BE2C6CDABCDB5D5 B9279ECC60757835354D65D0444D15AB4269C0898DCDA2B87E71761E65BCD099 883D508F2E7B644A4663CAF135DB26A351F6877F76EF639F7D7DBD579B6F3DD7 69DF1EE43FFC85D7BC95CE8F34BCE6F6F860FE68B7EE7EE1C52F2C34966BD2DC D59359BB73B0339A77FD1B07BB64AE99469A27595264B0D553C0A542BF8B57FF B7E3C79EE213D8949F48ED9FB97933A879DFB5B4FC8E6178A8E15DCF927BDCF9 AFB3DD6F5DA97C2367D534F87411FCEDD75FBBC5CDF3E71EA909F9F295D7C771 8AAD9938EA900BEC8BD68D7A3D9F848126CF1E3F737E7ECD8F0CFCDCC480611D 26C4BC6D0BCE2ACD86E2A497CC3686DD5BBDBD2B5BF7B692514228870CEAFA5E A5E23329B49152E268046C47691D8C06F7073BCB6EE39953E79E3F79B636D541 6CB218A9E5C4323B2A7CF1CED5EBC3FD09D3BD648A1615259AF8AAD5113C6B92 70E1E5C543C1FCC2B993AF5C7BCD1E8D8F1F5DDA3F983C57C8EF5D3DF43F7ADB 3F35EBFEE38A9F79952804E46CA3EF3485602C33AF7E65B03F4CA7F3ADF6DDF5 BDC595C3444D73035BB56EC55951C4DC23E16064537F4FD19DD9F842C5FBD1A3 C71F1D8C0E87E1FA52EDD36CB63119FA81F3753FF0D1C77EF0AF17E5806834D8 8947FD46738E54EA3AF74B3585298E70171E26423A4551CBC227C62F7B955340 A14C738632400ACF8F71A96440E86081022C175C1033E0E95EFFEED526C46380 ADC796B910165AA5E021F3F8F5DBCDFA823ABC32B3926AAEA75FB954332A7D1A 32B5E3E826E7CD9964D2E6FAE26BD1F5CBADE78FC60D42128560490801B9FDF6 AD85471F82140A6FC59ACE20D26554E48D8ED35AE4400174066859F1441A514A D9986C7FCBDADDC6A322088C2A98BD3E1A6ECED69E3D9CAFF58A994B712E0202 AC89F74DF7EE64EDD472D14C2076938C73055F07BE584509399A60172A1105EA A0A638473648BB3BC3C6CABC6CFBC97E347E694CB739D7B2C0B21B1D1426016C 4D8BD10C375ACB0B9A267467C3AA578921BEBC4B7516AC7C20366F85F38702CF D1BDEB61ADB648DAB33B071B87E69E84B571E7C697C895051A3853C2FB593150 C53453118AA6947C8642E2CA70564D027643E9AB9869F84F2ADE485183111887 27F365DFAB1556CBB6ED51B4FD1DFAE1777EDDE8535F8A2F1C597CE1F1383A70 1D0138066709F259A187B9C9AC585A5E06E0C28FDAFD5F7EA3F8E28E58A0F5C7 3BFB77F6CCCDA206D7178F2679DE67F5B1C95D9A7674655104C0A1D323FD85E7 DBB482BAC7D4B700F88952B68F48787804C54B543DBD496F7CFED2B16F7D2E78 AA1D5B112D848007FB40C2D1583806CFCCFF9408DD336B87CB44D8F10257EA8C 407064D2C75E536084ACC76D74478E638B25990F1C4BE519C3284E1C0BC83FD0 732C6169E03B063E047B1B934C0FE1277969F9F4E083A8A570BC095D30200F26 99C2032F4BD0AC488B228448A27170A25DF11BCCB4514F42930AB32CAA6653BF 5A314C4CA753BB2D6A2B958D9B9BDE30A8E58DA416C9474D549F39DA718B20E7 B9B25349FCB83920B78AFCB3AC50B52D5BA78590B3593348AB107595AF4FB3FA 87AAA6617846BBD7FADD3BA3879F7DA4588D9535B4329F2A5FF130B3A7527BD6 AC639C3DD849B0110169782CE569AC077EEF3331BB299CCC682F875B0E127F6F 6967EDA9C3642E4BD501CF05292A39410F49759344D7285004740E4559CEC43A 4ADD677C33AF3009C2A3CF858B8A0264BC3918BFDA5D4B974CC2FAF676ED899A A87B8597119114461186C57FC31381F41432AF9B111CFBB04818572D2FA967D7 E25C27D573EDDCC444A79627F7B7C67E52ADB46AFB7B976B672F38473A7990B2 007BF1607352E26B923187147916EF4E93BB7B0DE16DE595B5279FD0D53AE33E DC2FD0762AE085660072B8420D22005D0A8F28A93BDA995CBE0888AEF5E473B9 5FB109CD61CFF82E10F8F8952FB9FB1BCACEBA51EFE8534FAB464B7B4D3B1304 ED742DED5615AB4A12508D67BC00DC1E5405693935580E9263DB5529CB8C6D94 90808914493C0DFFEBE7C3FFF8B9ABD374A9522C4BB61577FEFDCB77229E5D98 AFADA4CC0967DEA1E69795F9C49B1B67EBAD908577D359F3F8B95B3736E2643C 2A54B5D9E699D81EED25362C2DCB0FAD42A87F7AE891EFA8CB7A762F66CE17D3 F6BFBC7333AB938F763ACFF46675DFBFC3D87E66DF28F6BFEBCCC2D970A88BD6 BFDD4AFED5C67AD4749F3C757CEFCEC69DFD1EF656A36B8D28044ECD76E0D165 3A20E2C4FCE25AAD9D0EC6AEC501A94F6653CBB52DDF691953E372B9D1AE30D1 F6AAAD2AFCCA1E84D32B5BF76FF5F6B766E3FD783ACC62801BA26031CD018A38 8E53B14447784FAC9DB870EC14C0A67BDBF73787DD8899711CA5148F4F59E010 DF79E9CD37B6A37E56AA6F17E47F4A8454423E1176CE2A8C2F1F3EB4BFB7A9A2 D9DAE139A7F04EDCDFFD5B874F5C76C83FBA73E387EC8237DB565CCC3976E49A FBD9ACC8651A895E202636E96DEE3022F70A92E433EAD83E71DBCC0A6AD202E6 3698DACABD1727FD78F694EBFDBD93C70FA7E3E530D44E70C5B63EABF6C73479 E4CCC9EFFDA97FAA4E2E45A33E3BD8633E7596E659E6E4994B6D80D053885EAC 0018AC191F172CA206C89347F118ABC06E523CE6CD0A6CAC2C9B6500D0910827 05A967B4029ACDD3DDD1FA359F08F42F3F3C276DDB523AC67670515CD99253A2 1F393EF68B4A18CBABB7CDA01B3DBF6C58D5CB1B166DE4D222341D7DF6738D64 C4CF779226A42163176ECC857CE9E646BC3FF7F459C8D65E1691E904F2754265 DA9EF79A8B2285259A6A1448CA44EE6A2528CFB3EE26DFD98228A9207852AFB8 A9362EEE2C5D5862E72634ADB314E0645C50A347D6CED57E67A5E61E9668389D E2A15B61325823D802C7729CDC80406D04C4CBC28A00428EAFC796A8D1E356C6 C3EA0D77F4629A44284A92856694B0B145C745846A27761DF25647983995B976 406A2E3FB1D53AEAB0DCEFDF4D940E178ECC997D33EC8D9DA3D6C4642C0C163A F5EEE84DFAE9F94490905A075931360438CF344ED1B281A1AA66564EF2108BCB B29727E5049D76B5ACE5A88B412D5DB7AD7987036F6B0ADE08D58D139B173EF8 C141323DB0E213DFF49E0248B30406686B222D35A1700580C2539FF168E4641E 5BD4BFB511FDE135B64CDCA72A7A94655FC9E5C4813F13167ADBD426260F2CDD C8BC255A4BAC7DEBE938B860E3B49B741207E599B816CC01DAA338F594C89DAC 9DBE91DDBF7AE3C877BE531C0F520861BC5492C6BA9E45DE9E5ACECB6D82C773 A8E7E79DC54478EB9D87EA6EE0DA242DA68C17B26AEB00CF508B811153E07B69 8ACE4A2E8005406D16047B217C6013D82FAC092BCDD561E75A3256263566A2AC 6914E3A47DD9F5673B5EE9DD8BEEA2B9D140091F48D06845E0416734A30ABE21 EF54DC86E03548EC7462D7D088219D66959A542A9FC5B9B76ABB55AF77A32F67 8E6B79A133AD9C97690D3D820001606BB553D6D32B1373974C3F6F4953EB8A70 9826552EDB9242EA8238EEBDC7B7DEC7688C039DC9DD6CFD4FD7CF3EF308BD50 E4CE80C52E3692D9CAC88467164F835C740112C4386AC22B94D328224A0E5E4F 9217757D82C93764B11F05C3B9FEF2938B6629CBF508B255513828A20BE06343 4EDE48016918AE53344D35EC04B59E76545B13DBC63D0ABB3E54D89619E6E1CB 3DF706B1943F5D1D579E85DC4F6540959E726C1F70729CC186550AE0D826859B A132A561B0B02A86EEB1F8F260FEE44ABAA834C91D85C7D1BDED69B3793C196C CB562ECE9DA6350FE832DC1AC3419100283D13C0F2144DD8CE57AE2F009BD9DB 8CCFBED03C75A2B0645158C074B17DCD2A721C783128C38EA6D9C0BD25507D7A E562EFE635FFF85971E22C81AF329A03C8830DB37B7FF70B9F3E7EB8B3BB7EAD FAC83167ED701134340BAC1490B28FE352D2D7CCB3884B4D59EC047458580C47 02E027B094615921B82328218106050AD80CE3832FBD3AF8FDFF115DDE8E1657 4EB1D8CCA23FE8DBAFAE4F3EDAAE756683F5542F7AD66AA5F8F551F8CB5DF5BE C09B568A8368EA588DFB7B0721505F781E1130CB02F5023DD4247195F3818AF9 47C79F3E9D8C18DFB5B87725A9FDC4ED1B9305F79BABEDC7F66685676DD8C0C3 94559F7EFBF1D5EA7878D79EFBC94B9B9F18F784EF342A72DC9B68859ACF8471 549B238012A55F30BFE08F1C3B5DC409C133250DF96F6FD093813B9ACEE65796 9C38124AFB8555CBC985B9B5355939B770C4C3895D36E36440F23153C33C8E6C 221BC1349CD66C7FD16F0469116434EA8FB7F6F7D667FDABA3BD03A9779271C4 68779C546CC7E479AD1674BBDDC16C044C2A2D4F464BE5F2B2FE814E56C0EAB9 8D625299EF57B22C86287DEC50E788DBAA5EBFF5CDABC72673D5FFE7F2EB1F96 A4B1B26267BC0A9C8024B78B70A6D098F47E3C9BE2B40FD184EFE76AA0A6AA9C 96AD1456B351D71492A66ABA8DBB835998A68F5BE2EF9C3A7E544DEB6AB6A01B 07B6FB8762EFA61E1DF51B3FFC4FFE81FB0D8F0FBA3B1D085CF3416C332B92AC 70B0BC401314E7283C822DE709A54939442FF1048296F33390008B1C45BF5939 F7556A9328AD8050A82CE16CC292BDD9DEBA8E23C9DD1CEDE21B3C434F6C08D2 A23FEDDD5CB78F1DA24B73766EC4FEC1F0CA9BEE230B59634E92BA456AC49224 0D0FFEECD373358B3E5C9F019E4E81E1F0C491EE9FDEDDAFCC9A4F1E15B06081 0EC6112AE7694B3797ED3A902C4D8A4C0B6C81E7B905C88ED02CED6FB29D6D47 E902FDDDAB648BDCFBFC8DFA4A507DCC2DA887CA107A8612ADA1DBBB32911EAF 3D5CC9816402BF25794EA23C970E36604078CEF1141665E90CEC0D74243EB0C2 712A8F3B333A6AC59DD9CBE9F0666E5B82656216920921C374A64D2E2A7EA28B BA6537B14551790B7ED1D9F33BA2D2AEAAB4E8ED749B95961DD4EEDFBBE1D5ED A032777077BFB95A63AD9C7CC11B0F66692E878A8F5254B319677998E51CB6B8 B02378FED8CCAB329D219F82776209BBB01C9CABC209848623EBB4A8C8A22969 53932EDD3AFCDE73D3278FAEAF5F3BFD8DEFB73B9632A1812D42ED824C99EE71 9500136045380CB4CDDAE2E3DDD16F7D45CE53EB710705D0DED2E9BA760111AA 7CC77890982B5CD714EF10277147C17B043D894D551CE2B495026261CA223EF0 ED1C7662CE122F5E4D2E66DB83CD237FFD3C9B47B1421C9BC77940343520A5D7 29C1AE518C3414A5305C5A39B3BAF6AFE9FA732B9E0BAC594022D4762CEA8E25 81218964183248829A180DFF270744A0A114DC3677AA42025E89790AD4DE258E 996536E7090E7D9328060E17A39B1E13A82563F1288A381EB6615B60566AF5C0 820E5162CD58269739AD4B31571501401C0119E3A039EFC453279CC86A4DE731 BC17E99D1210308A7580404637D299355B3C39A7FC543BE5791F878D05F43713 DC4C6F15C3CBAE97FBA1DEEDA96EBBBA58CB6AC0A1278D61E79BABEAA1993CA8 87CD8C6FC983FFB471F8F832F9801BD701B6429200D6CA9801EA05D827418F78 539A7F03088D1D6C5516E3702F1AFDC96CAEBB4C5D3A110378F22648E79E69AA 95486111D701549B3A998010BFEB0E5E1BBBB94F4B41492BD5E46152BC439ABA 6509DF38DA861430CE531423B1D46BBDD9E70F026B717632AE3FEB9A5C491416 C92CEC862ACA762D081512C51D903941A8A085570D52D3BDBB29AAB5FA7C33CE 8702E856564CD7C71E2C45297BD9FEF2C9C5FC58CDC2062DC2988BDE1896C0E1 0D48CCB43EBE3B0AEF6DB4ADC466917ACF0F10F82CE950F8A0FC6D8DD8426273 93CA0ADFAE520DCF57D2D1ADD19B2F4D9268E1990FA8C6023171298BED38D378 EF337FD2AC18ECAC9E0EACF73DC9FD2AA5F089361E3B500F3E1D162167361EB1 C2B5506CEA27F0BBDC248014817F660ED002C5E00F6500B4538B692EFCBD69F2 AB7FB8FDB92F8E1D7BD55914B17539CDFEE0F69D67168F9FDF1D9B6434AAAA33 F59AADED7FB2B9FB1BA9FE1A53CD56BCCDD9EE6830959ED38F34107A7898B6C5 F22CB78404B466DBCE6F35A277D74FC3529ED9D32AA1DD54FEEB9DCDF596FBB5 AC7DEE209DFA7CB3C17607BDE757C873D5F9705A7CA2F07FFAEABDBB61C418B6 45C302056E09403EE7B0F2A4800F51854D69C50DDAF586673BD3499429787772 329935DBADD1603CBF303F9A0C1E08894B6D4ED4DBF309FDC0A94760412DD49B 52F2F9C585F9B9B68E13F71D67C87CEDD6A73EE70E33368CFB07FD3B83EE9D22 FE72776387ABDBFDBDA0DEE81F74857043D4135205044B1C59C4294648F8400A 21A63E30EC2D855C702CD1CA958FA61699E2A55E5D4E1E5DE89C72FDECDEFA63 AB871E5A5CDCBA75A3C1F5C2DA9A06B037C9874976DF31D720F0DA80D364B737 DE9D2676ABBDDF1DF4B197102DDC458182B18C27D2354BEDE6EE560424F694B0 7EE4A1C34F45B136C3635947D9C127AABD97A2EE9CAEBEE79BDEF7D4FFF591CC 2E6C53A14C45900133177D06A979706A44FFD259F1AB254EFA80D51A52566050 B5092728CA210A82DEE0826A94E43663A2872AEC8E0FB65B4C86B670978F2419 93686E13531EEDDEBECE159F3F763EE6962BC8CEEB1797E224397732AB341C56 A5C0AC27D1CE9FFFD9D291063D5DEB934923232225A164F67F1FC60B71E55CBD 90065E32A439D81789166E658DF91D52EA511BF44551F002E03903DC52E37DBD B9EEA26D9034CCE389BDFDEA957C161D79EC7C520B25A5B909958C9DCC37B78A 497FDA3AD7CE58CC12C90564EE2849224FD7705849A48AC44AC3F245C528A664 1E8607FB5BEDF926AA0A38820CE9E873D3749F7B566D9665690EEF9EBBAE008A 37988E04AB07965FF523668FE5A17A91E58D4702DD8806B746625A6D9E5CDA9D 6D24B77A471A67A2783C1093DAB1C5A2A7062F77ED7140A407FC61AACC589351 AC6CE67361F7F219F02D00BCE8B7891620F002882E050151AE95B38AB42ACCB4 39E434E632321799D105617FDB63772FBF79EC6BDFE31CB5515A3C7761D7C732 263AB213846D804C47B61256DDF9E26CF41B5F842C567DA2AD85CE0F44EFADB0 3A7128FA0CF071813257151A06100B9BBAF6AE76BE961B82232448C7455068A9 7D9EF184530D40C59D9E88BE30DBAD8E8FFD8D234A2622AA02AD029E088B0DF2 24818C05F015F706C7C61A9615903C2A67D7D67E8E6EBE6BCDB13D47E2EC8DF1 325973187C746EA58388A19C059ED66719ED335B1B250B536522E040FEB31852 27806AEE14D3CC2AC5A06352448915C619170E1ADEE498EE60E1612BEE03FBE3 B2F742A1FA680EA14150E612AB2E8AA66DAA52A09D931C3757DCF140C176A9B9 5632EB15AEEF1F72D2416A762D03E4D2CF13912C9EE82495D0380AB6039ADFC2 C6B472ECB2BF1A4F2EDB226D8CCD8E92D33AADD5C85C5C44E454DAFA403D6B4E 49C85555B21D2BFA5C9F98A4F5B50BB3B90487F188C484AFF14209CF21B1713C 10C7E0415307DD5165684666FB63DDF6C182655BA19850607F9570F1E9B65E85 559B5BB1449B389942A017075EFFB5A90845995D61C3A6FCACC59F77F22A7720 AFF8B0AFB3629C285E4ECB5D99402214AA6ECE16C11348C850EC1A2899857117 27ABB411B6C3284F1348D7BCB0255CAF736DB817EED59F3D8ABF1E66B461452A D9BCB4776AEEE428DE9187EBDEE2A25EB00996234B5D2B88220C968065290E78 6FE7D28DC5A03E99F59A678F93D5F740C65548CA184E2DA3BA281EFD01B3C908 0554C452C3231D5D7F311CEDDB0B9DEAC38F4D880DA8D72A52B89483B7AE93AD 3B9D656FE3C6EB0B8F3E6A9F3A04E412403DA0F682F8DCF219750CF23FF17622 2416B65061D79F41C57F600228B763699C0CC94881CD8A4CD1FEA7BE34FDCF9F 9A6C6C693F38162CEF27FABF6D6DDEEF261F5E3EDDD9DD9B99C8590CE6899E24 EAA7B7879F50E2A96AF3D2DEBD48AA4946FCAA1586A59819E7316C5841A4324D 45CE2CAEFE9BA65AD60D58BFA19B0248DF89ADDF8FA6EB1679C6B887F693B8EE ECB4ACEE6CFC5DC7AAC7123188C8AFF5C39FDDD808A543B218C3362AF331087F 69A983EA96B506400E4B8B4BE3F1984B9124499AE78C5B10BA032CCD6A4FDABB D9185696CE32C968857227D38F1C3AEA52BA3AB7E0E4E688D758226E3D21B593 878DE70CAEDC55FD69549875137D65B6774B4FEF8CFA49816A1590DE90DDA20A B929BD014AC58FAF7A8B97A72D586085AF5968E86D60D303B6CC3161E259342C 6E3B2F1EA9B5CE373BDDAD7B6BADDA372E1F593D486EBB13783B387E91D1B1D2 1B3CBFEFA81E901574D1F6B7C793FB93E934573197890A21F801AB4182C6D286 CFEBAEBB3B4081AEE7FCE0EF1E5FBB10023599D6E30AABD42E37934BE1819E14 FEE1C637FDCC0FAD3E798EA05A6554B85CE42E296D534A458552C892FE651624 E5793CB61313CC95584246468853920F3227D6CCD30492BCC986B49800AE1E6F DFB59319CB5D313FAFE6DB198405636C1199EE56BCD1F7578FC46D0827C46CEF 45AF5F729F7E3CAEB703D92253931EF476BEFCB9D5F387AC23FE34EDDB94DB8A 2571A23EDD17A76CFBA14003D356144382CAD3C2716A6BD46B950DCE6834C14D 5ACE8451D4448887F97DBC0CB4283510245AE1B58DED5BEBC7CE9FCD97F091F1 4225722AB8CDEFDB7BD7F6E64FB68B36864474D4C26F9801C363C019F13B971D F740387380F92851D43BD8E796D5E8347395092A92EB5974313743C81E629C46 6E2A6BA23A23B3AE990869071AA90CF732EB84930D74ED14A59D7131ABF66F65 95359737CCF4DAD48BDD60516E8F77ECEA72B3E3755F9D9A7B90525824E99ED2 13C56731EC1FE158228CA6833C8F1C37804D6C0CA47E9C9D2DC18A41EB315A95 BCCA69CBA22DC121112E68B2BE385DFDC8E3D76EDD39F4FC1395A7E633C0BBA9 032125854468207E0366CB98D2FD22E47EA57E830F7EE57379389E7F6A392491 9BD5873743B299DAA918293A31C2E2A68A276D29ED14CDF7CF4D9B13C12101C3 672B0E0FC7D885C770EC12D845CD937B8BFD4FED9887FCE64716144D6C48A08C 2B60FA58F5C132B341698AB24101A36BFE9789F0E083C7E0C9C26FA5C58C05CA 6D784CFA26A1490F928642FD338509B18FDD495A1A13301E60015BA53C2736F3 1C578F13A6913FA74077139EC10344108A07CD104751F3094F47F17814DD2B38 C071D8D639162EB90D1F5613694BC455E02B102BFDDC99A7DDEE3828DA0D694F 475D3957779B72B8332AC60C7B3A03E057F1DC8976581B291B82A71090B1ECA2 006A20ECC91B93E49AC7D2763FDF17DEB896FB35B6BC2FBBB5F7B1CA19892238 68AB5C1F5C1D7B7B4CA7B3CA238D6C956454A1455F29DA84538E705F58C546F9 01883D5C3938D6266336A5FBFFBD2F6FFB425819835B96716DB4FC7447AFA640 026462C383CDAD0412A13D080617C77AC401EC414CD4B3909EE3D6BBFDA22E1C A74A1C9CCC48FB2191802BA87D371A7D6657CDA4FB84EF3C6C348451E482381B AA4B69666E49CB92650F333E3E884032E5BB97EFBA8B15FB742333CA5780AFAD F58D3D9F576D20080CC0E6F118E8C9524B11530EA9294C75860B59B10AA7FBE5 D7ACC94C7A415E096AE7CF10FB1441595DC8B2185F51801E255D347C1AAB7A61 9A789A445BDD60F7DADDDE7EEBCCC3B5A3A753D4FDE64E3E55BBDB373EFBA587 CE9CDABB7711F2DDE213EF2C9A759CA80186A704A57EB9589C029D5951CC1507 BC294A6C3F60B70F3840490C10FCE7B09E2D03218C0EA39BFFF677F9576E4461 9E52F950D0FAB3DEDE6F5EB9F7C2A90BCF1CE4411C4EEA56A3E557A2C976417E E6CEFE6712BE5C71EE0E7BDEF2DC56771F1E9B635B698C932639AC55071064FE 358EFD3DC7CE7F1DE9FBC64D4C92004EB5DCEBD3E2535138E0E6A142CE4D7452 77B7AD98DAF47B3AB213B99B33FEB3BDEEAFEEEF680E3787CD0319036C446CEC F8C7690558C4582500CE6B036CA5D370824DD1857E300FC24C09410A1C8E0CB3 54489165397E034D443943D9C6CE13B7A9AD536EEB6C6B25366A1AC76D062C5E 8F0A7D79B6F7B9833B1317F11F6431B7E02AD7AC742B248542CF2EECFE2E3564 3479BB4D06F3138A1C3EF8B5C525A0D718B80B563E52561AC29D92DE3B1756F6 FABBB26A7D777BF5DDDBE6F54E1A87A8FB9BA374345957E11D13A6F0B9DCCAD2 2217727D3ADD9A8E01606468216A0C001761130E0B03360E7AF616DABCAB52FD DF8F1E393D191385A69599ED242D7E67D6DF9CC54993BFE787BEF11DDFF52DCA 123941586E29973394597C9B05D2B230FC76122FFF47BF6A378C3902A9E15713 216642D862049639CD0A35219008AD2CEE6E98C146A0DABD246C3E71764A20EB D91E99D0685FAD1F24DAF21E3A92EBD8A656F8E2978BB905EFD88942567866A7 D7EE7401C03D759C2F79C02C299A22596977947E79129CAF91359E1610E7208A 193C1F218E533F44DD46A903946B487F0CB54D729434296411EBDD0D3E1A50AC 1F02B20ECC406D5CBAB630B724CF7A244981D8E67252006E1F54775EDE69741A DE4937A463A6CA5A8955F22C8D95A61216501C3283278CCDE3F66C184D879385 C5398876B98E78EAF2CB64EB624F543BD3249419090A774655E868B76201DC91 91B1A5CC8EE98AEBEF4F6EAD9C6E113FE8AF8FE2385F5C836F22F6AEAFD76B0D 29ADEEB8B7B87A240B49F7D28EB56B6CAFB567F428CD00DD47681D2B695A0CD2 6CEC42202BC58FB06ACB68C96D4A815C0036B4C6491372A164BEE0CD2CDF680F E7DF7BB23789E71E5AAD7CF82C8A9F641E2F38F08482C42283A7A7585A0CF540 559CCE9ED3FB952FC45BBD952756672CF24433D94C66D7FB2EDC562A122315C5 7E1C4E52B2405AEF6D4F6A6360188E052F0A22AE0570B4B08DB2125821BA52F7 D6ABDB9FBAB5F0A187B3E76CE0106EE4C1D70DB0654454165A91C26EA2FFEB44 78C4429933D85B89A813A7EE122A554CA3EE549642A06946D29C764D69BACD68 CD621561414ECA9951B6F102271F4C798ACF2743D534EC9AC90D2C0AA0F7584A D1A8C7AD9552E8610FE8DC96C00C4C8E076B8CBA01706311B7641440AC37969C 735410ED777BF3F6A297B05938F40F7580540DB6FBE803E414D51A84C1AC79AC 3EABF7950D08D3E170F1403F5CE5154EFF2B5DBED934E97C2FDBF7DC713DF304 EFEC777AF31FB264DBF0B43E6B74836861F3E26E43BA702FA9ABBD33CD9935E5 389780AE9E862428F855E0B82E221F64CF12509012A94C85BA4C075F9A38058A 1AB25C24CDE1D233F37A21C94C26331BB669CE33887DF6A40289507501B600BD 66268CE9192ADE57656DB81EAF10065EA29E015B67799A3A9B79FFF3DB7A68B5 DED12C0E87001984E4B49C2A2E432ABE338E3676A8BF0829842645B2DDEF8AD9 9113C7811C28196ADB8DD689D9D1AD438DBDC93DBBD3F017DB72A1AA821A3012 8EB26519E48434279E3F9F5CDD8C6FDD6956835112D79E7C5675565956C76F0D EBA26C412E99A3801582F3310F7A47A7D3D9F64E231EEE4EA6CDC72ED85E35A3 6E2E2C3F3E187CE1CFF524648D7A7778EFF4B38F9BE62A1E82A2C52044E03211 329FA2D1A055EAD4C2D60126C94B27F7F2AC9C582501D00FB0BE922C37A99526 627F7CF3DFFCBABB31BCB13BB0BDFA138DF6EF6CDEFDCF9B931F7CE8DC737787 49348A0F2FD41D5A998E77BCE0A76E6CFDF7510CF82A65DC78DE6C8CA23ED8AD 8F185C58C0A459D291E4C73ACB3FE82F53DA13E8A39242B64F45E5E224FDD274 427DB94C58901A7840BD7474E8F0FCD7C8480FF89599FD2F36EF7ECA4404D006 44A842A4164E9E8902D7842E385AA11B54042DF23C905E9E450F44CE0C4AD361 5F9A299DAA3D8874148D29530617553ADAE8B25C4F515F0DC29F4358D3AB201D 284CD5F1B1AD96D1814EB7C331EA9097F1876646941D23B08DB3B2A25AAAF03C 28FF971AADD850F27616C493033CB22B80B302A482CFC5592000705C75F2E283 ED95309B4441F6DD0B6B5F7F9FBCE92438352B9C6192778B7C9FE63B453A86DC 63410EE6C3D96C20D8D4B5EEEE46990A317959704340FA2348EC100B334790CC BCE078FFF0C4C995C9D0516CE0C86191AD54834116BD38DD8BDAF2CCB3E73EFC 7FFCBD68B1618AD445CB2AC1D015B2785B638F9007A7A30F6EF5ED669FBF6087 25562ADEFE03D87940CAA37693CD8095123223262ED420DB7A4B16AD7034644B 4DB17C3223AE4B263CDED3A3687CBFEFCF35C442CD0029EC75C757B69BE72EF0 B9369E485EBC3AB97FABF3DC493E6F9370889A2A944D76F7F5C5B871BEA61721 69139A708915BE5CF140360E535921B03529D60939EA1FB01440AA2036308EFE 8ED9DBE4B0EB1807F2E0686FFB951B3E091A4F36218D62494D461036645C19BD 9EE6936CEED1EAC4E972511511AC909C328892800701254981A7BB992119044F 40FA109077EF1FD45DAFB6D056F188405AEAD1FD2FF6C941C3A6954C8D21688C C671068CB6213D69F89408E3462BF9C279E7E0EE76D36FB3550D69657A8D36FD 79B216F6C7FBEC8EDB593BD60B2FD2C99A7FBCE86F76E975D799B663A6C67A9A 50DD4D93C8488B35E3249B15E36946CBC206C37A0F2B8F21181A8ACA42573869 58B42978555A0D52ECD787D69976ADB59078AAF53DEF8824FE0B610F1221C453 0B5BF0729AD214228BABDB43BBFB9BAFE4B7BB4B6757721FA7364CD7F4DFD813 23E6D080154194C6C255A811BA5CD4DF5949EA1124151B9EAEA4A56B94AB51B8 286102804D875D357BAFDC3EF2379F9B3E846AED7E6C0367233C47B44D442288 931BF2C0E20637480E988040225CFD593A78E1088657C069B0AF6B94FB901425 8978D89D3910AA298B63035C76887B8BBA8CC27E753946E50CB69E47FC869D0E 2622022A05048D2586CDD22C49E16D8A82C91C3E0AA28E5210DF3385DE13C2B6 0D6CD72C1284D896E75BAC21D39A08F1A48CD995B5E6848E8783615BB6E900A5 959C955A3A49E3616C2C9DDB59B3DA4A4779F5587D52DFD34EEE64AE456D63E7 999D7BA9B3FFCA9EDB9FD77173928F02270C70C0D04ECFE69577E5CC06E2BF3C AEDDABF78E6DBEB6595F747C29F677068B4F1F1D05039EAB4A1E14103D1936EF 51D8E0149536711452B1B24F3A1510FBF79B834FED924979D29BB1687EB0F4F4 929E4B520541413278D31CE03071A34AFFB589DE811B74D1B7288EE859EEBCBF 465A9E5576D0405E63449A2C4BA3D0DECA7B2FEE28D8BFEF5AC8E687A54D3402 2EF47C4033479EE7E8668526DB1A070CD8244BB7F692B32DDFF39D094041D253 66743D393E77360558E5F4AA4757A55F95738DC8164E8A50469334B181C47039 E68397AF771C3B51115D5BE347CFEAEA2A9F180B5B3B717C1EE0BE07094C0B08 A7B9E416ACB4C968BA7D37687AD6CDBBA34633387B8EC1A2622E4E19DE7D23BE F4A56667FED6A0575B6BCF9D3D9B396D880F1C7B868105DA947A947965B6130F 9AA75000829459B0EC46852550CA6BAB02C59449CA39FAC1E6095BDFBDF973BF CE36866FDD1F3895E6B3F3CD3F8BA28F6D6C7F74EED8B3B7B73535D19165006B F5F168DBAFFFC4C6EE1F0DA6F59A3FD21A582064606971F430C3634BF8EE4540 D5B72D777EB832F7F82C1FD48AACD0C0F1018FEC19F962945D9E8C9A15594963 D814AE033B3A3B7974E1341BEEF4ADCF8EE54FDFBF794762B7A21FC3E3AF8512 CDE7A88EE10101C3363EFC7114A0C2286DB483EE630A2DBE8BE22F0FFA28F1A5 07993954098EB82B85B11F2B2CB4A4EA002081DFE4780E0FB0A3D4ED7DF00F12 74580D401E7124175992836614460891306D72B469B7CA29C6F2713E90F7C505 036B0B87E1B46A2FB7CFAF1EBB78F5EA701AB6A86C35DA039E9183DEFBDB4B56 A00FF8E03B9A6B1FD9166FDA090A26503E8610A6558FE40745366006186A4540 90D5EBD124AEDB772319F7BB4419C5FD04595BE23005D7AD01ECA4FADB83E6F7 1F5A0BA2413BF1EFD4F98109CF11DBB6F97F8BB676DDFCC4CACA87FFF1DFB7DF F14852CC6A19F6441126ADB270FA20113E7860947E5511E0ABF5C2E2EDDFC08A E2838222C16A21E078AEB31992946266700E2F9A6CBD6545B96F59B3701A9CBC 907B55ADC7824EE0B146B7B6A3DDFDF623A7B2C0D22C519FB9E5D6E7ADF32709 13F1E53B83BB3716DE718AB545114F908172D6DDDE26AF459DC73ABA83850A92 50018B068298ACC8E661222A10FC8A724CC2D2092C6F4889A8D48F8D3043B579 87A5D302760E953CB5476FED16FB49F3C21CAD0A65622EF39CCE84F6F47DFFE0 CDBDB9336EBA34D354BA916F61A7748EE7D999205AA0E610D00A9E6A9C6DC7FE 8BF1FE4C4DE295D5C39099533142A07C838DFE2CAF679DC489636B964FA94B6A 404EB44C6D58CC5930F6B3E6FBF30A6FF55E3AA85C70E8616D6EB9E97DE39CA7 B11BA56FB24049FFA8D9BA46FCA3B1EBBBE95B727A25867D9FD945549049944C 217688469899341D4D8A320392B7A7C7213940B646676D58279C352C5215AC6A 0BA0865DBF5F2C88C3A7CEEF66DD851F7C7754D31232BDE2C64E31FAA1989C62 11DA208F44DC98C8FEEF5DA2570E3A2717D24AA2002C8FACDE5BFB7C0C31DBB2 621F82B24151AF501EE795A79DAC1E5BCAC26340C742373DB44E88889D30E912 B3D47D694FCFA64BDFFEC864B1E0CAF69187C778B4AEB1CD3B12D4436F456C44 443515D8F3CCFA6A22FCBA230827B1972F950D8B07809AA40959D89B7904B505 66B18E133A01D088B304CC151A122103AC42B4AA107FDE4E0663672644E64222 8C74819C1A05E92027B00CA9332C2E04B2D826AA806E400C01401C57A4A8385E 8515352B173452F0AA3DD95A9B1FA593E964526315354A1AAD1A698AD95E54A4 A4F05528660DBBA9FB26385E9F34778011BA992FA8ADED1472A41FFADB2F75DD 695B47AE5269C541D9A638C81AEFF1CDB129200D8FCEF71BEBAD9D47365FBDE5 9FE0F57A6DFFF5DDC5C78F8E3A434BEB2074B1302EF1C4976A1B4F26B04F16A2 1AF6726BC8712911F1C2ECB37BC97A2E80142626591B2E3FB5ACDB599A4F01ED A07F2844285AD8B13F786DA2B66820AA00E34D3293171CF9BE9AAAC1E6F7E1C9 EB22B584A3E2183294D8CD0E5EDA86F0B3F49E95B4DDA7C8FF507EACD491A21A C2BA70013E90D28D2089F3B0DF0F1C210F2F6624C4422DA9DDBFDD6BDAB5CADC C2F6EDABD5F34BA6CDFD4687BB6D5864B55C42464DE19384A94A6F74E9763045 D7C9B16BD5CE5FC82A8B69E156320CEE8AEB18CD334DC5A0B487B6D848C52D5B CEAEBF05BB975559F895ABB5F38FE9A54310003CE690E9A0FBEA9FBA69AFE2B8 9B93C9F2BB9F3395A6A155341260086949E1128074B037CBA1A8D20E1AD6229E 8B9603A6A8B1560017420306A008190A1FE1A10EAACBD1DDFD5BBFFC3BB3D7EE DDDB99595EF5B176F06A94FFD7DB9B1F3D72FCC2FD4D5BB8D3E57997AA466FB0 41BD9F1C8CFE7D774F329951F4C1B6B1ED9495AADD740A31CC2ABE46D83FB176 FA7C91320075D20E2D656779A09DFBD4FE6C18EF4C27A7EB9E134F2006796E75 AEEA34ABBC930F6F91D62FDFECFE5E6F7F2660897227B726CA49A4579884E819 EAE2A0806A5CDA502B20B99020FE22FB41F05C59EC34AA8D878E1E7DF4DCD9BD 59F2B3BFF0CBB5A6EF577C9567E1645A092A92F3517F28A56DD0CA1A5F77A474 86744EFD95C1F8BF9A4F79499D391312E9B506F69E03F555A59ADAA3674F9F3B 71EA8D2B57DEBC735B03F88E73DFB67FECFFFCDB3FF63D3FF8333FFF0BBFF9DB FF894E92278F9D679ED8BE72F5A8EB581DEB20DBFDAE60ED3BFAEE8B9544602F 080B05DB8867138B612EA44061A84760F1C901C9AF0EF7DF2A5C1E85781648BD 14A3616C51ADCA33DE6545FEFEDCD117E66A61365C1C05D71B6662E7477AE14A A7F59233BD1A769782C6F3DFFDAD47BEFF5B429A0405C1B23CDE06FF6A502DD3 61F1554D85074CB02483655110F321A20252BA39E2707259FA24B8518D0E3960 381DA5D11E59BF5A0138AA592A03EFD04A62E51907D0C3ADEE687CFB2E776570 F278DF9975EEA5DD2BEB9D271F214190DEBABFB37E7BE5B1E356CBCE9269210B 4758DDDBF7E8B5BCFDE4625E097358B2A9B0E1AE21783975D93A42988723851C A7C63896D179A6D0C106389D4D5275F79A997409B043D7CF67841F9083976FCF 9F9C13C71B78E08D6836750A4106ADD1C53DBE429DD3269C4E1AA665B8D0050A B9631B242C28048A9A60102D32A500280244EF6D1C2C3497590D326C3723A432 AAE52F67E97A11A2521C356313B0EA5845298ABF15B0589510F9D3DDB5E3CBEA 2E3A53D59FA9F14C4FDF98322FF08E57E3D928BCD55FAC2E871D37DCDA9F3B7C 888C67DD2BFB6C2061232780CB125457EBD1623737514E55A99042500D0E8B84 784E05FF1A8C9A5561D5805971C07C56C362136FC86AC5EAD1B37D1936FFEEFB E26A2A63DBCA4861034CC6C309D82C569615221FD3A83EB3BBBF7F895EDE9A3B DA8EEA093A29F4ADFEF521DC04DC3AD903EA574FAD749C4F6AE7FDE02916BB13 07E03AF0415F10015780AD6F04A82471ADE9CA9DCFBE357766AEF2C2B19995F0 DC75738A33395411946F1229F047A5BFDA7868D0010BC271700613E1E8EB0E95 4DD11A62BBDDB22C4F42244F473AE9871E159006627C00EE88289A118F52DF2D 044F5906498E447EEA2D09F8627A3F76525F172CA104B26094E9ACE011BC3E83 D68414476771DC10BD99B074822363362DAACCD4B8A9DA783E1EC3376B7B7EB3 DAEF0F714632CA007A34E6DB29CDB0CDB7D2E42DDECBF76A56D3F48BEAF1C6A4 B95778DA493C805EC0088963DC91BF7D714CC7152B6596529EE3F6D4C03EC33B EF6EE4F6C8B2013599706ED0B9F7C8D66BB79C476973717EFF4FEF2E9C3F121E 4E7412D554B51040646722B750CCA2500F4E6E4AF92408FE282728E24AF2DAA4 FBEA182E43E7A6DBD93CF9EC31D3CE92228290CB55C994E1ED244E78258D6EAA C0AA690B8DEFC479CBFD6B0B894305AD2229A0A9854398261B8FE4888C2EEEAB AEE93C3DA79766181651010FA7CD1F8C6362815753CB7288E5F637B7A7D164ED FC2108230A9E519AD169D5EC6B7FB9B977FF4DEFF08ABD58D31E71D70E271393 BBA16F2427324C523BA864DD7EF2E69D865D893497A7CFF143C7D30C98A6532A 4727B950B0D49DC2E288A16CB8684851E1C156B67BBFB3DC984CB6A603B57C12 C8753B62A20217F8D6AB07772F556B34EE0D6AF3CBECB9E742BBE6C41C3D2871 9D01D573D8832C484419C4CB01C8726A100F9C71F930433D1CAC212945792D0C 1EDA180B50FB6870E997FE63FF335746BB28BBF5C491F91777FA57FAC9B79C3E 7EE8EE2D0868F1E242918CDBA3D97DEDFC762DF8F1B75ED38944E3143C4FCA6B A51AFD906519CF8E72F67F2F1FFE96C2095CBDEFC63552EDD194A7B9CF9CEB9A 7DB2DFA74ABFB7DD5C73D004AF60B645330938BA37FD535AFB9583E44F77B797 E75B8B55EFDAAD0DC0166156A47AC84A7D4C263C5B4782B150A12240A7E13DFD 8E678E1D3BBAB03077687969796E0E5080CFE5DACACAAB37AEFEED1FFDD16FF8 D087BEEF07BE2FCA9344658EEBC2FB8DC3C42AF931D1F495975FFEF19FFBC57E 983D7AE6E1A5F9059C54163C5719EC9968340580D2EBF7168F1C7AF3E6F57B77 3729F1B001CE24A71717BFE11B5FB8F0E4F9E3870E7782DAEFFDC17FF967BFF8 FF46C8A0C8630F3FFC477FFEDBCE4EFCFA975FFB934FFFF9C7FECB1F9F3F7E76 B1DABA7EE99539D7E52BCE6CB6FF9DFEF247C2FACBD5990891C7C3DBDBD359CF A8FD223F40490AEAC0C652342CF23D127D3E66B36928D1E309F61B2CF444529D A3A175715A917F75F2B19326DB95E1FCC0DF0DCCCCD79D717C64AE734B4EAF8D F75CE11F7DE6C2D3FFF06F596B6D42746A328BDA1447234AD5750413C503A2FC 5706214B31573C002EA742DEF66B2E7FC00C8A9EBD083F08B694240427936B37 BF40A37DDD5E1AF6FACDD58EEA54C74404856D27A10A87DB6FDE3CD25AC9CEB7 E498F4AEDC198C27279F786ABAB5BD7B7FFDE8630FF3869DA87126B59FEBC9B5 BBBC1FD41E9FCF6857594C640ECF8C424658771A6BC46994B32AA8BE823AA3A8 FE040818654B6C15B17098EFDE333A228EC8664535F2F75EBA2D7CD17C62A560 C3428A384F1C6DACA4115D8BC7226C9D93229D903131414341DCCF01DC00CD92 78A66EB01E62800D13C8B45A127FB6398EFB79FB583BA90CF54854DC257DF320 DE8AF7EEC455D5B633194613E4498E25015F4639D7F6E47877E9A99ACDEADDCB 43EB90104726C5769E5FA90490750EEFA7F727C1CD39F30C536F72CF61CE091D EE8FE337A43A8037AF6CE9AA8C6E46FD7DC17AA984C085658C721C0E0B20383F 0519823814D03D05601A580C20658D93993394B6EE74D6F8B116FDA1A7A22016 992DB0A29E69AB74DD035E9F4F15C746026FC87B1F7B2D7FF5C6E2434B5115FB F0BC5963E3E5CD46BD6935CCECF5712D9E87783CCA26CE49D17C4E0081F46839 12ED62B301EA598B2C96B1E6ADE08A73E9CB97CEFDCD67CC393F85A55B542C3C 460BB1F48AE14502FE82B4FD762234B872601B93EAD9078970156E2981255D61 4E5B6007A692493F57E3D4C7BF55CCB242517B5CE45602F74C3D5F4974F1826F 6ACDAAB1774402C799DD983853B7A016A0F230CD814A2BB4C3141A831D479910 8365C25CA3ECE8033D2D8F1635123725055E08780AEEA4B6E8BA9ED3DD1C4114 234409C7AA765A93F160DC9D765A1DC820133DF0799043223CD298D5F70A17A8 A08B1BC5856BD1F681BBF74642429F2669800EC36EAF366D3CC3AAA704ECA69C F3194BF3FA6CEEE6F9ADCBB7DC77C9E67C7BF4C9FBC1E1F9EC94364954511523 D29CC752F93844C7CA6636034902DE3F603E656988E895E246BEFFF9BE1305B0 3347477B871F5BD3D5242E429A97A535D8A7125EB708AF64E15555A1B55C6439 99D69EA989BF3617A3426CDD821C8BEAB310FF13331E8A584C2EEFAA5DD57A6A 4E2D3E4884584D43936E1C6315063B5D70925045F9C6C6D6CAB135BEE6446CE6 E5D21AD85B37BB95F9C57A91EF8FEF77DEFDD0841795D61ADA9C7B70E5A16549 F4ADE0BE1AC6BD2B371ADC524966AD9E94271E8F65CDD2B08ECB3284407F370B 4BFE166C39C21DAC4DC6D1EDEB6FAC1C6AB92C1DDDB94E8F9DAD553B3975940C E4CE7D7DF94B444F49D31DEF6CB6CF5D288E9D9FB0AA0FEB1CEDF54A3880DA37 7681A7812523C4A61D3C91302853003FCBB144CA247A1901B3C10E396C7F661C B06CC2D2F8E61F7CF2D2AFFF89D5D5ED6A656DA9F5E2BD9D9DA97A616D69F560 D773FD49BD4A92597396ED68F76315E79F5F7AAD4F7C5A1E5801C0F013082462 44D3C50AF991D6CA0F54E7DB793824D302187AEE8E981284438AF9F268F87A9E D798F840A376D80624A352CBA2B2001ADFB8A37FCF923FB9B133B3BDB30B0D9D 8C8115BC7E637DAED6FABEBFF1ED97DF7CE5CAB59B49AC46D3F8C223C71E7FE4 C2F1B5B5F367CECE355B0CE73FD01E811A6CA240016D434769FA6BFFEEDF3D74 E6F4473EFAAD80616DC09205EE044F3A4A192EA5A2EC939FFDEC2FFDEAAF7DD7 77FFCD6FFBB66F0B1C5BA729B07492E5053E1416C571A255A5DDFA833FFEF8DF FBB11FCF0BEBD133A7BEFB9B3EF4C1773CB37678BE3FE9C5A3A915EB4B576FFF A39FFFC5DBFD116CBC7FF9CF7EE247FFF1B7DFFCF817772EDDBEBEBBFFF157BE DC8BE343F585E9FA96D661FD50438DF6BFCEEF3C168908F6518E354CD4D9A245 97EA6D488410E38BA26A2C9459CA93DD7870C56BDF1C1C60C3442EB0B2824AD3 A53F94559CD5E4174E3D7E6836BD5957CD098EC7E92A9D26D3D576DD91C59B83 ED892B17D756DFFBFDDF69BFFB91A967090D19E781DD2B023E4C69D8A3856D88 0F14D8FF820763D3FA0369F31249958DEFB87ADE668F385B088FB088015831AB 75FF8BE9CE5BE2E89169BF6715A17BF2C88435F9B4B0ADD4C83CBCB1616F8C82 278E42A825B9B9F3F21B0D11B8F5DAFEDEF6CAC3C7F87C2DD44388589544EDBD F89AB4969B8F958910822304F1143BC7B5D3B0EB87885D43E9F9D25F0E35D2E1 09B07230AD30A2C84932CA76EF15F914F99C116EEC46370EA6F7479D0B2DB590 1B22012E5B586AF593AD62AFDB5F7AB826F98460BB5D15B23A5729705FF1C0A4 DA30B40432199EA0E719921980F65B53AFED5A73C4CD03D8B4F9A89FF6757E9F CF6E161553878B5080BC058F4B0D7627A3AA326EBEBF4217647A8786FDB1F704 AE4CFFDED2F060E83C6B0BC3CDC56227E81EF61E3E38B8EB9E8097E914D72BEA 06FA6067961311F7209EF4751A3199A658CD306FFB665AE51B810D0C3BD6F882 7B54BB9CB8D25A749D31EF721ACF7B73D1B257F93BEF4C8F3A3C07724A0A2BC3 9AB5B1506D5C0D811D7258FD7D36FCF8C5F4D56B0BA75B6913503AF7C2F6CEC5 9E5FF3ED63041221BDE730E98659E61D2F9ACF3B49302299B05845A1136D21D0 CE2C8F1CE0760BD62707BD74B6F4038FC5F386CD980589816B6970A2D8303408 E1060D1ECA00551EA6B0BF9208C72FAC412C8244E8366DD9B232C03799887A29 0F8D43A5566692AA54C9194D816903F9B3FDCC96CAD6B6A1226AE5DE695971E4 F82B3DD6931C0FD16892EB59AA90D25B8525CFD90000FFFF4944415436309954 EB1C5830ACDCE26DE590B2C86C5504AB9859CD36AEED4F0DD155D55AB481360E B7229CD1F289AC79AE571D1D1C00939E9B5FCA7402905452990C54FD7073E677 0BD748ED6005C5C65149B26DF5AF199A793C09FD822490894FB3CE3B61FD4CE0 DA136EC5419E3BF1DC8D935B57EED43E58ABCCD592CF433695F49C67B2D0CB6D 2D211102ACAB004B40AD6D1CEB15CA686C89451D716D5B36DB95A3CF4EE91E8A E298C7A2CE438B4A4C13862AB4000E28B626C16292D13515BD9EFB452515A996 61FB034BE4F9604C329F77302D7394F223714CC72311D3DEE5DD625F759E5ACC E7666FEB26975513EC73E0680001EB0D7EDCDBD8821F174E1C99556649905566 9EBE69D2595E3D3C37DADD6C1DEAE42B34EFB45C7F8DC2BE2A86800A53600D05 0BB4DF7BE33E9B2455DF8E2CDAB8F07C66CF6B120094A3E108DF880FAB5401F6 8737A3917E4A969AD1FA7AC6A3D6D156B2B7C937B6F347DF51ADD5F292F8EACD 6BD9ED577C4F8EB23CCE670BCF3E5FF887525A93458CA34678D22E4B25659B42 4A4216585AEF6285A7648488EB55597E454824F0793C6840C39321A27266DBBB 7FF8A9CFFCFCEFB447EA48BBC31AB5CFDDB8037FEBF97A7369322182E58D2A49 237B96012CFE9C903FF5EAC52B5432C42E0AD696282C783973BEF5F5F5E68FD4 E71F2AF248A64313BB5CFA4A282E6015F5C3F0C583BD7EA55667E269DF5E9510 69540A4C1282BCD4955BF27703E7C7D7D79BF30B6B34FF968F7EC85E5BFEA5FF EF573FF4CEE7BEE985F716BCD8D9DDEF1D8C7EF7131F7FFF7BDFFBCEA79E8E27 335F8870342E14E23D53023F568E91C2EDCCDCCAC7FEE88F035B7EE4C31FD688 0615EC0808EBAE70933891AE67847CE9F2A5D75F79E97BBFF33B8E1D3B922529 3C276572C659E9D28437261C07FECE2B6F5CFAA5DFF80F2F7CF377FCD0F7FD8D 5A61061B7787D31EE44C07251A8AFDC1EC9FFF87DFFECC9B774E2DAF7EFC377F 978BFB77FFFC92D99BAD0FC67FBE71FBE53BB70E2DAEC4BD51B7B7FDD8C3C79B D3E959C7B7FAC3D3AE1758B6457898E543627688DE30E900EBC3C4CB888FBA51 3AB5CCCBDDE80D088E2EA41E0B8F9F01F7A578BE9D32FDA4EFFCFC91730BBDC1 F5162191D79C44564DBC49C6EDC079B25ABF39D8BA11D046107CED07BF26F8FE 6FDE6FFAF59CD8189BE85F4E4D940C10153729217FA914F71789B0AC0FE2D1E8 DBA31645D96DF5403B00E106B1F12C32BE325E7F8907AE63CBFECECDEACA8268 1C2E3287A29DE1D40A93D9F52D01BF3E7D8856DDF8DE5EEFF28D854A7B3299D6 8EAFF087972333E169EC4CE39D175F92F513ED0BF329ED199C2C915652E06996 D3149808EB58D32588585991A0734479B9A843084156476977534D0F08C96C8E 94810CF3E98B9BC98A721E6DF08CB931248E9078428DEC83CBBB9DB586BD9029 9660E906DD4A916B2253C66E7B9B713B4DD3A2007E91096673ED4E77C238CE9A 4B0D861A5739CB65B81DFA597570234CB7B85304693A2EAC3CA742C10EA74590 8BE231C3DEC9452CC797C6A44D2A2700409BD9CDD86A35FC05DF84D1FE8D41EB 68739A4EE2309E5B5885FB9DBEBA27F738DCDBC8E62353CC923C056654B610EA B25E441FF8A55048234C14103F2C00DE3605A658CC33A1AA91CD3337B676DD6C F51FBCDF7AFEB08A9115952E221A123D1AB699516E41C4B4C57E31FAA3AF246F DC5E38D1C81B514A951F2F0CDE8AA9A52B4F38F9BD78FA6A4221CBA784CE25AD F7DA45273629E756A03005614340C1F250E4229D9B7CEC56FDFC32FBB6635327 0EA69251948696B9C6214041006E4AD41A2D85CFFE5789709559225199DBF158 15C93990B1F8201329B381F2E7C534D391825FA59E71030EF91A821D505D4717 225D36DE1911046EF8CAA0D8661C331FCE33CD128D16EFE8BDCAD1C3038302E1 282F09EB098BBF8209C08A1E893DB80161037CB23BA2D2A440FEF4D82A74EA77 B8DDACC7D362D6ED39F3A2D9EE4CFB68C66B2880ADAC73781ED877E1186924F6 E6090D4F395FA7E31BC62A2A5CC5CC60D77FE5D9B67B0616F09027C240BA75F3 5C269D5B87F76EDC0B5E68072D27BB08603DB51F69EA6C06E0413919247227AE 14458A5A769AA3886B61143C783C1E372806D2B7A79F8921E90246E4CFAAC689 4E568C3391F00250804423779E5A809EAEEBF092F6F34A22135D8D5B5F7FC83C C6074C37F81C36A2B8800F1499CED864688566F78D5DB2972F3DB596B7A70F26 8C71FA509745136CF673B0CC0B01AFDB5F3D74CC701D059174023E03547BEBC4 9147FBE33EABE5ADB36BDAE6ACD3C92CD4331580DB4C02D7CD1CAFE866BDCBF7 9B5E73301934CF9D116BA7725311C46528CA98A017B1CDE131D9389F86D3F3B0 C207B7EF5951543BB1F0FFD3F5A6C1961CE79558AEB557DDF5BD7BDFDEAFF70D 0D34BA416223C05D122942D4429923999664DA8E98989035E1B027E6A7FDC3CB D8E11F0E4F84359EB0ACD1D89425D99A18D1144552DC40122080EE4603BD77BF 5EDE7ADFDD97DA2B332B9D791BF4BF09220844A3D1EFDEAACCEF9C93F97DE7A8 67D2B97DB39508F4FC2BDC30948833FBE3E98377E2D1FD65BF321EC6F0C88A73 E61942D751A994FD08AB5503A9D2C5730834F5109F9CFBEDC18FB27675AA8E9C DF05C192CF3B27B573C13C99161A941539C1060CF9BBFFC3BFB8F3CD1F9EC2EE F1C6E220A8FCE0E68DB6E35EB62BF5B8C878469B9EC24E3E4D62C3BD0F8D3FBE 76FD2F2951DAC0D5112AA0089099B07F505DF80F17964F118164A4AA54498C0C 0287299AE228B9D54D670FE2195958265C1E37E4028CA0AACD9E2BF5496D029F 38FF0B66FFDB74044BF1EB2F3CFBC66FBFF12899FEF0BBDFFB83377EA5EA6085 A4EAB31AC8FC9FFED59F3CF7DC73674E9DCAD254BDB8248EE17C5848556F8D5D 399B3797E37DCBFBBBEFFC60C1B4BFF8DAA7B22812FA8445B74B69CB965201B8 96C5F7EEDEBB73FFC66BAFBE7866E3284620963C73606E6AF3CD3AB670AA5638 C4AEFDE6F52BEFDDBAF1C6577EE3D4B1A379B78B9244ADF8B82C402AAAC25240 F8E76FFFF4AF7EF4F6175FF9D41F7EF56B7C767F389C2935BBD719DEED749EF4 875CEAF185EE70FF54109C4CF809C739B2B1DADE3B84485F4A27059B40B08FCA 1DA8FF41AD3D57CF8AA80AC272CC6785F37E3EDE4A33CE11C373BB68062D4032 C0BEB4D2FAA78D95C5D16CCB8713601D1D24B64B7FE66927B85F739B6311FE98 8415DF7EE5C499A57FFA0F7BABF58061538117864F0F3F9E3687E2B9C7DE7C7A 507ED42F039F02E11C173FEA087A7A3CAAFBBBE5477D35404914C5CF855A6FA4 2F467766FB0F5A9BC7A6835D9E8D1A8B6BD25BD79170E55849822CE3F9BBB7E1 5ADD5F6E40C34AEF3E49EEEFC388559E3D899E5D1966E30AE3749674AFBD47AA 271B171A89EC423D2664814C55312EAC06AD6C00ABA181701E7A05455C607DC6 41849E109ADF60323EEBE5FD1D2212A4EDE34C6D69712D7C983EAEBDBC12208B 0CB5C5605A070A99D277FAB6629DCF37623AA44C1130534A25340B3DACA7CD15 09D6E78EEAE9E79217DA818F3AC9AC986CC70BD526D80C1311F9F982E82AA297 52E8EF5D1DA28EE90358682F7417505B66C38568695CE938BF29E98249EE07BD 47FDE0596A2E02F898A40F85BF5913EB65F1806EE7D736578E47B715CA137353 E6BB0C5CB5C1284F9D74046156B851C443A2C09515424F8BE85415A4C7C991D0 06D436D117E6149588C836C36583539CBB31EE9945EB0F5F317EF914CB75CF73 09F53C9F6E7DA1EADD8739621411E3A018FFCDD5FCCE5EFB58B3704729CADDA2 1DDFE27132ABBDE2E21C4757D3B4071D1614EEA4FE290BAEE8E34B4C7C6EEA69 2B43A71BB00C036350ED7FFF7EFB73E7B24F5412C482C894041554384C8FA22A CDA494A0FAC100FD3B14E1EC57D611A60C49B361AA3AA1C74719890F73BBA4EA A30B0113A176194E415E81BE870930A712C5FA04519AE5514CCF958167A55742 FE483D15539B4FA87F5DB0382F9976CBD563E93A4BE817413B425BB52313E280 1A14291D9C96BA6195042DC54A796F6768480FE0B4BE6602B732D84ED874629D 20B54A75F0646CFB0E439922D1CB1BCB099DA99F8FD5EA578F96705BB198FB45 FAA8B44045554806677059D65EAC978B8504BA21105027525CD62D1A0F16BB8F 76FD5F69393E64776385AFCE332DC9525BAD6E4BE71C3991CF8D54E84850AAF8 04D767F54CDF03A0B2340B3A36C67F97A07D53D212BCC2AA471A7939652653DF 936486361A20B9E2F1C55D995D55C8E017569E5466AD37368BE750E699015A44 99008E9E772E8623381AD01CF6EFF5CA9D74F9D20AAB87BA8B501BF1A0A73794 EA6561A24165EBEEFD7A7DA1D95ACED84CBAC2CE9AFD833D66A296B39875C7F4 941F564963F938206688679CB14AE9E9CC1AED48C89F5CBDD3361B3ABBBBD6F4 4E9C4C886519BE3E1ED7327D2E02E7C584EA0B773DE6174FC6E3CEC1D27A0B3B EA7BE7FB376EB42CCF38FF7C2E284939DCBB1B753E80E5CC83E67818562E7FBC 583AEE9AEB4AE0A6E68494AE2262481F6EEBBF74D6EE539D376F5FD128A8B110 E85652DD1EC1F4A5B5FAC68AA50985815C2261956EFEA39B3FF81FFFD7A2DBBB D06CD680B15D5DFCF1B52B176AD5533420A96E7AB61C4895E2CFCA5901A6C4FE F6EEFE7F31EB9B1C04C04D008B71F192EBFC93E6FAEBA6E25823B362FA2950E4 7A40011531CDDC5E943FCEA6B39235ABCBA620CBA6F4C550111959AB42C5AA47 D1C1C4FFE7D3EE5F4C7A2DDFFF47BFFEA5A5631BF7BBDDFD07F73FFFC2330BCD 6096A845E52A7EF997DFF9E6D1E3C7BCC0EF0F0783C9382BF2A7F935EDC5D672 A36DAB6AC1CAC030275EF5BBDFFBFB05C37DFDF20B6A0B443C55FBB13489D285 16A096C436321FDC7F78FDD1CDCB1FBFB4E454F4EDBFC8BB657CBFB74B14C0CF 8A6395C5E34BEBD576EBEEC1F6DD07772F3F7B6A7171C1E18A659721CF33AA94 3DAF975694E67FBF75E7AF7FF2A3AF7FF91FFCF2858FCFBA0F3A797A3018C7D3 7478308C92BC3B9D1CA413C337D64A7826156B94989EF9796044520FF6E65C8C 65F918B11D50C63A7E0BD9FA2852E4306758B8B23A06E24AEFF02113B1A54FEF B0EE01243509BE7EEAC41B08D593B48BD143039D18660EC157968C593A7AC308 6C977C1F8D888B4F369ACFFD937F1C3E7B86E4DC504048E6E934BFE896D16397 F0171784F2A3A866F991E9CCD3E3D15F8C16EAFFA8FC45578D9E45579C2A8720 31EC5ABE9DDCFB99BB7A2CC764FAE0ADC5AA532E3FC39949C9AC844AB6BBE69D BDC1E1FEE24ADB585D90593EB9723FBCBBBF7AE919F8F2E951781828209C849D ABEF1A0BE71ACFD413A92802B2B9A51E8D12F9CCA8207F9DDA0BF33B4DAECD72 D51F41588984A968BFFE05A27B2259C40E9F906C2CD44AD47326906E93C78FEE 544E37EBAD9A9C69979FDC071693E28338DF4FFC578FE495114C13535A732B01 CE4AAEBD43C57CAC91C13253B548A9153D5251221EEF16BC5FBAE7951A4C6862 183CE8EF1D361ACB2C743A6F3EB226D051B293AB826E6111D9A142859EFD7262 5FF2415C0F6F872118B62F2E2AEA9EDD0C0131AC330B3C2F1EED7CD0A02B75BE 318E76C57AD6A8AD85EF14E2C1D0C07CC261C4AB31A393527F303DCF8C9E5212 6D2D434A6961ACC517522B1A5013AD64A4A867254C6BB9153A65FDEB97D097CE 692374FD3E73A2347F693382308B639C2B926F758BD1BFBD96DC395CDE68317B 90D1D8E68BF98D62D21B545FF569E0940FCBEEF5692D6F423FF75FA77239E142 C1B0AB1421224C8F96515542CCEC269B6EF7567FED39F68CCD39B072CAA9A20F C2CD0D25024B2357B58D30F3DF0984F1178EE8F12413D31A559F90E92C2FA814 61206DDDDC224052A28423B5196AB8EA21F5F44710A73433552DA0E71D70A630 0D9CBF17C6770A8C0C55F21807092B33A6DEA05A458612374A75510CF4D6D18D E5D2304D1F694F19F5D2190A95BCC78655ABBB591E4E06EA77FA4E2573965092 92E97E1950048EEB9CB6F1FD59B5560BE1342DD2D58D950C24D21408EB438412 9776660E6F86F2907865450F875752FF02C29B90FB405FCE2A99AA7324FCBC9A F9B79CFE5EAFF9AB1B3428F9ED61FF60109C5F539FDA865CA937064C2FAE7233 669061A580981E2EE452935FED2561E746E2CCFE36118F947294F255563BB258 88890242B50968A6E72B0B92696FBBBBA2B8AA588CCFAC3C6C444BBF719C3F8F 8B8AE7899AD4F90FB2544F633896831E888BC18391D88D572EAE8A5AA8F8968E 2F9F4FDA49DD2F4314258EA37CD01FADAF6F2AB5A4D3E26949F7E44177D07EF6 786FEF71CD75CCA36B61E0DAD51A3669CA435554782E1CE228108D1E6F77B61E B7EACBE3046D5C7A9D3955DD91AF74BF1084BA3C95C852DF55DBB0A8CA642818 8CF2D1EE13A7E5394B359045C5703CD9DBAFAF2FF1E575DDBEB5771876DE73CA 03A714D9309C61D4B8F82AAA9F03B45616536E46985590968304E8F0031DE1AC B6F01C05E7E194504FD8CD7791352F77A9765B53A0966987065981427DACADEE A33FFE56F7FBEF550373253015F2DD0E96AEBCF7CE27EA9506B459697858540C 0587DAEF218F794E9D2B71FCB58347342399DA0F223B6D90FF6879ED974DE215 9302A755BF6A15EA81EAC387084F48ECEE3279A3E8255976DC596900B76DA3A0 1C219AC7815D481BF6D3BBFEE2FFFCE8DE7767935F7BF5D5CBEB6BC8F7B7763A 66963C7F728D9505F61610AD8571F1BF7FFBFFCCF26C3C1E4F93E269A3E7D3D1 F68AEF78DA8843D1645A0F2AC071F676F61694083B7E54FB8B28ED5C75F32CB7 F4B1928E27CAA47C78B07BF7FEBD9AE7C9AC30D4AE636A211451CEC03CA6CF46 D8B5ECDA42CB6D564514BF72E6D4E6D1A37C125958679915EA4D0352CDE4741A DD8C7BDFBDF6D6172EBEF2CAB173BDB0D74FA2699846E3300B8BB410FBE3E1CD EED6F2D2E22AA54BB3F4747B8118E0778632346082CA94892928EF97F9235114 00BB6AA70A99CA34A7C2F00C77AABB08F645F9F7F1F06E1AA945A4392DC097AD C67F76E2C4E97864F08C31FC41808F4E12B3845B1BB54ED8FB15CB69F8F6CFE0 28B159CB772FFDFEEFBBBFFC4B420FA33389E1FF7FD6A91B6544A94F923FD27F F3565158C25FF8AD89F9AA51A0279F5E0D4A6D183717904F57549A922C119B0D BE0F767E20BC16AE1F89EE7DDB4977F19197B8BB8A5097E3596205D5A888EE3D 29D3C43ED6A6CD4AD90D7B6FDD324CA7FEC98BB92B5016D2E1A4F7EE7BB27AA2 75B195C11EC4C8CC2928F45C4C4E02E8AD9BEE02D4A71A62DEB99317549139F5 7F4A266BB42AB0E297091977E168BF94AA8CE8FC657B5A11BBC32C99F8679BB9 ADFB252D7D3E98832E1EDF8F82F52A3A52A6A06F7042E63EAB4C0FE7E820265C 22C5C5B51561565A8E2580622489828F68AB50E5B37ED4C98D01E634EF1AE140 B6D75747B71E4FAF8D17F93A407681B8E261398A6DB598DC2478CD2E56211C06 E31B09A98AC6598B8FC2C9966856378BCDFD72600DB647ED95B55CAD8169B8B8 5EE7D934BC33063B26C9AB21C01192831CE582AB0F269E7ADD69631DA814E13C 1557E7E35A962AE4A41D4ABEA004725A4B8C214C2BBF77C1F9DD9798D0D199EA 7199FA2444E90682B32C8431F5A533CA077F7D2DBA37DED858E6B4A7D0D3E0B5 E28322ED4CAA2F57CA0545B7CDC3B767B4636337F75E23E898605CC96F0B58AA 54EA19166963C449F7FB07B8EEB6BF78A65CC7905394E3D4CC38126E666B514E 33A1AA3337951AFA7701E18692E2C8B58C86515AAA48972C96455F78C0924A09 F3322A74EFACA0B28E2B36848C8E08C9696196B6EBBCD45028A5EDBBDE9D4C3E 883072D4C2CE758A0750B247CF68601D4D9AA6B14590A9DDDDF4559B6558AA58 526DA80515FE9794798EEBB9F6643810B98252C35FD675B5BB330313BFBDE6E5 EB91629FE35BB3467D61207A8A132DAD2E33A44F8BD0FC308F436E4566EFC6C4 1A3BAEF05359D235E97CCC949569699A0A918991B34289C746ECC7E687C6A437 597CE338AA14FCC3EEE1E37EF5DCA6699704664ACC2999EB14358643ED4C2DA8 AA9D4FE728D43F085014C6CC1695FCEF797A9BEB2CE54FCBEA469389483B26E8 803F83428303852D20BBCBF32BC8631566C6D14ABCF4D567E0059C3A8E95B9DA 5F073125AE4892817E2FEFCF7AB70FC161B1F6C2111E8425E390CC5D1B109A77 289B2C159DBD6EADD572025F1B5C413D77DBBBBFBDB87422216838DA5A3ED686 0B4760A30D1C24CA544940A116820D40628AC16CE7C3DB6BAD058EB0BF7E8E3B CB1974DCC0D25C557710414C5CF5ADA9C02597198496DAF5BB5D3E9D06A79653 9719692A1F1FA671E89CDD8C9C6A6566878FB6D2E28E2DFB7E4192D1205BA8D4 CE7E02DAE7F4C9909908105256D3DE790AEAF5C8A0927D74DE2CFA94CBC35FCC D1ABB7E6E805A99E953601D72E01A048A5A78A6EB8FD6FDEDCFF93EF35064AF7 B75D99283A7C2D58FCF09D773F5BAD1B82C6542D1EB66EE926AC54E714EB39F7 0F19FFC7D1E0A033ED41E863F97BED235FB57D27ED4A186D542A8EC4917A3BD2 AC416B87F448E21F98E6DB45771A8E2F3BEB4BA5BB60A1051413940F081E0323 192657AAC1BF7EF2F826E39F7CF6D90B4BAB4A4F5EBF7177A3527DFED47A2459 4EBDC787D30F6EDCBBD5BFADDE48DDB2EB414029C9B2621E3F06923C0FD33807 4A62536DA00CA44914F7297413B78329412017156AABB5A26A5406F808C99147 02C3F68BD2A6868B71839A6DC30D945AE7BC1B4F27A548111AC561278E5D004E D5974E5F387F64B16D0AAC14704AA5C9C09AE377BA87B7C283EF5FB9F6E9B367 BF70E9D5BBE35E328DD33861B922FD3C43707B3A7AD0D9B6203856F19A48562D BC7174F53F7DACCA3F9AE6C924CF13CBDC26728B65312F1D4E3C25BB118F642A 48B94AAADE8097D5C56FC9E90F0F762CACCDC73997BFD9D8FCA395F5C5F0A010 19CAAD6BBE6CCD62BB04FBEB8D6E387CCDB6973CF3A6110DAC2CF0EC335FFCE2 C6577E1B580E2F72809F3AC5284084DA9F40B3271D48A8506FEEDE81B16E2F9F 3BCEA07960F647898BE5D35B44F41441E70DBC00E689DABCC5315F1CCADDEFA5 66D3699F07FB3F9ADEF9A1B3F41C3D7939C71D484256FA0843FB7032BB7B3FB3 41E3B9D33AC4E07EB7F3FEDD85234BD6857569723209C377AE276871E9636D66 8CB5B74A612A762F05CF9107DC3910C2B97DB33E0BCDB86E0051F5B09C0321CA 75285041A2A9EC6F4BA5D355ED94C22A9B6488B2EB77D029BFD8ACF1905599D0 7338A51BDECF449CD59EADA6EE00175C9F8E6243FBE7979A13EA6EA214C0C4CC 67DCA9A93D173392125548F768BC55D48FDA6CA3CB25377B6BC307B1B3086D9F 446F87F90D6A421729C40DCBA4BAAB2AB91872EF45C45F2D4AD6746EB5A2FD9D CAC7725617EC81071ED8E8D5BEC34E749E3CC9EDE448EBB9C18753A3360E4EE6 93272C7CDBA9154B8288319BF58491E63CD310AD7DE5F4C43FD0069F54EAD14E 8B405BAD7293288D92067949F306B34722B4BF72BAF27B9FD00DA23AFF41D577 3D64CCE70ECC333445BEF4FB45FFAFDF4B1F4ED6373704EEE7F64C87055D2F8B 8369F5D586A8A798BBC9F522B9C125C8DC8F4BE7A2952BEA0C6D69718805D240 68C258F4BEBFD3F8F869E3E565EEE7EA97CA4411C45CF14E3BB100D779AEDAAA 4F9A73DFF6790FB25E720AA30CE89FD7A6DBD9178F4C4B819A81D9344A10DAA5 CC7B4C28AA2FE93CC4892B565AE4AAC2F20AF22CAA7E72E222329874C1254C7F B586AA5EB55F2D7FBCD7BF35C670D92DA32C4B7349C605CC39B16C8749452312 47BB0F60858258C9106C9B4A75221412327642AB02979C66D651388A0B90A584 BB47177432C9DDD4378DFC130973336BEC26D78AE6E2D261B1E3564D3FF04A5B 686B3462E8F6265838B3E6F066CF9952C018AF67C1E540AE29DDAA477D2CDD88 2E199E96242DB185EE3651E199AF05C0DB673B79FFA7E3E69163C69ACCC1C0D4 43AA40271D316D0956E8CBF904A10895141735B51572736232C2AF5AC3776303 18E6A7D360A322F4B32938C9730CADDCD52D0D948FB7A2E81D6781B552B2DD7B 6E70FC2B1FC347EBC2A8E509B230473252E40EA352F643F8A4185FDD4B67F1D2 4BC785CF61AEC7840BC890EB089D7665173B3336898253ABA1ABCA5161737BB6 CF87FCE1C673A71FBEFB78B579CC3EDE4C568CD2095C198852244ADC40613060 64EEF0DE2E555486CD1A478FD1A553DC69EA7B07AED828513A1CC21CC0303596 8954622A52189586717FFB7065F304A83B11492BBC60D7EF294A239F3F82F912 8DBAFCF1FB84C53C11C433F63BB7AB278E7AEB9F94E0882E5338CAB59F724D7B 116BBC439A79E92C433CBF5C474F8DB4E0D3695C6AC3648E03262F885A936A43 095B559437AFECFDCB3F4FF7F688EBB59C85C6140CCAE2EA927BFF9D5BAFA2D5 145B63BF5C47F909B58E2D73CA52332D0037BAA5F37F15F91FEF6F75817CC335 FFE346730193297160289FA176C329263802301063F418F59A6AEB59CE8FCBD9 5E32F9B8533B278167EBE6C7A03090B015B2DDB6C0E38AF8F9C39D9D61F2F2D9 E7DA5E6BAF3FE88C7A17CF9E590C82ED647865B873EBC94310CA571D73C3B64E BA4D078299C8B0679471025366FAFE411C8E92A2516DA459D19548AD404B2452 3D6740694EA156A81621C8D3B1CB4507CB5B359860B1099D1569015624EA7796 B209A88FB5CF905362339163C47FCA07939A3798943BD968D10F2EB456D6DBCB 8E691A9902BAACC3E36E3C9BEC1D2E571B479548E3940CA76999C548E09C29A0 B911F7DEDFDF5EC5F66937F0021318DA3EF1BFF75CA3A022958765D933D036CF B68B3832B4396CA5D0C11A0A790AF5AAFCA4153939AE7E331BFD3C1CA972E823 5293E91F9E3CF1C512F85932A4C64418DB98A2223469CA2A6612D1162727379C 211DEE096906FEC6F30BCFFCEE97F263AFE2D4C398C554E763D8A55AF009C7BA B7CE013192C30C1021035FAD965CED42ED52AFF58DA6C9F3C86F44D9FCA24587 D66B2F023D7CAB882E2F950E1A88E16E7F1C37CF3E2F15365F7FCB5644F67833 6FEB1955927B077ED954F4F2DE8EFCF0915C59282F1F8BD44E7EE71EF8C907E6 A935E3D5338A32EEBD7DAB3A2EAA9F68B320494ADF60BE5546201F08E83063DD 0C5A88EA194E28AB92244AF6C1522D5F6B9E2B104214E9359F53168F59F8C82A 279815294456E266B7A7719C365F3C5A665D4474D705B714C9E59D379353A72E F2E3432986B470E623A3DA948B03C230536BC11B98E010E2B6350BC6B976E44F 6BAAACDD70C6E1D87AD61108BA69BB1C4507C95675B36624FEF0E7B3F27E5141 B558D8A1EC981490CC301BBEFF1967B270581FFBF8433211DBF03525E56AF94D CBE830EF9259E2A4F3E1AC619E566BAE175E5B5A0F64EACC768CC9BDB4963901 331F59F778DE8AF25A58F214863A05501224758381F6B82C0D45A32D037BEA21 58981AD885722A23E7D3A72A5FFF8CC2246DADA738BAF6EED0BDEAA4A41363CA 096C3E32277FFE03113EAC9F6AEA665C551E4BC23E44F1C378E9B55AD19A2924 91A1C9DEA2E563404E70F52D0A5B517853FB272A7D557AA5E94DB6B6D1F6C4FF F2C7E5513F82B1ABA48B2A2FBACB05950AAC758342F9F43841111B3A37C1D0CD EC3AE6CB42DE8595F5FF06C66F6C28AA88EA1EF4D46FCFD593CF7B855295505F 002B84940220A1343BD40DDF16D6B64BA814A199982F06F66B4D61036BE28BEF 6E4F6E8E31AE9B324FB2AC9466C6D0AC046A2792BC7095DCB024345155A0401A 537D37C5A99E4E342632F1D73C5CB272AF704A37F112B65056ECFAEC61CC19AB 1EF7E82955E878FA24CD1F948B4BAB87B327D59667FAB692FCDADF8F98B9981F FE76AAB3873D458F4B05D8275DE3B49D55E35C8F4762DD98A4DBF3D5EF2F0C2B 48EF180455AD1783D239901DDE7D73546F2D5BC7690ABAA6A44810BDF1B9C5B5 46D2DE6D12E5DA76897B3AA997C690E3FC261DBD1B07D2259F4BDD15AF54D55C BB402ABDAE60C03198AAFC3CDC66B39F925ADE4CE96EFC09B6F25B97D0B2C789 2352C328F564B78E6F790A840FA2DED5031EA7CB2F6C960D9D074E45519A3033 29859E31C6FDADDDE0680BD50D7D89424C31CE07DBC3E074A348E2B813AD9E3D 2F975CB1E831645368C92CA184A7A95A8B16B83B9EF4078665DAB5BADD5E05B5 9592044C8F269758CFB5E8F603F5B758611ACB68C9409A3CDADA6AAF1E75AACD 82F0C2645E148B9BF7A58393F3CBAE5C90BD8362EF9E981D52DDD626BA93BDD5 4B97C8C20B12ACE98585C2CCC046F95411CEAD79F4CD0FFE286E1062F8D191D7 D36E4028D4522A99A9DB9F984650C5D7EEECDCF9E36FCC6EDEB372BE525F502F 0E4FE29092EB75A77F65EB0258E860241CF45C96AF6238ADDB639ED5A779591A 5D603FE6D67FD9DFBA56845F3BB2FE15C3409D43A3B21225B065C015B50949DE 91E4FE388D71D6924151E0031BDD0B7B9B96F532718E39760744EF4D0E497BB5 1F4A419D304357A2FE9571F7E4E6712B47DBFBFB674F9E5B5D5E3AE8ECDDE93E D91E0F172179C65B7C09675EE0AB7DCB33453FED9183EF8D0EC2C0987AE4706F 70AAB457ACEAA32C02F170D5919B7EA5416D6490CC32182581631DAD54033D27 A6968F140C8E9231E1C29889C371B8C3590C8945BD719A0D41AE1851C371A081 1EF3B192509BDCDD8F679293D92C1907B6B7B1DEF69A1EC74591EF0F3A44711D 2C17961697140F9F2ACE0243A4EF7630A0777B9D07C34385B49F3C720A8523C9 A24FBEFAD2D7B73BA1677547B3A4280F0D743D9FF5B3CC290D8718BA89A928A4 89231BB68633DE68BF93A53FE877A76A2B401A08F1B9D6E2D75BADE7B204E4C9 00D29C3977A8643CB5655A718C71812779F1DC338B1CF59F4459D06AB596F199 375E059FFB6A26AAA6CEBCD4AB1D2B1C54C2D9AC08552614472A432433001D90 5260724962202C80DC791F19D72D94BA03FE69FA019C1FCBA99256725094A569 815919ED0E0E06D5CDD3069BC2CE0385E9639434CEAFEA79A494A48E7A3685A5 AADA6E777C77B776EA78B25AA5928BABF70EAF7DB878E19473E9D9CEDD2DF1C1 F6EAA737CB6A2E915308079685C523255633A72582150706B0D0BD7340B165F5 51358F33741B0F4C244975776B69CA642AC22720EFA9829928519852D1A5DDEB 8F5A173769BB2CCA589B020125B282FD1FF77CBBE27D5CD1F62965D6FC0E41C9 2E058886346596A7461F8343612C7BA93FD521B9892AA5AAE680E47E81332B38 E787A4E7C9C6E8D6181865F3588BEFA68377A6621F3858BD6A55C4594981FA12 F5975BC5B1282FC3DAA41ADF0C69955A67CD21E88AF72AB8356D2CB5D981DCDA D93D76F668783885A2A89FF093493EBB0AE18E69133944B1006E5CD050082566 333D5A592A9A6613DDD26348DD704D30ACE20CDAD430B003CA9198599F3CD6F8 7DA51804D5FBA4D48D640ABE745B008EDD38916CE13E1AFDC58F141B74D77DA5 1905E5589AE226891E85ED5783645167FB78A496FD3C8B6EE57811D53E5B056D 9116A9EE5C765439B5A0F076DFBEE1D7FCFAAF5CCE9A802B882C141301DAE81F CD23A1F5797A396FC5551F40F7FCCC9D024B3DDB056DE83CA38170FCC632744C 527775541C10322C8A7EE2404F8B495E6682A9FA9F33BD16D46A34A02AA576C2 92685DB63FBF098F999C3033F2F36F3ECC6FC6C034899E95D08979992089EE8C D496A7041655DF91A53E38724C2BC90AF5CC28450A7172A3A42BF674326C2735 1CC16175626EDA681FB2DD92AD95B5972AD8D28794BD3B43C5875BCDA549DC75 9A0EF6A1BE23C40AB8A810C04026BF6D4EBA7D96C5B44ADA2FAC96CDAC70624E 54C5C58636FAD0790E3AE71D3ADD1B53AFB1EA5FAE31A707FABCF7A351DD6ED8 CF5A21D8B74A9372535112C2EC82E8EC3F531F46F39C28D547CD5CE99B5CEDBA 44C98AB726ADBC82BF949A8BA6F65950CB12338E116186A11D7C44F2984F7E06 EB7C3141FBFC0D63E1CBCFC11AC915A468FE9422436DFD8CE212F6C2F2F6A47F BD0372DE7A76350F32ED6D2198A020D31DC9F5E8C38E8214E7E27224679E924E A0DA7FB88F1DDCD8583BBC75AFB9B088CEAC8145B7543A9304BC2C5836B359A1 C46A3A8DD2EB7BDAF5DA772B6BC7A5DB8456854B9D0B3177BEE63AE34D622135 B9B64A8EB3B4FBE82171DDC6DAA66E47C11CAA67311CF07B8FF052657CB45649 ACE8C9632F9BF2A8AB4AD0349A2815B1FCFC8BC03D07E43290B90489369606D5 A7C11DF2A34ED1F928FDDC22123E758D9CB7010A2A95D0B69163A58AD3E7C02D F178D4FFD3BF39FCD1BB6994ACF98D40150F878A245592FCBA4986F70F4E81C6 5820D3B78EE6F1320679C54E59EE865926E9A8A432B1FF1998FD45F7F1E5A6FF DB8DE048C2ADB2112A1A8A8B9619D68CB223F0B530BEDD0497C3C0C9E89E5BEE E7D3D3885E1264D5B5F2AAF9A3E1FE16C121B02CE972B4F8D3D1E36BB38360A1 1150A777D03B7FE23418C593EE4E2A3217A3E797964F230FB368E693619C99C3 C2A34EE21BFBD99854CDA9AAB88C7F6AF5A49D97EFCD3A17EAF6B3CBCBABF505 6A1A40ED35D3408C791455166BC0A7DA916DAF4B26AC6F7086A43715655AC6A2 1C8CA3E920EAE5F9C3E974A638AC40BD247A48F24482F37E5D95079FEABEA42B 87BB7B79BAE0D457AD4635A80DF2CC6E56FB59AC5EF24564C9A24C6C1271E1E9 590C7AB5BFBD33DC7E7D651345035A0375C95E6E2EFF7B4E354470E7E0B0E078 00C0B564BA6BEAB8C956461AB99E1B1B58C5A8825FEEE2777DF4B793E16ECC98 AD2D38D7B9F95FAF9DFA8C142E9C659247C29D16F63D52F4746A57B62E7901DD EB4978F9C2E2321C3D1A86E6FAC691263FF9E229F43BFF09B3EA52DFDB28A134 42C3C3E8605871AB78A10E1C9BB98D248726504555201A03A40FC7800CE6FD19 5C87DC94856E26D54685942B3CD1C15E02F34C5517836665BE3F7AF4C46F1DB5 4C90ECDD22251BCD068D134BD872B2D2343D219350FB252289EEF793FB1DEF85 D3C396B9C060FAD68DC3ADEDE6B95346AD1EBEF961EDD575BC4C74B61AB21936 DC22812C4E5DAF084E78E50ACE15978FB478036C3EF46FCC5D601381626D8621 4DC05219EDF0B883B9AACAA50D4CB90F46577BC2000B9F5E8BF89EA37E57A20D 90E51E3E7CB4BDFC729D5B3A4A11E93E7FA6ED0C84A10871CE133484BCC314E7 CEDD485BB8A75621435613CE61857DC8CD65181D1FC5196B67A767B73BF60A36 EA26DF927B3FEF37FA865B561310312F55BBDD5D0D8C577067713F60F5CACD76 FE3832CEB1ECC8587417665BFB0B8B6DBA64F5BBDBC5A05C5938B3DDDD751759 B3554F1F96D30F0A3246A5D18CD838D3392C749A69032EFDE0157241A9478651 A90326100E50A1781B9D03E1804D8CD736171510D6C13C624667FB0A885589C0 0C465E168BACF5900EBFF17D038FCD255BC3A4A13885CD6FA1706BB6F84A2569 E78CF3C074CB7BF9E44A5A0A52FF441D9D2E32F59CB1294C25FA08EA984FDEBA 5DF9DCC9C60BA7622B03B6C4796188B95FB33E3B9F0FAA3EEDB382BA474B03A1 D4974C9268E342E45E585240D8FF72DBACB9EA2F6D13CC61DE8FF844113A1321 25B640C6943C519FA4B0D52B5AB04421EB6930E453F6A2B5FAABE77394EA4695 C499FC3F0FF19D54DA9AF98B5C2A551A2B26A2EA1B32904738E19EE0342F7255 3A2C132BE5E052C37592EEB47EA4D1617DCA49105A4214E008C60E89EFC78AF3 D53FD58ADB331B51D4273B1F6EFB4E25F06AB3F1D06959A5CF155895FA961C9B 3A972848DF65C359A7B479FD44C53BE673272AB4FD85B690D6CD9050D75F8271 59D87B0F0EEAC74EF927BCC83EB4133CFD6142121A7CCC1E935D9B99160F729C 1B859B1991A29FA61E9B02899121255F153F15AAAA93FC90EEFDA4B394D7C897 33146877301DC0A4F681169E98C25249BDF89E98FE4C36C952040FE8D79AFE2F 9D045699A98D2A0CCC73A95521239091EE58DE8EFA1F740928EBCFB415A750EF 45D10F4C31A17E361483ADEEDAC9CDA2CA62AAD909DD43FD4EDFBEB8EC1D8AB8 37F69F5B2B4FD6996519B026A7FA86416D3E4BCFB13BC3B73EB4A12D03692EB5 85DB3682354560B162058C964AE9EBBB0D4599D4B7AB182256127FB2B31D8553 A52F158951D4473315B51B0F76F8EEBE797471BCE4F9AADE1F0C5C9E8AE91E09 CC5EAFE72F2FD91BE7253D0AD102D0F38A8C236D31A1C8C77C6010CD27A6D1DC 6B147E9432079F1A73CAB94B63A9401F44DCA418C844FCE0AD9DBFFC567138E2 12B7AD7A45C0A9E2DA3CCF25BE695B078FBA6BA9A93489BD5A5F44E9BA2CABD4 9105177992481A4B2A38FA5B62FCCBEDAD3D167F6AC5FEACBDB89238408139CA 6C1AD50814CCEC25E59FB4E28BBB602168DCC131CF939789BFCEB963825650CD A0F1BDF1E1BB2C1F142C15C11E4A77D2B1A25A811B4C8763806D33CE8E523FC0 B2EEC39315B7398B1F7A0BD7A3EE2C0C5FA1FE05C3F3EA6EB56A9FB05D12CF90 8D6B8B4124D22E4A8F2D9D709145B1A1682040D8E1408766B797E4520D346C20 5270F756DAD98F1C04B1D68078165351A2428002C4051FA73C1EE43C940752FE 0C863FDEDB35BD8A30B1549F67716596A6BA4B38CCD3593A531BD8A935D78F8C B374320B3FD93EC20B91194A6AE0A6B46669F2D6E8D168D6FBEDF3E7E3C17E48 275FD8583A7F989D7EE6A4EC45DD9D4E06E9419EDF299247018D6DA39D1A2B89 525DBC076214980DE17E371CFD7438324D7DFA4488FCDDC595FF1CD68FA693A2 2E2682A72CE8156E5744F76D2C0CB11E4D7C6FF16A9A9E5DA22F58E9E330ED2F D4CFB4F8E92375F737BF5EAEAEC72685A6EB16394C0B9015D9ADF7BA1FFCA07E F9227EF937385E0EB4F54338E3535F47FD58DA50421B9A284A5B104494FC03D0 8486919549A1982B513F9048EE109A49713879B4E5F86DAB59DFBBFB5ED33764 3C558FDF5C598D002EC93450EF1744B123EB099EFCF886D76EF1538BAA9CFB51 31FEE0C1FEBD9DE3474F9A5B83FC7CD57AA6AAF05D028B6117E6B101A6B9E2B1 EE394B9E562496195D5C3E3D73D3845B0779622564752CB94E3655E58F0DD874 4764A1D41173C218E2F4663AEC8F973FB521FD8954C53C45283690B5D279F7FD 60D532562A8233ED0B8114F726A4B455A5CE250393B238CCFCD5A03043F56449 614BC82294B88AFBEE88C19DBDC58BADBCADBE13850F091B45C1E9A612AB9307 21FE317432BFC0B3D01A188252CBB03E6D8C4F0F40EE3447C7677787AC8C1B27 97C7EEB6F54143692CE79222C06C722DF1DB4B7145849DD991664B38C5F0F608 DF0E205F4FE5BEFAD392D29A4626D3833F50C723436211E852666A0A8C3DA08F 10541D744AA114A1F1FAD1853FF84C5E538A88696BD8A7079525524263E2260C F08527F6F0CFBE63D289B162EBBC1DA5AC90C36EE3C9BD49EB652F5C2A1857E4 9AA0298EDE8BF37D5CBFD48417D3D48B75CCAA052D88C57BF9743FB1BE7ECE5D 08325B08C80DAE98F6D3609BF9BD4C39372D9ADB1B7384F588E57CC2691E51E7 626F0E849DAFB4DCBA433DDDA3AF2D463B33A390544F3A905CA0449BC11488A8 BA83CBAA523AC289EC9E955ABFD66E7C62238DA6981AE610F7BE71CF795428DA 29A15A8E98154A9BE8196A8290527E0656252B4154D7C39C33DBF568C554FBD6 563AA609FBE36E132D24D3C45CC666C5CCBA6C329A352F368DF35E614C0C6996 77C0E31B8FD64E6FA8CD30EB0C6A47AA893D0373F37AF5CD3C59C1A19D5ECDBB C94EE564503BAF366C96CB085089E769A8187D34BB8695100B2BDB4F6EB52F3D E7AD7821ED9A05CADE2CF801AFBDE28DAD2716771C56CBB18E92C88C99923046 E140A8D66AAA1E9A9D11BDE625E17D6BE7273B6DD8A45F8A156E95B99EA1D7E3 B50AE3444989AAEF28BE59CC7E2EABC662EE8EBD7FB8493ED6123A6AD022DC50 68ACA891DAB648C472AF4F1FB2C1875D4240E5B905401354CA01CA88ED5473BB 7FB743EA41EDD89212613CA005B4B3EBA306F5CB0B95F4DD2E34A8FFD953794D 61BC123115A5F138544CBA302115B7764827CA2C0A9BB6B9BA8E1B4773EE18AA 7CE8AC03136AA364C690E23966593ABE48B2787A78B8BBBCB641BD40FD0BED47 030B0CD364F7A1188FFCCD76D830C8CE132BC56C342E663BDE6A6D341855374E A2E649898F00180019EBF4465855CF671E873077D67EDA9D25F1D3FE78DD26AA 4DEB9FDAA832DDCCCC81AA6A8694F483BB87FFFAFF9E3D7A944579CB6BE9A307 3D87905B4936A3F41AC583BB9D0D59B9361E676DF705D73A9F32DF7275774292 94059E0A7C88F31037FE269AFCABC327C4869FA92CBC44AB4B58DFF2329999D4 A88AA02A9C6FC05EBFAFB8D4A27A5AC6343CE757DA042E5BB4910297B85B447E AB1C7F273C3C3A8603227A5CC739CDA679410CBB5A55EFED48A3698BA402B253 B05C0F93074E4B5469D327AFD71AC7A54C1524C86CC9B06D01814DD22A960DCB F00C401AA23410D763A96A4DC5BCD865455F3D1EDB2FB5191DABF2B09E4C2B59 66280A39CD933819121952AC541C360C93D00632BD5CFD7C3672E1BDD9643FC5 5BE9F883AD9D8AA9B8A7B93B8B17373752017687FDA8C89F1E07A9477EBAB96C 1BB6621B79214605DF190FF766BD672E9C99F677CCD1E04B2BEDDF5A3E76D1A9 0E6B71BE3D8E0F6663096FB2EC5E99C69810880DDBE158E6695263B0CDD13783 E2FDC7831926AA7AAC97F04B4B2B5FACD436D35903A686077A420CB83BCB8361 3ED9A658583088066E7B759B8123E5F4930DFC90C80F1D78AE25CED58CC6177E 87BEFCCB0CC612A44641B3C488E399BCFF13B273ABFAE95F8A37CFCB070FDD41 579C3D95A8F7C3F40986AA584CF72AEAD109458E75DFA95ACF04739E409921A2 6A81850AA754420574B3BDFB845BD6FAE6934737037D89C48B49E89D3E9B1223 879D4AC121CEA7668E84B4F7D3DE8D07B5D31B622528A566C1B36B0FA3FB074B 218E4F55ED5756F420562E29AE49A076C490EB2EC9B3845C280961E49032340F AB992F72ED5D99973A104311628844815024667B69382821B0D4CB9C89F821E3 3390E3F1F2854581D42E545C474994CAF0E161DE9FAE9CDF001E1465968B9030 B52F1CED6946CA722A93C338D808040D154B47D255655C3D81DC8EF534ED6DC8 0E44E5B21F56877462151F428B1AC633468427E6DBFEECADD8C686F0D22C2A0C 83D28B105DD09680AEA8C802EFDDE83564DB7C71820FD7F6B677617DB4D26E16 63301C0F168E6E8C0E0A11674BC79D7C944C6E32F2E8A8B407399C24054D8A6A CA702E12ED7A85A94D91A92DA3B9DA9135AA305F62021D20C722B45E3F5EFF83 4F17D552FBF109ADE399361F409895232B4204551FE0E19FFD1DB1A6F69A2B15 10626E203BBF0927F7C6AD97837029565BC485061138BB914EAFA6F5E34DF239 3BAF8C95B4344C8A5271F0F707CB6B67C17FB0AC9D7A35CF173AE64DB759A977 83E791964FDD17E683D9F3DB3DF5B24A24B42726F4B0FBCCD2FA7F0B3BFF7EDB A9EA2B1A8A5C3696B3DD698D9A50EAC189A234E25CD5F6DCB065DDB092325345 1632DC6FB2E5DF3F0F8FA82A34734815EFE0CEFF712338E022D027B0FA023B55 3F425538932B7954144A2624A6284C05AD9C0AE96E2C47492832EED42BD378E0 4BAD95982BED6553E9DDC1C3B173B21EBCE46534A40628A7A2B822FB7BFDCD8F 1D1D1FF6410A6B472B03D8559258B10F020D97077C8F471F847C81D72F2F8A7A 9EE3046B378E922A2454C082F5A0912831A526DFF61F0DDE5F7FED6356C599A2 810B71F1164BEF258BAFD526C1138BB95651CB51A1146A4163B5BAA976DF0619 2AD41F6370ED080F72C20FEC9DB71E2FD616E8E7536D7D58689EA97BBF0D9289 5C89104BA9DF1B7CF21E37B127DBA2FE4767C069B7D0C35054ED1EF5660AC835 1E65E3F2F1A1BB877B1F1E22837B971631C96892873A773D30B6E3B233712F1E C9BD02153905767F94643BE1FAF193C28AC39DC43DB9414E55325098DC83D0CD 29E72C7491193DEE87F71E2FD76A13C0BCCD236471A3B45B4CAD2EAE562AD4D4 155205E8421F8D6AB94614344CFB76ABE6D4EB6A55AB0F47745D29D44B9BEE3D 90D9ACBAB698D9B8D8BAA2C3B52709C233A3026785B45A2768E32C406B528F0C C67ABEB6ACCD97DCBCB71AA0A73E32701EB430B7CA9977C3CE81100A3D23A636 47A6D8D0641CFFE937931F5D1DC5B31C93556F11275CC88270E1E5C5C8205700 1CDCDE3F16ACFD78D2670DE753D87C26CA60C54B2DE02AF114C369490EEC92C4 E0BEEDFEF38327EFA5E99A1BBC54719EB1E102109041A5F638C72E552826FF02 1F0CCAE2B2B148A30459E565A77236D59E8E5EE0AB87F21336FC06EE7CBE5CDD CD42B58CFCA0B1B5B553FA95DC322693A10FCA65079EAD39172DF3ACDA9C6A19 596AC1AB85AA5648A6A940A3CAAB556A5628B695AC670ECE49E969B486C3044C FBC5EE60FAF6E0F06A148EA2DCD5D1CCC036C98556E5190E8F33B9C055693777 257A87B277B2D94134D156CE101C6DF92F9D683FE7394B692A26B1C076C7425B B369A7178792BCDF1D3E4A622580F4051A670510BDA9827F40544124A60287A4 10BB882BF95C6568B15AE9E5C30BBEFB5F9DBCF4A2E17325E0F341B73B096762 5BC8B7417257C4CDD26CC7007846C795837876D66BD3DDF1BF402385E25159B6 4CE7B7FCF65748A55126C24C0250F8058B09DD03F634731ECB512675800A2B26 72637526C0C6B8FF4ADBBF63F3F78DF4FC8A75CC47ADD73FD7F8CCD7F4A292E3 7C30750AB52ED2CEDBDF96021EFFF5AFE5C92CFADE5F183B8FF9C73F6BBEFC05 ACE3A018B669C6CBB4440635140C1255C5A01EE5A3A5A439D3C69C8E8B5393E9 99EE61D9BD5F0E66D6B1677B830E487B8B81DBDF3954BC8DD4AB1CF445194319 AB07AD48B9238DC9CDC7691CB72E9DC85C80D5170A517CED6E7175BB6C07EEE5 D57243DFAB5025AB092AC150556A4C8F4BEB02B32C0147B490F32C6FED37A60D 2DB112AADA32498FC3F35CD51B313BC8C35ECE0B5F6632CEA75DAE887BE7C1DD F5132B68B55116038852A67447EA4EDEDDF65BAEB5EA215B89CA29E2AA246885 A455D79827DD28385613460C134CCA603E6A9945602A89F4A266F27E1647E3C6 CBAE50CCEAA13FB91BFB17707264608E7CF843B3BC8B153153F58129FCF48B95 8F57D05AC15868E04A32E0BB0F0E4FAD1F495A2C9D96F07EEAB7093A02BAF7FA 6ED272D79BBBFDFB75E4556AAD4EBC6D7CA70568CC807ADC765A38515AA62253 CC565335B595656A404009AD527D5A4A942294E5B89C99AF9DA8FFFEA7F2AA9E 1BC27A145F5FF0526CC0948DAC996952F70336FAC677B19FD81B1EE40A9F728A ECE2261A2B207CC54F9723C5DD4DE4EA8AD1C5831FF42CDF09BEBC1A350ED53B 777125EFCCEEFD6CFBB9AFFE267B21D787730AE9D0BCD37F6EDF27F424BB36A6 9D77EACDDD6911A073273FCD69B07A731E74CE2D6FFC77F0E00FDAD586A70754 B99576051B1435C3D21B0AC0422D8042A9C8C2521A54A907A6D4351A8A59F0FA 86FBD935518F533675613BFB791CFEBF8FFC69993925E7F3FE67AE2580A52FDB 15DEE58A14B32211825935CFAAFAA26062921A4DE7904D7C1928C49BB0BE7722 20C41A6D4D8045163E77AC68C66A1159180805726F3396170BCF2F1FDCDFAAB9 0BEEB235C6036C8292AB1564BA68A17775971FE68B97DA700DE55E0AF4542B9A CF56E8761781756C9ABE232516BC6EEE990FD65EB9084D3B01639B20790D4DAE 0E9B973DB6364619368A2AD7B170AA6C6A8DA7B5FE3C050773A27E35078995BA 7CCBDAB9FA78E144137F5C3132A43B30D507D1EED2280549890B57AD9277D2F4 AE0213609EAF2EFEA373E512E6DA6793285EA85E88D03D9B02A443F8A863EEE2 BDEBBB769D38CFD5114A4CAE4A7235435EEFFA93A54AC55C25033BC2C4AD4EFD FECDEDEA5ACB68BA617FC0835AEDF9B31C460A69D4C65020935A191369353486 3FDFF24C9892D85C6ADB2BA785B1C069A0E5B97A12F0A933941E4F9ACF6EA90D 52A477F764C5A04B0D4E54C53149493580F1486DD1F1EE5D848BCA52332EF2E2 E14F14ACE01C10572DB7594E3CAB751EB8C7015A527F762923DD0E231BE57C50 023E1DF09A63E1FC74146870D4F18E3ABD4FFD1DE6500167216792A4E13BEF0F FEEC3B0B07E9342B40A38658E965C2D40EF79CB03C46C675A5750E8681D93888 79C5F78E17F10A63C4358943AD3821198C9931C2202FA2BE41AF40F31BDB9DC7 223B52359E6F908BD45E4E9D8C93DB28DB73CB93A9FDA69F6E1F76CEE0BA6910 04F8A740E5F91C2B765BAD7B2B25BD3BEDBEE987316B3CEE76B86961C3B97E78 A8FD0C8138E1D997AAFE59DF5EAF9A0D0379A0749524C98AD292B3A6C103CB75 2ADC71A7B6671A7E10635A004E615816F5FEC12C4E7F1CA6FFE6C1F67B7B8330 152D028ED86E8DD8B1949D24E4455103A0E6D8FADA2F02DB32B9057847297D80 17941C52EBC8E60B15FC99C5FA97DB474E9B0EE25164009DD19ECB38556B9F6D 8D467E7D613889B64793D4B77B79B2DF9F3CCA50FC34DD4EF114C5A40C7052A8 2A87D6576A1736975E0EEAB5528430C7BBF1613F3C44D6BB22BF56C43D9E2E7A 7E352B36BD6ABFD713819FB8CE8D87BB2667ED8B97AF6EDDFFFCC2FAAB02AEC8 DC25AC8A71850BA86D299DBD440E8171C38A59912B9498F14CAEB54CD3A83D7E F2426BF1C097D7F0B8BD6CAE7AF4F8858B1BBFF5B572F9784FC8EEC3F79BBBEF 7B93CEE3C1A8FDCAA7DB274F4FAFBE133D7CB070E2C4FE6CDA3AF5327416B7EF BD1754EDF6EA516936737DB99D134B953A46A0A29D6AD91982E5A563D3D4D493 787452766FC94ECF3AF142389D458777978E6E74F7876A1335D7D64AAA0AFE90 6A3B08A1876DA1243938B876C3AADB8D67369518A70A64C3627CED617CFFA0BE DAB05F5ECD168D52B116C5DACA58DB55964DE01DE776557BCD09AE135FA5760A 9C3B02A8ADA1539B757F62C9292A249F6493FD241DFB79A6107DB43FA9B80B7C 7F301BCDDA97CF72DCC56E1216D0608DF2DE341A751A67D791D20CDAFBB9B471 C0D258DB8E8630DC9DD48ED65237314A93167E89A5C023912B5569C0D2A091D5 7B6FA74445FBA5230092E993F0B0F7A47DAE66B6A8B9EB4EBECFF2C70878A434 403149375E6A83CB09031D9A7A5CE0BDECB0FDC172F6D2D4A4BE79C7EF87BBD6 59E0F3D6E05A64AE406B8125DBACB6B01C2E4D9C6FA15E7F8691AF3479920BA6 67E4E60EB0588F75AACD6F228570C44585AAE19800AB1493327C0A84853E1A55 40A8951AD7328DAAE7382113971AF2CDFEF4DFFEB4BA691501570201C1C2C04E 71878CEE8E5B9F08583B44C202C02C04F73267F2B3693661AD2F2D8747C70A56 5DB6DEFBE0495F84E7BEFEAB7930A1DA97A39CCFA6EA0F36B720D2A786F3384B A4E798A0DAE9DA29AED4A157DACB48E7AE3BE75736FF199CFED131AA87FD289F C9B4C360041DAC0AA62864996BE70AF5A1B9A9571A0C90ABC47CB73E59FAB567 C9994A863AC851056B2DFD9B6EF8FD278EE26B064292E8597A29896D9ADADDBB 280C9920EE22AC5BBB6A266D56263B0735EAC5384E74AE712B19847445075F88 09EE1F460B2FADDBE7DD42917898E2828187F0E0CD7EA351A5C783837BF7DAF5 366990DC8D39609C4BCFF4F243D6B973B8D46CFA27AB85DABE8E52DED02C14D7 269A0358AA64E63A3F54296264A39F93E15A7FE1D23120AD5C868A57E23B7074 65523F61A39305CF0A55CFE6ED8E59F9D4DD503D54C80D060133D5FF5233F1C3 0ABF460EEF6C2FBCB6CC364666A9081A994B4EEDAF96E24C11067BE6A46FA5D1 16CB02E9BFBE56FFEA49519F5FA5EB03133D17A53DC289A29F7D79FF09D9A5BB 1FEC54D63DE78C1B9633DF0D08AAA513D9DDE9AD6C34A8310C6B304315EB7EE9 765278792D32676C3F368EACB81B6DDD10064D823C4C7092ECA9EDC7B742EB90 019B172D68B4574DEF98404DA11E8628C83C060968C31FA3D482D440329E751F 281D8CEB8EAC3A420FB753A0677CD47F90C26438DCBB6F352DB7DD9CF54760FF 4D9F2E177169FABC1063102CD385E724DD8470415FC1825007B3C8A65E86DAD1 08CF2D21E72632F3633A3DB4A3CD48E6E9018A3017043A4604BBCEDECEE15FFD 5D7AE551DA89AA56D3356DC57AB086404E4BC0F224A5742B478F065369FAFBDD F85863719D274E3CF502CF750DB348518E0B61C68C6EA3FE949631AEFEA01B7F 6BD2E90171B44E5E0F1A2F0BDF4ED1552BBF5613453473B0338B92EE343C7EEC 18EA4F4E94F4C56A73554A2F8B1B8E416CA488E54F5C679A6421175151A8D5AC 7E9053A497169AC720ADEAAFA22822C62695145B109B4135AC5A916358C45412 D8A4C4559AA81B81BC8CC7D3D92C8C45F9FD8383BF1A0D7E1A31D3345FF01477 779B79A22841AC21CA9E029A42B48FD9B4CC61940BC5DC280A88B900E992ADE4 BE98C8244A6734CF372B8D1757975E0850229822E381699B3A104032519AA633 4EF33BA35EE2DA96E98E06D39F6297C56105D01AA5994C5D8F3CDF6AAD2A9EC1 0A573D050CD2C9783A9944539264F08E043FC3E5FB83DE62BDAECD3A0CD9CCB9 B91F561BED9F27D31FC6A33FB55EB87961E16F6EFEFC578DC6A7A8493D166761 5B5A1E36A16B8D87230A6D7DB88A63A65E080287C3D85F6EAFD45CFCE8C9856A 3BAEE277C1BE58A247EAB573D5C5E3AF3C6B6E9E96474EC92A0687B7D1BD875B 196E7EF2A56AB83BFEE6B761F34CF50B5F9EFEFCDB15A70DDA67E2DEFB3CDEEF EE8FD62FBC4E1BEBB963A8756A114A39903A375EE14F019069E694415BD2100C 6EE4DD03EFE48BE92849766E36CF1DED8E0B312D969796CA9A919623231B90B2 90284B6969AADDB83BDCBD777BE1B9A3B415200115B112D04CBF7B9D3FEAF897 37D1C75622A520F3829690104715146037A1DB46280050274A418502BA8355FB 2249F0D41B51B765685718398BA7FB3C3DF4D5AFA66870AF535D5B5745FDE1FB B7FF3FA6DE33D8B2EC3A0FDBE9E470E3BB2FBFD7EFBD4ED333DD33DD339800CC 201000854083044980840A94299954A9542A972CC992FFD855F61FFFF00FFF71 956455892591166DAB28069022001279800998DC39BF9C6EBEF7E4B3F73EDB6B DF66599AEAEAEAE99977C3D96BAFF57D7BAFF57D4B9B9BCE0603080729194F3C 16F1C9EE6E2D0CE9529DB304EA19D5D6E79916698859BC37A96D36D320867203 9988E8DEFD0C978865966EC454BACF3FFE10389D517BB19DB17EEFE6C038313A CF36C55C5E6EA3C177A35036B459D8B80CCEB8C62F906CAE4FB963555E6116C3 1F26B525D36C424AB22747137868CB67CF46C38938E93797E662A3988AB4D3E9 D00751F76E24E28681AD42F76C0157304AC125CA9136EC354CAA471C5D546287 EAC10629262A363F79B6F95FFFFF85502709AEF5D529C36A42061E61FC7B47D1 77DE695F0C633B6540D23037A853DE65FD7BA3C54F846831C725E35ADB1DB9B2 31FED974B8DB5FFAC24275250310601FAF3F7AEFFEFC97169D57E78A423AB076 B3A90E0DC5352E9935C9CC9238A9C84C064195BA934BB7856A17560599CA45DE E5F5B5FF1597FFC3A592172675927E5676852B1C6D7C89AB02D89DF62236989E 1691C0107DEC1F9647E4457FF94B97499D726B5CA0C84F57E23FD8493FEC7AAE 55E86E148800C80FDAB9B804C4822AD3A49C672474AC9ACB2A958DA7954DA1D6 88A20CDCD664529210301FB691DA7FDCB3563BF39FD92CBC0C5E084B21475975 5D1EDD38D9BC7C3953835EF7686575A5B2612B8B4268F35C8BDA7B770F59C9D6 CF2F4151CDCC5442D552D412A66670909F4D48A8BC84C4CC1CED79FB1351BE44 EDB3735561542A073A4F76D0F8FDC86D33E7B2CD8B8981025C01994CB5FFA706 133ABE4D6076A505553075D2E6A4297EA606C7FDCE575622E7C8D64274545680 30002BD2D2282BAB72FB7EF6539E1D96A376BEF0EB5782CFAF4A7726E12D6687 2640B5A9A9A072C6A7D5DD1D7A603CBAB1BBF26CC75AC2B94BB9EF04792D7A30 89CBAC732EAC540F7B665ED5066F9DAECCADE20B6E8F0C9CD4F33796F4411CB3 741A60968979150F6822A2DB5D8784531699E7EADEC205A4E6150A956EFDCBB4 AF939EE517BA42490F2B8347C7E3FEC356FB22D68AB9A61EF8D3979D84434A53 393DDEEB1F3D686E2D9256303A3875C76F19E6129F0AAB267939323A1755E3D9 0A2F1155C3FA9C41778D53D59885DECC1B606637A10F28B466F26CF4B9D28F53 56FA5E450232772A7897F19FFF59FE273F89FBF10499EBCE7C27821F1023960B 25FD02E122EF1BE83435C7FDAC5FD1BF3CDCDBD838F38BA6DBE90ECCA66F06CC 4E125A42DEB5E3C23AF0E39191034ADDCFC9774F076FE559CAF0D3AEFB39B771 9EBA1383EE9BF2CDF4C01BF06079F166EFC812F49CEE431EAF5AE6AFBA0B4B59 9A9BE942DD3B33E1FD96D6C940BE9FE6B96758B6D2F3B48E4972C191EB54D4B5 8CD0564E66C714433EF60BC24A53AB2519B270D2884E27D1C9204B4592221E95 7F60DADFDADF7D9496679CDAA76BCB172975D4D0F24A0F60638E0A6164CA2EA9 5DDA0AB2B280FD26B89D0BAFAC426A65DA79564C0517840D8126AA72D9A1BFD1 F2571A1D2C35B0653630639B99CC80C76AD3BD74988962411AFC64F27DA080ED A50561041C29DF1001205E6CC14F41AE4E84D94DCB93E9641AEDB26A5F889B9C 7FC48B3E258029D1B01F78EC7874BAD8595489BA7970E2ACAFFF4BF2F45FCD57 7FB8F7E1FA30F9BB73AB4D99ABBA367E9E292D2BCC3990988257FBFA8A31E396 71382A9A9DF6D69CA31EEE754848576A6F573B9310AF359AE74DA3D6A09D90B5 167C72E122DBBA4AEA5BB43597A084DEFEE9E04FFEBC73ED33E5D266EFE63B67 AE7DBC17A5B5E42EA6D183B73F38FBD9AF1F2784DBDED9ABCFEB6BB942289B40 D9C861932AD316B454B6828018DDC87B07DED64B7137CEF7AFCF3D7BA12F9DE8 C1FE4633CC37D72D31C1F13192908800DA62AD8A5F92FCF69D918CE75F389F2B ADDF225D3F7830887F7C1709E17DFC6C75C91BF1D8290C573980820AC330C355 6A2C2B5A286DB842F521182E66DAC04F64E1B4563F835057513A3D54C52EEC52 32B686EFED7AAB8BCE8A77F0E15D392AD63F762E72269E15A0A1AA4C99EF9D4C F7078B979F421ED04AC84FC09D0ABD692746B693781B0D6DCE5001D5D0473744 1AFA9EABC0B800C692112842474E723B411DE15D3248EA4DDE89459E84AF5908 C272CF3DF9EE9E3B716CD80866127CAA81AF1078DA4E663AA59DF332F9691C9C 6F8D167A3534977F50925A15AC1AE26ECE32377F061FC73BF37CC50B647CB3E8 EE10BBB291CC2BCD77E067818F008A5300FF989688AF5C5CCC1821B12500B8C8 FAD4B9C6DFF9F47F510819D7E2FAC0184544C79E22C5B777D21FDF684221F472 262A8680923BF95D3AB8375A7835240BBACE72484B0EB66573FC767972F770E3 8B1D7131A6659DDC6A1DF6871BFFFC4A54DFA1E3C0AE005BD299D18D6E4E7832 B6AC4FAAD54CA0444BC361AE27E400FB10AE57078A44808CA7B6CEFD6F38F967 5BB0CD015224BD9CA6FAC41409594AA9B5D6C89346436D040DCB5D547CD22E56 BE7ED9DCA8C97C5A8595D6A90646F5FBF7F0B1243527177A408D0158D61101A8 197128AA65E1BB8ED9A945F0A7DEA0E30699414665BFE3CE89014ECCD2D90C81 AB4687A73149D73E7FADEA981CC536D4CCA4420768F84697172504477FFB2E71 4963A9C14901D1AE662E65C9382913DE6EB5691D4B7D7550223DE30675C6D4FD 1A545FBD960041305071378F8BEC9DB4F5C525D13149AAEFEA2A19C953317A3F A28AB45F9C2FD529831F146EC54A9D2C669C1F5083C1352D4C8D3431F3F6B451 FCB8488BA2FEA576447A8E30E04DE05969615269E634AF58E59D3626DF8B81A9 ECB67A1BBFF3B2FBB105208D4A11ADDCAD6D57F551973E1F1DEFA3877B6407DF B9B973EED3EB34E478AE39662C189BF98D63A3E5962B9438855BB2B45F8D0EE2 C54B17A515A736778205B311689703D3A3CA81072170EE00367E771B9D64A5EF 96EB356F6B8199679470F5813DACBE9E082340E5B4E5839E9F70CA49968C8F82 00B3E616D23DCD88E8F952132043464A0B28DBF6C3D1E976E3D22AF2ACC976DF 2FDF45B80DF8C47033AD0B5C3B47E79E97AA4321F2813093528F0AAA70D61AF3 37238A68A698FA441D1920A212DA9041B34351E54C1A10580F1F3FF8BDFF47DE DCE159D5682F06A5E1C7404821F7E665250D0062924F148F64303D88FBD4FC8F E9F81827BFD99EFF44AAE7969C399FA453C60997765AB091218FCC7488924854 8F12F45681DF9926854C9F0EEC979ACDA750DD99543FF126BB93D1D46341A3DD DD3EB62C7B617DB1FFF8F18B5EED9736CF56477BC0B2CF07F5964CB4E778E8CD A03D30D34C3B0DFBE6D842C203A8640722B00A2B734EB5CF992462A634A9644E CBC426D5388BBB51713C110323B83D9CFE9F453245F8AA137CCEACBF82E899D0 50A12075E618D448443E29D299D519AD04573C65152C8F8F589DDA9E5FCB6CFB F164B23318F7F3B2B09C3164DD62F4711B3D1B2EB5B1C9A8517A6C6ACAD2357C CF69B71BD2375259061137A6C5011BB6ED9A0B698BEB2660E41A230ED55EA629 4F7A71B117C93EEC697CE296B74CFE7E3A1924796B61B93F1AAE7B3E8457C464 B6D278F7EE8E1755AF2D3DF53BB5E5C74DFBDF3EFAF0E1C9C157B6965EE92C8C BB7D0001ADCA59E2CCB7E9513218A372171277961A96F3B0E0763BB8E25BECC1 A1EBF86AB3F9283DAC055EC3750C35C13563C1CD9AC634B51B85BF197636ECB5 157BA553735D3699267132A4B8BDB282C29A35EE92C7378EDE789DAE6CCC7FF5 370FEEEF0C1EEF3EFBF15781399B2B67B8EF8A7CEABB5656159E50050A2591CE F876DADBF1365F880669B9F341FBB9A72377A1FBC18D2DBB8A9FF998570C7176 A2F0B064253629E14A9394E168FFDECDE6994573A95550ED8318621B3F98643F BC011CC7FEFCB9F13C2139AEE526E28243B2F5E60D67BD3228E41D808F5869D4 3693CFA54277EC73ADDE2B04ADA2243D30D25DED2E9485C99B07C852DE8B4BD9 707CF2E37B2BE7B7C4BAA38FE893A2744A3CCA4F3EDA77EB8DE6D965A985A551 2A879689D0C04E1E66DE7A1D2D14852AD9AC2D95A9507B7500212E4BA13B2B89 6D34CAED68F4B01B366AEED62282A8BB799021D9BC58379A6EF266BF7A47B0CA E99B09DD08973EBD9CD4FB18AA7B04098BA9BBDEFEA383CE734DA3EE8BAECCBA A761CD36DCA5E1C32E6B32B3A94693C1C25C580DC3DEEDA41C008633AA1C320E 13BA61BE04C243894929A47EF4A410128AEC0A18610A8CB0F1773E5536D0DF14 42CCB896C73398CA1373EA499CFCF1DDF29D47F5A7822C10A40010CE0976F23B AC777FB8F089907480B713E488D8882DD592379DC35B3B673ED7A8560B9674F6 DFCA9B9716FC6FD406C65E3069594F4622B488879ADD0AEA412D2D4BA4EFA308 D3765904880A11A2D2A785026A058A29CA57CFBDF27B38FE27672C1644FD3C1B E5AEA4361047494AA85F1492A3A0049B9232C1A4C58FE924FC85B5CE2F5EAC74 D6033EC54DE6E6DF7A50FCF9B62DEB65E8222DF6A2CFC6B499A43E3BD70AEA05 ECFA9505CCE5F0E4B4B5BC10E7D3A23F6E2C77E26926125E3FD3462E2947FCE8 7867F3B35BD6D38BBCC82A6D6B989B89535DE7C76F1E36CED5ECD0DBBE7D7F09 92FB1C9969DF4391C38092A7A3B8D56A52870196D76CD82033E11F4C7547996E 4E1288EB142F99899DC1E9881F560B5FDACCDDC2C84DAA8F14A272944DAEA7BC 2F565E3E239C2E503BA30C34C2038AA3BB1B4DD813A4D253CF052DB94582A1DF FF51DF702DEF352F373240F2448A123E12320D611418322665DBFEE82FA7AEED EE9E196CFEA357CCCDA61609865AA00780F59C67815D02E9F3E421DA3B5277CB 073BBD8DCFAED336E0144F39ADFC284AB60FE7CFAF4656CA3CD38AC9F8FA8EBD D8616B4D8061BEEFABB916AC2087F526AE8D2C5115C850F8709CBD71D737DD62 39A82EAEA14693F1B3B04D912815C01CD3D48B0FAB52E6A60DE0331D1DEE7B9E E334EB8A352B08526D214889B6365100CC6C5C8ADB37CB6CE05F39038023BD7F 6AA2F7B90C0C6A53166146536BDD59FA84500D880CF81F046C7F8299B4919641 7F322BA147092B0D5894062552BBEECCDA5667E8C24EE9FE69F9676F3CFCE97B 5199370D770DF928CF134074B0A52228AC2A665AC88095722AC3C3D3A867DAEF 20B92FE3ADAAF8A2556F0EB3F67C2D47892928F0F582A328134796EA07729246 69491F56F6EB71723D19019C3C1FDA9FA1ED4B99F36E201F5BC5ADFEE15CBD5D 0B1B8FEF3DDEAACFD98EB5D3DF7BA1DEFE9DF9B3E1699FBBE89CC16C605ABA31 1CC32EC096CA51A9076DF5B03A29A302888481CC9135B2A10016DA5D059899AD 8FAAE484570FC6D3FD021F33F7FD52FC68D48B05BF1A7A5FAE373F56B3565CDC B1A8C385ACAAC22225D527F85A505449789B4A5FE443D552AE02B2A8A5262BD3 1D0125C0F6DD93FEC12051D4C9AA0CD3F469165C72432D155AE5A54F22AB7283 30741A2690EAD093850AB512F249AE9B31045586278DD164B437ED47A3A93C89 E2B2EA52524AE273F384B03B6274BF18B71A4D344E2183D71A359272F8D77786 471FC5D1B5B9CE7389FBF946D0EA9CF9C1F6E37F7F7A3B59665716DB5713FBCB 0B97D75010967CD83DDC57933BD5F05EC53B5CFBA5FC34396D2C34BEE4B68207 C75960A8ADB9FEFEEE0BEDE5D585664E4607814891B024AF31ECC992C884BA76 E2D4BDF5A7D4C2F2FCE54BDE5A4734BCE9D136BFFEA1DA3D193EDC3FFBA5AF9A 1F7F7978F38387DFFB4FCF5D389F2FACB22B2F567EDBCA0A54E4B95F050570FA B912917078BBE86F9B5B2F44E34CEEBCDF78FA521900BFFC60393F4E5EF8BC95 75A9EC29322EAB4CEB580340941C6559F268273BED2FBE7C256E5A264F286493 D4C0D74FBAEFDF729E6ABBAF6C64506263601C14606F4E5CC759947E8B481BC8 1906DAA2D2997F30933AFB95B3835260185112EF59D343EE6240B0F93B7D9E64 E1A796B192C3BF7A04D8A4FE89CD9C0C4D5E084B2161E2C3ECDEEDED8D8B67BD 561D5250569D22A69C7138BD97BB0B015B07041A11A9805E02FDD73458DB87C6 5085AB0476A08034C7F6D8F09DA1B5EAF8CFD938E3F1F502487FEB52DD091792 EF1F678F4BE59A995FAD7E721D2D259C9E54104E4980A85B6ECBD18341E7DA02 D41EF1782A8E72E7C252518AE47E3CBF3E370C7655845BCDF57427E9DD3AB54B D7559ED6B4D685B02AA510B0090831197381D659DA38E03F17C2DFFA5409194B 4292D04DFC5CDB57692FF6D48CDCB29AFCE147F8DE897F31C84281B3C2D6C2FF 4E7A970CEE4FE63F11AA8E64B9454C3EB6068ED166F7FCEDF7EF2EBFD6725782 6CDFDD7BD83BF7DB2FC8CD714CB41795A1CFA80D7D5BAB2FB5E46C7019D6026B 4B044598802C442B6DA732530ED7B213489C14F1A8F9F257FE0C67FF6C83617F 7C92F371E1112DEAAC84B6FA2E34D22D344790262BACA9E8E2E783E0AB4FE1F5 1A2D0A839191A81AA236F8BD9FFAEF0C14694D4C430B9DCA598304D33041216E 39166D05C2A1D16054B75C88F771345D6DB4B3313F29FAC186EF189E35754FFB 5DF729B7F9D222C02955F1CA1222CE8DBE11FD742A7644F3A57030ECE7837CE9 FCA26CE550D489248492422BBF31B7E94136E4B6B6D8861A849EA45D6376C8C7 A0FE4251330C61037139797860BBF5FAAB0B298D6D6E93025768C29334BA57C6 0F8B332F6C88B941C933A7A84BDD751A11E0CE32905A612783C89700270C070F CC939F41459FA3175465033C308007142C27CA34B9054F0C9B46FC4E257FAA9D 77F9E7ACB9DFBD821A904D997CE2CE0E9B0EF813F60DE00FBB37D8DE6972238A A539F789965EF2C2C33CECEF1CC39FE69742407ACCACF15E36DDDD6B5F5E4B03 C2ACD0F25AAA65E82B3765736572937011D5384B7F7C4F1D8E9C650F3DBD44D6 CE14B4C6F2670819101A2B2E80244BADF60FAC54EB37A6BDEDAC98D417572964 21E4403A067464432DE7A69252FB85556972F73A35B87D7145A585BA3350F607 B9F0B505118B3133B8F794B1F0B29001AB74AFB21EDB218A098842FB89570E22 BA574D1FB2CF26E8B57CB83E1017BA9F0C0AE4839F1F7DFBFBEAC668B83F315C AFEDB8012F384F72A8E8889A2936394D24441EE012312ADDC3ACBA9124EF27D9 F2FAEAD2B877B9221E975EDDB2A860B9163DCE65910B7BC0EC2EAD46F91450DC 88A31B08BD5EC677D32915D533AE73B9357F621869554688EFF64EDACDB90676 7AFB27EEEA3C7769B6BDFDAA59FFFCEA26298B9AECCE79B586E34200F7F32833 98964783D295E61E33F2386616E054A0E6F605335C46AC222A536232C9FB8978 3CC846C23840E4A653FD7C749AA5E52F85DE2F2E2D5CB38D798D348585985700 4537726776CFA3B89E553514077EA12CD87E062F2C3D500DE49C4179AC385324 384EC58D93DE715666869563838AACE9985B8EDDC94A4314A43E53B5024EE206 713BE486EDD98E3EA2C59570AC2AAB703FAE86D37432247AC44A23D90963534A 32A5DE43CE607FD7F0993BEF4DBBDDA7EA2B629811DB3FA88A77BA87D2A52F75 E6CF67D6CB8EBADABABC93A0FFF1FE0F3F34E38FD7C2FFFDC55F5E9B92A9C876 4707513E9ED0F47131CC325233DA3B55F19DF1FEC75617FFA177C63EEC1E3584 B1DA1E5FDFDE70DCF39BED26A9064D56050D2C4DAD48230790B34DE0BA044FA9 5785F3AC16D8736EFBD2456F65A182C54B8BE9307197CFF547233CDC4E0E6F2E AD2FFBAF7E41998B9878A8CA38CF728705C9380F97F3CAA8F76F8BEE6376F6DA 24CDD5EE87F58D73A2717EFCE046FBF446F6F1AFB26A484517C9518153884943 107DCBE2127A3818BDF161B0B1CC9F5E2668EC0032E48037ADE31F5F2F0F4F97 5F394BCED6B9E496F6248728429E11F0C606A95CA69DF8728492995D8621017E C34B6A2F00C8C6D3287AEC8E27DCCF1580EC3B3C1F64EE0B2D00C5D93BD3F1DD C1FC2F9E2F5A235C460CA8147128778EAFEF624CE7D716B05594665FA0D28D9A E3EBB90DD17E81293546BAC3C7244FD42A98E410421C1BA5214B5E14A9A37CD2 25C0DB3BCBCDE0724D95E4E8BDBE9AE2D6D9B6631A27DF3D207D3B6BA4CD97C3 E07C4BB149614F8DBC1917C3A008A25B4926B2852B1D29E5600FB23A9E9F5F8D F62648097F99ED4ECB859A637334BE394AF681A40554FB3E18A59E4AD6E22B5A 1D99180160334B4F9538AAFA9B42F8CD4F966DC87CB3420891ABD13135549219 130B38C8EFBF6F1F26FE793BF139CE4A47DFB83AC95D3A783459FC789D2FE446 EA318247CEA9E7F9F4A6F9F8C307673EB361D63ABDB7C674D568FEBD33058BAA 143213815C84354C61951604071429F55D2051C09CF4C270CD08850DC856EAA6 76787E31D0F5A448165FFBF5BFC4D93FDDE099910E2B1115C16C824C965A98AC D4ADA705A3CA849D9B30A39E9BDF7C8E7FCC89A90C4AC5CB4C85EDE4CE34FFFD 37967765459BA7843A2477E00B42F0941942C26E79662B80A4D73D3995BE6504 5E79DC5D0E5A8543E29D8CAC5BF956E28F5C764773B0E0D736B11B41E1523853 2E02F491DE1A476F458DA25D9E8DF68E0EB6E6CEBBEBF58C1D318BCA58518BC9 4A9A9687A9100E7C0348E100D2993EC862DA14B6C0BA2D598B0021CB142E11EE E1EDEDFAE68A7BA591E2A92B5D04B98D4415CF92077CF851BA71F50C5F1D9565 E4E64D09DF020F2914425E57CACA69423585C6B872E480F53EEC2F9D5F2F3A31 2CAC0B3441F19CC6B07C967091C50536BADF9F36EECE45F9A4F1DF9C21BFB981 81816B5105DD5589913E9D2C95674239DCBE6EEE9D8C3F1C7973EBD68B7EE24E 4C32C7EE2607DDDEDC33F310F1B3A6E1C660FBC8B12B6FAB2E01F0788B955B2F DDC4443681E28F9DA10B2F9C5AEFEDC91F6CD76B3579B96E5C9A47F5E53CF599 7801D35D6A455AF846598A5965C15D3710FD9351EF4163C13783B94AFA840600 EC125659D2700BAA7DD698C032CA1EDD364282576A729CB18751E57E984B4F2A F8E8B9428CCD7F4C359FAF9447B566297D52082106915EBC99F320D1D3C6529F 4D548C682D23580CACBB10ACEDBBF7F8B7FE437EE75E34A14DD19A17BEE31923 DC4724F7844ED23981AF66B07119A812A0F59407C30CBF391DFDF568B06407DF AC2F84FD6E31E7947EB58EA933058E6924559C283F96C150A88448544632CF0E 1CF32DC7FA28C94E7BA706E30B9B1DA30A3A533D47F2B81C27A7E3A717D60FA9 BC333E59B2FD33ADD6E9F068B1905F9BBFB44AEF9B1545C02B999D63AB9BCBA3 54A676D02F0B270C46938161EAF392B0429FF617AF1197A2A2C7B387C9F43EA6 FDCA3169ED9E48BE9DEE18147DA9B6F4B717E79E69048D6C52D737B5380542C7 743205C669C8C29AE9CE416572387524F0318EAB9240A1A5628A7926A45FD92C 26CA0A6E15C9EB83A38930EAD5CA8957EC64DD39443FEE34CF306B5A4C4D9336 B40D62D527C5208DE228B90E299F03FC450E42EDB0BE82ED95821ABED587B0CA 8A05D8F59679DF16FF6A3CBEA4E87AE0DC1AEC35CEB5EB27F9B991231CFF0FA3 ED135B0512BD42FDADA0F1AC597CB279357617FEF18DEFF4ABE47FDE78E56BC6 726EE1EF0DEFDEA5C3C22EA52A8199AD8DFD08B9DF95A31FA4275F5D5CFCC76C 838E47B76B13B7DDC0BB93203056979C8D69456B96412C208EB269F5022BE2A5 5D8E2D34E502E114D5CBC40596E4340F6BCDE9566BFED5ABC1C58B16C0C7DE18 D5917AF8B39F7EF4C18B5FF82DABF35CF7C1E3478FDF597B66D33BF38C333911 CD334965354F6FC9D307D6D32F4FCA126D7F585BDDE4B5B3D9DE3D6FEF8DE2D5 BF6DB288E62788F71223D7F6C8C0C0119A5AA2964BFEF6FD3899D63E7B6D8A4E EBC22C8A52D65BC6419AFCF5FB569D3A9FDC4CA10C72A0634126615528AF5F24 F0A9B4D068362B8444BB57CDEE0B016E522D60124D270FBC484A770275373CB2 D2BD889EF7ACD02EAFF3E39FDC6F7E72D9BD4ACB746CE55ACC4B091315FEF19D FB41DD0B966015868216F6B8DD7B676A78A4F68C8349A4C7C121FD69612DC04E D5CCCB46A2A23073605934A589E0457DBC16FDE0F8E4525C7FD16EE5E7D0EB6A 7B74BD75D9A96F37B3378B41D02DAFA46B579F6106205AC042D828721E4D59E1 E40F0BD84EEEB5DA484E8B5BD1B2BFC69BE468E7C18ABD329A0F507AD0AA79F8 900E3E88791FAA3163CC29F44832AF48AE3B5288E942099A1542BBAAA628365E 3BD7FCAD4FF13681EDCF6685906B7D45ED3893D19139CDFB7FF0BE3790DE9631 B5325A7047EBC138F13D3A7C3459FA44239F4FAC3C341024BA031B0ADC757CF4 F064EBB397A4B5D2FDEBDDC61716F0671369BA7636C7CD88696A4E84F6C1D547 2B9A91CF0A614935B3615C8FD34321D4679D8CA14A6627DDFC30B5E8854F7CF5 5B38FB274F4F7B391D91B0842A22A626CF6DDD941C629C28CD54A9A4FE801CFE 93FAB9679FD106CA552580D752D89CA8FB1FDE09DF1CBBC55CDF90795D060560 774BE82949ACE6CB702E3052F768F7B0B654D794BE1FD5365C887C719B1B2D3C 5EAF1C7B29D8A1F9603FF8FADC782365A9E7670D6589524DE841856EA2E9CD51 C3EEA4A63CC1C7CBD79A3448052F097209B1F474A09523A2A584B5A69C01CFD6 64243348AAB057E210880AAD606D646EE9832CFAC82577DCD1EF8EB1B1E0CAD2 92D35290D86C1ABD69B0CF7B6F1DB79ED95467B535A9211758C98193417AD5ED AE525468C829A003C716C1E4E1703C4CD7AFADC4C12E9ECCBB1A7D649C687914 9E4666AD19F750FFC7DDC6918397C2F0EF3F9BBEC42B6A1A523717310E051CE8 945922BF9239DEBB6DDDD93B79FBA4F5DC65F5B9C563B3B718B5A77F71109826 7BD9EE8AA3865C61FB4E77776FE9C55612C699EB07ED4BD4080B15999562681E D873619E3A834AFDD161D1EFF5AE45F62B579ACE27296AA6E6D4E558228B00D2 CE07D8A45201BF8230194EF76EAA4687B5CF5BB8C18090E0AC2296769697136D D24B7DA598111DF7B7AFB7CFC222F9FCF881717C1BA07795F4A92394ED96AC65 B49E25F5A72B484B7A9E73D61FA09986ADA767B49C917657C294009FC900FF99 36FC1642393E7C247EFE7D75FBEDE97D343ED654D26B04402F211368B32B0AA0 D830CBC22812D853C07731D787FD8900803A7D5018FF26C91ECAF8B7E7DB5FCA 9925C2C434E6EA82C85E2A1308709AA903621C386E318BE404C84696908C6C97 E82D141F66F16B1736FD0C3FC812EE87A922B71F3F04C8FECCFA4A59E40F8E7B 81635C9EDFEC9D76FB8A5FADC933F579324DE175009D559E1517599615067323 A8E5CCE6B96CD8F5D3747FC90880CEA62E3951714D90D588A5CCFA361A3D984E D738FD0781F36B2B2B8BDE2453190E42CED52C5D0074603633202F10934D991C E4B1966F627EA15B799516EACFF380576DCC1AA6C539103D45993121D5EDB47F 3B490EF4CC0CA03EA75FF201E04037E8D8F59A697362DC8E46774472271A2251 20C1F4399E145A0B127E37CDF966B3A6D0F3C8FF38AAB9187FA8FADF1B3FFE54 DEE86FCCDFCB0E9FC1CE99B19AC01ED858FAE1CE76570AC97496DDF2C20BCABA 66F27F686C99F5D63FEB7D3894F87FBAF8AA5BC37F36BE63ED8C7E316F0E2C7E CFC3669F1E5BD3479CFC71D43D41D1AF2C2EFCB7AAE148F1C82A964C37182407 81F22FCE5F8ECA00705308B019BE059DA98D54B3D1537D9A0E1C4837CE564213 872A33AB82326A359AECE2167EFE39F3FCB92344FA69BEDE9CAB4D93DD3FFDD6 7C929320343EF172F7F5EF345EFA8CBA724D9E7E808E6EB9CFBE721817E5DE8D 8D8DF3D25AA359367AF707DECB5FC05E9E14C7663176B5B9BDBEC401E82C502E 2AAEA2227AF75167F1A9F155C31EC7C04E944B4A5E8D6EECE7770E979FBF6A6C D647680C28C8930C892A732F59C61C51819AB1C0990F175318F2520E01AC7161 5524834776F9885BFAD6C51D907CBFCF36C2744EB95DD1FBE37B4115F87FEB12 5FC92407A6264A028CCF327AE1F0C3A3F5AB0B49ABEFC12AF66BA30F86799A2F BCB881FC44028D17100F16B1ACD9742E7C894294B93E5AD0DE888C566699F37C ACF29F20FF9CE55E4305C9E447627AABDF3CDB193CCC83074B4E1DB15F9A96E7 806D87CACFADA91355A3D28CED232F7B3B6F6E76D826CEC763C0CCF5A57A3994 64DBAE6F365590C65E02515BDEE3E9FB4933092D494A3D060F45DCCCB0C84919 22015580122BE028AA22F2A9B5C6DFFF340F2BDD925931039BFA524070CB9438 9FA8DE64EFFFFDF69C1DFA8D86C05056AA120DECCACE6E99D3E36CE1D5A00C07 56E14224E4B5C2E0EDE2C734EE9F2CFE72238A878347C6DA377EA1BFBA0D0C63 AE9C53B0C534D5F81B49632D6F40C94CC84A3D99E87A726523314D586E198E75 A2D09D1D589FC9C2C5AB5FFC0E16FFE84A74382C0B60513E3C49B72C5CC0A166 951A86B65AACD4040F5AD796AC5FDF341A8D2A05380BA9AD70ED7AFC6EFFF0DF 7FB038F61C6665552E75A6A7494AD2766C75C83C5EA946AACF8FAC868D134BEB F774ACD00C478F7B9597D355E25A0D72484EBB83F6A7CE18CF1A051B1B9C3111 0AACF2E8881C24D9CF113E727C879D88B177D60F36CCCA8A755FC84CFE4D2B39 4041A15AAF0780754599BEA5A6DA815821E0364C30C01D954970C50AEA38DD37 C7F5D339F90FB1287D5315968A3937721CB069EAEC64BDB74EE72E6DF0F34929 274E314FAAFC498F2796FA485BAAA4A0B1492CB3583CFDE0A832F9E295664147 C5C4730D0CA880EB39F54A8AC4731AE9BDAAF7D6C82E8CE6F38BC66F5DCB5613 9DC3B84F801791441FA154A6D04AC189BC7B8FDD3CD97E7072F6CBAFCA4D23B7 4BB3CF4EBEBFB37A66A55C4C739A86D57CF7BDAEEF39EE537E6CC6C2ABD55A1B 50DB6637B6FAC8445966897B06D4E63F7A4888F4BFBA2237962CF534C6ADD205 8488058016782BA0A1DA08921A5539DDBFA558112E6E29675914CC44909681F9 5A8090A88C106C5CECC25F41180EF66EB4CEAC55AECB8F1F1BC777B9BEEC838C 9C594158D0A674CEBA2B2F0814EA3B4FDD8903FF190AA1A53D28A5804CA13D28 142EF5AC08AC91B4CB51F6F0EEF0DDF7933B3B78148BAEE5A85ADD72B5B05E51 20253DC518E43F8B4E2D840AD892DA0A55FB5F136754C989146F9E4EBFD54D1A 4B4B9F75C9B584ABD28A02ABDD228DB8EBA478AC3A12A5B1C82400DA8AED18E2 4D231912D6E61D0B8577A72747E39DCF7EECD9602CBF1F9F6E0B00DE0E2CF1F6 F43416F999CE5C60DA83D15409B9B1B23C1E8DCC189220E9788116F525D5C1A4 874277CC3976DD619452C7EB0E466167CE1F89656AAC32E5E4B16798B9E5DCC5 EA5E3CA986D3174CEF2BE797AFD5DDD5224FF4F927A9225594A427D5C02645E8 F4B30993A2832DA790495E4C893EDB77A87592E6DB3C4B6D5A67C6F36670D5F6 9A3C47B2D4CD6FCC4C313915D5F549749A4EB96529CB99E67C906713247A5C9B E67159D57DDBF77CCECB35624179E9F37C4A1047B89BC62758A602352AB4A49D D0A48371DB7016ADFAB638F53CBC82583ECA78BBF3C1787C7738CA11321D6C94 6AC9B0CECE2F3D5D0C7F25B87461E9FCCFF293BDFDBD5FBBFCCA819AFCBB8FBE F3F2E2F2F92182973D21083ECDF5067E30E5DF8BC62734FDDAEAE23F251D33CD B67DD9765D74D4DFA559EBC2E28B257C53223D0BB02B6614694F1BEDC854E971 754298BED9D6BF74572C575529290070F87AA5E585FEDC5270FE29736B0B6FAC 4331DAD97EA0146C7763C9F0F77FF4BDC5973F6F5D7B7678F4AE353A0CB63E36 194CC64737D62F3F93B9EBAC4C4FDFFECBE6539F31E750297A241BD840DDF4E5 3D00346ED8333DC6428DDE7B502BECF4F3AB2C4A6C5E401A293036233C7CEB0E 6C44FFC5CD91995054B929206D96785B8E354F504D6B9FE242372702FCD6D384 99BE24D2F34849367A6CA5BBB1C115B36A3D1C3F38762FB4B396B226387BA317 ED8DDB57978C4B1E376202EF46694C2D3B72C7B7BAD441FE19C04B318EE9F461 7978FBE4FCB35BF81C11D5104BBDB998EE37D3AD9ADABD0357651A2B5969F5CD 129E97D23286276C78732F9CF3FDCB6D008CD3835EFA7034D75DC6BBF6D8EC99 5F40FED5262F4DDBABB41D7B95A5F92490417E83E32975364CB4549CEE76CD7E BB39BF7238BCD58A6BF6592F62036659D62818BC3561C7A62F1DA465AA440908 46DF8F9AA61CFF9785907DF64CFD773ECD7D0148CFD20D0086D62A1340A66243 94F27177FB8FFF6AA5D1706AA15637C65CE0B12BDDF8264D86E5FCCB3E0F229A 9998C9DC2B6CD918FFA490836CEEF3CB8F763E6CAE5D6EBE7A215B1CA569DC04 444EF45886FACF96964F7C9E615575AF877AA27CACDDD52B6E106DBC72FF041D 9E12650CD4EA677EFB0778F4F575D81C0C3B95E9142550A5C2257A0D15F5D344 262CB55F0A5A5FD920F3ED1CAA258428E5DA6F370AF6FFF51BCE4D4EB1256CE1 AB12E7A5B4DC8959862BAE5977F941CA27D2AE69CD9AEE60505FAB4118C5F752 0544EC9982D7F3FA710D3D28B3F3AEF1D5B5C4CCBC6C56B420FC635E0D27E5CE 347D57D6D2564227B199AFBDB85ED5B292C45AD0481F7D9ADA1199012ED23A02 500A15440D9BE8B65CE5610D97CB0C57545A8EBE122D84C48FDF3A39BFF852F2 C50189610F42C98582E41429A569696CC7A7AF1F2E5CDA2C9FCE7314F9D33902 E40269950A4840B460801B0B73A4ED9CBA4BDBEFEC2F3F1F92A55C2482704F8B 5902C9AE34AB572C0ACBFAF80749BE43AB76D5FC5BABCE97AF1496BE43A6DAD7 49092B834861B9ADF485F1407D7818BF79DC37F2AD6F7C4CA284627FBA37CA0F A69D67CE95C99EBE6B1DB3E33B87EBCF9C2D6B9C375D16B41971113301F31985 36A192162DF3BE7CEF60F0FD87EDAD79EF572E54619D141B888499C39DC2D0CE B78C1792333D3E8A807CF7BB0F3A6BAB96BF8A708B4BADBDC0A921C9AC31444C A020E5D8D3E13C3E181DDD6E6EAC57965D1E3EB24EEE240C5BC0E6CBC8F28202 D573F34CE3CC8B9CD62B5860F2443F14B080A198F6A3D1DA0EDAE5A2D2233BB8 24FDC3E9DB3F4EEFDDE7C7D3C9495E64B4A11A35CB562A9759EE73D3AECCCA00 E617C343A2C82C20238BDC0556A41D6A2D58F5E32CBB1ECBBFECC656ABF95FAD 759676F6025A4B2C5AABA1B9745A2BC99407B04A009553012FE1EC9BF85B93BD DB694A55D86E2E4FF2118B8EBFF0CC533C91DF49BB3BD4981EC50C3EA6672532 CBE264A9D668B5DAC37EBF90E9D2FAB29B93224E7C89D7837A4858B77B3CC562 CAD428CFC769969A2C122231880FE0D135E62CB290A1ADE6CAE33CFDE9708F55 E26B41EB775BCB573CABA8A6852192D8988CA11A393B881C79F6CDDE51A92908 2FD2C933CDF92DE6ABB84C18314809002232DC5B3CBF9DC173B6CE88EA2AA32F B61AF314A3516A4A83502BAAD021557BF9F8541465056CCA848A7882C4E36868 9B64DDB22FD8DEAAE3B23CB72B927A6614A526B18781F546747A5064C0F1BAE3 C9312FDB8DDAD3766BA3726E4D8FD67C33ACF271321173F3EF8E92BBE34CFBA5 29AE415289363C7F5199AE3BFEADFA4BAF7A9B4ECB9D0E4FE63A8B3F4C0EBFBD FBE6A7DBADD5E33C37BC7D99D6A2E9775AD6E1B0BA9DF31D32FEC6C2FC3FB716 DDA8D8F64AC7B78BEE705B458B1B8BAF720B7238F70D6C403521C8D446844F66 6D34944752014564442BEEEA330683CB242D07B8CAB4427926800AE776C036CF 345FBA26969B68B5432DAB78EF231A06FED92B630BE50737BDB808162E1783D3 61FC60F1E2E502CD99383FFCF0DBB585ABFE8ACDF150A5430B16411B0269A324 28C0BC2AF584DCFDA3E4CE01FEC2F91A3001C87814012570A99FBDFB287BB4DF 7CED52D4D41FCF4B2483445F5F76ED25AAF58BE0C3F3995E04ABD0AC3D6D26AA 8BF8289B3EB2E25E62C9CC64ED3ECD6EEDBB973A794DD094C9874579A85D3C9B D7168A0E52716A3396C20AC1CEEDA9A3BB872B6717490D6062540CADDEF5B4D3 6818976941BA86B4A4E6829008000330053C872155729917DAF058FBDA931208 3D36BCFBE8F48303FBC29CF56C806849E11D7F9E557B500CAA6C2D5FFCF299B8 CD036E284B506A00CB429056064EF63E673E225721051AD59BB61586A38DDDF2 BDCA99677687492A8CD24347FEE0DDB133B560F5A491675551499BA11AC503EE 3D2984782C27EC17B71ABFFD5AE172C0B54C2BAF315D8AA428E851887CF9F6EE FE0F7EB2BADE24405D2A03104F456297FB931B8A67AAFDA2CDCD0C657A1423A7 8983C2D39F4CC238F0AEAEDE3EFCD9D62FBD666D3620CD6120CD0A289B3632D7 9DEA331547CD009FF4A8AB599302FA1B2F38A23901C353113D7C6C6605CDFCA3 FDDAD7FE97B770FF5757F4B09FB0EDB2826A16F9126A4B98313F55033A51AF2D CCFDCAD35998233C47502CD0B0B280322CAA1F0E7ABFFF612B012EAD329B0794 E02467AE5D5E9235B52AB7D33E3D09163CDAB326FDC43E6B9A8199EF4A8887D6 A500B538C979F928C1C4F2BF7436B9A0B2427899C7CCAA02647F1CB143A7FF51 C40E4A1F9B3D3C6E9D6DBA5B6161C6C0C221E74232D0F2EE7A9446BB0861C289 56B0F4B03904482055A0D5605882A9A967FB909EB29B1E46A7BB9373CFBD985D 1D5AB15DA9825BA98302DED5E62DE2D1B8FFE3FDD58BEBC535053C2C18368891 2B64EBC62F55B042FB3272736AC136B95F1B1E25AD978DC43FB58BA651E154CF 0E4369324B234336F74EFCC99FC57C8CF127C3FA6F6C184F2D03F9D493740228 7F99413A1096090B6A242A3FC66F0F8EBF77E0BC32677EB1094FCFC9E64F6FEF F86DC79D0FF241CF914EFF711F3E7FFD5C2782975F5E33BDA6BE61D40626B651 96B0E504A09DD174F0FDEB626FB2FCD96BE8724B990D229611B252530027442C AE681E6565CD69A0F170727C1B9277B0B82E658BC850EB6AD3122B9713531FAE CB297C543D0D0BD47ABC1775EFD7CFAC54869D1D3D744EEEA6C0F7146C506158 7E8E6AD8BF60AD5C9324AC90A50D962A8C009F4BCDD325212963D8365D4A68DA 4387BBD14F7F96DC79C426B29C8AD12873C366877954E463314C50D550BE1D93 98F2C4E576CC1BB991303636CA304F9A398E8939E112D6E176ACFE54A11F1D3D FEDAFAC2972DCF1C41C8BA6D1B85465514318062036A28F6079533A56E01C984 92C32AFF93C3FB3F9283D2549FB3CCDF5A3D7F87F3FFD4DF7F44CDFE71EA56D4 608C5AB8943CCFCB86E99C5B5C8A8B4917A5CBC46C7B7EBD440004E633D16276 5226D261D43400883C3E3E1A19D56E34EDF9E25E82A60AD5256E586E96A7AB06 FECDCDCD5FF0DD559E5B458E1DE79408347076D2E2F182F3A37470F7B4C752B1 6EF8E716A0BA09CF32589CB91CB9DA3F244BB349514180F83DC3882D76DC3F2A 8AE962685F09DB17911B260A707565306991312E87551A43EED3B21E86043A6E 985559BABC58B5CC550B92389F785E61607BC243E6DE328A77D5A4819CF5CA9F C8E2482BB21019655C49D36F5AFD6E998D8AC5DA0749F2615F6433D1779C27C8 41C242418C5E514BE973EA737BEED7C3A7963B1DCFB6ABD0F9BF47B7BFFDF8E7 5FABAF9E3F4E8F42F28139AEA5E9B70C3A395527053E40E35F9F6FFF0B6FB915 95BB56815C20C0FC818CE7169BAF26CC70110F341D541460B58E2DF83CFAA0EF C91116D6B366B0CB65E556B0CEA6B45D55C849524CF42497C0B3235F484F422D 36365FBD4ACE6DAAF90E6ED54FF4B50C1627F79BD2B7BDF5E4F8718A7A739B4F ABA28EADFCF0F6779BE1056715027E28CBB1AD37B83EE8D0C269DA674E001A41 A7D1BD1FBDD37879AB7D66499699414CA9CF5D4C6767D2FFD97BCDE7D6D5969F CACC83AC939653A032E6A28117600900C36993600ADF4422A567D480A455E971 163F74329EBB6A4254A74BF8BD03EBA9791E40A5B4C677E240F8E3EDFBC18A69 7C6CBD12A5D649C405E38A885AEFF680166573D3156E94A7667A5BF99239CFB9 253B35746F36D193E950064D63A6ECAB35C42A6D4B09AF4CB4902F503CC103A0 534774FBFA365D71D79E3B83739E1F4DFBD78FCDC79E47EBEEAF86C7AF1C77A6 2D496734899710CE0EB7D42D32DE1B87171DEA53756444FD6978C92D8FF9703C ECAC75A4A10FEF7D3C37FCF9B078C81D05B404E7DA158459CA27348142088B5A E3B8C747E617CF37BFF9F1C2D3B2A954ABA653556976185B8F9A624E7CEB5EFF DEF5C5731EAC8484F7352AED779B87FD0F7262188D6B2610119A3BD492299958 95DDFFD9B42DB64A968CCE44CBBFF454D5B260F3DA8429A1352E75A523B34238 2B801A5B6139D3BA7AF27480184A0BFE3C56C57E4FC5131B12F836DDBFE3FDCE BFFD00F7BFB2AE9B9084E1001D33A182CB1CCD382A8E82975AC1972FA865BF28 052FDCC095393F64614876CDE37F7DA3F3088A3B4ADD3CA139E4401B7043BDC1 EB49B2175B99E32F7ADDE4A8C8CBE5B555C81DE96E924C33738B9873C48B6AF9 5ED4E7278B9F3C8B2ED552125B95874BAF6039A35DB437C61FD487EFC15247C8 99960EE95C5B23419ED3029988E2CAD0C50D1EA921B4DD8FD45DB15AD0C1234C EBBE97D8E056652078A8363C09C184C983EE7B3DA31DD45F598B6BC320714A95 66660E7804F5217444FA683CFCC9C1FA85B5E205921B7930A86152560C950034 B45DB6A69E984A73649DFE7CDAECB4D1D934B327AEA8335C2415F01DC702F669 E48C39F8A693FD309EF069F877CF39BF7E2E07B83666A6A9E7160A526416E429 DB84D248A7D5E4A0FAEBE1F0ED41FB9B174780620BE6EF370E6EDD9D7B795DB0 DC8C151B92FD7B3B6B17D601B0C94E5D868B1572038B5510E0D8A55A3DBD84BC 888FD29DBF78BB59731B5F7CA16C7A8C76480950C084F8B773785E7D00AE39D7 E3A1C9F62D2507FE5AA78035902DA3720138E6A6D047F0C0AFB5F467A46F6888 A3554887DBE9E87170664552333F0046782FB70015640E10476C032334E69E26 8BCF4A1BB6902566623200EC219F583C2326D1084CE42A9A94776F8D6FDC4E1E 1EE309CA8785A3ACB930443CC9726169557809B038C6C4E4A42E4CA3D4A7615A 2D449FED1744E6A69EAFB362C0BE29BB9FB27F39E9DD30F3E78DEAF309B91CCC DB12AF042E22798C0B61549550ADCCB126AC5FD1D8323B8657B31B6F86E25F1C BEFB7EFFF8BFDF5AFBA5D8F8619E7C5B4C1EBADEF038C65262622426D7E249A9 80C75167C642BBE6D73D511CD791B9C0F17C562D556CC9B243D3847760089B86 0958AC72CD14C901CD1E17F9614572C8F3A55A40F2A576E3AC40CD4A25AC1A50 C925478369CF593DF4AD1F1EDD827A0C14730B9E7077DCA08E5222D7BABC59CD 606B5AB654999E41241DC7E2342E0EB3A26F59FB0EBE93F6459C6F51FFBC0125 CB75990AAB5277E3C2F20130991DE0B38478CC0726226DD81C00D8CB2ACBA1A0 EAD17645639BDE89BB000BCFD8B5464AD22449003D38F49496A9C7167A2E24E0 D8A3B7D2C17BA7710A355432A8D05CA4256C2C8A2C81CEB92B7D79F0593FFC8D C52B97E9E22A701BBBF85138FE77AF7FF7571A97AE4C2550838F8269AF88DFB4 9DB28B8F87651F4D7F636DE1BFB3E717C7E5C8060AA2846BBD5374DB9DFA6762 2059B2D48510102DD585504379829FFCA347A1B55AC0EC444BCB6BE9AE3D208D 50EE21E14951E625CF52472F4891E99604A52C163EFB82F7ECF3E4F96785936F EFDD5C59B9E054CDEEAD0F0D473436AF2004EB196FDFFFC1325B35D7A18A01B8 1AC12E82809B19F2E8E16B8925030298A89DB73EAA874EF0C27900AF36B2B0E1 4056B647E5F0F59FFB2DCBB8BA5ACAA909FB201771C00CBA60AA050CF81B8889 825822336AAB1B467199CAF8519EEF38A551DA2446C2DD4DABBDBE7F7931F50A 87F8DD8F7A35D634D2E969FFD1D2279E51A199270347715DD664884BFFF4A3BB 3ED4C12BCB83EEC4E852375655A330561D7D1F89592904506AC3B0A0FA03B156 5C774655A21259A9CD7614CB3385DDCC8D5C721C0EEEEF2B07B59E5BAB1AF960 FB54FD79D5DC9E33BE5E1B7F659F4EADC00E9506D92213A9C50C32228377C664 421A975AB9DF1F1D4661BFE99E3327C713AC4CB7E5C8194D402764F4518607A6 C91C59E9FE201B013D2D72D706980E85F0B8EC3BBFFC4CFB1B1FE796566A56BA 99139E8D14A28CDCFB8D517BFC6F6FA8F4B07E9102A063C22B595991C29B368E DF1B3B353B7CCEC87061153EA3B8302790DCE3D7795D6C1C57DB9D5F5B65CFD4 0A47478DC1B51D82DE9C330E3813349E15436D5F59CD441E758FADD63890D215 44ED4D928313C7A538C2C3B7F3FE41E777FFF47DDCFBF29609D594E99148583B 2624A745B48AC80BCDA54F5F42755BA63107F6CBB1313BEEC2C8E9FEC5EDEC2F F7578B79D826198BB917571DABB6B844859D3F1E0A3F751B56795C4D93117DAA F2EA2EB96BAB1EE48042ACE546663ABBF55E7FE47CCCF35FAEC5666E08C3E636 BC3D008D34EECA0743FE3AB57B1DE41553FB385CA905E76AC288848131F00CDD 00A0B5C0148004C00F9A19E6DAE196DA904E91AC72A328DD0A4AA19530649490 E4E9A9DB7F6B38F7994BE5452DCCE61766456461958C1BC608A15842219CBC7B BA7461A5BCAC4A967BE3100A97D00DD2106F906C4B65A596F0F207B47FFF68F5 EA8AEA544595CE9E465E70AFA29EA2538C73375E2C5FAF86B74ED553ACF30F9E E757E76565981901DEA5C712F53841E968060B686552ED9E8EFFFC808C8CC6DF BB14AFEF11EE58EFCBEEEE71FBCB170B11795D91ED245194749E5EA90285DAED C26A01EA0476A95DDAB885B57C536CA479F2C1E9E8A39D9517CF56171A7963C1 41F334A7881925A1A63025D36D3E1436C5681A1DDCAEB74DDA5E14C63C96A16E 69A3F07D21CDD955656859BE2AD6649AB8DA69B8FFB08C76DDF565207CE5FE23 F3F46EAEF5094A3DFA40CCA8F2E9DC3967F599C26955A60351A6FBC58090718C 8AE32A9D54A787D5D1A1EC0DA607C3F1E1146A9DC1CD1A735C854CC1551A4D4C DB29AC664663220726B715F162CCA78A592E507D45B25203740E60478B193333 8ED0BDD2FCBF46837B81BAD20E2F1F0F3FE1B4AD42F875A7C465C94568D60860 C3A2B2B831A9AA4347CFEE6E8830F017FF028DBE3DBCF7E5D6F2B5EDC91B6DF3 DFF5B63F802D9B31CC8B940988103DE39169197D2245D3648B61080FDB2F655B 50C0804DCBAA9B6C8EB2BA406D80DF52CE1AA385C38CB60298644E008859D447 CA1785C28253CC53C599B3AD8A4955AC28F646A3FDB3DB1FAD98F6AF5E58BB64 5B5AFA40C914004DA9679D66C3EE1C5EDFD52A12B29A72541929B2764EA77B51 BE4BD9638F3E16D9388E7C8E96C2FA82E52C0222C190FD948460A2C8C1468D3A 50FB12934E6D36CDB2D0B0EC52F95C41F89EF8E84304045B6D950E6C9D02DE45 08001A8985C7B3D3BCD6D8380ECDF7B2E99DC948DF3B72D9E6FC4A678DD6ADB7 1F3F8800C5432528F1A7DB18FB68A924DFAC5F7BCDDAE40E3E5AB1FED5CFBE97 66FC0BABE71626A3C7C9E19B56F25D959AB1D71D019D4CFFF699A57F64CF6DC4 32861D435012DA7F317934BFD2F94A59338C9C8754CD2E08A9359B3D25FA7A67 769E35AB4BB3C3AC0A093D23ABC74874EB974D2DA22D1E94965B5239D06528E5 4691C2CF6B4B5CD65C38BF89D7EDF1A63FFFDAA70152ECBCF74E7DAE196E3E85 A90F38AF7BFFBD7AE5999B35C1265C4C814AC90A2A16665A728B0B6DD1C36849 263BC7E8CE41F0E9CB69DB75044485A94C071732BFFD6072F468E1C5735AF945 6979ED22842ADC6472919026021AA1F50BB5F1A316549400A427E5F4BEAA0EAD D2CB0D9DB492EB07A23B6DBFB805FCC143CEF0D688A5383CB7B2F7C19B61BB61 5F98E7D528D0FEBF44B27A455CD5ED4F1E3D6A3F7531850FDA9FC282F6A683F6 F945C88DB00FB3921BB665C2D303A2054F528A992EB29050210BFDB808671119 B0980672550E8ADDF76ED4173ADEE5BA72847C9D973F10FEB3BEF93577541BD4 69539F121B924F0A78313DABBDCFA66F24FEB2976E766969583F6FA80B2945DE 60AF1F766A3814158212E5C677C5E41EF7AB1A81BF50B9A52FEA50EA1890A86A 1C1D8961F0F5E71BBFF10AEC793A6B23D7545F165C947170BFB1D738F93F3EA8 B7043B9F0213B6648D0303C1C219D5F77FDEF516FCDA659A1178540D28A1A59B A0098A7F20D9D4CA9ECDE77F6D55CD79507BB56E4E0640C0AFB425328028A29E 58DDE85F9A084AFC44E4513F1BD8EA462F53DB87324BA9E5AA7D347A2349D1D9 6FFCD14FF1F4972FE20AF643296720C67031D924F2A5BA716D11F99EC5F5DD63 41329302E06036AFABDBA3FDFFF8A6D3C76615E82B3933C7F3922E43C1B14787 853FC1F58E3B48BAF0A6C19257B965D12BF31D1EB403639D6891912E8D8E137A 26AC7F72A56A4649953B3234B518680AE9B4D8CDA2F7A7FCEEB86985C2701333 AF3FCDCC36E4F669653066D8FF1F4D6F0264D9715D8965BECC7CFBDF97DAABBA BABA7A4503683440022040823B2990222929280D35638D6C8D368F35632B1CB6 4333316387631C61876D4D48E1912C69461A990C8D1652163710DC0102241B00 BB1B8DDEABBB6B5FFEFEFFDBF3BDCCF4CDDF720702BDD6AFFFF365DE73CECD7B CF457AC0091C7E8D7C025908A217E5DABD19E00655B5B7873BC92DE4E4650032 E564028EDF0629B665FDA327BA33BB15E29BD9D453DA140A7E312CCC00253787 E33BC3D993F3625D807E62A1AB73FB6408D2C7484A9CC1D61896A3F9FE1B29B2 E3FA2396326DC991B0063A571E56A861C76E8F4862BD3313BF120E8D6EE91FAE 975E7C2CB1403BC0F906B59CC06916A48233AE2FF500C0A2145DEEED7C79A3B2 B658FBD41C6FF6556E8A4B13950AFBFDCB3C195BF782F1FD016D37ECC50A9B29 0BCB16AC0CBC5715125E5564444FF13026CE303E7CF9266059F3FDEB51592177 858906993A5C63641B12C38701A24581BA6EDF338A6E69A6AEAC1964CEEBCB3B A5C7DB0099D08147DAFAD9A344C2D710DFC88AA2733B09364B2BCBB0D1E4F686 7174A728F4752C923936DD103BA15D9F3DFB6E556AC07144C3480D43D98FE424 E9474769D815C3BE11847CCCF9C440DCB3855DC1B06AB0E6896EEB0701E3D072 88FC808E74B355560E8B7B05FF6E1AACB9B32F2480ACC17E4D5AA9AAC438850F A1EF54BD7762F43DA43EBF777775A1F2D9F6F2B98349492ADE74C62C0F27E367 D15C39A1375CF54D63B2DD1DE45902A8F588DFFC0C3E5132AAAF1B932C1C1CEF A67F5E0DDE4CE2DB0A75063A861EAF94EA257B6730DCCD442699874164A4B008 ED9ABF54AECC595E1E85F0A62B0EAD2BBC88CD79C44A05AA51B32C0D33130ECF B48D122513D890253BE05126F3A1CCC7DA67D2CDF544557650B237F6779F6CB5 3F5CAFAD8BD82711C883CC84306562645266711E8330F6192A98E271562DDCE9 D45133412C0C8B5ECCF70C010F6F47E5DB61D0D373B2290070C5B2E7CA95BA69 D6E1B1C7B1290AE5D289890EE24870BCE4B5FC0C5BC924748CDB34D947E92AAB 2EC6041E62CF42B12129904909EF407BA5DE358A2B9DCE3D644C2850C9DC44F2 59CCFED1E29976A3FAFBD75EFBA64824B0165139A3FA89858F551BCF9A8DC749 ED8C3BB3589B7D75B2FF3FFEE4ABEDD9995F6C9CE1FB87DF977B7F678E54E484 0970FCE01FAFCEFF8A5D5F0A41006444E141D5FACBF05E75AEF90B79D3667151 06324FD543D7D6A91AD4F64B3AB9450D5066BAF21DE9F21594E8CEA5A95996F6 92A496204C4E193F902603E4611822005A546485A567FD40CC5A6EF8CF5C304F 2C6C4E3A334F3C91575B4C2237CDD5F59B1C58D76A4DD9612142DD6D4DF44C1E 7D98406B62FD5BCA553C08D4D7DF363FF868B13E4B736A4646416DC930EDF6B6 5EF9DECAD92574A21E6390DD085510CECBB05FA8310BCA55C2F9D44617D3EE21 E04AE1BE483709EEC85487140B93A31FDDA0B9AA5F584E2A02744C7A639C1E4E 9ACF9E39DCBA9B6DF5DA4FAFA3B24E6EAB08E7568D33EA1314BF732F0B556DE5 F8E1FD3B6DD71A4C227BA6E4B635D6C69C33D7B6DCE91858430F0045523E4C0B CA248941DBC7125BC050690E9B0ECE5F0F77DE3A307DD27E62A648F0E1B70EE5 A058FEF8BB83A7EF3B486B395D4C1201DD0550028A48F07DB27373AB72CCABD7 1A689FF4E3A3467B76D8EDC0B732AB6C5A1B60C92EE95E1DE0235A4525052490 026F9281AB6B792A5C1DE2A0F64BCFF89F7E97488684D05C3F5769F0585F66FA DBA55BEEC11F5C9B5BB393E59EC841BF5480D4C2C2D9C3FAE68FF6FC39B7F6B8 1DCB9127EB86768451EA904DBE15C622763F6339CF956DB72D41F53A992D4C5C 7852A3C874F6CD74F2A92E97318C5C8F019EA6DCA7F3C1618B140FC646779B81 F022CDEC4A165FE749EDC4A7FEFC153CF9E431C18804651B87B5A51239E3E727 1DE714083233369434992995A950A802D769E00732F8FC55741D600960581838 ABCC78F66C29564577BF47895D2FF9E97E4AE0C77A6E9410DB76C61B63B682E9 124213E2A5ED83DD2DBA40EB4FAFAA59A73039CF1217B835085263840251BC26 FB9742B7940B2F1061B9546BD14743ECC9C808416B33664FB956AE20EE505300 5019585338836B4B6BD5E0ACC8ED31C126CB7D104E8584A7EA1D5E9B38E56AF5 E9765219E95692E9C4628300F726C528B30738BEDC0D3A99B752325711682E9C 809E543AFB211C23776388D5B6A29BE5DEE571E92CA1C752108D86F422773FA7 AC12943050B06A28072EFEB637BED615CFA8EA7FF9943CB60AE8CD8C22A319CA 878A9488A1A70B297B1CB17EA96BC47F7D6FEFCACECA2F3E831F29104D51618E 7FB85B9F9D5567CBF960686E06C39D817B7AD96857EC7A451A5477A02A13635B CF55CC50EA20538DC8FEE8F0EB57CAA7D6FDC7EB8143295995459999BA5C9681 90C459C6E0190963D40FF66E961BC428D7743C375A9A2EC11B43D428DC8C4654 BA9AA4900C7418213ECB447C78239A3C681D3F8190C7376E91EE5DA06CA6A15D D3409827B1ECA768F1E4A33CA783CD7D71D8F71261A59C8F20009238E5690687 C200616449B361551D61500E7B19E284CAF4C5BEC9596E27DA112F42C213B21C 93FB44FDC9FE6D9192CF9416D79895594505132743014EB44750E1EDE4E64B38 FF93DD8D30C97EAED5FAB9D6BC3D1EE366E9C0E607E9E8949AA909EB8BD1E11F 1FEEAEFAA58FCE1C1F19E37BBD07EFB78EBFD87EC2F4CB9BFD9DA4DFFBC26CF1 FDAB37F70C96306284E10B55EF62B5B51B47AF87C17E2C815A17868A7C510A65 CBF596AAF512A3C0160CC1ED229F41B42A54839855CB32B5F721896D93C70904 F33D1EA4AD6A3FE54977623BE6114D866178D25B188DE48F0AFE9F79EE472BF5 750885244ABC4C17CF15C2CC9941ED5014101B18F0239572A1EBCBBDC2CA1223 85C793EBBBAB28CB06880716EB2063A3E0D792F04E180F20586BB701B6EE379F AA348FC19B492686590406100DE51AAE5F58043649056FA9B8134F96ABCD4A41 8A28D6724B4F3E413CCDD9B4D877148EBF24B29E764B24674BAB9D34D8CA8FDE DFA8FC8EBD7411BB5F63C3FFBE7B77270766E9D5645CAFCC342961FDBD274F1D 7FCFCCC927BA5E09197F516CFCEF772F1FAFCF3FB778E6C1C19DBFE5BB833184 41D757E96FAC2D7FCEF41B610E728115B257B7FF4AECDB15FF7351D5375351A3 D4328127822884388EA6E343010889CE9FFD7DF18C2220210A9CA57AAA9A4505 D52E21B0C15C625B48276590769724292DE058A6496E24A91F0740CE44891D56 B1F7CC13C73FFBD9AC51814358CAC4E42737B1352AAFB7A41E7C9F023E2BAA1B F12C0DB05C0321D5B2251BC5F86FAE92E7CEC8F32BB05E66C420DCE49EC1C6C3 EDAF7D6376B6449E3E0ED4A75A98855B808021AA451000A1ADA741E962F3E9BC 3111A7E37BA8D8B7C944701F01F076BA7C6FE823CB393D17F8103E09BD15C6FB C3F2D36BDD74585C7AD03ABBAC962D9287A0E432788CCD16A342ED76FB37B74A 6E2B1B45F0DC0C8F4C50DC9AAF82FED26561B6451C6698ECE1B817FCD0E25E09 9EA6791C5B11C85003742AB04950BB7E5C310EEDF4DE5E27E91C7B663D38E477 BF76E789273E1EFDDC2633298275E7F0F11D95004B2A623A0636DDFFC9C8DDF3 EBCB33817520B74D62177EDD1D1E1DDA9E67987686A583DCF0F6247C7B5CCB6B 44D37D409B30AD38B06E6E941D5951EB9FBCE0BDF8840081800D4E3185709486 9988A83FA13F11479FBF3173BA12B70EA5C81DE169F30444AC497DFBC7BBFE8C 5D7E94E52234E12D214A71B5B82A469747645D9117253DEBDAA865483BB70A4A 80BC310085696D8C662153AB7F5D0A35759799EE27CDE10B38A6F9DD0911070E 9CEB416D7C295443CA8F9FF8D0EF7E1B8F7E6A3E965279CC3FE698EB56BE48ED A536734A8261512509E62647CE98F44A4593D5B26FDC1FFEE5CD56DA18A12CAA 25F525CB6F94B2DCE81F4C804DBB2E1A0631A0BEDBB64157A48769FE40949B3E 39A1B22234875E67738466D5CCBBDBC642A97059068C50DF15915C1BD566F25A 3FFED6880C7C7FD5DF4937087217CEACABB95E4E408B16806E58EB3E3DE34432 6D1D2721F24F73BFD40035C3E0ECA5762EACDCCD2D5011DCCA7096935163EBED FBADF79F7097752609428B2E84D2C381B4EF5D3ECEEC7D19BDD595C81ED861F3 B8E9F9B61216C7913E903AE74A633572BCF6F0B541DA895ACF57F25A604D5CD8 2E41B997655653794A46D89293B7A4BAE4242AF0FEF18CFF334F24AA6A278661 A6059CE01CE473456575B33062EB50B289FF001FFDEE8F84EFCEFFF3677BE5C3 32572AB0BBAF5F9FBD78AE68C962B7CF80FC27997BE104A943D4F521AE288AF5 A047E24300B4040A40471791B876EFE8D2ED99179ECA17486E7A365E93C89710 6273C4720759B9B6044645BC7B07A7FBFE42A5B06A58AE105585730D3AD18008 C4BDC21851E9E9BA230A11581886677131DE7B27CBF767978FC9CC9ADCBB6B8F 77A8E4324A4C58FA18A5DDB0DB8DA959C932DDFBA3B2BC88339EA7FA0A3DD741 1E7ED6E3EC1001802DC13BC8E15CEA8003E2D5288433ED39E42A63598A329E60 AADBECC74610245F9B1C6ED0FC23AD95F765DA439233C1B49D5B6E66E6803B5F C5C91F6E6F2CADAC1D1B844F537CB15283101557C9CD68F0F5C3F8504510013F 7572F53CAECE680364F96331F956E7E8036BCF7ED239968EF7DF89B6BE81E546 5E5C1A0E3A59E014F9C7E6AB67407B61720DE13BA1188E934044D29776A29D29 7C832D54CA2DCF77E8D424B600C29A1A59E6FB2E08E94136C1EC3888C2687858 9DAB6DF43AA65BB2ECDA9D8383AEE04EC3D21DE123F5FEF6C23F9D6DB482D0CB 14708CAE999392E5E6869F2262526E91D8C483342C08AA21D34AA51E6D633971 00740CB8793E41FCC8C803A5AF26465C7489B18D8A2D860E27C9C6519F20B26A 969F2A374E52ECEA2E55405920F654FB42156AC3175C0A1719F3D831D23C41B9 B2994A38111880B2C7E4BD7177732CBA148D1DF45469F15F2CBF1025D9FFBAFD CA417CF42F1BB39F5325D92EFDFE78FB8FB77B47BA05C889316A2AF1F1A505D3 E7A9C87ECE3AFED3495394C8BFE5F77FF7D6D55ABDB1ECD7EE8ADEC1280B5352 E1E17F73ECD8CF9B80A0284D123347FDBAF325D4B53DE71706A5929DCA3AA30E 403F9214C2A626CFD321DAC6F47E673A2C0E1EA1319D3A8A04D2065D70A2399C 62CBB2E0CF81A6074AC6105EB56F6151485ECE4919F4844DF2389C04831C541E F5DDD553E50F3C557ADF29B351DD7CE77A89EF35CE2CE4720C080878C1A78EB8 A6F6821412F483BE24A4799CA02FBCAD1E3B469F5C07C2CD60D70373B2A41D07 BDAFBE0C02CCFCE0F921112DE141983140D2A22A514DA4CA429BEA4AA584F679 E4231E6E22BEC78CD420B362D43FD8DD2E2B8B16D45D9D899DC060A6F176B7D8 1FB9CF9F991809BAB40D8855B9B8949248BBAD150E6BAF189EA7824E74E376B1 97F945358A23F7B4BBB9736369FEB865038DE48645904940170225D08D28E8E1 F859A16D1900D623C2A3A190890687C2C69963610F1F84BDBB3B85AD668F1FBF F9F29D53F6B9ECD753A40B782981D048184A24022AEC05A93B718FBCE8DBBCEC 97B3E3637BCF3B1CECB5E69B3C8A01CBAAED664A397C526B6C0F2FF5E53629D9 E51CC3C39EF0BA870CEA0649D74D6BBFFAFEF2C71E57E11869A731633ACB6E08 44CE3469FEDDDDE1771FCC9D9D49FC4320EFA01C08D32AC70AAA7B3F39A82D94 E8AA4E5562F89F659B8399C1B7FA4A15E5F7B1E25D395EB44D5421B2A48D344D 396544DA564CA3A07A985F3774F398691659A6E7E92023EB0E38C8900ECA69CF C70EBF528C6F2666B9EA5E7CF4A9DFFE5BDCF9D812F285B966D917EAC37A414A 4E6B76055916978932013514432E300A3653E2970E77FEEC47E543D3111602A0 3C66E1B67EEC87F7BA1E29B5EAF5E1DE26A29E7BCA0DC9D8EE95B23B05F1B1BB 46182362820F778F64C998BB380F9A84F880194899865D1078BF9C927C8F4F5E DEC0F7839963EBB03D8F7ABBF5739E7F0A228ECC3017546F4804DAD4D0CDDBDA 641CD04F7B0C6153D342F8D44C1A38712428735F8F26291233F5503DB91A1C84 83A59F3B99D3D8CD1CC0DC824E9D44E1278CB23875EEC4D995893DB7787B7277 EEB857AE803E01F0EBBB461D363016898490382E6DBEFAA0DCA08D674B318DDC 183E0F8B7D4EF21243801C29DA97FDEF84C911514F7AF3BF7E06ADCE1A7CEA2F 6A0404CE330B95B0F3485FAC73DAB16486BE7774FB3FFEE8D4A79FE71F6B0CBD 7E33B5D4BDBC7BF35EFB038FE74640F786FC76AF68D5ADC78F53C767CAD11447 272E70817D2E2D13A308A7E53C4BBFFD7A16E7D5F79E8FAA70806B0CAD70E248 0A7C008396455E96E7A03CE2C3DB3F6CB719AAC3339B256ADE109E76CD67B069 19CA6DAC607BF9DAAEC9CC6243970CB3AC18ECBEAD8C41737ED9E05EB6B3551C DEA13B9DE068E8C3974400ADC03059C6591201ABD696033A276133645158154B 9926B64C20EA859245A2D320C00688AE5B06165FD1466E2A2914C71988144097 D87038F6BD21C2C374B74ABF38DC1F8DA34FCD1E3F03FA37CF61957387536106 D2FB661EFCC1EE76E095DFD35A7C2E4BCFF3C28AF9DCF2CC90A1BF88C516DAF9 945DFB448F184912E1C2CEE87EB3FE1F68A870E9B7579E215B777E22B7FF762F B85C245BBEB73D386A19EA232BB5F9244B25D972FC7DE24F22DE191E8E60E7E7 9A5D2B90AA86D130419397DCAA8700D1D3647C78A46BC0EB5E5726B4EF9F68CF 07DDC3389BCCB41BD7770F7516CFD343584B367568FA2E9BFE7273A50D749852 69BA7B9358942BDD2402086C5A6E7767C76BFA03438E7956712B6650D04CFB34 47805826B05CA06EC6385371C9EDA769DDAFE6E35022A98DBD096C4B7727CADF EEF78FF27CD5B23EBAB0B2902444260905B80676C2E03C6CD3105EA6CE1C12C1 69164A37D7EA794F01C13B22BD39EE771321B5231056A67A7165FDBF5D79FE24 AD7D7578EFF7EF7EA7AE26BF3DB7F21827BD6AF54F7B077FB575B061D490272C 919D376BE9F0C8F2E9878F2F7E3A6B9D4CFDC962FD2BA4F77B6FBE1AB9BE4827 A3CC480CAF914D7E676DED538655416A92C44CE27ED9790918B8C53E3B2C57ED 4C362C02B800CAD48437A08B44B551F0B4DB4B676D74EE765AFB473137F44D0F 83B3CFB5895FCAB383D1600261CE77608BF144DFAC54983D87AC92EB14651218 BA9C8666121FA4282051D3339E3FB1F0D10B4589987EEAB6DC424DA8A10583AE 82437A2CD9D406B7104412A0654926FFD3B5FCE4ACFBAE470AD3345322A915D2 C21559F6F2F793A45FF9C4BB270CD53237235CCF7D452E550D8C1BBAFC4B5FBB 6AA72FC9BB8AEFE2AC8761331595EEEE03BFECC69D09934E79AE965732A078EA EA3E1B65F499B5C8C8E8C6B8FFF68399E7CE669518F0DD9665523D811A6D1EEE B0F14176A767EC3922976C1DED1CDCAAD1B9CA4213E32C5329F118B11FFA123C 2C98D440A86BDF8043E4463686ED3C7138A86A27D7C5F4A2245C636C76EFDC62 6547756CB46DB9FFCC3619438C3E2CBA01C69BC7B9D21D68411995D21B7C786F 30B73A63147CD81FE4B99C692CECEFED969B0E6D209E6725D14EAFE5C36B8187 3C8822565E8C7CAD502AA9E895F2F2AFBEB7F4C2591486100F4155EBF9D5E31E 44633BF676FEEE12DD0FE7D6DA311980AE01AEA63302CCCD07E6C1D5C3D513F3 6201341A3C5C05EC3C7A130757E3C619973D8FC4496C3400FB6193970D505266 5ED80595B6EEA49F0E5E42D3CCA16E2B84C528344AA284A7FB47617F5CC7A5D4 48ED210B7E3C2C0645F9F422BB78FE915FFC0BDCF9C5F5C6595F1E4B7B7E64CD 2F95E75675FEDD2A086CBF54A08C22E6E4259BDD1F6F7EE1C7F89DB464557212 B5965DDCB2828287C3C427B6E3B0C3FD435F5AFE5205578C34C9265B2144FDF6 FA8C601C27B2DF1925246D9E9BF1562BA201CF8AE961C42447B0590D9B2A6FF8 BDC3C90FF75B0DDF6ED8DD8DB1EF96BCF791A87E64E7BEA01ABBE0B4307D0BAA 5D3900ED0A0A62677A65A028687AED684D733D0A0799A68EBB1CDBAEE890DB3F BCBDF2EC9AF11810A7C84A741BBE203AC801106A0BD62447977BC646C1D64FDD 39B83CB3E2572A6E0ECCD09C58599980505331C6EDE1A5C9D1E6E1B1679A6C55 BB480178EB222588548599CAD05326FF711C5F49820AF67EFE78FDC553DAF641 7985BE16400697C88C212CABC24F68C45866EECB9D3FFA76EFA077E1373F192E A68917377059BC31187526F50F9FE4F1917D100EAF75CA4F3C2AD6670C5DC10B 6F9B222AF5C463EC257AA69FC645BB1FEC7FF16BB38FACCAC767B8456DB980C5 5CAABD84E014998070999F984981FABBA3DEF5FAB29F5B65642E1BAAA53D8CD0 F48E48197A34AF1A2320560AA82D445888C065139ED7D6654AC795A513A88FE2 5B7793EDB7BD1BA32CC91DD30FC37C1209615869A298B27DE478866D19A64270 82B2DC2C014B61598479028F394300B9BAAE03E4BCA92D6F21EC021527B280BF 4841798F59E1A56629B46F53F9061F5746C631DCFAFCD1EDA305E3372A6B670F D3B1C73D12C1374A0DEFCD22FF7783BDAFF5C2D395FA3F9B5D7C0E625718C3F7 9E6F9622E0F7056F8D049AF06D4772DFF48649E0D95F3542BB36F7CBCB17E2FB B7AF8C37FE0AD3ABFDD1957104707CC6A51F2AF9AB4AEE64E9154008BFE14A3B 84186F0CEEEF6A0F712905D30EB1C224B452AB54ABE532637626B23002A14D6B A5B4D3990449BBB970341C053C499948937CB95259B4ABC63878726E76CD314A 2A746391B8DEA6897FB4B9539E5BBEB1BDAD1C9A6731B00FCF61C3389A6DCFF3 4E00A2A65A295718BDB7BF43172BFB71542BCF0C0E278CFA719635CA259FE228 E82F34BD72D8F3582D34AC3726FD3B99F62BFDF8F2FC09AE5C91735A404C74B8 C1B47B4716133D06A6A40B4A4126E869A90748BD81E35BF1240F41B65BF0702A 1576DE2EB52D326F3A9FF04F9EAF1DFBE2E4C69FDF7DED85B2F919BB494D73DF 776FDD7EF0AFE1B84C46004419470BC879FED8729176EAB6FBE9850BE7C78653 615F9787FFE78DCB47A3788050C29C4A9EFCEB93EB3F4BCC8A508334C28A0C6D F60A8EE0A87E32F21B562EAB105B0C6562E2EA44C3C329CEC0EBB1CED9129DE3 D3E9514E489E2A23A1103BEDEDC9B81B85405D8CACA8536BC12DD799ED80FA00 C60F62AED0063CCA0668138663E7C4CA46B1DD89F2CE784F04EC62FBFC2F7F58 3D79222B4618C7A648B5F703A1704E6147EA924F9CE73AF34A445AD0BFBD15AF B7BD779D2D40B8C5585033320B5715F807970EB6EFCCFFD4B359C5D3E9FBE900 2A3DF51BD5099D81C32A20F268489245BC2BB31D13580D66F15E04C77BF1C4CA C1EDCD1229FB4BED080FE031893B5DC7A0EC64739847B5D4E97D7FA37A6611AF CAACE83BA8A69C35D598CD64DF9503B43BE437C3FE56B7BC6A1B3E05646A1F9B 25755B2443E560EADBD824C57406ED94484CEF548DE998F604A1D1984E429443 4037C6104194E716B64883AD3BB7BD5EDBDDAFE15FC27EBB8660DD4CA05E0AB6 7D96719219148E2A4EB431F55B87956EB3B40684DE19EE84E5EA0252498A0776 5DA71B1D51378E4AFD2B43DE150EB67CA97A36260457537158E2A55F7D5FF585 331A08A5E21E04EC844CBAC24ACCADD2ADBFFB56CB218DB946C6433D483DD76E 42D4AE0C0FB2A36B0767CE9C12F340F81256D8BC63ECBE3A007CA9BFDB97E772 B6E2CB9A9753650ADB487513A4B2B5AEC20F47C83E343BD63D857A3003F02719 24A23B42610A5AD6827D226AFC0E0FAFF7A8252B4F1D43AB274E7DF66F70F66F CE190BE6C80FDDA5A63B3BAF98C795EEB1A63ADF805506ECD78325467F7465FB 877767ACB676E69B334A8B6ECE033E484DB3424D67BFB307B26FA6D1966E4C73 F360E3085077E1EC82CCE19D56870787810A661F5D446D8AEBA6B4292E00DC04 A68012C2E00EBE2D76BFF9C02CBCF6CAC2A0BF1B4C460BE7E6C92999B23E4801 69D8A053085354176A124069101B824941391C14580D3804BAA2DD84E0C5B034 859E0C0F08D4D8BDB43D52C9239F7CBC60037D295E800CA482E9442CBC01C043 23C9931FEED95D9F1D3F7E67FFCDD963A572D9CB0B9959891D5954DF5B2874E0 EFBCBC6F54D8C2879BB933D4731AF47A830EF453806324D8019DBC3CE1E342BC CB6CFDC30BEAC4829EC022329048187B52A51C8E30073D618FECA15D18CE373A 6F7FE1E5858F9C6A7CF4B440516666AEE7673F1C2BC9CC272BE9781BDDE9C47B B2F9BEE793790F14AC39AD812D7001420A0477041062310B78F4F59DCD97BE79 EC238FC76B361C0547AC4AD9D2CE3A328678A78415B861398827772EFBCDC4A8 D1DC9A31E81292FEC361DA9A25016F45C015235396912EAAE1A9A12C5C61A108 EF5DA6A2679767866FED8537EE5AC18E15CC6629AC0D20BB811CD7F2FC9C1766 6178B9617150D8859E0E8BF3D8B08190519181D4D3ED60D311E2448B1B61333D F199174202F54F858AD394C998159504552664C324AFE3FCFEF5DD47ABC78633 EE770FAE3F26DD17CBCB9E0A9919F87A3C96771FE33F1EF63EDF1F372AF5A7F9 E493EDC6AA53F60A3ECB642D0E50662069EF53D6AB5514E7561C1F95F0170F1E 3C7EFAB18F374E1FBDF3769F06FF5B7AB8C5F116C06698FD546BFE8325D79EF4 EFE2FCB26B05C4F352CC583E62A377F6719E24BAC80CA16CDA9D6B11A344CD39 BF32E394B5578FD283A1310B336A704598A1E7418F93B0CCCC8A3440C2D70D52 E6B9418A3D1637B292512EBFBC75A7A75461E8AA77E259711657ABAEC995AF8C E599F99DEDDD72BD2AB3B4EA96EF75F70754C5F0CF08443A055C596F7A2C5CCF EC0561BD6A3603EE596E8AF0761607B0CF387ABED95A2766991840D480BE59C2 30854AB5E5879E98910B245D275268BF3BBC1FA79B1828A3696406D3D34259A3 6EB4B8CAC6BD26313E7BFCA94FAFBE5B79F6B776AFDDDFB8F6AE66B33925715E 967F63C6BDB1B175651CDC305028C802B6CB44AD9D3F65E5C9BBFAC53FA81DF3 EBE537D0F0F76FBFF35AA77B80481915FFD363A77F56B086B64DCF845063CA2E 9B0527C67391D5A639D655A3DA278AB8548760AA592EC8423D4647F715C20F82 5466332351C66E10EE26F1419618AE33D76ACD30ABA5B0132726CF7556131519 33726C23C21C8A1C205AA617571BDC25E6B8EBEC45C3D12439474EFCDAFBE4E9 8B69D2A32A627042617F0281D635CF42EB20D8C480A010F8D3DCFCF2DDF09139 EBE26943121620389AB12D1C50E3576FDCBDF4FAD2F317ADE32B585AB9F6F44A A47667AE986C1620BD905C4FA153599E6CAB64DBC2B948F0783FF46B2E75D878 A75329CF929A17CB3E30DBC18DCD5AAD6AAD94C722AD083F7CBD6BD8D27DC211 18B8691997D60BBFAEA35D31C09391B133DCBD7483B9DECCC9539D5B0F2C5B55 8EB5240A33945A551F9BB49856DEEA04A95646C5C3764C88C628CED0642C9334 978473E22A4BE5A9740B919BF10F52FE96A03F63B59F5C90A5109B96AEDE3738 408035B608770B3ACABD18EDA2E0FB9CAD1DD6ECF9F028E7B1A8CE57A4954823 C112B426E8924A743B19DDCC9CB8E6A318142150132F48BBB5A2FA4F3F5C7AF6 040A223846097C329198A13617A36F786FBFF4F5D5F552A95496A9023D48540A 54199BE5EECE6470BB77EAE44931130B27A1436F72598C3782CA12AB3C618905 49179BB2EE734368D294E9E3A1A9079CC2A925C3B47D422B42F9D0B38FCBE4B0 27FB134FDB728A944EDCFE6A703909F73BB545659F6F87AD638F7EEE25ACFE7C 6D02FF7A71DE3FB118C9C8A1F01C999E2BE9E0C82E40399479E5EE0FDF99FDDD 5DDBB1805538CB2DB5523AC003DED99DC38E4DCBF73B815D6ECECD9695310165 7B786B0B58547D6D265643CFF500148B402C3FBA6A1C339306971684F1B2D0B9 BB54A9C8ACB262578CBFB4C377C4CC99F3A0C647DBBBEE09613F692ACC2D0022 A78078AB18687788DD1C693B3947CF58B70AC1523D674259BAD30830D5528674 9022A919316CD32DF79DEF5D5FF9F879EB3835F304111EF9B1979415C934E5E4 3483558FB2F8B55D2F9B67B333770E7F32BF56F121AE66227540BE19BAF113E1 E18F137EB958786A4D3E59087468E5105F32452D6BE085F5CC4C45F8CA58BCE1 D497EAC68B16F9F8A9DCAA0348E3A26FA9860AEDA29409AB607D8C4C32AE847E 60E4FFF6FAFE953BEBFFF2436895A0490A442CA379FFFBC3F9D935790E25BD7B 934B77AC62B6FEC20B7193D13436B157309303F302EE6A7A201C90637BF0445F BF31BE7A7DFEA7CE4D96B1A9DB5C4E29D4C8F54A4486E1E4828D9C49B337E95F 7FB5098ADF076A3347F002046FA9B5340386A1BD914814D1DC931510D69C7288 FD9E002054FCEE9BE1DE0D5638FB6FEC543AA399AC7F8F9E726DDF661E253A0B AD4D77A2D0C874E6128396A1BAE90FC85B2904464DB51FBFEE7391B0F574DDB2 69723D4398E84E2325088F49F2FFF76AC06ACB0882771BC47F50FEDB16FABDF8 FACFB4D6DE7744BF31B8B7BCBCF0A1613269C74DC36D446E0FDB7FDEEDFDC761 B771ECF4FA3C52F7AEBDC76D9C21660301BE18130B894CD584AF9BEA12C17CEB 25D2FB4FF1E8577FE1571EDB14BDCB57B78AA3BFF606DFE98D1E04E814AEFD83 A5B556D8A16E7117253798D5C516CD8B3ACBC351E7F53EB614AAB81E47B2CB63 4DB1B5D510F214764D562EFBCD5A9DEA9B14D812802739AC5C33B77C5C19481A BB16452AEC1FF2921AE06212C56BADB5FB1BBB99763F44382FE8B4B66F44B441 A39DA3655DD080FAA671A2519D1C0EC6520D284E0923053173583EA01742E73B 84CE08080F0098E05CB705EBD602D04E8558B74ACFB517EB694E0A08747ABA84 1E828C70E2945A008686EA9AA21B070F06C3072A87F04F72642A23D67930A0BB 464525131B3FD39EFF40EAB72D4F5ACE29D23A5F5EEC323E96FDD6DE6E2DEEA4 4DB990D36BB6F363E67D7F3CFAEAC14E54D085BC3467F2A1DB7FEECCDA7F912D BC075EC54EFFF464FB0FBFF3DA8F471DC7E0FFEAF1339F136C2615C334E2B99A 5076DD8180871E8B413D6556D904FC2BA83220E8380FFD65B4598A2E6ED04645 48DF7A61DDBC31E07C04ACC2724C89671C976631D5F6E5B9A43A3798EBA02F2D C3318D7A1E0359CC882BB9DD48BC56C4B28A9BD4A4130125F960257B9254F227 F5A530B01D60B4DA170DA2A9F6E6D7269784C34F18085D929A7F773F78721E3F BA6E6BBB41A4284B5C3D3A976EDCDFF8CEB7DB8F9F2D3F7A1EE9166620A45151 C482BB269C2FE6095DD6AE9278A08A7D0B1D9932EF3C18A0CC6C9F5BCDFBDD49 77D2585C0FA2BE59358085F7DEB9D75C6819B356AAE00C7AF2ADA273B435FB42 453922CF5C3A7B16E05C80D2D1A4A643865D75E7E0E0EE64FEC4853C1A0E063B ADC59A51C65C25D83188E3E8CB4A0AEF47371EE914A18E8D7A97E866942848C6 914C0D27B3081C5D3A19D0D837E6EDFB73F1FFBB75786EB4F699E5B83E74AC1A 4A69C17401AD9555D5418AEB05B72634AAE21FCB7BE2B5F5F973688427834961 E695853AE7A109BB288D0971F36DD9BFA2ECFE9C2D7A41058EB6F22669346F55 7EEB43F4C2BC11A5004D1100888CECA8874ADC7899FCE85B5F3EF544AD62968D 1CB85C08D40C4D654FE72888EF4D8E2F1D17B3496877E97E257DD504064D4F65 95C71D888374A1259A258E15800251B0E561C39805D3C7944CCB8975D0D19D1A D232ADA833480EFB3E572C06ED9E27EDD07B7BA5F7A6803DB578C146C79C9E3F 77E197BE87FB7FFD64C9ADD0854ADAB04C6C435C13D63022A995D72CA3A9EDFF 5EDF93FF7EA3E7C4C24D4A4D56A9B751828793917498C3EC496FE0376C552D72 854D519277A29CA56A2E771AAE29DCF830ED4F06CDC75B78598992F2BC06CD2C 6C945032285C7668F93301125FBE155D19D41E5B2FEAFCFE5B5B7534DB7EBA15 B7EFE73628B20A56CAB6884EE86B6F5C5D110B4F581954B7CE80FCD3F383941E AD2EAB088D1C00C2C24CCA6921C3DE57EEAC7A67F0332792F60089C4C9296CFA C8169E7491E2A8E816869D0FEDDEABB7671ACBA65FDBD8BCD95A6F79AED0842A 174119E23B2ADD609BDFD9F44FCC362F36911DC3198911A8D80C58BC2140ADAD D12DB5F7EDB7891957DF3F6F7EF0ACB1BA024A90A1940052485317550992FA47 16ECF3C8854F625CDFDBF9C36FB4D76AD66F9CD4A3379272119798E51FBDF266 E5F41C9B2DB19B93FE959BF8C953F4EC716CDB44E8A10438877885801B3365EA 86594C4AE334FEE6F73AC1D1B14FBCB7F05D3807D8694863FA0BAE8BD7B42836 69BA75CD09B7D9027C6B1C1835622E325EB5940558A810070A85B22C72B69CA2 0E02574F8D560188042C4B727B3778E55BE6B57EB1E7935A2D6B805E5A320A65 14A0C3854CB2224C65C695F6769FDED00B7D3761A8696A7EEA6724E187EE4B25 86B6809AA6EEA713A0880EE72077322715AEC001C33814DE180F6CF31D9155B9 BDDF19FE7EBE93BF70EAE923F2D8ADECE46CB5A98E942F9507A1D57EA3A3FED5 FEFE3BE5F4D9E5D95F0B2B17C75E801334532CE44319E2541B598B7A612484DD AC955E7AE7FA67CEBDFB85F513DBFDEDFD6E67B23BFC5F3C7E3518D290FF9C39 FB81D9D6281908C7DCCBB31B6672E4625BFA062F5F7DD0EB99878FD9E6139576 ACE4D5417F3F571AF1B1122C4786CE97567232EFB5AD86366905216169134350 2509D17E7ADA930FF664A68D3F0570C19B61D00B020E279950384F7A55D8D46A FA219A15BA4D8021CD3FB5C594EEF17E5800086BA82C583D0D0BF0550F2D14B5 25999E71A0908BF480AFF9B2DFF07C7D5100EB2A35C46A054E7021D10439A382 EF2593C33849F478617849EDED861E3E21F802783226294DE48C41E767E6F6B3 BE17843F5B597E77B5016AB15AB15896968534C7513516BD399B867153181DCB FC9FBB77FFEF482278738175617979C9C673F7777EE5D1A7EAAE65FBC55B8EFA 97AFBEDEEF45FFE6CCB98F9813257927F173409F3CCC7C5D7B578F48C90E4A65 E250E06382FB24F76033B23A7648A67DA132D3183824700C5624153E1D0D2835 FF62DA7D96A6A0114D1AEAB48FB60266B091B42FDB64186621CADD8AD9AECF38 AC9E1952950536120F74D65C557DF05878C2F2F852815200165B290A5209BED0 82F3348ED058A7EF33E6A0663A11D6CB2FF3C7CEDB8F3E8942587B91D9516187 8ECA483FBAF5E56FCEAEAF572F3CA29F7ACE0DD0DE59A65D0C9D194CE7B591A5 3CC0FC36161322DD7C92450F36AD47566C60EE373745DD45ABED2C4D2A114E76 F6FBE978E6ECF15C70538393B206EAC6F7DE3AF5CC05398752C44BE53564B6B9 8353953A5CCA615FF4BB7CE34096A9B5D4B4BEB245DA9E3CC5841C03570EAA1E 291397C77008C71097B9E658B959603D0755E70CE5244DFB63CA152D1E5AE44F 2DC74CB2BDBF17BCC11FF9D4453E2341FBBB962375AA43A6205438D2735B01D9 4D1EA27EFA3725D61E78332C890C314CCA4C18E55261E00CD09F15EC88A69794 718752339C505D3AA978909F610BBFF589A2AD67144A05DF5BD03841C538AC8F ED3F2E0E6E5E9AFB683D4EB81DD998E61335F6916F85A5F183F148A0A5C79638 7900C83ABAC447E1BE72F2D5674E733FE55EE6AFB6E1AD0AA68D1080C11B8086 7024A8C0FABA4B9B262BC6853E2825154CD2CE261A0A5BB608042F3920478BE8 6D35EA0C06F3FB4B4FB98C551372EEF15FFD1A1E7DED89D2DCBC51D3D3597562 D800E2A3FB0B80DD3362A33B7CFFCFDE74EFA1E1D2A05E6E345A331CCED5D15E A95C2DB9F5DEE1A1D7B0EC1A81B78333ABBBD9CF653633D7362B2529B2834EA7 C88BC5D38BC62C0ABC10576CC7AEA1846A971D952AD754C20F5FDD3FFCC13B8B AB6D7F61B9FF76371C4473175A6C4E820A126523E0898320FCEB22325D034B41 EBC267267A022FFC02A430D153BF74C21495F328620EAC34E08FDDBD71F0E0CD 3B173FF60239DE800FAFED5F726094AE7210A85664A254F6688CF323B37FE5FE ECD9474894DFDFB83B7F6AD6AE1A2AE7394931B3CDC8BDFFF53BE9517AF6C38F A379D08781EE3000B18C6217A83497787CA2F7830DB1D9378F39A5174F92A78F 73CFC7FACA9F6B8325612A058C056131569E1B64662534B7FEECE5FCEE8313BF F9A25A0E331632E502EAE09476DFBC5D7D74D10051FBE66E7FBF577BDFC56279 3637F415B29EB4A83D890D6E32ED640D9C9312EF60DC7DE9E50C678B1F7B5695 7D6438C8AA15CA228603914EEA9E2B3D6F34DCB9E6913EAD61E9DA19AE503C4F 540349AA406F0364A481C179520DA928B3ACAC032E8E0A6629E03893F183AF7F 71F2838D75FF09AFDC2AFC719A3A3AB80269CEE00B731967921722D76562DA01 643A6E776AF4AE6D6DE107AC0281688FA71656785AC7359D4AA80D1E40DE6A20 94A0788028264961052897ECA683BF33D89B5D590BBBC1E5CD07EDF5E513E5D9 8B9D7406F5F31A8870BB19DAD727E4B7F636DE2AA19924F964A3F1587D6536E6 2755BE9224631375A93EB54CB2B0E27D6772301CC7BFF6E4C7D7ADC6DDFDDBD7 260F86F9E4FF29BC1FEC6FCF58E49F2C68034AD8184734BFCD8307C0B44A25CC D9D1985FEEF79FA7F8ECB125CB346F4FFA7779322A8CC99803B049C2752D82CE FD22A64747C84AC9AB38AE6F5A7A1EA810A6C940251AD34E000D4A9A1CA88E94 E3389E04419A17BAC3573381E9852F990E8894EAE1F53ED246F253CB60DDF624 1F66060118E18F28C636D559116A1A2E210D426CD3B219E828C2A6344489426B 294280A5C4054F78CEA5389A2481EE5244D9B4BFD89086A33B7A749126336922 F358DFC9209619164600F9258F5E6CCF9DB34B7521EABDF173B4D2307058C1D8 25DE24210EB1B960518E2AF56FF2F8F7F636DF00F24B3D33E5368A3F71F6D479 C76D23F2D34E239D6D7EA177F4EFBEF7EDFFEAD98B9FE6E35A101F09A7C78D4C 650353668ACD25D60CCD7D8F3A0CD4AE2E31162E81D5645477CA480CB1CCB011 D5EDC148EA3E5C4A028B05948C0A11E562389980689B740E576BCDF3B30B7E21 991E005E241CC5B8A02EAE962A26AD48DB944E8E8D0C560F2FD5D907D6C6CB56 2559123843B08F8BD4365974D41DEFEE54E61BDE5225CB87C0601CCCFA877DFC 9DCBE5F73C458F1D078584B4F767C61DE188981DF4EF7DF9EBED33274B4F9DCF 00A7A31C68875EC8BC40DE82B28E113DEF7E2B496EEB8AF308776EDDF3EABEBF 34AF78D1BBBF596D3550C5532666B1ECBE75955501ECE6629EF8268353CB1276 EFBB3FA9AECC564F377256D8CE0A32F5D03AA06176AE40FDA27127B9BD152649 E9D471FBDEE8E8C146ED54C3A8018C1A29424ED3A59684036D10936852AB14D1 7DFFBAB21EB656CAF930444961F082E900A1B79D61B1388ABBAF4773CF1F27CB 564632C775F0D4250E7668015B278250A13D0C40211A6FB6F70F2EB7E6CA965B 4DBA23110EFC993AA76602F4C11466EE16D769F6E38CA838F32A12C35B99E047 BDD63FFF645E2634076A08473C67314889202A25E48F0EF8A8537ACA0BE31106 5E83A56031C9A91DD6861B41E191EA5A051B0372CFD9FF4990E060F191797BB5 14A3A1D134EDF99AB475BDE4F4DC6847A2E9819153E37A1B54408E52669962C2 93C32149731C17A0DA78CA81B6E67795785B8154E2EB41EB2C06E114B2472FFC E63770F1E673C66CA3201E2B7046E39C489F97E0E814A58C46AAFB671BF1AB5D CB67E27CB8505A890FB3240BDD86578CE364929855EA2EE936523BF3C73BE334 8CACD366D56DA1C81FEF77631635D62B7486A6249275CBAC54619B29383C38E7 043B70BCAE05F7BF76CB9E2B37CEF9F98368F466D15C6DDACF16A939B2503D67 3937630FB9DA4F16C209510F27CBC24FC64345A8E7D44FDDC5750709C5993901 E55F22E63DBCFFDD5D7AA2D6FAF042C12704849CC7382B40D014FA66AF965BC6 040D1AF0373F9944A371EBBD8FC75B9DCED5FB0BE797C92CC149D0F7C2663C9F 5D930FDEBAD780D779A2A9C818504D1466217362020064B6E9A4DF37A2BB7B25 C7244FCF1B1F3B552C374C60EA70C4741697C243057CC86CCE222332B3D4B4EA 6F24F7FFE4A5D967E7CA3F73AA50910296641B26B1E47EB1FFF6CED2BB4FEA89 B9DFBA2C4D67F6034FE7AD9A1E1F99EB3B026D1F64104E75A004B802A2E2DEDD DB78F99BA599F2CC0B4FA9B28789A768854B060104B8B39E9C08417E1C0407D7 FD6641ED4CE9819A356ACC196C4EA512B839F5E195A242F19CA6282F79465382 94C47AB442269869F07CF3EDC95B9BB5D17C314149BE6F17257DDAB31CA78591 E5C01841376BF9023244E85F68BC83873135B6351EF6F43F34749842C7DFBB1F 692A2A8B8C6B04154092B55714077448B09D98F7A9FCE362E72E293E61AD550E 92BFCEB7ABEBABFF28F01679BF280BD72B2D44E6B508FDDAD68D37987AFFE28C 71D82F79F6C7EBF3CF04128853E8020615CCAEECBAD63BF9786B77E723E72EBE 77E571BF2FF677B7BE1D5D7DCD387C7532BB3D3C7C7EA5FDA9F26CF360029CEA C045B754DCD11042A964EFECEDA435EBFF289D1A7AE4ADB4FFF2EEFDD0778344 F0145E5C6113690F38F1B0B2039E8E3E8C26315C667A96693388ECA66B9B44FB BEEB1486CE4D8182B728A634E6D9703C8AB22CC9754731C833A98BAED0431CD4 79629084CAD44028212003FEC1EF1168269340F0746BE58A6BE96F8F0B614963 7A09A2171AF4A3D093965090A6419AA552264511F33CD7E3C3F43BD5EF73EAAB 012F0D340D626EAB526DD4AB098FF6BB5DF892BEEEA600B52B1BB63DEFBBF164 00A4F8D3B32B1F22757F34A62E49696EDBAC210B1724822213651C99FE2B71FA EF8F36DF2A1278E835AC96E7ABB8DB7FFFFCC2E76A0BA754359959FA179B3F0C 45F77FF09B6746E9D0C09B4022A4DAC7D984E2A5CC9951A86CD312C394480551 C1457AAC39A3802B10CDE0437B06C15CE5D80915EBF3A46FC8FD3C7B301E74C2 099C8153F3F34D85566D67D171EC2C037EF0D0A380E3E9B589CD3073B0E30211 654CE524A36B2DEBBD27470D52CD9774999848756EA5E0A23BBEFEF20F839DCE 890BE7169F3BAB4AB07EFDDECEDDF807F7563EFC5EDC9E45B905CB96611179A8 04D2EDC1FEC1D75FAA5D5CB79E38139BC44DB0BE54E4639AF3C2399679EB2E4F 70F44E220E2875F38D83ACD3293F7586242A187686882F2F2EC309820016777A 9D9B77974F9D50259343F892FA82CF52F6D11B776197CD3F75BC60B9E1CE1BF6 6C6E01CDE12C53040ECF683FDFDC3EBAB9D33C7D92D5D8F0D61D23C86B2757B8 CE9D2676CDE54D4BE409705E0CAB4224042C357554D1B112C02F4ED3418062EE 5006645414B9EE5931CDE80A972B5EE96C3394BA0B96981A2881CFC3F6960170 7038DC09F50C74D818DEB82192B8D66AC223E0C1107627F65C881B8C4A05B167 DF0DBE17AB7EA84AF5A94089CC276B95FFFAC5CC122C833321722B61E9D888E2 5066A3BFB8B358ADC8FA24E43D823C966360079900CA3DD77B67622D316B09D3 891ABE150DF6E3F2BC3DF3C4B2F293188F59D3371B1565326DEBAAEB1EE5C3E9 5D1A1385E604102C7546260D93FD3D1A10C41DA27352A1A1FC7C600C6E1CDA3B AEE596D8A3D25C9800F70DEDC72EFCDA4B586DFE546E2AC07E07B66541E084EA 3147BAC3CF1EFED5F5C14BFBBE6539276CB79945139EC367749B2407B018093F A5CB06C4001278F10338DCB1B7C88CA6B0843FD9137194344EFAD69218E309AB 969D4A7BEA8806AC57A432644EDDDB35FBFFE1FBA9451BEF3B83833CFAD19E54 46F3BD4B79AD2F6C20D5262E0A671A52B44DEBC3D40FD110A85B82A765A27FBF 100084BA6506096C26BAAFA4147D73373EC8DA3FFFD4A07140F9A4242C6D6369 23AC7350B19FB5C67992D8F9ECD80FBF74851CABD327E7B30783C1A5CDF90B27 E49C606918D464796B6EFCF54E6088F9F7D545B907C8A03237CFA99E036523A0 DC94D3E21B9992895C30DC0F9E921756739BB910F8200251F8A4B6AEDD01E549 62A3288522B6A87BF007AFABCDCECA6F3C11AF72232196705227336113DD8FF6 6F1CAD5C38A9B2F1BD57AF2E9C3EED3C76065E4DEA849B9EFDA87B65FFDE5355 17FAE8E1C75737B65FFB6163B55D7EF29CB46D6CFA9856330042E24CDB49745A 4D1CED4D7A77EB4BA6E1895C2BE932554DA22708DA4817B6A48599174478699E 095B1A756DD3A4A75AEA59875C8E48BAC7EFF5B29B980D884ABA3406E65BA84C 4F91C67A1EB50642351D95230BA9A65EFB3AFD09510C94207CBBE95F4CEF2A8C A931BCA14B99013B737D37034098237D1FE3447A8869C13184DB4E2EDEACE3AF 8CB6F361FEC173175FDBDB1867C52FB78F1F1F756A1E2D973D1A8B5B96F53B7B 1BDF9CC4EF69345EA8CC1583614DF153AEDDC636E00A9B14B4D17C0505570E1E 7C62EED4730B6BFEEC6C7C34EE5DBFFB03B2FF25EFF0E50D74CE903F7F7CE524 665622925C4425F3463239304848ECF138E8F6BB1F7C64ED7369EB1A49FE72EF EEA6437A691E85A91654DAE47FEA51A17BE0A795B7629A66D4C1462F3AEC4B53 B72C1197B19AEBF9141E0CB1F43F9E4A3CA50A401BA5ED32B34270BD6C02D63E 4EB32CD75B53672E0D43275775A65497E7388C362B65CF623603E95468E70ED8 53C0C1892BA7CEC5499E055114C659A65F733AC10F1942F30D32B5E0CF1ECE73 60067619F519AD3B4ED3731DD850596601C02A1984931B1C1F8411C40A4F22AF 6ACE366B8F798D75CBB551361FF1A7020202F1C8CADB36AA71906F46D7621B51 F220C7D7EBA5CFEFDEDD0D43D73469C69F6CD75F3C7E6AEFF0EE4FC7F5F71C7B F45BF3F8FF7AED2BFFDDEA23EFEE8D43CC77050B39DBC749ECA8666197455EB3 6813A42DB00147A6962EFAB389E9992E71EDD8A65D233BE2E17627EE1D7247E1 965FAAFA2E9002CC9069D38A6BDB6A5AFBA1BD9CF5E533D3BEC326D216DED8B0 650171D9F409351D8F0666C0CEB49D67CEA5AE69237DCBAABDA5B42F289647D1 D52F7C67EBF5BB079DDEC90F5E78FE17DEE3ACDA93DB6F1CBD7D79ED43EF5773 0B28F78828C1D19BB0AC04AF7A6BB3F3CAF76ACF3D82CE2C73845D69EB31BC79 97E699B4D763E7A4278678F886B28AB0270EDFBCBA7EE1743A53B2877C7F73C3 5E9D75EB151A719ACAED77DE218EB5707C199E18C4AE04E540F22D10601B83C1 EE64E95DEBFADAC09F33BCD91C545DC1755D2041C5708B4CFAF1E55DA3D4C81E B3BD38ED7CF7AE5F9B2D9D6C01520BA094ED12B3094912446902145B09081680 78DA5A0C3E2D20EA302882D8D475B5C00664CEB9695A7C93C5665A7B62252531 7590C1E8F496445BFC68E91485DAD34003995DECA4A3DBBBF5BA4F2DE0B1796C 70C62C8B5B08F3C44EADC80B5F2BD4DD443017361DE848FBB919FFD73F9058CA CA816AE5B13934C5988D8BD14ED07BFDCEF153A7D1E87E68744CB36CC54CD071 4C8A7267A17B69E89E63F671226FA0834BC3DCE22B178F91162ADC90DB9CF88E 5DAD236A4148543A53AEDBFFA79EE354E9CA919C681A8FE2FD1D36195AB85684 34D725B09165CCED5DED87FB87AD7086799E7F1144ECBE89FCC87E54A746E3BD 4FB05CE68029768945962E9DAD65F0A68ABFEB057FB9635AD43C498D4AE1C445 67DCF5CA552BAB649DCC6AE07C3E483D4E9352B283D361DE5EAD935ACE947974 7030C9B2B9E373FE3CCBBD20F7B0E5CF13512BD24CBA69C140B43A645C1A7EE5 2ED93C24E7CBC6ECAC79858EDE7E507A811A8F51C54D4CEDC80D4B0AD384209B 48430906B101C08000D3C3FABF290AEA4E0A5DF9A5C736828271B127DAC61BC9 CE5BB71BEF5AB22FCE86466081CA451C1113428F6D3108E14EC0222149A56ADD 2B76BFFAE6D2F32BE9BCC2BBBCFB6667E6E27ADE8A6C31C2760BBDC68757127A A2547E9791E20320AF794874983721BA48A7F07AD70E4BDB6ED212F8A94AF5D9 3339A8666AA25CCF01138653180ED15DE309968099C0301C71F9E0F6E7BFBEFA A967EC67FDAEDCAFE32A9566C2728B32B51777EFF4E64EACE6FD83FD07FB2BCF 5C54332D5D6CA9C7164E071A217D9F2301CA75613884D2A0F8C9ADF0C1666DB5 ED9C3F29A9A98887CD5A214CA23303D34C2468988DEB417C503D5E91151DC11D E4535E52CA43B61B6B52C1EC828AADA3EEFE8DD9D38FABCA9C1EAB2BF9D4E991 291AF2E85EB6DDC30F1C7668F0FE21C9F460389C7194E62ACDE163499072C574 C2C954D4E83C9FD2B57F6A0A0E64EA99A5EF09A5D0CEB8DA6B572A6DE8A86FD0 0C5E4CA7B140AC96668CE1F9F50D7C40D0A05023C7FC9B3BB7F339F7F4FCF15B 6F5C7B6A76E6E3A6B966D09AEB82A8BF631BBF373AF8D3FB0347A10F18FE878F AD65664C54F4D941EDAEAD8CC5F9EB3B9B37F6B72EAE9D7BCFD2A993ADD91CC7 97DF7E6324D597BADB5F9E0C07D8F8CFEBF31F352D3B8F12830ACA0289EEA7F1 B64D8372B5BBBDFD84657D646676A8C8A571FF95717F234CA6330574FE45BF63 7D4B671453FE0921574F1E2E7243F346A4AFFEF0DFF7332BEDFE87B40F10A225 CB3509282AD3F78152DA4277EE018CEA6134787A9FAFA666C0F05BA1516C5A2C A9ADAE80E951A6FD23B40BA6EE8F9E527B9E25132EBB02026FC6739EEBAF9FD6 B6AA87A6D5FAF2609ABBD5A68B52027E2BF8AE8D8A5F766C871AA6EE314B2D85 7C3625F10A39A6752F11F77B87FD8457AB4EDDF5ABB1805593458CEDE25D738B CF0A6B214356C904C2EBE6242F8C81EBDC0E839D281D942A5FDADDBE9245D274 1CCED7A9B900DFD4E7BF70FAC2934E9DCCCDFDE92BAFD851F44B6757EC83BD61 616F29B78B52203E36B29A326D315CA7D4833762A3844961528398D47127046F 4CFAB7C7DDD028CC5263C69F5DFBFF787A1320BBCEEB4CEC5FEE7EEF5BFBBDDE D1DD001AFB420004375114B553B26CC992C78EC7E3B1C7BB3C49CDC495A4928C CB93642AA9D4A46AC6992A4FA6E28CCB138F13C7E3C81A499629D1A228719140 82200162071A4BA3F7D7FDF6BBFFCBCD3917745024AA49A05FDFE5FCE77CDF59 BEE305FBB95B497353A6DC61591E17541B8E9D6915032176E198500F1E1FC3E8 67BABC7015AE3F332B0E09B8677483AEF7E47470E6096205B191149984604B85 CA7A43F5A83FBCB476F787B7DF7DE7DA808AB953D37FE7175F627AB4D97FFDE4 97BE24E7F6C729AF0817AC39E189A3327EF9F6DABB17DB9F7BBA589A02966618 35554014DB62280E7F54F245AA3659720D62F2830BF76A35BB79729E70335EDD 1CF5BA93A70EEFF1BC4A2D672BEEDCBAD13C7388D8864101ABF7651537874070 A11DB2F1EEDAE2D96535E390EA14B126105EA98CE6F07255D87FE08B1E7D10F7 3622F2B18A0B68ECF2A87BB73B7DE680D124513CB20034B501CFA410FBB034C8 E128E37E2229CB96524DB9D26977980F4716CA5B983A4DE110927E7D90F69AA7 F6EBAAC2ED7300636D5FA1F02AF08F5C8D47E06F7179114BECB8D9BBB2658703 BFE9252ECBB13E6818C249011A7BA81136BA418C7754069F414CA0B1F5CFECB7 7EF9D9C426107398060FBAC38AAE3F30F6DEDCE96EAF1E7AE234DDB8139A7B56 61DB297C771CD9C27F38397E37AA9E75C46C2A7E40460F23B6504C9F5F26663F 7580CC4A2BF05CBF563088D81C73A210E80D51F2219C45C55522A95083B4E88D 1DF03CC86DED5C65A6ED8975F9F0DA4ECDB79C3DD7A8FAC1595BF00DAE9CB175 F2C97FF80A1D6C7E29480196011F50392DC0D7988592EF0D37FFDD4A23745C40 CE07AD7CA4C4CE206856E1A10D3B63D777ED69AADD94C676B2AEC330ADEDAB56 5A2E8DF5706D343407134F34BD192F8EC7BC6EF15A4074CD9415F8FCD8DE834B F5D2A6BE10DF7AE3E2C2936D7F3E101B4EFF8D6163CEE21F4BC6F581A99A06A9 6A278388C371CDBC09485FDA38E90A8EC764C8118BC7AEC264D8AAC170DDD4D8 4A2DEEF8ABF5F03B8F926AD6FECA62E48A40FBB9803834760CC40860161901AC 0670C8A072E2D1EB1B469CCE3E1D287BC85769F7AE6C9E9E4FAB7B361BD1D5A9 EE8FD74DA7593D535753834247C028C13224CD35A07BE5F15D6B7469332D4CFB FC44F53307D9F4441172C059848B52E9D507374808A0B8143C0ABC047BD349FF F8875DD29FFF8D8F2413828ACC421561784DB6439C74A737B8B737B3EFC068F5 7ECC8AE927CFAA8A0B4E0D683996FB50C0971765773966EF0CC2B2BDF89DEB66 1CB1C9AA75644962F8A952BB564800C3B80BC220D49022BEF6664CD3EAA156EC E486C93D6930E110E6C5DC4ACD4A35F1B2371EDEFF8F6F84C7C7CFFDFC2F9289 3951181CFBC891BC502392C9837CBB47EE9BC6B64947233D4E1538DE342F12FC 47A539C1E6B2BF4D78E2F02A766D89B2E30FC066B905B39C70C56E036C008140 889D92587C906E22019F461AF5A7AD94E782AD1B6ACBB5AEAF6FB4A6E63B32FF F69DBBC14C332FE8A2107F7F7AEE705E3438731CB6CEE41FEDAEFDABED30AA98 0BCA5E1AA5678F2ECE99EC17EED06BCB8D97B3EDCEE6D6179ACB2FEC3F553FB4 D8D95D373A1B8F861BDF25E177237D63737CCAA1BF3C7BF0449A4A390EC184BD 66278A6EE7F166E08C29AF67F2D393D3537BBDAF4F19AF5D5FD9A62EE16E1846 AEE38CB3A181AB6321C65918940A35ED55A86BF507830CD85D99802C1815A854 87E96094CCC45C0D668C9DB23B05B08CEF3BAEE594BA99E4F1CA980F55F249D9 FFC23E9C0046A450605E4AE1B8568E829C054972FC259085624F00B6A0969557 5D72D4C77D3465870D792C5A5D76DCE00F5D6CB56627EA0CABB9D8ED6F02632D 55372C1C7335E14A003FF4F3ECED6E673317F3844C631286ECABD54F3995B373 331422CA70704C3ABE39CC151C3A1F6EB8A7F5B652B7A3F8A62A7E1C8E1FE4CA C6C1F3F1A15AED670E1E51245A20E285F6916BFDFC9FBFF3DD5F7FEED86786A1 1898EFFBCD2D92D0708F98DE3122F791A2C64DCFA285CD538B640EEF0143D3A2 5768C08F15EE2DB7676B752FD3A923B42394555637116D31860DDDB869DA5026 0FC1CFA378AE03566F72D7B4B9F4B3C4CD0DABE6A906F559B7D5F79F99090E1E D3B43674C686623EC0EA61DEBB7A87EE60F7021DF33B371EBEFBFEB5475B1BF5 89EAB1E3CB27BF509BF9FC67E2806694368C00D8414C121F40CFDBD71EDCBA31 FB9517C454DD1D2BE2B5B81A2BB10D67D9B696A9AEE7F986497792EBABA3F5D1 F4A79E5456C46263776DB53DD128A626129D18E3545EBD6F780E3F3C0DA8D001 E4A9F3A49445A486B0FBD6EAF757168F2EC9E59AAEB799DD46695E78E719961D A278BD18DEAF8CD8C6071BE6211ECC35DDB83ABEB4414C121C6E2BAC862ADAB4 4480A4D7C6B6BFA25C7185757C045EB83598B0340FF77A45047808FC0B405F41 C35A6FD0B317DBEE0CC499046CD1726A943865A55F143AD34939D74EBB059DCA 1F44D9E59589A9463461E27AFB0CDCB2372299E148C00BF190CB9785EC139BB9 4316B6FE93D3F6CF9C063A63E4BE49F588AD12B55B1D787B7FB136B4B6F61F5B 16DBABDA1D992933B20AC4B92420C635D3BCCB9DF3EDED7CB5780353F1CE59DB DF57577C149B11C079370838801DC32ECA40A80D943C817F0B6A714037512AFB 3119094B021F06AF1F99AE60C4A57D7FE33AF03FDE98981ADEEDD5F7B5F87EAD 8D5D925B43EBD8D3FFE9F768BAF977796E1AB8437B2CAA02B8057F3BEEFED90D 3E067CC3FC059E47F9684BD69A152E8CEE5ED76E5BD60C76CF57F3BA5E63FDDD 9E7FD0B6670C9D12B94A0749AF75BA6E2EE9488DB95DB76A4D6D198F8B213AA0 09096B999FBF9F0FBFF3C03E68AAD3DCDF33C57B7A2CC2E6A7A6596BAC582C39 E785EF683727232380376BE39E3B0B17781AE4C34D2D70F005DCB86B295CE58B B5296DEBEA6E3DFEC1CE78B757FFCCA23A01511D352315300F1B3B4C70A1844A B919601D4170B5625C7D75E5C8B3CBC6C18141737A938DD68BDAC909ED0FB4CE F8CBD6FAEE66FD8959EFB095B121DCB8211DCAF2980EE1F4F972667079606C66 5B4BC5D2A74F592767531CF70F4804C15023AAD72E020B120B432586E3E55CFE D5EDDBDFB8F8C4AFBFA89E0B32955A096A3625C05675C32AEAE9DA5AF7E1FAFC ECF2CE9D156B69BAF1C471696290A7D88C809F8883B2583002A286939072B01A 5FBCE931A227036F7911FC4361569855D70202A121B135102C2FCF2FBF0A74DC 5F9EC2A9185C388832CBCCACC1712DEEC7EBAFDEBDF7FDABE3FBBDB9AFCE9CFB 7BBFA42C8075B683CD141217AC807B118FE820CE6F4ABA0E103902C721211026 2970C122CD75A6280442ACC3976B30CBAD6EF03B163C1EB7C660D55031642614 0029CE5696E303BC408AE324322B542A891B5299B30E01AE0387C9F85EBE7B99 264F4E1E2EB6C2FF67E74E32E1FCB45DFBB8573B6A581E512EEE2260EF16E4F7 6EDF7D8BF303FB0F9C4C726F75FDFCDCC2E244EDEAF6EAC3DEE085E3273ED138 74B0313B92A3EE6063F5E1ED4EDDF9D3EED67736438307FFAC3571B8DEA88A4C EA482B69683362E60D956C1BC44CE4A9A039639B7132FAA7E387B915EC446434 CAC17C98A5AB137E16460978312C42D870D18BB5C6F4DCD4A0D74BE2641CC3F9 13A2ACC961F1EFF1523D1437E01814952CDB884AB258262B29F9F08BC7BF1E57 F13E9C822AA7A1B1A88749374CFB3D2E80941F07271F2011A0FBB494E184B856 A8928F3B0074B0CD8187719864B8251631393C5ECE0E4C4F01995629EE55C7F3 4350A2C5668625B156E1E0560D09F8E44E3EFAF16E7771AAD5766A3953538EB3 BF1B4D0901CFE078BBF551D6A8E47B3D83A7B607FC248AB22D60E715F39665FF E0C1E6BD2863AE4BF264A6EA3EA7ACB0B7FD2BCB075E9A3E76ABDEFA8D1F7EED CC8CF9DFF84D77435FABB4EF90B037DC1EB9F60BA673481593D4AC622DB4885D 9206D688C92E4E0A3A138D5603702DB6E8A6D8A66CF08C0129E2052FCB224279 8086F3B225ED31FEB2CC1C9E0F33C0FFC251CCBD240BA461D67C3AA93D325A88 2A1F99B5DA0B85A80FFCD487F7372C929BAB64A347FB215C7692E4AE15EC6E8F DE7EF3F2BD950D70AE875E3AF8A9DFF899DA999670224B0B01BCCF62DE38D56F 5DD9DB7E34F5A5E79366C51D662C9821B2AF652F25966D4E734086D91E8F471B 3FB834BD7F819E9CCC5C9ADFE8E6229C3CBA5F14C22C68BCB2DEDFDA9C3B7F5A 39A54AF63862811B8D872661B222BCB1DB79E5D1E4FCA43CDE90F596EDCFEB1C 252489C05139A93A71F74690ABC18DBD6CB43773EE08B12CB99376AEAFB6F6CF D9B3819603EAD3A2E1246847063C394CB6C3D93779B97AA12052A08ADC384EBB 031546F0F671666568EEF6FBB4556F1C680A03F54951EE1BFC1C0A59E6D428F4 58CA84D8C568C01D37F58B77D7582ED5AC53A8C44D14719C117868425C88998E 8ABF4EC47A1E9060C718CFFC83A79D2F1C4FC05671BC448FF47DAAF72ABB95FE BF7F90CC0D2766FD78B8E738C28E091395D81079C0F22B51A513B8670EADAE5C 2EAE8BFA6CE09DF7B85948F0682CE3BE61551C6A59B889881A8F8F4FD9DD6360 D54D0DB2DE880D95A32070B8B9694B6B2CF3DD8A9EEE5CCFD3FE78E1E854167A 83BB6BED63FB4473C48DA121DC917BE2C9DFFE2ED50F7F5D9090F11C6BD3E007 57CDEEFFB9421F8C8D83313DACB97092FBCAF11A8512516F14B41C3D99092777 F3BA7868C851EE2D72D5CCB0483234C2ADCC3F4C7106DA4A53AACCFA8C61D750 235A0FA52301BB59A1656F583B7F75D593B4FAD464DAE4F4FD30BCD9093E3E1D 1D85735B006D048C04C7DE127E617281BB560D65716562FEC944BF8B8E171010 7CBE760C54AE92E0F799916AF28E7AF0F6D5B94FED739E9B4B21D06BF0C95261 37B347212CEA11849D0AAF65466A2A3F7A75B7776FBCF8C5C3DD898755EA1717 C9687DD83ADF20563ADC48EDFF108E1769E3E3D3792584C357C41678436D8E00 6978C5845AB187377B8167872FB5DA270F14AE2F01369B96CAC73E782D6D2840 DE549581D0CCBCE9CAFB6BB7FFFC1577B2B5F4A533C52C46284B01E018655431 51B3E954FFFACDA8D7996F2D6CDC79D878EE947370010CD8065E57AE1E2E0744 4B465866470597A4F720BDB26280E39CAB790BF39AD8D4AE174650E42672D252 4CD5082371E53B74AA66CC3494A973A07A0E18D104DFE5E13B3B5BDF787FF3FA 465F28A3553FFB5F3E31F7DC5309E3DAAA8153B571F0083E3A64C50EEB0DF41D 291F167A10B39E0446A8CA284853015F636759493DB026A970ED25C18E56386F 8FAF1B9B48F157D9444ACB561A144394400321D6EA04DC6F4AEAA119667A0B75 1570A5C8EB4EF4F57463DA699F08F6BDB2797F6DDCFBB57D07CE88E230A3AE8F 1D142C49BBCAFE83B5CE1FC603C7F53FE1554E566A11D7EFC8B573C2F8CABE23 67178F9AA6636432BC756B908E2EDAEACF3A1B1F8C1391EA530B4BFF056519C1 5E5678F45C0B1BC88B640FB51814629AF0E3C1C4D8A6EF843BDF267A7D1C7742 090E68C2F59BF5209870D61EAD8F46B1407E0E3729E6EBCD16EE2426CD5A3D8D D3288EFA511C67D9A8284439C984F18D633E1F7BF44B9E8C698C32C5898B154A DA56B6BCA0C426A6461FEF4E2B0523F1FB8BC7F21865D351C13ED48E2AA9372F A7E6791940392E6FB01CDBC10E1091C719AABA22012DF708B66AD5F9769B2144 4289AB722F2AB10AE24A12480EBFE31A654F83271A9BC6F77B9BEBA46804A8C0 EE1AA459E827AAD513B677AEB04E499FF35E5FEB91698D235CDEB5CBD5DFC47B 3F90E92A31A3CCC86260EF2AA7D94962BC7478F927DCCAF24087874FFCCF8F3E E86D7CF04FE616E676E923A371CB48AF8F376F1BC5CF4DCE1D49E46C6136503C 4945A660012E93C1222B2EF52A30F36103F2B7E17613A690EC18A5E81AAACEB0 C7F963041A40040A06CF37B6A5412D9BD910E421108A2A3C3BAF62CD8C78AC4F B2FA47F651AF55A8E6189C80E46CBD3BBE7CCF8B950E63ECF9A422C9635280CF 70AFBDFBF09D1F7FB0CDC8E2B1D6A77EF333273F77141E96E232467DE16CF09D 1FA3B2C167CE8415D34FB861B554BE5DAA4440E045E9433793C3F7568BFEB0FE C272EE2B25CDF1EDED4ADDE28BAD44E6B56E3EBA72CB393A5F2C34782E0CA915 3A2965A32E9B0EAB9937F2E2EF775019E1A959519DB4AC79809B0C700F805DC6 A5DECBC7778AA8EB8DE8F0E283C6D1037ADA02D435BEB1D75FED1C78E6A80C52 0A9EDC7313DFCE4D16C458960653407D4A1CF001EF54AEED0303EC0DA34E97E6 D2B32D0E6730078370DC99005C9C6101DC700DEE0162029649A9E4C0C6C79A27 A3A14B6CDE70EFA67B371FFA6DC7B6207A0B0124082C50386691A7D53DF6A3E9 FEA5DD20AF749B6AEAD79EB15FD81F09F0489E49D330BFEFD1AC5851C9FFBB61 3D69447C60A80C8CD3958C0BB044B874AB737DA3295B95C6E2FD2B57C1DFCD9C 6BEA69AC71228846595A6DD75CE26023047B8C8A504E0EA2A0A9E228CA7769AE 7CE133B826CA625CCD9EFAF0DD6BE6CEEDB031E75716BCF42E1BEE75DAC766E2 6068D1B129FD5170E2C9AF7E978A9BBF441A61C4FB01ABF31B34FADAC3E1D5AE BF64BBC732C16220FA9E98B66C6B6F73D3A9B1CA9C238D84D360BC268683C45B 70CC69206C2CDF537B7BC3D6F25CEDC0B86C08F049C3271597011D2334617D59 5576E6DBDDF9DEB7AFECDE5F39F2B199A25AA783CACEFBB7FD69EE3FD31AFAC2 D6D4D5407AC08F4A3CDF05AE10D75681B2A248070BE3B18010EE22E2C2661235 5A01F5C02B76D377FB3BAF5D9A3C3DE37E7E213685957303F0014DB9B489080A 06D025CF1C38036E2194D9E5ABDFBC363FBB583C67F7273A353193BF9EAA41B7 76DE22891E5C50C9C5ADD627E78C336EA40634B7EDA2CA7496921DE6D94E3813 FFA0170DC3EA9996F9734718C4641A281B02A6222CF114F64741A0CE2D916B14 073244BBFF477FD5D9BE7BF0CBCF160767EC89A64C064611123008BCA780E9FA D63BEF93643C5399EA6CF69A9F3A5F4C4F884402DB65B8E9A49C9BC465DD6651 DAB08048B7772FBFF69001065B6A3B5353053C23B3024C9549135C205816783D 3A1CE56B3FB05B2DED5A89C3A8E3FBBC955EEDAD7FE35AFFD27677AD97F262F2 C4BE275E7CC6F97483D62DE1B99A550DE00C801A291C8004E7B07B83E26E46EE 29B51BB3013039A162E08265B38C9045D9298A1CA6449BB4FC5D96D09395A314 AC8C83D8B883C315E56C5CD92B52082994B2626A46452659889F47BABE759BA7 9D420D52F1FAFABA7D68A1625657AF5F7F7E71EE8B7E63FFDEC0F6189DF6AD0C 28A9F9C71BE37F39EE8F8938EF9B7E60F5B4FC98197C7661F9B99905CF31B6F7 36E4701875FB37E2E4F2E4E49F3C5819C6D1479DE08B734BC78A512E2CAD4C69 28CD73F03232633B7102FE739FE3D42DF7523EFA9BBC7B2562F099A330AD59FE A16A73D2730B975C5B5BEBC409E03989B54262335AD77A6EAA6983E7D0D4B16C 88673BFD9EA07047D938CDA21C3962B956EF43B2F7789CB2EC63C1E7F3A13064 490E5919D58AC76BF83EDCA95D16FFCA19F302F319BA78CC228B9224A2203FF3 9DC0344C21B071069E6B2253F00EC00BE1BF185E9E9C9B9A69FA2E38281CB805 D80ED191141E6115493D5160209474ECE96A6E4020BCEEA877D6364F1D5886BF C06C0A7EC94AC753C3F053ACFE597B26F28682F071568C000599F66A1EBD9FC5 576C76258CA288181926CF2257BC68360F3F79B87BF9E2E7F3DA4B1FFDFCAB2A FA93BFF9CB5F9D6D3FEB4D3D1CE4DB15E7F5EEDA4597FEF6C4CCE98CD484AA72 E2B940F832DB312D6C41D2580AC19928EC43348C5AC1ABD80A67E2EAC6925BE3 629D1C9B4B0D5A98B6C2B54CF0AC067E6813C72096E9D0CCCBA40F1FDB28B43D 02D47EBE1E3C39538A7F551262F8892A6E3D4AEE6DB294D254B32C2732CEC0B2 71B2CE4FBB746F6DF8D6ADFB771FDEF3F7FBE7BFFCCC177FE573648EE519309C F0FE5FBF39333BEF7DF2A988666E02C4A196923D8867866C86561ED2CDE928E8 7DED03E7E894F94C138E42726F34CED2F6FC44EA190E10F9776ED334F33E767A 64A46E0E5688E51FAA9585C984226A64EE38C8BEB7CDFC823F33A3AA33165B00 CC04F115ED0037B0F6D3E16D956F05D2CA7FDC9169E63F3D2BBDC28CDCD50BB7 B9A9E6CFCE837F30EA7515986191F9191A1DA6BA51749A60BF0DE0275626D6A3 34EB0F4594C011F0B10DD9A4BEAB3CF01EA96D9B06B8358020161338950C6E05 5876418659EC668A5AC1A0B2F7DE8A23D26AAB2A49849D3CC4B3449DF34C541E 1A0F8EF4BFBF4176F868C999FD472F5A2726A304D83920AB1195DB2C17E30B5B F95BA3C6F395B0D83684D2A9B638EED62189055468F5E6CA543053D973EFDD7E 543D5EA99F71B59361B4D3D817A5B936AB105599427F8B4384541A4430922819 8E12961AB6E9C0BB4F3830C8C41A03C8AC4453DB9776C0F21BA75A190B8BABEE 30E9B44F4FC7D6D0D6C0428371F5D8935F7D8526777E8A069298DA582DC65FDF C9DEEE3616AAE410FCC8385C1F3AB4E239EDDD47237F96FBD39E48FA16A9249B D9284BED258B4F1632C9ADC818EE8DED496FE2D874C61E10655BC1826A022D4D 6CAC665819036EA483F1147D33EBBC7F3D7882D3456D87137B6FEEEA1A997C61 42BA391505B30C6A822D9A121381E0E7713935F601194C976920A35C7082FAEE 2E05D3709C0A194A6E56E96A7FE7FFBA216686733F7F2EF64B45CEA2DCCF5208 9C2590E5A2969A1599991BD32072F7DE59CD1EF5E75E3C23DABBDD4AD8C8978A 37803174FC733C5E19F1D7BCA1BF37FDDC62D1CE00D149E594F2E643660230F5 B39B2CBB1615755EFBF993E4988B8251465D17A6048C62139E6570B7E0EDB280 0F64381DD5B3D7B6B67EF0837D4F4FB2530D79E088F65A34DE368B3E158A7017 AC8D68E7C10F2F0585AE1835388BF54F9DCF3C8BA528F347CD12C7D3B2091005 E6C00102D691BCB322AF3FA40EE78766D8C404010F64D5C11573696199CAD426 84ACBDBD7EFA7EAB352724B7BD1ACDADBD3756565FBED97B7FB7908EAA385367 160E9E5DA84F5746F3D46DDB46BD9A0BB07D0F6702B999C111A05D6BD8E77752 7227D3DBA11E1922C5D220462D21758ECD9F10E2CA9C5E598128490F3CF1B2E2 553C1E9FA7BAF8F0574910CBF12485F96AA1FD314E4DECA2320755823DA89B17 AC71B2171EB6A6BFDF5D7B450CF655A6E3CEEEC1A9DAAF4C4C9FEA87B8CC62C2 0B28981CFD5A44FFC7CED63A1B1E6F3BB5501C0EE67EBF7EBC3EBF205CD24B36 FBF76F44E978777EF64F1F6C5CD80EF74472A635F5F946FD9CA223DEAD8AAAAD DC1CA00DCF8996C09DFA1100686BDA770771F26ADC7DC7D3B7C6AC1F8F805F1F AFB78EB24A93182322AE87BBD7C328B51ED33DACCE1D9AAA3A862993B4EE06BE 05764204EE07B32052A64A03394B532068F928C6BD1CEA31C72B63992A891FF6 3F944FC62873A365E7292FF789B272845E60FC2B89A52E2326C05F564ED3576C B3D6A8E36A6EAD33A1934C0C8663C3B1C15AF1F3C0EB09787D64CA31E626DA01 787709C8B408004A4208834068A053C6065059BE35203C8615DACEB0517DE3FA 758AAB99B94B0BCFE36EC39CAFF92FF2DAB3A9ABE4907AFE6E7F0486DEAB7A97 557C274DAE77F63639DF18C51E3100D18F83E2E058140EAFBAEC978E9EFE787B 59DA95DFFF0F7F72A0E97D696939DAE9DD2EC8CBE3EE8522FBDD6AFB050A0798 D42CE6A0BE1A5C03874027C08AE141828F93D25705E55EEAF8E58E05ACD0320D B6A238A79212810ADD1C1C369C3DF8FB0357D8850DC89839140CBC70981B3423 30D016AB3E336B1E6EA0CC9FE9A49ABBFD347DEF96EC440A18726A5BA1362388 8F58DB0993DC94969D591FAC5D7BF0A077637B3408D847BE74EEA77EF169FFB0 95AFDD5A7FFFD681675E94FBDA82482711D4B0637B6464CCCAEA036BAC8261E3 7A147F6F3DF8F491FE715AEBA9E1C57576B86DB57D076E686BB073E5DAE4A9C3 E64C35A1B981DA2FEAF1B01F93788E926A6627B5FC7B9B8527CCA7265565D122 07B0A0CC06BA94F903D2988F1F64C9FD006CE63ED9BEF570FAF8543EE5C02B77 847FF3F5D767665A9543B3A2EE02A363D833FCD87F500C198C3213075380C269 6CAB2B070D4761341A9B09005362553C5671A84DB596A5EE9C415C47309CC371 801BC243866053843150703651AC74D9834DA7EA01E6C8590260C3104D9C0B76 EED3E4E8E8DBDBF2AE144FCF4C7EF5237C165F06D899D61D3BEF91906DBE7283 AD15B5272108762BCCC96306F407F8A2193A6254DF5EDD6807D5F466A424F19F AFCAB9984A81A0A8B0F0187062FA40500B70B6386F8B02B15C258038046E5A80 78CDC148000F01CC1B9956C8F3DAE896956CC7ED43369F67A324352EDA91D99F 38D91EB1A187D3A71808CFFFD677A9DAF8743C24816C76FEEA83F0DDBD76ADE5 ED678015BBF7476D7F4A98D16EB733E11EA6FB212A00D33212D4374C1B87AB51 6DE85A8EDA51E3CEB0B25009F6573165C3864EA55D54A7849DA664E8C0E11536 E56E911AF483E1EAB7AEEE7FE260F64421E558DDCDF61EF6E79F3D2417E07E12 4F628F93F0B432380358871B4339768432A65056025E230ED063EEC82C94EB8C 15847CC3274DB293DEFFD68FAC3D63DF570F1733B21FE98613103D26D4C49176 9C7F4F95ED12DF8B55EAA48EB3AEEFFDF0D2BE9307AC63CD9C6D8D1D524FE6C5 DB430EB0EB88F9E8FB7766DF9DD63F53F8537E2122CADC1C25ED04E309AE10ED 051BAFAF9B855F7D76C67E6951C095D87ECE5037C1C46E40C570BF1991E01A2B B6A056E3810CFFE5CB6A5E563EB19F55893A7C26D486A78766D2018224E17C03 E895E6FD1FBCD7E2B6C52AB4D1B2CE2D8744DB8299D81C5C6680703D29C7A111 1C59E292E66CE30EBDB789027447E678A5C28807562C0B0742240000E0C05C64 E1A3D54D7D6BFFC1D3B6ACA90DBDF6E76FDC7BEB6618AA514616970E1D3DB2DC 5A6AA68D74EC24B5A9B639498A1AB6109ABC4232F8A46AC614314756D86377A3 E256A23686AA67880C586E0E51904AC018A20C848FCBF0E5C4062E7A47468819 3D9CF3C079B8722B4A512E5C2D270AE129E18A1869C4B89910A26A287808A188 D25DAE3B457E636323F53C363FFB9DAB37760B6552F664BBFE65AFF2AC16338E 63DB5695EA61227EE8B7FEEB7B7756E5F0B44FBEDA3EFABCBD7CC8236E63B637 EAEF0C1E2823BCB4B3F59D3C7D4392DE20FB98D3FCC9A99905AEF37CC483A296 D896B2335C7487ABA8C72A4B5951B7BD8AA21B227B9D846FE9C1AAAAAA7EEF68 BD7ACAAB1EE4AE19EB8126D748FCFAEEF6001BD508CBA96DD8C7F74F6D6F6D36 836AC5762D4A542E3CCB96521806CE8663EE53E1A808367C9112006895893C4C E2384D22A01126CD153A2ACB33E14F0749916357144E3B037EB4192043EE007F 4476545806ABB838A7C039371C0B10C5200A31199BE7618624091B67308D8621 16BEB712F80B35B7CA6D57C836B3EB84FB4A191045CADE5478853901BFA61425 0B09DF2E84617A865DBD34DEBD95456797F64F02CAF70BED168B993C9319FB6D BFD58F76751E2A0981F061DDFBAE1CBCDDDDE3DCCB29BFB9D3314D96E75A9BE0 87D4195AFDCA91B3091F0624FEF8E299572E5DBB35DAFECAD2FCF2DEE82229FE D560E7662EFEBBDAC44B5EA591D3498301B32B6C9273383C387F4B6D13C7478A B2F1982801DCDD0140EC301B9837B8036AE25D00F004D0015F6985C3C40439B9 B6F12978E058350782EEFA912DEDE59AFFC42C99B4518C1BA22C709FCDD1E8DD BB64542861F3CC72426A26B8A75E17792601E7A9AC1B926A2F09ABEFDD1A5DDE E96DC88D8F7C6AFFCFFECA8B69B41665C399173F967A16B8233BCA12DC9B211D 6130610FE8B056E57BDFBE6C8741F0F103E1942CAE75F8766A3D335B80E546A4 F3C64556F75A670F27F1D8F56C08A50AAE54682EB0F3170E5056155652CD5FDB 2C2AA9F964BBF0960C7518370BD97D546E83E085DBE737B3E81E4F7A8E6E0F6F 6FA6C3DED4897DB15358B6973FEC0EEFAC4D1D3B346A9995099703D5729816AA 2CAE50E485A651A6D8513B8B96E711E820114AF507E3F1C8742CAB562186A151 DF5883FB242E8AA966C83B70DA13453AA234D22A37CC666A8877EE17595ECC58 394FDCD4E17955F28C985BDA3FC0BF97F57EDCD39F3CD8FEEAD3BA6A18B995F2 58A9752FCD68D77EF8D7179D9CD58F90BCE8575855C6BEB495E65D3F76D46A2D E9A2EE6BEFDECEECA145759E25C69E8D39369C19C7D201588B6DC045A3AA3429 FBCE912CE25E1E5323EB898B14E5D799C3248E1F141D7BE5E24E7BAEDD58A6A9 31C215706F51D94ABCC34144468194A6AA8E6B479E844028EF7E820F6AF93BC3 F5D73EB01DA379A8C5033DDEE80745CBB4FDDDC13DF0E0D5C959C0B8F02347BB 51328AE70FCC156E863BB346AABF3598586ABBC71A52EE019E53F559B31200BF 04C62BB0C289F2D641DE2077A39597DF6A36EDC6134BB1258D903FB87473FAD8 54FDE8FC30ED7936E3D8A9682A302CB821802EDC43E91CEC7E054AC9716E1995 9B011C69EADB7D60BD6ECD9101EFF2EDFFF8A3B52BAB477FEEF9CAB3ED88F470 B00471361C251B8C5433919939B34D138E8F28CC9E3BBABE1587FDA9170F0293 05D3A716E006777CA1530B6AA12B57BE77E5787C2AFFB5C885AB880862CB0CDC 5BCE00140D5D7A9BAE5F5EB38E4D4D7EF9F4B0AD2AB4866ABC8C38F093944601 55C3213243FB32202C55BADFBD927EFDCDC99F9810F39EB7FFA89A9C4D55E6C2 691FF5C0E36506059C68447AF3AD2B0D2BE024309697F5F2549866014E041A92 7D5807C22C290AF5A3AC8094717AF3127BB0232A66F0E4611E549872885B95DA 82788DEB3A1D6DC82CBCFFA0203BB5F6F1E18D78E3BBB7D75FBD9A0EC3B46E4E 9D3CB87CE0C06C50A3868E2A92EFAF032DE073059D75891930E094C025AC3AE0 3F6D85663A28EE8FE58D71BEDEE7DB96CC5299E414A58915020C85194FAA11D5 D2322282F3528FC7E871A4455374B365C1AB1C15409D27A9B0C54F4892145250 80D4800787CCD8E52C163221C5C5BCFFC341E7E0D2A164205FEBAC8221BC589D F8FC44ED5C329A31B8E13A6DCB48F3FC35B7F1DFDEBA9D64E17FB56FF28BC6D2 E2D4B1FE2221A334DADE7DB8BDF6A86A5C73F95F5EBBBD958845CFF9D9E9A527 5118196EDF6E9A6625848B201190078844B91CD334B38A36F759CA6FABE48211 AEF0F0478F921396FD89C9D67E40CE596E185E57F39B32FD6177F3612E305D09 70D5F07CE0F322DF3733331EF4271B0D402B5A009F47C76E0210D3286166606F 307BCC051FAF1157C896B58468071CA89C2D41150C556C47E95E9C257198C315 71DEC4C9B9AA03CE0B9087467DE1728A160E008DB488B2349622D11202212E7B 0427CF48CBB63CE00AB99AAE54271B759F4AF8DB6651540CC7C4817A5E608A43 642ACF8A1C7754A366346D86D9C8352AC2B68579D5557FB5BB71B85D6F8D0544 C156D5F9A4AE9CCD4DAFE258998C45063F3177BC1B52FC98C947CDDADD7E7763 7D1B405C8CFD50B858329ED087C7D5A7F28A26DDCF9D39F0E2FE93FFF6D28DD7 06DBBF7A68F6E4DAE645C7FEE7D1786D987ED9317EF1E489C958199DDE846BBB 81C131EC16B62A90F0D934B534406886B79001CB2E2C97D80EAE30C6CA15D64F F0697370CA3A37118899856BE1A6014E3DEC2332C08180A934957B6CC239D0D2 3ED535A5016EA75E76AF1BDFECD89151E45C65054D942BE1A73399E5F0F40B01 5C0D38C69E99BAE3C8BCBA3D78FBD18A72D4F3E70F1E3F3D3DFF89C3C5E999B4 182A4A1D80713E500F62693CAAB248ED4CAF7CFBC2DC9163DEA9C9381C742E3D DC37BF902D8227F2D5C3DDB5EBB70EBC7036AF1A44E6B6654964FC80B10B8AF6 8887270F841D55F337378B7A6A3DD926E612D327705AD5DDD35418C2C50679D5 51F1A364F8C8759B744FAEBE7B636271CA5FF0D322F649A3FFC156344C664E2D 90166101EE21C03A0712C3722EC7300A03557BD4FFDF445AE26C0045321C2A99 1B6E0098CA20C442C55430713BE7565E50ECC22A2420156BC873A1866CD43482 E2CA4EBAD5B7E79C0CB84EEE989903942367433DBBE0BE65AE7D6DC5F8A9E3AD DF3A4F3C8B470C35EAF4C3202AC823F3EECB3F6E37BDC6BE2CD51195159A36A8 2322BE8E3B763F08ECDD4A12F7123A9E3ABF902DA54A02DDB41128308615554C 0DC2635065B11D8E12E69DB8512A586410C2730DC7D54A0AAD7C51337AF5D1CA 68A7D7D9777696D4C1EF640CE337B7C1572C82771F55217C0A7F543F7AFEABAF D0ECD2E7CC87AAFB9D9562A46A87AA69908A040295E55BF678AF5700A25CB206 8DF5A98DA5EE662731736FD1038759110160F8FE6ECF596E788B6EC22132096A C759F5AC097691EFA00A95E9772DE5586EB0A206DFBA516483898FD64601B392 F9E1A53DB76506478CD4CC6D2C322B65C15987AF6C74A396D016970C2CDAB048 868BEE7829108CFDE04AD90CC79BCD8A195AEBDFF960F4DABDA3CF7E8CFFB423 930AB3536D74C0B28ADC718857C2492D0300E8404104D5BEBC4E77AFDE6C3D7F 481CC89322AD00AB82901D8BDD1FADED9B3AB1BBBEB9FEC1DAE9633FBDFDC91F 5632AB925668087C3C57D538E5DADFA9872F77C2715CFDF231FB278F8634AF44 154681A7835B8BCB02BE0FF65318398EF64A7F74677CE1DF7FF364BD35F37C94 CF4EB1B9739803A2315534CDB18AAB4C0587D5EC24FDB72FDB7E23CBCDDA13E7 E4622349F240324C620086837B462919E059A681C4802B9188DBEFF1477B79D5 F2CF1D2A1C87173EB17C858F0CF576A5AB2D80240FD78CB5BBDD07C5BB2FDF1F AF534BB9CDA6DB6CDB0796A7A85550E0178ECD7042D9289A969CCB8A250FDC9D AF3D1C38140EEA663B21CB87727590DD1CC56B7BC1AA03FE334F520E40167DB9 C4B6170C6EA536A62E6D927CD8FE8129D0521E85FE6D59AB1C2A04F78F1D371A A54FA49D321E193BA218105440EC19C50F65A73B575959D9B2C7AA39B9FF95AD 5580A71FF11B5F5A9E3BBDFA68C130B3997A9DEBB6E4BFFF60FD7F95F2A7A7A7 7F573BADA9B9DE8953D6DEEEB5ADABE3B4AFBDD6BFFB60E5DDC05F4FC329917D 7961DF01456A391C384C5DDBA298CD95B0C8A68F961464A8CF2F0DD192CE68A8 AFFBF402DDBDBBD75BCDAC9F9A997F9AAA1A4D534BF6A91592E0912217C7BB37 A27E86D35646A96C944D375AB601FE386BD483FEDEEE64BBEE19C0DD150EF702 8DD3149312589E414CFE58E18551FEB8E1B3289DD1E35429FCB13068821DB542 2A78E1DCB06D6E1A39FC073C3D030F3EB049F499942739D82CD06992232B2F7C C7A932DEA46CDE71DD5154136AC60D58263D92636B8FC942A5BA492C21A69A98 4DC53916049B26E6C7281DD30180D020352DE2DED4F1A5B4DFAAD71AA2A85A6C BFE53C4FBCFD0970607DA3A6DA31F81919B90E30EBCB3B839749FF8651F4D2F1 84426E90828F45550F80E2C64230FD4FEACBBFA8B5BB30F1AF45F6BFBF73E1B7 97A78F8D367E44F81F8DC8FD5172B848BE78EAB0B1D39D12F2FCE282311AB60D B3A295AB35B769E614C2C4ADA31C05062CDCB346110DAB001C8A9D639FA9816D F38030282AD148ACCB4B2BB770BF89872DB3160D0040C793B975AC664CD694CB 485BA56ED80CA7863777D46A1E44266ABEE549AE3200C334295428805EE67924 65942BB39AC355A8ED5C5DDC0D6FAE8EC0A9CC2D7AE7FEEEF1937FFF9C0AD224 C900926715DA1800DA371347A014D9B5CD952B2B4B2F9D77A6FCEE7B2B795FCF 3C79ACF0BA7447AE5CFA607269BE7A6449D254519CA6053C4C112C22642C6163 91D9A91356D30BDB6422B5CE4E50BEC4D513383CE57624492DE16304CB3B2A7D 9467DB003A3D511BAE0CBADDF585B32D6CEF54551DB73A17EF06565A79612169 016A16B8F1052EAC1459806786A3381C421C116592A65C4053182267245769C8 DC6A96E24C0517400252E239B9E5E79827275CE6A9AF9C7E55C47968746CC086 DB8E7EB8A78D710C105AFB6E0231354DB9E8B5BC99F72676BFBE56F9958FF29F DB0F80CF0326E10ED3FC4E302AC84DF6FE77DE3A7172DE09B6322AA46E5919DC 693A34565CBB92FEC8B26FB8C025ACB38179C2EA9B5BB6369DC491F0C44C0AE8 DBE060140CAE9E61C73AAE1D1224C7D5BDC810EB809D0A3216765FD3D4194EE9 3B53DBB736AB0755F56490990696B17706E24A25386E65B35946C20650F9CC1E 354E3CF50FFF86EABFFA78F8EACEEEFDD1FC91B6E5E42A116912DB81D9DBED55 1A2DA35D4B75E84996AC0F13513833137C82416C2E46B2B3B15D3B54F18FB999 8E2110789559D6AA1225531A129FD8194E798F99AE0B2FFDE6ADDECDAD994F1E 4DBCAEE7557B57867D3A9E3E0290172287C22160DB105C31D46B2C9754632B10 703AB073CB48201A38C524C9F82EF6EBA741566BC88653DDE3C99FDDDDB97067 EE2716ED976612125B31F826B32CB2A4C8C93C3362A8FED8341BC538A6344B2C 3D7AF53678C4B97327E199A6391C7D08BD54F4C7BB973767EDA7E04FD3E9A4F9 C5C650A7F58473D31C1411E07B6F6416AA9D3C4AD6DFBDD1D8576FFFFCB3F962 4DE3FA21ADBC3A382E271F129E46D8EFED03A5B255C2EF245BFFE66DDDED4CFD DC4272D0B05B73E6C482A24E51E4F8EE742E44C63D13F55FF646BDF757DB60D3 F5BA7BFE04B8322C04E6C2F1822C430D245A0EA53D9E5228415034BCF3666D2D 24AC309E7F820054C0DC0C1869B5488163D880122A96BBFBEEB5E40FBF7F6963 BD9B4A3823879DEAB98525AB624BCFC8C0715AAE617252A1B95B88A9C2F53DD6 768A691B423F589C99FB66EEA06E0115F9A32EBDDC376E6572779067994C52B0 3AA3AC90A1B25A79C2CA1E7E2C81C1FF4C2C545F3170E1290563D5255BCCB149 A640B1D854F30C67E264EE39433A2AF4C509D1D5720198BD51FC41763FAA0447 47EEB5DECE3D0FB78490883D6DD6FEF3D999AAE84C35F54122686DFAFF36FD3F BC70E5F3C1CC6F2E1CAF35AA74A6BE1DEE6CC53DB5AB3EB8BFF55EC05E33865B 9DBDE76CE3735663C10D88D22E8261462C7A20129231B094B181C3EB0E84042D B0E1C97406B9BA978BBB35EB9D517710757FB6B9FF7848B1FC2B04D8C91D4BBC CBE3D8F5363BA32B83F1D83174C1672022B66A5BE3FEE2E44CB6D3755DABDAAA 86A3DE8CEB37990D5ED666E0BC5114CFC0EA0C2D918132093E0A7838E51E555C 16A3186E36960CECBB14C8C0B576806A28B09E8C493097288F0DB808D3120215 6898C069E88AD4CD3C9928F286C3044030ABA232872BD776DC8CAB98EA7B5A77 45BCA3E29D7498246983F1436E6DD9AAB4726038C2B30D6D62C6CD4C2CD46885 1F6C5A3759F2A35167D2F01623C3C8D366D57F2AA83F5938ED4C5D6CCA6A86FB 65EE4C3A6FEFEEACAD0DEC5ABB639B773A1D96E50173C645820967575642FEDC FE539393D9A98DBDAFEEFFEC059DFFDEB5BFFCDCF4DCA7B2EA6B72F75F8C76C2 D045D940534F64FA7327CF383A951BEB5FAACE9E2BDCC4531D2B5EE67E7D0067 808455941125F638C1893EDF6775DBE1BA028C36765893A6150994C54D09CB1B 5900A421B6696273D4E70154E133DE72EAEDAA59B7448DF30AA760F35925BAB5 EAEE09302F3888512E0B709192F02837C25C4AA0BC39C091569E922C36E14FB3 A2E70697E2ECD6FDCD6A2FF27DB1F80F9E3EF77B5F29802C6D8F8BC688EF35A4 5FDFAC77A788E2DFBCD7EF86AD2F1DA646347CEB4E656939DDE74581E63FBAD7 DBEB2E3F75BAA8D8699111291D8E3A60082309561178B9A325B5883DE4FD1F5E AE2CD78A1373055FB4E422DC94E0618133C298BE85B324E22D39BE62B358F3AA 336CF55FBDEDB72AE6D3131DABD3CC73B2A96E5ED95A989EAF9D5A90730FA4AC 73D6B2F0DBBA08FACD466A59DACC00A299998F991B3682BB2FBB9351B40A751F 558ED44A63BBA9E56058C455A805E00E9B3143A46906AE94514B32D58FC3ED5D 9CCDA7E08510EE2AA992BA51B9ECAEBDBE3BFB8F7E2A79A1C673E9A75E6CF732 79BF3676E8B7B7376EDF0B9EB51DD31662E8C2D3CFDA198D92C68E3DAE15AF35 A33BE37461BDF9F11A097C03200AE6C8B194AD51314997F54E8A734558F3E465 6F5F51D25E66E0F88402E029486AE40E5BB193CB38BC6C9E50EA489291BC954E 0F6F8FC683707A799F5161B98AB92120A426F5C3CFFDD6AB54FE0F67D6EEAE78 10F4DAB380177A6BF79B4DBF3F1A2ACB0CDA354D81975A83F5311DE71327E614 F65270D9CFBAFD2D7B96B64EB6223906EA673B55125464D56145CC00B5E42AC7 4E66CB9376F4E666E7E2C6CC52CB9A17AA42FADBF9F0E6E8C099E9A2AD146780 DAB09EC24DCC0D606B132D70E00D35C5B0550CF31B55468706C9A8EB0BA6129F CBC86A8AC5D137DEBFFEF685139F3E5279E9AC9223A98784D0724018E04F5E70 225C306FE6B767E438D1E3185EDBCECA4AB2D35FFAC859018C2913A60DBE511A CC0CD77687573AD3C962E7EA76EBD909FD5422A4E9A31BA629006026DCC8E6A3 A9FEFBDBF7566E9DFFC54F14E7E7722C683A0AEED2AC80CF42A5F922225E25E3 56A675A52FC2AF5D8EDF5AD37535FD957D499BD98D69569F57040B8826C5E610 2D33CCFDC299D81D0EAE6DD506963AB8DF3CBD5CEE8FB3D24CDAB68D5BE3B155 9095FA010C85ADE12665165D7DCFD81D8C8DBCF5D1D3998583D1D40DB204E0A9 83DD37D42C6EECFCF85FFFC5C30FF61878B3283B3039FBC4FC5205021CD3110E 08791E200C8381F71AFBD4AE09DB75F9844D661DD9A4402C99F689004E820547 B131525746C6CDACE88C054466B028A1B06B51959226B8E5A50C84C5E30429C4 796C5DE0A5EC112BCA5C0E2D7553B442B9F40C0003C0B53C4E6C969B7D99DDF7 D5D8E4E928DD33F93B2C7AFFE1CEC9F9A52BDB9B77698693C4929DB0BDDF999B DD978D66B85872CC5B8DDAEF5CBB6593893FFEE817A659BE867B31D3F5EFBF75 716F6BFAD0A90BFDD15FACDE360C72C8343F3B39B700412607B6C96CC77605AD A802C770915843BCC754AD05FC83A17CA72C4846CCBB4976C9106F8E7617ABD6 4F7A8B0B51217D167101FCB997C6EBC3916106436AFD381F5E0D078042AB529A 553F2B74BBDE4C3BBD8353D3E3613F8AC7CB8BB376265B8EA792D4E046A15449 06051A35F67A63942B25125959B3010F84AD3438BF89932B9C634A84E25F3168 5E3E6E81E49141ECA0A230007D310941D2A14695501768612198E3A5CC898495 499ECA7C18F586C9789D61D5D0B6CD8AEFD56CABED78554DEA94044A7B1CC78F B33C965258B91FAAB4EC65625160DFD6635209269D4A5D9209A567355D14455B 177DA6D3712A6AD5EF0D373F2832A335FDA81B5DED6C2BDB5512759F84CE0B0F 5E999CC89C3698951AFEE385835F3CF0C26B3CF95FAE7EF305BFFE42D1FC6EBC F9BF85FD3C7311DB8968D27527DB0DB9B1F9923DF1D9FD87439E74C2CE416A1F 2A9C4AAD7257F503831F17CC48E2B45274ABDCA0B69716BCCAE2260009A30297 2BAD2C50639E7945A5DC2F586807EBB37041C23658CDF1AB8E5531559D8BBA45 3D9327BC7BEF91D357AE6014ABD45877C23C7F26589A6981EDB7120707B90958 01CE1C4AF09B0973D6F6C657EFDC8F81F736C9337FE7E9A77EE979D92AD262D3 1187B43B9DF1ADCA68AFF3CA753A3DD97A665FB1BA12DDDD099E7D424C386AAD B77BE5FAE4C29CB334AD8D02E80B60238ECE0FA16D299080C93E8849B9C5AC11 EFBFFE7EE3484B1C9BD56CDE960B70FA154F8AB2F88EDB5BC176D4808C2F5B79 880B15555B5FDC1EDE7ED4FEDCF96EB35F2DC6B6743A6BE9FA95F573278FCA27 25D735B0F79CA516451173E018D26299E1E2A67305BE0DC288A5EC04A731D9E3 0B02D896972B5034921203970894EAF18A817F05D0A69504FA2F721B3859A6D2 ED1E4985A1D177A303905AD60CEB225F7BBBBFEF777E3A7CD6B3B2C2CD9CD8EC A7F9837A97AB3FBF93E6929D2BED9B67B8463A6D0A238D825D6FD44CBEEB88CD 849F19B9E780EDB91C801D2BB52590B83ED6512BFBAE4939988EF3B5986BC243 5494529B0E20F75CA7C44CCCF06E561B4DA449EA1D37F2C5719C47CD6C7ABC12 81954EEC9B2A38209CD03020BE1A517DF985DF7C95EE7D615F3AB9DB5A6E8BB8 9986B4EAC93CDC4B15710F4C2734F463A97755181793FB1A021CA9E3F4C01F74 7B9327EAD5E36ECE8491C011B00A70A3754BC1173A85284B9CCAA0E08EE93837 F6B6BE798B04ADE9A75C56EB247DEBC15D3933D16E1C7609194644163EBC7CD3 202595A3E50257604CF0BB6570AC8BDBB9EB30DEB77341AD661AD81195ED512B FEA36BE9FDADFA1767D9271B69268CB10B6705276D70E48502C45706043EE6F8 AEF2ADDEB057B103FE6030BAFCC0393513ECDF97A591598E7CA722B5B90D7148 DC1CB35D2B2DE8BECF1FCAEA3B188DA5C6F4BD49431AD10208BBB3FDBD07C6E1 FAF4AF3E23AB38C04FA9999BCAA5BE1200F29525C6B820D40657EF67DF7BE87C 7F358D87CE8B33E4282D02CBA94E916052E204973229407C012106C59BB5D0BD 71747B8F6D6BFFEC99E2F01C2A9738367671614444C1DD7276AC54582F230F4D 85B874830E76B79CA4F5E229695BA646640477644760D76EF7FAC6E57FFB4AF2 EEC65A3033478D5353B3134EC070D5B2257C5306A663910AD652781CD8610040 23345D57374C3E6BB31623158ED5162DB135AF507237C9AEC5FA5A646F0A3800 32CE80C4F3B2FF1327DF1EF7339681B01C09785C5287F38992D34C95D74C5142 4CC1E107D69117149042A6639C57320752C0DFECDBFCB574A7EF385E61DF5EDB DA98F01EE5493ECA716BB0C5263DFACBED89CF8EE961E224FBAAFFE2C1ADF7FB C53FFDEC2F7CA1591BCAAD37F61E0EBBFD45BBF2F2DD4717C2E1EDBABD3108CF B1E0A71BF30BA62164886CCCE6E0749A824CE67C58D70ED06CC9CA16D7B2231B 8DC5C881A32AD6F3FD1F15E1D71E3D7AD2245F0816F71173AB41EE9B317CBB97 10DA4B4844879EF7418DFF60674D44798E9B3E09E038CB45E1AF73B34B83870F DB130DBBE10E76760EB7A76CA12476FB959324F8A5B44AB55C88C360ADB8E510 C331844024D6A8B583B36C0657468E6330A43039A62E709F05846F6EE1D4BA45 0B389D3D258196BB58E5243A03249864DB49DE153A027FA0B2A6451BAEC5FC6A C33427A859CF8B6AAE7CA52BA665E1442EE116174AC5698AC84A167921B1673E 97C471D764DCD199E7BAFB9CEA02B5DA52FA5A5844B92923BEBF96A77788BCE7 1A17FABD3B7B3D60A7D2B5710D6C2E3083438B9C3037D3FB2CE7974F9CFE3CF5 97ACE977E783FFE9C77FF12C733EC29B7FD65BF9B32CE7CA03771A1458D3EB19 627F61FC6733A7EA53B53FED5DDDBED7FDEF0F1F9FF3AAAFC7AB571E6DFDC24C FB73ACA9687DCB88BB5E6FCE3671574AE0EF3688B28BA92270A5A11C36021FCF 3D5316E0AA0120E43EBC54C336002A5845C5A03EB32A465E87906945FDB8DE00 00FFFF494441547971DEDDECF018E227C534548E6DB9E0BEB16D2497141895C0 2E96D8F678228A4228A60CDC944285E1BF3D1C5CDDDE6EC24F5283A77EEB63F3 BFFA5C5EDBCED3039EB9E8665B6CF5EAA36BB7FCE79FAE4ED786DFFFD144B551 9CDF9FA9C27E79A54376A73F7A9E98125BFD25EAA35A65A580A21C63392C0367 078E9CC5CC21D97DF34AFBC454BE0CCE7AC19273787956063602F683AD0FCC14 2426836B46D4A5864E4CDB5ACF1EBD7CB5F0260E7CEEB472370A1D1A7472F7FA 70EFCED6C2470FF98B41C6BA56102411B750822F86C891F34A99338DED1C2846 8DB8A3C77A0FA54A1476C015E877CA2D2858592C6BDB280661684C52A03E7B16 C16BC0DD3A726F94F5C6A602AB367419088DAA23DF48B66FE50BBFF3E5F119CB 019094B9B9358CA2BBF535B1F17FBC3D7FF0607C34A2716ED8809E849978CAD4 A13DF686F5BD6FC5AE322B1FB38AF9181D89B2E9DF2E192EF7B594EDE79A9866 B93117F50535B6FD94D28EC861E1E7E48E350C761FEE884CCE0673A3DEB87EBC 9ED406799AF961BDBF3230EBBC3E352154A60105A0FAA61DD70E7EF4ABAFD29D 2FCC56969935ED74F6C04F4E18329151DF6A57E306D6208DAD6CB031682CCEAA C9911DFBE15A12E6E3DAC98AB764E688256D9C726C52D2B650AE5CF8242D5845 843A72BD257247EC7EE3020B65EBE9257D20A63ABEFFC3CEF4C489E0A82BAC81 41CA6DF310C381B79BCA3430258A0BDB189700E92D97A3920C26D1397380E9A6 2EB18DAA759F6F7FE38ADCDA9C7FF1203DD7CAEC942B6D01E6C12627F01EE023 003900CDF44CDB2716EB8FB66D38A8FDBCF3FE8339BB653D339BE2B62D834B81 3A91B805CC17EFF5C4D54138CA9D1353B553B5ACD83331A664AEE48692B19316 4690BF32CA2EF6A67EFD63F9477176DECF0389A2EE0A351320EEDB06CEFA1421 83977E3B1B7EFD4EA3277B6E3F7869561E305DA7623A0DE2B524168C348EBD40 FCC3058E4A65111F67F1AD3DBD2983679F5607A6C08F99B64BCA3575A8658933 6345A9AA876946AC26246372E91D6337EA7BDAFFF469301527050B6412804764 6FBD7EEFBD6FBDDD7D304876E24665FA54AB75A05A052B4A0024D83E2EA6B151 85CDC61D26A6F082CCF71B24294C4B02536C19BC5A9006276D533AE516442072 2395DE8AA36BE3EA1A9119D84F867ADD65AE4297B58D72A7106033590E076843 3D16A1267F2B3783423B003051101A684CA6554E65AEE3BCD8320B082ED5986E 31FD9764F77E1C3F5DDFBFDA1DFE75BE13735289894FDD6D92183EF97B8B93BF D5F3E70AFF1B8BFA0FAEDFF8C7FB3FFE9B4F7CA4A3EE85E95E7C7BF71B373E58 9FAB5BED7DDFB8737B43E4C420A7DD892FB4E767800BE62985174CD19536E01C 4B895D5318C46906409B967B8FB4B24CB433C9CC475A5F90A3CB3A3A4B9DA78B DAB432C2BAB16DE6A3281C84E34C68D7AC6496B3E6F2F77BBBBB80B0F8879ADB F0CB73BC45CBE7C3E1C1E9B931046022662AE0A625B8908AC0C563AC5C1D52EA E6C1BB2C0B008FA54969991F23AA1490A6A644889B42B8E3A8960D1606E82661 34026C01069DD1413418D90944D548D011B86CA063E56B88C0591AAC541F2A8E B72A0B7E60A6D2D6DA4DF3094166B83DCD9C3AF8108D79D9B1567DA9E0639561 0A863BE22C452D4D4297EF125923D6BC725C822A253305C0269A9A325334F3BD 75ADAEF47B97C6833B940E15B027520A25682353A7279BD554BEA962272C6603 F7A3C70F1D58DDF9A9FAF1DDE5F97F76F15B674DFB05BBF16F36AEBF42A8A37C 59641EAE9D603B245FA8D73F3B75E0CAFADDF7C4F8A989C95F5A3C7E696BE56F F6D6F771FF77E7670E70EB47BC76E1D6B59766DD175D8B9BD58E1B843A9EC7CD 2D86085C8EB40198B26968CB515CDB32F2E1D11995C22B0C2BAC12E6932A9044 C7CE5CDB1171D81FA22E120A9233DCAC055C5B69962B8AA3B1B89301488F23FE 3FD2DE3448B2EC3A0FBBEB5B73CFAC7DEFEEEA7D9B9EC1CC608019AC04409004 2841A2291A324559B4251A222539BC842539B42B420A5BB615525896C2A44453 96284AA2450224400CC00166C54C637A7ADF97DAB32AF7CCB7DF77AFCF79D543 FED12FBBA7A3A7BBABAB2AF3BE7BCFF9BE73CFF9BE881B8E5AB816075688D663 CCEA5BCECD83CEE39D769204AC257FEC4FFDF1B93F3BABD4BCA44DA9F6C66FFD CECE4177FD477F34D171F7871FCC9F3C45A7CBC9C188FE3FD7F80BF3E2182C64 AA6D9666096C06CBC2CA39E2C4436958829B1207273BD9D6EBEF2F3EB394AEB6 885C956AA9385409929F027762CCD7891ADFB3821D0A545CA08DCDE89DDEF856 525AA9B55EA9246EDF8C8593CFEF5DD9A5EDB0F5E519324DF5C87001473A16A8 B2065F2307064088EB286C9E3656D1FE8D4FD21C8A3C90436D071C00C6866426 D0F4A6F01BC5B90A543B8EA38208323D8EC37697A6041E4CD12D476CCB1D7FB7 3BDC7717FFD24F4E8E1947199188C499C4E3C7D55BA33BFFEC7B275E7A3E5A1A 7280D43805606482940E82AA7AC2F7BEDD9E996B953E56CA4B43026B2E9D0CA0 C2618FEBE1753AE66303698214A6378763CA48A98D80283861A329B2A8EED3AD 278F9A271AF03EB3495E3BD20AD881A452B6DD9D5B6D7F4DD49BF554A7000A8C 82EF21A2F2B157BEF61D3AFCDAA2EF35229D71C73065FAED416DB6E24C0BD81B FD9D300E557DB66E3B3CF406E387A37CA4662E4C8BA37C9244E5BCCA9815F961 3EC59D7289A59264108F69EEDB1989ED763EFE7A3B7E9CD94773F759F880BDFF 7E0A1F683D3B9B9413B47CC61151A2A52636C96C130B38888079B9ADD0689148 9B5A9067B35C1227ADC30E87BF0BAF1F0CBEBBE17153FBDC9C3A0E789FF9A1AB C73D5E85B0EC70A066905E6C9E4B6941F8A45CE5994E2219AA83EBF7FD5AABB2 7E44B1310A20C0B74A156C968C253228A7AF76FB9777CC949CF9DC7A56C5DE23 AAAD208D5DC44F63522259E0EEFE87ED9AAED77EEE23C31389E4BE1738F0CD00 73E2A1C1ABA6346563E2337B434F7EFD8EBD43D077A53E9CF9C4323D0D89C515 BC6AEC4A2E1C83FE6B29B63DA155789604032752839BED6C339BFEE427F263B3 388480045016D3D487625B85E8163A2B6101DF045DFDCE77EDB68E4B8EFB2317 5549CB202656858CEDCBBF7DF3D1D76F77EEECB925B75CF69F91F52917E89F06 9E1A42D0A79604D40647C1C5D11214E5918EB2EC32845A69E7C0DF7D092183D4 683A23521B8BD0C84223926EE6E1FD0930853C455288E31318B70BDF5DAC991C FA2CA1056891080F711B45FAAA0FFD32F14A14AB7B8A65294D3293247AAC5587 418011E9441DD8F28A6FBE7FE7FE4A7576ECDADFEF6F02472965C6A676DFC2C6 A73FDEAA7C8DCD579DCADFCE1E6C97C83F3CF7A54B8A3FE85CBDBEF3B84EE66E 39FC970F505F3C82CD42AD865F6A3AA2D1ED5F14DE3CB05FCFAA1BBA6A784992 098F5D0D81AD3077C40E158D6ACD592AE5E19D9D35B6AD1B797C25E82E4B795E 345A198B51681C9DD277447A35E8461A7695086D6B9FEBEDC1602BCE50E8B278 48900E2C458E3567962BB5839DCDC65CCD76B91EF5E72CBF3441C028F1A217BB DD003BA3DAA7E18702A5BAE8DB2358DFA42838831E1724A439042D6DB14C9B94 73485AFB510A5887E2D463B81B05D87E8B6109BBE0A5D658E1B0AC986057E85A DD3D55AFD6D2AC94A6AE943E253526EA9CFB89AE325B689EE4649293808B48CA 002D9CC6BEA27E946B473EB2E20E514744E5A8F25C8D059A1A312E92CEA4DBAC 6E8EC71FF4BB0F09E9B8EE6E9AF58214DB86A9E249DA22F48F1E3F3E3F8CFFC6 609BC5B9073CB8C47EA23AF58B2B1F3DF0FCBFF9F637CE35CAE76DFF7F7F74F3 2D41DDACA4540898040D4C24B7A4849D1D5325737AC6ADFA8C5F4D0FBAA9F9CA D1E35F69346F6CDDF9B7C3F844B9FADFCDCF2F8D26D7297973D0F948B9FC39D7 17593A99AD25558BD39843CE1715413C48180C4579B14492D85215F0CF65944A 2FB45C8B246910B14493041FAC52981610476429B6D4024E23901C752D8D0867 718A8DE078679FE0F686D7D9CBC27D416EEF1E0C0EC21936FDD2DFBAB4FC635F D40E9CFE07EDF75E9B24F4E8473F33DC7E381AB7E7CF9F63CCEFBD7F9BEDF5EA AF9CCC19EAF067D8410C4407686CE18E5B9CF6C3580EA988C38AECC78FDFFA60 F5F9B574AE4AE4114916B16B9447861619936638150D6F30DBE3E37B5A0C01E9 F0908DAE8FCBD14CBBBD535D35A5D3F500BE50EA5A7DD2797B3BAC8D973E7946 9780AA8738738263278AA374A99DB32A76CBB088622F94396C41A0853EE0A1C1 366CD7FC700C91E355DCA17126CA651C3A4A4789497278D693FD9E89528BE240 030AF66BB7F3ED9D844C2FFCF99F08175208942C21B13BC987BBD65BDB3B5FBF BEF2B14BE9745FA42A450E01BC27858827F256F7CA6474FB60FEC2A27D42E67C 0C90019E5CAA143AAE605194B30FC77069B15E943C15AE2A3AC6982A3A0BED7E 65E79D3DBB6537CE5536B79ED444D39FAB8DCC5E4996F3FB7C7067547E917AAE 9764D84D0B901C187B503AF6C95F7A95C67F755967CD3836F532D97B70B7BA30 67A62D440C80C66189E7A455B7EA91DDE9ECF7E2BDF90BCDD2AC0B38DB629548 C5B441EC055F71B479E1C88D469A7313F85EE68CBFF366763B294D1F4F8E8FCA 6BC1E41A518F1BD5974A41F33A37D3AE6E6A162516CD24430F732972802636CE 4BE0E8212D8890CD13CF495DBF9411BA473BAF6D76EE6EAF3CBBECBED08ABD61 E859C8640255B24B46A5AC686104D0CC5D1BE76D248EC7F8F0BF5E36BE725799 BCFEC299A444659CC54E4E52EE51373507A993967B53C16F1C048F3AD5179AF2 C57AA2033BCF9971F11695E52A1F58D44DAE269BEF1ECC7DFC52E9D373A36A04 89CDD62E24010BC7C288B420998F8D9DB2C81A7E6B337FF5C974B9B26FB6D205 B1F8CA293545A90B51A8A2A58FD25CB4F012C669698086933C1EB949DEB9B13B BA3739F2E52FE9B516D6BE331C70A685874441FD0B388485348A2673A34EFED6 77ED8E1E7A76EDF397D2AA71E0984C9CF7FEDDFBEF7FFD2E69C30BC98FD5BD13 732D9100E8E63A2763E07615CB68E0DEF06A6DE07FB0E2940B6591541A9993CC B28528F9CC619227751E55E155440E4B054466D8F643A67623DE55388A0B794C A96276222BAC180EAD267272383808A4075DF08AF1B90F270B213DE06C6202A7 8A47298D158D92BC0B81879884F1C759B4CD816A54AE3CDAB89386CEE2DCC67E DB8E2960A41068A6E75A51F4D376FD8F1D39BD1D4E7EE3D1952F7CE58B5F9A5F 9EBE7E37EDECFFDB9D47BF390C8E7FE2B3EFDDBCF5C6A4E319370F8206B7CFAD 2ECE2429DFD95D70BD69AF045B6D4E300F02A507698DC3F3170AFB5E1576CD41 BAC5DBB1AC48A2B190BB16DB9390B5A355ED95C23CC953DB7560F50F58BA4D81 3EC838481F8F06DB5485161D69C9ABA5BD687230E8637B81C1B16F4F91C55269 69797EA7BF65A7E9B9DA74691259380945195A67121CFA4658CDF1321C7319DE B81625649C214A29AA4E25B03E02521C0F00DB497B485857C35ED6ED208AC214 1842806D4A18145088A9085EC2B668AA9A8C9F9F9A59B22C1E84751C3D744B9C 3A463B78C15818EFA015A2C90AA5128A8AB7E1C415B310512335F4E8C0E7D273 7C23BC9CC009B1D3CC41B338E16B76DDA5D776B6BBB5F25DA2AFEFF7925C20E2 865442623F239F6A567F72797DA637F9A551AFDDDF5F99AA9F5D5EFA546AFDC4 D491DBC4FC4FEF7DE7FC6C7DC1D0FFF3D1BD2BB683BA169274D308323D8A734D 501A13E0011CAA9AE1898903611C215F9C3D22C2E0F2C12684E15FB870F62566 3FEA0FFFF9F6931A935F3B72F4133A9182F62C16547C0ECF5E1CA4DEACB26A9E 969514837560F1D4111ECB1CD87492055E25B34A8484223132353C4C2115209D E63CA5A8410851022810C50B3CD8F54094933C0B5D78A0C4569080002AA98440 F43666A4C5FBF7B6816F2B6BEF137FF34F1FFFCA59123CDAFAFEB763BB7EECCC 8B836B57554D359EB9000166E38DCBADD3F3E5E546863EA63CCD951438C46252 C0D3F2309217CD1FF81BCE05DB4F363FB8BDF4D11349991B6BD5262B382FC942 78A5382D898A69583363D93E1B5D4DC89E721C7FEC74AEB72BD32B2C89F6AF5C 9EBB7426586EE8745CC9533DAE6CFFDEEDFA9146E9F30B93B4EF9B32CD536585 C03DB1631DF57A083628A3C14A71F5429E5A8816679914CE6A85BD0FCE44612C F8C34448F182D044099A780CC66A1CC91C711C8E2B4EECED6F3F32B5B5C53FFB 85B015BB385D9E4662C207FDC16F7D20EF8F1BCF1D53953E5329DE7B4A5897C0 322EEF4C6DBCBE030167FEB959DD82B310E3E42D36A3E3250B66E342C9B17881 856423E297C3FE044D0B36C268458CF9F861900CD3C6D9D9D89F6C3E7AB8D25C 93556B2CBA0C0EFDFBD4EF56CD278758BFC0F0C32C3CB26EE81F7DF997BE4DF5 5F39D50B72BFD28CDBDB82C5D6620D4EB8E8656663E4CD56E3650FF686F528DE 89BA2B2F4CD1E9C4A099570DE05B5C4D9DA66B7B0DCA4A59318AC23360BB1527 2BEF7FE38A0B9F5E723B0D555B6FF24E32BE39AE9E3DA257F663B7E70533286D 6E019DB60DB6FD4060B098E562473EB0358FA61ECAC770EC012DD3C8DD7F78E7 C90F1E56D2C6898F5D346B49EAF62C514A8714A28EB2725C9088BB244CA59373 1B5E1080AF88C62449FC5866B7F6869DC1D4F3677599842C72122BF1032BB365 5A1A905D678639372BFBBFBCCD79DEFCD29C9E490114A2F11BF36524321664D6 D81D57C36F1CEC076AE5CF7C9C2E7338F7D2AF1466454C64190576274C604D5C 78346F74AFFCDFEFAECD2ED7ABAADBBEE39C59B4CE2D912697F539C25D1C37E2 569108152F62583ADAE728B2A80737F7B76EF4CEFED44FE9F92A322965B890D8 1A838669A410593FAC9E4024567AD0653FF81EEF84079EAE7CEE7952AA79A3F2 DD7FF9F6ABBFF94E3210156D1F2D974E352B65AAFA6A58A7150ADCC7B5276C62 B8B21C1C6CD390098983E5615BC7562E88492D5BE676257553C607654E5D20D4 70F0B2A4B0F770636AC6400970EC017E35E863807EBCC8598B3B4CE43045CE63 78EB911688A4B833846FA6B4844418650490B61661C6261919A76628D03120A4 FC364BAF07636E95C78ABCB6B731406D595A42DD001A0BBC3CAB69F379E57EE2 C58F5D0DBBE3479BFFE317FFC80C19EE6FDEDE198CEE37A7FFE9A307B7B63A2E E16D213D25D0269E289744EB7E65AE5999B69DA9493EA74CD3E3401F50CD2B96 52A30E6C006F0F65A78C40C13E58676086800E9D2E2757F7B74DCB3DCDAACD84 0D4DA6CA368480284C26008EB80889E90AB26F00CE669B44C469829784BE7BEF 6037A0260833A1C842AD56AF973B7B5BA717169B39F593409262A6D068692836 B0630F290AA3144FB5E81BC55722544E2201085943C6427E6DC90133BD5C4F0C 4B2D6F2F5177061D9E64254DE165A405421694A32A2FFC5EA972669EF1EBE7CB CD29CECA52DA28CD6F6CB47F06E48A32AF8AE85827287697632DCE42C799EC41 5594B0F986F57422389D52B29C11D7B260D359B9AE72896364997ABB2276987E F3A07DAD37E816CEA28E119AA050D89A4D7F6EE5F473995589C2AF65D1DEDED6 D1F9E929C29FDB99FCEC99E7AFB6BCBF7BFD7BCF4EB766C7C93FDBDAB85B72FD 30859493A070F8A18517A3B8D10C45175D60CFC5E829C139889460CBDB6999FE DCC58B6194FEB37BF77693EC2F2D9CF9AFA66793D1FDE18CB8BDDB99B1CAEBB5 EAACECA5DE4C586A1157DA2854AF03007D8C9571A43CEC7934B76B1E2B0319C6 DA1390BE28B3E04840FE63704430072268CB8C9302343413B4E780E79439612C 6295583C1278B5EC8E73C8A3BAEADF8E47EFEF6E66991CCC909FF885CFAF7F6C F9F10FBFA33CFFD8D167FAD76E964EB5E4EAC2E8FDBBC3ED83F9574E1B97A151 067656170214796EE158943EAC9C106CAF2EDC42208FEC47DBF71F2F7EF4780C 419A2DBBEC084600E0F014F703DECDE3859897853B227A2F37FB3855AD1A9D07 BBC3F1E0E8A57383D7DF1BF7F5E2479EC9EA23F411CD1BE65EFEF0DD9BB593F5 D6A74F64B024406D730A7930457F422DB011C646DD60BCDF2D0861AE9F6ABC1F CAE5E2E0963EAC8892A70A5145723C1CE2435336A527513A00B09D03E14531DB AEFBE4BBF7E9CC91E59FFF5C508F3C62992C4EC8481E048F7FED7B53A955BD30 9FD9038217629E6679E08C5C5A17B72B8FDED828AD59AD67EB14B6150461A163 15095A8C851755DB621A12BF7D21BAA48B6EA3436345BCAA175933BB9BEEEFEC 2D3DB3485B766F7F67329C2C2FAF0000546E0000327E379F63A7C2E71F90ACE8 8E83E38E9AF84E5C3AFEF22F7E93A65F3B665C27CC92D1E460F6C4540227625C 1A3C6AD79724AF43D4AE86BB51D4EF565E9971CA2ED26780A81E091B8654E0F8 3704AD638D9DA5513CE251EC8BB5FDCB3707971F1C2B2DF644CF7FA6C527CEE4 F2B8B2ECD00B4001133B2A73EE25A864C8645EF873A3AD022F9AF898F6DD4C00 C2B45DAF620F92D1DDBDDEE5073DA3E79F3BD53C56D65E081B421A5B66852035 3719A0B4C2AFD05624B7FD5CDA1095541A430C7723153DDC1FF646B3E74FEB86 9765231B1E65E666DE814C6C6CB76E8411EB55DE71767F6DDF5F756B7F6CC690 1149E06BC639ABBA23204443ED45CE5675FF5FED88D30BB53FB39E39DA0E2AB9 9423803DDC0682058F2C131A6D0A6F0DB7FEC9F7CD84CE3E7F340B3748A7ED9D 5A31CF2CB3699B784DC23D14C4A0C80851FB03767C9EA97840B391C8F2D1FDC1 F6ADC1A92FFF113357D259D1224C0E4596292974AA9FAA5216FE7E597797BFFB 7B72146EE5E3A91FFB9C200B5BBF7EEFCD7FF97637028663CE79A50BD556A412 5D73991A8B98C85CE0BC361C7648E29228CF8912E353CF2BAE0A201868C76496 B413EE025676ECA0E6AA49D84CD000720291D2183744F9F2A4C87680D20A4698 9BC30BC2C27209E96021B15668A9A490365461E5849B37CB45AAB15D2D83004E 079005212C193A32F950670726DFB4E9ADF1683FCA4CB9767B7F2FC4928C412F 66C9528482793533A78D3CF9FCF36F3CB8F195E9F5BF76F165D97BF0FDF4F16F DC7F38A1F57640DEEFEF7684B66989A71A2DCD913DC7F0AC4BC4AC57CBE72B53 CBC27293C9AC51AB8E373FC4B1B3093703A133419D9C3A38DF9F69C74E01E302 0A71AC83286C67C3B3BC0E29211474EC3194624BF338C6CAC384D3BD2C4A2D11 8DC6772B5E0DF807D005413B323FC892611CF7C3D86F362683E19CED2D57AAD9 683CE3730BD629C65E49CBE0303E10F0421F821FC61486EC148589E0054485CB A8C42E0D03C1F7C0627D0EBC906EEDF77B79DEC6BE0E2A0A2D1F735896860875 3877A4B305C53E3B3B7F8C595E1C799CBBDC6239B1F01A9F15FA4424173C841D 86FA2D026B4A1952910D2B19E82404D02358C9F005251613EE131E61533FAD11 4B083964EA0742BFBEBBF1849A9EA27D88CCB66BE2C826B947CCCBD3B59F995D AFEF1C346CF6E75DEBC9FDDB539295AAFE579CD99F76172F4BF5F73BD72F2DCC D61E777FB5BFFFC0B74AB182638BE39885B771C6E8532AF2B458882536F394EF 4A2248C3CDCF55A71E1E048F4C30EFF0BF3773E653ACF6A63DF8D7C123D91DFD B76BC74F47906980FF941E6791DB70CB3EB04B2B63A2446CCF90894C070EF5B4 5B8BADD40949865A8548698C46729C637D117682AD2890F514D81F65A94CA32C 074A62E12B4C980F1165D2C89835C131F44892C0C9C741FFAD09DDEB1C2CCED5 BEF0B35F882A9D49395D5B3F7F70F34EE3C28AB0F283EF5F29976AF2A513DA46 84C8CDA18D33E6423C2FE4D043EBB0CE08F8082FE57B373746C3D1EA474F1651 65C5626BE8ECC563143D3368FA8EE49F9613D54DB337CAC901CD4A4A4E75B6F6 BB1F7C70E653CFA524DB7CE3F154E2575E5E1CF93BD644885A25B997B4DFB83F 7561DAFEF8344B8D0801C0A4B11F33B4B671E9A1E16951DD290C378B2751D043 7A98110F7D0E8A426E91009F5A70E39F5365821836ECE4A0AB83C481E0CB28EB 961FBD7AD35E3F39FF275F09CA8983F24D61A646F249F8E4DFBCB3D4A859C74A B98C2002D208A5D346A2E7645579D9E93F18555E288B239AC6F0393215A14A43 F41E285CF70E05267561878D521D464909481981601AA5D23862D7ED5E1990A6 2A3FE758DCEBDDEA318FD5966B582B14A43FE88DAE47ABB32F4C8E5CA30ABDE2 809248BC77F722FFD8C7211106FFF5BACB4ABDCE015FA27A8A38A11FDFCC6499 A96363CFE2D6C3CA70B7EF3D6B9313B605713191DACFE36666A61CDBAD621792 E3E6B196DACB46236A25C31F3C39F8E1C1F2FCF1406F93169BF256BB1F1CB052 52FFB81FC8BE93F8DC548D04ECEAE4C074502FA350DC93E87242CA65CE6C97D5 0940D3079DC193763C18545A6EF5997374D119D30DC9533B2F0361C4EB15AC67 14235A3C071E29ED063E18C98659EC12E10C75FFDAED34CF1A67D668C3572A95 1A35EA8929296B53688F26CDB01CE46624BFA3F67FB73FF3F139EB93321F8E85 71323B4874A914F13CEFC349A537AD87BFBDB7F653CF275F70614DDD64D100E3 F4E1C38017B384C49665DB1DA7F72BEFC63F7838736121596051A7CD7B41EDD2 51F29145330D11AF45092442882BFCB0C880164B4427A336CB8752586A27D9B8 3938FAE9CF9AA992C9152A9000CCC784C88B40C70BAF5774EAC568D9DB6397BF 4927E14610AC7CE2C79FBCD77FE3577E30D844E9B39353A58F48A7494420E9BE CB01E603F2118CA93C8568E860E3289DD86CA4D312737DC50B292267040904B2 7AA23D626FC6E3CD6474A631D78C490C5BDA42E1A21230439E6545D70B1AEC1D FE2C3A64CCA1AF42F19317A2D03C2F7C66F10EB1F8FB143D78B18296D1203143 4D23610F8104A769DF97B7D25147E911E5EF76DA51C94FC6313C4CC83AC875D0 B7016FCCAC44B784EB2FB4D283FDBFFFD2177FAC5ABDD1BE728B46BDA8F6FD2B 8FAF65831DA632889779D1B486537694B9F468B3BC4E1D7DD0654CAFB59AE7A4 3B370ED006D675F08253086371F42F09949D6A60BC5149A616BC49D4E6618C05 463514E711BC73923AF0D4B0C32C203A3058B2E9E7699FE927DD839B25FB4263 B1B43B0484185AA42F7447E7FB0056CADEC3FB5B1F595FE7411C4E26ABADB289 82AAED382A67515CE216451D201B1FF0A1FA5521AB069938A426E10A16C14A73 087D63482AC26CE46A9CA94E6714E83CA44C216A84A099D50CAB97CB90D7C7E1 C4A86CDE774EFAEE51C15BB9F255EE419403CC5B5CB633E0125C2AC71D0A33E4 24B1D8380907C301AC80056C360E2BC20686C025F76CA72C50E4054783801125 865AD6B86CFF707F6BA33DCE5A8D51D9BBB1BD1B27381A891E2F4A3DE3583F7D ECD4729A7B79E6E9EC2F6AB5F564E3E4D27465A5B9B235F8CFACB59D28F9B5F1 83D5D32BBDEB8F7E6F34DA949603680918B9219642188C553059845A5554BEE8 87161C14601C0ECA469A9449354DED840D2EB6D2BF7CE6B9ADBB9D5F9F0C1F8C FA7FE5F4B1AF44A449EDAB73CDB7B6EFBA6EF4A9E5C546128B92A55CC8879EA4 76C699B161F7E3A55FE2E1FD1CC60D788746C3E1C2C1FC58BB0665F052D73E20 E95E3C7EBF3308BB31B36A0183959E9C6B965E9AAEF9E14803107724AA1E8C46 0DD7FE60ACAE0E7AE1283F3BB5404F598B5F3DBF707CAE7FEDC6D473C7A264B4 FBCDCB478F9C0A3EB684DDEC38F97F885E0A190A733843AF8B24836F19088E08 CDEEF587C49273E71712ECF93B6AF3159A9AC344585CC0EB2247958D9964EA2D 2BDA21DA4D7923DA998CAEDE5AB9B068D64AE94678F0DDFBCE8CDBFAD88AD269 6A02CF9F8E3FE8EDBE776BE12347AC6797C32C16394402A561A7499FC61C086B 91A19FFE2848D721F3A387AD70E469E2FB501DE3E9C751282A8F22E0EC497F94 0D0307423A2CE97EF5EE77AF59C78FADFEEC27A332606F6ED4C84443713BDAFC EDABCB47A7E9A2022298031085B0946721A4F27189BC9527E3D4F9A8934D454E 0CF9D4896562D2107608B6371C0E4D98427D1E3804C06A5BA824B385934D3287 3B2C12D1FBC9706BCC4FE5DE45E14E2AC18DD499B3F88AD1211171696F73230F CCC2EAE9A0FA10A7D4B1A18F5998D9DDC85FC74438FE9BA7D5760C54B474DCD7 9619DC1DB9B9535AB343ABCFFA426D1967B542CFA30121304A61D9BA4C75CB92 E52A31566EA1FD05A404D2212C1183F6D6E6EB974F342E72DA78A4AF2DADCF06 6FC1F9F7D28B83687A52CE9A12721804030BFB06B44D525B62893EA38E7049A9 92C0E91EABE0DEBE7ED435A3B8BEB4E43F738236F254F73213D95C08E6992803 D8017009A53A31601A266DC3ED1C1646983407B867ACCC1A5CDF9CF486732F9D 150D1AA880A5B9D41C50221061C33608B5685A8B5D4D8328F89D83E86E3CFF85 35733C316378276EEE41D8711CC48A015556E7B5CEC14676EABFFC91E8C898A6 DCD173D85FE14424A1C436693629E78EFA467BEB57AE2CCE55F9593271827813 9027ABBE72D43C3FA54A10A96629E05154C728802EDA677148142ADC376A206D 69066CEF61327FF1395277745167C76EAAC30E19BCA8D4456D9461B91176DEB0 9DBFF33B6AA843559A64F5EF7CFDCA7023B26276F6C8E27ADDAB8481AB0D0030 749D95558E713B857D23B9E568D4F132BE852F5DE912F7B8550E614BDA56064C 59F044654FA2DEF5FB373EB17274C5A9C55CF484844468AB04599CB10B4F0994 C340894A8332C145A7F553EB0956643E1BCB14980951730DD26502F410A571C6 61121036A172CCC420078848F6AAF28DE1EE5E3768CDCCBE7BB07BA0215BB252 01D6035174A81955784D6215CE92E633BEFF3F7FF6C7AA2278B77BEBE6ADEDB8 5B7FD738BFC737529DCD666202C81EBEBF2CA35C649EAD50F95CA9313FD78AF3 B495AAD3315D9072928CD259AB9161868395703CCFD1DC8E14DAA7146D2C1624 7C95C1A768D7E67971FF20393E05051188878C8C549660DDC0EC58F9B5D1DE0F 083DD39A5D18668BA9F6251F5B64C364DB460FB40E32E3974A9DFD6EA55CF2B3 B4E5B90DDBB693C403F299E736821A1C622E3AF2F07A80E83CC12CC83001C21E C8B0F3ACEF3BEF0D0EEEC69350E3E8290E54738EB6C044365474D6692C4F3521 4A8CC2106586B5024246550C8F12C087C98D745D4F383E6CFB4C4FC270902640 65B46F474475FB5D78630B535325D75DA56E2B846400BC38438F3C69EED9C183 B8B7CA2BEBB2B99944D758D416CA8F4B83497C7F3CD9CA6053A1455E2889ABF5 9F6CCCFE64636914F7C6B69AD1EC6F64EACE93CD6987F9929CD5E2674FBEB4F1 64F707D96EEBFCF1372F5FBB11267D6A03F5E545831084D9A719B008C5564135 9243132F7DD843423C8F6769EEAA724EFC80F44E56D20BB39537B7C71BA9F931 BBF5D7A7D766887ADF36FF70BC17B6F7FEF4D9F93F5A6F55D3085860E6DA9655 91BC82369C00072DBC2417581B818789739C3CD3164234954B8BD42B8FC7C33B EDDDDDFE804BB1559A6908AFD69C3AC8A278347CDEAA7EBC524FC3F6DDF1C371 3258AAD49B5629D77AAA9BBECD27F70FC246C7ED39D1CA9FB9F8D9AFBE143FBE EA5C5C3A18F627DF7BBC76F662FF2C7C7B48C354E28CCCA17C7A61DD59EC71AC B214BDD5B92062906C7C70BFBC345B5FAD872AE6EE718B3E4D84682B84D78339 BABC190FCD19B3CB71F20865FAF212DB373B571FAE5C5C2673E87732B93FBEF9 BD2BCF3F77911C71494E3BD9BEE778EC36E9BC7EB7F5D963E4D92AA7C0F1F13E 1AAB42D227FC69DAFB834488A9B9B88FC15B0FF30759907D98139F5E6D229E88 139E997C1444DD21B06A4C849BEEDDB7EFF8E74F2EFC898F4DAC58A00DFA848F 87E91B9D8337B7165F5854D52ED7B043130B9872AA946F99368BDE1A7A55973F 2FC7F6A894B81C18991D03321519B265546147C88422E59AA99428345284B54C 08F6C113A777A7AD6F43784EFCE7855C62D6B6AF1F337BDD0BEAF0A52DB737B5 777FB33CEF7A736E442745D2A7B8F700803037F28EBDFC8BDFA23BFFFD4AD68D E6661AD2B727ED711A25628EB80D21D37AE7836DB1204A97EAA9AF7942439DB8 D335A751CD60E17C47D8B64E391752C5FD6C34E05DB9F18DFB0BCB70FA5ABB37 F79B47D7DAFD2D279F4C9D99C99B09BC21875620781BDF66A8A882C228592E0C 2FD94E0350371DA89DF76FF7BB3D7BA6347B76D55F9F860C391E8C80614837B4 CB5E4ECA3AF105BE8309F62AA1131B0A5111EE181C54A7611ED038F479B9F3CE 8D49AA973E7251D4C524EE3A2ECBD354328766C0C61D08EFB806B94B652DDFCD DBBF75D5036EFBE9055589646E1354048A586A698AEA5B74DFBBF51FAED48FAF CE7EF9029A4D8B4A9E4B06FBD1A4D85BEA137B34C93ED8DFF9D59BD51DABB220 C8053201F2F040B996677F7E397D0E0E6166D30594EBC3F633BC0FA0C55035CE 14C40779DAB52D4992526F8F36568ED38A85C37998010B16689E1AB5E2EC0E36 A1605E24FD1D72F9F7C8A87EEF72FB7B5737B67783D9DC7F6E66A95E2E45F0C2 28A43BC033D476249BC465B4F21EA3F62E60B598DA104705D73C67C02A989D0A 2F61523234107AD2DEEDD0B4756429EF755AC1A8658B945B1173D1F8238F7316 50EDA1960396277401050F7B97C91F6441530845C914DE98292821D528EDAC95 82AC00D44A845CB67335C84940C97E6ABABEBC110FAE6CED4DD76A434277E231 2CAAA3B19D3882EC5F2442DCA9C2CF20E2E4E12FAE2CFCCC4B97443ECE06A36B 0F27FFF8FEC6EB4C47226D09B240AC014D870119A2338F05240000013CE55AC5 7A7166E97C68AFE60041235EB39A79D22436537A331DED8A5454FC962C4DE7B2 344C911D721AB23C764860714B17330F9099326592CC62229772886AF180B6D8 814D9E64A35FE974EAAEF3D2DCFCDA3899C9607349F8FB2EA1FD486BB774BB77 70BFDBB55CBE506A345CDF49E206232D2664147985A23C5AAAB1C243411F3A30 C19B474770C031A4E40F18BBD9EF4316DC48E2A468CF6585349E527995B20BD5 FAE952C905866A005A5BD8F6081CCE176315A13F13C45E0DE93E1EF606491878 8C351CA761B97561958969385ED57320D7C3B74ED3B88B750F3451024CD0182B 57D0276CB2958F679DFAB4F1132EEF92A44DF47BC37EEFA01F70D107969DA932 E501C98E38EC6B8DB5E7B5B7CB277BAE5A35CE5FCEC2FB4FB69FABD48E3BF242 6DEAF4F4FAEFBFFBF66E396D1E3FF2F5F7AE3E4A59006FC144688C880CBEF0E4 282A6F784352845B7437453B26E214934380458082C112454820F30AC72EA191 C36590FFA5B5135F741A6F05837FD27EB891A7FF7973EA97E69666832068F171 DD94745E4F99F0AAA95F8B09CEFD0A475787DEC8CA436994324EA4AC8450C7D9 75D877B7EEFDE0C9A3B5A5231F3F726E9695978E2E03FF2779341A766B76DD05 8430C08BEF87BD8D1F6C5E7BD2D99E6A4E9D3C7AF2D95E9096F34783C9E35DB3 9FE5AD15EBA5CF2E352F96EC8FAD6CDF7A98DF0D973FF9526776CF210E8A162A 54633A34D1C04E558D33F278EB05479E011460726FBC7967A375EAA8D3125196 4AFF04D34B5CE11D618A8910DB830996056D48EB84DE49837B285C44B81CB9B7 BE75F5D4C553F9BA1EA7FB156761F4CED6CEF5074B1F3D575E6CE4A6C3E13B85 F6F0D6F0C9ADDBA77FE41C5BAFA58176806603B4F31392FB8766DAC58FA23C7D 38565830C24357B0E2C9F00F0961D15D5AFC3F4F1240DA3448E2FD3E9C7D01CC 64C37FF0EE7DFFC2FAEC4F7F34E421AA61B2A138E8F57E6B237B90CC7C7A39F0 B79C4402FEC0517122009E440FB2E8EE60EA583D3F89C3207E5E2144243C96A8 7591A34DB8A6020DC4F07E152D48188EFD4B6A9990DABC36DAE8761FF41B7173 52194C5DAA31874DEEC676E2BB6B56D7DE29D19A78E00F1F0DEACFD507FE8E97 96716E0DE13B002F78004569F4CF7F8BDEFDD9C6F47CB9DA2887BB936490BB73 2E5DC8935192DE57A55AC5B924C26602B1817145CBB6A854855D32965025AD2D 4A426E2B97A991EE1F3CFAEEED7A67BE7176A1B37B05A89BABD6BA3B4FA63F46 74331070FC2108BBB16140213D2323830E83656ABC7C904FBAE36E679277A3F9 72C35F9E261766F5ACD953ED3C0B6A392F0F71AD72478C6C27D3B29431178BF8 496E01AC7171280BEBDAC03AD0BD9EC77AEBCDCB2A568B972E88F97A100D6C2C 442ABC864624614251F1902A07B01F45BE985DC9B65E7B6FEE7CC379763A873C 696C9545C6D656CA6377C44DD5BAE65F7DF5F2A9AF9C17E7A68DB298DB189BC0 05E01A69143764B175BB7DF01F3EC8EFA6555DF217ADC96C622067DF0B7CD7E5 5F5C0C2E9504B0CBC344480AD1774455C20095861714EFC771DBB605E733C1D0 732A53C22BEA8BD85C5ADCC715AE75820B54E0823F4820D14AB57782D7DFE95E EDBEF5FAFDFB83940B6785B8EB6E75B3D7DE33A974BD1AB54B9EDB9FF4EB2A39 BDB8522F7900BD52AA81E396F2A2CAE7DBA12D8208C001FCCB0A7A9B4E9227C1 E4DFDFFC60EDE8B1CF2CAC3682036DC6486115403399B19800234C0F4B79C5F5 012A2CE745EF16BA2BA0F251714D68701E0B1F86423D6134844C1334249A10C8 58B2CF48273707F05C09B9DC398090EA4D4FBD75FF1E4446DB7682242D2802B3 8A615E78C6B0F7AB06C83C0B3DF16C12FDFD67CE9F3D31BFB7DFEEDDDC3D68AD FC63AEBF7BFFFDF530FB52AB79E6F8C96B7B0FBF7E6FE77ED1C381754C896EA7 9E25CE4CF47953599B9EAA7BAE95A4E78249CBC6E2DF9EC8F63C3D4461ABAC4C 042C5A8B591E009C3820820696B0332D52BCBACB8A9B1C9B0B38B87D6D02F80C 450246C624FB5F7AFD7E307A7E69EA2463470CA9A2EB2FC9A51B196B274A1FE6 F19D647277309A6FB51CA5A61D67D5F7BC20F073E511834EA987D78478678C18 C729ECE7336380DF6DB2FCC664F87018F45136CA433B4102FF653E2555424E57 4BC7661A9ED6699C42DE1B336B1F92251A74922418F14457EDB22FBD1A47D903 C715CD92DF94B29E9396E135CD2C65D224810C1A19D50DC68F44DEA631E49B55 5939AEDC29065009F2ABA2960DBC36E0F25EAF7FEF60EFE61C76033C6C1FC4B0 1C129BE51B89FED2D4F417DDA959039C241C3BCC89D25F18EEE9917AA531BF9A 4CD69ACDE9E9A3EFBE7F9936A85998FD37D76FEFE78E1240C7635DB8A90803E8 BEF057CC89F8F09E501D564701A9A1D98C1551C3018643AA40C32A408DC68307 4574CB319F599C0DF6FAAF767A0387AF19F677D79E7929E73B267C9DF74333FA E242EB58AA985F0EA6A653A0E359E8E5B11B9523874EA4899204D886C71D2DED EFDCBEF6C1F0E0B94F7FF6E8C23167A8F2F668CE4AF646EDCEC1C672ADE908F7 6E67D23C7AD2E4F6CCCC7CECB23BED271BF71E64DB9D959A39DB842F2D5FDF1A 6D0EB3659B96E478F5274E1EFBF94F0EEEDF1C6F0F963EFFC951AB2F52E6607D B6B847C0B6547A18CA81DCA14F8B46A3800C76C3A36EAF3DAA9F39463C5495E5 DE3A37FF914408D190C92CE50FE5E01184E0CCD77464EDFFF6ED85D523E933D6 8075EB5149B2A987AFBFEBEC9AF2F333A5B91A894699935AD21FBED5EEDDDF6E BDB8527EEE042A874B2074DB5CCF222863E8F0F3B47BF40FB3207D3ABD873F24 F9839C7878C909BF85381042B84C92EE00C2880DCCED71E5EE1B57EDB32B2B7F E26311EA4572A13B72A3BDFBAFEF95E266E913CD5179CB0B25BC2F25B4101EE9 58C18D408DE3FAF9B29E89229D70532EACC853469FBADB7034C390C06372AD08 7A5516CAC68A59DA4F3BE9E6EDED9633CF941CD676178F2FE513D1BEB3596955 9DA698F051D9AE04573231B0BD4BF6967F77763C8F85D9A29085588C3961F9D8 CB5FFB36EDFDE9B5FAB152120FC7EDC49B6E65B54408113E89B358CDBF389B37 86B14A8C2ECB06B59B35653BA818237D588A8915A54EEC00FF789C8F5F7DA2F6 E3D6FA521202BDDCF41C13DFCFA69656E5BACAEA3DA0DFD29451CCCAB50A581B 8874266C8B60AF9DF7C78A687BA6D53C32A316CA71554A15F06482EA0579866A 1B02E2B44F99453900AA18151179891A17F20376F7C37F409F7305C70AA26CEF FAA3384E162E9D11754BC563E6BA45A7160AAE196C51549135ED4409758619CB ECDE62F06AD8797867E10BF3621ECEA217A1597896675139A6417348F53479D5 DEBEF160FDAB2BE668D58433DA2A054ECFA2CA898050BA241EB6FFFD3BEED571 DEC9806895979B7185A972257CB85FAF48F923CBD1F9B2C962972E1A94823787 8EE2A818AC65515A1C25F10EA438C759CCCD3C632E6AE1A21D2F2442D827A8E5 C9F1F8E4B6B09238DD7EB2B97DFBF6E05E7FF2DAE0DAA327C0B229C04C424AAE 14406685A971B1665566A54F5DB931EC0CC693D5A945C776377B7B8D927DCCF1 6AD8F0567E371E7F6F73636E6AF6B3272E3413FA647237DD1A0CFCEAEFF4F655 48FEECB9176AC15EE68C25822507C2512462CA027815BCD8FF454144E9A72D70 A85F88B7D7586AC8D1AA574B6C3F48706A107E46A90A729D48D9A7BA2F29A4DB 87A391DFA8BF3101F21F9C995B7DBFBBB38DD782542A6C4D2BEAADC62ADA8460 257C83927DB0D89FF7FC7FBA7E6EA95AB95DCAFFDE1B6FBDDF8EBAA2C2F2F0AB C7A6BEACDDB5C47FBF6CFEC6D6AD7792D44B3C91EBA1CC154D3ED268CC116B37 1D088BBFECCD5D0C5DE9F4E6A85F5104F69383D0CAEC27C1A6A536DC3423F99A 71CE44723E30996D17AC57651609449E1643BB19E7E83E0FC728258126A130BF AAC5EEEEE359A94F4CFBEBB6B5AA582D05B62947D46E2BB2CDC91D997E67FF49 949029D73FD2A8CE0B594B93729EB9D83ECA04432D793CD2007819247062C3B2 51BACDCD0FCDE4FD68D20D144B794954462A46A3479ECF38EE71CF39EB8A4418 C87C41A4DA63BD13EB9D3C1325DEA0FA2823EBDC59F11A8EA2AB9C5B9C95B8B0 512208F0633E81A740C981C90F543EE262A0D4FE783CEB668BC65DE07E8B3A33 8035E1D4B96C120318B01E67E91B69BF47F902AF3FB6C53B3B8F801343480A45 0AF0F46C6E7D6DFAF81203B281B766F0EF373A7B7F75DC33C659CFE82587CCAF 2C38336B5BBFFFF6A546E356D3FA3F3636E2CCADEA6862C36A0B96D2C36BE7A2 63F4C3DA1B0E463254E32380A9B047121E84C0AD8189D0147CCAC2295BE5399C 733D01EA64A86D89CFF8DECFCF9D20E3C9AB61FF8D4EFB33CB4B3FB5E01F6313 0B30B453335E058EA6934623C7A385473446422CBE002AE5411073AB5C995F7C 34181E30FDF537BED79A3932A1F97B376E2C2F2EB62AE5BB0FEE3973D541AE4E AF9E3AEEB65E9939BA4064B2B7FF8DCEEB79B471BA516BB0D94707E3FB071B4D DB9B9DAB5EF8F997C6B5DD348BD73EF64A5C81F781D751B8B935D259D4B72D78 2D0AAD61C51B1DA71404869BDB2A61DEA95525820412A173CC966B34C6D2E861 22B4B0559B2A6233587FF2840F36341F2565257BF9E01B0F5BEB27D28B254000 A521900488CE49F4EF76B34A3AFDD2115587CCDA730884DE72F78D9D7E37997B F9987BD6C9CD5844B9E2FEA1263C5A401785DBA2505ADCC51CDE1D1E36EC5179 D82A73D8315358AFE174631EC63CD5796FA8FB63093BFAA17FE78D6BCE99A595 9F791913A1E096DEE70F76767FF5DE54E524BF4407F54D7F685B390FED8C72D7 D97482EB136A13FF826DDC014024453CD86368070531854326D042331B1321C1 A4206027A8C3597C1E5B0FDF7FE2297F76F1CCD693DBCE49D2AA2CE4BBA2DD79 503EE2A33C0B6A22ABC1D560C63FC5E7075B530F163A8B383583B93DC7EA2A24 C2D23A26C2C9DF39E113166CF6730B0E6B5903D87F48C334122F657A792CFA9E 0D046DC64E67E02538A5E692C64E039587FB7999A45AFB7B0E3C83F1C660E999 C5B07C40DF172273F7FA7BF6BCD378BE11F8079604FC5BA27989508CD69C55C8 66B6B3B531268155F55A8B00581ADA1799D4C63629DE8EE64E6E9E4ED1A16C0C 1C62B439828D021B01CB39396C1A1710241A722611ECEECCB7BCBBD9C6CD1BDC B2962F9E2255A1754434F604E768E329C8A186126C25B76CF749E6662399B436 AAC1AF3F8C1BC4FBF20CE5133B10916B67327723656524A919A1BCFD6F6C6723 B5FCC72F25D384E91A44086341428F5986CA5DE4EB573B3F7C349D97C69DB15D 96B449555DB86EAD7F7FB73C5BB23E73245B75288A76C227BBF4B0A07058E934 1C3D1B1881BD0A3CCAB62B5C56B00DB3F0E0C53DCFE94467C4AD94F3AADE1AED 5EB9F5F89DF7AFBCF5C14EA4FB13520AA5CFF9AA5F9B6772CE2F55966628FCD9 C686449E01E9B6A5F406834129780CA06998EAEF6CDEBF9127F6CC9223AA7944 3676B62DCBFCE4CB174FDB3479F0E07B43D63C3EFFABAFBD7A6C7DF6F3732BE7 0252A1D9884790B6DD8C499C04CE5391515409859DA94B09154A870C6D595062 0699A11139C3D9AC189E1C1C629E02F0C8D309445BE10F289CB6EC6118248DE9 CD71F7EAE3CDD66CB3EB57EE3FDE7298889919A944EBC3F9E243F140EC27C2AA 0941DF2055F65510FFE2F2CC5F9C9F230B47372CB7F7E4D1B73FB8FAAF47837A D5F91F16677E247265684F5AE6DFC6EDFFF5417B0FF8A5B6D034BC98929F9A6A 2D4D2F3487D1C293DDE7CB3556137363BD64FBCA362151365A2A9BD8913DCFEC 07A3209C680B108DF44A8DB21253096B46C68F7211E7C0D64241FBC28C2D3A61 6688CE7CD9435AFEBDCEA32D2BBBD89CFA682ECF08CB4E20DD30582C40690769 BA27F93B9DDEEFC743517657BCD211CB5EA0AC1CA790386CF4A467C54C3D367B 09269C9C26926CD8E6918A7792F840653B69189BE2A36156A766B5565DAB3467 996C06A358C551C5BD41CD5B079D7E90AD576BE72C678989BA612DCA66192F29 60B0D20806007BACE35196C0FB5582C585912FE1B6E75784857AFD2E0D2AA999 CF780B9EB6CDB17DD43095D13DA62F77DAD6D2D241D5796DE75E776B84032746 241A302871ECE44789FD738D55875BA18C793C8EABF5AF0F835FDBDF30D5FA47 4BF597D3C97CAD99558FBDF5C6373FBDBAF88E33FEBF9E1C64BA544FD291CCD0 3A02B9B6FAB005E369774C91080BE720D4E9A3D830A59F4E90FD81ADF1534E72 C85DD0A8539409FDDCD2916A4D7CFFD19DCD50AD31FFEFAC9C8417507549E089 B16709697CDBD8AE35B0CA7692C2F1439F0CB4394656C68D9DA77C9FE63FD8D9 AC375A7BD7EFFD0E1D3E73FC64CBF27B4FB69F3F7D7AD2DD1F45E3914A076194 6397823D7BF4C8F233A7CF3CA2F7834737B63F98AB952BA5CAE39DBD6873705C 96D78FB7E2D3C4FEE4D2C2A72F4626B01044D978710E101708711A59D403C888 3B1D0E248DB001C0B0EEB5C755BF61AD4D293A29462C8FDA729E60AB72561034 BC2CC032A1964C28AAF7D97043CB4EEE07BCA7F67E777B66F999ECB99911BD5B 33B18865444B624BA6DFBAC66AC4F9D1B5AC0AAC68281C2789E8C13B6DB2912C 7EEE05BDA2FBA2E74C64EE401432028EB02C1B48B23AA662924A889B152B2DA3 69311F42BEC436077D7865885CF1B0E904A09F0E22368E5467C0618BB55B37BF 7FB9727679F18F3D9B5728529930A437B7F7FFCDB5A98553FC3419796D1F5879 9EA52E2C46995ECFD2C7315F74E999DC587D915846D5726E311A60A3CBA11221 CE0E02AB11944616965B4902E94A37B39B83FD7B5B331F5D4F190BAF75C48BAC 2C2BD94D14EEA24795E25159D7838D34EE46CDC5E9BC3A1EF9E372BF648A1A8F 4146623011968FBFF4B56FD1E81F9DD48F433DCAE47C89785C7645B237B1CF94 B3E393B1ECFBBA6ADB33AC52530B29F51B69EE4B742BEE513F811C23C6A5BDDF BE33BAFEF8D88B673236190F7BD5BB8BC9689CCE67B5F3E5A41AA432F42B4E9E 688BD4299D269DF4FECD7B8A648BC7E79CD92AAB79D4938A6768280B98288980 F541EC13879373ACA823A2859B950B89932C45CFA566C545371569960274015C AF06E1E6ABD75BAB73A523F3CC56C621A9C2F65CF9E1443AC1BE0B8CB419175E 6487324B2D56BB4506BF71D3FDC89CF95445ABA137A459C98D19D6CC09F6CC51 2B128FBF7DB735B558F9E49914E222711964018412816D4CAFDD0BFFF9DBD380 C30332E907A22CC5ACD075E35995FEED3D6FB16A7DE6680A144003A99A02CCCA D8E106E24533165AAAE116C2390326A4C5398A3BA05B38E5D2B6D2144894CF3B E4B57FF1AD6B6F5CDDDFDA2CC7BA3491C2999F595A9D2FCBC2A6474A0BBB2E60 1FA6A8869D2471A20C0588EC97CAF57A0D48414DB83C02969EEEC5F14616B583 D037CE51BBB65C2EA726FAEEAD77AA47675FDF519DF6C3C176E70B17D67EFCDC 49B2DB2E178E57A6780245B0C1967637D1014E4E185BA1FB48861D1D28EEAE50 988A588AF1C4A8D4A419564A0CB1321A6F49BD273C9DD0448D7F7F7F6FD09A9E 69563FB876A3E3D9B5F9A5F6EEC13018C3532DDE375ECEFE6140C4DB487C0502 AD4BA94AD37F70E9FC575B0B5B2C7BEDC1A3C5D2CCB568F48F1E5E3FDFA8FDB5 F2D2723F90D3B52ACFB728F9074FEEFE8B308A60612226591A50E370B692B9E7 CACD93F3D58AA7C8607226738EC316D1586E12943809E44449F14E149503DA56 D675F2C12082175DA2D6B45B6959251B9E8AC2C9C92457139207CCC47801AAF7 12FE9BD1DEDBD1F0F9E6DCA798BFC299A7F3121AC7AB98A5699E4FB87F2752BF 3ADAEE27C9B146E564A50169007DF1F2CCE24F6F7F21B970F4189396E13DA9DF CB067B24779D72B73FDC5361E25012AA79C24F54EA4B00E3625DD6A481C2F2D1 A0E4BCA6E2EF0FBA00485E999A3B93EAA99C0176F6045243DFE400B77301C995 0642452855A98BBA3CB772C25308A838A60254C0E6AA2CE414C440023411B220 6F06BC2FE4EB357D5DC76C94DFD9DAD89FF6BA8A8D4743A958C64A9165AAF9F8 4FD5BD2F958F10C5E27C68E9E0A05AFFF5947CE7F10365E439C63EABA273ABC7 F767D6BFFFCEAB5F3D79F4B618FCEDDBDB2361571312D12CC37E39BC2723FFBF 7F703C3C7C8ED89AC4BB1632862F24A5BF3C776CB9246F8F7752939F5C5EE03C 941EF16C5BC98640B31485970D0C5BE8116E67BCAFD416C9DB3A1BB67B2F1C3D 736DF2D80AD5A9E9793A18D61D57081C7C8AB39C7B5E2FCD36C2F1AD5E7B2318 7CF5F49767A75B51D0BB71E3DDF6702FF5F85EBF37C54B47FD9AD2A34BFFE94B AB7FEE93B1D7112A14C6023297A09E5B2AB398A100AD0DD497639B738C8C3D4E B73F783437BF28E7AB391947C417E238E72D8A9F8442F678DA1078021B86770C 6FA1CB461B461C182F60C3ECF16F3F593EF252F6C2D240DFACE71D4BBBC00F48 5EB6EE0D36DFBC2C979CD98F1F4BACC864B00EE5BC4782F77ABDFBEDB59FFE44 BC66B251E0A349E284D9907E3CA16D02215B84091CBFDC13CA6126A534488503 ABC00E99603162A1D0B1C2C0F6CB27810C52D51D923094DD99DB6F5EAE5D589B FDF1B3B9070FDAE2134DAEEDECFFE60F6756D7F94931B1BB2EE0409441A14E56 8F7FD0CFDAA973B29E1F8774DBB3639764CD0C071203AA27B01F212642504C98 549A380061B26EA673CF9A4E3748FFCACEF45C9D9C9F6EDF7AD8086BEC79CA33 B3FF666F6A663E5C089813F961EDE0DA4872595FF1622F482C650FD154B9E0BD 46A2228D1B558E7FF46BDFA4C3BFB51C6CC7D5A62F6A9445FEF051E82DE7EE79 19E190BB476B99F188E59EA4F5B1B17CC37C38E09919E55239AA3279B3BBF59D 77D72FCD667E20A3527C9DF56E4FEC453AFDF18AAA8EA8052FC009B2484962C7 DEE8668C17E5D35C9CCAFD568B6BCF0860FD46A1090E0706108E8792A2673B0E 0B141D759C5B00F894A335840A2D600B6900ADC21020ACD4842ED16EC9BEDD3F F8EE0DB6D6983B77CA788C70D8511386E66548DB0BE99382D623C03410B41D23 620806C619FDCE7672FD60FE27CF86472392C6DE58C04307AEE766B4F013D7A6 A39FBCF3E0D8A73EC596CBB94DE163C4A98EE1DCE7B11FAB8DD7DE35EFEDAC34 E77B0FDB3467A56689CE1255A38E28F56FED788B35EB536BF18C94D461740A72 393B1C18C3AC8CD10FA8136712AD3C729C5A65286D2B4D96A125B4272034EBEB 076FFD83DFBCF3FAAD9050BBEE2D79E51796CE97C50CFCCB34D9D94AE3BB93C1 F57EAF1BA77194E95134E3F86434247998998CBBA632D33AB01B6BCDE9F3CDF9 356ACF4A96E9C960B05D2F79BC17F67626D9EA91FFEDC67B0FE72A9D83ADC55D FAF367D74FD76AA872E0531A475E027089A682C76817935BCA544254578D1809 3976533A00C900D1983C56394F8D9589549189C9A3DC8C9580189BD0F4BA883E 48F325BBEE8EC26F74766E59E4C5B5E3C3870FDF52B128970C7C416C0DD279F1 EB87D21687934BC80831136B07364889247FE7D9F35F5DB89492F1BFBBF9E6BF 7AB07B0F289FA57EBEB5FC3349CB8A476CD1694E9443BDDF52A3BFF0E4FE4360 9AB0AB9000E540B35632BB4558EA27F6BCF3E9E6F2CC589D8CF97C08D908D02A 42251BD5E219772DE5C814E584203ACB763CDED041479A04288F84C515954C54 722E1549731DE45946D59855DEB5E36FEF3E99A7EE7926174AEEB17AD39F2471 16055C092A12E26E49FE9A8EEE6D6DF0541D9B6E4E3B8E97E7AECE1D5D284423 2B41897F062F99986D153EB1808EB324806D46E14B0459386579CBAE5F37DCCD 50D0C897100A13381F3B16FB66AF737D1CCCF8DE2B33D33349021FB508478D50 CBD83C2FA7B62EE633D0C4961DAA32E0183FCEE0A3D90E0A7E09C1EB467986D9 E858834DFCFE447B21EBCED65F9DA6BF7EEF5ABC171EAB4E29CEDFCEC3D170E4 321A1937B3E8B209FFC2D1A5675525CF79A2461ECF6F53FACB83C94EAF9B32FF 9214FF0921CB274FFC56AAF76EDFFEEBEB273B7AF2DF6C3E782BD7AE42BBEDA4 D071FEFF9C08595130783AF706395548A685AFC2D03210D37FA1B5F0C5D993DF 196FBCBE77EF474BCD9F6ACE4A57850ED05D69B9756263CA072007C41012218F A96397EE06A31FEEEF2CAEAEEA9C6EEEEDBC323FA7D3CC33B4EAB90C1959063B 320E23AA80A108E997472ABB7EE7F66B69F2DCC2995796CE7B54BC73F79D9BDD 3B0347F582B4215BB3DA5E98E12FFDB9176B5F5A8A2CECEBE61A52B5A2286F96 1B9325969511E623E381BFCEA27E7FFBC6A3E593A7658D290660B226E4714E01 D224980A709C4E6B9A6982172B5C64C41C6022E40303E87D946EFEEEEDA5132F 67CFAD4FB2276ED8B635169FB9F17347843FDC08DEBC5B3936EBBF386F649801 CA17AED7D39DDFBF166464ED8B3F428F6AB3D76502DBF8B1431BFB5B0129310B 9687449A47E881998B4C70FE6122FC434688480E6271C4210AF527D968607766 EFBFF77EF3E2B1FA674E846C441CD71AE5F90F77F77FF7CADCFA51BE6E4DE410 659C194AD3585165F0D63E9DD0D2B946B63CA67C64A73E30427405E331876D42 B54E00AF96623B2534F48C3D998C99C39DB0B2FF5E07166EF69945A3B2EEB59D 4A73CA396D659374EBED8DD5D3A7C695816319BA4FB76FF51BB35395592BA47D 08E372EC1476A938C28E5D8FF4C344B8F35F347843D6E6AB2291DD8781049EF6 9CEC8BA163AF38E519CC6755C3ED05EC3E000A28053C8C88008B73F8EDB4FBCD AB7E25774F92281FD93BCDE8DBAC3DBDBBF2CC823DE76932C87D03B8CF91F5B4 AD7A4F7AB099968ECFEBE59296118A483047C37E449DA943E11EBC3D84A5A6E8 E16350BF11F228434F2643335658D54346F87F597BD328CBB2AB3CF04C777E63 BC98232322E7A132B3B2C6AC524A3568000909B0C036B06C63830D46D80B5663 1BEC05C66EB7DD6E2FDC0683C16EDBED0170DBD818612484542551524935660D AA21E739638E78F1E24DF7DDE94CBDF77D59422C2FAFE5A6A9953F322B2323EE 3BF79CBDBF6F9FBDBF8FE2BF51C6A74339889C30BEBEB3FED6CAECD47CEBB143 903D0B3DA281C8758A72E1783558D2C072E8057B7DF14A028236BA97F8BBDE9D CF5C0BB83BF31D07E37A87A5D6CF5CE292822960070AC2EC888F6E0F37AE6D1E FEEE8FA755E132E624D8CA3D14D629B4B87277E3D91766C23951D8DD9B1091C2 682A62B3844E394CBBDDABDBB5A549FEC1FD498BBAC849A608F3700C808E9B40 D11113A01DE71EA4793D3ECB5428D4BA377ED5198E327F20CEFFC2672F7EFA35 402DCC634F1C3B7EBC36A572BA29ED8DBDEDBB831B498255C85156445ED4A834 E69A130B9313805138518E2012F8A1D12FADF57B8391E201840948B30F1F3F58 813DA552C7775EBA7C63D33A973ADDBDC23EF160EBB160EA03C1A4371AE69ED4 214B8771DDC23F61900501B5C156E45263B111CBF7164803B0A56AAC8123E665 DF0C2D30E70C2D19E0BD36BBEDBB5B2A6F1A7A274BFECBF6C6E2BE85434EF5F9 BB77DE24D9C9E9D97945DFE86E77CAEFC6016863F243E9B86F2A909517146828 0AAF2C64461D37E9DF3BF7D09393CB8C7BD7ECF0777AEBBF76F18AD9337F7D7E E993D64062C81BD5864EEA997B25727EAE7DF7D36B3B2873CD7856C50DB048A2 FB1A2D9EF7F3D1F00CE193CDFA013F3A24D9AC043C640A40318CA03602843A01 8B0DAF8ACB4CE6911884628B155B39AA52007A6FB210F6AE63786ED408AF41E5 3609F6EACED551574919595A859FE57A4B7E40B5CC9472B89B12B1CBED6A58D9 EC766F6FACD4427F6666C2A459437058E9C030BF545E2B2765B822BA63D35D97 F5E1A04956F72BC378E80AD6E0BC4250111B088D9028B12881C310F7AA94CF6E 6F7489BDBFD93A530D7D99C02BAB58C8D994C1E37ABA95A19E8C0328CC4294A3 76AC0F8E2347AC34472C1D7A299D014E4588A4E85755E52EF0FB5DC1DFB5E9CB DDF6D541DA5C9CD3966FAF6E5DD19983DB918D083A69BFBFC27E74E9C0BE1124 0940B2B9E798AF4BFD8BEB9B43C8C7470E9EAC04DFBADD9E9B9AF90F3BEDE982 FCEFAD7DA237FA4592FDF2CEAD019238405978F90DDBC7DAFF8F39F0BD4488F6 CFE85E55FE1E28921110BF955BCC56C977EE5BD8DB4E9FDF6B2F46EE3F5C3CF1 E1B800D4DD89A8F03DEB23D6F6197AFA4A8762392667D60D06F5F0DDAD8DB8DD 3D3CBD0040A6458673D333324D91B552ACC969AB7018170045668B24751C0FFE FB2A1B5DBBB0D68896970F9C6835A3A6C846BB9B5BBDE1FA301F144567B8D65C 92DFF1A98F46DF7ED4850D9D59ECFA3605B602B0340F200E335F3925A922C99D 8D9D3B77171E7E40389974B56435871F16B485573CF4BD44C834361569C11D49 ED0EE9AF12116389A69FAD7FE5C2C29187F499933991CE7087C94DC501690227 D20D199257BBBDB7571A0FCED3137EDFCB0128D24116E4DEF52F5CA8058B931F 5DE015E01E79E92DE1D8C0C11B5C59C5BB27DE516E07D29D23A3B261E11B5267 980855A9D20D1B98E5394B151926D95EC76F4FDD78F3ADC6E983934F9F4AF81E 0F3DD156C5AB1BDD972ECFDC7F982DF1848D7CC03F3827E6EB4DB27D7EBB1ED6 C3D355393360247565A86C24891136475539BC7AF124A0563172D8906926B5E7 C94A726DD05FEFB51E9AA7D3D4DEEC9BF5DC2EF8E17C35E90C465BC3E9438B99 9B00DB886F0FE3BD62EED0020BB2911D59877BB1474A8C4D34641C097034AB1F 3B0789B0F72307F841294237BBEDC4E970FEC9DAA839A0BC15D416D023A9E6B3 90153CA66CDA81F797B5F3905277CABBEBDDFD8D172AB2DF7AA43132EDB068EC 3CBF0BB970F4C1F585934B2475F08EB52E52A5E5B68D6F0E6BB5B0F670ABA8F5 320A906D16D21AF321EF0125423F6E6C1CA368E4514264F4B3332E5A5C698E8D C628DBAAE1A90D300D54C742155A2144905F58EF5DBA151C9CAF9D39589ABF4A 80C12990450F87069061D1F1CD2E1BBF36BC83E32251A94F22FE4EBCFAEAFAEC 7D8BEE23B0601D9639BE0C0083682040BC3AE283DAA032BAB0DBD91BECFBF6A7 4735DFB7106E35CA9D08D7D94BDACFBC686FDC9A993B1C6FEE02A22C321DB402 6741D8490679B677A3D3383CCF3F7830AB6B144DB453A5086599054929AC85F2 E61077BD724C829667D941D12B8242F7BE12E9BBF1333FFDEBEB6BA3BE07B995 7CF7E291FAB0B853645F1F75AFEC6EBA756721AC1EAF3567099BE4C2A7F03E0B 14AD02E0E07ABA30387603B1CF09FA425CCC928B2A7BE1E6ED666D021E271EF4 9BFB67AFECAC17C3E4DB8E9D78A0B9B844FA65B73AE0E30202AECD33D7F3F0D6 0EF587C6D381D81BD603AE0CE45561B606AC01BC8117D8AC4BE0E449D6117C47 0057606298BF39EDBD34DC3C9EFBD3DEC4BF5EBBBE129033FBF66DB7FB5786BD 8AE72C0A6F7D102774CCD5B1220ACCDF94E2F6DF7455841409560A0898B5EC51 39FA990F9C796469699078CFBFF3D61D2FFBFDCE607D97FCC8A1C5EFE09D2027 4EEB50A5D886089E04955715F9A5B7DFBECC4422003663618648B52882072BF5 C37ECDD72347C925D73FE1042D14D9D2CA872FC269B69A15012460075DD63142 4BCCCE65191E0F7F397565735D0E6602AA2F8724375C3F4E4603AB3685CA6147 16A69EA7879B8D4978C523550811C38651C51EF147946E27BDAE02A0E60209F3 940D35A9181E96C62278DC4BB78E8CAA01454708A1A9CD4AAF0C5DA0463AB765 1D812BF46AA6D2133B929EEF0EDF887B0DEEBD7F727A994BA213209713A65283 A70E9075560B070822FC081C4AC1DE6A52CA929632DFF8070D30D377DC8A32F0 A9358A5A9A8AE6B1602F8BF485742F68CC6E6F77D7956A1BD9EB8D868E084AE9 47F4B3CED23F33D3FADED6642D8505013A860E8F6F72FE8B2BEBFD6C249BD5A9 3CFD76A34E9D3CF16F6FDDBEAFD9FAFBC1E4EC46F6B989C68FDF7C7505A024A4 75742B317F644638EEF4FF0346C8B02B9C58178E942F460DC7DD898BC0921F5B 3EFE432468AAEC9A1879CDCA1C71B2968A1456A00C36440367824DCE33748362 5776B72A41659FF18F88FA76AD6F0BEDD2F222121821407FF8294A931CF5D361 D1B23CC39B03415607F93B9D7435A341503D596D9E6D4C855936CC87B7EDF07A 7F6390740EB7264FFDC2279BF72FC96C8493E106D2754AB01C01F10CA1C54838 211C8037AF0EB261F3A1FBAC19595F4BB48F3AEC8869620B9418B5805C6C69E0 2CAC811D945BB343E2BB94A5C4A1742FD93AFFEEECA163FAD86974224FFA26BF 9E896D6A81142503F8A0F9A4F7423BBDB956FFC4B1DE82E2C35E15C2AAA2BC1F 76BE0C5F99CD7FD7834594FB199C41370724E84622F3714788A1E28392C202B9 70EF25C2B10F04125553AA80029C5714126192A7DD4EB03571F3EDB7BCE5997D DFF2681AF45940DD35993EB736B87A67EAB14390B7329D3B40910A0880B5CEDB 3B83AB716B61B67ADAB7AD21913955516101F5C1E228ACDCC13B76446A80A56A C74D129B447C815EF3DBEFAC8905123C38013BCFBF95F5EEACF90F4E85EEC4CE AD95A8EA89A900753B477CE3D23A75BDD9C3538AC5D8758DC67EE1580EC0A229 37D0102FAD1F39F7579FA1D9CFDCE7D42590819DCD74F9ECBCDDDFEFD17C62F2 3EEB56F84460A37A9EC7DAEF397A4EA89839314A9A2533EDCFADE88B37171EF0 46F56D57369CABB5DD77768285C0792C371503E7CE77EA7A20061B6977A7BBFF E47E31E3E830371EEAA530486361809AD6C0ED4839DA86E86EEC408BB3555608 E2398AA16D24E4A5202F476DE0A9599E09402E4E23AF26E7D7E2F576E3F43EF7 505DB2545057969E92CC81AF2D956DA51A33C272321D4B12106A24972663919E D87BF652D291FB3E74D22C254AF548225C1B1020861CE84D2DF6F75A7B95D15B 9DA1D6331F79349F68D0425005D8D7B8D6D517B636BFF4B5C90A0958B373772B A24196C9EA5C1D186152293870A35BDDE6F165FEC143595870ED3B640AF731A5 DF4884069B8319A67E6CC4E2986930BCE1D18EDDC42BE8C6EFDD7EEE9F7E6973 57B68BFEC373931F9C9D5DB97DEB52779B546B0727E7F7870D580CB7483DAB42 0189141D9D00D6E3852376A201DEF761312ADA9555310A599FA87E21617B6DF6 6027E1CC44DD1575AA9A56C3DEA9ECD8D429763D0910A392A92A2A1C90C405EC C521F7FB789944007A7784F4E1E4403690680B83F3D74A67C06214CB8DD8F69C 5BC2AE98E2409F5C9FF69EEDAE84DBC58353FB5F95C3E7F7B6265AD519B7B1B2 BD0367C0077C6BB147C2A07A0C8A3D7E23B47D732EC4CA00442BE6014E3A61D2 9F7DEAF487168F98CCB9B1B6F1ECA5B79F4D8B75E2FDF9E5D9EFD6BD068A3C4C 1D48E30E572C637BD2FF959D8D7FA7FB23CAFC943BA4C850B098449A1CACD6A6 172B0FBACD135D75589205D7254C028C81DCE0115B234814726152AA203FB0C2 B885757263F1261A5BFD134647948CB8CD084E392BA5B77D9F7763C006D75DBD CE182FF4BCEFCD507D94857E6AFB820F03EBA54941A301306966D7B2FE901A2F 0A7596570DC744880385E5A9C4EB009D1A607A2E760EC1CA3BAE91B2E2B9D8B8 82E11A5D29540EC999F4855D63C1D7DABDCDA4381C468F46FE34C18772A93BAD 2B2DEB515F15BE810DE151011F52A87200D48E35FBCA7694525C2F108E27B88B DDBED8B418617F3CDDB1FA7A4DBC15D2AB2A7FE3F2ED89A8D1A8B75636366EAA 02CBA738F1462B52FF8DA5A58F86914E522902971048E1CFA9E29FAF6FD5543E 154E9FF4BDA7AB2C9BF0FFC9BB57BFEDC1C37F2D7597568B97E6E77E72EFE22B DDBD8A1185469AF3FFE78EF0DEC4F77BEA97020FBB537E4A5DAA909BFD84FC9D D3670F8FD237D2CD17F3DD4FCC2F7E92B7F6AAA30ABE6F9E8502A9212618D7AF 373706FDD7576E3697E78E0593F3315F8B7A0E6140D6007954C248C22BB8A76E 82C3414996708FC3F34F6479AE484C834BC3F4CBD7EF7447FAB183CB6767A7F6 D1C22BB25C93ABBBF18D4E7AFC874F9DF9E16FC9A6B0A61EC16ACB8245941429 9758D0ED7ADC0704FED2BBA4E1BB27978C49B4289481707E8C931662455C2AEC D8340CE5C2C68990E82D9DAE0891E1B56F7BD87EF7F2F47DC7F5E251C566DD42 13793921777C7CEF328B684FD19976D0FDE27548E3531F3E6AA394A4314402AE 03DB1E6D7CE9323D3A39FFC4710BA495993C535150C7A084296F7C3729A593BB C0A0C91F4A84A5340E9E5BA46E4941B222EB77FDCDDACAC50BBA5E3DF0D17379 63A84416ADF1E1E76E0DD6D7E69EDCAF1BA29012CE90A3425EF86BAFDE768615 6F2A8CEE77597DC891CE84196A166B17BBA44BB91F262102B9854B9C22F3D2B0 3F415FF3B757D6AB1F8E14E4C23DDF5C1FC5C966EDB179B61DEEAEAE37F647AA 06CCBFC677CCC6B5B5FAD2A43B2D0C1B31C300B20BED23272ACB235C2BC28251 F5F0B9BFFA05DAFD3F161B69ABB7B14B0F0BEF3E88765A34EA2AAA87B5291E4D C0BF8DC948081BA84A0E870DE23AC0A52F5EDD7DF9F6C9C3D3796DD556B5DF59 D8F8AFDB7E406B9FA8F0964964CA2B1EC9DCDEF584277CF2EC51D3CA87BAE73A 15A11CD787039748E443D1D8EF114DB6C69D2406312FB6CD084E80FC97DDBB00 D6B582C8A9D1B7C6053089D756DBCF5F81D0D2387DC8EC0F0C4F848263552244 66CA3651948EA5656B2F72EBF2A794F2FEB608B27034CD6ECACB9F7F7EF9FE63 FE430BB9D3814C256305CB8C824E942679349CE84E6D86A37780BFEAC90F3F66 AB0DC8AA29013668A221CDBF7461F3EB6FCD1F6F7A4963B8BA4D53F4738E662A 64CEE816304236B8D56D1D3DC09F3A38F45357791E9B2919E17B1784046D80D0 F816FBE705964971060F029DA765EAD4017FD2AFFFA7377EEB9F3C63870E4F86 E78ECC3B452FE7DAAD560FD6A75A43D3882D9AC578BC70598AC65A026DA800D4 1799C0EAC558F713C866D5B8CAE53A02CE0DDB9439F02C31A417E08DD838979A 4877D5707A349D326D7D27C94615CF3759A12129E34D2D053AE3A25838514AB1 02071B4BF36A401A44E76AA4F5AEA07B0292A393E6ECDD2CFE7DD9792A9C7126 1B97E2EEC59B2B954A8DB526DFBC7B0B3EA68386ECE82283067602B1F537DF08 DAFFAE4086ED40A8F3EB145A4E11F90F3E74EAFB668EDB9DF4E2DAC6FA6CEB97 6F5C797B6BFBC7970F7E6F9654039A352BCB9DB4D7E4F58CAB1EFF7455FCB5B5 8B6DC2BD11A4371AA3E32AA956825AB33E950E267AE953E1E4B74C2FB68ACCCA 141285436D8046C544E21D084EF8A11E064E3560C6234AE390037532038C8DA5 D4623A24C012CCAE66A1D6B2483604BD5C149BA3E4D8FCF4BE243DC32B15EB75 394D59EEE7B124BE14EE1E55DB2AEB9822C72E0D34D5AD50A06BB803B0E988E8 0C189980CC5CC0EEF7855FE459846EB9800939064F6B5CE1CA519EC87C3BE237 DCE86BEBBBAAB00F45B5FB7DDA727347B02A8B26555833B0B564CE51191E2734 50C310AB11E5FE433CE9C06EA1B4E230013F395782B29C9910492AEFBB742312 EBC4BEB8B676D1251BA1073F2F28443CEAAF73E64144041CE49013DCF9A9A5C3 A7F302F512DC80293DE4E4B369FCEFF7BA07737B74E9F062919F483A6A3AFAF5 5B6B9F7CF4C4F70F54733DBBB47CF0D778FBD7DEBA54A0BB2CC3C1893F8E6699 7BC5D2125A79449466433CE4F6B156FDF1F9E9AB1B6BAFECF51E3E30FDA970E2 ECC640CF06104264C44751E97C0DC91018AD00DAE226DCC6D64C00F2EE664983 EA4C42EE0BDCA04853F842FC1102125191C38973580E278191404B9E023FF7B6 B4DD12EEAD7EB2D3DB8BFBEDA5807F68E9E01C9B5C4BD997B7BA8D46F74FFCDC 0F26EFF78776670A58602A49E8A24C4C5C10C71B38C02F0A73FEA2BF3CC9F6B7 2C2D321303300BFC5354D571AE12A1A3832F0FA70F51B99DB382E84D95DD769C 046DB836B2CD772F2E3C7646CD2E49358DF55FB39266574239905EC460DB3A79 AC0CDF08F7BE7063DFF28C7D6A6EC43AA171549A15CDC07B3B5E79F5E6C243F7 07675B5DB5D174439258ED39F0011D05C4C2D78E2E9CC2CB25EEA552F309BBE8 C6EE85E5E115902E939CE6328D07C196B771F9462EDC03DF722E6F0D733AA86D 45F167EEF477EECC7D6849D57D92E3F09DC8EAACA757DE5C9D8E96FB4E5A3FCD ADDF0B6C08712DE5F8533D8DEE18C00AA54C80A358255247BBBECB2F91C10B7D D5A4C1870315CA5A6F62EF8DF5FAA2470EB1C11B08CC1B2782D42F4235915C1D F6DB7BF3F72FAB30C9640FBDB94855973601A88CA351929E30FF5E2254FFFC48 7CC1BA0E0F1E35BDC9A1539971EB4DDBF09CEA24CE507B24E799B424821310FA 049EF0ADADBB5F7879796992B54699ED44DE7C7C5EC59792F9C7E6060FED3990 6BFC59B34737AF6E724F4C3F7A98B8A3C2C9157319F3E08D0B2C592A045B066D 00CABBFB7B763EA5D82B3242D871182AA8287D28794C5288BDA11F41A870467C EFF5EB4596CE9FBBCF4CBA806B04964F0DC36B64F25E7FF558C1AF9C77193B80 E3A5286061DEF7F6263796E21737F7B66F2D7DCB493DED4A53EAB140F087D02F 30E073D26C4FECCCECD47AAF6CD0C966EDB153D4C38E80D8518615CD3DD3FFEC 790B3F7789BBB749B2DDA539D6C9FDA980EFE7AA01C99676AFB4278F1D101F3C 36701200323E9F41CB9B524AA304E470548542E31087A1D07AD9200B0BC1DCB4 88B9906EE6BCF65B6FFDD6AF7CD1EDB27A3A3A77DF62C093AAE7D5846762D80C 004A145AE90ABC6CB7CCC1EF8388011601C0BAC21B373C3CD6BA35ACDE602BAA 762D75352E2E044960A939C764592A5B19C1AB00B96005B04709FE8CB727A83E 85456B74A5C16DC3203AF4C746F324C98B18A58A693FCBD7EAEEF3C55E104E4C F79C82FAFFB1BFA6E4F050B531516D7EE5CEED35A3208863D226A5C922A03DCC F2657DFB9BBBE6BF49C810201162023C6FC6755C0A4C85E1CDE4CF7FE0D4F7D6 E769E63D7BF5CA7FDBBBF3D9449AD0FBD1D9437F512A54E1A8786156EC54C9B4 F178C75E999AFAE9BB97BED21D121C408245290265E782EAFEC5038FF6D31D9E 06323DE7D51E13515D03D9D2A8FECF2C9A3FBB98F52B7949C1CA435E9A0CA3C2 139340A26C618173D298932E3119D13D4D539BC1176505BDC3C52B717BB65E79 B860A7881F7A15E53A453EF0489A1391339132DBB7B65DA4E86251C23D8F30F8 854AA0381EA733522A6859214CD9B08B8512F80393AA1403773C406A32C9072A BD5521E733F34E7B30C3BD8F4D2F4D177B754F459E1BD9202CE0DB96A9CF48DF 7170748D972678088CA8A351672F643C0222881414EFE801952A6E84B2C021FB 3EBFE0DBD73ADB9686B599A5AF27FD6757AE671A874CA4E33A68828890F2C3AD DA4FEFBFAFB5B1818512EEC201EBFAEEAFED6E7D7A38088DF6EBD5F9A2F89823 E6A69A5FB8B1F6038F3DF8D4762748D9D5C6CCD50AFDCF97DF78A6505AA0BCD6 1F5722C4620BBC45A139A418C246E85C234F371AB2282EC5C97E3FFA997D873F 98C9A6C9E21AF584F0016B844E16F08C9AC8091CEE9432271C1DDF50A3CF88A0 9C7837E3C972818B5706146CEEB3A5AC5269BE077C4C5299E1126287B3A39152 BDBBBDFEF6C69653F517E70F1419690FB2B9E1F0237FF33B5B9F3AD1753660EF F93A2C0CBE789EE654331A0672676FE7FCDBF38F9C203311C6063352B2EA4068 679304CE0F72799CF033400DA98BFEF6C0C0ED8E2CEE30DA434B953B83BDEB6B F3674F98C96945A71D5321764F1577597E7BC4A20A56187A893FB264A6F226DD 7CE1A2F7E864F591299E0D35B5BBA19D4A987A256F5FE9CC3CB1EC9E8D8AAC23 18D0660FFD6F310E301A0400FBB81A94DC9B8D27E949D9C53F1EB98773CAB001 485159901DBEF6FA8551428E7DC707D399BE66A3CADD20FEBD957EF7CEF407F7 B166A887868ACC1935DB17EFF0C28BFC7D7B69BBF98020EEC09581855CE8A33D 84ABD13D05A82B364CC2E161348F3CD2E1C957B7E566428FD2FA07A6D1C471D5 EE5C6DCFDDBF60A7B3DD17926AE4FB27C448C7513CB1F5CEFAD474532C350AD2 D576E402FCD3410187ACF4CD01B28057ED2CCC6AC71EFF2B9FA7F9DF3FB2B33B 9801DA31391C4E286761D1AF4D29AE59D5B32480734F044D434D06851F55E44A 7CED375FDCEF7AD5A3ACEFAEB9ACEADEAA6FBCB413B4A2C927277727B7ABCAE3 7125B91E1BE1358E4FA6AD51EE015605600BD894A3753CF398894AB7C732C472 72CFBDBBD4E02C271D58D95759CA8C615D000EA88BB92677AA6965F36BEFD83C 9DFFC8E9E1AC4E477B93AC6AFB05F1024E47EF0553FB9E90FD781611FF1F3099 52928D0FC351F3DDA9D5CFBD5B3FECD49E984B21D58B90E48595193C9DF180B0 7057D5B7A7776756FDC19B6DB6BC2F7AE8388A8A02D5087190D159EFAE7FE6C5 C5895A528D9D9B3CDBE97389BD1EDE74E02C71D9443D84D19DB8B16F8E3F7968 54B12277BC71B30C7607B071D71E2A54C339629811F11729E75401213B0C7867 3472BFF40B9FFDCA7F78A1967BA7E6A7165BDE944F26132D0669E1F34108A107 B5E90476FA619A8038C7B1F4859417AF42D93DE74A9CDD0728C8DD0C3634733C 6DC35C39067B1E460EC47EE149114A78C02E2B637D791B88BAF8C20056B4901D 4BD1506C638288E5F4F10E324F54616C07423FA3E9A8588BF8EFC8EDDB7BA34F 4C9EA8A4DECB45E799EEDA2CB3C05C6FF47A1B90F858D9AD8B852B8B326728A2 4585C4BA84FAC329707CB8CA71A97BEF4D70C737F2C881C9BD8DDD9F3A7EE22F 1E3A1533F34277FBF99DF6EF6DAD5F1BC47F6A6AF9C745F53E1DBB759A689B87 8C26AA6AFC2DE2FEEE28FDBFD66E5F83EFE4A17D395EC8690891DEFB9D8A737C A6E2D8B323FBC1DC9B020E2E8A1C5B65300541D615008525BC1E54682F359271 4D39A653F4AC93188AE01DD1A145C9E64D4E776852C0DBCF9DDD20FC6ABA1B67 A34F34E78E176EA35249B3B422ACD5C31415E2515A3A23E8293F9438F763CBCA B043B957220F8A92ACD81886FDABB066E584353C45A625F3B1AEEE2806103D2F F42EC95E61F18B3B386278369A7F2CF4266C5C0B1844D0D0E02D0EE458B7845A 0EC1EE07F856B654F2C4495D6542CBAA1C3201DAC362BB2E8E22392868847EAF 7CC4D82DA62E436AF36BDB2BBB173ABB177D13FB02B88B34F0DD3D05599998EF 9D69FDE8F4FEFA4EDBB89C3A1EA4B3B540FCCBADD5CF0F06914727A6A64E56C2 8FD52299A45F7DF7E68F9F3BFBC0DABA2EF80D017B84BF99F6FEE1E66ADFF5E0 D8FCF12542F83C6839CCB0A6534A783B2450C0A43800883F3931FBE7824628F4 85BCB32B3B1F99DDB7189B894A308C8874ACCF1CE27BB1CF1DC226124A8D1E06 D497D93D7C04B499972B6871F01371912DBD9B10AED160487BAE190A405AC544 2ADD42637475AB5BDCFFCAA0FDE5F60A849EC3229A2F2A071F9B3FF713EF238F 3A9664B627FDEA445F1847E6410628C5C9B736372FDE587EDF19D2F460B32854 77AF3BF620259384493C42A51E284ACA233504545D10BB2DF35B8CF50509E5ED 78FBC6CABEF79D31130D4D5BC2D6A9CE35E95879D1A2E9169C6048D005BC402F 6FEEBD7873F5D2D5E34F9D728FD650283D19C27344F162FFAB5BBAD36D7E6056 1F439A1990AAA010605017033570B4CB9CC13D2308FA07A384E3D9275EBA16E2 EC94917CB7D83C7F6BB8AD8E7EF2C978A147785EB9118E9E5D1924EBAD0F4C93 8A6746867BCAD99D58BB78B9D99C71F85C6FB853392279251332B2D6D31EE003 ED480F6DDC782694A1434DEA131238C6853EBB9A3AA2B0C774E3C1293A74D26B 597B7D67E9FD8735EBF5DF50CDD9AA5D2C10C2AFF1EEEDEDB94333B6E1646608 A7D6B510EA5DC94BD3A652270055377898548F3CFEA3CFD0D54FCD7887DD70C9 876CE52C4C91992AADD7718615502C1334AB409ACADC3E0FE6DDF5DDCE9700F5 A6D3732D51DD25B558C755FBA627D7B3E889E9D1C2907B26DA6EAD5FBCEA4E85 93C7E64D04FFD060CC8697CBE1C8708A763421A551B988B2A400A6B41645AB29 5DDA5F71404A250127E846A69493D39110DE9488DD8DAFBC19D582C6C34B8330 46DD5E7846E139311105A15EF11EC5C00B5DFA9EAF4BC9DFCD373A31004B99AF A9F62BD7173E7E502FE4992121ABD142E245926B9587E6B15E5EDF9AEACCAEBB C93B7BE4D00176DF21D7BA0CC298CF1557E9EDB5C16B17676B7EE18CDC9B4EDE 190AC5923C8D162A6289650DC0A46EBE9A04934DFEE491510498D1F5580B1821 764594899060A7E858DD027B33CA4488BB088801561FA360F3FCEDDFFA5BFF4A DF181C9FDB1FCA7CA62E6643B71AE77E2275CDDFE50A6BAA0469845B3AB96157 27A4454C63C06E201C000DC29B488E76265C8D8711B01D4601F7457D22BCA104 8A0881C2376820BFC1C6F36C5899475D6F74D036E57D04243D2C4BA369B71D91 C417DD34D5056D07CE2650CF21A400FA76D57CE6EEEA0C0F4ED71747C67C36BE 5364A8FE9C14A568246E3A84CED8A488A6B408745899070CF9C668F47BF1EC9E D0FD3D360FDBE08035DFF9BE535F5BBFF6317FFE6FDCFF0158DA4F5F7EE36A2F 3F9F652FEC759EAECFFD7475E1B4EA044DCD320149252EEF720AE55E0C2A3F7B E7F24B121EC1F3A42428CF849A1CBE3075461E0CA34FD6E79EE095892CC55B78 74A8C56BB8F21E199F0B3B38C75CAA9C7436584861B814105B51DF896670D4AC BDE1990E9331107404AEC1555EBCB3B9FAD044EBE9DABE19F8B23C154279BAC8 05CF8DCE0DF6E043F61A4A95688DB68D907739F7182BE7949136A3945459CC47 6A5E4A72E55449660147FA04295CBFD02B22FDDDACBD32D4154BBF6DE6E0D122 6F0A59F579CD7801CAC8628F814784A74AA3827B47006FCF3C632B4084207C23 A82F0D1890E250915B149023B64F644AB98CAA9747F1735BAB1B79C167E62E75 771383BD434381EE98C05AEBC4FE85A57DDFE9565B49CA1C6CD04E0B73A7EAFF F2C6EDAFA4A3638C9FDA77B8D58FEF9F0E01249EBF70EB271E7BF8C4CE363CD6 060900EAAFB8F41FDD5D7D1B5B46FFE8CD32FF7D2A8434E592D2E3103DA96860 4BC350C51E684C7EC7F264DED978AB9FAC90E27D75F667EBCB6712019451CD86 70849856C09DE3C8154254F02656E70E9C8D0C8D66D1A6AF24D4B0697177A063 1140380C13A51E8E5FB004B2AD515121852E461CE208737327B095B6E79FD783 AF6FADE771D2F0665B3C7BFA13C78EFED06364BFAB0101001B44F9DA22C880E4 D19DCB57F276BC0899AC023FA5D038A6D460E420B50D74ED427D72519AB960C9 805AC03992DACD0C18218B5DE3A6373AED95CDA5738F9A5AD58A096EEA00D988 AB94BEE1C66B191FA5220A53D7D369E68E9C986DFFD7777C529BF8D8A9A4DA0F 6CA22B242DDCB0D7C89EBF9B8F868D8F1C8867200E561C120219766881150F51 D36C40FF70221C5FB595B75265090E7EA0926298EDBDBAD5BD1E1FFA53EF1F2C 751995956B61FAFC6A62DACD875BCAC35A8AE3537ED3BF73F3EAFE53C7D23D77 341CD48FC0EE4C816D4088B22E9A9772E523A63785E0E83AC6752B6D938D776E CEFB332A1DF2138A1F62EE60227D3DEBC9CEFC0766465B7DB92A1A87264CA5C7 4C757823EDB537164F2F683EF62F4C18A4A2CCB501BCAE3226E1F8042C7E98D4 8E3EFEA92FD0DBFFCBECE2B9994ED80F1BD3D1EC320985AC10ED722729CA71E6 4095773A4CEC1F7CF699FEABE79B670E98E98A27BB8E92B21F745ED96BB526D8 FBEAC35ADA48C5F0BC2ABCBCF550606664819AEA9110551471700C24414EB02F 14DBB9911F95422A63E202CF5A3242EC1AA5E59FB15F88E63423BE8AD83CB9D2 5FBF74A73255AD9F9C8AC314B09A8FC18AE6C684A86E0EA0BF181742C7A1746C 25424AE103740432F7E410685ADFF8FCA57AE0D7CEB686745B4475AE1C748E55 981110D16916E8C6567338BBC1F3B777F4F113F9B10321F7BC118EE54086D87C F752D4EB063AA581B69789EC8E20ED0C47C3E6A109B6CCB28A62CA295673BF51 E31F3C117BD2CF03666BC0BE181A52C367877DCC3011E2D4082F7B06B91D8FAD 2B80E691C9BC7FF7777EE5C6675F6919B742E9FD730B4B9520C472A274383697 A685E4A8BDCC4A9FCA317946C08AC51A5ADE0AE10C1EAEA1E163917BC52DB642 E0FD1C0EF143E4C7916A08F3928B82D1DCC903C93D206FDA486B729CBC96F07B F8650047E658FFB19951A9B9EBCAC4F58ADCDEE4EA8DA2DFE4C18134EA70F3AB 5BD7573999F48339B77961D0CEAD142E294C29036B34846009911CFDC44AF37A A4A7686148CC7B44F01B5990FE41C1B4B40720DF6ACD5F39FBD0CFEFDE6A64F9 3F7AE42387DCD6A5DD95FFF6EEF3BFDDD157A878B23AFF93CDF074A0A46BA653 E26937156628932A716E06E1DFED6F7EBADFF5B200FE7EE89564548BCA74F0F4 E4A27BF90649B24742E7E9D2BD2F02BEE733E5A2CB04D6BF01D696D720AA2C14 23B68288A8506D17252B2CCDB1AB0A074D6F78104574D702C49758350DBD97DB AB10D9BE6BF1F0E98CD551403277B2DC085EA0C424769CA69AC446A3A15201AB 820D410E43FD4048B6E8F7884344A50E33CE09A1922BE427C9F0FADA334E6AC8 9A5597E8F0F3835DD82D87DDEA879A338B32096C5173FC9A0D02343150706E39 BAEB71E3304C76006B080DF14E9E0217142864A74B396B8AAEE79654129B454E 2273696937125793F8C6EA36AB4E65CBF3AF257B17D7D6B2423A44241ED7B0F7 AC39C8E80F1D3DFE4056B4340AC50565E1F76A3DF8A5BBD7BE9A0C8F2BBB48C2 A34E74FAD8CC4AB7BDB5BEFDA38F9F5D8E3BC35E51D0AAE2F2AE6FFFFD5EFCD9 9DB6840FADE51F53222CFB6560A7113437C5BB3DB43A66AE70268160B86A6B58 0C1539383DFB73ADD67D43BEEC781BAC6BA79C00780EBCE2C081436585C33D9C 93F0144A4899B29517BE89809CA2392FB72B2A7ED152FD12EDD36D26AC28206C E4C0BF0BCA06DC26CC400EAE421A4DB4ACD62F48F5FCC6FAAE2147FDEA344FEF FF1367F6FFB9C79D057FA4530087B0E31C5910CEAE3CFFE26C65BA71EAB00DE0 14A738AF4B9B8C1E20A68E8910BB064579602007C33B0B282BA85D4FE43AB799 A7E8E0F2ED61AFB770F6AC0C9BCC99E416881E7C7857AB36936FA76C37272D3F 6B04BA67834D56E4F2025FFDDCEDB99347FC732D52EF6590797DE55A5FAC06DB 5FBD15B5FCE8ECD44E907A9556C3AB188923902AC968A5B4432A67B3BFE9D4DA B11700E645ADF06E291F14E793EED77B0BDFF3F0E0F09016AA7A2B4ABF765BF1 41E564DD384A498B5E416F92D5CEDDC573277BB733D52F268E50532B8C76E115 328066D894152851A0090C953AE0617FDFE0ADCE70B4BD70F050E7FA5AE3E128 9EEA54F616F297A45D4CC57D32B9A8008D364E340CEBF364A27DA1ADFCFEEC71 E091DCA5AED2436C0297BEF54DE909404BE738E0FC415239F2F88F3C4BBBBF7C D89DAFE4D33C5A9871BC3A09C2C4CD803945238026360B299C1DD754E3E75676 5E7E75BE66D921BF1B15A10EAABDA8FFD656DC8DE71F3FD09FB561A562DEDDE9 F4F2F9534B769E6676C7A90063F184AD52E2C1EEB41E247B45C65EA4F78CD8CA 204ECAF11AC6F0DECB404AA238F8C07182106F0B098F6F6DB6DFBD35B3B4109E D9D7A33DC00C90BA00F98B20624055480E31CE49C712786CFC4E6CA982573655 A31531197B8B00C3B9D1BCFBFA2BCB8F1CF2278A1CCDD00264A49097149C6892 8B04E84F401A3B55397D3B4D2FB4DD47CE25470E406E094609DE572B7BEB4B5F 9D6145880FA1B337133BCC5D2AFAC341EBF80C5F66799411E59A0D651D27F8D0 C9B442B119D9D4A8334E8490E945590E6628A73E7EC4F1F5030EA953BFA8FCCE CFFF97377EFB259198AA638E4CB68ED59A5380E6B3A4DC2106BD7D618B38DC45 CF55830015C10453CC96071F1B720476A3E2E6CCB0EB0DA7A04AAE88F00DBEA6 C4B9A8E92DB4022E041C7114845E6602EC3A84178E7D30A86AA560890D44778B 667DD8330261EC4E6876992D62BD1B7ABF3B58E98C8AA79BCB151E7DA17BE73C 1D007FAF2991E128862CCA821BEA07400CB5E8330E89C0B3A8A693415471CB1F A2FF87899095E3139AD2EF67E46F9F3EFD4F8AD1F99BD7FEEEFBDEFF1DF5FBB3 78E76AB8FEAB5B3BFFF9623E9FE47FF34878D6A5006FA91AB67425C6189F4D64 7A4DB8FFC8F6FFC566DB0382A368CF87D397B9399925EC4CD43834DDA8CEF835 5E1CEBE68F8C9C1926B28613430CB2DA4BB5A74981DD4BA5100BDE54031AB5AE 02228B2D2B9099124A122C4ED1356ED35CED5ABAC3B5820572DD378BC1EBEDDE 47F72DFCE960BE9E0DD1A2ACB4D943F13B624716FEAD8D8D813C3ACC335BFA82 732C0B942564563AD45914520408E76BE2E2653E03B002AF4D307FCF11AF27BB AF0FDADBD22CBAD1E393F3CB793A0D140EF6837523E37914BBEB34430179470A 59D6BB3D2C7351B4C31602B6206E07E4BEACBC8E2552C948B17E88A2CFC059D7 85BDE9937619326E76BAAFF436E37AB53D1A96880B771C2480871CF72FDF7772 7130A82AD3606E50E014E1DB15E79FDEB9F64A36DACFC8A9A5C347C2CAB24FBA 9BEDEEEACE0F9C7B78BABFA58636274161E2F5807C3EF37F756D75C0B0551641 EA380EBC6780FE474E84E3A1B67B3BC9701FB16696C1FFF0B122B1A4DD6F593E F3133D9A0A9D38A38CC53561F6B76AAE0BC0126F8A73C16C1404F08960413C54 351B1BC7BB68E28EA5C9D2098920A884000A94459BBE47210BBA796ED152DD21 400B21C8E01B4B9B044F60D7A95DD4FAD5B53BF02227FDCA44853DFDA96F9DFC 9E5343B2CD0B09E900CE239C865B5F7DE5E0FD676C0B5B632011A26B279FA0F6 80D53582735539C1B673600D8066716B10015466232B36B9B14E21F72EBC0D48 AD79EA412966983BC3D0EBAE949654A9A49788DD826D4120A2409AA6DB44C5AA D758F9CD9BD55DDBFAC87EFA80970081A671AA93804FE9AB72EDC58BF327E7C5 8946828E947ED89C50088F0BEE8CF3071D7BF38E2F32CAAE193236B52F4D1E75 A13BE1EB4EE7A59DD6270E268F189290CAED4AFAE2552520E3D488A70AA560CB 3BAFE8B6DE997EFFC1C10A911B49733FB5D34A2AB45F418D75ED4AED6B6F24B4 0504A984E7DFAD6FBDBE32737A268E7BE9209F3BB7300A7782DBF5F40D1D3DC6 D3E9EDF42560774EF3486099A2EDFAD6BB1BD111EA2C58127B40D0A5E9634B3D 894A1BAE72A7E9D2F28D05A3E8302642F5DBA7B25AC55B98168D0A0984F45129 D1C9518A09F2D788A481718A8DD4FC9BF389E74E9D9826DEDDBEBF9B9989E98D FDA367AF9139C53E3CA527C260C526AFB7D9395A996DA03EBAF05139C343E707 4C7B0C5E9E87367C389B6D4A7A5D3AD198F25A08D91B9C5AD87D16877C9C8073 D87E8C277EFAE6E6EAF6C5A58797FDFDF52CED4288F089879915D59F716CC056 70FC3122D198046273E6B8784DC715C7D20DC8964E6056A7BF2B06517BE69116 85751161CE1D341590C03D0378E78533305606A4DEAEF2D6D53D79A5E73DF5AD C3F919C28DAF522E058BC9CAEF7D69D6CD9D0951386AF872173083EF45FD6E67 E2C4345FA6795430E98A3DBE3B1CD69F3C6EF63578EC08DE24C21D8F0F628983 62A70A83D845CA05182BDCC20278D185CFBCFE1B7FF3DFD238309E7D7079EAE1 A8DA84B308D9C9480006464A7817801833AFC0CB2C5BDE5AF0D26F186F1CC744 BABC2E29CBAE586BC6BFC595823CEFA0D83AB6E067023BE099358102BE8D5E49 40800ABCEB06788BC3AB006F75561408EF682CD930B73915A9359B21DD1E6561 C2B3207A96EC3DBBB5BDE8889313F36B2A7D2B6EC31A577288F211C7E102A9A8 074FE76A6041652224C6C7DA0EC9F1F5A9F70C3FDFCB85F60FFD1EBB88E1DB09 E753B3D33F393DF1B5AAF8175F79E3DCA1233FF5D053BC7DE5CB3B579FD5D1B3 9B321E6CFFE59333DF2FA2433A5875E3D96198C322F1A411677BC2F9053BFA85 8D0EE0B0AA2423478D681115F6E34E0BAD297D3D3B13DD17F8F717EC508C5AF7 A4161611CBE009A5842488BEE406158E915C8FB186C1692E55E0249D2A670AE1 59B7991D4ABB6120114A9927B0DE3742F6DCCECE1116FDF8BE23F3DD3EC435E0 2381C2EF914374E474C4484C74624C52147AEC4457F613E3AF72144E725294AA 29416181C712470CB125C08583F46E1EFF7EB6BB529823247AA43E7FCA09EBE9 6E84ED588E4FAAB09119E4B5D2DAC5D18ED02E5A4F500E0723C272A829FB0ED5 188796960FE86A62951939B42669E29235A1123851F5C6AB3CFFCCB5AB40634F 4E1EBA2EE4CB1B3703D7CF8A4C130658F5A96AE3CFEE5F9E1AC53542A7AC57C9 4CEA7B2FFAE69FDDB9F686869C689726A7267BA38FCECE878EF7DAC58B7FE589 B3C7B7B65DE56F6A9AB07E22F8053BFB8FEF5E5FB329F60895D59A71221CCF05 FED1FE13B886D87E4F04CE4932830E6D12E10A8AB9BA967D6C66EEA3FBE68EAE AB1766465FBD7BF92162BE7F76F9A0EF1BA6DCC031826540DC23CF713CEC5791 E538A940980E47D4C166CD329470A464F0D4808D84D43D3FF0F3CC2D5286B7E9 C24A0FC0267A6A00AB33238EBEBFA1712B6F6CAF3DD35E0FE70F2CF6E4030FCD 9CFA3B1F8657E84BC001107384DDD8DD7DF3EAC2071E35150FAF71486248CA45 8B9203D6D6F0AE1EF91F2F555C54A9151912AC64AF24451B8366AEDAEFBE549F 10EEA1FB155D606201D5394C8152DEC8DE36885EA7B44F4AB96EA24726A464E4 0EBEDC366FED3A33C27DB4498E2FE8D19EEB29650B9E849D77F6E44A7FFEC402 9FA703CFB8937386BA7E18E86C9B9371AB2806F5F19165A55E19DAFBE01B8417 6832BE5379776AF8CC2A7DDCA71FAD914444B72AF14B97351BD60E4D4026922A 53C6F15F34B2259D33CDC1AAD177B3E67EA15B399C4C9EC33E96D8340AF1C91F 1193311B9AC4DD3CDF710B3E7FF6C89D375FF3EA95C6FD13C691FA6D63EEC8DA FB9C4EB0C55E0B83C52A991DA1B7F6ADFA683B094EAB51ADE7278D20AB583642 DEA0038D060CBAACB6108E29391C452523342F3E665B337A6242B90C1EA3A012 60A333022E16163E408861A32BD67EFBD2CCF59BECF4BEB44654B6596DF234AF AA57A8BE3E6C3EEAE50FF964146DBFBA32315B731F2168A29A7BAEDBC4B29280 B8A731F8B3529601D80FB66F97D5D6D284CB7A80B3199C6157F81A21072C6C45 B911E1C2EDE5C377AE0F7777674FED730E5646BA2F240451785DE59517501601 9F4C62A91E1996531ADEE2C4204035CC04089DE077B9C1B8803523D34F6F7E6E 75F9DCA2B7C00C602580767EC0590AB412681C01A6220A0BA08E8AC40FBCAB3B C5968A9EF8D8306A008BF32017C061E8647B2FBED4F00A1D42B0E4E973BBD416 5E33EC6DED4D1D98E107998C205854BD61B0BDB1593BBDEC9DDA2FF3DC6513C4 095146B61C21007067CA5C0E1CD1E8DCBA0CE7F19D7AFFADF5CFFC835FDDBAB0 4E44B8FFC85233192E0FB285663345450924F4A8EEC900722A8F1738DF0FE4D0 E114719FC6D9A212152B0E9F16C800D229C05EA8DF544ECC0854162E077F10E7 629661A58412D63F7512731C09A085AE26241AC1A29244CAA1D4A96143CDF614 4AF5EC59B9E6C8769E4FAB0A51E26A407FAF7B7B2FD7532883C7BB2A2F94A910 88F2D8A2515E363A10309C32E195C6E3B6ACC3C1F673042642ABEEE1784EC607 0B7D06CAC992728E06F872E0881F5E5CFCEB2E654B533FFBD6852FF6E5CF9C7B FA4F4DFB57D76EFEE63BEB6F0FE99BB6F7E0F2E4FF3635FB7837D99C20610CFB C853721426E99EE7FE8BA2F72BDB5D65EB414E24CB32212722FBEFDD3366B6D2 B383BCDF992BE421EA4E30E1006C8B3CEA8BBCAC7D2AA57D5376589BD21E8997 6D720C8105264289CDCEA50A9F1D68BECBE95D66B64D9E2431EC9E5EA3F272DC 6FEF0E7EE4D8A92763D35279D72B1CED0BBC204532917112230AD389C6566683 52F0848CE539603B97A58BD205C7968F80CB27B9000C7A331FBDD6D9BCA3ED9C E73DC19A471A939534AF419CF24AA063E0AD5314CDC4322E9A2A302382520826 A00C158C6C39494FCA26658B134558A647E1055208E317807864D7E7A3D0BB3D 1ABE96F47AF313D2093637BAEBBDDE2EBCEF28CA62D5B7D225FADB5A537F6662 7A261E5604AF6A56532CAFF82F7AF6E76F5E79232FEA9E3D31BB782A779EACFA 03269FBB79F32F3EFEC813EDB69B92EBD651113C88DC2EAA7FB77DE7F5B48F87 A17486C34E3A8DAA7E1261D3587D7D6C4AF807AD54E40FE973933FF8DB721213 B87769768F3692141B0FE8D81EC5C5ADE454DDE0ECFE19E0E8EB2B7B172BC954 E0FDADF9E58FF66853177985F2BA4F3D9100A30B51D0C343B38808532B64A972 160B43A729FB18F0EE1AA7B498964CA99C07104CDDA2A0089B9025425AE7584F C9CA63414DAE02EE0F69F66CBBFD76CF2E7953135575FA07CF9CFEA1739AF5D1 97D1E5EDD72E92AE9C7BDF3908FE0C1298411937CA1B94CE581B95E685A83EC0 C75A0858AEF52D03587537916D40E7DEC8EE5C7865F2C0849EDD0F47858B0578 AB5A25D886402B0C5D153734B9CD4C0F4BE180F94388C18E79BD6FBFDE253EDD AA0C179F3C6602D83C895509C014A6EBBD2F5CAB74B2F089FDFA1089F3B4513F 20FD69375F2B6FB4AC29A707B1B10E7FC437542CC796C376E0C5F5BBADE477AF 26FB6CF5DBF7C3A2386BA2FFCA3563F3E6C106A90167542AF5F2AFB72B872B64 3E1ADE36763D6B1CF18BCA80F38848407D10E4803301E1C8809379692BB9A836 3656F69D9E8CAAADED77D6DDB9C83FC08516F11B7D47B2E0016F2FEB78D7A3CA 112773129E06D9F51CD62B38C24762E049C729DC52D69C62DD039B65F060C39F 8586931CA695A38FFDF033D4DCF8840D6B59AD2A1D6CE474D12464847DF83682 432B7C95BD7827FF8D3B8DE37D71A83A30A9365E45396C5B77DEEC19E14F3ED6 70A69DADD73B92BBB34F470ACD34B9E33ADC15886F61E560651D3C71184AC6F6 8F78FABC72EDB2CC51B9137840EB8004618F00C056A0CF13222E7AAF7E3DEBAE 788F345B33F326C9C76DFC22F0B1C91CEF17C7132CA5D1330A7373F4A1D60C05 39440A8781E70EBC78487FB9A3DD0C584EB5FFCECA667FEDF8A3A7880B611B32 A8E3B8704852F827C8556C80A79269CB338756D3AB1B59E2361FFFD644345DBC 85CC50E8686DB3B87185885801DEA62EF9E2A0CF77FDD9A0BB32989B9A12275C 19C6199B088ADADEEA56D4AA47E7EE4FDD9E250D973708F74B9B51546BB024B2 3894AC5C4FE724173A949BECD9FFF53FDD7EEE229FAF61A52F2916A43D39398B ED3B06933D16D1C8D89A178B751A2D3080DEA1C1B9837423F73162972AA6C291 0003D02544DE1B7D2DF9314688D2E706A723B4C1DC09B14743B6948529BD4E20 2967D64969A1E0609A21E303697AB9929E3F34722F8FB75D7B7D34180EB2C589 85BC523DBFB771AB0FA70BB59B15960A35D6F0FEA7317DE934203047E3BA14F8 980CD32347F9691A31DD08D98F1C3AF413B18268F3EB35FA636F5D797CF6D82F 9D7D8CAF5F5E1BE99777E9AFAFDE889DF8EFDD77F8BB80D5F211A311B63C6526 C8F52DA6FEF568FB3FEE0C463A1224306438EBE71F3938FBEF7A531D61621748 30766757B1C7D22A8F5A5FA06E0644B95C8A4CCBF20EB6EC98C5DD55CEB9A2EE BE86445860230D96A9E0C514EE864FEF08D9967927CF472842E85F33C5D706BB C7ABB59F993A79BCD369D7FAC6547CE9B828724D24B57B4477991A96B60A468F 3DEACAD351CEBBE2C52E3665201AC08E604D0AC7BDCBE585ACDF57AA4E83936E E521A9CB886C7DCF15381383473AD424804D56DE106B041EB6AEF5B83599951D 33F63DC65D0E7EA10D252D6B44401D338ACA61A6A07B55EF4E483B44AD8DE2AF B63B1B34DBBF7828E915B777378DAAEFD04488E24FD4277FB032352747F0EA2A 8A4E6A31F4F9D76AEC176FDD7C3B2607DDFCD4FC91437BFA313F1F54C96FDE5A FF73EF3FFBF1189621BB61EA03EE04904334FD6F3EFBC2D69D8BDD61EEE2BC30 60439FC227A089C149D3B24F12559EC6358C7B6DC7A4ACA6B37B3E14F7ACEDCB 2977FC5872EC9F6EBE516387D3001B9C950386AEC3AA51348C01FE9A295F7C72 6EFF77FBADA5781438CAB8B252751C476440DA7DE1320A47A9E7718761BD88A1 FA152B2B1863AD600010787F6571DA45E29CBB2D7D6C4B33329C4E2BA10C4A2E 8D4BBDA8570F50C66C8BE0A5D5BD7844ABDCD6979DEFFAC73FC01EA8247CAF1A C7B79F3F3F39B75839791A621657A9D1F0436B84D709857DEB1B36D6C792A591 3141BF6B200C6444ED6D45761D0989D4742E5F689E59CE6A131E8744380314C0 C8A48CFD4D3C597A5BAB9BD4B6CBB60C91F2DC389CBF3DD42F6C44870F5CEC5E 3F343BE99DAC0185A5522435B7A0AA723D895FDC96ADA0F9E4A4249BDC992513 673CB35B6211BC6AD1B4B446C48B7F52E2EB7136C4926937E0CD8E933C776D90 66D31F3DC32AB96D27BD97EECA5C4F1EADD39A22CAC9B7C4EECAE599FB6678A5 99DDB6C5F6B07ECCD3D1906BAF003C17A203145302C28E1B92607766FD8B5B62 319B7E9F4B7BC1DAAB71E350B3B2DF9081D97E63BB3A55F78F43BCDD753B7E70 08C7599C7876EFF60AECCBCA7C136F38F48060AB5C852A8722A19663A32974D5 C46A849F578F3DFA979EA176EBCF1A1F68844F8807F104128323F19EDD845E9E E5DE667AEDBF3E5FCFC4ECC30C7275965B11447AA4F4DA28DF056EE74CDE7F20 EF6CAEAEAD1D7DE2C17C4A190AF815A563A8C34B1F254C84D445A7595B0EFB8C BD17F0860CABA1180A0A52FAD43B55949909423B22FEC8E9BE7D6967D499BD7F BE3E17E00E2B70A81E3E94E3BA8CB17B5B1DA56490577074E5C346678DE30490 C3731C128153904A470885B7A2AE3310779F7BBB7572B632D7B03AC648E206A5 0F4E4ACBAA3141D91B81EEBD3C17364CAF6EAA22AC3FF6918437E193382874A3 B22B37C5D6AA15830217D571BF96EDDAED602E88579356A52AEEF3B32AF0A99A 4F9A83AD6EA6D4ECD38FE7952C1561486AAE8DEC9814E15AF839842CF4C3CB7C E1B001FBCAFFFDF92FFE9B2FCBDC23136EB1B7F7C4C2D299EA640DDE53966064 64A4E00861029C0574BA5184801FC8A1494D29CBEA086C98C78127331EEFC191 7A322659F77A31699905991D93336C48841D592E6A56E040A2340046A5C4CBC1 91B27D8DBF12CB32C27764D603C69602A460EB327BB5D3CE9B11AD56B5669BEB 3BA5EE013EA242C11CC0F386FCCF5DF494E10B3B01B0D7555BAF04F84529B327 8C9A26FAF06CE32F1F3EF23DDDE1500D361766FFD56AFB959B9B7FFBDB3E7E3A 1BBD78E1C2A7B3E20BFD2EECDAEFACBB3F78FFE947BA1D029CD04216379096AF 0AF34B3BB77FBF9B4B12024D34B4F7679ACD9F9A3BBE3FEB64C44A07A7B8024A 5D8D361A994B8D5B36D72AEB64DACF740CF9858E0DA66CA9E0C5CAEE63841E80 A1EEE9E260236D3070D9B62DD6F2749DCB2EA08A8CEC79DE8B5977B097FCCCC1 FB3E42DC11ED08485892C307F460AB31DBB5B26B514A4D6179E45E47338288F2 5E32E7A47091B1D70A52CD89E67CD335AB3607045A73229FBB338E3B9B25197A 1040F2A04EAE6A14300F5A9C4138A7A536852847209DB2D65AB6FC9752BD18A7 CBCB837B032A64FC576B55D3CCB06C9E1800032EF5BC7744F6C5CEDD94886A6D 7245A96B9BDB699E75889F321D70F37D13F3DF15351A454C3C3321D901E5ED71 FB5C83FFB3BB772E0DD82C19F1C0395278DF5789AAF3AD7F79F7DA93F71FFD0B 5936DFCF76A289D554D56053A7B6578D5688FC5C67ED4B49A70DA0AD600E7153 74E953A46CE5C17B837216C2604037F71221FD8655136EE53129BC274D746F6A CAFC7760EBDEBDA1C0D203691A72667AE1A9FDC77916EFEEDDADA4FD0F355B87 1975AA5C57DD887B78ABEB38431787C721B0E0482B7A3DE01D4E59C0A6D86141 E021D1811AB5F770F204D5E2EE25C27210A5D4BCB9970A5DCE578C685BD5636C 7D65B32E519AEBD09F7CE8919FFCB899B57EAFB7F2C597978E1E2E8ECF5AAEDC 1CD01784B81A110D4884E8FE3D961A41B91C6C872306259F081BB1E246CEBA3E C0F73BC3EEADEB8D478F8C829ACB175D3A59E0954981DD35A646D129BB63D42A 31BBDC482268425320CF95DB45FF992BF513A76EF5EE56578AE98FCED82908EF 10A57D78CF1E84886BB2F3D69E3BED571EA87668DE983A4C03174E17F6321340 5880CE0D7637E222987BE606185FECC80FA258646F6EEC5C5B9D7BEA84B3BF62 D77A835756659C4D1C6FD1A6A2851BDFCC069DBBB3A7175825CAEF92D17AB771 38A42DD4819612CE092C01BA106556E141BC21EEBCDEDEF7C4B47B20B777E9FA EB83D907E69C254376D2F5B7B6671667D962D8BEB61AE615F7084E1FEA15B6B3 B50DECD3A9BBA8DF4C126C255601B04C34C2429D9A924895EE138440D03E7A16 1361FF878C23015372E52BB4894CBD02E2044F3D196837FE8D77F6DEBD317DA6 59CC0DC39E2B86DCFA8E2998DECC46710E446E627ADFFA8D1BF3A79BF660902B 8DFD8C980879D91409FB0BF80B407C51D2C1F2302221C466198D7D8484BA1E84 748E2D4B5112052627D58EDA7DE9ADD466FB9E3C55D4A897F5015E31D7C3338B BEC228506DCB1603948BC19B76D4EA2E61209C2688F0D65398F6A52B6591855A A09EB35FED5C6EDBDBDD99A70E10931B9B418696A858CACB7A342A6B12EB21CA C4E8A498F6D3CB6B9A346B8F3C9D3A35D87AAE2301940D2F5D8344E87869C173 0F78CA79B32B57C3F9C86CE61EE4CA9395AC9E70E20956CB12DDD9EAEF7BE401 B918150C0E79C5B55502E1B60C46967B12823077E1AC05C6BBFEF9373EFD0BFF 69736B94485B1FE5E7960F1CC71E191B5A698B6C7C09585AB7E14C18012C6002 C0A48263E30B5207EEE2941047BFE7B211071B1E11E89B80BE3752F88DC850DA CA63479156AA28324CCB890932E3A704B8616274AC016991AEB1DD52992F17FC D6A87F2DE93895569DB980DD9FDFDBF87A9102149EE41599E4319C8AB2008BD1 061E4FFD4F35C48F1D58D1700E9F0F55DCFCF27FE7C0D65DF86EE984B41F9FAC FED881E327935E5A413392BBDEE4CFBD7DE981071FF9F333B3ABEFBEFB5B3AFD 7F7636E26EB240C85FFAC0833FB63BEC739CA33699DD96EAE50AFB95BB37AE26 9047AAB9CD8F87F4EFCD1DFCAE2CE8D6364410521F27CD6D29A76CCB2464B177 108BC334431F0DE978ACE44B3838C1CA31CDB11B1500A502A0831A07E28EEB43 6CDEB3E68A4D3758911666B7906B9E73B3483BEDC131C17EF0E4E9538581FD02 5129C0FB00AA18E9D9A2A7ED90C166E77AACFB896557142B80AD0A5F50607F35 AD15D42FACF5F8B650B19555E34EBAA192684B13E120069C2DEE691B14AA257C 5EE06E266E39EF81131E6523002A6D97D7F1A69403B1FABD6B9DD209B7545E82 4F3D1000D12DF1F062D1CD601BC88D90AE550564BFAB9B3B97D2115DDA0779E4 95DBB7E0DF5709F9D8CCCCF74ECE4FF47BB58AEB2835875C85BC55F5FFCFB595 67FBD9619145270FDE174C7C5FD7D618FFD77B37A7AAEECF4ECCB676763BD54A 3B5141CEF6F0661BA0A07FD78F3EBDB3FE3BED8D8E28D30C9E5C525E2897822A 65D9A774A3C3E116F20D4658A6195A9242FA5E2E34FF83448890AB74B4C33E32 0776B0393339EF3376BBBF314AF50F1C9EFED34E6B3E1D9940CB90052E50C2D0 84BE2239BB67DACEC7B68558F21CDB45E3600BEA565A0451A54B609908C71EC3 A5978A06562E381FABA9C289DC09EBEBB7560A6EAF53BD9599255115B4F7919F FDF685EF3969FAEDBBCFBD76E0D8497D64D632A0445A9B50B03A610D4C08D858 5ECE2ED2327A23D017684ACB8722B9A19C21D0A6F4E256D6DE9A78FFE9D80D3C BACFFD7F297B1368CBB2B33C6C4F679FE9CE6F1EEBBD7A3577F55C3D09A9D502 0D0861C460244300818060104EB0B29278D961D9C6E09078D9719689094B9824 205980C03212436BA4D5929AEE56CFDD55D555F5AAEACDD39D8733EE29FB3FF7 B524042B567A692D757775D5BBF79CBDFFFFFBFEE1FB501D2608C02BD4028A92 BD52040D953842AA4375A44D2CCA2C4E45BDEFF49EB85E722BD954597DEA1679 73A5F4C8B4D23289535AB25F6F14E6657245ED3FB73571E9B439CD63D6F1E72E 9038772C652B6A4A30F968C4F86240A1B1D805B7472AC19EAB5DBD971F7EE9D5 A9F30BEE7D8B6AEF20797A5777F3F29DD3B29639291B5D8EE37877EABE058BBA B25D32D868D757389B77C0204B28892DC302BD7F6939544AF69F6A6AE52FBC63 21B5A4EF3A6B5F194C3C346BA633B59B366F742757A669C0DAD7767CBFC64E68 9BC6872FB62CD86D9C993000AAA4B067DA58E6E11B456322DC821BA8F1A27551 1ACD4A671EF8E9C7B18C7E56C39C1A8C0F430CB54441D30C845A52FF00F73FFA 1CB4DD2FCA23B733114F7A7108B13412D9A11C0E138BF8A23CA34CD6EFAB49DA 51BC01725F0EACAEC3E9834D3786C10F09A8A129C6588A7B095664883A11A5B9 A115A7C468085C84FB4E3B1DBC7C5567C3C9379DCF3D686139796C0A05E6C2F0 034E3EA83A009B2CA8B8D6C51A01007603701B188F6BB9AFCE321E192AC0BB23 F38CF2AE3C7DE5ECD48A739619916AA02DE34D8362471612A1FD676E60B50366 59A8F24697B7106D94EE7F2CA7150C2EC09008D36BB7E4C60DAF94E724B57706 BF800ED3CD6026743B20FAED9C2BA9C91CA282B191ACD4D91996A7E6DD7B4F14 F5D010D12A28FBD99703380404398CBD774E255BEF7CEC5FFCD6AB4F5D1B70E6 3BECEDB5E50B4E4886BD5AD5C52AA304E6D508F8C7C2E461EC420F3F140500B0 F0DDF149E17D6D60D90996DC60D21FF28B2C9AA541B18F89BFAE3100B571A038 509F16360FE6B9328AA4D48BB59342857494EB813603428E84B0C920CE442B8A D246E9A5A3DDA75076CAABCEBAB50D993C3F6A827429548B583AF60F11BAE01F 6372FDEDD0C1428F62DCB2829302922E5CBB16498D5C8BBF933399F9D95AFDA7 164E18D1D6B3A5EA709498CAAFEFB586AB2B1F3E77C7F4959B9F6AB63EAA922F 6F6E941DFDAE93ABBF81F87E48A7738E8FB217EBFC7F8FF73F7F7034020330D6 C8925F9C5DFCD9FAD49CC8E3E9D81E514BA6A06452841710282F02AED4B02A0D 0812EAC685F83B945060B4B3708BD4A6D85051B062322E57E38E6341A1EE127C 9D646D0BBBA4BCC9D0EBF62C0876D86A75B47ADBE2C47F573F33331C619D716D 38CCDC209BD57AC68C084A3011B03503941A96D1A0C649C121051CCBE1BD09D0 2902C9409BB73D857CCA60D40D72867411B53C37C4C42DDA0CD0482A66C58A4C 01BE0EB818BE1E8B2B90829E14211B446BC68317E3186EB93C03174C833853DA 027D58C3B73F32729D2B71EFBA1607A1D7E5EECBEBEB87816B33D4B0973C58F2 3F74EAE2C9A39E43940871559BAA64DBCCFF3787BBBF1FC71332F6CE2C943B83 9FC96BF7AFAEFDE7787B67E3F6BFBEFBD27CAFD9F634163E1E926D1FB4BB5594 29B7D6E6D53F69EE7CB2BFDFF40C071D132358A1332591832D5E840A74D12183 94775CDFC0C7B2195F4F7DE61B3A1A7F3D1162344EF6E35FB3275F38A6AC482C 2D6844EF9EADFD4479F9443F2E5155F288E718EC135161F610B9506126302905 B34C60F8AE081D6FBEC2F304811D01054228E216A5AA8208A2B1144D41BE0B8B 770C965E5A0FBDBA6B99FDA8FB85E6CE564ED6DC99A97C347BA9F4E65FF9415D 4A0E9EBFB272E16E335B33BC0F2D685376C804C6651BBD81B9A3A247580CD783 E883A1B00BAC0EE9E8360DA425139D57B65812571FBC10DBF881E71D5C87D860 3FACB041C22534C73A31F67FB28355D790511EA03413D58CC7CF6D0C77FBB397 1E141F7DE1A8964DBC79D13B170ED30EE51C89848BCC429AE4F96C74A0A6DEB2 309ADACE1A676B963A8090698A60174C15D2B305F325C7C57C0A4C82E78CFB11 E97DFE55CF73C2474FE5BD6EFED52DDCCC83BB66F346EA8E4CFC5A9AEAA3FAA5 25FB626493B66F1CD6E75CF78467BFAD823151098BD1B961DC452D76EB73D7E7 EF5AA397BC38ED562FBBDD1BDDDAA3737852A5EBA3FEDE60E2CC028EB3FEB5C3 D2E2643E9184B9DB7BE5D09F9924330ECA6202F51E289AFBA9CD8034611629CB 62B8D0147B84F6538749781A126194FD949F39901D2D30B4AF306719CA331C57 B4DFFAE857E5F668F66C5DD7DB03C7E6D32014250B89D3C32E8D1B515FBB137E DFED4D5DA8A960E0943DFBE8347799037636D045B57490B30289B1225217FCA4 981785190DC74B5D501F853BE93ABE0EC9ADB8F7B55707613AF3D0095CB1D458 306E017ECC1C3E3E5D84F231A731E373761CC18A6D5A10CF1712A4A52885ADAF 0CB3D4BE4991A98A9ED047AABD7B34B5B6AAFD26484ACA5C2A15F0A068314220 82BE0C19EFF91583252A18BDB28E9DC9D2FD8F0AA76E79038535769D5FBBA536 6FB87E949024703C7C191D0EB7BC09AF94FA4924E94AC817ECA789413D8D9465 CFB5C17BF2C1F3A8649F866F680DE1B2C5999A680FCCE929E535D9C5CF7CE44F BFF07FFF79EC9662EE2C961B4B92CC46F95AB54A1D056B06B0D801F8046C8A2C 10502492E9CBB29DA526CD1DD7AF576B933E774B8E0989AA3ABA42B493E7284D 6DFC88DD607C21DF081250C719EF0159DC29054C85DAD8E78FB8CEA5CC742C74 4F6988D1988E104EA41E65626454CCA158FCEFFA077428A7BDC0B2E3DD6828C1 0FC6E218402205B9D32EA43793A06F73049E14E1A990DC76E01F80BBC3A9E099 489708FAAF66A67FA836758E8A98C731F35654163BFEAFDE38B83DB7F0CB97EE 5F7BE5FA33DB838FC4D1E3D16E4CF503D38D8FCD2C0E7DBA7028A27EFEF119F2 6B87EBED8171842378F6F66AE5D72757CF933C9EB3D428D2D25850ED407E8337 CE40410459280403A1E3A2963DB9F6B617BD19688450A81C40914B8E57B940B5 C3E6427B2263EC0C94EC38744FE703A19A1A943C0E3C6F24E8ED4EBB25D37984 7F6EF6E47B3C2F94994D662ED8249004A981D1436C220BD2A06B58E442AD8E55 5E34F6606C84242EEA737B9E4529B7B11B3B0E307D9C669C501BF1AAD83E291B 120B78E9802E9D637F97B2100C82B72A5A55787C41C65D9CB1C462D1D8310476 704571F4A1676DF1572A7811D22C450D8A5E54EEB22641B7A8B9924507C38C64 66FDDE85839D83ADCDE612423FBF72E61DA4ACD3415AC51EB65195EE22FEFFF4 07BFD7E9DA845E2E790F4D4C7E8F3F35530B2FE3FED3CFBEF0F7CFDF79B7AB75 D677539FA44E8BA5039CDA9B9A02022FC76EF98B9DBD4FF6772EDB0F95A24A51 B3480B7F2E0D9AAEE3C21B3E4EE66F50BD715D54BFC111F1B161ACFEA62CF88D 099BF1240760420EC36536863FD8F07EACB1762646A6665F627422D61799A7FC 7C5412CCC79281C01854B6A0FE04B6550A468B8A7E2B3042056D059B060C3CD8 62AC4A159BBCBA28BAD95F298AB805F4A704EF0DF1F56C40961A0162839DDE8E 4DFAB5AA71F387DFF7C89DDF7DF1E0E0B5D9F3CB72BEAC1DD8CE47BA4EF004C5 150342DBF6744A73AC49681320856E29B5586C4F8E367C1F662A0F5E5EAF56C3 F0F4424E2C5D9F769C3A744714946DA1414A3250C606BDB8A1D107F6E74728A3 0E0B5294BDBEB3F9C2C6A90B0F98E7F7DA478766D92B7FE7A299C26E2C991009 B3370585FDE9DE53FB92A5936F5AE855DD6AB50CE5044BA0B100B6438AB2A839 8EC2E3293CC6DC1E685373FCF466776B7FF22D67B1A3B3A76EC9ED24BC73DECC 49D6CBD317E38C0F2A0F2CC28E719F375F3F28D759B856B6405AC3706B21B228 ED41E7EAA63E7CE968FE2DCB8393314A4DE919D4DBE955DE3143EB247EB1938E F2C69D8BE95637BBD90DCE4D10FBCC5A49EBDAE1E4C925D4603A8F2D6411DC1E 32ECE6368E026AE79672154B4AE858D92448C353D0231C651F0893922624F322 3F272865B9BDAA01434F6DB7FFE2B5F27CE82E59B09F0843136DCF050F1311DF 6EFB66A1B52BDC29C7B9CBD0D3965EA49E71893D49CCC1DC2163B46613A1C340 890886596073A9D8F806900574DFF125A91AE9081FDA78D5031C7DFCABBD6177 EE27BFA33F97053A83159D341F03B3A29E077F90C5E7E35C08619D166CA7F84A C4F816EC804A3A2C7DD9DF291C1DE75CC58C5787A5D653EB95C519776D52EA43 D80132E0806BF307880916CB8645221C97208B0FA883C18BD7089F2A4322AC21 E83D82907B74F99ADFDE47A49BE0A1CF5CB2CDDB9D1DB7E4863818F6133615F8 273CCDFAA0DC927B4C34F60F0673F7DD25E7B90508183524AFC41496D93DC847 1C3913AF7CE2A9CFFCAF7F60867897A25A250C5A9D7B6717EF086A0D61A164AC 1C9BDE95C5FE1032B8BD87CC4B4DACF4F3751345F951CFA6236333878061AF81 4FF40CCC0F971683EA945B2A395C8A812E3C28D1B83D742C4A0105A83CCD4C5E 149A2D68EC80D3EC48CA8E520760F7699262C836CD75138951E858A21348F429 956CB6DB02044341115BC00D80E98E71ABE6B8FFFCED66C1B123151AD7EA0B81 2C505380212881CE31F2438DA91F985D5E8675F08334508E9998CBA31113BFBE DFDFAC2FFC4FF7DF7BE6E6E64BFBF1E3BCFC47BBAFBF36682ED5F9EF2DAC2E90 A0DACAF7272B1FDA79E98B6942845715D8A5E92F9D5BFBFBBC464D677F099746 5019F40D9C4B9B786C3AF712E3099B905442209CD99B61BF63095CA8A05600C3 82A03459647B05931B5814A3A5E0BB81124223AD3B8CEE491BE7C8619E3ED73A EAD46A3D1E5C3ED85714558DBE58AAFFF389C979A92D9AF3C16985DA8C3BB480 438B112445589680D1502D610201DAE7301468FF671146E268FBD31CB05482D9 477B1898C655CF075E20A565841EE7AAD0A401566D403E86C3143F1AEB22175B A6C7F21264DCCA821B842566394631ECCB00179416864660F644893DA6BAA8F9 48103F09FCDD5CEC33DAB2FF26D5FFD169277BC3E999D9214A1786D1CF4D9F39 D1CF70687FAA281B6CBFF22785FADF366F6D0B7ED1F3DE5CABF3417779B23C37 33F1C28D5BE530F8E1732796DBAD7CA472A744A276645064CF00E7FD3C033198 72E3691DFFF6E6956BB03482C342C5612CC257487E8E8B9FF88DA9D7BF51672F 12A141FA6F0E977EE3BF02212A96832CA89A36E80796CF3E549AE8E6DDAF75B7 6643FEBDEECC9D292812F206B72C22AE060E881DD06219093834782812A78860 F6CCEB62E1161CA84D81CB6DE61BEFDF165A2B63768EC690DDBE849895BFB4BF 792D1EACD6A7EE9D5CDC3E3ABA9E8C10734FD482FBDF7AB2F6E6C9EA230BA6C4 348A8A75FD3A23531895612F1812A3282E312928188502858A083D4CD47E8854 D6965BAF5E5DB8F34C502B6B5CCE4D83FA756683242039C8A30834B108961C16 27D09EC24D49C110DBE603D61ADEFCEAB5532BF7C9C38EDC6A764992DC33B37C CF12EBEC232A3BAE8586B891723E445B4F5D9DAB9EA46FAAE180EB1253B0679C DB67319E522C3ACDA04BA581C61B1EB87DA2B8E1FEF5DECDAFBC387FDF197F92 272F6F0E6F0C1A1796E9298ABB83E4A951E627D50716B54970C29B570EC3925B 3A55312C81C28C050F20E563E91CEABF10E12EA93E5C692F0FFDD4A75FCCB224 F1DE396DA810CF740875FC3BA67A570F9D23E5DD5162F6386DEE47CDC1F48945 4B3FA44EECC382E922FBD42428790ACBF1A540304405F566079A9B90082F7DF0 3358263F454568D1B00825CE73077AB992B6A25B1F7D6A12B9FE056FC45A15E1 52C57B360CB89CB746EE814183DAE161347147CDB99F762B7D07B3B2F1C133D2 F14100CC816A57A1234A0C94AB91855420B386F0B1140AE4356F084A7F158650 D0CDF7FEF8CBC9ADD6DABBDF22EF6FF4C8BEEF681F86F4308525E0C2C38F14FA DC662C6650C8471DEFE12A08A43234C466A09180D97CE6669A6995DABCE8959D 7D153D7FBB7EE95CE40F03D7721F68C58CA502C7A22C45AD1015CD335218411A 4682C1F3D708A9972FBD45976675AE4008590BB5B1A5B7D6116D099E836CDCA8 34D8DE73B9C33C3F1A6688E1CA6A4956226912967894CF775A49383DA72F4C80 C8BDAA2A5A9186739B8F20D1F0EE95EE1FFC93FF10EDA50723914939C9B24726 EA0F57E76A8990F1002C6271B11EA8A4B13C813AC4F1A4A5BB0E1F0AC139A8F4 64362073D2C3663F49777AFD83CE9028EA193A53699C595CBA40FB09D8B63884 519B3109881729920B92432F18E6ED84FDB395B2E05C88619E77913E709D438E 648E585F6602DDF6D50BB2E387A525123685F7F4FEED7D6C7F8D4003FE78EC06 5696DC62E45DBC31C5F06D66C237E217B64FD21ED59C494FA2FB28F9C1C9B977 4FCFCF58AA9245DA19757C15B80B0BDD66ECA4BF29E9B332F8E5FB1F387FB0F5 B9CDBD3FECE64F778E36B1989EABFE5BAFFA98BBD0CB92DF37ED7FDFDCDE4A70 09977C317C4FADF1332B8B77DA1812A6C34055B240011224A1137492DC3E8652 64F830B7F9208147CB6CDA8B541AC296A72A7209C8B016CEB5B0F2C62C2ACF41 2000C4E794E9517026EC12B2C17407E9612237B07AA2798026A6F75BA38E4EA9 6B7C8C7E6772F60EEE59C25B755D528CFE0D733144A8AB750C935D36B1C28986 A613C81D4024E71235882B85903E19A8BCECB8EE30ABF85ECEEDB960754B39B9 FDF3603894539B09251E7768080C5A905C05F6F14A2D9CE2BE14A37DE31B03DA 0B084BCA86F6E4601A23F0BBA8A4045B3E284568A112404D455331E585221136 304741789BA9AB69EF5A26E775894E4E3EA17647FDC39F7696DE8B2629117998 86499EC7F8CB93E57FB4BB7E39E3B3A958C1E97410BE7779E5FB264E3C7EFBE6 7F1A6CFDCC2397BEF3B0A70DDDF369A9B583339E80CE9FFD9078C88CFD30467B 87CCFDD8CE8D2F64FDC8585ACC0454B0B503AB9B050231F2B8CAF9F544772C9C 888E05A58E59DFDF920B0B7608FFCEB550DFA049CDBE636ECDC6BB978E36271C FDBEB985479D8A1F0D1A815B62A4EC7883AAE48C41A70A17B24C1609316618D8 EBC2D0BA12189485A01D004C1EA64615E00C355EA73BAE8E8ED722ED0FB62C5E F2D20B87C3CFAF5FAF4D4DCC57AA719CD89839030AB3870F7FF8BBD77EF43B40 35DFA223667F5383E1694242482D32B5C9177E9C0D80D4058B7A23894E183B1A A1663957D16BFBDD2C9EBF740EFA13A2A4F8A4F4CB1649D86B0A8910E7E09A8D 6C16F42D96317857A043A963CF329A3C22C3F4D613AF9D9CBA332BCBE485751E 94AFABC1A94B2BA5B2D44E96952B71264DDC2EDBAFBE65465FED850FD6D8B995 AC425266CFA7FD4F8AF558A768D4CA02AAD82859A84A4722F35D9F75F4ADCF3D 57AF57EA67A6C5D65EE77267E2C4223D8550DC4BFEB297964CFD9E796D699772 0F5FDD0F192F9F6D1877A44026CB03206A53528CF69EDC9B0EA7C3B7549BA5DD 4ADA905F88984FD1DBCA2A4ED5932D5E2BBB77540F5FDA9BC84BF83CA5897B78 E3A6C379637ECADED4D48006192FB61C01C4AA626814F0B68699424087F6B641 8FF0D24F3E8E4DE783DA03FB3A90FEB21C568D4A09EA7EE672FBC5CD850BF369 A3EFBB9A8F1C9B9F47167A069ED8EE577AF56C374BFDAC76A96E96DC98098723 0F24339980C579CC68D11AB4019FC1A270219FC680A703BA26E03D64EFA6E31E 12E6686FE2306FFDD993ADAD83C93BCE4E3E768FAAE6202C8C73A1146781835D 00E464DC432F8AAB006C0B85BBE2C0EB719D4D8684F635190A2600C48BA2B0C5 3C2DDD747B40E23C5C2A67CE10135824013FA02475182E9AE885E0A7253A209E 0518474355CC1BBE700DE172E5BEB7AAEA9CC90D9446ED33DAD855DBEB883505 8B41A85957A3DB4D6E73816753AE96C3A4B136934FA43690B870CE1BFD91A23A 60F72E927248B4E56C15AACA16B5EBC0CF23F4E95FFEED9DCFDF3C443653E733 DA79687EE6D454B53C125CAB086509CA8892A1574AC1A0878CE2C227D6F327AA B55A24984A267D7B3553A984F1BCC40D12AF14513796A8D71B25A338709C4B2E B8B80A806908262BEC05CD1292E52C030B41FB244CA6EDEF6E4B1C4B150B1149 D522E8C0413605F281CD0ADEF510FD696BA323CDE9C9CAC9E0D4CBADEDF5612B 2F263C615BD1D1A830BA18AB3FE9FF5F891094D5191610F699FD6814A4AEBFB3 5EFA7BB3271EF1023719983C2D51E632D52AB124ACAF748FB4ABFF83249F49DC FFF1C23D8FA8F8F9DEDEC706D117AE6FAE8FD2E9D9DAAFB9E103EEEC5535FA3F 06375F4B753484F37E6FADFA8FD6CE5CB27FD4A405DB9127646E3CD7759DC4E2 63D5D472643FF550043656F84C70E30B55D1C6F7BD04B6DAE00281DE1A052C81 C7B0C422DFCCD27D205396BCA654F733D567FC8890A612B786FDFE64F5C5666B 98335669BCD2DC023704077FB43E7D1FF738C165D76330546146B9EA2BD3D1AA AB04F24017D34221FBBE33A2C761DBD5A861DF80259DF675D84B205410A9897A 6D9F59F023CF655EAC72EEBB26173E486A0A909A05D920656F18953611821D0B 44A5E28A14D5ABE26F314D95128ED3953222247540DED64D546283BCE5AF9AF8 487BC45429AE1912004BA7FBA3C18E8B0E1B8E1E7949245E4FFACFE94EA3EABF 2B9CBF983ABE0B73888B714E05793EF47E23DEFB784F73692ECCD42E9C58B8B4 D97C3F9DECAFAEFC0FD79E3A57F73F5C9DF386F92E8A269C81D37352E1E4967A 121439B0E75FCA5848CBD702E7B7DAD73FDDED24D00BE145F3361F17B2F01BE6 24C766DBF8B836CA8B0395FF3590F5ADB9F0580005C1D1B5600216712DFB40A2 51E2BFB070E6C1561A72A1CAA824F402F2ABAE9FD6ECB3618CD3A26102DAE506 26B160A5A2E07F1226F7C0D915DE17749BC753A37A5CBE35C72B1EE6F8532426 1F089C35E6AE66F2CB37AE6559BC5CA94D21D6701CEDC4CEE9D20FFF2FBF606A 0A7943FB4D299B063D57E4155F2385AD1DC049AC30C584AA015123840E86CEA0 DECB06CFDE420B93CED959575262139ADFC8FDD005DF5006AA5C2431855A9F41 3E569921473611421E250ACC4ED264E3F32F9FF456D3737CE74B975756EFDABF 7D1DD7C4E29BCE1A9F8CA2144A7A5C8941AF8E6AE2F9EDE65E6FEED17BD59999 21539008E39C079E2CBE3C0397CC42949C5940CCB5908EBDD5D8DB79E275D61E CDDE359FF58E5AAFF567E616E9599DE61DF9C428E168EA81130A0D18E6EDD77B 24C6F50B13A63CCC6160C52F242C90E8C8FD670E66A717BC7BBD7E78584E1AC9 9787A842CDC33E8BB4F9CB269BAAA0D3ECE095A3053EA5CF1A76C8F6AEDF0CE6 C25AA36E5F5244621B584A05BACC29A4382E41E9D098F19217C04D7BF38F13A1 6EFF0319C4369FF0DC1EC52C6183CAFAF0E8779F2ECDD4F5592A64AB2C99C036 55EA5C2AC2FCE166D488E77A9B7BE15DCCB9C7974E99663E0E52134618071201 68A2E31999639593A2940CCB6FCC8CFDD961F39D650ECBFC90DC68E74F5EAE31 BE93F46A67972BF79E4A719F3B9AA4D0E6C29EEF48A84C158DE7F1BA10311226 B180C49171CD0F46DCB10C08B56967204962DF0A366EAC09476596F1A3ABB72A 272CC0B54728CE48E63A81CE74321A84815BD4B86D9200CF6265C0EC8680FE8B 4DE0CEE8C5EB48FBE54B6F55B5059B30301075A43777E4E635C7EB256400332A D4CF6EC734C679091434C541525D9A120B46D39483F4A97D283C39C8C33B4FA1 F9AAA1DC9355E8F8908097E79EFFBDC79FF9ADC7875DB3614392CCEF9E9EBD6F 7AF9F0A0B99FF6736E922CB6A88ABADC0DFC4CA80CE36E96E549DE108E05DAD4 130DCF5D2E55E65C67C2712A1434D510EC0E82BD0FB1B7AB1058752DA4B7814F 9B61965A6E117820AAC972019D99CC224522332433BD65700F094B11A40598B9 B4B970E4329D5BB2887A3E7F31EBBDD4ECD87CB5589BB27F4E3F8EEC53B2C136 83F1A03742CD1BC98F7E6396FDFF930C166A51363407207F87528226197D57D0 F8C9B993A7729BAA3B84E5A5B0E428EEE4795AF70F036771D8A43EFD48863FB1 9BFFCAFD8F3E2A07AFF66EFE09355FDAEE7C6DA71D72FF5F2C4CCC37E6BFDADC 795247378749341265633E7066ED03D5A9D97C90556190A71699A1EFA6B934BD CCA6C45D25FABEE31930D46D8B8857DC99D4AC2037D02609A1DC2B41715523C7 10365674855300E6F4B9D65931DFA2D501C37DCAE3D4EC12FCB468B7187571E9 EAF65134D5D8EC35858E4DD9F958A971C9F13CEEF896628060148AA1106DFA18 B52D25E72EC4F3DCF2702540680896FC7CE86A58FE5518CB3BCCFEF7D4E339A5 5BA34E89BB6759354E129F33FBE15DA97C10C3541E23B075089A1F0A146D6DA8 426EC13F0BD399A25D6CBF412C75C679DB7E006432CFED0C072DC746786E4F77 95B0529A9FF4CB75A943ADCAAEE372368C238062DAE6F4D2659C5CD3A9CBF80C F71393F5557EAA317147AA67FB7DC3E966C97BF6A8F94B83A89367AE4756B0F3 4E4DDE3FBB5A5FBBF0C941F3A5F5E7FFEB0BE72EA5BE038389FB6EE666B9332A 268739E85858EEA385FD0A8EBFEBF28F0DF6FE73BBD593A6D09E1BAF93DBD7A4 A17880E0E009F48D51193E665DDF5A70F81BBCB040CEC0F40944430B502C99FE 8ECAFC8F87CBD3A328AAEB1189E662715A7B65E698BAA61473B73022845D25B0 4B4210DD9DF18811E85516DE4305D280A2E8B84D680A61BE374400C658DD32C7 F2CB9DFD5D992D2FACB563F9B5BDADF6B077C22B4F867598B127F13B7FEC4D8B 1FBCA47D0B8031F166B40A351E370873D0B58399D9A2E0CD84C4299643A35B29 1D56BAEAF0A92B530FDE95CC78BE7D7679457AB5DC773D61013FB7710D41E9BD B8AFC6415A18DA53A84DF5088137456263DFEEE75F5ECE2BD943959B4F5C3971 FA92D7EBDCDE7A65F94D7790E91A0287DE84020634E0DB96F4BA5F18F5EB6CE9 ED0F9946600919CE0403690F298DF00CC05954B44C85F15D904455B854EA3C7B 107FEDFAF23DB39993345FE8CCD617E8451D931EFD8AE8E7E9F423A7B56E5B8E 34BA9DA67BF1F49D73666A94490B2F4B04142150B69F345F3E9C5D5B73567414 74C3B81A3F33340D62EEF6BC11565F6AB3C55A3C131D5E6EAF4DAD88D5945F47 9B376F4D9E9F0A43DF5EA8C4CD2511958C621BF01C1800E7B0415198AEA07169 D4BE219B08CFDEFF81BFC0BAFFDFA7CE917D679EA84A992096449F794D3FBB57 BF67E6A0D66C50C6076CC81943112834E76EBC8F9D8E9F8A56ED511E2FD88436 E1A635538EF270804D193350B105215B0A10C114E575B0DB2D3A17A0206A1894 FB1D17F43137DBDD97D6432FE453B58DC3DBA7EEBB03CD86891C1197A1547298 7C2230FA5648538F05C98A49BEC2B0AEB0F01BAF54008C529C904C9111821297 52C415B4C452171FE5DDE6BEBF36413CE967198820D3B06F217B329C9AA94377 DBBE4107E4F82598612A184AD7AEFDA8C9CBD755EE961F7C4C5717B4B0970836 17E4C65E76FB4A508D12D273C1C58DE16D9C1F24A861B3AEE27D8B1C5DE75C4D B298295080D024C80E51522ED72E2C4B64BF51593A534E7575FB895B9FFDD5DF 6DED0EB7A1FA46CF54263049C251B2CCABB2E2F14A80A44D539633F34CE489C5 1FBE875CD7C64727439E433BA49F8C3228DA2914223C5F09A73875C158D1BE21 88A4AAF03EC23A241CFC94F68F5AFD7E6F7662A2E6729CE53895D806DDCC820D 202287CA3960798B096873A4B2A7E50E5107798A895B0EEBB9C35FDCDBDA8E46 03D0CD4663C672ECC6595CF8AF2F72BDB1E8FC6DB04150A1423EF07A8066B365 E7AD934B3F5C595EDD6F4EA0445A5A0B64C4E1928786E401EB7035A5E398E9DF 95EC0F5F3DFCD76F79EF9B70BADFBFF6FBC3EE9F6F775F8CF3925FF9F05C59D4 EAD73BFDE78F8EDA15B7D71FBCB35CFDF985D53332A9CE58A49D952477074A52 67271DB5A3B4A7CD9647F6F2748E95829148987227CABCD33F69512EA127400B AF188AA012A6131C3ABE3990082DC4C98C4D84E010E6E08ED45D4D7B88DE0ED8 6B347D65FDF6E2F4CA4E2A2E8FBA89C82D5AF0E7ABBFEBD7EEC2D47338DC09B0 35B6C80A1D64798F9211E77DD89C02DB6903FB2A1ABC268805F0D8BEA9BAE397 ED635666E8923D1FBDB4BD89A5BA70F2F4B03F2A3B6ED571519ADA445842B88A F0ACE37BF0136D78968283976B59BAE385DA62FE1EDE9AD06868018FE3B68C6E 229D06EED6E1E18ECB2C49B2DFAFC17D33189E2AD5571379CA0D616827802660 25B3FC21F3476C7D92AFABC48D208E3C2BDADB5ABC6D62F5BB4C3887651BF52D 84A292FFF4A0F554A7A7313A83C307EAFE02556F5BBA67B971F24FAF7FB59F1F FCC8FC1DA7BB79D73BB271055B04991B95831B89423AF6F5C005E5E0C09486A5 EA9F0F3B9F3ADC7E5DA4B96F191948305598E300C1A6912515050534E392A8F9 5B2A115FF735F916DB4B825D171A7AF682A1956AF8AEF9B3E5486E8D0E3B2A59 71D0778593A715AE20542A3B960E72B798CF03A92D02BE1430B7EE1423301A72 1EA8D31716AF05EBB6140486758B06A139EEDBE0711ECC8D175373ADB37FADD3 37D5D9F2ECD2CEC14E92F64BAEB75C9E72D35496078FFDB7EF5E78E759A8B2D2 86321E7C4C943388DB607D607329843B66E98145AD7D6686988AFCE6E170AF3F FDC0C5AC44B8B0B9BA2ADD8AE48E6B593648C85B0417E3A2A651146B72431385 FA54F4503E128E60DC6D7FF1C5A90E126F9D6BFEE54BF5C6BCBFBABAF557CF94 CBBCFEE05A5A4634C134D1C6B3B0A3E7DA477F6BF6FAD597272E9E9A3CBD6602 5F469126E33A9D66056D2EDE84067700CB990293052EBE26065F7CB53A2DF9A9 5AF3D9D6046DD00759ECF6F8D3E6A0DD5F78F4BC514DB075D9279DD7BB8B77CF EBB9616672AE2A36E48309F26EDA7AFD60FA8EF34E234FFDC81BBAC317BA64C6 C3675D6FC0F3AFB6DCB589B6BFDBBE3E38BD7A41CEF7D94BFA60777FF69E69CC C1663375721853CE08919621C3442FF80C23A960341736BE1C981A2DE5A5B3F7 FEC49F61D3FBA51CE8530E8F32C16AAF77F8F8B3538187A632539338B3A9CE1B 48EDFA998B1CD526B85DED1FF6DC25155C6223DFF859CD4125E3099036A49E25 84168D167B84C5240BBC3C1B4838E42B4429F140120CF42308BED53AFACC5313 F373A507EFE8745A3A1F4C9E5B30DC9E2C9C3B7E8A710D7B3ACE152B0629604E 063AD0E3F2FBB1B636C8C519B06D2DCA10C5DE021825C01221B199618AB674F3 EA4663B9212C8820C229ACD7B164BB9B07AE4B2667AAC5B1752C0805395B3522 A0AF062A23F6F065976F6709A95C7AABAE2F1A019515FBA5D4ADEDF8D66BE589 2CC13D8F10E550761844B746B4961A3A0C6465D093E5F333C0FA4C4A51B11B9B 368E0662EAEC82A93250E599BA906EF34FFE938FB65EDC6B3BEE2D2D1B193E69 19274F1E3A39778F7D81892039EC2141C116EC3B415A0DB9BCF0D8C08A69E162 9AE7F6886A2F4CB19B096969B36F4FA14860A287803E2E4C35D93C9638207041 38746D4100CAA2C914E71978DCD9E32670949A2C372DEDB550D676546A015D2E 32A1BB9CBC9C74AF75926AE82D3416F63ABDCD51A7EBD904A08EA34B110A9C6F DA6856DF1C7EFE4B7410666A6110DCA61473BEC6DF3EBDFCB03BB118E9FA68D8 20794EE33834C8F503E587DAC45C240E9E22C832983FC4F88F5FDBFE576FFDA1 077ABDBDEEFAE748FED95EFEC451DB7ECB7F7C62BA5B6FBCBA7DB0314A3A4C57 B2EC975656DF45792D9451055A61E06F3D54F120DFE46A4365AFB49BF9B99557 B7B7EEAF9E70767AB2C4D0A4C786A309441AD3533FD0ED2397C2BE1811B8703E 065235F6E2C9B1490DF0428946548A4C0F6978C3A52F8AE1C0E3378F5ABBA9A5 72E5AD7647143EC7F37393BF5B9E58D316FBC1FA3C290C8F13835B42ED199595 CA7DD848B3418B599601BA1160832841725E8B19BFD4C8492071EC3BB73DFDF4 D64D7B16824AE57A34589E984A7BC3BAEF855ABB51BA56AA9D0DEB554BF7F35C 5BAAEFD8A86DAAD203470B3C56DA2ED43F181F6933406857E647961106DE8DDD 9D5E50EE97DD7E06A0B93E59636976AA933EE094B8272BD3C19CC1A538D31C4D B6E4BE47070C0B83AFA7FDCB8E0EBCFA79515E9568C29754DA0C6B49A8FF718A FFEDABD70E089ED1DE4205AFCC853F3175D723A35ABF4E3EDB7DE5FEF2D43D99 DBB544341D9412144450BBEF21D5A3852FB491196C35F152CA55B9F6A4137DE2 70F3E5CE10E67A1CB08EB67720A43C07D553309A50DF92F4BE8903BE7112F1B7 9C3E0B6A2C4865A0178B4E544B15EAEE24DD96D26BA1F3AEDAC2C34EB860135F 9ACC13CC7DC7F541D317734BCF8114C2C45E511B40C7F6804A4B7CEC6CA38B8E 20A00E335E28F86625712E4D609C23CE9F70F2AFEC1D913E9E28958E74DBA772 85058D5218C9E8E2EACA231F7E07BA179EB70145138B7253C6607F1E2B8E1487 4119364C5453A87E6073642E6F7DF9B9D995D3C1EABC251758BB9A54A5530219 00989EF7C0A58D8E8C02750604420ED250A14C44B31E4ADA2220D40F465F7AA9 BA3B4ADE7D527DFA39A756731FB86BEB4BCF97F6078DC72E749650DDC6DD5E2E 984E5D150A43D444FFF6F6D14173F58E3BD8C2BCF17D983C20AC70695485B247 814C2C044B865983268E536DD7F1E75FDBEBBCB8F8C85AFFC538B4A0E62DC1C8 6DB97F8576F69B2B8F5D34AC2B4CCEDAFED1AB9DD9B30D7422CDB04D845568A2 4921B6B3CEFAFEE4BD179D50E73C617DD37DB9595AAA392BAE69D3ECB96E707E FA40DF18DE8ED6CEDEA51ACDFC6B4A0C93DA9D5505B3B25CA04413E1E60C5CB5 8994505C00293FFBDA8AEA3582F5091366E5B3F7FED89FE164F821C79E331F26 078376203E7D636FF376ED3C67BC5FB2843BD5CA095CE166B03445B37DEC76A6 07A3A6779FD14B963587B0F465B18B4D81A4621C1B9DC1DC1BCCB58BB577047A 4F30EE084A93369463AE144E6D0CDE181D3CF5F2FC6CDD3B3D9F7BCECEED8DD9 E5097F39D0609FEE19D0CA72A8540E78D5F2621019B65349B1165CD8F815A3E4 451DA9806412DEB4CD0260539F6B9E678479A8D1BBBC37E80D4EDC770AF12C53 D06A28DBC83F3207DB87D35355AFC20BEB23CF80F2884589A3C2C494834D8252 F2EA461CA1A234BA08827390D9A9DCD819DD78B93AA3EDD3E030D664E86052DC 4E116F21A7CF5123691B5377F9B22FD8889B1CE596CBCE770E85E4AA7ECF6C56 09FC7CE1958F3CFFDC1FBF7AA4BDD7A3A1B4B8A0172F19F5CEF36BE77D7BFF63 99E570F560DC96A834D22ECB9C621B536A0B928403E6BD0CC649516A114D1022 18EB802D1E950B02EB9BD0289290D7F3003216C805033D140A251993028B5CA4 22C94D2CF0282731F8DB95646653BBEC516909A8C520D4F75F67EA33BD9DAD4C 83DDB962B03B024B76C7CE05A6B06580F5EF6F841DFC86E487FE2F26424A01DC 50915D2A87EF5D5EBE1BBB8D514E8749804D3D608CD9C765BF9B8B8C45C57916 A403D759B28F53B9FF17EEFF616BFF1F3FF89E770C4CB379EB8FB2FEC7F79BCF 8D46131EF967F599EDB0F4974787786136DF39FCFECAC40F542B4B2C26010C2A 6AE48F226728D146921E107D24E4EB474D72D7B967366FDFD1581E6E1FB67D35 F4CCAC2233A3FCDE8B777FA87B803808DE0822C0499C1774D8D847418C4D8145 22D4A0C19DC6DC3DF0839B1ABDD26DBD9E0ED0DCF44B9BDB238B4661DBC51E77 7D6176E637AB8D65D0CDA642C04451968B589136D2FB18751D161B1C25A963A8 0ADD51964D8261B2CD28A0D55377B8C54993C8F5308F3D76430CD7E5E8D5F651 363521B5CC653A5BADFB513A23D0922277D7A62D9560164858E00628143B9A17 D31A1A16EC8B251A7B05326867AA23A33B9CA6E5F0F5ADADAF105D2F570F86C3 5E9EDC71EEBC6A75AB229B4EE28B88BE6D71B16EA4075A858A13B09517898A52 B1EDA13DC7232AB494A3A33A55123F165427043ED25916CEFCFAED1BBF17A742 D3D569F7CE13B5BBF6C54FD7EE9C3B31B713A6BADF5F566437DB57E920CC8C97 1BAEA945AF7D2D6426A9451D7E0073A460F56162A6B7ABD39FBCB5FFDC70BBC9 71D7822E97A25417B65E85AA1AFAEBB5886FCD85C7E239DFF4D758D7157E87C5 1D817DC40CC742DE5173DF3BBB76C6069D24B554B0E6B8D369B748848C79C6BE 38EC8221AEA1746C6E73DC969130647CAC5937EE0EAA6F68CA8C2B1FB074A355 638022466E84B4E97B19722FDFDA7E6177B7B23035414C29ED2F4C5502EC4CF4 79E50717EFFDC5EFF166D62C56824D751BCD6D56302E929E312EB867A1768E9B 398D7CA3E9E5CDED8DAD9537BFD9F80EB66CC7E2035ED7ACC4CDD8F23C30B0CD 3C423A90F6CA92981968C85BC6CDB20E4A5A2260C6F3932F3D5FDB68A77FF7AC F993EB36C2F2EFBC78F4CC65E7F95EFD9E73E2AD9EA47BFE50283A93281E6A94 F2919FB2EEF33734F5CB674E3BA7D6A4C50530506BB19116363241DD8F6039D0 2A19D6754AD964BC4C9FDED8BEF6175377CEEA9B0E1B10E7EDD5917B183EE7DE DADA3BF91DE77068EF4AC647B5D64BEDD20CE3E761C2D129122108876FC6ADF5 ADA9FB2EF27260F131EDE7CD97F627D766D9BC278F74FAEAA074E7DC5E7239DB C94E9CBD5354F6875FC9AB8CB3354B89630BD409CA91CEA8E22039086AFA06B6 90844503122EA7C5F1A0B81464A52211A6E92FE248AA522ED1B07C93757EE759 5D55E84E5342B11751E9F2A4D8394C51C771DD7CDB06FC4AEE8FF85D3AAD5117 4D309D11DFDEFAB22153C8139A2B8BE80A5999C2E9853AF63EC2A9A020498673 9444F9A0DD47CFEF9431F5EE5B4021CB7A6967FF68FAE28299B447573836F0EB 32623EC8985944A48A2C88C6D670C542117D4361A9687E1482350A06D1734424 985769702CE25EE46D3C77B536D7A8AF3594850486C5125BBE9E74A2D17E737A 754EB10C2E05F1201722214D4C416EDE31CA81F9F16BDBD150952FBD5957972C 2203B10142CDC65E7CE5A5D27C9692B68B1DCBADBC7C4EEE5828DCE2C110211F A7E5CE70503D3329BDC42102A5169F35D4D0DF69EF56EF5BAC9C5CDBF9CCCE53 FFE6E97ED3BD8CF2239BA1DAD149EE7FF73D1726E3A836485C46871C88075840 C07A254D9986E123C096DA25C451F62938894D6F22E58C849EAB5261E31E83E1 41D7615C5A52018629859192FD80CABE0A9B3C91CA729C49474A9443B1D59EBE 81C03DFB9D35DA661E4D2D2BD16D2312FBE553FB0369B3EC3C8BA3E706CDC4C6 1DE45A4611C262339417C438F13960617ABCA3753CBC57C4886FB695F8E66ECD 1BA3340C17D38D0E3A1F947E7C7AE54DD4F1467D1F610FF6492DEC41DC413ED4 1059CAECFFE5999B0E3CB6D8B470ABFADBF9D11FC9E6BF7CC7FB1EDE4C776FAD 3F5E359F1AF59ED8D89A0CE8AF4DAFBCD0ECBF5AF16ECAE48188FED2C4F2791A FB332A967D4FF17E4CB6227D28CC0B21694736DDA06E948FA6269F3DD8A68647 3A1B55B912919FA1D302FDD0FD8F7E38DA85D5518B222D86E41655156F4015DB 06199289D620B065A632B35E612F13D311F450AB3FDDB9E92CCFA499DA3E68F5 A014C22AB978D389A5FF39A8CC29D80FD7796E215594C99E2247461D11B26B44 5FEB4EB7EF222E676BBD243ACBC29A8459C98CE5F699CC1967D9840DA8E2E0B6 876F38D957FB077BA5D2955BBB172EAEB68E0E83445CF4C21389B934B5388928 CB33CF48076C20E125C14E1BD1028407012F81CD0865474AEDE4EA90F3038E5F D9DEFC3394CD691AC1F8309A2F57CB890AE6CB49B7F37DD8FBD1F27C4324F586 17087138A570A66BF6504AB69DA51BA9CA4C39F5BC6BE260CE57DFEB36EA4751 ECE1D211FDECE2C43FD8BF797D98B8323D3F5B7ADFDCEAF78BCA5A581A56B95B 2EF338133425694F44F128491888E32047EA14B4B7991CE692B17DDFC2523997 DA30D658AFCD3DDDD9F9A39D2B372DEF016546AA12D09E2E0681907A83F8FD8D C59D6FE182C77F7916C614AA031E543C8D66621291F74E2C3DEA3598CAFB165E E672296CCCA76D9733DF258147604C11901936CEB828658E27750AA521F4C69A 041A6B817EFD0717055B03CED6AADA718EAAE40527D9DBD85D9C984FE6A69FEE F5B6379BB3984D9748C09205AF5C1D90FDE5E8A10FBDE7C2DBBFCB026F656136 58ECE4DCBE44C90AFF9854A896E10349724F9A832F3C556B4C84F75E045144D0 2709325E26A404C6CE3023C061418BC406EC116D9C4C401F159667729AB751DA 161ED6DC8D9E78A171FB487CE00EF427CDD6C6D6ECFB2F0EAE6DA82F8EEA6B67 C8F79663EF75CF3E2C31AF4D68D1E9C8EF5A5E2B77E29D67AFCDDD732739BB44 6A134C84F6B948A2A0D466D397A514590B531D8532C5A691CED3F5CEFE6B8FBB 934E79BF6ACF3D7F7B230ADB95D7DD9DABBBF3F79DC4D32AC33D2F9D1C3C1FD9 F451BE17A77444F22A269E3DC3E25672707D63E6DE0B6EA30216C8DDF4F0A59D D9B3CB6CD6CF9B3AB9DCA9DE39BF3FBA9C1FC813A7EFCAFD83CED383A972152D 53892D15A654E50555050D2E52ECD10BC408FC4B536898EB4289DECF2D23FCD1 3FC36AF4A10CE671B5D345C9E76E6757D7CB67503269816335C85DA57ACA5826 5189392AC50D71ADDB615178CE096798E04CB92185C0E5221B823DA9BD88A31A B6C4C505AF54504F5621D6A1050D164F6A95F1412E7707C3AB3BB993D7EF59D0 2C779193ED2742627E6A4A362CE7311ED8F5F890AD2988FCC3C88BC519204EC6 41B10DB463042CC7804EBD861578031B56148DB41E5A7069891383F43C355A3F D06258395912156D81B06FAA1661662121376FD3FEA1B352EB7189DCA02C030A A759E53067AC0BA5272877CB5B0783F6A07CEF7D4EF99451B5CC8756B0B7334A 9F7992CF1CA6B581A3CA4A67DC12F01689DB5958B257B3C7682DDA9141AD4227 9DD43E13CB7D48C7A793BB9B0752B3E9C6FD5FFC9D57AE5DD1BD587651B7A3D2 19AFF4771696E8CEAD03A44F4DCD9E12166112B09C2F84D1800683D038EC52DA E4218B0959C0A4B85810B39919AC66B0858FF0E0D0D8CEEDD8E311620481C532 0BAC2CDAD6B98065EAC498488B048D046A1A7D84F590202FCE0EA8EE539A4832 74F9AB71772B8966BDF27C505BEFB55FECB7118395CFE85BC711FEF6BF7881D3 CD1BD89C154D042864B16296468000B6FDD5FB2BC1FBE7E61F13957AAB2F5C11 95A06460F94199DA74EE98C238443098CA3160079EB8B9C89C994FECF73A8DE0 E71E7870FE4AB47FADF96423FE9878FD89BD78BE1AFCD8F47494D3EB697CD46D FEDCF4EA7B30E5A53899E1366A93163948F44D230FB4FAE3AAC9FA712F4AF606 91F64BAD28B377813AA424C46AADB2CAE982520F9E39FB7DFD4351585A12D885 2D2AF30466AF2DCCD0B901B3F9C209004BD424CEEB0EFB4AD6D9AFBABBFD51AB D5F53C7B4C464327D4195E40A3EF5D9CFD87A55A95484BCF582E1DE57612B28D F92173AFF45B875C0F5CBAD7E954BC4A14A0C351FB6C69A2D41CCC4F4D0C9C94 EAFC3EB731DDCD2B143CEBED1D28197A5D89DFCCFAD75BBDE9C946120F4F4E35 6A69BC96E187C3993552B2ACD3B1F7124CF1526923392878E391FD832CF9015D 0ADD17F988BA7B8AAEBBC117B2E8D9A46B3A322E54666124A3D8B8771B659926 DF35BFF45D197D4C9313152ABC645445B54C97C1EA9BF4993BE8A3EE614C5C2F C259E09A39DF0925A81A97F6D1FE44F07F8AEE270E87112D8752BC7D2278BFC3 EEA60E9F59C8974FA6C4AB583EAD0619D1A0B09C0836E8B9AA9F0C0F649E78D8 CF8593145B9EC55ABA0DA728AA4C3F9EF53FD9D9BB368CEC7B893007446F6FDF 37D51FBE4D875F3A2EEBA3E345671B032E96A62E2D9CBCB6BFBE09D37BF2AD5E FDAE88ADB87E95B0098DCA5AFB1CC32E834DA1BC58E72B522E2CB9D9BB938D19 60A16E638E37768B2559322688A6D09A8935A91B7F94ABAFB0D1E786879D94CD CDCCD810366A75EB86367CB71E387386F8712C974BEFF8950F7A0FAFA6790C8A 46C67160002AD164A0F140E64310BF1248EFF577F63656EF3C4B024B0E89441E A5558C4B187B68EC9C5828D4C1972C8AE250DFB720094AB791511DA4BB198E5C C7193D75C35BEF347FEAE4DCA755F7CAAB8D0F9CEAECECB3C7FBA5A042DFB320 E6088A72F0F6B2F1570458AB5198BA244C9F3D186E6D4DBD6D8DAD2E69BD44F1 848145F3A418AA3689FDD002BBD095C90A013073E3E9AF5663341DD547FDA1F3 50236DC4BC3F549FEFF80B27F083A52EBB5A1593E6D9C6A097D41F92AAD61569 8870C5B318E766B2777D6FF29E357F9A4996AAC3A4FBC2CEE4F9D374B11677A2 E48AFDFBF983F68D6CE89E5879308F77DB1B376BF36534C16D6276A39C67D85E EE088A89C64207C7A619532CC340871774BD990111379B08EF7AFF67B1ECFF7C CE1298C4B819DFFEFD2FCF071E3B092C94F22010C4920418DBD7AE0A1CFFC8EB 5EEFA00609CFB9EE948D30547B3E816A856B099FF2ECEB48090B318CEDA20C14 63A8275D7BAD900B0ECFAAD5A7AD68FFEABAFD140BE7567019A7266299CE9A29 09CAFE99F9C88D1936AE4D842600E92BB0F3D2DAB21B4BC8B48B914D844560B4 CF17E7E389FDC21C8B146404B6F7B44C1C0A06D126F1B6BF766D7179862D07B9 6F01322182A782DA98D6BF7A39E0CA9BF1464C21EEFBDAA7904A65062A1FCA81 9402C21C78A73BD86F86172E3A5316735521EB13E9B7B3E1D34FF270874E152A 90B290F2CD9C7C4FC0B64A55A5C9C886199AD260615AFB2422A9C7120757545F 6E5DEDDC78313F7C5D773B72D798FD249FF76AAB8BD32F0F6ECBA8FBE395C57B B0A7C70A2664AC1500DE10A4502D2C921FB41CD1D87F02C6B8297A63817DAC87 F9F5AB3E364629CC8F342DBC6190B060C6063A63526DD1749CE8A1402DAD5B58 47E0CA4E8644F6F258336744F106924FEF1D0E35F6FD20D3A89F25CCB1D9D4FE D66F77577E2C15391E9E2B1A149668B3F12081FD3537438F5627FFDEE2CA2A22 FE68E45B4468D98EC96AD8A9196E5FB07048CA41B510F6F7A428410B4D6D556D BE71BFFCB56B0F3DFCC85D67D6AAEBBDC12BDBCF4CE6FFAC7B6D2B96EFAEADFE 28AA3CE9B65F6CEEBCEFC4D2F70A6F568B78D6CD3C8F7770D6D5EB3ABD89D29E 111FD796FE9951AE778789743C873B248956B4FC3B5373EF5E5A9ACF635FC6C5 646758EC0E180A33CBE343A640843B172A1FCBCA80E2C7AB3577B2E366A4F47B 6AFF89BCB53C71E2D68DDB9B588C5C1B344B2855F359FA0F17973FE85B9C2E44 C9C458BAC21975F42EF3D64BDE176E5D35955256765FB9BD736A76A11B8D2222 E627278FD637EF3EB1D28ABAD5927FDAF1678EE2B5A05C2D792A4F6082C161FF 31EA7C3A3EBA3D5477D567CF609FD12420E99B79E96115064AE5BEF12CB38FF3 C4AF1732DBA056036D0462329326F6C9B8E46696BC2C9317B2D18685A6C9548A 53629318588659F20FE8DEA5E4E46479CD771E6D54EF8AB20B884D1127774DC2 A115E4397E22F17E371F0CB1614162491A894ED6FC992C3B0A4469231F7853BF 2A8E5EC8B24BA83E68DFBEF3DC89F7D467EFDD4AD9D25CEFEC8A9FFBE0C1CD2C E3562008CC244D3A49F760D86D73C9EAA862FA791789C350F6CD10DC4B592362 FE55223E71B4FE646F28ECAB81124D2148AA8AA336362EF976FEB2B74717ECC0 83ABE2A5A80676A34E5726532EFEEED2F4DB9CDA545F24155D254EDDD88F6242 8F70DF72494C5C8840DA1C4F1ED940ED8139E1F1C51CA7C2C25BE77848C61496 1436E7274E254B729BF3820C1D66D91754F4F1687BAF129670701697A686A3A5 320B43141AC2B59EBBB4F2D03FFFA9D1899248B29A0E10B4E8A4917D37EBD87C D3B7A050A2F60B372626ABA5D52528F8514F184E9D1AC6A10DB6103E4C51042D 782290546231FE5832D59EDAD46641AD5A926516A5AB97B6F52B5BAD1F595AFC 72D07EE9C5C6FB4FA4DDA1FECB0115583CE897EE9BB59FC151C58EBBF2211958 F0E17196B19DBFBA8C7C77EEA18BB9EB79EE2CC2A176499AF77DD0F6A4208F07 EB95B2182C32FBAFBC40F7FAD374A9BD77507F6446D5239CCBE8334DCB432A8F CDF5BDCDD04C3AAF56F76FEECD3D1288992C8989A3B86F53D4567274ED60EAAE 53EE24963C374769E7F9DD890BA7E862A9B7DB569B83C953B39B7BAF525D5D5C BDCF5E88C1DEDECC4A43D759A253CFE240986BA771613F6613B3FD48D0CAA585 B1249C1E65BF1AA56E563A73F7FB3E83E5F017323AF430975FDE6E3F75796ECE 177595126983ADCD3F38CFB5A419664EC8D106E9AC77CBAB703B711569CEB4CB 2D4D22F60D3A365549041C0B36BD614E15E48830948C6D10B4F1DD6699ED5EE7 EA462A93C53B5689CB651E492EECEFE8EF0EC28969BED448C21C83AC868BECEB B7241BBCE92CDC6146D9B8E8DB5F2934D572E8CF14676FDC882EC2BEC5679196 997D0BAE1B225A6EDF6A756E1FADDD7D4E546D48827AAD6547B93D16BD74FBF2 8BB327268392491C84B9CF8D4BC014C212E60C1E0DD8F2609BF6587338BCBD41 574E054B0F1A3901F21F340F041D3DFB344DAF0773DA7E565847F331C83AEE13 D654649A27B4130D33AFEF87C1249AF363A7CF70CAED1DCA6A07CFA59FFE83D7 1D5DDD6BEE365D673D6361B592B63B796FF4C147DFF4A8C92AA3618A38F4DE59 A11E4790D412E4EF198CE08E05A00B466899B6C3409D00FAF3E35C38EE46A063 8BDF63558B632D3AA5C146365728070891A76A98EABE346DA3EDC58AA949739A E93CB5B8CF3E44AC078EFB62AFF3F2609812708B8325025C8C847F3B8B1105E6 C645C97ADCB9019716FB891D4FE4F9D856EDFED0FDC9F90B971242551EBBB943 F584C2B55496EDDB20CC1EAADC2596689362565C21E12A98FA796EB1F491D6C6 4C33FFE01D0F4F2C2EAFDFDEEC6D6C3EC3FBFF6E78180DCC4F2CDD7777AA3EAB 6F973CF9E3D5B907879A387234558A2D7AEE9976A46F197153A63D2AFF53EF30 1AA114A111E616F510AC17B3FC479717DEBFB8B8140D2D354D490E869CF91488 B031631F33C6B9BD42609569E9A08421BEC4E20A021E5743C40E52759DD2D703 FAECFA8D52A97124C595A8071203DCB551FABCC2FF7471E5BD4E20751CD920A1 84C57947237D9DB1F592FBA92BAF9497E7BA49B4BED7BB7862E9A8DDB120A031 D1B0E464696AA6D96B2F9F58C4FBCDB3823D3A35BF606F533AAC84AEE2F42B26 FD573B5BDB256FD1341AFD7865A991A7BB3F509F796BC41D914621A552377218 105030A4CD24E68281112FC9A1EFB94FD5735E7ABDC20794E6FDEC53B7A2C4C2 79A2901C437818F286D12A6A4EAF36EE71F93B3BE687C974164853F30C2882C6 257BDC186D27FAE840F406942D2CAD0F0F3C3D7A647666E036D75A5CF5DCBF98 62BFB177350CEB6766575E7FF9E51F39B1FA6E8B1DF3A4DF68F8E555E91947CA 496F129643A84DCFC9147347EDFE6EA773ED70A75A0BA70322BA07C6C531652C E17E07A35AF58BEEE0DFEFDDB896C882DA15B2ED2014C30B978AE4DB6484A070 4B8F2B15AE025E9841C441DFDF987F0C552B484754063AAB50A782490D9B2A67 30495C8C8F12B07A53E34D8C22A8D2E3B91C3316781B5F40700447C57E7D6128 626F60902636DE653D93A372557BF5EBEDE1E78E766E9649B55A3A3DCC57F29C 05C677FC936EA9DFDFBBF3BFF99E93BFF07D5DAAEB12DA34B1655896C0456DAA E2CC979DC3667EEB70F1AE73AC907F038D5EE2178930B03CA2D07A5280A20BD7 D1C2F89BE410D62011221C633C94F991E21960ECF5CEE8A9ABDDBF3BB7F4DA54 F3AFFE6AE27BE694D2F157867CA4BA4BA3F977DF2344EE6469A1F8E4DB400C62 338E04578C26BDF1D4C6E4E999F074A871E8D7EFB039429A819F27C605ED6C06 E2FB85E23836C9FA7A6A337769757FFF70FADE0932678188504F66C34134F5F6 95C83F7450856F56F75EB83E77DF845E71876916E660B199F650F3A5ADD9B513 6CD951BEC447A2FDDC6EE3EC1A5DF23A5B87B8A91BCB93B7375FA9946727E6CF F66F5C4DFB9DE9B5695341890D2D0ACC706D004C08A8E783E2122442A52908E4 81A18F06430642DDFC3811C63FAF68C49BF9CE27BE36A9B4BBCC324BD52CF871 14B347C22655E5A696817022D7F1683BA9DF51624BD8C0A63BB16980E880988A 7194F652030B98483BDC62132639949660A39D9844D2FD34BE76D0EFB467CECC 933A8345ECA27006DB953BEDC995553A574E5C45B14DA99E4D7B40F069A18F6F 93A9B4FF2600BF4C10954E8D8DE8088DD5CE61DA058942897364510C06C0433D 1374AE6CF36ABDB40A5D06CF81A544C61C9BE1F28DE1C6CD174FDCBB6A518D86 CD46CB687921582373934BAC980DC70A27F6480ED2C1F5EB7862AE74FA3184E6 720B8B78E611367AF935B3FF5A65221716AB655A7930C6EDF7BCEC56E4781CCF A161D4A55D8B8E423EEDD3691BFB86CCAFE1CEC4A73EF24AEB263B8A464D151D 65F288BA57DABD151EFCD33BDFFCE0FFCBD87B46DB765D65822BECBCCF3EF9E6 F4720E7A8AB6244BCE3960CA2EDB6D032E188CA2A92AAA1905157A34A3A8D035 6050D035E81A5D0DDD403514D1808D8D0D18D99295ACE0A7F0DE939EEE4B37E7 734FD867E7957ACD7DAE8CF9A72B0D8DA777D30E6BCDF97D73CDF97D0C677C59 BF2847943305448D8EF94B0A55CAD893BFB3042AFB8F409D73843FDFAC881E28 2B8E44B50E52209CE9C17409E698E49AD329A083B9EC31D193AA2BD540098D29 864A64799E52B2AF98E155B1B27A5CBCD8DDBE95473A01834766E928FB1613A1 668FD0104201AA9796C950C1453094AEDF5E7EDE34BE3077FC02B52A83C4B04D 8D226DCE5A99AC4A287B831F97A9DF86C6691CE1DC100C114DA59C4C7A7F6993 3F59BEFAE3A7CE7F944C5AD5D997366E2E89CDEF5AD197EEEC1C42F58FCF9CDA 94EB5C646F6BB4CF0EC434C1B5C0D4E16090C55B486E30B495A16B59B1E5DACF 0ED692214A11664E50886C5CB01F3BB4F0F9C9C9B9B8970EF648BDA2170A2764 32620A2048E9268CCA6E4081048333259D01408D40413747A3C3BE396DFDFAFE AD86D36C85C6E5DEFA3A21D1E8A4C80099F907A9F90BC78EBE333386384B5C11 141A8CDAAF08FE9D7E2F6B8E3DB7B9C2261B71946C6FEC07D5EA0E4F2596150D 85A382940D60ED7A8D7776DF3679E8A2693F208D5956F00ACF5DBA27CC5FBAB3 B83A3BB9B31D4F52A346F854C0DF69BAEF93D516C311A85668A0CB5CB28789A3 135A4CA8E6B92631AA1A6A15A4E39BDF0DD06371677D6F207BF9CD961FE75928 402E03A68E878C68A203A677A9E393339CFEF4F4A987721705BDA0E25B1AAD18 CCB560F2516632D2A16A68686CDF77C8F5D5C5A9F9C9F79872CAAE0E77A3A16B 7FDB2F7E73F38E5D19BB17B74F0EC2B78FD9CD249189D153F5EEA4A5B27CDE69 10D31D06AE19040D6606C85D35C5FF79F5B1EFF56EDDD308BE509B9CE24AAF46 137976A89339DA6839BF976DFD7FAB1B1924322A50391AA0ACB2D899BD95F5E9 E80862944E150C050AC111980BDFFA60A5F9C3B3A7AAAC5813DD25127D54EF5F 4A7CCD089168505A31B16320C3A6D28699F1B2EA52AA3B2AF226D12C6B35521D B4AB9689B0345584F942956736B5D7A8F84BD1BBCE8BF378FA01736E9DA77FD4 BFBEAAA2E3563027887E060DBFAA1366953073CE7ECFFFFE8FD9A5C318536F98 1B92312352A267292665BE7CFDF57673AC363325F394B81E68EA618FD02A2442 648F180228369562EE46A9DBCDE0DA48E9A0A4EF38E4BCC3AC0C6C8156C2E8E9 6BE1C727A75766B6BFFDC4F8BB26956B77BFDB6D3363592D4D7DE86EC3778D2C 82D335CB47F1D0549EB48A0CF75DD5DE7FA91F0FF7171E988E742AA89D4869D5 D27FE099DEC8607322351D940C4C43A4B1B3DBFBDB179AFE4277185566A473CC CD2C61BDE26EAD6ECF3C38CDDA4C5FACB1EFEEBCB8549DA99BA7DB891A5684C6 9B3835FCEE776E8CD71AF4EEB60C04D991BBCFAFB58F2FD043CE606D1B0FAC5A B37967F5558D1283C65CEFEA1B9867B5A363CA2E729E5A42072152D60FD12811 52516A02810B4B3971A33447D47BDDCA829377E944D81B7EB1AA49EF95CDEDAF BD343B55457328E51A94573004B4A1260B8ABB896D9888A73768D1E1CDBB2A64 5AFF60073B44D85CA744821AC862C24931D5E95326960ED39E9FE9F56564BED0 D43AE864E2B59DFDE5ADFAE1697BAA92AB4873144BE74B8AD241D4DB1F4E1D3D 82C702FD953ACE9B50B3B04061B6B42A9530991F6014C0FB04A3C11897C40281 7623C8F0EBC5AC749817919D1AC8F185618ACDE1FECDD5F6DD678B46C5C83563 35629D0488A8089C5DDD5FEBBC317FFF51D07184E56B2162C3E429B8AAE460FF A1E370AE1321750B1EDDB921885F3DF93EE41E014D122BD319892D6FE68B2F55 AC1E691B586582181C46308D6C2D6511F6DBBEB49362C0D4D0618A55677CE431 6CB55EFA9BDD67BEB68D327F35EF6DDBCE6A2FC9FBE14CA5F6E1F3F71F8B0A73 F58D63734D4DFEC0D8A474E005FA57624D908606E55F8DED45293B0E0783A0EF 57163ECAB3427CA0E45426C283A6B5520E9F16601924CBE3569A091969DEC787 4CED0BD155A8A753A0E05CA28E93EB45BB55F0CB3D38EAAC1B5EC3F156A2EE1B 831E1858958D31296CEFE2AD041A8A4C58663AD67050F6829B20A06CA9D3D249 6A7DA1BDF04ED73344244BC9461D956AD020012D01C2A19E41EA4CAFA95C0303 696862C6AD210DEDD69363DE9F5F5EBCA73AFDCE76EDD8C4144BEC95F5D537BC FDBFAC445FBBBAF385D6C90788FD426DE982F42F66CEAC5351BEA9DF4D2363BD B8BFECCB358937FAE8C941F27AC3594FFA79CC618EC67135FF7BC471FEEDA9D3 6F8B229CEC23BDD30D5B32CB66156CDFD2984E51CDA5F472A039485FEA4708D8 0D0E2E0B90D2C085584BD35B47C77F776B69B79F9D1D5FB8BAB6B6C86301B01C E5A507D2BB3CE73F9F3A7161B7885D35F48557A07D869E31F81FBD7E7B6C6A7E 254DEFC8849AC6B03318600D2B4B9569AEC18429736EBBBE99E6358CCE9E3A6A F5F67EA432F530C321190A0B9B79F0CBFDDB5F2DD202B941266BAE9A9B70A67B C38FD893978C86A177B963A61A9B1BFBB6E14065B77C173A1698B97ECC6E8AC9 2AA5D7A9BC4DD16A1C2D79C6EE6E6735CE184CFC5053EF2C4443D0A9C9356038 6E791F397EC862C5FFD21F388DAA0CACDCA73ACD3B12579053E4686B3FDC19C4 45105CE583A7A3DDCFB626EF761BED5ECC86C3B0567B81A22F6DACD7265AEFF4 8233DD6E83A23E3652E17DBBB7DD38B690C471D61F1C9F9EA9497AB635DFB61A 7950FBAE1AFCCEAB4FBC7E73E9D3F3739FF4DA13FD4168DB392666C2ACA0FAE5 6CF7DF6FAC86145541D40825E0CF4B4D0E72816F657DEADD9E9743A12E9890A3 88009FB43577776B93BEBFB1B31958E8C8E4D87B0B8F52AC61724DA126686053 4FDFB48D9103F62F8882730D29650A47D6EC6864F428D5C8F913FAAA2428C280 E13507E30A96B344D230A83EDFED3CBFB9451BE35387E6B1616CEE6E46E9D0B4 34ED25D3A6DF901A466094EF1FFDD0FDF7FCAB1FEFB70C3B4E3C6874ECE776E4 28CE973707BBBBC1F99336D5A1CA4280891DAE831CF1813F60701902EC0B1736 4A8420CBCE014A973E9450510B91EA26343229B256C3E4B9C5E883CDF1D5A9B5 C71E9F7E7412D583BD677727BDB15B1B2F56DE7E6CE2E83CCE0790D6EC0A4D86 B200C332E9491EE55ED1DC7EE10D67DCAE1C6FC541CDACCC3AA48AB9808145C8 B930F6C1F45E11DC4B92F0AF9FB5458B712EBC5EFD5C5D677BFB767DEDB55BD5 23F5C6C916D73B2F27FD57F6456634EE9A4983D0959CC44487A3F499653342DE 7B16729F395DB2F5CC5AFBF08C71CC8F36D655E855ABED3BCBAF4C1E9AF6BCF6 FE2BB73C8F38B3754553A60A13CCC8801817257787433621A16A5CDAAFC11CE1 A834AA1361A54C84FBC5179BA18AFEEA95FCE67AEBD458EA8458510B7BA5F14F 4452A64343625A1A0346D7091F88D625574E4A620508060DF456D1DBA2AD71A6 7022422A7A13A7A0B9EDBA05683F85AEA695C2BAB63EBC72DB1E6F58B32D0C0E 2C82A7CC32602E22EC853997630B73A81568200AFA6BAAD441003DC8B2470B86 F3EB5805E53174A24808F8068DDA67F41ECF11492041F254655410D7B6AABD6B 37F53756CE1EC93DD7C9A90E5B0C2603E30A31F2C757B7D5D6E47D7318832D0E 826057EAF5C30943AE598CDE23264385A3B3B48C576E8A5006C7DE831AE75296 1B760EE38BFD3C7AF5459A2CFB9336F2872CD189CBD6FB11E7B8D8B60C669855 5E50265223DD8FA5CADB4767B66ECA6F7F65B1B7ED7653B926F89230BA993AE4 388F8CCFE0DDFDA4BFF6B6E33317B06717925B07FE7CA89CCB05F9151021808E 55595A28C1E001C89E8E04BF0EDC5ED0DF1DD4A383095ED881C2C941104495A6 F524956CC8D38C871CED22D92568A0542AB8DE61116198917D6A3C9BF55E0841 E3D4839A9AC84ACE49CAE8AFD124087ABC950F4C46616124B151EA88EA67C317 5CE73363871F95764B134DB33047EDCB044EA64C308AA37AB1EADDEC72042774 14BC7834947613BCE1FBBF966CE8F0F92FA7EE9EA1A237E9AF76C36253B3EBE1 EFB2CEED4CFCD4D899F3FBFDCE4438CFE819668EB94168E1D8347C650EC241C7 466B397FBD9B7D65B87FA5EA7A091CAAB0924CB464FE99D9B99F989A39D4EF50 1C271A6F1B6E85578DA1D1696D9BF05EA1F3174C0AD9C83010645034B8CE47CE 405C7CBB417ABB71EA35FF667739B2351837EF0CFA854E959A5D2968A07B7FD5 FB8D63476776D32430071A0F70BC9BCB376A95FFFAD22B03D389A8B195C79AF3 43CE31084CFE10017A4C9A8E6AFC8A4135A68E0D772A202CFA9F5B731FEDA331 13C6A0286EFEBBFCCE9FA561AD3E35DCD86B8C0506CD4E38F645663E60D58F51 9B4621B849500384A84B3D688DF0F4DD0CF563762CC28923AC1D42BEEBE54FA4 3B9DC207FB2350114EB73B037DE519C2197825EB0D91B6091DF748FBC8F85F6D 177985A41EA6150F9E2EF671D05096196DEFCA4EBF9F176B6DE7AB3BCB2F27EC 67C7173E4D020D7265465448AF4E7ABFDDBB7EC4F7DF4F5A2B7177FD507B7BAB FFF4EAAE79686A637F5BE3C947A7661A83E4EEE943E3C49FB627BCDAC40A12BF F7CA735F5DBFFAAF8F9CFE4C526C12B967C31EF0B0F3B5A4F30B3B1BB18BBC14 6858E4C041A1AF43E95B5A9DE8FBCEBEA53F75E9160EA668A589B8423398BE77 7CE624F50D1E5B860E0DAA8AD438A16D4CA15462EA4458826513544334D9CA0F C6340F4028E82D2040A6AA14E02E13A128D1A6192B5EE3A4D1054FF2AF07ECBF 679D8D6174B836E3586698F531292C57FF22EF30F55B69E2999C358D07FFE9E7 E67EE8A1DC4C080F0DDE57669A0DBADD976ECC4CCFCAC3E3A545142DD5513449 AFC295016A2D2DFDA418158604D15B170EB979A95806A2435883D250A27E8A07 E08FB0DCCD5FBA1DBDBFD55E1A5FF9DB6FCFBD734636AA3B4FADCFCC1D5F7CED 09FBC8F8A107EE52AC2375FA248121D202EE45BF094A4C4638CF6F17FD5B3B13 0FCC0C9A9CBAE38175146B16CD86C8B4404580086918B95E354A848FBF88D660 9A4FD587D50726725758FDF195E75EC3265D78DB4966EF1A06626F88FE623A7E F76C3E1552298CC4CE6CA9AE0ED852147CE8786C2795D8597F66756C76CA3AE5 0D569754546DD4676EDF7E79EAF884E734F69FBB5169FBF6A4CF710CDAF53983 F936BDB0E16DC09F88669950C3863343015AD8C2D0999A38997F1C12E1AEFCFC D8228FBEF4947E13F8989F88A84A6DD033B3495144B67E91054A91A72972789D A3C2AE9EA36A52489DFF3C47D02122BEDE96C8D68C30A1A8023A7E9AC270A871 E636D808D99B83C1B3AF9854554FCFA406735C9741A1D2000552457AFB3DECDA D5D94952AD0898FAA61496A539EAD893D400954C04520FB0BCD01026633078B4 21E542D82785824ED994147962FB0E0AC84EBEB7B4523D392D1B3EA52E91B680 80AB11414A1D94FED9CD15BE72E4FDE772110606B8AA2AF0762F3D7E75F0D7BF 936B22A5DFB52D682E3A9BC54AB772F85D68EC42562A2169646DE9FC72F38D7C EBAA5391E64488729F274CFA439D88ECC1045FC94C4FB0AAC645860AD96073E0 7ACD971ECB3696077B51BA56382BCADD4C21A05E3A7972E7FAEBD568F77397CE 9D527610C6B663EA8481CA2111386326203208D61B0658E6C9D1882E3422C129 3D294D05BF5F141DC95B8CCCCB3894C2A5FE2BBF108592AC84682A5122911A29 7538DF51BC6BD048CAA828403A98EB104E986DBD61E77FBDB7B2A95F82659405 85517B1D58AE8D1A3EDFD20710216C40FEB5CAF61AAEC3B22BC4A7E70F7DD06E 36E3C800096215E4DC739C88A78E6154390E0ABD77ECD0B737B1481D37CD1031 3DCDE2139A5C1FAC2F2E753E75E66DEFF11A565A5C4FFB4B281EA8FC7A127D75 6FAB5A6F7CAA3D736CAF57AFC2CB3E629AB5021CAE7A86A1D70F8FF358CA15CE 9E4EB3DF1D6CAFB8A4950A0D67B809C5B4716A7CF4DCB90BCD00857B693EE865 500FB5896F53A76A3835D70EB01AC72888E2DA209E90C4CCB88E6B434A068EB9 4365ACE4AB9EB1BCBE3FA4DEA6892FEF6D4827D8CB126496C2ED1AAD60FE71D7 FB6F4716AA29CF3C38531461DE13C6F576EB3FBDF4DCEBFA899AB6D25820D3A1 9572C3F078AEBF646808BD0AAAFAB795A650A5520C3A3C55FDB01B7CBAF01EB0 7DB11F15F5F67F41DB7F3EE87534D612D0FE315B714ED60227EEDF53AD3FA49C F6C6F684ED2354D39BA94F71CF239167EFF1AC03E3285078B0333944E2B219BF C83B34A96B001909B9D5E9EE8629342B93F25F1D4C8546977C0CA17B0E1FFB17 2DDFC6791B174D51540C5705CD9EEF5B8D9613034D89777B43DB5C67C98FE56B 87F7D02F9D3E7346F3D261E6A4A88BF07240770DB419462B54AE54ADE7EEDC6E CC1DED0FA2ACD73F3A3DD9DBD838D1ACDFD39E3057F73E7CE4C2C9E6216939AF 07C62FBEF0D7E765F8CF1D3F67B88F419EC032FD6F2683FF6D6DA9E761E8F6D0 B1D883C2A627C186FC2D7E98E57F19CC64E1D2A0199AC50D2E4F51F70333470F 05FA6D0F2A2C168A7B060D906A2B32A9F380529E4D61A44127020B0E2CF4CF29 DD47117A931782FC0CD43E4A937AF857E36BBD1DB90DB23CA0DC580D79C1D45A BDB255A93EBFBEFBE46077BD61342C32CF64ADEC2B3B4283A99C69309805AA32 597FE4473F3CF9B10B03BF67B39E13277BAFBFA191EBF485F3CA05D52E902482 29D70A9C662AE8AB1FC98AE052695D9552D826B04338E787C36E9872CCC004CC 08131CEA4D8016B7D0EBEBC30FB65BB7C7561E7B7CE2A109A35EDD7B7673EAF0 89D55B2FC6529C7EDF23CCED0A1443FFBF02FF212C3DFDEC241D481C59616DEF F29ED952C17D8DFD28092A175CEF302442285783B3241CE4C01165945E5FC95E DC3422612D28E7FE26B775866EECBC782B5A8D8EBEEBAEA8B1AAACB4B23DD97F AA57BBD014C712C1959D55537B682EF3FDE7B6263E7846B4100DF1E6F39BCDF1 8673D2EFACDD369246A33A7FE7CEAB13C775ACF7F69F5F0DA6036BA6A6542445 8E0A06672D2074804B622E3088D4CB7270029A65F45E038D5B65B1E0E4F94F7D 03F78ACFD4FE764F3C7ECD38E52733384F8BBA26B5FA253B16CB35BACDA5DEFE 2AB04C32788353E4542E5239A6AFD385B1421A61EC18A4813D291D9D81FDC2B3 AD149A85986B31DB71F778F78997D1A05F3F3541DA46CE13CBB081872980273A 9FF5BB7DA315B8132DBD1575DA2BFDE741E1B804D43A3E1B84389ADD29E56009 078188429F6329D96195AE4C1AE0C02197C845BFE2D5454DBCBA9EA9DC3E3FA7 59902BAD02E4E5A80B5AB5097265FABB8B2B62F9E40FDF978A501344D01635EC 91659F240C6C09A586E2A01E0E4239D19EB8BD65B72EA1B9FB0BCFC77CA8F901 D59B6E676B7FF179DFC8CC56DFB2ABAAC8841F2759EAC54DAA576CBF4F1B26A9 B94552B01DF5DA53EBCB579A719EAF17BBAFE7FE2D5E8F25C7C95075C379DFFB E283E7CF633A1E32274F84CA90EB8027DC489D6E648C012518220EDC45F5EEA3 50F8C4E807752B0E1A64462ABFA5238C04B168E5330626134C7339A5F77591C9 98A13D29F7B018501C2A9982CC80DC251510F7325011D8ABB878696F77372AA0 62CC47B6A60C58E15B4F840EC83E6A2268801E9991E2C251E243EDF68782F159 C66C13347CAC42F826911A117B2D1E659A614406D9A0E265163D9FF61787693F D1DBDA65C8DE32B3059BFDDAF4230F3A7E3FDF897B79C56A2DAABD17DCF06526 AEAFEC3D303F7F56E54704AA23AFE69B4DDB30B2842AACEF0B5412E24C47CBDB 35F72F64F25B5BAB5D2C4BDD4AA0030627152E9B08F9C028CAFA2FB44DA0C4D0 5C191D6670F4AB3FD5A468CA774E8E8D1F0E2A0D45AA985A98244992711E86E1 ADA0FEBAE28FAF6B943ABFB4B1B55AE448735B0187BB2087ABF8672BDEAFCECD 540A39B40DCE999B903DABF2DB49E77FEC6DF50D3F2B34FFA516933AA0A7967E E28A1785F4CC8A4683C39440559670382BE78E941703FBC7CF9C3FDDCF0E0D98 5F6FFC06EDFFF6AD9B3DBD0DFDAA1A0E8E7B9E278A5AD39E88B28F54262F500D 37D3AE5DD9B3D42D992C25834E3F0CA3C44578A2D99C1B6BD52C9B13B1A1A275 D6AFA79E06C6E02795A4EB71B49E8818FA49E0090C7520B06C279747504567B4 F37EE51D2DFF42C33ADC746BA6A161B75F69DA7690F7B26CB38B874555D0CF7B BDC76E2C3FD4A8FCFCF1BB8E169144439D63ADD0D8A937BF85C228F0D6FBC36F EDADE744EF944180AC4CA7B7B976A3E2B0D76E7FFED499B73527E6BD7AD01A5F 22E81B9DADC517BEFE530B634764232F445264987ACF0AF16F576EDE866E31DB 12796A438554E7B3B7B83CBF3F738FDF6C6F560618DD8E13EBE1F1F94962ECB1 C1CD64EF53A45E6B35B1606522446302B7A901D551476741047EB7B04BA16E31 6A9CF93B698911682DAB6FA50BA0E482575238F48E881A20D42334E5062F0C35 39F1E5FD3BCFE51DD7B6A6121430EC578DAAE00BA6A7332E8339D082B8FC9E2F 3C7CEE271F298A6D74FD56B4B4D1BCFF623E51A59A98951A1B84F88478947A40 07A10E4AD59B02E5501AC5D4901C7A0680ADD2122FEBD00FDEDB31E9D93616AF ADE2C58DE8C313EDEB8DD5279F9E7ADF216C5A9D6756264F9E5E5D7CB9BFD3BB F0B1F767D34921F683D4471683F02C6D9D08158E859918DC4F6FE5BB2B2B0BEF 58E09E4C44DBF7CED1729A5B6F7BBDD9CC021B808A63B1DB4DBE79CBDA4BC55C 5E79703CC5CC0ADCECFA70E7F1D5A38F5E88CEEC33276AACCFE4CF256292D18B 9AAB3B34F6F3CA906EAB9DC7D79A17E7BC536332E19BCFAD4E4C8C1BA7839D3B D7CDA8D10AE6EF2CBF3A75BAE50AB3F7E266E570D39CAAEA4C2F41469903DF17 80CB753CE4BC18A98F013A07E34F10E635A1BDD664FEC9739FFA3AE6DDCFE47F 784DDCD80CEEAFEF37B89D519F0964736E5B184ABCA0564F4955E3C3FE4D665A 9E7F9723DA4C70C3321D666A42A69764057904E9B4256CCDF0AD1C2A9C79CDD4 8040BEB0D27B61B1757CC2395A9532C4C034F486F7B9E49A5D9344757ABDCAFC 0488886B8E085A4626D4CBA032A8998527A98D8903CA8BD0965A28E8724830CC D15050928504904B1521952BA69F5BC54BADBDE717278FCDB3F91A93DC65061C 911A14EA057A779BACF89D376EA4372F7CE621EE3368E6D1E19F58A5C9EF68EA A750A5BCA9A640DC21B408E5AD354AA7D1F14778D042857EF19A72C1986B78FD 856867A935C19CC065451781B5B622A965C494EFEA744371DD355D27DFB2BEFB FB8BABABF59DA4BF898777686339AFF69268B8BB798F1FFCCCA5FB27D27C335A 6D37ADD34CB5B039040127586C6A64E8484A41A8B25F5481622B58A41D983C8C F673D928532AD99191C8135623F4032DA51528CB403BACC8509AF03893A1441D 253A520C888AF567C0E71EFD354FD7BB614A50BDE6DBA6B79FE4BB515694C281 B49CA0C7A5B1C45B2B8C42B364C1F4A6341D09758158A4F7D7821F9B3A7A58B3 3C15EBD7EBC15429E1B6AC247C3A75ECE6D8E3ACF76D34B81C75AF77F288003C 2F8DD52D5448FD533E3936FDEFBD0B93BB9B3D374930A8A82F89DD27FCF05B61 8499F98199A9E9B0336F7B4DB35E6785A32FD5411A8CE184D9CACC045A26EC29 94FD79D27BB61B4A038422C154A760B3C43C6AB8E38A4C786EDD30EB084D7841 C57763CC7A4592F6FB0CDA5EF08D7ED8112224BC9BF146C39AABD4E72DE794E9 1FA68EBB3FFC35BE49DB53AB83F84E77BFCBA00C800BE5026690CCA444B19F98 6CFDC776B339E0031BEB1F5824EAC934FE3D877D736DDF968E83ACC895704A95 827F26D8A0C0A88BC80DD80456AE4C389DA54A2F45919C996ECE17F90F8D4F3F 94999352FD7E85FD49A7133BD5BDBD9E91A756C28E1E1917457154FAF77A533B 83DE96235F43D952DCD91BB071441E30ECBBFDDAE12098F1DC0990A3CCC10351 6F0C229D1C6AA04C037E9B740DBCC3D9562FD91A648B69FE32E74B4815C2D414 00510F896113E5271ACEF9B6F9AEB1FAC3B5D618754CBF364CB3224CC87E18F4 A33FAE8FFDEA6B2FDD40EA9353933F3D373E2D3A34CEABA21567D6BE46A3546C 4B7599659D0C9459946F5FEEAE862D002DD5FDE81F9D3D7DBAC067C766BCE6F4 96ED5DC9D4D3DFF9832FCCFAC742BBE0AC30905738B7ACE0E7B66E3E99652682 599190E4709ACEE45BF43D399822C4D0CF8C4B77A7B25A065DD7D58A5DE43929 D4E9F9F11FCA6DBD1C5091691ED442A425D018A181411C0BFC27742284961024 4A154FF4F7122114D3607801447FE1A22428CF15D221262E8C84A92EA1AFF2E8 59D6DBB28D66AB9D266C27CB52A561ABD934A429D349DB19D3095FE737CF2AE2 8E3F412E7DFEC1131FBB7BF585A7EA958AFFC8BD7D195761E3820D33255ED948 E8C0294469E93272031E293C41850D545434F406592E6877055BF948C96E847B AE8DD3576F183776931F9E6F5FB6D79E7D6EE6D31745CEBA4F2D4D9C3EB571F3 B5C1CD9D331F78677A5E23F4FD7AE8318F9BA274E91CF50441FC153826EB2FDC AC56DDE0DEB94C51CB38468D403F99CC019D133B03775766E6344AC36F5CA7CB BD7C226EBD772ED790AFA9AADBE6FA1FBF3E7DD7B1FC5195D04EABBB507C2F1F D09DE03ECF00492D9FD77219A2F0E93D64E2F623A7F5CED87C7E7922A89B77CF ECDC7CD54C1A2D6FEECEF22BB3E726AC4C8497F7BC5393B46DA922C47076017E 42E06A0C23BF3A283298212CD5A5E190A9EC36B4C09ADA649513E77EF8EB58BC F0BEDDBFBC12E8B473CEEBD8A9CF1D9749BD35994D41ED6C98EB686A3A2EE576 7F29B6FD9A7F97CFDB85FE99A6E14A10D5C160746A952378D2C696A7A187124C FAB6581FECFCF50B4DD7F72FCE08272179841C1222E54B1F92B20657BD62A73F 689E9E276D5FC1888053BAC84022C0423F734FEF3D4A7C585A3A144BBDD8538C 73104E18650698FDD51908743E88728915443B61B83B983E7D525A5C67610A2E BD600E2228933225AA607FB874A7FFFAB11FBADF98D009A6D4EF13E5A418E565 6F51A91E8F60085DE3002A13BCBA920F0DE7D47B446356471943870D0E82136C 6F75EBDAE58AEA555B06B153FD86C01DC3202A4CD4D0187698E9066E73E2DA13 EB57BEB11D27C1729ADE10F906B53687388DF884C57FF4A173EE46B8F7C6FAF1 C3F5D393C682548ED0F8898CF4E34A6BE98344C8E1B2244808427B1151E518D3 68F3BDD9B88D47595081E316F46A967F968E2ADD8232C5321CA5BCCF645FAA1E 525D0565B144B28C318EE4EA58F04AAF73A50B0E240E07F13A0572E7603343CA 0D4EA179090FDE929E3644021B74326116522A3EA7F08F9E387F46293BEEEBC0 AF194FC5F20DAA5739AB571BEB8C7D67D8FD467FE78D24739133ED05E3AE57F3 1C47BF5BCE7396CF62F31FCE9EAEA7991F75321E0FACEA1E939BBC7BCD2AFE76 6BFB687BE241CB5E20D2378D0941E611F5F31C1A562BDED0716E6272352B9EE9 749E1F0E9672E608348D9C591BCFFA9579D75AA8B90B357F8C90B624D54CEF06 A0D1259783A6DDA8068E8DCC717A12F530594FD25BDD9E668A6B9D6E27892B88 5483E0C4C4DC9F36B7E48DE1DD53C79F5F5F5A2F12A9A851002491D03307424A 3F737CFE5F7B5EA59F62DF8F24BF1525CF18EAEB88BFB0D537334BFFAEAE665B 06AB47E81ECB39128C698CA7D3FBCB38793D0D35EAF28599132B037394645A8A 4791FF8F8F1D3F97318BA7CFCC55FFDBCD1BD753893D92EAD758F0E9BA6FE564 C21AEFF48637D2C1064F1B269AA9572F55BC771AC125B35257858B85E61C1E2F 2D308CF2688B0B6159D050834461CADC84837A8D4763626F12E3B5387D65307C 23CF6F0CFB3B294DA9816C537F8B5764A72DF6C8C2F4474E1EBDA73E8EF7BBBC 08150B65B4970D0EFD695EFC87F545EEA39F9CAEFE64A3322BCC38B5BCD8AEA6 452C87EBAED171EA5DA1012CDF2DD23D472DB2E1CBFB1D91A387AAE4F313A7DF 3775DCA836F75BED1787C9B37FF5875F9CAA1D2EECBECB39E5F57DB1E3B6FE55 B2F5077BDB06AAF89C8438D5E9005470DF1A27B410A8A61F9447A12718A6860D 4234B703A1494A1FAD4FBFB3B960159D3CCDF43AF4146A10D2C2B8C645DB307C 93581A4DD944EA88078D98074E88F24D704A4B0948548E2D21C0A590090719F4 B8B90CD552696273D156DF76F32F6D6CEEB1B4516B6BFCA35F826FDA1AB90654 55899A40641C1B2E26BE6F09191A4EF2F61F7EBB73EF54EDBE63B10F39CE8129 3DCDFF1C430749E00930665DA6607CA0AA014950FF9982C428D1EBA34C84504A D21C28166C3FC63DCF4583E7AF7ACBDDFCB327EA4FB2A5E75E98FF91B78B34EB 3E7567F2E4D1DD95A5E1B5BDA30F5C4C1EB1733BAC779CD4675EA14342C1A88E 49AE296D65E8800CFA2FAB57568F3E7C8A37F4D369533AAB435262420C03611A 890B17ACDFB22796B3579665331A7BF734F3AC61236DF4DDEC1BDB8567041F6C 0DD056431ECA5FCF3B83B5C97BC614E706AE140ED3F755BC1245773A131FB824 3DB6F9FC8D0672BDB71FDD59BA6EA58DA63D79FBCEF7E62FCE1AC322BAD2F3CE 4D2B5F49313421D78108BA8635A41C3280523598BB2850CE17701246C19E4AFF B551544E9CD78990FFDE3DCB2FBD367378CA59707AAC6771EA1B1637F56E9396 F48B3DA6B830EB9864D5DE72DFAD54FDBBEA45BB80B84F7C70CCB509D29B4753 70C33440AAC1614C99A68B867CFFD95707B7968EDC7B4AB674A6C93589633CE3 A6E160100D20D4255DDE8D92FAF979D5B075E430A42BB07EB87A87EA584E05AA 2023A0C8077931F0BCE1E0E60DCD0AA5A51B82A151309B51057862E1C029CCB5 C53BCD230B6E35006178137A674194532F46CA04618AA5F4CBDBFD62B5FA8EA3 E6AC1DF1D82536E5261AF57FE925527EAD86CA3031431C0DE1D0EE4AB897560E 3D48C64E72BD8CF47D12572F6DCAA26873BD77E3B245A389E9000CEC539D3019 6699CADC645FF18135D8202F3CB1D9EFD8C334BF95ABEBDCD8167C10A6768E1F 39B2E0E0FEE595B5B71D5EF8717FE21C8B733FEB115C9156A9A40AA71765D7A8 8EACC008C1AC92188665A1912D71A9A17460C8581243C14706D9B2EC02D0A41F 1221C8C1EB9BC95091AA61A1F6B9EC22D4C72A5432963C953C13FA5DE93BB537 2CFCECEEEE56065564503187F358567AAC1D80687D59E95B4B847A45B8A5307A 42E518429FA8CFBCBB36666934410A076B5C6C000452B425832D9BFE49BEF595 AD8D71BF7E37197F57FDF0E9C95924339186380E45916BCE5EE1469BEA88DC31 09D734A987D05A9EEC09BEC892E522BC50AFDF5DD09661D99E335D0C6B82E814 6538F63AE2CF8AF89B79FCECA0580B73DF30175CF73EC33E4FBD77B8A26D3975 53132E91D24CDFABA579A7DE20A6993B16C42B811CBD80B1C3F242EF1C971860 7DAE81237174EAD8467891A267D3F0E9787F53F23E8D9CAE3C12D407926FCBBC 93327CA0EBA1E3A21160FE2F4E1EF9A71635D2C2305D0D34AEF3EC55CBFA9BCD BD97C3B40B8E42906D031BBDCDB17EC49BBFDB194FA33CAFD8DFB5E3FF67E5B5 5B29D7FB2AC7A6F03452CBDFCDADFF74F4C2854162E6C3A2ED2CD7AAFFC76B2F BFE0997CAE79EDFA46CD420DECEACD1BB3622F2F5C1B9D68353E677A97DCC699 8C563486F3F5C2649A771A70D28122BDB84B17271DDA423B774ACB040ECA77A0 8FAAB10494B78885989109B269A2C5B4FF1759B454B0A5FD2CC90CBDE753BD4C 6C7EB6EE7F7EFEF0A39E77C8D7C96590C65B13B7EB97BDDA3F595E7C91263304 FDCBC3E39F1A3BE684308DA6E17D2C863D8506B43AA039172CEA47B18617AEFB 64D25B8A9379A9BE78E8FC596579F5201B6F2E86F19DE79EFAC953A76694D111 1D9BE6339A1F58D55F91C35F5ABE2D84E12ACD9819D29B927168B77D0B1F6E39 4000DD78301104DED42E36393414C90A4217AB63EFA8CDDA9D30B27BAD403F54 E4295541AA86509B50488706C40562636EE3DC00990F74A0A374B019F56A294D ECD1E87802F0052B246F6454152A21451CE4AAC2ECD0089E76D46FE7BBCF1761 9D38B3CAB441C1CDA8606AF1A846C414B5260CCF301CCD177C94593EBBFB27DF D7FCF885C8D2809ED97A55429F8463D080824148D97386461A94EA4D692998FF 85B54B39878841CA234C1D3F3325F633D4776CD979EA7BEDBD3CF9F431E79B83 B5975E9DFFD107799C75BF7B7BEAECA9DDEB8BF12BBB0BF79C293EDA888D6E63 DF29FCB2391215CC141C39A6D038013AF669EC2E3D7BABD16AD6CE8C0BB7A0F4 0C32AD9882898FC9217C319BE9474C5F1F6E3DF1B2E1F4C61E9A6093D5D80F6B 435BBC26571797173E7852D563AA6CB66FAF5D5D9C3E3DED003B261AAA133FE0 8B51F8D4CAE47B2E88C3D6D6B3D7EB85E9BFFDF8CEC69235AC34CDD68D3B970F DDB360862C5F8CEC3353A99D519ED8A3BE79FD305201DDDE104EB1A6670A8C24 2938684960576639DCC10E12E12F9FDF0E576AA7A62C4F1545A81F95EB068C16 C2CA6CE4176BA531F7544E07ADEECABE1B54BC8BADBC9DC340AA8EDB3AAE3992 583AAD3AC874293672F0B5353D54E55736B79F7ED19D705B17E7941A82FD0C0C 1F80140B58D910644B97F455981595B3B3B2618A02D9CA1778A4EAA9C0670157 1494642B188CF60AA58AD170372E9BB140370ED08DCEFA8C43C6ABD3B5DEA03B 6C9C3F11C30FC730E984CA550963C2521A729086B5DFBF935432F77C939E6E0E 44ECE8F507DDA79A3D0BE83146907200302A185D329040F16A7FB76F54CFF953 7749C3D5E91452459E5399E9C7992EBDD25B596C58D86D56B99920DC27BC4024 20B4B1FF527CE52F76B7569C0E1637546F39161DD9D888F241D2E3095B702C54 141F3D7DE4E3870F9FEBE48D22193A61666318BE04B16670082EC72847D67DA0 5D8E356C354B35196087A319C2837E51B0C6E4C065CBA6603C92B410E5F130C9 A44A342344FD427610EA12BC2F44C88B4470565A6F6B7C911B7E4AF05691BFDE D95DE52C87A28B85991A4D0389D1683C416F2DCE200F592948BD628DB61EAAD5 3ED15A988A120F834090622C705D5C48271783F1992F2FDDF8CE70F78185E39F 98BFEB7CE1D238DD186E7650A2B15D56E42008685B7ABD10964E578DAA53C974 0C976CABDFD927EECD34713C75C294E7A4DFE27EDD7203B2CFBCC6A6E9BC54C4 8F6DADBC3A1CEE09D442E8DE5AFBDD5373472D3A6514BE6455910630B0A19FB2 E81356687C6EE89B95A96019D5E8B3ACC54B9274E3AA5FD19496E4CC9506DC3B D4244862183DCFD8B18D7EE06CA5E1AB4BE1AD5EEFAA8C07182504955EB25472 59B275EA22F96F4E1DFF69C55BD4EEE6AC8BC5ED22BFC2D01B5EF09D41EF76D8 B7F2E20C46EF9F9D7CCFF4F4429FE130340D53162A76BC2748FA7F6F2CDFE400 4D72962DF8D62F2C9CFBA141DE505168EB355615D8FFADC1FAEF90FE625AD452 DB91CE40E41AFFBB32BB189047C68287C7260FEDB06964DB1AD2E07450C1434B EF1762806A815998542F109D8AC1F0D0910C9A4B9529895BE24786C1F4C597C8 8A72C904778CCC40776A5E27CAEE84D98BFBE153FBC3DB0A84A534BA0D8AE4ED 75F30B174F3FDC6878FD417B67FB8A32FF18D9BFBE7823C2E85E1F7D60EC588D 5B37BABBA12BA07B0999213707860E8E859B70AE3156C5DFC4B4976BAA2A5B4A 40A0C7D801274E8CF3E803478FBD77E1689B87AD616732CC9811FC8D6DFE87D7 AF5C0735C5D199063C6EF6962B163F58C784AE04844DD3C9596E2339496D1814 95C5872AF589F698C184A3848FB08FC59861B5106E601D17A09F987B342B27BD 0E7E1EFEC1DF00E71B8030CB9A0D678C269AB4214DA432ACE14081721C6173BB 56DB9E187B6C4D07915DE4800E88234DDFC01E8D1D33D7EC7096D6CCCC702A0D 53530494546AECDECF3D38F1B947851B490D2A3482978E65D630F64AB74203BF 29337EA00105FDAC509FD7B1B7A01224C32111F25296B99BD3BE45D9DE932F4C 6456FC9149F2F54EB8B432FEA9FBD3FEA0F7D2F2CCC5F3DBCF5D66D7C3B13387 C93F981C5A9D462FE00EB32091E8DF8C0B42C1A9B300A84C6D3B5CECE52BF1D8 5DF3C9E4AE2BEF96AE971165731DCBADB222995B3A11EE195B7FFB82956FB41E 9ECEE7AAD218D82991FBFEAD27AECD5E385A39EDC5B84F5163E73B77C66A15EF 7C35F314EED13C709D2D1E7FF5A67566CC7F74AEF3D2A2B55B046F3FB5DDDBB2 3A66CB6EDD587EE9D0A5055307B82546CF4F4624B6786230566A202A2393242B 5BFE4A6D6A986B111A17C852670958BDD230D83F5E26C29F994D66A479AA258A D4928C52A1A8A54963610E3D4D4E57F4DF093A1B1B83F1EECA9E53F3BDF36359 13A6F51D5213868D2C416C098252C425181831B67C73ADE0CFDC8E37B6AA9726 691B7CD0C0684D832969E224E301653671521BEDAB4191FBA7A755DB419C982A 50D8843977706DD5C8BA2A719520AFB439D0893083D3DFB23FBF9C6983397A10 B5053684A5D54AAEDCAEB626D07890F89A96C21404E44B80DD19A40C536D27FB F4BFBC44268871CCAB3E7C24A64C3F234FDA65A651A59424F41515D0735E58FA 2A31C76C6BB0DB91E4706D4ABF5D4D39600413644F44068577DE63D75E8D3636 9C9A6B4D604834522718CB40F5D7BFBE71FB2BB9418EBD38B8F59CD7DF0A35E3 9CBCB593C43C44FAE922F4D92377FD737FFAECFE665137762BA8CA425FF0C204 C788D28118182126B8343A21652FAD414AE5FB520CF2CD09FA7264704407F181 80A22A6778CB44A8097B2254A48A0CF7B8D8537817AB011660CD2A65AA58C8D2 61926CCF4C93B4A8F8FE1BFBDB6FA451EA18256AB44C0167CD0506336F80CF6F 49B80305C81ADE899B630000FFFF49444154EA4B71C514C29F9E39728EBAED82 37A06A5BE496CE8FA42E0CFD1C7FC7155FBE75EB8BA7EFFB78E3E8F85E1CC5DD 657B780BF77768D2C34A93AD814486E9C5A268A8ECDDD81D27F5D5CDC144DD8D C3C1AE5DDBE46ACC2D168C7C01FB27D9E478417AF6DEE521FBB334FB1ACD7748 6239C623F5F627BCB17729F778ACDFE6403FE20DB9BFD91CABE57A59EB9764C1 0C288143035B08134A3150F886563C9D869B6E51E8F86A151A4E537054C941E7 5DFF4FD1C0AA9633A3DFC7BCB833FEEED764F1241DFEF9F6E24AD21709D4A54B ED12BDC9F44E12FFEBE9E3FFACE06385D537C4862557F27CCDAA7C797FEFB174 A021C6516EFCA3C9C3EFF58320E9E5463EB40AFDAAEB5D3925EAEBCDFA2F87CB 5FE9EC6485C616E881B1899F9F3CF260AF1F7A9D7EC31EDBF202DAFC7F8BCEBF D9BD1513B290D72972776D54A9E08F8FD73F5935CEC73BE3593A306710B899C8 348047AFC99D7E3BB494A1700476F4BAD1D15AFF7D21341B56C87272FDEA514E 50E8A89C704854509C07F33D9D27DA03185CCBAADE9315F9155E3CBF126EAEC6 11A2911523839FE1E82726A67EF4C87D4A3C3F34EB9755ED3FBF74ED5A9CE82C 55277848C9501D1C3B9703B0967EBB90418A1454F860393B34814F72473FBA02 5249824B58A51C159D29D02308BDA7EE9FF6BD5A307EC7A9FFF295571EE3716A 424B95061EC55BC5695014A50C7861795848F8818F9846BE7A8B09306176CDE3 274EFED4AE4A92C4161A5888C0307D8A6A424C5043432B8F82A227F78DC2D210 E2E06052FDBD44584E5208D0CDD71F5CA39904FB1C6C17F5B5C606BA5E119703 76636DEB54CF3F317BFA8936FE52BC418662B2306D4BBF9EAEEF7257F1315999 524D221DDAAA78329EEE6ECF1EAA9CFEF98FF18767A97E4AD0F6EA425BABBE1B A1AFC92AAF01FE534A5095BA8BD22813212F132150108935FA4D944E84041261 472742528B1FADA26FECCA4E2FF8F85DC39DDDFEB5ADB9B3A7B69FB96CAC4A73 A66E7F7A320DE25A0F46E929B459EA7DA24100D3D0C9CD1C6840D150317787DF 59B75AA6B82F73F8255569E448E81CA8437E0E7D88A923088EBC9DC7BE4B3B77 DA0FCF25F39E8963C2102A9A6B4FDCA87B95FA0313835A57294F3D3FF4A2CCBE AF168EA94A371878869739E69FDC5CF792994F5FCC6F6D26AF6FB51E3ABBA783 F91E6DB9134BAB2FCF9C9D36BB995C97F4C254AA314611911CF03C24C242D1BC 1C6241E55CBA7E1E820826802428095447D1C23B7EFE935FC7BB3F77B432C5ED 393EB473FDDE03E19832537E1149E18966BE952B56382DBD40C6BB373B55DF73 CEB5D198468C4C7952E34A93B40CE42333134EC6909DD3A84E27C5CBE9C677AE D45AAA76DE2B82388342AFEB146065A470C11D0D4D345EA847377A862DECA335 D99CE0B84EC1B642336B0363701BE2461D18A1B0C03D119A6B8648DF2498CE3A A5296CAE70A433609E4BCBA8F2BEECECAD8DCFCF184E4320073A2F75042F791B 1C014A860D11EDAD1ABF79CD99ACF69BCABB77CE1A7334C564384F1DE26AC692 405F08B735D5577E0E043A07F7032EFAAB3CCCABED07917B8253A5D3201C2560 A7205D33072782EEE26BE2E67AD5AB39E319ABDC40D84D16CF3EFDDFF73A5BD1 000F9786EA1525D70BD68FF820E230A328D58F4D4F7CE6D0A1D7766FA45EF1A1 DADCC9FD0235DC9EA9434FA94806DE8BA5ED309CD680752DB5F58336D4E80CB3 AC081F405B1D5BA031142A5AA529181A91E5B292AC2A5191A7B84871C2E89E82 B6CC3D2A06D0F203AED27D872E39E2998DDD6E264048C473E31CA6290C8D9279 29A1588AB7C14F7B73731F7CBC69BF8BBF7F4C391ACB2ABFC66281A820830D3F D29AF887F6442BCDC01B0C6781A5AA98889833B7BAE758FF75A3FBF0F8A99FF5 C768BCF38AD1BDAEC38EA0A934B6395943C60D21BAB60E1B7D9E7475747A68E1 7CB0959E55C1AC30A3AC7FDBE8C70D3C67D9F7A7F6BC90A119BF6ACA5F6663B7 7617335ECC20E38375EF1FD46B97945BC3E00D332C65A65C4E4D81D3DA88531F 7456E0035182B2BF4096D65E6543212F4AD360551639473E73E51722F0872C3D 5915A0264DA16A16153C5FA5FC0FF6FB7F34C8D7852C44854B9D69D30AC6BF78 71FEB349D0486D66683AB8B71A982F0E064B06BE1285833DF585F6F18F617782 8485A55F8A8384CFC0282F342D169AE44E50FDAD1B4BDF8A32E5D20F555AFFAE 317D7E77538EB181ADF373EB0DA7F2E5DDE11F6EED6C3A82BA6C4E193F52215F 085A2774B09274E054128358B2078A0C0639D06427A569EC48B3BD744953A377 8B4BC991D2470F3CAEE13C89C2A9334C85A3B2C600FFE7225F382295435BA92A F157FBC537BBE9EFF6F6BE2750567135D139CEC5A3274FFDFB22AA5BB413547E 7377E7FF5ADBEC063A91BA4666E97844342932B96D150E0245E072301D260FC8 C85014838EBE69E37C94D8884CF32CCA3DC62B06D159517FAF6C38D6856AE3C1 6367AFDEBEF9F8EA9DA1FE62BDEE8B3717217AB363468D00F3283D953747DE74 B4573FE0D9840FDA2B4BEC0903D71AB43F32B970CC6FBCE8AE4D46EAA4AA4C14 145A85956C1A749CD01A52B6093D7C301CA4530083D680B2211F7E8524A55957 79C442CBC678BD56E0A08291129DC21995250CCECD5D625EF1E81F76579F6183 C6ECD4BC5F439B9D38CD9105150A1B893A130D4DD0090DBC8AA348D332352B15 3C9A3F34F5C0CFFF4FE2FEA63594B25A83DE62AC9F2808C7300B7E8F03898F6B A6AF919D015DAD50A2E5205909CD108C30532528D7A8B8CB4976FB5BCF9C6E2C A46F9B527F79CDC8FBD6C72E6CDE5C153793B9C3A7BA2FBF4CBA3CB650FBE327 8D294A0728F176BCAC817000E61738B1870231195759E4C889A15B3CB7DBEFEC 8DBFFB5C36360D926FCA330F949B8B58E694B83AB9771FFF5E7AE3FACC3B16A2 E33AD04416B39CA23E7861476E158DF79E099B6F100D902EDBFCA65179D7D470 6ACB4C30D3A489BBD6B3E8F26BB7E7DE7D7E1CF1C12BAFD7DEF14058F4D97ED4 1A9BBD79EBCAA113937837123BD43E5F4B9D0867B99D9A9AC5489143ED5B7018 25848E10784BA14DDCCCB4231F4AE4EE90B971E61D7DDB07BF83F77FFE68FDB0 A526E38468E6E4F9CA46285366A681A1C9AA681F657164370C62B6C35B7DC776 DC732D344994E60B5025C726AD520C9DB5C2669A30290D608656F2ECF6F6B5A5 C9930DEF30E14E0AE39C42330C108F5612C42D74A0B5442DBD15128B998702D5 9E40B4A9F7AC466B60ECABF788B0386D28FDC335AE127A071714C708C7655BC8 C8D2A05038451A6F31621A5EBA9B856167ECD02C362A1AECC28C3C18C7C1C124 D65F0CB088F57757D0AFBF583D3EB96947953393F5432DE89F3515279AA46170 B3048B7A70DAB1391538E74639B6AED1FA20B1EDA366FDACB27D905B3EA8A6A6 88EB7855A0B8C76E6E6FBE76AB316554E728EF916B5FE9BDF1BC0813BC83F35B 61FA9A29B6F6E32C31869A3B17FC6CADF69EBB4EAEDC7EA91DC63F75E6DC9142 73BE2277384CE8B291AD0434CC946A693041A1D1031CBF52325259FBFE068624 C9CAA3410E86A56864935D0ECEF0B259C64EA448649EA0501A7B186F2335543C 2E322679AE34F0A7CC32C334FD6A3C0CB3342BFB42C5A8B20343DD30D05FB6E2 1DE4390C6203EA4DCCAB465146BED9830764B4FCC22A322996D306F9EC91E317 0AC3CD9900B313700C76B14E4506372BD78783AB69FAC8F1F3F7928A08BB4BDD AD4816BB247BC38A372BF6B5E55DA6A8E3E9D82A6A35AF50694BA963C2B8AFBD 9031BE83338DA38EC5F96961E28AFF5D077F29DD7FB5B3AF06EC98EBBE4D53FD C98943B61D606E223088C760AD55C67E98C8B460B603E13767BF7E00C597C1B1 BC853221801038D0D852C600DA8754D947537EE58196A4FEC7606E2011CBE37E 606C55EC1B61FEE246F8ED387C15A506450F70FC2B27EEBA3B2C7AB60C711ECA 78A0D09584DD688FFDD58DC513B5EA175A537785A8A5378FAD43585C28640BCB E205736417313E36F7DB4B6BFFA3B74909FD27F3F39F71EC19965589132AEB45 93FCC5DEC65F0DF7D652B4E018EFF55A9F1C9F3E49648D1652A3581836B27410 CA08502B42A10F5B96EAB5A5EA5DD9238D0F5431470646EAC04E168DECD6A161 AA9C01287D5DE0CFC06F1C9FB114F457351ACD0A4D9D32AFF5DCFEF06B7BDB4F 85FD958299D432A5FD99C3E8D2FC7C8B56F73BFD9BDB7B1D26AB966972067AEA B6E556ED71D79920A607E8A374DC2E315CE92F0ABDEE30ED467126C08765676F EFC5ADF0DB6172DB92A8A210C3C1505635A62134B5D02E170CFC374D683F409A 20B19107C48147D2281B1E5815C2822D55A731038BDAEF5B389530A0943F2A25 01A5069C6DD374987C342F8ED5679B753FCD871597D6949CE268013B9EC6D5BE AD615D68C234DD1BA0592F0A30BAD6C94632CE0ACEA1720378025B841AA581A1 301A2ED1B85EB6196BE9FC05624F1AD7A37DC37C6667E7F2A0BBED1A03D754FA 0181CC55E1913C209ABE2BBDBAF4866A1876C3B46DC1025305A6D97C70E1D0CF 7F229898CCB8B00D0FA9B2A7C280A1687430DC8FE941BE1F75CD0801FD6F147A 4629C762A829BA2AB6D3ACDF79F5FA4263363D55155F7FD572A9F58EC39B6B1B FC7A387FE474FF754D5CEDAD6177FC43C7C9A461649A5E7689ACC344A5A9934C 425278E0B9CDB8C17D1E14CBF9DA956B53170FD927CFEA440805DB1CDEAF66CD A928748875849B3CF75AEFD597671E399C9CC2A408F595B9A4995CEE4557B6C7 DE7D223FDA478E81BE27F69FDF997ADF49B690A3AC90A014ED19D7ADABCF5FAD 9F9A9D1B6FAFBF7879E6E1BB06FADB07BCD998BBAD13E1B9E97C63176F5BEEA5 566647382FACC2040F05A953009C0B72CD00C1744987305168A89153C44A9EC1 996046BF987EC74F3C86377E666AEA5C833506392D4CC3B725D40EA491087D17 994B12271E844ED530ED60703BA6CAAA5CA8C939021EE8A6CE08D4A01E412043 A36102C7D8D154FD567FE7894543CAB14B93AAA679564A9551FA6395837F7A89 5BA6A656A6A826B706D4E6E6A18A6A8D13670CDE1B2D099C02090746EB8804A5 4D38EC11ACB3204ECAE32F4AA926851902ECC8094C929AD1565FC334AFD542A6 AB53008C02EAF7A00AA05120C1CE90C1F7B797D5AF3C659D9B8E036935EDD6D9 B9AC82904F35B925E0D4087D554A8C4880A12F1BAE1A909D28C26191DB95F679 ECCD0A5576D8C161A22A64D73123948638B3C35B1B4BAFBD7CF1E88970913DF3 4757A3ACBAADE8D5580788FC0ECF630DA47785A693C2B0FD804C9BFC7492FEB3 7BDF7E1A114D9EA2A2673A4A237870262F0BFB2566075E8860E2DF04FFCBD207 74343548CA2806E77B1C44A04731ED60A4501DA83A41BD344722127986FBD2D8 A5785FC17C7D9C6731CB72CB2A0878F85A983C557136B63737E23019CD488CC0 F4DF794D1CA45E2A1D31C2DB548C6CE0CAA9D4BF5711D25B4DE3D02A971F0EDA 1F9E9B0BE2C412C22ABDA2242888114B077BC3B99DC6451C5F3A7C520ABC3DEC EF0FBA7A035CCDBBDF12836507309C954A87FA961130968CD5C90453F707CDE3 9E97457BFAD3358EE79CD69058DF18EEFE69B77F5B1573B5E0C7EBED7BFCD6D9 C29853B860C3D8CA4560085538A012673082220331C76CC44C9183D838FA478E A2A5546F361894B70CE65F6F726050DF1F09FBA0B23BB06494E5C4A612AE7E28 16B4C7B39C0AFDAAB6047A56F03FEFED7C6F105DC4E4678E5E7A7B6108BE39A4 8A9BD57E94AC59E849C4EE0CD2475B9397B2E1314A1BA49214726815B9856BB9 E5E4ACDF44A1CA3C1E3C9D935FDCB83AE9577E696AE1DEB49778B870A65E19AA 5F8D9697F7F73561BB7FC2FD7875EA11E61D651A3FB2D853B1262954FA423A08 A7B60377542E27F0CA2B95D9CB1EAA72F8EDA0DB4A8D10811CA11CF926AF1AC9 B92B72E0A22015E350EE1D79FB80B017589A7061B8CB96F5B54EE7CF3677AF65 9A8554E7ACC111623CDA6EDED79C98B4488DA240AFD42CD34B4D789AEC581565 38191A299DE0116D536FF67DC1D936D7997B98C49A425996B527F13345FEF5AC FFB5E54E02EEF52E294663421C2C4A6DB0FB26196855811C2E5C33F4908CCEED 7EC0BFBEF4B72C6F3A076D0D351A3518759A8E1A3EE17B286CEA40A043CDE6E7 DA5004CBC37E60E2A6EB683CD7345DCD0276915856EC7A38581F445CAA451B34 987228322B71A0E8F4035512D8AA1ADEEBD46EEBA4A8F15C4DAA3A96535563CA 77A70D6FDAAAFB5E735DAA27F7775E4AC162A9AAA39B62B6250D134E6BFD424E 49B32568DD36357DA8DBA4A1B7932B263F7AF1F08F7D229B68A142B81A978334 1E1AF5CAE5162D88E170628207AB28AD1744B96281EA430FA20A411B84ED0E7B DBC9CAFAC4F42156C3FDAF3F579D6EDB77CFED6C6C6437FB0BD347FA3796EA13 33EB77AE8F3F7A824E3B4430C462613584593175E0E089E220424FC0E959236B 4A8DDAC6AB8B0D2C2BF73E20EC0A367C19436B26F1692A32AA919970F0B595E5 A79F38F4E07C72D634E39451411CDF5932F71FBF593B55C70FF843A2EA3BDECA 63572A47C69BF72D301972AC318F6F0C1A5B2FDC2A86C9C2A5BB162F3F3B77DF 09C62211D1667D61F5D6D5F9BBA7F79797DDED8A77FF44610F1124425B47672C 74042C14544235A655541606E892981AD615143C952AAC9AAF98AB5BFE477FE9 49BCF9B35353175B45A0A325B7A8A3BF9168FC6531203D9161C8DAB03F745CD3 F28DF48EC85352BDBB261794324CB0B405B51D1D4B1D8DCE0B9BEB25E6E6ADFC F93B9BDFBD367F769E9EF49919D96006AB518B8EBCF0C6348593A62606C814C1 F046CF74A54E84B2356EB8E352959615A46CE7511E371A0A5768E9F10C26389A 81812BBB5E6C3A116AC0AED7700EC2D4A6C58679B81B36A69A7A8FD86E9581BC A8A113A1027B625E32429043EF6C2F59BFF66C76BAE5CD56F368D0BAFF041B33 731BBBB9D46892D954635D488A20EA598AB75126846662A6CCD3701006F5A346 E50C9C5C42F770A6B1803413916F9B2A827345E4EE7EEF6AF7B9ADF45535D8D0 5C3FBB9267D705DA50D95A37CA33027E07C818501D31F93D04FDC6A5074F49D2 3523E5613B8CF4FA4E414304722FE8A741F02A4921004B037A47E1D8AFF4BC25 D800860D7D69A86CFA1FED3939CA842053A0139A46CB60599F273AF3C9BEA0FB 54F560D08481430797A981F7A5EC6A9657A9F48DEADEA07F6B6FB32F788EBE5F 411A8D4EFCDD6C168888C2672524C2D1345669F544DF34DC1D5D07AAC9F190FD DCA1F3E70D228BC80295585B872DCDB12DA24C601238748917A9A9FAC49614AF 859D9E26C481FB9DCDADA7E30CD4996CFBFF67EC4D802DBBAEEBB073CE3DE78E 6FFAF3D07FE8B91B8D460368824003202912242D99B24C91D460592957942851 E2D8719C722A7165B0934A3955492576AAE24A2A2E3996234783455123458A10 21700007104377A3E7F977FFFEF39BDF9DCE94BDCF7DBFD1A0E938BFC006FAF3 FDF7EFBBF79CBDD7DA67EFB5161A352021C36EAA7471A8159F23CD9F985BA9F7 3727746F2EF6DB567C4784FF74F3E18541FFB0603FD56C7E6A6EE12489782979 5186A1871305689B5262FB3BE1584FE01E5C4AC9C964EE0C3BAA0CE0A2BAA9FA CBC898D4BA34007F0F1C39A14EDBC171A37162C07EE40A74407881C72E0BD3A2 492C01E001E72F3361012BDE30F437B71F7C79BBB7DC8C3EBB74E22FCAB465C3 CD4E5124D14DD2BBAB4711AF2F49719CB119A06DF050082F78A3F4D0F0CF2F55 A7050FB3688C82B7A2E4EFDE7CFBC5E5437FAFA81D36C5F9E5E8F7A5FEDDEB77 CF9BD101697F7961F1B3D37373BDFE940F5C5714C4C03B501CAA561E57D89F6B 1354B871C5764D5DAA776373848C534F450ADD9376DFB795B1592557EB3081EB 7B44380D1F2B45D73148289A0B80351E3A89C3EF2C0A116C04B5EF8CD497AEDF 5FF3EBFF569D1D0C83A7E717025278A268D483A2B3DD641EBC21DA2789308464 A8781A40C877D2F06349411C4547131537A306BF2F4D5340F201C3668B5DAFF1 F5ADC1EF6EF5BEDE199AB849720FDD4E292CD711098C93478475E899F7FDE8AB 7C6DE9BE5760B55A5D011F12320622C717AA695D1CA2C01F551A80F12A8F5E3A F9D46E73B37F71ED1931F1447D3E61A2E0EC9E4CAFC8C1B777B7D6B52B324BEC C843314FD81ADC734D9928780159BCAA22E00A31CE31069E256C5759DD62D4AF A7CE2D2309C88262AB4173766A1152D39D618FABBC49AD6FD0340BDE5770D630 BC55D009EAD585D7A8031BCFA622BE2A48ADA1E7FE832F4C7CF6E33D200D9686 F01340A1356E4C08E225E781E40C239F72756D85FDB1C8BADDF9351B126C15E8 0C36EE673BDBB3274F9479F6F04F5E9B3B72307AEAE0E6DD9BE54EB6942CF4EE 3C98387DEACEF7BF35F7DC89F870CB7A3919699D34B45FF301C0969932B02054 5060EB465F1A31332F1FECB1772E472F9CA3CD491A4E1AB425F78025A53A1710 C594606B3BF7BFF6EAF2D9B9E26CC23BA501B2C8556338DB79FDB62A77A73FF3 54C66D6C93ED372E0DF786873FF9924A061A1B2D631417BBD4DD7EEDE2818FBE 7C7DE3DADCD18990DA515B4F4E1EDDBAFADEEC8B0BEB37AEB7F6266B2FCC49D1 2765290A81D60CE8295058695CEFA07338C5F364E098C5D007F4C493DD287DCF EB99D54FFD833FA1DDFFEA70F3C9864AE096E610DA4BF89031C5A68D5CCB01EC A6E6B09F41BE0B264C7E9BA54336716E4AAF6A8D76A5B1273CF837C0672DB80C 34E526B853DB7EFD42FAF0DEC1978E65F3B0D6B30478620E4CD2870400A1904A C849403BA95726839B5D3FD17C35D193D3229AC19E3B08A7383BEF535AD37CC2 D0C873C236044BA378B46AB095D143A531488FC0B801E986B5F69D07592A0F1C 5D95AA10514B6A2CBA78B88510A63BA72608D47267E36EEBFF78B373A43E7978 AE73FFCEF49387F4F1A92C2489446FB99C63220C94F3BD44474558E4290E96B1 08D6D2A0B7197ACDA0FE0C114B9A630EF6F08408EEF11E6329DC6C8003DE1E7D EF7FFEF3CD6F654091AF8E36CE1B7BC38677069DBDDCA6EDAC4622CF87583D3A DD60BFFCECE967198BBBBDA9466D980E26E34630CA816AA6BEABBE310C5D04D6 107C50741E1CBB4F8CB77855ED50A884C32A2919D7D2A82B317C78DE80610A09 B74AA6A2AF7457410AA46D4A76891C5A6CFAA20092085B27E5DB65F7965693A6 09D871271B0E2CB6648F4F4D8C9B85228FD4F5612B794ED3A63A6621E30A1479 0C78BB5A1709CA1FB3B5FF6EF9E989417BE4A5C2133525D0FDC5335898214A7A 320F591DA80FAD6FF8FCEDD1CE66A43BC2FBCE839D2B6D99D466003247A6DB8A 2C1B1553ADE983CDD9E7253B0B9174D4B5ADE87A29DF54F28B77EF95717076AA F9D3B5E64F2649ABD783305A84AC48BC019310EB28B609DB880908514A29AC8B 32B4B2D2743F0D50779F2B37EFCA25A3FA1C555264C2D59891228C47C5F62D05 C61EAC55519897688A6C039AA11CBAC2415A49D2DC26F1E57AF0CF1EDEFDDAD6 A8AFED4F35273E33756049D30E31DBC0CB47831A4EED9863C974AB57901AE90A 00D5105FA4AF47BED38A64A52613D35F547BBFBDBBFEB3078EFDE2A8D5F3F43F B43BFF72341AF446CF47FEE7A6973FC5FCA3B28823B4E9E9036467CC29E7020C D72A84484A79EE744658557574C7CFCC7524D3FDE27095FE2180BA995CF2A8F6 3B3639238E42BA804E6C920105A080320DCAE8E1E1ABC1EE1E08F20A2B28F1C4 D56EBA19849F8C43D3EDC137837A90C71495F4AD89205700C80B04301D809122 B36988D52957CC1FF341EA0ED50003CAB20CFD80732FCB20F8EE358A2CF05ABB C6BFEA277F7C7FEB3B0FDB6B9959073E02090CB5DD736AB4EF148D4A82C67BBA 1A6ADFAFDC3B6B5ABB9F05B14CE955EE6290DF5D11C35142EA61EA2131A14D4F 1C989ABAB9BB716E66EED9C6322FE8ADC1DEF96CEF4ADE4BB1559E4C87742116 532288393F59E889D6047C0179B5952607AA5531B22FFCE4802BDDE86EF54769 7764F74A00A0B019ED90EB92EA52A5AEFB0152A808A3988B06B72C01A26B81D1 48A7248252E9091685EC742D4C3CDA107C35B2D3ACED9F3AFAC4BFF3B3F4A9C3 39501289EE0AAE0BA912BA61E3623FC79B40B5C2E930774080D05564B9DEF1CB DEE0D64D69F2E9278E640F7AF77FF0C6CAC963E1C2C2BDAB17E2280AF2506DF6 273F74FAF26B5F5E3C79ACF5E44A110D833452518D88D8439F4500D8236A8B20 CD0040C01352CD49D11EA5AFFFC03F72325E59A5B519220505A4E8ABC2E43E45 8B6C6F77B8FEA75F9D3994D8732D6FE8B140652C8FF5E4F0EDEDBD4B570E7EE6 637A2E8260C9D776D75FBF79F88597CA1310F700C0FBD26FB476C4E0F77E10CE 2E6EFAA3682168B66AA37B9DD6ECC99D2B17A75E5CBC77EDEACC60B6F6C26C2E 7A342F60E5230E00F40168A7B2E0410DCD02780EC923156719CF229A742FB6C9 6E6DFAC9579EF86BFF171DFCF74792A335C8BD56A710436814DA06C741F4B474 A271F5742021E027D3457EC71FF6C4CC4767CBD542511ED20908D308481870C9 40736089D67BDDDCFDF60F1A5364F2D999B25594360F0B0E5880047EC1240A2D 1BAC01422264AA36BAD5F3634D96849A980EEA0B58C444D71B8FEA90B09AE133 C09C3D031C5CE311009220A0B31AB325DA1301592F708F87C9DA858B7EDC9C5F 5DC096581A3A856186A55152BA26010FA562987AB87E6BFE372E6E4D91A9932B 726BA3F0CAFA878FEBD93AC44AAE810042A4A63ECEE85B85BDAB9448AC8E6A0A BCC24BFB0F49A192C633343EAE30E097F05CDD162E95EDC930F5D5C8BB25DFFD 87DF79F88EEE4A7BADD8BBA4C8F5823F1C0EDB1A0542028BBE6B8B46FECAE927 8F2F04D777AF7C746AFEB95D581F369BAEC97637F42094BB1A3F7C017646D309 CA7CCF99F45274EB76811B63B5225496144FDFF073625330C15B830739F02100 2D64D216860C833DAB7788855CBD4BED2E29B0F51108798EBDD4ED90BF237B6F 75FA43EC0EC5A2A87CBC29C6C54546C6840FFE238367A321DC205B37EEA84D8D 0F14C7AFA91C52E137FC470BCB7FA3B1140CF63A2C0B4594E401254209D88F79 C04D41CBDC960D1A181BEC84C9B7B3DEF764EF924AEF0CD2306CD4D3E274149C 690407EB7EC323D35EAB36644D3D028A73839AAF95E5971EEEEC4AF57273E2E7 67E73E598B5B65895D7991CF792707EE100A373163D14C107B409CF5983BFCF3 B1619A0E03D7FD5159CE7BE313D97142B0E451273C2E515760260825DD41ACAD 4CE64805AD5D0427DC4A95E14850E9F9CC8B68BFA833CFB06264712473984C7E BDDFFF8D07EBDFCE4B40F17F756EEEE38D79366203331A660F6703B6ECB562B8 39BE0056583227BAAD21643021791E24B726C5ABDBD75A8CBEDC5C1E4AF6CFBA 9BBFBFBD57F7A2BF3CB9FC1F36C2F95A5C2BB28687C134658AD40260101E4A99 3B3EE12ED7D78E84B8416A875D30118E6374F51D5B8127B3DFF9E462B73B8776 140D2BC69847AA5343609500310B8F16B0146045EB212BE177D420060C732025 063E88F0463EAD73DFCFF0777B5180C57E3C1E64A5670B1F4715B16104CFDF43 3CA3B1A66284E339A14A4C02E84D5972875334E05D20DBA504C82958484DB055 90AFEC6CFDD6C6DDF76019699C8D93AE3B45D8CADA6DBF7D74BC92C79F738CE8 F085BA6A3150D52B1966DFE0B133458BC34AE4279295B985855B6BF76F8DBA6B 00887DD2F0D95322FC8848CED6EAABCDA0591741C26773FC98B850A4C42338EC D1A315A9B5AED8A0AB1545B9F684F4C24CB37E8E26D90002B654F69064973A1B EBB22C3CD8B2E5AE6A48D11001890057C05AC6F9261D46BE50BA61C8B465935C C4823726EC5C2D5F085AF5E3ABABBFF2B3F6D0AC8290877B0F27D3D07F142F40 5BD472477350A6340AAB79EEA4DC94C42F246B8BFE4EF7CA9570AEE92DCFC8F3 3B0F77DE3BF8D4199EB25B17BFBF70FAD0F0611A776CEDC3A72E7EEDF7E7570E CF3C736210ED267A8EF28878A81923CD5099015780C14A58254508A4D90F4732 BB78DDD064E2E429DB9A233280F598D21CE5C2202E59E10DCBDD3FFBB36442B3 17A73D15729D6B5E68E6B38766FDAB17569F7A469E9DED89EDE911DDF8E27B0B CBC78B8FCF48B323E045A2DE281BF91BF7C9CD0D7B70623BC9960EAE0E2FDC6B 2E1D5FBB7171E5C5C39B976FD4CAA9DA73B305EFDAA26029F1012559A7AAE5AA 66A8310ACF08EBF94929FA48553BA47D67A7D99A0E4FBD74FCD3FF9C0EFFA743 D16A2293CC1603A6983FD95235789A8AF633087E4607E940CB7E397950C9DB71 7B9BCDBC32AF0F17D290C49B85608D07A70C6013F62EC15D165FEC3CB87173F2 4C3D3E2A6C58282999C66C89BB91E1503F16D9A8C036455D2FEE0E5850920302 4BA3F12C75FB14B56A4C4859C378D392F81C15D460FB68C78370B99652B91507 1B0BE20F3C15BBF6DEA5E6E24A63AA01A1AFC0B36A00A0DC9ACC83E7650C6302 AB885C6F6FDE99FE97EFEE25A6797259E8ECC6B5CBC73EFA21BD3C59FA00E631 A15B9437C3E15CE99742A30E8A85E74421A8463A6F67EDAD5A72CC4B4E9BA869 4D8EE1C3625E30241D7A0F123DCCFEE8EAF7FFE9C52C9BB95BEA1BE9E84AAA6F E57A7720074526BC008215C4CD93B3CD234DC1DB0F3FFBE4E1E76DBC38C22E86 8EC030E85BE6CE9EAAF91FD83BCE8A5030BBAF2C8AD1C909C8288DC4DAD3DA69 01D871A7A89B1661C8BF35C9A5CAA5CCE2BEB5BB8C6C52B34D551F45444C259A 56723108FC1D6ABBAA78756FAF28325DD58F1EF5853AF5ECF71BEBE0B6FB0E4D 1A22F070106827714786148B65CE1D55B9721AABD17FF7E8E9CFD7A658BED7B7 C31A8B27550D5046C2450D90BEC921871A09904D7212EC2AFE03CE7E33DD7DB5 D805E6B41AF14FCF1C789E8A335ED03072500E67983F5FFA6BB5E0AB59FB77BB BBDFEB173382FEDCEAD19F4C1AA7898975A605CF81BDE124EB2EEC7B88B840A1 2108B0EADCCB919A6A7415991D3A3972879A71260505AFAB6333FBA809E8D167 1755DB91C682041EB8D2AA40AA318E539708B1C356A28892A2D8768B9A7F050F 21D8C922F089C84B66C40E15B764F1DFE63BDFC87AD339F9BBCDA58FF0FA666D 04776D75AB9C899261C293D44E8EC86E9D75429FA195B8DEF5E49586F7E660AF B537F8FCF4D1B6D0FF4BE7EED73BE90AA3FFDECCB11F4F6A87740F071571AE14 BB3258C0B1383066F355C771D5532C5D5795CB01AC62816CDC295B8D7DBB8242 C508C9FEA1618507AAFF8F54B299386CC77A4013A4176754E4909A50D8A24477 68021000BDAD2DDAEE58231FC6017C37318008B05429E0AF026D0F809E97D8E4 8996A8D8125272D4BE720397E35E4E77E508E6E06D95F381E11858FA58ECC776 223F4D2389632E9DC87F77307863ABFF8D07DD8B23D3C5B2BD8FC30FC42D43E9 72B0CB6A664C353931A8AC87BF0E82BD466119830358EEF09BA290120E96F2AA 29CA04015FF56AE8DA570CE135B375F2ECE4D4C7C2D68B2C3EC1FD165AFCC132 969CD912FD26F014D0D1595B35AC918A8593F1E9A7C59E79AC9D426E971EBE48 6874DE34CC1F09B64B48D7F306C48C8AF2DEB0BC5F16F765BA298B148225C3F3 C040889A310BC64EA96282DB5A5D844D7FC6278783BA17B3E99F7A7EEAF31F07 068D1297123BEB509C18537C69F13C491888C97862C26CC553613DF3A11523B3 7B7F70ED7AF3E8817C26A6DF5CDFF2D7979F7CCABB3BBA73FE8D951F3BB37665 635E35A2B3272EBEFA7BF3078ECE3C75BC17EF867405D63545F33456D0D4CA1E 973D4F49000E256E08C0FAB4DCEBA6D7B6269F79C6CE2C6322A45EE66500A6E0 9E79DCF75255BEF536257BF4F9296B039EA1BF6C9AE8200BFBBF7F87673CF9D9 A7BAD3ED2690CFDFB9ECF9F5E0332746C15E1D87D36313B4C8ED81FCF29BC9E2 F4ED69BB787845BF732F3974F0F2FD8B4F3C753CBDFCD092A8F6E13960849008 015A3AEB89D2EACCC39E18ECF612004B0A488D91D699A049FBE62EE0CFD6C1A9 7CEAC8994FFF211DFEA39570295161698AA147B9989954119E29B0DE480F602B F9BAE0693B6B1C18B08DE9EE166F7E6CC61C453951DFB680D113942B4407649F 876537F57F73BD5B76EBE75A625159D9C772268F34CE75E2A193C221718A1633 1E2C845A796F04F0841CF0E9CC1CF567D163085551813B049437211196867332 80ACECA19D9071DD0DB4542512268B050148846A777B6B6363EAF0C9A0EEC3AA 2BA545A13E847670339451E838854BD3D7ED9D87F117BF6B222E666BF0CFE69D 5B3CF1A79F3B954D86140B06CAF3856B99B0D24B7D9920C9F2FA1A473E6ADCE4 69FBBE2993FACC732499C3E880472B1E33934AE6367E2886ED9DFFFD9B977FFF EE1E9FB850963746F6562AEF0C477BFD0CAE53705C8D4C9740FB4E34EC5F3F71 EA33266A49350CF588433E534E1C00DE0D379976BE6170439910C06BB035C061 65F8366AD92329A690D484469339447F6A5CCE436E8882AC063067599A1D1BE6 DA74ACDD26668FA80227684CA924D0B43B32BD3D1C7871837BFEB7B25E99E64E 27EA7D2FA78A1602DA30AE83A14A0EA412B6C7FA157A75EBEAD50882B1FE0857 22E036C7F4C9303AA8756900E7A2524E9D06046EAD2613D634B89D68C5B3CDE6 A208166D50F68AB528F9A79D075FD959AF29F2F3F3739F9E9A6BF5D359EB03C4 18D9D4D4FD3B25FDDA68F45B3B9B436B3E3A3DF10BD3133FE6799390EE43D1F1 21002B4899915225845B477DAAD951005A189E3C6238223183CA1B8E02EE1F07 8E950AC66275F6511E1C1F906A8E4DB36E20D309ECEC1B8E03A2C491248B31DF 6ABF98280924C211D011582D0AB542714C2896AC3065CE60ED914661BF1B44FF 9BE97C717BFD749FFCAD8307E71B51AD6F0F0F3D12CADD389F49BD851EDF8C54 47D49B286C38B89F0CBFE5F51E66E65CEDA4E998DFE8AC7D89EE1EAFD5FF463C FBB9D01774D88F6D5DF30407CA3DF8740A528F70E74A68BC0318969402D713AF 6CBAB0F7D89548C6A3DE15AAE2FB1F1D198D71D3A8FB66269533B4E353EE0CCF 3A47A15E50D6244D72E2C16746850B86F65E90FE0115F9B04561EF6A58E5D824 AC810F9392280944288617185848220C8CF0257347AF900835AB9E42C55671A0 C5569E4874DF977A9FCBE1D5138E6ABE3AA399B67954AA86120312BF45C9D746 E97736F66EECF4360AC86FDE38F1E1930618AC20397A15BF456F2BA7C01B60F1 0461108078F75DF49B4274E7951C87878853164475F68C9C69F82F4FCE3D1745 6798BF2C4D0D6E5440B39049C0C6C08C341F0579C5B299DB1AD59F3875E33EA6 DD3F48E00AFF0FE423A87DA958B5C030B2088F216DC2C12DADA428875C6F5176 5FDAB5917A30547BB91996DA96AAEE91C9800187F223D2E4FE0AF50F3793F999 B03FA967BFF0D2C42BE7465EC895EFE3110D247A4935A45D08A5E884E2A10278 55B841470ACB869AF6D28737E9CE4EFDE8724FC8F0ABB73AC7D9ECC143ECFCE6 C35B97667FFCECCD776FAC360F472BB3175FFBA3032B27278FAE66AD11854468 500417C09A44178B2E551D6083B8B6B0028D35DED2E8FE6BE71B4F9DF60F9FB2 32A27857E1C61710D7507AAC34F6E225953FA41F9A3010BC4B00FFD9A03E8A4C 9DFFE960E3C2C6E25F7BBAB738A81535F6DAFD8DEDBDC5BFF04C3A9907A382AB 896C6A86B60BFEA5EF9ADDDEFD6313CB4F9EF22EDCF60ECDBEB371F1D8E241BE 5628C16BCFCF17A26BCBC2078A8DB56269740EBF5AA24C1641C7992C83A8C973 9E6EE7DD9DFECC8184B5423279FAF4277F9B76FFF1623257977E0ECB378E6232 35A104DAC27BA32C7DD0218517F156D653A6B65E1B1E1C6C90F8F94973A22021 6765C2FDC80AF40A32D85212F6AF6F477F70BF9C30E1C726757DE841A8D5DCC0 D30152863A0B687CAD39E604C86C9008ED8352D2115B0AC9CC020B66DDE4B84B 8436A25ED3D056091984F4107A22E7A9DA12D124BC90680422A80FA87EF7C655 ADE5CCC967282C37B4ED03C81FB8738EC263520373F2F0E48DFAAAD7DDF1FEE0 0D0EE931B0C98945930F6FBE77F9F8473EA45767606788543A54685908173BE0 9008B1AC3640F70E120384D4D94E7BBB3D77E02C8D0F1180459ED7D569D3CECA D2B05A9B3F78B0F63FFED9CE0FBAD72DF96EA96E64E2CE305B1B76D3144DA26B 46001E1D70BDE2D17F70FAD99FF6E2A0EC0F035570144EF580023B4B15E9551B D13569084852C2AD5E777C851404A3B0719678187EB1F8E1722196C0D1F70F0F C50BA325FCA972A56EFB615EAA81B1B06053D740ACF202789B6C25D7F3E19B3B ED1D471952EE14179D28D47820D089F7603BA5E0A672BB0E04C9CBAAD59E01B4 813BAC51EF5C62FB1DC24F403C4D45A6097D8AD77C953214AE2423418639D935 64CF154E7D577D05E212D7C245429E4E5AC71BD3455CFFDD3BD76F75F6FE5230 F11FAF1E69ED6E037074DDACCC8BC93799FAC7BDDE958DED194A7F7175F5F353 D30B79A7C9B1535679A20C99F12102A742195F4E03A090D40D3253E048022E5E 01C5E208A320EEF996FA86E4AEF705D582C71E8EE352F4075549ACC0134657FD 743EA788439C582FEC2C55C2FF1441B50292A4AD926A547C370593B8F93C0ABB 1DB644906A9B09E0AB3AB632ECC557EAF13F94EBBFBBB7F1E2E481BF191F5D59 EF717838611A69035B05E853CA52AAFC26ECBD624F35F46E4DEC0593B74DEBD7 EFAE7F65F0E058D4FC4F178F7C2E14B1DCEC8B7C14383F4058D93817014B1EAB 5EDC608B1744BCCC27B98F36434D5875558771E5A9548D0F5647D05589C1113F AD72477AB52B198CC745903FA354A5A3364EC61D650FAD753A15D8A4880EE418 D5112F15CCA2B89C87F6443ECB21A45B9C5DD328E0E9889F10212C662622E607 D89DA94D35C74811BBB85E25D7C5AAC687D08FBA3D81D128A770C4AD6B56C6F3 0B538659DEC8F022D324DEF4C5C361FE6050BCD16517D66EDE90450796193673 E211197316D102FB70F0465974214248A9DCD8390EF9592F40592C9E2259B068 EA0798A6D467A2E495D9839F11134F97BA950DFCB0D45E5E46B4F069E90BC543 0A0FDA40784BD9D8E9016FA5F7A8A6E2B2A0A99AAFD1401573AB8776A7D5082B 6C5CC8D16E60DA29F879AC602829E27C65349A528E086B53DA61DEAD5EEF4196 6F97C5D0391B46225E4C1A07A370CE53CB81495A263FD93AF4EFFF747EE800F0 F00878B7768360F08B6529AA66D9AAB65F39DA18C8FC234B3BEDFBD76255C62B 0BDD5187FFF1BBFA23071B73B3E4CD5B6591AA6757D72E5C3E7CE285C0A357BE F1B5B963A72657166D0BD6C001371DE9C322A7E84AB4A769C709E6789EC29A11 3C6BE9FBA32FBFA19797279F39C76CC3426244C7A8D253A8131D42C63C7F39EF AEF91F9EC16A010462A17BE15E621BFEBBE1EDD7CE2FFFA523FA20DC9D3ABF93 5F7DEBAD95B367C4A184E5038F4E95537365466ADFBEBAF58D37BB338D132FBF 5CDCBE2B0EB66E6D5CAE7BAD569A94DC365E5A92A243CA124797512501C07F41 95DBF178E625693E826CE5F593FB97D6825630BBDA3426CAE5D117FECA6FD1DE 3F998F2713D45185FC3331495A0D9CFEF4AC5FCACEF57BB4A7279A4B695F96F1 83A63AD9BF95F9CFB6F85354FBDAA73103D6EE6128C2C68ECCEF7CE781F8EE3D BE1AB1E792D2EF4790848CC0AA1D00281CEB047CC831540004E5CAD335B64172 D3A5CB319D3EC0C3395BD52950D11D566683D0A91CA76E7B1E29703360E9C799 6A01D3C55DC64286D25DF7DF7D7372A2991C791208AF1B1986E714BABA584EF1 D005D28A335AE23ACD3AC51F7F3348512A257A6291066CFBC6ED68BA557FE2A0 84CF0BF912684DE84964AB25FA6F6276C8146ECF100B4C6AD46F3F1462B2367D CAF059CB82BE9FB76C0B129702B27FF5FE3B7FEF0F83F5E0A2CCDE50C5B5CCBB 3DCCEFF5FBB0AD508348A27E6952A79F5D5EFA9BD34B47CB613F18E5C2C612E2 04C469961490DF4D2A70E320EAC2A2283042CEDCF09A1BC6755C041132407E8A EDC0C678D5319EA218EA1595051262A96C2E35209F3521E0B9F500475B0BB0D2 0572481F41A14DDFF36EE6D9773A7B3B009C283639BB9674F36828D9BA2C08B1 0D821AD6D838112A419749D4DCC7DF3441503124A1689415076CA5E69D684E1F 6C4E3E5D04A8A516C80C303C0F0B1A6F8CEC5A5AF488ED66E966BFBD9D8E5294 7A96814681C81121F7198982F0E7570EFF5CBDB1900D803DE4460CBCF042BAF3 4F6E5DBF44E9F3A1F76FAFCC7C3A6E4E01A3F52CBAFA6AD53232F6601D920E27 2517A10AB1378E42BC153E1778E558AA44C7384869006D502A1410A1FF81A4E7 1A0B28F957BE388AFF54BD31FBF7C3566A5E38B262E0C2B125DB8619E232601D D8332FB3441601CEA810C950AC06B61150125824CD2E6DD1DAA526FB1FE4CE5B 6BDDFF72E1DC2BD21449CFD262BA8D03CF9B4D7C0690BA4A2D8594B9F076A4BD ABC49FA5C59FEC6D1D6A4EFC4A6BF167E3382A77733F0BC288A44447C42616DD A40CEA30F878342A946025E47E9F28543FA275191B572336ACAAACBB36CDAA7D 12EB796CDC125331FEEA3F517E0A4F461DF1C5BE0F8F8E67723CEBE46CB1C6CA 31D6228B84B08A9AF054623D803886E3513B16B4D2B69A6453D47935409E0C04 0F020119917203E4011B59E9FB1265AE23EC71B932E4521AE58225C75C814545 A0640A2BDC58EB2A0B9EC9C039B067D4DF20337B26BFDADB7D737BF34A2FDB34 A62B21C3DB02192CFA7C1AF7AB288E5F60BD185304B61BB06AA812BD487DEA17 1984A1A5A0F94BB3ADE727970F7732BFC82D19E9A61DF202693796AD7CB44AC5 7167600C5995C4997D7FA67F7C165919A3B96F49E61819AC15E34EF171AF03B9 12053C710FF6BBB45E091B189EA4AF45A24D00D45368E92392C83D36E4FC8134 7786F94EAFC8FB78E7EAB13F3D192CC4F4409DD150359E3B32F5E97376798E4D CE692F444B5CB4D5B0A156C83E5C47396AA950A7B8A607D6EBF7376FFA9E8926 5BA39DEDEE6B6FCD7FFAC35E1276DEBA3831BFD8637A7363EDF0B32F88A1BAF1 8D6FCE9D3ED9387C00A5F4F5015786F238C4431CC5DA3174CF407657CE28CE14 0AFE15D5FC6F9D7F20F8EC0B1FF5ED24E2F218A8B762D28E0001FB81BE78A9FF E07AFD234B4C4B6C1D086949F7621D7B9BD337BFFA66E35834FBDC0197B7EA57 BEFECDC9A985B9670F6936347EC346D32663E1D668E76BDFEA6F768E7CE8C36D 3B8816C36CE781CA78DD9B9045D6F8E88A0A7AC84D733C5E2ECB14B563D09984 A171419A017CC3F1F875B5B7B137756C064090E9D71FACD57FFC3FFF1AEDFFFA 7C1447A82CE9B3606696C411AA50A286A8EA5EBE69B646D393ABD9D08E82F569 FA44FFFAC07BAA197F38CEE122A23A61B59285F0DE914FC9B6E9FFE903B976BF 79AA454F45251B044853E0914B37CE026035D0906C1836C3285E6222DCE569B6 C757EB9808A30554CA84E5EA1221E50DCB26725C6E1DEE54469D0A35422608C3 06D83F84749278D2DC7FF7074BAB4B64F1B8D6438D49045032BA17E0A021FC20 EE2CD7ADCC204764A3AFBC4EF6FACCC8E8C8AC986FC9C170F7DEFDD933A7BCA9 1A5A303A61333CD5C475ABF66BFC1827B0140A1B5EF577D63766174F93DA312D A6B2400583820B0840C6DF2CDEF9FB5F4ADFDEBBA1D4F755762D233707F27EAF 8F8D70163B87238FFEC2A1E3AF4C364CBAB632CD8F4A3251D0C2133913009742 9C8987F0235DAF17F0534E39EA0FB88E05B418C4FC8672ADB0EB61B9E1FCAFB3 8F71A7D00AFF01565696169B9A21BB48932AB9E5F19E913D1CA5C19E0FED0C25 3CD8FB8A9644EC86C1F962F05E6777A45D5BADD64E84F8511328B5E3FE0944FA 904B629514AE90147233E78B0F359B1FAA3556AD5D0268E0B310A2A33B640914 EC6963433C79F24AA0248931A240B532869918B8BCF58694DC2CFB5B44DD4A01 3194D76C794FE69125273CEF895A6325AECD86936F3D587F75D4CE02F685B9C9 CF359AA7B915BECA08C48F30464DBFD27A32B4008A6023F96518CAC4F8786AE6 E2361E1030E908EE78BA63EC4A8EB1F6915879557B631F50CDD92F8DBA2A5725 C25E25886A44DA2D63D49C3190B2A4543283E5CA340A4D19253D0D39C8A95850 8EEA5600ED0186523DE2C3E9922774F64D2FFCD2E65ACD2B7F7C6A6A517AB823 20E4B1B2CBE48E0E2E05E5D5DE5E56987542EF154567582AAB5663FE4B470EFD 24E14798EE167D1AF2180745A22C32790C3B1E56ABF2815C40CA105C86423A87 20EE768BAF23371D489D21D0783870FFF1B2FDD95382024A848C83B6EB5E81CF A66031E1C9A85B72AE5119BDECB0820FF916F73CDC49D82119F62328812E5206 E2468A238C91805059150BF10D600F7B38988A569F801E81E8733F093026E156 67D5287FC5508D4B84D5D043D56F025B2B426B3E9C970766CFD1208562375800 9BC6468504AA068B41A356789C61CB0ACFB9B7ABE4462ED7B2F26E26AFF7B37B C37CBBD06DA5011743F4F0F174865583931ADB479DDC3E3713D4BE14B77E329C 7B319E6FCEDC6BC032EB0E22CEB1C95AE03C9E87E913A2834F9C081624D18CAB 712DF6830BE8FD7624FC1434C4490D5399B920CF1EBBDA03C7C5F6238213F8CE 80D9841C120ECA40E4190568AC22788E40443D61449072AF0F21AC9465CE76B3 F2BEEEB0297F2A602760BF00669D8ACD99E5E8C3A7826387497302D825C48CD0 509453E4AE0D0AD01230396CA41CE874BBB377AB365D0BC3A877F9FACEFD7B47 5FFAC8B0BFBD76E7EAA9A73E3CBCB1D60FE4FC13C7D880DD7DF58DE9E74ED68E 2F3B25E605407D254781694F4BA2B60969439C44348AAC3E2B75C982BA7F63ED 5E7B67FA858F276C1609450411C7D052A73EF383C05EBAD6BD7DA9F9B1153C5D C79363CA552600B116ADEDEFDF68DFBF7BF2A75E285BC40FEAEBAF5F20237AE0 E533793C829FAD9129AFAC312FC8DFBEBCF3D537661696D2A353D104F1DAED11 5A392E14EB1BF58F1F36511F017D06818A00BBF5ACA4AA8A6D68BE86ED575DB6 7BEB7E637A2A9A8E4C59F46E67053FF9637FEBCBB4FFDB0B31FAFB701D077C6E 9A705F614FB48A3D925EBB23EFEC4DB4968AD26BD3F5057D38DDA2C5826E7D74 5A854321207DD64BAFA19989858515D7FFE34D69B767CF4CD35521ED108925BA 4102622EDC9A08350D10960047152E1176C3B4B7C50F36E90C30C203588583B5 669C8181D720AC991B88285DB849CE5F4A1004BE043782A721EA0A52A3DDF4C1 D5F3CBF0ECE78E1A14D194141348E4785489E23298C850DE41911CA8937CE37B A3DBEBB1D67A328C4E2DC1761F5CBDD7AC3583678E03BE5604E5467984136786 0E0D1AAD240C0BECC0AF0086061E19F5D6AF7B7C229E3D67EB47944778771B52 6C5AAF4569B2F9ABDF7EF357BFBEADF805935ECD8A6B7DB6DE2D21BD26B61C86 8444DEA76DED139E78EEE9E5C8F64F2A0F3EDED0E705F370489023D9E2CA35F0 710F87DF58A51E6A5C290A9B5C3C5329646189033B53AA22A6C6214894D991AC 2CEC5091BE257D25874AEF7AB01E0CC001893F8DC64A70EB4B58BC5ADFEA0FB6 84481B8D3B9DBD9142B35A850397E4B15089272B7CEC80851B78819039414F4E CF9C9A9E3C9484F39C4C5BD52C64539948BB83119436A4393A46025291405704 36B37B0104941C7735968173547D05503960368BC35D3FD829E5A62A6EE972AD 3017EE6EED317889AC595153F2E0F4EC2B2BF37F11C80F446458CE354427B134 11819BC6528176513E10578F13A0419101AE016C526A55A20184C5D913583FCE 714EA1421785E8EDEF17AF8C1D4F86ECB72C7E2090E9F1B7ABEE87313660AE79 92EE9FCBC257990F508101C23DA2338AE4DA50210D8E92794877E0028047F7E9 5E11257ED1AAA7D12D91FD497AE5C8C4C473A3E6F6B0F8AEEDA6692E3279DFB0 4BCC6C18DB27A443C8D0C3C3B315DFFED2B1039F30F4704EEA2C0220160618BA 4D504725705175485A1CB1E13EC210D45EC0C3648A05182C458C8D48F7074281 D1D8FD483D3E207C1F14607DCF9DF6B0CAC9D49412B5D9CD788A262702D5DB0C 1ED857077A880A14DA833289F4B17403CCB10642EE970C4572E1650ABB5B9810 A89258C93B024C65B12FC3004F0EB125DAB5C954877B6391CCCA37072FCA33CC 79E051A75E8697E83E1C6A29411E052402375D109C5214598AF415B13FB655C3 73D03CEC29B2874ED464BD2CEE763B9B83C1F7DAAA9B8FFAAE1010C501C322BB 2EE07D083935E57F6EE5D847CA68616BB835FD70162D4861C9700FDB00316B21 5685558493830C4D09153C26FBC81CFBF134588935D87D496EB8580729DD8340 4F08ED067E81AE5B48C91E3C40B82FF03724704671AC351A77DC2850221AA71E 7DC0764641A627818F3DB9466F18B5568C0CF792422F25E1F46454D4B49DAFC5 C7561AA74EB2A387C8C4A475A73D2543857D64A0D6758D924C6DDFDE1EACCD1C 9A03C8D4F9D6DBA369B63471FCC6951FA453FAE9436786AF5FB2C7A7FCE3F341 9BDFFF93EF4E7EF49477743EC0DEEF39CB4A6C72F2F0F48897DB446EA3A82AF6 DAC3EE80AB2BA9A889F58DEB776E4E9DFB44CB3FC048A005B66F924203A885B0 16DCBCD7BBF15EEDA503D8D6CF4BD89FCEAA0918B6B0B77A6B5FF9FEC14F3D5D 7CA8C58D672F767A37B6665E7E6A382973C881B6E5D9392DE2606B37FDBDD7F4 48F2E78EB2BA26A3C1302D5A73077B976E363F71C86B1518E8D0EDD25A5DE832 859B8D8D7CCAD973283BBA5CEE65EB8B479721B8C9F6B0BB3D9879F65327FFD2 FF43075F9C0F3D58BB814D223A3B8DE22EC24F6D590B98B9B596DFD8AAD51694 F677E9DA5CB69C0F9ABB6273F69373FE2CC3E0EAB54A6F02C85A5DA8EC9D8DF6 1F6CC54BB6756A824C6ACD528BC3B710387076033125EE6414E686685C026ED3 75364846ED87E2F0049D5AE2F1222422EC4A444DBC907A35CB5AC8084997D314 955CCC3811960C0806A0C4C0F75AD9C3ED9D9B57564E1DB353872D2D34901FEB C46E70FB17633759B753004B41C2D1EF5D6ABFFDDE7454DBD3FDE4D9239299D6 6EB971FED2EC4B4FD393F30A4B4A805D0A9F4E186F07202F532DEC3EC29342CE 68ECE9BE2D367636FB8D95574CFD345C6B4D768CE9741B2D9EB71A6F76BFF6F7 7FEDD2C3DE759BDF48D36BBDE07E1FC79B66C8708F98628EBD387BE0BF5E38F3 B1F5AE9FD0221C8E6C91143480CC21E448286E9D02199EB9504C84E836AA5DA1 C9CD57E1311ECA71B893798AAC9D39A40F7B0AD851A66DE915A51928D223B4AD 24E4C2AD00EB0328E784B52E6C1CE09C0D4276B91C7CA7DFB9AD5CDF9B713D96 807395464179E34CDD505ACE0A3CC0C11CD010F1D4CCC2A717B26792C9E74CB4 DACE9222055493066A0844000082F5B14E8E7DAC8CE52312738933A95604518A 074F840AAF675308A249469812ED463C931B80BA70013529A3AC50C47FA06A37 6A077E6DB4FD9BBB6F2FCE07BFD25AFCC2283A09DBCE8EB6A603157A13C3ACA6 8A3C4454E1D1A0AE63CA82B44EF31A7628C6391E0A380E084FCC35228EE7C35C 3F860BA200C2722C07BA96C2FDE67AE63A293E980821AF79D51076A5A7365623 33985C51E3D9F5A4084FD0FE5015A95619B027897A7D3157310E31031DE5E87C EB97C0A3294BF3ADD95A47F8AB1D74117F3D196E75F63E519BDFE6E61B934921 A797BA62140E7A3E4FA9582FB6A6944F87EC56B697CC9BE7853E727FF864722C 209344A6B5FA40C5C391A719074C29DCAC014A9E784E470D5DD3A92BDF3A953D 2A7C32A656D8ACE9D2FDB845B6129671841045535DFFACD331C20A39A4540F5B 2D0A601F80F215866E207F5E102919EA02E04CCA81BFC0C20A825C08E9438ECB 0D4EE6A1DC9207149D296CA1C3031195E670CF78E023D8C36E382455701FBD46 D30B024CE1AE05773CC2E26459ECF871E183D13CCFE126020551415406000F81 77C34E67E8D1AE14A24216E79EC855CE07D238175AF8CD0512C7A870A528A625 532361F2C0E6C2FB23FDCCF5F6DAF7B6EEDCCD7A8D7AFD4473FEA8DF48B4CECB 5E1299495DACE672D58A5885335E3465610BD9BE678690B5130199CA33A58F7B 06E2B4820B51C2B74E75A86ABCB2951C8193C2783F2D02300DB86751EDC5C72C 6A4ACF14020F1D210702726228DB18C03F84E3C932555EA478A27D2A51EA268B 78C6D1590088388469D8A5A5ED59D68B499D78136BA36CC32B467ECEE9E8602C 96E30070CA60AE159C3B537FF6A9E8E029D8DE991E2140C1DE0758D9B0030ABD 7DBB6F76EB2B133CD7C3EF5D3467E71ABDA98B6FBFD67879E94016E7DFBE5D3B 776478B8515BA76B5FFEDEF4A79F920727EB1009F534C021C5592E6288FE71BA 4DF24D4CF23CC8199057490A4C84ECFEFD8B372FCFBEF8E9C970457811C023EC D1286D1EB082DAC683EDE1F50BC1F373705F0A3F075C11F77D1B0459A0E30D92 FDC1BBEA708DFEE46153AAFAC378F0BDCBB5E78F8F1601E916B488AC5D902C69 C1BDFEEA3747D7EF864F1FD3335C95A3CDCDCD434B2736CE5F9B79E5B098C145 88CAF1D81AA5D4A8076B0D1DFC009C43341BE4DBDF95FCA06ACEC5C0FC3AE7AF C70B33C133CF1F7EF15FD0FC4B27852A588DAB8529D5ACFB58542A744232ABC2 1D99BD75A71E8861538BF555DB1CC13B0D1FA6D31F39C70E8A614DB34CC45E98 623522ECFDC19DFA9FF5DB2F6E2F3EBB68314A333C7B60D6756F535BB9435977 FECEF0ACD546F1D0446A63AF29027660951C3859A05EDEC87AB9CF1ACCCE5A0D 603A25B4C35580D9D42B35054AEE5B8DB2A8413221B220BB7A3DF35572FC7080 AE618FA686AA63358C845523798579F1BBDB37EF7EF7BD05AF56DB7E60E7A439 D5C893A87BAD5BDCEE1E3EF7AC5AAD675E1112C1D49E0C13D84DBE146189BDA8 5664CA1F315D7805D5DB59BF57348F1DC9A2BF48E43001B6C9681AE061C485FF FB7B7FFA0FBEDACEC3B7EBE48D8D01E984F356ECD5462C357F7BF1C05F3F7264 42754741DA8BC8106DA7A24885214A4D41B2952858C334C04C84C0AE160CB951 B9AD25AA520BF262EC51F00C0720E9E32D41BA27818E5036B4BCAB544F031D34 D85AA7750FBB3833695329B41438FF1C0C75AC681AB18B227DBDB3BB97A32E07 A4BE11C43934FFF3EA0A7284E8309AC5CAE3455D92CFFBFC17A7E65E6A4C17AA 8751CBC376442416D53434D9C7C28C54531E25ED3B214EE06BDCFD49ABD1172C 2DA17C1D0E48A266198A8103736375E54703D637DEA526FF965FBCB776FB796F E20B8D03F3A3CCAB99B286E77C185FB0D0685D487607C93E1AA4322E5C76638F 2A5174FF413F7606F8810C47F75FC2ECA38ED1F775E2EC78840E02ADAA5A94C7 EAA3159B72A29BD4C9FB545C4AB8CC018442E3E0A6040C051C0DDD539054614E 76229DD84381F32E820076A624F04C2AF33D9F47D434554A7CA08DBAF4A89F72 92181E0F491E2BC681EB88776AF13FEFDCFCC8C2C24FED7A89F5EE4C6A78CE0B 08A5438DA90D00B7E0A1CF8027B271FBE5B895D74565CE797533AA34CFC635DE 1FB622A2C67BECEFE39F7F5F610FA89E2C8BB24C0AA779341E4B775DA65A436E 739EA7E80688057C836A67927B35E92703AF570FDE9A343B9DF673A6364FF990 E661006B4876204D8920491A344161185FE129AB414D6EE2743271B61D9EF588 E1D861A479954FDE5773A824BA1F8920513461255ABAE9204D9CBB36766F6A4D DDC40B5CED5869DCDA465BE713B59B82BEB1B9F98DADDD35C83E8BB3672617FF 829E7CEE61D1DAEBF745B6194955148D46924401B6B5406A7227AA8EF95B74B2 1B8FA8E0E0D00FD16B5DDD3CEB8E3FD9FE8DC40FF443DAB6FFEAC9F458FAE0D1 2B1F2799E47D250B029B901B9F56AD85826544F64DB631ECE4428B7ADCACC73E 5AA59328F0A75F3CC13EF3C2D681598F24ADA1878F59A445BED1EBDE896ABAD6 0AE9835D7AEDEEE0F9B3F5CEDEF6DEFDF8A9278B9DDEE0D6B5A5B347456B7AF0 EEC6F6F5070B9F7861549B9922CBA5BFCB6C84871C1640DE2EA35D060149A391 2B1EFADBC2004BE794DF2F6EDFBE7AE0B967FCD6A2D14DAB03ECE102560A711C 38D1CECED6E5EFCC9E9962416404D0448D7A9B0638A50D4BDB7EEDDD9DBDFCE4 E77EA210992F4DFBCD6B74BE3E7172954A413C085D6284AEACBED8E95DFEDDAF 1C9E98F163E1B71A77AEDF3874E464EFCA95F8A5D3E24844CA1D581ED2FAB4C8 A81C4180F46C2152580C47B6AF0D47C5ABABA7CEB2DE427A61D7869BC9B3BE8E 0F9DF8E8D7E8E8778EC2D3F61ABE9D9B34F53AAA6E1A59F8D2E39CAC8FFA3FB8 D5AA452564E1B5992CE8795C0EEF0F675F7E819D8A3A415153B1EF45B9C83D29 76BF74ADF5FD72F0627BE6A939EAA670B1ABC2694193F1B9B10379CC75B5DB9C F8C0891BF9FA6E4CBCE0E011B2700C309C31A905C0416BCC4EA3149C9751DAC6 448863314AD300E82A04DB91197A61332CC3FCFA8D3224C9B1C39E0C1F65C1FD C38F7133F8FB7FC573F52CFDF6C5F0CEBA6FD25DBE573FBB620211C9B0776DBD 3066F6DCE9744A141199E862BCD088B29D6B0D29013252AE0C95D8A36FE8C6BD F54614D7A73F85BA8B5EA05464E224F082EEB71FFEDEDFF9B56BD777CE87F69B BD6E5A025E2E4F12F30BA797BFB0746465D8E74537F373E037805D7D856A0B38 130834036B21B0ADD02E055BD960FB19CD7164CD54669FAE1B06590A22767758 CA25E1E82C8B23C225F306C6EE95BA0DF98FD89101D4A7254AF8BB1A1E2C533C 9BC6A115AE83A1F1376AE2DDA27DADB38B4A3392433428B5C9290E87C2DB3573 F57C527B6976E689245816DE92E735819CEA913BECA904BFA9ADC4BA1E6B0FA8 36AFB6A36AE73BA7506F7F4619D119766120B9C28450A2283615A5C907E580B1 5D5FDCCBF3ED349FAD4DAC26F529A2135B3642B87809ABD8F5623194906238EB 8E06C57886CA9C381616269D141D7B14320CF9D77E55E4AFFAD309508F41FC38 B6D26A9A9C98AAFF6F9C01DDBCDBFE68DD78E8D0FDE963B10F3D8C4DA1704CBA C43319809F2E00625FA4A3915668348443DE0D315F7825A0F63CAD8F00DD0543 9F8711E7B9A42889424A090F0AADA821AF6ED4C36FA6BD52786783E4644E430A 6C1EB0D120F221A80715F7459758DF674238AC517DC0F1D1EEFB62A2E471BEFB A3EE8D653F9408DFCF87EE1D5C4FA9F253B94F7EF0973077EFF0F458B9495783 9A0F0071986B507483BB3C26FE2E27E7FD7433EDBD24A60FA7A41FA951932679 4198D0400803DFAFC55470D46FC60284869FF4B0A7D4798DE2611AE398A7B103 93DA71BD94EEBB478CAF7B3CF208775AB926B26AD605791671B32EA8C8E19E35 BC4758504F4443CA77B9D8D0E6DEE6DEDE76B7371C0D6891CC4DACCC4DADB070 46D14617C819E2CD381211646BAAA445955A4C3E0CAD1E9C1B89B72F53BFBF58 DC02AAB4689D5F09AB5A8670949952F26FFA1A37EC568B72DCD6FB4817F77DAC 06EB0867558CB344416D03E0E0283BD22DD35E3E843B19D76A22C0993123ECCC 91A5F94F9D0DCF3D6992B02C64E0B174E36E7BE3FAF2992545D2CDAB371A23D3 387B66EFDDB7A37A141F3956AC6FE4B25F3FB9A001905FDE2D76468D674FE5B5 095F366D2099091132E318E51E231069806A56D39A80F732BC1B9CB1F5F2D68D 4B4B2F7C5834E6B5AE4382E3C87B7196C657C66EEF6D5CF8E6DC99695E4F34D0 397F9C0821E4F9C01ADFBDB7717767E5531F29A222A6DEE09DDB6D5E2E3E754C D0D88A44F9313C0301F8AE9776DE7ECFDBEA41649B589EBF7FE7DEF2EAF1F6DA ADDAD983E26883E41D5C8DF0DCCB9CCA02A05069523FA3BC3DB5F6DDBBB31F2E C2D6A1D16DB57B637DF9448DCD6B931C3AF6B13FA1BDDF3A544B023611909909 1B2506CD104C4AB2300CD9AE1EBD732B025ADF20F47EB243761B7194DDE8B75E 7896BD38D909D346019C3F50C2B02ED9F8ADF3D3B7BCE1CBBD89E3ADFDD0E29C F3E8383B5594C18C917B6901D5FA13E9FA1ECBCAFAE1E364E1B8F6EBD6E60625 21236627AC4D248344D87589B0C0491B8A064E94C98C145ED0F053DA7FEF126D C5F59327B02F7E7FBB8FB74A2539B42F745445B08ECF662FDFC9FFFCCFC3D5E9 ADBD757FBAD15A99914489D40C6FEF904652FFF8998DDA70B623A8544C78961B 278863387A894BC0A645C4E06946A996D7EE25C75FB15393A31240EEA41FB470 B46A43BFF6F77FFDCB7FF09D9BF5D6ABBB1BA9291B0DF19F2D4D7CFED0914540 CF7B3DDFE74358B494F806D615D63C01C1960E6C7A122BC92E2952D7CF46B993 32818D8778DFC3D29F33CEC1F35FB8E51E908FD22167EB0DB5ED4AB5AB54DBDA 3E23230B8F51C75A0FB987827F0A824B5940720CFC9485D7F606F70CE9C67C2F EF15A52A78032B4C10C3745E17EAE464FD13B5E66792DA591184BACC74A97D8E 6E1E2ADF37C4A0D529886594EC0B64D1477FA29BBBAD5A7C5DE4A9DA07D5BE6C 17754C110FB345611A702FA4BE1FB375DFA6BDF484989CCC0C244A39C1686263 B83B79E93457DDD91C8004D8030172416C87C70D482B8E431F4F841F04D13F14 E1F5F8300A7395EB06B2EFFB1B3F96002C3363F1CDFDC33352A9E8D831DBA85E ED55D10F5616E6426C68425CE23A74DF579EB334C0914AB8FA0038BF163A8D2C 2B68AD8F8EB279E20538378E7DDAA1F180D30F895CCA05C09A575BF2EDDEF65F 6E1E7A028B33D6F3794DEADC1F167516A38C03D0620FED0A501A10BB72EC232D 15BA3F05F85846DBBF238F44741EEF9DF57E440EAC7A58C8FBE198A7522925A5 B4763C03E8B9DBE8467C510D10AD6E14644C166A92C147166C428AA0A0375AFC 55B95D2BC95F10F30DAD0676D010CC44BE72D399340C543D28432E807E29CBA5 332C7289D611553781BF4F921E19287DC046C9558058550572CDD1C4B9AFB899 5733B6AD36E36756581B9434B23E64EABCC4F313589BF7CAF42D3EBC1415DD7C 74A808CE86B32B704B25EECB38E08D24F2B18958BB4217AD569E6B5BA3D80240 1E95A248A5CF80EEAF0E26BAD91327E1F723EEF08FFA72F8723F5EFEE8448800 1DD09657B5EA23C8AC9A7C7910A1539D965B837EBBCC19F0C17A02D7329D0ECC 94F53E7AE4E8E77F22593E44CAF4C6D5EFD66BE5FCEA9419A5B7DEBC726062D1 3F32BDF9DEBB532B87231BB6AF5D699E5E5507EA382D7A754BC0E63F7AD8268D 3CA3611411ED63FD0073DE1EA15DF476C04203C1561CF48B9578511BFAF6B50B 4BE7CE412294BAE6113CA8B2CE1C180085DDDC5E7FE7754884FE444D7389B317 384F19E07CB936F2E168E79DDB532F9CE55358E61F5DBA7F6FFBC191E79F860F A3839A0A1382D22DA89F54DE5BEFBC715E285D5B9C69EFB6E7E796B606DBB553 13F1D13993E71E42A20C9B8107230AC04A58D3B5E9F7F7E251E87F2AB4DBF18D F3775B53D1ECC11AE4721DAD1EFAE41FD2EE6F1CAA4D27AC1590891609125962 9B79264754EA863F2B2FDC518361D0F0D88EFFD0EC4E474D7D350D9E38C43EB3 DA6F64511F089A6FA3C0DE2F777EFB7C6357941F1DD557922AE08DC9181E0F9A B1969543D76E16AD541E67C174BEDD2FBB838983C7C9D2091B4D6244C1A9C180 DA3A907BC50A42AA44285D220CDC48589E33CBE3261FC8DD77DE09E6A6EB274E C2A3791C72D9AAE4432B8856494921986DC78DF9CD8DF5AF7CA9D50802C5FB9B 3B134F1FEA4F911AE76C4B76DFBB250F4EB55E7E22C75E1E3CAB7491136511B0 EA8536B92A05D6C41ADEC58DFCCF2F77CEBCB8F0E3AF74057C9238F1629BA6C0 DADEFDCD57FFD1FFFAA5777BE2C2567BB96E7FFEDC137F65752EEC0C9ADA8F80 E18E4AEE070C154D25F6CD2158053CA798D6BEC68177A7C90FAC0092A057A9E6 BB56336C12D095340F4AE92A8731E0D250933253B65B943D657B440F09C918A4 192BB5AA4B823ABECC5939199696BA0C448FD35B727435CFD6868551BC4E1A83 6943864340E32FD69A3FDD9AF9B1A8B604049F650C4557F11662BFA6EFFB52D2 B14A6725D449EDA35D5A49D054FF2155E506870FD9564DE55818406B1A2C9FA2 D0237CC8DCF2B253F89D02BED3164014BC8879B5413E6148D4F055D3EB93113C 1341B9ADE08CF0E02F4E61801B579732FB24AD4AC0EC83B5A6477FFB009A7E3C 4BEECFD0EFE3A4C7638D75622C767FE558B65F8F2363C7A2AADE88E27DCC4D79 6273364470659D72176C6808BE6E5401B90164F64CD24051D875322429C4E4B6 F4FB9AD47D3A018F502AECE10F682879E6D14E319C2DA21D3FFE75B2C96BFECF A5B5233DB53BE5A9484C65A5098A51C3C34AA88732BF0C274D995344ADFCACC9 7EC6265567E8E361FA8753DD231E427E749836A6722B1CCF5906107021CD0169 854D0A9F116996158C7B6E189ED9F1A16A66785C5A5264A3C8149CD486AC4EEB 5723FB876A6352843F534C4EEDA5C396EA2724819DE0BA608A80153EA3BE8845 80A9032D925115C12FB1654472563DAF4774F0D107608F25C2312573749462F2 33E39DAF8CAD52A37B6A12FD2581F0D344515E9042EA3EB5DBC60CB0FFDA1F64 B237CA0155D49B24A45E6249AC80D490A920AA71ECF7A91C1C1D32C37F43B27F 84BFF7452FB4DD17311F2742421EADA07F532264E347F6FF9908210B2A2081C4 D9D31886A22D387B8D9ACF2A106D2DD77AED8DB48710B2114CC315AA7CC0D4D4 93C7CF7DEE33F1C9A90B0FBF79F8C3D391CAC89D76EF6E7FF2C96773AFBBBBB7 39BF74886FF44777EE26E79E2C12EA9B60F4EE1D9E34C323474D9094A50E8310 95ECD02B0B1321D00AEC19C39E508CE7E87000710C22D696BD7BE5E281E79FE7 AD45656A28988A73A3106C480020787367FDAD3F9B3933154CD615852C5072EC AF0E1CBC0638AFD75FBF3875E244EDC8043C80FCC1E0E195CB8BCF9D096BAD5C C015D5454138453CC9D3ACFFED77E96E2F8AA3C2EA204876CD303C1AB79E582D 0B481839D1993BB38650D8B7C6EBDC198DDE7AB07AE8A83DA6079755BBD75F78 A6415437304D151F5AF9E4EFD0DEBF38545F6AE996CFEA75261209CF9AEBB41C 8E36760FCC9D28AEAD0F1F3C98684624E3DBBAD76475715BCBE906FF9993F901 2BBA1982F3A8692FF6F6FEF0520081F6133A9C7133582EDDD171BDC90DDA5489 905443D9A5018C2C266C5FF5B7F61A070E8995274932EDD49E95C3FF31C1D801 98ADEFCE08952B8D0AD40CB6D8B44E453D4C55F7F285687EDE5F3DEC0C3AC907 52E1BE74887DFF8B283E199ACED63BDF1E9DBF7064F6607E773D9DF0C32717B3 504FC0AFBDDBDEBEB33E73E2A8FCF8240B831C755A750D1E519123558DBDBEB1 89AEF3CD60EBFF7C8DBCB5BDB6B4F2C2DFFE65FDA1A3854E035B0935A9F3DFFA C1DFF92F7EF5C22DD5B2C17F72EEF45F5D6AF2CE26DC877C38427205E1BC24F5 A04152891258566590E0AD1BCB72194357AE82D88F4F055060C39C34067123E4 54E2C9AF4D0A541B058C905AD697AA0F9B595B487E196112C7288874FEF49029 15D6EC2440AED4F33BF002A9B860B2EE5F96E9F736DB52C6C43443B63EEBD14F 2DCFFFCCD4C2330335374C896F7BA11A851EF77D0C700A6B923594E0C05852D9 BA9A2A2392C747A071C70AD7248E7D12CEEEC73D70ECA5AF2AD3F8C3840380ED 0F4C3E505EAE8574F11B2982CD8AFEC26C2B462250629F57C49D4B0EDA31FA41 E034FE5106FB112B75C77BD6D9BFB994F8D85CC4A362A0611F08223F94265DC1 C2D932EC9F318E4B18D8496BF773A4258F52AED95F4EE3D8472A31335B8D2628 C70E5D5F27E445277480B158790543B9A986E2B269466146AE93F01DAF5C8AC4 33E85B5C74EBD8B684A3B95CA4FDAEA4B5F3547CBDF7F0DCD1D5B35BBD03B9CD 5AA18CBC40E63E372A6468D405904008946CF25C354D70BC274E6895D0F1B1A6 BB2548983F70137E4446FC208670C5B7AA9452A91AB917D98078956823D64721 1F1625E4425175BFE0488976B78E16B0C6A5122ACFB86C87264CE9EAA09647F5 AF3646AFEDDCFA6CB2FC093231CA3AED200BE300329F7598CE54403914A5603A F45143119874E97614F71E4DF5D00F5EF7A3448817853C953AA8E592A693DA76 C7D5EE9CD6B87448501B30F3B0BB9564995768112739F74603C9DAA63E148445 3B91BF1BF3B6D94E2887359F48136BD564ACE90369B5D8568E580E5335AE70C3 C624DCCD69126F7FC138008E2B73CCACFFCD75515A55D3FF7F30428B52316A5F 05084FE57C02EB0278224E1817810054BBD6D959DBD9D90EA94D926992CC97C9 DEA0D73A39BBFAA1F9B9E71B339F5A21C56EF7DD2BF1DC9277F45071F9FCC324 585A5C3637EE85F02EC7568CE05EC9BAEFDEF06796C59193254402A58417616B 2BB6538D08D905E08D636C5438297B00CD39730E79F4A159BF7D75EED9B3ACB9 4858D3E040B641E56F8F858693ADBDCD77FF7CEA74534C25DA42162818FC321D A2C88FA7794E1FBE7AB13939577F6EB50824DB955B6FBD3773F689606626E5A1 07EB03A017E310D63863A30BD7F4F95BF5A405EFDAEE778D6FF9A178F2CC718D 3DF5A9674B1C16835C9B77F928B8F9C683D9A8D638D4CC55B6F57677E1E4829A EBE8B45DD773A6F6C4CA27FF05EDFCDA72FDC8AC6AF9A25667B4860A5E3EACEA BC7767637EF14471777BEFEAD59946DD637C4F0D82A1686C253B54463FF7043D 11DBD108CDE0798B7C7373F7F5DB9EE0B557286FEE8B75B16A85D3B1388A5B2A 660CE1D1ACD7024656A2B3B193B416C243A749631E1EAB46DD42586301612E11 5AD420738910B61A77A2623247E1F9381C8D7AD72E379656C8FC0A9A6ED0F70F 45AA0DADA91BD1D91717C66F8EFCB469FDF64EE78B7F34E77BC0D6FBC0476767 D4B1A99E9F4D15CCBBD1DBBEBA9E9C9BA83D73329D0C0BAA6A84F022334C8E3C 1D89067FE86DFDCE7BED57D766D2E67A9E4E7FEE95A5BFF5B3859F528DC2BACC E67B7BDB7FF7BFF9D5DFF98DAB7FF3D35FF8A5A3F3F39B37BC2225AA3054E6B6 305A05D697DD22C26367AE3929995698C5726C59D51141211B37DA846B0B67D7 90045676A5B0CF2C3656FB524BC68684B68DEA48353024438971E499CA9D58E1 A6A704EF92461F3908CB236E86DCE680CCFC60BB94E747FD1B23B477F359EDE7 D8F0234B332F2413B325C4596C5E738A1E109A31B64AC49A16C7A40D7647386D 4807549C60B5AECAA16CFF448A521F4B17D4CD83992A0BBA067EEC5C725AC442 4A938ED2AC0B17C6422FE4F01151CFD5C8A00CA700745A321A46802A84287D91 41D01110F07D1F2D4B21B8A116C8FEB0037B14B82BFBF8C747011E653BFA4174 F428F4D371B674BA7D9548245EA9A30E78BA50927D0C45ECFBA57D27B353794F 3C2ABC8E67D45D472675DEB70CA921160C0DE0174012BD304BB2309249266444 73607E3782E80D355AA4F4E5129668D9ADB1A07036A5A5F287A31BF5D6EFB5FB 32559F3DBCDCEC6D260CB8630D826FEE9711CE6BD22244DF2524631E1DD75E2A 753136A66F0E7D32F34375E1315FA4F6B18230211FDC35FFDA6C69991ED343C7 808D2E4AEDEC30D9BEB458756758E967A694A837A428722F1EE45EDD26ED50BC 963FBCCDD20F4D2E9EEBFA44F6F2C46A1FFB4811F36A78E23C67368D2011E239 30CAA6BB793BCDC646128F1745DF4F8476FC0C9CD47485B7ABE310FCF495126F 650A51A570962A2FF0D2328594E6FFBF8CBD79B465E75527F64D67BCE7DEFBEE 1BEBBD9A47956A90549A6DC9B2658C3118D38CA13B045869422774D2BD92954E AF26F92BABE974BAC9CA5A1D92954E8006DC0492B669C0C6605B0D18DBD8962D A1C12595AA5473BD57AFDE78C7337E53F6FECEB9AF4A865E8D58585592AAEADE 73BE6FEFFDDBFBB77FBFD0D785F4146EB61783AAC80047F8395A180929CA5A8C 3BC01578147FF13C06A910B57F05EEF362990941A8624DF3182F0142D1BDE769 9B4448F6C607FFE1BFFEBD89704AF29A92B95C83147F7FB71F0A9989A2C42E75 CE6C10227D9129B993A55F5EDDDEF4C572E740B42D935694F111D7FD734F1C5C 786A79EEB18383E19DC5674E0E6603F6AD57F9A9933C8937DE7EF3F0CA1C9B9D 3590753627BB97EEF44E5E28F71F2D2D8BCA2CC09606D624507E1BB26BEC041B 66F02CB0862FAD2990CAC604BD936F6DACCD9E7BC4B6F651DED10A754190D227 4404A87063FBDEB7BF3C7BA6CDE7B14182EC3A5C3146D9F389A76312ECFEE9E5 96F6A3174E1761C936F29DAF7F7BFED1D3F4E87E2D5A9E749A67E8DB8E9E2966 7377E70B5F9FCD985D9ABBB7B316C18B3F3EDB7BF234F1903E8F0B34949772DB 93A5BCAAFAEFE4CB170EDAB9BCFFC6EE64233FF0E8FEB2B3C94926C66D925C38 FAC14FD2FEAF1E484E2F973D2F8CDBDCC6A84483934B95DDD9EACC1E921BC3FE B7DFEA793E6D0769392603DE1974EF6693E4FB4EC64F2DE67212426C333DFBF9 9B5BAFAEB2B6E87E80B396A91783E8343E3A1841EEA334E274B9F0044396F187 9B432E5AED138F91EE7EC34383B431EDCC67E17640E49D706C4C1B5707213901 92A284FF8C45C1B8DFBFF4DACCE187E8F2715B96647A741E2886EF53AFEA3609 CF48DAF1C3BCD22F7D65F3AD6FEE3F7D205DED076322CE1FDA3DC0B9477B233F 7D774B5F7B873F72C47BF2985E6E39BD095C4CB1F7C6936BC3F19BBBF7BEB116 0C235FC5A32ABBB7D2F9E0FFF89F278F2D1BA77BCFF40EF126AFBDBEF1DFFD97 BF116E064F2F2F86D55040EC57A622957453FB009E74D0F659D4F28385D89BF5 754B8D3D358234DCCB84270DA97083BF14041E6E86FB52E8551B4A1E29A8855C BB962AC5F858AB5DC082C60010447F79CADD7CCA482CCEF1FE1486A68256F02E F2D22F4BE3B39D905F36FAB5D178B3AA124D3F10773EB8B0FF7BA37496F80088 8D55694491354BE90C840BD7452A2055075CE17EBFAD853F9A1E186B5C326AF4 80FFCB58E3E453FF3F7A8029A72CC56B5F27463C25C9789CA6691E56B82B826C 172A2ADCACA17E9B390B9312C5C48528153110EB5BB1C6350EDC0E68EC56D97D E87F1FB191FB0231DF391EB3EF4906ACDE1D700A397508AD75A5B5769E65DAFD C0221F804C23EC1EF5AF0E45666AE15BFB353649B0260E21D7C1F53D348AD451 E77701BF7CE2ABA8E25189969C107721226CF1E05A5ED2B43C13855DAF8083C7 D17E26F027653029BFB56FEED7D7D61FE3733FD4696BB3A102326F5A01256904 F58F816050C6CCF7FD9AA63F155163F520804EFFAA23E474A76D6A447CBF954D F6D2E15F4E84DF91209B9F4EBBD075E3DB893C685556D6113585B3B982A707D5 EB98E8925B519904B9146C42CD4CE527B9D89AF17E35BF9672F293D1E9A3E924 C392879196085083D07DE040E410E470D6803D700B9017F359B3DB6AA68DDFE6 45DB8601DCAC85ECBD6232CD2575AFD62542373D74A20090718BD2896E9B4C57 A8C6073046B252D19D428F4B745A0CA95F3885D369E183DAB20437E9791CF93E D65C15D41D0167587EBBA161BD8FE2CA9F3D01F3FBE1C8D8BF5667F481D6E87B 073D4DDBA1F9870C570FB9AA154D715E69DC1442BBCADF8D52D069004596AE67 FED736D62E1779B7B7D82176C19240159CE9D4E6BD8333C9E1E4D4074FDB19DB 6999DEF9C7F349BF3FB8B6707CB66823B799DCDE2E5747730F3F5BCD1CC835C4 9F3420317E060EB5CFC0E2B26B8A7264008D21AAB112F98F284115903BC39DDD ED99871F35D13CA022381D3EBA1FC88A89D804747D7BE3D257E61E8EED6CC2B1 C8518E111E5AAB4681F179A0FEFC36BF3B8A3F7C3E9DB3FE50E75F79CBDFBF48 2E3CC4BDC4CB3D17024988701BA2A0DCFCCC97C96BD7E7CF3EB45D0EE3529313 4BADF79D247E5A56F802352BA1E6E1BBD5F657EE24F14A7C6EA16F37477F72AF BB1877F6B7489211962AF84FC2274F3CFB493AFCE5839DF307271D16C609DA22 7A9E86734174BEB61D415E9462FCCEE5565A98C58EAA72F8FA71DEBB3B1C7A8F 2D2E7DE4CCC4CF505723EFE8CF5CDBBD74D7DF17B69F868F59C3765B87C6E6BE D5C00CB9EE75D8C2F1352E0B1A2F9DC874502C9C7A8C2E1EB3ACAB1171549CB9 B903EEABE6980891848E6AD48CC06723924686C5C164AB7FE92F668E9CA14B27 48953F58EABA53C36AA3CEFA1FB8AB60D19F99F9B8CF7A7775ED0B7F34475418 4583BB3B9CF9C94387D295B6A4B64B42F6E6CDE1F61DB9D89A3D77942DCE8F6F EDEC5EDC48DF1DA7774A39E290192C6047C9367975450E573E7AE187FFC14F86 0B3DC4AAE9BB22B84782F93FFB833BFFDF2F7E6EB436D69D76EA1A6508A3B4CA F36230816F2C791CABBCEC7ADE015FEC27FA40C73FD88AF631EF40D89D95342E 95AF350A5B7AB44224A7182E8E79683C83A6F54C12B2359E8C2BF88D7C001595 6BCB610317E78DA4B4F06B8D27830DAF1CE93CD6144AAD2D42DE30D9B726FD54 91932DEFE3734B3F1ACF9F18C8A49DC1F1D21CA11F026E01EF44C11980F48B99 8A411D0615B3F04C59BB11D829230E4295E77BA4F13168FE729319276F883F34 8EEAC074653D1AAACA8E47793EC90163C7164B3A85D52DE391EFB521C6604E34 3263460B16303F227E0855034E4BEB1850738F9DD36CDD859B8A65E36BD67B5C 996658594747E72C4F1B6D4D42DC6E6F1D26B5A9A323CEBD240A32DB7AA7D085 CEB096776DF27EFD67DD9F36D366F5BBE18EDADABCC8456C5AD77A8EE584E7DF D6DEB6F0BE14EEDA5B51787CE0C3E1E7E3D4BE3D1E77577A6799DEB73D327E34 F0452BAD98E27FDC0D3E75E7EEC77A475E2CF2309C8C239AD8B0630860C95238 FBDAD0F545EB9A8033DB384BDCA72CD5D5277EF5BA4C6982F59438E6584EF731 C77BF7C11FC48BF4813B659A32A2498ACCFD76BA42036874E0300E59E3E6038A C21BA71A86DEC54EA92E9134906C1C7BDF66E5B7D6D7E67B2B9F68CFD2E14E1E 201B5F082782ED391721E4E040D5E5D940285FE0B6D55E3F874DEB9CFA5339A9 6B378AC3BF6B721F367177ED6B83DC86AEE2D2A033A945D90A214DDDB550B6E6 5AE1A2525598B2540A09D23AAB7C38FA7517C03D04053592274812F8A1C70214 3C5670F4339FD46C5407E6DC3890EE0D569BC92B6DCEEDFD87FC573EF67AA767 AF0BBA973ADD20804C1361AD848ECE29B43E774EBD4773D705767327A111B222 8AA55CB66657D3F2F3FD8DD7AB7162BCC32468792855D74133039287700327FB C3D0BEB078F2F8A3A69C1C39DBF39E5DCA5B25C4C3F2EA5D9BD1CEF1274DB8A8 20FAB20AC55E91EC2E2BB30D88D06700FB9D7EAAACA849516508CE5AD022EFAE 6FE7F9DCD9C72AD1E3A2EBDE16E4285332D1B231BDB3BE75FD9B8BE79322F603 3489AA9055A7E089AA490BFE53CF7F6DA778F346FBC3E7C72BC813355F7F77A2 64F4C1276D904455085F4B7BF0CBB0678603FA37AEDDFBDC57BAB3B332107EA1 ECB15EFC81E336A848414A5DCA78D236A6BA9C0EAF6CCE9D3BCE5BE2DE951BEA 6AB1FCC41C4FA89599E5E34A083F7AFFA90BBF4E47BF7CB87DE148D985AB1571 2804B80FC70462B6DC1EE9BE0CFC767EF5865E5FF7F72DBBC65FDA52B3DB8394 AC448B1F7DBC5AA292E6F136CF7FEFDAF0C676FB78123F49501CD01DB23D6C4F 9D7459D38CE2AECCE2C8E6222C223C2E73D5BFBBB378E8143FF08841C5519FE1 223C2E9901963008115093C451433473168392B72D6BF9E9BDC1A557BA47CED1 C58708A0D5FBA7AADEA362662AB8EFCE0CB646525CDDF2502ACCD3DE5BB746BF FD7BBD238B5BB450B72673BACB1F399EEE8757927779976CF5EFBDFCFA701BD0 62EBEEC6481621D14926BDC28AB454AC905145533EEA7325F7F93FFD0BFFF5E2 E3E72C20A7EC3AA177D07A7B2DDCFDC35BF24A3AB641214B539546490FF57755 5A66F06A57B7B6876999A66A3C916BBBA32DA9502C9893034BBD738B734FB467 1ED3E2E0309FC90A6B8AC2B732F67257F631E61715640C3DC8F31C1FAC9F5695 C27BC02AB4870180A8553D74C9F58014B61516425C9A94AF9BEA763EEE48F5F1 EEEC8FCC2E9C25AC6774E2FB4A17A5E00AD5C938FA3A41DAF254E92111DE7364 4D884B159AE4150DF27352A84288BA33B3B79D829AE075EB865B27F4AFEB162A EE705450BB7A13C882E39CE1DE0367068E2D64751E856127C68DF0CAD7B95715 A897425B0C49843A08B0F4A1B5B7724DB3A27B03131C88D9FB5BCC9ABD17D7B8 66BCA9E3C303C8064536482D9CE22443ADEBDCBAD485D2D4ACDEE4B2DC4CC1A6 6D925EBD215067C2691AC47154F35F99468ACDE18FC6EE5DD4F47E9420F153BF 5254C5D22F7980CE2639920FFEC896AFC8DD9F3C70ECA9D5494909243CD39F90 B9E5CFE4C36F0E073F78F8F485F5CD599AA52DCE4518C143E51594E580EC631F 11BAEB15DB0746B6D359D534D4E26E1EFEC59D10C0746104E7A676BA61E1A832 7F9DC69D2B35F6D8B6B5C674334FD54616254AB261B906CF102E9885EAA982AC 4F9CB400DAC518D40B867FE4B7DF2DE557F29DE7E6170EA1C486F58CF30EF789 0DE183A01B1AFA7FC101F17D8BBD5F564F3C5D4FB6C982CD96826B19369BACB5 F370AD1D6B1B4D9726113A0FC2FBBD015C18B24EDD055DDD89B24DD18CE24A8E 0C04C525FC9546F55A241E092813EBF606B55120429F63EF16A7D5DAFA8D28BE 3B98B80A890C16CEDFB3BC35ED703E98F6F6D8ECEF79C6B45E9F78109AE385DC FB8735A5CB2948A3063977DB95CEAF062F997B187874854666131CFD3CA812D5 5EF3E3CF6CAFBDBEB3CD8356E4F90B8AEF2B89F0BDACE3897179CCC6B7DA59CC A25815474E758EFFC899E0915E30D3195FBD6D6717DA271F23B24D39D7A1A285 C421A897E56AC3981D1FAE7485CE4014955032C2150AFC324FBF7E3D0D829933 8F4BD2612C761AE759851934F13500CDB59DF5D7E71F69E54E6208AD94512528 40064E82EC63FFDBC3E1D7DF9A7DF15C79A42DB4B0AFDC4C4793CE0B4F547137 D02153024E45014516B701BCBBDD7CE78B7F5E6EECEE9B5B1AF487E448D07BF1 988E435106B9DC95AD413222E9CB7D15D0DE332B643DDFFEFC65B63C3BFB74CF 16635AC063DDA95A34883FF8D0B97F4577FFE5C1DE530FC959088382DB90A284 1EFC09252F6DBA396EB15679E76E76EB4698EC0FDB7CBC3B0855528C75CECCD2 0B8FD973F315DCEBF56AFC3B57F2DB83E44C1C3E06E15321BD78AF45431B2848 A68910CBB3864BE15B2F8617375EDD0CC25EF4F033263E6C4CE8DC8533D755C2 9533A80CA93BF328EF4A7338C192CF182F0926ABC3775EE91C3E4F171EB6E5C0 0D2FEE6741D74B994289E9E4BF2FE882B4399355E47777B2ECD32F659B37C283 F3D57AE1DF01FCEE916333DDD30BBB77B39DABEBEAF6D00E4C56D051654ACAFA 6898AD34B27759378A665AC93C95F1BE245F62473FF17CF7C9B3035D757CC034 9B9AE6E67646BE70A77539239947CC984084CFD1B107754970B852D8D02F2D57 2219B0D6D5CC5CCE8B9B94BF331CDCD95C1D0DF258914767C217160F9C8B3A07 7D218A94149304E2A1AE4A457779770CD9542BF4D7E0BC50BA36F7D6D691B78C 4B848C95797F20BC41105D2AF5ABFDED6D5DAD84FE4FCD2DFFA7F1FCA90CCAB7 A2DFB2C380B775E46C138CF14D19A2651A64041FD0A176222594B96D005CE640 29041FC5405089C6DD4B8DE2BE740F704FE76558EDE0BF85648A4B0371959A71 3F93504438C20502389A2BB4730E925698A00097CD89843F5DFB509089C80348 E6553898D4DCA9DBB870D07808D551C6AD6F38C3C11A10EC419C9A22419A1FD4 232D78F7280DAA1457AA514E4302052E86D581D63A3789BA75E87CF4F434EEB8 E451F3275DB3AD9E19B207429B1B48B9A25F370F00A3B3A175D318FF310BA074 F294F2B45FE12EBC9CCDD2C2FA9F9DF1FFD9DB573EB66FE9EFCF1E4BFABB95C9 46CA6E2FECFFADAB6FE7B1F723878F9EDAD85940C9484FC19DC00E942C026603 1679489E370F30C298CB8B76DA1DAD27A6CA09AB361F03F14DCDE775A3E7DAC1 9DD65B10EF19A4FEFB12A169FA72D3B99CBBC9EEA6510085659901B0867F1099 C2579009FC0A05C2288702C054A9A80039B0CC44AC33F0826F8C76EEA5DBCF1E 3B7EA414BD09649F4CB53D28BF4420681DFA51ABD5E3AEF7DB2886B3A98B329D 6ADFD9BDA59686253E4D274D227C20D3D85A6AAEDEB6D1B5293D8A4F5ABF340C 25FC0D76ADB98B4C65652BC9B24E9665A8638AF110CD938C7BEB807701C74065 12505C964493DA5A9A81B968E3B211AEDB369FB03E92DC9D0FBB1788FECA2CE8 58EE666F1C781F9DD70CD5FBBD2E9CCB69C062D6F98D20D308AB5EED08EE8E3E CD9CE61C9E3BC926710E356C7B356EFDD6DAF52F0EB675D43A44DBCB58AA17C1 4C305FDA857E29A2561885FB235F9577E3B3C1FC538B8BCB3305449BA79FB087 4F7865E0335A055555469C4A4B86D66E733EE6A8FA0C8100AA8412B787D1D5DD 332C907F718DCE2EB54F9C95B4AB8D2790ED5E40E0D3412B54A1BE797BB87369 F6D120D726C45917044401550F6A92845088F0EE6DB5F595D7679F39454ECD42 BCF4DEBA3758DF997DEEA9B23B234C204ADC9B2CA02A54653429E110F6DF7C7B F3AB6F3CD439B0391AD94366F1A30F9B4E9B679C88B4A27DBE5AAE7EF9D6CAFB 8ED393CC7E6B4B7F61937FEF51EF00A9C6235FFB968D4AA1C2D673271FF975BA F62F96569E3BAFE684123C8004EE84E195C97DE66D5FBF2732DBD6A4B873938F 67BD056F52F4F918CE78B43B29BBA74F441F7A482E48BE369EFC9B77E9DA509C 0BFD47D164C25D9807BBE47522743442BC3E460A2C67D0314404D48FD5C660D2 CFE61E7FD1F4CE68190956A16225C246A398F49A44481497BC4984B39AB7C2F4 CEE8CA37DB871F23B3A7A91C10BAD71D63F76784D39AB18ED4B9170A9D0B61E1 CA4205436FAEDFFDDDCF2F50786AEDC95A26B6719577272AD52059BBBB694958 4A9AE5B84510FB7C36648BEDB01BF958C4B63CD30E9675A2932A9B93FE138792 F79FCAE0C82848F11241BB129B9F793B7875D4CE22536D595559786B0567A53B 4BBA82875CA98248F8092F3D2F0B04DCFC62548E73B395DB6F4FD257C6E31B1A 97B64E86C90BDDC5E7A2E46051C445069FF03681E4A7A40F9591CD501B8D6AB8 A9943B316E5AA223A1AAB4AC02F99621AF8CD26B83718FB20FCCCC7E6C66E603 223E00918794BA03BF5C6B59FAAD0566014C9606D0AD1BC40AE3F9803B707F84 A28532470851C5CEC0C6C52353E716378322D33D83865AE23A974EA1131F0385 575CDAC9A04CC790D704A4390897C8B2F124C492761289003DC271F38012CFF3 991F92008FA2746D388E54852684D85A7B631A0E30E2B89CD46462B779566F79 3BB784BA59E9FA00DA99CDA3D190765634B53A4A4D71E0353BA6B66475A4503C 29DC15F5B489F9749AEADCB8CA3CC09DA9F566EA9C5A771E1C3433F5D66ADD95 A46C0C184256ED12CD3927BE0FD5CC4C5E4AC6BF36D3FEE737EEDCEA0F7EF6C8 A9BF1927E1F6FAE64CF79B51E7536FBC726EAEF791C5D94365D593803F7C03A5 302DA573DE62BEDB2411BC7691A80365FDBF8CEE8190E69934F9C2C9EFD43345 3A9D3791262FD6D3C5BF94F8BEA35FBA6710D8B4A459D31FB68E910ADF57A1FA 0CFCFF1C7AA4D18A795C0B5FA1CD1E3C9D52E752AB246A1719DC0438EDFEE7D7 AF2EF4662FF8B3FB0A9D4019A4321A0B867BC2460BAE7D3867027911B8C3EB3A DBBC1988367BEB0DAEAA4F02A95D14F79834763A0C9D7E976658E83AA80D0115 C288A80C91B8F387E3355579DA06DA32148D55D2B4C66936017448B13F26918A 822E0E5CE984920E612DE4F599B28395BDDBA181CF89CC9EBAF4C04FCC9DBFB6 63169B66A782900770E15FCE850E597E6755D280F7079ADE285D80BD31E7BB69 EADD1297A7A953986F342FD0938BE6591AD46B60DEF5D0FFCD8DD53FDDDCCD45 329BCCB574792E101F5E983FEA7BE9F668271BC4D402E68A0F90A5F35D1D2BFF D489D6777D7832331749882CD5849782EF17A4B4D536B73B9CA7503CE88A2ACB B115CB7263D07459B056FEE66DB1B83FDA7FC27A0BAA82D3557934870F5C9220 32ADEAF6ED7C7CA57B96031A17CA0D189980E20EBE5B8AF2E6A2330876BEF25A F7F43E7E6EA5D0C67FB7BF736D6DE1B9A7646706701A2F5199350DB557568136 981437776E7DFA4FF60F2037F0F1427EF0E38F92A519592A343AD264FBCF2E66 E3FCD0779FA9F8F8DE1FBE7368A74BBE7FC9C8AC52DA876A9CE75067B2E8A9E3 8F7F92DEF9174B073EF0889AF77242232F061CA06CA9791504C1E0CE6EB93ED8 174493B55BD1EA6C3EAB755CD0EDB4AD3A83BED2ED99B98F9C338F4472635CFE D695642DB58F7AEC31B4DD6D3AF8D30AE8BD8910DFAC14F8D2E006160C625FEC 8F8BCDDBF7BA0FBDCF3FFC7EAD5A1C82399D30C621C24020C544A81D170FD748 533803159BD32C8CD2DBE36BAF24871EB7BDD34CF5FF8A44B8D73999421666C3 9C550154CFAA94016385CC5F7A3D7AED7610B5D7EF6DEEDE1D15233D009433F2 20102BA799D08EE2AEE7CF066197909642DB51DCB24F780AE5BD9E3349A96654 F2E8A1E0A9657ACC9779061F8E041CB99117B3E2CFFBAD2D403AA312AE166AE6 9310BE7009B05095A6E244B6541557151C120092508F89AC2226863F731075DF F4C52B56BED6DFDAEA0FCCF6F0B0D73ADBED1E9D9B5D8AE35E5E6D4F46F0F1B4 C750635A29C8249E1F4A88B90A220AC9A99D48F5B2B66FA73B7727D94381F8E1 DED2F7757AC7A10AB32A656A1C311289589AAEB659803B064AE06BF2D15C1799 889A429526D03714A22E231E9484CC195ED4A4043AE55A9A26FF3117FA8DDB01 10C4853FA33CEE15B91AF5B332331C758399E3EF291F004D4B78210F03141A97 70E23C865AC2D413229470D051BF1A8221DAD0391F05BCE766BAC8BE07FC6A59 B16669D5A9D8340D41DC3176167A8E02E3FAB47BD1453719AA69EBD52887B9AF C09AFC80A0A11E4C36131EFCADACDB197793A67A4CE666D5889291A95F3B164D DBA8C8E56F14B39C2E11A7A1D48144E57E25001EC291AEE0A3AF7ADDFFA75FFE EADDD50321FDA7478F5CE8F7DFE9767E4FC4DF7CEB8D9F5A3EF478CB2482C52A 4C8CB0BE2EB13AC4A400400BF222C7756A5720387FA21AB14E4D77A70528FA61 4F49B6CEF0004D64D97DFD2E97CFDD76C55FFAEB2FE7C669846EBA2C757D80EE 3E6E911C9DEE24E0C2A205A90E3F11F3217B00EE40B7265C01D752713F50856C C56DA8092F12FBEDABD74E2E2C1E69CFCC1A1B419C848B10B2CA471B1C2B50D4 09400F0649CFE515B735D7B4C6DDEC75AA65841D6BD45F6F84E2EE5334ED7BF5 CFAC7BD99AD61ADF18A58C13A3C74508402E858A2A2AB03D6A717FCB7A6951A6 051A3955C4399D62AE23BE25B1352DC2624B7D6BAA0859BF4C38716061EB219F 937E7172A30D9189D7BAED7B75C58394DDF73E61FBD74984EEBF3476CA0973FD 6A9453AA1BDE3513DA3881F8A0B27DF4EA2241A95910DCE6DEEFDE59FFB7EB5B D77930EFB74F8CB327BAFED3678F7D2409535265B28042548B51B0A4D889CEC2 075F14271FD72C6610AB489EDA2AA03342A6D5F67553DC8D234D5B01F11382A6 696965C6A1203EFC5F4107D7FBC9A163BABB4CC58291B82EC66D6A982989EFEB A8B87ECBE85BF1698D62B41211A5E69EB5C840CA511505924DB4FDD5D7C2C530 79FA6449897F637CEFD2CD7DCF3D63DA5DAE43240AFA10624DA8E02D991229F8 66FCD96F906FDEF4FCE86E373BF69147ED99DE844F02150777D9952FFEC9CA93 CBC999FDD59DFEF5AF5C3A7DFA8C3A5DB25D018FA824BB812D84EE90F0DC81A7 7E9D5EFFDF968E3EFFA89EF7336A03BF25B0752425944170EF2B3EBAB2DA92DA 0CB6C3CB8BBBC94EB05FD0BBFD5876B31DBA236DFCCCE1E47B0EAB7EAAFEF595 CEEA583EC6F985C03A76432DC130957634D34458B79A48E57A64504BC8205044 44920C6EAD4FBA47F73DFA716A7A8C00D09E503F44A4C04A488408FB1955A2E0 24859B51D9594582B8B83DBAFE5AFBD005D23D45F5605A0C367F06B57B8AFBCE 77CD8D9844EEDB84638B55671A3E451091B777367FED257E657560D29BB6EA97 2D9DC634C1BEF8B14E326700F4411988A578457CCD5042132E851720E8ABFC1E 6F69B8166265A9F5C251FA5834A80689091CC0AAEC9572FCEFEEB5D62B969AC2 A8D46652E56125713F516A897C2F2E2A817D24424AB48E86A23A878F19405C28 5194BD52246F27EF04E6AB3AFBD268F7CDF56D23A267DBAD7F987292B4003915 A87E857B0D8279847B130D689715215FEDEFBCBDB5F3DB6CBF95EB177AFCA797 66BF87C6B388422C8DD17B9449E5873E0902C8CE33AA5F795EE9F90AEA2B85E2 E21C0ADBC0EA98A800813D435B23122866EC74F98590C6CA6E4A6470AD1824D5 87850F79997BE853980EC7FD01A466F871883EF110D92045591902C699491814 2290021976889DFF6248B84FBCD0898903CA55B8BB8B7FA0471C61429B262834 1BFDCE58A466B0B8A654930851E60B77DB1102D656F26C1AD6DD7C4FBB50E9A0 2DEA31C3ABAD371FDCE8C834610777C5F6A0148A77A0D2014E045D92AD3B5614 81023A28D4EBDBDC2519F81301D722DF02DB6FCC09E691A4C2DF3615B4F474A8 6D280D2025A803A4EA7E6194FC37B7DF1ED3D13F39BEF0B72AF2177EF8C92059 7DEBCACF1F387ADA4B735FB7C55C1BFE18214B5E7A06A230D59E2D43EC853297 1B700433D5B961D33B57F3B5DDFA50FD0DDC256C5AA9B5842A69D6316B58FCDE 803CAD35F6D0605D2E342D5184387B3434970B1D65D83D1B2DF3BC0C25F1951B D0E18AAC9376C14E37F14B74073521203DBBCBE7AE6C6CDEDCBC75E2F49183AD 76779476E05D708B9AD61E26419707D186054E2575BE88F5465D63CF329D88D6 D26BF845D130EA41613CE25AFA7B08AC117971BB10786094A395610A941A3E1B 9A4C41018E964E380FE8A64AA39FB92A4A54019684A3C9B923603951721308EE 79222E46707205948A3E77C6BB1A1FAE83B2F56220BE118CA4864C812B992E81 DC17F79BFE659A06D67B92259D62DDFBC910F772D1E41C4B619709DD5C900AF7 BD4C3332AC533281A4C15880B61955DEE2E166D8F9B5EDDD7F797575BDA4F314 65E30F1CEE7EBA37D33E72A06AC72A0EE316890E7BE6B145FFFC9395D9E79B36 512312A902DE5B39B1D96070F9B5FEADD7A9DE659DD09B5FEA1D391C2C245A8D B92C710B626826832279E89CF47A95ED425E0D015AC9010070291252F8E9B5AB BEB7EE9FAC888208AA1854754C68054F9195A4E0DAF727E1E637DEA4B15EF8C0 2325BCD21BE3CDCB3797DFFF344F6609FA80A318341CB5002F78398ACC0C0FE8 57AFCBDFFD9AA0DEED397AE8B993F6B1682719C77A7FF8F57CE39D57573EBE8F 745BFD2FDDBD7B6FF7EC271E4F835BAD9D05A964166D045511668BA47D76E9D9 5FA6939F9F8DFEE3F7F5176D44C3A884E007D7CC8898C92C8B724FDFDE36A36D DD2AE5BA4CB7F385708117C518623A098355C5231EFCC4B3A61B6EFDDA97F66D AAF2784B3D2D45C0040A10581E3005B887351D0D57C5A89A6A4CAD4F70E1AC2C E1EDC76DA893E9BD147D0B9E7961D43D14EA19C81684F415A41EDD82F71DA0E4 3FFC24A46CC2F4B0E4B3156BB7C717CDCDAFB3A31F1AF49E9BC9EF56D80BD09E 531744CD1FC17115174AC542E3B21AFC14D936B84B5B51D30E4256FAE6E2C6B5 DFFDFAAD376E1486C91877997B855EA1E189A55952EB28D62B791AA95935A3CB 55FEEEA2C2770A221B7B3424DE6CE43FB1CC5E385C45433822840180F7E90D32 F9B3417993FAA394C802D9049544731E091F0247F6A446124E999C38F8C2E0CE 690E90575A5610559032C255A70232C258B335A95E5DBFF75221BFD026A75756 3ED13BF1C1015B198E391D43B2EDE783AA33B31DF5DE52FEEFAD6D5EADB288ED FE74B7F777E2A3672B48199322943CC65113862E147340EF2D288D2A5AE0DF09 7A4E031A149EC702E46298A613C9EB4B5D52DE425B255508749EF3DC70028205 BC150815288D0D203357C340EC2FE03B9A353BBAABCC5C3F9C9D04A390EDFA70 4FB29099280E223F869487D717BD13D08218E551A04C097C4BF72A67DB30AD6A C271FD436C3D023CE58EF1893BEF1CD3B6331E2A2D806EDC4FD1B65E08445501 1C8DD57590B3EFA0B4C2957CF8CCB6536213AC405F5FA38C0D357A3A4AEB8C6B 184B2C99681A42D5505080DC05836B270B69C75C40119428DA754BE5BEC9A186 18A11F70101A6400791ED4759239B76563E322E8E471D723FD44661C3233F57D A486A891B0C20FBA457E85C8FF76E7DE4B03F95FACECFB7B3CBE9A24BF58153B EF5EFF27278E3CA673CA82166D8514C054595A4F4084F3A046D11E0930C00AD7 84E68D9CAB75632AA76FD92409AB25AD7314A353B6D15486ADD6C9AB53446DE2 B887052D2376AFE071CFBF591AD758DCD60BF0F7DBA70D09D7C12CC74F2DA52E AB0A6E364A5DE37B4581D9BAA5EC0A1482EF5CB48AEACAC1D95FD9DE985D973F DD5E8AD4968D595B2546F1F13C2992D243334BA8960000649E6A1B91A4A127E1 11D092E16C0AF2243C6C643565A195C2B68BEF1017FA4ED66B8366C97D058886 3AA4DCA7720C1AA43A39CBEB24E3386B873B599A0A92227A6C06F03E32648BC0 8B465BE98EE72F96B61FD8716823C36625BC2196C750E3504FE14A438E2E4A34 8118E7A3CA5A030F9AF2E1C1F542EAA60C8D97EF77AC7852361541A27B449AFB C2117B6F690AD6F70615B8CD12A31E9640D7781FAEBDF60B9D485E04C91FEE6E FEAF6FBE7B35F6260071A5786629F99F3F71EE4969E2702E3D4ECA4749E7D173 B47D528908508757CD6B09F8775C78E3D6E0A6BEF4657DE54D7127D5B7C56E1E 4DBAD1814797836797CC41AB13B1B5B13D73E77474FAA06A634798EA00A94600 3B480A55424BD9FE2B6F2D2DCCD80538B523642E41F1E1E3043E944E44114B6A FFDEAB6F439C597CDF858A97E25EB9F6EAD503CF3F67E61695416335B890AE0F E0544E5BA21A8FC3E168F5737FDEB9B69BB58A95F73D632E1C2A7B9BF1C48E3F 7D852F24E1F72E54DBD9F0D3D7DAFBA3F0C333588D4AE7548061AC24D6E3D199 13E7FF35DDFD47F3BD1F7D727C3020D2242A361E97D86EC5B799DD1B0729CF6E 5DD77E995462BC5D84551079623BEB5B16CFF4795995E4C563C99963C3DF7939 BEB15B1C4AF8F3D48BB13A83D80D28C5100529C3196FD9DAD514B99C08D67C94 6EA7A544AE7A0B0A2AD157FDCD51F7FCD3E5FE73BA6AB50A4BFC9C086D542039 09E1A4AAC030A884278C8C4BDA95A29B8C2EEA9B5FE5475E1CF4DE3793AF6AC7 06709D573C5515EAB463F30CC08955AA9495D78E31382A1D7811DD4A6FBFF4AD 9B5F7B7BBC3A20CA2B7345A45A08E239CF5F48921822883323352E1D36FA6CAE D6C6F9AEC08621D22B85CF131F896E331E7D78B6F58163641FFC921DC372DCBC BBC5CA6F8C2757B53FCAA82C555911F470364E82CB3980A3E137BE7CE6880D1A 7D73355244D087821690996CE1515C7B8A585812DE1762D70B6E57D54B83E19F ADAD95D63EB3B8F4446FF180E7CD1BE34FD2B215FD49BEFBFB1BEB7772BD1877 7EFC50F2BC58BA90B2783232B12D3AB80314A0F01E65BE501EFE1D1330C78A1E 2523D08190A1AB83CB4C763AE56A628AACAF996EAE1BFA6EA3840A00C900F974 A46066E49903630FE2C29ACCE2EDAA3B107D2F58EF42192393B2EC70D3F2A180 F2BC08E9A098D4E0493A0B62C21B7063F644C1EC7423C06D45BBF85E2BB4D53B 5BDAF5F56A66BCB2CE7ACC38EFE2FA94D53ADF6EA24885C6DF822334A4BB3EE2 12F8B1448732ACE043DCB962CED4071D1D9064840280CC0764C378A6AB01E4C0 3056E8BF4C664A93189B52BD2DE838F045B9DDF6E396165DDC62B14555F54303 5F9F0BDEB1A2E53E4BC68DCF455B2B6C2FA35E3813A69A7800F7D5A2D1DB49F0 F39B6B9F5E1DFFCCD2FCDF8F7B975AE13F5A5BB5A3F1FFF4D0C9F3722C88DFE2 49082885C3D7C3CA4E860A12A18F72132EBEBB2C4844D3A9C6DAA236CC70D194 2321ADD9F1743342AA1BC79066B7D0D4E452E6363D1A3599294DBFFE4913769D 9313DB832A54EF35215D70AFD7EDEA4EB28FDD45258B0AD03600169481704C2C DC77C3638FD7496075A547865FE7F19F0FEECD07E2C3223E30292467638483C4 8B858EB0D528584145C54922596C85879212B4501C0A391EA02F9BDBD1400E1D 7ACDFF87293F7B0AC4F7B33EA93BA4A49680D0CE041BA93E029742148405AB73 5DE5444A802C0285A539EA2085C404944418625CB166D035D10B05898511D409 935A5413A234546899D2AC6F3EB0B2F21D6B2A0D22746BF87BFFD6D2A97E6993 08A72D36B7CC42DE2BCFFDC06FEB369C206523B515496FB83CE8D1883038ABB9 A53743FFB76EDCF9ECCDBB747E697D6BBCD2B51F5B097EFE7B3E462669F278E2 3FDF53070E52FF283791C154D5C1C7C6D381C766D20D79E96BBB5FFB32BB3E0C B7929D3E5BCF33E94FE265B2F2ECE195F75DD8BA7B37EC9C693F76BC0A2A388A 9E0AA584430F787A42024327E38DBF78F3C08903AA5B427244755A9708E1B70F 301132C598C7A2CD57DF2655B1F8CC63CA577C2DBFFDF2E5432F7E50F7E615AE 34A07FB90B0E1C971003A8C20B3FCFFA7FF62679F94A15E4FB1E3D4F5E3C6BBA 3BE6DDF5BB9FBB7AE87DE7EC33C9E4E26DF9D2BDD9678FEB4794C8A03C293111 A250650E9FC00BCF9C3CFF9B74FD7FD8BFF4F147CDC96E918E005DD2C8230C0A 2CB4B4BF777D739EF6AA8D6D25D37661CAAC2A06E54CD2D91AF795F11654540C 27A343C9BE671FD3DFB8626E6EA53D117CC00BBB5E4D3A70DD0CED7CCE583350 AA7B2AF87E7DF752D1901D17587908C7677277A092A5E4C43355B4CFD39C4345 0C5843048808D16005AA8190D294D22CD72D1BF6E2D15BE6E6D7D8E1F70F7B4F 77CA351C26E125770B7BE85200BF5AB93E10DE7FB83AE8F362FD56C5FA6F5CBB FA856F6EBF7E558D0017F0C9249DE5D1D178769E077114E51AD255CE6AB2B6B5 74DAFFC30FEC86DF508C6231CE98022415F9489B4AB8DA1F25CF1C8CCFCD197F 0889102E0D5BA3FAB56AF44EEE0D9111698ACA20DDA149844E8B0BFF971B1744 8CA970F90F1221E38A43CA2A91F052449C0725043E5E5464C845DFF7F2D27846 7C830EFF707BFB523A91942CB6DA8FB796CEF0F6E664E7B3933B17B57D24143F B274F847FD76BBB2EDAA82C79675E9C42BA8D189B211C42EEE0CCD6BB31EA6A8 5B4C8284245C5AB2534F1FD700AC2DECACA86489FC761A49C7E5E54844674EED DF3310A870F8B69990D9015D2BB2AD521F1EB5221DBF3D47DF10834E513D5CB1 43AD563B42AA5325B4F5A1AE16DC17D491FB0194C0CFDCD4C6352EEDB422AE79 704DA4A0D3A576ED5C75F0D3230346566809A46A4A8B719A1B75FE74CB5DBAF6 EC68C677251361063802552271E95B91A840353BD4ABC37911AE17965249826B 8DDAB7DB50C230EEF1168AD82B3D03B8C092A16FEF1255526FC5B31EDCA45CA2 3EAC8FE6A2383A846A06EA1234D1D250887B50D7482F84CFE0D12C0AE1DC24D8 8FF3E1E327453AECB5FEE9CEC66FDCDCFEF195C5FF2A9EB9CAC5CF5DBED4F5BC 7FFCD08973E530E4F00BDAB1010C542092355EE16BA865007DD606102E503A02 1A36864DBD87671C86833727D8144AF0665251EF45BA897D33F3430E1A9B0E9F 1A0848A7FA17F7FBA2048988B666CE4E050DDC3A09690063B36A02F7AEF6E880 5C08D01029A34815B6B88C635D9A31CEF81E9E21D99F7ACC069F4EB22F8CD77F 283EFC91093122ED8792E75E2012D209503497166548D1B71DE016C7045AB00A AA5D88E98240D1C80A617DA89901DE4F679FDFA1B5781FFCD570C92910DB6916 74C7DB34C28F4E9DC66D4D584042900515DC1D855A15325359A651BB1E62BB73 CA1658CB131D52D4C1A86C69F528D038770F51E34542B4762AB402459A7096BF A763D06C793E9008C9B44D5AABE7EC653EF7D41F503C68FC5EE80389B0E18A7D C7DE67D368A5B68207A7382A6558B4441680C4D121D8CBA3F635C23EF5E6DB6B C257713248D7A2BCFAC4A38FFCD087CFC547F2E4F9C3E5FC7E410F8932C6C615 92F02476EFE8BCB77E7BF4C6B7CC8D1BFE7A565C4FFB9BE5B8C01B43CC58FAE9 FCB1C5C59545F2B73ED43D7B5822B7CB173AB629098288A8098974B9BDB973ED F2CAC3CB793410501A6A6C2348142B85C78DF30D2B846783DDD7AEE8B25878E6 BC06EC73275DFDDADB073EFADDBAD783ABE6E34576BAEA68B94D2A141ED6A816 72656DF4D9AFCB6A1C9C3AD4FDC4132449075FBD387A373DF4F167F5623EFECA DBD1DB79F07D8FF597367A29DC4524B112B8E536574640223C71F637E8FA2F1C 9F7BE121EFA159056F9B1A250C2ADAE3BA95BF71A72F0ABF6B83EDEBD7174B38 6E7C3CCE620A2F9C8DD3AA478262673489C4FC89237A7BA836FBB960FEB3B4BD 2FC656A2AB571EDCA3719342C77BA0AE5180FF5A72C3B04F2C022F08E4A8DCB9 5BCE9D7A3F59395DD0808FD2183B7878B13DF8E85A58408414B2639AAA8845BD 28BDAC6E7D432C3F9ECD3F11566B0C2A4483074F39ED430FC9F18EC0C1B12D00 8FCE0B23BECBDEFAE2D7AE7EF15BEACEA0C54259C9221F2FB6E223DD5E0F3072 89CD1C692C606267BCD6F00F9ADD009708DDE8C229AA60A0F4D071141E5A8B56 333C7C78AEF7CC21BD2015031CADC4863097757A7144FB584F427C3565C56AB7 786CC5983D44E87661E134E9C26A01F1556360932E9670A93AC4F31583FC3716 FE8EB5E3B20420BA1DB03C0C2F8FD32F6E6DBF9A0D2125CDA0FBA01E78EA482C FEF6F2C10F92CEA9B4C0F94DC0AA884E7C05E11F424B8C03060A6546E531893C 0B1ADAD2F37D56932F845B07AF735FBD884DA7E2A7902CE0202ADC15D250C220 DD40C1692E710CAE001446E81CA0AFFA64E696DCD76FDD99EF7DC66C5CDDBDF3 FEB98593C25BF4BD5EE841010775830E341248998FEE8435ADC08116DDDC7362 A7A0B046844DD93B8D190E981B670E084F12CB762BB5879ECAC6D58AF03F1AA9 7CC631419DB4969E0AA5B633AF74C20C113A2B928C93B16D24B29D9EACA5CA02 5C65B64CDBF13AB3934ACE10316770A83F88BC9B21B9A5F3B43F9A1B17E76716 97684B09318CC535BF5AD593D09833053F33224956963E2D628F73BF25E11017 BE29954FC63144443BA768807B289E57E6D96CFB93B6FC5FFEE29D0F9E58FABB 3CD961FECF5DBA3CE385FFF8C4D10B6A2044C8593B51F04B73F8AED2599441DD E1BBEC63DD065B333FAB3785584310ADF5B6F9D481B0B9859C369D66DAD04FEA EDA6D2B5DCEE932F6AD6614D3D732B6B3567886BBBB792FFC06B22CDC8B1F939 F22F71E04320CE289957507AE355C7551C274086044D2C372AE2B5210894D956 BBF5B9D1F07A7FF403078F9E2F264A0EB782A0ACC2251ACC87268B4D1E7B89B4 01BC21C1D3180E2D89358D0C458758DFB5CAE134510641BFF18DA2647A8EDE93 05A7EB1FEFFD774E5BAFAE77697DCD6B3D55C8ADF0052011A2662C60782B735B 16564A67CE84253572853D6EE72587170A4160E8C9CA871849A1C6D301D3BEAB 32359444C8EFB07B3284E4AFC85B7B88904C570CA7C96FAF41ED3ADB7B9CE9A9 9D16EABEBF575A722F1142B538096CA450E1D3B9D668F832D89F83F0CD421577 EF50F1FB6FBD69667BAA03D7636E77FDFA0FFCE0F1173E71A675F6948A178DE9 F955E298BA3B9AA5A8FEBA15A46F5E1CBE7D650EEE48AAB2BBC3B42FD7D67786 FD499BD04E44B2305FB9702CFAEF7F30EA25C88C473DC84414C805808286FA72 B0768BE4FD998351EEED7848C1C5AFA539B646390A4B3A4F3BED4322847FDC7B EA9C82E07A6DB8FDCAD5C5EFFB6ED3E96ACB7CB7D684EF0837B85885CA9650A9 4CC24131F8D497ECED757266A5F3438F73DFEEBCF4AAB5D1EC471F356438FEDC B75AA9EF7FEFB99DB9FEDCB6A96DA3A8A9A829B46B8D1E7FF85FD1C1FF7E8E9D 986D9F5B81EAA5D45561AB28E6A86F1E24A3BB43D95773F1CCCD8B170F0D2CED 78A92AAB41D56B2F8ED23484A831D280CEC29936F7E8B8BF4B48C81F379DC3B8 7041FD469D9F4EF53AA6531E47E78432A59E0DA36C9F40A661EC0BC5B6DFD96E CD3E1C9E7D661CCED0A1EA40D4F54A8C9AB8EA833B69141E28129C7C1A75C2FC 86BAF52D3E77422F3FCEE536807F82A70E1321B6C2E06CC8D27A383C625EE0D3 58AF6D5DFCF5AF5C7AF97591430CF607E34927F4F7C7D18AEFB790DB06A74408 C3012E5751231756CB369AA6EBEE4EA570FC111CAB101B060269D35402D08999 D817779EDE6F1F8A4A918A71110C3C73836417077633659022A4825CC8B01269 1221445F5705E102609D08E196718810980899529009911F217289E5120BFA9A EE6A351474187348A8618EDB44EB9DD617ABD167D76FEE78F0C9E5E3739D9F5C 3CF2F4B03AA5190F47DC43116C00479E07E520BAAEA3BBB6C0ED43E7FD84DF25 065883CA8E0D2073FC135BF32CB95B07ADEF9D64134F23275E595EF345882EBD AA8AD1E9C264026D1A834175D9F0B971EC7BB39F0DC7FFEFEDD73FB1FFD08F05 50CBE5B6E7A1269041D56F010959F8C43118F74C9D9C8781257B55F3B49335A5 A962D7D6B1E24C4DD0301532111B31651C55068EC3EA4C7C5C89513336715D0C BDA649BD0B16A868DB5313667087AC805887961D434E2B8F63FDA45103066E98 E9F25B32DF95D59CDFEE7911053028E52DA82C475B376D756E7EFE99EECA82A6 E389BF3D19AEC9FE5D39D2429E5A983F1FCF2F97AC8D0250B43450D6901694E4 51E5DB02BE6B0E8F59998592C4CCF3E290139946DE9738FFA557DF38F7F0D19F 0AA20D4DFEEEA57713E2FDF323479EB729E0541BCC008887BA5A5299E3E5170C ABB1A9A6256ED939D598DA18C9A537E2B4BA6CAD823635986AC816EE81D78DFD 5A150F657F716DDDF98350B72AE908218EF4DD74F390F3E1CCBCEC5EAC65F441 F0411FC82D5296C213F0290186A03077853AD528838C19C5A51C8D6339CF2643 EC2DA40746DE2AEBFEE2E6BB6226FA9968DF4A3EBCD1359B855A9E78CBAD181D 3A380B4895585D72B5DB62D40B7B05D4CE348D00D613DF3000F458BAF00764E1 1A58785F7DD6D03D13CAF7A2C56635DFBA7F65EB1DFC5AC11BAF7D594F9DDD9E BA6490A62B40E64C408139816F1FFBFB46907F6DC87884894AE578C874E063A3 C8404C20D8F2092C2EFD4DBD76A7542FDAFCD90FA6C6DA20E37E9A64D3566ACD 07237B8CD23A11EE89B1B1F720CB3D5D3748843E202D121811E29743622E54CB 3ED4291075599486E156E0BFB676F3D023676EDE98905EB1F878F53D3FFBC356 CF411122D13D1BA51C18DD311C8E5F107DEBCAFA2B17C331F1526DF322044850 E8494EB6B627E5E640A493513B3DFD532FC63FF971AA4AC1099A16D0380068A5 1443F36572F79DB77A7351B40021708B600644BE9BE18D2455855FD78BA4D879 F51DCFE79D27CE4888529776866FDFED7DDF7755ED04928527DD30B55186108E 31041FB4F0A44C7FFFABFED7AEAA338BD17FF2B4A7ECC6675F4E8E1DF49E3A44 36B7869F7F79E630FC78653B4AE7878E700B5F0E8B9A0C3730A2B3C74FFF0A55 FFE6997532DEFFEC591200EED2D2B90CC3A9028CA6FB45766FD88EBB93F12078 E5B6688B82E9F176D90DE68CAC5495B649526C971C8051D71B8C065CB7D85999 1CEF28316111D6E702F3A171BC74C7E072C9047E6AEA1E29DE30819758E04E43 E045E5CDF16457F41EFF50B67084957E0CB1242820117AE85884C4177468C0FC 161A2F0A8AD5EAF65F90D64270F082D1388B214861F6DCD0D9EA2A835B18F412 78B83427E377EEBEFC993FD55FBA33D6CA7A419E637FEE50A773BC3BC3C6C390 413200BC3B01882704F60C1B4F556BF7144BA8039A3814A8D793E1A721F2C398 EF55016581E05D21CECD8BA717327FE24FCA702CEC1D9D5D1AC9D5115E1059FB D53589706F4648B16CC417A3DCB082BB0518F8E712698F28B362B30A0FAE170F B4D92ACB54F0211704DBA86558D9B68DB73BED2F75EDAFBEF6EAC976F7278F3D 7266521E1EA7FB3D2FEBF52DE222785834864707A915406F04B9CC33B8075C0B 8532D542F68F53107388AA660535A4415A33BA9DA1107A7E6803F95208645AEA 02426855CEA5DA336233E0FDD2067DD919F55E5F897E876E5D7CEBDDBFFDD0B9 27299FD1A3768B12242741A9C303EC211A7874D4E77BCBC2754F4FBF4757CA25 4553EB9CA1DFA7DBEA732B14D85BC62C08D9B0DE78C01703250F1E12C2117158 D9F84740EAC0DEAB0F08BFC02DAF6D4F4CACDA167A003F9134C9B17734F6D816 3563A9221186410888FD8BC5BD4540B1D4EBB5925D462F0EFB6BFD41319A1C4C 5AE70F1DF2C3F8727FFBFA64B45D5039DE5DA6EC99DEEC63F34B506CACA9AA3F 93DCD8DCE4A3F4212F3C158733C478C8335211240928E4946E1700CD45E1D9D0 07C418DEF2E3DF7CF30D3DDBFBB17D331B1EF9B98BEF26CAFF27FB963FE12145 43C633B162900873AFCCD0FC137D06B427E9349E4E074FAC99DC3D20C1AAF554 12ADA18818A4F5BBA9A15B4044F40F7F57C2FDCCD150A78BF9EEAD60C3BC594D C41EACE14D5A6DCCF69A25A526913402D370729503A48842EA251678D2AAC08E 88AD9079ECAC91E0932599674232999D1029BA5FF2D967576F9D8D7B1F4B6602 33DAF18B8D4A425D7BD25B98857B90A82082BF65057CC038F171DE6A4AC06C3E D66AC24918991ABB3676B88D02CB7D043525C9D432027BD420D6D82EBA67E93E 58BD1F8336470A871E066F215C5AA115A95274BB2E151F1833603A0BF8999C23 718CD88E613EDC08E1487D1018024142F8984DC8AEC5CFD80319CB51B89AADC1 3D08B89708EBF5A08638566FB8D0FB42010F24423B4D846CFAE3FBBF1B96388E FF03AF0E9E13AA73394D1288BD611815108EC298F5BA248E869688B025F74F96 3EB6A4970EC5E1232407A43429E0B89920E0A930697F98FB9F7BA9BF3E9E353D 363155550AA6E5242322367EE2E57478E7D668491FFDB98FC6179EB24541B892 B884058758112A3DA67956ADBDF3EEDCC92531A369B90991DCD14574DDDB8003 51BAAE7E5B065BDFBC18775AAD474F4A52F16FAF67B706ADEF79A148120E49BC 946E2DA5065688B3725B91882A95FADF7C37FC9D37766665F8779E0F2AB6F3C7 17E79F3B4B0E24D56BD78AD7AF745F7C981EF407D9A4E75C05706A06EF52E7B8 CE1F9E3D76FAFFA6F2DF7DE0D6BD5B475F7896006A428CCA725300B41396F890 FBAFAF4122895BADD19F5CF402E3055E3684F087FEC7D9B8DF0A66AA5D0C8D5E 8FA7454E729F9FA4D1E98E0C86D4D9F670126233043DA7D13FC7519CD18B1B1D C0F1BD72CD05EACF23599E004C09F36070B9DF3AFE4475E0A1D05FE62524AD42 C35B74ED7B4B6BCD2A64DFC12FF4AAAD72F5350BEFF0F023C6FA167DDDD1CBDC 011B0893856885E32C8B69BCFDC6EA973FF907E98D9D99B20525DC7034EE50EF 917D07BB064A39CB20079529970A6013849E52101F62C35EA9C81A39676CB635 ABAA4D41AD4294F7F0C2107E4FCFF7BDC8330FB5BD0FEC9F8493202B824C2069 E4F248DD1C5269911689135A74738328AD9D5431753BE9DCD147DD46138EB699 727C2BDCC5D33257B11F184D4785EC6B3D4166BFA725ABA8DA2259C2837D4530 12DE67CCF61B9B5B3F76E8E1F7F30EC9FB0B6D7F16E7183B39EAD2F3002A2945 00155701CB040E0FB8D6916528151AF02CE4F5E68371329EF733915B02AEEF2B DCC0D22BF1C32A5C304654885A07F0F94A9B435D1F8EB5184EB4A88409F6FFBE B9F3F9ADCB3FBEFFF88FAA24B1995AF6E0E07B1255266414063C8AAD909ED65E 130E74ADFAC1F66681F74379C3777403663A1DA63AA167499CF32AAD9B5D2833 45EA1E83631E0180C513E7C4C444C9784E686E4C66CD9A2A4469E0B3EC50B30B 3993F91C1F4CAB6064A72C86B21A65D9D6CEF69519FEFCBEA3ED42DFDAD95CAD B27B568F383D3C33FBB1B9E3F363F5E6D6ED57F5E086D5CB89776261F191DE62 6F98D1AD7156C83BB25855256D474BADE858121E162461F2F86E385F5078CC55 442BDCFEC14D0C54D237D8249E04C91FDC5D7DC5B37FF3C09C09C4DFBBF82E14 C9FFB037F713B1D7F2781EB67D80DA042AF03C632C2EA340D1C22F594D286C62 7FB3DB584B4BEBDA9F165548F9D45FAA9EF8EEAD4C583BED79DAFA09BAFF8EE1 4A80C7D1D7028376E30AC4E8D4F55E4C45136C9D4DEDFDE160DDA3ADD7DBDD28 0BFB4FCD78047E992C2AC88500B07041D4DD6034892E20ABAB344273D696B7EF F7B7767F67EDE64F9C3CF791AD89EA557FDC1ADF4DC99364F9049CB7B66233A6 D213569120E894A8B34A3C48B01034045485DCD7AE4B46A7EDC77AB4C61AE060 1B9545B771489A350CBAA71547C894F2E35C7C1D6C0DD0205B72E79E82ABBA6E 35BACA543E569288228836ADBC3DEC1F9E9D4F0C9B99C83914EBD61572987450 56BE60240224EB298FA650F1D4061D88B9A7A603AE8CB05301843A43EB0710E1 834D512759BF2797F39ED6E81450B23D25D2BD7F88242A34A360CA3D101FB5EB 7007C8843405841EFA0CAAFE204E5A6DDBEDE8D98A9EB5FCC2F2801D6C87E758 9552BF6FB848A51F50E38F463B9756D54B5F8EBD1931E65EE541CD55AAC247B3 566F4468E2B7BCAAF29E5EB67FE361EE2D41490A0183602C23E36242621B68E9 AD0D766E6F76CE1F2CE22C2AB70147B8CBAFEB21B3A13C83EBAD695B855BDFFC 76D4EB248F9CD4A6B06FDC2D36B2D6479ECBE2040A6E01B5142338708637863F A4A9C945DB4F491AAC0E5ABFF1EA7A76ADF59F7D303261FAEDD5CE7327598BCA AF5CABD6D7A38F1FAB66793044CBECBA444384ACD1818786678E9DFCBFA8FAF3 17D7D756F73DF688E8B6319518542046075CAD221E141B3BE38DC1FCF2C1E2CD 9BBBAB3756E6E67429D2DD2AC2D3544A0DE02051932C0809AE7517BE5A52DD27 16281C8D28A7508CC35387732570CC8C1D16EDE4F1B8427E82035692616B1FD5 057D56C01D547EB15A14B23DFBC48B522C1885465B482DB228EFDA6819695BC0 EFE2FB811D176BDF36B2681D7BD8E825B7736D7D0F2A3325750197047225CFD9 E8F2C61FFFEA67762F6F26B4759B56E1A4DC67F8F9DEE2320FA1BAC3099325E8 26886A6100C10C9499A8B2D96CE25B46A6CA6DB5AC83A3DE3843042143EE51D4 DE34211C174FF82CDDEF271F399EB50B51E55E6ACD3DA56E64EAFA08CD7315AE 15A3F56E854D4FFC2D55339CC03219D1A176632D8AAC1E5C7183FF33455E447E 4B19BA9BE5630DEF1C39604ACA0C4A0B2E02E36BCFBF6CB32F6DADBD70F4D8F3 B4D3DEDCF121CF7479ECF3382B0B81A3141F021C9E4AE473439A875A1D302224 7112084066AE08760B07E48156173662186BB495B16B39F02407CC87321398B4 855291B215A7DB1E4B53C37758253AD742F2A9FE2ADBDAF981DED285F98E6726 33BD16DA82D58B5528D00EC5951721A0B74859A90B3B4AF78ADBBD152BD2C82C 370D3857F3E352B69692BA0D19D6B4B3EA6519EB24BC8DAB282CAE7D95243402 727569599FDA7B56EE40F92768E194937CCBD3ACBC5DA4EFD272187B82061049 791C5FDABA3BD172B637BBB1BDC9995758DEAF8A52E903B349E8791B1BFD1880 2DE129A92A22E766DB4F74718D6237CD5687031BB06E18EFA7C1A3D1EC821F96 A4EAEB3144CE38F69F2D920315EBC2674386008EC4B9A5055A66E910E277107E 4965FF677FFD67F62F3F9C74FFD9C6EE37566FFFCCF2D2CFF57A0B0081E28E44 35C6D242310CB744860192920BE2B4E518A7CDF3B27BD29AF50F089D2A71EF91 296B2246AD0953FB2A12FC0D70645CF3F4DDDD32AE1E02A88AF425E109140CC3 80835BAFB6D653A053B385A98BEC7BB8FEA6197DD5FE7F02973318567E456500 E4612108658CF42A64C14D98EA47454FDB8551703399FFF5E156DA9FFCECDCA1 997CE7664FDE8DC3DD9DFC61AF730E2E4590A51D8272B8D6AF7C9C1524509731 33F629115E44A00E567BDD4E470E720D86A91D47D3279FCA0B3C980BD9FDA14D 9DC1518716AA0D86053CFE1C4D9795AB134BA3729B9524E5DE24F03727E96531 B9D05E3E70375BB17EEAAB81AF43A37B68A3684880C3421BF9FD04E514847B5F B59C5143EC75CC23D2D8F9D682B5D34458E7F2FAA936D8F141C795A91FCAFD15 7B7C6D282ABBC79D71EF00F2951369E270809CEE9A854BAF035600848A84F0BD 36D6EFA19C61F258193D3DA7E6574CF010E10B5A6DFB665B20D7A78DC63BEFDC DE7EF9ADE8FA0EDC14AFF229EE15E05814AAE14AB0DC67F04D0591C947CE8C3F 7434221D62140530E7CA564DF25D9EC7D456AFDF8E594C4ECFCB78128FD78D70 6F0962A087C7035E620EDF43B17842365F7FA7B53CDF3A7900DE69FECA4D2AFD E8B9272661EC618715A7CD50A5206F0A194B281A0B55752E4A3E91EDDF7E6D75 FD8DEE7FF44CCB26C32B6BDD0F9D84BA447DE1B2A185FCFE65E9EB99616859E1 A4690D51153AF79080B5CE1E3EFA7F50FDD6F76FBC757DE6C4A9687F2FE7250F 982DA1DEC41D5BF8A0AAD03B37B6E75A4BBE2AEEBCFCCD7D61E2B130ED97BCC2 F5B154028CECF2CAA83485325256B488AB997333ECA4AD82318334A962A405B2 4C091C7371E5BBCD271422434751EA95A84C6C9CC79490108E080B2762E37A7F EEA167D9CAA942711FBE32F5B1B627859B7A63BBA1726B243E2BCBB5778AD17A EFF809C3CE6384C6075F719F5516BF651B60FB8DE14BBFF4A9AD8BEB44F9908C AEFBD99182BDD0DD778478A62890C806E743D7DEA606893B0C57EC0A11EC3114 EBE653332DA4B5CF6CCD50E032E002775B2981E3443DC057E5B217BEEF805966 B29CF8F0293755717D64AF8F69A61D6117535DBD3BE1666C756B141132F2FEC9 74C7C4897C2A6C00BA446CD15C7E54C90CF96B4C595D9062CCC54CE1C7ACF54E 285F2DB74EF7E6CF49AF5B15B12DE7E1FA0566E2A9992AD41E8304ED21178B42 293121520A285579EC0463328F649EE994C23476420DE381DAA6235A337C9D7C 131A3CE11E02A64DADE0E5498D3336CA46F012B7CAA848DE0AE92F55D79782E8 13D1D2F38078E8EEB86B131125055C28BF0CB0DCC0E705B195095CBAFB0E110D 17979B15ED5AA3C3052DAB8C43CFA6E6D9C21FCE496D6FC41AE7F17A59C2D93E D17A5B1A3DBC21DEB2B454934A97480A65D2ADCBBFA547FD2A2F3C11F57A5EAB DB576AECF39BDB5BEFDEBC836C69081391475A61B7AFAF55135449F77C92CBD9 20EED160371F0D43A1B902581C4BDA46EB794850059CE0EE62E7C8D19516A7C1 A0D07776E249D9D5346EB5A29559D38D629A2F64EA78411621364914A481679C 86B6E02452F01EF89B21FD85D55B3FB1B4F40C097E5F84BF7AF9CDE79766FEC1 CACAB9ED491CB7C61EA01F155A94F03568472814934EF9720FD33D80CC1869C4 CF28F6E0EBDD0680602E3632178B49E313D18027868585EBAE515783B943EF96 0591348F479DBB999F0ADCA2FB54ECBBD6DEDC93AD99724C6D1DEC75BD71E496 013C072A99B3C6D495544529A59CC958C5C504F2AC9651597848FBEDBCE3B77E 7BF376BB9DFC28993995CA3B71FA4762C42AF6BD2A990584B114010609B98FBB 09E85A815B091091A5EFC36D14F59AE394FB5A4F9D9BADFF07F616F66A8269B3 D4B2667DCFD2A97EBA75F37BC83F2E94D7D6BEA80C402A2B0B5DE424455E3844 34FE19B2B962FCE7BCC585CDCC7A366D518F99AE24C808F06C849584376A51D4 6E9AAE434C3F1E44C3A9F6F9B40B5227C25A0061CFAA1E757DEF37451B46127E 76FA9EDD8929F586EE257EDAFC894CA37717162448248630E753D3E265C47820 66E29610225D2EFDC713766645F907AD9EA7C8821BD8721C21332EB2B7FAE3AF 5F1A5FBC9198C48DA791F006401C7780D109078E26093D9457F7DE774CBE7044 F296717C7280FA00DA08AFC6BEB43BA31BFFF6AB67DEF782776636E777A3FC1E EE4BC36976136B775600AA86906EC281DC7CEBDADCE9A37CA96B6535FAD6CDA8 B3143CF2300051A85F3DECF64B83979F395208FC490AAE640195AFD4ED3FBB79 E98D2F2D7FF4425CB5AAAD9DD6779F363B7DF3B9CBDE4AABFFDD339077667762 EB1758FC187471B236831BC9E2F3878FFE12ADAEFD8D9DD76F84ADB999C74FF6 C500F2AE28A4707AD5887E9818DE1CFA9B76E67077F8C6B7CDC67026EA408CC9 0729AE01C28DE1810F1172778C8306114E74111CE5AD67DBA53F4085AE324275 60964B1F09A25C076ED74FE1F7404777A82C9C4A1F9A10FA70A08DEFC37F98DF 1964B235FFC47795341436416D114C0EB92B8D3C9CA909F45E879B506C5C9B6C 5E5A3C7E84842F6893E29A113C0F86161D1C9268DF7CED57FEE0F21FBC3CEBCD 8E941E1A15CAF2FCDCBE87FC56301A636F8261F3D5B5105C5CA628E6865DDFC0 234DC387D4A5F75EB302BB886EBEC219935835635FDBF9E5F92CF0E59CF0CECF C5A77AC372171089D831C5B5A1BD39A6A9428D4DE912A132CEFE4037F2D04EFD 84B895DADA2D8128A70857E1763744ECAC90695E15F0C5182B9D7AD9985469E8 45C8A9E2EF90B116EA39DADE37CA6462829658D2B8CCBDEB9BFF9FADF700B6EC BAAEC44EBCF1A5FF7EEEC6EFDC8D0C104414863980A248310CE919CB1435A15C 234A768DCAB2E419554DD9E5B2C7AEB2C75556288F4AD2A84899435B928BA43C A3A1280FD3104C2040100D800DA073FEF9C59BCE3DC17B9FFBDE6F5036C96211 44E3FFF7EE3D67EFBDF65E7BAD98A212171CF4D0FBFE55D4645443FC8803D9C2 334C328693D5366E25CF0D87E6222C8DFC2F222DCBBC9D9B4D94A80C3207280A AD68E5153EECC4A9CD42C49D2BB1F8B3ABAFEA078FFFC3BCD5E55AD1412B2180 4A556E22D925618CE3B1105EBF01800031029709BCA1D041F675B33EE741446D 9AD10EF5E81A9B24F440C7470798CA5BA22363D4FA3118BC0B545BC508C621ED 4D6B3D36640FC09C9456849846B5C314CCC34B5DBE3BCDAED4D32BF964981776 0A892FDEAAB1BD7BDFBDF74D86A3D76E5D2B2146641C59DD4C8718A902A5398E 31E1ADC40ECD1F6B82FC2E175649E88C1275B1E2F43A8763EDB6851D4AF6D8E9 BB9F904BCBBB139E4D6E0E6F8F3BF9E9DEC263C1C2E142A51A82510A0F709F14 39BC5DC763676EF6DABFF1DA1BEF6EB53ED15DFD9615FFD3E5B3FD88FED6B123 1FCC6947F26142E1617514AEB496F05B2836480EB88F7E3AC7EE28BFCD4CB17C EB4C34A58CDF1068C832D41E640237EB5D365B04B36D439F021BACE12574E6EA 6CB88328A540AAAB6CD63D673B367E26D7E89562FEC0297D631CDB4CD8F16309 AF42471BEFB55A4322D4BA4A725741514E65AB826B516AAA7A36CC68F2A5C87D E1EA1BBF72E4C90F5C2B281FBC7C587E6FBCBFE4ECDFEA1F6A0DA64127540189 044ACB5401A643A4E073DCDA25DC0FE13040375AB37389BB26A9507A8005E901 34A477B2227D33E4320E6A3CAFCF81467044FB3A15574DF14A6A45AA928E33C5 79F483D45C1E6EDDB77AF8FE01ED8E2AB9948C4DD12648E3AD5086A38EA08A48 2051345D8B6681B3D982204CB003DAD13C1136F3C3991EC2EC26B03B05E301F9 87CEFFEC9B69326C365C608D4F87C3361ABC614F49919E9EC6299AC6604748D6 F091221E771211CAC189E1F26327F5C6514557B97282ECD62483C89F025ADA2A EAEF9D1FBC7885668AD8962F33A1DAE4B82ACB8208A24B280CAD892D5CAC9327 8FBBC737B0EA150E825582DC3A891BC39CAAF33BE77EE78BA74EDFDFFDE85BED 0943A6E759E02DD118D4E6D8DE465E7F10C081709BD9E0CAF5E5B7DCAB422295 DBFBE1C5DEF1FB822387A79463D70DA7891572C4E0D26BE169501685B220B2D5 2ABA313DFBECBF3BF9967BC53428F76EB73F709FDA19D55FF949FBF4F2E09D6D 0077BD1D69D3DAB7B83C8BD64258953479E0E8B1DFA1D3AB1F36E776CDA85E78 EFE3C36022E0FFD77E906914D40EE80E38E25BCF5F3B7C347559B5F5FC4F96C2 3408C26252C0DFE722282A05056B547235CD591AD605D5CB55FF5DBDAA3386A7 009818359B65AE830A729F3009F298A5F625A480A789137EC0C3F83E2305310B 6E9AC39DCFDD6BE3D6F187C2B533842C199C9929D4ABC66DEE18A21245E92FF8 BDAEDABD3ABEF1E2CAC935127FC0D8090BE13668C81C914C441D7FE7737FF9CA 5F7C77A98A4D56EF155397041FE68B411A40B512195C14C2313EFC5C81A3715C BCC01E945751118ECCEDEFEE8837362D0832531044DE81C49E83E7ED413E9706 B2764784277BED470E0DD59E743C19B0E2CAC05C9E90A9D23820B1DE24C2CF03 6BDD2442EFFA893C47D37468FCFFF6C81DCA5DB851015CB9A95228DCC845654D 45DD08D71C04D433234C39EA64106D8CAAD429889AF0046294AF0ECA10533BE4 E7B0111546AF54246B90104E7E105B8496D69B54683237A9694082F709F1F426 3FE347B71914AB0A14C010246B8A4A439D945131851037B03DD1FD912CFF68EF EC6A6FE153FCD8D1C9982C309B9280D510874B789F510AB535471CE8A47FDD0A 8A196C88F08344D83CEAB9077923ECECFF0A9298F2FB7DBAF69BF218C901F909 AFC10C77C25B4A6093B5550619450AE8102A1EE350AA2E08B12F6AAACD3ADB36 E5085B284C067DA809DAED8531A7E7F6B65EBB7D1BBE658072E30A005709BF3B 106819030143B9C090A6DBC8898447575B45B8C43205456D684445C56BE7552E 636322A8548919C1715810478EAC1CDA9F6CDC98DCEB82A369FFAEC3E95214F5 501BA220B82E19DAACE2012FE1E318805AD9F5E5CE675E7DED7E117EE6F0C99F 28FAF9EDCB37F3E13F3975FA638A4580FE530AB570474119EB8A00C11DF3CBE3 BE43DC043E0CFD5E96AC710C6C24271D7216BDC280A787DA83E04966BDD0D95A 219FD935CEA5D6B01F611A70399F0EE2CFAFB1398AFF42068DF0C55F2071EBD4 79E3059F781AE5D58606724003F6DA14D67BD6229FC0A1D2BBE20554D31A4519 E0E258238C4A18CD45F09A0CFECD959B9B7BD35F7CF089878659E2CC0FBAF537 CCE629D17D6F9E2E1A52B51D8BF1FBE421832B02612D740E6241858A6C0D15D6 93909B1B3C9723A707B27C8C1EB04A9A443247AE736F278F1195D50D959119F4 1722A686029B780D5946425BB26CBF80BFB5DF59FCABFCCA353DF950FBC899ED 3A904CB784AC7528A0CAB45AABC8B22E97BA8B7BBA5E1E96CC8D4E1A97413797 41F79B5E7EDD95CEA5D31BF6AE9DB3F566ECB1C621716EAF71800BFFFF1221D1 CD3614C60154C9B0DC0BB74A11C6014F8449B9ED4AD20EE953B47DF464152F57 2E8DC834A8B7E11539D1B5B9A6AF5C533FB83ABD328218DD365DE6F9B7956016 F2A90CB1C49090040011157C4D749ED8E0A77BC40A12C04185AF8A4E4D8076D2 C295DFBC70F34FBEB5756BB8FCEE074EFEC70FB2E3F0D447784A43A1EA3AB090 0E350F6341C2F1855BF9FE70F5890772A2A371B5FDD2D5FE038F870B7D452135 0994B42565235AC70CA652C016C2D6DE55046E88BBF2C277D844ADBB8E76E3F8 7DF78C2E6E965F7F7DF5F19393C763B80EBD61E012642522CFCED6F055D0F52F BEFFC8B1DFA6C5E607821B667475D47EF261DD87FBA2420790931A5DA24A04EA A176063FBE45D456AFBDBAFBD2F9B8285B5050583199D492305D17DCC90EE94C 47194094487527E9A0F3B6901C82708989108E2724C23A2CD1484AC7F8CE207C 600494F07051FB80A17F826391B511AE92873684DF3AB4FBB95C3AF39495C71D D2D56AB8263E11A6CA482A21FCD450B3BAC9CEE8DA7716D73B6EF16F5B9B5109 2F10D9CAD2B6AF7DF327FFEE0FBE2C264E54A49A4E8CCA0E1F5AFB689E66B118 1994638A147C5E54A42D24A45AC4B3E885EEA7970DB5A7719563BEA5EF8FA35F E5F100A4B1BA410D8CA851E304FCC9AB48B0842577B55A4F9DD837FB80DD7A23 A1AE4FEB8B433B5516875B9E2DFBA64488C7DFD3EABC7D29698408705C8F740F D41AA80D9D167A8AA12280A0515B53505A08D9869ACDD6F0AAFA92AF00DCA9F3 34926DC1025C10C486042A43C60DD9C4FF408AAD6407A95A0A3FD52438A8C5D2 955770EB9B59DD9CE3CD9B91A8F76DC02CA93113A9DA4A48FC6509212C2261A1 C54E49A62CD895EC2B7B6F648BFCEF1E3EF3AE1F8FF70E21F1BC05209B933CB6 26955061027C9524404B0754A0D698481D6773422E9D2742FA66312C6F778E83 55553742B1882A1A6AFF6CA4EAF1AA379727706D276240F52E757B9C141CAA54 E92DDB285CDA51E0AEBBE96BC3DBD746DA655669DD26D23179DB969BD22DDC75 988ECB6C6F1F6A832A209E03841D56087F021B9910538C40E204B23F490DB56B E417C9CBC81AC08BF896182F206111169A7A9DEA43D41D4DD8A97EF8D0F2A1A3 3659CCD92188AAA6866C4BE3BA8800B3463160CA0ACAD8080D3EEAC9E57EFC5F 5ED98AF3EC53EB1B85EC3C9B8FAEEFEEFCCA91D34F8D4621CFAA14627D18D65C 71787A06430043E61B1AE2D6B58FE638B7F52343DE8441EAA77DA81944660329 31ABE366E68E9EBC31D3B56484DE0144DED6DDEF57343D11DB147F0D40691834 082ABDFC825760902845E4AD30AC572743BE2869EA7462E72F186FBDC6956989 529D165D55A08CCE9551069E283E980A3798A7702259BCE5E46F9F3F6742F90F 0E3FF0D8D0EC85D93783FCC6CECE3BD2430F062DEA32136B03759E17508C1C22 1CC3A1409B49C8CEF855074D483EEB97CE1A1E9C9183B5FBBF61C438EB4DE203 B15AA1FC07DE02BC291445009045A3F1100A52113B303487AFB4F0B55EF6F5C1 F9F72C1E7B70045FA48AD3282DA132B3D300DBD8F0A263438A16447911600BD7 2F347ADAB9A767DB8344E89A87D6D071DFAC153E9F171C9080C8FC9E5A3B1353 9D7DEC39DD6C262BE4A130AE0BA386398F517B87560124B410126194062A26C5 82948717DAEF8113B65AEAD8E12A4846D584E880647CF78D2BD94B57BB9B548C 58A5E02A071CB7D85811A1334D0051560A13E20A72214A76BA15BF6551AC89A8 2424242A94042A4C8A5B52C1BE3AFF7BFF76F7AF2F456661CB65D15BDA3FF38F DE959C818F55170EBD68A0A6B495862A939160FFD54B70B616DE72BA225ADE1E ED9FDFED3DF4844C3A7061FDBC5B6BA650261FFBE29E074491AF805521FC28A9 F2ED5B37BEFDD2C96849D171FCC147B79F7F6DFADCC5131F78B4BC2F28F3AC57 A590A27CB0C5251E4E4AC86F34BA770310A1DA7D97DC8F4797A76E63B573EAB0 290A29125422B0059C4C085C8CB5CC9EDB7CF9B9F5A523F9AD517DE37AAF1541 B99C97CC4EF348A2DF666C3B102EC666D0AD9776C5A678C2A46722694251B4B1 23124D5554405801408EDD2FA1BCEE15A066C87AB89C5D43ECA6113729542B90 3223F8A5135E9569111C8E561F174C3264164C04EE79F52C244AC8751C75ED79 391A5EFCE6429FD8955F302E63312F6B958ADEE0ECEDAFFEDE972757A6BAA2C3 7CCA5C79667971A3DDBE6FA72A506F17D7F9B8B3316463240E19153805250C0F 25605278D2388C9FCDD2B99DD1C79B617A73DB2CF7DD5194D74423146E782505 94A822249DD556FAF4C93DBA5F17D5D234D437F3FAF2C84EE1A21B665CC38BF1 369FE6CD89D0355A6BE8EB8EFC4DDCF1C6F82FCBCA66DAE694A14DBC3125F655 E1E54BF89E0EB7F1680F8E0F24C44ED08D655769C6DD3442B6508F0AF852B380 885A555444010033F45CC67BC8B171D6E869A1E09EDF61985BDE52D2F033E149 613BC84BBFE136B436980ED0382473F590E6B2F5429B7DE1EACBF7AEAE7D2A59 5FBE715BAC8406553B03174528B0C474185A5CD9E34CB09841B863A2C43EB817 012207240572B04E7CC06B47590F281DB4178FF5CDBD6641DEF7F7E1C8A1B37C A398A92AE424EE6A59523A91622CC5AE35BB6505610AAA55B48F34D8390B11C4 D0676BFEEAE6F56B50AC73FC8D5CB34446F860FD73471D74FFFDEDDC7FCE79E3 DA86E11C19B4A36B201214D73A807451A3DF95EF4D2EA4C18349F77D61F76D46 DC4D5827093451900091E088BBB2DCD3F7A61506D328AA110741FA84CF94A8D1 ED50FCF676FDC6FEAD9F3F7D848BDED72F5D5EEF1FFE446BE9D4DE4D994CE098 A626352E988448DB0D6BDCD8848F59AA52D7E8C388E2D464E601C2BD945AED4C 59D72CC4C228E082FA5A5272D1AC3CCCED6D1B217A9CCFCF989533CFD046BCED 40DAA7D961F3AD478F638CEF8B6ABC4770AE4410064834E56CB6C9EE71A5EF9D A2180EC6F79924AA638DFE9BF6358EA15A295255A242DD12EB09621C2DF4EC56 277ACE167FFEC38B8716D67F69FDE883FBFB0317BEE08A5B66FCD4E2E2095593 C464298D2C4FBC294F155AAF413DEFEBFB8280CCF9AECDBAA4A173598879E2F1 A8C98F47D881B717F26D1B128BACE0D778853A8772A90C97712052688CBC50F8 E434CC981916266FFFE008FF3ED90A6FECBE77ED2451AAEBF8DA0472BA1B2744 739718FCD6D32097500CC6B1DF704645432A049292665DE9E6C259DBD062D80C 127A83CBD95CE68EFAF681E49D6BECCFC9C1DF7DB3720D7E3707F5139B24F07C A05CE72DF446A70A0AD3451C8C8411D7A9506B69FBAD779BBBF7955DB43A8849 CEECC866B5998474B7DC3F7BA1BC32E894BD605F84399DAE1581C257AE42AC93 62386A41E024B263759B9307DAE63821D1344A7A0E57013822368AABC86658BF F0BB5FBAFE8DEB71D68F9D1CB1ADDEA3DD53FFE8F4FA23C72110158582B88F3C 6A05F50C0744982C2E93BB160A5BA5D706C5B64AEE7F94CB04EA4C4F6D428974 ECCE7A1F2AE56D4F425D6337C65534CADC78BAF3AD97D7007BB141FCDEC7F69F 7F7DF4CAF513CF3CA2EF09F2D1A4633B5AE69EBF0B853520C2DC18C9C37B8F1C FF5D3A19BE2F2842B3A5B3ED7CF1F1A7A06E2D24DC3308ED0535458DAC5B09CF 6DF2FD37767707C797D68A572E5038C5FD16D44C7C7B1C423242AB059684E924 1F75C687C66C6A8E174B8F76ED8246FBC8D26217CF19DA0AB0DD0021248CBCC2 8CF178CB979C5E848132FC0F8A910A14BD9C54F574C49616DE26164F94750269 44F289A01382DF2036AE456A9A98C1E4F2B34C0DC4A99FD3A9343C681B615EDD FD0F7FF46FAFBD7A4BB3741BF054963FD05D7E24ED2FD5C49643A3BD6D8B3F50 3EC479693EA420A1F0985F39C6016C1394DD7C824267BE3D5EC1B2198A38405C B64CA22A8E383A0D43DC85E0C882E5B8FF8E7BA77A6227AE3DE5E56068AE0EC9 B482B80E3FD55BE62011061775D15D01550A89B72FF06EAF1CFFFFAAC65D7BC0 0CCA4D2A9B432A1381111C390610F9B898C800925F579084D8D8D671C01796BA 782F342A03E266B145BF1E234D63CD80814162C06A7CF2BC6F3C7204670673B5 AB3156C38FC2294E85ABC348241495D7B5B6A8F616A0C2589D31BD9F84537853 7B792B5DFEEA34FBEAD68DC737D6EFAF74ACF5D18DFE4ABD85CC4881E5041A4A 502CF268D81806E1EDC735BF66458D35DB0E78EF1BE75D88D79EC0608DAA702B 038B03AC0B20EFF989355A59C3F7836C222B4634441931E26468EABC568571E3 B81D28C8C296E525546613E2DE2826E7D4F47555EF20C421CBBD147ECE39C5CB B2528D872A7A2F62C0F7AC795F883485396A973028FAF16936CBEA5E368113DF 4ED13813AEA1168E43528E7BA57D22221F5C5C7F2A5D5825A40D37926B1B1103 F5ABD110AC2100E592D668D184923CF804AC81DC8C06012442E591AABA1E447F 34CDBE7B73F3FD0FBFA5D2DBD77F72FD13A7EFBD2F9731A09FB41282F5740099 2247B90716685663A9CF4B8D132B28BED3120A24BAB7B8F89CABC7ED7899D223 A3E972A10C3C9C585618248542CF02F878B68576083A0982A422A2294850090D B98570EC95ACEA842B4B5313247809EA3AB40A6A7F03010FCA0F8ADECCF0004A B4397111CEED3509002C43C26549C4DB21F57D633F006F24AE9B7E8A5F61C674 884D2DE4FAE91A8A3A5B6B56C0B3C6468EF21028341C8ABEA14CBE3ADEF9DFAE DCB8AFB3F1ABCBEB1B6CFF663D79099F6CF0B75ADDE34501A14476432B32A85A EBB05B1934F3407337C86106E5402D6A8F421942CA18191E2DA83C7036E4CA60 46319A371B3D89C46B3558EA66D912BB4A66365074DE4A1ADBD00D4308B91A54 43AD41745EED4F49A2F4F958FCCED6EDA327CF7C82464737772B494DC4A3AA90 61080FBF6B9872257A2185A108392E3130643813E147E26CAEE78B0C103B5F15 9F05A6A6E139CF7433FEAFFF2F4BEE90BCC96CB43877669E2B52C0E1162A4648 191BD4F04441F0AE082291866915DBE161DD7E5B9F1C0902D5762CE4F0864B4D 06B9DBA9DC9EA5D7C7EAEA8E9D1AAB5855E0BA421C96A853124606F21F8E0871 FE474226DB325E6FD34328484D23C297129EC468E4512B48C535D4A217F4E667 7FB4FDDCE6B5FDE9C0AA8576CB646A29499EFC7B8F479FEC664BDB79A5BA7C5D 4C433B2A2683CDE4C8218186EDACBC71C9842BC9EABD121325F3A36E7C6EDEFC 8B1E94CDF8B50DBC955C055026EAE1B75FEA4F540D78F5D1BB377F7CB6DCDA3D F6CE47EC5D5151E76963E7674B842CD8B39AF08090D6F1B58D7F49B3C907519F 7CCCB32BE3F4E809BBB6985305179943BD861BB0685C09C79CEEB3ABCFBDD8D7 AC55DAC9CE2E8DE1CB266677C20B000B2C77E8AA8A54A9F182712A6BEDF71EED 89634145CBB89DD8AC8032108D3605D312C231EE44607B8E98F9228F27BFA104 69881809CBEF00B5C1A786952BE9E27D243A0A7795898CF2716D2B4B3BC4F690 2B6286EEE60BC3DDABEC9EB78B850E443079397FFE0FBE72E5D9D7A11EDE31B6 2CD571913ED85E5C06F4A42078648CFC9482111660DCF7E4FC42A39DF1AA6B72 40B09EF51C660A0E7E9B11CB4CA81E1367F238AE9204B5DD6C0D0942014A580A 16DFFD60AEA67AB76E41229C0EED754884AAAE148A7A12E225C09000D2680561 DDAC11056216443938EB509214C52C26F0EA6A84E41A17A5FC828A315ACA890C 6595779CED30DD9174A103A8A661B2E0E88DCD396635AB9B76197C012170ACD6 48C6345A9EB38B85780FF2130017176A4481259AB83B56A37FB741DD230A9992 57A64DAA218E02E2DCBA1D16BC34CCCF6EDD3C76FCE8F1E5A5E2D6F523213BDD 961D632AE11DBABD8E360E1242E456BBE60379A99A86E5D8C83B368D58EBFD04 7D3482F30C18AB7275D5901D85B6F0C1941FA462DA02C45B5364586964810ECB 6AAF2C2AB427101738CDCB4AA6299348140FC228D76AABC8369DB95696676FDF 1E68ACC1B0FC42F4815DF0C65A6926E16DE78B5933394E4F94920C8A2D695D42 E0FB8831000238201132EF640E1186BEBBCF1F5C5A7BB2BB7AC6B0B5A28E6D55 0B350DEA2A866A18FE419AD424B5A2C21FE3CB3E2BBC2400BC195C2A815A36D0 566873354E3F974FFEFDE55B4F9FBEC755D78F85F2EE2239A9C23830B66D42C2 DA167E98AE90052543C26BA7CC44543C1C0506C2548A2738D8822396B677F776 E1F11710563BB10364AEAAC5B15AAE9C93E14022733CD03AB16631903160BB50 9401ED02608003482131D6A62A222322D1CA38CDA4459E37204BCDB988A42B90 8288F8450448C5D715A40BF42FA13E48C08F863CC66514797F28D1589F114F6C C08B83AE58B6D1C0C1C1A4374A46556E654589FAD6257C41B4F1628BAE535AF9 4637FE4AB5FDE5B3179F5C58F9F46A7FC3DAD7ADFDC6787F25483F14F40FE785 6959DD832A9D4DC665D459A82C14ED589FD6DCD512AFB2F4AA2515F6C879ACE1 03A11C76ED3BF24D898B19EE4DFF326FF29DA266AEEE70A715AF1B3D77A2303E 39EDAA52E5056D8FF2BD5EFFF755F5FCF55BBF7EF7030F8CC79A1B40DF415946 0297A0138C7CD67B42B93009C2141EAB2D6D856C113E532A17BE38B53E113626 E48DACC19B12618364E9FC8CDA372F0EFA80D628211CF875129C08C2B10D70B0 269DA481A852413B611447861AB544A2477BC15BE2A1D85FB0278DAEE1D1E84C 93DD926C55F456A66F8CF5768E0C08CBD1BD86B3C842B2A13C8CD1B75B480789 503A9E8AB02FC395D0F6781DD6B21D143DD64AD31A996A1493960A76FEEFD747 7F71FE30593DB7B9F5FCCD0B244C96D355B95BDBF5E9BBFF9BA79377C4A87B38 911DB9565EB935AAA62B678EA1634365F2AD2DD13B4A3B87BD3F0AF5C5823B18 8E92D94AA5979F87884D8B9CD61171D5D90BE2CA36FC6AF9C089EBAFBCC4CAF2 F03B1F354BACD2795263F3B9B63913B1D342D4155C26121FBDEBD8EFD36AF861 87D4BAC4DCCCA6A5ED3E782F9C241453C76400984061300CE19374ECB9EB7BCF BDBCD25D980E87769C777BBDBC2AEB7119D748682F7089202419875AAFA42373 98F71E5C676D5A26759938A9CAA4F46288516A78889434D650F6CD8C02817D1D 6CB4D45EF39647210F24A90B359EB2E4B85C79186A599F37E1E142D2E1CA483F B61FD3E1C5CD4B2FD3F507568FDE63AF64AF7EE1BB6FFCE58B01EDECE87A0B55 3F82B72D1F3A2C645167635AB547AEB1ED69C82FCD4620C660E9FB249C35D332 AF77F0D3662894CE38A4F3CD24546C71BA886213250222231ADF519CCFF5C5F2 FB1FCEABBCB836EC66B22A26EEF698647E01CE9B5061C50C71476BDAAC92C3E9 B2DAAB4AE08237D186D606F7080D1B15650939082D4EB1C06AAE26DCC2C292D0 D60B9277856D05ACDB82AA0FB205865A2A9B513912130A00A832E0701EE71CF7 6645E3A0D9D254C65A70597B9769676BBF46E5D0EA1E374B6A87D018AD4A8D4D B231E0205AF061DA7996F32F9D7BF1ED87EE7A64A57F76E7D6DAA195F770B6B8 B53B4A164C1B430EEA3D437496682EC1428929676662D8D4BFD4CEA4F61B4EBF B702D6681F880CFBAA428D74CF421435EE42E55E8B0ABBBA0AE28F9812332E00 1B239D1D1BEB819808F29A569747C32B757D4D9713419334594DD3051E044C6C 4DAB57F687BB41A4386D4F7695439969E27D56396214B80A80892D7A3810EFC5 6C70828E9ABC33FA244478BC5610DE4AC019C2F62AF56410BFFFAEE31F4ADA01 EAC7A38A5480D4630C27D84EC1262097C40738E36D88F0AC5974678257651482 2B08C92E0C707468AE26E9E7CBFC8B172EBDEDF899933C3F9544D14E71427622 0B7524835F116A0FD7381AC67A82594E0B38FAC10DE66E218BD8CA28E80AB96E 6532B5578BE9D9C4BC6246CBDDF4B80DEE93AD6498C3E335328422264EDAA454 4429C8A88A2BD9096BD65AD3659F2A2861A50BDB531154761CA9410F4D1EBB15 4BA128C2158B2A9012CD94D07F19D080A8B038A521F5A2BED807464B5B000EB8 9C164256C2057C6CFACF8CB0ACC73F5EF6130E195E028440A1A2F01074AD32AB B0D95DE82463814BF784D8EFB7FF6CF7E2972FDCFE3B6B1BBF14ADC4D5F82B62 F295DD9D67564F7D54045CED4E7AA91371CBE482A82A68A75EF26112225D23F4 FBE30D06F5B41166B04282F84AE85CA4E180A7D9FCCBCE44E5FC7F3589D0F302 AC6D08C9DACFF8E1F460CA825B5C4389908B3CCF26ADF66B61FB0F5FF9D1BDAD 958F6CACF7075B11263401E808E28A137E208BED600D7F1DA6217C7628851CDA 00F8C6F62C89316FCED3D87CCC97B5DE243A78C0DB6BE6E4E44D59B09913CFF6 690E3C99E10F62160C990070449A057F28535C1A4CD322BEBF953CD8278BBCB6 4AD63DAB4D31C8CBBD2C9C72BE5796570776A7E480430C9267BD4E0927120A09 A8A821A4006E173AE43662C142142D46A4836447A804652BC897C324845AA084 B410BA363D3BBDF4AFBE19DF221D974E6B7D65327A696BB312412B6D25A266CB D907FFEB8FB51FE9917AEA46FAD6B5EDEECA526BB507F1281B56EA46B6B0F180 69B52D0027E48279D695B594CD81F15CADCE42E86239948238B6DA1995DF7D99 D73A7AF0F8C5F33F89193BF4F647F20E361DD2DA61B700B71F03C053F03AB4AA 4DB178DFC39FA5D5EE47709C43223AB2B7AE6DAD9D3AC39716D1DDD4E1BE2294 0EA80C16B1CAC94ECE27DF7AC18CA721A5D5E65E12C47528AABC0AA7367290D3 094F9350993C9F9818EE6A19DDD50DEF5D524B2E1305A1AA65A8C405401C1D22 65C34BAFE17CB8519BF0EF129B61D842871B175924BD8D04DF9DB805DA3D25E4 D1B0EEF3BA45F001472A26B5C8433A146EB477F1B568B81894F1F35F7AEED6D9 BDE9582816EC67A3B6D56F6D2F3C14A7892A0B574E00ED94319EB8597D414C23 0B8E732484838D778FAF31EC412274F329826F5DBA66D8DE8CD290432151C94F 60FB51435AD69CA8BE587AE6A16995951707FD3C5455AEB74724C36E27EA5EA2 00B1F5847EEDC3238E8C981FD620FF492124F2AB0BB86232C8AA8AC98ACBDCC2 5B43F5F066900149122EFB422CFB218FA1D40B00F3E1C0C636AA378D14192548 E795121321F31388466E644E999B094542EA113C42E11B830E5D501369272130 019846E72F8A94B91A79A394093D1EAAB8F5ADB1FEEECED67DC7EF3A11C8D1F6 CE423739D30E0E4D8A368BB258D629A036480288FEE1F260F39F23A5C533812C F7108CDD893600D3BC7AA673000AA08A9C690B183B93B8C3C51254C7E6165D53 B2DA0EACDEA7649FBB9C0164C535502863201D4294878A625F55DBB5BA5E4E2F 8D87BB45D90CC521A1E5F0AE71139DC585560477C4A8D7F99598E1E087488D02 BE08D988E7D00218E4C64246ABA1D494A8B18421BCB46B9A3C12B7DEBFBCFCF4 C2C25D84AE030C27A86F62436C7F411CE7811FC5B866AECCBD34381626F0F1FD 9E0CBE190C8846399F08A546CDC38B71FC2779F1854B573E78E2CC7BDB61BCBB D395AD1E117D6612A8B3F17AC2D142916048BB18E1840268996937B0C980467B B6BA996F6E4E47ADD6722B5A4DDA296DEBBDF1F5EE4DB5332827EDAE5DEB2F46 E268562C55F5A4ACC65154B75A82D1D5A25EC9EA4B0BF5E1AC5E544EB47A55BB E3EA7A9954899EE01E3C8D2A5C058304E2B0C160BCC633F22FE016A2720F40F6 1863242ED5D528DAC08DCC91A208158887E68D54BD464E1C69660AB8C38502E2 9EC2A56D845BD2D823CD5D551944CE61455B7558295728BBBBD6FEECEEB56F5F D8FDF4EAE95F9041DE219F25C3AF9FBFF9E9B5B5F7C5294FE3A213CA62774157 8AA55022949CC01DF4D35C38FFD88B6F6147948E635A034AA31CB7BCF8ECF879 1EED9B54E858B30CE2AB64BFE9DBE8F735236AEC945B2F66E497BF1CDAF89800 62A6D5D3BA0E93C56FECE77FBE75FE230FDCFF3E5DC1532D5C240C8528350D34 2EC0E1A3C00240480EA09084AC46373EBCB0BC99D5BB59A93A33129FFB2E1DB4 AFBC7CCC0C15CE3C34DE24D8ED678273D952DEB449211743A0486D1094292129 4F824806E128AEF419B9FCB756D15E098A4BDED27BB929EA7250B0A98B725EDE 1CE53786B2805B812A2606AF0A86C73215110042C03B22408D9790D9B60C1763 B110A0D754A86C68792AB37E90C44E41E463BCBD934E3EF7F2E41B573A32A9AB B213B4322ABF73EBFAB9D1DE34B4C73AAB6A6FEFD8D31B4F7FE6A9F4FE747AED E2F6B43EF1C0FD35648C90EE5D1BB9DD68F9EE474CC49A75208CDB0DAB6ED64C 62F3F5558A453B84040821DC844539FAABEFF3DD71F7AD67DEB8F6463B8ED69F 7E68D2861C6912C51494700655465C59D380A989DD7FDDBDE7235FA26AFF9310 89D07AD1F2FD1BFB214B3AC74FE900259825A0120889BC56C8CB91A911E6EACE ED677FB81AB769560DF706ED6E0FB7C3C7654B49381C652C630711BEA89044AD 444FB013ADF078C7C4B6C25D7592C2F9ACA08E824F10723CABDEEE8FF994D7A8 B860F92104E01AC03CF8AE010E4E5529F23A6D75CF88F008618BCA06BEF70288 AA103A23D968F0FA05F152FEC68F2F5F7E633836C924ECEC8EC6647FF8587FF1 89A595563625451642A65290579246C9C4EFB1CFFA83E82921BCBB389DE12476 A06E3B4F8407A5C79B7D3219AE9A85CDBE3F812FE509CAC5025BFCC043E37CAC CF0F978B685A4DF4EE84A22B7D53F035EA3E9E9039970D633E6033F87785A21B C4B7492BCB0685AA714ACD728049B8B60719C5C0FDEB181308DA4F02EC896293 CF4B69434A9DE9D0E39783A35BC75E14C4DB3BF83D337267DB8CDCC1BBDCBB63 4116AC305CDBB482A8E632E700E2D3CAA519811A07FEC1ABCE0D1683EF0C77AF ED4D1E5ADF58EBB5AFDCBCB11AA66F6FB7FBD9C884814AC280642696508162F6 95283CEDBCB1F8ECC1CE290A0D498ECD2431B4171940CB1BA3503CD277FCBD69 02064C8612FF9506980A6866687406415304634A375D7D494DB6AA1277CBAD70 410C993021BCDDED96A1B86ECA6F5FB97C1B75833CDBA5B19EC75F17FB85763D 332A68D815D888C1E55CE399BB68EB1D26F09C0514025441C081C3DA12E4C1C5 D6CFAEAE3F1DB6376A9D1805E547CE4D138A984F945EB0D5F299E111EE416B0C 6D5EFE058EAB41296E8485A6E68067A1E0F13342A2EAD7C3E04FF2FC5F5FBAFE F3274E7F9041950C98288A185FE5AEA533A8C0A11C86D21C37042C0F917A843D 1DA604E0CF8CE829D7DB9C9C93E2FB595956D40E070F2D25CB4BC9C96C6DB32A 5F27E5053B2E86837B93CEA96E3791625C97D7CA69C1C97DC1E28989A8E55658 473C5CD8A27CB71A1F0AEC69AA9698A54932062CAA39D4A40977B19D181E9634 2A195AA2715111977344C3009F23EA024A71C5508BCC503FF505F01045220054 C27DEBDFCE34DE7CEB19977BA0C6D2E81283336083A501BCC6699EE35F4ED482 480305250EB910467F91B9BF3CFFD2DF3F74E2E7C370109A3F2593E7AE6F7E74 E1C8BB5BAD3456289358550001AB00B531624D5385117E1C02C8672DCF08CF70 A71DDD9AA03E6BAC179BEE8E1F8ECC50979D135C7D9FD4EB2DCD7A94CD6E8F69 E0085A6EE1BE38FE9170646E5257E5E5A2E257170FFFB3D75F024CF0EB1B2B0F 4D2D372DC856815013A9022D11AF6147CBE2124004719868DF844035BBB9490A 614DFB6FB6A935137DBDA3BB4649A38333E335DCE158FBD8C99A0AB751C56B76 4820F4072CAEE3A068099AC87610D55CD5A782E8C95E7C22B610898B408DAC1B D76A5C867087272EBF0615D4804C4C40B0869D09D4A1BE101F7482948A180E01 947B929711218B4900C5780AC8A57691413E75CC758BF10591F3691A2C655FB9 B5FFB99F2C0F432D746D33C8208446DB4CBCB873E3A5E1CD56D8EFD91E17E5DD EF5C7DF86F9F3EBFF5D289A71F111B4BDA2878839B2FDE585ABD9FAF1FB1E26F 28E9B86662351319F04FC760C72513C695A2E24AE55F7B9E9CBFD97DF0E4C5DD 6BAD5E7BF5671E98A61564F5A8B485340032204291BA04FC536E93EBDF197FE2 57FF9AE6C35F881DC3F91304D7B1CEAF0E7AEB47CCDA12BC6E092537AD8DA8AD C393E5E0B29476F75B2FB406559C24DB576EC60457CA8BBC8A4A1A3A91638F51 B78244E5D37D92B78F76923EDB23C385BB376818C28BD31205F925629586A037 B7B86633A128FF0E118822AF90CA1A671F36A8501199F14EDD5D2BD24591F413 97909DC29DBB36B870E3D6A59B3B9B7BD15E3D9C5450D3EC190E50A09A6427E3 D6A38B2BC7D3D44E512316DE2BC3BA74C654460B0CEEED5E913B805AC3DE8177 DEF9B4EECD88903602543F9D08D1CD3540DE2B47835003E50247F906592CF1FE 330FEC0DF7D91BC3C5A91C5413370124EAF7A8AC9F319806209146D550204644 5F3DBCF48A78362986CBD29051A54B2A330AFFDBD66CB6280D6549DFD5DD14EA FE20099186A6E1DD0888B168ECD74C3271BD58F03AE05EB1813452CB77842289 970F9857A16981622D25C4597839CAB6D000DC66485EE051E6E03FB682046D5F 590BBF31186F55D553FDF6B16EE7AB675F5D585EFED0F2F23DA58154B4139BA0 455B28131E009E871848BCA09EF564D4C6E2A721EECC5A3DC8AE27DE7B496B40 020A774B002EA3C30D2ECBE364C9A05F1582B24C55136B4A47146EF7636B9879 ADB15D4E6ED5C5D5C9DE8DE9F4A26075ADA7E86BC510C7523984BF0E65891D57 7445875B6D2C0E6999EF8799A6E9C9676342C010B2A65E5A01EDEDF2B044D10C ADD7B47E8425EF5E5F832C78B84D17024B8B49006F211080E846C2C5020D8E39 546716439A86FB88A41A7E2084E58B736F7907111F79A9F07215478D15F80CA1 C06E70FDBA909F2BF2CF5FBAF19163A73E46E89AAA6ACA3A69ABA3A64B807571 4F1C45BA15A441A8B951A050E5A4277912D1A236FB43EE2EBBD6451657290039 40E93BCFEFED6C46E18943A74FC7EC58CA62662F6EEE7EF7C6D690B387EEDA38 C648AB1F3F7BEBEAEBB7B323FDEEAFF49777C2D67383C11B7B9B4F2EF43ED15D 690D86BBCBE9F35C0D46D913A2FB561A2C94A58DB32A8C4734C90C09284B8416 28644EBCA3AA14C899D79240DD2C4CC3BFC4681060731A4D2E67FE0F33D76C1C 552290677AB6B3E37C62D1352A6D636F431B28B55B4602EA4AF8C2E589F83D35 FADEE4E67FBB71F2833BC30BDDF80F22F2F2A5EBFFF9B1934FD1124A181D8410 87343A7BB148E1532F39559801E7D3256FA886DB4B286EC40E2CA81AF6ACDFF6 9F6B07F8F3296CA3DB4A677A2D7855BCBC914FE1489CC59A068590F7A0F89D56 EDA9BA99F4FE54F22FBCF1E22F9E59FD38EDAC8D439C7BC85AD122A468458163 3B5C7674285C075944629043F698E71ECCFD24A8F11ED56EA66640DF6C7DC5E7 D2A9334BE4B9D0B9FF936C9638393B68B948F89491ACD310E2B5882319D1B297 77DFB926EE6F55266713C7723ED92F3B5389CAA0B5D0D7867BE76FD1A90B594C 9BA62D6AAA382F54C0C7BDA8C5824091508636A0554CD9720BE12084C1A02650 8E8496C40C8026E98785AD932D79FB0F9FE72F565DD22AEDD4891AAE969DB88A B07D6A9FDBBA7633AF9378A52B2346F697EF13F7FFFCE9C31F7F649C94B8A378 69525CCEDB6F795CA7F11D436832AFA51BDC74474797033E700612A129B8C291 D773E7F40F5F6FDFB572AB1EC8D5EEF2E3F7E77145751902D80C5C625090C110 28056571AEBAF142FDF1DFF80A1D8F7EB18DBB49908579E4C2F18B5745D88D8E 1DB761883B0B983DA1BA51E86614F31AFEEBF6E4F2579E5D8B3BD2B1BD1B5B2D 1663DBAEC6C512789B79CC3AA8F0598ECC98AFF3EE99E551B1091179E9D82922 A38A15659849808EB84EE77D7499B7BA683425D9CCFED6870E6C1CE6321A87E9 12942095294719093B41B4CCEB287B6DF7E6B3E777CFDE16753AC5C556564CB6 4B089C446679B9D259488C5D1672354C025C5AC2D402C8958930ACF2D92FC019 B04F71DC1B987A29293B57BEA4F60E229C5722078970267E02A7B0928ADB0832 35768F792D03B8F661B1C8FB1F786067679B9E1BF686745F8D5164B946C59B66 25DCEB6BDB99DE87F56D16EF060B053141AB2088E4123E6C65E9B8D223654B86 BC7B9F515098069EF27A08C57A08B107D5E138C5A04C8CF6BD035C73C6292AE4 4151F299DDB607AFDC352E338D57834FF6D463C456692AF43BC5850489701025 73E1C701BC85124455668798A130FF26C8A66FEC3FB97E6665397DF1C639CBE5 BB8F1CDF980C799D97ED40B7651C8814B27980D6BE7845BD5F956D2CEDEF8C5A 99F5BF97371108DE187A4296804443CE2DBC291C34353462FC93B5221388F444 4F002AE34F9315E063F893686E20D16F14429EE043672E27E64651FCE0C68DED 0A725A40146ED74A782FB641F790F1B0836CC9D42FC7A122B19773448159E9FF 365224D1C32B222C689B3DB8CE0F745A1F58DF78D7C2D24942528D0B9C35AB50 8727148A51146180275CA30C13948880C7EB46A00045AD30367174DDF4960DB6 29F90D37C2CF9C94D406BE5AEDA4C0AEA07A4D467F52667F7AE9E607D68FFCDD 5EA7BBB317A52D69C9E188B56C29FD90260BA018B291F1F3197836359F502324 81727C44E9EBB5BEBD335A72721AF1ADBB8FFD684C7EF8EAD571B07568A8EEEF 86DD5E9AC5D1344C6FED8DC75BDBB676877AE93E24FDF5953DE7DE71BDBCDE92 2FEFDEFCC0C3F7BC838A433B1904F76769FDC2DED6BD61F4E9D58DBB2BD375EE 7B4792F1E6765C952792F61AC4D712D7CD6D08852D8AEF31E11D6C7158834A6C 8DFA8C76FE650B16A61152A82023FA5B66908789D75DF85184172BC25DFB18DE BF56B903DC0F65824BACCB294D2AD1CF926F25ED7FB17D79D1AA7F922E6C4CCA CB87373EBB777B73EFC62F9C3CFAA4128B868C3B258E78702DCA150095E197A2 B618AB71FC4F908327508C863B3953C340FE216FF6EB7D7F682E43E30F2BC745 7BE7AFCB4128C0D628F165ABA7D361E654704F70E3A08CB4DDB5E2FC5D47FFFB 57BED7EA069FE9AF3CB98F4C8369827E9F10EB1CF2A23956CCF0F60144751228 8B74C38EF1EECA7EB36226683E1371F5BFD9F85ACACF6B66AE9C3F95086711B3 11A86FB4D966069F486A82679A70134744B65D1A17ADB2F578DA7AB45BC78A54 4C4E65B197C3FDEB0EDAA8BA7C7B3CBDB24FC6566AC81368DF66FCA216F68B38 2E4454691BCA3EA8928340988857000F9752D9C6E939871018BB3AD42C0E6827 AF9228311DF55757A75F7CAD5D76344ACC968656503C88CA910A0D4A760117DE BE75A5AEA2A8B30438894D3EF19B3F4B7E7E75BA947145F2EFDF5E6E1DD1678E EA28807FA459AF646F36C76B884B4DEB180F1B9CB58CD790DE4B0189F5952BD5 B75F6AB5DB6356D487BA4B4F9C29A5A2E817497361A068D70E4AEF3C5551F1FD E1CE8DCE07FE8B2FD23CFB4F63EC44D505EE2872B1AF0757F77B474FF17E17CF B5ABA56723E31A78C0A6B64A6430FDEEABC5D94B6BDD95E9DEA0DECBE066D6E8 17CC7A3618270C10C2221CF92A1BD05D794FABF3E8E9D1F9376898B436EE42B2 5EE24A3282300238D3971C11F120C0B7CB911A0B076556DE505E703910F06883 5EB8C04674786EA7BA3419BDB65BDED6F5946B134E4B572857691351BD20C345 213B82E326ABC3EC044F1E891E16DE1D32169195610BD43EC59579EBC54970D9 CD7BEDBA195BB0694637AA0F3F65213D638D3633C24693B08C6A408509D44290 452084E26E1055CB72F99987B76EDFA4AF0EBA6336618A969A57B8DB306347FB 352A6C76615BD935133C5DA13C3F779E4C803533E436365180846D09E0CC1AE4 A9EA5A4AB6D269F724264C6CD0708B858440A510F4A942F300E9FB919877EAD9 961866C126E759EF613EDBC96D261F0E2D809BFF17250AD0E3169789C39AF3A9 81937BCD96B75276DBE52F0DAA9F93BDD3BDD5BFD8DBDAAC279F5A5FBDA7AA54 68B3968E22C36458B1560CB71E699D7E12C41A8D527767B57986C4BD622CE006 ADEB1C0A47850E1E0D62C59285A371B4A7D356553D069087DA37CE3725D8C0E8 6BA4BECAEB9BA6CED1B54320B0D024C1252DB96BC90B5B5B378B12011912D6B0 E068A498F1817A25636F5A3153334635206F748EC40D783770D08D4661A380FD 4749F8D4EAFA7B56D63670BE35CE009373C890580EA3C737A73620E8BFA32B5F 18A1E814EE9E208781CDF97D28B04E678B920CDFB4A959CDBD0127244278C870 47D15D1D0EC66B22F85C917DF1F2CDF7AC6F7C7CA1B7381AA450F4C9B0CF5407 A9850E8E4B018950D208DE8B0E4A4E223784BB5DD9A8A317A108CEDD24A7E545 5DFFF960F802E7277B773DD559B5FCD64FAEEF3DBB35D89624EACA87BADDC716 56B4E55FFED1CBB90820189C5ABD2BEDB6CE5DB894CB6AA39BFC4CDCBAAFDDBB 5E555FDBDCDCCFCA0FAD1CFDE8FA61B57D55A5E194D1DF99E61B83AD4FF69377 A471978AC286A568C1CD4A20D788C2E10085174C2468034B708F81C2BDF32EB7 F08C04E311BA58FB8D25FC4F29F069497F46B1F103305CDBB4E4901A95ADC750 181AA82CE0CD409CB041ED42B2F4231DFC2F175FDE586FFF5ABA7CF2CAF0CA5D 2BFF6CF3826BD17F7CE8F863835206662F501CE75738C8AF50BF0703642590BB 1478BD698BFE0BC2CDF5A27CC27073E729DB8862DB86D48A3FA4518D3EA092E2 56A4E73C19EA8D4D20A4E4A6EC57919998619EC13FB99BF6FFD8E65FB8F4DAAF 9CDAF874154725C95A510CE81DFB5B78027DDA558C530141AD1D619B1C07E08E F399B84CD39B6DD48C0F46304D186207B2A2B3194763DE7240ABF112577466F0 89A65A700D655D0738930CD3CE3474F481A4F78E25D22B543EA5234EA7C2E480 A2B9B8ECB29D41BD3BB57B2AA85880FEE71241AFC4B201A941A8CD4679D4ADB5 42881DA3D012ED45B21F052920206F400CF9AA2DA19E66EB654C7BD58F8B9DCF 3EDFBB6E24FC08C99C422E61419456059450C232D7EADD52D9B76F5FD8246239 583B6465BCA19EF8ADB775DEBD56ECECE5578AE563F7A9D585AAA8521C3F51EF C5CB0EFAC4737558AFA58BD8108AE20C75F9439B57D3CEA452DFFC51B03BD9B6 D3E88953ED073734C5B13AD4AD15AA1CC89C2988D8ED2D553EBB6FD387EEF9F4 1F5093FFB2DF9BA971CD1BBEAE22D9A5BDC045C93D272701151AF227F21971B5 B8CACB441A4993FD72F28D1F9BEB7BBD4E6FB239888CC850195FB4AD1C86D87C 886B28EE4CC5C6D35EB5F4964364AD35D8DB56C6F67A8B512B862245BB214551 A400E382F5DD01AC99FC82955F5D40D56FDC150678D19179505C55FBE7C67BE7 87D98D52A8B8CE21F743C484FC56479202046D85BD95D2F490B9A632807F162D DB4288B15087E081B6319A5CD371A231D3A02801EE1EFBE910EE7EBAD990722E 4C6F0F24FBDFBCB1CA9ACB4367E2FAAE0AA16E0D230A1588D5520312D210010E B517DEF3E0B5577FC25E1FAFE8784C4A78FB0205488C77046B6C3F7D2758E34E 2DEA410202AB14A26ADF2F44F618157072C6A5065C58E29FC20C19700AA82B0E 782C15D67F1C39EA506EE380D0CBA841193393716ADA728C9399120E278D9069 9301DC5CD9B05146A6A8012F14EA1C6874F640037B36D4905A6F3875A3236ED8 626B347C9B3C4D7BEEECE4F68D49F558B2FE5E89838029406CEC0098108A4FD9 29482C45EDF735BCE9EEBCB13C1B6934F68ECDB945BE044A3003B6C13EB9462D 72B86E80A04AA5F35229A4AA1A806F25D44A06D9EA993113C6A791BC5595576D 7E2ECB2E293511BAA84948C91280358762F208EC082950F005C0ADC7F4D66F75 93597D3DB3D26AACE94860BC081D04A3A0CE8E4BFBD44AFAF0E1E50FB71717AC 6B43A231D934ACCB38702C8C00FD23FB1015D1116BA0DD1AF18CE7C67B883522 0CDCD38B715AE837D6AD5F3DC5E70C884E7BA6A0AD0594420A823513B5A98BEA 42147DB6CCBE74E5D63B560F7F74B5BF381C2CB8A84F832EAF13A8CFB1A7478B C069C92205DF4AE6A1436F8C2A63D8736BF5264CE4F5E505F2C79DF22F2E6FDE 2DFBDD6C3C1A4F16177B57163BDFBD7E637171B5866C5E4DBB00BC8268ACF999 7B1E0947EAF2951F0BE26E4A7E7A636585B9E2EA662DD22B6817CA3E75EABE77 545A4EF6AEC5F66B93D18F07FB3DBBF491B5E5F70BB562C6E3B6DC5A58BC35D5 ADBCBE2F64EBB897A14A11A0F399F1520CCD936E445D009F21DBCAF1508489EF 253B378CB0571129D4BE816F58FBB4D95650D9A08E5F61E100285743C4823042 AAC8AD8E21502CFF7155FED1E61B7FEFEE33BFB457B40CF97F1693DF3DFFFAB1 85D6270FDFF5DE8CDC0ACA292BFB491C42DDE209CF0EB52EB0B907B54484E206 24C726EE5C855BF80D57CF86F15E1E98FCC8BCE7C6D16D036E84F5B7AF11EFB4 8DF1334ABDFAA64545AA854C984AEC96559067326A7D3189FFE71B171E6C05BF D65E3A3481571EB4303C1BFFDB384AD63A4FFD12344A03DCA6613875F458C7CE 3617E788B0D137B8B3EF3FA7AF3789702EFA786006E2D1B577666E8C4691841E 575CB4E308100ACD0FD3EE3347F80959E50339ACE8883A2558C5AB61662E9793 DDA11B433CE3910D190E08A8C11BCD903EEDCB73082D118B71BD2B80988B242E D94FC26E84F08B29171000DD15C0C8381287B43BAF76BF7895BE3469D70C850B 71315BE05E20D6FB05532A423368B471BD60273F1C0E4B95AEF305CA27DD27A2 0FFEFA87C664142FF4E5EA618545B587EDBE7F8DCF6FDE5AF2EDE0A6ABDE0C0A E1386548AE9368C017E755F9ED97C28BB70187F0A7CF440F1E3668726E9C20A5 D38996590058C4B42F8EEAEFEF070FFCECDA87FF476AB35F555443F52A017748 283705BB9595B787D1A963936ED4764216F0FFC3C5474D0C1DF152B8A4A6E4FC E6D6D77EB8922C40369AEE8D45E9225C8882DC606311422E7392496ACA623B38 1EC5EF380E5F7DB4B989C32C11F6FB877530B522476369843AA88CAEADA201EE 76A32A253C6FCF516075E02EE4A3B35BF9C522DB65838A4D7830AA8C34E11289 172DEF4A93045ADB4AA9B4A34C50EB920386403E5A58D24021066B76995BCA42 093C68CFECCA9A2C8879074B27DE88111FB8FFFC0D5F843B0BAD738926E2F598 6ADC390F258B05603C5C7983BB27E2A3FDCE53A76FBFF432BF9277AB08703EF6 4D711BC13364BDA42F8E44508ECA4B2C2159C89A52415EE49E18EA6701A2ACF5 B8AC016A29AFCC0EE1A193849D3822440B2439420A47CB6174CEF2DB90D64B3D 36BAC9B39BECEDE8DC5C9CC293E46CA334DCA05A1FB0006EC249B6B2C2920E3E 54610860725AD19DB2D85F6E5F76459DA975921EA39DAF429D37B9F289B0FBAE 3A850FA9C2BC151A1D0693286E311B73B2E7654CB85F89B8F3E49AC186F5E986 FAF53263110B6A831913356B70C7006113946D709C2A55E00607F69D1445F108 D412E370F0B82150EFCBD0C85CBBED805E4ADD8FAAFDEFDFBC9C7B221FA63574 BF430DE01A5905DC53583CE90F17D610C971657045075027F5E695F0F70D729C CFB4A327175AEF5C6EBD350D97290062A3E0CE609002BC2F63C3031461E6A564 85B4354409ECCC2287181BFA6466088505DDCCB8C39B3734FD5DE26916B83AAA 7D6B14AA931A0A345B31A5311196D3EC7ABBF3AF26E33FBF7EEB6756563FBEB6 BC321A2FDA7091C92E5561881F137E6A05801560045257A08484EC1FA43CF10A 3C555AC54AF6FFF7F1CDCFEF5F797BBFFF91F8C8AB64FA6536FCFAF9BCD01348 18EF5F5D4B9756BE35DCBE9E176452F66B756A710D7EECCD6CD03DB4AEB7F747 A35167A95D8AF0FA10924E78AFE04FA5C17AECF6B9796E6FF7D6A83E7578E397 F9EA5A12D5F9FE7E527F6B74FB9AB52717961FE3F1FD56AFE2C4CBE27A948890 813C8B557E04E05744B1AC45471E246CF3408661384EF07424350A84D4A88A87 CF2CB2525638AC4739234884AA12A566B545E2A7D2116DDF96CB9FDBDAFECEFE D57FF8C0C9776F4DBAA2F51F62F1FB17CEF5FBEDDF5C3DBC5C4328A9ABD4E186 26F21BF0CC789B069C5A06C686D64D02DC92699A3BC862F21C27E7EF356533FF 26BF578136677385257805AC112F77DEE5043799BCD803C4802883BB190F9521 83ED84CAB32B1BFFEBFECEA5ED2BBF76FFE9478734C989CFC52E60287284B436 DF2B71CC0449D8D8526081CCFC49A5AC5199F13CBE199DF54032E64E227433D1 3B4C0F6C66E784A6E57C6ED88429178D59555C0AB610279D49306DBD7D257EFB E182E66673120F0C57DC94D6ECEAE2D6A8DCC96D89920D815F8BF12337D40CC0 61428069157FB6E080F501059511AB12CA7B51DC4B652ABD46335A18A3424424 E4E2821EDF1E7EF5927DB6088A58913284FA5AA1A42742B212CD47A855A9E195 8137CA8B76FC93F1E895BD0909BA29658B1D7BFF7B4F1EF9D03DF22D6B958C44 0E0125F264122FA8DEF84C11368783640688F1D9F844683560534355A054F5FD 57C37337B23A734F9E481E3966B10D83747148769086F3102F62F0D28DEA9551 FB83BFB4F8C83FA576FCCB28034A391C41781395A461E5AA9B83DDBAE8DF7B2A A631819005B9C28C49C8B5DF882138AB71EA87AFE7AF5E6BF516767706F11832 0D2F1891806104C40B9C18B49924E5240B26ADC756C37BFB756C8AD1787C63D8 D64972A805490CC9CCB8B55D0354B60281189702A230AF209EF6C97EB5FBF2EE F8BB93D1E650D44969ED6E5D2989307D4D748FC95E0B62765D1A88E2B68E6AA9 A0C46964F9A15C8662DD13B491708168006A2F17125A066CE6152D1BB5CB99CB EE8C32E61A3358FA371D8266CA53ACE9501C1C4AE74A94B142CB559CFB430D61 38EF1CEA894579F3CAB57E91464A4E5C89FB7076960899774DF48B2F1E175AFF CB9033593BEFD2886B0A14D50D01186535B689AD772E6656B793A0154AA72B12 7987B8C0DB803726005ECD9E362CCDA65940899C9912349EDD3EEDD9D97899CD 4121766A34CA0AF31AB1A755B6AA2CA0B15C9BFD585ED0B94BD2E53A389107CF 9E8EBEF6BDEF3D7DF8D007237E42987DA755D26D452164058D768C51406A1B14 35F631F89D2DCC197C768DB521AAD11974A4AAAB9242F180AD704A6AAF14E144 5E54650DBF5AD7DE585E590DB175C8D94D57EEC5B410A2825AA16290A409844B 1E03487865B0F5E3E94ECE91AA8120A4F624AC99CD024E2703FCBD50563188B1 50F474B599A2EE5948C290A89CAAFCBE80FCDCFAE2C78E6FDC9BC840E5A52B2B 62621C008B9AE21B6D43E15163158E5E95B8CC8815518DD22E54E0781175D2D9 7C29DB4F36DDCC6611B3B2CFC2B8265AFB311896385068701413E78087A178AC 46D98D76FB0F87A3CF6FDE7E6265F9532B2B6BA3499B868B3CE8902A89BC1792 1FA9C321E6F0D6E196913CD2215DE88EAAA25507A356EF5FEE5CF8CAC56B9F5E E97F9A2F6F0EC66F3C78E6B3B7AE7E636BF8787F49DCDEB95D8E76D3E4662C93 B87BEFF2CAF0F6B59DAD6D387D192587EE3BFE50915CCE772EECEF96500FF174 6D61A1274D35DC2A8D1B013AA8F947568F3E932C759DBE6DD479E9BEB57DF9D6 307B72B5F5B195BBEE0650A8ADED46A390E41A157BEE4B52E64504311433F427 840B8E97161720219D55F05604BCDF561C089920AAB170143011C21F0268A41A 653382F361EC8ED62287184BB2908ADC2C549DD7E2EE7F77FB279033FFE9C2C6 FD9B83DD85F6D70DFFCAE52BA78F24FF383CD62DD5B4AFF764D5D65034D04242 C0C7870CD532BA5E735261F6F3ED475F3412EFA7D65069FC1061D6C64719BB19 619F7B32A79D375290C8E3EB524C8481C5E117A711BCCA626F87EA7AAFB3FEF9 51F6AFB72E3E736CE5EFB70E1DDACCAAA0A1D5E2621314407E6319AEBE0E1208 F202E21EB618180E7EF1D7CD548C1BC58999DDCD4F25423233F7680CB8685371 A2430C5618D66B88A324BA4055C35AD632EEE984F19341F7999345BBA8265938 A0E110215ABD9B8D5EDF7503ED272690C502EAE138AAE3A3C4BF17A8C35560DE 88AD0390874C9147CC2D04F1621AA621CE63A5E1ADA0B425BCE5D6D212BCB2AD BFFEB17A6E736DDC87589071C82795A0BAA80C20129137F30240E7F01DF4946A 1D4725672FEC6F9F2DCB4EB478C40819E54FFEE633CB1F7FA094AE6552382F4D AF9D21C156FABD36F6E66732872916497450D5C33B903A8000F3C2EBC1CBD7AA 7242DF7A2C7AEC38001556940CDE5E40015BA800B09DC89F7B5D6F16FD8FFD83 FEF1DF8044F819AC58A08840FB22DC1D2392A94976E9FCA57B1E7CD8CA88D218 C74D32ABE1EEE26E91E1A1AC30C1999DAFFF50142EE691DE9DBA6125C23006E8 4B75D5924E99368F594046F9BE5864DD270F4F0EA1974BAAC5F0E66E5EEA76B7 9376BB7E015C7B4A8E296BF8A022B46D5AB6DC2EBFF1A3CB975ED8E4FBAB05DC 09F8B7AE62E6D65BED651EB7E02368AECA1ACE2BBA9C12DD2AAA29BA14611729 5254D6987070E7B5F159771EC9711CF536CD750871380368E671B4A9115DA372 439BFDC2FF4F22F4DC56FCF3072AEFA1AB0A4F99924873046411400497313180 1495E9DB9E1D9B52E078BC5993E05E3F80341B140D251B32131C3E6C12A21269 2339C73007B802628683E062D0625ECA489276004715FD7A19A0766C8A523B13 46C12C832C1986CC73D4F0F269A86992FA269D6DE69F3333EE86BEE1C7374808 301217362A03458529B5D743A67BC44D92602BCFFABD15244C67FA9F57AF7DD8 A4FFC9CA116727269D444CB170791C7535AB5A18475A7076BA629089D878D4DC 508F66463D4886F385ACA12814AD21B4214D14676BF035E05516068E4405DF8D F092901C39AB48F1ADA4DC62EE52313C9F0F6E666A5793292753061F96441856 518C51A3DC755CDAC2F351FC345020EAC28D147C4818C1F08F51E9D78C153A7E 0521546C8BC43CB3B1FCC9131B8F30BB5466AE2EEA480E5BC930E4ED4C61116C 99445559A865E19340B480786A20C24AC72AE6E09304762EDEDCF8B963218F12 E5D6971D021709F1F1333C8535E60623FCE2225C55403DBCAE00B318359D5E8B D33FC9B33FBC75F3E1D5C55FEDAFAD0D27810C3A32E83B950600831B15020BB0 02B5D7292EF5F58D2ADB720A87CFF49F2D26FFE2C6AB4F9F5AF8CD6ABDB7A9AF 1DEEFE5FDBB75FB972ED2D87564FAD9EDA61F2CF6EBEF1E268078D15194F0F2D 5D2D46A3BC6AF3109EDDB02C0F93603F746355779D0C08243FAD3A1C2BC302DE 175F0BA24FAE1F7DBAE6CFA7EEA5DDCDB3E30104BB4FDC7DFA7D616B6D3020B5 99B65BB71CBDB6B999D4E523C78E9C049C23B844B54224AA211A830A4060C1E9 A5F689775A3104E228204389D3C41A0222F767C122966F2EA3315ECF044E5101 47C64045D8D2B4939171D2FE7AC4FE8F1FBDF8CCE123EF72A20FE93CEA7C773A FA3F772FFD672BA79E4CBB159996900839824108B225FABDD9D018E67B048E06 BE246CF454E94CDB138928C46BADCDACDFFD7B446D42C66553DF90C61AC27ADF 63AFB9063F2655046008A03D866A88D5342B18ED7E5FD9FFE1F64597BA7F7EF7 230FDD1C16B1800A4A181CB70914F96FBC410C8BB88871CB48FB3161B3E6341B F979DA8BF7A6713F8D081BC6A447D9E816E9A5635963344B4518A0931C625986 4C5DCC1D61959AD142B6F1FE33C183ABD568576726282403443874E595BDF1A5 BDD8452CE4702921DD3512BBBEEEF604465428161CCD2851EA8409534852B505 EFC70807E1ACF8ED9992636FA707C13C8837BFFF03F2EFC7ED5204199D8C72D9 0ACB622C0257E1FA2E0A52B09AF972DDC01DA691307049043F5F4DBE3319E6A2 B5520429AF8F7FE4EE477FEB63A603F90CEDD21D2E22E363C1E53FEBE6FB9477 44F29A092E21259C5C289DAA500546DB572FEB17CE93AA0C1F3ECA1F3F5E4245 94E5011C28DC91508643D6973B3F3C1BD2A0F7BEBFD33FF45F5137FD0CBCD712 F707440C05755EB83694DD26BB7C2B75A1583F6CE356A0A22A9DD0AA96AEB137 210A35087979E1F6F007E756839E52F5DECD9D4ECD231E00A86011AD5C2DC348 B21022EBC44DDAF7F6E28717B33887A41551414641B99D95E514304EB282CC53 6573F8A20EFE51B2545D5257BE7B6DEBDC603A094ABE44CBA247D85A982EB128 C1CD2E8D4B06A837E97D99B1B50800B0C27E9509D158172766002772E390E3A7 71531EBE1ED400504D67987EE07807102ED12CD83A7B506A3552FD08B39B45A8 032784D9E3F68990354E9F98345B564DA9D490A72C3AFAD6316467387C50FF56 B108C5549ACCD244E6AAF057DAA7224F966BBC6471DE60BC735A0D20C9083F75 C2834844A1202AD79A0B74C4823BC3C842278E0386B64BE8E52751A89DE3123D 263C217C031D352031B961C307BB71C21BA0CDA93DD66BCBCD2C78E7A34ABFC8 6103F800655915B9DF93207CC2E830901355B7782A69B81F92B3C5EEEA76F1FE 63C716B35194101DEB30A525165F0915093C4A8D6098248E97C23BA87954E477 351B113DEFE5A4A16AF41605E8EEA67923360227B7B49008D1F49D70E5688E2B 8CB6A2A83AAEE01BC39962BCB076CFEA1DF1FFF2F5DEC1B666579DD84EDFFEC2 C9F7DCF8F27BDDEA28B5D4414212CA48622410A90083042E30533535530CCC60 0C35C9C30CF80FA772195761B9C62EDBE59A318CA74C8D84848484029240EA6E B5D4AD0E2F75BF1C6E3EE98B3B79ADBDBF73BB5B80BB9A47EBBDFBEE3DE77C7B AFB57E6BFDD6EFE7EE26ECD9FDEDE7F70E6A045742D8C86308F4BA6D702CC7C2 C691686D59FDD66D00F2DE0AA1864F51570F0AFAC1F5EE874EACBDB1978C71CB 1D503641014F2CFBA2A6AA53280E70BF52C1BFD8BCC6356AF845008403D084A3 27A86521B9091F36030A6FCB75FF096B3F82F5711F3E6364E3589C5B33DB2642 C028080BE1A494DACDF32B69F61FA3E8F76FBF7CAEDBF9ADFEF18DC3A94D6427 91ABBAEE47C64A44D2586C41BC8D6328F22987E2B4E6C55C27C979499FDCDBDE 4C7AEF5939DB9B348522974CF5872F3EB7727AF4DBA6FF2CD7CF3173FD203F9E AEDB28FBA35B97BE562F20E80E79679CF5A344EEECDC9D51B82910F013543382 1310AA35ACF0789C02F22D32ED5628A9343E9A53BDDE4F9CBAF7ED0D4B67D39D 0EFB6AD47C199050453F385CFF709ADE53E71A5963900871F32C91B829E051A1 225EE4C1632C8A18C8240C40508CFA2BB8F71EC4BE9D5F9DE20C4EAF8257E200 7147BAC4C469165035603BA85792A9957FC2ABCFDCBAF98995073E3AB1A6337D 61CCFF74875D3CBCF2E1379C7C5F139DC401B75924045E0ABADB205CB0B183A8 EB34F356A3D42D117C88A9D6EFDE310F177D07235A364C011E79D1A7B0D1B02C 228937C7B49D8A161C4F0A5CF2A9907B45BD5289DDA4F75FDCBAFC4C3DFDA727 EFFD19CD2692667060BCA7253A08FB5D554C06709D534124D7B8FA14366C83D0 120DE2325E55DBBD6E46C8DABD398F90960E1B9E9BED9396E73E433E9591D704 60895B391CEDCA778D463F78B286DA72AED031033ED73921572B7D61227203E5 08C4D25A2BA819B158458160EF6182C28C3C12B147CCF83BC8B5EC4AB7D6E1A3 348AFDE085939C369534BDB515282E17DFBB78E5C927EF7BFE3E1DB9BC9C26B3 AA67E285291BA1702519574913AA13B8A2503D273A46DA58B370D23483EE3345 F1D4DEA4970C57A10019356FFFCD1F39FB636F216A81964E3C313610FC5B44F8 EAE684B718C3EA0A5F7BC921D9B0BA4C943426BA70B3F8F6793B5FA4F71F136F 3B97776C94978981446819CA5B26AE20579FFACE786BA5FFC447C7C7FE3975F9 AF42E057BE2D8142B53532B4200ED06939B9B1D3DD382E7B23E19246967E1E82 A1A651B5CD243274E666FEE7CF885B8B6EB7BFBFBF6FF6CB0E54170062982B62 6723DCBE9498A36A9556FDC74F360F0D0E44D9AF34E054FC9AC9BE9ECCE9AC91 44F4B7D66C1FEE46CF5CB52F7FE1EACEF373ABE2BAC2C58E95385D89B21E2A4F E39E99370A4341B0400915FE7460DE857CA111D23BEFA2821EF5E8650C090125 4E3872A5053A4079DE31EEFC8956939EB47B81BED0F2FFCB1ED9BABD26178675 DB9653E3CF9F741A4299C15D257F742301294A08C0A12576B36AECBF60F06A54 5B053ABF41EFEF3C2E0E3AEF79DB601644313B94606199B68D6E0E351CCCC892 58C5721FEF5A7D264DC610948836386D402F037C18C10D030718DEE91947547E 0CE8CD3CE174083F95F49BDD3E2FE11812AF9272BE79E52D2F927972689B596D 8B5295F097A2082E6001474A22D52861D90B8B836FA6D57F6F470E4E7FA43BD2 57741937A8040E3F36D31CD24613A1BE4DD688C60FB29171A77CD1247121D4A0 32235ADBF84D2C2F8E8302950D7370930AC01E3CE7D182F305A47FB8CD717CC0 CD1D5BEC3272887D045A2A3BD166662D7CCDEE74B65D2D94F7B8771861694479 EDF7BFD0A1D78772AF1082350236AD3DFF0F324F4CD87B62F6F0D9D13B8F6DBE B99BACD5A554254601C92B996874C6231DC35203901442240AC038E4B720AF14 7220D4ED75846342F83CA5B19921DA23BEA53400220DE69583DA851117F4DA90 5287EA0068A3E1B5361DAEF4426480B2CFA27E8AB925A297A2E87FBA7B4DC6F1 DFEB6F6CE63316D15194AC2A8B8930C29D3C814ABC1CA28743794F8202255505 A7EB566A4A4ACEEA6E34B38B5834B1D8DFDDDBA375EFE4FA63379B2FBAED0B93 BD87E8F8DE64F37B4DF9C787B74D36E0B53C7FB0FF5D9A9700DC88B0B1250BDB 45BC0675167ABB794989188E28B689004C47C8AA1D565DC0D30F6F6EBCF7C499 FE24BFB573F77BD5E4AA2DCEAC0C3EB87AFA712BFAD55CF2E6FC607865BA7730 393897741EED8F57894D553D8A3229A48EBC690E551635825264334125111399 088977C88B7AC22D14C82835B52F3D080B3BA6246F16107904599DB9B4E217C6 D9FF35BDD599D19FEB9E1AE5872A717749FA3FCE6F3A5BFDEAF0FE879BA6EE2A 9332890401644658AB3AC6C406C0BDEFFE11AF2DEC07F428E4EC15C9A917C046 14881A57B803D3440C300C927A8C4B896FDC0AEFB9A1B1D681079A5414C00194 4EACD28B78B45FAAFE6C9E77BAFFE4CEF69FE4C58FF63ABFB5B115577506DF52 6B810A457EAAEC0D3FF1D4C25D4E23BC9338230CA3C176AB3FD4054BE189F0BB CB753A8A3BFD6EE9F41B289418E30079FA6E168B716B1A59E4CAEDDD674E7DE2 09D251CDCE1E81B8AB23AC736F2AF3D29EDECDE314C5DC49ED7737E1C1F8C482 18104D8FA877318C9CE4002EE08FEA4C252B7DB93E44697584213554F755D488 B561DC5B31AF6C6F7FF93976773EDE5E9DA9A2D1650F55CF501C44E337567E10 2318C403287089CAD0605094D4D4A649443271F6BBE5F4B962DACF7A63C6BAC7 928FFDF35F20EF38EE203628AB5D94451D548FB17ED8EF097D5EFA82A2C545EB 666E44ADACADEB0E7C3CC6BE72B3F9CE457138352B69FF071F2CC752344AD4C6 26A6E2266B3AF47A79EB85E7FA6F3DD33FFB8EADCDDFA176F1EBFEDC63911124 2FBD6FA1861BB298CCEB79BDB6750A303C69E54F2CC27102774F29EA7AF0C6AE ECDDF9B327874D94C6C9CE74329863C46F38D3118A8543AD9CA1F3019DE9D974 436C7DF8513396E5FEBE1490E2F2141E68AEDD76DDEC5607935CF657A8EEEC3D 9F1FBE509279628C489CDBA21015136CC97A1F5240E9DE7A6AB90D1076E31C6E 8807C9B90845E731CDA07518F34C795CAC0B0419DF73F02D056C1D306797DAA1 4B2E656826124BC95F4B844B35233F3C5F4EAA3D1D92923615C1D189F067A09E C9B28BADB10DB8144370AD821B92581A1D84D01DF223F1ED3450201B40D05023 55B3CA746CBFE6E9A5581D8AFC5CC4EF87FAD9D4351CCF58E08BF77372172A44 BFAE40961C802596052809C1CC42A88127D578193794CB34686AD8A0CB0312D6 2365E99ED8767A9F0B859C30649A54B4C10538429A4E72A1985EBBBBF7F8038F BE7F761D1E248A682770CD309E21C049A4656143A365D5A28395F78880CF12A0 1AC4B5C4125154687D0B7503EAC8C151448FF70650DE545140CB245944D19E24 0768ADC4507252440BEAAEE6930BF9FC42A31AC9F7A8B9AB94692553C3F88DF9 798857C5E35E1D4DA1C2648418105737E15DC0FFC6D5C1868CB5BB7F3878707D EB3F5D9D1FDFDA04E49AE0801F0B7B7C2A382A168145EAFDB4591516EE7D400A 6295962EA7324BA3734BFD950C2E3A47E423CFB86F1754C25E18FA5AF8638A1F 793B3BE5CA2F54955089F319E1B78D9D51F7C9BDEDB98C7F6EB4B651CF3266D7 49B2A618C41C0D5F8A3D700E2189C69405614A0FADFC74075BFDDE6C0B27C170 141B85010D15100DFF8E3DD0C43E126F3407F9F96A3AB1E4B41BC9267E3A33FF A1BE7BFECEB628C8CBA853899B4D61E91315DABD9AA5C151ACF3D52113B8DB04 B1C774653CEA74F3BAA8CAEA781ABD73FDD8BBB3E159CD164DFE922C9F34FB97 775047FEFEF1CA07FA6B0F17B6972F2090DA4454F0CA7B69227856DB3E00C288 0683713CFDDCCB14C6D8C2D07E1D05A197C6B502DF59C5353483C513D65635CA BC45C2F02B4DF9A9C9F5D1B1AD0F4E876FDC277707D3CBC3B5CFBD7C0D4EF54F DC77CF60BE87332C9C95C5387C806A07255B754D51FA87A30937F7CB430417E6 906AE63BDC785EFC1605C703A10429D19C1C72391E2513B142E2734F1BC700B1 1A25D046DD0AB5E08AE47CA580CAE4F0EE228B7FBF247F7067FBA134FE17674F 3F9C370C120DC11D215C1073DEFDDBA75E22699C0128C6862BF3DBCCAE15B7A2 2498C1E32B64472E892D8AA55E3D23300E3C0B3B6A799D28CDAFD148870819A1 568598B10FDED77FD759B7738BCE8B8A49130DE855259E9BB0DB730558218583 AE3B4D048F165012DAC122811F196F50237184F30CBBD6107685586CB1DE70C8 1240FA8C485BB9D2463A59E97191D43726310E7BEE0000D50849444154F3676F 91CB457AE848A5555D63970E7DDC50F2C5B315AD0B0275FEE2C0B9952856264A 01CFC441F5091FCB76623EBB77654F887BD3D561513EF4138F1FFF473FAC362C 6D9476494A7B91C15A1E1798E098E808E11ADAD46B87024F2887119580146AD3 A195507667A77EE6FC70924F74B9FAFE37371B19BC18A8C8B550D38E5B5974D8 B7B60F77AE241F7930193E7466EDF7A85BFC5AD05DF0DB75CE0612AF17B674F0 DD6EEC0E56563BDDA1F3263EF0F4E11E22EAA96B948E4F8468C8E25B2F16DF3C BFDE5F9D548B6CB7D69495A858C5B1EFC74806C193D16954DFB6D39593AB1B3F F048B311EBBD9B6931A35D385625CA6B00789AC8E6FCFCCAD3DBDB37CABA8C5D 25A064383D5CEB619B538529170B333C6FE91E14C348207C0457DBD6E4C54F69 FC2279685B058634F54CD15638C627426F04D56EB9B51E182E5813799B82D7E4 BF23DA286DB3ED32117A7CD74AB7F8141B7955E2A0E71236837CEF912C13A10B E6EF98C4B437398253D018BFB98A4A26F000725B4D8422137D5C0DF7FB9D2FD0 DD2C631F60D9AA6D76A22A8E64C7C2ED5B6E71B0561DC3CF39FC7E290E3AA877 60B6350AC6BBD0BD6BD06D96C40615A63D9B9BA39E5851BBBCDE53A268CC5470 C5791FA9CE761B9D7798C8B539B6FA872F3FFD031B277FB1D922D90E4EAB13C9 6228D82DAEA1405C46653DFF997ABA1DFC5F09052EEA0E422D0FFF1F0E8C410E 6F55C32944B54DB8509ACAD26E1B9C3947B911D84DA55361A704C5E5B08CC090 1E617642D7D6CE41D69B25E499C39B5FBFFECA367CB8121F9308EB608436AE7D 017058F1F66A81041C8225281CCEAA99C29FDC93900F6D8E7EFCCC7D6F487B3A 394CA02C2AEB0E6150A71B8D7E5758AF71BFFB8046EA1450882F5EE852BF6969 6CE3394741882BC832784DD4D62D20CC5C9D1F000786109E52FF27478930F405 E00BE0097388E8282420268E41229C52F76F0EF60E28FD85B5ADF572DA1174D5 8A75C37B38CBA8BD7A24B3E869059FA00FD847E7AB55AAB33C8A83D97A9B20FD 86D53CC3F4366C18AD4CE1F1793267CDB4DE8DF84538698DEEB0E4DF1EBE7C79 515FE6A491185C383A663410150BE4CA639605209C68F87C9B4C20199E22B9CA ACA6EC5D67CF3EBEB299E6667F517E73FBEA3767D3BD94FC304D3F76E6FEFB1B B73A2F363A9DCAD8FD544F325DD753D1D449D419C8F1B8E94769EE1D331D2024 E59A9A1B920AD9CBD03742E395811BAA707B41453A94BC36AB5D54D99DD84D29 397900D157FCFB68E77376FB13BD87DEB513DD968BE355F674663F79E78537AF AC7D3C3ED6AFE7C5C0A179708DD47100E6915170B0258B20F37A3A2FF71D2314 E8C2F2CDD908E932F8E95609EFA0A6846B228B8A0916D7BC20792BB80284261A A91235CA49A5E8DBE2CA08B20A1998DC4587079388FCBFC3F13F7DE185F588FC C6F1E31F21296406ECB1C27BC2E48506CF02571C71894276E2E0EF45B9BFCE1E 1A62E70FB59831C2504E5FBFBF453D45DCB372B92799F90507896B8A1C921649 A5B22A8BE00D36E509B7FAB3EF736951EDDE4950953F66363B7CF62EBD38EDA3 C82B24330555791CFA44D46F61A1698C2052E8500F44DE429DF24E922EDE304A D0FD04623AD549331545D4CBFAFD15FBCADECEB75E51AF2C7A5502E19C1625F1 7EAB2C68EA7992605B20064783B661A2B1C4A07E95579B18C2713FFDFAE4EE8B F57C1877B7986846EA2DBFF113673EFAC6064E22EDEA9AC42C463C666B3F1C65 E8948D580499A21A1BCC96370D442678CC0D6F583EAF9EBDD89FD4FB93EDD17B 1F51C7BA70EFE043A8459D77C8709ED12F9C9FBB3CFBC89B48E7CCB9D5FF8ABA FCD7C31E4DF87CC333E058982BF8353F9CCF0F176BC74ED49D0E8AB723D5D120 BF09C31560362CA94461A75FFA96BA74BB2F533A856A002B522A315AFB5E1C80 185641DD24E1BBEDADBFE95EFEA1C7695490C97EB9D89B93B9EBC19F2783E95A F1A5BD57BE74A3CA23F81E3D196FF0EE104A180DB1D404976DEA428666A1DCB6 81F5182CC47C3B0A9F1AB2FFBD3C6EBB334BC2F10A9C6E836A0B58267ADF6ADB 66CBA0DCD096036146F8AA2AFD913EF5F727426FFDEEF520DA0143BBA8704471 B6ADE17548842CCCACFC81C0260B04CC5AE95A7B36A9374134B83433D74D6E15 2F4997F75F89CCF924BF6FD87F736EA929A7239E51D9ABE8226DB78B6CF850DA 2B12945B7C4FD4AF1EE631873B11F9001C2CA5705910C9081C805755ABFAB030 45755744D80BA6A2F026E2095C2A2DA6B1BC3A4EBE7EF5A547462B3F928E4FEF 2EF42636FED0823512A80E061523C0411AD0330F89107E08F68A2CC93493161E BEA974A31B25FC229D82B3A0192D9DC8EDAE26155A01C0B7B2398EE87458B180 80754757B7EB6A56AB54745C96BD5CE6FBA6B9A6F2AB655D08AF26812221B829 814E1E0CFF267CB009520E281AD38B44A906106AA48BE3827FE0C4E823674FBC 7D6DB865959A1CDCEC76120235257A1BF130266568B7EDA51A91C11BC6AA8C2D 0F40A890C23CE6E8F7A8D7C3A29ECE19B0E0F279FBCD9D76699284756C6C961A BFB219FEC45B31FBAD4D5741BD121D187757BB99A0FFE76276ADC87F79EBD426 2442C9570CDFB412471098365124CEE15E9747848CB42A7DBCB52FF7FBDFDC04 29145CB7C22612CE2E394ED0216A4BEC77519DC3A79A4038AF6A53D6C6739DDD 15086565F9ED79FEED9DD995461D125946BE9C7080DD6D02818799D2D77C0C75 B589178ED00964A3946F657D28E46E4D674ADB33DDCE13A7EF7D37AF47B9491B 51487947B86BD5749A4FEFEB74DF49BB6B853AB4C5AC930236CB78CDB1272D3A 592C18550CC9455196701C59F050DEF9154CEFFB60510B3E4662B59D464C156A 3C816C2C2EAFB0CFEF5F3BD6193DC0C7AB73339C2CE6ABE917E3EAE93BDB1F1C 9E7EAB621D5E1419C031915A89E81F5EB8941EA938DC11E7705421AC3628DAEC 19D69ED18697096A821867B2B691486E664E497FEDA11661D870C7BDAC8A1A99 CB1AA02D29B96EA4EA885CC6102F89FECAC6EA6FBEF8FCA151BFBCD2FB07FD2D 5BC307C720E30994D9B3917767C1E21D13A124A88416F43D48B095C7E447DBE6 7A6BC6EB230F6BB56F02B91481ACF60D42E47760CC463129DA8DE1AF0EA2A834 65F1BEF1C6136F2A673BAC2A2504B59A95B7F3E2E2A1DCD5A94C4B3FB7072C83 362EF8697B53282CA951AD1FBE1F5E2E2820229A42C21BF4176324BAA2888CA8 CA4CB9612CE34CDD2916DFB9C52E2F3A33462A5AD5DA55393E35B47D753C489B FB2599A02879C43CAC98812B10E34A111ABE01244AE2F426774FCE760F953AD6 EB29BED87CCFFDEFFC871F33231A451D8385AEC00CA82B1B71FF7004EE792029 1FD28CF64D6EA48FA06821AB5DB5502FBCDCD3517EE30A7FEC0CB9771DAE615C A1BB62D113FDA9B47FFA5C93BAF8236FA4C9A933AB8808FF21D640985A7D8389 856E9F69F7360D39B8BB2B21696F9D88B98869D023B7705E2153E2BA3FD27EA8 DD3DB8F5F96FACECC2839064D1E8BAA9A1AC88645CE3A7A0532862C980A18BD9 353DE93F72EFE8FD0F92012D6753471B281507159B3F7D78F153D7DD7599D804 C0FDC6A017352832817E3CA1B208D968F9DF9EEFE8ABECB08DE0438FF0C4644C 844B213EEADB10583D04AC07674CA082ACE76579AB9557DBEFAF4984AFDFA77F AD6FD9EB1221BA2AB636667EA1A14D8421E0792C688F565EDAA8EA25D68817D5 6C2AF8A0B45759E3149553A8E6C22C6A593A97742EA6F67BF3EDFBC7AB8F44A9 6CE62A732C4DA28A243C2A22E3BDA358AB0447C3010E4B482E7C20F01A6A81C4 712F15851C1F1CE13516DDC01D2B20F22257A981C03DE5128731942C989E489B 55747D1A4F8FADFDC1C17953D5FFEDA9474EDDBA3BDF3402DB8CE82F48E1E062 31CB792CFD0AA32F3748D8B344ED2F013705872880B634F225B5B79DA350D3F0 32376E4E628544DF0557070C7E3A003F8BD45BC78B4635FDCE15575D54F92DAB F71AB5ABEBEB10B371E88CF82A82176168E0E0E098D11B56591F40529DE02022 C6B127557A859077AD0D7FECE489F7AEAE9D709A56D3C62DA0FA3E9443F87B02 BF0A15EFB0B413411ABBA50C7B6A212EB591EFFB67590DB516015E672F622DB5 22C8E685EE285DB649BD0B4830206A394AEDE693C2E13547AD29A20C3F506E87 B01975FF9EA8E7EFDCFDCF4E9C39D62CBA115FB172D3F214E9864864C0B99540 F3092F62E31304F352094BD34C4F72B1C2B7CDB52FD19CD19132712C1B8ACF02 FB72947B2959486F319F2B0BE508BCB6B2E432AB5874A56C9E2A8B2F15B3A7AA F2D0F399626420924A12953A31E75A373C42A93F784B4822ACFD5B272615E4BD 5BC73F3AD87A78066972FF90D38B8DB9A2CCF5C55452F7B6D58DC775726FC353 ED0A4085B1B252CB0207FC040E512621BA2682A752A00F4BCA28B2AFA0B2878A 0AA20944383F6AC7E6AFCD51EACAA287007AF92202CAB5FDFAEC56B6BAFADEBD CE6192AFA02A5BF619973F77B0FBF32B671E6DF4A457E55D3E2E50FDA64E718A 867BD92D39C07A3F60949EF4DA2ED405E636A1B9C02107DAB221FBCE716FE7DD 204F9BA3B6828D14E773E100A456F0186D255599353229B3A83673A2BE33EAFD CB6B2F7F7D3AFFF1D5EC9FF536D0E99321990DF75CD1FF132295E77E72128544 E8F53D6890E20DC4191666343EDEBD6665CBB72342B9ED13211A5CE2D5C64418 C90642780AE013B786A0D653BFF4C058A4F9DE5E8466D9C21C54B397EEC8031C EE1BC0F93E3071286AD0BC190F3E2240F82E5E68209851E7529B61223786D1A8 C77813A55C79A77539EEC02751DE994F5EDA56AF4C87739914B45E14566B836A 8FC13706091C4883403E4470BDB22D838D901C252C5CD260D8D4110ED70178AB B4734117DFDDB92D07C96090A6C3E82D3FFF039B3FF636F8080C9778315160C6 2A6483C0F94397037405C199AD42EC09771F0D4C94A675554CCA172FAFA7E3E6 C695C5A96EF6C8598875B2D48A36E54074F7B9FDFC8BBA43E4871F649D73A7D7 FE15B58B5FC519815746245EB0CE0FD234E22528978550557DFBEAF5F563F7F2 0C9108C1D3CB9944892C8122618DC3C74BD5D53BF3CF7F532C4862B9A95489BA C102003B5C41F84C21644686902ED4BF15C066F1C4F1D187DFCAE22E5F14E4E6 76F59DCB2FFDC585E2AE8C8AEED824C764222C6484466448CD6BA9FFF6481490 861E9409857658DBF2A0087F5FA31A1C69A5DA5B5F80E0FBE519C9A889CF515D C20B96BBA382BFC54C7F6322FCDB10A10771AC455C614AB71462234BD99610FA 48D828F7E890057D19F8F1B542AB4BEB8D6120E9533683BCBFB07069A7DDE4D3 D1EE84373FD93D76EFB45AA4753D84AA5610C35D1C794A41B83474E98AD18A46 9157CD633CB8B181EEBD24FB1AC8BE36AFF542B979856D4BC8958A27A42C72C8 15D2C454F41B14A5FC4ABE7D7B32FD95071F7DD3EDFDD5541F0E7133053F3A09 D52236949CD721F4A8B41D5C845D8904DE0B8AB4357E49C25BCBC3235C34B676 0AE35C8CEB780D849772C1EB1BB19D4AA4FDC435C1BD906EE7AE30BB9D7892C9 EB6571ABC8EF94EAEEEE94D42A32104190C2E55D74BD0D50AB51133A9558B343 CD094960E4C85B57C587CE1CFBC1F5F5B342A606B22EB611501B1C4E828CD137 C933CFBCE828BA4538E659C25E62240C9BC3097B9DA6C291BA5568857A181A05 2C18EEB89F61BB80056DE8B02F1F876B9BE8ED8E67B09CAC9C57DF2307B53B8C E4A1359F4DA36FBC7CE9578E9D3945EA8CD3B193EB9AA510A8A4225E781B9E3F AE1BF1E05FE637C2596BBEE31FB16F8D6322C4E083343F47320C1B5018421D03 39009945689989CD4DDCDC88450C8FA93F2191C1C265C6CC5ECAEE507265D1BC 30597C6B3A7F56D9190A6E65DC04D8924319864D2DAC45925A09A88DE150467A F2C65EE76DAB6BDDD9E290B22BD5FC465DF7087DCB60ED07871B6F8832C8F857 BB7A5B2D36E7F50326EA4538BFA0ADE02E7C38904A791247543293380E5540C2 7DFAB37EA30D578394F0761D4880830F9A5645D387D33AD72A8E5F2A0EE0A3B8 7F914CBA265DD47D9B5CEAA57F56EEF7A97C7B946CB086448D6011ABA188EB29 5A4659E652513983C454AB63EAD7C19B0623B85F7884427992623718FE95A886 6FA194AB24AD13F4978C0D85AAC00951C0E5A10D12F61524F7455653A1FA5021 34AEBC9EC5BF7FB0FFBFDEBCFDC438F9DDFEC6262602F862FC2825AADD605333 C2BD42DC2241B0CA7D59D36E7239DF0927CB3E965B0A82D3302844ED4F0F0B01 B6281A429FEFEC73B89B3879B5DE3F6F706EADFCE913F26E450F00D2A3DE81B9 3D27D726684A49598DD70ED504D00A3B6DBCC208FC2B2011E27E37E38A68006D 741427C786740808DF257D3B55B918A49DF1106EA07A79AFB8B447F78C992A5A 43395593AA02FC5C7B4F39E705CAF175FA415510930EFF84905AA1E831DA3721 0EC5EE34065626D2B98C9FDEBF7D9B55D920DE88B3F587870FFEDAC7E233EB35 0E7BD1AED54956E32500788DE44E87D31FDC95C2D212F29855DC2AED6A532D26 CF5FDC1CAC56776F1D74F4EA130FE0FE918612B4AA07BCB34DEACF3E2BC619FF D003B473F6F4EAEF509BFF2A6DB3A0F0726EE8F5E3F1850BDEA410E2A707077A B7199CD8602BC3C6D31D8DF6F610283C675453E26A94E3B3F3978B2F7C378E13 A4DBEEE6B22116AB5117552EB6144E9E662E81524BD9EDB45A7FECC164F34C7D FEC6B5275F20FB2524C7FD837ABDB7B6493BE9BC461A509695F0AE747364A017 E28B8F46EDDAF2D13FC40FFEA01EF10D38EAC872A4876C6076B4630E1F7714E1 414759314402AFEE7D2F91955F3BF349EDF55AA3DF3F23F48B9D505771ED5169 7078380A9A2C986A06024588959ED7E04D18B1FA6A2A43BC43212E12FB316645 C8B4A8925208175F94EACF8B6B8F3C78EFBB4D32DE3DB05D32E53AE2B1C87A73 DCA72461684482880C5DAA61B4134F0FEAF1A91F6110D4FAB55EE6A9C89B49DE E41AE5E6D14191F30AF74BEA192F4A5D8F9BC474865F96F5F307B7FEFEDA43EF 9B42C17B408E475DD51431EE6CA0B13B3C7ED4A563B8A3E096EE546DD6402A1C 14804DADB47799640A0A666D66B5AEF1866899D4B809C7EB4617D41C46A62448 FB4A0C42F55DA65EAAE72F94B3EBCAEC560E8A7D9C8C5B21E1CC7BFE3D96EC48 DE0C3B44E831815A63B84C6F377BEAD478E5CD9B9B0F76E4C39DF834C45280DB 90F6051A0DC22DC964178917AEF495BEB764A7A1E6C7E692F6BD77E602C2420D DFEF2B838E7A3A6DABDCBF691150A07FCA3634DA977B23ED84C74342CF37095B 2B7E03070A568D89106A1F881EFB8D5E24D9BE525F5EE97FF1FC0B7F77FDF819 0631DE8E69BA56932CF2785978114224B012AFE4ED97593DD73E5402A82BEFC3 A55F27655E5D1DAE35AE3B019A49F0455B9CD34AA6F1F4E28C1CEDF45864E115 78B53FC80050407234087480190F187B36E19F2FE75FBE73706507C0839801EE 833750E529407314D406A01A1B2413E9140DE36A380F9A3BC5E28ED66F5D5B7B EBEAF81C8DD74B9ECF8BE7E9FC6BEAF638133F1E6F3D5AA770182BA1BD203091 0645DA7168CE303742ED9C243CEDC7492741253AEB203342E6A839FA16650A7B 3A53D774B448769B8A91C384478A7673CBB00F6516919334824B74A513FDDBFD 971FDC3AF6230B37AAA7DB1BB123A3E3793717539675F868483A5D25301320FD A56AA03053BAD24E55706834E0867CA079D72019B3469E305AAEE1B492E2B81D 707902084FD3A2835347A79A48CDB21A8EC0B0E61DADF205257FA4CDBFBCFAF2 BA8CFE9BCDE3F7A1A2869194C7B87C4C390E899567A210D989098E1ED1708C7B B1EF769DD9AFF25B6FD2DA76EABD8F222E7FF9000289D47A355FBF558F8D5E78 E6704771F207956D4F9C7CEF9BE60F1A77F1B05B4A42D2E9AD6973FD605C0A53 9635C3D601E60E4FA96E6413A1E134767D39F2A29882B221D2AC27D3B58EEC62 7EA5521C64FB71AF9FAD6D925C972F1FD8CB87EC76214B5617355A68E13A68CD 3494B4998728C4338F5CCB93704BF9E665696830FE604190F99DC826F0A46A22 93EE75D27CF3F0BA4AC53DBDD5C1489FFCB1371DFFF80FE72995B58B503711C3 6E6C704FAB1680044D178D493591B501FC867697B53155ECECE485F3C34EAFDC DF9DD062E3F1071BD324510C8FB7E9D3F4AE9DFE87A77A6757E987EE67C9C953 E37F4DDDE2D77D6B94075D628FB8C2C81DCDDC1D2457C48572FFCA4D4052FDB5 75DB43AB79EEB868AC10118E663C2DD7D906C24AF3B96FDFB87C65D01D74F69B 74A61770A252692BF44D44550D47124592345B545505B1124ED2023E40A9145F CC67A34E36603C417D2F48CA710DE7C3E854E393F6F440D2EE34B8657C5A4A96 B4C242709DE1D56AD4AD087FBEF440F02C1AF4DA846A42C8280A1BF14789F0D5 6C478297F4AB88F0A884A121E8BCC609D3D3515B916EBB147A78ADE7ADF79A6E 95C6FCF29C3F1C3E6861A8C5ED718BF81551360A8FCDA028CC695290BBEBBDAF 347713C1DED619AD3565CA548A119A432AAA23891636F0CA43E317A36158E838 22B57A5160EAF5D69CAF652954AC1AF2130034C88290EE8A0AA7268AC1B9221A 0056C5E75111B16615103ECF9EEEF2CF5EBFF8EEF5939FA0FD938B995D753369 577852A1C9942F5139F15D0A1F7C83FF8BA7B9874F10E0070A4B3A38A16822E0 7205E704F539AD2B892D84984B36A328B5AD20CB7968AE8D96E8DD43AA2CBEC6 ED5FCD0FBE7AFBF681369C763DEED2087744B0F0D1415863C4E88A712B9ADC33 E83E72EAF4E9F5D5F5B819B26885D10103C00779A6D1AEF11BCA0C939AF59E93 02F2494396DDF096FC495EA30B8E4D271C0FE8C8B41A4E4B6985574F820F4861 2628B0C5A69727D16F86B4BA75C145DC92D64D072B38DCC5F02D399426D1D850 8342B6516C6AC8AE213342BE3CEE7DE5E24B9F18ACDE1BD14CF0918B5795CBD0 EC4273DCA9C70E3A920E395C25E480603A5F165E08BE030B6C39A5F65B6910CC D0512845D122282AA1E8C04110D3B4A1B6C62939811264D69D6B00B73A4A1ADE 2D05A0431711D4C3226EC6D8556DBEB67DF31BD7F7BF085113A25783B01AEA20 D4FA85BADB6B547B3F7AA9554323E9687E92C73F79E2DC6627BD72B87D757F72 77B20040FBC6D1DA0F8F4FBC01ED399A45849359696DA268822448EBB508E093 44DA63C451C64376A264D031A8AB8B3E67223878F8F715F9205AD7BA404E108F 6A43F24662E595DE01E0A8F499229A89F84B237379FFF68F8BD11B6A351DCB3A EE8C50A47556B388F6C7D1788BA48328EBC93806C822B18707255BA95C332B16 2B7B57F349D1103A8FC8C42FA5AE2BB1599148AB052D490FEAF36245C48B9441 D90A61C7948712B2291915B2C7544D8DFE94A1BF7EF5E598B3DFD93CFE0E1E7B E082B36DC885F0968546DB73CE5D9CC5905615BADDA134301E211401F779432C 0D3178881C4168342C4D40CCF5BB287EB88D99113E35ED7A129E9ECE87FC7033 B9E7A7DE579457DC2BB3CC0D9AA9BAFDF29D61C1B31C2909B5C0B25978F163F8 B94CE2BA88F00281B8042C792D9DED8964BD17F523B4E163064E9B3A213A834D B270E5C5DDFCD23EBD5B24B96325A2310751C4550A0EB470B24A1D2AB47A0283 379E0B1C8CD6EEA6E57311A7B9E7082A89CE56B6E2B86B10E10446141DF9D46C FB5A7EB835DA3839A4FCDEF8A17FF4B3E40DEBD85546E418B9E0F1E695E8210A 752A4B94B2121D74E0B32A4929286E0DCECF5FEAAD8DCBE9FEEEFEDD636F7E48 0C93B2A9E09C547D96DD68A69FFE4EEFCC9801224C4F2322F464193F1941C12E 2C5EC9512264ACE5130094D665796BBF233AD1B1CD2285E748A02843DF704084 B867828156DB461ED6DB5F7FAAB9B6773C19D9DD392D75891AC3C2D4D8880EEB A85013991A8E0DC695D2893B33335BE841C4B7241922918442196FD011026A44 2335F6C302080B2E252EA81F91B65F4A8F5A43D89DC680205A43795F23FB269E 97F0F4610C377CD190CC38BF724319792DF25BCAB81EC5BEA3AC46968A9DAF02 0512AC7C978E154B1AC551527DAD0810F5344E7F145810FF82CA13F55C2C6DF5 48082DA0E498A8341B7D25997FE5F0CA4737CEBC8FF68C9B95A9E93B9610B148 78051903EB45D5D218BDDB9A6B398947CA00CBB44D68AD01162901E95321AF78 3A2D2BB4C6E1CAB0C2C289A1906DE22A9AA64D5FA9EEDCDCD81AFED1F4D616EB FC92DCBCCFE62ECB650661235E3811253ED9E1729EF3EA97CE8F5B58EB0DE637 E6ACF7DD6B0096D7CE401CCD0DADD13C4A0874EF2BA9C98999733D87EF509084 4426923347177134A5747F516E2F8A9766FB1748BDC3132B136CF1A84AD8398E C61C041FB699251B7174B6979D4CE5D961F7782F594BA38463485D29C8B2198D 4640152E3963564097742F6517FC4E43BBA0B5F424AD8C15690B171E76B7E083 D3A21D65B8D73CEEA53B3639B288C3D984B7970C8B13AC1D0CB6041AFC13FCFA 50B96337D26F1E614B1F63BE424DD746D143CDF6AC9D3BF29595DE572EBDF4F1 C1EA1B244F391D5A395634839F91586FAC2E9C5F6126DCFA4A1E9F3E06CD2025 E7675B9E67C15A822B562754F9F70B5506F3423B70A0236F93A150BB02DF01D2 4590C98EE93FD64C2A443F39EA1C988E215D48EE31B91D41403DF8CC15F69D5B 93670BBD4D3D5D9F941038D193DA043C2D03405723951EEAD3E8BD24AFD505E9 F033ABDD277A5B6F67EBE9ACB9AD67139A6775F3A088FBD89CE110B933C73B50 E919EF72830E91D80F12DCF593D8F592058406C1526D98D685C46929602F7801 73A81E7395CC6AC5B81664B4D09358A28877054013F2A19B0BF6929B6FEBD9DB BB1BF7CC9CEECA1B993E55D70B786F715F0CD7F9602D5ADD10FD610E395D8824 4D96C591EB4D2E43957A7331BBBEBD33992F266551E8F278B7FBA0CC56E6F39E A479541689896D14B90847102E8F2AD334D994A61925B1AA3FE7F8DFBB7C5931 F15B5B273E14C5508D3A0F0A539C3222652646F061933426095AC718EE6301CE 0A39B6F8BCAD28A39E51EEAB9AA3452F4F54864A05CB82D8C20345EE5DC9287C 987D29B5ADF77B46BFF9F889F73F5EBCF05CB2606C81C4C462BFEC96346A0CD4 46004001D6FA620F47A061BE227061C4EFE6C7CC2514D2061BC94236754A3A1B 83EEDA801A57DD38585CDA73771B72A021054AE46DD7BE418BC7194B3B29B212 C593DD321106CC1A28CE47E8C58F9584D7D2535E1507AA3444BEDC90082AAA48 6C537571763865ECDC281E1D8BB28FBEE59E9F7E4F25D194071E3645610A82C2 A7B87163630887908C7985CA8511A441EC2346BB87872FBFB272FA58914FF66E 5C3FF6C07D626358B2461675DD67E9F51A1261F7F40A0344989D39BDFAAF2011 FEE360698E8507612DEE6A05ED423040262F4B213E1DBA690D35145D1DEB3446 D9165CD563D8BEF73AC202F04DCCF82B3B075F788A2F9A7E6734BFBA4D21E1C9 0480022B9134819D994AD5AA33ABA1845894CECD2B96D0EED9DEB05FE799059C C00A86DE9E5092A262B9494958B56D9B7CBEFB1C98ED61E534284358AB9557B1 225E7C9DB2D60028980185C50BF8DA54E26E7D1BC8FE5A22FC6B43C1BFFE47AF FD2758CAB48E15A1814683C3514B11A64B1E8E67107AFD0AE707F2D8826990F8 8F1B7068C38BCBB9259B697AE944F6A91BE737A3F467D74F1F6FEA9CE74D0A39 033DA195A48D37756875BDBC415700295884F87A85FBD4E8E32167A52B9C6EFC 2BCA674555A8B2310DEE8CC11DE295730B670B623B26C1157A539BB5E11FDFBC 3635F5C78F3DF89E99598FAB7C542F6893C901A51DEC9A11DF3A44668F0AA7DB F37328F72B8DA820AA8CACB0AEAE6A07B9106DC22D479D03C917BAF213515403 2DA8172515722F8B5F16FC45A59EDBDFBF395F3468D080063A58E63BD2776435 9127620201E8649A9CEBA6F7F7FBC752D187720F47840A610E2E8023BBBD6B64 8373426416441495040DC06101F71CC96FDE121D2FBFE6DE91A37D2A2CCC5697 6B398CB4F356F832B3DC6D3EAA65DA412FB1EED50310FADE48666C3DB3973D02 12CEE4D2ED038F04471108EAF59AFDD4C4A28A4B899B32744FDBB9A55F1D77BE 7AE9FC27066BF748967236347255931812934784028765FE477A29F0568498F3 D09730618934F4E75B022FFC89F10EB2C4B59C263F7EB2B46DA2604F18DF72DC 443EDE62E18F8A75481FC4FE3D327C0996D870039111D06C5D54F9A717879F3F 38B870309BD6BE25E03D4EBC13950F14CE3F02ECA10BAA9A15621FDF587BECCC 162D178765F1BDC362DF9523CB1F8B57DFDDEF49052745278C772CEB29DAC19F 6B392AE802F26FB881E23826595475699CC854E2F27F01153555423B11CAC0C6 DAA2A9FDFA6392AB5C90AC89B0C34178B730E35A5F1EBA4F8983536EF491FD34 8BD4E5F5EAD8143EC34853DE70693A59B2B5959E3866FA7D970E948357045928 112C91F6BAEAA410BAF8BC714573A39E3D3DBF71FEEA4B9B8BE2BDB27F0E22B6 680EA37A8349091F14378D2D0198DA1A4AC6348573572EBE1625FFE0CA8D1D42 7F75EBC44FC01BA9D1130E8E652A444AA9B404C00CC44C190B786F802550FEC6 576BA8E4C24222C427699614ADF6D7D0F781A785620EF87DA02A411B94345646 77E3C8E2945D9DF8C9F74EDD42BC70A3C77AE5DE7C7A5830C5646170F105E788 14894886E15347BD16543080A2CA2253D4B058A4A34C0C925AEA0A52FD563F5D EF4390D74F6FEF5FBDEBEE2E56349AED5954C28792B780BC87D28E9635D8DE95 0CCD95DBC5C79635B6C41264090A1109BA08F9A7C8F0D415CE5E238FF618D25F 888B92EC5A597C6731591FC98D01B7F78D1EFBFB3F46EEDF328D86C21D02009C 8026864861219D73AC34BDB20CDC7949EAC8F0A6A43777A6D7AFAFDE77B66AE6 BB172E6F9E39159D5C2D232B8BB2ECB2CECD66F2E967BA2747FC430FB0CE69DF 1AC544E889B39EB4DBFA1DD3D008F20D198A0C3BEE70E1AF9AE46A7FD14B0774 BCA2635A433589566C063D8450B39214513DB0A97EFAF2ED2F3D3D5E5D4F79BA B8782782888BEC7CA24A0D07B782A24CC5B5E58D29E00C27245D637D74DF6D2A 2898516D194B7528EA5045CBDA842C9D5DDB1CD5328A1182B4171CA79908075B 9F2472A4C4E0372391EC6E83491EC9E46B4444EDB2C9F9B726C2EFFB9DD7FF43 79D855780D1C0C5FBA74F74420188838414494F80886D3E30629E1D823257E87 08124BDD0CA6E2CEB8FBC9F1EEF54B37FED9E69B1FB66C922E4AD9A4D81695E8 60EC85DAAC374B747E63D0F715BDC9106A1CA32F3CAA33FBDF81F2B073A0E7F0 DDBB9DBDC34931AF8C26389C83236870B00E1760EECC025343B2B520F930FD5C 74F0CD0B377EF9E4990FD2E1AA293A2984613D4F898953A4D1F0D6FA17D93018 78F1C6624046AA098A9D37156ECEC8490DA52FF2063029A0DF4C25E8044528B0 9C020484F690F0DF697218F36F4D76BFB17F704DDB290D54010D297DC5918723 760F130F0C460F9E585B4B5D8FF101611DA815AC8BF19EC005627EFDCB195F6C F80219BE03EE823134E6A61152E5F1E3C5BBED47683690A7C8ABFA4CB4758D68 330459FA57F914A95FAD0397CF9490E0BCDEAEB4FAF1CD727961390B248117B7 AC7DC382B4C1D781FF7AC97562BCDE02EAF86122A487CA612274E46B2BDDAF5E BAF089C1EA7D92C7111F6122640025486CBCDCA3B72DE0DEA419273B81F9EC5F 350F3A5B816D1818F04169014A755CA1D3B84881E618C2B38182674F4887486C 87721C2F11D71C4E086A224B884EC455119B47F0D1899E4A7A8A274591C76E3B 15D71AF3CCCDC9376ECE9EA99AEB90387116C4128D9B4BDE4235764984BD86DA 8EAC3DC6E8A64CF6CCE436779D84BCABB7F6D8E0944807BCD963C52C3634234C 7A9A311AFE681763A30EC5CAE105C5B1843C03F8A4834E9BBCE9B12283380E58 8A243A18CB63A882FA0BC59B1A176BC83471830D01D1ABAC528B3B43762915BB DB8B3789C16955A7B4313CF12D5624A436823450718C877CBC46079B241DC964 8389015CA6193FCC3A3D2C3EA03088186498C255D3C3BDEF3DFD8DE7BFF7CCC9 6EE7D1EECA3D2656ECB083BB70063E370980A866B9167DF878E7D367D2CEAF5D BBF55C597FFCF8E62FC53DD128DFD642C9978CF30E7A05A2BB5822211142E4B6 DAFB1CF3208FE4F97D21116A6F3CEB960BC3AD9E035289829E1A3A4360535370 8CCFA451A91B3D74B2FBE8B95BD75E39BE9F985931D9DE2FEB46D248029CB2DE B58D6339CC713D05AD3F1228B520C4E3049A0168A5FD98AD404561452FEE6CAD C2D9CB77B6F7F777F905E5AA4662C9C275513AA41093C636E86E6D7CAF5233E1 E0E207156FACD542B3E42886869E8AFF4F409149A22D941E155739F66679A220 8FB25CA0165D8F240B11FF5579A06273A217A51BC9B11F7DCBC64FBDA7664436 0808AC74650C6741473E2C615474357A7B426A153AD68ADCDE99DCBC31BEFF6C A3ABFD17CE8F8F6DCAD36BB9307155173DDABBAD269FFA4EF7F8507CE87EDA39 736A156784FFB9BFC22111860DE2B0F9EBFD29311B78B562946B45A31EBA5FD2 FD85CCBAECE46A2109699AA4F198D11B9B43968E5117C42D9EBA7CEBC9EF6D74 D6E29D5ABF720899741F6074696809A084F2B81B8938123C852B54EBA482AC0A A9BA5234AC5CDAC0F1F45ACD81FA618F3631D9724648BD80B55F1C861F6C349C 5F3F354649DFB0E44EBCA77B808FA81F2B5C8A23E265FBD010F23724C2A3FFF9 FF0F07DB19E1B2DA0933C276FF3AE0577CA95E55D417EA6183109BA9008C1B1C ADFA148D9514F674ABA6DF642FAD26BFF6CA777FE6A1D3BF34198E99BE398482 C10ED1F23B815F22A40EC34DC685C9A0110CA7174E30863D2EE2248922094101 8D2CFCEC8B4EF494A88AB2C974612A2BA214992BA163675C434CC15DCEA12863 4397BD22E91FDE7CFEDDF7DDFB9143FA383CF7AC810A05EAD4A893D65081E149 F7F46E8E34193F0643EE3EA02F5D695DD906F542EBBA50C8FF14AC925C31EFE7 E248C920CA63918236AB5072215F86BD68F537B76F3D3B3B2808C037E11A2D89 3BD78DCFAC644F6CAD3EDAED6C19BD4A48876BA30E20AD0B99502E35D4EB688E 4BBD899585401163D0442036157E8BD41BCB41E4C25AC8F33E247AA842B8A7B5 C0408F625BED336DB360E00CFB44D92AC810126840F4A8926DE95101FF05FF2C DFFAC678D28E044D0BD43D69A9AD9C303FE20F43512EE76784D62B5187B51F43 00AD03309E347657033A775F1FF5BEF6F2855F18ACDE1373C00D432BD73597B4 86F7E0B7EB22DF97C60C80AA3281F0853E7F84452C947FAFE6C2C09F420A2C35 7EB705A56882727CB0015912A4E1973A99A0D1B0498C67B3E35A090A43413431 1C0940B226A246E1926957F028AF84A22419BFA8A23F9DCCFE9FEBAF3C3F2B2A 05F806806342892C913EA8E035A4510AD0A334048EA575D57AA23FB679FC4362 C466F597263798A8CEAE8CD6D37EAC2C606588F5B8E0017F5F93C4B6429A2E82 B76F86C48EA3B8CB4429F56CC800420D2DCB289B5364436518BF690E154AD164 A5D12870CD860BEC52DC8D1B0D09B4E2579BF220B36FAAF8A99D66364A907805 4937A1283A69BD7B9A84D8D989D636A2D5E3ACBF267BBD54F6E1A3538089B3A8 E87029A2782FEFE4BA19C45F9B5FFFD437BE18BF70FB27D3732BC79A21ADE3A0 E44E00E29BBC76034B3B557129C97EE3DAEDCFCDA61F3C3EFEC7F16AC72CC96C 164030ED712171479324924712B280C5CACB433BEF13EE2572914D0317DC1E19 F09260C6EB2B38BF4CEDC99E38B3F67AFEA900901A9F181C7FFF3BD4AD2BF9EE E1CA616FBEB75B2D161CA934D63B26F9FACD3B572F9B58B85B0D471C1BEDA920 DD840E923221DDF59118F5D5CEDEE2F68E3B585493594F8FFDAA2F54AB8DF5BA 7728F3857D05DF3953A8A92B2DA023BC9EF4882DE1C93247C2E1AD160AAE2524 31E0375DD70C1529053A9D09CD6C8919842400F3E3FE79662E37FB1B83787D10 650FAF9EFCC51FA267B638817A061018CAC74840A5D897F70BE20445BC1AECE5 A81460D9CEEEE4EEEDD5732721821CBE747EB0B5294F8E4BAEA3A62EBAB477D7 CC3EFD6CBAD5153FE411212442BBF84DE24D54BDAB74B84D183A9061C245C020 8048A880008B792A32ACDA9FD479150FBB62DC83FC9F600313FF120E0BE0034F 903A93156CF74F9E5A7CEBF2B84AF5DCCE6775D1C05F4ED3EEA03B1A6759E4B4 7205C1058C72A1ABB92108A9714F0799A20A8F06442DACE995D7E6B42DCC424D E9D6F215C5595AB502828814A51143A7D16251858BA2DEEB2B50AD22387A9196 2C24424F8ED5AFC2BE2315D716DAFDED893074B8499802BE66DB6C99058FF4A6 9720D25B471316CCCC107F68622AEDFD9E50CA4A3500A8219DB969AFFB27BBB7 AEE507FFC9436F7DAC82C49DEFC4332145EA248E6FB085AF045E39283F334F16 65019E44328EA44C1274789BCF1615947F0A61F781A30BEA2EDDBA351AACD286 A27CAD8810E6C3CBC0EB65174C4F5D73BC16D737FA9FBF74F95477E547568F3F A88A4D5AA1DE742F538E43851E31456353536FB74B8F1030626D2807EB5CD5B9 360DF16B4DF8ED55CC4A09D013D90F280DE28C927CA19087E03A83B98C2F4DF6 FEEC60F72AA078FC2CCC0A25EFE877DFBFBAF6C64E76B69F66992B515752E3A6 006432BF3FE764A404C25FA877B238064C887AFD7E60DA7254222F13A2BDCA02 3A177A0641F02EF373EF30C70CEE02410480B52A0AE1D91BC75AA16EC81CA969 456883C672FBB8492BECE7A7E6819BCB5ADCE7ECABF5D35259262442DCFAF75F 879A8806974FB5F1C343A8451A522936D56EB7B17342FE72A5F78DCB173E3E58 BD37E609244227D71A16C3A38A1A2F958B8252F05C7CACA4414EA1353EE6BE3B C1486B70EE9DB910195B6C0B33AF9682AA8C1E17FAE549E721852727E2E76334 65C6F3F4830F1ED63D0EF00E9ABCC377AC711E484C26A3BA49B4829CA9A1B2E1 511365970F9BAFDCDAFFEADEE4DB4539432772806A73217DE18A9390C84BB5C2 C9252BCA9E6250FF42249D0F8578EF60782CC9E051723489739C2EBD857C0D4B DB453F169B0AD7D73AF1BAA12308331D4A3A0C57D8182D248065C8DEE8AE0400 56E0FA32A1CAD10A4E0AA9399CBEB863535BEA8358EF9362B56427E66237C54C 83DD722FD60BAF34C648676BAEE6299BF6A25926DCB07B5F7D62DB9562DC1F0C 07755E0FC76BD9680C4109379E46FDBB567FE9CB5F7DE62FBFFDA1BE7D60909C CE2447D5419C929710DCE7E54AAD763A83DFD939F83F76EE3CB8D5FDDDECC450 2FEB5E282EAD8344DE210EDE481AE1C536BE28334BF5ED50395311AA19D69E52 D662C2B053819C26CE94C08574811F195B48A74EF6C68FDF9BF5A2F98557C461 55DD895C91A32A402AF2BAE0B8AEE0D59871F51EBB65B833E15C2DFC228EE432 4B64377631DAF2C161ABE779B93FE585492D7A77933AF60E6A95F074756FFD83 A70CF10472569A0865CD8DB2B15DA2C0201F11C2A2DFAD0FBA762E24C2481B74 2922100750C90D7261050541AC25B54943144D279DCED3D52E4FCDB944C893F1 F0471F5FFFF03B759442A98BCBAC42450846AD67A7A213461D99DABF8C549B72 FB6E5D4C875B1B5635934B97BA1B6BF2C4B81696352526C25D527CEA19B9DEE1 3F741FC73DC27F4D4DFEDB5E4033481AB8B6951BB820CCCB325B549D6B62442E AC6C382EF4DAE9FE819D95E3D1C80C1312730E35A101A08B0A590094F60D3630 0677E9E2D3DFBAFEE44B94A489C886D938EEAFD8B42369ACF2C36631270B4A6B 28D335BCEC0AAA0C745B605C359808E194C2214798AAB0DDE7FDBE79C8B85E7C 8F86598B57B4C217A4BD0B28A321110ADF4BF2F8D16BF1C0DFC59527890AA858 ADB0A37D03D20E19C96BC4641CF96B88F0D5D6286D57FB09F136739E14EF5763 896F94A16D39947010FD7100688C309E2D8BA7C00B8259245840E50A8020A611 04A71C8F96E9BAE89B43FEEF5EBEF8CB6BF73CDA1D46ACACA31CA29E44173D38 2191F23CCD184D614905E9C9AB04432CA59003B3512CBAD291453EB93CDBD9AF EAA4A4663F7F6E85C5925F7C65FFC4E618AA75DE38299881148504362C37F74D 79D7568FC7EB9FA9772E6FEF7CFCF89B9EA8EC7A54AF8F38AD4B97C55512C36B 4F2DE2835C06617C78CEC63720E141D9C5BCAC2B1C077A1D4C09B8A582E21F6E 9F80FBD0488F7D91C512273E24C7B723F1AD7AF18D9D1BD7EB0602D0E97EFCE0 78F4D878F468B77B4EA913D8BD2D75ECCA9842918E90DBC093ECA26993ABA14E 8B0585C8C595F6EB0310CE78053714B0114764EAF564D14B4DA07A02EE1A5682 A0C82A32275D6C5092D070D6F29C96D58B6BDB352EC0C1F06BEC654D03392B34 775AD25E18F8DB9666EA2C6B51A37BCDE470A935DA8E89FD008FD9F06F408448 E6C55F1A5AE08CD0ED683BA7E4A995FE5F5C3CFF33AB5B6FE0BC4FE80A114328 B1F1FE41B823B8B426FC6607DECB96E5DA9A88211F86D160B0415B8B73F8BDC8 BF5F8E16CE98B871961F2469A983FC84E374CF0B9050AA7280ECDAE1437291D7 2420C1D9382C5522BBC7341CE0377281150AD96959159D057CFBE18C76BED1B8 3FD9B9FBECC1C1DEACB8248CF56AD6B1C5D5CF1A6D881185243A2A224932A871 9B1FDEBAFFE7936E329D10A56584510CD27D179DBC517617EB18E4F6601122A9 56A259703B6AE849137592C8640C509FE45054470C17FB88F2A82676D8674EE6 8E9555CEE0D645E9426626863C50D32AAAD1E4CB26196F6C858C66D489C4D765 B00F3C1002CEC95D51DFE9924B6A76A598FC48F6F09FDF7C295EEDBFFBF403E6 CADD8DB3C79B336333C8EE5939995611ED0EB77BE91F3FFFEDFD3FFAD420A9DF 7AF2F823F180E5E54C2A2D5C7F37EFE5F6CE60F4C9AAFA9F5FBE3458EDFC0FFD CD1512553E0E51A4583619717D467A0034258EBB202F080465DE3BCD7715A937 660AEAF9AE65A407CD761A2494238DAAB00A89C4A8835699C66E7593B79CE9DF 7BFCC60B2FADCCB598A8728F5355B9A664128919A8F1A69173659968B041EABC F01B2D622BA2085E8AC0A612624774922F6AD2286CA556DAD6808D9924C80742 357E9CFC1B6530BC311EE11E282E9922B78DD3CA9A8E0D5A83A1AD18B4968EDC B9DBD6287AE8F8EA10C5B2D1C50E4545BC968D40FDBA0435A7984B7BCFDAC58E 999DED27FD4D91BDEDD4899FFFA81AF6ADC18A1E6D0DA4C5AD7483680DC0B362 46FB85AD4CE9C58D5BF074BB5BEBB6AE272F5DE8AC8EE233AB4D0478AB2ABBAC BB43AACF7C978E63F9C1FB5876F6ECEAEF525BFC9360234A83E76CA870E9B2E1 E7CD36E0B72AAF5C213511F86E0CF694E74D71FD6E767C936EF6AD6EA026A955 91A0A22469A2D48A6E2A06CDCE62FBD98B90DE331ED9CAAA85650BC20B460F66 BC500EC20D8EBB954122057CE8DACB4141AC0F330C8678CE0F302B8184EFACB1 B1A68D40717081CA95A441B3379BA2704E6B0B1176DB83F8345E302F1484CC04 94044377B96004F1FD49CEAFEB1CFD63E8EB6684AFFB628FA8C27F95D8A5C341 119E2CE36738D8E667F0522B5DC71197B87B843A788D9FEFC575246A5A3A33E3 9A3B3380E7579A46A407851E93DE27D5CE53F5E17FB7FED0996A5166458E9D49 9A89D847A6069E36447C0C41061B8F7071BA0099E178273D32BC57EA8199EE5D 9FBEF4F5C5F55772F3C4FA63E24EF57977F38151B7DB983C67BDCEBA5CCC643D 2946F1AD4CCEA6E586EC7F6F7F7BFFD4CA908E6E7CF7A9F76E6EBC7D3C3EDED8 7547FBC831A9ABA8B289D78B870C47B24620DF1EA3254EE822A8070F67F9A268 2C8DBC2E4D84D1CC5B3D4089A76955F2AAF2DA580A5B989911F1BE105FDCBDF9 E78BD942D0B767E27DA3E49D83953792640BE79E8DE9D169A46A5C0FA1B185B8 29E0E2C1C52A85DF406ADB7D5EBC300C86E9EBE17CA85EC21AD6D16375E4E839 06EE0B6BE7CB4765CD72CDF3FBC6BFDABCE69BBCBA421AE6526D0D8568DC83AC D0293E5AEE712DAB39CC84BCEBA467386116449868D06F16D55FA0AA996B7360 DC2DABA69CBE38E87EF1C2A50F1E3FFD084D4F16F506731131688787A28AD44B 0312D4BCF7DB8ED80F602D50F59342D420F52271EDB2A35F6B6E3C3EF4ABD334 D8DDB9402E7D55BA12AD709B76701EA8CE4B6D55B2AC125CAB11A9BC7490E716 79A468F14D50E49E5892D76A329DDDBAB3F37BA477653A3D682A1D447828AE30 F9212DF213191A95519976EEA1EA894EE7078E9F1C55B5CB6791B5DD28D6B546 1521F4D54618AD503645E3F1C25E35F6A9224878DC25CCA611ED24AC93465122 50E148D89CE791C50D103669E804CAD0B881B70609B1B4718D0DE45AB81A058A E28AA3F0232E2E6232E02862297A33D9F9C66CF26CC2B6B3F8C9F3E7DF7DF2D8 E5ED3B80D73EF6E0A3D3AF7FEBFEAD113D9BCCF5C147DEF0C67B065B66752517 E9B0964F6FCFFFDD0B4F5EB8F0BDBF7BFCE407924C745853ECC71340269DDB83 E1974CF1BF3CFBC2C5EEDABF19CBCD349D555CD83446A9EC3266E5AA7323C018 718CDB51C4A4B84A25FC6784526E1001396EF932AF7E85AD3FAF2F0007C097D8 847A9585C42BA3028268163D3B78C77DF2FE53D32B77D89D8ADE29C9C208D5C0 078AACCCF679220FC527541E1E34F5EEC98DC4B2400AFCD9E895A691D91C5600 89D77DB528A809F55835430A4F9456655C9791C8702C8B74CD126D056C2A0C95 246F309F93D7901B5F433C0C3B8521A286993D6E12A23CB7BF307EAC88D409CF 871738FBBECBA2678B291B91335B697FCD9CFCB9F7CAC71EAEA14807E0076564 17FF725249C0088E5590074D54175199D6757EF9669C25C9A94D5B5493EFBDD4 1D66F2CC6A91B8B834E58067DBD4FCD98B554775FFCEC3343BFD86D1EF519BFF 76B0ED691533DACDE130893E4A84484C40F681F3A0CCE24B87BB309B2FDCDE7C 3818EAB574214C4743148CD02B944BE56827CA78D960F99A57646FAA6EED9903 CD6794CD0151160E8A8E52D952BB52DB0A89E40E92A806F05D63AB1CB5DB5072 092A506971A28BC430E4B5B9462007000A22F8E0342062C88E803EBC8B77DBA7 4209EAB68F859A2D0C65F359841E849AB56312475E0D916DA7CF1EF5B6FE0665 99575BDEE1AF8720CB116A0B13112B156781E40A6577DA0018C2D1E082B80A8A 4D7C37F06413284359EDA242418E309E671BE7D6E6769FF3EBE3E40F2EBF78EE DCD95FEC6E6C4016E93645556CB06E862B9070924BC08F6869E9B7CB73F8C858 9C59E41F476BC749B671B83F7FEEC677A7E98C2B76EBFCC1DE70757A627CFCDA 4132720388447552C73DA7CA95AA6A62FE62A29F7FF9E65B374F7DE3D6F5E26D F73517F78EE58B9F3B71F2616DD671C198D53135D241A52E71B28E9B4600B129 3AE36061C868543566BAA817798541CECFC9292AE2C3C9704553F7B2DEA2A976 45BD279A1E93E38923C9F04B2BE4FF9E5FBB7E65FE2E463FB07EFA6D1B831359 3470AC8776F056C13B8AA062084E1A28EF80E2BF0C4BE5C82EA72318CA311EB6 7B2C6D83BCDDEDA3AD66FFEBF94D4725CC5137DBBEBED74D8F0CE55FDFFFD6FA 756723440D7B44875AB2C02D5DA6DB57D3E951CDDB66464C9B7E35DA78400989 50A35D1EF2A7355D687B60C92DDDCC397D76D0F9C2C5CBEF1D6FBE2DE91FAB9A 35673AE83187EF4D60224495BC6036D9E63CB6EC5EF8EBCBC591351D0B128FB8 30E8039E5D922C96A651AF1AFCF89953CB7925CB9CFF7D55E0F2D79625145C97 E952F110D97254340E6A5A92E7F38B3BF1CB8BC5372777FFAACC6F52143B00CC C934CB50D50E778610FB48D22DC9A988BDE7DCE9F777460F1690BAF6275C4D63 A2D1DA2081621895EF0D8D8D89B12EC6F38521125BB7689D0AC942C0C991ACD7 15FD5E14A791278F788E5609D705EA34D738C0B916B05252239B02305089EF15 134713D31A85A3EDD8C544C697CBC5454E2EAEA69FCF77A6DDF4A5EFDD88FBB4 5B0170A4E3F5F1F0E6DE1BB3A1B86F757B76F3BF7CF007EFDD2D16A7BBD1E9F1 A649E7E9E66133FBDFBEFE85AFBC78E1571EB8FFA76AD9AF9A9B99AA78BD4AE4 0DD3FF17CF5FFC8F9DF493BDEC3E99EA8264B20BB18A48C3F47CDDBA35C5BA91 549D08E24538C13680402F7042BD2FA0EF26047E3A824580EC0D3300CA1216D9 C266697A68F222B35B6F3E1B3F74AE994E762F5C1505277B75820EA1B85466FD C48EB47B0BB49D8933BEB460E438945B122F5A15A4608668829A1EF52B4226D1 16596F99744A651A95D7E1862A5C02313E7DE16B155679BF067A746C8E944996 C302BB3C4EE150FA5915F2487D00F69EC75E1D85A36C3F630B265F6816B34E75 ACCF47AB2C7ECFB9933FFD7778327425711D5A9B69CA62D4E4C0E2B021DCE67A 1AA78CE7F9E1956BFDF1588C7AB6AC0F5EBAD81BF7E2532B8A6A80B9F980F777 B9FAECF3BA6BB28FBE9176CE9C59F95D6A8ADF0E3789045353D7068C3090A561 7129D48FC613FF999FA4585B426A61D1FCD2CD5EE9E253C75C2F820231AFFB3C CA0065D746C591688A69842ACCDA2D2AB253C2E321DB8D9B38B750AED66A5EE8 1CA7DCAE8444086572E35483E67CC6BB7BC339864408251C324BB0048F50A4CB 55F8C173F40FC22F44471BA96C1D0CE6DB96175D864484FFD81D451B2C262083 06DB001294425F33D7F1068F2C04D3BF25111EFDB7BF7138039636F2581A37B4 DA63EC4F52701D34A8F28B4814CE3E942180E3B125C9711B1E7E7F91B29AD0DE 9C929D666F6DF8BFDBED9D9BB77FFBDC43C78A02CADAFDA466B18C4CA491E49D D4A6F65ABD9C54485181EF01C0A9E1E230ED2427EF258D28A793BFBCF0CD67AE 5D7FD33DE774213F75F9FCE8E137FCECAC77536E67C6442ABBDBEDC0CF3FB350 506B7D355A3C73E3EE07B6CEFEC5CD6BDF3A26DF72CBFCECFD0FBCB328EE5DCC 56FB7296D04957B8244E09ED1B2C40518C42902E6ABC03F88D8A52EF1E2C146A C1C4C1F61417E5B0290127D1242CBE924FEB41D7567655A687F9B418F7BEAD66 9FB9768BA6FC87368E7F24EEBDD9D135AFC4E3E05C260C2A1D05453A96FD4E3A 8EBBFF8C965058481CE267DA2FE7B1D63924E82484EE507BD9B025CEFEC681EE D1D4E9D5FF6D96AC613C2C7EBA11B4D1BFEFEFFA4478245A17CC52E96BC0639B 830D79F565049D3FD752035CE005F808847B1328DA42C2F20FB64AD19E064200 2994DBB7F6B6515346BEDBCF3E7BF995C7A3F43DE3CD33CAAC39D2E72EE2FE06 722F16EF3D833C22F4077899085B3D21CC16CC97FC3468C1634B81B469AFDD70 0C6F8A073CC7DA9BC0DD522ACE4B4030FA7D8B43AD6D0AD664181983777A60D4 A16DA3FF08B48F999AD9C161B4B3585CD7E622215F3F38FCABFDC31B84C0F524 490A77813595431176007638441C33F24837FAA1CD13F776BA09E4C919CA5145 9E0F14A509BC0B9421246E4174893A5A0091596A448FA74C41FC04BCDB08897D F734126B4937EEC4F8A00006354DA99B422B08D571C3658EE01B0020D4D0CEA8 055A60A37869C35CCD5DC6D2BDBCFCFCF695ECF1879FBC72F3CEFED4A5E43B82 ACCD494E08E4E69447DDD2D503D9A1E6BF7EECFDFF1F65EF016E4976D7079E50 A7E24DEFBED82FBFEE9E0E93734B23314A4848489665839025BC800DF8C36093 6CF8583E63AF65EF7A31BBC6BB66C1EB4F1804B2C064590109C18C66A491349A 9ED43D339D737AF1E6CA27ECF99FAABAEFF54832DE9ED64CF753F77DF756D5F9 C75F70BEFE125B73EF78E31D075285FD5535812E8BF0AFCE5CFBD217BEF61D53 93EF5C5C0EF281AD767C2E76F2F93F8E9D8FEE5CFC6994BD6B7E3F1DE6FAEC86 226160B5AE5B40D994FA9CD9A84E958D7D18B281EF2354BBA69227C62C9D1B6D 59B3ED0686BDB93D9C037898921C1423BB76EEDFB5D8BEF7A05ABFD53B778D87 C065F391A7C21CBAC50A4551FA821598FA22174228010A8EA0266A953E9AAA10 1531961112B40E8CB78FFE6F002FCC07B64E87E087D5C6BA01C8817501E671D2 CC83604C31C6CCEF1DA8A05DF8D8B74D84D5DB944591665916F85229EB1AE167 51BF51C7AB539E58F356FFEE7B9C3B0FC561E6D9BA504ECD68066CCA41BDDF41 B11882AA7AAF97F7FADEF414D6212A4EB6CF9E6F4DB69CF9A62E4064C6874DDA DAA1F9674FE62C0FDE77176E1D9C9FF92816A39F33A824AB82CF1564B862AA53 E0B00DF0DB4051300517010E990AD2BE4C858702F1F55383B3D71AF71DA6772F 64EEACCAE03348C1CB7D0E4E2C9C5B3A6FF533BC1EF19B111A70D417BA734F07 311F266A94A92827FA894F7595C641CB869BF123189F42B1E1E6B880676220FE C27C4387030768B4C6E829930CD666A4223F96456D9108C1FE557F3C87621B14 AA709527D51E7788F1808D54AC0B89D1EB63EA9EEA98943E22BA2BAD0B2A329D 8A694615D05A2C30346189024F20FD196C007B739AA40CB6569E502C964A87BC 3EB36EA691AE56518FBBCEC456B3F97FBEF6D5F7B4DBFFACB968A5A1FE6C231A DB9683329C077EE4EBD7948100515ADDFA47CC5E17743E8BD33AA3870E73D5C0 03FEE26B2F929AFBD2B98B97E2D89A69E2EEF0D1C6BE033DE76263DB57C2E6FE 49875C8EBBC7F2A065D77EB37F6EC3B7DFD25CFAF285F32FFBF9CFD86B8FED9B 59D9BE75A78B3C5BE9939FD47D7DFC5C7DCC416B4F573C28B2A49FE82C680D63 BEBD3314C262D4D3F91F58DE667DCB29B8C6E9277AA493613DD84EE32677DC91 1AB482FF1A5F7C29E9DEAD9CBFD7DE7FACD16462C8541C301BAEB76B0997C658 874604E667B9F074A520A109024B4B38A2B0A647B864F855ADCC9E7D5CD51192 3136E95B105D76EF66D511AAF174B4EADBF0DE3FAD8A22BAE44198954D4594BF 4DD848EC6641AC4A838AA20A46722C32AB000B62BCFEA070330027182942D843 11471D216F88ACAF3BC256FDB367CFEFCFF9772EAC1C10640EA91606BA08683E 5160CBE8FC67442BCB44583CED66D2656A40662891300529D9A5A4C85AC56722 06EB5BB994140D46C536AAEA80B1DB22AE6CA7F0F892C2340E190350838C9000 1297C6621315DE5FD8E0FC75DB17EBFCCB47288A50475A2786F133C3DE57A3FE 39CE238048C0F2D6533A35C2E7D2DD5FCE65C3C50F4C4EBED99F79C06AB413CE B87EEE13CB1239069D2249C00D63C4745F07BC5196F31AD267296328D7E79B1B B9419D206791E5347C5F3F583A3EA31CD48EF5FBCC94359256A4AF044B75F10C FE5CC9B6A71F66359992EDBAF59A1327A3F4E8E4E289B3A7A766E6F7295FFFE5 9D00BFAA0683EEF0E2707895CA6B9C6F263235B21CC79656D0952B0FCE4D3CFE E091AD5B57FFCEEC01B9D2267EAD96D59EB87CF56327BFDA24F2EFEF5B3E38E8 D6148A79F00D12FCE2F50B87D3C10FDCF3E8C4B6AEFA790CC2D0C4D3B194E775 A2F467A701E09A9A298C8263D01B377672A41009623AECF2D2ED0460FD208366 9E275D7638B61BEB4E6D3668DDB31AF370FD9533B39CE158DF0796A5FA6C3158 D0CB021D553DDA65F6294155D880C0799E9ADF902A5719380E4246F1439582B0 4AD960C09D752DBE59F35F3875FE81A5A549530253EE80C00B8E4182567AC6B6 A432DED99DB2A162BF2EF726421871412244452294630113332485E8825D65C5 9EF34C7C2B74C5D1767DBAC58277DDED7DCF9B534F87970CAC7D758C55CC824C 10C3AE8C29958DC2CD4D3B93EEEC2CB0D1E3B87BEADCD4CCB4BDAF99EACFA09B B23AAA7728F9CC2B61D6F7DF772F99BB7B7ADF2FE944F8B304E4755881D442C5 9E1D97C101179614E0D908C90D14A54055C6BC75451DECC7CF5D1C7EFAD9E1C5 75B47FDFD4FBDFD478E02E204D25FA0D31E0C7329520D096D189D4CD11D5A5D9 5698F622B2C5695FEA442806311EE6729822DD142619E09973D00B85F25200EE 5C5F28079C3B61D403AB49093206F0807070AE930632030237945618CDE27E83 182794EC046239F5984E84AF134EAB340EF03835EE2E486E0F8CAFEB36CA8936 AC7E192D67AA30E8CC2CC8DE4C1F6CFDF0A632D3EFAD16C4163E4FDC758537C2 E18D9DCE4647277FF08071758510E90CCA3618EE31E75667F8C0FCEC23ED89FD 8D5AC3162D8A6712B42FD3C950B7FF1185C42A90AD7ABE3C2DF11F5DECBF6F7E 6A61AE3D39B7BF99D587D7B7FEF81B4F9F917CF5FE473FF7FC57EB53CEDB9B53 0774C19137AFB6BB2EDCB1DA536AF4CA60E37DCDE529ABF9AB374F86FB670F84 ECFCF5AB9DFD339FCC171BAE6A8BD1B4CD61536E21C9806B5298EE21CBCE2D16 29E4C779371C0E923C17D49236538EE24A609A5A48B7AB393CCFB0E5BD6A5BAD 8CD642B9CDE8A5BAF3DCF5AB28936F5E5A7CB3EBDC8D05CDFAC6A9D9C97D9AE8 FE0174D999916DA36098A0409EBF00771B022B36ACA092E58277E737BBCC2459 DEA8DBDAB5D7253FA4F624C26F51DC7CAB9247967FC7DC5BD07D1CF791A5B164 A9AA56B006D56D2FA4AA5D61C9295450659AF91248B080DF163CDEB0E213E04B DD91EA06CF0644BD3CD5FCCC99F37361FCAE950307105E50A8A5504041970BB0 5F009D004A222473563EA98294014515CA6F94A0DD11B132DD5A859D313000A5 C68EE70538AEA8192BAD5D42C66B557805189E958A13E6F3B0D2590A4CDA4D46 849FA2A84D40A6D9A0CA93000A6747105BDFE0484589EA627636CA5E89E2E7FA C393617843C848F77196AF3FBEAEE485D0C561D6147C15E1FB1AB38BF5C66C2B 6829D9C0320029B2C4E61C5082D24A240A89CA28A04D1C257CFD5D0C8B5F1A54 49206158C56C590FEC5A00945A9D36F82011BD94A63ADE7B09B6603D6FA55C87 581D257548719C4B76F6F51B178E2CADDE4D9A933DAE1B4DFDFC539B51DBDA70 A408BCEE283E978627A3D18B37D72F61719300B7E651BFFDE0E4BEE7AF9FFF9D BBA66B2BF738B5B9090AD481673A3BFFF92B5FD7F1E1FDFB0E7DA7C08DED1BA7 6AF6BFEE0C4E24FD1FDC7FFFB1BEB2D238F6416D099A31CEE7255F20CAAA89D8 E50C7CB3EC8C82F389A1D5C3A2CC88CD58A804CA809C1A2D4B1F503CC08E1311 65B76BC8B73A9DCDBA224ECCAD0C96B0023458741F97E2BD0AC8A50089B9D145 2E34E512A0B60A249C2AF5B251B53D2F86F995822ED1093675E8C674EB934F3E 73ECD0EAFDF5BAFE8E12C6DFBA7A0D8D88448D16B954958A22D5B92B4FE8DE44 58E0AEF726C2DD7EC318D7C13E4967C7C07B898F2E9168B9E11D74085EF19B3F F40E79CFB2B10584AD19F08A925C3189F348F73C3219746EDC0898EBCD4CE956 7B341A0D5E39373BBBCF9AAFC581B263356CC87A8F922F9E0DB7D76BEF7B082D DDDF5AF8052C863F05E61B60D94C40344E15666063356708F5C66CA5E4F6E8AC 06B0277D171423673BEB9F7852BDBA1EB4DAA3F9867D6405DF37D5BEEB20A83B 524B988A53149366C96DFDBE39923B83A41F918D9C74653E88E520C783140D52 19A628C9700AD2B92A037E1C30CDE1D88992FC0BCD7B5E5C61AB4884B959E216 8466C3A451552204389C454AFA842E2C7C1B1221DECD7F7BE3E938C98D3111DF AE172C7E1039264680A48205B0509A1194321DCBB971580078736A79EB043D7B E1DA5FED24578518F0B8E6DA73B5F684E7E96A71095B938A2636BA8C93CE305C 96DEE53C3C47C2762E7C21E73DE7FE66FB0EAB36EFF9759F790C814D610D9F4D B63E73EAFA3A99F9D03D871E9E5FA9D1261EAACDF3174E6DAF7F7A67FD344213 0E7943CD5FD3B72E4C2C676EDDEDD20C145B9FC8FA17B2DE07560E8E6E84BFD5 BDBAB33435D98FEBBDE19DF7DFFFAFB7842EC26D96D503621B230CB0EF719982 8CC824D535331984FA360D439EE7167C6209C07A468163A1529B2496EEE175D9 02A63F3B44E551D69C9A7B2EEEFFC5C6E5A3FBD6BE87CE7C472C2CAB1B4E2599 AB7CE233E486AE2E8EB8ABDB4005FAF40C54260C0AC0CC3C71795A617A5A1087 C702A17BEFC8DE9E1E8FF7BE52DDD602AADBD22725E4B6CC87BF75262CB424D0 58449B90B2ACADAA22E3FF55E8C88C0FF69E8C5BAA69A8C28F10467AC09790CA 24C2E2D714BC3848CCD58E54370524C2E313F5CF9DBD301927EF5CDB7F87C4CB 984C497DB9900D9C51031FA0AA808F19603D364C5859EA6F01C51E12A152E58E 10581184179FAFCC94003356BB1D21AE382060C36858A2E5665D16026E0525B1 40BDC367E1A4FA6C856F29C8E4986C0CE1D261CC483BC18E08E651168823E8CC E9A658F7642461C3DCBA82E9D792F089DEE6C9B8DF09495F9F7233397609630A A7C02FE1BA47F4A955C764C9B2F6FBCD45C759B4D9B4E54C49E46620880DFA2D CCCA747831A621B6CEA646B14BD2CC01B94EAEBFB3CB503D70DB9E6F251C8DB8 4EB5B90045387D483B2477381ED84487EDA98CB998BD48FA518DDE2382F98188 1C91A1BC9D1247BF6517DB167325892CBCEDB2AB5972228DBE940FBFB1BD95A4 74C2AA6D65E2638F4CD4C4B4CBED373CB2D2A4431EAA5389FB6BC74F5EB9B1FE 0FD60EBEDD433B34F9F420FA5FD7AF7EB0BDFA4374CA0FBB3D9208C7C600A493 0B0AAFEAABECABBE0B77A906C36ED8B308B01C01208F11418370AF2F9365D21F 543A16496080C238A3B9676AA2514439581EC2283C952EF58CFE347689D83D0A 15A2CB3C1EB4A07B15AE48B4EAFBAB5D43A926288D1853F1701BDB6FD01CD517 7FAB6E7FEEF42B4DC77FDBECFC4C9CEA3E25B6F4239E32507A0ECCF4A34C78E3 8EF09B13A179FE60D06F50E886105FEEF44BC07581F1029800A5EB9675261BB0 9A75B8E54ED4143F3AE1BCF35EFF91A3BAB2D1A5B30D221520AE67030E29E449 B473F3DAC4E23C0D3CE09176FA9D9367A65716D98C97372C5D808F021EF43179 E25CF7F2D589EF7E181F3E36B1F873588E7E128A4962DCB272A86289F1EB2AAE 04B4E3E5D849571940A2A4E00990E54DDFB93A1C7DFCCBE4E486D4D547BD565B 99B7E6A6C2BB88BF34694D4E2ACF01ED658062C335E7220747657DB4A24C7443 B4256557F041AAFA99EA266898CA414432015AF829A8C0035B53819B042D3D77 9559D882E32EC9112BF6B7E04667549961816FB6238896C800B3AE81034CF5C7 B2883E194688447DEBFA7F4F60FCEB1221B4CCA21C49B14C378028A1FADE725D 9C061C7CEEC2A0763DB08EF7B65FBC7EB9DF83E5D704B3671AEDA5C6D46A3039 ED353225129E06CC69580EA51628917169C5B283127D6CE2FE707D7BFDFA7027 5429AB795B8398D4D974BBAD4F751687377736E284BEEFE023F72ECC1F9C5BE9 21AB2792979E7ED251E442E07FEC85AFBFF3C0E25BB92D06C3B4DDE64ED08B76 986E3B90FB546FBDCBF2B7EC5F39FFEAF5CFC7836E2DF0E3E8DD5EFB1D2BFBDF D5E961265D577A2EB56D687E442161033A59A03132E8F27000C36DD8A9583837 7B3A90E8D5815D57223A00C36402A55926321120796BB5FDD9DECDCDF5C1E3F5 F977CC2C2D25FD763EA46E163748EA325DF6A64C7F1B301F6046251A44BFCC33 A69F0FB8B1C4804B8CA3B2FE2E8EC0AA92A3D87BFB4A30A3AA92A442F8B66611 9506F3E3C456143118FF354F40F5E2E3E7A0488A9582A85295A3082A2001C557 54C9A32FE5338A305314C6D26CD740A50C99498A8905425A8A0AC008A1AE42EB 4AF495F86ADDFDF4A5CB1371FADE83079633B186E93E42BD8CEB5867C145A6E0 A009A0843199031E69522CBD2146AA72FF578C3701325DCABDE13D334F647449 2A95F1F2A2A0A23E2765D1510A55149ABD45C70D625FB404FFE0628B535E29B3 104795BD06C23960DC32DDCAD3C22C52DA39B239D5854F465864B14DC1B7D2F8 E2D6F0E56EF7996EFF428E1278218A5C0F392ECA74744974C0B011D74D5B80AD A63E3E1E3D18D877DBCE51EA2E210FC7F94888C465DC615C870809B4B71467AE EE4B81E5A65C0696BA356A3789DDD02927136192C652C0AA0559BA8BDA767048 48531F8C58656D6FDBCE7C85BD51E811EC615497BA62C7AE229E305B2A50AA51 C475B1B2AFC5D9D32AF96477FD786FC8ACFAE119A7B5D3797763EAFB1FBDAF3D 578B508207EEFA36FAC3F3A7BF7EEBE29156FBADABCBED3AFF99F5EBCDD35BFF 64E98E054707BCAE954987FAFAC834199BA6B6F22CC1583D77BD3CC42C8F4442 EA0E4C9830B8E0A14AAC032608E0C20EFC63A66C4070339C59A00AD388A52565 4C516C4307C38CFC9A048E79A5CA5EC1A7CBE11629C41F8B98599A8E8D1FEFC2 2CACA47416030C730A02996EB17A2793B576ED85F51B17B6BBEF5E3D7024CD74 F4EBD9BA6A4E7DD8C9FAB038DC03402BA609D5C352E55A5401CD8ABC2BF1DE2A B30AC5450612CC7162E29ECFE20D2BD937EDAD30EEBA39BD77BEFE7D6F8D0F4E EBC6BE96A546F59A663CF27431F5CA19EE59E88EB9A1E433CA8BCFDFE85EBB36 FBD051DA62D0507334B4E35AC2C8F39B1BC75F6ABEF1A8F7A6774122CCFA3FC6 2CD7306B593153346F5B55EFC7F4E0FA4AA6DC6838201527A8E68A61BAF9075F F19FBEE60C64D66EDAD353B9459D8989EC9065CF37D8F2B46879DC86D1074835 73106003D30DFD721117BD91EA2039C028E47828742254BD840F22354A4C22E4 32C9818B0D1AF3FAD6EBBE1D196F5990E4A002DC85649C51CAA4D9D1EB9BCAB9 2EA12C330BAA3435C035BE1C4A6107F84618F4B7E45E4CC4B7D58CF936597057 6E4694F00D9AE6BA8C8D9892367104B1521AA5E4E5ED9DF30C9DE1694CD01DED B907160E1EA6722A17AD988209AC1BC0D0D8652925943980384D61AE005AF432 635124E338647830E15D73F25B32BBB0B37D2B0A7B494E73D4CCF0BE66EBF054 FB2D9E17F88D91E50C3CE7C2D5F35FFEE2E7FA2A0FE766AEEEAC1F9B691DC955 3EE0AA397B5C0C9C8DEE6C73BAEB044FDDB8880274EF81C5174E5C7A395123DF 9DE0F14FCFAF7DB7AA37D55077CB0D0FB960BDAB0F9B9531065EA5BA81E772D4 4FA27E2A737D2803FDF8E64480DF97B11924309B0205CC2CE3BA44D5492EB170 97862FF6B6CE0CA2C76796BFBFB93AB9B32E1A71D2103E2113C243D4DFA99181 837CA94B0705CAF7C4326AA586B666C4F0B841F90AA3A8A95F9C09B2F7508D67 94D56EAFFC3A51E5CC12DF96C28C856FB5BDC37B73633900204A7D9BF208A3B1 8603A9FC4C5441A8AFA206A9BE3DAA80C4A6B095A561A1E91ACD0F4A0A7ABF71 8784D193C0FA79E5998AF5E3AFF0A6147D2CBF5A73FFDBA5CB7E9C7CF781FD2B 5C1EC4D682BE5E59E6EBABA47F42072EC13205CE6835BD20458D5FB84F4BC395 307BFD023E6D644849A1FB60B261B1562446F2568DD5C16935232DB1B1267D1A C95E51495CEAAF33552E6865A91D41CA9459CCDC64E1150A406E98C718DEA4BE F62986D5576ED64DBA720F04F1C15B4B848475197D3509BF3A18BC92E45706E9 B0970FC3C4540B043C964D6993EBD406E33B28866731BECF6F3CC86A0F375AB3 52B13CD3B5197619D46782634E7547123008525CE6B6FE459607083798EB5AB0 65CFB82E38254AC88E8B068CF282310ACA0C88B87602A453D9E4B256C0439822 290F2C0FE51258052ECDF3A8855D27A59D7AEDAFEAF8E337CE9DD81C5CB37536 4E3E323FF5A1F9834D4F4DAFD6D6EC9AB545AE30E7BF6CDCF8CB17CFD141F72E 37FDC3A929727DFB7B1757F62FD6158ADB215F946E43E119E6D849AC6FA28549 7380B927F22656967E2A52987E53E3BA47CCFA85900CFC19405343DF083F2F24 06E12EE8D6D2CBE07EE614250CE74645CF9837EBF394997B4CAA80573EE763B8 19AEB6EC7B0BCD127A5F1167CBCA0FA18978F8727DF24C6F78340846427DE9EA F5B7DD75E703E1C0E1C996C7F483ADFB500CB34CB1B766ADCE4549DA55C5B4B1 1CAAE16264629C2977F9D9B872BB43006E036B1A4EBC33323B937727A783054B EE6F59C8CADC63879CBFF3E6EEBC4F47DDB6B43264592EC1DD41F4F2E96079A6 77B01D5964BE8F93972F8FC25EFBB123C201B8A5642C26B1A78BF0D77AB7BEF2 7CEDD072E3DD7FABBDEF6770DAF921DBAD81C635240DBB4C84E6692FC2BF01AA A310CB40827647EC60324AF19367B7FEF41BCDD0B27412D0C17DA231A4A866FB 6ACEC6B375BAD6E60B3E6E5AAE07DA5048E82B04CC4918E747B9ECC5A8A3E400 C958621DB27B19D61D613FE1C3584530209509F827528E48C67530D6958E6120 83BA15E1F036A230C1BEC375A9120B7D99B23CB70A0911329E6D9ABD2BD47F65 22047236967BA2E4FF9F4C783B8342199219841C2FD39F0C9203F53A0A5F8AC2 5B89AECDD84C6D6A61627EBA365BF35A3A8631AA8F954439D8FF71D03706B514 7D4774C4B78DE891BED0A10B62D1C036D6353FB544CD89606690D7A8C3A92E36 509C666EAE6A16F52DE1C82DDD296D882C1F46E18BA7CF776F7D3CBE7252C4EF 9C597818C60D09462E15B58F67DB2BD7FB879656CF12F4C4C5338BD3AD9999C6 D74F5FDB148CD8EEBD35EBE797F6BF6523EDDABCE6AA9AFEDE34855AC1AE49BB 110B1226F968344C873116C8B1EC2E0A8C16AD2E4678A2233285299D076B0314 A5F9C8B1BB2D671DF32FA73767AFA51F995CD9EFFB94C6353B77A8103AAC58CC 53201E9ED83046B68CEF060760005C55DDF9C100BC802383AF05E490E2E04A80 71A93169B01C51EE1EB3F214EFD5C22EFE18DECB69D87327F726C23D2FF2FA24 582AAC8D0F27C2C51454EE050294BA7FE513478A37537655A5C650B1FB374AD6 A5DA8319AB02FB92A7C01EEA29BC85650FC9AFD7833FBD78C18E9377AFADAC0A 7498B0659D08D3CCA314803036016E1758CFE3C2C2D5301F54817A282F41D1C6 91721E8C2BBB14335D2B0361910E3129BC370A584F018D29D74965D758887717 C0311315AD22BB579D6511614B9527648A15A833894031313A964C82BE2EF431 8698ABBFA394709C1D983550B0C84AF5CB5861E0DEA06A3B49A872AEDDD8BE12 46D7B8EC73328CF820E71D9A75691EA532E52436F6A258E6071DF68EE9D9377A F59924F661DDAA12AE0F56DD03CB667066D2B94B27095D43DB5CB81805AEEDDB 1618D5E5B92E5DF5FB03F48CA1C3E8749812E5EB6433089DA6DFA3B995E73360 E0BA6959BEC56D3FA68162828AD0CE29D3CD22189875293BDDB4BF70F3E22775 80F14073EB9EFAE47732FAE183734D4F92E939E5B413D47A61B3FF9F9F7AF2CA CEC649BF9EF7469360D928A88F0FBAB507EB93872C7759F065873A2C0D089A8C 651FABD821E0022F323770C0638F23864DFC000430C8A0738A0D9F9073F0A6D0 6522E8E3880A2468A8A3707774F9680965B4E3C7CFC0D88207ED464954990354 516E0FEDC1187A19A48CA925F144AFFFECC2FC976EDC7858D907160EFCF6ABAF 3C76EF91C7069D7A9A745CA6DB4037D737C0473AFBEE4984A59A0CAE06366A5C C4AADB12A12AF5718BC7D4589799790A9536CCFBDC0B9E7ABA77ABDEAC2DB974 39C02D95D296E3BCE77EF637EEC175E4409FE6E39C8FCE9D15A3A87974ADD722 9239ED4E9E1D3F9F59DC7BC3FE04E77E2E758309937A6CA3EBE9AD279E73EB8D F6DFF8F0BE959FD589F0072D062659987A405E57459D09FF05AE60811E12FA53 822024B7756077864FBF92FFF1F3AD0ECA846EEC5D17045271125835456910A0 491FAF34C5A28774C1D3B4886F295B2ADB024A9A4E05A942C304ED48D9136294 A91EE7BD540D32FD451566284C55022052DD17EA0E8E66B9FE6CA105E1074CBD 05F0E86D4962C913CF1EC5B117A9B6E5666906A1A13CE10455E672CA44D12211 2A28A0A4113837B7077F8B5C38D69751DF841AFDE644A83BBAA11DB20C7B9923 B9DB61F666E0C6813B3FB36F11D702236A02CD9FCD864464920B5D906211A761 DA1F7869E643E1C96129E7829726ACFC5960F933C4F6F4EF09B013784D7F14D0 21C7C8F390BEB030050677EE18739CEA3011EDBC7AC6BEDCB9DA0EFE3D5B7FE6 EA957FBA74E48141DAB5C2D8664928FEBD251EDA1ADDB3B2F2D564F0CCB59B77 CDCD12465E585F1F096B89D00FAD2CBF9F584777A2C4F3DC06267E2259029B21 1C64993B18C930CD139E9B0E0BE89BDB96C7C0055781C61BD1252B287FE8B883 335D09E041605FB6F2D7E29D59ABF516D67C3CC56D190EEB59E45317DB9E7E9C 1948AF21C30F32B52A2CFF04087D151D8E196A9B0589815B824F8D8E46FA0F80 A01342BB9BBD62BCF3BA412832027F7BEF5755FEEEFD33456EDB0B8FBA3D23EE 6A26E0BD1A51A6A9C26A1711BA3BF91145A15B0ACD2A630E274B81BD526BDFF4 9146BE0C4814AAB4D5030D01ACABA858A09E445B580D08FA46BDF62717CE9138 7EE7EAF29A904788BB9F58419C7916B40C0AD48480E16C7CC5CB4926C2E57329 5189B52B1784B850934063767CF9E856BF31E393C2C0BA689C4BEA6DE5AF6CD8 B8B8D04F2D9163941697B020F2170E64454B3D2E30B0F1751A561354A3705AB4 33B2505A00DD9114ACF0A8A33F883EDD99F0C1E31EEBD0A2B3574CC94E96EFA4 7294B338B7D294C4288CF0B013CBAB213F1DA66779B6A12007E8EB71C871DFD4 6A1F0BEACB0AD99C87BA2349942F75D6B0746E4B9470618D26B10E5A54F9BA5B 30165423D82C82322D548B19DCA26D0FEBC8361BC1BCE69C0F50933B45BD635D ACA3C0CF9C1AB80E531032663C63C2B2542BA7CDDCEA33BA51234F0E87BF7DF5 EA0B0C1EE71F3EB8F6FDB3FBE6717F76BE4E9D093F58418DA97349F6D246F8EA CE7594886BD7AE5DE86D6F0C876916EA2CE7223487D0C244A35D23F7CD37EF71 EA0B23E40A20D201EEC006C35458F3003FD4D2EF1D36B946C0016A01A62F0298 34DB20EB8922D01B508E004F891C2452817E06897017FC34168440635AEC38E7 C96A913EA6D118CA6CC5CB29380F18B77AA3E307963F75EEE2EA4EF8E8C38FFD FAB35F7FE4D0E2DF267222CE7A9E9322EE4315A21BDD187D73222CF374C1BAC1 E37D4229CC65E60C253BB804C589B2E2A4B002248C5EAFDB9FDABA1A32B6DFF2 D61C34DBD625436ED5D9FEF73EA2FEE6BD4336F2B8CBAE6DF637AEBB8B6D7B7E 32D66580ED38DB49FCE23959B7ED0796339AB95CE6D8622AA1C4D2476EE3A997 59A426DFF1C1D57B7F1167BDFF09448D984FEC1A301301C0434B2D62C02F11A3 852128C503A29F03669DDE1C7CF685ECE59B4D5217A97E871ED2B9C9A27196FA BE0FE2C835074D7B78D6C533369D747153D751360A402ACC0CAA304A72D4D7E9 50C160A897C99D28EBC4A21FE18843228C53C888092442A2339CC847604DA86C 30382F099E9963DDC0E9288C673247976FBAD9E2B62A12E1F89C9BEB394E84C0 9DD0719616C408552A697D33EFACDC88A86FCA917BD930A2181DE188802E0338 E410C7F5DBAC3183FD969416668E79912C8BBA3BB7AE47832E49722B4A2D0E14 A7904794600F9E76291D92F93A5048961960B9ED63EAD6A4EB80E764AEF33631 6C15D998F06B6D1C257918020E8937699C847C304CC39E629FE96DFFB7787BC9 A33F36B13ADF4D7A0D6B1BACC1C83F97C9DBFAA3C30BD39FEE5C7FA9932F32DF 26D62519EA40F630B27FE98E3B573BDB0D2C9AACAE0229028E7CAC2C3B1DCAFE 0ECF12B068E12050A9402C54D7A836034F5413DCE12BCA882319817369D310CB 6D1E6DA2F447F365D620291BAC211124B96CD53703B0BFF6748B005610A08594 EAC74882135E4E0011051DA14946E09466444888CEB81C642B752791D1DD7B80 D06EFEC37BBAC0B180C537B57E95344A95F0C66B926F5A06DFFE5BA1C67EDAC5 7729FFE2B8D12CDD454AD686B1B420E5B72C668B55162CBE027807500D2CCF3F 313C3C9EC954E0BEC29B580D893ADE68FCE9F9B3288EDEBEB6BA98E547897D07 B59B2977CD4CDDA02780B1516C2ACA1168D91182BF66B9C6A464FCD18855804A C79CA2825058F28B5499CB4ADA142A004178DC4D92AAD1BC4D7D62FCEF92B882 49D91A57E7C690E1F56D0538A92A52695927E897B3E0FF00614B66E5DDCCCA43 9D1E331CA4441FF00CF42D51A01FBB5864298F108E94CAC248E57962D121B6B6 727583E3ABD4FE467F7032EE75643E49C911EA3C5E9BBA676EC6B78533C8BC18 143D33D334E9776643230A735BDD52050ABBD88A2D9C2135A4323732E84AA0A1 4BB7E25140BDC0727B59BA1D8D9616166DB9B9716B6BB539DBA67EC47362D129 62B17EA85B73CB75C830F108CB1CCA13F6FB4EF8FFDC384B1C5B67A276E0BFCB 4A7F6E6DC60F6AD1C17B5214B4A89706351DEC74A4D8E9445B29D91AE59BC3C1 88A82BE1CEF9C1F633175FDD19A68B143D546B7EA4B9EF8176DB463A98412AB7 5D23DF6B81A2050037406100FA3C3829AC906B03A8A52EA333334B7104489FEB 472F33F64125B7B9A2DE5641ACAC57F6D6797B8698A8D249960558DA3CC9258B A8958997A6A7FFFCC2D5E1A5EB0FBDFB5DBFFFE20BC71ACE8FB61ACD14EDB8FA 028701207466241EA1F1D271ACBD80C7696FB7792D579295C382795E2C84C6C0 6CE017EADE8A28CE2CD4A93B9FEA6FBD92644B5670D4B66B405A416B39AAFBB4 F18FBF337DDB2AE945E8F8E94C67C70796B98DED4C31DB5737BBDB27CFD457E6 D8DDF33AA9B0304998E3E7316CEDA5DFFDDA197665D8BCEBAD87DFF3AB38DAFE 30D58D097528AB616C1B3E251DABAC15D310C979CC844B2CEBE668F499E3FCD5 75399234B36BB4314A79A6E39A8EEA6962376AC8D1BFC4D4676CC2C1131E99F2 51CB1535866A0EB82963C33F14394CBB5390025023243B51DE8D85FE18612E47 098E521166BAE3413AF3A560511752C572ECC5006E56464D66E0B357A31DFDC6 0E9156BBAF7B671C39DC9837E3CA231EB4E76E4F8450351789B0E8FC5ECF9A2F 6E80A9EF89BC2D30DE96052BD4A869145CE1B912C42D2682A0AD5B9E3C5494B9 239975469D9DED1BC9CE2D140E5DD0E6D7BD2CA844A73689404590E94F043693 04C704668135DDD3AA3487BD27D3DD24185A3969EEE923A12B5116031695BA16 134CC5484C8CEA548A11E6B79AF444ADFEF1B3676EF4BA3F7164FF31801C65B7 EA8D244C830CFD42DA7F9FCAD7DACE1FAE6F5FD12126757D656DEB6F6CA51FF6 DBFF6C62B11EF53A4DB4227DE42A9D053346869918F4F32C01BF4E2EB244B7B1 9472CBE6BA8C4209C49862E227CCCE471F390BA7167473569AD5399A0E1A47FA 7D67A6BEC1929AE3349115892C6B790951BA29F4A13614B97E526C5D70D93A26 E68621AE9F08304E424480D60A0C7F1038DBE8325F1F57915925071EE8BDE335 ED6E015B1636C6E8A15C6A8C472CA69C957BB92FDF0E0CF5DF4F84632E144168 0C135506B95F50EC4811594A85355454BED5AEA54C8AA818605589D0A0BD5422 F000914D0C5AA3C7EB8D3FBB7006C7D1E307D6F685C9516C1D61EE04579E0E80 1464378DA79820C5B2AF64462B84C7234D5992FF2AA944AAE34771A1A82C99F5 8542BD098F0506AEE826CBCB824B705F893235026C4599012C6E548DADCC9FA4 B75FB38A7564A80D6622AA0CBB022055D850F74541B504AB14231397652217C0 A0702537C3268F89247672EE64BA60229CD091103CC53246511A81AB2D83815F 48C88EEBBFD8ED9C18F6CF0DC3EB60F54EEE989C7AD794B3CC26EA23409E5B0E E346FD92552253FA02F88AB8A0DA286200DF228E14A870085DFBB9AFC9E1D706 B71E593C7A60E83C71E9B5AB0FCDFFC468E9BF6EBDAC73E3DBFC592B09079E68 617220D42710EDE4F18C57C769DE43E2A83DF79CBDF3E9F0FA676F0D4F725B04 C10362F0D17B561F741DDB6E37279669C389DA2337052E73EAB4246D4429684D DA352749F848A0B3E1E8D4A07BE2D557AF9D3C15A16C7FC3FDCEC3773CD86AEF E35910EB1620C1BA12B541BB0956BB5C1925481D4118454AE84E95182C963006 5B66B147CCB43165302F659C8E6B20B4670A627E4BC645DE38059A475516E400 52148EC638CCC8E7EADCC02F7B932F6FEF7CFED5F34BEFFE8EE7AF5E7DA7CA7F A4D670A5AD13A1A5B66B394AC812C2BDD727C2719E2DE883BB6917176C7D352E 975429CC6CCC81E01B7303E172683E0ABCA7F3F4F31BDBBED75CB6E88C2717EA F6214C797FDBFD8E95D9BFF796A421D1F173EEEA6474F78C3E29B5912076905D BAD179F5C2DC2347E2B5893C1FD423197BAE1F0DC166CC9F489EBFAC8E5FAF35 8FDCFB63BF8F07373EE0FA758960486731F0C992C50A1EC9B282806506EF35C9 4C66AB274E0D3EFF9CE87114219FB67415D219C5D475C1F2C6D5E152290FCC42 29232089DBF0703B902D4FD61CE5C39C5DF712368CB63948C70846734C80DAC3 D190EB142886BA174CA1291C81692FD06D325DB789884A3B157E8C28587A21DD FB6F3279BC7BB3516BDEC7A6FC5BBA9A6343D7D85390AA7807CF5118B50156C7 B18AD1A804198CDD36F0F51DE1AE0185A9EE0B678942CF1F950A96129894C510 0F182135A7EEB4A7517326726A436475C2783418F4AFDF40DD6E90678C43A803 75006F22C3B48FF22D9CEDE03CCC384B7507AD3CE627064F1B283A816C6C253C D0D72998E26E0B368591EE391708AB0D244893623060EE38F990E4CDD84116ED 79F8CB83CE571CFBC9CDED2587FEA3B5A599CEE6592C2FF8ED19EED66F45FF5C F43FE0A1C53AFDC4D5ADED003B6950E7AC57534CF57F71EDC80F747880D2732D 7554D740FA12D956274E377BA324A7C4F1C16E258D61226439BA4FD515549D77 80B162018805A214A219D225160A819F292662B1969323B811EE1FD983AC8E1B DBBED59D6430958A129732701232D0438475BD1E0B5044B033B02487EAC5D127 5B18F94D0CEA63C086116057ADAF34B778117CC9B8354165E385AB95A1195FEE 01349588D1EA9FF142A4D0D02EB66A7B0A20B5E77C8EBF5AB2E385AC7036B8FA 767B2838A2E236CA3D3DABA9170C88D4786F19B285498085F5052E12A1822DB1 2EF6489508D5F3B5FAA72E9EC371F8A6036B33A3E8B0A2773AFE9C248E8EDA16 B89B4BB06E37D500A9BAB1A22228EA7D2C2B3FC2326D53CB2AB782C828C05497 A55813162F623E48A9FBA870D5F1A231C910573C4DCCC70025D32B1479D5BCBA ACE22CB498996C1807506444521403D92D50DC350438187DA7267C27C4A909BB 3902AD2AE15BA14AA36810F84E6E4087BAF531DB30C6B1A772CB4E339AA72A8F 8588854CB33C57CC8BBC895398FD457FF864AFBB13870F26F1B1A9F6FDD3F32D 98392540E631904B6966ED4C59AE24BADEA202C4A76DF314741DA87874357A6A 8AFCBB53A78ECD4F7FD03DFC47974E7E6CB1FFB5ECFDFFBB7FFEFCCEC57FDA58 594CF31364BBD50AF6F7B0876C643BD3096C6DD6679CC5EB913365BDD6B67EE5 CAFA135B29C3FA7B8EDEBE7FFA83B6F35DA1CFA4DF5BA4FD83D11459CEED1669 4C12EA4384A7A92BF3662F47918748D0B3693E3F757AFDC6AF9FF9CA13674FB0 6BD1633EFEBEC3871F086AB3796CCB4497C3996D78D2A0F3A0BB2E86B16F0105 47A5C05D965E8E58067D9F306079501DB1646E613B2F1FDBF17E7D8F8A04A99A B2DDBC64E4C454B917283816A21C1CE82FF4D2240BA6D6F3FCDF1D3FA18EDDB9 D9EB7F50E6FFB03EA16BEC4D1F3B7CAB99AB08AF28D22DCE43590956048CF176 7F0FDA0DEDED08CD3B24E3534C0AFE3DB016742F9C478CBCA8C8272F5C19351A 730E3D4AD54146A728996A07FD6C7DFAED879363338B31B18F1D4EA6215C3B23 5D473BD1D9CBE1958D9937DDDD99D395FC702267B16FFBC301A8CF3726B29337 932FE99039FF965FFC3CEE7CF19ED6D18389E7EB3ECEB1EAE078AC3359A1638F 64022A2F940A3020706E84D11F7F83BEB4E9644EA274A3E2EBDAC6CA20968312 33D50D231636FC07D916F86C7AD4AABBA4E6E817A68103A8445AAAFB086E8288 4E1306238AD25CD7843211224AF908181424933C4E719CDB190E6D0091D999EE 20005CCF897B3EEEF5797A87D5588B49061C558A8070521C7990481360750D80 7F4114F36D5843D0C264878C63DDEB59F3D582101638D9B4B4B7891DC9843A62 C2B59C440C24C9F41DD39F21E732B37DE97944F7E8534B58BAACD3BFD93FFFE9 CD67AF38A91DDBDE7A7EF7CC4A776BC39E695EA7E9F329BF3AE87549BE814721 E7347368E6253A8DB8969D0F66399F643A3A48E983B94C9D5BD3822DF8CDA966 2BB0693B95CB115E009B1CA10F37ECF074F795939B727076B9F97BB7AEBC7A73 670D91F7EE5B78831BE88FFBC5BC73A5CD1E5041FDCCB57FE1660F35D6E828BD 126D7499C8904E36765DE66FAA3B3FBABAEFAE41ECE784D4266A0D192BB293CB BE4E4FB1B2111D39A8A73FA512BA0507328FD4C9108F5C306FD3095066B9AE40 1D5A8B731CE91ED7520EE5FBA8D84FE48292038F218F5936D3C550A14162FCF0 C0E6A0C0FC53A355C90DC4976253E1AA720FA5CA3D96393FE68BF00A181E2E52 1D66D84C52903604312485990EB266971FBA057611911243B9DB389232C7C1E1 E4AA6AEEF608D414051FDE9368A51A2BCB14655121E552B18C45C9DC9010E465 B5EE90C6FD01154C3F43A62A40A7A0B004805BD3189A1E89E8275966FA1F9220 ACC34657E523A9CE34833FBC722189E3636B2B33196AA6E93DF5D67DC86E2769 6EF3C88531B267B95C726901C10BB6EE46905A19C60B8CD14174A400E09AAD0E 32A6D6E691374E54E5F4161B9F16301F329F5401FBA0D0EE32C7C2CCAB8D549B 516D2BF445153097F734801570A9BCB6645C55EEF151472542B0EC8477D5CF4D EB68C6C4A4087925DC579557B820A219DF4764C6C83AC0C0AC40E21CB2AD417F 5A29BC325CCB308C4EA7A3FF40D4D9FE4EADE9BCADB5F036D15A4B7022463D27 9736F124668900DB6EDDFD657EDFCD67E2AC95892B4DB1E1A0E981A51FE74FCA 5B7FB5B1FDB70EDCC9A8F3FF9E7AF1C7BDA5A71F58B8F1D2C99F4A2617EEBEE3 B73AAF3E829DF7AA89A7B3FECD49F743B9B3B6B57D7C851DBB2272DFEB79F6F5 86F35B17CF7E7634881C622774C509BE6375F17E5BDE9B2547200D337BBA467D 8BD4DA89ED84D39EB27133B68334C81D77E408CE455D059E0CCEF5FB7F70EBC2 EF3FFBEC569C3C7660E11FCCB1B7E61D9D1E761A736E9835465BAAC5B631B185 9FA1CC85A88C12D826222FA33AD9EB6C9150A0E6D9461B4C58460EC208BE1708 E371C14654E1C7098F2B473A8DA18C8A11531E174DB07AC123B009A5766A2C08 C1B72579A67B709F7F814C8A7F71FCEA976BD36B81F38361FF27970E22946E7B B97EA95A0E2EC18089267BEB4555C2B664694E575229B821159A310FC5A55A57 C95528A4AFCDC32A2D9EE8D4231BADB4768559FF72E3C4CBF5FC509E3D96646B F566CD691FAC4F37F8C0A33BD6DD96F3937F335DF325CF19A19C512B91979F7C 7EAE39E5DFB994348995652C9389837D30BFCB2CCF153B9DCD275F71C285EFFA A92FE0C1A7EF47CDBA333F4BDA6DC4C01DBA187B988E9AC1D3A80B4EC7B16275 EB534FA55FBDD0DA52016970EA8C626181840A3CBBC689D0043602386FECE85B 8F752EC4BE098B90052DC4E0E482929605EE4E703E74064D850268A87EBAA5FE B530735160D627324F5212E7FA620D6D580D36231EE82F62B28D554F37B0399D CA8897E5AC467B303D7508AA0A7D2329832CB0FA940CD91E187E836A5E35D1F9 EFFF80C0A77C01024E308D15B4E1F2A03E0A2D9A773CEB7C1622954D059313D3 77B4BD037D57DCEC76062F9DDD44834F77CE04D27D5BEDE857AE5C3A7BEFE489 CD8BCDA1CC926C455953AE978BCC7758CBF2943371224B9EDEBAAEBB9DF72F2E BFB5D6AA71BEC375E947028163DDB9E6D2E7A8A6FB614BDE542362E325162C4A 3721F28C9B757DE6E5B52F9D3FB933CFBA98892B83C7EBFB8E3527BC7E2F65D6 9F743736A7DCC71AF3F2D5D3FF818943CE940EACB74408B58DD11D7679F6A3CB 0B3FD89A6C6F6D79AE576F4D0FF36E4F5FF8441F082B252462A0DF84407649A6 C4C4470928862083AFEA760DF00EA003AD7B43E27214E462DAA6D335BBEEEB74 9111A653A045F52D062E60E16D5491D98A2155C53D4755B82C9A365C38DF9AB2 B418D914434EE3728D64A9B2060526E4E6C21CC938F0A982308A4BBF115C05F4 4A3250ED458AEEC18A8FB94DBB44F871959423512ECCCA6EB16020E392263846 C1A04AA6B36234526391598AF516490019F75E5CBE49983B72706095BA08CC51 8CC880EA125A0C257F35F0FEE4CA25DD883FB2BA3219E5F52C3DECD71E71EAD3 B910348B1D50BEB2A94EFD8216003BC31C34DAA3B810CEC6C624157E1A269172 6C5956E025C7B0A813CDD8136C246429A59A9689B2E008E202CD5EE265709908 7522BF3D09569DA2DA9316E10AD0C25B70578C07305EB262708C5135659980AA CEB2C40A16B0DB0254545C58690C86A980850516A0479D26B96E2D75E59C0BC3 BBC63425F6B6D35CEF6D9F1C765F4DB64483DD39397BCC9D9CD81CE03CE73547 87661671375703CF778570A4C82CDEF5604A5C8B75EC66676AF43F9E3E21276B 8BCBCBE7CF5D6E84C9C6E26CB8B5F5E684DCF7F0835FDBBAB4BC1D7D70FF9D9F BD796103E7FF70E6C0E4C6C69959745756DFC963DFF227707085928F0D2EFDD1 F696EE66752A9815D61A236BBEAF6BE7070367CDF166FC20D405ADEFB5905AC8 C56C6B5A35267A1E95818E556AD26E7063BD18AADAE9ADAD2FBCFCFC532F1E6F F9EADD0726BE776E657628623B4C7CD02109642D74F5FB8707511F40DB00A8F2 A25C832B04BB356A544700922D0BEFB062025ED15CCD55060493B93FBAC63089 50C5543A42D5329511A4E31D5544F721302CB5008EF4BB726E7978E1D052FB57 CF5EFD8D8D4180F0FF3C37F18F9616B12EE32CE408E171CCC10158EDEAD08F59 83A6C82DB60CA49AE8184E5C35D729881C05998700AA4E16930C96E9C8A8DBA9 C9B4BE6E051FBD75FA8B79F700B51F88A3BB1A8DC5DAC48245675B6287DE9CFC C823CDF73E169221760825FAC3A4CE6674EDF9533387F6DB87E7535BA024D1D5 724A81798929CD45CE521E3D77A97F85BDF7A7FF128B67DFD7BB7ABDB1B04FED 6BC74D27A8D7B0EE3810388C13EAE8365EB701C4F7C9572E9FFCD32F4EECC866 C294B22575129D08736C6780C202316C6A5674A09A05BB7030AAD4315DF785B6 853D4A5C5BFF54E6FF024205CC1781AB8AC0ABBD7070D53547A6F4231EE92C08 CB1315EBA227259CA70A6ADD7A2CFC340B6DB1ED5B68489A43BBC7D0756734C9 938339EB192151B322294E34987B81BB994D6C5FFFCF12C8D8E819BDA2BF2611 C221CEA5AC83D3993DD0DD36891B5389B258760A89D7926872C23EB270C0F38F 763BFD4486972F9FBE7CF132599EBF42E8E9572F1D6CAF7EF9E6853375D18DD3 7B6BB53BFDD6E3F5C634C55614B539D1F7746362EA376EBCF6646FEB10633FBF 76E4A10CD33CED617D38A98758CFC30942BA03ABE9A4C8D00537DEB052FDD9F7 E7BEF2BD2F66B79EDADA52A97545DFA3097474B679B798384A1BD6689825A19C 68FFD1AD1B373C726C7975E3F997BF60215DB0E864A67F3A9CEA0B14BAAA9565 1F5D3DFC9E04F9246713757D9DAFE0482737FDE7A4658D5C2B52C24A39D3A9D1 281F62B3E41952DCCC99E2C65CDDD625AF1872DD0A8A1985D7B0BDC058E052E1 A3CCC7BA68297DD42A3D30494AEC5281432B534E213C888CB94C31AC2C3A72D3 0418A15993D3A43111C46592C2A0230D8A4AC4FC5D6EE94E1AE853FA6FFAB961 BF95A79C14AAE8BBE48A6A14432C324E7BB880B1182424BA6D3A803299E33DBA A62611C26C8AEC369ABBE56E29B456CC1AE1709B642E8AFAD7584815DB175C41 49C11991C81CA512453A115AB4A3C45089D702F78F2F5D4059F2E0F24A2BCEBC 2C5965EC0DB5F6125CA03C353825CBB2CCFE1B956C7E6C20EEA4703C32F9CED4 D3C6ED0241F16376A726CD115C663413684A3F2520A9509C14A37F50F72A84E5 7029375A0C4E48D99DEFB6808656B16BEB719B00E198C2541110D178653486DD EEE925F74290C8DE7552B18B05AE88015001CA5A1F62A8214050475F3B6E5620 3A6EA4A057CDB8AF2BF16ECD7EC149BF916FED0C7B7793E6FDB8364DED218F42 9179847ACADAB2F1848E2B4497D7F03D3C589F5A51C213D7FFB3FECD3F8A766A 93CD7D5BE24A3E8A1D7DFD543D938BAB734DDF95AF5DFEEEA3F7BE1CEE9CB97E EB87F7DFB192645D163B3A32FA5E1066331D3E3931F39C95FDC1E8D613DB9B9B 5CC7331B8A429BE48ADFC5C41CC20B6E4DB7163A00DE3FD98C5F39FDDEFB1F38 5F27A7BAB73E70E4E87C94A85690FBB419EC8B134779569FCA9736FB9F7CE299 E357CEBE77FFF4870F1D382A12371D859229DBC528023B62830472CC314B815C 0372C6FAA6EA025A00075197C9A69C29C5D248E1E42C77EB13595439BA4A3012 E4F0171DAEDC0C714A1228828DF221923AB3D473F5CBEDA9A57367DEB8BCF43B 1BEBBF726B338FF25F589AFEF1A55947E429B5BC5CBA52C4CCDE2D0DAB7BA92A A25191EE0A41A38A915B72790A8EAE7936CD1D2795139E9545B66E9B6B93B137 608D7FBB75FD77366EACF9AD372A7CD842876AB57DB64A9D5B4BEF3D127CE4CD A4A5C34094109D96747EC2EC959BFD6BEBF5478F66B301C838891C405ABA8DCE 39617694453EB1D3D7D66FBC30F8C0CF7E09ABAB7F575CD9C8B6FBF6F2BE6CA5 9DDBB44E743747392C636DB097D65151D70EFFE9B973DF38D9D45190EB6B6C73 6CF34CE9DED3E5506B80150F293003D4E8E881730C8C776DA218C8EF60D7B65C 07C38812A49BA46524845111F38020883295C689FE374974472808B841422264 69C6723BD7BDBE8E7B32C968CA294B3B1839135F89D77B0DF98844F7F4D516F3 0BAB1252A82C026F4B17470239C4F15D6C99121CD0F8FF031D2124C2BE54B3F0 90591DFDF672DE92CCDECEBAB74679ADB56F7EAED96C4D61B5FF539BAF354E5F 0892E15F8AF5EDE9D9BA35F7C5175EB85ACF58983F9AE2FB5A4B47571756739C C41D9285BAAE6F597EC7F1BF80B35FB974BAABD047EACD5F9C5D9B8942EE11E9 D83ACB8CF23C84D1A360FA4E59B6702D7D5CA52EC742B092519E774685AF0CBA 1D4BB761FD89802D5B7E3DB74671B49345B58956A4ECBFBC71FD3A110FDC73F4 E2CB275ECA25E32AD7A1DF76EC18E0BF09491F9EB0FFD5DCD107BA9935E1F428 0FD777AEB79CC904609C11C5B12921A4044F4858D340128542C5E22A52963072 3FD0D063285BEA44CC33BADF0FA62C7DED0510926B8EB1D20666374C3660518E 8D38479966CCC0BF90FD31BC501DC70A4535D39FE9245710B18BC9232F9878A6 6D2900A7D4F01348B95600CB75612163ADA55CCE55E1FAA90A469F2A165CE37E D0D8E82151B095C67BFB2253C19E8BEEED5273505F2C85A78CEE0DA115D80422 F2F89C17AADBAA14622AF9FE05D0AEDCB09B608D2AD68569708C6115C819E68A 8C30E961B4ADE0BE9FA905900893F8E19595469231914ECBEC4DF599033AA0EA E6C7A89453CB1295588442A5480CF01908B01A0A95E0824768F25E36B6552A48 9ABB34325CD8BC9AC59391E52D71EB0560BE400B1AB551B4F7D3957F518D794A A85A40557B54FD64A871FEC395EA0D31F620B2281AF61057CA856525596E1E0C 3C46189A8B8F21ED5763B6D22D2E97443FDB3A23A60A1628E6411971C1B0AD63 466EBB59B3B189F273B7AE4C05C1BC13B849268D89CA08D883D4CB7168A184AA 8918B90ADF744562DB766E9FC2FCD76E9DDFC8C56A46AFBBF0E9B24C97C2FAB1 CEF7050EEEA60FAF2CB7DAAD2FBD78E2F1D9A9C7266616F2F4F9243C5A9F6AC5 695D57FBA14E646EB7D5FCCB9DF5E35BDB674476C667C0004CB0CE1052A7AD44 D641ACDEBD6F757678F2DCB17DD39DA589574E9DFDB5636FBF3BCC9ECA6FDEBD 34AF62B6556B2E2D34025D9CB299A198FDD8E7BFF05F4E7FE5C0C1C99FDB77F0 1DBA4760E17A2DAFA7FA81D7B789A68CE60840C366F3AC8B695DF242A307E6C3 04073129C0F4D5992AC7D4C524A094F296A5D02778404246040B3D9D6533AC0A E355DDCDFB880619FAB7737EFCC40BEFBCFBAE675DF1D1B36775C2F999B9E97F 325FAFE53CA201E09A75E8B26CF94D8910552288A852652A4AE36A1331A67E9B 3902359C1C64C08C0488ED09280CB1662233A7F19BE1F037CE5E9E20F53751E7 D19AB78878ABC9EDFBDC033FF236B9564F46436AE9BCA8944B6B09A5CF9E0355 90470F8654D472882DA90D4F936E0601ED4789A3707AA173F9B99DF7FFE32FE1 64EB83F6508ECEDF8AD2CC999B7667A71DDFC78EEE95510EA53275B8DDB97C8D FDEA2BD1F6D0678E7E7739A6B016048D39097C70C02981D24191DAA12B33B830 48EEB66E01614AA67B413030B799624457B58281843E20B4E1B628F0F9E58227 1901A92E4E13091ADC2927798A44A67B6E0634583EB2E3A938ABEDA04EB3FE29 9ADCE874BFDB9BD99FEB4632C4B861B22029C483CC425F771242A732DB770823 6084F63F9808917E7AFB996A2BC45CD1F794EE8D9A571CB291844DEEEEAF2D34 67A684DD9461E33FF54FF03F7FFAFEF985DFF376FEBCB73D330C54364A1AF8ED B3B50FAB993B6B33DC564EA77F556436C51371CA5DFBF444F357AE9DFBFCA8D7 44E81727E67FCC9F0D70B6E5E499AE2A74F9E598E978A67826063C1FE82C2671 9D135759A142234699EFA78E775677E9DDAD49A49C54F5903C95F6AEE7D1F2EA 1DBD6EF4DCCD9B7D860E1D3E70EED4E93312B02AA9D055A2C39097F3D043E90F 1F58F8FBDECCCC20ED3BAAC36396A43B6EE0EB4215046405085C113C70A5EE11 6C68CAD0C802938476A8B61AB544700E1667B99D250B165D64648EE186436D17 F09F59E1276F622A32B2261297A22770D65445FE56A5CE59C132106372BA044D 07905B9395419E522945A9852D49CAC99882524B944A14C55401F072906C4C04 1EE3E0C60001599CB30AF79B61B9E77C12AC6E6B042BCB3E70911D9F5C5CE2EE 48C57F32401859A05F4AC27C35052D664DE51770B50D312283869A0CFB1369A4 94A97E1C33AC1321DE41725B0091E07CC3FFB30B26112EAD0659A6DBDD5A12BF A9D1BE9BD56C9D98016C0CC57231FA34F1A4A42E540DAEE9AACBBE1BCE802E6A 31AA2C8DC148C74000CB65A028C43CF42BA496474A019202D8830BECBC34854B 71248CE15C655D7D7BE62B8FDB581004EF591E8EF18A948C592C7B14084AA053 897E2DB3221A035C8B3EB480064B52B59890BA756C1216D7F599BEA3B94CF30C C91E1522E441EE04C21339DDD1A96E32E88B8886490B3024B8CFD480E6AE8471 4B9F9198A2A90839425DAC8991872723A7AFD8C73B37BED6EF4C4A77689111D2 D1CD35B68809D8AB20346FFBEF7AE0A1174FBFD84FF9F7DD71F40DEBA34F38BD C751EB00C7BC8193B0BB9F3B36B2B3C9896E8A2E8EC227D2AD17B27E2D163BD2 D62F311069AA03912E4C256FA6C863944F046267F4FDC1F49B16173E71F5C44F 3FF450D36DFCFAC9E3DFF5E83DDF353B496262D59762DBFBEC8533FFF7979EB0 F2EC27EE3AF09686535331D1C909CCBE49C6007B060F03AC2560DA59031D6070 98D25FA79C95D4185932178A9A4C95FB80021723CDF8C0ECF2E14F82C2A9BED6 C23CDE12EBDE5BF89C3652FC8939EF85A75EBEF7C8C1D162FDDFBCF0F2FA80FE C864E39757275A09EF383030726444B06390611257876597BF210B219B12952A AAC7633C8D81C28B14AB18F3268D35A9A35B7DD7E28170F348B9C16773F56B2F 9E9191F546AFF6486037F968F5A185C33FF3EE742A49933EA82FC98CB55C1AD8 6C6BB4FDEC2B53FBD7F2BB17629ED5A0213022AE308DD1193BA71E635CF2EBA3 9BA7D2B77FE4CF70B4FD3EB0FE18A9F0D276BA9DD426A6DD8559B26F4AB824D2 6F3957B5013FFDB927F67D4AC84C588E4E2C0EF0ACF5B1CA0C25003A4723D68D 2B0019CC5471E1894D8D5217B68C4E21CC4B8DAF9A6549468CE956D5BE817C9A 12999118CD743B28509CAB24275C27081E1216A420A6DEB5E3C53EAF77AD936D FA6FF24B8FC8E99FD86ADB72786A5F363972F48B5945ED696A7FC059105DDE58 2C7040744F472130CBA27BE866DFC416AC7E04791A62600CB12C5124DFB1AD2B 59E6E060D19BAA3BF5E6DC5AB72F6E5ED9FABAB5FDDA979F999A997BDA4B9FBE 75F3517FFA1D4EFDE119F7401DCFE9C39A03F6570CA35E1ED839AA61B9CEF053 16F93F2E9EBB68F13969FDF2EA1DEF4F89CFC4BA95D98AF920BC95EB6792197D 5D7DF14744C651AC7B41FD348C28A02AC00A1CA9EB34D3459227601FBB49E589 DEF695C1E08EFD0707483D73F58A74E8E17D0B57CF5F3C8B6D585D8396949703 923EB997895F3A7AD7A17E9CE779D7F89B39522499030918613B81EF1F33A4EB 650EDA0A66DC267131F3DFF66BFDB84F6DEC633123F811D75FA6B401B07E99B9 287380E6844B398382AA842B074159AA8EC992FF6D184E85FFD96E4FA08C9299 B16383DF5320EE2B5D96A6FA85CDEABC64A2EB744B41ED152B43BA000513B3A5 A6559FA6C64CE1CA76BDC2C198819EDA9BFBC604B8F249A840A0B6AC8C9AAA67 648F0C4DF57D94CEDCA592B12C44FA0B565EB1EB2F02BB2AE5FEA449D112BCBF 15A81C19FC472CC980A02E529B320F95B8D26C7CF6E27994250F2CACBA694248 EE67D131AFF58053F74152192CAE014B4E81572D6519578A444F8B6E704CB134 43CE94B9804420A458134965ECC689AA581286D3A77F61312C4B5D005C74B315 D1A1D8BA17697C4CBB2E2796A5EE4435681B7781A4ECB1D5EBD6B345C35739A1 C9AADF46E3A1D91EF1205CD24441CB8A00C3DCEC3FAB600D080B33476512CE33 00AFA588F5614F318E740746728E22A5D3056C2CA1EAE2208A9B5B6610257428 2111A531ECC040F13DB44524333FD72D5BF0743AFABDF56B3B2E6EC7FEC04A52 625B99E3906C4442C5901FD347E6167A7274BAD3FDAEB9A51FCA6BFF8B3AFFBD DED283DC19B238F2F3A9444E65C4B141DA38206E6291EB3C4C457A11B776FA3B 5D1C5F50FCB2E49B61A2CB7EEE0511B414F9AC1293ADE07CB7FF7D93EDC9A9F6 6F9F3EFFFD6F79F8BD7E3BBE75EB8DEF7ACC4E071374EA2FAE0D7FE9B9A7AE6D 5FF9C9B5E50FB5F7CDC115805E44C8543F84FA44C4A04587807D2B70218CAEAF 5E421955A57A505175C872345AF867998C636C80252E8851D8ECF6A9C19D714A 11A732D5AD764E9BA9F5E262F03BCFBE6A4D4E1C393CFF9BC75F796188BFB7ED FCC7FD9313A3BC1B4C8F5CE909FD2FB0261CD3E7F7B0350A34E29E47688CA91A 3B59C3301F9E6D64B82258270ADB2214B4C575F1C2A46E3B6B5F4FE8FFF59513 C39CDD59634768FAF8A3470E7DCF31FAAEFDBD9D73EC5A47F994B98C78D809FC E4DAADCDB317971FBD2F9F6FF25CE75102DB4E07529ACE0FE0E06781D41FEA89 E14DF7FEB7FF26969DF744B9BECBAE3D20D9F9ED683B62AD6670F8009A6F757C 309BAF9DD9BEF09B7FD678750234F97C8F529AA71918360207DCB892411E3300 2430682706B7578C437051649AAD05C10C4C01C169DBA2605D402B941A34EE92 73D380E89B9B4992EA075977843A1102633B55C8E890C90C712FC19CD84FAAE1 9F77D73FBCEFCE375F4811496F4EAA7A68084AD4987899A91098E4E998A9BB41 1F12A1111A95B85809A1DB42DBEE4CB4BA497E2687AE0E2EFAB8A87E839C53C3 6C2BBAA7B6EC365B687AA6E12F5DB870EB4B174FD61C7C72B0F3E737AFF53059 B1ECBFBD76E031C73944B82F0692A6E0A827E96810E749D3CF40F4FB6AD3FFDD CECEEF6D6C7490B897D9FFDBDDF73E166516CEFB32AB63D7CEB39C6420675DAC 707445AFAB75D0D4018421C835BA6E4707CD7494A85C3027D3D911D34DC9CF6F 6EDE1C0DEE583D7099A65FBE711DB9D6AADB0AD7B76F22AAFF926D88C529B31D 14FDC0ECEC0FBA8D208976405C81B9665C0A798C416F94F13C065173DD7EE14C 973D167594554BF0C052B7A6D8A9CBD7DBBEBB685BCB041FB099FE459D5161A9 0466F404043D806984845540FB4B587F392B346C21047BE4C2E705D47960AD8C 41BC1BC871A0850B752357C6621DE6871294489099202218146779862D208629 5190E18C099051B68647CC182F14071C576289642C93566CCA505907C94A84BA 4827255AB550DA340F805BB031C6B21C4576AB9E912AD1021EA10474800CD52E 4BBFE805F7047493C5C1350C58E606374B75C9132AD5C7A8A354478908C91B13 ADCF9C3F6B2375746A4E27425DCFFB79F4B0537FC49F70E284C2E368F88036CD 8DBB78A17441A02028AC32E06AE858AF8BCE54C184C5086F92924C4D0A4B44FD A72DFDA77545ACFF8A4D987E05A643435198CB92752949C1AFA8726125BA88CB 596FC53A2B3264759A8A5F1132EEE7763BC5B1D257D14412C3B418D3738B1284 18C1ADD79D4970A22F2C108834559961A6A192DA042B953DD860FD1402F92655 3C15592EFAA9BE88288759BD6D21171BD3755BE58902ED069D43470EE24C78C6 0F3CD4E1C2A9AD23F6BBDDAB4FCBC1E4C08F499271EAA19A44718C1369819875 1B0158B3CBD59DB4F6E3B3FBFF65F7C4E3B9FFA1D5BB6EC45B5D121D095AFB22 1D04619ADEC6966EFB7485A9EF50441BD2D13D48D253F25C869FC992CF5CBDBC 6D33C9EA3C0F114B21CF67F63EA11B3D6B03A3FB1AAD87DD76FFFAA51FFDDEB7 1F9BB251283ADEB2AE703FF1B94F3F75E9CC07EED9FFF353FBDD38127260054A A491452D5D3759C20A6258810F1DC92DB86039C1D58AD7D851164F08B8BC40CF 008F832800CFD450A7FFBFB6DE0440D3B32A137DD76FFDD7DAABABAAF7A497EC 3B4BD8110119641405F52282BBE2B871959971667067B87A9DAB730725A020E8 1D71608C8048804012208124A4B374964EAFD5D5555DFBBF7EEBBBDC73DEEFAF 4A82C636C6A4BBAAFEEF7BDF739E73CE739EC7D19E01DD21B9039E72C9517FA7 C415342585F63A4DFA5F9E38DD09821FBFE1EA4F7EEDC17FCEF51B66C28F1E6C 4DF6CD7A389E84B659F6F171EE74D20979E12B7E7E9C75F4E9E71FA76A880120 8F7B4E8846501E785032E55213497D6225D35A84CB74EC43F73DF644AF17D8C1 9B6F9D7BFBBBDE14DFB6A76CE7DA64DEE96EA152D60A20E8C541B8F5CCE9BC18 CEBEEC263483D590F31C751B129046AB2B2805A19883BBC6534ECAB97DC7FE90 16EBDF87430B055958DAA12E2E6E952B9DA03926AE3FD299AC05362CEF3C51FC 7F5F57662FDC40CFF390E1991610291165B9355BDC74769342B875B861C0D03B AD6ADC387D0AE6FA39D8118303293CB41CD098F947DA72D5A85F1997A50CCAC7 B042D9B4A47989A0072D99D0910C3E4934B443E99D6CB0BB9E79E27030F1E278 B651A0F941920EFC1109063D811D53C3994A31CD3C9708B92DAB66DA73780423 04794179B8DBBCC6139F44F0EC945FB00B757922EFCC65E645D154DA9AC8A6F7 85A9BFB8BCF2C9E513B717B57BFDEC2F9E7DEA587BFC9DCD3D377133169A96A0 7156FA280A6986B9E90F21C3D7BD142A73F658CBFFA3E5F35F4B325E966FABB5 DFB37FFFE112977A1353B691169FA70C8D7D15662214D311684A2A133CD13644 FB61B16ACA359592A2EC7AC18A212B503586E2FCCACA627F70FCC0BE678AFE83 97B7087A250714F2AFDBE5C2461CF54A41E6A9F98DFD57BC64981A9D77EA4101 0561E966BB10238CC9ACEE402A04000667B0405900C885BAB00059367CF3686F A525C2F9C03FC2C551C6F6481A72A303F464C9B0CB8D7C448F1A09E848544BE4 2301CB5DB204A9388EA8A286C65CC6596B4104E766D4B229192B8883558EF08D 1C06E5466DB8678F4A892A477B01E9C832C83746FF36A67CAE25BA0DA5AA70F9 CA95A59401CE42FEBDB66C34BAABB81D5841BA6AD5857D1706AA3D41439FCB79 78709DAEBADDD194A13BF1DB8C968E475D3DEE9452C90E1FBD6A43EE0A133E07 AC9C312FA41C67175E19C3F3D498C4D21EA5808A36B5CE28B9D4A8FFD399538D 303CD818135942591197F9712B5FDC9C8A208AF29D35795CC5C5CA193E1E7E42 67A38A31C4DD34CCEB82091F6E1AB7D996D33BE6D58B803F025901031B942C70 C64A53950B899730D7FC6495C2D568D3C2C1C6DDDEA65B77DAD5232515B99391 DDBD975171886DADAAE07B7E3540CD882E6347C46E67B8B7DB41DDF9D3D458F3 5D1193DAE7F570762C0A1060992A8ABB4A11FB07C8DFB3CEA00E3DC04B53967A ABCC0604758B21A4338D69071E8DA19905788F9F9D5BA8F750C3A550420F29BC 1D99C8E82BA6F7898D8BFD9C43F03539E52406445A92D4ADE8C1ED302C4232FB 94F55E3736F199F2E2F55DF1FD87AFDB94C9D94B675F33B1F768E10368B51EF5 08161C2D2AEB99691299F01EF5871EF15607E2E17AEDC39B17EEED0F27EBCDB6 31FD413F8364A7E007F74C8C64887DCC8F995CDD5E7DE7F143BF7AF38D0F2F9D 51B30B6F6C5D4197D67FEDDC037F7BEEE9FF38B5EF87A7F7ED29D3815AB735B4 BA037C1428DFCF51353FF5019E56D8133D3E1D10ABACC1AA511D769A85DB2374 8B9D3447A15F08E4CA699BE346128A5800F4863845B5B2B2A738A98DD593AD5F BAB07CC6D8F7DD76EB3FDEF3F09D4ABD6636B8E3406336314BFE385CFEB1A26F 7157E5859AA5CFA3533D8FB7462B3161E684FB88EB69542C2F38DE908871F5C0 258EB4560A8FD60A2C9C4C106F16B5FFF74B0F7CE6ECE557BC7AFA577EF20DC7 5FB2BF6C16B6A63D00A58B03D5E9A5210D261AB2B0DB8F3C51DB3721AE9A4F14 3C0C273C0DE74448F47C81BB88EC048D0702B2A1383CBFF09F68DAF99120C3F2 0E371C7C493707E5A9CBC3B51E9D9F6B1EBB1A9EF3A50F7D61EA64A73FB71F82 32DA30E54A669A2545A95489447B44FC5CE179858B93E322343643AB90517138 511E08C5729C0BB9C4FEA57585A3193D22142A732C04ED38758640F2739B85DA E168A840E1878644DFECB3BEEF7FCB2B1E7EFAF45BE7AF9AEEDB21831F5BB21C 6A0544C7B8762290BB5F2542E4497954443EFC70AA9A59EAD1ACFEF9AFE7F92D AF6AFC816ABC527A791648F948691E4B7A2F9E6A1D83C4D13A984D1FC9D63696 174FFFFD99A7F676BDC766A2CF5C7AE6FBF71CF8512F5C20BD7AC462EA8B0242 114AFDF5866947418DE4B35E2A1AF5AF70F5FEC5B38B5CD687E96FCD1DF88146 348D1EC470C98A2094E8D988B2FD98B1B56BDF43EEF7391B000C101E545CDDB4 582B00E4223CD894C1A3DDCE79934773E3E756D6CE75FB371CDBBFD4EB9FB8B4 89D30C1B31E395BC83EE54C835941052BFA7D17EC7ECDC7C1F779813DF471E85 561E021539D04557E8CC1A1FBE15F13288980589A8D70FE913B6737EE3F2E1DA C415326C51722814F33E09217C70A27D387EBEA5122F952BE22C4747AC5D594E B22B59E2E611B8418052C7D82655AE6A73925180D79CCC3642073CA14A01F4B1 50C83A653DF827E76CE0DA0B58FA94E8623812DB73991E9E1BEE99C231303B4B BCCAEC2A21B8BE8BA9E888680786D4105E952CA6A238F2E70A1AB3035315233B 6B10CF69CC5641DFECEABAE11264D5DEE72314E574318C46A758CC970AA50098 735AAD7AA73B6D55A890D04E3BA1A44BEC36D4854625D69C0FC3AF5C3CDF6AB6 F6D6EA22CD98CDC2223B5E8A974CCCD65C36D11094ACF58994E8446D3200B744 95AED6F6280F21FD01782F01EC6A0E88DF17F99487F30B02EF14939B82C3CF59 59A07F85B49822206DFA4CF4EB29AA5A1A171C2B65C56AB4C82A0D1A52F9952B 5AF57AAA29E0A8675AA9D230D7BA7E6E60B8CB47AA4E03A3E679156155A1577C D77FA539F3C27FDEA9F8B0B9CB9CF770C5C4D5D54465A4AA88F3AC1025DA1C23 9F1BDCCA876304F5B7227949D3D49470A60BF4EFD8F65448D0FFB62434D4566A D5F774CF2B425C48D4DDC0BB50F34EAC2C7D44F50075E90143A552FCE8194EA6 DD749B055CA304A0DA23F9A23007FAFAA513FB6B7B5A0F9F7CEC7B1AE3B74CCC D0A2F019F17020AD22CF6F66641C426EB141FD84787EDE111B7EEBD35EF2E1CB 67AE9B3BFC3A7F2AE92D9FA2C3D3DB8333FDA28752C3AA6EC830E0452CAF26E4 57AFB8E1D1279F98BFED9A771CB962BAB097B9F8F7DFBEEFA1C71EFFA5E3477F A8363936D81A7A59CF834B8FFE0795A546A490228AFB1578CF5C8932526FB1BB 6BF4BC62A438E09109699115502051C025428942C0991685274592D35349D99D 9E79E5C6F6CF6D6D7D697BEBE76FB8F6C45317EFCE8AEF9B941F3AD01A2BEDF9 A01D1235960D067E4DD0E7C8322F24588D026F055F1C91AE720D231504432A89 E357721FED634B7893F0991AC6F39997F3211C784009C1F889CB834786EBB77E EF35B7BF68BFACE73D9E859241AA030CCE2E77378AC1F8150BC30BABF9A9B363 2FB93A9D8290A4C2D21975A003111A73689C5939F515950B1E93E8D8C2F46FD2 A2FF732CCB50F810E22E296AF8D2C96069F5E2F98D2B67AFB617F4D6671F09B6 49B26F567A9ECE0B2F3751665592C339CB1C090CBE9550A442CB1AEFC3A8FDC8 B8A878034EFC1EC711908F19320C511D06C5641D7F90B88122FCCEBC2C317E68 2C0A6D5192129D9BE0BBF83914551A82622D65199717000E666626F121E52DEA 4E9D885925D2403B975E6C7E4122C4DE38926514954C441E14D7AA1A5FEE48BE EE46B7EF9AFD542C8394E9D0FA4C15AA19DCB3D25D1966FFE6EA85B1FE3098B9 6D3071E8E4E9FB579F795CAF05776C2FAAE929789A3F323D7F73DE596851B823 F0C64AEBAB3030653118F4D6B8AEE154DF0E9BF54F773BFFE3F2F296E78F0FB3 DFDBB7F775357F1C0058C94B5564359C92FA26C08937455327EE6893AAEA5641 AEA2EC729AF50A2CE4122E37BDE0DECB17CF97834357EEBFB0B4766ABB77E0D0 6C96E66797B7127892AC46A84FE8A66346630FE44A4D7F72FED0B55284A680AA A82835A0642CD0B519123DB02AF710247027830D980512E236D567746F31DF3A D0681F22F1F1A48C3D3E3B1686ACD43A0903B4B0C07D6E546376C192A1EDFAF3 640CDDEB18497152E344175C0B045B01057C34381A0AC333C14933FA89B9BA84 B9F2D20539642D31CFB2C4AA1215997168AA42D1C912F86F90297D4342457C85 63426FA4AAB9EBAD46ABA5A59DA2B46A899A52EE8EB52A1BF61D885C55B13BFB 88DA6723730937D6C2B5A48AEAE2CE4945F0C1936B468AFEAEF93A62DFECAE05 570B90A4F25ADD194D3A7E1029094929858F8189D0A8AEC6AEC0F920FAF2A5C5 280E0E8D4F46000455DA2CF2AB497063732270ADFEB228B0E2817B85BB0368D2 8B55912340C8AA59CA705537C7B0AD3A5ADF9B2780E9E197B4D4AB9298351E02 0164428DC7B5D9F638608BB1A2076741C28574D45AFC98D512E6C8B8D7D8E7D5 6E666733A29A41D0519F79248B55F5284718DF2121B623F946769C5F0CD9DD16 7DC13EC6086D8C1AB0238511E5CE49452AAEF6FA475865670966B4A86A504E8C E1BAA2EBD57378592A2C480D3DBD44A2C8208302DC18653B924045603C591032 2C73E67100E67003A136C4DC0975A31FA479FEF3D9C5CDEDBCC070249C3E95AE 98B4F081502857509C55181D9B40EA726FAD71DBFEC38F3D7D628ED8575D7395 E87622ADC7B98C33DBF4022DB997C929019865BB80289F07FD847C6B8C7EA47F 9E9AE076D23E34562BA412093DD95BFD66776345F10191691CEB1AF793C14B83 F6F6FAD2B5C7AF7AD7EB6FBB2AED4F90E9551AFEF6439FBDFB3B4FFFECC1B99F 69EF63F9A013E1C6043A8F3A07C22644494B31113235AA3676440D8C5BA4A92E 2833238188044E14859AAB44221CC44A780A8845732D8B58F8C38CDFDBE93FD8 F2FF60E8FF5239BCE3F2C55BA7DB9D813A352C7E6CCCFFB37DE33121E7C27A4D 976379B21DD67C77F49F2FE7E65EEB48F0DEB217621E4EAB061E71A349267155 96782874850C754F92C8A0511B09CD7464C7453C3EC69AB36C6AACF406D402E8 876C147A4E54D7069ED84C7B9DADDAC4E4F97B1F6885F1D8CB8E6FD6531F3061 5A2023058D794A236D05DA1C7101E2904F6B572D4CBF8FDADEAFA11526EEA726 3C4BEB38FAC094D8BFD8B3277BECC4F6C6D39BADB15951AB53383059E9E7D64F 01C1E6252A9D63DE8233C50B2495AB4A0DC0C13FE668324800AC04B0281ACFA1 BFA8234317889231613938C92A68F99CE41DA4B412B7EC4BA3E01AC7436C6CC2 2F3CAC949541E4F745D92D1EAB954FCAEE8B49FDBAA57C6BDC67238B1C7870CC F325CA3342C0F1B9C4440827C27927ED36C0FE05FA7C6EB44B682E743B17F0E9 96276B9F7FEA5CCDB2B75E7BC8EBE5E1C44B37E2F6FDE7EEBEF8C423B7D01B7E C09C66BDDE5BC7E75E25E555524D45F00DCA94B082C890F874507607C38E67A3 52D1C0BFE07B1FBF70F11F927C2039A4AC3FD8B7E7D5AD382A4998A21B64A796 94C6F83A184AC8E0AC5622DF1C575C218A091F32C5BA52EBD8C044BFB16D62B6 FDF8AE95B34B7972D3D1C32B17571FDFEE7A936310E42FAF6FA670A464801798 0E6881C537A0D7EF0BA377EED9DF243A6746A6B8870B992F83405ED835898B11 703672621281A57A587A9005EF1FAE0C687ED3F8EC026E28E9973019075E23F2 103912253D51328BC187613B4E10C8E244A00805DFDDD8AD84745DDBD0890ABA 71380AFF9438FA45EE482594869E0A28511458414B035849013A3705FC3DA041 A8E4003045C096CBC1A56230AC01D2B046A0315150D858D9861175CAE7E1DE57 3BBBA3CDB491BAF488B8B8B3B38DA873E4A245858BE328C68264623AF280727F A2DC9929E25585BFAAEA65A41DEC3CDC2DA9E09B63FD58F7692A508589D35463 4B27D4891D515BFD7B566D1896CE2B67486C9508BBC6F4AD015CF9ACEFDF75E9 229CFA6BF6EF6FC31FC986E3A5BE5ED6AF903E412880967ADCED5020B801B402 590DB0020E5321372B2D6816886D692E99EC72D15F2FD413B968077E33F442D4 5D82DF04D7DA006C91146D431A528E8731D4E0AFE896807103E97B4E52AB5AE0 23CE2A863D4F8F77A430506DF23B324EC503786EACE7629C61F6B98BC5767981 A3F4697744EA9EA74947767C835DC464A3F66C95EE5075BADA60ACE83B6E7F66 3452A2D54A080A1F22BCE0989DB05BE2949BA946AD5151699DBB614B9E43896E CB9C2E8902CDBD2D5D8CEC122FF724E20A1D67D26ED9BC5932599A24B09FAF87 779E7AFA59ED300FDA49E240B6EADF32EB218B44945041CF0FBD0D0EA953BC72 F6E0C6D2D9ED2C79FD8D472787799675E7EBF52B37ED5CC6B79AF062C4B80FD7 5C53F8BE24E811FD08EFDD2DF2CF5F589E68345F3D377F652FBFA68CD35AF608 CD1E18906F6CACAE42E58E9FC8D40090EB72A6D97EEDC2CCCB03FED69B5F2652 F9AC1DFEE677BE74EEF10BBFBCFFC0CBC6A6A549C7888AF23C176A2829D39C1B E956D9B493A4607634A6876AC2BD3CB7A7EB8A6C56AD1B790C20620147046297 D4812CF103662C898C503AFA7C92DC91AD7F31DAFF3B01F97F164F7BA4CC3487 9BFAE335F9DFF64DC5942CFA6164CB6691F4C2BAF75DE2F8BB2ACDBB13413672 3571B44A67A582FE2A0C87E790B5420F958E7CA45552345956AC11C9A9596FBE 4927B511CEEEA9241C82A6C8512F974AEA8534144EF48BD3829467D79EFC9F9F DD77DB0DADEFBF65E8F5206AD6348A2FB9FB4FDDB603807E6C43098C46928647 E6A6FE23B5DBEF856A3867055C464FC303284A03C7C197344ACF76D892DAF8CE 92EC9A71D6CA8B4221A5D3B044D9CC1404391C70A3BC14B540210BA65C07F069 20D0E05A3D9C289CEE50A83A946255347196A0682302851B147474C4976195EE 011B31C9508F180B0508BF055339C985F32C8752056A46833CC10E1BC8DA67B3 A5FE187B3D6F5E7F29DD8A83CA190D19658248C034B8540C1988E28C50C20974 DE492F3458FA9783DCDD7F5F2BF2C4F71E6FB63FF3F0896BDAF10F1E3DCCF326 AD5D970A7E66F391AF9CF866A9E73F202ED716D7DF77E0C04D813C588F82AC80 F79006E8D9111581E9996EBF285169232F6AC159EE7DE4F4997FC2E503313DE8 7FF8C0DE57C471AA3424F62661B9DFCBB9A2A5D899C3F06A8B00375E84D7D5E6 7251F6014D5299E8728B163D197EF1E29945A36F3974606D65EB915E37091A11 C085B49B8A91F5063EE342C2559E13E45D3333AF9611C4CE1E637E62634353DF 746D4E33D3F1658835BDC14418CA21A3BD429DD958B3A1B86A6A7AAE974F40B4 6D05570B1452445633837F40F1761441870BC4475A958EC04935633B587DA421 5F71EA9D4BAD0B8125B6ADE20400ACCD05474239F2FA0CCF6D000F0E0A210A49 5A26211B08DAE16C55DBEDADED222FFB833E3CCB46A3DEA8D703210381FBCE4C A337B72424CE14613B5B0008FE78B5AA5F85E91D970814C8206EE9023E85D329 C6AE253C74512D63547B8F8CE9B218B53F5D3B8E8DE832F897363BFEF428443D E2EDE84A4DF479811FF308777524DE0256B1678CBB8EF09C734212488494758D EE193B203637E624215F59BBDC2FCB5B8E1C1A87538C8950DD128ECD19782A79 2171902ED1761E573971AB9290002A636351C9D395B28520434EFA9E2D43CF00 ACF651A1521A172E708712EE2C3A82C10F2650E046399722330BEF82E368DDF5 D2D037D8544A3E7457A3C7318346BE1623A652C54DDD21E63AC2B8CB4B8A5592 DE3B19AECA682351851D213B3AD234DF0991A3AD44FB3CD20D1D29A01247601A 098ABB92B5E2B0BAC75D695ABAC92B14C500CBA046169AA1B50BAEDF03E00614 82C41847D842861F1DF85B0CEE760AFF7933E68BB650899A14CD5A1493B2E083 04E05919C2816CFDCD60EDB3BDD50E36D320E686B4CC3C34A606F4E735085AAA 0D22313ED45B105D843818B4F2325F19F45EBF307773D83EB77A66DFDED91B7A 62A167B6EA2C369037F27618FBB86727E1149E559D6F49FDD7CB1BC9F8D8AD73 B3731757AEA3FEAC0FC1A0BEC4C28BA6FFC0D2D947FAF95078435A6A09C92D6A 64C52B6BECBFBEF52D53998AA3F1937AF0970F3EF0F5C79E79CFF5D7BDDC6FCE A43D01179A6650FB24507158CFD31EE05C5EB5EE8DD32C410B70E462C20576C2 AF1A87CC0AEA5AC06880C0538DF5861445E04145E8ABBE1ED44BC05D63FF40F5 6F2E9FFC726DEFDFCD4EFED9E9A713F483C5B6DB8FC4F4FFDA3F33A6E9060F24 49635D245E9DB95597DD66DBEE06C5486BC851B1700A5F598609DC2980D2854A 8E626492F1C847794EF87F05F183504C10B66F9CCDED83FAC2D08D9C678CC5A2 04842C0A9AC001E6D4833F55D438E4C2228E6A7DD1FBD897B7EF7AB07DC3C1C6 BB5F65F6C726EF0A14F7289535501639C50B847BDCB1B98988887FE5FCD47FA0 66EBD771A28709AA84CCA16CE136BAE0EBC73D487BA55FBBCCEC131BF4B1B57C 98400843CD971E443FA87B701E013F5E3054B2C015C5C40390AE7581EC3EB859 4996431C97510CC969677F7EA47C016007BD97E1F4579646EE1AA0587E356B71 8910822333397CBF0EF545E9D5E1354100014C935A25C61E1C0EBE33D83AB67F FECA2459282D144E948DB67051BA4EE0823FDAF904C48B03836D7EAC5925DDB5 23A1FF320BEE4E743D43FCA2DB8FEB0F04639FFED603AFDC37F686FDFB04D92F 5AD7D32C5D59FDCE874FDCFB8F9607E3EDDAD9F36F1DAFDF32D96E06718B052D C02A79477B34A5FE70C8B31E266522D3A1C756C2FA1DA7CFDF0908A2CEDBEBDD FFB5EFC0ABBDF0325189A8355092B85BF838F969E0A365431FDB8D5E0EA51B14 40744995AB4A651420071990B2C3F3C4F85FB878E63C67D7EFDBB3B1963C3628 523F0AF33C223D256CA248CC498711A8ED00505C13C7EFB9E28A23DBDD9E2E86 6158D3BE4CB2BE57260098733D400D2128E6505D0230D2394FDF976CC10B7C45 38BDBF6F22A6C3C0EE6D34A64C82126AF0507DDFBD29233DA49655CA9B5A403E C311BB2C79A552BB331C77260D5015690830DA946EB8C3D8D8B6090A53063C09 78CE59592A96695FA1EE7B4119DCE965AE9EEDACDE9DA60FD6C89E38383ABE67 5AF90B24982978A3AF6B8515A892A920B263F74B92CC096C60D711BE17F60865 5AE4D5C2BEA9DAB02E27B77306004CE25A8FA92439059E0A546582DC80430A82 BC661F0F53A5F3A577B22BA9CA14A4FAB8438BD211963C576FDAE7E800ACAA95 46DC1A5B9A1181147E1E788055222C241F10BAA5CBAE32A9AB084F287D4F77AB AFF58B8E1F6E96D6CFF2A942DD1434A73426C2DCC78CE06B0270A186BB708A38 3144B8D9B2D47580C80552E7D1331235EF3DA73BB0EAF840C82173A9C8106C7A 55E66AB8FAEE32845D6A7A4874D458440847C335AEB5659CCC4755BC19DC15D9 E50D593332BEC6B624232343ECAA395A6007938D66844EE082552AADEE77EE7E 899D5C689EBB79EC390329BD4334722FC8388D62BC17C6AD51569C03C7D4750B 00D8A32690FC32C953384BF0292977FC08645E57171F5E0577A69FA56ED4866A DB642B2617197CAAF091583F39D83A9247D7C9769767039189BCB8A633F3A583 637F7EF9E4936B97E1D291208ACADC331A17B60B6F9A200567C3E78E86495097 12C2520439D2DCC2EADFDB9C7FE2F2E9030767AFA6F16C62FA019DF5867E9671 08F6B20EA9A5990CE1857D93D33BB786A74B3677707AB8FEECC16678ED963CEE CF09C03D7E67B9A6BE90969FBBB8D94D1400F0BE0932BF9C8886775C7DCD6BF7 EE2DFCFA58A7F69019FEF613F7DAB3CB7F70F8BAC3A8C9B94549026738659E07 1955051D1FB770E181691CB79342E9C6D858D46CB17A8D489F16453648D23411 5B0392F5881A38790AC973CF2FAC8A69CFF4C70CDC95A93B3DFAEEB30F7D427B 0F1DBDFA2F4E3ED1CFE0AEC656656F99083F7870663EA35D5C12CF0293155E6B B4EDB25B72ECCA3BEDA82B1847E64602A79B3A20D29498080190FAB5C8FA0CE2 3D148556B0787C825C19D9199E794DA901E66DC33B23269269407C9178458836 5ECCFA4A353C1D46FD762D3AD75979DFC7F79D4F2E8D69FF1D2F9E7DF3AD70D5 203519F8E15044C744D6993672149284BA0112218DAE9A9F7A1FB5FD5F85E056 70A3859686CB3280D0A664DFD08CAA96C7E7E15224E972EFAE27C872DED890A2 4355AE5335F4201F0DD13AB3CC71F82F88E645DE116C4CF32453A75AD1F941FF FA921DC8331AC24F1B58CD87B2C8B96E16D2B3B470485B5746545537C4ED1EE2 E410900A8EBA0B51A22BCF806642E704150F82366400C5BF528FFE2A593F38DC FC3519F0542E3567C7F20E1A9162F84207182CC3242E6BB150F050C2755128C8 4747938AE76D86ED52FBAAEB69DC5CBF2FFD7DDDCE30AC7FB6D9FCD437EEFF99 BDB3AF9FBFB2D3DC4F6BE3CDB573174E3DF2E9D4FEFEA5F4ED87F7D9B3ABD712 F3BA7DA21DA58AF9D286B22835A7DD522689B605DAA834339278FAE264F4E133 A73F970ECB1ADFD3517FB3EFC84BA9DF176926B23A843023010541CEEB84E82A 1666344AE0B3B1AEC82E58B652788AD9C40C376574B6D38B9AF65C197CE3C252 C2CD81430B97D7D7D7FB436445C0E9C22887B0AE44F2AE5221690FF5CFB6F77F 4FB34DF5B6B54560456EBDBE08526ABA7A5806A43ED06914D921DC15F95450DC 9F2EEFF5FCDBC3318EB61FD931165D21EB26901E4F2A795CC62BCE80A386085C 4FADE66F8ECBC00A9BC6A9F58DE8465EC2483030B5CC40766268B46A20E77520 F9716C3E239D202B9A80C7134913A6FDD6B3E3B53BC3E2CB6478AAB3156D1637 F8D33747F17E9E05BE2F01F143F157002E4AF127F0FC6D413602B6E293659BAD 517BA6D61AF47B493A4CB3B4DF1D428AAA53947D6A28D650A645C44CD06C45D1 3C391BC78D804B5F19DFB08830A8866B44C45CC4168B5A08F7D8F9420D1DDC8E 703562B57DACB14DC79CB675A5980328DAD6ACB392B12329095E299F55798FD1 5142702C76F4CA51381C2539854ADC24CC0C00EF293ACCCD455D2EC7EC2B0338 3266361F1C9EDD832B6F69BA57D07921EADA07F4AD2007EAB459D27100CC809E 09FEF2990D71A704D7E59D0E8C2BD19074EB066C23AAECCE2203327D4CA5F462 AD7A8ECE367289AB24C26DB5143C5A09B523E0682AC94267B56B9D7C4C25E3E3 50BDADF6EF47EAAE908BDD42B5C53DBD8AA2EB20AACF723792F228F3147C39A3 2BA3849D162C2EAE553FC36852C89C1043A5CAF73CE46A71DB0CBF28FC1F945F 27D5DE15431C5FF9C68C8870D6A57947D3C5BD2AA87E54A9B8E50A975331C6F8 43CDFAE566E4DDEBF51F2ABB351DBE48CC8DF77828FC6ED9895871211C7E7C6B EBBEAE2A8DA43C3000908B829528B96190E45F02C61FBA6D4500ACF0BA33AE27 2CBB76DFFEA7D62FDCB06FEECD76829FBD7461825D3B4EE3BE9DCC1A110934CF 1A2C6F0F8B41187CC86C7D34DDDA33B577AE93B74272D560F8BA785AF7922216 B1E7B7B4FF2D95BEFFF2D99394856523C015DFE4F689C66BA70F1D9F3A74D335 7BA2DEC67736977FEBC1870A1ABEFFE0D15B36168D9FAF9A302C6BCD00C24587 B3C82F4DCE505E0A0AD960E66871F0886AFB6DA1485A6C49C8253AEBAEB49E7E A09B01B2CCC34E129493051D2FC3D4231B8D6E52CF78AFD5FC7C18BEF7C463C7 83B1F91BAEB9F7E16FADA7C33E8FE08AFD4443FEE181D9A649BB4168348D9429 5DA9C1D007A3D2A2B0744718089113AAECBB4D413812D229AF206B04FDF9B82F 68C045C3CB7D93475AD5B937D568CD8DF326C0B31C8F858EAC8A50F6520C0DB6 8DC62D852A27237E1F3052EE4BDD68D6366BE547EEEEDF7BA64DA24DB2991EA5 0BBFFE7D7AA1960AC0F9CC1F747C88915250471AC5438AC8D7A7C1B1D9A9DF80 44F8EB04DDBFA07AD7F013714884E8043F5434B76543B219009D6827FF9D8B5B 8F2FC6EB52F6A84AF342E5241D8854B38CEA12E5CBF07F8B2CB3B41E0490B5BE B3BDA5B8770597D33A2302EEBF4F155300D03854ECF0E9B9D385A223B1FE1D1F 41E6A635C8CC530A4A08E4C5E3B83C87425349CC13B514C2BC7F6FE0FDCDD6E9 D74F4DBEB56B00F72FB66A5359E1DC8C2B188A8910C7568020478910C9B2D869 41ADD191F315DD31AB7C218914A3C6507873C3C1308CFF21083FF9B56FFFFCB1 D9D7ED395CC407646D8A2C3F737AE5E45DA5F8EFA7FB0717E2DA4AFF4D8DF61B A6685DF4520ACF388E5509A9701DEDA400CC0ADC11C06E5AD96FD5FEE8ECA93B 756A037A55DF7CE8E055371A5AD04CB3023010F7225BC2D3D149809B535E4665 2E20E077687A51914D1D427E4B68BAC4F8E32BAB63D3C1920EBFBEB494313637 3BD11DF6D63A59412A5E259246A130C01E8E80DA83DC1C36FFDDE4916359D627 DBDD10CA360FD25191E123C0F716403232714E3B8DE86B66FBDCEAE59BE4F88D ED096EB31A2927899DA9C563D2AFA55AD777F8F3ACEA6F54EC057C61A65A97A8 2667281A8B7AF670E4BDD452404CD4A490E60A38462CE51482CA648FD635C989 EE44C15A3D5E8E820B463FDBDFBAB0B191A603486007EAB58546BD1D458D52C5 8344417927509C7A83914DC9D7B859EE0D20F5439652DB43B8E921614DC01194 D7040BE013E2B59263CDA60C3CDCA740CA2D730520A488A82872A44D3AA2B2AD E4C930FE1AADE090A1A00C137C5E896A75B0629572D75D821A14C59B1481DC09 791422A1A429311583D1ED29904A9A6544E7A8EC8A88138B42A22132BE90C952 608BD22682F6147C4B74E1BC64CCA2AFBFDA1F74F3E2C689E6441C0F87459DB0 BDDCCE1356D7A8CFABB1D95FB472334682004A3E8E733F89C6F558DE556C78C7 7375FC545E79E27EB78E92D3F818D9EA56BF1DC9839559805B1871468286EEEC 8138519C9D86E60EF953DB8AA2B323DF5D99785AD7A8842F20B0092B5D9F1870 6CE15232005F0F770AD0C31AF31F3E4FC01AE868A1DC8220443B0FEEBD6B351B A72A525921BA66B275F61AD598D6ED6195F84D2A15128214713C8DD832A695C8 6DE560B1CBDBAABA5018989190ACB1FF26A1EC877393AB5E59F69549845C31EA F1AD750855C726F6B606A49594033F2F7C7359F0BFBCB0F88082EBE5C7251A47 17F0000BB4D3844223267420F0470D4A242697DC34959D6B342E67BDC393CDB7 350F0E4F9EDAD8D7B82D26AD94B65523341E409A80408229322FF84248FFE4E2 E90DCA6F9C989A0AD8116DE70B3A69C4B4EF27C53008FC31397176507EF0D2D3 777B80A0F8749AD5399D9F1A7FE5F8DE9FB8FDA6B912B21DFDF2C6E93BEEBAF7 96D9A91FDD3B37B9B50C019C88094D078C6C6B1A025AF5942E4BDB6F4FB5AE7D B9A8CD69DF167EA7AE4CB06EC8CA46A9BA6B64B1D92371D14B86ABBC8CCC202A 99CED12680923EEDD7BC2FD6C8079E3D3D6FFCF163579E3C7B7A3B19F6FDBA50 E5BB1BFEEF1E9C6DA9ACEB07F0AA42A5D4CEBCCBECECDD3E474B6498021D8076 931F89A2C41C6D6AE07D30282258248D4F0A5FEB1A0B661AE19E715A87022087 1C2311FB6022C4F28E0DD19A5843C1E61351F04823D9D01372622AFFE2B327FF EAAB635D3EED459EC82FF9EB7BDFF1A2E8CD3796D29AB2A03A133EA778DAD548 61020D1E438689F0372111BE17C97AB860A039E448E5C14FAD658A4B78A445CD 843B722959EEF51F3C652E401D6D49A6549A29781A998150503AF2285C035A16 C830D6A6AFD4939BDDA9F69EBD0CCEF760C821037B710A18022B428A09833979 8D4A6F64342EDF19B0546BD190B9B4424F6012A72557F03FF070F3548B253176 6F6FEB62E7D2BF3D727CEFB636E94047F01691A3C147C6BA686B0C7102C0BB08 3011C207D34E53C3ADAB905D4D60B223F8F402FA8CB509977BD2C1208A3E2DFD BFFCD2C3BF72CBC26BA60E186FA1DE9CED5D3AF9ADC5474E04639F3CB575966E CC0CED7B160EFDF094DFB6BD2D03EF3A6A4044CDD46A61071A723117254F3CEB 43152EE41F9D3BFDF71E82CB5764EC83FB8E1D5425F3A1162C6909F8D3837810 C14D93049319264501AF6BD30E564A78F30DF85450193F43CD7D8B8B07172637 68F8F5C5C582D0289679A906257C40D41D11680C8E63528DB8BF685BFAC37B0F BF498E875B6B2A80BB0DF010DD8EE13647806FB51950741C1C50FB00E97F3B59 7D516BE18D64C2EB758C574C52BB4F7A8D460007B8D92B933151B99CD2D186BC 934A137CD4E0D24E48C9F1724B5D26B8A1446566598E9D40482D8D82F15C7738 76C59B4338897ED2A89DB6EA11959E28FACF7437E02B5D59AF1FF3FD2BBC20C6 A45468B4539659A6B7B20C8AD9356BCEE7E98AD65B0AE97C2193B35E34C9E418 15D33C38824C0F78E7F00D0C5C0AF88E99D5902AB78AE1801603663A795A2251 662249065959389E0E94E1D8C547FDEEB228E0BC19A7E425C91E2D91B3CA99E7 09DC7DE53460BCC64493F249168C33AF85037AE197DB9558B0AE66F1D4152815 65AE92AB76E70A42A5D0A8EE8CEA981C19B3F06B809A5B2AD7645098654ECEF0 E26BFD4167387CCD81BD50BCF40B3D26FCBD54EFB5B4A9D16187C329A27A2CB7 63C447BE38B67751C6AE5A22AC5E8C53F3778AE523C3C2DD445869BCECB83D54 1C263BDA2C43F9B0111CC4A5C35182DBB1371E19E418A862477C36B7DD375236 DF51DFB16C67C95E3B6984AAD7692A022880418DE4149C6C729AC1C5963CA6A8 D3E888B54EC58CBBC784DDCB510FD60A86D297E86184E02E77A60A882D0C0928 8E87711E49915056BA0124F6B4256A9160DB9B5762794E48055794CDAE892560 226DB580AC8C2B84B4EF715350AFA3D3DC3E13937B7A2B706BF786E3D7E86646 521F91117FDCA39F585D7C66305496156EADD1B33624064010C0EA044B70E477 39CB281269DC4E8332714292771EB8AEF7CCE9E4F0F8AB886917A26EA2580B09 D1880D83B2143C3ADB68FDF9F2D9CF6F6E5E71707246DBC3CD317579E3A6DAD4 2188D0653F0CF8A12C9CB5CDCFD1FEEF0C4F3F94E79E76FBF1C65C25C57B5E7A EB5BF6DD38A164575DFAD8E9073FF6C0D95FB8F59AB7147A32B19B2C2ABDC4B7 1D6B9A4C17904086456EAF3816DEFCDAC46F87A610C965D5D91EACF4972E5C5A EBAC3F396566697098AA232CF7B733DAC761FBB6601B417B693BCF3CF378BDFC F8C573596A82F1C9F5612FCDF2CCAF89A278772BFCDDFD334D9576FD10CE44B0 93082B76683517A4958E26A205284EF000E091758910797CBE0F29904342A82A 16404375CEDBBE37DD201375228CB6998183808BA901811C8E965303C0530AE2 8817E76AC80222FDB870628B5FFFD097CF7DF1E481FAC47CE84DD932B583C175 AD43BFF85A7EB066CB2192443DE6E7156E73D7819686F93C8444F8EFA9EDFEBA A50EA66139EB04AC90BE932382F6DA70F5D09190E62C2FCCB32B83C757CCA5A1 97D3B2D763494187054D6D911AA3F0D3E18FED10632FCD015C3582F6988573D1 1F420D58F8AD3E26F2542A8B11863B11ADCABBCD8E58EA23DB175BD10FA02E84 8A0730626B580E216F1B3D91F5CE07C1472D7BF8D9733F353BBB506B9CCCCB23 BE7FF5F67AC76BE00CC0996E550BD3A81C0E7F476519A91C6D0A45C077BAA264 24B4B8E341B9A31A55F54D874CEE49FABD5AFD7FFBFE5FDEF5E02FDF76E03593 FB099B698E2F6CAF3EF9E5A7BE795FC6BEB1EA9DF42E4503F25353B3EF9E6BCE 9B04FE94F1EA7E9EDB426F28D253F8117D25D62313970652DE5F6FAE7E28DD4C 897E4B7DFC37E60F8CA5834892891C1069BE5943B3C626AEB75AA94BC8E0032B 7AAC582D3ADBC42FF898CACB2E4D1EA7EA4BCB2BC7E6A6FA32F8E6F945549882 4C86910FB28DE7A45C949332C36750B7E5CD7EFC837B0F8D95A8D90987C85736 2176832B43E0107100197D66B37AFD6B7CEB9E334BAFAEB5BF6F727FB1BD2985 9A137441F0B140441E171A059F87E1281156EC172750E88C26B024741A4DDA69 7E418A298C2E4D02D8DF30A99CF185B53C01A4CAE1035F0EE9409267E2C68961 FFE995F3DBBDC17C1CDD3A317790066DC6726EB73CB321EC76A97AFDC1CA20BD 90170526291C62D5A53713D566E346CB97015A7AC1D5A01A8D5F98187A49098F 5EE72896A3377B502AE6F0E3F486059AD7619D4302490E7B5E2DAE85810F473C 6034967E88F3340CB802A104D67050B518888E8E4123777934706D5D0D0C4F03 6941D649D061D9847274A833E81899DA19EE8EC84A5514C07A084007EA86437D 5370566222347DABFA56679A763275D9A3A778FED5ADAD288C6F6AD6B32C592F CC4CBD395FA407051B47E74F54CC8DB91D2F48DB601BC9F3511B8450774FEC28 F5BA5EA7931C6795D4DB77558476571BC0353B7736D573BBE3D431927AAAFE99 579B2FC46920184770B38E1F6BABC9BEFB6D8C5775DBAEED92803217852EF167 82A4E5558AA0048BBF5C12547C742D1205D098A09D5B8CCF0E6A0F0BAF1253B7 B101AA5F219F100A2CD45BB618080BDC86C28F289CB5A5ABBEB14C84FAAC1498 20BDB26AD13A268644C42B9088E116D4ACDE91A1458651E5BB4170C9107F5E5D 9248D6D6D6BAEB5A6DB7A26FAF5F7A76ABF3A27D572EB0580E0B38D942F88B59 FAC98DC5AF990420862C842065E1A4187C42329C6462830BDBB29C07B87C6252 6900D4BE65DF957A63736B32789B081A38C1F51B4644AC241E1CF3A2C5EA4356 FF5CD6FFD3CB4FDBF9766373787461EFC6A9F3AF1F5B381AC72D283755D6D426 26105582C743F65F174F7E0370930C20E97A79F23D87E77FEAFA57BF2C6836E9 C6D371FF8FEF3FB1F4E4DA1F5D75D381C1A0F4D910E03753B46C37732D58BA4D 93C6F53715476FD8E2DE043C8C53A71E3B7FF6CEEDC5BB2FAC9469B9C46CCAD8 7E8FFCE8F4F46BC2F65C61659AE49EBF529F7A60653391653126EEB970EAC1BE D19E971337EFF76391E43F3D16BF7FEF3426C220840810A8B2949C8CF64AA9DD A50D57E3638E6BFCB84AE0F48E4C80A43BE17B2C94C4E3900E29DCCF907AED50 4CD648CBB71EEA1F384F5394AA6450C89BC005B70C7D4551DB8032A4F540DE8A 015D961BDB9FF8D03FAD3CBA7E306E1E6CC905419B945D0EB3D977DFDA7AF3A1 BC5C25425A2F1669C64762C73839352CD84984DBBF5AA53FD7A444D325D4F8B2 6E1CE235886DB93E97916448B68BFCC4D2F0D4AA9F9872B30B45A3ED16809154 060719F9DB56153E80B48877933254754AFD3E1B667A634C04ACF088E6A12E00 1AA790CF399323D92737BA70984E88914F815B9A42DE79C638A0F4466636C258 16C57CAF7BBA19BFFDF4199DD3BFBAFA9AD54B2BF7B6E39705D1EB2F2E2F3626 B0B94B59D5A883CB809D238631436245081F423B212E4E763C717638E1C6EE58 AA8D28F26EDA3C9B26DD7AFC99D0FBD85D0FFEFC0DFBDF307B250966A3D6647F EDD96F3EFDD0C74F2D9D89F7792DBD7A61E995ADE67B0ECF1E2DE1908685088D CE54516EE5B68FE2552CD072B14DDBDDAC5D049FA2E507509981FED4D12347B2 CE71210E6B394E586A504246A0889601BCEA978815B6185FA7D946D11BF88DA1 AE9559D623C347B8BEEBD2E563F35379587BF0D97358F919DC61C12B4D45257A CE779CC6A74BF5A31333AF69CF6E0F2FF366542BA8DFCBB7855DA96308A90FB8 16C15A24BFD45F3AB9B97575BDFEE6706ED2D08E1C36A53D4AC4249CCED00616 BD3AA9CF7338026EACEB5A601596272E5BC0D1E1D810559578BA12A91139A0A2 4A6D9DA6825C16655E0F86C2F6A9592FB38BABAB4F156A4BB23092FB67C6AF8C 5B631DE56DE554864F66BD87D2AD8B0AB54E9AF83E3D5DAF8FC7B5A95AD4B4A4 9E638DEB6799505A01A812644D2597B33E3230498CFBB20C75E9E0DBE645590B C2561C35843FE6454D2E214749C216548F73494BA8D08B0039D8106E15D4EB9E 53ADE4A553A835366DC30F6FB18E31D643791AC74E744AA9D80AC5260F86DC0E F1352E9459E536225C231FB72C2DDDD90970152114FBA344883F210ED8E0720D 2011129B29B29EE56BBE789224F76D6ECED4DB37D7E34E3EB8A84C5386D786FE 74D69FB17E9B844D291B9C8C29DB423E831598CA918F3FFAE178E50A8C4C748E 89A2FAE62F4884A34EE68EB423D911C2E21A3D0E49658CE50C719D1A19FE852B 03A3B51162AA7E122E1AE29242C53E72B00B4B37F764B0200E9D3A02C011ED68 43704C0A8BE6A080FD71F05F949554FAA2CCFBB68C2C9B10D118957EA678692A 3D2AEB04F921174ADC517106423B16881569D939078CFEA295F61B0AED302776 85D200B822871A25A8D72503891BCBB86F82DF1F8A000F9981AC80DF50D21020 09F3564949837A90D2AC9B9E26D977F2F5AF9FEFDD7E78DF7C63D21FE6931B03 9FF16F46E623BDE5277BA94542040666809FA146EA81AA98AF0E7E00722A1DC3 C72BC84D639311A1CBB27C4F7326E8A711F7A7B85FD319F5D13EA39ECB3132F1 08A7EF5D7CF0E9313631E447F72E246717DFBCE7C8D87030E3FB6D7C896924D9 82163109BEE1B3DF3EFBC413052473A9683E29A2DBDA33EFBCEAC89BAF9CDDEA AF9E0FE3DFBFE37F5DDD9A7BFBFEB9C326E90FB7951F701B7A2CC8D3C44EF9B5 1BAF31937B65E9659DCDFB9F3AF19907BF75B697B46623AFE9EF27531732FBE0 FAF2603878DBECCC4F4FEF6F77364A9FAF05CDBBCE5CBC20F399437BD69E3DF3 896E9A62231A8702DAAFC92C7FCF44FB3FCCB61B2AE90421FC071F2A426FE439 58D13E9EF31EC15ADE6D6EC0574080C2554028C4BCD0E3814F7C88051E0921E0 081A317FA2CE2011A2301A7110132E0D2428DCA540E693C9B04B8034679E41B4 ACCD3C7BB673FA81475F3C33F5975F78F8D48995A3516B7FDDCED7BC290A9F7D 18DE3EBEF07FBE64303350858975640138559EA5A65ADB0A79E012A1D9FE655B 1581709628EA9249B48186BCCDCBA04E6CEC16F08894294D75797AA3FBE879B1 96D2CD21EB15A45F02BE2D53654AEB242D549419A8C9D3C23454AB53E8F36CB3 29D4151A1E91D793BC56AA56A17B1E12053D77BFCC887087D90FF04165CA49AB 4E0EE00EF8B7394422D3F7635614B379FF992878D71367AE3C7EE487026FE9D1 93FCF055575172FDE6DA5AD840E7598C03CEBB15DD3AD101031766A122E4463B C751FA3C9ACC2E55948C24C176D4212D19707F7E38ECC6E1FFF4F9C7BE72E267 AF9CFDC123379AE62C8F1AE5A5D34F3C7BF2631796BE1E4CBC6961DFA34F3D3E 29CA5FBEEEE0B5BD4494E150048528933CDF4E4B9472E2B8E1BC5433E39DBC66 C3BF15E59FAE5E9C14B5D72F4C89CD33FF6672FEE63E4465D2F56D3D153EA183 086DADA0A62CB8B72EBD359B6C95FDBE5FBF9C7BA8042A8B0749F1C5A5CB57EC 192751F3B1331770071DD7BB2B6CCFABCD018CD21869ED8B6AE1DB660F1CC900 A70D73080A5A9485DDF4C9C087FB6FC2C23B2FD8B7B2CE3DDBAB2F0FE257B6F6 007229D5609C91235E3823B9E7E1D81887AAA8734544E9D3D1F6AB0B97463BD5 69C799D1C81E85736651630899DA523324412BD44F5989CCB9367D8AF717D3AE 52B6663D9194E3A53838374F43EF726FAB6BF55A9AF77293589121EB5D37255F 08BDBDDCAB330FB5C3F2C2B35A3A1D75DCEF6104A25186ABF95E9E972A47D30B 1F1E9D1F720C80481AAC41FCB314D28F0761172A53C8E56E1D45684D76D6B79D B49BAA383ED566BDBBC1F89F525BC2A794188BA9D3B8319588BCF350D3D51E08 9CDCA11F004A441D1364EAD31247F9B4C0D6341DAD2D56B595418EAB70C41185 4F0B499829A303A3014C6E66E54AC84FE4BDFB373A876BF597B66A6B797252EB 1A2442C10FB2728E7A93B6D662B2CEEC78A96B1A679D0C13A1C51E3AF2EBA068 1576B4CE4E391F6DBAEB7F5553DEEEBAEA8E12A144F170639FE73365DCAE8B71 D526D9E1C2E278D30D82AB5543E55C440BE751039FBA44696BEC4CA0E03E56AA 6E2D93B3A1641DAE0748F9134DC3B1CD8B6314BA16D875536CABA166A466F98C 0DF6582F2CF10FE18A14C356AA5F6A85AE3A5078B10A9470B772A6DDEBC0AC83 9D5278A7C4AD6D08D7A3771D54E75482494A30110AF48AF6B8E3BEE2CE0F8AEC 389E8E8022C6A21E52EA714D85CC59A820AA157D4E3EDBBD74FF7A7F6EFFBE5B 59F35067C875B1510F4F58FBC5B5E547079DBE70D370B428554EC0933814E258 C404C336C1150933C3C3462D5EE7E52F8F2FD8B58D5610EDAB351AC3BEEF9B5C 40A8B407CA899530FEC5C507EE11BA41BD8566C3F47A6F3C7CDC3B776921AE4F 346A6D6A26F36C06C27E5ED0DAD883C6FED9C533F7904122583DF57D52BC62EF DC7F7EDD4BAFCEB381127FD74F3EFAD5AFFEF8FE7D6F83FC324C0AE95B933C5A AB9DDED8BEE5FA1BDA870E13D96CE4E41B4F3FF4A7F7DF4572F18B0B076EA9D7 33994643CB8AF6DDB6FC3B7D8975377FA1397FAD5699B06BB2FEE9A5C5FB587A EDB143CD27573ED0EFA0FE35AE8B1378575EAE7F7D76F2BD13B546996EF90145 D00F31CAD5371825460BA16E851C0755B61298852CE8E146B9C6D51F2E439FC6 48014581B0484022243EDE5E1E71E33913267CA84806A7EED4BB8451C28DC532 3188ADD7E815F5DFFFC0C72F3CF0D41FFCDB57DDB334B8E78167E6BDFAFE069F 6DCA591A3613A5DA8343BFF512F3AAF1022AEC3C2A58E6B4CD70EA86114186CC BF6A76EA7D90087FC988AA8D02E703576D24F2D9A14A0DCB30A20C9E364EBB89 3F405388D5E1E0B173EACC06DF28F876660648A95139FAE8E2DA1F8AEB1B2FCB 99969B41EDC4FA2A2B939BA627BC3437C6C7240EF105F96DD23EA727E14439DC 76A1331DD5AEE5662AA3468A5C30A7056BA0D25246161709FDF05367F7BFEAB5 9DD5B3D1A90B6F983B3E863DF3AE44252EEC5671279DC3DCB218223F8F414508 B580D3F4A24EE3AB92C077C2FBA335A75DF9C46A258E7499B77790F482E0D3A1 F8E8D74EFCC054FCEE17BFD6B6A701649A73A7CE5EB870E770F0575BDD5F397A EBC9A57369B2FC0BC7F6DED2CFA33CEA726FE897DD6CD8C7D32288134F852F2B ACE9C5FEDFA2E2F61A3C8643A67CC7A13D6FAA4D4E6F24DC427D6B628522DF59 60A0620E4A9331B122F986C9FB6AB0EE45CF26D6E445ADE17DBB48BEB0BCB6A7 1187CDE6B9E5B5A2127030AA62665432C9524248CE5A9CFDFCE4C2E176B3DEEB C40CAA16B6AD49CAA182742BD85CAE337A5F7FF31BDB1BB786F1EDD37BC62D2F CC70DCDAABA8BFC0250ABA60274F699FA50145AE6FE6558612CE8E025321245C F8841AFB0106B360456C2F4AC07B79E8AF487349173916896435E97659D1ACB7 27833A1C855E4D36131D6D67795A6C0E875B507EB46BB41687BE57E7B2C66854 96F5A404CCC4F10B97CCBD5907D4A81288E5351478AE3D06B7C4231CEE4EBDC8 A0A4C6B20F5EAF429A3CAECF18E2441BDCACAB62C750A1AB891114676E07DE54 978B8E960EAB2E5F4D8D9A047624A7622A36388AEEE0661E4A07C0F7EA738E89 10DDDBDD46043A94A1E603FAC8BA6CE714E9717903C5A3F14B72A872DD180FA9 A4430D0F8F6CE7E56ACDBFBFBFFEF056FFE593D3B779F2924EBFDCE9B46BAD63 BABC26E6F35E306BEB6D2BEBD436E0C9546ADF489581BB0A279C238A8522D18E 047E391D7970389EB425FFFA5FBBA97047F265A75AB41547A63206194996E36F 93051BCD158D75171DE96785CB85B9B51954C678454DEAC9D2652489924302B2 424F12C040DB45164A7F326E8488FDB0615E6A5C5EDBA24547A5F05262CB67BD 78827A7161785E7A3803C5FA5332E2A3DC209E5B4C731C15DE71711233198EEB A4533FD35452B6C304AF3A5F804F1CC286DC2C256A2FE255F7B596B8C48DB5AA 132192D8D3C3EA7928B1E9562B693D21677CFB3935F8C74BCB578FCDBEB13915 6FAD6B299246FB9924B97FE3F223DDEE12B67301E8964CBB44E8787FDCC106DC E3914C943AB0C4F7FD2C10EF9E5C60EB9B535170A4D59AE8270129F298C586CF 6D72559FF8EDDEB31F815B6EC534876796DF72F48AF8F4F2B5F144CDF3E76430 D7192E48EA3305907A10D6EFD6C97F5B39F3A02E27B448A81F08FB7BAFB9E95D 7BA63C153E363BF7275FFD62F1E4133FBBE7C0354AF8F9A0F48ABFAB07DF21FA C76E7DCD0D6476C0BCBB2E3FF6A92F7EEE58D0FEA18563570E07ADC1329C5C00 07A26CF783D65333D1C98D73FB95BA062EA2F59EE6E293C9DA3FA75B2FBBF2D0 C1531BEFEFF7D04D0F62383C6D1940987ADFDE99F7D4BCBACAB7C2103E7E604A 052FC1A0466865AE4BAB7488CB00F8AF11200ADC8E6050CFC5820502CA4140C3 26848A50DA807180773E87530D119B0782B9150B77E8CA4A969DE15BE638F785 225106DA9BFAD8A7EEFBC33FFEA763CDF08FDF78CB968E3F75DF439BA93A38D6 D8E793F9209A448E5177FF4F1E1F7FD7F1211936585CE821A7954491EB6B8860 2711767FD13A8D0DB8EE706A73AB8354A8F582D59A76B205E70EC01E03A814E4 12EAC86E963EB5989FBCE4AD412254AA57DA1C8D7C4C5290D2EA4227A498EB03 44640F34F9A3FDAD9B0BEF7A3FD8643994B0ED4440B0DDF675A085A7A8DE118D B76EC4E436278493BDD9112680824421633D830755A0AEFC5648174D71F7998B E2E65BEF3DF5C4AB44F076AFA5B3BCDB0827B21CFBFD58BA383526E296C2DCED 105100C8A2A42E5018BB43CA19499E3F2F0B3E1721B6843C38488632BCAB59BB E3BE6FDF1CD29F7BED9BFDE6746859F2F49367D7D6BE60CA3B2E2EBE349A2819 8BCACECF1D9EBD6DA864E675A5DF17C556D24F01AD720F2547289B18925ECD3E 33CEFFFECCD2DD5BC33420D74AF17B078F5ED783EAB10C18EE0B1A11A06C001A B61AF86309974B50299A42537D418A877B59DAEFEFDD33F148967CE5D22A9C9F A81E6FF7D35C550CF76A04C25C2EA43E6431951D9D1EFFCF644F5683A0369490 4D18D497F07BFCC6C0428E3BD3B07725ABE7D7BB33A2FD33E3131BBE2A5472BD D7B8DAE9EB979E862716E232862D7C368828A4EB06A275A2474AD4CE4A028E76 819284B843AA502B1BD18740CDB68B4C3FC5D215CFB6C3FA0153AB77F37A49C7 8917427D6CB3C71B2A93CC4F4DAD6435226338FFC44444C38F0DF72C172C45CA 15D40790D255E627082F911F41B0D034AECE43695363B85252971495B5EAAA81 CCB21D285351FE2B8C4347D3BAAAFED796EC78C1D05D1B05475E1E7925E0DF03 35A280A2381AEA1857AC2EA7916430FB32E3D4FD91508F32D680573111A26412 442C54FF71BA4B6838017F2548D6B7C249A30040423152AC6058866D74D22BD5 7A23BA77EBD2A97EF6968503AF6B344FEBE4134B177C1EBFAC1EEF33BDBD51B4 4737C6B4173328078B18BEB240460F0B180BD0F5C31978D06AA037626F3A311B C5BF6B5596ED98E13C971DDD3860C7A371472ED93EDF1AA9329274A335D735C5 FC88CBEA23E60A6E13006CC8D0A54D4309B721FCBE2E074E10068D4501D549DA 0DF9655A0C89C9CA222B0A8892335ED3CB8C2F2424BA7E405779B1A5F3B43F18 D3FCB0DF9815112D2196CB16170DC88BE83A89752B4026F4D8A423C5560425B4 92F60370ED911115C88CBC3F5C5277CF863A6B1A9C0DF99E363E7AA30A8C0758 DC42DD59CFF1F7C28F3184635FD85609B1387AB2577C8E9B7F5C3B7DD3C4F85B E209B1DD1D22FF3C28897FCFD6FAFFDE58BB04E98EA5D5B2A8DBA6ACA6AA959A 0B0E2D3C6CBE2AEB796F9C9C690E923DBEB8667C6C76908779AE1B1EFCE40B1D 2E83F627FDC1EF5C38D9D162425B2FA273FB676A6756DE30B9DF23A85CB1AFB4 D728B83BAAC40DC66048C5E786C91F6F5F1A14E976D06639FDC9E393FFFEF623 63F5E96DDDB8BCBDFD892F7CA629821F6E4E5DBBB97DA616FDC1E5C53DAFBAE5 676FB87DFCA9CE5D17CEFDD5A57BAE90FEBFE357CC6DE84EB3AF5837EEE7FD46 AB06771D8D7D583FD209405FEBA703F170597C2556FFBCBCF8A27DF3473BE907 37BBB85A0A5854DB42C88665BF7560E1DDC2D64DB91906F01442EB12212E43B8 A68473564097768C4CCE475356146E815CAF484222A4013C71CF865811125702 E25A85C798FB8536A9C4F5E299338BC2EEBB24021BA425C483B07DE7971FF9DD 3FF9C2F21639D0083E70DBA1C3F5B94F3EF2C897B63BFB5A93C7ADDD13891A21 0D564EBF64ECAADF7C653909604269B475336CA492085F39A0FE7197087BBF60 1C579C690A07A0202AEEB3F3F79FF6A7E6276F3C52A83C60A1A571260B498C97 64D9D397CAC797E572CAB74C3940574C9DE47A9052D71CCBB36CCE04A9B277DA EE65C9DEC0C7E757B7CAB6DFE5B29E40142B8602A552444946D7AFDAABC5B927 857F8DC1AB9AE9BBEE1B840D65781220D9C4CBE4A6173ECD06F76C2EA67B8F3D F0F033EF3A72F855B60F78328BA627CB6D97FB50479DBBED275485463B0F2242 497CE68496E8CE24B012A6D86DFABCD034CDDA2DDF3FD01D1622B8AFDDFAF307 BE75452C7FE2556F98AE4DB500093C79F2E18DE57B7DF9F7E7CEAD25C9B817DE 1A05EF3DBC70756FA0739984F18026DBC97088DA87A8A30D3F5473688775F268 DDFCF5A9B3DF49E195AAB7EFDDFB53B5D6D4D2DA542DB6451E7961669038E7C4 1F908ED1E7F22225439503983DE3F1AF757A836EE7EAF93DA78CFAE78B972C2E 4603688698270A5CF0C2852927DF85C36841CA31615F7EECF0AFAFC7EB7EAEB8 D23A57C2DB5256167C22F7D784F95B7BE9DEAC7BA31C7FA77F3C56E7BB35D2E4 F4E6CC3B96101AB26E03AE206B203B02003ECD3D8C35D884AAAC74AB71083A8F D0725850ED56D6DC441B1EFC79DEBFC88B61EC8DD178A60C85A170401A528699 C62A8DB84CC0E1BEE1663AD40E02B74871CF332E755C96E8222D009B03524269 0CCC3262E07CCB71650CBE9A6769886D0AA770CA9C0A24D3CEBC29A0AC329A19 F9308D66C1B45AF718D94428510983DAAA054A779A9C48B3D80DFD84649C55CA 96DC8E542D2B06BF711652A3251B6B3C85DBDE0A0DC270928EE511C56892A38E 1A5C255BB8E5F40E6E2E994A3C0935B295A9F4DF32630A657BA5D9A8F95FDD5E B990163F3677E00D71E3ACD41F5DB90431FF564AAFAEA9B9289853F5B60A4280 0B36F54D5940B9E43111321EE0E45139B30C5C4E76844E1C6FB85456F2EFAA08 D9BF62C089794D8D2687B4724BDE21C958F25C7D556D3518E7D4E378A9F0382A 5B198D8F9B613F48E1FAEF268DBA446FE96C882A0A4830EF58DDE5F888A4DBB3 8434B96DF30B3A51CA2CD4C71A04923949ACEA7B360DF856D61F7406754A179A AD1AD4B96916C0BB16A865E45316103A26BC49C8907919E2FA4A95110DEAF9A3 DE5CB535489D74258AFFB391B691D3A471148948A55091F0500824EDD3000913 A573EF53D5BA6501002790743599B17B9EF2E3BF18EF7FF6D9136F64C10F36F7 D03283A240FAAD93B9BDE3E2B993514DE7EB54DB1D01235AB90AE3DE06B69B20 C5A3F90FFC7AD1D4543B4D0FFBE2FAC9F1F9A1AAC38BAFC17F2AF7E51E37DE83 F3ADF79EF8E6392D27E18306349A8A26973ADFBF70B050692ED4611A5C5FF079 D46D56BA506DBFF664107F70F3E2DDDBCBEB518B0DBD9B65FF3FBDE3E557EC9D 5FD88AA3A1F7C9A7BFFDF1A7BFF58B137BDFD4A5FFC3DA7FDC5AF9A51F78F3CB 09BDEFECE9FFFEE8B76E9D1EFBE9D6CCCCB6018892932413ACAC37753F680E87 46DA0E207D9AF92ADFE4C1A981BD98E8E5D8FFDCE553FBE6E68F29FAE7AB2B1A F7D290E751303EC9BDDF3A7CE0FFD0596CD56618C1A38B4C597ACEEDA42A072B 8B214721C02207BB370220087225A5E4B1C41E69E8D14018C88E2E116213CD87 87003912FFD97536D0400FBB1CD87C2970C0CF6B4A91A1B60F3D7DF1FDFFF757 4F5CE89BA03DE5D90F5E3FFBDAD6C2A7CE3E73C7E6FA4434757DA1A742158772 06C0CB6471FB7FF9DEF8F699ACBFCE3DE1C6D0162B42C4B350111EDB33FDBEFF 1F1CAF12FB8DB29B6E0000000049454E44AE426082} end object lblTitle: TLabel Left = 24 Top = 140 Width = 153 Height = 41 AutoSize = False Caption = 'Mator Smash' Color = clWhite Font.Charset = DEFAULT_CHARSET Font.Color = clBlack Font.Height = -24 Font.Name = 'Tahoma' Font.Style = [] ParentColor = False ParentFont = False end object lblAuthor: TLabel Left = 24 Top = 168 Width = 93 Height = 13 Caption = 'by matortheeternal' Color = clWhite Font.Charset = DEFAULT_CHARSET Font.Color = clBlack Font.Height = -11 Font.Name = 'Tahoma' Font.Style = [] ParentColor = False ParentFont = False end object lblProgress: TLabel Left = 24 Top = 200 Width = 481 Height = 31 AutoSize = False Caption = ' Loading...' Color = clWhite Font.Charset = DEFAULT_CHARSET Font.Color = clBlack Font.Height = -11 Font.Name = 'Tahoma' Font.Style = [] GlowSize = 1 ParentColor = False ParentFont = False Layout = tlCenter end object lblVersion: TLabel Left = 174 Top = 155 Width = 35 Height = 11 Caption = 'v0.0.0.1' Color = clWhite Font.Charset = DEFAULT_CHARSET Font.Color = clBlack Font.Height = -9 Font.Name = 'Tahoma' Font.Style = [] ParentColor = False ParentFont = False end end ================================================ FILE: frontend/msSplashForm.pas ================================================ unit msSplashForm; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls, ExtCtrls, pngimage, // mte units mteTracker, mteHelpers, // smash units msConfiguration; type TSplashForm = class(TForm) lblTitle: TLabel; imgSplash: TImage; lblAuthor: TLabel; lblProgress: TLabel; lblVersion: TLabel; procedure ProgressMessage(const s: string); procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end; var SplashForm: TSplashForm; implementation {$R *.dfm} procedure TSplashForm.ProgressMessage(const s: string); begin lblProgress.Caption := ' '+s; Application.ProcessMessages; end; procedure TSplashForm.FormCreate(Sender: TObject); begin Tracker.OnLogEvent := ProgressMessage; lblVersion.Caption := 'v'+GetVersionMem; if settings.simpleSplash then lblProgress.GlowSize := 0; end; end. ================================================ FILE: frontend/msTagHelper.dfm ================================================ object TagHelper: TTagHelper Left = 0 Top = 0 Caption = 'Tag Helper' ClientHeight = 412 ClientWidth = 334 Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'Tahoma' Font.Style = [] OldCreateOrder = False Position = poMainFormCenter OnClose = FormClose OnCreate = FormCreate OnShow = FormShow PixelsPerInch = 96 TextHeight = 13 object lblPrompt: TLabel Left = 8 Top = 8 Width = 185 Height = 13 Caption = 'Check the tags you want to {ACTION}' end object CheckList: TCheckListBox Left = 8 Top = 27 Width = 318 Height = 346 Align = alCustom Anchors = [akLeft, akTop, akRight, akBottom] ItemHeight = 13 Sorted = True TabOrder = 0 end object btnCancel: TButton Left = 251 Top = 379 Width = 75 Height = 25 Align = alCustom Anchors = [akRight, akBottom] Caption = 'Cancel' ModalResult = 2 TabOrder = 1 end object btnOK: TButton Left = 170 Top = 379 Width = 75 Height = 25 Align = alCustom Anchors = [akRight, akBottom] Caption = 'OK' ModalResult = 1 TabOrder = 2 end end ================================================ FILE: frontend/msTagHelper.pas ================================================ unit msTagHelper; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, CheckLst, // mte units RttiTranslation, // smash units msConfiguration; type TTagHelper = class(TForm) CheckList: TCheckListBox; lblPrompt: TLabel; btnCancel: TButton; btnOK: TButton; procedure FormShow(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } slTags: TStringList; iMode: Integer; end; var TagHelper: TTagHelper; implementation {$R *.dfm} procedure TTagHelper.FormClose(Sender: TObject; var Action: TCloseAction); var i: Integer; begin slTags.Clear; if ModalResult = mrOK then for i := 0 to Pred(CheckList.Items.Count) do begin if CheckList.Checked[i] then slTags.Add(CheckList.Items[i]); end; end; procedure TTagHelper.FormCreate(Sender: TObject); begin // do a translation dump? if bTranslationDump then TRttiTranslation.Save('lang\english.lang', self); // load translation TRttiTranslation.Load(language, self); end; procedure TTagHelper.FormShow(Sender: TObject); begin // update lblPrompt case iMode of -1: begin Caption := GetLanguageString('msTagH_RemoveTags'); lblPrompt.Caption := GetLanguageString('msTagH_PromptRemove'); end; 1: begin Caption := GetLanguageString('msTagH_AddTags'); lblPrompt.Caption := GetLanguageString('msTagH_PromptAdd'); end; end; // populate checklist CheckList.Items.Text := slTags.Text; end; end. ================================================ FILE: frontend/msTagManager.dfm ================================================ object TagManager: TTagManager Left = 0 Top = 0 Caption = 'Manage Tags' ClientHeight = 312 ClientWidth = 434 Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'Tahoma' Font.Style = [] OldCreateOrder = False Position = poMainFormCenter OnClose = FormClose OnCreate = FormCreate OnShow = FormShow PixelsPerInch = 96 TextHeight = 13 object Panel: TPanel Left = 0 Top = 0 Width = 434 Height = 273 Align = alTop Anchors = [akLeft, akTop, akRight, akBottom] TabOrder = 0 object lblDescription: TLabel Left = 8 Top = 8 Width = 53 Height = 13 Align = alCustom Caption = 'Description' end object meDescription: TMemo Left = 8 Top = 27 Width = 321 Height = 238 Align = alCustom Anchors = [akLeft, akTop, akRight, akBottom] TabOrder = 0 end object btnClear: TButton Left = 335 Top = 87 Width = 90 Height = 25 Align = alCustom Anchors = [akTop, akRight] Caption = 'Clear Tags' TabOrder = 1 OnClick = btnClearClick end object btnRemove: TButton Left = 335 Top = 56 Width = 90 Height = 25 Align = alCustom Anchors = [akTop, akRight] Caption = 'Remove Tags' TabOrder = 2 OnClick = btnRemoveClick end object btnAdd: TButton Left = 335 Top = 25 Width = 90 Height = 25 Align = alCustom Anchors = [akTop, akRight] Caption = 'Add Tags' TabOrder = 3 OnClick = btnAddClick end object btnReset: TButton Left = 335 Top = 118 Width = 90 Height = 25 Align = alCustom Anchors = [akTop, akRight] Caption = 'Reset Tags' TabOrder = 4 OnClick = btnResetClick end end object btnCancel: TButton Left = 346 Top = 279 Width = 80 Height = 25 Align = alCustom Anchors = [akRight, akBottom] Caption = 'Cancel' ModalResult = 2 TabOrder = 1 end object btnApply: TButton Left = 260 Top = 279 Width = 80 Height = 25 Align = alCustom Anchors = [akRight, akBottom] Caption = 'Apply' ModalResult = 1 TabOrder = 2 end object kbCombine: TCheckBox Left = 8 Top = 283 Width = 201 Height = 17 Align = alCustom Anchors = [akLeft, akBottom] Caption = 'Apply combined setting' Checked = True State = cbChecked TabOrder = 3 end end ================================================ FILE: frontend/msTagManager.pas ================================================ unit msTagManager; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls, RegularExpressions, // mte units RttiTranslation, // smash units msCore, msConfiguration, msTagHelper; type TTagManager = class(TForm) Panel: TPanel; lblDescription: TLabel; meDescription: TMemo; btnClear: TButton; btnRemove: TButton; btnAdd: TButton; btnCancel: TButton; btnApply: TButton; btnReset: TButton; kbCombine: TCheckBox; procedure btnAddClick(Sender: TObject); procedure btnRemoveClick(Sender: TObject); procedure btnClearClick(Sender: TObject); procedure btnResetClick(Sender: TObject); procedure FormShow(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure FormCreate(Sender: TObject); procedure ReadTags; procedure WriteTags; procedure AddTags(var slTagsToAdd: TStringList); procedure RemoveTags(var slTagsToRemove: TStringList); private { Private declarations } public { Public declarations } plugin: TPlugin; end; var TagManager: TTagManager; implementation var slTags: TStringList; {$R *.dfm} procedure TTagManager.btnAddClick(Sender: TObject); var thForm: TTagHelper; begin thForm := TTagHelper.Create(self); try thForm.iMode := 1; thForm.slTags := TStringList.Create; GetMissingTags(slTags, thForm.slTags); if thForm.ShowModal = mrOK then AddTags(thForm.slTags); finally ReadTags; thForm.Free; end; end; procedure TTagManager.btnRemoveClick(Sender: TObject); var thForm: TTagHelper; begin thForm := TTagHelper.Create(self); try thForm.iMode := -1; thForm.slTags := TStringList.Create; thForm.slTags.Text := slTags.Text; if thForm.ShowModal = mrOK then RemoveTags(thForm.slTags); finally ReadTags; thForm.Free; end; end; procedure TTagManager.btnClearClick(Sender: TObject); begin meDescription.Lines.Text := ClearTags(meDescription.Lines.Text); ReadTags; end; procedure TTagManager.btnResetClick(Sender: TObject); begin meDescription.Lines.Text := plugin.description.Text; ReadTags; end; procedure TTagManager.FormShow(Sender: TObject); begin // create tags stringlist slTags := TStringList.Create; // update description and tags meDescription.Lines.Text := plugin.description.Text; ReadTags; // update the form's caption Caption := Format(GetLanguageString('msTagM_Caption'), [plugin.filename]); end; procedure TTagManager.FormClose(Sender: TObject; var Action: TCloseAction); begin if ModalResult = mrOK then begin plugin.description.Text := meDescription.Lines.Text; if kbCombine.Checked then plugin.GetSettingTag; plugin.WriteDescription; plugin.Save; end; // free memory slTags.Free; end; procedure TTagManager.FormCreate(Sender: TObject); begin // do a translation dump? if bTranslationDump then TRttiTranslation.Save('lang\english.lang', self); // load translation TRttiTranslation.Load(language, self); end; procedure TTagManager.ReadTags; var bHasTags: Boolean; begin slTags.Clear; ParseTags(meDescription.Lines.Text, slTags); bHasTags := slTags.Count > 0; btnClear.Enabled := bHasTags; btnRemove.Enabled := bHasTags; end; procedure TTagManager.WriteTags; var sTags: String; begin // clear tags meDescription.Lines.Text := ClearTags(meDescription.Lines.Text); // if no tags to write, exit if slTags.Count = 0 then exit; // see if all of the tags belong to the same group sTags := GetTagString(slTags); // write the tags to the description meDescription.Lines.Add(' '); meDescription.Lines.Add(sTags); meDescription.Lines.Text := Trim(meDescription.Lines.Text); end; procedure TTagManager.AddTags(var slTagsToAdd: TStringList); var tag: string; begin // add the tags to slTags for tag in slTagsToAdd do slTags.Add(tag); // write tags to the description WriteTags; end; procedure TTagManager.RemoveTags(var slTagsToRemove: TStringList); var tag: string; begin // remove the tags from slTags for tag in slTagsToRemove do slTags.Delete(slTags.IndexOf(tag)); // write tags to the description WriteTags; end; end. ================================================ FILE: frontend/msThreads.pas ================================================ unit msThreads; interface uses Classes, SysUtils, StrUtils, shlObj, Dialogs, ComCtrls, Windows, MMSystem, // superobject superobject, // mte units mteHelpers, mteLogger, mteLogging, mteTracker, mteBase, // ms units msCore, msConfiguration, msLoader, msSmash, // xedit units wbBSA, wbInterface, wbImplementation; type // THREADS AND CALLBACKS TCallback = procedure of object; TStatusCallback = procedure(s: string) of object; TInitThread = class(TThread) protected procedure Execute; override; end; TLoaderThread = class(TThread) protected procedure Execute; override; end; TPatchThread = class(TThread) protected procedure Execute; override; end; TSaveThread = class(TThread) protected procedure Execute; override; end; var InitCallback, LoaderCallback, ErrorCheckCallback, ErrorFixCallback, PatchCallback, SaveCallback: TCallback; StatusCallback: TStatusCallback; implementation {******************************************************************************} { THREAD METHODS These are threads that the program will run for various large jobs which need to be decoupled from general program operation and the GUI. List of methods: - TInitThread.Execute - LoaderProgress - TLoaderThread.Execute - TErrorCheckThread.Execute - TPatchThread.Execute - TSaveThread.Execute } {******************************************************************************} { TInitThread } procedure TInitThread.Execute; var i: integer; plugin: TPlugin; aFile: IwbFile; begin try // PRINT LOAD ORDER TO LOG for i := 0 to Pred(slPlugins.Count) do Logger.Write('LOAD', 'Order', '['+IntToHex(i, 2)+'] '+slPlugins[i]); // LOAD RESOURCES Tracker.Write('Loading Resources'); wbContainerHandler.AddFolder(wbDataPath); LoadBSAs; // LOAD PLUGINS for i := 0 to Pred(slPlugins.Count) do begin Tracker.Write('Loading '+slPlugins[i]); try plugin := TPlugin.Create; plugin.filename := slPlugins[i]; plugin._File := wbFile(wbDataPath + slPlugins[i], i, '', False, False); plugin._File._AddRef; plugin.GetMsData; PluginsList.Add(Pointer(plugin)); except on x: Exception do begin Logger.Write('ERROR', 'Load', 'Exception loading '+slPlugins[i]); Logger.Write('ERROR', 'Load', x.Message); ProgramStatus.bLoadException := true; end; end; // load hardcoded dat if i = 0 then try aFile := wbFile(wbProgramPath + wbGameName + wbHardcodedDat, 0); aFile._AddRef; except on x: Exception do begin Logger.Write('ERROR', 'Load', 'Exception loading '+wbGameName+wbHardcodedDat); Logger.Write('ERROR', 'Load', 'Please download and install this dat file!'); raise x; end; end; end; // LOAD PLUGIN INFORMATION Tracker.Write('Loading plugin information'); TPatchHelpers.AssignPatchesToPlugins; LoadPluginInfo; LoadSettingTags; // CLEAN UP slPlugins.Free; except on x: Exception do begin if Assigned(slPlugins) then slPlugins.Free; ProgramStatus.bInitException := true; Logger.Write('ERROR', 'Load', x.Message); end; end; if Assigned(InitCallback) then Synchronize(nil, InitCallback); end; { TLoaderThread } procedure LoaderProgress(const s: string); begin if s <> '' then Logger.Write('LOAD', 'Background', s); if ProgramStatus.bForceTerminate then Abort; end; procedure TLoaderThread.Execute; var i: Integer; f: IwbFile; plugin: TPlugin; begin FreeOnTerminate := true; StatusCallback(Format('%s (%d/%d)', [GetLanguageString('msMain_LoaderInProgress'), 1, PluginsList.Count])); try for i := 0 to Pred(PluginsList.Count) do begin StatusCallback(Format('%s (%d/%d)', [GetLanguageString('msMain_LoaderInProgress'), i + 1, PluginsList.Count])); plugin := TPlugin(PluginsList[i]); f := plugin._File; if SameText(plugin.filename, wbGameName + '.esm') then continue; LoaderProgress('[' + plugin.filename + '] Building reference info.'); f.BuildRef; if ProgramStatus.bForceTerminate then begin LoaderProgress('Aborted.'); break; end; end; except on E: Exception do begin LoaderProgress('Fatal: <' + e.ClassName + ': ' + e.Message + '>'); wbLoaderError := true; ProgramStatus.bInitException := true; end; end; LoaderProgress('finished'); StatusCallback(GetLanguageString('msMain_LoaderFinished')); if Assigned(LoaderCallback) then Synchronize(nil, LoaderCallback); end; { TPatchThread } procedure PlaySmashSound; var HResource: TResourceHandle; HResData: THandle; PWav: Pointer; begin HResource := FindResource(HInstance, PChar('SMASH'), 'WAV'); if HResource = 0 then exit; HResData := LoadResource(HInstance, HResource); if HResData = 0 then exit; PWav := LockResource(HResData); if not Assigned(PWav) then exit; sndPlaySound(nil, SND_NODEFAULT); sndPlaySound(PWav, SND_ASYNC or SND_MEMORY); end; procedure TPatchThread.Execute; var i: integer; patch: TPatch; begin FreeOnTerminate := true; // build patches for i := 0 to Pred(patchesToBuild.Count) do begin if Tracker.Cancel then break; patch := TPatch(patchesToBuild[i]); StatusCallback(Format('%s "%s" (%d/%d)', [GetLanguageString('msProg_Smashing'), patch.name, i + 1, patchesToBuild.Count])); try if (patch.status in RebuildStatuses) then RebuildPatch(patch) else BuildPatch(patch); except on x : Exception do begin patch.status := psFailed; Tracker.Write('Exception: ' + x.Message); end; end; Tracker.Write(' '#13#10); Tracker.SetProgress(IntegerListSum(timeCosts, i)); if Tracker.Cancel then Tracker.Write('Smashing canceled.'); end; // say thread is done if it wasn't cancelled if not Tracker.Cancel then begin Tracker.Write('All done!'); try if settings.smashSound then PlaySmashSound; except on x: Exception do Tracker.Write('Failed to play Smash sound.'); end; end; // clean up, fire callback StatusCallback(GetLanguageString('msProg_DoneBuilding')); Tracker.Cancel := false; if Assigned(PatchCallback) then Synchronize(nil, PatchCallback); end; { TSaveThread } procedure TSaveThread.Execute; begin FreeOnTerminate := true; // save ESPs only if it's safe to do so if not ProgramStatus.bInitException then begin // Save plugin errors try SavePluginInfo; except on x: Exception do Tracker.Write('Exception saving plugin errors '+x.Message); end; Tracker.SetProgress(PluginsList.Count + 1); // save patches SavePatches; // force close files wbFileForceClosed; // rename saved plugins RenameSavedPlugins; end; // save statistics and settings SaveStatistics; SaveSettings; // delete temppath if not settings.preserveTempPath then DeleteTempPath; // print final messages Tracker.Write(' '); Tracker.Write('All done'); // unbind events Logger.OnLogEvent := nil; Tracker.OnLogEvent := nil; Tracker.OnStatusEvent := nil; if Assigned(SaveCallback) then Synchronize(nil, SaveCallback); end; end. ================================================ FILE: frontend/settings/Fallout3/Smash.All.json ================================================ {"records":"ACHR,ACTI,ADDN,ALCH,AMMO,ANIO,ARMA,ARMO,ASPC,AVIF,BOOK,BPTD,CAMS,CELL,CLAS,CLMT,COBJ,CONT,CPTH,CREA,CSTY,DEBR,DIAL,DOOR,ECZN,EFSH,ENCH,EXPL,EYES,FACT,FLST,FURN,GLOB,GMST,GRAS,HAIR,HDPT,IDLM,IMAD,IMGS,INFO,INGR,IPCT,IPDS,KEYM,LAND,LGTM,LIGH,LSCR,LTEX,LVLC,LVLI,LVLN,MESG,MGEF,MICN,MISC,MSTT,MUSC,NOTE,NPC_,PACK,PBEA,PERK,PGRE,PMIS,PROJ,PWAT,QUST,RACE,RADS,REFR,REGN,RGDL,SCOL,SCPT,SOUN,SPEL,STAT,TACT,TERM,TREE,TXST,VTYP,WATR,WEAP,WRLD,WTHR,ACRE","description":"Smashes all the things. Produced using autoset attributes on all record prototypes produced by v1.0.0.\r\n\r\nLast updated 4\/30\/2018.","tree":{"records":[{"t":1,"p":1,"n":"ACHR - Placed NPC","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"NAME - Base"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":11,"n":"XRGD - Ragdoll Data"},{"t":11,"n":"XRGB - Ragdoll Biped Data"},{"t":6,"s":1,"p":1,"n":"Patrol Data","c":[{"t":5,"p":1,"n":"XPRD - Idle Time"},{"p":1,"n":"XPPA - Patrol Script Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":6,"p":1,"n":"Embedded Script","c":[{"t":6,"p":1,"n":"SCHR - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"p":1,"n":"SCDA - Compiled Embedded Script"},{"t":2,"p":1,"n":"SCTX - Embedded Script Source"},{"t":10,"p":1,"n":"Local Variables","c":[{"t":6,"p":1,"n":"Local Variable","c":[{"t":6,"p":1,"n":"SLSD - Local Variable Data","c":[{"t":3,"p":1,"n":"Index"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"SCVR - Name"}]}]},{"t":8,"p":1,"n":"References","c":[{"t":3,"p":1,"n":"SCRO - Global Reference"},{"t":3,"p":1,"n":"SCRV - Local Variable"}]}]},{"t":3,"p":1,"n":"TNAM - Topic"}]},{"t":3,"p":1,"n":"XLCM - Level Modifier"},{"t":3,"p":1,"n":"XMRC - Merchant Container"},{"t":3,"p":1,"n":"XCNT - Count"},{"t":5,"p":1,"n":"XRDS - Radius"},{"t":5,"p":1,"n":"XHLP - Health"},{"t":8,"s":1,"p":1,"n":"Linked Decals","d":1,"c":[{"t":6,"p":1,"n":"XDCR - Decal","c":[{"t":3,"p":1,"n":"Reference"},{"t":11,"n":"Unknown"}]}]},{"t":3,"p":1,"n":"XLKR - Linked Reference"},{"t":6,"s":1,"p":1,"n":"XCLP - Linked Reference Color","c":[{"t":6,"p":1,"n":"Link Start Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Link End Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIBS - Ignored By Sandbox"},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"ACTI - Activator","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"SNAM - Sound - Looping"},{"t":3,"p":1,"n":"VNAM - Sound - Activation"},{"t":3,"p":1,"n":"RNAM - Radio Station"},{"t":3,"p":1,"n":"WNAM - Water Type"}]},{"t":1,"p":1,"n":"ADDN - Addon Node","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":3,"p":1,"n":"DATA - Node Index"},{"t":3,"p":1,"n":"SNAM - Sound"},{"t":6,"s":1,"p":1,"n":"DNAM - Data","c":[{"t":3,"p":1,"n":"Master Particle System Cap"},{"t":11,"n":"Unknown"}]}]},{"t":1,"p":1,"n":"ALCH - Ingestible","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Drop"},{"t":3,"p":1,"n":"ETYP - Equiptment Type"},{"t":5,"p":1,"n":"DATA - Weight"},{"t":6,"s":1,"p":1,"n":"ENIT - Effect Data","c":[{"t":3,"p":1,"n":"Value"},{"t":3,"p":1,"n":"Flags?"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Withdrawal Effect"},{"t":5,"p":1,"n":"Addiction Chance"},{"t":3,"p":1,"n":"Sound - Consume"}]},{"t":8,"s":1,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":3,"p":1,"n":"EFID - Base Effect"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":3,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Actor Value"}]},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"CTDA - Condition","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Note"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Creature Type"},{"t":3,"p":1,"n":"Menu Mode"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Body Location"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"VATS Value Function (INVALID)"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"}]}]}]}]}]},{"t":1,"p":1,"n":"AMMO - Ammunition","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Drop"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":5,"p":1,"n":"Speed"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Value"},{"t":3,"p":1,"n":"Clip Rounds"}]},{"t":2,"p":1,"n":"ONAM - Short Name"}]},{"t":1,"p":1,"n":"ANIO - Animated Object","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":3,"p":1,"n":"DATA - Animation"}]},{"t":1,"p":1,"n":"ARMA - Armor Addon","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"BMDT - Biped Data","c":[{"t":3,"p":1,"n":"Biped Flags"},{"t":3,"p":1,"n":"General Flags"},{"t":11,"n":"Unused"}]},{"t":6,"s":1,"p":1,"n":"Male biped model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Male world model","c":[{"t":2,"p":1,"n":"MOD2 - Model Filename"},{"t":11,"p":1,"n":"MO2T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO2S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":2,"p":1,"n":"ICON - Male icon filename"},{"t":2,"p":1,"n":"MICO - Male mico filename"},{"t":6,"s":1,"p":1,"n":"Female biped model","c":[{"t":2,"p":1,"n":"MOD3 - Model Filename"},{"t":11,"p":1,"n":"MO3T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO3S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MOSD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Female world model","c":[{"t":2,"p":1,"n":"MOD4 - Model Filename"},{"t":11,"p":1,"n":"MO4T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO4S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":2,"p":1,"n":"ICO2 - Female icon filename"},{"t":2,"p":1,"n":"MIC2 - Female mico filename"},{"t":3,"p":1,"n":"ETYP - Equiptment Type"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Value"},{"t":3,"p":1,"n":"Max Condition"},{"t":5,"p":1,"n":"Weight"}]},{"t":6,"s":1,"p":1,"n":"DNAM - ","c":[{"t":3,"p":1,"n":"AR"},{"t":3,"p":1,"n":"Flags"}]}]},{"t":1,"p":1,"n":"ARMO - Armor","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"SCRI - Script"},{"t":3,"p":1,"n":"EITM - Object Effect"},{"t":6,"s":1,"p":1,"n":"BMDT - Biped Data","c":[{"t":3,"p":1,"n":"Biped Flags"},{"t":3,"p":1,"n":"General Flags"},{"t":11,"n":"Unused"}]},{"t":6,"s":1,"p":1,"n":"Male biped model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Male world model","c":[{"t":2,"p":1,"n":"MOD2 - Model Filename"},{"t":11,"p":1,"n":"MO2T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO2S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":2,"p":1,"n":"ICON - Male icon filename"},{"t":2,"p":1,"n":"MICO - Male mico filename"},{"t":6,"s":1,"p":1,"n":"Female biped model","c":[{"t":2,"p":1,"n":"MOD3 - Model Filename"},{"t":11,"p":1,"n":"MO3T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO3S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MOSD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Female world model","c":[{"t":2,"p":1,"n":"MOD4 - Model Filename"},{"t":11,"p":1,"n":"MO4T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO4S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":2,"p":1,"n":"ICO2 - Female icon filename"},{"t":2,"p":1,"n":"MIC2 - Female mico filename"},{"t":2,"p":1,"n":"BMCT - Ragdoll Constraint Template"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"REPL - Repair List"},{"t":3,"p":1,"n":"BIPL - Biped Model List"},{"t":3,"p":1,"n":"ETYP - Equiptment Type"},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Drop"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Value"},{"t":3,"p":1,"n":"Max Condition"},{"t":5,"p":1,"n":"Weight"}]},{"t":6,"s":1,"p":1,"n":"DNAM - ","c":[{"t":3,"p":1,"n":"AR"},{"t":3,"p":1,"n":"Flags"}]}]},{"t":1,"p":1,"n":"ASPC - Acoustic Space","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"SNAM - Sound - Looping"},{"t":3,"p":1,"n":"RDAT - Use Sound from Region (Interiors Only)"},{"t":3,"p":1,"n":"ANAM - Environment Type"}]},{"t":1,"p":1,"n":"AVIF - ActorValue Information","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":2,"p":1,"n":"ANAM - Short Name"}]},{"t":1,"p":1,"n":"BOOK - Book","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Drop"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Skill"},{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]}]},{"t":1,"p":1,"n":"BPTD - Body Part Data","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":8,"s":1,"p":1,"n":"Body Parts","d":1,"c":[{"t":6,"p":1,"n":"Body Part","c":[{"t":2,"p":1,"n":"BPTN - Part Name"},{"t":2,"p":1,"n":"BPNN - Part Node"},{"t":2,"p":1,"n":"BPNT - VATS Target"},{"t":2,"p":1,"n":"BPNI - IK Data - Start Node"},{"t":6,"p":1,"n":"BPND - ","c":[{"t":5,"p":1,"n":"Damage Mult"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Part Type"},{"t":3,"p":1,"n":"Health Percent"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"To Hit Chance"},{"t":3,"p":1,"n":"Explodable - Explosion Chance %"},{"t":3,"p":1,"n":"Explodable - Debris Count"},{"t":3,"p":1,"n":"Explodable - Debris"},{"t":3,"p":1,"n":"Explodable - Explosion"},{"t":5,"p":1,"n":"Tracking Max Angle"},{"t":5,"p":1,"n":"Explodable - Debris Scale"},{"t":3,"p":1,"n":"Severable - Debris Count"},{"t":3,"p":1,"n":"Severable - Debris"},{"t":3,"p":1,"n":"Severable - Explosion"},{"t":5,"p":1,"n":"Severable - Debris Scale"},{"t":6,"p":1,"n":"Gore Effects Positioning","c":[{"t":6,"p":1,"n":"Translate","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]},{"t":3,"p":1,"n":"Severable - Impact DataSet"},{"t":3,"p":1,"n":"Explodable - Impact DataSet"},{"t":3,"p":1,"n":"Severable - Decal Count"},{"t":3,"p":1,"n":"Explodable - Decal Count"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Limb Replacement Scale"}]},{"t":2,"p":1,"n":"NAM1 - Limb Replacement Model"},{"t":2,"p":1,"n":"NAM4 - Gore Effects - Target Bone"},{"t":11,"p":1,"n":"NAM5 - Texture Files Hashes"}]}]},{"t":3,"p":1,"n":"RAGA - Ragdoll"}]},{"t":1,"p":1,"n":"CAMS - Camera Shot","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Action"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Flags"},{"t":6,"p":1,"n":"Time Multipliers","c":[{"t":5,"p":1,"n":"Player"},{"t":5,"p":1,"n":"Target"},{"t":5,"p":1,"n":"Global"}]},{"t":5,"p":1,"n":"Max Time"},{"t":5,"p":1,"n":"Min Time"},{"t":5,"p":1,"n":"Target % Between Actors"}]},{"t":3,"p":1,"n":"MNAM - Image Space Modifier"}]},{"t":1,"p":1,"n":"CELL - Cell","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"DATA - Flags"},{"t":6,"s":1,"p":1,"n":"XCLC - Grid","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"},{"t":3,"p":1,"n":"Force Hide Land"}]},{"t":6,"s":1,"p":1,"n":"XCLL - Lighting","c":[{"t":6,"p":1,"n":"Ambient Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Directional Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Fog Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Fog Near"},{"t":5,"p":1,"n":"Fog Far"},{"t":3,"p":1,"n":"Directional Rotation XY"},{"t":3,"p":1,"n":"Directional Rotation Z"},{"t":5,"p":1,"n":"Directional Fade"},{"t":5,"p":1,"n":"Fog Clip Dist"},{"t":5,"p":1,"n":"Fog Power"}]},{"t":7,"n":"IMPF - Footstep Materials","c":[{"t":2,"n":"Unknown"}]},{"t":6,"s":1,"p":1,"n":"Light Template","c":[{"t":3,"p":1,"n":"LTMP - Template"},{"t":3,"p":1,"n":"LNAM - Inherit"}]},{"t":5,"p":1,"n":"XCLW - Water Height"},{"t":2,"p":1,"n":"XNAM - Water Noise Texture"},{"t":7,"p":1,"n":"XCLR - Regions","c":[{"t":3,"p":1,"n":"Region"}]},{"t":3,"p":1,"n":"XCIM - Image Space"},{"t":11,"n":"XCET - Unknown"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":3,"p":1,"n":"XCCM - Climate"},{"t":3,"p":1,"n":"XCWT - Water"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":3,"p":1,"n":"XCAS - Acoustic Space"},{"t":11,"n":"XCMT - Unused"},{"t":3,"p":1,"n":"XCMO - Music Type"}]},{"t":1,"p":1,"n":"CLAS - Class","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":7,"p":1,"n":"Tag Skills","c":[{"t":3,"p":1,"n":"Tag Skill"}]},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Buys\/Sells and Services"},{"t":3,"p":1,"n":"Teaches"},{"t":3,"p":1,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":7,"p":1,"n":"ATTR - Attributes","c":[{"t":3,"p":1,"n":"Attribute"}]}]},{"t":1,"p":1,"n":"CLMT - Climate","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":7,"p":1,"n":"WLST - Weather Types","c":[{"t":6,"p":1,"n":"Weather Type","c":[{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Chance"},{"t":3,"p":1,"n":"Global"}]}]},{"t":2,"p":1,"n":"FNAM - Sun Texture"},{"t":2,"p":1,"n":"GNAM - Sun Glare Texture"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"TNAM - Timing","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Begin"},{"t":3,"p":1,"n":"End"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Begin"},{"t":3,"p":1,"n":"End"}]},{"t":3,"p":1,"n":"Volatility"},{"t":3,"p":1,"n":"Moons \/ Phase Length"}]}]},{"t":1,"p":1,"n":"COBJ - Constructible Object","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Drop"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]}]},{"t":1,"p":1,"n":"CONT - Container","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":10,"p":1,"n":"Items","d":1,"c":[{"t":6,"p":1,"n":"Item","c":[{"t":6,"p":1,"n":"CNTO - Item","c":[{"t":3,"p":1,"n":"Item"},{"t":3,"p":1,"n":"Count"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Weight"}]},{"t":3,"p":1,"n":"SNAM - Sound - Open"},{"t":3,"p":1,"n":"QNAM - Sound - Close"}]},{"t":1,"p":1,"n":"CPTH - Camera Path","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"CTDA - Condition","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Note"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Creature Type"},{"t":3,"p":1,"n":"Menu Mode"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Body Location"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"VATS Value Function (INVALID)"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"}]}]},{"t":7,"p":1,"n":"ANAM - Related Camera Paths","c":[{"t":3,"p":1,"n":"Related Camera Path"}]},{"t":3,"p":1,"n":"DATA - Camera Zoom"},{"t":8,"s":1,"p":1,"n":"Camera Shots","d":1,"c":[{"t":3,"p":1,"n":"SNAM - Camera Shot"}]}]},{"t":1,"p":1,"n":"CREA - Creature","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":8,"s":1,"p":1,"n":"Actor Effects","d":1,"c":[{"t":3,"p":1,"n":"SPLO - Actor Effect"}]},{"t":3,"p":1,"n":"EITM - Unarmed Attack Effect"},{"t":3,"p":1,"n":"EAMT - Unarmed Attack Animation"},{"t":7,"p":1,"n":"NIFZ - Model List","c":[{"t":2,"p":1,"n":"Model"}]},{"t":11,"n":"NIFT - Texture Files Hashes"},{"t":6,"s":1,"p":1,"n":"ACBS - Configuration","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Fatigue"},{"t":3,"p":1,"n":"Barter gold"},{"t":3,"p":1,"n":"Level"},{"t":3,"p":1,"n":"Level Mult"},{"t":3,"p":1,"n":"Calc min"},{"t":3,"p":1,"n":"Calc max"},{"t":3,"p":1,"n":"Speed Multiplier"},{"t":5,"p":1,"n":"Karma (Alignment)"},{"t":3,"p":1,"n":"Disposition Base"},{"t":3,"p":1,"n":"Template Flags"}]},{"t":8,"s":1,"p":1,"n":"Factions","d":1,"c":[{"t":6,"p":1,"n":"SNAM - Faction","c":[{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"p":1,"n":"INAM - Death item"},{"t":3,"p":1,"n":"VTCK - Voice"},{"t":3,"p":1,"n":"TPLT - Template"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":10,"p":1,"n":"Items","d":1,"c":[{"t":6,"p":1,"n":"Item","c":[{"t":6,"p":1,"n":"CNTO - Item","c":[{"t":3,"p":1,"n":"Item"},{"t":3,"p":1,"n":"Count"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]},{"t":6,"s":1,"p":1,"n":"AIDT - AI Data","c":[{"t":3,"p":1,"n":"Aggression"},{"t":3,"p":1,"n":"Confidence"},{"t":3,"p":1,"n":"Energy Level"},{"t":3,"p":1,"n":"Responsibility"},{"t":3,"p":1,"n":"Mood"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Buys\/Sells and Services"},{"t":3,"p":1,"n":"Teaches"},{"t":3,"p":1,"n":"Maximum training level"},{"t":3,"p":1,"n":"Assistance"},{"t":3,"p":1,"n":"Aggro Radius Behavior"},{"t":3,"p":1,"n":"Aggro Radius"}]},{"t":8,"s":1,"p":1,"n":"Packages","d":1,"c":[{"t":3,"p":1,"n":"PKID - Package"}]},{"t":7,"p":1,"n":"KFFZ - Animations","c":[{"t":2,"p":1,"n":"Animation"}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Combat Skill"},{"t":3,"p":1,"n":"Magic Skill"},{"t":3,"p":1,"n":"Stealth Skill"},{"t":3,"p":1,"n":"Health"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Damage"},{"t":7,"p":1,"n":"Attributes","c":[{"t":3,"p":1,"n":"Attribute"}]}]},{"t":3,"p":1,"n":"RNAM - Attack reach"},{"t":3,"p":1,"n":"ZNAM - Combat Style"},{"t":3,"p":1,"n":"PNAM - Body Part Data"},{"t":5,"p":1,"n":"TNAM - Turning Speed"},{"t":5,"p":1,"n":"BNAM - Base Scale"},{"t":5,"p":1,"n":"WNAM - Foot Weight"},{"t":3,"p":1,"n":"NAM4 - Impact Material Type"},{"t":3,"p":1,"n":"NAM5 - Sound Level"},{"t":3,"p":1,"n":"CSCR - Inherits Sounds from"},{"t":10,"p":1,"n":"Sound Types","d":1,"c":[{"t":6,"p":1,"n":"Sound Type","c":[{"t":3,"p":1,"n":"CSDT - Type"},{"t":10,"p":1,"n":"Sounds","c":[{"t":6,"p":1,"n":"Sound","c":[{"t":3,"p":1,"n":"CSDI - Sound"},{"t":3,"p":1,"n":"CSDC - Sound Chance"}]}]}]}]},{"t":3,"p":1,"n":"CNAM - Impact Dataset"},{"t":3,"p":1,"n":"LNAM - Melee Weapon List"}]},{"t":1,"p":1,"n":"CSTY - Combat Style","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"CSTD - Advanced - Standard","c":[{"t":3,"p":1,"n":"Maneuver Decision - Dodge % Chance"},{"t":3,"p":1,"n":"Maneuver Decision - Left\/Right % Chance"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Maneuver Decision - Dodge L\/R Timer (min)"},{"t":5,"p":1,"n":"Maneuver Decision - Dodge L\/R Timer (max)"},{"t":5,"p":1,"n":"Maneuver Decision - Dodge Forward Timer (min)"},{"t":5,"p":1,"n":"Maneuver Decision - Dodge Forward Timer (max)"},{"t":5,"p":1,"n":"Maneuver Decision - Dodge Back Timer Min"},{"t":5,"p":1,"n":"Maneuver Decision - Dodge Back Timer Max"},{"t":5,"p":1,"n":"Maneuver Decision - Idle Timer min"},{"t":5,"p":1,"n":"Maneuver Decision - Idle Timer max"},{"t":3,"p":1,"n":"Melee Decision - Block % Chance"},{"t":3,"p":1,"n":"Melee Decision - Attack % Chance"},{"t":5,"p":1,"n":"Melee Decision - Recoil\/Stagger Bonus to Attack"},{"t":5,"p":1,"n":"Melee Decision - Unconscious Bonus to Attack"},{"t":5,"p":1,"n":"Melee Decision - Hand-To-Hand Bonus to Attack"},{"t":3,"p":1,"n":"Melee Decision - Power Attacks - Power Attack % Chance"},{"t":5,"p":1,"n":"Melee Decision - Power Attacks - Recoil\/Stagger Bonus to Power"},{"t":5,"p":1,"n":"Melee Decision - Power Attacks - Unconscious Bonus to Power Attack"},{"t":3,"p":1,"n":"Melee Decision - Power Attacks - Normal"},{"t":3,"p":1,"n":"Melee Decision - Power Attacks - Forward"},{"t":3,"p":1,"n":"Melee Decision - Power Attacks - Back"},{"t":3,"p":1,"n":"Melee Decision - Power Attacks - Left"},{"t":3,"p":1,"n":"Melee Decision - Power Attacks - Right"},{"t":5,"p":1,"n":"Melee Decision - Hold Timer (min)"},{"t":5,"p":1,"n":"Melee Decision - Hold Timer (max)"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Maneuver Decision - Acrobatic Dodge % Chance"},{"t":3,"p":1,"n":"Melee Decision - Power Attacks - Rushing Attack % Chance"},{"t":5,"p":1,"n":"Melee Decision - Power Attacks - Rushing Attack Distance Mult"}]},{"t":6,"s":1,"p":1,"n":"CSAD - Advanced - Advanced","c":[{"t":5,"p":1,"n":"Dodge Fatigue Mod Mult"},{"t":5,"p":1,"n":"Dodge Fatigue Mod Base"},{"t":5,"p":1,"n":"Encumb. Speed Mod Base"},{"t":5,"p":1,"n":"Encumb. Speed Mod Mult"},{"t":5,"p":1,"n":"Dodge While Under Attack Mult"},{"t":5,"p":1,"n":"Dodge Not Under Attack Mult"},{"t":5,"p":1,"n":"Dodge Back While Under Attack Mult"},{"t":5,"p":1,"n":"Dodge Back Not Under Attack Mult"},{"t":5,"p":1,"n":"Dodge Forward While Attacking Mult"},{"t":5,"p":1,"n":"Dodge Forward Not Attacking Mult"},{"t":5,"p":1,"n":"Block Skill Modifier Mult"},{"t":5,"p":1,"n":"Block Skill Modifier Base"},{"t":5,"p":1,"n":"Block While Under Attack Mult"},{"t":5,"p":1,"n":"Block Not Under Attack Mult"},{"t":5,"p":1,"n":"Attack Skill Modifier Mult"},{"t":5,"p":1,"n":"Attack Skill Modifier Base"},{"t":5,"p":1,"n":"Attack While Under Attack Mult"},{"t":5,"p":1,"n":"Attack Not Under Attack Mult"},{"t":5,"p":1,"n":"Attack During Block Mult"},{"t":5,"p":1,"n":"Power Att. Fatigue Mod Base"},{"t":5,"p":1,"n":"Power Att. Fatigue Mod Mult"}]},{"t":6,"s":1,"p":1,"n":"CSSD - Simple","c":[{"t":5,"p":1,"n":"Cover Search Radius"},{"t":5,"p":1,"n":"Take Cover Chance"},{"t":5,"p":1,"n":"Wait Timer (min)"},{"t":5,"p":1,"n":"Wait Timer (max)"},{"t":5,"p":1,"n":"Wait to Fire Timer (min)"},{"t":5,"p":1,"n":"Wait to Fire Timer (max)"},{"t":5,"p":1,"n":"Fire Timer (min)"},{"t":5,"p":1,"n":"Fire Timer (max)"},{"t":5,"p":1,"n":"Ranged Weapon Range Mult (min)"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Weapon Restrictions"},{"t":5,"p":1,"n":"Ranged Weapon Range Mult (max)"},{"t":5,"p":1,"n":"Max Targeting FOV"},{"t":5,"p":1,"n":"Combat Radius"},{"t":5,"p":1,"n":"Semi-Auto Firing Delay Mult (min)"},{"t":5,"p":1,"n":"Semi-Auto Firing Delay Mult (max)"}]}]},{"t":1,"p":1,"n":"DEBR - Debris","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":8,"s":1,"p":1,"n":"Models","d":1,"c":[{"t":6,"p":1,"n":"Model","c":[{"t":6,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Percentage"},{"t":2,"p":1,"n":"Model Filename"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]}]}]},{"t":1,"p":1,"n":"DIAL - Dialog Topic","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":8,"s":1,"p":1,"n":"Quests","d":1,"c":[{"t":3,"p":1,"n":"QSTI - Quest"}]},{"t":8,"s":1,"p":1,"n":"Quests?","d":1,"c":[{"t":3,"p":1,"n":"QSTR - Quest?"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":5,"p":1,"n":"PNAM - Priority"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"}]}]},{"t":1,"p":1,"n":"DOOR - Door","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"SNAM - Sound - Open"},{"t":3,"p":1,"n":"ANAM - Sound - Close"},{"t":3,"p":1,"n":"BNAM - Sound - Looping"},{"t":3,"p":1,"n":"FNAM - Flags"}]},{"t":1,"p":1,"n":"ECZN - Encounter Zone","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Rank"},{"t":3,"p":1,"n":"Minimum Level"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]}]},{"t":1,"p":1,"n":"EFSH - Effect Shader","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"ICON - Fill Texture"},{"t":2,"p":1,"n":"ICO2 - Particle Shader Texture"},{"t":2,"p":1,"n":"NAM7 - Holes Texture"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Membrane Shader - Source Blend Mode"},{"t":3,"p":1,"n":"Membrane Shader - Blend Operation"},{"t":3,"p":1,"n":"Membrane Shader - Z Test Function"},{"t":6,"p":1,"n":"Fill\/Texture Effect - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Fade In Time"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Full Alpha Time"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Fade Out Time"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Presistent Alpha Ratio"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Pulse Amplitude"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Pulse Frequency"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Animation Speed (U)"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Animation Speed (V)"},{"t":5,"p":1,"n":"Edge Effect - Fall Off"},{"t":6,"p":1,"n":"Edge Effect - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Edge Effect - Alpha Fade In Time"},{"t":5,"p":1,"n":"Edge Effect - Full Alpha Time"},{"t":5,"p":1,"n":"Edge Effect - Alpha Fade Out Time"},{"t":5,"p":1,"n":"Edge Effect - Persistent Alpha Ratio"},{"t":5,"p":1,"n":"Edge Effect - Alpha Pulse Amplitude"},{"t":5,"p":1,"n":"Edge Effect - Alpha Pusle Frequence"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Full Alpha Ratio"},{"t":5,"p":1,"n":"Edge Effect - Full Alpha Ratio"},{"t":3,"p":1,"n":"Membrane Shader - Dest Blend Mode"},{"t":3,"p":1,"n":"Particle Shader - Source Blend Mode"},{"t":3,"p":1,"n":"Particle Shader - Blend Operation"},{"t":3,"p":1,"n":"Particle Shader - Z Test Function"},{"t":3,"p":1,"n":"Particle Shader - Dest Blend Mode"},{"t":5,"p":1,"n":"Particle Shader - Particle Birth Ramp Up Time"},{"t":5,"p":1,"n":"Particle Shader - Full Particle Birth Time"},{"t":5,"p":1,"n":"Particle Shader - Particle Birth Ramp Down Time"},{"t":5,"p":1,"n":"Particle Shader - Full Particle Birth Ratio"},{"t":5,"p":1,"n":"Particle Shader - Persistant Particle Birth Ratio"},{"t":5,"p":1,"n":"Particle Shader - Particle Lifetime"},{"t":5,"p":1,"n":"Particle Shader - Particle Lifetime +\/-"},{"t":5,"p":1,"n":"Particle Shader - Initial Speed Along Normal"},{"t":5,"p":1,"n":"Particle Shader - Acceleration Along Normal"},{"t":5,"p":1,"n":"Particle Shader - Initial Velocity #1"},{"t":5,"p":1,"n":"Particle Shader - Initial Velocity #2"},{"t":5,"p":1,"n":"Particle Shader - Initial Velocity #3"},{"t":5,"p":1,"n":"Particle Shader - Acceleration #1"},{"t":5,"p":1,"n":"Particle Shader - Acceleration #2"},{"t":5,"p":1,"n":"Particle Shader - Acceleration #3"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 1"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 2"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 1 Time"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 2 Time"},{"t":6,"p":1,"n":"Color Key 1 - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Color Key 2 - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Color Key 3 - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Color Key 1 - Color Alpha"},{"t":5,"p":1,"n":"Color Key 2 - Color Alpha"},{"t":5,"p":1,"n":"Color Key 3 - Color Alpha"},{"t":5,"p":1,"n":"Color Key 1 - Color Key Time"},{"t":5,"p":1,"n":"Color Key 2 - Color Key Time"},{"t":5,"p":1,"n":"Color Key 3 - Color Key Time"},{"t":5,"p":1,"n":"Particle Shader - Initial Speed Along Normal +\/-"},{"t":5,"p":1,"n":"Particle Shader - Initial Rotation (deg)"},{"t":5,"p":1,"n":"Particle Shader - Initial Rotation (deg) +\/-"},{"t":5,"p":1,"n":"Particle Shader - Rotation Speed (deg\/sec)"},{"t":5,"p":1,"n":"Particle Shader - Rotation Speed (deg\/sec) +\/-"},{"t":3,"p":1,"n":"Addon Models"},{"t":5,"p":1,"n":"Holes - Start Time"},{"t":5,"p":1,"n":"Holes - End Time"},{"t":5,"p":1,"n":"Holes - Start Val"},{"t":5,"p":1,"n":"Holes - End Val"},{"t":5,"p":1,"n":"Edge Width (alpha units)"},{"t":6,"p":1,"n":"Edge Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Explosion Wind Speed"},{"t":3,"p":1,"n":"Texture Count U"},{"t":3,"p":1,"n":"Texture Count V"},{"t":5,"p":1,"n":"Addon Models - Fade In Time"},{"t":5,"p":1,"n":"Addon Models - Fade Out Time"},{"t":5,"p":1,"n":"Addon Models - Scale Start"},{"t":5,"p":1,"n":"Addon Models - Scale End"},{"t":5,"p":1,"n":"Addon Models - Scale In Time"},{"t":5,"p":1,"n":"Addon Models - Scale Out Time"}]}]},{"t":1,"p":1,"n":"ENCH - Object Effect","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"ENIT - Effect Data","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]},{"t":8,"s":1,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":3,"p":1,"n":"EFID - Base Effect"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":3,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Actor Value"}]},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"CTDA - Condition","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Note"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Creature Type"},{"t":3,"p":1,"n":"Menu Mode"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Body Location"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"VATS Value Function (INVALID)"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"}]}]}]}]}]},{"t":1,"p":1,"n":"EXPL - Explosion","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":3,"p":1,"n":"EITM - Object Effect"},{"t":3,"p":1,"n":"MNAM - Image Space Modifier"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":5,"p":1,"n":"Force"},{"t":5,"p":1,"n":"Damage"},{"t":5,"p":1,"n":"Radius"},{"t":3,"p":1,"n":"Light"},{"t":3,"p":1,"n":"Sound 1"},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"IS Radius"},{"t":3,"p":1,"n":"Impact DataSet"},{"t":3,"p":1,"n":"Sound 2"},{"t":6,"p":1,"n":"Radiation","c":[{"t":5,"p":1,"n":"Level"},{"t":5,"p":1,"n":"Dissipation Time"},{"t":5,"p":1,"n":"Radius"}]},{"t":3,"p":1,"n":"Sound Level"}]},{"t":3,"p":1,"n":"INAM - Placed Impact Object"}]},{"t":1,"p":1,"n":"EYES - Eyes","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"ICON - Texture"},{"t":3,"p":1,"n":"DATA - Flags"}]},{"t":1,"p":1,"n":"FACT - Faction","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":8,"s":1,"p":1,"n":"Relations","d":1,"c":[{"t":6,"p":1,"n":"XNAM - Relation","c":[{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Modifier"},{"t":3,"p":1,"n":"Group Combat Reaction"}]}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Flags 1"},{"t":3,"p":1,"n":"Flags 2"},{"t":11,"n":"Unused"}]},{"t":5,"n":"CNAM - Unused"},{"t":10,"p":1,"n":"Ranks","d":1,"c":[{"t":6,"p":1,"n":"Rank","c":[{"t":3,"p":1,"n":"RNAM - Rank#"},{"t":2,"p":1,"n":"MNAM - Male"},{"t":2,"p":1,"n":"FNAM - Female"},{"t":2,"n":"INAM - Insignia (Unused)"}]}]}]},{"t":1,"p":1,"n":"FLST - FormID List","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":8,"s":1,"p":1,"n":"FormIDs","d":1,"c":[{"t":3,"p":1,"n":"LNAM - FormID"}]}]},{"t":1,"p":1,"n":"FURN - Furniture","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":11,"n":"MNAM - Marker Flags"}]},{"t":1,"p":1,"n":"GLOB - Global","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"FNAM - Type"},{"t":5,"p":1,"n":"FLTV - Value"}]},{"t":1,"p":1,"n":"GMST - Game Setting","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":""}]},{"t":1,"p":1,"n":"GRAS - Grass","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Density"},{"t":3,"p":1,"n":"Min Slope"},{"t":3,"p":1,"n":"Max Slope"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Unit from water amount"},{"t":3,"p":1,"n":"Unit from water type"},{"t":5,"p":1,"n":"Position Range"},{"t":5,"p":1,"n":"Height Range"},{"t":5,"p":1,"n":"Color Range"},{"t":5,"p":1,"n":"Wave Period"},{"t":3,"p":1,"n":"Flags"}]}]},{"t":1,"p":1,"n":"HAIR - Hair","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":2,"p":1,"n":"ICON - Texture"},{"t":3,"p":1,"n":"DATA - Flags"}]},{"t":1,"p":1,"n":"HDPT - Head Part","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":3,"p":1,"n":"DATA - Flags"},{"t":8,"s":1,"p":1,"n":"Extra Parts","d":1,"c":[{"t":3,"p":1,"n":"HNAM - Part"}]}]},{"t":1,"p":1,"n":"IDLM - Idle Marker","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"IDLF - Flags"},{"t":6,"s":1,"p":1,"n":"IDLC - ","c":[{"t":3,"p":1,"n":"Animation Count"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"IDLT - Idle Timer Setting"},{"t":7,"p":1,"n":"IDLA - Animations","c":[{"t":3,"p":1,"n":"Animation"}]}]},{"t":1,"p":1,"n":"IMAD - Image Space Adapter","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DNAM - Data Count","c":[{"t":3,"n":"Flags"},{"t":5,"n":"Duration"},{"t":6,"n":"HDR","c":[{"t":3,"n":"Eye Adapt Speed Mult"},{"t":3,"n":"Eye Adapt Speed Add"},{"t":3,"n":"Bloom Blur Radius Mult"},{"t":3,"n":"Bloom Blur Radius Add"},{"t":3,"n":"Bloom Threshold Mult"},{"t":3,"n":"Bloom Threshold Add"},{"t":3,"n":"Bloom Scale Mult"},{"t":3,"n":"Bloom Scale Add"},{"t":3,"n":"Target Lum Min Mult"},{"t":3,"n":"Target Lum Min Add"},{"t":3,"n":"Target Lum Max Mult"},{"t":3,"n":"Target Lum Max Add"},{"t":3,"n":"Sunlight Scale Mult"},{"t":3,"n":"Sunlight Scale Add"},{"t":3,"n":"Sky Scale Mult"},{"t":3,"n":"Sky Scale Add"}]},{"t":3,"n":"Unknown08 Mult"},{"t":3,"n":"Unknown48 Add"},{"t":3,"n":"Unknown09 Mult"},{"t":3,"n":"Unknown49 Add"},{"t":3,"n":"Unknown0A Mult"},{"t":3,"n":"Unknown4A Add"},{"t":3,"n":"Unknown0B Mult"},{"t":3,"n":"Unknown4B Add"},{"t":3,"n":"Unknown0C Mult"},{"t":3,"n":"Unknown4C Add"},{"t":3,"n":"Unknown0D Mult"},{"t":3,"n":"Unknown4D Add"},{"t":3,"n":"Unknown0E Mult"},{"t":3,"n":"Unknown4E Add"},{"t":3,"n":"Unknown0F Mult"},{"t":3,"n":"Unknown4F Add"},{"t":3,"n":"Unknown10 Mult"},{"t":3,"n":"Unknown50 Add"},{"t":6,"n":"Cinematic","c":[{"t":3,"n":"Saturation Mult"},{"t":3,"n":"Saturation Add"},{"t":3,"n":"Brightness Mult"},{"t":3,"n":"Brightness Add"},{"t":3,"n":"Contrast Mult"},{"t":3,"n":"Contrast Add"}]},{"t":3,"n":"Unknown14 Mult"},{"t":3,"n":"Unknown54 Add"},{"t":3,"n":"Tint Color"},{"t":3,"n":"Blur Radius"},{"t":3,"n":"Double Vision Strength"},{"t":3,"n":"Radial Blur Strength"},{"t":3,"n":"Radial Blur Ramp Up"},{"t":3,"n":"Radial Blur Start"},{"t":3,"n":"Radial Blur Flags"},{"t":5,"n":"Radial Blur Center X"},{"t":5,"n":"Radial Blur Center Y"},{"t":3,"n":"DoF Strength"},{"t":3,"n":"DoF Distance"},{"t":3,"n":"DoF Range"},{"t":3,"n":"DoF Flags"},{"t":3,"n":"Radial Blur Ramp Down"},{"t":3,"n":"Radial Blur Down Start"},{"t":3,"n":"Fade Color"},{"t":3,"n":"Motion Blur Strength"}]},{"t":7,"p":1,"n":"BNAM - Blur Radius","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"VNAM - Double Vision Strength","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"TNAM - Tint Color","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"},{"t":5,"p":1,"n":"Alpha"}]}]},{"t":7,"p":1,"n":"NAM3 - Fade Color","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"},{"t":5,"p":1,"n":"Alpha"}]}]},{"t":7,"p":1,"n":"RNAM - Radial Blur Strength","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"SNAM - Radial Blur Ramp Up","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"UNAM - Radial Blur Start","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"NAM1 - Radial Blur Ramp Down","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"NAM2 - Radial Blur Down Start","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"WNAM - DoF Strength","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"XNAM - DoF Distance","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"YNAM - DoF Range","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"NAM4 - Motion Blur Strength","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":6,"s":1,"p":1,"n":"HDR","c":[{"t":7,"p":1,"n":"aIAD - Eye Adapt Speed Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"@IAD - Eye Adapt Speed Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"bIAD - Bloom Blur Radius Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"AIAD - Bloom Blur Radius Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"cIAD - Bloom Threshold Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"BIAD - Bloom Threshold Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"dIAD - Bloom Scale Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"CIAD - Bloom Scale Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"eIAD - Target Lum Min Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"DIAD - Target Lum Min Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"fIAD - Target Lum Max Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"EIAD - Target Lum Max Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"gIAD - Sunlight Scale Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"FIAD - Sunlight Scale Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"hIAD - Sky Scale Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"GIAD - Sky Scale Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]}]},{"t":11,"n":"iIAD - Unknown"},{"t":11,"n":"HIAD - Unknown"},{"t":11,"n":"jIAD - Unknown"},{"t":11,"n":"IIAD - Unknown"},{"t":11,"n":"kIAD - Unknown"},{"t":11,"n":"JIAD - Unknown"},{"t":11,"n":"lIAD - Unknown"},{"t":11,"n":"KIAD - Unknown"},{"t":11,"n":"mIAD - Unknown"},{"t":11,"n":"LIAD - Unknown"},{"t":11,"n":"nIAD - Unknown"},{"t":11,"n":"MIAD - Unknown"},{"t":11,"n":"oIAD - Unknown"},{"t":11,"n":"NIAD - Unknown"},{"t":11,"n":"pIAD - Unknown"},{"t":11,"n":"OIAD - Unknown"},{"t":11,"n":"qIAD - Unknown"},{"t":11,"n":"PIAD - Unknown"},{"t":6,"s":1,"p":1,"n":"Cinematic","c":[{"t":7,"p":1,"n":"rIAD - Saturation Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"QIAD - Saturation Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"sIAD - Brightness Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"RIAD - Brightness Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"tIAD - Contrast Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"SIAD - Contrast Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]}]},{"t":11,"n":"uIAD - Unknown"},{"t":11,"n":"TIAD - Unknown"}]},{"t":1,"p":1,"n":"IMGS - Image Space","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DNAM - ","c":[{"t":6,"p":1,"n":"HDR","c":[{"t":5,"p":1,"n":"Eye Adapt Speed"},{"t":5,"p":1,"n":"Blur Radius"},{"t":5,"p":1,"n":"Blur Passes"},{"t":5,"p":1,"n":"Emissive Mult"},{"t":5,"p":1,"n":"Target LUM"},{"t":5,"p":1,"n":"Upper LUM Clamp"},{"t":5,"p":1,"n":"Bright Scale"},{"t":5,"p":1,"n":"Bright Clamp"},{"t":5,"p":1,"n":"LUM Ramp No Tex"},{"t":5,"p":1,"n":"LUM Ramp Min"},{"t":5,"p":1,"n":"LUM Ramp Max"},{"t":5,"p":1,"n":"Sunlight Dimmer"},{"t":5,"p":1,"n":"Grass Dimmer"},{"t":5,"p":1,"n":"Tree Dimmer"},{"t":5,"p":1,"n":"Skin Dimmer"}]},{"t":6,"p":1,"n":"Bloom","c":[{"t":5,"p":1,"n":"Blur Radius"},{"t":5,"p":1,"n":"Alpha Mult Interior"},{"t":5,"p":1,"n":"Alpha Mult Exterior"}]},{"t":6,"p":1,"n":"Get Hit","c":[{"t":5,"p":1,"n":"Blur Radius"},{"t":5,"p":1,"n":"Blur Damping Constant"},{"t":5,"p":1,"n":"Damping Constant"}]},{"t":6,"p":1,"n":"Night Eye","c":[{"t":6,"p":1,"n":"Tint Color","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}]},{"t":5,"p":1,"n":"Brightness"}]},{"t":6,"p":1,"n":"Cinematic","c":[{"t":5,"p":1,"n":"Saturation"},{"t":6,"p":1,"n":"Contrast","c":[{"t":5,"p":1,"n":"Avg Lum Value"},{"t":5,"p":1,"n":"Value"}]},{"t":5,"p":1,"n":"Cinematic - Brightness - Value"},{"t":6,"p":1,"n":"Tint","c":[{"t":6,"p":1,"n":"Color","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}]},{"t":5,"p":1,"n":"Value"}]}]},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]}]},{"t":1,"p":1,"n":"INFO - Dialog response","d":1,"c":[{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Next Speaker"},{"t":3,"p":1,"n":"Flags 1"},{"t":3,"p":1,"n":"Flags 2"}]},{"t":3,"p":1,"n":"QSTI - Quest"},{"t":3,"p":1,"n":"TPIC - Topic"},{"t":3,"p":1,"n":"PNAM - Previous INFO"},{"t":8,"s":1,"p":1,"n":"Add Topics","d":1,"c":[{"t":3,"p":1,"n":"NAME - Topic"}]},{"t":8,"s":1,"p":1,"n":"Responses","d":1,"c":[{"t":6,"p":1,"n":"Response","c":[{"t":6,"p":1,"n":"TRDT - Response Data","c":[{"t":3,"p":1,"n":"Emotion Type"},{"t":3,"p":1,"n":"Emotion Value"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Response number"},{"t":3,"p":1,"n":"Sound"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"NAM1 - Response Text"},{"t":2,"p":1,"n":"NAM2 - Script Notes"},{"t":2,"p":1,"n":"NAM3 - Edits"},{"t":3,"p":1,"n":"SNAM - Speaker Animation"},{"t":3,"p":1,"n":"LNAM - Listener Animation"}]}]},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"CTDA - Condition","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Note"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Creature Type"},{"t":3,"p":1,"n":"Menu Mode"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Body Location"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"VATS Value Function (INVALID)"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"}]}]},{"t":8,"s":1,"p":1,"n":"Choices","d":1,"c":[{"t":3,"p":1,"n":"TCLT - Choice"}]},{"t":8,"s":1,"p":1,"n":"Link From","d":1,"c":[{"t":3,"p":1,"n":"TCLF - Topic"}]},{"t":6,"s":1,"p":1,"n":"Script (Begin)","c":[{"t":6,"p":1,"n":"Embedded Script","c":[{"t":6,"p":1,"n":"SCHR - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"p":1,"n":"SCDA - Compiled Embedded Script"},{"t":2,"p":1,"n":"SCTX - Embedded Script Source"},{"t":10,"p":1,"n":"Local Variables","c":[{"t":6,"p":1,"n":"Local Variable","c":[{"t":6,"p":1,"n":"SLSD - Local Variable Data","c":[{"t":3,"p":1,"n":"Index"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"SCVR - Name"}]}]},{"t":8,"p":1,"n":"References","c":[{"t":3,"p":1,"n":"SCRO - Global Reference"},{"t":3,"p":1,"n":"SCRV - Local Variable"}]}]}]},{"t":6,"s":1,"p":1,"n":"Script (End)","c":[{"p":1,"n":"NEXT - Marker"},{"t":6,"p":1,"n":"Embedded Script","c":[{"t":6,"p":1,"n":"SCHR - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"p":1,"n":"SCDA - Compiled Embedded Script"},{"t":2,"p":1,"n":"SCTX - Embedded Script Source"},{"t":10,"p":1,"n":"Local Variables","c":[{"t":6,"p":1,"n":"Local Variable","c":[{"t":6,"p":1,"n":"SLSD - Local Variable Data","c":[{"t":3,"p":1,"n":"Index"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"SCVR - Name"}]}]},{"t":8,"p":1,"n":"References","c":[{"t":3,"p":1,"n":"SCRO - Global Reference"},{"t":3,"p":1,"n":"SCRV - Local Variable"}]}]}]},{"t":3,"n":"SNDD - Unused"},{"t":2,"p":1,"n":"RNAM - Prompt"},{"t":3,"p":1,"n":"ANAM - Speaker"},{"t":3,"p":1,"n":"KNAM - ActorValue\/Perk"},{"t":3,"p":1,"n":"DNAM - Speech Challenge"}]},{"t":1,"p":1,"n":"INGR - Ingredient","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":3,"p":1,"n":"ETYP - Equiptment Type"},{"t":5,"p":1,"n":"DATA - Weight"},{"t":6,"s":1,"p":1,"n":"ENIT - Effect Data","c":[{"t":3,"p":1,"n":"Value"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"s":1,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":3,"p":1,"n":"EFID - Base Effect"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":3,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Actor Value"}]},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"CTDA - Condition","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Note"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Creature Type"},{"t":3,"p":1,"n":"Menu Mode"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Body Location"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"VATS Value Function (INVALID)"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"}]}]}]}]}]},{"t":1,"p":1,"n":"IPCT - Impact","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":5,"p":1,"n":"Effect - Duration"},{"t":3,"p":1,"n":"Effect - Orientation"},{"t":5,"p":1,"n":"Angle Threshold"},{"t":5,"p":1,"n":"Placement Radius"},{"t":3,"p":1,"n":"Sound Level"},{"t":3,"p":1,"n":"Flags"}]},{"t":6,"s":1,"p":1,"n":"DODT - Decal Data","c":[{"t":5,"p":1,"n":"Min Width"},{"t":5,"p":1,"n":"Max Width"},{"t":5,"p":1,"n":"Min Height"},{"t":5,"p":1,"n":"Max Height"},{"t":5,"p":1,"n":"Depth"},{"t":5,"p":1,"n":"Shininess"},{"t":6,"p":1,"n":"Parallax","c":[{"t":5,"p":1,"n":"Scale"},{"t":3,"p":1,"n":"Passes"}]},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":3,"p":1,"n":"DNAM - Texture Set"},{"t":3,"p":1,"n":"SNAM - Sound 1"},{"t":3,"p":1,"n":"NAM1 - Sound 2"}]},{"t":1,"p":1,"n":"IPDS - Impact DataSet","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - Impacts","c":[{"t":3,"p":1,"n":"Stone"},{"t":3,"p":1,"n":"Dirt"},{"t":3,"p":1,"n":"Grass"},{"t":3,"p":1,"n":"Glass"},{"t":3,"p":1,"n":"Metal"},{"t":3,"p":1,"n":"Wood"},{"t":3,"p":1,"n":"Organic"},{"t":3,"p":1,"n":"Cloth"},{"t":3,"p":1,"n":"Water"},{"t":3,"p":1,"n":"Hollow Metal"},{"t":3,"p":1,"n":"Organic Bug"},{"t":3,"p":1,"n":"Organic Glow"}]}]},{"t":1,"p":1,"n":"KEYM - Key","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Drop"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]}]},{"t":1,"p":1,"n":"LAND - Landscape","d":1,"c":[{"t":11,"n":"DATA - Unknown"},{"t":11,"n":"VNML - Vertex Normals"},{"t":11,"n":"VHGT - Vertext Height Map"},{"t":11,"n":"VCLR - Vertex Colours"},{"t":8,"s":1,"p":1,"n":"Layers","d":1,"c":[{"t":6,"p":1,"n":"Base Layer","c":[{"t":6,"p":1,"n":"BTXT - Base Layer Header","c":[{"t":3,"p":1,"n":"Texture"},{"t":3,"p":1,"n":"Quadrant"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Layer"}]}]},{"t":6,"p":1,"n":"Alpha Layer","c":[{"t":6,"p":1,"n":"ATXT - Alpha Layer Header","c":[{"t":3,"p":1,"n":"Texture"},{"t":3,"p":1,"n":"Quadrant"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Layer"}]},{"t":11,"p":1,"n":"VTXT - Alpha Layer Data"}]}]},{"t":7,"p":1,"n":"VTEX - Textures","c":[{"t":3,"p":1,"n":"Texture"}]}]},{"t":1,"p":1,"n":"LGTM - Lighting Template","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - Lighting","c":[{"t":6,"p":1,"n":"Ambient Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Directional Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Fog Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Fog Near"},{"t":5,"p":1,"n":"Fog Far"},{"t":3,"p":1,"n":"Directional Rotation XY"},{"t":3,"p":1,"n":"Directional Rotation Z"},{"t":5,"p":1,"n":"Directional Fade"},{"t":5,"p":1,"n":"Fog Clip Dist"},{"t":5,"p":1,"n":"Fog Power"}]}]},{"t":1,"p":1,"n":"LIGH - Light","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Time"},{"t":3,"p":1,"n":"Radius"},{"t":6,"p":1,"n":"Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":3,"n":"Unused"}]},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Falloff Exponent"},{"t":5,"p":1,"n":"FOV"},{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":5,"p":1,"n":"FNAM - Fade value"},{"t":3,"p":1,"n":"SNAM - Sound"}]},{"t":1,"p":1,"n":"LSCR - Load Screen","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":2,"p":1,"n":"DESC - Description"},{"t":8,"s":1,"p":1,"n":"Locations","d":1,"c":[{"t":6,"p":1,"n":"LNAM - Location","c":[{"t":3,"p":1,"n":"Cell"},{"t":11,"n":"Unused"}]}]}]},{"t":1,"p":1,"n":"LTEX - Landscape Texture","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":3,"p":1,"n":"TNAM - Texture"},{"t":6,"s":1,"p":1,"n":"HNAM - Havok Data","c":[{"t":3,"p":1,"n":"Material Type"},{"t":3,"p":1,"n":"Friction"},{"t":3,"p":1,"n":"Restitution"}]},{"t":3,"p":1,"n":"SNAM - Texture Specular Exponent"},{"t":8,"s":1,"p":1,"n":"Grasses","d":1,"c":[{"t":3,"p":1,"n":"GNAM - Grass"}]}]},{"t":1,"p":1,"n":"LVLC - Leveled Creature","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"LVLD - Chance none"},{"t":3,"p":1,"n":"LVLF - Flags"},{"t":10,"p":1,"n":"Leveled List Entries","d":1,"c":[{"t":6,"p":1,"n":"Leveled List Entry","c":[{"t":6,"p":1,"n":"LVLO - Base Data","c":[{"t":3,"p":1,"n":"Level"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Count"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]}]},{"t":1,"p":1,"n":"LVLI - Leveled Item","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"LVLD - Chance none"},{"t":3,"p":1,"n":"LVLF - Flags"},{"t":3,"p":1,"n":"LVLG - Global"},{"t":10,"p":1,"n":"Leveled List Entries","d":1,"c":[{"t":6,"p":1,"n":"Leveled List Entry","c":[{"t":6,"p":1,"n":"LVLO - Base Data","c":[{"t":3,"p":1,"n":"Level"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Count"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]}]},{"t":1,"p":1,"n":"LVLN - Leveled NPC","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"LVLD - Chance none"},{"t":3,"p":1,"n":"LVLF - Flags"},{"t":10,"p":1,"n":"Leveled List Entries","d":1,"c":[{"t":6,"p":1,"n":"Leveled List Entry","c":[{"t":6,"p":1,"n":"LVLO - Base Data","c":[{"t":3,"p":1,"n":"Level"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Count"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]}]},{"t":1,"p":1,"n":"MESG - Message","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"DESC - Description"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"INAM - Icon"},{"t":11,"n":"NAM0 - Unused"},{"t":11,"n":"NAM1 - Unused"},{"t":11,"n":"NAM2 - Unused"},{"t":11,"n":"NAM3 - Unused"},{"t":11,"n":"NAM4 - Unused"},{"t":11,"n":"NAM5 - Unused"},{"t":11,"n":"NAM6 - Unused"},{"t":11,"n":"NAM7 - Unused"},{"t":11,"n":"NAM8 - Unused"},{"t":11,"n":"NAM9 - Unused"},{"t":3,"p":1,"n":"DNAM - Flags"},{"t":3,"p":1,"n":"TNAM - Display Time"},{"t":8,"s":1,"p":1,"n":"Menu Buttons","d":1,"c":[{"t":6,"p":1,"n":"Menu Button","c":[{"t":2,"p":1,"n":"ITXT - Button Text"},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"CTDA - Condition","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Note"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Creature Type"},{"t":3,"p":1,"n":"Menu Mode"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Body Location"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"VATS Value Function (INVALID)"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"}]}]}]}]}]},{"t":1,"p":1,"n":"MGEF - Base Effect","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Flags"},{"t":5,"n":"Base cost (Unused)"},{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Assoc. Item"},{"t":3,"p":1,"n":"Assoc. Script"},{"t":3,"p":1,"n":"Assoc. Creature"},{"t":3,"n":"Magic School (Unused)"},{"t":3,"p":1,"n":"Resistance Type"},{"t":3,"p":1,"n":"Counter effect count"},{"t":3,"p":1,"n":"Light"},{"t":5,"p":1,"n":"Projectile speed"},{"t":3,"p":1,"n":"Effect Shader"},{"t":3,"p":1,"n":"Object Display Shader"},{"t":3,"p":1,"n":"Effect sound"},{"t":3,"p":1,"n":"Bolt sound"},{"t":3,"p":1,"n":"Hit sound"},{"t":3,"p":1,"n":"Area sound"},{"t":5,"n":"Constant Effect enchantment factor (Unused)"},{"t":5,"n":"Constant Effect barter factor (Unused)"},{"t":3,"p":1,"n":"Archtype"},{"t":3,"p":1,"n":"Actor Value"}]},{"t":8,"s":1,"p":1,"n":"Counter Effects","d":1,"c":[{"t":3,"p":1,"n":"ESCE - Effect"}]}]},{"t":1,"p":1,"n":"MICN - Menu Icon","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]}]},{"t":1,"p":1,"n":"MISC - Misc. Item","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Drop"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]}]},{"t":1,"p":1,"n":"MSTT - Moveable Static","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":11,"n":"DATA - Unknown"},{"t":3,"p":1,"n":"SNAM - Sound"}]},{"t":1,"p":1,"n":"MUSC - Music Type","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FNAM - Filename"}]},{"t":1,"p":1,"n":"NOTE - Note","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Drop"},{"t":3,"p":1,"n":"DATA - Type"},{"t":8,"s":1,"p":1,"n":"Quests","d":1,"c":[{"t":3,"p":1,"n":"ONAM - Quest"}]},{"t":2,"p":1,"n":"XNAM - Texture"},{"t":2,"p":1,"n":"Text"},{"t":3,"p":1,"n":"Topic"},{"t":3,"p":1,"n":"Sound"},{"t":3,"p":1,"n":"NPC"}]},{"t":1,"p":1,"n":"NPC_ - Non-Player Character","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"ACBS - Configuration","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Fatigue"},{"t":3,"p":1,"n":"Barter gold"},{"t":3,"p":1,"n":"Level"},{"t":3,"p":1,"n":"Level Mult"},{"t":3,"p":1,"n":"Calc min"},{"t":3,"p":1,"n":"Calc max"},{"t":3,"p":1,"n":"Speed Multiplier"},{"t":5,"p":1,"n":"Karma (Alignment)"},{"t":3,"p":1,"n":"Disposition Base"},{"t":3,"p":1,"n":"Template Flags"}]},{"t":8,"s":1,"p":1,"n":"Factions","d":1,"c":[{"t":6,"p":1,"n":"SNAM - Faction","c":[{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"p":1,"n":"INAM - Death item"},{"t":3,"p":1,"n":"VTCK - Voice"},{"t":3,"p":1,"n":"TPLT - Template"},{"t":3,"p":1,"n":"RNAM - Race"},{"t":8,"s":1,"p":1,"n":"Actor Effects","d":1,"c":[{"t":3,"p":1,"n":"SPLO - Actor Effect"}]},{"t":3,"p":1,"n":"EITM - Unarmed Attack Effect"},{"t":3,"p":1,"n":"EAMT - Unarmed Attack Animation"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":10,"p":1,"n":"Items","d":1,"c":[{"t":6,"p":1,"n":"Item","c":[{"t":6,"p":1,"n":"CNTO - Item","c":[{"t":3,"p":1,"n":"Item"},{"t":3,"p":1,"n":"Count"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]},{"t":6,"s":1,"p":1,"n":"AIDT - AI Data","c":[{"t":3,"p":1,"n":"Aggression"},{"t":3,"p":1,"n":"Confidence"},{"t":3,"p":1,"n":"Energy Level"},{"t":3,"p":1,"n":"Responsibility"},{"t":3,"p":1,"n":"Mood"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Buys\/Sells and Services"},{"t":3,"p":1,"n":"Teaches"},{"t":3,"p":1,"n":"Maximum training level"},{"t":3,"p":1,"n":"Assistance"},{"t":3,"p":1,"n":"Aggro Radius Behavior"},{"t":3,"p":1,"n":"Aggro Radius"}]},{"t":8,"s":1,"p":1,"n":"Packages","d":1,"c":[{"t":3,"p":1,"n":"PKID - Package"}]},{"t":7,"p":1,"n":"KFFZ - Animations","c":[{"t":2,"p":1,"n":"Animation"}]},{"t":3,"p":1,"n":"CNAM - Class"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Base Health"},{"t":7,"p":1,"n":"Attributes","c":[{"t":3,"p":1,"n":"Attribute"}]},{"t":11,"n":"Unused"}]},{"t":6,"s":1,"p":1,"n":"DNAM - ","c":[{"t":7,"p":1,"n":"Skill Values","c":[{"t":3,"p":1,"n":"Skill"}]},{"t":7,"p":1,"n":"Skill Offsets","c":[{"t":3,"p":1,"n":"Skill"}]}]},{"t":8,"s":1,"p":1,"n":"Head Parts","d":1,"c":[{"t":3,"p":1,"n":"PNAM - Head Part"}]},{"t":3,"p":1,"n":"HNAM - Hair"},{"t":5,"p":1,"n":"LNAM - Hair length"},{"t":3,"p":1,"n":"ENAM - Eyes"},{"t":6,"s":1,"p":1,"n":"HCLR - Hair color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"ZNAM - Combat Style"},{"t":3,"p":1,"n":"NAM4 - Impact Material Type"},{"t":6,"s":1,"p":1,"n":"FaceGen Data","c":[{"t":11,"p":1,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"p":1,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"p":1,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":3,"n":"NAM5 - Unknown"},{"t":5,"p":1,"n":"NAM6 - Height"},{"t":5,"p":1,"n":"NAM7 - Weight"}]},{"t":1,"p":1,"n":"PACK - Package","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"PKDT - General","c":[{"t":3,"p":1,"n":"General Flags"},{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Fallout Behavior Flags"},{"p":1,"n":"Type Specific Flags (missing)"},{"t":3,"p":1,"n":"Type Specific Flags - Find"},{"t":3,"p":1,"n":"Type Specific Flags - Follow"},{"t":3,"p":1,"n":"Type Specific Flags - Escort"},{"t":3,"p":1,"n":"Type Specific Flags - Eat"},{"t":3,"p":1,"n":"Type Specific Flags - Sleep"},{"t":3,"p":1,"n":"Type Specific Flags - Wander"},{"t":3,"p":1,"n":"Type Specific Flags - Travel"},{"t":3,"p":1,"n":"Type Specific Flags - Accompany"},{"t":3,"p":1,"n":"Type Specific Flags - Use Item At"},{"t":3,"p":1,"n":"Type Specific Flags - Ambush"},{"t":3,"p":1,"n":"Type Specific Flags - Flee Not Combat"},{"t":3,"p":1,"n":"Type Specific Flags - ?"},{"t":3,"p":1,"n":"Type Specific Flags - Sandbox"},{"t":3,"p":1,"n":"Type Specific Flags - Patrol"},{"t":3,"p":1,"n":"Type Specific Flags - Guard"},{"t":3,"p":1,"n":"Type Specific Flags - Dialogue"},{"t":3,"p":1,"n":"Type Specific Flags - Use Weapon"}]},{"t":6,"s":1,"p":1,"n":"Locations","c":[{"t":6,"p":1,"n":"PLDT - Location 1","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Cell"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Object ID"},{"t":3,"p":1,"n":"Object Type"},{"t":3,"p":1,"n":"Radius"}]},{"t":6,"p":1,"n":"PLD2 - Location 2","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Cell"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Object ID"},{"t":3,"p":1,"n":"Object Type"},{"t":3,"p":1,"n":"Radius"}]}]},{"t":6,"s":1,"p":1,"n":"PSDT - Schedule","c":[{"t":3,"p":1,"n":"Month"},{"t":3,"p":1,"n":"Day of week"},{"t":3,"p":1,"n":"Date"},{"t":3,"p":1,"n":"Time"},{"t":3,"p":1,"n":"Duration"}]},{"t":6,"s":1,"p":1,"n":"PTDT - Target 1","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Object ID"},{"t":3,"p":1,"n":"Object Type"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Count \/ Distance"},{"t":5,"n":"Unknown"}]},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"CTDA - Condition","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Note"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Creature Type"},{"t":3,"p":1,"n":"Menu Mode"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Body Location"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"VATS Value Function (INVALID)"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"}]}]},{"t":6,"s":1,"p":1,"n":"Idle Animations","c":[{"t":3,"p":1,"n":"IDLF - Flags"},{"t":6,"p":1,"n":"IDLC - ","c":[{"t":3,"p":1,"n":"Animation Count"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"IDLT - Idle Timer Setting"},{"t":7,"p":1,"n":"IDLA - Animations","c":[{"t":3,"p":1,"n":"Animation"}]},{"t":11,"n":"IDLB - Unused"}]},{"t":3,"p":1,"n":"CNAM - Combat Style"},{"p":1,"n":"PKED - Eat Marker"},{"t":3,"p":1,"n":"PKE2 - Escort Distance"},{"t":5,"p":1,"n":"PKFD - Follow - Start Location - Trigger Radius"},{"t":6,"s":1,"p":1,"n":"PKPT - Patrol Flags","c":[{"t":3,"p":1,"n":"Repeatable"},{"t":11,"n":"Unused"}]},{"t":6,"s":1,"p":1,"n":"PKW3 - Use Weapon Data","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Fire Rate"},{"t":3,"p":1,"n":"Fire Count"},{"t":3,"p":1,"n":"Number of Bursts"},{"t":6,"p":1,"n":"Shoots Per Volleys","c":[{"t":3,"p":1,"n":"Min"},{"t":3,"p":1,"n":"Max"}]},{"t":6,"p":1,"n":"Pause Between Volleys","c":[{"t":5,"p":1,"n":"Min"},{"t":5,"p":1,"n":"Max"}]},{"t":11,"n":"Unused"}]},{"t":6,"s":1,"p":1,"n":"PTD2 - Target 2","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Object ID"},{"t":3,"p":1,"n":"Object Type"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Count \/ Distance"},{"t":5,"n":"Unknown"}]},{"p":1,"n":"PUID - Use Item Marker"},{"p":1,"n":"PKAM - Ambush Marker"},{"t":6,"s":1,"p":1,"n":"PKDD - Dialogue Data","c":[{"t":5,"p":1,"n":"FOV"},{"t":3,"p":1,"n":"Topic"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Dialogue Type"},{"t":11,"n":"Unknown"}]},{"t":6,"s":1,"p":1,"n":"PLD2 - Location 2 (again??)","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Cell"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Object ID"},{"t":3,"p":1,"n":"Object Type"},{"t":3,"p":1,"n":"Radius"}]},{"t":6,"s":1,"p":1,"n":"OnBegin","c":[{"p":1,"n":"POBA - OnBegin Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":6,"p":1,"n":"Embedded Script","c":[{"t":6,"p":1,"n":"SCHR - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"p":1,"n":"SCDA - Compiled Embedded Script"},{"t":2,"p":1,"n":"SCTX - Embedded Script Source"},{"t":10,"p":1,"n":"Local Variables","c":[{"t":6,"p":1,"n":"Local Variable","c":[{"t":6,"p":1,"n":"SLSD - Local Variable Data","c":[{"t":3,"p":1,"n":"Index"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"SCVR - Name"}]}]},{"t":8,"p":1,"n":"References","c":[{"t":3,"p":1,"n":"SCRO - Global Reference"},{"t":3,"p":1,"n":"SCRV - Local Variable"}]}]},{"t":3,"p":1,"n":"TNAM - Topic"}]},{"t":6,"s":1,"p":1,"n":"OnEnd","c":[{"p":1,"n":"POEA - OnEnd Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":6,"p":1,"n":"Embedded Script","c":[{"t":6,"p":1,"n":"SCHR - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"p":1,"n":"SCDA - Compiled Embedded Script"},{"t":2,"p":1,"n":"SCTX - Embedded Script Source"},{"t":10,"p":1,"n":"Local Variables","c":[{"t":6,"p":1,"n":"Local Variable","c":[{"t":6,"p":1,"n":"SLSD - Local Variable Data","c":[{"t":3,"p":1,"n":"Index"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"SCVR - Name"}]}]},{"t":8,"p":1,"n":"References","c":[{"t":3,"p":1,"n":"SCRO - Global Reference"},{"t":3,"p":1,"n":"SCRV - Local Variable"}]}]},{"t":3,"p":1,"n":"TNAM - Topic"}]},{"t":6,"s":1,"p":1,"n":"OnChange","c":[{"p":1,"n":"POCA - OnChange Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":6,"p":1,"n":"Embedded Script","c":[{"t":6,"p":1,"n":"SCHR - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"p":1,"n":"SCDA - Compiled Embedded Script"},{"t":2,"p":1,"n":"SCTX - Embedded Script Source"},{"t":10,"p":1,"n":"Local Variables","c":[{"t":6,"p":1,"n":"Local Variable","c":[{"t":6,"p":1,"n":"SLSD - Local Variable Data","c":[{"t":3,"p":1,"n":"Index"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"SCVR - Name"}]}]},{"t":8,"p":1,"n":"References","c":[{"t":3,"p":1,"n":"SCRO - Global Reference"},{"t":3,"p":1,"n":"SCRV - Local Variable"}]}]},{"t":3,"p":1,"n":"TNAM - Topic"}]}]},{"t":1,"p":1,"n":"PBEA - Placed Beam","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"NAME - Base"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":11,"n":"XRGD - Ragdoll Data"},{"t":11,"n":"XRGB - Ragdoll Biped Data"},{"t":6,"s":1,"p":1,"n":"Patrol Data","c":[{"t":5,"p":1,"n":"XPRD - Idle Time"},{"p":1,"n":"XPPA - Patrol Script Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":6,"p":1,"n":"Embedded Script","c":[{"t":6,"p":1,"n":"SCHR - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"p":1,"n":"SCDA - Compiled Embedded Script"},{"t":2,"p":1,"n":"SCTX - Embedded Script Source"},{"t":10,"p":1,"n":"Local Variables","c":[{"t":6,"p":1,"n":"Local Variable","c":[{"t":6,"p":1,"n":"SLSD - Local Variable Data","c":[{"t":3,"p":1,"n":"Index"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"SCVR - Name"}]}]},{"t":8,"p":1,"n":"References","c":[{"t":3,"p":1,"n":"SCRO - Global Reference"},{"t":3,"p":1,"n":"SCRV - Local Variable"}]}]},{"t":3,"p":1,"n":"TNAM - Topic"}]},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":3,"p":1,"n":"XCNT - Count"},{"t":5,"p":1,"n":"XRDS - Radius"},{"t":5,"p":1,"n":"XHLP - Health"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked Decals","d":1,"c":[{"t":6,"p":1,"n":"XDCR - Decal","c":[{"t":3,"p":1,"n":"Reference"},{"t":11,"n":"Unknown"}]}]},{"t":3,"p":1,"n":"XLKR - Linked Reference"},{"t":6,"s":1,"p":1,"n":"XCLP - Linked Reference Color","c":[{"t":6,"p":1,"n":"Link Start Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Link End Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIBS - Ignored By Sandbox"},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"PERK - Perk","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"CTDA - Condition","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Note"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Creature Type"},{"t":3,"p":1,"n":"Menu Mode"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Body Location"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"VATS Value Function (INVALID)"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"}]}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Trait"},{"t":3,"p":1,"n":"Min Level"},{"t":3,"p":1,"n":"Ranks"},{"t":3,"p":1,"n":"Playable"},{"t":3,"p":1,"n":"Hidden"}]},{"t":10,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":6,"p":1,"n":"PRKE - Header","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Rank"},{"t":3,"p":1,"n":"Priority"}]},{"t":6,"p":1,"n":"Quest + Stage","c":[{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"Ability"},{"t":6,"p":1,"n":"Entry Point","c":[{"t":3,"p":1,"n":"Entry Point"},{"t":3,"p":1,"n":"Function"},{"t":3,"p":1,"n":"Perk Condition Tab Count"}]},{"t":10,"p":1,"n":"Perk Conditions","c":[{"t":6,"p":1,"n":"Perk Condition","c":[{"t":3,"p":1,"n":"PRKC - Run On"},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"CTDA - Condition","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Note"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Creature Type"},{"t":3,"p":1,"n":"Menu Mode"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Body Location"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"VATS Value Function (INVALID)"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"}]}]}]}]},{"t":6,"p":1,"n":"Entry Point Function Parameters","c":[{"t":3,"p":1,"n":"EPFT - Type"},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"Float"},{"t":6,"p":1,"n":"Float, Float","c":[{"t":5,"p":1,"n":"Float 1"},{"t":5,"p":1,"n":"Float 2"}]},{"t":3,"p":1,"n":"Leveled Item"},{"p":1,"n":"None (Script)"},{"t":6,"p":1,"n":"Actor Value, Float","c":[{"t":3,"p":1,"n":"Actor Value"},{"t":5,"p":1,"n":"Float"}]},{"t":2,"p":1,"n":"EPF2 - Button Label"},{"t":3,"p":1,"n":"EPF3 - Script Flags"},{"t":6,"p":1,"n":"Embedded Script","c":[{"t":6,"p":1,"n":"SCHR - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"p":1,"n":"SCDA - Compiled Embedded Script"},{"t":2,"p":1,"n":"SCTX - Embedded Script Source"},{"t":10,"p":1,"n":"Local Variables","c":[{"t":6,"p":1,"n":"Local Variable","c":[{"t":6,"p":1,"n":"SLSD - Local Variable Data","c":[{"t":3,"p":1,"n":"Index"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"SCVR - Name"}]}]},{"t":8,"p":1,"n":"References","c":[{"t":3,"p":1,"n":"SCRO - Global Reference"},{"t":3,"p":1,"n":"SCRV - Local Variable"}]}]}]},{"p":1,"n":"PRKF - End Marker"}]}]}]},{"t":1,"p":1,"n":"PGRE - Placed Grenade","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"NAME - Base"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":11,"n":"XRGD - Ragdoll Data"},{"t":11,"n":"XRGB - Ragdoll Biped Data"},{"t":6,"s":1,"p":1,"n":"Patrol Data","c":[{"t":5,"p":1,"n":"XPRD - Idle Time"},{"p":1,"n":"XPPA - Patrol Script Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":6,"p":1,"n":"Embedded Script","c":[{"t":6,"p":1,"n":"SCHR - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"p":1,"n":"SCDA - Compiled Embedded Script"},{"t":2,"p":1,"n":"SCTX - Embedded Script Source"},{"t":10,"p":1,"n":"Local Variables","c":[{"t":6,"p":1,"n":"Local Variable","c":[{"t":6,"p":1,"n":"SLSD - Local Variable Data","c":[{"t":3,"p":1,"n":"Index"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"SCVR - Name"}]}]},{"t":8,"p":1,"n":"References","c":[{"t":3,"p":1,"n":"SCRO - Global Reference"},{"t":3,"p":1,"n":"SCRV - Local Variable"}]}]},{"t":3,"p":1,"n":"TNAM - Topic"}]},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":3,"p":1,"n":"XCNT - Count"},{"t":5,"p":1,"n":"XRDS - Radius"},{"t":5,"p":1,"n":"XHLP - Health"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked Decals","d":1,"c":[{"t":6,"p":1,"n":"XDCR - Decal","c":[{"t":3,"p":1,"n":"Reference"},{"t":11,"n":"Unknown"}]}]},{"t":3,"p":1,"n":"XLKR - Linked Reference"},{"t":6,"s":1,"p":1,"n":"XCLP - Linked Reference Color","c":[{"t":6,"p":1,"n":"Link Start Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Link End Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIBS - Ignored By Sandbox"},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"PMIS - Placed Missile","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"NAME - Base"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":11,"n":"XRGD - Ragdoll Data"},{"t":11,"n":"XRGB - Ragdoll Biped Data"},{"t":6,"s":1,"p":1,"n":"Patrol Data","c":[{"t":5,"p":1,"n":"XPRD - Idle Time"},{"p":1,"n":"XPPA - Patrol Script Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":6,"p":1,"n":"Embedded Script","c":[{"t":6,"p":1,"n":"SCHR - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"p":1,"n":"SCDA - Compiled Embedded Script"},{"t":2,"p":1,"n":"SCTX - Embedded Script Source"},{"t":10,"p":1,"n":"Local Variables","c":[{"t":6,"p":1,"n":"Local Variable","c":[{"t":6,"p":1,"n":"SLSD - Local Variable Data","c":[{"t":3,"p":1,"n":"Index"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"SCVR - Name"}]}]},{"t":8,"p":1,"n":"References","c":[{"t":3,"p":1,"n":"SCRO - Global Reference"},{"t":3,"p":1,"n":"SCRV - Local Variable"}]}]},{"t":3,"p":1,"n":"TNAM - Topic"}]},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":3,"p":1,"n":"XCNT - Count"},{"t":5,"p":1,"n":"XRDS - Radius"},{"t":5,"p":1,"n":"XHLP - Health"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked Decals","d":1,"c":[{"t":6,"p":1,"n":"XDCR - Decal","c":[{"t":3,"p":1,"n":"Reference"},{"t":11,"n":"Unknown"}]}]},{"t":3,"p":1,"n":"XLKR - Linked Reference"},{"t":6,"s":1,"p":1,"n":"XCLP - Linked Reference Color","c":[{"t":6,"p":1,"n":"Link Start Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Link End Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIBS - Ignored By Sandbox"},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"PROJ - Projectile","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Type"},{"t":5,"p":1,"n":"Gravity"},{"t":5,"p":1,"n":"Speed"},{"t":5,"p":1,"n":"Range"},{"t":3,"p":1,"n":"Light"},{"t":3,"p":1,"n":"Muzzle Flash - Light"},{"t":5,"p":1,"n":"Tracer Chance"},{"t":5,"p":1,"n":"Explosion - Alt. Trigger - Proximity"},{"t":5,"p":1,"n":"Explosion - Alt. Trigger - Timer"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Sound"},{"t":5,"p":1,"n":"Muzzle Flash - Duration"},{"t":5,"p":1,"n":"Fade Duration"},{"t":5,"p":1,"n":"Impact Force"},{"t":3,"p":1,"n":"Sound - Countdown"},{"t":3,"p":1,"n":"Sound - Disable"},{"t":3,"p":1,"n":"Default Weapon Source"}]},{"t":6,"s":1,"p":1,"n":"Muzzle Flash Model","c":[{"t":2,"p":1,"n":"NAM1 - Model Filename"},{"t":11,"p":1,"n":"NAM2 - Texture Files Hashes"}]},{"t":3,"p":1,"n":"VNAM - Sound Level"}]},{"t":1,"p":1,"n":"PWAT - Placeable Water","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"DNAM - ","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Water"}]}]},{"t":1,"p":1,"n":"QUST - Quest","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"SCRI - Script"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"DATA - General","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Priority"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Quest Delay"}]},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"CTDA - Condition","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Note"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Creature Type"},{"t":3,"p":1,"n":"Menu Mode"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Body Location"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"VATS Value Function (INVALID)"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"}]}]},{"t":10,"p":1,"n":"Stages","d":1,"c":[{"t":6,"p":1,"n":"Stage","c":[{"t":3,"p":1,"n":"INDX - Stage Index"},{"t":8,"p":1,"n":"Log Entries","c":[{"t":6,"p":1,"n":"Log Entry","c":[{"t":3,"p":1,"n":"QSDT - Stage Flags"},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"CTDA - Condition","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Note"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Creature Type"},{"t":3,"p":1,"n":"Menu Mode"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Body Location"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"VATS Value Function (INVALID)"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"}]}]},{"t":2,"p":1,"n":"CNAM - Log Entry"},{"t":6,"p":1,"n":"Embedded Script","c":[{"t":6,"p":1,"n":"SCHR - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"p":1,"n":"SCDA - Compiled Embedded Script"},{"t":2,"p":1,"n":"SCTX - Embedded Script Source"},{"t":10,"p":1,"n":"Local Variables","c":[{"t":6,"p":1,"n":"Local Variable","c":[{"t":6,"p":1,"n":"SLSD - Local Variable Data","c":[{"t":3,"p":1,"n":"Index"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"SCVR - Name"}]}]},{"t":8,"p":1,"n":"References","c":[{"t":3,"p":1,"n":"SCRO - Global Reference"},{"t":3,"p":1,"n":"SCRV - Local Variable"}]}]},{"t":3,"p":1,"n":"NAM0 - Next Quest"}]}]}]}]},{"t":8,"s":1,"p":1,"n":"Objectives","d":1,"c":[{"t":6,"p":1,"n":"Objective","c":[{"t":3,"p":1,"n":"QOBJ - Objective Index"},{"t":2,"p":1,"n":"NNAM - Description"},{"t":8,"p":1,"n":"Targets","c":[{"t":6,"p":1,"n":"Target","c":[{"t":6,"p":1,"n":"QSTA - Target","c":[{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"CTDA - Condition","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Note"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Creature Type"},{"t":3,"p":1,"n":"Menu Mode"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Body Location"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"VATS Value Function (INVALID)"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"}]}]}]}]}]}]}]},{"t":1,"p":1,"n":"RACE - Race","c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"DESC - Description"},{"t":8,"s":1,"p":1,"n":"Relations","d":1,"c":[{"t":6,"p":1,"n":"XNAM - Relation","c":[{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Modifier"},{"t":3,"p":1,"n":"Group Combat Reaction"}]}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":7,"p":1,"n":"Skill Boosts","d":1,"c":[{"t":6,"p":1,"n":"Skill Boost","c":[{"t":3,"p":1,"n":"Skill"},{"t":3,"p":1,"n":"Boost"}]}]},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Male Height"},{"t":5,"p":1,"n":"Female Height"},{"t":5,"p":1,"n":"Male Weight"},{"t":5,"p":1,"n":"Female Weight"},{"t":3,"p":1,"n":"Flags"}]},{"t":3,"p":1,"n":"ONAM - Older"},{"t":3,"p":1,"n":"YNAM - Younger"},{"p":1,"n":"NAM2 - Unknown Marker"},{"t":7,"s":1,"p":1,"n":"VTCK - Voices","d":1,"c":[{"t":3,"p":1,"n":"Voice"}]},{"t":7,"s":1,"p":1,"n":"DNAM - Default Hair Styles","d":1,"c":[{"t":3,"p":1,"n":"Default Hair Style"}]},{"t":7,"s":1,"p":1,"n":"CNAM - Default Hair Colors","d":1,"c":[{"t":3,"p":1,"n":"Default Hair Color"}]},{"t":5,"p":1,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"p":1,"n":"UNAM - FaceGen - Face clamp"},{"t":11,"p":1,"n":"ATTR - Unused"},{"t":6,"s":1,"p":1,"n":"Head Data","c":[{"p":1,"n":"NAM0 - Head Data Marker"},{"t":6,"p":1,"n":"Male Head Data","c":[{"p":1,"n":"MNAM - Male Data Marker"},{"t":10,"p":1,"n":"Parts","d":1,"c":[{"t":6,"p":1,"n":"Part","c":[{"t":3,"p":1,"n":"INDX - Index"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]}]}]}]},{"t":6,"p":1,"n":"Female Head Data","c":[{"p":1,"n":"FNAM - Female Data Marker"},{"t":10,"p":1,"n":"Parts","d":1,"c":[{"t":6,"p":1,"n":"Part","c":[{"t":3,"p":1,"n":"INDX - Index"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"Body Data","c":[{"p":1,"n":"NAM1 - Body Data Marker"},{"t":6,"p":1,"n":"Male Body Data","c":[{"p":1,"n":"MNAM - Male Data Marker"},{"t":10,"p":1,"n":"Parts","d":1,"c":[{"t":6,"p":1,"n":"Part","c":[{"t":3,"p":1,"n":"INDX - Index"},{"t":6,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]}]}]}]},{"t":6,"p":1,"n":"Female Body Data","c":[{"p":1,"n":"FNAM - Female Data Marker"},{"t":10,"p":1,"n":"Parts","d":1,"c":[{"t":6,"p":1,"n":"Part","c":[{"t":3,"p":1,"n":"INDX - Index"},{"t":6,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]}]}]}]}]},{"t":7,"s":1,"p":1,"n":"HNAM - Hairs","d":1,"c":[{"t":3,"p":1,"n":"Hair"}]},{"t":7,"s":1,"p":1,"n":"ENAM - Eyes","d":1,"c":[{"t":3,"p":1,"n":"Eye"}]},{"t":6,"s":1,"p":1,"n":"FaceGen Data","c":[{"t":6,"p":1,"n":"Male FaceGen Data","c":[{"p":1,"n":"MNAM - Male Data Marker"},{"t":6,"p":1,"n":"FaceGen Data","c":[{"t":11,"p":1,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"p":1,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"p":1,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"n":"SNAM - Unknown"}]},{"t":6,"p":1,"n":"Female FaceGen Data","c":[{"p":1,"n":"FNAM - Female Data Marker"},{"t":6,"p":1,"n":"FaceGen Data","c":[{"t":11,"p":1,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"p":1,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"p":1,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"n":"SNAM - Unknown"}]}]}]},{"t":1,"p":1,"n":"RADS - Radiation Stage","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Trigger Threshold"},{"t":3,"p":1,"n":"Actor Effect"}]}]},{"t":1,"p":1,"n":"REFR - Placed Object","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":11,"n":"RCLR - Unused"},{"t":3,"p":1,"n":"NAME - Base"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":11,"n":"XRGD - Ragdoll Data"},{"t":11,"n":"XRGB - Ragdoll Biped Data"},{"t":6,"s":1,"p":1,"n":"XPRM - Primitive","c":[{"t":6,"p":1,"n":"Bounds","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Color","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}]},{"t":5,"n":"Unknown"},{"t":3,"p":1,"n":"Type"}]},{"t":3,"p":1,"n":"XTRI - Collision Layer"},{"p":1,"n":"XMBP - MultiBound Primitive Marker"},{"t":6,"s":1,"p":1,"n":"XMBO - Bound Half Extents","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"s":1,"p":1,"n":"XTEL - Teleport Destination","c":[{"t":3,"p":1,"n":"Door"},{"t":6,"p":1,"n":"Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]},{"t":3,"p":1,"n":"Flags"}]},{"t":6,"s":1,"p":1,"n":"Map Marker","c":[{"p":1,"n":"XMRK - Map Marker Data"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"p":1,"n":"TNAM - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"}]}]},{"t":3,"p":1,"n":"XSRF - Special Rendering Flags"},{"t":11,"n":"XSRD - Special Rendering Data"},{"t":3,"p":1,"n":"XTRG - Target"},{"t":3,"p":1,"n":"XLCM - Level Modifier"},{"t":6,"s":1,"p":1,"n":"Patrol Data","c":[{"t":5,"p":1,"n":"XPRD - Idle Time"},{"p":1,"n":"XPPA - Patrol Script Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":6,"p":1,"n":"Embedded Script","c":[{"t":6,"p":1,"n":"SCHR - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"p":1,"n":"SCDA - Compiled Embedded Script"},{"t":2,"p":1,"n":"SCTX - Embedded Script Source"},{"t":10,"p":1,"n":"Local Variables","c":[{"t":6,"p":1,"n":"Local Variable","c":[{"t":6,"p":1,"n":"SLSD - Local Variable Data","c":[{"t":3,"p":1,"n":"Index"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"SCVR - Name"}]}]},{"t":8,"p":1,"n":"References","c":[{"t":3,"p":1,"n":"SCRO - Global Reference"},{"t":3,"p":1,"n":"SCRV - Local Variable"}]}]},{"t":3,"p":1,"n":"TNAM - Topic"}]},{"t":6,"s":1,"p":1,"n":"XRDO - Radio Data","c":[{"t":5,"p":1,"n":"Range Radius"},{"t":3,"p":1,"n":"Broadcast Range Type"},{"t":5,"p":1,"n":"Static Percentage"},{"t":3,"p":1,"n":"Position Reference"}]},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":6,"s":1,"p":1,"n":"XLOC - Lock Data","c":[{"t":3,"p":1,"n":"Level"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Key"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"}]},{"t":3,"p":1,"n":"XCNT - Count"},{"t":5,"p":1,"n":"XRDS - Radius"},{"t":5,"p":1,"n":"XHLP - Health"},{"t":5,"p":1,"n":"XRAD - Radiation"},{"t":5,"p":1,"n":"XCHG - Charge"},{"t":6,"s":1,"p":1,"n":"Ammo","c":[{"t":3,"p":1,"n":"XAMT - Type"},{"t":3,"p":1,"n":"XAMC - Count"}]},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Lit Water","d":1,"c":[{"t":3,"p":1,"n":"XLTW - Water"}]},{"t":8,"s":1,"p":1,"n":"Linked Decals","d":1,"c":[{"t":6,"p":1,"n":"XDCR - Decal","c":[{"t":3,"p":1,"n":"Reference"},{"t":11,"n":"Unknown"}]}]},{"t":3,"p":1,"n":"XLKR - Linked Reference"},{"t":6,"s":1,"p":1,"n":"XCLP - Linked Reference Color","c":[{"t":6,"p":1,"n":"Link Start Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Link End Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"t":3,"p":1,"n":"XACT - Action Flag"},{"p":1,"n":"ONAM - Open by Default"},{"p":1,"n":"XIBS - Ignored By Sandbox"},{"t":6,"s":1,"p":1,"n":"XNDP - Navigation Door Link","c":[{"t":3,"p":1,"n":"Navigation Mesh"},{"t":3,"p":1,"n":"Teleport Marker Triangle"},{"t":11,"n":"Unused"}]},{"t":7,"p":1,"n":"XPOD - Portal Data","c":[{"t":3,"p":1,"n":"Room"}]},{"t":6,"s":1,"p":1,"n":"XPTL - Portal Data","c":[{"t":6,"p":1,"n":"Size","c":[{"t":5,"p":1,"n":"Width"},{"t":5,"p":1,"n":"Height"}]},{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation (Quaternion?)","c":[{"t":5,"p":1,"n":"q1"},{"t":5,"p":1,"n":"q2"},{"t":5,"p":1,"n":"q3"},{"t":5,"p":1,"n":"q4"}]}]},{"t":3,"p":1,"n":"XSED - SpeedTree Seed"},{"t":6,"s":1,"p":1,"n":"Room Data","c":[{"t":6,"p":1,"n":"XRMR - Header","c":[{"t":3,"p":1,"n":"Linked Rooms Count"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Linked Rooms","c":[{"t":3,"p":1,"n":"XLRM - Linked Room"}]}]},{"t":6,"s":1,"p":1,"n":"XOCP - Occlusion Plane Data","c":[{"t":6,"p":1,"n":"Size","c":[{"t":5,"p":1,"n":"Width"},{"t":5,"p":1,"n":"Height"}]},{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation (Quaternion?)","c":[{"t":5,"p":1,"n":"q1"},{"t":5,"p":1,"n":"q2"},{"t":5,"p":1,"n":"q3"},{"t":5,"p":1,"n":"q4"}]}]},{"t":7,"p":1,"n":"XORD - Linked Occlusion Planes","c":[{"t":3,"p":1,"n":"Plane"}]},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"REGN - Region","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"RCLR - Map Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"WNAM - Worldspace"},{"t":8,"s":1,"p":1,"n":"Region Areas","d":1,"c":[{"t":6,"p":1,"n":"Region Area","c":[{"t":3,"p":1,"n":"RPLI - Edge Fall-off"},{"t":7,"p":1,"n":"RPLD - Region Point List Data","c":[{"t":6,"p":1,"n":"Point","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"}]}]}]}]},{"t":10,"p":1,"n":"Region Data Entries","d":1,"c":[{"t":6,"p":1,"n":"Region Data Entry","c":[{"t":6,"p":1,"n":"RDAT - Data Header","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Priority"},{"t":11,"n":"Unused"}]},{"t":7,"p":1,"n":"RDOT - Objects","c":[{"t":6,"p":1,"n":"Object","c":[{"t":3,"p":1,"n":"Object"},{"t":3,"p":1,"n":"Parent Index"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Density"},{"t":3,"p":1,"n":"Clustering"},{"t":3,"p":1,"n":"Min Slope"},{"t":3,"p":1,"n":"Max Slope"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Radius wrt Parent"},{"t":3,"p":1,"n":"Radius"},{"t":5,"p":1,"n":"Min Height"},{"t":5,"p":1,"n":"Max Height"},{"t":5,"p":1,"n":"Sink"},{"t":5,"p":1,"n":"Sink Variance"},{"t":5,"p":1,"n":"Size Variance"},{"t":6,"p":1,"n":"Angle Variance","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"},{"t":3,"p":1,"n":"Z"}]},{"t":11,"n":"Unknown"}]}]},{"t":2,"p":1,"n":"RDMP - Map Name"},{"t":7,"p":1,"n":"RDGS - Grasses","c":[{"t":6,"p":1,"n":"Grass","c":[{"t":3,"p":1,"n":"Grass"},{"t":11,"n":"Unknown"}]}]},{"t":3,"p":1,"n":"RDMD - Music Type"},{"t":3,"p":1,"n":"RDMO - Music"},{"t":7,"p":1,"n":"RDSD - Sounds","c":[{"t":6,"p":1,"n":"Sound","c":[{"t":3,"p":1,"n":"Sound"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Chance"}]}]},{"t":7,"p":1,"n":"RDWT - Weather Types","c":[{"t":6,"p":1,"n":"Weather Type","c":[{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Chance"},{"t":3,"p":1,"n":"Global"}]}]}]}]}]},{"t":1,"p":1,"n":"RGDL - Ragdoll","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"NVER - Version"},{"t":6,"s":1,"p":1,"n":"DATA - General Data","c":[{"t":3,"p":1,"n":"Dynamic Bone Count"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Enabled","c":[{"t":3,"p":1,"n":"Feedback"},{"t":3,"p":1,"n":"Foot IK (broken, don't use)"},{"t":3,"p":1,"n":"Look IK (broken, don't use)"},{"t":3,"p":1,"n":"Grab IK (broken, don't use)"},{"t":3,"p":1,"n":"Pose Matching"}]}]},{"t":3,"p":1,"n":"XNAM - Actor Base"},{"t":3,"p":1,"n":"TNAM - Body Part Data"},{"t":6,"s":1,"p":1,"n":"RAFD - Feedback Data","c":[{"t":5,"p":1,"n":"Dynamic\/Keyframe Blend Amount"},{"t":5,"p":1,"n":"Hierarchy Gain"},{"t":5,"p":1,"n":"Position Gain"},{"t":5,"p":1,"n":"Velocity Gain"},{"t":5,"p":1,"n":"Acceleration Gain"},{"t":5,"p":1,"n":"Snap Gain"},{"t":5,"p":1,"n":"Velocity Damping"},{"t":6,"p":1,"n":"Snap Max Settings","c":[{"t":5,"p":1,"n":"Linear Velocity"},{"t":5,"p":1,"n":"Angular Velocity"},{"t":5,"p":1,"n":"Linear Distance"},{"t":5,"p":1,"n":"Angular Distance"}]},{"t":6,"p":1,"n":"Position Max Velocity","c":[{"t":5,"p":1,"n":"Linear"},{"t":5,"p":1,"n":"Angular"}]}]},{"t":7,"p":1,"n":"RAFB - Feedback Dynamic Bones","c":[{"t":3,"p":1,"n":"Bone"}]},{"t":6,"s":1,"p":1,"n":"RAPS - Pose Matching Data","c":[{"t":7,"p":1,"n":"Match Bones","c":[{"t":3,"p":1,"n":"Bone"}]},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Motors Strength"},{"t":5,"p":1,"n":"Pose Activation Delay Time"},{"t":5,"p":1,"n":"Match Error Allowance"},{"t":5,"p":1,"n":"Displacement To Disable"}]},{"t":2,"p":1,"n":"ANAM - Death Pose"}]},{"t":1,"p":1,"n":"SCOL - Static Collection","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":10,"p":1,"n":"Parts","d":1,"c":[{"t":6,"p":1,"n":"Part","c":[{"t":3,"p":1,"n":"ONAM - Static"},{"t":7,"p":1,"n":"DATA - Placements","c":[{"t":6,"p":1,"n":"Placement","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":5,"p":1,"n":"Scale"}]}]}]}]}]},{"t":1,"p":1,"n":"SCPT - Script","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"SCHR - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"n":"SCDA - Compiled Script"},{"t":2,"p":1,"n":"SCTX - Script Source"},{"t":10,"p":1,"n":"Local Variables","d":1,"c":[{"t":6,"p":1,"n":"Local Variable","c":[{"t":6,"p":1,"n":"SLSD - Local Variable Data","c":[{"t":3,"p":1,"n":"Index"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"SCVR - Name"}]}]},{"t":8,"s":1,"p":1,"n":"References","d":1,"c":[{"t":3,"p":1,"n":"SCRO - Global Reference"},{"t":3,"p":1,"n":"SCRV - Local Variable"}]}]},{"t":1,"p":1,"n":"SOUN - Sound","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FNAM - Sound Filename"},{"t":6,"s":1,"p":1,"n":"SNDD - Sound Data","c":[{"t":3,"p":1,"n":"Minimum Attentuation Distance"},{"t":3,"p":1,"n":"Maximum Attentuation Distance"},{"t":3,"p":1,"n":"Frequency Adjustment %"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Static attentuation cdB"},{"t":3,"p":1,"n":"Stop time "},{"t":3,"p":1,"n":"Start time "},{"t":7,"p":1,"n":"Attenuation Curve","c":[{"t":3,"p":1,"n":"Point"}]},{"t":3,"p":1,"n":"Reverb Attenuation Control"},{"t":3,"p":1,"n":"Priority"},{"t":11,"n":"Unknown"}]},{"t":6,"s":1,"p":1,"n":"SNDX - Sound Data","c":[{"t":3,"p":1,"n":"Minimum attentuation distance"},{"t":3,"p":1,"n":"Maximum attentuation distance"},{"t":3,"p":1,"n":"Frequency adjustment %"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Static attentuation cdB"},{"t":3,"p":1,"n":"Stop time "},{"t":3,"p":1,"n":"Start time "}]},{"t":7,"p":1,"n":"ANAM - Attenuation Curve","c":[{"t":3,"p":1,"n":"Point"}]},{"t":3,"p":1,"n":"GNAM - Reverb Attenuation Control"},{"t":3,"p":1,"n":"HNAM - Priority"}]},{"t":1,"p":1,"n":"SPEL - Actor Effect","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"SPIT - ","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"n":"Cost (Unused)"},{"t":3,"n":"Level (Unused)"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"s":1,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":3,"p":1,"n":"EFID - Base Effect"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":3,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Actor Value"}]},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"CTDA - Condition","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Note"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Creature Type"},{"t":3,"p":1,"n":"Menu Mode"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Body Location"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"VATS Value Function (INVALID)"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"}]}]}]}]}]},{"t":1,"p":1,"n":"STAT - Static","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]}]},{"t":1,"p":1,"n":"TACT - Talking Activator","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"SNAM - Sound"},{"t":3,"p":1,"n":"VNAM - Voice Type"}]},{"t":1,"p":1,"n":"TERM - Terminal","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":2,"p":1,"n":"DESC - Description"},{"t":3,"p":1,"n":"SNAM - Sound - Looping"},{"t":3,"p":1,"n":"PNAM - Password Note"},{"t":6,"s":1,"p":1,"n":"DNAM - ","c":[{"t":3,"p":1,"n":"Base Hacking Difficulty"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"ServerType"},{"t":11,"n":"Unused"}]},{"t":8,"s":1,"p":1,"n":"Menu Items","d":1,"c":[{"t":6,"p":1,"n":"Menu Item","c":[{"t":2,"p":1,"n":"ITXT - Item Text"},{"t":2,"p":1,"n":"RNAM - Result Text"},{"t":3,"p":1,"n":"ANAM - Flags"},{"t":3,"p":1,"n":"INAM - Display Note"},{"t":3,"p":1,"n":"TNAM - Sub Menu"},{"t":6,"p":1,"n":"Embedded Script","c":[{"t":6,"p":1,"n":"SCHR - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"p":1,"n":"SCDA - Compiled Embedded Script"},{"t":2,"p":1,"n":"SCTX - Embedded Script Source"},{"t":10,"p":1,"n":"Local Variables","c":[{"t":6,"p":1,"n":"Local Variable","c":[{"t":6,"p":1,"n":"SLSD - Local Variable Data","c":[{"t":3,"p":1,"n":"Index"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"SCVR - Name"}]}]},{"t":8,"p":1,"n":"References","c":[{"t":3,"p":1,"n":"SCRO - Global Reference"},{"t":3,"p":1,"n":"SCRV - Local Variable"}]}]},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"CTDA - Condition","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Note"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Creature Type"},{"t":3,"p":1,"n":"Menu Mode"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Body Location"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"VATS Value Function (INVALID)"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"}]}]}]}]}]},{"t":1,"p":1,"n":"TREE - Tree","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":7,"p":1,"n":"SNAM - SpeedTree Seeds","c":[{"t":3,"p":1,"n":"SpeedTree Seed"}]},{"t":6,"s":1,"p":1,"n":"CNAM - Tree Data","c":[{"t":5,"p":1,"n":"Leaf Curvature"},{"t":5,"p":1,"n":"Minimum Leaf Angle"},{"t":5,"p":1,"n":"Maximum Leaf Angle"},{"t":5,"p":1,"n":"Branch Dimming Value"},{"t":5,"p":1,"n":"Leaf Dimming Value"},{"t":3,"p":1,"n":"Shadow Radius"},{"t":5,"p":1,"n":"Rock Speed"},{"t":5,"p":1,"n":"Rustle Speed"}]},{"t":6,"s":1,"p":1,"n":"BNAM - Billboard Dimensions","c":[{"t":5,"p":1,"n":"Width"},{"t":5,"p":1,"n":"Height"}]}]},{"t":1,"p":1,"n":"TXST - Texture Set","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Textures (RGB\/A)","c":[{"t":2,"p":1,"n":"TX00 - Base Image \/ Transparency"},{"t":2,"p":1,"n":"TX01 - Normal Map \/ Specular"},{"t":2,"p":1,"n":"TX02 - Environment Map Mask \/ ?"},{"t":2,"n":"TX03 - Glow Map \/ Unused"},{"t":2,"n":"TX04 - Parallax Map \/ Unused"},{"t":2,"n":"TX05 - Environment Map \/ Unused"}]},{"t":6,"s":1,"p":1,"n":"DODT - Decal Data","c":[{"t":5,"p":1,"n":"Min Width"},{"t":5,"p":1,"n":"Max Width"},{"t":5,"p":1,"n":"Min Height"},{"t":5,"p":1,"n":"Max Height"},{"t":5,"p":1,"n":"Depth"},{"t":5,"p":1,"n":"Shininess"},{"t":6,"p":1,"n":"Parallax","c":[{"t":5,"p":1,"n":"Scale"},{"t":3,"p":1,"n":"Passes"}]},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":3,"p":1,"n":"DNAM - Flags"}]},{"t":1,"p":1,"n":"VTYP - Voice Type","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"DNAM - Flags"}]},{"t":1,"p":1,"n":"WATR - Water","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"NNAM - Noise Map"},{"t":3,"p":1,"n":"ANAM - Opacity"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":2,"p":1,"n":"MNAM - Material ID"},{"t":3,"p":1,"n":"SNAM - Sound"},{"t":3,"p":1,"n":"XNAM - Actor Effect"},{"t":3,"p":1,"n":"DATA - Damage"},{"t":6,"s":1,"p":1,"n":"DNAM - Visual Data","c":[{"t":5,"n":"Unknown"},{"t":5,"p":1,"n":"Water Properties - Sun Power"},{"t":5,"p":1,"n":"Water Properties - Reflectivity Amount"},{"t":5,"p":1,"n":"Water Properties - Fresnel Amount"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Fog Properties - Above Water - Fog Distance - Near Plane"},{"t":5,"p":1,"n":"Fog Properties - Above Water - Fog Distance - Far Plane"},{"t":6,"p":1,"n":"Shallow Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Deep Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Reflection Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Rain Simulator - Force"},{"t":5,"p":1,"n":"Rain Simulator - Velocity"},{"t":5,"p":1,"n":"Rain Simulator - Falloff"},{"t":5,"p":1,"n":"Rain Simulator - Dampner"},{"t":5,"p":1,"n":"Displacement Simulator - Starting Size"},{"t":5,"p":1,"n":"Displacement Simulator - Force"},{"t":5,"p":1,"n":"Displacement Simulator - Velocity"},{"t":5,"p":1,"n":"Displacement Simulator - Falloff"},{"t":5,"p":1,"n":"Displacement Simulator - Dampner"},{"t":5,"p":1,"n":"Rain Simulator - Starting Size"},{"t":5,"p":1,"n":"Noise Properties - Normals - Noise Scale"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer One - Wind Direction"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer Two - Wind Direction"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer Three - Wind Direction"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer One - Wind Speed"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer Two - Wind Speed"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer Three - Wind Speed"},{"t":5,"p":1,"n":"Noise Properties - Normals - Depth Falloff Start"},{"t":5,"p":1,"n":"Noise Properties - Normals - Depth Falloff End"},{"t":5,"p":1,"n":"Fog Properties - Above Water - Fog Amount"},{"t":5,"p":1,"n":"Noise Properties - Normals - UV Scale"},{"t":5,"p":1,"n":"Fog Properties - Under Water - Fog Amount"},{"t":5,"p":1,"n":"Fog Properties - Under Water - Fog Distance - Near Plane"},{"t":5,"p":1,"n":"Fog Properties - Under Water - Fog Distance - Far Plane"},{"t":5,"p":1,"n":"Water Properties - Distortion Amount"},{"t":5,"p":1,"n":"Water Properties - Shininess"},{"t":5,"p":1,"n":"Water Properties - Reflection HDR Multiplier"},{"t":5,"p":1,"n":"Water Properties - Light Radius"},{"t":5,"p":1,"n":"Water Properties - Light Brightness"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer One - UV Scale"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer Two - UV Scale"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer Three - UV Scale"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer One - Amplitude Scale"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer Two - Amplitude Scale"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer Three - Amplitude Scale"}]},{"t":6,"s":1,"p":1,"n":"DATA - Visual Data","c":[{"t":5,"n":"Unknown"},{"t":5,"p":1,"n":"Water Properties - Sun Power"},{"t":5,"p":1,"n":"Water Properties - Reflectivity Amount"},{"t":5,"p":1,"n":"Water Properties - Fresnel Amount"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Fog Properties - Above Water - Fog Distance - Near Plane"},{"t":5,"p":1,"n":"Fog Properties - Above Water - Fog Distance - Far Plane"},{"t":6,"p":1,"n":"Shallow Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Deep Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Reflection Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Rain Simulator - Force"},{"t":5,"p":1,"n":"Rain Simulator - Velocity"},{"t":5,"p":1,"n":"Rain Simulator - Falloff"},{"t":5,"p":1,"n":"Rain Simulator - Dampner"},{"t":5,"p":1,"n":"Displacement Simulator - Starting Size"},{"t":5,"p":1,"n":"Displacement Simulator - Force"},{"t":5,"p":1,"n":"Displacement Simulator - Velocity"},{"t":5,"p":1,"n":"Displacement Simulator - Falloff"},{"t":5,"p":1,"n":"Displacement Simulator - Dampner"},{"t":5,"p":1,"n":"Rain Simulator - Starting Size"},{"t":5,"p":1,"n":"Noise Properties - Normals - Noise Scale"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer One - Wind Direction"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer Two - Wind Direction"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer Three - Wind Direction"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer One - Wind Speed"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer Two - Wind Speed"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer Three - Wind Speed"},{"t":5,"p":1,"n":"Noise Properties - Normals - Depth Falloff Start"},{"t":5,"p":1,"n":"Noise Properties - Normals - Depth Falloff End"},{"t":5,"p":1,"n":"Fog Properties - Above Water - Fog Amount"},{"t":5,"p":1,"n":"Noise Properties - Normals - UV Scale"},{"t":5,"p":1,"n":"Fog Properties - Under Water - Fog Amount"},{"t":5,"p":1,"n":"Fog Properties - Under Water - Fog Distance - Near Plane"},{"t":5,"p":1,"n":"Fog Properties - Under Water - Fog Distance - Far Plane"},{"t":5,"p":1,"n":"Water Properties - Distortion Amount"},{"t":5,"p":1,"n":"Water Properties - Shininess"},{"t":5,"p":1,"n":"Water Properties - Reflection HDR Multiplier"},{"t":5,"p":1,"n":"Water Properties - Light Radius"},{"t":5,"p":1,"n":"Water Properties - Light Brightness"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer One - UV Scale"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer Two - UV Scale"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer Three - UV Scale"},{"p":1,"n":"Noise Properties - Noise Layer One - Amplitude Scale"},{"p":1,"n":"Noise Properties - Noise Layer Two - Amplitude Scale"},{"p":1,"n":"Noise Properties - Noise Layer Three - Amplitude Scale"},{"t":3,"p":1,"n":"Damage (Old Format)"}]},{"t":6,"n":"GNAM - Related Waters (Unused)","c":[{"t":3,"n":"Daytime"},{"t":3,"n":"Nighttime"},{"t":3,"n":"Underwater"}]}]},{"t":1,"p":1,"n":"WEAP - Weapon","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":3,"p":1,"n":"EITM - Object Effect"},{"t":3,"p":1,"n":"EAMT - Enchantment Charge Amount"},{"t":3,"p":1,"n":"NAM0 - Ammo"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"REPL - Repair List"},{"t":3,"p":1,"n":"ETYP - Equiptment Type"},{"t":3,"p":1,"n":"BIPL - Biped Model List"},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Drop"},{"t":6,"s":1,"p":1,"n":"Shell Casing Model","c":[{"t":2,"p":1,"n":"MOD2 - Model Filename"},{"t":11,"p":1,"n":"MO2T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO2S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Scope Model","c":[{"t":2,"p":1,"n":"MOD3 - Model Filename"},{"t":11,"p":1,"n":"MO3T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO3S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":3,"p":1,"n":"EFSD - Scope Effect"},{"t":6,"s":1,"p":1,"n":"World Model","c":[{"t":2,"p":1,"n":"MOD4 - Model Filename"},{"t":11,"p":1,"n":"MO4T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO4S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":2,"p":1,"n":"NNAM - Embedded Weapon Node"},{"t":3,"p":1,"n":"INAM - Impact DataSet"},{"t":3,"p":1,"n":"WNAM - 1st Person Model"},{"t":3,"p":1,"n":"SNAM - Sound - Gun - Shoot 3D"},{"t":3,"p":1,"n":"XNAM - Sound - Gun - Shoot 2D"},{"t":3,"p":1,"n":"NAM7 - Sound - Gun - Shoot 3D Looping"},{"t":3,"p":1,"n":"TNAM - Sound - Melee - Swing \/ Gun - No Ammo"},{"t":3,"p":1,"n":"NAM6 - Sound - Block"},{"t":3,"p":1,"n":"UNAM - Sound - Idle"},{"t":3,"p":1,"n":"NAM9 - Sound - Equip"},{"t":3,"p":1,"n":"NAM8 - Sound - Unequip"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Value"},{"t":3,"p":1,"n":"Health"},{"t":5,"p":1,"n":"Weight"},{"t":3,"p":1,"n":"Base Damage"},{"t":3,"p":1,"n":"Clip Size"}]},{"t":6,"s":1,"p":1,"n":"DNAM - ","c":[{"t":3,"p":1,"n":"Animation Type"},{"t":5,"p":1,"n":"Animation Multiplier"},{"t":5,"p":1,"n":"Reach"},{"t":3,"p":1,"n":"Flags 1"},{"t":3,"p":1,"n":"Grip Animation"},{"t":3,"p":1,"n":"Ammo Use"},{"t":3,"p":1,"n":"Reload Animation"},{"t":5,"p":1,"n":"Min Spread"},{"t":5,"p":1,"n":"Spread"},{"t":5,"n":"Unknown"},{"t":5,"p":1,"n":"Sight FOV"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Projectile"},{"t":3,"p":1,"n":"Base VATS To-Hit Chance"},{"t":3,"p":1,"n":"Attack Animation"},{"t":3,"p":1,"n":"Projectile Count"},{"t":3,"p":1,"n":"Embedded Weapon - Actor Value"},{"t":5,"p":1,"n":"Min Range"},{"t":5,"p":1,"n":"Max Range"},{"t":3,"p":1,"n":"On Hit"},{"t":3,"p":1,"n":"Flags 2"},{"t":5,"p":1,"n":"Animation Attack Multiplier"},{"t":5,"p":1,"n":"Fire Rate"},{"t":5,"p":1,"n":"Override - Action Points"},{"t":5,"p":1,"n":"Rumble - Left Motor Strength"},{"t":5,"p":1,"n":"Rumble - Right Motor Strength"},{"t":5,"p":1,"n":"Rumble - Duration"},{"t":5,"p":1,"n":"Override - Damage to Weapon Mult"},{"t":5,"p":1,"n":"Attack Shots\/Sec"},{"t":5,"p":1,"n":"Reload Time"},{"t":5,"p":1,"n":"Jam Time"},{"t":5,"p":1,"n":"Aim Arc"},{"t":3,"p":1,"n":"Skill"},{"t":3,"p":1,"n":"Rumble - Pattern"},{"t":5,"p":1,"n":"Rumble - Wavelength"},{"t":5,"p":1,"n":"Limb Dmg Mult"},{"t":3,"p":1,"n":"Resist Type"},{"t":5,"p":1,"n":"Sight Usage"},{"t":5,"p":1,"n":"Semi-Automatic Fire Delay Min"},{"t":5,"p":1,"n":"Semi-Automatic Fire Delay Max"}]},{"t":6,"s":1,"p":1,"n":"CRDT - Critical Data","c":[{"t":3,"p":1,"n":"Critical Damage"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Crit % Mult"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Effect"}]},{"t":3,"p":1,"n":"VNAM - Sound Level"}]},{"t":1,"p":1,"n":"WRLD - Worldspace","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":6,"s":1,"p":1,"n":"Parent","c":[{"t":3,"p":1,"n":"WNAM - Worldspace"},{"t":6,"p":1,"n":"PNAM - ","c":[{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"}]}]},{"t":3,"p":1,"n":"CNAM - Climate"},{"t":3,"p":1,"n":"NAM2 - Water"},{"t":3,"p":1,"n":"NAM3 - LOD Water Type"},{"t":5,"p":1,"n":"NAM4 - LOD Water Height"},{"t":6,"s":1,"p":1,"n":"DNAM - Land Data","c":[{"t":5,"p":1,"n":"Default Land Height"},{"t":5,"p":1,"n":"Default Water Height"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"MNAM - Map Data","c":[{"t":6,"p":1,"n":"Usable Dimensions","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"}]},{"t":6,"p":1,"n":"Cell Coordinates","c":[{"t":6,"p":1,"n":"NW Cell","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"}]},{"t":6,"p":1,"n":"SE Cell","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"}]}]}]},{"t":6,"s":1,"p":1,"n":"ONAM - World Map Offset Data","c":[{"t":5,"p":1,"n":"World Map Scale"},{"t":5,"p":1,"n":"Cell X Offset"},{"t":5,"p":1,"n":"Cell Y Offset"}]},{"t":3,"p":1,"n":"INAM - Image Space"},{"t":3,"p":1,"n":"DATA - Flags"},{"t":6,"s":1,"p":1,"n":"Object Bounds","c":[{"t":6,"p":1,"n":"NAM0 - Min","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"}]},{"t":6,"p":1,"n":"NAM9 - Max","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"}]}]},{"t":3,"p":1,"n":"ZNAM - Music"},{"t":2,"p":1,"n":"NNAM - Canopy Shadow"},{"t":2,"p":1,"n":"XNAM - Water Noise Texture"},{"t":8,"s":1,"p":1,"n":"Swapped Impacts","d":1,"c":[{"t":6,"p":1,"n":"IMPS - Swapped Impact","c":[{"t":3,"p":1,"n":"Material Type"},{"t":3,"p":1,"n":"Old"},{"t":3,"p":1,"n":"New"}]}]},{"t":7,"n":"IMPF - Footstep Materials","c":[{"t":2,"n":"Unknown"}]},{"t":11,"n":"OFST - Offset Data"}]},{"t":1,"p":1,"n":"WTHR - Weather","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"aIAD - Sunrise Image Space Modifier"},{"t":3,"p":1,"n":"bIAD - Day Image Space Modifier"},{"t":3,"p":1,"n":"cIAD - Sunset Image Space Modifier"},{"t":3,"p":1,"n":"dIAD - Night Image Space Modifier"},{"t":2,"p":1,"n":"DNAM - Cloud Textures - Layer 0"},{"t":2,"p":1,"n":"CNAM - Cloud Textures - Layer 1"},{"t":2,"p":1,"n":"ANAM - Cloud Textures - Layer 2"},{"t":2,"p":1,"n":"BNAM - Cloud Textures - Layer 3"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":11,"n":"LNAM - Unknown"},{"t":7,"p":1,"n":"ONAM - Cloud Speed","c":[{"t":3,"p":1,"n":"Layer"}]},{"t":7,"p":1,"n":"PNAM - Cloud Layer Colors","c":[{"t":7,"p":1,"n":"Layer","c":[{"t":6,"p":1,"n":"Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]}]},{"t":7,"p":1,"n":"NAM0 - Colors by Types\/Times","c":[{"t":7,"p":1,"n":"Type","c":[{"t":6,"p":1,"n":"Time","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]}]},{"t":6,"s":1,"p":1,"n":"FNAM - Fog Distance","c":[{"t":5,"p":1,"n":"Day - Near"},{"t":5,"p":1,"n":"Day - Far"},{"t":5,"p":1,"n":"Night - Near"},{"t":5,"p":1,"n":"Night - Far"},{"t":5,"p":1,"n":"Day - Power"},{"t":5,"p":1,"n":"Night - Fower"}]},{"t":11,"n":"INAM - Unused"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Wind Speed"},{"t":3,"p":1,"n":"Cloud Speed (Lower)"},{"t":3,"p":1,"n":"Cloud Speed (Upper)"},{"t":3,"p":1,"n":"Trans Delta"},{"t":3,"p":1,"n":"Sun Glare"},{"t":3,"p":1,"n":"Sun Damage"},{"t":3,"p":1,"n":"Precipitation - Begin Fade In"},{"t":3,"p":1,"n":"Precipitation - End Fade Out"},{"t":3,"p":1,"n":"Thunder\/Lightning - Begin Fade In"},{"t":3,"p":1,"n":"Thunder\/Lightning - End Fade Out"},{"t":3,"p":1,"n":"Thunder\/Lightning - Frequency"},{"t":3,"p":1,"n":"Weather Classification"},{"t":6,"p":1,"n":"Lightning Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"}]}]},{"t":8,"s":1,"p":1,"n":"Sounds","d":1,"c":[{"t":6,"p":1,"n":"SNAM - Sound","c":[{"t":3,"p":1,"n":"Sound"},{"t":3,"p":1,"n":"Type"}]}]}]},{"t":1,"p":1,"n":"ACRE - Placed Creature","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"NAME - Base"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":11,"n":"XRGD - Ragdoll Data"},{"t":11,"n":"XRGB - Ragdoll Biped Data"},{"t":6,"s":1,"p":1,"n":"Patrol Data","c":[{"t":5,"p":1,"n":"XPRD - Idle Time"},{"p":1,"n":"XPPA - Patrol Script Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":6,"p":1,"n":"Embedded Script","c":[{"t":6,"p":1,"n":"SCHR - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"p":1,"n":"SCDA - Compiled Embedded Script"},{"t":2,"p":1,"n":"SCTX - Embedded Script Source"},{"t":10,"p":1,"n":"Local Variables","c":[{"t":6,"p":1,"n":"Local Variable","c":[{"t":6,"p":1,"n":"SLSD - Local Variable Data","c":[{"t":3,"p":1,"n":"Index"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"SCVR - Name"}]}]},{"t":8,"p":1,"n":"References","c":[{"t":3,"p":1,"n":"SCRO - Global Reference"},{"t":3,"p":1,"n":"SCRV - Local Variable"}]}]},{"t":3,"p":1,"n":"TNAM - Topic"}]},{"t":3,"p":1,"n":"XLCM - Level Modifier"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":3,"p":1,"n":"XMRC - Merchant Container"},{"t":3,"p":1,"n":"XCNT - Count"},{"t":5,"p":1,"n":"XRDS - Radius"},{"t":5,"p":1,"n":"XHLP - Health"},{"t":8,"s":1,"p":1,"n":"Linked Decals","d":1,"c":[{"t":6,"p":1,"n":"XDCR - Decal","c":[{"t":3,"p":1,"n":"Reference"},{"t":11,"n":"Unknown"}]}]},{"t":3,"p":1,"n":"XLKR - Linked Reference"},{"t":6,"s":1,"p":1,"n":"XCLP - Linked Reference Color","c":[{"t":6,"p":1,"n":"Link Start Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Link End Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIBS - Ignored By Sandbox"},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]}]},"name":"Smash.All","hash":"0BB5CBB2","color":128} ================================================ FILE: frontend/settings/Fallout4/Smash.All.json ================================================ {"records":"ACHR,ACTI,ADDN,AECH,ALCH,AMDL,AMMO,ANIO,AORU,ARMA,ARMO,ARTO,ASPC,ASTP,AVIF,BNDS,BOOK,BPTD,CAMS,CELL,CLAS,CLFM,CLMT,CMPO,COBJ,COLL,CONT,CPTH,CSTY,DEBR,DFOB,DIAL,DLBR,DLVW,DMGT,DOOR,DUAL,ECZN,EFSH,ENCH,EQUP,EXPL,FACT,FLOR,FLST,FSTP,FSTS,FURN,GDRY,GLOB,GMST,GRAS,HAZD,HDPT,IDLM,IMAD,IMGS,INFO,INGR,INNR,IPCT,IPDS,KEYM,KSSM,KYWD,LAND,LAYR,LCRT,LENS,LGTM,LIGH,LSCR,LTEX,LVLI,LVLN,LVSP,MATO,MATT,MESG,MGEF,MISC,MOVT,MSTT,MSWP,MUSC,MUST,NOTE,NPC_,OMOD,OTFT,PACK,PARW,PBAR,PBEA,PCON,PERK,PFLA,PGRE,PHZD,PKIN,PMIS,PROJ,QUST,REFR,REGN,RELA,REVB,RFCT,RFGP,SCCO,SCEN,SCOL,SCSN,SMBN,SMEN,SMQN,SNCT,SNDR,SOPM,SOUN,SPEL,SPGD,STAG,STAT,TACT,TERM,TREE,TRNS,TXST,VTYP,WATR,WEAP,WRLD,WTHR,ZOOM,AACT","description":"Smashes all the things. Produced using autoset attributes on all record types found in Fallout4.esm.\r\n\r\nLast updated 05\/01\/2018.","tree":{"records":[{"t":1,"p":1,"n":"ACHR - Placed NPC","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Base"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":11,"n":"XRGD - Ragdoll Data"},{"t":11,"n":"XRGB - Ragdoll Biped Data"},{"t":6,"s":1,"p":1,"n":"Patrol Data","c":[{"t":5,"p":1,"n":"XPRD - Idle Time"},{"p":1,"n":"XPPA - Patrol Script Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":8,"p":1,"n":"Topic","c":[{"t":6,"p":1,"n":"PDTO - Topic Data","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Topic"},{"t":2,"p":1,"n":"Subtype"}]}]},{"t":3,"p":1,"n":"TNAM - Topic"}]},{"t":3,"p":1,"n":"XLCM - Level Modifier"},{"t":3,"p":1,"n":"XCNT - Count"},{"t":5,"p":1,"n":"XRDS - Radius"},{"t":3,"p":1,"n":"XHLT - Health %"},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"p":1,"n":"XLKT - Linked Ref Transient"},{"t":3,"p":1,"n":"XRFG - Reference Group"},{"t":3,"p":1,"n":"XLYR - Layer"},{"t":3,"p":1,"n":"XMSP - Material Swap"},{"t":3,"p":1,"n":"XLCN - Persistent Location"},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":8,"s":1,"p":1,"n":"Spline Connection","d":1,"c":[{"t":6,"p":1,"n":"XPLK - Link","c":[{"t":3,"p":1,"n":"Ref"},{"t":11,"n":"Unknown"}]}]},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":6,"s":1,"p":1,"n":"XOWN - Owner","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Flags"}]},{"t":3,"p":1,"n":"XRNK - Owner Faction Rank"},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIBS - Ignored By Sandbox"},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]},{"t":2,"p":1,"n":"MNAM - Comments"}]},{"t":1,"p":1,"n":"ACTI - Activator","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"PTRN - Preview Transform"},{"t":3,"p":1,"n":"STCP - Sound"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]},{"t":6,"s":1,"p":1,"n":"Destructible","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"}]},{"t":7,"p":1,"n":"DAMC - Resistances","c":[{"t":6,"p":1,"n":"Resistance","c":[{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Value"}]}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":2,"p":1,"n":"DSTA - Sequence Name"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":5,"p":1,"n":"DMDC - Color Remapping Index"},{"t":3,"p":1,"n":"DMDS - Material Swap"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":7,"p":1,"n":"PRPS - Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":3,"p":1,"n":"Actor Value"},{"t":5,"p":1,"n":"Value"}]}]},{"t":3,"p":1,"n":"NTRM - Native Terminal"},{"t":3,"p":1,"n":"FTYP - Forced Loc Ref Type"},{"t":6,"s":1,"p":1,"n":"PNAM - Marker Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":3,"n":"Unused"}]},{"t":3,"p":1,"n":"SNAM - Sound - Looping"},{"t":3,"p":1,"n":"VNAM - Sound - Activation"},{"t":3,"p":1,"n":"WNAM - Water Type"},{"t":2,"p":1,"n":"ATTX - Activate Text Override"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":3,"p":1,"n":"KNAM - Interaction Keyword"},{"t":6,"s":1,"p":1,"n":"RADR - Radio Receiver","c":[{"t":3,"p":1,"n":"Sound Model"},{"t":5,"p":1,"n":"Frequency"},{"t":5,"p":1,"n":"Volume"},{"t":3,"p":1,"n":"Starts Active"},{"t":3,"p":1,"n":"No Signal Static"}]},{"t":3,"n":"CITC - Condition Count"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":6,"s":1,"p":1,"n":"NVNM - Navmesh Geometry","c":[{"t":3,"p":1,"n":"Version"},{"t":11,"p":1,"n":"Magic"},{"t":3,"p":1,"n":"Parent Worldspace"},{"t":6,"p":1,"n":"Coordinates","c":[{"t":3,"p":1,"n":"Grid Y"},{"t":3,"p":1,"n":"Grid X"}]},{"t":3,"p":1,"n":"Parent Cell"},{"t":11,"p":1,"n":"Vertices and Triangles"}]}]},{"t":1,"p":1,"n":"ADDN - Addon Node","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]},{"t":3,"p":1,"n":"DATA - Node Index"},{"t":3,"p":1,"n":"SNAM - Sound"},{"t":3,"p":1,"n":"LNAM - Light"},{"t":6,"s":1,"p":1,"n":"DNAM - Data","c":[{"t":3,"p":1,"n":"Master Particle System Cap"},{"t":3,"p":1,"n":"Flags"}]}]},{"t":1,"p":1,"n":"AECH - Audio Effect Chain","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":8,"s":1,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":3,"p":1,"n":"KNAM - Type"},{"t":6,"p":1,"n":"DNAM - Data","c":[{"t":3,"p":1,"n":"Enabled"},{"t":5,"p":1,"n":"Input Gain"},{"t":5,"p":1,"n":"Center Freq"},{"t":5,"p":1,"n":"Feedback %"},{"t":5,"p":1,"n":"Output Gain"},{"t":5,"p":1,"n":"Q Value"},{"t":5,"p":1,"n":"Wet Mix %"},{"t":5,"p":1,"n":"Upper Threshold"},{"t":3,"p":1,"n":"Filter Mode"},{"t":3,"p":1,"n":"Delay MS"},{"t":5,"p":1,"n":"Lower Threshold"},{"t":11,"n":"Unused"}]}]}]}]},{"t":1,"p":1,"n":"ALCH - Ingestible","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"PTRN - Preview Transform"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]},{"t":2,"p":1,"n":"ICON - Inventory Image"},{"t":2,"p":1,"n":"MICO - Message Icon"},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":3,"p":1,"n":"ETYP - Equipment Type"},{"t":3,"p":1,"n":"CUSD - Sound - Crafting"},{"t":6,"s":1,"p":1,"n":"Destructible","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"}]},{"t":7,"p":1,"n":"DAMC - Resistances","c":[{"t":6,"p":1,"n":"Resistance","c":[{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Value"}]}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":2,"p":1,"n":"DSTA - Sequence Name"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":5,"p":1,"n":"DMDC - Color Remapping Index"},{"t":3,"p":1,"n":"DMDS - Material Swap"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":2,"p":1,"n":"DESC - Description"},{"t":5,"p":1,"n":"DATA - Weight"},{"t":6,"s":1,"p":1,"n":"ENIT - Effect Data","c":[{"t":3,"p":1,"n":"Value"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Addiction"},{"t":5,"p":1,"n":"Addiction Chance"},{"t":3,"p":1,"n":"Sound - Consume"}]},{"t":2,"p":1,"n":"DNAM - Addiction Name"},{"t":8,"s":1,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":3,"p":1,"n":"EFID - Base Effect"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":5,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"}]},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]}]},{"t":1,"p":1,"n":"AMDL - Aim Model","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DNAM - Data","c":[{"t":5,"p":1,"n":"Cone of Fire - Min Angle"},{"t":5,"p":1,"n":"Cone of Fire - Max Angle"},{"t":5,"p":1,"n":"Cone of Fire - Increase Per Shot"},{"t":5,"p":1,"n":"Cone of Fire - Decrease Per Sec"},{"t":3,"p":1,"n":"Cone of Fire - Decrease Delay MS"},{"t":5,"p":1,"n":"Cone of Fire - Sneak Mult"},{"t":5,"p":1,"n":"Recoil - Diminish Spring Force"},{"t":5,"p":1,"n":"Recoil - Diminish Sights Mult"},{"t":5,"p":1,"n":"Recoil - Max Per Shot"},{"t":5,"p":1,"n":"Recoil - Min Per Shot"},{"t":5,"p":1,"n":"Recoil - Hip Mult"},{"t":3,"p":1,"n":"Runaway - Recoil Shots"},{"t":5,"p":1,"n":"Recoil - Arc"},{"t":5,"p":1,"n":"Recoil - Arc Rotate"},{"t":5,"p":1,"n":"Cone of Fire - Iron Sights Mult"},{"t":5,"p":1,"n":"Stability - Base Stability"}]}]},{"t":1,"p":1,"n":"AMMO - Ammunition","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"PTRN - Preview Transform"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]},{"t":6,"s":1,"p":1,"n":"Destructible","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"}]},{"t":7,"p":1,"n":"DAMC - Resistances","c":[{"t":6,"p":1,"n":"Resistance","c":[{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Value"}]}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":2,"p":1,"n":"DSTA - Sequence Name"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":5,"p":1,"n":"DMDC - Color Remapping Index"},{"t":3,"p":1,"n":"DMDS - Material Swap"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":2,"p":1,"n":"DESC - Description"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":6,"s":1,"p":1,"n":"DNAM - ","c":[{"t":3,"p":1,"n":"Projectile"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Damage"},{"t":3,"p":1,"n":"Health"}]},{"t":2,"p":1,"n":"ONAM - Short Name"},{"t":2,"p":1,"n":"NAM1 - Casing Model"},{"t":11,"n":"NAM2 - Texture Files Hashes"}]},{"t":1,"p":1,"n":"ANIO - Animated Object","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]},{"t":2,"p":1,"n":"BNAM - Unload Event"}]},{"t":1,"p":1,"n":"AORU - Attraction Rule","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"AOR2 - Data","c":[{"t":5,"p":1,"n":"Radius"},{"t":5,"p":1,"n":"Min Delay"},{"t":5,"p":1,"n":"Max Delay"},{"t":3,"p":1,"n":"Requires Line of Sight"},{"t":3,"p":1,"n":"Combat Target"},{"t":11,"n":"Unused"}]}]},{"t":1,"p":1,"n":"ARMA - Armor Addon","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"BOD2 - Biped Body Template","c":[{"t":3,"p":1,"n":"First Person Flags"}]},{"t":3,"p":1,"n":"RNAM - Race"},{"t":6,"s":1,"p":1,"n":"DNAM - Data","c":[{"t":3,"p":1,"n":"Male Priority"},{"t":3,"p":1,"n":"Female Priority"},{"t":3,"p":1,"n":"Weight slider - Male"},{"t":3,"p":1,"n":"Weight slider - Female"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Detection Sound Value"},{"t":5,"p":1,"n":"Weapon Adjust"}]},{"t":6,"s":1,"p":1,"n":"Male world model","c":[{"t":2,"p":1,"n":"MOD2 - Model Filename"},{"t":11,"p":1,"n":"MO2T - Texture Files Hashes"},{"t":3,"p":1,"n":"MO2S - Material Swap"},{"t":5,"p":1,"n":"MO2C - Color Remapping Index"},{"t":11,"n":"MO2F - Unknown"}]},{"t":6,"s":1,"p":1,"n":"Female world model","c":[{"t":2,"p":1,"n":"MOD3 - Model Filename"},{"t":11,"p":1,"n":"MO3T - Texture Files Hashes"},{"t":3,"p":1,"n":"MO3S - Material Swap"},{"t":5,"p":1,"n":"MO3C - Color Remapping Index"},{"t":11,"n":"MO3F - Unknown"}]},{"t":6,"s":1,"p":1,"n":"Male 1st Person","c":[{"t":2,"p":1,"n":"MOD4 - Model Filename"},{"t":11,"p":1,"n":"MO4T - Texture Files Hashes"},{"t":3,"p":1,"n":"MO4S - Material Swap"},{"t":5,"p":1,"n":"MO4C - Color Remapping Index"},{"t":11,"n":"MO4F - Unknown"}]},{"t":6,"s":1,"p":1,"n":"Female 1st Person","c":[{"t":2,"p":1,"n":"MOD5 - Model Filename"},{"t":11,"p":1,"n":"MO5T - Texture Files Hashes"},{"t":3,"p":1,"n":"MO5S - Material Swap"},{"t":5,"p":1,"n":"MO5C - Color Remapping Index"},{"t":11,"n":"MO5F - Unknown"}]},{"t":3,"p":1,"n":"NAM0 - Male Skin Texture"},{"t":3,"p":1,"n":"NAM1 - Female Skin Texture"},{"t":3,"p":1,"n":"NAM2 - Male Skin Texture Swap List"},{"t":3,"p":1,"n":"NAM3 - Female Skin Texture Swap List"},{"t":8,"s":1,"p":1,"n":"Additional Races","d":1,"c":[{"t":3,"p":1,"n":"MODL - Race"}]},{"t":3,"p":1,"n":"SNDD - Footstep Sound"},{"t":3,"p":1,"n":"ONAM - Art Object"},{"t":8,"s":1,"p":1,"n":"Bone Data","d":1,"c":[{"t":6,"p":1,"n":"Data","c":[{"t":3,"p":1,"n":"BSMP - Gender"},{"t":8,"p":1,"n":"Bones","c":[{"t":6,"p":1,"n":"Bone","c":[{"t":2,"p":1,"n":"BSMB - Name"},{"t":7,"p":1,"n":"BSMS - Values","c":[{"t":5,"p":1,"n":"Value"}]},{"t":11,"n":"BMMP - Unknown"}]}]}]}]}]},{"t":1,"p":1,"n":"ARMO - Armor","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"PTRN - Preview Transform"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"EITM - Object Effect"},{"t":6,"s":1,"p":1,"n":"Male world model","c":[{"t":2,"p":1,"n":"MOD2 - Model Filename"},{"t":11,"p":1,"n":"MO2T - Texture Files Hashes"},{"t":3,"p":1,"n":"MO2S - Material Swap"}]},{"t":2,"p":1,"n":"ICON - Male Inventory Image"},{"t":2,"p":1,"n":"MICO - Male Message Icon"},{"t":6,"s":1,"p":1,"n":"Female world model","c":[{"t":2,"p":1,"n":"MOD4 - Model Filename"},{"t":11,"p":1,"n":"MO4T - Texture Files Hashes"},{"t":3,"p":1,"n":"MO4S - Material Swap"}]},{"t":2,"p":1,"n":"ICO2 - Female Inventory Image"},{"t":2,"p":1,"n":"MIC2 - Female Message Icon"},{"t":6,"s":1,"p":1,"n":"BOD2 - Biped Body Template","c":[{"t":3,"p":1,"n":"First Person Flags"}]},{"t":6,"s":1,"p":1,"n":"Destructible","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"}]},{"t":7,"p":1,"n":"DAMC - Resistances","c":[{"t":6,"p":1,"n":"Resistance","c":[{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Value"}]}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":2,"p":1,"n":"DSTA - Sequence Name"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":5,"p":1,"n":"DMDC - Color Remapping Index"},{"t":3,"p":1,"n":"DMDS - Material Swap"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":3,"p":1,"n":"ETYP - Equipment Type"},{"t":3,"p":1,"n":"BIDS - Block Bash Impact Data Set"},{"t":3,"p":1,"n":"BAMT - Alternate Block Material"},{"t":3,"p":1,"n":"RNAM - Race"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":2,"p":1,"n":"DESC - Description"},{"t":3,"p":1,"n":"INRD - Instance Naming"},{"t":8,"s":1,"p":1,"n":"Models","d":1,"c":[{"t":6,"p":1,"n":"Model","c":[{"t":3,"p":1,"n":"INDX - Addon Index"},{"t":3,"p":1,"n":"MODL - Armor Addon"}]}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"},{"t":3,"p":1,"n":"Health"}]},{"t":6,"s":1,"p":1,"n":"FNAM - ","c":[{"t":3,"p":1,"n":"Armor Rating"},{"t":3,"p":1,"n":"Base Addon Index"},{"t":3,"p":1,"n":"Stagger Rating"},{"t":11,"n":"Unknown"}]},{"t":7,"p":1,"n":"DAMA - Resistances","c":[{"t":6,"p":1,"n":"Resistance","c":[{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Value"}]}]},{"t":3,"p":1,"n":"TNAM - Template Armor"},{"t":7,"p":1,"n":"APPR - Attach Parent Slots","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"Object Template","c":[{"t":3,"p":1,"n":"OBTE - Count"},{"t":8,"p":1,"n":"Combinations","c":[{"t":6,"p":1,"n":"Combination","c":[{"p":1,"n":"OBTF - Editor Only"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"p":1,"n":"OBTS - Object Mod Template Item","c":[{"t":3,"p":1,"n":"Include Count"},{"t":3,"p":1,"n":"Property Count"},{"t":3,"p":1,"n":"Level Min"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Level Max"},{"t":3,"p":1,"n":"ID"},{"t":3,"p":1,"n":"Default"},{"t":7,"p":1,"n":"Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":3,"p":1,"n":"Min Level For Ranks"},{"t":3,"p":1,"n":"Alt Levels Per Tier"},{"t":7,"p":1,"n":"Includes","c":[{"t":6,"p":1,"n":"Include","c":[{"t":3,"p":1,"n":"Mod"},{"t":3,"p":1,"n":"Attach Point Index"},{"t":3,"p":1,"n":"Optional"},{"t":3,"p":1,"n":"Don't Use All"}]}]},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":3,"p":1,"n":"Value Type"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Function Type"},{"t":3,"p":1,"n":"Property"},{"t":11,"n":"Value 1 - Unknown"},{"t":3,"p":1,"n":"Value 1 - Int"},{"t":5,"p":1,"n":"Value 1 - Float"},{"t":3,"p":1,"n":"Value 1 - Bool"},{"t":3,"p":1,"n":"Value 1 - FormID"},{"t":3,"p":1,"n":"Value 1 - Enum"},{"t":3,"p":1,"n":"Sound Level"},{"t":3,"p":1,"n":"Stagger Value"},{"t":3,"p":1,"n":"Hit Behaviour"},{"t":3,"p":1,"n":"Value 2 - Int"},{"t":5,"p":1,"n":"Value 2 - Float"},{"t":3,"p":1,"n":"Value 2 - Bool"},{"t":5,"p":1,"n":"Step"}]}]}]}]}]},{"p":1,"n":"STOP - Marker"}]}]},{"t":1,"p":1,"n":"ARTO - Art Object","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"PTRN - Preview Transform"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]},{"t":3,"p":1,"n":"DNAM - Art Type"}]},{"t":1,"p":1,"n":"ASPC - Acoustic Space","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"SNAM - Looping Sound"},{"t":3,"p":1,"n":"RDAT - Use Sound from Region (Interiors Only)"},{"t":3,"p":1,"n":"BNAM - Environment Type"},{"t":3,"p":1,"n":"XTRI - Is Interior"},{"t":3,"p":1,"n":"WNAM - Weather Attenuation (dB)"}]},{"t":1,"p":1,"n":"ASTP - Association Type","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"MPRT - Male Parent Title"},{"t":2,"p":1,"n":"FPRT - Female Parent Title"},{"t":2,"p":1,"n":"MCHT - Male Child Title"},{"t":2,"p":1,"n":"FCHT - Female Child Title"},{"t":3,"p":1,"n":"DATA - Flags"}]},{"t":1,"p":1,"n":"AVIF - Actor Value Information","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"DESC - Description"},{"t":2,"p":1,"n":"ANAM - Abbreviation"},{"t":5,"p":1,"n":"NAM0 - Default Value"},{"t":3,"p":1,"n":"AVFL - Flags"},{"t":3,"p":1,"n":"NAM1 - Type"}]},{"t":1,"p":1,"n":"BNDS - Bendable Spline","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"DNAM - Data","c":[{"t":5,"p":1,"n":"Default Number of Tiles"},{"t":3,"p":1,"n":"Default Number of Slices"},{"t":3,"p":1,"n":"Default Number of Tiles - Relative to Length"},{"t":6,"p":1,"n":"Default Color","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}]},{"t":5,"p":1,"n":"Wind Settings - Sensibility"},{"t":5,"p":1,"n":"Wind Settings - Flexibility"}]},{"t":3,"p":1,"n":"TNAM - Texture"}]},{"t":1,"p":1,"n":"BOOK - Book","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"PTRN - Preview Transform"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]},{"t":2,"p":1,"n":"ICON - Inventory Image"},{"t":2,"p":1,"n":"MICO - Message Icon"},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"Destructible","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"}]},{"t":7,"p":1,"n":"DAMC - Resistances","c":[{"t":6,"p":1,"n":"Resistance","c":[{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Value"}]}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":2,"p":1,"n":"DSTA - Sequence Name"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":5,"p":1,"n":"DMDC - Color Remapping Index"},{"t":3,"p":1,"n":"DMDS - Material Swap"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":3,"p":1,"n":"FIMD - Featured Item Message"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":6,"s":1,"p":1,"n":"DNAM - ","c":[{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Spell"},{"t":3,"p":1,"n":"Perk"},{"t":6,"p":1,"n":"Text Offset","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"}]}]},{"t":2,"p":1,"n":"CNAM - Description"},{"t":3,"p":1,"n":"INAM - Inventory Art"}]},{"t":1,"p":1,"n":"BPTD - Body Part Data","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]},{"t":10,"p":1,"n":"Body Parts","d":1,"c":[{"t":6,"p":1,"n":"Body Part","c":[{"t":2,"p":1,"n":"BPTN - Part Name"},{"t":2,"p":1,"n":"BPNN - Part Node"},{"t":2,"p":1,"n":"BPNT - VATS Target"},{"t":6,"p":1,"n":"BPND - ","c":[{"t":5,"p":1,"n":"Damage Mult"},{"t":3,"p":1,"n":"Explodable - Debris"},{"t":3,"p":1,"n":"Explodable - Explosion"},{"t":5,"p":1,"n":"Explodable - Debris Scale"},{"t":3,"p":1,"n":"Severable - Debris"},{"t":3,"p":1,"n":"Severable - Explosion"},{"t":5,"p":1,"n":"Severable - Debris Scale"},{"t":5,"p":1,"n":"Cut - Min"},{"t":5,"p":1,"n":"Cut - Max"},{"t":5,"p":1,"n":"Cut - Radius"},{"t":5,"p":1,"n":"Gore Effects - Local Rotate X"},{"t":5,"p":1,"n":"Gore Effects - Local Rotate Y"},{"t":5,"p":1,"n":"Cut - Tesselation"},{"t":3,"p":1,"n":"Severable - Impact DataSet"},{"t":3,"p":1,"n":"Explodable - Impact DataSet"},{"t":5,"p":1,"n":"Explodable - Limb Replacement Scale"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Part Type"},{"t":3,"p":1,"n":"Health Percent"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"To Hit Chance"},{"t":3,"p":1,"n":"Explodable - Explosion Chance %"},{"t":3,"p":1,"n":"Non-Lethal Dismemberment Chance"},{"t":3,"p":1,"n":"Severable - Debris Count"},{"t":3,"p":1,"n":"Explodable - Debris Count"},{"t":3,"p":1,"n":"Severable - Decal Count"},{"t":3,"p":1,"n":"Explodable - Decal Count"},{"t":3,"p":1,"n":"Geometry Segment Index"},{"t":3,"p":1,"n":"On Cripple - Art Object"},{"t":3,"p":1,"n":"On Cripple - Debris"},{"t":3,"p":1,"n":"On Cripple - Explosion"},{"t":3,"p":1,"n":"On Cripple - Impact DataSet"},{"t":5,"p":1,"n":"On Cripple - Debris Scale"},{"t":3,"p":1,"n":"On Cripple - Debris Count"},{"t":3,"p":1,"n":"On Cripple - Decal Count"}]},{"t":2,"p":1,"n":"NAM1 - Limb Replacement Model"},{"t":2,"p":1,"n":"NAM4 - Gore Effects - Target Bone"},{"t":11,"p":1,"n":"NAM5 - Texture Files Hashes"},{"t":2,"p":1,"n":"ENAM - Hit Reaction - Start"},{"t":2,"p":1,"n":"FNAM - Hit Reaction - End"},{"t":3,"p":1,"n":"BNAM - Gore Effects - Dismember Blood Art"},{"t":3,"p":1,"n":"INAM - Gore Effects - Blood Impact Material Type"},{"t":3,"p":1,"n":"JNAM - On Cripple - Blood Impact Material Type"},{"t":3,"p":1,"n":"CNAM - Meat Cap TextureSet"},{"t":3,"p":1,"n":"NAM2 - Collar TextureSet"},{"t":2,"p":1,"n":"DNAM - Twist Variable Prefix"}]}]}]},{"t":1,"p":1,"n":"CAMS - Camera Shot","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Action"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Flags"},{"t":6,"p":1,"n":"Time Multipliers","c":[{"t":5,"p":1,"n":"Player"},{"t":5,"p":1,"n":"Target"},{"t":5,"p":1,"n":"Global"}]},{"t":5,"p":1,"n":"Max Time"},{"t":5,"p":1,"n":"Min Time"},{"t":5,"p":1,"n":"Target % Between Actors"},{"t":5,"p":1,"n":"Near Target Distance"},{"t":5,"p":1,"n":"Location Spring"},{"t":5,"p":1,"n":"Target Spring"},{"t":6,"p":1,"n":"Rotation Offset","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]},{"t":3,"p":1,"n":"MNAM - Image Space Modifier"}]},{"t":1,"p":1,"n":"CELL - Cell","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"DATA - Flags"},{"t":6,"s":1,"p":1,"n":"XCLC - Grid","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"},{"t":3,"p":1,"n":"Force Hide Land"}]},{"t":11,"n":"VISI - PreVis Files Timestamp"},{"t":3,"p":1,"n":"RVIS - In PreVis File Of"},{"t":11,"n":"PCMB - PreCombined Files Timestamp"},{"t":6,"s":1,"p":1,"n":"XCLL - Lighting","c":[{"t":6,"p":1,"n":"Ambient Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Directional Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Fog Color Near","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Fog Near"},{"t":5,"p":1,"n":"Fog Far"},{"t":3,"p":1,"n":"Directional Rotation XY"},{"t":3,"p":1,"n":"Directional Rotation Z"},{"t":5,"p":1,"n":"Directional Fade"},{"t":5,"p":1,"n":"Fog Clip Distance"},{"t":5,"p":1,"n":"Fog Power"},{"t":6,"p":1,"n":"Directional Ambient Lighting Colors","c":[{"t":6,"p":1,"n":"Directional","c":[{"t":6,"p":1,"n":"X+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"X-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Specular","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Scale"}]},{"t":6,"p":1,"n":"Fog Color Far","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Fog Max"},{"t":5,"p":1,"n":"Light Fade Begin"},{"t":5,"p":1,"n":"Light Fade End"},{"t":3,"p":1,"n":"Inherits"},{"t":5,"p":1,"n":"Near Height Mid"},{"t":5,"p":1,"n":"Near Height Range"},{"t":6,"p":1,"n":"Fog Color High Near","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Fog Color High Far","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"High Density Scale"},{"t":5,"p":1,"n":"Fog Near Scale"},{"t":5,"p":1,"n":"Fog Far Scale"},{"t":5,"p":1,"n":"Fog High Near Scale"},{"t":5,"p":1,"n":"Fog High Far Scale"},{"t":5,"p":1,"n":"Far Height Mid"},{"t":5,"p":1,"n":"Far Height Range"}]},{"t":3,"p":1,"n":"CNAM - Precombined Object Level XY"},{"t":3,"p":1,"n":"ZNAM - Precombined Object Level Z"},{"t":11,"n":"TVDT - Unknown"},{"t":11,"n":"MHDT - Max Height Data"},{"t":3,"p":1,"n":"LTMP - Lighting Template"},{"t":5,"p":1,"n":"XCLW - Water Height"},{"t":7,"p":1,"n":"XCLR - Regions","c":[{"t":3,"p":1,"n":"Region"}]},{"t":3,"p":1,"n":"XLCN - Location"},{"t":11,"n":"XWCN - Unknown"},{"t":6,"s":1,"p":1,"n":"XWCU - Water Velocity","c":[{"t":5,"p":1,"n":"X Offset"},{"t":5,"p":1,"n":"Y Offset"},{"t":5,"p":1,"n":"Z Offset"},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"X Angle"},{"t":5,"p":1,"n":"Y Angle"},{"t":5,"p":1,"n":"Z Angle"}]},{"t":3,"p":1,"n":"XCWT - Water"},{"t":6,"s":1,"p":1,"n":"XOWN - Owner","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Flags"}]},{"t":3,"p":1,"n":"XRNK - Owner Faction Rank"},{"t":3,"p":1,"n":"XILL - Lock List"},{"t":6,"s":1,"p":1,"n":"XILW - Exterior LOD","c":[{"t":3,"p":1,"n":"Worldspace"},{"t":5,"p":1,"n":"Offset X"},{"t":5,"p":1,"n":"Offset Y"},{"t":5,"p":1,"n":"Offset Z"}]},{"t":2,"p":1,"n":"XWEM - Water Environment Map"},{"t":3,"p":1,"n":"XCCM - Sky\/Weather from Region"},{"t":3,"p":1,"n":"XCAS - Acoustic Space"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":3,"p":1,"n":"XCMO - Music Type"},{"t":3,"p":1,"n":"XCIM - Image Space"},{"t":3,"p":1,"n":"XGDR - God Rays"},{"t":7,"p":1,"n":"XPRI - Physics References","c":[{"t":3,"p":1,"n":"Reference"}]},{"t":6,"s":1,"p":1,"n":"XCRI - Combined References","c":[{"t":3,"p":1,"n":"Meshes Count"},{"t":3,"p":1,"n":"References Count"},{"t":7,"p":1,"n":"Meshes","c":[{"t":3,"p":1,"n":"Combined Mesh"}]},{"t":7,"p":1,"n":"References","c":[{"t":6,"p":1,"n":"Reference","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Combined Mesh"}]}]}]}]},{"t":1,"p":1,"n":"CLAS - Class","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"DESC - Description"},{"t":2,"p":1,"n":"ICON - Inventory Image"},{"t":7,"p":1,"n":"PRPS - Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":3,"p":1,"n":"Actor Value"},{"t":5,"p":1,"n":"Value"}]}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"Bleedout Default"}]}]},{"t":1,"p":1,"n":"CLFM - Color","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"CNAM - Color\/Index"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]},{"t":1,"p":1,"n":"CLMT - Climate","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":7,"p":1,"n":"WLST - Weather Types","c":[{"t":6,"p":1,"n":"Weather Type","c":[{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Chance"},{"t":3,"p":1,"n":"Global"}]}]},{"t":2,"p":1,"n":"FNAM - Sun Texture"},{"t":2,"p":1,"n":"GNAM - Sun Glare Texture"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]},{"t":6,"s":1,"p":1,"n":"TNAM - Timing","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Begin"},{"t":3,"p":1,"n":"End"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Begin"},{"t":3,"p":1,"n":"End"}]},{"t":3,"p":1,"n":"Volatility"},{"t":3,"p":1,"n":"Moons \/ Phase Length"}]}]},{"t":1,"p":1,"n":"CMPO - Component","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"CUSD - Sound - Crafting"},{"t":3,"p":1,"n":"DATA - Auto Calc Value"},{"t":3,"p":1,"n":"MNAM - Scrap Item"},{"t":3,"p":1,"n":"GNAM - Mod Scrap Scalar"}]},{"t":1,"p":1,"n":"COBJ - Constructible Object","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":7,"p":1,"n":"FVPA - Components","c":[{"t":6,"p":1,"n":"Component","c":[{"t":3,"p":1,"n":"Component"},{"t":3,"p":1,"n":"Count"}]}]},{"t":2,"p":1,"n":"DESC - Description"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":3,"p":1,"n":"CNAM - Created Object"},{"t":3,"p":1,"n":"BNAM - Workbench Keyword"},{"t":11,"n":"NAM1 - Unused"},{"t":11,"n":"NAM2 - Unused"},{"t":11,"n":"NAM3 - Unused"},{"t":3,"p":1,"n":"ANAM - Menu Art Object"},{"t":7,"p":1,"n":"FNAM - Category","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"INTV - Data","c":[{"t":3,"p":1,"n":"Created Object Count"},{"t":3,"p":1,"n":"Priority"}]}]},{"t":1,"p":1,"n":"COLL - Collision Layer","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"DESC - Description"},{"t":3,"p":1,"n":"BNAM - Index"},{"t":6,"s":1,"p":1,"n":"FNAM - Debug Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":3,"n":"Unused"}]},{"t":3,"p":1,"n":"GNAM - Flags"},{"t":2,"p":1,"n":"MNAM - Name"},{"t":3,"n":"INTV - Interactables Count"},{"t":7,"p":1,"n":"CNAM - Collides With","c":[{"t":3,"p":1,"n":"Forms"}]}]},{"t":1,"p":1,"n":"CONT - Container","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"PTRN - Preview Transform"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]},{"t":3,"n":"COCT - Count"},{"t":10,"p":1,"n":"Items","d":1,"c":[{"t":6,"p":1,"n":"Item","c":[{"t":6,"p":1,"n":"CNTO - Item","c":[{"t":3,"p":1,"n":"Item"},{"t":3,"p":1,"n":"Count"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructible","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"}]},{"t":7,"p":1,"n":"DAMC - Resistances","c":[{"t":6,"p":1,"n":"Resistance","c":[{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Value"}]}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":2,"p":1,"n":"DSTA - Sequence Name"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":5,"p":1,"n":"DMDC - Color Remapping Index"},{"t":3,"p":1,"n":"DMDS - Material Swap"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Weight"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":3,"p":1,"n":"FTYP - Forced Loc Ref Type"},{"t":7,"p":1,"n":"PRPS - Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":3,"p":1,"n":"Actor Value"},{"t":5,"p":1,"n":"Value"}]}]},{"t":3,"p":1,"n":"NTRM - Native Terminal"},{"t":3,"p":1,"n":"SNAM - Sound - Open"},{"t":3,"p":1,"n":"QNAM - Sound - Close"},{"t":3,"p":1,"n":"TNAM - Sound - Take All"},{"t":3,"p":1,"n":"ONAM - Filter List"}]},{"t":1,"p":1,"n":"CPTH - Camera Path","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":7,"p":1,"n":"ANAM - Related Camera Paths","c":[{"t":3,"p":1,"n":"Related Camera Path"}]},{"t":3,"p":1,"n":"DATA - Camera Zoom \/ Flags"},{"t":8,"s":1,"p":1,"n":"Camera Shots","d":1,"c":[{"t":3,"p":1,"n":"SNAM - Camera Shot"}]}]},{"t":1,"p":1,"n":"CSTY - Combat Style","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"CSGD - General","c":[{"t":5,"p":1,"n":"Offensive Mult"},{"t":5,"p":1,"n":"Defensive Mult"},{"t":5,"p":1,"n":"Group Offensive Mult"},{"t":5,"p":1,"n":"Equipment Score Mult - Melee"},{"t":5,"p":1,"n":"Equipment Score Mult - Magic"},{"t":5,"p":1,"n":"Equipment Score Mult - Ranged"},{"t":5,"p":1,"n":"Equipment Score Mult - Shout"},{"t":5,"p":1,"n":"Equipment Score Mult - Unarmed"},{"t":5,"p":1,"n":"Equipment Score Mult - Staff"},{"t":5,"p":1,"n":"Avoid Threat Chance"},{"t":5,"p":1,"n":"Dodge Threat Chance"},{"t":5,"p":1,"n":"Evade Threat Chance"}]},{"t":11,"n":"CSMD - Unknown"},{"t":6,"s":1,"p":1,"n":"CSME - Melee","c":[{"t":5,"p":1,"n":"Attack Staggered Mult"},{"t":5,"p":1,"n":"Power Attack Staggered Mult"},{"t":5,"p":1,"n":"Power Attack Blocking Mult"},{"t":5,"p":1,"n":"Bash Mult"},{"t":5,"p":1,"n":"Bash Recoil Mult"},{"t":5,"p":1,"n":"Bash Attack Mult"},{"t":5,"p":1,"n":"Bash Power Attack Mult"},{"t":5,"p":1,"n":"Special Attack Mult"},{"t":5,"p":1,"n":"Block When Staggered Mult"},{"t":5,"p":1,"n":"Attack When Staggered Mult"}]},{"t":5,"p":1,"n":"CSRA - Ranged Accuracy Mult"},{"t":6,"s":1,"p":1,"n":"CSCR - Close Range","c":[{"t":5,"p":1,"n":"Dueling - Circle Mult"},{"t":5,"p":1,"n":"Dueling - Fallback Mult"},{"t":5,"p":1,"n":"Flanking - Flank Distance"},{"t":5,"p":1,"n":"Flanking - Stalk Time"},{"t":5,"p":1,"n":"Charging - Charge Distance"},{"t":5,"p":1,"n":"Charging - Throw Probability"},{"t":5,"p":1,"n":"Charging - Sprint Fast Probability"},{"t":5,"p":1,"n":"Charging - Sideswipe Probability"},{"t":5,"p":1,"n":"Charging - Disengane Probability"},{"t":3,"p":1,"n":"Charging - Throw Max Targets"},{"t":5,"p":1,"n":"Flanking - Flank Variance"}]},{"t":6,"s":1,"p":1,"n":"CSLR - Long Range","c":[{"t":5,"p":1,"n":"Strafe Mult"},{"t":5,"p":1,"n":"Adjust Range Mult"},{"t":5,"p":1,"n":"Crouch Mult"},{"t":5,"p":1,"n":"Wait Mult"},{"t":5,"p":1,"n":"Range Mult"}]},{"t":5,"p":1,"n":"CSCV - Cover Search Distance Mult"},{"t":6,"s":1,"p":1,"n":"CSFL - Flight","c":[{"t":5,"p":1,"n":"Hover Chance"},{"t":5,"p":1,"n":"Dive Bomb Chance"},{"t":5,"p":1,"n":"Ground Attack Chance"},{"t":5,"p":1,"n":"Hover Time"},{"t":5,"p":1,"n":"Ground Attack Time"},{"t":5,"p":1,"n":"Perch Attack Chance"},{"t":5,"p":1,"n":"Perch Attack Time"},{"t":5,"p":1,"n":"Flying Attack Chance"}]},{"t":3,"p":1,"n":"DATA - Flags"}]},{"t":1,"p":1,"n":"DEBR - Debris","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":8,"s":1,"p":1,"n":"Models","d":1,"c":[{"t":6,"p":1,"n":"Model","c":[{"t":6,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Percentage"},{"t":2,"p":1,"n":"Model Filename"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]}]}]},{"t":1,"p":1,"n":"DFOB - Default Object","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"DATA - Object"}]},{"t":1,"p":1,"n":"DIAL - Dialog Topic","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":5,"p":1,"n":"PNAM - Priority"},{"t":3,"p":1,"n":"BNAM - Branch"},{"t":3,"p":1,"n":"QNAM - Quest"},{"t":3,"p":1,"n":"KNAM - Keyword"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Topic Flags"},{"t":3,"p":1,"n":"Category"},{"t":3,"p":1,"n":"Subtype"}]},{"t":2,"p":1,"n":"SNAM - Subtype Name"},{"t":3,"p":1,"n":"TIFC - Info Count"}]},{"t":1,"p":1,"n":"DLBR - Dialog Branch","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"QNAM - Quest"},{"t":3,"n":"TNAM - Unknown"},{"t":3,"p":1,"n":"DNAM - Flags"},{"t":3,"p":1,"n":"SNAM - Starting Topic"}]},{"t":1,"p":1,"n":"DLVW - Dialog View","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"QNAM - Quest"},{"t":8,"s":1,"p":1,"n":"Branches","d":1,"c":[{"t":3,"p":1,"n":"BNAM - Branch"}]},{"t":8,"n":"Unknown TNAM","c":[{"t":6,"n":"Unknown","c":[{"t":11,"n":"TNAM - Unknown"}]}]},{"t":11,"n":"ENAM - Unknown"},{"t":11,"n":"DNAM - Unknown"}]},{"t":1,"p":1,"n":"DMGT - Damage Type","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":7,"p":1,"n":"Damage Types","c":[{"t":3,"p":1,"n":"Actor Value Index"}]}]},{"t":1,"n":"DOBJ - Default Object Manager","c":[{"t":2,"n":"EDID - Editor ID"},{"t":7,"n":"DNAM - Objects","c":[{"t":6,"n":"Object","c":[{"t":3,"n":"Use"},{"t":3,"n":"Object ID"}]}]}]},{"t":1,"p":1,"n":"DOOR - Door","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"PTRN - Preview Transform"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]},{"t":6,"s":1,"p":1,"n":"Destructible","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"}]},{"t":7,"p":1,"n":"DAMC - Resistances","c":[{"t":6,"p":1,"n":"Resistance","c":[{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Value"}]}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":2,"p":1,"n":"DSTA - Sequence Name"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":5,"p":1,"n":"DMDC - Color Remapping Index"},{"t":3,"p":1,"n":"DMDS - Material Swap"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":3,"p":1,"n":"NTRM - Native Terminal"},{"t":3,"p":1,"n":"SNAM - Sound - Open"},{"t":3,"p":1,"n":"ANAM - Sound - Close"},{"t":3,"p":1,"n":"BNAM - Sound - Loop"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":2,"p":1,"n":"ONAM - Alternate Text - Open"},{"t":2,"p":1,"n":"CNAM - Alternate Text - Close"}]},{"t":1,"p":1,"n":"DUAL - Dual Cast Data","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"}]},{"t":1,"p":1,"n":"ECZN - Encounter Zone","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Rank"},{"t":3,"p":1,"n":"Min Level"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Max Level"}]}]},{"t":1,"p":1,"n":"EFSH - Effect Shader","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"ICON - Fill Texture"},{"t":2,"p":1,"n":"ICO2 - Particle Shader Texture"},{"t":2,"p":1,"n":"NAM7 - Holes Texture"},{"t":2,"p":1,"n":"NAM8 - Membrane Palette Texture"},{"t":2,"p":1,"n":"NAM9 - Particle Palette Texture"},{"t":11,"n":"DATA - Unknown"},{"t":6,"s":1,"p":1,"n":"Data","c":[{"t":3,"p":1,"n":"Membrane Shader - Source Blend Mode"},{"t":3,"p":1,"n":"Membrane Shader - Blend Operation"},{"t":3,"p":1,"n":"Membrane Shader - Z Test Function"},{"t":6,"p":1,"n":"Fill\/Texture Effect - Color Key 1","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Fade In Time"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Full Alpha Time"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Fade Out Time"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Presistent Alpha Ratio"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Pulse Amplitude"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Pulse Frequency"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Animation Speed (U)"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Animation Speed (V)"},{"t":5,"p":1,"n":"Edge Effect - Fall Off"},{"t":6,"p":1,"n":"Edge Effect - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Edge Effect - Alpha Fade In Time"},{"t":5,"p":1,"n":"Edge Effect - Full Alpha Time"},{"t":5,"p":1,"n":"Edge Effect - Alpha Fade Out Time"},{"t":5,"p":1,"n":"Edge Effect - Persistent Alpha Ratio"},{"t":5,"p":1,"n":"Edge Effect - Alpha Pulse Amplitude"},{"t":5,"p":1,"n":"Edge Effect - Alpha Pulse Frequency"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Full Alpha Ratio"},{"t":5,"p":1,"n":"Edge Effect - Full Alpha Ratio"},{"t":3,"p":1,"n":"Membrane Shader - Dest Blend Mode"},{"t":5,"p":1,"n":"Holes Animation - Start Time"},{"t":5,"p":1,"n":"Holes Animation - End Time"},{"t":5,"p":1,"n":"Holes Animation - Start Value"},{"t":5,"p":1,"n":"Holes Animation - End Value"},{"t":3,"p":1,"n":"Ambient Sound"},{"t":6,"p":1,"n":"Fill\/Texture Effect - Color Key 2","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Fill\/Texture Effect - Color Key 3","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":3,"n":"Unknown"},{"t":6,"p":1,"n":"Fill\/Texture Effect - Color Key Scale\/Time","c":[{"t":5,"p":1,"n":"Color Key 1 - Scale"},{"t":5,"p":1,"n":"Color Key 2 - Scale"},{"t":5,"p":1,"n":"Color Key 3 - Scale"},{"t":5,"p":1,"n":"Color Key 1 - Time"},{"t":5,"p":1,"n":"Color Key 2 - Time"},{"t":5,"p":1,"n":"Color Key 3 - Time"}]},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Scale (U)"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Scale (V)"}]},{"t":6,"s":1,"p":1,"n":"Data (old format)","c":[{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Membrane Shader - Source Blend Mode"},{"t":3,"p":1,"n":"Membrane Shader - Blend Operation"},{"t":3,"p":1,"n":"Membrane Shader - Z Test Function"},{"t":6,"p":1,"n":"Fill\/Texture Effect - Color Key 1","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Fade In Time"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Full Alpha Time"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Fade Out Time"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Presistent Alpha Ratio"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Pulse Amplitude"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Pulse Frequency"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Animation Speed (U)"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Animation Speed (V)"},{"t":5,"p":1,"n":"Edge Effect - Fall Off"},{"t":6,"p":1,"n":"Edge Effect - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Edge Effect - Alpha Fade In Time"},{"t":5,"p":1,"n":"Edge Effect - Full Alpha Time"},{"t":5,"p":1,"n":"Edge Effect - Alpha Fade Out Time"},{"t":5,"p":1,"n":"Edge Effect - Persistent Alpha Ratio"},{"t":5,"p":1,"n":"Edge Effect - Alpha Pulse Amplitude"},{"t":5,"p":1,"n":"Edge Effect - Alpha Pulse Frequency"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Full Alpha Ratio"},{"t":5,"p":1,"n":"Edge Effect - Full Alpha Ratio"},{"t":3,"p":1,"n":"Membrane Shader - Dest Blend Mode"},{"t":3,"p":1,"n":"Particle Shader - Source Blend Mode"},{"t":3,"p":1,"n":"Particle Shader - Blend Operation"},{"t":3,"p":1,"n":"Particle Shader - Z Test Function"},{"t":3,"p":1,"n":"Particle Shader - Dest Blend Mode"},{"t":5,"p":1,"n":"Particle Shader - Particle Birth Ramp Up Time"},{"t":5,"p":1,"n":"Particle Shader - Full Particle Birth Time"},{"t":5,"p":1,"n":"Particle Shader - Particle Birth Ramp Down Time"},{"t":5,"p":1,"n":"Particle Shader - Full Particle Birth Ratio"},{"t":5,"p":1,"n":"Particle Shader - Persistant Particle Count"},{"t":5,"p":1,"n":"Particle Shader - Particle Lifetime"},{"t":5,"p":1,"n":"Particle Shader - Particle Lifetime +\/-"},{"t":5,"p":1,"n":"Particle Shader - Initial Speed Along Normal"},{"t":5,"p":1,"n":"Particle Shader - Acceleration Along Normal"},{"t":5,"p":1,"n":"Particle Shader - Initial Velocity #1"},{"t":5,"p":1,"n":"Particle Shader - Initial Velocity #2"},{"t":5,"p":1,"n":"Particle Shader - Initial Velocity #3"},{"t":5,"p":1,"n":"Particle Shader - Acceleration #1"},{"t":5,"p":1,"n":"Particle Shader - Acceleration #2"},{"t":5,"p":1,"n":"Particle Shader - Acceleration #3"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 1"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 2"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 1 Time"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 2 Time"},{"t":6,"p":1,"n":"Color Key 1 - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Color Key 2 - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Color Key 3 - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Color Key 1 - Color Alpha"},{"t":5,"p":1,"n":"Color Key 2 - Color Alpha"},{"t":5,"p":1,"n":"Color Key 3 - Color Alpha"},{"t":5,"p":1,"n":"Color Key 1 - Color Key Time"},{"t":5,"p":1,"n":"Color Key 2 - Color Key Time"},{"t":5,"p":1,"n":"Color Key 3 - Color Key Time"},{"t":5,"p":1,"n":"Particle Shader - Initial Speed Along Normal +\/-"},{"t":5,"p":1,"n":"Particle Shader - Initial Rotation (deg)"},{"t":5,"p":1,"n":"Particle Shader - Initial Rotation (deg) +\/-"},{"t":5,"p":1,"n":"Particle Shader - Rotation Speed (deg\/sec)"},{"t":5,"p":1,"n":"Particle Shader - Rotation Speed (deg\/sec) +\/-"},{"t":3,"p":1,"n":"Addon Models"},{"t":5,"p":1,"n":"Holes - Start Time"},{"t":5,"p":1,"n":"Holes - End Time"},{"t":5,"p":1,"n":"Holes - Start Val"},{"t":5,"p":1,"n":"Holes - End Val"},{"t":5,"p":1,"n":"Edge Width (alpha units)"},{"t":6,"p":1,"n":"Edge Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Explosion Wind Speed"},{"t":3,"p":1,"n":"Texture Count U"},{"t":3,"p":1,"n":"Texture Count V"},{"t":5,"p":1,"n":"Addon Models - Fade In Time"},{"t":5,"p":1,"n":"Addon Models - Fade Out Time"},{"t":5,"p":1,"n":"Addon Models - Scale Start"},{"t":5,"p":1,"n":"Addon Models - Scale End"},{"t":5,"p":1,"n":"Addon Models - Scale In Time"},{"t":5,"p":1,"n":"Addon Models - Scale Out Time"},{"t":3,"p":1,"n":"Ambient Sound"},{"t":6,"p":1,"n":"Fill\/Texture Effect - Color Key 2","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Fill\/Texture Effect - Color Key 3","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Fill\/Texture Effect - Color Key Scale\/Time","c":[{"t":5,"p":1,"n":"Color Key 1 - Scale"},{"t":5,"p":1,"n":"Color Key 2 - Scale"},{"t":5,"p":1,"n":"Color Key 3 - Scale"},{"t":5,"p":1,"n":"Color Key 1 - Time"},{"t":5,"p":1,"n":"Color Key 2 - Time"},{"t":5,"p":1,"n":"Color Key 3 - Time"}]},{"t":5,"p":1,"n":"Color Scale"},{"t":5,"p":1,"n":"Birth Position Offset"},{"t":5,"p":1,"n":"Birth Position Offset Range +\/-"},{"t":6,"p":1,"n":"Particle Shader Animated","c":[{"t":3,"p":1,"n":"Start Frame"},{"t":3,"p":1,"n":"Start Frame Variation"},{"t":3,"p":1,"n":"End Frame"},{"t":3,"p":1,"n":"Loop Start Frame"},{"t":3,"p":1,"n":"Loop Start Variation"},{"t":3,"p":1,"n":"Frame Count"},{"t":3,"p":1,"n":"Frame Count Variation"}]},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Scale (U)"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Scale (V)"},{"t":3,"p":1,"n":"Scene Graph Emit Depth Limit (unused)"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]}]},{"t":1,"p":1,"n":"ENCH - Object Effect","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"ENIT - Effect Data","c":[{"t":3,"p":1,"n":"Enchantment Cost"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Cast Type"},{"t":3,"p":1,"n":"Enchantment Amount"},{"t":3,"p":1,"n":"Target Type"},{"t":3,"p":1,"n":"Enchant Type"},{"t":5,"p":1,"n":"Charge Time"},{"t":3,"p":1,"n":"Base Enchantment"},{"t":3,"p":1,"n":"Worn Restrictions"}]},{"t":8,"s":1,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":3,"p":1,"n":"EFID - Base Effect"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":5,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"}]},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]}]},{"t":1,"p":1,"n":"EQUP - Equip Type","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":7,"p":1,"n":"PNAM - Slot Parents","c":[{"t":3,"p":1,"n":"Parent"}]},{"t":3,"p":1,"n":"DATA - Flags"},{"t":3,"p":1,"n":"ANAM - Condition Actor Value"}]},{"t":1,"p":1,"n":"EXPL - Explosion","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]},{"t":3,"p":1,"n":"EITM - Object Effect"},{"t":3,"p":1,"n":"MNAM - Image Space Modifier"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Light"},{"t":3,"p":1,"n":"Sound 1"},{"t":3,"p":1,"n":"Sound 2"},{"t":3,"p":1,"n":"Impact Data Set"},{"t":3,"p":1,"n":"Placed Object"},{"t":3,"p":1,"n":"Spawn Projectile"},{"t":5,"p":1,"n":"Force"},{"t":5,"p":1,"n":"Damage"},{"t":5,"p":1,"n":"Inner Radius"},{"t":5,"p":1,"n":"Outer Radius"},{"t":5,"p":1,"n":"IS Radius"},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"Vertical Offset Mult"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Sound Level"},{"t":5,"p":1,"n":"Placed Object AutoFade Delay"},{"t":3,"p":1,"n":"Stagger"},{"t":6,"p":1,"n":"Spawn","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"},{"t":5,"p":1,"n":"Spread Degrees"},{"t":3,"p":1,"n":"Count"}]}]}]},{"t":1,"p":1,"n":"FACT - Faction","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":8,"s":1,"p":1,"n":"Relations","d":1,"c":[{"t":6,"p":1,"n":"XNAM - Relation","c":[{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Modifier"},{"t":3,"p":1,"n":"Group Combat Reaction"}]}]},{"t":6,"s":1,"p":1,"n":"DATA - Flags","c":[{"t":3,"p":1,"n":"Flags"}]},{"t":3,"p":1,"n":"JAIL - Exterior Jail Marker"},{"t":3,"p":1,"n":"WAIT - Follower Wait Marker"},{"t":3,"p":1,"n":"STOL - Stolen Goods Container"},{"t":3,"p":1,"n":"PLCN - Player Inventory Container"},{"t":3,"p":1,"n":"CRGR - Shared Crime Faction List"},{"t":3,"p":1,"n":"JOUT - Jail Outfit"},{"t":6,"s":1,"p":1,"n":"CRVA - Crime Values","c":[{"t":3,"p":1,"n":"Arrest"},{"t":3,"p":1,"n":"Attack On Sight"},{"t":3,"p":1,"n":"Murder"},{"t":3,"p":1,"n":"Assault"},{"t":3,"p":1,"n":"Trespass"},{"t":3,"p":1,"n":"Pickpocket"},{"t":3,"n":"Unknown"},{"t":5,"p":1,"n":"Steal Multiplier"},{"t":3,"p":1,"n":"Escape"},{"t":3,"p":1,"n":"Werewolf (unused)"}]},{"t":10,"p":1,"n":"Ranks","d":1,"c":[{"t":6,"p":1,"n":"Rank","c":[{"t":3,"p":1,"n":"RNAM - Rank#"},{"t":2,"p":1,"n":"MNAM - Male Title"},{"t":2,"p":1,"n":"FNAM - Female Title"},{"t":2,"p":1,"n":"INAM - Insignia (unused)"}]}]},{"t":3,"p":1,"n":"VEND - Vendor Buy\/Sell List"},{"t":3,"p":1,"n":"VENC - Merchant Container"},{"t":6,"s":1,"p":1,"n":"VENV - Vendor Values","c":[{"t":3,"p":1,"n":"Start Hour"},{"t":3,"p":1,"n":"End Hour"},{"t":3,"p":1,"n":"Radius"},{"t":11,"n":"Unknown 1"},{"t":3,"p":1,"n":"Buys Stolen Items"},{"t":3,"p":1,"n":"Buy\/Sell Everything Not In List?"},{"t":3,"p":1,"n":"Buys NonStolen Items"},{"t":3,"n":"Unknown"}]},{"t":6,"s":1,"p":1,"n":"PLVD - Location","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Cell"},{"t":11,"p":1,"n":"Near Package Start Location"},{"t":11,"p":1,"n":"Near Editor Location"},{"t":3,"p":1,"n":"Object ID"},{"t":3,"p":1,"n":"Object Type"},{"t":3,"p":1,"n":"Keyword"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Ref Alias"},{"t":3,"p":1,"n":"Loc Alias"},{"t":3,"p":1,"n":"Interrupt Data"},{"t":3,"p":1,"n":"Packdata Target"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Ref Collection Alias"},{"t":3,"p":1,"n":"Radius"},{"t":3,"p":1,"n":"Collection Index"}]},{"t":3,"n":"CITC - Condition Count"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]},{"t":1,"p":1,"n":"FLOR - Flora","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"PTRN - Preview Transform"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]},{"t":6,"s":1,"p":1,"n":"Destructible","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"}]},{"t":7,"p":1,"n":"DAMC - Resistances","c":[{"t":6,"p":1,"n":"Resistance","c":[{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Value"}]}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":2,"p":1,"n":"DSTA - Sequence Name"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":5,"p":1,"n":"DMDC - Color Remapping Index"},{"t":3,"p":1,"n":"DMDS - Material Swap"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":7,"p":1,"n":"PRPS - Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":3,"p":1,"n":"Actor Value"},{"t":5,"p":1,"n":"Value"}]}]},{"t":11,"n":"PNAM - Unknown"},{"t":2,"p":1,"n":"ATTX - Activate Text Override"},{"t":2,"p":1,"n":"RNAM - Activate Text Override"},{"t":11,"n":"FNAM - Unknown"},{"t":3,"p":1,"n":"PFIG - Ingredient"},{"t":3,"p":1,"n":"SNAM - Harvest Sound"},{"t":6,"s":1,"p":1,"n":"PFPC - Ingredient Production","c":[{"t":3,"p":1,"n":"Spring"},{"t":3,"p":1,"n":"Summer "},{"t":3,"p":1,"n":"Fall"},{"t":3,"p":1,"n":"Winter"}]}]},{"t":1,"p":1,"n":"FLST - FormID List","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":8,"s":1,"p":1,"n":"FormIDs","d":1,"c":[{"t":3,"p":1,"n":"LNAM - FormID"}]}]},{"t":1,"p":1,"n":"FSTP - Footstep","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"DATA - Impact Data Set"},{"t":2,"p":1,"n":"ANAM - Tag"}]},{"t":1,"p":1,"n":"FSTS - Footstep Set","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"n":"XCNT - Count","c":[{"t":3,"n":"Walking"},{"t":3,"n":"Running"},{"t":3,"n":"Sprinting"},{"t":3,"n":"Sneaking"},{"t":3,"n":"Swimming"}]},{"t":7,"p":1,"n":"DATA - Footstep Sets","c":[{"t":3,"p":1,"n":"Footstep"}]}]},{"t":1,"p":1,"n":"FURN - Furniture","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"PTRN - Preview Transform"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]},{"t":6,"s":1,"p":1,"n":"Destructible","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"}]},{"t":7,"p":1,"n":"DAMC - Resistances","c":[{"t":6,"p":1,"n":"Resistance","c":[{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Value"}]}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":2,"p":1,"n":"DSTA - Sequence Name"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":5,"p":1,"n":"DMDC - Color Remapping Index"},{"t":3,"p":1,"n":"DMDS - Material Swap"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":7,"p":1,"n":"PRPS - Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":3,"p":1,"n":"Actor Value"},{"t":5,"p":1,"n":"Value"}]}]},{"t":3,"p":1,"n":"NTRM - Native Terminal"},{"t":3,"p":1,"n":"FTYP - Forced Loc Ref Type"},{"t":11,"n":"PNAM - Unknown"},{"t":3,"p":1,"n":"WNAM - Drinking Water Type"},{"t":2,"p":1,"n":"ATTX - Activate Text Override"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":3,"n":"CITC - Condition Count"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":3,"n":"COCT - Count"},{"t":10,"p":1,"n":"Items","d":1,"c":[{"t":6,"p":1,"n":"Item","c":[{"t":6,"p":1,"n":"CNTO - Item","c":[{"t":3,"p":1,"n":"Item"},{"t":3,"p":1,"n":"Count"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]},{"t":3,"p":1,"n":"MNAM - Active Markers \/ Flags"},{"t":6,"s":1,"p":1,"n":"WBDT - Workbench Data","c":[{"t":3,"p":1,"n":"Bench Type"},{"t":3,"p":1,"n":"Uses Skill"}]},{"t":3,"p":1,"n":"NAM1 - Associated Form"},{"t":8,"s":1,"p":1,"n":"Markers","d":1,"c":[{"t":6,"p":1,"n":"Marker","c":[{"t":3,"p":1,"n":"ENAM - Marker Index"},{"t":6,"p":1,"n":"NAM0 - Disabled Entry Points","c":[{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Disabled Points"}]}]}]},{"t":8,"s":1,"p":1,"n":"Marker Entry Points","d":1,"c":[{"t":6,"p":1,"n":"FNPR - Marker","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Entry Points"}]}]},{"t":2,"p":1,"n":"XMRK - Marker Model"},{"t":7,"p":1,"n":"SNAM - Marker Paramaters","c":[{"t":6,"p":1,"n":"Marker","c":[{"t":5,"p":1,"n":"Offset X"},{"t":5,"p":1,"n":"Offset Y"},{"t":5,"p":1,"n":"Offset Z"},{"t":5,"p":1,"n":"Rotation Z"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Entry Types"},{"t":11,"n":"Unknown"}]}]},{"t":6,"s":1,"p":1,"n":"NVNM - Navmesh Geometry","c":[{"t":3,"p":1,"n":"Version"},{"t":11,"p":1,"n":"Magic"},{"t":3,"p":1,"n":"Parent Worldspace"},{"t":6,"p":1,"n":"Coordinates","c":[{"t":3,"p":1,"n":"Grid Y"},{"t":3,"p":1,"n":"Grid X"}]},{"t":3,"p":1,"n":"Parent Cell"},{"t":11,"p":1,"n":"Vertices and Triangles"}]},{"t":7,"p":1,"n":"APPR - Attach Parent Slots","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"Object Template","c":[{"t":3,"p":1,"n":"OBTE - Count"},{"t":8,"p":1,"n":"Combinations","c":[{"t":6,"p":1,"n":"Combination","c":[{"p":1,"n":"OBTF - Editor Only"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"p":1,"n":"OBTS - Object Mod Template Item","c":[{"t":3,"p":1,"n":"Include Count"},{"t":3,"p":1,"n":"Property Count"},{"t":3,"p":1,"n":"Level Min"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Level Max"},{"t":3,"p":1,"n":"ID"},{"t":3,"p":1,"n":"Default"},{"t":7,"p":1,"n":"Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":3,"p":1,"n":"Min Level For Ranks"},{"t":3,"p":1,"n":"Alt Levels Per Tier"},{"t":7,"p":1,"n":"Includes","c":[{"t":6,"p":1,"n":"Include","c":[{"t":3,"p":1,"n":"Mod"},{"t":3,"p":1,"n":"Attach Point Index"},{"t":3,"p":1,"n":"Optional"},{"t":3,"p":1,"n":"Don't Use All"}]}]},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":3,"p":1,"n":"Value Type"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Function Type"},{"t":3,"p":1,"n":"Property"},{"t":11,"n":"Value 1 - Unknown"},{"t":3,"p":1,"n":"Value 1 - Int"},{"t":5,"p":1,"n":"Value 1 - Float"},{"t":3,"p":1,"n":"Value 1 - Bool"},{"t":3,"p":1,"n":"Value 1 - FormID"},{"t":3,"p":1,"n":"Value 1 - Enum"},{"t":3,"p":1,"n":"Sound Level"},{"t":3,"p":1,"n":"Stagger Value"},{"t":3,"p":1,"n":"Hit Behaviour"},{"t":3,"p":1,"n":"Value 2 - Int"},{"t":5,"p":1,"n":"Value 2 - Float"},{"t":3,"p":1,"n":"Value 2 - Bool"},{"t":5,"p":1,"n":"Step"}]}]}]}]}]},{"p":1,"n":"STOP - Marker"}]}]},{"t":1,"p":1,"n":"GDRY - God Rays","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":6,"p":1,"n":"Back Color","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}]},{"t":6,"p":1,"n":"Fwd Color","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}]},{"t":5,"p":1,"n":"Intensity"},{"t":5,"p":1,"n":"Air Color - Scale"},{"t":5,"p":1,"n":"Back Color - Scale"},{"t":5,"p":1,"n":"Fwd Color - Scale"},{"t":5,"p":1,"n":"Back Phase"},{"t":6,"p":1,"n":"Air Color","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}]},{"t":5,"p":1,"n":"Fwd Phase"}]}]},{"t":1,"p":1,"n":"GLOB - Global","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"FNAM - Type"},{"t":5,"p":1,"n":"FLTV - Value"}]},{"t":1,"p":1,"n":"GMST - Game Setting","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"Name"},{"t":3,"p":1,"n":"Int"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"}]},{"t":1,"p":1,"n":"GRAS - Grass","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Density"},{"t":3,"p":1,"n":"Min Slope"},{"t":3,"p":1,"n":"Max Slope"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Units From Water"},{"t":3,"p":1,"n":"Units From Water Type"},{"t":5,"p":1,"n":"Position Range"},{"t":5,"p":1,"n":"Height Range"},{"t":5,"p":1,"n":"Color Range"},{"t":5,"p":1,"n":"Wave Period"},{"t":3,"p":1,"n":"Flags"}]}]},{"t":1,"p":1,"n":"HAZD - Hazard","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]},{"t":3,"p":1,"n":"MNAM - Image Space Modifier"},{"t":6,"s":1,"p":1,"n":"DNAM - Data","c":[{"t":3,"p":1,"n":"Limit"},{"t":5,"p":1,"n":"Radius"},{"t":5,"p":1,"n":"Lifetime"},{"t":5,"p":1,"n":"Image Space Radius"},{"t":5,"p":1,"n":"Target Interval"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Effect"},{"t":3,"p":1,"n":"Light"},{"t":3,"p":1,"n":"Impact Data Set"},{"t":3,"p":1,"n":"Sound"},{"t":6,"p":1,"n":"Taper Effectiveness","c":[{"t":5,"p":1,"n":"Full Effect Radius"},{"t":5,"p":1,"n":"Taper Weight"},{"t":5,"p":1,"n":"Taper Curse"}]}]}]},{"t":1,"p":1,"n":"HDPT - Head Part","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]},{"t":3,"p":1,"n":"DATA - Flags"},{"t":3,"p":1,"n":"PNAM - Type"},{"t":8,"s":1,"p":1,"n":"Extra Parts","d":1,"c":[{"t":3,"p":1,"n":"HNAM - Part"}]},{"t":8,"s":1,"p":1,"n":"Parts","d":1,"c":[{"t":6,"p":1,"n":"Part","c":[{"t":3,"p":1,"n":"NAM0 - Part Type"},{"t":2,"p":1,"n":"NAM1 - Filename"}]}]},{"t":3,"p":1,"n":"TNAM - Texture Set"},{"t":3,"p":1,"n":"CNAM - Color"},{"t":3,"p":1,"n":"RNAM - Valid Races"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]},{"t":1,"n":"IDLE - Idle Animation","c":[{"t":2,"n":"EDID - Editor ID"},{"t":8,"n":"Conditions","d":1,"c":[{"t":6,"n":"Condition","c":[{"t":6,"n":"CTDA - ","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"n":"Comparison Value - Float"},{"t":3,"n":"Comparison Value - Global"},{"t":3,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"n":"None"},{"t":3,"n":"Integer"},{"t":5,"n":"Float"},{"t":3,"n":"Actor"},{"t":3,"n":"Actor Base"},{"t":3,"n":"Actor Value"},{"t":3,"n":"Player Action"},{"t":3,"n":"Alias"},{"t":3,"n":"Alignment"},{"t":3,"n":"Association Type"},{"t":3,"n":"Axis"},{"t":3,"n":"Casting Type"},{"t":3,"n":"Cell"},{"t":3,"n":"Class"},{"t":3,"n":"Crime Type"},{"t":3,"n":"Critical Stage"},{"t":3,"n":"Encounter Zone"},{"t":3,"n":"Equip Type"},{"t":3,"n":"Event"},{"t":3,"n":"Event Data"},{"t":3,"n":"Faction"},{"t":3,"n":"Form List"},{"t":3,"n":"Form Type"},{"t":3,"n":"Furniture"},{"t":3,"n":"Furniture Anim"},{"t":3,"n":"Furniture Entry"},{"t":3,"n":"Global"},{"t":3,"n":"Idle"},{"t":3,"n":"Inventory Object"},{"t":3,"n":"Keyword"},{"t":3,"n":"Location"},{"t":3,"n":"Base Effect"},{"t":3,"n":"Effect Item"},{"t":3,"n":"Misc Stat"},{"t":3,"n":"Object Reference"},{"t":3,"n":"Owner"},{"t":3,"n":"Package"},{"t":3,"n":"Packdata ID"},{"t":3,"n":"Perk"},{"t":3,"n":"Quest"},{"t":3,"n":"Quest Stage"},{"t":3,"n":"Race"},{"t":3,"n":"Referenceable Object"},{"t":3,"n":"Location Ref Type"},{"t":3,"n":"Region"},{"t":3,"n":"Scene"},{"t":3,"n":"Sex"},{"t":3,"n":"Shout"},{"t":11,"n":"Variable Name (unused)"},{"t":3,"n":"VATS Value Function"},{"t":3,"n":"VATS Value Param (unused)"},{"t":3,"n":"Voice Type"},{"t":3,"n":"Ward State"},{"t":3,"n":"Weather"},{"t":3,"n":"Worldspace"},{"t":3,"n":"Damage Type"},{"t":3,"n":"Weapon"},{"t":3,"n":"Weapon List"},{"t":3,"n":"Target"},{"t":3,"n":"Target List"},{"t":3,"n":"Target Part"},{"t":3,"n":"VATS Action"},{"t":3,"n":"Critical Effect"},{"t":3,"n":"Critical Effect List"},{"t":3,"n":"Weapon Type"},{"t":3,"n":"Projectile Type"},{"t":3,"n":"Delivery Type"},{"t":3,"n":"Run On"},{"t":3,"n":"Reference"},{"t":3,"n":"Parameter #3"}]},{"t":2,"n":"CIS1 - Parameter #1"},{"t":2,"n":"CIS2 - Parameter #2"}]}]},{"t":2,"n":"DNAM - Behavior Graph"},{"t":2,"n":"ENAM - Animation Event"},{"t":7,"n":"ANAM - Related Idle Animations","c":[{"t":3,"n":"Related Idle Animation"}]},{"t":6,"n":"DATA - ","c":[{"t":6,"n":"Looping seconds (both 255 forever)","c":[{"t":3,"n":"Min"},{"t":3,"n":"Max"}]},{"t":3,"n":"Flags"},{"t":3,"n":"Animation Group Section"},{"t":3,"n":"Replay Delay"}]},{"t":2,"n":"GNAM - Animation File"}]},{"t":1,"p":1,"n":"IDLM - Idle Marker","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":3,"p":1,"n":"IDLF - Flags"},{"t":3,"p":1,"n":"IDLC - Animation Count"},{"t":5,"p":1,"n":"IDLT - Idle Timer Setting"},{"t":7,"p":1,"n":"IDLA - Animations","c":[{"t":3,"p":1,"n":"Animation"}]},{"t":3,"n":"QNAM - Unknown"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]}]},{"t":1,"p":1,"n":"IMAD - Image Space Adapter","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"n":"DNAM - Data Count","c":[{"t":3,"n":"Flags"},{"t":5,"n":"Duration"},{"t":6,"n":"HDR","c":[{"t":3,"n":"Eye Adapt Speed Mult"},{"t":3,"n":"Eye Adapt Speed Add"},{"t":3,"n":"Bloom Blur Radius Mult"},{"t":3,"n":"Bloom Blur Radius Add"},{"t":3,"n":"Bloom Threshold Mult"},{"t":3,"n":"Bloom Threshold Add"},{"t":3,"n":"Bloom Scale Mult"},{"t":3,"n":"Bloom Scale Add"},{"t":3,"n":"Target Lum Min Mult"},{"t":3,"n":"Target Lum Min Add"},{"t":3,"n":"Target Lum Max Mult"},{"t":3,"n":"Target Lum Max Add"},{"t":3,"n":"Sunlight Scale Mult"},{"t":3,"n":"Sunlight Scale Add"},{"t":3,"n":"Sky Scale Mult"},{"t":3,"n":"Sky Scale Add"}]},{"t":3,"n":"Unknown08 Mult"},{"t":3,"n":"Unknown48 Add"},{"t":3,"n":"Unknown09 Mult"},{"t":3,"n":"Unknown49 Add"},{"t":3,"n":"Unknown0A Mult"},{"t":3,"n":"Unknown4A Add"},{"t":3,"n":"Unknown0B Mult"},{"t":3,"n":"Unknown4B Add"},{"t":3,"n":"Unknown0C Mult"},{"t":3,"n":"Unknown4C Add"},{"t":3,"n":"Unknown0D Mult"},{"t":3,"n":"Unknown4D Add"},{"t":3,"n":"Unknown0E Mult"},{"t":3,"n":"Unknown4E Add"},{"t":3,"n":"Unknown0F Mult"},{"t":3,"n":"Unknown4F Add"},{"t":3,"n":"Unknown10 Mult"},{"t":3,"n":"Unknown50 Add"},{"t":6,"n":"Cinematic","c":[{"t":3,"n":"Saturation Mult"},{"t":3,"n":"Saturation Add"},{"t":3,"n":"Brightness Mult"},{"t":3,"n":"Brightness Add"},{"t":3,"n":"Contrast Mult"},{"t":3,"n":"Contrast Add"}]},{"t":3,"n":"Unknown14 Mult"},{"t":3,"n":"Unknown54 Add"},{"t":3,"n":"Tint Color"},{"t":3,"n":"Blur Radius"},{"t":3,"n":"Double Vision Strength"},{"t":3,"n":"Radial Blur Strength"},{"t":3,"n":"Radial Blur Ramp Up"},{"t":3,"n":"Radial Blur Start"},{"t":3,"n":"Radial Blur Flags"},{"t":5,"n":"Radial Blur Center X"},{"t":5,"n":"Radial Blur Center Y"},{"t":3,"n":"DoF Strength"},{"t":3,"n":"DoF Distance"},{"t":3,"n":"DoF Range"},{"t":3,"n":"DoF Flags"},{"t":3,"n":"Radial Blur Ramp Down"},{"t":3,"n":"Radial Blur Down Start"},{"t":3,"n":"Fade Color"},{"t":3,"n":"Motion Blur Strength"},{"t":11,"n":"Unknown"}]},{"t":7,"p":1,"n":"BNAM - Blur Radius","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"VNAM - Double Vision Strength","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"TNAM - Tint Color","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"},{"t":5,"p":1,"n":"Alpha"}]}]},{"t":7,"p":1,"n":"NAM3 - Fade Color","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"},{"t":5,"p":1,"n":"Alpha"}]}]},{"t":6,"s":1,"p":1,"n":"Radial Blur","c":[{"t":7,"p":1,"n":"RNAM - Strength","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"SNAM - RampUp","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"UNAM - Start","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"NAM1 - RampDown","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"NAM2 - DownStart","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]}]},{"t":6,"s":1,"p":1,"n":"Depth of Field","c":[{"t":7,"p":1,"n":"WNAM - Strength","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"XNAM - Distance","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"YNAM - Range","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"NAM5 - Vignette Radius","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"NAM6 - Vignette Strength","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]}]},{"t":7,"p":1,"n":"NAM4 - Motion Blur Strength","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":6,"s":1,"p":1,"n":"HDR","c":[{"t":7,"p":1,"n":"aIAD - Eye Adapt Speed Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"@IAD - Eye Adapt Speed Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"bIAD - Bloom Blur Radius Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"AIAD - Bloom Blur Radius Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"cIAD - Bloom Threshold Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"BIAD - Bloom Threshold Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"dIAD - Bloom Scale Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"CIAD - Bloom Scale Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"eIAD - Target Lum Min Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"DIAD - Target Lum Min Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"fIAD - Target Lum Max Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"EIAD - Target Lum Max Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"gIAD - Sunlight Scale Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"FIAD - Sunlight Scale Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"hIAD - Sky Scale Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"GIAD - Sky Scale Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]}]},{"t":11,"n":"iIAD - Unknown"},{"t":11,"n":"HIAD - Unknown"},{"t":11,"n":"jIAD - Unknown"},{"t":11,"n":"IIAD - Unknown"},{"t":11,"n":"kIAD - Unknown"},{"t":11,"n":"JIAD - Unknown"},{"t":11,"n":"lIAD - Unknown"},{"t":11,"n":"KIAD - Unknown"},{"t":11,"n":"mIAD - Unknown"},{"t":11,"n":"LIAD - Unknown"},{"t":11,"n":"nIAD - Unknown"},{"t":11,"n":"MIAD - Unknown"},{"t":11,"n":"oIAD - Unknown"},{"t":11,"n":"NIAD - Unknown"},{"t":11,"n":"pIAD - Unknown"},{"t":11,"n":"OIAD - Unknown"},{"t":11,"n":"qIAD - Unknown"},{"t":11,"n":"PIAD - Unknown"},{"t":6,"s":1,"p":1,"n":"Cinematic","c":[{"t":7,"p":1,"n":"rIAD - Saturation Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"QIAD - Saturation Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"sIAD - Brightness Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"RIAD - Brightness Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"tIAD - Contrast Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"SIAD - Contrast Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]}]},{"t":11,"n":"uIAD - Unknown"},{"t":11,"n":"TIAD - Unknown"}]},{"t":1,"p":1,"n":"IMGS - Image Space","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":11,"n":"ENAM - Unused"},{"t":6,"s":1,"p":1,"n":"HNAM - HDR","c":[{"t":5,"p":1,"n":"Eye Adapt Speed"},{"t":5,"p":1,"n":"Tonemap E"},{"t":5,"p":1,"n":"Bloom Threshold"},{"t":5,"p":1,"n":"Bloom Scale"},{"t":5,"p":1,"n":"Auto Exposure Max"},{"t":5,"p":1,"n":"Auto Exposure Min"},{"t":5,"p":1,"n":"Sunlight Scale"},{"t":5,"p":1,"n":"Sky Scale"},{"t":5,"p":1,"n":"Middle Gray"}]},{"t":6,"s":1,"p":1,"n":"CNAM - Cinematic","c":[{"t":5,"p":1,"n":"Saturation"},{"t":5,"p":1,"n":"Brightness"},{"t":5,"p":1,"n":"Contrast"}]},{"t":6,"s":1,"p":1,"n":"TNAM - Tint","c":[{"t":5,"p":1,"n":"Amount"},{"t":6,"p":1,"n":"Color","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}]}]},{"t":6,"s":1,"p":1,"n":"DNAM - Depth of Field","c":[{"t":5,"p":1,"n":"Strength"},{"t":5,"p":1,"n":"Distance"},{"t":5,"p":1,"n":"Range"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Sky \/ Blur Radius"},{"t":5,"p":1,"n":"Vignette Radius"},{"t":5,"p":1,"n":"Vignette Strength"}]},{"t":2,"p":1,"n":"TX00 - LUT"}]},{"t":1,"p":1,"n":"INFO - Dialog response","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]},{"t":6,"p":1,"n":"Script Fragments","c":[{"t":3,"n":"Unknown"},{"t":3,"p":1,"n":"Flags"},{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]},{"t":7,"p":1,"n":"Fragments","c":[{"t":6,"p":1,"n":"Fragment","c":[{"t":3,"n":"Unknown"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]}]}]},{"t":6,"s":1,"p":1,"n":"ENAM - Response flags","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Reset Hours"}]},{"t":3,"p":1,"n":"TPIC - Topic"},{"t":3,"p":1,"n":"PNAM - Previous INFO"},{"t":3,"p":1,"n":"DNAM - Shared INFO"},{"t":3,"n":"GNAM - Unknown"},{"t":2,"p":1,"n":"IOVR - Override Filename"},{"t":8,"s":1,"p":1,"n":"Responses","d":1,"c":[{"t":6,"p":1,"n":"Response","c":[{"t":6,"p":1,"n":"TRDA - Response Data","c":[{"t":3,"p":1,"n":"Emotion"},{"t":3,"p":1,"n":"Response number"},{"t":11,"n":"Unused"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Interrupt Percentage"},{"t":3,"p":1,"n":"Camera Target Alias"},{"t":3,"p":1,"n":"Camera Location Alias"}]},{"t":2,"p":1,"n":"NAM1 - Response Text"},{"t":2,"p":1,"n":"NAM2 - Script Notes"},{"t":2,"p":1,"n":"NAM3 - Edits"},{"t":2,"p":1,"n":"NAM4 - Alternate LIP Text"},{"t":3,"p":1,"n":"SNAM - Idle Animations: Speaker"},{"t":3,"p":1,"n":"LNAM - Idle Animations: Listener"},{"t":3,"p":1,"n":"TNAM - Interrupt Percentage"},{"t":11,"p":1,"n":"NAM9 - Text Hash"},{"t":3,"p":1,"n":"SRAF - Camera Path"},{"p":1,"n":"WZMD - Stop on Scene End"}]}]},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":2,"p":1,"n":"RNAM - Prompt"},{"t":3,"p":1,"n":"ANAM - Speaker"},{"t":3,"p":1,"n":"TSCE - Start Scene"},{"t":3,"p":1,"n":"ALFA - Forced Alias"},{"t":11,"n":"INTV - Unknown"},{"t":3,"p":1,"n":"ONAM - Audio Output Override"},{"t":3,"p":1,"n":"GREE - Greet Distance"},{"t":6,"s":1,"p":1,"n":"TIQS - Set Parent Quest Stage","c":[{"t":3,"p":1,"n":"On Begin"},{"t":3,"p":1,"n":"On End"}]},{"t":2,"p":1,"n":"NAM0 - Start Scene Phase"},{"t":3,"p":1,"n":"INCC - Challenge"},{"t":3,"p":1,"n":"MODQ - Reset Global"},{"t":3,"p":1,"n":"INAM - Subtitle Priority"}]},{"t":1,"p":1,"n":"INGR - Ingredient","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]},{"t":2,"p":1,"n":"ICON - Inventory Image"},{"t":2,"p":1,"n":"MICO - Message Icon"},{"t":6,"s":1,"p":1,"n":"Destructible","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"}]},{"t":7,"p":1,"n":"DAMC - Resistances","c":[{"t":6,"p":1,"n":"Resistance","c":[{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Value"}]}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":2,"p":1,"n":"DSTA - Sequence Name"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":5,"p":1,"n":"DMDC - Color Remapping Index"},{"t":3,"p":1,"n":"DMDS - Material Swap"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"ETYP - Equipment Type"},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":6,"s":1,"p":1,"n":"ENIT - Effect Data","c":[{"t":3,"p":1,"n":"Ingredient Value"},{"t":3,"p":1,"n":"Flags"}]},{"t":8,"s":1,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":3,"p":1,"n":"EFID - Base Effect"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":5,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"}]},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]}]},{"t":1,"p":1,"n":"INNR - Instance Naming Rules","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"UNAM - Target"},{"t":8,"s":1,"p":1,"n":"Naming Rules","d":1,"c":[{"t":6,"p":1,"n":"Ruleset","c":[{"t":3,"p":1,"n":"VNAM - Count"},{"t":8,"p":1,"n":"Names","c":[{"t":6,"p":1,"n":"Name","c":[{"t":2,"p":1,"n":"WNAM - Text"},{"t":3,"p":1,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"p":1,"n":"XNAM - Property","c":[{"t":5,"p":1,"n":"Value"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Op"}]},{"t":3,"p":1,"n":"YNAM - Index"}]}]}]}]}]},{"t":1,"p":1,"n":"IPCT - Impact","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":5,"p":1,"n":"Effect - Duration"},{"t":3,"p":1,"n":"Effect - Orientation"},{"t":5,"p":1,"n":"Angle Threshold"},{"t":5,"p":1,"n":"Placement Radius"},{"t":3,"p":1,"n":"Sound Level"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Impact Result"},{"t":11,"n":"Unknown"}]},{"t":6,"s":1,"p":1,"n":"DODT - Decal Data","c":[{"t":5,"p":1,"n":"Min Width"},{"t":5,"p":1,"n":"Max Width"},{"t":5,"p":1,"n":"Min Height"},{"t":5,"p":1,"n":"Max Height"},{"t":5,"p":1,"n":"Depth"},{"t":5,"p":1,"n":"Shininess"},{"t":6,"p":1,"n":"Parallax","c":[{"t":5,"p":1,"n":"Scale"},{"t":3,"p":1,"n":"Passes"}]},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Alpha Threshold?"},{"t":6,"p":1,"n":"Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":3,"p":1,"n":"DNAM - Texture Set"},{"t":3,"p":1,"n":"ENAM - Secondary Texture Set"},{"t":3,"p":1,"n":"SNAM - Sound 1"},{"t":3,"p":1,"n":"NAM1 - Sound 2"},{"t":3,"p":1,"n":"NAM3 - Footstep Explosion"},{"t":3,"p":1,"n":"NAM2 - Hazard"},{"t":5,"p":1,"n":"FNAM - Footstep Particle Max Dist"}]},{"t":1,"p":1,"n":"IPDS - Impact Data Set","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":8,"s":1,"p":1,"n":"Data","d":1,"c":[{"t":6,"p":1,"n":"PNAM - ","c":[{"t":3,"p":1,"n":"Material"},{"t":3,"p":1,"n":"Impact"}]}]}]},{"t":1,"p":1,"n":"KEYM - Key","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"PTRN - Preview Transform"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]},{"t":2,"p":1,"n":"ICON - Inventory Image"},{"t":2,"p":1,"n":"MICO - Message Icon"},{"t":6,"s":1,"p":1,"n":"Destructible","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"}]},{"t":7,"p":1,"n":"DAMC - Resistances","c":[{"t":6,"p":1,"n":"Resistance","c":[{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Value"}]}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":2,"p":1,"n":"DSTA - Sequence Name"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":5,"p":1,"n":"DMDC - Color Remapping Index"},{"t":3,"p":1,"n":"DMDS - Material Swap"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]}]},{"t":1,"p":1,"n":"KSSM - Sound Keyword Mapping","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"DNAM - Primary Descriptor"},{"t":3,"p":1,"n":"ENAM - Exterior Tail"},{"t":3,"p":1,"n":"VNAM - VATS Descriptor"},{"t":5,"p":1,"n":"TNAM - VATS Threshold"},{"t":8,"s":1,"p":1,"n":"Keywords","d":1,"c":[{"t":3,"p":1,"n":"KNAM - Keyword"}]},{"t":8,"s":1,"p":1,"n":"Sounds","d":1,"c":[{"t":6,"p":1,"n":"RNAM - Sound","c":[{"t":3,"p":1,"n":"Reverb Class"},{"t":3,"p":1,"n":"Descriptor"}]}]}]},{"t":1,"p":1,"n":"KYWD - Keyword","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"CNAM - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":2,"p":1,"n":"DNAM - Notes"},{"t":3,"p":1,"n":"TNAM - Type"},{"t":3,"p":1,"n":"DATA - Attraction Rule"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"NNAM - Display Name"}]},{"t":1,"p":1,"n":"LAND - Landscape","d":1,"c":[{"t":11,"n":"DATA - Unknown"},{"t":11,"n":"VNML - Vertex Normals"},{"t":11,"n":"VHGT - Vertext Height Map"},{"t":11,"n":"VCLR - Vertex Colours"},{"t":8,"s":1,"p":1,"n":"Layers","d":1,"c":[{"t":6,"p":1,"n":"Base Layer","c":[{"t":6,"p":1,"n":"BTXT - Base Layer Header","c":[{"t":3,"p":1,"n":"Texture"},{"t":3,"p":1,"n":"Quadrant"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Layer"}]}]},{"t":6,"p":1,"n":"Alpha Layer","c":[{"t":6,"p":1,"n":"ATXT - Alpha Layer Header","c":[{"t":3,"p":1,"n":"Texture"},{"t":3,"p":1,"n":"Quadrant"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Layer"}]},{"t":11,"p":1,"n":"VTXT - Alpha Layer Data"}]}]},{"t":7,"p":1,"n":"VTEX - Textures","c":[{"t":3,"p":1,"n":"Texture"}]},{"t":8,"n":"Unknown","c":[{"t":11,"n":"MPCD - Unknown"}]}]},{"t":1,"p":1,"n":"LAYR - Layer","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"PNAM - Parent"}]},{"t":1,"p":1,"n":"LCRT - Location Reference Type","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"CNAM - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":11,"n":"TNAM - Unknown"}]},{"t":1,"n":"LCTN - Location","c":[{"t":2,"n":"EDID - Editor ID"},{"t":7,"n":"ACPR - Actor Cell Persistent Reference","c":[{"t":6,"n":"","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Location"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":7,"n":"LCPR - Location Cell Persistent Reference","c":[{"t":6,"n":"","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Location"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":7,"n":"RCPR - Reference Cell Persistent Reference","c":[{"t":3,"n":"Ref"}]},{"t":7,"n":"ACUN - Actor Cell Unique","c":[{"t":6,"n":"","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Ref"},{"t":3,"n":"Location"}]}]},{"t":7,"n":"LCUN - Location Cell Unique","c":[{"t":6,"n":"","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Ref"},{"t":3,"n":"Location"}]}]},{"t":7,"n":"RCUN - Reference Cell Unique","c":[{"t":3,"n":"Actor"}]},{"t":7,"n":"ACSR - Actor Cell Static Reference","c":[{"t":6,"n":"","c":[{"t":3,"n":"Loc Ref Type"},{"t":3,"n":"Marker"},{"t":3,"n":"Location"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":7,"n":"LCSR - Location Cell Static Reference","c":[{"t":6,"n":"","c":[{"t":3,"n":"Loc Ref Type"},{"t":3,"n":"Marker"},{"t":3,"n":"Location"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":7,"n":"RCSR - Reference Cell Static Reference","c":[{"t":3,"n":"Ref"}]},{"t":8,"n":"Actor Cell Encounter Cell","c":[{"t":6,"n":"ACEC - Unknown","c":[{"t":3,"n":"Location"},{"t":7,"n":"Coordinates","c":[{"t":6,"n":"","c":[{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]}]}]},{"t":8,"n":"Location Cell Encounter Cell","c":[{"t":6,"n":"LCEC - Unknown","c":[{"t":3,"n":"Location"},{"t":7,"n":"Coordinates","c":[{"t":6,"n":"","c":[{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]}]}]},{"t":8,"n":"Reference Cell Encounter Cell","c":[{"t":6,"n":"RCEC - Unknown","c":[{"t":3,"n":"Location"},{"t":7,"n":"Coordinates","c":[{"t":6,"n":"","c":[{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]}]}]},{"t":7,"n":"ACID - Actor Cell Marker Reference","c":[{"t":3,"n":"Ref"}]},{"t":7,"n":"LCID - Location Cell Marker Reference","c":[{"t":3,"n":"Ref"}]},{"t":7,"n":"ACEP - Actor Cell Enable Point","c":[{"t":6,"n":"","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Ref"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":7,"n":"LCEP - Location Cell Enable Point","c":[{"t":6,"n":"","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Ref"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":2,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"n":"KWDA - Keywords","d":1,"c":[{"t":3,"n":"Keyword"}]},{"t":3,"n":"PNAM - Parent Location"},{"t":3,"n":"NAM1 - Music"},{"t":3,"n":"FNAM - Unreported Crime Faction"},{"t":3,"n":"MNAM - World Location Marker Ref"},{"t":5,"n":"RNAM - World Location Radius"},{"t":5,"n":"ANAM - Unknown"},{"t":6,"n":"CNAM - Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":1,"p":1,"n":"LENS - Lens Flare","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":5,"p":1,"n":"CNAM - Color Influence"},{"t":5,"p":1,"n":"DNAM - Fade Distance Radius Scale"},{"t":3,"n":"LFSP - Count"},{"t":10,"p":1,"n":"Lens Flare Sprites","d":1,"c":[{"t":6,"p":1,"n":"Flare","c":[{"t":2,"p":1,"n":"DNAM - Lens Flare Sprite ID"},{"t":2,"p":1,"n":"FNAM - Texture"},{"t":6,"p":1,"n":"LFSD - Lens Flare Data","c":[{"t":6,"p":1,"n":"Tint","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}]},{"t":5,"p":1,"n":"Width"},{"t":5,"p":1,"n":"Height"},{"t":5,"p":1,"n":"Position"},{"t":5,"p":1,"n":"Angular Fade"},{"t":5,"p":1,"n":"Opacity"},{"t":3,"p":1,"n":"Flags"}]}]}]}]},{"t":1,"p":1,"n":"LGTM - Lighting Template","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - Lighting","c":[{"t":6,"p":1,"n":"Ambient Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Directional Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Fog Color Near","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Fog Near"},{"t":5,"p":1,"n":"Fog Far"},{"t":3,"p":1,"n":"Directional Rotation XY"},{"t":3,"p":1,"n":"Directional Rotation Z"},{"t":5,"p":1,"n":"Directional Fade"},{"t":5,"p":1,"n":"Fog Clip Distance"},{"t":5,"p":1,"n":"Fog Power"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Fog Color Far","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Fog Max"},{"t":5,"p":1,"n":"Light Fade Begin"},{"t":5,"p":1,"n":"Light Fade End"},{"t":5,"p":1,"n":"Near Height Mid"},{"t":5,"p":1,"n":"Near Height Range"},{"t":6,"p":1,"n":"Fog Color High Near","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Fog Color High Far","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"High Density Scale"},{"t":5,"p":1,"n":"Fog Near Scale"},{"t":5,"p":1,"n":"Fog Far Scale"},{"t":5,"p":1,"n":"Fog High Near Scale"},{"t":5,"p":1,"n":"Fog High Far Scale"},{"t":5,"p":1,"n":"Far Height Mid"},{"t":5,"p":1,"n":"Far Height Range"}]},{"t":6,"s":1,"p":1,"n":"DALC - Directional Ambient Lighting Colors","c":[{"t":6,"p":1,"n":"Directional","c":[{"t":6,"p":1,"n":"X+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"X-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Specular","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Scale"}]},{"t":3,"p":1,"n":"WGDR - God Rays"}]},{"t":1,"p":1,"n":"LIGH - Light","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"PTRN - Preview Transform"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"Destructible","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"}]},{"t":7,"p":1,"n":"DAMC - Resistances","c":[{"t":6,"p":1,"n":"Resistance","c":[{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Value"}]}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":2,"p":1,"n":"DSTA - Sequence Name"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":5,"p":1,"n":"DMDC - Color Remapping Index"},{"t":3,"p":1,"n":"DMDS - Material Swap"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":7,"p":1,"n":"PRPS - Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":3,"p":1,"n":"Actor Value"},{"t":5,"p":1,"n":"Value"}]}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"ICON - Inventory Image"},{"t":2,"p":1,"n":"MICO - Message Icon"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Time"},{"t":3,"p":1,"n":"Radius"},{"t":6,"p":1,"n":"Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Falloff Exponent"},{"t":5,"p":1,"n":"FOV"},{"t":5,"p":1,"n":"Near Clip"},{"t":6,"p":1,"n":"Flicker Effect","c":[{"t":5,"p":1,"n":"Period"},{"t":5,"p":1,"n":"Intensity Amplitude"},{"t":5,"p":1,"n":"Movement Amplitude"}]},{"t":5,"p":1,"n":"Constant"},{"t":5,"p":1,"n":"Scalar"},{"t":5,"p":1,"n":"Exponent"},{"t":5,"p":1,"n":"God Rays - Near Clip"},{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":5,"p":1,"n":"FNAM - Fade value"},{"t":2,"p":1,"n":"NAM0 - Gobo"},{"t":3,"p":1,"n":"LNAM - Lens"},{"t":3,"p":1,"n":"WGDR - God Rays"},{"t":3,"p":1,"n":"SNAM - Sound"}]},{"t":1,"p":1,"n":"LSCR - Load Screen","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"DESC - Description"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":3,"p":1,"n":"NNAM - Loading Screen NIF"},{"t":3,"p":1,"n":"TNAM - Transform"},{"t":6,"s":1,"p":1,"n":"ONAM - Rotation","c":[{"t":3,"p":1,"n":"Min"},{"t":3,"p":1,"n":"Max"}]},{"t":6,"s":1,"p":1,"n":"ZNAM - Zoom","c":[{"t":5,"p":1,"n":"Min"},{"t":5,"p":1,"n":"Max"}]},{"t":2,"p":1,"n":"MOD2 - Camera Path"}]},{"t":1,"p":1,"n":"LTEX - Landscape Texture","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"TNAM - Texture Set"},{"t":3,"p":1,"n":"MNAM - Material Type"},{"t":6,"s":1,"p":1,"n":"HNAM - Havok Data","c":[{"t":3,"p":1,"n":"Friction"},{"t":3,"p":1,"n":"Restitution"}]},{"t":3,"p":1,"n":"SNAM - Texture Specular Exponent"},{"t":8,"s":1,"p":1,"n":"Grasses","d":1,"c":[{"t":3,"p":1,"n":"GNAM - Grass"}]}]},{"t":1,"p":1,"n":"LVLI - Leveled Item","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"LVLD - Chance None"},{"t":3,"p":1,"n":"LVLM - Max Count"},{"t":3,"p":1,"n":"LVLF - Flags"},{"t":3,"p":1,"n":"LVLG - Use Global"},{"t":3,"n":"LLCT - Count"},{"t":10,"p":1,"n":"Leveled List Entries","d":1,"c":[{"t":6,"p":1,"n":"Leveled List Entry","c":[{"t":6,"p":1,"n":"LVLO - Base Data","c":[{"t":3,"p":1,"n":"Level"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Chance None"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]},{"t":7,"p":1,"n":"LLKC - Filter Keyword Chances","c":[{"t":6,"p":1,"n":"Filter","c":[{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Chance"}]}]},{"t":3,"p":1,"n":"LVSG - Epic Loot Chance"},{"t":2,"p":1,"n":"ONAM - Override Name"}]},{"t":1,"p":1,"n":"LVLN - Leveled NPC","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"LVLD - Chance None"},{"t":3,"p":1,"n":"LVLM - Max Count"},{"t":3,"p":1,"n":"LVLF - Flags"},{"t":3,"p":1,"n":"LVLG - Use Global"},{"t":3,"n":"LLCT - Count"},{"t":10,"p":1,"n":"Leveled List Entries","d":1,"c":[{"t":6,"p":1,"n":"Leveled List Entry","c":[{"t":6,"p":1,"n":"LVLO - Base Data","c":[{"t":3,"p":1,"n":"Level"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Chance None"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]},{"t":7,"p":1,"n":"LLKC - Filter Keyword Chances","c":[{"t":6,"p":1,"n":"Filter","c":[{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Chance"}]}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]}]},{"t":1,"p":1,"n":"LVSP - Leveled Spell","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"}]},{"t":1,"p":1,"n":"MATO - Material Object","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]},{"t":8,"s":1,"p":1,"n":"Property Data","d":1,"c":[{"t":11,"p":1,"n":"DNAM - Data"}]},{"t":6,"s":1,"p":1,"n":"DATA - Directional Material Data","c":[{"t":5,"p":1,"n":"Falloff Scale"},{"t":5,"p":1,"n":"Falloff Bias"},{"t":5,"p":1,"n":"Noise UV Scale"},{"t":5,"p":1,"n":"Material UV Scale"},{"t":6,"p":1,"n":"Projection Vector","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":5,"p":1,"n":"Normal Dampener"},{"t":6,"p":1,"n":"Single Pass Color","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}]},{"t":3,"p":1,"n":"Flags"}]}]},{"t":1,"p":1,"n":"MATT - Material Type","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"PNAM - Material Parent"},{"t":2,"p":1,"n":"MNAM - Material Name"},{"t":6,"s":1,"p":1,"n":"CNAM - Havok Display Color","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}]},{"t":5,"p":1,"n":"BNAM - Buoyancy"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":3,"p":1,"n":"HNAM - Havok Impact Data Set"},{"t":2,"p":1,"n":"ANAM - Breakable FX"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":1,"p":1,"n":"MESG - Message","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"DESC - Description"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"INAM - Icon (unused)"},{"t":3,"p":1,"n":"QNAM - Owner Quest"},{"t":3,"p":1,"n":"DNAM - Flags"},{"t":3,"p":1,"n":"TNAM - Display Time"},{"t":2,"p":1,"n":"SNAM - SWF"},{"t":2,"p":1,"n":"NNAM - Short Title"},{"t":8,"s":1,"p":1,"n":"Menu Buttons","d":1,"c":[{"t":6,"p":1,"n":"Menu Button","c":[{"t":2,"p":1,"n":"ITXT - Button Text"},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]}]},{"t":1,"p":1,"n":"MGEF - Magic Effect","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"MDOB - Menu Display Object"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"Magic Effect Data","c":[{"t":6,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Base Cost"},{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Assoc. Item"},{"t":11,"p":1,"n":"Magic Skill (unused)"},{"t":3,"p":1,"n":"Resist Value"},{"t":3,"p":1,"n":"Counter Effect count"},{"t":3,"p":1,"n":"Casting Light"},{"t":5,"p":1,"n":"Taper Weight"},{"t":3,"p":1,"n":"Hit Shader"},{"t":3,"p":1,"n":"Enchant Shader"},{"t":3,"p":1,"n":"Minimum Skill Level"},{"t":6,"p":1,"n":"Spellmaking","c":[{"t":3,"p":1,"n":"Area"},{"t":5,"p":1,"n":"Casting Time"}]},{"t":5,"p":1,"n":"Taper Curve"},{"t":5,"p":1,"n":"Taper Duration"},{"t":5,"p":1,"n":"Second AV Weight"},{"t":3,"p":1,"n":"Archetype"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Projectile"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Delivery"},{"t":3,"p":1,"n":"Casting Art"},{"t":3,"p":1,"n":"Hit Effect Art"},{"t":3,"p":1,"n":"Impact Data"},{"t":5,"p":1,"n":"Skill Usage Multiplier"},{"t":6,"p":1,"n":"Dual Casting","c":[{"t":3,"p":1,"n":"Art"},{"t":5,"p":1,"n":"Scale"}]},{"t":3,"p":1,"n":"Enchant Art"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Equip Ability"},{"t":3,"p":1,"n":"Image Space Modifier"},{"t":3,"p":1,"n":"Perk to Apply"},{"t":3,"p":1,"n":"Casting Sound Level"},{"t":6,"p":1,"n":"Script Effect AI","c":[{"t":5,"p":1,"n":"Score"},{"t":5,"p":1,"n":"Delay Time"}]}]}]},{"t":8,"s":1,"n":"Counter Effects","d":1,"c":[{"t":3,"n":"ESCE - Effect"}]},{"t":7,"p":1,"n":"SNDD - Sounds","c":[{"t":6,"p":1,"n":"","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Sound"}]}]},{"t":2,"p":1,"n":"DNAM - Magic Item Description"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]},{"t":1,"p":1,"n":"MISC - Misc. Item","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"PTRN - Preview Transform"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]},{"t":2,"p":1,"n":"ICON - Inventory Image"},{"t":2,"p":1,"n":"MICO - Message Icon"},{"t":6,"s":1,"p":1,"n":"Destructible","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"}]},{"t":7,"p":1,"n":"DAMC - Resistances","c":[{"t":6,"p":1,"n":"Resistance","c":[{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Value"}]}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":2,"p":1,"n":"DSTA - Sequence Name"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":5,"p":1,"n":"DMDC - Color Remapping Index"},{"t":3,"p":1,"n":"DMDS - Material Swap"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":3,"p":1,"n":"FIMD - Featured Item Message"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":7,"p":1,"n":"CVPA - Components","c":[{"t":6,"p":1,"n":"Component","c":[{"t":3,"p":1,"n":"Component"},{"t":3,"p":1,"n":"Count"}]}]},{"t":7,"p":1,"n":"CDIX - Component Display Indices","c":[{"t":3,"p":1,"n":"Display Index"}]}]},{"t":1,"p":1,"n":"MOVT - Movement Type","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"MNAM - Name"},{"t":6,"s":1,"p":1,"n":"SPED - Movement Data","c":[{"t":5,"n":"Unknown"},{"t":5,"p":1,"n":"Walk - Left"},{"t":5,"p":1,"n":"Run - Left"},{"t":5,"p":1,"n":"Walk - Right"},{"t":5,"p":1,"n":"Run - Right"},{"t":5,"p":1,"n":"Walk - Forward"},{"t":5,"p":1,"n":"Run - Forward"},{"t":5,"p":1,"n":"Sprint - Forward"},{"t":5,"p":1,"n":"Walk - Back"},{"t":5,"p":1,"n":"Run - Back"},{"t":5,"p":1,"n":"Standing - Pitch"},{"t":5,"p":1,"n":"Walk - Pitch"},{"t":5,"p":1,"n":"Run - Pitch"},{"t":5,"p":1,"n":"Sprint - Pitch"},{"t":5,"p":1,"n":"Standing - Yaw"},{"t":5,"p":1,"n":"Walk - Yaw"},{"t":5,"p":1,"n":"Run - Yaw"},{"t":5,"p":1,"n":"Sprint - Yaw"}]},{"t":6,"s":1,"p":1,"n":"INAM - Anim Change Thresholds (unused)","c":[{"t":5,"p":1,"n":"Directional"},{"t":5,"p":1,"n":"Movement Speed"},{"t":5,"p":1,"n":"Rotation Speed"}]},{"t":5,"p":1,"n":"JNAM - Float Height"},{"t":5,"p":1,"n":"LNAM - Flight - Angle Gain"}]},{"t":1,"p":1,"n":"MSTT - Moveable Static","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"PTRN - Preview Transform"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]},{"t":6,"s":1,"p":1,"n":"Destructible","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"}]},{"t":7,"p":1,"n":"DAMC - Resistances","c":[{"t":6,"p":1,"n":"Resistance","c":[{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Value"}]}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":2,"p":1,"n":"DSTA - Sequence Name"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":5,"p":1,"n":"DMDC - Color Remapping Index"},{"t":3,"p":1,"n":"DMDS - Material Swap"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":7,"p":1,"n":"PRPS - Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":3,"p":1,"n":"Actor Value"},{"t":5,"p":1,"n":"Value"}]}]},{"t":3,"p":1,"n":"DATA - On Local Map"},{"t":3,"p":1,"n":"SNAM - Looping Sound"}]},{"t":1,"p":1,"n":"MSWP - Material Swap","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FNAM - Tree Folder"},{"t":10,"p":1,"n":"Material Substitutions","d":1,"c":[{"t":6,"p":1,"n":"Substitution","c":[{"t":2,"p":1,"n":"BNAM - Original Material"},{"t":2,"p":1,"n":"SNAM - Replacement Material"},{"t":2,"p":1,"n":"FNAM - Tree Folder (obsolete)"},{"t":5,"p":1,"n":"CNAM - Color Remapping Index"}]}]}]},{"t":1,"p":1,"n":"MUSC - Music Type","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":6,"s":1,"p":1,"n":"PNAM - Data","c":[{"t":3,"p":1,"n":"Priority"},{"t":3,"p":1,"n":"Ducking (dB)"}]},{"t":5,"p":1,"n":"WNAM - Fade Duration"},{"t":7,"p":1,"n":"TNAM - Music Tracks","c":[{"t":3,"p":1,"n":"Track"}]}]},{"t":1,"p":1,"n":"MUST - Music Track","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"CNAM - Track Type"},{"t":5,"p":1,"n":"FLTV - Duration"},{"t":5,"p":1,"n":"DNAM - Fade-Out"},{"t":2,"p":1,"n":"ANAM - Track Filename"},{"t":2,"p":1,"n":"BNAM - Finale Filename"},{"t":6,"s":1,"p":1,"n":"LNAM - Loop Data","c":[{"t":5,"p":1,"n":"Loop Begins"},{"t":5,"p":1,"n":"Loop Ends"},{"t":3,"p":1,"n":"Loop Count"}]},{"t":7,"p":1,"n":"FNAM - Cue Points","c":[{"t":5,"p":1,"n":"Point"}]},{"t":3,"n":"CITC - Condition Count"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":7,"p":1,"n":"SNAM - Tracks","c":[{"t":3,"p":1,"n":"Track"}]}]},{"t":1,"n":"NAVI - Navigation Mesh Info Map","c":[{"t":2,"n":"EDID - Editor ID"},{"t":3,"n":"NVER - Version"},{"t":8,"n":"Navigation Map Infos","c":[{"t":6,"n":"NVMI - Navigation Map Info","c":[{"t":3,"n":"Navigation Mesh"},{"t":11,"n":"Data"},{"t":7,"n":"Merged To","c":[{"t":3,"n":"Mesh"}]},{"t":7,"n":"Preferred Merges","c":[{"t":3,"n":"Mesh"}]},{"t":7,"n":"Linked Doors","c":[{"t":6,"n":"Door","c":[{"t":11,"n":"Unknown"},{"t":3,"n":"Door Ref"}]}]},{"t":3,"n":"Is Island"},{"t":11,"n":"Unused"},{"t":6,"n":"Island Data","c":[{"t":11,"n":"Unknown"},{"t":7,"n":"Triangles","c":[{"t":11,"n":"Triangle"}]},{"t":7,"n":"Vertices","c":[{"t":11,"n":"Vertex"}]}]},{"t":11,"n":"Unknown"},{"t":3,"n":"Parent Worldspace"},{"t":6,"n":"Coordinates","c":[{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]},{"t":3,"n":"Parent Cell"}]}]},{"t":6,"n":"NVPP - Preferred Pathing","c":[{"t":7,"n":"NavMeshes","c":[{"t":7,"n":"Set","c":[{"t":3,"n":""}]}]},{"t":7,"n":"NavMesh Tree?","c":[{"t":6,"n":"","c":[{"t":3,"n":"NavMesh"},{"t":3,"n":"Index\/Node"}]}]}]},{"t":11,"n":"NVSI - Unknown"}]},{"t":1,"n":"NAVM - Navigation Mesh","c":[{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"NVNM - Navmesh Geometry","c":[{"t":3,"n":"Version"},{"t":11,"n":"Magic"},{"t":3,"n":"Parent Worldspace"},{"t":6,"n":"Coordinates","c":[{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]},{"t":3,"n":"Parent Cell"},{"t":11,"n":"Vertices and Triangles"}]},{"t":11,"n":"ONAM - Unknown"},{"t":11,"n":"NNAM - Unknown"},{"t":11,"n":"MNAM - Unknown"}]},{"t":1,"n":"NOCM - Navigation Mesh Obstacle Manager","d":1,"c":[{"t":8,"n":"Unknown","c":[{"t":6,"n":"Unknown","c":[{"t":3,"n":"INDX - Index"},{"t":8,"n":"Unknown","c":[{"t":11,"n":"DATA - Unknown"}]},{"t":11,"n":"INTV - Unknown"},{"t":2,"n":"NAM1 - Model"}]}]}]},{"t":1,"p":1,"n":"NOTE - Note","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"PTRN - Preview Transform"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]},{"t":2,"p":1,"n":"ICON - Inventory Image"},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":3,"p":1,"n":"DNAM - Type"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Sound"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Terminal"},{"t":2,"p":1,"n":"PNAM - Program File"}]},{"t":1,"p":1,"n":"NPC_ - Non-Player Character (Actor)","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"PTRN - Preview Transform"},{"t":3,"n":"STCP - Unknown"},{"t":6,"s":1,"p":1,"n":"ACBS - Configuration","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"XP Value Offset"},{"t":3,"p":1,"n":"Level"},{"t":3,"p":1,"n":"Level Mult"},{"t":3,"p":1,"n":"Calc min level"},{"t":3,"p":1,"n":"Calc max level"},{"t":3,"p":1,"n":"Disposition Base"},{"t":3,"p":1,"n":"Use Template Actors"},{"t":3,"p":1,"n":"Bleedout Override"},{"t":11,"n":"Unknown"}]},{"t":8,"s":1,"p":1,"n":"Factions","d":1,"c":[{"t":6,"p":1,"n":"SNAM - Faction","c":[{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Rank"}]}]},{"t":3,"p":1,"n":"INAM - Death item"},{"t":3,"p":1,"n":"VTCK - Voice"},{"t":3,"p":1,"n":"TPLT - Default Template"},{"t":3,"p":1,"n":"LTPT - Legendary Template"},{"t":3,"p":1,"n":"LTPC - Legendary Chance"},{"t":6,"s":1,"p":1,"n":"TPTA - Template Actors","c":[{"t":3,"p":1,"n":"Traits"},{"t":3,"p":1,"n":"Stats"},{"t":3,"p":1,"n":"Factions"},{"t":3,"p":1,"n":"Spell List"},{"t":3,"p":1,"n":"AI Data"},{"t":3,"p":1,"n":"AI Packages"},{"t":3,"p":1,"n":"Model\/Animation"},{"t":3,"p":1,"n":"Base Data"},{"t":3,"p":1,"n":"Inventory"},{"t":3,"p":1,"n":"Script"},{"t":3,"p":1,"n":"Def Pack List"},{"t":3,"p":1,"n":"Attack Data"},{"t":3,"p":1,"n":"Keywords"}]},{"t":3,"p":1,"n":"RNAM - Race"},{"t":3,"n":"SPCT - Count"},{"t":8,"s":1,"p":1,"n":"Actor Effects","d":1,"c":[{"t":3,"p":1,"n":"SPLO - Actor Effect"}]},{"t":6,"s":1,"p":1,"n":"Destructible","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"}]},{"t":7,"p":1,"n":"DAMC - Resistances","c":[{"t":6,"p":1,"n":"Resistance","c":[{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Value"}]}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":2,"p":1,"n":"DSTA - Sequence Name"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":5,"p":1,"n":"DMDC - Color Remapping Index"},{"t":3,"p":1,"n":"DMDS - Material Swap"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"WNAM - Skin"},{"t":3,"p":1,"n":"ANAM - Far away model"},{"t":3,"p":1,"n":"ATKR - Attack Race"},{"t":10,"p":1,"n":"Attacks","d":1,"c":[{"t":6,"p":1,"n":"Attack","c":[{"t":6,"p":1,"n":"ATKD - Attack Data","c":[{"t":5,"p":1,"n":"Damage Mult"},{"t":5,"p":1,"n":"Attack Chance"},{"t":3,"p":1,"n":"Attack Spell"},{"t":3,"p":1,"n":"Attack Flags"},{"t":5,"p":1,"n":"Attack Angle"},{"t":5,"p":1,"n":"Strike Angle"},{"t":5,"p":1,"n":"Stagger"},{"t":5,"p":1,"n":"Knockdown"},{"t":5,"p":1,"n":"Recovery Time"},{"t":5,"p":1,"n":"Action Points Mult"},{"t":3,"p":1,"n":"Stagger Offset"}]},{"t":2,"p":1,"n":"ATKE - Attack Event"},{"t":3,"p":1,"n":"ATKW - Weapon Slot"},{"t":3,"p":1,"n":"ATKS - Required Slot"},{"t":2,"p":1,"n":"ATKT - Description"}]}]},{"t":3,"p":1,"n":"SPOR - Spectator Override Package List"},{"t":3,"p":1,"n":"OCOR - Observe Dead Body Override Package List"},{"t":3,"p":1,"n":"GWOR - Guard Warn Override Package List"},{"t":3,"p":1,"n":"ECOR - Combat Override Package List"},{"t":3,"p":1,"n":"FCPL - Follower Command Package List"},{"t":3,"p":1,"n":"RCLR - Follower Elevator Package List"},{"t":3,"n":"PRKZ - Perk Count"},{"t":8,"s":1,"p":1,"n":"Perks","d":1,"c":[{"t":6,"p":1,"n":"PRKR - Perk","c":[{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Rank"}]}]},{"t":7,"p":1,"n":"PRPS - Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":3,"p":1,"n":"Actor Value"},{"t":5,"p":1,"n":"Value"}]}]},{"t":3,"p":1,"n":"FTYP - Forced Loc Ref Type"},{"t":3,"p":1,"n":"NTRM - Native Terminal"},{"t":3,"n":"COCT - Count"},{"t":10,"p":1,"n":"Items","d":1,"c":[{"t":6,"p":1,"n":"Item","c":[{"t":6,"p":1,"n":"CNTO - Item","c":[{"t":3,"p":1,"n":"Item"},{"t":3,"p":1,"n":"Count"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]},{"t":6,"s":1,"p":1,"n":"AIDT - AI Data","c":[{"t":3,"p":1,"n":"Aggression"},{"t":3,"p":1,"n":"Confidence"},{"t":3,"p":1,"n":"Energy Level"},{"t":3,"p":1,"n":"Responsibility"},{"t":3,"p":1,"n":"Mood"},{"t":3,"p":1,"n":"Assistance"},{"t":6,"p":1,"n":"Aggro","c":[{"t":3,"p":1,"n":"Aggro Radius Behavior"},{"t":3,"n":"Unknown"},{"t":3,"p":1,"n":"Warn"},{"t":3,"p":1,"n":"Warn\/Attack"},{"t":3,"p":1,"n":"Attack"}]},{"t":11,"n":"Unknown"}]},{"t":8,"s":1,"p":1,"n":"Packages","d":1,"c":[{"t":3,"p":1,"n":"PKID - Package"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":7,"p":1,"n":"APPR - Attach Parent Slots","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"Object Template","c":[{"t":3,"p":1,"n":"OBTE - Count"},{"t":8,"p":1,"n":"Combinations","c":[{"t":6,"p":1,"n":"Combination","c":[{"p":1,"n":"OBTF - Editor Only"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"p":1,"n":"OBTS - Object Mod Template Item","c":[{"t":3,"p":1,"n":"Include Count"},{"t":3,"p":1,"n":"Property Count"},{"t":3,"p":1,"n":"Level Min"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Level Max"},{"t":3,"p":1,"n":"ID"},{"t":3,"p":1,"n":"Default"},{"t":7,"p":1,"n":"Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":3,"p":1,"n":"Min Level For Ranks"},{"t":3,"p":1,"n":"Alt Levels Per Tier"},{"t":7,"p":1,"n":"Includes","c":[{"t":6,"p":1,"n":"Include","c":[{"t":3,"p":1,"n":"Mod"},{"t":3,"p":1,"n":"Attach Point Index"},{"t":3,"p":1,"n":"Optional"},{"t":3,"p":1,"n":"Don't Use All"}]}]},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":3,"p":1,"n":"Value Type"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Function Type"},{"t":3,"p":1,"n":"Property"},{"t":11,"n":"Value 1 - Unknown"},{"t":3,"p":1,"n":"Value 1 - Int"},{"t":5,"p":1,"n":"Value 1 - Float"},{"t":3,"p":1,"n":"Value 1 - Bool"},{"t":3,"p":1,"n":"Value 1 - FormID"},{"t":3,"p":1,"n":"Value 1 - Enum"},{"t":3,"p":1,"n":"Sound Level"},{"t":3,"p":1,"n":"Stagger Value"},{"t":3,"p":1,"n":"Hit Behaviour"},{"t":3,"p":1,"n":"Value 2 - Int"},{"t":5,"p":1,"n":"Value 2 - Float"},{"t":3,"p":1,"n":"Value 2 - Bool"},{"t":5,"p":1,"n":"Step"}]}]}]}]}]},{"p":1,"n":"STOP - Marker"}]},{"t":3,"p":1,"n":"CNAM - Class"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"SHRT - Short Name"},{"t":11,"n":"DATA - Marker"},{"t":6,"s":1,"p":1,"n":"DNAM - ","c":[{"t":3,"n":"Unknown"},{"t":3,"p":1,"n":"Far Away Model Distance"},{"t":3,"p":1,"n":"Geared Up Weapons"}]},{"t":8,"s":1,"p":1,"n":"Head Parts","d":1,"c":[{"t":3,"p":1,"n":"PNAM - Head Part"}]},{"t":3,"p":1,"n":"HCLF - Hair Color"},{"t":3,"p":1,"n":"BCLF - Facial Hair Color"},{"t":3,"p":1,"n":"ZNAM - Combat Style"},{"t":3,"p":1,"n":"GNAM - Gift Filter"},{"t":11,"n":"NAM5 - Unknown"},{"t":5,"p":1,"n":"NAM6 - Height Min"},{"t":5,"n":"NAM7 - Unused"},{"t":5,"p":1,"n":"NAM4 - Height Max"},{"t":6,"s":1,"p":1,"n":"MWGT - Weight","c":[{"t":5,"p":1,"n":"Thin"},{"t":5,"p":1,"n":"Muscular"},{"t":5,"p":1,"n":"Fat"}]},{"t":3,"p":1,"n":"NAM8 - Sound Level"},{"t":6,"s":1,"p":1,"n":"Actor Sounds","c":[{"t":3,"p":1,"n":"CS2H - Count"},{"t":10,"p":1,"n":"Sounds","c":[{"t":6,"p":1,"n":"Sound","c":[{"t":3,"p":1,"n":"CS2K - Keyword"},{"t":3,"p":1,"n":"CS2D - Sound"}]}]},{"p":1,"n":"CS2E - End Marker"},{"t":11,"p":1,"n":"CS2F - Finalize"}]},{"t":3,"p":1,"n":"CSCR - Inherits Sounds From"},{"t":3,"p":1,"n":"PFRN - Power Armor Stand"},{"t":3,"p":1,"n":"DOFT - Default Outfit"},{"t":3,"p":1,"n":"SOFT - Sleeping Outfit"},{"t":3,"p":1,"n":"DPLT - Default Package List"},{"t":3,"p":1,"n":"CRIF - Crime Faction"},{"t":3,"p":1,"n":"FTST - Head Texture"},{"t":6,"s":1,"p":1,"n":"QNAM - Texture lighting","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"},{"t":5,"p":1,"n":"Alpha"}]},{"t":7,"p":1,"n":"MSDK - Morph Keys","c":[{"t":3,"p":1,"n":"Key"}]},{"t":7,"p":1,"n":"MSDV - Morph Values","c":[{"t":5,"p":1,"n":"Value"}]},{"t":10,"p":1,"n":"Face Tinting Layers","d":1,"c":[{"t":6,"p":1,"n":"Layer","c":[{"t":6,"p":1,"n":"TETI - Index","c":[{"t":3,"p":1,"n":"Data Type"},{"t":3,"p":1,"n":"Index"}]},{"t":6,"p":1,"n":"TEND - Data","c":[{"t":3,"p":1,"n":"Value"},{"t":6,"p":1,"n":"Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"Template Color Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"MRSV - Body Morph Region Values","c":[{"t":5,"p":1,"n":"Head"},{"t":5,"p":1,"n":"Upper Torso"},{"t":5,"p":1,"n":"Arms"},{"t":5,"p":1,"n":"Lower Torso"},{"t":5,"p":1,"n":"Legs"}]},{"t":10,"p":1,"n":"Face Morphs","d":1,"c":[{"t":6,"p":1,"n":"Face Morph","c":[{"t":3,"p":1,"n":"FMRI - Index"},{"t":6,"p":1,"n":"FMRS - Values","c":[{"t":5,"p":1,"n":"Position - X"},{"t":5,"p":1,"n":"Position - Y"},{"t":5,"p":1,"n":"Position - Z"},{"t":5,"p":1,"n":"Rotation - X"},{"t":5,"p":1,"n":"Rotation - Y"},{"t":5,"p":1,"n":"Rotation - Z"},{"t":5,"p":1,"n":"Scale"},{"t":11,"n":"Unknown"}]}]}]},{"t":5,"p":1,"n":"FMIN - Facial Morph Intensity"},{"t":2,"p":1,"n":"ATTX - Activate Text Override"}]},{"t":1,"p":1,"n":"OMOD - Object Modification","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Include Count"},{"t":3,"p":1,"n":"Property Count"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Attach Point"},{"t":7,"p":1,"n":"Attach Parent Slots","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":7,"p":1,"n":"Items","c":[{"t":6,"p":1,"n":"Item","c":[{"t":11,"p":1,"n":"Value 1"},{"t":11,"p":1,"n":"Value 2"}]}]},{"t":7,"p":1,"n":"Includes","c":[{"t":6,"p":1,"n":"Include","c":[{"t":3,"p":1,"n":"Mod"},{"t":3,"p":1,"n":"Minimum Level"},{"t":3,"p":1,"n":"Optional"},{"t":3,"p":1,"n":"Don't Use All"}]}]},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":3,"p":1,"n":"Value Type"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Function Type"},{"t":3,"p":1,"n":"Property"},{"t":11,"n":"Value 1 - Unknown"},{"t":3,"p":1,"n":"Value 1 - Int"},{"t":5,"p":1,"n":"Value 1 - Float"},{"t":3,"p":1,"n":"Value 1 - Bool"},{"t":3,"p":1,"n":"Value 1 - FormID"},{"t":3,"p":1,"n":"Value 1 - Enum"},{"t":3,"p":1,"n":"Sound Level"},{"t":3,"p":1,"n":"Stagger Value"},{"t":3,"p":1,"n":"Hit Behaviour"},{"t":3,"p":1,"n":"Value 2 - Int"},{"t":5,"p":1,"n":"Value 2 - Float"},{"t":3,"p":1,"n":"Value 2 - Bool"},{"t":5,"p":1,"n":"Step"}]}]}]},{"t":7,"p":1,"n":"MNAM - Target OMOD Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":7,"p":1,"n":"FNAM - Filter Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":3,"p":1,"n":"LNAM - Loose Mod"},{"t":3,"p":1,"n":"NAM1 - Priority"},{"t":2,"p":1,"n":"FLTR - Filter"}]},{"t":1,"p":1,"n":"OTFT - Outfit","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":7,"p":1,"n":"INAM - Items","c":[{"t":3,"p":1,"n":"Item"}]}]},{"t":1,"n":"OVIS - Object Visibility Manager","d":1,"c":[{"t":8,"n":"Unknown","c":[{"t":6,"n":"Unknown","c":[{"t":3,"n":"INDX - Object"},{"t":6,"n":"DATA - Object Bounds","c":[{"t":5,"n":"X1"},{"t":5,"n":"Y1"},{"t":5,"n":"Z1"},{"t":5,"n":"X2"},{"t":5,"n":"Y2"},{"t":5,"n":"Z2"}]}]}]}]},{"t":1,"p":1,"n":"PACK - Package","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]},{"t":6,"p":1,"n":"Script Fragments","c":[{"t":3,"n":"Unknown"},{"t":3,"p":1,"n":"Flags"},{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]},{"t":7,"p":1,"n":"Fragments","c":[{"t":6,"p":1,"n":"Fragment","c":[{"t":3,"n":"Unknown"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]}]}]},{"t":6,"s":1,"p":1,"n":"PKDT - Pack Data","c":[{"t":3,"p":1,"n":"General Flags"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Interrupt Override"},{"t":3,"p":1,"n":"Preferred Speed"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Interrupt Flags"}]},{"t":6,"s":1,"p":1,"n":"PSDT - Schedule","c":[{"t":3,"p":1,"n":"Month"},{"t":3,"p":1,"n":"Day of week"},{"t":3,"p":1,"n":"Date"},{"t":3,"p":1,"n":"Hour"},{"t":3,"p":1,"n":"Minute"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Duration (minutes)"}]},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":6,"s":1,"p":1,"n":"Idle Animations","c":[{"t":3,"p":1,"n":"IDLF - Flags"},{"t":3,"p":1,"n":"IDLC - Animation Count"},{"t":5,"p":1,"n":"IDLT - Idle Timer Setting"},{"t":7,"p":1,"n":"IDLA - Animations","c":[{"t":3,"p":1,"n":"Animation"}]},{"t":11,"n":"IDLB - Unknown"}]},{"t":3,"p":1,"n":"CNAM - Combat Style"},{"t":3,"p":1,"n":"QNAM - Owner Quest"},{"t":6,"s":1,"p":1,"n":"PKCU - Counter","c":[{"t":3,"p":1,"n":"Data Input Count"},{"t":3,"p":1,"n":"Package Template"},{"t":3,"p":1,"n":"Version Counter (autoincremented)"}]},{"t":6,"s":1,"p":1,"n":"Package Data","c":[{"t":8,"p":1,"n":"Data Input Values","c":[{"t":6,"p":1,"n":"Value","c":[{"t":2,"p":1,"n":"ANAM - Type"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Bool"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"n":"BNAM - Unknown"},{"t":8,"p":1,"n":"Topic","c":[{"t":6,"p":1,"n":"PDTO - Topic Data","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Topic"},{"t":2,"p":1,"n":"Subtype"}]}]},{"t":6,"p":1,"n":"PLDT - Location","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Cell"},{"t":11,"p":1,"n":"Near Package Start Location"},{"t":11,"p":1,"n":"Near Editor Location"},{"t":3,"p":1,"n":"Object ID"},{"t":3,"p":1,"n":"Object Type"},{"t":3,"p":1,"n":"Keyword"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Ref Alias"},{"t":3,"p":1,"n":"Loc Alias"},{"t":3,"p":1,"n":"Interrupt Data"},{"t":3,"p":1,"n":"Packdata Target"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Ref Collection Alias"},{"t":3,"p":1,"n":"Radius"},{"t":3,"p":1,"n":"Collection Index"}]},{"t":6,"p":1,"n":"PTDA - Target","c":[{"t":6,"p":1,"n":"Target Data","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Object ID"},{"t":3,"p":1,"n":"Object Type"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Interrupt Data"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Count \/ Distance"}]}]},{"t":11,"n":"TPIC - Unknown"}]}]},{"t":8,"p":1,"n":"Data Inputs","c":[{"t":6,"p":1,"n":"Data Input","c":[{"t":3,"p":1,"n":"UNAM - Index"},{"t":2,"p":1,"n":"BNAM - Name"},{"t":3,"p":1,"n":"PNAM - Flags"}]}]}]},{"t":11,"n":"XNAM - Marker"},{"t":6,"s":1,"p":1,"n":"Procedure Tree","c":[{"t":8,"p":1,"n":"Branches","c":[{"t":6,"p":1,"n":"Branch","c":[{"t":2,"p":1,"n":"ANAM - Branch Type"},{"t":3,"p":1,"n":"CITC - Condition Count"},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":6,"p":1,"n":"PRCB - Root","c":[{"t":3,"p":1,"n":"Branch Count"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"PNAM - Procedure Type"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":8,"p":1,"n":"Data Input Indexes","c":[{"t":3,"p":1,"n":"PKC2 - Index"}]},{"t":8,"p":1,"n":"Flags Override","c":[{"t":6,"p":1,"n":"PFO2 - Data","c":[{"t":3,"p":1,"n":"Set General Flags"},{"t":3,"p":1,"n":"Clear General Flags"},{"t":3,"p":1,"n":"Set Interrupt Flags"},{"t":3,"p":1,"n":"Clear Interrupt Flags"},{"t":3,"p":1,"n":"Preferred Speed Override"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Unknown","c":[{"t":11,"n":"PFOR - Unknown"}]}]}]}]},{"t":8,"s":1,"p":1,"n":"Data Inputs","d":1,"c":[{"t":6,"p":1,"n":"Data Input","c":[{"t":3,"p":1,"n":"UNAM - Index"},{"t":2,"p":1,"n":"BNAM - Name"},{"t":3,"p":1,"n":"PNAM - Flags"}]}]},{"t":6,"s":1,"p":1,"n":"OnBegin","c":[{"p":1,"n":"POBA - OnBegin Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":8,"p":1,"n":"Topic","c":[{"t":6,"p":1,"n":"PDTO - Topic Data","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Topic"},{"t":2,"p":1,"n":"Subtype"}]}]}]},{"t":6,"s":1,"p":1,"n":"OnEnd","c":[{"p":1,"n":"POEA - OnEnd Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":8,"p":1,"n":"Topic","c":[{"t":6,"p":1,"n":"PDTO - Topic Data","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Topic"},{"t":2,"p":1,"n":"Subtype"}]}]}]},{"t":6,"s":1,"p":1,"n":"OnChange","c":[{"p":1,"n":"POCA - OnChange Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":8,"p":1,"n":"Topic","c":[{"t":6,"p":1,"n":"PDTO - Topic Data","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Topic"},{"t":2,"p":1,"n":"Subtype"}]}]}]}]},{"t":1,"p":1,"n":"PARW - Placed Arrow","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Projectile"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":3,"n":"XASP - Unknown"},{"t":11,"n":"XATP - Unknown"},{"t":3,"p":1,"n":"XAMC - Ammo Count"},{"p":1,"n":"XLKT - Linked Ref Transient"},{"t":3,"p":1,"n":"XLYR - Layer"},{"t":3,"p":1,"n":"XMSP - Material Swap"},{"t":3,"p":1,"n":"XRFG - Reference Group"},{"t":11,"n":"XCVR - Unknown"},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":6,"s":1,"p":1,"n":"XOWN - Owner","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Flags"}]},{"t":3,"p":1,"n":"XRNK - Owner Faction Rank"},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]},{"t":2,"p":1,"n":"MNAM - Comments"}]},{"t":1,"p":1,"n":"PBAR - Placed Barrier","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Projectile"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":3,"n":"XASP - Unknown"},{"t":11,"n":"XATP - Unknown"},{"t":3,"p":1,"n":"XAMC - Ammo Count"},{"p":1,"n":"XLKT - Linked Ref Transient"},{"t":3,"p":1,"n":"XLYR - Layer"},{"t":3,"p":1,"n":"XMSP - Material Swap"},{"t":3,"p":1,"n":"XRFG - Reference Group"},{"t":11,"n":"XCVR - Unknown"},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":6,"s":1,"p":1,"n":"XOWN - Owner","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Flags"}]},{"t":3,"p":1,"n":"XRNK - Owner Faction Rank"},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]},{"t":2,"p":1,"n":"MNAM - Comments"}]},{"t":1,"p":1,"n":"PBEA - Placed Beam","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Projectile"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":3,"n":"XASP - Unknown"},{"t":11,"n":"XATP - Unknown"},{"t":3,"p":1,"n":"XAMC - Ammo Count"},{"p":1,"n":"XLKT - Linked Ref Transient"},{"t":3,"p":1,"n":"XLYR - Layer"},{"t":3,"p":1,"n":"XMSP - Material Swap"},{"t":3,"p":1,"n":"XRFG - Reference Group"},{"t":11,"n":"XCVR - Unknown"},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":6,"s":1,"p":1,"n":"XOWN - Owner","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Flags"}]},{"t":3,"p":1,"n":"XRNK - Owner Faction Rank"},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]},{"t":2,"p":1,"n":"MNAM - Comments"}]},{"t":1,"p":1,"n":"PCON - Placed Cone\/Voice","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Projectile"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":3,"n":"XASP - Unknown"},{"t":11,"n":"XATP - Unknown"},{"t":3,"p":1,"n":"XAMC - Ammo Count"},{"p":1,"n":"XLKT - Linked Ref Transient"},{"t":3,"p":1,"n":"XLYR - Layer"},{"t":3,"p":1,"n":"XMSP - Material Swap"},{"t":3,"p":1,"n":"XRFG - Reference Group"},{"t":11,"n":"XCVR - Unknown"},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":6,"s":1,"p":1,"n":"XOWN - Owner","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Flags"}]},{"t":3,"p":1,"n":"XRNK - Owner Faction Rank"},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]},{"t":2,"p":1,"n":"MNAM - Comments"}]},{"t":1,"p":1,"n":"PERK - Perk","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]},{"t":6,"p":1,"n":"Script Fragments","c":[{"t":3,"n":"Unknown"},{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]},{"t":7,"p":1,"n":"Fragments","c":[{"t":6,"p":1,"n":"Fragment","c":[{"t":3,"p":1,"n":"Fragment Index"},{"t":3,"n":"Unknown"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]}]}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"DESC - Description"},{"t":2,"p":1,"n":"ICON - Image"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Trait"},{"t":3,"p":1,"n":"Level"},{"t":3,"p":1,"n":"Num Ranks"},{"t":3,"p":1,"n":"Playable"},{"t":3,"p":1,"n":"Hidden"}]},{"t":3,"p":1,"n":"SNAM - Sound"},{"t":3,"p":1,"n":"NNAM - Next Perk"},{"t":2,"p":1,"n":"FNAM - SWF"},{"t":10,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":6,"p":1,"n":"PRKE - Header","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Rank"},{"t":3,"p":1,"n":"Priority"}]},{"t":6,"p":1,"n":"Quest + Stage","c":[{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"Ability"},{"t":6,"p":1,"n":"Entry Point","c":[{"t":3,"p":1,"n":"Entry Point"},{"t":3,"p":1,"n":"Function"},{"t":3,"p":1,"n":"Perk Condition Tab Count"}]},{"t":10,"p":1,"n":"Perk Conditions","c":[{"t":6,"p":1,"n":"Perk Condition","c":[{"t":3,"p":1,"n":"PRKC - Run On (Tab Index)"},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]},{"t":6,"p":1,"n":"Function Parameters","c":[{"t":3,"p":1,"n":"EPFT - Type"},{"t":3,"p":1,"n":"EPFB - Perk Entry ID (unique)"},{"t":2,"p":1,"n":"EPF2 - Button Label"},{"t":6,"p":1,"n":"EPF3 - Script Flags","c":[{"t":3,"p":1,"n":"Script Flags"},{"t":11,"n":"Unknown"}]},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"Float"},{"t":6,"p":1,"n":"Float, Float","c":[{"t":5,"p":1,"n":"Float 1"},{"t":5,"p":1,"n":"Float 2"}]},{"t":3,"p":1,"n":"Leveled Item"},{"t":3,"p":1,"n":"Spell"},{"t":2,"p":1,"n":"Text"},{"t":6,"p":1,"n":"Actor Value, Float","c":[{"t":3,"p":1,"n":"Actor Value"},{"t":5,"p":1,"n":"Float"}]}]},{"p":1,"n":"PRKF - End Marker"}]}]}]},{"t":1,"p":1,"n":"PFLA - Placed Flame","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Projectile"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":3,"n":"XASP - Unknown"},{"t":11,"n":"XATP - Unknown"},{"t":3,"p":1,"n":"XAMC - Ammo Count"},{"p":1,"n":"XLKT - Linked Ref Transient"},{"t":3,"p":1,"n":"XLYR - Layer"},{"t":3,"p":1,"n":"XMSP - Material Swap"},{"t":3,"p":1,"n":"XRFG - Reference Group"},{"t":11,"n":"XCVR - Unknown"},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":6,"s":1,"p":1,"n":"XOWN - Owner","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Flags"}]},{"t":3,"p":1,"n":"XRNK - Owner Faction Rank"},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]},{"t":2,"p":1,"n":"MNAM - Comments"}]},{"t":1,"p":1,"n":"PGRE - Placed Projectile","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Projectile"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":3,"n":"XASP - Unknown"},{"t":11,"n":"XATP - Unknown"},{"t":3,"p":1,"n":"XAMC - Ammo Count"},{"p":1,"n":"XLKT - Linked Ref Transient"},{"t":3,"p":1,"n":"XLYR - Layer"},{"t":3,"p":1,"n":"XMSP - Material Swap"},{"t":3,"p":1,"n":"XRFG - Reference Group"},{"t":11,"n":"XCVR - Unknown"},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":6,"s":1,"p":1,"n":"XOWN - Owner","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Flags"}]},{"t":3,"p":1,"n":"XRNK - Owner Faction Rank"},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]},{"t":2,"p":1,"n":"MNAM - Comments"}]},{"t":1,"p":1,"n":"PHZD - Placed Hazard","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Projectile"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":3,"n":"XASP - Unknown"},{"t":11,"n":"XATP - Unknown"},{"t":3,"p":1,"n":"XAMC - Ammo Count"},{"p":1,"n":"XLKT - Linked Ref Transient"},{"t":3,"p":1,"n":"XLYR - Layer"},{"t":3,"p":1,"n":"XMSP - Material Swap"},{"t":3,"p":1,"n":"XRFG - Reference Group"},{"t":11,"n":"XCVR - Unknown"},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":6,"s":1,"p":1,"n":"XOWN - Owner","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Flags"}]},{"t":3,"p":1,"n":"XRNK - Owner Faction Rank"},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]},{"t":2,"p":1,"n":"MNAM - Comments"}]},{"t":1,"p":1,"n":"PKIN - Pack-In","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FLTR - Filter"},{"t":3,"p":1,"n":"CNAM - Cell"},{"t":3,"p":1,"n":"VNAM - Version"}]},{"t":1,"p":1,"n":"PMIS - Placed Missile","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Projectile"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":3,"n":"XASP - Unknown"},{"t":11,"n":"XATP - Unknown"},{"t":3,"p":1,"n":"XAMC - Ammo Count"},{"p":1,"n":"XLKT - Linked Ref Transient"},{"t":3,"p":1,"n":"XLYR - Layer"},{"t":3,"p":1,"n":"XMSP - Material Swap"},{"t":3,"p":1,"n":"XRFG - Reference Group"},{"t":11,"n":"XCVR - Unknown"},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":6,"s":1,"p":1,"n":"XOWN - Owner","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Flags"}]},{"t":3,"p":1,"n":"XRNK - Owner Faction Rank"},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]},{"t":2,"p":1,"n":"MNAM - Comments"}]},{"t":1,"p":1,"n":"PROJ - Projectile","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]},{"t":6,"s":1,"p":1,"n":"Destructible","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"}]},{"t":7,"p":1,"n":"DAMC - Resistances","c":[{"t":6,"p":1,"n":"Resistance","c":[{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Value"}]}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":2,"p":1,"n":"DSTA - Sequence Name"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":5,"p":1,"n":"DMDC - Color Remapping Index"},{"t":3,"p":1,"n":"DMDS - Material Swap"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":11,"n":"DATA - Unused"},{"t":6,"s":1,"p":1,"n":"DNAM - Data","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Type"},{"t":5,"p":1,"n":"Gravity"},{"t":5,"p":1,"n":"Speed"},{"t":5,"p":1,"n":"Range"},{"t":3,"p":1,"n":"Light"},{"t":3,"p":1,"n":"Muzzle Flash - Light"},{"t":5,"p":1,"n":"Explosion - Alt. Trigger - Proximity"},{"t":5,"p":1,"n":"Explosion - Alt. Trigger - Timer"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Sound"},{"t":5,"p":1,"n":"Muzzle Flash - Duration"},{"t":5,"p":1,"n":"Fade Duration"},{"t":5,"p":1,"n":"Impact Force"},{"t":3,"p":1,"n":"Sound - Countdown"},{"t":3,"p":1,"n":"Sound - Disable"},{"t":3,"p":1,"n":"Default Weapon Source"},{"t":5,"p":1,"n":"Cone Spread"},{"t":5,"p":1,"n":"Collision Radius"},{"t":5,"p":1,"n":"Lifetime"},{"t":5,"p":1,"n":"Relaunch Interval"},{"t":3,"p":1,"n":"Decal Data"},{"t":3,"p":1,"n":"Collision Layer"},{"t":3,"p":1,"n":"Tracer Frequency"},{"t":3,"p":1,"n":"VATS Projectile"}]},{"t":6,"s":1,"p":1,"n":"Muzzle Flash Model","c":[{"t":2,"p":1,"n":"NAM1 - Model Filename"},{"t":11,"p":1,"n":"NAM2 - Texture Files Hashes"}]},{"t":3,"p":1,"n":"VNAM - Sound Level"}]},{"t":1,"p":1,"n":"QUST - Quest","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]},{"t":6,"p":1,"n":"Script Fragments","c":[{"t":3,"n":"Unknown"},{"t":3,"p":1,"n":"fragmentCount"},{"t":2,"p":1,"n":"scriptName"},{"t":6,"p":1,"n":"Script Data","c":[{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]},{"t":11,"n":"Unused"},{"t":7,"p":1,"n":"Fragments","c":[{"t":6,"p":1,"n":"Fragment","c":[{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"n":"Unknown"},{"t":3,"p":1,"n":"Quest Stage Index"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]}]},{"t":7,"p":1,"n":"Aliases","c":[{"t":6,"p":1,"n":"Alias","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Alias Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]}]}]}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"DNAM - General","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Priority"},{"t":3,"p":1,"n":"Form Version"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Type"}]},{"t":2,"p":1,"n":"ENAM - Event"},{"t":3,"p":1,"n":"LNAM - Location"},{"t":3,"p":1,"n":"XNAM - Quest Completion XP"},{"t":8,"s":1,"p":1,"n":"Text Display Globals","d":1,"c":[{"t":3,"p":1,"n":"QTGL - Global"}]},{"t":2,"p":1,"n":"FLTR - Filter"},{"t":6,"s":1,"p":1,"n":"Quest Dialogue Conditions","c":[{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]},{"p":1,"n":"NEXT - Marker"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":10,"p":1,"n":"Stages","d":1,"c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"INDX - Stage Index","c":[{"t":3,"p":1,"n":"Stage Index"},{"t":3,"p":1,"n":"Flags"},{"t":3,"n":"Unknown"}]},{"t":8,"p":1,"n":"Log Entries","c":[{"t":6,"p":1,"n":"Log Entry","c":[{"t":3,"p":1,"n":"QSDT - Stage Flags"},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":2,"p":1,"n":"NAM2 - Note"},{"t":2,"p":1,"n":"CNAM - Log Entry"},{"t":3,"p":1,"n":"NAM0 - Next Quest"}]}]}]}]},{"t":8,"s":1,"p":1,"n":"Objectives","d":1,"c":[{"t":6,"p":1,"n":"Objective","c":[{"t":3,"p":1,"n":"QOBJ - Objective Index"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":2,"p":1,"n":"NNAM - Display Text"},{"t":8,"p":1,"n":"Targets","c":[{"t":6,"p":1,"n":"Target","c":[{"t":6,"p":1,"n":"QSTA - Target","c":[{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Keyword"}]},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]}]}]},{"t":11,"n":"ANAM - Aliases Marker"},{"t":8,"s":1,"p":1,"n":"Aliases","d":1,"c":[{"t":6,"p":1,"n":"Alias","c":[{"t":3,"p":1,"n":"ALST - Reference Alias ID"},{"t":2,"p":1,"n":"ALID - Alias Name"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":3,"p":1,"n":"ALFI - Force Into Alias When Filled"},{"t":3,"p":1,"n":"ALFR - Forced Reference"},{"t":3,"p":1,"n":"ALUA - Unique Actor"},{"t":6,"p":1,"n":"Location Alias Reference","c":[{"t":3,"p":1,"n":"ALFA - Alias"},{"t":3,"p":1,"n":"KNAM - Keyword"},{"t":3,"p":1,"n":"ALRT - Ref Type"}]},{"t":6,"p":1,"n":"External Alias Reference","c":[{"t":3,"p":1,"n":"ALEQ - Quest"},{"t":3,"p":1,"n":"ALEA - Alias"}]},{"t":6,"p":1,"n":"Create Reference to Object","c":[{"t":3,"p":1,"n":"ALCO - Object"},{"t":6,"p":1,"n":"ALCA - Alias","c":[{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Create"}]},{"t":3,"p":1,"n":"ALCL - Level"}]},{"t":6,"p":1,"n":"Find Matching Reference Near Alias","c":[{"t":3,"p":1,"n":"ALNA - Alias"},{"t":3,"p":1,"n":"ALNT - Type"}]},{"t":6,"p":1,"n":"Find Matching Reference From Event","c":[{"t":2,"p":1,"n":"ALFE - From Event"},{"t":11,"p":1,"n":"ALFD - Event Data"}]},{"t":3,"p":1,"n":"ALCC - Closest To Alias"},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":3,"p":1,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":3,"p":1,"n":"COCT - Count"},{"t":10,"p":1,"n":"Items","c":[{"t":6,"p":1,"n":"Item","c":[{"t":6,"p":1,"n":"CNTO - Item","c":[{"t":3,"p":1,"n":"Item"},{"t":3,"p":1,"n":"Count"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]},{"t":3,"p":1,"n":"SPOR - Spectator override package list"},{"t":3,"p":1,"n":"OCOR - Observe dead body override package list"},{"t":3,"p":1,"n":"GWOR - Guard warn override package list"},{"t":3,"p":1,"n":"ECOR - Combat override package list"},{"t":7,"p":1,"n":"ALLA - Linked Aliases","c":[{"t":6,"p":1,"n":"Linked Alias","c":[{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Alias"}]}]},{"t":3,"p":1,"n":"ALDN - Display Name"},{"t":3,"p":1,"n":"ALFV - Forced Voice"},{"t":3,"p":1,"n":"ALDI - Death Item"},{"t":8,"p":1,"n":"Alias Spells","c":[{"t":3,"p":1,"n":"ALSP - Spell"}]},{"t":8,"p":1,"n":"Alias Factions","c":[{"t":3,"p":1,"n":"ALFC - Faction"}]},{"t":8,"p":1,"n":"Alias Package Data","c":[{"t":3,"p":1,"n":"ALPC - Package"}]},{"t":3,"p":1,"n":"VTCK - Voice Types"},{"p":1,"n":"ALED - Alias End"}]}]},{"t":2,"p":1,"n":"NNAM - Description"},{"t":3,"p":1,"n":"GNAM - Quest Group"},{"t":2,"p":1,"n":"SNAM - SWF File"}]},{"t":1,"n":"RACE - Race","c":[{"t":2,"n":"EDID - Editor ID"},{"t":3,"n":"STCP - Sound"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":3,"n":"SPCT - Count"},{"t":8,"n":"Actor Effects","c":[{"t":3,"n":"SPLO - Actor Effect"}]},{"t":3,"n":"WNAM - Skin"},{"t":6,"n":"BOD2 - Biped Body Template","c":[{"t":3,"n":"First Person Flags"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":7,"n":"PRPS - Properties","c":[{"t":6,"n":"Property","c":[{"t":3,"n":"Actor Value"},{"t":5,"n":"Value"}]}]},{"t":7,"n":"APPR - Attach Parent Slots","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"DATA - Data","c":[{"t":5,"n":"Male Height"},{"t":5,"n":"Female Height"},{"t":6,"n":"Male Default Weight","c":[{"t":5,"n":"Thin"},{"t":5,"n":"Muscular"},{"t":5,"n":"Fat"}]},{"t":6,"n":"Female Default Weight","c":[{"t":5,"n":"Thin"},{"t":5,"n":"Muscular"},{"t":5,"n":"Fat"}]},{"t":3,"n":"Flags"},{"t":5,"n":"Acceleration Rate"},{"t":5,"n":"Deceleration Rate"},{"t":3,"n":"Size"},{"t":11,"n":"Unknown"},{"t":5,"n":"Injured Health Pct"},{"t":3,"n":"Shield Biped Object"},{"t":3,"n":"Beard Biped Object"},{"t":3,"n":"Body Biped Object"},{"t":5,"n":"Aim Angle Tolerance"},{"t":5,"n":"Flight Radius"},{"t":5,"n":"Angular Acceleration Rate"},{"t":5,"n":"Angular Tolerance"},{"t":3,"n":"Flags 2"},{"t":3,"n":"Pipboy Biped Object"},{"t":3,"n":"XP Value"},{"t":5,"n":"Severable - Debris Scale"},{"t":3,"n":"Severable - Debris Count"},{"t":3,"n":"Severable - Decal Count"},{"t":5,"n":"Explodable - Debris Scale"},{"t":3,"n":"Explodable - Debris Count"},{"t":3,"n":"Explodable - Decal Count"},{"t":3,"n":"Severable - Explosion"},{"t":3,"n":"Severable - Debris"},{"t":3,"n":"Severable - Impact DataSet"},{"t":3,"n":"Explodable - Explosion"},{"t":3,"n":"Explodable - Debris"},{"t":3,"n":"Explodable - Impact DataSet"},{"t":5,"n":"OnCripple - Debris Scale"},{"t":3,"n":"OnCripple - Debris Count"},{"t":3,"n":"OnCripple - Decal Count"},{"t":3,"n":"OnCripple - Explosion"},{"t":3,"n":"OnCripple - Debris"},{"t":3,"n":"OnCripple - Impact DataSet"},{"t":3,"n":"Explodable - Subsegment Explosion"},{"t":5,"n":"Orientation Limits - Pitch"},{"t":5,"n":"Orientation Limits - Roll"}]},{"n":"MNAM - Male Marker"},{"t":2,"n":"ANAM - Male Skeletal Model"},{"t":11,"n":"MODT - Texture Files Hashes"},{"n":"FNAM - Female Marker"},{"t":2,"n":"ANAM - Female Skeletal Model"},{"n":"NAM2 - Marker NAM2 #1"},{"t":8,"n":"Movement Type Names","c":[{"t":2,"n":"MTNM - Name"}]},{"t":7,"n":"VTCK - Voices","c":[{"t":3,"n":"Voice"}]},{"t":7,"n":"HCLF - Default Hair Colors","c":[{"t":3,"n":"Default Hair Color"}]},{"t":3,"n":"TINL - Total Number of Tints in List"},{"t":5,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"n":"UNAM - FaceGen - Face clamp"},{"t":3,"n":"ATKR - Attack Race"},{"t":10,"n":"Attacks","c":[{"t":6,"n":"Attack","c":[{"t":6,"n":"ATKD - Attack Data","c":[{"t":5,"n":"Damage Mult"},{"t":5,"n":"Attack Chance"},{"t":3,"n":"Attack Spell"},{"t":3,"n":"Attack Flags"},{"t":5,"n":"Attack Angle"},{"t":5,"n":"Strike Angle"},{"t":5,"n":"Stagger"},{"t":5,"n":"Knockdown"},{"t":5,"n":"Recovery Time"},{"t":5,"n":"Action Points Mult"},{"t":3,"n":"Stagger Offset"}]},{"t":2,"n":"ATKE - Attack Event"},{"t":3,"n":"ATKW - Weapon Slot"},{"t":3,"n":"ATKS - Required Slot"},{"t":2,"n":"ATKT - Description"}]}]},{"t":6,"n":"Body Data","c":[{"n":"NAM1 - Body Data Marker"},{"t":6,"n":"Male Body Data","c":[{"n":"MNAM - Male Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":11,"n":"MODT - Texture Files Hashes"},{"t":3,"n":"MODS - Material Swap"},{"t":5,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]}]}]}]},{"t":6,"n":"Female Body Data","c":[{"n":"FNAM - Female Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":11,"n":"MODT - Texture Files Hashes"},{"t":3,"n":"MODS - Material Swap"},{"t":5,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]}]}]}]}]},{"t":3,"n":"GNAM - Body Part Data"},{"n":"NAM2 - Marker NAM2 #2"},{"n":"NAM3 - Marker NAM3 #3"},{"t":6,"n":"Male Behavior Graph","c":[{"n":"MNAM - Male Data Marker"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":11,"n":"MODT - Texture Files Hashes"},{"t":3,"n":"MODS - Material Swap"},{"t":5,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]}]},{"t":6,"n":"Female Behavior Graph","c":[{"n":"FNAM - Female Data Marker"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":11,"n":"MODT - Texture Files Hashes"},{"t":3,"n":"MODS - Material Swap"},{"t":5,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]}]},{"t":3,"n":"NAM4 - Impact Material Type"},{"t":3,"n":"NAM5 - Impact Data Set"},{"t":3,"n":"NAM7 - Dismember Blood Art"},{"t":3,"n":"CNAM - Meat Cap TextureSet"},{"t":3,"n":"NAM2 - Collar TextureSet"},{"t":3,"n":"ONAM - Sound - Open Corpse"},{"t":3,"n":"LNAM - Sound - Close Corpse"},{"t":8,"n":"Biped Object Names","c":[{"t":2,"n":"NAME - Name"}]},{"t":7,"n":"RBPC - Biped Object Conditions","c":[{"t":3,"n":"Slot 30+"}]},{"t":10,"n":"Movement Data Overrides","c":[{"t":6,"n":"Override","c":[{"t":3,"n":"MTYP - Movement Type"},{"t":6,"n":"SPED - Movement Data","c":[{"t":5,"n":"Unknown"},{"t":5,"n":"Walk - Left"},{"t":5,"n":"Run - Left"},{"t":5,"n":"Walk - Right"},{"t":5,"n":"Run - Right"},{"t":5,"n":"Walk - Forward"},{"t":5,"n":"Run - Forward"},{"t":5,"n":"Sprint - Forward"},{"t":5,"n":"Walk - Back"},{"t":5,"n":"Run - Back"},{"t":5,"n":"Standing - Pitch"},{"t":5,"n":"Walk - Pitch"},{"t":5,"n":"Run - Pitch"},{"t":5,"n":"Sprint - Pitch"},{"t":5,"n":"Standing - Yaw"},{"t":5,"n":"Walk - Yaw"},{"t":5,"n":"Run - Yaw"},{"t":5,"n":"Sprint - Yaw"}]}]}]},{"t":3,"n":"VNAM - Equipment Flags"},{"t":8,"n":"Equip Slots","c":[{"t":6,"n":"Equip Slot","c":[{"t":3,"n":"QNAM - Equip Slot"},{"t":2,"n":"ZNAM - Node"}]}]},{"t":3,"n":"UNWP - Unarmed Weapon"},{"t":8,"n":"Phoneme Target Names","c":[{"t":2,"n":"PHTN - Name"}]},{"t":6,"n":"FaceFX Phonemes","c":[{"t":6,"n":"IY","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"IH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"EH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"EY","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"AE","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"AA","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"AW","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"AY","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"AH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"AO","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"OY","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"OW","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"UH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"UW","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"ER","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"AX","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"S","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"SH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"Z","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"ZH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"F","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"TH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"V","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"DH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"M","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"N","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"NG","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"L","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"R","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"W","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"Y","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"HH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"B","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"D","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"JH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"G","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"P","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"T","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"K","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"CH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"SIL","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"SHOTSIL","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"FLAP","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"},{"t":11,"n":"Unknown"}]}]}]},{"t":3,"n":"WKMV - Base Movement Defaults - Default"},{"t":3,"n":"SWMV - Base Movement Defaults - Swim"},{"t":3,"n":"FLMV - Base Movement Defaults - Fly"},{"t":3,"n":"SNMV - Base Movement Defaults - Sneak"},{"n":"NAM0 - Head Data Marker"},{"n":"MNAM - Male Data Marker"},{"t":6,"n":"NNAM - Male Neck Fat Adjustments Scale","c":[{"t":11,"n":"Unknown"},{"t":5,"n":"X"},{"t":5,"n":"Y"}]},{"t":10,"n":"Male Head Parts","c":[{"t":6,"n":"Head Part","c":[{"t":3,"n":"INDX - Head Part Number"},{"t":3,"n":"HEAD - Head"}]}]},{"t":8,"n":"Male Race Presets","c":[{"t":3,"n":"RPRM - Preset NPC"}]},{"t":8,"n":"Male Hair Colors","c":[{"t":3,"n":"AHCM - Hair Color"}]},{"t":8,"n":"Male Face Details","c":[{"t":3,"n":"FTSM - Texture Set"}]},{"t":3,"n":"DFTM - Male Default Face Texture"},{"t":8,"n":"Male Tint Layers","c":[{"t":6,"n":"Group","c":[{"t":2,"n":"TTGP - Group Name"},{"t":8,"n":"Options","c":[{"t":6,"n":"Option","c":[{"t":6,"n":"TETI - Index","c":[{"t":11,"n":"Unknown"},{"t":3,"n":"Index"}]},{"t":2,"n":"TTGP - Name"},{"t":11,"n":"TTEF - Unknown"},{"t":8,"n":"Conditions","c":[{"t":6,"n":"Condition","c":[{"t":6,"n":"CTDA - ","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"n":"Comparison Value - Float"},{"t":3,"n":"Comparison Value - Global"},{"t":3,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"n":"None"},{"t":3,"n":"Integer"},{"t":5,"n":"Float"},{"t":3,"n":"Actor"},{"t":3,"n":"Actor Base"},{"t":3,"n":"Actor Value"},{"t":3,"n":"Player Action"},{"t":3,"n":"Alias"},{"t":3,"n":"Alignment"},{"t":3,"n":"Association Type"},{"t":3,"n":"Axis"},{"t":3,"n":"Casting Type"},{"t":3,"n":"Cell"},{"t":3,"n":"Class"},{"t":3,"n":"Crime Type"},{"t":3,"n":"Critical Stage"},{"t":3,"n":"Encounter Zone"},{"t":3,"n":"Equip Type"},{"t":3,"n":"Event"},{"t":3,"n":"Event Data"},{"t":3,"n":"Faction"},{"t":3,"n":"Form List"},{"t":3,"n":"Form Type"},{"t":3,"n":"Furniture"},{"t":3,"n":"Furniture Anim"},{"t":3,"n":"Furniture Entry"},{"t":3,"n":"Global"},{"t":3,"n":"Idle"},{"t":3,"n":"Inventory Object"},{"t":3,"n":"Keyword"},{"t":3,"n":"Location"},{"t":3,"n":"Base Effect"},{"t":3,"n":"Effect Item"},{"t":3,"n":"Misc Stat"},{"t":3,"n":"Object Reference"},{"t":3,"n":"Owner"},{"t":3,"n":"Package"},{"t":3,"n":"Packdata ID"},{"t":3,"n":"Perk"},{"t":3,"n":"Quest"},{"t":3,"n":"Quest Stage"},{"t":3,"n":"Race"},{"t":3,"n":"Referenceable Object"},{"t":3,"n":"Location Ref Type"},{"t":3,"n":"Region"},{"t":3,"n":"Scene"},{"t":3,"n":"Sex"},{"t":3,"n":"Shout"},{"t":11,"n":"Variable Name (unused)"},{"t":3,"n":"VATS Value Function"},{"t":3,"n":"VATS Value Param (unused)"},{"t":3,"n":"Voice Type"},{"t":3,"n":"Ward State"},{"t":3,"n":"Weather"},{"t":3,"n":"Worldspace"},{"t":3,"n":"Damage Type"},{"t":3,"n":"Weapon"},{"t":3,"n":"Weapon List"},{"t":3,"n":"Target"},{"t":3,"n":"Target List"},{"t":3,"n":"Target Part"},{"t":3,"n":"VATS Action"},{"t":3,"n":"Critical Effect"},{"t":3,"n":"Critical Effect List"},{"t":3,"n":"Weapon Type"},{"t":3,"n":"Projectile Type"},{"t":3,"n":"Delivery Type"},{"t":3,"n":"Run On"},{"t":3,"n":"Reference"},{"t":3,"n":"Parameter #3"}]},{"t":2,"n":"CIS1 - Parameter #1"},{"t":2,"n":"CIS2 - Parameter #2"}]}]},{"t":8,"n":"Textures","c":[{"t":2,"n":"TTET - Texture"}]},{"t":11,"n":"TTEB - Unknown"},{"t":7,"n":"TTEC - Template Colors","c":[{"t":6,"n":"Template Color","c":[{"t":3,"n":"Color"},{"t":5,"n":"Alpha"},{"t":3,"n":"Template Index"},{"t":11,"n":"Unknown"}]}]},{"t":5,"n":"TTED - Unknown"}]}]},{"t":11,"n":"TTGE - Group End"}]}]},{"t":8,"n":"Male Morph Groups","c":[{"t":6,"n":"Morph Group","c":[{"t":2,"n":"MPGN - Name"},{"t":3,"n":"MPPC - Count"},{"t":8,"n":"Morph Presets","c":[{"t":6,"n":"Morph Preset","c":[{"t":3,"n":"MPPI - Index"},{"t":2,"n":"MPPN - Name"},{"t":2,"n":"MPPM - Unknown"},{"t":3,"n":"MPPT - Texture"},{"t":11,"n":"MPPF - Unknown"}]}]},{"t":11,"n":"MPPK - Unknown"},{"t":11,"n":"MPGS - Unknown"}]}]},{"t":8,"n":"Male Face Morphs","c":[{"t":6,"n":"Face Morph","c":[{"t":3,"n":"FMRI - Index"},{"t":2,"n":"FMRN - Name"}]}]},{"t":2,"n":"WMAP - Male Wrinkle Map Path"},{"n":"FNAM - Female Data Marker"},{"t":6,"n":"NNAM - Female Neck Fat Adjustments Scale","c":[{"t":11,"n":"Unknown"},{"t":5,"n":"X"},{"t":5,"n":"Y"}]},{"t":10,"n":"Female Head Parts","c":[{"t":6,"n":"Head Part","c":[{"t":3,"n":"INDX - Head Part Number"},{"t":3,"n":"HEAD - Head"}]}]},{"t":8,"n":"Female Race Presets","c":[{"t":3,"n":"RPRF - Preset NPC"}]},{"t":8,"n":"Female Hair Colors","c":[{"t":3,"n":"AHCF - Hair Color"}]},{"t":8,"n":"Female Face Details","c":[{"t":3,"n":"FTSF - Texture Set"}]},{"t":3,"n":"DFTF - Female Default Face Texture"},{"t":8,"n":"Female Tint Layers","c":[{"t":6,"n":"Group","c":[{"t":2,"n":"TTGP - Group Name"},{"t":8,"n":"Options","c":[{"t":6,"n":"Option","c":[{"t":6,"n":"TETI - Index","c":[{"t":11,"n":"Unknown"},{"t":3,"n":"Index"}]},{"t":2,"n":"TTGP - Name"},{"t":11,"n":"TTEF - Unknown"},{"t":8,"n":"Conditions","c":[{"t":6,"n":"Condition","c":[{"t":6,"n":"CTDA - ","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"n":"Comparison Value - Float"},{"t":3,"n":"Comparison Value - Global"},{"t":3,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"n":"None"},{"t":3,"n":"Integer"},{"t":5,"n":"Float"},{"t":3,"n":"Actor"},{"t":3,"n":"Actor Base"},{"t":3,"n":"Actor Value"},{"t":3,"n":"Player Action"},{"t":3,"n":"Alias"},{"t":3,"n":"Alignment"},{"t":3,"n":"Association Type"},{"t":3,"n":"Axis"},{"t":3,"n":"Casting Type"},{"t":3,"n":"Cell"},{"t":3,"n":"Class"},{"t":3,"n":"Crime Type"},{"t":3,"n":"Critical Stage"},{"t":3,"n":"Encounter Zone"},{"t":3,"n":"Equip Type"},{"t":3,"n":"Event"},{"t":3,"n":"Event Data"},{"t":3,"n":"Faction"},{"t":3,"n":"Form List"},{"t":3,"n":"Form Type"},{"t":3,"n":"Furniture"},{"t":3,"n":"Furniture Anim"},{"t":3,"n":"Furniture Entry"},{"t":3,"n":"Global"},{"t":3,"n":"Idle"},{"t":3,"n":"Inventory Object"},{"t":3,"n":"Keyword"},{"t":3,"n":"Location"},{"t":3,"n":"Base Effect"},{"t":3,"n":"Effect Item"},{"t":3,"n":"Misc Stat"},{"t":3,"n":"Object Reference"},{"t":3,"n":"Owner"},{"t":3,"n":"Package"},{"t":3,"n":"Packdata ID"},{"t":3,"n":"Perk"},{"t":3,"n":"Quest"},{"t":3,"n":"Quest Stage"},{"t":3,"n":"Race"},{"t":3,"n":"Referenceable Object"},{"t":3,"n":"Location Ref Type"},{"t":3,"n":"Region"},{"t":3,"n":"Scene"},{"t":3,"n":"Sex"},{"t":3,"n":"Shout"},{"t":11,"n":"Variable Name (unused)"},{"t":3,"n":"VATS Value Function"},{"t":3,"n":"VATS Value Param (unused)"},{"t":3,"n":"Voice Type"},{"t":3,"n":"Ward State"},{"t":3,"n":"Weather"},{"t":3,"n":"Worldspace"},{"t":3,"n":"Damage Type"},{"t":3,"n":"Weapon"},{"t":3,"n":"Weapon List"},{"t":3,"n":"Target"},{"t":3,"n":"Target List"},{"t":3,"n":"Target Part"},{"t":3,"n":"VATS Action"},{"t":3,"n":"Critical Effect"},{"t":3,"n":"Critical Effect List"},{"t":3,"n":"Weapon Type"},{"t":3,"n":"Projectile Type"},{"t":3,"n":"Delivery Type"},{"t":3,"n":"Run On"},{"t":3,"n":"Reference"},{"t":3,"n":"Parameter #3"}]},{"t":2,"n":"CIS1 - Parameter #1"},{"t":2,"n":"CIS2 - Parameter #2"}]}]},{"t":8,"n":"Textures","c":[{"t":2,"n":"TTET - Texture"}]},{"t":11,"n":"TTEB - Unknown"},{"t":7,"n":"TTEC - Template Colors","c":[{"t":6,"n":"Template Color","c":[{"t":3,"n":"Color"},{"t":5,"n":"Alpha"},{"t":3,"n":"Template Index"},{"t":11,"n":"Unknown"}]}]},{"t":5,"n":"TTED - Unknown"}]}]},{"t":11,"n":"TTGE - Group End"}]}]},{"t":8,"n":"Female Morph Groups","c":[{"t":6,"n":"Morph Group","c":[{"t":2,"n":"MPGN - Name"},{"t":3,"n":"MPPC - Count"},{"t":8,"n":"Morph Presets","c":[{"t":6,"n":"Morph Preset","c":[{"t":3,"n":"MPPI - Index"},{"t":2,"n":"MPPN - Name"},{"t":2,"n":"MPPM - Unknown"},{"t":3,"n":"MPPT - Texture"},{"t":11,"n":"MPPF - Unknown"}]}]},{"t":11,"n":"MPPK - Unknown"},{"t":11,"n":"MPGS - Unknown"}]}]},{"t":8,"n":"Female Face Morphs","c":[{"t":6,"n":"Face Morph","c":[{"t":3,"n":"FMRI - Index"},{"t":2,"n":"FMRN - Name"}]}]},{"t":2,"n":"WMAP - Female Wrinkle Map Path"},{"t":3,"n":"NAM8 - Morph Race"},{"t":3,"n":"RNAM - Armor Race"},{"t":3,"n":"SRAC - Subgraph Template Race"},{"t":3,"n":"SADD - Subgraph Additive Race"},{"t":8,"n":"Subgraph Data","c":[{"t":6,"n":"Data","c":[{"t":2,"n":"SGNM - Behaviour Graph"},{"t":8,"n":"Actor Keywords","c":[{"t":3,"n":"SAKD - Keyword"}]},{"t":8,"n":"Target Keywords","c":[{"t":3,"n":"STKD - Keyword"}]},{"t":8,"n":"Animation Paths","c":[{"t":2,"n":"SAPT - Path"}]},{"t":6,"n":"SRAF - Flags","c":[{"t":3,"n":"Role"},{"t":3,"n":"Perspective"}]}]}]},{"t":5,"n":"PTOP - Idle Chatter Time Min"},{"t":5,"n":"NTOP - Idle Chatter Time Max"},{"t":8,"n":"Morph Values","c":[{"t":6,"n":"Value","c":[{"t":3,"n":"MSID - Index"},{"t":2,"n":"MSM0 - Min Name"},{"t":2,"n":"MSM1 - Max Name"}]}]},{"t":11,"n":"MLSI - Unknown"},{"t":2,"n":"HNAM - Hair Color Lookup Texture"},{"t":2,"n":"HLTX - Hair Color Extended Lookup Texture"},{"t":3,"n":"QSTI - Dialogue Quest"},{"t":8,"n":"Bone Data","c":[{"t":6,"n":"Data","c":[{"t":3,"n":"BSMP - Gender"},{"t":8,"n":"Bones","c":[{"t":6,"n":"Bone","c":[{"t":2,"n":"BSMB - Name"},{"t":7,"n":"BSMS - Values","c":[{"t":5,"n":"Value"}]},{"t":11,"n":"BMMP - Unknown"}]}]}]}]}]},{"t":1,"p":1,"n":"REFR - Placed Object","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Base"},{"t":6,"s":1,"p":1,"n":"XMBO - Bound Half Extents","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"s":1,"p":1,"n":"XPRM - Primitive","c":[{"t":6,"p":1,"n":"Bounds","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Color","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}]},{"t":5,"n":"Unknown"},{"t":3,"p":1,"n":"Type"}]},{"t":7,"p":1,"n":"XPOD - Portal Data","c":[{"t":6,"p":1,"n":"References","c":[{"t":3,"p":1,"n":"Origin"},{"t":3,"p":1,"n":"Destination"}]}]},{"t":11,"n":"XORD - Unknown"},{"t":6,"s":1,"p":1,"n":"XOCP - Occlusion Plane Data","c":[{"t":6,"p":1,"n":"Size","c":[{"t":5,"p":1,"n":"Width"},{"t":5,"p":1,"n":"Height"}]},{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation (Quaternion?)","c":[{"t":5,"p":1,"n":"q1"},{"t":5,"p":1,"n":"q2"},{"t":5,"p":1,"n":"q3"},{"t":5,"p":1,"n":"q4"}]}]},{"t":6,"s":1,"p":1,"n":"Bound Data","c":[{"t":6,"p":1,"n":"XRMR - Header","c":[{"t":3,"p":1,"n":"Linked Rooms Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"}]},{"t":3,"p":1,"n":"LNAM - Lighting Template"},{"t":3,"p":1,"n":"INAM - Image Space"},{"t":8,"p":1,"n":"Linked Rooms","c":[{"t":3,"p":1,"n":"XLRM - Linked Room"}]}]},{"p":1,"n":"XMBP - MultiBound Primitive Marker"},{"t":11,"n":"XRGD - Ragdoll Data"},{"t":11,"n":"XRGB - Ragdoll Biped Data"},{"t":5,"p":1,"n":"XRDS - Radius"},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":6,"s":1,"p":1,"n":"XLIG - Light Data","c":[{"t":5,"p":1,"n":"FOV 90+\/-"},{"t":5,"p":1,"n":"Fade 1.0+\/-"},{"t":5,"p":1,"n":"End Distance Cap"},{"t":5,"p":1,"n":"Shadow Depth Bias"},{"t":5,"p":1,"n":"Near Clip"},{"t":5,"p":1,"n":"Volumetric Intensity"}]},{"t":6,"s":1,"p":1,"n":"XALP - Alpha","c":[{"t":3,"p":1,"n":"Cutoff"},{"t":3,"p":1,"n":"Base"}]},{"t":6,"s":1,"p":1,"n":"XTEL - Teleport Destination","c":[{"t":3,"p":1,"n":"Door"},{"t":6,"p":1,"n":"Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Transition Interior"}]},{"t":3,"p":1,"n":"XTNM - Teleport Loc Name"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"t":11,"n":"XWCN - Unknown"},{"t":6,"s":1,"p":1,"n":"XWCU - Water Velocity","c":[{"t":5,"p":1,"n":"X Offset"},{"t":5,"p":1,"n":"Y Offset"},{"t":5,"p":1,"n":"Z Offset"},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"X Angle"},{"t":5,"p":1,"n":"Y Angle"},{"t":5,"p":1,"n":"Z Angle"}]},{"t":3,"p":1,"n":"XASP - Acoustic Restriction"},{"p":1,"n":"XATP - Activation Point"},{"t":3,"p":1,"n":"XAMC - Ammo Count"},{"p":1,"n":"XLKT - Linked Ref Transient"},{"t":3,"p":1,"n":"XLYR - Layer"},{"t":3,"p":1,"n":"XMSP - Material Swap"},{"t":3,"p":1,"n":"XRFG - Reference Group"},{"t":6,"s":1,"p":1,"n":"XRDO - Radio","c":[{"t":5,"p":1,"n":"Frequency"},{"t":5,"p":1,"n":"Min Weak Distance"},{"t":5,"p":1,"n":"Max Weak Distance"},{"t":3,"p":1,"n":"Flags"}]},{"t":6,"s":1,"p":1,"n":"XBSD - Spline","c":[{"t":5,"p":1,"n":"Slack"},{"t":5,"p":1,"n":"Thickness"},{"t":5,"n":"Unknown"},{"t":3,"p":1,"n":"Wind - Detached End"},{"t":11,"n":"Unused"}]},{"t":6,"s":1,"p":1,"n":"XPDD - Projected Decal","c":[{"t":5,"p":1,"n":"Width Scale"},{"t":5,"p":1,"n":"Height Scale"}]},{"t":3,"p":1,"n":"XSPC - Spawn Container"},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":3,"p":1,"n":"XLIB - Leveled Item Base Object"},{"t":3,"p":1,"n":"XLCM - Level Modifier"},{"t":3,"p":1,"n":"XLCN - Persistent Location"},{"t":3,"p":1,"n":"XTRI - Collision Layer"},{"t":6,"s":1,"p":1,"n":"XLOC - Lock Data","c":[{"t":3,"p":1,"n":"Level"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Key"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"}]},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":6,"s":1,"p":1,"n":"XNDP - Navigation Door Link","c":[{"t":3,"p":1,"n":"Navigation Mesh"},{"t":3,"p":1,"n":"Teleport Marker Triangle"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":6,"s":1,"p":1,"n":"XOWN - Owner","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Flags"}]},{"t":3,"p":1,"n":"XRNK - Owner Faction Rank"},{"t":3,"p":1,"n":"XCNT - Item Count"},{"t":3,"p":1,"n":"XHLT - Health %"},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":8,"s":1,"p":1,"n":"Patrol","d":1,"c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"XPRD - Idle Time"},{"p":1,"n":"XPPA - Patrol Script Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":8,"p":1,"n":"Topic","c":[{"t":6,"p":1,"n":"PDTO - Topic Data","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Topic"},{"t":2,"p":1,"n":"Subtype"}]}]}]}]},{"t":3,"p":1,"n":"XACT - Action Flag"},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"p":1,"n":"ONAM - Open by Default"},{"t":6,"s":1,"p":1,"n":"Map Marker","c":[{"p":1,"n":"XMRK - Map Marker Data"},{"t":3,"p":1,"n":"FNAM - Map Flags"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"p":1,"n":"TNAM - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"}]}]},{"t":3,"p":1,"n":"XATR - Attach Ref"},{"t":8,"s":1,"p":1,"n":"Spline Connection","d":1,"c":[{"t":6,"p":1,"n":"XPLK - Link","c":[{"t":3,"p":1,"n":"Ref"},{"t":11,"n":"Unknown"}]}]},{"t":6,"s":1,"p":1,"n":"Power Grid","c":[{"t":3,"p":1,"n":"XWPG - Count"},{"t":8,"p":1,"n":"Connections","c":[{"t":6,"p":1,"n":"XWPN - Connection","c":[{"t":3,"p":1,"n":"Node 1"},{"t":3,"p":1,"n":"Node 2"},{"t":3,"p":1,"n":"Line"}]}]}]},{"t":11,"n":"XCVR - Unknown"},{"t":11,"n":"XCVL - Unknown"},{"t":3,"n":"XCZR - Unknown"},{"t":11,"n":"XCZA - Unknown"},{"t":3,"n":"XCZC - Unknown"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]},{"t":2,"p":1,"n":"MNAM - Comments"}]},{"t":1,"p":1,"n":"REGN - Region","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"RCLR - Map Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":3,"p":1,"n":"WNAM - Worldspace"},{"t":8,"s":1,"p":1,"n":"Region Areas","d":1,"c":[{"t":6,"p":1,"n":"Region Area","c":[{"t":3,"p":1,"n":"RPLI - Edge Fall-off"},{"t":7,"p":1,"n":"RPLD - Region Point List Data","c":[{"t":6,"p":1,"n":"Point","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"}]}]},{"t":11,"n":"ANAM - Unknown"}]}]},{"t":10,"p":1,"n":"Region Data Entries","d":1,"c":[{"t":6,"p":1,"n":"Region Data Entry","c":[{"t":6,"p":1,"n":"RDAT - Data Header","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Priority"},{"t":11,"n":"Unknown"}]},{"t":2,"p":1,"n":"ICON - Inventory Image"},{"t":3,"p":1,"n":"RDMO - Music"},{"t":7,"p":1,"n":"RDSA - Sounds","c":[{"t":6,"p":1,"n":"Sound","c":[{"t":3,"p":1,"n":"Sound"},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Chance"}]}]},{"t":2,"p":1,"n":"RDMP - Map Name"},{"t":7,"p":1,"n":"RDOT - Objects","c":[{"t":6,"p":1,"n":"Object","c":[{"t":3,"p":1,"n":"Object"},{"t":3,"p":1,"n":"Parent Index"},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"Density"},{"t":3,"p":1,"n":"Clustering"},{"t":3,"p":1,"n":"Min Slope"},{"t":3,"p":1,"n":"Max Slope"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Radius wrt Parent"},{"t":3,"p":1,"n":"Radius"},{"t":5,"p":1,"n":"Min Height"},{"t":5,"p":1,"n":"Max Height"},{"t":5,"p":1,"n":"Sink"},{"t":5,"p":1,"n":"Sink Variance"},{"t":5,"p":1,"n":"Size Variance"},{"t":6,"p":1,"n":"Angle Variance","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"},{"t":3,"p":1,"n":"Z"}]}]}]},{"t":7,"p":1,"n":"RDGS - Grasses","c":[{"t":6,"p":1,"n":"Grass","c":[{"t":3,"p":1,"n":"Grass"},{"t":11,"n":"Unknown"}]}]},{"t":7,"p":1,"n":"RDWT - Weather Types","c":[{"t":6,"p":1,"n":"Weather Type","c":[{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Chance"},{"t":3,"p":1,"n":"Global"}]}]},{"t":5,"p":1,"n":"RLDM - LOD Display Distance Multiplier"},{"t":5,"p":1,"n":"ANAM - Occlusion Accuracy Dist"}]}]}]},{"t":1,"p":1,"n":"RELA - Relationship","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Parent"},{"t":3,"p":1,"n":"Child"},{"t":3,"p":1,"n":"Rank"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Association Type"}]}]},{"t":1,"p":1,"n":"REVB - Reverb Parameters","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Decay Time (ms)"},{"t":3,"p":1,"n":"HF Reference (Hz)"},{"t":3,"p":1,"n":"Room Filter"},{"t":3,"p":1,"n":"Room HF Filter"},{"t":3,"p":1,"n":"Reflections"},{"t":3,"p":1,"n":"Reverb Amp"},{"t":3,"p":1,"n":"Decay HF Ratio"},{"t":3,"p":1,"n":"Reflect Delay (ms), scaled"},{"t":3,"p":1,"n":"Reverb Delay (ms)"},{"t":3,"p":1,"n":"Diffusion %"},{"t":3,"p":1,"n":"Density %"},{"t":3,"n":"Unknown"}]},{"t":3,"p":1,"n":"ANAM - Reverb Class"}]},{"t":1,"p":1,"n":"RFCT - Visual Effect","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - Effect Data","c":[{"t":3,"p":1,"n":"Effect Art"},{"t":3,"p":1,"n":"Shader"},{"t":3,"p":1,"n":"Flags"}]}]},{"t":1,"p":1,"n":"RFGP - Reference Group","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"NNAM - Name"},{"t":3,"p":1,"n":"RNAM - Reference"},{"t":11,"n":"PNAM - Unknown"}]},{"t":1,"p":1,"n":"SCCO - Scene Collection","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"QNAM - Quest"},{"t":8,"s":1,"p":1,"n":"Scenes","d":1,"c":[{"t":6,"p":1,"n":"Scene","c":[{"t":3,"p":1,"n":"SNAM - Scene"},{"t":6,"n":"XNAM - Unknown","c":[{"t":3,"n":"Unknown"}]}]}]},{"t":11,"n":"VNAM - Unknown"},{"t":8,"n":"Unknown","c":[{"t":6,"n":"XNAM - Unknown","c":[{"t":3,"n":"Unknown"}]}]}]},{"t":1,"p":1,"n":"SCEN - Scene","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]},{"t":6,"p":1,"n":"Script Fragments","c":[{"t":3,"n":"Unknown"},{"t":3,"p":1,"n":"Flags"},{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]},{"t":7,"p":1,"n":"Fragments","c":[{"t":6,"p":1,"n":"Fragment","c":[{"t":3,"n":"Unknown"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]},{"t":7,"p":1,"n":"Phase Fragments","c":[{"t":6,"p":1,"n":"Phase Fragment","c":[{"t":3,"p":1,"n":"Phase Flag"},{"t":3,"p":1,"n":"Phase Index"},{"t":3,"n":"Unknown"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]}]}]},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":8,"s":1,"p":1,"n":"Phases","d":1,"c":[{"t":6,"p":1,"n":"Phase","c":[{"p":1,"n":"HNAM - Marker Phase Start"},{"t":2,"p":1,"n":"NAM0 - Name"},{"t":6,"p":1,"n":"Start Conditions","c":[{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]},{"p":1,"n":"NEXT - Marker Start Conditions"},{"t":6,"p":1,"n":"Completion Conditions","c":[{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]},{"p":1,"n":"NEXT - Marker Completion Conditions"},{"t":3,"p":1,"n":"WNAM - Editor Width"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":6,"p":1,"n":"SCQS - Set Parent Quest Stage","c":[{"t":3,"p":1,"n":"On Start"},{"t":3,"p":1,"n":"On Completion"}]},{"p":1,"n":"HNAM - Marker Phase End"}]}]},{"t":8,"s":1,"p":1,"n":"Actors","d":1,"c":[{"t":6,"p":1,"n":"Actor","c":[{"t":3,"p":1,"n":"ALID - Alias ID"},{"t":3,"p":1,"n":"LNAM - Flags"},{"t":3,"p":1,"n":"DNAM - Behaviour Flags"}]}]},{"t":8,"s":1,"p":1,"n":"Actions","d":1,"c":[{"t":6,"p":1,"n":"Action","c":[{"t":3,"p":1,"n":"ANAM - Type"},{"t":2,"p":1,"n":"NAM0 - Name"},{"t":3,"p":1,"n":"ALID - Alias ID"},{"t":3,"p":1,"n":"INAM - Index"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":3,"p":1,"n":"SNAM - Start Phase"},{"t":3,"p":1,"n":"ENAM - End Phase"},{"t":5,"p":1,"n":"SNAM - Timer - Max Seconds"},{"t":3,"p":1,"n":"SCQS - Set Parent Quest Stage"},{"t":5,"p":1,"n":"TNAM - Timer - Min Seconds"},{"t":11,"n":"STSC - Unknown"},{"t":8,"p":1,"n":"Start Scenes","c":[{"t":6,"p":1,"n":"Start Scene","c":[{"t":3,"p":1,"n":"LCEP - Scene"},{"t":3,"p":1,"n":"INTT - Phase Index"},{"t":2,"p":1,"n":"SSPN - Start Phase for Scene"},{"t":3,"p":1,"n":"CITC - Condition Count"},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]},{"t":3,"p":1,"n":"PTOP - Player Positive Response"},{"t":3,"p":1,"n":"NTOP - Player Negative Response"},{"t":3,"p":1,"n":"NETO - Player Neutral Response"},{"t":3,"p":1,"n":"QTOP - Player Question Response"},{"t":3,"p":1,"n":"VENC - Player Positive Dialogue Subtype"},{"t":3,"p":1,"n":"PLVD - Player Negative Dialogue Subtype"},{"t":3,"p":1,"n":"JOUT - Player Neutral Dialogue Subtype"},{"t":3,"p":1,"n":"DALC - Player Question Dialogue Subtype"},{"t":7,"p":1,"n":"DTID - NPC Headtracking","c":[{"t":3,"p":1,"n":"Actor ID"}]},{"t":3,"p":1,"n":"NPOT - NPC Positive Response"},{"t":3,"p":1,"n":"NNGT - NPC Negative Response"},{"t":3,"p":1,"n":"NNUT - NPC Neutral Response"},{"t":3,"p":1,"n":"NQUT - NPC Question Response"},{"t":3,"p":1,"n":"NPOS - NPC Positive Dialogue Subtype"},{"t":3,"p":1,"n":"NNGS - NPC Negative Dialogue Subtype"},{"t":3,"p":1,"n":"NNUS - NPC Neutral Dialogue Subtype"},{"t":3,"p":1,"n":"NQUS - NPC Question Dialogue Subtype"},{"t":3,"p":1,"n":"DTGT - Dialogue Target Actor"},{"t":8,"p":1,"n":"Packages","c":[{"t":3,"p":1,"n":"PNAM - Package"}]},{"t":3,"p":1,"n":"DATA - Topic"},{"p":1,"n":"End Scene Say Greeting"},{"t":3,"p":1,"n":"Play Sound"},{"t":5,"p":1,"n":"DMAX - Looping - Max"},{"t":5,"p":1,"n":"DMIN - Looping - Min"},{"t":6,"p":1,"n":"CRIS - Camera","c":[{"t":5,"p":1,"n":"FOV On Player Camera"},{"t":5,"p":1,"n":"Rate Of Camera Change"}]},{"t":3,"p":1,"n":"DEMO - Emotion Type"},{"t":3,"p":1,"n":"DEVA - Emotion Value"},{"t":7,"p":1,"n":"HTID - Player Headtracking","c":[{"t":3,"p":1,"n":"Actor ID"}]},{"t":3,"p":1,"n":"VENC - Dialogue Subtype"},{"t":3,"p":1,"n":"PNAM - AnimArchType"},{"t":3,"p":1,"n":"ONAM - Audio Output Override"},{"p":1,"n":"ANAM - End Marker"}]}]},{"t":3,"p":1,"n":"PNAM - Quest"},{"t":3,"p":1,"n":"INAM - Last Action Index"},{"t":11,"n":"VNAM - Unknown"},{"t":5,"p":1,"n":"CNAM - Camera Distance Override"},{"t":5,"p":1,"n":"ACTV - Dialogue Distance Override"},{"t":5,"p":1,"n":"CRIS - FOV Override"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":6,"s":1,"p":1,"n":"SCQS - Set Parent Quest Stage","c":[{"t":3,"p":1,"n":"On Begin"},{"t":3,"p":1,"n":"On End"}]},{"t":2,"p":1,"n":"NNAM - Notes"},{"t":3,"p":1,"n":"TNAM - Template Scene"},{"t":3,"p":1,"n":"XNAM - Index"}]},{"t":1,"p":1,"n":"SCOL - Static Collection","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"PTRN - Preview Transform"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"FLTR - Filter"},{"t":10,"p":1,"n":"Parts","d":1,"c":[{"t":6,"p":1,"n":"Part","c":[{"t":3,"p":1,"n":"ONAM - Static"},{"t":7,"p":1,"n":"DATA - Placements","c":[{"t":6,"p":1,"n":"Placement","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":5,"p":1,"n":"Scale"}]}]}]}]}]},{"t":1,"p":1,"n":"SCSN - Audio Category Snapshot","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"PNAM - Priority"},{"t":8,"s":1,"p":1,"n":"Category Multipliers","d":1,"c":[{"t":6,"p":1,"n":"CNAM - Category Multiplier","c":[{"t":3,"p":1,"n":"Categoty"},{"t":5,"p":1,"n":"Multiplier"}]}]}]},{"t":1,"p":1,"n":"SMBN - Story Manager Branch Node","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"PNAM - Parent "},{"t":3,"p":1,"n":"SNAM - Child "},{"t":3,"n":"CITC - Condition Count"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":3,"p":1,"n":"DNAM - Flags"},{"t":11,"n":"XNAM - Unknown"}]},{"t":1,"p":1,"n":"SMEN - Story Manager Event Node","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"PNAM - Parent "},{"t":3,"p":1,"n":"SNAM - Child "},{"t":3,"n":"CITC - Condition Count"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":3,"p":1,"n":"DNAM - Flags"},{"t":11,"n":"XNAM - Unknown"},{"t":2,"p":1,"n":"ENAM - Type"}]},{"t":1,"p":1,"n":"SMQN - Story Manager Quest Node","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"PNAM - Parent "},{"t":3,"p":1,"n":"SNAM - Child "},{"t":3,"n":"CITC - Condition Count"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":6,"s":1,"p":1,"n":"DNAM - Flags","c":[{"t":3,"p":1,"n":"Node Flags"},{"t":3,"p":1,"n":"Quest Flags"}]},{"t":3,"p":1,"n":"XNAM - Max concurrent quests"},{"t":3,"p":1,"n":"MNAM - Num quests to run"},{"t":5,"p":1,"n":"HNAM - Hours until reset"},{"t":3,"n":"QNAM - Quest Count"},{"t":10,"p":1,"n":"Quests","d":1,"c":[{"t":6,"p":1,"n":"Quest","c":[{"t":3,"p":1,"n":"NNAM - Quest"},{"t":11,"n":"FNAM - Unknown"},{"t":5,"p":1,"n":"RNAM - Hours until reset"}]}]}]},{"t":1,"p":1,"n":"SNCT - Sound Category","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":3,"p":1,"n":"PNAM - Parent Category"},{"t":3,"p":1,"n":"ONAM - Menu Slider Category"},{"t":3,"p":1,"n":"VNAM - Static Volume Multiplier"},{"t":3,"p":1,"n":"UNAM - Default Menu Value"},{"t":5,"p":1,"n":"MNAM - Min Frequency Multiplier"},{"t":5,"p":1,"n":"CNAM - Sidechain Target Multiplier"}]},{"t":1,"p":1,"n":"SNDR - Sound Descriptor","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"NNAM - Notes"},{"t":3,"p":1,"n":"CNAM - Descriptor Type"},{"t":3,"p":1,"n":"GNAM - Category"},{"t":3,"p":1,"n":"SNAM - Alternate Sound For"},{"t":8,"s":1,"p":1,"n":"Sounds","d":1,"c":[{"t":6,"p":1,"n":"Sound Files","c":[{"t":2,"p":1,"n":"ANAM - File Name"}]}]},{"t":3,"p":1,"n":"ONAM - Output Model"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":6,"s":1,"p":1,"n":"LNAM - Values","c":[{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Looping"},{"t":3,"p":1,"n":"Sidechain"},{"t":3,"p":1,"n":"Rumble Send Value = (Small \/ 7) + ((Big \/ 7) * 16)"}]},{"t":6,"s":1,"p":1,"n":"Values","c":[{"t":3,"p":1,"n":"% Frequency Shift"},{"t":3,"p":1,"n":"% Frequency Variance"},{"t":3,"p":1,"n":"Priority"},{"t":3,"p":1,"n":"db Variance"},{"t":3,"p":1,"n":"Static Attenuation (db)"}]},{"t":3,"p":1,"n":"Base Descriptor"},{"t":8,"s":1,"p":1,"n":"Descriptors","d":1,"c":[{"t":3,"p":1,"n":"DNAM - Descriptor"}]},{"t":3,"n":"ITMC - Count"},{"t":10,"p":1,"n":"Rates of Fire","d":1,"c":[{"t":6,"p":1,"n":"Sound","c":[{"p":1,"n":"ITMS - Marker Start"},{"t":3,"p":1,"n":"INTV - RoF (RPM)"},{"t":2,"p":1,"n":"FNAM - File"},{"p":1,"n":"ITME - Marker End"}]}]}]},{"t":1,"p":1,"n":"SOPM - Sound Output Model","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"NAM1 - Data","c":[{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Reverb Send %"}]},{"t":3,"p":1,"n":"MNAM - Type"},{"t":3,"p":1,"n":"VNAM - Static Attenuation"},{"t":6,"s":1,"p":1,"n":"ONAM - Output Values","c":[{"t":7,"p":1,"n":"Channels","c":[{"t":6,"p":1,"n":"","c":[{"t":3,"p":1,"n":"FL"},{"t":3,"p":1,"n":"FR"},{"t":3,"p":1,"n":"C"},{"t":3,"p":1,"n":"LFE"},{"t":3,"p":1,"n":"RL"},{"t":3,"p":1,"n":"RR"},{"t":3,"p":1,"n":"SL"},{"t":3,"p":1,"n":"SR"}]}]}]},{"t":6,"s":1,"p":1,"n":"ATTN - Attenuation Values","c":[{"t":5,"p":1,"n":"Fade In Distance - Start"},{"t":5,"p":1,"n":"Fade In Distance - End"},{"t":5,"p":1,"n":"Fade Out Distance - Start"},{"t":5,"p":1,"n":"Fade Out Distance - End"},{"t":6,"p":1,"n":"Fade In Curve","c":[{"t":3,"p":1,"n":"Value 1"},{"t":3,"p":1,"n":"Value 2"},{"t":3,"p":1,"n":"Value 3"},{"t":3,"p":1,"n":"Value 4"}]},{"t":6,"p":1,"n":"Fade Out Curve","c":[{"t":3,"p":1,"n":"Value 1"},{"t":3,"p":1,"n":"Value 2"},{"t":3,"p":1,"n":"Value 3"},{"t":3,"p":1,"n":"Value 4"}]}]},{"t":3,"p":1,"n":"ENAM - Effect Chain"}]},{"t":1,"p":1,"n":"SOUN - Sound Marker","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"SDSC - Sound Descriptor"},{"t":6,"s":1,"p":1,"n":"REPT - Repeat","c":[{"t":5,"p":1,"n":"Min Time"},{"t":5,"p":1,"n":"Max Time"},{"t":3,"p":1,"n":"Stackable"}]}]},{"t":1,"p":1,"n":"SPEL - Spell","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":3,"p":1,"n":"ETYP - Equipment Type"},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"SPIT - Data","c":[{"t":3,"p":1,"n":"Base Cost"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Type"},{"t":5,"p":1,"n":"Charge Time"},{"t":3,"p":1,"n":"Cast Type"},{"t":3,"p":1,"n":"Target Type"},{"t":5,"p":1,"n":"Cast Duration"},{"t":5,"p":1,"n":"Range"},{"t":3,"p":1,"n":"Casting Perk"}]},{"t":8,"s":1,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":3,"p":1,"n":"EFID - Base Effect"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":5,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"}]},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]}]},{"t":1,"p":1,"n":"SPGD - Shader Particle Geometry","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":5,"p":1,"n":"Gravity Velocity"},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"Rotation Velocity"},{"t":5,"p":1,"n":"Particle Size X"},{"t":5,"p":1,"n":"Center Offset Min"},{"t":5,"p":1,"n":"Particle Size Y"},{"t":5,"p":1,"n":"Center Offset Max"},{"t":5,"p":1,"n":"Initial Rotation"},{"t":3,"p":1,"n":"# of Subtextures X"},{"t":3,"p":1,"n":"# of Subtextures Y"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Box Size"},{"t":5,"p":1,"n":"Particle Density"}]},{"t":2,"p":1,"n":"MNAM - Particle Texture"}]},{"t":1,"p":1,"n":"STAG - Animation Sound Tag Set","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":8,"s":1,"p":1,"n":"Sounds","d":1,"c":[{"t":6,"p":1,"n":"TNAM - Sound","c":[{"t":3,"p":1,"n":"Sound"},{"t":2,"p":1,"n":"Action"}]}]}]},{"t":1,"p":1,"n":"STAT - Static","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"PTRN - Preview Transform"},{"t":3,"p":1,"n":"FTYP - Forced Loc Ref Type"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]},{"t":7,"p":1,"n":"PRPS - Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":3,"p":1,"n":"Actor Value"},{"t":5,"p":1,"n":"Value"}]}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"DNAM - Direction Material","c":[{"t":5,"p":1,"n":"Max Angle (30-120)"},{"t":3,"p":1,"n":"Material"},{"t":5,"p":1,"n":"Leaf Amplitude"},{"t":5,"p":1,"n":"Leaf Frequency"}]},{"t":6,"s":1,"p":1,"n":"NVNM - Navmesh Geometry","c":[{"t":3,"p":1,"n":"Version"},{"t":11,"p":1,"n":"Magic"},{"t":3,"p":1,"n":"Parent Worldspace"},{"t":6,"p":1,"n":"Coordinates","c":[{"t":3,"p":1,"n":"Grid Y"},{"t":3,"p":1,"n":"Grid X"}]},{"t":3,"p":1,"n":"Parent Cell"},{"t":11,"p":1,"n":"Vertices and Triangles"}]},{"t":7,"p":1,"n":"MNAM - Distant LOD","c":[{"t":6,"p":1,"n":"LOD","c":[{"t":2,"p":1,"n":"Mesh"}]}]}]},{"t":1,"p":1,"n":"TACT - Talking Activator","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]},{"t":6,"s":1,"p":1,"n":"Destructible","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"}]},{"t":7,"p":1,"n":"DAMC - Resistances","c":[{"t":6,"p":1,"n":"Resistance","c":[{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Value"}]}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":2,"p":1,"n":"DSTA - Sequence Name"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":5,"p":1,"n":"DMDC - Color Remapping Index"},{"t":3,"p":1,"n":"DMDS - Material Swap"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":11,"n":"PNAM - Unknown"},{"t":3,"p":1,"n":"SNAM - Looping Sound"},{"t":11,"n":"FNAM - Unknown"},{"t":3,"p":1,"n":"VNAM - Voice Type"}]},{"t":1,"p":1,"n":"TERM - Terminal","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]},{"t":6,"p":1,"n":"Script Fragments","c":[{"t":3,"n":"Unknown"},{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]},{"t":7,"p":1,"n":"Fragments","c":[{"t":6,"p":1,"n":"Fragment","c":[{"t":3,"p":1,"n":"Fragment Index"},{"t":3,"n":"Unknown"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"PTRN - Preview Transform"},{"t":2,"p":1,"n":"NAM0 - Header Text"},{"t":2,"p":1,"n":"WNAM - Welcome Text"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":7,"p":1,"n":"PRPS - Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":3,"p":1,"n":"Actor Value"},{"t":5,"p":1,"n":"Value"}]}]},{"t":11,"n":"PNAM - Unknown"},{"t":3,"p":1,"n":"SNAM - Looping Sound"},{"t":11,"n":"FNAM - Unknown"},{"t":3,"n":"COCT - Count"},{"t":10,"p":1,"n":"Items","d":1,"c":[{"t":6,"p":1,"n":"Item","c":[{"t":6,"p":1,"n":"CNTO - Item","c":[{"t":3,"p":1,"n":"Item"},{"t":3,"p":1,"n":"Count"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]},{"t":3,"p":1,"n":"MNAM - Active Markers \/ Flags"},{"t":11,"n":"WBDT - Workbench Data (unused)"},{"t":2,"p":1,"n":"XMRK - Marker Model"},{"t":7,"p":1,"n":"SNAM - Marker Paramaters","c":[{"t":6,"p":1,"n":"Marker","c":[{"t":5,"p":1,"n":"Offset X"},{"t":5,"p":1,"n":"Offset Y"},{"t":5,"p":1,"n":"Offset Z"},{"t":5,"p":1,"n":"Rotation Z"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Entry Types"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"BSIZ - Count"},{"t":8,"s":1,"p":1,"n":"Body Text","d":1,"c":[{"t":6,"p":1,"n":"Item","c":[{"t":2,"p":1,"n":"BTXT - Text"},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]},{"t":3,"n":"ISIZ - Count"},{"t":8,"s":1,"p":1,"n":"Menu Items","d":1,"c":[{"t":6,"p":1,"n":"Menu Item","c":[{"t":2,"p":1,"n":"ITXT - Item Text"},{"t":2,"p":1,"n":"RNAM - Response Text"},{"t":3,"p":1,"n":"ANAM - Type"},{"t":3,"p":1,"n":"ITID - Item ID"},{"t":2,"p":1,"n":"UNAM - Display Text"},{"t":2,"p":1,"n":"VNAM - Show Image"},{"t":3,"p":1,"n":"TNAM - Submenu"},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Shout"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (unused)"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]}]},{"t":1,"p":1,"n":"TREE - Tree","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]},{"t":3,"p":1,"n":"PFIG - Ingredient"},{"t":3,"p":1,"n":"SNAM - Harvest Sound"},{"t":6,"s":1,"p":1,"n":"PFPC - Ingredient Production","c":[{"t":3,"p":1,"n":"Spring"},{"t":3,"p":1,"n":"Summer"},{"t":3,"p":1,"n":"Fall"},{"t":3,"p":1,"n":"Winter"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"CNAM - Tree Data","c":[{"t":5,"p":1,"n":"Trunk Flexibility"},{"t":5,"p":1,"n":"Branch Flexibility"},{"t":5,"n":"Unknown"},{"t":5,"p":1,"n":"Leaf Amplitude"},{"t":5,"p":1,"n":"Leaf Frequency"}]}]},{"t":1,"p":1,"n":"TRNS - Transform","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":6,"p":1,"n":"Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]},{"t":5,"p":1,"n":"Scale"},{"t":5,"p":1,"n":"Zoom Min"},{"t":5,"p":1,"n":"Zoom Max"}]}]},{"t":1,"p":1,"n":"TXST - Texture Set","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Textures (RGB\/A)","c":[{"t":2,"p":1,"n":"TX00 - Difuse"},{"t":2,"p":1,"n":"TX01 - Normal\/Gloss"},{"t":2,"p":1,"n":"TX03 - Glow"},{"t":2,"p":1,"n":"TX04 - Height"},{"t":2,"p":1,"n":"TX05 - Environment"},{"t":2,"p":1,"n":"TX02 - Wrinkles"},{"t":2,"p":1,"n":"TX06 - Multilayer"},{"t":2,"p":1,"n":"TX07 - Smooth Spec"}]},{"t":6,"s":1,"p":1,"n":"DODT - Decal Data","c":[{"t":5,"p":1,"n":"Min Width"},{"t":5,"p":1,"n":"Max Width"},{"t":5,"p":1,"n":"Min Height"},{"t":5,"p":1,"n":"Max Height"},{"t":5,"p":1,"n":"Depth"},{"t":5,"p":1,"n":"Shininess"},{"t":6,"p":1,"n":"Parallax","c":[{"t":5,"p":1,"n":"Scale"},{"t":3,"p":1,"n":"Passes"}]},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Alpha Threshold?"},{"t":6,"p":1,"n":"Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":3,"p":1,"n":"DNAM - Flags"},{"t":2,"p":1,"n":"MNAM - Material"}]},{"t":1,"p":1,"n":"VTYP - Voice Type","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"DNAM - Flags"}]},{"t":1,"p":1,"n":"WATR - Water","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"ANAM - Opacity (unused)"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":3,"p":1,"n":"TNAM - Material (unused)"},{"t":3,"p":1,"n":"SNAM - Open Sound"},{"t":3,"p":1,"n":"XNAM - Consume Spell"},{"t":3,"p":1,"n":"YNAM - Contact Spell"},{"t":3,"p":1,"n":"INAM - Image Space"},{"t":11,"n":"DATA - Unused"},{"t":6,"s":1,"p":1,"n":"DNAM - Visual Data","c":[{"t":6,"p":1,"n":"Fog Properties","c":[{"t":5,"p":1,"n":"Depth Amount"},{"t":6,"p":1,"n":"Shallow Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Deep Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Color Shallow Range"},{"t":5,"p":1,"n":"Color Deep Range"},{"t":5,"p":1,"n":"Shallow Alpha"},{"t":5,"p":1,"n":"Deep Alpha"},{"t":5,"p":1,"n":"Alpha Shallow Range"},{"t":5,"p":1,"n":"Alpha Deep Range"},{"t":6,"p":1,"n":"Underwater Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Underwater Fog Amount"},{"t":5,"p":1,"n":"Underwater Near Fog"},{"t":5,"p":1,"n":"Underwater Far Fog"}]},{"t":6,"p":1,"n":"Physical Properties","c":[{"t":5,"p":1,"n":"Normal Magnitude"},{"t":5,"p":1,"n":"Shallow Normal Falloff"},{"t":5,"p":1,"n":"Deep Normal Falloff"},{"t":5,"p":1,"n":"Reflectivity Amount"},{"t":5,"p":1,"n":"Fresnel Amount"},{"t":5,"p":1,"n":"Surface Effect Falloff"},{"t":6,"p":1,"n":"Displacement Simulator","c":[{"t":5,"p":1,"n":"Force"},{"t":5,"p":1,"n":"Velocity"},{"t":5,"p":1,"n":"Falloff"},{"t":5,"p":1,"n":"Dampener"},{"t":5,"p":1,"n":"Starting Size"}]},{"t":6,"p":1,"n":"Reflection Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Specular Properties","c":[{"t":5,"p":1,"n":"Sun Specular Power"},{"t":5,"p":1,"n":"Sun Specular Magnitude"},{"t":5,"p":1,"n":"Sun Sparkle Power"},{"t":5,"p":1,"n":"Sun Sparkle Magnitude"},{"t":5,"p":1,"n":"Interior Specular Radius"},{"t":5,"p":1,"n":"Interior Specular Brightness"},{"t":5,"p":1,"n":"Interior Specular Power"}]},{"t":6,"p":1,"n":"Noise Properties","c":[{"t":5,"p":1,"n":"Layer 1 - Wind Direction"},{"t":5,"p":1,"n":"Layer 2 - Wind Direction"},{"t":5,"p":1,"n":"Layer 3 - Wind Direction"},{"t":5,"p":1,"n":"Layer 1 - Wind Speed"},{"t":5,"p":1,"n":"Layer 2 - Wind Speed"},{"t":5,"p":1,"n":"Layer 3 - Wind Speed"},{"t":5,"p":1,"n":"Layer 1 - Amplitude Scale"},{"t":5,"p":1,"n":"Layer 2 - Amplitude Scale"},{"t":5,"p":1,"n":"Layer 3 - Amplitude Scale"},{"t":5,"p":1,"n":"Layer 1 - UV Scale"},{"t":5,"p":1,"n":"Layer 2 - UV Scale"},{"t":5,"p":1,"n":"Layer 3 - UV Scale"},{"t":5,"p":1,"n":"Layer 1 - Noise Falloff"},{"t":5,"p":1,"n":"Layer 2 - Noise Falloff"},{"t":5,"p":1,"n":"Layer 3 - Noise Falloff"}]},{"t":6,"p":1,"n":"Silt Properties","c":[{"t":5,"p":1,"n":"Silt Amount"},{"t":6,"p":1,"n":"Light Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Dark Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":3,"p":1,"n":"Screen Space Reflections"}]},{"t":11,"n":"GNAM - Unused"},{"t":6,"s":1,"p":1,"n":"NAM0 - Linear Velocity","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"s":1,"p":1,"n":"NAM1 - Angular Velocity","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":2,"p":1,"n":"NAM2 - Layer 1 Noise Texture"},{"t":2,"p":1,"n":"NAM3 - Layer 2 Noise Texture"},{"t":2,"p":1,"n":"NAM4 - Layer 3 Noise Texture"}]},{"t":1,"p":1,"n":"WEAP - Weapon","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Struct","c":[{"t":7,"p":1,"n":"Struct","c":[{"t":6,"p":1,"n":"Member","c":[{"t":2,"p":1,"n":"memberName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"PTRN - Preview Transform"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]},{"t":2,"p":1,"n":"ICON - Inventory Image"},{"t":2,"p":1,"n":"MICO - Message Icon"},{"t":3,"p":1,"n":"EITM - Object Effect"},{"t":3,"p":1,"n":"EAMT - Enchantment Amount"},{"t":6,"s":1,"p":1,"n":"Destructible","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"}]},{"t":7,"p":1,"n":"DAMC - Resistances","c":[{"t":6,"p":1,"n":"Resistance","c":[{"t":3,"p":1,"n":"Damage Type"},{"t":3,"p":1,"n":"Value"}]}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":2,"p":1,"n":"DSTA - Sequence Name"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":5,"p":1,"n":"DMDC - Color Remapping Index"},{"t":3,"p":1,"n":"DMDS - Material Swap"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"ETYP - Equipment Type"},{"t":3,"p":1,"n":"BIDS - Block Bash Impact Data Set"},{"t":3,"p":1,"n":"BAMT - Alternate Block Material"},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":2,"p":1,"n":"DESC - Description"},{"t":3,"p":1,"n":"INRD - Instance Naming"},{"t":7,"p":1,"n":"APPR - Attach Parent Slots","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"Object Template","c":[{"t":3,"p":1,"n":"OBTE - Count"},{"t":8,"p":1,"n":"Combinations","c":[{"t":6,"p":1,"n":"Combination","c":[{"p":1,"n":"OBTF - Editor Only"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"p":1,"n":"OBTS - Object Mod Template Item","c":[{"t":3,"p":1,"n":"Include Count"},{"t":3,"p":1,"n":"Property Count"},{"t":3,"p":1,"n":"Level Min"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Level Max"},{"t":3,"p":1,"n":"ID"},{"t":3,"p":1,"n":"Default"},{"t":7,"p":1,"n":"Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":3,"p":1,"n":"Min Level For Ranks"},{"t":3,"p":1,"n":"Alt Levels Per Tier"},{"t":7,"p":1,"n":"Includes","c":[{"t":6,"p":1,"n":"Include","c":[{"t":3,"p":1,"n":"Mod"},{"t":3,"p":1,"n":"Attach Point Index"},{"t":3,"p":1,"n":"Optional"},{"t":3,"p":1,"n":"Don't Use All"}]}]},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":3,"p":1,"n":"Value Type"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Function Type"},{"t":3,"p":1,"n":"Property"},{"t":11,"n":"Value 1 - Unknown"},{"t":3,"p":1,"n":"Value 1 - Int"},{"t":5,"p":1,"n":"Value 1 - Float"},{"t":3,"p":1,"n":"Value 1 - Bool"},{"t":3,"p":1,"n":"Value 1 - FormID"},{"t":3,"p":1,"n":"Value 1 - Enum"},{"t":3,"p":1,"n":"Sound Level"},{"t":3,"p":1,"n":"Stagger Value"},{"t":3,"p":1,"n":"Hit Behaviour"},{"t":3,"p":1,"n":"Value 2 - Int"},{"t":5,"p":1,"n":"Value 2 - Float"},{"t":3,"p":1,"n":"Value 2 - Bool"},{"t":5,"p":1,"n":"Step"}]}]}]}]}]},{"p":1,"n":"STOP - Marker"}]},{"t":3,"p":1,"n":"NNAM - Embedded Weapon Mod"},{"t":6,"s":1,"p":1,"n":"1st Person Model","c":[{"t":2,"p":1,"n":"MOD4 - Model Filename"},{"t":11,"p":1,"n":"MO4T - Texture Files Hashes"},{"t":3,"p":1,"n":"MO4S - Material Swap"},{"t":5,"p":1,"n":"MO4C - Color Remapping Index"},{"t":11,"n":"MO4F - Unknown"}]},{"t":6,"s":1,"p":1,"n":"DNAM - Data","c":[{"t":3,"p":1,"n":"Ammo"},{"t":5,"p":1,"n":"Speed"},{"t":5,"p":1,"n":"Reload Speed"},{"t":5,"p":1,"n":"Reach"},{"t":5,"p":1,"n":"Min Range"},{"t":5,"p":1,"n":"Max Range"},{"t":5,"p":1,"n":"Attack Delay"},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"Damage - OutOfRange Mult"},{"t":3,"p":1,"n":"On Hit"},{"t":3,"p":1,"n":"Skill"},{"t":3,"p":1,"n":"Resist"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Capacity"},{"t":3,"p":1,"n":"Animation Type"},{"t":5,"p":1,"n":"Damage - Secondary"},{"t":5,"p":1,"n":"Weight"},{"t":3,"p":1,"n":"Value"},{"t":3,"p":1,"n":"Damage - Base"},{"t":3,"p":1,"n":"Sound Level"},{"t":3,"p":1,"n":"Sound - Attack"},{"t":3,"p":1,"n":"Sound - Attack 2D"},{"t":3,"p":1,"n":"Sound - Attack Loop"},{"t":3,"p":1,"n":"Sound - Attack Fail"},{"t":3,"p":1,"n":"Sound - Idle"},{"t":3,"p":1,"n":"Sound - Equip Sound"},{"t":3,"p":1,"n":"Sound - UnEquip Sound"},{"t":3,"p":1,"n":"Sound - Fast Equip Sound"},{"t":3,"p":1,"n":"Accuracy Bonus"},{"t":5,"p":1,"n":"Animation Attack Seconds"},{"t":5,"p":1,"n":"Action Point Cost"},{"t":5,"p":1,"n":"Full Power Seconds"},{"t":5,"p":1,"n":"Min Power Per Shot"},{"t":3,"p":1,"n":"Stagger"}]},{"t":6,"s":1,"p":1,"n":"FNAM - ","c":[{"t":5,"p":1,"n":"Animation Fire Seconds"},{"t":5,"p":1,"n":"Rumble - Left Motor Strength"},{"t":5,"p":1,"n":"Rumble - Right Motor Strength"},{"t":5,"p":1,"n":"Rumble - Duration"},{"t":5,"p":1,"n":"Animation Reload Seconds"},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"Sighted Transition Seconds"},{"t":3,"p":1,"n":"# Projectiles"},{"t":3,"p":1,"n":"Override Projectile"},{"t":3,"p":1,"n":"Pattern"},{"t":3,"p":1,"n":"Rumble - Peroid (ms)"}]},{"t":6,"s":1,"p":1,"n":"CRDT - Critical Data","c":[{"t":5,"p":1,"n":"Crit Damage Mult"},{"t":5,"p":1,"n":"Crit Charge Bonus"},{"t":3,"p":1,"n":"Crit Effect"}]},{"t":3,"p":1,"n":"INAM - Impact Data Set"},{"t":3,"p":1,"n":"LNAM - NPC Add Ammo List"},{"t":3,"p":1,"n":"WAMD - Aim Model"},{"t":3,"p":1,"n":"WZMD - Zoom"},{"t":3,"p":1,"n":"CNAM - Template"},{"t":7,"p":1,"n":"DAMA - Damage Types","c":[{"t":6,"p":1,"n":"Damage Type","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Amount"}]}]},{"t":2,"p":1,"n":"FLTR - Filter"},{"t":3,"p":1,"n":"MASE - Melee Speed"}]},{"t":1,"p":1,"n":"WRLD - Worldspace","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":8,"n":"Unused RNAM","c":[{"t":11,"n":"RNAM - Unknown"}]},{"t":11,"n":"MHDT - Max Height Data"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"WCTR - Fixed Dimensions Center Cell","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"}]},{"t":3,"p":1,"n":"LTMP - Interior Lighting"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":3,"p":1,"n":"XLCN - Location"},{"t":6,"s":1,"p":1,"n":"Parent","c":[{"t":3,"p":1,"n":"WNAM - Worldspace"},{"t":6,"p":1,"n":"PNAM - ","c":[{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"}]}]},{"t":3,"p":1,"n":"CNAM - Climate"},{"t":3,"p":1,"n":"NAM2 - Water"},{"t":3,"p":1,"n":"NAM3 - LOD Water Type"},{"t":5,"p":1,"n":"NAM4 - LOD Water Height"},{"t":6,"s":1,"p":1,"n":"DNAM - Land Data","c":[{"t":5,"p":1,"n":"Default Land Height"},{"t":5,"p":1,"n":"Default Water Height"}]},{"t":2,"p":1,"n":"ICON - Map Image"},{"t":6,"s":1,"p":1,"n":"Cloud Model","c":[{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]}]},{"t":6,"s":1,"p":1,"n":"MNAM - Map Data","c":[{"t":6,"p":1,"n":"Usable Dimensions","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"}]},{"t":6,"p":1,"n":"Cell Coordinates","c":[{"t":6,"p":1,"n":"NW Cell","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"}]},{"t":6,"p":1,"n":"SE Cell","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"}]}]}]},{"t":6,"s":1,"p":1,"n":"ONAM - World Map Offset Data","c":[{"t":5,"p":1,"n":"World Map Scale"},{"t":5,"p":1,"n":"Cell X Offset"},{"t":5,"p":1,"n":"Cell Y Offset"},{"t":5,"p":1,"n":"Cell Z Offset"}]},{"t":5,"p":1,"n":"NAMA - Distant LOD Multiplier"},{"t":3,"p":1,"n":"DATA - Flags"},{"t":6,"s":1,"p":1,"n":"Object Bounds","c":[{"t":6,"p":1,"n":"NAM0 - Min","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"}]},{"t":6,"p":1,"n":"NAM9 - Max","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"}]}]},{"t":3,"p":1,"n":"ZNAM - Music"},{"t":2,"p":1,"n":"NNAM - Canopy Shadow (unused)"},{"t":2,"p":1,"n":"XWEM - Water Environment Map"},{"t":2,"p":1,"n":"TNAM - HD LOD Diffuse Texture"},{"t":2,"p":1,"n":"UNAM - HD LOD Normal Texture"},{"t":6,"s":1,"p":1,"n":"World Default Level Data","c":[{"t":6,"p":1,"n":"WLEV - Dimension","c":[{"t":6,"p":1,"n":"NW Cell","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"}]},{"t":6,"p":1,"n":"Size","c":[{"t":3,"p":1,"n":"Width"},{"t":3,"p":1,"n":"Height"}]}]},{"t":11,"p":1,"n":"WLEV - Data"}]},{"t":11,"n":"OFST - Offset Data"},{"t":11,"n":"CLSZ - Unknown"}]},{"t":1,"p":1,"n":"WTHR - Weather","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"00TX - Cloud Texture Layer #0"},{"t":2,"p":1,"n":"10TX - Cloud Texture Layer #1"},{"t":2,"p":1,"n":"20TX - Cloud Texture Layer #2"},{"t":2,"p":1,"n":"30TX - Cloud Texture Layer #3"},{"t":2,"p":1,"n":"40TX - Cloud Texture Layer #4"},{"t":2,"p":1,"n":"50TX - Cloud Texture Layer #5"},{"t":2,"p":1,"n":"60TX - Cloud Texture Layer #6"},{"t":2,"p":1,"n":"70TX - Cloud Texture Layer #7"},{"t":2,"p":1,"n":"80TX - Cloud Texture Layer #8"},{"t":2,"p":1,"n":"90TX - Cloud Texture Layer #9"},{"t":2,"p":1,"n":":0TX - Cloud Texture Layer #10"},{"t":2,"p":1,"n":";0TX - Cloud Texture Layer #11"},{"t":2,"p":1,"n":"<0TX - Cloud Texture Layer #12"},{"t":2,"p":1,"n":"=0TX - Cloud Texture Layer #13"},{"t":2,"p":1,"n":">0TX - Cloud Texture Layer #14"},{"t":2,"p":1,"n":"?0TX - Cloud Texture Layer #15"},{"t":2,"p":1,"n":"@0TX - Cloud Texture Layer #16"},{"t":2,"p":1,"n":"A0TX - Cloud Texture Layer #17"},{"t":2,"p":1,"n":"B0TX - Cloud Texture Layer #18"},{"t":2,"p":1,"n":"C0TX - Cloud Texture Layer #19"},{"t":2,"p":1,"n":"D0TX - Cloud Texture Layer #20"},{"t":2,"p":1,"n":"E0TX - Cloud Texture Layer #21"},{"t":2,"p":1,"n":"F0TX - Cloud Texture Layer #22"},{"t":2,"p":1,"n":"G0TX - Cloud Texture Layer #23"},{"t":2,"p":1,"n":"H0TX - Cloud Texture Layer #24"},{"t":2,"p":1,"n":"I0TX - Cloud Texture Layer #25"},{"t":2,"p":1,"n":"J0TX - Cloud Texture Layer #26"},{"t":2,"p":1,"n":"K0TX - Cloud Texture Layer #27"},{"t":2,"p":1,"n":"L0TX - Cloud Texture Layer #28"},{"t":11,"n":"LNAM - Unknown"},{"t":3,"p":1,"n":"MNAM - Precipitation Type"},{"t":3,"p":1,"n":"NNAM - Visual Effect"},{"t":11,"n":"ONAM - Unused"},{"t":6,"s":1,"p":1,"n":"Cloud Speed","c":[{"t":7,"p":1,"n":"RNAM - Y Speed","c":[{"t":3,"p":1,"n":"Layer"}]},{"t":7,"p":1,"n":"QNAM - X Speed","c":[{"t":3,"p":1,"n":"Layer"}]}]},{"t":7,"p":1,"n":"PNAM - Cloud Colors","c":[{"t":6,"p":1,"n":"Layer","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]}]},{"t":7,"p":1,"n":"JNAM - Cloud Alphas","c":[{"t":6,"p":1,"n":"Layer","c":[{"t":5,"p":1,"n":"Sunrise"},{"t":5,"p":1,"n":"Day"},{"t":5,"p":1,"n":"Sunset"},{"t":5,"p":1,"n":"Night"},{"t":5,"p":1,"n":"EarlySunrise"},{"t":5,"p":1,"n":"LateSunrise"},{"t":5,"p":1,"n":"EarlySunset"},{"t":5,"p":1,"n":"LateSunset"}]}]},{"t":6,"s":1,"p":1,"n":"NAM0 - Weather Colors","c":[{"t":6,"p":1,"n":"Sky-Upper","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Fog Near","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"n":"Unknown","c":[{"t":6,"n":"Sunrise","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"n":"Day","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"n":"Sunset","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"n":"Night","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"n":"EarlySunrise","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"n":"LateSunrise","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"n":"EarlySunset","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"n":"LateSunset","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Ambient","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Sunlight","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Sun","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Stars","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Sky-Lower","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Horizon","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Effect Lighting","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Cloud LOD Diffuse","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Cloud LOD Ambient","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Fog Far","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Sky Statics","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Water Multiplier","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Sun Glare","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Moon Glare","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Fog Near High","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Fog Far High","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"EarlySunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"LateSunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]}]},{"t":7,"n":"NAM4 - Unknown","c":[{"t":5,"n":"Unknown"}]},{"t":6,"s":1,"p":1,"n":"FNAM - Fog Distance","c":[{"t":5,"p":1,"n":"Day - Near"},{"t":5,"p":1,"n":"Day - Far"},{"t":5,"p":1,"n":"Night - Near"},{"t":5,"p":1,"n":"Night - Far"},{"t":5,"p":1,"n":"Day - Power"},{"t":5,"p":1,"n":"Night - Power"},{"t":5,"p":1,"n":"Day - Max"},{"t":5,"p":1,"n":"Night - Max"},{"t":5,"p":1,"n":"Day - Near Height Mid"},{"t":5,"p":1,"n":"Day - Near Height Range"},{"t":5,"p":1,"n":"Night - Near Height Mid"},{"t":5,"p":1,"n":"Night - Near Height Range"},{"t":5,"p":1,"n":"Day - High Density Scale"},{"t":5,"p":1,"n":"Night - High Density Scale"},{"t":5,"p":1,"n":"Day - Far Height Mid"},{"t":5,"p":1,"n":"Day - Far Height Range"},{"t":5,"p":1,"n":"Night - Far Height Mid"},{"t":5,"p":1,"n":"Night - Far Height Range"}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Wind Speed"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Trans Delta"},{"t":3,"p":1,"n":"Sun Glare"},{"t":3,"p":1,"n":"Sun Damage"},{"t":3,"p":1,"n":"Precipitation - Begin Fade In"},{"t":3,"p":1,"n":"Precipitation - End Fade Out"},{"t":3,"p":1,"n":"Thunder\/Lightning - Begin Fade In"},{"t":3,"p":1,"n":"Thunder\/Lightning - End Fade Out"},{"t":3,"p":1,"n":"Thunder\/Lightning - Frequency"},{"t":3,"p":1,"n":"Flags"},{"t":6,"p":1,"n":"Lightning Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"}]},{"t":3,"p":1,"n":"Visual Effect - Begin"},{"t":3,"p":1,"n":"Visual Effect - End"},{"t":3,"p":1,"n":"Wind Direction"},{"t":3,"p":1,"n":"Wind Direction Range"}]},{"t":3,"p":1,"n":"NAM1 - Disabled Cloud Layers"},{"t":8,"s":1,"p":1,"n":"Sounds","d":1,"c":[{"t":6,"p":1,"n":"SNAM - Sound","c":[{"t":3,"p":1,"n":"Sound"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Sky Statics","d":1,"c":[{"t":3,"p":1,"n":"TNAM - Static"}]},{"t":6,"s":1,"p":1,"n":"IMSP - Image Spaces","c":[{"t":3,"p":1,"n":"Sunrise"},{"t":3,"p":1,"n":"Day"},{"t":3,"p":1,"n":"Sunset"},{"t":3,"p":1,"n":"Night"},{"t":3,"p":1,"n":"EarlySunrise"},{"t":3,"p":1,"n":"LateSunrise"},{"t":3,"p":1,"n":"EarlySunset"},{"t":3,"p":1,"n":"LateSunset"}]},{"t":6,"s":1,"p":1,"n":"WGDR - God Rays","c":[{"t":3,"p":1,"n":"Sunrise"},{"t":3,"p":1,"n":"Day"},{"t":3,"p":1,"n":"Sunset"},{"t":3,"p":1,"n":"Night"},{"t":3,"p":1,"n":"EarlySunrise"},{"t":3,"p":1,"n":"LateSunrise"},{"t":3,"p":1,"n":"EarlySunset"},{"t":3,"p":1,"n":"LateSunset"}]},{"t":6,"s":1,"p":1,"n":"Directional Ambient Lighting Colors","c":[{"t":6,"p":1,"n":"DALC - Sunrise","c":[{"t":6,"p":1,"n":"Directional","c":[{"t":6,"p":1,"n":"X+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"X-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Specular","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Scale"}]},{"t":6,"p":1,"n":"DALC - Day","c":[{"t":6,"p":1,"n":"Directional","c":[{"t":6,"p":1,"n":"X+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"X-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Specular","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Scale"}]},{"t":6,"p":1,"n":"DALC - Sunset","c":[{"t":6,"p":1,"n":"Directional","c":[{"t":6,"p":1,"n":"X+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"X-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Specular","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Scale"}]},{"t":6,"p":1,"n":"DALC - Night","c":[{"t":6,"p":1,"n":"Directional","c":[{"t":6,"p":1,"n":"X+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"X-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Specular","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Scale"}]},{"t":6,"p":1,"n":"DALC - EarlySunrise","c":[{"t":6,"p":1,"n":"Directional","c":[{"t":6,"p":1,"n":"X+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"X-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Specular","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Scale"}]},{"t":6,"p":1,"n":"DALC - LateSunrise","c":[{"t":6,"p":1,"n":"Directional","c":[{"t":6,"p":1,"n":"X+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"X-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Specular","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Scale"}]},{"t":6,"p":1,"n":"DALC - EarlySunset","c":[{"t":6,"p":1,"n":"Directional","c":[{"t":6,"p":1,"n":"X+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"X-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Specular","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Scale"}]},{"t":6,"p":1,"n":"DALC - LateSunset","c":[{"t":6,"p":1,"n":"Directional","c":[{"t":6,"p":1,"n":"X+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"X-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Specular","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Scale"}]}]},{"t":6,"s":1,"p":1,"n":"Aurora","c":[{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":3,"p":1,"n":"MODS - Material Swap"},{"t":5,"p":1,"n":"MODC - Color Remapping Index"},{"t":11,"n":"MODF - Unknown"}]}]},{"t":3,"p":1,"n":"GNAM - Sun Glare Lens Flare"},{"t":6,"s":1,"p":1,"n":"UNAM - Magic","c":[{"t":3,"p":1,"n":"On Lightning Strike - Spell"},{"t":5,"p":1,"n":"On Lightning Strike - Threshold"},{"t":3,"p":1,"n":"On Weather Activate - Spell"},{"t":5,"p":1,"n":"On Weather Activate - Threshold"},{"t":11,"n":"Unknown"}]},{"t":5,"p":1,"n":"VNAM - Volatility Mult"},{"t":5,"p":1,"n":"WNAM - Visibility Mult"}]},{"t":1,"p":1,"n":"ZOOM - Zoom","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"GNAM - Data","c":[{"t":5,"p":1,"n":"FOV Mult"},{"t":3,"p":1,"n":"Overlay"},{"t":3,"p":1,"n":"Imagespace Modifier"},{"t":6,"p":1,"n":"Camera Offset","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"AACT - Action","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"CNAM - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":2,"p":1,"n":"DNAM - Notes"},{"t":3,"p":1,"n":"TNAM - Type"},{"t":3,"p":1,"n":"DATA - Attraction Rule"},{"t":2,"p":1,"n":"FULL - Name"}]}]},"name":"Smash.All","hash":"A4B4931B","color":128} ================================================ FILE: frontend/settings/FalloutNV/Smash.All.json ================================================ {"records":"ACHR,ACTI,ADDN,ALCH,ALOC,AMEF,AMMO,ANIO,ARMA,ARMO,ASPC,AVIF,BOOK,BPTD,CAMS,CCRD,CDCK,CELL,CHAL,CHIP,CLAS,CLMT,CMNY,COBJ,CONT,CPTH,CREA,CSNO,CSTY,DEBR,DEHY,DIAL,DOOR,ECZN,EFSH,ENCH,EXPL,EYES,FACT,FLST,FURN,GLOB,GMST,GRAS,HAIR,HDPT,HUNG,IDLM,IMAD,IMGS,IMOD,INFO,INGR,IPCT,IPDS,KEYM,LAND,LGTM,LIGH,LSCR,LSCT,LTEX,LVLC,LVLI,LVLN,MESG,MGEF,MICN,MISC,MSET,MSTT,MUSC,NOTE,NPC_,PACK,PBEA,PERK,PGRE,PMIS,PROJ,PWAT,QUST,RACE,RADS,RCCT,RCPE,REFR,REGN,REPU,RGDL,SCOL,SCPT,SLPD,SOUN,SPEL,STAT,TACT,TERM,TREE,TXST,VTYP,WATR,WEAP,WRLD,WTHR,ACRE","description":"Smashes all the things. Produced using autoset attributes on all record prototypes produced by v1.0.0.\r\n\r\nLast updated 04\/30\/2018.","tree":{"records":[{"t":1,"p":1,"n":"ACHR - Placed NPC","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"NAME - Base"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":11,"n":"XRGD - Ragdoll Data"},{"t":11,"n":"XRGB - Ragdoll Biped Data"},{"t":6,"s":1,"p":1,"n":"Patrol Data","c":[{"t":5,"p":1,"n":"XPRD - Idle Time"},{"p":1,"n":"XPPA - Patrol Script Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":6,"p":1,"n":"Embedded Script","c":[{"t":6,"p":1,"n":"SCHR - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"p":1,"n":"SCDA - Compiled Embedded Script"},{"t":2,"p":1,"n":"SCTX - Embedded Script Source"},{"t":10,"p":1,"n":"Local Variables","c":[{"t":6,"p":1,"n":"Local Variable","c":[{"t":6,"p":1,"n":"SLSD - Local Variable Data","c":[{"t":3,"p":1,"n":"Index"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"SCVR - Name"}]}]},{"t":8,"p":1,"n":"References","c":[{"t":3,"p":1,"n":"SCRO - Global Reference"},{"t":3,"p":1,"n":"SCRV - Local Variable"}]}]},{"t":3,"p":1,"n":"TNAM - Topic"}]},{"t":3,"p":1,"n":"XLCM - Level Modifier"},{"t":3,"p":1,"n":"XMRC - Merchant Container"},{"t":3,"p":1,"n":"XCNT - Count"},{"t":5,"p":1,"n":"XRDS - Radius"},{"t":5,"p":1,"n":"XHLP - Health"},{"t":8,"s":1,"p":1,"n":"Linked Decals","d":1,"c":[{"t":6,"p":1,"n":"XDCR - Decal","c":[{"t":3,"p":1,"n":"Reference"},{"t":11,"n":"Unknown"}]}]},{"t":3,"p":1,"n":"XLKR - Linked Reference"},{"t":6,"s":1,"p":1,"n":"XCLP - Linked Reference Color","c":[{"t":6,"p":1,"n":"Link Start Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Link End Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":2,"p":1,"n":"XATO - Activation Prompt"},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIBS - Ignored By Sandbox"},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"ACTI - Activator","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"SNAM - Sound - Looping"},{"t":3,"p":1,"n":"VNAM - Sound - Activation"},{"t":3,"p":1,"n":"INAM - Radio Template"},{"t":3,"p":1,"n":"RNAM - Radio Station"},{"t":3,"p":1,"n":"WNAM - Water Type"},{"t":2,"p":1,"n":"XATO - Activation Prompt"}]},{"t":1,"p":1,"n":"ADDN - Addon Node","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":3,"p":1,"n":"DATA - Node Index"},{"t":3,"p":1,"n":"SNAM - Sound"},{"t":6,"s":1,"p":1,"n":"DNAM - Data","c":[{"t":3,"p":1,"n":"Master Particle System Cap"},{"t":11,"n":"Unknown"}]}]},{"t":1,"p":1,"n":"ALCH - Ingestible","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Drop"},{"t":3,"p":1,"n":"ETYP - Equiptment Type"},{"t":5,"p":1,"n":"DATA - Weight"},{"t":6,"s":1,"p":1,"n":"ENIT - Effect Data","c":[{"t":3,"p":1,"n":"Value"},{"t":3,"p":1,"n":"Flags?"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Withdrawal Effect"},{"t":5,"p":1,"n":"Addiction Chance"},{"t":3,"p":1,"n":"Sound - Consume"}]},{"t":8,"s":1,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":3,"p":1,"n":"EFID - Base Effect"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":3,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Actor Value"}]},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"CTDA - Condition","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Note"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Creature Type"},{"t":3,"p":1,"n":"Menu Mode"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Body Location"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Quest Objective (INVALID)"},{"t":3,"p":1,"n":"Reputation"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Challenge"},{"t":3,"p":1,"n":"Casino"},{"t":3,"p":1,"n":"Form"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"VATS Value Function (INVALID)"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Quest Objective"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"}]}]}]}]}]},{"t":1,"p":1,"n":"ALOC - Media Location Controller","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":11,"n":"NAM1 - Flags and Enums, messily combined"},{"t":11,"n":"NAM2 - Unknown"},{"t":11,"n":"NAM3 - Unknown"},{"t":5,"p":1,"n":"NAM4 - Location Delay"},{"t":3,"p":1,"n":"NAM5 - Day Start"},{"t":3,"p":1,"n":"NAM6 - Night Start"},{"t":5,"p":1,"n":"NAM7 - Retrigger Delay"},{"t":8,"s":1,"p":1,"n":"Neutral Sets","d":1,"c":[{"t":3,"p":1,"n":"HNAM - Media Set"}]},{"t":8,"s":1,"p":1,"n":"Ally Sets","d":1,"c":[{"t":3,"p":1,"n":"ZNAM - Media Set"}]},{"t":8,"s":1,"p":1,"n":"Friend Sets","d":1,"c":[{"t":3,"p":1,"n":"XNAM - Media Set"}]},{"t":8,"s":1,"p":1,"n":"Enemy Sets","d":1,"c":[{"t":3,"p":1,"n":"YNAM - Media Set"}]},{"t":8,"s":1,"p":1,"n":"Location Sets","d":1,"c":[{"t":3,"p":1,"n":"LNAM - Media Set"}]},{"t":8,"s":1,"p":1,"n":"Battle Sets","d":1,"c":[{"t":3,"p":1,"n":"GNAM - Media Set"}]},{"t":3,"p":1,"n":"RNAM - Conditional Faction"},{"t":11,"n":"FNAM - Unknown"}]},{"t":1,"p":1,"n":"AMEF - Ammo Effect","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Operation"},{"t":5,"p":1,"n":"Value"}]}]},{"t":1,"p":1,"n":"AMMO - Ammunition","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Drop"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":5,"p":1,"n":"Speed"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Value"},{"t":3,"p":1,"n":"Clip Rounds"}]},{"t":6,"s":1,"p":1,"n":"DAT2 - Data 2","c":[{"t":3,"p":1,"n":"Proj. per Shot"},{"t":3,"p":1,"n":"Projectile"},{"t":5,"p":1,"n":"Weight"},{"t":3,"p":1,"n":"Consumed Ammo"},{"t":5,"p":1,"n":"Consumed Percentage"}]},{"t":2,"p":1,"n":"ONAM - Short Name"},{"t":2,"p":1,"n":"QNAM - Abbrev."},{"t":8,"s":1,"p":1,"n":"Ammo Effects","d":1,"c":[{"t":3,"p":1,"n":"RCIL - Effect"}]}]},{"t":1,"p":1,"n":"ANIO - Animated Object","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":3,"p":1,"n":"DATA - Animation"}]},{"t":1,"p":1,"n":"ARMA - Armor Addon","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"BMDT - Biped Data","c":[{"t":3,"p":1,"n":"Biped Flags"},{"t":3,"p":1,"n":"General Flags"},{"t":11,"n":"Unused"}]},{"t":6,"s":1,"p":1,"n":"Male biped model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Male world model","c":[{"t":2,"p":1,"n":"MOD2 - Model Filename"},{"t":11,"p":1,"n":"MO2T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO2S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":2,"p":1,"n":"ICON - Male icon filename"},{"t":2,"p":1,"n":"MICO - Male mico filename"},{"t":6,"s":1,"p":1,"n":"Female biped model","c":[{"t":2,"p":1,"n":"MOD3 - Model Filename"},{"t":11,"p":1,"n":"MO3T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO3S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MOSD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Female world model","c":[{"t":2,"p":1,"n":"MOD4 - Model Filename"},{"t":11,"p":1,"n":"MO4T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO4S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":2,"p":1,"n":"ICO2 - Female icon filename"},{"t":2,"p":1,"n":"MIC2 - Female mico filename"},{"t":3,"p":1,"n":"ETYP - Equiptment Type"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Value"},{"t":3,"p":1,"n":"Max Condition"},{"t":5,"p":1,"n":"Weight"}]},{"t":6,"s":1,"p":1,"n":"DNAM - ","c":[{"t":3,"p":1,"n":"AR"},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"DT"},{"t":11,"n":"Unused"}]}]},{"t":1,"p":1,"n":"ARMO - Armor","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"SCRI - Script"},{"t":3,"p":1,"n":"EITM - Object Effect"},{"t":6,"s":1,"p":1,"n":"BMDT - Biped Data","c":[{"t":3,"p":1,"n":"Biped Flags"},{"t":3,"p":1,"n":"General Flags"},{"t":11,"n":"Unused"}]},{"t":6,"s":1,"p":1,"n":"Male biped model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Male world model","c":[{"t":2,"p":1,"n":"MOD2 - Model Filename"},{"t":11,"p":1,"n":"MO2T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO2S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":2,"p":1,"n":"ICON - Male icon filename"},{"t":2,"p":1,"n":"MICO - Male mico filename"},{"t":6,"s":1,"p":1,"n":"Female biped model","c":[{"t":2,"p":1,"n":"MOD3 - Model Filename"},{"t":11,"p":1,"n":"MO3T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO3S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MOSD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Female world model","c":[{"t":2,"p":1,"n":"MOD4 - Model Filename"},{"t":11,"p":1,"n":"MO4T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO4S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":2,"p":1,"n":"ICO2 - Female icon filename"},{"t":2,"p":1,"n":"MIC2 - Female mico filename"},{"t":2,"p":1,"n":"BMCT - Ragdoll Constraint Template"},{"t":3,"p":1,"n":"REPL - Repair List"},{"t":3,"p":1,"n":"BIPL - Biped Model List"},{"t":3,"p":1,"n":"ETYP - Equiptment Type"},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Drop"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Value"},{"t":3,"p":1,"n":"Health"},{"t":5,"p":1,"n":"Weight"}]},{"t":6,"s":1,"p":1,"n":"DNAM - ","c":[{"t":3,"p":1,"n":"AR"},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"DT"},{"t":11,"p":1,"n":"?"}]},{"t":3,"p":1,"n":"BNAM - Overrides Animation Sounds"},{"t":8,"s":1,"p":1,"n":"Animation Sounds","d":1,"c":[{"t":6,"p":1,"n":"SNAM - Animation Sound","c":[{"t":3,"p":1,"n":"Sound"},{"t":3,"p":1,"n":"Chance"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Type"}]}]},{"t":3,"p":1,"n":"TNAM - Animation Sounds Template"}]},{"t":1,"p":1,"n":"ASPC - Acoustic Space","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"SNAM - Dawn \/ Default Loop"},{"t":3,"p":1,"n":"SNAM - Afternoon"},{"t":3,"p":1,"n":"SNAM - Dusk"},{"t":3,"p":1,"n":"SNAM - Night"},{"t":3,"p":1,"n":"SNAM - Walla"},{"t":3,"p":1,"n":"WNAM - Walla Trigger Count"},{"t":3,"p":1,"n":"RDAT - Use Sound from Region (Interiors Only)"},{"t":3,"p":1,"n":"ANAM - Environment Type"},{"t":3,"p":1,"n":"INAM - Is Interior"}]},{"t":1,"p":1,"n":"AVIF - ActorValue Information","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":2,"p":1,"n":"ANAM - Short Name"}]},{"t":1,"p":1,"n":"BOOK - Book","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Drop"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Skill"},{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]}]},{"t":1,"p":1,"n":"BPTD - Body Part Data","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":8,"s":1,"p":1,"n":"Body Parts","d":1,"c":[{"t":6,"p":1,"n":"Body Part","c":[{"t":2,"p":1,"n":"BPTN - Part Name"},{"t":2,"p":1,"n":"BPNN - Part Node"},{"t":2,"p":1,"n":"BPNT - VATS Target"},{"t":2,"p":1,"n":"BPNI - IK Data - Start Node"},{"t":6,"p":1,"n":"BPND - ","c":[{"t":5,"p":1,"n":"Damage Mult"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Part Type"},{"t":3,"p":1,"n":"Health Percent"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"To Hit Chance"},{"t":3,"p":1,"n":"Explodable - Explosion Chance %"},{"t":3,"p":1,"n":"Explodable - Debris Count"},{"t":3,"p":1,"n":"Explodable - Debris"},{"t":3,"p":1,"n":"Explodable - Explosion"},{"t":5,"p":1,"n":"Tracking Max Angle"},{"t":5,"p":1,"n":"Explodable - Debris Scale"},{"t":3,"p":1,"n":"Severable - Debris Count"},{"t":3,"p":1,"n":"Severable - Debris"},{"t":3,"p":1,"n":"Severable - Explosion"},{"t":5,"p":1,"n":"Severable - Debris Scale"},{"t":6,"p":1,"n":"Gore Effects Positioning","c":[{"t":6,"p":1,"n":"Translate","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]},{"t":3,"p":1,"n":"Severable - Impact DataSet"},{"t":3,"p":1,"n":"Explodable - Impact DataSet"},{"t":3,"p":1,"n":"Severable - Decal Count"},{"t":3,"p":1,"n":"Explodable - Decal Count"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Limb Replacement Scale"}]},{"t":2,"p":1,"n":"NAM1 - Limb Replacement Model"},{"t":2,"p":1,"n":"NAM4 - Gore Effects - Target Bone"},{"t":11,"p":1,"n":"NAM5 - Texture Files Hashes"}]}]},{"t":8,"s":1,"p":1,"n":"Unnamed Body Parts","d":1,"c":[{"t":6,"p":1,"n":"Body Part","c":[{"t":2,"p":1,"n":"BPNN - Part Node"},{"t":2,"p":1,"n":"BPNT - VATS Target"},{"t":2,"p":1,"n":"BPNI - IK Data - Start Node"},{"t":6,"p":1,"n":"BPND - ","c":[{"t":5,"p":1,"n":"Damage Mult"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Part Type"},{"t":3,"p":1,"n":"Health Percent"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"To Hit Chance"},{"t":3,"p":1,"n":"Explodable - Explosion Chance %"},{"t":3,"p":1,"n":"Explodable - Debris Count"},{"t":3,"p":1,"n":"Explodable - Debris"},{"t":3,"p":1,"n":"Explodable - Explosion"},{"t":5,"p":1,"n":"Tracking Max Angle"},{"t":5,"p":1,"n":"Explodable - Debris Scale"},{"t":3,"p":1,"n":"Severable - Debris Count"},{"t":3,"p":1,"n":"Severable - Debris"},{"t":3,"p":1,"n":"Severable - Explosion"},{"t":5,"p":1,"n":"Severable - Debris Scale"},{"t":6,"p":1,"n":"Gore Effects Positioning","c":[{"t":6,"p":1,"n":"Translate","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]},{"t":3,"p":1,"n":"Severable - Impact DataSet"},{"t":3,"p":1,"n":"Explodable - Impact DataSet"},{"t":3,"p":1,"n":"Severable - Decal Count"},{"t":3,"p":1,"n":"Explodable - Decal Count"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Limb Replacement Scale"}]},{"t":2,"p":1,"n":"NAM1 - Limb Replacement Model"},{"t":2,"p":1,"n":"NAM4 - Gore Effects - Target Bone"},{"t":11,"p":1,"n":"NAM5 - Texture Files Hashes"}]}]},{"t":3,"p":1,"n":"RAGA - Ragdoll"}]},{"t":1,"p":1,"n":"CAMS - Camera Shot","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Action"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Flags"},{"t":6,"p":1,"n":"Time Multipliers","c":[{"t":5,"p":1,"n":"Player"},{"t":5,"p":1,"n":"Target"},{"t":5,"p":1,"n":"Global"}]},{"t":5,"p":1,"n":"Max Time"},{"t":5,"p":1,"n":"Min Time"},{"t":5,"p":1,"n":"Target % Between Actors"}]},{"t":3,"p":1,"n":"MNAM - Image Space Modifier"}]},{"t":1,"p":1,"n":"CCRD - Caravan Card","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Drop"},{"t":6,"s":1,"p":1,"n":"High Res Image","c":[{"t":2,"p":1,"n":"TX00 - Face"},{"t":2,"p":1,"n":"TX01 - Back"}]},{"t":6,"s":1,"p":1,"n":"Card","c":[{"t":3,"p":1,"n":"INTV - Suit"},{"t":3,"p":1,"n":"INTV - Value"}]},{"t":3,"p":1,"n":"DATA - Value"}]},{"t":1,"p":1,"n":"CDCK - Caravan Deck","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":8,"s":1,"p":1,"n":"Cards","d":1,"c":[{"t":3,"p":1,"n":"CARD - Card"}]},{"t":3,"p":1,"n":"DATA - Count (broken)"}]},{"t":1,"p":1,"n":"CELL - Cell","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"DATA - Flags"},{"t":6,"s":1,"p":1,"n":"XCLC - Grid","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"},{"t":3,"p":1,"n":"Force Hide Land"}]},{"t":6,"s":1,"p":1,"n":"XCLL - Lighting","c":[{"t":6,"p":1,"n":"Ambient Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Directional Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Fog Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Fog Near"},{"t":5,"p":1,"n":"Fog Far"},{"t":3,"p":1,"n":"Directional Rotation XY"},{"t":3,"p":1,"n":"Directional Rotation Z"},{"t":5,"p":1,"n":"Directional Fade"},{"t":5,"p":1,"n":"Fog Clip Dist"},{"t":5,"p":1,"n":"Fog Power"}]},{"t":7,"n":"IMPF - Footstep Materials","c":[{"t":2,"n":"Unknown"}]},{"t":6,"s":1,"p":1,"n":"Light Template","c":[{"t":3,"p":1,"n":"LTMP - Template"},{"t":3,"p":1,"n":"LNAM - Inherit"}]},{"t":5,"p":1,"n":"XCLW - Water Height"},{"t":2,"p":1,"n":"XNAM - Water Noise Texture"},{"t":7,"p":1,"n":"XCLR - Regions","c":[{"t":3,"p":1,"n":"Region"}]},{"t":3,"p":1,"n":"XCIM - Image Space"},{"t":11,"n":"XCET - Unknown"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":3,"p":1,"n":"XCCM - Climate"},{"t":3,"p":1,"n":"XCWT - Water"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":3,"p":1,"n":"XCAS - Acoustic Space"},{"t":11,"n":"XCMT - Unused"},{"t":3,"p":1,"n":"XCMO - Music Type"}]},{"t":1,"p":1,"n":"CHAL - Challenge","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Threshold"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Interval"},{"t":11,"p":1,"n":"(depends on type)"}]},{"t":3,"p":1,"n":"SNAM - (depends on type)"},{"t":3,"p":1,"n":"XNAM - (depends on type)"}]},{"t":1,"p":1,"n":"CHIP - Casino Chip","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Drop"}]},{"t":1,"p":1,"n":"CLAS - Class","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":7,"p":1,"n":"Tag Skills","c":[{"t":3,"p":1,"n":"Tag Skill"}]},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Buys\/Sells and Services"},{"t":3,"p":1,"n":"Teaches"},{"t":3,"p":1,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":7,"p":1,"n":"ATTR - Attributes","c":[{"t":3,"p":1,"n":"Attribute"}]}]},{"t":1,"p":1,"n":"CLMT - Climate","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":7,"p":1,"n":"WLST - Weather Types","c":[{"t":6,"p":1,"n":"Weather Type","c":[{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Chance"},{"t":3,"p":1,"n":"Global"}]}]},{"t":2,"p":1,"n":"FNAM - Sun Texture"},{"t":2,"p":1,"n":"GNAM - Sun Glare Texture"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"TNAM - Timing","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Begin"},{"t":3,"p":1,"n":"End"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Begin"},{"t":3,"p":1,"n":"End"}]},{"t":3,"p":1,"n":"Volatility"},{"t":3,"p":1,"n":"Moons \/ Phase Length"}]}]},{"t":1,"p":1,"n":"CMNY - Caravan Money","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Drop"},{"t":3,"p":1,"n":"DATA - Absolute Value"}]},{"t":1,"p":1,"n":"COBJ - Constructible Object","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Drop"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]}]},{"t":1,"p":1,"n":"CONT - Container","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":10,"p":1,"n":"Items","d":1,"c":[{"t":6,"p":1,"n":"Item","c":[{"t":6,"p":1,"n":"CNTO - Item","c":[{"t":3,"p":1,"n":"Item"},{"t":3,"p":1,"n":"Count"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Weight"}]},{"t":3,"p":1,"n":"SNAM - Sound - Open"},{"t":3,"p":1,"n":"QNAM - Sound - Close"},{"t":3,"p":1,"n":"RNAM - Sound - Random\/Looping"}]},{"t":1,"p":1,"n":"CPTH - Camera Path","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"CTDA - Condition","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Note"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Creature Type"},{"t":3,"p":1,"n":"Menu Mode"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Body Location"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Quest Objective (INVALID)"},{"t":3,"p":1,"n":"Reputation"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Challenge"},{"t":3,"p":1,"n":"Casino"},{"t":3,"p":1,"n":"Form"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"VATS Value Function (INVALID)"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Quest Objective"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"}]}]},{"t":7,"p":1,"n":"ANAM - Related Camera Paths","c":[{"t":3,"p":1,"n":"Related Camera Path"}]},{"t":3,"p":1,"n":"DATA - Camera Zoom"},{"t":8,"s":1,"p":1,"n":"Camera Shots","d":1,"c":[{"t":3,"p":1,"n":"SNAM - Camera Shot"}]}]},{"t":1,"p":1,"n":"CREA - Creature","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":8,"s":1,"p":1,"n":"Actor Effects","d":1,"c":[{"t":3,"p":1,"n":"SPLO - Actor Effect"}]},{"t":3,"p":1,"n":"EITM - Unarmed Attack Effect"},{"t":3,"p":1,"n":"EAMT - Unarmed Attack Animation"},{"t":7,"p":1,"n":"NIFZ - Model List","c":[{"t":2,"p":1,"n":"Model"}]},{"t":11,"n":"NIFT - Texture Files Hashes"},{"t":6,"s":1,"p":1,"n":"ACBS - Configuration","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Fatigue"},{"t":3,"p":1,"n":"Barter gold"},{"t":3,"p":1,"n":"Level"},{"t":3,"p":1,"n":"Level Mult"},{"t":3,"p":1,"n":"Calc min"},{"t":3,"p":1,"n":"Calc max"},{"t":3,"p":1,"n":"Speed Multiplier"},{"t":5,"p":1,"n":"Karma (Alignment)"},{"t":3,"p":1,"n":"Disposition Base"},{"t":3,"p":1,"n":"Template Flags"}]},{"t":8,"s":1,"p":1,"n":"Factions","d":1,"c":[{"t":6,"p":1,"n":"SNAM - Faction","c":[{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"p":1,"n":"INAM - Death item"},{"t":3,"p":1,"n":"VTCK - Voice"},{"t":3,"p":1,"n":"TPLT - Template"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":10,"p":1,"n":"Items","d":1,"c":[{"t":6,"p":1,"n":"Item","c":[{"t":6,"p":1,"n":"CNTO - Item","c":[{"t":3,"p":1,"n":"Item"},{"t":3,"p":1,"n":"Count"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]},{"t":6,"s":1,"p":1,"n":"AIDT - AI Data","c":[{"t":3,"p":1,"n":"Aggression"},{"t":3,"p":1,"n":"Confidence"},{"t":3,"p":1,"n":"Energy Level"},{"t":3,"p":1,"n":"Responsibility"},{"t":3,"p":1,"n":"Mood"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Buys\/Sells and Services"},{"t":3,"p":1,"n":"Teaches"},{"t":3,"p":1,"n":"Maximum training level"},{"t":3,"p":1,"n":"Assistance"},{"t":3,"p":1,"n":"Aggro Radius Behavior"},{"t":3,"p":1,"n":"Aggro Radius"}]},{"t":8,"s":1,"p":1,"n":"Packages","d":1,"c":[{"t":3,"p":1,"n":"PKID - Package"}]},{"t":7,"p":1,"n":"KFFZ - Animations","c":[{"t":2,"p":1,"n":"Animation"}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Combat Skill"},{"t":3,"p":1,"n":"Magic Skill"},{"t":3,"p":1,"n":"Stealth Skill"},{"t":3,"p":1,"n":"Health"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Damage"},{"t":7,"p":1,"n":"Attributes","c":[{"t":3,"p":1,"n":"Attribute"}]}]},{"t":3,"p":1,"n":"RNAM - Attack reach"},{"t":3,"p":1,"n":"ZNAM - Combat Style"},{"t":3,"p":1,"n":"PNAM - Body Part Data"},{"t":5,"p":1,"n":"TNAM - Turning Speed"},{"t":5,"p":1,"n":"BNAM - Base Scale"},{"t":5,"p":1,"n":"WNAM - Foot Weight"},{"t":3,"p":1,"n":"NAM4 - Impact Material Type"},{"t":3,"p":1,"n":"NAM5 - Sound Level"},{"t":3,"p":1,"n":"CSCR - Inherits Sounds from"},{"t":10,"p":1,"n":"Sound Types","d":1,"c":[{"t":6,"p":1,"n":"Sound Type","c":[{"t":3,"p":1,"n":"CSDT - Type"},{"t":10,"p":1,"n":"Sounds","c":[{"t":6,"p":1,"n":"Sound","c":[{"t":3,"p":1,"n":"CSDI - Sound"},{"t":3,"p":1,"n":"CSDC - Sound Chance"}]}]}]}]},{"t":3,"p":1,"n":"CNAM - Impact Dataset"},{"t":3,"p":1,"n":"LNAM - Melee Weapon List"}]},{"t":1,"p":1,"n":"CSNO - Casino","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":5,"p":1,"n":"Decks % Before Shuffle"},{"t":5,"p":1,"n":"BlackJack Payout Ratio"},{"t":7,"p":1,"n":"Slot Reel Stops","c":[{"t":3,"p":1,"n":"Reel"}]},{"t":3,"p":1,"n":"Number of Decks"},{"t":3,"p":1,"n":"Max Winnings"},{"t":3,"p":1,"n":"Currency"},{"t":3,"p":1,"n":"Casino Winnings Quest"},{"t":3,"p":1,"n":"Flags"}]},{"t":6,"s":1,"p":1,"n":"Casino Chip Models","c":[{"t":2,"p":1,"n":"MODL - $1 Chip"},{"t":2,"p":1,"n":"MODL - $5 Chip"},{"t":2,"p":1,"n":"MODL - $10 Chip"},{"t":2,"p":1,"n":"MODL - $25 Chip"},{"t":2,"p":1,"n":"MODL - $100 Chip"},{"t":2,"p":1,"n":"MODL - $500 Chip"},{"t":2,"p":1,"n":"MODL - Roulette Chip"}]},{"t":2,"p":1,"n":"MODL - Slot Machine Model"},{"t":2,"p":1,"n":"MOD2 - Slot Machine Model (again?)"},{"t":2,"p":1,"n":"MOD3 - BlackJack Table Model"},{"t":2,"p":1,"n":"MODT - BlackJack Table Model related"},{"t":2,"p":1,"n":"MOD4 - Roulette Table Model"},{"t":6,"s":1,"p":1,"n":"Slot Reel Textures","c":[{"t":2,"p":1,"n":"ICON - Symbol 1"},{"t":2,"p":1,"n":"ICON - Symbol 2"},{"t":2,"p":1,"n":"ICON - Symbol 3"},{"t":2,"p":1,"n":"ICON - Symbol 4"},{"t":2,"p":1,"n":"ICON - Symbol 5"},{"t":2,"p":1,"n":"ICON - Symbol 6"},{"t":2,"p":1,"n":"ICON - Symbol W"}]},{"t":6,"s":1,"p":1,"n":"BlackJack Decks","c":[{"t":2,"p":1,"n":"ICO2 - Deck 1"},{"t":2,"p":1,"n":"ICO2 - Deck 2"},{"t":2,"p":1,"n":"ICO2 - Deck 3"},{"t":2,"p":1,"n":"ICO2 - Deck 4"}]}]},{"t":1,"p":1,"n":"CSTY - Combat Style","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"CSTD - Advanced - Standard","c":[{"t":3,"p":1,"n":"Maneuver Decision - Dodge % Chance"},{"t":3,"p":1,"n":"Maneuver Decision - Left\/Right % Chance"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Maneuver Decision - Dodge L\/R Timer (min)"},{"t":5,"p":1,"n":"Maneuver Decision - Dodge L\/R Timer (max)"},{"t":5,"p":1,"n":"Maneuver Decision - Dodge Forward Timer (min)"},{"t":5,"p":1,"n":"Maneuver Decision - Dodge Forward Timer (max)"},{"t":5,"p":1,"n":"Maneuver Decision - Dodge Back Timer Min"},{"t":5,"p":1,"n":"Maneuver Decision - Dodge Back Timer Max"},{"t":5,"p":1,"n":"Maneuver Decision - Idle Timer min"},{"t":5,"p":1,"n":"Maneuver Decision - Idle Timer max"},{"t":3,"p":1,"n":"Melee Decision - Block % Chance"},{"t":3,"p":1,"n":"Melee Decision - Attack % Chance"},{"t":5,"p":1,"n":"Melee Decision - Recoil\/Stagger Bonus to Attack"},{"t":5,"p":1,"n":"Melee Decision - Unconscious Bonus to Attack"},{"t":5,"p":1,"n":"Melee Decision - Hand-To-Hand Bonus to Attack"},{"t":3,"p":1,"n":"Melee Decision - Power Attacks - Power Attack % Chance"},{"t":5,"p":1,"n":"Melee Decision - Power Attacks - Recoil\/Stagger Bonus to Power"},{"t":5,"p":1,"n":"Melee Decision - Power Attacks - Unconscious Bonus to Power Attack"},{"t":3,"p":1,"n":"Melee Decision - Power Attacks - Normal"},{"t":3,"p":1,"n":"Melee Decision - Power Attacks - Forward"},{"t":3,"p":1,"n":"Melee Decision - Power Attacks - Back"},{"t":3,"p":1,"n":"Melee Decision - Power Attacks - Left"},{"t":3,"p":1,"n":"Melee Decision - Power Attacks - Right"},{"t":5,"p":1,"n":"Melee Decision - Hold Timer (min)"},{"t":5,"p":1,"n":"Melee Decision - Hold Timer (max)"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Maneuver Decision - Acrobatic Dodge % Chance"},{"t":3,"p":1,"n":"Melee Decision - Power Attacks - Rushing Attack % Chance"},{"t":5,"p":1,"n":"Melee Decision - Power Attacks - Rushing Attack Distance Mult"}]},{"t":6,"s":1,"p":1,"n":"CSAD - Advanced - Advanced","c":[{"t":5,"p":1,"n":"Dodge Fatigue Mod Mult"},{"t":5,"p":1,"n":"Dodge Fatigue Mod Base"},{"t":5,"p":1,"n":"Encumb. Speed Mod Base"},{"t":5,"p":1,"n":"Encumb. Speed Mod Mult"},{"t":5,"p":1,"n":"Dodge While Under Attack Mult"},{"t":5,"p":1,"n":"Dodge Not Under Attack Mult"},{"t":5,"p":1,"n":"Dodge Back While Under Attack Mult"},{"t":5,"p":1,"n":"Dodge Back Not Under Attack Mult"},{"t":5,"p":1,"n":"Dodge Forward While Attacking Mult"},{"t":5,"p":1,"n":"Dodge Forward Not Attacking Mult"},{"t":5,"p":1,"n":"Block Skill Modifier Mult"},{"t":5,"p":1,"n":"Block Skill Modifier Base"},{"t":5,"p":1,"n":"Block While Under Attack Mult"},{"t":5,"p":1,"n":"Block Not Under Attack Mult"},{"t":5,"p":1,"n":"Attack Skill Modifier Mult"},{"t":5,"p":1,"n":"Attack Skill Modifier Base"},{"t":5,"p":1,"n":"Attack While Under Attack Mult"},{"t":5,"p":1,"n":"Attack Not Under Attack Mult"},{"t":5,"p":1,"n":"Attack During Block Mult"},{"t":5,"p":1,"n":"Power Att. Fatigue Mod Base"},{"t":5,"p":1,"n":"Power Att. Fatigue Mod Mult"}]},{"t":6,"s":1,"p":1,"n":"CSSD - Simple","c":[{"t":5,"p":1,"n":"Cover Search Radius"},{"t":5,"p":1,"n":"Take Cover Chance"},{"t":5,"p":1,"n":"Wait Timer (min)"},{"t":5,"p":1,"n":"Wait Timer (max)"},{"t":5,"p":1,"n":"Wait to Fire Timer (min)"},{"t":5,"p":1,"n":"Wait to Fire Timer (max)"},{"t":5,"p":1,"n":"Fire Timer (min)"},{"t":5,"p":1,"n":"Fire Timer (max)"},{"t":5,"p":1,"n":"Ranged Weapon Range Mult (min)"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Weapon Restrictions"},{"t":5,"p":1,"n":"Ranged Weapon Range Mult (max)"},{"t":5,"p":1,"n":"Max Targeting FOV"},{"t":5,"p":1,"n":"Combat Radius"},{"t":5,"p":1,"n":"Semi-Auto Firing Delay Mult (min)"},{"t":5,"p":1,"n":"Semi-Auto Firing Delay Mult (max)"}]}]},{"t":1,"p":1,"n":"DEBR - Debris","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":8,"s":1,"p":1,"n":"Models","d":1,"c":[{"t":6,"p":1,"n":"Model","c":[{"t":6,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Percentage"},{"t":2,"p":1,"n":"Model Filename"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]}]}]},{"t":1,"p":1,"n":"DEHY - Dehydration Stage","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Trigger Threshold"},{"t":3,"p":1,"n":"Actor Effect"}]}]},{"t":1,"p":1,"n":"DIAL - Dialog Topic","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":10,"p":1,"n":"Added Quests","d":1,"c":[{"t":6,"p":1,"n":"Added Quest","c":[{"t":3,"p":1,"n":"QSTI - Quest"},{"t":8,"p":1,"n":"Shared Infos","c":[{"t":6,"p":1,"n":"Shared Info","c":[{"t":3,"p":1,"n":"INFC - Info Connection"},{"t":3,"p":1,"n":"INFX - Info Index"}]}]}]}]},{"t":10,"p":1,"n":"Removed Quests","d":1,"c":[{"t":6,"p":1,"n":"Removed Quest","c":[{"t":3,"p":1,"n":"QSTR - Quest"}]}]},{"t":8,"n":"Unused","c":[{"t":6,"n":"Unused","c":[{"t":11,"n":"INFC - Unknown"},{"t":11,"n":"INFX - Unknown"}]}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":5,"p":1,"n":"PNAM - Priority"},{"t":2,"p":1,"n":"TDUM - Dumb Response"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"}]}]},{"t":1,"p":1,"n":"DOOR - Door","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"SNAM - Sound - Open"},{"t":3,"p":1,"n":"ANAM - Sound - Close"},{"t":3,"p":1,"n":"BNAM - Sound - Looping"},{"t":3,"p":1,"n":"FNAM - Flags"}]},{"t":1,"p":1,"n":"ECZN - Encounter Zone","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Rank"},{"t":3,"p":1,"n":"Minimum Level"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]}]},{"t":1,"p":1,"n":"EFSH - Effect Shader","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"ICON - Fill Texture"},{"t":2,"p":1,"n":"ICO2 - Particle Shader Texture"},{"t":2,"p":1,"n":"NAM7 - Holes Texture"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Membrane Shader - Source Blend Mode"},{"t":3,"p":1,"n":"Membrane Shader - Blend Operation"},{"t":3,"p":1,"n":"Membrane Shader - Z Test Function"},{"t":6,"p":1,"n":"Fill\/Texture Effect - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Fade In Time"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Full Alpha Time"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Fade Out Time"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Presistent Alpha Ratio"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Pulse Amplitude"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Pulse Frequency"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Animation Speed (U)"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Animation Speed (V)"},{"t":5,"p":1,"n":"Edge Effect - Fall Off"},{"t":6,"p":1,"n":"Edge Effect - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Edge Effect - Alpha Fade In Time"},{"t":5,"p":1,"n":"Edge Effect - Full Alpha Time"},{"t":5,"p":1,"n":"Edge Effect - Alpha Fade Out Time"},{"t":5,"p":1,"n":"Edge Effect - Persistent Alpha Ratio"},{"t":5,"p":1,"n":"Edge Effect - Alpha Pulse Amplitude"},{"t":5,"p":1,"n":"Edge Effect - Alpha Pusle Frequence"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Full Alpha Ratio"},{"t":5,"p":1,"n":"Edge Effect - Full Alpha Ratio"},{"t":3,"p":1,"n":"Membrane Shader - Dest Blend Mode"},{"t":3,"p":1,"n":"Particle Shader - Source Blend Mode"},{"t":3,"p":1,"n":"Particle Shader - Blend Operation"},{"t":3,"p":1,"n":"Particle Shader - Z Test Function"},{"t":3,"p":1,"n":"Particle Shader - Dest Blend Mode"},{"t":5,"p":1,"n":"Particle Shader - Particle Birth Ramp Up Time"},{"t":5,"p":1,"n":"Particle Shader - Full Particle Birth Time"},{"t":5,"p":1,"n":"Particle Shader - Particle Birth Ramp Down Time"},{"t":5,"p":1,"n":"Particle Shader - Full Particle Birth Ratio"},{"t":5,"p":1,"n":"Particle Shader - Persistant Particle Birth Ratio"},{"t":5,"p":1,"n":"Particle Shader - Particle Lifetime"},{"t":5,"p":1,"n":"Particle Shader - Particle Lifetime +\/-"},{"t":5,"p":1,"n":"Particle Shader - Initial Speed Along Normal"},{"t":5,"p":1,"n":"Particle Shader - Acceleration Along Normal"},{"t":5,"p":1,"n":"Particle Shader - Initial Velocity #1"},{"t":5,"p":1,"n":"Particle Shader - Initial Velocity #2"},{"t":5,"p":1,"n":"Particle Shader - Initial Velocity #3"},{"t":5,"p":1,"n":"Particle Shader - Acceleration #1"},{"t":5,"p":1,"n":"Particle Shader - Acceleration #2"},{"t":5,"p":1,"n":"Particle Shader - Acceleration #3"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 1"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 2"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 1 Time"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 2 Time"},{"t":6,"p":1,"n":"Color Key 1 - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Color Key 2 - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Color Key 3 - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Color Key 1 - Color Alpha"},{"t":5,"p":1,"n":"Color Key 2 - Color Alpha"},{"t":5,"p":1,"n":"Color Key 3 - Color Alpha"},{"t":5,"p":1,"n":"Color Key 1 - Color Key Time"},{"t":5,"p":1,"n":"Color Key 2 - Color Key Time"},{"t":5,"p":1,"n":"Color Key 3 - Color Key Time"},{"t":5,"p":1,"n":"Particle Shader - Initial Speed Along Normal +\/-"},{"t":5,"p":1,"n":"Particle Shader - Initial Rotation (deg)"},{"t":5,"p":1,"n":"Particle Shader - Initial Rotation (deg) +\/-"},{"t":5,"p":1,"n":"Particle Shader - Rotation Speed (deg\/sec)"},{"t":5,"p":1,"n":"Particle Shader - Rotation Speed (deg\/sec) +\/-"},{"t":3,"p":1,"n":"Addon Models"},{"t":5,"p":1,"n":"Holes - Start Time"},{"t":5,"p":1,"n":"Holes - End Time"},{"t":5,"p":1,"n":"Holes - Start Val"},{"t":5,"p":1,"n":"Holes - End Val"},{"t":5,"p":1,"n":"Edge Width (alpha units)"},{"t":6,"p":1,"n":"Edge Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Explosion Wind Speed"},{"t":3,"p":1,"n":"Texture Count U"},{"t":3,"p":1,"n":"Texture Count V"},{"t":5,"p":1,"n":"Addon Models - Fade In Time"},{"t":5,"p":1,"n":"Addon Models - Fade Out Time"},{"t":5,"p":1,"n":"Addon Models - Scale Start"},{"t":5,"p":1,"n":"Addon Models - Scale End"},{"t":5,"p":1,"n":"Addon Models - Scale In Time"},{"t":5,"p":1,"n":"Addon Models - Scale Out Time"}]}]},{"t":1,"p":1,"n":"ENCH - Object Effect","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"ENIT - Effect Data","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]},{"t":8,"s":1,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":3,"p":1,"n":"EFID - Base Effect"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":3,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Actor Value"}]},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"CTDA - Condition","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Note"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Creature Type"},{"t":3,"p":1,"n":"Menu Mode"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Body Location"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Quest Objective (INVALID)"},{"t":3,"p":1,"n":"Reputation"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Challenge"},{"t":3,"p":1,"n":"Casino"},{"t":3,"p":1,"n":"Form"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"VATS Value Function (INVALID)"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Quest Objective"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"}]}]}]}]}]},{"t":1,"p":1,"n":"EXPL - Explosion","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":3,"p":1,"n":"EITM - Object Effect"},{"t":3,"p":1,"n":"MNAM - Image Space Modifier"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":5,"p":1,"n":"Force"},{"t":5,"p":1,"n":"Damage"},{"t":5,"p":1,"n":"Radius"},{"t":3,"p":1,"n":"Light"},{"t":3,"p":1,"n":"Sound 1"},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"IS Radius"},{"t":3,"p":1,"n":"Impact DataSet"},{"t":3,"p":1,"n":"Sound 2"},{"t":6,"p":1,"n":"Radiation","c":[{"t":5,"p":1,"n":"Level"},{"t":5,"p":1,"n":"Dissipation Time"},{"t":5,"p":1,"n":"Radius"}]},{"t":3,"p":1,"n":"Sound Level"}]},{"t":3,"p":1,"n":"INAM - Placed Impact Object"}]},{"t":1,"p":1,"n":"EYES - Eyes","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"ICON - Texture"},{"t":3,"p":1,"n":"DATA - Flags"}]},{"t":1,"p":1,"n":"FACT - Faction","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":8,"s":1,"p":1,"n":"Relations","d":1,"c":[{"t":6,"p":1,"n":"XNAM - Relation","c":[{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Modifier"},{"t":3,"p":1,"n":"Group Combat Reaction"}]}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Flags 1"},{"t":3,"p":1,"n":"Flags 2"},{"t":11,"n":"Unused"}]},{"t":5,"n":"CNAM - Unused"},{"t":10,"p":1,"n":"Ranks","d":1,"c":[{"t":6,"p":1,"n":"Rank","c":[{"t":3,"p":1,"n":"RNAM - Rank#"},{"t":2,"p":1,"n":"MNAM - Male"},{"t":2,"p":1,"n":"FNAM - Female"},{"t":2,"n":"INAM - Insignia (Unused)"}]}]},{"t":3,"p":1,"n":"WMI1 - Reputation"}]},{"t":1,"p":1,"n":"FLST - FormID List","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":8,"s":1,"p":1,"n":"FormIDs","d":1,"c":[{"t":3,"p":1,"n":"LNAM - FormID"}]}]},{"t":1,"p":1,"n":"FURN - Furniture","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":11,"n":"MNAM - Marker Flags"}]},{"t":1,"p":1,"n":"GLOB - Global","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"FNAM - Type"},{"t":5,"p":1,"n":"FLTV - Value"}]},{"t":1,"p":1,"n":"GMST - Game Setting","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":""}]},{"t":1,"p":1,"n":"GRAS - Grass","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Density"},{"t":3,"p":1,"n":"Min Slope"},{"t":3,"p":1,"n":"Max Slope"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Unit from water amount"},{"t":3,"p":1,"n":"Unit from water type"},{"t":5,"p":1,"n":"Position Range"},{"t":5,"p":1,"n":"Height Range"},{"t":5,"p":1,"n":"Color Range"},{"t":5,"p":1,"n":"Wave Period"},{"t":3,"p":1,"n":"Flags"}]}]},{"t":1,"p":1,"n":"HAIR - Hair","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":2,"p":1,"n":"ICON - Texture"},{"t":3,"p":1,"n":"DATA - Flags"}]},{"t":1,"p":1,"n":"HDPT - Head Part","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":3,"p":1,"n":"DATA - Flags"},{"t":8,"s":1,"p":1,"n":"Extra Parts","d":1,"c":[{"t":3,"p":1,"n":"HNAM - Part"}]}]},{"t":1,"p":1,"n":"HUNG - Hunger Stage","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Trigger Threshold"},{"t":3,"p":1,"n":"Actor Effect"}]}]},{"t":1,"p":1,"n":"IDLM - Idle Marker","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"IDLF - Flags"},{"t":6,"s":1,"p":1,"n":"IDLC - ","c":[{"t":3,"p":1,"n":"Animation Count"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"IDLT - Idle Timer Setting"},{"t":7,"p":1,"n":"IDLA - Animations","c":[{"t":3,"p":1,"n":"Animation"}]}]},{"t":1,"p":1,"n":"IMAD - Image Space Adapter","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DNAM - Data Count","c":[{"t":3,"n":"Flags"},{"t":5,"n":"Duration"},{"t":6,"n":"HDR","c":[{"t":3,"n":"Eye Adapt Speed Mult"},{"t":3,"n":"Eye Adapt Speed Add"},{"t":3,"n":"Bloom Blur Radius Mult"},{"t":3,"n":"Bloom Blur Radius Add"},{"t":3,"n":"Bloom Threshold Mult"},{"t":3,"n":"Bloom Threshold Add"},{"t":3,"n":"Bloom Scale Mult"},{"t":3,"n":"Bloom Scale Add"},{"t":3,"n":"Target Lum Min Mult"},{"t":3,"n":"Target Lum Min Add"},{"t":3,"n":"Target Lum Max Mult"},{"t":3,"n":"Target Lum Max Add"},{"t":3,"n":"Sunlight Scale Mult"},{"t":3,"n":"Sunlight Scale Add"},{"t":3,"n":"Sky Scale Mult"},{"t":3,"n":"Sky Scale Add"}]},{"t":3,"n":"Unknown08 Mult"},{"t":3,"n":"Unknown48 Add"},{"t":3,"n":"Unknown09 Mult"},{"t":3,"n":"Unknown49 Add"},{"t":3,"n":"Unknown0A Mult"},{"t":3,"n":"Unknown4A Add"},{"t":3,"n":"Unknown0B Mult"},{"t":3,"n":"Unknown4B Add"},{"t":3,"n":"Unknown0C Mult"},{"t":3,"n":"Unknown4C Add"},{"t":3,"n":"Unknown0D Mult"},{"t":3,"n":"Unknown4D Add"},{"t":3,"n":"Unknown0E Mult"},{"t":3,"n":"Unknown4E Add"},{"t":3,"n":"Unknown0F Mult"},{"t":3,"n":"Unknown4F Add"},{"t":3,"n":"Unknown10 Mult"},{"t":3,"n":"Unknown50 Add"},{"t":6,"n":"Cinematic","c":[{"t":3,"n":"Saturation Mult"},{"t":3,"n":"Saturation Add"},{"t":3,"n":"Brightness Mult"},{"t":3,"n":"Brightness Add"},{"t":3,"n":"Contrast Mult"},{"t":3,"n":"Contrast Add"}]},{"t":3,"n":"Unknown14 Mult"},{"t":3,"n":"Unknown54 Add"},{"t":3,"n":"Tint Color"},{"t":3,"n":"Blur Radius"},{"t":3,"n":"Double Vision Strength"},{"t":3,"n":"Radial Blur Strength"},{"t":3,"n":"Radial Blur Ramp Up"},{"t":3,"n":"Radial Blur Start"},{"t":3,"n":"Radial Blur Flags"},{"t":5,"n":"Radial Blur Center X"},{"t":5,"n":"Radial Blur Center Y"},{"t":3,"n":"DoF Strength"},{"t":3,"n":"DoF Distance"},{"t":3,"n":"DoF Range"},{"t":3,"n":"DoF Flags"},{"t":3,"n":"Radial Blur Ramp Down"},{"t":3,"n":"Radial Blur Down Start"},{"t":3,"n":"Fade Color"},{"t":3,"n":"Motion Blur Strength"}]},{"t":7,"p":1,"n":"BNAM - Blur Radius","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"VNAM - Double Vision Strength","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"TNAM - Tint Color","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"},{"t":5,"p":1,"n":"Alpha"}]}]},{"t":7,"p":1,"n":"NAM3 - Fade Color","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"},{"t":5,"p":1,"n":"Alpha"}]}]},{"t":7,"p":1,"n":"RNAM - Radial Blur Strength","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"SNAM - Radial Blur Ramp Up","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"UNAM - Radial Blur Start","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"NAM1 - Radial Blur Ramp Down","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"NAM2 - Radial Blur Down Start","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"WNAM - DoF Strength","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"XNAM - DoF Distance","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"YNAM - DoF Range","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"NAM4 - Motion Blur Strength","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":6,"s":1,"p":1,"n":"HDR","c":[{"t":7,"p":1,"n":"aIAD - Eye Adapt Speed Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"@IAD - Eye Adapt Speed Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"bIAD - Bloom Blur Radius Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"AIAD - Bloom Blur Radius Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"cIAD - Bloom Threshold Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"BIAD - Bloom Threshold Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"dIAD - Bloom Scale Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"CIAD - Bloom Scale Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"eIAD - Target Lum Min Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"DIAD - Target Lum Min Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"fIAD - Target Lum Max Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"EIAD - Target Lum Max Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"gIAD - Sunlight Scale Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"FIAD - Sunlight Scale Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"hIAD - Sky Scale Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"GIAD - Sky Scale Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]}]},{"t":11,"n":"iIAD - Unknown"},{"t":11,"n":"HIAD - Unknown"},{"t":11,"n":"jIAD - Unknown"},{"t":11,"n":"IIAD - Unknown"},{"t":11,"n":"kIAD - Unknown"},{"t":11,"n":"JIAD - Unknown"},{"t":11,"n":"lIAD - Unknown"},{"t":11,"n":"KIAD - Unknown"},{"t":11,"n":"mIAD - Unknown"},{"t":11,"n":"LIAD - Unknown"},{"t":11,"n":"nIAD - Unknown"},{"t":11,"n":"MIAD - Unknown"},{"t":11,"n":"oIAD - Unknown"},{"t":11,"n":"NIAD - Unknown"},{"t":11,"n":"pIAD - Unknown"},{"t":11,"n":"OIAD - Unknown"},{"t":11,"n":"qIAD - Unknown"},{"t":11,"n":"PIAD - Unknown"},{"t":6,"s":1,"p":1,"n":"Cinematic","c":[{"t":7,"p":1,"n":"rIAD - Saturation Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"QIAD - Saturation Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"sIAD - Brightness Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"RIAD - Brightness Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"tIAD - Contrast Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"SIAD - Contrast Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]}]},{"t":11,"n":"uIAD - Unknown"},{"t":11,"n":"TIAD - Unknown"},{"t":3,"p":1,"n":"RDSD - Sound - Intro"},{"t":3,"p":1,"n":"RDSI - Sound - Outro"}]},{"t":1,"p":1,"n":"IMGS - Image Space","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DNAM - ","c":[{"t":6,"p":1,"n":"HDR","c":[{"t":5,"p":1,"n":"Eye Adapt Speed"},{"t":5,"p":1,"n":"Blur Radius"},{"t":5,"p":1,"n":"Blur Passes"},{"t":5,"p":1,"n":"Emissive Mult"},{"t":5,"p":1,"n":"Target LUM"},{"t":5,"p":1,"n":"Upper LUM Clamp"},{"t":5,"p":1,"n":"Bright Scale"},{"t":5,"p":1,"n":"Bright Clamp"},{"t":5,"p":1,"n":"LUM Ramp No Tex"},{"t":5,"p":1,"n":"LUM Ramp Min"},{"t":5,"p":1,"n":"LUM Ramp Max"},{"t":5,"p":1,"n":"Sunlight Dimmer"},{"t":5,"p":1,"n":"Grass Dimmer"},{"t":5,"p":1,"n":"Tree Dimmer"},{"t":5,"p":1,"n":"Skin Dimmer"}]},{"t":6,"p":1,"n":"Bloom","c":[{"t":5,"p":1,"n":"Blur Radius"},{"t":5,"p":1,"n":"Alpha Mult Interior"},{"t":5,"p":1,"n":"Alpha Mult Exterior"}]},{"t":6,"p":1,"n":"Get Hit","c":[{"t":5,"p":1,"n":"Blur Radius"},{"t":5,"p":1,"n":"Blur Damping Constant"},{"t":5,"p":1,"n":"Damping Constant"}]},{"t":6,"p":1,"n":"Night Eye","c":[{"t":6,"p":1,"n":"Tint Color","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}]},{"t":5,"p":1,"n":"Brightness"}]},{"t":6,"p":1,"n":"Cinematic","c":[{"t":5,"p":1,"n":"Saturation"},{"t":6,"p":1,"n":"Contrast","c":[{"t":5,"p":1,"n":"Avg Lum Value"},{"t":5,"p":1,"n":"Value"}]},{"t":5,"p":1,"n":"Cinematic - Brightness - Value"},{"t":6,"p":1,"n":"Tint","c":[{"t":6,"p":1,"n":"Color","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}]},{"t":5,"p":1,"n":"Value"}]}]},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]}]},{"t":1,"p":1,"n":"IMOD - Item Mod","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Drop"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]}]},{"t":1,"p":1,"n":"INFO - Dialog response","d":1,"c":[{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Next Speaker"},{"t":3,"p":1,"n":"Flags 1"},{"t":3,"p":1,"n":"Flags 2"}]},{"t":3,"p":1,"n":"QSTI - Quest"},{"t":3,"p":1,"n":"TPIC - Topic"},{"t":3,"p":1,"n":"PNAM - Previous INFO"},{"t":8,"s":1,"p":1,"n":"Add Topics","d":1,"c":[{"t":3,"p":1,"n":"NAME - Topic"}]},{"t":8,"s":1,"p":1,"n":"Responses","d":1,"c":[{"t":6,"p":1,"n":"Response","c":[{"t":6,"p":1,"n":"TRDT - Response Data","c":[{"t":3,"p":1,"n":"Emotion Type"},{"t":3,"p":1,"n":"Emotion Value"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Response number"},{"t":3,"p":1,"n":"Sound"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"NAM1 - Response Text"},{"t":2,"p":1,"n":"NAM2 - Script Notes"},{"t":2,"p":1,"n":"NAM3 - Edits"},{"t":3,"p":1,"n":"SNAM - Speaker Animation"},{"t":3,"p":1,"n":"LNAM - Listener Animation"}]}]},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"CTDA - Condition","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Note"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Creature Type"},{"t":3,"p":1,"n":"Menu Mode"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Body Location"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Quest Objective (INVALID)"},{"t":3,"p":1,"n":"Reputation"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Challenge"},{"t":3,"p":1,"n":"Casino"},{"t":3,"p":1,"n":"Form"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"VATS Value Function (INVALID)"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Quest Objective"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"}]}]},{"t":8,"s":1,"p":1,"n":"Choices","d":1,"c":[{"t":3,"p":1,"n":"TCLT - Choice"}]},{"t":8,"s":1,"p":1,"n":"Link From","d":1,"c":[{"t":3,"p":1,"n":"TCLF - Topic"}]},{"t":8,"n":"Unknown","c":[{"t":3,"n":"TCFU - Info"}]},{"t":6,"s":1,"p":1,"n":"Script (Begin)","c":[{"t":6,"p":1,"n":"Embedded Script","c":[{"t":6,"p":1,"n":"SCHR - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"p":1,"n":"SCDA - Compiled Embedded Script"},{"t":2,"p":1,"n":"SCTX - Embedded Script Source"},{"t":10,"p":1,"n":"Local Variables","c":[{"t":6,"p":1,"n":"Local Variable","c":[{"t":6,"p":1,"n":"SLSD - Local Variable Data","c":[{"t":3,"p":1,"n":"Index"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"SCVR - Name"}]}]},{"t":8,"p":1,"n":"References","c":[{"t":3,"p":1,"n":"SCRO - Global Reference"},{"t":3,"p":1,"n":"SCRV - Local Variable"}]}]}]},{"t":6,"s":1,"p":1,"n":"Script (End)","c":[{"p":1,"n":"NEXT - Marker"},{"t":6,"p":1,"n":"Embedded Script","c":[{"t":6,"p":1,"n":"SCHR - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"p":1,"n":"SCDA - Compiled Embedded Script"},{"t":2,"p":1,"n":"SCTX - Embedded Script Source"},{"t":10,"p":1,"n":"Local Variables","c":[{"t":6,"p":1,"n":"Local Variable","c":[{"t":6,"p":1,"n":"SLSD - Local Variable Data","c":[{"t":3,"p":1,"n":"Index"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"SCVR - Name"}]}]},{"t":8,"p":1,"n":"References","c":[{"t":3,"p":1,"n":"SCRO - Global Reference"},{"t":3,"p":1,"n":"SCRV - Local Variable"}]}]}]},{"t":3,"n":"SNDD - Unused"},{"t":2,"p":1,"n":"RNAM - Prompt"},{"t":3,"p":1,"n":"ANAM - Speaker"},{"t":3,"p":1,"n":"KNAM - ActorValue\/Perk"},{"t":3,"p":1,"n":"DNAM - Speech Challenge"}]},{"t":1,"p":1,"n":"INGR - Ingredient","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":3,"p":1,"n":"ETYP - Equiptment Type"},{"t":5,"p":1,"n":"DATA - Weight"},{"t":6,"s":1,"p":1,"n":"ENIT - Effect Data","c":[{"t":3,"p":1,"n":"Value"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"s":1,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":3,"p":1,"n":"EFID - Base Effect"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":3,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Actor Value"}]},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"CTDA - Condition","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Note"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Creature Type"},{"t":3,"p":1,"n":"Menu Mode"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Body Location"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Quest Objective (INVALID)"},{"t":3,"p":1,"n":"Reputation"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Challenge"},{"t":3,"p":1,"n":"Casino"},{"t":3,"p":1,"n":"Form"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"VATS Value Function (INVALID)"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Quest Objective"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"}]}]}]}]}]},{"t":1,"p":1,"n":"IPCT - Impact","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":5,"p":1,"n":"Effect - Duration"},{"t":3,"p":1,"n":"Effect - Orientation"},{"t":5,"p":1,"n":"Angle Threshold"},{"t":5,"p":1,"n":"Placement Radius"},{"t":3,"p":1,"n":"Sound Level"},{"t":3,"p":1,"n":"Flags"}]},{"t":6,"s":1,"p":1,"n":"DODT - Decal Data","c":[{"t":5,"p":1,"n":"Min Width"},{"t":5,"p":1,"n":"Max Width"},{"t":5,"p":1,"n":"Min Height"},{"t":5,"p":1,"n":"Max Height"},{"t":5,"p":1,"n":"Depth"},{"t":5,"p":1,"n":"Shininess"},{"t":6,"p":1,"n":"Parallax","c":[{"t":5,"p":1,"n":"Scale"},{"t":3,"p":1,"n":"Passes"}]},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":3,"p":1,"n":"DNAM - Texture Set"},{"t":3,"p":1,"n":"SNAM - Sound 1"},{"t":3,"p":1,"n":"NAM1 - Sound 2"}]},{"t":1,"p":1,"n":"IPDS - Impact DataSet","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - Impacts","c":[{"t":3,"p":1,"n":"Stone"},{"t":3,"p":1,"n":"Dirt"},{"t":3,"p":1,"n":"Grass"},{"t":3,"p":1,"n":"Glass"},{"t":3,"p":1,"n":"Metal"},{"t":3,"p":1,"n":"Wood"},{"t":3,"p":1,"n":"Organic"},{"t":3,"p":1,"n":"Cloth"},{"t":3,"p":1,"n":"Water"},{"t":3,"p":1,"n":"Hollow Metal"},{"t":3,"p":1,"n":"Organic Bug"},{"t":3,"p":1,"n":"Organic Glow"}]}]},{"t":1,"p":1,"n":"KEYM - Key","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Drop"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":3,"p":1,"n":"RNAM - Sound - Random\/Looping"}]},{"t":1,"p":1,"n":"LAND - Landscape","d":1,"c":[{"t":11,"n":"DATA - Unknown"},{"t":11,"n":"VNML - Vertex Normals"},{"t":11,"n":"VHGT - Vertext Height Map"},{"t":11,"n":"VCLR - Vertex Colours"},{"t":8,"s":1,"p":1,"n":"Layers","d":1,"c":[{"t":6,"p":1,"n":"Base Layer","c":[{"t":6,"p":1,"n":"BTXT - Base Layer Header","c":[{"t":3,"p":1,"n":"Texture"},{"t":3,"p":1,"n":"Quadrant"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Layer"}]}]},{"t":6,"p":1,"n":"Alpha Layer","c":[{"t":6,"p":1,"n":"ATXT - Alpha Layer Header","c":[{"t":3,"p":1,"n":"Texture"},{"t":3,"p":1,"n":"Quadrant"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Layer"}]},{"t":11,"p":1,"n":"VTXT - Alpha Layer Data"}]}]},{"t":7,"p":1,"n":"VTEX - Textures","c":[{"t":3,"p":1,"n":"Texture"}]}]},{"t":1,"p":1,"n":"LGTM - Lighting Template","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - Lighting","c":[{"t":6,"p":1,"n":"Ambient Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Directional Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Fog Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Fog Near"},{"t":5,"p":1,"n":"Fog Far"},{"t":3,"p":1,"n":"Directional Rotation XY"},{"t":3,"p":1,"n":"Directional Rotation Z"},{"t":5,"p":1,"n":"Directional Fade"},{"t":5,"p":1,"n":"Fog Clip Dist"},{"t":5,"p":1,"n":"Fog Power"}]}]},{"t":1,"p":1,"n":"LIGH - Light","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Time"},{"t":3,"p":1,"n":"Radius"},{"t":6,"p":1,"n":"Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":3,"n":"Unused"}]},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Falloff Exponent"},{"t":5,"p":1,"n":"FOV"},{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":5,"p":1,"n":"FNAM - Fade value"},{"t":3,"p":1,"n":"SNAM - Sound"}]},{"t":1,"p":1,"n":"LSCR - Load Screen","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":2,"p":1,"n":"DESC - Description"},{"t":8,"s":1,"p":1,"n":"Locations","d":1,"c":[{"t":6,"p":1,"n":"LNAM - Location","c":[{"t":3,"p":1,"n":"Direct"},{"t":6,"p":1,"n":"Indirect","c":[{"t":3,"p":1,"n":"World"},{"t":6,"p":1,"n":"Grid","c":[{"t":3,"p":1,"n":"Y"},{"t":3,"p":1,"n":"X"}]}]}]}]},{"t":3,"p":1,"n":"WMI1 - Load Screen Type"}]},{"t":1,"p":1,"n":"LSCT - Load Screen Type","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Type"},{"t":6,"p":1,"n":"Data 1","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"},{"t":3,"p":1,"n":"Width"},{"t":3,"p":1,"n":"Height"},{"t":5,"p":1,"n":"Orientation"},{"t":3,"p":1,"n":"Font"},{"t":6,"p":1,"n":"Font Color","c":[{"t":5,"p":1,"n":"R"},{"t":5,"p":1,"n":"G"},{"t":5,"p":1,"n":"B"}]}]},{"t":11,"n":"Unknown"},{"t":6,"p":1,"n":"Data 2","c":[{"t":3,"p":1,"n":"Font"},{"t":6,"p":1,"n":"Font Color","c":[{"t":5,"p":1,"n":"R"},{"t":5,"p":1,"n":"G"},{"t":5,"p":1,"n":"B"}]},{"t":11,"p":1,"n":""},{"t":3,"p":1,"n":"Stats"}]}]}]},{"t":1,"p":1,"n":"LTEX - Landscape Texture","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":3,"p":1,"n":"TNAM - Texture"},{"t":6,"s":1,"p":1,"n":"HNAM - Havok Data","c":[{"t":3,"p":1,"n":"Material Type"},{"t":3,"p":1,"n":"Friction"},{"t":3,"p":1,"n":"Restitution"}]},{"t":3,"p":1,"n":"SNAM - Texture Specular Exponent"},{"t":8,"s":1,"p":1,"n":"Grasses","d":1,"c":[{"t":3,"p":1,"n":"GNAM - Grass"}]}]},{"t":1,"p":1,"n":"LVLC - Leveled Creature","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"LVLD - Chance none"},{"t":3,"p":1,"n":"LVLF - Flags"},{"t":10,"p":1,"n":"Leveled List Entries","d":1,"c":[{"t":6,"p":1,"n":"Leveled List Entry","c":[{"t":6,"p":1,"n":"LVLO - Base Data","c":[{"t":3,"p":1,"n":"Level"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Count"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]}]},{"t":1,"p":1,"n":"LVLI - Leveled Item","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"LVLD - Chance none"},{"t":3,"p":1,"n":"LVLF - Flags"},{"t":3,"p":1,"n":"LVLG - Global"},{"t":10,"p":1,"n":"Leveled List Entries","d":1,"c":[{"t":6,"p":1,"n":"Leveled List Entry","c":[{"t":6,"p":1,"n":"LVLO - Base Data","c":[{"t":3,"p":1,"n":"Level"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Count"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]}]},{"t":1,"p":1,"n":"LVLN - Leveled NPC","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"LVLD - Chance none"},{"t":3,"p":1,"n":"LVLF - Flags"},{"t":10,"p":1,"n":"Leveled List Entries","d":1,"c":[{"t":6,"p":1,"n":"Leveled List Entry","c":[{"t":6,"p":1,"n":"LVLO - Base Data","c":[{"t":3,"p":1,"n":"Level"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Count"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]}]},{"t":1,"p":1,"n":"MESG - Message","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"DESC - Description"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"INAM - Icon"},{"t":11,"n":"NAM0 - Unused"},{"t":11,"n":"NAM1 - Unused"},{"t":11,"n":"NAM2 - Unused"},{"t":11,"n":"NAM3 - Unused"},{"t":11,"n":"NAM4 - Unused"},{"t":11,"n":"NAM5 - Unused"},{"t":11,"n":"NAM6 - Unused"},{"t":11,"n":"NAM7 - Unused"},{"t":11,"n":"NAM8 - Unused"},{"t":11,"n":"NAM9 - Unused"},{"t":3,"p":1,"n":"DNAM - Flags"},{"t":3,"p":1,"n":"TNAM - Display Time"},{"t":8,"s":1,"p":1,"n":"Menu Buttons","d":1,"c":[{"t":6,"p":1,"n":"Menu Button","c":[{"t":2,"p":1,"n":"ITXT - Button Text"},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"CTDA - Condition","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Note"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Creature Type"},{"t":3,"p":1,"n":"Menu Mode"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Body Location"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Quest Objective (INVALID)"},{"t":3,"p":1,"n":"Reputation"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Challenge"},{"t":3,"p":1,"n":"Casino"},{"t":3,"p":1,"n":"Form"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"VATS Value Function (INVALID)"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Quest Objective"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"}]}]}]}]}]},{"t":1,"p":1,"n":"MGEF - Base Effect","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Flags"},{"t":5,"n":"Base cost (Unused)"},{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Assoc. Item"},{"t":3,"p":1,"n":"Assoc. Script"},{"t":3,"p":1,"n":"Assoc. Creature"},{"t":3,"n":"Magic School (Unused)"},{"t":3,"p":1,"n":"Resistance Type"},{"t":3,"p":1,"n":"Counter effect count"},{"t":3,"p":1,"n":"Light"},{"t":5,"p":1,"n":"Projectile speed"},{"t":3,"p":1,"n":"Effect Shader"},{"t":3,"p":1,"n":"Object Display Shader"},{"t":3,"p":1,"n":"Effect sound"},{"t":3,"p":1,"n":"Bolt sound"},{"t":3,"p":1,"n":"Hit sound"},{"t":3,"p":1,"n":"Area sound"},{"t":5,"n":"Constant Effect enchantment factor (Unused)"},{"t":5,"n":"Constant Effect barter factor (Unused)"},{"t":3,"p":1,"n":"Archtype"},{"t":3,"p":1,"n":"Actor Value"}]},{"t":8,"s":1,"p":1,"n":"Counter Effects","d":1,"c":[{"t":3,"p":1,"n":"ESCE - Effect"}]}]},{"t":1,"p":1,"n":"MICN - Menu Icon","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]}]},{"t":1,"p":1,"n":"MISC - Misc. Item","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Drop"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":3,"p":1,"n":"RNAM - Sound - Random\/Looping"}]},{"t":1,"p":1,"n":"MSET - Media Set","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"NAM1 - Type"},{"t":2,"p":1,"n":"NAM2 - Loop (B) \/ Battle (D) \/ Day Outer (L)"},{"t":2,"p":1,"n":"NAM3 - Explore (D) \/ Day Middle (L)"},{"t":2,"p":1,"n":"NAM4 - Suspense (D) \/ Day Inner (L)"},{"t":2,"p":1,"n":"NAM5 - Night Outer (L)"},{"t":2,"p":1,"n":"NAM6 - Night Middle (L)"},{"t":2,"p":1,"n":"NAM7 - Night Inner (L)"},{"t":5,"p":1,"n":"NAM8 - Loop dB (B) \/ Battle dB (D) \/ Day Outer dB (L)"},{"t":5,"p":1,"n":"NAM9 - Explore dB (D) \/ Day Middle dB (L)"},{"t":5,"p":1,"n":"NAM0 - Suspense dB (D) \/ Day Inner dB (L)"},{"t":5,"p":1,"n":"ANAM - Night Outer dB (L)"},{"t":5,"p":1,"n":"BNAM - Night Middle dB (L)"},{"t":5,"p":1,"n":"CNAM - Night Inner dB (L)"},{"t":5,"p":1,"n":"JNAM - Day Outer Boundary % (L)"},{"t":5,"p":1,"n":"KNAM - Day Middle Boundary % (L)"},{"t":5,"p":1,"n":"LNAM - Day Inner Boundary % (L)"},{"t":5,"p":1,"n":"MNAM - Night Outer Boundary % (L)"},{"t":5,"p":1,"n":"NNAM - Night Middle Boundary % (L)"},{"t":5,"p":1,"n":"ONAM - Night Inner Boundary % (L)"},{"t":3,"p":1,"n":"PNAM - Enable Flags"},{"t":5,"p":1,"n":"DNAM - Wait Time (B) \/ Minimum Time On (D,L) \/ Daytime Min (I)"},{"t":5,"p":1,"n":"ENAM - Loop Fade Out (B) \/ Looping\/Random Crossfade Overlap (D,L) \/ Nighttime Min (I)"},{"t":5,"p":1,"n":"FNAM - Recovery Time (B) \/ Layer Crossfade Time (D,L) \/ Daytime Max (I)"},{"t":5,"p":1,"n":"GNAM - Nighttime Max (I)"},{"t":3,"p":1,"n":"HNAM - Intro (B,D) \/ Daytime (I)"},{"t":3,"p":1,"n":"INAM - Outro (B,D) \/ Nighttime (I)"},{"t":11,"n":"DATA - Unknown"}]},{"t":1,"p":1,"n":"MSTT - Moveable Static","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":11,"n":"DATA - Unknown"},{"t":3,"p":1,"n":"SNAM - Sound"}]},{"t":1,"p":1,"n":"MUSC - Music Type","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FNAM - Filename"},{"t":5,"p":1,"n":"ANAM - dB (positive = Loop)"}]},{"t":1,"p":1,"n":"NOTE - Note","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Drop"},{"t":3,"p":1,"n":"DATA - Type"},{"t":8,"s":1,"p":1,"n":"Quests","d":1,"c":[{"t":3,"p":1,"n":"ONAM - Quest"}]},{"t":2,"p":1,"n":"XNAM - Texture"},{"t":2,"p":1,"n":"Text"},{"t":3,"p":1,"n":"Topic"},{"t":3,"p":1,"n":"Sound"},{"t":3,"p":1,"n":"Actor"}]},{"t":1,"p":1,"n":"NPC_ - Non-Player Character","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"ACBS - Configuration","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Fatigue"},{"t":3,"p":1,"n":"Barter gold"},{"t":3,"p":1,"n":"Level"},{"t":3,"p":1,"n":"Level Mult"},{"t":3,"p":1,"n":"Calc min"},{"t":3,"p":1,"n":"Calc max"},{"t":3,"p":1,"n":"Speed Multiplier"},{"t":5,"p":1,"n":"Karma (Alignment)"},{"t":3,"p":1,"n":"Disposition Base"},{"t":3,"p":1,"n":"Template Flags"}]},{"t":8,"s":1,"p":1,"n":"Factions","d":1,"c":[{"t":6,"p":1,"n":"SNAM - Faction","c":[{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"p":1,"n":"INAM - Death item"},{"t":3,"p":1,"n":"VTCK - Voice"},{"t":3,"p":1,"n":"TPLT - Template"},{"t":3,"p":1,"n":"RNAM - Race"},{"t":8,"s":1,"p":1,"n":"Actor Effects","d":1,"c":[{"t":3,"p":1,"n":"SPLO - Actor Effect"}]},{"t":3,"p":1,"n":"EITM - Unarmed Attack Effect"},{"t":3,"p":1,"n":"EAMT - Unarmed Attack Animation"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":10,"p":1,"n":"Items","d":1,"c":[{"t":6,"p":1,"n":"Item","c":[{"t":6,"p":1,"n":"CNTO - Item","c":[{"t":3,"p":1,"n":"Item"},{"t":3,"p":1,"n":"Count"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]},{"t":6,"s":1,"p":1,"n":"AIDT - AI Data","c":[{"t":3,"p":1,"n":"Aggression"},{"t":3,"p":1,"n":"Confidence"},{"t":3,"p":1,"n":"Energy Level"},{"t":3,"p":1,"n":"Responsibility"},{"t":3,"p":1,"n":"Mood"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Buys\/Sells and Services"},{"t":3,"p":1,"n":"Teaches"},{"t":3,"p":1,"n":"Maximum training level"},{"t":3,"p":1,"n":"Assistance"},{"t":3,"p":1,"n":"Aggro Radius Behavior"},{"t":3,"p":1,"n":"Aggro Radius"}]},{"t":8,"s":1,"p":1,"n":"Packages","d":1,"c":[{"t":3,"p":1,"n":"PKID - Package"}]},{"t":7,"p":1,"n":"KFFZ - Animations","c":[{"t":2,"p":1,"n":"Animation"}]},{"t":3,"p":1,"n":"CNAM - Class"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Base Health"},{"t":7,"p":1,"n":"Attributes","c":[{"t":3,"p":1,"n":"Attribute"}]},{"t":11,"n":"Unused"}]},{"t":6,"s":1,"p":1,"n":"DNAM - ","c":[{"t":7,"p":1,"n":"Skill Values","c":[{"t":3,"p":1,"n":"Skill"}]},{"t":7,"p":1,"n":"Skill Offsets","c":[{"t":3,"p":1,"n":"Skill"}]}]},{"t":8,"s":1,"p":1,"n":"Head Parts","d":1,"c":[{"t":3,"p":1,"n":"PNAM - Head Part"}]},{"t":3,"p":1,"n":"HNAM - Hair"},{"t":5,"p":1,"n":"LNAM - Hair length"},{"t":3,"p":1,"n":"ENAM - Eyes"},{"t":6,"s":1,"p":1,"n":"HCLR - Hair color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"ZNAM - Combat Style"},{"t":3,"p":1,"n":"NAM4 - Impact Material Type"},{"t":6,"s":1,"p":1,"n":"FaceGen Data","c":[{"t":11,"p":1,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"p":1,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"p":1,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":3,"n":"NAM5 - Unknown"},{"t":5,"p":1,"n":"NAM6 - Height"},{"t":5,"p":1,"n":"NAM7 - Weight"}]},{"t":1,"p":1,"n":"PACK - Package","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"PKDT - General","c":[{"t":3,"p":1,"n":"General Flags"},{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Fallout Behavior Flags"},{"p":1,"n":"Type Specific Flags (missing)"},{"t":3,"p":1,"n":"Type Specific Flags - Find"},{"t":3,"p":1,"n":"Type Specific Flags - Follow"},{"t":3,"p":1,"n":"Type Specific Flags - Escort"},{"t":3,"p":1,"n":"Type Specific Flags - Eat"},{"t":3,"p":1,"n":"Type Specific Flags - Sleep"},{"t":3,"p":1,"n":"Type Specific Flags - Wander"},{"t":3,"p":1,"n":"Type Specific Flags - Travel"},{"t":3,"p":1,"n":"Type Specific Flags - Accompany"},{"t":3,"p":1,"n":"Type Specific Flags - Use Item At"},{"t":3,"p":1,"n":"Type Specific Flags - Ambush"},{"t":3,"p":1,"n":"Type Specific Flags - Flee Not Combat"},{"t":3,"p":1,"n":"Type Specific Flags - ?"},{"t":3,"p":1,"n":"Type Specific Flags - Sandbox"},{"t":3,"p":1,"n":"Type Specific Flags - Patrol"},{"t":3,"p":1,"n":"Type Specific Flags - Guard"},{"t":3,"p":1,"n":"Type Specific Flags - Dialogue"},{"t":3,"p":1,"n":"Type Specific Flags - Use Weapon"}]},{"t":6,"s":1,"p":1,"n":"Locations","c":[{"t":6,"p":1,"n":"PLDT - Location 1","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Cell"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Object ID"},{"t":3,"p":1,"n":"Object Type"},{"t":3,"p":1,"n":"Radius"}]},{"t":6,"p":1,"n":"PLD2 - Location 2","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Cell"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Object ID"},{"t":3,"p":1,"n":"Object Type"},{"t":3,"p":1,"n":"Radius"}]}]},{"t":6,"s":1,"p":1,"n":"PSDT - Schedule","c":[{"t":3,"p":1,"n":"Month"},{"t":3,"p":1,"n":"Day of week"},{"t":3,"p":1,"n":"Date"},{"t":3,"p":1,"n":"Time"},{"t":3,"p":1,"n":"Duration"}]},{"t":6,"s":1,"p":1,"n":"PTDT - Target 1","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Object ID"},{"t":3,"p":1,"n":"Object Type"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Count \/ Distance"},{"t":5,"n":"Unknown"}]},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"CTDA - Condition","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Note"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Creature Type"},{"t":3,"p":1,"n":"Menu Mode"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Body Location"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Quest Objective (INVALID)"},{"t":3,"p":1,"n":"Reputation"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Challenge"},{"t":3,"p":1,"n":"Casino"},{"t":3,"p":1,"n":"Form"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"VATS Value Function (INVALID)"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Quest Objective"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"}]}]},{"t":6,"s":1,"p":1,"n":"Idle Animations","c":[{"t":3,"p":1,"n":"IDLF - Flags"},{"t":6,"p":1,"n":"IDLC - ","c":[{"t":3,"p":1,"n":"Animation Count"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"IDLT - Idle Timer Setting"},{"t":7,"p":1,"n":"IDLA - Animations","c":[{"t":3,"p":1,"n":"Animation"}]},{"t":11,"n":"IDLB - Unused"}]},{"t":3,"p":1,"n":"CNAM - Combat Style"},{"p":1,"n":"PKED - Eat Marker"},{"t":3,"p":1,"n":"PKE2 - Escort Distance"},{"t":5,"p":1,"n":"PKFD - Follow - Start Location - Trigger Radius"},{"t":6,"s":1,"p":1,"n":"PKPT - Patrol Flags","c":[{"t":3,"p":1,"n":"Repeatable"},{"t":11,"n":"Unused"}]},{"t":6,"s":1,"p":1,"n":"PKW3 - Use Weapon Data","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Fire Rate"},{"t":3,"p":1,"n":"Fire Count"},{"t":3,"p":1,"n":"Number of Bursts"},{"t":6,"p":1,"n":"Shoots Per Volleys","c":[{"t":3,"p":1,"n":"Min"},{"t":3,"p":1,"n":"Max"}]},{"t":6,"p":1,"n":"Pause Between Volleys","c":[{"t":5,"p":1,"n":"Min"},{"t":5,"p":1,"n":"Max"}]},{"t":11,"n":"Unused"}]},{"t":6,"s":1,"p":1,"n":"PTD2 - Target 2","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Object ID"},{"t":3,"p":1,"n":"Object Type"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Count \/ Distance"},{"t":5,"n":"Unknown"}]},{"p":1,"n":"PUID - Use Item Marker"},{"p":1,"n":"PKAM - Ambush Marker"},{"t":6,"s":1,"p":1,"n":"PKDD - Dialogue Data","c":[{"t":5,"p":1,"n":"FOV"},{"t":3,"p":1,"n":"Topic"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Dialogue Type"},{"t":11,"n":"Unknown"}]},{"t":6,"s":1,"p":1,"n":"PLD2 - Location 2 (again??)","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Cell"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Object ID"},{"t":3,"p":1,"n":"Object Type"},{"t":3,"p":1,"n":"Radius"}]},{"t":6,"s":1,"p":1,"n":"OnBegin","c":[{"p":1,"n":"POBA - OnBegin Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":6,"p":1,"n":"Embedded Script","c":[{"t":6,"p":1,"n":"SCHR - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"p":1,"n":"SCDA - Compiled Embedded Script"},{"t":2,"p":1,"n":"SCTX - Embedded Script Source"},{"t":10,"p":1,"n":"Local Variables","c":[{"t":6,"p":1,"n":"Local Variable","c":[{"t":6,"p":1,"n":"SLSD - Local Variable Data","c":[{"t":3,"p":1,"n":"Index"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"SCVR - Name"}]}]},{"t":8,"p":1,"n":"References","c":[{"t":3,"p":1,"n":"SCRO - Global Reference"},{"t":3,"p":1,"n":"SCRV - Local Variable"}]}]},{"t":3,"p":1,"n":"TNAM - Topic"}]},{"t":6,"s":1,"p":1,"n":"OnEnd","c":[{"p":1,"n":"POEA - OnEnd Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":6,"p":1,"n":"Embedded Script","c":[{"t":6,"p":1,"n":"SCHR - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"p":1,"n":"SCDA - Compiled Embedded Script"},{"t":2,"p":1,"n":"SCTX - Embedded Script Source"},{"t":10,"p":1,"n":"Local Variables","c":[{"t":6,"p":1,"n":"Local Variable","c":[{"t":6,"p":1,"n":"SLSD - Local Variable Data","c":[{"t":3,"p":1,"n":"Index"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"SCVR - Name"}]}]},{"t":8,"p":1,"n":"References","c":[{"t":3,"p":1,"n":"SCRO - Global Reference"},{"t":3,"p":1,"n":"SCRV - Local Variable"}]}]},{"t":3,"p":1,"n":"TNAM - Topic"}]},{"t":6,"s":1,"p":1,"n":"OnChange","c":[{"p":1,"n":"POCA - OnChange Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":6,"p":1,"n":"Embedded Script","c":[{"t":6,"p":1,"n":"SCHR - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"p":1,"n":"SCDA - Compiled Embedded Script"},{"t":2,"p":1,"n":"SCTX - Embedded Script Source"},{"t":10,"p":1,"n":"Local Variables","c":[{"t":6,"p":1,"n":"Local Variable","c":[{"t":6,"p":1,"n":"SLSD - Local Variable Data","c":[{"t":3,"p":1,"n":"Index"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"SCVR - Name"}]}]},{"t":8,"p":1,"n":"References","c":[{"t":3,"p":1,"n":"SCRO - Global Reference"},{"t":3,"p":1,"n":"SCRV - Local Variable"}]}]},{"t":3,"p":1,"n":"TNAM - Topic"}]}]},{"t":1,"p":1,"n":"PBEA - Placed Beam","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"NAME - Base"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":11,"n":"XRGD - Ragdoll Data"},{"t":11,"n":"XRGB - Ragdoll Biped Data"},{"t":6,"s":1,"p":1,"n":"Patrol Data","c":[{"t":5,"p":1,"n":"XPRD - Idle Time"},{"p":1,"n":"XPPA - Patrol Script Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":6,"p":1,"n":"Embedded Script","c":[{"t":6,"p":1,"n":"SCHR - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"p":1,"n":"SCDA - Compiled Embedded Script"},{"t":2,"p":1,"n":"SCTX - Embedded Script Source"},{"t":10,"p":1,"n":"Local Variables","c":[{"t":6,"p":1,"n":"Local Variable","c":[{"t":6,"p":1,"n":"SLSD - Local Variable Data","c":[{"t":3,"p":1,"n":"Index"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"SCVR - Name"}]}]},{"t":8,"p":1,"n":"References","c":[{"t":3,"p":1,"n":"SCRO - Global Reference"},{"t":3,"p":1,"n":"SCRV - Local Variable"}]}]},{"t":3,"p":1,"n":"TNAM - Topic"}]},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":3,"p":1,"n":"XCNT - Count"},{"t":5,"p":1,"n":"XRDS - Radius"},{"t":5,"p":1,"n":"XHLP - Health"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked Decals","d":1,"c":[{"t":6,"p":1,"n":"XDCR - Decal","c":[{"t":3,"p":1,"n":"Reference"},{"t":11,"n":"Unknown"}]}]},{"t":3,"p":1,"n":"XLKR - Linked Reference"},{"t":6,"s":1,"p":1,"n":"XCLP - Linked Reference Color","c":[{"t":6,"p":1,"n":"Link Start Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Link End Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":2,"p":1,"n":"XATO - Activation Prompt"},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIBS - Ignored By Sandbox"},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"PERK - Perk","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"CTDA - Condition","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Note"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Creature Type"},{"t":3,"p":1,"n":"Menu Mode"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Body Location"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Quest Objective (INVALID)"},{"t":3,"p":1,"n":"Reputation"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Challenge"},{"t":3,"p":1,"n":"Casino"},{"t":3,"p":1,"n":"Form"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"VATS Value Function (INVALID)"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Quest Objective"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"}]}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Trait"},{"t":3,"p":1,"n":"Min Level"},{"t":3,"p":1,"n":"Ranks"},{"t":3,"p":1,"n":"Playable"},{"t":3,"p":1,"n":"Hidden"}]},{"t":10,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":6,"p":1,"n":"PRKE - Header","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Rank"},{"t":3,"p":1,"n":"Priority"}]},{"t":6,"p":1,"n":"Quest + Stage","c":[{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"Ability"},{"t":6,"p":1,"n":"Entry Point","c":[{"t":3,"p":1,"n":"Entry Point"},{"t":3,"p":1,"n":"Function"},{"t":3,"p":1,"n":"Perk Condition Tab Count"}]},{"t":10,"p":1,"n":"Perk Conditions","c":[{"t":6,"p":1,"n":"Perk Condition","c":[{"t":3,"p":1,"n":"PRKC - Run On"},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"CTDA - Condition","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Note"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Creature Type"},{"t":3,"p":1,"n":"Menu Mode"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Body Location"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Quest Objective (INVALID)"},{"t":3,"p":1,"n":"Reputation"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Challenge"},{"t":3,"p":1,"n":"Casino"},{"t":3,"p":1,"n":"Form"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"VATS Value Function (INVALID)"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Quest Objective"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"}]}]}]}]},{"t":6,"p":1,"n":"Entry Point Function Parameters","c":[{"t":3,"p":1,"n":"EPFT - Type"},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"Float"},{"t":6,"p":1,"n":"Float, Float","c":[{"t":5,"p":1,"n":"Float 1"},{"t":5,"p":1,"n":"Float 2"}]},{"t":3,"p":1,"n":"Leveled Item"},{"p":1,"n":"None (Script)"},{"t":6,"p":1,"n":"Actor Value, Float","c":[{"t":3,"p":1,"n":"Actor Value"},{"t":5,"p":1,"n":"Float"}]},{"t":2,"p":1,"n":"EPF2 - Button Label"},{"t":3,"p":1,"n":"EPF3 - Script Flags"},{"t":6,"p":1,"n":"Embedded Script","c":[{"t":6,"p":1,"n":"SCHR - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"p":1,"n":"SCDA - Compiled Embedded Script"},{"t":2,"p":1,"n":"SCTX - Embedded Script Source"},{"t":10,"p":1,"n":"Local Variables","c":[{"t":6,"p":1,"n":"Local Variable","c":[{"t":6,"p":1,"n":"SLSD - Local Variable Data","c":[{"t":3,"p":1,"n":"Index"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"SCVR - Name"}]}]},{"t":8,"p":1,"n":"References","c":[{"t":3,"p":1,"n":"SCRO - Global Reference"},{"t":3,"p":1,"n":"SCRV - Local Variable"}]}]}]},{"p":1,"n":"PRKF - End Marker"}]}]}]},{"t":1,"p":1,"n":"PGRE - Placed Grenade","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"NAME - Base"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":11,"n":"XRGD - Ragdoll Data"},{"t":11,"n":"XRGB - Ragdoll Biped Data"},{"t":6,"s":1,"p":1,"n":"Patrol Data","c":[{"t":5,"p":1,"n":"XPRD - Idle Time"},{"p":1,"n":"XPPA - Patrol Script Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":6,"p":1,"n":"Embedded Script","c":[{"t":6,"p":1,"n":"SCHR - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"p":1,"n":"SCDA - Compiled Embedded Script"},{"t":2,"p":1,"n":"SCTX - Embedded Script Source"},{"t":10,"p":1,"n":"Local Variables","c":[{"t":6,"p":1,"n":"Local Variable","c":[{"t":6,"p":1,"n":"SLSD - Local Variable Data","c":[{"t":3,"p":1,"n":"Index"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"SCVR - Name"}]}]},{"t":8,"p":1,"n":"References","c":[{"t":3,"p":1,"n":"SCRO - Global Reference"},{"t":3,"p":1,"n":"SCRV - Local Variable"}]}]},{"t":3,"p":1,"n":"TNAM - Topic"}]},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":3,"p":1,"n":"XCNT - Count"},{"t":5,"p":1,"n":"XRDS - Radius"},{"t":5,"p":1,"n":"XHLP - Health"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked Decals","d":1,"c":[{"t":6,"p":1,"n":"XDCR - Decal","c":[{"t":3,"p":1,"n":"Reference"},{"t":11,"n":"Unknown"}]}]},{"t":3,"p":1,"n":"XLKR - Linked Reference"},{"t":6,"s":1,"p":1,"n":"XCLP - Linked Reference Color","c":[{"t":6,"p":1,"n":"Link Start Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Link End Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":2,"p":1,"n":"XATO - Activation Prompt"},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIBS - Ignored By Sandbox"},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"PMIS - Placed Missile","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"NAME - Base"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":11,"n":"XRGD - Ragdoll Data"},{"t":11,"n":"XRGB - Ragdoll Biped Data"},{"t":6,"s":1,"p":1,"n":"Patrol Data","c":[{"t":5,"p":1,"n":"XPRD - Idle Time"},{"p":1,"n":"XPPA - Patrol Script Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":6,"p":1,"n":"Embedded Script","c":[{"t":6,"p":1,"n":"SCHR - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"p":1,"n":"SCDA - Compiled Embedded Script"},{"t":2,"p":1,"n":"SCTX - Embedded Script Source"},{"t":10,"p":1,"n":"Local Variables","c":[{"t":6,"p":1,"n":"Local Variable","c":[{"t":6,"p":1,"n":"SLSD - Local Variable Data","c":[{"t":3,"p":1,"n":"Index"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"SCVR - Name"}]}]},{"t":8,"p":1,"n":"References","c":[{"t":3,"p":1,"n":"SCRO - Global Reference"},{"t":3,"p":1,"n":"SCRV - Local Variable"}]}]},{"t":3,"p":1,"n":"TNAM - Topic"}]},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":3,"p":1,"n":"XCNT - Count"},{"t":5,"p":1,"n":"XRDS - Radius"},{"t":5,"p":1,"n":"XHLP - Health"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked Decals","d":1,"c":[{"t":6,"p":1,"n":"XDCR - Decal","c":[{"t":3,"p":1,"n":"Reference"},{"t":11,"n":"Unknown"}]}]},{"t":3,"p":1,"n":"XLKR - Linked Reference"},{"t":6,"s":1,"p":1,"n":"XCLP - Linked Reference Color","c":[{"t":6,"p":1,"n":"Link Start Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Link End Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":2,"p":1,"n":"XATO - Activation Prompt"},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIBS - Ignored By Sandbox"},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"PROJ - Projectile","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Type"},{"t":5,"p":1,"n":"Gravity"},{"t":5,"p":1,"n":"Speed"},{"t":5,"p":1,"n":"Range"},{"t":3,"p":1,"n":"Light"},{"t":3,"p":1,"n":"Muzzle Flash - Light"},{"t":5,"p":1,"n":"Tracer Chance"},{"t":5,"p":1,"n":"Explosion - Alt. Trigger - Proximity"},{"t":5,"p":1,"n":"Explosion - Alt. Trigger - Timer"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Sound"},{"t":5,"p":1,"n":"Muzzle Flash - Duration"},{"t":5,"p":1,"n":"Fade Duration"},{"t":5,"p":1,"n":"Impact Force"},{"t":3,"p":1,"n":"Sound - Countdown"},{"t":3,"p":1,"n":"Sound - Disable"},{"t":3,"p":1,"n":"Default Weapon Source"},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":5,"p":1,"n":"Bouncy Mult"}]},{"t":6,"s":1,"p":1,"n":"Muzzle Flash Model","c":[{"t":2,"p":1,"n":"NAM1 - Model Filename"},{"t":11,"p":1,"n":"NAM2 - Texture Files Hashes"}]},{"t":3,"p":1,"n":"VNAM - Sound Level"}]},{"t":1,"p":1,"n":"PWAT - Placeable Water","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"DNAM - ","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Water"}]}]},{"t":1,"p":1,"n":"QUST - Quest","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"SCRI - Script"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"DATA - General","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Priority"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Quest Delay"}]},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"CTDA - Condition","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Note"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Creature Type"},{"t":3,"p":1,"n":"Menu Mode"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Body Location"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Quest Objective (INVALID)"},{"t":3,"p":1,"n":"Reputation"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Challenge"},{"t":3,"p":1,"n":"Casino"},{"t":3,"p":1,"n":"Form"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"VATS Value Function (INVALID)"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Quest Objective"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"}]}]},{"t":10,"p":1,"n":"Stages","d":1,"c":[{"t":6,"p":1,"n":"Stage","c":[{"t":3,"p":1,"n":"INDX - Stage Index"},{"t":8,"p":1,"n":"Log Entries","c":[{"t":6,"p":1,"n":"Log Entry","c":[{"t":3,"p":1,"n":"QSDT - Stage Flags"},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"CTDA - Condition","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Note"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Creature Type"},{"t":3,"p":1,"n":"Menu Mode"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Body Location"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Quest Objective (INVALID)"},{"t":3,"p":1,"n":"Reputation"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Challenge"},{"t":3,"p":1,"n":"Casino"},{"t":3,"p":1,"n":"Form"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"VATS Value Function (INVALID)"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Quest Objective"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"}]}]},{"t":2,"p":1,"n":"CNAM - Log Entry"},{"t":6,"p":1,"n":"Embedded Script","c":[{"t":6,"p":1,"n":"SCHR - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"p":1,"n":"SCDA - Compiled Embedded Script"},{"t":2,"p":1,"n":"SCTX - Embedded Script Source"},{"t":10,"p":1,"n":"Local Variables","c":[{"t":6,"p":1,"n":"Local Variable","c":[{"t":6,"p":1,"n":"SLSD - Local Variable Data","c":[{"t":3,"p":1,"n":"Index"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"SCVR - Name"}]}]},{"t":8,"p":1,"n":"References","c":[{"t":3,"p":1,"n":"SCRO - Global Reference"},{"t":3,"p":1,"n":"SCRV - Local Variable"}]}]},{"t":3,"p":1,"n":"NAM0 - Next Quest"}]}]}]}]},{"t":8,"s":1,"p":1,"n":"Objectives","d":1,"c":[{"t":6,"p":1,"n":"Objective","c":[{"t":3,"p":1,"n":"QOBJ - Objective Index"},{"t":2,"p":1,"n":"NNAM - Description"},{"t":8,"p":1,"n":"Targets","c":[{"t":6,"p":1,"n":"Target","c":[{"t":6,"p":1,"n":"QSTA - Target","c":[{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"CTDA - Condition","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Note"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Creature Type"},{"t":3,"p":1,"n":"Menu Mode"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Body Location"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Quest Objective (INVALID)"},{"t":3,"p":1,"n":"Reputation"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Challenge"},{"t":3,"p":1,"n":"Casino"},{"t":3,"p":1,"n":"Form"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"VATS Value Function (INVALID)"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Quest Objective"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"}]}]}]}]}]}]}]},{"t":1,"p":1,"n":"RACE - Race","c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"DESC - Description"},{"t":8,"s":1,"p":1,"n":"Relations","d":1,"c":[{"t":6,"p":1,"n":"XNAM - Relation","c":[{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Modifier"},{"t":3,"p":1,"n":"Group Combat Reaction"}]}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":7,"p":1,"n":"Skill Boosts","d":1,"c":[{"t":6,"p":1,"n":"Skill Boost","c":[{"t":3,"p":1,"n":"Skill"},{"t":3,"p":1,"n":"Boost"}]}]},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Male Height"},{"t":5,"p":1,"n":"Female Height"},{"t":5,"p":1,"n":"Male Weight"},{"t":5,"p":1,"n":"Female Weight"},{"t":3,"p":1,"n":"Flags"}]},{"t":3,"p":1,"n":"ONAM - Older"},{"t":3,"p":1,"n":"YNAM - Younger"},{"n":"NAM2 - Unknown Marker"},{"t":7,"s":1,"p":1,"n":"VTCK - Voices","d":1,"c":[{"t":3,"p":1,"n":"Voice"}]},{"t":7,"s":1,"p":1,"n":"DNAM - Default Hair Styles","d":1,"c":[{"t":3,"p":1,"n":"Default Hair Style"}]},{"t":7,"s":1,"p":1,"n":"CNAM - Default Hair Colors","d":1,"c":[{"t":3,"p":1,"n":"Default Hair Color"}]},{"t":5,"p":1,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"p":1,"n":"UNAM - FaceGen - Face clamp"},{"t":11,"n":"ATTR - Unused"},{"t":6,"s":1,"p":1,"n":"Head Data","c":[{"p":1,"n":"NAM0 - Head Data Marker"},{"t":6,"p":1,"n":"Male Head Data","c":[{"p":1,"n":"MNAM - Male Data Marker"},{"t":10,"p":1,"n":"Parts","d":1,"c":[{"t":6,"p":1,"n":"Part","c":[{"t":3,"p":1,"n":"INDX - Index"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]}]}]}]},{"t":6,"p":1,"n":"Female Head Data","c":[{"p":1,"n":"FNAM - Female Data Marker"},{"t":10,"p":1,"n":"Parts","d":1,"c":[{"t":6,"p":1,"n":"Part","c":[{"t":3,"p":1,"n":"INDX - Index"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"Body Data","c":[{"p":1,"n":"NAM1 - Body Data Marker"},{"t":6,"p":1,"n":"Male Body Data","c":[{"p":1,"n":"MNAM - Male Data Marker"},{"t":10,"p":1,"n":"Parts","d":1,"c":[{"t":6,"p":1,"n":"Part","c":[{"t":3,"p":1,"n":"INDX - Index"},{"t":6,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","d":1,"c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]}]}]}]},{"t":6,"p":1,"n":"Female Body Data","c":[{"p":1,"n":"FNAM - Female Data Marker"},{"t":10,"p":1,"n":"Parts","d":1,"c":[{"t":6,"p":1,"n":"Part","c":[{"t":3,"p":1,"n":"INDX - Index"},{"t":6,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","d":1,"c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]}]}]}]}]},{"t":7,"s":1,"p":1,"n":"HNAM - Hairs","d":1,"c":[{"t":3,"p":1,"n":"Hair"}]},{"t":7,"s":1,"p":1,"n":"ENAM - Eyes","d":1,"c":[{"t":3,"p":1,"n":"Eye"}]},{"t":6,"s":1,"p":1,"n":"FaceGen Data","c":[{"t":6,"p":1,"n":"Male FaceGen Data","c":[{"p":1,"n":"MNAM - Male Data Marker"},{"t":6,"p":1,"n":"FaceGen Data","c":[{"t":11,"p":1,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"p":1,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"p":1,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":3,"n":"SNAM - Unknown"}]},{"t":6,"p":1,"n":"Female FaceGen Data","c":[{"p":1,"n":"FNAM - Female Data Marker"},{"t":6,"p":1,"n":"FaceGen Data","c":[{"t":11,"p":1,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"p":1,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"p":1,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":3,"n":"SNAM - Unknown"}]}]}]},{"t":1,"p":1,"n":"RADS - Radiation Stage","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Trigger Threshold"},{"t":3,"p":1,"n":"Actor Effect"}]}]},{"t":1,"p":1,"n":"RCCT - Recipe Category","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"DATA - Flags"}]},{"t":1,"p":1,"n":"RCPE - Recipe","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"CTDA - Condition","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Note"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Creature Type"},{"t":3,"p":1,"n":"Menu Mode"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Body Location"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Quest Objective (INVALID)"},{"t":3,"p":1,"n":"Reputation"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Challenge"},{"t":3,"p":1,"n":"Casino"},{"t":3,"p":1,"n":"Form"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"VATS Value Function (INVALID)"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Quest Objective"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"}]}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Skill"},{"t":3,"p":1,"n":"Level"},{"t":3,"p":1,"n":"Category"},{"t":3,"p":1,"n":"Sub-Category"}]},{"t":8,"s":1,"p":1,"n":"Ingredients","d":1,"c":[{"t":6,"p":1,"n":"Ingredient","c":[{"t":3,"p":1,"n":"RCIL - Item"},{"t":3,"p":1,"n":"RCQY - Quantity"}]}]},{"t":8,"s":1,"p":1,"n":"Outputs","d":1,"c":[{"t":6,"p":1,"n":"Output","c":[{"t":3,"p":1,"n":"RCOD - Item"},{"t":3,"p":1,"n":"RCQY - Quantity"}]}]}]},{"t":1,"p":1,"n":"REFR - Placed Object","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":11,"n":"RCLR - Unused"},{"t":3,"p":1,"n":"NAME - Base"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":11,"n":"XRGD - Ragdoll Data"},{"t":11,"n":"XRGB - Ragdoll Biped Data"},{"t":6,"s":1,"p":1,"n":"XPRM - Primitive","c":[{"t":6,"p":1,"n":"Bounds","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Color","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}]},{"t":5,"n":"Unknown"},{"t":3,"p":1,"n":"Type"}]},{"t":3,"p":1,"n":"XTRI - Collision Layer"},{"p":1,"n":"XMBP - MultiBound Primitive Marker"},{"t":6,"s":1,"p":1,"n":"XMBO - Bound Half Extents","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"s":1,"p":1,"n":"XTEL - Teleport Destination","c":[{"t":3,"p":1,"n":"Door"},{"t":6,"p":1,"n":"Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]},{"t":3,"p":1,"n":"Flags"}]},{"t":6,"s":1,"p":1,"n":"Map Marker","c":[{"p":1,"n":"XMRK - Map Marker Data"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"p":1,"n":"TNAM - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"WMI1 - Reputation"}]},{"t":6,"s":1,"p":1,"n":"Audio Data","c":[{"p":1,"n":"MMRK - Audio Marker"},{"t":11,"n":"FULL - Unknown"},{"t":3,"p":1,"n":"CNAM - Audio Location"},{"t":3,"p":1,"n":"BNAM - Flags"},{"t":5,"p":1,"n":"MNAM - Layer 2 Trigger %"},{"t":5,"p":1,"n":"NNAM - Layer 3 Trigger %"}]},{"t":3,"p":1,"n":"XSRF - Special Rendering Flags"},{"t":11,"n":"XSRD - Special Rendering Data"},{"t":3,"p":1,"n":"XTRG - Target"},{"t":3,"p":1,"n":"XLCM - Level Modifier"},{"t":6,"s":1,"p":1,"n":"Patrol Data","c":[{"t":5,"p":1,"n":"XPRD - Idle Time"},{"p":1,"n":"XPPA - Patrol Script Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":6,"p":1,"n":"Embedded Script","c":[{"t":6,"p":1,"n":"SCHR - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"p":1,"n":"SCDA - Compiled Embedded Script"},{"t":2,"p":1,"n":"SCTX - Embedded Script Source"},{"t":10,"p":1,"n":"Local Variables","c":[{"t":6,"p":1,"n":"Local Variable","c":[{"t":6,"p":1,"n":"SLSD - Local Variable Data","c":[{"t":3,"p":1,"n":"Index"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"SCVR - Name"}]}]},{"t":8,"p":1,"n":"References","c":[{"t":3,"p":1,"n":"SCRO - Global Reference"},{"t":3,"p":1,"n":"SCRV - Local Variable"}]}]},{"t":3,"p":1,"n":"TNAM - Topic"}]},{"t":6,"s":1,"p":1,"n":"XRDO - Radio Data","c":[{"t":5,"p":1,"n":"Range Radius"},{"t":3,"p":1,"n":"Broadcast Range Type"},{"t":5,"p":1,"n":"Static Percentage"},{"t":3,"p":1,"n":"Position Reference"}]},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":6,"s":1,"p":1,"n":"XLOC - Lock Data","c":[{"t":3,"p":1,"n":"Level"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Key"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"}]},{"t":3,"p":1,"n":"XCNT - Count"},{"t":5,"p":1,"n":"XRDS - Radius"},{"t":5,"p":1,"n":"XHLP - Health"},{"t":5,"p":1,"n":"XRAD - Radiation"},{"t":5,"p":1,"n":"XCHG - Charge"},{"t":6,"s":1,"p":1,"n":"Ammo","c":[{"t":3,"p":1,"n":"XAMT - Type"},{"t":3,"p":1,"n":"XAMC - Count"}]},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Lit Water","d":1,"c":[{"t":3,"p":1,"n":"XLTW - Water"}]},{"t":8,"s":1,"p":1,"n":"Linked Decals","d":1,"c":[{"t":6,"p":1,"n":"XDCR - Decal","c":[{"t":3,"p":1,"n":"Reference"},{"t":11,"n":"Unknown"}]}]},{"t":3,"p":1,"n":"XLKR - Linked Reference"},{"t":6,"s":1,"p":1,"n":"XCLP - Linked Reference Color","c":[{"t":6,"p":1,"n":"Link Start Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Link End Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":2,"p":1,"n":"XATO - Activation Prompt"},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"t":3,"p":1,"n":"XACT - Action Flag"},{"p":1,"n":"ONAM - Open by Default"},{"p":1,"n":"XIBS - Ignored By Sandbox"},{"t":6,"s":1,"p":1,"n":"XNDP - Navigation Door Link","c":[{"t":3,"p":1,"n":"Navigation Mesh"},{"t":3,"p":1,"n":"Teleport Marker Triangle"},{"t":11,"n":"Unused"}]},{"t":7,"p":1,"n":"XPOD - Portal Data","c":[{"t":3,"p":1,"n":"Room"}]},{"t":6,"s":1,"p":1,"n":"XPTL - Portal Data","c":[{"t":6,"p":1,"n":"Size","c":[{"t":5,"p":1,"n":"Width"},{"t":5,"p":1,"n":"Height"}]},{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation (Quaternion?)","c":[{"t":5,"p":1,"n":"q1"},{"t":5,"p":1,"n":"q2"},{"t":5,"p":1,"n":"q3"},{"t":5,"p":1,"n":"q4"}]}]},{"t":3,"p":1,"n":"XSED - SpeedTree Seed"},{"t":6,"s":1,"p":1,"n":"Room Data","c":[{"t":6,"p":1,"n":"XRMR - Header","c":[{"t":3,"p":1,"n":"Linked Rooms Count"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Linked Rooms","c":[{"t":3,"p":1,"n":"XLRM - Linked Room"}]}]},{"t":6,"s":1,"p":1,"n":"XOCP - Occlusion Plane Data","c":[{"t":6,"p":1,"n":"Size","c":[{"t":5,"p":1,"n":"Width"},{"t":5,"p":1,"n":"Height"}]},{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation (Quaternion?)","c":[{"t":5,"p":1,"n":"q1"},{"t":5,"p":1,"n":"q2"},{"t":5,"p":1,"n":"q3"},{"t":5,"p":1,"n":"q4"}]}]},{"t":7,"p":1,"n":"XORD - Linked Occlusion Planes","c":[{"t":3,"p":1,"n":"Plane"}]},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"REGN - Region","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"RCLR - Map Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"WNAM - Worldspace"},{"t":8,"s":1,"p":1,"n":"Region Areas","d":1,"c":[{"t":6,"p":1,"n":"Region Area","c":[{"t":3,"p":1,"n":"RPLI - Edge Fall-off"},{"t":7,"p":1,"n":"RPLD - Region Point List Data","c":[{"t":6,"p":1,"n":"Point","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"}]}]}]}]},{"t":10,"p":1,"n":"Region Data Entries","d":1,"c":[{"t":6,"p":1,"n":"Region Data Entry","c":[{"t":6,"p":1,"n":"RDAT - Data Header","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Priority"},{"t":11,"n":"Unused"}]},{"t":7,"p":1,"n":"RDOT - Objects","c":[{"t":6,"p":1,"n":"Object","c":[{"t":3,"p":1,"n":"Object"},{"t":3,"p":1,"n":"Parent Index"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Density"},{"t":3,"p":1,"n":"Clustering"},{"t":3,"p":1,"n":"Min Slope"},{"t":3,"p":1,"n":"Max Slope"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Radius wrt Parent"},{"t":3,"p":1,"n":"Radius"},{"t":5,"p":1,"n":"Min Height"},{"t":5,"p":1,"n":"Max Height"},{"t":5,"p":1,"n":"Sink"},{"t":5,"p":1,"n":"Sink Variance"},{"t":5,"p":1,"n":"Size Variance"},{"t":6,"p":1,"n":"Angle Variance","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"},{"t":3,"p":1,"n":"Z"}]},{"t":11,"n":"Unknown"}]}]},{"t":2,"p":1,"n":"RDMP - Map Name"},{"t":7,"p":1,"n":"RDGS - Grasses","c":[{"t":6,"p":1,"n":"Grass","c":[{"t":3,"p":1,"n":"Grass"},{"t":11,"n":"Unknown"}]}]},{"t":3,"p":1,"n":"RDMD - Music Type"},{"t":3,"p":1,"n":"RDMO - Music"},{"t":3,"p":1,"n":"RDSI - Incidental MediaSet"},{"t":8,"p":1,"n":"Battle MediaSets","c":[{"t":3,"p":1,"n":"RDSB - Battle MediaSet"}]},{"t":7,"p":1,"n":"RDSD - Sounds","c":[{"t":6,"p":1,"n":"Sound","c":[{"t":3,"p":1,"n":"Sound"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Chance"}]}]},{"t":7,"p":1,"n":"RDWT - Weather Types","c":[{"t":6,"p":1,"n":"Weather Type","c":[{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Chance"},{"t":3,"p":1,"n":"Global"}]}]},{"t":7,"p":1,"n":"RDID - Imposters","c":[{"t":3,"p":1,"n":"Imposter"}]}]}]}]},{"t":1,"p":1,"n":"REPU - Reputation","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":5,"p":1,"n":"DATA - Value"}]},{"t":1,"p":1,"n":"RGDL - Ragdoll","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"NVER - Version"},{"t":6,"s":1,"p":1,"n":"DATA - General Data","c":[{"t":3,"p":1,"n":"Dynamic Bone Count"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Enabled","c":[{"t":3,"p":1,"n":"Feedback"},{"t":3,"p":1,"n":"Foot IK (broken, don't use)"},{"t":3,"p":1,"n":"Look IK (broken, don't use)"},{"t":3,"p":1,"n":"Grab IK (broken, don't use)"},{"t":3,"p":1,"n":"Pose Matching"}]}]},{"t":3,"p":1,"n":"XNAM - Actor Base"},{"t":3,"p":1,"n":"TNAM - Body Part Data"},{"t":6,"s":1,"p":1,"n":"RAFD - Feedback Data","c":[{"t":5,"p":1,"n":"Dynamic\/Keyframe Blend Amount"},{"t":5,"p":1,"n":"Hierarchy Gain"},{"t":5,"p":1,"n":"Position Gain"},{"t":5,"p":1,"n":"Velocity Gain"},{"t":5,"p":1,"n":"Acceleration Gain"},{"t":5,"p":1,"n":"Snap Gain"},{"t":5,"p":1,"n":"Velocity Damping"},{"t":6,"p":1,"n":"Snap Max Settings","c":[{"t":5,"p":1,"n":"Linear Velocity"},{"t":5,"p":1,"n":"Angular Velocity"},{"t":5,"p":1,"n":"Linear Distance"},{"t":5,"p":1,"n":"Angular Distance"}]},{"t":6,"p":1,"n":"Position Max Velocity","c":[{"t":5,"p":1,"n":"Linear"},{"t":5,"p":1,"n":"Angular"}]}]},{"t":7,"p":1,"n":"RAFB - Feedback Dynamic Bones","c":[{"t":3,"p":1,"n":"Bone"}]},{"t":6,"s":1,"p":1,"n":"RAPS - Pose Matching Data","c":[{"t":7,"p":1,"n":"Match Bones","c":[{"t":3,"p":1,"n":"Bone"}]},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Motors Strength"},{"t":5,"p":1,"n":"Pose Activation Delay Time"},{"t":5,"p":1,"n":"Match Error Allowance"},{"t":5,"p":1,"n":"Displacement To Disable"}]},{"t":2,"p":1,"n":"ANAM - Death Pose"}]},{"t":1,"p":1,"n":"SCOL - Static Collection","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":10,"p":1,"n":"Parts","d":1,"c":[{"t":6,"p":1,"n":"Part","c":[{"t":3,"p":1,"n":"ONAM - Static"},{"t":7,"p":1,"n":"DATA - Placements","c":[{"t":6,"p":1,"n":"Placement","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":5,"p":1,"n":"Scale"}]}]}]}]}]},{"t":1,"p":1,"n":"SCPT - Script","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"SCHR - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"n":"SCDA - Compiled Script"},{"t":2,"p":1,"n":"SCTX - Script Source"},{"t":10,"p":1,"n":"Local Variables","d":1,"c":[{"t":6,"p":1,"n":"Local Variable","c":[{"t":6,"p":1,"n":"SLSD - Local Variable Data","c":[{"t":3,"p":1,"n":"Index"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"SCVR - Name"}]}]},{"t":8,"s":1,"p":1,"n":"References","d":1,"c":[{"t":3,"p":1,"n":"SCRO - Global Reference"},{"t":3,"p":1,"n":"SCRV - Local Variable"}]}]},{"t":1,"p":1,"n":"SLPD - Sleep Deprivation Stage","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Trigger Threshold"},{"t":3,"p":1,"n":"Actor Effect"}]}]},{"t":1,"p":1,"n":"SOUN - Sound","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FNAM - Sound Filename"},{"t":3,"p":1,"n":"RNAM - Random Chance %"},{"t":6,"s":1,"p":1,"n":"SNDD - Sound Data","c":[{"t":3,"p":1,"n":"Minimum Attentuation Distance"},{"t":3,"p":1,"n":"Maximum Attentuation Distance"},{"t":3,"p":1,"n":"Frequency Adjustment %"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Static attentuation cdB"},{"t":3,"p":1,"n":"Stop time "},{"t":3,"p":1,"n":"Start time "},{"t":7,"p":1,"n":"Attenuation Curve","c":[{"t":3,"p":1,"n":"Point"}]},{"t":3,"p":1,"n":"Reverb Attenuation Control"},{"t":3,"p":1,"n":"Priority"},{"t":3,"p":1,"n":"x"},{"t":3,"p":1,"n":"y"}]},{"t":6,"s":1,"p":1,"n":"SNDX - Sound Data","c":[{"t":3,"p":1,"n":"Minimum attentuation distance"},{"t":3,"p":1,"n":"Maximum attentuation distance"},{"t":3,"p":1,"n":"Frequency adjustment %"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Static attentuation cdB"},{"t":3,"p":1,"n":"Stop time "},{"t":3,"p":1,"n":"Start time "}]},{"t":7,"p":1,"n":"ANAM - Attenuation Curve","c":[{"t":3,"p":1,"n":"Point"}]},{"t":3,"p":1,"n":"GNAM - Reverb Attenuation Control"},{"t":3,"p":1,"n":"HNAM - Priority"}]},{"t":1,"p":1,"n":"SPEL - Actor Effect","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"SPIT - ","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"n":"Cost (Unused)"},{"t":3,"n":"Level (Unused)"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"s":1,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":3,"p":1,"n":"EFID - Base Effect"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":3,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Actor Value"}]},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"CTDA - Condition","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Note"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Creature Type"},{"t":3,"p":1,"n":"Menu Mode"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Body Location"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Quest Objective (INVALID)"},{"t":3,"p":1,"n":"Reputation"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Challenge"},{"t":3,"p":1,"n":"Casino"},{"t":3,"p":1,"n":"Form"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"VATS Value Function (INVALID)"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Quest Objective"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"}]}]}]}]}]},{"t":1,"p":1,"n":"STAT - Static","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":3,"p":1,"n":"BRUS - Passthrough Sound"},{"t":3,"p":1,"n":"RNAM - Sound - Looping\/Random"}]},{"t":1,"p":1,"n":"TACT - Talking Activator","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"SNAM - Looping Sound"},{"t":3,"p":1,"n":"VNAM - Voice Type"},{"t":3,"p":1,"n":"INAM - Radio Template"}]},{"t":1,"p":1,"n":"TERM - Terminal","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":2,"p":1,"n":"DESC - Description"},{"t":3,"p":1,"n":"SNAM - Sound - Looping"},{"t":3,"p":1,"n":"PNAM - Password Note"},{"t":6,"s":1,"p":1,"n":"DNAM - ","c":[{"t":3,"p":1,"n":"Base Hacking Difficulty"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"ServerType"},{"t":11,"n":"Unused"}]},{"t":8,"s":1,"p":1,"n":"Menu Items","d":1,"c":[{"t":6,"p":1,"n":"Menu Item","c":[{"t":2,"p":1,"n":"ITXT - Item Text"},{"t":2,"p":1,"n":"RNAM - Result Text"},{"t":3,"p":1,"n":"ANAM - Flags"},{"t":3,"p":1,"n":"INAM - Display Note"},{"t":3,"p":1,"n":"TNAM - Sub Menu"},{"t":6,"p":1,"n":"Embedded Script","c":[{"t":6,"p":1,"n":"SCHR - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"p":1,"n":"SCDA - Compiled Embedded Script"},{"t":2,"p":1,"n":"SCTX - Embedded Script Source"},{"t":10,"p":1,"n":"Local Variables","c":[{"t":6,"p":1,"n":"Local Variable","c":[{"t":6,"p":1,"n":"SLSD - Local Variable Data","c":[{"t":3,"p":1,"n":"Index"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"SCVR - Name"}]}]},{"t":8,"p":1,"n":"References","c":[{"t":3,"p":1,"n":"SCRO - Global Reference"},{"t":3,"p":1,"n":"SCRV - Local Variable"}]}]},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"CTDA - Condition","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Note"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Creature Type"},{"t":3,"p":1,"n":"Menu Mode"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Body Location"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Quest Objective (INVALID)"},{"t":3,"p":1,"n":"Reputation"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Challenge"},{"t":3,"p":1,"n":"Casino"},{"t":3,"p":1,"n":"Form"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"VATS Value Function (INVALID)"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Quest Objective"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"}]}]}]}]}]},{"t":1,"p":1,"n":"TREE - Tree","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":7,"p":1,"n":"SNAM - SpeedTree Seeds","c":[{"t":3,"p":1,"n":"SpeedTree Seed"}]},{"t":6,"s":1,"p":1,"n":"CNAM - Tree Data","c":[{"t":5,"p":1,"n":"Leaf Curvature"},{"t":5,"p":1,"n":"Minimum Leaf Angle"},{"t":5,"p":1,"n":"Maximum Leaf Angle"},{"t":5,"p":1,"n":"Branch Dimming Value"},{"t":5,"p":1,"n":"Leaf Dimming Value"},{"t":3,"p":1,"n":"Shadow Radius"},{"t":5,"p":1,"n":"Rock Speed"},{"t":5,"p":1,"n":"Rustle Speed"}]},{"t":6,"s":1,"p":1,"n":"BNAM - Billboard Dimensions","c":[{"t":5,"p":1,"n":"Width"},{"t":5,"p":1,"n":"Height"}]}]},{"t":1,"p":1,"n":"TXST - Texture Set","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Textures (RGB\/A)","c":[{"t":2,"p":1,"n":"TX00 - Base Image \/ Transparency"},{"t":2,"p":1,"n":"TX01 - Normal Map \/ Specular"},{"t":2,"p":1,"n":"TX02 - Environment Map Mask \/ ?"},{"t":2,"n":"TX03 - Glow Map \/ Unused"},{"t":2,"n":"TX04 - Parallax Map \/ Unused"},{"t":2,"n":"TX05 - Environment Map \/ Unused"}]},{"t":6,"s":1,"p":1,"n":"DODT - Decal Data","c":[{"t":5,"p":1,"n":"Min Width"},{"t":5,"p":1,"n":"Max Width"},{"t":5,"p":1,"n":"Min Height"},{"t":5,"p":1,"n":"Max Height"},{"t":5,"p":1,"n":"Depth"},{"t":5,"p":1,"n":"Shininess"},{"t":6,"p":1,"n":"Parallax","c":[{"t":5,"p":1,"n":"Scale"},{"t":3,"p":1,"n":"Passes"}]},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":3,"p":1,"n":"DNAM - Flags"}]},{"t":1,"p":1,"n":"VTYP - Voice Type","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"DNAM - Flags"}]},{"t":1,"p":1,"n":"WATR - Water","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"NNAM - Noise Map"},{"t":3,"p":1,"n":"ANAM - Opacity"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":2,"p":1,"n":"MNAM - Material ID"},{"t":3,"p":1,"n":"SNAM - Sound"},{"t":3,"p":1,"n":"XNAM - Actor Effect"},{"t":3,"p":1,"n":"DATA - Damage"},{"t":6,"s":1,"p":1,"n":"DNAM - Visual Data","c":[{"t":5,"n":"Unknown"},{"t":5,"p":1,"n":"Water Properties - Sun Power"},{"t":5,"p":1,"n":"Water Properties - Reflectivity Amount"},{"t":5,"p":1,"n":"Water Properties - Fresnel Amount"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Fog Properties - Above Water - Fog Distance - Near Plane"},{"t":5,"p":1,"n":"Fog Properties - Above Water - Fog Distance - Far Plane"},{"t":6,"p":1,"n":"Shallow Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Deep Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Reflection Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Rain Simulator - Force"},{"t":5,"p":1,"n":"Rain Simulator - Velocity"},{"t":5,"p":1,"n":"Rain Simulator - Falloff"},{"t":5,"p":1,"n":"Rain Simulator - Dampner"},{"t":5,"p":1,"n":"Displacement Simulator - Starting Size"},{"t":5,"p":1,"n":"Displacement Simulator - Force"},{"t":5,"p":1,"n":"Displacement Simulator - Velocity"},{"t":5,"p":1,"n":"Displacement Simulator - Falloff"},{"t":5,"p":1,"n":"Displacement Simulator - Dampner"},{"t":5,"p":1,"n":"Rain Simulator - Starting Size"},{"t":5,"p":1,"n":"Noise Properties - Normals - Noise Scale"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer One - Wind Direction"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer Two - Wind Direction"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer Three - Wind Direction"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer One - Wind Speed"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer Two - Wind Speed"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer Three - Wind Speed"},{"t":5,"p":1,"n":"Noise Properties - Normals - Depth Falloff Start"},{"t":5,"p":1,"n":"Noise Properties - Normals - Depth Falloff End"},{"t":5,"p":1,"n":"Fog Properties - Above Water - Fog Amount"},{"t":5,"p":1,"n":"Noise Properties - Normals - UV Scale"},{"t":5,"p":1,"n":"Fog Properties - Under Water - Fog Amount"},{"t":5,"p":1,"n":"Fog Properties - Under Water - Fog Distance - Near Plane"},{"t":5,"p":1,"n":"Fog Properties - Under Water - Fog Distance - Far Plane"},{"t":5,"p":1,"n":"Water Properties - Distortion Amount"},{"t":5,"p":1,"n":"Water Properties - Shininess"},{"t":5,"p":1,"n":"Water Properties - Reflection HDR Multiplier"},{"t":5,"p":1,"n":"Water Properties - Light Radius"},{"t":5,"p":1,"n":"Water Properties - Light Brightness"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer One - UV Scale"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer Two - UV Scale"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer Three - UV Scale"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer One - Amplitude Scale"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer Two - Amplitude Scale"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer Three - Amplitude Scale"}]},{"t":6,"s":1,"p":1,"n":"DATA - Visual Data","c":[{"t":5,"n":"Unknown"},{"t":5,"p":1,"n":"Water Properties - Sun Power"},{"t":5,"p":1,"n":"Water Properties - Reflectivity Amount"},{"t":5,"p":1,"n":"Water Properties - Fresnel Amount"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Fog Properties - Above Water - Fog Distance - Near Plane"},{"t":5,"p":1,"n":"Fog Properties - Above Water - Fog Distance - Far Plane"},{"t":6,"p":1,"n":"Shallow Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Deep Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Reflection Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Rain Simulator - Force"},{"t":5,"p":1,"n":"Rain Simulator - Velocity"},{"t":5,"p":1,"n":"Rain Simulator - Falloff"},{"t":5,"p":1,"n":"Rain Simulator - Dampner"},{"t":5,"p":1,"n":"Displacement Simulator - Starting Size"},{"t":5,"p":1,"n":"Displacement Simulator - Force"},{"t":5,"p":1,"n":"Displacement Simulator - Velocity"},{"t":5,"p":1,"n":"Displacement Simulator - Falloff"},{"t":5,"p":1,"n":"Displacement Simulator - Dampner"},{"t":5,"p":1,"n":"Rain Simulator - Starting Size"},{"t":5,"p":1,"n":"Noise Properties - Normals - Noise Scale"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer One - Wind Direction"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer Two - Wind Direction"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer Three - Wind Direction"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer One - Wind Speed"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer Two - Wind Speed"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer Three - Wind Speed"},{"t":5,"p":1,"n":"Noise Properties - Normals - Depth Falloff Start"},{"t":5,"p":1,"n":"Noise Properties - Normals - Depth Falloff End"},{"t":5,"p":1,"n":"Fog Properties - Above Water - Fog Amount"},{"t":5,"p":1,"n":"Noise Properties - Normals - UV Scale"},{"t":5,"p":1,"n":"Fog Properties - Under Water - Fog Amount"},{"t":5,"p":1,"n":"Fog Properties - Under Water - Fog Distance - Near Plane"},{"t":5,"p":1,"n":"Fog Properties - Under Water - Fog Distance - Far Plane"},{"t":5,"p":1,"n":"Water Properties - Distortion Amount"},{"t":5,"p":1,"n":"Water Properties - Shininess"},{"t":5,"p":1,"n":"Water Properties - Reflection HDR Multiplier"},{"t":5,"p":1,"n":"Water Properties - Light Radius"},{"t":5,"p":1,"n":"Water Properties - Light Brightness"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer One - UV Scale"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer Two - UV Scale"},{"t":5,"p":1,"n":"Noise Properties - Noise Layer Three - UV Scale"},{"p":1,"n":"Noise Properties - Noise Layer One - Amplitude Scale"},{"p":1,"n":"Noise Properties - Noise Layer Two - Amplitude Scale"},{"p":1,"n":"Noise Properties - Noise Layer Three - Amplitude Scale"},{"t":3,"p":1,"n":"Damage (Old Format)"}]},{"t":6,"n":"GNAM - Related Waters (Unused)","c":[{"t":3,"n":"Daytime"},{"t":3,"n":"Nighttime"},{"t":3,"n":"Underwater"}]}]},{"t":1,"p":1,"n":"WEAP - Weapon","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":3,"p":1,"n":"EITM - Object Effect"},{"t":3,"p":1,"n":"EAMT - Enchantment Charge Amount"},{"t":3,"p":1,"n":"NAM0 - Ammo"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"REPL - Repair List"},{"t":3,"p":1,"n":"ETYP - Equiptment Type"},{"t":3,"p":1,"n":"BIPL - Biped Model List"},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Drop"},{"t":6,"s":1,"p":1,"n":"Shell Casing Model","c":[{"t":2,"p":1,"n":"MOD2 - Model Filename"},{"t":11,"p":1,"n":"MO2T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO2S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Scope Model","c":[{"t":2,"p":1,"n":"MOD3 - Model Filename"},{"t":11,"p":1,"n":"MO3T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO3S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":3,"p":1,"n":"EFSD - Scope Effect"},{"t":6,"s":1,"p":1,"n":"World Model","c":[{"t":2,"p":1,"n":"MOD4 - Model Filename"},{"t":11,"p":1,"n":"MO4T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO4S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":2,"p":1,"n":"MWD1 - Model - Mod 1"},{"t":2,"p":1,"n":"MWD2 - Model - Mod 2"},{"t":2,"p":1,"n":"MWD3 - Model - Mod 1 and 2"},{"t":2,"p":1,"n":"MWD4 - Model - Mod 3"},{"t":2,"p":1,"n":"MWD5 - Model - Mod 1 and 3"},{"t":2,"p":1,"n":"MWD6 - Model - Mod 2 and 3"},{"t":2,"p":1,"n":"MWD7 - Model - Mod 1, 2 and 3"},{"t":2,"p":1,"n":"VANM - VATS Attack Name"},{"t":2,"p":1,"n":"NNAM - Embedded Weapon Node"},{"t":3,"p":1,"n":"INAM - Impact DataSet"},{"t":3,"p":1,"n":"WNAM - 1st Person Model"},{"t":3,"p":1,"n":"WNM1 - 1st Person Model - Mod 1"},{"t":3,"p":1,"n":"WNM2 - 1st Person Model - Mod 2"},{"t":3,"p":1,"n":"WNM3 - 1st Person Model - Mod 1 and 2"},{"t":3,"p":1,"n":"WNM4 - 1st Person Model - Mod 3"},{"t":3,"p":1,"n":"WNM5 - 1st Person Model - Mod 1 and 3"},{"t":3,"p":1,"n":"WNM6 - 1st Person Model - Mod 2 and 3"},{"t":3,"p":1,"n":"WNM7 - 1st Person Model - Mod 1, 2 and 3"},{"t":3,"p":1,"n":"WMI1 - Weapon Mod 1"},{"t":3,"p":1,"n":"WMI2 - Weapon Mod 2"},{"t":3,"p":1,"n":"WMI3 - Weapon Mod 3"},{"t":6,"s":1,"p":1,"n":"Sound - Gun","c":[{"t":3,"p":1,"n":"SNAM - Shoot 3D"},{"t":3,"p":1,"n":"SNAM - Shoot Dist"}]},{"t":3,"p":1,"n":"XNAM - Sound - Gun - Shoot 2D"},{"t":3,"p":1,"n":"NAM7 - Sound - Gun - Shoot 3D Looping"},{"t":3,"p":1,"n":"TNAM - Sound - Melee - Swing \/ Gun - No Ammo"},{"t":3,"p":1,"n":"NAM6 - Sound - Block"},{"t":3,"p":1,"n":"UNAM - Sound - Idle"},{"t":3,"p":1,"n":"NAM9 - Sound - Equip"},{"t":3,"p":1,"n":"NAM8 - Sound - Unequip"},{"t":6,"s":1,"p":1,"n":"Sound - Mod 1","c":[{"t":3,"p":1,"n":"WMS1 - Shoot 3D"},{"t":3,"p":1,"n":"WMS1 - Shoot Dist"}]},{"t":3,"p":1,"n":"WMS2 - Sound - Mod 1 - Shoot 2D"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Value"},{"t":3,"p":1,"n":"Health"},{"t":5,"p":1,"n":"Weight"},{"t":3,"p":1,"n":"Base Damage"},{"t":3,"p":1,"n":"Clip Size"}]},{"t":6,"s":1,"p":1,"n":"DNAM - ","c":[{"t":3,"p":1,"n":"Animation Type"},{"t":5,"p":1,"n":"Animation Multiplier"},{"t":5,"p":1,"n":"Reach"},{"t":3,"p":1,"n":"Flags 1"},{"t":3,"p":1,"n":"Grip Animation"},{"t":3,"p":1,"n":"Ammo Use"},{"t":3,"p":1,"n":"Reload Animation"},{"t":5,"p":1,"n":"Min Spread"},{"t":5,"p":1,"n":"Spread"},{"t":5,"n":"Unknown"},{"t":5,"p":1,"n":"Sight FOV"},{"t":3,"p":1,"n":"Projectile"},{"t":3,"p":1,"n":"Base VATS To-Hit Chance"},{"t":3,"p":1,"n":"Attack Animation"},{"t":3,"p":1,"n":"Projectile Count"},{"t":3,"p":1,"n":"Embedded Weapon - Actor Value"},{"t":5,"p":1,"n":"Min Range"},{"t":5,"p":1,"n":"Max Range"},{"t":3,"p":1,"n":"On Hit"},{"t":3,"p":1,"n":"Flags 2"},{"t":5,"p":1,"n":"Animation Attack Multiplier"},{"t":5,"p":1,"n":"Fire Rate"},{"t":5,"p":1,"n":"Override - Action Points"},{"t":5,"p":1,"n":"Rumble - Left Motor Strength"},{"t":5,"p":1,"n":"Rumble - Right Motor Strength"},{"t":5,"p":1,"n":"Rumble - Duration"},{"t":5,"p":1,"n":"Override - Damage to Weapon Mult"},{"t":5,"p":1,"n":"Attack Shots\/Sec"},{"t":5,"p":1,"n":"Reload Time"},{"t":5,"p":1,"n":"Jam Time"},{"t":5,"p":1,"n":"Aim Arc"},{"t":3,"p":1,"n":"Skill"},{"t":3,"p":1,"n":"Rumble - Pattern"},{"t":5,"p":1,"n":"Rumble - Wavelength"},{"t":5,"p":1,"n":"Limb Dmg Mult"},{"t":3,"p":1,"n":"Resist Type"},{"t":5,"p":1,"n":"Sight Usage"},{"t":5,"p":1,"n":"Semi-Automatic Fire Delay Min"},{"t":5,"p":1,"n":"Semi-Automatic Fire Delay Max"},{"t":3,"p":1,"n":"Effect - Mod 1"},{"t":3,"p":1,"n":"Effect - Mod 2"},{"t":3,"p":1,"n":"Effect - Mod 3"},{"t":5,"p":1,"n":"Value A - Mod 1"},{"t":5,"p":1,"n":"Value A - Mod 2"},{"t":5,"p":1,"n":"Value A - Mod 3"},{"t":3,"p":1,"n":"Power Attack Animation Override"},{"t":3,"p":1,"n":"Strength Req"},{"t":3,"p":1,"n":"Reload Animation - Mod"},{"t":5,"p":1,"n":"Regen Rate"},{"t":5,"p":1,"n":"Kill Impulse"},{"t":5,"p":1,"n":"Value B - Mod 1"},{"t":5,"p":1,"n":"Value B - Mod 2"},{"t":5,"p":1,"n":"Value B - Mod 3"},{"t":5,"p":1,"n":"Impulse Dist"},{"t":3,"p":1,"n":"Skill Req"}]},{"t":6,"s":1,"p":1,"n":"CRDT - Critical Data","c":[{"t":3,"p":1,"n":"Critical Damage"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Crit % Mult"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Effect"}]},{"t":6,"s":1,"p":1,"n":"VATS - VATS","c":[{"t":3,"p":1,"n":"Effect"},{"t":5,"p":1,"n":"Skill"},{"t":5,"p":1,"n":"Dam. Mult"},{"t":5,"p":1,"n":"AP"},{"t":3,"p":1,"n":"Silent"},{"t":3,"p":1,"n":"Mod Required"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"VNAM - Sound Level"}]},{"t":1,"p":1,"n":"WRLD - Worldspace","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":6,"s":1,"p":1,"n":"Parent","c":[{"t":3,"p":1,"n":"WNAM - Worldspace"},{"t":3,"p":1,"n":"PNAM - Flags"}]},{"t":3,"p":1,"n":"CNAM - Climate"},{"t":3,"p":1,"n":"NAM2 - Water"},{"t":3,"p":1,"n":"NAM3 - LOD Water Type"},{"t":5,"p":1,"n":"NAM4 - LOD Water Height"},{"t":6,"s":1,"p":1,"n":"DNAM - Land Data","c":[{"t":5,"p":1,"n":"Default Land Height"},{"t":5,"p":1,"n":"Default Water Height"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"MNAM - Map Data","c":[{"t":6,"p":1,"n":"Usable Dimensions","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"}]},{"t":6,"p":1,"n":"Cell Coordinates","c":[{"t":6,"p":1,"n":"NW Cell","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"}]},{"t":6,"p":1,"n":"SE Cell","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"}]}]}]},{"t":6,"s":1,"p":1,"n":"ONAM - World Map Offset Data","c":[{"t":5,"p":1,"n":"World Map Scale"},{"t":5,"p":1,"n":"Cell X Offset"},{"t":5,"p":1,"n":"Cell Y Offset"}]},{"t":3,"p":1,"n":"INAM - Image Space"},{"t":3,"p":1,"n":"DATA - Flags"},{"t":6,"s":1,"p":1,"n":"Object Bounds","c":[{"t":6,"p":1,"n":"NAM0 - Min","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"}]},{"t":6,"p":1,"n":"NAM9 - Max","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"}]}]},{"t":3,"p":1,"n":"ZNAM - Music"},{"t":2,"p":1,"n":"NNAM - Canopy Shadow"},{"t":2,"p":1,"n":"XNAM - Water Noise Texture"},{"t":8,"s":1,"p":1,"n":"Swapped Impacts","d":1,"c":[{"t":6,"p":1,"n":"IMPS - Swapped Impact","c":[{"t":3,"p":1,"n":"Material Type"},{"t":3,"p":1,"n":"Old"},{"t":3,"p":1,"n":"New"}]}]},{"t":7,"n":"IMPF - Footstep Materials","c":[{"t":2,"n":"Unknown"}]},{"t":11,"n":"OFST - Offset Data"}]},{"t":1,"p":1,"n":"WTHR - Weather","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"aIAD - Sunrise Image Space Modifier"},{"t":3,"p":1,"n":"bIAD - Day Image Space Modifier"},{"t":3,"p":1,"n":"cIAD - Sunset Image Space Modifier"},{"t":3,"p":1,"n":"dIAD - Night Image Space Modifier"},{"t":3,"n":"eIAD - Unknown"},{"t":3,"n":"fIAD - Unknown"},{"t":2,"p":1,"n":"DNAM - Cloud Textures - Layer 0"},{"t":2,"p":1,"n":"CNAM - Cloud Textures - Layer 1"},{"t":2,"p":1,"n":"ANAM - Cloud Textures - Layer 2"},{"t":2,"p":1,"n":"BNAM - Cloud Textures - Layer 3"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"n":"MODB - Unknown"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]},{"t":3,"p":1,"n":"MODD - FaceGen Model Flags"}]},{"t":11,"n":"LNAM - Unknown"},{"t":7,"p":1,"n":"ONAM - Cloud Speed","c":[{"t":3,"p":1,"n":"Layer"}]},{"t":7,"p":1,"n":"PNAM - Cloud Layer Colors","c":[{"t":7,"p":1,"n":"Layer","c":[{"t":6,"p":1,"n":"Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]}]},{"t":7,"p":1,"n":"NAM0 - Colors by Types\/Times","c":[{"t":7,"p":1,"n":"Type","c":[{"t":6,"p":1,"n":"Time","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]}]},{"t":6,"s":1,"p":1,"n":"FNAM - Fog Distance","c":[{"t":5,"p":1,"n":"Day - Near"},{"t":5,"p":1,"n":"Day - Far"},{"t":5,"p":1,"n":"Night - Near"},{"t":5,"p":1,"n":"Night - Far"},{"t":5,"p":1,"n":"Day - Power"},{"t":5,"p":1,"n":"Night - Fower"}]},{"t":11,"n":"INAM - Unused"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Wind Speed"},{"t":3,"p":1,"n":"Cloud Speed (Lower)"},{"t":3,"p":1,"n":"Cloud Speed (Upper)"},{"t":3,"p":1,"n":"Trans Delta"},{"t":3,"p":1,"n":"Sun Glare"},{"t":3,"p":1,"n":"Sun Damage"},{"t":3,"p":1,"n":"Precipitation - Begin Fade In"},{"t":3,"p":1,"n":"Precipitation - End Fade Out"},{"t":3,"p":1,"n":"Thunder\/Lightning - Begin Fade In"},{"t":3,"p":1,"n":"Thunder\/Lightning - End Fade Out"},{"t":3,"p":1,"n":"Thunder\/Lightning - Frequency"},{"t":3,"p":1,"n":"Weather Classification"},{"t":6,"p":1,"n":"Lightning Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"}]}]},{"t":8,"s":1,"p":1,"n":"Sounds","d":1,"c":[{"t":6,"p":1,"n":"SNAM - Sound","c":[{"t":3,"p":1,"n":"Sound"},{"t":3,"p":1,"n":"Type"}]}]}]},{"t":1,"p":1,"n":"ACRE - Placed Creature","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"NAME - Base"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":11,"n":"XRGD - Ragdoll Data"},{"t":11,"n":"XRGB - Ragdoll Biped Data"},{"t":6,"s":1,"p":1,"n":"Patrol Data","c":[{"t":5,"p":1,"n":"XPRD - Idle Time"},{"p":1,"n":"XPPA - Patrol Script Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":6,"p":1,"n":"Embedded Script","c":[{"t":6,"p":1,"n":"SCHR - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"p":1,"n":"SCDA - Compiled Embedded Script"},{"t":2,"p":1,"n":"SCTX - Embedded Script Source"},{"t":10,"p":1,"n":"Local Variables","c":[{"t":6,"p":1,"n":"Local Variable","c":[{"t":6,"p":1,"n":"SLSD - Local Variable Data","c":[{"t":3,"p":1,"n":"Index"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"SCVR - Name"}]}]},{"t":8,"p":1,"n":"References","c":[{"t":3,"p":1,"n":"SCRO - Global Reference"},{"t":3,"p":1,"n":"SCRV - Local Variable"}]}]},{"t":3,"p":1,"n":"TNAM - Topic"}]},{"t":3,"p":1,"n":"XLCM - Level Modifier"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":3,"p":1,"n":"XMRC - Merchant Container"},{"t":3,"p":1,"n":"XCNT - Count"},{"t":5,"p":1,"n":"XRDS - Radius"},{"t":5,"p":1,"n":"XHLP - Health"},{"t":8,"s":1,"p":1,"n":"Linked Decals","d":1,"c":[{"t":6,"p":1,"n":"XDCR - Decal","c":[{"t":3,"p":1,"n":"Reference"},{"t":11,"n":"Unknown"}]}]},{"t":3,"p":1,"n":"XLKR - Linked Reference"},{"t":6,"s":1,"p":1,"n":"XCLP - Linked Reference Color","c":[{"t":6,"p":1,"n":"Link Start Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Link End Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":2,"p":1,"n":"XATO - Activation Prompt"},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIBS - Ignored By Sandbox"},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]}]},"name":"Smash.All","hash":"522394C0","color":128} ================================================ FILE: frontend/settings/Oblivion/Bash.Actors.ACBS.json ================================================ {"records":"NPC_,CREA","description":"Actors.ACBS tag from Wrye Bash.\r\n\r\nUsed when the mod modifies NPC ACBS configuration.","tree":{"records":[{"t":1,"p":1,"n":"NPC_ - Non-Player Character","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":6,"s":1,"p":1,"n":"ACBS - Configuration","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Base spell points"},{"t":3,"p":1,"n":"Fatigue"},{"t":3,"p":1,"n":"Barter gold"},{"t":3,"p":1,"n":"Level (offset)"},{"t":3,"p":1,"n":"Calc min"},{"t":3,"p":1,"n":"Calc max"}]},{"t":8,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"RNAM - Race"},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Buys\/Sells and Services"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":8,"n":"AI Packages","c":[{"t":3,"n":"PKID - AI Package"}]},{"t":7,"n":"KFFZ - Animations","c":[{"t":2,"n":"Animation"}]},{"t":3,"n":"CNAM - Class"},{"t":6,"n":"DATA - Stats","c":[{"t":3,"n":"Armorer"},{"t":3,"n":"Athletics"},{"t":3,"n":"Blade"},{"t":3,"n":"Block"},{"t":3,"n":"Blunt"},{"t":3,"n":"Hand to Hand"},{"t":3,"n":"Heavy Armor"},{"t":3,"n":"Alchemy"},{"t":3,"n":"Alteration"},{"t":3,"n":"Conjuration"},{"t":3,"n":"Destruction"},{"t":3,"n":"Illusion"},{"t":3,"n":"Mysticism"},{"t":3,"n":"Restoration"},{"t":3,"n":"Acrobatics"},{"t":3,"n":"Light Armor"},{"t":3,"n":"Marksman"},{"t":3,"n":"Mercantile"},{"t":3,"n":"Security"},{"t":3,"n":"Sneak"},{"t":3,"n":"Speechcraft"},{"t":3,"n":"Health"},{"t":11,"n":"Unused"},{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":3,"n":"HNAM - Hair"},{"t":5,"n":"LNAM - Hair length"},{"t":7,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eyes"}]},{"t":6,"n":"HCLR - Hair color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":3,"n":"ZNAM - Combat Style"},{"t":6,"n":"FaceGen Data","c":[{"t":11,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"n":"FNAM - Unknown"}]},{"t":1,"p":1,"n":"CREA - Creature","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":7,"n":"NIFZ - Models","c":[{"t":2,"n":"Model"}]},{"t":11,"n":"NIFT - Texture Files Hashes"},{"t":6,"s":1,"p":1,"n":"ACBS - Configuration","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Base spell points"},{"t":3,"p":1,"n":"Fatigue"},{"t":3,"p":1,"n":"Barter gold"},{"t":3,"p":1,"n":"Level (offset)"},{"t":3,"p":1,"n":"Calc min"},{"t":3,"p":1,"n":"Calc max"}]},{"t":8,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Buys\/Sells and Services"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":8,"n":"AI Packages","c":[{"t":3,"n":"PKID - AI Package"}]},{"t":7,"n":"KFFZ - Animations","c":[{"t":2,"n":"Animation"}]},{"t":6,"n":"DATA - Creature Data","c":[{"t":3,"n":"Type"},{"t":3,"n":"Combat Skill"},{"t":3,"n":"Magic Skill"},{"t":3,"n":"Stealth Skill"},{"t":3,"n":"Soul"},{"t":11,"n":"Unused"},{"t":3,"n":"Health"},{"t":3,"n":"Attack Damage"},{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":3,"n":"RNAM - Attack reach"},{"t":3,"n":"ZNAM - Combat Style"},{"t":5,"n":"TNAM - Turning Speed"},{"t":5,"n":"BNAM - Base Scale"},{"t":5,"n":"WNAM - Foot Weight"},{"t":2,"n":"NAM0 - Blood Spray"},{"t":2,"n":"NAM1 - Blood Decal"},{"t":3,"n":"CSCR - Inherits Sounds from"},{"t":10,"n":"Sound Types","c":[{"t":6,"n":"Sound Type","c":[{"t":3,"n":"CSDT - Type"},{"t":10,"n":"Sounds","c":[{"t":6,"n":"Sound","c":[{"t":3,"n":"CSDI - Sound"},{"t":3,"n":"CSDC - Sound Chance"}]}]}]}]}]}]},"name":"Bash.Actors.ACBS","hash":"0AE1EBDE","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.Actors.AIData.json ================================================ {"records":"NPC_,CREA","description":"Actors.AIData tag from Wrye Bash.\r\n\r\nUsed when the mod modifies NPC AI data.","tree":{"records":[{"t":1,"p":1,"n":"NPC_ - Non-Player Character","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Base spell points"},{"t":3,"n":"Fatigue"},{"t":3,"n":"Barter gold"},{"t":3,"n":"Level (offset)"},{"t":3,"n":"Calc min"},{"t":3,"n":"Calc max"}]},{"t":8,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"RNAM - Race"},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":3,"n":"SCRI - Script"},{"t":6,"s":1,"p":1,"n":"AIDT - AI Data","c":[{"t":3,"p":1,"n":"Aggression"},{"t":3,"p":1,"n":"Confidence"},{"t":3,"p":1,"n":"Energy Level"},{"t":3,"p":1,"n":"Responsibility"},{"t":3,"p":1,"n":"Buys\/Sells and Services"},{"t":3,"p":1,"n":"Teaches"},{"t":3,"p":1,"n":"Maximum training level"},{"t":11,"p":1,"n":"Unused"}]},{"t":8,"n":"AI Packages","c":[{"t":3,"n":"PKID - AI Package"}]},{"t":7,"n":"KFFZ - Animations","c":[{"t":2,"n":"Animation"}]},{"t":3,"n":"CNAM - Class"},{"t":6,"n":"DATA - Stats","c":[{"t":3,"n":"Armorer"},{"t":3,"n":"Athletics"},{"t":3,"n":"Blade"},{"t":3,"n":"Block"},{"t":3,"n":"Blunt"},{"t":3,"n":"Hand to Hand"},{"t":3,"n":"Heavy Armor"},{"t":3,"n":"Alchemy"},{"t":3,"n":"Alteration"},{"t":3,"n":"Conjuration"},{"t":3,"n":"Destruction"},{"t":3,"n":"Illusion"},{"t":3,"n":"Mysticism"},{"t":3,"n":"Restoration"},{"t":3,"n":"Acrobatics"},{"t":3,"n":"Light Armor"},{"t":3,"n":"Marksman"},{"t":3,"n":"Mercantile"},{"t":3,"n":"Security"},{"t":3,"n":"Sneak"},{"t":3,"n":"Speechcraft"},{"t":3,"n":"Health"},{"t":11,"n":"Unused"},{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":3,"n":"HNAM - Hair"},{"t":5,"n":"LNAM - Hair length"},{"t":7,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eyes"}]},{"t":6,"n":"HCLR - Hair color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":3,"n":"ZNAM - Combat Style"},{"t":6,"n":"FaceGen Data","c":[{"t":11,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"n":"FNAM - Unknown"}]},{"t":1,"p":1,"n":"CREA - Creature","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":7,"n":"NIFZ - Models","c":[{"t":2,"n":"Model"}]},{"t":11,"n":"NIFT - Texture Files Hashes"},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Base spell points"},{"t":3,"n":"Fatigue"},{"t":3,"n":"Barter gold"},{"t":3,"n":"Level (offset)"},{"t":3,"n":"Calc min"},{"t":3,"n":"Calc max"}]},{"t":8,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"SCRI - Script"},{"t":6,"s":1,"p":1,"n":"AIDT - AI Data","c":[{"t":3,"p":1,"n":"Aggression"},{"t":3,"p":1,"n":"Confidence"},{"t":3,"p":1,"n":"Energy Level"},{"t":3,"p":1,"n":"Responsibility"},{"t":3,"p":1,"n":"Buys\/Sells and Services"},{"t":3,"p":1,"n":"Teaches"},{"t":3,"p":1,"n":"Maximum training level"},{"t":11,"p":1,"n":"Unused"}]},{"t":8,"n":"AI Packages","c":[{"t":3,"n":"PKID - AI Package"}]},{"t":7,"n":"KFFZ - Animations","c":[{"t":2,"n":"Animation"}]},{"t":6,"n":"DATA - Creature Data","c":[{"t":3,"n":"Type"},{"t":3,"n":"Combat Skill"},{"t":3,"n":"Magic Skill"},{"t":3,"n":"Stealth Skill"},{"t":3,"n":"Soul"},{"t":11,"n":"Unused"},{"t":3,"n":"Health"},{"t":3,"n":"Attack Damage"},{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":3,"n":"RNAM - Attack reach"},{"t":3,"n":"ZNAM - Combat Style"},{"t":5,"n":"TNAM - Turning Speed"},{"t":5,"n":"BNAM - Base Scale"},{"t":5,"n":"WNAM - Foot Weight"},{"t":2,"n":"NAM0 - Blood Spray"},{"t":2,"n":"NAM1 - Blood Decal"},{"t":3,"n":"CSCR - Inherits Sounds from"},{"t":10,"n":"Sound Types","c":[{"t":6,"n":"Sound Type","c":[{"t":3,"n":"CSDT - Type"},{"t":10,"n":"Sounds","c":[{"t":6,"n":"Sound","c":[{"t":3,"n":"CSDI - Sound"},{"t":3,"n":"CSDC - Sound Chance"}]}]}]}]}]}]},"name":"Bash.Actors.AIData","hash":"20E41AEA","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.Actors.AIPackages.json ================================================ {"records":"NPC_,CREA","description":"Actors.AIPackages tag from Wrye Bash.\r\n\r\nUsed when the mod modifies NPC AI packages list.","tree":{"records":[{"t":1,"p":1,"n":"NPC_ - Non-Player Character","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Base spell points"},{"t":3,"n":"Fatigue"},{"t":3,"n":"Barter gold"},{"t":3,"n":"Level (offset)"},{"t":3,"n":"Calc min"},{"t":3,"n":"Calc max"}]},{"t":8,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"RNAM - Race"},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Buys\/Sells and Services"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"AI Packages","d":1,"c":[{"t":3,"p":1,"n":"PKID - AI Package"}]},{"t":7,"n":"KFFZ - Animations","c":[{"t":2,"n":"Animation"}]},{"t":3,"n":"CNAM - Class"},{"t":6,"n":"DATA - Stats","c":[{"t":3,"n":"Armorer"},{"t":3,"n":"Athletics"},{"t":3,"n":"Blade"},{"t":3,"n":"Block"},{"t":3,"n":"Blunt"},{"t":3,"n":"Hand to Hand"},{"t":3,"n":"Heavy Armor"},{"t":3,"n":"Alchemy"},{"t":3,"n":"Alteration"},{"t":3,"n":"Conjuration"},{"t":3,"n":"Destruction"},{"t":3,"n":"Illusion"},{"t":3,"n":"Mysticism"},{"t":3,"n":"Restoration"},{"t":3,"n":"Acrobatics"},{"t":3,"n":"Light Armor"},{"t":3,"n":"Marksman"},{"t":3,"n":"Mercantile"},{"t":3,"n":"Security"},{"t":3,"n":"Sneak"},{"t":3,"n":"Speechcraft"},{"t":3,"n":"Health"},{"t":11,"n":"Unused"},{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":3,"n":"HNAM - Hair"},{"t":5,"n":"LNAM - Hair length"},{"t":7,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eyes"}]},{"t":6,"n":"HCLR - Hair color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":3,"n":"ZNAM - Combat Style"},{"t":6,"n":"FaceGen Data","c":[{"t":11,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"n":"FNAM - Unknown"}]},{"t":1,"p":1,"n":"CREA - Creature","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":7,"n":"NIFZ - Models","c":[{"t":2,"n":"Model"}]},{"t":11,"n":"NIFT - Texture Files Hashes"},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Base spell points"},{"t":3,"n":"Fatigue"},{"t":3,"n":"Barter gold"},{"t":3,"n":"Level (offset)"},{"t":3,"n":"Calc min"},{"t":3,"n":"Calc max"}]},{"t":8,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Buys\/Sells and Services"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"AI Packages","d":1,"c":[{"t":3,"p":1,"n":"PKID - AI Package"}]},{"t":7,"n":"KFFZ - Animations","c":[{"t":2,"n":"Animation"}]},{"t":6,"n":"DATA - Creature Data","c":[{"t":3,"n":"Type"},{"t":3,"n":"Combat Skill"},{"t":3,"n":"Magic Skill"},{"t":3,"n":"Stealth Skill"},{"t":3,"n":"Soul"},{"t":11,"n":"Unused"},{"t":3,"n":"Health"},{"t":3,"n":"Attack Damage"},{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":3,"n":"RNAM - Attack reach"},{"t":3,"n":"ZNAM - Combat Style"},{"t":5,"n":"TNAM - Turning Speed"},{"t":5,"n":"BNAM - Base Scale"},{"t":5,"n":"WNAM - Foot Weight"},{"t":2,"n":"NAM0 - Blood Spray"},{"t":2,"n":"NAM1 - Blood Decal"},{"t":3,"n":"CSCR - Inherits Sounds from"},{"t":10,"n":"Sound Types","c":[{"t":6,"n":"Sound Type","c":[{"t":3,"n":"CSDT - Type"},{"t":10,"n":"Sounds","c":[{"t":6,"n":"Sound","c":[{"t":3,"n":"CSDI - Sound"},{"t":3,"n":"CSDC - Sound Chance"}]}]}]}]}]}]},"name":"Bash.Actors.AIPackages","hash":"D1B8291B","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.Actors.Animations.json ================================================ {"records":"NPC_,CREA","description":"Actors.Animations tag from Wrye Bash.\r\n\r\nUsed when the mod modifies creature or NPC special animations lists.","tree":{"records":[{"t":1,"p":1,"n":"NPC_ - Non-Player Character","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Base spell points"},{"t":3,"n":"Fatigue"},{"t":3,"n":"Barter gold"},{"t":3,"n":"Level (offset)"},{"t":3,"n":"Calc min"},{"t":3,"n":"Calc max"}]},{"t":8,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"RNAM - Race"},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Buys\/Sells and Services"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":8,"n":"AI Packages","c":[{"t":3,"n":"PKID - AI Package"}]},{"t":7,"s":1,"p":1,"n":"KFFZ - Animations","c":[{"t":2,"p":1,"n":"Animation"}]},{"t":3,"n":"CNAM - Class"},{"t":6,"n":"DATA - Stats","c":[{"t":3,"n":"Armorer"},{"t":3,"n":"Athletics"},{"t":3,"n":"Blade"},{"t":3,"n":"Block"},{"t":3,"n":"Blunt"},{"t":3,"n":"Hand to Hand"},{"t":3,"n":"Heavy Armor"},{"t":3,"n":"Alchemy"},{"t":3,"n":"Alteration"},{"t":3,"n":"Conjuration"},{"t":3,"n":"Destruction"},{"t":3,"n":"Illusion"},{"t":3,"n":"Mysticism"},{"t":3,"n":"Restoration"},{"t":3,"n":"Acrobatics"},{"t":3,"n":"Light Armor"},{"t":3,"n":"Marksman"},{"t":3,"n":"Mercantile"},{"t":3,"n":"Security"},{"t":3,"n":"Sneak"},{"t":3,"n":"Speechcraft"},{"t":3,"n":"Health"},{"t":11,"n":"Unused"},{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":3,"n":"HNAM - Hair"},{"t":5,"n":"LNAM - Hair length"},{"t":7,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eyes"}]},{"t":6,"n":"HCLR - Hair color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":3,"n":"ZNAM - Combat Style"},{"t":6,"n":"FaceGen Data","c":[{"t":11,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"n":"FNAM - Unknown"}]},{"t":1,"p":1,"n":"CREA - Creature","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":7,"n":"NIFZ - Models","c":[{"t":2,"n":"Model"}]},{"t":11,"n":"NIFT - Texture Files Hashes"},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Base spell points"},{"t":3,"n":"Fatigue"},{"t":3,"n":"Barter gold"},{"t":3,"n":"Level (offset)"},{"t":3,"n":"Calc min"},{"t":3,"n":"Calc max"}]},{"t":8,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Buys\/Sells and Services"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":8,"n":"AI Packages","c":[{"t":3,"n":"PKID - AI Package"}]},{"t":7,"s":1,"p":1,"n":"KFFZ - Animations","c":[{"t":2,"p":1,"n":"Animation"}]},{"t":6,"n":"DATA - Creature Data","c":[{"t":3,"n":"Type"},{"t":3,"n":"Combat Skill"},{"t":3,"n":"Magic Skill"},{"t":3,"n":"Stealth Skill"},{"t":3,"n":"Soul"},{"t":11,"n":"Unused"},{"t":3,"n":"Health"},{"t":3,"n":"Attack Damage"},{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":3,"n":"RNAM - Attack reach"},{"t":3,"n":"ZNAM - Combat Style"},{"t":5,"n":"TNAM - Turning Speed"},{"t":5,"n":"BNAM - Base Scale"},{"t":5,"n":"WNAM - Foot Weight"},{"t":2,"n":"NAM0 - Blood Spray"},{"t":2,"n":"NAM1 - Blood Decal"},{"t":3,"n":"CSCR - Inherits Sounds from"},{"t":10,"n":"Sound Types","c":[{"t":6,"n":"Sound Type","c":[{"t":3,"n":"CSDT - Type"},{"t":10,"n":"Sounds","c":[{"t":6,"n":"Sound","c":[{"t":3,"n":"CSDI - Sound"},{"t":3,"n":"CSDC - Sound Chance"}]}]}]}]}]}]},"name":"Bash.Actors.Animations","hash":"F1DB25EA","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.Actors.CombatStyle.json ================================================ {"records":"NPC_,CREA","description":"Actors.CombatStyle tag from Wrye Bash.\r\n\r\nUsed when the mod modifies NPC combat styles.","tree":{"records":[{"t":1,"p":1,"n":"NPC_ - Non-Player Character","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Base spell points"},{"t":3,"n":"Fatigue"},{"t":3,"n":"Barter gold"},{"t":3,"n":"Level (offset)"},{"t":3,"n":"Calc min"},{"t":3,"n":"Calc max"}]},{"t":8,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"RNAM - Race"},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Buys\/Sells and Services"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":8,"n":"AI Packages","c":[{"t":3,"n":"PKID - AI Package"}]},{"t":7,"n":"KFFZ - Animations","c":[{"t":2,"n":"Animation"}]},{"t":3,"n":"CNAM - Class"},{"t":6,"n":"DATA - Stats","c":[{"t":3,"n":"Armorer"},{"t":3,"n":"Athletics"},{"t":3,"n":"Blade"},{"t":3,"n":"Block"},{"t":3,"n":"Blunt"},{"t":3,"n":"Hand to Hand"},{"t":3,"n":"Heavy Armor"},{"t":3,"n":"Alchemy"},{"t":3,"n":"Alteration"},{"t":3,"n":"Conjuration"},{"t":3,"n":"Destruction"},{"t":3,"n":"Illusion"},{"t":3,"n":"Mysticism"},{"t":3,"n":"Restoration"},{"t":3,"n":"Acrobatics"},{"t":3,"n":"Light Armor"},{"t":3,"n":"Marksman"},{"t":3,"n":"Mercantile"},{"t":3,"n":"Security"},{"t":3,"n":"Sneak"},{"t":3,"n":"Speechcraft"},{"t":3,"n":"Health"},{"t":11,"n":"Unused"},{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":3,"n":"HNAM - Hair"},{"t":5,"n":"LNAM - Hair length"},{"t":7,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eyes"}]},{"t":6,"n":"HCLR - Hair color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"ZNAM - Combat Style"},{"t":6,"n":"FaceGen Data","c":[{"t":11,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"n":"FNAM - Unknown"}]},{"t":1,"p":1,"n":"CREA - Creature","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":7,"n":"NIFZ - Models","c":[{"t":2,"n":"Model"}]},{"t":11,"n":"NIFT - Texture Files Hashes"},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Base spell points"},{"t":3,"n":"Fatigue"},{"t":3,"n":"Barter gold"},{"t":3,"n":"Level (offset)"},{"t":3,"n":"Calc min"},{"t":3,"n":"Calc max"}]},{"t":8,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Buys\/Sells and Services"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":8,"n":"AI Packages","c":[{"t":3,"n":"PKID - AI Package"}]},{"t":7,"n":"KFFZ - Animations","c":[{"t":2,"n":"Animation"}]},{"t":6,"n":"DATA - Creature Data","c":[{"t":3,"n":"Type"},{"t":3,"n":"Combat Skill"},{"t":3,"n":"Magic Skill"},{"t":3,"n":"Stealth Skill"},{"t":3,"n":"Soul"},{"t":11,"n":"Unused"},{"t":3,"n":"Health"},{"t":3,"n":"Attack Damage"},{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":3,"n":"RNAM - Attack reach"},{"t":3,"p":1,"n":"ZNAM - Combat Style"},{"t":5,"n":"TNAM - Turning Speed"},{"t":5,"n":"BNAM - Base Scale"},{"t":5,"n":"WNAM - Foot Weight"},{"t":2,"n":"NAM0 - Blood Spray"},{"t":2,"n":"NAM1 - Blood Decal"},{"t":3,"n":"CSCR - Inherits Sounds from"},{"t":10,"n":"Sound Types","c":[{"t":6,"n":"Sound Type","c":[{"t":3,"n":"CSDT - Type"},{"t":10,"n":"Sounds","c":[{"t":6,"n":"Sound","c":[{"t":3,"n":"CSDI - Sound"},{"t":3,"n":"CSDC - Sound Chance"}]}]}]}]}]}]},"name":"Bash.Actors.CombatStyle","hash":"6815F8AC","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.Actors.DeathItem.json ================================================ {"records":"NPC_,CREA","description":"Actors.DeathItem tag from Wrye Bash.\r\n\r\nUsed when the mod modifies creature or NPC death items.","tree":{"records":[{"t":1,"p":1,"n":"NPC_ - Non-Player Character","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Base spell points"},{"t":3,"n":"Fatigue"},{"t":3,"n":"Barter gold"},{"t":3,"n":"Level (offset)"},{"t":3,"n":"Calc min"},{"t":3,"n":"Calc max"}]},{"t":8,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"p":1,"n":"INAM - Death item"},{"t":3,"n":"RNAM - Race"},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Buys\/Sells and Services"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":8,"n":"AI Packages","c":[{"t":3,"n":"PKID - AI Package"}]},{"t":7,"n":"KFFZ - Animations","c":[{"t":2,"n":"Animation"}]},{"t":3,"n":"CNAM - Class"},{"t":6,"n":"DATA - Stats","c":[{"t":3,"n":"Armorer"},{"t":3,"n":"Athletics"},{"t":3,"n":"Blade"},{"t":3,"n":"Block"},{"t":3,"n":"Blunt"},{"t":3,"n":"Hand to Hand"},{"t":3,"n":"Heavy Armor"},{"t":3,"n":"Alchemy"},{"t":3,"n":"Alteration"},{"t":3,"n":"Conjuration"},{"t":3,"n":"Destruction"},{"t":3,"n":"Illusion"},{"t":3,"n":"Mysticism"},{"t":3,"n":"Restoration"},{"t":3,"n":"Acrobatics"},{"t":3,"n":"Light Armor"},{"t":3,"n":"Marksman"},{"t":3,"n":"Mercantile"},{"t":3,"n":"Security"},{"t":3,"n":"Sneak"},{"t":3,"n":"Speechcraft"},{"t":3,"n":"Health"},{"t":11,"n":"Unused"},{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":3,"n":"HNAM - Hair"},{"t":5,"n":"LNAM - Hair length"},{"t":7,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eyes"}]},{"t":6,"n":"HCLR - Hair color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":3,"n":"ZNAM - Combat Style"},{"t":6,"n":"FaceGen Data","c":[{"t":11,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"n":"FNAM - Unknown"}]},{"t":1,"p":1,"n":"CREA - Creature","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":7,"n":"NIFZ - Models","c":[{"t":2,"n":"Model"}]},{"t":11,"n":"NIFT - Texture Files Hashes"},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Base spell points"},{"t":3,"n":"Fatigue"},{"t":3,"n":"Barter gold"},{"t":3,"n":"Level (offset)"},{"t":3,"n":"Calc min"},{"t":3,"n":"Calc max"}]},{"t":8,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"p":1,"n":"INAM - Death item"},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Buys\/Sells and Services"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":8,"n":"AI Packages","c":[{"t":3,"n":"PKID - AI Package"}]},{"t":7,"n":"KFFZ - Animations","c":[{"t":2,"n":"Animation"}]},{"t":6,"n":"DATA - Creature Data","c":[{"t":3,"n":"Type"},{"t":3,"n":"Combat Skill"},{"t":3,"n":"Magic Skill"},{"t":3,"n":"Stealth Skill"},{"t":3,"n":"Soul"},{"t":11,"n":"Unused"},{"t":3,"n":"Health"},{"t":3,"n":"Attack Damage"},{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":3,"n":"RNAM - Attack reach"},{"t":3,"n":"ZNAM - Combat Style"},{"t":5,"n":"TNAM - Turning Speed"},{"t":5,"n":"BNAM - Base Scale"},{"t":5,"n":"WNAM - Foot Weight"},{"t":2,"n":"NAM0 - Blood Spray"},{"t":2,"n":"NAM1 - Blood Decal"},{"t":3,"n":"CSCR - Inherits Sounds from"},{"t":10,"n":"Sound Types","c":[{"t":6,"n":"Sound Type","c":[{"t":3,"n":"CSDT - Type"},{"t":10,"n":"Sounds","c":[{"t":6,"n":"Sound","c":[{"t":3,"n":"CSDI - Sound"},{"t":3,"n":"CSDC - Sound Chance"}]}]}]}]}]}]},"name":"Bash.Actors.DeathItem","hash":"DAECBF12","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.Actors.Skeleton.json ================================================ {"records":"NPC_,CREA","description":"Actors.Skeleton from Wrye Bash.\r\n\r\nUsed when the mod modifies creature or NPC skeletons.","tree":{"records":[{"t":1,"p":1,"n":"NPC_ - Non-Player Character","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Base spell points"},{"t":3,"n":"Fatigue"},{"t":3,"n":"Barter gold"},{"t":3,"n":"Level (offset)"},{"t":3,"n":"Calc min"},{"t":3,"n":"Calc max"}]},{"t":8,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"RNAM - Race"},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Buys\/Sells and Services"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":8,"n":"AI Packages","c":[{"t":3,"n":"PKID - AI Package"}]},{"t":7,"n":"KFFZ - Animations","c":[{"t":2,"n":"Animation"}]},{"t":3,"n":"CNAM - Class"},{"t":6,"n":"DATA - Stats","c":[{"t":3,"n":"Armorer"},{"t":3,"n":"Athletics"},{"t":3,"n":"Blade"},{"t":3,"n":"Block"},{"t":3,"n":"Blunt"},{"t":3,"n":"Hand to Hand"},{"t":3,"n":"Heavy Armor"},{"t":3,"n":"Alchemy"},{"t":3,"n":"Alteration"},{"t":3,"n":"Conjuration"},{"t":3,"n":"Destruction"},{"t":3,"n":"Illusion"},{"t":3,"n":"Mysticism"},{"t":3,"n":"Restoration"},{"t":3,"n":"Acrobatics"},{"t":3,"n":"Light Armor"},{"t":3,"n":"Marksman"},{"t":3,"n":"Mercantile"},{"t":3,"n":"Security"},{"t":3,"n":"Sneak"},{"t":3,"n":"Speechcraft"},{"t":3,"n":"Health"},{"t":11,"n":"Unused"},{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":3,"n":"HNAM - Hair"},{"t":5,"n":"LNAM - Hair length"},{"t":7,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eyes"}]},{"t":6,"n":"HCLR - Hair color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":3,"n":"ZNAM - Combat Style"},{"t":6,"n":"FaceGen Data","c":[{"t":11,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"n":"FNAM - Unknown"}]},{"t":1,"p":1,"n":"CREA - Creature","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":7,"n":"NIFZ - Models","c":[{"t":2,"n":"Model"}]},{"t":11,"n":"NIFT - Texture Files Hashes"},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Base spell points"},{"t":3,"n":"Fatigue"},{"t":3,"n":"Barter gold"},{"t":3,"n":"Level (offset)"},{"t":3,"n":"Calc min"},{"t":3,"n":"Calc max"}]},{"t":8,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Buys\/Sells and Services"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":8,"n":"AI Packages","c":[{"t":3,"n":"PKID - AI Package"}]},{"t":7,"n":"KFFZ - Animations","c":[{"t":2,"n":"Animation"}]},{"t":6,"n":"DATA - Creature Data","c":[{"t":3,"n":"Type"},{"t":3,"n":"Combat Skill"},{"t":3,"n":"Magic Skill"},{"t":3,"n":"Stealth Skill"},{"t":3,"n":"Soul"},{"t":11,"n":"Unused"},{"t":3,"n":"Health"},{"t":3,"n":"Attack Damage"},{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":3,"n":"RNAM - Attack reach"},{"t":3,"n":"ZNAM - Combat Style"},{"t":5,"n":"TNAM - Turning Speed"},{"t":5,"n":"BNAM - Base Scale"},{"t":5,"n":"WNAM - Foot Weight"},{"t":2,"n":"NAM0 - Blood Spray"},{"t":2,"n":"NAM1 - Blood Decal"},{"t":3,"n":"CSCR - Inherits Sounds from"},{"t":10,"n":"Sound Types","c":[{"t":6,"n":"Sound Type","c":[{"t":3,"n":"CSDT - Type"},{"t":10,"n":"Sounds","c":[{"t":6,"n":"Sound","c":[{"t":3,"n":"CSDI - Sound"},{"t":3,"n":"CSDC - Sound Chance"}]}]}]}]}]}]},"name":"Bash.Actors.Skeleton","hash":"FCEBB959","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.Actors.Spells.json ================================================ {"records":"NPC_,CREA","description":"Actors.Spells tag from Wrye Bash.\r\n\r\nUse when the mod modifies creature or NPC spell lists.","tree":{"records":[{"t":1,"p":1,"n":"NPC_ - Non-Player Character","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Base spell points"},{"t":3,"n":"Fatigue"},{"t":3,"n":"Barter gold"},{"t":3,"n":"Level (offset)"},{"t":3,"n":"Calc min"},{"t":3,"n":"Calc max"}]},{"t":8,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"RNAM - Race"},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":8,"p":1,"n":"Spells","d":1,"c":[{"t":3,"p":1,"n":"SPLO - Spell"}]},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Buys\/Sells and Services"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":8,"n":"AI Packages","c":[{"t":3,"n":"PKID - AI Package"}]},{"t":7,"n":"KFFZ - Animations","c":[{"t":2,"n":"Animation"}]},{"t":3,"n":"CNAM - Class"},{"t":6,"n":"DATA - Stats","c":[{"t":3,"n":"Armorer"},{"t":3,"n":"Athletics"},{"t":3,"n":"Blade"},{"t":3,"n":"Block"},{"t":3,"n":"Blunt"},{"t":3,"n":"Hand to Hand"},{"t":3,"n":"Heavy Armor"},{"t":3,"n":"Alchemy"},{"t":3,"n":"Alteration"},{"t":3,"n":"Conjuration"},{"t":3,"n":"Destruction"},{"t":3,"n":"Illusion"},{"t":3,"n":"Mysticism"},{"t":3,"n":"Restoration"},{"t":3,"n":"Acrobatics"},{"t":3,"n":"Light Armor"},{"t":3,"n":"Marksman"},{"t":3,"n":"Mercantile"},{"t":3,"n":"Security"},{"t":3,"n":"Sneak"},{"t":3,"n":"Speechcraft"},{"t":3,"n":"Health"},{"t":11,"n":"Unused"},{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":3,"n":"HNAM - Hair"},{"t":5,"n":"LNAM - Hair length"},{"t":7,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eyes"}]},{"t":6,"n":"HCLR - Hair color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":3,"n":"ZNAM - Combat Style"},{"t":6,"n":"FaceGen Data","c":[{"t":11,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"n":"FNAM - Unknown"}]},{"t":1,"p":1,"n":"CREA - Creature","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":8,"p":1,"n":"Spells","d":1,"c":[{"t":3,"p":1,"n":"SPLO - Spell"}]},{"t":7,"n":"NIFZ - Models","c":[{"t":2,"n":"Model"}]},{"t":11,"n":"NIFT - Texture Files Hashes"},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Base spell points"},{"t":3,"n":"Fatigue"},{"t":3,"n":"Barter gold"},{"t":3,"n":"Level (offset)"},{"t":3,"n":"Calc min"},{"t":3,"n":"Calc max"}]},{"t":8,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Buys\/Sells and Services"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":8,"n":"AI Packages","c":[{"t":3,"n":"PKID - AI Package"}]},{"t":7,"n":"KFFZ - Animations","c":[{"t":2,"n":"Animation"}]},{"t":6,"n":"DATA - Creature Data","c":[{"t":3,"n":"Type"},{"t":3,"n":"Combat Skill"},{"t":3,"n":"Magic Skill"},{"t":3,"n":"Stealth Skill"},{"t":3,"n":"Soul"},{"t":11,"n":"Unused"},{"t":3,"n":"Health"},{"t":3,"n":"Attack Damage"},{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":3,"n":"RNAM - Attack reach"},{"t":3,"n":"ZNAM - Combat Style"},{"t":5,"n":"TNAM - Turning Speed"},{"t":5,"n":"BNAM - Base Scale"},{"t":5,"n":"WNAM - Foot Weight"},{"t":2,"n":"NAM0 - Blood Spray"},{"t":2,"n":"NAM1 - Blood Decal"},{"t":3,"n":"CSCR - Inherits Sounds from"},{"t":10,"n":"Sound Types","c":[{"t":6,"n":"Sound Type","c":[{"t":3,"n":"CSDT - Type"},{"t":10,"n":"Sounds","c":[{"t":6,"n":"Sound","c":[{"t":3,"n":"CSDI - Sound"},{"t":3,"n":"CSDC - Sound Chance"}]}]}]}]}]}]},"name":"Bash.Actors.Spells","hash":"4CFC09CA","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.Actors.Stats.json ================================================ {"records":"NPC_,CREA","description":"Actors.Stats tag from Wrye Bash.\r\n\r\nUsed when the mod modifies creature or NPC stats.","tree":{"records":[{"t":1,"p":1,"n":"NPC_ - Non-Player Character","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Base spell points"},{"t":3,"n":"Fatigue"},{"t":3,"n":"Barter gold"},{"t":3,"n":"Level (offset)"},{"t":3,"n":"Calc min"},{"t":3,"n":"Calc max"}]},{"t":8,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"RNAM - Race"},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Buys\/Sells and Services"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":8,"n":"AI Packages","c":[{"t":3,"n":"PKID - AI Package"}]},{"t":7,"n":"KFFZ - Animations","c":[{"t":2,"n":"Animation"}]},{"t":3,"n":"CNAM - Class"},{"t":6,"s":1,"p":1,"n":"DATA - Stats","c":[{"t":3,"p":1,"n":"Armorer"},{"t":3,"p":1,"n":"Athletics"},{"t":3,"p":1,"n":"Blade"},{"t":3,"p":1,"n":"Block"},{"t":3,"p":1,"n":"Blunt"},{"t":3,"p":1,"n":"Hand to Hand"},{"t":3,"p":1,"n":"Heavy Armor"},{"t":3,"p":1,"n":"Alchemy"},{"t":3,"p":1,"n":"Alteration"},{"t":3,"p":1,"n":"Conjuration"},{"t":3,"p":1,"n":"Destruction"},{"t":3,"p":1,"n":"Illusion"},{"t":3,"p":1,"n":"Mysticism"},{"t":3,"p":1,"n":"Restoration"},{"t":3,"p":1,"n":"Acrobatics"},{"t":3,"p":1,"n":"Light Armor"},{"t":3,"p":1,"n":"Marksman"},{"t":3,"p":1,"n":"Mercantile"},{"t":3,"p":1,"n":"Security"},{"t":3,"p":1,"n":"Sneak"},{"t":3,"p":1,"n":"Speechcraft"},{"t":3,"p":1,"n":"Health"},{"t":11,"p":1,"n":"Unused"},{"t":3,"p":1,"n":"Strength"},{"t":3,"p":1,"n":"Intelligence"},{"t":3,"p":1,"n":"Willpower"},{"t":3,"p":1,"n":"Agility"},{"t":3,"p":1,"n":"Speed"},{"t":3,"p":1,"n":"Endurance"},{"t":3,"p":1,"n":"Personality"},{"t":3,"p":1,"n":"Luck"}]},{"t":3,"n":"HNAM - Hair"},{"t":5,"n":"LNAM - Hair length"},{"t":7,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eyes"}]},{"t":6,"n":"HCLR - Hair color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":3,"n":"ZNAM - Combat Style"},{"t":6,"n":"FaceGen Data","c":[{"t":11,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"n":"FNAM - Unknown"}]},{"t":1,"p":1,"n":"CREA - Creature","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":7,"n":"NIFZ - Models","c":[{"t":2,"n":"Model"}]},{"t":11,"n":"NIFT - Texture Files Hashes"},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Base spell points"},{"t":3,"n":"Fatigue"},{"t":3,"n":"Barter gold"},{"t":3,"n":"Level (offset)"},{"t":3,"n":"Calc min"},{"t":3,"n":"Calc max"}]},{"t":8,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Buys\/Sells and Services"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":8,"n":"AI Packages","c":[{"t":3,"n":"PKID - AI Package"}]},{"t":7,"n":"KFFZ - Animations","c":[{"t":2,"n":"Animation"}]},{"t":6,"s":1,"p":1,"n":"DATA - Creature Data","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Combat Skill"},{"t":3,"p":1,"n":"Magic Skill"},{"t":3,"p":1,"n":"Stealth Skill"},{"t":3,"p":1,"n":"Soul"},{"t":11,"p":1,"n":"Unused"},{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Attack Damage"},{"t":3,"p":1,"n":"Strength"},{"t":3,"p":1,"n":"Intelligence"},{"t":3,"p":1,"n":"Willpower"},{"t":3,"p":1,"n":"Agility"},{"t":3,"p":1,"n":"Speed"},{"t":3,"p":1,"n":"Endurance"},{"t":3,"p":1,"n":"Personality"},{"t":3,"p":1,"n":"Luck"}]},{"t":3,"n":"RNAM - Attack reach"},{"t":3,"n":"ZNAM - Combat Style"},{"t":5,"n":"TNAM - Turning Speed"},{"t":5,"n":"BNAM - Base Scale"},{"t":5,"n":"WNAM - Foot Weight"},{"t":2,"n":"NAM0 - Blood Spray"},{"t":2,"n":"NAM1 - Blood Decal"},{"t":3,"n":"CSCR - Inherits Sounds from"},{"t":10,"n":"Sound Types","c":[{"t":6,"n":"Sound Type","c":[{"t":3,"n":"CSDT - Type"},{"t":10,"n":"Sounds","c":[{"t":6,"n":"Sound","c":[{"t":3,"n":"CSDI - Sound"},{"t":3,"n":"CSDC - Sound Chance"}]}]}]}]}]}]},"name":"Bash.Actors.Stats","hash":"98C8C674","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.Body-F.json ================================================ {"records":"RACE","description":"Body-F tag from Wrye Bash.\r\n\r\nUsed when the mod modifies female body mesh\/texture definitions.","tree":{"records":[{"t":1,"p":1,"n":"RACE - Race","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":8,"n":"Relations","c":[{"t":6,"n":"XNAM - Relation","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Modifier"}]}]},{"t":6,"n":"DATA - ","c":[{"t":7,"n":"Skill Boosts","c":[{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]}]},{"t":11,"n":"Unused"},{"t":5,"n":"Male Height"},{"t":5,"n":"Female Height"},{"t":5,"n":"Male Weight"},{"t":5,"n":"Female Weight"},{"t":3,"n":"Flags"}]},{"t":6,"n":"VNAM - Voice","c":[{"t":3,"n":"Male"},{"t":3,"n":"Female"}]},{"t":6,"n":"DNAM - Default Hair","c":[{"t":3,"n":"Male"},{"t":3,"n":"Female"}]},{"t":3,"n":"CNAM - Default Hair Color"},{"t":5,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"n":"UNAM - FaceGen - Face clamp"},{"t":6,"n":"ATTR - Base Attributes","c":[{"t":6,"n":"Male","c":[{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":6,"n":"Female","c":[{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]}]},{"t":6,"n":"Face Data","c":[{"n":"NAM0 - Face Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"n":"NAM1 - Body Data Marker"},{"t":6,"n":"Male Body Data","c":[{"n":"MNAM - Male Body Data Marker"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"t":6,"s":1,"p":1,"n":"Female Body Data","c":[{"p":1,"n":"FNAM - Female Body Data Marker"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":10,"p":1,"n":"Parts","c":[{"t":6,"p":1,"n":"Part","c":[{"t":3,"p":1,"n":"INDX - Index"},{"t":2,"p":1,"n":"ICON - Icon filename"}]}]}]},{"t":7,"n":"HNAM - Hairs","c":[{"t":3,"n":"Hair"}]},{"t":7,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eye"}]},{"t":6,"n":"FaceGen Data","c":[{"t":11,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"n":"SNAM - Unknown"}]}]},"name":"Bash.Body-F","hash":"A14859EB","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.Body-M.json ================================================ {"records":"RACE","description":"Body-M tag from Wrye Bash.\r\n\r\nUsed when the mod modifies male body mesh\/texture definitions.","tree":{"records":[{"t":1,"p":1,"n":"RACE - Race","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":8,"n":"Relations","c":[{"t":6,"n":"XNAM - Relation","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Modifier"}]}]},{"t":6,"n":"DATA - ","c":[{"t":7,"n":"Skill Boosts","c":[{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]}]},{"t":11,"n":"Unused"},{"t":5,"n":"Male Height"},{"t":5,"n":"Female Height"},{"t":5,"n":"Male Weight"},{"t":5,"n":"Female Weight"},{"t":3,"n":"Flags"}]},{"t":6,"n":"VNAM - Voice","c":[{"t":3,"n":"Male"},{"t":3,"n":"Female"}]},{"t":6,"n":"DNAM - Default Hair","c":[{"t":3,"n":"Male"},{"t":3,"n":"Female"}]},{"t":3,"n":"CNAM - Default Hair Color"},{"t":5,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"n":"UNAM - FaceGen - Face clamp"},{"t":6,"n":"ATTR - Base Attributes","c":[{"t":6,"n":"Male","c":[{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":6,"n":"Female","c":[{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]}]},{"t":6,"n":"Face Data","c":[{"n":"NAM0 - Face Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"n":"NAM1 - Body Data Marker"},{"t":6,"s":1,"p":1,"n":"Male Body Data","c":[{"p":1,"n":"MNAM - Male Body Data Marker"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":10,"p":1,"n":"Parts","c":[{"t":6,"p":1,"n":"Part","c":[{"t":3,"p":1,"n":"INDX - Index"},{"t":2,"p":1,"n":"ICON - Icon filename"}]}]}]},{"t":6,"n":"Female Body Data","c":[{"n":"FNAM - Female Body Data Marker"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"t":7,"n":"HNAM - Hairs","c":[{"t":3,"n":"Hair"}]},{"t":7,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eye"}]},{"t":6,"n":"FaceGen Data","c":[{"t":11,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"n":"SNAM - Unknown"}]}]},"name":"Bash.Body-M","hash":"83DA1936","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.Body-Size-F.json ================================================ {"records":"RACE","description":"Body-Size-F tag from Wrye Bash.\r\n\r\nUsed when the mod modifies female body weight\/height definitions.","tree":{"records":[{"t":1,"p":1,"n":"RACE - Race","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":8,"n":"Relations","c":[{"t":6,"n":"XNAM - Relation","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Modifier"}]}]},{"t":6,"p":1,"n":"DATA - ","c":[{"t":7,"n":"Skill Boosts","c":[{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]}]},{"t":11,"n":"Unused"},{"t":5,"n":"Male Height"},{"t":5,"p":1,"n":"Female Height"},{"t":5,"n":"Male Weight"},{"t":5,"p":1,"n":"Female Weight"},{"t":3,"n":"Flags"}]},{"t":6,"n":"VNAM - Voice","c":[{"t":3,"n":"Male"},{"t":3,"n":"Female"}]},{"t":6,"n":"DNAM - Default Hair","c":[{"t":3,"n":"Male"},{"t":3,"n":"Female"}]},{"t":3,"n":"CNAM - Default Hair Color"},{"t":5,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"n":"UNAM - FaceGen - Face clamp"},{"t":6,"n":"ATTR - Base Attributes","c":[{"t":6,"n":"Male","c":[{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":6,"n":"Female","c":[{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]}]},{"t":6,"n":"Face Data","c":[{"n":"NAM0 - Face Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"n":"NAM1 - Body Data Marker"},{"t":6,"n":"Male Body Data","c":[{"n":"MNAM - Male Body Data Marker"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"t":6,"n":"Female Body Data","c":[{"n":"FNAM - Female Body Data Marker"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"t":7,"n":"HNAM - Hairs","c":[{"t":3,"n":"Hair"}]},{"t":7,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eye"}]},{"t":6,"n":"FaceGen Data","c":[{"t":11,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"n":"SNAM - Unknown"}]}]},"name":"Bash.Body-Size-F","hash":"C6CC40E5","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.Body-Size-M.json ================================================ {"records":"RACE","description":"Body-Size-M tag from Wrye Bash.\r\n\r\nUsed when the mod modifies male body weight\/height definitions.","tree":{"records":[{"t":1,"p":1,"n":"RACE - Race","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":8,"n":"Relations","c":[{"t":6,"n":"XNAM - Relation","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Modifier"}]}]},{"t":6,"p":1,"n":"DATA - ","c":[{"t":7,"n":"Skill Boosts","c":[{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]}]},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Male Height"},{"t":5,"n":"Female Height"},{"t":5,"p":1,"n":"Male Weight"},{"t":5,"n":"Female Weight"},{"t":3,"n":"Flags"}]},{"t":6,"n":"VNAM - Voice","c":[{"t":3,"n":"Male"},{"t":3,"n":"Female"}]},{"t":6,"n":"DNAM - Default Hair","c":[{"t":3,"n":"Male"},{"t":3,"n":"Female"}]},{"t":3,"n":"CNAM - Default Hair Color"},{"t":5,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"n":"UNAM - FaceGen - Face clamp"},{"t":6,"n":"ATTR - Base Attributes","c":[{"t":6,"n":"Male","c":[{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":6,"n":"Female","c":[{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]}]},{"t":6,"n":"Face Data","c":[{"n":"NAM0 - Face Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"n":"NAM1 - Body Data Marker"},{"t":6,"n":"Male Body Data","c":[{"n":"MNAM - Male Body Data Marker"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"t":6,"n":"Female Body Data","c":[{"n":"FNAM - Female Body Data Marker"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"t":7,"n":"HNAM - Hairs","c":[{"t":3,"n":"Hair"}]},{"t":7,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eye"}]},{"t":6,"n":"FaceGen Data","c":[{"t":11,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"n":"SNAM - Unknown"}]}]},"name":"Bash.Body-Size-M","hash":"FF3104AC","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.C.Climate.json ================================================ {"records":"CELL","description":"C.Climate tag from Wrye Bash.\r\n\r\nUsed when the mod modifies cell climates.","tree":{"records":[{"t":1,"p":1,"n":"CELL - Cell","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":3,"n":"DATA - Flags"},{"t":6,"n":"XCLC - Grid","c":[{"t":3,"n":"X"},{"t":3,"n":"Y"}]},{"t":6,"n":"XCLL - Lighting","c":[{"t":6,"n":"Ambient Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"n":"Directional Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"n":"Fog Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"n":"Fog Near"},{"t":5,"n":"Fog Far"},{"t":3,"n":"Directional Rotation XY"},{"t":3,"n":"Directional Rotation Z"},{"t":5,"n":"Directional Fade"},{"t":5,"n":"Fog Clip Dist"}]},{"t":7,"n":"XCLR - Regions","c":[{"t":3,"n":"Region"}]},{"t":3,"n":"XCMT - Music"},{"t":5,"n":"XCLW - Water Height"},{"t":3,"p":1,"n":"XCCM - Climate"},{"t":3,"n":"XCWT - Water"},{"t":6,"n":"Ownership","c":[{"t":3,"n":"XOWN - Owner"},{"t":3,"n":"XRNK - Faction rank"},{"t":3,"n":"XGLB - Global variable"}]}]}]},"name":"Bash.C.Climate","hash":"2BA85E9B","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.C.Light.json ================================================ {"records":"CELL","description":"C.Light tag from Wrye Bash.\r\n\r\nUsed when the mod modifies cell lighting or fog.","tree":{"records":[{"t":1,"p":1,"n":"CELL - Cell","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":3,"n":"DATA - Flags"},{"t":6,"n":"XCLC - Grid","c":[{"t":3,"n":"X"},{"t":3,"n":"Y"}]},{"t":6,"p":1,"n":"XCLL - Lighting","c":[{"t":6,"s":1,"p":1,"n":"Ambient Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unused"}]},{"t":6,"s":1,"p":1,"n":"Directional Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unused"}]},{"t":6,"s":1,"p":1,"n":"Fog Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unused"}]},{"t":5,"n":"Fog Near"},{"t":5,"n":"Fog Far"},{"t":3,"n":"Directional Rotation XY"},{"t":3,"n":"Directional Rotation Z"},{"t":5,"n":"Directional Fade"},{"t":5,"n":"Fog Clip Dist"}]},{"t":7,"n":"XCLR - Regions","c":[{"t":3,"n":"Region"}]},{"t":3,"n":"XCMT - Music"},{"t":5,"n":"XCLW - Water Height"},{"t":3,"n":"XCCM - Climate"},{"t":3,"n":"XCWT - Water"},{"t":6,"n":"Ownership","c":[{"t":3,"n":"XOWN - Owner"},{"t":3,"n":"XRNK - Faction rank"},{"t":3,"n":"XGLB - Global variable"}]}]}]},"name":"Bash.C.Light","hash":"FD3FC808","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.C.Music.json ================================================ {"records":"CELL","description":"C.Music tag from Wrye Bash.\r\n\r\nUsed when the mod modifies cell music type.","tree":{"records":[{"t":1,"p":1,"n":"CELL - Cell","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":3,"n":"DATA - Flags"},{"t":6,"n":"XCLC - Grid","c":[{"t":3,"n":"X"},{"t":3,"n":"Y"}]},{"t":6,"n":"XCLL - Lighting","c":[{"t":6,"n":"Ambient Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"n":"Directional Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"n":"Fog Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"n":"Fog Near"},{"t":5,"n":"Fog Far"},{"t":3,"n":"Directional Rotation XY"},{"t":3,"n":"Directional Rotation Z"},{"t":5,"n":"Directional Fade"},{"t":5,"n":"Fog Clip Dist"}]},{"t":7,"n":"XCLR - Regions","c":[{"t":3,"n":"Region"}]},{"t":3,"p":1,"n":"XCMT - Music"},{"t":5,"n":"XCLW - Water Height"},{"t":3,"n":"XCCM - Climate"},{"t":3,"n":"XCWT - Water"},{"t":6,"n":"Ownership","c":[{"t":3,"n":"XOWN - Owner"},{"t":3,"n":"XRNK - Faction rank"},{"t":3,"n":"XGLB - Global variable"}]}]}]},"name":"Bash.C.Music","hash":"2C2C6A24","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.C.Name.json ================================================ {"records":"CELL","description":"C.Name tag from Wrye Bash.\r\n\r\nUsed when the mod modifies cell names.","tree":{"records":[{"t":1,"p":1,"n":"CELL - Cell","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"DATA - Flags"},{"t":6,"n":"XCLC - Grid","c":[{"t":3,"n":"X"},{"t":3,"n":"Y"}]},{"t":6,"n":"XCLL - Lighting","c":[{"t":6,"n":"Ambient Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"n":"Directional Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"n":"Fog Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"n":"Fog Near"},{"t":5,"n":"Fog Far"},{"t":3,"n":"Directional Rotation XY"},{"t":3,"n":"Directional Rotation Z"},{"t":5,"n":"Directional Fade"},{"t":5,"n":"Fog Clip Dist"}]},{"t":7,"n":"XCLR - Regions","c":[{"t":3,"n":"Region"}]},{"t":3,"n":"XCMT - Music"},{"t":5,"n":"XCLW - Water Height"},{"t":3,"n":"XCCM - Climate"},{"t":3,"n":"XCWT - Water"},{"t":6,"n":"Ownership","c":[{"t":3,"n":"XOWN - Owner"},{"t":3,"n":"XRNK - Faction rank"},{"t":3,"n":"XGLB - Global variable"}]}]}]},"name":"Bash.C.Name","hash":"2AE9B4F8","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.C.Owner.json ================================================ {"records":"CELL","description":"C.Owner tag from Wrye Bash.\r\n\r\nUsed when the mod modifies cell ownership.","tree":{"records":[{"t":1,"p":1,"n":"CELL - Cell","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":3,"n":"DATA - Flags"},{"t":6,"n":"XCLC - Grid","c":[{"t":3,"n":"X"},{"t":3,"n":"Y"}]},{"t":6,"n":"XCLL - Lighting","c":[{"t":6,"n":"Ambient Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"n":"Directional Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"n":"Fog Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"n":"Fog Near"},{"t":5,"n":"Fog Far"},{"t":3,"n":"Directional Rotation XY"},{"t":3,"n":"Directional Rotation Z"},{"t":5,"n":"Directional Fade"},{"t":5,"n":"Fog Clip Dist"}]},{"t":7,"n":"XCLR - Regions","c":[{"t":3,"n":"Region"}]},{"t":3,"n":"XCMT - Music"},{"t":5,"n":"XCLW - Water Height"},{"t":3,"n":"XCCM - Climate"},{"t":3,"n":"XCWT - Water"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"},{"t":3,"p":1,"n":"XGLB - Global variable"}]}]}]},"name":"Bash.C.Owner","hash":"B04A60C6","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.C.RecordFlags.json ================================================ {"records":"CELL","description":"C.RecordFlags tag from Wrye Bash.\r\n\r\nUsed when the mod modifies the off-limits or dangerous flags.","tree":{"records":[{"t":1,"p":1,"n":"CELL - Cell","c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":3,"n":"DATA - Flags"},{"t":6,"n":"XCLC - Grid","c":[{"t":3,"n":"X"},{"t":3,"n":"Y"}]},{"t":6,"n":"XCLL - Lighting","c":[{"t":6,"n":"Ambient Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"n":"Directional Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"n":"Fog Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"n":"Fog Near"},{"t":5,"n":"Fog Far"},{"t":3,"n":"Directional Rotation XY"},{"t":3,"n":"Directional Rotation Z"},{"t":5,"n":"Directional Fade"},{"t":5,"n":"Fog Clip Dist"}]},{"t":7,"n":"XCLR - Regions","c":[{"t":3,"n":"Region"}]},{"t":3,"n":"XCMT - Music"},{"t":5,"n":"XCLW - Water Height"},{"t":3,"n":"XCCM - Climate"},{"t":3,"n":"XCWT - Water"},{"t":6,"n":"Ownership","c":[{"t":3,"n":"XOWN - Owner"},{"t":3,"n":"XRNK - Faction rank"},{"t":3,"n":"XGLB - Global variable"}]}]}]},"name":"Bash.C.RecordFlags","hash":"FFCD1DD2","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.C.Water.json ================================================ {"records":"CELL","description":"C.Water tag from Wrye Bash.\r\n\r\nUsed when the mod modifies cell water type or level.","tree":{"records":[{"t":1,"p":1,"n":"CELL - Cell","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":3,"n":"DATA - Flags"},{"t":6,"n":"XCLC - Grid","c":[{"t":3,"n":"X"},{"t":3,"n":"Y"}]},{"t":6,"n":"XCLL - Lighting","c":[{"t":6,"n":"Ambient Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"n":"Directional Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"n":"Fog Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"n":"Fog Near"},{"t":5,"n":"Fog Far"},{"t":3,"n":"Directional Rotation XY"},{"t":3,"n":"Directional Rotation Z"},{"t":5,"n":"Directional Fade"},{"t":5,"n":"Fog Clip Dist"}]},{"t":7,"n":"XCLR - Regions","c":[{"t":3,"n":"Region"}]},{"t":3,"n":"XCMT - Music"},{"t":5,"p":1,"n":"XCLW - Water Height"},{"t":3,"n":"XCCM - Climate"},{"t":3,"p":1,"n":"XCWT - Water"},{"t":6,"n":"Ownership","c":[{"t":3,"n":"XOWN - Owner"},{"t":3,"n":"XRNK - Faction rank"},{"t":3,"n":"XGLB - Global variable"}]}]}]},"name":"Bash.C.Water","hash":"3A3E7791","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.Creatures.Blood.json ================================================ {"records":"CREA","description":"Creatures.Blood tag from Wrye Bash.\r\n\r\nUsed when the mod modifies the creature blood subrecords.","tree":{"records":[{"t":1,"p":1,"n":"CREA - Creature","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":7,"n":"NIFZ - Models","c":[{"t":2,"n":"Model"}]},{"t":11,"n":"NIFT - Texture Files Hashes"},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Base spell points"},{"t":3,"n":"Fatigue"},{"t":3,"n":"Barter gold"},{"t":3,"n":"Level (offset)"},{"t":3,"n":"Calc min"},{"t":3,"n":"Calc max"}]},{"t":8,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Buys\/Sells and Services"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":8,"n":"AI Packages","c":[{"t":3,"n":"PKID - AI Package"}]},{"t":7,"n":"KFFZ - Animations","c":[{"t":2,"n":"Animation"}]},{"t":6,"n":"DATA - Creature Data","c":[{"t":3,"n":"Type"},{"t":3,"n":"Combat Skill"},{"t":3,"n":"Magic Skill"},{"t":3,"n":"Stealth Skill"},{"t":3,"n":"Soul"},{"t":11,"n":"Unused"},{"t":3,"n":"Health"},{"t":3,"n":"Attack Damage"},{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":3,"n":"RNAM - Attack reach"},{"t":3,"n":"ZNAM - Combat Style"},{"t":5,"n":"TNAM - Turning Speed"},{"t":5,"n":"BNAM - Base Scale"},{"t":5,"n":"WNAM - Foot Weight"},{"t":2,"p":1,"n":"NAM0 - Blood Spray"},{"t":2,"p":1,"n":"NAM1 - Blood Decal"},{"t":3,"n":"CSCR - Inherits Sounds from"},{"t":10,"n":"Sound Types","c":[{"t":6,"n":"Sound Type","c":[{"t":3,"n":"CSDT - Type"},{"t":10,"n":"Sounds","c":[{"t":6,"n":"Sound","c":[{"t":3,"n":"CSDI - Sound"},{"t":3,"n":"CSDC - Sound Chance"}]}]}]}]}]}]},"name":"Bash.Creatures.Blood","hash":"859EBB9B","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.Eyes.json ================================================ {"records":"RACE","description":"Eyes tag from Wrye Bash.\r\n\r\nUsed when the mod adds eyes to races.","tree":{"records":[{"t":1,"p":1,"n":"RACE - Race","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":8,"n":"Relations","c":[{"t":6,"n":"XNAM - Relation","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Modifier"}]}]},{"t":6,"n":"DATA - ","c":[{"t":7,"n":"Skill Boosts","c":[{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]}]},{"t":11,"n":"Unused"},{"t":5,"n":"Male Height"},{"t":5,"n":"Female Height"},{"t":5,"n":"Male Weight"},{"t":5,"n":"Female Weight"},{"t":3,"n":"Flags"}]},{"t":6,"n":"VNAM - Voice","c":[{"t":3,"n":"Male"},{"t":3,"n":"Female"}]},{"t":6,"n":"DNAM - Default Hair","c":[{"t":3,"n":"Male"},{"t":3,"n":"Female"}]},{"t":3,"n":"CNAM - Default Hair Color"},{"t":5,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"n":"UNAM - FaceGen - Face clamp"},{"t":6,"n":"ATTR - Base Attributes","c":[{"t":6,"n":"Male","c":[{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":6,"n":"Female","c":[{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]}]},{"t":6,"n":"Face Data","c":[{"n":"NAM0 - Face Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"n":"NAM1 - Body Data Marker"},{"t":6,"n":"Male Body Data","c":[{"n":"MNAM - Male Body Data Marker"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"t":6,"n":"Female Body Data","c":[{"n":"FNAM - Female Body Data Marker"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"t":7,"n":"HNAM - Hairs","c":[{"t":3,"n":"Hair"}]},{"t":7,"p":1,"n":"ENAM - Eyes","c":[{"t":3,"p":1,"n":"Eye"}]},{"t":6,"n":"FaceGen Data","c":[{"t":11,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"n":"SNAM - Unknown"}]}]},"name":"Bash.Eyes","hash":"2EBA80F8","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.Factions.json ================================================ {"records":"NPC_,CREA","description":"Factions tag from Wrye Bash.\r\n\r\nUsed when the mod modifies creature or NPC factions.","tree":{"records":[{"t":1,"p":1,"n":"NPC_ - Non-Player Character","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Base spell points"},{"t":3,"n":"Fatigue"},{"t":3,"n":"Barter gold"},{"t":3,"n":"Level (offset)"},{"t":3,"n":"Calc min"},{"t":3,"n":"Calc max"}]},{"t":8,"p":1,"n":"Factions","d":1,"c":[{"t":6,"p":1,"n":"SNAM - Faction","c":[{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Rank"},{"t":11,"p":1,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"RNAM - Race"},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Buys\/Sells and Services"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":8,"n":"AI Packages","c":[{"t":3,"n":"PKID - AI Package"}]},{"t":7,"n":"KFFZ - Animations","c":[{"t":2,"n":"Animation"}]},{"t":3,"n":"CNAM - Class"},{"t":6,"n":"DATA - Stats","c":[{"t":3,"n":"Armorer"},{"t":3,"n":"Athletics"},{"t":3,"n":"Blade"},{"t":3,"n":"Block"},{"t":3,"n":"Blunt"},{"t":3,"n":"Hand to Hand"},{"t":3,"n":"Heavy Armor"},{"t":3,"n":"Alchemy"},{"t":3,"n":"Alteration"},{"t":3,"n":"Conjuration"},{"t":3,"n":"Destruction"},{"t":3,"n":"Illusion"},{"t":3,"n":"Mysticism"},{"t":3,"n":"Restoration"},{"t":3,"n":"Acrobatics"},{"t":3,"n":"Light Armor"},{"t":3,"n":"Marksman"},{"t":3,"n":"Mercantile"},{"t":3,"n":"Security"},{"t":3,"n":"Sneak"},{"t":3,"n":"Speechcraft"},{"t":3,"n":"Health"},{"t":11,"n":"Unused"},{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":3,"n":"HNAM - Hair"},{"t":5,"n":"LNAM - Hair length"},{"t":7,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eyes"}]},{"t":6,"n":"HCLR - Hair color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":3,"n":"ZNAM - Combat Style"},{"t":6,"n":"FaceGen Data","c":[{"t":11,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"n":"FNAM - Unknown"}]},{"t":1,"p":1,"n":"CREA - Creature","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":7,"n":"NIFZ - Models","c":[{"t":2,"n":"Model"}]},{"t":11,"n":"NIFT - Texture Files Hashes"},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Base spell points"},{"t":3,"n":"Fatigue"},{"t":3,"n":"Barter gold"},{"t":3,"n":"Level (offset)"},{"t":3,"n":"Calc min"},{"t":3,"n":"Calc max"}]},{"t":8,"p":1,"n":"Factions","d":1,"c":[{"t":6,"p":1,"n":"SNAM - Faction","c":[{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Rank"},{"t":11,"p":1,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Buys\/Sells and Services"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":8,"n":"AI Packages","c":[{"t":3,"n":"PKID - AI Package"}]},{"t":7,"n":"KFFZ - Animations","c":[{"t":2,"n":"Animation"}]},{"t":6,"n":"DATA - Creature Data","c":[{"t":3,"n":"Type"},{"t":3,"n":"Combat Skill"},{"t":3,"n":"Magic Skill"},{"t":3,"n":"Stealth Skill"},{"t":3,"n":"Soul"},{"t":11,"n":"Unused"},{"t":3,"n":"Health"},{"t":3,"n":"Attack Damage"},{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":3,"n":"RNAM - Attack reach"},{"t":3,"n":"ZNAM - Combat Style"},{"t":5,"n":"TNAM - Turning Speed"},{"t":5,"n":"BNAM - Base Scale"},{"t":5,"n":"WNAM - Foot Weight"},{"t":2,"n":"NAM0 - Blood Spray"},{"t":2,"n":"NAM1 - Blood Decal"},{"t":3,"n":"CSCR - Inherits Sounds from"},{"t":10,"n":"Sound Types","c":[{"t":6,"n":"Sound Type","c":[{"t":3,"n":"CSDT - Type"},{"t":10,"n":"Sounds","c":[{"t":6,"n":"Sound","c":[{"t":3,"n":"CSDI - Sound"},{"t":3,"n":"CSDC - Sound Chance"}]}]}]}]}]}]},"name":"Bash.Factions","hash":"FB84E394","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.Graphics.json ================================================ {"records":"ALCH,AMMO,APPA,ARMO,BOOK,BSGN,CLAS,CLOT,CREA,DOOR,EFSH,FLOR,FURN,GRAS,INGR,KEYM,LIGH,LSCR,LTEX,MGEF,MISC,REGN,SGST,SLGM,STAT,TREE,WEAP,ACTI","description":"Graphics tag from Wrye Bash.\r\n\r\nUsed when the mod is a graphics replacer.","tree":{"records":[{"t":1,"p":1,"n":"ALCH - Potion","c":[{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBME - Oblivion Magic Extender","c":[{"t":3,"n":"Record Version"},{"t":6,"n":"OBME Version","c":[{"t":3,"n":"Beta"},{"t":3,"n":"Minor"},{"t":3,"n":"Major"}]},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":3,"n":"SCRI - Script"},{"t":5,"n":"DATA - Weight"},{"t":6,"n":"ENIT - ","c":[{"t":3,"n":"Value"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":3,"n":"EFID - Magic effect name"},{"t":6,"n":"EFIT - ","c":[{"t":3,"n":"Magic effect name"},{"t":3,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"},{"t":3,"n":"Type"},{"t":3,"n":"Actor Value"}]},{"t":6,"n":"Script effect","c":[{"t":6,"n":"SCIT - Script effect data","c":[{"t":3,"n":"Script effect"},{"t":3,"n":"Magic school"},{"t":3,"n":"Visual effect name"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"}]}]},{"t":6,"n":"Effects","c":[{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":6,"n":"EFME - Oblivion Magic Extender","c":[{"t":3,"n":"Record Version"},{"t":6,"n":"OBME Version","c":[{"t":3,"n":"Beta"},{"t":3,"n":"Minor"},{"t":3,"n":"Major"}]},{"t":3,"n":"EFIT Param Info"},{"t":3,"n":"EFIX Param Info"},{"t":11,"n":"Unused"}]},{"t":2,"n":"EFID - Magic Effect Code"},{"t":6,"n":"EFIT - ","c":[{"t":2,"n":"Magic Effect Code"},{"t":3,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"},{"t":3,"n":"Type"},{"t":11,"n":"Param #1 - Unknown Type"},{"t":3,"n":"Param #1 - FormID"},{"t":2,"n":"Param #1 - Magic Effect Code"},{"t":3,"n":"Param #1 - Actor Value"}]},{"t":6,"n":"Script effect","c":[{"t":6,"n":"SCIT - Script effect data","c":[{"t":3,"n":"Script effect"},{"t":3,"n":"Magic school"},{"t":2,"n":"Visual Effect Code"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"}]},{"t":2,"n":"EFII - Icon"},{"t":6,"n":"EFIX - ","c":[{"t":3,"n":"Override Mask"},{"t":3,"n":"Flags"},{"t":5,"n":"Base Cost"},{"t":11,"n":"Param #2 - Unknown Type"},{"t":3,"n":"Param #2 - FormID"},{"t":2,"n":"Param #2 - Magic Effect Code"},{"t":3,"n":"Param #2 - Actor Value"}]}]}]},{"n":"EFXX - Effects End Marker"},{"t":2,"n":"FULL - Name"}]}]}]},{"t":1,"p":1,"n":"AMMO - Ammunition","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":3,"n":"ENAM - Enchantment"},{"t":3,"n":"ANAM - Enchantment Points"},{"t":6,"n":"DATA - ","c":[{"t":5,"n":"Speed"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"},{"t":3,"n":"Value"},{"t":5,"n":"Weight"},{"t":3,"n":"Damage"}]}]},{"t":1,"p":1,"n":"APPA - Alchemical Apparatus","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Type"},{"t":3,"n":"Value"},{"t":5,"n":"Weight"},{"t":5,"n":"Quality"}]}]},{"t":1,"p":1,"n":"ARMO - Armor","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":3,"n":"SCRI - Script"},{"t":3,"n":"ENAM - Enchantment"},{"t":3,"n":"ANAM - Enchantment Points"},{"t":6,"n":"BMDT - ","c":[{"t":3,"n":"Biped Flags"},{"t":3,"n":"General Flags"},{"t":11,"n":"Unused"}]},{"t":6,"s":1,"p":1,"n":"Male biped model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":6,"s":1,"p":1,"n":"Male world model","c":[{"t":2,"p":1,"n":"MOD2 - Model Filename"},{"t":5,"p":1,"n":"MO2B - Bound Radius"},{"t":11,"p":1,"n":"MO2T - Texture Files Hashes"}]},{"t":2,"p":1,"n":"ICON - Male icon filename"},{"t":6,"s":1,"p":1,"n":"Female biped model","c":[{"t":2,"p":1,"n":"MOD3 - Model Filename"},{"t":5,"p":1,"n":"MO3B - Bound Radius"},{"t":11,"p":1,"n":"MO3T - Texture Files Hashes"}]},{"t":6,"s":1,"p":1,"n":"Female world model","c":[{"t":2,"p":1,"n":"MOD4 - Model Filename"},{"t":5,"p":1,"n":"MO4B - Bound Radius"},{"t":11,"p":1,"n":"MO4T - Texture Files Hashes"}]},{"t":2,"p":1,"n":"ICO2 - Female icon filename"},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Armor"},{"t":3,"n":"Value"},{"t":3,"n":"Health"},{"t":5,"n":"Weight"}]}]},{"t":1,"p":1,"n":"BOOK - Book","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":3,"n":"SCRI - Script"},{"t":3,"n":"ENAM - Enchantment"},{"t":3,"n":"ANAM - Enchantment Points"},{"t":2,"n":"DESC - Description"},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Teaches"},{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]}]},{"t":1,"p":1,"n":"BSGN - Birthsign","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":2,"n":"DESC - Description"},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]}]},{"t":1,"p":1,"n":"CLAS - Class","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":6,"n":"DATA - ","c":[{"t":7,"n":"Primary Attributes","c":[{"t":3,"n":"Primary Attribute"}]},{"t":3,"n":"Specialization"},{"t":7,"n":"Major Skills","c":[{"t":3,"n":"Major Skill"}]},{"t":3,"n":"Flags"},{"t":3,"n":"Buys\/Sells and Services"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":3,"n":"Unused"}]}]},{"t":1,"p":1,"n":"CLOT - Clothing","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":3,"n":"SCRI - Script"},{"t":3,"n":"ENAM - Enchantment"},{"t":3,"n":"ANAM - Enchantment Points"},{"t":6,"n":"BMDT - ","c":[{"t":3,"n":"Biped Flags"},{"t":3,"n":"General Flags"},{"t":11,"n":"Unused"}]},{"t":6,"s":1,"p":1,"n":"Male biped model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":6,"s":1,"p":1,"n":"Male world model","c":[{"t":2,"p":1,"n":"MOD2 - Model Filename"},{"t":5,"p":1,"n":"MO2B - Bound Radius"},{"t":11,"p":1,"n":"MO2T - Texture Files Hashes"}]},{"t":2,"p":1,"n":"ICON - Male icon filename"},{"t":6,"s":1,"p":1,"n":"Female biped model","c":[{"t":2,"p":1,"n":"MOD3 - Model Filename"},{"t":5,"p":1,"n":"MO3B - Bound Radius"},{"t":11,"p":1,"n":"MO3T - Texture Files Hashes"}]},{"t":6,"s":1,"p":1,"n":"Female world model","c":[{"t":2,"p":1,"n":"MOD4 - Model Filename"},{"t":5,"p":1,"n":"MO4B - Bound Radius"},{"t":11,"p":1,"n":"MO4T - Texture Files Hashes"}]},{"t":2,"p":1,"n":"ICO2 - Female icon filename"},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]}]},{"t":1,"p":1,"n":"CREA - Creature","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":7,"s":1,"p":1,"n":"NIFZ - Models","c":[{"t":2,"p":1,"n":"Model"}],"lt":"NIFT - Texture Files Hashes","lf":"NIFT - Texture Files Hashes"},{"t":11,"p":1,"n":"NIFT - Texture Files Hashes","lt":"NIFZ - Models","lf":"NIFZ - Models"},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Base spell points"},{"t":3,"n":"Fatigue"},{"t":3,"n":"Barter gold"},{"t":3,"n":"Level (offset)"},{"t":3,"n":"Calc min"},{"t":3,"n":"Calc max"}]},{"t":8,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Buys\/Sells and Services"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":8,"n":"AI Packages","c":[{"t":3,"n":"PKID - AI Package"}]},{"t":7,"n":"KFFZ - Animations","c":[{"t":2,"n":"Animation"}]},{"t":6,"n":"DATA - Creature Data","c":[{"t":3,"n":"Type"},{"t":3,"n":"Combat Skill"},{"t":3,"n":"Magic Skill"},{"t":3,"n":"Stealth Skill"},{"t":3,"n":"Soul"},{"t":11,"n":"Unused"},{"t":3,"n":"Health"},{"t":3,"n":"Attack Damage"},{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":3,"n":"RNAM - Attack reach"},{"t":3,"n":"ZNAM - Combat Style"},{"t":5,"n":"TNAM - Turning Speed"},{"t":5,"n":"BNAM - Base Scale"},{"t":5,"n":"WNAM - Foot Weight"},{"t":2,"n":"NAM0 - Blood Spray"},{"t":2,"n":"NAM1 - Blood Decal"},{"t":3,"n":"CSCR - Inherits Sounds from"},{"t":10,"n":"Sound Types","c":[{"t":6,"n":"Sound Type","c":[{"t":3,"n":"CSDT - Type"},{"t":10,"n":"Sounds","c":[{"t":6,"n":"Sound","c":[{"t":3,"n":"CSDI - Sound"},{"t":3,"n":"CSDC - Sound Chance"}]}]}]}]}]},{"t":1,"p":1,"n":"DOOR - Door","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":3,"n":"SCRI - Script"},{"t":3,"n":"SNAM - Open sound"},{"t":3,"n":"ANAM - Close sound"},{"t":3,"n":"BNAM - Loop sound"},{"t":3,"n":"FNAM - Flags"},{"t":8,"n":"Random teleport destinations","c":[{"t":3,"n":"TNAM - Destination"}]}]},{"t":1,"p":1,"n":"EFSH - Effect Shader","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"ICON - Fill Texture"},{"t":2,"p":1,"n":"ICO2 - Particle Shader Texture"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Flags"},{"t":11,"p":1,"n":"Unused"},{"t":3,"p":1,"n":"Membrane Shader - Source Blend Mode"},{"t":3,"p":1,"n":"Membrane Shader - Blend Operation"},{"t":3,"p":1,"n":"Membrane Shader - Z Test Function"},{"t":6,"p":1,"n":"Fill\/Texture Effect - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unused"}]},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Fade In Time"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Full Alpha Time"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Fade Out Time"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Presistent Alpha Ratio"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Pulse Amplitude"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Pulse Frequency"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Animation Speed (U)"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Animation Speed (V)"},{"t":5,"p":1,"n":"Edge Effect - Fall Off"},{"t":6,"p":1,"n":"Edge Effect - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unused"}]},{"t":5,"p":1,"n":"Edge Effect - Alpha Fade In Time"},{"t":5,"p":1,"n":"Edge Effect - Full Alpha Time"},{"t":5,"p":1,"n":"Edge Effect - Alpha Fade Out Time"},{"t":5,"p":1,"n":"Edge Effect - Persistent Alpha Ratio"},{"t":5,"p":1,"n":"Edge Effect - Alpha Pulse Amplitude"},{"t":5,"p":1,"n":"Edge Effect - Alpha Pusle Frequence"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Full Alpha Ratio"},{"t":5,"p":1,"n":"Edge Effect - Full Alpha Ratio"},{"t":3,"p":1,"n":"Membrane Shader - Dest Blend Mode"},{"t":3,"p":1,"n":"Particle Shader - Source Blend Mode"},{"t":3,"p":1,"n":"Particle Shader - Blend Operation"},{"t":3,"p":1,"n":"Particle Shader - Z Test Function"},{"t":3,"p":1,"n":"Particle Shader - Dest Blend Mode"},{"t":5,"p":1,"n":"Particle Shader - Particle Birth Ramp Up Time"},{"t":5,"p":1,"n":"Particle Shader - Full Particle Birth Time"},{"t":5,"p":1,"n":"Particle Shader - Particle Birth Ramp Down Time"},{"t":5,"p":1,"n":"Particle Shader - Full Particle Birth Ratio"},{"t":5,"p":1,"n":"Particle Shader - Persistant Particle Birth Ratio"},{"t":5,"p":1,"n":"Particle Shader - Particle Lifetime"},{"t":5,"p":1,"n":"Particle Shader - Particle Lifetime +\/-"},{"t":5,"p":1,"n":"Particle Shader - Initial Speed Along Normal"},{"t":5,"p":1,"n":"Particle Shader - Acceleration Along Normal"},{"t":5,"p":1,"n":"Particle Shader - Initial Velocity #1"},{"t":5,"p":1,"n":"Particle Shader - Initial Velocity #2"},{"t":5,"p":1,"n":"Particle Shader - Initial Velocity #3"},{"t":5,"p":1,"n":"Particle Shader - Acceleration #1"},{"t":5,"p":1,"n":"Particle Shader - Acceleration #2"},{"t":5,"p":1,"n":"Particle Shader - Acceleration #3"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 1"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 2"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 1 Time"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 2 Time"},{"t":6,"p":1,"n":"Color Key 1 - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unused"}]},{"t":6,"p":1,"n":"Color Key 2 - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unused"}]},{"t":6,"p":1,"n":"Color Key 3 - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unused"}]},{"t":5,"p":1,"n":"Color Key 1 - Color Alpha"},{"t":5,"p":1,"n":"Color Key 2 - Color Alpha"},{"t":5,"p":1,"n":"Color Key 3 - Color Alpha"},{"t":5,"p":1,"n":"Color Key 1 - Color Key Time"},{"t":5,"p":1,"n":"Color Key 2 - Color Key Time"},{"t":5,"p":1,"n":"Color Key 3 - Color Key Time"}]}]},{"t":1,"p":1,"n":"FLOR - Flora","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":3,"n":"SCRI - Script"},{"t":3,"n":"PFIG - Ingredient"},{"t":6,"n":"PFPC - Seasonal ingredient production","c":[{"t":3,"n":"Spring"},{"t":3,"n":"Summer "},{"t":3,"n":"Fall"},{"t":3,"n":"Winter"}]}]},{"t":1,"p":1,"n":"FURN - Furniture","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":3,"n":"SCRI - Script"},{"t":11,"n":"MNAM - Marker Flags"}]},{"t":1,"p":1,"n":"GRAS - Grass","c":[{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Density"},{"t":3,"n":"Min Slope"},{"t":3,"n":"Max Slope"},{"t":11,"n":"Unused"},{"t":3,"n":"Unit from water amount"},{"t":3,"n":"Unit from water type"},{"t":5,"n":"Position Range"},{"t":5,"n":"Height Range"},{"t":5,"n":"Color Range"},{"t":5,"n":"Wave Period"},{"t":3,"n":"Flags"}]}]},{"t":1,"p":1,"n":"INGR - Ingredient","c":[{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBME - Oblivion Magic Extender","c":[{"t":3,"n":"Record Version"},{"t":6,"n":"OBME Version","c":[{"t":3,"n":"Beta"},{"t":3,"n":"Minor"},{"t":3,"n":"Major"}]},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":3,"n":"SCRI - Script"},{"t":5,"n":"DATA - Weight"},{"t":6,"n":"ENIT - ","c":[{"t":3,"n":"Value"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":3,"n":"EFID - Magic effect name"},{"t":6,"n":"EFIT - ","c":[{"t":3,"n":"Magic effect name"},{"t":3,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"},{"t":3,"n":"Type"},{"t":3,"n":"Actor Value"}]},{"t":6,"n":"Script effect","c":[{"t":6,"n":"SCIT - Script effect data","c":[{"t":3,"n":"Script effect"},{"t":3,"n":"Magic school"},{"t":3,"n":"Visual effect name"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"}]}]},{"t":6,"n":"Effects","c":[{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":6,"n":"EFME - Oblivion Magic Extender","c":[{"t":3,"n":"Record Version"},{"t":6,"n":"OBME Version","c":[{"t":3,"n":"Beta"},{"t":3,"n":"Minor"},{"t":3,"n":"Major"}]},{"t":3,"n":"EFIT Param Info"},{"t":3,"n":"EFIX Param Info"},{"t":11,"n":"Unused"}]},{"t":2,"n":"EFID - Magic Effect Code"},{"t":6,"n":"EFIT - ","c":[{"t":2,"n":"Magic Effect Code"},{"t":3,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"},{"t":3,"n":"Type"},{"t":11,"n":"Param #1 - Unknown Type"},{"t":3,"n":"Param #1 - FormID"},{"t":2,"n":"Param #1 - Magic Effect Code"},{"t":3,"n":"Param #1 - Actor Value"}]},{"t":6,"n":"Script effect","c":[{"t":6,"n":"SCIT - Script effect data","c":[{"t":3,"n":"Script effect"},{"t":3,"n":"Magic school"},{"t":2,"n":"Visual Effect Code"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"}]},{"t":2,"n":"EFII - Icon"},{"t":6,"n":"EFIX - ","c":[{"t":3,"n":"Override Mask"},{"t":3,"n":"Flags"},{"t":5,"n":"Base Cost"},{"t":11,"n":"Param #2 - Unknown Type"},{"t":3,"n":"Param #2 - FormID"},{"t":2,"n":"Param #2 - Magic Effect Code"},{"t":3,"n":"Param #2 - Actor Value"}]}]}]},{"n":"EFXX - Effects End Marker"},{"t":2,"n":"FULL - Name"}]}]}]},{"t":1,"p":1,"n":"KEYM - Key","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]}]},{"t":1,"p":1,"n":"LIGH - Light","c":[{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":3,"n":"SCRI - Script"},{"t":2,"n":"FULL - Name"},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Time"},{"t":3,"n":"Radius"},{"t":6,"n":"Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":3,"n":"Unused"}]},{"t":3,"n":"Flags"},{"t":5,"n":"Falloff Exponent"},{"t":5,"n":"FOV"},{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]},{"t":5,"n":"FNAM - Fade value"},{"t":3,"n":"SNAM - Sound"}]},{"t":1,"p":1,"n":"LSCR - Load Screen","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":2,"n":"DESC - Description"},{"t":8,"n":"Locations","c":[{"t":6,"n":"LNAM - Location","c":[{"t":3,"n":"Direct"},{"t":6,"n":"Indirect","c":[{"t":3,"n":"World"},{"t":6,"n":"Grid","c":[{"t":3,"n":"Y"},{"t":3,"n":"X"}]}]}]}]}]},{"t":1,"p":1,"n":"LTEX - Landscape Texture","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":6,"n":"HNAM - Havok Data","c":[{"t":3,"n":"Material Type"},{"t":3,"n":"Friction"},{"t":3,"n":"Restitution"}]},{"t":3,"n":"SNAM - Texture Specular Exponent"},{"t":8,"n":"Grasses","c":[{"t":3,"n":"GNAM - Grass"}]}]},{"t":1,"p":1,"n":"MGEF - Magic Effect","c":[{"t":2,"n":"EDID - Magic Effect Code"},{"t":6,"n":"OBME - Oblivion Magic Extender","c":[{"t":3,"n":"Record Version"},{"t":6,"n":"OBME Version","c":[{"t":3,"n":"Beta"},{"t":3,"n":"Minor"},{"t":3,"n":"Major"}]},{"t":3,"n":"Param A Info"},{"t":3,"n":"Param B Info"},{"t":11,"n":"Unused"},{"t":2,"n":"Handler"},{"t":3,"n":"Flag Overrides"},{"t":11,"n":"ParamB"}]},{"t":2,"n":"EDDX - EditorID"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":6,"n":"DATA - Data","c":[{"t":3,"n":"Flags"},{"t":5,"n":"Base cost"},{"t":3,"n":"Unused"},{"t":3,"n":"Assoc. Weapon"},{"t":3,"n":"Assoc. Armor"},{"t":3,"n":"Assoc. Creature"},{"t":3,"n":"Assoc. Actor Value"},{"t":3,"n":"Magic School"},{"t":3,"n":"Resist value"},{"t":3,"n":"Counter Effect Count"},{"t":3,"n":"Light"},{"t":5,"n":"Projectile speed"},{"t":3,"n":"Effect Shader"},{"t":3,"n":"Enchant effect"},{"t":3,"n":"Casting sound"},{"t":3,"n":"Bolt sound"},{"t":3,"n":"Hit sound"},{"t":3,"n":"Area sound"},{"t":5,"n":"Constant Effect enchantment factor"},{"t":5,"n":"Constant Effect barter factor"}]},{"t":7,"n":"ESCE - Counter Effects","c":[{"t":2,"n":"Counter Effect Code"}]}]},{"t":1,"p":1,"n":"MISC - Misc. Item","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Value"},{"t":3,"n":"Actor Value"},{"t":5,"n":"Weight"},{"t":3,"n":"Group"}]}]},{"t":1,"p":1,"n":"REGN - Region","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":6,"n":"RCLR - Map Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":3,"n":"WNAM - Worldspace"},{"t":8,"n":"Region Areas","c":[{"t":6,"n":"Region Area","c":[{"t":3,"n":"RPLI - Edge Fall-off"},{"t":7,"n":"RPLD - Region Point List Data","c":[{"t":6,"n":"Point","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"}]}]}]}]},{"t":10,"n":"Region Data Entries","c":[{"t":6,"n":"Region Data Entry","c":[{"t":6,"n":"RDAT - Data Header","c":[{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":3,"n":"Priority"},{"t":11,"n":"Unused"}]},{"t":7,"n":"RDOT - Objects","c":[{"t":6,"n":"Object","c":[{"t":3,"n":"Object"},{"t":3,"n":"Parent Index"},{"t":11,"n":"Unused"},{"t":5,"n":"Density"},{"t":3,"n":"Clustering"},{"t":3,"n":"Min Slope"},{"t":3,"n":"Max Slope"},{"t":3,"n":"Flags"},{"t":3,"n":"Radius wrt Parent"},{"t":3,"n":"Radius"},{"t":5,"n":"Min Height"},{"t":5,"n":"Max Height"},{"t":5,"n":"Sink"},{"t":5,"n":"Sink Variance"},{"t":5,"n":"Size Variance"},{"t":6,"n":"Angle Variance","c":[{"t":3,"n":"X"},{"t":3,"n":"Y"},{"t":3,"n":"Z"}]},{"t":11,"n":"Unknown"}]}]},{"t":2,"n":"RDMP - Map Name"},{"t":7,"n":"RDGS - Grasses","c":[{"t":6,"n":"Grass","c":[{"t":3,"n":"Grass"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"RDMD - Music Type"},{"t":7,"n":"RDSD - Sounds","c":[{"t":6,"n":"Sound","c":[{"t":3,"n":"Sound"},{"t":3,"n":"Flags"},{"t":3,"n":"Chance"}]}]},{"t":7,"n":"RDWT - Weather Types","c":[{"t":6,"n":"Weather Type","c":[{"t":3,"n":"Weather"},{"t":3,"n":"Chance"}]}]}]}]}]},{"t":1,"p":1,"n":"SGST - Sigil Stone","c":[{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBME - Oblivion Magic Extender","c":[{"t":3,"n":"Record Version"},{"t":6,"n":"OBME Version","c":[{"t":3,"n":"Beta"},{"t":3,"n":"Minor"},{"t":3,"n":"Major"}]},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":3,"n":"SCRI - Script"},{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":3,"n":"EFID - Magic effect name"},{"t":6,"n":"EFIT - ","c":[{"t":3,"n":"Magic effect name"},{"t":3,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"},{"t":3,"n":"Type"},{"t":3,"n":"Actor Value"}]},{"t":6,"n":"Script effect","c":[{"t":6,"n":"SCIT - Script effect data","c":[{"t":3,"n":"Script effect"},{"t":3,"n":"Magic school"},{"t":3,"n":"Visual effect name"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"}]}]},{"t":6,"n":"Effects","c":[{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":6,"n":"EFME - Oblivion Magic Extender","c":[{"t":3,"n":"Record Version"},{"t":6,"n":"OBME Version","c":[{"t":3,"n":"Beta"},{"t":3,"n":"Minor"},{"t":3,"n":"Major"}]},{"t":3,"n":"EFIT Param Info"},{"t":3,"n":"EFIX Param Info"},{"t":11,"n":"Unused"}]},{"t":2,"n":"EFID - Magic Effect Code"},{"t":6,"n":"EFIT - ","c":[{"t":2,"n":"Magic Effect Code"},{"t":3,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"},{"t":3,"n":"Type"},{"t":11,"n":"Param #1 - Unknown Type"},{"t":3,"n":"Param #1 - FormID"},{"t":2,"n":"Param #1 - Magic Effect Code"},{"t":3,"n":"Param #1 - Actor Value"}]},{"t":6,"n":"Script effect","c":[{"t":6,"n":"SCIT - Script effect data","c":[{"t":3,"n":"Script effect"},{"t":3,"n":"Magic school"},{"t":2,"n":"Visual Effect Code"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"}]},{"t":2,"n":"EFII - Icon"},{"t":6,"n":"EFIX - ","c":[{"t":3,"n":"Override Mask"},{"t":3,"n":"Flags"},{"t":5,"n":"Base Cost"},{"t":11,"n":"Param #2 - Unknown Type"},{"t":3,"n":"Param #2 - FormID"},{"t":2,"n":"Param #2 - Magic Effect Code"},{"t":3,"n":"Param #2 - Actor Value"}]}]}]},{"n":"EFXX - Effects End Marker"},{"t":2,"n":"FULL - Name"}]}]},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Uses "},{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]}]},{"t":1,"p":1,"n":"SLGM - Soul Gem","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]},{"t":3,"n":"SOUL - Contained Soul"},{"t":3,"n":"SLCP - Maximum Capacity"}]},{"t":1,"p":1,"n":"STAT - Static","c":[{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]}]},{"t":1,"p":1,"n":"TREE - Tree","c":[{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":7,"n":"SNAM - SpeedTree Seeds","c":[{"t":3,"n":"SpeedTree Seed"}]},{"t":6,"n":"CNAM - Tree Data","c":[{"t":5,"n":"Leaf Curvature"},{"t":5,"n":"Minimum Leaf Angle"},{"t":5,"n":"Maximum Leaf Angle"},{"t":5,"n":"Branch Dimming Value"},{"t":5,"n":"Leaf Dimming Value"},{"t":3,"n":"Shadow Radius"},{"t":5,"n":"Rock Speed"},{"t":5,"n":"Rustle Speed"}]},{"t":6,"n":"BNAM - Billboard Dimensions","c":[{"t":5,"n":"Width"},{"t":5,"n":"Height"}]}]},{"t":1,"p":1,"n":"WEAP - Weapon","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":3,"n":"SCRI - Script"},{"t":3,"n":"ENAM - Enchantment"},{"t":3,"n":"ANAM - Enchantment Points"},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Type"},{"t":5,"n":"Speed"},{"t":5,"n":"Reach"},{"t":3,"n":"Flags"},{"t":3,"n":"Value"},{"t":3,"n":"Health"},{"t":5,"n":"Weight"},{"t":3,"n":"Damage"}]}]},{"t":1,"p":1,"n":"ACTI - Activator","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":3,"n":"SCRI - Script"},{"t":3,"n":"SNAM - Sound"}]}]},"name":"Bash.Graphics","hash":"655B6D00","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.Hair.json ================================================ {"records":"RACE","description":"Hair tag from Wrye Bash.\r\n\r\nUsed when the mod adds hairs to races.","tree":{"records":[{"t":1,"p":1,"n":"RACE - Race","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":8,"n":"Relations","c":[{"t":6,"n":"XNAM - Relation","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Modifier"}]}]},{"t":6,"n":"DATA - ","c":[{"t":7,"n":"Skill Boosts","c":[{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]}]},{"t":11,"n":"Unused"},{"t":5,"n":"Male Height"},{"t":5,"n":"Female Height"},{"t":5,"n":"Male Weight"},{"t":5,"n":"Female Weight"},{"t":3,"n":"Flags"}]},{"t":6,"n":"VNAM - Voice","c":[{"t":3,"n":"Male"},{"t":3,"n":"Female"}]},{"t":6,"n":"DNAM - Default Hair","c":[{"t":3,"n":"Male"},{"t":3,"n":"Female"}]},{"t":3,"n":"CNAM - Default Hair Color"},{"t":5,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"n":"UNAM - FaceGen - Face clamp"},{"t":6,"n":"ATTR - Base Attributes","c":[{"t":6,"n":"Male","c":[{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":6,"n":"Female","c":[{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]}]},{"t":6,"n":"Face Data","c":[{"n":"NAM0 - Face Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"n":"NAM1 - Body Data Marker"},{"t":6,"n":"Male Body Data","c":[{"n":"MNAM - Male Body Data Marker"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"t":6,"n":"Female Body Data","c":[{"n":"FNAM - Female Body Data Marker"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"t":7,"p":1,"n":"HNAM - Hairs","c":[{"t":3,"p":1,"n":"Hair"}]},{"t":7,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eye"}]},{"t":6,"n":"FaceGen Data","c":[{"t":11,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"n":"SNAM - Unknown"}]}]},"name":"Bash.Hair","hash":"3E90E02A","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.Invent.json ================================================ {"records":"CREA,NPC_,CONT","description":"Invent tag from Wrye Bash.\r\n\r\nUsed when the mod changes inventories.","tree":{"records":[{"t":1,"p":1,"n":"CREA - Creature","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":8,"p":1,"n":"Items","d":1,"c":[{"t":6,"p":1,"n":"CNTO - Item","c":[{"t":3,"p":1,"n":"Item"},{"t":3,"p":1,"n":"Count"}]}]},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":7,"n":"NIFZ - Models","c":[{"t":2,"n":"Model"}]},{"t":11,"n":"NIFT - Texture Files Hashes"},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Base spell points"},{"t":3,"n":"Fatigue"},{"t":3,"n":"Barter gold"},{"t":3,"n":"Level (offset)"},{"t":3,"n":"Calc min"},{"t":3,"n":"Calc max"}]},{"t":8,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Buys\/Sells and Services"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":8,"n":"AI Packages","c":[{"t":3,"n":"PKID - AI Package"}]},{"t":7,"n":"KFFZ - Animations","c":[{"t":2,"n":"Animation"}]},{"t":6,"n":"DATA - Creature Data","c":[{"t":3,"n":"Type"},{"t":3,"n":"Combat Skill"},{"t":3,"n":"Magic Skill"},{"t":3,"n":"Stealth Skill"},{"t":3,"n":"Soul"},{"t":11,"n":"Unused"},{"t":3,"n":"Health"},{"t":3,"n":"Attack Damage"},{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":3,"n":"RNAM - Attack reach"},{"t":3,"n":"ZNAM - Combat Style"},{"t":5,"n":"TNAM - Turning Speed"},{"t":5,"n":"BNAM - Base Scale"},{"t":5,"n":"WNAM - Foot Weight"},{"t":2,"n":"NAM0 - Blood Spray"},{"t":2,"n":"NAM1 - Blood Decal"},{"t":3,"n":"CSCR - Inherits Sounds from"},{"t":10,"n":"Sound Types","c":[{"t":6,"n":"Sound Type","c":[{"t":3,"n":"CSDT - Type"},{"t":10,"n":"Sounds","c":[{"t":6,"n":"Sound","c":[{"t":3,"n":"CSDI - Sound"},{"t":3,"n":"CSDC - Sound Chance"}]}]}]}]}]},{"t":1,"p":1,"n":"NPC_ - Non-Player Character","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Base spell points"},{"t":3,"n":"Fatigue"},{"t":3,"n":"Barter gold"},{"t":3,"n":"Level (offset)"},{"t":3,"n":"Calc min"},{"t":3,"n":"Calc max"}]},{"t":8,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"RNAM - Race"},{"t":8,"p":1,"n":"Items","d":1,"c":[{"t":6,"p":1,"n":"CNTO - Item","c":[{"t":3,"p":1,"n":"Item"},{"t":3,"p":1,"n":"Count"}]}]},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Buys\/Sells and Services"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":8,"n":"AI Packages","c":[{"t":3,"n":"PKID - AI Package"}]},{"t":7,"n":"KFFZ - Animations","c":[{"t":2,"n":"Animation"}]},{"t":3,"n":"CNAM - Class"},{"t":6,"n":"DATA - Stats","c":[{"t":3,"n":"Armorer"},{"t":3,"n":"Athletics"},{"t":3,"n":"Blade"},{"t":3,"n":"Block"},{"t":3,"n":"Blunt"},{"t":3,"n":"Hand to Hand"},{"t":3,"n":"Heavy Armor"},{"t":3,"n":"Alchemy"},{"t":3,"n":"Alteration"},{"t":3,"n":"Conjuration"},{"t":3,"n":"Destruction"},{"t":3,"n":"Illusion"},{"t":3,"n":"Mysticism"},{"t":3,"n":"Restoration"},{"t":3,"n":"Acrobatics"},{"t":3,"n":"Light Armor"},{"t":3,"n":"Marksman"},{"t":3,"n":"Mercantile"},{"t":3,"n":"Security"},{"t":3,"n":"Sneak"},{"t":3,"n":"Speechcraft"},{"t":3,"n":"Health"},{"t":11,"n":"Unused"},{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":3,"n":"HNAM - Hair"},{"t":5,"n":"LNAM - Hair length"},{"t":7,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eyes"}]},{"t":6,"n":"HCLR - Hair color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":3,"n":"ZNAM - Combat Style"},{"t":6,"n":"FaceGen Data","c":[{"t":11,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"n":"FNAM - Unknown"}]},{"t":1,"p":1,"n":"CONT - Container","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":3,"n":"SCRI - Script"},{"t":8,"p":1,"n":"Items","d":1,"c":[{"t":6,"p":1,"n":"CNTO - Item","c":[{"t":3,"p":1,"n":"Item"},{"t":3,"p":1,"n":"Count"}]}]},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Flags"},{"t":5,"n":"Weight"}]},{"t":3,"n":"SNAM - Open sound"},{"t":3,"n":"QNAM - Close sound"}]}]},"name":"Bash.Invent","hash":"7774E3B4","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.Lev.json ================================================ {"records":"LVLC,LVSP,LVLI","description":"Base setting for Wrye Bash's leveled list handling.\r\n\r\nWhen used, leveled list entries will be merged.","tree":{"records":[{"t":1,"p":1,"n":"LVLC - Leveled Creature","c":[{"t":2,"n":"EDID - Editor ID"},{"t":3,"n":"LVLD - Chance none"},{"t":3,"n":"LVLF - Flags"},{"t":8,"p":1,"n":"Leveled List Entries","c":[{"t":6,"s":1,"p":1,"n":"LVLO - Leveled List Entry","c":[{"t":3,"n":"Level"},{"t":11,"n":"Unused"},{"t":3,"n":"Reference"},{"t":3,"n":"Count"}]}]},{"t":3,"n":"SCRI - Script"},{"t":3,"n":"TNAM - Creature template"}]},{"t":1,"p":1,"n":"LVSP - Leveled Spell","c":[{"t":2,"n":"EDID - Editor ID"},{"t":3,"n":"LVLD - Chance none"},{"t":3,"n":"LVLF - Flags"},{"t":8,"p":1,"n":"Leveled List Entries","c":[{"t":6,"s":1,"p":1,"n":"LVLO - Leveled List Entry","c":[{"t":3,"n":"Level"},{"t":11,"n":"Unused"},{"t":3,"n":"Reference"},{"t":3,"n":"Count"}]}]}]},{"t":1,"p":1,"n":"LVLI - Leveled Item","c":[{"t":2,"n":"EDID - Editor ID"},{"t":3,"n":"LVLD - Chance none"},{"t":3,"n":"LVLF - Flags"},{"t":8,"p":1,"n":"Leveled List Entries","c":[{"t":6,"s":1,"p":1,"n":"LVLO - Leveled List Entry","c":[{"t":3,"n":"Level"},{"t":11,"n":"Unused"},{"t":3,"n":"Reference"},{"t":3,"n":"Count"}]}]},{"t":11,"n":"DATA - Unused"}]}]},"name":"Bash.Lev","hash":"1AEC5FC1","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.NPC.Class.json ================================================ {"records":"NPC_","description":"NPC.Class tag from Wrye Bash.\r\n\r\nUsed when the mod changes the classes of NPCs.","tree":{"records":[{"t":1,"p":1,"n":"NPC_ - Non-Player Character","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Base spell points"},{"t":3,"n":"Fatigue"},{"t":3,"n":"Barter gold"},{"t":3,"n":"Level (offset)"},{"t":3,"n":"Calc min"},{"t":3,"n":"Calc max"}]},{"t":8,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"RNAM - Race"},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Buys\/Sells and Services"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":8,"n":"AI Packages","c":[{"t":3,"n":"PKID - AI Package"}]},{"t":7,"n":"KFFZ - Animations","c":[{"t":2,"n":"Animation"}]},{"t":3,"p":1,"n":"CNAM - Class"},{"t":6,"n":"DATA - Stats","c":[{"t":3,"n":"Armorer"},{"t":3,"n":"Athletics"},{"t":3,"n":"Blade"},{"t":3,"n":"Block"},{"t":3,"n":"Blunt"},{"t":3,"n":"Hand to Hand"},{"t":3,"n":"Heavy Armor"},{"t":3,"n":"Alchemy"},{"t":3,"n":"Alteration"},{"t":3,"n":"Conjuration"},{"t":3,"n":"Destruction"},{"t":3,"n":"Illusion"},{"t":3,"n":"Mysticism"},{"t":3,"n":"Restoration"},{"t":3,"n":"Acrobatics"},{"t":3,"n":"Light Armor"},{"t":3,"n":"Marksman"},{"t":3,"n":"Mercantile"},{"t":3,"n":"Security"},{"t":3,"n":"Sneak"},{"t":3,"n":"Speechcraft"},{"t":3,"n":"Health"},{"t":11,"n":"Unused"},{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":3,"n":"HNAM - Hair"},{"t":5,"n":"LNAM - Hair length"},{"t":7,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eyes"}]},{"t":6,"n":"HCLR - Hair color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":3,"n":"ZNAM - Combat Style"},{"t":6,"n":"FaceGen Data","c":[{"t":11,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"n":"FNAM - Unknown"}]}]},"name":"Bash.NPC.Class","hash":"C435CA64","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.NPC.Race.json ================================================ {"records":"NPC_","description":"NPC.Race tag from Wrye Bash.\r\n\r\nUsed when the mod modifies NPC races.","tree":{"records":[{"t":1,"p":1,"n":"NPC_ - Non-Player Character","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Base spell points"},{"t":3,"n":"Fatigue"},{"t":3,"n":"Barter gold"},{"t":3,"n":"Level (offset)"},{"t":3,"n":"Calc min"},{"t":3,"n":"Calc max"}]},{"t":8,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"p":1,"n":"RNAM - Race"},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Buys\/Sells and Services"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":8,"n":"AI Packages","c":[{"t":3,"n":"PKID - AI Package"}]},{"t":7,"n":"KFFZ - Animations","c":[{"t":2,"n":"Animation"}]},{"t":3,"n":"CNAM - Class"},{"t":6,"n":"DATA - Stats","c":[{"t":3,"n":"Armorer"},{"t":3,"n":"Athletics"},{"t":3,"n":"Blade"},{"t":3,"n":"Block"},{"t":3,"n":"Blunt"},{"t":3,"n":"Hand to Hand"},{"t":3,"n":"Heavy Armor"},{"t":3,"n":"Alchemy"},{"t":3,"n":"Alteration"},{"t":3,"n":"Conjuration"},{"t":3,"n":"Destruction"},{"t":3,"n":"Illusion"},{"t":3,"n":"Mysticism"},{"t":3,"n":"Restoration"},{"t":3,"n":"Acrobatics"},{"t":3,"n":"Light Armor"},{"t":3,"n":"Marksman"},{"t":3,"n":"Mercantile"},{"t":3,"n":"Security"},{"t":3,"n":"Sneak"},{"t":3,"n":"Speechcraft"},{"t":3,"n":"Health"},{"t":11,"n":"Unused"},{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":3,"n":"HNAM - Hair"},{"t":5,"n":"LNAM - Hair length"},{"t":7,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eyes"}]},{"t":6,"n":"HCLR - Hair color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":3,"n":"ZNAM - Combat Style"},{"t":6,"n":"FaceGen Data","c":[{"t":11,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"n":"FNAM - Unknown"}]}]},"name":"Bash.NPC.Race","hash":"971AC450","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.Names.json ================================================ {"records":"ALCH,AMMO,APPA,ARMO,BOOK,BSGN,CELL,CLAS,CLOT,CONT,CREA,DIAL,DOOR,ENCH,EYES,FACT,FLOR,FURN,HAIR,INGR,KEYM,LIGH,MGEF,MISC,NPC_,QUST,RACE,SGST,SLGM,SPEL,WEAP,WRLD,ACTI","description":"Names tag from Wrye Bash.\r\n\r\nUsed when the mod changes the names of things.","tree":{"records":[{"t":1,"p":1,"n":"ALCH - Potion","c":[{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBME - Oblivion Magic Extender","c":[{"t":3,"n":"Record Version"},{"t":6,"n":"OBME Version","c":[{"t":3,"n":"Beta"},{"t":3,"n":"Minor"},{"t":3,"n":"Major"}]},{"t":11,"n":"Unused"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"},{"t":3,"n":"SCRI - Script"},{"t":5,"n":"DATA - Weight"},{"t":6,"n":"ENIT - ","c":[{"t":3,"n":"Value"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":3,"n":"EFID - Magic effect name"},{"t":6,"n":"EFIT - ","c":[{"t":3,"n":"Magic effect name"},{"t":3,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"},{"t":3,"n":"Type"},{"t":3,"n":"Actor Value"}]},{"t":6,"n":"Script effect","c":[{"t":6,"n":"SCIT - Script effect data","c":[{"t":3,"n":"Script effect"},{"t":3,"n":"Magic school"},{"t":3,"n":"Visual effect name"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"}]}]},{"t":6,"n":"Effects","c":[{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":6,"n":"EFME - Oblivion Magic Extender","c":[{"t":3,"n":"Record Version"},{"t":6,"n":"OBME Version","c":[{"t":3,"n":"Beta"},{"t":3,"n":"Minor"},{"t":3,"n":"Major"}]},{"t":3,"n":"EFIT Param Info"},{"t":3,"n":"EFIX Param Info"},{"t":11,"n":"Unused"}]},{"t":2,"n":"EFID - Magic Effect Code"},{"t":6,"n":"EFIT - ","c":[{"t":2,"n":"Magic Effect Code"},{"t":3,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"},{"t":3,"n":"Type"},{"t":11,"n":"Param #1 - Unknown Type"},{"t":3,"n":"Param #1 - FormID"},{"t":2,"n":"Param #1 - Magic Effect Code"},{"t":3,"n":"Param #1 - Actor Value"}]},{"t":6,"n":"Script effect","c":[{"t":6,"n":"SCIT - Script effect data","c":[{"t":3,"n":"Script effect"},{"t":3,"n":"Magic school"},{"t":2,"n":"Visual Effect Code"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"}]},{"t":2,"n":"EFII - Icon"},{"t":6,"n":"EFIX - ","c":[{"t":3,"n":"Override Mask"},{"t":3,"n":"Flags"},{"t":5,"n":"Base Cost"},{"t":11,"n":"Param #2 - Unknown Type"},{"t":3,"n":"Param #2 - FormID"},{"t":2,"n":"Param #2 - Magic Effect Code"},{"t":3,"n":"Param #2 - Actor Value"}]}]}]},{"n":"EFXX - Effects End Marker"},{"t":2,"n":"FULL - Name"}]}]}]},{"t":1,"p":1,"n":"AMMO - Ammunition","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"},{"t":3,"n":"ENAM - Enchantment"},{"t":3,"n":"ANAM - Enchantment Points"},{"t":6,"n":"DATA - ","c":[{"t":5,"n":"Speed"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"},{"t":3,"n":"Value"},{"t":5,"n":"Weight"},{"t":3,"n":"Damage"}]}]},{"t":1,"p":1,"n":"APPA - Alchemical Apparatus","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Type"},{"t":3,"n":"Value"},{"t":5,"n":"Weight"},{"t":5,"n":"Quality"}]}]},{"t":1,"p":1,"n":"ARMO - Armor","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"SCRI - Script"},{"t":3,"n":"ENAM - Enchantment"},{"t":3,"n":"ANAM - Enchantment Points"},{"t":6,"n":"BMDT - ","c":[{"t":3,"n":"Biped Flags"},{"t":3,"n":"General Flags"},{"t":11,"n":"Unused"}]},{"t":6,"n":"Male biped model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":6,"n":"Male world model","c":[{"t":2,"n":"MOD2 - Model Filename"},{"t":5,"n":"MO2B - Bound Radius"},{"t":11,"n":"MO2T - Texture Files Hashes"}]},{"t":2,"n":"ICON - Male icon filename"},{"t":6,"n":"Female biped model","c":[{"t":2,"n":"MOD3 - Model Filename"},{"t":5,"n":"MO3B - Bound Radius"},{"t":11,"n":"MO3T - Texture Files Hashes"}]},{"t":6,"n":"Female world model","c":[{"t":2,"n":"MOD4 - Model Filename"},{"t":5,"n":"MO4B - Bound Radius"},{"t":11,"n":"MO4T - Texture Files Hashes"}]},{"t":2,"n":"ICO2 - Female icon filename"},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Armor"},{"t":3,"n":"Value"},{"t":3,"n":"Health"},{"t":5,"n":"Weight"}]}]},{"t":1,"p":1,"n":"BOOK - Book","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"},{"t":3,"n":"SCRI - Script"},{"t":3,"n":"ENAM - Enchantment"},{"t":3,"n":"ANAM - Enchantment Points"},{"t":2,"n":"DESC - Description"},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Teaches"},{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]}]},{"t":1,"p":1,"n":"BSGN - Birthsign","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"n":"ICON - Icon filename"},{"t":2,"n":"DESC - Description"},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]}]},{"t":1,"p":1,"n":"CELL - Cell","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"DATA - Flags"},{"t":6,"n":"XCLC - Grid","c":[{"t":3,"n":"X"},{"t":3,"n":"Y"}]},{"t":6,"n":"XCLL - Lighting","c":[{"t":6,"n":"Ambient Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"n":"Directional Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"n":"Fog Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"n":"Fog Near"},{"t":5,"n":"Fog Far"},{"t":3,"n":"Directional Rotation XY"},{"t":3,"n":"Directional Rotation Z"},{"t":5,"n":"Directional Fade"},{"t":5,"n":"Fog Clip Dist"}]},{"t":7,"n":"XCLR - Regions","c":[{"t":3,"n":"Region"}]},{"t":3,"n":"XCMT - Music"},{"t":5,"n":"XCLW - Water Height"},{"t":3,"n":"XCCM - Climate"},{"t":3,"n":"XCWT - Water"},{"t":6,"n":"Ownership","c":[{"t":3,"n":"XOWN - Owner"},{"t":3,"n":"XRNK - Faction rank"},{"t":3,"n":"XGLB - Global variable"}]}]},{"t":1,"p":1,"n":"CLAS - Class","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":2,"n":"ICON - Icon filename"},{"t":6,"n":"DATA - ","c":[{"t":7,"n":"Primary Attributes","c":[{"t":3,"n":"Primary Attribute"}]},{"t":3,"n":"Specialization"},{"t":7,"n":"Major Skills","c":[{"t":3,"n":"Major Skill"}]},{"t":3,"n":"Flags"},{"t":3,"n":"Buys\/Sells and Services"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":3,"n":"Unused"}]}]},{"t":1,"p":1,"n":"CLOT - Clothing","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"SCRI - Script"},{"t":3,"n":"ENAM - Enchantment"},{"t":3,"n":"ANAM - Enchantment Points"},{"t":6,"n":"BMDT - ","c":[{"t":3,"n":"Biped Flags"},{"t":3,"n":"General Flags"},{"t":11,"n":"Unused"}]},{"t":6,"n":"Male biped model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":6,"n":"Male world model","c":[{"t":2,"n":"MOD2 - Model Filename"},{"t":5,"n":"MO2B - Bound Radius"},{"t":11,"n":"MO2T - Texture Files Hashes"}]},{"t":2,"n":"ICON - Male icon filename"},{"t":6,"n":"Female biped model","c":[{"t":2,"n":"MOD3 - Model Filename"},{"t":5,"n":"MO3B - Bound Radius"},{"t":11,"n":"MO3T - Texture Files Hashes"}]},{"t":6,"n":"Female world model","c":[{"t":2,"n":"MOD4 - Model Filename"},{"t":5,"n":"MO4B - Bound Radius"},{"t":11,"n":"MO4T - Texture Files Hashes"}]},{"t":2,"n":"ICO2 - Female icon filename"},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]}]},{"t":1,"p":1,"n":"CONT - Container","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":3,"n":"SCRI - Script"},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Flags"},{"t":5,"n":"Weight"}]},{"t":3,"n":"SNAM - Open sound"},{"t":3,"n":"QNAM - Close sound"}]},{"t":1,"p":1,"n":"CREA - Creature","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":7,"n":"NIFZ - Models","c":[{"t":2,"n":"Model"}]},{"t":11,"n":"NIFT - Texture Files Hashes"},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Base spell points"},{"t":3,"n":"Fatigue"},{"t":3,"n":"Barter gold"},{"t":3,"n":"Level (offset)"},{"t":3,"n":"Calc min"},{"t":3,"n":"Calc max"}]},{"t":8,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Buys\/Sells and Services"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":8,"n":"AI Packages","c":[{"t":3,"n":"PKID - AI Package"}]},{"t":7,"n":"KFFZ - Animations","c":[{"t":2,"n":"Animation"}]},{"t":6,"n":"DATA - Creature Data","c":[{"t":3,"n":"Type"},{"t":3,"n":"Combat Skill"},{"t":3,"n":"Magic Skill"},{"t":3,"n":"Stealth Skill"},{"t":3,"n":"Soul"},{"t":11,"n":"Unused"},{"t":3,"n":"Health"},{"t":3,"n":"Attack Damage"},{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":3,"n":"RNAM - Attack reach"},{"t":3,"n":"ZNAM - Combat Style"},{"t":5,"n":"TNAM - Turning Speed"},{"t":5,"n":"BNAM - Base Scale"},{"t":5,"n":"WNAM - Foot Weight"},{"t":2,"n":"NAM0 - Blood Spray"},{"t":2,"n":"NAM1 - Blood Decal"},{"t":3,"n":"CSCR - Inherits Sounds from"},{"t":10,"n":"Sound Types","c":[{"t":6,"n":"Sound Type","c":[{"t":3,"n":"CSDT - Type"},{"t":10,"n":"Sounds","c":[{"t":6,"n":"Sound","c":[{"t":3,"n":"CSDI - Sound"},{"t":3,"n":"CSDC - Sound Chance"}]}]}]}]}]},{"t":1,"p":1,"n":"DIAL - Dialog Topic","c":[{"t":2,"n":"EDID - Editor ID"},{"t":8,"n":"Quests","c":[{"t":3,"n":"QSTI - Quest"}]},{"t":8,"n":"Quests?","c":[{"t":3,"n":"QSTR - Quest?"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"DATA - Type"}]},{"t":1,"p":1,"n":"DOOR - Door","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":3,"n":"SCRI - Script"},{"t":3,"n":"SNAM - Open sound"},{"t":3,"n":"ANAM - Close sound"},{"t":3,"n":"BNAM - Loop sound"},{"t":3,"n":"FNAM - Flags"},{"t":8,"n":"Random teleport destinations","c":[{"t":3,"n":"TNAM - Destination"}]}]},{"t":1,"p":1,"n":"ENCH - Enchantment","c":[{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBME - Oblivion Magic Extender","c":[{"t":3,"n":"Record Version"},{"t":6,"n":"OBME Version","c":[{"t":3,"n":"Beta"},{"t":3,"n":"Minor"},{"t":3,"n":"Major"}]},{"t":11,"n":"Unused"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"ENIT - ","c":[{"t":3,"n":"Type"},{"t":3,"n":"Charge Amount"},{"t":3,"n":"Enchant Cost"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":3,"n":"EFID - Magic effect name"},{"t":6,"n":"EFIT - ","c":[{"t":3,"n":"Magic effect name"},{"t":3,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"},{"t":3,"n":"Type"},{"t":3,"n":"Actor Value"}]},{"t":6,"n":"Script effect","c":[{"t":6,"n":"SCIT - Script effect data","c":[{"t":3,"n":"Script effect"},{"t":3,"n":"Magic school"},{"t":3,"n":"Visual effect name"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"}]}]},{"t":6,"n":"Effects","c":[{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":6,"n":"EFME - Oblivion Magic Extender","c":[{"t":3,"n":"Record Version"},{"t":6,"n":"OBME Version","c":[{"t":3,"n":"Beta"},{"t":3,"n":"Minor"},{"t":3,"n":"Major"}]},{"t":3,"n":"EFIT Param Info"},{"t":3,"n":"EFIX Param Info"},{"t":11,"n":"Unused"}]},{"t":2,"n":"EFID - Magic Effect Code"},{"t":6,"n":"EFIT - ","c":[{"t":2,"n":"Magic Effect Code"},{"t":3,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"},{"t":3,"n":"Type"},{"t":11,"n":"Param #1 - Unknown Type"},{"t":3,"n":"Param #1 - FormID"},{"t":2,"n":"Param #1 - Magic Effect Code"},{"t":3,"n":"Param #1 - Actor Value"}]},{"t":6,"n":"Script effect","c":[{"t":6,"n":"SCIT - Script effect data","c":[{"t":3,"n":"Script effect"},{"t":3,"n":"Magic school"},{"t":2,"n":"Visual Effect Code"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"}]},{"t":2,"n":"EFII - Icon"},{"t":6,"n":"EFIX - ","c":[{"t":3,"n":"Override Mask"},{"t":3,"n":"Flags"},{"t":5,"n":"Base Cost"},{"t":11,"n":"Param #2 - Unknown Type"},{"t":3,"n":"Param #2 - FormID"},{"t":2,"n":"Param #2 - Magic Effect Code"},{"t":3,"n":"Param #2 - Actor Value"}]}]}]},{"n":"EFXX - Effects End Marker"},{"t":2,"n":"FULL - Name"}]}]}]},{"t":1,"p":1,"n":"EYES - Eyes","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"n":"ICON - Texture"},{"t":3,"n":"DATA - Flags"}]},{"t":1,"p":1,"n":"FACT - Faction","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":8,"n":"Relations","c":[{"t":6,"n":"XNAM - Relation","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Modifier"}]}]},{"t":3,"n":"DATA - Flags"},{"t":5,"n":"CNAM - Crime Gold Multiplier"},{"t":10,"n":"Ranks","c":[{"t":6,"n":"Rank","c":[{"t":3,"n":"RNAM - Rank#"},{"t":2,"n":"MNAM - Male"},{"t":2,"n":"FNAM - Female"},{"t":2,"n":"INAM - Insignia"}]}]}]},{"t":1,"p":1,"n":"FLOR - Flora","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":3,"n":"SCRI - Script"},{"t":3,"n":"PFIG - Ingredient"},{"t":6,"n":"PFPC - Seasonal ingredient production","c":[{"t":3,"n":"Spring"},{"t":3,"n":"Summer "},{"t":3,"n":"Fall"},{"t":3,"n":"Winter"}]}]},{"t":1,"p":1,"n":"FURN - Furniture","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":3,"n":"SCRI - Script"},{"t":11,"n":"MNAM - Marker Flags"}]},{"t":1,"p":1,"n":"HAIR - Hair","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Texture"},{"t":3,"n":"DATA - Flags"}]},{"t":1,"p":1,"n":"INGR - Ingredient","c":[{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBME - Oblivion Magic Extender","c":[{"t":3,"n":"Record Version"},{"t":6,"n":"OBME Version","c":[{"t":3,"n":"Beta"},{"t":3,"n":"Minor"},{"t":3,"n":"Major"}]},{"t":11,"n":"Unused"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"},{"t":3,"n":"SCRI - Script"},{"t":5,"n":"DATA - Weight"},{"t":6,"n":"ENIT - ","c":[{"t":3,"n":"Value"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":3,"n":"EFID - Magic effect name"},{"t":6,"n":"EFIT - ","c":[{"t":3,"n":"Magic effect name"},{"t":3,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"},{"t":3,"n":"Type"},{"t":3,"n":"Actor Value"}]},{"t":6,"n":"Script effect","c":[{"t":6,"n":"SCIT - Script effect data","c":[{"t":3,"n":"Script effect"},{"t":3,"n":"Magic school"},{"t":3,"n":"Visual effect name"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"}]}]},{"t":6,"n":"Effects","c":[{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":6,"n":"EFME - Oblivion Magic Extender","c":[{"t":3,"n":"Record Version"},{"t":6,"n":"OBME Version","c":[{"t":3,"n":"Beta"},{"t":3,"n":"Minor"},{"t":3,"n":"Major"}]},{"t":3,"n":"EFIT Param Info"},{"t":3,"n":"EFIX Param Info"},{"t":11,"n":"Unused"}]},{"t":2,"n":"EFID - Magic Effect Code"},{"t":6,"n":"EFIT - ","c":[{"t":2,"n":"Magic Effect Code"},{"t":3,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"},{"t":3,"n":"Type"},{"t":11,"n":"Param #1 - Unknown Type"},{"t":3,"n":"Param #1 - FormID"},{"t":2,"n":"Param #1 - Magic Effect Code"},{"t":3,"n":"Param #1 - Actor Value"}]},{"t":6,"n":"Script effect","c":[{"t":6,"n":"SCIT - Script effect data","c":[{"t":3,"n":"Script effect"},{"t":3,"n":"Magic school"},{"t":2,"n":"Visual Effect Code"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"}]},{"t":2,"n":"EFII - Icon"},{"t":6,"n":"EFIX - ","c":[{"t":3,"n":"Override Mask"},{"t":3,"n":"Flags"},{"t":5,"n":"Base Cost"},{"t":11,"n":"Param #2 - Unknown Type"},{"t":3,"n":"Param #2 - FormID"},{"t":2,"n":"Param #2 - Magic Effect Code"},{"t":3,"n":"Param #2 - Actor Value"}]}]}]},{"n":"EFXX - Effects End Marker"},{"t":2,"n":"FULL - Name"}]}]}]},{"t":1,"p":1,"n":"KEYM - Key","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]}]},{"t":1,"p":1,"n":"LIGH - Light","c":[{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":3,"n":"SCRI - Script"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"n":"ICON - Icon filename"},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Time"},{"t":3,"n":"Radius"},{"t":6,"n":"Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":3,"n":"Unused"}]},{"t":3,"n":"Flags"},{"t":5,"n":"Falloff Exponent"},{"t":5,"n":"FOV"},{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]},{"t":5,"n":"FNAM - Fade value"},{"t":3,"n":"SNAM - Sound"}]},{"t":1,"p":1,"n":"MGEF - Magic Effect","c":[{"t":2,"n":"EDID - Magic Effect Code"},{"t":6,"n":"OBME - Oblivion Magic Extender","c":[{"t":3,"n":"Record Version"},{"t":6,"n":"OBME Version","c":[{"t":3,"n":"Beta"},{"t":3,"n":"Minor"},{"t":3,"n":"Major"}]},{"t":3,"n":"Param A Info"},{"t":3,"n":"Param B Info"},{"t":11,"n":"Unused"},{"t":2,"n":"Handler"},{"t":3,"n":"Flag Overrides"},{"t":11,"n":"ParamB"}]},{"t":2,"n":"EDDX - EditorID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":2,"n":"ICON - Icon filename"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":6,"n":"DATA - Data","c":[{"t":3,"n":"Flags"},{"t":5,"n":"Base cost"},{"t":3,"n":"Unused"},{"t":3,"n":"Assoc. Weapon"},{"t":3,"n":"Assoc. Armor"},{"t":3,"n":"Assoc. Creature"},{"t":3,"n":"Assoc. Actor Value"},{"t":3,"n":"Magic School"},{"t":3,"n":"Resist value"},{"t":3,"n":"Counter Effect Count"},{"t":3,"n":"Light"},{"t":5,"n":"Projectile speed"},{"t":3,"n":"Effect Shader"},{"t":3,"n":"Enchant effect"},{"t":3,"n":"Casting sound"},{"t":3,"n":"Bolt sound"},{"t":3,"n":"Hit sound"},{"t":3,"n":"Area sound"},{"t":5,"n":"Constant Effect enchantment factor"},{"t":5,"n":"Constant Effect barter factor"}]},{"t":7,"n":"ESCE - Counter Effects","c":[{"t":2,"n":"Counter Effect Code"}]}]},{"t":1,"p":1,"n":"MISC - Misc. Item","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Value"},{"t":3,"n":"Actor Value"},{"t":5,"n":"Weight"},{"t":3,"n":"Group"}]}]},{"t":1,"p":1,"n":"NPC_ - Non-Player Character","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Base spell points"},{"t":3,"n":"Fatigue"},{"t":3,"n":"Barter gold"},{"t":3,"n":"Level (offset)"},{"t":3,"n":"Calc min"},{"t":3,"n":"Calc max"}]},{"t":8,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"RNAM - Race"},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Buys\/Sells and Services"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":8,"n":"AI Packages","c":[{"t":3,"n":"PKID - AI Package"}]},{"t":7,"n":"KFFZ - Animations","c":[{"t":2,"n":"Animation"}]},{"t":3,"n":"CNAM - Class"},{"t":6,"n":"DATA - Stats","c":[{"t":3,"n":"Armorer"},{"t":3,"n":"Athletics"},{"t":3,"n":"Blade"},{"t":3,"n":"Block"},{"t":3,"n":"Blunt"},{"t":3,"n":"Hand to Hand"},{"t":3,"n":"Heavy Armor"},{"t":3,"n":"Alchemy"},{"t":3,"n":"Alteration"},{"t":3,"n":"Conjuration"},{"t":3,"n":"Destruction"},{"t":3,"n":"Illusion"},{"t":3,"n":"Mysticism"},{"t":3,"n":"Restoration"},{"t":3,"n":"Acrobatics"},{"t":3,"n":"Light Armor"},{"t":3,"n":"Marksman"},{"t":3,"n":"Mercantile"},{"t":3,"n":"Security"},{"t":3,"n":"Sneak"},{"t":3,"n":"Speechcraft"},{"t":3,"n":"Health"},{"t":11,"n":"Unused"},{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":3,"n":"HNAM - Hair"},{"t":5,"n":"LNAM - Hair length"},{"t":7,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eyes"}]},{"t":6,"n":"HCLR - Hair color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":3,"n":"ZNAM - Combat Style"},{"t":6,"n":"FaceGen Data","c":[{"t":11,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"n":"FNAM - Unknown"}]},{"t":1,"p":1,"n":"QUST - Quest","c":[{"t":2,"n":"EDID - Editor ID"},{"t":3,"n":"SCRI - Script"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"n":"ICON - Icon filename"},{"t":6,"n":"DATA - General","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Priority"}]},{"t":8,"n":"Conditions","c":[{"t":6,"n":"CTDA - Condition","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"n":"Comparison Value - Float"},{"t":3,"n":"Comparison Value - Global"},{"t":3,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"n":"None"},{"t":3,"n":"Integer"},{"t":3,"n":"Variable Name (INVALID)"},{"t":3,"n":"Sex"},{"t":3,"n":"Actor Value"},{"t":3,"n":"Crime Type"},{"t":3,"n":"Axis"},{"t":3,"n":"Form Type"},{"t":3,"n":"Quest Stage (INVALID)"},{"t":3,"n":"Object Reference"},{"t":3,"n":"Inventory Object"},{"t":3,"n":"Actor"},{"t":3,"n":"Quest"},{"t":3,"n":"Faction"},{"t":3,"n":"Cell"},{"t":3,"n":"Class"},{"t":3,"n":"Race"},{"t":3,"n":"Actor Base"},{"t":3,"n":"Global"},{"t":3,"n":"Weather"},{"t":3,"n":"Package"},{"t":3,"n":"Owner"},{"t":3,"n":"Birthsign"},{"t":3,"n":"Furniture"},{"t":3,"n":"Magic Item"},{"t":3,"n":"Magic Effect"},{"t":3,"n":"Worldspace"},{"t":3,"n":"Referenceable Object"},{"t":3,"n":"Variable Name"},{"t":3,"n":"Quest Stage"}]},{"t":6,"n":"CTDT - Condition (old format)","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"n":"Comparison Value - Float"},{"t":3,"n":"Comparison Value - Global"},{"t":3,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"n":"None"},{"t":3,"n":"Integer"},{"t":3,"n":"Variable Name (INVALID)"},{"t":3,"n":"Sex"},{"t":3,"n":"Actor Value"},{"t":3,"n":"Crime Type"},{"t":3,"n":"Axis"},{"t":3,"n":"Form Type"},{"t":3,"n":"Quest Stage (INVALID)"},{"t":3,"n":"Object Reference"},{"t":3,"n":"Inventory Object"},{"t":3,"n":"Actor"},{"t":3,"n":"Quest"},{"t":3,"n":"Faction"},{"t":3,"n":"Cell"},{"t":3,"n":"Class"},{"t":3,"n":"Race"},{"t":3,"n":"Actor Base"},{"t":3,"n":"Global"},{"t":3,"n":"Weather"},{"t":3,"n":"Package"},{"t":3,"n":"Owner"},{"t":3,"n":"Birthsign"},{"t":3,"n":"Furniture"},{"t":3,"n":"Magic Item"},{"t":3,"n":"Magic Effect"},{"t":3,"n":"Worldspace"},{"t":3,"n":"Referenceable Object"},{"t":3,"n":"Variable Name"},{"t":3,"n":"Quest Stage"}]}]},{"t":10,"n":"Stages","c":[{"t":6,"n":"Stage","c":[{"t":3,"n":"INDX - Stage index"},{"t":8,"n":"Log Entries","c":[{"t":6,"n":"Log Entry","c":[{"t":3,"n":"QSDT - Stage Flags"},{"t":8,"n":"Conditions","c":[{"t":6,"n":"CTDA - Condition","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"n":"Comparison Value - Float"},{"t":3,"n":"Comparison Value - Global"},{"t":3,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"n":"None"},{"t":3,"n":"Integer"},{"t":3,"n":"Variable Name (INVALID)"},{"t":3,"n":"Sex"},{"t":3,"n":"Actor Value"},{"t":3,"n":"Crime Type"},{"t":3,"n":"Axis"},{"t":3,"n":"Form Type"},{"t":3,"n":"Quest Stage (INVALID)"},{"t":3,"n":"Object Reference"},{"t":3,"n":"Inventory Object"},{"t":3,"n":"Actor"},{"t":3,"n":"Quest"},{"t":3,"n":"Faction"},{"t":3,"n":"Cell"},{"t":3,"n":"Class"},{"t":3,"n":"Race"},{"t":3,"n":"Actor Base"},{"t":3,"n":"Global"},{"t":3,"n":"Weather"},{"t":3,"n":"Package"},{"t":3,"n":"Owner"},{"t":3,"n":"Birthsign"},{"t":3,"n":"Furniture"},{"t":3,"n":"Magic Item"},{"t":3,"n":"Magic Effect"},{"t":3,"n":"Worldspace"},{"t":3,"n":"Referenceable Object"},{"t":3,"n":"Variable Name"},{"t":3,"n":"Quest Stage"}]},{"t":6,"n":"CTDT - Condition (old format)","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"n":"Comparison Value - Float"},{"t":3,"n":"Comparison Value - Global"},{"t":3,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"n":"None"},{"t":3,"n":"Integer"},{"t":3,"n":"Variable Name (INVALID)"},{"t":3,"n":"Sex"},{"t":3,"n":"Actor Value"},{"t":3,"n":"Crime Type"},{"t":3,"n":"Axis"},{"t":3,"n":"Form Type"},{"t":3,"n":"Quest Stage (INVALID)"},{"t":3,"n":"Object Reference"},{"t":3,"n":"Inventory Object"},{"t":3,"n":"Actor"},{"t":3,"n":"Quest"},{"t":3,"n":"Faction"},{"t":3,"n":"Cell"},{"t":3,"n":"Class"},{"t":3,"n":"Race"},{"t":3,"n":"Actor Base"},{"t":3,"n":"Global"},{"t":3,"n":"Weather"},{"t":3,"n":"Package"},{"t":3,"n":"Owner"},{"t":3,"n":"Birthsign"},{"t":3,"n":"Furniture"},{"t":3,"n":"Magic Item"},{"t":3,"n":"Magic Effect"},{"t":3,"n":"Worldspace"},{"t":3,"n":"Referenceable Object"},{"t":3,"n":"Variable Name"},{"t":3,"n":"Quest Stage"}]}]},{"t":2,"n":"CNAM - Log Entry"},{"t":6,"n":"Result Script","c":[{"t":6,"n":"SCHR - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"n":"RefCount"},{"t":3,"n":"CompiledSize"},{"t":3,"n":"VariableCount"},{"t":3,"n":"Type"}]},{"t":6,"n":"SCHD - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"n":"RefCount"},{"t":3,"n":"CompiledSize"},{"t":3,"n":"VariableCount"},{"t":3,"n":"Type"},{"t":11,"n":"Unknown"}]},{"t":11,"n":"SCDA - Compiled result script"},{"t":2,"n":"SCTX - Result script source"},{"t":8,"n":"References","c":[{"t":3,"n":"SCRO - Global Reference"},{"t":3,"n":"SCRV - Local Variable"}]}]}]}]}]}]},{"t":8,"n":"Targets","c":[{"t":6,"n":"Target","c":[{"t":6,"n":"QSTA - Target","c":[{"t":3,"n":"Target"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"n":"Conditions","c":[{"t":6,"n":"CTDA - Condition","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"n":"Comparison Value - Float"},{"t":3,"n":"Comparison Value - Global"},{"t":3,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"n":"None"},{"t":3,"n":"Integer"},{"t":3,"n":"Variable Name (INVALID)"},{"t":3,"n":"Sex"},{"t":3,"n":"Actor Value"},{"t":3,"n":"Crime Type"},{"t":3,"n":"Axis"},{"t":3,"n":"Form Type"},{"t":3,"n":"Quest Stage (INVALID)"},{"t":3,"n":"Object Reference"},{"t":3,"n":"Inventory Object"},{"t":3,"n":"Actor"},{"t":3,"n":"Quest"},{"t":3,"n":"Faction"},{"t":3,"n":"Cell"},{"t":3,"n":"Class"},{"t":3,"n":"Race"},{"t":3,"n":"Actor Base"},{"t":3,"n":"Global"},{"t":3,"n":"Weather"},{"t":3,"n":"Package"},{"t":3,"n":"Owner"},{"t":3,"n":"Birthsign"},{"t":3,"n":"Furniture"},{"t":3,"n":"Magic Item"},{"t":3,"n":"Magic Effect"},{"t":3,"n":"Worldspace"},{"t":3,"n":"Referenceable Object"},{"t":3,"n":"Variable Name"},{"t":3,"n":"Quest Stage"}]},{"t":6,"n":"CTDT - Condition (old format)","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"n":"Comparison Value - Float"},{"t":3,"n":"Comparison Value - Global"},{"t":3,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"n":"None"},{"t":3,"n":"Integer"},{"t":3,"n":"Variable Name (INVALID)"},{"t":3,"n":"Sex"},{"t":3,"n":"Actor Value"},{"t":3,"n":"Crime Type"},{"t":3,"n":"Axis"},{"t":3,"n":"Form Type"},{"t":3,"n":"Quest Stage (INVALID)"},{"t":3,"n":"Object Reference"},{"t":3,"n":"Inventory Object"},{"t":3,"n":"Actor"},{"t":3,"n":"Quest"},{"t":3,"n":"Faction"},{"t":3,"n":"Cell"},{"t":3,"n":"Class"},{"t":3,"n":"Race"},{"t":3,"n":"Actor Base"},{"t":3,"n":"Global"},{"t":3,"n":"Weather"},{"t":3,"n":"Package"},{"t":3,"n":"Owner"},{"t":3,"n":"Birthsign"},{"t":3,"n":"Furniture"},{"t":3,"n":"Magic Item"},{"t":3,"n":"Magic Effect"},{"t":3,"n":"Worldspace"},{"t":3,"n":"Referenceable Object"},{"t":3,"n":"Variable Name"},{"t":3,"n":"Quest Stage"}]}]}]}]}]},{"t":1,"p":1,"n":"RACE - Race","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":8,"n":"Relations","c":[{"t":6,"n":"XNAM - Relation","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Modifier"}]}]},{"t":6,"n":"DATA - ","c":[{"t":7,"n":"Skill Boosts","c":[{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]}]},{"t":11,"n":"Unused"},{"t":5,"n":"Male Height"},{"t":5,"n":"Female Height"},{"t":5,"n":"Male Weight"},{"t":5,"n":"Female Weight"},{"t":3,"n":"Flags"}]},{"t":6,"n":"VNAM - Voice","c":[{"t":3,"n":"Male"},{"t":3,"n":"Female"}]},{"t":6,"n":"DNAM - Default Hair","c":[{"t":3,"n":"Male"},{"t":3,"n":"Female"}]},{"t":3,"n":"CNAM - Default Hair Color"},{"t":5,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"n":"UNAM - FaceGen - Face clamp"},{"t":6,"n":"ATTR - Base Attributes","c":[{"t":6,"n":"Male","c":[{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":6,"n":"Female","c":[{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]}]},{"t":6,"n":"Face Data","c":[{"n":"NAM0 - Face Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"n":"NAM1 - Body Data Marker"},{"t":6,"n":"Male Body Data","c":[{"n":"MNAM - Male Body Data Marker"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"t":6,"n":"Female Body Data","c":[{"n":"FNAM - Female Body Data Marker"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"t":7,"n":"HNAM - Hairs","c":[{"t":3,"n":"Hair"}]},{"t":7,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eye"}]},{"t":6,"n":"FaceGen Data","c":[{"t":11,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"n":"SNAM - Unknown"}]},{"t":1,"p":1,"n":"SGST - Sigil Stone","c":[{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBME - Oblivion Magic Extender","c":[{"t":3,"n":"Record Version"},{"t":6,"n":"OBME Version","c":[{"t":3,"n":"Beta"},{"t":3,"n":"Minor"},{"t":3,"n":"Major"}]},{"t":11,"n":"Unused"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"},{"t":3,"n":"SCRI - Script"},{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":3,"n":"EFID - Magic effect name"},{"t":6,"n":"EFIT - ","c":[{"t":3,"n":"Magic effect name"},{"t":3,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"},{"t":3,"n":"Type"},{"t":3,"n":"Actor Value"}]},{"t":6,"n":"Script effect","c":[{"t":6,"n":"SCIT - Script effect data","c":[{"t":3,"n":"Script effect"},{"t":3,"n":"Magic school"},{"t":3,"n":"Visual effect name"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"}]}]},{"t":6,"n":"Effects","c":[{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":6,"n":"EFME - Oblivion Magic Extender","c":[{"t":3,"n":"Record Version"},{"t":6,"n":"OBME Version","c":[{"t":3,"n":"Beta"},{"t":3,"n":"Minor"},{"t":3,"n":"Major"}]},{"t":3,"n":"EFIT Param Info"},{"t":3,"n":"EFIX Param Info"},{"t":11,"n":"Unused"}]},{"t":2,"n":"EFID - Magic Effect Code"},{"t":6,"n":"EFIT - ","c":[{"t":2,"n":"Magic Effect Code"},{"t":3,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"},{"t":3,"n":"Type"},{"t":11,"n":"Param #1 - Unknown Type"},{"t":3,"n":"Param #1 - FormID"},{"t":2,"n":"Param #1 - Magic Effect Code"},{"t":3,"n":"Param #1 - Actor Value"}]},{"t":6,"n":"Script effect","c":[{"t":6,"n":"SCIT - Script effect data","c":[{"t":3,"n":"Script effect"},{"t":3,"n":"Magic school"},{"t":2,"n":"Visual Effect Code"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"}]},{"t":2,"n":"EFII - Icon"},{"t":6,"n":"EFIX - ","c":[{"t":3,"n":"Override Mask"},{"t":3,"n":"Flags"},{"t":5,"n":"Base Cost"},{"t":11,"n":"Param #2 - Unknown Type"},{"t":3,"n":"Param #2 - FormID"},{"t":2,"n":"Param #2 - Magic Effect Code"},{"t":3,"n":"Param #2 - Actor Value"}]}]}]},{"n":"EFXX - Effects End Marker"},{"t":2,"n":"FULL - Name"}]}]},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Uses "},{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]}]},{"t":1,"p":1,"n":"SLGM - Soul Gem","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]},{"t":3,"n":"SOUL - Contained Soul"},{"t":3,"n":"SLCP - Maximum Capacity"}]},{"t":1,"p":1,"n":"SPEL - Spell","c":[{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBME - Oblivion Magic Extender","c":[{"t":3,"n":"Record Version"},{"t":6,"n":"OBME Version","c":[{"t":3,"n":"Beta"},{"t":3,"n":"Minor"},{"t":3,"n":"Major"}]},{"t":11,"n":"Unused"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"SPIT - ","c":[{"t":3,"n":"Type"},{"t":3,"n":"Cost"},{"t":3,"n":"Level"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":3,"n":"EFID - Magic effect name"},{"t":6,"n":"EFIT - ","c":[{"t":3,"n":"Magic effect name"},{"t":3,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"},{"t":3,"n":"Type"},{"t":3,"n":"Actor Value"}]},{"t":6,"n":"Script effect","c":[{"t":6,"n":"SCIT - Script effect data","c":[{"t":3,"n":"Script effect"},{"t":3,"n":"Magic school"},{"t":3,"n":"Visual effect name"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"}]}]},{"t":6,"n":"Effects","c":[{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":6,"n":"EFME - Oblivion Magic Extender","c":[{"t":3,"n":"Record Version"},{"t":6,"n":"OBME Version","c":[{"t":3,"n":"Beta"},{"t":3,"n":"Minor"},{"t":3,"n":"Major"}]},{"t":3,"n":"EFIT Param Info"},{"t":3,"n":"EFIX Param Info"},{"t":11,"n":"Unused"}]},{"t":2,"n":"EFID - Magic Effect Code"},{"t":6,"n":"EFIT - ","c":[{"t":2,"n":"Magic Effect Code"},{"t":3,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"},{"t":3,"n":"Type"},{"t":11,"n":"Param #1 - Unknown Type"},{"t":3,"n":"Param #1 - FormID"},{"t":2,"n":"Param #1 - Magic Effect Code"},{"t":3,"n":"Param #1 - Actor Value"}]},{"t":6,"n":"Script effect","c":[{"t":6,"n":"SCIT - Script effect data","c":[{"t":3,"n":"Script effect"},{"t":3,"n":"Magic school"},{"t":2,"n":"Visual Effect Code"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"}]},{"t":2,"n":"EFII - Icon"},{"t":6,"n":"EFIX - ","c":[{"t":3,"n":"Override Mask"},{"t":3,"n":"Flags"},{"t":5,"n":"Base Cost"},{"t":11,"n":"Param #2 - Unknown Type"},{"t":3,"n":"Param #2 - FormID"},{"t":2,"n":"Param #2 - Magic Effect Code"},{"t":3,"n":"Param #2 - Actor Value"}]}]}]},{"n":"EFXX - Effects End Marker"},{"t":2,"n":"FULL - Name"}]}]}]},{"t":1,"p":1,"n":"WEAP - Weapon","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"},{"t":3,"n":"SCRI - Script"},{"t":3,"n":"ENAM - Enchantment"},{"t":3,"n":"ANAM - Enchantment Points"},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Type"},{"t":5,"n":"Speed"},{"t":5,"n":"Reach"},{"t":3,"n":"Flags"},{"t":3,"n":"Value"},{"t":3,"n":"Health"},{"t":5,"n":"Weight"},{"t":3,"n":"Damage"}]}]},{"t":1,"p":1,"n":"WRLD - Worldspace","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Parent","c":[{"t":3,"n":"WNAM - Worldspace"}]},{"t":3,"n":"CNAM - Climate"},{"t":3,"n":"NAM2 - Water"},{"t":2,"n":"ICON - Icon filename"},{"t":6,"n":"MNAM - Map Data","c":[{"t":6,"n":"Usable Dimensions","c":[{"t":3,"n":"X"},{"t":3,"n":"Y"}]},{"t":6,"n":"Cell Coordinates","c":[{"t":6,"n":"NW Cell","c":[{"t":3,"n":"X"},{"t":3,"n":"Y"}]},{"t":6,"n":"SE Cell","c":[{"t":3,"n":"X"},{"t":3,"n":"Y"}]}]}]},{"t":3,"n":"DATA - Flags"},{"t":6,"n":"Object Bounds","c":[{"t":6,"n":"NAM0 - Min","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"}]},{"t":6,"n":"NAM9 - Max","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"}]}]},{"t":3,"n":"SNAM - Music"},{"t":11,"n":"OFST - Offset Data"}]},{"t":1,"p":1,"n":"ACTI - Activator","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":3,"n":"SCRI - Script"},{"t":3,"n":"SNAM - Sound"}]}]},"name":"Bash.Names","hash":"C16AAD3F","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.Npc.EyesOnly.json ================================================ {"records":"NPC_","description":"Npc.HairOnly tag from Wrye Bash.\r\n\r\nUse when the mod modifies NPC eyes.","tree":{"records":[{"t":1,"p":1,"n":"NPC_ - Non-Player Character","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Base spell points"},{"t":3,"n":"Fatigue"},{"t":3,"n":"Barter gold"},{"t":3,"n":"Level (offset)"},{"t":3,"n":"Calc min"},{"t":3,"n":"Calc max"}]},{"t":8,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"RNAM - Race"},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Buys\/Sells and Services"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":8,"n":"AI Packages","c":[{"t":3,"n":"PKID - AI Package"}]},{"t":7,"n":"KFFZ - Animations","c":[{"t":2,"n":"Animation"}]},{"t":3,"n":"CNAM - Class"},{"t":6,"n":"DATA - Stats","c":[{"t":3,"n":"Armorer"},{"t":3,"n":"Athletics"},{"t":3,"n":"Blade"},{"t":3,"n":"Block"},{"t":3,"n":"Blunt"},{"t":3,"n":"Hand to Hand"},{"t":3,"n":"Heavy Armor"},{"t":3,"n":"Alchemy"},{"t":3,"n":"Alteration"},{"t":3,"n":"Conjuration"},{"t":3,"n":"Destruction"},{"t":3,"n":"Illusion"},{"t":3,"n":"Mysticism"},{"t":3,"n":"Restoration"},{"t":3,"n":"Acrobatics"},{"t":3,"n":"Light Armor"},{"t":3,"n":"Marksman"},{"t":3,"n":"Mercantile"},{"t":3,"n":"Security"},{"t":3,"n":"Sneak"},{"t":3,"n":"Speechcraft"},{"t":3,"n":"Health"},{"t":11,"n":"Unused"},{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":3,"n":"HNAM - Hair"},{"t":5,"n":"LNAM - Hair length"},{"t":7,"s":1,"p":1,"n":"ENAM - Eyes","c":[{"t":3,"p":1,"n":"Eyes"}]},{"t":6,"n":"HCLR - Hair color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":3,"n":"ZNAM - Combat Style"},{"t":6,"n":"FaceGen Data","c":[{"t":11,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"n":"FNAM - Unknown"}]}]},"name":"Bash.Npc.EyesOnly","hash":"97266C5F","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.Npc.HairOnly.json ================================================ {"records":"NPC_","description":"Npc.HairOnly tag from Wrye Bash.\r\n\r\nUse when the mod modifies NPC hair.","tree":{"records":[{"t":1,"p":1,"n":"NPC_ - Non-Player Character","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Base spell points"},{"t":3,"n":"Fatigue"},{"t":3,"n":"Barter gold"},{"t":3,"n":"Level (offset)"},{"t":3,"n":"Calc min"},{"t":3,"n":"Calc max"}]},{"t":8,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"RNAM - Race"},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Buys\/Sells and Services"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":8,"n":"AI Packages","c":[{"t":3,"n":"PKID - AI Package"}]},{"t":7,"n":"KFFZ - Animations","c":[{"t":2,"n":"Animation"}]},{"t":3,"n":"CNAM - Class"},{"t":6,"n":"DATA - Stats","c":[{"t":3,"n":"Armorer"},{"t":3,"n":"Athletics"},{"t":3,"n":"Blade"},{"t":3,"n":"Block"},{"t":3,"n":"Blunt"},{"t":3,"n":"Hand to Hand"},{"t":3,"n":"Heavy Armor"},{"t":3,"n":"Alchemy"},{"t":3,"n":"Alteration"},{"t":3,"n":"Conjuration"},{"t":3,"n":"Destruction"},{"t":3,"n":"Illusion"},{"t":3,"n":"Mysticism"},{"t":3,"n":"Restoration"},{"t":3,"n":"Acrobatics"},{"t":3,"n":"Light Armor"},{"t":3,"n":"Marksman"},{"t":3,"n":"Mercantile"},{"t":3,"n":"Security"},{"t":3,"n":"Sneak"},{"t":3,"n":"Speechcraft"},{"t":3,"n":"Health"},{"t":11,"n":"Unused"},{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":3,"p":1,"n":"HNAM - Hair"},{"t":5,"n":"LNAM - Hair length"},{"t":7,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eyes"}]},{"t":6,"n":"HCLR - Hair color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":3,"n":"ZNAM - Combat Style"},{"t":6,"n":"FaceGen Data","c":[{"t":11,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"n":"FNAM - Unknown"}]}]},"name":"Bash.Npc.HairOnly","hash":"8E1AE0C5","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.NpcFaces.json ================================================ {"records":"NPC_","description":"NpcFaces tag from Wrye Bash.\r\n\r\nUsed when the mod modifies NPC faces.","tree":{"records":[{"t":1,"p":1,"n":"NPC_ - Non-Player Character","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Base spell points"},{"t":3,"n":"Fatigue"},{"t":3,"n":"Barter gold"},{"t":3,"n":"Level (offset)"},{"t":3,"n":"Calc min"},{"t":3,"n":"Calc max"}]},{"t":8,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"RNAM - Race"},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Buys\/Sells and Services"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":8,"n":"AI Packages","c":[{"t":3,"n":"PKID - AI Package"}]},{"t":7,"n":"KFFZ - Animations","c":[{"t":2,"n":"Animation"}]},{"t":3,"n":"CNAM - Class"},{"t":6,"n":"DATA - Stats","c":[{"t":3,"n":"Armorer"},{"t":3,"n":"Athletics"},{"t":3,"n":"Blade"},{"t":3,"n":"Block"},{"t":3,"n":"Blunt"},{"t":3,"n":"Hand to Hand"},{"t":3,"n":"Heavy Armor"},{"t":3,"n":"Alchemy"},{"t":3,"n":"Alteration"},{"t":3,"n":"Conjuration"},{"t":3,"n":"Destruction"},{"t":3,"n":"Illusion"},{"t":3,"n":"Mysticism"},{"t":3,"n":"Restoration"},{"t":3,"n":"Acrobatics"},{"t":3,"n":"Light Armor"},{"t":3,"n":"Marksman"},{"t":3,"n":"Mercantile"},{"t":3,"n":"Security"},{"t":3,"n":"Sneak"},{"t":3,"n":"Speechcraft"},{"t":3,"n":"Health"},{"t":11,"n":"Unused"},{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":3,"p":1,"n":"HNAM - Hair"},{"t":5,"p":1,"n":"LNAM - Hair length"},{"t":7,"s":1,"p":1,"n":"ENAM - Eyes","c":[{"t":3,"p":1,"n":"Eyes"}]},{"t":6,"p":1,"n":"HCLR - Hair color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unused"}]},{"t":3,"n":"ZNAM - Combat Style"},{"t":6,"s":1,"p":1,"n":"FaceGen Data","c":[{"t":11,"p":1,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"p":1,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"p":1,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"p":1,"n":"FNAM - Unknown"}]}]},"name":"Bash.NpcFaces","hash":"CC68CF3A","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.NpcFacesForceFullImport.json ================================================ {"records":"NPC_","description":"NpcFacesForceFullImport tag from Wrye Bash.\r\n\r\nUsed when the mod modifies NPC faces, and you wish to import the unmodified subrecords as well as the modified subrecords.","tree":{"records":[{"t":1,"p":1,"n":"NPC_ - Non-Player Character","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Base spell points"},{"t":3,"n":"Fatigue"},{"t":3,"n":"Barter gold"},{"t":3,"n":"Level (offset)"},{"t":3,"n":"Calc min"},{"t":3,"n":"Calc max"}]},{"t":8,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"RNAM - Race"},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Buys\/Sells and Services"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":8,"n":"AI Packages","c":[{"t":3,"n":"PKID - AI Package"}]},{"t":7,"n":"KFFZ - Animations","c":[{"t":2,"n":"Animation"}]},{"t":3,"n":"CNAM - Class"},{"t":6,"n":"DATA - Stats","c":[{"t":3,"n":"Armorer"},{"t":3,"n":"Athletics"},{"t":3,"n":"Blade"},{"t":3,"n":"Block"},{"t":3,"n":"Blunt"},{"t":3,"n":"Hand to Hand"},{"t":3,"n":"Heavy Armor"},{"t":3,"n":"Alchemy"},{"t":3,"n":"Alteration"},{"t":3,"n":"Conjuration"},{"t":3,"n":"Destruction"},{"t":3,"n":"Illusion"},{"t":3,"n":"Mysticism"},{"t":3,"n":"Restoration"},{"t":3,"n":"Acrobatics"},{"t":3,"n":"Light Armor"},{"t":3,"n":"Marksman"},{"t":3,"n":"Mercantile"},{"t":3,"n":"Security"},{"t":3,"n":"Sneak"},{"t":3,"n":"Speechcraft"},{"t":3,"n":"Health"},{"t":11,"n":"Unused"},{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":3,"p":1,"n":"HNAM - Hair","lt":"LNAM - Hair length","lf":"FNAM - Unknown"},{"t":5,"p":1,"n":"LNAM - Hair length","lt":"ENAM - Eyes","lf":"HNAM - Hair"},{"t":7,"s":1,"p":1,"n":"ENAM - Eyes","c":[{"t":3,"p":1,"n":"Eyes"}],"lt":"HCLR - Hair color","lf":"LNAM - Hair length"},{"t":6,"p":1,"n":"HCLR - Hair color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unused"}],"lt":"FaceGen Data","lf":"ENAM - Eyes"},{"t":3,"n":"ZNAM - Combat Style"},{"t":6,"s":1,"p":1,"n":"FaceGen Data","c":[{"t":11,"p":1,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"p":1,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"p":1,"n":"FGTS - FaceGen Texture-Symmetric"}],"lt":"FNAM - Unknown","lf":"HCLR - Hair color"},{"t":11,"p":1,"n":"FNAM - Unknown","lt":"HNAM - Hair","lf":"FaceGen Data"}]}]},"name":"Bash.NpcFacesForceFullImport","hash":"CA166AFE","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.R.AddSpells.json ================================================ {"records":"RACE","description":"R.AddSpells tag from Wrye Bash.\r\n\r\nUsed when the mod adds spells to racial spell list(s). Either R.ChangeSpells or R.AddSpells should be used for a plugin, not both.","tree":{"records":[{"t":1,"p":1,"n":"RACE - Race","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":8,"p":1,"n":"Spells","c":[{"t":3,"p":1,"n":"SPLO - Spell"}]},{"t":8,"n":"Relations","c":[{"t":6,"n":"XNAM - Relation","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Modifier"}]}]},{"t":6,"n":"DATA - ","c":[{"t":7,"n":"Skill Boosts","c":[{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]}]},{"t":11,"n":"Unused"},{"t":5,"n":"Male Height"},{"t":5,"n":"Female Height"},{"t":5,"n":"Male Weight"},{"t":5,"n":"Female Weight"},{"t":3,"n":"Flags"}]},{"t":6,"n":"VNAM - Voice","c":[{"t":3,"n":"Male"},{"t":3,"n":"Female"}]},{"t":6,"n":"DNAM - Default Hair","c":[{"t":3,"n":"Male"},{"t":3,"n":"Female"}]},{"t":3,"n":"CNAM - Default Hair Color"},{"t":5,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"n":"UNAM - FaceGen - Face clamp"},{"t":6,"n":"ATTR - Base Attributes","c":[{"t":6,"n":"Male","c":[{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":6,"n":"Female","c":[{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]}]},{"t":6,"n":"Face Data","c":[{"n":"NAM0 - Face Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"n":"NAM1 - Body Data Marker"},{"t":6,"n":"Male Body Data","c":[{"n":"MNAM - Male Body Data Marker"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"t":6,"n":"Female Body Data","c":[{"n":"FNAM - Female Body Data Marker"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"t":7,"n":"HNAM - Hairs","c":[{"t":3,"n":"Hair"}]},{"t":7,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eye"}]},{"t":6,"n":"FaceGen Data","c":[{"t":11,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"n":"SNAM - Unknown"}]}]},"name":"Bash.R.AddSpells","hash":"8BF9489F","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.R.Attributes-F.json ================================================ {"records":"RACE","description":"R.Attributes-F tag from Wrye Bash.\r\n\r\nUse when the mod modifies racial attributes for females.","tree":{"records":[{"t":1,"p":1,"n":"RACE - Race","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":8,"n":"Relations","c":[{"t":6,"n":"XNAM - Relation","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Modifier"}]}]},{"t":6,"n":"DATA - ","c":[{"t":7,"n":"Skill Boosts","c":[{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]}]},{"t":11,"n":"Unused"},{"t":5,"n":"Male Height"},{"t":5,"n":"Female Height"},{"t":5,"n":"Male Weight"},{"t":5,"n":"Female Weight"},{"t":3,"n":"Flags"}]},{"t":6,"n":"VNAM - Voice","c":[{"t":3,"n":"Male"},{"t":3,"n":"Female"}]},{"t":6,"n":"DNAM - Default Hair","c":[{"t":3,"n":"Male"},{"t":3,"n":"Female"}]},{"t":3,"n":"CNAM - Default Hair Color"},{"t":5,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"n":"UNAM - FaceGen - Face clamp"},{"t":6,"p":1,"n":"ATTR - Base Attributes","c":[{"t":6,"n":"Male","c":[{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":6,"p":1,"n":"Female","c":[{"t":3,"p":1,"n":"Strength"},{"t":3,"p":1,"n":"Intelligence"},{"t":3,"p":1,"n":"Willpower"},{"t":3,"p":1,"n":"Agility"},{"t":3,"p":1,"n":"Speed"},{"t":3,"p":1,"n":"Endurance"},{"t":3,"p":1,"n":"Personality"},{"t":3,"p":1,"n":"Luck"}]}]},{"t":6,"n":"Face Data","c":[{"n":"NAM0 - Face Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"n":"NAM1 - Body Data Marker"},{"t":6,"n":"Male Body Data","c":[{"n":"MNAM - Male Body Data Marker"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"t":6,"n":"Female Body Data","c":[{"n":"FNAM - Female Body Data Marker"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"t":7,"n":"HNAM - Hairs","c":[{"t":3,"n":"Hair"}]},{"t":7,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eye"}]},{"t":6,"n":"FaceGen Data","c":[{"t":11,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"n":"SNAM - Unknown"}]}]},"name":"Bash.R.Attributes-F","hash":"CD64505C","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.R.Attributes-M.json ================================================ {"records":"RACE","description":"R.Attributes-M tag from Wrye Bash.\r\n\r\nUse when the mod modifies racial attributes for males.","tree":{"records":[{"t":1,"p":1,"n":"RACE - Race","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":8,"n":"Relations","c":[{"t":6,"n":"XNAM - Relation","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Modifier"}]}]},{"t":6,"n":"DATA - ","c":[{"t":7,"n":"Skill Boosts","c":[{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]}]},{"t":11,"n":"Unused"},{"t":5,"n":"Male Height"},{"t":5,"n":"Female Height"},{"t":5,"n":"Male Weight"},{"t":5,"n":"Female Weight"},{"t":3,"n":"Flags"}]},{"t":6,"n":"VNAM - Voice","c":[{"t":3,"n":"Male"},{"t":3,"n":"Female"}]},{"t":6,"n":"DNAM - Default Hair","c":[{"t":3,"n":"Male"},{"t":3,"n":"Female"}]},{"t":3,"n":"CNAM - Default Hair Color"},{"t":5,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"n":"UNAM - FaceGen - Face clamp"},{"t":6,"p":1,"n":"ATTR - Base Attributes","c":[{"t":6,"p":1,"n":"Male","c":[{"t":3,"p":1,"n":"Strength"},{"t":3,"p":1,"n":"Intelligence"},{"t":3,"p":1,"n":"Willpower"},{"t":3,"p":1,"n":"Agility"},{"t":3,"p":1,"n":"Speed"},{"t":3,"p":1,"n":"Endurance"},{"t":3,"p":1,"n":"Personality"},{"t":3,"p":1,"n":"Luck"}]},{"t":6,"n":"Female","c":[{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]}]},{"t":6,"n":"Face Data","c":[{"n":"NAM0 - Face Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"n":"NAM1 - Body Data Marker"},{"t":6,"n":"Male Body Data","c":[{"n":"MNAM - Male Body Data Marker"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"t":6,"n":"Female Body Data","c":[{"n":"FNAM - Female Body Data Marker"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"t":7,"n":"HNAM - Hairs","c":[{"t":3,"n":"Hair"}]},{"t":7,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eye"}]},{"t":6,"n":"FaceGen Data","c":[{"t":11,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"n":"SNAM - Unknown"}]}]},"name":"Bash.R.Attributes-M","hash":"424C5E7E","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.R.ChangeSpells.json ================================================ {"records":"RACE","description":"R.ChangeSpells tag from Wrye Bash.\r\n\r\nUsed when the mod modifies racial spell list(s) (beyond adding spells). Either R.ChangeSpells or R.AddSpells should be used for a plugin, not both.","tree":{"records":[{"t":1,"p":1,"n":"RACE - Race","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":8,"s":1,"p":1,"n":"Spells","c":[{"t":3,"p":1,"n":"SPLO - Spell"}]},{"t":8,"n":"Relations","c":[{"t":6,"n":"XNAM - Relation","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Modifier"}]}]},{"t":6,"n":"DATA - ","c":[{"t":7,"n":"Skill Boosts","c":[{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]}]},{"t":11,"n":"Unused"},{"t":5,"n":"Male Height"},{"t":5,"n":"Female Height"},{"t":5,"n":"Male Weight"},{"t":5,"n":"Female Weight"},{"t":3,"n":"Flags"}]},{"t":6,"n":"VNAM - Voice","c":[{"t":3,"n":"Male"},{"t":3,"n":"Female"}]},{"t":6,"n":"DNAM - Default Hair","c":[{"t":3,"n":"Male"},{"t":3,"n":"Female"}]},{"t":3,"n":"CNAM - Default Hair Color"},{"t":5,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"n":"UNAM - FaceGen - Face clamp"},{"t":6,"n":"ATTR - Base Attributes","c":[{"t":6,"n":"Male","c":[{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":6,"n":"Female","c":[{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]}]},{"t":6,"n":"Face Data","c":[{"n":"NAM0 - Face Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"n":"NAM1 - Body Data Marker"},{"t":6,"n":"Male Body Data","c":[{"n":"MNAM - Male Body Data Marker"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"t":6,"n":"Female Body Data","c":[{"n":"FNAM - Female Body Data Marker"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"t":7,"n":"HNAM - Hairs","c":[{"t":3,"n":"Hair"}]},{"t":7,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eye"}]},{"t":6,"n":"FaceGen Data","c":[{"t":11,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"n":"SNAM - Unknown"}]}]},"name":"Bash.R.ChangeSpells","hash":"0AB33E74","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.R.Description.json ================================================ {"records":"RACE","description":"R.Description tag from Wrye Bash.\r\n\r\nUsed when the mod modifies race descriptions.","tree":{"records":[{"t":1,"p":1,"n":"RACE - Race","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":2,"p":1,"n":"DESC - Description"},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":8,"n":"Relations","c":[{"t":6,"n":"XNAM - Relation","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Modifier"}]}]},{"t":6,"n":"DATA - ","c":[{"t":7,"n":"Skill Boosts","c":[{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]}]},{"t":11,"n":"Unused"},{"t":5,"n":"Male Height"},{"t":5,"n":"Female Height"},{"t":5,"n":"Male Weight"},{"t":5,"n":"Female Weight"},{"t":3,"n":"Flags"}]},{"t":6,"n":"VNAM - Voice","c":[{"t":3,"n":"Male"},{"t":3,"n":"Female"}]},{"t":6,"n":"DNAM - Default Hair","c":[{"t":3,"n":"Male"},{"t":3,"n":"Female"}]},{"t":3,"n":"CNAM - Default Hair Color"},{"t":5,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"n":"UNAM - FaceGen - Face clamp"},{"t":6,"n":"ATTR - Base Attributes","c":[{"t":6,"n":"Male","c":[{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":6,"n":"Female","c":[{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]}]},{"t":6,"n":"Face Data","c":[{"n":"NAM0 - Face Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"n":"NAM1 - Body Data Marker"},{"t":6,"n":"Male Body Data","c":[{"n":"MNAM - Male Body Data Marker"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"t":6,"n":"Female Body Data","c":[{"n":"FNAM - Female Body Data Marker"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"t":7,"n":"HNAM - Hairs","c":[{"t":3,"n":"Hair"}]},{"t":7,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eye"}]},{"t":6,"n":"FaceGen Data","c":[{"t":11,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"n":"SNAM - Unknown"}]}]},"name":"Bash.R.Description","hash":"73C945FB","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.Relations.json ================================================ {"records":"FACT","description":"Relations tag from Wrye Bash.\r\n\r\nUsed when the mod modifies faction relationships.","tree":{"records":[{"t":1,"p":1,"n":"FACT - Faction","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":8,"p":1,"n":"Relations","d":1,"c":[{"t":6,"p":1,"n":"XNAM - Relation","c":[{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Modifier"}]}]},{"t":3,"n":"DATA - Flags"},{"t":5,"n":"CNAM - Crime Gold Multiplier"},{"t":10,"n":"Ranks","c":[{"t":6,"n":"Rank","c":[{"t":3,"n":"RNAM - Rank#"},{"t":2,"n":"MNAM - Male"},{"t":2,"n":"FNAM - Female"},{"t":2,"n":"INAM - Insignia"}]}]}]}]},"name":"Bash.Relations","hash":"43A8A464","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.Scripts.json ================================================ {"records":"ALCH,APPA,ARMO,BOOK,CLOT,CONT,CREA,DOOR,FLOR,FURN,INGR,KEYM,LIGH,LVLC,MISC,NPC_,QUST,SGST,SLGM,WEAP,ACTI","description":"Scripts tag from Wrye Bash.\r\n\r\nUsed when the mod modifies item, NPC or object scripts.","tree":{"records":[{"t":1,"p":1,"n":"ALCH - Potion","c":[{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBME - Oblivion Magic Extender","c":[{"t":3,"n":"Record Version"},{"t":6,"n":"OBME Version","c":[{"t":3,"n":"Beta"},{"t":3,"n":"Minor"},{"t":3,"n":"Major"}]},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"},{"t":3,"p":1,"n":"SCRI - Script"},{"t":5,"n":"DATA - Weight"},{"t":6,"n":"ENIT - ","c":[{"t":3,"n":"Value"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":3,"n":"EFID - Magic effect name"},{"t":6,"n":"EFIT - ","c":[{"t":3,"n":"Magic effect name"},{"t":3,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"},{"t":3,"n":"Type"},{"t":3,"n":"Actor Value"}]},{"t":6,"n":"Script effect","c":[{"t":6,"n":"SCIT - Script effect data","c":[{"t":3,"n":"Script effect"},{"t":3,"n":"Magic school"},{"t":3,"n":"Visual effect name"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"}]}]},{"t":6,"n":"Effects","c":[{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":6,"n":"EFME - Oblivion Magic Extender","c":[{"t":3,"n":"Record Version"},{"t":6,"n":"OBME Version","c":[{"t":3,"n":"Beta"},{"t":3,"n":"Minor"},{"t":3,"n":"Major"}]},{"t":3,"n":"EFIT Param Info"},{"t":3,"n":"EFIX Param Info"},{"t":11,"n":"Unused"}]},{"t":2,"n":"EFID - Magic Effect Code"},{"t":6,"n":"EFIT - ","c":[{"t":2,"n":"Magic Effect Code"},{"t":3,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"},{"t":3,"n":"Type"},{"t":11,"n":"Param #1 - Unknown Type"},{"t":3,"n":"Param #1 - FormID"},{"t":2,"n":"Param #1 - Magic Effect Code"},{"t":3,"n":"Param #1 - Actor Value"}]},{"t":6,"n":"Script effect","c":[{"t":6,"n":"SCIT - Script effect data","c":[{"t":3,"n":"Script effect"},{"t":3,"n":"Magic school"},{"t":2,"n":"Visual Effect Code"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"}]},{"t":2,"n":"EFII - Icon"},{"t":6,"n":"EFIX - ","c":[{"t":3,"n":"Override Mask"},{"t":3,"n":"Flags"},{"t":5,"n":"Base Cost"},{"t":11,"n":"Param #2 - Unknown Type"},{"t":3,"n":"Param #2 - FormID"},{"t":2,"n":"Param #2 - Magic Effect Code"},{"t":3,"n":"Param #2 - Actor Value"}]}]}]},{"n":"EFXX - Effects End Marker"},{"t":2,"n":"FULL - Name"}]}]}]},{"t":1,"p":1,"n":"APPA - Alchemical Apparatus","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"},{"t":3,"p":1,"n":"SCRI - Script"},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Type"},{"t":3,"n":"Value"},{"t":5,"n":"Weight"},{"t":5,"n":"Quality"}]}]},{"t":1,"p":1,"n":"ARMO - Armor","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":3,"p":1,"n":"SCRI - Script"},{"t":3,"n":"ENAM - Enchantment"},{"t":3,"n":"ANAM - Enchantment Points"},{"t":6,"n":"BMDT - ","c":[{"t":3,"n":"Biped Flags"},{"t":3,"n":"General Flags"},{"t":11,"n":"Unused"}]},{"t":6,"n":"Male biped model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":6,"n":"Male world model","c":[{"t":2,"n":"MOD2 - Model Filename"},{"t":5,"n":"MO2B - Bound Radius"},{"t":11,"n":"MO2T - Texture Files Hashes"}]},{"t":2,"n":"ICON - Male icon filename"},{"t":6,"n":"Female biped model","c":[{"t":2,"n":"MOD3 - Model Filename"},{"t":5,"n":"MO3B - Bound Radius"},{"t":11,"n":"MO3T - Texture Files Hashes"}]},{"t":6,"n":"Female world model","c":[{"t":2,"n":"MOD4 - Model Filename"},{"t":5,"n":"MO4B - Bound Radius"},{"t":11,"n":"MO4T - Texture Files Hashes"}]},{"t":2,"n":"ICO2 - Female icon filename"},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Armor"},{"t":3,"n":"Value"},{"t":3,"n":"Health"},{"t":5,"n":"Weight"}]}]},{"t":1,"p":1,"n":"BOOK - Book","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"},{"t":3,"p":1,"n":"SCRI - Script"},{"t":3,"n":"ENAM - Enchantment"},{"t":3,"n":"ANAM - Enchantment Points"},{"t":2,"n":"DESC - Description"},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Teaches"},{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]}]},{"t":1,"p":1,"n":"CLOT - Clothing","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":3,"p":1,"n":"SCRI - Script"},{"t":3,"n":"ENAM - Enchantment"},{"t":3,"n":"ANAM - Enchantment Points"},{"t":6,"n":"BMDT - ","c":[{"t":3,"n":"Biped Flags"},{"t":3,"n":"General Flags"},{"t":11,"n":"Unused"}]},{"t":6,"n":"Male biped model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":6,"n":"Male world model","c":[{"t":2,"n":"MOD2 - Model Filename"},{"t":5,"n":"MO2B - Bound Radius"},{"t":11,"n":"MO2T - Texture Files Hashes"}]},{"t":2,"n":"ICON - Male icon filename"},{"t":6,"n":"Female biped model","c":[{"t":2,"n":"MOD3 - Model Filename"},{"t":5,"n":"MO3B - Bound Radius"},{"t":11,"n":"MO3T - Texture Files Hashes"}]},{"t":6,"n":"Female world model","c":[{"t":2,"n":"MOD4 - Model Filename"},{"t":5,"n":"MO4B - Bound Radius"},{"t":11,"n":"MO4T - Texture Files Hashes"}]},{"t":2,"n":"ICO2 - Female icon filename"},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]}]},{"t":1,"p":1,"n":"CONT - Container","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Flags"},{"t":5,"n":"Weight"}]},{"t":3,"n":"SNAM - Open sound"},{"t":3,"n":"QNAM - Close sound"}]},{"t":1,"p":1,"n":"CREA - Creature","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":7,"n":"NIFZ - Models","c":[{"t":2,"n":"Model"}]},{"t":11,"n":"NIFT - Texture Files Hashes"},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Base spell points"},{"t":3,"n":"Fatigue"},{"t":3,"n":"Barter gold"},{"t":3,"n":"Level (offset)"},{"t":3,"n":"Calc min"},{"t":3,"n":"Calc max"}]},{"t":8,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"p":1,"n":"SCRI - Script"},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Buys\/Sells and Services"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":8,"n":"AI Packages","c":[{"t":3,"n":"PKID - AI Package"}]},{"t":7,"n":"KFFZ - Animations","c":[{"t":2,"n":"Animation"}]},{"t":6,"n":"DATA - Creature Data","c":[{"t":3,"n":"Type"},{"t":3,"n":"Combat Skill"},{"t":3,"n":"Magic Skill"},{"t":3,"n":"Stealth Skill"},{"t":3,"n":"Soul"},{"t":11,"n":"Unused"},{"t":3,"n":"Health"},{"t":3,"n":"Attack Damage"},{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":3,"n":"RNAM - Attack reach"},{"t":3,"n":"ZNAM - Combat Style"},{"t":5,"n":"TNAM - Turning Speed"},{"t":5,"n":"BNAM - Base Scale"},{"t":5,"n":"WNAM - Foot Weight"},{"t":2,"n":"NAM0 - Blood Spray"},{"t":2,"n":"NAM1 - Blood Decal"},{"t":3,"n":"CSCR - Inherits Sounds from"},{"t":10,"n":"Sound Types","c":[{"t":6,"n":"Sound Type","c":[{"t":3,"n":"CSDT - Type"},{"t":10,"n":"Sounds","c":[{"t":6,"n":"Sound","c":[{"t":3,"n":"CSDI - Sound"},{"t":3,"n":"CSDC - Sound Chance"}]}]}]}]}]},{"t":1,"p":1,"n":"DOOR - Door","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":3,"n":"SNAM - Open sound"},{"t":3,"n":"ANAM - Close sound"},{"t":3,"n":"BNAM - Loop sound"},{"t":3,"n":"FNAM - Flags"},{"t":8,"n":"Random teleport destinations","c":[{"t":3,"n":"TNAM - Destination"}]}]},{"t":1,"p":1,"n":"FLOR - Flora","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":3,"n":"PFIG - Ingredient"},{"t":6,"n":"PFPC - Seasonal ingredient production","c":[{"t":3,"n":"Spring"},{"t":3,"n":"Summer "},{"t":3,"n":"Fall"},{"t":3,"n":"Winter"}]}]},{"t":1,"p":1,"n":"FURN - Furniture","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":11,"n":"MNAM - Marker Flags"}]},{"t":1,"p":1,"n":"INGR - Ingredient","c":[{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBME - Oblivion Magic Extender","c":[{"t":3,"n":"Record Version"},{"t":6,"n":"OBME Version","c":[{"t":3,"n":"Beta"},{"t":3,"n":"Minor"},{"t":3,"n":"Major"}]},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"},{"t":3,"p":1,"n":"SCRI - Script"},{"t":5,"n":"DATA - Weight"},{"t":6,"n":"ENIT - ","c":[{"t":3,"n":"Value"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":3,"n":"EFID - Magic effect name"},{"t":6,"n":"EFIT - ","c":[{"t":3,"n":"Magic effect name"},{"t":3,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"},{"t":3,"n":"Type"},{"t":3,"n":"Actor Value"}]},{"t":6,"n":"Script effect","c":[{"t":6,"n":"SCIT - Script effect data","c":[{"t":3,"n":"Script effect"},{"t":3,"n":"Magic school"},{"t":3,"n":"Visual effect name"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"}]}]},{"t":6,"n":"Effects","c":[{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":6,"n":"EFME - Oblivion Magic Extender","c":[{"t":3,"n":"Record Version"},{"t":6,"n":"OBME Version","c":[{"t":3,"n":"Beta"},{"t":3,"n":"Minor"},{"t":3,"n":"Major"}]},{"t":3,"n":"EFIT Param Info"},{"t":3,"n":"EFIX Param Info"},{"t":11,"n":"Unused"}]},{"t":2,"n":"EFID - Magic Effect Code"},{"t":6,"n":"EFIT - ","c":[{"t":2,"n":"Magic Effect Code"},{"t":3,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"},{"t":3,"n":"Type"},{"t":11,"n":"Param #1 - Unknown Type"},{"t":3,"n":"Param #1 - FormID"},{"t":2,"n":"Param #1 - Magic Effect Code"},{"t":3,"n":"Param #1 - Actor Value"}]},{"t":6,"n":"Script effect","c":[{"t":6,"n":"SCIT - Script effect data","c":[{"t":3,"n":"Script effect"},{"t":3,"n":"Magic school"},{"t":2,"n":"Visual Effect Code"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"}]},{"t":2,"n":"EFII - Icon"},{"t":6,"n":"EFIX - ","c":[{"t":3,"n":"Override Mask"},{"t":3,"n":"Flags"},{"t":5,"n":"Base Cost"},{"t":11,"n":"Param #2 - Unknown Type"},{"t":3,"n":"Param #2 - FormID"},{"t":2,"n":"Param #2 - Magic Effect Code"},{"t":3,"n":"Param #2 - Actor Value"}]}]}]},{"n":"EFXX - Effects End Marker"},{"t":2,"n":"FULL - Name"}]}]}]},{"t":1,"p":1,"n":"KEYM - Key","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"},{"t":3,"p":1,"n":"SCRI - Script"},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]}]},{"t":1,"p":1,"n":"LIGH - Light","c":[{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"ICON - Icon filename"},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Time"},{"t":3,"n":"Radius"},{"t":6,"n":"Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":3,"n":"Unused"}]},{"t":3,"n":"Flags"},{"t":5,"n":"Falloff Exponent"},{"t":5,"n":"FOV"},{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]},{"t":5,"n":"FNAM - Fade value"},{"t":3,"n":"SNAM - Sound"}]},{"t":1,"p":1,"n":"LVLC - Leveled Creature","c":[{"t":2,"n":"EDID - Editor ID"},{"t":3,"n":"LVLD - Chance none"},{"t":3,"n":"LVLF - Flags"},{"t":8,"n":"Leveled List Entries","c":[{"t":6,"n":"LVLO - Leveled List Entry","c":[{"t":3,"n":"Level"},{"t":11,"n":"Unused"},{"t":3,"n":"Reference"},{"t":3,"n":"Count"}]}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":3,"n":"TNAM - Creature template"}]},{"t":1,"p":1,"n":"MISC - Misc. Item","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"},{"t":3,"p":1,"n":"SCRI - Script"},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Value"},{"t":3,"n":"Actor Value"},{"t":5,"n":"Weight"},{"t":3,"n":"Group"}]}]},{"t":1,"p":1,"n":"NPC_ - Non-Player Character","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Base spell points"},{"t":3,"n":"Fatigue"},{"t":3,"n":"Barter gold"},{"t":3,"n":"Level (offset)"},{"t":3,"n":"Calc min"},{"t":3,"n":"Calc max"}]},{"t":8,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"RNAM - Race"},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Buys\/Sells and Services"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":8,"n":"AI Packages","c":[{"t":3,"n":"PKID - AI Package"}]},{"t":7,"n":"KFFZ - Animations","c":[{"t":2,"n":"Animation"}]},{"t":3,"n":"CNAM - Class"},{"t":6,"n":"DATA - Stats","c":[{"t":3,"n":"Armorer"},{"t":3,"n":"Athletics"},{"t":3,"n":"Blade"},{"t":3,"n":"Block"},{"t":3,"n":"Blunt"},{"t":3,"n":"Hand to Hand"},{"t":3,"n":"Heavy Armor"},{"t":3,"n":"Alchemy"},{"t":3,"n":"Alteration"},{"t":3,"n":"Conjuration"},{"t":3,"n":"Destruction"},{"t":3,"n":"Illusion"},{"t":3,"n":"Mysticism"},{"t":3,"n":"Restoration"},{"t":3,"n":"Acrobatics"},{"t":3,"n":"Light Armor"},{"t":3,"n":"Marksman"},{"t":3,"n":"Mercantile"},{"t":3,"n":"Security"},{"t":3,"n":"Sneak"},{"t":3,"n":"Speechcraft"},{"t":3,"n":"Health"},{"t":11,"n":"Unused"},{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":3,"n":"HNAM - Hair"},{"t":5,"n":"LNAM - Hair length"},{"t":7,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eyes"}]},{"t":6,"n":"HCLR - Hair color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":3,"n":"ZNAM - Combat Style"},{"t":6,"n":"FaceGen Data","c":[{"t":11,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"n":"FNAM - Unknown"}]},{"t":1,"p":1,"n":"QUST - Quest","c":[{"t":2,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"SCRI - Script"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"ICON - Icon filename"},{"t":6,"n":"DATA - General","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Priority"}]},{"t":8,"n":"Conditions","c":[{"t":6,"n":"CTDA - Condition","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"n":"Comparison Value - Float"},{"t":3,"n":"Comparison Value - Global"},{"t":3,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"n":"None"},{"t":3,"n":"Integer"},{"t":3,"n":"Variable Name (INVALID)"},{"t":3,"n":"Sex"},{"t":3,"n":"Actor Value"},{"t":3,"n":"Crime Type"},{"t":3,"n":"Axis"},{"t":3,"n":"Form Type"},{"t":3,"n":"Quest Stage (INVALID)"},{"t":3,"n":"Object Reference"},{"t":3,"n":"Inventory Object"},{"t":3,"n":"Actor"},{"t":3,"n":"Quest"},{"t":3,"n":"Faction"},{"t":3,"n":"Cell"},{"t":3,"n":"Class"},{"t":3,"n":"Race"},{"t":3,"n":"Actor Base"},{"t":3,"n":"Global"},{"t":3,"n":"Weather"},{"t":3,"n":"Package"},{"t":3,"n":"Owner"},{"t":3,"n":"Birthsign"},{"t":3,"n":"Furniture"},{"t":3,"n":"Magic Item"},{"t":3,"n":"Magic Effect"},{"t":3,"n":"Worldspace"},{"t":3,"n":"Referenceable Object"},{"t":3,"n":"Variable Name"},{"t":3,"n":"Quest Stage"}]},{"t":6,"n":"CTDT - Condition (old format)","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"n":"Comparison Value - Float"},{"t":3,"n":"Comparison Value - Global"},{"t":3,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"n":"None"},{"t":3,"n":"Integer"},{"t":3,"n":"Variable Name (INVALID)"},{"t":3,"n":"Sex"},{"t":3,"n":"Actor Value"},{"t":3,"n":"Crime Type"},{"t":3,"n":"Axis"},{"t":3,"n":"Form Type"},{"t":3,"n":"Quest Stage (INVALID)"},{"t":3,"n":"Object Reference"},{"t":3,"n":"Inventory Object"},{"t":3,"n":"Actor"},{"t":3,"n":"Quest"},{"t":3,"n":"Faction"},{"t":3,"n":"Cell"},{"t":3,"n":"Class"},{"t":3,"n":"Race"},{"t":3,"n":"Actor Base"},{"t":3,"n":"Global"},{"t":3,"n":"Weather"},{"t":3,"n":"Package"},{"t":3,"n":"Owner"},{"t":3,"n":"Birthsign"},{"t":3,"n":"Furniture"},{"t":3,"n":"Magic Item"},{"t":3,"n":"Magic Effect"},{"t":3,"n":"Worldspace"},{"t":3,"n":"Referenceable Object"},{"t":3,"n":"Variable Name"},{"t":3,"n":"Quest Stage"}]}]},{"t":10,"n":"Stages","c":[{"t":6,"n":"Stage","c":[{"t":3,"n":"INDX - Stage index"},{"t":8,"n":"Log Entries","c":[{"t":6,"n":"Log Entry","c":[{"t":3,"n":"QSDT - Stage Flags"},{"t":8,"n":"Conditions","c":[{"t":6,"n":"CTDA - Condition","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"n":"Comparison Value - Float"},{"t":3,"n":"Comparison Value - Global"},{"t":3,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"n":"None"},{"t":3,"n":"Integer"},{"t":3,"n":"Variable Name (INVALID)"},{"t":3,"n":"Sex"},{"t":3,"n":"Actor Value"},{"t":3,"n":"Crime Type"},{"t":3,"n":"Axis"},{"t":3,"n":"Form Type"},{"t":3,"n":"Quest Stage (INVALID)"},{"t":3,"n":"Object Reference"},{"t":3,"n":"Inventory Object"},{"t":3,"n":"Actor"},{"t":3,"n":"Quest"},{"t":3,"n":"Faction"},{"t":3,"n":"Cell"},{"t":3,"n":"Class"},{"t":3,"n":"Race"},{"t":3,"n":"Actor Base"},{"t":3,"n":"Global"},{"t":3,"n":"Weather"},{"t":3,"n":"Package"},{"t":3,"n":"Owner"},{"t":3,"n":"Birthsign"},{"t":3,"n":"Furniture"},{"t":3,"n":"Magic Item"},{"t":3,"n":"Magic Effect"},{"t":3,"n":"Worldspace"},{"t":3,"n":"Referenceable Object"},{"t":3,"n":"Variable Name"},{"t":3,"n":"Quest Stage"}]},{"t":6,"n":"CTDT - Condition (old format)","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"n":"Comparison Value - Float"},{"t":3,"n":"Comparison Value - Global"},{"t":3,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"n":"None"},{"t":3,"n":"Integer"},{"t":3,"n":"Variable Name (INVALID)"},{"t":3,"n":"Sex"},{"t":3,"n":"Actor Value"},{"t":3,"n":"Crime Type"},{"t":3,"n":"Axis"},{"t":3,"n":"Form Type"},{"t":3,"n":"Quest Stage (INVALID)"},{"t":3,"n":"Object Reference"},{"t":3,"n":"Inventory Object"},{"t":3,"n":"Actor"},{"t":3,"n":"Quest"},{"t":3,"n":"Faction"},{"t":3,"n":"Cell"},{"t":3,"n":"Class"},{"t":3,"n":"Race"},{"t":3,"n":"Actor Base"},{"t":3,"n":"Global"},{"t":3,"n":"Weather"},{"t":3,"n":"Package"},{"t":3,"n":"Owner"},{"t":3,"n":"Birthsign"},{"t":3,"n":"Furniture"},{"t":3,"n":"Magic Item"},{"t":3,"n":"Magic Effect"},{"t":3,"n":"Worldspace"},{"t":3,"n":"Referenceable Object"},{"t":3,"n":"Variable Name"},{"t":3,"n":"Quest Stage"}]}]},{"t":2,"n":"CNAM - Log Entry"},{"t":6,"n":"Result Script","c":[{"t":6,"n":"SCHR - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"n":"RefCount"},{"t":3,"n":"CompiledSize"},{"t":3,"n":"VariableCount"},{"t":3,"n":"Type"}]},{"t":6,"n":"SCHD - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"n":"RefCount"},{"t":3,"n":"CompiledSize"},{"t":3,"n":"VariableCount"},{"t":3,"n":"Type"},{"t":11,"n":"Unknown"}]},{"t":11,"n":"SCDA - Compiled result script"},{"t":2,"n":"SCTX - Result script source"},{"t":8,"n":"References","c":[{"t":3,"n":"SCRO - Global Reference"},{"t":3,"n":"SCRV - Local Variable"}]}]}]}]}]}]},{"t":8,"n":"Targets","c":[{"t":6,"n":"Target","c":[{"t":6,"n":"QSTA - Target","c":[{"t":3,"n":"Target"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"n":"Conditions","c":[{"t":6,"n":"CTDA - Condition","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"n":"Comparison Value - Float"},{"t":3,"n":"Comparison Value - Global"},{"t":3,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"n":"None"},{"t":3,"n":"Integer"},{"t":3,"n":"Variable Name (INVALID)"},{"t":3,"n":"Sex"},{"t":3,"n":"Actor Value"},{"t":3,"n":"Crime Type"},{"t":3,"n":"Axis"},{"t":3,"n":"Form Type"},{"t":3,"n":"Quest Stage (INVALID)"},{"t":3,"n":"Object Reference"},{"t":3,"n":"Inventory Object"},{"t":3,"n":"Actor"},{"t":3,"n":"Quest"},{"t":3,"n":"Faction"},{"t":3,"n":"Cell"},{"t":3,"n":"Class"},{"t":3,"n":"Race"},{"t":3,"n":"Actor Base"},{"t":3,"n":"Global"},{"t":3,"n":"Weather"},{"t":3,"n":"Package"},{"t":3,"n":"Owner"},{"t":3,"n":"Birthsign"},{"t":3,"n":"Furniture"},{"t":3,"n":"Magic Item"},{"t":3,"n":"Magic Effect"},{"t":3,"n":"Worldspace"},{"t":3,"n":"Referenceable Object"},{"t":3,"n":"Variable Name"},{"t":3,"n":"Quest Stage"}]},{"t":6,"n":"CTDT - Condition (old format)","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"n":"Comparison Value - Float"},{"t":3,"n":"Comparison Value - Global"},{"t":3,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"n":"None"},{"t":3,"n":"Integer"},{"t":3,"n":"Variable Name (INVALID)"},{"t":3,"n":"Sex"},{"t":3,"n":"Actor Value"},{"t":3,"n":"Crime Type"},{"t":3,"n":"Axis"},{"t":3,"n":"Form Type"},{"t":3,"n":"Quest Stage (INVALID)"},{"t":3,"n":"Object Reference"},{"t":3,"n":"Inventory Object"},{"t":3,"n":"Actor"},{"t":3,"n":"Quest"},{"t":3,"n":"Faction"},{"t":3,"n":"Cell"},{"t":3,"n":"Class"},{"t":3,"n":"Race"},{"t":3,"n":"Actor Base"},{"t":3,"n":"Global"},{"t":3,"n":"Weather"},{"t":3,"n":"Package"},{"t":3,"n":"Owner"},{"t":3,"n":"Birthsign"},{"t":3,"n":"Furniture"},{"t":3,"n":"Magic Item"},{"t":3,"n":"Magic Effect"},{"t":3,"n":"Worldspace"},{"t":3,"n":"Referenceable Object"},{"t":3,"n":"Variable Name"},{"t":3,"n":"Quest Stage"}]}]}]}]}]},{"t":1,"p":1,"n":"SGST - Sigil Stone","c":[{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBME - Oblivion Magic Extender","c":[{"t":3,"n":"Record Version"},{"t":6,"n":"OBME Version","c":[{"t":3,"n":"Beta"},{"t":3,"n":"Minor"},{"t":3,"n":"Major"}]},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"},{"t":3,"p":1,"n":"SCRI - Script"},{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":3,"n":"EFID - Magic effect name"},{"t":6,"n":"EFIT - ","c":[{"t":3,"n":"Magic effect name"},{"t":3,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"},{"t":3,"n":"Type"},{"t":3,"n":"Actor Value"}]},{"t":6,"n":"Script effect","c":[{"t":6,"n":"SCIT - Script effect data","c":[{"t":3,"n":"Script effect"},{"t":3,"n":"Magic school"},{"t":3,"n":"Visual effect name"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"}]}]},{"t":6,"n":"Effects","c":[{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":6,"n":"EFME - Oblivion Magic Extender","c":[{"t":3,"n":"Record Version"},{"t":6,"n":"OBME Version","c":[{"t":3,"n":"Beta"},{"t":3,"n":"Minor"},{"t":3,"n":"Major"}]},{"t":3,"n":"EFIT Param Info"},{"t":3,"n":"EFIX Param Info"},{"t":11,"n":"Unused"}]},{"t":2,"n":"EFID - Magic Effect Code"},{"t":6,"n":"EFIT - ","c":[{"t":2,"n":"Magic Effect Code"},{"t":3,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"},{"t":3,"n":"Type"},{"t":11,"n":"Param #1 - Unknown Type"},{"t":3,"n":"Param #1 - FormID"},{"t":2,"n":"Param #1 - Magic Effect Code"},{"t":3,"n":"Param #1 - Actor Value"}]},{"t":6,"n":"Script effect","c":[{"t":6,"n":"SCIT - Script effect data","c":[{"t":3,"n":"Script effect"},{"t":3,"n":"Magic school"},{"t":2,"n":"Visual Effect Code"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"}]},{"t":2,"n":"EFII - Icon"},{"t":6,"n":"EFIX - ","c":[{"t":3,"n":"Override Mask"},{"t":3,"n":"Flags"},{"t":5,"n":"Base Cost"},{"t":11,"n":"Param #2 - Unknown Type"},{"t":3,"n":"Param #2 - FormID"},{"t":2,"n":"Param #2 - Magic Effect Code"},{"t":3,"n":"Param #2 - Actor Value"}]}]}]},{"n":"EFXX - Effects End Marker"},{"t":2,"n":"FULL - Name"}]}]},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Uses "},{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]}]},{"t":1,"p":1,"n":"SLGM - Soul Gem","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"},{"t":3,"p":1,"n":"SCRI - Script"},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]},{"t":3,"n":"SOUL - Contained Soul"},{"t":3,"n":"SLCP - Maximum Capacity"}]},{"t":1,"p":1,"n":"WEAP - Weapon","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"},{"t":3,"p":1,"n":"SCRI - Script"},{"t":3,"n":"ENAM - Enchantment"},{"t":3,"n":"ANAM - Enchantment Points"},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Type"},{"t":5,"n":"Speed"},{"t":5,"n":"Reach"},{"t":3,"n":"Flags"},{"t":3,"n":"Value"},{"t":3,"n":"Health"},{"t":5,"n":"Weight"},{"t":3,"n":"Damage"}]}]},{"t":1,"p":1,"n":"ACTI - Activator","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":3,"n":"SNAM - Sound"}]}]},"name":"Bash.Scripts","hash":"E3E9B7F3","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.Sound.json ================================================ {"records":"CONT,CREA,DOOR,LIGH,MGEF,WTHR,ACTI","description":"Sound tag from Wrye Bash.\r\n\r\nUsed when the mod replaces sounds.","tree":{"records":[{"t":1,"p":1,"n":"CONT - Container","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":3,"n":"SCRI - Script"},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Flags"},{"t":5,"n":"Weight"}]},{"t":3,"p":1,"n":"SNAM - Open sound"},{"t":3,"p":1,"n":"QNAM - Close sound"}]},{"t":1,"p":1,"n":"CREA - Creature","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":8,"n":"Items","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":7,"n":"NIFZ - Models","c":[{"t":2,"n":"Model"}]},{"t":11,"n":"NIFT - Texture Files Hashes"},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Base spell points"},{"t":3,"n":"Fatigue"},{"t":3,"n":"Barter gold"},{"t":3,"n":"Level (offset)"},{"t":3,"n":"Calc min"},{"t":3,"n":"Calc max"}]},{"t":8,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"SCRI - Script"},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Buys\/Sells and Services"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":8,"n":"AI Packages","c":[{"t":3,"n":"PKID - AI Package"}]},{"t":7,"n":"KFFZ - Animations","c":[{"t":2,"n":"Animation"}]},{"t":6,"n":"DATA - Creature Data","c":[{"t":3,"n":"Type"},{"t":3,"n":"Combat Skill"},{"t":3,"n":"Magic Skill"},{"t":3,"n":"Stealth Skill"},{"t":3,"n":"Soul"},{"t":11,"n":"Unused"},{"t":3,"n":"Health"},{"t":3,"n":"Attack Damage"},{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":3,"n":"RNAM - Attack reach"},{"t":3,"n":"ZNAM - Combat Style"},{"t":5,"n":"TNAM - Turning Speed"},{"t":5,"n":"BNAM - Base Scale"},{"t":5,"p":1,"n":"WNAM - Foot Weight"},{"t":2,"n":"NAM0 - Blood Spray"},{"t":2,"n":"NAM1 - Blood Decal"},{"t":3,"p":1,"n":"CSCR - Inherits Sounds from"},{"t":10,"s":1,"p":1,"n":"Sound Types","d":1,"c":[{"t":6,"p":1,"n":"Sound Type","c":[{"t":3,"p":1,"n":"CSDT - Type"},{"t":10,"p":1,"n":"Sounds","d":1,"c":[{"t":6,"p":1,"n":"Sound","c":[{"t":3,"p":1,"n":"CSDI - Sound"},{"t":3,"p":1,"n":"CSDC - Sound Chance"}]}]}]}]}]},{"t":1,"p":1,"n":"DOOR - Door","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":3,"n":"SCRI - Script"},{"t":3,"p":1,"n":"SNAM - Open sound"},{"t":3,"p":1,"n":"ANAM - Close sound"},{"t":3,"p":1,"n":"BNAM - Loop sound"},{"t":3,"n":"FNAM - Flags"},{"t":8,"n":"Random teleport destinations","c":[{"t":3,"n":"TNAM - Destination"}]}]},{"t":1,"p":1,"n":"LIGH - Light","c":[{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":3,"n":"SCRI - Script"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"ICON - Icon filename"},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Time"},{"t":3,"n":"Radius"},{"t":6,"n":"Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":3,"n":"Unused"}]},{"t":3,"n":"Flags"},{"t":5,"n":"Falloff Exponent"},{"t":5,"n":"FOV"},{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]},{"t":5,"n":"FNAM - Fade value"},{"t":3,"p":1,"n":"SNAM - Sound"}]},{"t":1,"p":1,"n":"MGEF - Magic Effect","c":[{"t":2,"n":"EDID - Magic Effect Code"},{"t":6,"n":"OBME - Oblivion Magic Extender","c":[{"t":3,"n":"Record Version"},{"t":6,"n":"OBME Version","c":[{"t":3,"n":"Beta"},{"t":3,"n":"Minor"},{"t":3,"n":"Major"}]},{"t":3,"n":"Param A Info"},{"t":3,"n":"Param B Info"},{"t":11,"n":"Unused"},{"t":2,"n":"Handler"},{"t":3,"n":"Flag Overrides"},{"t":11,"n":"ParamB"}]},{"t":2,"n":"EDDX - EditorID"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":2,"n":"ICON - Icon filename"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":6,"p":1,"n":"DATA - Data","c":[{"t":3,"n":"Flags"},{"t":5,"n":"Base cost"},{"t":3,"n":"Unused"},{"t":3,"n":"Assoc. Weapon"},{"t":3,"n":"Assoc. Armor"},{"t":3,"n":"Assoc. Creature"},{"t":3,"n":"Assoc. Actor Value"},{"t":3,"n":"Magic School"},{"t":3,"n":"Resist value"},{"t":3,"n":"Counter Effect Count"},{"t":3,"n":"Light"},{"t":5,"n":"Projectile speed"},{"t":3,"n":"Effect Shader"},{"t":3,"n":"Enchant effect"},{"t":3,"p":1,"n":"Casting sound"},{"t":3,"p":1,"n":"Bolt sound"},{"t":3,"p":1,"n":"Hit sound"},{"t":3,"p":1,"n":"Area sound"},{"t":5,"n":"Constant Effect enchantment factor"},{"t":5,"n":"Constant Effect barter factor"}]},{"t":7,"n":"ESCE - Counter Effects","c":[{"t":2,"n":"Counter Effect Code"}]}]},{"t":1,"p":1,"n":"WTHR - Weather","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"CNAM - Texture Lower Layer"},{"t":2,"n":"DNAM - Texture Upper Layer"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":7,"n":"NAM0 - Colors by Types\/Times","c":[{"t":7,"n":"Type","c":[{"t":6,"n":"Time","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]}]}]},{"t":6,"n":"FNAM - Fog Distance","c":[{"t":5,"n":"Day Near"},{"t":5,"n":"Day Far"},{"t":5,"n":"Night Near"},{"t":5,"n":"Night Far"}]},{"t":6,"n":"HNAM - HDR Data","c":[{"t":5,"n":"Eye Adapt Speed"},{"t":5,"n":"Blur Radius"},{"t":5,"n":"Blur Passes"},{"t":5,"n":"Emissive Mult"},{"t":5,"n":"Target LUM"},{"t":5,"n":"Upper LUM Clamp"},{"t":5,"n":"Bright Scale"},{"t":5,"n":"Bright Clamp"},{"t":5,"n":"LUM Ramp No Tex"},{"t":5,"n":"LUM Ramp Min"},{"t":5,"n":"LUM Ramp Max"},{"t":5,"n":"Sunlight Dimmer"},{"t":5,"n":"Grass Dimmer"},{"t":5,"n":"Tree Dimmer"}]},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Wind Speed"},{"t":3,"n":"Cloud Speed (Lower)"},{"t":3,"n":"Cloud Speed (Upper)"},{"t":3,"n":"Trans Delta"},{"t":3,"n":"Sun Glare"},{"t":3,"n":"Sun Damage"},{"t":3,"n":"Precipitation - Begin Fade In"},{"t":3,"n":"Precipitation - End Fade Out"},{"t":3,"n":"Thunder\/Lightning - Begin Fade In"},{"t":3,"n":"Thunder\/Lightning - End Fade Out"},{"t":3,"n":"Thunder\/Lightning - Frequency"},{"t":3,"n":"Weather Classification"},{"t":6,"n":"Lightning Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"}]}]},{"t":8,"s":1,"p":1,"n":"Sounds","d":1,"c":[{"t":6,"p":1,"n":"SNAM - Sound","c":[{"t":3,"p":1,"n":"Sound"},{"t":3,"p":1,"n":"Type"}]}]}]},{"t":1,"p":1,"n":"ACTI - Activator","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":3,"n":"SCRI - Script"},{"t":3,"p":1,"n":"SNAM - Sound"}]}]},"name":"Bash.Sound","hash":"E24E2BAF","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.SpellStats.json ================================================ {"records":"SPEL","description":"SpellStats tag from Wrye Bash.\r\n\r\nUsed when the mod modifies spell stats.","tree":{"records":[{"t":1,"p":1,"n":"SPEL - Spell","c":[{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBME - Oblivion Magic Extender","c":[{"t":3,"n":"Record Version"},{"t":6,"n":"OBME Version","c":[{"t":3,"n":"Beta"},{"t":3,"n":"Minor"},{"t":3,"n":"Major"}]},{"t":11,"n":"Unused"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"p":1,"n":"SPIT - ","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Cost"},{"t":3,"p":1,"n":"Level"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":3,"n":"EFID - Magic effect name"},{"t":6,"n":"EFIT - ","c":[{"t":3,"n":"Magic effect name"},{"t":3,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"},{"t":3,"n":"Type"},{"t":3,"n":"Actor Value"}]},{"t":6,"n":"Script effect","c":[{"t":6,"n":"SCIT - Script effect data","c":[{"t":3,"n":"Script effect"},{"t":3,"n":"Magic school"},{"t":3,"n":"Visual effect name"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"}]}]},{"t":6,"n":"Effects","c":[{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":6,"n":"EFME - Oblivion Magic Extender","c":[{"t":3,"n":"Record Version"},{"t":6,"n":"OBME Version","c":[{"t":3,"n":"Beta"},{"t":3,"n":"Minor"},{"t":3,"n":"Major"}]},{"t":3,"n":"EFIT Param Info"},{"t":3,"n":"EFIX Param Info"},{"t":11,"n":"Unused"}]},{"t":2,"n":"EFID - Magic Effect Code"},{"t":6,"n":"EFIT - ","c":[{"t":2,"n":"Magic Effect Code"},{"t":3,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"},{"t":3,"n":"Type"},{"t":11,"n":"Param #1 - Unknown Type"},{"t":3,"n":"Param #1 - FormID"},{"t":2,"n":"Param #1 - Magic Effect Code"},{"t":3,"n":"Param #1 - Actor Value"}]},{"t":6,"n":"Script effect","c":[{"t":6,"n":"SCIT - Script effect data","c":[{"t":3,"n":"Script effect"},{"t":3,"n":"Magic school"},{"t":2,"n":"Visual Effect Code"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"}]},{"t":2,"n":"EFII - Icon"},{"t":6,"n":"EFIX - ","c":[{"t":3,"n":"Override Mask"},{"t":3,"n":"Flags"},{"t":5,"n":"Base Cost"},{"t":11,"n":"Param #2 - Unknown Type"},{"t":3,"n":"Param #2 - FormID"},{"t":2,"n":"Param #2 - Magic Effect Code"},{"t":3,"n":"Param #2 - Actor Value"}]}]}]},{"n":"EFXX - Effects End Marker"},{"t":2,"n":"FULL - Name"}]}]}]}]},"name":"Bash.SpellStats","hash":"F4C3769F","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.Stats.json ================================================ {"records":"ALCH,APPA,ARMO,BOOK,CLOT,INGR,KEYM,LIGH,MISC,SGST,WEAP,AMMO","description":"Stats tag from Wrye Bash.\r\n\r\nUsed when the mod modifies item stats.","tree":{"records":[{"t":1,"p":1,"n":"ALCH - Potion","c":[{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBME - Oblivion Magic Extender","c":[{"t":3,"n":"Record Version"},{"t":6,"n":"OBME Version","c":[{"t":3,"n":"Beta"},{"t":3,"n":"Minor"},{"t":3,"n":"Major"}]},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"},{"t":3,"n":"SCRI - Script"},{"t":5,"p":1,"n":"DATA - Weight"},{"t":6,"p":1,"n":"ENIT - ","c":[{"t":3,"p":1,"n":"Value"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":3,"n":"EFID - Magic effect name"},{"t":6,"n":"EFIT - ","c":[{"t":3,"n":"Magic effect name"},{"t":3,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"},{"t":3,"n":"Type"},{"t":3,"n":"Actor Value"}]},{"t":6,"n":"Script effect","c":[{"t":6,"n":"SCIT - Script effect data","c":[{"t":3,"n":"Script effect"},{"t":3,"n":"Magic school"},{"t":3,"n":"Visual effect name"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"}]}]},{"t":6,"n":"Effects","c":[{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":6,"n":"EFME - Oblivion Magic Extender","c":[{"t":3,"n":"Record Version"},{"t":6,"n":"OBME Version","c":[{"t":3,"n":"Beta"},{"t":3,"n":"Minor"},{"t":3,"n":"Major"}]},{"t":3,"n":"EFIT Param Info"},{"t":3,"n":"EFIX Param Info"},{"t":11,"n":"Unused"}]},{"t":2,"n":"EFID - Magic Effect Code"},{"t":6,"n":"EFIT - ","c":[{"t":2,"n":"Magic Effect Code"},{"t":3,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"},{"t":3,"n":"Type"},{"t":11,"n":"Param #1 - Unknown Type"},{"t":3,"n":"Param #1 - FormID"},{"t":2,"n":"Param #1 - Magic Effect Code"},{"t":3,"n":"Param #1 - Actor Value"}]},{"t":6,"n":"Script effect","c":[{"t":6,"n":"SCIT - Script effect data","c":[{"t":3,"n":"Script effect"},{"t":3,"n":"Magic school"},{"t":2,"n":"Visual Effect Code"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"}]},{"t":2,"n":"EFII - Icon"},{"t":6,"n":"EFIX - ","c":[{"t":3,"n":"Override Mask"},{"t":3,"n":"Flags"},{"t":5,"n":"Base Cost"},{"t":11,"n":"Param #2 - Unknown Type"},{"t":3,"n":"Param #2 - FormID"},{"t":2,"n":"Param #2 - Magic Effect Code"},{"t":3,"n":"Param #2 - Actor Value"}]}]}]},{"n":"EFXX - Effects End Marker"},{"t":2,"n":"FULL - Name"}]}]}]},{"t":1,"p":1,"n":"APPA - Alchemical Apparatus","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"},{"t":3,"n":"SCRI - Script"},{"t":6,"p":1,"n":"DATA - ","c":[{"t":3,"n":"Type"},{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"},{"t":5,"p":1,"n":"Quality"}]}]},{"t":1,"p":1,"n":"ARMO - Armor","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":3,"n":"SCRI - Script"},{"t":3,"n":"ENAM - Enchantment"},{"t":3,"n":"ANAM - Enchantment Points"},{"t":6,"n":"BMDT - ","c":[{"t":3,"n":"Biped Flags"},{"t":3,"n":"General Flags"},{"t":11,"n":"Unused"}]},{"t":6,"n":"Male biped model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":6,"n":"Male world model","c":[{"t":2,"n":"MOD2 - Model Filename"},{"t":5,"n":"MO2B - Bound Radius"},{"t":11,"n":"MO2T - Texture Files Hashes"}]},{"t":2,"n":"ICON - Male icon filename"},{"t":6,"n":"Female biped model","c":[{"t":2,"n":"MOD3 - Model Filename"},{"t":5,"n":"MO3B - Bound Radius"},{"t":11,"n":"MO3T - Texture Files Hashes"}]},{"t":6,"n":"Female world model","c":[{"t":2,"n":"MOD4 - Model Filename"},{"t":5,"n":"MO4B - Bound Radius"},{"t":11,"n":"MO4T - Texture Files Hashes"}]},{"t":2,"n":"ICO2 - Female icon filename"},{"t":6,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Armor"},{"t":3,"p":1,"n":"Value"},{"t":3,"p":1,"n":"Health"},{"t":5,"p":1,"n":"Weight"}]}]},{"t":1,"p":1,"n":"BOOK - Book","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"},{"t":3,"n":"SCRI - Script"},{"t":3,"n":"ENAM - Enchantment"},{"t":3,"p":1,"n":"ANAM - Enchantment Points"},{"t":2,"n":"DESC - Description"},{"t":6,"p":1,"n":"DATA - ","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Teaches"},{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]}]},{"t":1,"p":1,"n":"CLOT - Clothing","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":3,"n":"SCRI - Script"},{"t":3,"n":"ENAM - Enchantment"},{"t":3,"p":1,"n":"ANAM - Enchantment Points"},{"t":6,"n":"BMDT - ","c":[{"t":3,"n":"Biped Flags"},{"t":3,"n":"General Flags"},{"t":11,"n":"Unused"}]},{"t":6,"n":"Male biped model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":6,"n":"Male world model","c":[{"t":2,"n":"MOD2 - Model Filename"},{"t":5,"n":"MO2B - Bound Radius"},{"t":11,"n":"MO2T - Texture Files Hashes"}]},{"t":2,"n":"ICON - Male icon filename"},{"t":6,"n":"Female biped model","c":[{"t":2,"n":"MOD3 - Model Filename"},{"t":5,"n":"MO3B - Bound Radius"},{"t":11,"n":"MO3T - Texture Files Hashes"}]},{"t":6,"n":"Female world model","c":[{"t":2,"n":"MOD4 - Model Filename"},{"t":5,"n":"MO4B - Bound Radius"},{"t":11,"n":"MO4T - Texture Files Hashes"}]},{"t":2,"n":"ICO2 - Female icon filename"},{"t":6,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]}]},{"t":1,"p":1,"n":"INGR - Ingredient","c":[{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBME - Oblivion Magic Extender","c":[{"t":3,"n":"Record Version"},{"t":6,"n":"OBME Version","c":[{"t":3,"n":"Beta"},{"t":3,"n":"Minor"},{"t":3,"n":"Major"}]},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"},{"t":3,"n":"SCRI - Script"},{"t":5,"p":1,"n":"DATA - Weight"},{"t":6,"p":1,"n":"ENIT - ","c":[{"t":3,"p":1,"n":"Value"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":3,"n":"EFID - Magic effect name"},{"t":6,"n":"EFIT - ","c":[{"t":3,"n":"Magic effect name"},{"t":3,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"},{"t":3,"n":"Type"},{"t":3,"n":"Actor Value"}]},{"t":6,"n":"Script effect","c":[{"t":6,"n":"SCIT - Script effect data","c":[{"t":3,"n":"Script effect"},{"t":3,"n":"Magic school"},{"t":3,"n":"Visual effect name"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"}]}]},{"t":6,"n":"Effects","c":[{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":6,"n":"EFME - Oblivion Magic Extender","c":[{"t":3,"n":"Record Version"},{"t":6,"n":"OBME Version","c":[{"t":3,"n":"Beta"},{"t":3,"n":"Minor"},{"t":3,"n":"Major"}]},{"t":3,"n":"EFIT Param Info"},{"t":3,"n":"EFIX Param Info"},{"t":11,"n":"Unused"}]},{"t":2,"n":"EFID - Magic Effect Code"},{"t":6,"n":"EFIT - ","c":[{"t":2,"n":"Magic Effect Code"},{"t":3,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"},{"t":3,"n":"Type"},{"t":11,"n":"Param #1 - Unknown Type"},{"t":3,"n":"Param #1 - FormID"},{"t":2,"n":"Param #1 - Magic Effect Code"},{"t":3,"n":"Param #1 - Actor Value"}]},{"t":6,"n":"Script effect","c":[{"t":6,"n":"SCIT - Script effect data","c":[{"t":3,"n":"Script effect"},{"t":3,"n":"Magic school"},{"t":2,"n":"Visual Effect Code"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"}]},{"t":2,"n":"EFII - Icon"},{"t":6,"n":"EFIX - ","c":[{"t":3,"n":"Override Mask"},{"t":3,"n":"Flags"},{"t":5,"n":"Base Cost"},{"t":11,"n":"Param #2 - Unknown Type"},{"t":3,"n":"Param #2 - FormID"},{"t":2,"n":"Param #2 - Magic Effect Code"},{"t":3,"n":"Param #2 - Actor Value"}]}]}]},{"n":"EFXX - Effects End Marker"},{"t":2,"n":"FULL - Name"}]}]}]},{"t":1,"p":1,"n":"KEYM - Key","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"},{"t":3,"n":"SCRI - Script"},{"t":6,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]}]},{"t":1,"p":1,"n":"LIGH - Light","c":[{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":3,"n":"SCRI - Script"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"ICON - Icon filename"},{"t":6,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Time"},{"t":3,"n":"Radius"},{"t":6,"n":"Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":3,"n":"Unused"}]},{"t":3,"n":"Flags"},{"t":5,"n":"Falloff Exponent"},{"t":5,"n":"FOV"},{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":5,"n":"FNAM - Fade value"},{"t":3,"n":"SNAM - Sound"}]},{"t":1,"p":1,"n":"MISC - Misc. Item","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"},{"t":3,"n":"SCRI - Script"},{"t":6,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Value"},{"t":3,"n":"Actor Value"},{"t":5,"p":1,"n":"Weight"},{"t":3,"n":"Group"}]}]},{"t":1,"p":1,"n":"SGST - Sigil Stone","c":[{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBME - Oblivion Magic Extender","c":[{"t":3,"n":"Record Version"},{"t":6,"n":"OBME Version","c":[{"t":3,"n":"Beta"},{"t":3,"n":"Minor"},{"t":3,"n":"Major"}]},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"},{"t":3,"n":"SCRI - Script"},{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":3,"n":"EFID - Magic effect name"},{"t":6,"n":"EFIT - ","c":[{"t":3,"n":"Magic effect name"},{"t":3,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"},{"t":3,"n":"Type"},{"t":3,"n":"Actor Value"}]},{"t":6,"n":"Script effect","c":[{"t":6,"n":"SCIT - Script effect data","c":[{"t":3,"n":"Script effect"},{"t":3,"n":"Magic school"},{"t":3,"n":"Visual effect name"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"}]}]},{"t":6,"n":"Effects","c":[{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":6,"n":"EFME - Oblivion Magic Extender","c":[{"t":3,"n":"Record Version"},{"t":6,"n":"OBME Version","c":[{"t":3,"n":"Beta"},{"t":3,"n":"Minor"},{"t":3,"n":"Major"}]},{"t":3,"n":"EFIT Param Info"},{"t":3,"n":"EFIX Param Info"},{"t":11,"n":"Unused"}]},{"t":2,"n":"EFID - Magic Effect Code"},{"t":6,"n":"EFIT - ","c":[{"t":2,"n":"Magic Effect Code"},{"t":3,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"},{"t":3,"n":"Type"},{"t":11,"n":"Param #1 - Unknown Type"},{"t":3,"n":"Param #1 - FormID"},{"t":2,"n":"Param #1 - Magic Effect Code"},{"t":3,"n":"Param #1 - Actor Value"}]},{"t":6,"n":"Script effect","c":[{"t":6,"n":"SCIT - Script effect data","c":[{"t":3,"n":"Script effect"},{"t":3,"n":"Magic school"},{"t":2,"n":"Visual Effect Code"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"n":"FULL - Name"}]},{"t":2,"n":"EFII - Icon"},{"t":6,"n":"EFIX - ","c":[{"t":3,"n":"Override Mask"},{"t":3,"n":"Flags"},{"t":5,"n":"Base Cost"},{"t":11,"n":"Param #2 - Unknown Type"},{"t":3,"n":"Param #2 - FormID"},{"t":2,"n":"Param #2 - Magic Effect Code"},{"t":3,"n":"Param #2 - Actor Value"}]}]}]},{"n":"EFXX - Effects End Marker"},{"t":2,"n":"FULL - Name"}]}]},{"t":6,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Uses "},{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]}]},{"t":1,"p":1,"n":"WEAP - Weapon","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"},{"t":3,"n":"SCRI - Script"},{"t":3,"n":"ENAM - Enchantment"},{"t":3,"p":1,"n":"ANAM - Enchantment Points"},{"t":6,"p":1,"n":"DATA - ","c":[{"t":3,"n":"Type"},{"t":5,"p":1,"n":"Speed"},{"t":5,"p":1,"n":"Reach"},{"t":3,"n":"Flags"},{"t":3,"p":1,"n":"Value"},{"t":3,"p":1,"n":"Health"},{"t":5,"p":1,"n":"Weight"},{"t":3,"p":1,"n":"Damage"}]}]},{"t":1,"p":1,"n":"AMMO - Ammunition","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"},{"t":3,"n":"ENAM - Enchantment"},{"t":3,"p":1,"n":"ANAM - Enchantment Points"},{"t":6,"p":1,"n":"DATA - ","c":[{"t":5,"p":1,"n":"Speed"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"},{"t":3,"p":1,"n":"Damage"}]}]}]},"name":"Bash.Stats","hash":"3AA18F73","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.Voice-F.json ================================================ {"records":"RACE","description":"Voice-F tag from Wrye Bash.\r\n\r\nUsed when the mod modifies female voice definitions.","tree":{"records":[{"t":1,"p":1,"n":"RACE - Race","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":8,"n":"Relations","c":[{"t":6,"n":"XNAM - Relation","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Modifier"}]}]},{"t":6,"n":"DATA - ","c":[{"t":7,"n":"Skill Boosts","c":[{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]}]},{"t":11,"n":"Unused"},{"t":5,"n":"Male Height"},{"t":5,"n":"Female Height"},{"t":5,"n":"Male Weight"},{"t":5,"n":"Female Weight"},{"t":3,"n":"Flags"}]},{"t":6,"p":1,"n":"VNAM - Voice","c":[{"t":3,"n":"Male"},{"t":3,"p":1,"n":"Female"}]},{"t":6,"n":"DNAM - Default Hair","c":[{"t":3,"n":"Male"},{"t":3,"n":"Female"}]},{"t":3,"n":"CNAM - Default Hair Color"},{"t":5,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"n":"UNAM - FaceGen - Face clamp"},{"t":6,"n":"ATTR - Base Attributes","c":[{"t":6,"n":"Male","c":[{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":6,"n":"Female","c":[{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]}]},{"t":6,"n":"Face Data","c":[{"n":"NAM0 - Face Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"n":"NAM1 - Body Data Marker"},{"t":6,"n":"Male Body Data","c":[{"n":"MNAM - Male Body Data Marker"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"t":6,"n":"Female Body Data","c":[{"n":"FNAM - Female Body Data Marker"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"t":7,"n":"HNAM - Hairs","c":[{"t":3,"n":"Hair"}]},{"t":7,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eye"}]},{"t":6,"n":"FaceGen Data","c":[{"t":11,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"n":"SNAM - Unknown"}]}]},"name":"Bash.Voice-F","hash":"A74B2831","color":255} ================================================ FILE: frontend/settings/Oblivion/Bash.Voice-M.json ================================================ {"records":"RACE","description":"Voice-M tag from Wrye Bash.\r\n\r\nUsed when the mod modifies male voice definitions.","tree":{"records":[{"t":1,"p":1,"n":"RACE - Race","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":8,"n":"Spells","c":[{"t":3,"n":"SPLO - Spell"}]},{"t":8,"n":"Relations","c":[{"t":6,"n":"XNAM - Relation","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Modifier"}]}]},{"t":6,"n":"DATA - ","c":[{"t":7,"n":"Skill Boosts","c":[{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]}]},{"t":11,"n":"Unused"},{"t":5,"n":"Male Height"},{"t":5,"n":"Female Height"},{"t":5,"n":"Male Weight"},{"t":5,"n":"Female Weight"},{"t":3,"n":"Flags"}]},{"t":6,"p":1,"n":"VNAM - Voice","c":[{"t":3,"p":1,"n":"Male"},{"t":3,"n":"Female"}]},{"t":6,"n":"DNAM - Default Hair","c":[{"t":3,"n":"Male"},{"t":3,"n":"Female"}]},{"t":3,"n":"CNAM - Default Hair Color"},{"t":5,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"n":"UNAM - FaceGen - Face clamp"},{"t":6,"n":"ATTR - Base Attributes","c":[{"t":6,"n":"Male","c":[{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]},{"t":6,"n":"Female","c":[{"t":3,"n":"Strength"},{"t":3,"n":"Intelligence"},{"t":3,"n":"Willpower"},{"t":3,"n":"Agility"},{"t":3,"n":"Speed"},{"t":3,"n":"Endurance"},{"t":3,"n":"Personality"},{"t":3,"n":"Luck"}]}]},{"t":6,"n":"Face Data","c":[{"n":"NAM0 - Face Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"n":"NAM1 - Body Data Marker"},{"t":6,"n":"Male Body Data","c":[{"n":"MNAM - Male Body Data Marker"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"t":6,"n":"Female Body Data","c":[{"n":"FNAM - Female Body Data Marker"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"},{"t":2,"n":"ICON - Icon filename"}]}]}]},{"t":7,"n":"HNAM - Hairs","c":[{"t":3,"n":"Hair"}]},{"t":7,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eye"}]},{"t":6,"n":"FaceGen Data","c":[{"t":11,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"n":"SNAM - Unknown"}]}]},"name":"Bash.Voice-M","hash":"DEBE38B3","color":255} ================================================ FILE: frontend/settings/Oblivion/Smash.All.json ================================================ {"records":"ACRE,ACTI,ALCH,AMMO,ANIO,APPA,ARMO,BOOK,BSGN,CELL,CLAS,CLMT,CLOT,CONT,CREA,CSTY,DIAL,DOOR,EFSH,ENCH,EYES,FACT,FLOR,FURN,GLOB,GMST,GRAS,HAIR,INFO,INGR,KEYM,LAND,LIGH,LSCR,LTEX,LVLC,LVLI,LVSP,MGEF,MISC,NPC_,PACK,PGRD,QUST,RACE,REFR,REGN,ROAD,SBSP,SCPT,SGST,SKIL,SLGM,SOUN,SPEL,STAT,TREE,WATR,WEAP,WRLD,WTHR,ACHR","description":"Smashes all the things. Produced using autoset attributes on all record types found in oblivion.esm and DLCs.\r\n\r\nLast updated 05\/01\/2018.","tree":{"records":[{"t":1,"p":1,"n":"ACRE - Placed Creature","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"NAME - Base"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"},{"t":3,"p":1,"n":"XGLB - Global variable"}]},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":11,"n":"XRGD - Ragdoll Data"},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"ACTI - Activator","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":3,"p":1,"n":"SNAM - Sound"}]},{"t":1,"p":1,"n":"ALCH - Potion","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBME - Oblivion Magic Extender","c":[{"t":3,"p":1,"n":"Record Version"},{"t":6,"p":1,"n":"OBME Version","c":[{"t":3,"p":1,"n":"Beta"},{"t":3,"p":1,"n":"Minor"},{"t":3,"p":1,"n":"Major"}]},{"t":11,"n":"Unused"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":3,"p":1,"n":"SCRI - Script"},{"t":5,"p":1,"n":"DATA - Weight"},{"t":6,"s":1,"p":1,"n":"ENIT - ","c":[{"t":3,"p":1,"n":"Value"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"s":1,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":3,"p":1,"n":"EFID - Magic effect name"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":3,"p":1,"n":"Magic effect name"},{"t":3,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Actor Value"}]},{"t":6,"p":1,"n":"Script effect","c":[{"t":6,"p":1,"n":"SCIT - Script effect data","c":[{"t":3,"p":1,"n":"Script effect"},{"t":3,"p":1,"n":"Magic school"},{"t":3,"p":1,"n":"Visual effect name"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"p":1,"n":"FULL - Name"}]}]},{"t":6,"p":1,"n":"Effects","c":[{"t":8,"p":1,"n":"Effects","c":[{"t":6,"p":1,"n":"Effect","c":[{"t":6,"p":1,"n":"EFME - Oblivion Magic Extender","c":[{"t":3,"p":1,"n":"Record Version"},{"t":6,"p":1,"n":"OBME Version","c":[{"t":3,"p":1,"n":"Beta"},{"t":3,"p":1,"n":"Minor"},{"t":3,"p":1,"n":"Major"}]},{"t":3,"p":1,"n":"EFIT Param Info"},{"t":3,"p":1,"n":"EFIX Param Info"},{"t":11,"n":"Unused"}]},{"t":2,"p":1,"n":"EFID - Magic Effect Code"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":2,"p":1,"n":"Magic Effect Code"},{"t":3,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"},{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Param #1 - Unknown Type"},{"t":3,"p":1,"n":"Param #1 - FormID"},{"t":2,"p":1,"n":"Param #1 - Magic Effect Code"},{"t":3,"p":1,"n":"Param #1 - Actor Value"}]},{"t":6,"p":1,"n":"Script effect","c":[{"t":6,"p":1,"n":"SCIT - Script effect data","c":[{"t":3,"p":1,"n":"Script effect"},{"t":3,"p":1,"n":"Magic school"},{"t":2,"p":1,"n":"Visual Effect Code"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"p":1,"n":"FULL - Name"}]},{"t":2,"p":1,"n":"EFII - Icon"},{"t":6,"p":1,"n":"EFIX - ","c":[{"t":3,"p":1,"n":"Override Mask"},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Base Cost"},{"t":11,"n":"Param #2 - Unknown Type"},{"t":3,"p":1,"n":"Param #2 - FormID"},{"t":2,"p":1,"n":"Param #2 - Magic Effect Code"},{"t":3,"p":1,"n":"Param #2 - Actor Value"}]}]}]},{"p":1,"n":"EFXX - Effects End Marker"},{"t":2,"p":1,"n":"FULL - Name"}]}]}]},{"t":1,"p":1,"n":"AMMO - Ammunition","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":3,"p":1,"n":"ENAM - Enchantment"},{"t":3,"p":1,"n":"ANAM - Enchantment Points"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":5,"p":1,"n":"Speed"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"},{"t":3,"p":1,"n":"Damage"}]}]},{"t":1,"p":1,"n":"ANIO - Animated Object","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":3,"p":1,"n":"DATA - IDLE animation"}]},{"t":1,"p":1,"n":"APPA - Alchemical Apparatus","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":3,"p":1,"n":"SCRI - Script"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"},{"t":5,"p":1,"n":"Quality"}]}]},{"t":1,"p":1,"n":"ARMO - Armor","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"SCRI - Script"},{"t":3,"p":1,"n":"ENAM - Enchantment"},{"t":3,"p":1,"n":"ANAM - Enchantment Points"},{"t":6,"s":1,"p":1,"n":"BMDT - ","c":[{"t":3,"p":1,"n":"Biped Flags"},{"t":3,"p":1,"n":"General Flags"},{"t":11,"n":"Unused"}]},{"t":6,"s":1,"p":1,"n":"Male biped model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":6,"s":1,"p":1,"n":"Male world model","c":[{"t":2,"p":1,"n":"MOD2 - Model Filename"},{"t":5,"p":1,"n":"MO2B - Bound Radius"},{"t":11,"p":1,"n":"MO2T - Texture Files Hashes"}]},{"t":2,"p":1,"n":"ICON - Male icon filename"},{"t":6,"s":1,"p":1,"n":"Female biped model","c":[{"t":2,"p":1,"n":"MOD3 - Model Filename"},{"t":5,"p":1,"n":"MO3B - Bound Radius"},{"t":11,"p":1,"n":"MO3T - Texture Files Hashes"}]},{"t":6,"s":1,"p":1,"n":"Female world model","c":[{"t":2,"p":1,"n":"MOD4 - Model Filename"},{"t":5,"p":1,"n":"MO4B - Bound Radius"},{"t":11,"p":1,"n":"MO4T - Texture Files Hashes"}]},{"t":2,"p":1,"n":"ICO2 - Female icon filename"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Armor"},{"t":3,"p":1,"n":"Value"},{"t":3,"p":1,"n":"Health"},{"t":5,"p":1,"n":"Weight"}]}]},{"t":1,"p":1,"n":"BOOK - Book","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":3,"p":1,"n":"SCRI - Script"},{"t":3,"p":1,"n":"ENAM - Enchantment"},{"t":3,"p":1,"n":"ANAM - Enchantment Points"},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Teaches"},{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]}]},{"t":1,"p":1,"n":"BSGN - Birthsign","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":2,"p":1,"n":"DESC - Description"},{"t":8,"s":1,"p":1,"n":"Spells","d":1,"c":[{"t":3,"p":1,"n":"SPLO - Spell"}]}]},{"t":1,"p":1,"n":"CELL - Cell","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"DATA - Flags"},{"t":6,"s":1,"p":1,"n":"XCLC - Grid","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"}]},{"t":6,"s":1,"p":1,"n":"XCLL - Lighting","c":[{"t":6,"p":1,"n":"Ambient Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Directional Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Fog Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Fog Near"},{"t":5,"p":1,"n":"Fog Far"},{"t":3,"p":1,"n":"Directional Rotation XY"},{"t":3,"p":1,"n":"Directional Rotation Z"},{"t":5,"p":1,"n":"Directional Fade"},{"t":5,"p":1,"n":"Fog Clip Dist"}]},{"t":7,"p":1,"n":"XCLR - Regions","c":[{"t":3,"p":1,"n":"Region"}]},{"t":3,"p":1,"n":"XCMT - Music"},{"t":5,"p":1,"n":"XCLW - Water Height"},{"t":3,"p":1,"n":"XCCM - Climate"},{"t":3,"p":1,"n":"XCWT - Water"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"},{"t":3,"p":1,"n":"XGLB - Global variable"}]}]},{"t":1,"p":1,"n":"CLAS - Class","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"DESC - Description"},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":7,"p":1,"n":"Primary Attributes","c":[{"t":3,"p":1,"n":"Primary Attribute"}]},{"t":3,"p":1,"n":"Specialization"},{"t":7,"p":1,"n":"Major Skills","c":[{"t":3,"p":1,"n":"Major Skill"}]},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Buys\/Sells and Services"},{"t":3,"p":1,"n":"Teaches"},{"t":3,"p":1,"n":"Maximum training level"},{"t":3,"n":"Unused"}]}]},{"t":1,"p":1,"n":"CLMT - Climate","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":7,"p":1,"n":"WLST - Weather Types","c":[{"t":6,"p":1,"n":"Weather Type","c":[{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Chance"}]}]},{"t":2,"p":1,"n":"FNAM - Sun Texture"},{"t":2,"p":1,"n":"GNAM - Sun Glare Texture"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":6,"s":1,"p":1,"n":"TNAM - Timing","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Begin"},{"t":3,"p":1,"n":"End"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Begin"},{"t":3,"p":1,"n":"End"}]},{"t":3,"p":1,"n":"Volatility"},{"t":3,"p":1,"n":"Moons \/ Phase Length"}]}]},{"t":1,"p":1,"n":"CLOT - Clothing","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"SCRI - Script"},{"t":3,"p":1,"n":"ENAM - Enchantment"},{"t":3,"p":1,"n":"ANAM - Enchantment Points"},{"t":6,"s":1,"p":1,"n":"BMDT - ","c":[{"t":3,"p":1,"n":"Biped Flags"},{"t":3,"p":1,"n":"General Flags"},{"t":11,"n":"Unused"}]},{"t":6,"s":1,"p":1,"n":"Male biped model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":6,"s":1,"p":1,"n":"Male world model","c":[{"t":2,"p":1,"n":"MOD2 - Model Filename"},{"t":5,"p":1,"n":"MO2B - Bound Radius"},{"t":11,"p":1,"n":"MO2T - Texture Files Hashes"}]},{"t":2,"p":1,"n":"ICON - Male icon filename"},{"t":6,"s":1,"p":1,"n":"Female biped model","c":[{"t":2,"p":1,"n":"MOD3 - Model Filename"},{"t":5,"p":1,"n":"MO3B - Bound Radius"},{"t":11,"p":1,"n":"MO3T - Texture Files Hashes"}]},{"t":6,"s":1,"p":1,"n":"Female world model","c":[{"t":2,"p":1,"n":"MOD4 - Model Filename"},{"t":5,"p":1,"n":"MO4B - Bound Radius"},{"t":11,"p":1,"n":"MO4T - Texture Files Hashes"}]},{"t":2,"p":1,"n":"ICO2 - Female icon filename"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]}]},{"t":1,"p":1,"n":"CONT - Container","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":8,"s":1,"p":1,"n":"Items","d":1,"c":[{"t":6,"p":1,"n":"CNTO - Item","c":[{"t":3,"p":1,"n":"Item"},{"t":3,"p":1,"n":"Count"}]}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Weight"}]},{"t":3,"p":1,"n":"SNAM - Open sound"},{"t":3,"p":1,"n":"QNAM - Close sound"}]},{"t":1,"p":1,"n":"CREA - Creature","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":8,"s":1,"p":1,"n":"Items","d":1,"c":[{"t":6,"p":1,"n":"CNTO - Item","c":[{"t":3,"p":1,"n":"Item"},{"t":3,"p":1,"n":"Count"}]}]},{"t":8,"s":1,"p":1,"n":"Spells","d":1,"c":[{"t":3,"p":1,"n":"SPLO - Spell"}]},{"t":7,"p":1,"n":"NIFZ - Models","c":[{"t":2,"p":1,"n":"Model"}]},{"t":11,"n":"NIFT - Texture Files Hashes"},{"t":6,"s":1,"p":1,"n":"ACBS - Configuration","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Base spell points"},{"t":3,"p":1,"n":"Fatigue"},{"t":3,"p":1,"n":"Barter gold"},{"t":3,"p":1,"n":"Level (offset)"},{"t":3,"p":1,"n":"Calc min"},{"t":3,"p":1,"n":"Calc max"}]},{"t":8,"s":1,"p":1,"n":"Factions","d":1,"c":[{"t":6,"p":1,"n":"SNAM - Faction","c":[{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"p":1,"n":"INAM - Death item"},{"t":3,"p":1,"n":"SCRI - Script"},{"t":6,"s":1,"p":1,"n":"AIDT - AI Data","c":[{"t":3,"p":1,"n":"Aggression"},{"t":3,"p":1,"n":"Confidence"},{"t":3,"p":1,"n":"Energy Level"},{"t":3,"p":1,"n":"Responsibility"},{"t":3,"p":1,"n":"Buys\/Sells and Services"},{"t":3,"p":1,"n":"Teaches"},{"t":3,"p":1,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":8,"s":1,"p":1,"n":"AI Packages","d":1,"c":[{"t":3,"p":1,"n":"PKID - AI Package"}]},{"t":7,"p":1,"n":"KFFZ - Animations","c":[{"t":2,"p":1,"n":"Animation"}]},{"t":6,"s":1,"p":1,"n":"DATA - Creature Data","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Combat Skill"},{"t":3,"p":1,"n":"Magic Skill"},{"t":3,"p":1,"n":"Stealth Skill"},{"t":3,"p":1,"n":"Soul"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Attack Damage"},{"t":3,"p":1,"n":"Strength"},{"t":3,"p":1,"n":"Intelligence"},{"t":3,"p":1,"n":"Willpower"},{"t":3,"p":1,"n":"Agility"},{"t":3,"p":1,"n":"Speed"},{"t":3,"p":1,"n":"Endurance"},{"t":3,"p":1,"n":"Personality"},{"t":3,"p":1,"n":"Luck"}]},{"t":3,"p":1,"n":"RNAM - Attack reach"},{"t":3,"p":1,"n":"ZNAM - Combat Style"},{"t":5,"p":1,"n":"TNAM - Turning Speed"},{"t":5,"p":1,"n":"BNAM - Base Scale"},{"t":5,"p":1,"n":"WNAM - Foot Weight"},{"t":2,"p":1,"n":"NAM0 - Blood Spray"},{"t":2,"p":1,"n":"NAM1 - Blood Decal"},{"t":3,"p":1,"n":"CSCR - Inherits Sounds from"},{"t":10,"p":1,"n":"Sound Types","d":1,"c":[{"t":6,"p":1,"n":"Sound Type","c":[{"t":3,"p":1,"n":"CSDT - Type"},{"t":10,"p":1,"n":"Sounds","c":[{"t":6,"p":1,"n":"Sound","c":[{"t":3,"p":1,"n":"CSDI - Sound"},{"t":3,"p":1,"n":"CSDC - Sound Chance"}]}]}]}]}]},{"t":1,"p":1,"n":"CSTY - Combat Style","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"CSTD - Standard","c":[{"t":3,"p":1,"n":"Dodge % Chance"},{"t":3,"p":1,"n":"Left\/Right % Chance"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Dodge L\/R Timer (min)"},{"t":5,"p":1,"n":"Dodge L\/R Timer (max)"},{"t":5,"p":1,"n":"Dodge Forward Timer (min)"},{"t":5,"p":1,"n":"Dodge Forward Timer (max)"},{"t":5,"p":1,"n":"Dodge Back Timer Min"},{"t":5,"p":1,"n":"Dodge Back Timer Max"},{"t":5,"p":1,"n":"Idle Timer min"},{"t":5,"p":1,"n":"Idle Timer max"},{"t":3,"p":1,"n":"Block % Chance"},{"t":3,"p":1,"n":"Attack % Chance"},{"t":5,"p":1,"n":"Recoil\/Stagger Bonus to Attack"},{"t":5,"p":1,"n":"Unconscious Bonus to Attack"},{"t":5,"p":1,"n":"Hand-To-Hand Bonus to Attack"},{"t":3,"p":1,"n":"Power Attack % Chance"},{"t":5,"p":1,"n":"Recoil\/Stagger Bonus to Power"},{"t":5,"p":1,"n":"Unconscious Bonus to Power Attack"},{"t":3,"p":1,"n":"Power Attack - Normal"},{"t":3,"p":1,"n":"Power Attack - Forward"},{"t":3,"p":1,"n":"Power Attack - Back"},{"t":3,"p":1,"n":"Power Attack - Left"},{"t":3,"p":1,"n":"Power Attack - Right"},{"t":5,"p":1,"n":"Hold Timer (min)"},{"t":5,"p":1,"n":"Hold Timer (max)"},{"t":3,"p":1,"n":"Flags 1"},{"t":3,"p":1,"n":"Acrobatic Dodge % Chance"},{"t":5,"p":1,"n":"Range Mult (Optimal)"},{"t":5,"p":1,"n":"Range Mult (Max)"},{"t":5,"p":1,"n":"Switch Distance (Melee)"},{"t":5,"p":1,"n":"Switch Distance (Ranged)"},{"t":5,"p":1,"n":"Buff standoff Distance"},{"t":5,"p":1,"n":"Ranged standoff Distance"},{"t":5,"p":1,"n":"Group standoff Distance"},{"t":3,"p":1,"n":"Rushing Attack % Chance"},{"t":5,"p":1,"n":"Rushing Attack Distance Mult"},{"t":3,"p":1,"n":"Flags 2"}]},{"t":6,"s":1,"p":1,"n":"CSAD - Advanced","c":[{"t":5,"p":1,"n":"Dodge Fatigue Mod Mult"},{"t":5,"p":1,"n":"Dodge Fatigue Mod Base"},{"t":5,"p":1,"n":"Encumb. Speed Mod Base"},{"t":5,"p":1,"n":"Encumb. Speed Mod Mult"},{"t":5,"p":1,"n":"Dodge While Under Attack Mult"},{"t":5,"p":1,"n":"Dodge Not Under Attack Mult"},{"t":5,"p":1,"n":"Dodge Back While Under Attack Mult"},{"t":5,"p":1,"n":"Dodge Back Not Under Attack Mult"},{"t":5,"p":1,"n":"Dodge Forward While Attacking Mult"},{"t":5,"p":1,"n":"Dodge Forward Not Attacking Mult"},{"t":5,"p":1,"n":"Block Skill Modifier Mult"},{"t":5,"p":1,"n":"Block Skill Modifier Base"},{"t":5,"p":1,"n":"Block While Under Attack Mult"},{"t":5,"p":1,"n":"Block Not Under Attack Mult"},{"t":5,"p":1,"n":"Attack Skill Modifier Mult"},{"t":5,"p":1,"n":"Attack Skill Modifier Base"},{"t":5,"p":1,"n":"Attack While Under Attack Mult"},{"t":5,"p":1,"n":"Attack Not Under Attack Mult"},{"t":5,"p":1,"n":"Attack During Block Mult"},{"t":5,"p":1,"n":"Power Att. Fatigue Mod Base"},{"t":5,"p":1,"n":"Power Att. Fatigue Mod Mult"}]}]},{"t":1,"p":1,"n":"DIAL - Dialog Topic","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":8,"s":1,"p":1,"n":"Quests","d":1,"c":[{"t":3,"p":1,"n":"QSTI - Quest"}]},{"t":8,"s":1,"p":1,"n":"Quests?","d":1,"c":[{"t":3,"p":1,"n":"QSTR - Quest?"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"DATA - Type"}]},{"t":1,"p":1,"n":"DOOR - Door","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":3,"p":1,"n":"SNAM - Open sound"},{"t":3,"p":1,"n":"ANAM - Close sound"},{"t":3,"p":1,"n":"BNAM - Loop sound"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":8,"s":1,"p":1,"n":"Random teleport destinations","d":1,"c":[{"t":3,"p":1,"n":"TNAM - Destination"}]}]},{"t":1,"p":1,"n":"EFSH - Effect Shader","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"ICON - Fill Texture"},{"t":2,"p":1,"n":"ICO2 - Particle Shader Texture"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Membrane Shader - Source Blend Mode"},{"t":3,"p":1,"n":"Membrane Shader - Blend Operation"},{"t":3,"p":1,"n":"Membrane Shader - Z Test Function"},{"t":6,"p":1,"n":"Fill\/Texture Effect - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Fade In Time"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Full Alpha Time"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Fade Out Time"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Presistent Alpha Ratio"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Pulse Amplitude"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Pulse Frequency"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Animation Speed (U)"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Animation Speed (V)"},{"t":5,"p":1,"n":"Edge Effect - Fall Off"},{"t":6,"p":1,"n":"Edge Effect - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Edge Effect - Alpha Fade In Time"},{"t":5,"p":1,"n":"Edge Effect - Full Alpha Time"},{"t":5,"p":1,"n":"Edge Effect - Alpha Fade Out Time"},{"t":5,"p":1,"n":"Edge Effect - Persistent Alpha Ratio"},{"t":5,"p":1,"n":"Edge Effect - Alpha Pulse Amplitude"},{"t":5,"p":1,"n":"Edge Effect - Alpha Pusle Frequence"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Full Alpha Ratio"},{"t":5,"p":1,"n":"Edge Effect - Full Alpha Ratio"},{"t":3,"p":1,"n":"Membrane Shader - Dest Blend Mode"},{"t":3,"p":1,"n":"Particle Shader - Source Blend Mode"},{"t":3,"p":1,"n":"Particle Shader - Blend Operation"},{"t":3,"p":1,"n":"Particle Shader - Z Test Function"},{"t":3,"p":1,"n":"Particle Shader - Dest Blend Mode"},{"t":5,"p":1,"n":"Particle Shader - Particle Birth Ramp Up Time"},{"t":5,"p":1,"n":"Particle Shader - Full Particle Birth Time"},{"t":5,"p":1,"n":"Particle Shader - Particle Birth Ramp Down Time"},{"t":5,"p":1,"n":"Particle Shader - Full Particle Birth Ratio"},{"t":5,"p":1,"n":"Particle Shader - Persistant Particle Birth Ratio"},{"t":5,"p":1,"n":"Particle Shader - Particle Lifetime"},{"t":5,"p":1,"n":"Particle Shader - Particle Lifetime +\/-"},{"t":5,"p":1,"n":"Particle Shader - Initial Speed Along Normal"},{"t":5,"p":1,"n":"Particle Shader - Acceleration Along Normal"},{"t":5,"p":1,"n":"Particle Shader - Initial Velocity #1"},{"t":5,"p":1,"n":"Particle Shader - Initial Velocity #2"},{"t":5,"p":1,"n":"Particle Shader - Initial Velocity #3"},{"t":5,"p":1,"n":"Particle Shader - Acceleration #1"},{"t":5,"p":1,"n":"Particle Shader - Acceleration #2"},{"t":5,"p":1,"n":"Particle Shader - Acceleration #3"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 1"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 2"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 1 Time"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 2 Time"},{"t":6,"p":1,"n":"Color Key 1 - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Color Key 2 - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Color Key 3 - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Color Key 1 - Color Alpha"},{"t":5,"p":1,"n":"Color Key 2 - Color Alpha"},{"t":5,"p":1,"n":"Color Key 3 - Color Alpha"},{"t":5,"p":1,"n":"Color Key 1 - Color Key Time"},{"t":5,"p":1,"n":"Color Key 2 - Color Key Time"},{"t":5,"p":1,"n":"Color Key 3 - Color Key Time"}]}]},{"t":1,"p":1,"n":"ENCH - Enchantment","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBME - Oblivion Magic Extender","c":[{"t":3,"p":1,"n":"Record Version"},{"t":6,"p":1,"n":"OBME Version","c":[{"t":3,"p":1,"n":"Beta"},{"t":3,"p":1,"n":"Minor"},{"t":3,"p":1,"n":"Major"}]},{"t":11,"n":"Unused"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"ENIT - ","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Charge Amount"},{"t":3,"p":1,"n":"Enchant Cost"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"s":1,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":3,"p":1,"n":"EFID - Magic effect name"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":3,"p":1,"n":"Magic effect name"},{"t":3,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Actor Value"}]},{"t":6,"p":1,"n":"Script effect","c":[{"t":6,"p":1,"n":"SCIT - Script effect data","c":[{"t":3,"p":1,"n":"Script effect"},{"t":3,"p":1,"n":"Magic school"},{"t":3,"p":1,"n":"Visual effect name"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"p":1,"n":"FULL - Name"}]}]},{"t":6,"p":1,"n":"Effects","c":[{"t":8,"p":1,"n":"Effects","c":[{"t":6,"p":1,"n":"Effect","c":[{"t":6,"p":1,"n":"EFME - Oblivion Magic Extender","c":[{"t":3,"p":1,"n":"Record Version"},{"t":6,"p":1,"n":"OBME Version","c":[{"t":3,"p":1,"n":"Beta"},{"t":3,"p":1,"n":"Minor"},{"t":3,"p":1,"n":"Major"}]},{"t":3,"p":1,"n":"EFIT Param Info"},{"t":3,"p":1,"n":"EFIX Param Info"},{"t":11,"n":"Unused"}]},{"t":2,"p":1,"n":"EFID - Magic Effect Code"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":2,"p":1,"n":"Magic Effect Code"},{"t":3,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"},{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Param #1 - Unknown Type"},{"t":3,"p":1,"n":"Param #1 - FormID"},{"t":2,"p":1,"n":"Param #1 - Magic Effect Code"},{"t":3,"p":1,"n":"Param #1 - Actor Value"}]},{"t":6,"p":1,"n":"Script effect","c":[{"t":6,"p":1,"n":"SCIT - Script effect data","c":[{"t":3,"p":1,"n":"Script effect"},{"t":3,"p":1,"n":"Magic school"},{"t":2,"p":1,"n":"Visual Effect Code"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"p":1,"n":"FULL - Name"}]},{"t":2,"p":1,"n":"EFII - Icon"},{"t":6,"p":1,"n":"EFIX - ","c":[{"t":3,"p":1,"n":"Override Mask"},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Base Cost"},{"t":11,"n":"Param #2 - Unknown Type"},{"t":3,"p":1,"n":"Param #2 - FormID"},{"t":2,"p":1,"n":"Param #2 - Magic Effect Code"},{"t":3,"p":1,"n":"Param #2 - Actor Value"}]}]}]},{"p":1,"n":"EFXX - Effects End Marker"},{"t":2,"p":1,"n":"FULL - Name"}]}]}]},{"t":1,"p":1,"n":"EYES - Eyes","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"ICON - Texture"},{"t":3,"p":1,"n":"DATA - Flags"}]},{"t":1,"p":1,"n":"FACT - Faction","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":8,"s":1,"p":1,"n":"Relations","d":1,"c":[{"t":6,"p":1,"n":"XNAM - Relation","c":[{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Modifier"}]}]},{"t":3,"p":1,"n":"DATA - Flags"},{"t":5,"p":1,"n":"CNAM - Crime Gold Multiplier"},{"t":10,"p":1,"n":"Ranks","d":1,"c":[{"t":6,"p":1,"n":"Rank","c":[{"t":3,"p":1,"n":"RNAM - Rank#"},{"t":2,"p":1,"n":"MNAM - Male"},{"t":2,"p":1,"n":"FNAM - Female"},{"t":2,"p":1,"n":"INAM - Insignia"}]}]}]},{"t":1,"p":1,"n":"FLOR - Flora","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":3,"p":1,"n":"PFIG - Ingredient"},{"t":6,"s":1,"p":1,"n":"PFPC - Seasonal ingredient production","c":[{"t":3,"p":1,"n":"Spring"},{"t":3,"p":1,"n":"Summer "},{"t":3,"p":1,"n":"Fall"},{"t":3,"p":1,"n":"Winter"}]}]},{"t":1,"p":1,"n":"FURN - Furniture","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":11,"n":"MNAM - Marker Flags"}]},{"t":1,"p":1,"n":"GLOB - Global","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"FNAM - Type"},{"t":5,"p":1,"n":"FLTV - Value"}]},{"t":1,"p":1,"n":"GMST - Game Setting","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":""}]},{"t":1,"p":1,"n":"GRAS - Grass","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Density"},{"t":3,"p":1,"n":"Min Slope"},{"t":3,"p":1,"n":"Max Slope"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Unit from water amount"},{"t":3,"p":1,"n":"Unit from water type"},{"t":5,"p":1,"n":"Position Range"},{"t":5,"p":1,"n":"Height Range"},{"t":5,"p":1,"n":"Color Range"},{"t":5,"p":1,"n":"Wave Period"},{"t":3,"p":1,"n":"Flags"}]}]},{"t":1,"p":1,"n":"HAIR - Hair","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":2,"p":1,"n":"ICON - Texture"},{"t":3,"p":1,"n":"DATA - Flags"}]},{"t":1,"n":"IDLE - Idle Animation","c":[{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":5,"n":"MODB - Bound Radius"},{"t":11,"n":"MODT - Texture Files Hashes"}]},{"t":8,"n":"Conditions","c":[{"t":6,"n":"CTDA - Condition","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"n":"Comparison Value - Float"},{"t":3,"n":"Comparison Value - Global"},{"t":3,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"n":"None"},{"t":3,"n":"Integer"},{"t":3,"n":"Variable Name (INVALID)"},{"t":3,"n":"Sex"},{"t":3,"n":"Actor Value"},{"t":3,"n":"Crime Type"},{"t":3,"n":"Axis"},{"t":3,"n":"Form Type"},{"t":3,"n":"Quest Stage (INVALID)"},{"t":3,"n":"Object Reference"},{"t":3,"n":"Inventory Object"},{"t":3,"n":"Actor"},{"t":3,"n":"Quest"},{"t":3,"n":"Faction"},{"t":3,"n":"Cell"},{"t":3,"n":"Class"},{"t":3,"n":"Race"},{"t":3,"n":"Actor Base"},{"t":3,"n":"Global"},{"t":3,"n":"Weather"},{"t":3,"n":"Package"},{"t":3,"n":"Owner"},{"t":3,"n":"Birthsign"},{"t":3,"n":"Furniture"},{"t":3,"n":"Magic Item"},{"t":3,"n":"Magic Effect"},{"t":3,"n":"Worldspace"},{"t":3,"n":"Referenceable Object"},{"t":3,"n":"Variable Name"},{"t":3,"n":"Quest Stage"}]},{"t":6,"n":"CTDT - Condition (old format)","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"n":"Comparison Value - Float"},{"t":3,"n":"Comparison Value - Global"},{"t":3,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"n":"None"},{"t":3,"n":"Integer"},{"t":3,"n":"Variable Name (INVALID)"},{"t":3,"n":"Sex"},{"t":3,"n":"Actor Value"},{"t":3,"n":"Crime Type"},{"t":3,"n":"Axis"},{"t":3,"n":"Form Type"},{"t":3,"n":"Quest Stage (INVALID)"},{"t":3,"n":"Object Reference"},{"t":3,"n":"Inventory Object"},{"t":3,"n":"Actor"},{"t":3,"n":"Quest"},{"t":3,"n":"Faction"},{"t":3,"n":"Cell"},{"t":3,"n":"Class"},{"t":3,"n":"Race"},{"t":3,"n":"Actor Base"},{"t":3,"n":"Global"},{"t":3,"n":"Weather"},{"t":3,"n":"Package"},{"t":3,"n":"Owner"},{"t":3,"n":"Birthsign"},{"t":3,"n":"Furniture"},{"t":3,"n":"Magic Item"},{"t":3,"n":"Magic Effect"},{"t":3,"n":"Worldspace"},{"t":3,"n":"Referenceable Object"},{"t":3,"n":"Variable Name"},{"t":3,"n":"Quest Stage"}]}]},{"t":3,"n":"ANAM - Animation Group Section"},{"t":7,"n":"DATA - Related Idle Animations","c":[{"t":3,"n":"Related Idle Animation"}]}]},{"t":1,"p":1,"n":"INFO - Dialog response","d":1,"c":[{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Next Speaker"},{"t":3,"p":1,"n":"Flags"}]},{"t":3,"p":1,"n":"QSTI - Quest"},{"t":3,"p":1,"n":"TPIC - Topic"},{"t":3,"p":1,"n":"PNAM - Previous INFO"},{"t":8,"s":1,"p":1,"n":"Add topics","d":1,"c":[{"t":3,"p":1,"n":"NAME - Topic"}]},{"t":8,"s":1,"p":1,"n":"Responses","d":1,"c":[{"t":6,"p":1,"n":"Response","c":[{"t":6,"p":1,"n":"TRDT - Response Data","c":[{"t":3,"p":1,"n":"Emotion Type"},{"t":3,"p":1,"n":"Emotion Value"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Response number"}]},{"t":2,"p":1,"n":"NAM1 - Response Text"},{"t":2,"p":1,"n":"NAM2 - Actor notes"}]}]},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"CTDA - Condition","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Birthsign"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Magic Item"},{"t":3,"p":1,"n":"Magic Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"}]},{"t":6,"p":1,"n":"CTDT - Condition (old format)","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Birthsign"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Magic Item"},{"t":3,"p":1,"n":"Magic Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"}]}]},{"t":8,"s":1,"p":1,"n":"Choices","d":1,"c":[{"t":3,"p":1,"n":"TCLT - Choice"}]},{"t":8,"s":1,"p":1,"n":"Link From","d":1,"c":[{"t":3,"p":1,"n":"TCLF - Topic"}]},{"t":6,"s":1,"p":1,"n":"Result Script","c":[{"t":6,"p":1,"n":"SCHR - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"}]},{"t":6,"p":1,"n":"SCHD - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unknown"}]},{"t":11,"p":1,"n":"SCDA - Compiled result script"},{"t":2,"p":1,"n":"SCTX - Result script source"},{"t":8,"p":1,"n":"References","c":[{"t":3,"p":1,"n":"SCRO - Global Reference"},{"t":3,"p":1,"n":"SCRV - Local Variable"}]}]}]},{"t":1,"p":1,"n":"INGR - Ingredient","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBME - Oblivion Magic Extender","c":[{"t":3,"p":1,"n":"Record Version"},{"t":6,"p":1,"n":"OBME Version","c":[{"t":3,"p":1,"n":"Beta"},{"t":3,"p":1,"n":"Minor"},{"t":3,"p":1,"n":"Major"}]},{"t":11,"n":"Unused"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":3,"p":1,"n":"SCRI - Script"},{"t":5,"p":1,"n":"DATA - Weight"},{"t":6,"s":1,"p":1,"n":"ENIT - ","c":[{"t":3,"p":1,"n":"Value"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"s":1,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":3,"p":1,"n":"EFID - Magic effect name"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":3,"p":1,"n":"Magic effect name"},{"t":3,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Actor Value"}]},{"t":6,"p":1,"n":"Script effect","c":[{"t":6,"p":1,"n":"SCIT - Script effect data","c":[{"t":3,"p":1,"n":"Script effect"},{"t":3,"p":1,"n":"Magic school"},{"t":3,"p":1,"n":"Visual effect name"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"p":1,"n":"FULL - Name"}]}]},{"t":6,"p":1,"n":"Effects","c":[{"t":8,"p":1,"n":"Effects","c":[{"t":6,"p":1,"n":"Effect","c":[{"t":6,"p":1,"n":"EFME - Oblivion Magic Extender","c":[{"t":3,"p":1,"n":"Record Version"},{"t":6,"p":1,"n":"OBME Version","c":[{"t":3,"p":1,"n":"Beta"},{"t":3,"p":1,"n":"Minor"},{"t":3,"p":1,"n":"Major"}]},{"t":3,"p":1,"n":"EFIT Param Info"},{"t":3,"p":1,"n":"EFIX Param Info"},{"t":11,"n":"Unused"}]},{"t":2,"p":1,"n":"EFID - Magic Effect Code"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":2,"p":1,"n":"Magic Effect Code"},{"t":3,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"},{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Param #1 - Unknown Type"},{"t":3,"p":1,"n":"Param #1 - FormID"},{"t":2,"p":1,"n":"Param #1 - Magic Effect Code"},{"t":3,"p":1,"n":"Param #1 - Actor Value"}]},{"t":6,"p":1,"n":"Script effect","c":[{"t":6,"p":1,"n":"SCIT - Script effect data","c":[{"t":3,"p":1,"n":"Script effect"},{"t":3,"p":1,"n":"Magic school"},{"t":2,"p":1,"n":"Visual Effect Code"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"p":1,"n":"FULL - Name"}]},{"t":2,"p":1,"n":"EFII - Icon"},{"t":6,"p":1,"n":"EFIX - ","c":[{"t":3,"p":1,"n":"Override Mask"},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Base Cost"},{"t":11,"n":"Param #2 - Unknown Type"},{"t":3,"p":1,"n":"Param #2 - FormID"},{"t":2,"p":1,"n":"Param #2 - Magic Effect Code"},{"t":3,"p":1,"n":"Param #2 - Actor Value"}]}]}]},{"p":1,"n":"EFXX - Effects End Marker"},{"t":2,"p":1,"n":"FULL - Name"}]}]}]},{"t":1,"p":1,"n":"KEYM - Key","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":3,"p":1,"n":"SCRI - Script"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]}]},{"t":1,"p":1,"n":"LAND - Landscape","d":1,"c":[{"t":11,"n":"DATA - Unknown"},{"t":11,"n":"VNML - Vertex Normals"},{"t":11,"n":"VHGT - Vertext Height Map"},{"t":11,"n":"VCLR - Vertex Colours"},{"t":8,"s":1,"p":1,"n":"Layers","d":1,"c":[{"t":6,"p":1,"n":"Base Layer","c":[{"t":6,"p":1,"n":"BTXT - Base Layer Header","c":[{"t":3,"p":1,"n":"Texture"},{"t":3,"p":1,"n":"Quadrant"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Layer"}]}]},{"t":6,"p":1,"n":"Alpha Layer","c":[{"t":6,"p":1,"n":"ATXT - Alpha Layer Header","c":[{"t":3,"p":1,"n":"Texture"},{"t":3,"p":1,"n":"Quadrant"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Layer"}]},{"t":11,"p":1,"n":"VTXT - Alpha Layer Data"}]}]},{"t":7,"p":1,"n":"VTEX - Textures","c":[{"t":3,"p":1,"n":"Texture"}]}]},{"t":1,"p":1,"n":"LIGH - Light","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Time"},{"t":3,"p":1,"n":"Radius"},{"t":6,"p":1,"n":"Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":3,"n":"Unused"}]},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Falloff Exponent"},{"t":5,"p":1,"n":"FOV"},{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":5,"p":1,"n":"FNAM - Fade value"},{"t":3,"p":1,"n":"SNAM - Sound"}]},{"t":1,"p":1,"n":"LSCR - Load Screen","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":2,"p":1,"n":"DESC - Description"},{"t":8,"s":1,"p":1,"n":"Locations","d":1,"c":[{"t":6,"p":1,"n":"LNAM - Location","c":[{"t":3,"p":1,"n":"Direct"},{"t":6,"p":1,"n":"Indirect","c":[{"t":3,"p":1,"n":"World"},{"t":6,"p":1,"n":"Grid","c":[{"t":3,"p":1,"n":"Y"},{"t":3,"p":1,"n":"X"}]}]}]}]}]},{"t":1,"p":1,"n":"LTEX - Landscape Texture","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":6,"s":1,"p":1,"n":"HNAM - Havok Data","c":[{"t":3,"p":1,"n":"Material Type"},{"t":3,"p":1,"n":"Friction"},{"t":3,"p":1,"n":"Restitution"}]},{"t":3,"p":1,"n":"SNAM - Texture Specular Exponent"},{"t":8,"s":1,"p":1,"n":"Grasses","d":1,"c":[{"t":3,"p":1,"n":"GNAM - Grass"}]}]},{"t":1,"p":1,"n":"LVLC - Leveled Creature","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"LVLD - Chance none"},{"t":3,"p":1,"n":"LVLF - Flags"},{"t":8,"s":1,"p":1,"n":"Leveled List Entries","d":1,"c":[{"t":6,"p":1,"n":"LVLO - Leveled List Entry","c":[{"t":3,"p":1,"n":"Level"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Count"}]}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":3,"p":1,"n":"TNAM - Creature template"}]},{"t":1,"p":1,"n":"LVLI - Leveled Item","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"LVLD - Chance none"},{"t":3,"p":1,"n":"LVLF - Flags"},{"t":8,"s":1,"p":1,"n":"Leveled List Entries","d":1,"c":[{"t":6,"p":1,"n":"LVLO - Leveled List Entry","c":[{"t":3,"p":1,"n":"Level"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Count"}]}]},{"t":11,"n":"DATA - Unused"}]},{"t":1,"p":1,"n":"LVSP - Leveled Spell","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"LVLD - Chance none"},{"t":3,"p":1,"n":"LVLF - Flags"},{"t":8,"s":1,"p":1,"n":"Leveled List Entries","d":1,"c":[{"t":6,"p":1,"n":"LVLO - Leveled List Entry","c":[{"t":3,"p":1,"n":"Level"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Count"}]}]}]},{"t":1,"p":1,"n":"MGEF - Magic Effect","d":1,"c":[{"t":2,"p":1,"n":"EDID - Magic Effect Code"},{"t":6,"s":1,"p":1,"n":"OBME - Oblivion Magic Extender","c":[{"t":3,"p":1,"n":"Record Version"},{"t":6,"p":1,"n":"OBME Version","c":[{"t":3,"p":1,"n":"Beta"},{"t":3,"p":1,"n":"Minor"},{"t":3,"p":1,"n":"Major"}]},{"t":3,"p":1,"n":"Param A Info"},{"t":3,"p":1,"n":"Param B Info"},{"t":11,"n":"Unused"},{"t":2,"p":1,"n":"Handler"},{"t":3,"p":1,"n":"Flag Overrides"},{"t":11,"p":1,"n":"ParamB"}]},{"t":2,"p":1,"n":"EDDX - EditorID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"DESC - Description"},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Base cost"},{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Assoc. Weapon"},{"t":3,"p":1,"n":"Assoc. Armor"},{"t":3,"p":1,"n":"Assoc. Creature"},{"t":3,"p":1,"n":"Assoc. Actor Value"},{"t":3,"p":1,"n":"Magic School"},{"t":3,"p":1,"n":"Resist value"},{"t":3,"p":1,"n":"Counter Effect Count"},{"t":3,"p":1,"n":"Light"},{"t":5,"p":1,"n":"Projectile speed"},{"t":3,"p":1,"n":"Effect Shader"},{"t":3,"p":1,"n":"Enchant effect"},{"t":3,"p":1,"n":"Casting sound"},{"t":3,"p":1,"n":"Bolt sound"},{"t":3,"p":1,"n":"Hit sound"},{"t":3,"p":1,"n":"Area sound"},{"t":5,"p":1,"n":"Constant Effect enchantment factor"},{"t":5,"p":1,"n":"Constant Effect barter factor"}]},{"t":7,"p":1,"n":"ESCE - Counter Effects","c":[{"t":2,"p":1,"n":"Counter Effect Code"}]}]},{"t":1,"p":1,"n":"MISC - Misc. Item","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":3,"p":1,"n":"SCRI - Script"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Value"},{"t":3,"p":1,"n":"Actor Value"},{"t":5,"p":1,"n":"Weight"},{"t":3,"p":1,"n":"Group"}]}]},{"t":1,"p":1,"n":"NPC_ - Non-Player Character","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":6,"s":1,"p":1,"n":"ACBS - Configuration","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Base spell points"},{"t":3,"p":1,"n":"Fatigue"},{"t":3,"p":1,"n":"Barter gold"},{"t":3,"p":1,"n":"Level (offset)"},{"t":3,"p":1,"n":"Calc min"},{"t":3,"p":1,"n":"Calc max"}]},{"t":8,"s":1,"p":1,"n":"Factions","d":1,"c":[{"t":6,"p":1,"n":"SNAM - Faction","c":[{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"p":1,"n":"INAM - Death item"},{"t":3,"p":1,"n":"RNAM - Race"},{"t":8,"s":1,"p":1,"n":"Items","d":1,"c":[{"t":6,"p":1,"n":"CNTO - Item","c":[{"t":3,"p":1,"n":"Item"},{"t":3,"p":1,"n":"Count"}]}]},{"t":8,"s":1,"p":1,"n":"Spells","d":1,"c":[{"t":3,"p":1,"n":"SPLO - Spell"}]},{"t":3,"p":1,"n":"SCRI - Script"},{"t":6,"s":1,"p":1,"n":"AIDT - AI Data","c":[{"t":3,"p":1,"n":"Aggression"},{"t":3,"p":1,"n":"Confidence"},{"t":3,"p":1,"n":"Energy Level"},{"t":3,"p":1,"n":"Responsibility"},{"t":3,"p":1,"n":"Buys\/Sells and Services"},{"t":3,"p":1,"n":"Teaches"},{"t":3,"p":1,"n":"Maximum training level"},{"t":11,"n":"Unused"}]},{"t":8,"s":1,"p":1,"n":"AI Packages","d":1,"c":[{"t":3,"p":1,"n":"PKID - AI Package"}]},{"t":7,"p":1,"n":"KFFZ - Animations","c":[{"t":2,"p":1,"n":"Animation"}]},{"t":3,"p":1,"n":"CNAM - Class"},{"t":6,"s":1,"p":1,"n":"DATA - Stats","c":[{"t":3,"p":1,"n":"Armorer"},{"t":3,"p":1,"n":"Athletics"},{"t":3,"p":1,"n":"Blade"},{"t":3,"p":1,"n":"Block"},{"t":3,"p":1,"n":"Blunt"},{"t":3,"p":1,"n":"Hand to Hand"},{"t":3,"p":1,"n":"Heavy Armor"},{"t":3,"p":1,"n":"Alchemy"},{"t":3,"p":1,"n":"Alteration"},{"t":3,"p":1,"n":"Conjuration"},{"t":3,"p":1,"n":"Destruction"},{"t":3,"p":1,"n":"Illusion"},{"t":3,"p":1,"n":"Mysticism"},{"t":3,"p":1,"n":"Restoration"},{"t":3,"p":1,"n":"Acrobatics"},{"t":3,"p":1,"n":"Light Armor"},{"t":3,"p":1,"n":"Marksman"},{"t":3,"p":1,"n":"Mercantile"},{"t":3,"p":1,"n":"Security"},{"t":3,"p":1,"n":"Sneak"},{"t":3,"p":1,"n":"Speechcraft"},{"t":3,"p":1,"n":"Health"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Strength"},{"t":3,"p":1,"n":"Intelligence"},{"t":3,"p":1,"n":"Willpower"},{"t":3,"p":1,"n":"Agility"},{"t":3,"p":1,"n":"Speed"},{"t":3,"p":1,"n":"Endurance"},{"t":3,"p":1,"n":"Personality"},{"t":3,"p":1,"n":"Luck"}]},{"t":3,"p":1,"n":"HNAM - Hair"},{"t":5,"p":1,"n":"LNAM - Hair length"},{"t":7,"p":1,"n":"ENAM - Eyes","c":[{"t":3,"p":1,"n":"Eyes"}]},{"t":6,"s":1,"p":1,"n":"HCLR - Hair color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"ZNAM - Combat Style"},{"t":6,"s":1,"p":1,"n":"FaceGen Data","c":[{"t":11,"p":1,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"p":1,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"p":1,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"n":"FNAM - Unknown"}]},{"t":1,"p":1,"n":"PACK - AI Package","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"General","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"}]},{"t":6,"s":1,"p":1,"n":"PLDT - Location","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Cell"},{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Object ID"},{"t":3,"p":1,"n":"Object type"},{"t":3,"p":1,"n":"Radius"}]},{"t":6,"s":1,"p":1,"n":"PSDT - Schedule","c":[{"t":3,"p":1,"n":"Month"},{"t":3,"p":1,"n":"Day of week"},{"t":3,"p":1,"n":"Date"},{"t":3,"p":1,"n":"Time"},{"t":3,"p":1,"n":"Duration"}]},{"t":6,"s":1,"p":1,"n":"PTDT - Target","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Object ID"},{"t":3,"p":1,"n":"Object type"},{"t":3,"p":1,"n":"Count"}]},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"CTDA - Condition","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Birthsign"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Magic Item"},{"t":3,"p":1,"n":"Magic Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"}]},{"t":6,"p":1,"n":"CTDT - Condition (old format)","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Birthsign"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Magic Item"},{"t":3,"p":1,"n":"Magic Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"}]}]}]},{"t":1,"p":1,"n":"PGRD - Path Grid","d":1,"c":[{"t":3,"n":"DATA - Point Count"},{"t":7,"p":1,"n":"PGRP - Points","c":[{"t":6,"p":1,"n":"Point","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z (Even = Red\/Orange, Odd = Blue)"},{"t":3,"p":1,"n":"Connections"},{"t":11,"n":"Unused"}]}]},{"t":11,"n":"PGAG - Unknown"},{"t":7,"p":1,"n":"PGRR - Point-to-Point Connections","c":[{"t":7,"p":1,"n":"Point","c":[{"t":3,"p":1,"n":"Point"}]}]},{"t":7,"p":1,"n":"PGRI - Inter-Cell Connections","c":[{"t":6,"p":1,"n":"Inter-Cell Connection","c":[{"t":3,"p":1,"n":"Point"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]},{"t":8,"s":1,"p":1,"n":"Point-to-Reference Mappings","d":1,"c":[{"t":6,"p":1,"n":"PGRL - Point-to-Reference Mapping","c":[{"t":3,"p":1,"n":"Reference"},{"t":7,"p":1,"n":"Points","c":[{"t":3,"p":1,"n":"Point"}]}]}]}]},{"t":1,"p":1,"n":"QUST - Quest","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"SCRI - Script"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":6,"s":1,"p":1,"n":"DATA - General","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Priority"}]},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"CTDA - Condition","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Birthsign"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Magic Item"},{"t":3,"p":1,"n":"Magic Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"}]},{"t":6,"p":1,"n":"CTDT - Condition (old format)","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Birthsign"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Magic Item"},{"t":3,"p":1,"n":"Magic Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"}]}]},{"t":10,"p":1,"n":"Stages","d":1,"c":[{"t":6,"p":1,"n":"Stage","c":[{"t":3,"p":1,"n":"INDX - Stage index"},{"t":8,"p":1,"n":"Log Entries","c":[{"t":6,"p":1,"n":"Log Entry","c":[{"t":3,"p":1,"n":"QSDT - Stage Flags"},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"CTDA - Condition","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Birthsign"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Magic Item"},{"t":3,"p":1,"n":"Magic Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"}]},{"t":6,"p":1,"n":"CTDT - Condition (old format)","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Birthsign"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Magic Item"},{"t":3,"p":1,"n":"Magic Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"}]}]},{"t":2,"p":1,"n":"CNAM - Log Entry"},{"t":6,"p":1,"n":"Result Script","c":[{"t":6,"p":1,"n":"SCHR - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"}]},{"t":6,"p":1,"n":"SCHD - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unknown"}]},{"t":11,"p":1,"n":"SCDA - Compiled result script"},{"t":2,"p":1,"n":"SCTX - Result script source"},{"t":8,"p":1,"n":"References","c":[{"t":3,"p":1,"n":"SCRO - Global Reference"},{"t":3,"p":1,"n":"SCRV - Local Variable"}]}]}]}]}]}]},{"t":8,"s":1,"p":1,"n":"Targets","d":1,"c":[{"t":6,"p":1,"n":"Target","c":[{"t":6,"p":1,"n":"QSTA - Target","c":[{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"CTDA - Condition","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Birthsign"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Magic Item"},{"t":3,"p":1,"n":"Magic Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"}]},{"t":6,"p":1,"n":"CTDT - Condition (old format)","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":3,"p":1,"n":"Variable Name (INVALID)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Quest Stage (INVALID)"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Birthsign"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Magic Item"},{"t":3,"p":1,"n":"Magic Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Variable Name"},{"t":3,"p":1,"n":"Quest Stage"}]}]}]}]}]},{"t":1,"p":1,"n":"RACE - Race","c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"DESC - Description"},{"t":8,"s":1,"p":1,"n":"Spells","d":1,"c":[{"t":3,"p":1,"n":"SPLO - Spell"}]},{"t":8,"s":1,"p":1,"n":"Relations","d":1,"c":[{"t":6,"p":1,"n":"XNAM - Relation","c":[{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Modifier"}]}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":7,"p":1,"n":"Skill Boosts","d":1,"c":[{"t":6,"p":1,"n":"Skill Boost","c":[{"t":3,"p":1,"n":"Skill"},{"t":3,"p":1,"n":"Boost"}]}]},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Male Height"},{"t":5,"p":1,"n":"Female Height"},{"t":5,"p":1,"n":"Male Weight"},{"t":5,"p":1,"n":"Female Weight"},{"t":3,"p":1,"n":"Flags"}]},{"t":6,"s":1,"p":1,"n":"VNAM - Voice","c":[{"t":3,"p":1,"n":"Male"},{"t":3,"p":1,"n":"Female"}]},{"t":6,"s":1,"p":1,"n":"DNAM - Default Hair","c":[{"t":3,"p":1,"n":"Male"},{"t":3,"p":1,"n":"Female"}]},{"t":3,"p":1,"n":"CNAM - Default Hair Color"},{"t":5,"p":1,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"p":1,"n":"UNAM - FaceGen - Face clamp"},{"t":6,"s":1,"p":1,"n":"ATTR - Base Attributes","c":[{"t":6,"p":1,"n":"Male","c":[{"t":3,"p":1,"n":"Strength"},{"t":3,"p":1,"n":"Intelligence"},{"t":3,"p":1,"n":"Willpower"},{"t":3,"p":1,"n":"Agility"},{"t":3,"p":1,"n":"Speed"},{"t":3,"p":1,"n":"Endurance"},{"t":3,"p":1,"n":"Personality"},{"t":3,"p":1,"n":"Luck"}]},{"t":6,"p":1,"n":"Female","c":[{"t":3,"p":1,"n":"Strength"},{"t":3,"p":1,"n":"Intelligence"},{"t":3,"p":1,"n":"Willpower"},{"t":3,"p":1,"n":"Agility"},{"t":3,"p":1,"n":"Speed"},{"t":3,"p":1,"n":"Endurance"},{"t":3,"p":1,"n":"Personality"},{"t":3,"p":1,"n":"Luck"}]}]},{"t":6,"s":1,"p":1,"n":"Face Data","c":[{"p":1,"n":"NAM0 - Face Data Marker"},{"t":10,"p":1,"n":"Parts","d":1,"c":[{"t":6,"p":1,"n":"Part","c":[{"t":3,"p":1,"n":"INDX - Index"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":2,"p":1,"n":"ICON - Icon filename"}]}]}]},{"p":1,"n":"NAM1 - Body Data Marker"},{"t":6,"s":1,"p":1,"n":"Male Body Data","c":[{"p":1,"n":"MNAM - Male Body Data Marker"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":10,"p":1,"n":"Parts","c":[{"t":6,"p":1,"n":"Part","c":[{"t":3,"p":1,"n":"INDX - Index"},{"t":2,"p":1,"n":"ICON - Icon filename"}]}]}]},{"t":6,"s":1,"p":1,"n":"Female Body Data","c":[{"p":1,"n":"FNAM - Female Body Data Marker"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":10,"p":1,"n":"Parts","d":1,"c":[{"t":6,"p":1,"n":"Part","c":[{"t":3,"p":1,"n":"INDX - Index"},{"t":2,"p":1,"n":"ICON - Icon filename"}]}]}]},{"t":7,"s":1,"p":1,"n":"HNAM - Hairs","d":1,"c":[{"t":3,"p":1,"n":"Hair"}]},{"t":7,"s":1,"p":1,"n":"ENAM - Eyes","d":1,"c":[{"t":3,"p":1,"n":"Eye"}]},{"t":6,"s":1,"p":1,"n":"FaceGen Data","c":[{"t":11,"p":1,"n":"FGGS - FaceGen Geometry-Symmetric"},{"t":11,"p":1,"n":"FGGA - FaceGen Geometry-Asymmetric"},{"t":11,"p":1,"n":"FGTS - FaceGen Texture-Symmetric"}]},{"t":11,"n":"SNAM - Unknown"}]},{"t":1,"p":1,"n":"REFR - Placed Object","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"NAME - Base"},{"t":6,"s":1,"p":1,"n":"XTEL - Teleport Destination","c":[{"t":3,"p":1,"n":"Door"},{"t":6,"p":1,"n":"Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":6,"s":1,"p":1,"n":"XLOC - Lock information","c":[{"t":3,"p":1,"n":"Lock Level"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Key"},{"t":3,"p":1,"n":"Flags"}]},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"},{"t":3,"p":1,"n":"XGLB - Global variable"}]},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XTRG - Target"},{"t":6,"s":1,"p":1,"n":"XSED - SpeedTree","c":[{"t":3,"p":1,"n":"Seed"},{"n":"Unused"}]},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":5,"p":1,"n":"XCHG - Charge"},{"t":3,"p":1,"n":"XHLT - Health"},{"t":6,"n":"Unused","c":[{"t":3,"n":"XPCI - Unused"},{"t":2,"n":"FULL - Unused"}]},{"t":3,"p":1,"n":"XLCM - Level Modifier"},{"t":3,"n":"XRTM - Unknown"},{"t":3,"p":1,"n":"XACT - Action Flag"},{"t":3,"p":1,"n":"XCNT - Count"},{"t":6,"s":1,"p":1,"n":"Map Marker","c":[{"p":1,"n":"XMRK - Map Marker Data"},{"t":3,"p":1,"n":"FNAM - Map Flags"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"p":1,"n":"TNAM - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"}]}]},{"p":1,"n":"ONAM - Open by Default"},{"t":11,"n":"XRGD - Ragdoll Data"},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":3,"p":1,"n":"XSOL - Contained Soul"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"REGN - Region","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":6,"s":1,"p":1,"n":"RCLR - Map Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"WNAM - Worldspace"},{"t":8,"s":1,"p":1,"n":"Region Areas","d":1,"c":[{"t":6,"p":1,"n":"Region Area","c":[{"t":3,"p":1,"n":"RPLI - Edge Fall-off"},{"t":7,"p":1,"n":"RPLD - Region Point List Data","c":[{"t":6,"p":1,"n":"Point","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"}]}]}]}]},{"t":10,"p":1,"n":"Region Data Entries","d":1,"c":[{"t":6,"p":1,"n":"Region Data Entry","c":[{"t":6,"p":1,"n":"RDAT - Data Header","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Priority"},{"t":11,"n":"Unused"}]},{"t":7,"p":1,"n":"RDOT - Objects","c":[{"t":6,"p":1,"n":"Object","c":[{"t":3,"p":1,"n":"Object"},{"t":3,"p":1,"n":"Parent Index"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Density"},{"t":3,"p":1,"n":"Clustering"},{"t":3,"p":1,"n":"Min Slope"},{"t":3,"p":1,"n":"Max Slope"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Radius wrt Parent"},{"t":3,"p":1,"n":"Radius"},{"t":5,"p":1,"n":"Min Height"},{"t":5,"p":1,"n":"Max Height"},{"t":5,"p":1,"n":"Sink"},{"t":5,"p":1,"n":"Sink Variance"},{"t":5,"p":1,"n":"Size Variance"},{"t":6,"p":1,"n":"Angle Variance","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"},{"t":3,"p":1,"n":"Z"}]},{"t":11,"n":"Unknown"}]}]},{"t":2,"p":1,"n":"RDMP - Map Name"},{"t":7,"p":1,"n":"RDGS - Grasses","c":[{"t":6,"p":1,"n":"Grass","c":[{"t":3,"p":1,"n":"Grass"},{"t":11,"n":"Unused"}]}]},{"t":3,"p":1,"n":"RDMD - Music Type"},{"t":7,"p":1,"n":"RDSD - Sounds","c":[{"t":6,"p":1,"n":"Sound","c":[{"t":3,"p":1,"n":"Sound"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Chance"}]}]},{"t":7,"p":1,"n":"RDWT - Weather Types","c":[{"t":6,"p":1,"n":"Weather Type","c":[{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Chance"}]}]}]}]}]},{"t":1,"p":1,"n":"ROAD - Road","d":1,"c":[{"t":7,"p":1,"n":"PGRP - Points","c":[{"t":6,"p":1,"n":"Point","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z (Even = Red\/Orange, Odd = Blue)"},{"t":3,"p":1,"n":"Connections"},{"t":11,"n":"Unused"}]}]},{"t":7,"p":1,"n":"PGRR - Point-to-Point Connections (complex structure can't be represented, see source)","c":[{"t":6,"p":1,"n":"Point","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"SBSP - Subspace","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DNAM - ","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]},{"t":1,"p":1,"n":"SCPT - Script","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":11,"n":"SCHD - Unknown (Script Header?)"},{"t":6,"s":1,"p":1,"n":"SCHR - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"}]},{"t":6,"s":1,"p":1,"n":"SCHD - Basic Script Data","c":[{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"RefCount"},{"t":3,"p":1,"n":"CompiledSize"},{"t":3,"p":1,"n":"VariableCount"},{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unknown"}]},{"t":11,"n":"SCDA - Compiled Script"},{"t":2,"p":1,"n":"SCTX - Script Source"},{"t":10,"p":1,"n":"Local Variables","d":1,"c":[{"t":6,"p":1,"n":"Local Variable","c":[{"t":6,"p":1,"n":"SLSD - Local Variable Data","c":[{"t":3,"p":1,"n":"Index"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"SCVR - Name"}]}]},{"t":8,"s":1,"p":1,"n":"References","d":1,"c":[{"t":3,"p":1,"n":"SCRO - Global Reference"},{"t":3,"p":1,"n":"SCRV - Local Variable"}]}]},{"t":1,"p":1,"n":"SGST - Sigil Stone","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBME - Oblivion Magic Extender","c":[{"t":3,"p":1,"n":"Record Version"},{"t":6,"p":1,"n":"OBME Version","c":[{"t":3,"p":1,"n":"Beta"},{"t":3,"p":1,"n":"Minor"},{"t":3,"p":1,"n":"Major"}]},{"t":11,"n":"Unused"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":3,"p":1,"n":"SCRI - Script"},{"t":8,"s":1,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":3,"p":1,"n":"EFID - Magic effect name"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":3,"p":1,"n":"Magic effect name"},{"t":3,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Actor Value"}]},{"t":6,"p":1,"n":"Script effect","c":[{"t":6,"p":1,"n":"SCIT - Script effect data","c":[{"t":3,"p":1,"n":"Script effect"},{"t":3,"p":1,"n":"Magic school"},{"t":3,"p":1,"n":"Visual effect name"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"p":1,"n":"FULL - Name"}]}]},{"t":6,"p":1,"n":"Effects","c":[{"t":8,"p":1,"n":"Effects","c":[{"t":6,"p":1,"n":"Effect","c":[{"t":6,"p":1,"n":"EFME - Oblivion Magic Extender","c":[{"t":3,"p":1,"n":"Record Version"},{"t":6,"p":1,"n":"OBME Version","c":[{"t":3,"p":1,"n":"Beta"},{"t":3,"p":1,"n":"Minor"},{"t":3,"p":1,"n":"Major"}]},{"t":3,"p":1,"n":"EFIT Param Info"},{"t":3,"p":1,"n":"EFIX Param Info"},{"t":11,"n":"Unused"}]},{"t":2,"p":1,"n":"EFID - Magic Effect Code"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":2,"p":1,"n":"Magic Effect Code"},{"t":3,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"},{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Param #1 - Unknown Type"},{"t":3,"p":1,"n":"Param #1 - FormID"},{"t":2,"p":1,"n":"Param #1 - Magic Effect Code"},{"t":3,"p":1,"n":"Param #1 - Actor Value"}]},{"t":6,"p":1,"n":"Script effect","c":[{"t":6,"p":1,"n":"SCIT - Script effect data","c":[{"t":3,"p":1,"n":"Script effect"},{"t":3,"p":1,"n":"Magic school"},{"t":2,"p":1,"n":"Visual Effect Code"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"p":1,"n":"FULL - Name"}]},{"t":2,"p":1,"n":"EFII - Icon"},{"t":6,"p":1,"n":"EFIX - ","c":[{"t":3,"p":1,"n":"Override Mask"},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Base Cost"},{"t":11,"n":"Param #2 - Unknown Type"},{"t":3,"p":1,"n":"Param #2 - FormID"},{"t":2,"p":1,"n":"Param #2 - Magic Effect Code"},{"t":3,"p":1,"n":"Param #2 - Actor Value"}]}]}]},{"p":1,"n":"EFXX - Effects End Marker"},{"t":2,"p":1,"n":"FULL - Name"}]}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Uses "},{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]}]},{"t":1,"p":1,"n":"SKIL - Skill","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"INDX - Skill"},{"t":2,"p":1,"n":"DESC - Description"},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":6,"s":1,"p":1,"n":"DATA - Skill Data","c":[{"t":3,"p":1,"n":"Action"},{"t":3,"p":1,"n":"Attribute"},{"t":3,"p":1,"n":"Specialization"},{"t":7,"p":1,"n":"Use Values","c":[{"t":5,"p":1,"n":"Use Value"}]}]},{"t":2,"p":1,"n":"ANAM - Apprentice Text"},{"t":2,"p":1,"n":"JNAM - Journeyman Text"},{"t":2,"p":1,"n":"ENAM - Expert Text"},{"t":2,"p":1,"n":"MNAM - Master Text"}]},{"t":1,"p":1,"n":"SLGM - Soul Gem","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":3,"p":1,"n":"SCRI - Script"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":3,"p":1,"n":"SOUL - Contained Soul"},{"t":3,"p":1,"n":"SLCP - Maximum Capacity"}]},{"t":1,"p":1,"n":"SOUN - Sound","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FNAM - Sound Filename"},{"t":6,"s":1,"p":1,"n":"SNDX - Sound Data","c":[{"t":3,"p":1,"n":"Minimum attenuation distance"},{"t":3,"p":1,"n":"Maximum attenuation distance"},{"t":3,"p":1,"n":"Frequency adjustment %"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Static Attenuation (db)"},{"t":3,"p":1,"n":"Stop time"},{"t":3,"p":1,"n":"Start time"}]},{"t":6,"s":1,"p":1,"n":"SNDD - Sound Data","c":[{"t":3,"p":1,"n":"Minimum attenuation distance"},{"t":3,"p":1,"n":"Maximum attenuation distance"},{"t":3,"p":1,"n":"Frequency adjustment %"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Flags"}]}]},{"t":1,"p":1,"n":"SPEL - Spell","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBME - Oblivion Magic Extender","c":[{"t":3,"p":1,"n":"Record Version"},{"t":6,"p":1,"n":"OBME Version","c":[{"t":3,"p":1,"n":"Beta"},{"t":3,"p":1,"n":"Minor"},{"t":3,"p":1,"n":"Major"}]},{"t":11,"n":"Unused"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"SPIT - ","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Cost"},{"t":3,"p":1,"n":"Level"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"s":1,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":3,"p":1,"n":"EFID - Magic effect name"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":3,"p":1,"n":"Magic effect name"},{"t":3,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Actor Value"}]},{"t":6,"p":1,"n":"Script effect","c":[{"t":6,"p":1,"n":"SCIT - Script effect data","c":[{"t":3,"p":1,"n":"Script effect"},{"t":3,"p":1,"n":"Magic school"},{"t":3,"p":1,"n":"Visual effect name"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"p":1,"n":"FULL - Name"}]}]},{"t":6,"p":1,"n":"Effects","c":[{"t":8,"p":1,"n":"Effects","c":[{"t":6,"p":1,"n":"Effect","c":[{"t":6,"p":1,"n":"EFME - Oblivion Magic Extender","c":[{"t":3,"p":1,"n":"Record Version"},{"t":6,"p":1,"n":"OBME Version","c":[{"t":3,"p":1,"n":"Beta"},{"t":3,"p":1,"n":"Minor"},{"t":3,"p":1,"n":"Major"}]},{"t":3,"p":1,"n":"EFIT Param Info"},{"t":3,"p":1,"n":"EFIX Param Info"},{"t":11,"n":"Unused"}]},{"t":2,"p":1,"n":"EFID - Magic Effect Code"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":2,"p":1,"n":"Magic Effect Code"},{"t":3,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"},{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Param #1 - Unknown Type"},{"t":3,"p":1,"n":"Param #1 - FormID"},{"t":2,"p":1,"n":"Param #1 - Magic Effect Code"},{"t":3,"p":1,"n":"Param #1 - Actor Value"}]},{"t":6,"p":1,"n":"Script effect","c":[{"t":6,"p":1,"n":"SCIT - Script effect data","c":[{"t":3,"p":1,"n":"Script effect"},{"t":3,"p":1,"n":"Magic school"},{"t":2,"p":1,"n":"Visual Effect Code"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":2,"p":1,"n":"FULL - Name"}]},{"t":2,"p":1,"n":"EFII - Icon"},{"t":6,"p":1,"n":"EFIX - ","c":[{"t":3,"p":1,"n":"Override Mask"},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Base Cost"},{"t":11,"n":"Param #2 - Unknown Type"},{"t":3,"p":1,"n":"Param #2 - FormID"},{"t":2,"p":1,"n":"Param #2 - Magic Effect Code"},{"t":3,"p":1,"n":"Param #2 - Actor Value"}]}]}]},{"p":1,"n":"EFXX - Effects End Marker"},{"t":2,"p":1,"n":"FULL - Name"}]}]}]},{"t":1,"p":1,"n":"STAT - Static","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]}]},{"t":1,"p":1,"n":"TREE - Tree","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":7,"p":1,"n":"SNAM - SpeedTree Seeds","c":[{"t":3,"p":1,"n":"SpeedTree Seed"}]},{"t":6,"s":1,"p":1,"n":"CNAM - Tree Data","c":[{"t":5,"p":1,"n":"Leaf Curvature"},{"t":5,"p":1,"n":"Minimum Leaf Angle"},{"t":5,"p":1,"n":"Maximum Leaf Angle"},{"t":5,"p":1,"n":"Branch Dimming Value"},{"t":5,"p":1,"n":"Leaf Dimming Value"},{"t":3,"p":1,"n":"Shadow Radius"},{"t":5,"p":1,"n":"Rock Speed"},{"t":5,"p":1,"n":"Rustle Speed"}]},{"t":6,"s":1,"p":1,"n":"BNAM - Billboard Dimensions","c":[{"t":5,"p":1,"n":"Width"},{"t":5,"p":1,"n":"Height"}]}]},{"t":1,"p":1,"n":"WATR - Water","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"TNAM - Texture"},{"t":3,"p":1,"n":"ANAM - Opacity"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":2,"p":1,"n":"MNAM - Material ID"},{"t":3,"p":1,"n":"SNAM - Sound"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":5,"p":1,"n":"Wind Velocity"},{"t":5,"p":1,"n":"Wind Direction"},{"t":5,"p":1,"n":"Wave Amplitude"},{"t":5,"p":1,"n":"Wave Frequency"},{"t":5,"p":1,"n":"Sun Power"},{"t":5,"p":1,"n":"Reflectivity Amount"},{"t":5,"p":1,"n":"Fresnel Amount"},{"t":5,"p":1,"n":"Scroll X Speed"},{"t":5,"p":1,"n":"Scroll Y Speed"},{"t":5,"p":1,"n":"Fog Distance - Near Plane"},{"t":5,"p":1,"n":"Fog Distance - Far Plane"},{"t":6,"p":1,"n":"Shallow Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Deep Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Reflection Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"Texture Blend"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Rain Simulator - Force"},{"t":5,"p":1,"n":"Rain Simulator - Velocity"},{"t":5,"p":1,"n":"Rain Simulator - Falloff"},{"t":5,"p":1,"n":"Rain Simulator - Dampner"},{"t":5,"p":1,"n":"Rain Simulator - Starting Size"},{"t":5,"p":1,"n":"Displacement Simulator - Force"},{"t":5,"p":1,"n":"Displacement Simulator - Velocity"},{"t":5,"p":1,"n":"Displacement Simulator - Falloff"},{"t":5,"p":1,"n":"Displacement Simulator - Dampner"},{"t":5,"p":1,"n":"Displacement Simulator - Starting Size"},{"t":3,"p":1,"n":"Damage"}]},{"t":6,"s":1,"p":1,"n":"GNAM - Related Waters","c":[{"t":3,"p":1,"n":"Daytime"},{"t":3,"p":1,"n":"Nighttime"},{"t":3,"p":1,"n":"Underwater"}]}]},{"t":1,"p":1,"n":"WEAP - Weapon","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":3,"p":1,"n":"SCRI - Script"},{"t":3,"p":1,"n":"ENAM - Enchantment"},{"t":3,"p":1,"n":"ANAM - Enchantment Points"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":5,"p":1,"n":"Speed"},{"t":5,"p":1,"n":"Reach"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Value"},{"t":3,"p":1,"n":"Health"},{"t":5,"p":1,"n":"Weight"},{"t":3,"p":1,"n":"Damage"}]}]},{"t":1,"p":1,"n":"WRLD - Worldspace","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Parent","c":[{"t":3,"p":1,"n":"WNAM - Worldspace"}]},{"t":3,"p":1,"n":"CNAM - Climate"},{"t":3,"p":1,"n":"NAM2 - Water"},{"t":2,"p":1,"n":"ICON - Icon filename"},{"t":6,"s":1,"p":1,"n":"MNAM - Map Data","c":[{"t":6,"p":1,"n":"Usable Dimensions","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"}]},{"t":6,"p":1,"n":"Cell Coordinates","c":[{"t":6,"p":1,"n":"NW Cell","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"}]},{"t":6,"p":1,"n":"SE Cell","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"}]}]}]},{"t":3,"p":1,"n":"DATA - Flags"},{"t":6,"s":1,"p":1,"n":"Object Bounds","c":[{"t":6,"p":1,"n":"NAM0 - Min","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"}]},{"t":6,"p":1,"n":"NAM9 - Max","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"}]}]},{"t":3,"p":1,"n":"SNAM - Music"},{"t":11,"n":"OFST - Offset Data"}]},{"t":1,"p":1,"n":"WTHR - Weather","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"CNAM - Texture Lower Layer"},{"t":2,"p":1,"n":"DNAM - Texture Upper Layer"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":5,"p":1,"n":"MODB - Bound Radius"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]},{"t":7,"p":1,"n":"NAM0 - Colors by Types\/Times","c":[{"t":7,"p":1,"n":"Type","c":[{"t":6,"p":1,"n":"Time","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]}]},{"t":6,"s":1,"p":1,"n":"FNAM - Fog Distance","c":[{"t":5,"p":1,"n":"Day Near"},{"t":5,"p":1,"n":"Day Far"},{"t":5,"p":1,"n":"Night Near"},{"t":5,"p":1,"n":"Night Far"}]},{"t":6,"s":1,"p":1,"n":"HNAM - HDR Data","c":[{"t":5,"p":1,"n":"Eye Adapt Speed"},{"t":5,"p":1,"n":"Blur Radius"},{"t":5,"p":1,"n":"Blur Passes"},{"t":5,"p":1,"n":"Emissive Mult"},{"t":5,"p":1,"n":"Target LUM"},{"t":5,"p":1,"n":"Upper LUM Clamp"},{"t":5,"p":1,"n":"Bright Scale"},{"t":5,"p":1,"n":"Bright Clamp"},{"t":5,"p":1,"n":"LUM Ramp No Tex"},{"t":5,"p":1,"n":"LUM Ramp Min"},{"t":5,"p":1,"n":"LUM Ramp Max"},{"t":5,"p":1,"n":"Sunlight Dimmer"},{"t":5,"p":1,"n":"Grass Dimmer"},{"t":5,"p":1,"n":"Tree Dimmer"}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Wind Speed"},{"t":3,"p":1,"n":"Cloud Speed (Lower)"},{"t":3,"p":1,"n":"Cloud Speed (Upper)"},{"t":3,"p":1,"n":"Trans Delta"},{"t":3,"p":1,"n":"Sun Glare"},{"t":3,"p":1,"n":"Sun Damage"},{"t":3,"p":1,"n":"Precipitation - Begin Fade In"},{"t":3,"p":1,"n":"Precipitation - End Fade Out"},{"t":3,"p":1,"n":"Thunder\/Lightning - Begin Fade In"},{"t":3,"p":1,"n":"Thunder\/Lightning - End Fade Out"},{"t":3,"p":1,"n":"Thunder\/Lightning - Frequency"},{"t":3,"p":1,"n":"Weather Classification"},{"t":6,"p":1,"n":"Lightning Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"}]}]},{"t":8,"s":1,"p":1,"n":"Sounds","d":1,"c":[{"t":6,"p":1,"n":"SNAM - Sound","c":[{"t":3,"p":1,"n":"Sound"},{"t":3,"p":1,"n":"Type"}]}]}]},{"t":1,"p":1,"n":"ACHR - Placed NPC","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"NAME - Base"},{"t":6,"n":"Unused","c":[{"t":3,"n":"XPCI - Unused"},{"t":2,"n":"FULL - Unused"}]},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XMRC - Merchant container"},{"t":3,"p":1,"n":"XHRS - Horse"},{"t":11,"n":"XRGD - Ragdoll Data"},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]}]},"name":"Smash.All","hash":"E9DB3045","color":128} ================================================ FILE: frontend/settings/Skyrim/Bash.Actors.ACBS.json ================================================ {"records":"NPC_","description":"Actors.ACBS tag from Wrye Bash.\r\n\r\nUsed when the mod modifies NPC ACBS configuration.","tree":{"records":[{"t":1,"p":1,"n":"NPC_ - Non-Player Character (Actor)","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"ACBS - Configuration","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Magicka Offset"},{"t":3,"p":1,"n":"Stamina Offset"},{"t":12,"p":1,"n":"Level"},{"t":3,"p":1,"n":"Calc min level"},{"t":3,"p":1,"n":"Calc max level"},{"t":3,"p":1,"n":"Speed Multiplier"},{"t":3,"p":1,"n":"Disposition Base (unused)"},{"t":3,"p":1,"n":"Template Flags"},{"t":3,"p":1,"n":"Health Offset"},{"t":3,"p":1,"n":"Bleedout Override"}]},{"t":10,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"VTCK - Voice"},{"t":3,"n":"TPLT - Template"},{"t":3,"n":"RNAM - Race"},{"t":3,"n":"SPCT - Count"},{"t":9,"n":"Actor Effects","c":[{"t":3,"n":"SPLO - Actor Effect"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"WNAM - Worn Armor"},{"t":3,"n":"ANAM - Far away model"},{"t":3,"n":"ATKR - Attack Race"},{"t":10,"n":"Attacks","c":[{"t":6,"n":"Attack","c":[{"t":6,"n":"ATKD - Attack Data","c":[{"t":5,"n":"Damage Mult"},{"t":5,"n":"Attack Chance"},{"t":3,"n":"Attack Spell"},{"t":3,"n":"Attack Flags"},{"t":5,"n":"Attack Angle"},{"t":5,"n":"Strike Angle"},{"t":5,"n":"Stagger"},{"t":3,"n":"Attack Type"},{"t":5,"n":"Knockdown"},{"t":5,"n":"Recovery Time"},{"t":5,"n":"Stamina Mult"}]}]}]},{"t":3,"n":"SPOR - Spectator override package list"},{"t":3,"n":"OCOR - Observe dead body override package list"},{"t":3,"n":"GWOR - Guard warn override package list"},{"t":3,"n":"ECOR - Combat override package list"},{"t":3,"n":"PRKZ - Perk Count"},{"t":10,"n":"Perks","c":[{"t":6,"n":"PRKR - Perk","c":[{"t":3,"n":"Perk"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"COCT - Count"},{"t":10,"n":"Items","c":[{"t":6,"n":"Item","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]}]},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Mood"},{"t":3,"n":"Assistance"},{"t":6,"n":"Aggro","c":[{"t":3,"n":"Aggro Radius Behavior"},{"t":3,"n":"Unknown"},{"t":3,"n":"Warn"},{"t":3,"n":"Warn\/Attack"},{"t":3,"n":"Attack"}]}]},{"t":7,"n":"Packages","c":[{"t":3,"n":"PKID - Package"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":3,"n":"CNAM - Class"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"SHRT - Short Name"},{"t":11,"n":"DATA - Marker"},{"t":6,"n":"DNAM - Player Skills","c":[{"t":7,"n":"Skill Values","c":[{"t":3,"n":"Skill #0 (OneHanded)"},{"t":3,"n":"Skill #1 (TwoHanded)"},{"t":3,"n":"Skill #2 (Marksman)"},{"t":3,"n":"Skill #3 (Block)"},{"t":3,"n":"Skill #4 (Smithing)"},{"t":3,"n":"Skill #5 (HeavyArmor)"},{"t":3,"n":"Skill #6 (LightArmor)"},{"t":3,"n":"Skill #7 (Pickpocket)"},{"t":3,"n":"Skill #8 (Lockpicking)"},{"t":3,"n":"Skill #9 (Sneak)"},{"t":3,"n":"Skill #10 (Alchemy)"},{"t":3,"n":"Skill #11 (Speechcraft)"},{"t":3,"n":"Skill #12 (Alteration)"},{"t":3,"n":"Skill #13 (Conjuration)"},{"t":3,"n":"Skill #14 (Destruction)"},{"t":3,"n":"Skill #15 (Illusion)"},{"t":3,"n":"Skill #16 (Restoration)"},{"t":3,"n":"Skill #17 (Enchanting)"}]},{"t":7,"n":"Skill Offsets","c":[{"t":3,"n":"Skill #0 (OneHanded)"},{"t":3,"n":"Skill #1 (TwoHanded)"},{"t":3,"n":"Skill #2 (Marksman)"},{"t":3,"n":"Skill #3 (Block)"},{"t":3,"n":"Skill #4 (Smithing)"},{"t":3,"n":"Skill #5 (HeavyArmor)"},{"t":3,"n":"Skill #6 (LightArmor)"},{"t":3,"n":"Skill #7 (Pickpocket)"},{"t":3,"n":"Skill #8 (Lockpicking)"},{"t":3,"n":"Skill #9 (Sneak)"},{"t":3,"n":"Skill #10 (Alchemy)"},{"t":3,"n":"Skill #11 (Speechcraft)"},{"t":3,"n":"Skill #12 (Alteration)"},{"t":3,"n":"Skill #13 (Conjuration)"},{"t":3,"n":"Skill #14 (Destruction)"},{"t":3,"n":"Skill #15 (Illusion)"},{"t":3,"n":"Skill #16 (Restoration)"},{"t":3,"n":"Skill #17 (Enchanting)"}]},{"t":3,"n":"Health"},{"t":3,"n":"Magicka"},{"t":3,"n":"Stamina"},{"t":11,"n":"Unused"},{"t":5,"n":"Far away model distance"},{"t":3,"n":"Geared up weapons"},{"t":11,"n":"Unused"}]},{"t":9,"n":"Head Parts","c":[{"t":3,"n":"PNAM - Head Part"}]},{"t":3,"n":"HCLF - Hair Color"},{"t":3,"n":"ZNAM - Combat Style"},{"t":3,"n":"GNAM - Gift Filter"},{"t":11,"n":"NAM5 - Unknown"},{"t":5,"n":"NAM6 - Height"},{"t":5,"n":"NAM7 - Weight"},{"t":3,"n":"NAM8 - Sound Level"},{"t":10,"n":"Sound Types","c":[{"t":6,"n":"Sound Type","c":[{"t":3,"n":"CSDT - Type"},{"t":10,"n":"Sounds","c":[{"t":6,"n":"Sound","c":[{"t":3,"n":"CSDI - Sound"},{"t":3,"n":"CSDC - Sound Chance"}]}]}]}]},{"t":3,"n":"CSCR - Inherits Sounds From"},{"t":3,"n":"DOFT - Default outfit"},{"t":3,"n":"SOFT - Sleeping outfit"},{"t":3,"n":"DPLT - Default Package List"},{"t":3,"n":"CRIF - Crime faction"},{"t":3,"n":"FTST - Head texture"},{"t":6,"n":"QNAM - Texture lighting","c":[{"t":5,"n":"Red"},{"t":5,"n":"Green"},{"t":5,"n":"Blue"}]},{"t":6,"n":"NAM9 - Face morph","c":[{"t":5,"n":"Nose Long\/Short"},{"t":5,"n":"Nose Up\/Down"},{"t":5,"n":"Jaw Up\/Down"},{"t":5,"n":"Jaw Narrow\/Wide"},{"t":5,"n":"Jaw Farward\/Back"},{"t":5,"n":"Cheeks Up\/Down"},{"t":5,"n":"Cheeks Farward\/Back"},{"t":5,"n":"Eyes Up\/Down"},{"t":5,"n":"Eyes In\/Out"},{"t":5,"n":"Brows Up\/Down"},{"t":5,"n":"Brows In\/Out"},{"t":5,"n":"Brows Farward\/Back"},{"t":5,"n":"Lips Up\/Down"},{"t":5,"n":"Lips In\/Out"},{"t":5,"n":"Chin Narrow\/Wide"},{"t":5,"n":"Chin Up\/Down"},{"t":5,"n":"Chin Underbite\/Overbite"},{"t":5,"n":"Eyes Farward\/Back"},{"t":5,"n":"Unknown"}]},{"t":6,"n":"NAMA - Face parts","c":[{"t":3,"n":"Nose"},{"t":3,"n":"Unknown"},{"t":3,"n":"Eyes"},{"t":3,"n":"Mouth"}]},{"t":10,"n":"Tint Layers","c":[{"t":6,"n":"Layer","c":[{"t":3,"n":"TINI - Tint Index"}]}]}]}]},"name":"Bash.Actors.ACBS","hash":"$75515CF0","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.Actors.AIData.json ================================================ {"records":"NPC_","description":"Actors.AIData tag from Wrye Bash.\r\n\r\nUsed when the mod modifies NPC AI data.","tree":{"records":[{"t":1,"p":1,"n":"NPC_ - Non-Player Character (Actor)","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Magicka Offset"},{"t":3,"n":"Stamina Offset"},{"t":12,"n":"Level"},{"t":3,"n":"Calc min level"},{"t":3,"n":"Calc max level"},{"t":3,"n":"Speed Multiplier"},{"t":3,"n":"Disposition Base (unused)"},{"t":3,"n":"Template Flags"},{"t":3,"n":"Health Offset"},{"t":3,"n":"Bleedout Override"}]},{"t":10,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"VTCK - Voice"},{"t":3,"n":"TPLT - Template"},{"t":3,"n":"RNAM - Race"},{"t":3,"n":"SPCT - Count"},{"t":9,"n":"Actor Effects","c":[{"t":3,"n":"SPLO - Actor Effect"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"WNAM - Worn Armor"},{"t":3,"n":"ANAM - Far away model"},{"t":3,"n":"ATKR - Attack Race"},{"t":10,"n":"Attacks","c":[{"t":6,"n":"Attack","c":[{"t":6,"n":"ATKD - Attack Data","c":[{"t":5,"n":"Damage Mult"},{"t":5,"n":"Attack Chance"},{"t":3,"n":"Attack Spell"},{"t":3,"n":"Attack Flags"},{"t":5,"n":"Attack Angle"},{"t":5,"n":"Strike Angle"},{"t":5,"n":"Stagger"},{"t":3,"n":"Attack Type"},{"t":5,"n":"Knockdown"},{"t":5,"n":"Recovery Time"},{"t":5,"n":"Stamina Mult"}]}]}]},{"t":3,"n":"SPOR - Spectator override package list"},{"t":3,"n":"OCOR - Observe dead body override package list"},{"t":3,"n":"GWOR - Guard warn override package list"},{"t":3,"n":"ECOR - Combat override package list"},{"t":3,"n":"PRKZ - Perk Count"},{"t":10,"n":"Perks","c":[{"t":6,"n":"PRKR - Perk","c":[{"t":3,"n":"Perk"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"COCT - Count"},{"t":10,"n":"Items","c":[{"t":6,"n":"Item","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]}]},{"t":6,"s":1,"p":1,"n":"AIDT - AI Data","c":[{"t":3,"p":1,"n":"Aggression"},{"t":3,"p":1,"n":"Confidence"},{"t":3,"p":1,"n":"Energy Level"},{"t":3,"p":1,"n":"Responsibility"},{"t":3,"p":1,"n":"Mood"},{"t":3,"p":1,"n":"Assistance"},{"t":6,"p":1,"n":"Aggro","c":[{"t":3,"p":1,"n":"Aggro Radius Behavior"},{"t":3,"p":1,"n":"Unknown"},{"t":3,"p":1,"n":"Warn"},{"t":3,"p":1,"n":"Warn\/Attack"},{"t":3,"p":1,"n":"Attack"}]}]},{"t":7,"n":"Packages","c":[{"t":3,"n":"PKID - Package"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":3,"n":"CNAM - Class"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"SHRT - Short Name"},{"t":11,"n":"DATA - Marker"},{"t":6,"n":"DNAM - Player Skills","c":[{"t":7,"n":"Skill Values","c":[{"t":3,"n":"Skill #0 (OneHanded)"},{"t":3,"n":"Skill #1 (TwoHanded)"},{"t":3,"n":"Skill #2 (Marksman)"},{"t":3,"n":"Skill #3 (Block)"},{"t":3,"n":"Skill #4 (Smithing)"},{"t":3,"n":"Skill #5 (HeavyArmor)"},{"t":3,"n":"Skill #6 (LightArmor)"},{"t":3,"n":"Skill #7 (Pickpocket)"},{"t":3,"n":"Skill #8 (Lockpicking)"},{"t":3,"n":"Skill #9 (Sneak)"},{"t":3,"n":"Skill #10 (Alchemy)"},{"t":3,"n":"Skill #11 (Speechcraft)"},{"t":3,"n":"Skill #12 (Alteration)"},{"t":3,"n":"Skill #13 (Conjuration)"},{"t":3,"n":"Skill #14 (Destruction)"},{"t":3,"n":"Skill #15 (Illusion)"},{"t":3,"n":"Skill #16 (Restoration)"},{"t":3,"n":"Skill #17 (Enchanting)"}]},{"t":7,"n":"Skill Offsets","c":[{"t":3,"n":"Skill #0 (OneHanded)"},{"t":3,"n":"Skill #1 (TwoHanded)"},{"t":3,"n":"Skill #2 (Marksman)"},{"t":3,"n":"Skill #3 (Block)"},{"t":3,"n":"Skill #4 (Smithing)"},{"t":3,"n":"Skill #5 (HeavyArmor)"},{"t":3,"n":"Skill #6 (LightArmor)"},{"t":3,"n":"Skill #7 (Pickpocket)"},{"t":3,"n":"Skill #8 (Lockpicking)"},{"t":3,"n":"Skill #9 (Sneak)"},{"t":3,"n":"Skill #10 (Alchemy)"},{"t":3,"n":"Skill #11 (Speechcraft)"},{"t":3,"n":"Skill #12 (Alteration)"},{"t":3,"n":"Skill #13 (Conjuration)"},{"t":3,"n":"Skill #14 (Destruction)"},{"t":3,"n":"Skill #15 (Illusion)"},{"t":3,"n":"Skill #16 (Restoration)"},{"t":3,"n":"Skill #17 (Enchanting)"}]},{"t":3,"n":"Health"},{"t":3,"n":"Magicka"},{"t":3,"n":"Stamina"},{"t":11,"n":"Unused"},{"t":5,"n":"Far away model distance"},{"t":3,"n":"Geared up weapons"},{"t":11,"n":"Unused"}]},{"t":9,"n":"Head Parts","c":[{"t":3,"n":"PNAM - Head Part"}]},{"t":3,"n":"HCLF - Hair Color"},{"t":3,"n":"ZNAM - Combat Style"},{"t":3,"n":"GNAM - Gift Filter"},{"t":11,"n":"NAM5 - Unknown"},{"t":5,"n":"NAM6 - Height"},{"t":5,"n":"NAM7 - Weight"},{"t":3,"n":"NAM8 - Sound Level"},{"t":10,"n":"Sound Types","c":[{"t":6,"n":"Sound Type","c":[{"t":3,"n":"CSDT - Type"},{"t":10,"n":"Sounds","c":[{"t":6,"n":"Sound","c":[{"t":3,"n":"CSDI - Sound"},{"t":3,"n":"CSDC - Sound Chance"}]}]}]}]},{"t":3,"n":"CSCR - Inherits Sounds From"},{"t":3,"n":"DOFT - Default outfit"},{"t":3,"n":"SOFT - Sleeping outfit"},{"t":3,"n":"DPLT - Default Package List"},{"t":3,"n":"CRIF - Crime faction"},{"t":3,"n":"FTST - Head texture"},{"t":6,"n":"QNAM - Texture lighting","c":[{"t":5,"n":"Red"},{"t":5,"n":"Green"},{"t":5,"n":"Blue"}]},{"t":6,"n":"NAM9 - Face morph","c":[{"t":5,"n":"Nose Long\/Short"},{"t":5,"n":"Nose Up\/Down"},{"t":5,"n":"Jaw Up\/Down"},{"t":5,"n":"Jaw Narrow\/Wide"},{"t":5,"n":"Jaw Farward\/Back"},{"t":5,"n":"Cheeks Up\/Down"},{"t":5,"n":"Cheeks Farward\/Back"},{"t":5,"n":"Eyes Up\/Down"},{"t":5,"n":"Eyes In\/Out"},{"t":5,"n":"Brows Up\/Down"},{"t":5,"n":"Brows In\/Out"},{"t":5,"n":"Brows Farward\/Back"},{"t":5,"n":"Lips Up\/Down"},{"t":5,"n":"Lips In\/Out"},{"t":5,"n":"Chin Narrow\/Wide"},{"t":5,"n":"Chin Up\/Down"},{"t":5,"n":"Chin Underbite\/Overbite"},{"t":5,"n":"Eyes Farward\/Back"},{"t":5,"n":"Unknown"}]},{"t":6,"n":"NAMA - Face parts","c":[{"t":3,"n":"Nose"},{"t":3,"n":"Unknown"},{"t":3,"n":"Eyes"},{"t":3,"n":"Mouth"}]},{"t":10,"n":"Tint Layers","c":[{"t":6,"n":"Layer","c":[{"t":3,"n":"TINI - Tint Index"}]}]}]}]},"name":"Bash.Actors.AIData","hash":"$E4A27332","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.Actors.AIPackages.json ================================================ {"records":"NPC_","description":"Actors.AIPackages tag from Wrye Bash.\r\n\r\nUsed when the mod modifies NPC AI packages list.","tree":{"records":[{"t":1,"p":1,"n":"NPC_ - Non-Player Character (Actor)","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Magicka Offset"},{"t":3,"n":"Stamina Offset"},{"t":12,"n":"Level"},{"t":3,"n":"Calc min level"},{"t":3,"n":"Calc max level"},{"t":3,"n":"Speed Multiplier"},{"t":3,"n":"Disposition Base (unused)"},{"t":3,"n":"Template Flags"},{"t":3,"n":"Health Offset"},{"t":3,"n":"Bleedout Override"}]},{"t":10,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"VTCK - Voice"},{"t":3,"n":"TPLT - Template"},{"t":3,"n":"RNAM - Race"},{"t":3,"n":"SPCT - Count"},{"t":9,"n":"Actor Effects","c":[{"t":3,"n":"SPLO - Actor Effect"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"WNAM - Worn Armor"},{"t":3,"n":"ANAM - Far away model"},{"t":3,"n":"ATKR - Attack Race"},{"t":10,"n":"Attacks","c":[{"t":6,"n":"Attack","c":[{"t":6,"n":"ATKD - Attack Data","c":[{"t":5,"n":"Damage Mult"},{"t":5,"n":"Attack Chance"},{"t":3,"n":"Attack Spell"},{"t":3,"n":"Attack Flags"},{"t":5,"n":"Attack Angle"},{"t":5,"n":"Strike Angle"},{"t":5,"n":"Stagger"},{"t":3,"n":"Attack Type"},{"t":5,"n":"Knockdown"},{"t":5,"n":"Recovery Time"},{"t":5,"n":"Stamina Mult"}]}]}]},{"t":3,"n":"SPOR - Spectator override package list"},{"t":3,"n":"OCOR - Observe dead body override package list"},{"t":3,"n":"GWOR - Guard warn override package list"},{"t":3,"n":"ECOR - Combat override package list"},{"t":3,"n":"PRKZ - Perk Count"},{"t":10,"n":"Perks","c":[{"t":6,"n":"PRKR - Perk","c":[{"t":3,"n":"Perk"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"COCT - Count"},{"t":10,"n":"Items","c":[{"t":6,"n":"Item","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]}]},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Mood"},{"t":3,"n":"Assistance"},{"t":6,"n":"Aggro","c":[{"t":3,"n":"Aggro Radius Behavior"},{"t":3,"n":"Unknown"},{"t":3,"n":"Warn"},{"t":3,"n":"Warn\/Attack"},{"t":3,"n":"Attack"}]}]},{"t":7,"s":1,"p":1,"n":"Packages","d":1,"c":[{"t":3,"p":1,"n":"PKID - Package"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":3,"n":"CNAM - Class"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"SHRT - Short Name"},{"t":11,"n":"DATA - Marker"},{"t":6,"n":"DNAM - Player Skills","c":[{"t":7,"n":"Skill Values","c":[{"t":3,"n":"Skill #0 (OneHanded)"},{"t":3,"n":"Skill #1 (TwoHanded)"},{"t":3,"n":"Skill #2 (Marksman)"},{"t":3,"n":"Skill #3 (Block)"},{"t":3,"n":"Skill #4 (Smithing)"},{"t":3,"n":"Skill #5 (HeavyArmor)"},{"t":3,"n":"Skill #6 (LightArmor)"},{"t":3,"n":"Skill #7 (Pickpocket)"},{"t":3,"n":"Skill #8 (Lockpicking)"},{"t":3,"n":"Skill #9 (Sneak)"},{"t":3,"n":"Skill #10 (Alchemy)"},{"t":3,"n":"Skill #11 (Speechcraft)"},{"t":3,"n":"Skill #12 (Alteration)"},{"t":3,"n":"Skill #13 (Conjuration)"},{"t":3,"n":"Skill #14 (Destruction)"},{"t":3,"n":"Skill #15 (Illusion)"},{"t":3,"n":"Skill #16 (Restoration)"},{"t":3,"n":"Skill #17 (Enchanting)"}]},{"t":7,"n":"Skill Offsets","c":[{"t":3,"n":"Skill #0 (OneHanded)"},{"t":3,"n":"Skill #1 (TwoHanded)"},{"t":3,"n":"Skill #2 (Marksman)"},{"t":3,"n":"Skill #3 (Block)"},{"t":3,"n":"Skill #4 (Smithing)"},{"t":3,"n":"Skill #5 (HeavyArmor)"},{"t":3,"n":"Skill #6 (LightArmor)"},{"t":3,"n":"Skill #7 (Pickpocket)"},{"t":3,"n":"Skill #8 (Lockpicking)"},{"t":3,"n":"Skill #9 (Sneak)"},{"t":3,"n":"Skill #10 (Alchemy)"},{"t":3,"n":"Skill #11 (Speechcraft)"},{"t":3,"n":"Skill #12 (Alteration)"},{"t":3,"n":"Skill #13 (Conjuration)"},{"t":3,"n":"Skill #14 (Destruction)"},{"t":3,"n":"Skill #15 (Illusion)"},{"t":3,"n":"Skill #16 (Restoration)"},{"t":3,"n":"Skill #17 (Enchanting)"}]},{"t":3,"n":"Health"},{"t":3,"n":"Magicka"},{"t":3,"n":"Stamina"},{"t":11,"n":"Unused"},{"t":5,"n":"Far away model distance"},{"t":3,"n":"Geared up weapons"},{"t":11,"n":"Unused"}]},{"t":9,"n":"Head Parts","c":[{"t":3,"n":"PNAM - Head Part"}]},{"t":3,"n":"HCLF - Hair Color"},{"t":3,"n":"ZNAM - Combat Style"},{"t":3,"n":"GNAM - Gift Filter"},{"t":11,"n":"NAM5 - Unknown"},{"t":5,"n":"NAM6 - Height"},{"t":5,"n":"NAM7 - Weight"},{"t":3,"n":"NAM8 - Sound Level"},{"t":10,"n":"Sound Types","c":[{"t":6,"n":"Sound Type","c":[{"t":3,"n":"CSDT - Type"},{"t":10,"n":"Sounds","c":[{"t":6,"n":"Sound","c":[{"t":3,"n":"CSDI - Sound"},{"t":3,"n":"CSDC - Sound Chance"}]}]}]}]},{"t":3,"n":"CSCR - Inherits Sounds From"},{"t":3,"n":"DOFT - Default outfit"},{"t":3,"n":"SOFT - Sleeping outfit"},{"t":3,"n":"DPLT - Default Package List"},{"t":3,"n":"CRIF - Crime faction"},{"t":3,"n":"FTST - Head texture"},{"t":6,"n":"QNAM - Texture lighting","c":[{"t":5,"n":"Red"},{"t":5,"n":"Green"},{"t":5,"n":"Blue"}]},{"t":6,"n":"NAM9 - Face morph","c":[{"t":5,"n":"Nose Long\/Short"},{"t":5,"n":"Nose Up\/Down"},{"t":5,"n":"Jaw Up\/Down"},{"t":5,"n":"Jaw Narrow\/Wide"},{"t":5,"n":"Jaw Farward\/Back"},{"t":5,"n":"Cheeks Up\/Down"},{"t":5,"n":"Cheeks Farward\/Back"},{"t":5,"n":"Eyes Up\/Down"},{"t":5,"n":"Eyes In\/Out"},{"t":5,"n":"Brows Up\/Down"},{"t":5,"n":"Brows In\/Out"},{"t":5,"n":"Brows Farward\/Back"},{"t":5,"n":"Lips Up\/Down"},{"t":5,"n":"Lips In\/Out"},{"t":5,"n":"Chin Narrow\/Wide"},{"t":5,"n":"Chin Up\/Down"},{"t":5,"n":"Chin Underbite\/Overbite"},{"t":5,"n":"Eyes Farward\/Back"},{"t":5,"n":"Unknown"}]},{"t":6,"n":"NAMA - Face parts","c":[{"t":3,"n":"Nose"},{"t":3,"n":"Unknown"},{"t":3,"n":"Eyes"},{"t":3,"n":"Mouth"}]},{"t":10,"n":"Tint Layers","c":[{"t":6,"n":"Layer","c":[{"t":3,"n":"TINI - Tint Index"}]}]}]}]},"name":"Bash.Actors.AIPackages","hash":"$4707BEC7","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.Actors.AIPackagesMerge.json ================================================ {"records":"NPC_","description":"An alternative to the Actors.AIPackagesForceAdd tag from Wrye Bash.\r\n\r\nMator Smash cannot currently perform the logic for a forced addition as Wrye Bash does with the Actors.AIPackagesForceAdd tag. This tag does the next best thing, which causes packages to be merged.","tree":{"records":[{"t":1,"p":1,"n":"NPC_ - Non-Player Character (Actor)","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Magicka Offset"},{"t":3,"n":"Stamina Offset"},{"t":12,"n":"Level"},{"t":3,"n":"Calc min level"},{"t":3,"n":"Calc max level"},{"t":3,"n":"Speed Multiplier"},{"t":3,"n":"Disposition Base (unused)"},{"t":3,"n":"Template Flags"},{"t":3,"n":"Health Offset"},{"t":3,"n":"Bleedout Override"}]},{"t":10,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"VTCK - Voice"},{"t":3,"n":"TPLT - Template"},{"t":3,"n":"RNAM - Race"},{"t":3,"n":"SPCT - Count"},{"t":9,"n":"Actor Effects","c":[{"t":3,"n":"SPLO - Actor Effect"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"WNAM - Worn Armor"},{"t":3,"n":"ANAM - Far away model"},{"t":3,"n":"ATKR - Attack Race"},{"t":10,"n":"Attacks","c":[{"t":6,"n":"Attack","c":[{"t":6,"n":"ATKD - Attack Data","c":[{"t":5,"n":"Damage Mult"},{"t":5,"n":"Attack Chance"},{"t":3,"n":"Attack Spell"},{"t":3,"n":"Attack Flags"},{"t":5,"n":"Attack Angle"},{"t":5,"n":"Strike Angle"},{"t":5,"n":"Stagger"},{"t":3,"n":"Attack Type"},{"t":5,"n":"Knockdown"},{"t":5,"n":"Recovery Time"},{"t":5,"n":"Stamina Mult"}]}]}]},{"t":3,"n":"SPOR - Spectator override package list"},{"t":3,"n":"OCOR - Observe dead body override package list"},{"t":3,"n":"GWOR - Guard warn override package list"},{"t":3,"n":"ECOR - Combat override package list"},{"t":3,"n":"PRKZ - Perk Count"},{"t":10,"n":"Perks","c":[{"t":6,"n":"PRKR - Perk","c":[{"t":3,"n":"Perk"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"COCT - Count"},{"t":10,"n":"Items","c":[{"t":6,"n":"Item","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]}]},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Mood"},{"t":3,"n":"Assistance"},{"t":6,"n":"Aggro","c":[{"t":3,"n":"Aggro Radius Behavior"},{"t":3,"n":"Unknown"},{"t":3,"n":"Warn"},{"t":3,"n":"Warn\/Attack"},{"t":3,"n":"Attack"}]}]},{"t":7,"p":1,"n":"Packages","c":[{"t":3,"p":1,"n":"PKID - Package"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":3,"n":"CNAM - Class"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"SHRT - Short Name"},{"t":11,"n":"DATA - Marker"},{"t":6,"n":"DNAM - Player Skills","c":[{"t":7,"n":"Skill Values","c":[{"t":3,"n":"Skill #0 (OneHanded)"},{"t":3,"n":"Skill #1 (TwoHanded)"},{"t":3,"n":"Skill #2 (Marksman)"},{"t":3,"n":"Skill #3 (Block)"},{"t":3,"n":"Skill #4 (Smithing)"},{"t":3,"n":"Skill #5 (HeavyArmor)"},{"t":3,"n":"Skill #6 (LightArmor)"},{"t":3,"n":"Skill #7 (Pickpocket)"},{"t":3,"n":"Skill #8 (Lockpicking)"},{"t":3,"n":"Skill #9 (Sneak)"},{"t":3,"n":"Skill #10 (Alchemy)"},{"t":3,"n":"Skill #11 (Speechcraft)"},{"t":3,"n":"Skill #12 (Alteration)"},{"t":3,"n":"Skill #13 (Conjuration)"},{"t":3,"n":"Skill #14 (Destruction)"},{"t":3,"n":"Skill #15 (Illusion)"},{"t":3,"n":"Skill #16 (Restoration)"},{"t":3,"n":"Skill #17 (Enchanting)"}]},{"t":7,"n":"Skill Offsets","c":[{"t":3,"n":"Skill #0 (OneHanded)"},{"t":3,"n":"Skill #1 (TwoHanded)"},{"t":3,"n":"Skill #2 (Marksman)"},{"t":3,"n":"Skill #3 (Block)"},{"t":3,"n":"Skill #4 (Smithing)"},{"t":3,"n":"Skill #5 (HeavyArmor)"},{"t":3,"n":"Skill #6 (LightArmor)"},{"t":3,"n":"Skill #7 (Pickpocket)"},{"t":3,"n":"Skill #8 (Lockpicking)"},{"t":3,"n":"Skill #9 (Sneak)"},{"t":3,"n":"Skill #10 (Alchemy)"},{"t":3,"n":"Skill #11 (Speechcraft)"},{"t":3,"n":"Skill #12 (Alteration)"},{"t":3,"n":"Skill #13 (Conjuration)"},{"t":3,"n":"Skill #14 (Destruction)"},{"t":3,"n":"Skill #15 (Illusion)"},{"t":3,"n":"Skill #16 (Restoration)"},{"t":3,"n":"Skill #17 (Enchanting)"}]},{"t":3,"n":"Health"},{"t":3,"n":"Magicka"},{"t":3,"n":"Stamina"},{"t":11,"n":"Unused"},{"t":5,"n":"Far away model distance"},{"t":3,"n":"Geared up weapons"},{"t":11,"n":"Unused"}]},{"t":9,"n":"Head Parts","c":[{"t":3,"n":"PNAM - Head Part"}]},{"t":3,"n":"HCLF - Hair Color"},{"t":3,"n":"ZNAM - Combat Style"},{"t":3,"n":"GNAM - Gift Filter"},{"t":11,"n":"NAM5 - Unknown"},{"t":5,"n":"NAM6 - Height"},{"t":5,"n":"NAM7 - Weight"},{"t":3,"n":"NAM8 - Sound Level"},{"t":10,"n":"Sound Types","c":[{"t":6,"n":"Sound Type","c":[{"t":3,"n":"CSDT - Type"},{"t":10,"n":"Sounds","c":[{"t":6,"n":"Sound","c":[{"t":3,"n":"CSDI - Sound"},{"t":3,"n":"CSDC - Sound Chance"}]}]}]}]},{"t":3,"n":"CSCR - Inherits Sounds From"},{"t":3,"n":"DOFT - Default outfit"},{"t":3,"n":"SOFT - Sleeping outfit"},{"t":3,"n":"DPLT - Default Package List"},{"t":3,"n":"CRIF - Crime faction"},{"t":3,"n":"FTST - Head texture"},{"t":6,"n":"QNAM - Texture lighting","c":[{"t":5,"n":"Red"},{"t":5,"n":"Green"},{"t":5,"n":"Blue"}]},{"t":6,"n":"NAM9 - Face morph","c":[{"t":5,"n":"Nose Long\/Short"},{"t":5,"n":"Nose Up\/Down"},{"t":5,"n":"Jaw Up\/Down"},{"t":5,"n":"Jaw Narrow\/Wide"},{"t":5,"n":"Jaw Farward\/Back"},{"t":5,"n":"Cheeks Up\/Down"},{"t":5,"n":"Cheeks Farward\/Back"},{"t":5,"n":"Eyes Up\/Down"},{"t":5,"n":"Eyes In\/Out"},{"t":5,"n":"Brows Up\/Down"},{"t":5,"n":"Brows In\/Out"},{"t":5,"n":"Brows Farward\/Back"},{"t":5,"n":"Lips Up\/Down"},{"t":5,"n":"Lips In\/Out"},{"t":5,"n":"Chin Narrow\/Wide"},{"t":5,"n":"Chin Up\/Down"},{"t":5,"n":"Chin Underbite\/Overbite"},{"t":5,"n":"Eyes Farward\/Back"},{"t":5,"n":"Unknown"}]},{"t":6,"n":"NAMA - Face parts","c":[{"t":3,"n":"Nose"},{"t":3,"n":"Unknown"},{"t":3,"n":"Eyes"},{"t":3,"n":"Mouth"}]},{"t":10,"n":"Tint Layers","c":[{"t":6,"n":"Layer","c":[{"t":3,"n":"TINI - Tint Index"}]}]}]}]},"name":"Bash.Actors.AIPackagesMerge","hash":"$11434ADE","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.Actors.CombatStyle.json ================================================ {"records":"NPC_","description":"Actors.CombatStyle tag from Wrye Bash.\r\n\r\nUsed when the mod modifies NPC combat styles.","tree":{"records":[{"t":1,"p":1,"n":"NPC_ - Non-Player Character (Actor)","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Magicka Offset"},{"t":3,"n":"Stamina Offset"},{"t":12,"n":"Level"},{"t":3,"n":"Calc min level"},{"t":3,"n":"Calc max level"},{"t":3,"n":"Speed Multiplier"},{"t":3,"n":"Disposition Base (unused)"},{"t":3,"n":"Template Flags"},{"t":3,"n":"Health Offset"},{"t":3,"n":"Bleedout Override"}]},{"t":10,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"VTCK - Voice"},{"t":3,"n":"TPLT - Template"},{"t":3,"n":"RNAM - Race"},{"t":3,"n":"SPCT - Count"},{"t":9,"n":"Actor Effects","c":[{"t":3,"n":"SPLO - Actor Effect"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"WNAM - Worn Armor"},{"t":3,"n":"ANAM - Far away model"},{"t":3,"n":"ATKR - Attack Race"},{"t":10,"n":"Attacks","c":[{"t":6,"n":"Attack","c":[{"t":6,"n":"ATKD - Attack Data","c":[{"t":5,"n":"Damage Mult"},{"t":5,"n":"Attack Chance"},{"t":3,"n":"Attack Spell"},{"t":3,"n":"Attack Flags"},{"t":5,"n":"Attack Angle"},{"t":5,"n":"Strike Angle"},{"t":5,"n":"Stagger"},{"t":3,"n":"Attack Type"},{"t":5,"n":"Knockdown"},{"t":5,"n":"Recovery Time"},{"t":5,"n":"Stamina Mult"}]}]}]},{"t":3,"n":"SPOR - Spectator override package list"},{"t":3,"n":"OCOR - Observe dead body override package list"},{"t":3,"n":"GWOR - Guard warn override package list"},{"t":3,"n":"ECOR - Combat override package list"},{"t":3,"n":"PRKZ - Perk Count"},{"t":10,"n":"Perks","c":[{"t":6,"n":"PRKR - Perk","c":[{"t":3,"n":"Perk"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"COCT - Count"},{"t":10,"n":"Items","c":[{"t":6,"n":"Item","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]}]},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Mood"},{"t":3,"n":"Assistance"},{"t":6,"n":"Aggro","c":[{"t":3,"n":"Aggro Radius Behavior"},{"t":3,"n":"Unknown"},{"t":3,"n":"Warn"},{"t":3,"n":"Warn\/Attack"},{"t":3,"n":"Attack"}]}]},{"t":7,"n":"Packages","c":[{"t":3,"n":"PKID - Package"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":3,"n":"CNAM - Class"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"SHRT - Short Name"},{"t":11,"n":"DATA - Marker"},{"t":6,"n":"DNAM - Player Skills","c":[{"t":7,"n":"Skill Values","c":[{"t":3,"n":"Skill #0 (OneHanded)"},{"t":3,"n":"Skill #1 (TwoHanded)"},{"t":3,"n":"Skill #2 (Marksman)"},{"t":3,"n":"Skill #3 (Block)"},{"t":3,"n":"Skill #4 (Smithing)"},{"t":3,"n":"Skill #5 (HeavyArmor)"},{"t":3,"n":"Skill #6 (LightArmor)"},{"t":3,"n":"Skill #7 (Pickpocket)"},{"t":3,"n":"Skill #8 (Lockpicking)"},{"t":3,"n":"Skill #9 (Sneak)"},{"t":3,"n":"Skill #10 (Alchemy)"},{"t":3,"n":"Skill #11 (Speechcraft)"},{"t":3,"n":"Skill #12 (Alteration)"},{"t":3,"n":"Skill #13 (Conjuration)"},{"t":3,"n":"Skill #14 (Destruction)"},{"t":3,"n":"Skill #15 (Illusion)"},{"t":3,"n":"Skill #16 (Restoration)"},{"t":3,"n":"Skill #17 (Enchanting)"}]},{"t":7,"n":"Skill Offsets","c":[{"t":3,"n":"Skill #0 (OneHanded)"},{"t":3,"n":"Skill #1 (TwoHanded)"},{"t":3,"n":"Skill #2 (Marksman)"},{"t":3,"n":"Skill #3 (Block)"},{"t":3,"n":"Skill #4 (Smithing)"},{"t":3,"n":"Skill #5 (HeavyArmor)"},{"t":3,"n":"Skill #6 (LightArmor)"},{"t":3,"n":"Skill #7 (Pickpocket)"},{"t":3,"n":"Skill #8 (Lockpicking)"},{"t":3,"n":"Skill #9 (Sneak)"},{"t":3,"n":"Skill #10 (Alchemy)"},{"t":3,"n":"Skill #11 (Speechcraft)"},{"t":3,"n":"Skill #12 (Alteration)"},{"t":3,"n":"Skill #13 (Conjuration)"},{"t":3,"n":"Skill #14 (Destruction)"},{"t":3,"n":"Skill #15 (Illusion)"},{"t":3,"n":"Skill #16 (Restoration)"},{"t":3,"n":"Skill #17 (Enchanting)"}]},{"t":3,"n":"Health"},{"t":3,"n":"Magicka"},{"t":3,"n":"Stamina"},{"t":11,"n":"Unused"},{"t":5,"n":"Far away model distance"},{"t":3,"n":"Geared up weapons"},{"t":11,"n":"Unused"}]},{"t":9,"n":"Head Parts","c":[{"t":3,"n":"PNAM - Head Part"}]},{"t":3,"n":"HCLF - Hair Color"},{"t":3,"p":1,"n":"ZNAM - Combat Style"},{"t":3,"n":"GNAM - Gift Filter"},{"t":11,"n":"NAM5 - Unknown"},{"t":5,"n":"NAM6 - Height"},{"t":5,"n":"NAM7 - Weight"},{"t":3,"n":"NAM8 - Sound Level"},{"t":10,"n":"Sound Types","c":[{"t":6,"n":"Sound Type","c":[{"t":3,"n":"CSDT - Type"},{"t":10,"n":"Sounds","c":[{"t":6,"n":"Sound","c":[{"t":3,"n":"CSDI - Sound"},{"t":3,"n":"CSDC - Sound Chance"}]}]}]}]},{"t":3,"n":"CSCR - Inherits Sounds From"},{"t":3,"n":"DOFT - Default outfit"},{"t":3,"n":"SOFT - Sleeping outfit"},{"t":3,"n":"DPLT - Default Package List"},{"t":3,"n":"CRIF - Crime faction"},{"t":3,"n":"FTST - Head texture"},{"t":6,"n":"QNAM - Texture lighting","c":[{"t":5,"n":"Red"},{"t":5,"n":"Green"},{"t":5,"n":"Blue"}]},{"t":6,"n":"NAM9 - Face morph","c":[{"t":5,"n":"Nose Long\/Short"},{"t":5,"n":"Nose Up\/Down"},{"t":5,"n":"Jaw Up\/Down"},{"t":5,"n":"Jaw Narrow\/Wide"},{"t":5,"n":"Jaw Farward\/Back"},{"t":5,"n":"Cheeks Up\/Down"},{"t":5,"n":"Cheeks Farward\/Back"},{"t":5,"n":"Eyes Up\/Down"},{"t":5,"n":"Eyes In\/Out"},{"t":5,"n":"Brows Up\/Down"},{"t":5,"n":"Brows In\/Out"},{"t":5,"n":"Brows Farward\/Back"},{"t":5,"n":"Lips Up\/Down"},{"t":5,"n":"Lips In\/Out"},{"t":5,"n":"Chin Narrow\/Wide"},{"t":5,"n":"Chin Up\/Down"},{"t":5,"n":"Chin Underbite\/Overbite"},{"t":5,"n":"Eyes Farward\/Back"},{"t":5,"n":"Unknown"}]},{"t":6,"n":"NAMA - Face parts","c":[{"t":3,"n":"Nose"},{"t":3,"n":"Unknown"},{"t":3,"n":"Eyes"},{"t":3,"n":"Mouth"}]},{"t":10,"n":"Tint Layers","c":[{"t":6,"n":"Layer","c":[{"t":3,"n":"TINI - Tint Index"}]}]}]}]},"name":"Bash.Actors.CombatStyle","hash":"$1593A13F","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.Actors.DeathItem.json ================================================ {"records":"NPC_","description":"Actors.DeathItem tag from Wrye Bash.\r\n\r\nUsed when the mod modifies NPC death items.","tree":{"records":[{"t":1,"p":1,"n":"NPC_ - Non-Player Character (Actor)","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Magicka Offset"},{"t":3,"n":"Stamina Offset"},{"t":12,"n":"Level"},{"t":3,"n":"Calc min level"},{"t":3,"n":"Calc max level"},{"t":3,"n":"Speed Multiplier"},{"t":3,"n":"Disposition Base (unused)"},{"t":3,"n":"Template Flags"},{"t":3,"n":"Health Offset"},{"t":3,"n":"Bleedout Override"}]},{"t":10,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"p":1,"n":"INAM - Death item"},{"t":3,"n":"VTCK - Voice"},{"t":3,"n":"TPLT - Template"},{"t":3,"n":"RNAM - Race"},{"t":3,"n":"SPCT - Count"},{"t":9,"n":"Actor Effects","c":[{"t":3,"n":"SPLO - Actor Effect"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"WNAM - Worn Armor"},{"t":3,"n":"ANAM - Far away model"},{"t":3,"n":"ATKR - Attack Race"},{"t":10,"n":"Attacks","c":[{"t":6,"n":"Attack","c":[{"t":6,"n":"ATKD - Attack Data","c":[{"t":5,"n":"Damage Mult"},{"t":5,"n":"Attack Chance"},{"t":3,"n":"Attack Spell"},{"t":3,"n":"Attack Flags"},{"t":5,"n":"Attack Angle"},{"t":5,"n":"Strike Angle"},{"t":5,"n":"Stagger"},{"t":3,"n":"Attack Type"},{"t":5,"n":"Knockdown"},{"t":5,"n":"Recovery Time"},{"t":5,"n":"Stamina Mult"}]}]}]},{"t":3,"n":"SPOR - Spectator override package list"},{"t":3,"n":"OCOR - Observe dead body override package list"},{"t":3,"n":"GWOR - Guard warn override package list"},{"t":3,"n":"ECOR - Combat override package list"},{"t":3,"n":"PRKZ - Perk Count"},{"t":10,"n":"Perks","c":[{"t":6,"n":"PRKR - Perk","c":[{"t":3,"n":"Perk"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"COCT - Count"},{"t":10,"n":"Items","c":[{"t":6,"n":"Item","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]}]},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Mood"},{"t":3,"n":"Assistance"},{"t":6,"n":"Aggro","c":[{"t":3,"n":"Aggro Radius Behavior"},{"t":3,"n":"Unknown"},{"t":3,"n":"Warn"},{"t":3,"n":"Warn\/Attack"},{"t":3,"n":"Attack"}]}]},{"t":7,"n":"Packages","c":[{"t":3,"n":"PKID - Package"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":3,"n":"CNAM - Class"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"SHRT - Short Name"},{"t":11,"n":"DATA - Marker"},{"t":6,"n":"DNAM - Player Skills","c":[{"t":7,"n":"Skill Values","c":[{"t":3,"n":"Skill #0 (OneHanded)"},{"t":3,"n":"Skill #1 (TwoHanded)"},{"t":3,"n":"Skill #2 (Marksman)"},{"t":3,"n":"Skill #3 (Block)"},{"t":3,"n":"Skill #4 (Smithing)"},{"t":3,"n":"Skill #5 (HeavyArmor)"},{"t":3,"n":"Skill #6 (LightArmor)"},{"t":3,"n":"Skill #7 (Pickpocket)"},{"t":3,"n":"Skill #8 (Lockpicking)"},{"t":3,"n":"Skill #9 (Sneak)"},{"t":3,"n":"Skill #10 (Alchemy)"},{"t":3,"n":"Skill #11 (Speechcraft)"},{"t":3,"n":"Skill #12 (Alteration)"},{"t":3,"n":"Skill #13 (Conjuration)"},{"t":3,"n":"Skill #14 (Destruction)"},{"t":3,"n":"Skill #15 (Illusion)"},{"t":3,"n":"Skill #16 (Restoration)"},{"t":3,"n":"Skill #17 (Enchanting)"}]},{"t":7,"n":"Skill Offsets","c":[{"t":3,"n":"Skill #0 (OneHanded)"},{"t":3,"n":"Skill #1 (TwoHanded)"},{"t":3,"n":"Skill #2 (Marksman)"},{"t":3,"n":"Skill #3 (Block)"},{"t":3,"n":"Skill #4 (Smithing)"},{"t":3,"n":"Skill #5 (HeavyArmor)"},{"t":3,"n":"Skill #6 (LightArmor)"},{"t":3,"n":"Skill #7 (Pickpocket)"},{"t":3,"n":"Skill #8 (Lockpicking)"},{"t":3,"n":"Skill #9 (Sneak)"},{"t":3,"n":"Skill #10 (Alchemy)"},{"t":3,"n":"Skill #11 (Speechcraft)"},{"t":3,"n":"Skill #12 (Alteration)"},{"t":3,"n":"Skill #13 (Conjuration)"},{"t":3,"n":"Skill #14 (Destruction)"},{"t":3,"n":"Skill #15 (Illusion)"},{"t":3,"n":"Skill #16 (Restoration)"},{"t":3,"n":"Skill #17 (Enchanting)"}]},{"t":3,"n":"Health"},{"t":3,"n":"Magicka"},{"t":3,"n":"Stamina"},{"t":11,"n":"Unused"},{"t":5,"n":"Far away model distance"},{"t":3,"n":"Geared up weapons"},{"t":11,"n":"Unused"}]},{"t":9,"n":"Head Parts","c":[{"t":3,"n":"PNAM - Head Part"}]},{"t":3,"n":"HCLF - Hair Color"},{"t":3,"n":"ZNAM - Combat Style"},{"t":3,"n":"GNAM - Gift Filter"},{"t":11,"n":"NAM5 - Unknown"},{"t":5,"n":"NAM6 - Height"},{"t":5,"n":"NAM7 - Weight"},{"t":3,"n":"NAM8 - Sound Level"},{"t":10,"n":"Sound Types","c":[{"t":6,"n":"Sound Type","c":[{"t":3,"n":"CSDT - Type"},{"t":10,"n":"Sounds","c":[{"t":6,"n":"Sound","c":[{"t":3,"n":"CSDI - Sound"},{"t":3,"n":"CSDC - Sound Chance"}]}]}]}]},{"t":3,"n":"CSCR - Inherits Sounds From"},{"t":3,"n":"DOFT - Default outfit"},{"t":3,"n":"SOFT - Sleeping outfit"},{"t":3,"n":"DPLT - Default Package List"},{"t":3,"n":"CRIF - Crime faction"},{"t":3,"n":"FTST - Head texture"},{"t":6,"n":"QNAM - Texture lighting","c":[{"t":5,"n":"Red"},{"t":5,"n":"Green"},{"t":5,"n":"Blue"}]},{"t":6,"n":"NAM9 - Face morph","c":[{"t":5,"n":"Nose Long\/Short"},{"t":5,"n":"Nose Up\/Down"},{"t":5,"n":"Jaw Up\/Down"},{"t":5,"n":"Jaw Narrow\/Wide"},{"t":5,"n":"Jaw Farward\/Back"},{"t":5,"n":"Cheeks Up\/Down"},{"t":5,"n":"Cheeks Farward\/Back"},{"t":5,"n":"Eyes Up\/Down"},{"t":5,"n":"Eyes In\/Out"},{"t":5,"n":"Brows Up\/Down"},{"t":5,"n":"Brows In\/Out"},{"t":5,"n":"Brows Farward\/Back"},{"t":5,"n":"Lips Up\/Down"},{"t":5,"n":"Lips In\/Out"},{"t":5,"n":"Chin Narrow\/Wide"},{"t":5,"n":"Chin Up\/Down"},{"t":5,"n":"Chin Underbite\/Overbite"},{"t":5,"n":"Eyes Farward\/Back"},{"t":5,"n":"Unknown"}]},{"t":6,"n":"NAMA - Face parts","c":[{"t":3,"n":"Nose"},{"t":3,"n":"Unknown"},{"t":3,"n":"Eyes"},{"t":3,"n":"Mouth"}]},{"t":10,"n":"Tint Layers","c":[{"t":6,"n":"Layer","c":[{"t":3,"n":"TINI - Tint Index"}]}]}]}]},"name":"Bash.Actors.DeathItem","hash":"$EB6FA4F8","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.Actors.Spells.json ================================================ {"records":"NPC_","description":"Actors.Spells tag from Wrye Bash.\r\n\r\nUsed when the mod modifies NPC spell lists.","tree":{"records":[{"t":1,"p":1,"n":"NPC_ - Non-Player Character (Actor)","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Magicka Offset"},{"t":3,"n":"Stamina Offset"},{"t":12,"n":"Level"},{"t":3,"n":"Calc min level"},{"t":3,"n":"Calc max level"},{"t":3,"n":"Speed Multiplier"},{"t":3,"n":"Disposition Base (unused)"},{"t":3,"n":"Template Flags"},{"t":3,"n":"Health Offset"},{"t":3,"n":"Bleedout Override"}]},{"t":10,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"VTCK - Voice"},{"t":3,"n":"TPLT - Template"},{"t":3,"n":"RNAM - Race"},{"t":3,"n":"SPCT - Count"},{"t":9,"s":1,"p":1,"n":"Actor Effects","d":1,"c":[{"t":3,"p":1,"n":"SPLO - Actor Effect"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"WNAM - Worn Armor"},{"t":3,"n":"ANAM - Far away model"},{"t":3,"n":"ATKR - Attack Race"},{"t":10,"n":"Attacks","c":[{"t":6,"n":"Attack","c":[{"t":6,"n":"ATKD - Attack Data","c":[{"t":5,"n":"Damage Mult"},{"t":5,"n":"Attack Chance"},{"t":3,"n":"Attack Spell"},{"t":3,"n":"Attack Flags"},{"t":5,"n":"Attack Angle"},{"t":5,"n":"Strike Angle"},{"t":5,"n":"Stagger"},{"t":3,"n":"Attack Type"},{"t":5,"n":"Knockdown"},{"t":5,"n":"Recovery Time"},{"t":5,"n":"Stamina Mult"}]}]}]},{"t":3,"n":"SPOR - Spectator override package list"},{"t":3,"n":"OCOR - Observe dead body override package list"},{"t":3,"n":"GWOR - Guard warn override package list"},{"t":3,"n":"ECOR - Combat override package list"},{"t":3,"n":"PRKZ - Perk Count"},{"t":10,"n":"Perks","c":[{"t":6,"n":"PRKR - Perk","c":[{"t":3,"n":"Perk"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"COCT - Count"},{"t":10,"n":"Items","c":[{"t":6,"n":"Item","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]}]},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Mood"},{"t":3,"n":"Assistance"},{"t":6,"n":"Aggro","c":[{"t":3,"n":"Aggro Radius Behavior"},{"t":3,"n":"Unknown"},{"t":3,"n":"Warn"},{"t":3,"n":"Warn\/Attack"},{"t":3,"n":"Attack"}]}]},{"t":7,"n":"Packages","c":[{"t":3,"n":"PKID - Package"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":3,"n":"CNAM - Class"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"SHRT - Short Name"},{"t":11,"n":"DATA - Marker"},{"t":6,"n":"DNAM - Player Skills","c":[{"t":7,"n":"Skill Values","c":[{"t":3,"n":"Skill #0 (OneHanded)"},{"t":3,"n":"Skill #1 (TwoHanded)"},{"t":3,"n":"Skill #2 (Marksman)"},{"t":3,"n":"Skill #3 (Block)"},{"t":3,"n":"Skill #4 (Smithing)"},{"t":3,"n":"Skill #5 (HeavyArmor)"},{"t":3,"n":"Skill #6 (LightArmor)"},{"t":3,"n":"Skill #7 (Pickpocket)"},{"t":3,"n":"Skill #8 (Lockpicking)"},{"t":3,"n":"Skill #9 (Sneak)"},{"t":3,"n":"Skill #10 (Alchemy)"},{"t":3,"n":"Skill #11 (Speechcraft)"},{"t":3,"n":"Skill #12 (Alteration)"},{"t":3,"n":"Skill #13 (Conjuration)"},{"t":3,"n":"Skill #14 (Destruction)"},{"t":3,"n":"Skill #15 (Illusion)"},{"t":3,"n":"Skill #16 (Restoration)"},{"t":3,"n":"Skill #17 (Enchanting)"}]},{"t":7,"n":"Skill Offsets","c":[{"t":3,"n":"Skill #0 (OneHanded)"},{"t":3,"n":"Skill #1 (TwoHanded)"},{"t":3,"n":"Skill #2 (Marksman)"},{"t":3,"n":"Skill #3 (Block)"},{"t":3,"n":"Skill #4 (Smithing)"},{"t":3,"n":"Skill #5 (HeavyArmor)"},{"t":3,"n":"Skill #6 (LightArmor)"},{"t":3,"n":"Skill #7 (Pickpocket)"},{"t":3,"n":"Skill #8 (Lockpicking)"},{"t":3,"n":"Skill #9 (Sneak)"},{"t":3,"n":"Skill #10 (Alchemy)"},{"t":3,"n":"Skill #11 (Speechcraft)"},{"t":3,"n":"Skill #12 (Alteration)"},{"t":3,"n":"Skill #13 (Conjuration)"},{"t":3,"n":"Skill #14 (Destruction)"},{"t":3,"n":"Skill #15 (Illusion)"},{"t":3,"n":"Skill #16 (Restoration)"},{"t":3,"n":"Skill #17 (Enchanting)"}]},{"t":3,"n":"Health"},{"t":3,"n":"Magicka"},{"t":3,"n":"Stamina"},{"t":11,"n":"Unused"},{"t":5,"n":"Far away model distance"},{"t":3,"n":"Geared up weapons"},{"t":11,"n":"Unused"}]},{"t":9,"n":"Head Parts","c":[{"t":3,"n":"PNAM - Head Part"}]},{"t":3,"n":"HCLF - Hair Color"},{"t":3,"n":"ZNAM - Combat Style"},{"t":3,"n":"GNAM - Gift Filter"},{"t":11,"n":"NAM5 - Unknown"},{"t":5,"n":"NAM6 - Height"},{"t":5,"n":"NAM7 - Weight"},{"t":3,"n":"NAM8 - Sound Level"},{"t":10,"n":"Sound Types","c":[{"t":6,"n":"Sound Type","c":[{"t":3,"n":"CSDT - Type"},{"t":10,"n":"Sounds","c":[{"t":6,"n":"Sound","c":[{"t":3,"n":"CSDI - Sound"},{"t":3,"n":"CSDC - Sound Chance"}]}]}]}]},{"t":3,"n":"CSCR - Inherits Sounds From"},{"t":3,"n":"DOFT - Default outfit"},{"t":3,"n":"SOFT - Sleeping outfit"},{"t":3,"n":"DPLT - Default Package List"},{"t":3,"n":"CRIF - Crime faction"},{"t":3,"n":"FTST - Head texture"},{"t":6,"n":"QNAM - Texture lighting","c":[{"t":5,"n":"Red"},{"t":5,"n":"Green"},{"t":5,"n":"Blue"}]},{"t":6,"n":"NAM9 - Face morph","c":[{"t":5,"n":"Nose Long\/Short"},{"t":5,"n":"Nose Up\/Down"},{"t":5,"n":"Jaw Up\/Down"},{"t":5,"n":"Jaw Narrow\/Wide"},{"t":5,"n":"Jaw Farward\/Back"},{"t":5,"n":"Cheeks Up\/Down"},{"t":5,"n":"Cheeks Farward\/Back"},{"t":5,"n":"Eyes Up\/Down"},{"t":5,"n":"Eyes In\/Out"},{"t":5,"n":"Brows Up\/Down"},{"t":5,"n":"Brows In\/Out"},{"t":5,"n":"Brows Farward\/Back"},{"t":5,"n":"Lips Up\/Down"},{"t":5,"n":"Lips In\/Out"},{"t":5,"n":"Chin Narrow\/Wide"},{"t":5,"n":"Chin Up\/Down"},{"t":5,"n":"Chin Underbite\/Overbite"},{"t":5,"n":"Eyes Farward\/Back"},{"t":5,"n":"Unknown"}]},{"t":6,"n":"NAMA - Face parts","c":[{"t":3,"n":"Nose"},{"t":3,"n":"Unknown"},{"t":3,"n":"Eyes"},{"t":3,"n":"Mouth"}]},{"t":10,"n":"Tint Layers","c":[{"t":6,"n":"Layer","c":[{"t":3,"n":"TINI - Tint Index"}]}]}]}]},"name":"Bash.Actors.Spells","hash":"$EA31B7C4","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.Actors.SpellsMerge.json ================================================ {"records":"NPC_","description":"An alternative to the Actors.SpellsForceAdd tag from Wrye Bash.\r\n\r\nMator Smash cannot currently perform the logic for a forced addition as Wrye Bash does with the Actors.SpellsForceAdd tag. This tag does the next best thing, which causes spells to be merged.","tree":{"records":[{"t":1,"p":1,"n":"NPC_ - Non-Player Character (Actor)","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Magicka Offset"},{"t":3,"n":"Stamina Offset"},{"t":12,"n":"Level"},{"t":3,"n":"Calc min level"},{"t":3,"n":"Calc max level"},{"t":3,"n":"Speed Multiplier"},{"t":3,"n":"Disposition Base (unused)"},{"t":3,"n":"Template Flags"},{"t":3,"n":"Health Offset"},{"t":3,"n":"Bleedout Override"}]},{"t":10,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"VTCK - Voice"},{"t":3,"n":"TPLT - Template"},{"t":3,"n":"RNAM - Race"},{"t":3,"n":"SPCT - Count"},{"t":9,"p":1,"n":"Actor Effects","c":[{"t":3,"p":1,"n":"SPLO - Actor Effect"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"WNAM - Worn Armor"},{"t":3,"n":"ANAM - Far away model"},{"t":3,"n":"ATKR - Attack Race"},{"t":10,"n":"Attacks","c":[{"t":6,"n":"Attack","c":[{"t":6,"n":"ATKD - Attack Data","c":[{"t":5,"n":"Damage Mult"},{"t":5,"n":"Attack Chance"},{"t":3,"n":"Attack Spell"},{"t":3,"n":"Attack Flags"},{"t":5,"n":"Attack Angle"},{"t":5,"n":"Strike Angle"},{"t":5,"n":"Stagger"},{"t":3,"n":"Attack Type"},{"t":5,"n":"Knockdown"},{"t":5,"n":"Recovery Time"},{"t":5,"n":"Stamina Mult"}]}]}]},{"t":3,"n":"SPOR - Spectator override package list"},{"t":3,"n":"OCOR - Observe dead body override package list"},{"t":3,"n":"GWOR - Guard warn override package list"},{"t":3,"n":"ECOR - Combat override package list"},{"t":3,"n":"PRKZ - Perk Count"},{"t":10,"n":"Perks","c":[{"t":6,"n":"PRKR - Perk","c":[{"t":3,"n":"Perk"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"COCT - Count"},{"t":10,"n":"Items","c":[{"t":6,"n":"Item","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]}]},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Mood"},{"t":3,"n":"Assistance"},{"t":6,"n":"Aggro","c":[{"t":3,"n":"Aggro Radius Behavior"},{"t":3,"n":"Unknown"},{"t":3,"n":"Warn"},{"t":3,"n":"Warn\/Attack"},{"t":3,"n":"Attack"}]}]},{"t":7,"n":"Packages","c":[{"t":3,"n":"PKID - Package"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":3,"n":"CNAM - Class"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"SHRT - Short Name"},{"t":11,"n":"DATA - Marker"},{"t":6,"n":"DNAM - Player Skills","c":[{"t":7,"n":"Skill Values","c":[{"t":3,"n":"Skill #0 (OneHanded)"},{"t":3,"n":"Skill #1 (TwoHanded)"},{"t":3,"n":"Skill #2 (Marksman)"},{"t":3,"n":"Skill #3 (Block)"},{"t":3,"n":"Skill #4 (Smithing)"},{"t":3,"n":"Skill #5 (HeavyArmor)"},{"t":3,"n":"Skill #6 (LightArmor)"},{"t":3,"n":"Skill #7 (Pickpocket)"},{"t":3,"n":"Skill #8 (Lockpicking)"},{"t":3,"n":"Skill #9 (Sneak)"},{"t":3,"n":"Skill #10 (Alchemy)"},{"t":3,"n":"Skill #11 (Speechcraft)"},{"t":3,"n":"Skill #12 (Alteration)"},{"t":3,"n":"Skill #13 (Conjuration)"},{"t":3,"n":"Skill #14 (Destruction)"},{"t":3,"n":"Skill #15 (Illusion)"},{"t":3,"n":"Skill #16 (Restoration)"},{"t":3,"n":"Skill #17 (Enchanting)"}]},{"t":7,"n":"Skill Offsets","c":[{"t":3,"n":"Skill #0 (OneHanded)"},{"t":3,"n":"Skill #1 (TwoHanded)"},{"t":3,"n":"Skill #2 (Marksman)"},{"t":3,"n":"Skill #3 (Block)"},{"t":3,"n":"Skill #4 (Smithing)"},{"t":3,"n":"Skill #5 (HeavyArmor)"},{"t":3,"n":"Skill #6 (LightArmor)"},{"t":3,"n":"Skill #7 (Pickpocket)"},{"t":3,"n":"Skill #8 (Lockpicking)"},{"t":3,"n":"Skill #9 (Sneak)"},{"t":3,"n":"Skill #10 (Alchemy)"},{"t":3,"n":"Skill #11 (Speechcraft)"},{"t":3,"n":"Skill #12 (Alteration)"},{"t":3,"n":"Skill #13 (Conjuration)"},{"t":3,"n":"Skill #14 (Destruction)"},{"t":3,"n":"Skill #15 (Illusion)"},{"t":3,"n":"Skill #16 (Restoration)"},{"t":3,"n":"Skill #17 (Enchanting)"}]},{"t":3,"n":"Health"},{"t":3,"n":"Magicka"},{"t":3,"n":"Stamina"},{"t":11,"n":"Unused"},{"t":5,"n":"Far away model distance"},{"t":3,"n":"Geared up weapons"},{"t":11,"n":"Unused"}]},{"t":9,"n":"Head Parts","c":[{"t":3,"n":"PNAM - Head Part"}]},{"t":3,"n":"HCLF - Hair Color"},{"t":3,"n":"ZNAM - Combat Style"},{"t":3,"n":"GNAM - Gift Filter"},{"t":11,"n":"NAM5 - Unknown"},{"t":5,"n":"NAM6 - Height"},{"t":5,"n":"NAM7 - Weight"},{"t":3,"n":"NAM8 - Sound Level"},{"t":10,"n":"Sound Types","c":[{"t":6,"n":"Sound Type","c":[{"t":3,"n":"CSDT - Type"},{"t":10,"n":"Sounds","c":[{"t":6,"n":"Sound","c":[{"t":3,"n":"CSDI - Sound"},{"t":3,"n":"CSDC - Sound Chance"}]}]}]}]},{"t":3,"n":"CSCR - Inherits Sounds From"},{"t":3,"n":"DOFT - Default outfit"},{"t":3,"n":"SOFT - Sleeping outfit"},{"t":3,"n":"DPLT - Default Package List"},{"t":3,"n":"CRIF - Crime faction"},{"t":3,"n":"FTST - Head texture"},{"t":6,"n":"QNAM - Texture lighting","c":[{"t":5,"n":"Red"},{"t":5,"n":"Green"},{"t":5,"n":"Blue"}]},{"t":6,"n":"NAM9 - Face morph","c":[{"t":5,"n":"Nose Long\/Short"},{"t":5,"n":"Nose Up\/Down"},{"t":5,"n":"Jaw Up\/Down"},{"t":5,"n":"Jaw Narrow\/Wide"},{"t":5,"n":"Jaw Farward\/Back"},{"t":5,"n":"Cheeks Up\/Down"},{"t":5,"n":"Cheeks Farward\/Back"},{"t":5,"n":"Eyes Up\/Down"},{"t":5,"n":"Eyes In\/Out"},{"t":5,"n":"Brows Up\/Down"},{"t":5,"n":"Brows In\/Out"},{"t":5,"n":"Brows Farward\/Back"},{"t":5,"n":"Lips Up\/Down"},{"t":5,"n":"Lips In\/Out"},{"t":5,"n":"Chin Narrow\/Wide"},{"t":5,"n":"Chin Up\/Down"},{"t":5,"n":"Chin Underbite\/Overbite"},{"t":5,"n":"Eyes Farward\/Back"},{"t":5,"n":"Unknown"}]},{"t":6,"n":"NAMA - Face parts","c":[{"t":3,"n":"Nose"},{"t":3,"n":"Unknown"},{"t":3,"n":"Eyes"},{"t":3,"n":"Mouth"}]},{"t":10,"n":"Tint Layers","c":[{"t":6,"n":"Layer","c":[{"t":3,"n":"TINI - Tint Index"}]}]}]}]},"name":"Bash.Actors.SpellsMerge","hash":"$F37D6A14","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.Actors.Stats.json ================================================ {"records":"NPC_","description":"Actors.Stats tag from Wrye Bash.\r\n\r\nUsed when the mod modifies NPC stats.","tree":{"records":[{"t":1,"p":1,"n":"NPC_ - Non-Player Character (Actor)","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Magicka Offset"},{"t":3,"n":"Stamina Offset"},{"t":12,"n":"Level"},{"t":3,"n":"Calc min level"},{"t":3,"n":"Calc max level"},{"t":3,"n":"Speed Multiplier"},{"t":3,"n":"Disposition Base (unused)"},{"t":3,"n":"Template Flags"},{"t":3,"n":"Health Offset"},{"t":3,"n":"Bleedout Override"}]},{"t":10,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"VTCK - Voice"},{"t":3,"n":"TPLT - Template"},{"t":3,"n":"RNAM - Race"},{"t":3,"n":"SPCT - Count"},{"t":9,"n":"Actor Effects","c":[{"t":3,"n":"SPLO - Actor Effect"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"WNAM - Worn Armor"},{"t":3,"n":"ANAM - Far away model"},{"t":3,"n":"ATKR - Attack Race"},{"t":10,"n":"Attacks","c":[{"t":6,"n":"Attack","c":[{"t":6,"n":"ATKD - Attack Data","c":[{"t":5,"n":"Damage Mult"},{"t":5,"n":"Attack Chance"},{"t":3,"n":"Attack Spell"},{"t":3,"n":"Attack Flags"},{"t":5,"n":"Attack Angle"},{"t":5,"n":"Strike Angle"},{"t":5,"n":"Stagger"},{"t":3,"n":"Attack Type"},{"t":5,"n":"Knockdown"},{"t":5,"n":"Recovery Time"},{"t":5,"n":"Stamina Mult"}]}]}]},{"t":3,"n":"SPOR - Spectator override package list"},{"t":3,"n":"OCOR - Observe dead body override package list"},{"t":3,"n":"GWOR - Guard warn override package list"},{"t":3,"n":"ECOR - Combat override package list"},{"t":3,"n":"PRKZ - Perk Count"},{"t":10,"n":"Perks","c":[{"t":6,"n":"PRKR - Perk","c":[{"t":3,"n":"Perk"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"COCT - Count"},{"t":10,"n":"Items","c":[{"t":6,"n":"Item","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]}]},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Mood"},{"t":3,"n":"Assistance"},{"t":6,"n":"Aggro","c":[{"t":3,"n":"Aggro Radius Behavior"},{"t":3,"n":"Unknown"},{"t":3,"n":"Warn"},{"t":3,"n":"Warn\/Attack"},{"t":3,"n":"Attack"}]}]},{"t":7,"n":"Packages","c":[{"t":3,"n":"PKID - Package"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":3,"n":"CNAM - Class"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"SHRT - Short Name"},{"t":11,"n":"DATA - Marker"},{"t":6,"s":1,"p":1,"n":"DNAM - Player Skills","c":[{"t":7,"p":1,"n":"Skill Values","c":[{"t":3,"p":1,"n":"Skill #0 (OneHanded)"},{"t":3,"p":1,"n":"Skill #1 (TwoHanded)"},{"t":3,"p":1,"n":"Skill #2 (Marksman)"},{"t":3,"p":1,"n":"Skill #3 (Block)"},{"t":3,"p":1,"n":"Skill #4 (Smithing)"},{"t":3,"p":1,"n":"Skill #5 (HeavyArmor)"},{"t":3,"p":1,"n":"Skill #6 (LightArmor)"},{"t":3,"p":1,"n":"Skill #7 (Pickpocket)"},{"t":3,"p":1,"n":"Skill #8 (Lockpicking)"},{"t":3,"p":1,"n":"Skill #9 (Sneak)"},{"t":3,"p":1,"n":"Skill #10 (Alchemy)"},{"t":3,"p":1,"n":"Skill #11 (Speechcraft)"},{"t":3,"p":1,"n":"Skill #12 (Alteration)"},{"t":3,"p":1,"n":"Skill #13 (Conjuration)"},{"t":3,"p":1,"n":"Skill #14 (Destruction)"},{"t":3,"p":1,"n":"Skill #15 (Illusion)"},{"t":3,"p":1,"n":"Skill #16 (Restoration)"},{"t":3,"p":1,"n":"Skill #17 (Enchanting)"}]},{"t":7,"p":1,"n":"Skill Offsets","c":[{"t":3,"p":1,"n":"Skill #0 (OneHanded)"},{"t":3,"p":1,"n":"Skill #1 (TwoHanded)"},{"t":3,"p":1,"n":"Skill #2 (Marksman)"},{"t":3,"p":1,"n":"Skill #3 (Block)"},{"t":3,"p":1,"n":"Skill #4 (Smithing)"},{"t":3,"p":1,"n":"Skill #5 (HeavyArmor)"},{"t":3,"p":1,"n":"Skill #6 (LightArmor)"},{"t":3,"p":1,"n":"Skill #7 (Pickpocket)"},{"t":3,"p":1,"n":"Skill #8 (Lockpicking)"},{"t":3,"p":1,"n":"Skill #9 (Sneak)"},{"t":3,"p":1,"n":"Skill #10 (Alchemy)"},{"t":3,"p":1,"n":"Skill #11 (Speechcraft)"},{"t":3,"p":1,"n":"Skill #12 (Alteration)"},{"t":3,"p":1,"n":"Skill #13 (Conjuration)"},{"t":3,"p":1,"n":"Skill #14 (Destruction)"},{"t":3,"p":1,"n":"Skill #15 (Illusion)"},{"t":3,"p":1,"n":"Skill #16 (Restoration)"},{"t":3,"p":1,"n":"Skill #17 (Enchanting)"}]},{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Magicka"},{"t":3,"p":1,"n":"Stamina"},{"t":11,"p":1,"n":"Unused"},{"t":5,"p":1,"n":"Far away model distance"},{"t":3,"p":1,"n":"Geared up weapons"},{"t":11,"p":1,"n":"Unused"}]},{"t":9,"n":"Head Parts","c":[{"t":3,"n":"PNAM - Head Part"}]},{"t":3,"n":"HCLF - Hair Color"},{"t":3,"n":"ZNAM - Combat Style"},{"t":3,"n":"GNAM - Gift Filter"},{"t":11,"n":"NAM5 - Unknown"},{"t":5,"n":"NAM6 - Height"},{"t":5,"n":"NAM7 - Weight"},{"t":3,"n":"NAM8 - Sound Level"},{"t":10,"n":"Sound Types","c":[{"t":6,"n":"Sound Type","c":[{"t":3,"n":"CSDT - Type"},{"t":10,"n":"Sounds","c":[{"t":6,"n":"Sound","c":[{"t":3,"n":"CSDI - Sound"},{"t":3,"n":"CSDC - Sound Chance"}]}]}]}]},{"t":3,"n":"CSCR - Inherits Sounds From"},{"t":3,"n":"DOFT - Default outfit"},{"t":3,"n":"SOFT - Sleeping outfit"},{"t":3,"n":"DPLT - Default Package List"},{"t":3,"n":"CRIF - Crime faction"},{"t":3,"n":"FTST - Head texture"},{"t":6,"n":"QNAM - Texture lighting","c":[{"t":5,"n":"Red"},{"t":5,"n":"Green"},{"t":5,"n":"Blue"}]},{"t":6,"n":"NAM9 - Face morph","c":[{"t":5,"n":"Nose Long\/Short"},{"t":5,"n":"Nose Up\/Down"},{"t":5,"n":"Jaw Up\/Down"},{"t":5,"n":"Jaw Narrow\/Wide"},{"t":5,"n":"Jaw Farward\/Back"},{"t":5,"n":"Cheeks Up\/Down"},{"t":5,"n":"Cheeks Farward\/Back"},{"t":5,"n":"Eyes Up\/Down"},{"t":5,"n":"Eyes In\/Out"},{"t":5,"n":"Brows Up\/Down"},{"t":5,"n":"Brows In\/Out"},{"t":5,"n":"Brows Farward\/Back"},{"t":5,"n":"Lips Up\/Down"},{"t":5,"n":"Lips In\/Out"},{"t":5,"n":"Chin Narrow\/Wide"},{"t":5,"n":"Chin Up\/Down"},{"t":5,"n":"Chin Underbite\/Overbite"},{"t":5,"n":"Eyes Farward\/Back"},{"t":5,"n":"Unknown"}]},{"t":6,"n":"NAMA - Face parts","c":[{"t":3,"n":"Nose"},{"t":3,"n":"Unknown"},{"t":3,"n":"Eyes"},{"t":3,"n":"Mouth"}]},{"t":10,"n":"Tint Layers","c":[{"t":6,"n":"Layer","c":[{"t":3,"n":"TINI - Tint Index"}]}]}]}]},"name":"Bash.Actors.Stats","hash":"$5853D7A6","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.All.json ================================================ {"records":"ACTI,ALCH,AMMO,APPA,ARMA,ARMO,ARTO,ASPC,AVIF,BOOK,CELL,CLAS,CONT,DEBR,DIAL,DOOR,EFSH,ENCH,EXPL,FACT,FLOR,FURN,GRAS,HAZD,HDPT,INFO,INGR,IPCT,KEYM,LCTN,LIGH,LSCR,LVLI,LVLN,LVSP,MESG,MGEF,MISC,MSTT,NPC_,PACK,PERK,PHZD,PROJ,QUST,RACE,REFR,REVB,SCEN,SCRL,SHOU,SLGM,SNCT,SNDR,SOPM,SOUN,SPEL,STAT,TREE,WATR,WEAP,WRLD,WTHR,ACHR","description":"Combined setting:\r\nBash.Actors.ACBS,Bash.Actors.AIData,Bash.Actors.AIPackages,Bash.Actors.AIPackagesMerge,Bash.Actors.CombatStyle,Bash.Actors.DeathItem,Bash.Actors.Spells,Bash.Actors.SpellsMerge,Bash.Actors.Stats,Bash.Body-F,Bash.Body-M,Bash.Body-Size-F,Bash.Body-Size-M,Bash.C.Climate,Bash.C.Light,Bash.C.Music,Bash.C.Name,Bash.C.Owner,Bash.C.RecordFlags,Bash.C.Water,Bash.Delev,Bash.Eyes,Bash.Factions,Bash.Graphics,Bash.Hairs,Bash.Invent,Bash.Names,Bash.NPC.Class,Bash.NPC.Race,Bash.NpcFaces,Bash.NpcFacesForceFullImport,Bash.R.AddSpells,Bash.R.ChangeSpells,Bash.R.Description,Bash.R.Head,Bash.R.Skills,Bash.Relations,Bash.Relev,Bash.Scripts,Bash.Sound,Bash.SpellStats,Bash.Stats,Bash.Voice-F,Bash.Voice-M","tree":{"records":[{"t":1,"p":1,"n":"ACTI - Activator","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"PNAM - Marker Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":3,"n":"Unused"}]},{"t":3,"p":1,"n":"SNAM - Sound - Looping"},{"t":3,"p":1,"n":"VNAM - Sound - Activation"},{"t":3,"n":"WNAM - Water Type"},{"t":2,"n":"RNAM - Activate Text Override"},{"t":3,"n":"FNAM - Flags"},{"t":3,"n":"KNAM - Interaction Keyword"}]},{"t":1,"p":1,"n":"ALCH - Ingestible","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":2,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":3,"n":"ETYP - Equipment Type"},{"t":5,"p":1,"n":"DATA - Weight"},{"t":6,"n":"ENIT - Effect Data","c":[{"t":3,"n":"Value"},{"t":3,"n":"Flags"},{"t":3,"n":"Addiction"},{"t":5,"n":"Addiction Chance"},{"t":3,"n":"Sound - Consume"}]},{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":3,"n":"EFID - Base Effect"},{"t":6,"n":"EFIT - ","c":[{"t":5,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"}]}]}]}]},{"t":1,"p":1,"n":"AMMO - Ammunition","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":2,"n":"DESC - Description"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Projectile"},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Damage"},{"t":3,"p":1,"n":"Value"}]},{"t":2,"n":"ONAM - Short Name"}]},{"t":1,"p":1,"n":"APPA - Alchemical Apparatus","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":3,"n":"QUAL - Quality"},{"t":2,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]}]},{"t":1,"p":1,"n":"ARMA - Armor Addon","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"BOD2 - Biped Body Template","c":[{"t":3,"n":"First Person Flags"},{"t":3,"n":"General Flags"},{"n":"Unused"},{"t":3,"n":"Armor Type"}]},{"t":3,"n":"RNAM - Race"},{"t":6,"n":"DNAM - Data","c":[{"t":3,"n":"Male Priority"},{"t":3,"n":"Female Priority"},{"t":3,"n":"Weight slider - Male"},{"t":3,"n":"Weight slider - Female"},{"t":11,"n":"Unknown"},{"t":3,"n":"Detection Sound Value"},{"t":11,"n":"Unknown"},{"t":5,"n":"Weapon Adjust"}]},{"t":6,"s":1,"p":1,"n":"Male world model","c":[{"t":2,"p":1,"n":"MOD2 - Model Filename"}]},{"t":6,"s":1,"p":1,"n":"Female world model","c":[{"t":2,"p":1,"n":"MOD3 - Model Filename"}]},{"t":6,"s":1,"p":1,"n":"Male 1st Person","c":[{"t":2,"p":1,"n":"MOD4 - Model Filename"}]},{"t":6,"s":1,"p":1,"n":"Female 1st Person","c":[{"t":2,"p":1,"n":"MOD5 - Model Filename"}]},{"t":3,"n":"NAM0 - Male Skin Texture"},{"t":3,"n":"NAM1 - Female Skin texture"},{"t":3,"n":"NAM2 - Male Skin Texture Swap List"},{"t":3,"n":"NAM3 - Female Skin Texture Swap List"},{"t":9,"n":"Additional Races","c":[{"t":3,"n":"MODL - Race"}]},{"t":3,"p":1,"n":"SNDD - Footstep Sound"},{"t":3,"n":"ONAM - Art Object"}]},{"t":1,"p":1,"n":"ARMO - Armor","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"EITM - Object Effect"},{"t":3,"n":"EAMT - Enchantment Amount"},{"t":6,"n":"Male world model","c":[{"t":2,"n":"MOD2 - Model Filename"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"}]},{"t":6,"n":"Female world model","c":[{"t":2,"n":"MOD4 - Model Filename"}]},{"t":6,"n":"Icon 2 (female)","c":[{"t":2,"n":"ICO2 - Large Icon filename"}]},{"t":6,"n":"BOD2 - Biped Body Template","c":[{"t":3,"n":"First Person Flags"},{"t":3,"n":"General Flags"},{"n":"Unused"},{"t":3,"n":"Armor Type"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":2,"n":"BMCT - Ragdoll Constraint Template"},{"t":3,"n":"ETYP - Equipment Type"},{"t":3,"n":"BIDS - Bash Impact Data Set"},{"t":3,"n":"BAMT - Alternate Block Material"},{"t":3,"n":"RNAM - Race"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":2,"n":"DESC - Description"},{"t":7,"p":1,"n":"Armature","c":[{"t":3,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":3,"n":"DNAM - Armor Rating"},{"t":3,"n":"TNAM - Template Armor"}]},{"t":1,"p":1,"n":"ARTO - Art Object","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":3,"n":"DNAM - Art Type"}]},{"t":1,"p":1,"n":"ASPC - Acoustic Space","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}],"lt":"BNAM - Environment Type (reverb)","lf":"SNAM - Ambient Sound"},{"t":3,"p":1,"n":"SNAM - Ambient Sound","lt":"OBND - Object Bounds","lf":"RDAT - Use Sound from Region (Interiors Only)"},{"t":3,"p":1,"n":"RDAT - Use Sound from Region (Interiors Only)","lt":"SNAM - Ambient Sound","lf":"BNAM - Environment Type (reverb)"},{"t":3,"p":1,"n":"BNAM - Environment Type (reverb)","lt":"RDAT - Use Sound from Region (Interiors Only)","lf":"OBND - Object Bounds"}]},{"t":1,"p":1,"n":"AVIF - Actor Value Information","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":2,"n":"ANAM - Abbreviation"},{"t":11,"n":"CNAM - Unknown"},{"t":6,"n":"AVSK - Skill","c":[{"t":5,"n":"Skill Use Mult"},{"t":5,"n":"Skill Offset Mult"},{"t":5,"n":"Skill Improve Mult"},{"t":5,"n":"Skill Improve Offset"}]},{"t":8,"n":"Perk Tree","c":[{"t":6,"n":"Node","c":[{"t":3,"n":"PNAM - Perk"}]}]}]},{"t":1,"p":1,"n":"BOOK - Book","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"}]},{"t":2,"n":"DESC - Book Text"},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Type"},{"t":11,"p":1,"n":"Unused"},{"t":12,"p":1,"n":"Teaches"},{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":3,"n":"INAM - Inventory Art"},{"t":2,"n":"CNAM - Description"}]},{"t":1,"p":1,"n":"CELL - Cell","c":[{"t":6,"p":1,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"p":1,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"DATA - Flags","c":[{"t":4,"n":"Is Interior Cell"}]},{"t":6,"n":"XCLC - Grid","c":[{"t":3,"n":"X"},{"t":3,"n":"Y"},{"t":3,"n":"Force Hide Land"}]},{"t":6,"p":1,"n":"XCLL - Lighting","c":[{"t":6,"s":1,"p":1,"n":"Ambient Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":6,"s":1,"p":1,"n":"Directional Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":6,"s":1,"p":1,"n":"Fog Color Near","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":5,"n":"Fog Near"},{"t":5,"n":"Fog Far"},{"t":3,"n":"Directional Rotation XY"},{"t":3,"n":"Directional Rotation Z"},{"t":5,"n":"Directional Fade"},{"t":5,"n":"Fog Clip Distance"},{"t":5,"n":"Fog Power"},{"t":6,"s":1,"p":1,"n":"Ambient Colors","c":[{"t":8,"p":1,"n":"Colors","c":[{"t":6,"p":1,"n":"Color #0 (X+)","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":6,"p":1,"n":"Color #1 (X-)","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":6,"p":1,"n":"Color #2 (Y+)","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":6,"p":1,"n":"Color #3 (Y-)","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":6,"p":1,"n":"Color #4 (Z+)","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":6,"p":1,"n":"Color #5 (Z-)","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]}]},{"t":6,"p":1,"n":"Specular","c":[{"t":6,"p":1,"n":"Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":5,"p":1,"n":"Fresnel Power"}]}]},{"t":6,"s":1,"p":1,"n":"Fog Color Far","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":5,"n":"Fog Max"},{"t":5,"n":"Light Fade Begin"},{"t":5,"n":"Light Fade End"},{"t":3,"n":"Inherits"}]},{"t":11,"n":"TVDT - Unknown"},{"t":11,"n":"MHDT - Max Height Data"},{"t":3,"n":"LTMP - Lighting Template"},{"t":11,"n":"LNAM - Unknown"},{"t":5,"p":1,"n":"XCLW - Water Height"},{"t":2,"n":"XNAM - Water Noise Texture"},{"t":9,"n":"XCLR - Regions","c":[{"t":3,"n":"Region"}]},{"t":3,"n":"XLCN - Location"},{"t":11,"n":"XWCN - Unknown"},{"t":11,"n":"XWCS - Unknown"},{"t":6,"n":"XWCU - Water Velocity","c":[{"t":5,"n":"X Offset"},{"t":5,"n":"Y Offset"},{"t":5,"n":"Z Offset"},{"t":11,"n":"Unknown"},{"t":5,"n":"X Angle"},{"t":5,"n":"Y Angle"},{"t":5,"n":"Z Angle"},{"t":11,"n":"Unknown"}]},{"t":3,"p":1,"n":"XCWT - Water"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"}]},{"t":3,"n":"XILL - Lock List"},{"t":2,"n":"XWEM - Water Environment Map"},{"t":3,"p":1,"n":"XCCM - Sky\/Weather from Region"},{"t":3,"n":"XCAS - Acoustic Space"},{"t":3,"n":"XEZN - Encounter Zone"},{"t":3,"p":1,"n":"XCMO - Music Type"},{"t":3,"n":"XCIM - Image Space"}]},{"t":1,"p":1,"n":"CLAS - Class","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"}]},{"t":6,"n":"DATA - ","c":[{"t":11,"n":"Unknown"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":7,"n":"Skill Weights","c":[{"t":3,"n":"Weight #0 (One Handed)"},{"t":3,"n":"Weight #1 (Two Handed)"},{"t":3,"n":"Weight #2 (Archery)"},{"t":3,"n":"Weight #3 (Block)"},{"t":3,"n":"Weight #4 (Smithing)"},{"t":3,"n":"Weight #5 (Heavy Armor)"},{"t":3,"n":"Weight #6 (Light Armor)"},{"t":3,"n":"Weight #7 (Pickpocket)"},{"t":3,"n":"Weight #8 (Lockpicking)"},{"t":3,"n":"Weight #9 (Sneak)"},{"t":3,"n":"Weight #10 (Alchemy)"},{"t":3,"n":"Weight #11 (Speech)"},{"t":3,"n":"Weight #12 (Alteration)"},{"t":3,"n":"Weight #13 (Conjuration)"},{"t":3,"n":"Weight #14 (Destruction)"},{"t":3,"n":"Weight #15 (Illusion)"},{"t":3,"n":"Weight #16 (Restoration)"},{"t":3,"n":"Weight #17 (Enchanting)"}]},{"t":5,"n":"Bleedout Default"},{"t":3,"n":"Voice Points"},{"t":7,"n":"Attribute Weights","c":[{"t":3,"n":"Weight #0 (Health)"},{"t":3,"n":"Weight #1 (Magicka)"},{"t":3,"n":"Weight #2 (Stamina)"},{"t":3,"n":"Weight #3 (Unknown)"}]}]}]},{"t":1,"p":1,"n":"CONT - Container","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":3,"n":"COCT - Count"},{"t":10,"p":1,"n":"Items","d":1,"c":[{"t":6,"p":1,"n":"Item","c":[{"t":6,"p":1,"n":"CNTO - Item","c":[{"t":3,"p":1,"n":"Item"},{"t":3,"p":1,"n":"Count"}]}]}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Flags"},{"t":5,"n":"Weight"}]},{"t":3,"n":"SNAM - Sound - Open"},{"t":3,"n":"QNAM - Sound - Close"}]},{"t":1,"p":1,"n":"DEBR - Debris","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":8,"p":1,"n":"Models","c":[{"t":6,"p":1,"n":"Model","c":[{"t":6,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Percentage"},{"t":2,"p":1,"n":"Model Filename"},{"t":3,"p":1,"n":"Flags"}]}]}]}]},{"t":1,"p":1,"n":"DIAL - Dialog Topic","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":5,"n":"PNAM - Priority"},{"t":3,"n":"BNAM - Branch"},{"t":3,"n":"QNAM - Quest"},{"t":6,"n":"DATA - Data","c":[{"t":3,"n":"Topic Flags"},{"t":3,"n":"Category"},{"t":3,"n":"Subtype"}]},{"t":2,"n":"SNAM - Subtype Name"},{"t":3,"n":"TIFC - Info Count"}]},{"t":1,"p":1,"n":"DOOR - Door","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"SNAM - Sound - Open"},{"t":3,"n":"ANAM - Sound - Close"},{"t":3,"n":"BNAM - Sound - Loop"},{"t":3,"n":"FNAM - Flags"}]},{"t":1,"p":1,"n":"EFSH - Effect Shader","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"ICON - Fill Texture","lt":"ICO2 - Particle Shader Texture","lf":"DATA - "},{"t":2,"p":1,"n":"ICO2 - Particle Shader Texture","lt":"NAM7 - Holes Texture","lf":"ICON - Fill Texture"},{"t":2,"p":1,"n":"NAM7 - Holes Texture","lt":"NAM8 - Membrane Palette Texture","lf":"ICO2 - Particle Shader Texture"},{"t":2,"p":1,"n":"NAM8 - Membrane Palette Texture","lt":"NAM9 - Particle Palette Texture","lf":"NAM7 - Holes Texture"},{"t":2,"p":1,"n":"NAM9 - Particle Palette Texture","lt":"DATA - ","lf":"NAM8 - Membrane Palette Texture"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":11,"p":1,"n":"Unknown"},{"t":3,"p":1,"n":"Membrane Shader - Source Blend Mode"},{"t":3,"p":1,"n":"Membrane Shader - Blend Operation"},{"t":3,"p":1,"n":"Membrane Shader - Z Test Function"},{"t":6,"p":1,"n":"Fill\/Texture Effect - Color Key 1","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Fade In Time"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Full Alpha Time"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Fade Out Time"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Presistent Alpha Ratio"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Pulse Amplitude"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Pulse Frequency"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Animation Speed (U)"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Animation Speed (V)"},{"t":5,"p":1,"n":"Edge Effect - Fall Off"},{"t":6,"p":1,"n":"Edge Effect - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":5,"p":1,"n":"Edge Effect - Alpha Fade In Time"},{"t":5,"p":1,"n":"Edge Effect - Full Alpha Time"},{"t":5,"p":1,"n":"Edge Effect - Alpha Fade Out Time"},{"t":5,"p":1,"n":"Edge Effect - Persistent Alpha Ratio"},{"t":5,"p":1,"n":"Edge Effect - Alpha Pulse Amplitude"},{"t":5,"p":1,"n":"Edge Effect - Alpha Pulse Frequency"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Full Alpha Ratio"},{"t":5,"p":1,"n":"Edge Effect - Full Alpha Ratio"},{"t":3,"p":1,"n":"Membrane Shader - Dest Blend Mode"},{"t":3,"p":1,"n":"Particle Shader - Source Blend Mode"},{"t":3,"p":1,"n":"Particle Shader - Blend Operation"},{"t":3,"p":1,"n":"Particle Shader - Z Test Function"},{"t":3,"p":1,"n":"Particle Shader - Dest Blend Mode"},{"t":5,"p":1,"n":"Particle Shader - Particle Birth Ramp Up Time"},{"t":5,"p":1,"n":"Particle Shader - Full Particle Birth Time"},{"t":5,"p":1,"n":"Particle Shader - Particle Birth Ramp Down Time"},{"t":5,"p":1,"n":"Particle Shader - Full Particle Birth Ratio"},{"t":5,"p":1,"n":"Particle Shader - Persistant Particle Count"},{"t":5,"p":1,"n":"Particle Shader - Particle Lifetime"},{"t":5,"p":1,"n":"Particle Shader - Particle Lifetime +\/-"},{"t":5,"p":1,"n":"Particle Shader - Initial Speed Along Normal"},{"t":5,"p":1,"n":"Particle Shader - Acceleration Along Normal"},{"t":5,"p":1,"n":"Particle Shader - Initial Velocity #1"},{"t":5,"p":1,"n":"Particle Shader - Initial Velocity #2"},{"t":5,"p":1,"n":"Particle Shader - Initial Velocity #3"},{"t":5,"p":1,"n":"Particle Shader - Acceleration #1"},{"t":5,"p":1,"n":"Particle Shader - Acceleration #2"},{"t":5,"p":1,"n":"Particle Shader - Acceleration #3"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 1"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 2"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 1 Time"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 2 Time"},{"t":6,"p":1,"n":"Color Key 1 - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":6,"p":1,"n":"Color Key 2 - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":6,"p":1,"n":"Color Key 3 - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":5,"p":1,"n":"Color Key 1 - Color Alpha"},{"t":5,"p":1,"n":"Color Key 2 - Color Alpha"},{"t":5,"p":1,"n":"Color Key 3 - Color Alpha"},{"t":5,"p":1,"n":"Color Key 1 - Color Key Time"},{"t":5,"p":1,"n":"Color Key 2 - Color Key Time"},{"t":5,"p":1,"n":"Color Key 3 - Color Key Time"},{"t":5,"p":1,"n":"Particle Shader - Initial Speed Along Normal +\/-"},{"t":5,"p":1,"n":"Particle Shader - Initial Rotation (deg)"},{"t":5,"p":1,"n":"Particle Shader - Initial Rotation (deg) +\/-"},{"t":5,"p":1,"n":"Particle Shader - Rotation Speed (deg\/sec)"},{"t":5,"p":1,"n":"Particle Shader - Rotation Speed (deg\/sec) +\/-"},{"t":3,"p":1,"n":"Addon Models"},{"t":5,"p":1,"n":"Holes - Start Time"},{"t":5,"p":1,"n":"Holes - End Time"},{"t":5,"p":1,"n":"Holes - Start Val"},{"t":5,"p":1,"n":"Holes - End Val"},{"t":5,"p":1,"n":"Edge Width (alpha units)"},{"t":6,"p":1,"n":"Edge Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":5,"p":1,"n":"Explosion Wind Speed"},{"t":3,"p":1,"n":"Texture Count U"},{"t":3,"p":1,"n":"Texture Count V"},{"t":5,"p":1,"n":"Addon Models - Fade In Time"},{"t":5,"p":1,"n":"Addon Models - Fade Out Time"},{"t":5,"p":1,"n":"Addon Models - Scale Start"},{"t":5,"p":1,"n":"Addon Models - Scale End"},{"t":5,"p":1,"n":"Addon Models - Scale In Time"},{"t":5,"p":1,"n":"Addon Models - Scale Out Time"},{"t":3,"p":1,"n":"Ambient Sound"},{"t":6,"p":1,"n":"Fill\/Texture Effect - Color Key 2","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":6,"p":1,"n":"Fill\/Texture Effect - Color Key 3","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":6,"p":1,"n":"Fill\/Texture Effect - Color Key Scale\/Time","c":[{"t":5,"p":1,"n":"Color Key 1 - Scale"},{"t":5,"p":1,"n":"Color Key 2 - Scale"},{"t":5,"p":1,"n":"Color Key 3 - Scale"},{"t":5,"p":1,"n":"Color Key 1 - Time"},{"t":5,"p":1,"n":"Color Key 2 - Time"},{"t":5,"p":1,"n":"Color Key 3 - Time"}]},{"t":5,"p":1,"n":"Color Scale"},{"t":5,"p":1,"n":"Birth Position Offset"},{"t":5,"p":1,"n":"Birth Position Offset Range +\/-"},{"t":6,"p":1,"n":"Particle Shader Animated","c":[{"t":3,"p":1,"n":"Start Frame"},{"t":3,"p":1,"n":"Start Frame Variation"},{"t":3,"p":1,"n":"End Frame"},{"t":3,"p":1,"n":"Loop Start Frame"},{"t":3,"p":1,"n":"Loop Start Variation"},{"t":3,"p":1,"n":"Frame Count"},{"t":3,"p":1,"n":"Frame Count Variation"}]},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Scale (U)"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Scale (V)"},{"t":3,"p":1,"n":"Scene Graph Emit Depth Limit (unused)"}],"lt":"ICON - Fill Texture","lf":"NAM9 - Particle Palette Texture"}]},{"t":1,"p":1,"n":"ENCH - Object Effect","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"ENIT - Effect Data","c":[{"t":3,"n":"Enchantment Cost"},{"t":3,"n":"Flags"},{"t":3,"n":"Cast Type"},{"t":3,"n":"Enchantment Amount"},{"t":3,"n":"Target Type"},{"t":3,"n":"Enchant Type"},{"t":5,"n":"Charge Time"},{"t":3,"n":"Base Enchantment"},{"t":3,"n":"Worn Restrictions"}]},{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":3,"n":"EFID - Base Effect"},{"t":6,"n":"EFIT - ","c":[{"t":5,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"}]}]}]}]},{"t":1,"p":1,"n":"EXPL - Explosion","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":3,"n":"EITM - Object Effect"},{"t":3,"n":"MNAM - Image Space Modifier"},{"t":6,"p":1,"n":"DATA - Data","c":[{"t":3,"n":"Light"},{"t":3,"p":1,"n":"Sound 1","lt":"Sound 2","lf":"Sound Level"},{"t":3,"p":1,"n":"Sound 2","lt":"Sound Level","lf":"Sound 1"},{"t":3,"n":"Impact Data Set"},{"t":3,"n":"Placed Object"},{"t":3,"n":"Spawn Projectile"},{"t":5,"n":"Force"},{"t":5,"n":"Damage"},{"t":5,"n":"Radius"},{"t":5,"n":"IS Radius"},{"t":5,"n":"Vertical Offset Mult"},{"t":3,"n":"Flags"},{"t":3,"p":1,"n":"Sound Level","lt":"Sound 1","lf":"Sound 2"}]}]},{"t":1,"p":1,"n":"FACT - Faction","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":10,"p":1,"n":"Relations","d":1,"c":[{"t":6,"p":1,"n":"XNAM - Relation","c":[{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Modifier"},{"t":3,"p":1,"n":"Group Combat Reaction"}]}]},{"t":6,"n":"DATA - Flags","c":[{"t":3,"n":"Flags"}]},{"t":3,"n":"JAIL - Exterior Jail Marker"},{"t":3,"n":"WAIT - Follower Wait Marker"},{"t":3,"n":"STOL - Stolen Goods Container"},{"t":3,"n":"PLCN - Player Inventory Container"},{"t":3,"n":"CRGR - Shared Crime Faction List"},{"t":3,"n":"JOUT - Jail Outfit"},{"t":6,"n":"CRVA - Crime Values","c":[{"t":3,"n":"Arrest"},{"t":3,"n":"Attack On Sight"},{"t":3,"n":"Murder"},{"t":3,"n":"Assault"},{"t":3,"n":"Trespass"},{"t":3,"n":"Pickpocket"},{"t":3,"n":"Unknown"},{"t":5,"n":"Steal Multiplier"},{"t":3,"n":"Escape"},{"t":3,"n":"Werewolf"}]},{"t":10,"n":"Ranks","c":[{"t":6,"n":"Rank","c":[{"t":3,"n":"RNAM - Rank#"}]}]},{"t":3,"n":"VEND - Vendor Buy\/Sell List"},{"t":3,"n":"VENC - Merchant Container"},{"t":6,"n":"VENV - Vendor Values","c":[{"t":3,"n":"Start Hour"},{"t":3,"n":"End Hour"},{"t":3,"n":"Radius"},{"t":11,"n":"Unknown 1"},{"t":3,"n":"Only Buys Stolen Items"},{"t":3,"n":"Not\/Sell Buy"},{"t":11,"n":"Unknown 2"}]},{"t":6,"n":"PLVD - Location","c":[{"t":3,"n":"Type"},{"t":12,"n":"Location Value"},{"t":3,"n":"Radius"}]},{"t":3,"n":"CITC - Condition Count"},{"t":8,"n":"Conditions","c":[{"t":6,"n":"Condition","c":[{"t":6,"n":"CTDA - ","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":12,"n":"Comparison Value"},{"t":3,"n":"Function"},{"t":11,"n":"Unused"},{"t":12,"n":"Parameter #1"},{"t":12,"n":"Parameter #2"},{"t":3,"n":"Run On"},{"t":12,"n":"Reference"},{"t":3,"n":"Parameter #3"}]}]}]}]},{"t":1,"p":1,"n":"FLOR - Flora","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":11,"n":"PNAM - Unknown"},{"t":2,"n":"RNAM - Activate Text Override"},{"t":11,"n":"FNAM - Unknown"},{"t":3,"n":"PFIG - Ingredient"},{"t":3,"n":"SNAM - Sound"},{"t":6,"n":"PFPC - Seasonal ingredient production","c":[{"t":3,"n":"Spring"},{"t":3,"n":"Summer "},{"t":3,"n":"Fall"},{"t":3,"n":"Winter"}]}]},{"t":1,"p":1,"n":"FURN - Furniture","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":11,"n":"PNAM - Unknown"},{"t":3,"n":"FNAM - Flags"},{"t":3,"n":"KNAM - Interaction Keyword"},{"t":3,"n":"MNAM - Active Markers \/ Flags"},{"t":6,"n":"WBDT - Workbench Data","c":[{"t":3,"n":"Bench Type"},{"t":3,"n":"Uses Skill"}]},{"t":3,"n":"NAM1 - Associated Spell"},{"t":8,"n":"Markers","c":[{"t":6,"n":"Marker","c":[{"t":3,"n":"ENAM - Marker Index"}]}]},{"t":8,"n":"Marker Entry Points","c":[{"t":6,"n":"FNPR - Marker","c":[{"t":3,"n":"Type"},{"t":3,"n":"Entry Points"}]}]},{"t":2,"n":"XMRK - Model Filename"}]},{"t":1,"p":1,"n":"GRAS - Grass","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Density"},{"t":3,"n":"Min Slope"},{"t":3,"n":"Max Slope"},{"t":11,"n":"Unknown"},{"t":3,"n":"Units From Water"},{"t":11,"n":"Unknown"},{"t":3,"n":"Units From Water Type"},{"t":5,"n":"Position Range"},{"t":5,"n":"Height Range"},{"t":5,"n":"Color Range"},{"t":5,"n":"Wave Period"},{"t":3,"n":"Flags"},{"t":11,"n":"Unknown"}]}]},{"t":1,"p":1,"n":"HAZD - Hazard","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":3,"n":"MNAM - Image Space Modifier"},{"t":6,"n":"DATA - Data","c":[{"t":3,"n":"Limit"},{"t":5,"n":"Radius"},{"t":5,"n":"Lifetime"},{"t":5,"n":"Image Space Radius"},{"t":5,"n":"Target Interval"},{"t":3,"n":"Flags"},{"t":3,"n":"Spell"},{"t":3,"n":"Light"},{"t":3,"n":"Impact Data Set"},{"t":3,"n":"Sound"}]}]},{"t":1,"p":1,"n":"HDPT - Head Part","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":3,"n":"DATA - Flags"},{"t":3,"n":"PNAM - Type"},{"t":9,"n":"Extra Parts","c":[{"t":3,"n":"HNAM - Part"}]},{"t":8,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"NAM0 - Part Type"},{"t":2,"n":"NAM1 - Filename"}]}]},{"t":3,"n":"TNAM - Texture Set"},{"t":3,"n":"CNAM - Color"},{"t":3,"n":"RNAM - Valid Races"}]},{"t":1,"p":1,"n":"INFO - Dialog response","c":[{"t":3,"n":"Topic"},{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":6,"p":1,"n":"Info VMAD","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]},{"t":6,"p":1,"n":"Script Fragments Info","c":[{"t":3,"p":1,"n":"Unknown"},{"t":3,"p":1,"n":"Info Fragments Flags"},{"t":2,"p":1,"n":"fileName"},{"t":7,"p":1,"n":"Info Fragments","c":[{"t":6,"p":1,"n":"Info Fragment #0","c":[{"t":3,"p":1,"n":"Unknown"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]}]}]}]}]},{"t":11,"n":"DATA - Unknown"},{"t":6,"n":"ENAM - Response flags","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Reset Hours"}]},{"t":3,"n":"TPIC - Topic"},{"t":3,"n":"PNAM - Previous INFO"},{"t":3,"n":"CNAM - Favor Level"},{"t":7,"n":"Link To","c":[{"t":3,"n":"TCLT - Response"}]},{"t":3,"n":"DNAM - Response Data"},{"t":8,"n":"Responses","c":[{"t":6,"n":"Response","c":[{"t":6,"n":"TRDT - Response Data","c":[{"t":3,"n":"Emotion Type"},{"t":3,"n":"Emotion Value"},{"t":11,"n":"Unused"},{"t":3,"n":"Response number"},{"t":11,"n":"Unused"},{"t":3,"n":"Sound"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]}]}]},{"t":8,"n":"Conditions","c":[{"t":6,"n":"Condition","c":[{"t":6,"n":"CTDA - ","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":12,"n":"Comparison Value"},{"t":3,"n":"Function"},{"t":11,"n":"Unused"},{"t":12,"n":"Parameter #1"},{"t":12,"n":"Parameter #2"},{"t":3,"n":"Run On"},{"t":12,"n":"Reference"},{"t":3,"n":"Parameter #3"}]}]}]},{"t":8,"n":"Unknown","c":[{"t":6,"n":"Unknown","c":[{"t":11,"n":"SCHR - Unknown"}]}]},{"t":2,"n":"RNAM - Prompt"},{"t":3,"n":"ANAM - Speaker"},{"t":3,"n":"TWAT - Walk Away Topic"},{"t":3,"n":"ONAM - Audio Output Override"}]},{"t":1,"p":1,"n":"INGR - Ingredient","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"ETYP - Equipment Type"},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":6,"n":"ENIT - Effect Data","c":[{"t":3,"n":"Ingredient Value"},{"t":3,"n":"Flags"}]},{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":3,"n":"EFID - Base Effect"},{"t":6,"n":"EFIT - ","c":[{"t":5,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"}]}]}]}]},{"t":1,"p":1,"n":"IPCT - Impact","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"DATA - ","c":[{"t":5,"n":"Effect - Duration"},{"t":3,"n":"Effect - Orientation"},{"t":5,"n":"Angle Threshold"},{"t":5,"n":"Placement Radius"},{"t":3,"n":"Sound Level"},{"t":3,"n":"Flags"},{"t":3,"n":"Impact Result"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"DODT - Decal Data","c":[{"t":5,"n":"Min Width"},{"t":5,"n":"Max Width"},{"t":5,"n":"Min Height"},{"t":5,"n":"Max Height"},{"t":5,"n":"Depth"},{"t":5,"n":"Shininess"},{"t":6,"n":"Parallax","c":[{"t":5,"n":"Scale"},{"t":3,"n":"Passes"}]},{"t":3,"n":"Flags"},{"t":11,"n":"Unknown"},{"t":6,"n":"Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"DNAM - Texture Set"},{"t":3,"n":"ENAM - Secondary Texture Set"},{"t":3,"p":1,"n":"SNAM - Sound 1","lt":"NAM1 - Sound 2","lf":"NAM1 - Sound 2"},{"t":3,"p":1,"n":"NAM1 - Sound 2","lt":"SNAM - Sound 1","lf":"SNAM - Sound 1"},{"t":3,"n":"NAM2 - Hazard"}]},{"t":1,"p":1,"n":"KEYM - Key","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]}]},{"t":1,"p":1,"n":"LCTN - Location","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":8,"n":"ACPR - Actor Cell Persistent Reference","c":[{"t":6,"n":" #0","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Location"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":8,"n":"LCPR - Location Cell Persistent Reference","c":[{"t":6,"n":" #0","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Location"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":7,"n":"RCPR - Reference Cell Persistent Reference","c":[{"t":3,"n":"Ref #0"}]},{"t":8,"n":"ACUN - Actor Cell Unique","c":[{"t":6,"n":" #0","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Ref"},{"t":3,"n":"Location"}]}]},{"t":8,"n":"LCUN - Location Cell Unique","c":[{"t":6,"n":" #0","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Ref"},{"t":3,"n":"Location"}]}]},{"t":7,"n":"RCUN - Reference Cell Unique","c":[{"t":3,"n":"Actor #0"}]},{"t":8,"n":"ACSR - Actor Cell Static Reference","c":[{"t":6,"n":" #0","c":[{"t":3,"n":"Loc Ref Type"},{"t":3,"n":"Marker"},{"t":3,"n":"Location"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":8,"n":"LCSR - Location Cell Static Reference","c":[{"t":6,"n":" #0","c":[{"t":3,"n":"Loc Ref Type"},{"t":3,"n":"Marker"},{"t":3,"n":"Location"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":7,"n":"RCSR - Reference Cell Static Reference","c":[{"t":3,"n":"Ref #0"}]},{"t":8,"n":"Actor Cell Encounter Cell","c":[{"t":6,"n":"ACEC - Unknown","c":[{"t":3,"n":"Location"},{"t":8,"n":"Coordinates","c":[{"t":6,"n":" #0","c":[{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]}]}]},{"t":8,"n":"Location Cell Encounter Cell","c":[{"t":6,"n":"LCEC - Unknown","c":[{"t":3,"n":"Location"},{"t":8,"n":"Coordinates","c":[{"t":6,"n":" #0","c":[{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]}]}]},{"t":8,"n":"Reference Cell Encounter Cell","c":[{"t":6,"n":"RCEC - Unknown","c":[{"t":3,"n":"Location"},{"t":8,"n":"Coordinates","c":[{"t":6,"n":" #0","c":[{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]}]}]},{"t":7,"n":"ACID - Actor Cell Marker Reference","c":[{"t":3,"n":"Ref #0"}]},{"t":7,"n":"LCID - Location Cell Marker Reference","c":[{"t":3,"n":"Ref #0"}]},{"t":8,"n":"ACEP - Actor Cell Enable Point","c":[{"t":6,"n":" #0","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Ref"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":8,"n":"LCEP - Location Cell Enable Point","c":[{"t":6,"n":" #0","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Ref"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":3,"n":"PNAM - Parent Location"},{"t":3,"n":"NAM1 - Music"},{"t":3,"n":"FNAM - Unreported Crime Faction"},{"t":3,"n":"MNAM - World Location Marker Ref"},{"t":5,"n":"RNAM - World Location Radius"},{"t":3,"n":"NAM0 - Horse Marker Ref"},{"t":6,"n":"CNAM - Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":1,"p":1,"n":"LIGH - Light","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"}]},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Time"},{"t":3,"n":"Radius"},{"t":6,"n":"Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":3,"n":"Unknown"}]},{"t":3,"n":"Flags"},{"t":5,"n":"Falloff Exponent"},{"t":5,"n":"FOV"},{"t":5,"n":"Near Clip"},{"t":6,"n":"Flicker Effect","c":[{"t":5,"n":"Period"},{"t":5,"n":"Intensity Amplitude"},{"t":5,"n":"Movement Amplitude"}]},{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]},{"t":5,"n":"FNAM - Fade value"},{"t":3,"n":"SNAM - Sound"}]},{"t":1,"p":1,"n":"LSCR - Load Screen","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"}]},{"t":2,"n":"DESC - Description"},{"t":8,"n":"Conditions","c":[{"t":6,"n":"Condition","c":[{"t":6,"n":"CTDA - ","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":12,"n":"Comparison Value"},{"t":3,"n":"Function"},{"t":11,"n":"Unused"},{"t":12,"n":"Parameter #1"},{"t":12,"n":"Parameter #2"},{"t":3,"n":"Run On"},{"t":12,"n":"Reference"},{"t":3,"n":"Parameter #3"}]}]}]},{"t":3,"n":"NNAM - Loading Screen NIF"},{"t":5,"n":"SNAM - Initial Scale"},{"t":6,"n":"RNAM - Initial Rotation","c":[{"t":3,"n":"X"},{"t":3,"n":"Y"},{"t":3,"n":"Z"}]},{"t":6,"n":"ONAM - Rotation Offset Constraints","c":[{"t":3,"n":"Min"},{"t":3,"n":"Max"}]},{"t":6,"n":"XNAM - Initial Translation Offset","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]},{"t":2,"n":"MOD2 - Camera Path"}]},{"t":1,"p":1,"n":"LVLI - Leveled Item","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":3,"n":"LVLD - Chance None"},{"t":3,"n":"LVLF - Flags"},{"t":3,"n":"LVLG - Global"},{"t":3,"n":"LLCT - Count"},{"t":10,"p":1,"o":1,"n":"Leveled List Entries","d":1,"c":[{"t":6,"p":1,"n":"Leveled List Entry","c":[{"t":6,"p":1,"n":"LVLO - Base Data","c":[{"t":3,"p":1,"n":"Level"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Reference"},{"t":3,"n":"Count"},{"t":11,"n":"Unknown"}]}]}]}]},{"t":1,"p":1,"n":"LVLN - Leveled NPC","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":3,"n":"LVLD - Chance None"},{"t":3,"n":"LVLF - Flags"},{"t":3,"n":"LVLG - Global"},{"t":3,"n":"LLCT - Count"},{"t":10,"p":1,"o":1,"n":"Leveled List Entries","d":1,"c":[{"t":6,"p":1,"n":"Leveled List Entry","c":[{"t":6,"p":1,"n":"LVLO - Base Data","c":[{"t":3,"p":1,"n":"Level"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Reference"},{"t":3,"n":"Count"},{"t":11,"n":"Unknown"}]}]}]},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]}]},{"t":1,"p":1,"n":"LVSP - Leveled Spell","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":3,"n":"LVLD - Chance None"},{"t":3,"n":"LVLF - Flags"},{"t":3,"n":"LLCT - Count"},{"t":10,"p":1,"o":1,"n":"Leveled List Entries","d":1,"c":[{"t":6,"p":1,"n":"Leveled List Entry","c":[{"t":6,"p":1,"n":"LVLO - Base Data","c":[{"t":3,"p":1,"n":"Level"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Reference"},{"t":3,"n":"Count"},{"t":11,"n":"Unknown"}]}]}]}]},{"t":1,"p":1,"n":"MESG - Message","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"DESC - Description"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"INAM - Icon (unused)"},{"t":3,"n":"QNAM - Owner Quest"},{"t":3,"n":"DNAM - Flags","c":[{"t":4,"n":"Message Box"}]},{"t":3,"n":"TNAM - Display Time"},{"t":8,"n":"Menu Buttons","c":[{"t":6,"n":"Menu Button","c":[{"t":2,"n":"ITXT - Button Text"}]}]}]},{"t":1,"p":1,"n":"MGEF - Magic Effect","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"MDOB - Menu Display Object"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"Magic Effect Data","c":[{"t":6,"n":"DATA - Data","c":[{"t":3,"n":"Flags"},{"t":5,"n":"Base Cost"},{"t":12,"n":"Assoc. Item"},{"t":3,"n":"Magic Skill"},{"t":3,"n":"Resist Value"},{"t":3,"n":"Counter Effect count"},{"t":11,"n":"Unused"},{"t":3,"n":"Casting Light"},{"t":5,"n":"Taper Weight"},{"t":3,"n":"Hit Shader"},{"t":3,"n":"Enchant Shader"},{"t":3,"n":"Minimum Skill Level"},{"t":6,"n":"Spellmaking","c":[{"t":3,"n":"Area"},{"t":5,"n":"Casting Time"}]},{"t":5,"n":"Taper Curve"},{"t":5,"n":"Taper Duration"},{"t":5,"n":"Second AV Weight"},{"t":3,"n":"Archtype"},{"t":3,"n":"Actor Value"},{"t":3,"n":"Projectile"},{"t":3,"n":"Explosion"},{"t":3,"n":"Casting Type"},{"t":3,"n":"Delivery"},{"t":3,"n":"Second Actor Value"},{"t":3,"n":"Casting Art"},{"t":3,"n":"Hit Effect Art"},{"t":3,"n":"Impact Data"},{"t":5,"n":"Skill Usage Multiplier"},{"t":6,"n":"Dual Casting","c":[{"t":3,"n":"Art"},{"t":5,"n":"Scale"}]},{"t":3,"n":"Enchant Art"},{"t":11,"n":"Unknown"},{"t":11,"n":"Unknown"},{"t":3,"n":"Equip Ability"},{"t":3,"n":"Image Space Modifier"},{"t":3,"n":"Perk to Apply"},{"t":3,"n":"Casting Sound Level"},{"t":6,"n":"Script Effect AI","c":[{"t":5,"n":"Score"},{"t":5,"n":"Delay Time"}]}]}]},{"t":9,"n":"Counter Effects","c":[{"t":3,"n":"ESCE - Effect"}]},{"t":8,"s":1,"p":1,"n":"SNDD - Sounds","c":[{"t":6,"p":1,"n":" #0","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Sound"}]}]},{"t":2,"n":"DNAM - Magic Item Description"},{"t":8,"n":"Conditions","c":[{"t":6,"n":"Condition","c":[{"t":6,"n":"CTDA - ","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":12,"n":"Comparison Value"},{"t":3,"n":"Function"},{"t":11,"n":"Unused"},{"t":12,"n":"Parameter #1"},{"t":12,"n":"Parameter #2"},{"t":3,"n":"Run On"},{"t":12,"n":"Reference"},{"t":3,"n":"Parameter #3"}]}]}]}]},{"t":1,"p":1,"n":"MISC - Misc. Item","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]}]},{"t":1,"p":1,"n":"MSTT - Moveable Static","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"DATA - Flags"},{"t":3,"p":1,"n":"SNAM - Looping Sound"}]},{"t":1,"p":1,"n":"NPC_ - Non-Player Character (Actor)","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"ACBS - Configuration","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Magicka Offset"},{"t":3,"p":1,"n":"Stamina Offset"},{"t":12,"p":1,"n":"Level"},{"t":3,"p":1,"n":"Calc min level"},{"t":3,"p":1,"n":"Calc max level"},{"t":3,"p":1,"n":"Speed Multiplier"},{"t":3,"p":1,"n":"Disposition Base (unused)"},{"t":3,"p":1,"n":"Template Flags"},{"t":3,"p":1,"n":"Health Offset"},{"t":3,"p":1,"n":"Bleedout Override"}]},{"t":10,"s":1,"p":1,"n":"Factions","d":1,"c":[{"t":6,"p":1,"n":"SNAM - Faction","c":[{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Rank"},{"t":11,"p":1,"n":"Unused"}]}]},{"t":3,"p":1,"n":"INAM - Death item"},{"t":3,"n":"VTCK - Voice"},{"t":3,"n":"TPLT - Template"},{"t":3,"p":1,"n":"RNAM - Race"},{"t":3,"n":"SPCT - Count"},{"t":9,"s":1,"p":1,"n":"Actor Effects","d":1,"c":[{"t":3,"p":1,"n":"SPLO - Actor Effect"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"WNAM - Worn Armor"},{"t":3,"n":"ANAM - Far away model"},{"t":3,"n":"ATKR - Attack Race"},{"t":10,"n":"Attacks","c":[{"t":6,"n":"Attack","c":[{"t":6,"n":"ATKD - Attack Data","c":[{"t":5,"n":"Damage Mult"},{"t":5,"n":"Attack Chance"},{"t":3,"n":"Attack Spell"},{"t":3,"n":"Attack Flags"},{"t":5,"n":"Attack Angle"},{"t":5,"n":"Strike Angle"},{"t":5,"n":"Stagger"},{"t":3,"n":"Attack Type"},{"t":5,"n":"Knockdown"},{"t":5,"n":"Recovery Time"},{"t":5,"n":"Stamina Mult"}]}]}]},{"t":3,"n":"SPOR - Spectator override package list"},{"t":3,"n":"OCOR - Observe dead body override package list"},{"t":3,"n":"GWOR - Guard warn override package list"},{"t":3,"n":"ECOR - Combat override package list"},{"t":3,"n":"PRKZ - Perk Count"},{"t":10,"n":"Perks","c":[{"t":6,"n":"PRKR - Perk","c":[{"t":3,"n":"Perk"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"COCT - Count"},{"t":10,"p":1,"n":"Items","d":1,"c":[{"t":6,"p":1,"n":"Item","c":[{"t":6,"p":1,"n":"CNTO - Item","c":[{"t":3,"p":1,"n":"Item"},{"t":3,"p":1,"n":"Count"}]}]}]},{"t":6,"s":1,"p":1,"n":"AIDT - AI Data","c":[{"t":3,"p":1,"n":"Aggression"},{"t":3,"p":1,"n":"Confidence"},{"t":3,"p":1,"n":"Energy Level"},{"t":3,"p":1,"n":"Responsibility"},{"t":3,"p":1,"n":"Mood"},{"t":3,"p":1,"n":"Assistance"},{"t":6,"p":1,"n":"Aggro","c":[{"t":3,"p":1,"n":"Aggro Radius Behavior"},{"t":3,"p":1,"n":"Unknown"},{"t":3,"p":1,"n":"Warn"},{"t":3,"p":1,"n":"Warn\/Attack"},{"t":3,"p":1,"n":"Attack"}]}]},{"t":7,"s":1,"p":1,"n":"Packages","d":1,"c":[{"t":3,"p":1,"n":"PKID - Package"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":3,"p":1,"n":"CNAM - Class"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"n":"SHRT - Short Name"},{"t":11,"n":"DATA - Marker"},{"t":6,"s":1,"p":1,"n":"DNAM - Player Skills","c":[{"t":7,"p":1,"n":"Skill Values","c":[{"t":3,"p":1,"n":"Skill #0 (OneHanded)"},{"t":3,"p":1,"n":"Skill #1 (TwoHanded)"},{"t":3,"p":1,"n":"Skill #2 (Marksman)"},{"t":3,"p":1,"n":"Skill #3 (Block)"},{"t":3,"p":1,"n":"Skill #4 (Smithing)"},{"t":3,"p":1,"n":"Skill #5 (HeavyArmor)"},{"t":3,"p":1,"n":"Skill #6 (LightArmor)"},{"t":3,"p":1,"n":"Skill #7 (Pickpocket)"},{"t":3,"p":1,"n":"Skill #8 (Lockpicking)"},{"t":3,"p":1,"n":"Skill #9 (Sneak)"},{"t":3,"p":1,"n":"Skill #10 (Alchemy)"},{"t":3,"p":1,"n":"Skill #11 (Speechcraft)"},{"t":3,"p":1,"n":"Skill #12 (Alteration)"},{"t":3,"p":1,"n":"Skill #13 (Conjuration)"},{"t":3,"p":1,"n":"Skill #14 (Destruction)"},{"t":3,"p":1,"n":"Skill #15 (Illusion)"},{"t":3,"p":1,"n":"Skill #16 (Restoration)"},{"t":3,"p":1,"n":"Skill #17 (Enchanting)"}]},{"t":7,"p":1,"n":"Skill Offsets","c":[{"t":3,"p":1,"n":"Skill #0 (OneHanded)"},{"t":3,"p":1,"n":"Skill #1 (TwoHanded)"},{"t":3,"p":1,"n":"Skill #2 (Marksman)"},{"t":3,"p":1,"n":"Skill #3 (Block)"},{"t":3,"p":1,"n":"Skill #4 (Smithing)"},{"t":3,"p":1,"n":"Skill #5 (HeavyArmor)"},{"t":3,"p":1,"n":"Skill #6 (LightArmor)"},{"t":3,"p":1,"n":"Skill #7 (Pickpocket)"},{"t":3,"p":1,"n":"Skill #8 (Lockpicking)"},{"t":3,"p":1,"n":"Skill #9 (Sneak)"},{"t":3,"p":1,"n":"Skill #10 (Alchemy)"},{"t":3,"p":1,"n":"Skill #11 (Speechcraft)"},{"t":3,"p":1,"n":"Skill #12 (Alteration)"},{"t":3,"p":1,"n":"Skill #13 (Conjuration)"},{"t":3,"p":1,"n":"Skill #14 (Destruction)"},{"t":3,"p":1,"n":"Skill #15 (Illusion)"},{"t":3,"p":1,"n":"Skill #16 (Restoration)"},{"t":3,"p":1,"n":"Skill #17 (Enchanting)"}]},{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Magicka"},{"t":3,"p":1,"n":"Stamina"},{"t":11,"p":1,"n":"Unused"},{"t":5,"p":1,"n":"Far away model distance"},{"t":3,"p":1,"n":"Geared up weapons"},{"t":11,"n":"Unused"}]},{"t":9,"s":1,"p":1,"n":"Head Parts","c":[{"t":3,"p":1,"n":"PNAM - Head Part"}],"lt":"HCLF - Hair Color","lf":"QNAM - Texture lighting"},{"t":3,"p":1,"n":"HCLF - Hair Color","lt":"FTST - Head texture","lf":"Head Parts"},{"t":3,"p":1,"n":"ZNAM - Combat Style"},{"t":3,"n":"GNAM - Gift Filter"},{"t":11,"n":"NAM5 - Unknown"},{"t":5,"n":"NAM6 - Height"},{"t":5,"n":"NAM7 - Weight"},{"t":3,"n":"NAM8 - Sound Level"},{"t":10,"n":"Sound Types","c":[{"t":6,"n":"Sound Type","c":[{"t":3,"n":"CSDT - Type"},{"t":10,"n":"Sounds","c":[{"t":6,"n":"Sound","c":[{"t":3,"n":"CSDI - Sound"},{"t":3,"n":"CSDC - Sound Chance"}]}]}]}]},{"t":3,"n":"CSCR - Inherits Sounds From"},{"t":3,"n":"DOFT - Default outfit"},{"t":3,"n":"SOFT - Sleeping outfit"},{"t":3,"n":"DPLT - Default Package List"},{"t":3,"n":"CRIF - Crime faction"},{"t":3,"p":1,"n":"FTST - Head texture","lt":"Tint Layers","lf":"HCLF - Hair Color"},{"t":6,"s":1,"p":1,"n":"QNAM - Texture lighting","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}],"lt":"Head Parts","lf":"NAM9 - Face morph"},{"t":6,"s":1,"p":1,"n":"NAM9 - Face morph","c":[{"t":5,"p":1,"n":"Nose Long\/Short"},{"t":5,"p":1,"n":"Nose Up\/Down"},{"t":5,"p":1,"n":"Jaw Up\/Down"},{"t":5,"p":1,"n":"Jaw Narrow\/Wide"},{"t":5,"p":1,"n":"Jaw Farward\/Back"},{"t":5,"p":1,"n":"Cheeks Up\/Down"},{"t":5,"p":1,"n":"Cheeks Farward\/Back"},{"t":5,"p":1,"n":"Eyes Up\/Down"},{"t":5,"p":1,"n":"Eyes In\/Out"},{"t":5,"p":1,"n":"Brows Up\/Down"},{"t":5,"p":1,"n":"Brows In\/Out"},{"t":5,"p":1,"n":"Brows Farward\/Back"},{"t":5,"p":1,"n":"Lips Up\/Down"},{"t":5,"p":1,"n":"Lips In\/Out"},{"t":5,"p":1,"n":"Chin Narrow\/Wide"},{"t":5,"p":1,"n":"Chin Up\/Down"},{"t":5,"p":1,"n":"Chin Underbite\/Overbite"},{"t":5,"p":1,"n":"Eyes Farward\/Back"},{"t":5,"p":1,"n":"Unknown"}],"lt":"QNAM - Texture lighting","lf":"NAMA - Face parts"},{"t":6,"s":1,"p":1,"n":"NAMA - Face parts","c":[{"t":3,"p":1,"n":"Nose"},{"t":3,"p":1,"n":"Unknown"},{"t":3,"p":1,"n":"Eyes"},{"t":3,"p":1,"n":"Mouth"}],"lt":"NAM9 - Face morph","lf":"Tint Layers"},{"t":10,"s":1,"p":1,"n":"Tint Layers","c":[{"t":6,"p":1,"n":"Layer","c":[{"t":3,"p":1,"n":"TINI - Tint Index"}]}],"lt":"NAMA - Face parts","lf":"FTST - Head texture"}]},{"t":1,"p":1,"n":"PACK - Package","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":6,"p":1,"n":"Pack VMAD","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]},{"t":6,"p":1,"n":"Script Fragments Package","c":[{"t":3,"p":1,"n":"Unknown"},{"t":3,"p":1,"n":"Package Fragments Flags"},{"t":2,"p":1,"n":"fileName"},{"t":7,"p":1,"n":"Package Fragments","c":[{"t":6,"p":1,"n":"Package Fragment #0","c":[{"t":3,"p":1,"n":"Unknown"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]}]}]}]}]},{"t":6,"n":"PKDT - Pack Data","c":[{"t":3,"n":"General Flags"},{"t":3,"n":"Type"},{"t":3,"n":"Interrupt Override"},{"t":3,"n":"Preferred Speed"},{"t":11,"n":"Unknown"},{"t":3,"n":"Interrupt Flags"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"PSDT - Schedule","c":[{"t":3,"n":"Month"},{"t":3,"n":"Day of week"},{"t":3,"n":"Date"},{"t":3,"n":"Hour"},{"t":3,"n":"Minute"},{"t":11,"n":"Unused"},{"t":3,"n":"Duration (minutes)"}]},{"t":8,"n":"Conditions","c":[{"t":6,"n":"Condition","c":[{"t":6,"n":"CTDA - ","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":12,"n":"Comparison Value"},{"t":3,"n":"Function"},{"t":11,"n":"Unused"},{"t":12,"n":"Parameter #1"},{"t":12,"n":"Parameter #2"},{"t":3,"n":"Run On"},{"t":12,"n":"Reference"},{"t":3,"n":"Parameter #3"}]}]}]},{"t":6,"n":"Idle Animations","c":[{"t":3,"n":"IDLF - Flags"},{"t":6,"n":"IDLC - ","c":[{"t":3,"n":"Animation Count"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"IDLT - Idle Timer Setting"},{"t":7,"n":"IDLA - Animations","c":[{"t":3,"n":"Animation #0"}]}]},{"t":3,"n":"CNAM - Combat Style"},{"t":3,"n":"QNAM - Owner Quest"},{"t":6,"n":"PKCU - Counter","c":[{"t":3,"n":"Data Input Count"},{"t":3,"n":"Package Template"},{"t":3,"n":"Version Counter (autoincremented)"}]},{"t":6,"n":"Package Data","c":[{"t":8,"n":"Data Input Values","c":[{"t":6,"n":"Value","c":[{"t":2,"n":"ANAM - Type"}]}]}]},{"t":11,"n":"XNAM - Marker"},{"t":6,"n":"Procedure Tree","c":[{"t":8,"n":"Branches","c":[{"t":6,"n":"Branch","c":[{"t":2,"n":"ANAM - Branch Type"}]}]}]},{"t":8,"n":"Data Inputs","c":[{"t":6,"n":"Data Input","c":[{"t":3,"n":"UNAM - Index"}]}]},{"t":6,"n":"OnBegin","c":[{"n":"POBA - OnBegin Marker"},{"t":3,"n":"INAM - Idle"}]},{"t":6,"n":"OnEnd","c":[{"n":"POEA - OnEnd Marker"},{"t":3,"n":"INAM - Idle"}]},{"t":6,"n":"OnChange","c":[{"n":"POCA - OnChange Marker"},{"t":3,"n":"INAM - Idle"}]}]},{"t":1,"p":1,"n":"PERK - Perk","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":6,"p":1,"n":"Perk VMAD","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]},{"t":6,"p":1,"n":"Script Fragments Perk","c":[{"t":3,"p":1,"n":"Unknown"},{"t":2,"p":1,"n":"fileName"},{"t":9,"p":1,"n":"Perk Fragments","c":[{"t":6,"p":1,"n":"Perk Fragment","c":[{"t":3,"p":1,"n":"Fragment Index"},{"t":3,"p":1,"n":"Unknown"},{"t":3,"n":"Unknown"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]}]}]}]}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"}]},{"t":8,"n":"Conditions","c":[{"t":6,"n":"Condition","c":[{"t":6,"n":"CTDA - ","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":12,"n":"Comparison Value"},{"t":3,"n":"Function"},{"t":11,"n":"Unused"},{"t":12,"n":"Parameter #1"},{"t":12,"n":"Parameter #2"},{"t":3,"n":"Run On"},{"t":12,"n":"Reference"},{"t":3,"n":"Parameter #3"}]}]}]},{"t":6,"n":"DATA - Data","c":[{"t":3,"n":"Trait"},{"t":3,"n":"Level"},{"t":3,"n":"Num Ranks"},{"t":3,"n":"Playable"},{"t":3,"n":"Hidden"}]},{"t":3,"n":"NNAM - Next Perk"},{"t":10,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":6,"n":"PRKE - Header","c":[{"t":3,"n":"Type"},{"t":3,"n":"Rank"},{"t":3,"n":"Priority"}]},{"t":12,"n":"DATA - Effect Data","c":[{"t":6,"n":"Quest + Stage","c":[{"t":3,"n":"Quest"},{"t":3,"n":"Quest Stage"},{"t":11,"n":"Unused"}]}]},{"n":"PRKF - End Marker"}]}]}]},{"t":1,"p":1,"n":"PHZD - Placed Hazard","c":[{"t":3,"n":"Cell"},{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":3,"n":"NAME - Projectile"},{"t":3,"n":"XEZN - Encounter Zone"},{"t":6,"n":"Ownership","c":[{"t":3,"n":"XOWN - Owner"}]},{"t":5,"n":"XHTW - Head-Tracking Weight"},{"t":5,"n":"XFVC - Favor Cost"},{"t":10,"n":"Reflected\/Refracted By","c":[{"t":6,"n":"XPWR - Water","c":[{"t":3,"n":"Reference"},{"t":3,"n":"Type"}]}]},{"t":10,"n":"Linked References","c":[{"t":6,"n":"XLKR - Linked Reference","c":[{"t":3,"n":"Keyword\/Ref"},{"t":3,"n":"Ref"}]}]},{"t":6,"n":"Activate Parents","c":[{"t":3,"n":"XAPD - Flags"}]},{"t":6,"n":"XESP - Enable Parent","c":[{"t":3,"n":"Reference"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"n":"XEMI - Emittance"},{"t":3,"n":"XMBR - MultiBound Reference"},{"n":"XIS2 - Ignored by Sandbox"},{"t":7,"n":"XLRT - Location Ref Type","c":[{"t":3,"n":"Ref #0"}]},{"t":3,"n":"XLRL - Location Reference"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown #0"},{"t":5,"n":"Unknown #1"},{"t":5,"n":"Unknown #2"}]},{"t":5,"n":"XSCL - Scale"},{"t":6,"n":"DATA - Position\/Rotation","c":[{"t":6,"n":"Position","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]},{"t":6,"n":"Rotation","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"PROJ - Projectile","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":6,"p":1,"n":"DATA - Data","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Type"},{"t":5,"p":1,"n":"Gravity","lt":"Range","lf":"Speed"},{"t":5,"p":1,"n":"Speed","lt":"Gravity","lf":"Range"},{"t":5,"p":1,"n":"Range","lt":"Speed","lf":"Gravity"},{"t":3,"n":"Light"},{"t":3,"n":"Muzzle Flash - Light"},{"t":5,"n":"Tracer Chance"},{"t":5,"n":"Explosion - Alt. Trigger - Proximity"},{"t":5,"n":"Explosion - Alt. Trigger - Timer"},{"t":3,"n":"Explosion"},{"t":3,"n":"Sound"},{"t":5,"n":"Muzzle Flash - Duration"},{"t":5,"n":"Fade Duration"},{"t":5,"n":"Impact Force"},{"t":3,"n":"Sound - Countdown"},{"t":3,"n":"Sound - Disable"},{"t":3,"n":"Default Weapon Source"},{"t":5,"n":"Cone Spread"},{"t":5,"n":"Collision Radius"},{"t":5,"n":"Lifetime"},{"t":5,"n":"Relaunch Interval"},{"t":3,"n":"Decal Data"},{"t":3,"n":"Collision Layer"}]},{"t":6,"n":"Muzzle Flash Model","c":[{"t":2,"n":"NAM1 - Model Filename"}]},{"t":3,"n":"VNAM - Sound Level"}]},{"t":1,"p":1,"n":"QUST - Quest","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":6,"p":1,"n":"Quest VMAD","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]},{"t":6,"p":1,"n":"Script Fragments Quest","c":[{"t":3,"p":1,"n":"Unknown"},{"t":3,"p":1,"n":"fragmentCount"},{"t":2,"p":1,"n":"fileName"},{"t":9,"p":1,"n":"Quest Fragments","c":[{"t":6,"p":1,"n":"Quest Fragment","c":[{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Unknown"},{"t":3,"p":1,"n":"Quest Stage Index"},{"t":3,"n":"Unknown"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]},{"t":9,"p":1,"n":"Aliases","c":[{"t":6,"p":1,"n":"Alias","c":[{"t":12,"p":1,"n":"Object Union","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Unused"}]}]},{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":9,"p":1,"n":"Alias Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]}]}]}]}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"DNAM - General","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Priority"},{"t":3,"n":"Form Version"},{"t":11,"n":"Unknown"},{"t":3,"n":"Type"}]},{"t":2,"n":"ENAM - Event"},{"t":7,"n":"Text Display Globals","c":[{"t":3,"n":"QTGL - Global"}]},{"t":2,"n":"FLTR - Object Window Filter"},{"t":6,"n":"Quest Dialogue Conditions","c":[{"t":8,"n":"Conditions","c":[{"t":6,"n":"Condition","c":[{"t":6,"n":"CTDA - ","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":12,"n":"Comparison Value"},{"t":3,"n":"Function"},{"t":11,"n":"Unused"},{"t":12,"n":"Parameter #1"},{"t":12,"n":"Parameter #2"},{"t":3,"n":"Run On"},{"t":12,"n":"Reference"},{"t":3,"n":"Parameter #3"}]}]}]}]},{"n":"NEXT - Marker"},{"t":8,"n":"Conditions","c":[{"t":6,"n":"Condition","c":[{"t":6,"n":"CTDA - ","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":12,"n":"Comparison Value"},{"t":3,"n":"Function"},{"t":11,"n":"Unused"},{"t":12,"n":"Parameter #1"},{"t":12,"n":"Parameter #2"},{"t":3,"n":"Run On"},{"t":12,"n":"Reference"},{"t":3,"n":"Parameter #3"}]}]}]},{"t":10,"n":"Stages","c":[{"t":6,"n":"Stage","c":[{"t":6,"n":"INDX - Stage Index","c":[{"t":3,"n":"Stage Index"},{"t":3,"n":"Flags"},{"t":3,"n":"Unknown"}]}]}]},{"t":8,"n":"Objectives","c":[{"t":6,"n":"Objective","c":[{"t":3,"n":"QOBJ - Objective Index"},{"t":2,"n":"NNAM - Display Text"}]}]},{"t":11,"n":"ANAM - Aliases Marker"},{"t":8,"n":"Aliases","c":[{"t":6,"n":"Alias","c":[{"t":3,"n":"ALST - Reference Alias ID"},{"n":"ALED - Alias End"}]}]},{"t":2,"n":"NNAM - Description"},{"t":8,"n":"Targets","c":[{"t":6,"n":"Target","c":[{"t":6,"n":"QSTA - Target","c":[{"t":3,"n":"Target"},{"t":3,"n":"Flags"},{"t":11,"n":"Unknown"}]}]}]}]},{"t":1,"p":1,"n":"RACE - Race","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"DESC - Description"},{"t":3,"n":"SPCT - Count"},{"t":9,"s":1,"p":1,"n":"Actor Effects","c":[{"t":3,"p":1,"n":"SPLO - Actor Effect"}]},{"t":3,"n":"WNAM - Skin"},{"t":6,"n":"BOD2 - Biped Body Template","c":[{"t":3,"n":"First Person Flags"},{"t":3,"n":"General Flags"},{"n":"Unused"},{"t":3,"n":"Armor Type"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":10,"p":1,"n":"Skill Boosts","c":[{"t":6,"p":1,"n":"Skill Boost","c":[{"t":3,"p":1,"n":"Skill"},{"t":3,"p":1,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]}]},{"t":11,"p":1,"n":"Unknown"},{"t":5,"p":1,"n":"Male Height"},{"t":5,"p":1,"n":"Female Height"},{"t":5,"p":1,"n":"Male Weight"},{"t":5,"p":1,"n":"Female Weight"},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Starting Health"},{"t":5,"p":1,"n":"Starting Magicka"},{"t":5,"p":1,"n":"Starting Stamina"},{"t":5,"p":1,"n":"Base Carry Weight"},{"t":5,"p":1,"n":"Base Mass"},{"t":5,"p":1,"n":"Acceleration rate"},{"t":5,"p":1,"n":"Deceleration rate"},{"t":3,"p":1,"n":"Size"},{"t":3,"p":1,"n":"Head Biped Object"},{"t":3,"p":1,"n":"Hair Biped Object"},{"t":5,"p":1,"n":"Injured Health Pct"},{"t":3,"p":1,"n":"Shield Biped Object"},{"t":5,"p":1,"n":"Health Regen"},{"t":5,"p":1,"n":"Magicka Regen"},{"t":5,"p":1,"n":"Stamina Regen"},{"t":5,"p":1,"n":"Unarmed Damage"},{"t":5,"p":1,"n":"Unarmed Reach"},{"t":3,"p":1,"n":"Body Biped Object"},{"t":5,"p":1,"n":"Aim Angle Tolerance"},{"t":5,"p":1,"n":"Flight Radius"},{"t":5,"p":1,"n":"Angular Acceleration Rate"},{"t":5,"p":1,"n":"Angular Tolerance"},{"t":3,"p":1,"n":"Flags 2"},{"t":6,"p":1,"n":"Mount Data","c":[{"t":5,"p":1,"n":"Offset X"},{"t":5,"p":1,"n":"Offset Y"},{"t":5,"p":1,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"}]}]},{"n":"MNAM - Male Marker"},{"t":2,"n":"ANAM - Male Skeletal Model"},{"t":11,"n":"MODT - Texture Files Hashes"},{"n":"FNAM - Female Marker"},{"t":2,"n":"ANAM - Female Skeletal Model"},{"t":11,"n":"MODT - Texture Files Hashes"},{"n":"NAM2 - Marker NAM2 #1"},{"t":9,"n":"Movement Type Names","c":[{"t":2,"n":"MTNM - Name"}]},{"t":7,"p":1,"n":"VTCK - Voices","c":[{"t":3,"p":1,"n":"Voice #0 (Male)"},{"t":3,"p":1,"n":"Voice #1 (Female)"}]},{"t":7,"n":"DNAM - Decapitate Armors","c":[{"t":3,"n":"Decapitate Armor #0 (Male)"},{"t":3,"n":"Decapitate Armor #1 (Female)"}]},{"t":7,"n":"HCLF - Default Hair Colors","c":[{"t":3,"n":"Default Hair Color #0 (Male)"},{"t":3,"n":"Default Hair Color #1 (Female)"}]},{"t":3,"n":"TINL - Total Number of Tints in List"},{"t":5,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"n":"UNAM - FaceGen - Face clamp"},{"t":3,"n":"ATKR - Attack Race"},{"t":10,"n":"Attacks","c":[{"t":6,"n":"Attack","c":[{"t":6,"n":"ATKD - Attack Data","c":[{"t":5,"n":"Damage Mult"},{"t":5,"n":"Attack Chance"},{"t":3,"n":"Attack Spell"},{"t":3,"n":"Attack Flags"},{"t":5,"n":"Attack Angle"},{"t":5,"n":"Strike Angle"},{"t":5,"n":"Stagger"},{"t":3,"n":"Attack Type"},{"t":5,"n":"Knockdown"},{"t":5,"n":"Recovery Time"},{"t":5,"n":"Stamina Mult"}]}]}]},{"t":6,"p":1,"n":"Body Data","c":[{"n":"NAM1 - Body Data Marker"},{"t":6,"p":1,"n":"Male Body Data","c":[{"n":"MNAM - Male Data Marker"},{"t":10,"s":1,"p":1,"n":"Parts","d":1,"c":[{"t":6,"p":1,"n":"Part","c":[{"t":3,"p":1,"n":"INDX - Index"}]}]}]},{"t":6,"p":1,"n":"Female Body Data","c":[{"n":"FNAM - Female Data Marker"},{"t":10,"s":1,"p":1,"n":"Parts","d":1,"c":[{"t":6,"p":1,"n":"Part","c":[{"t":3,"p":1,"n":"INDX - Index"}]}]}]}]},{"t":9,"p":1,"n":"HNAM - Hairs","c":[{"t":3,"p":1,"n":"Hair"}]},{"t":9,"p":1,"n":"ENAM - Eyes","c":[{"t":3,"p":1,"n":"Eye"}]},{"t":3,"n":"GNAM - Body Part Data"},{"n":"NAM2 - Marker NAM2 #2"},{"n":"NAM3 - Marker NAM3 #3"},{"t":6,"n":"Male Behavior Graph","c":[{"n":"MNAM - Male Data Marker"}]},{"t":6,"n":"Female Behavior Graph","c":[{"n":"FNAM - Female Data Marker"}]},{"t":3,"n":"NAM4 - Material Type"},{"t":3,"n":"NAM5 - Impact Data Set"},{"t":3,"n":"NAM7 - Decapitation FX"},{"t":3,"p":1,"n":"ONAM - Open Loot Sound"},{"t":3,"p":1,"n":"LNAM - Close Loot Sound"},{"t":7,"n":"Biped Object Names","c":[{"t":2,"n":"NAME - Name"}]},{"t":10,"n":"Movement Types","c":[{"t":6,"n":"Movement Types","c":[{"t":3,"n":"MTYP - Movement Type"}]}]},{"t":3,"n":"VNAM - Equipment Flags"},{"t":9,"n":"Equip Slots","c":[{"t":3,"n":"QNAM - Equip Slot"}]},{"t":3,"n":"UNES - Unarmed Equip Slot"},{"t":7,"n":"Phoneme Target Names","c":[{"t":2,"n":"PHTN - Name"}]},{"t":6,"n":"FaceFX Phonemes","c":[{"t":6,"n":"IY","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]}]},{"t":3,"n":"WKMV - Base Movement Default - Walk"},{"t":3,"n":"RNMV - Base Movement Default - Run"},{"t":3,"n":"SWMV - Base Movement Default - Swim"},{"t":3,"n":"FLMV - Base Movement Default - Fly"},{"t":3,"n":"SNMV - Base Movement Default - Sneak"},{"t":3,"n":"SPMV - Base Movement Default - Sprint"},{"t":6,"p":1,"n":"Head Data","c":[{"n":"NAM0 - Head Data Marker"},{"t":6,"s":1,"p":1,"n":"Male Head Data","d":1,"c":[{"p":1,"n":"MNAM - Male Data Marker"}]},{"t":6,"s":1,"p":1,"n":"Female Head Data","d":1,"c":[{"p":1,"n":"NAM0 - Head Data Marker"},{"p":1,"n":"FNAM - Female Data Marker"}]}]},{"t":3,"n":"NAM8 - Morph race"},{"t":3,"n":"RNAM - Armor race"}]},{"t":1,"p":1,"n":"REFR - Placed Object","c":[{"t":3,"n":"Cell"},{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags","c":[{"t":4,"n":"Persistent"}]},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":3,"n":"NAME - Base"},{"t":6,"n":"XMBO - Bound Half Extents","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]},{"t":6,"n":"XPRM - Primitive","c":[{"t":6,"n":"Bounds","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]},{"t":6,"n":"Color","c":[{"t":5,"n":"Red"},{"t":5,"n":"Green"},{"t":5,"n":"Blue"}]},{"t":5,"n":"Unknown"},{"t":3,"n":"Type"}]},{"t":11,"n":"XORD - Unknown"},{"t":6,"n":"XOCP - Occlusion Plane Data","c":[{"t":6,"n":"Size","c":[{"t":5,"n":"Width"},{"t":5,"n":"Height"}]},{"t":6,"n":"Position","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]},{"t":6,"n":"Rotation (Quaternion?)","c":[{"t":5,"n":"q1"},{"t":5,"n":"q2"},{"t":5,"n":"q3"},{"t":5,"n":"q4"}]}]},{"t":8,"n":"XPOD - Portal Data","c":[{"t":6,"n":"References #0","c":[{"t":3,"n":"Origin"},{"t":3,"n":"Destination"}]}]},{"t":6,"n":"XPTL - Room Portal (unused)","c":[{"t":6,"n":"Size","c":[{"t":5,"n":"Width"},{"t":5,"n":"Height"}]},{"t":6,"n":"Position","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]},{"t":6,"n":"Rotation (Quaternion?)","c":[{"t":5,"n":"q1"},{"t":5,"n":"q2"},{"t":5,"n":"q3"},{"t":5,"n":"q4"}]}]},{"t":6,"n":"Bound Data","c":[{"t":6,"n":"XRMR - Header","c":[{"t":3,"n":"Linked Rooms Count"},{"t":3,"n":"Flags"},{"t":11,"n":"Unknown"}]}]},{"n":"XMBP - MultiBound Primitive Marker"},{"t":11,"n":"XRGD - Ragdoll Data"},{"t":11,"n":"XRGB - Ragdoll Biped Data"},{"t":5,"n":"XRDS - Radius"},{"t":10,"n":"Reflected\/Refracted By","c":[{"t":6,"n":"XPWR - Water","c":[{"t":3,"n":"Reference"},{"t":3,"n":"Type"}]}]},{"t":9,"n":"Lit Water","c":[{"t":3,"n":"XLTW - Water"}]},{"t":3,"n":"XEMI - Emittance"},{"t":6,"n":"XLIG - Light Data","c":[{"t":5,"n":"FOV 90+\/-"},{"t":5,"n":"Fade 1.35+\/-"},{"t":11,"n":"Unknown"},{"t":5,"n":"Shadow Depth Bias"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"XALP - Alpha","c":[{"t":3,"n":"Cutoff"},{"t":3,"n":"Base"}]},{"t":6,"n":"XTEL - Teleport Destination","c":[{"t":3,"n":"Door"},{"t":6,"n":"Position\/Rotation","c":[{"t":6,"n":"Position","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]},{"t":6,"n":"Rotation","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]}]},{"t":3,"n":"Flags"}]},{"t":3,"n":"XTNM - Teleport Message Box"},{"t":3,"n":"XMBR - MultiBound Reference"},{"t":11,"n":"XWCN - Unknown"},{"t":11,"n":"XWCS - Unknown"},{"t":6,"n":"XWCU - Water Velocity","c":[{"t":5,"n":"X Offset"},{"t":5,"n":"Y Offset"},{"t":5,"n":"Z Offset"},{"t":11,"n":"Unknown"},{"t":5,"n":"X Angle"},{"t":5,"n":"Y Angle"},{"t":5,"n":"Z Angle"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"XCVL - Unknown","c":[{"t":11,"n":"Unknown"},{"t":5,"n":"X Angle"},{"t":11,"n":"Unknown"}]},{"t":3,"n":"XCZR - Unknown"},{"t":11,"n":"XCZA - Unknown"},{"t":3,"n":"XCZC - Unknown"},{"t":5,"n":"XSCL - Scale"},{"t":3,"n":"XSPC - Spawn Container"},{"t":6,"n":"Activate Parents","c":[{"t":3,"n":"XAPD - Flags"}]},{"t":3,"n":"XLIB - Leveled Item Base Object"},{"t":3,"n":"XLCM - Level Modifier"},{"t":3,"n":"XLCN - Persistent Location"},{"t":3,"n":"XTRI - Collision Layer"},{"t":6,"n":"XLOC - Lock Data","c":[{"t":3,"n":"Level"},{"t":11,"n":"Unused"},{"t":3,"n":"Key"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"},{"t":11,"n":"Unused"}]},{"t":3,"n":"XEZN - Encounter Zone"},{"t":6,"n":"XNDP - Navigation Door Link","c":[{"t":3,"n":"Navigation Mesh"},{"t":3,"n":"Teleport Marker Triangle"},{"t":11,"n":"Unused"}]},{"t":7,"n":"XLRT - Location Ref Type","c":[{"t":3,"n":"Ref #0"}]},{"n":"XIS2 - Ignored by Sandbox"},{"t":6,"n":"Ownership","c":[{"t":3,"n":"XOWN - Owner"}]},{"t":3,"n":"XCNT - Item Count"},{"t":5,"n":"XCHG - Charge"},{"t":3,"n":"XLRL - Location Reference"},{"t":6,"n":"XESP - Enable Parent","c":[{"t":3,"n":"Reference"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"n":"Linked References","c":[{"t":6,"n":"XLKR - Linked Reference","c":[{"t":3,"n":"Keyword\/Ref"},{"t":3,"n":"Ref"}]}]},{"t":8,"n":"Patrol","c":[{"t":6,"n":"Data","c":[{"t":5,"n":"XPRD - Idle Time"},{"n":"XPPA - Patrol Script Marker"},{"t":3,"n":"INAM - Idle"}]}]},{"t":3,"n":"XACT - Action Flag"},{"t":5,"n":"XHTW - Head-Tracking Weight"},{"t":5,"n":"XFVC - Favor Cost"},{"n":"ONAM - Open by Default"},{"t":6,"p":1,"n":"Map Marker","c":[{"n":"XMRK - Map Marker Data"},{"t":3,"n":"FNAM - Map Flags"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"TNAM - ","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"XATR - Attach Ref"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown #0"},{"t":5,"n":"Unknown #1"},{"t":5,"n":"Unknown #2"}]},{"t":6,"n":"DATA - Position\/Rotation","c":[{"t":6,"n":"Position","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]},{"t":6,"n":"Rotation","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"REVB - Reverb Parameters","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Decay Time (ms)"},{"t":3,"p":1,"n":"HF Reference (Hz)"},{"t":3,"p":1,"n":"Room Filter"},{"t":3,"p":1,"n":"Room HF Filter"},{"t":3,"p":1,"n":"Reflections"},{"t":3,"p":1,"n":"Reverb Amp"},{"t":3,"p":1,"n":"Decay HF Ratio"},{"t":3,"p":1,"n":"Reflect Delay (ms), scaled"},{"t":3,"p":1,"n":"Reverb Delay (ms)"},{"t":3,"p":1,"n":"Diffusion %"},{"t":3,"p":1,"n":"Density %"},{"t":3,"p":1,"n":"Unknown"}]}]},{"t":1,"p":1,"n":"SCEN - Scene","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":6,"p":1,"n":"Scene VMAD","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]},{"t":6,"p":1,"n":"Script Fragments Scene","c":[{"t":3,"p":1,"n":"Unknown"},{"t":3,"p":1,"n":"Scene Fragments Flags"},{"t":2,"p":1,"n":"fileName"},{"t":7,"p":1,"n":"Scene Fragments","c":[{"t":6,"p":1,"n":"Scene Fragment #0","c":[{"t":3,"p":1,"n":"Unknown"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]},{"t":7,"p":1,"n":"Phase Fragments","c":[{"t":6,"p":1,"n":"Phase Fragment #0","c":[{"t":3,"p":1,"n":"Phase Flag"},{"t":3,"p":1,"n":"Phase Index"},{"t":3,"p":1,"n":"Unknown"},{"t":3,"p":1,"n":"Unknown"},{"t":3,"p":1,"n":"Unknown"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]}]}]}]}]},{"t":3,"n":"FNAM - Flags"},{"t":8,"n":"Phases","c":[{"t":6,"n":"Phase","c":[{"n":"HNAM - Marker Phase Start"}]}]},{"t":8,"n":"Actors","c":[{"t":6,"n":"Actor","c":[{"t":3,"n":"ALID - Actor ID"}]}]},{"t":8,"n":"Actions","c":[{"t":6,"n":"Action","c":[{"t":3,"n":"ANAM - Type"}]}]},{"t":6,"n":"Unused","c":[{"t":11,"n":"SCHR - Unknown"}]},{"n":"NEXT - Marker"},{"t":6,"n":"Unused","c":[{"t":11,"n":"SCHR - Unknown"}]},{"t":3,"n":"PNAM - Quest"},{"t":3,"n":"INAM - Last Action Index"},{"t":11,"n":"VNAM - Unknown"},{"t":8,"n":"Conditions","c":[{"t":6,"n":"Condition","c":[{"t":6,"n":"CTDA - ","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":12,"n":"Comparison Value"},{"t":3,"n":"Function"},{"t":11,"n":"Unused"},{"t":12,"n":"Parameter #1"},{"t":12,"n":"Parameter #2"},{"t":3,"n":"Run On"},{"t":12,"n":"Reference"},{"t":3,"n":"Parameter #3"}]}]}]}]},{"t":1,"p":1,"n":"SCRL - Scroll","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":3,"n":"MDOB - Menu Display Object"},{"t":3,"n":"ETYP - Equipment Type"},{"t":2,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":6,"n":"DATA - Item","c":[{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]},{"t":6,"n":"SPIT - Data","c":[{"t":3,"n":"Base Cost"},{"t":3,"n":"Flags"},{"t":3,"n":"Type"},{"t":5,"n":"Charge Time"},{"t":3,"n":"Cast Type"},{"t":3,"n":"Target Type"},{"t":5,"n":"Cast Duration"},{"t":5,"n":"Range"},{"t":3,"n":"Half-cost Perk"}]},{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":3,"n":"EFID - Base Effect"},{"t":6,"n":"EFIT - ","c":[{"t":5,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"}]}]}]}]},{"t":1,"p":1,"n":"SHOU - Shout","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"MDOB - Menu Display Object"},{"t":2,"n":"DESC - Description"},{"t":8,"n":"Words of Power","c":[{"t":6,"n":"SNAM - ","c":[{"t":3,"n":"Word"},{"t":3,"n":"Spell"},{"t":5,"n":"Recovery Time"}]}]}]},{"t":1,"p":1,"n":"SLGM - Soul Gem","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]},{"t":3,"n":"SOUL - Contained Soul"},{"t":3,"n":"SLCP - Maximum Capacity"},{"t":3,"n":"NAM0 - Linked To"}]},{"t":1,"p":1,"n":"SNCT - Sound Category","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"FNAM - Flags","lt":"UNAM - Default Menu Value","lf":"PNAM - Parent"},{"t":3,"p":1,"n":"PNAM - Parent","lt":"FNAM - Flags","lf":"VNAM - Static Volume Multiplier"},{"t":3,"p":1,"n":"VNAM - Static Volume Multiplier","lt":"PNAM - Parent","lf":"UNAM - Default Menu Value"},{"t":3,"p":1,"n":"UNAM - Default Menu Value","lt":"VNAM - Static Volume Multiplier","lf":"FNAM - Flags"}]},{"t":1,"p":1,"n":"SNDR - Sound Descriptor","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":11,"n":"CNAM - Unknown"},{"t":3,"p":1,"n":"GNAM - Category","lt":"BNAM - Values","lf":"SNAM - Alternate Sound For"},{"t":3,"p":1,"n":"SNAM - Alternate Sound For","lt":"GNAM - Category","lf":"Sounds"},{"t":8,"s":1,"p":1,"n":"Sounds","c":[{"t":6,"p":1,"n":"Sound Files","c":[{"t":2,"p":1,"n":"ANAM - File Name"}]}],"lt":"SNAM - Alternate Sound For","lf":"ONAM - Output Model"},{"t":3,"p":1,"n":"ONAM - Output Model","lt":"Sounds","lf":"FNAM - String"},{"t":2,"p":1,"n":"FNAM - String","lt":"ONAM - Output Model","lf":"Conditions"},{"t":8,"s":1,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"p":1,"n":"Unused"},{"t":12,"p":1,"n":"Comparison Value"},{"t":3,"p":1,"n":"Function"},{"t":11,"p":1,"n":"Unused"},{"t":12,"p":1,"n":"Parameter #1"},{"t":12,"p":1,"n":"Parameter #2"},{"t":3,"p":1,"n":"Run On"},{"t":12,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]}]}],"lt":"FNAM - String","lf":"LNAM - Values"},{"t":6,"s":1,"p":1,"n":"LNAM - Values","c":[{"t":11,"p":1,"n":"Unknown"},{"t":3,"p":1,"n":"Looping"},{"t":11,"p":1,"n":"Unknown"},{"t":3,"p":1,"n":"Rumble Send Value = (Small \/ 7) + ((Big \/ 7) * 16)"}],"lt":"Conditions","lf":"BNAM - Values"},{"t":6,"s":1,"p":1,"n":"BNAM - Values","c":[{"t":3,"p":1,"n":"% Frequency Shift"},{"t":3,"p":1,"n":"% Frequency Variance"},{"t":3,"p":1,"n":"Priority"},{"t":3,"p":1,"n":"db Variance"},{"t":3,"p":1,"n":"Static Attenuation (db)"}],"lt":"LNAM - Values","lf":"GNAM - Category"}]},{"t":1,"p":1,"n":"SOPM - Sound Output Model","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"NAM1 - Data","c":[{"t":3,"p":1,"n":"Flags"},{"t":11,"p":1,"n":"Unknown"},{"t":3,"p":1,"n":"Reverb Send %"}],"lt":"ANAM - Attenuation Values","lf":"MNAM - Type"},{"t":11,"n":"FNAM - Unknown"},{"t":3,"p":1,"n":"MNAM - Type","lt":"NAM1 - Data","lf":"ONAM - Output Values"},{"t":11,"n":"CNAM - Unknown"},{"t":11,"n":"SNAM - Unknown"},{"t":6,"s":1,"p":1,"n":"ONAM - Output Values","c":[{"t":8,"p":1,"n":"Channels","c":[{"t":6,"p":1,"n":" #0 (Channel 0)","c":[{"t":3,"p":1,"n":"L"},{"t":3,"p":1,"n":"R"},{"t":3,"p":1,"n":"C"},{"t":3,"p":1,"n":"LFE"},{"t":3,"p":1,"n":"RL"},{"t":3,"p":1,"n":"RR"},{"t":3,"p":1,"n":"BL"},{"t":3,"p":1,"n":"BR"}]},{"t":6,"p":1,"n":" #1 (Channel 1)","c":[{"t":3,"p":1,"n":"L"},{"t":3,"p":1,"n":"R"},{"t":3,"p":1,"n":"C"},{"t":3,"p":1,"n":"LFE"},{"t":3,"p":1,"n":"RL"},{"t":3,"p":1,"n":"RR"},{"t":3,"p":1,"n":"BL"},{"t":3,"p":1,"n":"BR"}]},{"t":6,"p":1,"n":" #2 (Channel 2? (unused))","c":[{"t":3,"p":1,"n":"L"},{"t":3,"p":1,"n":"R"},{"t":3,"p":1,"n":"C"},{"t":3,"p":1,"n":"LFE"},{"t":3,"p":1,"n":"RL"},{"t":3,"p":1,"n":"RR"},{"t":3,"p":1,"n":"BL"},{"t":3,"p":1,"n":"BR"}]}]}],"lt":"MNAM - Type","lf":"ANAM - Attenuation Values"},{"t":6,"s":1,"p":1,"n":"ANAM - Attenuation Values","c":[{"t":11,"p":1,"n":"Unknown"},{"t":5,"p":1,"n":"Min Distance"},{"t":5,"p":1,"n":"Max Distance"},{"t":7,"p":1,"n":"Curve","c":[{"t":3,"p":1,"n":"Value #0"},{"t":3,"p":1,"n":"Value #1"},{"t":3,"p":1,"n":"Value #2"},{"t":3,"p":1,"n":"Value #3"},{"t":3,"p":1,"n":"Value #4"}]},{"t":11,"p":1,"n":"Unknown"}],"lt":"ONAM - Output Values","lf":"NAM1 - Data"}]},{"t":1,"p":1,"n":"SOUN - Sound Marker","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":11,"n":"FNAM - Unknown"},{"t":11,"n":"SNDD - Unknown"},{"t":3,"p":1,"n":"SDSC - Sound Descriptor"}]},{"t":1,"p":1,"n":"SPEL - Spell","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":3,"n":"MDOB - Menu Display Object"},{"t":3,"n":"ETYP - Equipment Type"},{"t":2,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"SPIT - Data","c":[{"t":3,"p":1,"n":"Base Cost"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Type"},{"t":5,"p":1,"n":"Charge Time"},{"t":3,"p":1,"n":"Cast Type"},{"t":3,"p":1,"n":"Target Type"},{"t":5,"p":1,"n":"Cast Duration"},{"t":5,"p":1,"n":"Range"},{"t":3,"p":1,"n":"Half-cost Perk"}]},{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":3,"n":"EFID - Base Effect"},{"t":6,"n":"EFIT - ","c":[{"t":5,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"}]}]}]}]},{"t":1,"p":1,"n":"STAT - Static","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"n":"DNAM - Direction Material","c":[{"t":5,"n":"Max Angle (30-120)"},{"t":3,"n":"Material"}]},{"t":8,"n":"MNAM - Distant LOD","c":[{"t":6,"n":"LOD #0 (Level 0)","c":[{"t":2,"n":"Mesh"}]},{"t":6,"n":"LOD #1 (Level 1)","c":[{"t":2,"n":"Mesh"}]},{"t":6,"n":"LOD #2 (Level 2)","c":[{"t":2,"n":"Mesh"}]},{"t":6,"n":"LOD #3 (Level 3)","c":[{"t":2,"n":"Mesh"}]}]}]},{"t":1,"p":1,"n":"TREE - Tree","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":3,"n":"PFIG - Ingredient"},{"t":3,"n":"SNAM - Harvest Sound"},{"t":6,"n":"PFPC - Ingredient Production","c":[{"t":3,"n":"Spring"},{"t":3,"n":"Summer"},{"t":3,"n":"Fall"},{"t":3,"n":"Winter"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"CNAM - Tree Data","c":[{"t":5,"n":"Trunk Flexibility"},{"t":5,"n":"Branch Flexibility"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Leaf Amplitude"},{"t":5,"n":"Leaf Frequency"}]}]},{"t":1,"p":1,"n":"WATR - Water","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":7,"n":"Unused","c":[{"t":2,"n":"NNAM - Noise Map"}]},{"t":3,"n":"ANAM - Opacity"},{"t":3,"n":"FNAM - Flags"},{"t":11,"n":"MNAM - Unused"},{"t":3,"n":"TNAM - Material"},{"t":3,"n":"SNAM - Open Sound"},{"t":3,"n":"XNAM - Spell"},{"t":3,"n":"INAM - Image Space"},{"t":3,"n":"DATA - Damage Per Second"},{"t":6,"n":"DNAM - Visual Data","c":[{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Specular Properties - Sun Specular Power"},{"t":5,"n":"Water Properties - Reflectivity Amount"},{"t":5,"n":"Water Properties - Fresnel Amount"},{"t":11,"n":"Unknown"},{"t":5,"n":"Fog Properties - Above Water - Fog Distance - Near Plane"},{"t":5,"n":"Fog Properties - Above Water - Fog Distance - Far Plane"},{"t":6,"n":"Shallow Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Deep Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Reflection Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":11,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Displacement Simulator - Starting Size"},{"t":5,"n":"Displacement Simulator - Force"},{"t":5,"n":"Displacement Simulator - Velocity"},{"t":5,"n":"Displacement Simulator - Falloff"},{"t":5,"n":"Displacement Simulator - Dampner"},{"t":5,"n":"Unknown"},{"t":5,"n":"Noise Properties - Noise Falloff"},{"t":5,"n":"Noise Properties - Layer One - Wind Direction"},{"t":5,"n":"Noise Properties - Layer Two - Wind Direction"},{"t":5,"n":"Noise Properties - Layer Three - Wind Direction"},{"t":5,"n":"Noise Properties - Layer One - Wind Speed"},{"t":5,"n":"Noise Properties - Layer Two - Wind Speed"},{"t":5,"n":"Noise Properties - Layer Three - Wind Speed"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Fog Properties - Above Water - Fog Amount"},{"t":5,"n":"Unknown"},{"t":5,"n":"Fog Properties - Under Water - Fog Amount"},{"t":5,"n":"Fog Properties - Under Water - Fog Distance - Near Plane"},{"t":5,"n":"Fog Properties - Under Water - Fog Distance - Far Plane"},{"t":5,"n":"Water Properties - Refraction Magnitude"},{"t":5,"n":"Specular Properties - Specular Power"},{"t":5,"n":"Unknown"},{"t":5,"n":"Specular Properties - Specular Radius"},{"t":5,"n":"Specular Properties - Specular Brightness"},{"t":5,"n":"Noise Properties - Layer One - UV Scale"},{"t":5,"n":"Noise Properties - Layer Two - UV Scale"},{"t":5,"n":"Noise Properties - Layer Three - UV Scale"},{"t":5,"n":"Noise Properties - Layer One - Amplitude Scale"},{"t":5,"n":"Noise Properties - Layer Two - Amplitude Scale"},{"t":5,"n":"Noise Properties - Layer Three - Amplitude Scale"},{"t":5,"n":"Water Properties - Reflection Magnitude"},{"t":5,"n":"Specular Properties - Sun Sparkle Magnitude"},{"t":5,"n":"Specular Properties - Sun Specular Magnitude"},{"t":5,"n":"Depth Properties - Reflections"},{"t":5,"n":"Depth Properties - Refraction"},{"t":5,"n":"Depth Properties - Normals"},{"t":5,"n":"Depth Properties - Specular Lighting"},{"t":5,"n":"Specular Properties - Sun Sparkle Power"}]},{"t":11,"n":"GNAM - Unused"},{"t":6,"n":"NAM0 - Linear Velocity","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]},{"t":6,"n":"NAM1 - Angular Velocity","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]},{"t":2,"n":"NAM2 - Noise Texture"},{"t":2,"n":"NAM3 - Unused"},{"t":2,"n":"NAM4 - Unused"}]},{"t":1,"p":1,"n":"WEAP - Weapon","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"}]},{"t":3,"n":"EITM - Object Effect"},{"t":3,"n":"EAMT - Enchantment Amount"},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"ETYP - Equipment Type"},{"t":3,"n":"BIDS - Block Bash Impact Data Set"},{"t":3,"n":"BAMT - Alternate Block Material"},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Drop"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":2,"n":"DESC - Description"},{"t":6,"n":"Has Scope","c":[{"t":2,"n":"MOD3 - Model Filename"}]},{"t":11,"n":"NNAM - Unused"},{"t":3,"n":"INAM - Impact Data Set"},{"t":3,"p":1,"n":"WNAM - 1st Person Model Object"},{"t":3,"p":1,"n":"SNAM - Attack Sound"},{"t":3,"p":1,"n":"XNAM - Attack Sound 2D"},{"t":3,"p":1,"n":"NAM7 - Attack Loop Sound"},{"t":3,"p":1,"n":"TNAM - Attack Fail Sound"},{"t":3,"p":1,"n":"UNAM - Idle Sound"},{"t":3,"p":1,"n":"NAM9 - Equip Sound"},{"t":3,"p":1,"n":"NAM8 - Unequip Sound"},{"t":6,"s":1,"p":1,"n":"DATA - Game Data","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"},{"t":3,"p":1,"n":"Damage"}]},{"t":6,"p":1,"n":"DNAM - Data","c":[{"t":3,"n":"Animation Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Speed","lt":"Reach","lf":"Stagger"},{"t":5,"p":1,"n":"Reach","lt":"Resist","lf":"Speed"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"},{"t":5,"n":"Sight FOV"},{"t":11,"n":"Unknown"},{"t":3,"n":"Base VATS To-Hit Chance"},{"t":3,"n":"Attack Animation"},{"t":3,"n":"# Projectiles"},{"t":3,"n":"Embedded Weapon AV (unused)"},{"t":5,"n":"Range Min"},{"t":5,"n":"Range Max"},{"t":3,"n":"On Hit"},{"t":3,"n":"Flags2"},{"t":5,"n":"Animation Attack Mult"},{"t":5,"n":"Unknown"},{"t":5,"n":"Rumble - Left Motor Strength"},{"t":5,"n":"Rumble - Right Motor Strength"},{"t":5,"n":"Rumble - Duration"},{"t":11,"n":"Unknown"},{"t":3,"n":"Skill"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Resist","lt":"Stagger","lf":"Reach"},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"Stagger","lt":"Speed","lf":"Resist"}]},{"t":6,"s":1,"p":1,"n":"CRDT - Critical Data","c":[{"t":3,"p":1,"n":"Damage"},{"t":11,"p":1,"n":"Unused"},{"t":5,"p":1,"n":"% Mult"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Effect"}]},{"t":3,"n":"VNAM - Detection Sound Level"},{"t":3,"n":"CNAM - Template"}]},{"t":1,"p":1,"n":"WRLD - Worldspace","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":7,"n":"Unused RNAM","c":[{"t":11,"n":"RNAM - Unknown"}]},{"t":11,"n":"MHDT - Max Height Data"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"WCTR - Fixed Dimensions Center Cell","c":[{"t":3,"n":"X"},{"t":3,"n":"Y"}]},{"t":3,"n":"LTMP - Interior Lighting"},{"t":3,"n":"XEZN - Encounter Zone"},{"t":3,"n":"XLCN - Location"},{"t":6,"n":"Parent","c":[{"t":3,"n":"WNAM - Worldspace"},{"t":6,"n":"PNAM - ","c":[{"t":3,"n":"Flags"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"CNAM - Climate"},{"t":3,"n":"NAM2 - Water"},{"t":3,"n":"NAM3 - LOD Water Type"},{"t":5,"n":"NAM4 - LOD Water Height"},{"t":6,"n":"DNAM - Land Data","c":[{"t":5,"n":"Default Land Height"},{"t":5,"n":"Default Water Height"}]},{"t":2,"n":"ICON - Map Image"},{"t":6,"n":"Cloud Model","c":[{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]}]},{"t":6,"n":"MNAM - Map Data","c":[{"t":6,"n":"Usable Dimensions","c":[{"t":3,"n":"X"},{"t":3,"n":"Y"}]},{"t":6,"n":"Cell Coordinates","c":[{"t":6,"n":"NW Cell","c":[{"t":3,"n":"X"},{"t":3,"n":"Y"}]},{"t":6,"n":"SE Cell","c":[{"t":3,"n":"X"},{"t":3,"n":"Y"}]}]},{"t":6,"n":"Camera Data","c":[{"t":5,"n":"Min Height"},{"t":5,"n":"Max Height"},{"t":5,"n":"Initial Pitch"}]}]},{"t":6,"n":"ONAM - World Map Offset Data","c":[{"t":5,"n":"World Map Scale"},{"t":5,"n":"Cell X Offset"},{"t":5,"n":"Cell Y Offset"},{"t":5,"n":"Cell Z Offset"}]},{"t":5,"n":"NAMA - Distant LOD Multiplier"},{"t":3,"n":"DATA - Flags"},{"t":6,"n":"Object Bounds","c":[{"t":6,"n":"NAM0 - Min","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"}]},{"t":6,"n":"NAM9 - Max","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"}]}]},{"t":3,"n":"ZNAM - Music"},{"t":2,"n":"NNAM - Canopy Shadow (unused)"},{"t":2,"n":"XNAM - Water Noise Texture"},{"t":2,"n":"TNAM - HD LOD Diffuse Texture"},{"t":2,"n":"UNAM - HD LOD Normal Texture"},{"t":2,"n":"XWEM - Water Environment Map (unused)"},{"t":11,"n":"OFST - Offset Data"}]},{"t":1,"p":1,"n":"WTHR - Weather","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"00TX - Cloud Texture Layer #0"},{"t":2,"n":"10TX - Cloud Texture Layer #1"},{"t":2,"n":"20TX - Cloud Texture Layer #2"},{"t":2,"n":"30TX - Cloud Texture Layer #3"},{"t":2,"n":"40TX - Cloud Texture Layer #4"},{"t":2,"n":"50TX - Cloud Texture Layer #5"},{"t":2,"n":"60TX - Cloud Texture Layer #6"},{"t":2,"n":"70TX - Cloud Texture Layer #7"},{"t":2,"n":"80TX - Cloud Texture Layer #8"},{"t":2,"n":"90TX - Cloud Texture Layer #9"},{"t":2,"n":":0TX - Cloud Texture Layer #10"},{"t":2,"n":";0TX - Cloud Texture Layer #11"},{"t":2,"n":"<0TX - Cloud Texture Layer #12"},{"t":2,"n":"=0TX - Cloud Texture Layer #13"},{"t":2,"n":">0TX - Cloud Texture Layer #14"},{"t":2,"n":"?0TX - Cloud Texture Layer #15"},{"t":2,"n":"@0TX - Cloud Texture Layer #16"},{"t":2,"n":"A0TX - Cloud Texture Layer #17"},{"t":2,"n":"B0TX - Cloud Texture Layer #18"},{"t":2,"n":"C0TX - Cloud Texture Layer #19"},{"t":2,"n":"D0TX - Cloud Texture Layer #20"},{"t":2,"n":"E0TX - Cloud Texture Layer #21"},{"t":2,"n":"F0TX - Cloud Texture Layer #22"},{"t":2,"n":"G0TX - Cloud Texture Layer #23"},{"t":2,"n":"H0TX - Cloud Texture Layer #24"},{"t":2,"n":"I0TX - Cloud Texture Layer #25"},{"t":2,"n":"J0TX - Cloud Texture Layer #26"},{"t":2,"n":"K0TX - Cloud Texture Layer #27"},{"t":2,"n":"L0TX - Cloud Texture Layer #28"},{"t":11,"n":"DNAM - Unused"},{"t":11,"n":"CNAM - Unused"},{"t":11,"n":"ANAM - Unused"},{"t":11,"n":"BNAM - Unused"},{"t":11,"n":"LNAM - Unknown"},{"t":3,"n":"MNAM - Precipitation Type"},{"t":3,"n":"NNAM - Visual Effect"},{"t":11,"n":"ONAM - Unused"},{"t":6,"n":"Cloud Speed","c":[{"t":7,"n":"RNAM - Y Speed","c":[{"t":3,"n":"Layer #0"}]}]},{"t":8,"n":"PNAM - Cloud Colors","c":[{"t":6,"n":"Layer #0","c":[{"t":8,"n":"Colors","c":[{"t":6,"n":"Time #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Time #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Time #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Time #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]}]}]},{"t":8,"n":"JNAM - Cloud Alphas","c":[{"t":6,"n":"Layer #0","c":[{"t":5,"n":"Sunrise"},{"t":5,"n":"Day"},{"t":5,"n":"Sunset"},{"t":5,"n":"Night"}]}]},{"t":6,"n":"NAM0 - Weather Colors","c":[{"t":8,"n":"Sky-Upper","c":[{"t":6,"n":"Color #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Fog Near","c":[{"t":6,"n":"Color #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Unknown","c":[{"t":6,"n":"Color #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Ambient","c":[{"t":6,"n":"Color #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Sunlight","c":[{"t":6,"n":"Color #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Sun","c":[{"t":6,"n":"Color #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Stars","c":[{"t":6,"n":"Color #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Sky-Lower","c":[{"t":6,"n":"Color #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Horizon","c":[{"t":6,"n":"Color #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Effect Lighting","c":[{"t":6,"n":"Color #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Cloud LOD Diffuse","c":[{"t":6,"n":"Color #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Cloud LOD Ambient","c":[{"t":6,"n":"Color #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Fog Far","c":[{"t":6,"n":"Color #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Sky Statics","c":[{"t":6,"n":"Color #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Water Multiplier","c":[{"t":6,"n":"Color #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Sun Glare","c":[{"t":6,"n":"Color #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Moon Glare","c":[{"t":6,"n":"Color #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]}]},{"t":6,"n":"FNAM - Fog Distance","c":[{"t":5,"n":"Day - Near"},{"t":5,"n":"Day - Far"},{"t":5,"n":"Night - Near"},{"t":5,"n":"Night - Far"},{"t":5,"n":"Day - Power"},{"t":5,"n":"Night - Power"},{"t":5,"n":"Day - Max"},{"t":5,"n":"Night - Max"}]},{"t":6,"n":"DATA - Data","c":[{"t":3,"n":"Wind Speed"},{"t":11,"n":"Unknown"},{"t":3,"n":"Trans Delta"},{"t":3,"n":"Sun Glare"},{"t":3,"n":"Sun Damage"},{"t":3,"n":"Precipitation - Begin Fade In"},{"t":3,"n":"Precipitation - End Fade Out"},{"t":3,"n":"Thunder\/Lightning - Begin Fade In"},{"t":3,"n":"Thunder\/Lightning - End Fade Out"},{"t":3,"n":"Thunder\/Lightning - Frequency"},{"t":3,"n":"Flags"},{"t":6,"n":"Lightning Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"}]},{"t":3,"n":"Visual Effect - Begin"},{"t":3,"n":"Visual Effect - End"},{"t":3,"n":"Wind Direction"},{"t":3,"n":"Wind Direction Range"}]},{"t":3,"n":"NAM1 - Disabled Cloud Layers"},{"t":8,"s":1,"p":1,"n":"Sounds","c":[{"t":6,"p":1,"n":"SNAM - Sound","c":[{"t":3,"p":1,"n":"Sound"},{"t":3,"p":1,"n":"Type"}]}]},{"t":9,"n":"Sky Statics","c":[{"t":3,"n":"TNAM - Static"}]},{"t":6,"n":"IMSP - Image Spaces","c":[{"t":3,"n":"Sunrise"},{"t":3,"n":"Day"},{"t":3,"n":"Sunset"},{"t":3,"n":"Night"}]},{"t":8,"n":"Directional Ambient Lighting Colors","c":[{"t":6,"n":"DALC - Sunrise\/Day\/Sunset\/Night Order","c":[{"t":6,"n":"Ambient Colors","c":[{"t":8,"n":"Colors","c":[{"t":6,"n":"Color #0 (X+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (X-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Y+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Y-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #4 (Z+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #5 (Z-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"Specular","c":[{"t":6,"n":"Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"Fresnel Power"}]}]}]}]},{"t":11,"n":"NAM2 - Unused"},{"t":11,"n":"NAM3 - Unused"},{"t":6,"n":"Aurora","c":[{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]}]}]},{"t":1,"p":1,"n":"ACHR - Placed NPC","c":[{"t":3,"n":"Cell"},{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags","c":[{"t":4,"n":"Persistent"}]},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":3,"n":"NAME - Base"},{"t":3,"n":"XEZN - Encounter Zone"},{"t":11,"n":"XRGD - Ragdoll Data"},{"t":11,"n":"XRGB - Ragdoll Biped Data"},{"t":6,"n":"Patrol Data","c":[{"t":5,"n":"XPRD - Idle Time"},{"n":"XPPA - Patrol Script Marker"},{"t":3,"n":"INAM - Idle"}]},{"t":3,"n":"XLCM - Level Modifier"},{"t":3,"n":"XMRC - Merchant Container"},{"t":3,"n":"XCNT - Count"},{"t":5,"n":"XRDS - Radius"},{"t":5,"n":"XHLP - Health"},{"t":10,"n":"Linked References","c":[{"t":6,"n":"XLKR - Linked Reference","c":[{"t":3,"n":"Keyword\/Ref"},{"t":3,"n":"Ref"}]}]},{"t":6,"n":"Activate Parents","c":[{"t":3,"n":"XAPD - Flags"}]},{"t":6,"n":"XCLP - Linked Reference Color","c":[{"t":6,"n":"Link Start Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Link End Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"XLCN - Persistent Location"},{"t":3,"n":"XLRL - Location Reference"},{"n":"XIS2 - Ignored by Sandbox"},{"t":7,"n":"XLRT - Location Ref Type","c":[{"t":3,"n":"Ref #0"}]},{"t":3,"n":"XHOR - Horse"},{"t":5,"n":"XHTW - Head-Tracking Weight"},{"t":5,"n":"XFVC - Favor Cost"},{"t":6,"n":"XESP - Enable Parent","c":[{"t":3,"n":"Reference"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":6,"n":"Ownership","c":[{"t":3,"n":"XOWN - Owner"}]},{"t":3,"n":"XEMI - Emittance"},{"t":3,"n":"XMBR - MultiBound Reference"},{"n":"XIBS - Ignored By Sandbox"},{"t":5,"n":"XSCL - Scale"},{"t":6,"n":"DATA - Position\/Rotation","c":[{"t":6,"n":"Position","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]},{"t":6,"n":"Rotation","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]}]}]}]},"name":"Bash.All","hash":"51EC207C","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.Body-F.json ================================================ {"records":"RACE","description":"Body-F tag from Wrye Bash.\r\n\r\nUsed when the mod modifies female body mesh\/texture definitions.","tree":{"records":[{"t":1,"p":1,"n":"RACE - Race","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":3,"n":"SPCT - Count"},{"t":9,"n":"Actor Effects","c":[{"t":3,"n":"SPLO - Actor Effect"}]},{"t":3,"n":"WNAM - Skin"},{"t":6,"n":"BOD2 - Biped Body Template","c":[{"t":3,"n":"First Person Flags"},{"t":3,"n":"General Flags"},{"n":"Unused"},{"t":3,"n":"Armor Type"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"DATA - ","c":[{"t":10,"n":"Skill Boosts","c":[{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]}]},{"t":11,"n":"Unknown"},{"t":5,"n":"Male Height"},{"t":5,"n":"Female Height"},{"t":5,"n":"Male Weight"},{"t":5,"n":"Female Weight"},{"t":3,"n":"Flags"},{"t":5,"n":"Starting Health"},{"t":5,"n":"Starting Magicka"},{"t":5,"n":"Starting Stamina"},{"t":5,"n":"Base Carry Weight"},{"t":5,"n":"Base Mass"},{"t":5,"n":"Acceleration rate"},{"t":5,"n":"Deceleration rate"},{"t":3,"n":"Size"},{"t":3,"n":"Head Biped Object"},{"t":3,"n":"Hair Biped Object"},{"t":5,"n":"Injured Health Pct"},{"t":3,"n":"Shield Biped Object"},{"t":5,"n":"Health Regen"},{"t":5,"n":"Magicka Regen"},{"t":5,"n":"Stamina Regen"},{"t":5,"n":"Unarmed Damage"},{"t":5,"n":"Unarmed Reach"},{"t":3,"n":"Body Biped Object"},{"t":5,"n":"Aim Angle Tolerance"},{"t":5,"n":"Flight Radius"},{"t":5,"n":"Angular Acceleration Rate"},{"t":5,"n":"Angular Tolerance"},{"t":3,"n":"Flags 2"},{"t":6,"n":"Mount Data","c":[{"t":5,"n":"Offset X"},{"t":5,"n":"Offset Y"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"}]}]},{"n":"MNAM - Male Marker"},{"t":2,"n":"ANAM - Male Skeletal Model"},{"t":11,"n":"MODT - Texture Files Hashes"},{"n":"FNAM - Female Marker"},{"t":2,"n":"ANAM - Female Skeletal Model"},{"t":11,"n":"MODT - Texture Files Hashes"},{"n":"NAM2 - Marker NAM2 #1"},{"t":9,"n":"Movement Type Names","c":[{"t":2,"n":"MTNM - Name"}]},{"t":7,"n":"VTCK - Voices","c":[{"t":3,"n":"Voice #0 (Male)"},{"t":3,"n":"Voice #1 (Female)"}]},{"t":7,"n":"DNAM - Decapitate Armors","c":[{"t":3,"n":"Decapitate Armor #0 (Male)"},{"t":3,"n":"Decapitate Armor #1 (Female)"}]},{"t":7,"n":"HCLF - Default Hair Colors","c":[{"t":3,"n":"Default Hair Color #0 (Male)"},{"t":3,"n":"Default Hair Color #1 (Female)"}]},{"t":3,"n":"TINL - Total Number of Tints in List"},{"t":5,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"n":"UNAM - FaceGen - Face clamp"},{"t":3,"n":"ATKR - Attack Race"},{"t":10,"n":"Attacks","c":[{"t":6,"n":"Attack","c":[{"t":6,"n":"ATKD - Attack Data","c":[{"t":5,"n":"Damage Mult"},{"t":5,"n":"Attack Chance"},{"t":3,"n":"Attack Spell"},{"t":3,"n":"Attack Flags"},{"t":5,"n":"Attack Angle"},{"t":5,"n":"Strike Angle"},{"t":5,"n":"Stagger"},{"t":3,"n":"Attack Type"},{"t":5,"n":"Knockdown"},{"t":5,"n":"Recovery Time"},{"t":5,"n":"Stamina Mult"}]}]}]},{"t":6,"p":1,"n":"Body Data","c":[{"n":"NAM1 - Body Data Marker"},{"t":6,"n":"Male Body Data","c":[{"n":"MNAM - Male Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"}]}]}]},{"t":6,"p":1,"n":"Female Body Data","c":[{"n":"FNAM - Female Data Marker"},{"t":10,"s":1,"p":1,"n":"Parts","d":1,"c":[{"t":6,"p":1,"n":"Part","c":[{"t":3,"p":1,"n":"INDX - Index"}]}]}]}]},{"t":9,"n":"HNAM - Hairs","c":[{"t":3,"n":"Hair"}]},{"t":9,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eye"}]},{"t":3,"n":"GNAM - Body Part Data"},{"n":"NAM2 - Marker NAM2 #2"},{"n":"NAM3 - Marker NAM3 #3"},{"t":6,"n":"Male Behavior Graph","c":[{"n":"MNAM - Male Data Marker"}]},{"t":6,"n":"Female Behavior Graph","c":[{"n":"FNAM - Female Data Marker"}]},{"t":3,"n":"NAM4 - Material Type"},{"t":3,"n":"NAM5 - Impact Data Set"},{"t":3,"n":"NAM7 - Decapitation FX"},{"t":3,"n":"ONAM - Open Loot Sound"},{"t":3,"n":"LNAM - Close Loot Sound"},{"t":7,"n":"Biped Object Names","c":[{"t":2,"n":"NAME - Name"}]},{"t":10,"n":"Movement Types","c":[{"t":6,"n":"Movement Types","c":[{"t":3,"n":"MTYP - Movement Type"}]}]},{"t":3,"n":"VNAM - Equipment Flags"},{"t":9,"n":"Equip Slots","c":[{"t":3,"n":"QNAM - Equip Slot"}]},{"t":3,"n":"UNES - Unarmed Equip Slot"},{"t":7,"n":"Phoneme Target Names","c":[{"t":2,"n":"PHTN - Name"}]},{"t":6,"n":"FaceFX Phonemes","c":[{"t":6,"n":"IY","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]}]},{"t":3,"n":"WKMV - Base Movement Default - Walk"},{"t":3,"n":"RNMV - Base Movement Default - Run"},{"t":3,"n":"SWMV - Base Movement Default - Swim"},{"t":3,"n":"FLMV - Base Movement Default - Fly"},{"t":3,"n":"SNMV - Base Movement Default - Sneak"},{"t":3,"n":"SPMV - Base Movement Default - Sprint"},{"t":6,"n":"Head Data","c":[{"n":"NAM0 - Head Data Marker"},{"t":6,"n":"Male Head Data","c":[{"n":"MNAM - Male Data Marker"}]},{"t":6,"n":"Female Head Data","c":[{"n":"NAM0 - Head Data Marker"},{"n":"FNAM - Female Data Marker"}]}]},{"t":3,"n":"NAM8 - Morph race"},{"t":3,"n":"RNAM - Armor race"}]}]},"name":"Bash.Body-F","hash":"$8D501033","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.Body-M.json ================================================ {"records":"RACE","description":"Body-M tag from Wrye Bash.\r\n\r\nUsed when the mod modifies male body mesh\/texture definitions.","tree":{"records":[{"t":1,"p":1,"n":"RACE - Race","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":3,"n":"SPCT - Count"},{"t":9,"n":"Actor Effects","c":[{"t":3,"n":"SPLO - Actor Effect"}]},{"t":3,"n":"WNAM - Skin"},{"t":6,"n":"BOD2 - Biped Body Template","c":[{"t":3,"n":"First Person Flags"},{"t":3,"n":"General Flags"},{"n":"Unused"},{"t":3,"n":"Armor Type"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"DATA - ","c":[{"t":10,"n":"Skill Boosts","c":[{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]}]},{"t":11,"n":"Unknown"},{"t":5,"n":"Male Height"},{"t":5,"n":"Female Height"},{"t":5,"n":"Male Weight"},{"t":5,"n":"Female Weight"},{"t":3,"n":"Flags"},{"t":5,"n":"Starting Health"},{"t":5,"n":"Starting Magicka"},{"t":5,"n":"Starting Stamina"},{"t":5,"n":"Base Carry Weight"},{"t":5,"n":"Base Mass"},{"t":5,"n":"Acceleration rate"},{"t":5,"n":"Deceleration rate"},{"t":3,"n":"Size"},{"t":3,"n":"Head Biped Object"},{"t":3,"n":"Hair Biped Object"},{"t":5,"n":"Injured Health Pct"},{"t":3,"n":"Shield Biped Object"},{"t":5,"n":"Health Regen"},{"t":5,"n":"Magicka Regen"},{"t":5,"n":"Stamina Regen"},{"t":5,"n":"Unarmed Damage"},{"t":5,"n":"Unarmed Reach"},{"t":3,"n":"Body Biped Object"},{"t":5,"n":"Aim Angle Tolerance"},{"t":5,"n":"Flight Radius"},{"t":5,"n":"Angular Acceleration Rate"},{"t":5,"n":"Angular Tolerance"},{"t":3,"n":"Flags 2"},{"t":6,"n":"Mount Data","c":[{"t":5,"n":"Offset X"},{"t":5,"n":"Offset Y"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"}]}]},{"n":"MNAM - Male Marker"},{"t":2,"n":"ANAM - Male Skeletal Model"},{"t":11,"n":"MODT - Texture Files Hashes"},{"n":"FNAM - Female Marker"},{"t":2,"n":"ANAM - Female Skeletal Model"},{"t":11,"n":"MODT - Texture Files Hashes"},{"n":"NAM2 - Marker NAM2 #1"},{"t":9,"n":"Movement Type Names","c":[{"t":2,"n":"MTNM - Name"}]},{"t":7,"n":"VTCK - Voices","c":[{"t":3,"n":"Voice #0 (Male)"},{"t":3,"n":"Voice #1 (Female)"}]},{"t":7,"n":"DNAM - Decapitate Armors","c":[{"t":3,"n":"Decapitate Armor #0 (Male)"},{"t":3,"n":"Decapitate Armor #1 (Female)"}]},{"t":7,"n":"HCLF - Default Hair Colors","c":[{"t":3,"n":"Default Hair Color #0 (Male)"},{"t":3,"n":"Default Hair Color #1 (Female)"}]},{"t":3,"n":"TINL - Total Number of Tints in List"},{"t":5,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"n":"UNAM - FaceGen - Face clamp"},{"t":3,"n":"ATKR - Attack Race"},{"t":10,"n":"Attacks","c":[{"t":6,"n":"Attack","c":[{"t":6,"n":"ATKD - Attack Data","c":[{"t":5,"n":"Damage Mult"},{"t":5,"n":"Attack Chance"},{"t":3,"n":"Attack Spell"},{"t":3,"n":"Attack Flags"},{"t":5,"n":"Attack Angle"},{"t":5,"n":"Strike Angle"},{"t":5,"n":"Stagger"},{"t":3,"n":"Attack Type"},{"t":5,"n":"Knockdown"},{"t":5,"n":"Recovery Time"},{"t":5,"n":"Stamina Mult"}]}]}]},{"t":6,"p":1,"n":"Body Data","c":[{"n":"NAM1 - Body Data Marker"},{"t":6,"p":1,"n":"Male Body Data","c":[{"n":"MNAM - Male Data Marker"},{"t":10,"s":1,"p":1,"n":"Parts","d":1,"c":[{"t":6,"p":1,"n":"Part","c":[{"t":3,"p":1,"n":"INDX - Index"}]}]}]},{"t":6,"n":"Female Body Data","c":[{"n":"FNAM - Female Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"}]}]}]}]},{"t":9,"n":"HNAM - Hairs","c":[{"t":3,"n":"Hair"}]},{"t":9,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eye"}]},{"t":3,"n":"GNAM - Body Part Data"},{"n":"NAM2 - Marker NAM2 #2"},{"n":"NAM3 - Marker NAM3 #3"},{"t":6,"n":"Male Behavior Graph","c":[{"n":"MNAM - Male Data Marker"}]},{"t":6,"n":"Female Behavior Graph","c":[{"n":"FNAM - Female Data Marker"}]},{"t":3,"n":"NAM4 - Material Type"},{"t":3,"n":"NAM5 - Impact Data Set"},{"t":3,"n":"NAM7 - Decapitation FX"},{"t":3,"n":"ONAM - Open Loot Sound"},{"t":3,"n":"LNAM - Close Loot Sound"},{"t":7,"n":"Biped Object Names","c":[{"t":2,"n":"NAME - Name"}]},{"t":10,"n":"Movement Types","c":[{"t":6,"n":"Movement Types","c":[{"t":3,"n":"MTYP - Movement Type"}]}]},{"t":3,"n":"VNAM - Equipment Flags"},{"t":9,"n":"Equip Slots","c":[{"t":3,"n":"QNAM - Equip Slot"}]},{"t":3,"n":"UNES - Unarmed Equip Slot"},{"t":7,"n":"Phoneme Target Names","c":[{"t":2,"n":"PHTN - Name"}]},{"t":6,"n":"FaceFX Phonemes","c":[{"t":6,"n":"IY","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]}]},{"t":3,"n":"WKMV - Base Movement Default - Walk"},{"t":3,"n":"RNMV - Base Movement Default - Run"},{"t":3,"n":"SWMV - Base Movement Default - Swim"},{"t":3,"n":"FLMV - Base Movement Default - Fly"},{"t":3,"n":"SNMV - Base Movement Default - Sneak"},{"t":3,"n":"SPMV - Base Movement Default - Sprint"},{"t":6,"n":"Head Data","c":[{"n":"NAM0 - Head Data Marker"},{"t":6,"n":"Male Head Data","c":[{"n":"MNAM - Male Data Marker"}]},{"t":6,"n":"Female Head Data","c":[{"n":"NAM0 - Head Data Marker"},{"n":"FNAM - Female Data Marker"}]}]},{"t":3,"n":"NAM8 - Morph race"},{"t":3,"n":"RNAM - Armor race"}]}]},"name":"Bash.Body-M","hash":"$8D185280","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.Body-Size-F.json ================================================ {"records":"RACE","description":"Body-Size-F tag from Wrye Bash.\r\n\r\nUsed when the mod modifies female body weight\/height definitions.","tree":{"records":[{"t":1,"p":1,"n":"RACE - Race","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":3,"n":"SPCT - Count"},{"t":9,"n":"Actor Effects","c":[{"t":3,"n":"SPLO - Actor Effect"}]},{"t":3,"n":"WNAM - Skin"},{"t":6,"n":"BOD2 - Biped Body Template","c":[{"t":3,"n":"First Person Flags"},{"t":3,"n":"General Flags"},{"n":"Unused"},{"t":3,"n":"Armor Type"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"p":1,"n":"DATA - ","c":[{"t":10,"n":"Skill Boosts","c":[{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]}]},{"t":11,"n":"Unknown"},{"t":5,"n":"Male Height"},{"t":5,"p":1,"n":"Female Height"},{"t":5,"n":"Male Weight"},{"t":5,"p":1,"n":"Female Weight"},{"t":3,"n":"Flags"},{"t":5,"n":"Starting Health"},{"t":5,"n":"Starting Magicka"},{"t":5,"n":"Starting Stamina"},{"t":5,"n":"Base Carry Weight"},{"t":5,"n":"Base Mass"},{"t":5,"n":"Acceleration rate"},{"t":5,"n":"Deceleration rate"},{"t":3,"n":"Size"},{"t":3,"n":"Head Biped Object"},{"t":3,"n":"Hair Biped Object"},{"t":5,"n":"Injured Health Pct"},{"t":3,"n":"Shield Biped Object"},{"t":5,"n":"Health Regen"},{"t":5,"n":"Magicka Regen"},{"t":5,"n":"Stamina Regen"},{"t":5,"n":"Unarmed Damage"},{"t":5,"n":"Unarmed Reach"},{"t":3,"n":"Body Biped Object"},{"t":5,"n":"Aim Angle Tolerance"},{"t":5,"n":"Flight Radius"},{"t":5,"n":"Angular Acceleration Rate"},{"t":5,"n":"Angular Tolerance"},{"t":3,"n":"Flags 2"},{"t":6,"n":"Mount Data","c":[{"t":5,"n":"Offset X"},{"t":5,"n":"Offset Y"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"}]}]},{"n":"MNAM - Male Marker"},{"t":2,"n":"ANAM - Male Skeletal Model"},{"t":11,"n":"MODT - Texture Files Hashes"},{"n":"FNAM - Female Marker"},{"t":2,"n":"ANAM - Female Skeletal Model"},{"t":11,"n":"MODT - Texture Files Hashes"},{"n":"NAM2 - Marker NAM2 #1"},{"t":9,"n":"Movement Type Names","c":[{"t":2,"n":"MTNM - Name"}]},{"t":7,"n":"VTCK - Voices","c":[{"t":3,"n":"Voice #0 (Male)"},{"t":3,"n":"Voice #1 (Female)"}]},{"t":7,"n":"DNAM - Decapitate Armors","c":[{"t":3,"n":"Decapitate Armor #0 (Male)"},{"t":3,"n":"Decapitate Armor #1 (Female)"}]},{"t":7,"n":"HCLF - Default Hair Colors","c":[{"t":3,"n":"Default Hair Color #0 (Male)"},{"t":3,"n":"Default Hair Color #1 (Female)"}]},{"t":3,"n":"TINL - Total Number of Tints in List"},{"t":5,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"n":"UNAM - FaceGen - Face clamp"},{"t":3,"n":"ATKR - Attack Race"},{"t":10,"n":"Attacks","c":[{"t":6,"n":"Attack","c":[{"t":6,"n":"ATKD - Attack Data","c":[{"t":5,"n":"Damage Mult"},{"t":5,"n":"Attack Chance"},{"t":3,"n":"Attack Spell"},{"t":3,"n":"Attack Flags"},{"t":5,"n":"Attack Angle"},{"t":5,"n":"Strike Angle"},{"t":5,"n":"Stagger"},{"t":3,"n":"Attack Type"},{"t":5,"n":"Knockdown"},{"t":5,"n":"Recovery Time"},{"t":5,"n":"Stamina Mult"}]}]}]},{"t":6,"n":"Body Data","c":[{"n":"NAM1 - Body Data Marker"},{"t":6,"n":"Male Body Data","c":[{"n":"MNAM - Male Data Marker"},{"t":10,"n":"Parts","d":1,"c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"}]}]}]},{"t":6,"n":"Female Body Data","c":[{"n":"FNAM - Female Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"}]}]}]}]},{"t":9,"n":"HNAM - Hairs","c":[{"t":3,"n":"Hair"}]},{"t":9,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eye"}]},{"t":3,"n":"GNAM - Body Part Data"},{"n":"NAM2 - Marker NAM2 #2"},{"n":"NAM3 - Marker NAM3 #3"},{"t":6,"n":"Male Behavior Graph","c":[{"n":"MNAM - Male Data Marker"}]},{"t":6,"n":"Female Behavior Graph","c":[{"n":"FNAM - Female Data Marker"}]},{"t":3,"n":"NAM4 - Material Type"},{"t":3,"n":"NAM5 - Impact Data Set"},{"t":3,"n":"NAM7 - Decapitation FX"},{"t":3,"n":"ONAM - Open Loot Sound"},{"t":3,"n":"LNAM - Close Loot Sound"},{"t":7,"n":"Biped Object Names","c":[{"t":2,"n":"NAME - Name"}]},{"t":10,"n":"Movement Types","c":[{"t":6,"n":"Movement Types","c":[{"t":3,"n":"MTYP - Movement Type"}]}]},{"t":3,"n":"VNAM - Equipment Flags"},{"t":9,"n":"Equip Slots","c":[{"t":3,"n":"QNAM - Equip Slot"}]},{"t":3,"n":"UNES - Unarmed Equip Slot"},{"t":7,"n":"Phoneme Target Names","c":[{"t":2,"n":"PHTN - Name"}]},{"t":6,"n":"FaceFX Phonemes","c":[{"t":6,"n":"IY","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]}]},{"t":3,"n":"WKMV - Base Movement Default - Walk"},{"t":3,"n":"RNMV - Base Movement Default - Run"},{"t":3,"n":"SWMV - Base Movement Default - Swim"},{"t":3,"n":"FLMV - Base Movement Default - Fly"},{"t":3,"n":"SNMV - Base Movement Default - Sneak"},{"t":3,"n":"SPMV - Base Movement Default - Sprint"},{"t":6,"n":"Head Data","c":[{"n":"NAM0 - Head Data Marker"},{"t":6,"n":"Male Head Data","c":[{"n":"MNAM - Male Data Marker"}]},{"t":6,"n":"Female Head Data","c":[{"n":"NAM0 - Head Data Marker"},{"n":"FNAM - Female Data Marker"}]}]},{"t":3,"n":"NAM8 - Morph race"},{"t":3,"n":"RNAM - Armor race"}]}]},"name":"Bash.Body-Size-F","hash":"$3ED676FA","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.Body-Size-M.json ================================================ {"records":"RACE","description":"Body-Size-M tag from Wrye Bash.\r\n\r\nUsed when the mod modifies male body weight\/height definitions.","tree":{"records":[{"t":1,"p":1,"n":"RACE - Race","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":3,"n":"SPCT - Count"},{"t":9,"n":"Actor Effects","c":[{"t":3,"n":"SPLO - Actor Effect"}]},{"t":3,"n":"WNAM - Skin"},{"t":6,"n":"BOD2 - Biped Body Template","c":[{"t":3,"n":"First Person Flags"},{"t":3,"n":"General Flags"},{"n":"Unused"},{"t":3,"n":"Armor Type"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"p":1,"n":"DATA - ","c":[{"t":10,"n":"Skill Boosts","c":[{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]}]},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"Male Height"},{"t":5,"n":"Female Height"},{"t":5,"p":1,"n":"Male Weight"},{"t":5,"n":"Female Weight"},{"t":3,"n":"Flags"},{"t":5,"n":"Starting Health"},{"t":5,"n":"Starting Magicka"},{"t":5,"n":"Starting Stamina"},{"t":5,"n":"Base Carry Weight"},{"t":5,"n":"Base Mass"},{"t":5,"n":"Acceleration rate"},{"t":5,"n":"Deceleration rate"},{"t":3,"n":"Size"},{"t":3,"n":"Head Biped Object"},{"t":3,"n":"Hair Biped Object"},{"t":5,"n":"Injured Health Pct"},{"t":3,"n":"Shield Biped Object"},{"t":5,"n":"Health Regen"},{"t":5,"n":"Magicka Regen"},{"t":5,"n":"Stamina Regen"},{"t":5,"n":"Unarmed Damage"},{"t":5,"n":"Unarmed Reach"},{"t":3,"n":"Body Biped Object"},{"t":5,"n":"Aim Angle Tolerance"},{"t":5,"n":"Flight Radius"},{"t":5,"n":"Angular Acceleration Rate"},{"t":5,"n":"Angular Tolerance"},{"t":3,"n":"Flags 2"},{"t":6,"n":"Mount Data","c":[{"t":5,"n":"Offset X"},{"t":5,"n":"Offset Y"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"}]}]},{"n":"MNAM - Male Marker"},{"t":2,"n":"ANAM - Male Skeletal Model"},{"t":11,"n":"MODT - Texture Files Hashes"},{"n":"FNAM - Female Marker"},{"t":2,"n":"ANAM - Female Skeletal Model"},{"t":11,"n":"MODT - Texture Files Hashes"},{"n":"NAM2 - Marker NAM2 #1"},{"t":9,"n":"Movement Type Names","c":[{"t":2,"n":"MTNM - Name"}]},{"t":7,"n":"VTCK - Voices","c":[{"t":3,"n":"Voice #0 (Male)"},{"t":3,"n":"Voice #1 (Female)"}]},{"t":7,"n":"DNAM - Decapitate Armors","c":[{"t":3,"n":"Decapitate Armor #0 (Male)"},{"t":3,"n":"Decapitate Armor #1 (Female)"}]},{"t":7,"n":"HCLF - Default Hair Colors","c":[{"t":3,"n":"Default Hair Color #0 (Male)"},{"t":3,"n":"Default Hair Color #1 (Female)"}]},{"t":3,"n":"TINL - Total Number of Tints in List"},{"t":5,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"n":"UNAM - FaceGen - Face clamp"},{"t":3,"n":"ATKR - Attack Race"},{"t":10,"n":"Attacks","c":[{"t":6,"n":"Attack","c":[{"t":6,"n":"ATKD - Attack Data","c":[{"t":5,"n":"Damage Mult"},{"t":5,"n":"Attack Chance"},{"t":3,"n":"Attack Spell"},{"t":3,"n":"Attack Flags"},{"t":5,"n":"Attack Angle"},{"t":5,"n":"Strike Angle"},{"t":5,"n":"Stagger"},{"t":3,"n":"Attack Type"},{"t":5,"n":"Knockdown"},{"t":5,"n":"Recovery Time"},{"t":5,"n":"Stamina Mult"}]}]}]},{"t":6,"n":"Body Data","c":[{"n":"NAM1 - Body Data Marker"},{"t":6,"n":"Male Body Data","c":[{"n":"MNAM - Male Data Marker"},{"t":10,"n":"Parts","d":1,"c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"}]}]}]},{"t":6,"n":"Female Body Data","c":[{"n":"FNAM - Female Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"}]}]}]}]},{"t":9,"n":"HNAM - Hairs","c":[{"t":3,"n":"Hair"}]},{"t":9,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eye"}]},{"t":3,"n":"GNAM - Body Part Data"},{"n":"NAM2 - Marker NAM2 #2"},{"n":"NAM3 - Marker NAM3 #3"},{"t":6,"n":"Male Behavior Graph","c":[{"n":"MNAM - Male Data Marker"}]},{"t":6,"n":"Female Behavior Graph","c":[{"n":"FNAM - Female Data Marker"}]},{"t":3,"n":"NAM4 - Material Type"},{"t":3,"n":"NAM5 - Impact Data Set"},{"t":3,"n":"NAM7 - Decapitation FX"},{"t":3,"n":"ONAM - Open Loot Sound"},{"t":3,"n":"LNAM - Close Loot Sound"},{"t":7,"n":"Biped Object Names","c":[{"t":2,"n":"NAME - Name"}]},{"t":10,"n":"Movement Types","c":[{"t":6,"n":"Movement Types","c":[{"t":3,"n":"MTYP - Movement Type"}]}]},{"t":3,"n":"VNAM - Equipment Flags"},{"t":9,"n":"Equip Slots","c":[{"t":3,"n":"QNAM - Equip Slot"}]},{"t":3,"n":"UNES - Unarmed Equip Slot"},{"t":7,"n":"Phoneme Target Names","c":[{"t":2,"n":"PHTN - Name"}]},{"t":6,"n":"FaceFX Phonemes","c":[{"t":6,"n":"IY","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]}]},{"t":3,"n":"WKMV - Base Movement Default - Walk"},{"t":3,"n":"RNMV - Base Movement Default - Run"},{"t":3,"n":"SWMV - Base Movement Default - Swim"},{"t":3,"n":"FLMV - Base Movement Default - Fly"},{"t":3,"n":"SNMV - Base Movement Default - Sneak"},{"t":3,"n":"SPMV - Base Movement Default - Sprint"},{"t":6,"n":"Head Data","c":[{"n":"NAM0 - Head Data Marker"},{"t":6,"n":"Male Head Data","c":[{"n":"MNAM - Male Data Marker"}]},{"t":6,"n":"Female Head Data","c":[{"n":"NAM0 - Head Data Marker"},{"n":"FNAM - Female Data Marker"}]}]},{"t":3,"n":"NAM8 - Morph race"},{"t":3,"n":"RNAM - Armor race"}]}]},"name":"Bash.Body-Size-M","hash":"$37B99D6E","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.C.Acoustic.json ================================================ {"records":"CELL","description":"","tree":{"records":[{"t":1,"p":1,"n":"CELL - Cell","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":3,"n":"DATA - Flags","c":[{"t":4,"n":"Is Interior Cell"}]},{"t":6,"n":"XCLC - Grid","c":[{"t":3,"n":"X"},{"t":3,"n":"Y"},{"t":3,"n":"Force Hide Land"}]},{"t":6,"n":"XCLL - Lighting","c":[{"t":6,"n":"Ambient Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Directional Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Fog Color Near","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"Fog Near"},{"t":5,"n":"Fog Far"},{"t":3,"n":"Directional Rotation XY"},{"t":3,"n":"Directional Rotation Z"},{"t":5,"n":"Directional Fade"},{"t":5,"n":"Fog Clip Distance"},{"t":5,"n":"Fog Power"},{"t":6,"n":"Ambient Colors","c":[{"t":8,"n":"Colors","c":[{"t":6,"n":"Color #0 (X+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (X-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Y+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Y-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #4 (Z+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #5 (Z-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"Specular","c":[{"t":6,"n":"Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"Fresnel Power"}]}]},{"t":6,"n":"Fog Color Far","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"Fog Max"},{"t":5,"n":"Light Fade Begin"},{"t":5,"n":"Light Fade End"},{"t":3,"n":"Inherits"}]},{"t":11,"n":"TVDT - Unknown"},{"t":11,"n":"MHDT - Max Height Data"},{"t":3,"n":"LTMP - Lighting Template"},{"t":11,"n":"LNAM - Unknown"},{"t":5,"n":"XCLW - Water Height"},{"t":2,"n":"XNAM - Water Noise Texture"},{"t":9,"n":"XCLR - Regions","c":[{"t":3,"n":"Region"}]},{"t":3,"n":"XLCN - Location"},{"t":11,"n":"XWCN - Unknown"},{"t":11,"n":"XWCS - Unknown"},{"t":6,"n":"XWCU - Water Velocity","c":[{"t":5,"n":"X Offset"},{"t":5,"n":"Y Offset"},{"t":5,"n":"Z Offset"},{"t":11,"n":"Unknown"},{"t":5,"n":"X Angle"},{"t":5,"n":"Y Angle"},{"t":5,"n":"Z Angle"},{"t":11,"n":"Unknown"}]},{"t":3,"n":"XCWT - Water"},{"t":6,"n":"Ownership","c":[{"t":3,"n":"XOWN - Owner"}]},{"t":3,"n":"XILL - Lock List"},{"t":2,"n":"XWEM - Water Environment Map"},{"t":3,"n":"XCCM - Sky\/Weather from Region"},{"t":3,"p":1,"n":"XCAS - Acoustic Space"},{"t":3,"n":"XEZN - Encounter Zone"},{"t":3,"n":"XCMO - Music Type"},{"t":3,"n":"XCIM - Image Space"}]}]},"name":"Bash.C.Acoustic","hash":"$65B5135E","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.C.Climate.json ================================================ {"records":"CELL","description":"C.Climate tag from Wrye Bash.\r\n\r\nUsed when the mod modifies cell climates.","tree":{"records":[{"t":1,"p":1,"n":"CELL - Cell","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":3,"n":"DATA - Flags","c":[{"t":4,"n":"Is Interior Cell"}]},{"t":6,"n":"XCLC - Grid","c":[{"t":3,"n":"X"},{"t":3,"n":"Y"},{"t":3,"n":"Force Hide Land"}]},{"t":6,"n":"XCLL - Lighting","c":[{"t":6,"n":"Ambient Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Directional Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Fog Color Near","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"Fog Near"},{"t":5,"n":"Fog Far"},{"t":3,"n":"Directional Rotation XY"},{"t":3,"n":"Directional Rotation Z"},{"t":5,"n":"Directional Fade"},{"t":5,"n":"Fog Clip Distance"},{"t":5,"n":"Fog Power"},{"t":6,"n":"Ambient Colors","c":[{"t":8,"n":"Colors","c":[{"t":6,"n":"Color #0 (X+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (X-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Y+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Y-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #4 (Z+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #5 (Z-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"Specular","c":[{"t":6,"n":"Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"Fresnel Power"}]}]},{"t":6,"n":"Fog Color Far","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"Fog Max"},{"t":5,"n":"Light Fade Begin"},{"t":5,"n":"Light Fade End"},{"t":3,"n":"Inherits"}]},{"t":11,"n":"TVDT - Unknown"},{"t":11,"n":"MHDT - Max Height Data"},{"t":3,"n":"LTMP - Lighting Template"},{"t":11,"n":"LNAM - Unknown"},{"t":5,"n":"XCLW - Water Height"},{"t":2,"n":"XNAM - Water Noise Texture"},{"t":9,"n":"XCLR - Regions","c":[{"t":3,"n":"Region"}]},{"t":3,"n":"XLCN - Location"},{"t":11,"n":"XWCN - Unknown"},{"t":11,"n":"XWCS - Unknown"},{"t":6,"n":"XWCU - Water Velocity","c":[{"t":5,"n":"X Offset"},{"t":5,"n":"Y Offset"},{"t":5,"n":"Z Offset"},{"t":11,"n":"Unknown"},{"t":5,"n":"X Angle"},{"t":5,"n":"Y Angle"},{"t":5,"n":"Z Angle"},{"t":11,"n":"Unknown"}]},{"t":3,"n":"XCWT - Water"},{"t":6,"n":"Ownership","c":[{"t":3,"n":"XOWN - Owner"}]},{"t":3,"n":"XILL - Lock List"},{"t":2,"n":"XWEM - Water Environment Map"},{"t":3,"p":1,"n":"XCCM - Sky\/Weather from Region"},{"t":3,"n":"XCAS - Acoustic Space"},{"t":3,"n":"XEZN - Encounter Zone"},{"t":3,"n":"XCMO - Music Type"},{"t":3,"n":"XCIM - Image Space"}]}]},"name":"Bash.C.Climate","hash":"$595B86E0","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.C.Encounter.json ================================================ {"records":"CELL","description":"","tree":{"records":[{"t":1,"p":1,"n":"CELL - Cell","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":3,"n":"DATA - Flags","c":[{"t":4,"n":"Is Interior Cell"}]},{"t":6,"n":"XCLC - Grid","c":[{"t":3,"n":"X"},{"t":3,"n":"Y"},{"t":3,"n":"Force Hide Land"}]},{"t":6,"n":"XCLL - Lighting","c":[{"t":6,"n":"Ambient Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Directional Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Fog Color Near","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"Fog Near"},{"t":5,"n":"Fog Far"},{"t":3,"n":"Directional Rotation XY"},{"t":3,"n":"Directional Rotation Z"},{"t":5,"n":"Directional Fade"},{"t":5,"n":"Fog Clip Distance"},{"t":5,"n":"Fog Power"},{"t":6,"n":"Ambient Colors","c":[{"t":8,"n":"Colors","c":[{"t":6,"n":"Color #0 (X+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (X-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Y+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Y-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #4 (Z+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #5 (Z-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"Specular","c":[{"t":6,"n":"Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"Fresnel Power"}]}]},{"t":6,"n":"Fog Color Far","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"Fog Max"},{"t":5,"n":"Light Fade Begin"},{"t":5,"n":"Light Fade End"},{"t":3,"n":"Inherits"}]},{"t":11,"n":"TVDT - Unknown"},{"t":11,"n":"MHDT - Max Height Data"},{"t":3,"n":"LTMP - Lighting Template"},{"t":11,"n":"LNAM - Unknown"},{"t":5,"n":"XCLW - Water Height"},{"t":2,"n":"XNAM - Water Noise Texture"},{"t":9,"n":"XCLR - Regions","c":[{"t":3,"n":"Region"}]},{"t":3,"n":"XLCN - Location"},{"t":11,"n":"XWCN - Unknown"},{"t":11,"n":"XWCS - Unknown"},{"t":6,"n":"XWCU - Water Velocity","c":[{"t":5,"n":"X Offset"},{"t":5,"n":"Y Offset"},{"t":5,"n":"Z Offset"},{"t":11,"n":"Unknown"},{"t":5,"n":"X Angle"},{"t":5,"n":"Y Angle"},{"t":5,"n":"Z Angle"},{"t":11,"n":"Unknown"}]},{"t":3,"n":"XCWT - Water"},{"t":6,"n":"Ownership","c":[{"t":3,"n":"XOWN - Owner"}]},{"t":3,"n":"XILL - Lock List"},{"t":2,"n":"XWEM - Water Environment Map"},{"t":3,"n":"XCCM - Sky\/Weather from Region"},{"t":3,"n":"XCAS - Acoustic Space"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":3,"n":"XCMO - Music Type"},{"t":3,"n":"XCIM - Image Space"}]}]},"name":"Bash.C.Encounter","hash":"$C39BCB8D","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.C.ImageSpace.json ================================================ {"records":"CELL","description":"","tree":{"records":[{"t":1,"p":1,"n":"CELL - Cell","d":1,"c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":3,"n":"DATA - Flags","c":[{"t":4,"n":"Is Interior Cell"}]},{"t":6,"n":"XCLC - Grid","c":[{"t":3,"n":"X"},{"t":3,"n":"Y"},{"t":3,"n":"Force Hide Land"}]},{"t":6,"n":"XCLL - Lighting","c":[{"t":6,"n":"Ambient Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Directional Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Fog Color Near","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"Fog Near"},{"t":5,"n":"Fog Far"},{"t":3,"n":"Directional Rotation XY"},{"t":3,"n":"Directional Rotation Z"},{"t":5,"n":"Directional Fade"},{"t":5,"n":"Fog Clip Distance"},{"t":5,"n":"Fog Power"},{"t":6,"n":"Ambient Colors","c":[{"t":8,"n":"Colors","c":[{"t":6,"n":"Color #0 (X+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (X-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Y+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Y-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #4 (Z+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #5 (Z-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"Specular","c":[{"t":6,"n":"Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"Fresnel Power"}]}]},{"t":6,"n":"Fog Color Far","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"Fog Max"},{"t":5,"n":"Light Fade Begin"},{"t":5,"n":"Light Fade End"},{"t":3,"n":"Inherits"}]},{"t":11,"n":"TVDT - Unknown"},{"t":11,"n":"MHDT - Max Height Data"},{"t":3,"n":"LTMP - Lighting Template"},{"t":11,"n":"LNAM - Unknown"},{"t":5,"n":"XCLW - Water Height"},{"t":2,"n":"XNAM - Water Noise Texture"},{"t":9,"n":"XCLR - Regions","d":1,"c":[{"t":3,"n":"Region"}]},{"t":3,"n":"XLCN - Location"},{"t":11,"n":"XWCN - Unknown"},{"t":11,"n":"XWCS - Unknown"},{"t":6,"n":"XWCU - Water Velocity","c":[{"t":5,"n":"X Offset"},{"t":5,"n":"Y Offset"},{"t":5,"n":"Z Offset"},{"t":11,"n":"Unknown"},{"t":5,"n":"X Angle"},{"t":5,"n":"Y Angle"},{"t":5,"n":"Z Angle"},{"t":11,"n":"Unknown"}]},{"t":3,"n":"XCWT - Water"},{"t":6,"n":"Ownership","c":[{"t":3,"n":"XOWN - Owner"}]},{"t":3,"n":"XILL - Lock List"},{"t":2,"n":"XWEM - Water Environment Map"},{"t":3,"n":"XCCM - Sky\/Weather from Region"},{"t":3,"n":"XCAS - Acoustic Space"},{"t":3,"n":"XEZN - Encounter Zone"},{"t":3,"n":"XCMO - Music Type"},{"t":3,"p":1,"n":"XCIM - Image Space"}]}]},"name":"Bash.C.ImageSpace","hash":"$B06BA239","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.C.Light.json ================================================ {"records":"CELL","description":"C.Light tag from Wrye Bash.\r\n\r\nUsed when the mod modifies cell lighting or fog.","tree":{"records":[{"t":1,"p":1,"n":"CELL - Cell","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":3,"n":"DATA - Flags","c":[{"t":4,"n":"Is Interior Cell"}]},{"t":6,"n":"XCLC - Grid","c":[{"t":3,"n":"X"},{"t":3,"n":"Y"},{"t":3,"n":"Force Hide Land"}]},{"t":6,"p":1,"n":"XCLL - Lighting","c":[{"t":6,"s":1,"p":1,"n":"Ambient Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":6,"s":1,"p":1,"n":"Directional Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":6,"s":1,"p":1,"n":"Fog Color Near","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":5,"n":"Fog Near"},{"t":5,"n":"Fog Far"},{"t":3,"n":"Directional Rotation XY"},{"t":3,"n":"Directional Rotation Z"},{"t":5,"n":"Directional Fade"},{"t":5,"n":"Fog Clip Distance"},{"t":5,"n":"Fog Power"},{"t":6,"s":1,"p":1,"n":"Ambient Colors","c":[{"t":8,"p":1,"n":"Colors","c":[{"t":6,"p":1,"n":"Color #0 (X+)","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":6,"p":1,"n":"Color #1 (X-)","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":6,"p":1,"n":"Color #2 (Y+)","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":6,"p":1,"n":"Color #3 (Y-)","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":6,"p":1,"n":"Color #4 (Z+)","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":6,"p":1,"n":"Color #5 (Z-)","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]}]},{"t":6,"p":1,"n":"Specular","c":[{"t":6,"p":1,"n":"Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":5,"p":1,"n":"Fresnel Power"}]}]},{"t":6,"s":1,"p":1,"n":"Fog Color Far","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":5,"n":"Fog Max"},{"t":5,"n":"Light Fade Begin"},{"t":5,"n":"Light Fade End"},{"t":3,"n":"Inherits"}]},{"t":11,"n":"TVDT - Unknown"},{"t":11,"n":"MHDT - Max Height Data"},{"t":3,"n":"LTMP - Lighting Template"},{"t":11,"n":"LNAM - Unknown"},{"t":5,"n":"XCLW - Water Height"},{"t":2,"n":"XNAM - Water Noise Texture"},{"t":9,"n":"XCLR - Regions","c":[{"t":3,"n":"Region"}]},{"t":3,"n":"XLCN - Location"},{"t":11,"n":"XWCN - Unknown"},{"t":11,"n":"XWCS - Unknown"},{"t":6,"n":"XWCU - Water Velocity","c":[{"t":5,"n":"X Offset"},{"t":5,"n":"Y Offset"},{"t":5,"n":"Z Offset"},{"t":11,"n":"Unknown"},{"t":5,"n":"X Angle"},{"t":5,"n":"Y Angle"},{"t":5,"n":"Z Angle"},{"t":11,"n":"Unknown"}]},{"t":3,"n":"XCWT - Water"},{"t":6,"n":"Ownership","c":[{"t":3,"n":"XOWN - Owner"}]},{"t":3,"n":"XILL - Lock List"},{"t":2,"n":"XWEM - Water Environment Map"},{"t":3,"n":"XCCM - Sky\/Weather from Region"},{"t":3,"n":"XCAS - Acoustic Space"},{"t":3,"n":"XEZN - Encounter Zone"},{"t":3,"n":"XCMO - Music Type"},{"t":3,"n":"XCIM - Image Space"}]}]},"name":"Bash.C.Light","hash":"$4E94E72C","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.C.Location.json ================================================ {"records":"CELL","description":"","tree":{"records":[{"t":1,"p":1,"n":"CELL - Cell","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":3,"n":"DATA - Flags","c":[{"t":4,"n":"Is Interior Cell"}]},{"t":6,"n":"XCLC - Grid","c":[{"t":3,"n":"X"},{"t":3,"n":"Y"},{"t":3,"n":"Force Hide Land"}]},{"t":6,"n":"XCLL - Lighting","c":[{"t":6,"n":"Ambient Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Directional Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Fog Color Near","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"Fog Near"},{"t":5,"n":"Fog Far"},{"t":3,"n":"Directional Rotation XY"},{"t":3,"n":"Directional Rotation Z"},{"t":5,"n":"Directional Fade"},{"t":5,"n":"Fog Clip Distance"},{"t":5,"n":"Fog Power"},{"t":6,"n":"Ambient Colors","c":[{"t":8,"n":"Colors","c":[{"t":6,"n":"Color #0 (X+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (X-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Y+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Y-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #4 (Z+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #5 (Z-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"Specular","c":[{"t":6,"n":"Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"Fresnel Power"}]}]},{"t":6,"n":"Fog Color Far","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"Fog Max"},{"t":5,"n":"Light Fade Begin"},{"t":5,"n":"Light Fade End"},{"t":3,"n":"Inherits"}]},{"t":11,"n":"TVDT - Unknown"},{"t":11,"n":"MHDT - Max Height Data"},{"t":3,"n":"LTMP - Lighting Template"},{"t":11,"n":"LNAM - Unknown"},{"t":5,"n":"XCLW - Water Height"},{"t":2,"n":"XNAM - Water Noise Texture"},{"t":9,"n":"XCLR - Regions","c":[{"t":3,"n":"Region"}]},{"t":3,"p":1,"n":"XLCN - Location"},{"t":11,"n":"XWCN - Unknown"},{"t":11,"n":"XWCS - Unknown"},{"t":6,"n":"XWCU - Water Velocity","c":[{"t":5,"n":"X Offset"},{"t":5,"n":"Y Offset"},{"t":5,"n":"Z Offset"},{"t":11,"n":"Unknown"},{"t":5,"n":"X Angle"},{"t":5,"n":"Y Angle"},{"t":5,"n":"Z Angle"},{"t":11,"n":"Unknown"}]},{"t":3,"n":"XCWT - Water"},{"t":6,"n":"Ownership","c":[{"t":3,"n":"XOWN - Owner"}]},{"t":3,"n":"XILL - Lock List"},{"t":2,"n":"XWEM - Water Environment Map"},{"t":3,"n":"XCCM - Sky\/Weather from Region"},{"t":3,"n":"XCAS - Acoustic Space"},{"t":3,"n":"XEZN - Encounter Zone"},{"t":3,"n":"XCMO - Music Type"},{"t":3,"n":"XCIM - Image Space"}]}]},"name":"Bash.C.Location","hash":"$3E1F8F01","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.C.Music.json ================================================ {"records":"CELL","description":"C.Music tag from Wrye Bash.\r\n\r\nUsed when the mod modifies cell music type.","tree":{"records":[{"t":1,"p":1,"n":"CELL - Cell","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":3,"n":"DATA - Flags","c":[{"t":4,"n":"Is Interior Cell"}]},{"t":6,"n":"XCLC - Grid","c":[{"t":3,"n":"X"},{"t":3,"n":"Y"},{"t":3,"n":"Force Hide Land"}]},{"t":6,"n":"XCLL - Lighting","c":[{"t":6,"n":"Ambient Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Directional Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Fog Color Near","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"Fog Near"},{"t":5,"n":"Fog Far"},{"t":3,"n":"Directional Rotation XY"},{"t":3,"n":"Directional Rotation Z"},{"t":5,"n":"Directional Fade"},{"t":5,"n":"Fog Clip Distance"},{"t":5,"n":"Fog Power"},{"t":6,"n":"Ambient Colors","c":[{"t":8,"n":"Colors","c":[{"t":6,"n":"Color #0 (X+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (X-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Y+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Y-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #4 (Z+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #5 (Z-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"Specular","c":[{"t":6,"n":"Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"Fresnel Power"}]}]},{"t":6,"n":"Fog Color Far","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"Fog Max"},{"t":5,"n":"Light Fade Begin"},{"t":5,"n":"Light Fade End"},{"t":3,"n":"Inherits"}]},{"t":11,"n":"TVDT - Unknown"},{"t":11,"n":"MHDT - Max Height Data"},{"t":3,"n":"LTMP - Lighting Template"},{"t":11,"n":"LNAM - Unknown"},{"t":5,"n":"XCLW - Water Height"},{"t":2,"n":"XNAM - Water Noise Texture"},{"t":9,"n":"XCLR - Regions","c":[{"t":3,"n":"Region"}]},{"t":3,"n":"XLCN - Location"},{"t":11,"n":"XWCN - Unknown"},{"t":11,"n":"XWCS - Unknown"},{"t":6,"n":"XWCU - Water Velocity","c":[{"t":5,"n":"X Offset"},{"t":5,"n":"Y Offset"},{"t":5,"n":"Z Offset"},{"t":11,"n":"Unknown"},{"t":5,"n":"X Angle"},{"t":5,"n":"Y Angle"},{"t":5,"n":"Z Angle"},{"t":11,"n":"Unknown"}]},{"t":3,"n":"XCWT - Water"},{"t":6,"n":"Ownership","c":[{"t":3,"n":"XOWN - Owner"}]},{"t":3,"n":"XILL - Lock List"},{"t":2,"n":"XWEM - Water Environment Map"},{"t":3,"n":"XCCM - Sky\/Weather from Region"},{"t":3,"n":"XCAS - Acoustic Space"},{"t":3,"n":"XEZN - Encounter Zone"},{"t":3,"p":1,"n":"XCMO - Music Type"},{"t":3,"n":"XCIM - Image Space"}]}]},"name":"Bash.C.Music","hash":"$A62AFF38","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.C.Name.json ================================================ {"records":"CELL","description":"C.Name tag from Wrye Bash.\r\n\r\nUsed when the mod modifies cell names.","tree":{"records":[{"t":1,"p":1,"n":"CELL - Cell","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"DATA - Flags","c":[{"t":4,"n":"Is Interior Cell"}]},{"t":6,"n":"XCLC - Grid","c":[{"t":3,"n":"X"},{"t":3,"n":"Y"},{"t":3,"n":"Force Hide Land"}]},{"t":6,"n":"XCLL - Lighting","c":[{"t":6,"n":"Ambient Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Directional Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Fog Color Near","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"Fog Near"},{"t":5,"n":"Fog Far"},{"t":3,"n":"Directional Rotation XY"},{"t":3,"n":"Directional Rotation Z"},{"t":5,"n":"Directional Fade"},{"t":5,"n":"Fog Clip Distance"},{"t":5,"n":"Fog Power"},{"t":6,"n":"Ambient Colors","c":[{"t":8,"n":"Colors","c":[{"t":6,"n":"Color #0 (X+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (X-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Y+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Y-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #4 (Z+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #5 (Z-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"Specular","c":[{"t":6,"n":"Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"Fresnel Power"}]}]},{"t":6,"n":"Fog Color Far","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"Fog Max"},{"t":5,"n":"Light Fade Begin"},{"t":5,"n":"Light Fade End"},{"t":3,"n":"Inherits"}]},{"t":11,"n":"TVDT - Unknown"},{"t":11,"n":"MHDT - Max Height Data"},{"t":3,"n":"LTMP - Lighting Template"},{"t":11,"n":"LNAM - Unknown"},{"t":5,"n":"XCLW - Water Height"},{"t":2,"n":"XNAM - Water Noise Texture"},{"t":9,"n":"XCLR - Regions","c":[{"t":3,"n":"Region"}]},{"t":3,"n":"XLCN - Location"},{"t":11,"n":"XWCN - Unknown"},{"t":11,"n":"XWCS - Unknown"},{"t":6,"n":"XWCU - Water Velocity","c":[{"t":5,"n":"X Offset"},{"t":5,"n":"Y Offset"},{"t":5,"n":"Z Offset"},{"t":11,"n":"Unknown"},{"t":5,"n":"X Angle"},{"t":5,"n":"Y Angle"},{"t":5,"n":"Z Angle"},{"t":11,"n":"Unknown"}]},{"t":3,"n":"XCWT - Water"},{"t":6,"n":"Ownership","c":[{"t":3,"n":"XOWN - Owner"}]},{"t":3,"n":"XILL - Lock List"},{"t":2,"n":"XWEM - Water Environment Map"},{"t":3,"n":"XCCM - Sky\/Weather from Region"},{"t":3,"n":"XCAS - Acoustic Space"},{"t":3,"n":"XEZN - Encounter Zone"},{"t":3,"n":"XCMO - Music Type"},{"t":3,"n":"XCIM - Image Space"}]}]},"name":"Bash.C.Name","hash":"$F1A2C84F","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.C.Owner.json ================================================ {"records":"CELL","description":"C.Owner tag from Wrye Bash.\r\n\r\nUsed when the mod modifies cell ownership.","tree":{"records":[{"t":1,"p":1,"n":"CELL - Cell","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":3,"n":"DATA - Flags","c":[{"t":4,"n":"Is Interior Cell"}]},{"t":6,"n":"XCLC - Grid","c":[{"t":3,"n":"X"},{"t":3,"n":"Y"},{"t":3,"n":"Force Hide Land"}]},{"t":6,"n":"XCLL - Lighting","c":[{"t":6,"n":"Ambient Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Directional Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Fog Color Near","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"Fog Near"},{"t":5,"n":"Fog Far"},{"t":3,"n":"Directional Rotation XY"},{"t":3,"n":"Directional Rotation Z"},{"t":5,"n":"Directional Fade"},{"t":5,"n":"Fog Clip Distance"},{"t":5,"n":"Fog Power"},{"t":6,"n":"Ambient Colors","c":[{"t":8,"n":"Colors","c":[{"t":6,"n":"Color #0 (X+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (X-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Y+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Y-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #4 (Z+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #5 (Z-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"Specular","c":[{"t":6,"n":"Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"Fresnel Power"}]}]},{"t":6,"n":"Fog Color Far","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"Fog Max"},{"t":5,"n":"Light Fade Begin"},{"t":5,"n":"Light Fade End"},{"t":3,"n":"Inherits"}]},{"t":11,"n":"TVDT - Unknown"},{"t":11,"n":"MHDT - Max Height Data"},{"t":3,"n":"LTMP - Lighting Template"},{"t":11,"n":"LNAM - Unknown"},{"t":5,"n":"XCLW - Water Height"},{"t":2,"n":"XNAM - Water Noise Texture"},{"t":9,"n":"XCLR - Regions","c":[{"t":3,"n":"Region"}]},{"t":3,"n":"XLCN - Location"},{"t":11,"n":"XWCN - Unknown"},{"t":11,"n":"XWCS - Unknown"},{"t":6,"n":"XWCU - Water Velocity","c":[{"t":5,"n":"X Offset"},{"t":5,"n":"Y Offset"},{"t":5,"n":"Z Offset"},{"t":11,"n":"Unknown"},{"t":5,"n":"X Angle"},{"t":5,"n":"Y Angle"},{"t":5,"n":"Z Angle"},{"t":11,"n":"Unknown"}]},{"t":3,"n":"XCWT - Water"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"}]},{"t":3,"n":"XILL - Lock List"},{"t":2,"n":"XWEM - Water Environment Map"},{"t":3,"n":"XCCM - Sky\/Weather from Region"},{"t":3,"n":"XCAS - Acoustic Space"},{"t":3,"n":"XEZN - Encounter Zone"},{"t":3,"n":"XCMO - Music Type"},{"t":3,"n":"XCIM - Image Space"}]}]},"name":"Bash.C.Owner","hash":"$C13A1CEE","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.C.RecordFlags.json ================================================ {"records":"CELL","description":"C.RecordFlags tag from Wrye Bash.\r\n\r\nUsed when the mod modifies the off-limits or dangerous flags.","tree":{"records":[{"t":1,"p":1,"n":"CELL - Cell","c":[{"t":6,"p":1,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"p":1,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":3,"n":"DATA - Flags","c":[{"t":4,"n":"Is Interior Cell"}]},{"t":6,"n":"XCLC - Grid","c":[{"t":3,"n":"X"},{"t":3,"n":"Y"},{"t":3,"n":"Force Hide Land"}]},{"t":6,"n":"XCLL - Lighting","c":[{"t":6,"n":"Ambient Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Directional Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Fog Color Near","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"Fog Near"},{"t":5,"n":"Fog Far"},{"t":3,"n":"Directional Rotation XY"},{"t":3,"n":"Directional Rotation Z"},{"t":5,"n":"Directional Fade"},{"t":5,"n":"Fog Clip Distance"},{"t":5,"n":"Fog Power"},{"t":6,"n":"Ambient Colors","c":[{"t":8,"n":"Colors","c":[{"t":6,"n":"Color #0 (X+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (X-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Y+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Y-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #4 (Z+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #5 (Z-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"Specular","c":[{"t":6,"n":"Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"Fresnel Power"}]}]},{"t":6,"n":"Fog Color Far","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"Fog Max"},{"t":5,"n":"Light Fade Begin"},{"t":5,"n":"Light Fade End"},{"t":3,"n":"Inherits"}]},{"t":11,"n":"TVDT - Unknown"},{"t":11,"n":"MHDT - Max Height Data"},{"t":3,"n":"LTMP - Lighting Template"},{"t":11,"n":"LNAM - Unknown"},{"t":5,"n":"XCLW - Water Height"},{"t":2,"n":"XNAM - Water Noise Texture"},{"t":9,"n":"XCLR - Regions","c":[{"t":3,"n":"Region"}]},{"t":3,"n":"XLCN - Location"},{"t":11,"n":"XWCN - Unknown"},{"t":11,"n":"XWCS - Unknown"},{"t":6,"n":"XWCU - Water Velocity","c":[{"t":5,"n":"X Offset"},{"t":5,"n":"Y Offset"},{"t":5,"n":"Z Offset"},{"t":11,"n":"Unknown"},{"t":5,"n":"X Angle"},{"t":5,"n":"Y Angle"},{"t":5,"n":"Z Angle"},{"t":11,"n":"Unknown"}]},{"t":3,"n":"XCWT - Water"},{"t":6,"n":"Ownership","c":[{"t":3,"n":"XOWN - Owner"}]},{"t":3,"n":"XILL - Lock List"},{"t":2,"n":"XWEM - Water Environment Map"},{"t":3,"n":"XCCM - Sky\/Weather from Region"},{"t":3,"n":"XCAS - Acoustic Space"},{"t":3,"n":"XEZN - Encounter Zone"},{"t":3,"n":"XCMO - Music Type"},{"t":3,"n":"XCIM - Image Space"}]}]},"name":"Bash.C.RecordFlags","hash":"$BA9E2375","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.C.Regions.json ================================================ {"records":"CELL","description":"","tree":{"records":[{"t":1,"p":1,"n":"CELL - Cell","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":3,"n":"DATA - Flags","c":[{"t":4,"n":"Is Interior Cell"}]},{"t":6,"n":"XCLC - Grid","c":[{"t":3,"n":"X"},{"t":3,"n":"Y"},{"t":3,"n":"Force Hide Land"}]},{"t":6,"n":"XCLL - Lighting","c":[{"t":6,"n":"Ambient Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Directional Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Fog Color Near","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"Fog Near"},{"t":5,"n":"Fog Far"},{"t":3,"n":"Directional Rotation XY"},{"t":3,"n":"Directional Rotation Z"},{"t":5,"n":"Directional Fade"},{"t":5,"n":"Fog Clip Distance"},{"t":5,"n":"Fog Power"},{"t":6,"n":"Ambient Colors","c":[{"t":8,"n":"Colors","c":[{"t":6,"n":"Color #0 (X+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (X-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Y+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Y-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #4 (Z+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #5 (Z-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"Specular","c":[{"t":6,"n":"Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"Fresnel Power"}]}]},{"t":6,"n":"Fog Color Far","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"Fog Max"},{"t":5,"n":"Light Fade Begin"},{"t":5,"n":"Light Fade End"},{"t":3,"n":"Inherits"}]},{"t":11,"n":"TVDT - Unknown"},{"t":11,"n":"MHDT - Max Height Data"},{"t":3,"n":"LTMP - Lighting Template"},{"t":11,"n":"LNAM - Unknown"},{"t":5,"n":"XCLW - Water Height"},{"t":2,"n":"XNAM - Water Noise Texture"},{"t":9,"p":1,"n":"XCLR - Regions","c":[{"t":3,"p":1,"n":"Region"}]},{"t":3,"n":"XLCN - Location"},{"t":11,"n":"XWCN - Unknown"},{"t":11,"n":"XWCS - Unknown"},{"t":6,"n":"XWCU - Water Velocity","c":[{"t":5,"n":"X Offset"},{"t":5,"n":"Y Offset"},{"t":5,"n":"Z Offset"},{"t":11,"n":"Unknown"},{"t":5,"n":"X Angle"},{"t":5,"n":"Y Angle"},{"t":5,"n":"Z Angle"},{"t":11,"n":"Unknown"}]},{"t":3,"n":"XCWT - Water"},{"t":6,"n":"Ownership","c":[{"t":3,"n":"XOWN - Owner"}]},{"t":3,"n":"XILL - Lock List"},{"t":2,"n":"XWEM - Water Environment Map"},{"t":3,"n":"XCCM - Sky\/Weather from Region"},{"t":3,"n":"XCAS - Acoustic Space"},{"t":3,"n":"XEZN - Encounter Zone"},{"t":3,"n":"XCMO - Music Type"},{"t":3,"n":"XCIM - Image Space"}]}]},"name":"Bash.C.Regions","hash":"$5ED0AD06","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.C.Water.json ================================================ {"records":"CELL","description":"C.Water tag from Wrye Bash.\r\n\r\nUsed when the mod modifies cell water type or level.","tree":{"records":[{"t":1,"p":1,"n":"CELL - Cell","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":3,"n":"DATA - Flags","c":[{"t":4,"n":"Is Interior Cell"}]},{"t":6,"n":"XCLC - Grid","c":[{"t":3,"n":"X"},{"t":3,"n":"Y"},{"t":3,"n":"Force Hide Land"}]},{"t":6,"n":"XCLL - Lighting","c":[{"t":6,"n":"Ambient Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Directional Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Fog Color Near","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"Fog Near"},{"t":5,"n":"Fog Far"},{"t":3,"n":"Directional Rotation XY"},{"t":3,"n":"Directional Rotation Z"},{"t":5,"n":"Directional Fade"},{"t":5,"n":"Fog Clip Distance"},{"t":5,"n":"Fog Power"},{"t":6,"n":"Ambient Colors","c":[{"t":8,"n":"Colors","c":[{"t":6,"n":"Color #0 (X+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (X-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Y+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Y-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #4 (Z+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #5 (Z-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"Specular","c":[{"t":6,"n":"Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"Fresnel Power"}]}]},{"t":6,"n":"Fog Color Far","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"Fog Max"},{"t":5,"n":"Light Fade Begin"},{"t":5,"n":"Light Fade End"},{"t":3,"n":"Inherits"}]},{"t":11,"n":"TVDT - Unknown"},{"t":11,"n":"MHDT - Max Height Data"},{"t":3,"n":"LTMP - Lighting Template"},{"t":11,"n":"LNAM - Unknown"},{"t":5,"p":1,"n":"XCLW - Water Height"},{"t":2,"n":"XNAM - Water Noise Texture"},{"t":9,"n":"XCLR - Regions","c":[{"t":3,"n":"Region"}]},{"t":3,"n":"XLCN - Location"},{"t":11,"n":"XWCN - Unknown"},{"t":11,"n":"XWCS - Unknown"},{"t":6,"n":"XWCU - Water Velocity","c":[{"t":5,"n":"X Offset"},{"t":5,"n":"Y Offset"},{"t":5,"n":"Z Offset"},{"t":11,"n":"Unknown"},{"t":5,"n":"X Angle"},{"t":5,"n":"Y Angle"},{"t":5,"n":"Z Angle"},{"t":11,"n":"Unknown"}]},{"t":3,"p":1,"n":"XCWT - Water"},{"t":6,"n":"Ownership","c":[{"t":3,"n":"XOWN - Owner"}]},{"t":3,"n":"XILL - Lock List"},{"t":2,"n":"XWEM - Water Environment Map"},{"t":3,"n":"XCCM - Sky\/Weather from Region"},{"t":3,"n":"XCAS - Acoustic Space"},{"t":3,"n":"XEZN - Encounter Zone"},{"t":3,"n":"XCMO - Music Type"},{"t":3,"n":"XCIM - Image Space"}]}]},"name":"Bash.C.Water","hash":"$1C99179F","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.Delev.json ================================================ {"records":"LVLI,LVSP,LVLN","description":"Delev tag from Wrye Bash.\r\n\r\nRemoval of entries from the leveled list entries of Leveled Actor (LVLN), Leveled Item (LVLI) or Leveled Spell (LVSP) records.","tree":{"records":[{"t":1,"p":1,"n":"LVLI - Leveled Item","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":3,"n":"LVLD - Chance None"},{"t":3,"n":"LVLF - Flags"},{"t":3,"n":"LVLG - Global"},{"t":3,"n":"LLCT - Count"},{"t":10,"p":1,"n":"Leveled List Entries","d":1,"c":[{"t":6,"p":1,"n":"Leveled List Entry","c":[{"t":6,"p":1,"n":"LVLO - Base Data","c":[{"t":3,"n":"Level"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Reference"},{"t":3,"n":"Count"},{"t":11,"n":"Unknown"}]}]}]}]},{"t":1,"p":1,"n":"LVSP - Leveled Spell","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":3,"n":"LVLD - Chance None"},{"t":3,"n":"LVLF - Flags"},{"t":3,"n":"LLCT - Count"},{"t":10,"p":1,"n":"Leveled List Entries","d":1,"c":[{"t":6,"p":1,"n":"Leveled List Entry","c":[{"t":6,"p":1,"n":"LVLO - Base Data","c":[{"t":3,"n":"Level"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Reference"},{"t":3,"n":"Count"},{"t":11,"n":"Unknown"}]}]}]}]},{"t":1,"p":1,"n":"LVLN - Leveled NPC","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":3,"n":"LVLD - Chance None"},{"t":3,"n":"LVLF - Flags"},{"t":3,"n":"LVLG - Global"},{"t":3,"n":"LLCT - Count"},{"t":10,"p":1,"n":"Leveled List Entries","d":1,"c":[{"t":6,"p":1,"n":"Leveled List Entry","c":[{"t":6,"p":1,"n":"LVLO - Base Data","c":[{"t":3,"n":"Level"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Reference"},{"t":3,"n":"Count"},{"t":11,"n":"Unknown"}]}]}]},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]}]}]},"name":"Bash.Delev","hash":"$90E3A612","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.Eyes.json ================================================ {"records":"RACE","description":"Eyes tag from Wrye Bash.\r\n\r\nUsed when the mod adds eyes to races.","tree":{"records":[{"t":1,"p":1,"n":"RACE - Race","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":3,"n":"SPCT - Count"},{"t":9,"n":"Actor Effects","c":[{"t":3,"n":"SPLO - Actor Effect"}]},{"t":3,"n":"WNAM - Skin"},{"t":6,"n":"BOD2 - Biped Body Template","c":[{"t":3,"n":"First Person Flags"},{"t":3,"n":"General Flags"},{"n":"Unused"},{"t":3,"n":"Armor Type"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"DATA - ","c":[{"t":10,"n":"Skill Boosts","c":[{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]}]},{"t":11,"n":"Unknown"},{"t":5,"n":"Male Height"},{"t":5,"n":"Female Height"},{"t":5,"n":"Male Weight"},{"t":5,"n":"Female Weight"},{"t":3,"n":"Flags"},{"t":5,"n":"Starting Health"},{"t":5,"n":"Starting Magicka"},{"t":5,"n":"Starting Stamina"},{"t":5,"n":"Base Carry Weight"},{"t":5,"n":"Base Mass"},{"t":5,"n":"Acceleration rate"},{"t":5,"n":"Deceleration rate"},{"t":3,"n":"Size"},{"t":3,"n":"Head Biped Object"},{"t":3,"n":"Hair Biped Object"},{"t":5,"n":"Injured Health Pct"},{"t":3,"n":"Shield Biped Object"},{"t":5,"n":"Health Regen"},{"t":5,"n":"Magicka Regen"},{"t":5,"n":"Stamina Regen"},{"t":5,"n":"Unarmed Damage"},{"t":5,"n":"Unarmed Reach"},{"t":3,"n":"Body Biped Object"},{"t":5,"n":"Aim Angle Tolerance"},{"t":5,"n":"Flight Radius"},{"t":5,"n":"Angular Acceleration Rate"},{"t":5,"n":"Angular Tolerance"},{"t":3,"n":"Flags 2"},{"t":6,"n":"Mount Data","c":[{"t":5,"n":"Offset X"},{"t":5,"n":"Offset Y"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"}]}]},{"n":"MNAM - Male Marker"},{"t":2,"n":"ANAM - Male Skeletal Model"},{"t":11,"n":"MODT - Texture Files Hashes"},{"n":"FNAM - Female Marker"},{"t":2,"n":"ANAM - Female Skeletal Model"},{"t":11,"n":"MODT - Texture Files Hashes"},{"n":"NAM2 - Marker NAM2 #1"},{"t":9,"n":"Movement Type Names","c":[{"t":2,"n":"MTNM - Name"}]},{"t":7,"n":"VTCK - Voices","c":[{"t":3,"n":"Voice #0 (Male)"},{"t":3,"n":"Voice #1 (Female)"}]},{"t":7,"n":"DNAM - Decapitate Armors","c":[{"t":3,"n":"Decapitate Armor #0 (Male)"},{"t":3,"n":"Decapitate Armor #1 (Female)"}]},{"t":7,"n":"HCLF - Default Hair Colors","c":[{"t":3,"n":"Default Hair Color #0 (Male)"},{"t":3,"n":"Default Hair Color #1 (Female)"}]},{"t":3,"n":"TINL - Total Number of Tints in List"},{"t":5,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"n":"UNAM - FaceGen - Face clamp"},{"t":3,"n":"ATKR - Attack Race"},{"t":10,"n":"Attacks","c":[{"t":6,"n":"Attack","c":[{"t":6,"n":"ATKD - Attack Data","c":[{"t":5,"n":"Damage Mult"},{"t":5,"n":"Attack Chance"},{"t":3,"n":"Attack Spell"},{"t":3,"n":"Attack Flags"},{"t":5,"n":"Attack Angle"},{"t":5,"n":"Strike Angle"},{"t":5,"n":"Stagger"},{"t":3,"n":"Attack Type"},{"t":5,"n":"Knockdown"},{"t":5,"n":"Recovery Time"},{"t":5,"n":"Stamina Mult"}]}]}]},{"t":6,"n":"Body Data","c":[{"n":"NAM1 - Body Data Marker"},{"t":6,"n":"Male Body Data","c":[{"n":"MNAM - Male Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"}]}]}]},{"t":6,"n":"Female Body Data","c":[{"n":"FNAM - Female Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"}]}]}]}]},{"t":9,"n":"HNAM - Hairs","c":[{"t":3,"n":"Hair"}]},{"t":9,"p":1,"n":"ENAM - Eyes","c":[{"t":3,"p":1,"n":"Eye"}]},{"t":3,"n":"GNAM - Body Part Data"},{"n":"NAM2 - Marker NAM2 #2"},{"n":"NAM3 - Marker NAM3 #3"},{"t":6,"n":"Male Behavior Graph","c":[{"n":"MNAM - Male Data Marker"}]},{"t":6,"n":"Female Behavior Graph","c":[{"n":"FNAM - Female Data Marker"}]},{"t":3,"n":"NAM4 - Material Type"},{"t":3,"n":"NAM5 - Impact Data Set"},{"t":3,"n":"NAM7 - Decapitation FX"},{"t":3,"n":"ONAM - Open Loot Sound"},{"t":3,"n":"LNAM - Close Loot Sound"},{"t":7,"n":"Biped Object Names","c":[{"t":2,"n":"NAME - Name"}]},{"t":10,"n":"Movement Types","c":[{"t":6,"n":"Movement Types","c":[{"t":3,"n":"MTYP - Movement Type"}]}]},{"t":3,"n":"VNAM - Equipment Flags"},{"t":9,"n":"Equip Slots","c":[{"t":3,"n":"QNAM - Equip Slot"}]},{"t":3,"n":"UNES - Unarmed Equip Slot"},{"t":7,"n":"Phoneme Target Names","c":[{"t":2,"n":"PHTN - Name"}]},{"t":6,"n":"FaceFX Phonemes","c":[{"t":6,"n":"IY","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]}]},{"t":3,"n":"WKMV - Base Movement Default - Walk"},{"t":3,"n":"RNMV - Base Movement Default - Run"},{"t":3,"n":"SWMV - Base Movement Default - Swim"},{"t":3,"n":"FLMV - Base Movement Default - Fly"},{"t":3,"n":"SNMV - Base Movement Default - Sneak"},{"t":3,"n":"SPMV - Base Movement Default - Sprint"},{"t":6,"n":"Head Data","c":[{"n":"NAM0 - Head Data Marker"},{"t":6,"n":"Male Head Data","c":[{"n":"MNAM - Male Data Marker"}]},{"t":6,"n":"Female Head Data","c":[{"n":"NAM0 - Head Data Marker"},{"n":"FNAM - Female Data Marker"}]}]},{"t":3,"n":"NAM8 - Morph race"},{"t":3,"n":"RNAM - Armor race"}]}]},"name":"Bash.Eyes","hash":"3992F5B6","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.Factions.json ================================================ {"records":"NPC_","description":"Factions tag from Wrye Bash.\r\n\r\nUsed when the mod modifies NPC factions.","tree":{"records":[{"t":1,"p":1,"n":"NPC_ - Non-Player Character (Actor)","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Magicka Offset"},{"t":3,"n":"Stamina Offset"},{"t":12,"n":"Level"},{"t":3,"n":"Calc min level"},{"t":3,"n":"Calc max level"},{"t":3,"n":"Speed Multiplier"},{"t":3,"n":"Disposition Base (unused)"},{"t":3,"n":"Template Flags"},{"t":3,"n":"Health Offset"},{"t":3,"n":"Bleedout Override"}]},{"t":10,"s":1,"p":1,"n":"Factions","d":1,"c":[{"t":6,"p":1,"n":"SNAM - Faction","c":[{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Rank"},{"t":11,"p":1,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"VTCK - Voice"},{"t":3,"n":"TPLT - Template"},{"t":3,"n":"RNAM - Race"},{"t":3,"n":"SPCT - Count"},{"t":9,"n":"Actor Effects","c":[{"t":3,"n":"SPLO - Actor Effect"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"WNAM - Worn Armor"},{"t":3,"n":"ANAM - Far away model"},{"t":3,"n":"ATKR - Attack Race"},{"t":10,"n":"Attacks","c":[{"t":6,"n":"Attack","c":[{"t":6,"n":"ATKD - Attack Data","c":[{"t":5,"n":"Damage Mult"},{"t":5,"n":"Attack Chance"},{"t":3,"n":"Attack Spell"},{"t":3,"n":"Attack Flags"},{"t":5,"n":"Attack Angle"},{"t":5,"n":"Strike Angle"},{"t":5,"n":"Stagger"},{"t":3,"n":"Attack Type"},{"t":5,"n":"Knockdown"},{"t":5,"n":"Recovery Time"},{"t":5,"n":"Stamina Mult"}]}]}]},{"t":3,"n":"SPOR - Spectator override package list"},{"t":3,"n":"OCOR - Observe dead body override package list"},{"t":3,"n":"GWOR - Guard warn override package list"},{"t":3,"n":"ECOR - Combat override package list"},{"t":3,"n":"PRKZ - Perk Count"},{"t":10,"n":"Perks","c":[{"t":6,"n":"PRKR - Perk","c":[{"t":3,"n":"Perk"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"COCT - Count"},{"t":10,"n":"Items","c":[{"t":6,"n":"Item","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]}]},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Mood"},{"t":3,"n":"Assistance"},{"t":6,"n":"Aggro","c":[{"t":3,"n":"Aggro Radius Behavior"},{"t":3,"n":"Unknown"},{"t":3,"n":"Warn"},{"t":3,"n":"Warn\/Attack"},{"t":3,"n":"Attack"}]}]},{"t":7,"n":"Packages","c":[{"t":3,"n":"PKID - Package"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":3,"n":"CNAM - Class"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"SHRT - Short Name"},{"t":11,"n":"DATA - Marker"},{"t":6,"n":"DNAM - Player Skills","c":[{"t":7,"n":"Skill Values","c":[{"t":3,"n":"Skill #0 (OneHanded)"},{"t":3,"n":"Skill #1 (TwoHanded)"},{"t":3,"n":"Skill #2 (Marksman)"},{"t":3,"n":"Skill #3 (Block)"},{"t":3,"n":"Skill #4 (Smithing)"},{"t":3,"n":"Skill #5 (HeavyArmor)"},{"t":3,"n":"Skill #6 (LightArmor)"},{"t":3,"n":"Skill #7 (Pickpocket)"},{"t":3,"n":"Skill #8 (Lockpicking)"},{"t":3,"n":"Skill #9 (Sneak)"},{"t":3,"n":"Skill #10 (Alchemy)"},{"t":3,"n":"Skill #11 (Speechcraft)"},{"t":3,"n":"Skill #12 (Alteration)"},{"t":3,"n":"Skill #13 (Conjuration)"},{"t":3,"n":"Skill #14 (Destruction)"},{"t":3,"n":"Skill #15 (Illusion)"},{"t":3,"n":"Skill #16 (Restoration)"},{"t":3,"n":"Skill #17 (Enchanting)"}]},{"t":7,"n":"Skill Offsets","c":[{"t":3,"n":"Skill #0 (OneHanded)"},{"t":3,"n":"Skill #1 (TwoHanded)"},{"t":3,"n":"Skill #2 (Marksman)"},{"t":3,"n":"Skill #3 (Block)"},{"t":3,"n":"Skill #4 (Smithing)"},{"t":3,"n":"Skill #5 (HeavyArmor)"},{"t":3,"n":"Skill #6 (LightArmor)"},{"t":3,"n":"Skill #7 (Pickpocket)"},{"t":3,"n":"Skill #8 (Lockpicking)"},{"t":3,"n":"Skill #9 (Sneak)"},{"t":3,"n":"Skill #10 (Alchemy)"},{"t":3,"n":"Skill #11 (Speechcraft)"},{"t":3,"n":"Skill #12 (Alteration)"},{"t":3,"n":"Skill #13 (Conjuration)"},{"t":3,"n":"Skill #14 (Destruction)"},{"t":3,"n":"Skill #15 (Illusion)"},{"t":3,"n":"Skill #16 (Restoration)"},{"t":3,"n":"Skill #17 (Enchanting)"}]},{"t":3,"n":"Health"},{"t":3,"n":"Magicka"},{"t":3,"n":"Stamina"},{"t":11,"n":"Unused"},{"t":5,"n":"Far away model distance"},{"t":3,"n":"Geared up weapons"},{"t":11,"n":"Unused"}]},{"t":9,"n":"Head Parts","c":[{"t":3,"n":"PNAM - Head Part"}]},{"t":3,"n":"HCLF - Hair Color"},{"t":3,"n":"ZNAM - Combat Style"},{"t":3,"n":"GNAM - Gift Filter"},{"t":11,"n":"NAM5 - Unknown"},{"t":5,"n":"NAM6 - Height"},{"t":5,"n":"NAM7 - Weight"},{"t":3,"n":"NAM8 - Sound Level"},{"t":10,"n":"Sound Types","c":[{"t":6,"n":"Sound Type","c":[{"t":3,"n":"CSDT - Type"},{"t":10,"n":"Sounds","c":[{"t":6,"n":"Sound","c":[{"t":3,"n":"CSDI - Sound"},{"t":3,"n":"CSDC - Sound Chance"}]}]}]}]},{"t":3,"n":"CSCR - Inherits Sounds From"},{"t":3,"n":"DOFT - Default outfit"},{"t":3,"n":"SOFT - Sleeping outfit"},{"t":3,"n":"DPLT - Default Package List"},{"t":3,"n":"CRIF - Crime faction"},{"t":3,"n":"FTST - Head texture"},{"t":6,"n":"QNAM - Texture lighting","c":[{"t":5,"n":"Red"},{"t":5,"n":"Green"},{"t":5,"n":"Blue"}]},{"t":6,"n":"NAM9 - Face morph","c":[{"t":5,"n":"Nose Long\/Short"},{"t":5,"n":"Nose Up\/Down"},{"t":5,"n":"Jaw Up\/Down"},{"t":5,"n":"Jaw Narrow\/Wide"},{"t":5,"n":"Jaw Farward\/Back"},{"t":5,"n":"Cheeks Up\/Down"},{"t":5,"n":"Cheeks Farward\/Back"},{"t":5,"n":"Eyes Up\/Down"},{"t":5,"n":"Eyes In\/Out"},{"t":5,"n":"Brows Up\/Down"},{"t":5,"n":"Brows In\/Out"},{"t":5,"n":"Brows Farward\/Back"},{"t":5,"n":"Lips Up\/Down"},{"t":5,"n":"Lips In\/Out"},{"t":5,"n":"Chin Narrow\/Wide"},{"t":5,"n":"Chin Up\/Down"},{"t":5,"n":"Chin Underbite\/Overbite"},{"t":5,"n":"Eyes Farward\/Back"},{"t":5,"n":"Unknown"}]},{"t":6,"n":"NAMA - Face parts","c":[{"t":3,"n":"Nose"},{"t":3,"n":"Unknown"},{"t":3,"n":"Eyes"},{"t":3,"n":"Mouth"}]},{"t":10,"n":"Tint Layers","c":[{"t":6,"n":"Layer","c":[{"t":3,"n":"TINI - Tint Index"}]}]}]}]},"name":"Bash.Factions","hash":"$727C24D6","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.Graphics.json ================================================ {"records":"ACTI,AMMO,APPA,ARMA,ARMO,ARTO,BOOK,DEBR,DOOR,EFSH,EXPL,FLOR,FURN,GRAS,INGR,LIGH,LSCR,MGEF,MISC,MSTT,PROJ,SCRL,SLGM,STAT,TREE,WEAP,ALCH","description":"Graphics tag from Wrye Bash.\r\n\r\nUsed when the mod is a graphics replacer.\r\n\r\nNote: I tried my best to get all appropriate records and subrecords for Skyrim in the spirit of this Bash Tag, but I may have missed things. Please let me know if I did. -Mator","tree":{"records":[{"t":1,"p":1,"n":"ACTI - Activator","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"PNAM - Marker Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":3,"n":"Unused"}]},{"t":3,"n":"SNAM - Sound - Looping"},{"t":3,"n":"VNAM - Sound - Activation"},{"t":3,"n":"WNAM - Water Type"},{"t":2,"n":"RNAM - Activate Text Override"},{"t":3,"n":"FNAM - Flags"},{"t":3,"n":"KNAM - Interaction Keyword"}]},{"t":1,"p":1,"n":"AMMO - Ammunition","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":2,"n":"DESC - Description"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"DATA - Data","c":[{"t":3,"n":"Projectile"},{"t":3,"n":"Flags"},{"t":5,"n":"Damage"},{"t":3,"n":"Value"}]},{"t":2,"n":"ONAM - Short Name"}]},{"t":1,"p":1,"n":"APPA - Alchemical Apparatus","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":3,"n":"QUAL - Quality"},{"t":2,"n":"DESC - Description"},{"t":6,"n":"DATA - Data","c":[{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]}]},{"t":1,"p":1,"n":"ARMA - Armor Addon","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"BOD2 - Biped Body Template","c":[{"t":3,"n":"First Person Flags"},{"t":3,"n":"General Flags"},{"n":"Unused"},{"t":3,"n":"Armor Type"}]},{"t":3,"n":"RNAM - Race"},{"t":6,"n":"DNAM - Data","c":[{"t":3,"n":"Male Priority"},{"t":3,"n":"Female Priority"},{"t":3,"n":"Weight slider - Male"},{"t":3,"n":"Weight slider - Female"},{"t":11,"n":"Unknown"},{"t":3,"n":"Detection Sound Value"},{"t":11,"n":"Unknown"},{"t":5,"n":"Weapon Adjust"}]},{"t":6,"s":1,"p":1,"n":"Male world model","c":[{"t":2,"p":1,"n":"MOD2 - Model Filename"}]},{"t":6,"s":1,"p":1,"n":"Female world model","c":[{"t":2,"p":1,"n":"MOD3 - Model Filename"}]},{"t":6,"s":1,"p":1,"n":"Male 1st Person","c":[{"t":2,"p":1,"n":"MOD4 - Model Filename"}]},{"t":6,"s":1,"p":1,"n":"Female 1st Person","c":[{"t":2,"p":1,"n":"MOD5 - Model Filename"}]},{"t":3,"n":"NAM0 - Male Skin Texture"},{"t":3,"n":"NAM1 - Female Skin texture"},{"t":3,"n":"NAM2 - Male Skin Texture Swap List"},{"t":3,"n":"NAM3 - Female Skin Texture Swap List"},{"t":9,"n":"Additional Races","c":[{"t":3,"n":"MODL - Race"}]},{"t":3,"n":"SNDD - Footstep Sound"},{"t":3,"n":"ONAM - Art Object"}]},{"t":1,"p":1,"n":"ARMO - Armor","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":3,"n":"EITM - Object Effect"},{"t":3,"n":"EAMT - Enchantment Amount"},{"t":6,"n":"Male world model","c":[{"t":2,"n":"MOD2 - Model Filename"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"}]},{"t":6,"n":"Female world model","c":[{"t":2,"n":"MOD4 - Model Filename"}]},{"t":6,"n":"Icon 2 (female)","c":[{"t":2,"n":"ICO2 - Large Icon filename"}]},{"t":6,"n":"BOD2 - Biped Body Template","c":[{"t":3,"n":"First Person Flags"},{"t":3,"n":"General Flags"},{"n":"Unused"},{"t":3,"n":"Armor Type"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":2,"n":"BMCT - Ragdoll Constraint Template"},{"t":3,"n":"ETYP - Equipment Type"},{"t":3,"n":"BIDS - Bash Impact Data Set"},{"t":3,"n":"BAMT - Alternate Block Material"},{"t":3,"n":"RNAM - Race"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":2,"n":"DESC - Description"},{"t":7,"p":1,"n":"Armature","c":[{"t":3,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"n":"DATA - Data","c":[{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]},{"t":3,"n":"DNAM - Armor Rating"},{"t":3,"n":"TNAM - Template Armor"}]},{"t":1,"p":1,"n":"ARTO - Art Object","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":3,"n":"DNAM - Art Type"}]},{"t":1,"p":1,"n":"BOOK - Book","c":[{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":7,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":7,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"n":"Alias"},{"t":3,"n":"FormID"}]},{"t":6,"n":"Object v1","c":[{"t":3,"n":"FormID"},{"t":3,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"n":"String"},{"t":3,"n":"Int32"},{"t":5,"n":"Float"},{"t":3,"n":"Bool"},{"t":7,"n":"Array of Object","c":[{"t":6,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"n":"Alias"},{"t":3,"n":"FormID"}]},{"t":6,"n":"Object v1","c":[{"t":3,"n":"FormID"},{"t":3,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"n":"Array of String","c":[{"t":2,"n":"Element"}]},{"t":7,"n":"Array of Int32","c":[{"t":3,"n":"Element"}]},{"t":7,"n":"Array of Float","c":[{"t":5,"n":"Element"}]},{"t":7,"n":"Array of Bool","c":[{"t":3,"n":"Element"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"},{"t":2,"n":"MICO - Small Icon filename"}]},{"t":2,"n":"DESC - Book Text"},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"n":"Stages","c":[{"t":6,"n":"Stage","c":[{"t":6,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"n":"Health %"},{"t":3,"n":"Index"},{"t":3,"n":"Model Damage Stage"},{"t":3,"n":"Flags"},{"t":3,"n":"Self Damage per Second"},{"t":3,"n":"Explosion"},{"t":3,"n":"Debris"},{"t":3,"n":"Debris Count"}]},{"t":6,"n":"Model","c":[{"t":2,"n":"DMDL - Model Filename"},{"t":11,"n":"DMDT - Texture Files Hashes"},{"t":7,"n":"DMDS - Alternate Textures","c":[{"t":6,"n":"Alternate Texture","c":[{"t":2,"n":"3D Name"},{"t":3,"n":"New Texture"},{"t":3,"n":"3D Index"}]}]}]},{"n":"DSTF - End Marker"}]}]}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Put Down"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"DATA - Data","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":3,"n":"Skill"},{"t":3,"n":"Spell"},{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]},{"t":3,"p":1,"n":"INAM - Inventory Art"},{"t":2,"n":"CNAM - Description"}]},{"t":1,"p":1,"n":"DEBR - Debris","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":8,"p":1,"n":"Models","c":[{"t":6,"p":1,"n":"Model","c":[{"t":6,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Percentage"},{"t":2,"p":1,"n":"Model Filename"},{"t":3,"p":1,"n":"Flags"}]}]}]}]},{"t":1,"p":1,"n":"DOOR - Door","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"SNAM - Sound - Open"},{"t":3,"n":"ANAM - Sound - Close"},{"t":3,"n":"BNAM - Sound - Loop"},{"t":3,"n":"FNAM - Flags"}]},{"t":1,"p":1,"n":"EFSH - Effect Shader","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"ICON - Fill Texture","lt":"ICO2 - Particle Shader Texture","lf":"DATA - "},{"t":2,"p":1,"n":"ICO2 - Particle Shader Texture","lt":"NAM7 - Holes Texture","lf":"ICON - Fill Texture"},{"t":2,"p":1,"n":"NAM7 - Holes Texture","lt":"NAM8 - Membrane Palette Texture","lf":"ICO2 - Particle Shader Texture"},{"t":2,"p":1,"n":"NAM8 - Membrane Palette Texture","lt":"NAM9 - Particle Palette Texture","lf":"NAM7 - Holes Texture"},{"t":2,"p":1,"n":"NAM9 - Particle Palette Texture","lt":"DATA - ","lf":"NAM8 - Membrane Palette Texture"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":11,"p":1,"n":"Unknown"},{"t":3,"p":1,"n":"Membrane Shader - Source Blend Mode"},{"t":3,"p":1,"n":"Membrane Shader - Blend Operation"},{"t":3,"p":1,"n":"Membrane Shader - Z Test Function"},{"t":6,"p":1,"n":"Fill\/Texture Effect - Color Key 1","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Fade In Time"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Full Alpha Time"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Fade Out Time"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Presistent Alpha Ratio"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Pulse Amplitude"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Pulse Frequency"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Animation Speed (U)"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Animation Speed (V)"},{"t":5,"p":1,"n":"Edge Effect - Fall Off"},{"t":6,"p":1,"n":"Edge Effect - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":5,"p":1,"n":"Edge Effect - Alpha Fade In Time"},{"t":5,"p":1,"n":"Edge Effect - Full Alpha Time"},{"t":5,"p":1,"n":"Edge Effect - Alpha Fade Out Time"},{"t":5,"p":1,"n":"Edge Effect - Persistent Alpha Ratio"},{"t":5,"p":1,"n":"Edge Effect - Alpha Pulse Amplitude"},{"t":5,"p":1,"n":"Edge Effect - Alpha Pulse Frequency"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Full Alpha Ratio"},{"t":5,"p":1,"n":"Edge Effect - Full Alpha Ratio"},{"t":3,"p":1,"n":"Membrane Shader - Dest Blend Mode"},{"t":3,"p":1,"n":"Particle Shader - Source Blend Mode"},{"t":3,"p":1,"n":"Particle Shader - Blend Operation"},{"t":3,"p":1,"n":"Particle Shader - Z Test Function"},{"t":3,"p":1,"n":"Particle Shader - Dest Blend Mode"},{"t":5,"p":1,"n":"Particle Shader - Particle Birth Ramp Up Time"},{"t":5,"p":1,"n":"Particle Shader - Full Particle Birth Time"},{"t":5,"p":1,"n":"Particle Shader - Particle Birth Ramp Down Time"},{"t":5,"p":1,"n":"Particle Shader - Full Particle Birth Ratio"},{"t":5,"p":1,"n":"Particle Shader - Persistant Particle Count"},{"t":5,"p":1,"n":"Particle Shader - Particle Lifetime"},{"t":5,"p":1,"n":"Particle Shader - Particle Lifetime +\/-"},{"t":5,"p":1,"n":"Particle Shader - Initial Speed Along Normal"},{"t":5,"p":1,"n":"Particle Shader - Acceleration Along Normal"},{"t":5,"p":1,"n":"Particle Shader - Initial Velocity #1"},{"t":5,"p":1,"n":"Particle Shader - Initial Velocity #2"},{"t":5,"p":1,"n":"Particle Shader - Initial Velocity #3"},{"t":5,"p":1,"n":"Particle Shader - Acceleration #1"},{"t":5,"p":1,"n":"Particle Shader - Acceleration #2"},{"t":5,"p":1,"n":"Particle Shader - Acceleration #3"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 1"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 2"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 1 Time"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 2 Time"},{"t":6,"p":1,"n":"Color Key 1 - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":6,"p":1,"n":"Color Key 2 - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":6,"p":1,"n":"Color Key 3 - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":5,"p":1,"n":"Color Key 1 - Color Alpha"},{"t":5,"p":1,"n":"Color Key 2 - Color Alpha"},{"t":5,"p":1,"n":"Color Key 3 - Color Alpha"},{"t":5,"p":1,"n":"Color Key 1 - Color Key Time"},{"t":5,"p":1,"n":"Color Key 2 - Color Key Time"},{"t":5,"p":1,"n":"Color Key 3 - Color Key Time"},{"t":5,"p":1,"n":"Particle Shader - Initial Speed Along Normal +\/-"},{"t":5,"p":1,"n":"Particle Shader - Initial Rotation (deg)"},{"t":5,"p":1,"n":"Particle Shader - Initial Rotation (deg) +\/-"},{"t":5,"p":1,"n":"Particle Shader - Rotation Speed (deg\/sec)"},{"t":5,"p":1,"n":"Particle Shader - Rotation Speed (deg\/sec) +\/-"},{"t":3,"p":1,"n":"Addon Models"},{"t":5,"p":1,"n":"Holes - Start Time"},{"t":5,"p":1,"n":"Holes - End Time"},{"t":5,"p":1,"n":"Holes - Start Val"},{"t":5,"p":1,"n":"Holes - End Val"},{"t":5,"p":1,"n":"Edge Width (alpha units)"},{"t":6,"p":1,"n":"Edge Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":5,"p":1,"n":"Explosion Wind Speed"},{"t":3,"p":1,"n":"Texture Count U"},{"t":3,"p":1,"n":"Texture Count V"},{"t":5,"p":1,"n":"Addon Models - Fade In Time"},{"t":5,"p":1,"n":"Addon Models - Fade Out Time"},{"t":5,"p":1,"n":"Addon Models - Scale Start"},{"t":5,"p":1,"n":"Addon Models - Scale End"},{"t":5,"p":1,"n":"Addon Models - Scale In Time"},{"t":5,"p":1,"n":"Addon Models - Scale Out Time"},{"t":3,"p":1,"n":"Ambient Sound"},{"t":6,"p":1,"n":"Fill\/Texture Effect - Color Key 2","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":6,"p":1,"n":"Fill\/Texture Effect - Color Key 3","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"p":1,"n":"Unknown"}]},{"t":6,"p":1,"n":"Fill\/Texture Effect - Color Key Scale\/Time","c":[{"t":5,"p":1,"n":"Color Key 1 - Scale"},{"t":5,"p":1,"n":"Color Key 2 - Scale"},{"t":5,"p":1,"n":"Color Key 3 - Scale"},{"t":5,"p":1,"n":"Color Key 1 - Time"},{"t":5,"p":1,"n":"Color Key 2 - Time"},{"t":5,"p":1,"n":"Color Key 3 - Time"}]},{"t":5,"p":1,"n":"Color Scale"},{"t":5,"p":1,"n":"Birth Position Offset"},{"t":5,"p":1,"n":"Birth Position Offset Range +\/-"},{"t":6,"p":1,"n":"Particle Shader Animated","c":[{"t":3,"p":1,"n":"Start Frame"},{"t":3,"p":1,"n":"Start Frame Variation"},{"t":3,"p":1,"n":"End Frame"},{"t":3,"p":1,"n":"Loop Start Frame"},{"t":3,"p":1,"n":"Loop Start Variation"},{"t":3,"p":1,"n":"Frame Count"},{"t":3,"p":1,"n":"Frame Count Variation"}]},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Scale (U)"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Scale (V)"},{"t":3,"p":1,"n":"Scene Graph Emit Depth Limit (unused)"}],"lt":"ICON - Fill Texture","lf":"NAM9 - Particle Palette Texture"}]},{"t":1,"p":1,"n":"EXPL - Explosion","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":3,"n":"EITM - Object Effect"},{"t":3,"n":"MNAM - Image Space Modifier"},{"t":6,"n":"DATA - Data","c":[{"t":3,"n":"Light"},{"t":3,"n":"Sound 1"},{"t":3,"n":"Sound 2"},{"t":3,"n":"Impact Data Set"},{"t":3,"n":"Placed Object"},{"t":3,"n":"Spawn Projectile"},{"t":5,"n":"Force"},{"t":5,"n":"Damage"},{"t":5,"n":"Radius"},{"t":5,"n":"IS Radius"},{"t":5,"n":"Vertical Offset Mult"},{"t":3,"n":"Flags"},{"t":3,"n":"Sound Level"}]}]},{"t":1,"p":1,"n":"FLOR - Flora","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":11,"n":"PNAM - Unknown"},{"t":2,"n":"RNAM - Activate Text Override"},{"t":11,"n":"FNAM - Unknown"},{"t":3,"n":"PFIG - Ingredient"},{"t":3,"n":"SNAM - Sound"},{"t":6,"n":"PFPC - Seasonal ingredient production","c":[{"t":3,"n":"Spring"},{"t":3,"n":"Summer "},{"t":3,"n":"Fall"},{"t":3,"n":"Winter"}]}]},{"t":1,"p":1,"n":"FURN - Furniture","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":11,"n":"PNAM - Unknown"},{"t":3,"n":"FNAM - Flags"},{"t":3,"n":"KNAM - Interaction Keyword"},{"t":3,"n":"MNAM - Active Markers \/ Flags"},{"t":6,"n":"WBDT - Workbench Data","c":[{"t":3,"n":"Bench Type"},{"t":3,"n":"Uses Skill"}]},{"t":3,"n":"NAM1 - Associated Spell"},{"t":8,"n":"Markers","c":[{"t":6,"n":"Marker","c":[{"t":3,"n":"ENAM - Marker Index"}]}]},{"t":8,"n":"Marker Entry Points","c":[{"t":6,"n":"FNPR - Marker","c":[{"t":3,"n":"Type"},{"t":3,"n":"Entry Points"}]}]},{"t":2,"n":"XMRK - Model Filename"}]},{"t":1,"p":1,"n":"GRAS - Grass","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Density"},{"t":3,"n":"Min Slope"},{"t":3,"n":"Max Slope"},{"t":11,"n":"Unknown"},{"t":3,"n":"Units From Water"},{"t":11,"n":"Unknown"},{"t":3,"n":"Units From Water Type"},{"t":5,"n":"Position Range"},{"t":5,"n":"Height Range"},{"t":5,"n":"Color Range"},{"t":5,"n":"Wave Period"},{"t":3,"n":"Flags"},{"t":11,"n":"Unknown"}]}]},{"t":1,"p":1,"n":"INGR - Ingredient","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"ETYP - Equipment Type"},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]},{"t":6,"n":"ENIT - Effect Data","c":[{"t":3,"n":"Ingredient Value"},{"t":3,"n":"Flags"}]},{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":3,"n":"EFID - Base Effect"},{"t":6,"n":"EFIT - ","c":[{"t":5,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"}]}]}]}]},{"t":1,"p":1,"n":"LIGH - Light","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":2,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"}]},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Time"},{"t":3,"n":"Radius"},{"t":6,"n":"Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":3,"n":"Unknown"}]},{"t":3,"n":"Flags"},{"t":5,"n":"Falloff Exponent"},{"t":5,"n":"FOV"},{"t":5,"n":"Near Clip"},{"t":6,"n":"Flicker Effect","c":[{"t":5,"n":"Period"},{"t":5,"n":"Intensity Amplitude"},{"t":5,"n":"Movement Amplitude"}]},{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]},{"t":5,"n":"FNAM - Fade value"},{"t":3,"n":"SNAM - Sound"}]},{"t":1,"p":1,"n":"LSCR - Load Screen","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"}]},{"t":2,"n":"DESC - Description"},{"t":8,"n":"Conditions","c":[{"t":6,"n":"Condition","c":[{"t":6,"n":"CTDA - ","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":12,"n":"Comparison Value"},{"t":3,"n":"Function"},{"t":11,"n":"Unused"},{"t":12,"n":"Parameter #1"},{"t":12,"n":"Parameter #2"},{"t":3,"n":"Run On"},{"t":12,"n":"Reference"},{"t":3,"n":"Parameter #3"}]}]}]},{"t":3,"n":"NNAM - Loading Screen NIF"},{"t":5,"n":"SNAM - Initial Scale"},{"t":6,"n":"RNAM - Initial Rotation","c":[{"t":3,"n":"X"},{"t":3,"n":"Y"},{"t":3,"n":"Z"}]},{"t":6,"n":"ONAM - Rotation Offset Constraints","c":[{"t":3,"n":"Min"},{"t":3,"n":"Max"}]},{"t":6,"n":"XNAM - Initial Translation Offset","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]},{"t":2,"n":"MOD2 - Camera Path"}]},{"t":1,"p":1,"n":"MGEF - Magic Effect","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":2,"n":"FULL - Name"},{"t":3,"p":1,"n":"MDOB - Menu Display Object"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"Magic Effect Data","c":[{"t":6,"n":"DATA - Data","c":[{"t":3,"n":"Flags"},{"t":5,"n":"Base Cost"},{"t":12,"n":"Assoc. Item"},{"t":3,"n":"Magic Skill"},{"t":3,"n":"Resist Value"},{"t":3,"n":"Counter Effect count"},{"t":11,"n":"Unused"},{"t":3,"n":"Casting Light"},{"t":5,"n":"Taper Weight"},{"t":3,"n":"Hit Shader"},{"t":3,"n":"Enchant Shader"},{"t":3,"n":"Minimum Skill Level"},{"t":6,"n":"Spellmaking","c":[{"t":3,"n":"Area"},{"t":5,"n":"Casting Time"}]},{"t":5,"n":"Taper Curve"},{"t":5,"n":"Taper Duration"},{"t":5,"n":"Second AV Weight"},{"t":3,"n":"Archtype"},{"t":3,"n":"Actor Value"},{"t":3,"n":"Projectile"},{"t":3,"n":"Explosion"},{"t":3,"n":"Casting Type"},{"t":3,"n":"Delivery"},{"t":3,"n":"Second Actor Value"},{"t":3,"n":"Casting Art"},{"t":3,"n":"Hit Effect Art"},{"t":3,"n":"Impact Data"},{"t":5,"n":"Skill Usage Multiplier"},{"t":6,"n":"Dual Casting","c":[{"t":3,"n":"Art"},{"t":5,"n":"Scale"}]},{"t":3,"n":"Enchant Art"},{"t":11,"n":"Unknown"},{"t":11,"n":"Unknown"},{"t":3,"n":"Equip Ability"},{"t":3,"n":"Image Space Modifier"},{"t":3,"n":"Perk to Apply"},{"t":3,"n":"Casting Sound Level"},{"t":6,"n":"Script Effect AI","c":[{"t":5,"n":"Score"},{"t":5,"n":"Delay Time"}]}]}]},{"t":9,"n":"Counter Effects","c":[{"t":3,"n":"ESCE - Effect"}]},{"t":8,"n":"SNDD - Sounds","c":[{"t":6,"n":" #0","c":[{"t":3,"n":"Type"},{"t":3,"n":"Sound"}]}]},{"t":2,"n":"DNAM - Magic Item Description"},{"t":8,"n":"Conditions","c":[{"t":6,"n":"Condition","c":[{"t":6,"n":"CTDA - ","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":12,"n":"Comparison Value"},{"t":3,"n":"Function"},{"t":11,"n":"Unused"},{"t":12,"n":"Parameter #1"},{"t":12,"n":"Parameter #2"},{"t":3,"n":"Run On"},{"t":12,"n":"Reference"},{"t":3,"n":"Parameter #3"}]}]}]}]},{"t":1,"p":1,"n":"MISC - Misc. Item","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"DATA - Data","c":[{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]}]},{"t":1,"p":1,"n":"MSTT - Moveable Static","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"DATA - Flags"},{"t":3,"n":"SNAM - Looping Sound"}]},{"t":1,"p":1,"n":"PROJ - Projectile","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"DATA - Data","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Type"},{"t":5,"n":"Gravity"},{"t":5,"n":"Speed"},{"t":5,"n":"Range"},{"t":3,"n":"Light"},{"t":3,"n":"Muzzle Flash - Light"},{"t":5,"n":"Tracer Chance"},{"t":5,"n":"Explosion - Alt. Trigger - Proximity"},{"t":5,"n":"Explosion - Alt. Trigger - Timer"},{"t":3,"n":"Explosion"},{"t":3,"n":"Sound"},{"t":5,"n":"Muzzle Flash - Duration"},{"t":5,"n":"Fade Duration"},{"t":5,"n":"Impact Force"},{"t":3,"n":"Sound - Countdown"},{"t":3,"n":"Sound - Disable"},{"t":3,"n":"Default Weapon Source"},{"t":5,"n":"Cone Spread"},{"t":5,"n":"Collision Radius"},{"t":5,"n":"Lifetime"},{"t":5,"n":"Relaunch Interval"},{"t":3,"n":"Decal Data"},{"t":3,"n":"Collision Layer"}]},{"t":6,"n":"Muzzle Flash Model","c":[{"t":2,"n":"NAM1 - Model Filename"}]},{"t":3,"n":"VNAM - Sound Level"}]},{"t":1,"p":1,"n":"SCRL - Scroll","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":3,"n":"MDOB - Menu Display Object"},{"t":3,"n":"ETYP - Equipment Type"},{"t":2,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":6,"n":"DATA - Item","c":[{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]},{"t":6,"n":"SPIT - Data","c":[{"t":3,"n":"Base Cost"},{"t":3,"n":"Flags"},{"t":3,"n":"Type"},{"t":5,"n":"Charge Time"},{"t":3,"n":"Cast Type"},{"t":3,"n":"Target Type"},{"t":5,"n":"Cast Duration"},{"t":5,"n":"Range"},{"t":3,"n":"Half-cost Perk"}]},{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":3,"n":"EFID - Base Effect"},{"t":6,"n":"EFIT - ","c":[{"t":5,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"}]}]}]}]},{"t":1,"p":1,"n":"SLGM - Soul Gem","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]},{"t":3,"n":"SOUL - Contained Soul"},{"t":3,"n":"SLCP - Maximum Capacity"},{"t":3,"n":"NAM0 - Linked To"}]},{"t":1,"p":1,"n":"STAT - Static","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"n":"DNAM - Direction Material","c":[{"t":5,"n":"Max Angle (30-120)"},{"t":3,"n":"Material"}]},{"t":8,"n":"MNAM - Distant LOD","c":[{"t":6,"n":"LOD #0 (Level 0)","c":[{"t":2,"n":"Mesh"}]},{"t":6,"n":"LOD #1 (Level 1)","c":[{"t":2,"n":"Mesh"}]},{"t":6,"n":"LOD #2 (Level 2)","c":[{"t":2,"n":"Mesh"}]},{"t":6,"n":"LOD #3 (Level 3)","c":[{"t":2,"n":"Mesh"}]}]}]},{"t":1,"p":1,"n":"TREE - Tree","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":3,"n":"PFIG - Ingredient"},{"t":3,"n":"SNAM - Harvest Sound"},{"t":6,"n":"PFPC - Ingredient Production","c":[{"t":3,"n":"Spring"},{"t":3,"n":"Summer"},{"t":3,"n":"Fall"},{"t":3,"n":"Winter"}]},{"t":2,"n":"FULL - Name"},{"t":6,"n":"CNAM - Tree Data","c":[{"t":5,"n":"Trunk Flexibility"},{"t":5,"n":"Branch Flexibility"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Leaf Amplitude"},{"t":5,"n":"Leaf Frequency"}]}]},{"t":1,"p":1,"n":"WEAP - Weapon","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"}]},{"t":3,"n":"EITM - Object Effect"},{"t":3,"n":"EAMT - Enchantment Amount"},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"ETYP - Equipment Type"},{"t":3,"n":"BIDS - Block Bash Impact Data Set"},{"t":3,"n":"BAMT - Alternate Block Material"},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":2,"n":"DESC - Description"},{"t":6,"n":"Has Scope","c":[{"t":2,"n":"MOD3 - Model Filename"}]},{"t":11,"n":"NNAM - Unused"},{"t":3,"n":"INAM - Impact Data Set"},{"t":3,"p":1,"n":"WNAM - 1st Person Model Object"},{"t":3,"n":"SNAM - Attack Sound"},{"t":3,"n":"XNAM - Attack Sound 2D"},{"t":3,"n":"NAM7 - Attack Loop Sound"},{"t":3,"n":"TNAM - Attack Fail Sound"},{"t":3,"n":"UNAM - Idle Sound"},{"t":3,"n":"NAM9 - Equip Sound"},{"t":3,"n":"NAM8 - Unequip Sound"},{"t":6,"n":"DATA - Game Data","c":[{"t":3,"n":"Value"},{"t":5,"n":"Weight"},{"t":3,"n":"Damage"}]},{"t":6,"n":"DNAM - Data","c":[{"t":3,"n":"Animation Type"},{"t":11,"n":"Unused"},{"t":5,"n":"Speed"},{"t":5,"n":"Reach"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"},{"t":5,"n":"Sight FOV"},{"t":11,"n":"Unknown"},{"t":3,"n":"Base VATS To-Hit Chance"},{"t":3,"n":"Attack Animation"},{"t":3,"n":"# Projectiles"},{"t":3,"n":"Embedded Weapon AV (unused)"},{"t":5,"n":"Range Min"},{"t":5,"n":"Range Max"},{"t":3,"n":"On Hit"},{"t":3,"n":"Flags2"},{"t":5,"n":"Animation Attack Mult"},{"t":5,"n":"Unknown"},{"t":5,"n":"Rumble - Left Motor Strength"},{"t":5,"n":"Rumble - Right Motor Strength"},{"t":5,"n":"Rumble - Duration"},{"t":11,"n":"Unknown"},{"t":3,"n":"Skill"},{"t":11,"n":"Unknown"},{"t":3,"n":"Resist"},{"t":11,"n":"Unknown"},{"t":5,"n":"Stagger"}]},{"t":6,"n":"CRDT - Critical Data","c":[{"t":3,"n":"Damage"},{"t":11,"n":"Unused"},{"t":5,"n":"% Mult"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"},{"t":3,"n":"Effect"}]},{"t":3,"n":"VNAM - Detection Sound Level"},{"t":3,"n":"CNAM - Template"}]},{"t":1,"p":1,"n":"ALCH - Ingestible","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":2,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":3,"n":"ETYP - Equipment Type"},{"t":5,"n":"DATA - Weight"},{"t":6,"n":"ENIT - Effect Data","c":[{"t":3,"n":"Value"},{"t":3,"n":"Flags"},{"t":3,"n":"Addiction"},{"t":5,"n":"Addiction Chance"},{"t":3,"n":"Sound - Consume"}]},{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":3,"n":"EFID - Base Effect"},{"t":6,"n":"EFIT - ","c":[{"t":5,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"}]}]}]}]}]},"name":"Bash.Graphics","hash":"8A68A29F","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.Hairs.json ================================================ {"records":"RACE","description":"Hairs tag from Wrye Bash.\r\n\r\nUsed when the mod adds hairs to races.","tree":{"records":[{"t":1,"p":1,"n":"RACE - Race","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":3,"n":"SPCT - Count"},{"t":9,"n":"Actor Effects","c":[{"t":3,"n":"SPLO - Actor Effect"}]},{"t":3,"n":"WNAM - Skin"},{"t":6,"n":"BOD2 - Biped Body Template","c":[{"t":3,"n":"First Person Flags"},{"t":3,"n":"General Flags"},{"n":"Unused"},{"t":3,"n":"Armor Type"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"DATA - ","c":[{"t":10,"n":"Skill Boosts","c":[{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]}]},{"t":11,"n":"Unknown"},{"t":5,"n":"Male Height"},{"t":5,"n":"Female Height"},{"t":5,"n":"Male Weight"},{"t":5,"n":"Female Weight"},{"t":3,"n":"Flags"},{"t":5,"n":"Starting Health"},{"t":5,"n":"Starting Magicka"},{"t":5,"n":"Starting Stamina"},{"t":5,"n":"Base Carry Weight"},{"t":5,"n":"Base Mass"},{"t":5,"n":"Acceleration rate"},{"t":5,"n":"Deceleration rate"},{"t":3,"n":"Size"},{"t":3,"n":"Head Biped Object"},{"t":3,"n":"Hair Biped Object"},{"t":5,"n":"Injured Health Pct"},{"t":3,"n":"Shield Biped Object"},{"t":5,"n":"Health Regen"},{"t":5,"n":"Magicka Regen"},{"t":5,"n":"Stamina Regen"},{"t":5,"n":"Unarmed Damage"},{"t":5,"n":"Unarmed Reach"},{"t":3,"n":"Body Biped Object"},{"t":5,"n":"Aim Angle Tolerance"},{"t":5,"n":"Flight Radius"},{"t":5,"n":"Angular Acceleration Rate"},{"t":5,"n":"Angular Tolerance"},{"t":3,"n":"Flags 2"},{"t":6,"n":"Mount Data","c":[{"t":5,"n":"Offset X"},{"t":5,"n":"Offset Y"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"}]}]},{"n":"MNAM - Male Marker"},{"t":2,"n":"ANAM - Male Skeletal Model"},{"t":11,"n":"MODT - Texture Files Hashes"},{"n":"FNAM - Female Marker"},{"t":2,"n":"ANAM - Female Skeletal Model"},{"t":11,"n":"MODT - Texture Files Hashes"},{"n":"NAM2 - Marker NAM2 #1"},{"t":9,"n":"Movement Type Names","c":[{"t":2,"n":"MTNM - Name"}]},{"t":7,"n":"VTCK - Voices","c":[{"t":3,"n":"Voice #0 (Male)"},{"t":3,"n":"Voice #1 (Female)"}]},{"t":7,"n":"DNAM - Decapitate Armors","c":[{"t":3,"n":"Decapitate Armor #0 (Male)"},{"t":3,"n":"Decapitate Armor #1 (Female)"}]},{"t":7,"n":"HCLF - Default Hair Colors","c":[{"t":3,"n":"Default Hair Color #0 (Male)"},{"t":3,"n":"Default Hair Color #1 (Female)"}]},{"t":3,"n":"TINL - Total Number of Tints in List"},{"t":5,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"n":"UNAM - FaceGen - Face clamp"},{"t":3,"n":"ATKR - Attack Race"},{"t":10,"n":"Attacks","c":[{"t":6,"n":"Attack","c":[{"t":6,"n":"ATKD - Attack Data","c":[{"t":5,"n":"Damage Mult"},{"t":5,"n":"Attack Chance"},{"t":3,"n":"Attack Spell"},{"t":3,"n":"Attack Flags"},{"t":5,"n":"Attack Angle"},{"t":5,"n":"Strike Angle"},{"t":5,"n":"Stagger"},{"t":3,"n":"Attack Type"},{"t":5,"n":"Knockdown"},{"t":5,"n":"Recovery Time"},{"t":5,"n":"Stamina Mult"}]}]}]},{"t":6,"n":"Body Data","c":[{"n":"NAM1 - Body Data Marker"},{"t":6,"n":"Male Body Data","c":[{"n":"MNAM - Male Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"}]}]}]},{"t":6,"n":"Female Body Data","c":[{"n":"FNAM - Female Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"}]}]}]}]},{"t":9,"p":1,"n":"HNAM - Hairs","c":[{"t":3,"p":1,"n":"Hair"}]},{"t":9,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eye"}]},{"t":3,"n":"GNAM - Body Part Data"},{"n":"NAM2 - Marker NAM2 #2"},{"n":"NAM3 - Marker NAM3 #3"},{"t":6,"n":"Male Behavior Graph","c":[{"n":"MNAM - Male Data Marker"}]},{"t":6,"n":"Female Behavior Graph","c":[{"n":"FNAM - Female Data Marker"}]},{"t":3,"n":"NAM4 - Material Type"},{"t":3,"n":"NAM5 - Impact Data Set"},{"t":3,"n":"NAM7 - Decapitation FX"},{"t":3,"n":"ONAM - Open Loot Sound"},{"t":3,"n":"LNAM - Close Loot Sound"},{"t":7,"n":"Biped Object Names","c":[{"t":2,"n":"NAME - Name"}]},{"t":10,"n":"Movement Types","c":[{"t":6,"n":"Movement Types","c":[{"t":3,"n":"MTYP - Movement Type"}]}]},{"t":3,"n":"VNAM - Equipment Flags"},{"t":9,"n":"Equip Slots","c":[{"t":3,"n":"QNAM - Equip Slot"}]},{"t":3,"n":"UNES - Unarmed Equip Slot"},{"t":7,"n":"Phoneme Target Names","c":[{"t":2,"n":"PHTN - Name"}]},{"t":6,"n":"FaceFX Phonemes","c":[{"t":6,"n":"IY","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]}]},{"t":3,"n":"WKMV - Base Movement Default - Walk"},{"t":3,"n":"RNMV - Base Movement Default - Run"},{"t":3,"n":"SWMV - Base Movement Default - Swim"},{"t":3,"n":"FLMV - Base Movement Default - Fly"},{"t":3,"n":"SNMV - Base Movement Default - Sneak"},{"t":3,"n":"SPMV - Base Movement Default - Sprint"},{"t":6,"n":"Head Data","c":[{"n":"NAM0 - Head Data Marker"},{"t":6,"n":"Male Head Data","c":[{"n":"MNAM - Male Data Marker"}]},{"t":6,"n":"Female Head Data","c":[{"n":"NAM0 - Head Data Marker"},{"n":"FNAM - Female Data Marker"}]}]},{"t":3,"n":"NAM8 - Morph race"},{"t":3,"n":"RNAM - Armor race"}]}]},"name":"Bash.Hairs","hash":"$533161C6","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.Invent.json ================================================ {"records":"NPC_,CONT","description":"Invent tag from Wrye Bash.\r\n\r\nUsed when the mod changes inventories.","tree":{"records":[{"t":1,"p":1,"n":"NPC_ - Non-Player Character (Actor)","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Magicka Offset"},{"t":3,"n":"Stamina Offset"},{"t":12,"n":"Level"},{"t":3,"n":"Calc min level"},{"t":3,"n":"Calc max level"},{"t":3,"n":"Speed Multiplier"},{"t":3,"n":"Disposition Base (unused)"},{"t":3,"n":"Template Flags"},{"t":3,"n":"Health Offset"},{"t":3,"n":"Bleedout Override"}]},{"t":10,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"VTCK - Voice"},{"t":3,"n":"TPLT - Template"},{"t":3,"n":"RNAM - Race"},{"t":3,"n":"SPCT - Count"},{"t":9,"n":"Actor Effects","c":[{"t":3,"n":"SPLO - Actor Effect"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"WNAM - Worn Armor"},{"t":3,"n":"ANAM - Far away model"},{"t":3,"n":"ATKR - Attack Race"},{"t":10,"n":"Attacks","c":[{"t":6,"n":"Attack","c":[{"t":6,"n":"ATKD - Attack Data","c":[{"t":5,"n":"Damage Mult"},{"t":5,"n":"Attack Chance"},{"t":3,"n":"Attack Spell"},{"t":3,"n":"Attack Flags"},{"t":5,"n":"Attack Angle"},{"t":5,"n":"Strike Angle"},{"t":5,"n":"Stagger"},{"t":3,"n":"Attack Type"},{"t":5,"n":"Knockdown"},{"t":5,"n":"Recovery Time"},{"t":5,"n":"Stamina Mult"}]}]}]},{"t":3,"n":"SPOR - Spectator override package list"},{"t":3,"n":"OCOR - Observe dead body override package list"},{"t":3,"n":"GWOR - Guard warn override package list"},{"t":3,"n":"ECOR - Combat override package list"},{"t":3,"n":"PRKZ - Perk Count"},{"t":10,"n":"Perks","c":[{"t":6,"n":"PRKR - Perk","c":[{"t":3,"n":"Perk"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"COCT - Count"},{"t":10,"p":1,"n":"Items","d":1,"c":[{"t":6,"p":1,"n":"Item","c":[{"t":6,"p":1,"n":"CNTO - Item","c":[{"t":3,"p":1,"n":"Item"},{"t":3,"p":1,"n":"Count"}]}]}]},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Mood"},{"t":3,"n":"Assistance"},{"t":6,"n":"Aggro","c":[{"t":3,"n":"Aggro Radius Behavior"},{"t":3,"n":"Unknown"},{"t":3,"n":"Warn"},{"t":3,"n":"Warn\/Attack"},{"t":3,"n":"Attack"}]}]},{"t":7,"n":"Packages","c":[{"t":3,"n":"PKID - Package"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":3,"n":"CNAM - Class"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"SHRT - Short Name"},{"t":11,"n":"DATA - Marker"},{"t":6,"n":"DNAM - Player Skills","c":[{"t":7,"n":"Skill Values","c":[{"t":3,"n":"Skill #0 (OneHanded)"},{"t":3,"n":"Skill #1 (TwoHanded)"},{"t":3,"n":"Skill #2 (Marksman)"},{"t":3,"n":"Skill #3 (Block)"},{"t":3,"n":"Skill #4 (Smithing)"},{"t":3,"n":"Skill #5 (HeavyArmor)"},{"t":3,"n":"Skill #6 (LightArmor)"},{"t":3,"n":"Skill #7 (Pickpocket)"},{"t":3,"n":"Skill #8 (Lockpicking)"},{"t":3,"n":"Skill #9 (Sneak)"},{"t":3,"n":"Skill #10 (Alchemy)"},{"t":3,"n":"Skill #11 (Speechcraft)"},{"t":3,"n":"Skill #12 (Alteration)"},{"t":3,"n":"Skill #13 (Conjuration)"},{"t":3,"n":"Skill #14 (Destruction)"},{"t":3,"n":"Skill #15 (Illusion)"},{"t":3,"n":"Skill #16 (Restoration)"},{"t":3,"n":"Skill #17 (Enchanting)"}]},{"t":7,"n":"Skill Offsets","c":[{"t":3,"n":"Skill #0 (OneHanded)"},{"t":3,"n":"Skill #1 (TwoHanded)"},{"t":3,"n":"Skill #2 (Marksman)"},{"t":3,"n":"Skill #3 (Block)"},{"t":3,"n":"Skill #4 (Smithing)"},{"t":3,"n":"Skill #5 (HeavyArmor)"},{"t":3,"n":"Skill #6 (LightArmor)"},{"t":3,"n":"Skill #7 (Pickpocket)"},{"t":3,"n":"Skill #8 (Lockpicking)"},{"t":3,"n":"Skill #9 (Sneak)"},{"t":3,"n":"Skill #10 (Alchemy)"},{"t":3,"n":"Skill #11 (Speechcraft)"},{"t":3,"n":"Skill #12 (Alteration)"},{"t":3,"n":"Skill #13 (Conjuration)"},{"t":3,"n":"Skill #14 (Destruction)"},{"t":3,"n":"Skill #15 (Illusion)"},{"t":3,"n":"Skill #16 (Restoration)"},{"t":3,"n":"Skill #17 (Enchanting)"}]},{"t":3,"n":"Health"},{"t":3,"n":"Magicka"},{"t":3,"n":"Stamina"},{"t":11,"n":"Unused"},{"t":5,"n":"Far away model distance"},{"t":3,"n":"Geared up weapons"},{"t":11,"n":"Unused"}]},{"t":9,"n":"Head Parts","c":[{"t":3,"n":"PNAM - Head Part"}]},{"t":3,"n":"HCLF - Hair Color"},{"t":3,"n":"ZNAM - Combat Style"},{"t":3,"n":"GNAM - Gift Filter"},{"t":11,"n":"NAM5 - Unknown"},{"t":5,"n":"NAM6 - Height"},{"t":5,"n":"NAM7 - Weight"},{"t":3,"n":"NAM8 - Sound Level"},{"t":10,"n":"Sound Types","c":[{"t":6,"n":"Sound Type","c":[{"t":3,"n":"CSDT - Type"},{"t":10,"n":"Sounds","c":[{"t":6,"n":"Sound","c":[{"t":3,"n":"CSDI - Sound"},{"t":3,"n":"CSDC - Sound Chance"}]}]}]}]},{"t":3,"n":"CSCR - Inherits Sounds From"},{"t":3,"n":"DOFT - Default outfit"},{"t":3,"n":"SOFT - Sleeping outfit"},{"t":3,"n":"DPLT - Default Package List"},{"t":3,"n":"CRIF - Crime faction"},{"t":3,"n":"FTST - Head texture"},{"t":6,"n":"QNAM - Texture lighting","c":[{"t":5,"n":"Red"},{"t":5,"n":"Green"},{"t":5,"n":"Blue"}]},{"t":6,"n":"NAM9 - Face morph","c":[{"t":5,"n":"Nose Long\/Short"},{"t":5,"n":"Nose Up\/Down"},{"t":5,"n":"Jaw Up\/Down"},{"t":5,"n":"Jaw Narrow\/Wide"},{"t":5,"n":"Jaw Farward\/Back"},{"t":5,"n":"Cheeks Up\/Down"},{"t":5,"n":"Cheeks Farward\/Back"},{"t":5,"n":"Eyes Up\/Down"},{"t":5,"n":"Eyes In\/Out"},{"t":5,"n":"Brows Up\/Down"},{"t":5,"n":"Brows In\/Out"},{"t":5,"n":"Brows Farward\/Back"},{"t":5,"n":"Lips Up\/Down"},{"t":5,"n":"Lips In\/Out"},{"t":5,"n":"Chin Narrow\/Wide"},{"t":5,"n":"Chin Up\/Down"},{"t":5,"n":"Chin Underbite\/Overbite"},{"t":5,"n":"Eyes Farward\/Back"},{"t":5,"n":"Unknown"}]},{"t":6,"n":"NAMA - Face parts","c":[{"t":3,"n":"Nose"},{"t":3,"n":"Unknown"},{"t":3,"n":"Eyes"},{"t":3,"n":"Mouth"}]},{"t":10,"n":"Tint Layers","c":[{"t":6,"n":"Layer","c":[{"t":3,"n":"TINI - Tint Index"}]}]}]},{"t":1,"p":1,"n":"CONT - Container","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":3,"n":"COCT - Count"},{"t":10,"p":1,"n":"Items","d":1,"c":[{"t":6,"p":1,"n":"Item","c":[{"t":6,"p":1,"n":"CNTO - Item","c":[{"t":3,"p":1,"n":"Item"},{"t":3,"p":1,"n":"Count"}]}]}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Flags"},{"t":5,"n":"Weight"}]},{"t":3,"n":"SNAM - Sound - Open"},{"t":3,"n":"QNAM - Sound - Close"}]}]},"name":"Bash.Invent","hash":"$7F0C9C4C","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.Lev.json ================================================ {"records":"LVLI,LVSP,LVLN","description":"Base setting for Wrye Bash's leveled list handling.\r\n\r\nWhen used, leveled list entries will be merged.","tree":{"records":[{"t":1,"p":1,"n":"LVLI - Leveled Item","c":[{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":3,"n":"LVLD - Chance None"},{"t":3,"n":"LVLF - Flags"},{"t":3,"n":"LVLG - Global"},{"t":3,"n":"LLCT - Count"},{"t":10,"p":1,"n":"Leveled List Entries","c":[{"t":6,"s":1,"p":1,"n":"Leveled List Entry","c":[{"t":6,"n":"LVLO - Base Data","c":[{"t":3,"n":"Level"},{"t":11,"n":"Unknown"},{"t":3,"n":"Reference"},{"t":3,"n":"Count"}]},{"t":6,"n":"COED - Extra Data","c":[{"t":3,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"n":"Global Variable"},{"t":3,"n":"Required Rank"},{"t":5,"n":"Item Condition"}]}]}]}]},{"t":1,"p":1,"n":"LVSP - Leveled Spell","c":[{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":3,"n":"LVLD - Chance None"},{"t":3,"n":"LVLF - Flags"},{"t":3,"n":"LLCT - Count"},{"t":10,"p":1,"n":"Leveled List Entries","c":[{"t":6,"s":1,"p":1,"n":"Leveled List Entry","c":[{"t":6,"n":"LVLO - Base Data","c":[{"t":3,"n":"Level"},{"t":11,"n":"Unknown"},{"t":3,"n":"Reference"},{"t":3,"n":"Count"}]}]}]}]},{"t":1,"p":1,"n":"LVLN - Leveled NPC","c":[{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":3,"n":"LVLD - Chance None"},{"t":3,"n":"LVLF - Flags"},{"t":3,"n":"LVLG - Global"},{"t":3,"n":"LLCT - Count"},{"t":10,"p":1,"n":"Leveled List Entries","c":[{"t":6,"s":1,"p":1,"n":"Leveled List Entry","c":[{"t":6,"n":"LVLO - Base Data","c":[{"t":3,"n":"Level"},{"t":11,"n":"Unknown"},{"t":3,"n":"Reference"},{"t":3,"n":"Count"}]},{"t":6,"n":"COED - Extra Data","c":[{"t":3,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"n":"Global Variable"},{"t":3,"n":"Required Rank"},{"t":5,"n":"Item Condition"}]}]}]},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":11,"n":"MODT - Texture Files Hashes"},{"t":7,"n":"MODS - Alternate Textures","c":[{"t":6,"n":"Alternate Texture","c":[{"t":2,"n":"3D Name"},{"t":3,"n":"New Texture"},{"t":3,"n":"3D Index"}]}]}]}]}]},"name":"Bash.Lev","hash":"E5E41BEB","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.NPC.Class.json ================================================ {"records":"NPC_","description":"NPC.Class tag from Wrye Bash.\r\n\r\nUsed when the mod changes the classes of NPCs.","tree":{"records":[{"t":1,"p":1,"n":"NPC_ - Non-Player Character (Actor)","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Magicka Offset"},{"t":3,"n":"Stamina Offset"},{"t":12,"n":"Level"},{"t":3,"n":"Calc min level"},{"t":3,"n":"Calc max level"},{"t":3,"n":"Speed Multiplier"},{"t":3,"n":"Disposition Base (unused)"},{"t":3,"n":"Template Flags"},{"t":3,"n":"Health Offset"},{"t":3,"n":"Bleedout Override"}]},{"t":10,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"VTCK - Voice"},{"t":3,"n":"TPLT - Template"},{"t":3,"n":"RNAM - Race"},{"t":3,"n":"SPCT - Count"},{"t":9,"n":"Actor Effects","c":[{"t":3,"n":"SPLO - Actor Effect"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"WNAM - Worn Armor"},{"t":3,"n":"ANAM - Far away model"},{"t":3,"n":"ATKR - Attack Race"},{"t":10,"n":"Attacks","c":[{"t":6,"n":"Attack","c":[{"t":6,"n":"ATKD - Attack Data","c":[{"t":5,"n":"Damage Mult"},{"t":5,"n":"Attack Chance"},{"t":3,"n":"Attack Spell"},{"t":3,"n":"Attack Flags"},{"t":5,"n":"Attack Angle"},{"t":5,"n":"Strike Angle"},{"t":5,"n":"Stagger"},{"t":3,"n":"Attack Type"},{"t":5,"n":"Knockdown"},{"t":5,"n":"Recovery Time"},{"t":5,"n":"Stamina Mult"}]}]}]},{"t":3,"n":"SPOR - Spectator override package list"},{"t":3,"n":"OCOR - Observe dead body override package list"},{"t":3,"n":"GWOR - Guard warn override package list"},{"t":3,"n":"ECOR - Combat override package list"},{"t":3,"n":"PRKZ - Perk Count"},{"t":10,"n":"Perks","c":[{"t":6,"n":"PRKR - Perk","c":[{"t":3,"n":"Perk"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"COCT - Count"},{"t":10,"n":"Items","c":[{"t":6,"n":"Item","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]}]},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Mood"},{"t":3,"n":"Assistance"},{"t":6,"n":"Aggro","c":[{"t":3,"n":"Aggro Radius Behavior"},{"t":3,"n":"Unknown"},{"t":3,"n":"Warn"},{"t":3,"n":"Warn\/Attack"},{"t":3,"n":"Attack"}]}]},{"t":7,"n":"Packages","c":[{"t":3,"n":"PKID - Package"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":3,"p":1,"n":"CNAM - Class"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"SHRT - Short Name"},{"t":11,"n":"DATA - Marker"},{"t":6,"n":"DNAM - Player Skills","c":[{"t":7,"n":"Skill Values","c":[{"t":3,"n":"Skill #0 (OneHanded)"},{"t":3,"n":"Skill #1 (TwoHanded)"},{"t":3,"n":"Skill #2 (Marksman)"},{"t":3,"n":"Skill #3 (Block)"},{"t":3,"n":"Skill #4 (Smithing)"},{"t":3,"n":"Skill #5 (HeavyArmor)"},{"t":3,"n":"Skill #6 (LightArmor)"},{"t":3,"n":"Skill #7 (Pickpocket)"},{"t":3,"n":"Skill #8 (Lockpicking)"},{"t":3,"n":"Skill #9 (Sneak)"},{"t":3,"n":"Skill #10 (Alchemy)"},{"t":3,"n":"Skill #11 (Speechcraft)"},{"t":3,"n":"Skill #12 (Alteration)"},{"t":3,"n":"Skill #13 (Conjuration)"},{"t":3,"n":"Skill #14 (Destruction)"},{"t":3,"n":"Skill #15 (Illusion)"},{"t":3,"n":"Skill #16 (Restoration)"},{"t":3,"n":"Skill #17 (Enchanting)"}]},{"t":7,"n":"Skill Offsets","c":[{"t":3,"n":"Skill #0 (OneHanded)"},{"t":3,"n":"Skill #1 (TwoHanded)"},{"t":3,"n":"Skill #2 (Marksman)"},{"t":3,"n":"Skill #3 (Block)"},{"t":3,"n":"Skill #4 (Smithing)"},{"t":3,"n":"Skill #5 (HeavyArmor)"},{"t":3,"n":"Skill #6 (LightArmor)"},{"t":3,"n":"Skill #7 (Pickpocket)"},{"t":3,"n":"Skill #8 (Lockpicking)"},{"t":3,"n":"Skill #9 (Sneak)"},{"t":3,"n":"Skill #10 (Alchemy)"},{"t":3,"n":"Skill #11 (Speechcraft)"},{"t":3,"n":"Skill #12 (Alteration)"},{"t":3,"n":"Skill #13 (Conjuration)"},{"t":3,"n":"Skill #14 (Destruction)"},{"t":3,"n":"Skill #15 (Illusion)"},{"t":3,"n":"Skill #16 (Restoration)"},{"t":3,"n":"Skill #17 (Enchanting)"}]},{"t":3,"n":"Health"},{"t":3,"n":"Magicka"},{"t":3,"n":"Stamina"},{"t":11,"n":"Unused"},{"t":5,"n":"Far away model distance"},{"t":3,"n":"Geared up weapons"},{"t":11,"n":"Unused"}]},{"t":9,"n":"Head Parts","c":[{"t":3,"n":"PNAM - Head Part"}]},{"t":3,"n":"HCLF - Hair Color"},{"t":3,"n":"ZNAM - Combat Style"},{"t":3,"n":"GNAM - Gift Filter"},{"t":11,"n":"NAM5 - Unknown"},{"t":5,"n":"NAM6 - Height"},{"t":5,"n":"NAM7 - Weight"},{"t":3,"n":"NAM8 - Sound Level"},{"t":10,"n":"Sound Types","c":[{"t":6,"n":"Sound Type","c":[{"t":3,"n":"CSDT - Type"},{"t":10,"n":"Sounds","c":[{"t":6,"n":"Sound","c":[{"t":3,"n":"CSDI - Sound"},{"t":3,"n":"CSDC - Sound Chance"}]}]}]}]},{"t":3,"n":"CSCR - Inherits Sounds From"},{"t":3,"n":"DOFT - Default outfit"},{"t":3,"n":"SOFT - Sleeping outfit"},{"t":3,"n":"DPLT - Default Package List"},{"t":3,"n":"CRIF - Crime faction"},{"t":3,"n":"FTST - Head texture"},{"t":6,"n":"QNAM - Texture lighting","c":[{"t":5,"n":"Red"},{"t":5,"n":"Green"},{"t":5,"n":"Blue"}]},{"t":6,"n":"NAM9 - Face morph","c":[{"t":5,"n":"Nose Long\/Short"},{"t":5,"n":"Nose Up\/Down"},{"t":5,"n":"Jaw Up\/Down"},{"t":5,"n":"Jaw Narrow\/Wide"},{"t":5,"n":"Jaw Farward\/Back"},{"t":5,"n":"Cheeks Up\/Down"},{"t":5,"n":"Cheeks Farward\/Back"},{"t":5,"n":"Eyes Up\/Down"},{"t":5,"n":"Eyes In\/Out"},{"t":5,"n":"Brows Up\/Down"},{"t":5,"n":"Brows In\/Out"},{"t":5,"n":"Brows Farward\/Back"},{"t":5,"n":"Lips Up\/Down"},{"t":5,"n":"Lips In\/Out"},{"t":5,"n":"Chin Narrow\/Wide"},{"t":5,"n":"Chin Up\/Down"},{"t":5,"n":"Chin Underbite\/Overbite"},{"t":5,"n":"Eyes Farward\/Back"},{"t":5,"n":"Unknown"}]},{"t":6,"n":"NAMA - Face parts","c":[{"t":3,"n":"Nose"},{"t":3,"n":"Unknown"},{"t":3,"n":"Eyes"},{"t":3,"n":"Mouth"}]},{"t":10,"n":"Tint Layers","c":[{"t":6,"n":"Layer","c":[{"t":3,"n":"TINI - Tint Index"}]}]}]}]},"name":"Bash.NPC.Class","hash":"$0B2151B6","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.NPC.Race.json ================================================ {"records":"NPC_","description":"NPC.Race tag from Wrye Bash.\r\n\r\nUsed when the mod modifies NPC races.","tree":{"records":[{"t":1,"p":1,"n":"NPC_ - Non-Player Character (Actor)","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Magicka Offset"},{"t":3,"n":"Stamina Offset"},{"t":12,"n":"Level"},{"t":3,"n":"Calc min level"},{"t":3,"n":"Calc max level"},{"t":3,"n":"Speed Multiplier"},{"t":3,"n":"Disposition Base (unused)"},{"t":3,"n":"Template Flags"},{"t":3,"n":"Health Offset"},{"t":3,"n":"Bleedout Override"}]},{"t":10,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"VTCK - Voice"},{"t":3,"n":"TPLT - Template"},{"t":3,"p":1,"n":"RNAM - Race"},{"t":3,"n":"SPCT - Count"},{"t":9,"n":"Actor Effects","c":[{"t":3,"n":"SPLO - Actor Effect"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"WNAM - Worn Armor"},{"t":3,"n":"ANAM - Far away model"},{"t":3,"n":"ATKR - Attack Race"},{"t":10,"n":"Attacks","c":[{"t":6,"n":"Attack","c":[{"t":6,"n":"ATKD - Attack Data","c":[{"t":5,"n":"Damage Mult"},{"t":5,"n":"Attack Chance"},{"t":3,"n":"Attack Spell"},{"t":3,"n":"Attack Flags"},{"t":5,"n":"Attack Angle"},{"t":5,"n":"Strike Angle"},{"t":5,"n":"Stagger"},{"t":3,"n":"Attack Type"},{"t":5,"n":"Knockdown"},{"t":5,"n":"Recovery Time"},{"t":5,"n":"Stamina Mult"}]}]}]},{"t":3,"n":"SPOR - Spectator override package list"},{"t":3,"n":"OCOR - Observe dead body override package list"},{"t":3,"n":"GWOR - Guard warn override package list"},{"t":3,"n":"ECOR - Combat override package list"},{"t":3,"n":"PRKZ - Perk Count"},{"t":10,"n":"Perks","c":[{"t":6,"n":"PRKR - Perk","c":[{"t":3,"n":"Perk"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"COCT - Count"},{"t":10,"n":"Items","c":[{"t":6,"n":"Item","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]}]},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Mood"},{"t":3,"n":"Assistance"},{"t":6,"n":"Aggro","c":[{"t":3,"n":"Aggro Radius Behavior"},{"t":3,"n":"Unknown"},{"t":3,"n":"Warn"},{"t":3,"n":"Warn\/Attack"},{"t":3,"n":"Attack"}]}]},{"t":7,"n":"Packages","c":[{"t":3,"n":"PKID - Package"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":3,"n":"CNAM - Class"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"SHRT - Short Name"},{"t":11,"n":"DATA - Marker"},{"t":6,"n":"DNAM - Player Skills","c":[{"t":7,"n":"Skill Values","c":[{"t":3,"n":"Skill #0 (OneHanded)"},{"t":3,"n":"Skill #1 (TwoHanded)"},{"t":3,"n":"Skill #2 (Marksman)"},{"t":3,"n":"Skill #3 (Block)"},{"t":3,"n":"Skill #4 (Smithing)"},{"t":3,"n":"Skill #5 (HeavyArmor)"},{"t":3,"n":"Skill #6 (LightArmor)"},{"t":3,"n":"Skill #7 (Pickpocket)"},{"t":3,"n":"Skill #8 (Lockpicking)"},{"t":3,"n":"Skill #9 (Sneak)"},{"t":3,"n":"Skill #10 (Alchemy)"},{"t":3,"n":"Skill #11 (Speechcraft)"},{"t":3,"n":"Skill #12 (Alteration)"},{"t":3,"n":"Skill #13 (Conjuration)"},{"t":3,"n":"Skill #14 (Destruction)"},{"t":3,"n":"Skill #15 (Illusion)"},{"t":3,"n":"Skill #16 (Restoration)"},{"t":3,"n":"Skill #17 (Enchanting)"}]},{"t":7,"n":"Skill Offsets","c":[{"t":3,"n":"Skill #0 (OneHanded)"},{"t":3,"n":"Skill #1 (TwoHanded)"},{"t":3,"n":"Skill #2 (Marksman)"},{"t":3,"n":"Skill #3 (Block)"},{"t":3,"n":"Skill #4 (Smithing)"},{"t":3,"n":"Skill #5 (HeavyArmor)"},{"t":3,"n":"Skill #6 (LightArmor)"},{"t":3,"n":"Skill #7 (Pickpocket)"},{"t":3,"n":"Skill #8 (Lockpicking)"},{"t":3,"n":"Skill #9 (Sneak)"},{"t":3,"n":"Skill #10 (Alchemy)"},{"t":3,"n":"Skill #11 (Speechcraft)"},{"t":3,"n":"Skill #12 (Alteration)"},{"t":3,"n":"Skill #13 (Conjuration)"},{"t":3,"n":"Skill #14 (Destruction)"},{"t":3,"n":"Skill #15 (Illusion)"},{"t":3,"n":"Skill #16 (Restoration)"},{"t":3,"n":"Skill #17 (Enchanting)"}]},{"t":3,"n":"Health"},{"t":3,"n":"Magicka"},{"t":3,"n":"Stamina"},{"t":11,"n":"Unused"},{"t":5,"n":"Far away model distance"},{"t":3,"n":"Geared up weapons"},{"t":11,"n":"Unused"}]},{"t":9,"n":"Head Parts","c":[{"t":3,"n":"PNAM - Head Part"}]},{"t":3,"n":"HCLF - Hair Color"},{"t":3,"n":"ZNAM - Combat Style"},{"t":3,"n":"GNAM - Gift Filter"},{"t":11,"n":"NAM5 - Unknown"},{"t":5,"n":"NAM6 - Height"},{"t":5,"n":"NAM7 - Weight"},{"t":3,"n":"NAM8 - Sound Level"},{"t":10,"n":"Sound Types","c":[{"t":6,"n":"Sound Type","c":[{"t":3,"n":"CSDT - Type"},{"t":10,"n":"Sounds","c":[{"t":6,"n":"Sound","c":[{"t":3,"n":"CSDI - Sound"},{"t":3,"n":"CSDC - Sound Chance"}]}]}]}]},{"t":3,"n":"CSCR - Inherits Sounds From"},{"t":3,"n":"DOFT - Default outfit"},{"t":3,"n":"SOFT - Sleeping outfit"},{"t":3,"n":"DPLT - Default Package List"},{"t":3,"n":"CRIF - Crime faction"},{"t":3,"n":"FTST - Head texture"},{"t":6,"n":"QNAM - Texture lighting","c":[{"t":5,"n":"Red"},{"t":5,"n":"Green"},{"t":5,"n":"Blue"}]},{"t":6,"n":"NAM9 - Face morph","c":[{"t":5,"n":"Nose Long\/Short"},{"t":5,"n":"Nose Up\/Down"},{"t":5,"n":"Jaw Up\/Down"},{"t":5,"n":"Jaw Narrow\/Wide"},{"t":5,"n":"Jaw Farward\/Back"},{"t":5,"n":"Cheeks Up\/Down"},{"t":5,"n":"Cheeks Farward\/Back"},{"t":5,"n":"Eyes Up\/Down"},{"t":5,"n":"Eyes In\/Out"},{"t":5,"n":"Brows Up\/Down"},{"t":5,"n":"Brows In\/Out"},{"t":5,"n":"Brows Farward\/Back"},{"t":5,"n":"Lips Up\/Down"},{"t":5,"n":"Lips In\/Out"},{"t":5,"n":"Chin Narrow\/Wide"},{"t":5,"n":"Chin Up\/Down"},{"t":5,"n":"Chin Underbite\/Overbite"},{"t":5,"n":"Eyes Farward\/Back"},{"t":5,"n":"Unknown"}]},{"t":6,"n":"NAMA - Face parts","c":[{"t":3,"n":"Nose"},{"t":3,"n":"Unknown"},{"t":3,"n":"Eyes"},{"t":3,"n":"Mouth"}]},{"t":10,"n":"Tint Layers","c":[{"t":6,"n":"Layer","c":[{"t":3,"n":"TINI - Tint Index"}]}]}]}]},"name":"Bash.NPC.Race","hash":"$1058B5BF","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.Names.json ================================================ {"records":"ACTI,AMMO,ARMO,AVIF,BOOK,CLAS,CONT,DIAL,DOOR,ENCH,EXPL,FACT,FLOR,FURN,HAZD,HDPT,INGR,KEYM,LCTN,LIGH,MESG,MGEF,MISC,MSTT,NPC_,PERK,PROJ,QUST,RACE,REFR,SCRL,SHOU,SLGM,SNCT,SPEL,TREE,WATR,WEAP,WRLD,ALCH","description":"Names tag from Wrye Bash.\r\n\r\nUsed when the mod changes the names of things.","tree":{"records":[{"t":1,"p":1,"n":"ACTI - Activator","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"PNAM - Marker Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":3,"n":"Unused"}]},{"t":3,"n":"SNAM - Sound - Looping"},{"t":3,"n":"VNAM - Sound - Activation"},{"t":3,"n":"WNAM - Water Type"},{"t":2,"n":"RNAM - Activate Text Override"},{"t":3,"n":"FNAM - Flags"},{"t":3,"n":"KNAM - Interaction Keyword"}]},{"t":1,"p":1,"n":"AMMO - Ammunition","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":2,"n":"DESC - Description"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"DATA - Data","c":[{"t":3,"n":"Projectile"},{"t":3,"n":"Flags"},{"t":5,"n":"Damage"},{"t":3,"n":"Value"}]},{"t":2,"n":"ONAM - Short Name"}]},{"t":1,"p":1,"n":"ARMO - Armor","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"EITM - Object Effect"},{"t":3,"n":"EAMT - Enchantment Amount"},{"t":6,"n":"Male world model","c":[{"t":2,"n":"MOD2 - Model Filename"}]},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"}]},{"t":6,"n":"Female world model","c":[{"t":2,"n":"MOD4 - Model Filename"}]},{"t":6,"n":"Icon 2 (female)","c":[{"t":2,"n":"ICO2 - Large Icon filename"}]},{"t":6,"n":"BOD2 - Biped Body Template","c":[{"t":3,"n":"First Person Flags"},{"t":3,"n":"General Flags"},{"n":"Unused"},{"t":3,"n":"Armor Type"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":2,"n":"BMCT - Ragdoll Constraint Template"},{"t":3,"n":"ETYP - Equipment Type"},{"t":3,"n":"BIDS - Bash Impact Data Set"},{"t":3,"n":"BAMT - Alternate Block Material"},{"t":3,"n":"RNAM - Race"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":2,"n":"DESC - Description"},{"t":7,"n":"Armature","c":[{"t":3,"n":"MODL - Model Filename"}]},{"t":6,"n":"DATA - Data","c":[{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]},{"t":3,"n":"DNAM - Armor Rating"},{"t":3,"n":"TNAM - Template Armor"}]},{"t":1,"p":1,"n":"AVIF - Actor Value Information","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":2,"n":"ANAM - Abbreviation"},{"t":11,"n":"CNAM - Unknown"},{"t":6,"n":"AVSK - Skill","c":[{"t":5,"n":"Skill Use Mult"},{"t":5,"n":"Skill Offset Mult"},{"t":5,"n":"Skill Improve Mult"},{"t":5,"n":"Skill Improve Offset"}]},{"t":8,"n":"Perk Tree","c":[{"t":6,"n":"Node","c":[{"t":3,"n":"PNAM - Perk"}]}]}]},{"t":1,"p":1,"n":"BOOK - Book","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"}]},{"t":2,"n":"DESC - Book Text"},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"DATA - Data","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":12,"n":"Teaches"},{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]},{"t":3,"n":"INAM - Inventory Art"},{"t":2,"n":"CNAM - Description"}]},{"t":1,"p":1,"n":"CLAS - Class","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"}]},{"t":6,"n":"DATA - ","c":[{"t":11,"n":"Unknown"},{"t":3,"n":"Teaches"},{"t":3,"n":"Maximum training level"},{"t":7,"n":"Skill Weights","c":[{"t":3,"n":"Weight #0 (One Handed)"},{"t":3,"n":"Weight #1 (Two Handed)"},{"t":3,"n":"Weight #2 (Archery)"},{"t":3,"n":"Weight #3 (Block)"},{"t":3,"n":"Weight #4 (Smithing)"},{"t":3,"n":"Weight #5 (Heavy Armor)"},{"t":3,"n":"Weight #6 (Light Armor)"},{"t":3,"n":"Weight #7 (Pickpocket)"},{"t":3,"n":"Weight #8 (Lockpicking)"},{"t":3,"n":"Weight #9 (Sneak)"},{"t":3,"n":"Weight #10 (Alchemy)"},{"t":3,"n":"Weight #11 (Speech)"},{"t":3,"n":"Weight #12 (Alteration)"},{"t":3,"n":"Weight #13 (Conjuration)"},{"t":3,"n":"Weight #14 (Destruction)"},{"t":3,"n":"Weight #15 (Illusion)"},{"t":3,"n":"Weight #16 (Restoration)"},{"t":3,"n":"Weight #17 (Enchanting)"}]},{"t":5,"n":"Bleedout Default"},{"t":3,"n":"Voice Points"},{"t":7,"n":"Attribute Weights","c":[{"t":3,"n":"Weight #0 (Health)"},{"t":3,"n":"Weight #1 (Magicka)"},{"t":3,"n":"Weight #2 (Stamina)"},{"t":3,"n":"Weight #3 (Unknown)"}]}]}]},{"t":1,"p":1,"n":"CONT - Container","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":3,"n":"COCT - Count"},{"t":10,"n":"Items","c":[{"t":6,"n":"Item","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Flags"},{"t":5,"n":"Weight"}]},{"t":3,"n":"SNAM - Sound - Open"},{"t":3,"n":"QNAM - Sound - Close"}]},{"t":1,"p":1,"n":"DIAL - Dialog Topic","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":5,"n":"PNAM - Priority"},{"t":3,"n":"BNAM - Branch"},{"t":3,"n":"QNAM - Quest"},{"t":6,"n":"DATA - Data","c":[{"t":3,"n":"Topic Flags"},{"t":3,"n":"Category"},{"t":3,"n":"Subtype"}]},{"t":2,"n":"SNAM - Subtype Name"},{"t":3,"n":"TIFC - Info Count"}]},{"t":1,"p":1,"n":"DOOR - Door","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"SNAM - Sound - Open"},{"t":3,"n":"ANAM - Sound - Close"},{"t":3,"n":"BNAM - Sound - Loop"},{"t":3,"n":"FNAM - Flags"}]},{"t":1,"p":1,"n":"ENCH - Object Effect","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"ENIT - Effect Data","c":[{"t":3,"n":"Enchantment Cost"},{"t":3,"n":"Flags"},{"t":3,"n":"Cast Type"},{"t":3,"n":"Enchantment Amount"},{"t":3,"n":"Target Type"},{"t":3,"n":"Enchant Type"},{"t":5,"n":"Charge Time"},{"t":3,"n":"Base Enchantment"},{"t":3,"n":"Worn Restrictions"}]},{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":3,"n":"EFID - Base Effect"},{"t":6,"n":"EFIT - ","c":[{"t":5,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"}]}]}]}]},{"t":1,"p":1,"n":"EXPL - Explosion","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":3,"n":"EITM - Object Effect"},{"t":3,"n":"MNAM - Image Space Modifier"},{"t":6,"n":"DATA - Data","c":[{"t":3,"n":"Light"},{"t":3,"n":"Sound 1"},{"t":3,"n":"Sound 2"},{"t":3,"n":"Impact Data Set"},{"t":3,"n":"Placed Object"},{"t":3,"n":"Spawn Projectile"},{"t":5,"n":"Force"},{"t":5,"n":"Damage"},{"t":5,"n":"Radius"},{"t":5,"n":"IS Radius"},{"t":5,"n":"Vertical Offset Mult"},{"t":3,"n":"Flags"},{"t":3,"n":"Sound Level"}]}]},{"t":1,"p":1,"n":"FACT - Faction","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":10,"n":"Relations","c":[{"t":6,"n":"XNAM - Relation","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Modifier"},{"t":3,"n":"Group Combat Reaction"}]}]},{"t":6,"n":"DATA - Flags","c":[{"t":3,"n":"Flags"}]},{"t":3,"n":"JAIL - Exterior Jail Marker"},{"t":3,"n":"WAIT - Follower Wait Marker"},{"t":3,"n":"STOL - Stolen Goods Container"},{"t":3,"n":"PLCN - Player Inventory Container"},{"t":3,"n":"CRGR - Shared Crime Faction List"},{"t":3,"n":"JOUT - Jail Outfit"},{"t":6,"n":"CRVA - Crime Values","c":[{"t":3,"n":"Arrest"},{"t":3,"n":"Attack On Sight"},{"t":3,"n":"Murder"},{"t":3,"n":"Assault"},{"t":3,"n":"Trespass"},{"t":3,"n":"Pickpocket"},{"t":3,"n":"Unknown"},{"t":5,"n":"Steal Multiplier"},{"t":3,"n":"Escape"},{"t":3,"n":"Werewolf"}]},{"t":10,"n":"Ranks","c":[{"t":6,"n":"Rank","c":[{"t":3,"n":"RNAM - Rank#"}]}]},{"t":3,"n":"VEND - Vendor Buy\/Sell List"},{"t":3,"n":"VENC - Merchant Container"},{"t":6,"n":"VENV - Vendor Values","c":[{"t":3,"n":"Start Hour"},{"t":3,"n":"End Hour"},{"t":3,"n":"Radius"},{"t":11,"n":"Unknown 1"},{"t":3,"n":"Only Buys Stolen Items"},{"t":3,"n":"Not\/Sell Buy"},{"t":11,"n":"Unknown 2"}]},{"t":6,"n":"PLVD - Location","c":[{"t":3,"n":"Type"},{"t":12,"n":"Location Value"},{"t":3,"n":"Radius"}]},{"t":3,"n":"CITC - Condition Count"},{"t":8,"n":"Conditions","c":[{"t":6,"n":"Condition","c":[{"t":6,"n":"CTDA - ","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":12,"n":"Comparison Value"},{"t":3,"n":"Function"},{"t":11,"n":"Unused"},{"t":12,"n":"Parameter #1"},{"t":12,"n":"Parameter #2"},{"t":3,"n":"Run On"},{"t":12,"n":"Reference"},{"t":3,"n":"Parameter #3"}]}]}]}]},{"t":1,"p":1,"n":"FLOR - Flora","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":11,"n":"PNAM - Unknown"},{"t":2,"n":"RNAM - Activate Text Override"},{"t":11,"n":"FNAM - Unknown"},{"t":3,"n":"PFIG - Ingredient"},{"t":3,"n":"SNAM - Sound"},{"t":6,"n":"PFPC - Seasonal ingredient production","c":[{"t":3,"n":"Spring"},{"t":3,"n":"Summer "},{"t":3,"n":"Fall"},{"t":3,"n":"Winter"}]}]},{"t":1,"p":1,"n":"FURN - Furniture","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":11,"n":"PNAM - Unknown"},{"t":3,"n":"FNAM - Flags"},{"t":3,"n":"KNAM - Interaction Keyword"},{"t":3,"n":"MNAM - Active Markers \/ Flags"},{"t":6,"n":"WBDT - Workbench Data","c":[{"t":3,"n":"Bench Type"},{"t":3,"n":"Uses Skill"}]},{"t":3,"n":"NAM1 - Associated Spell"},{"t":8,"n":"Markers","c":[{"t":6,"n":"Marker","c":[{"t":3,"n":"ENAM - Marker Index"}]}]},{"t":8,"n":"Marker Entry Points","c":[{"t":6,"n":"FNPR - Marker","c":[{"t":3,"n":"Type"},{"t":3,"n":"Entry Points"}]}]},{"t":2,"n":"XMRK - Model Filename"}]},{"t":1,"p":1,"n":"HAZD - Hazard","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":3,"n":"MNAM - Image Space Modifier"},{"t":6,"n":"DATA - Data","c":[{"t":3,"n":"Limit"},{"t":5,"n":"Radius"},{"t":5,"n":"Lifetime"},{"t":5,"n":"Image Space Radius"},{"t":5,"n":"Target Interval"},{"t":3,"n":"Flags"},{"t":3,"n":"Spell"},{"t":3,"n":"Light"},{"t":3,"n":"Impact Data Set"},{"t":3,"n":"Sound"}]}]},{"t":1,"p":1,"n":"HDPT - Head Part","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":3,"n":"DATA - Flags"},{"t":3,"n":"PNAM - Type"},{"t":9,"n":"Extra Parts","c":[{"t":3,"n":"HNAM - Part"}]},{"t":8,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"NAM0 - Part Type"},{"t":2,"n":"NAM1 - Filename"}]}]},{"t":3,"n":"TNAM - Texture Set"},{"t":3,"n":"CNAM - Color"},{"t":3,"n":"RNAM - Valid Races"}]},{"t":1,"p":1,"n":"INGR - Ingredient","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"ETYP - Equipment Type"},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]},{"t":6,"n":"ENIT - Effect Data","c":[{"t":3,"n":"Ingredient Value"},{"t":3,"n":"Flags"}]},{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":3,"n":"EFID - Base Effect"},{"t":6,"n":"EFIT - ","c":[{"t":5,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"}]}]}]}]},{"t":1,"p":1,"n":"KEYM - Key","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]}]},{"t":1,"p":1,"n":"LCTN - Location","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":8,"n":"ACPR - Actor Cell Persistent Reference","c":[{"t":6,"n":" #0","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Location"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":8,"n":"LCPR - Location Cell Persistent Reference","c":[{"t":6,"n":" #0","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Location"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":7,"n":"RCPR - Reference Cell Persistent Reference","c":[{"t":3,"n":"Ref #0"}]},{"t":8,"n":"ACUN - Actor Cell Unique","c":[{"t":6,"n":" #0","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Ref"},{"t":3,"n":"Location"}]}]},{"t":8,"n":"LCUN - Location Cell Unique","c":[{"t":6,"n":" #0","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Ref"},{"t":3,"n":"Location"}]}]},{"t":7,"n":"RCUN - Reference Cell Unique","c":[{"t":3,"n":"Actor #0"}]},{"t":8,"n":"ACSR - Actor Cell Static Reference","c":[{"t":6,"n":" #0","c":[{"t":3,"n":"Loc Ref Type"},{"t":3,"n":"Marker"},{"t":3,"n":"Location"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":8,"n":"LCSR - Location Cell Static Reference","c":[{"t":6,"n":" #0","c":[{"t":3,"n":"Loc Ref Type"},{"t":3,"n":"Marker"},{"t":3,"n":"Location"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":7,"n":"RCSR - Reference Cell Static Reference","c":[{"t":3,"n":"Ref #0"}]},{"t":8,"n":"Actor Cell Encounter Cell","c":[{"t":6,"n":"ACEC - Unknown","c":[{"t":3,"n":"Location"},{"t":8,"n":"Coordinates","c":[{"t":6,"n":" #0","c":[{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]}]}]},{"t":8,"n":"Location Cell Encounter Cell","c":[{"t":6,"n":"LCEC - Unknown","c":[{"t":3,"n":"Location"},{"t":8,"n":"Coordinates","c":[{"t":6,"n":" #0","c":[{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]}]}]},{"t":8,"n":"Reference Cell Encounter Cell","c":[{"t":6,"n":"RCEC - Unknown","c":[{"t":3,"n":"Location"},{"t":8,"n":"Coordinates","c":[{"t":6,"n":" #0","c":[{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]}]}]},{"t":7,"n":"ACID - Actor Cell Marker Reference","c":[{"t":3,"n":"Ref #0"}]},{"t":7,"n":"LCID - Location Cell Marker Reference","c":[{"t":3,"n":"Ref #0"}]},{"t":8,"n":"ACEP - Actor Cell Enable Point","c":[{"t":6,"n":" #0","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Ref"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":8,"n":"LCEP - Location Cell Enable Point","c":[{"t":6,"n":" #0","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Ref"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":3,"n":"PNAM - Parent Location"},{"t":3,"n":"NAM1 - Music"},{"t":3,"n":"FNAM - Unreported Crime Faction"},{"t":3,"n":"MNAM - World Location Marker Ref"},{"t":5,"n":"RNAM - World Location Radius"},{"t":3,"n":"NAM0 - Horse Marker Ref"},{"t":6,"n":"CNAM - Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":1,"p":1,"n":"LIGH - Light","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"}]},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Time"},{"t":3,"n":"Radius"},{"t":6,"n":"Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":3,"n":"Unknown"}]},{"t":3,"n":"Flags"},{"t":5,"n":"Falloff Exponent"},{"t":5,"n":"FOV"},{"t":5,"n":"Near Clip"},{"t":6,"n":"Flicker Effect","c":[{"t":5,"n":"Period"},{"t":5,"n":"Intensity Amplitude"},{"t":5,"n":"Movement Amplitude"}]},{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]},{"t":5,"n":"FNAM - Fade value"},{"t":3,"n":"SNAM - Sound"}]},{"t":1,"p":1,"n":"MESG - Message","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"DESC - Description"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"INAM - Icon (unused)"},{"t":3,"n":"QNAM - Owner Quest"},{"t":3,"n":"DNAM - Flags","c":[{"t":4,"n":"Message Box"}]},{"t":3,"n":"TNAM - Display Time"},{"t":8,"n":"Menu Buttons","c":[{"t":6,"n":"Menu Button","c":[{"t":2,"n":"ITXT - Button Text"}]}]}]},{"t":1,"p":1,"n":"MGEF - Magic Effect","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"MDOB - Menu Display Object"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"Magic Effect Data","c":[{"t":6,"n":"DATA - Data","c":[{"t":3,"n":"Flags"},{"t":5,"n":"Base Cost"},{"t":12,"n":"Assoc. Item"},{"t":3,"n":"Magic Skill"},{"t":3,"n":"Resist Value"},{"t":3,"n":"Counter Effect count"},{"t":11,"n":"Unused"},{"t":3,"n":"Casting Light"},{"t":5,"n":"Taper Weight"},{"t":3,"n":"Hit Shader"},{"t":3,"n":"Enchant Shader"},{"t":3,"n":"Minimum Skill Level"},{"t":6,"n":"Spellmaking","c":[{"t":3,"n":"Area"},{"t":5,"n":"Casting Time"}]},{"t":5,"n":"Taper Curve"},{"t":5,"n":"Taper Duration"},{"t":5,"n":"Second AV Weight"},{"t":3,"n":"Archtype"},{"t":3,"n":"Actor Value"},{"t":3,"n":"Projectile"},{"t":3,"n":"Explosion"},{"t":3,"n":"Casting Type"},{"t":3,"n":"Delivery"},{"t":3,"n":"Second Actor Value"},{"t":3,"n":"Casting Art"},{"t":3,"n":"Hit Effect Art"},{"t":3,"n":"Impact Data"},{"t":5,"n":"Skill Usage Multiplier"},{"t":6,"n":"Dual Casting","c":[{"t":3,"n":"Art"},{"t":5,"n":"Scale"}]},{"t":3,"n":"Enchant Art"},{"t":11,"n":"Unknown"},{"t":11,"n":"Unknown"},{"t":3,"n":"Equip Ability"},{"t":3,"n":"Image Space Modifier"},{"t":3,"n":"Perk to Apply"},{"t":3,"n":"Casting Sound Level"},{"t":6,"n":"Script Effect AI","c":[{"t":5,"n":"Score"},{"t":5,"n":"Delay Time"}]}]}]},{"t":9,"n":"Counter Effects","c":[{"t":3,"n":"ESCE - Effect"}]},{"t":8,"n":"SNDD - Sounds","c":[{"t":6,"n":" #0","c":[{"t":3,"n":"Type"},{"t":3,"n":"Sound"}]}]},{"t":2,"n":"DNAM - Magic Item Description"},{"t":8,"n":"Conditions","c":[{"t":6,"n":"Condition","c":[{"t":6,"n":"CTDA - ","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":12,"n":"Comparison Value"},{"t":3,"n":"Function"},{"t":11,"n":"Unused"},{"t":12,"n":"Parameter #1"},{"t":12,"n":"Parameter #2"},{"t":3,"n":"Run On"},{"t":12,"n":"Reference"},{"t":3,"n":"Parameter #3"}]}]}]}]},{"t":1,"p":1,"n":"MISC - Misc. Item","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"DATA - Data","c":[{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]}]},{"t":1,"p":1,"n":"MSTT - Moveable Static","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"DATA - Flags"},{"t":3,"n":"SNAM - Looping Sound"}]},{"t":1,"p":1,"n":"NPC_ - Non-Player Character (Actor)","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Magicka Offset"},{"t":3,"n":"Stamina Offset"},{"t":12,"n":"Level"},{"t":3,"n":"Calc min level"},{"t":3,"n":"Calc max level"},{"t":3,"n":"Speed Multiplier"},{"t":3,"n":"Disposition Base (unused)"},{"t":3,"n":"Template Flags"},{"t":3,"n":"Health Offset"},{"t":3,"n":"Bleedout Override"}]},{"t":10,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"VTCK - Voice"},{"t":3,"n":"TPLT - Template"},{"t":3,"n":"RNAM - Race"},{"t":3,"n":"SPCT - Count"},{"t":9,"n":"Actor Effects","c":[{"t":3,"n":"SPLO - Actor Effect"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"WNAM - Worn Armor"},{"t":3,"n":"ANAM - Far away model"},{"t":3,"n":"ATKR - Attack Race"},{"t":10,"n":"Attacks","c":[{"t":6,"n":"Attack","c":[{"t":6,"n":"ATKD - Attack Data","c":[{"t":5,"n":"Damage Mult"},{"t":5,"n":"Attack Chance"},{"t":3,"n":"Attack Spell"},{"t":3,"n":"Attack Flags"},{"t":5,"n":"Attack Angle"},{"t":5,"n":"Strike Angle"},{"t":5,"n":"Stagger"},{"t":3,"n":"Attack Type"},{"t":5,"n":"Knockdown"},{"t":5,"n":"Recovery Time"},{"t":5,"n":"Stamina Mult"}]}]}]},{"t":3,"n":"SPOR - Spectator override package list"},{"t":3,"n":"OCOR - Observe dead body override package list"},{"t":3,"n":"GWOR - Guard warn override package list"},{"t":3,"n":"ECOR - Combat override package list"},{"t":3,"n":"PRKZ - Perk Count"},{"t":10,"n":"Perks","c":[{"t":6,"n":"PRKR - Perk","c":[{"t":3,"n":"Perk"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"COCT - Count"},{"t":10,"n":"Items","c":[{"t":6,"n":"Item","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]}]},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Mood"},{"t":3,"n":"Assistance"},{"t":6,"n":"Aggro","c":[{"t":3,"n":"Aggro Radius Behavior"},{"t":3,"n":"Unknown"},{"t":3,"n":"Warn"},{"t":3,"n":"Warn\/Attack"},{"t":3,"n":"Attack"}]}]},{"t":7,"n":"Packages","c":[{"t":3,"n":"PKID - Package"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":3,"n":"CNAM - Class"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"n":"SHRT - Short Name"},{"t":11,"n":"DATA - Marker"},{"t":6,"n":"DNAM - Player Skills","c":[{"t":7,"n":"Skill Values","c":[{"t":3,"n":"Skill #0 (OneHanded)"},{"t":3,"n":"Skill #1 (TwoHanded)"},{"t":3,"n":"Skill #2 (Marksman)"},{"t":3,"n":"Skill #3 (Block)"},{"t":3,"n":"Skill #4 (Smithing)"},{"t":3,"n":"Skill #5 (HeavyArmor)"},{"t":3,"n":"Skill #6 (LightArmor)"},{"t":3,"n":"Skill #7 (Pickpocket)"},{"t":3,"n":"Skill #8 (Lockpicking)"},{"t":3,"n":"Skill #9 (Sneak)"},{"t":3,"n":"Skill #10 (Alchemy)"},{"t":3,"n":"Skill #11 (Speechcraft)"},{"t":3,"n":"Skill #12 (Alteration)"},{"t":3,"n":"Skill #13 (Conjuration)"},{"t":3,"n":"Skill #14 (Destruction)"},{"t":3,"n":"Skill #15 (Illusion)"},{"t":3,"n":"Skill #16 (Restoration)"},{"t":3,"n":"Skill #17 (Enchanting)"}]},{"t":7,"n":"Skill Offsets","c":[{"t":3,"n":"Skill #0 (OneHanded)"},{"t":3,"n":"Skill #1 (TwoHanded)"},{"t":3,"n":"Skill #2 (Marksman)"},{"t":3,"n":"Skill #3 (Block)"},{"t":3,"n":"Skill #4 (Smithing)"},{"t":3,"n":"Skill #5 (HeavyArmor)"},{"t":3,"n":"Skill #6 (LightArmor)"},{"t":3,"n":"Skill #7 (Pickpocket)"},{"t":3,"n":"Skill #8 (Lockpicking)"},{"t":3,"n":"Skill #9 (Sneak)"},{"t":3,"n":"Skill #10 (Alchemy)"},{"t":3,"n":"Skill #11 (Speechcraft)"},{"t":3,"n":"Skill #12 (Alteration)"},{"t":3,"n":"Skill #13 (Conjuration)"},{"t":3,"n":"Skill #14 (Destruction)"},{"t":3,"n":"Skill #15 (Illusion)"},{"t":3,"n":"Skill #16 (Restoration)"},{"t":3,"n":"Skill #17 (Enchanting)"}]},{"t":3,"n":"Health"},{"t":3,"n":"Magicka"},{"t":3,"n":"Stamina"},{"t":11,"n":"Unused"},{"t":5,"n":"Far away model distance"},{"t":3,"n":"Geared up weapons"},{"t":11,"n":"Unused"}]},{"t":9,"n":"Head Parts","c":[{"t":3,"n":"PNAM - Head Part"}]},{"t":3,"n":"HCLF - Hair Color"},{"t":3,"n":"ZNAM - Combat Style"},{"t":3,"n":"GNAM - Gift Filter"},{"t":11,"n":"NAM5 - Unknown"},{"t":5,"n":"NAM6 - Height"},{"t":5,"n":"NAM7 - Weight"},{"t":3,"n":"NAM8 - Sound Level"},{"t":10,"n":"Sound Types","c":[{"t":6,"n":"Sound Type","c":[{"t":3,"n":"CSDT - Type"},{"t":10,"n":"Sounds","c":[{"t":6,"n":"Sound","c":[{"t":3,"n":"CSDI - Sound"},{"t":3,"n":"CSDC - Sound Chance"}]}]}]}]},{"t":3,"n":"CSCR - Inherits Sounds From"},{"t":3,"n":"DOFT - Default outfit"},{"t":3,"n":"SOFT - Sleeping outfit"},{"t":3,"n":"DPLT - Default Package List"},{"t":3,"n":"CRIF - Crime faction"},{"t":3,"n":"FTST - Head texture"},{"t":6,"n":"QNAM - Texture lighting","c":[{"t":5,"n":"Red"},{"t":5,"n":"Green"},{"t":5,"n":"Blue"}]},{"t":6,"n":"NAM9 - Face morph","c":[{"t":5,"n":"Nose Long\/Short"},{"t":5,"n":"Nose Up\/Down"},{"t":5,"n":"Jaw Up\/Down"},{"t":5,"n":"Jaw Narrow\/Wide"},{"t":5,"n":"Jaw Farward\/Back"},{"t":5,"n":"Cheeks Up\/Down"},{"t":5,"n":"Cheeks Farward\/Back"},{"t":5,"n":"Eyes Up\/Down"},{"t":5,"n":"Eyes In\/Out"},{"t":5,"n":"Brows Up\/Down"},{"t":5,"n":"Brows In\/Out"},{"t":5,"n":"Brows Farward\/Back"},{"t":5,"n":"Lips Up\/Down"},{"t":5,"n":"Lips In\/Out"},{"t":5,"n":"Chin Narrow\/Wide"},{"t":5,"n":"Chin Up\/Down"},{"t":5,"n":"Chin Underbite\/Overbite"},{"t":5,"n":"Eyes Farward\/Back"},{"t":5,"n":"Unknown"}]},{"t":6,"n":"NAMA - Face parts","c":[{"t":3,"n":"Nose"},{"t":3,"n":"Unknown"},{"t":3,"n":"Eyes"},{"t":3,"n":"Mouth"}]},{"t":10,"n":"Tint Layers","c":[{"t":6,"n":"Layer","c":[{"t":3,"n":"TINI - Tint Index"}]}]}]},{"t":1,"p":1,"n":"PERK - Perk","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":6,"n":"Perk VMAD","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]},{"t":6,"n":"Script Fragments Perk","c":[{"t":3,"n":"Unknown"},{"t":2,"n":"fileName"},{"t":9,"n":"Perk Fragments","c":[{"t":6,"n":"Perk Fragment","c":[{"t":3,"n":"Fragment Index"},{"t":3,"n":"Unknown"},{"t":3,"n":"Unknown"},{"t":2,"n":"scriptName"},{"t":2,"n":"fragmentName"}]}]}]}]}]}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"}]},{"t":8,"n":"Conditions","c":[{"t":6,"n":"Condition","c":[{"t":6,"n":"CTDA - ","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":12,"n":"Comparison Value"},{"t":3,"n":"Function"},{"t":11,"n":"Unused"},{"t":12,"n":"Parameter #1"},{"t":12,"n":"Parameter #2"},{"t":3,"n":"Run On"},{"t":12,"n":"Reference"},{"t":3,"n":"Parameter #3"}]}]}]},{"t":6,"n":"DATA - Data","c":[{"t":3,"n":"Trait"},{"t":3,"n":"Level"},{"t":3,"n":"Num Ranks"},{"t":3,"n":"Playable"},{"t":3,"n":"Hidden"}]},{"t":3,"n":"NNAM - Next Perk"},{"t":10,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":6,"n":"PRKE - Header","c":[{"t":3,"n":"Type"},{"t":3,"n":"Rank"},{"t":3,"n":"Priority"}]},{"t":12,"n":"DATA - Effect Data","c":[{"t":6,"n":"Quest + Stage","c":[{"t":3,"n":"Quest"},{"t":3,"n":"Quest Stage"},{"t":11,"n":"Unused"}]}]},{"n":"PRKF - End Marker"}]}]}]},{"t":1,"p":1,"n":"PROJ - Projectile","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"DATA - Data","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Type"},{"t":5,"n":"Gravity"},{"t":5,"n":"Speed"},{"t":5,"n":"Range"},{"t":3,"n":"Light"},{"t":3,"n":"Muzzle Flash - Light"},{"t":5,"n":"Tracer Chance"},{"t":5,"n":"Explosion - Alt. Trigger - Proximity"},{"t":5,"n":"Explosion - Alt. Trigger - Timer"},{"t":3,"n":"Explosion"},{"t":3,"n":"Sound"},{"t":5,"n":"Muzzle Flash - Duration"},{"t":5,"n":"Fade Duration"},{"t":5,"n":"Impact Force"},{"t":3,"n":"Sound - Countdown"},{"t":3,"n":"Sound - Disable"},{"t":3,"n":"Default Weapon Source"},{"t":5,"n":"Cone Spread"},{"t":5,"n":"Collision Radius"},{"t":5,"n":"Lifetime"},{"t":5,"n":"Relaunch Interval"},{"t":3,"n":"Decal Data"},{"t":3,"n":"Collision Layer"}]},{"t":6,"n":"Muzzle Flash Model","c":[{"t":2,"n":"NAM1 - Model Filename"}]},{"t":3,"n":"VNAM - Sound Level"}]},{"t":1,"p":1,"n":"QUST - Quest","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":6,"n":"Quest VMAD","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]},{"t":6,"n":"Script Fragments Quest","c":[{"t":3,"n":"Unknown"},{"t":3,"n":"fragmentCount"},{"t":2,"n":"fileName"},{"t":9,"n":"Quest Fragments","c":[{"t":6,"n":"Quest Fragment","c":[{"t":3,"n":"Quest Stage"},{"t":3,"n":"Unknown"},{"t":3,"n":"Quest Stage Index"},{"t":3,"n":"Unknown"},{"t":2,"n":"scriptName"},{"t":2,"n":"fragmentName"}]}]},{"t":9,"n":"Aliases","c":[{"t":6,"n":"Alias","c":[{"t":12,"n":"Object Union","c":[{"t":6,"n":"Object v2","c":[{"t":3,"n":"FormID"},{"t":3,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":9,"n":"Alias Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]}]}]}]}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"DNAM - General","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Priority"},{"t":3,"n":"Form Version"},{"t":11,"n":"Unknown"},{"t":3,"n":"Type"}]},{"t":2,"n":"ENAM - Event"},{"t":7,"n":"Text Display Globals","c":[{"t":3,"n":"QTGL - Global"}]},{"t":2,"n":"FLTR - Object Window Filter"},{"t":6,"n":"Quest Dialogue Conditions","c":[{"t":8,"n":"Conditions","c":[{"t":6,"n":"Condition","c":[{"t":6,"n":"CTDA - ","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":12,"n":"Comparison Value"},{"t":3,"n":"Function"},{"t":11,"n":"Unused"},{"t":12,"n":"Parameter #1"},{"t":12,"n":"Parameter #2"},{"t":3,"n":"Run On"},{"t":12,"n":"Reference"},{"t":3,"n":"Parameter #3"}]}]}]}]},{"n":"NEXT - Marker"},{"t":8,"n":"Conditions","c":[{"t":6,"n":"Condition","c":[{"t":6,"n":"CTDA - ","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":12,"n":"Comparison Value"},{"t":3,"n":"Function"},{"t":11,"n":"Unused"},{"t":12,"n":"Parameter #1"},{"t":12,"n":"Parameter #2"},{"t":3,"n":"Run On"},{"t":12,"n":"Reference"},{"t":3,"n":"Parameter #3"}]}]}]},{"t":10,"n":"Stages","c":[{"t":6,"n":"Stage","c":[{"t":6,"n":"INDX - Stage Index","c":[{"t":3,"n":"Stage Index"},{"t":3,"n":"Flags"},{"t":3,"n":"Unknown"}]}]}]},{"t":8,"n":"Objectives","c":[{"t":6,"n":"Objective","c":[{"t":3,"n":"QOBJ - Objective Index"},{"t":2,"n":"NNAM - Display Text"}]}]},{"t":11,"n":"ANAM - Aliases Marker"},{"t":8,"n":"Aliases","c":[{"t":6,"n":"Alias","c":[{"t":3,"n":"ALST - Reference Alias ID"},{"n":"ALED - Alias End"}]}]},{"t":2,"n":"NNAM - Description"},{"t":8,"n":"Targets","c":[{"t":6,"n":"Target","c":[{"t":6,"n":"QSTA - Target","c":[{"t":3,"n":"Target"},{"t":3,"n":"Flags"},{"t":11,"n":"Unknown"}]}]}]}]},{"t":1,"p":1,"n":"RACE - Race","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":3,"n":"SPCT - Count"},{"t":9,"n":"Actor Effects","c":[{"t":3,"n":"SPLO - Actor Effect"}]},{"t":3,"n":"WNAM - Skin"},{"t":6,"n":"BOD2 - Biped Body Template","c":[{"t":3,"n":"First Person Flags"},{"t":3,"n":"General Flags"},{"n":"Unused"},{"t":3,"n":"Armor Type"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"DATA - ","c":[{"t":10,"n":"Skill Boosts","c":[{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]}]},{"t":11,"n":"Unknown"},{"t":5,"n":"Male Height"},{"t":5,"n":"Female Height"},{"t":5,"n":"Male Weight"},{"t":5,"n":"Female Weight"},{"t":3,"n":"Flags"},{"t":5,"n":"Starting Health"},{"t":5,"n":"Starting Magicka"},{"t":5,"n":"Starting Stamina"},{"t":5,"n":"Base Carry Weight"},{"t":5,"n":"Base Mass"},{"t":5,"n":"Acceleration rate"},{"t":5,"n":"Deceleration rate"},{"t":3,"n":"Size"},{"t":3,"n":"Head Biped Object"},{"t":3,"n":"Hair Biped Object"},{"t":5,"n":"Injured Health Pct"},{"t":3,"n":"Shield Biped Object"},{"t":5,"n":"Health Regen"},{"t":5,"n":"Magicka Regen"},{"t":5,"n":"Stamina Regen"},{"t":5,"n":"Unarmed Damage"},{"t":5,"n":"Unarmed Reach"},{"t":3,"n":"Body Biped Object"},{"t":5,"n":"Aim Angle Tolerance"},{"t":5,"n":"Flight Radius"},{"t":5,"n":"Angular Acceleration Rate"},{"t":5,"n":"Angular Tolerance"},{"t":3,"n":"Flags 2"},{"t":6,"n":"Mount Data","c":[{"t":5,"n":"Offset X"},{"t":5,"n":"Offset Y"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"}]}]},{"n":"MNAM - Male Marker"},{"t":2,"n":"ANAM - Male Skeletal Model"},{"t":11,"n":"MODT - Texture Files Hashes"},{"n":"FNAM - Female Marker"},{"t":2,"n":"ANAM - Female Skeletal Model"},{"t":11,"n":"MODT - Texture Files Hashes"},{"n":"NAM2 - Marker NAM2 #1"},{"t":9,"n":"Movement Type Names","c":[{"t":2,"n":"MTNM - Name"}]},{"t":7,"n":"VTCK - Voices","c":[{"t":3,"n":"Voice #0 (Male)"},{"t":3,"n":"Voice #1 (Female)"}]},{"t":7,"n":"DNAM - Decapitate Armors","c":[{"t":3,"n":"Decapitate Armor #0 (Male)"},{"t":3,"n":"Decapitate Armor #1 (Female)"}]},{"t":7,"n":"HCLF - Default Hair Colors","c":[{"t":3,"n":"Default Hair Color #0 (Male)"},{"t":3,"n":"Default Hair Color #1 (Female)"}]},{"t":3,"n":"TINL - Total Number of Tints in List"},{"t":5,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"n":"UNAM - FaceGen - Face clamp"},{"t":3,"n":"ATKR - Attack Race"},{"t":10,"n":"Attacks","c":[{"t":6,"n":"Attack","c":[{"t":6,"n":"ATKD - Attack Data","c":[{"t":5,"n":"Damage Mult"},{"t":5,"n":"Attack Chance"},{"t":3,"n":"Attack Spell"},{"t":3,"n":"Attack Flags"},{"t":5,"n":"Attack Angle"},{"t":5,"n":"Strike Angle"},{"t":5,"n":"Stagger"},{"t":3,"n":"Attack Type"},{"t":5,"n":"Knockdown"},{"t":5,"n":"Recovery Time"},{"t":5,"n":"Stamina Mult"}]}]}]},{"t":6,"n":"Body Data","c":[{"n":"NAM1 - Body Data Marker"},{"t":6,"n":"Male Body Data","c":[{"n":"MNAM - Male Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"}]}]}]},{"t":6,"n":"Female Body Data","c":[{"n":"FNAM - Female Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"}]}]}]}]},{"t":9,"n":"HNAM - Hairs","c":[{"t":3,"n":"Hair"}]},{"t":9,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eye"}]},{"t":3,"n":"GNAM - Body Part Data"},{"n":"NAM2 - Marker NAM2 #2"},{"n":"NAM3 - Marker NAM3 #3"},{"t":6,"n":"Male Behavior Graph","c":[{"n":"MNAM - Male Data Marker"}]},{"t":6,"n":"Female Behavior Graph","c":[{"n":"FNAM - Female Data Marker"}]},{"t":3,"n":"NAM4 - Material Type"},{"t":3,"n":"NAM5 - Impact Data Set"},{"t":3,"n":"NAM7 - Decapitation FX"},{"t":3,"n":"ONAM - Open Loot Sound"},{"t":3,"n":"LNAM - Close Loot Sound"},{"t":7,"n":"Biped Object Names","c":[{"t":2,"n":"NAME - Name"}]},{"t":10,"n":"Movement Types","c":[{"t":6,"n":"Movement Types","c":[{"t":3,"n":"MTYP - Movement Type"}]}]},{"t":3,"n":"VNAM - Equipment Flags"},{"t":9,"n":"Equip Slots","c":[{"t":3,"n":"QNAM - Equip Slot"}]},{"t":3,"n":"UNES - Unarmed Equip Slot"},{"t":7,"n":"Phoneme Target Names","c":[{"t":2,"n":"PHTN - Name"}]},{"t":6,"n":"FaceFX Phonemes","c":[{"t":6,"n":"IY","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]}]},{"t":3,"n":"WKMV - Base Movement Default - Walk"},{"t":3,"n":"RNMV - Base Movement Default - Run"},{"t":3,"n":"SWMV - Base Movement Default - Swim"},{"t":3,"n":"FLMV - Base Movement Default - Fly"},{"t":3,"n":"SNMV - Base Movement Default - Sneak"},{"t":3,"n":"SPMV - Base Movement Default - Sprint"},{"t":6,"n":"Head Data","c":[{"n":"NAM0 - Head Data Marker"},{"t":6,"n":"Male Head Data","c":[{"n":"MNAM - Male Data Marker"}]},{"t":6,"n":"Female Head Data","c":[{"n":"NAM0 - Head Data Marker"},{"n":"FNAM - Female Data Marker"}]}]},{"t":3,"n":"NAM8 - Morph race"},{"t":3,"n":"RNAM - Armor race"}]},{"t":1,"p":1,"n":"REFR - Placed Object","c":[{"t":3,"n":"Cell"},{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags","c":[{"t":4,"n":"Persistent"}]},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":3,"n":"NAME - Base"},{"t":6,"n":"XMBO - Bound Half Extents","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]},{"t":6,"n":"XPRM - Primitive","c":[{"t":6,"n":"Bounds","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]},{"t":6,"n":"Color","c":[{"t":5,"n":"Red"},{"t":5,"n":"Green"},{"t":5,"n":"Blue"}]},{"t":5,"n":"Unknown"},{"t":3,"n":"Type"}]},{"t":11,"n":"XORD - Unknown"},{"t":6,"n":"XOCP - Occlusion Plane Data","c":[{"t":6,"n":"Size","c":[{"t":5,"n":"Width"},{"t":5,"n":"Height"}]},{"t":6,"n":"Position","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]},{"t":6,"n":"Rotation (Quaternion?)","c":[{"t":5,"n":"q1"},{"t":5,"n":"q2"},{"t":5,"n":"q3"},{"t":5,"n":"q4"}]}]},{"t":8,"n":"XPOD - Portal Data","c":[{"t":6,"n":"References #0","c":[{"t":3,"n":"Origin"},{"t":3,"n":"Destination"}]}]},{"t":6,"n":"XPTL - Room Portal (unused)","c":[{"t":6,"n":"Size","c":[{"t":5,"n":"Width"},{"t":5,"n":"Height"}]},{"t":6,"n":"Position","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]},{"t":6,"n":"Rotation (Quaternion?)","c":[{"t":5,"n":"q1"},{"t":5,"n":"q2"},{"t":5,"n":"q3"},{"t":5,"n":"q4"}]}]},{"t":6,"n":"Bound Data","c":[{"t":6,"n":"XRMR - Header","c":[{"t":3,"n":"Linked Rooms Count"},{"t":3,"n":"Flags"},{"t":11,"n":"Unknown"}]}]},{"n":"XMBP - MultiBound Primitive Marker"},{"t":11,"n":"XRGD - Ragdoll Data"},{"t":11,"n":"XRGB - Ragdoll Biped Data"},{"t":5,"n":"XRDS - Radius"},{"t":10,"n":"Reflected\/Refracted By","c":[{"t":6,"n":"XPWR - Water","c":[{"t":3,"n":"Reference"},{"t":3,"n":"Type"}]}]},{"t":9,"n":"Lit Water","c":[{"t":3,"n":"XLTW - Water"}]},{"t":3,"n":"XEMI - Emittance"},{"t":6,"n":"XLIG - Light Data","c":[{"t":5,"n":"FOV 90+\/-"},{"t":5,"n":"Fade 1.35+\/-"},{"t":11,"n":"Unknown"},{"t":5,"n":"Shadow Depth Bias"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"XALP - Alpha","c":[{"t":3,"n":"Cutoff"},{"t":3,"n":"Base"}]},{"t":6,"n":"XTEL - Teleport Destination","c":[{"t":3,"n":"Door"},{"t":6,"n":"Position\/Rotation","c":[{"t":6,"n":"Position","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]},{"t":6,"n":"Rotation","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]}]},{"t":3,"n":"Flags"}]},{"t":3,"n":"XTNM - Teleport Message Box"},{"t":3,"n":"XMBR - MultiBound Reference"},{"t":11,"n":"XWCN - Unknown"},{"t":11,"n":"XWCS - Unknown"},{"t":6,"n":"XWCU - Water Velocity","c":[{"t":5,"n":"X Offset"},{"t":5,"n":"Y Offset"},{"t":5,"n":"Z Offset"},{"t":11,"n":"Unknown"},{"t":5,"n":"X Angle"},{"t":5,"n":"Y Angle"},{"t":5,"n":"Z Angle"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"XCVL - Unknown","c":[{"t":11,"n":"Unknown"},{"t":5,"n":"X Angle"},{"t":11,"n":"Unknown"}]},{"t":3,"n":"XCZR - Unknown"},{"t":11,"n":"XCZA - Unknown"},{"t":3,"n":"XCZC - Unknown"},{"t":5,"n":"XSCL - Scale"},{"t":3,"n":"XSPC - Spawn Container"},{"t":6,"n":"Activate Parents","c":[{"t":3,"n":"XAPD - Flags"}]},{"t":3,"n":"XLIB - Leveled Item Base Object"},{"t":3,"n":"XLCM - Level Modifier"},{"t":3,"n":"XLCN - Persistent Location"},{"t":3,"n":"XTRI - Collision Layer"},{"t":6,"n":"XLOC - Lock Data","c":[{"t":3,"n":"Level"},{"t":11,"n":"Unused"},{"t":3,"n":"Key"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"},{"t":11,"n":"Unused"}]},{"t":3,"n":"XEZN - Encounter Zone"},{"t":6,"n":"XNDP - Navigation Door Link","c":[{"t":3,"n":"Navigation Mesh"},{"t":3,"n":"Teleport Marker Triangle"},{"t":11,"n":"Unused"}]},{"t":7,"n":"XLRT - Location Ref Type","c":[{"t":3,"n":"Ref #0"}]},{"n":"XIS2 - Ignored by Sandbox"},{"t":6,"n":"Ownership","c":[{"t":3,"n":"XOWN - Owner"}]},{"t":3,"n":"XCNT - Item Count"},{"t":5,"n":"XCHG - Charge"},{"t":3,"n":"XLRL - Location Reference"},{"t":6,"n":"XESP - Enable Parent","c":[{"t":3,"n":"Reference"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"n":"Linked References","c":[{"t":6,"n":"XLKR - Linked Reference","c":[{"t":3,"n":"Keyword\/Ref"},{"t":3,"n":"Ref"}]}]},{"t":8,"n":"Patrol","c":[{"t":6,"n":"Data","c":[{"t":5,"n":"XPRD - Idle Time"},{"n":"XPPA - Patrol Script Marker"},{"t":3,"n":"INAM - Idle"}]}]},{"t":3,"n":"XACT - Action Flag"},{"t":5,"n":"XHTW - Head-Tracking Weight"},{"t":5,"n":"XFVC - Favor Cost"},{"n":"ONAM - Open by Default"},{"t":6,"p":1,"n":"Map Marker","c":[{"n":"XMRK - Map Marker Data"},{"t":3,"n":"FNAM - Map Flags"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"TNAM - ","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"XATR - Attach Ref"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown #0"},{"t":5,"n":"Unknown #1"},{"t":5,"n":"Unknown #2"}]},{"t":6,"n":"DATA - Position\/Rotation","c":[{"t":6,"n":"Position","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]},{"t":6,"n":"Rotation","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"SCRL - Scroll","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":3,"n":"MDOB - Menu Display Object"},{"t":3,"n":"ETYP - Equipment Type"},{"t":2,"n":"DESC - Description"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":6,"n":"DATA - Item","c":[{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]},{"t":6,"n":"SPIT - Data","c":[{"t":3,"n":"Base Cost"},{"t":3,"n":"Flags"},{"t":3,"n":"Type"},{"t":5,"n":"Charge Time"},{"t":3,"n":"Cast Type"},{"t":3,"n":"Target Type"},{"t":5,"n":"Cast Duration"},{"t":5,"n":"Range"},{"t":3,"n":"Half-cost Perk"}]},{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":3,"n":"EFID - Base Effect"},{"t":6,"n":"EFIT - ","c":[{"t":5,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"}]}]}]}]},{"t":1,"p":1,"n":"SHOU - Shout","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"MDOB - Menu Display Object"},{"t":2,"n":"DESC - Description"},{"t":8,"n":"Words of Power","c":[{"t":6,"n":"SNAM - ","c":[{"t":3,"n":"Word"},{"t":3,"n":"Spell"},{"t":5,"n":"Recovery Time"}]}]}]},{"t":1,"p":1,"n":"SLGM - Soul Gem","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]},{"t":3,"n":"SOUL - Contained Soul"},{"t":3,"n":"SLCP - Maximum Capacity"},{"t":3,"n":"NAM0 - Linked To"}]},{"t":1,"p":1,"n":"SNCT - Sound Category","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"FNAM - Flags"},{"t":3,"n":"PNAM - Parent"},{"t":3,"n":"VNAM - Static Volume Multiplier"},{"t":3,"n":"UNAM - Default Menu Value"}]},{"t":1,"p":1,"n":"SPEL - Spell","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":3,"n":"MDOB - Menu Display Object"},{"t":3,"n":"ETYP - Equipment Type"},{"t":2,"n":"DESC - Description"},{"t":6,"n":"SPIT - Data","c":[{"t":3,"n":"Base Cost"},{"t":3,"n":"Flags"},{"t":3,"n":"Type"},{"t":5,"n":"Charge Time"},{"t":3,"n":"Cast Type"},{"t":3,"n":"Target Type"},{"t":5,"n":"Cast Duration"},{"t":5,"n":"Range"},{"t":3,"n":"Half-cost Perk"}]},{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":3,"n":"EFID - Base Effect"},{"t":6,"n":"EFIT - ","c":[{"t":5,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"}]}]}]}]},{"t":1,"p":1,"n":"TREE - Tree","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":3,"n":"PFIG - Ingredient"},{"t":3,"n":"SNAM - Harvest Sound"},{"t":6,"n":"PFPC - Ingredient Production","c":[{"t":3,"n":"Spring"},{"t":3,"n":"Summer"},{"t":3,"n":"Fall"},{"t":3,"n":"Winter"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"CNAM - Tree Data","c":[{"t":5,"n":"Trunk Flexibility"},{"t":5,"n":"Branch Flexibility"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Leaf Amplitude"},{"t":5,"n":"Leaf Frequency"}]}]},{"t":1,"p":1,"n":"WATR - Water","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":7,"n":"Unused","c":[{"t":2,"n":"NNAM - Noise Map"}]},{"t":3,"n":"ANAM - Opacity"},{"t":3,"n":"FNAM - Flags"},{"t":11,"n":"MNAM - Unused"},{"t":3,"n":"TNAM - Material"},{"t":3,"n":"SNAM - Open Sound"},{"t":3,"n":"XNAM - Spell"},{"t":3,"n":"INAM - Image Space"},{"t":3,"n":"DATA - Damage Per Second"},{"t":6,"n":"DNAM - Visual Data","c":[{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Specular Properties - Sun Specular Power"},{"t":5,"n":"Water Properties - Reflectivity Amount"},{"t":5,"n":"Water Properties - Fresnel Amount"},{"t":11,"n":"Unknown"},{"t":5,"n":"Fog Properties - Above Water - Fog Distance - Near Plane"},{"t":5,"n":"Fog Properties - Above Water - Fog Distance - Far Plane"},{"t":6,"n":"Shallow Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Deep Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Reflection Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":11,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Displacement Simulator - Starting Size"},{"t":5,"n":"Displacement Simulator - Force"},{"t":5,"n":"Displacement Simulator - Velocity"},{"t":5,"n":"Displacement Simulator - Falloff"},{"t":5,"n":"Displacement Simulator - Dampner"},{"t":5,"n":"Unknown"},{"t":5,"n":"Noise Properties - Noise Falloff"},{"t":5,"n":"Noise Properties - Layer One - Wind Direction"},{"t":5,"n":"Noise Properties - Layer Two - Wind Direction"},{"t":5,"n":"Noise Properties - Layer Three - Wind Direction"},{"t":5,"n":"Noise Properties - Layer One - Wind Speed"},{"t":5,"n":"Noise Properties - Layer Two - Wind Speed"},{"t":5,"n":"Noise Properties - Layer Three - Wind Speed"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Fog Properties - Above Water - Fog Amount"},{"t":5,"n":"Unknown"},{"t":5,"n":"Fog Properties - Under Water - Fog Amount"},{"t":5,"n":"Fog Properties - Under Water - Fog Distance - Near Plane"},{"t":5,"n":"Fog Properties - Under Water - Fog Distance - Far Plane"},{"t":5,"n":"Water Properties - Refraction Magnitude"},{"t":5,"n":"Specular Properties - Specular Power"},{"t":5,"n":"Unknown"},{"t":5,"n":"Specular Properties - Specular Radius"},{"t":5,"n":"Specular Properties - Specular Brightness"},{"t":5,"n":"Noise Properties - Layer One - UV Scale"},{"t":5,"n":"Noise Properties - Layer Two - UV Scale"},{"t":5,"n":"Noise Properties - Layer Three - UV Scale"},{"t":5,"n":"Noise Properties - Layer One - Amplitude Scale"},{"t":5,"n":"Noise Properties - Layer Two - Amplitude Scale"},{"t":5,"n":"Noise Properties - Layer Three - Amplitude Scale"},{"t":5,"n":"Water Properties - Reflection Magnitude"},{"t":5,"n":"Specular Properties - Sun Sparkle Magnitude"},{"t":5,"n":"Specular Properties - Sun Specular Magnitude"},{"t":5,"n":"Depth Properties - Reflections"},{"t":5,"n":"Depth Properties - Refraction"},{"t":5,"n":"Depth Properties - Normals"},{"t":5,"n":"Depth Properties - Specular Lighting"},{"t":5,"n":"Specular Properties - Sun Sparkle Power"}]},{"t":11,"n":"GNAM - Unused"},{"t":6,"n":"NAM0 - Linear Velocity","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]},{"t":6,"n":"NAM1 - Angular Velocity","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]},{"t":2,"n":"NAM2 - Noise Texture"},{"t":2,"n":"NAM3 - Unused"},{"t":2,"n":"NAM4 - Unused"}]},{"t":1,"p":1,"n":"WEAP - Weapon","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"}]},{"t":3,"n":"EITM - Object Effect"},{"t":3,"n":"EAMT - Enchantment Amount"},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"ETYP - Equipment Type"},{"t":3,"n":"BIDS - Block Bash Impact Data Set"},{"t":3,"n":"BAMT - Alternate Block Material"},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":2,"n":"DESC - Description"},{"t":6,"n":"Has Scope","c":[{"t":2,"n":"MOD3 - Model Filename"}]},{"t":11,"n":"NNAM - Unused"},{"t":3,"n":"INAM - Impact Data Set"},{"t":3,"n":"WNAM - 1st Person Model Object"},{"t":3,"n":"SNAM - Attack Sound"},{"t":3,"n":"XNAM - Attack Sound 2D"},{"t":3,"n":"NAM7 - Attack Loop Sound"},{"t":3,"n":"TNAM - Attack Fail Sound"},{"t":3,"n":"UNAM - Idle Sound"},{"t":3,"n":"NAM9 - Equip Sound"},{"t":3,"n":"NAM8 - Unequip Sound"},{"t":6,"n":"DATA - Game Data","c":[{"t":3,"n":"Value"},{"t":5,"n":"Weight"},{"t":3,"n":"Damage"}]},{"t":6,"n":"DNAM - Data","c":[{"t":3,"n":"Animation Type"},{"t":11,"n":"Unused"},{"t":5,"n":"Speed"},{"t":5,"n":"Reach"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"},{"t":5,"n":"Sight FOV"},{"t":11,"n":"Unknown"},{"t":3,"n":"Base VATS To-Hit Chance"},{"t":3,"n":"Attack Animation"},{"t":3,"n":"# Projectiles"},{"t":3,"n":"Embedded Weapon AV (unused)"},{"t":5,"n":"Range Min"},{"t":5,"n":"Range Max"},{"t":3,"n":"On Hit"},{"t":3,"n":"Flags2"},{"t":5,"n":"Animation Attack Mult"},{"t":5,"n":"Unknown"},{"t":5,"n":"Rumble - Left Motor Strength"},{"t":5,"n":"Rumble - Right Motor Strength"},{"t":5,"n":"Rumble - Duration"},{"t":11,"n":"Unknown"},{"t":3,"n":"Skill"},{"t":11,"n":"Unknown"},{"t":3,"n":"Resist"},{"t":11,"n":"Unknown"},{"t":5,"n":"Stagger"}]},{"t":6,"n":"CRDT - Critical Data","c":[{"t":3,"n":"Damage"},{"t":11,"n":"Unused"},{"t":5,"n":"% Mult"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"},{"t":3,"n":"Effect"}]},{"t":3,"n":"VNAM - Detection Sound Level"},{"t":3,"n":"CNAM - Template"}]},{"t":1,"p":1,"n":"WRLD - Worldspace","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":7,"n":"Unused RNAM","c":[{"t":11,"n":"RNAM - Unknown"}]},{"t":11,"n":"MHDT - Max Height Data"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"n":"WCTR - Fixed Dimensions Center Cell","c":[{"t":3,"n":"X"},{"t":3,"n":"Y"}]},{"t":3,"n":"LTMP - Interior Lighting"},{"t":3,"n":"XEZN - Encounter Zone"},{"t":3,"n":"XLCN - Location"},{"t":6,"n":"Parent","c":[{"t":3,"n":"WNAM - Worldspace"},{"t":6,"n":"PNAM - ","c":[{"t":3,"n":"Flags"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"CNAM - Climate"},{"t":3,"n":"NAM2 - Water"},{"t":3,"n":"NAM3 - LOD Water Type"},{"t":5,"n":"NAM4 - LOD Water Height"},{"t":6,"n":"DNAM - Land Data","c":[{"t":5,"n":"Default Land Height"},{"t":5,"n":"Default Water Height"}]},{"t":2,"n":"ICON - Map Image"},{"t":6,"n":"Cloud Model","c":[{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]}]},{"t":6,"n":"MNAM - Map Data","c":[{"t":6,"n":"Usable Dimensions","c":[{"t":3,"n":"X"},{"t":3,"n":"Y"}]},{"t":6,"n":"Cell Coordinates","c":[{"t":6,"n":"NW Cell","c":[{"t":3,"n":"X"},{"t":3,"n":"Y"}]},{"t":6,"n":"SE Cell","c":[{"t":3,"n":"X"},{"t":3,"n":"Y"}]}]},{"t":6,"n":"Camera Data","c":[{"t":5,"n":"Min Height"},{"t":5,"n":"Max Height"},{"t":5,"n":"Initial Pitch"}]}]},{"t":6,"n":"ONAM - World Map Offset Data","c":[{"t":5,"n":"World Map Scale"},{"t":5,"n":"Cell X Offset"},{"t":5,"n":"Cell Y Offset"},{"t":5,"n":"Cell Z Offset"}]},{"t":5,"n":"NAMA - Distant LOD Multiplier"},{"t":3,"n":"DATA - Flags"},{"t":6,"n":"Object Bounds","c":[{"t":6,"n":"NAM0 - Min","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"}]},{"t":6,"n":"NAM9 - Max","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"}]}]},{"t":3,"n":"ZNAM - Music"},{"t":2,"n":"NNAM - Canopy Shadow (unused)"},{"t":2,"n":"XNAM - Water Noise Texture"},{"t":2,"n":"TNAM - HD LOD Diffuse Texture"},{"t":2,"n":"UNAM - HD LOD Normal Texture"},{"t":2,"n":"XWEM - Water Environment Map (unused)"},{"t":11,"n":"OFST - Offset Data"}]},{"t":1,"p":1,"n":"ALCH - Ingestible","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":2,"n":"DESC - Description"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":3,"n":"ETYP - Equipment Type"},{"t":5,"n":"DATA - Weight"},{"t":6,"n":"ENIT - Effect Data","c":[{"t":3,"n":"Value"},{"t":3,"n":"Flags"},{"t":3,"n":"Addiction"},{"t":5,"n":"Addiction Chance"},{"t":3,"n":"Sound - Consume"}]},{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":3,"n":"EFID - Base Effect"},{"t":6,"n":"EFIT - ","c":[{"t":5,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"}]}]}]}]}]},"name":"Bash.Names","hash":"$BB2ECCA2","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.NpcFaces.json ================================================ {"records":"NPC_","description":"NpcFaces tag from Wrye Bash.\r\n\r\nUsed when the mod modifies NPC faces.","tree":{"records":[{"t":1,"p":1,"n":"NPC_ - Non-Player Character (Actor)","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Magicka Offset"},{"t":3,"n":"Stamina Offset"},{"t":12,"n":"Level"},{"t":3,"n":"Calc min level"},{"t":3,"n":"Calc max level"},{"t":3,"n":"Speed Multiplier"},{"t":3,"n":"Disposition Base (unused)"},{"t":3,"n":"Template Flags"},{"t":3,"n":"Health Offset"},{"t":3,"n":"Bleedout Override"}]},{"t":10,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"VTCK - Voice"},{"t":3,"n":"TPLT - Template"},{"t":3,"n":"RNAM - Race"},{"t":3,"n":"SPCT - Count"},{"t":9,"n":"Actor Effects","c":[{"t":3,"n":"SPLO - Actor Effect"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"WNAM - Worn Armor"},{"t":3,"n":"ANAM - Far away model"},{"t":3,"n":"ATKR - Attack Race"},{"t":10,"n":"Attacks","c":[{"t":6,"n":"Attack","c":[{"t":6,"n":"ATKD - Attack Data","c":[{"t":5,"n":"Damage Mult"},{"t":5,"n":"Attack Chance"},{"t":3,"n":"Attack Spell"},{"t":3,"n":"Attack Flags"},{"t":5,"n":"Attack Angle"},{"t":5,"n":"Strike Angle"},{"t":5,"n":"Stagger"},{"t":3,"n":"Attack Type"},{"t":5,"n":"Knockdown"},{"t":5,"n":"Recovery Time"},{"t":5,"n":"Stamina Mult"}]}]}]},{"t":3,"n":"SPOR - Spectator override package list"},{"t":3,"n":"OCOR - Observe dead body override package list"},{"t":3,"n":"GWOR - Guard warn override package list"},{"t":3,"n":"ECOR - Combat override package list"},{"t":3,"n":"PRKZ - Perk Count"},{"t":10,"n":"Perks","c":[{"t":6,"n":"PRKR - Perk","c":[{"t":3,"n":"Perk"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"COCT - Count"},{"t":10,"n":"Items","c":[{"t":6,"n":"Item","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]}]},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Mood"},{"t":3,"n":"Assistance"},{"t":6,"n":"Aggro","c":[{"t":3,"n":"Aggro Radius Behavior"},{"t":3,"n":"Unknown"},{"t":3,"n":"Warn"},{"t":3,"n":"Warn\/Attack"},{"t":3,"n":"Attack"}]}]},{"t":7,"n":"Packages","c":[{"t":3,"n":"PKID - Package"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":3,"n":"CNAM - Class"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"SHRT - Short Name"},{"t":11,"n":"DATA - Marker"},{"t":6,"n":"DNAM - Player Skills","c":[{"t":7,"n":"Skill Values","c":[{"t":3,"n":"Skill #0 (OneHanded)"},{"t":3,"n":"Skill #1 (TwoHanded)"},{"t":3,"n":"Skill #2 (Marksman)"},{"t":3,"n":"Skill #3 (Block)"},{"t":3,"n":"Skill #4 (Smithing)"},{"t":3,"n":"Skill #5 (HeavyArmor)"},{"t":3,"n":"Skill #6 (LightArmor)"},{"t":3,"n":"Skill #7 (Pickpocket)"},{"t":3,"n":"Skill #8 (Lockpicking)"},{"t":3,"n":"Skill #9 (Sneak)"},{"t":3,"n":"Skill #10 (Alchemy)"},{"t":3,"n":"Skill #11 (Speechcraft)"},{"t":3,"n":"Skill #12 (Alteration)"},{"t":3,"n":"Skill #13 (Conjuration)"},{"t":3,"n":"Skill #14 (Destruction)"},{"t":3,"n":"Skill #15 (Illusion)"},{"t":3,"n":"Skill #16 (Restoration)"},{"t":3,"n":"Skill #17 (Enchanting)"}]},{"t":7,"n":"Skill Offsets","c":[{"t":3,"n":"Skill #0 (OneHanded)"},{"t":3,"n":"Skill #1 (TwoHanded)"},{"t":3,"n":"Skill #2 (Marksman)"},{"t":3,"n":"Skill #3 (Block)"},{"t":3,"n":"Skill #4 (Smithing)"},{"t":3,"n":"Skill #5 (HeavyArmor)"},{"t":3,"n":"Skill #6 (LightArmor)"},{"t":3,"n":"Skill #7 (Pickpocket)"},{"t":3,"n":"Skill #8 (Lockpicking)"},{"t":3,"n":"Skill #9 (Sneak)"},{"t":3,"n":"Skill #10 (Alchemy)"},{"t":3,"n":"Skill #11 (Speechcraft)"},{"t":3,"n":"Skill #12 (Alteration)"},{"t":3,"n":"Skill #13 (Conjuration)"},{"t":3,"n":"Skill #14 (Destruction)"},{"t":3,"n":"Skill #15 (Illusion)"},{"t":3,"n":"Skill #16 (Restoration)"},{"t":3,"n":"Skill #17 (Enchanting)"}]},{"t":3,"n":"Health"},{"t":3,"n":"Magicka"},{"t":3,"n":"Stamina"},{"t":11,"n":"Unused"},{"t":5,"n":"Far away model distance"},{"t":3,"n":"Geared up weapons"},{"t":11,"n":"Unused"}]},{"t":9,"s":1,"p":1,"n":"Head Parts","c":[{"t":3,"p":1,"n":"PNAM - Head Part"}]},{"t":3,"p":1,"n":"HCLF - Hair Color"},{"t":3,"n":"ZNAM - Combat Style"},{"t":3,"n":"GNAM - Gift Filter"},{"t":11,"n":"NAM5 - Unknown"},{"t":5,"n":"NAM6 - Height"},{"t":5,"n":"NAM7 - Weight"},{"t":3,"n":"NAM8 - Sound Level"},{"t":10,"n":"Sound Types","c":[{"t":6,"n":"Sound Type","c":[{"t":3,"n":"CSDT - Type"},{"t":10,"n":"Sounds","c":[{"t":6,"n":"Sound","c":[{"t":3,"n":"CSDI - Sound"},{"t":3,"n":"CSDC - Sound Chance"}]}]}]}]},{"t":3,"n":"CSCR - Inherits Sounds From"},{"t":3,"n":"DOFT - Default outfit"},{"t":3,"n":"SOFT - Sleeping outfit"},{"t":3,"n":"DPLT - Default Package List"},{"t":3,"n":"CRIF - Crime faction"},{"t":3,"p":1,"n":"FTST - Head texture"},{"t":6,"s":1,"p":1,"n":"QNAM - Texture lighting","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}]},{"t":6,"s":1,"p":1,"n":"NAM9 - Face morph","c":[{"t":5,"p":1,"n":"Nose Long\/Short"},{"t":5,"p":1,"n":"Nose Up\/Down"},{"t":5,"p":1,"n":"Jaw Up\/Down"},{"t":5,"p":1,"n":"Jaw Narrow\/Wide"},{"t":5,"p":1,"n":"Jaw Farward\/Back"},{"t":5,"p":1,"n":"Cheeks Up\/Down"},{"t":5,"p":1,"n":"Cheeks Farward\/Back"},{"t":5,"p":1,"n":"Eyes Up\/Down"},{"t":5,"p":1,"n":"Eyes In\/Out"},{"t":5,"p":1,"n":"Brows Up\/Down"},{"t":5,"p":1,"n":"Brows In\/Out"},{"t":5,"p":1,"n":"Brows Farward\/Back"},{"t":5,"p":1,"n":"Lips Up\/Down"},{"t":5,"p":1,"n":"Lips In\/Out"},{"t":5,"p":1,"n":"Chin Narrow\/Wide"},{"t":5,"p":1,"n":"Chin Up\/Down"},{"t":5,"p":1,"n":"Chin Underbite\/Overbite"},{"t":5,"p":1,"n":"Eyes Farward\/Back"},{"t":5,"p":1,"n":"Unknown"}]},{"t":6,"s":1,"p":1,"n":"NAMA - Face parts","c":[{"t":3,"p":1,"n":"Nose"},{"t":3,"p":1,"n":"Unknown"},{"t":3,"p":1,"n":"Eyes"},{"t":3,"p":1,"n":"Mouth"}]},{"t":10,"s":1,"p":1,"n":"Tint Layers","c":[{"t":6,"p":1,"n":"Layer","c":[{"t":3,"p":1,"n":"TINI - Tint Index"}]}]}]}]},"name":"Bash.NpcFaces","hash":"$E8292148","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.NpcFacesForceFullImport.json ================================================ {"records":"NPC_","description":"NpcFacesForceFullImport tag from Wrye Bash.\r\n\r\nUsed when the mod modifies NPC faces, and you wish to import the unmodified subrecords as well as the modified subrecords.","tree":{"records":[{"t":1,"p":1,"n":"NPC_ - Non-Player Character (Actor)","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Magicka Offset"},{"t":3,"n":"Stamina Offset"},{"t":12,"n":"Level"},{"t":3,"n":"Calc min level"},{"t":3,"n":"Calc max level"},{"t":3,"n":"Speed Multiplier"},{"t":3,"n":"Disposition Base (unused)"},{"t":3,"n":"Template Flags"},{"t":3,"n":"Health Offset"},{"t":3,"n":"Bleedout Override"}]},{"t":10,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"VTCK - Voice"},{"t":3,"n":"TPLT - Template"},{"t":3,"n":"RNAM - Race"},{"t":3,"n":"SPCT - Count"},{"t":9,"n":"Actor Effects","c":[{"t":3,"n":"SPLO - Actor Effect"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"WNAM - Worn Armor"},{"t":3,"n":"ANAM - Far away model"},{"t":3,"n":"ATKR - Attack Race"},{"t":10,"n":"Attacks","c":[{"t":6,"n":"Attack","c":[{"t":6,"n":"ATKD - Attack Data","c":[{"t":5,"n":"Damage Mult"},{"t":5,"n":"Attack Chance"},{"t":3,"n":"Attack Spell"},{"t":3,"n":"Attack Flags"},{"t":5,"n":"Attack Angle"},{"t":5,"n":"Strike Angle"},{"t":5,"n":"Stagger"},{"t":3,"n":"Attack Type"},{"t":5,"n":"Knockdown"},{"t":5,"n":"Recovery Time"},{"t":5,"n":"Stamina Mult"}]}]}]},{"t":3,"n":"SPOR - Spectator override package list"},{"t":3,"n":"OCOR - Observe dead body override package list"},{"t":3,"n":"GWOR - Guard warn override package list"},{"t":3,"n":"ECOR - Combat override package list"},{"t":3,"n":"PRKZ - Perk Count"},{"t":10,"n":"Perks","c":[{"t":6,"n":"PRKR - Perk","c":[{"t":3,"n":"Perk"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"COCT - Count"},{"t":10,"n":"Items","c":[{"t":6,"n":"Item","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]}]},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Mood"},{"t":3,"n":"Assistance"},{"t":6,"n":"Aggro","c":[{"t":3,"n":"Aggro Radius Behavior"},{"t":3,"n":"Unknown"},{"t":3,"n":"Warn"},{"t":3,"n":"Warn\/Attack"},{"t":3,"n":"Attack"}]}]},{"t":7,"n":"Packages","c":[{"t":3,"n":"PKID - Package"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":3,"n":"CNAM - Class"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"SHRT - Short Name"},{"t":11,"n":"DATA - Marker"},{"t":6,"n":"DNAM - Player Skills","c":[{"t":7,"n":"Skill Values","c":[{"t":3,"n":"Skill #0 (OneHanded)"},{"t":3,"n":"Skill #1 (TwoHanded)"},{"t":3,"n":"Skill #2 (Marksman)"},{"t":3,"n":"Skill #3 (Block)"},{"t":3,"n":"Skill #4 (Smithing)"},{"t":3,"n":"Skill #5 (HeavyArmor)"},{"t":3,"n":"Skill #6 (LightArmor)"},{"t":3,"n":"Skill #7 (Pickpocket)"},{"t":3,"n":"Skill #8 (Lockpicking)"},{"t":3,"n":"Skill #9 (Sneak)"},{"t":3,"n":"Skill #10 (Alchemy)"},{"t":3,"n":"Skill #11 (Speechcraft)"},{"t":3,"n":"Skill #12 (Alteration)"},{"t":3,"n":"Skill #13 (Conjuration)"},{"t":3,"n":"Skill #14 (Destruction)"},{"t":3,"n":"Skill #15 (Illusion)"},{"t":3,"n":"Skill #16 (Restoration)"},{"t":3,"n":"Skill #17 (Enchanting)"}]},{"t":7,"n":"Skill Offsets","c":[{"t":3,"n":"Skill #0 (OneHanded)"},{"t":3,"n":"Skill #1 (TwoHanded)"},{"t":3,"n":"Skill #2 (Marksman)"},{"t":3,"n":"Skill #3 (Block)"},{"t":3,"n":"Skill #4 (Smithing)"},{"t":3,"n":"Skill #5 (HeavyArmor)"},{"t":3,"n":"Skill #6 (LightArmor)"},{"t":3,"n":"Skill #7 (Pickpocket)"},{"t":3,"n":"Skill #8 (Lockpicking)"},{"t":3,"n":"Skill #9 (Sneak)"},{"t":3,"n":"Skill #10 (Alchemy)"},{"t":3,"n":"Skill #11 (Speechcraft)"},{"t":3,"n":"Skill #12 (Alteration)"},{"t":3,"n":"Skill #13 (Conjuration)"},{"t":3,"n":"Skill #14 (Destruction)"},{"t":3,"n":"Skill #15 (Illusion)"},{"t":3,"n":"Skill #16 (Restoration)"},{"t":3,"n":"Skill #17 (Enchanting)"}]},{"t":3,"n":"Health"},{"t":3,"n":"Magicka"},{"t":3,"n":"Stamina"},{"t":11,"n":"Unused"},{"t":5,"n":"Far away model distance"},{"t":3,"n":"Geared up weapons"},{"t":11,"n":"Unused"}]},{"t":9,"s":1,"p":1,"n":"Head Parts","c":[{"t":3,"p":1,"n":"PNAM - Head Part"}],"lt":"HCLF - Hair Color","lf":"QNAM - Texture lighting"},{"t":3,"p":1,"n":"HCLF - Hair Color","lt":"FTST - Head texture","lf":"Head Parts"},{"t":3,"n":"ZNAM - Combat Style"},{"t":3,"n":"GNAM - Gift Filter"},{"t":11,"n":"NAM5 - Unknown"},{"t":5,"n":"NAM6 - Height"},{"t":5,"n":"NAM7 - Weight"},{"t":3,"n":"NAM8 - Sound Level"},{"t":10,"n":"Sound Types","c":[{"t":6,"n":"Sound Type","c":[{"t":3,"n":"CSDT - Type"},{"t":10,"n":"Sounds","c":[{"t":6,"n":"Sound","c":[{"t":3,"n":"CSDI - Sound"},{"t":3,"n":"CSDC - Sound Chance"}]}]}]}]},{"t":3,"n":"CSCR - Inherits Sounds From"},{"t":3,"n":"DOFT - Default outfit"},{"t":3,"n":"SOFT - Sleeping outfit"},{"t":3,"n":"DPLT - Default Package List"},{"t":3,"n":"CRIF - Crime faction"},{"t":3,"p":1,"n":"FTST - Head texture","lt":"Tint Layers","lf":"HCLF - Hair Color"},{"t":6,"s":1,"p":1,"n":"QNAM - Texture lighting","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}],"lt":"Head Parts","lf":"NAM9 - Face morph"},{"t":6,"s":1,"p":1,"n":"NAM9 - Face morph","c":[{"t":5,"p":1,"n":"Nose Long\/Short"},{"t":5,"p":1,"n":"Nose Up\/Down"},{"t":5,"p":1,"n":"Jaw Up\/Down"},{"t":5,"p":1,"n":"Jaw Narrow\/Wide"},{"t":5,"p":1,"n":"Jaw Farward\/Back"},{"t":5,"p":1,"n":"Cheeks Up\/Down"},{"t":5,"p":1,"n":"Cheeks Farward\/Back"},{"t":5,"p":1,"n":"Eyes Up\/Down"},{"t":5,"p":1,"n":"Eyes In\/Out"},{"t":5,"p":1,"n":"Brows Up\/Down"},{"t":5,"p":1,"n":"Brows In\/Out"},{"t":5,"p":1,"n":"Brows Farward\/Back"},{"t":5,"p":1,"n":"Lips Up\/Down"},{"t":5,"p":1,"n":"Lips In\/Out"},{"t":5,"p":1,"n":"Chin Narrow\/Wide"},{"t":5,"p":1,"n":"Chin Up\/Down"},{"t":5,"p":1,"n":"Chin Underbite\/Overbite"},{"t":5,"p":1,"n":"Eyes Farward\/Back"},{"t":5,"p":1,"n":"Unknown"}],"lt":"QNAM - Texture lighting","lf":"NAMA - Face parts"},{"t":6,"s":1,"p":1,"n":"NAMA - Face parts","c":[{"t":3,"p":1,"n":"Nose"},{"t":3,"p":1,"n":"Unknown"},{"t":3,"p":1,"n":"Eyes"},{"t":3,"p":1,"n":"Mouth"}],"lt":"NAM9 - Face morph","lf":"Tint Layers"},{"t":10,"s":1,"p":1,"n":"Tint Layers","c":[{"t":6,"p":1,"n":"Layer","c":[{"t":3,"p":1,"n":"TINI - Tint Index"}]}],"lt":"NAMA - Face parts","lf":"FTST - Head texture"}]}]},"name":"Bash.NpcFacesForceFullImport","hash":"$3A36AED9","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.R.AddSpells.json ================================================ {"records":"RACE","description":"R.AddSpells tag from Wrye Bash.\r\n\r\nUsed when the mod adds spells to racial spell list(s). Either R.ChangeSpells or R.AddSpells should be used for a plugin, not both.","tree":{"records":[{"t":1,"p":1,"n":"RACE - Race","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":3,"n":"SPCT - Count"},{"t":9,"p":1,"n":"Actor Effects","c":[{"t":3,"p":1,"n":"SPLO - Actor Effect"}]},{"t":3,"n":"WNAM - Skin"},{"t":6,"n":"BOD2 - Biped Body Template","c":[{"t":3,"n":"First Person Flags"},{"t":3,"n":"General Flags"},{"n":"Unused"},{"t":3,"n":"Armor Type"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"DATA - ","c":[{"t":10,"n":"Skill Boosts","c":[{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]}]},{"t":11,"n":"Unknown"},{"t":5,"n":"Male Height"},{"t":5,"n":"Female Height"},{"t":5,"n":"Male Weight"},{"t":5,"n":"Female Weight"},{"t":3,"n":"Flags"},{"t":5,"n":"Starting Health"},{"t":5,"n":"Starting Magicka"},{"t":5,"n":"Starting Stamina"},{"t":5,"n":"Base Carry Weight"},{"t":5,"n":"Base Mass"},{"t":5,"n":"Acceleration rate"},{"t":5,"n":"Deceleration rate"},{"t":3,"n":"Size"},{"t":3,"n":"Head Biped Object"},{"t":3,"n":"Hair Biped Object"},{"t":5,"n":"Injured Health Pct"},{"t":3,"n":"Shield Biped Object"},{"t":5,"n":"Health Regen"},{"t":5,"n":"Magicka Regen"},{"t":5,"n":"Stamina Regen"},{"t":5,"n":"Unarmed Damage"},{"t":5,"n":"Unarmed Reach"},{"t":3,"n":"Body Biped Object"},{"t":5,"n":"Aim Angle Tolerance"},{"t":5,"n":"Flight Radius"},{"t":5,"n":"Angular Acceleration Rate"},{"t":5,"n":"Angular Tolerance"},{"t":3,"n":"Flags 2"},{"t":6,"n":"Mount Data","c":[{"t":5,"n":"Offset X"},{"t":5,"n":"Offset Y"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"}]}]},{"n":"MNAM - Male Marker"},{"t":2,"n":"ANAM - Male Skeletal Model"},{"t":11,"n":"MODT - Texture Files Hashes"},{"n":"FNAM - Female Marker"},{"t":2,"n":"ANAM - Female Skeletal Model"},{"t":11,"n":"MODT - Texture Files Hashes"},{"n":"NAM2 - Marker NAM2 #1"},{"t":9,"n":"Movement Type Names","c":[{"t":2,"n":"MTNM - Name"}]},{"t":7,"n":"VTCK - Voices","c":[{"t":3,"n":"Voice #0 (Male)"},{"t":3,"n":"Voice #1 (Female)"}]},{"t":7,"n":"DNAM - Decapitate Armors","c":[{"t":3,"n":"Decapitate Armor #0 (Male)"},{"t":3,"n":"Decapitate Armor #1 (Female)"}]},{"t":7,"n":"HCLF - Default Hair Colors","c":[{"t":3,"n":"Default Hair Color #0 (Male)"},{"t":3,"n":"Default Hair Color #1 (Female)"}]},{"t":3,"n":"TINL - Total Number of Tints in List"},{"t":5,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"n":"UNAM - FaceGen - Face clamp"},{"t":3,"n":"ATKR - Attack Race"},{"t":10,"n":"Attacks","c":[{"t":6,"n":"Attack","c":[{"t":6,"n":"ATKD - Attack Data","c":[{"t":5,"n":"Damage Mult"},{"t":5,"n":"Attack Chance"},{"t":3,"n":"Attack Spell"},{"t":3,"n":"Attack Flags"},{"t":5,"n":"Attack Angle"},{"t":5,"n":"Strike Angle"},{"t":5,"n":"Stagger"},{"t":3,"n":"Attack Type"},{"t":5,"n":"Knockdown"},{"t":5,"n":"Recovery Time"},{"t":5,"n":"Stamina Mult"}]}]}]},{"t":6,"n":"Body Data","c":[{"n":"NAM1 - Body Data Marker"},{"t":6,"n":"Male Body Data","c":[{"n":"MNAM - Male Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"}]}]}]},{"t":6,"n":"Female Body Data","c":[{"n":"FNAM - Female Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"}]}]}]}]},{"t":9,"n":"HNAM - Hairs","c":[{"t":3,"n":"Hair"}]},{"t":9,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eye"}]},{"t":3,"n":"GNAM - Body Part Data"},{"n":"NAM2 - Marker NAM2 #2"},{"n":"NAM3 - Marker NAM3 #3"},{"t":6,"n":"Male Behavior Graph","c":[{"n":"MNAM - Male Data Marker"}]},{"t":6,"n":"Female Behavior Graph","c":[{"n":"FNAM - Female Data Marker"}]},{"t":3,"n":"NAM4 - Material Type"},{"t":3,"n":"NAM5 - Impact Data Set"},{"t":3,"n":"NAM7 - Decapitation FX"},{"t":3,"n":"ONAM - Open Loot Sound"},{"t":3,"n":"LNAM - Close Loot Sound"},{"t":7,"n":"Biped Object Names","c":[{"t":2,"n":"NAME - Name"}]},{"t":10,"n":"Movement Types","c":[{"t":6,"n":"Movement Types","c":[{"t":3,"n":"MTYP - Movement Type"}]}]},{"t":3,"n":"VNAM - Equipment Flags"},{"t":9,"n":"Equip Slots","c":[{"t":3,"n":"QNAM - Equip Slot"}]},{"t":3,"n":"UNES - Unarmed Equip Slot"},{"t":7,"n":"Phoneme Target Names","c":[{"t":2,"n":"PHTN - Name"}]},{"t":6,"n":"FaceFX Phonemes","c":[{"t":6,"n":"IY","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]}]},{"t":3,"n":"WKMV - Base Movement Default - Walk"},{"t":3,"n":"RNMV - Base Movement Default - Run"},{"t":3,"n":"SWMV - Base Movement Default - Swim"},{"t":3,"n":"FLMV - Base Movement Default - Fly"},{"t":3,"n":"SNMV - Base Movement Default - Sneak"},{"t":3,"n":"SPMV - Base Movement Default - Sprint"},{"t":6,"n":"Head Data","c":[{"n":"NAM0 - Head Data Marker"},{"t":6,"n":"Male Head Data","c":[{"n":"MNAM - Male Data Marker"}]},{"t":6,"n":"Female Head Data","c":[{"n":"NAM0 - Head Data Marker"},{"n":"FNAM - Female Data Marker"}]}]},{"t":3,"n":"NAM8 - Morph race"},{"t":3,"n":"RNAM - Armor race"}]}]},"name":"Bash.R.AddSpells","hash":"$4A672F91","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.R.ChangeSpells.json ================================================ {"records":"RACE","description":"R.ChangeSpells tag from Wrye Bash.\r\n\r\nUsed when the mod modifies racial spell list(s) (beyond adding spells). Either R.ChangeSpells or R.AddSpells should be used for a plugin, not both.","tree":{"records":[{"t":1,"p":1,"n":"RACE - Race","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":3,"n":"SPCT - Count"},{"t":9,"s":1,"p":1,"n":"Actor Effects","c":[{"t":3,"p":1,"n":"SPLO - Actor Effect"}]},{"t":3,"n":"WNAM - Skin"},{"t":6,"n":"BOD2 - Biped Body Template","c":[{"t":3,"n":"First Person Flags"},{"t":3,"n":"General Flags"},{"n":"Unused"},{"t":3,"n":"Armor Type"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"DATA - ","c":[{"t":10,"n":"Skill Boosts","c":[{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]}]},{"t":11,"n":"Unknown"},{"t":5,"n":"Male Height"},{"t":5,"n":"Female Height"},{"t":5,"n":"Male Weight"},{"t":5,"n":"Female Weight"},{"t":3,"n":"Flags"},{"t":5,"n":"Starting Health"},{"t":5,"n":"Starting Magicka"},{"t":5,"n":"Starting Stamina"},{"t":5,"n":"Base Carry Weight"},{"t":5,"n":"Base Mass"},{"t":5,"n":"Acceleration rate"},{"t":5,"n":"Deceleration rate"},{"t":3,"n":"Size"},{"t":3,"n":"Head Biped Object"},{"t":3,"n":"Hair Biped Object"},{"t":5,"n":"Injured Health Pct"},{"t":3,"n":"Shield Biped Object"},{"t":5,"n":"Health Regen"},{"t":5,"n":"Magicka Regen"},{"t":5,"n":"Stamina Regen"},{"t":5,"n":"Unarmed Damage"},{"t":5,"n":"Unarmed Reach"},{"t":3,"n":"Body Biped Object"},{"t":5,"n":"Aim Angle Tolerance"},{"t":5,"n":"Flight Radius"},{"t":5,"n":"Angular Acceleration Rate"},{"t":5,"n":"Angular Tolerance"},{"t":3,"n":"Flags 2"},{"t":6,"n":"Mount Data","c":[{"t":5,"n":"Offset X"},{"t":5,"n":"Offset Y"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"}]}]},{"n":"MNAM - Male Marker"},{"t":2,"n":"ANAM - Male Skeletal Model"},{"t":11,"n":"MODT - Texture Files Hashes"},{"n":"FNAM - Female Marker"},{"t":2,"n":"ANAM - Female Skeletal Model"},{"t":11,"n":"MODT - Texture Files Hashes"},{"n":"NAM2 - Marker NAM2 #1"},{"t":9,"n":"Movement Type Names","c":[{"t":2,"n":"MTNM - Name"}]},{"t":7,"n":"VTCK - Voices","c":[{"t":3,"n":"Voice #0 (Male)"},{"t":3,"n":"Voice #1 (Female)"}]},{"t":7,"n":"DNAM - Decapitate Armors","c":[{"t":3,"n":"Decapitate Armor #0 (Male)"},{"t":3,"n":"Decapitate Armor #1 (Female)"}]},{"t":7,"n":"HCLF - Default Hair Colors","c":[{"t":3,"n":"Default Hair Color #0 (Male)"},{"t":3,"n":"Default Hair Color #1 (Female)"}]},{"t":3,"n":"TINL - Total Number of Tints in List"},{"t":5,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"n":"UNAM - FaceGen - Face clamp"},{"t":3,"n":"ATKR - Attack Race"},{"t":10,"n":"Attacks","c":[{"t":6,"n":"Attack","c":[{"t":6,"n":"ATKD - Attack Data","c":[{"t":5,"n":"Damage Mult"},{"t":5,"n":"Attack Chance"},{"t":3,"n":"Attack Spell"},{"t":3,"n":"Attack Flags"},{"t":5,"n":"Attack Angle"},{"t":5,"n":"Strike Angle"},{"t":5,"n":"Stagger"},{"t":3,"n":"Attack Type"},{"t":5,"n":"Knockdown"},{"t":5,"n":"Recovery Time"},{"t":5,"n":"Stamina Mult"}]}]}]},{"t":6,"n":"Body Data","c":[{"n":"NAM1 - Body Data Marker"},{"t":6,"n":"Male Body Data","c":[{"n":"MNAM - Male Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"}]}]}]},{"t":6,"n":"Female Body Data","c":[{"n":"FNAM - Female Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"}]}]}]}]},{"t":9,"n":"HNAM - Hairs","c":[{"t":3,"n":"Hair"}]},{"t":9,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eye"}]},{"t":3,"n":"GNAM - Body Part Data"},{"n":"NAM2 - Marker NAM2 #2"},{"n":"NAM3 - Marker NAM3 #3"},{"t":6,"n":"Male Behavior Graph","c":[{"n":"MNAM - Male Data Marker"}]},{"t":6,"n":"Female Behavior Graph","c":[{"n":"FNAM - Female Data Marker"}]},{"t":3,"n":"NAM4 - Material Type"},{"t":3,"n":"NAM5 - Impact Data Set"},{"t":3,"n":"NAM7 - Decapitation FX"},{"t":3,"n":"ONAM - Open Loot Sound"},{"t":3,"n":"LNAM - Close Loot Sound"},{"t":7,"n":"Biped Object Names","c":[{"t":2,"n":"NAME - Name"}]},{"t":10,"n":"Movement Types","c":[{"t":6,"n":"Movement Types","c":[{"t":3,"n":"MTYP - Movement Type"}]}]},{"t":3,"n":"VNAM - Equipment Flags"},{"t":9,"n":"Equip Slots","c":[{"t":3,"n":"QNAM - Equip Slot"}]},{"t":3,"n":"UNES - Unarmed Equip Slot"},{"t":7,"n":"Phoneme Target Names","c":[{"t":2,"n":"PHTN - Name"}]},{"t":6,"n":"FaceFX Phonemes","c":[{"t":6,"n":"IY","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]}]},{"t":3,"n":"WKMV - Base Movement Default - Walk"},{"t":3,"n":"RNMV - Base Movement Default - Run"},{"t":3,"n":"SWMV - Base Movement Default - Swim"},{"t":3,"n":"FLMV - Base Movement Default - Fly"},{"t":3,"n":"SNMV - Base Movement Default - Sneak"},{"t":3,"n":"SPMV - Base Movement Default - Sprint"},{"t":6,"n":"Head Data","c":[{"n":"NAM0 - Head Data Marker"},{"t":6,"n":"Male Head Data","c":[{"n":"MNAM - Male Data Marker"}]},{"t":6,"n":"Female Head Data","c":[{"n":"NAM0 - Head Data Marker"},{"n":"FNAM - Female Data Marker"}]}]},{"t":3,"n":"NAM8 - Morph race"},{"t":3,"n":"RNAM - Armor race"}]}]},"name":"Bash.R.ChangeSpells","hash":"$14C55D3A","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.R.Description.json ================================================ {"records":"RACE","description":"R.Description tag from Wrye Bash.\r\n\r\nUsed when the mod modifies race descriptions.","tree":{"records":[{"t":1,"p":1,"n":"RACE - Race","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":2,"p":1,"n":"DESC - Description"},{"t":3,"n":"SPCT - Count"},{"t":9,"n":"Actor Effects","c":[{"t":3,"n":"SPLO - Actor Effect"}]},{"t":3,"n":"WNAM - Skin"},{"t":6,"n":"BOD2 - Biped Body Template","c":[{"t":3,"n":"First Person Flags"},{"t":3,"n":"General Flags"},{"n":"Unused"},{"t":3,"n":"Armor Type"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"DATA - ","c":[{"t":10,"n":"Skill Boosts","c":[{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]}]},{"t":11,"n":"Unknown"},{"t":5,"n":"Male Height"},{"t":5,"n":"Female Height"},{"t":5,"n":"Male Weight"},{"t":5,"n":"Female Weight"},{"t":3,"n":"Flags"},{"t":5,"n":"Starting Health"},{"t":5,"n":"Starting Magicka"},{"t":5,"n":"Starting Stamina"},{"t":5,"n":"Base Carry Weight"},{"t":5,"n":"Base Mass"},{"t":5,"n":"Acceleration rate"},{"t":5,"n":"Deceleration rate"},{"t":3,"n":"Size"},{"t":3,"n":"Head Biped Object"},{"t":3,"n":"Hair Biped Object"},{"t":5,"n":"Injured Health Pct"},{"t":3,"n":"Shield Biped Object"},{"t":5,"n":"Health Regen"},{"t":5,"n":"Magicka Regen"},{"t":5,"n":"Stamina Regen"},{"t":5,"n":"Unarmed Damage"},{"t":5,"n":"Unarmed Reach"},{"t":3,"n":"Body Biped Object"},{"t":5,"n":"Aim Angle Tolerance"},{"t":5,"n":"Flight Radius"},{"t":5,"n":"Angular Acceleration Rate"},{"t":5,"n":"Angular Tolerance"},{"t":3,"n":"Flags 2"},{"t":6,"n":"Mount Data","c":[{"t":5,"n":"Offset X"},{"t":5,"n":"Offset Y"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"}]}]},{"n":"MNAM - Male Marker"},{"t":2,"n":"ANAM - Male Skeletal Model"},{"t":11,"n":"MODT - Texture Files Hashes"},{"n":"FNAM - Female Marker"},{"t":2,"n":"ANAM - Female Skeletal Model"},{"t":11,"n":"MODT - Texture Files Hashes"},{"n":"NAM2 - Marker NAM2 #1"},{"t":9,"n":"Movement Type Names","c":[{"t":2,"n":"MTNM - Name"}]},{"t":7,"n":"VTCK - Voices","c":[{"t":3,"n":"Voice #0 (Male)"},{"t":3,"n":"Voice #1 (Female)"}]},{"t":7,"n":"DNAM - Decapitate Armors","c":[{"t":3,"n":"Decapitate Armor #0 (Male)"},{"t":3,"n":"Decapitate Armor #1 (Female)"}]},{"t":7,"n":"HCLF - Default Hair Colors","c":[{"t":3,"n":"Default Hair Color #0 (Male)"},{"t":3,"n":"Default Hair Color #1 (Female)"}]},{"t":3,"n":"TINL - Total Number of Tints in List"},{"t":5,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"n":"UNAM - FaceGen - Face clamp"},{"t":3,"n":"ATKR - Attack Race"},{"t":10,"n":"Attacks","c":[{"t":6,"n":"Attack","c":[{"t":6,"n":"ATKD - Attack Data","c":[{"t":5,"n":"Damage Mult"},{"t":5,"n":"Attack Chance"},{"t":3,"n":"Attack Spell"},{"t":3,"n":"Attack Flags"},{"t":5,"n":"Attack Angle"},{"t":5,"n":"Strike Angle"},{"t":5,"n":"Stagger"},{"t":3,"n":"Attack Type"},{"t":5,"n":"Knockdown"},{"t":5,"n":"Recovery Time"},{"t":5,"n":"Stamina Mult"}]}]}]},{"t":6,"n":"Body Data","c":[{"n":"NAM1 - Body Data Marker"},{"t":6,"n":"Male Body Data","c":[{"n":"MNAM - Male Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"}]}]}]},{"t":6,"n":"Female Body Data","c":[{"n":"FNAM - Female Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"}]}]}]}]},{"t":9,"n":"HNAM - Hairs","c":[{"t":3,"n":"Hair"}]},{"t":9,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eye"}]},{"t":3,"n":"GNAM - Body Part Data"},{"n":"NAM2 - Marker NAM2 #2"},{"n":"NAM3 - Marker NAM3 #3"},{"t":6,"n":"Male Behavior Graph","c":[{"n":"MNAM - Male Data Marker"}]},{"t":6,"n":"Female Behavior Graph","c":[{"n":"FNAM - Female Data Marker"}]},{"t":3,"n":"NAM4 - Material Type"},{"t":3,"n":"NAM5 - Impact Data Set"},{"t":3,"n":"NAM7 - Decapitation FX"},{"t":3,"n":"ONAM - Open Loot Sound"},{"t":3,"n":"LNAM - Close Loot Sound"},{"t":7,"n":"Biped Object Names","c":[{"t":2,"n":"NAME - Name"}]},{"t":10,"n":"Movement Types","c":[{"t":6,"n":"Movement Types","c":[{"t":3,"n":"MTYP - Movement Type"}]}]},{"t":3,"n":"VNAM - Equipment Flags"},{"t":9,"n":"Equip Slots","c":[{"t":3,"n":"QNAM - Equip Slot"}]},{"t":3,"n":"UNES - Unarmed Equip Slot"},{"t":7,"n":"Phoneme Target Names","c":[{"t":2,"n":"PHTN - Name"}]},{"t":6,"n":"FaceFX Phonemes","c":[{"t":6,"n":"IY","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]}]},{"t":3,"n":"WKMV - Base Movement Default - Walk"},{"t":3,"n":"RNMV - Base Movement Default - Run"},{"t":3,"n":"SWMV - Base Movement Default - Swim"},{"t":3,"n":"FLMV - Base Movement Default - Fly"},{"t":3,"n":"SNMV - Base Movement Default - Sneak"},{"t":3,"n":"SPMV - Base Movement Default - Sprint"},{"t":6,"n":"Head Data","c":[{"n":"NAM0 - Head Data Marker"},{"t":6,"n":"Male Head Data","c":[{"n":"MNAM - Male Data Marker"}]},{"t":6,"n":"Female Head Data","c":[{"n":"NAM0 - Head Data Marker"},{"n":"FNAM - Female Data Marker"}]}]},{"t":3,"n":"NAM8 - Morph race"},{"t":3,"n":"RNAM - Armor race"}]}]},"name":"Bash.R.Description","hash":"$66D005FB","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.R.Head.json ================================================ {"records":"RACE","description":"R.Head tag from Wrye Bash.\r\n\r\nUsed when the mod modifies race heads.","tree":{"records":[{"t":1,"p":1,"n":"RACE - Race","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":2,"p":1,"n":"DESC - Description"},{"t":3,"n":"SPCT - Count"},{"t":9,"n":"Actor Effects","c":[{"t":3,"n":"SPLO - Actor Effect"}]},{"t":3,"n":"WNAM - Skin"},{"t":6,"n":"BOD2 - Biped Body Template","c":[{"t":3,"n":"First Person Flags"},{"t":3,"n":"General Flags"},{"n":"Unused"},{"t":3,"n":"Armor Type"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"DATA - ","c":[{"t":10,"n":"Skill Boosts","c":[{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]}]},{"t":11,"n":"Unknown"},{"t":5,"n":"Male Height"},{"t":5,"n":"Female Height"},{"t":5,"n":"Male Weight"},{"t":5,"n":"Female Weight"},{"t":3,"n":"Flags"},{"t":5,"n":"Starting Health"},{"t":5,"n":"Starting Magicka"},{"t":5,"n":"Starting Stamina"},{"t":5,"n":"Base Carry Weight"},{"t":5,"n":"Base Mass"},{"t":5,"n":"Acceleration rate"},{"t":5,"n":"Deceleration rate"},{"t":3,"n":"Size"},{"t":3,"n":"Head Biped Object"},{"t":3,"n":"Hair Biped Object"},{"t":5,"n":"Injured Health Pct"},{"t":3,"n":"Shield Biped Object"},{"t":5,"n":"Health Regen"},{"t":5,"n":"Magicka Regen"},{"t":5,"n":"Stamina Regen"},{"t":5,"n":"Unarmed Damage"},{"t":5,"n":"Unarmed Reach"},{"t":3,"n":"Body Biped Object"},{"t":5,"n":"Aim Angle Tolerance"},{"t":5,"n":"Flight Radius"},{"t":5,"n":"Angular Acceleration Rate"},{"t":5,"n":"Angular Tolerance"},{"t":3,"n":"Flags 2"},{"t":6,"n":"Mount Data","c":[{"t":5,"n":"Offset X"},{"t":5,"n":"Offset Y"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"}]}]},{"n":"MNAM - Male Marker"},{"t":2,"n":"ANAM - Male Skeletal Model"},{"t":11,"n":"MODT - Texture Files Hashes"},{"n":"FNAM - Female Marker"},{"t":2,"n":"ANAM - Female Skeletal Model"},{"t":11,"n":"MODT - Texture Files Hashes"},{"n":"NAM2 - Marker NAM2 #1"},{"t":9,"n":"Movement Type Names","c":[{"t":2,"n":"MTNM - Name"}]},{"t":7,"n":"VTCK - Voices","c":[{"t":3,"n":"Voice #0 (Male)"},{"t":3,"n":"Voice #1 (Female)"}]},{"t":7,"n":"DNAM - Decapitate Armors","c":[{"t":3,"n":"Decapitate Armor #0 (Male)"},{"t":3,"n":"Decapitate Armor #1 (Female)"}]},{"t":7,"n":"HCLF - Default Hair Colors","c":[{"t":3,"n":"Default Hair Color #0 (Male)"},{"t":3,"n":"Default Hair Color #1 (Female)"}]},{"t":3,"n":"TINL - Total Number of Tints in List"},{"t":5,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"n":"UNAM - FaceGen - Face clamp"},{"t":3,"n":"ATKR - Attack Race"},{"t":10,"n":"Attacks","c":[{"t":6,"n":"Attack","c":[{"t":6,"n":"ATKD - Attack Data","c":[{"t":5,"n":"Damage Mult"},{"t":5,"n":"Attack Chance"},{"t":3,"n":"Attack Spell"},{"t":3,"n":"Attack Flags"},{"t":5,"n":"Attack Angle"},{"t":5,"n":"Strike Angle"},{"t":5,"n":"Stagger"},{"t":3,"n":"Attack Type"},{"t":5,"n":"Knockdown"},{"t":5,"n":"Recovery Time"},{"t":5,"n":"Stamina Mult"}]}]}]},{"t":6,"n":"Body Data","c":[{"n":"NAM1 - Body Data Marker"},{"t":6,"n":"Male Body Data","c":[{"n":"MNAM - Male Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"}]}]}]},{"t":6,"n":"Female Body Data","c":[{"n":"FNAM - Female Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"}]}]}]}]},{"t":9,"n":"HNAM - Hairs","c":[{"t":3,"n":"Hair"}]},{"t":9,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eye"}]},{"t":3,"n":"GNAM - Body Part Data"},{"n":"NAM2 - Marker NAM2 #2"},{"n":"NAM3 - Marker NAM3 #3"},{"t":6,"n":"Male Behavior Graph","c":[{"n":"MNAM - Male Data Marker"}]},{"t":6,"n":"Female Behavior Graph","c":[{"n":"FNAM - Female Data Marker"}]},{"t":3,"n":"NAM4 - Material Type"},{"t":3,"n":"NAM5 - Impact Data Set"},{"t":3,"n":"NAM7 - Decapitation FX"},{"t":3,"n":"ONAM - Open Loot Sound"},{"t":3,"n":"LNAM - Close Loot Sound"},{"t":7,"n":"Biped Object Names","c":[{"t":2,"n":"NAME - Name"}]},{"t":10,"n":"Movement Types","c":[{"t":6,"n":"Movement Types","c":[{"t":3,"n":"MTYP - Movement Type"}]}]},{"t":3,"n":"VNAM - Equipment Flags"},{"t":9,"n":"Equip Slots","c":[{"t":3,"n":"QNAM - Equip Slot"}]},{"t":3,"n":"UNES - Unarmed Equip Slot"},{"t":7,"n":"Phoneme Target Names","c":[{"t":2,"n":"PHTN - Name"}]},{"t":6,"n":"FaceFX Phonemes","c":[{"t":6,"n":"IY","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]}]},{"t":3,"n":"WKMV - Base Movement Default - Walk"},{"t":3,"n":"RNMV - Base Movement Default - Run"},{"t":3,"n":"SWMV - Base Movement Default - Swim"},{"t":3,"n":"FLMV - Base Movement Default - Fly"},{"t":3,"n":"SNMV - Base Movement Default - Sneak"},{"t":3,"n":"SPMV - Base Movement Default - Sprint"},{"t":6,"p":1,"n":"Head Data","c":[{"n":"NAM0 - Head Data Marker"},{"t":6,"s":1,"p":1,"n":"Male Head Data","d":1,"c":[{"p":1,"n":"MNAM - Male Data Marker"}]},{"t":6,"s":1,"p":1,"n":"Female Head Data","d":1,"c":[{"p":1,"n":"NAM0 - Head Data Marker"},{"p":1,"n":"FNAM - Female Data Marker"}]}]},{"t":3,"n":"NAM8 - Morph race"},{"t":3,"n":"RNAM - Armor race"}]}]},"name":"Bash.R.Head","hash":"$57481EA8","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.R.Skills.json ================================================ {"records":"RACE","description":"R.Skills tag from Wrye Bash.\r\n\r\nUsed when the mod modifies race skill bonuses.","tree":{"records":[{"t":1,"p":1,"n":"RACE - Race","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":2,"p":1,"n":"DESC - Description"},{"t":3,"n":"SPCT - Count"},{"t":9,"n":"Actor Effects","c":[{"t":3,"n":"SPLO - Actor Effect"}]},{"t":3,"n":"WNAM - Skin"},{"t":6,"n":"BOD2 - Biped Body Template","c":[{"t":3,"n":"First Person Flags"},{"t":3,"n":"General Flags"},{"n":"Unused"},{"t":3,"n":"Armor Type"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":10,"p":1,"n":"Skill Boosts","c":[{"t":6,"p":1,"n":"Skill Boost","c":[{"t":3,"p":1,"n":"Skill"},{"t":3,"p":1,"n":"Boost"}]},{"t":6,"p":1,"n":"Skill Boost","c":[{"t":3,"p":1,"n":"Skill"},{"t":3,"p":1,"n":"Boost"}]},{"t":6,"p":1,"n":"Skill Boost","c":[{"t":3,"p":1,"n":"Skill"},{"t":3,"p":1,"n":"Boost"}]},{"t":6,"p":1,"n":"Skill Boost","c":[{"t":3,"p":1,"n":"Skill"},{"t":3,"p":1,"n":"Boost"}]},{"t":6,"p":1,"n":"Skill Boost","c":[{"t":3,"p":1,"n":"Skill"},{"t":3,"p":1,"n":"Boost"}]},{"t":6,"p":1,"n":"Skill Boost","c":[{"t":3,"p":1,"n":"Skill"},{"t":3,"p":1,"n":"Boost"}]},{"t":6,"p":1,"n":"Skill Boost","c":[{"t":3,"p":1,"n":"Skill"},{"t":3,"p":1,"n":"Boost"}]}]},{"t":11,"p":1,"n":"Unknown"},{"t":5,"p":1,"n":"Male Height"},{"t":5,"p":1,"n":"Female Height"},{"t":5,"p":1,"n":"Male Weight"},{"t":5,"p":1,"n":"Female Weight"},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Starting Health"},{"t":5,"p":1,"n":"Starting Magicka"},{"t":5,"p":1,"n":"Starting Stamina"},{"t":5,"p":1,"n":"Base Carry Weight"},{"t":5,"p":1,"n":"Base Mass"},{"t":5,"p":1,"n":"Acceleration rate"},{"t":5,"p":1,"n":"Deceleration rate"},{"t":3,"p":1,"n":"Size"},{"t":3,"p":1,"n":"Head Biped Object"},{"t":3,"p":1,"n":"Hair Biped Object"},{"t":5,"p":1,"n":"Injured Health Pct"},{"t":3,"p":1,"n":"Shield Biped Object"},{"t":5,"p":1,"n":"Health Regen"},{"t":5,"p":1,"n":"Magicka Regen"},{"t":5,"p":1,"n":"Stamina Regen"},{"t":5,"p":1,"n":"Unarmed Damage"},{"t":5,"p":1,"n":"Unarmed Reach"},{"t":3,"p":1,"n":"Body Biped Object"},{"t":5,"p":1,"n":"Aim Angle Tolerance"},{"t":5,"p":1,"n":"Flight Radius"},{"t":5,"p":1,"n":"Angular Acceleration Rate"},{"t":5,"p":1,"n":"Angular Tolerance"},{"t":3,"p":1,"n":"Flags 2"},{"t":6,"p":1,"n":"Mount Data","c":[{"t":5,"p":1,"n":"Offset X"},{"t":5,"p":1,"n":"Offset Y"},{"t":5,"p":1,"n":"Unknown"},{"t":5,"p":1,"n":"Unknown"},{"t":5,"p":1,"n":"Unknown"},{"t":5,"p":1,"n":"Unknown"},{"t":5,"p":1,"n":"Unknown"},{"t":5,"p":1,"n":"Unknown"},{"t":5,"p":1,"n":"Unknown"}]}]},{"n":"MNAM - Male Marker"},{"t":2,"n":"ANAM - Male Skeletal Model"},{"t":11,"n":"MODT - Texture Files Hashes"},{"n":"FNAM - Female Marker"},{"t":2,"n":"ANAM - Female Skeletal Model"},{"t":11,"n":"MODT - Texture Files Hashes"},{"n":"NAM2 - Marker NAM2 #1"},{"t":9,"n":"Movement Type Names","c":[{"t":2,"n":"MTNM - Name"}]},{"t":7,"n":"VTCK - Voices","c":[{"t":3,"n":"Voice #0 (Male)"},{"t":3,"n":"Voice #1 (Female)"}]},{"t":7,"n":"DNAM - Decapitate Armors","c":[{"t":3,"n":"Decapitate Armor #0 (Male)"},{"t":3,"n":"Decapitate Armor #1 (Female)"}]},{"t":7,"n":"HCLF - Default Hair Colors","c":[{"t":3,"n":"Default Hair Color #0 (Male)"},{"t":3,"n":"Default Hair Color #1 (Female)"}]},{"t":3,"n":"TINL - Total Number of Tints in List"},{"t":5,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"n":"UNAM - FaceGen - Face clamp"},{"t":3,"n":"ATKR - Attack Race"},{"t":10,"n":"Attacks","c":[{"t":6,"n":"Attack","c":[{"t":6,"n":"ATKD - Attack Data","c":[{"t":5,"n":"Damage Mult"},{"t":5,"n":"Attack Chance"},{"t":3,"n":"Attack Spell"},{"t":3,"n":"Attack Flags"},{"t":5,"n":"Attack Angle"},{"t":5,"n":"Strike Angle"},{"t":5,"n":"Stagger"},{"t":3,"n":"Attack Type"},{"t":5,"n":"Knockdown"},{"t":5,"n":"Recovery Time"},{"t":5,"n":"Stamina Mult"}]}]}]},{"t":6,"n":"Body Data","c":[{"n":"NAM1 - Body Data Marker"},{"t":6,"n":"Male Body Data","c":[{"n":"MNAM - Male Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"}]}]}]},{"t":6,"n":"Female Body Data","c":[{"n":"FNAM - Female Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"}]}]}]}]},{"t":9,"n":"HNAM - Hairs","c":[{"t":3,"n":"Hair"}]},{"t":9,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eye"}]},{"t":3,"n":"GNAM - Body Part Data"},{"n":"NAM2 - Marker NAM2 #2"},{"n":"NAM3 - Marker NAM3 #3"},{"t":6,"n":"Male Behavior Graph","c":[{"n":"MNAM - Male Data Marker"}]},{"t":6,"n":"Female Behavior Graph","c":[{"n":"FNAM - Female Data Marker"}]},{"t":3,"n":"NAM4 - Material Type"},{"t":3,"n":"NAM5 - Impact Data Set"},{"t":3,"n":"NAM7 - Decapitation FX"},{"t":3,"n":"ONAM - Open Loot Sound"},{"t":3,"n":"LNAM - Close Loot Sound"},{"t":7,"n":"Biped Object Names","c":[{"t":2,"n":"NAME - Name"}]},{"t":10,"n":"Movement Types","c":[{"t":6,"n":"Movement Types","c":[{"t":3,"n":"MTYP - Movement Type"}]}]},{"t":3,"n":"VNAM - Equipment Flags"},{"t":9,"n":"Equip Slots","c":[{"t":3,"n":"QNAM - Equip Slot"}]},{"t":3,"n":"UNES - Unarmed Equip Slot"},{"t":7,"n":"Phoneme Target Names","c":[{"t":2,"n":"PHTN - Name"}]},{"t":6,"n":"FaceFX Phonemes","c":[{"t":6,"n":"IY","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]}]},{"t":3,"n":"WKMV - Base Movement Default - Walk"},{"t":3,"n":"RNMV - Base Movement Default - Run"},{"t":3,"n":"SWMV - Base Movement Default - Swim"},{"t":3,"n":"FLMV - Base Movement Default - Fly"},{"t":3,"n":"SNMV - Base Movement Default - Sneak"},{"t":3,"n":"SPMV - Base Movement Default - Sprint"},{"t":6,"n":"Head Data","c":[{"n":"NAM0 - Head Data Marker"},{"t":6,"n":"Male Head Data","d":1,"c":[{"n":"MNAM - Male Data Marker"}]},{"t":6,"n":"Female Head Data","d":1,"c":[{"n":"NAM0 - Head Data Marker"},{"n":"FNAM - Female Data Marker"}]}]},{"t":3,"n":"NAM8 - Morph race"},{"t":3,"n":"RNAM - Armor race"}]}]},"name":"Bash.R.Skills","hash":"$6C639A99","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.Relations.json ================================================ {"records":"FACT","description":"Relations tag from Wrye Bash.\r\n\r\nUsed when the mod modifies faction relationships.","tree":{"records":[{"t":1,"p":1,"n":"FACT - Faction","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":10,"p":1,"n":"Relations","d":1,"c":[{"t":6,"p":1,"n":"XNAM - Relation","c":[{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Modifier"},{"t":3,"p":1,"n":"Group Combat Reaction"}]}]},{"t":6,"n":"DATA - Flags","c":[{"t":3,"n":"Flags"}]},{"t":3,"n":"JAIL - Exterior Jail Marker"},{"t":3,"n":"WAIT - Follower Wait Marker"},{"t":3,"n":"STOL - Stolen Goods Container"},{"t":3,"n":"PLCN - Player Inventory Container"},{"t":3,"n":"CRGR - Shared Crime Faction List"},{"t":3,"n":"JOUT - Jail Outfit"},{"t":6,"n":"CRVA - Crime Values","c":[{"t":3,"n":"Arrest"},{"t":3,"n":"Attack On Sight"},{"t":3,"n":"Murder"},{"t":3,"n":"Assault"},{"t":3,"n":"Trespass"},{"t":3,"n":"Pickpocket"},{"t":3,"n":"Unknown"},{"t":5,"n":"Steal Multiplier"},{"t":3,"n":"Escape"},{"t":3,"n":"Werewolf"}]},{"t":10,"n":"Ranks","c":[{"t":6,"n":"Rank","c":[{"t":3,"n":"RNAM - Rank#"}]}]},{"t":3,"n":"VEND - Vendor Buy\/Sell List"},{"t":3,"n":"VENC - Merchant Container"},{"t":6,"n":"VENV - Vendor Values","c":[{"t":3,"n":"Start Hour"},{"t":3,"n":"End Hour"},{"t":3,"n":"Radius"},{"t":11,"n":"Unknown 1"},{"t":3,"n":"Only Buys Stolen Items"},{"t":3,"n":"Not\/Sell Buy"},{"t":11,"n":"Unknown 2"}]},{"t":6,"n":"PLVD - Location","c":[{"t":3,"n":"Type"},{"t":12,"n":"Location Value"},{"t":3,"n":"Radius"}]},{"t":3,"n":"CITC - Condition Count"},{"t":8,"n":"Conditions","c":[{"t":6,"n":"Condition","c":[{"t":6,"n":"CTDA - ","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":12,"n":"Comparison Value"},{"t":3,"n":"Function"},{"t":11,"n":"Unused"},{"t":12,"n":"Parameter #1"},{"t":12,"n":"Parameter #2"},{"t":3,"n":"Run On"},{"t":12,"n":"Reference"},{"t":3,"n":"Parameter #3"}]}]}]}]}]},"name":"Bash.Relations","hash":"$D2149284","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.Relev.json ================================================ {"records":"LVLI,LVSP,LVLN","description":"Relev tag from Wrye Bash.\r\n\r\nRe-levelling of entries from the leveled list entries in Leveled Actor (LVLN), Leveled Item (LVLI) or Leveled Spell (LVSP) records.\r\n\r\nOnly changes to existing leveled list entries in the Level or Count element will be carried forward. Will also restore deleted leveled list entries.","tree":{"records":[{"t":1,"p":1,"n":"LVLI - Leveled Item","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":3,"n":"LVLD - Chance None"},{"t":3,"n":"LVLF - Flags"},{"t":3,"n":"LVLG - Global"},{"t":3,"n":"LLCT - Count"},{"t":10,"p":1,"o":1,"n":"Leveled List Entries","c":[{"t":6,"p":1,"n":"Leveled List Entry","c":[{"t":6,"p":1,"n":"LVLO - Base Data","c":[{"t":3,"p":1,"n":"Level"},{"t":11,"n":"Unknown"},{"t":3,"n":"Reference"},{"t":3,"p":1,"n":"Count"},{"t":11,"n":"Unknown"}]}]}]}]},{"t":1,"p":1,"n":"LVSP - Leveled Spell","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":3,"n":"LVLD - Chance None"},{"t":3,"n":"LVLF - Flags"},{"t":3,"n":"LLCT - Count"},{"t":10,"p":1,"o":1,"n":"Leveled List Entries","c":[{"t":6,"p":1,"n":"Leveled List Entry","c":[{"t":6,"p":1,"n":"LVLO - Base Data","c":[{"t":3,"p":1,"n":"Level"},{"t":11,"n":"Unknown"},{"t":3,"n":"Reference"},{"t":3,"p":1,"n":"Count"},{"t":11,"n":"Unknown"}]}]}]}]},{"t":1,"p":1,"n":"LVLN - Leveled NPC","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":3,"n":"LVLD - Chance None"},{"t":3,"n":"LVLF - Flags"},{"t":3,"n":"LVLG - Global"},{"t":3,"n":"LLCT - Count"},{"t":10,"p":1,"o":1,"n":"Leveled List Entries","c":[{"t":6,"p":1,"n":"Leveled List Entry","c":[{"t":6,"p":1,"n":"LVLO - Base Data","c":[{"t":3,"p":1,"n":"Level"},{"t":11,"n":"Unknown"},{"t":3,"n":"Reference"},{"t":3,"p":1,"n":"Count"},{"t":11,"n":"Unknown"}]}]}]},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]}]}]},"name":"Bash.Relev","hash":"1DFD70D9","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.Scripts.json ================================================ {"records":"ACHR,ACTI,ARMO,BOOK,CONT,DOOR,FLOR,FURN,INFO,INGR,KEYM,LIGH,MGEF,MISC,NPC_,PACK,PERK,PHZD,QUST,REFR,SCEN,TREE,WEAP","description":"Scripts tag from Wrye Bash.\r\n\r\nUsed when the mod modifies item, NPC or object scripts.","tree":{"records":[{"t":1,"p":1,"n":"ACHR - Placed NPC","c":[{"t":3,"n":"Cell"},{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags","c":[{"t":4,"n":"Persistent"}]},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":3,"n":"NAME - Base"},{"t":3,"n":"XEZN - Encounter Zone"},{"t":11,"n":"XRGD - Ragdoll Data"},{"t":11,"n":"XRGB - Ragdoll Biped Data"},{"t":6,"n":"Patrol Data","c":[{"t":5,"n":"XPRD - Idle Time"},{"n":"XPPA - Patrol Script Marker"},{"t":3,"n":"INAM - Idle"}]},{"t":3,"n":"XLCM - Level Modifier"},{"t":3,"n":"XMRC - Merchant Container"},{"t":3,"n":"XCNT - Count"},{"t":5,"n":"XRDS - Radius"},{"t":5,"n":"XHLP - Health"},{"t":10,"n":"Linked References","c":[{"t":6,"n":"XLKR - Linked Reference","c":[{"t":3,"n":"Keyword\/Ref"},{"t":3,"n":"Ref"}]}]},{"t":6,"n":"Activate Parents","c":[{"t":3,"n":"XAPD - Flags"}]},{"t":6,"n":"XCLP - Linked Reference Color","c":[{"t":6,"n":"Link Start Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Link End Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"XLCN - Persistent Location"},{"t":3,"n":"XLRL - Location Reference"},{"n":"XIS2 - Ignored by Sandbox"},{"t":7,"n":"XLRT - Location Ref Type","c":[{"t":3,"n":"Ref #0"}]},{"t":3,"n":"XHOR - Horse"},{"t":5,"n":"XHTW - Head-Tracking Weight"},{"t":5,"n":"XFVC - Favor Cost"},{"t":6,"n":"XESP - Enable Parent","c":[{"t":3,"n":"Reference"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":6,"n":"Ownership","c":[{"t":3,"n":"XOWN - Owner"}]},{"t":3,"n":"XEMI - Emittance"},{"t":3,"n":"XMBR - MultiBound Reference"},{"n":"XIBS - Ignored By Sandbox"},{"t":5,"n":"XSCL - Scale"},{"t":6,"n":"DATA - Position\/Rotation","c":[{"t":6,"n":"Position","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]},{"t":6,"n":"Rotation","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"ACTI - Activator","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"PNAM - Marker Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":3,"n":"Unused"}]},{"t":3,"n":"SNAM - Sound - Looping"},{"t":3,"n":"VNAM - Sound - Activation"},{"t":3,"n":"WNAM - Water Type"},{"t":2,"n":"RNAM - Activate Text Override"},{"t":3,"n":"FNAM - Flags"},{"t":3,"n":"KNAM - Interaction Keyword"}]},{"t":1,"p":1,"n":"ARMO - Armor","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":3,"n":"EITM - Object Effect"},{"t":3,"n":"EAMT - Enchantment Amount"},{"t":6,"n":"Male world model","c":[{"t":2,"n":"MOD2 - Model Filename"}]},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"}]},{"t":6,"n":"Female world model","c":[{"t":2,"n":"MOD4 - Model Filename"}]},{"t":6,"n":"Icon 2 (female)","c":[{"t":2,"n":"ICO2 - Large Icon filename"}]},{"t":6,"n":"BOD2 - Biped Body Template","c":[{"t":3,"n":"First Person Flags"},{"t":3,"n":"General Flags"},{"n":"Unused"},{"t":3,"n":"Armor Type"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":2,"n":"BMCT - Ragdoll Constraint Template"},{"t":3,"n":"ETYP - Equipment Type"},{"t":3,"n":"BIDS - Bash Impact Data Set"},{"t":3,"n":"BAMT - Alternate Block Material"},{"t":3,"n":"RNAM - Race"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":2,"n":"DESC - Description"},{"t":7,"n":"Armature","c":[{"t":3,"n":"MODL - Model Filename"}]},{"t":6,"n":"DATA - Data","c":[{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]},{"t":3,"n":"DNAM - Armor Rating"},{"t":3,"n":"TNAM - Template Armor"}]},{"t":1,"p":1,"n":"BOOK - Book","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"}]},{"t":2,"n":"DESC - Book Text"},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"DATA - Data","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":12,"n":"Teaches"},{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]},{"t":3,"n":"INAM - Inventory Art"},{"t":2,"n":"CNAM - Description"}]},{"t":1,"p":1,"n":"CONT - Container","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":3,"n":"COCT - Count"},{"t":10,"n":"Items","c":[{"t":6,"n":"Item","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Flags"},{"t":5,"n":"Weight"}]},{"t":3,"n":"SNAM - Sound - Open"},{"t":3,"n":"QNAM - Sound - Close"}]},{"t":1,"p":1,"n":"DOOR - Door","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"SNAM - Sound - Open"},{"t":3,"n":"ANAM - Sound - Close"},{"t":3,"n":"BNAM - Sound - Loop"},{"t":3,"n":"FNAM - Flags"}]},{"t":1,"p":1,"n":"FLOR - Flora","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":11,"n":"PNAM - Unknown"},{"t":2,"n":"RNAM - Activate Text Override"},{"t":11,"n":"FNAM - Unknown"},{"t":3,"n":"PFIG - Ingredient"},{"t":3,"n":"SNAM - Sound"},{"t":6,"n":"PFPC - Seasonal ingredient production","c":[{"t":3,"n":"Spring"},{"t":3,"n":"Summer "},{"t":3,"n":"Fall"},{"t":3,"n":"Winter"}]}]},{"t":1,"p":1,"n":"FURN - Furniture","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":11,"n":"PNAM - Unknown"},{"t":3,"n":"FNAM - Flags"},{"t":3,"n":"KNAM - Interaction Keyword"},{"t":3,"n":"MNAM - Active Markers \/ Flags"},{"t":6,"n":"WBDT - Workbench Data","c":[{"t":3,"n":"Bench Type"},{"t":3,"n":"Uses Skill"}]},{"t":3,"n":"NAM1 - Associated Spell"},{"t":8,"n":"Markers","c":[{"t":6,"n":"Marker","c":[{"t":3,"n":"ENAM - Marker Index"}]}]},{"t":8,"n":"Marker Entry Points","c":[{"t":6,"n":"FNPR - Marker","c":[{"t":3,"n":"Type"},{"t":3,"n":"Entry Points"}]}]},{"t":2,"n":"XMRK - Model Filename"}]},{"t":1,"p":1,"n":"INFO - Dialog response","c":[{"t":3,"n":"Topic"},{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":6,"p":1,"n":"Info VMAD","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]},{"t":6,"p":1,"n":"Script Fragments Info","c":[{"t":3,"p":1,"n":"Unknown"},{"t":3,"p":1,"n":"Info Fragments Flags"},{"t":2,"p":1,"n":"fileName"},{"t":7,"p":1,"n":"Info Fragments","c":[{"t":6,"p":1,"n":"Info Fragment #0","c":[{"t":3,"p":1,"n":"Unknown"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]}]}]}]}]},{"t":11,"n":"DATA - Unknown"},{"t":6,"n":"ENAM - Response flags","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Reset Hours"}]},{"t":3,"n":"TPIC - Topic"},{"t":3,"n":"PNAM - Previous INFO"},{"t":3,"n":"CNAM - Favor Level"},{"t":7,"n":"Link To","c":[{"t":3,"n":"TCLT - Response"}]},{"t":3,"n":"DNAM - Response Data"},{"t":8,"n":"Responses","c":[{"t":6,"n":"Response","c":[{"t":6,"n":"TRDT - Response Data","c":[{"t":3,"n":"Emotion Type"},{"t":3,"n":"Emotion Value"},{"t":11,"n":"Unused"},{"t":3,"n":"Response number"},{"t":11,"n":"Unused"},{"t":3,"n":"Sound"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]}]}]},{"t":8,"n":"Conditions","c":[{"t":6,"n":"Condition","c":[{"t":6,"n":"CTDA - ","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":12,"n":"Comparison Value"},{"t":3,"n":"Function"},{"t":11,"n":"Unused"},{"t":12,"n":"Parameter #1"},{"t":12,"n":"Parameter #2"},{"t":3,"n":"Run On"},{"t":12,"n":"Reference"},{"t":3,"n":"Parameter #3"}]}]}]},{"t":8,"n":"Unknown","c":[{"t":6,"n":"Unknown","c":[{"t":11,"n":"SCHR - Unknown"}]}]},{"t":2,"n":"RNAM - Prompt"},{"t":3,"n":"ANAM - Speaker"},{"t":3,"n":"TWAT - Walk Away Topic"},{"t":3,"n":"ONAM - Audio Output Override"}]},{"t":1,"p":1,"n":"INGR - Ingredient","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"ETYP - Equipment Type"},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]},{"t":6,"n":"ENIT - Effect Data","c":[{"t":3,"n":"Ingredient Value"},{"t":3,"n":"Flags"}]},{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":3,"n":"EFID - Base Effect"},{"t":6,"n":"EFIT - ","c":[{"t":5,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"}]}]}]}]},{"t":1,"p":1,"n":"KEYM - Key","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]}]},{"t":1,"p":1,"n":"LIGH - Light","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"}]},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Time"},{"t":3,"n":"Radius"},{"t":6,"n":"Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":3,"n":"Unknown"}]},{"t":3,"n":"Flags"},{"t":5,"n":"Falloff Exponent"},{"t":5,"n":"FOV"},{"t":5,"n":"Near Clip"},{"t":6,"n":"Flicker Effect","c":[{"t":5,"n":"Period"},{"t":5,"n":"Intensity Amplitude"},{"t":5,"n":"Movement Amplitude"}]},{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]},{"t":5,"n":"FNAM - Fade value"},{"t":3,"n":"SNAM - Sound"}]},{"t":1,"p":1,"n":"MGEF - Magic Effect","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":2,"n":"FULL - Name"},{"t":3,"n":"MDOB - Menu Display Object"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"Magic Effect Data","c":[{"t":6,"n":"DATA - Data","c":[{"t":3,"n":"Flags"},{"t":5,"n":"Base Cost"},{"t":12,"n":"Assoc. Item"},{"t":3,"n":"Magic Skill"},{"t":3,"n":"Resist Value"},{"t":3,"n":"Counter Effect count"},{"t":11,"n":"Unused"},{"t":3,"n":"Casting Light"},{"t":5,"n":"Taper Weight"},{"t":3,"n":"Hit Shader"},{"t":3,"n":"Enchant Shader"},{"t":3,"n":"Minimum Skill Level"},{"t":6,"n":"Spellmaking","c":[{"t":3,"n":"Area"},{"t":5,"n":"Casting Time"}]},{"t":5,"n":"Taper Curve"},{"t":5,"n":"Taper Duration"},{"t":5,"n":"Second AV Weight"},{"t":3,"n":"Archtype"},{"t":3,"n":"Actor Value"},{"t":3,"n":"Projectile"},{"t":3,"n":"Explosion"},{"t":3,"n":"Casting Type"},{"t":3,"n":"Delivery"},{"t":3,"n":"Second Actor Value"},{"t":3,"n":"Casting Art"},{"t":3,"n":"Hit Effect Art"},{"t":3,"n":"Impact Data"},{"t":5,"n":"Skill Usage Multiplier"},{"t":6,"n":"Dual Casting","c":[{"t":3,"n":"Art"},{"t":5,"n":"Scale"}]},{"t":3,"n":"Enchant Art"},{"t":11,"n":"Unknown"},{"t":11,"n":"Unknown"},{"t":3,"n":"Equip Ability"},{"t":3,"n":"Image Space Modifier"},{"t":3,"n":"Perk to Apply"},{"t":3,"n":"Casting Sound Level"},{"t":6,"n":"Script Effect AI","c":[{"t":5,"n":"Score"},{"t":5,"n":"Delay Time"}]}]}]},{"t":9,"n":"Counter Effects","c":[{"t":3,"n":"ESCE - Effect"}]},{"t":8,"n":"SNDD - Sounds","c":[{"t":6,"n":" #0","c":[{"t":3,"n":"Type"},{"t":3,"n":"Sound"}]}]},{"t":2,"n":"DNAM - Magic Item Description"},{"t":8,"n":"Conditions","c":[{"t":6,"n":"Condition","c":[{"t":6,"n":"CTDA - ","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":12,"n":"Comparison Value"},{"t":3,"n":"Function"},{"t":11,"n":"Unused"},{"t":12,"n":"Parameter #1"},{"t":12,"n":"Parameter #2"},{"t":3,"n":"Run On"},{"t":12,"n":"Reference"},{"t":3,"n":"Parameter #3"}]}]}]}]},{"t":1,"p":1,"n":"MISC - Misc. Item","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"DATA - Data","c":[{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]}]},{"t":1,"p":1,"n":"NPC_ - Non-Player Character (Actor)","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":6,"n":"ACBS - Configuration","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Magicka Offset"},{"t":3,"n":"Stamina Offset"},{"t":12,"n":"Level"},{"t":3,"n":"Calc min level"},{"t":3,"n":"Calc max level"},{"t":3,"n":"Speed Multiplier"},{"t":3,"n":"Disposition Base (unused)"},{"t":3,"n":"Template Flags"},{"t":3,"n":"Health Offset"},{"t":3,"n":"Bleedout Override"}]},{"t":10,"n":"Factions","c":[{"t":6,"n":"SNAM - Faction","c":[{"t":3,"n":"Faction"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"INAM - Death item"},{"t":3,"n":"VTCK - Voice"},{"t":3,"n":"TPLT - Template"},{"t":3,"n":"RNAM - Race"},{"t":3,"n":"SPCT - Count"},{"t":9,"n":"Actor Effects","c":[{"t":3,"n":"SPLO - Actor Effect"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"WNAM - Worn Armor"},{"t":3,"n":"ANAM - Far away model"},{"t":3,"n":"ATKR - Attack Race"},{"t":10,"n":"Attacks","c":[{"t":6,"n":"Attack","c":[{"t":6,"n":"ATKD - Attack Data","c":[{"t":5,"n":"Damage Mult"},{"t":5,"n":"Attack Chance"},{"t":3,"n":"Attack Spell"},{"t":3,"n":"Attack Flags"},{"t":5,"n":"Attack Angle"},{"t":5,"n":"Strike Angle"},{"t":5,"n":"Stagger"},{"t":3,"n":"Attack Type"},{"t":5,"n":"Knockdown"},{"t":5,"n":"Recovery Time"},{"t":5,"n":"Stamina Mult"}]}]}]},{"t":3,"n":"SPOR - Spectator override package list"},{"t":3,"n":"OCOR - Observe dead body override package list"},{"t":3,"n":"GWOR - Guard warn override package list"},{"t":3,"n":"ECOR - Combat override package list"},{"t":3,"n":"PRKZ - Perk Count"},{"t":10,"n":"Perks","c":[{"t":6,"n":"PRKR - Perk","c":[{"t":3,"n":"Perk"},{"t":3,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"COCT - Count"},{"t":10,"n":"Items","c":[{"t":6,"n":"Item","c":[{"t":6,"n":"CNTO - Item","c":[{"t":3,"n":"Item"},{"t":3,"n":"Count"}]}]}]},{"t":6,"n":"AIDT - AI Data","c":[{"t":3,"n":"Aggression"},{"t":3,"n":"Confidence"},{"t":3,"n":"Energy Level"},{"t":3,"n":"Responsibility"},{"t":3,"n":"Mood"},{"t":3,"n":"Assistance"},{"t":6,"n":"Aggro","c":[{"t":3,"n":"Aggro Radius Behavior"},{"t":3,"n":"Unknown"},{"t":3,"n":"Warn"},{"t":3,"n":"Warn\/Attack"},{"t":3,"n":"Attack"}]}]},{"t":7,"n":"Packages","c":[{"t":3,"n":"PKID - Package"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":3,"n":"CNAM - Class"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"SHRT - Short Name"},{"t":11,"n":"DATA - Marker"},{"t":6,"n":"DNAM - Player Skills","c":[{"t":7,"n":"Skill Values","c":[{"t":3,"n":"Skill #0 (OneHanded)"},{"t":3,"n":"Skill #1 (TwoHanded)"},{"t":3,"n":"Skill #2 (Marksman)"},{"t":3,"n":"Skill #3 (Block)"},{"t":3,"n":"Skill #4 (Smithing)"},{"t":3,"n":"Skill #5 (HeavyArmor)"},{"t":3,"n":"Skill #6 (LightArmor)"},{"t":3,"n":"Skill #7 (Pickpocket)"},{"t":3,"n":"Skill #8 (Lockpicking)"},{"t":3,"n":"Skill #9 (Sneak)"},{"t":3,"n":"Skill #10 (Alchemy)"},{"t":3,"n":"Skill #11 (Speechcraft)"},{"t":3,"n":"Skill #12 (Alteration)"},{"t":3,"n":"Skill #13 (Conjuration)"},{"t":3,"n":"Skill #14 (Destruction)"},{"t":3,"n":"Skill #15 (Illusion)"},{"t":3,"n":"Skill #16 (Restoration)"},{"t":3,"n":"Skill #17 (Enchanting)"}]},{"t":7,"n":"Skill Offsets","c":[{"t":3,"n":"Skill #0 (OneHanded)"},{"t":3,"n":"Skill #1 (TwoHanded)"},{"t":3,"n":"Skill #2 (Marksman)"},{"t":3,"n":"Skill #3 (Block)"},{"t":3,"n":"Skill #4 (Smithing)"},{"t":3,"n":"Skill #5 (HeavyArmor)"},{"t":3,"n":"Skill #6 (LightArmor)"},{"t":3,"n":"Skill #7 (Pickpocket)"},{"t":3,"n":"Skill #8 (Lockpicking)"},{"t":3,"n":"Skill #9 (Sneak)"},{"t":3,"n":"Skill #10 (Alchemy)"},{"t":3,"n":"Skill #11 (Speechcraft)"},{"t":3,"n":"Skill #12 (Alteration)"},{"t":3,"n":"Skill #13 (Conjuration)"},{"t":3,"n":"Skill #14 (Destruction)"},{"t":3,"n":"Skill #15 (Illusion)"},{"t":3,"n":"Skill #16 (Restoration)"},{"t":3,"n":"Skill #17 (Enchanting)"}]},{"t":3,"n":"Health"},{"t":3,"n":"Magicka"},{"t":3,"n":"Stamina"},{"t":11,"n":"Unused"},{"t":5,"n":"Far away model distance"},{"t":3,"n":"Geared up weapons"},{"t":11,"n":"Unused"}]},{"t":9,"n":"Head Parts","c":[{"t":3,"n":"PNAM - Head Part"}]},{"t":3,"n":"HCLF - Hair Color"},{"t":3,"n":"ZNAM - Combat Style"},{"t":3,"n":"GNAM - Gift Filter"},{"t":11,"n":"NAM5 - Unknown"},{"t":5,"n":"NAM6 - Height"},{"t":5,"n":"NAM7 - Weight"},{"t":3,"n":"NAM8 - Sound Level"},{"t":10,"n":"Sound Types","c":[{"t":6,"n":"Sound Type","c":[{"t":3,"n":"CSDT - Type"},{"t":10,"n":"Sounds","c":[{"t":6,"n":"Sound","c":[{"t":3,"n":"CSDI - Sound"},{"t":3,"n":"CSDC - Sound Chance"}]}]}]}]},{"t":3,"n":"CSCR - Inherits Sounds From"},{"t":3,"n":"DOFT - Default outfit"},{"t":3,"n":"SOFT - Sleeping outfit"},{"t":3,"n":"DPLT - Default Package List"},{"t":3,"n":"CRIF - Crime faction"},{"t":3,"n":"FTST - Head texture"},{"t":6,"n":"QNAM - Texture lighting","c":[{"t":5,"n":"Red"},{"t":5,"n":"Green"},{"t":5,"n":"Blue"}]},{"t":6,"n":"NAM9 - Face morph","c":[{"t":5,"n":"Nose Long\/Short"},{"t":5,"n":"Nose Up\/Down"},{"t":5,"n":"Jaw Up\/Down"},{"t":5,"n":"Jaw Narrow\/Wide"},{"t":5,"n":"Jaw Farward\/Back"},{"t":5,"n":"Cheeks Up\/Down"},{"t":5,"n":"Cheeks Farward\/Back"},{"t":5,"n":"Eyes Up\/Down"},{"t":5,"n":"Eyes In\/Out"},{"t":5,"n":"Brows Up\/Down"},{"t":5,"n":"Brows In\/Out"},{"t":5,"n":"Brows Farward\/Back"},{"t":5,"n":"Lips Up\/Down"},{"t":5,"n":"Lips In\/Out"},{"t":5,"n":"Chin Narrow\/Wide"},{"t":5,"n":"Chin Up\/Down"},{"t":5,"n":"Chin Underbite\/Overbite"},{"t":5,"n":"Eyes Farward\/Back"},{"t":5,"n":"Unknown"}]},{"t":6,"n":"NAMA - Face parts","c":[{"t":3,"n":"Nose"},{"t":3,"n":"Unknown"},{"t":3,"n":"Eyes"},{"t":3,"n":"Mouth"}]},{"t":10,"n":"Tint Layers","c":[{"t":6,"n":"Layer","c":[{"t":3,"n":"TINI - Tint Index"}]}]}]},{"t":1,"p":1,"n":"PACK - Package","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":6,"p":1,"n":"Pack VMAD","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]},{"t":6,"p":1,"n":"Script Fragments Package","c":[{"t":3,"p":1,"n":"Unknown"},{"t":3,"p":1,"n":"Package Fragments Flags"},{"t":2,"p":1,"n":"fileName"},{"t":7,"p":1,"n":"Package Fragments","c":[{"t":6,"p":1,"n":"Package Fragment #0","c":[{"t":3,"p":1,"n":"Unknown"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]}]}]}]}]},{"t":6,"n":"PKDT - Pack Data","c":[{"t":3,"n":"General Flags"},{"t":3,"n":"Type"},{"t":3,"n":"Interrupt Override"},{"t":3,"n":"Preferred Speed"},{"t":11,"n":"Unknown"},{"t":3,"n":"Interrupt Flags"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"PSDT - Schedule","c":[{"t":3,"n":"Month"},{"t":3,"n":"Day of week"},{"t":3,"n":"Date"},{"t":3,"n":"Hour"},{"t":3,"n":"Minute"},{"t":11,"n":"Unused"},{"t":3,"n":"Duration (minutes)"}]},{"t":8,"n":"Conditions","c":[{"t":6,"n":"Condition","c":[{"t":6,"n":"CTDA - ","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":12,"n":"Comparison Value"},{"t":3,"n":"Function"},{"t":11,"n":"Unused"},{"t":12,"n":"Parameter #1"},{"t":12,"n":"Parameter #2"},{"t":3,"n":"Run On"},{"t":12,"n":"Reference"},{"t":3,"n":"Parameter #3"}]}]}]},{"t":6,"n":"Idle Animations","c":[{"t":3,"n":"IDLF - Flags"},{"t":6,"n":"IDLC - ","c":[{"t":3,"n":"Animation Count"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"IDLT - Idle Timer Setting"},{"t":7,"n":"IDLA - Animations","c":[{"t":3,"n":"Animation #0"}]}]},{"t":3,"n":"CNAM - Combat Style"},{"t":3,"n":"QNAM - Owner Quest"},{"t":6,"n":"PKCU - Counter","c":[{"t":3,"n":"Data Input Count"},{"t":3,"n":"Package Template"},{"t":3,"n":"Version Counter (autoincremented)"}]},{"t":6,"n":"Package Data","c":[{"t":8,"n":"Data Input Values","c":[{"t":6,"n":"Value","c":[{"t":2,"n":"ANAM - Type"}]}]}]},{"t":11,"n":"XNAM - Marker"},{"t":6,"n":"Procedure Tree","c":[{"t":8,"n":"Branches","c":[{"t":6,"n":"Branch","c":[{"t":2,"n":"ANAM - Branch Type"}]}]}]},{"t":8,"n":"Data Inputs","c":[{"t":6,"n":"Data Input","c":[{"t":3,"n":"UNAM - Index"}]}]},{"t":6,"n":"OnBegin","c":[{"n":"POBA - OnBegin Marker"},{"t":3,"n":"INAM - Idle"}]},{"t":6,"n":"OnEnd","c":[{"n":"POEA - OnEnd Marker"},{"t":3,"n":"INAM - Idle"}]},{"t":6,"n":"OnChange","c":[{"n":"POCA - OnChange Marker"},{"t":3,"n":"INAM - Idle"}]}]},{"t":1,"p":1,"n":"PERK - Perk","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":6,"p":1,"n":"Perk VMAD","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]},{"t":6,"p":1,"n":"Script Fragments Perk","c":[{"t":3,"p":1,"n":"Unknown"},{"t":2,"p":1,"n":"fileName"},{"t":9,"p":1,"n":"Perk Fragments","c":[{"t":6,"p":1,"n":"Perk Fragment","c":[{"t":3,"p":1,"n":"Fragment Index"},{"t":3,"p":1,"n":"Unknown"},{"t":3,"p":1,"n":"Unknown"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]}]}]}]}]},{"t":2,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"}]},{"t":8,"n":"Conditions","c":[{"t":6,"n":"Condition","c":[{"t":6,"n":"CTDA - ","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":12,"n":"Comparison Value"},{"t":3,"n":"Function"},{"t":11,"n":"Unused"},{"t":12,"n":"Parameter #1"},{"t":12,"n":"Parameter #2"},{"t":3,"n":"Run On"},{"t":12,"n":"Reference"},{"t":3,"n":"Parameter #3"}]}]}]},{"t":6,"n":"DATA - Data","c":[{"t":3,"n":"Trait"},{"t":3,"n":"Level"},{"t":3,"n":"Num Ranks"},{"t":3,"n":"Playable"},{"t":3,"n":"Hidden"}]},{"t":3,"n":"NNAM - Next Perk"},{"t":10,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":6,"n":"PRKE - Header","c":[{"t":3,"n":"Type"},{"t":3,"n":"Rank"},{"t":3,"n":"Priority"}]},{"t":12,"n":"DATA - Effect Data","c":[{"t":6,"n":"Quest + Stage","c":[{"t":3,"n":"Quest"},{"t":3,"n":"Quest Stage"},{"t":11,"n":"Unused"}]}]},{"n":"PRKF - End Marker"}]}]}]},{"t":1,"p":1,"n":"PHZD - Placed Hazard","c":[{"t":3,"n":"Cell"},{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":3,"n":"NAME - Projectile"},{"t":3,"n":"XEZN - Encounter Zone"},{"t":6,"n":"Ownership","c":[{"t":3,"n":"XOWN - Owner"}]},{"t":5,"n":"XHTW - Head-Tracking Weight"},{"t":5,"n":"XFVC - Favor Cost"},{"t":10,"n":"Reflected\/Refracted By","c":[{"t":6,"n":"XPWR - Water","c":[{"t":3,"n":"Reference"},{"t":3,"n":"Type"}]}]},{"t":10,"n":"Linked References","c":[{"t":6,"n":"XLKR - Linked Reference","c":[{"t":3,"n":"Keyword\/Ref"},{"t":3,"n":"Ref"}]}]},{"t":6,"n":"Activate Parents","c":[{"t":3,"n":"XAPD - Flags"}]},{"t":6,"n":"XESP - Enable Parent","c":[{"t":3,"n":"Reference"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"n":"XEMI - Emittance"},{"t":3,"n":"XMBR - MultiBound Reference"},{"n":"XIS2 - Ignored by Sandbox"},{"t":7,"n":"XLRT - Location Ref Type","c":[{"t":3,"n":"Ref #0"}]},{"t":3,"n":"XLRL - Location Reference"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown #0"},{"t":5,"n":"Unknown #1"},{"t":5,"n":"Unknown #2"}]},{"t":5,"n":"XSCL - Scale"},{"t":6,"n":"DATA - Position\/Rotation","c":[{"t":6,"n":"Position","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]},{"t":6,"n":"Rotation","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"QUST - Quest","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":6,"p":1,"n":"Quest VMAD","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]},{"t":6,"p":1,"n":"Script Fragments Quest","c":[{"t":3,"p":1,"n":"Unknown"},{"t":3,"p":1,"n":"fragmentCount"},{"t":2,"p":1,"n":"fileName"},{"t":9,"p":1,"n":"Quest Fragments","c":[{"t":6,"p":1,"n":"Quest Fragment","c":[{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Unknown"},{"t":3,"p":1,"n":"Quest Stage Index"},{"t":3,"p":1,"n":"Unknown"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]},{"t":9,"p":1,"n":"Aliases","c":[{"t":6,"p":1,"n":"Alias","c":[{"t":12,"p":1,"n":"Object Union","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Unused"}]}]},{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":9,"p":1,"n":"Alias Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]}]}]}]}]},{"t":2,"n":"FULL - Name"},{"t":6,"n":"DNAM - General","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Priority"},{"t":3,"n":"Form Version"},{"t":11,"n":"Unknown"},{"t":3,"n":"Type"}]},{"t":2,"n":"ENAM - Event"},{"t":7,"n":"Text Display Globals","c":[{"t":3,"n":"QTGL - Global"}]},{"t":2,"n":"FLTR - Object Window Filter"},{"t":6,"n":"Quest Dialogue Conditions","c":[{"t":8,"n":"Conditions","c":[{"t":6,"n":"Condition","c":[{"t":6,"n":"CTDA - ","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":12,"n":"Comparison Value"},{"t":3,"n":"Function"},{"t":11,"n":"Unused"},{"t":12,"n":"Parameter #1"},{"t":12,"n":"Parameter #2"},{"t":3,"n":"Run On"},{"t":12,"n":"Reference"},{"t":3,"n":"Parameter #3"}]}]}]}]},{"n":"NEXT - Marker"},{"t":8,"n":"Conditions","c":[{"t":6,"n":"Condition","c":[{"t":6,"n":"CTDA - ","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":12,"n":"Comparison Value"},{"t":3,"n":"Function"},{"t":11,"n":"Unused"},{"t":12,"n":"Parameter #1"},{"t":12,"n":"Parameter #2"},{"t":3,"n":"Run On"},{"t":12,"n":"Reference"},{"t":3,"n":"Parameter #3"}]}]}]},{"t":10,"n":"Stages","c":[{"t":6,"n":"Stage","c":[{"t":6,"n":"INDX - Stage Index","c":[{"t":3,"n":"Stage Index"},{"t":3,"n":"Flags"},{"t":3,"n":"Unknown"}]}]}]},{"t":8,"n":"Objectives","c":[{"t":6,"n":"Objective","c":[{"t":3,"n":"QOBJ - Objective Index"},{"t":2,"n":"NNAM - Display Text"}]}]},{"t":11,"n":"ANAM - Aliases Marker"},{"t":8,"n":"Aliases","c":[{"t":6,"n":"Alias","c":[{"t":3,"n":"ALST - Reference Alias ID"},{"n":"ALED - Alias End"}]}]},{"t":2,"n":"NNAM - Description"},{"t":8,"n":"Targets","c":[{"t":6,"n":"Target","c":[{"t":6,"n":"QSTA - Target","c":[{"t":3,"n":"Target"},{"t":3,"n":"Flags"},{"t":11,"n":"Unknown"}]}]}]}]},{"t":1,"p":1,"n":"REFR - Placed Object","c":[{"t":3,"n":"Cell"},{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags","c":[{"t":4,"n":"Persistent"}]},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":3,"n":"NAME - Base"},{"t":6,"n":"XMBO - Bound Half Extents","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]},{"t":6,"n":"XPRM - Primitive","c":[{"t":6,"n":"Bounds","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]},{"t":6,"n":"Color","c":[{"t":5,"n":"Red"},{"t":5,"n":"Green"},{"t":5,"n":"Blue"}]},{"t":5,"n":"Unknown"},{"t":3,"n":"Type"}]},{"t":11,"n":"XORD - Unknown"},{"t":6,"n":"XOCP - Occlusion Plane Data","c":[{"t":6,"n":"Size","c":[{"t":5,"n":"Width"},{"t":5,"n":"Height"}]},{"t":6,"n":"Position","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]},{"t":6,"n":"Rotation (Quaternion?)","c":[{"t":5,"n":"q1"},{"t":5,"n":"q2"},{"t":5,"n":"q3"},{"t":5,"n":"q4"}]}]},{"t":8,"n":"XPOD - Portal Data","c":[{"t":6,"n":"References #0","c":[{"t":3,"n":"Origin"},{"t":3,"n":"Destination"}]}]},{"t":6,"n":"XPTL - Room Portal (unused)","c":[{"t":6,"n":"Size","c":[{"t":5,"n":"Width"},{"t":5,"n":"Height"}]},{"t":6,"n":"Position","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]},{"t":6,"n":"Rotation (Quaternion?)","c":[{"t":5,"n":"q1"},{"t":5,"n":"q2"},{"t":5,"n":"q3"},{"t":5,"n":"q4"}]}]},{"t":6,"n":"Bound Data","c":[{"t":6,"n":"XRMR - Header","c":[{"t":3,"n":"Linked Rooms Count"},{"t":3,"n":"Flags"},{"t":11,"n":"Unknown"}]}]},{"n":"XMBP - MultiBound Primitive Marker"},{"t":11,"n":"XRGD - Ragdoll Data"},{"t":11,"n":"XRGB - Ragdoll Biped Data"},{"t":5,"n":"XRDS - Radius"},{"t":10,"n":"Reflected\/Refracted By","c":[{"t":6,"n":"XPWR - Water","c":[{"t":3,"n":"Reference"},{"t":3,"n":"Type"}]}]},{"t":9,"n":"Lit Water","c":[{"t":3,"n":"XLTW - Water"}]},{"t":3,"n":"XEMI - Emittance"},{"t":6,"n":"XLIG - Light Data","c":[{"t":5,"n":"FOV 90+\/-"},{"t":5,"n":"Fade 1.35+\/-"},{"t":11,"n":"Unknown"},{"t":5,"n":"Shadow Depth Bias"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"XALP - Alpha","c":[{"t":3,"n":"Cutoff"},{"t":3,"n":"Base"}]},{"t":6,"n":"XTEL - Teleport Destination","c":[{"t":3,"n":"Door"},{"t":6,"n":"Position\/Rotation","c":[{"t":6,"n":"Position","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]},{"t":6,"n":"Rotation","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]}]},{"t":3,"n":"Flags"}]},{"t":3,"n":"XTNM - Teleport Message Box"},{"t":3,"n":"XMBR - MultiBound Reference"},{"t":11,"n":"XWCN - Unknown"},{"t":11,"n":"XWCS - Unknown"},{"t":6,"n":"XWCU - Water Velocity","c":[{"t":5,"n":"X Offset"},{"t":5,"n":"Y Offset"},{"t":5,"n":"Z Offset"},{"t":11,"n":"Unknown"},{"t":5,"n":"X Angle"},{"t":5,"n":"Y Angle"},{"t":5,"n":"Z Angle"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"XCVL - Unknown","c":[{"t":11,"n":"Unknown"},{"t":5,"n":"X Angle"},{"t":11,"n":"Unknown"}]},{"t":3,"n":"XCZR - Unknown"},{"t":11,"n":"XCZA - Unknown"},{"t":3,"n":"XCZC - Unknown"},{"t":5,"n":"XSCL - Scale"},{"t":3,"n":"XSPC - Spawn Container"},{"t":6,"n":"Activate Parents","c":[{"t":3,"n":"XAPD - Flags"}]},{"t":3,"n":"XLIB - Leveled Item Base Object"},{"t":3,"n":"XLCM - Level Modifier"},{"t":3,"n":"XLCN - Persistent Location"},{"t":3,"n":"XTRI - Collision Layer"},{"t":6,"n":"XLOC - Lock Data","c":[{"t":3,"n":"Level"},{"t":11,"n":"Unused"},{"t":3,"n":"Key"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"},{"t":11,"n":"Unused"}]},{"t":3,"n":"XEZN - Encounter Zone"},{"t":6,"n":"XNDP - Navigation Door Link","c":[{"t":3,"n":"Navigation Mesh"},{"t":3,"n":"Teleport Marker Triangle"},{"t":11,"n":"Unused"}]},{"t":7,"n":"XLRT - Location Ref Type","c":[{"t":3,"n":"Ref #0"}]},{"n":"XIS2 - Ignored by Sandbox"},{"t":6,"n":"Ownership","c":[{"t":3,"n":"XOWN - Owner"}]},{"t":3,"n":"XCNT - Item Count"},{"t":5,"n":"XCHG - Charge"},{"t":3,"n":"XLRL - Location Reference"},{"t":6,"n":"XESP - Enable Parent","c":[{"t":3,"n":"Reference"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"n":"Linked References","c":[{"t":6,"n":"XLKR - Linked Reference","c":[{"t":3,"n":"Keyword\/Ref"},{"t":3,"n":"Ref"}]}]},{"t":8,"n":"Patrol","c":[{"t":6,"n":"Data","c":[{"t":5,"n":"XPRD - Idle Time"},{"n":"XPPA - Patrol Script Marker"},{"t":3,"n":"INAM - Idle"}]}]},{"t":3,"n":"XACT - Action Flag"},{"t":5,"n":"XHTW - Head-Tracking Weight"},{"t":5,"n":"XFVC - Favor Cost"},{"n":"ONAM - Open by Default"},{"t":6,"n":"Map Marker","c":[{"n":"XMRK - Map Marker Data"},{"t":3,"n":"FNAM - Map Flags"},{"t":2,"n":"FULL - Name"},{"t":6,"n":"TNAM - ","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"XATR - Attach Ref"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown #0"},{"t":5,"n":"Unknown #1"},{"t":5,"n":"Unknown #2"}]},{"t":6,"n":"DATA - Position\/Rotation","c":[{"t":6,"n":"Position","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]},{"t":6,"n":"Rotation","c":[{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"SCEN - Scene","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":6,"p":1,"n":"Scene VMAD","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]},{"t":6,"p":1,"n":"Script Fragments Scene","c":[{"t":3,"p":1,"n":"Unknown"},{"t":3,"p":1,"n":"Scene Fragments Flags"},{"t":2,"p":1,"n":"fileName"},{"t":7,"p":1,"n":"Scene Fragments","c":[{"t":6,"p":1,"n":"Scene Fragment #0","c":[{"t":3,"p":1,"n":"Unknown"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]},{"t":7,"p":1,"n":"Phase Fragments","c":[{"t":6,"p":1,"n":"Phase Fragment #0","c":[{"t":3,"p":1,"n":"Phase Flag"},{"t":3,"p":1,"n":"Phase Index"},{"t":3,"p":1,"n":"Unknown"},{"t":3,"p":1,"n":"Unknown"},{"t":3,"p":1,"n":"Unknown"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]}]}]}]}]},{"t":3,"n":"FNAM - Flags"},{"t":8,"n":"Phases","c":[{"t":6,"n":"Phase","c":[{"n":"HNAM - Marker Phase Start"}]}]},{"t":8,"n":"Actors","c":[{"t":6,"n":"Actor","c":[{"t":3,"n":"ALID - Actor ID"}]}]},{"t":8,"n":"Actions","c":[{"t":6,"n":"Action","c":[{"t":3,"n":"ANAM - Type"}]}]},{"t":6,"n":"Unused","c":[{"t":11,"n":"SCHR - Unknown"}]},{"n":"NEXT - Marker"},{"t":6,"n":"Unused","c":[{"t":11,"n":"SCHR - Unknown"}]},{"t":3,"n":"PNAM - Quest"},{"t":3,"n":"INAM - Last Action Index"},{"t":11,"n":"VNAM - Unknown"},{"t":8,"n":"Conditions","c":[{"t":6,"n":"Condition","c":[{"t":6,"n":"CTDA - ","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":12,"n":"Comparison Value"},{"t":3,"n":"Function"},{"t":11,"n":"Unused"},{"t":12,"n":"Parameter #1"},{"t":12,"n":"Parameter #2"},{"t":3,"n":"Run On"},{"t":12,"n":"Reference"},{"t":3,"n":"Parameter #3"}]}]}]}]},{"t":1,"p":1,"n":"TREE - Tree","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":3,"n":"PFIG - Ingredient"},{"t":3,"n":"SNAM - Harvest Sound"},{"t":6,"n":"PFPC - Ingredient Production","c":[{"t":3,"n":"Spring"},{"t":3,"n":"Summer"},{"t":3,"n":"Fall"},{"t":3,"n":"Winter"}]},{"t":2,"n":"FULL - Name"},{"t":6,"n":"CNAM - Tree Data","c":[{"t":5,"n":"Trunk Flexibility"},{"t":5,"n":"Branch Flexibility"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Leaf Amplitude"},{"t":5,"n":"Leaf Frequency"}]}]},{"t":1,"p":1,"n":"WEAP - Weapon","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":12,"p":1,"n":"Data","c":[{"t":9,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":9,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":12,"p":1,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"}]},{"t":3,"n":"EITM - Object Effect"},{"t":3,"n":"EAMT - Enchantment Amount"},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"ETYP - Equipment Type"},{"t":3,"n":"BIDS - Block Bash Impact Data Set"},{"t":3,"n":"BAMT - Alternate Block Material"},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":2,"n":"DESC - Description"},{"t":6,"n":"Has Scope","c":[{"t":2,"n":"MOD3 - Model Filename"}]},{"t":11,"n":"NNAM - Unused"},{"t":3,"n":"INAM - Impact Data Set"},{"t":3,"n":"WNAM - 1st Person Model Object"},{"t":3,"n":"SNAM - Attack Sound"},{"t":3,"n":"XNAM - Attack Sound 2D"},{"t":3,"n":"NAM7 - Attack Loop Sound"},{"t":3,"n":"TNAM - Attack Fail Sound"},{"t":3,"n":"UNAM - Idle Sound"},{"t":3,"n":"NAM9 - Equip Sound"},{"t":3,"n":"NAM8 - Unequip Sound"},{"t":6,"n":"DATA - Game Data","c":[{"t":3,"n":"Value"},{"t":5,"n":"Weight"},{"t":3,"n":"Damage"}]},{"t":6,"n":"DNAM - Data","c":[{"t":3,"n":"Animation Type"},{"t":11,"n":"Unused"},{"t":5,"n":"Speed"},{"t":5,"n":"Reach"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"},{"t":5,"n":"Sight FOV"},{"t":11,"n":"Unknown"},{"t":3,"n":"Base VATS To-Hit Chance"},{"t":3,"n":"Attack Animation"},{"t":3,"n":"# Projectiles"},{"t":3,"n":"Embedded Weapon AV (unused)"},{"t":5,"n":"Range Min"},{"t":5,"n":"Range Max"},{"t":3,"n":"On Hit"},{"t":3,"n":"Flags2"},{"t":5,"n":"Animation Attack Mult"},{"t":5,"n":"Unknown"},{"t":5,"n":"Rumble - Left Motor Strength"},{"t":5,"n":"Rumble - Right Motor Strength"},{"t":5,"n":"Rumble - Duration"},{"t":11,"n":"Unknown"},{"t":3,"n":"Skill"},{"t":11,"n":"Unknown"},{"t":3,"n":"Resist"},{"t":11,"n":"Unknown"},{"t":5,"n":"Stagger"}]},{"t":6,"n":"CRDT - Critical Data","c":[{"t":3,"n":"Damage"},{"t":11,"n":"Unused"},{"t":5,"n":"% Mult"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"},{"t":3,"n":"Effect"}]},{"t":3,"n":"VNAM - Detection Sound Level"},{"t":3,"n":"CNAM - Template"}]}]},"name":"Bash.Scripts","hash":"$C2588973","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.Sound.json ================================================ {"records":"ARMA,ARMO,ASPC,EXPL,IPCT,MGEF,MISC,MSTT,RACE,REVB,SLGM,SNCT,SNDR,SOPM,SOUN,WEAP,WTHR,ACTI","description":"Sound tag from Wrye Bash.\r\n\r\nUsed when the mod replaces sounds.\r\n\r\nNote: I tried my best to get all appropriate records and subrecords for Skyrim in the spirit of this Bash Tag, but I may have missed things. Please let me know if I did. -Mator","tree":{"records":[{"t":1,"p":1,"n":"ARMA - Armor Addon","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"BOD2 - Biped Body Template","c":[{"t":3,"n":"First Person Flags"},{"t":3,"n":"General Flags"},{"n":"Unused"},{"t":3,"n":"Armor Type"}]},{"t":3,"n":"RNAM - Race"},{"t":6,"n":"DNAM - Data","c":[{"t":3,"n":"Male Priority"},{"t":3,"n":"Female Priority"},{"t":3,"n":"Weight slider - Male"},{"t":3,"n":"Weight slider - Female"},{"t":11,"n":"Unknown"},{"t":3,"n":"Detection Sound Value"},{"t":11,"n":"Unknown"},{"t":5,"n":"Weapon Adjust"}]},{"t":6,"n":"Male world model","c":[{"t":2,"n":"MOD2 - Model Filename"}]},{"t":6,"n":"Female world model","c":[{"t":2,"n":"MOD3 - Model Filename"}]},{"t":6,"n":"Male 1st Person","c":[{"t":2,"n":"MOD4 - Model Filename"}]},{"t":6,"n":"Female 1st Person","c":[{"t":2,"n":"MOD5 - Model Filename"}]},{"t":3,"n":"NAM0 - Male Skin Texture"},{"t":3,"n":"NAM1 - Female Skin texture"},{"t":3,"n":"NAM2 - Male Skin Texture Swap List"},{"t":3,"n":"NAM3 - Female Skin Texture Swap List"},{"t":9,"n":"Additional Races","c":[{"t":3,"n":"MODL - Race"}]},{"t":3,"p":1,"n":"SNDD - Footstep Sound"},{"t":3,"n":"ONAM - Art Object"}]},{"t":1,"p":1,"n":"ARMO - Armor","c":[{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":7,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":7,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"n":"Alias"},{"t":3,"n":"FormID"}]},{"t":6,"n":"Object v1","c":[{"t":3,"n":"FormID"},{"t":3,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"n":"String"},{"t":3,"n":"Int32"},{"t":5,"n":"Float"},{"t":3,"n":"Bool"},{"t":7,"n":"Array of Object","c":[{"t":6,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"n":"Alias"},{"t":3,"n":"FormID"}]},{"t":6,"n":"Object v1","c":[{"t":3,"n":"FormID"},{"t":3,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"n":"Array of String","c":[{"t":2,"n":"Element"}]},{"t":7,"n":"Array of Int32","c":[{"t":3,"n":"Element"}]},{"t":7,"n":"Array of Float","c":[{"t":5,"n":"Element"}]},{"t":7,"n":"Array of Bool","c":[{"t":3,"n":"Element"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":3,"n":"EITM - Object Effect"},{"t":3,"n":"EAMT - Enchantment Amount"},{"t":6,"n":"Male world model","c":[{"t":2,"n":"MOD2 - Model Filename"},{"t":11,"n":"MO2T - Texture Files Hashes"},{"t":7,"n":"MO2S - Alternate Textures","c":[{"t":6,"n":"Alternate Texture","c":[{"t":2,"n":"3D Name"},{"t":3,"n":"New Texture"},{"t":3,"n":"3D Index"}]}]}]},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"},{"t":2,"n":"MICO - Small Icon filename"}]},{"t":6,"n":"Female world model","c":[{"t":2,"n":"MOD4 - Model Filename"},{"t":11,"n":"MO4T - Texture Files Hashes"},{"t":7,"n":"MO4S - Alternate Textures","c":[{"t":6,"n":"Alternate Texture","c":[{"t":2,"n":"3D Name"},{"t":3,"n":"New Texture"},{"t":3,"n":"3D Index"}]}]}]},{"t":6,"n":"Icon 2 (female)","c":[{"t":2,"n":"ICO2 - Large Icon filename"},{"t":2,"n":"MIC2 - Small Icon filename"}]},{"t":6,"n":"BOD2 - Biped Body Template","c":[{"t":3,"n":"First Person Flags"},{"t":3,"n":"General Flags"},{"n":"Unused"},{"t":3,"n":"Armor Type"}]},{"t":6,"n":"BODT - Body Template","c":[{"t":3,"n":"First Person Flags"},{"t":3,"n":"General Flags"},{"t":11,"n":"Unused"},{"t":3,"n":"Armor Type"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"n":"Stages","c":[{"t":6,"n":"Stage","c":[{"t":6,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"n":"Health %"},{"t":3,"n":"Index"},{"t":3,"n":"Model Damage Stage"},{"t":3,"n":"Flags"},{"t":3,"n":"Self Damage per Second"},{"t":3,"n":"Explosion"},{"t":3,"n":"Debris"},{"t":3,"n":"Debris Count"}]},{"t":6,"n":"Model","c":[{"t":2,"n":"DMDL - Model Filename"},{"t":11,"n":"DMDT - Texture Files Hashes"},{"t":7,"n":"DMDS - Alternate Textures","c":[{"t":6,"n":"Alternate Texture","c":[{"t":2,"n":"3D Name"},{"t":3,"n":"New Texture"},{"t":3,"n":"3D Index"}]}]}]},{"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":2,"n":"BMCT - Ragdoll Constraint Template"},{"t":3,"n":"ETYP - Equipment Type"},{"t":3,"n":"BIDS - Bash Impact Data Set"},{"t":3,"n":"BAMT - Alternate Block Material"},{"t":3,"n":"RNAM - Race"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":2,"n":"DESC - Description"},{"t":8,"n":"Armature","c":[{"t":3,"n":"MODL - Model Filename"}]},{"t":6,"n":"DATA - Data","c":[{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]},{"t":3,"n":"DNAM - Armor Rating"},{"t":3,"n":"TNAM - Template Armor"}]},{"t":1,"p":1,"n":"ASPC - Acoustic Space","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}],"lt":"BNAM - Environment Type (reverb)","lf":"SNAM - Ambient Sound"},{"t":3,"p":1,"n":"SNAM - Ambient Sound","lt":"OBND - Object Bounds","lf":"RDAT - Use Sound from Region (Interiors Only)"},{"t":3,"p":1,"n":"RDAT - Use Sound from Region (Interiors Only)","lt":"SNAM - Ambient Sound","lf":"BNAM - Environment Type (reverb)"},{"t":3,"p":1,"n":"BNAM - Environment Type (reverb)","lt":"RDAT - Use Sound from Region (Interiors Only)","lf":"OBND - Object Bounds"}]},{"t":1,"p":1,"n":"EXPL - Explosion","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":3,"n":"EITM - Object Effect"},{"t":3,"n":"MNAM - Image Space Modifier"},{"t":6,"p":1,"n":"DATA - Data","c":[{"t":3,"n":"Light"},{"t":3,"p":1,"n":"Sound 1","lt":"Sound 2","lf":"Sound Level"},{"t":3,"p":1,"n":"Sound 2","lt":"Sound Level","lf":"Sound 1"},{"t":3,"n":"Impact Data Set"},{"t":3,"n":"Placed Object"},{"t":3,"n":"Spawn Projectile"},{"t":5,"n":"Force"},{"t":5,"n":"Damage"},{"t":5,"n":"Radius"},{"t":5,"n":"IS Radius"},{"t":5,"n":"Vertical Offset Mult"},{"t":3,"n":"Flags"},{"t":3,"p":1,"n":"Sound Level","lt":"Sound 1","lf":"Sound 2"}]}]},{"t":1,"p":1,"n":"IPCT - Impact","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"DATA - ","c":[{"t":5,"n":"Effect - Duration"},{"t":3,"n":"Effect - Orientation"},{"t":5,"n":"Angle Threshold"},{"t":5,"n":"Placement Radius"},{"t":3,"n":"Sound Level"},{"t":3,"n":"Flags"},{"t":3,"n":"Impact Result"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"DODT - Decal Data","c":[{"t":5,"n":"Min Width"},{"t":5,"n":"Max Width"},{"t":5,"n":"Min Height"},{"t":5,"n":"Max Height"},{"t":5,"n":"Depth"},{"t":5,"n":"Shininess"},{"t":6,"n":"Parallax","c":[{"t":5,"n":"Scale"},{"t":3,"n":"Passes"}]},{"t":3,"n":"Flags"},{"t":11,"n":"Unknown"},{"t":6,"n":"Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"DNAM - Texture Set"},{"t":3,"n":"ENAM - Secondary Texture Set"},{"t":3,"p":1,"n":"SNAM - Sound 1","lt":"NAM1 - Sound 2","lf":"NAM1 - Sound 2"},{"t":3,"p":1,"n":"NAM1 - Sound 2","lt":"SNAM - Sound 1","lf":"SNAM - Sound 1"},{"t":3,"n":"NAM2 - Hazard"}]},{"t":1,"p":1,"n":"MGEF - Magic Effect","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":2,"n":"FULL - Name"},{"t":3,"n":"MDOB - Menu Display Object"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"Magic Effect Data","c":[{"t":6,"n":"DATA - Data","c":[{"t":3,"n":"Flags"},{"t":5,"n":"Base Cost"},{"t":12,"n":"Assoc. Item"},{"t":3,"n":"Magic Skill"},{"t":3,"n":"Resist Value"},{"t":3,"n":"Counter Effect count"},{"t":11,"n":"Unused"},{"t":3,"n":"Casting Light"},{"t":5,"n":"Taper Weight"},{"t":3,"n":"Hit Shader"},{"t":3,"n":"Enchant Shader"},{"t":3,"n":"Minimum Skill Level"},{"t":6,"n":"Spellmaking","c":[{"t":3,"n":"Area"},{"t":5,"n":"Casting Time"}]},{"t":5,"n":"Taper Curve"},{"t":5,"n":"Taper Duration"},{"t":5,"n":"Second AV Weight"},{"t":3,"n":"Archtype"},{"t":3,"n":"Actor Value"},{"t":3,"n":"Projectile"},{"t":3,"n":"Explosion"},{"t":3,"n":"Casting Type"},{"t":3,"n":"Delivery"},{"t":3,"n":"Second Actor Value"},{"t":3,"n":"Casting Art"},{"t":3,"n":"Hit Effect Art"},{"t":3,"n":"Impact Data"},{"t":5,"n":"Skill Usage Multiplier"},{"t":6,"n":"Dual Casting","c":[{"t":3,"n":"Art"},{"t":5,"n":"Scale"}]},{"t":3,"n":"Enchant Art"},{"t":11,"n":"Unknown"},{"t":11,"n":"Unknown"},{"t":3,"n":"Equip Ability"},{"t":3,"n":"Image Space Modifier"},{"t":3,"n":"Perk to Apply"},{"t":3,"n":"Casting Sound Level"},{"t":6,"n":"Script Effect AI","c":[{"t":5,"n":"Score"},{"t":5,"n":"Delay Time"}]}]}]},{"t":9,"n":"Counter Effects","c":[{"t":3,"n":"ESCE - Effect"}]},{"t":8,"s":1,"p":1,"n":"SNDD - Sounds","c":[{"t":6,"p":1,"n":" #0","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Sound"}]}]},{"t":2,"n":"DNAM - Magic Item Description"},{"t":8,"n":"Conditions","c":[{"t":6,"n":"Condition","c":[{"t":6,"n":"CTDA - ","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":12,"n":"Comparison Value"},{"t":3,"n":"Function"},{"t":11,"n":"Unused"},{"t":12,"n":"Parameter #1"},{"t":12,"n":"Parameter #2"},{"t":3,"n":"Run On"},{"t":12,"n":"Reference"},{"t":3,"n":"Parameter #3"}]}]}]}]},{"t":1,"p":1,"n":"MISC - Misc. Item","c":[{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":7,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":7,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"n":"Alias"},{"t":3,"n":"FormID"}]},{"t":6,"n":"Object v1","c":[{"t":3,"n":"FormID"},{"t":3,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"n":"String"},{"t":3,"n":"Int32"},{"t":5,"n":"Float"},{"t":3,"n":"Bool"},{"t":7,"n":"Array of Object","c":[{"t":6,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"n":"Alias"},{"t":3,"n":"FormID"}]},{"t":6,"n":"Object v1","c":[{"t":3,"n":"FormID"},{"t":3,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"n":"Array of String","c":[{"t":2,"n":"Element"}]},{"t":7,"n":"Array of Int32","c":[{"t":3,"n":"Element"}]},{"t":7,"n":"Array of Float","c":[{"t":5,"n":"Element"}]},{"t":7,"n":"Array of Bool","c":[{"t":3,"n":"Element"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":11,"n":"MODT - Texture Files Hashes"},{"t":7,"n":"MODS - Alternate Textures","c":[{"t":6,"n":"Alternate Texture","c":[{"t":2,"n":"3D Name"},{"t":3,"n":"New Texture"},{"t":3,"n":"3D Index"}]}]}]},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"},{"t":2,"n":"MICO - Small Icon filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"n":"Stages","c":[{"t":6,"n":"Stage","c":[{"t":6,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"n":"Health %"},{"t":3,"n":"Index"},{"t":3,"n":"Model Damage Stage"},{"t":3,"n":"Flags"},{"t":3,"n":"Self Damage per Second"},{"t":3,"n":"Explosion"},{"t":3,"n":"Debris"},{"t":3,"n":"Debris Count"}]},{"t":6,"n":"Model","c":[{"t":2,"n":"DMDL - Model Filename"},{"t":11,"n":"DMDT - Texture Files Hashes"},{"t":7,"n":"DMDS - Alternate Textures","c":[{"t":6,"n":"Alternate Texture","c":[{"t":2,"n":"3D Name"},{"t":3,"n":"New Texture"},{"t":3,"n":"3D Index"}]}]}]},{"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"DATA - Data","c":[{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]}]},{"t":1,"p":1,"n":"MSTT - Moveable Static","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"DATA - Flags"},{"t":3,"p":1,"n":"SNAM - Looping Sound"}]},{"t":1,"p":1,"n":"RACE - Race","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":3,"n":"SPCT - Count"},{"t":9,"n":"Actor Effects","c":[{"t":3,"n":"SPLO - Actor Effect"}]},{"t":3,"n":"WNAM - Skin"},{"t":6,"n":"BOD2 - Biped Body Template","c":[{"t":3,"n":"First Person Flags"},{"t":3,"n":"General Flags"},{"n":"Unused"},{"t":3,"n":"Armor Type"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"DATA - ","c":[{"t":10,"n":"Skill Boosts","c":[{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]}]},{"t":11,"n":"Unknown"},{"t":5,"n":"Male Height"},{"t":5,"n":"Female Height"},{"t":5,"n":"Male Weight"},{"t":5,"n":"Female Weight"},{"t":3,"n":"Flags"},{"t":5,"n":"Starting Health"},{"t":5,"n":"Starting Magicka"},{"t":5,"n":"Starting Stamina"},{"t":5,"n":"Base Carry Weight"},{"t":5,"n":"Base Mass"},{"t":5,"n":"Acceleration rate"},{"t":5,"n":"Deceleration rate"},{"t":3,"n":"Size"},{"t":3,"n":"Head Biped Object"},{"t":3,"n":"Hair Biped Object"},{"t":5,"n":"Injured Health Pct"},{"t":3,"n":"Shield Biped Object"},{"t":5,"n":"Health Regen"},{"t":5,"n":"Magicka Regen"},{"t":5,"n":"Stamina Regen"},{"t":5,"n":"Unarmed Damage"},{"t":5,"n":"Unarmed Reach"},{"t":3,"n":"Body Biped Object"},{"t":5,"n":"Aim Angle Tolerance"},{"t":5,"n":"Flight Radius"},{"t":5,"n":"Angular Acceleration Rate"},{"t":5,"n":"Angular Tolerance"},{"t":3,"n":"Flags 2"},{"t":6,"n":"Mount Data","c":[{"t":5,"n":"Offset X"},{"t":5,"n":"Offset Y"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"}]}]},{"n":"MNAM - Male Marker"},{"t":2,"n":"ANAM - Male Skeletal Model"},{"t":11,"n":"MODT - Texture Files Hashes"},{"n":"FNAM - Female Marker"},{"t":2,"n":"ANAM - Female Skeletal Model"},{"t":11,"n":"MODT - Texture Files Hashes"},{"n":"NAM2 - Marker NAM2 #1"},{"t":9,"n":"Movement Type Names","c":[{"t":2,"n":"MTNM - Name"}]},{"t":7,"n":"VTCK - Voices","c":[{"t":3,"n":"Voice #0 (Male)"},{"t":3,"n":"Voice #1 (Female)"}]},{"t":7,"n":"DNAM - Decapitate Armors","c":[{"t":3,"n":"Decapitate Armor #0 (Male)"},{"t":3,"n":"Decapitate Armor #1 (Female)"}]},{"t":7,"n":"HCLF - Default Hair Colors","c":[{"t":3,"n":"Default Hair Color #0 (Male)"},{"t":3,"n":"Default Hair Color #1 (Female)"}]},{"t":3,"n":"TINL - Total Number of Tints in List"},{"t":5,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"n":"UNAM - FaceGen - Face clamp"},{"t":3,"n":"ATKR - Attack Race"},{"t":10,"n":"Attacks","c":[{"t":6,"n":"Attack","c":[{"t":6,"n":"ATKD - Attack Data","c":[{"t":5,"n":"Damage Mult"},{"t":5,"n":"Attack Chance"},{"t":3,"n":"Attack Spell"},{"t":3,"n":"Attack Flags"},{"t":5,"n":"Attack Angle"},{"t":5,"n":"Strike Angle"},{"t":5,"n":"Stagger"},{"t":3,"n":"Attack Type"},{"t":5,"n":"Knockdown"},{"t":5,"n":"Recovery Time"},{"t":5,"n":"Stamina Mult"}]}]}]},{"t":6,"n":"Body Data","c":[{"n":"NAM1 - Body Data Marker"},{"t":6,"n":"Male Body Data","c":[{"n":"MNAM - Male Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"}]}]}]},{"t":6,"n":"Female Body Data","c":[{"n":"FNAM - Female Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"}]}]}]}]},{"t":9,"n":"HNAM - Hairs","c":[{"t":3,"n":"Hair"}]},{"t":9,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eye"}]},{"t":3,"n":"GNAM - Body Part Data"},{"n":"NAM2 - Marker NAM2 #2"},{"n":"NAM3 - Marker NAM3 #3"},{"t":6,"n":"Male Behavior Graph","c":[{"n":"MNAM - Male Data Marker"}]},{"t":6,"n":"Female Behavior Graph","c":[{"n":"FNAM - Female Data Marker"}]},{"t":3,"n":"NAM4 - Material Type"},{"t":3,"n":"NAM5 - Impact Data Set"},{"t":3,"n":"NAM7 - Decapitation FX"},{"t":3,"p":1,"n":"ONAM - Open Loot Sound"},{"t":3,"p":1,"n":"LNAM - Close Loot Sound"},{"t":7,"n":"Biped Object Names","c":[{"t":2,"n":"NAME - Name"}]},{"t":10,"n":"Movement Types","c":[{"t":6,"n":"Movement Types","c":[{"t":3,"n":"MTYP - Movement Type"}]}]},{"t":3,"n":"VNAM - Equipment Flags"},{"t":9,"n":"Equip Slots","c":[{"t":3,"n":"QNAM - Equip Slot"}]},{"t":3,"n":"UNES - Unarmed Equip Slot"},{"t":7,"n":"Phoneme Target Names","c":[{"t":2,"n":"PHTN - Name"}]},{"t":6,"n":"FaceFX Phonemes","c":[{"t":6,"n":"IY","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]}]},{"t":3,"n":"WKMV - Base Movement Default - Walk"},{"t":3,"n":"RNMV - Base Movement Default - Run"},{"t":3,"n":"SWMV - Base Movement Default - Swim"},{"t":3,"n":"FLMV - Base Movement Default - Fly"},{"t":3,"n":"SNMV - Base Movement Default - Sneak"},{"t":3,"n":"SPMV - Base Movement Default - Sprint"},{"t":6,"n":"Head Data","c":[{"n":"NAM0 - Head Data Marker"},{"t":6,"n":"Male Head Data","c":[{"n":"MNAM - Male Data Marker"}]},{"t":6,"n":"Female Head Data","c":[{"n":"NAM0 - Head Data Marker"},{"n":"FNAM - Female Data Marker"}]}]},{"t":3,"n":"NAM8 - Morph race"},{"t":3,"n":"RNAM - Armor race"}]},{"t":1,"p":1,"n":"REVB - Reverb Parameters","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Decay Time (ms)"},{"t":3,"p":1,"n":"HF Reference (Hz)"},{"t":3,"p":1,"n":"Room Filter"},{"t":3,"p":1,"n":"Room HF Filter"},{"t":3,"p":1,"n":"Reflections"},{"t":3,"p":1,"n":"Reverb Amp"},{"t":3,"p":1,"n":"Decay HF Ratio"},{"t":3,"p":1,"n":"Reflect Delay (ms), scaled"},{"t":3,"p":1,"n":"Reverb Delay (ms)"},{"t":3,"p":1,"n":"Diffusion %"},{"t":3,"p":1,"n":"Density %"},{"t":3,"p":1,"n":"Unknown"}]}]},{"t":1,"p":1,"n":"SLGM - Soul Gem","c":[{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"},{"t":11,"n":"MODT - Texture Files Hashes"},{"t":7,"n":"MODS - Alternate Textures","c":[{"t":6,"n":"Alternate Texture","c":[{"t":2,"n":"3D Name"},{"t":3,"n":"New Texture"},{"t":3,"n":"3D Index"}]}]}]},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"},{"t":2,"n":"MICO - Small Icon filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"n":"Stages","c":[{"t":6,"n":"Stage","c":[{"t":6,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"n":"Health %"},{"t":3,"n":"Index"},{"t":3,"n":"Model Damage Stage"},{"t":3,"n":"Flags"},{"t":3,"n":"Self Damage per Second"},{"t":3,"n":"Explosion"},{"t":3,"n":"Debris"},{"t":3,"n":"Debris Count"}]},{"t":6,"n":"Model","c":[{"t":2,"n":"DMDL - Model Filename"},{"t":11,"n":"DMDT - Texture Files Hashes"},{"t":7,"n":"DMDS - Alternate Textures","c":[{"t":6,"n":"Alternate Texture","c":[{"t":2,"n":"3D Name"},{"t":3,"n":"New Texture"},{"t":3,"n":"3D Index"}]}]}]},{"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"DATA - ","c":[{"t":3,"n":"Value"},{"t":5,"n":"Weight"}]},{"t":3,"n":"SOUL - Contained Soul"},{"t":3,"n":"SLCP - Maximum Capacity"},{"t":3,"n":"NAM0 - Linked To"}]},{"t":1,"p":1,"n":"SNCT - Sound Category","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":3,"p":1,"n":"FNAM - Flags","lt":"UNAM - Default Menu Value","lf":"PNAM - Parent"},{"t":3,"p":1,"n":"PNAM - Parent","lt":"FNAM - Flags","lf":"VNAM - Static Volume Multiplier"},{"t":3,"p":1,"n":"VNAM - Static Volume Multiplier","lt":"PNAM - Parent","lf":"UNAM - Default Menu Value"},{"t":3,"p":1,"n":"UNAM - Default Menu Value","lt":"VNAM - Static Volume Multiplier","lf":"FNAM - Flags"}]},{"t":1,"p":1,"n":"SNDR - Sound Descriptor","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":11,"n":"CNAM - Unknown"},{"t":3,"p":1,"n":"GNAM - Category","lt":"BNAM - Values","lf":"SNAM - Alternate Sound For"},{"t":3,"p":1,"n":"SNAM - Alternate Sound For","lt":"GNAM - Category","lf":"Sounds"},{"t":8,"s":1,"p":1,"n":"Sounds","c":[{"t":6,"p":1,"n":"Sound Files","c":[{"t":2,"p":1,"n":"ANAM - File Name"}]}],"lt":"SNAM - Alternate Sound For","lf":"ONAM - Output Model"},{"t":3,"p":1,"n":"ONAM - Output Model","lt":"Sounds","lf":"FNAM - String"},{"t":2,"p":1,"n":"FNAM - String","lt":"ONAM - Output Model","lf":"Conditions"},{"t":8,"s":1,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"p":1,"n":"Unused"},{"t":12,"p":1,"n":"Comparison Value"},{"t":3,"p":1,"n":"Function"},{"t":11,"p":1,"n":"Unused"},{"t":12,"p":1,"n":"Parameter #1"},{"t":12,"p":1,"n":"Parameter #2"},{"t":3,"p":1,"n":"Run On"},{"t":12,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]}]}],"lt":"FNAM - String","lf":"LNAM - Values"},{"t":6,"s":1,"p":1,"n":"LNAM - Values","c":[{"t":11,"p":1,"n":"Unknown"},{"t":3,"p":1,"n":"Looping"},{"t":11,"p":1,"n":"Unknown"},{"t":3,"p":1,"n":"Rumble Send Value = (Small \/ 7) + ((Big \/ 7) * 16)"}],"lt":"Conditions","lf":"BNAM - Values"},{"t":6,"s":1,"p":1,"n":"BNAM - Values","c":[{"t":3,"p":1,"n":"% Frequency Shift"},{"t":3,"p":1,"n":"% Frequency Variance"},{"t":3,"p":1,"n":"Priority"},{"t":3,"p":1,"n":"db Variance"},{"t":3,"p":1,"n":"Static Attenuation (db)"}],"lt":"LNAM - Values","lf":"GNAM - Category"}]},{"t":1,"p":1,"n":"SOPM - Sound Output Model","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"NAM1 - Data","c":[{"t":3,"p":1,"n":"Flags"},{"t":11,"p":1,"n":"Unknown"},{"t":3,"p":1,"n":"Reverb Send %"}],"lt":"ANAM - Attenuation Values","lf":"MNAM - Type"},{"t":11,"n":"FNAM - Unknown"},{"t":3,"p":1,"n":"MNAM - Type","lt":"NAM1 - Data","lf":"ONAM - Output Values"},{"t":11,"n":"CNAM - Unknown"},{"t":11,"n":"SNAM - Unknown"},{"t":6,"s":1,"p":1,"n":"ONAM - Output Values","c":[{"t":8,"p":1,"n":"Channels","c":[{"t":6,"p":1,"n":" #0 (Channel 0)","c":[{"t":3,"p":1,"n":"L"},{"t":3,"p":1,"n":"R"},{"t":3,"p":1,"n":"C"},{"t":3,"p":1,"n":"LFE"},{"t":3,"p":1,"n":"RL"},{"t":3,"p":1,"n":"RR"},{"t":3,"p":1,"n":"BL"},{"t":3,"p":1,"n":"BR"}]},{"t":6,"p":1,"n":" #1 (Channel 1)","c":[{"t":3,"p":1,"n":"L"},{"t":3,"p":1,"n":"R"},{"t":3,"p":1,"n":"C"},{"t":3,"p":1,"n":"LFE"},{"t":3,"p":1,"n":"RL"},{"t":3,"p":1,"n":"RR"},{"t":3,"p":1,"n":"BL"},{"t":3,"p":1,"n":"BR"}]},{"t":6,"p":1,"n":" #2 (Channel 2? (unused))","c":[{"t":3,"p":1,"n":"L"},{"t":3,"p":1,"n":"R"},{"t":3,"p":1,"n":"C"},{"t":3,"p":1,"n":"LFE"},{"t":3,"p":1,"n":"RL"},{"t":3,"p":1,"n":"RR"},{"t":3,"p":1,"n":"BL"},{"t":3,"p":1,"n":"BR"}]}]}],"lt":"MNAM - Type","lf":"ANAM - Attenuation Values"},{"t":6,"s":1,"p":1,"n":"ANAM - Attenuation Values","c":[{"t":11,"p":1,"n":"Unknown"},{"t":5,"p":1,"n":"Min Distance"},{"t":5,"p":1,"n":"Max Distance"},{"t":7,"p":1,"n":"Curve","c":[{"t":3,"p":1,"n":"Value #0"},{"t":3,"p":1,"n":"Value #1"},{"t":3,"p":1,"n":"Value #2"},{"t":3,"p":1,"n":"Value #3"},{"t":3,"p":1,"n":"Value #4"}]},{"t":11,"p":1,"n":"Unknown"}],"lt":"ONAM - Output Values","lf":"NAM1 - Data"}]},{"t":1,"p":1,"n":"SOUN - Sound Marker","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":11,"n":"FNAM - Unknown"},{"t":11,"n":"SNDD - Unknown"},{"t":3,"p":1,"n":"SDSC - Sound Descriptor"}]},{"t":1,"p":1,"n":"WEAP - Weapon","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"}]},{"t":3,"n":"EITM - Object Effect"},{"t":3,"n":"EAMT - Enchantment Amount"},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"ETYP - Equipment Type"},{"t":3,"p":1,"n":"BIDS - Block Bash Impact Data Set"},{"t":3,"n":"BAMT - Alternate Block Material"},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Drop"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":2,"n":"DESC - Description"},{"t":6,"n":"Has Scope","c":[{"t":2,"n":"MOD3 - Model Filename"}]},{"t":11,"n":"NNAM - Unused"},{"t":3,"p":1,"n":"INAM - Impact Data Set"},{"t":3,"n":"WNAM - 1st Person Model Object"},{"t":3,"p":1,"n":"SNAM - Attack Sound"},{"t":3,"p":1,"n":"XNAM - Attack Sound 2D"},{"t":3,"p":1,"n":"NAM7 - Attack Loop Sound"},{"t":3,"p":1,"n":"TNAM - Attack Fail Sound"},{"t":3,"p":1,"n":"UNAM - Idle Sound"},{"t":3,"p":1,"n":"NAM9 - Equip Sound"},{"t":3,"p":1,"n":"NAM8 - Unequip Sound"},{"t":6,"n":"DATA - Game Data","c":[{"t":3,"n":"Value"},{"t":5,"n":"Weight"},{"t":3,"n":"Damage"}]},{"t":6,"n":"DNAM - Data","c":[{"t":3,"n":"Animation Type"},{"t":11,"n":"Unused"},{"t":5,"n":"Speed"},{"t":5,"n":"Reach"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"},{"t":5,"n":"Sight FOV"},{"t":11,"n":"Unknown"},{"t":3,"n":"Base VATS To-Hit Chance"},{"t":3,"n":"Attack Animation"},{"t":3,"n":"# Projectiles"},{"t":3,"n":"Embedded Weapon AV (unused)"},{"t":5,"n":"Range Min"},{"t":5,"n":"Range Max"},{"t":3,"n":"On Hit"},{"t":3,"n":"Flags2"},{"t":5,"n":"Animation Attack Mult"},{"t":5,"n":"Unknown"},{"t":5,"n":"Rumble - Left Motor Strength"},{"t":5,"n":"Rumble - Right Motor Strength"},{"t":5,"n":"Rumble - Duration"},{"t":11,"n":"Unknown"},{"t":3,"n":"Skill"},{"t":11,"n":"Unknown"},{"t":3,"n":"Resist"},{"t":11,"n":"Unknown"},{"t":5,"n":"Stagger"}]},{"t":6,"n":"CRDT - Critical Data","c":[{"t":3,"n":"Damage"},{"t":11,"n":"Unused"},{"t":5,"n":"% Mult"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"},{"t":3,"n":"Effect"}]},{"t":3,"n":"VNAM - Detection Sound Level"},{"t":3,"n":"CNAM - Template"}]},{"t":1,"p":1,"n":"WTHR - Weather","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"00TX - Cloud Texture Layer #0"},{"t":2,"n":"10TX - Cloud Texture Layer #1"},{"t":2,"n":"20TX - Cloud Texture Layer #2"},{"t":2,"n":"30TX - Cloud Texture Layer #3"},{"t":2,"n":"40TX - Cloud Texture Layer #4"},{"t":2,"n":"50TX - Cloud Texture Layer #5"},{"t":2,"n":"60TX - Cloud Texture Layer #6"},{"t":2,"n":"70TX - Cloud Texture Layer #7"},{"t":2,"n":"80TX - Cloud Texture Layer #8"},{"t":2,"n":"90TX - Cloud Texture Layer #9"},{"t":2,"n":":0TX - Cloud Texture Layer #10"},{"t":2,"n":";0TX - Cloud Texture Layer #11"},{"t":2,"n":"<0TX - Cloud Texture Layer #12"},{"t":2,"n":"=0TX - Cloud Texture Layer #13"},{"t":2,"n":">0TX - Cloud Texture Layer #14"},{"t":2,"n":"?0TX - Cloud Texture Layer #15"},{"t":2,"n":"@0TX - Cloud Texture Layer #16"},{"t":2,"n":"A0TX - Cloud Texture Layer #17"},{"t":2,"n":"B0TX - Cloud Texture Layer #18"},{"t":2,"n":"C0TX - Cloud Texture Layer #19"},{"t":2,"n":"D0TX - Cloud Texture Layer #20"},{"t":2,"n":"E0TX - Cloud Texture Layer #21"},{"t":2,"n":"F0TX - Cloud Texture Layer #22"},{"t":2,"n":"G0TX - Cloud Texture Layer #23"},{"t":2,"n":"H0TX - Cloud Texture Layer #24"},{"t":2,"n":"I0TX - Cloud Texture Layer #25"},{"t":2,"n":"J0TX - Cloud Texture Layer #26"},{"t":2,"n":"K0TX - Cloud Texture Layer #27"},{"t":2,"n":"L0TX - Cloud Texture Layer #28"},{"t":11,"n":"DNAM - Unused"},{"t":11,"n":"CNAM - Unused"},{"t":11,"n":"ANAM - Unused"},{"t":11,"n":"BNAM - Unused"},{"t":11,"n":"LNAM - Unknown"},{"t":3,"n":"MNAM - Precipitation Type"},{"t":3,"n":"NNAM - Visual Effect"},{"t":11,"n":"ONAM - Unused"},{"t":6,"n":"Cloud Speed","c":[{"t":7,"n":"RNAM - Y Speed","c":[{"t":3,"n":"Layer #0"}]}]},{"t":8,"n":"PNAM - Cloud Colors","c":[{"t":6,"n":"Layer #0","c":[{"t":8,"n":"Colors","c":[{"t":6,"n":"Time #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Time #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Time #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Time #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]}]}]},{"t":8,"n":"JNAM - Cloud Alphas","c":[{"t":6,"n":"Layer #0","c":[{"t":5,"n":"Sunrise"},{"t":5,"n":"Day"},{"t":5,"n":"Sunset"},{"t":5,"n":"Night"}]}]},{"t":6,"n":"NAM0 - Weather Colors","c":[{"t":8,"n":"Sky-Upper","c":[{"t":6,"n":"Color #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Fog Near","c":[{"t":6,"n":"Color #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Unknown","c":[{"t":6,"n":"Color #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Ambient","c":[{"t":6,"n":"Color #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Sunlight","c":[{"t":6,"n":"Color #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Sun","c":[{"t":6,"n":"Color #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Stars","c":[{"t":6,"n":"Color #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Sky-Lower","c":[{"t":6,"n":"Color #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Horizon","c":[{"t":6,"n":"Color #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Effect Lighting","c":[{"t":6,"n":"Color #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Cloud LOD Diffuse","c":[{"t":6,"n":"Color #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Cloud LOD Ambient","c":[{"t":6,"n":"Color #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Fog Far","c":[{"t":6,"n":"Color #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Sky Statics","c":[{"t":6,"n":"Color #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Water Multiplier","c":[{"t":6,"n":"Color #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Sun Glare","c":[{"t":6,"n":"Color #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Moon Glare","c":[{"t":6,"n":"Color #0 (Sunrise)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (Day)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Sunset)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Night)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]}]},{"t":6,"n":"FNAM - Fog Distance","c":[{"t":5,"n":"Day - Near"},{"t":5,"n":"Day - Far"},{"t":5,"n":"Night - Near"},{"t":5,"n":"Night - Far"},{"t":5,"n":"Day - Power"},{"t":5,"n":"Night - Power"},{"t":5,"n":"Day - Max"},{"t":5,"n":"Night - Max"}]},{"t":6,"n":"DATA - Data","c":[{"t":3,"n":"Wind Speed"},{"t":11,"n":"Unknown"},{"t":3,"n":"Trans Delta"},{"t":3,"n":"Sun Glare"},{"t":3,"n":"Sun Damage"},{"t":3,"n":"Precipitation - Begin Fade In"},{"t":3,"n":"Precipitation - End Fade Out"},{"t":3,"n":"Thunder\/Lightning - Begin Fade In"},{"t":3,"n":"Thunder\/Lightning - End Fade Out"},{"t":3,"n":"Thunder\/Lightning - Frequency"},{"t":3,"n":"Flags"},{"t":6,"n":"Lightning Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"}]},{"t":3,"n":"Visual Effect - Begin"},{"t":3,"n":"Visual Effect - End"},{"t":3,"n":"Wind Direction"},{"t":3,"n":"Wind Direction Range"}]},{"t":3,"n":"NAM1 - Disabled Cloud Layers"},{"t":8,"s":1,"p":1,"n":"Sounds","c":[{"t":6,"p":1,"n":"SNAM - Sound","c":[{"t":3,"p":1,"n":"Sound"},{"t":3,"p":1,"n":"Type"}]}]},{"t":9,"n":"Sky Statics","c":[{"t":3,"n":"TNAM - Static"}]},{"t":6,"n":"IMSP - Image Spaces","c":[{"t":3,"n":"Sunrise"},{"t":3,"n":"Day"},{"t":3,"n":"Sunset"},{"t":3,"n":"Night"}]},{"t":8,"n":"Directional Ambient Lighting Colors","c":[{"t":6,"n":"DALC - Sunrise\/Day\/Sunset\/Night Order","c":[{"t":6,"n":"Ambient Colors","c":[{"t":8,"n":"Colors","c":[{"t":6,"n":"Color #0 (X+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #1 (X-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #2 (Y+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #3 (Y-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #4 (Z+)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"Color #5 (Z-)","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"Specular","c":[{"t":6,"n":"Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":5,"n":"Fresnel Power"}]}]}]}]},{"t":11,"n":"NAM2 - Unused"},{"t":11,"n":"NAM3 - Unused"},{"t":6,"n":"Aurora","c":[{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]}]}]},{"t":1,"p":1,"n":"ACTI - Activator","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"PNAM - Marker Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":3,"n":"Unused"}]},{"t":3,"p":1,"n":"SNAM - Sound - Looping"},{"t":3,"p":1,"n":"VNAM - Sound - Activation"},{"t":3,"n":"WNAM - Water Type"},{"t":2,"n":"RNAM - Activate Text Override"},{"t":3,"n":"FNAM - Flags"},{"t":3,"n":"KNAM - Interaction Keyword"}]}]},"name":"Bash.Sound","hash":"9FC91972","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.SpellStats.json ================================================ {"records":"SPEL","description":"SpellStats tag from Wrye Bash.\r\n\r\nUsed when the mod modifies spell stats.","tree":{"records":[{"t":1,"p":1,"n":"SPEL - Spell","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":3,"n":"MDOB - Menu Display Object"},{"t":3,"n":"ETYP - Equipment Type"},{"t":2,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"SPIT - Data","c":[{"t":3,"p":1,"n":"Base Cost"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Type"},{"t":5,"p":1,"n":"Charge Time"},{"t":3,"p":1,"n":"Cast Type"},{"t":3,"p":1,"n":"Target Type"},{"t":5,"p":1,"n":"Cast Duration"},{"t":5,"p":1,"n":"Range"},{"t":3,"p":1,"n":"Half-cost Perk"}]},{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":3,"n":"EFID - Base Effect"},{"t":6,"n":"EFIT - ","c":[{"t":5,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"}]}]}]}]}]},"name":"Bash.SpellStats","hash":"$33DCE408","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.Stats.json ================================================ {"records":"AMMO,APPA,ARMO,BOOK,INGR,KEYM,MISC,PROJ,WEAP,ALCH","description":"Stats tag from Wrye Bash.\r\n\r\nUsed when the mod modifies item stats.","tree":{"records":[{"t":1,"p":1,"n":"AMMO - Ammunition","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":2,"n":"DESC - Description"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Projectile"},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Damage"},{"t":3,"p":1,"n":"Value"}]},{"t":2,"n":"ONAM - Short Name"}]},{"t":1,"p":1,"n":"APPA - Alchemical Apparatus","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":3,"n":"QUAL - Quality"},{"t":2,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]}]},{"t":1,"p":1,"n":"ARMO - Armor","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":3,"n":"EITM - Object Effect"},{"t":3,"n":"EAMT - Enchantment Amount"},{"t":6,"n":"Male world model","c":[{"t":2,"n":"MOD2 - Model Filename"}]},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"}]},{"t":6,"n":"Female world model","c":[{"t":2,"n":"MOD4 - Model Filename"}]},{"t":6,"n":"Icon 2 (female)","c":[{"t":2,"n":"ICO2 - Large Icon filename"}]},{"t":6,"n":"BOD2 - Biped Body Template","c":[{"t":3,"n":"First Person Flags"},{"t":3,"n":"General Flags"},{"n":"Unused"},{"t":3,"n":"Armor Type"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":2,"n":"BMCT - Ragdoll Constraint Template"},{"t":3,"n":"ETYP - Equipment Type"},{"t":3,"n":"BIDS - Bash Impact Data Set"},{"t":3,"n":"BAMT - Alternate Block Material"},{"t":3,"n":"RNAM - Race"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":2,"n":"DESC - Description"},{"t":7,"n":"Armature","c":[{"t":3,"n":"MODL - Model Filename"}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":3,"n":"DNAM - Armor Rating","p":1},{"t":3,"n":"TNAM - Template Armor"}]},{"t":1,"p":1,"n":"BOOK - Book","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"}]},{"t":2,"n":"DESC - Book Text"},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Type"},{"t":11,"p":1,"n":"Unused"},{"t":12,"p":1,"n":"Teaches"},{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":3,"n":"INAM - Inventory Art"},{"t":2,"n":"CNAM - Description"}]},{"t":1,"p":1,"n":"INGR - Ingredient","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"ETYP - Equipment Type"},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":6,"n":"ENIT - Effect Data","c":[{"t":3,"n":"Ingredient Value"},{"t":3,"n":"Flags"}]},{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":3,"n":"EFID - Base Effect"},{"t":6,"n":"EFIT - ","c":[{"t":5,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"}]}]}]}]},{"t":1,"p":1,"n":"KEYM - Key","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]}]},{"t":1,"p":1,"n":"MISC - Misc. Item","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]}]},{"t":1,"p":1,"n":"PROJ - Projectile","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":6,"p":1,"n":"DATA - Data","c":[{"t":3,"n":"Flags"},{"t":3,"n":"Type"},{"t":5,"p":1,"n":"Gravity","lt":"Range","lf":"Speed"},{"t":5,"p":1,"n":"Speed","lt":"Gravity","lf":"Range"},{"t":5,"p":1,"n":"Range","lt":"Speed","lf":"Gravity"},{"t":3,"n":"Light"},{"t":3,"n":"Muzzle Flash - Light"},{"t":5,"n":"Tracer Chance"},{"t":5,"n":"Explosion - Alt. Trigger - Proximity"},{"t":5,"n":"Explosion - Alt. Trigger - Timer"},{"t":3,"n":"Explosion"},{"t":3,"n":"Sound"},{"t":5,"n":"Muzzle Flash - Duration"},{"t":5,"n":"Fade Duration"},{"t":5,"n":"Impact Force"},{"t":3,"n":"Sound - Countdown"},{"t":3,"n":"Sound - Disable"},{"t":3,"n":"Default Weapon Source"},{"t":5,"n":"Cone Spread"},{"t":5,"n":"Collision Radius"},{"t":5,"n":"Lifetime"},{"t":5,"n":"Relaunch Interval"},{"t":3,"n":"Decal Data"},{"t":3,"n":"Collision Layer"}]},{"t":6,"n":"Muzzle Flash Model","c":[{"t":2,"n":"NAM1 - Model Filename"}]},{"t":3,"n":"VNAM - Sound Level"}]},{"t":1,"p":1,"n":"WEAP - Weapon","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"n":"Version"},{"t":3,"n":"Object Format"},{"t":12,"n":"Data","c":[{"t":9,"n":"Scripts","c":[{"t":6,"n":"Script","c":[{"t":2,"n":"scriptName"},{"t":3,"n":"Flags"},{"t":9,"n":"Properties","c":[{"t":6,"n":"Property","c":[{"t":2,"n":"propertyName"},{"t":3,"n":"Type"},{"t":3,"n":"Flags"},{"t":12,"n":"Value"}]}]}]}]}]}]},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"}]},{"t":3,"n":"EITM - Object Effect"},{"t":3,"n":"EAMT - Enchantment Amount"},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":3,"n":"ETYP - Equipment Type"},{"t":3,"n":"BIDS - Block Bash Impact Data Set"},{"t":3,"n":"BAMT - Alternate Block Material"},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":2,"n":"DESC - Description"},{"t":6,"n":"Has Scope","c":[{"t":2,"n":"MOD3 - Model Filename"}]},{"t":11,"n":"NNAM - Unused"},{"t":3,"n":"INAM - Impact Data Set"},{"t":3,"n":"WNAM - 1st Person Model Object"},{"t":3,"n":"SNAM - Attack Sound"},{"t":3,"n":"XNAM - Attack Sound 2D"},{"t":3,"n":"NAM7 - Attack Loop Sound"},{"t":3,"n":"TNAM - Attack Fail Sound"},{"t":3,"n":"UNAM - Idle Sound"},{"t":3,"n":"NAM9 - Equip Sound"},{"t":3,"n":"NAM8 - Unequip Sound"},{"t":6,"s":1,"p":1,"n":"DATA - Game Data","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"},{"t":3,"p":1,"n":"Damage"}]},{"t":6,"p":1,"n":"DNAM - Data","c":[{"t":3,"n":"Animation Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Speed","lt":"Reach","lf":"Stagger"},{"t":5,"p":1,"n":"Reach","lt":"Resist","lf":"Speed"},{"t":3,"n":"Flags"},{"t":11,"n":"Unused"},{"t":5,"n":"Sight FOV"},{"t":11,"n":"Unknown"},{"t":3,"n":"Base VATS To-Hit Chance"},{"t":3,"n":"Attack Animation"},{"t":3,"n":"# Projectiles"},{"t":3,"n":"Embedded Weapon AV (unused)"},{"t":5,"n":"Range Min"},{"t":5,"n":"Range Max"},{"t":3,"n":"On Hit"},{"t":3,"n":"Flags2"},{"t":5,"n":"Animation Attack Mult"},{"t":5,"n":"Unknown"},{"t":5,"n":"Rumble - Left Motor Strength"},{"t":5,"n":"Rumble - Right Motor Strength"},{"t":5,"n":"Rumble - Duration"},{"t":11,"n":"Unknown"},{"t":3,"n":"Skill"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Resist","lt":"Stagger","lf":"Reach"},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"Stagger","lt":"Speed","lf":"Resist"}]},{"t":6,"s":1,"p":1,"n":"CRDT - Critical Data","c":[{"t":3,"p":1,"n":"Damage"},{"t":11,"p":1,"n":"Unused"},{"t":5,"p":1,"n":"% Mult"},{"t":3,"p":1,"n":"Flags"},{"t":11,"p":1,"n":"Unused"},{"t":3,"p":1,"n":"Effect"}]},{"t":3,"n":"VNAM - Detection Sound Level"},{"t":3,"n":"CNAM - Template"}]},{"t":1,"p":1,"n":"ALCH - Ingestible","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"OBND - Object Bounds","c":[{"t":3,"n":"X1"},{"t":3,"n":"Y1"},{"t":3,"n":"Z1"},{"t":3,"n":"X2"},{"t":3,"n":"Y2"},{"t":3,"n":"Z2"}]},{"t":2,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":2,"n":"DESC - Description"},{"t":6,"n":"Model","c":[{"t":2,"n":"MODL - Model Filename"}]},{"t":6,"n":"Destructable","c":[{"t":6,"n":"DEST - Header","c":[{"t":3,"n":"Health"},{"t":3,"n":"DEST Count"},{"t":3,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]}]},{"t":6,"n":"Icon","c":[{"t":2,"n":"ICON - Large Icon filename"}]},{"t":3,"n":"YNAM - Sound - Pick Up"},{"t":3,"n":"ZNAM - Sound - Drop"},{"t":3,"n":"ETYP - Equipment Type"},{"t":5,"p":1,"n":"DATA - Weight"},{"t":6,"n":"ENIT - Effect Data","c":[{"t":3,"n":"Value"},{"t":3,"n":"Flags"},{"t":3,"n":"Addiction"},{"t":5,"n":"Addiction Chance"},{"t":3,"n":"Sound - Consume"}]},{"t":8,"n":"Effects","c":[{"t":6,"n":"Effect","c":[{"t":3,"n":"EFID - Base Effect"},{"t":6,"n":"EFIT - ","c":[{"t":5,"n":"Magnitude"},{"t":3,"n":"Area"},{"t":3,"n":"Duration"}]}]}]}]}]},"name":"Bash.Stats","hash":"9BB78E19","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.Voice-F.json ================================================ {"records":"RACE","description":"Voice-F tag from Wrye Bash.\r\n\r\nUsed when the mod modifies female voice definitions.","tree":{"records":[{"t":1,"p":1,"n":"RACE - Race","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":3,"n":"SPCT - Count"},{"t":9,"n":"Actor Effects","c":[{"t":3,"n":"SPLO - Actor Effect"}]},{"t":3,"n":"WNAM - Skin"},{"t":6,"n":"BOD2 - Biped Body Template","c":[{"t":3,"n":"First Person Flags"},{"t":3,"n":"General Flags"},{"n":"Unused"},{"t":3,"n":"Armor Type"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"DATA - ","c":[{"t":10,"n":"Skill Boosts","c":[{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]}]},{"t":11,"n":"Unknown"},{"t":5,"n":"Male Height"},{"t":5,"n":"Female Height"},{"t":5,"n":"Male Weight"},{"t":5,"n":"Female Weight"},{"t":3,"n":"Flags"},{"t":5,"n":"Starting Health"},{"t":5,"n":"Starting Magicka"},{"t":5,"n":"Starting Stamina"},{"t":5,"n":"Base Carry Weight"},{"t":5,"n":"Base Mass"},{"t":5,"n":"Acceleration rate"},{"t":5,"n":"Deceleration rate"},{"t":3,"n":"Size"},{"t":3,"n":"Head Biped Object"},{"t":3,"n":"Hair Biped Object"},{"t":5,"n":"Injured Health Pct"},{"t":3,"n":"Shield Biped Object"},{"t":5,"n":"Health Regen"},{"t":5,"n":"Magicka Regen"},{"t":5,"n":"Stamina Regen"},{"t":5,"n":"Unarmed Damage"},{"t":5,"n":"Unarmed Reach"},{"t":3,"n":"Body Biped Object"},{"t":5,"n":"Aim Angle Tolerance"},{"t":5,"n":"Flight Radius"},{"t":5,"n":"Angular Acceleration Rate"},{"t":5,"n":"Angular Tolerance"},{"t":3,"n":"Flags 2"},{"t":6,"n":"Mount Data","c":[{"t":5,"n":"Offset X"},{"t":5,"n":"Offset Y"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"}]}]},{"n":"MNAM - Male Marker"},{"t":2,"n":"ANAM - Male Skeletal Model"},{"t":11,"n":"MODT - Texture Files Hashes"},{"n":"FNAM - Female Marker"},{"t":2,"n":"ANAM - Female Skeletal Model"},{"t":11,"n":"MODT - Texture Files Hashes"},{"n":"NAM2 - Marker NAM2 #1"},{"t":9,"n":"Movement Type Names","c":[{"t":2,"n":"MTNM - Name"}]},{"t":7,"p":1,"n":"VTCK - Voices","c":[{"t":3,"n":"Voice #0 (Male)"},{"t":3,"p":1,"n":"Voice #1 (Female)"}]},{"t":7,"n":"DNAM - Decapitate Armors","c":[{"t":3,"n":"Decapitate Armor #0 (Male)"},{"t":3,"n":"Decapitate Armor #1 (Female)"}]},{"t":7,"n":"HCLF - Default Hair Colors","c":[{"t":3,"n":"Default Hair Color #0 (Male)"},{"t":3,"n":"Default Hair Color #1 (Female)"}]},{"t":3,"n":"TINL - Total Number of Tints in List"},{"t":5,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"n":"UNAM - FaceGen - Face clamp"},{"t":3,"n":"ATKR - Attack Race"},{"t":10,"n":"Attacks","c":[{"t":6,"n":"Attack","c":[{"t":6,"n":"ATKD - Attack Data","c":[{"t":5,"n":"Damage Mult"},{"t":5,"n":"Attack Chance"},{"t":3,"n":"Attack Spell"},{"t":3,"n":"Attack Flags"},{"t":5,"n":"Attack Angle"},{"t":5,"n":"Strike Angle"},{"t":5,"n":"Stagger"},{"t":3,"n":"Attack Type"},{"t":5,"n":"Knockdown"},{"t":5,"n":"Recovery Time"},{"t":5,"n":"Stamina Mult"}]}]}]},{"t":6,"n":"Body Data","c":[{"n":"NAM1 - Body Data Marker"},{"t":6,"n":"Male Body Data","c":[{"n":"MNAM - Male Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"}]}]}]},{"t":6,"n":"Female Body Data","c":[{"n":"FNAM - Female Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"}]}]}]}]},{"t":9,"n":"HNAM - Hairs","c":[{"t":3,"n":"Hair"}]},{"t":9,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eye"}]},{"t":3,"n":"GNAM - Body Part Data"},{"n":"NAM2 - Marker NAM2 #2"},{"n":"NAM3 - Marker NAM3 #3"},{"t":6,"n":"Male Behavior Graph","c":[{"n":"MNAM - Male Data Marker"}]},{"t":6,"n":"Female Behavior Graph","c":[{"n":"FNAM - Female Data Marker"}]},{"t":3,"n":"NAM4 - Material Type"},{"t":3,"n":"NAM5 - Impact Data Set"},{"t":3,"n":"NAM7 - Decapitation FX"},{"t":3,"n":"ONAM - Open Loot Sound"},{"t":3,"n":"LNAM - Close Loot Sound"},{"t":7,"n":"Biped Object Names","c":[{"t":2,"n":"NAME - Name"}]},{"t":10,"n":"Movement Types","c":[{"t":6,"n":"Movement Types","c":[{"t":3,"n":"MTYP - Movement Type"}]}]},{"t":3,"n":"VNAM - Equipment Flags"},{"t":9,"n":"Equip Slots","c":[{"t":3,"n":"QNAM - Equip Slot"}]},{"t":3,"n":"UNES - Unarmed Equip Slot"},{"t":7,"n":"Phoneme Target Names","c":[{"t":2,"n":"PHTN - Name"}]},{"t":6,"n":"FaceFX Phonemes","c":[{"t":6,"n":"IY","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]}]},{"t":3,"n":"WKMV - Base Movement Default - Walk"},{"t":3,"n":"RNMV - Base Movement Default - Run"},{"t":3,"n":"SWMV - Base Movement Default - Swim"},{"t":3,"n":"FLMV - Base Movement Default - Fly"},{"t":3,"n":"SNMV - Base Movement Default - Sneak"},{"t":3,"n":"SPMV - Base Movement Default - Sprint"},{"t":6,"n":"Head Data","c":[{"n":"NAM0 - Head Data Marker"},{"t":6,"n":"Male Head Data","d":1,"c":[{"n":"MNAM - Male Data Marker"}]},{"t":6,"n":"Female Head Data","d":1,"c":[{"n":"NAM0 - Head Data Marker"},{"n":"FNAM - Female Data Marker"}]}]},{"t":3,"n":"NAM8 - Morph race"},{"t":3,"n":"RNAM - Armor race"}]}]},"name":"Bash.Voice-F","hash":"$F6404D03","color":255} ================================================ FILE: frontend/settings/Skyrim/Bash.Voice-M.json ================================================ {"records":"RACE","description":"Voice-M tag from Wrye Bash.\r\n\r\nUsed when the mod modifies male voice definitions.","tree":{"records":[{"t":1,"p":1,"n":"RACE - Race","c":[{"t":6,"n":"Record Header","c":[{"t":2,"n":"Signature"},{"t":3,"n":"Data Size"},{"t":3,"n":"Record Flags"},{"t":3,"n":"FormID"},{"t":11,"n":"Version Control Info 1"},{"t":3,"n":"Form Version"},{"t":11,"n":"Version Control Info 2"}]},{"t":2,"n":"EDID - Editor ID"},{"t":2,"n":"FULL - Name"},{"t":2,"n":"DESC - Description"},{"t":3,"n":"SPCT - Count"},{"t":9,"n":"Actor Effects","c":[{"t":3,"n":"SPLO - Actor Effect"}]},{"t":3,"n":"WNAM - Skin"},{"t":6,"n":"BOD2 - Biped Body Template","c":[{"t":3,"n":"First Person Flags"},{"t":3,"n":"General Flags"},{"n":"Unused"},{"t":3,"n":"Armor Type"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":9,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":6,"n":"DATA - ","c":[{"t":10,"n":"Skill Boosts","c":[{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]},{"t":6,"n":"Skill Boost","c":[{"t":3,"n":"Skill"},{"t":3,"n":"Boost"}]}]},{"t":11,"n":"Unknown"},{"t":5,"n":"Male Height"},{"t":5,"n":"Female Height"},{"t":5,"n":"Male Weight"},{"t":5,"n":"Female Weight"},{"t":3,"n":"Flags"},{"t":5,"n":"Starting Health"},{"t":5,"n":"Starting Magicka"},{"t":5,"n":"Starting Stamina"},{"t":5,"n":"Base Carry Weight"},{"t":5,"n":"Base Mass"},{"t":5,"n":"Acceleration rate"},{"t":5,"n":"Deceleration rate"},{"t":3,"n":"Size"},{"t":3,"n":"Head Biped Object"},{"t":3,"n":"Hair Biped Object"},{"t":5,"n":"Injured Health Pct"},{"t":3,"n":"Shield Biped Object"},{"t":5,"n":"Health Regen"},{"t":5,"n":"Magicka Regen"},{"t":5,"n":"Stamina Regen"},{"t":5,"n":"Unarmed Damage"},{"t":5,"n":"Unarmed Reach"},{"t":3,"n":"Body Biped Object"},{"t":5,"n":"Aim Angle Tolerance"},{"t":5,"n":"Flight Radius"},{"t":5,"n":"Angular Acceleration Rate"},{"t":5,"n":"Angular Tolerance"},{"t":3,"n":"Flags 2"},{"t":6,"n":"Mount Data","c":[{"t":5,"n":"Offset X"},{"t":5,"n":"Offset Y"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"},{"t":5,"n":"Unknown"}]}]},{"n":"MNAM - Male Marker"},{"t":2,"n":"ANAM - Male Skeletal Model"},{"t":11,"n":"MODT - Texture Files Hashes"},{"n":"FNAM - Female Marker"},{"t":2,"n":"ANAM - Female Skeletal Model"},{"t":11,"n":"MODT - Texture Files Hashes"},{"n":"NAM2 - Marker NAM2 #1"},{"t":9,"n":"Movement Type Names","c":[{"t":2,"n":"MTNM - Name"}]},{"t":7,"p":1,"n":"VTCK - Voices","c":[{"t":3,"p":1,"n":"Voice #0 (Male)"},{"t":3,"n":"Voice #1 (Female)"}]},{"t":7,"n":"DNAM - Decapitate Armors","c":[{"t":3,"n":"Decapitate Armor #0 (Male)"},{"t":3,"n":"Decapitate Armor #1 (Female)"}]},{"t":7,"n":"HCLF - Default Hair Colors","c":[{"t":3,"n":"Default Hair Color #0 (Male)"},{"t":3,"n":"Default Hair Color #1 (Female)"}]},{"t":3,"n":"TINL - Total Number of Tints in List"},{"t":5,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"n":"UNAM - FaceGen - Face clamp"},{"t":3,"n":"ATKR - Attack Race"},{"t":10,"n":"Attacks","c":[{"t":6,"n":"Attack","c":[{"t":6,"n":"ATKD - Attack Data","c":[{"t":5,"n":"Damage Mult"},{"t":5,"n":"Attack Chance"},{"t":3,"n":"Attack Spell"},{"t":3,"n":"Attack Flags"},{"t":5,"n":"Attack Angle"},{"t":5,"n":"Strike Angle"},{"t":5,"n":"Stagger"},{"t":3,"n":"Attack Type"},{"t":5,"n":"Knockdown"},{"t":5,"n":"Recovery Time"},{"t":5,"n":"Stamina Mult"}]}]}]},{"t":6,"n":"Body Data","c":[{"n":"NAM1 - Body Data Marker"},{"t":6,"n":"Male Body Data","c":[{"n":"MNAM - Male Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"}]}]}]},{"t":6,"n":"Female Body Data","c":[{"n":"FNAM - Female Data Marker"},{"t":10,"n":"Parts","c":[{"t":6,"n":"Part","c":[{"t":3,"n":"INDX - Index"}]}]}]}]},{"t":9,"n":"HNAM - Hairs","c":[{"t":3,"n":"Hair"}]},{"t":9,"n":"ENAM - Eyes","c":[{"t":3,"n":"Eye"}]},{"t":3,"n":"GNAM - Body Part Data"},{"n":"NAM2 - Marker NAM2 #2"},{"n":"NAM3 - Marker NAM3 #3"},{"t":6,"n":"Male Behavior Graph","c":[{"n":"MNAM - Male Data Marker"}]},{"t":6,"n":"Female Behavior Graph","c":[{"n":"FNAM - Female Data Marker"}]},{"t":3,"n":"NAM4 - Material Type"},{"t":3,"n":"NAM5 - Impact Data Set"},{"t":3,"n":"NAM7 - Decapitation FX"},{"t":3,"n":"ONAM - Open Loot Sound"},{"t":3,"n":"LNAM - Close Loot Sound"},{"t":7,"n":"Biped Object Names","c":[{"t":2,"n":"NAME - Name"}]},{"t":10,"n":"Movement Types","c":[{"t":6,"n":"Movement Types","c":[{"t":3,"n":"MTYP - Movement Type"}]}]},{"t":3,"n":"VNAM - Equipment Flags"},{"t":9,"n":"Equip Slots","c":[{"t":3,"n":"QNAM - Equip Slot"}]},{"t":3,"n":"UNES - Unarmed Equip Slot"},{"t":7,"n":"Phoneme Target Names","c":[{"t":2,"n":"PHTN - Name"}]},{"t":6,"n":"FaceFX Phonemes","c":[{"t":6,"n":"IY","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]}]},{"t":3,"n":"WKMV - Base Movement Default - Walk"},{"t":3,"n":"RNMV - Base Movement Default - Run"},{"t":3,"n":"SWMV - Base Movement Default - Swim"},{"t":3,"n":"FLMV - Base Movement Default - Fly"},{"t":3,"n":"SNMV - Base Movement Default - Sneak"},{"t":3,"n":"SPMV - Base Movement Default - Sprint"},{"t":6,"n":"Head Data","c":[{"n":"NAM0 - Head Data Marker"},{"t":6,"n":"Male Head Data","d":1,"c":[{"n":"MNAM - Male Data Marker"}]},{"t":6,"n":"Female Head Data","d":1,"c":[{"n":"NAM0 - Head Data Marker"},{"n":"FNAM - Female Data Marker"}]}]},{"t":3,"n":"NAM8 - Morph race"},{"t":3,"n":"RNAM - Armor race"}]}]},"name":"Bash.Voice-M","hash":"$E9C18B2C","color":255} ================================================ FILE: frontend/settings/Skyrim/Skip.json ================================================ {"records":"","description":"Special setting. Any plugin with this setting will be excluded from patch creation.","tree":{"records":[]},"name":"Skip","hash":"$8ED3D1DA","color":8421504} ================================================ FILE: frontend/settings/Skyrim/Smash.All.json ================================================ {"records":"AACT,ACTI,ADDN,ALCH,AMMO,ANIO,APPA,ARMA,ARMO,ARTO,ASPC,ASTP,AVIF,BOOK,BPTD,CAMS,CELL,CLAS,CLDC,CLFM,CLMT,COBJ,COLL,CONT,CPTH,CSTY,DEBR,DIAL,DLBR,DLVW,DOOR,DUAL,ECZN,EFSH,ENCH,EQUP,EXPL,EYES,FACT,FLOR,FLST,FSTP,FSTS,FURN,GLOB,GMST,GRAS,HAIR,HAZD,HDPT,IDLM,IMAD,IMGS,INFO,INGR,IPCT,IPDS,KEYM,KYWD,LAND,LCRT,LENS,LGTM,LIGH,LSCR,LTEX,LVLI,LVLN,LVSP,MATO,MATT,MESG,MGEF,MISC,MOVT,MSTT,MUSC,MUST,NPC_,OTFT,PACK,PARW,PBAR,PBEA,PCON,PERK,PFLA,PGRE,PHZD,PMIS,PROJ,PWAT,QUST,RACE,REFR,REGN,RELA,REVB,RFCT,RGDL,SCEN,SCOL,SCPT,SCRL,SHOU,SLGM,SMBN,SMEN,SMQN,SNCT,SNDR,SOPM,SOUN,SPEL,SPGD,STAT,TACT,TREE,TXST,VOLI,VTYP,WATR,WEAP,WOOP,WRLD,WTHR,ACHR","description":"Smashes all the things. Produced using autoset attributes on all record types found in Skyrim.esm and DLCs. Replaces the old \"Automatic\" setting.\r\n\r\nLast updated 04\/14\/2018.","tree":{"records":[{"t":1,"p":1,"n":"AACT - Action","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"CNAM - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":1,"p":1,"n":"ACTI - Activator","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"PNAM - Marker Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":3,"n":"Unused"}]},{"t":3,"p":1,"n":"SNAM - Sound - Looping"},{"t":3,"p":1,"n":"VNAM - Sound - Activation"},{"t":3,"p":1,"n":"WNAM - Water Type"},{"t":2,"p":1,"n":"RNAM - Activate Text Override"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":3,"p":1,"n":"KNAM - Interaction Keyword"}]},{"t":1,"p":1,"n":"ADDN - Addon Node","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":3,"p":1,"n":"DATA - Node Index"},{"t":3,"p":1,"n":"SNAM - Sound"},{"t":6,"s":1,"p":1,"n":"DNAM - Data","c":[{"t":3,"p":1,"n":"Master Particle System Cap"},{"t":3,"p":1,"n":"Flags"}]}]},{"t":1,"p":1,"n":"ALCH - Ingestible","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":3,"p":1,"n":"ETYP - Equipment Type"},{"t":5,"p":1,"n":"DATA - Weight"},{"t":6,"s":1,"p":1,"n":"ENIT - Effect Data","c":[{"t":3,"p":1,"n":"Value"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Addiction"},{"t":5,"p":1,"n":"Addiction Chance"},{"t":3,"p":1,"n":"Sound - Consume"}]},{"t":8,"s":1,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":3,"p":1,"n":"EFID - Base Effect"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":5,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"}]},{"t":8,"s":1,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]}]},{"t":1,"p":1,"n":"AMMO - Ammunition","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":2,"p":1,"n":"DESC - Description"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Projectile"},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Damage"},{"t":3,"p":1,"n":"Value"}]},{"t":2,"p":1,"n":"ONAM - Short Name"}]},{"t":1,"p":1,"n":"ANIO - Animated Object","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":2,"p":1,"n":"BNAM - Unload Event"}]},{"t":1,"p":1,"n":"APPA - Alchemical Apparatus","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":3,"p":1,"n":"QUAL - Quality"},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]}]},{"t":1,"p":1,"n":"ARMA - Armor Addon","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"BOD2 - Biped Body Template","c":[{"t":3,"p":1,"n":"First Person Flags"},{"t":3,"p":1,"n":"General Flags"},{"n":"Unused"},{"t":3,"p":1,"n":"Armor Type"}],"lt":"BODT - Body Template","lf":"BODT - Body Template"},{"t":6,"s":1,"p":1,"n":"BODT - Body Template","c":[{"t":3,"p":1,"n":"First Person Flags"},{"t":3,"p":1,"n":"General Flags"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Armor Type"}],"lt":"BOD2 - Biped Body Template","lf":"BOD2 - Biped Body Template"},{"t":3,"p":1,"n":"RNAM - Race"},{"t":6,"s":1,"p":1,"n":"DNAM - Data","c":[{"t":3,"p":1,"n":"Male Priority"},{"t":3,"p":1,"n":"Female Priority"},{"t":3,"p":1,"n":"Weight slider - Male"},{"t":3,"p":1,"n":"Weight slider - Female"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Detection Sound Value"},{"t":5,"p":1,"n":"Weapon Adjust"}]},{"t":6,"s":1,"p":1,"n":"Male world model","c":[{"t":2,"p":1,"n":"MOD2 - Model Filename"},{"t":11,"p":1,"n":"MO2T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO2S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Female world model","c":[{"t":2,"p":1,"n":"MOD3 - Model Filename"},{"t":11,"p":1,"n":"MO3T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO3S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Male 1st Person","c":[{"t":2,"p":1,"n":"MOD4 - Model Filename"},{"t":11,"p":1,"n":"MO4T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO4S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Female 1st Person","c":[{"t":2,"p":1,"n":"MOD5 - Model Filename"},{"t":11,"p":1,"n":"MO5T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO5S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":3,"p":1,"n":"NAM0 - Male Skin Texture"},{"t":3,"p":1,"n":"NAM1 - Female Skin texture"},{"t":3,"p":1,"n":"NAM2 - Male Skin Texture Swap List"},{"t":3,"p":1,"n":"NAM3 - Female Skin Texture Swap List"},{"t":8,"s":1,"p":1,"n":"Additional Races","d":1,"c":[{"t":3,"p":1,"n":"MODL - Race"}]},{"t":3,"p":1,"n":"SNDD - Footstep Sound"},{"t":3,"p":1,"n":"ONAM - Art Object"}]},{"t":1,"p":1,"n":"ARMO - Armor","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"EITM - Object Effect"},{"t":3,"p":1,"n":"EAMT - Enchantment Amount"},{"t":6,"s":1,"p":1,"n":"Male world model","c":[{"t":2,"p":1,"n":"MOD2 - Model Filename"},{"t":11,"p":1,"n":"MO2T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO2S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"Female world model","c":[{"t":2,"p":1,"n":"MOD4 - Model Filename"},{"t":11,"p":1,"n":"MO4T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO4S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Icon 2 (female)","c":[{"t":2,"p":1,"n":"ICO2 - Large Icon filename"},{"t":2,"p":1,"n":"MIC2 - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"BOD2 - Biped Body Template","c":[{"t":3,"p":1,"n":"First Person Flags"},{"t":3,"p":1,"n":"General Flags"},{"n":"Unused"},{"t":3,"p":1,"n":"Armor Type"}],"lt":"BODT - Body Template","lf":"BODT - Body Template"},{"t":6,"s":1,"p":1,"n":"BODT - Body Template","c":[{"t":3,"p":1,"n":"First Person Flags"},{"t":3,"p":1,"n":"General Flags"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Armor Type"}],"lt":"BOD2 - Biped Body Template","lf":"BOD2 - Biped Body Template"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":2,"p":1,"n":"BMCT - Ragdoll Constraint Template"},{"t":3,"p":1,"n":"ETYP - Equipment Type"},{"t":3,"p":1,"n":"BIDS - Bash Impact Data Set"},{"t":3,"p":1,"n":"BAMT - Alternate Block Material"},{"t":3,"p":1,"n":"RNAM - Race"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":2,"p":1,"n":"DESC - Description"},{"t":8,"s":1,"p":1,"n":"Armature","d":1,"c":[{"t":3,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":3,"p":1,"n":"DNAM - Armor Rating"},{"t":3,"p":1,"n":"TNAM - Template Armor"}]},{"t":1,"p":1,"n":"ARTO - Art Object","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":3,"p":1,"n":"DNAM - Art Type"}]},{"t":1,"p":1,"n":"ASPC - Acoustic Space","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"SNAM - Ambient Sound"},{"t":3,"p":1,"n":"RDAT - Use Sound from Region (Interiors Only)"},{"t":3,"p":1,"n":"BNAM - Environment Type (reverb)"}]},{"t":1,"p":1,"n":"ASTP - Association Type","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"MPRT - Male Parent Title"},{"t":2,"p":1,"n":"FPRT - Female Parent Title"},{"t":2,"p":1,"n":"MCHT - Male Child Title"},{"t":2,"p":1,"n":"FCHT - Female Child Title"},{"t":3,"p":1,"n":"DATA - Flags"}]},{"t":1,"p":1,"n":"AVIF - Actor Value Information","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"DESC - Description"},{"t":2,"p":1,"n":"ANAM - Abbreviation"},{"t":11,"n":"CNAM - Unknown"},{"t":6,"s":1,"p":1,"n":"AVSK - Skill","c":[{"t":5,"p":1,"n":"Skill Use Mult"},{"t":5,"p":1,"n":"Skill Offset Mult"},{"t":5,"p":1,"n":"Skill Improve Mult"},{"t":5,"p":1,"n":"Skill Improve Offset"}]},{"t":8,"s":1,"p":1,"n":"Perk Tree","d":1,"c":[{"t":6,"p":1,"n":"Node","c":[{"t":3,"p":1,"n":"PNAM - Perk"},{"t":11,"n":"FNAM - Unknown"},{"t":3,"p":1,"n":"XNAM - Perk-Grid X"},{"t":3,"p":1,"n":"YNAM - Perk-Grid Y"},{"t":5,"p":1,"n":"HNAM - Horizontal Position"},{"t":5,"p":1,"n":"VNAM - Vertical Position"},{"t":3,"p":1,"n":"SNAM - Associated Skill"},{"t":8,"p":1,"n":"Connections","c":[{"t":3,"p":1,"n":"CNAM - Line to Index"}]},{"t":3,"p":1,"n":"INAM - Index"}]}]}]},{"t":1,"p":1,"n":"BOOK - Book","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":2,"p":1,"n":"DESC - Book Text"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Skill"},{"t":3,"p":1,"n":"Spell"},{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":3,"p":1,"n":"INAM - Inventory Art"},{"t":2,"p":1,"n":"CNAM - Description"}]},{"t":1,"p":1,"n":"BPTD - Body Part Data","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":10,"p":1,"n":"Body Parts","d":1,"c":[{"t":6,"p":1,"n":"Body Part","c":[{"t":2,"p":1,"n":"BPTN - Part Name"},{"t":2,"p":1,"n":"PNAM - Pose Matching"},{"t":2,"p":1,"n":"BPNN - Part Node"},{"t":2,"p":1,"n":"BPNT - VATS Target"},{"t":2,"p":1,"n":"BPNI - IK Data - Start Node"},{"t":6,"p":1,"n":"BPND - ","c":[{"t":5,"p":1,"n":"Damage Mult"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Part Type"},{"t":3,"p":1,"n":"Health Percent"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"To Hit Chance"},{"t":3,"p":1,"n":"Explodable - Explosion Chance %"},{"t":3,"p":1,"n":"Explodable - Debris Count"},{"t":3,"p":1,"n":"Explodable - Debris"},{"t":3,"p":1,"n":"Explodable - Explosion"},{"t":5,"p":1,"n":"Tracking Max Angle"},{"t":5,"p":1,"n":"Explodable - Debris Scale"},{"t":3,"p":1,"n":"Severable - Debris Count"},{"t":3,"p":1,"n":"Severable - Debris"},{"t":3,"p":1,"n":"Severable - Explosion"},{"t":5,"p":1,"n":"Severable - Debris Scale"},{"t":6,"p":1,"n":"Gore Effects Positioning","c":[{"t":6,"p":1,"n":"Translate","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]},{"t":3,"p":1,"n":"Severable - Impact DataSet"},{"t":3,"p":1,"n":"Explodable - Impact DataSet"},{"t":3,"p":1,"n":"Severable - Decal Count"},{"t":3,"p":1,"n":"Explodable - Decal Count"},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"Limb Replacement Scale"}]},{"t":2,"p":1,"n":"NAM1 - Limb Replacement Model"},{"t":2,"p":1,"n":"NAM4 - Gore Effects - Target Bone"},{"t":11,"p":1,"n":"NAM5 - Texture Files Hashes"}]}]}]},{"t":1,"p":1,"n":"CAMS - Camera Shot","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Action"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Flags"},{"t":6,"p":1,"n":"Time Multipliers","c":[{"t":5,"p":1,"n":"Player"},{"t":5,"p":1,"n":"Target"},{"t":5,"p":1,"n":"Global"}]},{"t":5,"p":1,"n":"Max Time"},{"t":5,"p":1,"n":"Min Time"},{"t":5,"p":1,"n":"Target % Between Actors"},{"t":5,"p":1,"n":"Near Target Distance"}]},{"t":3,"p":1,"n":"MNAM - Image Space Modifier"}]},{"t":1,"p":1,"n":"CELL - Cell","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"DATA - Flags"},{"t":6,"s":1,"p":1,"n":"XCLC - Grid","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"},{"t":3,"p":1,"n":"Force Hide Land"}]},{"t":6,"s":1,"p":1,"n":"XCLL - Lighting","c":[{"t":6,"p":1,"n":"Ambient Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Directional Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Fog Color Near","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Fog Near"},{"t":5,"p":1,"n":"Fog Far"},{"t":3,"p":1,"n":"Directional Rotation XY"},{"t":3,"p":1,"n":"Directional Rotation Z"},{"t":5,"p":1,"n":"Directional Fade"},{"t":5,"p":1,"n":"Fog Clip Distance"},{"t":5,"p":1,"n":"Fog Power"},{"t":6,"p":1,"n":"Ambient Colors","c":[{"t":6,"p":1,"n":"Directional","c":[{"t":6,"p":1,"n":"X+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"X-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Specular","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Scale"}]},{"t":6,"p":1,"n":"Fog Color Far","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Fog Max"},{"t":5,"p":1,"n":"Light Fade Begin"},{"t":5,"p":1,"n":"Light Fade End"},{"t":3,"p":1,"n":"Inherits"}]},{"t":11,"n":"TVDT - Occlusion Data"},{"t":11,"n":"MHDT - Max Height Data"},{"t":3,"p":1,"n":"LTMP - Lighting Template"},{"t":11,"n":"LNAM - Unknown"},{"t":5,"p":1,"n":"XCLW - Water Height"},{"t":2,"p":1,"n":"XNAM - Water Noise Texture"},{"t":7,"p":1,"n":"XCLR - Regions","c":[{"t":3,"p":1,"n":"Region"}]},{"t":3,"p":1,"n":"XLCN - Location"},{"t":11,"n":"XWCN - Unknown"},{"t":11,"n":"XWCS - Unknown"},{"t":6,"s":1,"p":1,"n":"XWCU - Water Velocity","c":[{"t":5,"p":1,"n":"X Offset"},{"t":5,"p":1,"n":"Y Offset"},{"t":5,"p":1,"n":"Z Offset"},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"X Angle"},{"t":5,"p":1,"n":"Y Angle"},{"t":5,"p":1,"n":"Z Angle"}]},{"t":3,"p":1,"n":"XCWT - Water"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":3,"p":1,"n":"XILL - Lock List"},{"t":2,"p":1,"n":"XWEM - Water Environment Map"},{"t":3,"p":1,"n":"XCCM - Sky\/Weather from Region"},{"t":3,"p":1,"n":"XCAS - Acoustic Space"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":3,"p":1,"n":"XCMO - Music Type"},{"t":3,"p":1,"n":"XCIM - Image Space"}]},{"t":1,"p":1,"n":"CLAS - Class","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Teaches"},{"t":3,"p":1,"n":"Maximum training level"},{"t":7,"p":1,"n":"Skill Weights","c":[{"t":3,"p":1,"n":"Weight"}]},{"t":5,"p":1,"n":"Bleedout Default"},{"t":3,"p":1,"n":"Voice Points"},{"t":7,"p":1,"n":"Attribute Weights","c":[{"t":3,"p":1,"n":"Weight"}]}]}]},{"t":1,"p":1,"n":"CLDC","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"}]},{"t":1,"p":1,"n":"CLFM - Color","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"CNAM - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":3,"p":1,"n":"FNAM - Playable"}]},{"t":1,"p":1,"n":"CLMT - Climate","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":7,"p":1,"n":"WLST - Weather Types","c":[{"t":6,"p":1,"n":"Weather Type","c":[{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Chance"},{"t":3,"p":1,"n":"Global"}]}]},{"t":2,"p":1,"n":"FNAM - Sun Texture"},{"t":2,"p":1,"n":"GNAM - Sun Glare Texture"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"TNAM - Timing","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Begin"},{"t":3,"p":1,"n":"End"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Begin"},{"t":3,"p":1,"n":"End"}]},{"t":3,"p":1,"n":"Volatility"},{"t":3,"p":1,"n":"Moons \/ Phase Length"}]}]},{"t":1,"p":1,"n":"COBJ - Constructible Object","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"n":"COCT - Count"},{"t":10,"p":1,"n":"Items","d":1,"c":[{"t":6,"p":1,"n":"Item","c":[{"t":6,"p":1,"n":"CNTO - Item","c":[{"t":3,"p":1,"n":"Item"},{"t":3,"p":1,"n":"Count"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":3,"p":1,"n":"CNAM - Created Object"},{"t":3,"p":1,"n":"BNAM - Workbench Keyword"},{"t":3,"p":1,"n":"NAM1 - Created Object Count"}]},{"t":1,"p":1,"n":"COLL - Collision Layer","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"DESC - Description"},{"t":3,"p":1,"n":"BNAM - Index"},{"t":6,"s":1,"p":1,"n":"FNAM - Debug Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":3,"n":"Unused"}]},{"t":3,"p":1,"n":"GNAM - Flags"},{"t":2,"p":1,"n":"MNAM - Name"},{"t":3,"n":"INTV - Interactables Count"},{"t":7,"p":1,"n":"CNAM - Collides With","c":[{"t":3,"p":1,"n":"Forms"}]}]},{"t":1,"p":1,"n":"CONT - Container","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":3,"n":"COCT - Count"},{"t":10,"p":1,"n":"Items","d":1,"c":[{"t":6,"p":1,"n":"Item","c":[{"t":6,"p":1,"n":"CNTO - Item","c":[{"t":3,"p":1,"n":"Item"},{"t":3,"p":1,"n":"Count"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Weight"}]},{"t":3,"p":1,"n":"SNAM - Sound - Open"},{"t":3,"p":1,"n":"QNAM - Sound - Close"}]},{"t":1,"p":1,"n":"CPTH - Camera Path","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":7,"p":1,"n":"ANAM - Related Camera Paths","c":[{"t":3,"p":1,"n":"Related Camera Path"}]},{"t":3,"p":1,"n":"DATA - Camera Zoom"},{"t":8,"s":1,"p":1,"n":"Camera Shots","d":1,"c":[{"t":3,"p":1,"n":"SNAM - Camera Shot"}]}]},{"t":1,"p":1,"n":"CSTY - Combat Style","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"CSGD - General","c":[{"t":5,"p":1,"n":"Offensive Mult"},{"t":5,"p":1,"n":"Defensive Mult"},{"t":5,"p":1,"n":"Group Offensive Mult"},{"t":5,"p":1,"n":"Equipment Score Mult - Melee"},{"t":5,"p":1,"n":"Equipment Score Mult - Magic"},{"t":5,"p":1,"n":"Equipment Score Mult - Ranged"},{"t":5,"p":1,"n":"Equipment Score Mult - Shout"},{"t":5,"p":1,"n":"Equipment Score Mult - Unarmed"},{"t":5,"p":1,"n":"Equipment Score Mult - Staff"},{"t":5,"p":1,"n":"Avoid Threat Chance"}]},{"t":11,"n":"CSMD - Unknown"},{"t":6,"s":1,"p":1,"n":"CSME - Melee","c":[{"t":5,"p":1,"n":"Attack Staggered Mult"},{"t":5,"p":1,"n":"Power Attack Staggered Mult"},{"t":5,"p":1,"n":"Power Attack Blocking Mult"},{"t":5,"p":1,"n":"Bash Mult"},{"t":5,"p":1,"n":"Bash Recoil Mult"},{"t":5,"p":1,"n":"Bash Attack Mult"},{"t":5,"p":1,"n":"Bash Power Attack Mult"},{"t":5,"p":1,"n":"Special Attack Mult"}]},{"t":6,"s":1,"p":1,"n":"CSCR - Close Range","c":[{"t":5,"p":1,"n":"Circle Mult"},{"t":5,"p":1,"n":"Fallback Mult"},{"t":5,"p":1,"n":"Flank Distance"},{"t":5,"p":1,"n":"Stalk Time"}]},{"t":6,"s":1,"p":1,"n":"CSLR - Long Range","c":[{"t":5,"p":1,"n":"Strafe Mult"}]},{"t":6,"s":1,"p":1,"n":"CSFL - Flight","c":[{"t":5,"p":1,"n":"Hover Chance"},{"t":5,"p":1,"n":"Dive Bomb Chance"},{"t":5,"p":1,"n":"Ground Attack Chance"},{"t":5,"p":1,"n":"Hover Time"},{"t":5,"p":1,"n":"Ground Attack Time"},{"t":5,"p":1,"n":"Perch Attack Chance"},{"t":5,"p":1,"n":"Perch Attack Time"},{"t":5,"p":1,"n":"Flying Attack Chance"}]},{"t":3,"p":1,"n":"DATA - Flags"}]},{"t":1,"p":1,"n":"DEBR - Debris","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":8,"s":1,"p":1,"n":"Models","d":1,"c":[{"t":6,"p":1,"n":"Model","c":[{"t":6,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Percentage"},{"t":2,"p":1,"n":"Model Filename"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]}]}]},{"t":1,"p":1,"n":"DIAL - Dialog Topic","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":5,"p":1,"n":"PNAM - Priority"},{"t":3,"p":1,"n":"BNAM - Branch"},{"t":3,"p":1,"n":"QNAM - Quest"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Topic Flags"},{"t":3,"p":1,"n":"Category"},{"t":3,"p":1,"n":"Subtype"}]},{"t":2,"p":1,"n":"SNAM - Subtype Name"},{"t":3,"p":1,"n":"TIFC - Info Count"}]},{"t":1,"p":1,"n":"DLBR - Dialog Branch","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"QNAM - Quest"},{"t":3,"n":"TNAM - Unknown"},{"t":3,"p":1,"n":"DNAM - Flags"},{"t":3,"p":1,"n":"SNAM - Starting Topic"}]},{"t":1,"p":1,"n":"DLVW - Dialog View","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"QNAM - Quest"},{"t":8,"s":1,"p":1,"n":"Branches","d":1,"c":[{"t":3,"p":1,"n":"BNAM - Branch"}]},{"t":8,"n":"Unknown TNAM","c":[{"t":6,"n":"Unknown","c":[{"t":11,"n":"TNAM - Unknown"}]}]},{"t":11,"n":"ENAM - Unknown"},{"t":11,"n":"DNAM - Unknown"}]},{"t":1,"n":"DOBJ - Default Object Manager","c":[{"t":2,"n":"EDID - Editor ID"},{"t":7,"n":"DNAM - Objects","c":[{"t":6,"n":"Object","c":[{"t":3,"n":"Use"},{"t":3,"n":"Object ID"}]}]}]},{"t":1,"p":1,"n":"DOOR - Door","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"SNAM - Sound - Open"},{"t":3,"p":1,"n":"ANAM - Sound - Close"},{"t":3,"p":1,"n":"BNAM - Sound - Loop"},{"t":3,"p":1,"n":"FNAM - Flags"}]},{"t":1,"p":1,"n":"DUAL - Dual Cast Data","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Projectile"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Effect Shader"},{"t":3,"p":1,"n":"Hit Effect Art"},{"t":3,"p":1,"n":"Impact Data Set"},{"t":3,"p":1,"n":"Inherit Scale"}]}]},{"t":1,"p":1,"n":"ECZN - Encounter Zone","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Rank"},{"t":3,"p":1,"n":"Min Level"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Max Level"}]}]},{"t":1,"p":1,"n":"EFSH - Effect Shader","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"ICON - Fill Texture"},{"t":2,"p":1,"n":"ICO2 - Particle Shader Texture"},{"t":2,"p":1,"n":"NAM7 - Holes Texture"},{"t":2,"p":1,"n":"NAM8 - Membrane Palette Texture"},{"t":2,"p":1,"n":"NAM9 - Particle Palette Texture"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Membrane Shader - Source Blend Mode"},{"t":3,"p":1,"n":"Membrane Shader - Blend Operation"},{"t":3,"p":1,"n":"Membrane Shader - Z Test Function"},{"t":6,"p":1,"n":"Fill\/Texture Effect - Color Key 1","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Fade In Time"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Full Alpha Time"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Fade Out Time"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Presistent Alpha Ratio"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Pulse Amplitude"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Pulse Frequency"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Animation Speed (U)"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Animation Speed (V)"},{"t":5,"p":1,"n":"Edge Effect - Fall Off"},{"t":6,"p":1,"n":"Edge Effect - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Edge Effect - Alpha Fade In Time"},{"t":5,"p":1,"n":"Edge Effect - Full Alpha Time"},{"t":5,"p":1,"n":"Edge Effect - Alpha Fade Out Time"},{"t":5,"p":1,"n":"Edge Effect - Persistent Alpha Ratio"},{"t":5,"p":1,"n":"Edge Effect - Alpha Pulse Amplitude"},{"t":5,"p":1,"n":"Edge Effect - Alpha Pulse Frequency"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Full Alpha Ratio"},{"t":5,"p":1,"n":"Edge Effect - Full Alpha Ratio"},{"t":3,"p":1,"n":"Membrane Shader - Dest Blend Mode"},{"t":3,"p":1,"n":"Particle Shader - Source Blend Mode"},{"t":3,"p":1,"n":"Particle Shader - Blend Operation"},{"t":3,"p":1,"n":"Particle Shader - Z Test Function"},{"t":3,"p":1,"n":"Particle Shader - Dest Blend Mode"},{"t":5,"p":1,"n":"Particle Shader - Particle Birth Ramp Up Time"},{"t":5,"p":1,"n":"Particle Shader - Full Particle Birth Time"},{"t":5,"p":1,"n":"Particle Shader - Particle Birth Ramp Down Time"},{"t":5,"p":1,"n":"Particle Shader - Full Particle Birth Ratio"},{"t":5,"p":1,"n":"Particle Shader - Persistant Particle Count"},{"t":5,"p":1,"n":"Particle Shader - Particle Lifetime"},{"t":5,"p":1,"n":"Particle Shader - Particle Lifetime +\/-"},{"t":5,"p":1,"n":"Particle Shader - Initial Speed Along Normal"},{"t":5,"p":1,"n":"Particle Shader - Acceleration Along Normal"},{"t":5,"p":1,"n":"Particle Shader - Initial Velocity #1"},{"t":5,"p":1,"n":"Particle Shader - Initial Velocity #2"},{"t":5,"p":1,"n":"Particle Shader - Initial Velocity #3"},{"t":5,"p":1,"n":"Particle Shader - Acceleration #1"},{"t":5,"p":1,"n":"Particle Shader - Acceleration #2"},{"t":5,"p":1,"n":"Particle Shader - Acceleration #3"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 1"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 2"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 1 Time"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 2 Time"},{"t":6,"p":1,"n":"Color Key 1 - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Color Key 2 - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Color Key 3 - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Color Key 1 - Color Alpha"},{"t":5,"p":1,"n":"Color Key 2 - Color Alpha"},{"t":5,"p":1,"n":"Color Key 3 - Color Alpha"},{"t":5,"p":1,"n":"Color Key 1 - Color Key Time"},{"t":5,"p":1,"n":"Color Key 2 - Color Key Time"},{"t":5,"p":1,"n":"Color Key 3 - Color Key Time"},{"t":5,"p":1,"n":"Particle Shader - Initial Speed Along Normal +\/-"},{"t":5,"p":1,"n":"Particle Shader - Initial Rotation (deg)"},{"t":5,"p":1,"n":"Particle Shader - Initial Rotation (deg) +\/-"},{"t":5,"p":1,"n":"Particle Shader - Rotation Speed (deg\/sec)"},{"t":5,"p":1,"n":"Particle Shader - Rotation Speed (deg\/sec) +\/-"},{"t":3,"p":1,"n":"Addon Models"},{"t":5,"p":1,"n":"Holes - Start Time"},{"t":5,"p":1,"n":"Holes - End Time"},{"t":5,"p":1,"n":"Holes - Start Val"},{"t":5,"p":1,"n":"Holes - End Val"},{"t":5,"p":1,"n":"Edge Width (alpha units)"},{"t":6,"p":1,"n":"Edge Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Explosion Wind Speed"},{"t":3,"p":1,"n":"Texture Count U"},{"t":3,"p":1,"n":"Texture Count V"},{"t":5,"p":1,"n":"Addon Models - Fade In Time"},{"t":5,"p":1,"n":"Addon Models - Fade Out Time"},{"t":5,"p":1,"n":"Addon Models - Scale Start"},{"t":5,"p":1,"n":"Addon Models - Scale End"},{"t":5,"p":1,"n":"Addon Models - Scale In Time"},{"t":5,"p":1,"n":"Addon Models - Scale Out Time"},{"t":3,"p":1,"n":"Ambient Sound"},{"t":6,"p":1,"n":"Fill\/Texture Effect - Color Key 2","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Fill\/Texture Effect - Color Key 3","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Fill\/Texture Effect - Color Key Scale\/Time","c":[{"t":5,"p":1,"n":"Color Key 1 - Scale"},{"t":5,"p":1,"n":"Color Key 2 - Scale"},{"t":5,"p":1,"n":"Color Key 3 - Scale"},{"t":5,"p":1,"n":"Color Key 1 - Time"},{"t":5,"p":1,"n":"Color Key 2 - Time"},{"t":5,"p":1,"n":"Color Key 3 - Time"}]},{"t":5,"p":1,"n":"Color Scale"},{"t":5,"p":1,"n":"Birth Position Offset"},{"t":5,"p":1,"n":"Birth Position Offset Range +\/-"},{"t":6,"p":1,"n":"Particle Shader Animated","c":[{"t":3,"p":1,"n":"Start Frame"},{"t":3,"p":1,"n":"Start Frame Variation"},{"t":3,"p":1,"n":"End Frame"},{"t":3,"p":1,"n":"Loop Start Frame"},{"t":3,"p":1,"n":"Loop Start Variation"},{"t":3,"p":1,"n":"Frame Count"},{"t":3,"p":1,"n":"Frame Count Variation"}]},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Scale (U)"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Scale (V)"},{"t":3,"p":1,"n":"Scene Graph Emit Depth Limit (unused)"}]}]},{"t":1,"p":1,"n":"ENCH - Object Effect","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"ENIT - Effect Data","c":[{"t":3,"p":1,"n":"Enchantment Cost"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Cast Type"},{"t":3,"p":1,"n":"Enchantment Amount"},{"t":3,"p":1,"n":"Target Type"},{"t":3,"p":1,"n":"Enchant Type"},{"t":5,"p":1,"n":"Charge Time"},{"t":3,"p":1,"n":"Base Enchantment"},{"t":3,"p":1,"n":"Worn Restrictions"}]},{"t":8,"s":1,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":3,"p":1,"n":"EFID - Base Effect"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":5,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"}]},{"t":8,"s":1,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]}]},{"t":1,"p":1,"n":"EQUP - Equip Type","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":7,"p":1,"n":"PNAM - Slot Parents","c":[{"t":3,"p":1,"n":"Can Be Equipped"}]},{"t":3,"p":1,"n":"DATA - Use All Parents"}]},{"t":1,"p":1,"n":"EXPL - Explosion","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":3,"p":1,"n":"EITM - Object Effect"},{"t":3,"p":1,"n":"MNAM - Image Space Modifier"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Light"},{"t":3,"p":1,"n":"Sound 1"},{"t":3,"p":1,"n":"Sound 2"},{"t":3,"p":1,"n":"Impact Data Set"},{"t":3,"p":1,"n":"Placed Object"},{"t":3,"p":1,"n":"Spawn Projectile"},{"t":5,"p":1,"n":"Force"},{"t":5,"p":1,"n":"Damage"},{"t":5,"p":1,"n":"Radius"},{"t":5,"p":1,"n":"IS Radius"},{"t":5,"p":1,"n":"Vertical Offset Mult"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Sound Level"}]}]},{"t":1,"p":1,"n":"EYES - Eyes","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"ICON - Texture"},{"t":3,"p":1,"n":"DATA - Flags"}]},{"t":1,"p":1,"n":"FACT - Faction","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":8,"s":1,"p":1,"n":"Relations","d":1,"c":[{"t":6,"p":1,"n":"XNAM - Relation","c":[{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Modifier"},{"t":3,"p":1,"n":"Group Combat Reaction"}]}]},{"t":6,"s":1,"p":1,"n":"DATA - Flags","c":[{"t":3,"p":1,"n":"Flags"}]},{"t":3,"p":1,"n":"JAIL - Exterior Jail Marker"},{"t":3,"p":1,"n":"WAIT - Follower Wait Marker"},{"t":3,"p":1,"n":"STOL - Stolen Goods Container"},{"t":3,"p":1,"n":"PLCN - Player Inventory Container"},{"t":3,"p":1,"n":"CRGR - Shared Crime Faction List"},{"t":3,"p":1,"n":"JOUT - Jail Outfit"},{"t":6,"s":1,"p":1,"n":"CRVA - Crime Values","c":[{"t":3,"p":1,"n":"Arrest"},{"t":3,"p":1,"n":"Attack On Sight"},{"t":3,"p":1,"n":"Murder"},{"t":3,"p":1,"n":"Assault"},{"t":3,"p":1,"n":"Trespass"},{"t":3,"p":1,"n":"Pickpocket"},{"t":3,"n":"Unknown"},{"t":5,"p":1,"n":"Steal Multiplier"},{"t":3,"p":1,"n":"Escape"},{"t":3,"p":1,"n":"Werewolf"}]},{"t":10,"p":1,"n":"Ranks","d":1,"c":[{"t":6,"p":1,"n":"Rank","c":[{"t":3,"p":1,"n":"RNAM - Rank#"},{"t":2,"p":1,"n":"MNAM - Male Title"},{"t":2,"p":1,"n":"FNAM - Female Title"},{"t":2,"n":"INAM - Insignia Unused"}]}]},{"t":3,"p":1,"n":"VEND - Vendor Buy\/Sell List"},{"t":3,"p":1,"n":"VENC - Merchant Container"},{"t":6,"s":1,"p":1,"n":"VENV - Vendor Values","c":[{"t":3,"p":1,"n":"Start Hour"},{"t":3,"p":1,"n":"End Hour"},{"t":3,"p":1,"n":"Radius"},{"t":11,"n":"Unknown 1"},{"t":3,"p":1,"n":"Only Buys Stolen Items"},{"t":3,"p":1,"n":"Not\/Sell Buy"},{"t":11,"n":"Unknown 2"}]},{"t":6,"s":1,"p":1,"n":"PLVD - Location","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Cell"},{"t":11,"p":1,"n":"Near Package Start Location"},{"t":11,"p":1,"n":"Near Editor Location"},{"t":3,"p":1,"n":"Object ID"},{"t":3,"p":1,"n":"Object Type"},{"t":3,"p":1,"n":"Keyword"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Radius"}]},{"t":3,"n":"CITC - Condition Count"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]},{"t":1,"p":1,"n":"FLOR - Flora","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":11,"n":"PNAM - Unknown"},{"t":2,"p":1,"n":"RNAM - Activate Text Override"},{"t":11,"n":"FNAM - Unknown"},{"t":3,"p":1,"n":"PFIG - Ingredient"},{"t":3,"p":1,"n":"SNAM - Sound"},{"t":6,"s":1,"p":1,"n":"PFPC - Seasonal ingredient production","c":[{"t":3,"p":1,"n":"Spring"},{"t":3,"p":1,"n":"Summer "},{"t":3,"p":1,"n":"Fall"},{"t":3,"p":1,"n":"Winter"}]}]},{"t":1,"p":1,"n":"FLST - FormID List","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":8,"s":1,"p":1,"n":"FormIDs","d":1,"c":[{"t":3,"p":1,"n":"LNAM - FormID"}]}]},{"t":1,"p":1,"n":"FSTP - Footstep","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"DATA - Impact Data Set"},{"t":2,"p":1,"n":"ANAM - Tag"}]},{"t":1,"p":1,"n":"FSTS - Footstep Set","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"XCNT - Count","c":[{"t":3,"p":1,"n":"Walk Forward Sets"},{"t":3,"p":1,"n":"Run Forward Sets"},{"t":3,"p":1,"n":"Walk Forward Alternate Sets"},{"t":3,"p":1,"n":"Run Forward Alternate Sets"},{"t":3,"p":1,"n":"Walk Forward Alternate 2 Sets"}]},{"t":7,"s":1,"p":1,"n":"DATA - Footstep Sets","c":[{"t":3,"p":1,"n":"Footstep"}]}]},{"t":1,"p":1,"n":"FURN - Furniture","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":11,"n":"PNAM - Unknown"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":3,"p":1,"n":"KNAM - Interaction Keyword"},{"t":3,"p":1,"n":"MNAM - Active Markers \/ Flags"},{"t":6,"s":1,"p":1,"n":"WBDT - Workbench Data","c":[{"t":3,"p":1,"n":"Bench Type"},{"t":3,"p":1,"n":"Uses Skill"}]},{"t":3,"p":1,"n":"NAM1 - Associated Spell"},{"t":8,"s":1,"p":1,"n":"Markers","d":1,"c":[{"t":6,"p":1,"n":"Marker","c":[{"t":3,"p":1,"n":"ENAM - Marker Index"},{"t":6,"p":1,"n":"NAM0 - Disabled Entry Points","c":[{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Disabled Points"}]},{"t":3,"p":1,"n":"FNMK - Marker Keyword"}]}]},{"t":8,"s":1,"p":1,"n":"Marker Entry Points","d":1,"c":[{"t":6,"p":1,"n":"FNPR - Marker","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Entry Points"}]}]},{"t":2,"p":1,"n":"XMRK - Model Filename"}]},{"t":1,"p":1,"n":"GLOB - Global","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"FNAM - Type"},{"t":5,"p":1,"n":"FLTV - Value"}]},{"t":1,"p":1,"n":"GMST - Game Setting","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"Name"},{"t":3,"p":1,"n":"Int"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"}]},{"t":1,"p":1,"n":"GRAS - Grass","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Density"},{"t":3,"p":1,"n":"Min Slope"},{"t":3,"p":1,"n":"Max Slope"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Units From Water"},{"t":3,"p":1,"n":"Units From Water Type"},{"t":5,"p":1,"n":"Position Range"},{"t":5,"p":1,"n":"Height Range"},{"t":5,"p":1,"n":"Color Range"},{"t":5,"p":1,"n":"Wave Period"},{"t":3,"p":1,"n":"Flags"}]}]},{"t":1,"p":1,"n":"HAIR","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"}]},{"t":1,"p":1,"n":"HAZD - Hazard","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":3,"p":1,"n":"MNAM - Image Space Modifier"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Limit"},{"t":5,"p":1,"n":"Radius"},{"t":5,"p":1,"n":"Lifetime"},{"t":5,"p":1,"n":"Image Space Radius"},{"t":5,"p":1,"n":"Target Interval"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Spell"},{"t":3,"p":1,"n":"Light"},{"t":3,"p":1,"n":"Impact Data Set"},{"t":3,"p":1,"n":"Sound"}]}]},{"t":1,"p":1,"n":"HDPT - Head Part","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":3,"p":1,"n":"DATA - Flags"},{"t":3,"p":1,"n":"PNAM - Type"},{"t":8,"s":1,"p":1,"n":"Extra Parts","d":1,"c":[{"t":3,"p":1,"n":"HNAM - Part"}]},{"t":8,"s":1,"p":1,"n":"Parts","d":1,"c":[{"t":6,"p":1,"n":"Part","c":[{"t":3,"p":1,"n":"NAM0 - Part Type"},{"t":2,"p":1,"n":"NAM1 - Filename"}]}]},{"t":3,"p":1,"n":"TNAM - Texture Set"},{"t":3,"p":1,"n":"CNAM - Color"},{"t":3,"p":1,"n":"RNAM - Valid Races"}]},{"t":1,"n":"IDLE - Idle Animation","c":[{"t":2,"n":"EDID - Editor ID"},{"t":8,"n":"Conditions","c":[{"t":6,"n":"Condition","c":[{"t":6,"n":"CTDA - ","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"n":"Comparison Value - Float"},{"t":3,"n":"Comparison Value - Global"},{"t":3,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"n":"None"},{"t":3,"n":"Integer"},{"t":5,"n":"Float"},{"t":11,"n":"Variable Name (unused)"},{"t":3,"n":"Sex"},{"t":3,"n":"Actor Value"},{"t":3,"n":"Crime Type"},{"t":3,"n":"Axis"},{"t":3,"n":"Quest Stage (unused)"},{"t":3,"n":"Misc Stat"},{"t":3,"n":"Alignment"},{"t":3,"n":"Equip Type"},{"t":3,"n":"Form Type"},{"t":3,"n":"Critical Stage"},{"t":3,"n":"Object Reference"},{"t":3,"n":"Inventory Object"},{"t":3,"n":"Actor"},{"t":3,"n":"Voice Type"},{"t":3,"n":"Idle"},{"t":3,"n":"Form List"},{"t":3,"n":"Quest"},{"t":3,"n":"Faction"},{"t":3,"n":"Cell"},{"t":3,"n":"Class"},{"t":3,"n":"Race"},{"t":3,"n":"Actor Base"},{"t":3,"n":"Global"},{"t":3,"n":"Weather"},{"t":3,"n":"Package"},{"t":3,"n":"Encounter Zone"},{"t":3,"n":"Perk"},{"t":3,"n":"Owner"},{"t":3,"n":"Furniture"},{"t":3,"n":"Effect Item"},{"t":3,"n":"Base Effect"},{"t":3,"n":"Worldspace"},{"t":3,"n":"VATS Value Function"},{"t":3,"n":"VATS Value Param (INVALID)"},{"t":3,"n":"Referenceable Object"},{"t":3,"n":"Region"},{"t":3,"n":"Keyword"},{"t":3,"n":"Player Action"},{"t":3,"n":"Casting Type"},{"t":3,"n":"Shout"},{"t":3,"n":"Location"},{"t":3,"n":"Location Ref Type"},{"t":3,"n":"Alias"},{"t":3,"n":"Packdata ID"},{"t":3,"n":"Association Type"},{"t":3,"n":"Furniture Anim"},{"t":3,"n":"Furniture Entry"},{"t":3,"n":"Scene"},{"t":3,"n":"Ward State"},{"t":3,"n":"Event"},{"t":3,"n":"Event Data"},{"t":3,"n":"Quest Stage"},{"t":3,"n":"Weapon"},{"t":3,"n":"Weapon List"},{"t":3,"n":"Target"},{"t":3,"n":"Target List"},{"t":3,"n":"Target Part"},{"t":3,"n":"VATS Action"},{"t":3,"n":"Critical Effect"},{"t":3,"n":"Critical Effect List"},{"t":3,"n":"Weapon Type"},{"t":3,"n":"Projectile Type"},{"t":3,"n":"Delivery Type"},{"t":3,"n":"Run On"},{"t":3,"n":"Reference"},{"t":3,"n":"Parameter #3"}]},{"t":2,"n":"CIS1 - Parameter #1"},{"t":2,"n":"CIS2 - Parameter #2"}]}]},{"t":2,"n":"DNAM - Filename"},{"t":2,"n":"ENAM - Animation Event"},{"t":7,"n":"ANAM - Related Idle Animations","c":[{"t":3,"n":"Related Idle Animation"}]},{"t":6,"n":"DATA - Data (unused)","c":[{"t":6,"n":"Looping seconds (both 255 forever)","c":[{"t":3,"n":"Min"},{"t":3,"n":"Max"}]},{"t":3,"n":"Flags"},{"t":3,"n":"Animation Group Section"},{"t":3,"n":"Replay Delay"}]}]},{"t":1,"p":1,"n":"IDLM - Idle Marker","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"IDLF - Flags"},{"t":3,"p":1,"n":"IDLC - Animation Count"},{"t":5,"p":1,"n":"IDLT - Idle Timer Setting"},{"t":7,"p":1,"n":"IDLA - Animations","c":[{"t":3,"p":1,"n":"Animation"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]}]},{"t":1,"p":1,"n":"IMAD - Image Space Adapter","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DNAM - Data Count","c":[{"t":3,"n":"Flags"},{"t":5,"n":"Duration"},{"t":6,"n":"HDR","c":[{"t":3,"n":"Eye Adapt Speed Mult"},{"t":3,"n":"Eye Adapt Speed Add"},{"t":3,"n":"Bloom Blur Radius Mult"},{"t":3,"n":"Bloom Blur Radius Add"},{"t":3,"n":"Bloom Threshold Mult"},{"t":3,"n":"Bloom Threshold Add"},{"t":3,"n":"Bloom Scale Mult"},{"t":3,"n":"Bloom Scale Add"},{"t":3,"n":"Target Lum Min Mult"},{"t":3,"n":"Target Lum Min Add"},{"t":3,"n":"Target Lum Max Mult"},{"t":3,"n":"Target Lum Max Add"},{"t":3,"n":"Sunlight Scale Mult"},{"t":3,"n":"Sunlight Scale Add"},{"t":3,"n":"Sky Scale Mult"},{"t":3,"n":"Sky Scale Add"}]},{"t":3,"n":"Unknown08 Mult"},{"t":3,"n":"Unknown48 Add"},{"t":3,"n":"Unknown09 Mult"},{"t":3,"n":"Unknown49 Add"},{"t":3,"n":"Unknown0A Mult"},{"t":3,"n":"Unknown4A Add"},{"t":3,"n":"Unknown0B Mult"},{"t":3,"n":"Unknown4B Add"},{"t":3,"n":"Unknown0C Mult"},{"t":3,"n":"Unknown4C Add"},{"t":3,"n":"Unknown0D Mult"},{"t":3,"n":"Unknown4D Add"},{"t":3,"n":"Unknown0E Mult"},{"t":3,"n":"Unknown4E Add"},{"t":3,"n":"Unknown0F Mult"},{"t":3,"n":"Unknown4F Add"},{"t":3,"n":"Unknown10 Mult"},{"t":3,"n":"Unknown50 Add"},{"t":6,"n":"Cinematic","c":[{"t":3,"n":"Saturation Mult"},{"t":3,"n":"Saturation Add"},{"t":3,"n":"Brightness Mult"},{"t":3,"n":"Brightness Add"},{"t":3,"n":"Contrast Mult"},{"t":3,"n":"Contrast Add"}]},{"t":3,"n":"Unknown14 Mult"},{"t":3,"n":"Unknown54 Add"},{"t":3,"n":"Tint Color"},{"t":3,"n":"Blur Radius"},{"t":3,"n":"Double Vision Strength"},{"t":3,"n":"Radial Blur Strength"},{"t":3,"n":"Radial Blur Ramp Up"},{"t":3,"n":"Radial Blur Start"},{"t":3,"n":"Radial Blur Flags"},{"t":5,"n":"Radial Blur Center X"},{"t":5,"n":"Radial Blur Center Y"},{"t":3,"n":"DoF Strength"},{"t":3,"n":"DoF Distance"},{"t":3,"n":"DoF Range"},{"t":3,"n":"DoF Flags"},{"t":3,"n":"Radial Blur Ramp Down"},{"t":3,"n":"Radial Blur Down Start"},{"t":3,"n":"Fade Color"},{"t":3,"n":"Motion Blur Strength"}]},{"t":7,"p":1,"n":"BNAM - Blur Radius","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"VNAM - Double Vision Strength","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"TNAM - Tint Color","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"},{"t":5,"p":1,"n":"Alpha"}]}]},{"t":7,"p":1,"n":"NAM3 - Fade Color","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"},{"t":5,"p":1,"n":"Alpha"}]}]},{"t":7,"p":1,"n":"RNAM - Radial Blur Strength","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"SNAM - Radial Blur Ramp Up","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"UNAM - Radial Blur Start","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"NAM1 - Radial Blur Ramp Down","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"NAM2 - Radial Blur Down Start","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"WNAM - DoF Strength","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"XNAM - DoF Distance","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"YNAM - DoF Range","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"NAM4 - Motion Blur Strength","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":6,"s":1,"p":1,"n":"HDR","c":[{"t":7,"p":1,"n":"aIAD - Eye Adapt Speed Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"@IAD - Eye Adapt Speed Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"bIAD - Bloom Blur Radius Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"AIAD - Bloom Blur Radius Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"cIAD - Bloom Threshold Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"BIAD - Bloom Threshold Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"dIAD - Bloom Scale Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"CIAD - Bloom Scale Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"eIAD - Target Lum Min Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"DIAD - Target Lum Min Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"fIAD - Target Lum Max Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"EIAD - Target Lum Max Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"gIAD - Sunlight Scale Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"FIAD - Sunlight Scale Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"hIAD - Sky Scale Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"GIAD - Sky Scale Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]}]},{"t":11,"n":"iIAD - Unknown"},{"t":11,"n":"HIAD - Unknown"},{"t":11,"n":"jIAD - Unknown"},{"t":11,"n":"IIAD - Unknown"},{"t":11,"n":"kIAD - Unknown"},{"t":11,"n":"JIAD - Unknown"},{"t":11,"n":"lIAD - Unknown"},{"t":11,"n":"KIAD - Unknown"},{"t":11,"n":"mIAD - Unknown"},{"t":11,"n":"LIAD - Unknown"},{"t":11,"n":"nIAD - Unknown"},{"t":11,"n":"MIAD - Unknown"},{"t":11,"n":"oIAD - Unknown"},{"t":11,"n":"NIAD - Unknown"},{"t":11,"n":"pIAD - Unknown"},{"t":11,"n":"OIAD - Unknown"},{"t":11,"n":"qIAD - Unknown"},{"t":11,"n":"PIAD - Unknown"},{"t":6,"s":1,"p":1,"n":"Cinematic","c":[{"t":7,"p":1,"n":"rIAD - Saturation Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"QIAD - Saturation Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"sIAD - Brightness Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"RIAD - Brightness Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"tIAD - Contrast Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"SIAD - Contrast Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]}]},{"t":11,"n":"uIAD - Unknown"},{"t":11,"n":"TIAD - Unknown"}]},{"t":1,"p":1,"n":"IMGS - Image Space","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":11,"n":"ENAM - Unknown"},{"t":6,"s":1,"p":1,"n":"HNAM - HDR","c":[{"t":5,"p":1,"n":"Eye Adapt Speed"},{"t":5,"p":1,"n":"Bloom Blur Radius"},{"t":5,"p":1,"n":"Bloom Threshold"},{"t":5,"p":1,"n":"Bloom Scale"},{"t":5,"p":1,"n":"Receive Bloom Threshold"},{"t":5,"p":1,"n":"White"},{"t":5,"p":1,"n":"Sunlight Scale"},{"t":5,"p":1,"n":"Sky Scale"},{"t":5,"p":1,"n":"Eye Adapt Strength"}]},{"t":6,"s":1,"p":1,"n":"CNAM - Cinematic","c":[{"t":5,"p":1,"n":"Saturation"},{"t":5,"p":1,"n":"Brightness"},{"t":5,"p":1,"n":"Contrast"}]},{"t":6,"s":1,"p":1,"n":"TNAM - Tint","c":[{"t":5,"p":1,"n":"Amount"},{"t":6,"p":1,"n":"Color","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}]}]},{"t":6,"s":1,"p":1,"n":"DNAM - Depth of Field","c":[{"t":5,"p":1,"n":"Strength"},{"t":5,"p":1,"n":"Distance"},{"t":5,"p":1,"n":"Range"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Sky \/ Blur Radius"}]}]},{"t":1,"p":1,"n":"INFO - Dialog response","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]},{"t":6,"p":1,"n":"Script Fragments","c":[{"t":3,"n":"Unknown"},{"t":3,"p":1,"n":"Flags"},{"t":2,"p":1,"n":"fileName"},{"t":7,"p":1,"n":"Fragments","c":[{"t":6,"p":1,"n":"Fragment","c":[{"t":3,"n":"Unknown"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]}]}]},{"t":11,"n":"DATA - Unknown"},{"t":6,"s":1,"p":1,"n":"ENAM - Response flags","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Reset Hours"}]},{"t":3,"p":1,"n":"TPIC - Topic"},{"t":3,"p":1,"n":"PNAM - Previous INFO"},{"t":3,"p":1,"n":"CNAM - Favor Level"},{"t":8,"s":1,"p":1,"n":"Link To","d":1,"c":[{"t":3,"p":1,"n":"TCLT - Response"}]},{"t":3,"p":1,"n":"DNAM - Response Data"},{"t":8,"s":1,"p":1,"n":"Responses","d":1,"c":[{"t":6,"p":1,"n":"Response","c":[{"t":6,"p":1,"n":"TRDT - Response Data","c":[{"t":3,"p":1,"n":"Emotion Type"},{"t":3,"p":1,"n":"Emotion Value"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Response number"},{"t":3,"p":1,"n":"Sound"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"NAM1 - Response Text"},{"t":2,"p":1,"n":"NAM2 - Script Notes"},{"t":2,"p":1,"n":"NAM3 - Edits"},{"t":3,"p":1,"n":"SNAM - Idle Animations: Speaker"},{"t":3,"p":1,"n":"LNAM - Idle Animations: Listener"}]}]},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":8,"n":"Unknown","c":[{"t":6,"n":"Unknown","c":[{"t":11,"n":"SCHR - Unknown"},{"t":3,"n":"QNAM - Unknown"},{"n":"NEXT - Marker"}]}]},{"t":2,"p":1,"n":"RNAM - Prompt"},{"t":3,"p":1,"n":"ANAM - Speaker"},{"t":3,"p":1,"n":"TWAT - Walk Away Topic"},{"t":3,"p":1,"n":"ONAM - Audio Output Override"}]},{"t":1,"p":1,"n":"INGR - Ingredient","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"ETYP - Equipment Type"},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":6,"s":1,"p":1,"n":"ENIT - Effect Data","c":[{"t":3,"p":1,"n":"Ingredient Value"},{"t":3,"p":1,"n":"Flags"}]},{"t":8,"s":1,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":3,"p":1,"n":"EFID - Base Effect"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":5,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"}]},{"t":8,"s":1,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]}]},{"t":1,"p":1,"n":"IPCT - Impact","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":5,"p":1,"n":"Effect - Duration"},{"t":3,"p":1,"n":"Effect - Orientation"},{"t":5,"p":1,"n":"Angle Threshold"},{"t":5,"p":1,"n":"Placement Radius"},{"t":3,"p":1,"n":"Sound Level"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Impact Result"},{"t":11,"n":"Unknown"}]},{"t":6,"s":1,"p":1,"n":"DODT - Decal Data","c":[{"t":5,"p":1,"n":"Min Width"},{"t":5,"p":1,"n":"Max Width"},{"t":5,"p":1,"n":"Min Height"},{"t":5,"p":1,"n":"Max Height"},{"t":5,"p":1,"n":"Depth"},{"t":5,"p":1,"n":"Shininess"},{"t":6,"p":1,"n":"Parallax","c":[{"t":5,"p":1,"n":"Scale"},{"t":3,"p":1,"n":"Passes"}]},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"},{"t":6,"p":1,"n":"Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":3,"p":1,"n":"DNAM - Texture Set"},{"t":3,"p":1,"n":"ENAM - Secondary Texture Set"},{"t":3,"p":1,"n":"SNAM - Sound 1"},{"t":3,"p":1,"n":"NAM1 - Sound 2"},{"t":3,"p":1,"n":"NAM2 - Hazard"}]},{"t":1,"p":1,"n":"IPDS - Impact Data Set","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":8,"s":1,"p":1,"n":"Data","d":1,"c":[{"t":6,"p":1,"n":"PNAM - ","c":[{"t":3,"p":1,"n":"Material"},{"t":3,"p":1,"n":"Impact"}]}]}]},{"t":1,"p":1,"n":"KEYM - Key","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]}]},{"t":1,"p":1,"n":"KYWD - Keyword","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"CNAM - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":1,"p":1,"n":"LAND - Landscape","d":1,"c":[{"t":11,"n":"DATA - Unknown"},{"t":11,"n":"VNML - Vertex Normals"},{"t":11,"n":"VHGT - Vertext Height Map"},{"t":11,"n":"VCLR - Vertex Colours"},{"t":8,"s":1,"p":1,"n":"Layers","d":1,"c":[{"t":6,"p":1,"n":"Base Layer","c":[{"t":6,"p":1,"n":"BTXT - Base Layer Header","c":[{"t":3,"p":1,"n":"Texture"},{"t":3,"p":1,"n":"Quadrant"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Layer"}]}]},{"t":6,"p":1,"n":"Alpha Layer","c":[{"t":6,"p":1,"n":"ATXT - Alpha Layer Header","c":[{"t":3,"p":1,"n":"Texture"},{"t":3,"p":1,"n":"Quadrant"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Layer"}]},{"t":11,"p":1,"n":"VTXT - Alpha Layer Data"}]}]},{"t":7,"p":1,"n":"VTEX - Textures","c":[{"t":3,"p":1,"n":"Texture"}]}]},{"t":1,"p":1,"n":"LCRT - Location Reference Type","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"CNAM - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":1,"n":"LCTN - Location","c":[{"t":2,"n":"EDID - Editor ID"},{"t":7,"n":"ACPR - Actor Cell Persistent Reference","c":[{"t":6,"n":"","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Location"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":7,"n":"LCPR - Location Cell Persistent Reference","c":[{"t":6,"n":"","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Location"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":7,"n":"RCPR - Reference Cell Persistent Reference","c":[{"t":3,"n":"Ref"}]},{"t":7,"n":"ACUN - Actor Cell Unique","c":[{"t":6,"n":"","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Ref"},{"t":3,"n":"Location"}]}]},{"t":7,"n":"LCUN - Location Cell Unique","c":[{"t":6,"n":"","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Ref"},{"t":3,"n":"Location"}]}]},{"t":7,"n":"RCUN - Reference Cell Unique","c":[{"t":3,"n":"Actor"}]},{"t":7,"n":"ACSR - Actor Cell Static Reference","c":[{"t":6,"n":"","c":[{"t":3,"n":"Loc Ref Type"},{"t":3,"n":"Marker"},{"t":3,"n":"Location"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":7,"n":"LCSR - Location Cell Static Reference","c":[{"t":6,"n":"","c":[{"t":3,"n":"Loc Ref Type"},{"t":3,"n":"Marker"},{"t":3,"n":"Location"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":7,"n":"RCSR - Reference Cell Static Reference","c":[{"t":3,"n":"Ref"}]},{"t":8,"n":"Actor Cell Encounter Cell","c":[{"t":6,"n":"ACEC - Unknown","c":[{"t":3,"n":"Location"},{"t":7,"n":"Coordinates","c":[{"t":6,"n":"","c":[{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]}]}]},{"t":8,"n":"Location Cell Encounter Cell","c":[{"t":6,"n":"LCEC - Unknown","c":[{"t":3,"n":"Location"},{"t":7,"n":"Coordinates","c":[{"t":6,"n":"","c":[{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]}]}]},{"t":8,"n":"Reference Cell Encounter Cell","c":[{"t":6,"n":"RCEC - Unknown","c":[{"t":3,"n":"Location"},{"t":7,"n":"Coordinates","c":[{"t":6,"n":"","c":[{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]}]}]},{"t":7,"n":"ACID - Actor Cell Marker Reference","c":[{"t":3,"n":"Ref"}]},{"t":7,"n":"LCID - Location Cell Marker Reference","c":[{"t":3,"n":"Ref"}]},{"t":7,"n":"ACEP - Actor Cell Enable Point","c":[{"t":6,"n":"","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Ref"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":7,"n":"LCEP - Location Cell Enable Point","c":[{"t":6,"n":"","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Ref"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":2,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":3,"n":"PNAM - Parent Location"},{"t":3,"n":"NAM1 - Music"},{"t":3,"n":"FNAM - Unreported Crime Faction"},{"t":3,"n":"MNAM - World Location Marker Ref"},{"t":5,"n":"RNAM - World Location Radius"},{"t":3,"n":"NAM0 - Horse Marker Ref"},{"t":6,"n":"CNAM - Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":1,"p":1,"n":"LENS - Lens Flare","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":5,"p":1,"n":"CNAM - Color Influence"},{"t":5,"p":1,"n":"DNAM - Fade Distance Radius Scale"},{"t":3,"n":"LFSP - Count"},{"t":8,"s":1,"p":1,"n":"Lens Flare Sprites","d":1,"c":[{"t":6,"p":1,"n":"Flare","c":[{"t":2,"p":1,"n":"DNAM - Lens Flare Sprite ID"},{"t":2,"p":1,"n":"FNAM - Texture"},{"t":6,"p":1,"n":"LFSD - Lens Flare Data","c":[{"t":6,"p":1,"n":"Tint","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}]},{"t":5,"p":1,"n":"Width"},{"t":5,"p":1,"n":"Height"},{"t":5,"p":1,"n":"Position"},{"t":5,"p":1,"n":"Angular Fade"},{"t":5,"p":1,"n":"Opacity"},{"t":3,"p":1,"n":"Flags"}]}]}]}]},{"t":1,"p":1,"n":"LGTM - Lighting Template","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - Lighting","c":[{"t":6,"p":1,"n":"Ambient Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Directional Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Fog Color Near","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Fog Near"},{"t":5,"p":1,"n":"Fog Far"},{"t":3,"p":1,"n":"Directional Rotation XY"},{"t":3,"p":1,"n":"Directional Rotation Z"},{"t":5,"p":1,"n":"Directional Fade"},{"t":5,"p":1,"n":"Fog Clip Dist"},{"t":5,"p":1,"n":"Fog Power"},{"t":6,"p":1,"n":"Ambient Colors","c":[{"t":6,"p":1,"n":"Directional","c":[{"t":6,"p":1,"n":"X+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"X-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Specular","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Scale"}]},{"t":6,"p":1,"n":"Fog Color Far","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Fog Max"},{"t":6,"p":1,"n":"Light Fade Distances","c":[{"t":5,"p":1,"n":"Start"},{"t":5,"p":1,"n":"End"}]},{"t":11,"n":"Unknown"}]},{"t":6,"s":1,"p":1,"n":"DALC - Directional Ambient Lighting Colors","c":[{"t":6,"p":1,"n":"Directional","c":[{"t":6,"p":1,"n":"X+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"X-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Specular","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Scale"}]}]},{"t":1,"p":1,"n":"LIGH - Light","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Time"},{"t":3,"p":1,"n":"Radius"},{"t":6,"p":1,"n":"Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Falloff Exponent"},{"t":5,"p":1,"n":"FOV"},{"t":5,"p":1,"n":"Near Clip"},{"t":6,"p":1,"n":"Flicker Effect","c":[{"t":5,"p":1,"n":"Period"},{"t":5,"p":1,"n":"Intensity Amplitude"},{"t":5,"p":1,"n":"Movement Amplitude"}]},{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":5,"p":1,"n":"FNAM - Fade value"},{"t":3,"p":1,"n":"SNAM - Sound"}]},{"t":1,"p":1,"n":"LSCR - Load Screen","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":2,"p":1,"n":"DESC - Description"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":3,"p":1,"n":"NNAM - Loading Screen NIF"},{"t":5,"p":1,"n":"SNAM - Initial Scale"},{"t":6,"s":1,"p":1,"n":"RNAM - Initial Rotation","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"},{"t":3,"p":1,"n":"Z"}]},{"t":6,"s":1,"p":1,"n":"ONAM - Rotation Offset Constraints","c":[{"t":3,"p":1,"n":"Min"},{"t":3,"p":1,"n":"Max"}]},{"t":6,"s":1,"p":1,"n":"XNAM - Initial Translation Offset","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":2,"p":1,"n":"MOD2 - Camera Path"}]},{"t":1,"p":1,"n":"LTEX - Landscape Texture","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"TNAM - Texture Set"},{"t":3,"p":1,"n":"MNAM - Material Type"},{"t":6,"s":1,"p":1,"n":"HNAM - Havok Data","c":[{"t":3,"p":1,"n":"Friction"},{"t":3,"p":1,"n":"Restitution"}]},{"t":3,"p":1,"n":"SNAM - Texture Specular Exponent"},{"t":8,"s":1,"p":1,"n":"Grasses","d":1,"c":[{"t":3,"p":1,"n":"GNAM - Grass"}]},{"t":3,"n":"INAM - Unused"}]},{"t":1,"p":1,"n":"LVLI - Leveled Item","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"LVLD - Chance None"},{"t":3,"p":1,"n":"LVLF - Flags"},{"t":3,"p":1,"n":"LVLG - Global"},{"t":3,"n":"LLCT - Count"},{"t":10,"p":1,"n":"Leveled List Entries","d":1,"c":[{"t":6,"p":1,"n":"Leveled List Entry","c":[{"t":6,"p":1,"n":"LVLO - Base Data","c":[{"t":3,"p":1,"n":"Level"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Count"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]}]},{"t":1,"p":1,"n":"LVLN - Leveled NPC","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"LVLD - Chance None"},{"t":3,"p":1,"n":"LVLF - Flags"},{"t":3,"p":1,"n":"LVLG - Global"},{"t":3,"n":"LLCT - Count"},{"t":10,"p":1,"n":"Leveled List Entries","d":1,"c":[{"t":6,"p":1,"n":"Leveled List Entry","c":[{"t":6,"p":1,"n":"LVLO - Base Data","c":[{"t":3,"p":1,"n":"Level"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Count"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]}]},{"t":1,"p":1,"n":"LVSP - Leveled Spell","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"LVLD - Chance None"},{"t":3,"p":1,"n":"LVLF - Flags"},{"t":3,"n":"LLCT - Count"},{"t":10,"p":1,"n":"Leveled List Entries","d":1,"c":[{"t":6,"p":1,"n":"Leveled List Entry","c":[{"t":6,"p":1,"n":"LVLO - Base Data","c":[{"t":3,"p":1,"n":"Level"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Count"}]}]}]}]},{"t":1,"p":1,"n":"MATO - Material Object","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":8,"s":1,"p":1,"n":"Property Data","d":1,"c":[{"t":11,"p":1,"n":"DNAM - Data"}]},{"t":6,"s":1,"p":1,"n":"DATA - Directional Material Data","c":[{"t":5,"p":1,"n":"Falloff Scale"},{"t":5,"p":1,"n":"Falloff Bias"},{"t":5,"p":1,"n":"Noise UV Scale"},{"t":5,"p":1,"n":"Material UV Scale"},{"t":6,"p":1,"n":"Projection Vector","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":5,"p":1,"n":"Normal Dampener"},{"t":6,"p":1,"n":"Single Pass Color","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}]},{"t":3,"p":1,"n":"Flags"}]}]},{"t":1,"p":1,"n":"MATT - Material Type","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"PNAM - Material Parent"},{"t":2,"p":1,"n":"MNAM - Material Name"},{"t":6,"s":1,"p":1,"n":"CNAM - Havok Display Color","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}]},{"t":5,"p":1,"n":"BNAM - Buoyancy"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":3,"p":1,"n":"HNAM - Havok Impact Data Set"}]},{"t":1,"p":1,"n":"MESG - Message","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"DESC - Description"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"INAM - Icon (unused)"},{"t":3,"p":1,"n":"QNAM - Owner Quest"},{"t":3,"p":1,"n":"DNAM - Flags"},{"t":3,"p":1,"n":"TNAM - Display Time"},{"t":8,"s":1,"p":1,"n":"Menu Buttons","d":1,"c":[{"t":6,"p":1,"n":"Menu Button","c":[{"t":2,"p":1,"n":"ITXT - Button Text"},{"t":8,"s":1,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]}]},{"t":1,"p":1,"n":"MGEF - Magic Effect","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"MDOB - Menu Display Object"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"Magic Effect Data","c":[{"t":6,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Base Cost"},{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Assoc. Item"},{"t":3,"p":1,"n":"Magic Skill"},{"t":3,"p":1,"n":"Resist Value"},{"t":3,"p":1,"n":"Counter Effect count"},{"t":3,"p":1,"n":"Casting Light"},{"t":5,"p":1,"n":"Taper Weight"},{"t":3,"p":1,"n":"Hit Shader"},{"t":3,"p":1,"n":"Enchant Shader"},{"t":3,"p":1,"n":"Minimum Skill Level"},{"t":6,"p":1,"n":"Spellmaking","c":[{"t":3,"p":1,"n":"Area"},{"t":5,"p":1,"n":"Casting Time"}]},{"t":5,"p":1,"n":"Taper Curve"},{"t":5,"p":1,"n":"Taper Duration"},{"t":5,"p":1,"n":"Second AV Weight"},{"t":3,"p":1,"n":"Archtype"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Projectile"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Delivery"},{"t":3,"p":1,"n":"Second Actor Value"},{"t":3,"p":1,"n":"Casting Art"},{"t":3,"p":1,"n":"Hit Effect Art"},{"t":3,"p":1,"n":"Impact Data"},{"t":5,"p":1,"n":"Skill Usage Multiplier"},{"t":6,"p":1,"n":"Dual Casting","c":[{"t":3,"p":1,"n":"Art"},{"t":5,"p":1,"n":"Scale"}]},{"t":3,"p":1,"n":"Enchant Art"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Equip Ability"},{"t":3,"p":1,"n":"Image Space Modifier"},{"t":3,"p":1,"n":"Perk to Apply"},{"t":3,"p":1,"n":"Casting Sound Level"},{"t":6,"p":1,"n":"Script Effect AI","c":[{"t":5,"p":1,"n":"Score"},{"t":5,"p":1,"n":"Delay Time"}]}]}]},{"t":8,"s":1,"p":1,"n":"Counter Effects","d":1,"c":[{"t":3,"n":"ESCE - Effect"}]},{"t":7,"p":1,"n":"SNDD - Sounds","c":[{"t":6,"p":1,"n":"","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Sound"}]}]},{"t":2,"p":1,"n":"DNAM - Magic Item Description"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]},{"t":1,"p":1,"n":"MISC - Misc. Item","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]}]},{"t":1,"p":1,"n":"MOVT - Movement Type","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"MNAM - Name"},{"t":6,"s":1,"p":1,"n":"SPED - Default Data","c":[{"t":5,"p":1,"n":"Left Walk"},{"t":5,"p":1,"n":"Left Run"},{"t":5,"p":1,"n":"Right Walk"},{"t":5,"p":1,"n":"Right Run"},{"t":5,"p":1,"n":"Forward Walk"},{"t":5,"p":1,"n":"Forward Run"},{"t":5,"p":1,"n":"Back Walk"},{"t":5,"p":1,"n":"Back Run"},{"t":5,"p":1,"n":"Rotate in Place Walk"},{"t":5,"p":1,"n":"Rotate in Place Run"},{"t":5,"p":1,"n":"Rotate while Moving Run"}]},{"t":6,"s":1,"p":1,"n":"INAM - Anim Change Thresholds","c":[{"t":5,"p":1,"n":"Directional"},{"t":5,"p":1,"n":"Movement Speed"},{"t":5,"p":1,"n":"Rotation Speed"}]}]},{"t":1,"p":1,"n":"MSTT - Moveable Static","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"DATA - Flags"},{"t":3,"p":1,"n":"SNAM - Looping Sound"}]},{"t":1,"p":1,"n":"MUSC - Music Type","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":6,"s":1,"p":1,"n":"PNAM - Data","c":[{"t":3,"p":1,"n":"Priority"},{"t":3,"p":1,"n":"Ducking (dB)"}]},{"t":5,"p":1,"n":"WNAM - Fade Duration"},{"t":7,"p":1,"n":"TNAM - Music Tracks","c":[{"t":3,"p":1,"n":"Track"}]}]},{"t":1,"p":1,"n":"MUST - Music Track","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"CNAM - Track Type"},{"t":5,"p":1,"n":"FLTV - Duration"},{"t":5,"p":1,"n":"DNAM - Fade-Out"},{"t":2,"p":1,"n":"ANAM - Track Filename"},{"t":2,"p":1,"n":"BNAM - Finale Filename"},{"t":7,"p":1,"n":"FNAM - Cue Points","c":[{"t":5,"p":1,"n":"Point"}]},{"t":6,"s":1,"p":1,"n":"LNAM - Loop Data","c":[{"t":5,"p":1,"n":"Loop Begins"},{"t":5,"p":1,"n":"Loop Ends"},{"t":3,"p":1,"n":"Loop Count"}]},{"t":3,"n":"CITC - Condition Count"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":7,"p":1,"n":"SNAM - Tracks","c":[{"t":3,"p":1,"n":"Track"}]}]},{"t":1,"n":"NAVI - Navigation Mesh Info Map","c":[{"t":2,"n":"EDID - Editor ID"},{"t":3,"n":"NVER - Version"},{"t":8,"n":"Navigation Map Infos","c":[{"t":6,"n":"NVMI - Navigation Map Info","c":[{"t":3,"n":"Navigation Mesh"},{"t":11,"n":"Unknown"},{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"},{"t":3,"n":"Preferred Merges Flag"},{"t":7,"n":"Merged To","c":[{"t":3,"n":"Mesh"}]},{"t":7,"n":"Preferred Merges","c":[{"t":3,"n":"Mesh"}]},{"t":7,"n":"Linked Doors","c":[{"t":6,"n":"Door","c":[{"t":11,"n":"Unknown"},{"t":3,"n":"Door Ref"}]}]},{"t":3,"n":"Is Island"},{"t":11,"n":"Unused"},{"t":6,"n":"Island Data","c":[{"t":11,"n":"Unknown"},{"t":7,"n":"Triangles","c":[{"t":11,"n":"Triangle"}]},{"t":7,"n":"Vertices","c":[{"t":11,"n":"Vertex"}]}]},{"t":3,"n":"Parent Worldspace"},{"t":6,"n":"Coordinates","c":[{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]},{"t":3,"n":"Parent Cell"}]}]},{"t":6,"n":"NVPP - Preferred Pathing","c":[{"t":7,"n":"NavMeshes","c":[{"t":7,"n":"Set","c":[{"t":3,"n":""}]}]},{"t":7,"n":"NavMesh Tree?","c":[{"t":6,"n":"","c":[{"t":3,"n":"NavMesh"},{"t":3,"n":"Index\/Node"}]}]}]},{"t":7,"n":"NVSI - Unknown","c":[{"t":3,"n":"Navigation Mesh"}]}]},{"t":1,"n":"NAVM - Navigation Mesh","c":[{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"NVNM - Geometry","c":[{"t":11,"n":"Unknown"},{"t":3,"n":"Parent Worldspace"},{"t":6,"n":"Coordinates","c":[{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]},{"t":3,"n":"Parent Cell"},{"t":7,"n":"Vertices","c":[{"t":11,"n":"Vertex"}]},{"t":7,"n":"Triangles","c":[{"t":11,"n":"Triangle"}]},{"t":7,"n":"External Connections","c":[{"t":6,"n":"Connection","c":[{"t":11,"n":"Unknown"},{"t":3,"n":"Mesh"},{"t":3,"n":"Triangle"}]}]},{"t":7,"n":"Door Triangles","c":[{"t":6,"n":"Door Triangle","c":[{"t":3,"n":"Triangle before door"},{"t":11,"n":"Unknown"},{"t":3,"n":"Door"}]}]}]},{"t":11,"n":"ONAM - Unknown"},{"t":11,"n":"PNAM - Unknown"},{"t":11,"n":"NNAM - Unknown"}]},{"t":1,"p":1,"n":"NPC_ - Non-Player Character (Actor)","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"ACBS - Configuration","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Magicka Offset"},{"t":3,"p":1,"n":"Stamina Offset"},{"t":3,"p":1,"n":"Level"},{"t":3,"p":1,"n":"Level Mult"},{"t":3,"p":1,"n":"Calc min level"},{"t":3,"p":1,"n":"Calc max level"},{"t":3,"p":1,"n":"Speed Multiplier"},{"t":3,"p":1,"n":"Disposition Base (unused)"},{"t":3,"p":1,"n":"Template Flags"},{"t":3,"p":1,"n":"Health Offset"},{"t":3,"p":1,"n":"Bleedout Override"}]},{"t":8,"s":1,"p":1,"n":"Factions","d":1,"c":[{"t":6,"p":1,"n":"SNAM - Faction","c":[{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"p":1,"n":"INAM - Death item"},{"t":3,"p":1,"n":"VTCK - Voice"},{"t":3,"p":1,"n":"TPLT - Template"},{"t":3,"p":1,"n":"RNAM - Race","lt":"Tint Layers","lf":"NAM7 - Weight"},{"t":3,"n":"SPCT - Count"},{"t":8,"s":1,"p":1,"n":"Actor Effects","d":1,"c":[{"t":3,"p":1,"n":"SPLO - Actor Effect"}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"WNAM - Worn Armor"},{"t":3,"p":1,"n":"ANAM - Far away model"},{"t":3,"p":1,"n":"ATKR - Attack Race"},{"t":10,"p":1,"n":"Attacks","d":1,"c":[{"t":6,"p":1,"n":"Attack","c":[{"t":6,"p":1,"n":"ATKD - Attack Data","c":[{"t":5,"p":1,"n":"Damage Mult"},{"t":5,"p":1,"n":"Attack Chance"},{"t":3,"p":1,"n":"Attack Spell"},{"t":3,"p":1,"n":"Attack Flags"},{"t":5,"p":1,"n":"Attack Angle"},{"t":5,"p":1,"n":"Strike Angle"},{"t":5,"p":1,"n":"Stagger"},{"t":3,"p":1,"n":"Attack Type"},{"t":5,"p":1,"n":"Knockdown"},{"t":5,"p":1,"n":"Recovery Time"},{"t":5,"p":1,"n":"Stamina Mult"}]},{"t":2,"p":1,"n":"ATKE - Attack Event"}]}]},{"t":3,"p":1,"n":"SPOR - Spectator override package list"},{"t":3,"p":1,"n":"OCOR - Observe dead body override package list"},{"t":3,"p":1,"n":"GWOR - Guard warn override package list"},{"t":3,"p":1,"n":"ECOR - Combat override package list"},{"t":3,"n":"PRKZ - Perk Count"},{"t":8,"s":1,"p":1,"n":"Perks","d":1,"c":[{"t":6,"p":1,"n":"PRKR - Perk","c":[{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"COCT - Count"},{"t":10,"p":1,"n":"Items","d":1,"c":[{"t":6,"p":1,"n":"Item","c":[{"t":6,"p":1,"n":"CNTO - Item","c":[{"t":3,"p":1,"n":"Item"},{"t":3,"p":1,"n":"Count"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]},{"t":6,"s":1,"p":1,"n":"AIDT - AI Data","c":[{"t":3,"p":1,"n":"Aggression"},{"t":3,"p":1,"n":"Confidence"},{"t":3,"p":1,"n":"Energy Level"},{"t":3,"p":1,"n":"Responsibility"},{"t":3,"p":1,"n":"Mood"},{"t":3,"p":1,"n":"Assistance"},{"t":6,"p":1,"n":"Aggro","c":[{"t":3,"p":1,"n":"Aggro Radius Behavior"},{"t":3,"n":"Unknown"},{"t":3,"p":1,"n":"Warn"},{"t":3,"p":1,"n":"Warn\/Attack"},{"t":3,"p":1,"n":"Attack"}]}]},{"t":8,"s":1,"p":1,"n":"Packages","d":1,"c":[{"t":3,"p":1,"n":"PKID - Package"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":3,"p":1,"n":"CNAM - Class"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"SHRT - Short Name"},{"t":11,"n":"DATA - Marker"},{"t":6,"s":1,"p":1,"n":"DNAM - Player Skills","c":[{"t":7,"p":1,"n":"Skill Values","c":[{"t":3,"p":1,"n":"Skill"}]},{"t":7,"p":1,"n":"Skill Offsets","c":[{"t":3,"p":1,"n":"Skill"}]},{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Magicka"},{"t":3,"p":1,"n":"Stamina"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Far away model distance"},{"t":3,"p":1,"n":"Geared up weapons"}]},{"t":8,"s":1,"p":1,"n":"Head Parts","d":1,"c":[{"t":3,"p":1,"n":"PNAM - Head Part"}],"lt":"NAM6 - Height","lf":"HCLF - Hair Color"},{"t":3,"p":1,"n":"HCLF - Hair Color","lt":"Head Parts","lf":"FTST - Head texture"},{"t":3,"p":1,"n":"ZNAM - Combat Style"},{"t":3,"p":1,"n":"GNAM - Gift Filter"},{"t":11,"n":"NAM5 - Unknown"},{"t":5,"p":1,"n":"NAM6 - Height","lt":"NAM7 - Weight","lf":"Head Parts"},{"t":5,"p":1,"n":"NAM7 - Weight","lt":"RNAM - Race","lf":"NAM6 - Height"},{"t":3,"p":1,"n":"NAM8 - Sound Level"},{"t":10,"p":1,"n":"Sound Types","d":1,"c":[{"t":6,"p":1,"n":"Sound Type","c":[{"t":3,"p":1,"n":"CSDT - Type"},{"t":10,"p":1,"n":"Sounds","c":[{"t":6,"p":1,"n":"Sound","c":[{"t":3,"p":1,"n":"CSDI - Sound"},{"t":3,"p":1,"n":"CSDC - Sound Chance"}]}]}]}]},{"t":3,"p":1,"n":"CSCR - Inherits Sounds From"},{"t":3,"p":1,"n":"DOFT - Default outfit"},{"t":3,"p":1,"n":"SOFT - Sleeping outfit"},{"t":3,"p":1,"n":"DPLT - Default Package List"},{"t":3,"p":1,"n":"CRIF - Crime faction"},{"t":3,"p":1,"n":"FTST - Head texture","lt":"HCLF - Hair Color","lf":"QNAM - Texture lighting"},{"t":6,"s":1,"p":1,"n":"QNAM - Texture lighting","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}],"lt":"FTST - Head texture","lf":"NAM9 - Face morph"},{"t":6,"s":1,"p":1,"n":"NAM9 - Face morph","c":[{"t":5,"p":1,"n":"Nose Long\/Short"},{"t":5,"p":1,"n":"Nose Up\/Down"},{"t":5,"p":1,"n":"Jaw Up\/Down"},{"t":5,"p":1,"n":"Jaw Narrow\/Wide"},{"t":5,"p":1,"n":"Jaw Farward\/Back"},{"t":5,"p":1,"n":"Cheeks Up\/Down"},{"t":5,"p":1,"n":"Cheeks Farward\/Back"},{"t":5,"p":1,"n":"Eyes Up\/Down"},{"t":5,"p":1,"n":"Eyes In\/Out"},{"t":5,"p":1,"n":"Brows Up\/Down"},{"t":5,"p":1,"n":"Brows In\/Out"},{"t":5,"p":1,"n":"Brows Farward\/Back"},{"t":5,"p":1,"n":"Lips Up\/Down"},{"t":5,"p":1,"n":"Lips In\/Out"},{"t":5,"p":1,"n":"Chin Narrow\/Wide"},{"t":5,"p":1,"n":"Chin Up\/Down"},{"t":5,"p":1,"n":"Chin Underbite\/Overbite"},{"t":5,"p":1,"n":"Eyes Farward\/Back"},{"t":5,"n":"Unknown"}],"lt":"QNAM - Texture lighting","lf":"NAMA - Face parts"},{"t":6,"s":1,"p":1,"n":"NAMA - Face parts","c":[{"t":3,"p":1,"n":"Nose"},{"t":3,"n":"Unknown"},{"t":3,"p":1,"n":"Eyes"},{"t":3,"p":1,"n":"Mouth"}],"lt":"NAM9 - Face morph","lf":"Tint Layers"},{"t":10,"p":1,"n":"Tint Layers","d":1,"c":[{"t":6,"p":1,"n":"Layer","c":[{"t":3,"p":1,"n":"TINI - Tint Index"},{"t":6,"p":1,"n":"TINC - Tint Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":3,"p":1,"n":"Alpha"}]},{"t":3,"p":1,"n":"TINV - Interpolation Value"},{"t":3,"p":1,"n":"TIAS - Preset"}]}],"lt":"NAMA - Face parts","lf":"RNAM - Race"}]},{"t":1,"p":1,"n":"OTFT - Outfit","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":7,"s":1,"p":1,"n":"INAM - Items","d":1,"c":[{"t":3,"p":1,"n":"Item"}]}]},{"t":1,"p":1,"n":"PACK - Package","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]},{"t":6,"p":1,"n":"Script Fragments","c":[{"t":3,"n":"Unknown"},{"t":3,"p":1,"n":"Flags"},{"t":2,"p":1,"n":"fileName"},{"t":7,"p":1,"n":"Fragments","c":[{"t":6,"p":1,"n":"Fragment","c":[{"t":3,"n":"Unknown"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]}]}]},{"t":6,"s":1,"p":1,"n":"PKDT - Pack Data","c":[{"t":3,"p":1,"n":"General Flags"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Interrupt Override"},{"t":3,"p":1,"n":"Preferred Speed"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Interrupt Flags"}]},{"t":6,"s":1,"p":1,"n":"PSDT - Schedule","c":[{"t":3,"p":1,"n":"Month"},{"t":3,"p":1,"n":"Day of week"},{"t":3,"p":1,"n":"Date"},{"t":3,"p":1,"n":"Hour"},{"t":3,"p":1,"n":"Minute"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Duration (minutes)"}]},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":6,"s":1,"p":1,"n":"Idle Animations","c":[{"t":3,"p":1,"n":"IDLF - Flags"},{"t":6,"p":1,"n":"IDLC - ","c":[{"t":3,"p":1,"n":"Animation Count"},{"t":11,"n":"Unknown"}]},{"t":5,"p":1,"n":"IDLT - Idle Timer Setting"},{"t":7,"p":1,"n":"IDLA - Animations","c":[{"t":3,"p":1,"n":"Animation"}]},{"t":11,"n":"IDLB - Unknown"}]},{"t":3,"p":1,"n":"CNAM - Combat Style"},{"t":3,"p":1,"n":"QNAM - Owner Quest"},{"t":6,"s":1,"p":1,"n":"PKCU - Counter","c":[{"t":3,"p":1,"n":"Data Input Count"},{"t":3,"p":1,"n":"Package Template"},{"t":3,"p":1,"n":"Version Counter (autoincremented)"}]},{"t":6,"s":1,"p":1,"n":"Package Data","c":[{"t":8,"p":1,"n":"Data Input Values","c":[{"t":6,"p":1,"n":"Value","c":[{"t":2,"p":1,"n":"ANAM - Type"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Bool"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"n":"BNAM - Unknown"},{"t":8,"p":1,"n":"Topic","c":[{"t":6,"p":1,"n":"PDTO - Topic Data","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Topic"},{"t":2,"p":1,"n":"Subtype"}]}]},{"t":6,"p":1,"n":"PLDT - Location","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Cell"},{"t":11,"p":1,"n":"Near Package Start Location"},{"t":11,"p":1,"n":"Near Editor Location"},{"t":3,"p":1,"n":"Object ID"},{"t":3,"p":1,"n":"Object Type"},{"t":3,"p":1,"n":"Keyword"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Radius"}]},{"t":6,"p":1,"n":"PTDA - Target","c":[{"t":6,"p":1,"n":"Target Data","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Object ID"},{"t":3,"p":1,"n":"Object Type"},{"t":3,"p":1,"n":"Alias"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Count \/ Distance"}]}]},{"t":11,"n":"TPIC - Unknown"}]}]},{"t":8,"p":1,"n":"Data Inputs","c":[{"t":6,"p":1,"n":"Data Input","c":[{"t":3,"p":1,"n":"UNAM - Index"},{"t":2,"p":1,"n":"BNAM - Name"},{"t":3,"p":1,"n":"PNAM - Flags"}]}]}]},{"t":11,"n":"XNAM - Marker"},{"t":6,"s":1,"p":1,"n":"Procedure Tree","c":[{"t":8,"p":1,"n":"Branches","c":[{"t":6,"p":1,"n":"Branch","c":[{"t":2,"p":1,"n":"ANAM - Branch Type"},{"t":3,"p":1,"n":"CITC - Condition Count"},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":6,"p":1,"n":"PRCB - Root","c":[{"t":3,"p":1,"n":"Branch Count"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"PNAM - Procedure Type"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":8,"p":1,"n":"Data Input Indexes","c":[{"t":3,"p":1,"n":"PKC2 - Index"}]},{"t":8,"p":1,"n":"Flags Override","c":[{"t":6,"p":1,"n":"PFO2 - Data","c":[{"t":3,"p":1,"n":"Set General Flags"},{"t":3,"p":1,"n":"Clear General Flags"},{"t":3,"p":1,"n":"Set Interrupt Flags"},{"t":3,"p":1,"n":"Clear Interrupt Flags"},{"t":3,"p":1,"n":"Preferred Speed Override"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Unknown","c":[{"t":11,"n":"PFOR - Unknown"}]}]}]}]},{"t":8,"s":1,"p":1,"n":"Data Inputs","d":1,"c":[{"t":6,"p":1,"n":"Data Input","c":[{"t":3,"p":1,"n":"UNAM - Index"},{"t":2,"p":1,"n":"BNAM - Name"},{"t":3,"p":1,"n":"PNAM - Flags"}]}]},{"t":6,"s":1,"p":1,"n":"OnBegin","c":[{"p":1,"n":"POBA - OnBegin Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":11,"n":"SCHR - Unused"},{"t":11,"n":"SCTX - Unused"},{"t":11,"n":"QNAM - Unused"},{"t":11,"n":"TNAM - Unused"},{"t":8,"p":1,"n":"Topic","c":[{"t":6,"p":1,"n":"PDTO - Topic Data","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Topic"},{"t":2,"p":1,"n":"Subtype"}]}]}]},{"t":6,"s":1,"p":1,"n":"OnEnd","c":[{"p":1,"n":"POEA - OnEnd Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":11,"n":"SCHR - Unused"},{"t":11,"n":"SCTX - Unused"},{"t":11,"n":"QNAM - Unused"},{"t":11,"n":"TNAM - Unused"},{"t":8,"p":1,"n":"Topic","c":[{"t":6,"p":1,"n":"PDTO - Topic Data","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Topic"},{"t":2,"p":1,"n":"Subtype"}]}]}]},{"t":6,"s":1,"p":1,"n":"OnChange","c":[{"p":1,"n":"POCA - OnChange Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":11,"n":"SCHR - Unused"},{"t":11,"n":"SCDA - Unused"},{"t":11,"n":"SCTX - Unused"},{"t":11,"n":"QNAM - Unused"},{"t":11,"n":"TNAM - Unused"},{"t":8,"p":1,"n":"Topic","c":[{"t":6,"p":1,"n":"PDTO - Topic Data","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Topic"},{"t":2,"p":1,"n":"Subtype"}]}]}]}]},{"t":1,"p":1,"n":"PARW - Placed Arrow","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Projectile"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"PBAR - Placed Barrier","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Projectile"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"PBEA - Placed Beam","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Projectile"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"PCON - Placed Cone\/Voice","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Projectile"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"PERK - Perk","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]},{"t":6,"p":1,"n":"Script Fragments","c":[{"t":3,"n":"Unknown"},{"t":2,"p":1,"n":"fileName"},{"t":7,"p":1,"n":"Fragments","c":[{"t":6,"p":1,"n":"Fragment","c":[{"t":3,"p":1,"n":"Fragment Index"},{"t":3,"n":"Unknown"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]}]}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Trait"},{"t":3,"p":1,"n":"Level"},{"t":3,"p":1,"n":"Num Ranks"},{"t":3,"p":1,"n":"Playable"},{"t":3,"p":1,"n":"Hidden"}]},{"t":3,"p":1,"n":"NNAM - Next Perk"},{"t":10,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":6,"p":1,"n":"PRKE - Header","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Rank"},{"t":3,"p":1,"n":"Priority"}]},{"t":6,"p":1,"n":"Quest + Stage","c":[{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"Ability"},{"t":6,"p":1,"n":"Entry Point","c":[{"t":3,"p":1,"n":"Entry Point"},{"t":3,"p":1,"n":"Function"},{"t":3,"p":1,"n":"Perk Condition Tab Count"}]},{"t":10,"p":1,"n":"Perk Conditions","c":[{"t":6,"p":1,"n":"Perk Condition","c":[{"t":3,"p":1,"n":"PRKC - Run On (Tab Index)"},{"t":8,"s":1,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"p":1,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]},{"t":6,"p":1,"n":"Function Parameters","c":[{"t":3,"p":1,"n":"EPFT - Type"},{"t":2,"p":1,"n":"EPF2 - Button Label"},{"t":6,"p":1,"n":"EPF3 - Script Flags","c":[{"t":3,"p":1,"n":"Script Flags"},{"t":11,"n":"Unknown"}]},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"Float"},{"t":6,"p":1,"n":"Float, Float","c":[{"t":5,"p":1,"n":"Float 1"},{"t":5,"p":1,"n":"Float 2"}]},{"t":3,"p":1,"n":"Leveled Item"},{"t":3,"p":1,"n":"Spell"},{"t":2,"p":1,"n":"Text"},{"t":6,"p":1,"n":"Actor Value, Float","c":[{"t":3,"p":1,"n":"Actor Value"},{"t":5,"p":1,"n":"Float"}]}]},{"p":1,"n":"PRKF - End Marker"}]}]}]},{"t":1,"p":1,"n":"PFLA - Placed Flame","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Projectile"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"PGRE - Placed Projectile","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Projectile"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"PHZD - Placed Hazard","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Projectile"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"PMIS - Placed Missile","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Projectile"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"PROJ - Projectile","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Type"},{"t":5,"p":1,"n":"Gravity"},{"t":5,"p":1,"n":"Speed"},{"t":5,"p":1,"n":"Range"},{"t":3,"p":1,"n":"Light"},{"t":3,"p":1,"n":"Muzzle Flash - Light"},{"t":5,"p":1,"n":"Tracer Chance"},{"t":5,"p":1,"n":"Explosion - Alt. Trigger - Proximity"},{"t":5,"p":1,"n":"Explosion - Alt. Trigger - Timer"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Sound"},{"t":5,"p":1,"n":"Muzzle Flash - Duration"},{"t":5,"p":1,"n":"Fade Duration"},{"t":5,"p":1,"n":"Impact Force"},{"t":3,"p":1,"n":"Sound - Countdown"},{"t":3,"p":1,"n":"Sound - Disable"},{"t":3,"p":1,"n":"Default Weapon Source"},{"t":5,"p":1,"n":"Cone Spread"},{"t":5,"p":1,"n":"Collision Radius"},{"t":5,"p":1,"n":"Lifetime"},{"t":5,"p":1,"n":"Relaunch Interval"},{"t":3,"p":1,"n":"Decal Data"},{"t":3,"p":1,"n":"Collision Layer"}]},{"t":6,"s":1,"p":1,"n":"Muzzle Flash Model","c":[{"t":2,"p":1,"n":"NAM1 - Model Filename"},{"t":11,"p":1,"n":"NAM2 - Texture Files Hashes"}]},{"t":3,"p":1,"n":"VNAM - Sound Level"}]},{"t":1,"p":1,"n":"PWAT","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"}]},{"t":1,"p":1,"n":"QUST - Quest","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]},{"t":6,"p":1,"n":"Script Fragments","c":[{"t":3,"n":"Unknown"},{"t":3,"p":1,"n":"fragmentCount"},{"t":2,"p":1,"n":"fileName"},{"t":7,"p":1,"n":"Fragments","c":[{"t":6,"p":1,"n":"Fragment","c":[{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"n":"Unknown"},{"t":3,"p":1,"n":"Quest Stage Index"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]}]},{"t":7,"p":1,"n":"Aliases","c":[{"t":6,"p":1,"n":"Alias","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Alias Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"DNAM - General","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Priority"},{"t":3,"p":1,"n":"Form Version"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Type"}]},{"t":2,"p":1,"n":"ENAM - Event"},{"t":8,"s":1,"p":1,"n":"Text Display Globals","d":1,"c":[{"t":3,"p":1,"n":"QTGL - Global"}]},{"t":2,"p":1,"n":"FLTR - Object Window Filter"},{"t":6,"s":1,"p":1,"n":"Quest Dialogue Conditions","c":[{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]},{"p":1,"n":"NEXT - Marker"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":10,"s":1,"p":1,"n":"Stages","d":1,"c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"INDX - Stage Index","c":[{"t":3,"p":1,"n":"Stage Index"},{"t":3,"p":1,"n":"Flags"},{"t":3,"n":"Unknown"}]},{"t":8,"p":1,"n":"Log Entries","c":[{"t":6,"p":1,"n":"Log Entry","c":[{"t":3,"p":1,"n":"QSDT - Stage Flags"},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":2,"p":1,"n":"CNAM - Log Entry"},{"t":3,"p":1,"n":"NAM0 - Next Quest"},{"t":11,"n":"SCHR - Unused"},{"t":11,"n":"SCTX - Unused"},{"t":11,"n":"QNAM - Unused"}]}]}]}]},{"t":8,"s":1,"p":1,"n":"Objectives","d":1,"c":[{"t":6,"p":1,"n":"Objective","c":[{"t":3,"p":1,"n":"QOBJ - Objective Index"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":2,"p":1,"n":"NNAM - Display Text"},{"t":8,"p":1,"n":"Targets","c":[{"t":6,"p":1,"n":"Target","c":[{"t":6,"p":1,"n":"QSTA - Target","c":[{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]}]}]},{"t":11,"n":"ANAM - Aliases Marker"},{"t":8,"s":1,"p":1,"n":"Aliases","d":1,"c":[{"t":6,"p":1,"n":"Alias","c":[{"t":3,"p":1,"n":"ALST - Reference Alias ID"},{"t":2,"p":1,"n":"ALID - Alias Name"},{"t":6,"p":1,"n":"FNAM - Alias Flags","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Additional Flags"}]},{"t":3,"p":1,"n":"ALFI - Force Into Alias When Filled"},{"t":3,"p":1,"n":"ALFL - Specific Location"},{"t":3,"p":1,"n":"ALFR - Forced Reference"},{"t":3,"p":1,"n":"ALUA - Unique Actor"},{"t":6,"p":1,"n":"Location Alias Reference","c":[{"t":3,"p":1,"n":"ALFA - Alias"},{"t":3,"p":1,"n":"KNAM - Keyword"},{"t":3,"p":1,"n":"ALRT - Ref Type"}]},{"t":6,"p":1,"n":"External Alias Reference","c":[{"t":3,"p":1,"n":"ALEQ - Quest"},{"t":3,"p":1,"n":"ALEA - Alias"}]},{"t":6,"p":1,"n":"Create Reference to Object","c":[{"t":3,"p":1,"n":"ALCO - Object"},{"t":6,"p":1,"n":"ALCA - Alias","c":[{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Create"}]},{"t":3,"p":1,"n":"ALCL - Level"}]},{"t":6,"p":1,"n":"Find Matching Reference Near Alias","c":[{"t":3,"p":1,"n":"ALNA - Alias"},{"t":3,"p":1,"n":"ALNT - Type"}]},{"t":6,"p":1,"n":"Find Matching Reference From Event","c":[{"t":2,"p":1,"n":"ALFE - From Event"},{"t":11,"p":1,"n":"ALFD - Event Data"}]},{"t":8,"s":1,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":3,"p":1,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":3,"p":1,"n":"COCT - Count"},{"t":10,"p":1,"n":"Items","c":[{"t":6,"p":1,"n":"Item","c":[{"t":6,"p":1,"n":"CNTO - Item","c":[{"t":3,"p":1,"n":"Item"},{"t":3,"p":1,"n":"Count"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]},{"t":3,"p":1,"n":"SPOR - Spectator override package list"},{"t":3,"p":1,"n":"OCOR - Observe dead body override package list"},{"t":3,"p":1,"n":"GWOR - Guard warn override package list"},{"t":3,"p":1,"n":"ECOR - Combat override package list"},{"t":3,"p":1,"n":"ALDN - Display Name"},{"t":8,"p":1,"n":"Alias Spells","c":[{"t":3,"p":1,"n":"ALSP - Spell"}]},{"t":8,"p":1,"n":"Alias Factions","c":[{"t":3,"p":1,"n":"ALFC - Faction"}]},{"t":8,"p":1,"n":"Alias Package Data","c":[{"t":3,"p":1,"n":"ALPC - Package"}]},{"t":3,"p":1,"n":"VTCK - Voice Types"},{"p":1,"n":"ALED - Alias End"}]}]},{"t":2,"p":1,"n":"NNAM - Description"},{"t":8,"s":1,"p":1,"n":"Targets","d":1,"c":[{"t":6,"p":1,"n":"Target","c":[{"t":6,"p":1,"n":"QSTA - Target","c":[{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"}]},{"t":8,"s":1,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]}]},{"t":1,"p":1,"n":"RACE - Race","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"DESC - Description"},{"t":3,"n":"SPCT - Count"},{"t":8,"s":1,"p":1,"n":"Actor Effects","c":[{"t":3,"p":1,"n":"SPLO - Actor Effect"}]},{"t":3,"p":1,"n":"WNAM - Skin"},{"t":6,"s":1,"p":1,"n":"BOD2 - Biped Body Template","c":[{"t":3,"p":1,"n":"First Person Flags"},{"t":3,"p":1,"n":"General Flags"},{"n":"Unused"},{"t":3,"p":1,"n":"Armor Type"}]},{"t":6,"s":1,"p":1,"n":"BODT - Body Template","c":[{"t":3,"p":1,"n":"First Person Flags"},{"t":3,"p":1,"n":"General Flags"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Armor Type"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":7,"p":1,"n":"Skill Boosts","c":[{"t":6,"p":1,"n":"Skill Boost","c":[{"t":3,"p":1,"n":"Skill"},{"t":3,"p":1,"n":"Boost"}]}]},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"Male Height"},{"t":5,"p":1,"n":"Female Height"},{"t":5,"p":1,"n":"Male Weight"},{"t":5,"p":1,"n":"Female Weight"},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Starting Health"},{"t":5,"p":1,"n":"Starting Magicka"},{"t":5,"p":1,"n":"Starting Stamina"},{"t":5,"p":1,"n":"Base Carry Weight"},{"t":5,"p":1,"n":"Base Mass"},{"t":5,"p":1,"n":"Acceleration rate"},{"t":5,"p":1,"n":"Deceleration rate"},{"t":3,"p":1,"n":"Size"},{"t":3,"p":1,"n":"Head Biped Object"},{"t":3,"p":1,"n":"Hair Biped Object"},{"t":5,"p":1,"n":"Injured Health Pct"},{"t":3,"p":1,"n":"Shield Biped Object"},{"t":5,"p":1,"n":"Health Regen"},{"t":5,"p":1,"n":"Magicka Regen"},{"t":5,"p":1,"n":"Stamina Regen"},{"t":5,"p":1,"n":"Unarmed Damage"},{"t":5,"p":1,"n":"Unarmed Reach"},{"t":3,"p":1,"n":"Body Biped Object"},{"t":5,"p":1,"n":"Aim Angle Tolerance"},{"t":5,"p":1,"n":"Flight Radius"},{"t":5,"p":1,"n":"Angular Acceleration Rate"},{"t":5,"p":1,"n":"Angular Tolerance"},{"t":3,"p":1,"n":"Flags 2"},{"t":6,"p":1,"n":"Mount Data","c":[{"t":5,"p":1,"n":"Offset X"},{"t":5,"p":1,"n":"Offset Y"},{"t":5,"p":1,"n":"Unknown"}]}]},{"p":1,"n":"MNAM - Male Marker"},{"t":2,"p":1,"n":"ANAM - Male Skeletal Model"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"p":1,"n":"FNAM - Female Marker"},{"t":2,"p":1,"n":"ANAM - Female Skeletal Model"},{"p":1,"n":"NAM2 - Marker NAM2 #1"},{"t":8,"p":1,"n":"Movement Type Names","c":[{"t":2,"p":1,"n":"MTNM - Name"}]},{"t":7,"p":1,"n":"VTCK - Voices","c":[{"t":3,"p":1,"n":"Voice"}]},{"t":7,"p":1,"n":"DNAM - Decapitate Armors","c":[{"t":3,"p":1,"n":"Decapitate Armor"}]},{"t":7,"p":1,"n":"HCLF - Default Hair Colors","c":[{"t":3,"p":1,"n":"Default Hair Color"}]},{"t":3,"n":"TINL - Total Number of Tints in List"},{"t":5,"p":1,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"p":1,"n":"UNAM - FaceGen - Face clamp"},{"t":3,"p":1,"n":"ATKR - Attack Race"},{"t":10,"p":1,"n":"Attacks","c":[{"t":6,"p":1,"n":"Attack","c":[{"t":6,"p":1,"n":"ATKD - Attack Data","c":[{"t":5,"p":1,"n":"Damage Mult"},{"t":5,"p":1,"n":"Attack Chance"},{"t":3,"p":1,"n":"Attack Spell"},{"t":3,"p":1,"n":"Attack Flags"},{"t":5,"p":1,"n":"Attack Angle"},{"t":5,"p":1,"n":"Strike Angle"},{"t":5,"p":1,"n":"Stagger"},{"t":3,"p":1,"n":"Attack Type"},{"t":5,"p":1,"n":"Knockdown"},{"t":5,"p":1,"n":"Recovery Time"},{"t":5,"p":1,"n":"Stamina Mult"}]},{"t":2,"p":1,"n":"ATKE - Attack Event"}]}]},{"t":6,"p":1,"n":"Body Data","c":[{"n":"NAM1 - Body Data Marker"},{"t":6,"p":1,"n":"Male Body Data","c":[{"n":"MNAM - Male Data Marker"},{"t":10,"s":1,"p":1,"n":"Parts","d":1,"c":[{"t":6,"p":1,"n":"Part","c":[{"t":3,"p":1,"n":"INDX - Index"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]}]}]}]},{"t":6,"p":1,"n":"Female Body Data","c":[{"n":"FNAM - Female Data Marker"},{"t":10,"s":1,"p":1,"n":"Parts","d":1,"c":[{"t":6,"p":1,"n":"Part","c":[{"t":3,"p":1,"n":"INDX - Index"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]}]}]}]}]},{"t":7,"p":1,"n":"HNAM - Hairs","c":[{"t":3,"p":1,"n":"Hair"}]},{"t":7,"p":1,"n":"ENAM - Eyes","c":[{"t":3,"p":1,"n":"Eye"}]},{"t":3,"p":1,"n":"GNAM - Body Part Data"},{"p":1,"n":"NAM2 - Marker NAM2 #2"},{"p":1,"n":"NAM3 - Marker NAM3 #3"},{"t":6,"s":1,"p":1,"n":"Male Behavior Graph","c":[{"p":1,"n":"MNAM - Male Data Marker"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]}]},{"t":6,"s":1,"p":1,"n":"Female Behavior Graph","c":[{"p":1,"n":"FNAM - Female Data Marker"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]}]},{"t":3,"p":1,"n":"NAM4 - Material Type"},{"t":3,"p":1,"n":"NAM5 - Impact Data Set"},{"t":3,"p":1,"n":"NAM7 - Decapitation FX"},{"t":3,"p":1,"n":"ONAM - Open Loot Sound"},{"t":3,"p":1,"n":"LNAM - Close Loot Sound"},{"t":8,"p":1,"n":"Biped Object Names","c":[{"t":2,"p":1,"n":"NAME - Name"}]},{"t":10,"n":"Movement Types","c":[{"t":6,"n":"Movement Types","c":[{"t":3,"n":"MTYP - Movement Type"},{"t":6,"n":"SPED - Override Values","c":[{"t":5,"n":"Left - Walk"},{"t":5,"n":"Left - Run"},{"t":5,"n":"Right - Walk"},{"t":5,"n":"Right - Run"},{"t":5,"n":"Forward - Walk"},{"t":5,"n":"Forward - Run"},{"t":5,"n":"Back - Walk"},{"t":5,"n":"Back - Run"},{"t":5,"n":"Rotate - Walk"},{"t":5,"n":"Unknown"}]}]}]},{"t":3,"n":"VNAM - Equipment Flags"},{"t":8,"p":1,"n":"Equip Slots","c":[{"t":3,"p":1,"n":"QNAM - Equip Slot"}]},{"t":3,"n":"UNES - Unarmed Equip Slot"},{"t":8,"n":"Phoneme Target Names","c":[{"t":2,"n":"PHTN - Name"}]},{"t":6,"n":"FaceFX Phonemes","c":[{"t":6,"n":"IY","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"IH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"EH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"EY","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"AE","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"AA","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"AW","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"AY","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"AH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"AO","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"OY","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"OW","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"UH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"UW","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"ER","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"AX","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"S","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"SH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"Z","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"ZH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"F","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"TH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"V","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"DH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"M","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"N","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"NG","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"L","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"R","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"W","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"Y","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"HH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"B","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"D","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"JH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"G","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"P","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"T","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"K","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"CH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"SIL","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"SHOTSIL","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"FLAP","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]}]},{"t":3,"n":"WKMV - Base Movement Default - Walk"},{"t":3,"n":"RNMV - Base Movement Default - Run"},{"t":3,"n":"SWMV - Base Movement Default - Swim"},{"t":3,"n":"FLMV - Base Movement Default - Fly"},{"t":3,"n":"SNMV - Base Movement Default - Sneak"},{"t":3,"n":"SPMV - Base Movement Default - Sprint"},{"t":6,"p":1,"n":"Head Data","c":[{"n":"NAM0 - Head Data Marker"},{"t":6,"s":1,"p":1,"n":"Male Head Data","c":[{"p":1,"n":"MNAM - Male Data Marker"},{"t":10,"p":1,"n":"Head Parts","c":[{"t":6,"p":1,"n":"Head Part","c":[{"t":3,"p":1,"n":"INDX - Head Part Number"},{"t":3,"p":1,"n":"HEAD - Head"}]}]},{"t":6,"n":"Available Morphs","c":[{"t":11,"n":"MPAI - Unknown"},{"t":6,"n":"MPAV - Nose Variants","c":[{"t":3,"n":"Nose Morph Flags"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"MPAV - Brow Variants","c":[{"t":3,"n":"Brow Morph Flags"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"MPAV - Eye Variants","c":[{"t":3,"n":"Eye Morph Flags 1"},{"t":3,"n":"Eye Morph Flags 2"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"MPAV - Lip Variants","c":[{"t":3,"n":"Lip Morph Flags"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Race Presets Male","c":[{"t":3,"n":"RPRM - Preset NPC"}]},{"t":8,"n":"Available Hair Colors Male","c":[{"t":3,"n":"AHCM - Hair Color"}]},{"t":8,"n":"Face Details Texture Set List Male","c":[{"t":3,"n":"FTSM - Texture Set"}]},{"t":3,"n":"DFTM - Default Face Texture Male"},{"t":8,"p":1,"n":"Tint Masks","c":[{"t":6,"p":1,"n":"Tint Assets","c":[{"t":8,"p":1,"n":"Tint Layer","c":[{"t":6,"p":1,"n":"Texture","c":[{"t":3,"p":1,"n":"TINI - Index"},{"t":2,"p":1,"n":"TINT - File Name"},{"t":3,"p":1,"n":"TINP - Mask Type"},{"t":3,"p":1,"n":"TIND - Preset Default"}]}]},{"t":8,"p":1,"n":"Presets","c":[{"t":6,"p":1,"n":"Preset","c":[{"t":3,"p":1,"n":"TINC - Color"},{"t":5,"p":1,"n":"TINV - Default Value"},{"t":3,"p":1,"n":"TIRS - Index"}]}]}]}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]}]},{"t":6,"s":1,"p":1,"n":"Female Head Data","c":[{"p":1,"n":"NAM0 - Head Data Marker"},{"p":1,"n":"FNAM - Female Data Marker"},{"t":10,"p":1,"n":"Head Parts","c":[{"t":6,"p":1,"n":"Head Part","c":[{"t":3,"p":1,"n":"INDX - Head Part Number"},{"t":3,"p":1,"n":"HEAD - Head"}]}]},{"t":6,"n":"Available Morphs","c":[{"t":11,"n":"MPAI - Unknown"},{"t":6,"n":"MPAV - Nose Variants","c":[{"t":3,"n":"Nose Morph Flags"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"MPAV - Brow Variants","c":[{"t":3,"n":"Brow Morph Flags"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"MPAV - Eye Variants","c":[{"t":3,"n":"Eye Morph Flags 1"},{"t":3,"n":"Eye Morph Flags 2"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"MPAV - Lip Variants","c":[{"t":3,"n":"Lip Morph Flags"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Race Presets Female","c":[{"t":3,"n":"RPRF - Preset NPC"}]},{"t":8,"n":"Available Hair Colors Female","c":[{"t":3,"n":"AHCF - Hair Color"}]},{"t":8,"n":"Face Details Texture Set List Female","c":[{"t":3,"n":"FTSF - Texture Set"}]},{"t":3,"n":"DFTF - Default Face Texture Female"},{"t":8,"p":1,"n":"Tint Masks","c":[{"t":6,"p":1,"n":"Tint Assets","c":[{"t":8,"p":1,"n":"Tint Layer","c":[{"t":6,"p":1,"n":"Texture","c":[{"t":3,"p":1,"n":"TINI - Index"},{"t":2,"p":1,"n":"TINT - File Name"},{"t":3,"p":1,"n":"TINP - Mask Type"},{"t":3,"p":1,"n":"TIND - Preset Default"}]}]},{"t":8,"p":1,"n":"Presets","c":[{"t":6,"p":1,"n":"Preset","c":[{"t":3,"p":1,"n":"TINC - Color"},{"t":5,"p":1,"n":"TINV - Default Value"},{"t":3,"p":1,"n":"TIRS - Index"}]}]}]}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]}]}]},{"t":3,"n":"NAM8 - Morph race"},{"t":3,"n":"RNAM - Armor race"}]},{"t":1,"p":1,"n":"REFR - Placed Object","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Base"},{"t":6,"s":1,"p":1,"n":"XMBO - Bound Half Extents","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"s":1,"p":1,"n":"XPRM - Primitive","c":[{"t":6,"p":1,"n":"Bounds","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Color","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}]},{"t":5,"n":"Unknown"},{"t":3,"p":1,"n":"Type"}]},{"t":11,"n":"XORD - Unknown"},{"t":6,"s":1,"p":1,"n":"XOCP - Occlusion Plane Data","c":[{"t":6,"p":1,"n":"Size","c":[{"t":5,"p":1,"n":"Width"},{"t":5,"p":1,"n":"Height"}]},{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation (Quaternion?)","c":[{"t":5,"p":1,"n":"q1"},{"t":5,"p":1,"n":"q2"},{"t":5,"p":1,"n":"q3"},{"t":5,"p":1,"n":"q4"}]}]},{"t":7,"p":1,"n":"XPOD - Portal Data","c":[{"t":6,"p":1,"n":"References","c":[{"t":3,"p":1,"n":"Origin"},{"t":3,"p":1,"n":"Destination"}]}]},{"t":6,"s":1,"p":1,"n":"XPTL - Room Portal (unused)","c":[{"t":6,"p":1,"n":"Size","c":[{"t":5,"p":1,"n":"Width"},{"t":5,"p":1,"n":"Height"}]},{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation (Quaternion?)","c":[{"t":5,"p":1,"n":"q1"},{"t":5,"p":1,"n":"q2"},{"t":5,"p":1,"n":"q3"},{"t":5,"p":1,"n":"q4"}]}]},{"t":6,"s":1,"p":1,"n":"Bound Data","c":[{"t":6,"p":1,"n":"XRMR - Header","c":[{"t":3,"p":1,"n":"Linked Rooms Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"}]},{"t":3,"p":1,"n":"LNAM - Lighting Template"},{"t":3,"p":1,"n":"INAM - Image Space"},{"t":8,"p":1,"n":"Linked Rooms","c":[{"t":3,"p":1,"n":"XLRM - Linked Room"}]}]},{"p":1,"n":"XMBP - MultiBound Primitive Marker"},{"t":11,"n":"XRGD - Ragdoll Data"},{"t":11,"n":"XRGB - Ragdoll Biped Data"},{"t":5,"p":1,"n":"XRDS - Radius"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Lit Water","d":1,"c":[{"t":3,"p":1,"n":"XLTW - Water"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":6,"s":1,"p":1,"n":"XLIG - Light Data","c":[{"t":5,"p":1,"n":"FOV 90+\/-"},{"t":5,"p":1,"n":"Fade 1.35+\/-"},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"Shadow Depth Bias"}]},{"t":6,"s":1,"p":1,"n":"XALP - Alpha","c":[{"t":3,"p":1,"n":"Cutoff"},{"t":3,"p":1,"n":"Base"}]},{"t":6,"s":1,"p":1,"n":"XTEL - Teleport Destination","c":[{"t":3,"p":1,"n":"Door"},{"t":6,"p":1,"n":"Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]},{"t":3,"p":1,"n":"Flags"}]},{"t":3,"p":1,"n":"XTNM - Teleport Message Box"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"t":11,"n":"XWCN - Unknown"},{"t":11,"n":"XWCS - Unknown"},{"t":6,"s":1,"p":1,"n":"XWCU - Water Velocity","c":[{"t":5,"p":1,"n":"X Offset"},{"t":5,"p":1,"n":"Y Offset"},{"t":5,"p":1,"n":"Z Offset"},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"X Angle"},{"t":5,"p":1,"n":"Y Angle"},{"t":5,"p":1,"n":"Z Angle"}]},{"t":6,"n":"XCVL - Unknown","c":[{"t":11,"n":"Unknown"},{"t":5,"n":"X Angle"}]},{"t":3,"n":"XCZR - Unknown"},{"t":11,"n":"XCZA - Unknown"},{"t":3,"n":"XCZC - Unknown"},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":3,"p":1,"n":"XSPC - Spawn Container"},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":3,"p":1,"n":"XLIB - Leveled Item Base Object"},{"t":3,"p":1,"n":"XLCM - Level Modifier"},{"t":3,"p":1,"n":"XLCN - Persistent Location"},{"t":3,"p":1,"n":"XTRI - Collision Layer"},{"t":6,"s":1,"p":1,"n":"XLOC - Lock Data","c":[{"t":3,"p":1,"n":"Level"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Key"},{"t":3,"p":1,"n":"Flags"}]},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":6,"s":1,"p":1,"n":"XNDP - Navigation Door Link","c":[{"t":3,"p":1,"n":"Navigation Mesh"},{"t":3,"p":1,"n":"Teleport Marker Triangle"},{"t":11,"n":"Unused"}]},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":3,"p":1,"n":"XCNT - Item Count"},{"t":5,"p":1,"n":"XCHG - Charge"},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":8,"s":1,"p":1,"n":"Patrol","d":1,"c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"XPRD - Idle Time"},{"p":1,"n":"XPPA - Patrol Script Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":11,"n":"SCHR - Unused"},{"t":11,"n":"SCTX - Unused"},{"t":8,"p":1,"n":"Topic","c":[{"t":6,"p":1,"n":"PDTO - Topic Data","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Topic"},{"t":2,"p":1,"n":"Subtype"}]}]}]}]},{"t":3,"p":1,"n":"XACT - Action Flag"},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"p":1,"n":"ONAM - Open by Default"},{"t":6,"s":1,"p":1,"n":"Map Marker","c":[{"p":1,"n":"XMRK - Map Marker Data"},{"t":3,"p":1,"n":"FNAM - Map Flags"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"p":1,"n":"TNAM - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"}]}]},{"t":3,"p":1,"n":"XATR - Attach Ref"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"REGN - Region","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"RCLR - Map Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":3,"p":1,"n":"WNAM - Worldspace"},{"t":8,"s":1,"p":1,"n":"Region Areas","d":1,"c":[{"t":6,"p":1,"n":"Region Area","c":[{"t":3,"p":1,"n":"RPLI - Edge Fall-off"},{"t":7,"p":1,"n":"RPLD - Region Point List Data","c":[{"t":6,"p":1,"n":"Point","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"}]}]}]}]},{"t":10,"p":1,"n":"Region Data Entries","d":1,"c":[{"t":6,"p":1,"n":"Region Data Entry","c":[{"t":6,"p":1,"n":"RDAT - Data Header","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Priority"},{"t":11,"n":"Unknown"}]},{"t":6,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":3,"p":1,"n":"RDMO - Music"},{"t":7,"p":1,"n":"RDSA - Sounds","c":[{"t":6,"p":1,"n":"Sound","c":[{"t":3,"p":1,"n":"Sound"},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Chance"}]}]},{"t":2,"p":1,"n":"RDMP - Map Name"},{"t":7,"p":1,"n":"RDOT - Objects","c":[{"t":6,"p":1,"n":"Object","c":[{"t":3,"p":1,"n":"Object"},{"t":3,"p":1,"n":"Parent Index"},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"Density"},{"t":3,"p":1,"n":"Clustering"},{"t":3,"p":1,"n":"Min Slope"},{"t":3,"p":1,"n":"Max Slope"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Radius wrt Parent"},{"t":3,"p":1,"n":"Radius"},{"t":5,"p":1,"n":"Min Height"},{"t":5,"p":1,"n":"Max Height"},{"t":5,"p":1,"n":"Sink"},{"t":5,"p":1,"n":"Sink Variance"},{"t":5,"p":1,"n":"Size Variance"},{"t":6,"p":1,"n":"Angle Variance","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"},{"t":3,"p":1,"n":"Z"}]}]}]},{"t":7,"p":1,"n":"RDGS - Grasses","c":[{"t":6,"p":1,"n":"Grass","c":[{"t":3,"p":1,"n":"Grass"},{"t":11,"n":"Unknown"}]}]},{"t":7,"p":1,"n":"RDWT - Weather Types","c":[{"t":6,"p":1,"n":"Weather Type","c":[{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Chance"},{"t":3,"p":1,"n":"Global"}]}]}]}]}]},{"t":1,"p":1,"n":"RELA - Relationship","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Parent"},{"t":3,"p":1,"n":"Child"},{"t":3,"p":1,"n":"Rank"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Association Type"}]}]},{"t":1,"p":1,"n":"REVB - Reverb Parameters","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Decay Time (ms)"},{"t":3,"p":1,"n":"HF Reference (Hz)"},{"t":3,"p":1,"n":"Room Filter"},{"t":3,"p":1,"n":"Room HF Filter"},{"t":3,"p":1,"n":"Reflections"},{"t":3,"p":1,"n":"Reverb Amp"},{"t":3,"p":1,"n":"Decay HF Ratio"},{"t":3,"p":1,"n":"Reflect Delay (ms), scaled"},{"t":3,"p":1,"n":"Reverb Delay (ms)"},{"t":3,"p":1,"n":"Diffusion %"},{"t":3,"p":1,"n":"Density %"},{"t":3,"n":"Unknown"}]}]},{"t":1,"p":1,"n":"RFCT - Visual Effect","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - Effect Data","c":[{"t":3,"p":1,"n":"Effect Art"},{"t":3,"p":1,"n":"Shader"},{"t":3,"p":1,"n":"Flags"}]}]},{"t":1,"p":1,"n":"RGDL","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"}]},{"t":1,"p":1,"n":"SCEN - Scene","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]},{"t":6,"p":1,"n":"Script Fragments","c":[{"t":3,"n":"Unknown"},{"t":3,"p":1,"n":"Flags"},{"t":2,"p":1,"n":"fileName"},{"t":7,"p":1,"n":"Fragments","c":[{"t":6,"p":1,"n":"Fragment","c":[{"t":3,"n":"Unknown"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]},{"t":7,"p":1,"n":"Phase Fragments","c":[{"t":6,"p":1,"n":"Phase Fragment","c":[{"t":3,"p":1,"n":"Phase Flag"},{"t":3,"p":1,"n":"Phase Index"},{"t":3,"n":"Unknown"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]}]}]},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":8,"s":1,"p":1,"n":"Phases","d":1,"c":[{"t":6,"p":1,"n":"Phase","c":[{"p":1,"n":"HNAM - Marker Phase Start"},{"t":2,"p":1,"n":"NAM0 - Name"},{"t":6,"p":1,"n":"Start Conditions","c":[{"t":8,"s":1,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]},{"p":1,"n":"NEXT - Marker"},{"t":6,"p":1,"n":"Completion Conditions","c":[{"t":8,"s":1,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]},{"t":6,"n":"Unused","c":[{"t":11,"n":"SCHR - Unknown"},{"t":11,"n":"SCDA - Unknown"},{"t":11,"n":"SCTX - Unknown"},{"t":11,"n":"QNAM - Unknown"},{"t":11,"n":"SCRO - Unknown"}]},{"t":3,"p":1,"n":"WNAM - Editor Width"},{"p":1,"n":"HNAM - Marker Phase End"}]}]},{"t":8,"s":1,"p":1,"n":"Actors","d":1,"c":[{"t":6,"p":1,"n":"Actor","c":[{"t":3,"p":1,"n":"ALID - Actor ID"},{"t":3,"p":1,"n":"LNAM - Flags"},{"t":3,"p":1,"n":"DNAM - Behaviour Flags"}]}]},{"t":8,"s":1,"p":1,"n":"Actions","d":1,"c":[{"t":6,"p":1,"n":"Action","c":[{"t":3,"p":1,"n":"ANAM - Type"},{"t":2,"p":1,"n":"NAM0 - Name"},{"t":3,"p":1,"n":"ALID - Actor ID"},{"t":11,"n":"LNAM - Unknown"},{"t":3,"p":1,"n":"INAM - Index"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":3,"p":1,"n":"SNAM - Start Phase"},{"t":3,"p":1,"n":"ENAM - End Phase"},{"t":5,"p":1,"n":"SNAM - Timer Seconds"},{"t":8,"p":1,"n":"Packages","c":[{"t":3,"p":1,"n":"PNAM - Package"}]},{"t":3,"p":1,"n":"DATA - Topic"},{"t":3,"p":1,"n":"HTID - Headtrack Actor ID"},{"t":5,"p":1,"n":"DMAX - Looping - Max"},{"t":5,"p":1,"n":"DMIN - Looping - Min"},{"t":3,"p":1,"n":"DEMO - Emotion Type"},{"t":3,"p":1,"n":"DEVA - Emotion Value"},{"t":6,"n":"Unused","c":[{"t":11,"n":"SCHR - Unknown"},{"t":11,"n":"SCDA - Unknown"},{"t":11,"n":"SCTX - Unknown"},{"t":11,"n":"QNAM - Unknown"},{"t":11,"n":"SCRO - Unknown"}]},{"p":1,"n":"ANAM - End Marker"}]}]},{"t":6,"n":"Unused","c":[{"t":11,"n":"SCHR - Unknown"},{"t":11,"n":"SCDA - Unknown"},{"t":11,"n":"SCTX - Unknown"},{"t":11,"n":"QNAM - Unknown"},{"t":11,"n":"SCRO - Unknown"}]},{"p":1,"n":"NEXT - Marker"},{"t":3,"p":1,"n":"PNAM - Quest"},{"t":3,"p":1,"n":"INAM - Last Action Index"},{"t":11,"n":"VNAM - Unknown"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]},{"t":1,"p":1,"n":"SCOL","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"}]},{"t":1,"p":1,"n":"SCPT","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"}]},{"t":1,"p":1,"n":"SCRL - Scroll","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":3,"p":1,"n":"MDOB - Menu Display Object"},{"t":3,"p":1,"n":"ETYP - Equipment Type"},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":6,"s":1,"p":1,"n":"DATA - Item","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":6,"s":1,"p":1,"n":"SPIT - Data","c":[{"t":3,"p":1,"n":"Base Cost"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Type"},{"t":5,"p":1,"n":"Charge Time"},{"t":3,"p":1,"n":"Cast Type"},{"t":3,"p":1,"n":"Target Type"},{"t":5,"p":1,"n":"Cast Duration"},{"t":5,"p":1,"n":"Range"},{"t":3,"p":1,"n":"Half-cost Perk"}]},{"t":8,"s":1,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":3,"p":1,"n":"EFID - Base Effect"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":5,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"}]},{"t":8,"s":1,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]}]},{"t":1,"p":1,"n":"SHOU - Shout","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"MDOB - Menu Display Object"},{"t":2,"p":1,"n":"DESC - Description"},{"t":8,"s":1,"p":1,"n":"Words of Power","d":1,"c":[{"t":6,"p":1,"n":"SNAM - ","c":[{"t":3,"p":1,"n":"Word"},{"t":3,"p":1,"n":"Spell"},{"t":5,"p":1,"n":"Recovery Time"}]}]}]},{"t":1,"p":1,"n":"SLGM - Soul Gem","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":3,"p":1,"n":"SOUL - Contained Soul"},{"t":3,"p":1,"n":"SLCP - Maximum Capacity"},{"t":3,"p":1,"n":"NAM0 - Linked To"}]},{"t":1,"p":1,"n":"SMBN - Story Manager Branch Node","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"PNAM - Parent "},{"t":3,"p":1,"n":"SNAM - Child "},{"t":3,"n":"CITC - Condition Count"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":3,"p":1,"n":"DNAM - Flags"},{"t":11,"n":"XNAM - Unknown"}]},{"t":1,"p":1,"n":"SMEN - Story Manager Event Node","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"PNAM - Parent "},{"t":3,"p":1,"n":"SNAM - Child "},{"t":3,"n":"CITC - Condition Count"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":3,"p":1,"n":"DNAM - Flags"},{"t":11,"n":"XNAM - Unknown"},{"t":2,"p":1,"n":"ENAM - Type"}]},{"t":1,"p":1,"n":"SMQN - Story Manager Quest Node","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"PNAM - Parent "},{"t":3,"p":1,"n":"SNAM - Child "},{"t":3,"n":"CITC - Condition Count"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":6,"s":1,"p":1,"n":"DNAM - Flags","c":[{"t":3,"p":1,"n":"Node Flags"},{"t":3,"p":1,"n":"Quest Flags"}]},{"t":3,"p":1,"n":"XNAM - Max concurrent quests"},{"t":3,"p":1,"n":"MNAM - Num quests to run"},{"t":3,"n":"QNAM - Quest Count"},{"t":10,"p":1,"n":"Quests","d":1,"c":[{"t":6,"p":1,"n":"Quest","c":[{"t":3,"p":1,"n":"NNAM - Quest"},{"t":11,"n":"FNAM - Unknown"},{"t":5,"p":1,"n":"RNAM - Hours until reset"}]}]}]},{"t":1,"p":1,"n":"SNCT - Sound Category","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":3,"p":1,"n":"PNAM - Parent"},{"t":3,"p":1,"n":"VNAM - Static Volume Multiplier"},{"t":3,"p":1,"n":"UNAM - Default Menu Value"}]},{"t":1,"p":1,"n":"SNDR - Sound Descriptor","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":11,"n":"CNAM - Unknown"},{"t":3,"p":1,"n":"GNAM - Category"},{"t":3,"p":1,"n":"SNAM - Alternate Sound For"},{"t":8,"s":1,"p":1,"n":"Sounds","d":1,"c":[{"t":6,"p":1,"n":"Sound Files","c":[{"t":2,"p":1,"n":"ANAM - File Name"}]}]},{"t":3,"p":1,"n":"ONAM - Output Model"},{"t":2,"p":1,"n":"FNAM - String"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":6,"s":1,"p":1,"n":"LNAM - Values","c":[{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Looping"},{"t":3,"p":1,"n":"Rumble Send Value = (Small \/ 7) + ((Big \/ 7) * 16)"}]},{"t":6,"s":1,"p":1,"n":"BNAM - Values","c":[{"t":3,"p":1,"n":"% Frequency Shift"},{"t":3,"p":1,"n":"% Frequency Variance"},{"t":3,"p":1,"n":"Priority"},{"t":3,"p":1,"n":"db Variance"},{"t":3,"p":1,"n":"Static Attenuation (db)"}]}]},{"t":1,"p":1,"n":"SOPM - Sound Output Model","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"NAM1 - Data","c":[{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Reverb Send %"}]},{"t":11,"n":"FNAM - Unknown"},{"t":3,"p":1,"n":"MNAM - Type"},{"t":11,"n":"CNAM - Unknown"},{"t":11,"n":"SNAM - Unknown"},{"t":6,"s":1,"p":1,"n":"ONAM - Output Values","c":[{"t":7,"p":1,"n":"Channels","c":[{"t":6,"p":1,"n":"","c":[{"t":3,"p":1,"n":"L"},{"t":3,"p":1,"n":"R"},{"t":3,"p":1,"n":"C"},{"t":3,"p":1,"n":"LFE"},{"t":3,"p":1,"n":"RL"},{"t":3,"p":1,"n":"RR"},{"t":3,"p":1,"n":"BL"},{"t":3,"p":1,"n":"BR"}]}]}]},{"t":6,"s":1,"p":1,"n":"ANAM - Attenuation Values","c":[{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"Min Distance"},{"t":5,"p":1,"n":"Max Distance"},{"t":7,"p":1,"n":"Curve","c":[{"t":3,"p":1,"n":"Value"}]}]}]},{"t":1,"p":1,"n":"SOUN - Sound Marker","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":11,"n":"FNAM - Unknown"},{"t":11,"n":"SNDD - Unknown"},{"t":3,"p":1,"n":"SDSC - Sound Descriptor"}]},{"t":1,"p":1,"n":"SPEL - Spell","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":3,"p":1,"n":"MDOB - Menu Display Object"},{"t":3,"p":1,"n":"ETYP - Equipment Type"},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"SPIT - Data","c":[{"t":3,"p":1,"n":"Base Cost"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Type"},{"t":5,"p":1,"n":"Charge Time"},{"t":3,"p":1,"n":"Cast Type"},{"t":3,"p":1,"n":"Target Type"},{"t":5,"p":1,"n":"Cast Duration"},{"t":5,"p":1,"n":"Range"},{"t":3,"p":1,"n":"Half-cost Perk"}]},{"t":8,"s":1,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":3,"p":1,"n":"EFID - Base Effect"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":5,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"}]},{"t":8,"s":1,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]}]},{"t":1,"p":1,"n":"SPGD - Shader Particle Geometry","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Gravity Velocity"},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"Rotation Velocity"},{"t":5,"p":1,"n":"Particle Size X"},{"t":5,"p":1,"n":"Center Offset Min"},{"t":5,"p":1,"n":"Particle Size Y"},{"t":5,"p":1,"n":"Center Offset Max"},{"t":5,"p":1,"n":"Initial Rotation"},{"t":3,"p":1,"n":"# of Subtextures X"},{"t":3,"p":1,"n":"# of Subtextures Y"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Box Size"},{"t":5,"p":1,"n":"Particle Density"}]},{"t":2,"p":1,"n":"ICON - Particle Texture"}]},{"t":1,"p":1,"n":"STAT - Static","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"DNAM - Direction Material","c":[{"t":5,"p":1,"n":"Max Angle (30-120)"},{"t":3,"p":1,"n":"Material"}]},{"t":7,"p":1,"n":"MNAM - Distant LOD","c":[{"t":6,"p":1,"n":"LOD","c":[{"t":2,"p":1,"n":"Mesh"}]}]}]},{"t":1,"p":1,"n":"TACT - Talking Activator","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":11,"n":"PNAM - Unknown"},{"t":3,"p":1,"n":"SNAM - Looping Sound"},{"t":11,"n":"FNAM - Unknown"},{"t":3,"p":1,"n":"VNAM - Voice Type"}]},{"t":1,"p":1,"n":"TREE - Tree","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":3,"p":1,"n":"PFIG - Ingredient"},{"t":3,"p":1,"n":"SNAM - Harvest Sound"},{"t":6,"s":1,"p":1,"n":"PFPC - Ingredient Production","c":[{"t":3,"p":1,"n":"Spring"},{"t":3,"p":1,"n":"Summer"},{"t":3,"p":1,"n":"Fall"},{"t":3,"p":1,"n":"Winter"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"CNAM - Tree Data","c":[{"t":5,"p":1,"n":"Trunk Flexibility"},{"t":5,"p":1,"n":"Branch Flexibility"},{"t":5,"n":"Unknown"},{"t":5,"p":1,"n":"Leaf Amplitude"},{"t":5,"p":1,"n":"Leaf Frequency"}]}]},{"t":1,"p":1,"n":"TXST - Texture Set","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Textures (RGB\/A)","c":[{"t":2,"p":1,"n":"TX00 - Difuse"},{"t":2,"p":1,"n":"TX01 - Normal\/Gloss"},{"t":2,"p":1,"n":"TX02 - Environment Mask\/Subsurface Tint"},{"t":2,"p":1,"n":"TX03 - Glow\/Detail Map"},{"t":2,"p":1,"n":"TX04 - Height"},{"t":2,"p":1,"n":"TX05 - Environment"},{"t":2,"p":1,"n":"TX06 - Multilayer"},{"t":2,"p":1,"n":"TX07 - Backlight Mask\/Specular"}]},{"t":6,"s":1,"p":1,"n":"DODT - Decal Data","c":[{"t":5,"p":1,"n":"Min Width"},{"t":5,"p":1,"n":"Max Width"},{"t":5,"p":1,"n":"Min Height"},{"t":5,"p":1,"n":"Max Height"},{"t":5,"p":1,"n":"Depth"},{"t":5,"p":1,"n":"Shininess"},{"t":6,"p":1,"n":"Parallax","c":[{"t":5,"p":1,"n":"Scale"},{"t":3,"p":1,"n":"Passes"}]},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"},{"t":6,"p":1,"n":"Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":3,"p":1,"n":"DNAM - Flags"}]},{"t":1,"p":1,"n":"VOLI - Volumetric Lighting","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":5,"p":1,"n":"CNAM - Intensity"},{"t":5,"p":1,"n":"DNAM - Custom Color - Contribution"},{"t":5,"p":1,"n":"ENAM - Red"},{"t":5,"p":1,"n":"FNAM - Green"},{"t":5,"p":1,"n":"GNAM - Blue"},{"t":5,"p":1,"n":"HNAM - Density - Contribution"},{"t":5,"p":1,"n":"INAM - Density - Size"},{"t":5,"p":1,"n":"JNAM - Density - Wind Speed"},{"t":5,"p":1,"n":"KNAM - Density - Falling Speed"},{"t":5,"p":1,"n":"LNAM - Phase Function - Contribution"},{"t":5,"p":1,"n":"MNAM - Phase Function - Scattering"},{"t":5,"p":1,"n":"NNAM - Sampling Repartition - Range Factor"}]},{"t":1,"p":1,"n":"VTYP - Voice Type","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"DNAM - Flags"}]},{"t":1,"p":1,"n":"WATR - Water","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":8,"n":"Unused","c":[{"t":2,"n":"NNAM - Noise Map"}]},{"t":3,"p":1,"n":"ANAM - Opacity"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":11,"n":"MNAM - Unused"},{"t":3,"p":1,"n":"TNAM - Material"},{"t":3,"p":1,"n":"SNAM - Open Sound"},{"t":3,"p":1,"n":"XNAM - Spell"},{"t":3,"p":1,"n":"INAM - Image Space"},{"t":3,"p":1,"n":"DATA - Damage Per Second"},{"t":6,"s":1,"p":1,"n":"DNAM - Visual Data","c":[{"t":5,"n":"Unknown"},{"t":5,"p":1,"n":"Specular Properties - Sun Specular Power"},{"t":5,"p":1,"n":"Water Properties - Reflectivity Amount"},{"t":5,"p":1,"n":"Water Properties - Fresnel Amount"},{"t":5,"p":1,"n":"Fog Properties - Above Water - Fog Distance - Near Plane"},{"t":5,"p":1,"n":"Fog Properties - Above Water - Fog Distance - Far Plane"},{"t":6,"p":1,"n":"Shallow Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Deep Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Reflection Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Displacement Simulator - Starting Size"},{"t":5,"p":1,"n":"Displacement Simulator - Force"},{"t":5,"p":1,"n":"Displacement Simulator - Velocity"},{"t":5,"p":1,"n":"Displacement Simulator - Falloff"},{"t":5,"p":1,"n":"Displacement Simulator - Dampner"},{"t":5,"p":1,"n":"Noise Properties - Noise Falloff"},{"t":5,"p":1,"n":"Noise Properties - Layer One - Wind Direction"},{"t":5,"p":1,"n":"Noise Properties - Layer Two - Wind Direction"},{"t":5,"p":1,"n":"Noise Properties - Layer Three - Wind Direction"},{"t":5,"p":1,"n":"Noise Properties - Layer One - Wind Speed"},{"t":5,"p":1,"n":"Noise Properties - Layer Two - Wind Speed"},{"t":5,"p":1,"n":"Noise Properties - Layer Three - Wind Speed"},{"t":5,"p":1,"n":"Fog Properties - Above Water - Fog Amount"},{"t":5,"p":1,"n":"Fog Properties - Under Water - Fog Amount"},{"t":5,"p":1,"n":"Fog Properties - Under Water - Fog Distance - Near Plane"},{"t":5,"p":1,"n":"Fog Properties - Under Water - Fog Distance - Far Plane"},{"t":5,"p":1,"n":"Water Properties - Refraction Magnitude"},{"t":5,"p":1,"n":"Specular Properties - Specular Power"},{"t":5,"p":1,"n":"Specular Properties - Specular Radius"},{"t":5,"p":1,"n":"Specular Properties - Specular Brightness"},{"t":5,"p":1,"n":"Noise Properties - Layer One - UV Scale"},{"t":5,"p":1,"n":"Noise Properties - Layer Two - UV Scale"},{"t":5,"p":1,"n":"Noise Properties - Layer Three - UV Scale"},{"t":5,"p":1,"n":"Noise Properties - Layer One - Amplitude Scale"},{"t":5,"p":1,"n":"Noise Properties - Layer Two - Amplitude Scale"},{"t":5,"p":1,"n":"Noise Properties - Layer Three - Amplitude Scale"},{"t":5,"p":1,"n":"Water Properties - Reflection Magnitude"},{"t":5,"p":1,"n":"Specular Properties - Sun Sparkle Magnitude"},{"t":5,"p":1,"n":"Specular Properties - Sun Specular Magnitude"},{"t":5,"p":1,"n":"Depth Properties - Reflections"},{"t":5,"p":1,"n":"Depth Properties - Refraction"},{"t":5,"p":1,"n":"Depth Properties - Normals"},{"t":5,"p":1,"n":"Depth Properties - Specular Lighting"},{"t":5,"p":1,"n":"Specular Properties - Sun Sparkle Power"}]},{"t":11,"n":"GNAM - Unused"},{"t":6,"s":1,"p":1,"n":"NAM0 - Linear Velocity","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"s":1,"p":1,"n":"NAM1 - Angular Velocity","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":2,"p":1,"n":"NAM2 - Noise Layer One - Noise Texture"},{"t":2,"p":1,"n":"NAM3 - Noise Layer Two - Noise Texture"},{"t":2,"p":1,"n":"NAM4 - Noise Layer Three - Noise Texture"},{"t":2,"p":1,"n":"NAM5 - Flow Normals - Noise Texture"}]},{"t":1,"p":1,"n":"WEAP - Weapon","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":3,"p":1,"n":"EITM - Object Effect"},{"t":3,"p":1,"n":"EAMT - Enchantment Amount"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"ETYP - Equipment Type"},{"t":3,"p":1,"n":"BIDS - Block Bash Impact Data Set"},{"t":3,"p":1,"n":"BAMT - Alternate Block Material"},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"Has Scope","c":[{"t":2,"p":1,"n":"MOD3 - Model Filename"},{"t":11,"p":1,"n":"MO3T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO3S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":11,"n":"NNAM - Unused"},{"t":3,"p":1,"n":"INAM - Impact Data Set"},{"t":3,"p":1,"n":"WNAM - 1st Person Model Object"},{"t":3,"p":1,"n":"SNAM - Attack Sound"},{"t":3,"p":1,"n":"XNAM - Attack Sound 2D"},{"t":3,"p":1,"n":"NAM7 - Attack Loop Sound"},{"t":3,"p":1,"n":"TNAM - Attack Fail Sound"},{"t":3,"p":1,"n":"UNAM - Idle Sound"},{"t":3,"p":1,"n":"NAM9 - Equip Sound"},{"t":3,"p":1,"n":"NAM8 - Unequip Sound"},{"t":6,"s":1,"p":1,"n":"DATA - Game Data","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"},{"t":3,"p":1,"n":"Damage"}]},{"t":6,"s":1,"p":1,"n":"DNAM - Data","c":[{"t":3,"p":1,"n":"Animation Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Speed"},{"t":5,"p":1,"n":"Reach"},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Sight FOV"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Base VATS To-Hit Chance"},{"t":3,"p":1,"n":"Attack Animation"},{"t":3,"p":1,"n":"# Projectiles"},{"t":3,"p":1,"n":"Embedded Weapon AV (unused)"},{"t":5,"p":1,"n":"Range Min"},{"t":5,"p":1,"n":"Range Max"},{"t":3,"p":1,"n":"On Hit"},{"t":3,"p":1,"n":"Flags2"},{"t":5,"p":1,"n":"Animation Attack Mult"},{"t":5,"p":1,"n":"Rumble - Left Motor Strength"},{"t":5,"p":1,"n":"Rumble - Right Motor Strength"},{"t":5,"p":1,"n":"Rumble - Duration"},{"t":3,"p":1,"n":"Skill"},{"t":3,"p":1,"n":"Resist"},{"t":5,"p":1,"n":"Stagger"}]},{"t":6,"s":1,"p":1,"n":"CRDT - Critical Data","c":[{"t":3,"p":1,"n":"Damage"},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"% Mult"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Effect"}]},{"t":3,"p":1,"n":"VNAM - Detection Sound Level"},{"t":3,"p":1,"n":"CNAM - Template"}]},{"t":1,"p":1,"n":"WOOP - Word of Power","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"TNAM - Translation"}]},{"t":1,"p":1,"n":"WRLD - Worldspace","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":8,"n":"Unused RNAM","c":[{"t":6,"n":"RNAM - Grid","c":[{"t":3,"n":"Y"},{"t":3,"n":"X"},{"t":7,"n":"References","c":[{"t":6,"n":"Reference","c":[{"t":3,"n":"Ref"},{"t":3,"n":"Y"},{"t":3,"n":"X"}]}]}]}]},{"t":11,"n":"MHDT - Max Height Data"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"WCTR - Fixed Dimensions Center Cell","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"}]},{"t":3,"p":1,"n":"LTMP - Interior Lighting"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":3,"p":1,"n":"XLCN - Location"},{"t":6,"s":1,"p":1,"n":"Parent","c":[{"t":3,"p":1,"n":"WNAM - Worldspace"},{"t":6,"p":1,"n":"PNAM - ","c":[{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"}]}]},{"t":3,"p":1,"n":"CNAM - Climate"},{"t":3,"p":1,"n":"NAM2 - Water"},{"t":3,"p":1,"n":"NAM3 - LOD Water Type"},{"t":5,"p":1,"n":"NAM4 - LOD Water Height"},{"t":6,"s":1,"p":1,"n":"DNAM - Land Data","c":[{"t":5,"p":1,"n":"Default Land Height"},{"t":5,"p":1,"n":"Default Water Height"}]},{"t":2,"p":1,"n":"ICON - Map Image"},{"t":6,"s":1,"p":1,"n":"Cloud Model","c":[{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]}]},{"t":6,"s":1,"p":1,"n":"MNAM - Map Data","c":[{"t":6,"p":1,"n":"Usable Dimensions","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"}]},{"t":6,"p":1,"n":"Cell Coordinates","c":[{"t":6,"p":1,"n":"NW Cell","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"}]},{"t":6,"p":1,"n":"SE Cell","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"}]}]},{"t":6,"p":1,"n":"Camera Data","c":[{"t":5,"p":1,"n":"Min Height"},{"t":5,"p":1,"n":"Max Height"},{"t":5,"p":1,"n":"Initial Pitch"}]}]},{"t":6,"s":1,"p":1,"n":"ONAM - World Map Offset Data","c":[{"t":5,"p":1,"n":"World Map Scale"},{"t":5,"p":1,"n":"Cell X Offset"},{"t":5,"p":1,"n":"Cell Y Offset"},{"t":5,"p":1,"n":"Cell Z Offset"}]},{"t":5,"p":1,"n":"NAMA - Distant LOD Multiplier"},{"t":3,"p":1,"n":"DATA - Flags"},{"t":6,"s":1,"p":1,"n":"Object Bounds","c":[{"t":6,"p":1,"n":"NAM0 - Min","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"}]},{"t":6,"p":1,"n":"NAM9 - Max","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"}]}]},{"t":3,"p":1,"n":"ZNAM - Music"},{"t":2,"p":1,"n":"NNAM - Canopy Shadow (unused)"},{"t":2,"p":1,"n":"XNAM - Water Noise Texture"},{"t":2,"p":1,"n":"TNAM - HD LOD Diffuse Texture"},{"t":2,"p":1,"n":"UNAM - HD LOD Normal Texture"},{"t":2,"p":1,"n":"XWEM - Water Environment Map (unused)"},{"t":11,"n":"OFST - Offset Data"}]},{"t":1,"p":1,"n":"WTHR - Weather","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"00TX - Cloud Texture Layer #0"},{"t":2,"p":1,"n":"10TX - Cloud Texture Layer #1"},{"t":2,"p":1,"n":"20TX - Cloud Texture Layer #2"},{"t":2,"p":1,"n":"30TX - Cloud Texture Layer #3"},{"t":2,"p":1,"n":"40TX - Cloud Texture Layer #4"},{"t":2,"p":1,"n":"50TX - Cloud Texture Layer #5"},{"t":2,"p":1,"n":"60TX - Cloud Texture Layer #6"},{"t":2,"p":1,"n":"70TX - Cloud Texture Layer #7"},{"t":2,"p":1,"n":"80TX - Cloud Texture Layer #8"},{"t":2,"p":1,"n":"90TX - Cloud Texture Layer #9"},{"t":2,"p":1,"n":":0TX - Cloud Texture Layer #10"},{"t":2,"p":1,"n":";0TX - Cloud Texture Layer #11"},{"t":2,"p":1,"n":"<0TX - Cloud Texture Layer #12"},{"t":2,"p":1,"n":"=0TX - Cloud Texture Layer #13"},{"t":2,"p":1,"n":">0TX - Cloud Texture Layer #14"},{"t":2,"p":1,"n":"?0TX - Cloud Texture Layer #15"},{"t":2,"p":1,"n":"@0TX - Cloud Texture Layer #16"},{"t":2,"p":1,"n":"A0TX - Cloud Texture Layer #17"},{"t":2,"p":1,"n":"B0TX - Cloud Texture Layer #18"},{"t":2,"p":1,"n":"C0TX - Cloud Texture Layer #19"},{"t":2,"p":1,"n":"D0TX - Cloud Texture Layer #20"},{"t":2,"p":1,"n":"E0TX - Cloud Texture Layer #21"},{"t":2,"p":1,"n":"F0TX - Cloud Texture Layer #22"},{"t":2,"p":1,"n":"G0TX - Cloud Texture Layer #23"},{"t":2,"p":1,"n":"H0TX - Cloud Texture Layer #24"},{"t":2,"p":1,"n":"I0TX - Cloud Texture Layer #25"},{"t":2,"p":1,"n":"J0TX - Cloud Texture Layer #26"},{"t":2,"p":1,"n":"K0TX - Cloud Texture Layer #27"},{"t":2,"p":1,"n":"L0TX - Cloud Texture Layer #28"},{"t":11,"n":"DNAM - Unused"},{"t":11,"n":"CNAM - Unused"},{"t":11,"n":"ANAM - Unused"},{"t":11,"n":"BNAM - Unused"},{"t":11,"n":"LNAM - Unknown"},{"t":3,"p":1,"n":"MNAM - Precipitation Type"},{"t":3,"p":1,"n":"NNAM - Visual Effect"},{"t":11,"n":"ONAM - Unused"},{"t":6,"s":1,"p":1,"n":"Cloud Speed","c":[{"t":7,"p":1,"n":"RNAM - Y Speed","c":[{"t":3,"p":1,"n":"Layer"}]},{"t":7,"p":1,"n":"QNAM - X Speed","c":[{"t":3,"p":1,"n":"Layer"}]}]},{"t":7,"s":1,"p":1,"n":"PNAM - Cloud Colors","c":[{"t":6,"p":1,"n":"Layer","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]}]},{"t":7,"s":1,"p":1,"n":"JNAM - Cloud Alphas","c":[{"t":6,"p":1,"n":"Layer","c":[{"t":5,"p":1,"n":"Sunrise"},{"t":5,"p":1,"n":"Day"},{"t":5,"p":1,"n":"Sunset"},{"t":5,"p":1,"n":"Night"}]}]},{"t":6,"s":1,"p":1,"n":"NAM0 - Weather Colors","c":[{"t":6,"p":1,"n":"Sky-Upper","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Fog Near","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"n":"Unknown","c":[{"t":6,"n":"Sunrise","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"n":"Day","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"n":"Sunset","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"n":"Night","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Ambient","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Sunlight","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Sun","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Stars","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Sky-Lower","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Horizon","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Effect Lighting","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Cloud LOD Diffuse","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Cloud LOD Ambient","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Fog Far","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Sky Statics","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Water Multiplier","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Sun Glare","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Moon Glare","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]}]},{"t":6,"s":1,"p":1,"n":"FNAM - Fog Distance","c":[{"t":5,"p":1,"n":"Day - Near"},{"t":5,"p":1,"n":"Day - Far"},{"t":5,"p":1,"n":"Night - Near"},{"t":5,"p":1,"n":"Night - Far"},{"t":5,"p":1,"n":"Day - Power"},{"t":5,"p":1,"n":"Night - Power"},{"t":5,"p":1,"n":"Day - Max"},{"t":5,"p":1,"n":"Night - Max"}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Wind Speed"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Trans Delta"},{"t":3,"p":1,"n":"Sun Glare"},{"t":3,"p":1,"n":"Sun Damage"},{"t":3,"p":1,"n":"Precipitation - Begin Fade In"},{"t":3,"p":1,"n":"Precipitation - End Fade Out"},{"t":3,"p":1,"n":"Thunder\/Lightning - Begin Fade In"},{"t":3,"p":1,"n":"Thunder\/Lightning - End Fade Out"},{"t":3,"p":1,"n":"Thunder\/Lightning - Frequency"},{"t":3,"p":1,"n":"Flags"},{"t":6,"p":1,"n":"Lightning Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"}]},{"t":3,"p":1,"n":"Visual Effect - Begin"},{"t":3,"p":1,"n":"Visual Effect - End"},{"t":3,"p":1,"n":"Wind Direction"},{"t":3,"p":1,"n":"Wind Direction Range"}]},{"t":3,"p":1,"n":"NAM1 - Disabled Cloud Layers"},{"t":8,"s":1,"p":1,"n":"Sounds","d":1,"c":[{"t":6,"p":1,"n":"SNAM - Sound","c":[{"t":3,"p":1,"n":"Sound"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Sky Statics","d":1,"c":[{"t":3,"p":1,"n":"TNAM - Static"}]},{"t":6,"s":1,"p":1,"n":"IMSP - Image Spaces","c":[{"t":3,"p":1,"n":"Sunrise"},{"t":3,"p":1,"n":"Day"},{"t":3,"p":1,"n":"Sunset"},{"t":3,"p":1,"n":"Night"}]},{"t":6,"s":1,"p":1,"n":"HNAM - Volumetric Lighting","c":[{"t":3,"p":1,"n":"Sunrise"},{"t":3,"p":1,"n":"Day"},{"t":3,"p":1,"n":"Sunset"},{"t":3,"p":1,"n":"Night"}]},{"t":6,"s":1,"p":1,"n":"Directional Ambient Lighting Colors","c":[{"t":6,"p":1,"n":"DALC - Sunrise","c":[{"t":6,"p":1,"n":"Directional","c":[{"t":6,"p":1,"n":"X+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"X-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Specular","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Scale"}]},{"t":6,"p":1,"n":"DALC - Day","c":[{"t":6,"p":1,"n":"Directional","c":[{"t":6,"p":1,"n":"X+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"X-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Specular","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Scale"}]},{"t":6,"p":1,"n":"DALC - Sunset","c":[{"t":6,"p":1,"n":"Directional","c":[{"t":6,"p":1,"n":"X+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"X-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Specular","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Scale"}]},{"t":6,"p":1,"n":"DALC - Night","c":[{"t":6,"p":1,"n":"Directional","c":[{"t":6,"p":1,"n":"X+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"X-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Specular","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Scale"}]}]},{"t":11,"n":"NAM2 - Unused"},{"t":11,"n":"NAM3 - Unused"},{"t":6,"s":1,"p":1,"n":"Aurora","c":[{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]}]},{"t":3,"p":1,"n":"GNAM - Sun Glare Lens Flare"}]},{"t":1,"p":1,"n":"ACHR - Placed NPC","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Base"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":11,"n":"XRGD - Ragdoll Data"},{"t":11,"n":"XRGB - Ragdoll Biped Data"},{"t":6,"s":1,"p":1,"n":"Patrol Data","c":[{"t":5,"p":1,"n":"XPRD - Idle Time"},{"p":1,"n":"XPPA - Patrol Script Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":6,"n":"Unused","c":[{"t":11,"n":"SCHR - Unknown"},{"t":11,"n":"SCDA - Unknown"},{"t":11,"n":"SCTX - Unknown"},{"t":11,"n":"QNAM - Unknown"},{"t":11,"n":"SCRO - Unknown"}]},{"t":8,"p":1,"n":"Topic","c":[{"t":6,"p":1,"n":"PDTO - Topic Data","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Topic"},{"t":2,"p":1,"n":"Subtype"}]}]},{"t":3,"p":1,"n":"TNAM - Topic"}]},{"t":3,"p":1,"n":"XLCM - Level Modifier"},{"t":3,"p":1,"n":"XMRC - Merchant Container"},{"t":3,"p":1,"n":"XCNT - Count"},{"t":5,"p":1,"n":"XRDS - Radius"},{"t":5,"p":1,"n":"XHLP - Health"},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":6,"s":1,"p":1,"n":"XCLP - Linked Reference Color","c":[{"t":6,"p":1,"n":"Link Start Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Link End Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":3,"p":1,"n":"XLCN - Persistent Location"},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"t":3,"p":1,"n":"XHOR - Horse"},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIBS - Ignored By Sandbox"},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]}]},"name":"Smash.All","hash":"B5A65E9D","color":128} ================================================ FILE: frontend/settings/Skyrim/Smash.ForceAll.json ================================================ {"records":"AACT,ACTI,ADDN,ALCH,AMMO,ANIO,APPA,ARMA,ARMO,ARTO,ASPC,ASTP,AVIF,BOOK,BPTD,CAMS,CELL,CLAS,CLDC,CLFM,CLMT,COBJ,COLL,CONT,CPTH,CSTY,DEBR,DIAL,DLBR,DLVW,DOOR,DUAL,ECZN,EFSH,ENCH,EQUP,EXPL,EYES,FACT,FLOR,FLST,FSTP,FSTS,FURN,GLOB,GMST,GRAS,HAIR,HAZD,HDPT,IDLM,IMAD,IMGS,INFO,INGR,IPCT,IPDS,KEYM,KYWD,LAND,LCRT,LENS,LGTM,LIGH,LSCR,LTEX,LVLI,LVLN,LVSP,MATO,MATT,MESG,MGEF,MISC,MOVT,MSTT,MUSC,MUST,NPC_,OTFT,PACK,PARW,PBAR,PBEA,PCON,PERK,PFLA,PGRE,PHZD,PMIS,PROJ,PWAT,QUST,RACE,REFR,REGN,RELA,REVB,RFCT,RGDL,SCEN,SCOL,SCPT,SCRL,SHOU,SLGM,SMBN,SMEN,SMQN,SNCT,SNDR,SOPM,SOUN,SPEL,SPGD,STAT,TACT,TREE,TXST,VOLI,VTYP,WATR,WEAP,WOOP,WRLD,WTHR,ACHR","description":"Forces the smashed patch to use records from the plugin this is applied to, and only allows changes in plugins that require the plugin this is applied to when resolving further conflicts.","tree":{"records":[{"t":1,"p":1,"n":"AACT - Action","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"CNAM - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":1,"p":1,"n":"ACTI - Activator","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"PNAM - Marker Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":3,"n":"Unused"}]},{"t":3,"p":1,"n":"SNAM - Sound - Looping"},{"t":3,"p":1,"n":"VNAM - Sound - Activation"},{"t":3,"p":1,"n":"WNAM - Water Type"},{"t":2,"p":1,"n":"RNAM - Activate Text Override"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":3,"p":1,"n":"KNAM - Interaction Keyword"}]},{"t":1,"p":1,"n":"ADDN - Addon Node","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":3,"p":1,"n":"DATA - Node Index"},{"t":3,"p":1,"n":"SNAM - Sound"},{"t":6,"s":1,"p":1,"n":"DNAM - Data","c":[{"t":3,"p":1,"n":"Master Particle System Cap"},{"t":3,"p":1,"n":"Flags"}]}]},{"t":1,"p":1,"n":"ALCH - Ingestible","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":3,"p":1,"n":"ETYP - Equipment Type"},{"t":5,"p":1,"n":"DATA - Weight"},{"t":6,"s":1,"p":1,"n":"ENIT - Effect Data","c":[{"t":3,"p":1,"n":"Value"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Addiction"},{"t":5,"p":1,"n":"Addiction Chance"},{"t":3,"p":1,"n":"Sound - Consume"}]},{"t":8,"s":1,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":3,"p":1,"n":"EFID - Base Effect"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":5,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"}]},{"t":8,"s":1,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]}]},{"t":1,"p":1,"n":"AMMO - Ammunition","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":2,"p":1,"n":"DESC - Description"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Projectile"},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Damage"},{"t":3,"p":1,"n":"Value"}]},{"t":2,"p":1,"n":"ONAM - Short Name"}]},{"t":1,"p":1,"n":"ANIO - Animated Object","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":2,"p":1,"n":"BNAM - Unload Event"}]},{"t":1,"p":1,"n":"APPA - Alchemical Apparatus","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":3,"p":1,"n":"QUAL - Quality"},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]}]},{"t":1,"p":1,"n":"ARMA - Armor Addon","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"BOD2 - Biped Body Template","c":[{"t":3,"p":1,"n":"First Person Flags"},{"t":3,"p":1,"n":"General Flags"},{"n":"Unused"},{"t":3,"p":1,"n":"Armor Type"}],"lt":"BODT - Body Template","lf":"BODT - Body Template"},{"t":6,"s":1,"p":1,"n":"BODT - Body Template","c":[{"t":3,"p":1,"n":"First Person Flags"},{"t":3,"p":1,"n":"General Flags"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Armor Type"}],"lt":"BOD2 - Biped Body Template","lf":"BOD2 - Biped Body Template"},{"t":3,"p":1,"n":"RNAM - Race"},{"t":6,"s":1,"p":1,"n":"DNAM - Data","c":[{"t":3,"p":1,"n":"Male Priority"},{"t":3,"p":1,"n":"Female Priority"},{"t":3,"p":1,"n":"Weight slider - Male"},{"t":3,"p":1,"n":"Weight slider - Female"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Detection Sound Value"},{"t":5,"p":1,"n":"Weapon Adjust"}]},{"t":6,"s":1,"p":1,"n":"Male world model","c":[{"t":2,"p":1,"n":"MOD2 - Model Filename"},{"t":11,"p":1,"n":"MO2T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO2S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Female world model","c":[{"t":2,"p":1,"n":"MOD3 - Model Filename"},{"t":11,"p":1,"n":"MO3T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO3S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Male 1st Person","c":[{"t":2,"p":1,"n":"MOD4 - Model Filename"},{"t":11,"p":1,"n":"MO4T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO4S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Female 1st Person","c":[{"t":2,"p":1,"n":"MOD5 - Model Filename"},{"t":11,"p":1,"n":"MO5T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO5S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":3,"p":1,"n":"NAM0 - Male Skin Texture"},{"t":3,"p":1,"n":"NAM1 - Female Skin texture"},{"t":3,"p":1,"n":"NAM2 - Male Skin Texture Swap List"},{"t":3,"p":1,"n":"NAM3 - Female Skin Texture Swap List"},{"t":8,"s":1,"p":1,"n":"Additional Races","d":1,"c":[{"t":3,"p":1,"n":"MODL - Race"}]},{"t":3,"p":1,"n":"SNDD - Footstep Sound"},{"t":3,"p":1,"n":"ONAM - Art Object"}]},{"t":1,"p":1,"n":"ARMO - Armor","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"EITM - Object Effect"},{"t":3,"p":1,"n":"EAMT - Enchantment Amount"},{"t":6,"s":1,"p":1,"n":"Male world model","c":[{"t":2,"p":1,"n":"MOD2 - Model Filename"},{"t":11,"p":1,"n":"MO2T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO2S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"Female world model","c":[{"t":2,"p":1,"n":"MOD4 - Model Filename"},{"t":11,"p":1,"n":"MO4T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO4S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Icon 2 (female)","c":[{"t":2,"p":1,"n":"ICO2 - Large Icon filename"},{"t":2,"p":1,"n":"MIC2 - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"BOD2 - Biped Body Template","c":[{"t":3,"p":1,"n":"First Person Flags"},{"t":3,"p":1,"n":"General Flags"},{"n":"Unused"},{"t":3,"p":1,"n":"Armor Type"}],"lt":"BODT - Body Template","lf":"BODT - Body Template"},{"t":6,"s":1,"p":1,"n":"BODT - Body Template","c":[{"t":3,"p":1,"n":"First Person Flags"},{"t":3,"p":1,"n":"General Flags"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Armor Type"}],"lt":"BOD2 - Biped Body Template","lf":"BOD2 - Biped Body Template"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":2,"p":1,"n":"BMCT - Ragdoll Constraint Template"},{"t":3,"p":1,"n":"ETYP - Equipment Type"},{"t":3,"p":1,"n":"BIDS - Bash Impact Data Set"},{"t":3,"p":1,"n":"BAMT - Alternate Block Material"},{"t":3,"p":1,"n":"RNAM - Race"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":2,"p":1,"n":"DESC - Description"},{"t":8,"s":1,"p":1,"n":"Armature","d":1,"c":[{"t":3,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":3,"p":1,"n":"DNAM - Armor Rating"},{"t":3,"p":1,"n":"TNAM - Template Armor"}]},{"t":1,"p":1,"n":"ARTO - Art Object","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":3,"p":1,"n":"DNAM - Art Type"}]},{"t":1,"p":1,"n":"ASPC - Acoustic Space","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"SNAM - Ambient Sound"},{"t":3,"p":1,"n":"RDAT - Use Sound from Region (Interiors Only)"},{"t":3,"p":1,"n":"BNAM - Environment Type (reverb)"}]},{"t":1,"p":1,"n":"ASTP - Association Type","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"MPRT - Male Parent Title"},{"t":2,"p":1,"n":"FPRT - Female Parent Title"},{"t":2,"p":1,"n":"MCHT - Male Child Title"},{"t":2,"p":1,"n":"FCHT - Female Child Title"},{"t":3,"p":1,"n":"DATA - Flags"}]},{"t":1,"p":1,"n":"AVIF - Actor Value Information","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"DESC - Description"},{"t":2,"p":1,"n":"ANAM - Abbreviation"},{"t":11,"n":"CNAM - Unknown"},{"t":6,"s":1,"p":1,"n":"AVSK - Skill","c":[{"t":5,"p":1,"n":"Skill Use Mult"},{"t":5,"p":1,"n":"Skill Offset Mult"},{"t":5,"p":1,"n":"Skill Improve Mult"},{"t":5,"p":1,"n":"Skill Improve Offset"}]},{"t":8,"s":1,"p":1,"n":"Perk Tree","d":1,"c":[{"t":6,"p":1,"n":"Node","c":[{"t":3,"p":1,"n":"PNAM - Perk"},{"t":11,"n":"FNAM - Unknown"},{"t":3,"p":1,"n":"XNAM - Perk-Grid X"},{"t":3,"p":1,"n":"YNAM - Perk-Grid Y"},{"t":5,"p":1,"n":"HNAM - Horizontal Position"},{"t":5,"p":1,"n":"VNAM - Vertical Position"},{"t":3,"p":1,"n":"SNAM - Associated Skill"},{"t":8,"p":1,"n":"Connections","c":[{"t":3,"p":1,"n":"CNAM - Line to Index"}]},{"t":3,"p":1,"n":"INAM - Index"}]}]}]},{"t":1,"p":1,"n":"BOOK - Book","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":2,"p":1,"n":"DESC - Book Text"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Skill"},{"t":3,"p":1,"n":"Spell"},{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":3,"p":1,"n":"INAM - Inventory Art"},{"t":2,"p":1,"n":"CNAM - Description"}]},{"t":1,"p":1,"n":"BPTD - Body Part Data","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":10,"p":1,"n":"Body Parts","d":1,"c":[{"t":6,"p":1,"n":"Body Part","c":[{"t":2,"p":1,"n":"BPTN - Part Name"},{"t":2,"p":1,"n":"PNAM - Pose Matching"},{"t":2,"p":1,"n":"BPNN - Part Node"},{"t":2,"p":1,"n":"BPNT - VATS Target"},{"t":2,"p":1,"n":"BPNI - IK Data - Start Node"},{"t":6,"p":1,"n":"BPND - ","c":[{"t":5,"p":1,"n":"Damage Mult"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Part Type"},{"t":3,"p":1,"n":"Health Percent"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"To Hit Chance"},{"t":3,"p":1,"n":"Explodable - Explosion Chance %"},{"t":3,"p":1,"n":"Explodable - Debris Count"},{"t":3,"p":1,"n":"Explodable - Debris"},{"t":3,"p":1,"n":"Explodable - Explosion"},{"t":5,"p":1,"n":"Tracking Max Angle"},{"t":5,"p":1,"n":"Explodable - Debris Scale"},{"t":3,"p":1,"n":"Severable - Debris Count"},{"t":3,"p":1,"n":"Severable - Debris"},{"t":3,"p":1,"n":"Severable - Explosion"},{"t":5,"p":1,"n":"Severable - Debris Scale"},{"t":6,"p":1,"n":"Gore Effects Positioning","c":[{"t":6,"p":1,"n":"Translate","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]},{"t":3,"p":1,"n":"Severable - Impact DataSet"},{"t":3,"p":1,"n":"Explodable - Impact DataSet"},{"t":3,"p":1,"n":"Severable - Decal Count"},{"t":3,"p":1,"n":"Explodable - Decal Count"},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"Limb Replacement Scale"}]},{"t":2,"p":1,"n":"NAM1 - Limb Replacement Model"},{"t":2,"p":1,"n":"NAM4 - Gore Effects - Target Bone"},{"t":11,"p":1,"n":"NAM5 - Texture Files Hashes"}]}]}]},{"t":1,"p":1,"n":"CAMS - Camera Shot","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Action"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Flags"},{"t":6,"p":1,"n":"Time Multipliers","c":[{"t":5,"p":1,"n":"Player"},{"t":5,"p":1,"n":"Target"},{"t":5,"p":1,"n":"Global"}]},{"t":5,"p":1,"n":"Max Time"},{"t":5,"p":1,"n":"Min Time"},{"t":5,"p":1,"n":"Target % Between Actors"},{"t":5,"p":1,"n":"Near Target Distance"}]},{"t":3,"p":1,"n":"MNAM - Image Space Modifier"}]},{"t":1,"p":1,"n":"CELL - Cell","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"DATA - Flags"},{"t":6,"s":1,"p":1,"n":"XCLC - Grid","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"},{"t":3,"p":1,"n":"Force Hide Land"}]},{"t":6,"s":1,"p":1,"n":"XCLL - Lighting","c":[{"t":6,"p":1,"n":"Ambient Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Directional Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Fog Color Near","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Fog Near"},{"t":5,"p":1,"n":"Fog Far"},{"t":3,"p":1,"n":"Directional Rotation XY"},{"t":3,"p":1,"n":"Directional Rotation Z"},{"t":5,"p":1,"n":"Directional Fade"},{"t":5,"p":1,"n":"Fog Clip Distance"},{"t":5,"p":1,"n":"Fog Power"},{"t":6,"p":1,"n":"Ambient Colors","c":[{"t":6,"p":1,"n":"Directional","c":[{"t":6,"p":1,"n":"X+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"X-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Specular","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Scale"}]},{"t":6,"p":1,"n":"Fog Color Far","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Fog Max"},{"t":5,"p":1,"n":"Light Fade Begin"},{"t":5,"p":1,"n":"Light Fade End"},{"t":3,"p":1,"n":"Inherits"}]},{"t":11,"n":"TVDT - Occlusion Data"},{"t":11,"n":"MHDT - Max Height Data"},{"t":3,"p":1,"n":"LTMP - Lighting Template"},{"t":11,"n":"LNAM - Unknown"},{"t":5,"p":1,"n":"XCLW - Water Height"},{"t":2,"p":1,"n":"XNAM - Water Noise Texture"},{"t":7,"p":1,"n":"XCLR - Regions","c":[{"t":3,"p":1,"n":"Region"}]},{"t":3,"p":1,"n":"XLCN - Location"},{"t":11,"n":"XWCN - Unknown"},{"t":11,"n":"XWCS - Unknown"},{"t":6,"s":1,"p":1,"n":"XWCU - Water Velocity","c":[{"t":5,"p":1,"n":"X Offset"},{"t":5,"p":1,"n":"Y Offset"},{"t":5,"p":1,"n":"Z Offset"},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"X Angle"},{"t":5,"p":1,"n":"Y Angle"},{"t":5,"p":1,"n":"Z Angle"}]},{"t":3,"p":1,"n":"XCWT - Water"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":3,"p":1,"n":"XILL - Lock List"},{"t":2,"p":1,"n":"XWEM - Water Environment Map"},{"t":3,"p":1,"n":"XCCM - Sky\/Weather from Region"},{"t":3,"p":1,"n":"XCAS - Acoustic Space"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":3,"p":1,"n":"XCMO - Music Type"},{"t":3,"p":1,"n":"XCIM - Image Space"}]},{"t":1,"p":1,"n":"CLAS - Class","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Teaches"},{"t":3,"p":1,"n":"Maximum training level"},{"t":7,"p":1,"n":"Skill Weights","c":[{"t":3,"p":1,"n":"Weight"}]},{"t":5,"p":1,"n":"Bleedout Default"},{"t":3,"p":1,"n":"Voice Points"},{"t":7,"p":1,"n":"Attribute Weights","c":[{"t":3,"p":1,"n":"Weight"}]}]}]},{"t":1,"p":1,"n":"CLDC","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"}]},{"t":1,"p":1,"n":"CLFM - Color","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"CNAM - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":3,"p":1,"n":"FNAM - Playable"}]},{"t":1,"p":1,"n":"CLMT - Climate","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":7,"p":1,"n":"WLST - Weather Types","c":[{"t":6,"p":1,"n":"Weather Type","c":[{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Chance"},{"t":3,"p":1,"n":"Global"}]}]},{"t":2,"p":1,"n":"FNAM - Sun Texture"},{"t":2,"p":1,"n":"GNAM - Sun Glare Texture"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"TNAM - Timing","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Begin"},{"t":3,"p":1,"n":"End"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Begin"},{"t":3,"p":1,"n":"End"}]},{"t":3,"p":1,"n":"Volatility"},{"t":3,"p":1,"n":"Moons \/ Phase Length"}]}]},{"t":1,"p":1,"n":"COBJ - Constructible Object","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"n":"COCT - Count"},{"t":10,"p":1,"n":"Items","d":1,"c":[{"t":6,"p":1,"n":"Item","c":[{"t":6,"p":1,"n":"CNTO - Item","c":[{"t":3,"p":1,"n":"Item"},{"t":3,"p":1,"n":"Count"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":3,"p":1,"n":"CNAM - Created Object"},{"t":3,"p":1,"n":"BNAM - Workbench Keyword"},{"t":3,"p":1,"n":"NAM1 - Created Object Count"}]},{"t":1,"p":1,"n":"COLL - Collision Layer","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"DESC - Description"},{"t":3,"p":1,"n":"BNAM - Index"},{"t":6,"s":1,"p":1,"n":"FNAM - Debug Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":3,"n":"Unused"}]},{"t":3,"p":1,"n":"GNAM - Flags"},{"t":2,"p":1,"n":"MNAM - Name"},{"t":3,"n":"INTV - Interactables Count"},{"t":7,"p":1,"n":"CNAM - Collides With","c":[{"t":3,"p":1,"n":"Forms"}]}]},{"t":1,"p":1,"n":"CONT - Container","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":3,"n":"COCT - Count"},{"t":10,"p":1,"n":"Items","d":1,"c":[{"t":6,"p":1,"n":"Item","c":[{"t":6,"p":1,"n":"CNTO - Item","c":[{"t":3,"p":1,"n":"Item"},{"t":3,"p":1,"n":"Count"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Weight"}]},{"t":3,"p":1,"n":"SNAM - Sound - Open"},{"t":3,"p":1,"n":"QNAM - Sound - Close"}]},{"t":1,"p":1,"n":"CPTH - Camera Path","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":7,"p":1,"n":"ANAM - Related Camera Paths","c":[{"t":3,"p":1,"n":"Related Camera Path"}]},{"t":3,"p":1,"n":"DATA - Camera Zoom"},{"t":8,"s":1,"p":1,"n":"Camera Shots","d":1,"c":[{"t":3,"p":1,"n":"SNAM - Camera Shot"}]}]},{"t":1,"p":1,"n":"CSTY - Combat Style","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"CSGD - General","c":[{"t":5,"p":1,"n":"Offensive Mult"},{"t":5,"p":1,"n":"Defensive Mult"},{"t":5,"p":1,"n":"Group Offensive Mult"},{"t":5,"p":1,"n":"Equipment Score Mult - Melee"},{"t":5,"p":1,"n":"Equipment Score Mult - Magic"},{"t":5,"p":1,"n":"Equipment Score Mult - Ranged"},{"t":5,"p":1,"n":"Equipment Score Mult - Shout"},{"t":5,"p":1,"n":"Equipment Score Mult - Unarmed"},{"t":5,"p":1,"n":"Equipment Score Mult - Staff"},{"t":5,"p":1,"n":"Avoid Threat Chance"}]},{"t":11,"n":"CSMD - Unknown"},{"t":6,"s":1,"p":1,"n":"CSME - Melee","c":[{"t":5,"p":1,"n":"Attack Staggered Mult"},{"t":5,"p":1,"n":"Power Attack Staggered Mult"},{"t":5,"p":1,"n":"Power Attack Blocking Mult"},{"t":5,"p":1,"n":"Bash Mult"},{"t":5,"p":1,"n":"Bash Recoil Mult"},{"t":5,"p":1,"n":"Bash Attack Mult"},{"t":5,"p":1,"n":"Bash Power Attack Mult"},{"t":5,"p":1,"n":"Special Attack Mult"}]},{"t":6,"s":1,"p":1,"n":"CSCR - Close Range","c":[{"t":5,"p":1,"n":"Circle Mult"},{"t":5,"p":1,"n":"Fallback Mult"},{"t":5,"p":1,"n":"Flank Distance"},{"t":5,"p":1,"n":"Stalk Time"}]},{"t":6,"s":1,"p":1,"n":"CSLR - Long Range","c":[{"t":5,"p":1,"n":"Strafe Mult"}]},{"t":6,"s":1,"p":1,"n":"CSFL - Flight","c":[{"t":5,"p":1,"n":"Hover Chance"},{"t":5,"p":1,"n":"Dive Bomb Chance"},{"t":5,"p":1,"n":"Ground Attack Chance"},{"t":5,"p":1,"n":"Hover Time"},{"t":5,"p":1,"n":"Ground Attack Time"},{"t":5,"p":1,"n":"Perch Attack Chance"},{"t":5,"p":1,"n":"Perch Attack Time"},{"t":5,"p":1,"n":"Flying Attack Chance"}]},{"t":3,"p":1,"n":"DATA - Flags"}]},{"t":1,"p":1,"n":"DEBR - Debris","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":8,"s":1,"p":1,"n":"Models","d":1,"c":[{"t":6,"p":1,"n":"Model","c":[{"t":6,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Percentage"},{"t":2,"p":1,"n":"Model Filename"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]}]}]},{"t":1,"p":1,"n":"DIAL - Dialog Topic","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":5,"p":1,"n":"PNAM - Priority"},{"t":3,"p":1,"n":"BNAM - Branch"},{"t":3,"p":1,"n":"QNAM - Quest"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Topic Flags"},{"t":3,"p":1,"n":"Category"},{"t":3,"p":1,"n":"Subtype"}]},{"t":2,"p":1,"n":"SNAM - Subtype Name"},{"t":3,"p":1,"n":"TIFC - Info Count"}]},{"t":1,"p":1,"n":"DLBR - Dialog Branch","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"QNAM - Quest"},{"t":3,"n":"TNAM - Unknown"},{"t":3,"p":1,"n":"DNAM - Flags"},{"t":3,"p":1,"n":"SNAM - Starting Topic"}]},{"t":1,"p":1,"n":"DLVW - Dialog View","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"QNAM - Quest"},{"t":8,"s":1,"p":1,"n":"Branches","d":1,"c":[{"t":3,"p":1,"n":"BNAM - Branch"}]},{"t":8,"n":"Unknown TNAM","c":[{"t":6,"n":"Unknown","c":[{"t":11,"n":"TNAM - Unknown"}]}]},{"t":11,"n":"ENAM - Unknown"},{"t":11,"n":"DNAM - Unknown"}]},{"t":1,"n":"DOBJ - Default Object Manager","c":[{"t":2,"n":"EDID - Editor ID"},{"t":7,"n":"DNAM - Objects","c":[{"t":6,"n":"Object","c":[{"t":3,"n":"Use"},{"t":3,"n":"Object ID"}]}]}]},{"t":1,"p":1,"n":"DOOR - Door","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"SNAM - Sound - Open"},{"t":3,"p":1,"n":"ANAM - Sound - Close"},{"t":3,"p":1,"n":"BNAM - Sound - Loop"},{"t":3,"p":1,"n":"FNAM - Flags"}]},{"t":1,"p":1,"n":"DUAL - Dual Cast Data","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Projectile"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Effect Shader"},{"t":3,"p":1,"n":"Hit Effect Art"},{"t":3,"p":1,"n":"Impact Data Set"},{"t":3,"p":1,"n":"Inherit Scale"}]}]},{"t":1,"p":1,"n":"ECZN - Encounter Zone","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Rank"},{"t":3,"p":1,"n":"Min Level"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Max Level"}]}]},{"t":1,"p":1,"n":"EFSH - Effect Shader","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"ICON - Fill Texture"},{"t":2,"p":1,"n":"ICO2 - Particle Shader Texture"},{"t":2,"p":1,"n":"NAM7 - Holes Texture"},{"t":2,"p":1,"n":"NAM8 - Membrane Palette Texture"},{"t":2,"p":1,"n":"NAM9 - Particle Palette Texture"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Membrane Shader - Source Blend Mode"},{"t":3,"p":1,"n":"Membrane Shader - Blend Operation"},{"t":3,"p":1,"n":"Membrane Shader - Z Test Function"},{"t":6,"p":1,"n":"Fill\/Texture Effect - Color Key 1","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Fade In Time"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Full Alpha Time"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Fade Out Time"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Presistent Alpha Ratio"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Pulse Amplitude"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Pulse Frequency"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Animation Speed (U)"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Animation Speed (V)"},{"t":5,"p":1,"n":"Edge Effect - Fall Off"},{"t":6,"p":1,"n":"Edge Effect - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Edge Effect - Alpha Fade In Time"},{"t":5,"p":1,"n":"Edge Effect - Full Alpha Time"},{"t":5,"p":1,"n":"Edge Effect - Alpha Fade Out Time"},{"t":5,"p":1,"n":"Edge Effect - Persistent Alpha Ratio"},{"t":5,"p":1,"n":"Edge Effect - Alpha Pulse Amplitude"},{"t":5,"p":1,"n":"Edge Effect - Alpha Pulse Frequency"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Full Alpha Ratio"},{"t":5,"p":1,"n":"Edge Effect - Full Alpha Ratio"},{"t":3,"p":1,"n":"Membrane Shader - Dest Blend Mode"},{"t":3,"p":1,"n":"Particle Shader - Source Blend Mode"},{"t":3,"p":1,"n":"Particle Shader - Blend Operation"},{"t":3,"p":1,"n":"Particle Shader - Z Test Function"},{"t":3,"p":1,"n":"Particle Shader - Dest Blend Mode"},{"t":5,"p":1,"n":"Particle Shader - Particle Birth Ramp Up Time"},{"t":5,"p":1,"n":"Particle Shader - Full Particle Birth Time"},{"t":5,"p":1,"n":"Particle Shader - Particle Birth Ramp Down Time"},{"t":5,"p":1,"n":"Particle Shader - Full Particle Birth Ratio"},{"t":5,"p":1,"n":"Particle Shader - Persistant Particle Count"},{"t":5,"p":1,"n":"Particle Shader - Particle Lifetime"},{"t":5,"p":1,"n":"Particle Shader - Particle Lifetime +\/-"},{"t":5,"p":1,"n":"Particle Shader - Initial Speed Along Normal"},{"t":5,"p":1,"n":"Particle Shader - Acceleration Along Normal"},{"t":5,"p":1,"n":"Particle Shader - Initial Velocity #1"},{"t":5,"p":1,"n":"Particle Shader - Initial Velocity #2"},{"t":5,"p":1,"n":"Particle Shader - Initial Velocity #3"},{"t":5,"p":1,"n":"Particle Shader - Acceleration #1"},{"t":5,"p":1,"n":"Particle Shader - Acceleration #2"},{"t":5,"p":1,"n":"Particle Shader - Acceleration #3"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 1"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 2"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 1 Time"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 2 Time"},{"t":6,"p":1,"n":"Color Key 1 - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Color Key 2 - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Color Key 3 - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Color Key 1 - Color Alpha"},{"t":5,"p":1,"n":"Color Key 2 - Color Alpha"},{"t":5,"p":1,"n":"Color Key 3 - Color Alpha"},{"t":5,"p":1,"n":"Color Key 1 - Color Key Time"},{"t":5,"p":1,"n":"Color Key 2 - Color Key Time"},{"t":5,"p":1,"n":"Color Key 3 - Color Key Time"},{"t":5,"p":1,"n":"Particle Shader - Initial Speed Along Normal +\/-"},{"t":5,"p":1,"n":"Particle Shader - Initial Rotation (deg)"},{"t":5,"p":1,"n":"Particle Shader - Initial Rotation (deg) +\/-"},{"t":5,"p":1,"n":"Particle Shader - Rotation Speed (deg\/sec)"},{"t":5,"p":1,"n":"Particle Shader - Rotation Speed (deg\/sec) +\/-"},{"t":3,"p":1,"n":"Addon Models"},{"t":5,"p":1,"n":"Holes - Start Time"},{"t":5,"p":1,"n":"Holes - End Time"},{"t":5,"p":1,"n":"Holes - Start Val"},{"t":5,"p":1,"n":"Holes - End Val"},{"t":5,"p":1,"n":"Edge Width (alpha units)"},{"t":6,"p":1,"n":"Edge Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Explosion Wind Speed"},{"t":3,"p":1,"n":"Texture Count U"},{"t":3,"p":1,"n":"Texture Count V"},{"t":5,"p":1,"n":"Addon Models - Fade In Time"},{"t":5,"p":1,"n":"Addon Models - Fade Out Time"},{"t":5,"p":1,"n":"Addon Models - Scale Start"},{"t":5,"p":1,"n":"Addon Models - Scale End"},{"t":5,"p":1,"n":"Addon Models - Scale In Time"},{"t":5,"p":1,"n":"Addon Models - Scale Out Time"},{"t":3,"p":1,"n":"Ambient Sound"},{"t":6,"p":1,"n":"Fill\/Texture Effect - Color Key 2","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Fill\/Texture Effect - Color Key 3","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Fill\/Texture Effect - Color Key Scale\/Time","c":[{"t":5,"p":1,"n":"Color Key 1 - Scale"},{"t":5,"p":1,"n":"Color Key 2 - Scale"},{"t":5,"p":1,"n":"Color Key 3 - Scale"},{"t":5,"p":1,"n":"Color Key 1 - Time"},{"t":5,"p":1,"n":"Color Key 2 - Time"},{"t":5,"p":1,"n":"Color Key 3 - Time"}]},{"t":5,"p":1,"n":"Color Scale"},{"t":5,"p":1,"n":"Birth Position Offset"},{"t":5,"p":1,"n":"Birth Position Offset Range +\/-"},{"t":6,"p":1,"n":"Particle Shader Animated","c":[{"t":3,"p":1,"n":"Start Frame"},{"t":3,"p":1,"n":"Start Frame Variation"},{"t":3,"p":1,"n":"End Frame"},{"t":3,"p":1,"n":"Loop Start Frame"},{"t":3,"p":1,"n":"Loop Start Variation"},{"t":3,"p":1,"n":"Frame Count"},{"t":3,"p":1,"n":"Frame Count Variation"}]},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Scale (U)"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Scale (V)"},{"t":3,"p":1,"n":"Scene Graph Emit Depth Limit (unused)"}]}]},{"t":1,"p":1,"n":"ENCH - Object Effect","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"ENIT - Effect Data","c":[{"t":3,"p":1,"n":"Enchantment Cost"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Cast Type"},{"t":3,"p":1,"n":"Enchantment Amount"},{"t":3,"p":1,"n":"Target Type"},{"t":3,"p":1,"n":"Enchant Type"},{"t":5,"p":1,"n":"Charge Time"},{"t":3,"p":1,"n":"Base Enchantment"},{"t":3,"p":1,"n":"Worn Restrictions"}]},{"t":8,"s":1,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":3,"p":1,"n":"EFID - Base Effect"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":5,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"}]},{"t":8,"s":1,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]}]},{"t":1,"p":1,"n":"EQUP - Equip Type","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":7,"p":1,"n":"PNAM - Slot Parents","c":[{"t":3,"p":1,"n":"Can Be Equipped"}]},{"t":3,"p":1,"n":"DATA - Use All Parents"}]},{"t":1,"p":1,"n":"EXPL - Explosion","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":3,"p":1,"n":"EITM - Object Effect"},{"t":3,"p":1,"n":"MNAM - Image Space Modifier"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Light"},{"t":3,"p":1,"n":"Sound 1"},{"t":3,"p":1,"n":"Sound 2"},{"t":3,"p":1,"n":"Impact Data Set"},{"t":3,"p":1,"n":"Placed Object"},{"t":3,"p":1,"n":"Spawn Projectile"},{"t":5,"p":1,"n":"Force"},{"t":5,"p":1,"n":"Damage"},{"t":5,"p":1,"n":"Radius"},{"t":5,"p":1,"n":"IS Radius"},{"t":5,"p":1,"n":"Vertical Offset Mult"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Sound Level"}]}]},{"t":1,"p":1,"n":"EYES - Eyes","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"ICON - Texture"},{"t":3,"p":1,"n":"DATA - Flags"}]},{"t":1,"p":1,"n":"FACT - Faction","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":8,"s":1,"p":1,"n":"Relations","d":1,"c":[{"t":6,"p":1,"n":"XNAM - Relation","c":[{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Modifier"},{"t":3,"p":1,"n":"Group Combat Reaction"}]}]},{"t":6,"s":1,"p":1,"n":"DATA - Flags","c":[{"t":3,"p":1,"n":"Flags"}]},{"t":3,"p":1,"n":"JAIL - Exterior Jail Marker"},{"t":3,"p":1,"n":"WAIT - Follower Wait Marker"},{"t":3,"p":1,"n":"STOL - Stolen Goods Container"},{"t":3,"p":1,"n":"PLCN - Player Inventory Container"},{"t":3,"p":1,"n":"CRGR - Shared Crime Faction List"},{"t":3,"p":1,"n":"JOUT - Jail Outfit"},{"t":6,"s":1,"p":1,"n":"CRVA - Crime Values","c":[{"t":3,"p":1,"n":"Arrest"},{"t":3,"p":1,"n":"Attack On Sight"},{"t":3,"p":1,"n":"Murder"},{"t":3,"p":1,"n":"Assault"},{"t":3,"p":1,"n":"Trespass"},{"t":3,"p":1,"n":"Pickpocket"},{"t":3,"n":"Unknown"},{"t":5,"p":1,"n":"Steal Multiplier"},{"t":3,"p":1,"n":"Escape"},{"t":3,"p":1,"n":"Werewolf"}]},{"t":10,"p":1,"n":"Ranks","d":1,"c":[{"t":6,"p":1,"n":"Rank","c":[{"t":3,"p":1,"n":"RNAM - Rank#"},{"t":2,"p":1,"n":"MNAM - Male Title"},{"t":2,"p":1,"n":"FNAM - Female Title"},{"t":2,"n":"INAM - Insignia Unused"}]}]},{"t":3,"p":1,"n":"VEND - Vendor Buy\/Sell List"},{"t":3,"p":1,"n":"VENC - Merchant Container"},{"t":6,"s":1,"p":1,"n":"VENV - Vendor Values","c":[{"t":3,"p":1,"n":"Start Hour"},{"t":3,"p":1,"n":"End Hour"},{"t":3,"p":1,"n":"Radius"},{"t":11,"n":"Unknown 1"},{"t":3,"p":1,"n":"Only Buys Stolen Items"},{"t":3,"p":1,"n":"Not\/Sell Buy"},{"t":11,"n":"Unknown 2"}]},{"t":6,"s":1,"p":1,"n":"PLVD - Location","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Cell"},{"t":11,"p":1,"n":"Near Package Start Location"},{"t":11,"p":1,"n":"Near Editor Location"},{"t":3,"p":1,"n":"Object ID"},{"t":3,"p":1,"n":"Object Type"},{"t":3,"p":1,"n":"Keyword"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Radius"}]},{"t":3,"n":"CITC - Condition Count"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]},{"t":1,"p":1,"n":"FLOR - Flora","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":11,"n":"PNAM - Unknown"},{"t":2,"p":1,"n":"RNAM - Activate Text Override"},{"t":11,"n":"FNAM - Unknown"},{"t":3,"p":1,"n":"PFIG - Ingredient"},{"t":3,"p":1,"n":"SNAM - Sound"},{"t":6,"s":1,"p":1,"n":"PFPC - Seasonal ingredient production","c":[{"t":3,"p":1,"n":"Spring"},{"t":3,"p":1,"n":"Summer "},{"t":3,"p":1,"n":"Fall"},{"t":3,"p":1,"n":"Winter"}]}]},{"t":1,"p":1,"n":"FLST - FormID List","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":8,"s":1,"p":1,"n":"FormIDs","d":1,"c":[{"t":3,"p":1,"n":"LNAM - FormID"}]}]},{"t":1,"p":1,"n":"FSTP - Footstep","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"DATA - Impact Data Set"},{"t":2,"p":1,"n":"ANAM - Tag"}]},{"t":1,"p":1,"n":"FSTS - Footstep Set","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"XCNT - Count","c":[{"t":3,"n":"Walk Forward Sets"},{"t":3,"n":"Run Forward Sets"},{"t":3,"n":"Walk Forward Alternate Sets"},{"t":3,"n":"Run Forward Alternate Sets"},{"t":3,"n":"Walk Forward Alternate 2 Sets"}]},{"t":7,"s":1,"p":1,"n":"DATA - Footstep Sets","c":[{"t":3,"p":1,"n":"Footstep"}]}]},{"t":1,"p":1,"n":"FURN - Furniture","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":11,"n":"PNAM - Unknown"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":3,"p":1,"n":"KNAM - Interaction Keyword"},{"t":3,"p":1,"n":"MNAM - Active Markers \/ Flags"},{"t":6,"s":1,"p":1,"n":"WBDT - Workbench Data","c":[{"t":3,"p":1,"n":"Bench Type"},{"t":3,"p":1,"n":"Uses Skill"}]},{"t":3,"p":1,"n":"NAM1 - Associated Spell"},{"t":8,"s":1,"p":1,"n":"Markers","d":1,"c":[{"t":6,"p":1,"n":"Marker","c":[{"t":3,"p":1,"n":"ENAM - Marker Index"},{"t":6,"p":1,"n":"NAM0 - Disabled Entry Points","c":[{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Disabled Points"}]},{"t":3,"p":1,"n":"FNMK - Marker Keyword"}]}]},{"t":8,"s":1,"p":1,"n":"Marker Entry Points","d":1,"c":[{"t":6,"p":1,"n":"FNPR - Marker","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Entry Points"}]}]},{"t":2,"p":1,"n":"XMRK - Model Filename"}]},{"t":1,"p":1,"n":"GLOB - Global","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"FNAM - Type"},{"t":5,"p":1,"n":"FLTV - Value"}]},{"t":1,"p":1,"n":"GMST - Game Setting","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"Name"},{"t":3,"p":1,"n":"Int"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"}]},{"t":1,"p":1,"n":"GRAS - Grass","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Density"},{"t":3,"p":1,"n":"Min Slope"},{"t":3,"p":1,"n":"Max Slope"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Units From Water"},{"t":3,"p":1,"n":"Units From Water Type"},{"t":5,"p":1,"n":"Position Range"},{"t":5,"p":1,"n":"Height Range"},{"t":5,"p":1,"n":"Color Range"},{"t":5,"p":1,"n":"Wave Period"},{"t":3,"p":1,"n":"Flags"}]}]},{"t":1,"p":1,"n":"HAIR","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"}]},{"t":1,"p":1,"n":"HAZD - Hazard","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":3,"p":1,"n":"MNAM - Image Space Modifier"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Limit"},{"t":5,"p":1,"n":"Radius"},{"t":5,"p":1,"n":"Lifetime"},{"t":5,"p":1,"n":"Image Space Radius"},{"t":5,"p":1,"n":"Target Interval"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Spell"},{"t":3,"p":1,"n":"Light"},{"t":3,"p":1,"n":"Impact Data Set"},{"t":3,"p":1,"n":"Sound"}]}]},{"t":1,"p":1,"n":"HDPT - Head Part","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":3,"p":1,"n":"DATA - Flags"},{"t":3,"p":1,"n":"PNAM - Type"},{"t":8,"s":1,"p":1,"n":"Extra Parts","d":1,"c":[{"t":3,"p":1,"n":"HNAM - Part"}]},{"t":8,"s":1,"p":1,"n":"Parts","d":1,"c":[{"t":6,"p":1,"n":"Part","c":[{"t":3,"p":1,"n":"NAM0 - Part Type"},{"t":2,"p":1,"n":"NAM1 - Filename"}]}]},{"t":3,"p":1,"n":"TNAM - Texture Set"},{"t":3,"p":1,"n":"CNAM - Color"},{"t":3,"p":1,"n":"RNAM - Valid Races"}]},{"t":1,"n":"IDLE - Idle Animation","c":[{"t":2,"n":"EDID - Editor ID"},{"t":8,"n":"Conditions","c":[{"t":6,"n":"Condition","c":[{"t":6,"n":"CTDA - ","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"n":"Comparison Value - Float"},{"t":3,"n":"Comparison Value - Global"},{"t":3,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"n":"None"},{"t":3,"n":"Integer"},{"t":5,"n":"Float"},{"t":11,"n":"Variable Name (unused)"},{"t":3,"n":"Sex"},{"t":3,"n":"Actor Value"},{"t":3,"n":"Crime Type"},{"t":3,"n":"Axis"},{"t":3,"n":"Quest Stage (unused)"},{"t":3,"n":"Misc Stat"},{"t":3,"n":"Alignment"},{"t":3,"n":"Equip Type"},{"t":3,"n":"Form Type"},{"t":3,"n":"Critical Stage"},{"t":3,"n":"Object Reference"},{"t":3,"n":"Inventory Object"},{"t":3,"n":"Actor"},{"t":3,"n":"Voice Type"},{"t":3,"n":"Idle"},{"t":3,"n":"Form List"},{"t":3,"n":"Quest"},{"t":3,"n":"Faction"},{"t":3,"n":"Cell"},{"t":3,"n":"Class"},{"t":3,"n":"Race"},{"t":3,"n":"Actor Base"},{"t":3,"n":"Global"},{"t":3,"n":"Weather"},{"t":3,"n":"Package"},{"t":3,"n":"Encounter Zone"},{"t":3,"n":"Perk"},{"t":3,"n":"Owner"},{"t":3,"n":"Furniture"},{"t":3,"n":"Effect Item"},{"t":3,"n":"Base Effect"},{"t":3,"n":"Worldspace"},{"t":3,"n":"VATS Value Function"},{"t":3,"n":"VATS Value Param (INVALID)"},{"t":3,"n":"Referenceable Object"},{"t":3,"n":"Region"},{"t":3,"n":"Keyword"},{"t":3,"n":"Player Action"},{"t":3,"n":"Casting Type"},{"t":3,"n":"Shout"},{"t":3,"n":"Location"},{"t":3,"n":"Location Ref Type"},{"t":3,"n":"Alias"},{"t":3,"n":"Packdata ID"},{"t":3,"n":"Association Type"},{"t":3,"n":"Furniture Anim"},{"t":3,"n":"Furniture Entry"},{"t":3,"n":"Scene"},{"t":3,"n":"Ward State"},{"t":3,"n":"Event"},{"t":3,"n":"Event Data"},{"t":3,"n":"Quest Stage"},{"t":3,"n":"Weapon"},{"t":3,"n":"Weapon List"},{"t":3,"n":"Target"},{"t":3,"n":"Target List"},{"t":3,"n":"Target Part"},{"t":3,"n":"VATS Action"},{"t":3,"n":"Critical Effect"},{"t":3,"n":"Critical Effect List"},{"t":3,"n":"Weapon Type"},{"t":3,"n":"Projectile Type"},{"t":3,"n":"Delivery Type"},{"t":3,"n":"Run On"},{"t":3,"n":"Reference"},{"t":3,"n":"Parameter #3"}]},{"t":2,"n":"CIS1 - Parameter #1"},{"t":2,"n":"CIS2 - Parameter #2"}]}]},{"t":2,"n":"DNAM - Filename"},{"t":2,"n":"ENAM - Animation Event"},{"t":7,"n":"ANAM - Related Idle Animations","c":[{"t":3,"n":"Related Idle Animation"}]},{"t":6,"n":"DATA - Data (unused)","c":[{"t":6,"n":"Looping seconds (both 255 forever)","c":[{"t":3,"n":"Min"},{"t":3,"n":"Max"}]},{"t":3,"n":"Flags"},{"t":3,"n":"Animation Group Section"},{"t":3,"n":"Replay Delay"}]}]},{"t":1,"p":1,"n":"IDLM - Idle Marker","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"IDLF - Flags"},{"t":3,"p":1,"n":"IDLC - Animation Count"},{"t":5,"p":1,"n":"IDLT - Idle Timer Setting"},{"t":7,"p":1,"n":"IDLA - Animations","c":[{"t":3,"p":1,"n":"Animation"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]}]},{"t":1,"p":1,"n":"IMAD - Image Space Adapter","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DNAM - Data Count","c":[{"t":3,"n":"Flags"},{"t":5,"n":"Duration"},{"t":6,"n":"HDR","c":[{"t":3,"n":"Eye Adapt Speed Mult"},{"t":3,"n":"Eye Adapt Speed Add"},{"t":3,"n":"Bloom Blur Radius Mult"},{"t":3,"n":"Bloom Blur Radius Add"},{"t":3,"n":"Bloom Threshold Mult"},{"t":3,"n":"Bloom Threshold Add"},{"t":3,"n":"Bloom Scale Mult"},{"t":3,"n":"Bloom Scale Add"},{"t":3,"n":"Target Lum Min Mult"},{"t":3,"n":"Target Lum Min Add"},{"t":3,"n":"Target Lum Max Mult"},{"t":3,"n":"Target Lum Max Add"},{"t":3,"n":"Sunlight Scale Mult"},{"t":3,"n":"Sunlight Scale Add"},{"t":3,"n":"Sky Scale Mult"},{"t":3,"n":"Sky Scale Add"}]},{"t":3,"n":"Unknown08 Mult"},{"t":3,"n":"Unknown48 Add"},{"t":3,"n":"Unknown09 Mult"},{"t":3,"n":"Unknown49 Add"},{"t":3,"n":"Unknown0A Mult"},{"t":3,"n":"Unknown4A Add"},{"t":3,"n":"Unknown0B Mult"},{"t":3,"n":"Unknown4B Add"},{"t":3,"n":"Unknown0C Mult"},{"t":3,"n":"Unknown4C Add"},{"t":3,"n":"Unknown0D Mult"},{"t":3,"n":"Unknown4D Add"},{"t":3,"n":"Unknown0E Mult"},{"t":3,"n":"Unknown4E Add"},{"t":3,"n":"Unknown0F Mult"},{"t":3,"n":"Unknown4F Add"},{"t":3,"n":"Unknown10 Mult"},{"t":3,"n":"Unknown50 Add"},{"t":6,"n":"Cinematic","c":[{"t":3,"n":"Saturation Mult"},{"t":3,"n":"Saturation Add"},{"t":3,"n":"Brightness Mult"},{"t":3,"n":"Brightness Add"},{"t":3,"n":"Contrast Mult"},{"t":3,"n":"Contrast Add"}]},{"t":3,"n":"Unknown14 Mult"},{"t":3,"n":"Unknown54 Add"},{"t":3,"n":"Tint Color"},{"t":3,"n":"Blur Radius"},{"t":3,"n":"Double Vision Strength"},{"t":3,"n":"Radial Blur Strength"},{"t":3,"n":"Radial Blur Ramp Up"},{"t":3,"n":"Radial Blur Start"},{"t":3,"n":"Radial Blur Flags"},{"t":5,"n":"Radial Blur Center X"},{"t":5,"n":"Radial Blur Center Y"},{"t":3,"n":"DoF Strength"},{"t":3,"n":"DoF Distance"},{"t":3,"n":"DoF Range"},{"t":3,"n":"DoF Flags"},{"t":3,"n":"Radial Blur Ramp Down"},{"t":3,"n":"Radial Blur Down Start"},{"t":3,"n":"Fade Color"},{"t":3,"n":"Motion Blur Strength"}]},{"t":7,"p":1,"n":"BNAM - Blur Radius","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"VNAM - Double Vision Strength","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"TNAM - Tint Color","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"},{"t":5,"p":1,"n":"Alpha"}]}]},{"t":7,"p":1,"n":"NAM3 - Fade Color","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"},{"t":5,"p":1,"n":"Alpha"}]}]},{"t":7,"p":1,"n":"RNAM - Radial Blur Strength","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"SNAM - Radial Blur Ramp Up","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"UNAM - Radial Blur Start","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"NAM1 - Radial Blur Ramp Down","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"NAM2 - Radial Blur Down Start","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"WNAM - DoF Strength","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"XNAM - DoF Distance","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"YNAM - DoF Range","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"NAM4 - Motion Blur Strength","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":6,"s":1,"p":1,"n":"HDR","c":[{"t":7,"p":1,"n":"aIAD - Eye Adapt Speed Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"@IAD - Eye Adapt Speed Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"bIAD - Bloom Blur Radius Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"AIAD - Bloom Blur Radius Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"cIAD - Bloom Threshold Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"BIAD - Bloom Threshold Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"dIAD - Bloom Scale Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"CIAD - Bloom Scale Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"eIAD - Target Lum Min Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"DIAD - Target Lum Min Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"fIAD - Target Lum Max Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"EIAD - Target Lum Max Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"gIAD - Sunlight Scale Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"FIAD - Sunlight Scale Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"hIAD - Sky Scale Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"GIAD - Sky Scale Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]}]},{"t":11,"n":"iIAD - Unknown"},{"t":11,"n":"HIAD - Unknown"},{"t":11,"n":"jIAD - Unknown"},{"t":11,"n":"IIAD - Unknown"},{"t":11,"n":"kIAD - Unknown"},{"t":11,"n":"JIAD - Unknown"},{"t":11,"n":"lIAD - Unknown"},{"t":11,"n":"KIAD - Unknown"},{"t":11,"n":"mIAD - Unknown"},{"t":11,"n":"LIAD - Unknown"},{"t":11,"n":"nIAD - Unknown"},{"t":11,"n":"MIAD - Unknown"},{"t":11,"n":"oIAD - Unknown"},{"t":11,"n":"NIAD - Unknown"},{"t":11,"n":"pIAD - Unknown"},{"t":11,"n":"OIAD - Unknown"},{"t":11,"n":"qIAD - Unknown"},{"t":11,"n":"PIAD - Unknown"},{"t":6,"s":1,"p":1,"n":"Cinematic","c":[{"t":7,"p":1,"n":"rIAD - Saturation Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"QIAD - Saturation Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"sIAD - Brightness Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"RIAD - Brightness Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"tIAD - Contrast Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"SIAD - Contrast Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]}]},{"t":11,"n":"uIAD - Unknown"},{"t":11,"n":"TIAD - Unknown"}]},{"t":1,"p":1,"n":"IMGS - Image Space","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":11,"n":"ENAM - Unknown"},{"t":6,"s":1,"p":1,"n":"HNAM - HDR","c":[{"t":5,"p":1,"n":"Eye Adapt Speed"},{"t":5,"p":1,"n":"Bloom Blur Radius"},{"t":5,"p":1,"n":"Bloom Threshold"},{"t":5,"p":1,"n":"Bloom Scale"},{"t":5,"p":1,"n":"Receive Bloom Threshold"},{"t":5,"p":1,"n":"White"},{"t":5,"p":1,"n":"Sunlight Scale"},{"t":5,"p":1,"n":"Sky Scale"},{"t":5,"p":1,"n":"Eye Adapt Strength"}]},{"t":6,"s":1,"p":1,"n":"CNAM - Cinematic","c":[{"t":5,"p":1,"n":"Saturation"},{"t":5,"p":1,"n":"Brightness"},{"t":5,"p":1,"n":"Contrast"}]},{"t":6,"s":1,"p":1,"n":"TNAM - Tint","c":[{"t":5,"p":1,"n":"Amount"},{"t":6,"p":1,"n":"Color","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}]}]},{"t":6,"s":1,"p":1,"n":"DNAM - Depth of Field","c":[{"t":5,"p":1,"n":"Strength"},{"t":5,"p":1,"n":"Distance"},{"t":5,"p":1,"n":"Range"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Sky \/ Blur Radius"}]}]},{"t":1,"p":1,"n":"INFO - Dialog response","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]},{"t":6,"p":1,"n":"Script Fragments","c":[{"t":3,"n":"Unknown"},{"t":3,"p":1,"n":"Flags"},{"t":2,"p":1,"n":"fileName"},{"t":7,"p":1,"n":"Fragments","c":[{"t":6,"p":1,"n":"Fragment","c":[{"t":3,"n":"Unknown"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]}]}]},{"t":11,"n":"DATA - Unknown"},{"t":6,"s":1,"p":1,"n":"ENAM - Response flags","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Reset Hours"}]},{"t":3,"p":1,"n":"TPIC - Topic"},{"t":3,"p":1,"n":"PNAM - Previous INFO"},{"t":3,"p":1,"n":"CNAM - Favor Level"},{"t":8,"s":1,"p":1,"n":"Link To","d":1,"c":[{"t":3,"p":1,"n":"TCLT - Response"}]},{"t":3,"p":1,"n":"DNAM - Response Data"},{"t":8,"s":1,"p":1,"n":"Responses","d":1,"c":[{"t":6,"p":1,"n":"Response","c":[{"t":6,"p":1,"n":"TRDT - Response Data","c":[{"t":3,"p":1,"n":"Emotion Type"},{"t":3,"p":1,"n":"Emotion Value"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Response number"},{"t":3,"p":1,"n":"Sound"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"NAM1 - Response Text"},{"t":2,"p":1,"n":"NAM2 - Script Notes"},{"t":2,"p":1,"n":"NAM3 - Edits"},{"t":3,"p":1,"n":"SNAM - Idle Animations: Speaker"},{"t":3,"p":1,"n":"LNAM - Idle Animations: Listener"}]}]},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":8,"n":"Unknown","c":[{"t":6,"n":"Unknown","c":[{"t":11,"n":"SCHR - Unknown"},{"t":3,"n":"QNAM - Unknown"},{"n":"NEXT - Marker"}]}]},{"t":2,"p":1,"n":"RNAM - Prompt"},{"t":3,"p":1,"n":"ANAM - Speaker"},{"t":3,"p":1,"n":"TWAT - Walk Away Topic"},{"t":3,"p":1,"n":"ONAM - Audio Output Override"}]},{"t":1,"p":1,"n":"INGR - Ingredient","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"ETYP - Equipment Type"},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":6,"s":1,"p":1,"n":"ENIT - Effect Data","c":[{"t":3,"p":1,"n":"Ingredient Value"},{"t":3,"p":1,"n":"Flags"}]},{"t":8,"s":1,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":3,"p":1,"n":"EFID - Base Effect"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":5,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"}]},{"t":8,"s":1,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]}]},{"t":1,"p":1,"n":"IPCT - Impact","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":5,"p":1,"n":"Effect - Duration"},{"t":3,"p":1,"n":"Effect - Orientation"},{"t":5,"p":1,"n":"Angle Threshold"},{"t":5,"p":1,"n":"Placement Radius"},{"t":3,"p":1,"n":"Sound Level"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Impact Result"},{"t":11,"n":"Unknown"}]},{"t":6,"s":1,"p":1,"n":"DODT - Decal Data","c":[{"t":5,"p":1,"n":"Min Width"},{"t":5,"p":1,"n":"Max Width"},{"t":5,"p":1,"n":"Min Height"},{"t":5,"p":1,"n":"Max Height"},{"t":5,"p":1,"n":"Depth"},{"t":5,"p":1,"n":"Shininess"},{"t":6,"p":1,"n":"Parallax","c":[{"t":5,"p":1,"n":"Scale"},{"t":3,"p":1,"n":"Passes"}]},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"},{"t":6,"p":1,"n":"Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":3,"p":1,"n":"DNAM - Texture Set"},{"t":3,"p":1,"n":"ENAM - Secondary Texture Set"},{"t":3,"p":1,"n":"SNAM - Sound 1"},{"t":3,"p":1,"n":"NAM1 - Sound 2"},{"t":3,"p":1,"n":"NAM2 - Hazard"}]},{"t":1,"p":1,"n":"IPDS - Impact Data Set","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":8,"s":1,"p":1,"n":"Data","d":1,"c":[{"t":6,"p":1,"n":"PNAM - ","c":[{"t":3,"p":1,"n":"Material"},{"t":3,"p":1,"n":"Impact"}]}]}]},{"t":1,"p":1,"n":"KEYM - Key","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]}]},{"t":1,"p":1,"n":"KYWD - Keyword","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"CNAM - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":1,"p":1,"n":"LAND - Landscape","f":1,"d":1,"c":[{"t":11,"n":"DATA - Unknown"},{"t":11,"n":"VNML - Vertex Normals"},{"t":11,"n":"VHGT - Vertext Height Map"},{"t":11,"n":"VCLR - Vertex Colours"},{"t":8,"s":1,"p":1,"n":"Layers","d":1,"c":[{"t":6,"p":1,"n":"Base Layer","c":[{"t":6,"p":1,"n":"BTXT - Base Layer Header","c":[{"t":3,"p":1,"n":"Texture"},{"t":3,"p":1,"n":"Quadrant"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Layer"}]}]},{"t":6,"p":1,"n":"Alpha Layer","c":[{"t":6,"p":1,"n":"ATXT - Alpha Layer Header","c":[{"t":3,"p":1,"n":"Texture"},{"t":3,"p":1,"n":"Quadrant"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Layer"}]},{"t":11,"p":1,"n":"VTXT - Alpha Layer Data"}]}]},{"t":7,"p":1,"n":"VTEX - Textures","c":[{"t":3,"p":1,"n":"Texture"}]}]},{"t":1,"p":1,"n":"LCRT - Location Reference Type","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"CNAM - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":1,"n":"LCTN - Location","c":[{"t":2,"n":"EDID - Editor ID"},{"t":7,"n":"ACPR - Actor Cell Persistent Reference","c":[{"t":6,"n":"","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Location"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":7,"n":"LCPR - Location Cell Persistent Reference","c":[{"t":6,"n":"","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Location"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":7,"n":"RCPR - Reference Cell Persistent Reference","c":[{"t":3,"n":"Ref"}]},{"t":7,"n":"ACUN - Actor Cell Unique","c":[{"t":6,"n":"","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Ref"},{"t":3,"n":"Location"}]}]},{"t":7,"n":"LCUN - Location Cell Unique","c":[{"t":6,"n":"","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Ref"},{"t":3,"n":"Location"}]}]},{"t":7,"n":"RCUN - Reference Cell Unique","c":[{"t":3,"n":"Actor"}]},{"t":7,"n":"ACSR - Actor Cell Static Reference","c":[{"t":6,"n":"","c":[{"t":3,"n":"Loc Ref Type"},{"t":3,"n":"Marker"},{"t":3,"n":"Location"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":7,"n":"LCSR - Location Cell Static Reference","c":[{"t":6,"n":"","c":[{"t":3,"n":"Loc Ref Type"},{"t":3,"n":"Marker"},{"t":3,"n":"Location"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":7,"n":"RCSR - Reference Cell Static Reference","c":[{"t":3,"n":"Ref"}]},{"t":8,"n":"Actor Cell Encounter Cell","c":[{"t":6,"n":"ACEC - Unknown","c":[{"t":3,"n":"Location"},{"t":7,"n":"Coordinates","c":[{"t":6,"n":"","c":[{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]}]}]},{"t":8,"n":"Location Cell Encounter Cell","c":[{"t":6,"n":"LCEC - Unknown","c":[{"t":3,"n":"Location"},{"t":7,"n":"Coordinates","c":[{"t":6,"n":"","c":[{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]}]}]},{"t":8,"n":"Reference Cell Encounter Cell","c":[{"t":6,"n":"RCEC - Unknown","c":[{"t":3,"n":"Location"},{"t":7,"n":"Coordinates","c":[{"t":6,"n":"","c":[{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]}]}]},{"t":7,"n":"ACID - Actor Cell Marker Reference","c":[{"t":3,"n":"Ref"}]},{"t":7,"n":"LCID - Location Cell Marker Reference","c":[{"t":3,"n":"Ref"}]},{"t":7,"n":"ACEP - Actor Cell Enable Point","c":[{"t":6,"n":"","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Ref"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":7,"n":"LCEP - Location Cell Enable Point","c":[{"t":6,"n":"","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Ref"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":2,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":3,"n":"PNAM - Parent Location"},{"t":3,"n":"NAM1 - Music"},{"t":3,"n":"FNAM - Unreported Crime Faction"},{"t":3,"n":"MNAM - World Location Marker Ref"},{"t":5,"n":"RNAM - World Location Radius"},{"t":3,"n":"NAM0 - Horse Marker Ref"},{"t":6,"n":"CNAM - Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":1,"p":1,"n":"LENS - Lens Flare","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":5,"p":1,"n":"CNAM - Color Influence"},{"t":5,"p":1,"n":"DNAM - Fade Distance Radius Scale"},{"t":3,"n":"LFSP - Count"},{"t":8,"s":1,"p":1,"n":"Lens Flare Sprites","d":1,"c":[{"t":6,"p":1,"n":"Flare","c":[{"t":2,"p":1,"n":"DNAM - Lens Flare Sprite ID"},{"t":2,"p":1,"n":"FNAM - Texture"},{"t":6,"p":1,"n":"LFSD - Lens Flare Data","c":[{"t":6,"p":1,"n":"Tint","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}]},{"t":5,"p":1,"n":"Width"},{"t":5,"p":1,"n":"Height"},{"t":5,"p":1,"n":"Position"},{"t":5,"p":1,"n":"Angular Fade"},{"t":5,"p":1,"n":"Opacity"},{"t":3,"p":1,"n":"Flags"}]}]}]}]},{"t":1,"p":1,"n":"LGTM - Lighting Template","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - Lighting","c":[{"t":6,"p":1,"n":"Ambient Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Directional Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Fog Color Near","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Fog Near"},{"t":5,"p":1,"n":"Fog Far"},{"t":3,"p":1,"n":"Directional Rotation XY"},{"t":3,"p":1,"n":"Directional Rotation Z"},{"t":5,"p":1,"n":"Directional Fade"},{"t":5,"p":1,"n":"Fog Clip Dist"},{"t":5,"p":1,"n":"Fog Power"},{"t":6,"p":1,"n":"Ambient Colors","c":[{"t":6,"p":1,"n":"Directional","c":[{"t":6,"p":1,"n":"X+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"X-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Specular","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Scale"}]},{"t":6,"p":1,"n":"Fog Color Far","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Fog Max"},{"t":6,"p":1,"n":"Light Fade Distances","c":[{"t":5,"p":1,"n":"Start"},{"t":5,"p":1,"n":"End"}]},{"t":11,"n":"Unknown"}]},{"t":6,"s":1,"p":1,"n":"DALC - Directional Ambient Lighting Colors","c":[{"t":6,"p":1,"n":"Directional","c":[{"t":6,"p":1,"n":"X+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"X-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Specular","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Scale"}]}]},{"t":1,"p":1,"n":"LIGH - Light","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Time"},{"t":3,"p":1,"n":"Radius"},{"t":6,"p":1,"n":"Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Falloff Exponent"},{"t":5,"p":1,"n":"FOV"},{"t":5,"p":1,"n":"Near Clip"},{"t":6,"p":1,"n":"Flicker Effect","c":[{"t":5,"p":1,"n":"Period"},{"t":5,"p":1,"n":"Intensity Amplitude"},{"t":5,"p":1,"n":"Movement Amplitude"}]},{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":5,"p":1,"n":"FNAM - Fade value"},{"t":3,"p":1,"n":"SNAM - Sound"}]},{"t":1,"p":1,"n":"LSCR - Load Screen","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":2,"p":1,"n":"DESC - Description"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":3,"p":1,"n":"NNAM - Loading Screen NIF"},{"t":5,"p":1,"n":"SNAM - Initial Scale"},{"t":6,"s":1,"p":1,"n":"RNAM - Initial Rotation","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"},{"t":3,"p":1,"n":"Z"}]},{"t":6,"s":1,"p":1,"n":"ONAM - Rotation Offset Constraints","c":[{"t":3,"p":1,"n":"Min"},{"t":3,"p":1,"n":"Max"}]},{"t":6,"s":1,"p":1,"n":"XNAM - Initial Translation Offset","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":2,"p":1,"n":"MOD2 - Camera Path"}]},{"t":1,"p":1,"n":"LTEX - Landscape Texture","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"TNAM - Texture Set"},{"t":3,"p":1,"n":"MNAM - Material Type"},{"t":6,"s":1,"p":1,"n":"HNAM - Havok Data","c":[{"t":3,"p":1,"n":"Friction"},{"t":3,"p":1,"n":"Restitution"}]},{"t":3,"p":1,"n":"SNAM - Texture Specular Exponent"},{"t":8,"s":1,"p":1,"n":"Grasses","d":1,"c":[{"t":3,"p":1,"n":"GNAM - Grass"}]},{"t":3,"n":"INAM - Unused"}]},{"t":1,"p":1,"n":"LVLI - Leveled Item","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"LVLD - Chance None"},{"t":3,"p":1,"n":"LVLF - Flags"},{"t":3,"p":1,"n":"LVLG - Global"},{"t":3,"n":"LLCT - Count"},{"t":10,"p":1,"n":"Leveled List Entries","d":1,"c":[{"t":6,"p":1,"n":"Leveled List Entry","c":[{"t":6,"p":1,"n":"LVLO - Base Data","c":[{"t":3,"p":1,"n":"Level"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Count"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]}]},{"t":1,"p":1,"n":"LVLN - Leveled NPC","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"LVLD - Chance None"},{"t":3,"p":1,"n":"LVLF - Flags"},{"t":3,"p":1,"n":"LVLG - Global"},{"t":3,"n":"LLCT - Count"},{"t":10,"p":1,"n":"Leveled List Entries","d":1,"c":[{"t":6,"p":1,"n":"Leveled List Entry","c":[{"t":6,"p":1,"n":"LVLO - Base Data","c":[{"t":3,"p":1,"n":"Level"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Count"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]}]},{"t":1,"p":1,"n":"LVSP - Leveled Spell","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"LVLD - Chance None"},{"t":3,"p":1,"n":"LVLF - Flags"},{"t":3,"n":"LLCT - Count"},{"t":10,"p":1,"n":"Leveled List Entries","d":1,"c":[{"t":6,"p":1,"n":"Leveled List Entry","c":[{"t":6,"p":1,"n":"LVLO - Base Data","c":[{"t":3,"p":1,"n":"Level"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Count"}]}]}]}]},{"t":1,"p":1,"n":"MATO - Material Object","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":8,"s":1,"p":1,"n":"Property Data","d":1,"c":[{"t":11,"p":1,"n":"DNAM - Data"}]},{"t":6,"s":1,"p":1,"n":"DATA - Directional Material Data","c":[{"t":5,"p":1,"n":"Falloff Scale"},{"t":5,"p":1,"n":"Falloff Bias"},{"t":5,"p":1,"n":"Noise UV Scale"},{"t":5,"p":1,"n":"Material UV Scale"},{"t":6,"p":1,"n":"Projection Vector","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":5,"p":1,"n":"Normal Dampener"},{"t":6,"p":1,"n":"Single Pass Color","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}]},{"t":3,"p":1,"n":"Flags"}]}]},{"t":1,"p":1,"n":"MATT - Material Type","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"PNAM - Material Parent"},{"t":2,"p":1,"n":"MNAM - Material Name"},{"t":6,"s":1,"p":1,"n":"CNAM - Havok Display Color","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}]},{"t":5,"p":1,"n":"BNAM - Buoyancy"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":3,"p":1,"n":"HNAM - Havok Impact Data Set"}]},{"t":1,"p":1,"n":"MESG - Message","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"DESC - Description"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"INAM - Icon (unused)"},{"t":3,"p":1,"n":"QNAM - Owner Quest"},{"t":3,"p":1,"n":"DNAM - Flags"},{"t":3,"p":1,"n":"TNAM - Display Time"},{"t":8,"s":1,"p":1,"n":"Menu Buttons","d":1,"c":[{"t":6,"p":1,"n":"Menu Button","c":[{"t":2,"p":1,"n":"ITXT - Button Text"},{"t":8,"s":1,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]}]},{"t":1,"p":1,"n":"MGEF - Magic Effect","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"MDOB - Menu Display Object"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"Magic Effect Data","c":[{"t":6,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Base Cost"},{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Assoc. Item"},{"t":3,"p":1,"n":"Magic Skill"},{"t":3,"p":1,"n":"Resist Value"},{"t":3,"p":1,"n":"Counter Effect count"},{"t":3,"p":1,"n":"Casting Light"},{"t":5,"p":1,"n":"Taper Weight"},{"t":3,"p":1,"n":"Hit Shader"},{"t":3,"p":1,"n":"Enchant Shader"},{"t":3,"p":1,"n":"Minimum Skill Level"},{"t":6,"p":1,"n":"Spellmaking","c":[{"t":3,"p":1,"n":"Area"},{"t":5,"p":1,"n":"Casting Time"}]},{"t":5,"p":1,"n":"Taper Curve"},{"t":5,"p":1,"n":"Taper Duration"},{"t":5,"p":1,"n":"Second AV Weight"},{"t":3,"p":1,"n":"Archtype"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Projectile"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Delivery"},{"t":3,"p":1,"n":"Second Actor Value"},{"t":3,"p":1,"n":"Casting Art"},{"t":3,"p":1,"n":"Hit Effect Art"},{"t":3,"p":1,"n":"Impact Data"},{"t":5,"p":1,"n":"Skill Usage Multiplier"},{"t":6,"p":1,"n":"Dual Casting","c":[{"t":3,"p":1,"n":"Art"},{"t":5,"p":1,"n":"Scale"}]},{"t":3,"p":1,"n":"Enchant Art"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Equip Ability"},{"t":3,"p":1,"n":"Image Space Modifier"},{"t":3,"p":1,"n":"Perk to Apply"},{"t":3,"p":1,"n":"Casting Sound Level"},{"t":6,"p":1,"n":"Script Effect AI","c":[{"t":5,"p":1,"n":"Score"},{"t":5,"p":1,"n":"Delay Time"}]}]}]},{"t":8,"s":1,"p":1,"n":"Counter Effects","d":1,"c":[{"t":3,"n":"ESCE - Effect"}]},{"t":7,"p":1,"n":"SNDD - Sounds","c":[{"t":6,"p":1,"n":"","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Sound"}]}]},{"t":2,"p":1,"n":"DNAM - Magic Item Description"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]},{"t":1,"p":1,"n":"MISC - Misc. Item","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]}]},{"t":1,"p":1,"n":"MOVT - Movement Type","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"MNAM - Name"},{"t":6,"s":1,"p":1,"n":"SPED - Default Data","c":[{"t":5,"p":1,"n":"Left Walk"},{"t":5,"p":1,"n":"Left Run"},{"t":5,"p":1,"n":"Right Walk"},{"t":5,"p":1,"n":"Right Run"},{"t":5,"p":1,"n":"Forward Walk"},{"t":5,"p":1,"n":"Forward Run"},{"t":5,"p":1,"n":"Back Walk"},{"t":5,"p":1,"n":"Back Run"},{"t":5,"p":1,"n":"Rotate in Place Walk"},{"t":5,"p":1,"n":"Rotate in Place Run"},{"t":5,"p":1,"n":"Rotate while Moving Run"}]},{"t":6,"s":1,"p":1,"n":"INAM - Anim Change Thresholds","c":[{"t":5,"p":1,"n":"Directional"},{"t":5,"p":1,"n":"Movement Speed"},{"t":5,"p":1,"n":"Rotation Speed"}]}]},{"t":1,"p":1,"n":"MSTT - Moveable Static","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"DATA - Flags"},{"t":3,"p":1,"n":"SNAM - Looping Sound"}]},{"t":1,"p":1,"n":"MUSC - Music Type","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":6,"s":1,"p":1,"n":"PNAM - Data","c":[{"t":3,"p":1,"n":"Priority"},{"t":3,"p":1,"n":"Ducking (dB)"}]},{"t":5,"p":1,"n":"WNAM - Fade Duration"},{"t":7,"p":1,"n":"TNAM - Music Tracks","c":[{"t":3,"p":1,"n":"Track"}]}]},{"t":1,"p":1,"n":"MUST - Music Track","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"CNAM - Track Type"},{"t":5,"p":1,"n":"FLTV - Duration"},{"t":5,"p":1,"n":"DNAM - Fade-Out"},{"t":2,"p":1,"n":"ANAM - Track Filename"},{"t":2,"p":1,"n":"BNAM - Finale Filename"},{"t":7,"p":1,"n":"FNAM - Cue Points","c":[{"t":5,"p":1,"n":"Point"}]},{"t":6,"s":1,"p":1,"n":"LNAM - Loop Data","c":[{"t":5,"p":1,"n":"Loop Begins"},{"t":5,"p":1,"n":"Loop Ends"},{"t":3,"p":1,"n":"Loop Count"}]},{"t":3,"n":"CITC - Condition Count"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":7,"p":1,"n":"SNAM - Tracks","c":[{"t":3,"p":1,"n":"Track"}]}]},{"t":1,"n":"NAVI - Navigation Mesh Info Map","c":[{"t":2,"n":"EDID - Editor ID"},{"t":3,"n":"NVER - Version"},{"t":8,"n":"Navigation Map Infos","c":[{"t":6,"n":"NVMI - Navigation Map Info","c":[{"t":3,"n":"Navigation Mesh"},{"t":11,"n":"Unknown"},{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"},{"t":3,"n":"Preferred Merges Flag"},{"t":7,"n":"Merged To","c":[{"t":3,"n":"Mesh"}]},{"t":7,"n":"Preferred Merges","c":[{"t":3,"n":"Mesh"}]},{"t":7,"n":"Linked Doors","c":[{"t":6,"n":"Door","c":[{"t":11,"n":"Unknown"},{"t":3,"n":"Door Ref"}]}]},{"t":3,"n":"Is Island"},{"t":11,"n":"Unused"},{"t":6,"n":"Island Data","c":[{"t":11,"n":"Unknown"},{"t":7,"n":"Triangles","c":[{"t":11,"n":"Triangle"}]},{"t":7,"n":"Vertices","c":[{"t":11,"n":"Vertex"}]}]},{"t":3,"n":"Parent Worldspace"},{"t":6,"n":"Coordinates","c":[{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]},{"t":3,"n":"Parent Cell"}]}]},{"t":6,"n":"NVPP - Preferred Pathing","c":[{"t":7,"n":"NavMeshes","c":[{"t":7,"n":"Set","c":[{"t":3,"n":""}]}]},{"t":7,"n":"NavMesh Tree?","c":[{"t":6,"n":"","c":[{"t":3,"n":"NavMesh"},{"t":3,"n":"Index\/Node"}]}]}]},{"t":7,"n":"NVSI - Unknown","c":[{"t":3,"n":"Navigation Mesh"}]}]},{"t":1,"n":"NAVM - Navigation Mesh","c":[{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"NVNM - Geometry","c":[{"t":11,"n":"Unknown"},{"t":3,"n":"Parent Worldspace"},{"t":6,"n":"Coordinates","c":[{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]},{"t":3,"n":"Parent Cell"},{"t":7,"n":"Vertices","c":[{"t":11,"n":"Vertex"}]},{"t":7,"n":"Triangles","c":[{"t":11,"n":"Triangle"}]},{"t":7,"n":"External Connections","c":[{"t":6,"n":"Connection","c":[{"t":11,"n":"Unknown"},{"t":3,"n":"Mesh"},{"t":3,"n":"Triangle"}]}]},{"t":7,"n":"Door Triangles","c":[{"t":6,"n":"Door Triangle","c":[{"t":3,"n":"Triangle before door"},{"t":11,"n":"Unknown"},{"t":3,"n":"Door"}]}]}]},{"t":11,"n":"ONAM - Unknown"},{"t":11,"n":"PNAM - Unknown"},{"t":11,"n":"NNAM - Unknown"}]},{"t":1,"p":1,"n":"NPC_ - Non-Player Character (Actor)","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"ACBS - Configuration","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Magicka Offset"},{"t":3,"p":1,"n":"Stamina Offset"},{"t":3,"p":1,"n":"Level"},{"t":3,"p":1,"n":"Level Mult"},{"t":3,"p":1,"n":"Calc min level"},{"t":3,"p":1,"n":"Calc max level"},{"t":3,"p":1,"n":"Speed Multiplier"},{"t":3,"p":1,"n":"Disposition Base (unused)"},{"t":3,"p":1,"n":"Template Flags"},{"t":3,"p":1,"n":"Health Offset"},{"t":3,"p":1,"n":"Bleedout Override"}]},{"t":8,"s":1,"p":1,"n":"Factions","d":1,"c":[{"t":6,"p":1,"n":"SNAM - Faction","c":[{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"p":1,"n":"INAM - Death item"},{"t":3,"p":1,"n":"VTCK - Voice"},{"t":3,"p":1,"n":"TPLT - Template"},{"t":3,"p":1,"n":"RNAM - Race","lt":"Head Parts","lf":"Tint Layers"},{"t":3,"n":"SPCT - Count"},{"t":8,"s":1,"p":1,"n":"Actor Effects","d":1,"c":[{"t":3,"p":1,"n":"SPLO - Actor Effect"}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"WNAM - Worn Armor"},{"t":3,"p":1,"n":"ANAM - Far away model"},{"t":3,"p":1,"n":"ATKR - Attack Race"},{"t":10,"p":1,"n":"Attacks","d":1,"c":[{"t":6,"p":1,"n":"Attack","c":[{"t":6,"p":1,"n":"ATKD - Attack Data","c":[{"t":5,"p":1,"n":"Damage Mult"},{"t":5,"p":1,"n":"Attack Chance"},{"t":3,"p":1,"n":"Attack Spell"},{"t":3,"p":1,"n":"Attack Flags"},{"t":5,"p":1,"n":"Attack Angle"},{"t":5,"p":1,"n":"Strike Angle"},{"t":5,"p":1,"n":"Stagger"},{"t":3,"p":1,"n":"Attack Type"},{"t":5,"p":1,"n":"Knockdown"},{"t":5,"p":1,"n":"Recovery Time"},{"t":5,"p":1,"n":"Stamina Mult"}]},{"t":2,"p":1,"n":"ATKE - Attack Event"}]}]},{"t":3,"p":1,"n":"SPOR - Spectator override package list"},{"t":3,"p":1,"n":"OCOR - Observe dead body override package list"},{"t":3,"p":1,"n":"GWOR - Guard warn override package list"},{"t":3,"p":1,"n":"ECOR - Combat override package list"},{"t":3,"n":"PRKZ - Perk Count"},{"t":8,"s":1,"p":1,"n":"Perks","d":1,"c":[{"t":6,"p":1,"n":"PRKR - Perk","c":[{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"COCT - Count"},{"t":10,"p":1,"n":"Items","d":1,"c":[{"t":6,"p":1,"n":"Item","c":[{"t":6,"p":1,"n":"CNTO - Item","c":[{"t":3,"p":1,"n":"Item"},{"t":3,"p":1,"n":"Count"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]},{"t":6,"s":1,"p":1,"n":"AIDT - AI Data","c":[{"t":3,"p":1,"n":"Aggression"},{"t":3,"p":1,"n":"Confidence"},{"t":3,"p":1,"n":"Energy Level"},{"t":3,"p":1,"n":"Responsibility"},{"t":3,"p":1,"n":"Mood"},{"t":3,"p":1,"n":"Assistance"},{"t":6,"p":1,"n":"Aggro","c":[{"t":3,"p":1,"n":"Aggro Radius Behavior"},{"t":3,"n":"Unknown"},{"t":3,"p":1,"n":"Warn"},{"t":3,"p":1,"n":"Warn\/Attack"},{"t":3,"p":1,"n":"Attack"}]}]},{"t":8,"s":1,"p":1,"n":"Packages","d":1,"c":[{"t":3,"p":1,"n":"PKID - Package"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":3,"p":1,"n":"CNAM - Class"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"SHRT - Short Name"},{"t":11,"n":"DATA - Marker"},{"t":6,"s":1,"p":1,"n":"DNAM - Player Skills","c":[{"t":7,"p":1,"n":"Skill Values","c":[{"t":3,"p":1,"n":"Skill"}]},{"t":7,"p":1,"n":"Skill Offsets","c":[{"t":3,"p":1,"n":"Skill"}]},{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Magicka"},{"t":3,"p":1,"n":"Stamina"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Far away model distance"},{"t":3,"p":1,"n":"Geared up weapons"}]},{"t":8,"s":1,"p":1,"n":"Head Parts","d":1,"c":[{"t":3,"p":1,"n":"PNAM - Head Part"}],"lt":"HCLF - Hair Color","lf":"RNAM - Race"},{"t":3,"p":1,"n":"HCLF - Hair Color","lt":"NAM6 - Height","lf":"Head Parts"},{"t":3,"p":1,"n":"ZNAM - Combat Style"},{"t":3,"p":1,"n":"GNAM - Gift Filter"},{"t":11,"n":"NAM5 - Unknown"},{"t":5,"p":1,"n":"NAM6 - Height","lt":"NAM7 - Weight","lf":"HCLF - Hair Color"},{"t":5,"p":1,"n":"NAM7 - Weight","lt":"FTST - Head texture","lf":"NAM6 - Height"},{"t":3,"p":1,"n":"NAM8 - Sound Level"},{"t":10,"p":1,"n":"Sound Types","d":1,"c":[{"t":6,"p":1,"n":"Sound Type","c":[{"t":3,"p":1,"n":"CSDT - Type"},{"t":10,"p":1,"n":"Sounds","c":[{"t":6,"p":1,"n":"Sound","c":[{"t":3,"p":1,"n":"CSDI - Sound"},{"t":3,"p":1,"n":"CSDC - Sound Chance"}]}]}]}]},{"t":3,"p":1,"n":"CSCR - Inherits Sounds From"},{"t":3,"p":1,"n":"DOFT - Default outfit"},{"t":3,"p":1,"n":"SOFT - Sleeping outfit"},{"t":3,"p":1,"n":"DPLT - Default Package List"},{"t":3,"p":1,"n":"CRIF - Crime faction"},{"t":3,"p":1,"n":"FTST - Head texture","lt":"QNAM - Texture lighting","lf":"NAM7 - Weight"},{"t":6,"s":1,"p":1,"n":"QNAM - Texture lighting","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}],"lt":"NAM9 - Face morph","lf":"FTST - Head texture"},{"t":6,"s":1,"p":1,"n":"NAM9 - Face morph","c":[{"t":5,"p":1,"n":"Nose Long\/Short"},{"t":5,"p":1,"n":"Nose Up\/Down"},{"t":5,"p":1,"n":"Jaw Up\/Down"},{"t":5,"p":1,"n":"Jaw Narrow\/Wide"},{"t":5,"p":1,"n":"Jaw Farward\/Back"},{"t":5,"p":1,"n":"Cheeks Up\/Down"},{"t":5,"p":1,"n":"Cheeks Farward\/Back"},{"t":5,"p":1,"n":"Eyes Up\/Down"},{"t":5,"p":1,"n":"Eyes In\/Out"},{"t":5,"p":1,"n":"Brows Up\/Down"},{"t":5,"p":1,"n":"Brows In\/Out"},{"t":5,"p":1,"n":"Brows Farward\/Back"},{"t":5,"p":1,"n":"Lips Up\/Down"},{"t":5,"p":1,"n":"Lips In\/Out"},{"t":5,"p":1,"n":"Chin Narrow\/Wide"},{"t":5,"p":1,"n":"Chin Up\/Down"},{"t":5,"p":1,"n":"Chin Underbite\/Overbite"},{"t":5,"p":1,"n":"Eyes Farward\/Back"},{"t":5,"n":"Unknown"}],"lt":"NAMA - Face parts","lf":"QNAM - Texture lighting"},{"t":6,"s":1,"p":1,"n":"NAMA - Face parts","c":[{"t":3,"p":1,"n":"Nose"},{"t":3,"n":"Unknown"},{"t":3,"p":1,"n":"Eyes"},{"t":3,"p":1,"n":"Mouth"}],"lt":"Tint Layers","lf":"NAM9 - Face morph"},{"t":10,"p":1,"n":"Tint Layers","d":1,"c":[{"t":6,"p":1,"n":"Layer","c":[{"t":3,"p":1,"n":"TINI - Tint Index"},{"t":6,"p":1,"n":"TINC - Tint Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":3,"p":1,"n":"Alpha"}]},{"t":3,"p":1,"n":"TINV - Interpolation Value"},{"t":3,"p":1,"n":"TIAS - Preset"}]}],"lt":"RNAM - Race","lf":"NAMA - Face parts"}]},{"t":1,"p":1,"n":"OTFT - Outfit","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":7,"s":1,"p":1,"n":"INAM - Items","d":1,"c":[{"t":3,"p":1,"n":"Item"}]}]},{"t":1,"p":1,"n":"PACK - Package","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]},{"t":6,"p":1,"n":"Script Fragments","c":[{"t":3,"n":"Unknown"},{"t":3,"p":1,"n":"Flags"},{"t":2,"p":1,"n":"fileName"},{"t":7,"p":1,"n":"Fragments","c":[{"t":6,"p":1,"n":"Fragment","c":[{"t":3,"n":"Unknown"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]}]}]},{"t":6,"s":1,"p":1,"n":"PKDT - Pack Data","c":[{"t":3,"p":1,"n":"General Flags"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Interrupt Override"},{"t":3,"p":1,"n":"Preferred Speed"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Interrupt Flags"}]},{"t":6,"s":1,"p":1,"n":"PSDT - Schedule","c":[{"t":3,"p":1,"n":"Month"},{"t":3,"p":1,"n":"Day of week"},{"t":3,"p":1,"n":"Date"},{"t":3,"p":1,"n":"Hour"},{"t":3,"p":1,"n":"Minute"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Duration (minutes)"}]},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":6,"s":1,"p":1,"n":"Idle Animations","c":[{"t":3,"p":1,"n":"IDLF - Flags"},{"t":6,"p":1,"n":"IDLC - ","c":[{"t":3,"p":1,"n":"Animation Count"},{"t":11,"n":"Unknown"}]},{"t":5,"p":1,"n":"IDLT - Idle Timer Setting"},{"t":7,"p":1,"n":"IDLA - Animations","c":[{"t":3,"p":1,"n":"Animation"}]},{"t":11,"n":"IDLB - Unknown"}]},{"t":3,"p":1,"n":"CNAM - Combat Style"},{"t":3,"p":1,"n":"QNAM - Owner Quest"},{"t":6,"s":1,"p":1,"n":"PKCU - Counter","c":[{"t":3,"p":1,"n":"Data Input Count"},{"t":3,"p":1,"n":"Package Template"},{"t":3,"p":1,"n":"Version Counter (autoincremented)"}]},{"t":6,"s":1,"p":1,"n":"Package Data","c":[{"t":8,"p":1,"n":"Data Input Values","c":[{"t":6,"p":1,"n":"Value","c":[{"t":2,"p":1,"n":"ANAM - Type"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Bool"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"n":"BNAM - Unknown"},{"t":8,"p":1,"n":"Topic","c":[{"t":6,"p":1,"n":"PDTO - Topic Data","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Topic"},{"t":2,"p":1,"n":"Subtype"}]}]},{"t":6,"p":1,"n":"PLDT - Location","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Cell"},{"t":11,"p":1,"n":"Near Package Start Location"},{"t":11,"p":1,"n":"Near Editor Location"},{"t":3,"p":1,"n":"Object ID"},{"t":3,"p":1,"n":"Object Type"},{"t":3,"p":1,"n":"Keyword"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Radius"}]},{"t":6,"p":1,"n":"PTDA - Target","c":[{"t":6,"p":1,"n":"Target Data","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Object ID"},{"t":3,"p":1,"n":"Object Type"},{"t":3,"p":1,"n":"Alias"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Count \/ Distance"}]}]},{"t":11,"n":"TPIC - Unknown"}]}]},{"t":8,"p":1,"n":"Data Inputs","c":[{"t":6,"p":1,"n":"Data Input","c":[{"t":3,"p":1,"n":"UNAM - Index"},{"t":2,"p":1,"n":"BNAM - Name"},{"t":3,"p":1,"n":"PNAM - Flags"}]}]}]},{"t":11,"n":"XNAM - Marker"},{"t":6,"s":1,"p":1,"n":"Procedure Tree","c":[{"t":8,"p":1,"n":"Branches","c":[{"t":6,"p":1,"n":"Branch","c":[{"t":2,"p":1,"n":"ANAM - Branch Type"},{"t":3,"p":1,"n":"CITC - Condition Count"},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":6,"p":1,"n":"PRCB - Root","c":[{"t":3,"p":1,"n":"Branch Count"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"PNAM - Procedure Type"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":8,"p":1,"n":"Data Input Indexes","c":[{"t":3,"p":1,"n":"PKC2 - Index"}]},{"t":8,"p":1,"n":"Flags Override","c":[{"t":6,"p":1,"n":"PFO2 - Data","c":[{"t":3,"p":1,"n":"Set General Flags"},{"t":3,"p":1,"n":"Clear General Flags"},{"t":3,"p":1,"n":"Set Interrupt Flags"},{"t":3,"p":1,"n":"Clear Interrupt Flags"},{"t":3,"p":1,"n":"Preferred Speed Override"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Unknown","c":[{"t":11,"n":"PFOR - Unknown"}]}]}]}]},{"t":8,"s":1,"p":1,"n":"Data Inputs","d":1,"c":[{"t":6,"p":1,"n":"Data Input","c":[{"t":3,"p":1,"n":"UNAM - Index"},{"t":2,"p":1,"n":"BNAM - Name"},{"t":3,"p":1,"n":"PNAM - Flags"}]}]},{"t":6,"s":1,"p":1,"n":"OnBegin","c":[{"p":1,"n":"POBA - OnBegin Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":11,"n":"SCHR - Unused"},{"t":11,"n":"SCTX - Unused"},{"t":11,"n":"QNAM - Unused"},{"t":11,"n":"TNAM - Unused"},{"t":8,"p":1,"n":"Topic","c":[{"t":6,"p":1,"n":"PDTO - Topic Data","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Topic"},{"t":2,"p":1,"n":"Subtype"}]}]}]},{"t":6,"s":1,"p":1,"n":"OnEnd","c":[{"p":1,"n":"POEA - OnEnd Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":11,"n":"SCHR - Unused"},{"t":11,"n":"SCTX - Unused"},{"t":11,"n":"QNAM - Unused"},{"t":11,"n":"TNAM - Unused"},{"t":8,"p":1,"n":"Topic","c":[{"t":6,"p":1,"n":"PDTO - Topic Data","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Topic"},{"t":2,"p":1,"n":"Subtype"}]}]}]},{"t":6,"s":1,"p":1,"n":"OnChange","c":[{"p":1,"n":"POCA - OnChange Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":11,"n":"SCHR - Unused"},{"t":11,"n":"SCDA - Unused"},{"t":11,"n":"SCTX - Unused"},{"t":11,"n":"QNAM - Unused"},{"t":11,"n":"TNAM - Unused"},{"t":8,"p":1,"n":"Topic","c":[{"t":6,"p":1,"n":"PDTO - Topic Data","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Topic"},{"t":2,"p":1,"n":"Subtype"}]}]}]}]},{"t":1,"p":1,"n":"PARW - Placed Arrow","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Projectile"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"PBAR - Placed Barrier","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Projectile"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"PBEA - Placed Beam","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Projectile"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"PCON - Placed Cone\/Voice","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Projectile"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"PERK - Perk","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]},{"t":6,"p":1,"n":"Script Fragments","c":[{"t":3,"n":"Unknown"},{"t":2,"p":1,"n":"fileName"},{"t":7,"p":1,"n":"Fragments","c":[{"t":6,"p":1,"n":"Fragment","c":[{"t":3,"p":1,"n":"Fragment Index"},{"t":3,"n":"Unknown"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]}]}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Trait"},{"t":3,"p":1,"n":"Level"},{"t":3,"p":1,"n":"Num Ranks"},{"t":3,"p":1,"n":"Playable"},{"t":3,"p":1,"n":"Hidden"}]},{"t":3,"p":1,"n":"NNAM - Next Perk"},{"t":10,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":6,"p":1,"n":"PRKE - Header","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Rank"},{"t":3,"p":1,"n":"Priority"}]},{"t":6,"p":1,"n":"Quest + Stage","c":[{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"Ability"},{"t":6,"p":1,"n":"Entry Point","c":[{"t":3,"p":1,"n":"Entry Point"},{"t":3,"p":1,"n":"Function"},{"t":3,"p":1,"n":"Perk Condition Tab Count"}]},{"t":10,"p":1,"n":"Perk Conditions","c":[{"t":6,"p":1,"n":"Perk Condition","c":[{"t":3,"p":1,"n":"PRKC - Run On (Tab Index)"},{"t":8,"s":1,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]},{"t":6,"p":1,"n":"Function Parameters","c":[{"t":3,"p":1,"n":"EPFT - Type"},{"t":2,"p":1,"n":"EPF2 - Button Label"},{"t":6,"p":1,"n":"EPF3 - Script Flags","c":[{"t":3,"p":1,"n":"Script Flags"},{"t":11,"n":"Unknown"}]},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"Float"},{"t":6,"p":1,"n":"Float, Float","c":[{"t":5,"p":1,"n":"Float 1"},{"t":5,"p":1,"n":"Float 2"}]},{"t":3,"p":1,"n":"Leveled Item"},{"t":3,"p":1,"n":"Spell"},{"t":2,"p":1,"n":"Text"},{"t":6,"p":1,"n":"Actor Value, Float","c":[{"t":3,"p":1,"n":"Actor Value"},{"t":5,"p":1,"n":"Float"}]}]},{"p":1,"n":"PRKF - End Marker"}]}]}]},{"t":1,"p":1,"n":"PFLA - Placed Flame","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Projectile"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"PGRE - Placed Projectile","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Projectile"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"PHZD - Placed Hazard","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Projectile"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"PMIS - Placed Missile","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Projectile"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"PROJ - Projectile","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Type"},{"t":5,"p":1,"n":"Gravity"},{"t":5,"p":1,"n":"Speed"},{"t":5,"p":1,"n":"Range"},{"t":3,"p":1,"n":"Light"},{"t":3,"p":1,"n":"Muzzle Flash - Light"},{"t":5,"p":1,"n":"Tracer Chance"},{"t":5,"p":1,"n":"Explosion - Alt. Trigger - Proximity"},{"t":5,"p":1,"n":"Explosion - Alt. Trigger - Timer"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Sound"},{"t":5,"p":1,"n":"Muzzle Flash - Duration"},{"t":5,"p":1,"n":"Fade Duration"},{"t":5,"p":1,"n":"Impact Force"},{"t":3,"p":1,"n":"Sound - Countdown"},{"t":3,"p":1,"n":"Sound - Disable"},{"t":3,"p":1,"n":"Default Weapon Source"},{"t":5,"p":1,"n":"Cone Spread"},{"t":5,"p":1,"n":"Collision Radius"},{"t":5,"p":1,"n":"Lifetime"},{"t":5,"p":1,"n":"Relaunch Interval"},{"t":3,"p":1,"n":"Decal Data"},{"t":3,"p":1,"n":"Collision Layer"}]},{"t":6,"s":1,"p":1,"n":"Muzzle Flash Model","c":[{"t":2,"p":1,"n":"NAM1 - Model Filename"},{"t":11,"p":1,"n":"NAM2 - Texture Files Hashes"}]},{"t":3,"p":1,"n":"VNAM - Sound Level"}]},{"t":1,"p":1,"n":"PWAT","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"}]},{"t":1,"p":1,"n":"QUST - Quest","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]},{"t":6,"p":1,"n":"Script Fragments","c":[{"t":3,"n":"Unknown"},{"t":3,"p":1,"n":"fragmentCount"},{"t":2,"p":1,"n":"fileName"},{"t":7,"p":1,"n":"Fragments","c":[{"t":6,"p":1,"n":"Fragment","c":[{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"n":"Unknown"},{"t":3,"p":1,"n":"Quest Stage Index"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]}]},{"t":7,"p":1,"n":"Aliases","c":[{"t":6,"p":1,"n":"Alias","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Alias Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"DNAM - General","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Priority"},{"t":3,"p":1,"n":"Form Version"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Type"}]},{"t":2,"p":1,"n":"ENAM - Event"},{"t":8,"s":1,"p":1,"n":"Text Display Globals","d":1,"c":[{"t":3,"p":1,"n":"QTGL - Global"}]},{"t":2,"p":1,"n":"FLTR - Object Window Filter"},{"t":6,"s":1,"p":1,"n":"Quest Dialogue Conditions","c":[{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]},{"p":1,"n":"NEXT - Marker"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":10,"s":1,"p":1,"n":"Stages","d":1,"c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"INDX - Stage Index","c":[{"t":3,"p":1,"n":"Stage Index"},{"t":3,"p":1,"n":"Flags"},{"t":3,"n":"Unknown"}]},{"t":8,"p":1,"n":"Log Entries","c":[{"t":6,"p":1,"n":"Log Entry","c":[{"t":3,"p":1,"n":"QSDT - Stage Flags"},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":2,"p":1,"n":"CNAM - Log Entry"},{"t":3,"p":1,"n":"NAM0 - Next Quest"},{"t":11,"n":"SCHR - Unused"},{"t":11,"n":"SCTX - Unused"},{"t":11,"n":"QNAM - Unused"}]}]}]}]},{"t":8,"s":1,"p":1,"n":"Objectives","d":1,"c":[{"t":6,"p":1,"n":"Objective","c":[{"t":3,"p":1,"n":"QOBJ - Objective Index"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":2,"p":1,"n":"NNAM - Display Text"},{"t":8,"p":1,"n":"Targets","c":[{"t":6,"p":1,"n":"Target","c":[{"t":6,"p":1,"n":"QSTA - Target","c":[{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]}]}]},{"t":11,"n":"ANAM - Aliases Marker"},{"t":8,"s":1,"p":1,"n":"Aliases","d":1,"c":[{"t":6,"p":1,"n":"Alias","c":[{"t":3,"p":1,"n":"ALST - Reference Alias ID"},{"t":2,"p":1,"n":"ALID - Alias Name"},{"t":6,"p":1,"n":"FNAM - Alias Flags","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Additional Flags"}]},{"t":3,"p":1,"n":"ALFI - Force Into Alias When Filled"},{"t":3,"p":1,"n":"ALFL - Specific Location"},{"t":3,"p":1,"n":"ALFR - Forced Reference"},{"t":3,"p":1,"n":"ALUA - Unique Actor"},{"t":6,"p":1,"n":"Location Alias Reference","c":[{"t":3,"p":1,"n":"ALFA - Alias"},{"t":3,"p":1,"n":"KNAM - Keyword"},{"t":3,"p":1,"n":"ALRT - Ref Type"}]},{"t":6,"p":1,"n":"External Alias Reference","c":[{"t":3,"p":1,"n":"ALEQ - Quest"},{"t":3,"p":1,"n":"ALEA - Alias"}]},{"t":6,"p":1,"n":"Create Reference to Object","c":[{"t":3,"p":1,"n":"ALCO - Object"},{"t":6,"p":1,"n":"ALCA - Alias","c":[{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Create"}]},{"t":3,"p":1,"n":"ALCL - Level"}]},{"t":6,"p":1,"n":"Find Matching Reference Near Alias","c":[{"t":3,"p":1,"n":"ALNA - Alias"},{"t":3,"p":1,"n":"ALNT - Type"}]},{"t":6,"p":1,"n":"Find Matching Reference From Event","c":[{"t":2,"p":1,"n":"ALFE - From Event"},{"t":11,"p":1,"n":"ALFD - Event Data"}]},{"t":8,"s":1,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":3,"p":1,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":3,"p":1,"n":"COCT - Count"},{"t":10,"p":1,"n":"Items","c":[{"t":6,"p":1,"n":"Item","c":[{"t":6,"p":1,"n":"CNTO - Item","c":[{"t":3,"p":1,"n":"Item"},{"t":3,"p":1,"n":"Count"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]},{"t":3,"p":1,"n":"SPOR - Spectator override package list"},{"t":3,"p":1,"n":"OCOR - Observe dead body override package list"},{"t":3,"p":1,"n":"GWOR - Guard warn override package list"},{"t":3,"p":1,"n":"ECOR - Combat override package list"},{"t":3,"p":1,"n":"ALDN - Display Name"},{"t":8,"p":1,"n":"Alias Spells","c":[{"t":3,"p":1,"n":"ALSP - Spell"}]},{"t":8,"p":1,"n":"Alias Factions","c":[{"t":3,"p":1,"n":"ALFC - Faction"}]},{"t":8,"p":1,"n":"Alias Package Data","c":[{"t":3,"p":1,"n":"ALPC - Package"}]},{"t":3,"p":1,"n":"VTCK - Voice Types"},{"p":1,"n":"ALED - Alias End"}]}]},{"t":2,"p":1,"n":"NNAM - Description"},{"t":8,"s":1,"p":1,"n":"Targets","d":1,"c":[{"t":6,"p":1,"n":"Target","c":[{"t":6,"p":1,"n":"QSTA - Target","c":[{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"}]},{"t":8,"s":1,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]}]},{"t":1,"p":1,"n":"RACE - Race","f":1,"c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"DESC - Description"},{"t":3,"n":"SPCT - Count"},{"t":8,"s":1,"p":1,"n":"Actor Effects","c":[{"t":3,"p":1,"n":"SPLO - Actor Effect"}]},{"t":3,"p":1,"n":"WNAM - Skin"},{"t":6,"s":1,"p":1,"n":"BOD2 - Biped Body Template","c":[{"t":3,"p":1,"n":"First Person Flags"},{"t":3,"p":1,"n":"General Flags"},{"n":"Unused"},{"t":3,"p":1,"n":"Armor Type"}]},{"t":6,"s":1,"p":1,"n":"BODT - Body Template","c":[{"t":3,"p":1,"n":"First Person Flags"},{"t":3,"p":1,"n":"General Flags"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Armor Type"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":7,"p":1,"n":"Skill Boosts","c":[{"t":6,"p":1,"n":"Skill Boost","c":[{"t":3,"p":1,"n":"Skill"},{"t":3,"p":1,"n":"Boost"}]}]},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"Male Height"},{"t":5,"p":1,"n":"Female Height"},{"t":5,"p":1,"n":"Male Weight"},{"t":5,"p":1,"n":"Female Weight"},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Starting Health"},{"t":5,"p":1,"n":"Starting Magicka"},{"t":5,"p":1,"n":"Starting Stamina"},{"t":5,"p":1,"n":"Base Carry Weight"},{"t":5,"p":1,"n":"Base Mass"},{"t":5,"p":1,"n":"Acceleration rate"},{"t":5,"p":1,"n":"Deceleration rate"},{"t":3,"p":1,"n":"Size"},{"t":3,"p":1,"n":"Head Biped Object"},{"t":3,"p":1,"n":"Hair Biped Object"},{"t":5,"p":1,"n":"Injured Health Pct"},{"t":3,"p":1,"n":"Shield Biped Object"},{"t":5,"p":1,"n":"Health Regen"},{"t":5,"p":1,"n":"Magicka Regen"},{"t":5,"p":1,"n":"Stamina Regen"},{"t":5,"p":1,"n":"Unarmed Damage"},{"t":5,"p":1,"n":"Unarmed Reach"},{"t":3,"p":1,"n":"Body Biped Object"},{"t":5,"p":1,"n":"Aim Angle Tolerance"},{"t":5,"p":1,"n":"Flight Radius"},{"t":5,"p":1,"n":"Angular Acceleration Rate"},{"t":5,"p":1,"n":"Angular Tolerance"},{"t":3,"p":1,"n":"Flags 2"},{"t":6,"p":1,"n":"Mount Data","c":[{"t":5,"p":1,"n":"Offset X"},{"t":5,"p":1,"n":"Offset Y"},{"t":5,"p":1,"n":"Unknown"}]}]},{"p":1,"n":"MNAM - Male Marker"},{"t":2,"p":1,"n":"ANAM - Male Skeletal Model"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"p":1,"n":"FNAM - Female Marker"},{"t":2,"p":1,"n":"ANAM - Female Skeletal Model"},{"p":1,"n":"NAM2 - Marker NAM2 #1"},{"t":8,"p":1,"n":"Movement Type Names","c":[{"t":2,"p":1,"n":"MTNM - Name"}]},{"t":7,"p":1,"n":"VTCK - Voices","c":[{"t":3,"p":1,"n":"Voice"}]},{"t":7,"p":1,"n":"DNAM - Decapitate Armors","c":[{"t":3,"p":1,"n":"Decapitate Armor"}]},{"t":7,"p":1,"n":"HCLF - Default Hair Colors","c":[{"t":3,"p":1,"n":"Default Hair Color"}]},{"t":3,"n":"TINL - Total Number of Tints in List"},{"t":5,"p":1,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"p":1,"n":"UNAM - FaceGen - Face clamp"},{"t":3,"p":1,"n":"ATKR - Attack Race"},{"t":10,"p":1,"n":"Attacks","c":[{"t":6,"p":1,"n":"Attack","c":[{"t":6,"p":1,"n":"ATKD - Attack Data","c":[{"t":5,"p":1,"n":"Damage Mult"},{"t":5,"p":1,"n":"Attack Chance"},{"t":3,"p":1,"n":"Attack Spell"},{"t":3,"p":1,"n":"Attack Flags"},{"t":5,"p":1,"n":"Attack Angle"},{"t":5,"p":1,"n":"Strike Angle"},{"t":5,"p":1,"n":"Stagger"},{"t":3,"p":1,"n":"Attack Type"},{"t":5,"p":1,"n":"Knockdown"},{"t":5,"p":1,"n":"Recovery Time"},{"t":5,"p":1,"n":"Stamina Mult"}]},{"t":2,"p":1,"n":"ATKE - Attack Event"}]}]},{"t":6,"p":1,"n":"Body Data","c":[{"n":"NAM1 - Body Data Marker"},{"t":6,"p":1,"n":"Male Body Data","c":[{"n":"MNAM - Male Data Marker"},{"t":10,"s":1,"p":1,"n":"Parts","d":1,"c":[{"t":6,"p":1,"n":"Part","c":[{"t":3,"p":1,"n":"INDX - Index"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]}]}]}]},{"t":6,"p":1,"n":"Female Body Data","c":[{"n":"FNAM - Female Data Marker"},{"t":10,"s":1,"p":1,"n":"Parts","d":1,"c":[{"t":6,"p":1,"n":"Part","c":[{"t":3,"p":1,"n":"INDX - Index"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]}]}]}]}]},{"t":7,"p":1,"n":"HNAM - Hairs","c":[{"t":3,"p":1,"n":"Hair"}]},{"t":7,"p":1,"n":"ENAM - Eyes","c":[{"t":3,"p":1,"n":"Eye"}]},{"t":3,"p":1,"n":"GNAM - Body Part Data"},{"p":1,"n":"NAM2 - Marker NAM2 #2"},{"p":1,"n":"NAM3 - Marker NAM3 #3"},{"t":6,"s":1,"p":1,"n":"Male Behavior Graph","c":[{"p":1,"n":"MNAM - Male Data Marker"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]}]},{"t":6,"s":1,"p":1,"n":"Female Behavior Graph","c":[{"p":1,"n":"FNAM - Female Data Marker"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]}]},{"t":3,"p":1,"n":"NAM4 - Material Type"},{"t":3,"p":1,"n":"NAM5 - Impact Data Set"},{"t":3,"p":1,"n":"NAM7 - Decapitation FX"},{"t":3,"p":1,"n":"ONAM - Open Loot Sound"},{"t":3,"p":1,"n":"LNAM - Close Loot Sound"},{"t":8,"p":1,"n":"Biped Object Names","c":[{"t":2,"p":1,"n":"NAME - Name"}]},{"t":10,"n":"Movement Types","c":[{"t":6,"n":"Movement Types","c":[{"t":3,"n":"MTYP - Movement Type"},{"t":6,"n":"SPED - Override Values","c":[{"t":5,"n":"Left - Walk"},{"t":5,"n":"Left - Run"},{"t":5,"n":"Right - Walk"},{"t":5,"n":"Right - Run"},{"t":5,"n":"Forward - Walk"},{"t":5,"n":"Forward - Run"},{"t":5,"n":"Back - Walk"},{"t":5,"n":"Back - Run"},{"t":5,"n":"Rotate - Walk"},{"t":5,"n":"Unknown"}]}]}]},{"t":3,"n":"VNAM - Equipment Flags"},{"t":8,"p":1,"n":"Equip Slots","c":[{"t":3,"p":1,"n":"QNAM - Equip Slot"}]},{"t":3,"n":"UNES - Unarmed Equip Slot"},{"t":8,"n":"Phoneme Target Names","c":[{"t":2,"n":"PHTN - Name"}]},{"t":6,"n":"FaceFX Phonemes","c":[{"t":6,"n":"IY","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"IH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"EH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"EY","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"AE","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"AA","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"AW","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"AY","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"AH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"AO","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"OY","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"OW","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"UH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"UW","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"ER","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"AX","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"S","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"SH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"Z","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"ZH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"F","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"TH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"V","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"DH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"M","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"N","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"NG","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"L","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"R","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"W","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"Y","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"HH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"B","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"D","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"JH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"G","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"P","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"T","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"K","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"CH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"SIL","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"SHOTSIL","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"FLAP","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]}]},{"t":3,"n":"WKMV - Base Movement Default - Walk"},{"t":3,"n":"RNMV - Base Movement Default - Run"},{"t":3,"n":"SWMV - Base Movement Default - Swim"},{"t":3,"n":"FLMV - Base Movement Default - Fly"},{"t":3,"n":"SNMV - Base Movement Default - Sneak"},{"t":3,"n":"SPMV - Base Movement Default - Sprint"},{"t":6,"p":1,"n":"Head Data","c":[{"n":"NAM0 - Head Data Marker"},{"t":6,"s":1,"p":1,"n":"Male Head Data","c":[{"p":1,"n":"MNAM - Male Data Marker"},{"t":10,"p":1,"n":"Head Parts","c":[{"t":6,"p":1,"n":"Head Part","c":[{"t":3,"p":1,"n":"INDX - Head Part Number"},{"t":3,"p":1,"n":"HEAD - Head"}]}]},{"t":6,"n":"Available Morphs","c":[{"t":11,"n":"MPAI - Unknown"},{"t":6,"n":"MPAV - Nose Variants","c":[{"t":3,"n":"Nose Morph Flags"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"MPAV - Brow Variants","c":[{"t":3,"n":"Brow Morph Flags"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"MPAV - Eye Variants","c":[{"t":3,"n":"Eye Morph Flags 1"},{"t":3,"n":"Eye Morph Flags 2"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"MPAV - Lip Variants","c":[{"t":3,"n":"Lip Morph Flags"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Race Presets Male","c":[{"t":3,"n":"RPRM - Preset NPC"}]},{"t":8,"n":"Available Hair Colors Male","c":[{"t":3,"n":"AHCM - Hair Color"}]},{"t":8,"n":"Face Details Texture Set List Male","c":[{"t":3,"n":"FTSM - Texture Set"}]},{"t":3,"n":"DFTM - Default Face Texture Male"},{"t":8,"p":1,"n":"Tint Masks","c":[{"t":6,"p":1,"n":"Tint Assets","c":[{"t":8,"p":1,"n":"Tint Layer","c":[{"t":6,"p":1,"n":"Texture","c":[{"t":3,"p":1,"n":"TINI - Index"},{"t":2,"p":1,"n":"TINT - File Name"},{"t":3,"p":1,"n":"TINP - Mask Type"},{"t":3,"p":1,"n":"TIND - Preset Default"}]}]},{"t":8,"p":1,"n":"Presets","c":[{"t":6,"p":1,"n":"Preset","c":[{"t":3,"p":1,"n":"TINC - Color"},{"t":5,"p":1,"n":"TINV - Default Value"},{"t":3,"p":1,"n":"TIRS - Index"}]}]}]}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]}]},{"t":6,"s":1,"p":1,"n":"Female Head Data","c":[{"p":1,"n":"NAM0 - Head Data Marker"},{"p":1,"n":"FNAM - Female Data Marker"},{"t":10,"p":1,"n":"Head Parts","c":[{"t":6,"p":1,"n":"Head Part","c":[{"t":3,"p":1,"n":"INDX - Head Part Number"},{"t":3,"p":1,"n":"HEAD - Head"}]}]},{"t":6,"n":"Available Morphs","c":[{"t":11,"n":"MPAI - Unknown"},{"t":6,"n":"MPAV - Nose Variants","c":[{"t":3,"n":"Nose Morph Flags"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"MPAV - Brow Variants","c":[{"t":3,"n":"Brow Morph Flags"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"MPAV - Eye Variants","c":[{"t":3,"n":"Eye Morph Flags 1"},{"t":3,"n":"Eye Morph Flags 2"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"MPAV - Lip Variants","c":[{"t":3,"n":"Lip Morph Flags"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Race Presets Female","c":[{"t":3,"n":"RPRF - Preset NPC"}]},{"t":8,"n":"Available Hair Colors Female","c":[{"t":3,"n":"AHCF - Hair Color"}]},{"t":8,"n":"Face Details Texture Set List Female","c":[{"t":3,"n":"FTSF - Texture Set"}]},{"t":3,"n":"DFTF - Default Face Texture Female"},{"t":8,"p":1,"n":"Tint Masks","c":[{"t":6,"p":1,"n":"Tint Assets","c":[{"t":8,"p":1,"n":"Tint Layer","c":[{"t":6,"p":1,"n":"Texture","c":[{"t":3,"p":1,"n":"TINI - Index"},{"t":2,"p":1,"n":"TINT - File Name"},{"t":3,"p":1,"n":"TINP - Mask Type"},{"t":3,"p":1,"n":"TIND - Preset Default"}]}]},{"t":8,"p":1,"n":"Presets","c":[{"t":6,"p":1,"n":"Preset","c":[{"t":3,"p":1,"n":"TINC - Color"},{"t":5,"p":1,"n":"TINV - Default Value"},{"t":3,"p":1,"n":"TIRS - Index"}]}]}]}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]}]}]},{"t":3,"n":"NAM8 - Morph race"},{"t":3,"n":"RNAM - Armor race"}]},{"t":1,"p":1,"n":"REFR - Placed Object","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Base"},{"t":6,"s":1,"p":1,"n":"XMBO - Bound Half Extents","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"s":1,"p":1,"n":"XPRM - Primitive","c":[{"t":6,"p":1,"n":"Bounds","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Color","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}]},{"t":5,"n":"Unknown"},{"t":3,"p":1,"n":"Type"}]},{"t":11,"n":"XORD - Unknown"},{"t":6,"s":1,"p":1,"n":"XOCP - Occlusion Plane Data","c":[{"t":6,"p":1,"n":"Size","c":[{"t":5,"p":1,"n":"Width"},{"t":5,"p":1,"n":"Height"}]},{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation (Quaternion?)","c":[{"t":5,"p":1,"n":"q1"},{"t":5,"p":1,"n":"q2"},{"t":5,"p":1,"n":"q3"},{"t":5,"p":1,"n":"q4"}]}]},{"t":7,"p":1,"n":"XPOD - Portal Data","c":[{"t":6,"p":1,"n":"References","c":[{"t":3,"p":1,"n":"Origin"},{"t":3,"p":1,"n":"Destination"}]}]},{"t":6,"s":1,"p":1,"n":"XPTL - Room Portal (unused)","c":[{"t":6,"p":1,"n":"Size","c":[{"t":5,"p":1,"n":"Width"},{"t":5,"p":1,"n":"Height"}]},{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation (Quaternion?)","c":[{"t":5,"p":1,"n":"q1"},{"t":5,"p":1,"n":"q2"},{"t":5,"p":1,"n":"q3"},{"t":5,"p":1,"n":"q4"}]}]},{"t":6,"s":1,"p":1,"n":"Bound Data","c":[{"t":6,"p":1,"n":"XRMR - Header","c":[{"t":3,"p":1,"n":"Linked Rooms Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"}]},{"t":3,"p":1,"n":"LNAM - Lighting Template"},{"t":3,"p":1,"n":"INAM - Image Space"},{"t":8,"p":1,"n":"Linked Rooms","c":[{"t":3,"p":1,"n":"XLRM - Linked Room"}]}]},{"p":1,"n":"XMBP - MultiBound Primitive Marker"},{"t":11,"n":"XRGD - Ragdoll Data"},{"t":11,"n":"XRGB - Ragdoll Biped Data"},{"t":5,"p":1,"n":"XRDS - Radius"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Lit Water","d":1,"c":[{"t":3,"p":1,"n":"XLTW - Water"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":6,"s":1,"p":1,"n":"XLIG - Light Data","c":[{"t":5,"p":1,"n":"FOV 90+\/-"},{"t":5,"p":1,"n":"Fade 1.35+\/-"},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"Shadow Depth Bias"}]},{"t":6,"s":1,"p":1,"n":"XALP - Alpha","c":[{"t":3,"p":1,"n":"Cutoff"},{"t":3,"p":1,"n":"Base"}]},{"t":6,"s":1,"p":1,"n":"XTEL - Teleport Destination","c":[{"t":3,"p":1,"n":"Door"},{"t":6,"p":1,"n":"Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]},{"t":3,"p":1,"n":"Flags"}]},{"t":3,"p":1,"n":"XTNM - Teleport Message Box"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"t":11,"n":"XWCN - Unknown"},{"t":11,"n":"XWCS - Unknown"},{"t":6,"s":1,"p":1,"n":"XWCU - Water Velocity","c":[{"t":5,"p":1,"n":"X Offset"},{"t":5,"p":1,"n":"Y Offset"},{"t":5,"p":1,"n":"Z Offset"},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"X Angle"},{"t":5,"p":1,"n":"Y Angle"},{"t":5,"p":1,"n":"Z Angle"}]},{"t":6,"n":"XCVL - Unknown","c":[{"t":11,"n":"Unknown"},{"t":5,"n":"X Angle"}]},{"t":3,"n":"XCZR - Unknown"},{"t":11,"n":"XCZA - Unknown"},{"t":3,"n":"XCZC - Unknown"},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":3,"p":1,"n":"XSPC - Spawn Container"},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":3,"p":1,"n":"XLIB - Leveled Item Base Object"},{"t":3,"p":1,"n":"XLCM - Level Modifier"},{"t":3,"p":1,"n":"XLCN - Persistent Location"},{"t":3,"p":1,"n":"XTRI - Collision Layer"},{"t":6,"s":1,"p":1,"n":"XLOC - Lock Data","c":[{"t":3,"p":1,"n":"Level"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Key"},{"t":3,"p":1,"n":"Flags"}]},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":6,"s":1,"p":1,"n":"XNDP - Navigation Door Link","c":[{"t":3,"p":1,"n":"Navigation Mesh"},{"t":3,"p":1,"n":"Teleport Marker Triangle"},{"t":11,"n":"Unused"}]},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":3,"p":1,"n":"XCNT - Item Count"},{"t":5,"p":1,"n":"XCHG - Charge"},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":8,"s":1,"p":1,"n":"Patrol","d":1,"c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"XPRD - Idle Time"},{"p":1,"n":"XPPA - Patrol Script Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":11,"n":"SCHR - Unused"},{"t":11,"n":"SCTX - Unused"},{"t":8,"p":1,"n":"Topic","c":[{"t":6,"p":1,"n":"PDTO - Topic Data","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Topic"},{"t":2,"p":1,"n":"Subtype"}]}]}]}]},{"t":3,"p":1,"n":"XACT - Action Flag"},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"p":1,"n":"ONAM - Open by Default"},{"t":6,"s":1,"p":1,"n":"Map Marker","c":[{"p":1,"n":"XMRK - Map Marker Data"},{"t":3,"p":1,"n":"FNAM - Map Flags"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"p":1,"n":"TNAM - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"}]}]},{"t":3,"p":1,"n":"XATR - Attach Ref"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"REGN - Region","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"RCLR - Map Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":3,"p":1,"n":"WNAM - Worldspace"},{"t":8,"s":1,"p":1,"n":"Region Areas","d":1,"c":[{"t":6,"p":1,"n":"Region Area","c":[{"t":3,"p":1,"n":"RPLI - Edge Fall-off"},{"t":7,"p":1,"n":"RPLD - Region Point List Data","c":[{"t":6,"p":1,"n":"Point","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"}]}]}]}]},{"t":10,"p":1,"n":"Region Data Entries","d":1,"c":[{"t":6,"p":1,"n":"Region Data Entry","c":[{"t":6,"p":1,"n":"RDAT - Data Header","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Priority"},{"t":11,"n":"Unknown"}]},{"t":6,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":3,"p":1,"n":"RDMO - Music"},{"t":7,"p":1,"n":"RDSA - Sounds","c":[{"t":6,"p":1,"n":"Sound","c":[{"t":3,"p":1,"n":"Sound"},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Chance"}]}]},{"t":2,"p":1,"n":"RDMP - Map Name"},{"t":7,"p":1,"n":"RDOT - Objects","c":[{"t":6,"p":1,"n":"Object","c":[{"t":3,"p":1,"n":"Object"},{"t":3,"p":1,"n":"Parent Index"},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"Density"},{"t":3,"p":1,"n":"Clustering"},{"t":3,"p":1,"n":"Min Slope"},{"t":3,"p":1,"n":"Max Slope"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Radius wrt Parent"},{"t":3,"p":1,"n":"Radius"},{"t":5,"p":1,"n":"Min Height"},{"t":5,"p":1,"n":"Max Height"},{"t":5,"p":1,"n":"Sink"},{"t":5,"p":1,"n":"Sink Variance"},{"t":5,"p":1,"n":"Size Variance"},{"t":6,"p":1,"n":"Angle Variance","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"},{"t":3,"p":1,"n":"Z"}]}]}]},{"t":7,"p":1,"n":"RDGS - Grasses","c":[{"t":6,"p":1,"n":"Grass","c":[{"t":3,"p":1,"n":"Grass"},{"t":11,"n":"Unknown"}]}]},{"t":7,"p":1,"n":"RDWT - Weather Types","c":[{"t":6,"p":1,"n":"Weather Type","c":[{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Chance"},{"t":3,"p":1,"n":"Global"}]}]}]}]}]},{"t":1,"p":1,"n":"RELA - Relationship","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Parent"},{"t":3,"p":1,"n":"Child"},{"t":3,"p":1,"n":"Rank"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Association Type"}]}]},{"t":1,"p":1,"n":"REVB - Reverb Parameters","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Decay Time (ms)"},{"t":3,"p":1,"n":"HF Reference (Hz)"},{"t":3,"p":1,"n":"Room Filter"},{"t":3,"p":1,"n":"Room HF Filter"},{"t":3,"p":1,"n":"Reflections"},{"t":3,"p":1,"n":"Reverb Amp"},{"t":3,"p":1,"n":"Decay HF Ratio"},{"t":3,"p":1,"n":"Reflect Delay (ms), scaled"},{"t":3,"p":1,"n":"Reverb Delay (ms)"},{"t":3,"p":1,"n":"Diffusion %"},{"t":3,"p":1,"n":"Density %"},{"t":3,"n":"Unknown"}]}]},{"t":1,"p":1,"n":"RFCT - Visual Effect","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - Effect Data","c":[{"t":3,"p":1,"n":"Effect Art"},{"t":3,"p":1,"n":"Shader"},{"t":3,"p":1,"n":"Flags"}]}]},{"t":1,"p":1,"n":"RGDL","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"}]},{"t":1,"p":1,"n":"SCEN - Scene","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]},{"t":6,"p":1,"n":"Script Fragments","c":[{"t":3,"n":"Unknown"},{"t":3,"p":1,"n":"Flags"},{"t":2,"p":1,"n":"fileName"},{"t":7,"p":1,"n":"Fragments","c":[{"t":6,"p":1,"n":"Fragment","c":[{"t":3,"n":"Unknown"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]},{"t":7,"p":1,"n":"Phase Fragments","c":[{"t":6,"p":1,"n":"Phase Fragment","c":[{"t":3,"p":1,"n":"Phase Flag"},{"t":3,"p":1,"n":"Phase Index"},{"t":3,"n":"Unknown"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]}]}]},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":8,"s":1,"p":1,"n":"Phases","d":1,"c":[{"t":6,"p":1,"n":"Phase","c":[{"p":1,"n":"HNAM - Marker Phase Start"},{"t":2,"p":1,"n":"NAM0 - Name"},{"t":6,"p":1,"n":"Start Conditions","c":[{"t":8,"s":1,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]},{"p":1,"n":"NEXT - Marker"},{"t":6,"p":1,"n":"Completion Conditions","c":[{"t":8,"s":1,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]},{"t":6,"n":"Unused","c":[{"t":11,"n":"SCHR - Unknown"},{"t":11,"n":"SCDA - Unknown"},{"t":11,"n":"SCTX - Unknown"},{"t":11,"n":"QNAM - Unknown"},{"t":11,"n":"SCRO - Unknown"}]},{"t":3,"p":1,"n":"WNAM - Editor Width"},{"p":1,"n":"HNAM - Marker Phase End"}]}]},{"t":8,"s":1,"p":1,"n":"Actors","d":1,"c":[{"t":6,"p":1,"n":"Actor","c":[{"t":3,"p":1,"n":"ALID - Actor ID"},{"t":3,"p":1,"n":"LNAM - Flags"},{"t":3,"p":1,"n":"DNAM - Behaviour Flags"}]}]},{"t":8,"s":1,"p":1,"n":"Actions","d":1,"c":[{"t":6,"p":1,"n":"Action","c":[{"t":3,"p":1,"n":"ANAM - Type"},{"t":2,"p":1,"n":"NAM0 - Name"},{"t":3,"p":1,"n":"ALID - Actor ID"},{"t":11,"n":"LNAM - Unknown"},{"t":3,"p":1,"n":"INAM - Index"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":3,"p":1,"n":"SNAM - Start Phase"},{"t":3,"p":1,"n":"ENAM - End Phase"},{"t":5,"p":1,"n":"SNAM - Timer Seconds"},{"t":8,"p":1,"n":"Packages","c":[{"t":3,"p":1,"n":"PNAM - Package"}]},{"t":3,"p":1,"n":"DATA - Topic"},{"t":3,"p":1,"n":"HTID - Headtrack Actor ID"},{"t":5,"p":1,"n":"DMAX - Looping - Max"},{"t":5,"p":1,"n":"DMIN - Looping - Min"},{"t":3,"p":1,"n":"DEMO - Emotion Type"},{"t":3,"p":1,"n":"DEVA - Emotion Value"},{"t":6,"n":"Unused","c":[{"t":11,"n":"SCHR - Unknown"},{"t":11,"n":"SCDA - Unknown"},{"t":11,"n":"SCTX - Unknown"},{"t":11,"n":"QNAM - Unknown"},{"t":11,"n":"SCRO - Unknown"}]},{"p":1,"n":"ANAM - End Marker"}]}]},{"t":6,"n":"Unused","c":[{"t":11,"n":"SCHR - Unknown"},{"t":11,"n":"SCDA - Unknown"},{"t":11,"n":"SCTX - Unknown"},{"t":11,"n":"QNAM - Unknown"},{"t":11,"n":"SCRO - Unknown"}]},{"p":1,"n":"NEXT - Marker"},{"t":3,"p":1,"n":"PNAM - Quest"},{"t":3,"p":1,"n":"INAM - Last Action Index"},{"t":11,"n":"VNAM - Unknown"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]},{"t":1,"p":1,"n":"SCOL","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"}]},{"t":1,"p":1,"n":"SCPT","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"}]},{"t":1,"p":1,"n":"SCRL - Scroll","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":3,"p":1,"n":"MDOB - Menu Display Object"},{"t":3,"p":1,"n":"ETYP - Equipment Type"},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":6,"s":1,"p":1,"n":"DATA - Item","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":6,"s":1,"p":1,"n":"SPIT - Data","c":[{"t":3,"p":1,"n":"Base Cost"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Type"},{"t":5,"p":1,"n":"Charge Time"},{"t":3,"p":1,"n":"Cast Type"},{"t":3,"p":1,"n":"Target Type"},{"t":5,"p":1,"n":"Cast Duration"},{"t":5,"p":1,"n":"Range"},{"t":3,"p":1,"n":"Half-cost Perk"}]},{"t":8,"s":1,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":3,"p":1,"n":"EFID - Base Effect"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":5,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"}]},{"t":8,"s":1,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]}]},{"t":1,"p":1,"n":"SHOU - Shout","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"MDOB - Menu Display Object"},{"t":2,"p":1,"n":"DESC - Description"},{"t":8,"s":1,"p":1,"n":"Words of Power","d":1,"c":[{"t":6,"p":1,"n":"SNAM - ","c":[{"t":3,"p":1,"n":"Word"},{"t":3,"p":1,"n":"Spell"},{"t":5,"p":1,"n":"Recovery Time"}]}]}]},{"t":1,"p":1,"n":"SLGM - Soul Gem","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":3,"p":1,"n":"SOUL - Contained Soul"},{"t":3,"p":1,"n":"SLCP - Maximum Capacity"},{"t":3,"p":1,"n":"NAM0 - Linked To"}]},{"t":1,"p":1,"n":"SMBN - Story Manager Branch Node","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"PNAM - Parent "},{"t":3,"p":1,"n":"SNAM - Child "},{"t":3,"n":"CITC - Condition Count"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":3,"p":1,"n":"DNAM - Flags"},{"t":11,"n":"XNAM - Unknown"}]},{"t":1,"p":1,"n":"SMEN - Story Manager Event Node","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"PNAM - Parent "},{"t":3,"p":1,"n":"SNAM - Child "},{"t":3,"n":"CITC - Condition Count"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":3,"p":1,"n":"DNAM - Flags"},{"t":11,"n":"XNAM - Unknown"},{"t":2,"p":1,"n":"ENAM - Type"}]},{"t":1,"p":1,"n":"SMQN - Story Manager Quest Node","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"PNAM - Parent "},{"t":3,"p":1,"n":"SNAM - Child "},{"t":3,"n":"CITC - Condition Count"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":6,"s":1,"p":1,"n":"DNAM - Flags","c":[{"t":3,"p":1,"n":"Node Flags"},{"t":3,"p":1,"n":"Quest Flags"}]},{"t":3,"p":1,"n":"XNAM - Max concurrent quests"},{"t":3,"p":1,"n":"MNAM - Num quests to run"},{"t":3,"n":"QNAM - Quest Count"},{"t":10,"p":1,"n":"Quests","d":1,"c":[{"t":6,"p":1,"n":"Quest","c":[{"t":3,"p":1,"n":"NNAM - Quest"},{"t":11,"n":"FNAM - Unknown"},{"t":5,"p":1,"n":"RNAM - Hours until reset"}]}]}]},{"t":1,"p":1,"n":"SNCT - Sound Category","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":3,"p":1,"n":"PNAM - Parent"},{"t":3,"p":1,"n":"VNAM - Static Volume Multiplier"},{"t":3,"p":1,"n":"UNAM - Default Menu Value"}]},{"t":1,"p":1,"n":"SNDR - Sound Descriptor","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":11,"n":"CNAM - Unknown"},{"t":3,"p":1,"n":"GNAM - Category"},{"t":3,"p":1,"n":"SNAM - Alternate Sound For"},{"t":8,"s":1,"p":1,"n":"Sounds","d":1,"c":[{"t":6,"p":1,"n":"Sound Files","c":[{"t":2,"p":1,"n":"ANAM - File Name"}]}]},{"t":3,"p":1,"n":"ONAM - Output Model"},{"t":2,"p":1,"n":"FNAM - String"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":6,"s":1,"p":1,"n":"LNAM - Values","c":[{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Looping"},{"t":3,"p":1,"n":"Rumble Send Value = (Small \/ 7) + ((Big \/ 7) * 16)"}]},{"t":6,"s":1,"p":1,"n":"BNAM - Values","c":[{"t":3,"p":1,"n":"% Frequency Shift"},{"t":3,"p":1,"n":"% Frequency Variance"},{"t":3,"p":1,"n":"Priority"},{"t":3,"p":1,"n":"db Variance"},{"t":3,"p":1,"n":"Static Attenuation (db)"}]}]},{"t":1,"p":1,"n":"SOPM - Sound Output Model","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"NAM1 - Data","c":[{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Reverb Send %"}]},{"t":11,"n":"FNAM - Unknown"},{"t":3,"p":1,"n":"MNAM - Type"},{"t":11,"n":"CNAM - Unknown"},{"t":11,"n":"SNAM - Unknown"},{"t":6,"s":1,"p":1,"n":"ONAM - Output Values","c":[{"t":7,"p":1,"n":"Channels","c":[{"t":6,"p":1,"n":"","c":[{"t":3,"p":1,"n":"L"},{"t":3,"p":1,"n":"R"},{"t":3,"p":1,"n":"C"},{"t":3,"p":1,"n":"LFE"},{"t":3,"p":1,"n":"RL"},{"t":3,"p":1,"n":"RR"},{"t":3,"p":1,"n":"BL"},{"t":3,"p":1,"n":"BR"}]}]}]},{"t":6,"s":1,"p":1,"n":"ANAM - Attenuation Values","c":[{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"Min Distance"},{"t":5,"p":1,"n":"Max Distance"},{"t":7,"p":1,"n":"Curve","c":[{"t":3,"p":1,"n":"Value"}]}]}]},{"t":1,"p":1,"n":"SOUN - Sound Marker","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":11,"n":"FNAM - Unknown"},{"t":11,"n":"SNDD - Unknown"},{"t":3,"p":1,"n":"SDSC - Sound Descriptor"}]},{"t":1,"p":1,"n":"SPEL - Spell","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":3,"p":1,"n":"MDOB - Menu Display Object"},{"t":3,"p":1,"n":"ETYP - Equipment Type"},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"SPIT - Data","c":[{"t":3,"p":1,"n":"Base Cost"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Type"},{"t":5,"p":1,"n":"Charge Time"},{"t":3,"p":1,"n":"Cast Type"},{"t":3,"p":1,"n":"Target Type"},{"t":5,"p":1,"n":"Cast Duration"},{"t":5,"p":1,"n":"Range"},{"t":3,"p":1,"n":"Half-cost Perk"}]},{"t":8,"s":1,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":3,"p":1,"n":"EFID - Base Effect"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":5,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"}]},{"t":8,"s":1,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]}]},{"t":1,"p":1,"n":"SPGD - Shader Particle Geometry","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Gravity Velocity"},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"Rotation Velocity"},{"t":5,"p":1,"n":"Particle Size X"},{"t":5,"p":1,"n":"Center Offset Min"},{"t":5,"p":1,"n":"Particle Size Y"},{"t":5,"p":1,"n":"Center Offset Max"},{"t":5,"p":1,"n":"Initial Rotation"},{"t":3,"p":1,"n":"# of Subtextures X"},{"t":3,"p":1,"n":"# of Subtextures Y"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Box Size"},{"t":5,"p":1,"n":"Particle Density"}]},{"t":2,"p":1,"n":"ICON - Particle Texture"}]},{"t":1,"p":1,"n":"STAT - Static","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"DNAM - Direction Material","c":[{"t":5,"p":1,"n":"Max Angle (30-120)"},{"t":3,"p":1,"n":"Material"}]},{"t":7,"p":1,"n":"MNAM - Distant LOD","c":[{"t":6,"p":1,"n":"LOD","c":[{"t":2,"p":1,"n":"Mesh"}]}]}]},{"t":1,"p":1,"n":"TACT - Talking Activator","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":11,"n":"PNAM - Unknown"},{"t":3,"p":1,"n":"SNAM - Looping Sound"},{"t":11,"n":"FNAM - Unknown"},{"t":3,"p":1,"n":"VNAM - Voice Type"}]},{"t":1,"p":1,"n":"TREE - Tree","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":3,"p":1,"n":"PFIG - Ingredient"},{"t":3,"p":1,"n":"SNAM - Harvest Sound"},{"t":6,"s":1,"p":1,"n":"PFPC - Ingredient Production","c":[{"t":3,"p":1,"n":"Spring"},{"t":3,"p":1,"n":"Summer"},{"t":3,"p":1,"n":"Fall"},{"t":3,"p":1,"n":"Winter"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"CNAM - Tree Data","c":[{"t":5,"p":1,"n":"Trunk Flexibility"},{"t":5,"p":1,"n":"Branch Flexibility"},{"t":5,"n":"Unknown"},{"t":5,"p":1,"n":"Leaf Amplitude"},{"t":5,"p":1,"n":"Leaf Frequency"}]}]},{"t":1,"p":1,"n":"TXST - Texture Set","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Textures (RGB\/A)","c":[{"t":2,"p":1,"n":"TX00 - Difuse"},{"t":2,"p":1,"n":"TX01 - Normal\/Gloss"},{"t":2,"p":1,"n":"TX02 - Environment Mask\/Subsurface Tint"},{"t":2,"p":1,"n":"TX03 - Glow\/Detail Map"},{"t":2,"p":1,"n":"TX04 - Height"},{"t":2,"p":1,"n":"TX05 - Environment"},{"t":2,"p":1,"n":"TX06 - Multilayer"},{"t":2,"p":1,"n":"TX07 - Backlight Mask\/Specular"}]},{"t":6,"s":1,"p":1,"n":"DODT - Decal Data","c":[{"t":5,"p":1,"n":"Min Width"},{"t":5,"p":1,"n":"Max Width"},{"t":5,"p":1,"n":"Min Height"},{"t":5,"p":1,"n":"Max Height"},{"t":5,"p":1,"n":"Depth"},{"t":5,"p":1,"n":"Shininess"},{"t":6,"p":1,"n":"Parallax","c":[{"t":5,"p":1,"n":"Scale"},{"t":3,"p":1,"n":"Passes"}]},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"},{"t":6,"p":1,"n":"Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":3,"p":1,"n":"DNAM - Flags"}]},{"t":1,"p":1,"n":"VOLI - Volumetric Lighting","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":5,"p":1,"n":"CNAM - Intensity"},{"t":5,"p":1,"n":"DNAM - Custom Color - Contribution"},{"t":5,"p":1,"n":"ENAM - Red"},{"t":5,"p":1,"n":"FNAM - Green"},{"t":5,"p":1,"n":"GNAM - Blue"},{"t":5,"p":1,"n":"HNAM - Density - Contribution"},{"t":5,"p":1,"n":"INAM - Density - Size"},{"t":5,"p":1,"n":"JNAM - Density - Wind Speed"},{"t":5,"p":1,"n":"KNAM - Density - Falling Speed"},{"t":5,"p":1,"n":"LNAM - Phase Function - Contribution"},{"t":5,"p":1,"n":"MNAM - Phase Function - Scattering"},{"t":5,"p":1,"n":"NNAM - Sampling Repartition - Range Factor"}]},{"t":1,"p":1,"n":"VTYP - Voice Type","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"DNAM - Flags"}]},{"t":1,"p":1,"n":"WATR - Water","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":8,"n":"Unused","c":[{"t":2,"n":"NNAM - Noise Map"}]},{"t":3,"p":1,"n":"ANAM - Opacity"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":11,"n":"MNAM - Unused"},{"t":3,"p":1,"n":"TNAM - Material"},{"t":3,"p":1,"n":"SNAM - Open Sound"},{"t":3,"p":1,"n":"XNAM - Spell"},{"t":3,"p":1,"n":"INAM - Image Space"},{"t":3,"p":1,"n":"DATA - Damage Per Second"},{"t":6,"s":1,"p":1,"n":"DNAM - Visual Data","c":[{"t":5,"n":"Unknown"},{"t":5,"p":1,"n":"Specular Properties - Sun Specular Power"},{"t":5,"p":1,"n":"Water Properties - Reflectivity Amount"},{"t":5,"p":1,"n":"Water Properties - Fresnel Amount"},{"t":5,"p":1,"n":"Fog Properties - Above Water - Fog Distance - Near Plane"},{"t":5,"p":1,"n":"Fog Properties - Above Water - Fog Distance - Far Plane"},{"t":6,"p":1,"n":"Shallow Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Deep Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Reflection Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Displacement Simulator - Starting Size"},{"t":5,"p":1,"n":"Displacement Simulator - Force"},{"t":5,"p":1,"n":"Displacement Simulator - Velocity"},{"t":5,"p":1,"n":"Displacement Simulator - Falloff"},{"t":5,"p":1,"n":"Displacement Simulator - Dampner"},{"t":5,"p":1,"n":"Noise Properties - Noise Falloff"},{"t":5,"p":1,"n":"Noise Properties - Layer One - Wind Direction"},{"t":5,"p":1,"n":"Noise Properties - Layer Two - Wind Direction"},{"t":5,"p":1,"n":"Noise Properties - Layer Three - Wind Direction"},{"t":5,"p":1,"n":"Noise Properties - Layer One - Wind Speed"},{"t":5,"p":1,"n":"Noise Properties - Layer Two - Wind Speed"},{"t":5,"p":1,"n":"Noise Properties - Layer Three - Wind Speed"},{"t":5,"p":1,"n":"Fog Properties - Above Water - Fog Amount"},{"t":5,"p":1,"n":"Fog Properties - Under Water - Fog Amount"},{"t":5,"p":1,"n":"Fog Properties - Under Water - Fog Distance - Near Plane"},{"t":5,"p":1,"n":"Fog Properties - Under Water - Fog Distance - Far Plane"},{"t":5,"p":1,"n":"Water Properties - Refraction Magnitude"},{"t":5,"p":1,"n":"Specular Properties - Specular Power"},{"t":5,"p":1,"n":"Specular Properties - Specular Radius"},{"t":5,"p":1,"n":"Specular Properties - Specular Brightness"},{"t":5,"p":1,"n":"Noise Properties - Layer One - UV Scale"},{"t":5,"p":1,"n":"Noise Properties - Layer Two - UV Scale"},{"t":5,"p":1,"n":"Noise Properties - Layer Three - UV Scale"},{"t":5,"p":1,"n":"Noise Properties - Layer One - Amplitude Scale"},{"t":5,"p":1,"n":"Noise Properties - Layer Two - Amplitude Scale"},{"t":5,"p":1,"n":"Noise Properties - Layer Three - Amplitude Scale"},{"t":5,"p":1,"n":"Water Properties - Reflection Magnitude"},{"t":5,"p":1,"n":"Specular Properties - Sun Sparkle Magnitude"},{"t":5,"p":1,"n":"Specular Properties - Sun Specular Magnitude"},{"t":5,"p":1,"n":"Depth Properties - Reflections"},{"t":5,"p":1,"n":"Depth Properties - Refraction"},{"t":5,"p":1,"n":"Depth Properties - Normals"},{"t":5,"p":1,"n":"Depth Properties - Specular Lighting"},{"t":5,"p":1,"n":"Specular Properties - Sun Sparkle Power"}]},{"t":11,"n":"GNAM - Unused"},{"t":6,"s":1,"p":1,"n":"NAM0 - Linear Velocity","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"s":1,"p":1,"n":"NAM1 - Angular Velocity","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":2,"p":1,"n":"NAM2 - Noise Layer One - Noise Texture"},{"t":2,"p":1,"n":"NAM3 - Noise Layer Two - Noise Texture"},{"t":2,"p":1,"n":"NAM4 - Noise Layer Three - Noise Texture"},{"t":2,"p":1,"n":"NAM5 - Flow Normals - Noise Texture"}]},{"t":1,"p":1,"n":"WEAP - Weapon","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":3,"p":1,"n":"EITM - Object Effect"},{"t":3,"p":1,"n":"EAMT - Enchantment Amount"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"ETYP - Equipment Type"},{"t":3,"p":1,"n":"BIDS - Block Bash Impact Data Set"},{"t":3,"p":1,"n":"BAMT - Alternate Block Material"},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"Has Scope","c":[{"t":2,"p":1,"n":"MOD3 - Model Filename"},{"t":11,"p":1,"n":"MO3T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO3S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":11,"n":"NNAM - Unused"},{"t":3,"p":1,"n":"INAM - Impact Data Set"},{"t":3,"p":1,"n":"WNAM - 1st Person Model Object"},{"t":3,"p":1,"n":"SNAM - Attack Sound"},{"t":3,"p":1,"n":"XNAM - Attack Sound 2D"},{"t":3,"p":1,"n":"NAM7 - Attack Loop Sound"},{"t":3,"p":1,"n":"TNAM - Attack Fail Sound"},{"t":3,"p":1,"n":"UNAM - Idle Sound"},{"t":3,"p":1,"n":"NAM9 - Equip Sound"},{"t":3,"p":1,"n":"NAM8 - Unequip Sound"},{"t":6,"s":1,"p":1,"n":"DATA - Game Data","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"},{"t":3,"p":1,"n":"Damage"}]},{"t":6,"s":1,"p":1,"n":"DNAM - Data","c":[{"t":3,"p":1,"n":"Animation Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Speed"},{"t":5,"p":1,"n":"Reach"},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Sight FOV"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Base VATS To-Hit Chance"},{"t":3,"p":1,"n":"Attack Animation"},{"t":3,"p":1,"n":"# Projectiles"},{"t":3,"p":1,"n":"Embedded Weapon AV (unused)"},{"t":5,"p":1,"n":"Range Min"},{"t":5,"p":1,"n":"Range Max"},{"t":3,"p":1,"n":"On Hit"},{"t":3,"p":1,"n":"Flags2"},{"t":5,"p":1,"n":"Animation Attack Mult"},{"t":5,"p":1,"n":"Rumble - Left Motor Strength"},{"t":5,"p":1,"n":"Rumble - Right Motor Strength"},{"t":5,"p":1,"n":"Rumble - Duration"},{"t":3,"p":1,"n":"Skill"},{"t":3,"p":1,"n":"Resist"},{"t":5,"p":1,"n":"Stagger"}]},{"t":6,"s":1,"p":1,"n":"CRDT - Critical Data","c":[{"t":3,"p":1,"n":"Damage"},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"% Mult"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Effect"}]},{"t":3,"p":1,"n":"VNAM - Detection Sound Level"},{"t":3,"p":1,"n":"CNAM - Template"}]},{"t":1,"p":1,"n":"WOOP - Word of Power","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"TNAM - Translation"}]},{"t":1,"p":1,"n":"WRLD - Worldspace","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":8,"n":"Unused RNAM","c":[{"t":6,"n":"RNAM - Grid","c":[{"t":3,"n":"Y"},{"t":3,"n":"X"},{"t":7,"n":"References","c":[{"t":6,"n":"Reference","c":[{"t":3,"n":"Ref"},{"t":3,"n":"Y"},{"t":3,"n":"X"}]}]}]}]},{"t":11,"n":"MHDT - Max Height Data"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"WCTR - Fixed Dimensions Center Cell","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"}]},{"t":3,"p":1,"n":"LTMP - Interior Lighting"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":3,"p":1,"n":"XLCN - Location"},{"t":6,"s":1,"p":1,"n":"Parent","c":[{"t":3,"p":1,"n":"WNAM - Worldspace"},{"t":6,"p":1,"n":"PNAM - ","c":[{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"}]}]},{"t":3,"p":1,"n":"CNAM - Climate"},{"t":3,"p":1,"n":"NAM2 - Water"},{"t":3,"p":1,"n":"NAM3 - LOD Water Type"},{"t":5,"p":1,"n":"NAM4 - LOD Water Height"},{"t":6,"s":1,"p":1,"n":"DNAM - Land Data","c":[{"t":5,"p":1,"n":"Default Land Height"},{"t":5,"p":1,"n":"Default Water Height"}]},{"t":2,"p":1,"n":"ICON - Map Image"},{"t":6,"s":1,"p":1,"n":"Cloud Model","c":[{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]}]},{"t":6,"s":1,"p":1,"n":"MNAM - Map Data","c":[{"t":6,"p":1,"n":"Usable Dimensions","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"}]},{"t":6,"p":1,"n":"Cell Coordinates","c":[{"t":6,"p":1,"n":"NW Cell","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"}]},{"t":6,"p":1,"n":"SE Cell","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"}]}]},{"t":6,"p":1,"n":"Camera Data","c":[{"t":5,"p":1,"n":"Min Height"},{"t":5,"p":1,"n":"Max Height"},{"t":5,"p":1,"n":"Initial Pitch"}]}]},{"t":6,"s":1,"p":1,"n":"ONAM - World Map Offset Data","c":[{"t":5,"p":1,"n":"World Map Scale"},{"t":5,"p":1,"n":"Cell X Offset"},{"t":5,"p":1,"n":"Cell Y Offset"},{"t":5,"p":1,"n":"Cell Z Offset"}]},{"t":5,"p":1,"n":"NAMA - Distant LOD Multiplier"},{"t":3,"p":1,"n":"DATA - Flags"},{"t":6,"s":1,"p":1,"n":"Object Bounds","c":[{"t":6,"p":1,"n":"NAM0 - Min","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"}]},{"t":6,"p":1,"n":"NAM9 - Max","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"}]}]},{"t":3,"p":1,"n":"ZNAM - Music"},{"t":2,"p":1,"n":"NNAM - Canopy Shadow (unused)"},{"t":2,"p":1,"n":"XNAM - Water Noise Texture"},{"t":2,"p":1,"n":"TNAM - HD LOD Diffuse Texture"},{"t":2,"p":1,"n":"UNAM - HD LOD Normal Texture"},{"t":2,"p":1,"n":"XWEM - Water Environment Map (unused)"},{"t":11,"n":"OFST - Offset Data"}]},{"t":1,"p":1,"n":"WTHR - Weather","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"00TX - Cloud Texture Layer #0"},{"t":2,"p":1,"n":"10TX - Cloud Texture Layer #1"},{"t":2,"p":1,"n":"20TX - Cloud Texture Layer #2"},{"t":2,"p":1,"n":"30TX - Cloud Texture Layer #3"},{"t":2,"p":1,"n":"40TX - Cloud Texture Layer #4"},{"t":2,"p":1,"n":"50TX - Cloud Texture Layer #5"},{"t":2,"p":1,"n":"60TX - Cloud Texture Layer #6"},{"t":2,"p":1,"n":"70TX - Cloud Texture Layer #7"},{"t":2,"p":1,"n":"80TX - Cloud Texture Layer #8"},{"t":2,"p":1,"n":"90TX - Cloud Texture Layer #9"},{"t":2,"p":1,"n":":0TX - Cloud Texture Layer #10"},{"t":2,"p":1,"n":";0TX - Cloud Texture Layer #11"},{"t":2,"p":1,"n":"<0TX - Cloud Texture Layer #12"},{"t":2,"p":1,"n":"=0TX - Cloud Texture Layer #13"},{"t":2,"p":1,"n":">0TX - Cloud Texture Layer #14"},{"t":2,"p":1,"n":"?0TX - Cloud Texture Layer #15"},{"t":2,"p":1,"n":"@0TX - Cloud Texture Layer #16"},{"t":2,"p":1,"n":"A0TX - Cloud Texture Layer #17"},{"t":2,"p":1,"n":"B0TX - Cloud Texture Layer #18"},{"t":2,"p":1,"n":"C0TX - Cloud Texture Layer #19"},{"t":2,"p":1,"n":"D0TX - Cloud Texture Layer #20"},{"t":2,"p":1,"n":"E0TX - Cloud Texture Layer #21"},{"t":2,"p":1,"n":"F0TX - Cloud Texture Layer #22"},{"t":2,"p":1,"n":"G0TX - Cloud Texture Layer #23"},{"t":2,"p":1,"n":"H0TX - Cloud Texture Layer #24"},{"t":2,"p":1,"n":"I0TX - Cloud Texture Layer #25"},{"t":2,"p":1,"n":"J0TX - Cloud Texture Layer #26"},{"t":2,"p":1,"n":"K0TX - Cloud Texture Layer #27"},{"t":2,"p":1,"n":"L0TX - Cloud Texture Layer #28"},{"t":11,"n":"DNAM - Unused"},{"t":11,"n":"CNAM - Unused"},{"t":11,"n":"ANAM - Unused"},{"t":11,"n":"BNAM - Unused"},{"t":11,"n":"LNAM - Unknown"},{"t":3,"p":1,"n":"MNAM - Precipitation Type"},{"t":3,"p":1,"n":"NNAM - Visual Effect"},{"t":11,"n":"ONAM - Unused"},{"t":6,"s":1,"p":1,"n":"Cloud Speed","c":[{"t":7,"p":1,"n":"RNAM - Y Speed","c":[{"t":3,"p":1,"n":"Layer"}]},{"t":7,"p":1,"n":"QNAM - X Speed","c":[{"t":3,"p":1,"n":"Layer"}]}]},{"t":7,"s":1,"p":1,"n":"PNAM - Cloud Colors","c":[{"t":6,"p":1,"n":"Layer","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]}]},{"t":7,"s":1,"p":1,"n":"JNAM - Cloud Alphas","c":[{"t":6,"p":1,"n":"Layer","c":[{"t":5,"p":1,"n":"Sunrise"},{"t":5,"p":1,"n":"Day"},{"t":5,"p":1,"n":"Sunset"},{"t":5,"p":1,"n":"Night"}]}]},{"t":6,"s":1,"p":1,"n":"NAM0 - Weather Colors","c":[{"t":6,"p":1,"n":"Sky-Upper","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Fog Near","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"n":"Unknown","c":[{"t":6,"n":"Sunrise","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"n":"Day","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"n":"Sunset","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"n":"Night","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Ambient","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Sunlight","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Sun","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Stars","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Sky-Lower","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Horizon","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Effect Lighting","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Cloud LOD Diffuse","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Cloud LOD Ambient","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Fog Far","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Sky Statics","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Water Multiplier","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Sun Glare","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Moon Glare","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]}]},{"t":6,"s":1,"p":1,"n":"FNAM - Fog Distance","c":[{"t":5,"p":1,"n":"Day - Near"},{"t":5,"p":1,"n":"Day - Far"},{"t":5,"p":1,"n":"Night - Near"},{"t":5,"p":1,"n":"Night - Far"},{"t":5,"p":1,"n":"Day - Power"},{"t":5,"p":1,"n":"Night - Power"},{"t":5,"p":1,"n":"Day - Max"},{"t":5,"p":1,"n":"Night - Max"}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Wind Speed"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Trans Delta"},{"t":3,"p":1,"n":"Sun Glare"},{"t":3,"p":1,"n":"Sun Damage"},{"t":3,"p":1,"n":"Precipitation - Begin Fade In"},{"t":3,"p":1,"n":"Precipitation - End Fade Out"},{"t":3,"p":1,"n":"Thunder\/Lightning - Begin Fade In"},{"t":3,"p":1,"n":"Thunder\/Lightning - End Fade Out"},{"t":3,"p":1,"n":"Thunder\/Lightning - Frequency"},{"t":3,"p":1,"n":"Flags"},{"t":6,"p":1,"n":"Lightning Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"}]},{"t":3,"p":1,"n":"Visual Effect - Begin"},{"t":3,"p":1,"n":"Visual Effect - End"},{"t":3,"p":1,"n":"Wind Direction"},{"t":3,"p":1,"n":"Wind Direction Range"}]},{"t":3,"p":1,"n":"NAM1 - Disabled Cloud Layers"},{"t":8,"s":1,"p":1,"n":"Sounds","d":1,"c":[{"t":6,"p":1,"n":"SNAM - Sound","c":[{"t":3,"p":1,"n":"Sound"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Sky Statics","d":1,"c":[{"t":3,"p":1,"n":"TNAM - Static"}]},{"t":6,"s":1,"p":1,"n":"IMSP - Image Spaces","c":[{"t":3,"p":1,"n":"Sunrise"},{"t":3,"p":1,"n":"Day"},{"t":3,"p":1,"n":"Sunset"},{"t":3,"p":1,"n":"Night"}]},{"t":6,"s":1,"p":1,"n":"HNAM - Volumetric Lighting","c":[{"t":3,"p":1,"n":"Sunrise"},{"t":3,"p":1,"n":"Day"},{"t":3,"p":1,"n":"Sunset"},{"t":3,"p":1,"n":"Night"}]},{"t":6,"s":1,"p":1,"n":"Directional Ambient Lighting Colors","c":[{"t":6,"p":1,"n":"DALC - Sunrise","c":[{"t":6,"p":1,"n":"Directional","c":[{"t":6,"p":1,"n":"X+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"X-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Specular","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Scale"}]},{"t":6,"p":1,"n":"DALC - Day","c":[{"t":6,"p":1,"n":"Directional","c":[{"t":6,"p":1,"n":"X+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"X-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Specular","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Scale"}]},{"t":6,"p":1,"n":"DALC - Sunset","c":[{"t":6,"p":1,"n":"Directional","c":[{"t":6,"p":1,"n":"X+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"X-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Specular","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Scale"}]},{"t":6,"p":1,"n":"DALC - Night","c":[{"t":6,"p":1,"n":"Directional","c":[{"t":6,"p":1,"n":"X+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"X-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Specular","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Scale"}]}]},{"t":11,"n":"NAM2 - Unused"},{"t":11,"n":"NAM3 - Unused"},{"t":6,"s":1,"p":1,"n":"Aurora","c":[{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]}]},{"t":3,"p":1,"n":"GNAM - Sun Glare Lens Flare"}]},{"t":1,"p":1,"n":"ACHR - Placed NPC","f":1,"d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Base"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":11,"n":"XRGD - Ragdoll Data"},{"t":11,"n":"XRGB - Ragdoll Biped Data"},{"t":6,"s":1,"p":1,"n":"Patrol Data","c":[{"t":5,"p":1,"n":"XPRD - Idle Time"},{"p":1,"n":"XPPA - Patrol Script Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":6,"n":"Unused","c":[{"t":11,"n":"SCHR - Unknown"},{"t":11,"n":"SCDA - Unknown"},{"t":11,"n":"SCTX - Unknown"},{"t":11,"n":"QNAM - Unknown"},{"t":11,"n":"SCRO - Unknown"}]},{"t":8,"p":1,"n":"Topic","c":[{"t":6,"p":1,"n":"PDTO - Topic Data","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Topic"},{"t":2,"p":1,"n":"Subtype"}]}]},{"t":3,"p":1,"n":"TNAM - Topic"}]},{"t":3,"p":1,"n":"XLCM - Level Modifier"},{"t":3,"p":1,"n":"XMRC - Merchant Container"},{"t":3,"p":1,"n":"XCNT - Count"},{"t":5,"p":1,"n":"XRDS - Radius"},{"t":5,"p":1,"n":"XHLP - Health"},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":6,"s":1,"p":1,"n":"XCLP - Linked Reference Color","c":[{"t":6,"p":1,"n":"Link Start Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Link End Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":3,"p":1,"n":"XLCN - Persistent Location"},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"t":3,"p":1,"n":"XHOR - Horse"},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIBS - Ignored By Sandbox"},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]}]},"name":"Smash.ForceAll","hash":"ADEDBA36","color":8388736} ================================================ FILE: frontend/settings/Skyrim/Smash.OverrideAll.json ================================================ {"records":"AACT,ACTI,ADDN,ALCH,AMMO,ANIO,APPA,ARMA,ARMO,ARTO,ASPC,ASTP,AVIF,BOOK,BPTD,CAMS,CELL,CLAS,CLDC,CLFM,CLMT,COBJ,COLL,CONT,CPTH,CSTY,DEBR,DIAL,DLBR,DLVW,DOOR,DUAL,ECZN,EFSH,ENCH,EQUP,EXPL,EYES,FACT,FLOR,FLST,FSTP,FSTS,FURN,GLOB,GMST,GRAS,HAIR,HAZD,HDPT,IDLM,IMAD,IMGS,INFO,INGR,IPCT,IPDS,KEYM,KYWD,LAND,LCRT,LENS,LGTM,LIGH,LSCR,LTEX,LVLI,LVLN,LVSP,MATO,MATT,MESG,MGEF,MISC,MOVT,MSTT,MUSC,MUST,NPC_,OTFT,PACK,PARW,PBAR,PBEA,PCON,PERK,PFLA,PGRE,PHZD,PMIS,PROJ,PWAT,QUST,RACE,REFR,REGN,RELA,REVB,RFCT,RGDL,SCEN,SCOL,SCPT,SCRL,SHOU,SLGM,SMBN,SMEN,SMQN,SNCT,SNDR,SOPM,SOUN,SPEL,SPGD,STAT,TACT,TREE,TXST,VOLI,VTYP,WATR,WEAP,WOOP,WRLD,WTHR,ACHR","description":"Smashes all the things and restores deletions in leveled lists.\r\n\r\nLast updated 05\/02\/2018.","tree":{"records":[{"t":1,"p":1,"n":"AACT - Action","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"CNAM - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":1,"p":1,"n":"ACTI - Activator","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"PNAM - Marker Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":3,"n":"Unused"}]},{"t":3,"p":1,"n":"SNAM - Sound - Looping"},{"t":3,"p":1,"n":"VNAM - Sound - Activation"},{"t":3,"p":1,"n":"WNAM - Water Type"},{"t":2,"p":1,"n":"RNAM - Activate Text Override"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":3,"p":1,"n":"KNAM - Interaction Keyword"}]},{"t":1,"p":1,"n":"ADDN - Addon Node","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":3,"p":1,"n":"DATA - Node Index"},{"t":3,"p":1,"n":"SNAM - Sound"},{"t":6,"s":1,"p":1,"n":"DNAM - Data","c":[{"t":3,"p":1,"n":"Master Particle System Cap"},{"t":3,"p":1,"n":"Flags"}]}]},{"t":1,"p":1,"n":"ALCH - Ingestible","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":3,"p":1,"n":"ETYP - Equipment Type"},{"t":5,"p":1,"n":"DATA - Weight"},{"t":6,"s":1,"p":1,"n":"ENIT - Effect Data","c":[{"t":3,"p":1,"n":"Value"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Addiction"},{"t":5,"p":1,"n":"Addiction Chance"},{"t":3,"p":1,"n":"Sound - Consume"}]},{"t":8,"s":1,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":3,"p":1,"n":"EFID - Base Effect"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":5,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"}]},{"t":8,"s":1,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]}]},{"t":1,"p":1,"n":"AMMO - Ammunition","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":2,"p":1,"n":"DESC - Description"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Projectile"},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Damage"},{"t":3,"p":1,"n":"Value"}]},{"t":2,"p":1,"n":"ONAM - Short Name"}]},{"t":1,"p":1,"n":"ANIO - Animated Object","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":2,"p":1,"n":"BNAM - Unload Event"}]},{"t":1,"p":1,"n":"APPA - Alchemical Apparatus","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":3,"p":1,"n":"QUAL - Quality"},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]}]},{"t":1,"p":1,"n":"ARMA - Armor Addon","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"BOD2 - Biped Body Template","c":[{"t":3,"p":1,"n":"First Person Flags"},{"t":3,"p":1,"n":"General Flags"},{"n":"Unused"},{"t":3,"p":1,"n":"Armor Type"}],"lt":"BODT - Body Template","lf":"BODT - Body Template"},{"t":6,"s":1,"p":1,"n":"BODT - Body Template","c":[{"t":3,"p":1,"n":"First Person Flags"},{"t":3,"p":1,"n":"General Flags"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Armor Type"}],"lt":"BOD2 - Biped Body Template","lf":"BOD2 - Biped Body Template"},{"t":3,"p":1,"n":"RNAM - Race"},{"t":6,"s":1,"p":1,"n":"DNAM - Data","c":[{"t":3,"p":1,"n":"Male Priority"},{"t":3,"p":1,"n":"Female Priority"},{"t":3,"p":1,"n":"Weight slider - Male"},{"t":3,"p":1,"n":"Weight slider - Female"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Detection Sound Value"},{"t":5,"p":1,"n":"Weapon Adjust"}]},{"t":6,"s":1,"p":1,"n":"Male world model","c":[{"t":2,"p":1,"n":"MOD2 - Model Filename"},{"t":11,"p":1,"n":"MO2T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO2S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Female world model","c":[{"t":2,"p":1,"n":"MOD3 - Model Filename"},{"t":11,"p":1,"n":"MO3T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO3S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Male 1st Person","c":[{"t":2,"p":1,"n":"MOD4 - Model Filename"},{"t":11,"p":1,"n":"MO4T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO4S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Female 1st Person","c":[{"t":2,"p":1,"n":"MOD5 - Model Filename"},{"t":11,"p":1,"n":"MO5T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO5S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":3,"p":1,"n":"NAM0 - Male Skin Texture"},{"t":3,"p":1,"n":"NAM1 - Female Skin texture"},{"t":3,"p":1,"n":"NAM2 - Male Skin Texture Swap List"},{"t":3,"p":1,"n":"NAM3 - Female Skin Texture Swap List"},{"t":8,"s":1,"p":1,"n":"Additional Races","d":1,"c":[{"t":3,"p":1,"n":"MODL - Race"}]},{"t":3,"p":1,"n":"SNDD - Footstep Sound"},{"t":3,"p":1,"n":"ONAM - Art Object"}]},{"t":1,"p":1,"n":"ARMO - Armor","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"EITM - Object Effect"},{"t":3,"p":1,"n":"EAMT - Enchantment Amount"},{"t":6,"s":1,"p":1,"n":"Male world model","c":[{"t":2,"p":1,"n":"MOD2 - Model Filename"},{"t":11,"p":1,"n":"MO2T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO2S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"Female world model","c":[{"t":2,"p":1,"n":"MOD4 - Model Filename"},{"t":11,"p":1,"n":"MO4T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO4S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Icon 2 (female)","c":[{"t":2,"p":1,"n":"ICO2 - Large Icon filename"},{"t":2,"p":1,"n":"MIC2 - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"BOD2 - Biped Body Template","c":[{"t":3,"p":1,"n":"First Person Flags"},{"t":3,"p":1,"n":"General Flags"},{"n":"Unused"},{"t":3,"p":1,"n":"Armor Type"}],"lt":"BODT - Body Template","lf":"BODT - Body Template"},{"t":6,"s":1,"p":1,"n":"BODT - Body Template","c":[{"t":3,"p":1,"n":"First Person Flags"},{"t":3,"p":1,"n":"General Flags"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Armor Type"}],"lt":"BOD2 - Biped Body Template","lf":"BOD2 - Biped Body Template"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":2,"p":1,"n":"BMCT - Ragdoll Constraint Template"},{"t":3,"p":1,"n":"ETYP - Equipment Type"},{"t":3,"p":1,"n":"BIDS - Bash Impact Data Set"},{"t":3,"p":1,"n":"BAMT - Alternate Block Material"},{"t":3,"p":1,"n":"RNAM - Race"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":2,"p":1,"n":"DESC - Description"},{"t":8,"s":1,"p":1,"n":"Armature","d":1,"c":[{"t":3,"p":1,"n":"MODL - Model Filename"}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":3,"p":1,"n":"DNAM - Armor Rating"},{"t":3,"p":1,"n":"TNAM - Template Armor"}]},{"t":1,"p":1,"n":"ARTO - Art Object","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":3,"p":1,"n":"DNAM - Art Type"}]},{"t":1,"p":1,"n":"ASPC - Acoustic Space","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"SNAM - Ambient Sound"},{"t":3,"p":1,"n":"RDAT - Use Sound from Region (Interiors Only)"},{"t":3,"p":1,"n":"BNAM - Environment Type (reverb)"}]},{"t":1,"p":1,"n":"ASTP - Association Type","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"MPRT - Male Parent Title"},{"t":2,"p":1,"n":"FPRT - Female Parent Title"},{"t":2,"p":1,"n":"MCHT - Male Child Title"},{"t":2,"p":1,"n":"FCHT - Female Child Title"},{"t":3,"p":1,"n":"DATA - Flags"}]},{"t":1,"p":1,"n":"AVIF - Actor Value Information","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"DESC - Description"},{"t":2,"p":1,"n":"ANAM - Abbreviation"},{"t":11,"n":"CNAM - Unknown"},{"t":6,"s":1,"p":1,"n":"AVSK - Skill","c":[{"t":5,"p":1,"n":"Skill Use Mult"},{"t":5,"p":1,"n":"Skill Offset Mult"},{"t":5,"p":1,"n":"Skill Improve Mult"},{"t":5,"p":1,"n":"Skill Improve Offset"}]},{"t":8,"s":1,"p":1,"n":"Perk Tree","d":1,"c":[{"t":6,"p":1,"n":"Node","c":[{"t":3,"p":1,"n":"PNAM - Perk"},{"t":11,"n":"FNAM - Unknown"},{"t":3,"p":1,"n":"XNAM - Perk-Grid X"},{"t":3,"p":1,"n":"YNAM - Perk-Grid Y"},{"t":5,"p":1,"n":"HNAM - Horizontal Position"},{"t":5,"p":1,"n":"VNAM - Vertical Position"},{"t":3,"p":1,"n":"SNAM - Associated Skill"},{"t":8,"p":1,"n":"Connections","c":[{"t":3,"p":1,"n":"CNAM - Line to Index"}]},{"t":3,"p":1,"n":"INAM - Index"}]}]}]},{"t":1,"p":1,"n":"BOOK - Book","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":2,"p":1,"n":"DESC - Book Text"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Skill"},{"t":3,"p":1,"n":"Spell"},{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":3,"p":1,"n":"INAM - Inventory Art"},{"t":2,"p":1,"n":"CNAM - Description"}]},{"t":1,"p":1,"n":"BPTD - Body Part Data","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":10,"p":1,"n":"Body Parts","d":1,"c":[{"t":6,"p":1,"n":"Body Part","c":[{"t":2,"p":1,"n":"BPTN - Part Name"},{"t":2,"p":1,"n":"PNAM - Pose Matching"},{"t":2,"p":1,"n":"BPNN - Part Node"},{"t":2,"p":1,"n":"BPNT - VATS Target"},{"t":2,"p":1,"n":"BPNI - IK Data - Start Node"},{"t":6,"p":1,"n":"BPND - ","c":[{"t":5,"p":1,"n":"Damage Mult"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Part Type"},{"t":3,"p":1,"n":"Health Percent"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"To Hit Chance"},{"t":3,"p":1,"n":"Explodable - Explosion Chance %"},{"t":3,"p":1,"n":"Explodable - Debris Count"},{"t":3,"p":1,"n":"Explodable - Debris"},{"t":3,"p":1,"n":"Explodable - Explosion"},{"t":5,"p":1,"n":"Tracking Max Angle"},{"t":5,"p":1,"n":"Explodable - Debris Scale"},{"t":3,"p":1,"n":"Severable - Debris Count"},{"t":3,"p":1,"n":"Severable - Debris"},{"t":3,"p":1,"n":"Severable - Explosion"},{"t":5,"p":1,"n":"Severable - Debris Scale"},{"t":6,"p":1,"n":"Gore Effects Positioning","c":[{"t":6,"p":1,"n":"Translate","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]},{"t":3,"p":1,"n":"Severable - Impact DataSet"},{"t":3,"p":1,"n":"Explodable - Impact DataSet"},{"t":3,"p":1,"n":"Severable - Decal Count"},{"t":3,"p":1,"n":"Explodable - Decal Count"},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"Limb Replacement Scale"}]},{"t":2,"p":1,"n":"NAM1 - Limb Replacement Model"},{"t":2,"p":1,"n":"NAM4 - Gore Effects - Target Bone"},{"t":11,"p":1,"n":"NAM5 - Texture Files Hashes"}]}]}]},{"t":1,"p":1,"n":"CAMS - Camera Shot","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Action"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Flags"},{"t":6,"p":1,"n":"Time Multipliers","c":[{"t":5,"p":1,"n":"Player"},{"t":5,"p":1,"n":"Target"},{"t":5,"p":1,"n":"Global"}]},{"t":5,"p":1,"n":"Max Time"},{"t":5,"p":1,"n":"Min Time"},{"t":5,"p":1,"n":"Target % Between Actors"},{"t":5,"p":1,"n":"Near Target Distance"}]},{"t":3,"p":1,"n":"MNAM - Image Space Modifier"}]},{"t":1,"p":1,"n":"CELL - Cell","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"DATA - Flags"},{"t":6,"s":1,"p":1,"n":"XCLC - Grid","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"},{"t":3,"p":1,"n":"Force Hide Land"}]},{"t":6,"s":1,"p":1,"n":"XCLL - Lighting","c":[{"t":6,"p":1,"n":"Ambient Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Directional Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Fog Color Near","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Fog Near"},{"t":5,"p":1,"n":"Fog Far"},{"t":3,"p":1,"n":"Directional Rotation XY"},{"t":3,"p":1,"n":"Directional Rotation Z"},{"t":5,"p":1,"n":"Directional Fade"},{"t":5,"p":1,"n":"Fog Clip Distance"},{"t":5,"p":1,"n":"Fog Power"},{"t":6,"p":1,"n":"Ambient Colors","c":[{"t":6,"p":1,"n":"Directional","c":[{"t":6,"p":1,"n":"X+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"X-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Specular","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Scale"}]},{"t":6,"p":1,"n":"Fog Color Far","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Fog Max"},{"t":5,"p":1,"n":"Light Fade Begin"},{"t":5,"p":1,"n":"Light Fade End"},{"t":3,"p":1,"n":"Inherits"}]},{"t":11,"n":"TVDT - Occlusion Data"},{"t":11,"n":"MHDT - Max Height Data"},{"t":3,"p":1,"n":"LTMP - Lighting Template"},{"t":11,"n":"LNAM - Unknown"},{"t":5,"p":1,"n":"XCLW - Water Height"},{"t":2,"p":1,"n":"XNAM - Water Noise Texture"},{"t":7,"p":1,"n":"XCLR - Regions","c":[{"t":3,"p":1,"n":"Region"}]},{"t":3,"p":1,"n":"XLCN - Location"},{"t":11,"n":"XWCN - Unknown"},{"t":11,"n":"XWCS - Unknown"},{"t":6,"s":1,"p":1,"n":"XWCU - Water Velocity","c":[{"t":5,"p":1,"n":"X Offset"},{"t":5,"p":1,"n":"Y Offset"},{"t":5,"p":1,"n":"Z Offset"},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"X Angle"},{"t":5,"p":1,"n":"Y Angle"},{"t":5,"p":1,"n":"Z Angle"}]},{"t":3,"p":1,"n":"XCWT - Water"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":3,"p":1,"n":"XILL - Lock List"},{"t":2,"p":1,"n":"XWEM - Water Environment Map"},{"t":3,"p":1,"n":"XCCM - Sky\/Weather from Region"},{"t":3,"p":1,"n":"XCAS - Acoustic Space"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":3,"p":1,"n":"XCMO - Music Type"},{"t":3,"p":1,"n":"XCIM - Image Space"}]},{"t":1,"p":1,"n":"CLAS - Class","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Teaches"},{"t":3,"p":1,"n":"Maximum training level"},{"t":7,"p":1,"n":"Skill Weights","c":[{"t":3,"p":1,"n":"Weight"}]},{"t":5,"p":1,"n":"Bleedout Default"},{"t":3,"p":1,"n":"Voice Points"},{"t":7,"p":1,"n":"Attribute Weights","c":[{"t":3,"p":1,"n":"Weight"}]}]}]},{"t":1,"p":1,"n":"CLDC","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"}]},{"t":1,"p":1,"n":"CLFM - Color","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"CNAM - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":3,"p":1,"n":"FNAM - Playable"}]},{"t":1,"p":1,"n":"CLMT - Climate","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":7,"p":1,"n":"WLST - Weather Types","c":[{"t":6,"p":1,"n":"Weather Type","c":[{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Chance"},{"t":3,"p":1,"n":"Global"}]}]},{"t":2,"p":1,"n":"FNAM - Sun Texture"},{"t":2,"p":1,"n":"GNAM - Sun Glare Texture"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"TNAM - Timing","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Begin"},{"t":3,"p":1,"n":"End"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Begin"},{"t":3,"p":1,"n":"End"}]},{"t":3,"p":1,"n":"Volatility"},{"t":3,"p":1,"n":"Moons \/ Phase Length"}]}]},{"t":1,"p":1,"n":"COBJ - Constructible Object","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"n":"COCT - Count"},{"t":10,"p":1,"n":"Items","d":1,"c":[{"t":6,"p":1,"n":"Item","c":[{"t":6,"p":1,"n":"CNTO - Item","c":[{"t":3,"p":1,"n":"Item"},{"t":3,"p":1,"n":"Count"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":3,"p":1,"n":"CNAM - Created Object"},{"t":3,"p":1,"n":"BNAM - Workbench Keyword"},{"t":3,"p":1,"n":"NAM1 - Created Object Count"}]},{"t":1,"p":1,"n":"COLL - Collision Layer","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"DESC - Description"},{"t":3,"p":1,"n":"BNAM - Index"},{"t":6,"s":1,"p":1,"n":"FNAM - Debug Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":3,"n":"Unused"}]},{"t":3,"p":1,"n":"GNAM - Flags"},{"t":2,"p":1,"n":"MNAM - Name"},{"t":3,"n":"INTV - Interactables Count"},{"t":7,"p":1,"n":"CNAM - Collides With","c":[{"t":3,"p":1,"n":"Forms"}]}]},{"t":1,"p":1,"n":"CONT - Container","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":3,"n":"COCT - Count"},{"t":10,"p":1,"n":"Items","d":1,"c":[{"t":6,"p":1,"n":"Item","c":[{"t":6,"p":1,"n":"CNTO - Item","c":[{"t":3,"p":1,"n":"Item"},{"t":3,"p":1,"n":"Count"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Weight"}]},{"t":3,"p":1,"n":"SNAM - Sound - Open"},{"t":3,"p":1,"n":"QNAM - Sound - Close"}]},{"t":1,"p":1,"n":"CPTH - Camera Path","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":7,"p":1,"n":"ANAM - Related Camera Paths","c":[{"t":3,"p":1,"n":"Related Camera Path"}]},{"t":3,"p":1,"n":"DATA - Camera Zoom"},{"t":8,"s":1,"p":1,"n":"Camera Shots","d":1,"c":[{"t":3,"p":1,"n":"SNAM - Camera Shot"}]}]},{"t":1,"p":1,"n":"CSTY - Combat Style","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"CSGD - General","c":[{"t":5,"p":1,"n":"Offensive Mult"},{"t":5,"p":1,"n":"Defensive Mult"},{"t":5,"p":1,"n":"Group Offensive Mult"},{"t":5,"p":1,"n":"Equipment Score Mult - Melee"},{"t":5,"p":1,"n":"Equipment Score Mult - Magic"},{"t":5,"p":1,"n":"Equipment Score Mult - Ranged"},{"t":5,"p":1,"n":"Equipment Score Mult - Shout"},{"t":5,"p":1,"n":"Equipment Score Mult - Unarmed"},{"t":5,"p":1,"n":"Equipment Score Mult - Staff"},{"t":5,"p":1,"n":"Avoid Threat Chance"}]},{"t":11,"n":"CSMD - Unknown"},{"t":6,"s":1,"p":1,"n":"CSME - Melee","c":[{"t":5,"p":1,"n":"Attack Staggered Mult"},{"t":5,"p":1,"n":"Power Attack Staggered Mult"},{"t":5,"p":1,"n":"Power Attack Blocking Mult"},{"t":5,"p":1,"n":"Bash Mult"},{"t":5,"p":1,"n":"Bash Recoil Mult"},{"t":5,"p":1,"n":"Bash Attack Mult"},{"t":5,"p":1,"n":"Bash Power Attack Mult"},{"t":5,"p":1,"n":"Special Attack Mult"}]},{"t":6,"s":1,"p":1,"n":"CSCR - Close Range","c":[{"t":5,"p":1,"n":"Circle Mult"},{"t":5,"p":1,"n":"Fallback Mult"},{"t":5,"p":1,"n":"Flank Distance"},{"t":5,"p":1,"n":"Stalk Time"}]},{"t":6,"s":1,"p":1,"n":"CSLR - Long Range","c":[{"t":5,"p":1,"n":"Strafe Mult"}]},{"t":6,"s":1,"p":1,"n":"CSFL - Flight","c":[{"t":5,"p":1,"n":"Hover Chance"},{"t":5,"p":1,"n":"Dive Bomb Chance"},{"t":5,"p":1,"n":"Ground Attack Chance"},{"t":5,"p":1,"n":"Hover Time"},{"t":5,"p":1,"n":"Ground Attack Time"},{"t":5,"p":1,"n":"Perch Attack Chance"},{"t":5,"p":1,"n":"Perch Attack Time"},{"t":5,"p":1,"n":"Flying Attack Chance"}]},{"t":3,"p":1,"n":"DATA - Flags"}]},{"t":1,"p":1,"n":"DEBR - Debris","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":8,"s":1,"p":1,"n":"Models","d":1,"c":[{"t":6,"p":1,"n":"Model","c":[{"t":6,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Percentage"},{"t":2,"p":1,"n":"Model Filename"},{"t":3,"p":1,"n":"Flags"}]},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"}]}]}]},{"t":1,"p":1,"n":"DIAL - Dialog Topic","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":5,"p":1,"n":"PNAM - Priority"},{"t":3,"p":1,"n":"BNAM - Branch"},{"t":3,"p":1,"n":"QNAM - Quest"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Topic Flags"},{"t":3,"p":1,"n":"Category"},{"t":3,"p":1,"n":"Subtype"}]},{"t":2,"p":1,"n":"SNAM - Subtype Name"},{"t":3,"p":1,"n":"TIFC - Info Count"}]},{"t":1,"p":1,"n":"DLBR - Dialog Branch","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"QNAM - Quest"},{"t":3,"n":"TNAM - Unknown"},{"t":3,"p":1,"n":"DNAM - Flags"},{"t":3,"p":1,"n":"SNAM - Starting Topic"}]},{"t":1,"p":1,"n":"DLVW - Dialog View","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"QNAM - Quest"},{"t":8,"s":1,"p":1,"n":"Branches","d":1,"c":[{"t":3,"p":1,"n":"BNAM - Branch"}]},{"t":8,"n":"Unknown TNAM","c":[{"t":6,"n":"Unknown","c":[{"t":11,"n":"TNAM - Unknown"}]}]},{"t":11,"n":"ENAM - Unknown"},{"t":11,"n":"DNAM - Unknown"}]},{"t":1,"n":"DOBJ - Default Object Manager","c":[{"t":2,"n":"EDID - Editor ID"},{"t":7,"n":"DNAM - Objects","c":[{"t":6,"n":"Object","c":[{"t":3,"n":"Use"},{"t":3,"n":"Object ID"}]}]}]},{"t":1,"p":1,"n":"DOOR - Door","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"SNAM - Sound - Open"},{"t":3,"p":1,"n":"ANAM - Sound - Close"},{"t":3,"p":1,"n":"BNAM - Sound - Loop"},{"t":3,"p":1,"n":"FNAM - Flags"}]},{"t":1,"p":1,"n":"DUAL - Dual Cast Data","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Projectile"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Effect Shader"},{"t":3,"p":1,"n":"Hit Effect Art"},{"t":3,"p":1,"n":"Impact Data Set"},{"t":3,"p":1,"n":"Inherit Scale"}]}]},{"t":1,"p":1,"n":"ECZN - Encounter Zone","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Rank"},{"t":3,"p":1,"n":"Min Level"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Max Level"}]}]},{"t":1,"p":1,"n":"EFSH - Effect Shader","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"ICON - Fill Texture"},{"t":2,"p":1,"n":"ICO2 - Particle Shader Texture"},{"t":2,"p":1,"n":"NAM7 - Holes Texture"},{"t":2,"p":1,"n":"NAM8 - Membrane Palette Texture"},{"t":2,"p":1,"n":"NAM9 - Particle Palette Texture"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Membrane Shader - Source Blend Mode"},{"t":3,"p":1,"n":"Membrane Shader - Blend Operation"},{"t":3,"p":1,"n":"Membrane Shader - Z Test Function"},{"t":6,"p":1,"n":"Fill\/Texture Effect - Color Key 1","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Fade In Time"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Full Alpha Time"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Fade Out Time"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Presistent Alpha Ratio"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Pulse Amplitude"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Alpha Pulse Frequency"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Animation Speed (U)"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Animation Speed (V)"},{"t":5,"p":1,"n":"Edge Effect - Fall Off"},{"t":6,"p":1,"n":"Edge Effect - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Edge Effect - Alpha Fade In Time"},{"t":5,"p":1,"n":"Edge Effect - Full Alpha Time"},{"t":5,"p":1,"n":"Edge Effect - Alpha Fade Out Time"},{"t":5,"p":1,"n":"Edge Effect - Persistent Alpha Ratio"},{"t":5,"p":1,"n":"Edge Effect - Alpha Pulse Amplitude"},{"t":5,"p":1,"n":"Edge Effect - Alpha Pulse Frequency"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Full Alpha Ratio"},{"t":5,"p":1,"n":"Edge Effect - Full Alpha Ratio"},{"t":3,"p":1,"n":"Membrane Shader - Dest Blend Mode"},{"t":3,"p":1,"n":"Particle Shader - Source Blend Mode"},{"t":3,"p":1,"n":"Particle Shader - Blend Operation"},{"t":3,"p":1,"n":"Particle Shader - Z Test Function"},{"t":3,"p":1,"n":"Particle Shader - Dest Blend Mode"},{"t":5,"p":1,"n":"Particle Shader - Particle Birth Ramp Up Time"},{"t":5,"p":1,"n":"Particle Shader - Full Particle Birth Time"},{"t":5,"p":1,"n":"Particle Shader - Particle Birth Ramp Down Time"},{"t":5,"p":1,"n":"Particle Shader - Full Particle Birth Ratio"},{"t":5,"p":1,"n":"Particle Shader - Persistant Particle Count"},{"t":5,"p":1,"n":"Particle Shader - Particle Lifetime"},{"t":5,"p":1,"n":"Particle Shader - Particle Lifetime +\/-"},{"t":5,"p":1,"n":"Particle Shader - Initial Speed Along Normal"},{"t":5,"p":1,"n":"Particle Shader - Acceleration Along Normal"},{"t":5,"p":1,"n":"Particle Shader - Initial Velocity #1"},{"t":5,"p":1,"n":"Particle Shader - Initial Velocity #2"},{"t":5,"p":1,"n":"Particle Shader - Initial Velocity #3"},{"t":5,"p":1,"n":"Particle Shader - Acceleration #1"},{"t":5,"p":1,"n":"Particle Shader - Acceleration #2"},{"t":5,"p":1,"n":"Particle Shader - Acceleration #3"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 1"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 2"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 1 Time"},{"t":5,"p":1,"n":"Particle Shader - Scale Key 2 Time"},{"t":6,"p":1,"n":"Color Key 1 - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Color Key 2 - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Color Key 3 - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Color Key 1 - Color Alpha"},{"t":5,"p":1,"n":"Color Key 2 - Color Alpha"},{"t":5,"p":1,"n":"Color Key 3 - Color Alpha"},{"t":5,"p":1,"n":"Color Key 1 - Color Key Time"},{"t":5,"p":1,"n":"Color Key 2 - Color Key Time"},{"t":5,"p":1,"n":"Color Key 3 - Color Key Time"},{"t":5,"p":1,"n":"Particle Shader - Initial Speed Along Normal +\/-"},{"t":5,"p":1,"n":"Particle Shader - Initial Rotation (deg)"},{"t":5,"p":1,"n":"Particle Shader - Initial Rotation (deg) +\/-"},{"t":5,"p":1,"n":"Particle Shader - Rotation Speed (deg\/sec)"},{"t":5,"p":1,"n":"Particle Shader - Rotation Speed (deg\/sec) +\/-"},{"t":3,"p":1,"n":"Addon Models"},{"t":5,"p":1,"n":"Holes - Start Time"},{"t":5,"p":1,"n":"Holes - End Time"},{"t":5,"p":1,"n":"Holes - Start Val"},{"t":5,"p":1,"n":"Holes - End Val"},{"t":5,"p":1,"n":"Edge Width (alpha units)"},{"t":6,"p":1,"n":"Edge Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Explosion Wind Speed"},{"t":3,"p":1,"n":"Texture Count U"},{"t":3,"p":1,"n":"Texture Count V"},{"t":5,"p":1,"n":"Addon Models - Fade In Time"},{"t":5,"p":1,"n":"Addon Models - Fade Out Time"},{"t":5,"p":1,"n":"Addon Models - Scale Start"},{"t":5,"p":1,"n":"Addon Models - Scale End"},{"t":5,"p":1,"n":"Addon Models - Scale In Time"},{"t":5,"p":1,"n":"Addon Models - Scale Out Time"},{"t":3,"p":1,"n":"Ambient Sound"},{"t":6,"p":1,"n":"Fill\/Texture Effect - Color Key 2","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Fill\/Texture Effect - Color Key 3","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Fill\/Texture Effect - Color Key Scale\/Time","c":[{"t":5,"p":1,"n":"Color Key 1 - Scale"},{"t":5,"p":1,"n":"Color Key 2 - Scale"},{"t":5,"p":1,"n":"Color Key 3 - Scale"},{"t":5,"p":1,"n":"Color Key 1 - Time"},{"t":5,"p":1,"n":"Color Key 2 - Time"},{"t":5,"p":1,"n":"Color Key 3 - Time"}]},{"t":5,"p":1,"n":"Color Scale"},{"t":5,"p":1,"n":"Birth Position Offset"},{"t":5,"p":1,"n":"Birth Position Offset Range +\/-"},{"t":6,"p":1,"n":"Particle Shader Animated","c":[{"t":3,"p":1,"n":"Start Frame"},{"t":3,"p":1,"n":"Start Frame Variation"},{"t":3,"p":1,"n":"End Frame"},{"t":3,"p":1,"n":"Loop Start Frame"},{"t":3,"p":1,"n":"Loop Start Variation"},{"t":3,"p":1,"n":"Frame Count"},{"t":3,"p":1,"n":"Frame Count Variation"}]},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Scale (U)"},{"t":5,"p":1,"n":"Fill\/Texture Effect - Texture Scale (V)"},{"t":3,"p":1,"n":"Scene Graph Emit Depth Limit (unused)"}]}]},{"t":1,"p":1,"n":"ENCH - Object Effect","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"ENIT - Effect Data","c":[{"t":3,"p":1,"n":"Enchantment Cost"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Cast Type"},{"t":3,"p":1,"n":"Enchantment Amount"},{"t":3,"p":1,"n":"Target Type"},{"t":3,"p":1,"n":"Enchant Type"},{"t":5,"p":1,"n":"Charge Time"},{"t":3,"p":1,"n":"Base Enchantment"},{"t":3,"p":1,"n":"Worn Restrictions"}]},{"t":8,"s":1,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":3,"p":1,"n":"EFID - Base Effect"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":5,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"}]},{"t":8,"s":1,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]}]},{"t":1,"p":1,"n":"EQUP - Equip Type","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":7,"p":1,"n":"PNAM - Slot Parents","c":[{"t":3,"p":1,"n":"Can Be Equipped"}]},{"t":3,"p":1,"n":"DATA - Use All Parents"}]},{"t":1,"p":1,"n":"EXPL - Explosion","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":3,"p":1,"n":"EITM - Object Effect"},{"t":3,"p":1,"n":"MNAM - Image Space Modifier"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Light"},{"t":3,"p":1,"n":"Sound 1"},{"t":3,"p":1,"n":"Sound 2"},{"t":3,"p":1,"n":"Impact Data Set"},{"t":3,"p":1,"n":"Placed Object"},{"t":3,"p":1,"n":"Spawn Projectile"},{"t":5,"p":1,"n":"Force"},{"t":5,"p":1,"n":"Damage"},{"t":5,"p":1,"n":"Radius"},{"t":5,"p":1,"n":"IS Radius"},{"t":5,"p":1,"n":"Vertical Offset Mult"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Sound Level"}]}]},{"t":1,"p":1,"n":"EYES - Eyes","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"ICON - Texture"},{"t":3,"p":1,"n":"DATA - Flags"}]},{"t":1,"p":1,"n":"FACT - Faction","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":8,"s":1,"p":1,"n":"Relations","d":1,"c":[{"t":6,"p":1,"n":"XNAM - Relation","c":[{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Modifier"},{"t":3,"p":1,"n":"Group Combat Reaction"}]}]},{"t":6,"s":1,"p":1,"n":"DATA - Flags","c":[{"t":3,"p":1,"n":"Flags"}]},{"t":3,"p":1,"n":"JAIL - Exterior Jail Marker"},{"t":3,"p":1,"n":"WAIT - Follower Wait Marker"},{"t":3,"p":1,"n":"STOL - Stolen Goods Container"},{"t":3,"p":1,"n":"PLCN - Player Inventory Container"},{"t":3,"p":1,"n":"CRGR - Shared Crime Faction List"},{"t":3,"p":1,"n":"JOUT - Jail Outfit"},{"t":6,"s":1,"p":1,"n":"CRVA - Crime Values","c":[{"t":3,"p":1,"n":"Arrest"},{"t":3,"p":1,"n":"Attack On Sight"},{"t":3,"p":1,"n":"Murder"},{"t":3,"p":1,"n":"Assault"},{"t":3,"p":1,"n":"Trespass"},{"t":3,"p":1,"n":"Pickpocket"},{"t":3,"n":"Unknown"},{"t":5,"p":1,"n":"Steal Multiplier"},{"t":3,"p":1,"n":"Escape"},{"t":3,"p":1,"n":"Werewolf"}]},{"t":10,"p":1,"n":"Ranks","d":1,"c":[{"t":6,"p":1,"n":"Rank","c":[{"t":3,"p":1,"n":"RNAM - Rank#"},{"t":2,"p":1,"n":"MNAM - Male Title"},{"t":2,"p":1,"n":"FNAM - Female Title"},{"t":2,"n":"INAM - Insignia Unused"}]}]},{"t":3,"p":1,"n":"VEND - Vendor Buy\/Sell List"},{"t":3,"p":1,"n":"VENC - Merchant Container"},{"t":6,"s":1,"p":1,"n":"VENV - Vendor Values","c":[{"t":3,"p":1,"n":"Start Hour"},{"t":3,"p":1,"n":"End Hour"},{"t":3,"p":1,"n":"Radius"},{"t":11,"n":"Unknown 1"},{"t":3,"p":1,"n":"Only Buys Stolen Items"},{"t":3,"p":1,"n":"Not\/Sell Buy"},{"t":11,"n":"Unknown 2"}]},{"t":6,"s":1,"p":1,"n":"PLVD - Location","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Cell"},{"t":11,"p":1,"n":"Near Package Start Location"},{"t":11,"p":1,"n":"Near Editor Location"},{"t":3,"p":1,"n":"Object ID"},{"t":3,"p":1,"n":"Object Type"},{"t":3,"p":1,"n":"Keyword"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Radius"}]},{"t":3,"n":"CITC - Condition Count"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]},{"t":1,"p":1,"n":"FLOR - Flora","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":11,"n":"PNAM - Unknown"},{"t":2,"p":1,"n":"RNAM - Activate Text Override"},{"t":11,"n":"FNAM - Unknown"},{"t":3,"p":1,"n":"PFIG - Ingredient"},{"t":3,"p":1,"n":"SNAM - Sound"},{"t":6,"s":1,"p":1,"n":"PFPC - Seasonal ingredient production","c":[{"t":3,"p":1,"n":"Spring"},{"t":3,"p":1,"n":"Summer "},{"t":3,"p":1,"n":"Fall"},{"t":3,"p":1,"n":"Winter"}]}]},{"t":1,"p":1,"n":"FLST - FormID List","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":8,"s":1,"p":1,"n":"FormIDs","d":1,"c":[{"t":3,"p":1,"n":"LNAM - FormID"}]}]},{"t":1,"p":1,"n":"FSTP - Footstep","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"DATA - Impact Data Set"},{"t":2,"p":1,"n":"ANAM - Tag"}]},{"t":1,"p":1,"n":"FSTS - Footstep Set","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"XCNT - Count","c":[{"t":3,"n":"Walk Forward Sets"},{"t":3,"n":"Run Forward Sets"},{"t":3,"n":"Walk Forward Alternate Sets"},{"t":3,"n":"Run Forward Alternate Sets"},{"t":3,"n":"Walk Forward Alternate 2 Sets"}]},{"t":7,"s":1,"p":1,"n":"DATA - Footstep Sets","c":[{"t":3,"p":1,"n":"Footstep"}]}]},{"t":1,"p":1,"n":"FURN - Furniture","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":11,"n":"PNAM - Unknown"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":3,"p":1,"n":"KNAM - Interaction Keyword"},{"t":3,"p":1,"n":"MNAM - Active Markers \/ Flags"},{"t":6,"s":1,"p":1,"n":"WBDT - Workbench Data","c":[{"t":3,"p":1,"n":"Bench Type"},{"t":3,"p":1,"n":"Uses Skill"}]},{"t":3,"p":1,"n":"NAM1 - Associated Spell"},{"t":8,"s":1,"p":1,"n":"Markers","d":1,"c":[{"t":6,"p":1,"n":"Marker","c":[{"t":3,"p":1,"n":"ENAM - Marker Index"},{"t":6,"p":1,"n":"NAM0 - Disabled Entry Points","c":[{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Disabled Points"}]},{"t":3,"p":1,"n":"FNMK - Marker Keyword"}]}]},{"t":8,"s":1,"p":1,"n":"Marker Entry Points","d":1,"c":[{"t":6,"p":1,"n":"FNPR - Marker","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Entry Points"}]}]},{"t":2,"p":1,"n":"XMRK - Model Filename"}]},{"t":1,"p":1,"n":"GLOB - Global","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"FNAM - Type"},{"t":5,"p":1,"n":"FLTV - Value"}]},{"t":1,"p":1,"n":"GMST - Game Setting","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"Name"},{"t":3,"p":1,"n":"Int"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"}]},{"t":1,"p":1,"n":"GRAS - Grass","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Density"},{"t":3,"p":1,"n":"Min Slope"},{"t":3,"p":1,"n":"Max Slope"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Units From Water"},{"t":3,"p":1,"n":"Units From Water Type"},{"t":5,"p":1,"n":"Position Range"},{"t":5,"p":1,"n":"Height Range"},{"t":5,"p":1,"n":"Color Range"},{"t":5,"p":1,"n":"Wave Period"},{"t":3,"p":1,"n":"Flags"}]}]},{"t":1,"p":1,"n":"HAIR","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"}]},{"t":1,"p":1,"n":"HAZD - Hazard","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":3,"p":1,"n":"MNAM - Image Space Modifier"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Limit"},{"t":5,"p":1,"n":"Radius"},{"t":5,"p":1,"n":"Lifetime"},{"t":5,"p":1,"n":"Image Space Radius"},{"t":5,"p":1,"n":"Target Interval"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Spell"},{"t":3,"p":1,"n":"Light"},{"t":3,"p":1,"n":"Impact Data Set"},{"t":3,"p":1,"n":"Sound"}]}]},{"t":1,"p":1,"n":"HDPT - Head Part","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":3,"p":1,"n":"DATA - Flags"},{"t":3,"p":1,"n":"PNAM - Type"},{"t":8,"s":1,"p":1,"n":"Extra Parts","d":1,"c":[{"t":3,"p":1,"n":"HNAM - Part"}]},{"t":8,"s":1,"p":1,"n":"Parts","d":1,"c":[{"t":6,"p":1,"n":"Part","c":[{"t":3,"p":1,"n":"NAM0 - Part Type"},{"t":2,"p":1,"n":"NAM1 - Filename"}]}]},{"t":3,"p":1,"n":"TNAM - Texture Set"},{"t":3,"p":1,"n":"CNAM - Color"},{"t":3,"p":1,"n":"RNAM - Valid Races"}]},{"t":1,"n":"IDLE - Idle Animation","c":[{"t":2,"n":"EDID - Editor ID"},{"t":8,"n":"Conditions","c":[{"t":6,"n":"Condition","c":[{"t":6,"n":"CTDA - ","c":[{"t":3,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"n":"Comparison Value - Float"},{"t":3,"n":"Comparison Value - Global"},{"t":3,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"n":"None"},{"t":3,"n":"Integer"},{"t":5,"n":"Float"},{"t":11,"n":"Variable Name (unused)"},{"t":3,"n":"Sex"},{"t":3,"n":"Actor Value"},{"t":3,"n":"Crime Type"},{"t":3,"n":"Axis"},{"t":3,"n":"Quest Stage (unused)"},{"t":3,"n":"Misc Stat"},{"t":3,"n":"Alignment"},{"t":3,"n":"Equip Type"},{"t":3,"n":"Form Type"},{"t":3,"n":"Critical Stage"},{"t":3,"n":"Object Reference"},{"t":3,"n":"Inventory Object"},{"t":3,"n":"Actor"},{"t":3,"n":"Voice Type"},{"t":3,"n":"Idle"},{"t":3,"n":"Form List"},{"t":3,"n":"Quest"},{"t":3,"n":"Faction"},{"t":3,"n":"Cell"},{"t":3,"n":"Class"},{"t":3,"n":"Race"},{"t":3,"n":"Actor Base"},{"t":3,"n":"Global"},{"t":3,"n":"Weather"},{"t":3,"n":"Package"},{"t":3,"n":"Encounter Zone"},{"t":3,"n":"Perk"},{"t":3,"n":"Owner"},{"t":3,"n":"Furniture"},{"t":3,"n":"Effect Item"},{"t":3,"n":"Base Effect"},{"t":3,"n":"Worldspace"},{"t":3,"n":"VATS Value Function"},{"t":3,"n":"VATS Value Param (INVALID)"},{"t":3,"n":"Referenceable Object"},{"t":3,"n":"Region"},{"t":3,"n":"Keyword"},{"t":3,"n":"Player Action"},{"t":3,"n":"Casting Type"},{"t":3,"n":"Shout"},{"t":3,"n":"Location"},{"t":3,"n":"Location Ref Type"},{"t":3,"n":"Alias"},{"t":3,"n":"Packdata ID"},{"t":3,"n":"Association Type"},{"t":3,"n":"Furniture Anim"},{"t":3,"n":"Furniture Entry"},{"t":3,"n":"Scene"},{"t":3,"n":"Ward State"},{"t":3,"n":"Event"},{"t":3,"n":"Event Data"},{"t":3,"n":"Quest Stage"},{"t":3,"n":"Weapon"},{"t":3,"n":"Weapon List"},{"t":3,"n":"Target"},{"t":3,"n":"Target List"},{"t":3,"n":"Target Part"},{"t":3,"n":"VATS Action"},{"t":3,"n":"Critical Effect"},{"t":3,"n":"Critical Effect List"},{"t":3,"n":"Weapon Type"},{"t":3,"n":"Projectile Type"},{"t":3,"n":"Delivery Type"},{"t":3,"n":"Run On"},{"t":3,"n":"Reference"},{"t":3,"n":"Parameter #3"}]},{"t":2,"n":"CIS1 - Parameter #1"},{"t":2,"n":"CIS2 - Parameter #2"}]}]},{"t":2,"n":"DNAM - Filename"},{"t":2,"n":"ENAM - Animation Event"},{"t":7,"n":"ANAM - Related Idle Animations","c":[{"t":3,"n":"Related Idle Animation"}]},{"t":6,"n":"DATA - Data (unused)","c":[{"t":6,"n":"Looping seconds (both 255 forever)","c":[{"t":3,"n":"Min"},{"t":3,"n":"Max"}]},{"t":3,"n":"Flags"},{"t":3,"n":"Animation Group Section"},{"t":3,"n":"Replay Delay"}]}]},{"t":1,"p":1,"n":"IDLM - Idle Marker","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"IDLF - Flags"},{"t":3,"p":1,"n":"IDLC - Animation Count"},{"t":5,"p":1,"n":"IDLT - Idle Timer Setting"},{"t":7,"p":1,"n":"IDLA - Animations","c":[{"t":3,"p":1,"n":"Animation"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]}]},{"t":1,"p":1,"n":"IMAD - Image Space Adapter","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DNAM - Data Count","c":[{"t":3,"n":"Flags"},{"t":5,"n":"Duration"},{"t":6,"n":"HDR","c":[{"t":3,"n":"Eye Adapt Speed Mult"},{"t":3,"n":"Eye Adapt Speed Add"},{"t":3,"n":"Bloom Blur Radius Mult"},{"t":3,"n":"Bloom Blur Radius Add"},{"t":3,"n":"Bloom Threshold Mult"},{"t":3,"n":"Bloom Threshold Add"},{"t":3,"n":"Bloom Scale Mult"},{"t":3,"n":"Bloom Scale Add"},{"t":3,"n":"Target Lum Min Mult"},{"t":3,"n":"Target Lum Min Add"},{"t":3,"n":"Target Lum Max Mult"},{"t":3,"n":"Target Lum Max Add"},{"t":3,"n":"Sunlight Scale Mult"},{"t":3,"n":"Sunlight Scale Add"},{"t":3,"n":"Sky Scale Mult"},{"t":3,"n":"Sky Scale Add"}]},{"t":3,"n":"Unknown08 Mult"},{"t":3,"n":"Unknown48 Add"},{"t":3,"n":"Unknown09 Mult"},{"t":3,"n":"Unknown49 Add"},{"t":3,"n":"Unknown0A Mult"},{"t":3,"n":"Unknown4A Add"},{"t":3,"n":"Unknown0B Mult"},{"t":3,"n":"Unknown4B Add"},{"t":3,"n":"Unknown0C Mult"},{"t":3,"n":"Unknown4C Add"},{"t":3,"n":"Unknown0D Mult"},{"t":3,"n":"Unknown4D Add"},{"t":3,"n":"Unknown0E Mult"},{"t":3,"n":"Unknown4E Add"},{"t":3,"n":"Unknown0F Mult"},{"t":3,"n":"Unknown4F Add"},{"t":3,"n":"Unknown10 Mult"},{"t":3,"n":"Unknown50 Add"},{"t":6,"n":"Cinematic","c":[{"t":3,"n":"Saturation Mult"},{"t":3,"n":"Saturation Add"},{"t":3,"n":"Brightness Mult"},{"t":3,"n":"Brightness Add"},{"t":3,"n":"Contrast Mult"},{"t":3,"n":"Contrast Add"}]},{"t":3,"n":"Unknown14 Mult"},{"t":3,"n":"Unknown54 Add"},{"t":3,"n":"Tint Color"},{"t":3,"n":"Blur Radius"},{"t":3,"n":"Double Vision Strength"},{"t":3,"n":"Radial Blur Strength"},{"t":3,"n":"Radial Blur Ramp Up"},{"t":3,"n":"Radial Blur Start"},{"t":3,"n":"Radial Blur Flags"},{"t":5,"n":"Radial Blur Center X"},{"t":5,"n":"Radial Blur Center Y"},{"t":3,"n":"DoF Strength"},{"t":3,"n":"DoF Distance"},{"t":3,"n":"DoF Range"},{"t":3,"n":"DoF Flags"},{"t":3,"n":"Radial Blur Ramp Down"},{"t":3,"n":"Radial Blur Down Start"},{"t":3,"n":"Fade Color"},{"t":3,"n":"Motion Blur Strength"}]},{"t":7,"p":1,"n":"BNAM - Blur Radius","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"VNAM - Double Vision Strength","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"TNAM - Tint Color","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"},{"t":5,"p":1,"n":"Alpha"}]}]},{"t":7,"p":1,"n":"NAM3 - Fade Color","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"},{"t":5,"p":1,"n":"Alpha"}]}]},{"t":7,"p":1,"n":"RNAM - Radial Blur Strength","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"SNAM - Radial Blur Ramp Up","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"UNAM - Radial Blur Start","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"NAM1 - Radial Blur Ramp Down","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"NAM2 - Radial Blur Down Start","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"WNAM - DoF Strength","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"XNAM - DoF Distance","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"YNAM - DoF Range","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"NAM4 - Motion Blur Strength","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":6,"s":1,"p":1,"n":"HDR","c":[{"t":7,"p":1,"n":"aIAD - Eye Adapt Speed Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"@IAD - Eye Adapt Speed Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"bIAD - Bloom Blur Radius Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"AIAD - Bloom Blur Radius Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"cIAD - Bloom Threshold Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"BIAD - Bloom Threshold Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"dIAD - Bloom Scale Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"CIAD - Bloom Scale Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"eIAD - Target Lum Min Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"DIAD - Target Lum Min Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"fIAD - Target Lum Max Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"EIAD - Target Lum Max Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"gIAD - Sunlight Scale Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"FIAD - Sunlight Scale Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"hIAD - Sky Scale Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"GIAD - Sky Scale Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]}]},{"t":11,"n":"iIAD - Unknown"},{"t":11,"n":"HIAD - Unknown"},{"t":11,"n":"jIAD - Unknown"},{"t":11,"n":"IIAD - Unknown"},{"t":11,"n":"kIAD - Unknown"},{"t":11,"n":"JIAD - Unknown"},{"t":11,"n":"lIAD - Unknown"},{"t":11,"n":"KIAD - Unknown"},{"t":11,"n":"mIAD - Unknown"},{"t":11,"n":"LIAD - Unknown"},{"t":11,"n":"nIAD - Unknown"},{"t":11,"n":"MIAD - Unknown"},{"t":11,"n":"oIAD - Unknown"},{"t":11,"n":"NIAD - Unknown"},{"t":11,"n":"pIAD - Unknown"},{"t":11,"n":"OIAD - Unknown"},{"t":11,"n":"qIAD - Unknown"},{"t":11,"n":"PIAD - Unknown"},{"t":6,"s":1,"p":1,"n":"Cinematic","c":[{"t":7,"p":1,"n":"rIAD - Saturation Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"QIAD - Saturation Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"sIAD - Brightness Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"RIAD - Brightness Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"tIAD - Contrast Mult","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]},{"t":7,"p":1,"n":"SIAD - Contrast Add","c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Time"},{"t":5,"p":1,"n":"Value"}]}]}]},{"t":11,"n":"uIAD - Unknown"},{"t":11,"n":"TIAD - Unknown"}]},{"t":1,"p":1,"n":"IMGS - Image Space","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":11,"n":"ENAM - Unknown"},{"t":6,"s":1,"p":1,"n":"HNAM - HDR","c":[{"t":5,"p":1,"n":"Eye Adapt Speed"},{"t":5,"p":1,"n":"Bloom Blur Radius"},{"t":5,"p":1,"n":"Bloom Threshold"},{"t":5,"p":1,"n":"Bloom Scale"},{"t":5,"p":1,"n":"Receive Bloom Threshold"},{"t":5,"p":1,"n":"White"},{"t":5,"p":1,"n":"Sunlight Scale"},{"t":5,"p":1,"n":"Sky Scale"},{"t":5,"p":1,"n":"Eye Adapt Strength"}]},{"t":6,"s":1,"p":1,"n":"CNAM - Cinematic","c":[{"t":5,"p":1,"n":"Saturation"},{"t":5,"p":1,"n":"Brightness"},{"t":5,"p":1,"n":"Contrast"}]},{"t":6,"s":1,"p":1,"n":"TNAM - Tint","c":[{"t":5,"p":1,"n":"Amount"},{"t":6,"p":1,"n":"Color","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}]}]},{"t":6,"s":1,"p":1,"n":"DNAM - Depth of Field","c":[{"t":5,"p":1,"n":"Strength"},{"t":5,"p":1,"n":"Distance"},{"t":5,"p":1,"n":"Range"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Sky \/ Blur Radius"}]}]},{"t":1,"p":1,"n":"INFO - Dialog response","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]},{"t":6,"p":1,"n":"Script Fragments","c":[{"t":3,"n":"Unknown"},{"t":3,"p":1,"n":"Flags"},{"t":2,"p":1,"n":"fileName"},{"t":7,"p":1,"n":"Fragments","c":[{"t":6,"p":1,"n":"Fragment","c":[{"t":3,"n":"Unknown"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]}]}]},{"t":11,"n":"DATA - Unknown"},{"t":6,"s":1,"p":1,"n":"ENAM - Response flags","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Reset Hours"}]},{"t":3,"p":1,"n":"TPIC - Topic"},{"t":3,"p":1,"n":"PNAM - Previous INFO"},{"t":3,"p":1,"n":"CNAM - Favor Level"},{"t":8,"s":1,"p":1,"n":"Link To","d":1,"c":[{"t":3,"p":1,"n":"TCLT - Response"}]},{"t":3,"p":1,"n":"DNAM - Response Data"},{"t":8,"s":1,"p":1,"n":"Responses","d":1,"c":[{"t":6,"p":1,"n":"Response","c":[{"t":6,"p":1,"n":"TRDT - Response Data","c":[{"t":3,"p":1,"n":"Emotion Type"},{"t":3,"p":1,"n":"Emotion Value"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Response number"},{"t":3,"p":1,"n":"Sound"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"NAM1 - Response Text"},{"t":2,"p":1,"n":"NAM2 - Script Notes"},{"t":2,"p":1,"n":"NAM3 - Edits"},{"t":3,"p":1,"n":"SNAM - Idle Animations: Speaker"},{"t":3,"p":1,"n":"LNAM - Idle Animations: Listener"}]}]},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":8,"n":"Unknown","c":[{"t":6,"n":"Unknown","c":[{"t":11,"n":"SCHR - Unknown"},{"t":3,"n":"QNAM - Unknown"},{"n":"NEXT - Marker"}]}]},{"t":2,"p":1,"n":"RNAM - Prompt"},{"t":3,"p":1,"n":"ANAM - Speaker"},{"t":3,"p":1,"n":"TWAT - Walk Away Topic"},{"t":3,"p":1,"n":"ONAM - Audio Output Override"}]},{"t":1,"p":1,"n":"INGR - Ingredient","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"ETYP - Equipment Type"},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":6,"s":1,"p":1,"n":"ENIT - Effect Data","c":[{"t":3,"p":1,"n":"Ingredient Value"},{"t":3,"p":1,"n":"Flags"}]},{"t":8,"s":1,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":3,"p":1,"n":"EFID - Base Effect"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":5,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"}]},{"t":8,"s":1,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]}]},{"t":1,"p":1,"n":"IPCT - Impact","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":5,"p":1,"n":"Effect - Duration"},{"t":3,"p":1,"n":"Effect - Orientation"},{"t":5,"p":1,"n":"Angle Threshold"},{"t":5,"p":1,"n":"Placement Radius"},{"t":3,"p":1,"n":"Sound Level"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Impact Result"},{"t":11,"n":"Unknown"}]},{"t":6,"s":1,"p":1,"n":"DODT - Decal Data","c":[{"t":5,"p":1,"n":"Min Width"},{"t":5,"p":1,"n":"Max Width"},{"t":5,"p":1,"n":"Min Height"},{"t":5,"p":1,"n":"Max Height"},{"t":5,"p":1,"n":"Depth"},{"t":5,"p":1,"n":"Shininess"},{"t":6,"p":1,"n":"Parallax","c":[{"t":5,"p":1,"n":"Scale"},{"t":3,"p":1,"n":"Passes"}]},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"},{"t":6,"p":1,"n":"Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":3,"p":1,"n":"DNAM - Texture Set"},{"t":3,"p":1,"n":"ENAM - Secondary Texture Set"},{"t":3,"p":1,"n":"SNAM - Sound 1"},{"t":3,"p":1,"n":"NAM1 - Sound 2"},{"t":3,"p":1,"n":"NAM2 - Hazard"}]},{"t":1,"p":1,"n":"IPDS - Impact Data Set","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":8,"s":1,"p":1,"n":"Data","d":1,"c":[{"t":6,"p":1,"n":"PNAM - ","c":[{"t":3,"p":1,"n":"Material"},{"t":3,"p":1,"n":"Impact"}]}]}]},{"t":1,"p":1,"n":"KEYM - Key","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]}]},{"t":1,"p":1,"n":"KYWD - Keyword","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"CNAM - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":1,"p":1,"n":"LAND - Landscape","d":1,"c":[{"t":11,"n":"DATA - Unknown"},{"t":11,"n":"VNML - Vertex Normals"},{"t":11,"n":"VHGT - Vertext Height Map"},{"t":11,"n":"VCLR - Vertex Colours"},{"t":8,"s":1,"p":1,"n":"Layers","d":1,"c":[{"t":6,"p":1,"n":"Base Layer","c":[{"t":6,"p":1,"n":"BTXT - Base Layer Header","c":[{"t":3,"p":1,"n":"Texture"},{"t":3,"p":1,"n":"Quadrant"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Layer"}]}]},{"t":6,"p":1,"n":"Alpha Layer","c":[{"t":6,"p":1,"n":"ATXT - Alpha Layer Header","c":[{"t":3,"p":1,"n":"Texture"},{"t":3,"p":1,"n":"Quadrant"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Layer"}]},{"t":11,"p":1,"n":"VTXT - Alpha Layer Data"}]}]},{"t":7,"p":1,"n":"VTEX - Textures","c":[{"t":3,"p":1,"n":"Texture"}]}]},{"t":1,"p":1,"n":"LCRT - Location Reference Type","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"CNAM - Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":1,"n":"LCTN - Location","c":[{"t":2,"n":"EDID - Editor ID"},{"t":7,"n":"ACPR - Actor Cell Persistent Reference","c":[{"t":6,"n":"","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Location"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":7,"n":"LCPR - Location Cell Persistent Reference","c":[{"t":6,"n":"","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Location"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":7,"n":"RCPR - Reference Cell Persistent Reference","c":[{"t":3,"n":"Ref"}]},{"t":7,"n":"ACUN - Actor Cell Unique","c":[{"t":6,"n":"","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Ref"},{"t":3,"n":"Location"}]}]},{"t":7,"n":"LCUN - Location Cell Unique","c":[{"t":6,"n":"","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Ref"},{"t":3,"n":"Location"}]}]},{"t":7,"n":"RCUN - Reference Cell Unique","c":[{"t":3,"n":"Actor"}]},{"t":7,"n":"ACSR - Actor Cell Static Reference","c":[{"t":6,"n":"","c":[{"t":3,"n":"Loc Ref Type"},{"t":3,"n":"Marker"},{"t":3,"n":"Location"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":7,"n":"LCSR - Location Cell Static Reference","c":[{"t":6,"n":"","c":[{"t":3,"n":"Loc Ref Type"},{"t":3,"n":"Marker"},{"t":3,"n":"Location"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":7,"n":"RCSR - Reference Cell Static Reference","c":[{"t":3,"n":"Ref"}]},{"t":8,"n":"Actor Cell Encounter Cell","c":[{"t":6,"n":"ACEC - Unknown","c":[{"t":3,"n":"Location"},{"t":7,"n":"Coordinates","c":[{"t":6,"n":"","c":[{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]}]}]},{"t":8,"n":"Location Cell Encounter Cell","c":[{"t":6,"n":"LCEC - Unknown","c":[{"t":3,"n":"Location"},{"t":7,"n":"Coordinates","c":[{"t":6,"n":"","c":[{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]}]}]},{"t":8,"n":"Reference Cell Encounter Cell","c":[{"t":6,"n":"RCEC - Unknown","c":[{"t":3,"n":"Location"},{"t":7,"n":"Coordinates","c":[{"t":6,"n":"","c":[{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]}]}]},{"t":7,"n":"ACID - Actor Cell Marker Reference","c":[{"t":3,"n":"Ref"}]},{"t":7,"n":"LCID - Location Cell Marker Reference","c":[{"t":3,"n":"Ref"}]},{"t":7,"n":"ACEP - Actor Cell Enable Point","c":[{"t":6,"n":"","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Ref"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":7,"n":"LCEP - Location Cell Enable Point","c":[{"t":6,"n":"","c":[{"t":3,"n":"Actor"},{"t":3,"n":"Ref"},{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]}]},{"t":2,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"n":"KWDA - Keywords","c":[{"t":3,"n":"Keyword"}]},{"t":3,"n":"PNAM - Parent Location"},{"t":3,"n":"NAM1 - Music"},{"t":3,"n":"FNAM - Unreported Crime Faction"},{"t":3,"n":"MNAM - World Location Marker Ref"},{"t":5,"n":"RNAM - World Location Radius"},{"t":3,"n":"NAM0 - Horse Marker Ref"},{"t":6,"n":"CNAM - Color","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unknown"}]}]},{"t":1,"p":1,"n":"LENS - Lens Flare","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":5,"p":1,"n":"CNAM - Color Influence"},{"t":5,"p":1,"n":"DNAM - Fade Distance Radius Scale"},{"t":3,"n":"LFSP - Count"},{"t":8,"s":1,"p":1,"n":"Lens Flare Sprites","d":1,"c":[{"t":6,"p":1,"n":"Flare","c":[{"t":2,"p":1,"n":"DNAM - Lens Flare Sprite ID"},{"t":2,"p":1,"n":"FNAM - Texture"},{"t":6,"p":1,"n":"LFSD - Lens Flare Data","c":[{"t":6,"p":1,"n":"Tint","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}]},{"t":5,"p":1,"n":"Width"},{"t":5,"p":1,"n":"Height"},{"t":5,"p":1,"n":"Position"},{"t":5,"p":1,"n":"Angular Fade"},{"t":5,"p":1,"n":"Opacity"},{"t":3,"p":1,"n":"Flags"}]}]}]}]},{"t":1,"p":1,"n":"LGTM - Lighting Template","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - Lighting","c":[{"t":6,"p":1,"n":"Ambient Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Directional Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Fog Color Near","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Fog Near"},{"t":5,"p":1,"n":"Fog Far"},{"t":3,"p":1,"n":"Directional Rotation XY"},{"t":3,"p":1,"n":"Directional Rotation Z"},{"t":5,"p":1,"n":"Directional Fade"},{"t":5,"p":1,"n":"Fog Clip Dist"},{"t":5,"p":1,"n":"Fog Power"},{"t":6,"p":1,"n":"Ambient Colors","c":[{"t":6,"p":1,"n":"Directional","c":[{"t":6,"p":1,"n":"X+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"X-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Specular","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Scale"}]},{"t":6,"p":1,"n":"Fog Color Far","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Fog Max"},{"t":6,"p":1,"n":"Light Fade Distances","c":[{"t":5,"p":1,"n":"Start"},{"t":5,"p":1,"n":"End"}]},{"t":11,"n":"Unknown"}]},{"t":6,"s":1,"p":1,"n":"DALC - Directional Ambient Lighting Colors","c":[{"t":6,"p":1,"n":"Directional","c":[{"t":6,"p":1,"n":"X+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"X-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Specular","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Scale"}]}]},{"t":1,"p":1,"n":"LIGH - Light","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Time"},{"t":3,"p":1,"n":"Radius"},{"t":6,"p":1,"n":"Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Falloff Exponent"},{"t":5,"p":1,"n":"FOV"},{"t":5,"p":1,"n":"Near Clip"},{"t":6,"p":1,"n":"Flicker Effect","c":[{"t":5,"p":1,"n":"Period"},{"t":5,"p":1,"n":"Intensity Amplitude"},{"t":5,"p":1,"n":"Movement Amplitude"}]},{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":5,"p":1,"n":"FNAM - Fade value"},{"t":3,"p":1,"n":"SNAM - Sound"}]},{"t":1,"p":1,"n":"LSCR - Load Screen","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":2,"p":1,"n":"DESC - Description"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":3,"p":1,"n":"NNAM - Loading Screen NIF"},{"t":5,"p":1,"n":"SNAM - Initial Scale"},{"t":6,"s":1,"p":1,"n":"RNAM - Initial Rotation","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"},{"t":3,"p":1,"n":"Z"}]},{"t":6,"s":1,"p":1,"n":"ONAM - Rotation Offset Constraints","c":[{"t":3,"p":1,"n":"Min"},{"t":3,"p":1,"n":"Max"}]},{"t":6,"s":1,"p":1,"n":"XNAM - Initial Translation Offset","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":2,"p":1,"n":"MOD2 - Camera Path"}]},{"t":1,"p":1,"n":"LTEX - Landscape Texture","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"TNAM - Texture Set"},{"t":3,"p":1,"n":"MNAM - Material Type"},{"t":6,"s":1,"p":1,"n":"HNAM - Havok Data","c":[{"t":3,"p":1,"n":"Friction"},{"t":3,"p":1,"n":"Restitution"}]},{"t":3,"p":1,"n":"SNAM - Texture Specular Exponent"},{"t":8,"s":1,"p":1,"n":"Grasses","d":1,"c":[{"t":3,"p":1,"n":"GNAM - Grass"}]},{"t":3,"n":"INAM - Unused"}]},{"t":1,"p":1,"n":"LVLI - Leveled Item","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"LVLD - Chance None"},{"t":3,"p":1,"n":"LVLF - Flags"},{"t":3,"p":1,"n":"LVLG - Global"},{"t":3,"n":"LLCT - Count"},{"t":10,"p":1,"o":1,"n":"Leveled List Entries","d":1,"c":[{"t":6,"p":1,"n":"Leveled List Entry","c":[{"t":6,"p":1,"n":"LVLO - Base Data","c":[{"t":3,"p":1,"n":"Level"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Count"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]}]},{"t":1,"p":1,"n":"LVLN - Leveled NPC","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"LVLD - Chance None"},{"t":3,"p":1,"n":"LVLF - Flags"},{"t":3,"p":1,"n":"LVLG - Global"},{"t":3,"n":"LLCT - Count"},{"t":10,"p":1,"o":1,"n":"Leveled List Entries","d":1,"c":[{"t":6,"p":1,"n":"Leveled List Entry","c":[{"t":6,"p":1,"n":"LVLO - Base Data","c":[{"t":3,"p":1,"n":"Level"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Count"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]}]},{"t":1,"p":1,"n":"LVSP - Leveled Spell","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":3,"p":1,"n":"LVLD - Chance None"},{"t":3,"p":1,"n":"LVLF - Flags"},{"t":3,"n":"LLCT - Count"},{"t":10,"p":1,"o":1,"n":"Leveled List Entries","d":1,"c":[{"t":6,"p":1,"n":"Leveled List Entry","c":[{"t":6,"p":1,"n":"LVLO - Base Data","c":[{"t":3,"p":1,"n":"Level"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Count"}]}]}]}]},{"t":1,"p":1,"n":"MATO - Material Object","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":8,"s":1,"p":1,"n":"Property Data","d":1,"c":[{"t":11,"p":1,"n":"DNAM - Data"}]},{"t":6,"s":1,"p":1,"n":"DATA - Directional Material Data","c":[{"t":5,"p":1,"n":"Falloff Scale"},{"t":5,"p":1,"n":"Falloff Bias"},{"t":5,"p":1,"n":"Noise UV Scale"},{"t":5,"p":1,"n":"Material UV Scale"},{"t":6,"p":1,"n":"Projection Vector","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":5,"p":1,"n":"Normal Dampener"},{"t":6,"p":1,"n":"Single Pass Color","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}]},{"t":3,"p":1,"n":"Flags"}]}]},{"t":1,"p":1,"n":"MATT - Material Type","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"PNAM - Material Parent"},{"t":2,"p":1,"n":"MNAM - Material Name"},{"t":6,"s":1,"p":1,"n":"CNAM - Havok Display Color","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}]},{"t":5,"p":1,"n":"BNAM - Buoyancy"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":3,"p":1,"n":"HNAM - Havok Impact Data Set"}]},{"t":1,"p":1,"n":"MESG - Message","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"DESC - Description"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"INAM - Icon (unused)"},{"t":3,"p":1,"n":"QNAM - Owner Quest"},{"t":3,"p":1,"n":"DNAM - Flags"},{"t":3,"p":1,"n":"TNAM - Display Time"},{"t":8,"s":1,"p":1,"n":"Menu Buttons","d":1,"c":[{"t":6,"p":1,"n":"Menu Button","c":[{"t":2,"p":1,"n":"ITXT - Button Text"},{"t":8,"s":1,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]}]},{"t":1,"p":1,"n":"MGEF - Magic Effect","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"MDOB - Menu Display Object"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"Magic Effect Data","c":[{"t":6,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Base Cost"},{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Assoc. Item"},{"t":3,"p":1,"n":"Magic Skill"},{"t":3,"p":1,"n":"Resist Value"},{"t":3,"p":1,"n":"Counter Effect count"},{"t":3,"p":1,"n":"Casting Light"},{"t":5,"p":1,"n":"Taper Weight"},{"t":3,"p":1,"n":"Hit Shader"},{"t":3,"p":1,"n":"Enchant Shader"},{"t":3,"p":1,"n":"Minimum Skill Level"},{"t":6,"p":1,"n":"Spellmaking","c":[{"t":3,"p":1,"n":"Area"},{"t":5,"p":1,"n":"Casting Time"}]},{"t":5,"p":1,"n":"Taper Curve"},{"t":5,"p":1,"n":"Taper Duration"},{"t":5,"p":1,"n":"Second AV Weight"},{"t":3,"p":1,"n":"Archtype"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Projectile"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Delivery"},{"t":3,"p":1,"n":"Second Actor Value"},{"t":3,"p":1,"n":"Casting Art"},{"t":3,"p":1,"n":"Hit Effect Art"},{"t":3,"p":1,"n":"Impact Data"},{"t":5,"p":1,"n":"Skill Usage Multiplier"},{"t":6,"p":1,"n":"Dual Casting","c":[{"t":3,"p":1,"n":"Art"},{"t":5,"p":1,"n":"Scale"}]},{"t":3,"p":1,"n":"Enchant Art"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Equip Ability"},{"t":3,"p":1,"n":"Image Space Modifier"},{"t":3,"p":1,"n":"Perk to Apply"},{"t":3,"p":1,"n":"Casting Sound Level"},{"t":6,"p":1,"n":"Script Effect AI","c":[{"t":5,"p":1,"n":"Score"},{"t":5,"p":1,"n":"Delay Time"}]}]}]},{"t":8,"s":1,"p":1,"n":"Counter Effects","d":1,"c":[{"t":3,"n":"ESCE - Effect"}]},{"t":7,"p":1,"n":"SNDD - Sounds","c":[{"t":6,"p":1,"n":"","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Sound"}]}]},{"t":2,"p":1,"n":"DNAM - Magic Item Description"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]},{"t":1,"p":1,"n":"MISC - Misc. Item","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]}]},{"t":1,"p":1,"n":"MOVT - Movement Type","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"MNAM - Name"},{"t":6,"s":1,"p":1,"n":"SPED - Default Data","c":[{"t":5,"p":1,"n":"Left Walk"},{"t":5,"p":1,"n":"Left Run"},{"t":5,"p":1,"n":"Right Walk"},{"t":5,"p":1,"n":"Right Run"},{"t":5,"p":1,"n":"Forward Walk"},{"t":5,"p":1,"n":"Forward Run"},{"t":5,"p":1,"n":"Back Walk"},{"t":5,"p":1,"n":"Back Run"},{"t":5,"p":1,"n":"Rotate in Place Walk"},{"t":5,"p":1,"n":"Rotate in Place Run"},{"t":5,"p":1,"n":"Rotate while Moving Run"}]},{"t":6,"s":1,"p":1,"n":"INAM - Anim Change Thresholds","c":[{"t":5,"p":1,"n":"Directional"},{"t":5,"p":1,"n":"Movement Speed"},{"t":5,"p":1,"n":"Rotation Speed"}]}]},{"t":1,"p":1,"n":"MSTT - Moveable Static","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"DATA - Flags"},{"t":3,"p":1,"n":"SNAM - Looping Sound"}]},{"t":1,"p":1,"n":"MUSC - Music Type","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":6,"s":1,"p":1,"n":"PNAM - Data","c":[{"t":3,"p":1,"n":"Priority"},{"t":3,"p":1,"n":"Ducking (dB)"}]},{"t":5,"p":1,"n":"WNAM - Fade Duration"},{"t":7,"p":1,"n":"TNAM - Music Tracks","c":[{"t":3,"p":1,"n":"Track"}]}]},{"t":1,"p":1,"n":"MUST - Music Track","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"CNAM - Track Type"},{"t":5,"p":1,"n":"FLTV - Duration"},{"t":5,"p":1,"n":"DNAM - Fade-Out"},{"t":2,"p":1,"n":"ANAM - Track Filename"},{"t":2,"p":1,"n":"BNAM - Finale Filename"},{"t":7,"p":1,"n":"FNAM - Cue Points","c":[{"t":5,"p":1,"n":"Point"}]},{"t":6,"s":1,"p":1,"n":"LNAM - Loop Data","c":[{"t":5,"p":1,"n":"Loop Begins"},{"t":5,"p":1,"n":"Loop Ends"},{"t":3,"p":1,"n":"Loop Count"}]},{"t":3,"n":"CITC - Condition Count"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":7,"p":1,"n":"SNAM - Tracks","c":[{"t":3,"p":1,"n":"Track"}]}]},{"t":1,"n":"NAVI - Navigation Mesh Info Map","c":[{"t":2,"n":"EDID - Editor ID"},{"t":3,"n":"NVER - Version"},{"t":8,"n":"Navigation Map Infos","c":[{"t":6,"n":"NVMI - Navigation Map Info","c":[{"t":3,"n":"Navigation Mesh"},{"t":11,"n":"Unknown"},{"t":5,"n":"X"},{"t":5,"n":"Y"},{"t":5,"n":"Z"},{"t":3,"n":"Preferred Merges Flag"},{"t":7,"n":"Merged To","c":[{"t":3,"n":"Mesh"}]},{"t":7,"n":"Preferred Merges","c":[{"t":3,"n":"Mesh"}]},{"t":7,"n":"Linked Doors","c":[{"t":6,"n":"Door","c":[{"t":11,"n":"Unknown"},{"t":3,"n":"Door Ref"}]}]},{"t":3,"n":"Is Island"},{"t":11,"n":"Unused"},{"t":6,"n":"Island Data","c":[{"t":11,"n":"Unknown"},{"t":7,"n":"Triangles","c":[{"t":11,"n":"Triangle"}]},{"t":7,"n":"Vertices","c":[{"t":11,"n":"Vertex"}]}]},{"t":3,"n":"Parent Worldspace"},{"t":6,"n":"Coordinates","c":[{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]},{"t":3,"n":"Parent Cell"}]}]},{"t":6,"n":"NVPP - Preferred Pathing","c":[{"t":7,"n":"NavMeshes","c":[{"t":7,"n":"Set","c":[{"t":3,"n":""}]}]},{"t":7,"n":"NavMesh Tree?","c":[{"t":6,"n":"","c":[{"t":3,"n":"NavMesh"},{"t":3,"n":"Index\/Node"}]}]}]},{"t":7,"n":"NVSI - Unknown","c":[{"t":3,"n":"Navigation Mesh"}]}]},{"t":1,"n":"NAVM - Navigation Mesh","c":[{"t":2,"n":"EDID - Editor ID"},{"t":6,"n":"NVNM - Geometry","c":[{"t":11,"n":"Unknown"},{"t":3,"n":"Parent Worldspace"},{"t":6,"n":"Coordinates","c":[{"t":3,"n":"Grid Y"},{"t":3,"n":"Grid X"}]},{"t":3,"n":"Parent Cell"},{"t":7,"n":"Vertices","c":[{"t":11,"n":"Vertex"}]},{"t":7,"n":"Triangles","c":[{"t":11,"n":"Triangle"}]},{"t":7,"n":"External Connections","c":[{"t":6,"n":"Connection","c":[{"t":11,"n":"Unknown"},{"t":3,"n":"Mesh"},{"t":3,"n":"Triangle"}]}]},{"t":7,"n":"Door Triangles","c":[{"t":6,"n":"Door Triangle","c":[{"t":3,"n":"Triangle before door"},{"t":11,"n":"Unknown"},{"t":3,"n":"Door"}]}]}]},{"t":11,"n":"ONAM - Unknown"},{"t":11,"n":"PNAM - Unknown"},{"t":11,"n":"NNAM - Unknown"}]},{"t":1,"p":1,"n":"NPC_ - Non-Player Character (Actor)","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"ACBS - Configuration","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Magicka Offset"},{"t":3,"p":1,"n":"Stamina Offset"},{"t":3,"p":1,"n":"Level"},{"t":3,"p":1,"n":"Level Mult"},{"t":3,"p":1,"n":"Calc min level"},{"t":3,"p":1,"n":"Calc max level"},{"t":3,"p":1,"n":"Speed Multiplier"},{"t":3,"p":1,"n":"Disposition Base (unused)"},{"t":3,"p":1,"n":"Template Flags"},{"t":3,"p":1,"n":"Health Offset"},{"t":3,"p":1,"n":"Bleedout Override"}]},{"t":8,"s":1,"p":1,"n":"Factions","d":1,"c":[{"t":6,"p":1,"n":"SNAM - Faction","c":[{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"p":1,"n":"INAM - Death item"},{"t":3,"p":1,"n":"VTCK - Voice"},{"t":3,"p":1,"n":"TPLT - Template"},{"t":3,"p":1,"n":"RNAM - Race","lt":"NAMA - Face parts","lf":"NAM6 - Height"},{"t":3,"n":"SPCT - Count"},{"t":8,"s":1,"p":1,"n":"Actor Effects","d":1,"c":[{"t":3,"p":1,"n":"SPLO - Actor Effect"}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"WNAM - Worn Armor"},{"t":3,"p":1,"n":"ANAM - Far away model"},{"t":3,"p":1,"n":"ATKR - Attack Race"},{"t":10,"p":1,"n":"Attacks","d":1,"c":[{"t":6,"p":1,"n":"Attack","c":[{"t":6,"p":1,"n":"ATKD - Attack Data","c":[{"t":5,"p":1,"n":"Damage Mult"},{"t":5,"p":1,"n":"Attack Chance"},{"t":3,"p":1,"n":"Attack Spell"},{"t":3,"p":1,"n":"Attack Flags"},{"t":5,"p":1,"n":"Attack Angle"},{"t":5,"p":1,"n":"Strike Angle"},{"t":5,"p":1,"n":"Stagger"},{"t":3,"p":1,"n":"Attack Type"},{"t":5,"p":1,"n":"Knockdown"},{"t":5,"p":1,"n":"Recovery Time"},{"t":5,"p":1,"n":"Stamina Mult"}]},{"t":2,"p":1,"n":"ATKE - Attack Event"}]}]},{"t":3,"p":1,"n":"SPOR - Spectator override package list"},{"t":3,"p":1,"n":"OCOR - Observe dead body override package list"},{"t":3,"p":1,"n":"GWOR - Guard warn override package list"},{"t":3,"p":1,"n":"ECOR - Combat override package list"},{"t":3,"n":"PRKZ - Perk Count"},{"t":8,"s":1,"p":1,"n":"Perks","d":1,"c":[{"t":6,"p":1,"n":"PRKR - Perk","c":[{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Rank"},{"t":11,"n":"Unused"}]}]},{"t":3,"n":"COCT - Count"},{"t":10,"p":1,"n":"Items","d":1,"c":[{"t":6,"p":1,"n":"Item","c":[{"t":6,"p":1,"n":"CNTO - Item","c":[{"t":3,"p":1,"n":"Item"},{"t":3,"p":1,"n":"Count"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]},{"t":6,"s":1,"p":1,"n":"AIDT - AI Data","c":[{"t":3,"p":1,"n":"Aggression"},{"t":3,"p":1,"n":"Confidence"},{"t":3,"p":1,"n":"Energy Level"},{"t":3,"p":1,"n":"Responsibility"},{"t":3,"p":1,"n":"Mood"},{"t":3,"p":1,"n":"Assistance"},{"t":6,"p":1,"n":"Aggro","c":[{"t":3,"p":1,"n":"Aggro Radius Behavior"},{"t":3,"n":"Unknown"},{"t":3,"p":1,"n":"Warn"},{"t":3,"p":1,"n":"Warn\/Attack"},{"t":3,"p":1,"n":"Attack"}]}]},{"t":8,"s":1,"p":1,"n":"Packages","d":1,"c":[{"t":3,"p":1,"n":"PKID - Package"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":3,"p":1,"n":"CNAM - Class"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"SHRT - Short Name"},{"t":11,"n":"DATA - Marker"},{"t":6,"s":1,"p":1,"n":"DNAM - Player Skills","c":[{"t":7,"p":1,"n":"Skill Values","c":[{"t":3,"p":1,"n":"Skill"}]},{"t":7,"p":1,"n":"Skill Offsets","c":[{"t":3,"p":1,"n":"Skill"}]},{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"Magicka"},{"t":3,"p":1,"n":"Stamina"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Far away model distance"},{"t":3,"p":1,"n":"Geared up weapons"}]},{"t":8,"s":1,"p":1,"n":"Head Parts","d":1,"c":[{"t":3,"p":1,"n":"PNAM - Head Part"}],"lt":"NAM7 - Weight","lf":"HCLF - Hair Color"},{"t":3,"p":1,"n":"HCLF - Hair Color","lt":"Head Parts","lf":"FTST - Head texture"},{"t":3,"p":1,"n":"ZNAM - Combat Style"},{"t":3,"p":1,"n":"GNAM - Gift Filter"},{"t":11,"n":"NAM5 - Unknown"},{"t":5,"p":1,"n":"NAM6 - Height","lt":"RNAM - Race","lf":"NAM7 - Weight"},{"t":5,"p":1,"n":"NAM7 - Weight","lt":"NAM6 - Height","lf":"Head Parts"},{"t":3,"p":1,"n":"NAM8 - Sound Level"},{"t":10,"p":1,"n":"Sound Types","d":1,"c":[{"t":6,"p":1,"n":"Sound Type","c":[{"t":3,"p":1,"n":"CSDT - Type"},{"t":10,"p":1,"n":"Sounds","c":[{"t":6,"p":1,"n":"Sound","c":[{"t":3,"p":1,"n":"CSDI - Sound"},{"t":3,"p":1,"n":"CSDC - Sound Chance"}]}]}]}]},{"t":3,"p":1,"n":"CSCR - Inherits Sounds From"},{"t":3,"p":1,"n":"DOFT - Default outfit"},{"t":3,"p":1,"n":"SOFT - Sleeping outfit"},{"t":3,"p":1,"n":"DPLT - Default Package List"},{"t":3,"p":1,"n":"CRIF - Crime faction"},{"t":3,"p":1,"n":"FTST - Head texture","lt":"HCLF - Hair Color","lf":"QNAM - Texture lighting"},{"t":6,"s":1,"p":1,"n":"QNAM - Texture lighting","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}],"lt":"FTST - Head texture","lf":"NAM9 - Face morph"},{"t":6,"s":1,"p":1,"n":"NAM9 - Face morph","c":[{"t":5,"p":1,"n":"Nose Long\/Short"},{"t":5,"p":1,"n":"Nose Up\/Down"},{"t":5,"p":1,"n":"Jaw Up\/Down"},{"t":5,"p":1,"n":"Jaw Narrow\/Wide"},{"t":5,"p":1,"n":"Jaw Farward\/Back"},{"t":5,"p":1,"n":"Cheeks Up\/Down"},{"t":5,"p":1,"n":"Cheeks Farward\/Back"},{"t":5,"p":1,"n":"Eyes Up\/Down"},{"t":5,"p":1,"n":"Eyes In\/Out"},{"t":5,"p":1,"n":"Brows Up\/Down"},{"t":5,"p":1,"n":"Brows In\/Out"},{"t":5,"p":1,"n":"Brows Farward\/Back"},{"t":5,"p":1,"n":"Lips Up\/Down"},{"t":5,"p":1,"n":"Lips In\/Out"},{"t":5,"p":1,"n":"Chin Narrow\/Wide"},{"t":5,"p":1,"n":"Chin Up\/Down"},{"t":5,"p":1,"n":"Chin Underbite\/Overbite"},{"t":5,"p":1,"n":"Eyes Farward\/Back"},{"t":5,"n":"Unknown"}],"lt":"QNAM - Texture lighting","lf":"Tint Layers"},{"t":6,"s":1,"p":1,"n":"NAMA - Face parts","c":[{"t":3,"p":1,"n":"Nose"},{"t":3,"n":"Unknown"},{"t":3,"p":1,"n":"Eyes"},{"t":3,"p":1,"n":"Mouth"}],"lt":"Tint Layers","lf":"RNAM - Race"},{"t":10,"p":1,"n":"Tint Layers","d":1,"c":[{"t":6,"p":1,"n":"Layer","c":[{"t":3,"p":1,"n":"TINI - Tint Index"},{"t":6,"p":1,"n":"TINC - Tint Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":3,"p":1,"n":"Alpha"}]},{"t":3,"p":1,"n":"TINV - Interpolation Value"},{"t":3,"p":1,"n":"TIAS - Preset"}]}],"lt":"NAM9 - Face morph","lf":"NAMA - Face parts"}]},{"t":1,"p":1,"n":"OTFT - Outfit","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":7,"s":1,"p":1,"n":"INAM - Items","d":1,"c":[{"t":3,"p":1,"n":"Item"}]}]},{"t":1,"p":1,"n":"PACK - Package","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]},{"t":6,"p":1,"n":"Script Fragments","c":[{"t":3,"n":"Unknown"},{"t":3,"p":1,"n":"Flags"},{"t":2,"p":1,"n":"fileName"},{"t":7,"p":1,"n":"Fragments","c":[{"t":6,"p":1,"n":"Fragment","c":[{"t":3,"n":"Unknown"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]}]}]},{"t":6,"s":1,"p":1,"n":"PKDT - Pack Data","c":[{"t":3,"p":1,"n":"General Flags"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Interrupt Override"},{"t":3,"p":1,"n":"Preferred Speed"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Interrupt Flags"}]},{"t":6,"s":1,"p":1,"n":"PSDT - Schedule","c":[{"t":3,"p":1,"n":"Month"},{"t":3,"p":1,"n":"Day of week"},{"t":3,"p":1,"n":"Date"},{"t":3,"p":1,"n":"Hour"},{"t":3,"p":1,"n":"Minute"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Duration (minutes)"}]},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":6,"s":1,"p":1,"n":"Idle Animations","c":[{"t":3,"p":1,"n":"IDLF - Flags"},{"t":6,"p":1,"n":"IDLC - ","c":[{"t":3,"p":1,"n":"Animation Count"},{"t":11,"n":"Unknown"}]},{"t":5,"p":1,"n":"IDLT - Idle Timer Setting"},{"t":7,"p":1,"n":"IDLA - Animations","c":[{"t":3,"p":1,"n":"Animation"}]},{"t":11,"n":"IDLB - Unknown"}]},{"t":3,"p":1,"n":"CNAM - Combat Style"},{"t":3,"p":1,"n":"QNAM - Owner Quest"},{"t":6,"s":1,"p":1,"n":"PKCU - Counter","c":[{"t":3,"p":1,"n":"Data Input Count"},{"t":3,"p":1,"n":"Package Template"},{"t":3,"p":1,"n":"Version Counter (autoincremented)"}]},{"t":6,"s":1,"p":1,"n":"Package Data","c":[{"t":8,"p":1,"n":"Data Input Values","c":[{"t":6,"p":1,"n":"Value","c":[{"t":2,"p":1,"n":"ANAM - Type"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Bool"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"n":"BNAM - Unknown"},{"t":8,"p":1,"n":"Topic","c":[{"t":6,"p":1,"n":"PDTO - Topic Data","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Topic"},{"t":2,"p":1,"n":"Subtype"}]}]},{"t":6,"p":1,"n":"PLDT - Location","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Cell"},{"t":11,"p":1,"n":"Near Package Start Location"},{"t":11,"p":1,"n":"Near Editor Location"},{"t":3,"p":1,"n":"Object ID"},{"t":3,"p":1,"n":"Object Type"},{"t":3,"p":1,"n":"Keyword"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Radius"}]},{"t":6,"p":1,"n":"PTDA - Target","c":[{"t":6,"p":1,"n":"Target Data","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Object ID"},{"t":3,"p":1,"n":"Object Type"},{"t":3,"p":1,"n":"Alias"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Count \/ Distance"}]}]},{"t":11,"n":"TPIC - Unknown"}]}]},{"t":8,"p":1,"n":"Data Inputs","c":[{"t":6,"p":1,"n":"Data Input","c":[{"t":3,"p":1,"n":"UNAM - Index"},{"t":2,"p":1,"n":"BNAM - Name"},{"t":3,"p":1,"n":"PNAM - Flags"}]}]}]},{"t":11,"n":"XNAM - Marker"},{"t":6,"s":1,"p":1,"n":"Procedure Tree","c":[{"t":8,"p":1,"n":"Branches","c":[{"t":6,"p":1,"n":"Branch","c":[{"t":2,"p":1,"n":"ANAM - Branch Type"},{"t":3,"p":1,"n":"CITC - Condition Count"},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":6,"p":1,"n":"PRCB - Root","c":[{"t":3,"p":1,"n":"Branch Count"},{"t":3,"p":1,"n":"Flags"}]},{"t":2,"p":1,"n":"PNAM - Procedure Type"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":8,"p":1,"n":"Data Input Indexes","c":[{"t":3,"p":1,"n":"PKC2 - Index"}]},{"t":8,"p":1,"n":"Flags Override","c":[{"t":6,"p":1,"n":"PFO2 - Data","c":[{"t":3,"p":1,"n":"Set General Flags"},{"t":3,"p":1,"n":"Clear General Flags"},{"t":3,"p":1,"n":"Set Interrupt Flags"},{"t":3,"p":1,"n":"Clear Interrupt Flags"},{"t":3,"p":1,"n":"Preferred Speed Override"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Unknown","c":[{"t":11,"n":"PFOR - Unknown"}]}]}]}]},{"t":8,"s":1,"p":1,"n":"Data Inputs","d":1,"c":[{"t":6,"p":1,"n":"Data Input","c":[{"t":3,"p":1,"n":"UNAM - Index"},{"t":2,"p":1,"n":"BNAM - Name"},{"t":3,"p":1,"n":"PNAM - Flags"}]}]},{"t":6,"s":1,"p":1,"n":"OnBegin","c":[{"p":1,"n":"POBA - OnBegin Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":11,"n":"SCHR - Unused"},{"t":11,"n":"SCTX - Unused"},{"t":11,"n":"QNAM - Unused"},{"t":11,"n":"TNAM - Unused"},{"t":8,"p":1,"n":"Topic","c":[{"t":6,"p":1,"n":"PDTO - Topic Data","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Topic"},{"t":2,"p":1,"n":"Subtype"}]}]}]},{"t":6,"s":1,"p":1,"n":"OnEnd","c":[{"p":1,"n":"POEA - OnEnd Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":11,"n":"SCHR - Unused"},{"t":11,"n":"SCTX - Unused"},{"t":11,"n":"QNAM - Unused"},{"t":11,"n":"TNAM - Unused"},{"t":8,"p":1,"n":"Topic","c":[{"t":6,"p":1,"n":"PDTO - Topic Data","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Topic"},{"t":2,"p":1,"n":"Subtype"}]}]}]},{"t":6,"s":1,"p":1,"n":"OnChange","c":[{"p":1,"n":"POCA - OnChange Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":11,"n":"SCHR - Unused"},{"t":11,"n":"SCDA - Unused"},{"t":11,"n":"SCTX - Unused"},{"t":11,"n":"QNAM - Unused"},{"t":11,"n":"TNAM - Unused"},{"t":8,"p":1,"n":"Topic","c":[{"t":6,"p":1,"n":"PDTO - Topic Data","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Topic"},{"t":2,"p":1,"n":"Subtype"}]}]}]}]},{"t":1,"p":1,"n":"PARW - Placed Arrow","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Projectile"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"PBAR - Placed Barrier","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Projectile"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"PBEA - Placed Beam","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Projectile"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"PCON - Placed Cone\/Voice","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Projectile"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"PERK - Perk","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]},{"t":6,"p":1,"n":"Script Fragments","c":[{"t":3,"n":"Unknown"},{"t":2,"p":1,"n":"fileName"},{"t":7,"p":1,"n":"Fragments","c":[{"t":6,"p":1,"n":"Fragment","c":[{"t":3,"p":1,"n":"Fragment Index"},{"t":3,"n":"Unknown"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]}]}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Trait"},{"t":3,"p":1,"n":"Level"},{"t":3,"p":1,"n":"Num Ranks"},{"t":3,"p":1,"n":"Playable"},{"t":3,"p":1,"n":"Hidden"}]},{"t":3,"p":1,"n":"NNAM - Next Perk"},{"t":10,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":6,"p":1,"n":"PRKE - Header","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Rank"},{"t":3,"p":1,"n":"Priority"}]},{"t":6,"p":1,"n":"Quest + Stage","c":[{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Quest Stage"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"Ability"},{"t":6,"p":1,"n":"Entry Point","c":[{"t":3,"p":1,"n":"Entry Point"},{"t":3,"p":1,"n":"Function"},{"t":3,"p":1,"n":"Perk Condition Tab Count"}]},{"t":10,"p":1,"n":"Perk Conditions","c":[{"t":6,"p":1,"n":"Perk Condition","c":[{"t":3,"p":1,"n":"PRKC - Run On (Tab Index)"},{"t":8,"s":1,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"p":1,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]},{"t":6,"p":1,"n":"Function Parameters","c":[{"t":3,"p":1,"n":"EPFT - Type"},{"t":2,"p":1,"n":"EPF2 - Button Label"},{"t":6,"p":1,"n":"EPF3 - Script Flags","c":[{"t":3,"p":1,"n":"Script Flags"},{"t":11,"n":"Unknown"}]},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"Float"},{"t":6,"p":1,"n":"Float, Float","c":[{"t":5,"p":1,"n":"Float 1"},{"t":5,"p":1,"n":"Float 2"}]},{"t":3,"p":1,"n":"Leveled Item"},{"t":3,"p":1,"n":"Spell"},{"t":2,"p":1,"n":"Text"},{"t":6,"p":1,"n":"Actor Value, Float","c":[{"t":3,"p":1,"n":"Actor Value"},{"t":5,"p":1,"n":"Float"}]}]},{"p":1,"n":"PRKF - End Marker"}]}]}]},{"t":1,"p":1,"n":"PFLA - Placed Flame","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Projectile"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"PGRE - Placed Projectile","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Projectile"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"PHZD - Placed Hazard","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Projectile"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"PMIS - Placed Missile","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Projectile"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"PROJ - Projectile","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Type"},{"t":5,"p":1,"n":"Gravity"},{"t":5,"p":1,"n":"Speed"},{"t":5,"p":1,"n":"Range"},{"t":3,"p":1,"n":"Light"},{"t":3,"p":1,"n":"Muzzle Flash - Light"},{"t":5,"p":1,"n":"Tracer Chance"},{"t":5,"p":1,"n":"Explosion - Alt. Trigger - Proximity"},{"t":5,"p":1,"n":"Explosion - Alt. Trigger - Timer"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Sound"},{"t":5,"p":1,"n":"Muzzle Flash - Duration"},{"t":5,"p":1,"n":"Fade Duration"},{"t":5,"p":1,"n":"Impact Force"},{"t":3,"p":1,"n":"Sound - Countdown"},{"t":3,"p":1,"n":"Sound - Disable"},{"t":3,"p":1,"n":"Default Weapon Source"},{"t":5,"p":1,"n":"Cone Spread"},{"t":5,"p":1,"n":"Collision Radius"},{"t":5,"p":1,"n":"Lifetime"},{"t":5,"p":1,"n":"Relaunch Interval"},{"t":3,"p":1,"n":"Decal Data"},{"t":3,"p":1,"n":"Collision Layer"}]},{"t":6,"s":1,"p":1,"n":"Muzzle Flash Model","c":[{"t":2,"p":1,"n":"NAM1 - Model Filename"},{"t":11,"p":1,"n":"NAM2 - Texture Files Hashes"}]},{"t":3,"p":1,"n":"VNAM - Sound Level"}]},{"t":1,"p":1,"n":"PWAT","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"}]},{"t":1,"p":1,"n":"QUST - Quest","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]},{"t":6,"p":1,"n":"Script Fragments","c":[{"t":3,"n":"Unknown"},{"t":3,"p":1,"n":"fragmentCount"},{"t":2,"p":1,"n":"fileName"},{"t":7,"p":1,"n":"Fragments","c":[{"t":6,"p":1,"n":"Fragment","c":[{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"n":"Unknown"},{"t":3,"p":1,"n":"Quest Stage Index"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]}]},{"t":7,"p":1,"n":"Aliases","c":[{"t":6,"p":1,"n":"Alias","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Alias Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]}]}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"DNAM - General","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Priority"},{"t":3,"p":1,"n":"Form Version"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Type"}]},{"t":2,"p":1,"n":"ENAM - Event"},{"t":8,"s":1,"p":1,"n":"Text Display Globals","d":1,"c":[{"t":3,"p":1,"n":"QTGL - Global"}]},{"t":2,"p":1,"n":"FLTR - Object Window Filter"},{"t":6,"s":1,"p":1,"n":"Quest Dialogue Conditions","c":[{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]},{"p":1,"n":"NEXT - Marker"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":10,"s":1,"p":1,"n":"Stages","d":1,"c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"INDX - Stage Index","c":[{"t":3,"p":1,"n":"Stage Index"},{"t":3,"p":1,"n":"Flags"},{"t":3,"n":"Unknown"}]},{"t":8,"p":1,"n":"Log Entries","c":[{"t":6,"p":1,"n":"Log Entry","c":[{"t":3,"p":1,"n":"QSDT - Stage Flags"},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":2,"p":1,"n":"CNAM - Log Entry"},{"t":3,"p":1,"n":"NAM0 - Next Quest"},{"t":11,"n":"SCHR - Unused"},{"t":11,"n":"SCTX - Unused"},{"t":11,"n":"QNAM - Unused"}]}]}]}]},{"t":8,"s":1,"p":1,"n":"Objectives","d":1,"c":[{"t":6,"p":1,"n":"Objective","c":[{"t":3,"p":1,"n":"QOBJ - Objective Index"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":2,"p":1,"n":"NNAM - Display Text"},{"t":8,"p":1,"n":"Targets","c":[{"t":6,"p":1,"n":"Target","c":[{"t":6,"p":1,"n":"QSTA - Target","c":[{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]}]}]},{"t":11,"n":"ANAM - Aliases Marker"},{"t":8,"s":1,"p":1,"n":"Aliases","d":1,"c":[{"t":6,"p":1,"n":"Alias","c":[{"t":3,"p":1,"n":"ALST - Reference Alias ID"},{"t":2,"p":1,"n":"ALID - Alias Name"},{"t":6,"p":1,"n":"FNAM - Alias Flags","c":[{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Additional Flags"}]},{"t":3,"p":1,"n":"ALFI - Force Into Alias When Filled"},{"t":3,"p":1,"n":"ALFL - Specific Location"},{"t":3,"p":1,"n":"ALFR - Forced Reference"},{"t":3,"p":1,"n":"ALUA - Unique Actor"},{"t":6,"p":1,"n":"Location Alias Reference","c":[{"t":3,"p":1,"n":"ALFA - Alias"},{"t":3,"p":1,"n":"KNAM - Keyword"},{"t":3,"p":1,"n":"ALRT - Ref Type"}]},{"t":6,"p":1,"n":"External Alias Reference","c":[{"t":3,"p":1,"n":"ALEQ - Quest"},{"t":3,"p":1,"n":"ALEA - Alias"}]},{"t":6,"p":1,"n":"Create Reference to Object","c":[{"t":3,"p":1,"n":"ALCO - Object"},{"t":6,"p":1,"n":"ALCA - Alias","c":[{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Create"}]},{"t":3,"p":1,"n":"ALCL - Level"}]},{"t":6,"p":1,"n":"Find Matching Reference Near Alias","c":[{"t":3,"p":1,"n":"ALNA - Alias"},{"t":3,"p":1,"n":"ALNT - Type"}]},{"t":6,"p":1,"n":"Find Matching Reference From Event","c":[{"t":2,"p":1,"n":"ALFE - From Event"},{"t":11,"p":1,"n":"ALFD - Event Data"}]},{"t":8,"s":1,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":3,"p":1,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":3,"p":1,"n":"COCT - Count"},{"t":10,"p":1,"n":"Items","c":[{"t":6,"p":1,"n":"Item","c":[{"t":6,"p":1,"n":"CNTO - Item","c":[{"t":3,"p":1,"n":"Item"},{"t":3,"p":1,"n":"Count"}]},{"t":6,"p":1,"n":"COED - Extra Data","c":[{"t":3,"p":1,"n":"Owner"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Global Variable"},{"t":3,"p":1,"n":"Required Rank"},{"t":5,"p":1,"n":"Item Condition"}]}]}]},{"t":3,"p":1,"n":"SPOR - Spectator override package list"},{"t":3,"p":1,"n":"OCOR - Observe dead body override package list"},{"t":3,"p":1,"n":"GWOR - Guard warn override package list"},{"t":3,"p":1,"n":"ECOR - Combat override package list"},{"t":3,"p":1,"n":"ALDN - Display Name"},{"t":8,"p":1,"n":"Alias Spells","c":[{"t":3,"p":1,"n":"ALSP - Spell"}]},{"t":8,"p":1,"n":"Alias Factions","c":[{"t":3,"p":1,"n":"ALFC - Faction"}]},{"t":8,"p":1,"n":"Alias Package Data","c":[{"t":3,"p":1,"n":"ALPC - Package"}]},{"t":3,"p":1,"n":"VTCK - Voice Types"},{"p":1,"n":"ALED - Alias End"}]}]},{"t":2,"p":1,"n":"NNAM - Description"},{"t":8,"s":1,"p":1,"n":"Targets","d":1,"c":[{"t":6,"p":1,"n":"Target","c":[{"t":6,"p":1,"n":"QSTA - Target","c":[{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"}]},{"t":8,"s":1,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]}]},{"t":1,"p":1,"n":"RACE - Race","c":[{"t":2,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"DESC - Description"},{"t":3,"n":"SPCT - Count"},{"t":8,"s":1,"p":1,"n":"Actor Effects","c":[{"t":3,"p":1,"n":"SPLO - Actor Effect"}]},{"t":3,"p":1,"n":"WNAM - Skin"},{"t":6,"s":1,"p":1,"n":"BOD2 - Biped Body Template","c":[{"t":3,"p":1,"n":"First Person Flags"},{"t":3,"p":1,"n":"General Flags"},{"n":"Unused"},{"t":3,"p":1,"n":"Armor Type"}]},{"t":6,"s":1,"p":1,"n":"BODT - Body Template","c":[{"t":3,"p":1,"n":"First Person Flags"},{"t":3,"p":1,"n":"General Flags"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Armor Type"}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":7,"p":1,"n":"Skill Boosts","c":[{"t":6,"p":1,"n":"Skill Boost","c":[{"t":3,"p":1,"n":"Skill"},{"t":3,"p":1,"n":"Boost"}]}]},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"Male Height"},{"t":5,"p":1,"n":"Female Height"},{"t":5,"p":1,"n":"Male Weight"},{"t":5,"p":1,"n":"Female Weight"},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Starting Health"},{"t":5,"p":1,"n":"Starting Magicka"},{"t":5,"p":1,"n":"Starting Stamina"},{"t":5,"p":1,"n":"Base Carry Weight"},{"t":5,"p":1,"n":"Base Mass"},{"t":5,"p":1,"n":"Acceleration rate"},{"t":5,"p":1,"n":"Deceleration rate"},{"t":3,"p":1,"n":"Size"},{"t":3,"p":1,"n":"Head Biped Object"},{"t":3,"p":1,"n":"Hair Biped Object"},{"t":5,"p":1,"n":"Injured Health Pct"},{"t":3,"p":1,"n":"Shield Biped Object"},{"t":5,"p":1,"n":"Health Regen"},{"t":5,"p":1,"n":"Magicka Regen"},{"t":5,"p":1,"n":"Stamina Regen"},{"t":5,"p":1,"n":"Unarmed Damage"},{"t":5,"p":1,"n":"Unarmed Reach"},{"t":3,"p":1,"n":"Body Biped Object"},{"t":5,"p":1,"n":"Aim Angle Tolerance"},{"t":5,"p":1,"n":"Flight Radius"},{"t":5,"p":1,"n":"Angular Acceleration Rate"},{"t":5,"p":1,"n":"Angular Tolerance"},{"t":3,"p":1,"n":"Flags 2"},{"t":6,"p":1,"n":"Mount Data","c":[{"t":5,"p":1,"n":"Offset X"},{"t":5,"p":1,"n":"Offset Y"},{"t":5,"p":1,"n":"Unknown"}]}]},{"p":1,"n":"MNAM - Male Marker"},{"t":2,"p":1,"n":"ANAM - Male Skeletal Model"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"p":1,"n":"FNAM - Female Marker"},{"t":2,"p":1,"n":"ANAM - Female Skeletal Model"},{"p":1,"n":"NAM2 - Marker NAM2 #1"},{"t":8,"p":1,"n":"Movement Type Names","c":[{"t":2,"p":1,"n":"MTNM - Name"}]},{"t":7,"p":1,"n":"VTCK - Voices","c":[{"t":3,"p":1,"n":"Voice"}]},{"t":7,"p":1,"n":"DNAM - Decapitate Armors","c":[{"t":3,"p":1,"n":"Decapitate Armor"}]},{"t":7,"p":1,"n":"HCLF - Default Hair Colors","c":[{"t":3,"p":1,"n":"Default Hair Color"}]},{"t":3,"n":"TINL - Total Number of Tints in List"},{"t":5,"p":1,"n":"PNAM - FaceGen - Main clamp"},{"t":5,"p":1,"n":"UNAM - FaceGen - Face clamp"},{"t":3,"p":1,"n":"ATKR - Attack Race"},{"t":10,"p":1,"n":"Attacks","c":[{"t":6,"p":1,"n":"Attack","c":[{"t":6,"p":1,"n":"ATKD - Attack Data","c":[{"t":5,"p":1,"n":"Damage Mult"},{"t":5,"p":1,"n":"Attack Chance"},{"t":3,"p":1,"n":"Attack Spell"},{"t":3,"p":1,"n":"Attack Flags"},{"t":5,"p":1,"n":"Attack Angle"},{"t":5,"p":1,"n":"Strike Angle"},{"t":5,"p":1,"n":"Stagger"},{"t":3,"p":1,"n":"Attack Type"},{"t":5,"p":1,"n":"Knockdown"},{"t":5,"p":1,"n":"Recovery Time"},{"t":5,"p":1,"n":"Stamina Mult"}]},{"t":2,"p":1,"n":"ATKE - Attack Event"}]}]},{"t":6,"p":1,"n":"Body Data","c":[{"n":"NAM1 - Body Data Marker"},{"t":6,"p":1,"n":"Male Body Data","c":[{"n":"MNAM - Male Data Marker"},{"t":10,"s":1,"p":1,"n":"Parts","d":1,"c":[{"t":6,"p":1,"n":"Part","c":[{"t":3,"p":1,"n":"INDX - Index"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]}]}]}]},{"t":6,"p":1,"n":"Female Body Data","c":[{"n":"FNAM - Female Data Marker"},{"t":10,"s":1,"p":1,"n":"Parts","d":1,"c":[{"t":6,"p":1,"n":"Part","c":[{"t":3,"p":1,"n":"INDX - Index"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]}]}]}]}]},{"t":7,"p":1,"n":"HNAM - Hairs","c":[{"t":3,"p":1,"n":"Hair"}]},{"t":7,"p":1,"n":"ENAM - Eyes","c":[{"t":3,"p":1,"n":"Eye"}]},{"t":3,"p":1,"n":"GNAM - Body Part Data"},{"p":1,"n":"NAM2 - Marker NAM2 #2"},{"p":1,"n":"NAM3 - Marker NAM3 #3"},{"t":6,"s":1,"p":1,"n":"Male Behavior Graph","c":[{"p":1,"n":"MNAM - Male Data Marker"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]}]},{"t":6,"s":1,"p":1,"n":"Female Behavior Graph","c":[{"p":1,"n":"FNAM - Female Data Marker"},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]}]},{"t":3,"p":1,"n":"NAM4 - Material Type"},{"t":3,"p":1,"n":"NAM5 - Impact Data Set"},{"t":3,"p":1,"n":"NAM7 - Decapitation FX"},{"t":3,"p":1,"n":"ONAM - Open Loot Sound"},{"t":3,"p":1,"n":"LNAM - Close Loot Sound"},{"t":8,"p":1,"n":"Biped Object Names","c":[{"t":2,"p":1,"n":"NAME - Name"}]},{"t":10,"n":"Movement Types","c":[{"t":6,"n":"Movement Types","c":[{"t":3,"n":"MTYP - Movement Type"},{"t":6,"n":"SPED - Override Values","c":[{"t":5,"n":"Left - Walk"},{"t":5,"n":"Left - Run"},{"t":5,"n":"Right - Walk"},{"t":5,"n":"Right - Run"},{"t":5,"n":"Forward - Walk"},{"t":5,"n":"Forward - Run"},{"t":5,"n":"Back - Walk"},{"t":5,"n":"Back - Run"},{"t":5,"n":"Rotate - Walk"},{"t":5,"n":"Unknown"}]}]}]},{"t":3,"n":"VNAM - Equipment Flags"},{"t":8,"p":1,"n":"Equip Slots","c":[{"t":3,"p":1,"n":"QNAM - Equip Slot"}]},{"t":3,"n":"UNES - Unarmed Equip Slot"},{"t":8,"n":"Phoneme Target Names","c":[{"t":2,"n":"PHTN - Name"}]},{"t":6,"n":"FaceFX Phonemes","c":[{"t":6,"n":"IY","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"IH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"EH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"EY","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"AE","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"AA","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"AW","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"AY","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"AH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"AO","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"OY","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"OW","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"UH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"UW","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"ER","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"AX","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"S","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"SH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"Z","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"ZH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"F","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"TH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"V","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"DH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"M","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"N","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"NG","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"L","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"R","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"W","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"Y","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"HH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"B","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"D","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"JH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"G","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"P","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"T","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"K","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"CH","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"SIL","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"SHOTSIL","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]},{"t":6,"n":"FLAP","c":[{"t":6,"n":"PHWT - Phoneme Target Weight","c":[{"t":5,"n":"Aah \/ LipBigAah"},{"t":5,"n":"BigAah \/ LipDST"},{"t":5,"n":"BMP \/ LipEee"},{"t":5,"n":"ChJsh \/ LipFV"},{"t":5,"n":"DST \/ LipK"},{"t":5,"n":"Eee \/ LipL"},{"t":5,"n":"Eh \/ LipR"},{"t":5,"n":"FV \/ LipTh"},{"t":5,"n":"I"},{"t":5,"n":"K"},{"t":5,"n":"N"},{"t":5,"n":"Oh"},{"t":5,"n":"OohQ"},{"t":5,"n":"R"},{"t":5,"n":"TH"},{"t":5,"n":"W"}]}]}]},{"t":3,"n":"WKMV - Base Movement Default - Walk"},{"t":3,"n":"RNMV - Base Movement Default - Run"},{"t":3,"n":"SWMV - Base Movement Default - Swim"},{"t":3,"n":"FLMV - Base Movement Default - Fly"},{"t":3,"n":"SNMV - Base Movement Default - Sneak"},{"t":3,"n":"SPMV - Base Movement Default - Sprint"},{"t":6,"p":1,"n":"Head Data","c":[{"n":"NAM0 - Head Data Marker"},{"t":6,"s":1,"p":1,"n":"Male Head Data","c":[{"p":1,"n":"MNAM - Male Data Marker"},{"t":10,"p":1,"n":"Head Parts","c":[{"t":6,"p":1,"n":"Head Part","c":[{"t":3,"p":1,"n":"INDX - Head Part Number"},{"t":3,"p":1,"n":"HEAD - Head"}]}]},{"t":6,"n":"Available Morphs","c":[{"t":11,"n":"MPAI - Unknown"},{"t":6,"n":"MPAV - Nose Variants","c":[{"t":3,"n":"Nose Morph Flags"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"MPAV - Brow Variants","c":[{"t":3,"n":"Brow Morph Flags"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"MPAV - Eye Variants","c":[{"t":3,"n":"Eye Morph Flags 1"},{"t":3,"n":"Eye Morph Flags 2"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"MPAV - Lip Variants","c":[{"t":3,"n":"Lip Morph Flags"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Race Presets Male","c":[{"t":3,"n":"RPRM - Preset NPC"}]},{"t":8,"n":"Available Hair Colors Male","c":[{"t":3,"n":"AHCM - Hair Color"}]},{"t":8,"n":"Face Details Texture Set List Male","c":[{"t":3,"n":"FTSM - Texture Set"}]},{"t":3,"n":"DFTM - Default Face Texture Male"},{"t":8,"p":1,"n":"Tint Masks","c":[{"t":6,"p":1,"n":"Tint Assets","c":[{"t":8,"p":1,"n":"Tint Layer","c":[{"t":6,"p":1,"n":"Texture","c":[{"t":3,"p":1,"n":"TINI - Index"},{"t":2,"p":1,"n":"TINT - File Name"},{"t":3,"p":1,"n":"TINP - Mask Type"},{"t":3,"p":1,"n":"TIND - Preset Default"}]}]},{"t":8,"p":1,"n":"Presets","c":[{"t":6,"p":1,"n":"Preset","c":[{"t":3,"p":1,"n":"TINC - Color"},{"t":5,"p":1,"n":"TINV - Default Value"},{"t":3,"p":1,"n":"TIRS - Index"}]}]}]}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]}]},{"t":6,"s":1,"p":1,"n":"Female Head Data","c":[{"p":1,"n":"NAM0 - Head Data Marker"},{"p":1,"n":"FNAM - Female Data Marker"},{"t":10,"p":1,"n":"Head Parts","c":[{"t":6,"p":1,"n":"Head Part","c":[{"t":3,"p":1,"n":"INDX - Head Part Number"},{"t":3,"p":1,"n":"HEAD - Head"}]}]},{"t":6,"n":"Available Morphs","c":[{"t":11,"n":"MPAI - Unknown"},{"t":6,"n":"MPAV - Nose Variants","c":[{"t":3,"n":"Nose Morph Flags"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"MPAV - Brow Variants","c":[{"t":3,"n":"Brow Morph Flags"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"MPAV - Eye Variants","c":[{"t":3,"n":"Eye Morph Flags 1"},{"t":3,"n":"Eye Morph Flags 2"},{"t":11,"n":"Unknown"}]},{"t":6,"n":"MPAV - Lip Variants","c":[{"t":3,"n":"Lip Morph Flags"},{"t":11,"n":"Unknown"}]}]},{"t":8,"n":"Race Presets Female","c":[{"t":3,"n":"RPRF - Preset NPC"}]},{"t":8,"n":"Available Hair Colors Female","c":[{"t":3,"n":"AHCF - Hair Color"}]},{"t":8,"n":"Face Details Texture Set List Female","c":[{"t":3,"n":"FTSF - Texture Set"}]},{"t":3,"n":"DFTF - Default Face Texture Female"},{"t":8,"p":1,"n":"Tint Masks","c":[{"t":6,"p":1,"n":"Tint Assets","c":[{"t":8,"p":1,"n":"Tint Layer","c":[{"t":6,"p":1,"n":"Texture","c":[{"t":3,"p":1,"n":"TINI - Index"},{"t":2,"p":1,"n":"TINT - File Name"},{"t":3,"p":1,"n":"TINP - Mask Type"},{"t":3,"p":1,"n":"TIND - Preset Default"}]}]},{"t":8,"p":1,"n":"Presets","c":[{"t":6,"p":1,"n":"Preset","c":[{"t":3,"p":1,"n":"TINC - Color"},{"t":5,"p":1,"n":"TINV - Default Value"},{"t":3,"p":1,"n":"TIRS - Index"}]}]}]}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]}]}]},{"t":3,"n":"NAM8 - Morph race"},{"t":3,"n":"RNAM - Armor race"}]},{"t":1,"p":1,"n":"REFR - Placed Object","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Base"},{"t":6,"s":1,"p":1,"n":"XMBO - Bound Half Extents","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"s":1,"p":1,"n":"XPRM - Primitive","c":[{"t":6,"p":1,"n":"Bounds","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Color","c":[{"t":5,"p":1,"n":"Red"},{"t":5,"p":1,"n":"Green"},{"t":5,"p":1,"n":"Blue"}]},{"t":5,"n":"Unknown"},{"t":3,"p":1,"n":"Type"}]},{"t":11,"n":"XORD - Unknown"},{"t":6,"s":1,"p":1,"n":"XOCP - Occlusion Plane Data","c":[{"t":6,"p":1,"n":"Size","c":[{"t":5,"p":1,"n":"Width"},{"t":5,"p":1,"n":"Height"}]},{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation (Quaternion?)","c":[{"t":5,"p":1,"n":"q1"},{"t":5,"p":1,"n":"q2"},{"t":5,"p":1,"n":"q3"},{"t":5,"p":1,"n":"q4"}]}]},{"t":7,"p":1,"n":"XPOD - Portal Data","c":[{"t":6,"p":1,"n":"References","c":[{"t":3,"p":1,"n":"Origin"},{"t":3,"p":1,"n":"Destination"}]}]},{"t":6,"s":1,"p":1,"n":"XPTL - Room Portal (unused)","c":[{"t":6,"p":1,"n":"Size","c":[{"t":5,"p":1,"n":"Width"},{"t":5,"p":1,"n":"Height"}]},{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation (Quaternion?)","c":[{"t":5,"p":1,"n":"q1"},{"t":5,"p":1,"n":"q2"},{"t":5,"p":1,"n":"q3"},{"t":5,"p":1,"n":"q4"}]}]},{"t":6,"s":1,"p":1,"n":"Bound Data","c":[{"t":6,"p":1,"n":"XRMR - Header","c":[{"t":3,"p":1,"n":"Linked Rooms Count"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"}]},{"t":3,"p":1,"n":"LNAM - Lighting Template"},{"t":3,"p":1,"n":"INAM - Image Space"},{"t":8,"p":1,"n":"Linked Rooms","c":[{"t":3,"p":1,"n":"XLRM - Linked Room"}]}]},{"p":1,"n":"XMBP - MultiBound Primitive Marker"},{"t":11,"n":"XRGD - Ragdoll Data"},{"t":11,"n":"XRGB - Ragdoll Biped Data"},{"t":5,"p":1,"n":"XRDS - Radius"},{"t":8,"s":1,"p":1,"n":"Reflected\/Refracted By","d":1,"c":[{"t":6,"p":1,"n":"XPWR - Water","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Lit Water","d":1,"c":[{"t":3,"p":1,"n":"XLTW - Water"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":6,"s":1,"p":1,"n":"XLIG - Light Data","c":[{"t":5,"p":1,"n":"FOV 90+\/-"},{"t":5,"p":1,"n":"Fade 1.35+\/-"},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"Shadow Depth Bias"}]},{"t":6,"s":1,"p":1,"n":"XALP - Alpha","c":[{"t":3,"p":1,"n":"Cutoff"},{"t":3,"p":1,"n":"Base"}]},{"t":6,"s":1,"p":1,"n":"XTEL - Teleport Destination","c":[{"t":3,"p":1,"n":"Door"},{"t":6,"p":1,"n":"Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]},{"t":3,"p":1,"n":"Flags"}]},{"t":3,"p":1,"n":"XTNM - Teleport Message Box"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"t":11,"n":"XWCN - Unknown"},{"t":11,"n":"XWCS - Unknown"},{"t":6,"s":1,"p":1,"n":"XWCU - Water Velocity","c":[{"t":5,"p":1,"n":"X Offset"},{"t":5,"p":1,"n":"Y Offset"},{"t":5,"p":1,"n":"Z Offset"},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"X Angle"},{"t":5,"p":1,"n":"Y Angle"},{"t":5,"p":1,"n":"Z Angle"}]},{"t":6,"n":"XCVL - Unknown","c":[{"t":11,"n":"Unknown"},{"t":5,"n":"X Angle"}]},{"t":3,"n":"XCZR - Unknown"},{"t":11,"n":"XCZA - Unknown"},{"t":3,"n":"XCZC - Unknown"},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":3,"p":1,"n":"XSPC - Spawn Container"},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":3,"p":1,"n":"XLIB - Leveled Item Base Object"},{"t":3,"p":1,"n":"XLCM - Level Modifier"},{"t":3,"p":1,"n":"XLCN - Persistent Location"},{"t":3,"p":1,"n":"XTRI - Collision Layer"},{"t":6,"s":1,"p":1,"n":"XLOC - Lock Data","c":[{"t":3,"p":1,"n":"Level"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Key"},{"t":3,"p":1,"n":"Flags"}]},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":6,"s":1,"p":1,"n":"XNDP - Navigation Door Link","c":[{"t":3,"p":1,"n":"Navigation Mesh"},{"t":3,"p":1,"n":"Teleport Marker Triangle"},{"t":11,"n":"Unused"}]},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":3,"p":1,"n":"XCNT - Item Count"},{"t":5,"p":1,"n":"XCHG - Charge"},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":8,"s":1,"p":1,"n":"Patrol","d":1,"c":[{"t":6,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"XPRD - Idle Time"},{"p":1,"n":"XPPA - Patrol Script Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":11,"n":"SCHR - Unused"},{"t":11,"n":"SCTX - Unused"},{"t":8,"p":1,"n":"Topic","c":[{"t":6,"p":1,"n":"PDTO - Topic Data","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Topic"},{"t":2,"p":1,"n":"Subtype"}]}]}]}]},{"t":3,"p":1,"n":"XACT - Action Flag"},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"p":1,"n":"ONAM - Open by Default"},{"t":6,"s":1,"p":1,"n":"Map Marker","c":[{"p":1,"n":"XMRK - Map Marker Data"},{"t":3,"p":1,"n":"FNAM - Map Flags"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"p":1,"n":"TNAM - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"}]}]},{"t":3,"p":1,"n":"XATR - Attach Ref"},{"t":7,"n":"XLOD - Distant LOD Data","c":[{"t":5,"n":"Unknown"}]},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]},{"t":1,"p":1,"n":"REGN - Region","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"RCLR - Map Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unknown"}]},{"t":3,"p":1,"n":"WNAM - Worldspace"},{"t":8,"s":1,"p":1,"n":"Region Areas","d":1,"c":[{"t":6,"p":1,"n":"Region Area","c":[{"t":3,"p":1,"n":"RPLI - Edge Fall-off"},{"t":7,"p":1,"n":"RPLD - Region Point List Data","c":[{"t":6,"p":1,"n":"Point","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"}]}]}]}]},{"t":10,"p":1,"n":"Region Data Entries","d":1,"c":[{"t":6,"p":1,"n":"Region Data Entry","c":[{"t":6,"p":1,"n":"RDAT - Data Header","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Priority"},{"t":11,"n":"Unknown"}]},{"t":6,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":3,"p":1,"n":"RDMO - Music"},{"t":7,"p":1,"n":"RDSA - Sounds","c":[{"t":6,"p":1,"n":"Sound","c":[{"t":3,"p":1,"n":"Sound"},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Chance"}]}]},{"t":2,"p":1,"n":"RDMP - Map Name"},{"t":7,"p":1,"n":"RDOT - Objects","c":[{"t":6,"p":1,"n":"Object","c":[{"t":3,"p":1,"n":"Object"},{"t":3,"p":1,"n":"Parent Index"},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"Density"},{"t":3,"p":1,"n":"Clustering"},{"t":3,"p":1,"n":"Min Slope"},{"t":3,"p":1,"n":"Max Slope"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Radius wrt Parent"},{"t":3,"p":1,"n":"Radius"},{"t":5,"p":1,"n":"Min Height"},{"t":5,"p":1,"n":"Max Height"},{"t":5,"p":1,"n":"Sink"},{"t":5,"p":1,"n":"Sink Variance"},{"t":5,"p":1,"n":"Size Variance"},{"t":6,"p":1,"n":"Angle Variance","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"},{"t":3,"p":1,"n":"Z"}]}]}]},{"t":7,"p":1,"n":"RDGS - Grasses","c":[{"t":6,"p":1,"n":"Grass","c":[{"t":3,"p":1,"n":"Grass"},{"t":11,"n":"Unknown"}]}]},{"t":7,"p":1,"n":"RDWT - Weather Types","c":[{"t":6,"p":1,"n":"Weather Type","c":[{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Chance"},{"t":3,"p":1,"n":"Global"}]}]}]}]}]},{"t":1,"p":1,"n":"RELA - Relationship","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Parent"},{"t":3,"p":1,"n":"Child"},{"t":3,"p":1,"n":"Rank"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Association Type"}]}]},{"t":1,"p":1,"n":"REVB - Reverb Parameters","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Decay Time (ms)"},{"t":3,"p":1,"n":"HF Reference (Hz)"},{"t":3,"p":1,"n":"Room Filter"},{"t":3,"p":1,"n":"Room HF Filter"},{"t":3,"p":1,"n":"Reflections"},{"t":3,"p":1,"n":"Reverb Amp"},{"t":3,"p":1,"n":"Decay HF Ratio"},{"t":3,"p":1,"n":"Reflect Delay (ms), scaled"},{"t":3,"p":1,"n":"Reverb Delay (ms)"},{"t":3,"p":1,"n":"Diffusion %"},{"t":3,"p":1,"n":"Density %"},{"t":3,"n":"Unknown"}]}]},{"t":1,"p":1,"n":"RFCT - Visual Effect","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"DATA - Effect Data","c":[{"t":3,"p":1,"n":"Effect Art"},{"t":3,"p":1,"n":"Shader"},{"t":3,"p":1,"n":"Flags"}]}]},{"t":1,"p":1,"n":"RGDL","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"}]},{"t":1,"p":1,"n":"SCEN - Scene","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]},{"t":6,"p":1,"n":"Script Fragments","c":[{"t":3,"n":"Unknown"},{"t":3,"p":1,"n":"Flags"},{"t":2,"p":1,"n":"fileName"},{"t":7,"p":1,"n":"Fragments","c":[{"t":6,"p":1,"n":"Fragment","c":[{"t":3,"n":"Unknown"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]},{"t":7,"p":1,"n":"Phase Fragments","c":[{"t":6,"p":1,"n":"Phase Fragment","c":[{"t":3,"p":1,"n":"Phase Flag"},{"t":3,"p":1,"n":"Phase Index"},{"t":3,"n":"Unknown"},{"t":2,"p":1,"n":"scriptName"},{"t":2,"p":1,"n":"fragmentName"}]}]}]}]},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":8,"s":1,"p":1,"n":"Phases","d":1,"c":[{"t":6,"p":1,"n":"Phase","c":[{"p":1,"n":"HNAM - Marker Phase Start"},{"t":2,"p":1,"n":"NAM0 - Name"},{"t":6,"p":1,"n":"Start Conditions","c":[{"t":8,"s":1,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]},{"p":1,"n":"NEXT - Marker"},{"t":6,"p":1,"n":"Completion Conditions","c":[{"t":8,"s":1,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]},{"t":6,"n":"Unused","c":[{"t":11,"n":"SCHR - Unknown"},{"t":11,"n":"SCDA - Unknown"},{"t":11,"n":"SCTX - Unknown"},{"t":11,"n":"QNAM - Unknown"},{"t":11,"n":"SCRO - Unknown"}]},{"t":3,"p":1,"n":"WNAM - Editor Width"},{"p":1,"n":"HNAM - Marker Phase End"}]}]},{"t":8,"s":1,"p":1,"n":"Actors","d":1,"c":[{"t":6,"p":1,"n":"Actor","c":[{"t":3,"p":1,"n":"ALID - Actor ID"},{"t":3,"p":1,"n":"LNAM - Flags"},{"t":3,"p":1,"n":"DNAM - Behaviour Flags"}]}]},{"t":8,"s":1,"p":1,"n":"Actions","d":1,"c":[{"t":6,"p":1,"n":"Action","c":[{"t":3,"p":1,"n":"ANAM - Type"},{"t":2,"p":1,"n":"NAM0 - Name"},{"t":3,"p":1,"n":"ALID - Actor ID"},{"t":11,"n":"LNAM - Unknown"},{"t":3,"p":1,"n":"INAM - Index"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":3,"p":1,"n":"SNAM - Start Phase"},{"t":3,"p":1,"n":"ENAM - End Phase"},{"t":5,"p":1,"n":"SNAM - Timer Seconds"},{"t":8,"p":1,"n":"Packages","c":[{"t":3,"p":1,"n":"PNAM - Package"}]},{"t":3,"p":1,"n":"DATA - Topic"},{"t":3,"p":1,"n":"HTID - Headtrack Actor ID"},{"t":5,"p":1,"n":"DMAX - Looping - Max"},{"t":5,"p":1,"n":"DMIN - Looping - Min"},{"t":3,"p":1,"n":"DEMO - Emotion Type"},{"t":3,"p":1,"n":"DEVA - Emotion Value"},{"t":6,"n":"Unused","c":[{"t":11,"n":"SCHR - Unknown"},{"t":11,"n":"SCDA - Unknown"},{"t":11,"n":"SCTX - Unknown"},{"t":11,"n":"QNAM - Unknown"},{"t":11,"n":"SCRO - Unknown"}]},{"p":1,"n":"ANAM - End Marker"}]}]},{"t":6,"n":"Unused","c":[{"t":11,"n":"SCHR - Unknown"},{"t":11,"n":"SCDA - Unknown"},{"t":11,"n":"SCTX - Unknown"},{"t":11,"n":"QNAM - Unknown"},{"t":11,"n":"SCRO - Unknown"}]},{"p":1,"n":"NEXT - Marker"},{"t":3,"p":1,"n":"PNAM - Quest"},{"t":3,"p":1,"n":"INAM - Last Action Index"},{"t":11,"n":"VNAM - Unknown"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]},{"t":1,"p":1,"n":"SCOL","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"}]},{"t":1,"p":1,"n":"SCPT","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"}]},{"t":1,"p":1,"n":"SCRL - Scroll","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":3,"p":1,"n":"MDOB - Menu Display Object"},{"t":3,"p":1,"n":"ETYP - Equipment Type"},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":6,"s":1,"p":1,"n":"DATA - Item","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":6,"s":1,"p":1,"n":"SPIT - Data","c":[{"t":3,"p":1,"n":"Base Cost"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Type"},{"t":5,"p":1,"n":"Charge Time"},{"t":3,"p":1,"n":"Cast Type"},{"t":3,"p":1,"n":"Target Type"},{"t":5,"p":1,"n":"Cast Duration"},{"t":5,"p":1,"n":"Range"},{"t":3,"p":1,"n":"Half-cost Perk"}]},{"t":8,"s":1,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":3,"p":1,"n":"EFID - Base Effect"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":5,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"}]},{"t":8,"s":1,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]}]},{"t":1,"p":1,"n":"SHOU - Shout","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"MDOB - Menu Display Object"},{"t":2,"p":1,"n":"DESC - Description"},{"t":8,"s":1,"p":1,"n":"Words of Power","d":1,"c":[{"t":6,"p":1,"n":"SNAM - ","c":[{"t":3,"p":1,"n":"Word"},{"t":3,"p":1,"n":"Spell"},{"t":5,"p":1,"n":"Recovery Time"}]}]}]},{"t":1,"p":1,"n":"SLGM - Soul Gem","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":6,"s":1,"p":1,"n":"DATA - ","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"}]},{"t":3,"p":1,"n":"SOUL - Contained Soul"},{"t":3,"p":1,"n":"SLCP - Maximum Capacity"},{"t":3,"p":1,"n":"NAM0 - Linked To"}]},{"t":1,"p":1,"n":"SMBN - Story Manager Branch Node","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"PNAM - Parent "},{"t":3,"p":1,"n":"SNAM - Child "},{"t":3,"n":"CITC - Condition Count"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":3,"p":1,"n":"DNAM - Flags"},{"t":11,"n":"XNAM - Unknown"}]},{"t":1,"p":1,"n":"SMEN - Story Manager Event Node","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"PNAM - Parent "},{"t":3,"p":1,"n":"SNAM - Child "},{"t":3,"n":"CITC - Condition Count"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":3,"p":1,"n":"DNAM - Flags"},{"t":11,"n":"XNAM - Unknown"},{"t":2,"p":1,"n":"ENAM - Type"}]},{"t":1,"p":1,"n":"SMQN - Story Manager Quest Node","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"PNAM - Parent "},{"t":3,"p":1,"n":"SNAM - Child "},{"t":3,"n":"CITC - Condition Count"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":6,"s":1,"p":1,"n":"DNAM - Flags","c":[{"t":3,"p":1,"n":"Node Flags"},{"t":3,"p":1,"n":"Quest Flags"}]},{"t":3,"p":1,"n":"XNAM - Max concurrent quests"},{"t":3,"p":1,"n":"MNAM - Num quests to run"},{"t":3,"n":"QNAM - Quest Count"},{"t":10,"p":1,"n":"Quests","d":1,"c":[{"t":6,"p":1,"n":"Quest","c":[{"t":3,"p":1,"n":"NNAM - Quest"},{"t":11,"n":"FNAM - Unknown"},{"t":5,"p":1,"n":"RNAM - Hours until reset"}]}]}]},{"t":1,"p":1,"n":"SNCT - Sound Category","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":3,"p":1,"n":"PNAM - Parent"},{"t":3,"p":1,"n":"VNAM - Static Volume Multiplier"},{"t":3,"p":1,"n":"UNAM - Default Menu Value"}]},{"t":1,"p":1,"n":"SNDR - Sound Descriptor","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":11,"n":"CNAM - Unknown"},{"t":3,"p":1,"n":"GNAM - Category"},{"t":3,"p":1,"n":"SNAM - Alternate Sound For"},{"t":8,"s":1,"p":1,"n":"Sounds","d":1,"c":[{"t":6,"p":1,"n":"Sound Files","c":[{"t":2,"p":1,"n":"ANAM - File Name"}]}]},{"t":3,"p":1,"n":"ONAM - Output Model"},{"t":2,"p":1,"n":"FNAM - String"},{"t":8,"s":1,"p":1,"n":"Conditions","d":1,"c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]},{"t":6,"s":1,"p":1,"n":"LNAM - Values","c":[{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Looping"},{"t":3,"p":1,"n":"Rumble Send Value = (Small \/ 7) + ((Big \/ 7) * 16)"}]},{"t":6,"s":1,"p":1,"n":"BNAM - Values","c":[{"t":3,"p":1,"n":"% Frequency Shift"},{"t":3,"p":1,"n":"% Frequency Variance"},{"t":3,"p":1,"n":"Priority"},{"t":3,"p":1,"n":"db Variance"},{"t":3,"p":1,"n":"Static Attenuation (db)"}]}]},{"t":1,"p":1,"n":"SOPM - Sound Output Model","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"NAM1 - Data","c":[{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Reverb Send %"}]},{"t":11,"n":"FNAM - Unknown"},{"t":3,"p":1,"n":"MNAM - Type"},{"t":11,"n":"CNAM - Unknown"},{"t":11,"n":"SNAM - Unknown"},{"t":6,"s":1,"p":1,"n":"ONAM - Output Values","c":[{"t":7,"p":1,"n":"Channels","c":[{"t":6,"p":1,"n":"","c":[{"t":3,"p":1,"n":"L"},{"t":3,"p":1,"n":"R"},{"t":3,"p":1,"n":"C"},{"t":3,"p":1,"n":"LFE"},{"t":3,"p":1,"n":"RL"},{"t":3,"p":1,"n":"RR"},{"t":3,"p":1,"n":"BL"},{"t":3,"p":1,"n":"BR"}]}]}]},{"t":6,"s":1,"p":1,"n":"ANAM - Attenuation Values","c":[{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"Min Distance"},{"t":5,"p":1,"n":"Max Distance"},{"t":7,"p":1,"n":"Curve","c":[{"t":3,"p":1,"n":"Value"}]}]}]},{"t":1,"p":1,"n":"SOUN - Sound Marker","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":11,"n":"FNAM - Unknown"},{"t":11,"n":"SNDD - Unknown"},{"t":3,"p":1,"n":"SDSC - Sound Descriptor"}]},{"t":1,"p":1,"n":"SPEL - Spell","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":3,"p":1,"n":"MDOB - Menu Display Object"},{"t":3,"p":1,"n":"ETYP - Equipment Type"},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"SPIT - Data","c":[{"t":3,"p":1,"n":"Base Cost"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Type"},{"t":5,"p":1,"n":"Charge Time"},{"t":3,"p":1,"n":"Cast Type"},{"t":3,"p":1,"n":"Target Type"},{"t":5,"p":1,"n":"Cast Duration"},{"t":5,"p":1,"n":"Range"},{"t":3,"p":1,"n":"Half-cost Perk"}]},{"t":8,"s":1,"p":1,"n":"Effects","d":1,"c":[{"t":6,"p":1,"n":"Effect","c":[{"t":3,"p":1,"n":"EFID - Base Effect"},{"t":6,"p":1,"n":"EFIT - ","c":[{"t":5,"p":1,"n":"Magnitude"},{"t":3,"p":1,"n":"Area"},{"t":3,"p":1,"n":"Duration"}]},{"t":8,"s":1,"p":1,"n":"Conditions","c":[{"t":6,"p":1,"n":"Condition","c":[{"t":6,"p":1,"n":"CTDA - ","c":[{"t":3,"p":1,"n":"Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Comparison Value - Float"},{"t":3,"p":1,"n":"Comparison Value - Global"},{"t":3,"p":1,"n":"Function"},{"t":11,"n":"Unknown"},{"t":11,"p":1,"n":"None"},{"t":3,"p":1,"n":"Integer"},{"t":5,"p":1,"n":"Float"},{"t":11,"p":1,"n":"Variable Name (unused)"},{"t":3,"p":1,"n":"Sex"},{"t":3,"p":1,"n":"Actor Value"},{"t":3,"p":1,"n":"Crime Type"},{"t":3,"p":1,"n":"Axis"},{"t":3,"p":1,"n":"Quest Stage (unused)"},{"t":3,"p":1,"n":"Misc Stat"},{"t":3,"p":1,"n":"Alignment"},{"t":3,"p":1,"n":"Equip Type"},{"t":3,"p":1,"n":"Form Type"},{"t":3,"p":1,"n":"Critical Stage"},{"t":3,"p":1,"n":"Object Reference"},{"t":3,"p":1,"n":"Inventory Object"},{"t":3,"p":1,"n":"Actor"},{"t":3,"p":1,"n":"Voice Type"},{"t":3,"p":1,"n":"Idle"},{"t":3,"p":1,"n":"Form List"},{"t":3,"p":1,"n":"Quest"},{"t":3,"p":1,"n":"Faction"},{"t":3,"p":1,"n":"Cell"},{"t":3,"p":1,"n":"Class"},{"t":3,"p":1,"n":"Race"},{"t":3,"p":1,"n":"Actor Base"},{"t":3,"p":1,"n":"Global"},{"t":3,"p":1,"n":"Weather"},{"t":3,"p":1,"n":"Package"},{"t":3,"p":1,"n":"Encounter Zone"},{"t":3,"p":1,"n":"Perk"},{"t":3,"p":1,"n":"Owner"},{"t":3,"p":1,"n":"Furniture"},{"t":3,"p":1,"n":"Effect Item"},{"t":3,"p":1,"n":"Base Effect"},{"t":3,"p":1,"n":"Worldspace"},{"t":3,"p":1,"n":"VATS Value Function"},{"t":3,"p":1,"n":"VATS Value Param (INVALID)"},{"t":3,"p":1,"n":"Referenceable Object"},{"t":3,"p":1,"n":"Region"},{"t":3,"p":1,"n":"Keyword"},{"t":3,"p":1,"n":"Player Action"},{"t":3,"p":1,"n":"Casting Type"},{"t":3,"p":1,"n":"Shout"},{"t":3,"p":1,"n":"Location"},{"t":3,"p":1,"n":"Location Ref Type"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"Packdata ID"},{"t":3,"p":1,"n":"Association Type"},{"t":3,"p":1,"n":"Furniture Anim"},{"t":3,"p":1,"n":"Furniture Entry"},{"t":3,"p":1,"n":"Scene"},{"t":3,"p":1,"n":"Ward State"},{"t":3,"p":1,"n":"Event"},{"t":3,"p":1,"n":"Event Data"},{"t":3,"p":1,"n":"Quest Stage"},{"t":3,"p":1,"n":"Weapon"},{"t":3,"p":1,"n":"Weapon List"},{"t":3,"p":1,"n":"Target"},{"t":3,"p":1,"n":"Target List"},{"t":3,"p":1,"n":"Target Part"},{"t":3,"p":1,"n":"VATS Action"},{"t":3,"p":1,"n":"Critical Effect"},{"t":3,"p":1,"n":"Critical Effect List"},{"t":3,"p":1,"n":"Weapon Type"},{"t":3,"p":1,"n":"Projectile Type"},{"t":3,"p":1,"n":"Delivery Type"},{"t":3,"p":1,"n":"Run On"},{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Parameter #3"}]},{"t":2,"p":1,"n":"CIS1 - Parameter #1"},{"t":2,"p":1,"n":"CIS2 - Parameter #2"}]}]}]}]}]},{"t":1,"p":1,"n":"SPGD - Shader Particle Geometry","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"Data","c":[{"t":5,"p":1,"n":"Gravity Velocity"},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"Rotation Velocity"},{"t":5,"p":1,"n":"Particle Size X"},{"t":5,"p":1,"n":"Center Offset Min"},{"t":5,"p":1,"n":"Particle Size Y"},{"t":5,"p":1,"n":"Center Offset Max"},{"t":5,"p":1,"n":"Initial Rotation"},{"t":3,"p":1,"n":"# of Subtextures X"},{"t":3,"p":1,"n":"# of Subtextures Y"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Box Size"},{"t":5,"p":1,"n":"Particle Density"}]},{"t":2,"p":1,"n":"ICON - Particle Texture"}]},{"t":1,"p":1,"n":"STAT - Static","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"DNAM - Direction Material","c":[{"t":5,"p":1,"n":"Max Angle (30-120)"},{"t":3,"p":1,"n":"Material"}]},{"t":7,"p":1,"n":"MNAM - Distant LOD","c":[{"t":6,"p":1,"n":"LOD","c":[{"t":2,"p":1,"n":"Mesh"}]}]}]},{"t":1,"p":1,"n":"TACT - Talking Activator","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":11,"n":"PNAM - Unknown"},{"t":3,"p":1,"n":"SNAM - Looping Sound"},{"t":11,"n":"FNAM - Unknown"},{"t":3,"p":1,"n":"VNAM - Voice Type"}]},{"t":1,"p":1,"n":"TREE - Tree","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":3,"p":1,"n":"PFIG - Ingredient"},{"t":3,"p":1,"n":"SNAM - Harvest Sound"},{"t":6,"s":1,"p":1,"n":"PFPC - Ingredient Production","c":[{"t":3,"p":1,"n":"Spring"},{"t":3,"p":1,"n":"Summer"},{"t":3,"p":1,"n":"Fall"},{"t":3,"p":1,"n":"Winter"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"CNAM - Tree Data","c":[{"t":5,"p":1,"n":"Trunk Flexibility"},{"t":5,"p":1,"n":"Branch Flexibility"},{"t":5,"n":"Unknown"},{"t":5,"p":1,"n":"Leaf Amplitude"},{"t":5,"p":1,"n":"Leaf Frequency"}]}]},{"t":1,"p":1,"n":"TXST - Texture Set","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":6,"s":1,"p":1,"n":"Textures (RGB\/A)","c":[{"t":2,"p":1,"n":"TX00 - Difuse"},{"t":2,"p":1,"n":"TX01 - Normal\/Gloss"},{"t":2,"p":1,"n":"TX02 - Environment Mask\/Subsurface Tint"},{"t":2,"p":1,"n":"TX03 - Glow\/Detail Map"},{"t":2,"p":1,"n":"TX04 - Height"},{"t":2,"p":1,"n":"TX05 - Environment"},{"t":2,"p":1,"n":"TX06 - Multilayer"},{"t":2,"p":1,"n":"TX07 - Backlight Mask\/Specular"}]},{"t":6,"s":1,"p":1,"n":"DODT - Decal Data","c":[{"t":5,"p":1,"n":"Min Width"},{"t":5,"p":1,"n":"Max Width"},{"t":5,"p":1,"n":"Min Height"},{"t":5,"p":1,"n":"Max Height"},{"t":5,"p":1,"n":"Depth"},{"t":5,"p":1,"n":"Shininess"},{"t":6,"p":1,"n":"Parallax","c":[{"t":5,"p":1,"n":"Scale"},{"t":3,"p":1,"n":"Passes"}]},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"},{"t":6,"p":1,"n":"Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":3,"p":1,"n":"DNAM - Flags"}]},{"t":1,"p":1,"n":"VOLI - Volumetric Lighting","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":5,"p":1,"n":"CNAM - Intensity"},{"t":5,"p":1,"n":"DNAM - Custom Color - Contribution"},{"t":5,"p":1,"n":"ENAM - Red"},{"t":5,"p":1,"n":"FNAM - Green"},{"t":5,"p":1,"n":"GNAM - Blue"},{"t":5,"p":1,"n":"HNAM - Density - Contribution"},{"t":5,"p":1,"n":"INAM - Density - Size"},{"t":5,"p":1,"n":"JNAM - Density - Wind Speed"},{"t":5,"p":1,"n":"KNAM - Density - Falling Speed"},{"t":5,"p":1,"n":"LNAM - Phase Function - Contribution"},{"t":5,"p":1,"n":"MNAM - Phase Function - Scattering"},{"t":5,"p":1,"n":"NNAM - Sampling Repartition - Range Factor"}]},{"t":1,"p":1,"n":"VTYP - Voice Type","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":3,"p":1,"n":"DNAM - Flags"}]},{"t":1,"p":1,"n":"WATR - Water","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":8,"n":"Unused","c":[{"t":2,"n":"NNAM - Noise Map"}]},{"t":3,"p":1,"n":"ANAM - Opacity"},{"t":3,"p":1,"n":"FNAM - Flags"},{"t":11,"n":"MNAM - Unused"},{"t":3,"p":1,"n":"TNAM - Material"},{"t":3,"p":1,"n":"SNAM - Open Sound"},{"t":3,"p":1,"n":"XNAM - Spell"},{"t":3,"p":1,"n":"INAM - Image Space"},{"t":3,"p":1,"n":"DATA - Damage Per Second"},{"t":6,"s":1,"p":1,"n":"DNAM - Visual Data","c":[{"t":5,"n":"Unknown"},{"t":5,"p":1,"n":"Specular Properties - Sun Specular Power"},{"t":5,"p":1,"n":"Water Properties - Reflectivity Amount"},{"t":5,"p":1,"n":"Water Properties - Fresnel Amount"},{"t":5,"p":1,"n":"Fog Properties - Above Water - Fog Distance - Near Plane"},{"t":5,"p":1,"n":"Fog Properties - Above Water - Fog Distance - Far Plane"},{"t":6,"p":1,"n":"Shallow Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Deep Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Reflection Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Displacement Simulator - Starting Size"},{"t":5,"p":1,"n":"Displacement Simulator - Force"},{"t":5,"p":1,"n":"Displacement Simulator - Velocity"},{"t":5,"p":1,"n":"Displacement Simulator - Falloff"},{"t":5,"p":1,"n":"Displacement Simulator - Dampner"},{"t":5,"p":1,"n":"Noise Properties - Noise Falloff"},{"t":5,"p":1,"n":"Noise Properties - Layer One - Wind Direction"},{"t":5,"p":1,"n":"Noise Properties - Layer Two - Wind Direction"},{"t":5,"p":1,"n":"Noise Properties - Layer Three - Wind Direction"},{"t":5,"p":1,"n":"Noise Properties - Layer One - Wind Speed"},{"t":5,"p":1,"n":"Noise Properties - Layer Two - Wind Speed"},{"t":5,"p":1,"n":"Noise Properties - Layer Three - Wind Speed"},{"t":5,"p":1,"n":"Fog Properties - Above Water - Fog Amount"},{"t":5,"p":1,"n":"Fog Properties - Under Water - Fog Amount"},{"t":5,"p":1,"n":"Fog Properties - Under Water - Fog Distance - Near Plane"},{"t":5,"p":1,"n":"Fog Properties - Under Water - Fog Distance - Far Plane"},{"t":5,"p":1,"n":"Water Properties - Refraction Magnitude"},{"t":5,"p":1,"n":"Specular Properties - Specular Power"},{"t":5,"p":1,"n":"Specular Properties - Specular Radius"},{"t":5,"p":1,"n":"Specular Properties - Specular Brightness"},{"t":5,"p":1,"n":"Noise Properties - Layer One - UV Scale"},{"t":5,"p":1,"n":"Noise Properties - Layer Two - UV Scale"},{"t":5,"p":1,"n":"Noise Properties - Layer Three - UV Scale"},{"t":5,"p":1,"n":"Noise Properties - Layer One - Amplitude Scale"},{"t":5,"p":1,"n":"Noise Properties - Layer Two - Amplitude Scale"},{"t":5,"p":1,"n":"Noise Properties - Layer Three - Amplitude Scale"},{"t":5,"p":1,"n":"Water Properties - Reflection Magnitude"},{"t":5,"p":1,"n":"Specular Properties - Sun Sparkle Magnitude"},{"t":5,"p":1,"n":"Specular Properties - Sun Specular Magnitude"},{"t":5,"p":1,"n":"Depth Properties - Reflections"},{"t":5,"p":1,"n":"Depth Properties - Refraction"},{"t":5,"p":1,"n":"Depth Properties - Normals"},{"t":5,"p":1,"n":"Depth Properties - Specular Lighting"},{"t":5,"p":1,"n":"Specular Properties - Sun Sparkle Power"}]},{"t":11,"n":"GNAM - Unused"},{"t":6,"s":1,"p":1,"n":"NAM0 - Linear Velocity","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"s":1,"p":1,"n":"NAM1 - Angular Velocity","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":2,"p":1,"n":"NAM2 - Noise Layer One - Noise Texture"},{"t":2,"p":1,"n":"NAM3 - Noise Layer Two - Noise Texture"},{"t":2,"p":1,"n":"NAM4 - Noise Layer Three - Noise Texture"},{"t":2,"p":1,"n":"NAM5 - Flow Normals - Noise Texture"}]},{"t":1,"p":1,"n":"WEAP - Weapon","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":6,"s":1,"p":1,"n":"OBND - Object Bounds","c":[{"t":3,"p":1,"n":"X1"},{"t":3,"p":1,"n":"Y1"},{"t":3,"p":1,"n":"Z1"},{"t":3,"p":1,"n":"X2"},{"t":3,"p":1,"n":"Y2"},{"t":3,"p":1,"n":"Z2"}]},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":6,"s":1,"p":1,"n":"Icon","c":[{"t":2,"p":1,"n":"ICON - Large Icon filename"},{"t":2,"p":1,"n":"MICO - Small Icon filename"}]},{"t":3,"p":1,"n":"EITM - Object Effect"},{"t":3,"p":1,"n":"EAMT - Enchantment Amount"},{"t":6,"s":1,"p":1,"n":"Destructable","c":[{"t":6,"p":1,"n":"DEST - Header","c":[{"t":3,"p":1,"n":"Health"},{"t":3,"p":1,"n":"DEST Count"},{"t":3,"p":1,"n":"VATS Targetable"},{"t":11,"n":"Unknown"}]},{"t":8,"p":1,"n":"Stages","c":[{"t":6,"p":1,"n":"Stage","c":[{"t":6,"p":1,"n":"DSTD - Destruction Stage Data","c":[{"t":3,"p":1,"n":"Health %"},{"t":3,"p":1,"n":"Index"},{"t":3,"p":1,"n":"Model Damage Stage"},{"t":3,"p":1,"n":"Flags"},{"t":3,"p":1,"n":"Self Damage per Second"},{"t":3,"p":1,"n":"Explosion"},{"t":3,"p":1,"n":"Debris"},{"t":3,"p":1,"n":"Debris Count"}]},{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"DMDL - Model Filename"},{"t":11,"p":1,"n":"DMDT - Texture Files Hashes"},{"t":7,"p":1,"n":"DMDS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"p":1,"n":"DSTF - End Marker"}]}]}]},{"t":3,"p":1,"n":"ETYP - Equipment Type"},{"t":3,"p":1,"n":"BIDS - Block Bash Impact Data Set"},{"t":3,"p":1,"n":"BAMT - Alternate Block Material"},{"t":3,"p":1,"n":"YNAM - Sound - Pick Up"},{"t":3,"p":1,"n":"ZNAM - Sound - Put Down"},{"t":3,"n":"KSIZ - Keyword Count"},{"t":7,"p":1,"n":"KWDA - Keywords","c":[{"t":3,"p":1,"n":"Keyword"}]},{"t":2,"p":1,"n":"DESC - Description"},{"t":6,"s":1,"p":1,"n":"Has Scope","c":[{"t":2,"p":1,"n":"MOD3 - Model Filename"},{"t":11,"p":1,"n":"MO3T - Texture Files Hashes"},{"t":7,"p":1,"n":"MO3S - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]},{"t":11,"n":"NNAM - Unused"},{"t":3,"p":1,"n":"INAM - Impact Data Set"},{"t":3,"p":1,"n":"WNAM - 1st Person Model Object"},{"t":3,"p":1,"n":"SNAM - Attack Sound"},{"t":3,"p":1,"n":"XNAM - Attack Sound 2D"},{"t":3,"p":1,"n":"NAM7 - Attack Loop Sound"},{"t":3,"p":1,"n":"TNAM - Attack Fail Sound"},{"t":3,"p":1,"n":"UNAM - Idle Sound"},{"t":3,"p":1,"n":"NAM9 - Equip Sound"},{"t":3,"p":1,"n":"NAM8 - Unequip Sound"},{"t":6,"s":1,"p":1,"n":"DATA - Game Data","c":[{"t":3,"p":1,"n":"Value"},{"t":5,"p":1,"n":"Weight"},{"t":3,"p":1,"n":"Damage"}]},{"t":6,"s":1,"p":1,"n":"DNAM - Data","c":[{"t":3,"p":1,"n":"Animation Type"},{"t":11,"n":"Unused"},{"t":5,"p":1,"n":"Speed"},{"t":5,"p":1,"n":"Reach"},{"t":3,"p":1,"n":"Flags"},{"t":5,"p":1,"n":"Sight FOV"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Base VATS To-Hit Chance"},{"t":3,"p":1,"n":"Attack Animation"},{"t":3,"p":1,"n":"# Projectiles"},{"t":3,"p":1,"n":"Embedded Weapon AV (unused)"},{"t":5,"p":1,"n":"Range Min"},{"t":5,"p":1,"n":"Range Max"},{"t":3,"p":1,"n":"On Hit"},{"t":3,"p":1,"n":"Flags2"},{"t":5,"p":1,"n":"Animation Attack Mult"},{"t":5,"p":1,"n":"Rumble - Left Motor Strength"},{"t":5,"p":1,"n":"Rumble - Right Motor Strength"},{"t":5,"p":1,"n":"Rumble - Duration"},{"t":3,"p":1,"n":"Skill"},{"t":3,"p":1,"n":"Resist"},{"t":5,"p":1,"n":"Stagger"}]},{"t":6,"s":1,"p":1,"n":"CRDT - Critical Data","c":[{"t":3,"p":1,"n":"Damage"},{"t":11,"n":"Unknown"},{"t":5,"p":1,"n":"% Mult"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":3,"p":1,"n":"Effect"}]},{"t":3,"p":1,"n":"VNAM - Detection Sound Level"},{"t":3,"p":1,"n":"CNAM - Template"}]},{"t":1,"p":1,"n":"WOOP - Word of Power","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"FULL - Name"},{"t":2,"p":1,"n":"TNAM - Translation"}]},{"t":1,"p":1,"n":"WRLD - Worldspace","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":8,"n":"Unused RNAM","c":[{"t":6,"n":"RNAM - Grid","c":[{"t":3,"n":"Y"},{"t":3,"n":"X"},{"t":7,"n":"References","c":[{"t":6,"n":"Reference","c":[{"t":3,"n":"Ref"},{"t":3,"n":"Y"},{"t":3,"n":"X"}]}]}]}]},{"t":11,"n":"MHDT - Max Height Data"},{"t":2,"p":1,"n":"FULL - Name"},{"t":6,"s":1,"p":1,"n":"WCTR - Fixed Dimensions Center Cell","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"}]},{"t":3,"p":1,"n":"LTMP - Interior Lighting"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":3,"p":1,"n":"XLCN - Location"},{"t":6,"s":1,"p":1,"n":"Parent","c":[{"t":3,"p":1,"n":"WNAM - Worldspace"},{"t":6,"p":1,"n":"PNAM - ","c":[{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unknown"}]}]},{"t":3,"p":1,"n":"CNAM - Climate"},{"t":3,"p":1,"n":"NAM2 - Water"},{"t":3,"p":1,"n":"NAM3 - LOD Water Type"},{"t":5,"p":1,"n":"NAM4 - LOD Water Height"},{"t":6,"s":1,"p":1,"n":"DNAM - Land Data","c":[{"t":5,"p":1,"n":"Default Land Height"},{"t":5,"p":1,"n":"Default Water Height"}]},{"t":2,"p":1,"n":"ICON - Map Image"},{"t":6,"s":1,"p":1,"n":"Cloud Model","c":[{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]}]},{"t":6,"s":1,"p":1,"n":"MNAM - Map Data","c":[{"t":6,"p":1,"n":"Usable Dimensions","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"}]},{"t":6,"p":1,"n":"Cell Coordinates","c":[{"t":6,"p":1,"n":"NW Cell","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"}]},{"t":6,"p":1,"n":"SE Cell","c":[{"t":3,"p":1,"n":"X"},{"t":3,"p":1,"n":"Y"}]}]},{"t":6,"p":1,"n":"Camera Data","c":[{"t":5,"p":1,"n":"Min Height"},{"t":5,"p":1,"n":"Max Height"},{"t":5,"p":1,"n":"Initial Pitch"}]}]},{"t":6,"s":1,"p":1,"n":"ONAM - World Map Offset Data","c":[{"t":5,"p":1,"n":"World Map Scale"},{"t":5,"p":1,"n":"Cell X Offset"},{"t":5,"p":1,"n":"Cell Y Offset"},{"t":5,"p":1,"n":"Cell Z Offset"}]},{"t":5,"p":1,"n":"NAMA - Distant LOD Multiplier"},{"t":3,"p":1,"n":"DATA - Flags"},{"t":6,"s":1,"p":1,"n":"Object Bounds","c":[{"t":6,"p":1,"n":"NAM0 - Min","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"}]},{"t":6,"p":1,"n":"NAM9 - Max","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"}]}]},{"t":3,"p":1,"n":"ZNAM - Music"},{"t":2,"p":1,"n":"NNAM - Canopy Shadow (unused)"},{"t":2,"p":1,"n":"XNAM - Water Noise Texture"},{"t":2,"p":1,"n":"TNAM - HD LOD Diffuse Texture"},{"t":2,"p":1,"n":"UNAM - HD LOD Normal Texture"},{"t":2,"p":1,"n":"XWEM - Water Environment Map (unused)"},{"t":11,"n":"OFST - Offset Data"}]},{"t":1,"p":1,"n":"WTHR - Weather","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":2,"p":1,"n":"00TX - Cloud Texture Layer #0"},{"t":2,"p":1,"n":"10TX - Cloud Texture Layer #1"},{"t":2,"p":1,"n":"20TX - Cloud Texture Layer #2"},{"t":2,"p":1,"n":"30TX - Cloud Texture Layer #3"},{"t":2,"p":1,"n":"40TX - Cloud Texture Layer #4"},{"t":2,"p":1,"n":"50TX - Cloud Texture Layer #5"},{"t":2,"p":1,"n":"60TX - Cloud Texture Layer #6"},{"t":2,"p":1,"n":"70TX - Cloud Texture Layer #7"},{"t":2,"p":1,"n":"80TX - Cloud Texture Layer #8"},{"t":2,"p":1,"n":"90TX - Cloud Texture Layer #9"},{"t":2,"p":1,"n":":0TX - Cloud Texture Layer #10"},{"t":2,"p":1,"n":";0TX - Cloud Texture Layer #11"},{"t":2,"p":1,"n":"<0TX - Cloud Texture Layer #12"},{"t":2,"p":1,"n":"=0TX - Cloud Texture Layer #13"},{"t":2,"p":1,"n":">0TX - Cloud Texture Layer #14"},{"t":2,"p":1,"n":"?0TX - Cloud Texture Layer #15"},{"t":2,"p":1,"n":"@0TX - Cloud Texture Layer #16"},{"t":2,"p":1,"n":"A0TX - Cloud Texture Layer #17"},{"t":2,"p":1,"n":"B0TX - Cloud Texture Layer #18"},{"t":2,"p":1,"n":"C0TX - Cloud Texture Layer #19"},{"t":2,"p":1,"n":"D0TX - Cloud Texture Layer #20"},{"t":2,"p":1,"n":"E0TX - Cloud Texture Layer #21"},{"t":2,"p":1,"n":"F0TX - Cloud Texture Layer #22"},{"t":2,"p":1,"n":"G0TX - Cloud Texture Layer #23"},{"t":2,"p":1,"n":"H0TX - Cloud Texture Layer #24"},{"t":2,"p":1,"n":"I0TX - Cloud Texture Layer #25"},{"t":2,"p":1,"n":"J0TX - Cloud Texture Layer #26"},{"t":2,"p":1,"n":"K0TX - Cloud Texture Layer #27"},{"t":2,"p":1,"n":"L0TX - Cloud Texture Layer #28"},{"t":11,"n":"DNAM - Unused"},{"t":11,"n":"CNAM - Unused"},{"t":11,"n":"ANAM - Unused"},{"t":11,"n":"BNAM - Unused"},{"t":11,"n":"LNAM - Unknown"},{"t":3,"p":1,"n":"MNAM - Precipitation Type"},{"t":3,"p":1,"n":"NNAM - Visual Effect"},{"t":11,"n":"ONAM - Unused"},{"t":6,"s":1,"p":1,"n":"Cloud Speed","c":[{"t":7,"p":1,"n":"RNAM - Y Speed","c":[{"t":3,"p":1,"n":"Layer"}]},{"t":7,"p":1,"n":"QNAM - X Speed","c":[{"t":3,"p":1,"n":"Layer"}]}]},{"t":7,"s":1,"p":1,"n":"PNAM - Cloud Colors","c":[{"t":6,"p":1,"n":"Layer","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]}]},{"t":7,"s":1,"p":1,"n":"JNAM - Cloud Alphas","c":[{"t":6,"p":1,"n":"Layer","c":[{"t":5,"p":1,"n":"Sunrise"},{"t":5,"p":1,"n":"Day"},{"t":5,"p":1,"n":"Sunset"},{"t":5,"p":1,"n":"Night"}]}]},{"t":6,"s":1,"p":1,"n":"NAM0 - Weather Colors","c":[{"t":6,"p":1,"n":"Sky-Upper","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Fog Near","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"n":"Unknown","c":[{"t":6,"n":"Sunrise","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"n":"Day","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"n":"Sunset","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"n":"Night","c":[{"t":3,"n":"Red"},{"t":3,"n":"Green"},{"t":3,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Ambient","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Sunlight","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Sun","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Stars","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Sky-Lower","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Horizon","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Effect Lighting","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Cloud LOD Diffuse","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Cloud LOD Ambient","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Fog Far","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Sky Statics","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Water Multiplier","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Sun Glare","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Moon Glare","c":[{"t":6,"p":1,"n":"Sunrise","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Day","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Sunset","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Night","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]}]},{"t":6,"s":1,"p":1,"n":"FNAM - Fog Distance","c":[{"t":5,"p":1,"n":"Day - Near"},{"t":5,"p":1,"n":"Day - Far"},{"t":5,"p":1,"n":"Night - Near"},{"t":5,"p":1,"n":"Night - Far"},{"t":5,"p":1,"n":"Day - Power"},{"t":5,"p":1,"n":"Night - Power"},{"t":5,"p":1,"n":"Day - Max"},{"t":5,"p":1,"n":"Night - Max"}]},{"t":6,"s":1,"p":1,"n":"DATA - Data","c":[{"t":3,"p":1,"n":"Wind Speed"},{"t":11,"n":"Unknown"},{"t":3,"p":1,"n":"Trans Delta"},{"t":3,"p":1,"n":"Sun Glare"},{"t":3,"p":1,"n":"Sun Damage"},{"t":3,"p":1,"n":"Precipitation - Begin Fade In"},{"t":3,"p":1,"n":"Precipitation - End Fade Out"},{"t":3,"p":1,"n":"Thunder\/Lightning - Begin Fade In"},{"t":3,"p":1,"n":"Thunder\/Lightning - End Fade Out"},{"t":3,"p":1,"n":"Thunder\/Lightning - Frequency"},{"t":3,"p":1,"n":"Flags"},{"t":6,"p":1,"n":"Lightning Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"}]},{"t":3,"p":1,"n":"Visual Effect - Begin"},{"t":3,"p":1,"n":"Visual Effect - End"},{"t":3,"p":1,"n":"Wind Direction"},{"t":3,"p":1,"n":"Wind Direction Range"}]},{"t":3,"p":1,"n":"NAM1 - Disabled Cloud Layers"},{"t":8,"s":1,"p":1,"n":"Sounds","d":1,"c":[{"t":6,"p":1,"n":"SNAM - Sound","c":[{"t":3,"p":1,"n":"Sound"},{"t":3,"p":1,"n":"Type"}]}]},{"t":8,"s":1,"p":1,"n":"Sky Statics","d":1,"c":[{"t":3,"p":1,"n":"TNAM - Static"}]},{"t":6,"s":1,"p":1,"n":"IMSP - Image Spaces","c":[{"t":3,"p":1,"n":"Sunrise"},{"t":3,"p":1,"n":"Day"},{"t":3,"p":1,"n":"Sunset"},{"t":3,"p":1,"n":"Night"}]},{"t":6,"s":1,"p":1,"n":"HNAM - Volumetric Lighting","c":[{"t":3,"p":1,"n":"Sunrise"},{"t":3,"p":1,"n":"Day"},{"t":3,"p":1,"n":"Sunset"},{"t":3,"p":1,"n":"Night"}]},{"t":6,"s":1,"p":1,"n":"Directional Ambient Lighting Colors","c":[{"t":6,"p":1,"n":"DALC - Sunrise","c":[{"t":6,"p":1,"n":"Directional","c":[{"t":6,"p":1,"n":"X+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"X-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Specular","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Scale"}]},{"t":6,"p":1,"n":"DALC - Day","c":[{"t":6,"p":1,"n":"Directional","c":[{"t":6,"p":1,"n":"X+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"X-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Specular","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Scale"}]},{"t":6,"p":1,"n":"DALC - Sunset","c":[{"t":6,"p":1,"n":"Directional","c":[{"t":6,"p":1,"n":"X+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"X-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Specular","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Scale"}]},{"t":6,"p":1,"n":"DALC - Night","c":[{"t":6,"p":1,"n":"Directional","c":[{"t":6,"p":1,"n":"X+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"X-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Y-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z+","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Z-","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":6,"p":1,"n":"Specular","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":5,"p":1,"n":"Scale"}]}]},{"t":11,"n":"NAM2 - Unused"},{"t":11,"n":"NAM3 - Unused"},{"t":6,"s":1,"p":1,"n":"Aurora","c":[{"t":6,"p":1,"n":"Model","c":[{"t":2,"p":1,"n":"MODL - Model Filename"},{"t":11,"p":1,"n":"MODT - Texture Files Hashes"},{"t":7,"p":1,"n":"MODS - Alternate Textures","c":[{"t":6,"p":1,"n":"Alternate Texture","c":[{"t":2,"p":1,"n":"3D Name"},{"t":3,"p":1,"n":"New Texture"},{"t":3,"p":1,"n":"3D Index"}]}]}]}]},{"t":3,"p":1,"n":"GNAM - Sun Glare Lens Flare"}]},{"t":1,"p":1,"n":"ACHR - Placed NPC","d":1,"c":[{"t":2,"p":1,"n":"EDID - Editor ID"},{"t":6,"s":1,"p":1,"n":"VMAD - Virtual Machine Adapter","c":[{"t":3,"p":1,"n":"Version"},{"t":3,"p":1,"n":"Object Format"},{"t":7,"p":1,"n":"Scripts","c":[{"t":6,"p":1,"n":"Script","c":[{"t":2,"p":1,"n":"scriptName"},{"t":3,"p":1,"n":"Flags"},{"t":7,"p":1,"n":"Properties","c":[{"t":6,"p":1,"n":"Property","c":[{"t":2,"p":1,"n":"propertyName"},{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"},{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]},{"t":2,"p":1,"n":"String"},{"t":3,"p":1,"n":"Int32"},{"t":5,"p":1,"n":"Float"},{"t":3,"p":1,"n":"Bool"},{"t":7,"p":1,"n":"Array of Object","c":[{"t":6,"p":1,"n":"Object v2","c":[{"t":3,"n":"Unused"},{"t":3,"p":1,"n":"Alias"},{"t":3,"p":1,"n":"FormID"}]},{"t":6,"p":1,"n":"Object v1","c":[{"t":3,"p":1,"n":"FormID"},{"t":3,"p":1,"n":"Alias"},{"t":3,"n":"Unused"}]}]},{"t":7,"p":1,"n":"Array of String","c":[{"t":2,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Int32","c":[{"t":3,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Float","c":[{"t":5,"p":1,"n":"Element"}]},{"t":7,"p":1,"n":"Array of Bool","c":[{"t":3,"p":1,"n":"Element"}]}]}]}]}]}]},{"t":3,"p":1,"n":"NAME - Base"},{"t":3,"p":1,"n":"XEZN - Encounter Zone"},{"t":11,"n":"XRGD - Ragdoll Data"},{"t":11,"n":"XRGB - Ragdoll Biped Data"},{"t":6,"s":1,"p":1,"n":"Patrol Data","c":[{"t":5,"p":1,"n":"XPRD - Idle Time"},{"p":1,"n":"XPPA - Patrol Script Marker"},{"t":3,"p":1,"n":"INAM - Idle"},{"t":6,"n":"Unused","c":[{"t":11,"n":"SCHR - Unknown"},{"t":11,"n":"SCDA - Unknown"},{"t":11,"n":"SCTX - Unknown"},{"t":11,"n":"QNAM - Unknown"},{"t":11,"n":"SCRO - Unknown"}]},{"t":8,"p":1,"n":"Topic","c":[{"t":6,"p":1,"n":"PDTO - Topic Data","c":[{"t":3,"p":1,"n":"Type"},{"t":3,"p":1,"n":"Topic"},{"t":2,"p":1,"n":"Subtype"}]}]},{"t":3,"p":1,"n":"TNAM - Topic"}]},{"t":3,"p":1,"n":"XLCM - Level Modifier"},{"t":3,"p":1,"n":"XMRC - Merchant Container"},{"t":3,"p":1,"n":"XCNT - Count"},{"t":5,"p":1,"n":"XRDS - Radius"},{"t":5,"p":1,"n":"XHLP - Health"},{"t":8,"s":1,"p":1,"n":"Linked References","d":1,"c":[{"t":6,"p":1,"n":"XLKR - Linked Reference","c":[{"t":3,"p":1,"n":"Keyword\/Ref"},{"t":3,"p":1,"n":"Ref"}]}]},{"t":6,"s":1,"p":1,"n":"Activate Parents","c":[{"t":3,"p":1,"n":"XAPD - Flags"},{"t":8,"p":1,"n":"Activate Parent Refs","c":[{"t":6,"p":1,"n":"XAPR - Activate Parent Ref","c":[{"t":3,"p":1,"n":"Reference"},{"t":5,"p":1,"n":"Delay"}]}]}]},{"t":6,"s":1,"p":1,"n":"XCLP - Linked Reference Color","c":[{"t":6,"p":1,"n":"Link Start Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]},{"t":6,"p":1,"n":"Link End Color","c":[{"t":3,"p":1,"n":"Red"},{"t":3,"p":1,"n":"Green"},{"t":3,"p":1,"n":"Blue"},{"t":11,"n":"Unused"}]}]},{"t":3,"p":1,"n":"XLCN - Persistent Location"},{"t":3,"p":1,"n":"XLRL - Location Reference"},{"p":1,"n":"XIS2 - Ignored by Sandbox"},{"t":7,"p":1,"n":"XLRT - Location Ref Type","c":[{"t":3,"p":1,"n":"Ref"}]},{"t":3,"p":1,"n":"XHOR - Horse"},{"t":5,"p":1,"n":"XHTW - Head-Tracking Weight"},{"t":5,"p":1,"n":"XFVC - Favor Cost"},{"t":6,"s":1,"p":1,"n":"XESP - Enable Parent","c":[{"t":3,"p":1,"n":"Reference"},{"t":3,"p":1,"n":"Flags"},{"t":11,"n":"Unused"}]},{"t":6,"s":1,"p":1,"n":"Ownership","c":[{"t":3,"p":1,"n":"XOWN - Owner"},{"t":3,"p":1,"n":"XRNK - Faction rank"}]},{"t":3,"p":1,"n":"XEMI - Emittance"},{"t":3,"p":1,"n":"XMBR - MultiBound Reference"},{"p":1,"n":"XIBS - Ignored By Sandbox"},{"t":5,"p":1,"n":"XSCL - Scale"},{"t":6,"s":1,"p":1,"n":"DATA - Position\/Rotation","c":[{"t":6,"p":1,"n":"Position","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]},{"t":6,"p":1,"n":"Rotation","c":[{"t":5,"p":1,"n":"X"},{"t":5,"p":1,"n":"Y"},{"t":5,"p":1,"n":"Z"}]}]}]}]},"name":"Smash.OverrideAll","hash":"36B6DC28","color":32768} ================================================ FILE: frontend/smash.rc ================================================ SMASH WAV ".\Resources\smash.wav" ================================================ FILE: lib/Imaging/Imaging.pas ================================================ { Vampyre Imaging Library by Marek Mauder http://imaginglib.sourceforge.net The contents of this file are used with permission, subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/MPL-1.1.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Alternatively, the contents of this file may be used under the terms of the GNU Lesser General Public License (the "LGPL License"), in which case the provisions of the LGPL License are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of the LGPL License and not to allow others to use your version of this file under the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the LGPL License. If you do not delete the provisions above, a recipient may use your version of this file under either the MPL or the LGPL License. For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html } { This unit is heart of Imaging library. It contains basic functions for manipulating image data as well as various image file format support.} unit Imaging; {$I ImagingOptions.inc} interface uses SysUtils, Classes, Types, ImagingTypes; type { Default Imaging excepton class } EImagingError = class(Exception); { Raised when function receives bad image (not passed TestImage).} EImagingBadImage = class(Exception) public constructor Create; end; { Dynamic array of TImageData records } TDynImageDataArray = array of TImageData; { ------------------------------------------------------------------------ Low Level Interface Functions ------------------------------------------------------------------------} { General Functions } { Initializes image (all is set to zeroes). Call this for each image before using it (before calling every other function) to be sure there are no random-filled bytes (which would cause errors later).} procedure InitImage(var Image: TImageData); { Creates empty image of given dimensions and format. Image is filled with transparent black color (A=0, R=0, G=0, B=0).} function NewImage(Width, Height: LongInt; Format: TImageFormat; var Image: TImageData): Boolean; { Returns True if given TImageData record is valid.} function TestImage(const Image: TImageData): Boolean; { Frees given image data. Ater this call image is in the same state as after calling InitImage. If image is not valid (dost not pass TestImage test) it is only zeroed by calling InitImage.} procedure FreeImage(var Image: TImageData); { Call FreeImage() on all images in given dynamic array and sets its length to zero.} procedure FreeImagesInArray(var Images: TDynImageDataArray); { Returns True if all TImageData records in given array are valid. Returns False if at least one is invalid or if array is empty.} function TestImagesInArray(const Images: TDynImageDataArray): Boolean; { Checks given file for every supported image file format and if the file is in one of them returns its string identifier (which can be used in LoadFromStream/LoadFromMem type functions). If file is not in any of the supported formats empty string is returned.} function DetermineFileFormat(const FileName: string): string; { Checks given stream for every supported image file format and if the stream is in one of them returns its string identifier (which can be used in LoadFromStream/LoadFromMem type functions). If stream is not in any of the supported formats empty string is returned.} function DetermineStreamFormat(Stream: TStream): string; { Checks given memory for every supported image file format and if the memory is in one of them returns its string identifier (which can be used in LoadFromStream/LoadFromMem type functions). If memory is not in any of the supported formats empty string is returned.} function DetermineMemoryFormat(Data: Pointer; Size: LongInt): string; { Checks that an apropriate file format is supported purely from inspecting the given file name's extension (not contents of the file itself). The file need not exist.} function IsFileFormatSupported(const FileName: string): Boolean; { Enumerates all registered image file formats. Descriptive name, default extension, masks (like '*.jpg,*.jfif') and some capabilities of each format are returned. To enumerate all formats start with Index at 0 and call EnumFileFormats with given Index in loop until it returns False (Index is automatically increased by 1 in function's body on successful call).} function EnumFileFormats(var Index: LongInt; var Name, DefaultExt, Masks: string; var CanSaveImages, IsMultiImageFormat: Boolean): Boolean; { Loading Functions } { Loads single image from given file.} function LoadImageFromFile(const FileName: string; var Image: TImageData): Boolean; { Loads single image from given stream. If function fails stream position is not changed.} function LoadImageFromStream(Stream: TStream; var Image: TImageData): Boolean; { Loads single image from given memory location.} function LoadImageFromMemory(Data: Pointer; Size: LongInt; var Image: TImageData): Boolean; { Loads multiple images from given file.} function LoadMultiImageFromFile(const FileName: string; var Images: TDynImageDataArray): Boolean; { Loads multiple images from given stream. If function fails stream position is not changed.} function LoadMultiImageFromStream(Stream: TStream; var Images: TDynImageDataArray): Boolean; { Loads multiple images from given memory location.} function LoadMultiImageFromMemory(Data: Pointer; Size: LongInt; var Images: TDynImageDataArray): Boolean; { Saving Functions } { Saves single image to given file.} function SaveImageToFile(const FileName: string; const Image: TImageData): Boolean; { Saves single image to given stream. If function fails stream position is not changed. Ext identifies desired image file format (jpg, png, dds, ...).} function SaveImageToStream(const Ext: string; Stream: TStream; const Image: TImageData): Boolean; { Saves single image to given memory location. Memory must be allocated and its size is passed in Size parameter in which number of written bytes is returned. Ext identifies desired image file format (jpg, png, dds, ...).} function SaveImageToMemory(const Ext: string; Data: Pointer; var Size: LongInt; const Image: TImageData): Boolean; { Saves multiple images to given file. If format supports only single level images and there are multiple images to be saved, they are saved as sequence of files img000.jpg, img001.jpg ....).} function SaveMultiImageToFile(const FileName: string; const Images: TDynImageDataArray): Boolean; { Saves multiple images to given stream. If format supports only single level images and there are multiple images to be saved, they are saved one after another to the stream. If function fails stream position is not changed. Ext identifies desired image file format (jpg, png, dds, ...).} function SaveMultiImageToStream(const Ext: string; Stream: TStream; const Images: TDynImageDataArray): Boolean; { Saves multiple images to given memory location. If format supports only single level images and there are multiple images to be saved, they are saved one after another to the memory. Memory must be allocated and its size is passed in Size parameter in which number of written bytes is returned. Ext identifies desired image file format (jpg, png, dds, ...).} function SaveMultiImageToMemory(const Ext: string; Data: Pointer; var Size: LongInt; const Images: TDynImageDataArray): Boolean; { Manipulation Functions } { Creates identical copy of image data. Clone should be initialized by InitImage or it should be vaild image which will be freed by CloneImage.} function CloneImage(const Image: TImageData; var Clone: TImageData): Boolean; { Converts image to the given format.} function ConvertImage(var Image: TImageData; DestFormat: TImageFormat): Boolean; { Flips given image. Reverses the image along its horizontal axis - the top becomes the bottom and vice versa.} function FlipImage(var Image: TImageData): Boolean; { Mirrors given image. Reverses the image along its vertical axis the left side becomes the right and vice versa.} function MirrorImage(var Image: TImageData): Boolean; { Resizes given image to new dimensions. Nearest, bilinear, or bicubic filtering can be used. Input Image must already be created - use NewImage to create new images.} function ResizeImage(var Image: TImageData; NewWidth, NewHeight: LongInt; Filter: TResizeFilter): Boolean; { Swaps SrcChannel and DstChannel color or alpha channels of image. Use ChannelRed, ChannelBlue, ChannelGreen, ChannelAlpha constants to identify channels.} function SwapChannels(var Image: TImageData; SrcChannel, DstChannel: LongInt): Boolean; { Reduces the number of colors of the Image. Currently MaxColors must be in range <2, 4096>. Color reduction works also for alpha channel. Note that for large images and big number of colors it can be very slow. Output format of the image is the same as input format.} function ReduceColors(var Image: TImageData; MaxColors: LongInt): Boolean; { Generates mipmaps for image. Levels is the number of desired mipmaps levels with zero (or some invalid number) meaning all possible levels.} function GenerateMipMaps(const Image: TImageData; Levels: LongInt; var MipMaps: TDynImageDataArray): Boolean; { Maps image to existing palette producing image in ifIndex8 format. Pal must be allocated to at least Entries * SizeOf(TColor32Rec) bytes. As resulting image is in 8bit indexed format Entries must be lower or equal to 256.} function MapImageToPalette(var Image: TImageData; Pal: PPalette32; Entries: LongInt): Boolean; { Splits image into XChunks x YChunks subimages. Default size of each chunk is ChunkWidth x ChunkHeight. If PreserveSize si True chunks at the edges of the image are also ChunkWidth x ChunkHeight sized and empty space is filled with optional Fill pixels. After calling this function XChunks contains number of chunks along x axis and YChunks along y axis. To access chunk [X, Y] use this index: Chunks[Y * XChunks + X].} function SplitImage(var Image: TImageData; var Chunks: TDynImageDataArray; ChunkWidth, ChunkHeight: LongInt; var XChunks, YChunks: LongInt; PreserveSize: Boolean; Fill: Pointer = nil): Boolean; { Creates palette with MaxColors based on the colors of images in Images array. Use it when you want to convert several images to indexed format using single palette for all of them. If ConvertImages is True images in array are converted to indexed format using resulting palette. if it is False images are left intact and only resulting palatte is returned in Pal. Pal must be allocated to have at least MaxColors entries.} function MakePaletteForImages(var Images: TDynImageDataArray; Pal: PPalette32; MaxColors: LongInt; ConvertImages: Boolean): Boolean; { Rotates image by Angle degrees counterclockwise. All angles are allowed.} procedure RotateImage(var Image: TImageData; Angle: Single); { Drawing/Pixel functions } { Copies rectangular part of SrcImage to DstImage. No blending is performed - alpha is simply copied to destination image. Operates also with negative X and Y coordinates. Note that copying is fastest for images in the same data format (and slowest for images in special formats).} function CopyRect(const SrcImage: TImageData; SrcX, SrcY, Width, Height: LongInt; var DstImage: TImageData; DstX, DstY: LongInt): Boolean; { Fills given rectangle of image with given pixel fill data. Fill should point to the pixel in the same format as the given image is in.} function FillRect(var Image: TImageData; X, Y, Width, Height: LongInt; FillColor: Pointer): Boolean; { Replaces pixels with OldPixel in the given rectangle by NewPixel. OldPixel and NewPixel should point to the pixels in the same format as the given image is in.} function ReplaceColor(var Image: TImageData; X, Y, Width, Height: LongInt; OldColor, NewColor: Pointer): Boolean; { Stretches the contents of the source rectangle to the destination rectangle with optional resampling. No blending is performed - alpha is simply copied/resampled to destination image. Note that stretching is fastest for images in the same data format (and slowest for images in special formats).} function StretchRect(const SrcImage: TImageData; SrcX, SrcY, SrcWidth, SrcHeight: LongInt; var DstImage: TImageData; DstX, DstY, DstWidth, DstHeight: LongInt; Filter: TResizeFilter): Boolean; { Copies pixel of Image at [X, Y] to memory pointed at by Pixel. Doesn't work with special formats.} procedure GetPixelDirect(const Image: TImageData; X, Y: LongInt; Pixel: Pointer); { Copies pixel from memory pointed at by Pixel to Image at position [X, Y]. Doesn't work with special formats.} procedure SetPixelDirect(const Image: TImageData; X, Y: LongInt; Pixel: Pointer); { Function for getting pixel colors. Native pixel is read from Image and then translated to 32 bit ARGB. Works for all image formats (except special) so it is not very fast.} function GetPixel32(const Image: TImageData; X, Y: LongInt): TColor32Rec; { Procedure for setting pixel colors. Input 32 bit ARGB color is translated to native format and then written to Image. Works for all image formats (except special) so it is not very fast.} procedure SetPixel32(const Image: TImageData; X, Y: LongInt; const Color: TColor32Rec); { Function for getting pixel colors. Native pixel is read from Image and then translated to FP ARGB. Works for all image formats (except special) so it is not very fast.} function GetPixelFP(const Image: TImageData; X, Y: LongInt): TColorFPRec; { Procedure for setting pixel colors. Input FP ARGB color is translated to native format and then written to Image. Works for all image formats (except special) so it is not very fast.} procedure SetPixelFP(const Image: TImageData; X, Y: LongInt; const Color: TColorFPRec); { Palette Functions } { Allocates new palette with Entries ARGB color entries.} procedure NewPalette(Entries: LongInt; var Pal: PPalette32); { Frees given palette.} procedure FreePalette(var Pal: PPalette32); { Copies Count palette entries from SrcPal starting at index SrcIdx to DstPal at index DstPal.} procedure CopyPalette(SrcPal, DstPal: PPalette32; SrcIdx, DstIdx, Count: LongInt); { Returns index of color in palette or index of nearest color if exact match is not found. Pal must have at least Entries color entries.} function FindColor(Pal: PPalette32; Entries: LongInt; Color: TColor32): LongInt; { Creates grayscale palette where each color channel has the same value. Pal must have at least Entries color entries.} procedure FillGrayscalePalette(Pal: PPalette32; Entries: LongInt); { Creates palette with given bitcount for each channel. 2^(RBits + GBits + BBits) should be equl to Entries. Examples: (3, 3, 2) will create palette with all possible colors of R3G3B2 format and (8, 0, 0) will create palette with 256 shades of red. Pal must be allocated to at least Entries * SizeOf(TColor32Rec) bytes.} procedure FillCustomPalette(Pal: PPalette32; Entries: LongInt; RBits, GBits, BBits: Byte; Alpha: Byte = $FF); { Swaps SrcChannel and DstChannel color or alpha channels of palette. Use ChannelRed, ChannelBlue, ChannelGreen, ChannelAlpha constants to identify channels. Pal must be allocated to at least Entries * SizeOf(TColor32Rec) bytes.} procedure SwapChannelsOfPalette(Pal: PPalette32; Entries, SrcChannel, DstChannel: LongInt); { Options Functions } { Sets value of integer option specified by OptionId parameter. Option Ids are constans starting ImagingXXX.} function SetOption(OptionId, Value: LongInt): Boolean; { Returns value of integer option specified by OptionId parameter. If OptionId is invalid, InvalidOption is returned. Option Ids are constans starting ImagingXXX.} function GetOption(OptionId: LongInt): LongInt; { Pushes current values of all options on the stack. Returns True if successfull (max stack depth is 8 now). } function PushOptions: Boolean; { Pops back values of all options from the top of the stack. Returns True if successfull (max stack depth is 8 now). } function PopOptions: Boolean; { Image Format Functions } { Returns short information about given image format.} function GetImageFormatInfo(Format: TImageFormat; out Info: TImageFormatInfo): Boolean; { Returns size in bytes of Width x Height area of pixels. Works for all formats.} function GetPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt; { IO Functions } { User can set his own file IO functions used when loading from/saving to files by this function.} procedure SetUserFileIO(OpenProc: TOpenProc; CloseProc: TCloseProc; EofProc: TEofProc; SeekProc: TSeekProc; TellProc: TTellProc; ReadProc: TReadProc; WriteProc: TWriteProc); { Sets file IO functions to Imaging default.} procedure ResetFileIO; { Raw Image IO Functions } procedure ReadRawImageFromFile(const FileName: string; Width, Height: Integer; Format: TImageFormat; var Image: TImageData; Offset: Integer = 0; RowLength: Integer = 0); procedure ReadRawImageFromStream(Stream: TStream; Width, Height: Integer; Format: TImageFormat; var Image: TImageData; Offset: Integer = 0; RowLength: Integer = 0); procedure ReadRawImageFromMemory(Data: Pointer; DataSize: Integer; Width, Height: Integer; Format: TImageFormat; var Image: TImageData; Offset: Integer = 0; RowLength: Integer = 0); procedure ReadRawImageRect(Data: Pointer; Left, Top, Width, Height: Integer; var Image: TImageData; Offset: Integer = 0; RowLength: Integer = 0); procedure WriteRawImageToFile(const FileName: string; const Image: TImageData; Offset: Integer = 0; RowLength: Integer = 0); procedure WriteRawImageToStream(Stream: TStream; const Image: TImageData; Offset: Integer = 0; RowLength: Integer = 0); procedure WriteRawImageToMemory(Data: Pointer; DataSize: Integer; const Image: TImageData; Offset: Integer = 0; RowLength: Integer = 0); procedure WriteRawImageRect(Data: Pointer; Left, Top, Width, Height: Integer; const Image: TImageData; Offset: Integer = 0; RowLength: Integer = 0); { Convenience/helper Functions } procedure ResizeImageToFit(const SrcImage: TImageData; FitWidth, FitHeight: Integer; Filter: TResizeFilter; var DestImage: TImageData); { ------------------------------------------------------------------------ Other Imaging Stuff ------------------------------------------------------------------------} type { Set of TImageFormat enum.} TImageFormats = set of TImageFormat; { Record containg set of IO functions internaly used by image loaders/savers.} TIOFunctions = record Open: TOpenProc; Close: TCloseProc; Eof: TEofProc; Seek: TSeekProc; Tell: TTellProc; Read: TReadProc; Write: TWriteProc; end; PIOFunctions = ^TIOFunctions; type TFileFormatFeature = ( ffLoad, ffSave, ffMultiImage, ffReadOnSave, ffProgress, ffReadScanlines); TFileFormatFeatures = set of TFileFormatFeature; TMetadata = class; { Base class for various image file format loaders/savers which descend from this class. If you want to add support for new image file format the best way is probably to look at TImageFileFormat descendants' implementations that are already part of Imaging.} {$TYPEINFO ON} TImageFileFormat = class private FExtensions: TStringList; FMasks: TStringList; function GetCanLoad: Boolean; function GetCanSave: Boolean; function GetIsMultiImageFormat: Boolean; { Does various checks and actions before LoadData method is called.} function PrepareLoad(Handle: TImagingHandle; var Images: TDynImageDataArray; OnlyFirstFrame: Boolean): Boolean; { Processes some actions according to result of LoadData.} function PostLoadCheck(var Images: TDynImageDataArray; LoadResult: Boolean): Boolean; { Helper function to be called in SaveData methods of descendants (ensures proper index and sets FFirstIdx and FLastIdx for multi-images).} function PrepareSave(Handle: TImagingHandle; const Images: TDynImageDataArray; var Index: LongInt): Boolean; { Returns file open mode used for saving images. Depends on defined Features.} function GetSaveOpenMode: TOpenMode; protected FName: string; FFeatures: TFileFormatFeatures; FSupportedFormats: TImageFormats; FFirstIdx, FLastIdx: LongInt; FMetadata: TMetadata; { Descendants must override this method and define file format name and capabilities.} procedure Define; virtual; { Defines filename masks for this image file format. AMasks should be in format '*.ext1,*.ext2,umajo.*'.} procedure AddMasks(const AMasks: string); function GetFormatInfo(Format: TImageFormat): TImageFormatInfo; { Returns set of TImageData formats that can be saved in this file format without need for conversion.} function GetSupportedFormats: TImageFormats; virtual; { Method which must be overrided in descendants if they' are be capable of loading images. Images are already freed and length is set to zero whenever this method gets called. Also Handle is assured to be valid and contains data that passed TestFormat method's check.} function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; OnlyFirstFrame: Boolean): Boolean; virtual; { Method which must be overriden in descendants if they are be capable of saving images. Images are checked to have length >0 and that they contain valid images. For single-image file formats Index contain valid index to Images array (to image which should be saved). Multi-image formats should use FFirstIdx and FLastIdx fields to to get all images that are to be saved.} function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray; Index: LongInt): Boolean; virtual; { This method is called internaly by MakeCompatible when input image is in format not supported by this file format. Image is clone of MakeCompatible's input and Info is its extended format info.} procedure ConvertToSupported(var Image: TImageData; const Info: TImageFormatInfo); virtual; { Returns True if given image is supported for saving by this file format. Most file formats don't need to override this method. It checks (in this base class) if Image's format is in SupportedFromats set. But you may override it if you want further checks (proper widht and height for example).} function IsSupported(const Image: TImageData): Boolean; virtual; public constructor Create(AMetadata: TMetadata = nil); virtual; destructor Destroy; override; { Loads images from file source.} function LoadFromFile(const FileName: string; var Images: TDynImageDataArray; OnlyFirstLevel: Boolean = False): Boolean; { Loads images from stream source.} function LoadFromStream(Stream: TStream; var Images: TDynImageDataArray; OnlyFirstLevel: Boolean = False): Boolean; { Loads images from memory source.} function LoadFromMemory(Data: Pointer; Size: LongInt; var Images: TDynImageDataArray; OnlyFirstLevel: Boolean = False): Boolean; { Saves images to file. If format supports only single level images and there are multiple images to be saved, they are saved as sequence of independent images (for example SaveToFile saves sequence of files img000.jpg, img001.jpg ....).} function SaveToFile(const FileName: string; const Images: TDynImageDataArray; OnlyFirstLevel: Boolean = False): Boolean; { Saves images to stream. If format supports only single level images and there are multiple images to be saved, they are saved as sequence of independent images.} function SaveToStream(Stream: TStream; const Images: TDynImageDataArray; OnlyFirstLevel: Boolean = False): Boolean; { Saves images to memory. If format supports only single level images and there are multiple images to be saved, they are saved as sequence of independent images. Data must be already allocated and their size passed as Size parameter, number of written bytes is then returned in the same parameter.} function SaveToMemory(Data: Pointer; var Size: LongInt; const Images: TDynImageDataArray; OnlyFirstLevel: Boolean = False): Boolean; { Makes Image compatible with this file format (that means it is in one of data formats in Supported formats set). If input is already in supported format then Compatible just use value from input (Compatible := Image) so must not free it after you are done with it (image bits pointer points to input image's bits). If input is not in supported format then it is cloned to Compatible and concerted to one of supported formats (which one dependeds on this file format). If image is cloned MustBeFreed is set to True to indicated that you must free Compatible after you are done with it.} function MakeCompatible(const Image: TImageData; var Compatible: TImageData; out MustBeFreed: Boolean): Boolean; { Returns True if data located in source identified by Handle represent valid image in current format.} function TestFormat(Handle: TImagingHandle): Boolean; virtual; { Resturns True if the given FileName matches filter for this file format. For most formats it just checks filename extensions. It uses filename masks in from Masks property so it can recognize filenames like this 'umajoXXXumajo.j0j' if one of themasks is 'umajo*umajo.j?j'.} function TestFileName(const FileName: string): Boolean; { Descendants use this method to check if their options (registered with constant Ids for SetOption/GetOption interface or accessible as properties of descendants) have valid values and make necessary changes.} procedure CheckOptionsValidity; virtual; { Description of this format.} property Name: string read FName; { Indicates whether images in this format can be loaded.} property CanLoad: Boolean read GetCanLoad; { Indicates whether images in this format can be saved.} property CanSave: Boolean read GetCanSave; { Indicates whether images in this format can contain multiple image levels.} property IsMultiImageFormat: Boolean read GetIsMultiImageFormat; { List of filename extensions for this format.} property Extensions: TStringList read FExtensions; { List of filename masks that are used to associate filenames with TImageFileFormat descendants. Typical mask looks like '*.bmp' or 'texture.*' (supports file formats which use filename instead of extension to identify image files).} property Masks: TStringList read FMasks; { Set of TImageFormats supported by saving functions of this format. Images can be saved only in one those formats.} property SupportedFormats: TImageFormats read GetSupportedFormats; end; {$TYPEINFO OFF} { Class reference for TImageFileFormat class} TImageFileFormatClass = class of TImageFileFormat; { Physical resolution unit.} TResolutionUnit = ( ruSizeInMicroMeters, // value is pixel size in micrometers ruDpi, // value is pixels/dots per inch ruDpm, // value is pixels/dots per meter ruDpcm // value is pixels/dots per centimeter ); { Class for storage of single metadata item.} TMetadataItem = class public Id: string; ImageIndex: Integer; Value: Variant; end; { Metadata manager class.} TMetadata = class private FLoadMetaItems: TStringList; FSaveMetaItems: TStringList; procedure AddMetaToList(List: TStringList; const Id: string; const Value: Variant; ImageIndex: Integer); procedure ClearMetaList(List: TStringList); function GetMetaById(const Id: string): Variant; function GetMetaByIdMulti(const Id: string; ImageIndex: Integer): Variant; function GetMetaCount: Integer; function GetMetaByIdx(Index: Integer): TMetadataItem; function GetSaveMetaById(const Id: string): Variant; function GetSaveMetaByIdMulti(const Id: string; ImageIndex: Integer): Variant; procedure TranslateUnits(ResolutionUnit: TResolutionUnit; var XRes, YRes: Single); public constructor Create; destructor Destroy; override; procedure SetMetaItem(const Id: string; const Value: Variant; ImageIndex: Integer = 0); procedure SetMetaItemForSaving(const Id: string; const Value: Variant; ImageIndex: Integer = 0); function HasMetaItem(const Id: string; ImageIndex: Integer = 0): Boolean; function HasMetaItemForSaving(const Id: string; ImageIndex: Integer = 0): Boolean; procedure ClearMetaItems; procedure ClearMetaItemsForSaving; function GetMetaItemName(const Id: string; ImageIndex: Integer): string; { Copies loaded meta items to items-for-save stack. Use this when you want to save metadata that have been just loaded (e.g. resaving image in different file format but keeping the metadata).} procedure CopyLoadedMetaItemsForSaving; function GetPhysicalPixelSize(ResUnit: TResolutionUnit; var XSize, YSize: Single; MetaForSave: Boolean = False; ImageIndex: Integer = 0): Boolean; procedure SetPhysicalPixelSize(ResUnit: TResolutionUnit; XSize, YSize: Single; MetaForSave: Boolean = False; ImageIndex: Integer = 0); property MetaItems[const Id: string]: Variant read GetMetaById; property MetaItemsMulti[const Id: string; ImageIndex: Integer]: Variant read GetMetaByIdMulti; { Number of loaded metadata items.} property MetaItemCount: Integer read GetMetaCount; property MetaItemsByIdx[Index: Integer]: TMetadataItem read GetMetaByIdx; property MetaItemsForSaving[const Id: string]: Variant read GetSaveMetaById; property MetaItemsForSavingMulti[const Id: string; ImageIndex: Integer]: Variant read GetSaveMetaByIdMulti; end; const { Metadata item id constants } { Physical size of one pixel in micrometers. Type of value is Float.} SMetaPhysicalPixelSizeX = 'PhysicalPixelSizeX'; SMetaPhysicalPixelSizeY = 'PhysicalPixelSizeY'; { Delay for frame of animation (how long it should stay visible) in milliseconds. Type of value is Integer.} SMetaFrameDelay = 'FrameDelay'; { Number of times animation should be looped (0 = infinite looping). Type is Int. } SMetaAnimationLoops = 'AnimationLoops'; { Gamma correction value. Type is Float.} SMetaGamma = 'Gamma'; { Exposure value for HDR etc. Type is Float.} SMetaExposure = 'Exposure'; { EXIF image metadata raw blob.} SMetaExifBlob = 'ExifBlob'; { XMP image metadata raw blob.} SMetaXmpBlob = 'XmpBlob'; { IPTC image metadata raw blob.} SMetaIptcBlob = 'IptcBlob'; var GlobalMetadata: TMetadata; { Returns symbolic name of given format.} function GetFormatName(Format: TImageFormat): string; { Returns string with information about given Image.} function ImageToStr(const Image: TImageData): string; { Returns Imaging version string in format 'Major.Minor.Patch'.} function GetVersionStr: string; { If Condition is True then TruePart is retured, otherwise FalsePart is returned.} function IffFormat(Condition: Boolean; const TruePart, FalsePart: TImageFormat): TImageFormat; { Registers new option so it can be used by SetOption and GetOption functions. Returns True if registration was succesful - that is Id is valid and is not already taken by another option.} function RegisterOption(OptionId: LongInt; Variable: PLongInt): Boolean; { Registers new image loader/saver so it can be used by LoadFrom/SaveTo functions.} procedure RegisterImageFileFormat(AClass: TImageFileFormatClass); { Returns image format loader/saver according to given extension or nil if not found.} function FindImageFileFormatByExt(const Ext: string): TImageFileFormat; { Returns image format loader/saver according to given filename or nil if not found.} function FindImageFileFormatByName(const FileName: string): TImageFileFormat; { Returns image format loader/saver based on its class or nil if not found or not registered.} function FindImageFileFormatByClass(AClass: TImageFileFormatClass): TImageFileFormat; { Returns number of registered image file format loaders/saver.} function GetFileFormatCount: LongInt; { Returns image file format loader/saver at given index. Index must be in range [0..GetFileFormatCount - 1] otherwise nil is returned.} function GetFileFormatAtIndex(Index: LongInt): TImageFileFormat; { Returns filter string for usage with open and save picture dialogs which contains all registered image file formats. Set OpenFileFilter to True if you want filter for open dialog and to False if you want save dialog filter (formats that cannot save to files are not added then). For open dialog filter for all known graphic files (like All(*.jpg;*.png;....) is added too at the first index.} function GetImageFileFormatsFilter(OpenFileFilter: Boolean): string; { Returns file extension (without dot) of image format selected by given filter index. Used filter string is defined by GetImageFileFormatsFilter function. This function can be used with save dialogs (with filters created by GetImageFileFormatsFilter) to get the extension of file format selected in dialog quickly. Index is in range 1..N (as FilterIndex property of TOpenDialog/TSaveDialog)} function GetFilterIndexExtension(Index: LongInt; OpenFileFilter: Boolean): string; { Returns filter index of image file format of file specified by FileName. Used filter string is defined by GetImageFileFormatsFilter function. Returned index is in range 1..N (as FilterIndex property of TOpenDialog/TSaveDialog)} function GetFileNameFilterIndex(const FileName: string; OpenFileFilter: Boolean): LongInt; { Returns current IO functions.} function GetIO: TIOFunctions; { Raises EImagingError with given message.} procedure RaiseImaging(const Msg: string; const Args: array of const); overload; procedure RaiseImaging(const Msg: string); overload; {$IFDEF USE_INLINE}inline;{$ENDIF} const SImagingLibTitle = 'Vampyre Imaging Library'; implementation uses {$IFNDEF DONT_LINK_BITMAP} ImagingBitmap, {$ENDIF} {$IFNDEF DONT_LINK_JPEG} ImagingJpeg, {$ENDIF} {$IF not Defined(DONT_LINK_PNG) or not Defined(DONT_LINK_MNG) or not Defined(DONT_LINK_JNG)} ImagingNetworkGraphics, {$IFEND} {$IFNDEF DONT_LINK_GIF} ImagingGif, {$ENDIF} {$IFNDEF DONT_LINK_DDS} ImagingDds, {$ENDIF} {$IFNDEF DONT_LINK_TARGA} ImagingTarga, {$ENDIF} {$IFNDEF DONT_LINK_PNM} ImagingPortableMaps, {$ENDIF} {$IFNDEF DONT_LINK_RADHDR} ImagingRadiance, {$ENDIF} {$IFNDEF DONT_LINK_EXTRAS} ImagingExtras, {$ENDIF} //ImagingDebug, ImagingFormats, ImagingUtility, ImagingIO, Variants; resourcestring SExceptMsg = 'Exception Message'; SAllFilter = 'All Images'; SUnknownFormat = 'Unknown and unsupported format'; SErrorFreeImage = 'Error while freeing image. %s'; SErrorCloneImage = 'Error while cloning image. %s'; SErrorFlipImage = 'Error while flipping image. %s'; SErrorMirrorImage = 'Error while mirroring image. %s'; SErrorResizeImage = 'Error while resizing image. %s'; SErrorSwapImage = 'Error while swapping channels of image. %s'; SFileFormatCanNotLoad = 'Image Format "%s" does not support loading images.'; SFileFormatCanNotSave = 'Image Format "%s" does not support saving images.'; SErrorNewImage = 'Error while creating image data with params: Width=%d ' + 'Height=%d Format=%s.'; SErrorConvertImage = 'Error while converting image to format "%s". %s'; SImageInfo = 'Image @%p info: Width = %dpx, Height = %dpx, ' + 'Format = %s, Size = %.0n %s, Bits @%p, Palette @%p.'; SImageInfoInvalid = 'Access violation encountered when getting info on ' + 'image at address %p.'; SFileNotValid = 'File "%s" is not valid image in "%s" format.'; SStreamNotValid = 'Stream %p does not contain valid image in "%s" format.'; SMemoryNotValid = 'Memory %p (%d Bytes) does not contain valid image ' + 'in "%s" format.'; SErrorLoadingFile = 'Error while loading images from file "%s" (file format: %s).'; SErrorLoadingStream = 'Error while loading images from stream %p (file format: %s).'; SErrorLoadingMemory = 'Error while loading images from memory %p (%d Bytes) (file format: %s).'; SErrorSavingFile = 'Error while saving images to file "%s" (file format: %s).'; SErrorSavingStream = 'Error while saving images to stream %p (file format: %s).'; SErrorSavingMemory = 'Error while saving images to memory %p (%d Bytes) (file format: %s).'; SErrorFindColor = 'Error while finding color in palette @%p with %d entries.'; SErrorGrayscalePalette = 'Error while filling grayscale palette @%p with %d entries.'; SErrorCustomPalette = 'Error while filling custom palette @%p with %d entries.'; SErrorSwapPalette = 'Error while swapping channels of palette @%p with %d entries.'; SErrorReduceColors = 'Error while reducing number of colors of image to %d. %s'; SErrorGenerateMipMaps = 'Error while generating %d mipmap levels for image %s'; SImagesNotValid = 'One or more images are not valid.'; SErrorCopyRect = 'Error while copying rect from image %s to image %s.'; SErrorMapImage = 'Error while mapping image %s to palette.'; SErrorFillRect = 'Error while filling rectangle X:%d Y:%d W:%d H:%d in image %s'; SErrorSplitImage = 'Error while splitting image %s to %dx%d sized chunks.'; SErrorMakePaletteForImages = 'Error while making %d color palette for %d images.'; SErrorNewPalette = 'Error while creating new palette with %d entries'; SErrorFreePalette = 'Error while freeing palette @%p'; SErrorCopyPalette = 'Error while copying %d entries from palette @%p to @%p'; SErrorReplaceColor = 'Error while replacing colors in rectangle X:%d Y:%d W:%d H:%d of image %s'; SErrorRotateImage = 'Error while rotating image %s by %.2n degrees'; SErrorStretchRect = 'Error while stretching rect from image %s to image %s.'; SErrorEmptyStream = 'Input stream has no data. Check Position property.'; SErrorInvalidInputImage = 'Invalid input image.'; SErrorBadImage = 'Bad image detected.'; const // Initial size of array with options information InitialOptions = 256; // Max depth of the option stack OptionStackDepth = 8; // Do not change the default format now, its too late DefaultImageFormat: TImageFormat = ifA8R8G8B8; // Format used to create metadata IDs for frames loaded form multiimages. SMetaIdForSubImage = '%s/%d'; type TOptionArray = array of PLongInt; TOptionValueArray = array of LongInt; TOptionStack = class(TObject) private FStack: array[0..OptionStackDepth - 1] of TOptionValueArray; FPosition: LongInt; public constructor Create; destructor Destroy; override; function Push: Boolean; function Pop: Boolean; end; var // Currently set IO functions IO: TIOFunctions; // List with all registered TImageFileFormat classes ImageFileFormats: TList = nil; // Aarray with registered options (pointers to their values) Options: TOptionArray = nil; // Array containing addional infomation about every image format ImageFormatInfos: TImageFormatInfoArray; // Stack used by PushOptions/PopOtions functions OptionStack: TOptionStack = nil; var // Variable for ImagingColorReduction option ColorReductionMask: LongInt = $FF; // Variable for ImagingLoadOverrideFormat option LoadOverrideFormat: TImageFormat = ifUnknown; // Variable for ImagingSaveOverrideFormat option SaveOverrideFormat: TImageFormat = ifUnknown; // Variable for ImagingSaveOverrideFormat option MipMapFilter: TSamplingFilter = sfLinear; // Variable for ImagingBinaryTreshold option BinaryTreshold: Integer = 128; { Exceptions } constructor EImagingBadImage.Create; begin inherited Create(SErrorBadImage); end; { Internal unit functions } { Modifies option value to be in the allowed range. Works only for options registered in this unit.} function CheckOptionValue(OptionId, Value: LongInt): LongInt; forward; { Sets IO functions to file IO.} procedure SetFileIO; forward; { Sets IO functions to stream IO.} procedure SetStreamIO; forward; { Sets IO functions to memory IO.} procedure SetMemoryIO; forward; { Inits image format infos array.} procedure InitImageFormats; forward; { Freew image format infos array.} procedure FreeImageFileFormats; forward; { Creates options array and stack.} procedure InitOptions; forward; { Frees options array and stack.} procedure FreeOptions; forward; function UpdateExceptMessage(E: Exception; const MsgToPrepend: string; const Args: array of const): Exception; begin Result := E; E.Message := Format(MsgToPrepend, Args) + ' ' + SExceptMsg + ': ' + E.Message end; { ------------------------------------------------------------------------ Low Level Interface Functions ------------------------------------------------------------------------} { General Functions } procedure InitImage(var Image: TImageData); begin FillChar(Image, SizeOf(Image), 0); end; function NewImage(Width, Height: LongInt; Format: TImageFormat; var Image: TImageData): Boolean; var FInfo: PImageFormatInfo; begin Assert((Width > 0) and (Height >0)); Assert(IsImageFormatValid(Format)); Result := False; FreeImage(Image); try Image.Width := Width; Image.Height := Height; // Select default data format if selected if (Format = ifDefault) then Image.Format := DefaultImageFormat else Image.Format := Format; // Get extended format info FInfo := ImageFormatInfos[Image.Format]; if FInfo = nil then begin InitImage(Image); Exit; end; // Check image dimensions and calculate its size in bytes FInfo.CheckDimensions(FInfo.Format, Image.Width, Image.Height); Image.Size := FInfo.GetPixelsSize(FInfo.Format, Image.Width, Image.Height); if Image.Size = 0 then begin InitImage(Image); Exit; end; // Image bits are allocated and set to zeroes GetMem(Image.Bits, Image.Size); FillChar(Image.Bits^, Image.Size, 0); // Palette is allocated and set to zeroes if FInfo.PaletteEntries > 0 then begin GetMem(Image.Palette, FInfo.PaletteEntries * SizeOf(TColor32Rec)); FillChar(Image.Palette^, FInfo.PaletteEntries * SizeOf(TColor32Rec), 0); end; Result := TestImage(Image); except on E: Exception do begin FreeMem(Image.Bits); FreeMem(Image.Palette); InitImage(Image); raise UpdateExceptMessage(E, SErrorNewImage, [Width, Height, GetFormatName(Format)]); end; end; end; function TestImage(const Image: TImageData): Boolean; begin try Result := (LongInt(Image.Format) >= LongInt(Low(TImageFormat))) and (LongInt(Image.Format) <= LongInt(High(TImageFormat))) and (ImageFormatInfos[Image.Format] <> nil) and (Assigned(ImageFormatInfos[Image.Format].GetPixelsSize) and (ImageFormatInfos[Image.Format].GetPixelsSize(Image.Format, Image.Width, Image.Height) = Image.Size)); except // Possible int overflows or other errors Result := False; end; end; procedure FreeImage(var Image: TImageData); begin try if TestImage(Image) then begin FreeMemNil(Image.Bits); FreeMemNil(Image.Palette); end; InitImage(Image); except raise UpdateExceptMessage(GetExceptObject, SErrorFreeImage, [ImageToStr(Image)]); end; end; procedure FreeImagesInArray(var Images: TDynImageDataArray); var I: LongInt; begin if Length(Images) > 0 then begin for I := 0 to Length(Images) - 1 do FreeImage(Images[I]); SetLength(Images, 0); end; end; function TestImagesInArray(const Images: TDynImageDataArray): Boolean; var I: LongInt; begin if Length(Images) > 0 then begin Result := True; for I := 0 to Length(Images) - 1 do begin Result := Result and TestImage(Images[I]); if not Result then Break; end; end else Result := False; end; function DetermineFileFormat(const FileName: string): string; var I: LongInt; Fmt: TImageFileFormat; Handle: TImagingHandle; begin Assert(FileName <> ''); Result := ''; SetFileIO; Handle := IO.Open(PChar(FileName), omReadOnly); try // First file format according to FileName and test if the data in // file is really in that format for I := 0 to ImageFileFormats.Count - 1 do begin Fmt := TImageFileFormat(ImageFileFormats[I]); if Fmt.TestFileName(FileName) and Fmt.TestFormat(Handle) then begin Result := Fmt.Extensions[0]; Exit; end; end; // No file format was found with filename search so try data-based search for I := 0 to ImageFileFormats.Count - 1 do begin Fmt := TImageFileFormat(ImageFileFormats[I]); if Fmt.TestFormat(Handle) then begin Result := Fmt.Extensions[0]; Exit; end; end; finally IO.Close(Handle); end; end; function DetermineStreamFormat(Stream: TStream): string; var I: LongInt; Fmt: TImageFileFormat; Handle: TImagingHandle; begin Assert(Stream <> nil); Result := ''; SetStreamIO; Handle := IO.Open(Pointer(Stream), omReadOnly); try for I := 0 to ImageFileFormats.Count - 1 do begin Fmt := TImageFileFormat(ImageFileFormats[I]); if Fmt.TestFormat(Handle) then begin Result := Fmt.Extensions[0]; Exit; end; end; finally IO.Close(Handle); end; end; function DetermineMemoryFormat(Data: Pointer; Size: LongInt): string; var I: LongInt; Fmt: TImageFileFormat; Handle: TImagingHandle; IORec: TMemoryIORec; begin Assert((Data <> nil) and (Size > 0)); Result := ''; SetMemoryIO; IORec.Data := Data; IORec.Position := 0; IORec.Size := Size; Handle := IO.Open(@IORec, omReadOnly); try for I := 0 to ImageFileFormats.Count - 1 do begin Fmt := TImageFileFormat(ImageFileFormats[I]); if Fmt.TestFormat(Handle) then begin Result := Fmt.Extensions[0]; Exit; end; end; finally IO.Close(Handle); end; end; function IsFileFormatSupported(const FileName: string): Boolean; begin Result := FindImageFileFormatByName(FileName) <> nil; end; function EnumFileFormats(var Index: LongInt; var Name, DefaultExt, Masks: string; var CanSaveImages, IsMultiImageFormat: Boolean): Boolean; var FileFmt: TImageFileFormat; begin FileFmt := GetFileFormatAtIndex(Index); Result := FileFmt <> nil; if Result then begin Name := FileFmt.Name; DefaultExt := FileFmt.Extensions[0]; Masks := FileFmt.Masks.DelimitedText; CanSaveImages := FileFmt.CanSave; IsMultiImageFormat := FileFmt.IsMultiImageFormat; Inc(Index); end else begin Name := ''; DefaultExt := ''; Masks := ''; CanSaveImages := False; IsMultiImageFormat := False; end; end; { Loading Functions } function LoadImageFromFile(const FileName: string; var Image: TImageData): Boolean; var Format: TImageFileFormat; IArray: TDynImageDataArray; I: LongInt; begin Assert(FileName <> ''); Result := False; Format := FindImageFileFormatByExt(DetermineFileFormat(FileName)); if Format <> nil then begin FreeImage(Image); Result := Format.LoadFromFile(FileName, IArray, True); if Result and (Length(IArray) > 0) then begin Image := IArray[0]; for I := 1 to Length(IArray) - 1 do FreeImage(IArray[I]); end else Result := False; end; end; function LoadImageFromStream(Stream: TStream; var Image: TImageData): Boolean; var Format: TImageFileFormat; IArray: TDynImageDataArray; I: LongInt; begin Assert(Stream <> nil); if Stream.Size - Stream.Position = 0 then RaiseImaging(SErrorEmptyStream, []); Result := False; Format := FindImageFileFormatByExt(DetermineStreamFormat(Stream)); if Format <> nil then begin FreeImage(Image); Result := Format.LoadFromStream(Stream, IArray, True); if Result and (Length(IArray) > 0) then begin Image := IArray[0]; for I := 1 to Length(IArray) - 1 do FreeImage(IArray[I]); end else Result := False; end; end; function LoadImageFromMemory(Data: Pointer; Size: LongInt; var Image: TImageData): Boolean; var Format: TImageFileFormat; IArray: TDynImageDataArray; I: LongInt; begin Assert((Data <> nil) and (Size > 0)); Result := False; Format := FindImageFileFormatByExt(DetermineMemoryFormat(Data, Size)); if Format <> nil then begin FreeImage(Image); Result := Format.LoadFromMemory(Data, Size, IArray, True); if Result and (Length(IArray) > 0) then begin Image := IArray[0]; for I := 1 to Length(IArray) - 1 do FreeImage(IArray[I]); end else Result := False; end; end; function LoadMultiImageFromFile(const FileName: string; var Images: TDynImageDataArray): Boolean; var Format: TImageFileFormat; begin Assert(FileName <> ''); Result := False; Format := FindImageFileFormatByExt(DetermineFileFormat(FileName)); if Format <> nil then begin FreeImagesInArray(Images); Result := Format.LoadFromFile(FileName, Images); end; end; function LoadMultiImageFromStream(Stream: TStream; var Images: TDynImageDataArray): Boolean; var Format: TImageFileFormat; begin Assert(Stream <> nil); if Stream.Size - Stream.Position = 0 then RaiseImaging(SErrorEmptyStream, []); Result := False; Format := FindImageFileFormatByExt(DetermineStreamFormat(Stream)); if Format <> nil then begin FreeImagesInArray(Images); Result := Format.LoadFromStream(Stream, Images); end; end; function LoadMultiImageFromMemory(Data: Pointer; Size: LongInt; var Images: TDynImageDataArray): Boolean; var Format: TImageFileFormat; begin Assert((Data <> nil) and (Size > 0)); Result := False; Format := FindImageFileFormatByExt(DetermineMemoryFormat(Data, Size)); if Format <> nil then begin FreeImagesInArray(Images); Result := Format.LoadFromMemory(Data, Size, Images); end; end; { Saving Functions } function SaveImageToFile(const FileName: string; const Image: TImageData): Boolean; var Format: TImageFileFormat; IArray: TDynImageDataArray; begin Assert(FileName <> ''); Result := False; Format := FindImageFileFormatByName(FileName); if Format <> nil then begin SetLength(IArray, 1); IArray[0] := Image; Result := Format.SaveToFile(FileName, IArray, True); end; end; function SaveImageToStream(const Ext: string; Stream: TStream; const Image: TImageData): Boolean; var Format: TImageFileFormat; IArray: TDynImageDataArray; begin Assert((Ext <> '') and (Stream <> nil)); Result := False; Format := FindImageFileFormatByExt(Ext); if Format <> nil then begin SetLength(IArray, 1); IArray[0] := Image; Result := Format.SaveToStream(Stream, IArray, True); end; end; function SaveImageToMemory(const Ext: string; Data: Pointer; var Size: LongInt; const Image: TImageData): Boolean; var Format: TImageFileFormat; IArray: TDynImageDataArray; begin Assert((Ext <> '') and (Data <> nil) and (Size > 0)); Result := False; Format := FindImageFileFormatByExt(Ext); if Format <> nil then begin SetLength(IArray, 1); IArray[0] := Image; Result := Format.SaveToMemory(Data, Size, IArray, True); end; end; function SaveMultiImageToFile(const FileName: string; const Images: TDynImageDataArray): Boolean; var Format: TImageFileFormat; begin Assert(FileName <> ''); Result := False; Format := FindImageFileFormatByName(FileName); if Format <> nil then Result := Format.SaveToFile(FileName, Images); end; function SaveMultiImageToStream(const Ext: string; Stream: TStream; const Images: TDynImageDataArray): Boolean; var Format: TImageFileFormat; begin Assert((Ext <> '') and (Stream <> nil)); Result := False; Format := FindImageFileFormatByExt(Ext); if Format <> nil then Result := Format.SaveToStream(Stream, Images); end; function SaveMultiImageToMemory(const Ext: string; Data: Pointer; var Size: LongInt; const Images: TDynImageDataArray): Boolean; var Format: TImageFileFormat; begin Assert((Ext <> '') and (Data <> nil) and (Size > 0)); Result := False; Format := FindImageFileFormatByExt(Ext); if Format <> nil then Result := Format.SaveToMemory(Data, Size, Images); end; { Manipulation Functions } function CloneImage(const Image: TImageData; var Clone: TImageData): Boolean; var Info: PImageFormatInfo; begin Result := False; if TestImage(Image) then try if TestImage(Clone) and (Image.Bits <> Clone.Bits) then FreeImage(Clone) else InitImage(Clone); Info := ImageFormatInfos[Image.Format]; Clone.Width := Image.Width; Clone.Height := Image.Height; Clone.Format := Image.Format; Clone.Size := Image.Size; if Info.PaletteEntries > 0 then begin GetMem(Clone.Palette, Info.PaletteEntries * SizeOf(TColor32Rec)); Move(Image.Palette^, Clone.Palette^, Info.PaletteEntries * SizeOf(TColor32Rec)); end; GetMem(Clone.Bits, Clone.Size); Move(Image.Bits^, Clone.Bits^, Clone.Size); Result := True; except raise UpdateExceptMessage(GetExceptObject, SErrorCloneImage, [ImageToStr(Image)]); end; end; function ConvertImage(var Image: TImageData; DestFormat: TImageFormat): Boolean; var NewData: Pointer; NewPal: PPalette32; NewSize, NumPixels: LongInt; SrcInfo, DstInfo: PImageFormatInfo; begin Assert(IsImageFormatValid(DestFormat)); Result := False; if TestImage(Image) then with Image do try // If default format is set we use DefaultImageFormat if DestFormat = ifDefault then DestFormat := DefaultImageFormat; SrcInfo := ImageFormatInfos[Format]; DstInfo := ImageFormatInfos[DestFormat]; if SrcInfo = DstInfo then begin // There is nothing to convert - src is alredy in dest format Result := True; Exit; end; // Exit Src or Dest format is invalid if (SrcInfo = nil) or (DstInfo = nil) then Exit; // If dest format is just src with swapped channels we call // SwapChannels instead if (SrcInfo.RBSwapFormat = DestFormat) and (DstInfo.RBSwapFormat = SrcInfo.Format) then begin Result := SwapChannels(Image, ChannelRed, ChannelBlue); Image.Format := SrcInfo.RBSwapFormat; Exit; end; if (not SrcInfo.IsSpecial) and (not DstInfo.IsSpecial) then begin NumPixels := Width * Height; NewSize := NumPixels * DstInfo.BytesPerPixel; GetMem(NewData, NewSize); FillChar(NewData^, NewSize, 0); GetMem(NewPal, DstInfo.PaletteEntries * SizeOf(TColor32Rec)); FillChar(NewPal^, DstInfo.PaletteEntries * SizeOf(TColor32Rec), 0); if SrcInfo.IsIndexed then begin // Source: indexed format if DstInfo.IsIndexed then IndexToIndex(NumPixels, Bits, NewData, SrcInfo, DstInfo, Palette, NewPal) else if DstInfo.HasGrayChannel then IndexToGray(NumPixels, Bits, NewData, SrcInfo, DstInfo, Palette) else if DstInfo.IsFloatingPoint then IndexToFloat(NumPixels, Bits, NewData, SrcInfo, DstInfo, Palette) else IndexToChannel(NumPixels, Bits, NewData, SrcInfo, DstInfo, Palette); end else if SrcInfo.HasGrayChannel then begin // Source: grayscale format if DstInfo.IsIndexed then GrayToIndex(NumPixels, Bits, NewData, SrcInfo, DstInfo, NewPal) else if DstInfo.HasGrayChannel then GrayToGray(NumPixels, Bits, NewData, SrcInfo, DstInfo) else if DstInfo.IsFloatingPoint then GrayToFloat(NumPixels, Bits, NewData, SrcInfo, DstInfo) else GrayToChannel(NumPixels, Bits, NewData, SrcInfo, DstInfo); end else if SrcInfo.IsFloatingPoint then begin // Source: floating point format if DstInfo.IsIndexed then FloatToIndex(NumPixels, Bits, NewData, SrcInfo, DstInfo, NewPal) else if DstInfo.HasGrayChannel then FloatToGray(NumPixels, Bits, NewData, SrcInfo, DstInfo) else if DstInfo.IsFloatingPoint then FloatToFloat(NumPixels, Bits, NewData, SrcInfo, DstInfo) else FloatToChannel(NumPixels, Bits, NewData, SrcInfo, DstInfo); end else begin // Source: standard multi channel image if DstInfo.IsIndexed then ChannelToIndex(NumPixels, Bits, NewData, SrcInfo, DstInfo, NewPal) else if DstInfo.HasGrayChannel then ChannelToGray(NumPixels, Bits, NewData, SrcInfo, DstInfo) else if DstInfo.IsFloatingPoint then ChannelToFloat(NumPixels, Bits, NewData, SrcInfo, DstInfo) else ChannelToChannel(NumPixels, Bits, NewData, SrcInfo, DstInfo); end; FreeMemNil(Bits); FreeMemNil(Palette); Format := DestFormat; Bits := NewData; Size := NewSize; Palette := NewPal; end else ConvertSpecial(Image, SrcInfo, DstInfo); Assert(SrcInfo.Format <> Image.Format); Result := True; except raise UpdateExceptMessage(GetExceptObject, SErrorConvertImage, [GetFormatName(DestFormat), ImageToStr(Image)]); end; end; function FlipImage(var Image: TImageData): Boolean; var P1, P2, Buff: Pointer; WidthBytes, I: LongInt; OldFmt: TImageFormat; begin Result := False; OldFmt := Image.Format; if TestImage(Image) then with Image do try if ImageFormatInfos[OldFmt].IsSpecial then ConvertImage(Image, ifDefault); WidthBytes := Width * ImageFormatInfos[Format].BytesPerPixel; GetMem(Buff, WidthBytes); try // Swap all scanlines of image for I := 0 to Height div 2 - 1 do begin P1 := @PByteArray(Bits)[I * WidthBytes]; P2 := @PByteArray(Bits)[(Height - I - 1) * WidthBytes]; Move(P1^, Buff^, WidthBytes); Move(P2^, P1^, WidthBytes); Move(Buff^, P2^, WidthBytes); end; finally FreeMemNil(Buff); end; if OldFmt <> Format then ConvertImage(Image, OldFmt); Result := True; except RaiseImaging(SErrorFlipImage, [ImageToStr(Image)]); end; end; function MirrorImage(var Image: TImageData): Boolean; var Scanline: PByte; Buff: TColorFPRec; Bpp, Y, X, WidthDiv2, WidthBytes, XLeft, XRight: LongInt; OldFmt: TImageFormat; begin Result := False; OldFmt := Image.Format; if TestImage(Image) then with Image do try if ImageFormatInfos[OldFmt].IsSpecial then ConvertImage(Image, ifDefault); Bpp := ImageFormatInfos[Format].BytesPerPixel; WidthDiv2 := Width div 2; WidthBytes := Width * Bpp; // Mirror all pixels on each scanline of image for Y := 0 to Height - 1 do begin Scanline := @PByteArray(Bits)[Y * WidthBytes]; XLeft := 0; XRight := (Width - 1) * Bpp; for X := 0 to WidthDiv2 - 1 do begin CopyPixel(@PByteArray(Scanline)[XLeft], @Buff, Bpp); CopyPixel(@PByteArray(Scanline)[XRight], @PByteArray(Scanline)[XLeft], Bpp); CopyPixel(@Buff, @PByteArray(Scanline)[XRight], Bpp); Inc(XLeft, Bpp); Dec(XRight, Bpp); end; end; if OldFmt <> Format then ConvertImage(Image, OldFmt); Result := True; except RaiseImaging(SErrorMirrorImage, [ImageToStr(Image)]); end; end; function ResizeImage(var Image: TImageData; NewWidth, NewHeight: LongInt; Filter: TResizeFilter): Boolean; var WorkImage: TImageData; begin Assert((NewWidth > 0) and (NewHeight > 0), 'New width or height is zero.'); Result := False; if TestImage(Image) and ((Image.Width <> NewWidth) or (Image.Height <> NewHeight)) then try InitImage(WorkImage); // Create new image with desired dimensions NewImage(NewWidth, NewHeight, Image.Format, WorkImage); // Stretch pixels from old image to new one StretchRect(Image, 0, 0, Image.Width, Image.Height, WorkImage, 0, 0, WorkImage.Width, WorkImage.Height, Filter); // Free old image and assign new image to it FreeMemNil(Image.Bits); if Image.Palette <> nil then begin FreeMem(WorkImage.Palette); WorkImage.Palette := Image.Palette; end; Image := WorkImage; Result := True; except raise UpdateExceptMessage(GetExceptObject, SErrorResizeImage, [ImageToStr(Image)]); end; end; function SwapChannels(var Image: TImageData; SrcChannel, DstChannel: LongInt): Boolean; var I, NumPixels: LongInt; Info: PImageFormatInfo; Swap, Alpha: Word; Data: PByte; Pix64: TColor64Rec; PixF: TColorFPRec; SwapF: Single; begin Assert((SrcChannel in [0..3]) and (DstChannel in [0..3])); Result := False; if TestImage(Image) and (SrcChannel <> DstChannel) then with Image do try NumPixels := Width * Height; Info := ImageFormatInfos[Format]; Data := Bits; if (Info.Format = ifR8G8B8) or ((Info.Format = ifA8R8G8B8) and (SrcChannel <> ChannelAlpha) and (DstChannel <> ChannelAlpha)) then begin // Swap channels of most common formats R8G8B8 and A8R8G8B8 (no alpha) for I := 0 to NumPixels - 1 do with PColor24Rec(Data)^ do begin Swap := Channels[SrcChannel]; Channels[SrcChannel] := Channels[DstChannel]; Channels[DstChannel] := Swap; Inc(Data, Info.BytesPerPixel); end; end else if Info.IsIndexed then begin // Swap palette channels of indexed images SwapChannelsOfPalette(Palette, Info.PaletteEntries, SrcChannel, DstChannel) end else if Info.IsFloatingPoint then begin // Swap channels of floating point images for I := 0 to NumPixels - 1 do begin FloatGetSrcPixel(Data, Info, PixF); with PixF do begin SwapF := Channels[SrcChannel]; Channels[SrcChannel] := Channels[DstChannel]; Channels[DstChannel] := SwapF; end; FloatSetDstPixel(Data, Info, PixF); Inc(Data, Info.BytesPerPixel); end; end else if Info.IsSpecial then begin // Swap channels of special format images ConvertImage(Image, ifDefault); SwapChannels(Image, SrcChannel, DstChannel); ConvertImage(Image, Info.Format); end else if Info.HasGrayChannel and Info.HasAlphaChannel and ((SrcChannel = ChannelAlpha) or (DstChannel = ChannelAlpha)) then begin for I := 0 to NumPixels - 1 do begin // If we have grayscale image with alpha and alpha is channel // to be swapped, we swap it. No other alternative for gray images, // just alpha and something GrayGetSrcPixel(Data, Info, Pix64, Alpha); Swap := Alpha; Alpha := Pix64.A; Pix64.A := Swap; GraySetDstPixel(Data, Info, Pix64, Alpha); Inc(Data, Info.BytesPerPixel); end; end else begin // Then do general swap on other channel image formats for I := 0 to NumPixels - 1 do begin ChannelGetSrcPixel(Data, Info, Pix64); with Pix64 do begin Swap := Channels[SrcChannel]; Channels[SrcChannel] := Channels[DstChannel]; Channels[DstChannel] := Swap; end; ChannelSetDstPixel(Data, Info, Pix64); Inc(Data, Info.BytesPerPixel); end; end; Result := True; except RaiseImaging(SErrorSwapImage, [ImageToStr(Image)]); end; end; function ReduceColors(var Image: TImageData; MaxColors: LongInt): Boolean; var TmpInfo: TImageFormatInfo; Data, Index: PWord; I, NumPixels: LongInt; Pal: PPalette32; Col:PColor32Rec; OldFmt: TImageFormat; begin Result := False; if TestImage(Image) then with Image do try // First create temp image info and allocate output bits and palette MaxColors := ClampInt(MaxColors, 2, High(Word)); OldFmt := Format; FillChar(TmpInfo, SizeOf(TmpInfo), 0); TmpInfo.PaletteEntries := MaxColors; TmpInfo.BytesPerPixel := 2; NumPixels := Width * Height; GetMem(Data, NumPixels * TmpInfo.BytesPerPixel); GetMem(Pal, MaxColors * SizeOf(TColor32Rec)); ConvertImage(Image, ifA8R8G8B8); // We use median cut algorithm to create reduced palette and to // fill Data with indices to this palette ReduceColorsMedianCut(NumPixels, Bits, PByte(Data), ImageFormatInfos[Format], @TmpInfo, MaxColors, ColorReductionMask, Pal); Col := Bits; Index := Data; // Then we write reduced colors to the input image for I := 0 to NumPixels - 1 do begin Col.Color := Pal[Index^].Color; Inc(Col); Inc(Index); end; FreeMemNil(Data); FreeMemNil(Pal); // And convert it to its original format ConvertImage(Image, OldFmt); Result := True; except RaiseImaging(SErrorReduceColors, [MaxColors, ImageToStr(Image)]); end; end; function GenerateMipMaps(const Image: TImageData; Levels: LongInt; var MipMaps: TDynImageDataArray): Boolean; var Width, Height, I, Count: LongInt; Info: TImageFormatInfo; CompatibleCopy: TImageData; begin Result := False; if TestImage(Image) then try Width := Image.Width; Height := Image.Height; // We compute number of possible mipmap levels and if // the given levels are invalid or zero we use this value Count := GetNumMipMapLevels(Width, Height); if (Levels <= 0) or (Levels > Count) then Levels := Count; // If we have special format image we create copy to allow pixel access. // This is also done in FillMipMapLevel which is called for each level // but then the main big image would be converted to compatible // for every level. GetImageFormatInfo(Image.Format, Info); if Info.IsSpecial then begin InitImage(CompatibleCopy); CloneImage(Image, CompatibleCopy); ConvertImage(CompatibleCopy, ifDefault); end else CompatibleCopy := Image; FreeImagesInArray(MipMaps); SetLength(MipMaps, Levels); CloneImage(Image, MipMaps[0]); for I := 1 to Levels - 1 do begin Width := Width shr 1; Height := Height shr 1; if Width < 1 then Width := 1; if Height < 1 then Height := 1; FillMipMapLevel(CompatibleCopy, Width, Height, MipMaps[I]); end; if CompatibleCopy.Format <> MipMaps[0].Format then begin // Must convert smaller levels to proper format for I := 1 to High(MipMaps) do ConvertImage(MipMaps[I], MipMaps[0].Format); FreeImage(CompatibleCopy); end; Result := True; except RaiseImaging(SErrorGenerateMipMaps, [Levels, ImageToStr(Image)]); end; end; function MapImageToPalette(var Image: TImageData; Pal: PPalette32; Entries: LongInt): Boolean; function FindNearestColor(Pal: PPalette32; Entries: LongInt; Col: TColor32Rec): LongInt; var I, MinDif, Dif: LongInt; begin Result := 0; MinDif := 1020; for I := 0 to Entries - 1 do with Pal[I] do begin Dif := Abs(R - Col.R); if Dif > MinDif then Continue; Dif := Dif + Abs(G - Col.G); if Dif > MinDif then Continue; Dif := Dif + Abs(B - Col.B); if Dif > MinDif then Continue; Dif := Dif + Abs(A - Col.A); if Dif < MinDif then begin MinDif := Dif; Result := I; end; end; end; var I, MaxEntries: LongInt; PIndex: PByte; PColor: PColor32Rec; CloneARGB: TImageData; Info: PImageFormatInfo; begin Assert((Entries >= 2) and (Entries <= 256)); Result := False; if TestImage(Image) then try // We create clone of source image in A8R8G8B8 and // then recreate source image in ifIndex8 format // with palette taken from Pal parameter InitImage(CloneARGB); CloneImage(Image, CloneARGB); ConvertImage(CloneARGB, ifA8R8G8B8); FreeImage(Image); NewImage(CloneARGB.Width, CloneARGB.Height, ifIndex8, Image); Info := ImageFormatInfos[Image.Format]; MaxEntries := Min(Info.PaletteEntries, Entries); Move(Pal^, Image.Palette^, MaxEntries * SizeOf(TColor32Rec)); PIndex := Image.Bits; PColor := CloneARGB.Bits; // For every pixel of ARGB clone we find closest color in // given palette and assign its index to resulting image's pixel // procedure used here is very slow but simple and memory usage friendly // (contrary to other methods) for I := 0 to Image.Width * Image.Height - 1 do begin PIndex^ := Byte(FindNearestColor(Image.Palette, MaxEntries, PColor^)); Inc(PIndex); Inc(PColor); end; FreeImage(CloneARGB); Result := True; except raise UpdateExceptMessage(GetExceptObject, SErrorMapImage, [ImageToStr(Image)]); end; end; function SplitImage(var Image: TImageData; var Chunks: TDynImageDataArray; ChunkWidth, ChunkHeight: LongInt; var XChunks, YChunks: LongInt; PreserveSize: Boolean; Fill: Pointer): Boolean; var X, Y, XTrunc, YTrunc: LongInt; NotOnEdge: Boolean; Info: PImageFormatInfo; OldFmt: TImageFormat; begin Assert((ChunkWidth > 0) and (ChunkHeight > 0)); Result := False; OldFmt := Image.Format; FreeImagesInArray(Chunks); if TestImage(Image) then try Info := ImageFormatInfos[Image.Format]; if Info.IsSpecial then ConvertImage(Image, ifDefault); // We compute make sure that chunks are not larger than source image or negative ChunkWidth := ClampInt(ChunkWidth, 0, Image.Width); ChunkHeight := ClampInt(ChunkHeight, 0, Image.Height); // Number of chunks along X and Y axes is computed XChunks := Trunc(Ceil(Image.Width / ChunkWidth)); YChunks := Trunc(Ceil(Image.Height / ChunkHeight)); SetLength(Chunks, XChunks * YChunks); // For every chunk we create new image and copy a portion of // the source image to it. If chunk is on the edge of the source image // we fill enpty space with Fill pixel data if PreserveSize is set or // make the chunk smaller if it is not set for Y := 0 to YChunks - 1 do for X := 0 to XChunks - 1 do begin // Determine if current chunk is on the edge of original image NotOnEdge := ((X < XChunks - 1) and (Y < YChunks - 1)) or ((Image.Width mod ChunkWidth = 0) and (Image.Height mod ChunkHeight = 0)); if PreserveSize or NotOnEdge then begin // We should preserve chunk sizes or we are somewhere inside original image NewImage(ChunkWidth, ChunkHeight, Image.Format, Chunks[Y * XChunks + X]); if (not NotOnEdge) and (Fill <> nil) then FillRect(Chunks[Y * XChunks + X], 0, 0, ChunkWidth, ChunkHeight, Fill); CopyRect(Image, X * ChunkWidth, Y * ChunkHeight, ChunkWidth, ChunkHeight, Chunks[Y * XChunks + X], 0, 0); end else begin // Create smaller edge chunk XTrunc := Image.Width - X * ChunkWidth; YTrunc := Image.Height - Y * ChunkHeight; NewImage(XTrunc, YTrunc, Image.Format, Chunks[Y * XChunks + X]); CopyRect(Image, X * ChunkWidth, Y * ChunkHeight, XTrunc, YTrunc, Chunks[Y * XChunks + X], 0, 0); end; // If source image is in indexed format we copy its palette to chunk if Info.IsIndexed then begin Move(Image.Palette^, Chunks[Y * XChunks + X].Palette^, Info.PaletteEntries * SizeOf(TColor32Rec)); end; end; if OldFmt <> Image.Format then begin ConvertImage(Image, OldFmt); for X := 0 to Length(Chunks) - 1 do ConvertImage(Chunks[X], OldFmt); end; Result := True; except raise UpdateExceptMessage(GetExceptObject, SErrorSplitImage, [ImageToStr(Image), ChunkWidth, ChunkHeight]); end; end; function MakePaletteForImages(var Images: TDynImageDataArray; Pal: PPalette32; MaxColors: LongInt; ConvertImages: Boolean): Boolean; var I: Integer; SrcInfo, DstInfo: PImageFormatInfo; Target, TempImage: TImageData; DstFormat: TImageFormat; begin Assert((Pal <> nil) and (MaxColors > 0)); Result := False; InitImage(TempImage); if TestImagesInArray(Images) then try // Null the color histogram ReduceColorsMedianCut(0, nil, nil, nil, nil, 0, 0, nil, [raCreateHistogram]); for I := 0 to Length(Images) - 1 do begin SrcInfo := ImageFormatInfos[Images[I].Format]; if SrcInfo.IsIndexed or SrcInfo.IsSpecial then begin // create temp image in supported format for updating histogram CloneImage(Images[I], TempImage); ConvertImage(TempImage, ifA8R8G8B8); SrcInfo := ImageFormatInfos[TempImage.Format]; end else TempImage := Images[I]; // Update histogram with colors of each input image ReduceColorsMedianCut(TempImage.Width * TempImage.Height, TempImage.Bits, nil, SrcInfo, nil, MaxColors, ColorReductionMask, nil, [raUpdateHistogram]); if Images[I].Bits <> TempImage.Bits then FreeImage(TempImage); end; // Construct reduced color map from the histogram ReduceColorsMedianCut(0, nil, nil, nil, nil, MaxColors, ColorReductionMask, Pal, [raMakeColorMap]); if ConvertImages then begin DstFormat := ifIndex8; DstInfo := ImageFormatInfos[DstFormat]; MaxColors := Min(DstInfo.PaletteEntries, MaxColors); for I := 0 to Length(Images) - 1 do begin SrcInfo := ImageFormatInfos[Images[I].Format]; if SrcInfo.IsIndexed or SrcInfo.IsSpecial then begin // If source image is in format not supported by ReduceColorsMedianCut // we convert it ConvertImage(Images[I], ifA8R8G8B8); SrcInfo := ImageFormatInfos[Images[I].Format]; end; InitImage(Target); NewImage(Images[I].Width, Images[I].Height, DstFormat, Target); // We map each input image to reduced palette and replace // image in array with mapped image ReduceColorsMedianCut(Images[I].Width * Images[I].Height, Images[I].Bits, Target.Bits, SrcInfo, DstInfo, MaxColors, 0, nil, [raMapImage]); Move(Pal^, Target.Palette^, MaxColors * SizeOf(TColor32Rec)); FreeImage(Images[I]); Images[I] := Target; end; end; Result := True; except RaiseImaging(SErrorMakePaletteForImages, [MaxColors, Length(Images)]); end; end; procedure RotateImage(var Image: TImageData; Angle: Single); var OldFmt: TImageFormat; procedure XShear(var Src, Dst: TImageData; Row, Offset, Weight, Bpp: Integer); var I, J, XPos: Integer; PixSrc, PixLeft, PixOldLeft: TColor32Rec; LineDst: PByteArray; SrcPtr: PColor32; begin SrcPtr := @PByteArray(Src.Bits)[Row * Src.Width * Bpp]; LineDst := @PByteArray(Dst.Bits)[Row * Dst.Width * Bpp]; PixOldLeft.Color := 0; for I := 0 to Src.Width - 1 do begin CopyPixel(SrcPtr, @PixSrc, Bpp); for J := 0 to Bpp - 1 do PixLeft.Channels[J] := MulDiv(PixSrc.Channels[J], Weight, 256); XPos := I + Offset; if (XPos >= 0) and (XPos < Dst.Width) then begin for J := 0 to Bpp - 1 do PixSrc.Channels[J] := ClampToByte(PixSrc.Channels[J] - (PixLeft.Channels[J] - PixOldLeft.Channels[J])); CopyPixel(@PixSrc, @LineDst[XPos * Bpp], Bpp); end; PixOldLeft := PixLeft; Inc(PByte(SrcPtr), Bpp); end; XPos := Src.Width + Offset; if XPos < Dst.Width then CopyPixel(@PixOldLeft, @LineDst[XPos * Bpp], Bpp); end; procedure YShear(var Src, Dst: TImageData; Col, Offset, Weight, Bpp: Integer); var I, J, YPos: Integer; PixSrc, PixLeft, PixOldLeft: TColor32Rec; SrcPtr: PByte; begin SrcPtr := @PByteArray(Src.Bits)[Col * Bpp]; PixOldLeft.Color := 0; for I := 0 to Src.Height - 1 do begin CopyPixel(SrcPtr, @PixSrc, Bpp); for J := 0 to Bpp - 1 do PixLeft.Channels[J] := MulDiv(PixSrc.Channels[J], Weight, 256); YPos := I + Offset; if (YPos >= 0) and (YPos < Dst.Height) then begin for J := 0 to Bpp - 1 do PixSrc.Channels[J] := ClampToByte(PixSrc.Channels[J] - (PixLeft.Channels[J] - PixOldLeft.Channels[J])); CopyPixel(@PixSrc, @PByteArray(Dst.Bits)[(YPos * Dst.Width + Col) * Bpp], Bpp); end; PixOldLeft := PixLeft; Inc(SrcPtr, Src.Width * Bpp); end; YPos := Src.Height + Offset; if YPos < Dst.Height then CopyPixel(@PixOldLeft, @PByteArray(Dst.Bits)[(YPos * Dst.Width + Col) * Bpp], Bpp); end; procedure Rotate45(var Image: TImageData; Angle: Single); var TempImage1, TempImage2: TImageData; AngleRad, AngleTan, AngleSin, AngleCos, Shear: Single; I, DstWidth, DstHeight, SrcWidth, SrcHeight, Bpp: Integer; SrcFmt, TempFormat: TImageFormat; Info: TImageFormatInfo; begin AngleRad := Angle * Pi / 180; AngleSin := Sin(AngleRad); AngleCos := Cos(AngleRad); AngleTan := Sin(AngleRad / 2) / Cos(AngleRad / 2); SrcWidth := Image.Width; SrcHeight := Image.Height; SrcFmt := Image.Format; if not (SrcFmt in [ifR8G8B8..ifX8R8G8B8, ifGray8..ifGray32, ifA16Gray16]) then ConvertImage(Image, ifA8R8G8B8); TempFormat := Image.Format; GetImageFormatInfo(TempFormat, Info); Bpp := Info.BytesPerPixel; // 1st shear (horizontal) DstWidth := Trunc(SrcWidth + SrcHeight * Abs(AngleTan) + 0.5); DstHeight := SrcHeight; InitImage(TempImage1); NewImage(DstWidth, DstHeight, TempFormat, TempImage1); for I := 0 to DstHeight - 1 do begin if AngleTan >= 0 then Shear := (I + 0.5) * AngleTan else Shear := (I - DstHeight + 0.5) * AngleTan; XShear(Image, TempImage1, I, Floor(Shear), Trunc(255 * (Shear - Floor(Shear)) + 1), Bpp); end; // 2nd shear (vertical) FreeImage(Image); DstHeight := Trunc(SrcWidth * Abs(AngleSin) + SrcHeight * AngleCos + 0.5) + 1; InitImage(TempImage2); NewImage(DstWidth, DstHeight, TempFormat, TempImage2); if AngleSin >= 0 then Shear := (SrcWidth - 1) * AngleSin else Shear := (SrcWidth - DstWidth) * -AngleSin; for I := 0 to DstWidth - 1 do begin YShear(TempImage1, TempImage2, I, Floor(Shear), Trunc(255 * (Shear - Floor(Shear)) + 1), Bpp); Shear := Shear - AngleSin; end; // 3rd shear (horizontal) FreeImage(TempImage1); DstWidth := Trunc(SrcHeight * Abs(AngleSin) + SrcWidth * AngleCos + 0.5) + 1; NewImage(DstWidth, DstHeight, TempFormat, Image); if AngleSin >= 0 then Shear := (SrcWidth - 1) * AngleSin * -AngleTan else Shear := ((SrcWidth - 1) * -AngleSin + (1 - DstHeight)) * AngleTan; for I := 0 to DstHeight - 1 do begin XShear(TempImage2, Image, I, Floor(Shear), Trunc(255 * (Shear - Floor(Shear)) + 1), Bpp); Shear := Shear + AngleTan; end; FreeImage(TempImage2); if Image.Format <> SrcFmt then ConvertImage(Image, SrcFmt); end; procedure RotateMul90(var Image: TImageData; Angle: Integer); var RotImage: TImageData; X, Y, BytesPerPixel: Integer; RotPix, Pix: PByte; begin InitImage(RotImage); BytesPerPixel := ImageFormatInfos[Image.Format].BytesPerPixel; if ((Angle = 90) or (Angle = 270)) and (Image.Width <> Image.Height) then NewImage(Image.Height, Image.Width, Image.Format, RotImage) else NewImage(Image.Width, Image.Height, Image.Format, RotImage); RotPix := RotImage.Bits; case Angle of 90: begin for Y := 0 to RotImage.Height - 1 do begin Pix := @PByteArray(Image.Bits)[(Image.Width - Y - 1) * BytesPerPixel]; for X := 0 to RotImage.Width - 1 do begin CopyPixel(Pix, RotPix, BytesPerPixel); Inc(RotPix, BytesPerPixel); Inc(Pix, Image.Width * BytesPerPixel); end; end; end; 180: begin Pix := @PByteArray(Image.Bits)[((Image.Height - 1) * Image.Width + (Image.Width - 1)) * BytesPerPixel]; for Y := 0 to RotImage.Height - 1 do for X := 0 to RotImage.Width - 1 do begin CopyPixel(Pix, RotPix, BytesPerPixel); Inc(RotPix, BytesPerPixel); Dec(Pix, BytesPerPixel); end; end; 270: begin for Y := 0 to RotImage.Height - 1 do begin Pix := @PByteArray(Image.Bits)[((Image.Height - 1) * Image.Width + Y) * BytesPerPixel]; for X := 0 to RotImage.Width - 1 do begin CopyPixel(Pix, RotPix, BytesPerPixel); Inc(RotPix, BytesPerPixel); Dec(Pix, Image.Width * BytesPerPixel); end; end; end; end; FreeMemNil(Image.Bits); RotImage.Palette := Image.Palette; Image := RotImage; end; begin if TestImage(Image) then try while Angle >= 360 do Angle := Angle - 360; while Angle < 0 do Angle := Angle + 360; if (Angle = 0) or (Abs(Angle) = 360) then Exit; OldFmt := Image.Format; if ImageFormatInfos[Image.Format].IsSpecial then ConvertImage(Image, ifDefault); if (Angle > 45) and (Angle <= 135) then begin RotateMul90(Image, 90); Angle := Angle - 90; end else if (Angle > 135) and (Angle <= 225) then begin RotateMul90(Image, 180); Angle := Angle - 180; end else if (Angle > 225) and (Angle <= 315) then begin RotateMul90(Image, 270); Angle := Angle - 270; end; if Angle <> 0 then Rotate45(Image, Angle); if OldFmt <> Image.Format then ConvertImage(Image, OldFmt); except raise UpdateExceptMessage(GetExceptObject, SErrorRotateImage, [ImageToStr(Image), Angle]); end; end; { Drawing/Pixel functions } function CopyRect(const SrcImage: TImageData; SrcX, SrcY, Width, Height: LongInt; var DstImage: TImageData; DstX, DstY: LongInt): Boolean; var Info: PImageFormatInfo; I, SrcWidthBytes, DstWidthBytes, MoveBytes: LongInt; SrcPointer, DstPointer: PByte; WorkImage: TImageData; OldFormat: TImageFormat; begin Result := False; OldFormat := ifUnknown; if TestImage(SrcImage) and TestImage(DstImage) then try // Make sure we are still copying image to image, not invalid pointer to protected memory ClipCopyBounds(SrcX, SrcY, Width, Height, DstX, DstY, SrcImage.Width, SrcImage.Height, Rect(0, 0, DstImage.Width, DstImage.Height)); if (Width > 0) and (Height > 0) then begin Info := ImageFormatInfos[DstImage.Format]; if Info.IsSpecial then begin // If dest image is in special format we convert it to default OldFormat := Info.Format; ConvertImage(DstImage, ifDefault); Info := ImageFormatInfos[DstImage.Format]; end; if SrcImage.Format <> DstImage.Format then begin // If images are in different format source is converted to dest's format InitImage(WorkImage); CloneImage(SrcImage, WorkImage); ConvertImage(WorkImage, DstImage.Format); end else WorkImage := SrcImage; MoveBytes := Width * Info.BytesPerPixel; DstWidthBytes := DstImage.Width * Info.BytesPerPixel; DstPointer := @PByteArray(DstImage.Bits)[DstY * DstWidthBytes + DstX * Info.BytesPerPixel]; SrcWidthBytes := WorkImage.Width * Info.BytesPerPixel; SrcPointer := @PByteArray(WorkImage.Bits)[SrcY * SrcWidthBytes + SrcX * Info.BytesPerPixel]; for I := 0 to Height - 1 do begin Move(SrcPointer^, DstPointer^, MoveBytes); Inc(SrcPointer, SrcWidthBytes); Inc(DstPointer, DstWidthBytes); end; // If dest image was in special format we convert it back if OldFormat <> ifUnknown then ConvertImage(DstImage, OldFormat); // Working image must be freed if it is not the same as source image if WorkImage.Bits <> SrcImage.Bits then FreeImage(WorkImage); Result := True; end; except RaiseImaging(SErrorCopyRect, [ImageToStr(SrcImage), ImageToStr(DstImage)]); end; end; function FillRect(var Image: TImageData; X, Y, Width, Height: LongInt; FillColor: Pointer): Boolean; var Info: PImageFormatInfo; I, J, ImageWidthBytes, RectWidthBytes, Bpp: Longint; LinePointer, PixPointer: PByte; OldFmt: TImageFormat; begin Result := False; if TestImage(Image) then try ClipRectBounds(X, Y, Width, Height, Rect(0, 0, Image.Width, Image.Height)); if (Width > 0) and (Height > 0) then begin OldFmt := Image.Format; if ImageFormatInfos[OldFmt].IsSpecial then ConvertImage(Image, ifDefault); Info := ImageFormatInfos[Image.Format]; Bpp := Info.BytesPerPixel; ImageWidthBytes := Image.Width * Bpp; RectWidthBytes := Width * Bpp; LinePointer := @PByteArray(Image.Bits)[Y * ImageWidthBytes + X * Bpp]; for I := 0 to Height - 1 do begin case Bpp of 1: FillMemoryByte(LinePointer, RectWidthBytes, PByte(FillColor)^); 2: FillMemoryWord(LinePointer, RectWidthBytes, PWord(FillColor)^); 4: FillMemoryLongWord(LinePointer, RectWidthBytes, PLongWord(FillColor)^); else PixPointer := LinePointer; for J := 0 to Width - 1 do begin CopyPixel(FillColor, PixPointer, Bpp); Inc(PixPointer, Bpp); end; end; Inc(LinePointer, ImageWidthBytes); end; if OldFmt <> Image.Format then ConvertImage(Image, OldFmt); end; Result := True; except RaiseImaging(SErrorFillRect, [X, Y, Width, Height, ImageToStr(Image)]); end; end; function ReplaceColor(var Image: TImageData; X, Y, Width, Height: LongInt; OldColor, NewColor: Pointer): Boolean; var Info: PImageFormatInfo; I, J, WidthBytes, Bpp: Longint; LinePointer, PixPointer: PByte; OldFmt: TImageFormat; begin Assert((OldColor <> nil) and (NewColor <> nil)); Result := False; if TestImage(Image) then try ClipRectBounds(X, Y, Width, Height, Rect(0, 0, Image.Width, Image.Height)); if (Width > 0) and (Height > 0) then begin OldFmt := Image.Format; if ImageFormatInfos[OldFmt].IsSpecial then ConvertImage(Image, ifDefault); Info := ImageFormatInfos[Image.Format]; Bpp := Info.BytesPerPixel; WidthBytes := Image.Width * Bpp; LinePointer := @PByteArray(Image.Bits)[Y * WidthBytes + X * Bpp]; for I := 0 to Height - 1 do begin PixPointer := LinePointer; for J := 0 to Width - 1 do begin if ComparePixels(PixPointer, OldColor, Bpp) then CopyPixel(NewColor, PixPointer, Bpp); Inc(PixPointer, Bpp); end; Inc(LinePointer, WidthBytes); end; if OldFmt <> Image.Format then ConvertImage(Image, OldFmt); end; Result := True; except RaiseImaging(SErrorReplaceColor, [X, Y, Width, Height, ImageToStr(Image)]); end; end; function StretchRect(const SrcImage: TImageData; SrcX, SrcY, SrcWidth, SrcHeight: LongInt; var DstImage: TImageData; DstX, DstY, DstWidth, DstHeight: LongInt; Filter: TResizeFilter): Boolean; var Info: PImageFormatInfo; WorkImage: TImageData; OldFormat: TImageFormat; Resampling: TSamplingFilter; begin Result := False; OldFormat := ifUnknown; if TestImage(SrcImage) and TestImage(DstImage) then try // Make sure we are still copying image to image, not invalid pointer to protected memory ClipStretchBounds(SrcX, SrcY, SrcWidth, SrcHeight, DstX, DstY, DstWidth, DstHeight, SrcImage.Width, SrcImage.Height, Rect(0, 0, DstImage.Width, DstImage.Height)); if (SrcWidth = DstWidth) and (SrcHeight = DstHeight) then begin // If source and dest rectangles have the same size call CopyRect Result := CopyRect(SrcImage, SrcX, SrcY, SrcWidth, SrcHeight, DstImage, DstX, DstY); end else if (SrcWidth > 0) and (SrcHeight > 0) and (DstWidth > 0) and (DstHeight > 0) then begin // If source and dest rectangles don't have the same size we do stretch Info := ImageFormatInfos[DstImage.Format]; if Info.IsSpecial then begin // If dest image is in special format we convert it to default OldFormat := Info.Format; ConvertImage(DstImage, ifDefault); Info := ImageFormatInfos[DstImage.Format]; end; if SrcImage.Format <> DstImage.Format then begin // If images are in different format source is converted to dest's format InitImage(WorkImage); CloneImage(SrcImage, WorkImage); ConvertImage(WorkImage, DstImage.Format); end else WorkImage := SrcImage; // Only pixel resize is supported for indexed images if Info.IsIndexed then Filter := rfNearest; if Filter = rfNearest then begin StretchNearest(WorkImage, SrcX, SrcY, SrcWidth, SrcHeight, DstImage, DstX, DstY, DstWidth, DstHeight); end else begin Resampling := sfNearest; case Filter of rfBilinear: Resampling := sfLinear; rfBicubic: Resampling := DefaultCubicFilter; rfLanczos: Resampling := sfLanczos; end; StretchResample(WorkImage, SrcX, SrcY, SrcWidth, SrcHeight, DstImage, DstX, DstY, DstWidth, DstHeight, Resampling); end; // If dest image was in special format we convert it back if OldFormat <> ifUnknown then ConvertImage(DstImage, OldFormat); // Working image must be freed if it is not the same as source image if WorkImage.Bits <> SrcImage.Bits then FreeImage(WorkImage); Result := True; end; except RaiseImaging(SErrorStretchRect, [ImageToStr(SrcImage), ImageToStr(DstImage)]); end; end; procedure GetPixelDirect(const Image: TImageData; X, Y: LongInt; Pixel: Pointer); var BytesPerPixel: LongInt; begin Assert(Pixel <> nil); BytesPerPixel := ImageFormatInfos[Image.Format].BytesPerPixel; CopyPixel(@PByteArray(Image.Bits)[(Y * Image.Width + X) * BytesPerPixel], Pixel, BytesPerPixel); end; procedure SetPixelDirect(const Image: TImageData; X, Y: LongInt; Pixel: Pointer); var BytesPerPixel: LongInt; begin Assert(Pixel <> nil); BytesPerPixel := ImageFormatInfos[Image.Format].BytesPerPixel; CopyPixel(Pixel, @PByteArray(Image.Bits)[(Y * Image.Width + X) * BytesPerPixel], BytesPerPixel); end; function GetPixel32(const Image: TImageData; X, Y: LongInt): TColor32Rec; var Info: PImageFormatInfo; Data: PByte; begin Info := ImageFormatInfos[Image.Format]; Data := @PByteArray(Image.Bits)[(Y * Image.Width + X) * Info.BytesPerPixel]; Result := GetPixel32Generic(Data, Info, Image.Palette); end; procedure SetPixel32(const Image: TImageData; X, Y: LongInt; const Color: TColor32Rec); var Info: PImageFormatInfo; Data: PByte; begin Info := ImageFormatInfos[Image.Format]; Data := @PByteArray(Image.Bits)[(Y * Image.Width + X) * Info.BytesPerPixel]; SetPixel32Generic(Data, Info, Image.Palette, Color); end; function GetPixelFP(const Image: TImageData; X, Y: LongInt): TColorFPRec; var Info: PImageFormatInfo; Data: PByte; begin Info := ImageFormatInfos[Image.Format]; Data := @PByteArray(Image.Bits)[(Y * Image.Width + X) * Info.BytesPerPixel]; Result := GetPixelFPGeneric(Data, Info, Image.Palette); end; procedure SetPixelFP(const Image: TImageData; X, Y: LongInt; const Color: TColorFPRec); var Info: PImageFormatInfo; Data: PByte; begin Info := ImageFormatInfos[Image.Format]; Data := @PByteArray(Image.Bits)[(Y * Image.Width + X) * Info.BytesPerPixel]; SetPixelFPGeneric(Data, Info, Image.Palette, Color); end; { Palette Functions } procedure NewPalette(Entries: LongInt; var Pal: PPalette32); begin Assert((Entries > 2) and (Entries <= 65535)); try GetMem(Pal, Entries * SizeOf(TColor32Rec)); FillChar(Pal^, Entries * SizeOf(TColor32Rec), $FF); except RaiseImaging(SErrorNewPalette, [Entries]); end; end; procedure FreePalette(var Pal: PPalette32); begin try FreeMemNil(Pal); except RaiseImaging(SErrorFreePalette, [Pal]); end; end; procedure CopyPalette(SrcPal, DstPal: PPalette32; SrcIdx, DstIdx, Count: LongInt); begin Assert((SrcPal <> nil) and (DstPal <> nil)); Assert((SrcIdx >= 0) and (DstIdx >= 0) and (Count >= 0)); try Move(SrcPal[SrcIdx], DstPal[DstIdx], Count * SizeOf(TColor32Rec)); except RaiseImaging(SErrorCopyPalette, [Count, SrcPal, DstPal]); end; end; function FindColor(Pal: PPalette32; Entries: LongInt; Color: TColor32): LongInt; var Col: TColor32Rec; I, MinDif, Dif: LongInt; begin Assert(Pal <> nil); Result := -1; Col.Color := Color; try // First try to find exact match for I := 0 to Entries - 1 do with Pal[I] do begin if (A = Col.A) and (R = Col.R) and (G = Col.G) and (B = Col.B) then begin Result := I; Exit; end; end; // If exact match was not found, find nearest color MinDif := 1020; for I := 0 to Entries - 1 do with Pal[I] do begin Dif := Abs(R - Col.R); if Dif > MinDif then Continue; Dif := Dif + Abs(G - Col.G); if Dif > MinDif then Continue; Dif := Dif + Abs(B - Col.B); if Dif > MinDif then Continue; Dif := Dif + Abs(A - Col.A); if Dif < MinDif then begin MinDif := Dif; Result := I; end; end; except RaiseImaging(SErrorFindColor, [Pal, Entries]); end; end; procedure FillGrayscalePalette(Pal: PPalette32; Entries: LongInt); var I: LongInt; begin Assert(Pal <> nil); try for I := 0 to Entries - 1 do with Pal[I] do begin A := $FF; R := Byte(I); G := Byte(I); B := Byte(I); end; except RaiseImaging(SErrorGrayscalePalette, [Pal, Entries]); end; end; procedure FillCustomPalette(Pal: PPalette32; Entries: LongInt; RBits, GBits, BBits: Byte; Alpha: Byte = $FF); var I, TotalBits, MaxEntries: LongInt; begin Assert(Pal <> nil); TotalBits := RBits + GBits + BBits; MaxEntries := Min(Pow2Int(TotalBits), Entries); FillChar(Pal^, Entries * SizeOf(TColor32Rec), 0); try for I := 0 to MaxEntries - 1 do with Pal[I] do begin A := Alpha; if RBits > 0 then R := ((I shr Max(0, GBits + BBits - 1)) and (1 shl RBits - 1)) * 255 div (1 shl RBits - 1); if GBits > 0 then G := ((I shr Max(0, BBits - 1)) and (1 shl GBits - 1)) * 255 div (1 shl GBits - 1); if BBits > 0 then B := ((I shr 0) and (1 shl BBits - 1)) * 255 div (1 shl BBits - 1); end; except RaiseImaging(SErrorCustomPalette, [Pal, Entries]); end; end; procedure SwapChannelsOfPalette(Pal: PPalette32; Entries, SrcChannel, DstChannel: LongInt); var I: LongInt; Swap: Byte; begin Assert(Pal <> nil); Assert((SrcChannel in [0..3]) and (DstChannel in [0..3])); try for I := 0 to Entries - 1 do with Pal[I] do begin Swap := Channels[SrcChannel]; Channels[SrcChannel] := Channels[DstChannel]; Channels[DstChannel] := Swap; end; except RaiseImaging(SErrorSwapPalette, [Pal, Entries]); end; end; { Options Functions } function SetOption(OptionId, Value: LongInt): Boolean; begin Result := False; if (OptionId >= 0) and (OptionId < Length(Options)) and (Options[OptionID] <> nil) then begin Options[OptionID]^ := CheckOptionValue(OptionId, Value); Result := True; end; end; function GetOption(OptionId: LongInt): LongInt; begin Result := InvalidOption; if (OptionId >= 0) and (OptionId < Length(Options)) and (Options[OptionID] <> nil) then begin Result := Options[OptionID]^; end; end; function PushOptions: Boolean; begin Result := OptionStack.Push; end; function PopOptions: Boolean; begin Result := OptionStack.Pop; end; { Image Format Functions } function GetImageFormatInfo(Format: TImageFormat; out Info: TImageFormatInfo): Boolean; begin FillChar(Info, SizeOf(Info), 0); if ImageFormatInfos[Format] <> nil then begin Info := ImageFormatInfos[Format]^; Result := True; end else Result := False; end; function GetPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt; begin if ImageFormatInfos[Format] <> nil then Result := ImageFormatInfos[Format].GetPixelsSize(Format, Width, Height) else Result := 0; end; { IO Functions } procedure SetUserFileIO(OpenProc: TOpenProc; CloseProc: TCloseProc; EofProc: TEofProc; SeekProc: TSeekProc; TellProc: TTellProc; ReadProc: TReadProc; WriteProc: TWriteProc); begin FileIO.Open := OpenProc; FileIO.Close := CloseProc; FileIO.Eof := EofProc; FileIO.Seek := SeekProc; FileIO.Tell := TellProc; FileIO.Read := ReadProc; FileIO.Write := WriteProc; end; procedure ResetFileIO; begin FileIO := OriginalFileIO; end; { Raw Image IO Functions } procedure ReadRawImage(Handle: TImagingHandle; Width, Height: Integer; Format: TImageFormat; out Image: TImageData; Offset, RowLength: Integer); var WidthBytes, I: Integer; Info: PImageFormatInfo; begin Info := ImageFormatInfos[Format]; // Calc scanline size WidthBytes := Info.GetPixelsSize(Format, Width, 1); if RowLength = 0 then RowLength := WidthBytes; // Create new image if needed - don't need to allocate new one if there is already // one with desired size and format if (Image.Width <> Width) or (Image.Height <> Height) or (Image.Format <> Format) then NewImage(Width, Height, Format, Image); // Move past the header IO.Seek(Handle, Offset, smFromCurrent); // Read scanlines from input for I := 0 to Height - 1 do begin IO.Read(Handle, @PByteArray(Image.Bits)[I * WidthBytes], WidthBytes); IO.Seek(Handle, RowLength - WidthBytes, smFromCurrent); end; end; procedure ReadRawImageFromFile(const FileName: string; Width, Height: Integer; Format: TImageFormat; var Image: TImageData; Offset, RowLength: Integer); var Handle: TImagingHandle; begin Assert(FileName <> ''); // Set IO ops to file ops and open given file SetFileIO; Handle := IO.Open(PChar(FileName), omReadOnly); try ReadRawImage(Handle, Width, Height, Format, Image, Offset, RowLength); finally IO.Close(Handle); end; end; procedure ReadRawImageFromStream(Stream: TStream; Width, Height: Integer; Format: TImageFormat; var Image: TImageData; Offset, RowLength: Integer); var Handle: TImagingHandle; begin Assert(Stream <> nil); if Stream.Size - Stream.Position = 0 then RaiseImaging(SErrorEmptyStream, []); // Set IO ops to stream ops and open given stream SetStreamIO; Handle := IO.Open(Pointer(Stream), omReadOnly); try ReadRawImage(Handle, Width, Height, Format, Image, Offset, RowLength); finally IO.Close(Handle); end; end; procedure ReadRawImageFromMemory(Data: Pointer; DataSize: Integer; Width, Height: Integer; Format: TImageFormat; var Image: TImageData; Offset, RowLength: Integer); var Handle: TImagingHandle; MemRec: TMemoryIORec; begin Assert((Data <> nil) and (DataSize > 0)); // Set IO ops to memory ops and open given stream SetMemoryIO; MemRec := PrepareMemIO(Data, DataSize); Handle := IO.Open(@MemRec, omReadOnly); try ReadRawImage(Handle, Width, Height, Format, Image, Offset, RowLength); finally IO.Close(Handle); end; end; procedure ReadRawImageRect(Data: Pointer; Left, Top, Width, Height: Integer; var Image: TImageData; Offset, RowLength: Integer); var DestScanBytes, RectBytes, I: Integer; Info: PImageFormatInfo; Src, Dest: PByte; begin Assert(Data <> nil); Assert((Left + Width <= Image.Width) and (Top + Height <= Image.Height)); Info := ImageFormatInfos[Image.Format]; // Calc scanline size DestScanBytes := Info.GetPixelsSize(Info.Format, Image.Width, 1); RectBytes := Info.GetPixelsSize(Info.Format, Width, 1); if RowLength = 0 then RowLength := RectBytes; Src := Data; Dest := @PByteArray(Image.Bits)[Top * DestScanBytes + Info.GetPixelsSize(Info.Format, Left, 1)]; // Move past the header Inc(Src, Offset); // Read lines into rect in the existing image for I := 0 to Height - 1 do begin Move(Src^, Dest^, RectBytes); Inc(Src, RowLength); Inc(Dest, DestScanBytes); end; end; procedure WriteRawImage(Handle: TImagingHandle; const Image: TImageData; Offset, RowLength: Integer); var WidthBytes, I: Integer; Info: PImageFormatInfo; begin Info := ImageFormatInfos[Image.Format]; // Calc scanline size WidthBytes := Info.GetPixelsSize(Image.Format, Image.Width, 1); if RowLength = 0 then RowLength := WidthBytes; // Move past the header IO.Seek(Handle, Offset, smFromCurrent); // Write scanlines to output for I := 0 to Image.Height - 1 do begin IO.Write(Handle, @PByteArray(Image.Bits)[I * WidthBytes], WidthBytes); IO.Seek(Handle, RowLength - WidthBytes, smFromCurrent); end; end; procedure WriteRawImageToFile(const FileName: string; const Image: TImageData; Offset, RowLength: Integer); var Handle: TImagingHandle; begin Assert(FileName <> ''); // Set IO ops to file ops and open given file SetFileIO; Handle := IO.Open(PChar(FileName), omCreate); try WriteRawImage(Handle, Image, Offset, RowLength); finally IO.Close(Handle); end; end; procedure WriteRawImageToStream(Stream: TStream; const Image: TImageData; Offset, RowLength: Integer); var Handle: TImagingHandle; begin Assert(Stream <> nil); // Set IO ops to stream ops and open given stream SetStreamIO; Handle := IO.Open(Pointer(Stream), omCreate); try WriteRawImage(Handle, Image, Offset, RowLength); finally IO.Close(Handle); end; end; procedure WriteRawImageToMemory(Data: Pointer; DataSize: Integer; const Image: TImageData; Offset, RowLength: Integer); var Handle: TImagingHandle; MemRec: TMemoryIORec; begin Assert((Data <> nil) and (DataSize > 0)); // Set IO ops to memory ops and open given stream SetMemoryIO; MemRec := PrepareMemIO(Data, DataSize); Handle := IO.Open(@MemRec, omCreate); try WriteRawImage(Handle, Image, Offset, RowLength); finally IO.Close(Handle); end; end; procedure WriteRawImageRect(Data: Pointer; Left, Top, Width, Height: Integer; const Image: TImageData; Offset, RowLength: Integer); var SrcScanBytes, RectBytes, I: Integer; Info: PImageFormatInfo; Src, Dest: PByte; begin Assert(Data <> nil); Assert((Left + Width <= Image.Width) and (Top + Height <= Image.Height)); Info := ImageFormatInfos[Image.Format]; // Calc scanline size SrcScanBytes := Info.GetPixelsSize(Info.Format, Image.Width, 1); RectBytes := Info.GetPixelsSize(Info.Format, Width, 1); if RowLength = 0 then RowLength := RectBytes; Src := @PByteArray(Image.Bits)[Top * SrcScanBytes + Info.GetPixelsSize(Info.Format, Left, 1)]; Dest := Data; // Move past the header Inc(Dest, Offset); // Write lines from rect of the existing image for I := 0 to Height - 1 do begin Move(Src^, Dest^, RectBytes); Inc(Dest, RowLength); Inc(Src, SrcScanBytes); end; end; { Convenience/helper Functions } procedure ResizeImageToFit(const SrcImage: TImageData; FitWidth, FitHeight: Integer; Filter: TResizeFilter; var DestImage: TImageData); var CurSize, FitSize, DestSize: TSize; begin if not TestImage(SrcImage) then raise EImagingError.Create(SErrorInvalidInputImage); FitSize.CX := FitWidth; FitSize.CY := FitHeight; CurSize.CX := SrcImage.Width; CurSize.CY := SrcImage.Height; DestSize := ImagingUtility.ScaleSizeToFit(CurSize, FitSize); NewImage(Max(DestSize.CX, 1), Max(DestSize.CY, 1), SrcImage.Format, DestImage); if SrcImage.Palette <> nil then CopyPalette(SrcImage.Palette, DestImage.Palette, 0, 0, ImageFormatInfos[SrcImage.Format].PaletteEntries); StretchRect(SrcImage, 0, 0, CurSize.CX, CurSize.CY, DestImage, 0, 0, DestSize.CX, DestSize.CY, Filter); end; { ------------------------------------------------------------------------ Other Imaging Stuff ------------------------------------------------------------------------} function GetFormatName(Format: TImageFormat): string; begin if ImageFormatInfos[Format] <> nil then Result := ImageFormatInfos[Format].Name else Result := SUnknownFormat; end; function ImageToStr(const Image: TImageData): string; var ImgSize: Integer; begin if TestImage(Image) then with Image do begin ImgSize := Size; if ImgSize > 8192 then ImgSize := ImgSize div 1024; Result := SysUtils.Format(SImageInfo, [@Image, Width, Height, GetFormatName(Format), ImgSize + 0.0, Iff(ImgSize = Size, 'B', 'KiB'), Bits, Palette]); end else Result := SysUtils.Format(SImageInfoInvalid, [@Image]); end; function GetVersionStr: string; begin Result := Format('%.1d.%.2d.%.1d', [ImagingVersionMajor, ImagingVersionMinor, ImagingVersionPatch]); end; function IffFormat(Condition: Boolean; const TruePart, FalsePart: TImageFormat): TImageFormat; begin if Condition then Result := TruePart else Result := FalsePart; end; procedure RegisterImageFileFormat(AClass: TImageFileFormatClass); begin Assert(AClass <> nil); if ImageFileFormats = nil then ImageFileFormats := TList.Create; if GlobalMetadata = nil then GlobalMetadata := TMetadata.Create; if ImageFileFormats <> nil then ImageFileFormats.Add(AClass.Create); end; function RegisterOption(OptionId: LongInt; Variable: PLongInt): Boolean; begin Result := False; if Options = nil then InitOptions; Assert(Variable <> nil); if OptionId >= Length(Options) then SetLength(Options, OptionId + InitialOptions); if (OptionId >= 0) and (OptionId < Length(Options)) {and (Options[OptionId] = nil) - must be able to override existing } then begin Options[OptionId] := Variable; Result := True; end; end; function FindImageFileFormatByExt(const Ext: string): TImageFileFormat; var I: LongInt; begin Result := nil; for I := ImageFileFormats.Count - 1 downto 0 do if TImageFileFormat(ImageFileFormats[I]).Extensions.IndexOf(Ext) >= 0 then begin Result := TImageFileFormat(ImageFileFormats[I]); Exit; end; end; function FindImageFileFormatByName(const FileName: string): TImageFileFormat; var I: LongInt; begin Result := nil; for I := ImageFileFormats.Count - 1 downto 0 do if TImageFileFormat(ImageFileFormats[I]).TestFileName(FileName) then begin Result := TImageFileFormat(ImageFileFormats[I]); Exit; end; end; function FindImageFileFormatByClass(AClass: TImageFileFormatClass): TImageFileFormat; var I: LongInt; begin Result := nil; for I := 0 to ImageFileFormats.Count - 1 do if TImageFileFormat(ImageFileFormats[I]) is AClass then begin Result := TObject(ImageFileFormats[I]) as TImageFileFormat; Break; end; end; function GetFileFormatCount: LongInt; begin Result := ImageFileFormats.Count; end; function GetFileFormatAtIndex(Index: LongInt): TImageFileFormat; begin if (Index >= 0) and (Index < ImageFileFormats.Count) then Result := TImageFileFormat(ImageFileFormats[Index]) else Result := nil; end; function GetImageFileFormatsFilter(OpenFileFilter: Boolean): string; var I, J, Count: LongInt; Descriptions: string; Filters, CurFilter: string; FileFormat: TImageFileFormat; begin Descriptions := ''; Filters := ''; Count := 0; for I := 0 to ImageFileFormats.Count - 1 do begin FileFormat := TObject(ImageFileFormats[I]) as TImageFileFormat; // If we are creating filter for save dialog and this format cannot save // files the we skip it if not OpenFileFilter and not FileFormat.CanSave then Continue; CurFilter := ''; for J := 0 to FileFormat.Masks.Count - 1 do begin CurFilter := CurFilter + FileFormat.Masks[J]; if J < FileFormat.Masks.Count - 1 then CurFilter := CurFilter + ';'; end; FmtStr(Descriptions, '%s%s (%s)|%2:s', [Descriptions, FileFormat.Name, CurFilter]); if Filters <> '' then FmtStr(Filters, '%s;%s', [Filters, CurFilter]) else Filters := CurFilter; if I < ImageFileFormats.Count - 1 then Descriptions := Descriptions + '|'; Inc(Count); end; if (Count > 1) and OpenFileFilter then FmtStr(Descriptions, '%s (%s)|%1:s|%s', [SAllFilter, Filters, Descriptions]); Result := Descriptions; end; function GetFilterIndexExtension(Index: LongInt; OpenFileFilter: Boolean): string; var I, Count: LongInt; FileFormat: TImageFileFormat; begin // -1 because filter indices are in 1..n range Index := Index - 1; Result := ''; if OpenFileFilter then begin if Index > 0 then Index := Index - 1; end; if (Index >= 0) and (Index < ImageFileFormats.Count) then begin Count := 0; for I := 0 to ImageFileFormats.Count - 1 do begin FileFormat := TObject(ImageFileFormats[I]) as TImageFileFormat; if not OpenFileFilter and not FileFormat.CanSave then Continue; if Index = Count then begin if FileFormat.Extensions.Count > 0 then Result := FileFormat.Extensions[0]; Exit; end; Inc(Count); end; end; end; function GetFileNameFilterIndex(const FileName: string; OpenFileFilter: Boolean): LongInt; var I: LongInt; FileFormat: TImageFileFormat; begin Result := 0; for I := 0 to ImageFileFormats.Count - 1 do begin FileFormat := TObject(ImageFileFormats[I]) as TImageFileFormat; if not OpenFileFilter and not FileFormat.CanSave then Continue; if FileFormat.TestFileName(FileName) then begin // +1 because filter indices are in 1..n range Inc(Result); if OpenFileFilter then Inc(Result); Exit; end; Inc(Result); end; Result := -1; end; function GetIO: TIOFunctions; begin Result := IO; end; procedure RaiseImaging(const Msg: string; const Args: array of const); var WholeMsg: string; begin WholeMsg := Msg; if GetExceptObject <> nil then begin WholeMsg := WholeMsg + ' ' + SExceptMsg + ': ' + GetExceptObject.Message; end; raise EImagingError.CreateFmt(WholeMsg, Args); end; procedure RaiseImaging(const Msg: string); begin RaiseImaging(Msg, []); end; { Internal unit functions } function CheckOptionValue(OptionId, Value: LongInt): LongInt; begin case OptionId of ImagingColorReductionMask: Result := ClampInt(Value, 0, $FF); ImagingLoadOverrideFormat, ImagingSaveOverrideFormat: Result := Iff(ImagingFormats.IsImageFormatValid(TImageFormat(Value)), Value, LongInt(ifUnknown)); ImagingMipMapFilter: Result := ClampInt(Value, Ord(Low(TSamplingFilter)), Ord(High(TSamplingFilter))); else Result := Value; end; end; procedure SetFileIO; begin IO := FileIO; end; procedure SetStreamIO; begin IO := StreamIO; end; procedure SetMemoryIO; begin IO := MemoryIO; end; procedure InitImageFormats; begin ImagingFormats.InitImageFormats(ImageFormatInfos); end; procedure FreeImageFileFormats; var I: LongInt; begin if ImageFileFormats <> nil then for I := 0 to ImageFileFormats.Count - 1 do TImageFileFormat(ImageFileFormats[I]).Free; FreeAndNil(ImageFileFormats); end; procedure InitOptions; begin SetLength(Options, InitialOptions); OptionStack := TOptionStack.Create; end; procedure FreeOptions; begin SetLength(Options, 0); FreeAndNil(OptionStack); end; { TImageFileFormat class implementation } constructor TImageFileFormat.Create(AMetadata: TMetadata); begin inherited Create; FName := SUnknownFormat; FExtensions := TStringList.Create; FMasks := TStringList.Create; if AMetadata = nil then FMetadata := GlobalMetadata else FMetadata := AMetadata; Define; end; destructor TImageFileFormat.Destroy; begin FExtensions.Free; FMasks.Free; inherited Destroy; end; procedure TImageFileFormat.Define; begin end; function TImageFileFormat.PrepareLoad(Handle: TImagingHandle; var Images: TDynImageDataArray; OnlyFirstFrame: Boolean): Boolean; begin FMetadata.ClearMetaItems; // Clear old metadata FreeImagesInArray(Images); SetLength(Images, 0); Result := Handle <> nil; end; function TImageFileFormat.PostLoadCheck(var Images: TDynImageDataArray; LoadResult: Boolean): Boolean; var I: LongInt; begin if not LoadResult then begin FreeImagesInArray(Images); SetLength(Images, 0); Result := False; end else begin Result := (Length(Images) > 0) and TestImagesInArray(Images); if Result then begin // Convert to overriden format if it is set if LoadOverrideFormat <> ifUnknown then for I := Low(Images) to High(Images) do ConvertImage(Images[I], LoadOverrideFormat); end; end; end; function TImageFileFormat.PrepareSave(Handle: TImagingHandle; const Images: TDynImageDataArray; var Index: Integer): Boolean; var Len, I: LongInt; begin CheckOptionsValidity; Result := False; if CanSave then begin Len := Length(Images); Assert(Len > 0); // If there are no images to be saved exit if Len = 0 then Exit; // Check index of image to be saved (-1 as index means save all images) if IsMultiImageFormat then begin if (Index >= Len) then Index := 0; if Index < 0 then begin Index := 0; FFirstIdx := 0; FLastIdx := Len - 1; end else begin FFirstIdx := Index; FLastIdx := Index; end; for I := FFirstIdx to FLastIdx - 1 do begin if not TestImage(Images[I]) then Exit; end; end else begin if (Index >= Len) or (Index < 0) then Index := 0; if not TestImage(Images[Index]) then Exit; end; Result := True; end; end; procedure TImageFileFormat.AddMasks(const AMasks: string); var I: LongInt; Ext: string; begin FExtensions.Clear; FMasks.CommaText := AMasks; FMasks.Delimiter := ';'; for I := 0 to FMasks.Count - 1 do begin FMasks[I] := Trim(FMasks[I]); Ext := GetFileExt(FMasks[I]); if (Ext <> '') and (Ext <> '*') then FExtensions.Add(Ext); end; end; function TImageFileFormat.GetFormatInfo(Format: TImageFormat): TImageFormatInfo; begin Result := ImageFormatInfos[Format]^; end; function TImageFileFormat.GetSupportedFormats: TImageFormats; begin Result := FSupportedFormats; end; function TImageFileFormat.LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; OnlyFirstFrame: Boolean): Boolean; begin Result := False; RaiseImaging(SFileFormatCanNotLoad, [FName]); end; function TImageFileFormat.SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray; Index: LongInt): Boolean; begin Result := False; RaiseImaging(SFileFormatCanNotSave, [FName]); end; procedure TImageFileFormat.ConvertToSupported(var Image: TImageData; const Info: TImageFormatInfo); begin end; function TImageFileFormat.IsSupported(const Image: TImageData): Boolean; begin Result := Image.Format in GetSupportedFormats; end; function TImageFileFormat.LoadFromFile(const FileName: string; var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; var Handle: TImagingHandle; begin Result := False; if CanLoad then try // Set IO ops to file ops and open given file SetFileIO; Handle := IO.Open(PChar(FileName), omReadOnly); try // Test if file contains valid image and if so then load it if TestFormat(Handle) then begin Result := PrepareLoad(Handle, Images, OnlyFirstLevel) and LoadData(Handle, Images, OnlyFirstlevel); Result := PostLoadCheck(Images, Result); end else RaiseImaging(SFileNotValid, [FileName, Name]); finally IO.Close(Handle); end; except RaiseImaging(SErrorLoadingFile, [FileName, FExtensions[0]]); end; end; function TImageFileFormat.LoadFromStream(Stream: TStream; var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; var Handle: TImagingHandle; OldPosition: Int64; begin Result := False; OldPosition := Stream.Position; if CanLoad then try // Set IO ops to stream ops and "open" given memory SetStreamIO; Handle := IO.Open(Pointer(Stream), omReadOnly); try // Test if stream contains valid image and if so then load it if TestFormat(Handle) then begin Result := PrepareLoad(Handle, Images, OnlyFirstLevel) and LoadData(Handle, Images, OnlyFirstlevel); Result := PostLoadCheck(Images, Result); end else RaiseImaging(SStreamNotValid, [@Stream, Name]); finally IO.Close(Handle); end; except Stream.Position := OldPosition; FreeImagesInArray(Images); RaiseImaging(SErrorLoadingStream, [@Stream, FExtensions[0]]); end; end; function TImageFileFormat.LoadFromMemory(Data: Pointer; Size: LongInt; var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; var Handle: TImagingHandle; IORec: TMemoryIORec; begin Result := False; if CanLoad then try // Set IO ops to memory ops and "open" given memory SetMemoryIO; IORec := PrepareMemIO(Data, Size); Handle := IO.Open(@IORec,omReadOnly); try // Test if memory contains valid image and if so then load it if TestFormat(Handle) then begin Result := PrepareLoad(Handle, Images, OnlyFirstLevel) and LoadData(Handle, Images, OnlyFirstlevel); Result := PostLoadCheck(Images, Result); end else RaiseImaging(SMemoryNotValid, [Data, Size, Name]); finally IO.Close(Handle); end; except RaiseImaging(SErrorLoadingMemory, [Data, Size, FExtensions[0]]); end; end; function TImageFileFormat.SaveToFile(const FileName: string; const Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; var Handle: TImagingHandle; Len, Index, I: LongInt; Ext, FName: string; begin Result := False; if CanSave and TestImagesInArray(Images) then try SetFileIO; Len := Length(Images); if IsMultiImageFormat or (not IsMultiImageFormat and (OnlyFirstLevel or (Len = 1))) then begin Handle := IO.Open(PChar(FileName), GetSaveOpenMode); try if OnlyFirstLevel then Index := 0 else Index := -1; // Write multi image to one file Result := PrepareSave(Handle, Images, Index) and SaveData(Handle, Images, Index); finally IO.Close(Handle); end; end else begin // Write multi image to file sequence Ext := ExtractFileExt(FileName); FName := ChangeFileExt(FileName, ''); Result := True; for I := 0 to Len - 1 do begin Handle := IO.Open(PChar(Format(FName + '%.3d' + Ext, [I])), GetSaveOpenMode); try Index := I; Result := Result and PrepareSave(Handle, Images, Index) and SaveData(Handle, Images, Index); if not Result then Break; finally IO.Close(Handle); end; end; end; except raise UpdateExceptMessage(GetExceptObject, SErrorSavingFile, [FileName, FExtensions[0]]); end; end; function TImageFileFormat.SaveToStream(Stream: TStream; const Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; var Handle: TImagingHandle; Len, Index, I: LongInt; OldPosition: Int64; begin Result := False; OldPosition := Stream.Position; if CanSave and TestImagesInArray(Images) then try SetStreamIO; Handle := IO.Open(PChar(Stream), GetSaveOpenMode); try if IsMultiImageFormat or OnlyFirstLevel then begin if OnlyFirstLevel then Index := 0 else Index := -1; // Write multi image in one run Result := PrepareSave(Handle, Images, Index) and SaveData(Handle, Images, Index); end else begin // Write multi image to sequence Result := True; Len := Length(Images); for I := 0 to Len - 1 do begin Index := I; Result := Result and PrepareSave(Handle, Images, Index) and SaveData(Handle, Images, Index); if not Result then Break; end; end; finally IO.Close(Handle); end; except Stream.Position := OldPosition; raise UpdateExceptMessage(GetExceptObject, SErrorSavingStream, [@Stream, FExtensions[0]]); end; end; function TImageFileFormat.SaveToMemory(Data: Pointer; var Size: LongInt; const Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; var Handle: TImagingHandle; Len, Index, I: LongInt; IORec: TMemoryIORec; begin Result := False; if CanSave and TestImagesInArray(Images) then try SetMemoryIO; IORec := PrepareMemIO(Data, Size); Handle := IO.Open(PChar(@IORec), GetSaveOpenMode); try if IsMultiImageFormat or OnlyFirstLevel then begin if OnlyFirstLevel then Index := 0 else Index := -1; // Write multi image in one run Result := PrepareSave(Handle, Images, Index) and SaveData(Handle, Images, Index); end else begin // Write multi image to sequence Result := True; Len := Length(Images); for I := 0 to Len - 1 do begin Index := I; Result := Result and PrepareSave(Handle, Images, Index) and SaveData(Handle, Images, Index); if not Result then Break; end; end; Size := IORec.Position; finally IO.Close(Handle); end; except raise UpdateExceptMessage(GetExceptObject, SErrorSavingMemory, [Data, Size, FExtensions[0]]); end; end; function TImageFileFormat.MakeCompatible(const Image: TImageData; var Compatible: TImageData; out MustBeFreed: Boolean): Boolean; begin InitImage(Compatible); if SaveOverrideFormat <> ifUnknown then begin // Save format override is active. Clone input and convert it to override format. CloneImage(Image, Compatible); ConvertImage(Compatible, SaveOverrideFormat); // Now check if override format is supported by file format. If it is not // then file format specific conversion (virtual method) is called. Result := IsSupported(Compatible); if not Result then begin ConvertToSupported(Compatible, GetFormatInfo(Compatible.Format)); Result := IsSupported(Compatible); end; end // Add IsCompatible function! not only checking by Format else if IsSupported(Image) then begin // No save format override and input is in format supported by this // file format. Just copy Image's fields to Compatible Compatible := Image; Result := True; end else begin // No override and input's format is not compatible with file format. // Clone it and the call file format specific conversion (virtual method). CloneImage(Image, Compatible); ConvertToSupported(Compatible, GetFormatInfo(Compatible.Format)); Result := IsSupported(Compatible); end; // Tell the user that he must free Compatible after he's done with it // (if necessary). MustBeFreed := Image.Bits <> Compatible.Bits; end; function TImageFileFormat.TestFormat(Handle: TImagingHandle): Boolean; begin Result := False; end; function TImageFileFormat.TestFileName(const FileName: string): Boolean; var I: LongInt; OnlyName: string; begin OnlyName := ExtractFileName(FileName); // For each mask test if filename matches it for I := 0 to FMasks.Count - 1 do if StrMaskMatch(OnlyName, FMasks[I], False) then begin Result := True; Exit; end; Result := False; end; procedure TImageFileFormat.CheckOptionsValidity; begin end; function TImageFileFormat.GetCanLoad: Boolean; begin Result := ffLoad in FFeatures; end; function TImageFileFormat.GetCanSave: Boolean; begin Result := ffSave in FFeatures; end; function TImageFileFormat.GetIsMultiImageFormat: Boolean; begin Result := ffMultiImage in FFeatures; end; function TImageFileFormat.GetSaveOpenMode: TOpenMode; begin // TODO: fix //if ffReadOnSave in FFeatures then // Result := omReadWrite //else Result := omCreate; end; { TOptionStack class implementation } constructor TOptionStack.Create; begin inherited Create; FPosition := -1; end; destructor TOptionStack.Destroy; var I: LongInt; begin for I := 0 to OptionStackDepth - 1 do SetLength(FStack[I], 0); inherited Destroy; end; function TOptionStack.Pop: Boolean; var I: LongInt; begin Result := False; if FPosition >= 0 then begin SetLength(Options, Length(FStack[FPosition])); for I := 0 to Length(FStack[FPosition]) - 1 do if Options[I] <> nil then Options[I]^ := FStack[FPosition, I]; Dec(FPosition); Result := True; end; end; function TOptionStack.Push: Boolean; var I: LongInt; begin Result := False; if FPosition < OptionStackDepth - 1 then begin Inc(FPosition); SetLength(FStack[FPosition], Length(Options)); for I := 0 to Length(Options) - 1 do if Options[I] <> nil then FStack[FPosition, I] := Options[I]^; Result := True; end; end; { TMetadata } procedure TMetadata.SetMetaItem(const Id: string; const Value: Variant; ImageIndex: Integer); begin AddMetaToList(FLoadMetaItems, Id, Value, ImageIndex); end; procedure TMetadata.SetMetaItemForSaving(const Id: string; const Value: Variant; ImageIndex: Integer); begin AddMetaToList(FSaveMetaItems, Id, Value, ImageIndex); end; procedure TMetadata.AddMetaToList(List: TStringList; const Id: string; const Value: Variant; ImageIndex: Integer); var Item: TMetadataItem; Idx: Integer; FullId: string; begin FullId := GetMetaItemName(Id, ImageIndex); if List.Find(FullId, Idx) then (List.Objects[Idx] as TMetadataItem).Value := Value else begin Item := TMetadataItem.Create; Item.Id := Id; Item.ImageIndex := ImageIndex; Item.Value := Value; List.AddObject(FullId, Item); end; end; procedure TMetadata.ClearMetaItems; begin ClearMetaList(FLoadMetaItems); end; procedure TMetadata.ClearMetaItemsForSaving; begin ClearMetaList(FSaveMetaItems); end; procedure TMetadata.ClearMetaList(List: TStringList); var I: Integer; begin for I := 0 to List.Count - 1 do List.Objects[I].Free; List.Clear; end; procedure TMetadata.CopyLoadedMetaItemsForSaving; var I: Integer; Copy, Orig: TMetadataItem; begin ClearMetaItemsForSaving; for I := 0 to FLoadMetaItems.Count - 1 do begin Orig := TMetadataItem(FLoadMetaItems.Objects[I]); Copy := TMetadataItem.Create; Copy.Id := Orig.Id; Copy.ImageIndex := Orig.ImageIndex; Copy.Value := Orig.Value; FSaveMetaItems.AddObject(GetMetaItemName(Copy.Id, Copy.ImageIndex), Copy); end; end; constructor TMetadata.Create; begin inherited; FLoadMetaItems := TStringList.Create; FLoadMetaItems.Sorted := True; FSaveMetaItems := TStringList.Create; FSaveMetaItems.Sorted := True; end; destructor TMetadata.Destroy; begin ClearMetaItems; ClearMetaItemsForSaving; FLoadMetaItems.Free; FSaveMetaItems.Free; inherited; end; function TMetadata.GetMetaById(const Id: string): Variant; var Idx: Integer; begin if FLoadMetaItems.Find(Id, Idx) then Result := (FLoadMetaItems.Objects[Idx] as TMetadataItem).Value else Result := Variants.Null; end; function TMetadata.GetMetaByIdMulti(const Id: string; ImageIndex: Integer): Variant; begin Result := GetMetaById(GetMetaItemName(Id, ImageIndex)); end; function TMetadata.GetSaveMetaById(const Id: string): Variant; var Idx: Integer; begin if FSaveMetaItems.Find(Id, Idx) then Result := (FSaveMetaItems.Objects[Idx] as TMetadataItem).Value else Result := Variants.Null; end; function TMetadata.GetSaveMetaByIdMulti(const Id: string; ImageIndex: Integer): Variant; begin Result := GetSaveMetaById(GetMetaItemName(Id, ImageIndex)); end; function TMetadata.GetMetaByIdx(Index: Integer): TMetadataItem; begin Result := FLoadMetaItems.Objects[Index] as TMetadataItem; end; function TMetadata.GetMetaCount: Integer; begin Result := FLoadMetaItems.Count; end; function TMetadata.GetMetaItemName(const Id: string; ImageIndex: Integer): string; begin Result := Iff(ImageIndex = 0, Id, Format(SMetaIdForSubImage, [Id, ImageIndex])); end; function TMetadata.GetPhysicalPixelSize(ResUnit: TResolutionUnit; var XSize, YSize: Single; MetaForSave: Boolean; ImageIndex: Integer): Boolean; type TGetter = function(const Id: string; ImageIndex: Integer): Variant of object; var Getter: TGetter; XMeta, YMeta: Variant; begin if MetaForSave then Getter := GetSaveMetaByIdMulti else Getter := GetMetaByIdMulti; XMeta := Getter(SMetaPhysicalPixelSizeX, ImageIndex); YMeta := Getter(SMetaPhysicalPixelSizeY, ImageIndex); XSize := -1; YSize := -1; Result := not VarIsNull(XMeta) or not VarIsNull(YMeta); if not Result then Exit; if not VarIsNull(XMeta) then XSize := XMeta; if not VarIsNull(YMeta) then YSize := YMeta; if XSize < 0 then XSize := YSize; if YSize < 0 then YSize := XSize; TranslateUnits(ResUnit, XSize, YSize); end; procedure TMetadata.SetPhysicalPixelSize(ResUnit: TResolutionUnit; XSize, YSize: Single; MetaForSave: Boolean; ImageIndex: Integer); type TAdder = procedure(const Id: string; const Value: Variant; ImageIndex: Integer) of object; var Adder: TAdder; begin TranslateUnits(ResUnit, XSize, YSize); if MetaForSave then Adder := SetMetaItemForSaving else Adder := SetMetaItem; Adder(SMetaPhysicalPixelSizeX, XSize, ImageIndex); Adder(SMetaPhysicalPixelSizeY, YSize, ImageIndex); end; procedure TMetadata.TranslateUnits(ResolutionUnit: TResolutionUnit; var XRes, YRes: Single); var UnitSize: Single; begin case ResolutionUnit of ruDpi: UnitSize := 25400; ruDpm: UnitSize := 1e06; ruDpcm: UnitSize := 1e04; else UnitSize := 1; end; if ResolutionUnit <> ruSizeInMicroMeters then begin XRes := UnitSize / XRes; YRes := UnitSize / YRes; end; end; function TMetadata.HasMetaItem(const Id: string; ImageIndex: Integer): Boolean; begin Result := GetMetaByIdMulti(Id, ImageIndex) <> Variants.Null; end; function TMetadata.HasMetaItemForSaving(const Id: string; ImageIndex: Integer): Boolean; begin Result := GetSaveMetaByIdMulti(Id, ImageIndex) <> Variants.Null; end; initialization {$IFDEF MEMCHECK} {$IF CompilerVersion >= 18} System.ReportMemoryLeaksOnShutdown := True; {$IFEND} {$ENDIF} if GlobalMetadata = nil then GlobalMetadata := TMetadata.Create; if ImageFileFormats = nil then ImageFileFormats := TList.Create; InitImageFormats; RegisterOption(ImagingColorReductionMask, @ColorReductionMask); RegisterOption(ImagingLoadOverrideFormat, @LoadOverrideFormat); RegisterOption(ImagingSaveOverrideFormat, @SaveOverrideFormat); RegisterOption(ImagingMipMapFilter, @MipMapFilter); RegisterOption(ImagingBinaryTreshold, @BinaryTreshold); finalization FreeOptions; FreeImageFileFormats; GlobalMetadata.Free; { File Notes: -- TODOS ---------------------------------------------------- - nothing now -- 0.77.1 --------------------------------------------------- - Updated IO Open functions according to changes in ImagingTypes. - Fixed bug in SplitImage that could cause wrong size of edge chunks. - Metadata support fixes and extensions (frame delays, animation loops). -- 0.26.5 Changes/Bug Fixes --------------------------------- - Started reworking exception raising to keep the original class type (e.g. in NewImage EOutOfMemory could be raised but was hidden by EImagingError raised afterwards in NewImage try/except). - Fixed possible AV in Rotate45 subproc of RotateImage. - Added ReadRawXXX and WriteRawXXX functions for raw image bits IO. - Implemented ImagingBinaryTreshold option. - Added support for simple image metadata loading/saving. - Moved file format definition (name, exts, caps, ...) from constructor to new Define method. - Fixed some memory leaks caused by failures during image loading. -- 0.26.3 Changes/Bug Fixes --------------------------------- - Extended RotateImage to allow arbitrary angle rotations. - Reversed the order file formats list is searched so if you register a new one it will be found sooner than built in formats. - Fixed memory leak in ResizeImage ocurring when resizing indexed images. -- 0.26.1 Changes/Bug Fixes --------------------------------- - Added position/size checks to LoadFromStream functions. - Changed conditional compilation in impl. uses section to reflect changes in LINK symbols. -- 0.24.3 Changes/Bug Fixes --------------------------------- - GenerateMipMaps now generates all smaller levels from original big image (better results when using more advanced filters). Also conversion to compatible image format is now done here not in FillMipMapLevel (that is called for every mipmap level). -- 0.23 Changes/Bug Fixes ----------------------------------- - MakePaletteForImages now works correctly for indexed and special format images - Fixed bug in StretchRect: Image was not properly stretched if src and dst dimensions differed only in height. - ConvertImage now fills new image with zeroes to avoid random data in some conversions (RGB->XRGB) - Changed RegisterOption procedure to function - Changed bunch of palette functions from low level interface to procedure (there was no reason for them to be functions). - Changed FreeImage and FreeImagesInArray functions to procedures. - Added many assertions, come try-finally, other checks, and small code and doc changes. -- 0.21 Changes/Bug Fixes ----------------------------------- - GenerateMipMaps threw failed assertion when input was indexed or special, fixed. - Added CheckOptionsValidity to TImageFileFormat and its decendants. - Unit ImagingExtras which registers file formats in Extras package is now automatically added to uses clause if LINK_EXTRAS symbol is defined in ImagingOptions.inc file. - Added EnumFileFormats function to low level interface. - Fixed bug in SwapChannels which could cause AV when swapping alpha channel of A8R8G8B8 images. - Converting loaded images to ImagingOverrideFormat is now done in PostLoadCheck method to avoid code duplicity. - Added GetFileFormatCount and GetFileFormatAtIndex functions - Bug in ConvertImage: if some format was converted to similar format only with swapped channels (R16G16B16<>B16G16R16) then channels were swapped correctly but new data format (swapped one) was not set. - Made TImageFileFormat.MakeCompatible public non-virtual method (and modified its function). Created new virtual ConvertToSupported which should be overriden by descendants. Main reason for doint this is to avoid duplicate code that was in all TImageFileFormat's descendants. - Changed TImageFileFormat.GetFormatInfo's result type to TImageFormatInfo. - Split overloaded FindImageFileFormat functions to FindImageFileFormatByClass and FindImageFileFormatByExt and created new FindImageFileFormatByName which operates on whole filenames. - Function GetExtensionFilterIndex renamed to GetFileNameFilterIndex (because it now works with filenames not extensions). - DetermineFileFormat now first searches by filename and if not found then by data. - Added TestFileName method to TImageFileFormat. - Updated GetImageFileFormatsFilter to uses Masks instead of Extensions property of TImageFileFormat. Also you can now request OpenDialog and SaveDialog type filters - Added Masks property and AddMasks method to TImageFileFormat. AddMasks replaces AddExtensions, it uses filename masks instead of sime filename extensions to identify supported files. - Changed TImageFileFormat.LoadData procedure to function and moved varios duplicate code from its descandats (check index,...) here to TImageFileFormat helper methods. - Changed TImageFileFormat.SaveData procedure to function and moved varios duplicate code from its descandats (check index,...) here to TImageFileFormat helper methods. - Removed RAISE_EXCEPTIONS define, exceptions are now raised everytime - Added MustBeFreed parameter to TImageFileFormat.MakeComptible method that indicates that compatible image returned by this method must be freed after its usage. -- 0.19 Changes/Bug Fixes ----------------------------------- - fixed bug in NewImage: if given format was ifDefault it wasn't replaced with DefaultImageFormat constant which caused problems later in other units - fixed bug in RotateImage which caused that rotated special format images were whole black - LoadImageFromXXX and LoadMultiImageFromXXX now use DetermineXXXFormat when choosing proper loader, this eliminated need for Ext parameter in stream and memory loading functions - added GetVersionStr function - fixed bug in ResizeImage which caued indexed images to lose their palette during process resulting in whole black image - Clipping in ...Rect functions now uses clipping procs from ImagingUtility, it also works better - FillRect optimization for 8, 16, and 32 bit formats - added pixel set/get functions to low level interface: GetPixelDirect, SetPixelDirect, GetPixel32, SetPixel32, GetPixelFP, SetPixelFP - removed GetPixelBytes low level intf function - redundant (same data can be obtained by GetImageFormatInfo) - made small changes in many parts of library to compile on AMD64 CPU (Linux with FPC) - changed InitImage to procedure (function was pointless) - Method TestFormat of TImageFileFormat class made public (was protected) - added function IsFileFormatSupported to low level interface (contributed by Paul Michell) - fixed some missing format arguments from error strings which caused Format function to raise exception - removed forgotten debug code that disabled filtered resizing of images with channel bitcounts > 8 -- 0.17 Changes/Bug Fixes ----------------------------------- - changed order of parameters of CopyRect function - GenerateMipMaps now filters mipmap levels - ResizeImage functions was extended to allow bilinear and bicubic filtering - added StretchRect function to low level interface - added functions GetImageFileFormatsFilter, GetFilterIndexExtension, and GetExtensionFilterIndex -- 0.15 Changes/Bug Fixes ----------------------------------- - added function RotateImage to low level interface - moved TImageFormatInfo record and types required by it to ImagingTypes unit, changed GetImageFormatInfo low level interface function to return TImageFormatInfo instead of short info - added checking of options values validity before they are used - fixed possible memory leak in CloneImage - added ReplaceColor function to low level interface - new function FindImageFileFormat by class added -- 0.13 Changes/Bug Fixes ----------------------------------- - added DetermineFileFormat, DetermineStreamFormat, DetermineMemoryFormat, GetPixelsSize functions to low level interface - added NewPalette, CopyPalette, FreePalette functions to low level interface - added MapImageToPalette, FillRect, SplitImage, MakePaletteForImages functions to low level interface - fixed buggy FillCustomPalette function (possible div by zero and others) - added CopyRect function to low level interface - Member functions of TImageFormatInfo record implemented for all formats - before saving images TestImagesInArray is called now - added TestImagesInArray function to low level interface - added GenerateMipMaps function to low level interface - stream position in load/save from/to stream is now set to position before function was called if error occurs - when error occured during load/save from/to file file handle was not released - CloneImage returned always False } end. ================================================ FILE: lib/Imaging/ImagingBitmap.pas ================================================ { Vampyre Imaging Library by Marek Mauder http://imaginglib.sourceforge.net The contents of this file are used with permission, subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/MPL-1.1.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Alternatively, the contents of this file may be used under the terms of the GNU Lesser General Public License (the "LGPL License"), in which case the provisions of the LGPL License are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of the LGPL License and not to allow others to use your version of this file under the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the LGPL License. If you do not delete the provisions above, a recipient may use your version of this file under either the MPL or the LGPL License. For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html } { This unit contains image format loader/saver for Windows Bitmap images. } unit ImagingBitmap; {$I ImagingOptions.inc} interface uses ImagingTypes, Imaging, ImagingUtility, ImagingFormats, ImagingIO; type { Class for loading and saving Windows Bitmap images. It can load/save 8bit indexed, 16, 24, 32 bit RGB or ARGB images with or without RLE compression. It can also load 1/4 bit indexed images and OS2 bitmaps.} TBitmapFileFormat = class(TImageFileFormat) protected FUseRLE: LongBool; procedure Define; override; function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; override; function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray; Index: LongInt): Boolean; override; procedure ConvertToSupported(var Image: TImageData; const Info: TImageFormatInfo); override; public function TestFormat(Handle: TImagingHandle): Boolean; override; published { Controls that RLE compression is used during saving. Accessible trough ImagingBitmapRLE option.} property UseRLE: LongBool read FUseRLE write FUseRLE; end; implementation const SBitmapFormatName = 'Windows Bitmap Image'; SBitmapMasks = '*.bmp,*.dib'; BitmapSupportedFormats: TImageFormats = [ifIndex8, ifA1R5G5B5, ifA4R4G4B4, ifR5G6B5, ifR8G8B8, ifA8R8G8B8, ifX1R5G5B5, ifX4R4G4B4, ifX8R8G8B8]; BitmapDefaultRLE = True; const { Bitmap file identifier 'BM'.} BMMagic: Word = 19778; { Constants for the TBitmapInfoHeader.Compression field.} BI_RGB = 0; BI_RLE8 = 1; BI_RLE4 = 2; BI_BITFIELDS = 3; V3InfoHeaderSize = 40; V4InfoHeaderSize = 108; type { File Header for Windows/OS2 bitmap file.} TBitmapFileHeader = packed record ID: Word; // Is always 19778 : 'BM' Size: LongWord; // Filesize Reserved1: Word; Reserved2: Word; Offset: LongWord; // Offset from start pos to beginning of image bits end; { Info Header for Windows bitmap file version 4.} TBitmapInfoHeader = packed record Size: LongWord; Width: LongInt; Height: LongInt; Planes: Word; BitCount: Word; Compression: LongWord; SizeImage: LongWord; XPelsPerMeter: LongInt; YPelsPerMeter: LongInt; ClrUsed: LongInt; ClrImportant: LongInt; RedMask: LongWord; GreenMask: LongWord; BlueMask: LongWord; AlphaMask: LongWord; CSType: LongWord; EndPoints: array[0..8] of LongWord; GammaRed: LongWord; GammaGreen: LongWord; GammaBlue: LongWord; end; { Info Header for OS2 bitmaps.} TBitmapCoreHeader = packed record Size: LongWord; Width: Word; Height: Word; Planes: Word; BitCount: Word; end; { Used in RLE encoding and decoding.} TRLEOpcode = packed record Count: Byte; Command: Byte; end; PRLEOpcode = ^TRLEOpcode; { TBitmapFileFormat class implementation } procedure TBitmapFileFormat.Define; begin inherited; FName := SBitmapFormatName; FFeatures := [ffLoad, ffSave]; FSupportedFormats := BitmapSupportedFormats; FUseRLE := BitmapDefaultRLE; AddMasks(SBitmapMasks); RegisterOption(ImagingBitmapRLE, @FUseRLE); end; function TBitmapFileFormat.LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; var BF: TBitmapFileHeader; BI: TBitmapInfoHeader; BC: TBitmapCoreHeader; IsOS2: Boolean; PalRGB: PPalette24; I, FPalSize, AlignedSize, StartPos, HeaderSize, AlignedWidthBytes, WidthBytes: LongInt; Info: TImageFormatInfo; Data: Pointer; procedure LoadRGB; var I: LongInt; LineBuffer: PByte; begin with Images[0], GetIO do begin // If BI.Height is < 0 then image data are stored non-flipped // but default in windows is flipped so if Height is positive we must // flip it if BI.BitCount < 8 then begin // For 1 and 4 bit images load aligned data, they will be converted to // 8 bit and unaligned later GetMem(Data, AlignedSize); if BI.Height < 0 then Read(Handle, Data, AlignedSize) else for I := Height - 1 downto 0 do Read(Handle, @PByteArray(Data)[I * AlignedWidthBytes], AlignedWidthBytes); end else begin // Images with pixels of size >= 1 Byte are read line by line and // copied to image bits without padding bytes GetMem(LineBuffer, AlignedWidthBytes); try if BI.Height < 0 then for I := 0 to Height - 1 do begin Read(Handle, LineBuffer, AlignedWidthBytes); Move(LineBuffer^, PByteArray(Bits)[I * WidthBytes], WidthBytes); end else for I := Height - 1 downto 0 do begin Read(Handle, LineBuffer, AlignedWidthBytes); Move(LineBuffer^, PByteArray(Bits)[I * WidthBytes], WidthBytes); end; finally FreeMemNil(LineBuffer); end; end; end; end; procedure LoadRLE4; var RLESrc: PByteArray; Row, Col, WriteRow, I: LongInt; SrcPos: LongWord; DeltaX, DeltaY, Low, High: Byte; Pixels: PByteArray; OpCode: TRLEOpcode; NegHeightBitmap: Boolean; begin GetMem(RLESrc, BI.SizeImage); GetIO.Read(Handle, RLESrc, BI.SizeImage); with Images[0] do try Low := 0; Pixels := Bits; SrcPos := 0; NegHeightBitmap := BI.Height < 0; Row := 0; // Current row in dest image Col := 0; // Current column in dest image // Row in dest image where actuall writting will be done WriteRow := Iff(NegHeightBitmap, Row, Height - 1 - Row); while (Row < Height) and (SrcPos < BI.SizeImage) do begin // Read RLE op-code OpCode := PRLEOpcode(@RLESrc[SrcPos])^; Inc(SrcPos, SizeOf(OpCode)); if OpCode.Count = 0 then begin // A byte Count of zero means that this is a special // instruction. case OpCode.Command of 0: begin // Move to next row Inc(Row); WriteRow := Iff(NegHeightBitmap, Row, Height - 1 - Row); Col := 0; end ; 1: Break; // Image is finished 2: begin // Move to a new relative position DeltaX := RLESrc[SrcPos]; DeltaY := RLESrc[SrcPos + 1]; Inc(SrcPos, 2); Inc(Col, DeltaX); Inc(Row, DeltaY); end else // Do not read data after EOF if SrcPos + OpCode.Command > BI.SizeImage then OpCode.Command := BI.SizeImage - SrcPos; // Take padding bytes and nibbles into account if Col + OpCode.Command > Width then OpCode.Command := Width - Col; // Store absolute data. Command code is the // number of absolute bytes to store for I := 0 to OpCode.Command - 1 do begin if (I and 1) = 0 then begin High := RLESrc[SrcPos] shr 4; Low := RLESrc[SrcPos] and $F; Pixels[WriteRow * Width + Col] := High; Inc(SrcPos); end else Pixels[WriteRow * Width + Col] := Low; Inc(Col); end; // Odd number of bytes is followed by a pad byte if (OpCode.Command mod 4) in [1, 2] then Inc(SrcPos); end; end else begin // Take padding bytes and nibbles into account if Col + OpCode.Count > Width then OpCode.Count := Width - Col; // Store a run of the same color value for I := 0 to OpCode.Count - 1 do begin if (I and 1) = 0 then Pixels[WriteRow * Width + Col] := OpCode.Command shr 4 else Pixels[WriteRow * Width + Col] := OpCode.Command and $F; Inc(Col); end; end; end; finally FreeMem(RLESrc); end; end; procedure LoadRLE8; var RLESrc: PByteArray; SrcCount, Row, Col, WriteRow: LongInt; SrcPos: LongWord; DeltaX, DeltaY: Byte; Pixels: PByteArray; OpCode: TRLEOpcode; NegHeightBitmap: Boolean; begin GetMem(RLESrc, BI.SizeImage); GetIO.Read(Handle, RLESrc, BI.SizeImage); with Images[0] do try Pixels := Bits; SrcPos := 0; NegHeightBitmap := BI.Height < 0; Row := 0; // Current row in dest image Col := 0; // Current column in dest image // Row in dest image where actuall writting will be done WriteRow := Iff(NegHeightBitmap, Row, Height - 1 - Row); while (Row < Height) and (SrcPos < BI.SizeImage) do begin // Read RLE op-code OpCode := PRLEOpcode(@RLESrc[SrcPos])^; Inc(SrcPos, SizeOf(OpCode)); if OpCode.Count = 0 then begin // A byte Count of zero means that this is a special // instruction. case OpCode.Command of 0: begin // Move to next row Inc(Row); WriteRow := Iff(NegHeightBitmap, Row, Height - 1 - Row); Col := 0; end ; 1: Break; // Image is finished 2: begin // Move to a new relative position DeltaX := RLESrc[SrcPos]; DeltaY := RLESrc[SrcPos + 1]; Inc(SrcPos, 2); Inc(Col, DeltaX); Inc(Row, DeltaY); end else SrcCount := OpCode.Command; // Do not read data after EOF if SrcPos + OpCode.Command > BI.SizeImage then OpCode.Command := BI.SizeImage - SrcPos; // Take padding bytes into account if Col + OpCode.Command > Width then OpCode.Command := Width - Col; // Store absolute data. Command code is the // number of absolute bytes to store Move(RLESrc[SrcPos], Pixels[WriteRow * Width + Col], OpCode.Command); Inc(SrcPos, SrcCount); Inc(Col, OpCode.Command); // Odd number of bytes is followed by a pad byte if (SrcCount mod 2) = 1 then Inc(SrcPos); end; end else begin // Take padding bytes into account if Col + OpCode.Count > Width then OpCode.Count := Width - Col; // Store a run of the same color value. Count is number of bytes to store FillChar(Pixels [WriteRow * Width + Col], OpCode.Count, OpCode.Command); Inc(Col, OpCode.Count); end; end; finally FreeMem(RLESrc); end; end; begin Data := nil; SetLength(Images, 1); with GetIO, Images[0] do try FillChar(BI, SizeOf(BI), 0); StartPos := Tell(Handle); Read(Handle, @BF, SizeOf(BF)); Read(Handle, @BI.Size, SizeOf(BI.Size)); IsOS2 := BI.Size = SizeOf(TBitmapCoreHeader); // Bitmap Info reading if IsOS2 then begin // OS/2 type bitmap, reads info header without 4 already read bytes Read(Handle, @PByteArray(@BC)[SizeOf(BI.Size)], SizeOf(TBitmapCoreHeader) - SizeOf(BI.Size)); with BI do begin ClrUsed := 0; Compression := BI_RGB; BitCount := BC.BitCount; Height := BC.Height; Width := BC.Width; end; end else begin // Windows type bitmap HeaderSize := Min(BI.Size - SizeOf(BI.Size), SizeOf(BI) - SizeOf(BI.Size)); // do not read more than size of BI! Read(Handle, @PByteArray(@BI)[SizeOf(BI.Size)], HeaderSize); // SizeImage can be 0 for BI_RGB images, but it is here because of: // I saved 8bit bitmap in Paint Shop Pro 8 as OS2 RLE compressed. // It wrote strange 64 Byte Info header with SizeImage set to 0 // Some progs were able to open it, some were not. if BI.SizeImage = 0 then BI.SizeImage := BF.Size - BF.Offset; end; // Bit mask reading. Only read it if there is V3 header, V4 header has // masks laoded already (only masks for RGB in V3). if (BI.Compression = BI_BITFIELDS) and (BI.Size = V3InfoHeaderSize) then Read(Handle, @BI.RedMask, SizeOf(BI.RedMask) * 3); case BI.BitCount of 1, 4, 8: Format := ifIndex8; 16: if BI.RedMask = $0F00 then // Set XRGB4 or ARGB4 according to value of alpha mask Format := IffFormat(BI.AlphaMask = 0, ifX4R4G4B4, ifA4R4G4B4) else if BI.RedMask = $F800 then Format := ifR5G6B5 else // R5G5B5 is default 16bit format (with Compression = BI_RGB or masks). // We set it to A1.. and later there is a check if there are any alpha values // and if not it is changed to X1R5G5B5 Format := ifA1R5G5B5; 24: Format := ifR8G8B8; 32: Format := ifA8R8G8B8; // As with R5G5B5 there is alpha check later end; NewImage(BI.Width, Abs(BI.Height), Format, Images[0]); Info := GetFormatInfo(Format); WidthBytes := Width * Info.BytesPerPixel; AlignedWidthBytes := (((Width * BI.BitCount) + 31) shr 5) * 4; AlignedSize := Height * LongInt(AlignedWidthBytes); // Palette settings and reading if BI.BitCount <= 8 then begin // Seek to the begining of palette Seek(Handle, StartPos + SizeOf(TBitmapFileHeader) + LongInt(BI.Size), smFromBeginning); if IsOS2 then begin // OS/2 type FPalSize := 1 shl BI.BitCount; GetMem(PalRGB, FPalSize * SizeOf(TColor24Rec)); try Read(Handle, PalRGB, FPalSize * SizeOf(TColor24Rec)); for I := 0 to FPalSize - 1 do with PalRGB[I] do begin Palette[I].R := R; Palette[I].G := G; Palette[I].B := B; end; finally FreeMemNil(PalRGB); end; end else begin // Windows type FPalSize := BI.ClrUsed; if FPalSize = 0 then FPalSize := 1 shl BI.BitCount; Read(Handle, Palette, FPalSize * SizeOf(TColor32Rec)); end; for I := 0 to Info.PaletteEntries - 1 do Palette[I].A := $FF; end; // Seek to the beginning of image bits Seek(Handle, StartPos + LongInt(BF.Offset), smFromBeginning); case BI.Compression of BI_RGB: LoadRGB; BI_RLE4: LoadRLE4; BI_RLE8: LoadRLE8; BI_BITFIELDS: LoadRGB; end; if BI.AlphaMask = 0 then begin // Alpha mask is not stored in file (V3) or not defined. // Check alpha channels of loaded images if they might contain them. if Format = ifA1R5G5B5 then begin // Check if there is alpha channel present in A1R5GB5 images, if it is not // change format to X1R5G5B5 if not Has16BitImageAlpha(Width * Height, Bits) then Format := ifX1R5G5B5; end else if Format = ifA8R8G8B8 then begin // Check if there is alpha channel present in A8R8G8B8 images, if it is not // change format to X8R8G8B8 if not Has32BitImageAlpha(Width * Height, Bits) then Format := ifX8R8G8B8; end; end; if BI.BitCount < 8 then begin // 1 and 4 bpp images are supported only for loading which is now // so we now convert them to 8bpp (and unalign scanlines). case BI.BitCount of 1: Convert1To8(Data, Bits, Width, Height, AlignedWidthBytes, False); 4: begin // RLE4 bitmaps are translated to 8bit during RLE decoding if BI.Compression <> BI_RLE4 then Convert4To8(Data, Bits, Width, Height, AlignedWidthBytes, False); end; end; // Enlarge palette ReallocMem(Palette, Info.PaletteEntries * SizeOf(TColor32Rec)); end; Result := True; finally FreeMemNil(Data); end; end; function TBitmapFileFormat.SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray; Index: LongInt): Boolean; var StartPos, EndPos, I, Pad, PadSize, WidthBytes: LongInt; BF: TBitmapFileHeader; BI: TBitmapInfoHeader; Info: TImageFormatInfo; ImageToSave: TImageData; MustBeFreed: Boolean; procedure SaveRLE8; const BufferSize = 8 * 1024; var X, Y, I, SrcPos: LongInt; DiffCount, SameCount: Byte; Pixels: PByteArray; Buffer: array[0..BufferSize - 1] of Byte; BufferPos: LongInt; procedure WriteByte(ByteToWrite: Byte); begin if BufferPos = BufferSize then begin // Flush buffer if necessary GetIO.Write(Handle, @Buffer, BufferPos); BufferPos := 0; end; Buffer[BufferPos] := ByteToWrite; Inc(BufferPos); end; begin BufferPos := 0; with GetIO, ImageToSave do begin for Y := Height - 1 downto 0 do begin X := 0; SrcPos := 0; Pixels := @PByteArray(Bits)[Y * Width]; while X < Width do begin SameCount := 1; DiffCount := 0; // Determine run length while X + SameCount < Width do begin // If we reach max run length or byte with different value // we end this run if (SameCount = 255) or (Pixels[SrcPos + SameCount] <> Pixels[SrcPos]) then Break; Inc(SameCount); end; if SameCount = 1 then begin // If there are not some bytes with the same value we // compute how many different bytes are there while X + DiffCount < Width do begin // Stop diff byte counting if there two bytes with the same value // or DiffCount is too big if (DiffCount = 255) or (Pixels[SrcPos + DiffCount + 1] = Pixels[SrcPos + DiffCount]) then Break; Inc(DiffCount); end; end; // Now store absolute data (direct copy image->file) or // store RLE code only (number of repeats + byte to be repeated) if DiffCount > 2 then begin // Save 'Absolute Data' (0 + number of bytes) but only // if number is >2 because (0+1) and (0+2) are other special commands WriteByte(0); WriteByte(DiffCount); // Write absolute data to buffer for I := 0 to DiffCount - 1 do WriteByte(Pixels[SrcPos + I]); Inc(X, DiffCount); Inc(SrcPos, DiffCount); // Odd number of bytes must be padded if (DiffCount mod 2) = 1 then WriteByte(0); end else begin // Save number of repeats and byte that should be repeated WriteByte(SameCount); WriteByte(Pixels[SrcPos]); Inc(X, SameCount); Inc(SrcPos, SameCount); end; end; // Save 'End Of Line' command WriteByte(0); WriteByte(0); end; // Save 'End Of Bitmap' command WriteByte(0); WriteByte(1); // Flush buffer GetIO.Write(Handle, @Buffer, BufferPos); end; end; begin Result := False; if MakeCompatible(Images[Index], ImageToSave, MustBeFreed) then with GetIO, ImageToSave do try Info := GetFormatInfo(Format); StartPos := Tell(Handle); FillChar(BF, SizeOf(BF), 0); FillChar(BI, SizeOf(BI), 0); // Other fields will be filled later - we don't know all values now BF.ID := BMMagic; Write(Handle, @BF, SizeOf(BF)); if Info.HasAlphaChannel and (Info.BytesPerPixel = 2){V4 temp hack} then // Save images with alpha in V4 format BI.Size := V4InfoHeaderSize else // Save images without alpha in V3 format - for better compatibility BI.Size := V3InfoHeaderSize; BI.Width := Width; BI.Height := Height; BI.Planes := 1; BI.BitCount := Info.BytesPerPixel * 8; BI.XPelsPerMeter := 2835; // 72 dpi BI.YPelsPerMeter := 2835; // 72 dpi // Set compression if (Info.BytesPerPixel = 1) and FUseRLE then BI.Compression := BI_RLE8 else if (Info.HasAlphaChannel or ((BI.BitCount = 16) and (Format <> ifX1R5G5B5))) and (Info.BytesPerPixel = 2){V4 temp hack} then BI.Compression := BI_BITFIELDS else BI.Compression := BI_RGB; // Write header (first time) Write(Handle, @BI, BI.Size); // Write mask info if BI.Compression = BI_BITFIELDS then begin if BI.BitCount = 16 then with Info.PixelFormat^ do begin BI.RedMask := RBitMask; BI.GreenMask := GBitMask; BI.BlueMask := BBitMask; BI.AlphaMask := ABitMask; end else begin // Set masks for A8R8G8B8 BI.RedMask := $00FF0000; BI.GreenMask := $0000FF00; BI.BlueMask := $000000FF; BI.AlphaMask := $FF000000; end; // If V3 header is used RGB masks must be written to file separately. // V4 header has embedded masks (V4 is default for formats with alpha). if BI.Size = V3InfoHeaderSize then Write(Handle, @BI.RedMask, SizeOf(BI.RedMask) * 3); end; // Write palette if Palette <> nil then Write(Handle, Palette, Info.PaletteEntries * SizeOf(TColor32Rec)); BF.Offset := Tell(Handle) - StartPos; if BI.Compression <> BI_RLE8 then begin // Save uncompressed data, scanlines must be filled with pad bytes // to be multiples of 4, save as bottom-up (Windows native) bitmap Pad := 0; WidthBytes := Width * Info.BytesPerPixel; PadSize := ((Width * BI.BitCount + 31) div 32) * 4 - WidthBytes; for I := Height - 1 downto 0 do begin Write(Handle, @PByteArray(Bits)[I * WidthBytes], WidthBytes); if PadSize > 0 then Write(Handle, @Pad, PadSize); end; end else begin // Save data with RLE8 compression SaveRLE8; end; EndPos := Tell(Handle); Seek(Handle, StartPos, smFromBeginning); // Rewrite header with new values BF.Size := EndPos - StartPos; BI.SizeImage := BF.Size - BF.Offset; Write(Handle, @BF, SizeOf(BF)); Write(Handle, @BI, BI.Size); Seek(Handle, EndPos, smFromBeginning); Result := True; finally if MustBeFreed then FreeImage(ImageToSave); end; end; procedure TBitmapFileFormat.ConvertToSupported(var Image: TImageData; const Info: TImageFormatInfo); var ConvFormat: TImageFormat; begin if Info.IsFloatingPoint then // Convert FP image to RGB/ARGB according to presence of alpha channel ConvFormat := IffFormat(Info.HasAlphaChannel, ifA8R8G8B8, ifR8G8B8) else if Info.HasGrayChannel or Info.IsIndexed then // Convert all grayscale and indexed images to Index8 unless they have alpha // (preserve it) ConvFormat := IffFormat(Info.HasAlphaChannel, ifA8R8G8B8, ifIndex8) else if Info.HasAlphaChannel then // Convert images with alpha channel to A8R8G8B8 ConvFormat := ifA8R8G8B8 else if Info.UsePixelFormat then // Convert 16bit RGB images (no alpha) to X1R5G5B5 ConvFormat := ifX1R5G5B5 else // Convert all other formats to R8G8B8 ConvFormat := ifR8G8B8; ConvertImage(Image, ConvFormat); end; function TBitmapFileFormat.TestFormat(Handle: TImagingHandle): Boolean; var Hdr: TBitmapFileHeader; ReadCount: LongInt; begin Result := False; if Handle <> nil then with GetIO do begin ReadCount := Read(Handle, @Hdr, SizeOf(Hdr)); Seek(Handle, -ReadCount, smFromCurrent); Result := (Hdr.ID = BMMagic) and (ReadCount = SizeOf(Hdr)); end; end; initialization RegisterImageFileFormat(TBitmapFileFormat); { File Notes: -- TODOS ---------------------------------------------------- - nothing now - Add option to choose to save V3 or V4 headers. -- 0.25.0 Changes/Bug Fixes --------------------------------- - Fixed problem with indexed BMP loading - some pal entries could end up with alpha=0. -- 0.23 Changes/Bug Fixes ----------------------------------- - Now saves bitmaps as bottom-up for better compatibility (mainly Lazarus' TImage!). - Fixed crash when loading bitmaps with headers larger than V4. - Temp hacks to disable V4 headers for 32bit images (compatibility with other soft). -- 0.21 Changes/Bug Fixes ----------------------------------- - Removed temporary data allocation for image with aligned scanlines. They are now directly written to output so memory requirements are much lower now. - Now uses and recognizes BITMAPINFOHEADERV4 when loading/saving. Mainly for formats with alpha channels. - Added ifR5G6B5 to supported formats, changed converting to supported formats little bit. - Rewritten SaveRLE8 nested procedure. Old code was long and mysterious - new is short and much more readable. - MakeCompatible method moved to base class, put ConvertToSupported here. GetSupportedFormats removed, it is now set in constructor. - Rewritten LoadRLE4 and LoadRLE8 nested procedures. Should be less buggy an more readable (load inspired by Colosseum Builders' code). - Made public properties for options registered to SetOption/GetOption functions. - Addded alpha check to 32b bitmap loading too (teh same as in 16b bitmap loading). - Moved Convert1To8 and Convert4To8 to ImagingFormats - Changed extensions to filename masks. - Changed SaveData, LoadData, and MakeCompatible methods according to changes in base class in Imaging unit. -- 0.19 Changes/Bug Fixes ----------------------------------- - fixed wrong const that caused A4R4G4B4 BMPs to load as A1R5G5B5 - fixed the bug that caused 8bit RLE compressed bitmaps to load as whole black -- 0.17 Changes/Bug Fixes ----------------------------------- - 16 bit images are usually without alpha but some has alpha channel and there is no indication of it - so I have added a check: if all pixels of image are with alpha = 0 image is treated as X1R5G5B5 otherwise as A1R5G5B5 -- 0.13 Changes/Bug Fixes ----------------------------------- - when loading 1/4 bit images with dword aligned dimensions there was ugly memory rewritting bug causing image corruption } end. ================================================ FILE: lib/Imaging/ImagingCanvases.pas ================================================ { Vampyre Imaging Library by Marek Mauder http://imaginglib.sourceforge.net The contents of this file are used with permission, subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/MPL-1.1.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Alternatively, the contents of this file may be used under the terms of the GNU Lesser General Public License (the "LGPL License"), in which case the provisions of the LGPL License are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of the LGPL License and not to allow others to use your version of this file under the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the LGPL License. If you do not delete the provisions above, a recipient may use your version of this file under either the MPL or the LGPL License. For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html } { This unit contains canvas classes for drawing and applying effects.} unit ImagingCanvases; {$I ImagingOptions.inc} interface uses SysUtils, Types, Classes, ImagingTypes, Imaging, ImagingClasses, ImagingFormats, ImagingUtility; const { Color constants in ifA8R8G8B8 format.} pcClear = $00000000; pcBlack = $FF000000; pcWhite = $FFFFFFFF; pcMaroon = $FF800000; pcGreen = $FF008000; pcOlive = $FF808000; pcNavy = $FF000080; pcPurple = $FF800080; pcTeal = $FF008080; pcGray = $FF808080; pcSilver = $FFC0C0C0; pcRed = $FFFF0000; pcLime = $FF00FF00; pcYellow = $FFFFFF00; pcBlue = $FF0000FF; pcFuchsia = $FFFF00FF; pcAqua = $FF00FFFF; pcLtGray = $FFC0C0C0; pcDkGray = $FF808080; MaxPenWidth = 256; type EImagingCanvasError = class(EImagingError); EImagingCanvasBlendingError = class(EImagingError); { Fill mode used when drawing filled objects on canvas.} TFillMode = ( fmSolid, // Solid fill using current fill color fmClear // No filling done ); { Pen mode used when drawing lines, object outlines, and similar on canvas.} TPenMode = ( pmSolid, // Draws solid lines using current pen color. pmClear // No drawing done ); { Source and destination blending factors for drawing functions with blending. Blending formula: SrcColor * SrcFactor + DestColor * DestFactor } TBlendingFactor = ( bfIgnore, // Don't care bfZero, // For Src and Dest, Factor = (0, 0, 0, 0) bfOne, // For Src and Dest, Factor = (1, 1, 1, 1) bfSrcAlpha, // For Src and Dest, Factor = (Src.A, Src.A, Src.A, Src.A) bfOneMinusSrcAlpha, // For Src and Dest, Factor = (1 - Src.A, 1 - Src.A, 1 - Src.A, 1 - Src.A) bfDstAlpha, // For Src and Dest, Factor = (Dest.A, Dest.A, Dest.A, Dest.A) bfOneMinusDstAlpha, // For Src and Dest, Factor = (1 - Dest.A, 1 - Dest.A, 1 - Dest.A, 1 - Dest.A) bfSrcColor, // For Dest, Factor = (Src.R, Src.R, Src.B, Src.A) bfOneMinusSrcColor, // For Dest, Factor = (1 - Src.R, 1 - Src.G, 1 - Src.B, 1 - Src.A) bfDstColor, // For Src, Factor = (Dest.R, Dest.G, Dest.B, Dest.A) bfOneMinusDstColor // For Src, Factor = (1 - Dest.R, 1 - Dest.G, 1 - Dest.B, 1 - Dest.A) ); { Procedure for custom pixel write modes with blending.} TPixelWriteProc = procedure(const SrcPix: TColorFPRec; DestPtr: PByte; DestInfo: PImageFormatInfo; SrcFactor, DestFactor: TBlendingFactor); { Represents 3x3 convolution filter kernel.} TConvolutionFilter3x3 = record Kernel: array[0..2, 0..2] of LongInt; Divisor: LongInt; Bias: Single; end; { Represents 5x5 convolution filter kernel.} TConvolutionFilter5x5 = record Kernel: array[0..4, 0..4] of LongInt; Divisor: LongInt; Bias: Single; end; TPointTransformFunction = function(const Pixel: TColorFPRec; Param1, Param2, Param3: Single): TColorFPRec; TDynFPPixelArray = array of TColorFPRec; THistogramArray = array[Byte] of Integer; TSelectPixelFunction = function(var Pixels: TDynFPPixelArray): TColorFPRec; { Base canvas class for drawing objects, applying effects, and other. Constructor takes TBaseImage (or pointer to TImageData). Source image bits are not copied but referenced so all canvas functions affect source image and vice versa. When you change format or resolution of source image you must call UpdateCanvasState method (so canvas could recompute some data size related stuff). TImagingCanvas works for all image data formats except special ones (compressed). Because of this its methods are quite slow (they usually work with colors in ifA32R32G32B32F format). If you want fast drawing you can use one of fast canvas clases. These descendants of TImagingCanvas work only for few select formats (or only one) but they are optimized thus much faster. } TImagingCanvas = class(TObject) private FDataSizeOnUpdate: LongInt; FLineRecursion: Boolean; function GetPixel32(X, Y: LongInt): TColor32; virtual; function GetPixelFP(X, Y: LongInt): TColorFPRec; virtual; function GetValid: Boolean; {$IFDEF USE_INLINE}inline;{$ENDIF} procedure SetPixel32(X, Y: LongInt; const Value: TColor32); virtual; procedure SetPixelFP(X, Y: LongInt; const Value: TColorFPRec); virtual; procedure SetPenColor32(const Value: TColor32); {$IFDEF USE_INLINE}inline;{$ENDIF} procedure SetPenColorFP(const Value: TColorFPRec); {$IFDEF USE_INLINE}inline;{$ENDIF} procedure SetPenWidth(const Value: LongInt); {$IFDEF USE_INLINE}inline;{$ENDIF} procedure SetFillColor32(const Value: TColor32); {$IFDEF USE_INLINE}inline;{$ENDIF} procedure SetFillColorFP(const Value: TColorFPRec); {$IFDEF USE_INLINE}inline;{$ENDIF} procedure SetClipRect(const Value: TRect); procedure CheckBeforeBlending(SrcFactor, DestFactor: TBlendingFactor; DestCanvas: TImagingCanvas); protected FPData: PImageData; FClipRect: TRect; FPenColorFP: TColorFPRec; FPenColor32: TColor32; FPenMode: TPenMode; FPenWidth: LongInt; FFillColorFP: TColorFPRec; FFillColor32: TColor32; FFillMode: TFillMode; FNativeColor: TColorFPRec; FFormatInfo: TImageFormatInfo; { Returns pointer to pixel at given position.} function GetPixelPointer(X, Y: LongInt): Pointer; {$IFDEF USE_INLINE}inline;{$ENDIF} { Translates given FP color to native format of canvas and stores it in FNativeColor field (its bit copy) or user pointer (in overloaded method).} procedure TranslateFPToNative(const Color: TColorFPRec); overload; {$IFDEF USE_INLINE}inline;{$ENDIF} procedure TranslateFPToNative(const Color: TColorFPRec; Native: Pointer); overload; {$IFDEF USE_INLINE}inline;{$ENDIF} { Clipping function used by horizontal and vertical line drawing functions.} function ClipAxisParallelLine(var A1, A2, B: LongInt; AStart, AStop, BStart, BStop: LongInt): Boolean; { Internal horizontal line drawer used mainly for filling inside of objects like ellipses and circles.} procedure HorzLineInternal(X1, X2, Y: LongInt; Color: Pointer; Bpp: LongInt); virtual; procedure CopyPixelInternal(X, Y: LongInt; Pixel: Pointer; Bpp: LongInt); {$IFDEF USE_INLINE}inline;{$ENDIF} procedure DrawInternal(const SrcRect: TRect; DestCanvas: TImagingCanvas; DestX, DestY: Integer; SrcFactor, DestFactor: TBlendingFactor; PixelWriteProc: TPixelWriteProc); procedure StretchDrawInternal(const SrcRect: TRect; DestCanvas: TImagingCanvas; const DestRect: TRect; SrcFactor, DestFactor: TBlendingFactor; Filter: TResizeFilter; PixelWriteProc: TPixelWriteProc); public constructor CreateForData(ImageDataPointer: PImageData); constructor CreateForImage(Image: TBaseImage); destructor Destroy; override; { Call this method when you change size or format of image this canvas operates on (like calling ResizeImage, ConvertImage, or changing Format property of TBaseImage descendants).} procedure UpdateCanvasState; virtual; { Resets clipping rectangle to Rect(0, 0, ImageWidth, ImageHeight).} procedure ResetClipRect; { Clears entire canvas with current fill color (ignores clipping rectangle and always uses fmSolid fill mode).} procedure Clear; { Draws horizontal line with current pen settings.} procedure HorzLine(X1, X2, Y: LongInt); virtual; { Draws vertical line with current pen settings.} procedure VertLine(X, Y1, Y2: LongInt); virtual; { Draws line from [X1, Y1] to [X2, Y2] with current pen settings.} procedure Line(X1, Y1, X2, Y2: LongInt); virtual; { Draws a rectangle using current pen settings.} procedure FrameRect(const Rect: TRect); { Fills given rectangle with current fill settings.} procedure FillRect(const Rect: TRect); virtual; { Fills given rectangle with current fill settings and pixel blending.} procedure FillRectBlend(const Rect: TRect; SrcFactor, DestFactor: TBlendingFactor); { Draws rectangle which is outlined by using the current pen settings and filled by using the current fill settings.} procedure Rectangle(const Rect: TRect); { Draws ellipse which is outlined by using the current pen settings and filled by using the current fill settings. Rect specifies bounding rectangle of ellipse to be drawn.} procedure Ellipse(const Rect: TRect); { Fills area of canvas with current fill color starting at point [X, Y] and coloring its neighbors. Default flood fill mode changes color of all neighbors with the same color as pixel [X, Y]. With BoundaryFillMode set to True neighbors are recolored regardless of their old color, but area which will be recolored has boundary (specified by current pen color).} procedure FloodFill(X, Y: Integer; BoundaryFillMode: Boolean = False); { Draws contents of this canvas onto another canvas with pixel blending. Blending factors are chosen using TBlendingFactor parameters. Resulting destination pixel color is: SrcColor * SrcFactor + DstColor * DstFactor} procedure DrawBlend(const SrcRect: TRect; DestCanvas: TImagingCanvas; DestX, DestY: Integer; SrcFactor, DestFactor: TBlendingFactor); { Draws contents of this canvas onto another one with typical alpha blending (Src 'over' Dest, factors are bfSrcAlpha and bfOneMinusSrcAlpha.)} procedure DrawAlpha(const SrcRect: TRect; DestCanvas: TImagingCanvas; DestX, DestY: Integer); virtual; { Draws contents of this canvas onto another one using additive blending (source and dest factors are bfOne).} procedure DrawAdd(const SrcRect: TRect; DestCanvas: TImagingCanvas; DestX, DestY: Integer); { Draws stretched and filtered contents of this canvas onto another canvas with pixel blending. Blending factors are chosen using TBlendingFactor parameters. Resulting destination pixel color is: SrcColor * SrcFactor + DstColor * DstFactor} procedure StretchDrawBlend(const SrcRect: TRect; DestCanvas: TImagingCanvas; const DestRect: TRect; SrcFactor, DestFactor: TBlendingFactor; Filter: TResizeFilter = rfBilinear); { Draws contents of this canvas onto another one with typical alpha blending (Src 'over' Dest, factors are bfSrcAlpha and bfOneMinusSrcAlpha.)} procedure StretchDrawAlpha(const SrcRect: TRect; DestCanvas: TImagingCanvas; const DestRect: TRect; Filter: TResizeFilter = rfBilinear); virtual; { Draws contents of this canvas onto another one using additive blending (source and dest factors are bfOne).} procedure StretchDrawAdd(const SrcRect: TRect; DestCanvas: TImagingCanvas; const DestRect: TRect; Filter: TResizeFilter = rfBilinear); { Convolves canvas' image with given 3x3 filter kernel. You can use predefined filter kernels or define your own.} procedure ApplyConvolution3x3(const Filter: TConvolutionFilter3x3); { Convolves canvas' image with given 5x5 filter kernel. You can use predefined filter kernels or define your own.} procedure ApplyConvolution5x5(const Filter: TConvolutionFilter5x5); { Computes 2D convolution of canvas' image and given filter kernel. Kernel is in row format and KernelSize must be odd number >= 3. Divisor is normalizing value based on Kernel (usually sum of all kernel's cells). The Bias number shifts each color value by a fixed amount (color values are usually in range [0, 1] during processing). If ClampChannels is True all output color values are clamped to [0, 1]. You can use predefined filter kernels or define your own.} procedure ApplyConvolution(Kernel: PLongInt; KernelSize, Divisor: LongInt; Bias: Single = 0.0; ClampChannels: Boolean = True); virtual; { Applies custom non-linear filter. Filter size is diameter of pixel neighborhood. Typical values are 3, 5, or 7. } procedure ApplyNonLinearFilter(FilterSize: Integer; SelectFunc: TSelectPixelFunction); { Applies median non-linear filter with user defined pixel neighborhood. Selects median pixel from the neighborhood as new pixel (current implementation is quite slow).} procedure ApplyMedianFilter(FilterSize: Integer); { Applies min non-linear filter with user defined pixel neighborhood. Selects min pixel from the neighborhood as new pixel.} procedure ApplyMinFilter(FilterSize: Integer); { Applies max non-linear filter with user defined pixel neighborhood. Selects max pixel from the neighborhood as new pixel.} procedure ApplyMaxFilter(FilterSize: Integer); { Transforms pixels one by one by given function. Pixel neighbors are not taken into account. Param 1-3 are optional parameters for transform function.} procedure PointTransform(Transform: TPointTransformFunction; Param1, Param2, Param3: Single); { Modifies image contrast and brightness. Parameters should be in range <-100; 100>.} procedure ModifyContrastBrightness(Contrast, Brightness: Single); { Gamma correction of individual color channels. Range is (0, +inf), 1.0 means no change.} procedure GammaCorection(Red, Green, Blue: Single); { Inverts colors of all image pixels, makes negative image. Ignores alpha channel.} procedure InvertColors; virtual; { Simple single level thresholding with threshold level (in range [0, 1]) for each color channel.} procedure Threshold(Red, Green, Blue: Single); { Adjusts the color levels of the image by scaling the colors falling between specified white and black points to full [0, 1] range. The black point specifies the darkest color in the image, white point specifies the lightest color, and mid point is gamma aplied to image. Black and white point must be in range [0, 1].} procedure AdjustColorLevels(BlackPoint, WhitePoint: Single; MidPoint: Single = 1.0); { Premultiplies color channel values by alpha. Needed for some platforms/APIs to display images with alpha properly.} procedure PremultiplyAlpha; { Reverses PremultiplyAlpha operation.} procedure UnPremultiplyAlpha; { Calculates image histogram for each channel and also gray values. Each channel has 256 values available. Channel values of data formats with higher precision are scaled and rounded. Example: Red[126] specifies number of pixels in image with red channel = 126.} procedure GetHistogram(out Red, Green, Blue, Alpha, Gray: THistogramArray); { Fills image channel with given value leaving other channels intact. Use ChannelAlpha, ChannelRed, etc. constants from ImagingTypes as channel identifier.} procedure FillChannel(ChannelId: Integer; NewChannelValue: Byte); overload; { Fills image channel with given value leaving other channels intact. Use ChannelAlpha, ChannelRed, etc. constants from ImagingTypes as channel identifier.} procedure FillChannelFP(ChannelId: Integer; NewChannelValue: Single); overload; { Color used when drawing lines, frames, and outlines of objects.} property PenColor32: TColor32 read FPenColor32 write SetPenColor32; { Color used when drawing lines, frames, and outlines of objects.} property PenColorFP: TColorFPRec read FPenColorFP write SetPenColorFP; { Pen mode used when drawing lines, object outlines, and similar on canvas.} property PenMode: TPenMode read FPenMode write FPenMode; { Width with which objects like lines, frames, etc. (everything which uses PenColor) are drawn.} property PenWidth: LongInt read FPenWidth write SetPenWidth; { Color used for filling when drawing various objects.} property FillColor32: TColor32 read FFillColor32 write SetFillColor32; { Color used for filling when drawing various objects.} property FillColorFP: TColorFPRec read FFillColorFP write SetFillColorFP; { Fill mode used when drawing filled objects on canvas.} property FillMode: TFillMode read FFillMode write FFillMode; { Specifies the current color of the pixels of canvas. Native pixel is read from canvas and then translated to 32bit ARGB. Reverse operation is made when setting pixel color.} property Pixels32[X, Y: LongInt]: TColor32 read GetPixel32 write SetPixel32; { Specifies the current color of the pixels of canvas. Native pixel is read from canvas and then translated to FP ARGB. Reverse operation is made when setting pixel color.} property PixelsFP[X, Y: LongInt]: TColorFPRec read GetPixelFP write SetPixelFP; { Clipping rectangle of this canvas. No pixels outside this rectangle are altered by canvas methods if Clipping property is True. Clip rect gets reseted when UpdateCanvasState is called.} property ClipRect: TRect read FClipRect write SetClipRect; { Extended format information.} property FormatInfo: TImageFormatInfo read FFormatInfo; { Indicates that this canvas is in valid state. If False canvas oprations may crash.} property Valid: Boolean read GetValid; { Returns all formats supported by this canvas class.} class function GetSupportedFormats: TImageFormats; virtual; end; TImagingCanvasClass = class of TImagingCanvas; TScanlineArray = array[0..MaxInt div SizeOf(Pointer) - 1] of PColor32RecArray; PScanlineArray = ^TScanlineArray; { Fast canvas class for ifA8R8G8B8 format images.} TFastARGB32Canvas = class(TImagingCanvas) protected FScanlines: PScanlineArray; procedure AlphaBlendPixels(SrcPix, DestPix: PColor32Rec); {$IFDEF USE_INLINE}inline;{$ENDIF} function GetPixel32(X, Y: LongInt): TColor32; override; procedure SetPixel32(X, Y: LongInt; const Value: TColor32); override; public destructor Destroy; override; procedure UpdateCanvasState; override; procedure DrawAlpha(const SrcRect: TRect; DestCanvas: TImagingCanvas; DestX, DestY: Integer); override; procedure StretchDrawAlpha(const SrcRect: TRect; DestCanvas: TImagingCanvas; const DestRect: TRect; Filter: TResizeFilter = rfBilinear); override; procedure InvertColors; override; property Scanlines: PScanlineArray read FScanlines; class function GetSupportedFormats: TImageFormats; override; end; const { Kernel for 3x3 average smoothing filter.} FilterAverage3x3: TConvolutionFilter3x3 = ( Kernel: ((1, 1, 1), (1, 1, 1), (1, 1, 1)); Divisor: 9); { Kernel for 5x5 average smoothing filter.} FilterAverage5x5: TConvolutionFilter5x5 = ( Kernel: ((1, 1, 1, 1, 1), (1, 1, 1, 1, 1), (1, 1, 1, 1, 1), (1, 1, 1, 1, 1), (1, 1, 1, 1, 1)); Divisor: 25); { Kernel for 3x3 Gaussian smoothing filter.} FilterGaussian3x3: TConvolutionFilter3x3 = ( Kernel: ((1, 2, 1), (2, 4, 2), (1, 2, 1)); Divisor: 16); { Kernel for 5x5 Gaussian smoothing filter.} FilterGaussian5x5: TConvolutionFilter5x5 = ( Kernel: ((1, 4, 6, 4, 1), (4, 16, 24, 16, 4), (6, 24, 36, 24, 6), (4, 16, 24, 16, 4), (1, 4, 6, 4, 1)); Divisor: 256); { Kernel for 3x3 Sobel horizontal edge detection filter (1st derivative approximation).} FilterSobelHorz3x3: TConvolutionFilter3x3 = ( Kernel: (( 1, 2, 1), ( 0, 0, 0), (-1, -2, -1)); Divisor: 1); { Kernel for 3x3 Sobel vertical edge detection filter (1st derivative approximation).} FilterSobelVert3x3: TConvolutionFilter3x3 = ( Kernel: ((-1, 0, 1), (-2, 0, 2), (-1, 0, 1)); Divisor: 1); { Kernel for 3x3 Prewitt horizontal edge detection filter.} FilterPrewittHorz3x3: TConvolutionFilter3x3 = ( Kernel: (( 1, 1, 1), ( 0, 0, 0), (-1, -1, -1)); Divisor: 1); { Kernel for 3x3 Prewitt vertical edge detection filter.} FilterPrewittVert3x3: TConvolutionFilter3x3 = ( Kernel: ((-1, 0, 1), (-1, 0, 1), (-1, 0, 1)); Divisor: 1); { Kernel for 3x3 Kirsh horizontal edge detection filter.} FilterKirshHorz3x3: TConvolutionFilter3x3 = ( Kernel: (( 5, 5, 5), (-3, 0, -3), (-3, -3, -3)); Divisor: 1); { Kernel for 3x3 Kirsh vertical edge detection filter.} FilterKirshVert3x3: TConvolutionFilter3x3 = ( Kernel: ((5, -3, -3), (5, 0, -3), (5, -3, -3)); Divisor: 1); { Kernel for 3x3 Laplace omni-directional edge detection filter (2nd derivative approximation).} FilterLaplace3x3: TConvolutionFilter3x3 = ( Kernel: ((-1, -1, -1), (-1, 8, -1), (-1, -1, -1)); Divisor: 1); { Kernel for 5x5 Laplace omni-directional edge detection filter (2nd derivative approximation).} FilterLaplace5x5: TConvolutionFilter5x5 = ( Kernel: ((-1, -1, -1, -1, -1), (-1, -1, -1, -1, -1), (-1, -1, 24, -1, -1), (-1, -1, -1, -1, -1), (-1, -1, -1, -1, -1)); Divisor: 1); { Kernel for 3x3 spharpening filter (Laplacian + original color).} FilterSharpen3x3: TConvolutionFilter3x3 = ( Kernel: ((-1, -1, -1), (-1, 9, -1), (-1, -1, -1)); Divisor: 1); { Kernel for 5x5 spharpening filter (Laplacian + original color).} FilterSharpen5x5: TConvolutionFilter5x5 = ( Kernel: ((-1, -1, -1, -1, -1), (-1, -1, -1, -1, -1), (-1, -1, 25, -1, -1), (-1, -1, -1, -1, -1), (-1, -1, -1, -1, -1)); Divisor: 1); { Kernel for 5x5 glow filter.} FilterGlow5x5: TConvolutionFilter5x5 = ( Kernel: (( 1, 2, 2, 2, 1), ( 2, 0, 0, 0, 2), ( 2, 0, -20, 0, 2), ( 2, 0, 0, 0, 2), ( 1, 2, 2, 2, 1)); Divisor: 8); { Kernel for 3x3 edge enhancement filter.} FilterEdgeEnhance3x3: TConvolutionFilter3x3 = ( Kernel: ((-1, -2, -1), (-2, 16, -2), (-1, -2, -1)); Divisor: 4); { Kernel for 3x3 contour enhancement filter.} FilterTraceControur3x3: TConvolutionFilter3x3 = ( Kernel: ((-6, -6, -2), (-1, 32, -1), (-6, -2, -6)); Divisor: 4; Bias: 240/255); { Kernel for filter that negates all images pixels.} FilterNegative3x3: TConvolutionFilter3x3 = ( Kernel: ((0, 0, 0), (0, -1, 0), (0, 0, 0)); Divisor: 1; Bias: 1); { Kernel for 3x3 horz/vert embossing filter.} FilterEmboss3x3: TConvolutionFilter3x3 = ( Kernel: ((2, 0, 0), (0, -1, 0), (0, 0, -1)); Divisor: 1; Bias: 0.5); { You can register your own canvas class. List of registered canvases is used by FindBestCanvasForImage functions to find best canvas for given image. If two different canvases which support the same image data format are registered then the one that was registered later is returned (so you can override builtin Imaging canvases).} procedure RegisterCanvas(CanvasClass: TImagingCanvasClass); { Returns best canvas for given TImageFormat.} function FindBestCanvasForImage(ImageFormat: TImageFormat): TImagingCanvasClass; overload; { Returns best canvas for given TImageData.} function FindBestCanvasForImage(const ImageData: TImageData): TImagingCanvasClass; overload; { Returns best canvas for given TBaseImage.} function FindBestCanvasForImage(Image: TBaseImage): TImagingCanvasClass; overload; implementation resourcestring SConstructorInvalidPointer = 'Invalid pointer (%p) to TImageData passed to TImagingCanvas constructor.'; SConstructorInvalidImage = 'Invalid image data passed to TImagingCanvas constructor (%s).'; SConstructorUnsupportedFormat = 'Image passed to TImagingCanvas constructor is in unsupported format (%s)'; var // list with all registered TImagingCanvas classes CanvasClasses: TList = nil; procedure RegisterCanvas(CanvasClass: TImagingCanvasClass); begin Assert(CanvasClass <> nil); if CanvasClasses = nil then CanvasClasses := TList.Create; if CanvasClasses.IndexOf(CanvasClass) < 0 then CanvasClasses.Add(CanvasClass); end; function FindBestCanvasForImage(ImageFormat: TImageFormat): TImagingCanvasClass; overload; var I: LongInt; begin for I := CanvasClasses.Count - 1 downto 0 do begin if ImageFormat in TImagingCanvasClass(CanvasClasses[I]).GetSupportedFormats then begin Result := TImagingCanvasClass(CanvasClasses[I]); Exit; end; end; Result := TImagingCanvas; end; function FindBestCanvasForImage(const ImageData: TImageData): TImagingCanvasClass; begin Result := FindBestCanvasForImage(ImageData.Format); end; function FindBestCanvasForImage(Image: TBaseImage): TImagingCanvasClass; begin Result := FindBestCanvasForImage(Image.Format); end; { Canvas helper functions } procedure PixelBlendProc(const SrcPix: TColorFPRec; DestPtr: PByte; DestInfo: PImageFormatInfo; SrcFactor, DestFactor: TBlendingFactor); var DestPix, FSrc, FDst: TColorFPRec; begin // Get set pixel color DestPix := DestInfo.GetPixelFP(DestPtr, DestInfo, nil); // Determine current blending factors case SrcFactor of bfZero: FSrc := ColorFP(0, 0, 0, 0); bfOne: FSrc := ColorFP(1, 1, 1, 1); bfSrcAlpha: FSrc := ColorFP(SrcPix.A, SrcPix.A, SrcPix.A, SrcPix.A); bfOneMinusSrcAlpha: FSrc := ColorFP(1 - SrcPix.A, 1 - SrcPix.A, 1 - SrcPix.A, 1 - SrcPix.A); bfDstAlpha: FSrc := ColorFP(DestPix.A, DestPix.A, DestPix.A, DestPix.A); bfOneMinusDstAlpha: FSrc := ColorFP(1 - DestPix.A, 1 - DestPix.A, 1 - DestPix.A, 1 - DestPix.A); bfDstColor: FSrc := ColorFP(DestPix.A, DestPix.R, DestPix.G, DestPix.B); bfOneMinusDstColor: FSrc := ColorFP(1 - DestPix.A, 1 - DestPix.R, 1 - DestPix.G, 1 - DestPix.B); end; case DestFactor of bfZero: FDst := ColorFP(0, 0, 0, 0); bfOne: FDst := ColorFP(1, 1, 1, 1); bfSrcAlpha: FDst := ColorFP(SrcPix.A, SrcPix.A, SrcPix.A, SrcPix.A); bfOneMinusSrcAlpha: FDst := ColorFP(1 - SrcPix.A, 1 - SrcPix.A, 1 - SrcPix.A, 1 - SrcPix.A); bfDstAlpha: FDst := ColorFP(DestPix.A, DestPix.A, DestPix.A, DestPix.A); bfOneMinusDstAlpha: FDst := ColorFP(1 - DestPix.A, 1 - DestPix.A, 1 - DestPix.A, 1 - DestPix.A); bfSrcColor: FDst := ColorFP(SrcPix.A, SrcPix.R, SrcPix.G, SrcPix.B); bfOneMinusSrcColor: FDst := ColorFP(1 - SrcPix.A, 1 - SrcPix.R, 1 - SrcPix.G, 1 - SrcPix.B); end; // Compute blending formula DestPix.R := SrcPix.R * FSrc.R + DestPix.R * FDst.R; DestPix.G := SrcPix.G * FSrc.G + DestPix.G * FDst.G; DestPix.B := SrcPix.B * FSrc.B + DestPix.B * FDst.B; DestPix.A := SrcPix.A * FSrc.A + DestPix.A * FDst.A; // Write blended pixel DestInfo.SetPixelFP(DestPtr, DestInfo, nil, DestPix); end; procedure PixelAlphaProc(const SrcPix: TColorFPRec; DestPtr: PByte; DestInfo: PImageFormatInfo; SrcFactor, DestFactor: TBlendingFactor); var DestPix: TColorFPRec; SrcAlpha, DestAlpha: Single; begin DestPix := DestInfo.GetPixelFP(DestPtr, DestInfo, nil); // Blend the two pixels (Src 'over' Dest alpha composition operation) DestPix.A := SrcPix.A + DestPix.A - SrcPix.A * DestPix.A; if DestPix.A = 0 then SrcAlpha := 0 else SrcAlpha := SrcPix.A / DestPix.A; DestAlpha := 1.0 - SrcAlpha; DestPix.R := SrcPix.R * SrcAlpha + DestPix.R * DestAlpha; DestPix.G := SrcPix.G * SrcAlpha + DestPix.G * DestAlpha; DestPix.B := SrcPix.B * SrcAlpha + DestPix.B * DestAlpha; // Write blended pixel DestInfo.SetPixelFP(DestPtr, DestInfo, nil, DestPix); end; procedure PixelAddProc(const SrcPix: TColorFPRec; DestPtr: PByte; DestInfo: PImageFormatInfo; SrcFactor, DestFactor: TBlendingFactor); var DestPix: TColorFPRec; begin // Just add Src and Dest DestPix := DestInfo.GetPixelFP(DestPtr, DestInfo, nil); DestPix.R := SrcPix.R + DestPix.R; DestPix.G := SrcPix.G + DestPix.G; DestPix.B := SrcPix.B + DestPix.B; DestPix.A := SrcPix.A + DestPix.A; DestInfo.SetPixelFP(DestPtr, DestInfo, nil, DestPix); end; function CompareColors(const C1, C2: TColorFPRec): Single; {$IFDEF USE_INLINE}inline;{$ENDIF} begin Result := (C1.R * GrayConv.R + C1.G * GrayConv.G + C1.B * GrayConv.B) - (C2.R * GrayConv.R + C2.G * GrayConv.G + C2.B * GrayConv.B); end; function MedianSelect(var Pixels: TDynFPPixelArray): TColorFPRec; procedure QuickSort(L, R: Integer); var I, J: Integer; P, Temp: TColorFPRec; begin repeat I := L; J := R; P := Pixels[(L + R) shr 1]; repeat while CompareColors(Pixels[I], P) < 0 do Inc(I); while CompareColors(Pixels[J], P) > 0 do Dec(J); if I <= J then begin Temp := Pixels[I]; Pixels[I] := Pixels[J]; Pixels[J] := Temp; Inc(I); Dec(J); end; until I > J; if L < J then QuickSort(L, J); L := I; until I >= R; end; begin // First sort pixels QuickSort(0, High(Pixels)); // Select middle pixel Result := Pixels[Length(Pixels) div 2]; end; function MinSelect(var Pixels: TDynFPPixelArray): TColorFPRec; var I: Integer; begin Result := Pixels[0]; for I := 1 to High(Pixels) do begin if CompareColors(Pixels[I], Result) < 0 then Result := Pixels[I]; end; end; function MaxSelect(var Pixels: TDynFPPixelArray): TColorFPRec; var I: Integer; begin Result := Pixels[0]; for I := 1 to High(Pixels) do begin if CompareColors(Pixels[I], Result) > 0 then Result := Pixels[I]; end; end; function TransformContrastBrightness(const Pixel: TColorFPRec; C, B, P3: Single): TColorFPRec; begin Result.A := Pixel.A; Result.R := Pixel.R * C + B; Result.G := Pixel.G * C + B; Result.B := Pixel.B * C + B; end; function TransformGamma(const Pixel: TColorFPRec; R, G, B: Single): TColorFPRec; begin Result.A := Pixel.A; Result.R := Power(Pixel.R, 1.0 / R); Result.G := Power(Pixel.G, 1.0 / G); Result.B := Power(Pixel.B, 1.0 / B); end; function TransformInvert(const Pixel: TColorFPRec; P1, P2, P3: Single): TColorFPRec; begin Result.A := Pixel.A; Result.R := 1.0 - Pixel.R; Result.G := 1.0 - Pixel.G; Result.B := 1.0 - Pixel.B; end; function TransformThreshold(const Pixel: TColorFPRec; R, G, B: Single): TColorFPRec; begin Result.A := Pixel.A; Result.R := IffFloat(Pixel.R >= R, 1.0, 0.0); Result.G := IffFloat(Pixel.G >= G, 1.0, 0.0); Result.B := IffFloat(Pixel.B >= B, 1.0, 0.0); end; function TransformLevels(const Pixel: TColorFPRec; BlackPoint, WhitePoint, Exp: Single): TColorFPRec; begin Result.A := Pixel.A; if Pixel.R > BlackPoint then Result.R := Power((Pixel.R - BlackPoint) / (WhitePoint - BlackPoint), Exp) else Result.R := 0.0; if Pixel.G > BlackPoint then Result.G := Power((Pixel.G - BlackPoint) / (WhitePoint - BlackPoint), Exp) else Result.G := 0.0; if Pixel.B > BlackPoint then Result.B := Power((Pixel.B - BlackPoint) / (WhitePoint - BlackPoint), Exp) else Result.B := 0.0; end; function TransformPremultiplyAlpha(const Pixel: TColorFPRec; P1, P2, P3: Single): TColorFPRec; begin Result.A := Pixel.A; Result.R := Result.R * Pixel.A; Result.G := Result.G * Pixel.A; Result.B := Result.B * Pixel.A; end; function TransformUnPremultiplyAlpha(const Pixel: TColorFPRec; P1, P2, P3: Single): TColorFPRec; begin Result.A := Pixel.A; if Pixel.A <> 0.0 then begin Result.R := Result.R / Pixel.A; Result.G := Result.G / Pixel.A; Result.B := Result.B / Pixel.A; end else begin Result.R := 0; Result.G := 0; Result.B := 0; end; end; { TImagingCanvas class implementation } constructor TImagingCanvas.CreateForData(ImageDataPointer: PImageData); begin if ImageDataPointer = nil then raise EImagingCanvasError.CreateFmt(SConstructorInvalidPointer, [ImageDataPointer]); if not TestImage(ImageDataPointer^) then raise EImagingCanvasError.CreateFmt(SConstructorInvalidImage, [Imaging.ImageToStr(ImageDataPointer^)]); if not (ImageDataPointer.Format in GetSupportedFormats) then raise EImagingCanvasError.CreateFmt(SConstructorUnsupportedFormat, [Imaging.ImageToStr(ImageDataPointer^)]); FPData := ImageDataPointer; FPenWidth := 1; SetPenColor32(pcWhite); SetFillColor32(pcBlack); FFillMode := fmSolid; UpdateCanvasState; end; constructor TImagingCanvas.CreateForImage(Image: TBaseImage); begin CreateForData(Image.ImageDataPointer); end; destructor TImagingCanvas.Destroy; begin inherited Destroy; end; function TImagingCanvas.GetPixel32(X, Y: LongInt): TColor32; begin Result := Imaging.GetPixel32(FPData^, X, Y).Color; end; function TImagingCanvas.GetPixelFP(X, Y: LongInt): TColorFPRec; begin Result := Imaging.GetPixelFP(FPData^, X, Y); end; function TImagingCanvas.GetValid: Boolean; begin Result := (FPData <> nil) and (FDataSizeOnUpdate = FPData.Size); end; procedure TImagingCanvas.SetPixel32(X, Y: LongInt; const Value: TColor32); begin if (X >= FClipRect.Left) and (Y >= FClipRect.Top) and (X < FClipRect.Right) and (Y < FClipRect.Bottom) then begin Imaging.SetPixel32(FPData^, X, Y, TColor32Rec(Value)); end; end; procedure TImagingCanvas.SetPixelFP(X, Y: LongInt; const Value: TColorFPRec); begin if (X >= FClipRect.Left) and (Y >= FClipRect.Top) and (X < FClipRect.Right) and (Y < FClipRect.Bottom) then begin Imaging.SetPixelFP(FPData^, X, Y, TColorFPRec(Value)); end; end; procedure TImagingCanvas.SetPenColor32(const Value: TColor32); begin FPenColor32 := Value; TranslatePixel(@FPenColor32, @FPenColorFP, ifA8R8G8B8, ifA32R32G32B32F, nil, nil); end; procedure TImagingCanvas.SetPenColorFP(const Value: TColorFPRec); begin FPenColorFP := Value; TranslatePixel(@FPenColorFP, @FPenColor32, ifA32R32G32B32F, ifA8R8G8B8, nil, nil); end; procedure TImagingCanvas.SetPenWidth(const Value: LongInt); begin FPenWidth := ClampInt(Value, 0, MaxPenWidth); end; procedure TImagingCanvas.SetFillColor32(const Value: TColor32); begin FFillColor32 := Value; TranslatePixel(@FFillColor32, @FFillColorFP, ifA8R8G8B8, ifA32R32G32B32F, nil, nil); end; procedure TImagingCanvas.SetFillColorFP(const Value: TColorFPRec); begin FFillColorFP := Value; TranslatePixel(@FFillColorFP, @FFillColor32, ifA32R32G32B32F, ifA8R8G8B8, nil, nil); end; procedure TImagingCanvas.SetClipRect(const Value: TRect); begin FClipRect := Value; SwapMin(FClipRect.Left, FClipRect.Right); SwapMin(FClipRect.Top, FClipRect.Bottom); IntersectRect(FClipRect, FClipRect, Rect(0, 0, FPData.Width, FPData.Height)); end; procedure TImagingCanvas.CheckBeforeBlending(SrcFactor, DestFactor: TBlendingFactor; DestCanvas: TImagingCanvas); begin if SrcFactor in [bfSrcColor, bfOneMinusSrcColor] then raise EImagingCanvasBlendingError.Create('Invalid source blending factor. Check the documentation for TBlendingFactor.'); if DestFactor in [bfDstColor, bfOneMinusDstColor] then raise EImagingCanvasBlendingError.Create('Invalid destination blending factor. Check the documentation for TBlendingFactor.'); if DestCanvas.FormatInfo.IsIndexed then raise EImagingCanvasBlendingError.Create('Blending destination canvas cannot be in indexed mode.'); end; function TImagingCanvas.GetPixelPointer(X, Y: LongInt): Pointer; begin Result := @PByteArray(FPData.Bits)[(Y * FPData.Width + X) * FFormatInfo.BytesPerPixel] end; procedure TImagingCanvas.TranslateFPToNative(const Color: TColorFPRec); begin TranslateFPToNative(Color, @FNativeColor); end; procedure TImagingCanvas.TranslateFPToNative(const Color: TColorFPRec; Native: Pointer); begin ImagingFormats.TranslatePixel(@Color, Native, ifA32R32G32B32F, FPData.Format, nil, FPData.Palette); end; procedure TImagingCanvas.UpdateCanvasState; begin FDataSizeOnUpdate := FPData.Size; ResetClipRect; Imaging.GetImageFormatInfo(FPData.Format, FFormatInfo) end; procedure TImagingCanvas.ResetClipRect; begin FClipRect := Rect(0, 0, FPData.Width, FPData.Height) end; procedure TImagingCanvas.Clear; begin TranslateFPToNative(FFillColorFP); Imaging.FillRect(FPData^, 0, 0, FPData.Width, FPData.Height, @FNativeColor); end; function TImagingCanvas.ClipAxisParallelLine(var A1, A2, B: LongInt; AStart, AStop, BStart, BStop: LongInt): Boolean; begin if (B >= BStart) and (B < BStop) then begin SwapMin(A1, A2); if A1 < AStart then A1 := AStart; if A2 >= AStop then A2 := AStop - 1; Result := True; end else Result := False; end; procedure TImagingCanvas.HorzLineInternal(X1, X2, Y: LongInt; Color: Pointer; Bpp: LongInt); var I, WidthBytes: LongInt; PixelPtr: PByte; begin if (Y >= FClipRect.Top) and (Y < FClipRect.Bottom) then begin SwapMin(X1, X2); X1 := Max(X1, FClipRect.Left); X2 := Min(X2, FClipRect.Right); PixelPtr := GetPixelPointer(X1, Y); WidthBytes := (X2 - X1) * Bpp; case Bpp of 1: FillMemoryByte(PixelPtr, WidthBytes, PByte(Color)^); 2: FillMemoryWord(PixelPtr, WidthBytes, PWord(Color)^); 4: FillMemoryLongWord(PixelPtr, WidthBytes, PLongWord(Color)^); else for I := X1 to X2 do begin ImagingFormats.CopyPixel(Color, PixelPtr, Bpp); Inc(PixelPtr, Bpp); end; end; end; end; procedure TImagingCanvas.CopyPixelInternal(X, Y: LongInt; Pixel: Pointer; Bpp: LongInt); begin if (X >= FClipRect.Left) and (Y >= FClipRect.Top) and (X < FClipRect.Right) and (Y < FClipRect.Bottom) then begin ImagingFormats.CopyPixel(Pixel, GetPixelPointer(X, Y), Bpp); end; end; procedure TImagingCanvas.HorzLine(X1, X2, Y: LongInt); var DstRect: TRect; begin if FPenMode = pmClear then Exit; SwapMin(X1, X2); if IntersectRect(DstRect, Rect(X1, Y - FPenWidth div 2, X2, Y + FPenWidth div 2 + FPenWidth mod 2), FClipRect) then begin TranslateFPToNative(FPenColorFP); Imaging.FillRect(FPData^, DstRect.Left, DstRect.Top, DstRect.Right - DstRect.Left, DstRect.Bottom - DstRect.Top, @FNativeColor); end; end; procedure TImagingCanvas.VertLine(X, Y1, Y2: LongInt); var DstRect: TRect; begin if FPenMode = pmClear then Exit; SwapMin(Y1, Y2); if IntersectRect(DstRect, Rect(X - FPenWidth div 2, Y1, X + FPenWidth div 2 + FPenWidth mod 2, Y2), FClipRect) then begin TranslateFPToNative(FPenColorFP); Imaging.FillRect(FPData^, DstRect.Left, DstRect.Top, DstRect.Right - DstRect.Left, DstRect.Bottom - DstRect.Top, @FNativeColor); end; end; procedure TImagingCanvas.Line(X1, Y1, X2, Y2: LongInt); var Steep: Boolean; Error, YStep, DeltaX, DeltaY, X, Y, I, Bpp, W1, W2, Code1, Code2: LongInt; begin if FPenMode = pmClear then Exit; // If line is vertical or horizontal just call appropriate method if X2 = X1 then begin VertLine(X1, Y1, Y2); Exit; end; if Y2 = Y1 then begin HorzLine(X1, X2, Y1); Exit; end; // Determine if line is steep (angle with X-axis > 45 degrees) Steep := Abs(Y2 - Y1) > Abs(X2 - X1); // If we need to draw thick line we just draw more 1 pixel lines around // the one we already drawn. Setting FLineRecursion assures that we // won't be doing recursions till the end of the world. if (FPenWidth > 1) and not FLineRecursion then begin FLineRecursion := True; W1 := FPenWidth div 2; W2 := W1; if FPenWidth mod 2 = 0 then Dec(W1); if Steep then begin // Add lines left/right for I := 1 to W1 do Line(X1, Y1 - I, X2, Y2 - I); for I := 1 to W2 do Line(X1, Y1 + I, X2, Y2 + I); end else begin // Add lines above/under for I := 1 to W1 do Line(X1 - I, Y1, X2 - I, Y2); for I := 1 to W2 do Line(X1 + I, Y1, X2 + I, Y2); end; FLineRecursion := False; end; with FClipRect do begin // Use part of Cohen-Sutherland line clipping to determine if any part of line // is in ClipRect Code1 := Ord(X1 < Left) + Ord(X1 > Right) shl 1 + Ord(Y1 < Top) shl 2 + Ord(Y1 > Bottom) shl 3; Code2 := Ord(X2 < Left) + Ord(X2 > Right) shl 1 + Ord(Y2 < Top) shl 2 + Ord(Y2 > Bottom) shl 3; end; if (Code1 and Code2) = 0 then begin TranslateFPToNative(FPenColorFP); Bpp := FFormatInfo.BytesPerPixel; // If line is steep swap X and Y coordinates so later we just have one loop // of two (where only one is used according to steepness). if Steep then begin SwapValues(X1, Y1); SwapValues(X2, Y2); end; if X1 > X2 then begin SwapValues(X1, X2); SwapValues(Y1, Y2); end; DeltaX := X2 - X1; DeltaY := Abs(Y2 - Y1); YStep := Iff(Y2 > Y1, 1, -1); Error := 0; Y := Y1; // Draw line using Bresenham algorithm. No real line clipping here, // just don't draw pixels outsize clip rect. for X := X1 to X2 do begin if Steep then CopyPixelInternal(Y, X, @FNativeColor, Bpp) else CopyPixelInternal(X, Y, @FNativeColor, Bpp); Error := Error + DeltaY; if Error * 2 >= DeltaX then begin Inc(Y, YStep); Dec(Error, DeltaX); end; end; end; end; procedure TImagingCanvas.FrameRect(const Rect: TRect); var HalfPen, PenMod: LongInt; begin if FPenMode = pmClear then Exit; HalfPen := FPenWidth div 2; PenMod := FPenWidth mod 2; HorzLine(Rect.Left - HalfPen, Rect.Right + HalfPen + PenMod - 1, Rect.Top); HorzLine(Rect.Left - HalfPen, Rect.Right + HalfPen + PenMod - 1, Rect.Bottom - 1); VertLine(Rect.Left, Rect.Top, Rect.Bottom); VertLine(Rect.Right - 1, Rect.Top, Rect.Bottom); end; procedure TImagingCanvas.FillRect(const Rect: TRect); var DstRect: TRect; begin if (FFillMode <> fmClear) and IntersectRect(DstRect, Rect, FClipRect) then begin TranslateFPToNative(FFillColorFP); Imaging.FillRect(FPData^, DstRect.Left, DstRect.Top, DstRect.Right - DstRect.Left, DstRect.Bottom - DstRect.Top, @FNativeColor); end; end; procedure TImagingCanvas.FillRectBlend(const Rect: TRect; SrcFactor, DestFactor: TBlendingFactor); var DstRect: TRect; X, Y: Integer; Line: PByte; begin if (FFillMode <> fmClear) and IntersectRect(DstRect, Rect, FClipRect) then begin CheckBeforeBlending(SrcFactor, DestFactor, Self); for Y := DstRect.Top to DstRect.Bottom - 1 do begin Line := @PByteArray(FPData.Bits)[(Y * FPData.Width + DstRect.Left) * FFormatInfo.BytesPerPixel]; for X := DstRect.Left to DstRect.Right - 1 do begin PixelBlendProc(FFillColorFP, Line, @FFormatInfo, SrcFactor, DestFactor); Inc(Line, FFormatInfo.BytesPerPixel); end; end; end; end; procedure TImagingCanvas.Rectangle(const Rect: TRect); begin FillRect(Rect); FrameRect(Rect); end; procedure TImagingCanvas.Ellipse(const Rect: TRect); var RadX, RadY, DeltaX, DeltaY, R, RX, RY: LongInt; X1, X2, Y1, Y2, Bpp, OldY: LongInt; Fill, Pen: TColorFPRec; begin // TODO: Use PenWidth X1 := Rect.Left; X2 := Rect.Right; Y1 := Rect.Top; Y2 := Rect.Bottom; TranslateFPToNative(FPenColorFP, @Pen); TranslateFPToNative(FFillColorFP, @Fill); Bpp := FFormatInfo.BytesPerPixel; SwapMin(X1, X2); SwapMin(Y1, Y2); RadX := (X2 - X1) div 2; RadY := (Y2 - Y1) div 2; Y1 := Y1 + RadY; Y2 := Y1; OldY := Y1; DeltaX := (RadX * RadX); DeltaY := (RadY * RadY); R := RadX * RadY * RadY; RX := R; RY := 0; if (FFillMode <> fmClear) then HorzLineInternal(X1, X2, Y1, @Fill, Bpp); CopyPixelInternal(X1, Y1, @Pen, Bpp); CopyPixelInternal(X2, Y1, @Pen, Bpp); while RadX > 0 do begin if R > 0 then begin Inc(Y1); Dec(Y2); Inc(RY, DeltaX); Dec(R, RY); end; if R <= 0 then begin Dec(RadX); Inc(X1); Dec(X2); Dec(RX, DeltaY); Inc(R, RX); end; if (OldY <> Y1) and (FFillMode <> fmClear) then begin HorzLineInternal(X1, X2, Y1, @Fill, Bpp); HorzLineInternal(X1, X2, Y2, @Fill, Bpp); end; OldY := Y1; CopyPixelInternal(X1, Y1, @Pen, Bpp); CopyPixelInternal(X2, Y1, @Pen, Bpp); CopyPixelInternal(X1, Y2, @Pen, Bpp); CopyPixelInternal(X2, Y2, @Pen, Bpp); end; end; procedure TImagingCanvas.FloodFill(X, Y: Integer; BoundaryFillMode: Boolean); var Stack: array of TPoint; StackPos, Y1: Integer; OldColor: TColor32; SpanLeft, SpanRight: Boolean; procedure Push(AX, AY: Integer); begin if StackPos < High(Stack) then begin Inc(StackPos); Stack[StackPos].X := AX; Stack[StackPos].Y := AY; end else begin SetLength(Stack, Length(Stack) + FPData.Width); Push(AX, AY); end; end; function Pop(out AX, AY: Integer): Boolean; begin if StackPos > 0 then begin AX := Stack[StackPos].X; AY := Stack[StackPos].Y; Dec(StackPos); Result := True; end else Result := False; end; function Compare(AX, AY: Integer): Boolean; var Color: TColor32; begin Color := GetPixel32(AX, AY); if BoundaryFillMode then Result := (Color <> FFillColor32) and (Color <> FPenColor32) else Result := Color = OldColor; end; begin // Scanline Floodfill Algorithm With Stack // http://student.kuleuven.be/~m0216922/CG/floodfill.html if not PtInRect(FClipRect, Point(X, Y)) then Exit; SetLength(Stack, FPData.Width * 4); StackPos := 0; OldColor := GetPixel32(X, Y); Push(X, Y); while Pop(X, Y) do begin Y1 := Y; while (Y1 >= FClipRect.Top) and Compare(X, Y1) do Dec(Y1); Inc(Y1); SpanLeft := False; SpanRight := False; while (Y1 < FClipRect.Bottom) and Compare(X, Y1) do begin SetPixel32(X, Y1, FFillColor32); if not SpanLeft and (X > FClipRect.Left) and Compare(X - 1, Y1) then begin Push(X - 1, Y1); SpanLeft := True; end else if SpanLeft and (X > FClipRect.Left) and not Compare(X - 1, Y1) then SpanLeft := False else if not SpanRight and (X < FClipRect.Right - 1) and Compare(X + 1, Y1)then begin Push(X + 1, Y1); SpanRight := True; end else if SpanRight and (X < FClipRect.Right - 1) and not Compare(X + 1, Y1) then SpanRight := False; Inc(Y1); end; end; end; procedure TImagingCanvas.DrawInternal(const SrcRect: TRect; DestCanvas: TImagingCanvas; DestX, DestY: Integer; SrcFactor, DestFactor: TBlendingFactor; PixelWriteProc: TPixelWriteProc); var X, Y, SrcX, SrcY, Width, Height, SrcBpp, DestBpp: Integer; PSrc: TColorFPRec; SrcPointer, DestPointer: PByte; begin CheckBeforeBlending(SrcFactor, DestFactor, DestCanvas); SrcX := SrcRect.Left; SrcY := SrcRect.Top; Width := SrcRect.Right - SrcRect.Left; Height := SrcRect.Bottom - SrcRect.Top; SrcBpp := FFormatInfo.BytesPerPixel; DestBpp := DestCanvas.FFormatInfo.BytesPerPixel; // Clip src and dst rects ClipCopyBounds(SrcX, SrcY, Width, Height, DestX, DestY, FPData.Width, FPData.Height, DestCanvas.ClipRect); for Y := 0 to Height - 1 do begin // Get src and dst scanlines SrcPointer := @PByteArray(FPData.Bits)[((SrcY + Y) * FPData.Width + SrcX) * SrcBpp]; DestPointer := @PByteArray(DestCanvas.FPData.Bits)[((DestY + Y) * DestCanvas.FPData.Width + DestX) * DestBpp]; for X := 0 to Width - 1 do begin PSrc := FFormatInfo.GetPixelFP(SrcPointer, @FFormatInfo, FPData.Palette); // Call pixel writer procedure - combine source and dest pixels PixelWriteProc(PSrc, DestPointer, @DestCanvas.FFormatInfo, SrcFactor, DestFactor); // Increment pixel pointers Inc(SrcPointer, SrcBpp); Inc(DestPointer, DestBpp); end; end; end; procedure TImagingCanvas.DrawBlend(const SrcRect: TRect; DestCanvas: TImagingCanvas; DestX, DestY: Integer; SrcFactor, DestFactor: TBlendingFactor); begin DrawInternal(SrcRect, DestCanvas, DestX, DestY, SrcFactor, DestFactor, PixelBlendProc); end; procedure TImagingCanvas.DrawAlpha(const SrcRect: TRect; DestCanvas: TImagingCanvas; DestX, DestY: Integer); begin DrawInternal(SrcRect, DestCanvas, DestX, DestY, bfIgnore, bfIgnore, PixelAlphaProc); end; procedure TImagingCanvas.DrawAdd(const SrcRect: TRect; DestCanvas: TImagingCanvas; DestX, DestY: Integer); begin DrawInternal(SrcRect, DestCanvas, DestX, DestY, bfIgnore, bfIgnore, PixelAddProc); end; procedure TImagingCanvas.StretchDrawInternal(const SrcRect: TRect; DestCanvas: TImagingCanvas; const DestRect: TRect; SrcFactor, DestFactor: TBlendingFactor; Filter: TResizeFilter; PixelWriteProc: TPixelWriteProc); const FilterMapping: array[TResizeFilter] of TSamplingFilter = (sfNearest, sfLinear, DefaultCubicFilter, sfLanczos); var X, Y, I, J, SrcX, SrcY, SrcWidth, SrcHeight: Integer; DestX, DestY, DestWidth, DestHeight, SrcBpp, DestBpp: Integer; SrcPix: TColorFPRec; MapX, MapY: TMappingTable; XMinimum, XMaximum: Integer; LineBuffer: array of TColorFPRec; ClusterX, ClusterY: TCluster; Weight, AccumA, AccumR, AccumG, AccumB: Single; DestLine: PByte; FilterFunction: TFilterFunction; Radius: Single; begin CheckBeforeBlending(SrcFactor, DestFactor, DestCanvas); SrcX := SrcRect.Left; SrcY := SrcRect.Top; SrcWidth := SrcRect.Right - SrcRect.Left; SrcHeight := SrcRect.Bottom - SrcRect.Top; DestX := DestRect.Left; DestY := DestRect.Top; DestWidth := DestRect.Right - DestRect.Left; DestHeight := DestRect.Bottom - DestRect.Top; SrcBpp := FFormatInfo.BytesPerPixel; DestBpp := DestCanvas.FFormatInfo.BytesPerPixel; // Get actual resampling filter and radius FilterFunction := SamplingFilterFunctions[FilterMapping[Filter]]; Radius := SamplingFilterRadii[FilterMapping[Filter]]; // Clip src and dst rects ClipStretchBounds(SrcX, SrcY, SrcWidth, SrcHeight, DestX, DestY, DestWidth, DestHeight, FPData.Width, FPData.Height, DestCanvas.ClipRect); // Generate mapping tables MapX := BuildMappingTable(DestX, DestX + DestWidth, SrcX, SrcX + SrcWidth, FPData.Width, FilterFunction, Radius, False); MapY := BuildMappingTable(DestY, DestY + DestHeight, SrcY, SrcY + SrcHeight, FPData.Height, FilterFunction, Radius, False); FindExtremes(MapX, XMinimum, XMaximum); SetLength(LineBuffer, XMaximum - XMinimum + 1); for J := 0 to DestHeight - 1 do begin ClusterY := MapY[J]; for X := XMinimum to XMaximum do begin AccumA := 0.0; AccumR := 0.0; AccumG := 0.0; AccumB := 0.0; for Y := 0 to Length(ClusterY) - 1 do begin Weight := ClusterY[Y].Weight; SrcPix := FFormatInfo.GetPixelFP(@PByteArray(FPData.Bits)[(ClusterY[Y].Pos * FPData.Width + X) * SrcBpp], @FFormatInfo, FPData.Palette); AccumB := AccumB + SrcPix.B * Weight; AccumG := AccumG + SrcPix.G * Weight; AccumR := AccumR + SrcPix.R * Weight; AccumA := AccumA + SrcPix.A * Weight; end; with LineBuffer[X - XMinimum] do begin A := AccumA; R := AccumR; G := AccumG; B := AccumB; end; end; DestLine := @PByteArray(DestCanvas.FPData.Bits)[((J + DestY) * DestCanvas.FPData.Width + DestX) * DestBpp]; for I := 0 to DestWidth - 1 do begin ClusterX := MapX[I]; AccumA := 0.0; AccumR := 0.0; AccumG := 0.0; AccumB := 0.0; for X := 0 to Length(ClusterX) - 1 do begin Weight := ClusterX[X].Weight; with LineBuffer[ClusterX[X].Pos - XMinimum] do begin AccumB := AccumB + B * Weight; AccumG := AccumG + G * Weight; AccumR := AccumR + R * Weight; AccumA := AccumA + A * Weight; end; end; SrcPix.A := AccumA; SrcPix.R := AccumR; SrcPix.G := AccumG; SrcPix.B := AccumB; // Write resulting blended pixel PixelWriteProc(SrcPix, DestLine, @DestCanvas.FFormatInfo, SrcFactor, DestFactor); Inc(DestLine, DestBpp); end; end; end; procedure TImagingCanvas.StretchDrawBlend(const SrcRect: TRect; DestCanvas: TImagingCanvas; const DestRect: TRect; SrcFactor, DestFactor: TBlendingFactor; Filter: TResizeFilter); begin StretchDrawInternal(SrcRect, DestCanvas, DestRect, SrcFactor, DestFactor, Filter, PixelBlendProc); end; procedure TImagingCanvas.StretchDrawAlpha(const SrcRect: TRect; DestCanvas: TImagingCanvas; const DestRect: TRect; Filter: TResizeFilter); begin StretchDrawInternal(SrcRect, DestCanvas, DestRect, bfIgnore, bfIgnore, Filter, PixelAlphaProc); end; procedure TImagingCanvas.StretchDrawAdd(const SrcRect: TRect; DestCanvas: TImagingCanvas; const DestRect: TRect; Filter: TResizeFilter); begin StretchDrawInternal(SrcRect, DestCanvas, DestRect, bfIgnore, bfIgnore, Filter, PixelAddProc); end; procedure TImagingCanvas.ApplyConvolution(Kernel: PLongInt; KernelSize, Divisor: LongInt; Bias: Single; ClampChannels: Boolean); var X, Y, I, J, PosY, PosX, SizeDiv2, KernelValue, WidthBytes, Bpp: LongInt; R, G, B, DivFloat: Single; Pixel: TColorFPRec; TempImage: TImageData; DstPointer, SrcPointer: PByte; begin SizeDiv2 := KernelSize div 2; DivFloat := IffFloat(Divisor > 1, 1.0 / Divisor, 1.0); Bpp := FFormatInfo.BytesPerPixel; WidthBytes := FPData.Width * Bpp; InitImage(TempImage); CloneImage(FPData^, TempImage); try // For every pixel in clip rect for Y := FClipRect.Top to FClipRect.Bottom - 1 do begin DstPointer := @PByteArray(FPData.Bits)[Y * WidthBytes + FClipRect.Left * Bpp]; for X := FClipRect.Left to FClipRect.Right - 1 do begin // Reset accumulators R := 0.0; G := 0.0; B := 0.0; for J := 0 to KernelSize - 1 do begin PosY := ClampInt(Y + J - SizeDiv2, FClipRect.Top, FClipRect.Bottom - 1); for I := 0 to KernelSize - 1 do begin PosX := ClampInt(X + I - SizeDiv2, FClipRect.Left, FClipRect.Right - 1); SrcPointer := @PByteArray(TempImage.Bits)[PosY * WidthBytes + PosX * Bpp]; // Get pixels from neighbourhood of current pixel and add their // colors to accumulators weighted by filter kernel values Pixel := FFormatInfo.GetPixelFP(SrcPointer, @FFormatInfo, TempImage.Palette); KernelValue := PLongIntArray(Kernel)[J * KernelSize + I]; R := R + Pixel.R * KernelValue; G := G + Pixel.G * KernelValue; B := B + Pixel.B * KernelValue; end; end; Pixel := FFormatInfo.GetPixelFP(DstPointer, @FFormatInfo, FPData.Palette); Pixel.R := R * DivFloat + Bias; Pixel.G := G * DivFloat + Bias; Pixel.B := B * DivFloat + Bias; if ClampChannels then ClampFloatPixel(Pixel); // Set resulting pixel color FFormatInfo.SetPixelFP(DstPointer, @FFormatInfo, FPData.Palette, Pixel); Inc(DstPointer, Bpp); end; end; finally FreeImage(TempImage); end; end; procedure TImagingCanvas.ApplyConvolution3x3(const Filter: TConvolutionFilter3x3); begin ApplyConvolution(@Filter.Kernel, 3, Filter.Divisor, Filter.Bias, True); end; procedure TImagingCanvas.ApplyConvolution5x5(const Filter: TConvolutionFilter5x5); begin ApplyConvolution(@Filter.Kernel, 5, Filter.Divisor, Filter.Bias, True); end; procedure TImagingCanvas.ApplyNonLinearFilter(FilterSize: Integer; SelectFunc: TSelectPixelFunction); var X, Y, I, J, PosY, PosX, SizeDiv2, WidthBytes, Bpp: LongInt; Pixel: TColorFPRec; TempImage: TImageData; DstPointer, SrcPointer: PByte; NeighPixels: TDynFPPixelArray; begin SizeDiv2 := FilterSize div 2; Bpp := FFormatInfo.BytesPerPixel; WidthBytes := FPData.Width * Bpp; SetLength(NeighPixels, FilterSize * FilterSize); InitImage(TempImage); CloneImage(FPData^, TempImage); try // For every pixel in clip rect for Y := FClipRect.Top to FClipRect.Bottom - 1 do begin DstPointer := @PByteArray(FPData.Bits)[Y * WidthBytes + FClipRect.Left * Bpp]; for X := FClipRect.Left to FClipRect.Right - 1 do begin for J := 0 to FilterSize - 1 do begin PosY := ClampInt(Y + J - SizeDiv2, FClipRect.Top, FClipRect.Bottom - 1); for I := 0 to FilterSize - 1 do begin PosX := ClampInt(X + I - SizeDiv2, FClipRect.Left, FClipRect.Right - 1); SrcPointer := @PByteArray(TempImage.Bits)[PosY * WidthBytes + PosX * Bpp]; // Get pixels from neighbourhood of current pixel and store them Pixel := FFormatInfo.GetPixelFP(SrcPointer, @FFormatInfo, TempImage.Palette); NeighPixels[J * FilterSize + I] := Pixel; end; end; // Choose pixel using custom function Pixel := SelectFunc(NeighPixels); // Set resulting pixel color FFormatInfo.SetPixelFP(DstPointer, @FFormatInfo, FPData.Palette, Pixel); Inc(DstPointer, Bpp); end; end; finally FreeImage(TempImage); end; end; procedure TImagingCanvas.ApplyMedianFilter(FilterSize: Integer); begin ApplyNonLinearFilter(FilterSize, MedianSelect); end; procedure TImagingCanvas.ApplyMinFilter(FilterSize: Integer); begin ApplyNonLinearFilter(FilterSize, MinSelect); end; procedure TImagingCanvas.ApplyMaxFilter(FilterSize: Integer); begin ApplyNonLinearFilter(FilterSize, MaxSelect); end; procedure TImagingCanvas.PointTransform(Transform: TPointTransformFunction; Param1, Param2, Param3: Single); var X, Y, Bpp, WidthBytes: Integer; PixPointer: PByte; Pixel: TColorFPRec; begin Bpp := FFormatInfo.BytesPerPixel; WidthBytes := FPData.Width * Bpp; // For every pixel in clip rect for Y := FClipRect.Top to FClipRect.Bottom - 1 do begin PixPointer := @PByteArray(FPData.Bits)[Y * WidthBytes + FClipRect.Left * Bpp]; for X := FClipRect.Left to FClipRect.Right - 1 do begin Pixel := FFormatInfo.GetPixelFP(PixPointer, @FFormatInfo, FPData.Palette); FFormatInfo.SetPixelFP(PixPointer, @FFormatInfo, FPData.Palette, Transform(Pixel, Param1, Param2, Param3)); Inc(PixPointer, Bpp); end; end; end; procedure TImagingCanvas.ModifyContrastBrightness(Contrast, Brightness: Single); begin PointTransform(TransformContrastBrightness, 1.0 + Contrast / 100, Brightness / 100, 0); end; procedure TImagingCanvas.GammaCorection(Red, Green, Blue: Single); begin PointTransform(TransformGamma, Red, Green, Blue); end; procedure TImagingCanvas.InvertColors; begin PointTransform(TransformInvert, 0, 0, 0); end; procedure TImagingCanvas.Threshold(Red, Green, Blue: Single); begin PointTransform(TransformThreshold, Red, Green, Blue); end; procedure TImagingCanvas.AdjustColorLevels(BlackPoint, WhitePoint, MidPoint: Single); begin PointTransform(TransformLevels, BlackPoint, WhitePoint, 1.0 / MidPoint); end; procedure TImagingCanvas.PremultiplyAlpha; begin PointTransform(TransformPremultiplyAlpha, 0, 0, 0); end; procedure TImagingCanvas.UnPremultiplyAlpha; begin PointTransform(TransformUnPremultiplyAlpha, 0, 0, 0); end; procedure TImagingCanvas.GetHistogram(out Red, Green, Blue, Alpha, Gray: THistogramArray); var X, Y, Bpp: Integer; PixPointer: PByte; Color32: TColor32Rec; begin FillChar(Red, SizeOf(Red), 0); FillChar(Green, SizeOf(Green), 0); FillChar(Blue, SizeOf(Blue), 0); FillChar(Alpha, SizeOf(Alpha), 0); FillChar(Gray, SizeOf(Gray), 0); Bpp := FFormatInfo.BytesPerPixel; for Y := FClipRect.Top to FClipRect.Bottom - 1 do begin PixPointer := @PByteArray(FPData.Bits)[Y * FPData.Width * Bpp + FClipRect.Left * Bpp]; for X := FClipRect.Left to FClipRect.Right - 1 do begin Color32 := FFormatInfo.GetPixel32(PixPointer, @FFormatInfo, FPData.Palette); Inc(Red[Color32.R]); Inc(Green[Color32.G]); Inc(Blue[Color32.B]); Inc(Alpha[Color32.A]); Inc(Gray[Round(GrayConv.R * Color32.R + GrayConv.G * Color32.G + GrayConv.B * Color32.B)]); Inc(PixPointer, Bpp); end; end; end; procedure TImagingCanvas.FillChannel(ChannelId: Integer; NewChannelValue: Byte); var X, Y, Bpp: Integer; PixPointer: PByte; Color32: TColor32Rec; begin Bpp := FFormatInfo.BytesPerPixel; for Y := FClipRect.Top to FClipRect.Bottom - 1 do begin PixPointer := @PByteArray(FPData.Bits)[Y * FPData.Width * Bpp + FClipRect.Left * Bpp]; for X := FClipRect.Left to FClipRect.Right - 1 do begin Color32 := FFormatInfo.GetPixel32(PixPointer, @FFormatInfo, FPData.Palette); Color32.Channels[ChannelId] := NewChannelValue; FFormatInfo.SetPixel32(PixPointer, @FFormatInfo, FPData.Palette, Color32); Inc(PixPointer, Bpp); end; end; end; procedure TImagingCanvas.FillChannelFP(ChannelId: Integer; NewChannelValue: Single); var X, Y, Bpp: Integer; PixPointer: PByte; ColorFP: TColorFPRec; begin Bpp := FFormatInfo.BytesPerPixel; for Y := FClipRect.Top to FClipRect.Bottom - 1 do begin PixPointer := @PByteArray(FPData.Bits)[Y * FPData.Width * Bpp + FClipRect.Left * Bpp]; for X := FClipRect.Left to FClipRect.Right - 1 do begin ColorFP := FFormatInfo.GetPixelFP(PixPointer, @FFormatInfo, FPData.Palette); ColorFP.Channels[ChannelId] := NewChannelValue; FFormatInfo.SetPixelFP(PixPointer, @FFormatInfo, FPData.Palette, ColorFP); Inc(PixPointer, Bpp); end; end; end; class function TImagingCanvas.GetSupportedFormats: TImageFormats; begin Result := [ifIndex8..Pred(ifDXT1)]; end; { TFastARGB32Canvas } destructor TFastARGB32Canvas.Destroy; begin FreeMem(FScanlines); inherited Destroy; end; procedure TFastARGB32Canvas.AlphaBlendPixels(SrcPix, DestPix: PColor32Rec); var SrcAlpha, DestAlpha, FinalAlpha: Integer; begin FinalAlpha := SrcPix.A + 1 + (DestPix.A * (256 - SrcPix.A)) shr 8; if FinalAlpha = 0 then SrcAlpha := 0 else SrcAlpha := (SrcPix.A shl 8) div FinalAlpha; DestAlpha := 256 - SrcAlpha; DestPix.A := ClampToByte(FinalAlpha); DestPix.R := (SrcPix.R * SrcAlpha + DestPix.R * DestAlpha) shr 8; DestPix.G := (SrcPix.G * SrcAlpha + DestPix.G * DestAlpha) shr 8; DestPix.B := (SrcPix.B * SrcAlpha + DestPix.B * DestAlpha) shr 8; end; procedure TFastARGB32Canvas.DrawAlpha(const SrcRect: TRect; DestCanvas: TImagingCanvas; DestX, DestY: Integer); var X, Y, SrcX, SrcY, Width, Height: Integer; SrcPix, DestPix: PColor32Rec; begin if DestCanvas.ClassType <> Self.ClassType then begin inherited; Exit; end; SrcX := SrcRect.Left; SrcY := SrcRect.Top; Width := SrcRect.Right - SrcRect.Left; Height := SrcRect.Bottom - SrcRect.Top; ClipCopyBounds(SrcX, SrcY, Width, Height, DestX, DestY, FPData.Width, FPData.Height, DestCanvas.ClipRect); for Y := 0 to Height - 1 do begin SrcPix := @FScanlines[SrcY + Y, SrcX]; DestPix := @TFastARGB32Canvas(DestCanvas).FScanlines[DestY + Y, DestX]; for X := 0 to Width - 1 do begin AlphaBlendPixels(SrcPix, DestPix); Inc(SrcPix); Inc(DestPix); end; end; end; function TFastARGB32Canvas.GetPixel32(X, Y: LongInt): TColor32; begin Result := FScanlines[Y, X].Color; end; procedure TFastARGB32Canvas.SetPixel32(X, Y: LongInt; const Value: TColor32); begin if (X >= FClipRect.Left) and (Y >= FClipRect.Top) and (X < FClipRect.Right) and (Y < FClipRect.Bottom) then begin FScanlines[Y, X].Color := Value; end; end; procedure TFastARGB32Canvas.StretchDrawAlpha(const SrcRect: TRect; DestCanvas: TImagingCanvas; const DestRect: TRect; Filter: TResizeFilter); var X, Y, ScaleX, ScaleY, Yp, Xp, Weight1, Weight2, Weight3, Weight4, InvFracY, T1, T2: Integer; FracX, FracY: Cardinal; SrcX, SrcY, SrcWidth, SrcHeight: Integer; DestX, DestY, DestWidth, DestHeight: Integer; SrcLine, SrcLine2: PColor32RecArray; DestPix: PColor32Rec; Accum: TColor32Rec; begin if (Filter = rfBicubic) or (DestCanvas.ClassType <> Self.ClassType) then begin inherited; Exit; end; SrcX := SrcRect.Left; SrcY := SrcRect.Top; SrcWidth := SrcRect.Right - SrcRect.Left; SrcHeight := SrcRect.Bottom - SrcRect.Top; DestX := DestRect.Left; DestY := DestRect.Top; DestWidth := DestRect.Right - DestRect.Left; DestHeight := DestRect.Bottom - DestRect.Top; // Clip src and dst rects ClipStretchBounds(SrcX, SrcY, SrcWidth, SrcHeight, DestX, DestY, DestWidth, DestHeight, FPData.Width, FPData.Height, DestCanvas.ClipRect); ScaleX := (SrcWidth shl 16) div DestWidth; ScaleY := (SrcHeight shl 16) div DestHeight; // Nearest and linear filtering using fixed point math if Filter = rfNearest then begin Yp := 0; for Y := DestY to DestY + DestHeight - 1 do begin Xp := 0; SrcLine := @FScanlines[SrcY + Yp shr 16, SrcX]; DestPix := @TFastARGB32Canvas(DestCanvas).FScanlines[Y, DestX]; for X := 0 to DestWidth - 1 do begin AlphaBlendPixels(@SrcLine[Xp shr 16], DestPix); Inc(DestPix); Inc(Xp, ScaleX); end; Inc(Yp, ScaleY); end; end else begin Yp := (ScaleY shr 1) - $8000; for Y := DestY to DestY + DestHeight - 1 do begin DestPix := @TFastARGB32Canvas(DestCanvas).FScanlines[Y, DestX]; if Yp < 0 then begin T1 := 0; FracY := 0; InvFracY := $10000; end else begin T1 := Yp shr 16; FracY := Yp and $FFFF; InvFracY := (not Yp and $FFFF) + 1; end; T2 := Iff(T1 < SrcHeight - 1, T1 + 1, T1); SrcLine := @Scanlines[T1 + SrcY, SrcX]; SrcLine2 := @Scanlines[T2 + SrcY, SrcX]; Xp := (ScaleX shr 1) - $8000; for X := 0 to DestWidth - 1 do begin if Xp < 0 then begin T1 := 0; FracX := 0; end else begin T1 := Xp shr 16; FracX := Xp and $FFFF; end; T2 := Iff(T1 < SrcWidth - 1, T1 + 1, T1); Weight2:= Integer((Cardinal(InvFracY) * FracX) shr 16); // cast to Card, Int can overflow here Weight1:= InvFracY - Weight2; Weight4:= Integer((Cardinal(FracY) * FracX) shr 16); Weight3:= FracY - Weight4; Accum.B := (SrcLine[T1].B * Weight1 + SrcLine[T2].B * Weight2 + SrcLine2[T1].B * Weight3 + SrcLine2[T2].B * Weight4 + $8000) shr 16; Accum.G := (SrcLine[T1].G * Weight1 + SrcLine[T2].G * Weight2 + SrcLine2[T1].G * Weight3 + SrcLine2[T2].G * Weight4 + $8000) shr 16; Accum.R := (SrcLine[T1].R * Weight1 + SrcLine[T2].R * Weight2 + SrcLine2[T1].R * Weight3 + SrcLine2[T2].R * Weight4 + $8000) shr 16; Accum.A := (SrcLine[T1].A * Weight1 + SrcLine[T2].A * Weight2 + SrcLine2[T1].A * Weight3 + SrcLine2[T2].A * Weight4 + $8000) shr 16; AlphaBlendPixels(@Accum, DestPix); Inc(Xp, ScaleX); Inc(DestPix); end; Inc(Yp, ScaleY); end; end; end; procedure TFastARGB32Canvas.UpdateCanvasState; var I: LongInt; ScanPos: PLongWord; begin inherited UpdateCanvasState; // Realloc and update scanline array ReallocMem(FScanlines, FPData.Height * SizeOf(PColor32RecArray)); ScanPos := FPData.Bits; for I := 0 to FPData.Height - 1 do begin FScanlines[I] := PColor32RecArray(ScanPos); Inc(ScanPos, FPData.Width); end; end; class function TFastARGB32Canvas.GetSupportedFormats: TImageFormats; begin Result := [ifA8R8G8B8]; end; procedure TFastARGB32Canvas.InvertColors; var X, Y: Integer; PixPtr: PColor32Rec; begin for Y := FClipRect.Top to FClipRect.Bottom - 1 do begin PixPtr := @FScanlines[Y, FClipRect.Left]; for X := FClipRect.Left to FClipRect.Right - 1 do begin PixPtr.R := not PixPtr.R; PixPtr.G := not PixPtr.G; PixPtr.B := not PixPtr.B; Inc(PixPtr); end; end; end; initialization RegisterCanvas(TFastARGB32Canvas); finalization FreeAndNil(CanvasClasses); { File Notes: -- TODOS ---------------------------------------------------- - more more more ... - implement pen width everywhere - more objects (arc, polygon) -- 0.26.5 Changes/Bug Fixes --------------------------------- - Fixed bug that could raise floating point error in DrawAlpha and StretchDrawAlpha. - Fixed bug in TImagingCanvas.Line that caused not drawing of horz or vert lines. -- 0.26.3 Changes/Bug Fixes --------------------------------- - Added some methods to TFastARGB32Canvas (InvertColors, DrawAlpha/StretchDrawAlpha) - Fixed DrawAlpha/StretchDrawAlpha destination alpha calculation. - Added PremultiplyAlpha and UnPremultiplyAlpha methods. -- 0.26.1 Changes/Bug Fixes --------------------------------- - Added FillChannel methods. - Added FloodFill method. - Added GetHistogram method. - Fixed "Invalid FP operation" in AdjustColorLevels in FPC compiled exes (thanks to Carlos Gonzlez). - Added TImagingCanvas.AdjustColorLevels method. -- 0.25.0 Changes/Bug Fixes --------------------------------- - Fixed error that could cause AV in linear and nonlinear filters. - Added blended rect filling function FillRectBlend. - Added drawing function with blending (DrawAlpha, StretchDrawAlpha, StretchDrawAdd, DrawBlend, StretchDrawBlend, ...) - Added non-linear filters (min, max, median). - Added point transforms (invert, contrast, gamma, brightness). -- 0.21 Changes/Bug Fixes ----------------------------------- - Added some new filter kernels for convolution. - Added FillMode and PenMode properties. - Added FrameRect, Rectangle, Ellipse, and Line methods. - Removed HorzLine and VertLine from TFastARGB32Canvas - new versions in general canvas is now as fast as those in TFastARGB32Canvas (only in case of A8R8G8B8 images of course). - Added PenWidth property, updated HorzLine and VertLine to use it. -- 0.19 Changes/Bug Fixes ----------------------------------- - added TFastARGB32Canvas - added convolutions, hline, vline - unit created, intial stuff added } end. ================================================ FILE: lib/Imaging/ImagingClasses.pas ================================================ { Vampyre Imaging Library by Marek Mauder http://imaginglib.sourceforge.net The contents of this file are used with permission, subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/MPL-1.1.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Alternatively, the contents of this file may be used under the terms of the GNU Lesser General Public License (the "LGPL License"), in which case the provisions of the LGPL License are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of the LGPL License and not to allow others to use your version of this file under the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the LGPL License. If you do not delete the provisions above, a recipient may use your version of this file under either the MPL or the LGPL License. For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html } { This unit contains class based wrapper to Imaging library.} unit ImagingClasses; {$I ImagingOptions.inc} interface uses Types, Classes, ImagingTypes, Imaging, ImagingFormats, ImagingUtility; type { Base abstract high level class wrapper to low level Imaging structures and functions.} TBaseImage = class(TPersistent) private function GetEmpty: Boolean; protected FPData: PImageData; FOnDataSizeChanged: TNotifyEvent; FOnPixelsChanged: TNotifyEvent; function GetFormat: TImageFormat; {$IFDEF USE_INLINE}inline;{$ENDIF} function GetHeight: Integer; {$IFDEF USE_INLINE}inline;{$ENDIF} function GetSize: Integer; {$IFDEF USE_INLINE}inline;{$ENDIF} function GetWidth: Integer; {$IFDEF USE_INLINE}inline;{$ENDIF} function GetBits: Pointer; {$IFDEF USE_INLINE}inline;{$ENDIF} function GetPalette: PPalette32; {$IFDEF USE_INLINE}inline;{$ENDIF} function GetPaletteEntries: Integer; {$IFDEF USE_INLINE}inline;{$ENDIF} function GetScanline(Index: Integer): Pointer; function GetPixelPointer(X, Y: Integer): Pointer; {$IFDEF USE_INLINE}inline;{$ENDIF} function GetScanlineSize: Integer; {$IFDEF USE_INLINE}inline;{$ENDIF} function GetFormatInfo: TImageFormatInfo; {$IFDEF USE_INLINE}inline;{$ENDIF} function GetValid: Boolean; {$IFDEF USE_INLINE}inline;{$ENDIF} function GetBoundsRect: TRect; procedure SetFormat(const Value: TImageFormat); {$IFDEF USE_INLINE}inline;{$ENDIF} procedure SetHeight(const Value: Integer); {$IFDEF USE_INLINE}inline;{$ENDIF} procedure SetWidth(const Value: Integer); {$IFDEF USE_INLINE}inline;{$ENDIF} procedure SetPointer; virtual; abstract; procedure DoDataSizeChanged; virtual; procedure DoPixelsChanged; virtual; public constructor Create; virtual; constructor CreateFromImage(AImage: TBaseImage); destructor Destroy; override; { Returns info about current image.} function ToString: string; {$IF Defined(DCC) and (CompilerVersion >= 20.0)}override;{$IFEND} { Creates a new image data with the given size and format. Old image data is lost. Works only for the current image of TMultiImage.} procedure RecreateImageData(AWidth, AHeight: Integer; AFormat: TImageFormat); { Maps underlying image data to given TImageData record. Both TBaseImage and TImageData now share some image memory (bits). So don't call FreeImage on TImageData afterwards since this TBaseImage would get really broken.} procedure MapImageData(const ImageData: TImageData); { Deletes current image.} procedure Clear; { Resizes current image with optional resampling.} procedure Resize(NewWidth, NewHeight: Integer; Filter: TResizeFilter); procedure ResizeToFit(FitWidth, FitHeight: Integer; Filter: TResizeFilter; DstImage: TBaseImage); { Flips current image. Reverses the image along its horizontal axis the top becomes the bottom and vice versa.} procedure Flip; { Mirrors current image. Reverses the image along its vertical axis the left side becomes the right and vice versa.} procedure Mirror; { Rotates image by Angle degrees counterclockwise.} procedure Rotate(Angle: Single); { Copies rectangular part of SrcImage to DstImage. No blending is performed - alpha is simply copied to destination image. Operates also with negative X and Y coordinates. Note that copying is fastest for images in the same data format (and slowest for images in special formats).} procedure CopyTo(SrcX, SrcY, Width, Height: Integer; DstImage: TBaseImage; DstX, DstY: Integer); { Stretches the contents of the source rectangle to the destination rectangle with optional resampling. No blending is performed - alpha is simply copied/resampled to destination image. Note that stretching is fastest for images in the same data format (and slowest for images in special formats).} procedure StretchTo(SrcX, SrcY, SrcWidth, SrcHeight: Integer; DstImage: TBaseImage; DstX, DstY, DstWidth, DstHeight: Integer; Filter: TResizeFilter); { Replaces pixels with OldPixel in the given rectangle by NewPixel. OldPixel and NewPixel should point to the pixels in the same format as the given image is in.} procedure ReplaceColor(X, Y, Width, Height: Integer; OldColor, NewColor: Pointer); { Swaps SrcChannel and DstChannel color or alpha channels of image. Use ChannelRed, ChannelBlue, ChannelGreen, ChannelAlpha constants to identify channels.} procedure SwapChannels(SrcChannel, DstChannel: Integer); { Loads current image data from file.} procedure LoadFromFile(const FileName: string); virtual; { Loads current image data from stream.} procedure LoadFromStream(Stream: TStream); virtual; { Saves current image data to file.} procedure SaveToFile(const FileName: string); { Saves current image data to stream. Ext identifies desired image file format (jpg, png, dds, ...)} procedure SaveToStream(const Ext: string; Stream: TStream); { Width of current image in pixels.} property Width: Integer read GetWidth write SetWidth; { Height of current image in pixels.} property Height: Integer read GetHeight write SetHeight; { Image data format of current image.} property Format: TImageFormat read GetFormat write SetFormat; { Size in bytes of current image's data.} property Size: Integer read GetSize; { Pointer to memory containing image bits.} property Bits: Pointer read GetBits; { Pointer to palette for indexed format images. It is nil for others. Max palette entry is at index [PaletteEntries - 1].} property Palette: PPalette32 read GetPalette; { Number of entries in image's palette} property PaletteEntries: Integer read GetPaletteEntries; { Provides indexed access to each line of pixels. Does not work with special format images (like DXT).} property Scanline[Index: Integer]: Pointer read GetScanline; { Returns pointer to image pixel at [X, Y] coordinates.} property PixelPointer[X, Y: Integer]: Pointer read GetPixelPointer; { Size/length of one image scanline in bytes.} property ScanlineSize: Integer read GetScanlineSize; { Extended image format information.} property FormatInfo: TImageFormatInfo read GetFormatInfo; { This gives complete access to underlying TImageData record. It can be used in functions that take TImageData as parameter (for example: ReduceColors(SingleImageInstance.ImageData^, 64)).} property ImageDataPointer: PImageData read FPData; { Indicates whether the current image is valid (proper format, allowed dimensions, right size, ...).} property Valid: Boolean read GetValid; { Indicates whether image containst any data (size in bytes > 0).} property Empty: Boolean read GetEmpty; { Specifies the bounding rectangle of the image.} property BoundsRect: TRect read GetBoundsRect; { This event occurs when the image data size has just changed. That means image width, height, or format has been changed.} property OnDataSizeChanged: TNotifyEvent read FOnDataSizeChanged write FOnDataSizeChanged; { This event occurs when some pixels of the image have just changed.} property OnPixelsChanged: TNotifyEvent read FOnPixelsChanged write FOnPixelsChanged; end; { Extension of TBaseImage which uses single TImageData record to store image. All methods inherited from TBaseImage work with this record.} TSingleImage = class(TBaseImage) protected FImageData: TImageData; procedure SetPointer; override; public constructor Create; override; constructor CreateFromParams(AWidth, AHeight: Integer; AFormat: TImageFormat = ifDefault); constructor CreateFromData(const AData: TImageData); constructor CreateFromFile(const FileName: string); constructor CreateFromStream(Stream: TStream); destructor Destroy; override; { Assigns single image from another single image or multi image.} procedure Assign(Source: TPersistent); override; { Assigns single image from image data record.} procedure AssignFromImageData(const AImageData: TImageData); end; { Extension of TBaseImage which uses array of TImageData records to store multiple images. Images are independent on each other and they don't share any common characteristic. Each can have different size, format, and palette. All methods inherited from TBaseImage work only with active image (it could represent mipmap level, animation frame, or whatever). Methods whose names contain word 'Multi' work with all images in array (as well as other methods with obvious names).} TMultiImage = class(TBaseImage) protected FDataArray: TDynImageDataArray; FActiveImage: Integer; procedure SetActiveImage(Value: Integer); {$IFDEF USE_INLINE}inline;{$ENDIF} function GetImageCount: Integer; {$IFDEF USE_INLINE}inline;{$ENDIF} procedure SetImageCount(Value: Integer); function GetAllImagesValid: Boolean; {$IFDEF USE_INLINE}inline;{$ENDIF} function GetImage(Index: Integer): TImageData; {$IFDEF USE_INLINE}inline;{$ENDIF} procedure SetImage(Index: Integer; Value: TImageData); {$IFDEF USE_INLINE}inline;{$ENDIF} procedure SetPointer; override; function PrepareInsert(Index, Count: Integer): Boolean; procedure DoInsertImages(Index: Integer; const Images: TDynImageDataArray); procedure DoInsertNew(Index: Integer; AWidth, AHeight: Integer; AFormat: TImageFormat); public constructor Create; override; constructor CreateFromParams(AWidth, AHeight: Integer; AFormat: TImageFormat; ImageCount: Integer); constructor CreateFromArray(const ADataArray: TDynImageDataArray); constructor CreateFromFile(const FileName: string); constructor CreateFromStream(Stream: TStream); destructor Destroy; override; { Assigns multi image from another multi image or single image.} procedure Assign(Source: TPersistent); override; { Assigns multi image from array of image data records.} procedure AssignFromArray(const ADataArray: TDynImageDataArray); { Adds new image at the end of the image array. } function AddImage(AWidth, AHeight: Integer; AFormat: TImageFormat = ifDefault): Integer; overload; { Adds existing image at the end of the image array. } function AddImage(const Image: TImageData): Integer; overload; { Adds existing image (Active image of a TmultiImage) at the end of the image array. } function AddImage(Image: TBaseImage): Integer; overload; { Adds existing image array ((all images of a multi image)) at the end of the image array. } procedure AddImages(const Images: TDynImageDataArray); overload; { Adds existing MultiImage images at the end of the image array. } procedure AddImages(Images: TMultiImage); overload; { Inserts new image image at the given position in the image array. } procedure InsertImage(Index, AWidth, AHeight: Integer; AFormat: TImageFormat = ifDefault); overload; { Inserts existing image at the given position in the image array. } procedure InsertImage(Index: Integer; const Image: TImageData); overload; { Inserts existing image (Active image of a TmultiImage) at the given position in the image array. } procedure InsertImage(Index: Integer; Image: TBaseImage); overload; { Inserts existing image at the given position in the image array. } procedure InsertImages(Index: Integer; const Images: TDynImageDataArray); overload; { Inserts existing images (all images of a TmultiImage) at the given position in the image array. } procedure InsertImages(Index: Integer; Images: TMultiImage); overload; { Exchanges two images at the given positions in the image array. } procedure ExchangeImages(Index1, Index2: Integer); { Deletes image at the given position in the image array.} procedure DeleteImage(Index: Integer); { Rearranges images so that the first image will become last and vice versa.} procedure ReverseImages; { Deletes all images.} procedure ClearAll; { Converts all images to another image data format.} procedure ConvertImages(Format: TImageFormat); { Resizes all images.} procedure ResizeImages(NewWidth, NewHeight: Integer; Filter: TResizeFilter); { Overloaded loading method that will add new image to multiimage if image array is empty bero loading. } procedure LoadFromFile(const FileName: string); override; { Overloaded loading method that will add new image to multiimage if image array is empty bero loading. } procedure LoadFromStream(Stream: TStream); override; { Loads whole multi image from file.} procedure LoadMultiFromFile(const FileName: string); { Loads whole multi image from stream.} procedure LoadMultiFromStream(Stream: TStream); { Saves whole multi image to file.} procedure SaveMultiToFile(const FileName: string); { Saves whole multi image to stream. Ext identifies desired image file format (jpg, png, dds, ...).} procedure SaveMultiToStream(const Ext: string; Stream: TStream); { Indicates active image of this multi image. All methods inherited from TBaseImage operate on this image only.} property ActiveImage: Integer read FActiveImage write SetActiveImage; { Number of images of this multi image.} property ImageCount: Integer read GetImageCount write SetImageCount; { This value is True if all images of this TMultiImage are valid.} property AllImagesValid: Boolean read GetAllImagesValid; { This gives complete access to underlying TDynImageDataArray. It can be used in functions that take TDynImageDataArray as parameter.} property DataArray: TDynImageDataArray read FDataArray; { Array property for accessing individual images of TMultiImage. When you set image at given index the old image is freed and the source is cloned.} property Images[Index: Integer]: TImageData read GetImage write SetImage; default; end; implementation const DefaultWidth = 16; Defaultheight = 16; function GetArrayFromImageData(const ImageData: TImageData): TDynImageDataArray; begin SetLength(Result, 1); Result[0] := ImageData; end; { TBaseImage class implementation } constructor TBaseImage.Create; begin SetPointer; end; constructor TBaseImage.CreateFromImage(AImage: TBaseImage); begin Create; Assign(AImage); end; destructor TBaseImage.Destroy; begin inherited Destroy; end; function TBaseImage.GetWidth: Integer; begin if Valid then Result := FPData.Width else Result := 0; end; function TBaseImage.GetHeight: Integer; begin if Valid then Result := FPData.Height else Result := 0; end; function TBaseImage.GetFormat: TImageFormat; begin if Valid then Result := FPData.Format else Result := ifUnknown; end; function TBaseImage.GetScanline(Index: Integer): Pointer; var Info: TImageFormatInfo; begin if Valid then begin Info := GetFormatInfo; if not Info.IsSpecial then Result := ImagingFormats.GetScanLine(FPData.Bits, Info, FPData.Width, Index) else Result := FPData.Bits; end else Result := nil; end; function TBaseImage.GetScanlineSize: Integer; begin if Valid then Result := FormatInfo.GetPixelsSize(Format, Width, 1) else Result := 0; end; function TBaseImage.GetPixelPointer(X, Y: Integer): Pointer; begin if Valid then Result := @PByteArray(FPData.Bits)[(Y * FPData.Width + X) * GetFormatInfo.BytesPerPixel] else Result := nil; end; function TBaseImage.GetSize: Integer; begin if Valid then Result := FPData.Size else Result := 0; end; function TBaseImage.GetBits: Pointer; begin if Valid then Result := FPData.Bits else Result := nil; end; function TBaseImage.GetPalette: PPalette32; begin if Valid then Result := FPData.Palette else Result := nil; end; function TBaseImage.GetPaletteEntries: Integer; begin Result := GetFormatInfo.PaletteEntries; end; function TBaseImage.GetFormatInfo: TImageFormatInfo; begin if Valid then Imaging.GetImageFormatInfo(FPData.Format, Result) else FillChar(Result, SizeOf(Result), 0); end; function TBaseImage.GetValid: Boolean; begin Result := Assigned(FPData) and Imaging.TestImage(FPData^); end; function TBaseImage.GetBoundsRect: TRect; begin Result := Rect(0, 0, GetWidth, GetHeight); end; function TBaseImage.GetEmpty: Boolean; begin Result := FPData.Size = 0; end; procedure TBaseImage.SetWidth(const Value: Integer); begin Resize(Value, GetHeight, rfNearest); end; procedure TBaseImage.SetHeight(const Value: Integer); begin Resize(GetWidth, Value, rfNearest); end; procedure TBaseImage.SetFormat(const Value: TImageFormat); begin if Valid and Imaging.ConvertImage(FPData^, Value) then DoDataSizeChanged; end; procedure TBaseImage.DoDataSizeChanged; begin if Assigned(FOnDataSizeChanged) then FOnDataSizeChanged(Self); DoPixelsChanged; end; procedure TBaseImage.DoPixelsChanged; begin if Assigned(FOnPixelsChanged) then FOnPixelsChanged(Self); end; procedure TBaseImage.RecreateImageData(AWidth, AHeight: Integer; AFormat: TImageFormat); begin if Assigned(FPData) and Imaging.NewImage(AWidth, AHeight, AFormat, FPData^) then DoDataSizeChanged; end; procedure TBaseImage.MapImageData(const ImageData: TImageData); begin Clear; FPData.Width := ImageData.Width; FPData.Height := ImageData.Height; FPData.Format := ImageData.Format; FPData.Size := ImageData.Size; FPData.Bits := ImageData.Bits; FPData.Palette := ImageData.Palette; end; procedure TBaseImage.Clear; begin FreeImage(FPData^); end; procedure TBaseImage.Resize(NewWidth, NewHeight: Integer; Filter: TResizeFilter); begin if Valid and Imaging.ResizeImage(FPData^, NewWidth, NewHeight, Filter) then DoDataSizeChanged; end; procedure TBaseImage.ResizeToFit(FitWidth, FitHeight: Integer; Filter: TResizeFilter; DstImage: TBaseImage); begin if Valid and Assigned(DstImage) then begin Imaging.ResizeImageToFit(FPData^, FitWidth, FitHeight, Filter, DstImage.FPData^); DstImage.DoDataSizeChanged; end; end; procedure TBaseImage.Flip; begin if Valid and Imaging.FlipImage(FPData^) then DoPixelsChanged; end; procedure TBaseImage.Mirror; begin if Valid and Imaging.MirrorImage(FPData^) then DoPixelsChanged; end; procedure TBaseImage.Rotate(Angle: Single); begin if Valid then begin Imaging.RotateImage(FPData^, Angle); DoPixelsChanged; end; end; procedure TBaseImage.CopyTo(SrcX, SrcY, Width, Height: Integer; DstImage: TBaseImage; DstX, DstY: Integer); begin if Valid and Assigned(DstImage) and DstImage.Valid then begin Imaging.CopyRect(FPData^, SrcX, SrcY, Width, Height, DstImage.FPData^, DstX, DstY); DstImage.DoPixelsChanged; end; end; procedure TBaseImage.StretchTo(SrcX, SrcY, SrcWidth, SrcHeight: Integer; DstImage: TBaseImage; DstX, DstY, DstWidth, DstHeight: Integer; Filter: TResizeFilter); begin if Valid and Assigned(DstImage) and DstImage.Valid then begin Imaging.StretchRect(FPData^, SrcX, SrcY, SrcWidth, SrcHeight, DstImage.FPData^, DstX, DstY, DstWidth, DstHeight, Filter); DstImage.DoPixelsChanged; end; end; procedure TBaseImage.ReplaceColor(X, Y, Width, Height: Integer; OldColor, NewColor: Pointer); begin if Valid then begin Imaging.ReplaceColor(FPData^, X, Y, Width, Height, OldColor, NewColor); DoPixelsChanged; end; end; procedure TBaseImage.SwapChannels(SrcChannel, DstChannel: Integer); begin if Valid then begin Imaging.SwapChannels(FPData^, SrcChannel, DstChannel); DoPixelsChanged; end; end; function TBaseImage.ToString: string; begin Result := Iff(Valid, Imaging.ImageToStr(FPData^), 'empty image'); end; procedure TBaseImage.LoadFromFile(const FileName: string); begin if Assigned(FPData) and Imaging.LoadImageFromFile(FileName, FPData^) then DoDataSizeChanged; end; procedure TBaseImage.LoadFromStream(Stream: TStream); begin if Assigned(FPData) and Imaging.LoadImageFromStream(Stream, FPData^) then DoDataSizeChanged; end; procedure TBaseImage.SaveToFile(const FileName: string); begin if Valid then Imaging.SaveImageToFile(FileName, FPData^); end; procedure TBaseImage.SaveToStream(const Ext: string; Stream: TStream); begin if Valid then Imaging.SaveImageToStream(Ext, Stream, FPData^); end; { TSingleImage class implementation } constructor TSingleImage.Create; begin inherited Create; Clear; end; constructor TSingleImage.CreateFromParams(AWidth, AHeight: Integer; AFormat: TImageFormat); begin inherited Create; RecreateImageData(AWidth, AHeight, AFormat); end; constructor TSingleImage.CreateFromData(const AData: TImageData); begin inherited Create; AssignFromImageData(AData); end; constructor TSingleImage.CreateFromFile(const FileName: string); begin inherited Create; LoadFromFile(FileName); end; constructor TSingleImage.CreateFromStream(Stream: TStream); begin inherited Create; LoadFromStream(Stream); end; destructor TSingleImage.Destroy; begin Imaging.FreeImage(FImageData); inherited Destroy; end; procedure TSingleImage.SetPointer; begin FPData := @FImageData; end; procedure TSingleImage.Assign(Source: TPersistent); begin if Source = nil then begin Clear; end else if Source is TSingleImage then begin AssignFromImageData(TSingleImage(Source).FImageData); end else if Source is TMultiImage then begin if TMultiImage(Source).Valid then AssignFromImageData(TMultiImage(Source).FPData^) else Clear; end else inherited Assign(Source); end; procedure TSingleImage.AssignFromImageData(const AImageData: TImageData); begin if Imaging.TestImage(AImageData) then begin Imaging.CloneImage(AImageData, FImageData); DoDataSizeChanged; end else Clear; end; { TMultiImage class implementation } constructor TMultiImage.Create; begin inherited Create; end; constructor TMultiImage.CreateFromParams(AWidth, AHeight: Integer; AFormat: TImageFormat; ImageCount: Integer); var I: Integer; begin Imaging.FreeImagesInArray(FDataArray); SetLength(FDataArray, ImageCount); for I := 0 to GetImageCount - 1 do Imaging.NewImage(AWidth, AHeight, AFormat, FDataArray[I]); if GetImageCount > 0 then SetActiveImage(0); end; constructor TMultiImage.CreateFromArray(const ADataArray: TDynImageDataArray); begin AssignFromArray(ADataArray); end; constructor TMultiImage.CreateFromFile(const FileName: string); begin LoadMultiFromFile(FileName); end; constructor TMultiImage.CreateFromStream(Stream: TStream); begin LoadMultiFromStream(Stream); end; destructor TMultiImage.Destroy; begin Imaging.FreeImagesInArray(FDataArray); inherited Destroy; end; procedure TMultiImage.SetActiveImage(Value: Integer); begin FActiveImage := Value; SetPointer; end; function TMultiImage.GetImageCount: Integer; begin Result := Length(FDataArray); end; procedure TMultiImage.SetImageCount(Value: Integer); var I, OldCount: Integer; begin if Value > GetImageCount then begin // Create new empty images if array will be enlarged OldCount := GetImageCount; SetLength(FDataArray, Value); for I := OldCount to Value - 1 do Imaging.NewImage(DefaultWidth, DefaultHeight, ifDefault, FDataArray[I]); end else begin // Free images that exceed desired count and shrink array for I := Value to GetImageCount - 1 do Imaging.FreeImage(FDataArray[I]); SetLength(FDataArray, Value); end; SetPointer; end; function TMultiImage.GetAllImagesValid: Boolean; begin Result := (GetImageCount > 0) and TestImagesInArray(FDataArray); end; function TMultiImage.GetImage(Index: Integer): TImageData; begin if (Index >= 0) and (Index < GetImageCount) then Result := FDataArray[Index]; end; procedure TMultiImage.SetImage(Index: Integer; Value: TImageData); begin if (Index >= 0) and (Index < GetImageCount) then Imaging.CloneImage(Value, FDataArray[Index]); end; procedure TMultiImage.SetPointer; begin if GetImageCount > 0 then begin FActiveImage := ClampInt(FActiveImage, 0, GetImageCount - 1); FPData := @FDataArray[FActiveImage]; end else begin FActiveImage := -1; FPData := nil end; end; function TMultiImage.PrepareInsert(Index, Count: Integer): Boolean; var I: Integer; begin // Inserting to empty image will add image at index 0 if GetImageCount = 0 then Index := 0; if (Index >= 0) and (Index <= GetImageCount) and (Count > 0) then begin SetLength(FDataArray, GetImageCount + Count); if Index < GetImageCount - 1 then begin // Move imges to new position System.Move(FDataArray[Index], FDataArray[Index + Count], (GetImageCount - Count - Index) * SizeOf(TImageData)); // Null old images, not free them! for I := Index to Index + Count - 1 do InitImage(FDataArray[I]); end; Result := True; end else Result := False; end; procedure TMultiImage.DoInsertImages(Index: Integer; const Images: TDynImageDataArray); var I, Len: Integer; begin Len := Length(Images); if PrepareInsert(Index, Len) then begin for I := 0 to Len - 1 do Imaging.CloneImage(Images[I], FDataArray[Index + I]); end; end; procedure TMultiImage.DoInsertNew(Index, AWidth, AHeight: Integer; AFormat: TImageFormat); begin if PrepareInsert(Index, 1) then Imaging.NewImage(AWidth, AHeight, AFormat, FDataArray[Index]); end; procedure TMultiImage.Assign(Source: TPersistent); var Arr: TDynImageDataArray; begin if Source = nil then begin ClearAll; end else if Source is TMultiImage then begin AssignFromArray(TMultiImage(Source).FDataArray); SetActiveImage(TMultiImage(Source).ActiveImage); end else if Source is TSingleImage then begin SetLength(Arr, 1); Arr[0] := TSingleImage(Source).FImageData; AssignFromArray(Arr); end else inherited Assign(Source); end; procedure TMultiImage.AssignFromArray(const ADataArray: TDynImageDataArray); var I: Integer; begin Imaging.FreeImagesInArray(FDataArray); SetLength(FDataArray, Length(ADataArray)); for I := 0 to GetImageCount - 1 do begin // Clone only valid images if Imaging.TestImage(ADataArray[I]) then Imaging.CloneImage(ADataArray[I], FDataArray[I]) else Imaging.NewImage(DefaultWidth, DefaultHeight, ifDefault, FDataArray[I]); end; if GetImageCount > 0 then SetActiveImage(0); end; function TMultiImage.AddImage(AWidth, AHeight: Integer; AFormat: TImageFormat): Integer; begin Result := GetImageCount; DoInsertNew(Result, AWidth, AHeight, AFormat); end; function TMultiImage.AddImage(const Image: TImageData): Integer; begin Result := GetImageCount; DoInsertImages(Result, GetArrayFromImageData(Image)); end; function TMultiImage.AddImage(Image: TBaseImage): Integer; begin if Assigned(Image) and Image.Valid then begin Result := GetImageCount; DoInsertImages(Result, GetArrayFromImageData(Image.FPData^)); end else Result := -1; end; procedure TMultiImage.AddImages(const Images: TDynImageDataArray); begin DoInsertImages(GetImageCount, Images); end; procedure TMultiImage.AddImages(Images: TMultiImage); begin DoInsertImages(GetImageCount, Images.FDataArray); end; procedure TMultiImage.InsertImage(Index, AWidth, AHeight: Integer; AFormat: TImageFormat); begin DoInsertNew(Index, AWidth, AHeight, AFormat); end; procedure TMultiImage.InsertImage(Index: Integer; const Image: TImageData); begin DoInsertImages(Index, GetArrayFromImageData(Image)); end; procedure TMultiImage.InsertImage(Index: Integer; Image: TBaseImage); begin if Assigned(Image) and Image.Valid then DoInsertImages(Index, GetArrayFromImageData(Image.FPData^)); end; procedure TMultiImage.InsertImages(Index: Integer; const Images: TDynImageDataArray); begin DoInsertImages(Index, FDataArray); end; procedure TMultiImage.InsertImages(Index: Integer; Images: TMultiImage); begin DoInsertImages(Index, Images.FDataArray); end; procedure TMultiImage.ExchangeImages(Index1, Index2: Integer); var TempData: TImageData; begin if (Index1 >= 0) and (Index1 < GetImageCount) and (Index2 >= 0) and (Index2 < GetImageCount) then begin TempData := FDataArray[Index1]; FDataArray[Index1] := FDataArray[Index2]; FDataArray[Index2] := TempData; end; end; procedure TMultiImage.DeleteImage(Index: Integer); var I: Integer; begin if (Index >= 0) and (Index < GetImageCount) then begin // Free image at index to be deleted Imaging.FreeImage(FDataArray[Index]); if Index < GetImageCount - 1 then begin // Move images to new indices if necessary for I := Index to GetImageCount - 2 do FDataArray[I] := FDataArray[I + 1]; end; // Set new array length and update pointer to active image SetLength(FDataArray, GetImageCount - 1); SetPointer; end; end; procedure TMultiImage.ClearAll; begin ImageCount := 0; end; procedure TMultiImage.ConvertImages(Format: TImageFormat); var I: Integer; begin for I := 0 to GetImageCount - 1 do Imaging.ConvertImage(FDataArray[I], Format); end; procedure TMultiImage.ResizeImages(NewWidth, NewHeight: Integer; Filter: TResizeFilter); var I: Integer; begin for I := 0 to GetImageCount - 1 do Imaging.ResizeImage(FDataArray[I], NewWidth, NewHeight, Filter); end; procedure TMultiImage.ReverseImages; var I: Integer; begin for I := 0 to GetImageCount div 2 do ExchangeImages(I, GetImageCount - 1 - I); end; procedure TMultiImage.LoadFromFile(const FileName: string); begin if GetImageCount = 0 then ImageCount := 1; inherited LoadFromFile(FileName); end; procedure TMultiImage.LoadFromStream(Stream: TStream); begin if GetImageCount = 0 then ImageCount := 1; inherited LoadFromStream(Stream); end; procedure TMultiImage.LoadMultiFromFile(const FileName: string); begin Imaging.LoadMultiImageFromFile(FileName, FDataArray); SetActiveImage(0); end; procedure TMultiImage.LoadMultiFromStream(Stream: TStream); begin Imaging.LoadMultiImageFromStream(Stream, FDataArray); SetActiveImage(0); end; procedure TMultiImage.SaveMultiToFile(const FileName: string); begin Imaging.SaveMultiImageToFile(FileName, FDataArray); end; procedure TMultiImage.SaveMultiToStream(const Ext: string; Stream: TStream); begin Imaging.SaveMultiImageToStream(Ext, Stream, FDataArray); end; { File Notes: -- TODOS ---------------------------------------------------- - nothing now -- 0.77.1 --------------------------------------------------- - Added TSingleImage.AssignFromData and TMultiImage.AssigntFromArray as a replacement for constructors used as methods (that is compiler error in Delphi XE3). - Added TBaseImage.ResizeToFit method. - Changed TMultiImage to have default state with no images. - TMultiImage.AddImage now returns index of newly added image. - Fixed img index bug in TMultiImage.ResizeImages -- 0.26.5 Changes/Bug Fixes --------------------------------- - Added MapImageData method to TBaseImage - Added Empty property to TBaseImage. - Added Clear method to TBaseImage. - Added ScanlineSize property to TBaseImage. -- 0.24.3 Changes/Bug Fixes --------------------------------- - Added TMultiImage.ReverseImages method. -- 0.23 Changes/Bug Fixes ----------------------------------- - Added SwapChannels method to TBaseImage. - Added ReplaceColor method to TBaseImage. - Added ToString method to TBaseImage. -- 0.21 Changes/Bug Fixes ----------------------------------- - Inserting images to empty MultiImage will act as Add method. - MultiImages with empty arrays will now create one image when LoadFromFile or LoadFromStream is called. - Fixed bug that caused AVs when getting props like Width, Height, asn Size and when inlining was off. There was call to Iff but with inlining disabled params like FPData.Size were evaluated and when FPData was nil => AV. - Added many FPData validity checks to many methods. There were AVs when calling most methods on empty TMultiImage. - Added AllImagesValid property to TMultiImage. - Fixed memory leak in TMultiImage.CreateFromParams. -- 0.19 Changes/Bug Fixes ----------------------------------- - added ResizeImages method to TMultiImage - removed Ext parameter from various LoadFromStream methods, no longer needed - fixed various issues concerning ActiveImage of TMultiImage (it pointed to invalid location after some operations) - most of property set/get methods are now inline - added PixelPointers property to TBaseImage - added Images default array property to TMultiImage - renamed methods in TMultiImage to contain 'Image' instead of 'Level' - added canvas support - added OnDataSizeChanged and OnPixelsChanged event to TBaseImage - renamed TSingleImage.NewImage to RecreateImageData, made public, and moved to TBaseImage -- 0.17 Changes/Bug Fixes ----------------------------------- - added props PaletteEntries and ScanLine to TBaseImage - aded new constructor to TBaseImage that take TBaseImage source - TMultiImage levels adding and inserting rewritten internally - added some new functions to TMultiImage: AddLevels, InsertLevels - added some new functions to TBaseImage: Flip, Mirror, Rotate, CopyRect, StretchRect - TBasicImage.Resize has now filter parameter - new stuff added to TMultiImage (DataArray prop, ConvertLevels) -- 0.13 Changes/Bug Fixes ----------------------------------- - added AddLevel, InsertLevel, ExchangeLevels and DeleteLevel methods to TMultiImage - added TBaseImage, TSingleImage and TMultiImage with initial members } end. ================================================ FILE: lib/Imaging/ImagingColors.pas ================================================ { Vampyre Imaging Library by Marek Mauder http://imaginglib.sourceforge.net The contents of this file are used with permission, subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/MPL-1.1.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Alternatively, the contents of this file may be used under the terms of the GNU Lesser General Public License (the "LGPL License"), in which case the provisions of the LGPL License are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of the LGPL License and not to allow others to use your version of this file under the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the LGPL License. If you do not delete the provisions above, a recipient may use your version of this file under either the MPL or the LGPL License. For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html } { This unit contains functions for manipulating and converting color values.} unit ImagingColors; interface {$I ImagingOptions.inc} uses SysUtils, ImagingTypes, ImagingUtility; { Converts RGB color to YUV.} procedure RGBToYUV(R, G, B: Byte; var Y, U, V: Byte); { Converts YIV to RGB color.} procedure YUVToRGB(Y, U, V: Byte; var R, G, B: Byte); { Converts RGB color to YCbCr as used in JPEG.} procedure RGBToYCbCr(R, G, B: Byte; var Y, Cb, Cr: Byte); { Converts YCbCr as used in JPEG to RGB color.} procedure YCbCrToRGB(Y, Cb, Cr: Byte; var R, G, B: Byte); { Converts RGB color to YCbCr as used in JPEG.} procedure RGBToYCbCr16(R, G, B: Word; var Y, Cb, Cr: Word); { Converts YCbCr as used in JPEG to RGB color.} procedure YCbCrToRGB16(Y, Cb, Cr: Word; var R, G, B: Word); { Converts RGB color to CMY.} procedure RGBToCMY(R, G, B: Byte; var C, M, Y: Byte); { Converts CMY to RGB color.} procedure CMYToRGB(C, M, Y: Byte; var R, G, B: Byte); { Converts RGB color to CMY.} procedure RGBToCMY16(R, G, B: Word; var C, M, Y: Word); { Converts CMY to RGB color.} procedure CMYToRGB16(C, M, Y: Word; var R, G, B: Word); { Converts RGB color to CMYK.} procedure RGBToCMYK(R, G, B: Byte; var C, M, Y, K: Byte); { Converts CMYK to RGB color.} procedure CMYKToRGB(C, M, Y, K: Byte; var R, G, B: Byte); { Converts RGB color to CMYK.} procedure RGBToCMYK16(R, G, B: Word; var C, M, Y, K: Word); { Converts CMYK to RGB color.} procedure CMYKToRGB16(C, M, Y, K: Word; var R, G, B: Word); { Converts RGB color to YCoCg.} procedure RGBToYCoCg(R, G, B: Byte; var Y, Co, Cg: Byte); { Converts YCoCg to RGB color.} procedure YCoCgToRGB(Y, Co, Cg: Byte; var R, G, B: Byte); //procedure RGBToHSL(R, G, B: Byte; var H, S, L: Byte); //procedure HSLToRGB(H, S, L: Byte; var R, G, B: Byte); implementation procedure RGBToYUV(R, G, B: Byte; var Y, U, V: Byte); begin Y := ClampToByte(Round( 0.257 * R + 0.504 * G + 0.098 * B) + 16); V := ClampToByte(Round( 0.439 * R - 0.368 * G - 0.071 * B) + 128); U := ClampToByte(Round(-0.148 * R - 0.291 * G + 0.439 * B) + 128); end; procedure YUVToRGB(Y, U, V: Byte; var R, G, B: Byte); var CY, CU, CV: LongInt; begin CY := Y - 16; CU := U - 128; CV := V - 128; R := ClampToByte(Round(1.164 * CY - 0.002 * CU + 1.596 * CV)); G := ClampToByte(Round(1.164 * CY - 0.391 * CU - 0.813 * CV)); B := ClampToByte(Round(1.164 * CY + 2.018 * CU - 0.001 * CV)); end; procedure RGBToYCbCr(R, G, B: Byte; var Y, Cb, Cr: Byte); begin Y := ClampToByte(Round( 0.29900 * R + 0.58700 * G + 0.11400 * B)); Cb := ClampToByte(Round(-0.16874 * R - 0.33126 * G + 0.50000 * B + 128)); Cr := ClampToByte(Round( 0.50000 * R - 0.41869 * G - 0.08131 * B + 128)); end; procedure YCbCrToRGB(Y, Cb, Cr: Byte; var R, G, B: Byte); begin R := ClampToByte(Round(Y + 1.40200 * (Cr - 128))); G := ClampToByte(Round(Y - 0.34414 * (Cb - 128) - 0.71414 * (Cr - 128))); B := ClampToByte(Round(Y + 1.77200 * (Cb - 128))); end; procedure RGBToYCbCr16(R, G, B: Word; var Y, Cb, Cr: Word); begin Y := ClampToWord(Round( 0.29900 * R + 0.58700 * G + 0.11400 * B)); Cb := ClampToWord(Round(-0.16874 * R - 0.33126 * G + 0.50000 * B + 32768)); Cr := ClampToWord(Round( 0.50000 * R - 0.41869 * G - 0.08131 * B + 32768)); end; procedure YCbCrToRGB16(Y, Cb, Cr: Word; var R, G, B: Word); begin R := ClampToWord(Round(Y + 1.40200 * (Cr - 32768))); G := ClampToWord(Round(Y - 0.34414 * (Cb - 32768) - 0.71414 * (Cr - 32768))); B := ClampToWord(Round(Y + 1.77200 * (Cb - 32768))); end; procedure RGBToCMY(R, G, B: Byte; var C, M, Y: Byte); begin C := 255 - R; M := 255 - G; Y := 255 - B; end; procedure CMYToRGB(C, M, Y: Byte; var R, G, B: Byte); begin R := 255 - C; G := 255 - M; B := 255 - Y; end; procedure RGBToCMY16(R, G, B: Word; var C, M, Y: Word); begin C := 65535 - R; M := 65535 - G; Y := 65535 - B; end; procedure CMYToRGB16(C, M, Y: Word; var R, G, B: Word); begin R := 65535 - C; G := 65535 - M; B := 65535 - Y; end; procedure RGBToCMYK(R, G, B: Byte; var C, M, Y, K: Byte); begin RGBToCMY(R, G, B, C, M, Y); K := Min(C, Min(M, Y)); if K = 255 then begin C := 0; M := 0; Y := 0; end else begin C := ClampToByte(Round((C - K) / (255 - K) * 255)); M := ClampToByte(Round((M - K) / (255 - K) * 255)); Y := ClampToByte(Round((Y - K) / (255 - K) * 255)); end; end; procedure CMYKToRGB(C, M, Y, K: Byte; var R, G, B: Byte); begin R := (255 - (C - MulDiv(C, K, 255) + K)); G := (255 - (M - MulDiv(M, K, 255) + K)); B := (255 - (Y - MulDiv(Y, K, 255) + K)); end; procedure RGBToCMYK16(R, G, B: Word; var C, M, Y, K: Word); begin RGBToCMY16(R, G, B, C, M, Y); K := Min(C, Min(M, Y)); if K = 65535 then begin C := 0; M := 0; Y := 0; end else begin C := ClampToWord(Round((C - K) / (65535 - K) * 65535)); M := ClampToWord(Round((M - K) / (65535 - K) * 65535)); Y := ClampToWord(Round((Y - K) / (65535 - K) * 65535)); end; end; procedure CMYKToRGB16(C, M, Y, K: Word; var R, G, B: Word); begin R := 65535 - (C - MulDiv(C, K, 65535) + K); G := 65535 - (M - MulDiv(M, K, 65535) + K); B := 65535 - (Y - MulDiv(Y, K, 65535) + K); end; procedure RGBToYCoCg(R, G, B: Byte; var Y, Co, Cg: Byte); begin // C and Delphi's SHR behaviour differs for negative numbers, use div instead. Y := ClampToByte(( R + G shl 1 + B + 2) div 4); Co := ClampToByte(( R shl 1 - B shl 1 + 2) div 4 + 128); Cg := ClampToByte((-R + G shl 1 - B + 2) div 4 + 128); end; procedure YCoCgToRGB(Y, Co, Cg: Byte; var R, G, B: Byte); var CoInt, CgInt: Integer; begin CoInt := Co - 128; CgInt := Cg - 128; R := ClampToByte(Y + CoInt - CgInt); G := ClampToByte(Y + CgInt); B := ClampToByte(Y - CoInt - CgInt); end; { File Notes: -- TODOS ---------------------------------------------------- - nothing now -- 0.26.3 Changes/Bug Fixes --------------------------------- - Added RGB<>YCoCg conversion functions. - Fixed RGB>>CMYK conversions. -- 0.23 Changes/Bug Fixes ----------------------------------- - Added RGB<>CMY(K) converion functions for 16 bit channels (needed by PSD loading code). -- 0.21 Changes/Bug Fixes ----------------------------------- - Added some color space conversion functions and LUTs (RGB/YUV/YCrCb/CMY/CMYK). -- 0.17 Changes/Bug Fixes ----------------------------------- - unit created (empty!) } end. ================================================ FILE: lib/Imaging/ImagingComponents.pas ================================================ { Vampyre Imaging Library by Marek Mauder http://imaginglib.sourceforge.net The contents of this file are used with permission, subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/MPL-1.1.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Alternatively, the contents of this file may be used under the terms of the GNU Lesser General Public License (the "LGPL License"), in which case the provisions of the LGPL License are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of the LGPL License and not to allow others to use your version of this file under the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the LGPL License. If you do not delete the provisions above, a recipient may use your version of this file under either the MPL or the LGPL License. For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html } { This unit contains VCL/LCL TGraphic descendant which uses Imaging library for saving and loading.} unit ImagingComponents; {$I ImagingOptions.inc} interface {$IFDEF LCL} {$DEFINE COMPONENT_SET_LCL} {$UNDEF COMPONENT_SET_VCL} {$ENDIF} {$IF not Defined(COMPONENT_SET_LCL) and not Defined(COMPONENT_SET_VCL)} // If no component sets should be used just include empty unit. //DOC-IGNORE-BEGIN implementation //DOC-IGNORE-END {$ELSE} uses SysUtils, Types, Classes, {$IFDEF MSWINDOWS} Windows, {$ENDIF} {$IFDEF COMPONENT_SET_VCL} Graphics, {$ENDIF} {$IFDEF COMPONENT_SET_LCL} InterfaceBase, GraphType, Graphics, LCLType, LCLIntf, {$ENDIF} ImagingTypes, Imaging, ImagingClasses; type { Graphic class which uses Imaging to load images. It has standard TBitmap class as ancestor and it can Assign also to/from TImageData structres and TBaseImage classes. For saving is uses inherited TBitmap methods. This class is automatically registered to TPicture for all file extensions supported by Imaging (useful only for loading). If you just want to load images in various formats you can use this class or simply use TPicture.LoadFromXXX which will create this class automatically. For TGraphic class that saves with Imaging look at TImagingGraphicForSave class.} TImagingGraphic = class(TBitmap) protected procedure ReadDataFromStream(Stream: TStream); virtual; procedure AssignTo(Dest: TPersistent); override; public constructor Create; override; { Loads new image from the stream. It can load all image file formats supported by Imaging (and enabled of course) even though it is called by descendant class capable of saving only one file format.} procedure LoadFromStream(Stream: TStream); override; { Copies the image contained in Source to this graphic object. Supports also TBaseImage descendants from ImagingClasses unit. } procedure Assign(Source: TPersistent); override; { Copies the image contained in TBaseImage to this graphic object.} procedure AssignFromImage(Image: TBaseImage); { Copies the current image to TBaseImage object.} procedure AssignToImage(Image: TBaseImage); { Copies the image contained in TImageData structure to this graphic object.} procedure AssignFromImageData(const ImageData: TImageData); { Copies the current image to TImageData structure.} procedure AssignToImageData(var ImageData: TImageData); end; TImagingGraphicClass = class of TImagingGraphic; { Base class for file format specific TGraphic classes that use Imaging for saving. Each descendant class can load all file formats supported by Imaging but save only one format (TImagingBitmap for *.bmp, TImagingJpeg for *.jpg). Format specific classes also allow easy access to Imaging options that affect saving of files (they are properties here).} TImagingGraphicForSave = class(TImagingGraphic) protected FDefaultFileExt: string; FSavingFormat: TImageFormat; procedure WriteDataToStream(Stream: TStream); virtual; public constructor Create; override; { Saves the current image to the stream. It is saved in the file format according to the DefaultFileExt property. So each descendant class can save some other file format.} procedure SaveToStream(Stream: TStream); override; { Returns TImageFileFormat descendant for this graphic class.} class function GetFileFormat: TImageFileFormat; virtual; abstract; {$IFDEF COMPONENT_SET_LCL} { Returns file extensions of this graphic class.} class function GetFileExtensions: string; override; { Returns default MIME type of this graphic class.} function GetMimeType: string; override; {$ENDIF} { Default (the most common) file extension of this graphic class.} property DefaultFileExt: string read FDefaultFileExt; end; TImagingGraphicForSaveClass = class of TImagingGraphicForSave; {$IFNDEF DONT_LINK_BITMAP} { TImagingGraphic descendant for loading/saving Windows bitmaps. VCL/CLX/LCL all have native support for bitmaps so you might want to disable this class (although you can save bitmaps with RLE compression with this class).} TImagingBitmap = class(TImagingGraphicForSave) protected FUseRLE: Boolean; public constructor Create; override; procedure SaveToStream(Stream: TStream); override; class function GetFileFormat: TImageFileFormat; override; { See ImagingBitmapRLE option for details.} property UseRLE: Boolean read FUseRLE write FUseRLE; end; {$ENDIF} {$IFNDEF DONT_LINK_JPEG} { TImagingGraphic descendant for loading/saving JPEG images.} TImagingJpeg = class(TImagingGraphicForSave) protected FQuality: LongInt; FProgressive: Boolean; public constructor Create; override; procedure SaveToStream(Stream: TStream); override; class function GetFileFormat: TImageFileFormat; override; {$IFDEF COMPONENT_SET_LCL} function GetMimeType: string; override; {$ENDIF} { See ImagingJpegQuality option for details.} property Quality: LongInt read FQuality write FQuality; { See ImagingJpegProgressive option for details.} property Progressive: Boolean read FProgressive write FProgressive; end; {$ENDIF} {$IFNDEF DONT_LINK_PNG} { TImagingGraphic descendant for loading/saving PNG images.} TImagingPNG = class(TImagingGraphicForSave) protected FPreFilter: LongInt; FCompressLevel: LongInt; public constructor Create; override; procedure SaveToStream(Stream: TStream); override; class function GetFileFormat: TImageFileFormat; override; { See ImagingPNGPreFilter option for details.} property PreFilter: LongInt read FPreFilter write FPreFilter; { See ImagingPNGCompressLevel option for details.} property CompressLevel: LongInt read FCompressLevel write FCompressLevel; end; {$ENDIF} {$IFNDEF DONT_LINK_GIF} { TImagingGraphic descendant for loading/saving GIF images.} TImagingGIF = class(TImagingGraphicForSave) public class function GetFileFormat: TImageFileFormat; override; end; {$ENDIF} {$IFNDEF DONT_LINK_TARGA} { TImagingGraphic descendant for loading/saving Targa images.} TImagingTarga = class(TImagingGraphicForSave) protected FUseRLE: Boolean; public constructor Create; override; procedure SaveToStream(Stream: TStream); override; class function GetFileFormat: TImageFileFormat; override; { See ImagingTargaRLE option for details.} property UseRLE: Boolean read FUseRLE write FUseRLE; end; {$ENDIF} {$IFNDEF DONT_LINK_DDS} { Compresssion type used when saving DDS files by TImagingDds.} TDDSCompresion = (dcNone, dcDXT1, dcDXT3, dcDXT5); { TImagingGraphic descendant for loading/saving DDS images.} TImagingDDS = class(TImagingGraphicForSave) protected FCompression: TDDSCompresion; public constructor Create; override; procedure SaveToStream(Stream: TStream); override; class function GetFileFormat: TImageFileFormat; override; { You can choose compression type used when saving DDS file. dcNone means that file will be saved in the current bitmaps pixel format.} property Compression: TDDSCompresion read FCompression write FCompression; end; {$ENDIF} {$IFNDEF DONT_LINK_MNG} { TImagingGraphic descendant for loading/saving MNG images.} TImagingMNG = class(TImagingGraphicForSave) protected FLossyCompression: Boolean; FLossyAlpha: Boolean; FPreFilter: LongInt; FCompressLevel: LongInt; FQuality: LongInt; FProgressive: Boolean; public constructor Create; override; procedure SaveToStream(Stream: TStream); override; class function GetFileFormat: TImageFileFormat; override; {$IFDEF COMPONENT_SET_LCL} function GetMimeType: string; override; {$ENDIF} { See ImagingMNGLossyCompression option for details.} property LossyCompression: Boolean read FLossyCompression write FLossyCompression; { See ImagingMNGLossyAlpha option for details.} property LossyAlpha: Boolean read FLossyAlpha write FLossyAlpha; { See ImagingMNGPreFilter option for details.} property PreFilter: LongInt read FPreFilter write FPreFilter; { See ImagingMNGCompressLevel option for details.} property CompressLevel: LongInt read FCompressLevel write FCompressLevel; { See ImagingMNGQuality option for details.} property Quality: LongInt read FQuality write FQuality; { See ImagingMNGProgressive option for details.} property Progressive: Boolean read FProgressive write FProgressive; end; {$ENDIF} {$IFNDEF DONT_LINK_JNG} { TImagingGraphic descendant for loading/saving JNG images.} TImagingJNG = class(TImagingGraphicForSave) protected FLossyAlpha: Boolean; FAlphaPreFilter: LongInt; FAlphaCompressLevel: LongInt; FQuality: LongInt; FProgressive: Boolean; public constructor Create; override; procedure SaveToStream(Stream: TStream); override; class function GetFileFormat: TImageFileFormat; override; { See ImagingJNGLossyAlpha option for details.} property LossyAlpha: Boolean read FLossyAlpha write FLossyAlpha; { See ImagingJNGPreFilter option for details.} property AlphaPreFilter: LongInt read FAlphaPreFilter write FAlphaPreFilter; { See ImagingJNGCompressLevel option for details.} property AlphaCompressLevel: LongInt read FAlphaCompressLevel write FAlphaCompressLevel; { See ImagingJNGQuality option for details.} property Quality: LongInt read FQuality write FQuality; { See ImagingJNGProgressive option for details.} property Progressive: Boolean read FProgressive write FProgressive; end; {$ENDIF} { Returns bitmap pixel format with the closest match with given data format.} function DataFormatToPixelFormat(Format: TImageFormat): TPixelFormat; { Returns data format with closest match with given bitmap pixel format.} function PixelFormatToDataFormat(Format: TPixelFormat): TImageFormat; { Converts TImageData structure to VCL/CLX/LCL bitmap.} procedure ConvertDataToBitmap(const Data: TImageData; Bitmap: TBitmap); { Converts VCL/CLX/LCL bitmap to TImageData structure.} procedure ConvertBitmapToData(Bitmap: TBitmap; var Data: TImageData); { Converts TBaseImage instance to VCL/CLX/LCL bitmap.} procedure ConvertImageToBitmap(Image: TBaseImage; Bitmap: TBitmap); { Converts VCL/CLX/LCL bitmap to TBaseImage. Image must exist before procedure is called. It overwrites its current image data. When Image is TMultiImage only the current image level is overwritten.} procedure ConvertBitmapToImage(Bitmap: TBitmap; Image: TBaseImage); { Displays image stored in TImageData structure onto TCanvas. This procedure draws image without converting from Imaging format to TBitmap. Only [ifA8R8G8B8, ifX8R8G8B8] image formats are supported. Use this when you want displaying images that change frequently (because converting to TBitmap by ConvertImageDataToBitmap is generally slow). Dest and Src rectangles represent coordinates in the form (X1, Y1, X2, Y2).} procedure DisplayImageData(DstCanvas: TCanvas; const DstRect: TRect; const ImageData: TImageData; const SrcRect: TRect); { Displays image onto TCanvas at position [DstX, DstY]. This procedure draws image without converting from Imaging format to TBitmap. Only [ifA8R8G8B8, ifX8R8G8B8] image formats are supported. Use this when you want displaying images that change frequently (because converting to TBitmap by ConvertImageDataToBitmap is generally slow).} procedure DisplayImage(DstCanvas: TCanvas; DstX, DstY: LongInt; Image: TBaseImage); overload; { Displays image onto TCanvas to rectangle DstRect. This procedure draws image without converting from Imaging format to TBitmap. Only [ifA8R8G8B8, ifX8R8G8B8] image formats are supported. Use this when you want displaying images that change frequently (because converting to TBitmap by ConvertImageDataToBitmap is generally slow).} procedure DisplayImage(DstCanvas: TCanvas; const DstRect: TRect; Image: TBaseImage); overload; { Displays part of the image specified by SrcRect onto TCanvas to rectangle DstRect. This procedure draws image without converting from Imaging format to TBitmap. Only [ifA8R8G8B8, ifX8R8G8B8] image formats are supported. Use this when you want displaying images that change frequently (because converting to TBitmap by ConvertImageDataToBitmap is generally slow).} procedure DisplayImage(DstCanvas: TCanvas; const DstRect: TRect; Image: TBaseImage; const SrcRect: TRect); overload; {$IFDEF MSWINDOWS} { Displays image stored in TImageData structure onto Windows device context. Behaviour is the same as of DisplayImageData.} procedure DisplayImageDataOnDC(DC: HDC; const DstRect: TRect; const ImageData: TImageData; const SrcRect: TRect); {$ENDIF} implementation uses {$IF Defined(LCL)} {$IF Defined(LCLGTK2)} GLib2, GDK2, GTK2, GTK2Def, GTK2Proc, {$IFEND} {$IFEND} {$IFNDEF DONT_LINK_BITMAP} ImagingBitmap, {$ENDIF} {$IFNDEF DONT_LINK_JPEG} ImagingJpeg, {$ENDIF} {$IFNDEF DONT_LINK_GIF} ImagingGif, {$ENDIF} {$IFNDEF DONT_LINK_TARGA} ImagingTarga, {$ENDIF} {$IFNDEF DONT_LINK_DDS} ImagingDds, {$ENDIF} {$IF not Defined(DONT_LINK_PNG) or not Defined(DONT_LINK_MNG) or not Defined(DONT_LINK_JNG)} ImagingNetworkGraphics, {$IFEND} ImagingFormats, ImagingUtility; resourcestring SBadFormatDataToBitmap = 'Cannot find compatible bitmap format for image %s'; SBadFormatBitmapToData = 'Cannot find compatible data format for bitmap %p'; SBadFormatDisplay = 'Unsupported image format passed'; SUnsupportedLCLWidgetSet = 'This function is not implemented for current LCL widget set'; SImagingGraphicName = 'Imaging Graphic AllInOne'; { Registers types to VCL/LCL.} procedure RegisterTypes; var I: LongInt; procedure RegisterFileFormatAllInOne(Format: TImageFileFormat); var I: LongInt; begin for I := 0 to Format.Extensions.Count - 1 do TPicture.RegisterFileFormat(Format.Extensions[I], SImagingGraphicName, TImagingGraphic); end; procedure RegisterFileFormat(AClass: TImagingGraphicForSaveClass); var I: LongInt; begin for I := 0 to AClass.GetFileFormat.Extensions.Count - 1 do TPicture.RegisterFileFormat(AClass.GetFileFormat.Extensions[I], AClass.GetFileFormat.Name, AClass); end; begin for I := Imaging.GetFileFormatCount - 1 downto 0 do RegisterFileFormatAllInOne(Imaging.GetFileFormatAtIndex(I)); Classes.RegisterClass(TImagingGraphic); {$IFNDEF DONT_LINK_TARGA} RegisterFileFormat(TImagingTarga); Classes.RegisterClass(TImagingTarga); {$ENDIF} {$IFNDEF DONT_LINK_DDS} RegisterFileFormat(TImagingDDS); Classes.RegisterClass(TImagingDDS); {$ENDIF} {$IFNDEF DONT_LINK_JNG} RegisterFileFormat(TImagingJNG); Classes.RegisterClass(TImagingJNG); {$ENDIF} {$IFNDEF DONT_LINK_MNG} RegisterFileFormat(TImagingMNG); Classes.RegisterClass(TImagingMNG); {$ENDIF} {$IFNDEF DONT_LINK_GIF} RegisterFileFormat(TImagingGIF); Classes.RegisterClass(TImagingGIF); {$ENDIF} {$IFNDEF DONT_LINK_PNG} {$IFDEF COMPONENT_SET_LCL} // Unregister Lazarus default PNG loader which crashes on some PNG files TPicture.UnregisterGraphicClass(TPortableNetworkGraphic); {$ENDIF} RegisterFileFormat(TImagingPNG); Classes.RegisterClass(TImagingPNG); {$ENDIF} {$IFNDEF DONT_LINK_JPEG} RegisterFileFormat(TImagingJpeg); Classes.RegisterClass(TImagingJpeg); {$ENDIF} {$IFNDEF DONT_LINK_BITMAP} RegisterFileFormat(TImagingBitmap); Classes.RegisterClass(TImagingBitmap); {$ENDIF} end; { Unregisters types from VCL/LCL.} procedure UnRegisterTypes; begin {$IFNDEF DONT_LINK_BITMAP} TPicture.UnregisterGraphicClass(TImagingBitmap); Classes.UnRegisterClass(TImagingBitmap); {$ENDIF} {$IFNDEF DONT_LINK_JPEG} TPicture.UnregisterGraphicClass(TImagingJpeg); Classes.UnRegisterClass(TImagingJpeg); {$ENDIF} {$IFNDEF DONT_LINK_PNG} TPicture.UnregisterGraphicClass(TImagingPNG); Classes.UnRegisterClass(TImagingPNG); {$ENDIF} {$IFNDEF DONT_LINK_GIF} TPicture.UnregisterGraphicClass(TImagingGIF); Classes.UnRegisterClass(TImagingGIF); {$ENDIF} {$IFNDEF DONT_LINK_TARGA} TPicture.UnregisterGraphicClass(TImagingTarga); Classes.UnRegisterClass(TImagingTarga); {$ENDIF} {$IFNDEF DONT_LINK_DDS} TPicture.UnregisterGraphicClass(TImagingDDS); Classes.UnRegisterClass(TImagingDDS); {$ENDIF} TPicture.UnregisterGraphicClass(TImagingGraphic); Classes.UnRegisterClass(TImagingGraphic); end; function DataFormatToPixelFormat(Format: TImageFormat): TPixelFormat; begin case Format of {$IFDEF COMPONENT_SET_VCL} ifIndex8: Result := pf8bit; ifR5G6B5: Result := pf16bit; ifR8G8B8: Result := pf24bit; {$ENDIF} ifA8R8G8B8, ifX8R8G8B8: Result := pf32bit; else Result := pfCustom; end; end; function PixelFormatToDataFormat(Format: TPixelFormat): TImageFormat; begin case Format of pf8bit: Result := ifIndex8; pf15bit: Result := ifA1R5G5B5; pf16bit: Result := ifR5G6B5; pf24bit: Result := ifR8G8B8; pf32bit: Result := ifA8R8G8B8; else Result := ifUnknown; end; end; procedure ConvertDataToBitmap(const Data: TImageData; Bitmap: TBitmap); var I, LineBytes: LongInt; PF: TPixelFormat; Info: TImageFormatInfo; WorkData: TImageData; {$IFDEF COMPONENT_SET_VCL} LogPalette: TMaxLogPalette; {$ENDIF} {$IFDEF COMPONENT_SET_LCL} RawImage: TRawImage; ImgHandle, ImgMaskHandle: HBitmap; {$ENDIF} begin PF := DataFormatToPixelFormat(Data.Format); GetImageFormatInfo(Data.Format, Info); if (PF = pf8bit) and PaletteHasAlpha(Data.Palette, Info.PaletteEntries) then begin // Some indexed images may have valid alpha data, dont lose it! // (e.g. transparent 8bit PNG or GIF images) PF := pfCustom; end; if PF = pfCustom then begin // Convert from formats not supported by Graphics unit Imaging.InitImage(WorkData); Imaging.CloneImage(Data, WorkData); if Info.IsFloatingPoint or Info.HasAlphaChannel or Info.IsSpecial then Imaging.ConvertImage(WorkData, ifA8R8G8B8) else begin {$IFDEF COMPONENT_SET_VCL} if Info.IsIndexed or Info.HasGrayChannel then Imaging.ConvertImage(WorkData, ifIndex8) else if Info.UsePixelFormat then Imaging.ConvertImage(WorkData, ifR5G6B5) else Imaging.ConvertImage(WorkData, ifR8G8B8); {$ELSE} Imaging.ConvertImage(WorkData, ifA8R8G8B8); {$ENDIF} end; PF := DataFormatToPixelFormat(WorkData.Format); GetImageFormatInfo(WorkData.Format, Info); end else WorkData := Data; if PF = pfCustom then RaiseImaging(SBadFormatDataToBitmap, [ImageToStr(WorkData)]); LineBytes := WorkData.Width * Info.BytesPerPixel; {$IFDEF COMPONENT_SET_VCL} Bitmap.Width := WorkData.Width; Bitmap.Height := WorkData.Height; Bitmap.PixelFormat := PF; if (PF = pf8bit) and (WorkData.Palette <> nil) then begin // Copy palette, this must be done before copying bits FillChar(LogPalette, SizeOf(LogPalette), 0); LogPalette.palVersion := $300; LogPalette.palNumEntries := Info.PaletteEntries; for I := 0 to Info.PaletteEntries - 1 do with LogPalette do begin palPalEntry[I].peRed := WorkData.Palette[I].R; palPalEntry[I].peGreen := WorkData.Palette[I].G; palPalEntry[I].peBlue := WorkData.Palette[I].B; end; Bitmap.Palette := CreatePalette(PLogPalette(@LogPalette)^); end; // Copy scanlines for I := 0 to WorkData.Height - 1 do Move(PByteArray(WorkData.Bits)[I * LineBytes], Bitmap.Scanline[I]^, LineBytes); // Delphi 2009 and newer support alpha transparency fro TBitmap {$IF Defined(DELPHI) and (CompilerVersion >= 20.0)} if Bitmap.PixelFormat = pf32bit then Bitmap.AlphaFormat := afDefined; {$IFEND} {$ENDIF} {$IFDEF COMPONENT_SET_LCL} // Create 32bit raw image from image data FillChar(RawImage, SizeOf(RawImage), 0); with RawImage.Description do begin Width := WorkData.Width; Height := WorkData.Height; BitsPerPixel := 32; Format := ricfRGBA; LineEnd := rileDWordBoundary; BitOrder := riboBitsInOrder; ByteOrder := riboLSBFirst; LineOrder := riloTopToBottom; AlphaPrec := 8; RedPrec := 8; GreenPrec := 8; BluePrec := 8; AlphaShift := 24; RedShift := 16; GreenShift := 8; BlueShift := 0; Depth := 32; // Must be 32 for alpha blending (and for working in MacOSX Carbon) end; RawImage.Data := WorkData.Bits; RawImage.DataSize := WorkData.Size; // Create bitmap from raw image if RawImage_CreateBitmaps(RawImage, ImgHandle, ImgMaskHandle) then begin Bitmap.Handle := ImgHandle; Bitmap.MaskHandle := ImgMaskHandle; end; {$ENDIF} if WorkData.Bits <> Data.Bits then Imaging.FreeImage(WorkData); end; procedure ConvertBitmapToData(Bitmap: TBitmap; var Data: TImageData); var I, LineBytes: LongInt; Format: TImageFormat; Info: TImageFormatInfo; {$IFDEF COMPONENT_SET_VCL} Colors: Word; LogPalette: TMaxLogPalette; {$ENDIF} {$IFDEF COMPONENT_SET_LCL} RawImage: TRawImage; LineLazBytes: LongInt; {$ENDIF} begin {$IFDEF COMPONENT_SET_LCL} // In the current Lazarus 0.9.10 Bitmap.PixelFormat property is useless. // We cannot change bitmap's format by changing it (it will just release // old image but not convert it to new format) nor we can determine bitmaps's // current format (it is usually set to pfDevice). So bitmap's format is obtained // trough RawImage api and cannot be changed to mirror some Imaging format // (so formats with no coresponding Imaging format cannot be saved now). if RawImage_DescriptionFromBitmap(Bitmap.Handle, RawImage.Description) then case RawImage.Description.BitsPerPixel of 8: Format := ifIndex8; 16: if RawImage.Description.Depth = 15 then Format := ifA1R5G5B5 else Format := ifR5G6B5; 24: Format := ifR8G8B8; 32: Format := ifA8R8G8B8; 48: Format := ifR16G16B16; 64: Format := ifA16R16G16B16; else Format := ifUnknown; end; {$ELSE} Format := PixelFormatToDataFormat(Bitmap.PixelFormat); if Format = ifUnknown then begin // Convert from formats not supported by Imaging (1/4 bit) if Bitmap.PixelFormat < pf8bit then Bitmap.PixelFormat := pf8bit else Bitmap.PixelFormat := pf32bit; Format := PixelFormatToDataFormat(Bitmap.PixelFormat); end; {$ENDIF} if Format = ifUnknown then RaiseImaging(SBadFormatBitmapToData, []); Imaging.NewImage(Bitmap.Width, Bitmap.Height, Format, Data); GetImageFormatInfo(Data.Format, Info); LineBytes := Data.Width * Info.BytesPerPixel; {$IFDEF COMPONENT_SET_VCL} if (Format = ifIndex8) and (GetObject(Bitmap.Palette, SizeOf(Colors), @Colors) <> 0) then begin // Copy palette GetPaletteEntries(Bitmap.Palette, 0, Colors, LogPalette.palPalEntry); if Colors > Info.PaletteEntries then Colors := Info.PaletteEntries; for I := 0 to Colors - 1 do with LogPalette do begin Data.Palette[I].A := $FF; Data.Palette[I].R := palPalEntry[I].peRed; Data.Palette[I].G := palPalEntry[I].peGreen; Data.Palette[I].B := palPalEntry[I].peBlue; end; end; // Copy scanlines for I := 0 to Data.Height - 1 do Move(Bitmap.ScanLine[I]^, PByteArray(Data.Bits)[I * LineBytes], LineBytes); {$ENDIF} {$IFDEF COMPONENT_SET_LCL} // Get raw image from bitmap (mask handle must be 0 or expect violations) if RawImage_FromBitmap(RawImage, Bitmap.Handle, 0, nil) then begin LineLazBytes := GetBytesPerLine(Data.Width, RawImage.Description.BitsPerPixel, RawImage.Description.LineEnd); // Copy scanlines for I := 0 to Data.Height - 1 do begin Move(PByteArray(RawImage.Data)[I * LineLazBytes], PByteArray(Data.Bits)[I * LineBytes], LineBytes); end; // May need to swap RB order, depends on wifget set if RawImage.Description.BlueShift > RawImage.Description.RedShift then SwapChannels(Data, ChannelRed, ChannelBlue); RawImage.FreeData; end; {$ENDIF} end; procedure ConvertImageToBitmap(Image: TBaseImage; Bitmap: TBitmap); begin ConvertDataToBitmap(Image.ImageDataPointer^, Bitmap); end; procedure ConvertBitmapToImage(Bitmap: TBitmap; Image: TBaseImage); begin ConvertBitmapToData(Bitmap, Image.ImageDataPointer^); end; {$IFDEF MSWINDOWS} procedure DisplayImageDataOnDC(DC: HDC; const DstRect: TRect; const ImageData: TImageData; const SrcRect: TRect); var OldMode: Integer; BitmapInfo: Windows.TBitmapInfo; Bmp: TBitmap; begin if TestImage(ImageData) then begin Assert(ImageData.Format in [ifA8R8G8B8, ifX8R8G8B8], SBadFormatDisplay); OldMode := Windows.SetStretchBltMode(DC, COLORONCOLOR); FillChar(BitmapInfo, SizeOf(BitmapInfo), 0); with BitmapInfo.bmiHeader do begin biSize := SizeOf(TBitmapInfoHeader); biPlanes := 1; biBitCount := 32; biCompression := BI_RGB; biWidth := ImageData.Width; biHeight := -ImageData.Height; biSizeImage := ImageData.Size; biXPelsPerMeter := 0; biYPelsPerMeter := 0; biClrUsed := 0; biClrImportant := 0; end; try with SrcRect, ImageData do if Windows.StretchDIBits(DC, DstRect.Left, DstRect.Top, DstRect.Right - DstRect.Left, DstRect.Bottom - DstRect.Top, Left, Top, Right - Left, Bottom - Top, Bits, BitmapInfo, DIB_RGB_COLORS, SRCCOPY) <> Height then begin // StretchDIBits may fail on some ocassions (error 487, http://support.microsoft.com/kb/269585). // This fallback is slow but works every time. Thanks to Sergey Galezdinov for the fix. Bmp := TBitmap.Create; try ConvertDataToBitmap(ImageData, Bmp); StretchBlt(DC, DstRect.Left, DstRect.Top, DstRect.Right - DstRect.Left, DstRect.Bottom - DstRect.Top, Bmp.Canvas.Handle, 0, 0, Width, Height, SRCCOPY); finally Bmp.Free; end; end; finally Windows.SetStretchBltMode(DC, OldMode); end; end; end; {$ENDIF} procedure DisplayImageData(DstCanvas: TCanvas; const DstRect: TRect; const ImageData: TImageData; const SrcRect: TRect); {$IF Defined(DCC) or Defined(LCLWIN32)} // Delphi or LCL Win32 begin DisplayImageDataOnDC(DstCanvas.Handle, DstRect, ImageData, SrcRect); end; {$ELSEIF Defined(LCLGTK2)} type TDeviceContext = TGtk2DeviceContext; procedure GDKDrawBitmap(Dest: HDC; DstX, DstY: Integer; SrcX, SrcY, SrcWidth, SrcHeight: Integer; ImageData: TImageData); var P: TPoint; begin P := TDeviceContext(Dest).Offset; Inc(DstX, P.X); Inc(DstY, P.Y); gdk_draw_rgb_32_image(TDeviceContext(Dest).Drawable, TDeviceContext(Dest).GC, DstX, DstY, SrcWidth, SrcHeight, GDK_RGB_DITHER_NONE, @PLongWordArray(ImageData.Bits)[SrcY * ImageData.Width + SrcX], ImageData.Width * 4); end; var DisplayImage: TImageData; NewWidth, NewHeight: Integer; SrcBounds, DstBounds, DstClip: TRect; begin if TestImage(ImageData) then begin Assert(ImageData.Format in [ifA8R8G8B8, ifX8R8G8B8], SBadFormatDisplay); InitImage(DisplayImage); SrcBounds := RectToBounds(SrcRect); DstBounds := RectToBounds(DstRect); WidgetSet.GetClipBox(DstCanvas.Handle, @DstClip); ClipStretchBounds(SrcBounds.Left, SrcBounds.Top, SrcBounds.Right, SrcBounds.Bottom, DstBounds.Left, DstBounds.Top, DstBounds.Right, DstBounds.Bottom, ImageData.Width, ImageData.Height, DstClip); NewWidth := DstBounds.Right; NewHeight := DstBounds.Bottom; if (NewWidth > 0) and (NewHeight > 0) then begin if (SrcBounds.Right = NewWidth) and (SrcBounds.Bottom = NewHeight) then try CloneImage(ImageData, DisplayImage); // Swap R-B channels for GTK display compatability! SwapChannels(DisplayImage, ChannelRed, ChannelBlue); GDKDrawBitmap(DstCanvas.Handle, DstBounds.Left, DstBounds.Top, SrcBounds.Left, SrcBounds.Top, NewWidth, NewHeight, DisplayImage); finally FreeImage(DisplayImage); end else try // Create new image with desired dimensions NewImage(NewWidth, NewHeight, ImageData.Format, DisplayImage); // Stretch pixels from old image to new one TResizeFilter = (rfNearest, rfBilinear, rfBicubic); StretchRect(ImageData, SrcBounds.Left, SrcBounds.Top, SrcBounds.Right, SrcBounds.Bottom, DisplayImage, 0, 0, NewWidth, NewHeight, rfNearest); // Swap R-B channels for GTK display compatability! SwapChannels(DisplayImage, ChannelRed, ChannelBlue); GDKDrawBitmap(DstCanvas.Handle, DstBounds.Left, DstBounds.Top, 0, 0, NewWidth, NewHeight, DisplayImage); finally FreeImage(DisplayImage); end end; end; end; {$ELSE} begin raise Exception.Create(SUnsupportedLCLWidgetSet); end; {$IFEND} procedure DisplayImage(DstCanvas: TCanvas; DstX, DstY: LongInt; Image: TBaseImage); begin DisplayImageData(DstCanvas, BoundsToRect(DstX, DstY, Image.Width, Image.Height), Image.ImageDataPointer^, Image.BoundsRect); end; procedure DisplayImage(DstCanvas: TCanvas; const DstRect: TRect; Image: TBaseImage); begin DisplayImageData(DstCanvas, DstRect, Image.ImageDataPointer^, Image.BoundsRect); end; procedure DisplayImage(DstCanvas: TCanvas; const DstRect: TRect; Image: TBaseImage; const SrcRect: TRect); begin DisplayImageData(DstCanvas, DstRect, Image.ImageDataPointer^, SrcRect); end; { TImagingGraphic class implementation } constructor TImagingGraphic.Create; begin inherited Create; PixelFormat := pf24Bit; end; procedure TImagingGraphic.LoadFromStream(Stream: TStream); begin ReadDataFromStream(Stream); end; procedure TImagingGraphic.ReadDataFromStream(Stream: TStream); var Image: TSingleImage; begin Image := TSingleImage.Create; try Image.LoadFromStream(Stream); Assign(Image); finally Image.Free; end; end; procedure TImagingGraphic.AssignTo(Dest: TPersistent); var Arr: TDynImageDataArray; begin if Dest is TSingleImage then begin AssignToImage(TSingleImage(Dest)) end else if Dest is TMultiImage then begin SetLength(Arr, 1); AssignToImageData(Arr[0]); TMultiImage(Dest).CreateFromArray(Arr); Imaging.FreeImagesInArray(Arr); end else inherited AssignTo(Dest); end; procedure TImagingGraphic.Assign(Source: TPersistent); begin if Source is TBaseImage then AssignFromImage(TBaseImage(Source)) else inherited Assign(Source); end; procedure TImagingGraphic.AssignFromImage(Image: TBaseImage); begin if (Image <> nil) and Image.Valid then AssignFromImageData(Image.ImageDataPointer^); end; procedure TImagingGraphic.AssignToImage(Image: TBaseImage); begin if (Image <> nil) and (Image.ImageDataPointer <> nil) then AssignToImageData(Image.ImageDataPointer^); end; procedure TImagingGraphic.AssignFromImageData(const ImageData: TImageData); begin if Imaging.TestImage(ImageData) then ConvertDataToBitmap(ImageData, Self); end; procedure TImagingGraphic.AssignToImageData(var ImageData: TImageData); begin Imaging.FreeImage(ImageData); ConvertBitmapToData(Self, ImageData); end; { TImagingGraphicForSave class implementation } constructor TImagingGraphicForSave.Create; begin inherited Create; FDefaultFileExt := GetFileFormat.Extensions[0]; FSavingFormat := ifUnknown; GetFileFormat.CheckOptionsValidity; end; procedure TImagingGraphicForSave.WriteDataToStream(Stream: TStream); var Image: TSingleImage; begin if FDefaultFileExt <> '' then begin Image := TSingleImage.Create; try Image.Assign(Self); if FSavingFormat <> ifUnknown then Image.Format := FSavingFormat; Image.SaveToStream(FDefaultFileExt, Stream); finally Image.Free; end; end; end; procedure TImagingGraphicForSave.SaveToStream(Stream: TStream); begin WriteDataToStream(Stream); end; {$IFDEF COMPONENT_SET_LCL} class function TImagingGraphicForSave.GetFileExtensions: string; begin Result := StringReplace(GetFileFormat.Extensions.CommaText, ',', ';', [rfReplaceAll]); end; function TImagingGraphicForSave.GetMimeType: string; begin Result := 'image/' + FDefaultFileExt; end; {$ENDIF} {$IFNDEF DONT_LINK_BITMAP} { TImagingBitmap class implementation } constructor TImagingBitmap.Create; begin inherited Create; FUseRLE := (GetFileFormat as TBitmapFileFormat).UseRLE; end; class function TImagingBitmap.GetFileFormat: TImageFileFormat; begin Result := FindImageFileFormatByClass(TBitmapFileFormat); end; procedure TImagingBitmap.SaveToStream(Stream: TStream); begin Imaging.PushOptions; Imaging.SetOption(ImagingBitmapRLE, Ord(FUseRLE)); inherited SaveToStream(Stream); Imaging.PopOptions; end; {$ENDIF} {$IFNDEF DONT_LINK_JPEG} { TImagingJpeg class implementation } constructor TImagingJpeg.Create; begin inherited Create; FQuality := (GetFileFormat as TJpegFileFormat).Quality; FProgressive := (GetFileFormat as TJpegFileFormat).Progressive; end; class function TImagingJpeg.GetFileFormat: TImageFileFormat; begin Result := FindImageFileFormatByClass(TJpegFileFormat); end; {$IFDEF COMPONENT_SET_LCL} function TImagingJpeg.GetMimeType: string; begin Result := 'image/jpeg'; end; {$ENDIF} procedure TImagingJpeg.SaveToStream(Stream: TStream); begin Imaging.PushOptions; Imaging.SetOption(ImagingJpegQuality, FQuality); Imaging.SetOption(ImagingJpegProgressive, Ord(FProgressive)); inherited SaveToStream(Stream); Imaging.PopOptions; end; {$ENDIF} {$IFNDEF DONT_LINK_PNG} { TImagingPNG class implementation } constructor TImagingPNG.Create; begin inherited Create; FPreFilter := (GetFileFormat as TPNGFileFormat).PreFilter; FCompressLevel := (GetFileFormat as TPNGFileFormat).CompressLevel; end; class function TImagingPNG.GetFileFormat: TImageFileFormat; begin Result := FindImageFileFormatByClass(TPNGFileFormat); end; procedure TImagingPNG.SaveToStream(Stream: TStream); begin Imaging.PushOptions; Imaging.SetOption(ImagingPNGPreFilter, FPreFilter); Imaging.SetOption(ImagingPNGCompressLevel, FCompressLevel); inherited SaveToStream(Stream); Imaging.PopOptions; end; {$ENDIF} {$IFNDEF DONT_LINK_GIF} { TImagingGIF class implementation} class function TImagingGIF.GetFileFormat: TImageFileFormat; begin Result := FindImageFileFormatByClass(TGIFFileFormat); end; {$ENDIF} {$IFNDEF DONT_LINK_TARGA} { TImagingTarga class implementation } constructor TImagingTarga.Create; begin inherited Create; FUseRLE := (GetFileFormat as TTargaFileFormat).UseRLE; end; class function TImagingTarga.GetFileFormat: TImageFileFormat; begin Result := FindImageFileFormatByClass(TTargaFileFormat); end; procedure TImagingTarga.SaveToStream(Stream: TStream); begin Imaging.PushOptions; Imaging.SetOption(ImagingTargaRLE, Ord(FUseRLE)); inherited SaveToStream(Stream); Imaging.PopOptions; end; {$ENDIF} {$IFNDEF DONT_LINK_DDS} { TImagingDDS class implementation } constructor TImagingDDS.Create; begin inherited Create; FCompression := dcNone; end; class function TImagingDDS.GetFileFormat: TImageFileFormat; begin Result := FindImageFileFormatByClass(TDDSFileFormat); end; procedure TImagingDDS.SaveToStream(Stream: TStream); begin case FCompression of dcNone: FSavingFormat := ifUnknown; dcDXT1: FSavingFormat := ifDXT1; dcDXT3: FSavingFormat := ifDXT3; dcDXT5: FSavingFormat := ifDXT5; end; Imaging.PushOptions; Imaging.SetOption(ImagingDDSSaveCubeMap, Ord(False)); Imaging.SetOption(ImagingDDSSaveVolume, Ord(False)); Imaging.SetOption(ImagingDDSSaveMipMapCount, 1); Imaging.SetOption(ImagingDDSSaveDepth, 1); inherited SaveToStream(Stream); Imaging.PopOptions; end; {$ENDIF} {$IFNDEF DONT_LINK_MNG} { TImagingMNG class implementation } constructor TImagingMNG.Create; begin inherited Create; FLossyCompression := (GetFileFormat as TMNGFileFormat).LossyCompression; FLossyAlpha := (GetFileFormat as TMNGFileFormat).LossyAlpha; FPreFilter := (GetFileFormat as TMNGFileFormat).PreFilter; FCompressLevel := (GetFileFormat as TMNGFileFormat).CompressLevel; FQuality := (GetFileFormat as TMNGFileFormat).Quality; FProgressive := (GetFileFormat as TMNGFileFormat).Progressive; end; class function TImagingMNG.GetFileFormat: TImageFileFormat; begin Result := FindImageFileFormatByClass(TMNGFileFormat); end; {$IFDEF COMPONENT_SET_LCL} function TImagingMNG.GetMimeType: string; begin Result := 'video/mng'; end; {$ENDIF} procedure TImagingMNG.SaveToStream(Stream: TStream); begin Imaging.PushOptions; Imaging.SetOption(ImagingMNGLossyCompression, Ord(FLossyCompression)); Imaging.SetOption(ImagingMNGLossyAlpha, Ord(FLossyAlpha)); Imaging.SetOption(ImagingMNGPreFilter, FPreFilter); Imaging.SetOption(ImagingMNGCompressLevel, FCompressLevel); Imaging.SetOption(ImagingMNGQuality, FQuality); Imaging.SetOption(ImagingMNGProgressive, Ord(FProgressive)); inherited SaveToStream(Stream); Imaging.PopOptions; end; {$ENDIF} {$IFNDEF DONT_LINK_JNG} { TImagingJNG class implementation } constructor TImagingJNG.Create; begin inherited Create; FLossyAlpha := (GetFileFormat as TJNGFileFormat).LossyAlpha; FAlphaPreFilter := (GetFileFormat as TJNGFileFormat).PreFilter; FAlphaCompressLevel := (GetFileFormat as TJNGFileFormat).CompressLevel; FQuality := (GetFileFormat as TJNGFileFormat).Quality; FProgressive := (GetFileFormat as TJNGFileFormat).Progressive; end; class function TImagingJNG.GetFileFormat: TImageFileFormat; begin Result := FindImageFileFormatByClass(TJNGFileFormat); end; procedure TImagingJNG.SaveToStream(Stream: TStream); begin Imaging.PushOptions; Imaging.SetOption(ImagingJNGLossyALpha, Ord(FLossyAlpha)); Imaging.SetOption(ImagingJNGAlphaPreFilter, FAlphaPreFilter); Imaging.SetOption(ImagingJNGAlphaCompressLevel, FAlphaCompressLevel); Imaging.SetOption(ImagingJNGQuality, FQuality); Imaging.SetOption(ImagingJNGProgressive, Ord(FProgressive)); inherited SaveToStream(Stream); Imaging.PopOptions; end; {$ENDIF} initialization RegisterTypes; finalization UnRegisterTypes; {$IFEND} // {$IF not Defined(COMPONENT_SET_LCL) and not Defined(COMPONENT_SET_VCL)} { File Notes: -- TODOS ---------------------------------------------------- - nothing now -- 0.77.1 --------------------------------------------------- - Fixed bug in ConvertBitmapToData causing images from GTK2 bitmaps to have swapped RB channels. - LCL: Removed GTK1 support (deprecated). -- 0.26.3 Changes/Bug Fixes --------------------------------- - Transparency of 8bit images (like loaded from 8bit PNG or GIF) is kept intact during conversion to TBitmap in ConvertDataToBitmap (32bit bitmap is created). -- 0.26.3 Changes/Bug Fixes --------------------------------- - Setting AlphaFormat property of TBitmap in ConvertDataToBitmap when using Delphi 2009+. - Fixed garbled LCL TBitmaps created by ConvertDataToBitmap in Mac OS X (Carbon). -- 0.26.1 Changes/Bug Fixes --------------------------------- - Added some more IFDEFs for Lazarus widget sets. - Removed CLX code. - GTK version of Unix DisplayImageData only used with LCL GTK so the the rest of the unit can be used with Qt or other LCL interfaces. - Fallback mechanism for DisplayImageDataOnDC, it may fail on occasions. - Changed file format conditional compilation to reflect changes in LINK symbols. - Lazarus 0.9.26 compatibility changes. -- 0.24.1 Changes/Bug Fixes --------------------------------- - Fixed wrong IFDEF causing that Imaging wouldn't compile in Lazarus with GTK2 target. - Added commnets with code for Lazarus rev. 11861+ regarding RawImage interface. Replace current code with that in comments if you use Lazarus from SVN. New RawImage interface will be used by default after next Lazarus release. -- 0.23 Changes/Bug Fixes ----------------------------------- - Added TImagingGIF. -- 0.21 Changes/Bug Fixes ----------------------------------- - Uses only high level interface now (except for saving options). - Slightly changed class hierarchy. TImagingGraphic is now only for loading and base class for savers is new TImagingGraphicForSave. Also TImagingGraphic is now registered with all supported file formats by TPicture's format support. -- 0.19 Changes/Bug Fixes ----------------------------------- - added DisplayImage procedures (thanks to Paul Michell, modified) - removed RegisterTypes and UnRegisterTypes from interface section, they are called automatically - added procedures: ConvertImageToBitmap and ConvertBitmapToImage -- 0.17 Changes/Bug Fixes ----------------------------------- - LCL data to bitmap conversion didnt work in Linux, fixed - added MNG file format - added JNG file format -- 0.15 Changes/Bug Fixes ----------------------------------- - made it LCL compatible - made it CLX compatible - added all initial stuff } end. ================================================ FILE: lib/Imaging/ImagingDds.pas ================================================ { Vampyre Imaging Library by Marek Mauder http://imaginglib.sourceforge.net The contents of this file are used with permission, subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/MPL-1.1.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Alternatively, the contents of this file may be used under the terms of the GNU Lesser General Public License (the "LGPL License"), in which case the provisions of the LGPL License are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of the LGPL License and not to allow others to use your version of this file under the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the LGPL License. If you do not delete the provisions above, a recipient may use your version of this file under either the MPL or the LGPL License. For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html } { This unit contains image format loader/saver for DirectDraw Surface images.} unit ImagingDds; {$I ImagingOptions.inc} interface uses ImagingTypes, Imaging, ImagingUtility, ImagingFormats; type { Class for loading and saving Microsoft DirectDraw surfaces. It can load/save all D3D formats which have coresponding TImageFormat. It supports plain textures, cube textures and volume textures, all of these can have mipmaps. It can also load some formats which have no exact TImageFormat, but can be easily converted to one (bump map formats, etc.). You can get some information about last loaded DDS file by calling GetOption with ImagingDDSLoadedXXX options and you can set some saving options by calling SetOption with ImagingDDSSaveXXX or you can simply use properties of this class. Note that when saving cube maps and volumes input image array must contain at least number of images to build cube/volume based on current Depth and MipMapCount settings.} TDDSFileFormat = class(TImageFileFormat) private FLoadedCubeMap: LongBool; FLoadedVolume: LongBool; FLoadedMipMapCount: LongInt; FLoadedDepth: LongInt; FSaveCubeMap: LongBool; FSaveVolume: LongBool; FSaveMipMapCount: LongInt; FSaveDepth: LongInt; procedure ComputeSubDimensions(Idx, Width, Height, MipMaps, Depth: LongInt; IsCubeMap, IsVolume: Boolean; var CurWidth, CurHeight: LongInt); protected procedure Define; override; function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; override; function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray; Index: LongInt): Boolean; override; procedure ConvertToSupported(var Image: TImageData; const Info: TImageFormatInfo); override; public function TestFormat(Handle: TImagingHandle): Boolean; override; procedure CheckOptionsValidity; override; published { True if last loaded DDS file was cube map.} property LoadedCubeMap: LongBool read FLoadedCubeMap write FLoadedCubeMap; { True if last loaded DDS file was volume texture.} property LoadedVolume: LongBool read FLoadedVolume write FLoadedVolume; { Number of mipmap levels of last loaded DDS image.} property LoadedMipMapCount: LongInt read FLoadedMipMapCount write FLoadedMipMapCount; { Depth (slices of volume texture or faces of cube map) of last loaded DDS image.} property LoadedDepth: LongInt read FLoadedDepth write FLoadedDepth; { True if next DDS file to be saved should be stored as cube map.} property SaveCubeMap: LongBool read FSaveCubeMap write FSaveCubeMap; { True if next DDS file to be saved should be stored as volume texture.} property SaveVolume: LongBool read FSaveVolume write FSaveVolume; { Sets the number of mipmaps which should be stored in the next saved DDS file. Only applies to cube maps and volumes, ordinary 2D textures save all levels present in input.} property SaveMipMapCount: LongInt read FSaveMipMapCount write FSaveMipMapCount; { Sets the depth (slices of volume texture or faces of cube map) of the next saved DDS file.} property SaveDepth: LongInt read FSaveDepth write FSaveDepth; end; const { DDS related metadata Ids } { DXGI format of textures stored in DDS files with DX10 extension. Type is Enum (value corresponding to DXGI_FORMAT enum from DX SDK).} SMetaDdsDxgiFormat = 'DdsDxgiFormat'; { Number of mipmaps for each main image in DDS file.} SMetaDdsMipMapCount = 'DdsMipMapCount'; { Texture array size stored in DDS file (DX10 extension).} SMetaDdsArraySize = 'DdsArraySize'; const SDDSFormatName = 'DirectDraw Surface'; SDDSMasks = '*.dds'; DDSSupportedFormats: TImageFormats = [ifR8G8B8, ifA8R8G8B8, ifX8R8G8B8, ifA1R5G5B5, ifA4R4G4B4, ifX1R5G5B5, ifX4R4G4B4, ifR5G6B5, ifA16B16G16R16, ifR32F, ifA32B32G32R32F, ifR16F, ifA16B16G16R16F, ifR3G3B2, ifGray8, ifA8Gray8, ifGray16, ifDXT1, ifDXT3, ifDXT5, ifATI1N, ifATI2N]; const { Four character codes.} DDSMagic = LongWord(Byte('D') or (Byte('D') shl 8) or (Byte('S') shl 16) or (Byte(' ') shl 24)); FOURCC_DXT1 = LongWord(Byte('D') or (Byte('X') shl 8) or (Byte('T') shl 16) or (Byte('1') shl 24)); FOURCC_DXT3 = LongWord(Byte('D') or (Byte('X') shl 8) or (Byte('T') shl 16) or (Byte('3') shl 24)); FOURCC_DXT5 = LongWord(Byte('D') or (Byte('X') shl 8) or (Byte('T') shl 16) or (Byte('5') shl 24)); FOURCC_ATI1 = LongWord(Byte('A') or (Byte('T') shl 8) or (Byte('I') shl 16) or (Byte('1') shl 24)); FOURCC_ATI2 = LongWord(Byte('A') or (Byte('T') shl 8) or (Byte('I') shl 16) or (Byte('2') shl 24)); FOURCC_DX10 = LongWord(Byte('D') or (Byte('X') shl 8) or (Byte('1') shl 16) or (Byte('0') shl 24)); { Some D3DFORMAT values used in DDS files as FourCC value.} D3DFMT_A16B16G16R16 = 36; D3DFMT_R32F = 114; D3DFMT_A32B32G32R32F = 116; D3DFMT_R16F = 111; D3DFMT_A16B16G16R16F = 113; { Constans used by TDDSurfaceDesc2.Flags.} DDSD_CAPS = $00000001; DDSD_HEIGHT = $00000002; DDSD_WIDTH = $00000004; DDSD_PITCH = $00000008; DDSD_PIXELFORMAT = $00001000; DDSD_MIPMAPCOUNT = $00020000; DDSD_LINEARSIZE = $00080000; DDSD_DEPTH = $00800000; { Constans used by TDDSPixelFormat.Flags.} DDPF_ALPHAPIXELS = $00000001; // used by formats which contain alpha DDPF_FOURCC = $00000004; // used by DXT and large ARGB formats DDPF_RGB = $00000040; // used by RGB formats DDPF_LUMINANCE = $00020000; // used by formats like D3DFMT_L16 DDPF_BUMPLUMINANCE = $00040000; // used by mixed signed-unsigned formats DDPF_BUMPDUDV = $00080000; // used by signed formats { Constans used by TDDSCaps.Caps1.} DDSCAPS_COMPLEX = $00000008; DDSCAPS_TEXTURE = $00001000; DDSCAPS_MIPMAP = $00400000; { Constans used by TDDSCaps.Caps2.} DDSCAPS2_CUBEMAP = $00000200; DDSCAPS2_POSITIVEX = $00000400; DDSCAPS2_NEGATIVEX = $00000800; DDSCAPS2_POSITIVEY = $00001000; DDSCAPS2_NEGATIVEY = $00002000; DDSCAPS2_POSITIVEZ = $00004000; DDSCAPS2_NEGATIVEZ = $00008000; DDSCAPS2_VOLUME = $00200000; { Flags for TDDSurfaceDesc2.Flags used when saving DDS file.} DDS_SAVE_FLAGS = DDSD_CAPS or DDSD_PIXELFORMAT or DDSD_WIDTH or DDSD_HEIGHT or DDSD_LINEARSIZE; type { Stores the pixel format information.} TDDPixelFormat = packed record Size: LongWord; // Size of the structure = 32 bytes Flags: LongWord; // Flags to indicate valid fields FourCC: LongWord; // Four-char code for compressed textures (DXT) BitCount: LongWord; // Bits per pixel if uncomp. usually 16,24 or 32 RedMask: LongWord; // Bit mask for the Red component GreenMask: LongWord; // Bit mask for the Green component BlueMask: LongWord; // Bit mask for the Blue component AlphaMask: LongWord; // Bit mask for the Alpha component end; { Specifies capabilities of surface.} TDDSCaps = packed record Caps1: LongWord; // Should always include DDSCAPS_TEXTURE Caps2: LongWord; // For cubic environment maps Reserved: array[0..1] of LongWord; // Reserved end; { Record describing DDS file contents.} TDDSurfaceDesc2 = packed record Size: LongWord; // Size of the structure = 124 Bytes Flags: LongWord; // Flags to indicate valid fields Height: LongWord; // Height of the main image in pixels Width: LongWord; // Width of the main image in pixels PitchOrLinearSize: LongWord; // For uncomp formats number of bytes per // scanline. For comp it is the size in // bytes of the main image Depth: LongWord; // Only for volume text depth of the volume MipMaps: LongInt; // Total number of levels in the mipmap chain Reserved1: array[0..10] of LongWord; // Reserved PixelFormat: TDDPixelFormat; // Format of the pixel data Caps: TDDSCaps; // Capabilities Reserved2: LongWord; // Reserved end; { DDS file header.} TDDSFileHeader = packed record Magic: LongWord; // File format magic Desc: TDDSurfaceDesc2; // Surface description end; { Resoirce types for D3D 10+ } TD3D10ResourceDimension = ( D3D10_RESOURCE_DIMENSION_UNKNOWN = 0, D3D10_RESOURCE_DIMENSION_BUFFER = 1, D3D10_RESOURCE_DIMENSION_TEXTURE1D = 2, D3D10_RESOURCE_DIMENSION_TEXTURE2D = 3, D3D10_RESOURCE_DIMENSION_TEXTURE3D = 4 ); { Texture formats for D3D 10+ } TDXGIFormat = ( DXGI_FORMAT_UNKNOWN = 0, DXGI_FORMAT_R32G32B32A32_TYPELESS = 1, DXGI_FORMAT_R32G32B32A32_FLOAT = 2, DXGI_FORMAT_R32G32B32A32_UINT = 3, DXGI_FORMAT_R32G32B32A32_SINT = 4, DXGI_FORMAT_R32G32B32_TYPELESS = 5, DXGI_FORMAT_R32G32B32_FLOAT = 6, DXGI_FORMAT_R32G32B32_UINT = 7, DXGI_FORMAT_R32G32B32_SINT = 8, DXGI_FORMAT_R16G16B16A16_TYPELESS = 9, DXGI_FORMAT_R16G16B16A16_FLOAT = 10, DXGI_FORMAT_R16G16B16A16_UNORM = 11, DXGI_FORMAT_R16G16B16A16_UINT = 12, DXGI_FORMAT_R16G16B16A16_SNORM = 13, DXGI_FORMAT_R16G16B16A16_SINT = 14, DXGI_FORMAT_R32G32_TYPELESS = 15, DXGI_FORMAT_R32G32_FLOAT = 16, DXGI_FORMAT_R32G32_UINT = 17, DXGI_FORMAT_R32G32_SINT = 18, DXGI_FORMAT_R32G8X24_TYPELESS = 19, DXGI_FORMAT_D32_FLOAT_S8X24_UINT = 20, DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS = 21, DXGI_FORMAT_X32_TYPELESS_G8X24_UINT = 22, DXGI_FORMAT_R10G10B10A2_TYPELESS = 23, DXGI_FORMAT_R10G10B10A2_UNORM = 24, DXGI_FORMAT_R10G10B10A2_UINT = 25, DXGI_FORMAT_R11G11B10_FLOAT = 26, DXGI_FORMAT_R8G8B8A8_TYPELESS = 27, DXGI_FORMAT_R8G8B8A8_UNORM = 28, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB = 29, DXGI_FORMAT_R8G8B8A8_UINT = 30, DXGI_FORMAT_R8G8B8A8_SNORM = 31, DXGI_FORMAT_R8G8B8A8_SINT = 32, DXGI_FORMAT_R16G16_TYPELESS = 33, DXGI_FORMAT_R16G16_FLOAT = 34, DXGI_FORMAT_R16G16_UNORM = 35, DXGI_FORMAT_R16G16_UINT = 36, DXGI_FORMAT_R16G16_SNORM = 37, DXGI_FORMAT_R16G16_SINT = 38, DXGI_FORMAT_R32_TYPELESS = 39, DXGI_FORMAT_D32_FLOAT = 40, DXGI_FORMAT_R32_FLOAT = 41, DXGI_FORMAT_R32_UINT = 42, DXGI_FORMAT_R32_SINT = 43, DXGI_FORMAT_R24G8_TYPELESS = 44, DXGI_FORMAT_D24_UNORM_S8_UINT = 45, DXGI_FORMAT_R24_UNORM_X8_TYPELESS = 46, DXGI_FORMAT_X24_TYPELESS_G8_UINT = 47, DXGI_FORMAT_R8G8_TYPELESS = 48, DXGI_FORMAT_R8G8_UNORM = 49, DXGI_FORMAT_R8G8_UINT = 50, DXGI_FORMAT_R8G8_SNORM = 51, DXGI_FORMAT_R8G8_SINT = 52, DXGI_FORMAT_R16_TYPELESS = 53, DXGI_FORMAT_R16_FLOAT = 54, DXGI_FORMAT_D16_UNORM = 55, DXGI_FORMAT_R16_UNORM = 56, DXGI_FORMAT_R16_UINT = 57, DXGI_FORMAT_R16_SNORM = 58, DXGI_FORMAT_R16_SINT = 59, DXGI_FORMAT_R8_TYPELESS = 60, DXGI_FORMAT_R8_UNORM = 61, DXGI_FORMAT_R8_UINT = 62, DXGI_FORMAT_R8_SNORM = 63, DXGI_FORMAT_R8_SINT = 64, DXGI_FORMAT_A8_UNORM = 65, DXGI_FORMAT_R1_UNORM = 66, DXGI_FORMAT_R9G9B9E5_SHAREDEXP = 67, DXGI_FORMAT_R8G8_B8G8_UNORM = 68, DXGI_FORMAT_G8R8_G8B8_UNORM = 69, DXGI_FORMAT_BC1_TYPELESS = 70, DXGI_FORMAT_BC1_UNORM = 71, DXGI_FORMAT_BC1_UNORM_SRGB = 72, DXGI_FORMAT_BC2_TYPELESS = 73, DXGI_FORMAT_BC2_UNORM = 74, DXGI_FORMAT_BC2_UNORM_SRGB = 75, DXGI_FORMAT_BC3_TYPELESS = 76, DXGI_FORMAT_BC3_UNORM = 77, DXGI_FORMAT_BC3_UNORM_SRGB = 78, DXGI_FORMAT_BC4_TYPELESS = 79, DXGI_FORMAT_BC4_UNORM = 80, DXGI_FORMAT_BC4_SNORM = 81, DXGI_FORMAT_BC5_TYPELESS = 82, DXGI_FORMAT_BC5_UNORM = 83, DXGI_FORMAT_BC5_SNORM = 84, DXGI_FORMAT_B5G6R5_UNORM = 85, DXGI_FORMAT_B5G5R5A1_UNORM = 86, DXGI_FORMAT_B8G8R8A8_UNORM = 87, DXGI_FORMAT_B8G8R8X8_UNORM = 88, DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM = 89, DXGI_FORMAT_B8G8R8A8_TYPELESS = 90, DXGI_FORMAT_B8G8R8A8_UNORM_SRGB = 91, DXGI_FORMAT_B8G8R8X8_TYPELESS = 92, DXGI_FORMAT_B8G8R8X8_UNORM_SRGB = 93, DXGI_FORMAT_BC6H_TYPELESS = 94, DXGI_FORMAT_BC6H_UF16 = 95, DXGI_FORMAT_BC6H_SF16 = 96, DXGI_FORMAT_BC7_TYPELESS = 97, DXGI_FORMAT_BC7_UNORM = 98, DXGI_FORMAT_BC7_UNORM_SRGB = 99, DXGI_FORMAT_AYUV = 100, DXGI_FORMAT_Y410 = 101, DXGI_FORMAT_Y416 = 102, DXGI_FORMAT_NV12 = 103, DXGI_FORMAT_P010 = 104, DXGI_FORMAT_P016 = 105, DXGI_FORMAT_420_OPAQUE = 106, DXGI_FORMAT_YUY2 = 107, DXGI_FORMAT_Y210 = 108, DXGI_FORMAT_Y216 = 109, DXGI_FORMAT_NV11 = 110, DXGI_FORMAT_AI44 = 111, DXGI_FORMAT_IA44 = 112, DXGI_FORMAT_P8 = 113, DXGI_FORMAT_A8P8 = 114, DXGI_FORMAT_B4G4R4A4_UNORM = 115 ); { DX10 extension header for DDS file format } TDX10Header = packed record DXGIFormat: TDXGIFormat; ResourceDimension: TD3D10ResourceDimension; MiscFlags: LongWord; ArraySize: LongWord; Reserved: LongWord; end; implementation { TDDSFileFormat class implementation } procedure TDDSFileFormat.Define; begin inherited; FName := SDDSFormatName; FFeatures := [ffLoad, ffSave, ffMultiImage]; FSupportedFormats := DDSSupportedFormats; FSaveCubeMap := False; FSaveVolume := False; FSaveMipMapCount := 1; FSaveDepth := 1; AddMasks(SDDSMasks); RegisterOption(ImagingDDSLoadedCubeMap, @FLoadedCubeMap); RegisterOption(ImagingDDSLoadedVolume, @FLoadedVolume); RegisterOption(ImagingDDSLoadedMipMapCount, @FLoadedMipMapCount); RegisterOption(ImagingDDSLoadedDepth, @FLoadedDepth); RegisterOption(ImagingDDSSaveCubeMap, @FSaveCubeMap); RegisterOption(ImagingDDSSaveVolume, @FSaveVolume); RegisterOption(ImagingDDSSaveMipMapCount, @FSaveMipMapCount); RegisterOption(ImagingDDSSaveDepth, @FSaveDepth); end; procedure TDDSFileFormat.CheckOptionsValidity; begin if FSaveCubeMap then FSaveVolume := False; if FSaveVolume then FSaveCubeMap := False; if FSaveDepth < 1 then FSaveDepth := 1; if FSaveMipMapCount < 1 then FSaveMipMapCount := 1; end; procedure TDDSFileFormat.ComputeSubDimensions(Idx, Width, Height, MipMaps, Depth: LongInt; IsCubeMap, IsVolume: Boolean; var CurWidth, CurHeight: LongInt); var I, Last, Shift: LongInt; begin CurWidth := Width; CurHeight := Height; if MipMaps > 1 then begin if not IsVolume then begin if IsCubeMap then begin // Cube maps are stored like this // Face 0 mimap 0 // Face 0 mipmap 1 // ... // Face 1 mipmap 0 // Face 1 mipmap 1 // ... // Modify index so later in for loop we iterate less times Idx := Idx - ((Idx div MipMaps) * MipMaps); end; for I := 0 to Idx - 1 do begin CurWidth := ClampInt(CurWidth shr 1, 1, CurWidth); CurHeight := ClampInt(CurHeight shr 1, 1, CurHeight); end; end else begin // Volume textures are stored in DDS files like this: // Slice 0 mipmap 0 // Slice 1 mipmap 0 // Slice 2 mipmap 0 // Slice 3 mipmap 0 // Slice 0 mipmap 1 // Slice 1 mipmap 1 // Slice 0 mipmap 2 // Slice 0 mipmap 3 ... Shift := 0; Last := Depth; while Idx > Last - 1 do begin CurWidth := ClampInt(CurWidth shr 1, 1, CurWidth); CurHeight := ClampInt(CurHeight shr 1, 1, CurHeight); if (CurWidth = 1) and (CurHeight = 1) then Break; Inc(Shift); Inc(Last, ClampInt(Depth shr Shift, 1, Depth)); end; end; end; end; function TDDSFileFormat.LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; var Hdr: TDDSFileHeader; HdrDX10: TDX10Header; SrcFormat: TImageFormat; FmtInfo: TImageFormatInfo; NeedsSwapChannels: Boolean; CurrentWidth, CurrentHeight, ImageCount, LoadSize, I, PitchOrLinear, MainImageLinearSize: Integer; Data: PByte; UseAsPitch: Boolean; UseAsLinear: Boolean; function MasksEqual(const DDPF: TDDPixelFormat; PF: PPixelFormatInfo): Boolean; begin Result := (DDPF.AlphaMask = PF.ABitMask) and (DDPF.RedMask = PF.RBitMask) and (DDPF.GreenMask = PF.GBitMask) and (DDPF.BlueMask = PF.BBitMask); end; function FindFourCCFormat(FourCC: LongWord): TImageFormat; begin // Handle FourCC and large ARGB formats case FourCC of D3DFMT_A16B16G16R16: Result := ifA16B16G16R16; D3DFMT_R32F: Result := ifR32F; D3DFMT_A32B32G32R32F: Result := ifA32B32G32R32F; D3DFMT_R16F: Result := ifR16F; D3DFMT_A16B16G16R16F: Result := ifA16B16G16R16F; FOURCC_DXT1: Result := ifDXT1; FOURCC_DXT3: Result := ifDXT3; FOURCC_DXT5: Result := ifDXT5; FOURCC_ATI1: Result := ifATI1N; FOURCC_ATI2: Result := ifATI2N; else Result := ifUnknown; end; end; function FindDX10Format(DXGIFormat: TDXGIFormat; var NeedsSwapChannels: Boolean): TImageFormat; begin Result := ifUnknown; NeedsSwapChannels := False; case DXGIFormat of DXGI_FORMAT_UNKNOWN: ; DXGI_FORMAT_R32G32B32A32_TYPELESS, DXGI_FORMAT_R32G32B32A32_FLOAT: Result := ifA32B32G32R32F; DXGI_FORMAT_R32G32B32A32_UINT: ; DXGI_FORMAT_R32G32B32A32_SINT: ; DXGI_FORMAT_R32G32B32_TYPELESS, DXGI_FORMAT_R32G32B32_FLOAT: Result := ifB32G32R32F; DXGI_FORMAT_R32G32B32_UINT: ; DXGI_FORMAT_R32G32B32_SINT: ; DXGI_FORMAT_R16G16B16A16_FLOAT: Result := ifA16B16G16R16F; DXGI_FORMAT_R16G16B16A16_TYPELESS, DXGI_FORMAT_R16G16B16A16_UNORM, DXGI_FORMAT_R16G16B16A16_UINT, DXGI_FORMAT_R16G16B16A16_SNORM, DXGI_FORMAT_R16G16B16A16_SINT: Result := ifA16B16G16R16; DXGI_FORMAT_R32G32_TYPELESS: ; DXGI_FORMAT_R32G32_FLOAT: ; DXGI_FORMAT_R32G32_UINT: ; DXGI_FORMAT_R32G32_SINT: ; DXGI_FORMAT_R32G8X24_TYPELESS: ; DXGI_FORMAT_D32_FLOAT_S8X24_UINT: ; DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS: ; DXGI_FORMAT_X32_TYPELESS_G8X24_UINT: ; DXGI_FORMAT_R10G10B10A2_TYPELESS: ; DXGI_FORMAT_R10G10B10A2_UNORM: ; DXGI_FORMAT_R10G10B10A2_UINT: ; DXGI_FORMAT_R11G11B10_FLOAT: ; DXGI_FORMAT_R8G8B8A8_TYPELESS, DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_FORMAT_R8G8B8A8_UINT, DXGI_FORMAT_R8G8B8A8_SNORM,DXGI_FORMAT_R8G8B8A8_SINT, DXGI_FORMAT_R8G8B8A8_UNORM_SRGB: begin Result := ifA8R8G8B8; NeedsSwapChannels := True; end; DXGI_FORMAT_R16G16_TYPELESS: ; DXGI_FORMAT_R16G16_FLOAT: ; DXGI_FORMAT_R16G16_UNORM: ; DXGI_FORMAT_R16G16_UINT: ; DXGI_FORMAT_R16G16_SNORM: ; DXGI_FORMAT_R16G16_SINT: ; DXGI_FORMAT_R32_TYPELESS, DXGI_FORMAT_R32_UINT, DXGI_FORMAT_R32_SINT: Result := ifGray32; DXGI_FORMAT_D32_FLOAT, DXGI_FORMAT_R32_FLOAT: Result := ifR32F; DXGI_FORMAT_R24G8_TYPELESS: ; DXGI_FORMAT_D24_UNORM_S8_UINT: ; DXGI_FORMAT_R24_UNORM_X8_TYPELESS: ; DXGI_FORMAT_X24_TYPELESS_G8_UINT: ; DXGI_FORMAT_R8G8_TYPELESS, DXGI_FORMAT_R8G8_UNORM, DXGI_FORMAT_R8G8_UINT, DXGI_FORMAT_R8G8_SNORM, DXGI_FORMAT_R8G8_SINT: Result := ifA8Gray8; DXGI_FORMAT_R16_TYPELESS, DXGI_FORMAT_D16_UNORM, DXGI_FORMAT_R16_UNORM, DXGI_FORMAT_R16_UINT, DXGI_FORMAT_R16_SNORM, DXGI_FORMAT_R16_SINT: Result := ifGray16; DXGI_FORMAT_R16_FLOAT: Result := ifR16F; DXGI_FORMAT_R8_TYPELESS, DXGI_FORMAT_R8_UNORM, DXGI_FORMAT_R8_UINT, DXGI_FORMAT_R8_SNORM, DXGI_FORMAT_R8_SINT, DXGI_FORMAT_A8_UNORM: Result := ifGray8; DXGI_FORMAT_R1_UNORM: ; DXGI_FORMAT_R9G9B9E5_SHAREDEXP: ; DXGI_FORMAT_R8G8_B8G8_UNORM: ; DXGI_FORMAT_G8R8_G8B8_UNORM: ; DXGI_FORMAT_BC1_TYPELESS, DXGI_FORMAT_BC1_UNORM, DXGI_FORMAT_BC1_UNORM_SRGB: Result := ifDXT1; DXGI_FORMAT_BC2_TYPELESS, DXGI_FORMAT_BC2_UNORM, DXGI_FORMAT_BC2_UNORM_SRGB: Result := ifDXT3; DXGI_FORMAT_BC3_TYPELESS, DXGI_FORMAT_BC3_UNORM, DXGI_FORMAT_BC3_UNORM_SRGB: Result := ifDXT5; DXGI_FORMAT_BC4_TYPELESS, DXGI_FORMAT_BC4_UNORM, DXGI_FORMAT_BC4_SNORM: Result := ifATI1N; DXGI_FORMAT_BC5_TYPELESS, DXGI_FORMAT_BC5_UNORM, DXGI_FORMAT_BC5_SNORM: Result := ifATI2N; DXGI_FORMAT_B5G6R5_UNORM: Result := ifR5G6B5; DXGI_FORMAT_B5G5R5A1_UNORM: Result := ifA1R5G5B5; DXGI_FORMAT_B8G8R8A8_UNORM, DXGI_FORMAT_B8G8R8A8_TYPELESS: Result := ifA8R8G8B8; DXGI_FORMAT_B8G8R8X8_UNORM, DXGI_FORMAT_B8G8R8X8_TYPELESS: Result := ifX8R8G8B8; DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM: ; DXGI_FORMAT_B8G8R8A8_UNORM_SRGB: ; DXGI_FORMAT_B8G8R8X8_UNORM_SRGB: ; DXGI_FORMAT_BC6H_TYPELESS: ; DXGI_FORMAT_BC6H_UF16: ; DXGI_FORMAT_BC6H_SF16: ; DXGI_FORMAT_BC7_TYPELESS: ; DXGI_FORMAT_BC7_UNORM: ; DXGI_FORMAT_BC7_UNORM_SRGB: ; DXGI_FORMAT_P8: ; DXGI_FORMAT_A8P8: ; DXGI_FORMAT_B4G4R4A4_UNORM: Result := ifA4R4G4B4; end; end; begin Result := False; ImageCount := 1; FLoadedMipMapCount := 1; FLoadedDepth := 1; FLoadedVolume := False; FLoadedCubeMap := False; ZeroMemory(@HdrDX10, SizeOf(HdrDX10)); with GetIO, Hdr, Hdr.Desc.PixelFormat do begin Read(Handle, @Hdr, SizeOf(Hdr)); SrcFormat := ifUnknown; NeedsSwapChannels := False; // Get image data format if (Flags and DDPF_FOURCC) = DDPF_FOURCC then begin if FourCC = FOURCC_DX10 then begin Read(Handle, @HdrDX10, SizeOf(HdrDX10)); SrcFormat := FindDX10Format(HdrDX10.DXGIFormat, NeedsSwapChannels); FMetadata.SetMetaItem(SMetaDdsDxgiFormat, HdrDX10.DXGIFormat); FMetadata.SetMetaItem(SMetaDdsArraySize, HdrDX10.ArraySize); end else SrcFormat := FindFourCCFormat(FourCC); end else if (Flags and DDPF_RGB) = DDPF_RGB then begin // Handle RGB formats if (Flags and DDPF_ALPHAPIXELS) = DDPF_ALPHAPIXELS then begin // Handle RGB with alpha formats case BitCount of 16: begin if MasksEqual(Desc.PixelFormat, GetFormatInfo(ifA4R4G4B4).PixelFormat) then SrcFormat := ifA4R4G4B4; if MasksEqual(Desc.PixelFormat, GetFormatInfo(ifA1R5G5B5).PixelFormat) then SrcFormat := ifA1R5G5B5; end; 32: begin SrcFormat := ifA8R8G8B8; if BlueMask = $00FF0000 then NeedsSwapChannels := True; end; end; end else begin // Handle RGB without alpha formats case BitCount of 8: if MasksEqual(Desc.PixelFormat, GetFormatInfo(ifR3G3B2).PixelFormat) then SrcFormat := ifR3G3B2; 16: begin if MasksEqual(Desc.PixelFormat, GetFormatInfo(ifX4R4G4B4).PixelFormat) then SrcFormat := ifX4R4G4B4; if MasksEqual(Desc.PixelFormat, GetFormatInfo(ifX1R5G5B5).PixelFormat) then SrcFormat := ifX1R5G5B5; if MasksEqual(Desc.PixelFormat, GetFormatInfo(ifR5G6B5).PixelFormat) then SrcFormat := ifR5G6B5; end; 24: SrcFormat := ifR8G8B8; 32: begin SrcFormat := ifX8R8G8B8; if BlueMask = $00FF0000 then NeedsSwapChannels := True; end; end; end; end else if (Flags and DDPF_LUMINANCE) = DDPF_LUMINANCE then begin // Handle luminance formats if (Flags and DDPF_ALPHAPIXELS) = DDPF_ALPHAPIXELS then begin // Handle luminance with alpha formats if BitCount = 16 then SrcFormat := ifA8Gray8; end else begin // Handle luminance without alpha formats case BitCount of 8: SrcFormat := ifGray8; 16: SrcFormat := ifGray16; end; end; end else if (Flags and DDPF_BUMPLUMINANCE) = DDPF_BUMPLUMINANCE then begin // Handle mixed bump-luminance formats like D3DFMT_X8L8V8U8 case BitCount of 32: if BlueMask = $00FF0000 then begin SrcFormat := ifX8R8G8B8; // D3DFMT_X8L8V8U8 NeedsSwapChannels := True; end; end; end else if (Flags and DDPF_BUMPDUDV) = DDPF_BUMPDUDV then begin // Handle bumpmap formats like D3DFMT_Q8W8V8U8 case BitCount of 16: SrcFormat := ifA8Gray8; // D3DFMT_V8U8 32: if AlphaMask = $FF000000 then begin SrcFormat := ifA8R8G8B8; // D3DFMT_Q8W8V8U8 NeedsSwapChannels := True; end; 64: SrcFormat := ifA16B16G16R16; // D3DFMT_Q16W16V16U16 end; end; // If DDS format is not supported we will exit if SrcFormat = ifUnknown then Exit; // File contains mipmaps for each subimage. { Some DDS writers ignore setting proper Caps and Flags so this check is not usable: if ((Desc.Caps.Caps1 and DDSCAPS_MIPMAP) = DDSCAPS_MIPMAP) and ((Desc.Flags and DDSD_MIPMAPCOUNT) = DDSD_MIPMAPCOUNT) then} if Desc.MipMaps > 1 then begin FLoadedMipMapCount := Desc.MipMaps; FMetadata.SetMetaItem(SMetaDdsMipMapCount, Desc.MipMaps); ImageCount := Desc.MipMaps; end; // File stores volume texture if ((Desc.Caps.Caps2 and DDSCAPS2_VOLUME) = DDSCAPS2_VOLUME) and ((Desc.Flags and DDSD_DEPTH) = DDSD_DEPTH) then begin FLoadedVolume := True; FLoadedDepth := Desc.Depth; ImageCount := GetVolumeLevelCount(Desc.Depth, ImageCount); end; // File stores cube texture if (Desc.Caps.Caps2 and DDSCAPS2_CUBEMAP) = DDSCAPS2_CUBEMAP then begin FLoadedCubeMap := True; I := 0; if (Desc.Caps.Caps2 and DDSCAPS2_POSITIVEX) = DDSCAPS2_POSITIVEX then Inc(I); if (Desc.Caps.Caps2 and DDSCAPS2_POSITIVEY) = DDSCAPS2_POSITIVEY then Inc(I); if (Desc.Caps.Caps2 and DDSCAPS2_POSITIVEZ) = DDSCAPS2_POSITIVEZ then Inc(I); if (Desc.Caps.Caps2 and DDSCAPS2_NEGATIVEX) = DDSCAPS2_NEGATIVEX then Inc(I); if (Desc.Caps.Caps2 and DDSCAPS2_NEGATIVEY) = DDSCAPS2_NEGATIVEY then Inc(I); if (Desc.Caps.Caps2 and DDSCAPS2_NEGATIVEZ) = DDSCAPS2_NEGATIVEZ then Inc(I); FLoadedDepth := I; ImageCount := ImageCount * I; end; // Allocate and load all images in file FmtInfo := GetFormatInfo(SrcFormat); SetLength(Images, ImageCount); // Compute the pitch or get if from file if present UseAsPitch := (Desc.Flags and DDSD_PITCH) = DDSD_PITCH; UseAsLinear := (Desc.Flags and DDSD_LINEARSIZE) = DDSD_LINEARSIZE; // Use linear as default if none is set if not UseAsPitch and not UseAsLinear then UseAsLinear := True; // Main image pitch or linear size PitchOrLinear := Desc.PitchOrLinearSize; // Check: some writers just write garbage to pitch/linear size fields and flags MainImageLinearSize := FmtInfo.GetPixelsSize(SrcFormat, Desc.Width, Desc.Height); if UseAsLinear and ((PitchOrLinear < MainImageLinearSize) or (PitchOrLinear * Integer(Desc.Height) = MainImageLinearSize)) then begin // Explicitly set linear size PitchOrLinear := MainImageLinearSize; end; for I := 0 to ImageCount - 1 do begin // Compute dimensions of surrent subimage based on texture type and // number of mipmaps ComputeSubDimensions(I, Desc.Width, Desc.Height, Desc.MipMaps, Desc.Depth, FLoadedCubeMap, FLoadedVolume, CurrentWidth, CurrentHeight); NewImage(CurrentWidth, CurrentHeight, SrcFormat, Images[I]); if (I > 0) or (PitchOrLinear = 0) then begin // Compute pitch or linear size for mipmap levels, or even for main image // since some formats do not fill pitch nor size if UseAsLinear then PitchOrLinear := FmtInfo.GetPixelsSize(SrcFormat, CurrentWidth, CurrentHeight) else PitchOrLinear := (CurrentWidth * FmtInfo.BytesPerPixel + 3) div 4 * 4; // must be DWORD aligned end; if UseAsLinear then LoadSize := PitchOrLinear else LoadSize := CurrentHeight * PitchOrLinear; if UseAsLinear or (LoadSize = Images[I].Size) then begin // If DDS does not use Pitch we can simply copy data Read(Handle, Images[I].Bits, LoadSize) end else begin // If DDS uses Pitch we must load aligned scanlines // and then remove padding GetMem(Data, LoadSize); try Read(Handle, Data, LoadSize); RemovePadBytes(Data, Images[I].Bits, CurrentWidth, CurrentHeight, FmtInfo.BytesPerPixel, PitchOrLinear); finally FreeMem(Data); end; end; if NeedsSwapChannels then SwapChannels(Images[I], ChannelRed, ChannelBlue); end; Result := True; end; end; function TDDSFileFormat.SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray; Index: LongInt): Boolean; var Hdr: TDDSFileHeader; MainImage, ImageToSave: TImageData; I, MainIdx, Len, ImageCount: LongInt; J: LongWord; FmtInfo: TImageFormatInfo; MustBeFreed: Boolean; Is2DTexture, IsCubeMap, IsVolume: Boolean; MipMapCount, CurrentWidth, CurrentHeight: LongInt; NeedsResize: Boolean; NeedsConvert: Boolean; begin Result := False; FillChar(Hdr, Sizeof(Hdr), 0); MainIdx := FFirstIdx; Len := FLastIdx - MainIdx + 1; // Some DDS saving rules: // 2D textures: Len is used as mipmap count (FSaveMipMapCount not used!). // Cube maps: FSaveDepth * FSaveMipMapCount images are used, if Len is // smaller than this file is saved as regular 2D texture. // Volume maps: GetVolumeLevelCount(FSaveDepth, FSaveMipMapCount) images are // used, if Len is smaller than this file is // saved as regular 2D texture. IsCubeMap := FSaveCubeMap; IsVolume := FSaveVolume; MipMapCount := FSaveMipMapCount; if IsCubeMap then begin // Check if we have enough images on Input to save cube map if Len < FSaveDepth * FSaveMipMapCount then IsCubeMap := False; end else if IsVolume then begin // Check if we have enough images on Input to save volume texture if Len < GetVolumeLevelCount(FSaveDepth, FSaveMipMapCount) then IsVolume := False; end; Is2DTexture := not IsCubeMap and not IsVolume; if Is2DTexture then begin // Get number of mipmaps used with 2D texture MipMapCount := Min(Len, GetNumMipMapLevels(Images[MainIdx].Width, Images[MainIdx].Height)); end; // we create compatible main image and fill headers if MakeCompatible(Images[MainIdx], MainImage, MustBeFreed) then with GetIO, MainImage, Hdr do try FmtInfo := GetFormatInfo(Format); Magic := DDSMagic; Desc.Size := SizeOf(Desc); Desc.Width := Width; Desc.Height := Height; Desc.Flags := DDS_SAVE_FLAGS; Desc.Caps.Caps1 := DDSCAPS_TEXTURE; Desc.PixelFormat.Size := SizeOf(Desc.PixelFormat); Desc.PitchOrLinearSize := MainImage.Size; ImageCount := MipMapCount; if MipMapCount > 1 then begin // Set proper flags if we have some mipmaps to be saved Desc.Flags := Desc.Flags or DDSD_MIPMAPCOUNT; Desc.Caps.Caps1 := Desc.Caps.Caps1 or DDSCAPS_MIPMAP or DDSCAPS_COMPLEX; Desc.MipMaps := MipMapCount; end; if IsCubeMap then begin // Set proper cube map flags - number of stored faces is taken // from FSaveDepth Desc.Caps.Caps1 := Desc.Caps.Caps1 or DDSCAPS_COMPLEX; Desc.Caps.Caps2 := Desc.Caps.Caps2 or DDSCAPS2_CUBEMAP; J := DDSCAPS2_POSITIVEX; for I := 0 to FSaveDepth - 1 do begin Desc.Caps.Caps2 := Desc.Caps.Caps2 or J; J := J shl 1; end; ImageCount := FSaveDepth * FSaveMipMapCount; end else if IsVolume then begin // Set proper flags for volume texture Desc.Flags := Desc.Flags or DDSD_DEPTH; Desc.Caps.Caps1 := Desc.Caps.Caps1 or DDSCAPS_COMPLEX; Desc.Caps.Caps2 := Desc.Caps.Caps2 or DDSCAPS2_VOLUME; Desc.Depth := FSaveDepth; ImageCount := GetVolumeLevelCount(FSaveDepth, FSaveMipMapCount); end; // Now we set DDS pixel format for main image if FmtInfo.IsSpecial or FmtInfo.IsFloatingPoint or (FmtInfo.BytesPerPixel > 4) then begin Desc.PixelFormat.Flags := DDPF_FOURCC; case Format of ifA16B16G16R16: Desc.PixelFormat.FourCC := D3DFMT_A16B16G16R16; ifR32F: Desc.PixelFormat.FourCC := D3DFMT_R32F; ifA32B32G32R32F: Desc.PixelFormat.FourCC := D3DFMT_A32B32G32R32F; ifR16F: Desc.PixelFormat.FourCC := D3DFMT_R16F; ifA16B16G16R16F: Desc.PixelFormat.FourCC := D3DFMT_A16B16G16R16F; ifDXT1: Desc.PixelFormat.FourCC := FOURCC_DXT1; ifDXT3: Desc.PixelFormat.FourCC := FOURCC_DXT3; ifDXT5: Desc.PixelFormat.FourCC := FOURCC_DXT5; ifATI1N: Desc.PixelFormat.FourCC := FOURCC_ATI1; ifATI2N: Desc.PixelFormat.FourCC := FOURCC_ATI2; end; end else if FmtInfo.HasGrayChannel then begin Desc.PixelFormat.Flags := DDPF_LUMINANCE; Desc.PixelFormat.BitCount := FmtInfo.BytesPerPixel * 8; case Format of ifGray8: Desc.PixelFormat.RedMask := 255; ifGray16: Desc.PixelFormat.RedMask := 65535; ifA8Gray8: begin Desc.PixelFormat.Flags := Desc.PixelFormat.Flags or DDPF_ALPHAPIXELS; Desc.PixelFormat.RedMask := 255; Desc.PixelFormat.AlphaMask := 65280; end; end; end else begin Desc.PixelFormat.Flags := DDPF_RGB; Desc.PixelFormat.BitCount := FmtInfo.BytesPerPixel * 8; if FmtInfo.HasAlphaChannel then begin Desc.PixelFormat.Flags := Desc.PixelFormat.Flags or DDPF_ALPHAPIXELS; Desc.PixelFormat.AlphaMask := $FF000000; end; if FmtInfo.BytesPerPixel > 2 then begin Desc.PixelFormat.RedMask := $00FF0000; Desc.PixelFormat.GreenMask := $0000FF00; Desc.PixelFormat.BlueMask := $000000FF; end else begin Desc.PixelFormat.AlphaMask := FmtInfo.PixelFormat.ABitMask; Desc.PixelFormat.RedMask := FmtInfo.PixelFormat.RBitMask; Desc.PixelFormat.GreenMask := FmtInfo.PixelFormat.GBitMask; Desc.PixelFormat.BlueMask := FmtInfo.PixelFormat.BBitMask; end; end; // Header and main image are written to output Write(Handle, @Hdr, SizeOf(Hdr)); Write(Handle, MainImage.Bits, MainImage.Size); // Write the rest of the images and convert them to // the same format as main image if necessary and ensure proper mipmap // simensions too. for I := MainIdx + 1 to MainIdx + ImageCount - 1 do begin // Get proper dimensions for this level ComputeSubDimensions(I, Desc.Width, Desc.Height, Desc.MipMaps, Desc.Depth, IsCubeMap, IsVolume, CurrentWidth, CurrentHeight); // Check if input image for this level has the right size and format NeedsResize := not ((Images[I].Width = CurrentWidth) and (Images[I].Height = CurrentHeight)); NeedsConvert := not (Images[I].Format = Format); if NeedsResize or NeedsConvert then begin // Input image must be resized or converted to different format // to become valid mipmap level InitImage(ImageToSave); CloneImage(Images[I], ImageToSave); if NeedsConvert then ConvertImage(ImageToSave, Format); if NeedsResize then ResizeImage(ImageToSave, CurrentWidth, CurrentHeight, rfBilinear); end else // Input image can be used without any changes ImageToSave := Images[I]; // Write level data and release temp image if necessary Write(Handle, ImageToSave.Bits, ImageToSave.Size); if Images[I].Bits <> ImageToSave.Bits then FreeImage(ImageToSave); end; Result := True; finally if MustBeFreed then FreeImage(MainImage); end; end; procedure TDDSFileFormat.ConvertToSupported(var Image: TImageData; const Info: TImageFormatInfo); var ConvFormat: TImageFormat; begin if Info.IsIndexed or Info.IsSpecial then // convert indexed and unsupported special formatd to A8R8G8B8 ConvFormat := ifA8R8G8B8 else if Info.IsFloatingPoint then begin if Info.Format = ifA16R16G16B16F then // only swap channels here ConvFormat := ifA16B16G16R16F else // convert other floating point formats to A32B32G32R32F ConvFormat := ifA32B32G32R32F end else if Info.HasGrayChannel then begin if Info.HasAlphaChannel then // convert grayscale with alpha to A8Gray8 ConvFormat := ifA8Gray8 else if Info.BytesPerPixel = 1 then // convert 8bit grayscale to Gray8 ConvFormat := ifGray8 else // convert 16-64bit grayscales to Gray16 ConvFormat := ifGray16; end else if Info.BytesPerPixel > 4 then ConvFormat := ifA16B16G16R16 else if Info.HasAlphaChannel then // convert the other images with alpha channel to A8R8G8B8 ConvFormat := ifA8R8G8B8 else // convert the other formats to X8R8G8B8 ConvFormat := ifX8R8G8B8; ConvertImage(Image, ConvFormat); end; function TDDSFileFormat.TestFormat(Handle: TImagingHandle): Boolean; var Hdr: TDDSFileHeader; ReadCount: LongInt; begin Result := False; if Handle <> nil then with GetIO do begin ReadCount := Read(Handle, @Hdr, SizeOf(Hdr)); Seek(Handle, -ReadCount, smFromCurrent); Result := (Hdr.Magic = DDSMagic) and (ReadCount = SizeOf(Hdr)) and ((Hdr.Desc.Caps.Caps1 and DDSCAPS_TEXTURE) = DDSCAPS_TEXTURE); end; end; initialization RegisterImageFileFormat(TDDSFileFormat); { File Notes: -- TODOS ---------------------------------------------------- - nothing now -- 0.77.1 ---------------------------------------------------- - Texture and D3D specific info stored in DDS is now available as metadata (loading). - Added support for loading DDS files with DX10 extension (http://msdn.microsoft.com/en-us/library/windows/desktop/bb943991(v=vs.85).aspx) and few compatibility fixes. -- 0.25.0 Changes/Bug Fixes --------------------------------- - Added support for 3Dc ATI1/2 formats. -- 0.23 Changes/Bug Fixes ----------------------------------- - Saved DDS with mipmaps now correctly defineds COMPLEX flag. - Fixed loading of RGB DDS files that use pitch and have mipmaps - mipmaps were loaded wrongly. -- 0.21 Changes/Bug Fixes ----------------------------------- - Changed saving behaviour a bit: mipmaps are inlcuded automatically for 2D textures if input image array has more than 1 image (no need to set SaveMipMapCount manually). - Mipmap levels are now saved with proper dimensions when saving DDS files. - Made some changes to not be so strict when loading DDS files. Many programs seem to save them in non-standard format (by MS DDS File Reference). - Added missing ifX8R8G8B8 to SupportedFormats, MakeCompatible failed when image was converted to this format (inside). - MakeCompatible method moved to base class, put ConvertToSupported here. GetSupportedFormats removed, it is now set in constructor. - Fixed bug that sometimes saved non-standard DDS files and another one that caused crash when these files were loaded. - Changed extensions to filename masks. - Changed SaveData, LoadData, and MakeCompatible methods according to changes in base class in Imaging unit. -- 0.19 Changes/Bug Fixes ----------------------------------- - added support for half-float image formats - change in LoadData to allow support for more images in one stream loading -- 0.17 Changes/Bug Fixes ----------------------------------- - fixed bug in TestFormat which does not recognize many DDS files - changed pitch/linearsize handling in DDS loading code to load DDS files produced by NVidia's Photoshop plugin } end. ================================================ FILE: lib/Imaging/ImagingFormats.pas ================================================ { Vampyre Imaging Library by Marek Mauder http://imaginglib.sourceforge.net The contents of this file are used with permission, subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/MPL-1.1.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Alternatively, the contents of this file may be used under the terms of the GNU Lesser General Public License (the "LGPL License"), in which case the provisions of the LGPL License are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of the LGPL License and not to allow others to use your version of this file under the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the LGPL License. If you do not delete the provisions above, a recipient may use your version of this file under either the MPL or the LGPL License. For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html } { This unit manages information about all image data formats and contains low level format conversion, manipulation, and other related functions.} unit ImagingFormats; {$I ImagingOptions.inc} interface uses ImagingTypes, Imaging, ImagingUtility; type TImageFormatInfoArray = array[TImageFormat] of PImageFormatInfo; PImageFormatInfoArray = ^TImageFormatInfoArray; { Additional image manipulation functions (usually used internally by Imaging unit) } type { Color reduction operations.} TReduceColorsAction = (raCreateHistogram, raUpdateHistogram, raMakeColorMap, raMapImage); TReduceColorsActions = set of TReduceColorsAction; const AllReduceColorsActions = [raCreateHistogram, raUpdateHistogram, raMakeColorMap, raMapImage]; { Reduces the number of colors of source. Src is bits of source image (ARGB or floating point) and Dst is in some indexed format. MaxColors is the number of colors to which reduce and DstPal is palette to which the resulting colors are written and it must be allocated to at least MaxColors entries. ChannelMask is 'anded' with every pixel's channel value when creating color histogram. If $FF is used all 8bits of color channels are used which can be slow for large images with many colors so you can use lower masks to speed it up.} procedure ReduceColorsMedianCut(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo; MaxColors: LongInt; ChannelMask: Byte; DstPal: PPalette32; Actions: TReduceColorsActions = AllReduceColorsActions); { Stretches rectangle in source image to rectangle in destination image using nearest neighbor filtering. It is fast but results look blocky because there is no interpolation used. SrcImage and DstImage must be in the same data format. Works for all data formats except special formats.} procedure StretchNearest(const SrcImage: TImageData; SrcX, SrcY, SrcWidth, SrcHeight: LongInt; var DstImage: TImageData; DstX, DstY, DstWidth, DstHeight: LongInt); type { Built-in sampling filters.} TSamplingFilter = (sfNearest, sfLinear, sfCosine, sfHermite, sfQuadratic, sfGaussian, sfSpline, sfLanczos, sfMitchell, sfCatmullRom); { Type of custom sampling function} TFilterFunction = function(Value: Single): Single; const { Default resampling filter used for bicubic resizing.} DefaultCubicFilter = sfCatmullRom; var { Built-in filter functions.} SamplingFilterFunctions: array[TSamplingFilter] of TFilterFunction; { Default radii of built-in filter functions.} SamplingFilterRadii: array[TSamplingFilter] of Single; { Stretches rectangle in source image to rectangle in destination image with resampling. One of built-in resampling filters defined by Filter is used. Set WrapEdges to True for seamlessly tileable images. SrcImage and DstImage must be in the same data format. Works for all data formats except special and indexed formats.} procedure StretchResample(const SrcImage: TImageData; SrcX, SrcY, SrcWidth, SrcHeight: LongInt; var DstImage: TImageData; DstX, DstY, DstWidth, DstHeight: LongInt; Filter: TSamplingFilter; WrapEdges: Boolean = False); overload; { Stretches rectangle in source image to rectangle in destination image with resampling. You can use custom sampling function and filter radius. Set WrapEdges to True for seamlessly tileable images. SrcImage and DstImage must be in the same data format. Works for all data formats except special and indexed formats.} procedure StretchResample(const SrcImage: TImageData; SrcX, SrcY, SrcWidth, SrcHeight: LongInt; var DstImage: TImageData; DstX, DstY, DstWidth, DstHeight: LongInt; Filter: TFilterFunction; Radius: Single; WrapEdges: Boolean = False); overload; { Helper for functions that create mipmap levels. BiggerLevel is valid image and SmallerLevel is empty zeroed image. SmallerLevel is created with Width and Height dimensions and it is filled with pixels of BiggerLevel using resampling filter specified by ImagingMipMapFilter option. Uses StretchNearest and StretchResample internally so the same image data format limitations apply.} procedure FillMipMapLevel(const BiggerLevel: TImageData; Width, Height: LongInt; var SmallerLevel: TImageData); { Various helper & support functions } { Copies Src pixel to Dest pixel. It is faster than System.Move procedure.} procedure CopyPixel(Src, Dest: Pointer; BytesPerPixel: LongInt); {$IFDEF USE_INLINE}inline;{$ENDIF} { Compares Src pixel and Dest pixel. It is faster than SysUtils.CompareMem function.} function ComparePixels(PixelA, PixelB: Pointer; BytesPerPixel: LongInt): Boolean; {$IFDEF USE_INLINE}inline;{$ENDIF} { Translates pixel color in SrcFormat to DstFormat.} procedure TranslatePixel(SrcPixel, DstPixel: Pointer; SrcFormat, DstFormat: TImageFormat; SrcPalette, DstPalette: PPalette32); { Clamps floating point pixel channel values to [0.0, 1.0] range.} procedure ClampFloatPixel(var PixF: TColorFPRec); {$IFDEF USE_INLINE}inline;{$ENDIF} { Helper function that converts pixel in any format to 32bit ARGB pixel. For common formats it's faster than calling GetPixel32 etc.} procedure ConvertToPixel32(SrcPix: PByte; DestPix: PColor32Rec; const SrcInfo: TImageFormatInfo; SrcPalette: PPalette32 = nil); {$IFDEF USE_INLINE}inline;{$ENDIF} { Adds padding bytes at the ends of scanlines. Bpp is the number of bytes per pixel of source and WidthBytes is the number of bytes per scanlines of dest.} procedure AddPadBytes(DataIn: Pointer; DataOut: Pointer; Width, Height, Bpp, WidthBytes: LongInt); { Removes padding from image with scanlines that have aligned sizes. Bpp is the number of bytes per pixel of dest and WidthBytes is the number of bytes per scanlines of source.} procedure RemovePadBytes(DataIn: Pointer; DataOut: Pointer; Width, Height, Bpp, WidthBytes: LongInt); { Converts 1bit image data to 8bit. Used mostly by file loaders for formats supporting 1bit images. Scaling of pixel values to 8bits is optional (indexed formats don't need this).} procedure Convert1To8(DataIn, DataOut: PByte; Width, Height, WidthBytes: LongInt; ScaleTo8Bits: Boolean); { Converts 2bit image data to 8bit. Used mostly by file loaders for formats supporting 2bit images. Scaling of pixel values to 8bits is optional (indexed formats don't need this).} procedure Convert2To8(DataIn, DataOut: PByte; Width, Height, WidthBytes: LongInt; ScaleTo8Bits: Boolean); { Converts 4bit image data to 8bit. Used mostly by file loaders for formats supporting 4bit images. Scaling of pixel values to 8bits is optional (indexed formats don't need this).} procedure Convert4To8(DataIn, DataOut: PByte; Width, Height, WidthBytes: LongInt; ScaleTo8Bits: Boolean); { Helper function for image file loaders. Some 15 bit images (targas, bitmaps) may contain 1 bit alpha but there is no indication of it. This function checks all 16 bit(should be X1R5G5B5 or A1R5G5B5 format) pixels and some of them have alpha bit set it returns True, otherwise False.} function Has16BitImageAlpha(NumPixels: LongInt; Data: PWord): Boolean; { Helper function for image file loaders. This function checks is similar to Has16BitImageAlpha but works with A8R8G8B8/X8R8G8B8 format.} function Has32BitImageAlpha(NumPixels: LongInt; Data: PLongWord): Boolean; { Checks if there is any relevant alpha data (any entry has alpha <> 255) in the given palette.} function PaletteHasAlpha(Palette: PPalette32; PaletteEntries: Integer): Boolean; { Provides indexed access to each line of pixels. Does not work with special format images.} function GetScanLine(ImageBits: Pointer; const FormatInfo: TImageFormatInfo; LineWidth, Index: LongInt): Pointer; {$IFDEF USE_INLINE}inline;{$ENDIF} { Returns True if Format is valid image data format identifier.} function IsImageFormatValid(Format: TImageFormat): Boolean; { Converts 16bit half floating point value to 32bit Single.} function HalfToFloat(Half: THalfFloat): Single; { Converts 32bit Single to 16bit half floating point.} function FloatToHalf(Float: Single): THalfFloat; { Converts half float color value to single-precision floating point color.} function ColorHalfToFloat(ColorHF: TColorHFRec): TColorFPRec; {$IFDEF USE_INLINE}inline;{$ENDIF} { Converts single-precision floating point color to half float color.} function ColorFloatToHalf(ColorFP: TColorFPRec): TColorHFRec; {$IFDEF USE_INLINE}inline;{$ENDIF} { Makes image PalEntries x 1 big where each pixel has color of one pal entry.} procedure VisualizePalette(Pal: PPalette32; Entries: Integer; out PalImage: TImageData); type TPointRec = record Pos: LongInt; Weight: Single; end; TCluster = array of TPointRec; TMappingTable = array of TCluster; { Helper function for resampling.} function BuildMappingTable(DstLow, DstHigh, SrcLow, SrcHigh, SrcImageWidth: LongInt; Filter: TFilterFunction; Radius: Single; WrapEdges: Boolean): TMappingTable; { Helper function for resampling.} procedure FindExtremes(const Map: TMappingTable; var MinPos, MaxPos: LongInt); { Pixel readers/writers for different image formats } { Returns pixel of image in any ARGB format. Channel values are scaled to 16 bits.} procedure ChannelGetSrcPixel(Src: PByte; SrcInfo: PImageFormatInfo; var Pix: TColor64Rec); { Sets pixel of image in any ARGB format. Channel values must be scaled to 16 bits.} procedure ChannelSetDstPixel(Dst: PByte; DstInfo: PImageFormatInfo; const Pix: TColor64Rec); { Returns pixel of image in any grayscale format. Gray value is scaled to 64 bits and alpha to 16 bits.} procedure GrayGetSrcPixel(Src: PByte; SrcInfo: PImageFormatInfo; var Gray: TColor64Rec; var Alpha: Word); { Sets pixel of image in any grayscale format. Gray value must be scaled to 64 bits and alpha to 16 bits.} procedure GraySetDstPixel(Dst: PByte; DstInfo: PImageFormatInfo; const Gray: TColor64Rec; Alpha: Word); { Returns pixel of image in any floating point format. Channel values are in range <0.0, 1.0>.} procedure FloatGetSrcPixel(Src: PByte; SrcInfo: PImageFormatInfo; var Pix: TColorFPRec); { Sets pixel of image in any floating point format. Channel values must be in range <0.0, 1.0>.} procedure FloatSetDstPixel(Dst: PByte; DstInfo: PImageFormatInfo; const Pix: TColorFPRec); { Returns pixel of image in any indexed format. Returned value is index to the palette.} procedure IndexGetSrcPixel(Src: PByte; SrcInfo: PImageFormatInfo; var Index: LongWord); { Sets pixel of image in any indexed format. Index is index to the palette.} procedure IndexSetDstPixel(Dst: PByte; DstInfo: PImageFormatInfo; Index: LongWord); { Pixel readers/writers for 32bit and FP colors} { Function for getting pixel colors. Native pixel is read from Image and then translated to 32 bit ARGB.} function GetPixel32Generic(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColor32Rec; { Procedure for setting pixel colors. Input 32 bit ARGB color is translated to native format and then written to Image.} procedure SetPixel32Generic(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColor32Rec); { Function for getting pixel colors. Native pixel is read from Image and then translated to FP ARGB.} function GetPixelFPGeneric(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColorFPRec; { Procedure for setting pixel colors. Input FP ARGB color is translated to native format and then written to Image.} procedure SetPixelFPGeneric(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColorFPRec); { Image format conversion functions } { Converts any ARGB format to any ARGB format.} procedure ChannelToChannel(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo); { Converts any ARGB format to any grayscale format.} procedure ChannelToGray(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo); { Converts any ARGB format to any floating point format.} procedure ChannelToFloat(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo); { Converts any ARGB format to any indexed format.} procedure ChannelToIndex(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo; DstPal: PPalette32); { Converts any grayscale format to any grayscale format.} procedure GrayToGray(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo); { Converts any grayscale format to any ARGB format.} procedure GrayToChannel(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo); { Converts any grayscale format to any floating point format.} procedure GrayToFloat(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo); { Converts any grayscale format to any indexed format.} procedure GrayToIndex(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo; DstPal: PPalette32); { Converts any floating point format to any floating point format.} procedure FloatToFloat(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo); { Converts any floating point format to any ARGB format.} procedure FloatToChannel(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo); { Converts any floating point format to any grayscale format.} procedure FloatToGray(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo); { Converts any floating point format to any indexed format.} procedure FloatToIndex(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo; DstPal: PPalette32); { Converts any indexed format to any indexed format.} procedure IndexToIndex(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo; SrcPal, DstPal: PPalette32); { Converts any indexed format to any ARGB format.} procedure IndexToChannel(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo; SrcPal: PPalette32); { Converts any indexed format to any grayscale format.} procedure IndexToGray(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo; SrcPal: PPalette32); { Converts any indexed format to any floating point format.} procedure IndexToFloat(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo; SrcPal: PPalette32); { Color constructor functions } { Constructs TColor24Rec color.} function Color24(R, G, B: Byte): TColor24Rec; {$IFDEF USE_INLINE}inline;{$ENDIF} { Constructs TColor32Rec color.} function Color32(A, R, G, B: Byte): TColor32Rec; {$IFDEF USE_INLINE}inline;{$ENDIF} { Constructs TColor48Rec color.} function Color48(R, G, B: Word): TColor48Rec; {$IFDEF USE_INLINE}inline;{$ENDIF} { Constructs TColor64Rec color.} function Color64(A, R, G, B: Word): TColor64Rec; {$IFDEF USE_INLINE}inline;{$ENDIF} { Constructs TColorFPRec color.} function ColorFP(A, R, G, B: Single): TColorFPRec; {$IFDEF USE_INLINE}inline;{$ENDIF} { Constructs TColorHFRec color.} function ColorHF(A, R, G, B: THalfFloat): TColorHFRec; {$IFDEF USE_INLINE}inline;{$ENDIF} { Special formats conversion functions } { Converts image to/from/between special image formats (dxtc, ...).} procedure ConvertSpecial(var Image: TImageData; SrcInfo, DstInfo: PImageFormatInfo); { Inits all image format information. Called internally on startup.} procedure InitImageFormats(var Infos: TImageFormatInfoArray); const // Grayscale conversion channel weights GrayConv: TColorFPRec = (B: 0.114; G: 0.587; R: 0.299; A: 0.0); // Contants for converting integer colors to floating point OneDiv8Bit: Single = 1.0 / 255.0; OneDiv16Bit: Single = 1.0 / 65535.0; implementation { TImageFormatInfo member functions } { Returns size in bytes of image in given standard format where Size = Width * Height * Bpp.} function GetStdPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt; forward; { Checks if Width and Height are valid for given standard format.} procedure CheckStdDimensions(Format: TImageFormat; var Width, Height: LongInt); forward; { Returns size in bytes of image in given DXT format.} function GetDXTPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt; forward; { Checks if Width and Height are valid for given DXT format. If they are not valid, they are changed to pass the check.} procedure CheckDXTDimensions(Format: TImageFormat; var Width, Height: LongInt); forward; { Returns size in bytes of image in BTC format.} function GetBTCPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt; forward; { Returns size in bytes of image in binary format (1bit image).} function GetBinaryPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt; forward; { Optimized pixel readers/writers for 32bit and FP colors to be stored in TImageFormatInfo } function GetPixel32ifA8R8G8B8(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColor32Rec; forward; procedure SetPixel32ifA8R8G8B8(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColor32Rec); forward; function GetPixelFPifA8R8G8B8(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColorFPRec; forward; procedure SetPixelFPifA8R8G8B8(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColorFPRec); forward; function GetPixel32Channel8Bit(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColor32Rec; forward; procedure SetPixel32Channel8Bit(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColor32Rec); forward; function GetPixelFPChannel8Bit(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColorFPRec; forward; procedure SetPixelFPChannel8Bit(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColorFPRec); forward; function GetPixelFPFloat32(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColorFPRec; forward; procedure SetPixelFPFloat32(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColorFPRec); forward; var PFR3G3B2: TPixelFormatInfo; PFX5R1G1B1: TPixelFormatInfo; PFR5G6B5: TPixelFormatInfo; PFA1R5G5B5: TPixelFormatInfo; PFA4R4G4B4: TPixelFormatInfo; PFX1R5G5B5: TPixelFormatInfo; PFX4R4G4B4: TPixelFormatInfo; FInfos: PImageFormatInfoArray; var // Free Pascal generates hundreds of warnings here {$WARNINGS OFF} // indexed formats Index8Info: TImageFormatInfo = ( Format: ifIndex8; Name: 'Index8'; BytesPerPixel: 1; ChannelCount: 1; PaletteEntries: 256; HasAlphaChannel: True; IsIndexed: True; GetPixelsSize: GetStdPixelsSize; CheckDimensions: CheckStdDimensions; GetPixel32: GetPixel32Generic; GetPixelFP: GetPixelFPGeneric; SetPixel32: SetPixel32Generic; SetPixelFP: SetPixelFPGeneric); // grayscale formats Gray8Info: TImageFormatInfo = ( Format: ifGray8; Name: 'Gray8'; BytesPerPixel: 1; ChannelCount: 1; HasGrayChannel: True; GetPixelsSize: GetStdPixelsSize; CheckDimensions: CheckStdDimensions; GetPixel32: GetPixel32Channel8Bit; GetPixelFP: GetPixelFPChannel8Bit; SetPixel32: SetPixel32Channel8Bit; SetPixelFP: SetPixelFPChannel8Bit); A8Gray8Info: TImageFormatInfo = ( Format: ifA8Gray8; Name: 'A8Gray8'; BytesPerPixel: 2; ChannelCount: 2; HasGrayChannel: True; HasAlphaChannel: True; GetPixelsSize: GetStdPixelsSize; CheckDimensions: CheckStdDimensions; GetPixel32: GetPixel32Channel8Bit; GetPixelFP: GetPixelFPChannel8Bit; SetPixel32: SetPixel32Channel8Bit; SetPixelFP: SetPixelFPChannel8Bit); Gray16Info: TImageFormatInfo = ( Format: ifGray16; Name: 'Gray16'; BytesPerPixel: 2; ChannelCount: 1; HasGrayChannel: True; GetPixelsSize: GetStdPixelsSize; CheckDimensions: CheckStdDimensions; GetPixel32: GetPixel32Generic; GetPixelFP: GetPixelFPGeneric; SetPixel32: SetPixel32Generic; SetPixelFP: SetPixelFPGeneric); Gray32Info: TImageFormatInfo = ( Format: ifGray32; Name: 'Gray32'; BytesPerPixel: 4; ChannelCount: 1; HasGrayChannel: True; GetPixelsSize: GetStdPixelsSize; CheckDimensions: CheckStdDimensions; GetPixel32: GetPixel32Generic; GetPixelFP: GetPixelFPGeneric; SetPixel32: SetPixel32Generic; SetPixelFP: SetPixelFPGeneric); Gray64Info: TImageFormatInfo = ( Format: ifGray64; Name: 'Gray64'; BytesPerPixel: 8; ChannelCount: 1; HasGrayChannel: True; GetPixelsSize: GetStdPixelsSize; CheckDimensions: CheckStdDimensions; GetPixel32: GetPixel32Generic; GetPixelFP: GetPixelFPGeneric; SetPixel32: SetPixel32Generic; SetPixelFP: SetPixelFPGeneric); A16Gray16Info: TImageFormatInfo = ( Format: ifA16Gray16; Name: 'A16Gray16'; BytesPerPixel: 4; ChannelCount: 2; HasGrayChannel: True; HasAlphaChannel: True; GetPixelsSize: GetStdPixelsSize; CheckDimensions: CheckStdDimensions; GetPixel32: GetPixel32Generic; GetPixelFP: GetPixelFPGeneric; SetPixel32: SetPixel32Generic; SetPixelFP: SetPixelFPGeneric); // ARGB formats X5R1G1B1Info: TImageFormatInfo = ( Format: ifX5R1G1B1; Name: 'X5R1G1B1'; BytesPerPixel: 1; ChannelCount: 3; UsePixelFormat: True; PixelFormat: @PFX5R1G1B1; GetPixelsSize: GetStdPixelsSize; CheckDimensions: CheckStdDimensions; GetPixel32: GetPixel32Generic; GetPixelFP: GetPixelFPGeneric; SetPixel32: SetPixel32Generic; SetPixelFP: SetPixelFPGeneric); R3G3B2Info: TImageFormatInfo = ( Format: ifR3G3B2; Name: 'R3G3B2'; BytesPerPixel: 1; ChannelCount: 3; UsePixelFormat: True; PixelFormat: @PFR3G3B2; GetPixelsSize: GetStdPixelsSize; CheckDimensions: CheckStdDimensions; GetPixel32: GetPixel32Generic; GetPixelFP: GetPixelFPGeneric; SetPixel32: SetPixel32Generic; SetPixelFP: SetPixelFPGeneric); R5G6B5Info: TImageFormatInfo = ( Format: ifR5G6B5; Name: 'R5G6B5'; BytesPerPixel: 2; ChannelCount: 3; UsePixelFormat: True; PixelFormat: @PFR5G6B5; GetPixelsSize: GetStdPixelsSize; CheckDimensions: CheckStdDimensions; GetPixel32: GetPixel32Generic; GetPixelFP: GetPixelFPGeneric; SetPixel32: SetPixel32Generic; SetPixelFP: SetPixelFPGeneric); A1R5G5B5Info: TImageFormatInfo = ( Format: ifA1R5G5B5; Name: 'A1R5G5B5'; BytesPerPixel: 2; ChannelCount: 4; HasAlphaChannel: True; UsePixelFormat: True; PixelFormat: @PFA1R5G5B5; GetPixelsSize: GetStdPixelsSize; CheckDimensions: CheckStdDimensions; GetPixel32: GetPixel32Generic; GetPixelFP: GetPixelFPGeneric; SetPixel32: SetPixel32Generic; SetPixelFP: SetPixelFPGeneric); A4R4G4B4Info: TImageFormatInfo = ( Format: ifA4R4G4B4; Name: 'A4R4G4B4'; BytesPerPixel: 2; ChannelCount: 4; HasAlphaChannel: True; UsePixelFormat: True; PixelFormat: @PFA4R4G4B4; GetPixelsSize: GetStdPixelsSize; CheckDimensions: CheckStdDimensions; GetPixel32: GetPixel32Generic; GetPixelFP: GetPixelFPGeneric; SetPixel32: SetPixel32Generic; SetPixelFP: SetPixelFPGeneric); X1R5G5B5Info: TImageFormatInfo = ( Format: ifX1R5G5B5; Name: 'X1R5G5B5'; BytesPerPixel: 2; ChannelCount: 3; UsePixelFormat: True; PixelFormat: @PFX1R5G5B5; GetPixelsSize: GetStdPixelsSize; CheckDimensions: CheckStdDimensions; GetPixel32: GetPixel32Generic; GetPixelFP: GetPixelFPGeneric; SetPixel32: SetPixel32Generic; SetPixelFP: SetPixelFPGeneric); X4R4G4B4Info: TImageFormatInfo = ( Format: ifX4R4G4B4; Name: 'X4R4G4B4'; BytesPerPixel: 2; ChannelCount: 3; UsePixelFormat: True; PixelFormat: @PFX4R4G4B4; GetPixelsSize: GetStdPixelsSize; CheckDimensions: CheckStdDimensions; GetPixel32: GetPixel32Generic; GetPixelFP: GetPixelFPGeneric; SetPixel32: SetPixel32Generic; SetPixelFP: SetPixelFPGeneric); R8G8B8Info: TImageFormatInfo = ( Format: ifR8G8B8; Name: 'R8G8B8'; BytesPerPixel: 3; ChannelCount: 3; GetPixelsSize: GetStdPixelsSize; CheckDimensions: CheckStdDimensions; GetPixel32: GetPixel32Channel8Bit; GetPixelFP: GetPixelFPChannel8Bit; SetPixel32: SetPixel32Channel8Bit; SetPixelFP: SetPixelFPChannel8Bit); A8R8G8B8Info: TImageFormatInfo = ( Format: ifA8R8G8B8; Name: 'A8R8G8B8'; BytesPerPixel: 4; ChannelCount: 4; HasAlphaChannel: True; GetPixelsSize: GetStdPixelsSize; CheckDimensions: CheckStdDimensions; GetPixel32: GetPixel32ifA8R8G8B8; GetPixelFP: GetPixelFPifA8R8G8B8; SetPixel32: SetPixel32ifA8R8G8B8; SetPixelFP: SetPixelFPifA8R8G8B8); X8R8G8B8Info: TImageFormatInfo = ( Format: ifX8R8G8B8; Name: 'X8R8G8B8'; BytesPerPixel: 4; ChannelCount: 3; GetPixelsSize: GetStdPixelsSize; CheckDimensions: CheckStdDimensions; GetPixel32: GetPixel32Channel8Bit; GetPixelFP: GetPixelFPChannel8Bit; SetPixel32: SetPixel32Channel8Bit; SetPixelFP: SetPixelFPChannel8Bit); R16G16B16Info: TImageFormatInfo = ( Format: ifR16G16B16; Name: 'R16G16B16'; BytesPerPixel: 6; ChannelCount: 3; RBSwapFormat: ifB16G16R16; GetPixelsSize: GetStdPixelsSize; CheckDimensions: CheckStdDimensions; GetPixel32: GetPixel32Generic; GetPixelFP: GetPixelFPGeneric; SetPixel32: SetPixel32Generic; SetPixelFP: SetPixelFPGeneric); A16R16G16B16Info: TImageFormatInfo = ( Format: ifA16R16G16B16; Name: 'A16R16G16B16'; BytesPerPixel: 8; ChannelCount: 4; HasAlphaChannel: True; RBSwapFormat: ifA16B16G16R16; GetPixelsSize: GetStdPixelsSize; CheckDimensions: CheckStdDimensions; GetPixel32: GetPixel32Generic; GetPixelFP: GetPixelFPGeneric; SetPixel32: SetPixel32Generic; SetPixelFP: SetPixelFPGeneric); B16G16R16Info: TImageFormatInfo = ( Format: ifB16G16R16; Name: 'B16G16R16'; BytesPerPixel: 6; ChannelCount: 3; IsRBSwapped: True; RBSwapFormat: ifR16G16B16; GetPixelsSize: GetStdPixelsSize; CheckDimensions: CheckStdDimensions; GetPixel32: GetPixel32Generic; GetPixelFP: GetPixelFPGeneric; SetPixel32: SetPixel32Generic; SetPixelFP: SetPixelFPGeneric); A16B16G16R16Info: TImageFormatInfo = ( Format: ifA16B16G16R16; Name: 'A16B16G16R16'; BytesPerPixel: 8; ChannelCount: 4; HasAlphaChannel: True; IsRBSwapped: True; RBSwapFormat: ifA16R16G16B16; GetPixelsSize: GetStdPixelsSize; CheckDimensions: CheckStdDimensions; GetPixel32: GetPixel32Generic; GetPixelFP: GetPixelFPGeneric; SetPixel32: SetPixel32Generic; SetPixelFP: SetPixelFPGeneric); // floating point formats R32FInfo: TImageFormatInfo = ( Format: ifR32F; Name: 'R32F'; BytesPerPixel: 4; ChannelCount: 1; IsFloatingPoint: True; GetPixelsSize: GetStdPixelsSize; CheckDimensions: CheckStdDimensions; GetPixel32: GetPixel32Generic; GetPixelFP: GetPixelFPFloat32; SetPixel32: SetPixel32Generic; SetPixelFP: SetPixelFPFloat32); A32R32G32B32FInfo: TImageFormatInfo = ( Format: ifA32R32G32B32F; Name: 'A32R32G32B32F'; BytesPerPixel: 16; ChannelCount: 4; HasAlphaChannel: True; IsFloatingPoint: True; RBSwapFormat: ifA32B32G32R32F; GetPixelsSize: GetStdPixelsSize; CheckDimensions: CheckStdDimensions; GetPixel32: GetPixel32Generic; GetPixelFP: GetPixelFPFloat32; SetPixel32: SetPixel32Generic; SetPixelFP: SetPixelFPFloat32); A32B32G32R32FInfo: TImageFormatInfo = ( Format: ifA32B32G32R32F; Name: 'A32B32G32R32F'; BytesPerPixel: 16; ChannelCount: 4; HasAlphaChannel: True; IsFloatingPoint: True; IsRBSwapped: True; RBSwapFormat: ifA32R32G32B32F; GetPixelsSize: GetStdPixelsSize; CheckDimensions: CheckStdDimensions; GetPixel32: GetPixel32Generic; GetPixelFP: GetPixelFPFloat32; SetPixel32: SetPixel32Generic; SetPixelFP: SetPixelFPFloat32); R16FInfo: TImageFormatInfo = ( Format: ifR16F; Name: 'R16F'; BytesPerPixel: 2; ChannelCount: 1; IsFloatingPoint: True; GetPixelsSize: GetStdPixelsSize; CheckDimensions: CheckStdDimensions; GetPixel32: GetPixel32Generic; GetPixelFP: GetPixelFPGeneric; SetPixel32: SetPixel32Generic; SetPixelFP: SetPixelFPGeneric); A16R16G16B16FInfo: TImageFormatInfo = ( Format: ifA16R16G16B16F; Name: 'A16R16G16B16F'; BytesPerPixel: 8; ChannelCount: 4; HasAlphaChannel: True; IsFloatingPoint: True; RBSwapFormat: ifA16B16G16R16F; GetPixelsSize: GetStdPixelsSize; CheckDimensions: CheckStdDimensions; GetPixel32: GetPixel32Generic; GetPixelFP: GetPixelFPGeneric; SetPixel32: SetPixel32Generic; SetPixelFP: SetPixelFPGeneric); A16B16G16R16FInfo: TImageFormatInfo = ( Format: ifA16B16G16R16F; Name: 'A16B16G16R16F'; BytesPerPixel: 8; ChannelCount: 4; HasAlphaChannel: True; IsFloatingPoint: True; IsRBSwapped: True; RBSwapFormat: ifA16R16G16B16F; GetPixelsSize: GetStdPixelsSize; CheckDimensions: CheckStdDimensions; GetPixel32: GetPixel32Generic; GetPixelFP: GetPixelFPGeneric; SetPixel32: SetPixel32Generic; SetPixelFP: SetPixelFPGeneric); R32G32B32FInfo: TImageFormatInfo = ( Format: ifR32G32B32F; Name: 'R32G32B32F'; BytesPerPixel: 12; ChannelCount: 3; IsFloatingPoint: True; RBSwapFormat: ifB32G32R32F; GetPixelsSize: GetStdPixelsSize; CheckDimensions: CheckStdDimensions; GetPixel32: GetPixel32Generic; GetPixelFP: GetPixelFPFloat32; SetPixel32: SetPixel32Generic; SetPixelFP: SetPixelFPFloat32); B32G32R32FInfo: TImageFormatInfo = ( Format: ifB32G32R32F; Name: 'B32G32R32F'; BytesPerPixel: 12; ChannelCount: 3; IsFloatingPoint: True; IsRBSwapped: True; RBSwapFormat: ifR32G32B32F; GetPixelsSize: GetStdPixelsSize; CheckDimensions: CheckStdDimensions; GetPixel32: GetPixel32Generic; GetPixelFP: GetPixelFPFloat32; SetPixel32: SetPixel32Generic; SetPixelFP: SetPixelFPFloat32); // special formats DXT1Info: TImageFormatInfo = ( Format: ifDXT1; Name: 'DXT1'; ChannelCount: 4; HasAlphaChannel: True; IsSpecial: True; GetPixelsSize: GetDXTPixelsSize; CheckDimensions: CheckDXTDimensions; SpecialNearestFormat: ifA8R8G8B8); DXT3Info: TImageFormatInfo = ( Format: ifDXT3; Name: 'DXT3'; ChannelCount: 4; HasAlphaChannel: True; IsSpecial: True; GetPixelsSize: GetDXTPixelsSize; CheckDimensions: CheckDXTDimensions; SpecialNearestFormat: ifA8R8G8B8); DXT5Info: TImageFormatInfo = ( Format: ifDXT5; Name: 'DXT5'; ChannelCount: 4; HasAlphaChannel: True; IsSpecial: True; GetPixelsSize: GetDXTPixelsSize; CheckDimensions: CheckDXTDimensions; SpecialNearestFormat: ifA8R8G8B8); BTCInfo: TImageFormatInfo = ( Format: ifBTC; Name: 'BTC'; ChannelCount: 1; HasAlphaChannel: False; IsSpecial: True; GetPixelsSize: GetBTCPixelsSize; CheckDimensions: CheckDXTDimensions; SpecialNearestFormat: ifGray8); ATI1NInfo: TImageFormatInfo = ( Format: ifATI1N; Name: 'ATI1N'; ChannelCount: 1; HasAlphaChannel: False; IsSpecial: True; GetPixelsSize: GetDXTPixelsSize; CheckDimensions: CheckDXTDimensions; SpecialNearestFormat: ifGray8); ATI2NInfo: TImageFormatInfo = ( Format: ifATI2N; Name: 'ATI2N'; ChannelCount: 2; HasAlphaChannel: False; IsSpecial: True; GetPixelsSize: GetDXTPixelsSize; CheckDimensions: CheckDXTDimensions; SpecialNearestFormat: ifA8R8G8B8); BinaryInfo: TImageFormatInfo = ( Format: ifBinary; Name: 'Binary'; ChannelCount: 1; HasAlphaChannel: False; IsSpecial: True; GetPixelsSize: GetBinaryPixelsSize; CheckDimensions: CheckStdDimensions; SpecialNearestFormat: ifGray8); {$WARNINGS ON} function PixelFormat(ABitCount, RBitCount, GBitCount, BBitCount: Byte): TPixelFormatInfo; forward; procedure InitImageFormats(var Infos: TImageFormatInfoArray); begin FInfos := @Infos; Infos[ifDefault] := @A8R8G8B8Info; // indexed formats Infos[ifIndex8] := @Index8Info; // grayscale formats Infos[ifGray8] := @Gray8Info; Infos[ifA8Gray8] := @A8Gray8Info; Infos[ifGray16] := @Gray16Info; Infos[ifGray32] := @Gray32Info; Infos[ifGray64] := @Gray64Info; Infos[ifA16Gray16] := @A16Gray16Info; // ARGB formats Infos[ifX5R1G1B1] := @X5R1G1B1Info; Infos[ifR3G3B2] := @R3G3B2Info; Infos[ifR5G6B5] := @R5G6B5Info; Infos[ifA1R5G5B5] := @A1R5G5B5Info; Infos[ifA4R4G4B4] := @A4R4G4B4Info; Infos[ifX1R5G5B5] := @X1R5G5B5Info; Infos[ifX4R4G4B4] := @X4R4G4B4Info; Infos[ifR8G8B8] := @R8G8B8Info; Infos[ifA8R8G8B8] := @A8R8G8B8Info; Infos[ifX8R8G8B8] := @X8R8G8B8Info; Infos[ifR16G16B16] := @R16G16B16Info; Infos[ifA16R16G16B16] := @A16R16G16B16Info; Infos[ifB16G16R16] := @B16G16R16Info; Infos[ifA16B16G16R16] := @A16B16G16R16Info; // floating point formats Infos[ifR32F] := @R32FInfo; Infos[ifA32R32G32B32F] := @A32R32G32B32FInfo; Infos[ifA32B32G32R32F] := @A32B32G32R32FInfo; Infos[ifR16F] := @R16FInfo; Infos[ifA16R16G16B16F] := @A16R16G16B16FInfo; Infos[ifA16B16G16R16F] := @A16B16G16R16FInfo; Infos[ifR32G32B32F] := @R32G32B32FInfo; Infos[ifB32G32R32F] := @B32G32R32FInfo; // special formats Infos[ifDXT1] := @DXT1Info; Infos[ifDXT3] := @DXT3Info; Infos[ifDXT5] := @DXT5Info; Infos[ifBTC] := @BTCInfo; Infos[ifATI1N] := @ATI1NInfo; Infos[ifATI2N] := @ATI2NInfo; Infos[ifBinary] := @BinaryInfo; PFR3G3B2 := PixelFormat(0, 3, 3, 2); PFX5R1G1B1 := PixelFormat(0, 1, 1, 1); PFR5G6B5 := PixelFormat(0, 5, 6, 5); PFA1R5G5B5 := PixelFormat(1, 5, 5, 5); PFA4R4G4B4 := PixelFormat(4, 4, 4, 4); PFX1R5G5B5 := PixelFormat(0, 5, 5, 5); PFX4R4G4B4 := PixelFormat(0, 4, 4, 4); end; { Internal unit helper functions } function PixelFormat(ABitCount, RBitCount, GBitCount, BBitCount: Byte): TPixelFormatInfo; begin Result.ABitMask := ((1 shl ABitCount) - 1) shl (RBitCount + GBitCount + BBitCount); Result.RBitMask := ((1 shl RBitCount) - 1) shl (GBitCount + BBitCount); Result.GBitMask := ((1 shl GBitCount) - 1) shl (BBitCount); Result.BBitMask := (1 shl BBitCount) - 1; Result.ABitCount := ABitCount; Result.RBitCount := RBitCount; Result.GBitCount := GBitCount; Result.BBitCount := BBitCount; Result.AShift := RBitCount + GBitCount + BBitCount; Result.RShift := GBitCount + BBitCount; Result.GShift := BBitCount; Result.BShift := 0; Result.ARecDiv := Max(1, Pow2Int(Result.ABitCount) - 1); Result.RRecDiv := Max(1, Pow2Int(Result.RBitCount) - 1); Result.GRecDiv := Max(1, Pow2Int(Result.GBitCount) - 1); Result.BRecDiv := Max(1, Pow2Int(Result.BBitCount) - 1); end; function PixelFormatMask(ABitMask, RBitMask, GBitMask, BBitMask: LongWord): TPixelFormatInfo; function GetBitCount(B: LongWord): LongWord; var I: LongWord; begin I := 0; while (I < 31) and (((1 shl I) and B) = 0) do Inc(I); Result := 0; while ((1 shl I) and B) <> 0 do begin Inc(I); Inc(Result); end; end; begin Result := PixelFormat(GetBitCount(ABitMask), GetBitCount(RBitMask), GetBitCount(GBitMask), GetBitCount(BBitMask)); end; function PFSetARGB(const PF: TPixelFormatInfo; A, R, G, B: Byte): TColor32; {$IFDEF USE_INLINE}inline;{$ENDIF} begin with PF do Result := (A shl ABitCount shr 8 shl AShift) or (R shl RBitCount shr 8 shl RShift) or (G shl GBitCount shr 8 shl GShift) or (B shl BBitCount shr 8 shl BShift); end; procedure PFGetARGB(const PF: TPixelFormatInfo; Color: LongWord; var A, R, G, B: Byte); {$IFDEF USE_INLINE}inline;{$ENDIF} begin with PF do begin A := (Color and ABitMask shr AShift) * 255 div ARecDiv; R := (Color and RBitMask shr RShift) * 255 div RRecDiv; G := (Color and GBitMask shr GShift) * 255 div GRecDiv; B := (Color and BBitMask shl BShift) * 255 div BRecDiv; end; end; function PFSetColor(const PF: TPixelFormatInfo; ARGB: TColor32): LongWord; {$IFDEF USE_INLINE}inline;{$ENDIF} begin with PF do Result := (Byte(ARGB shr 24) shl ABitCount shr 8 shl AShift) or (Byte(ARGB shr 16) shl RBitCount shr 8 shl RShift) or (Byte(ARGB shr 8) shl GBitCount shr 8 shl GShift) or (Byte(ARGB) shl BBitCount shr 8 shl BShift); end; function PFGetColor(const PF: TPixelFormatInfo; Color: LongWord): TColor32; {$IFDEF USE_INLINE}inline;{$ENDIF} begin with PF, TColor32Rec(Result) do begin A := (Color and ABitMask shr AShift) * 255 div ARecDiv; R := (Color and RBitMask shr RShift) * 255 div RRecDiv; G := (Color and GBitMask shr GShift) * 255 div GRecDiv; B := (Color and BBitMask shl BShift) * 255 div BRecDiv; end; end; { Color constructor functions } function Color24(R, G, B: Byte): TColor24Rec; begin Result.R := R; Result.G := G; Result.B := B; end; function Color32(A, R, G, B: Byte): TColor32Rec; begin Result.A := A; Result.R := R; Result.G := G; Result.B := B; end; function Color48(R, G, B: Word): TColor48Rec; begin Result.R := R; Result.G := G; Result.B := B; end; function Color64(A, R, G, B: Word): TColor64Rec; begin Result.A := A; Result.R := R; Result.G := G; Result.B := B; end; function ColorFP(A, R, G, B: Single): TColorFPRec; begin Result.A := A; Result.R := R; Result.G := G; Result.B := B; end; function ColorHF(A, R, G, B: THalfFloat): TColorHFRec; begin Result.A := A; Result.R := R; Result.G := G; Result.B := B; end; { Additional image manipulation functions (usually used internally by Imaging unit) } const MaxPossibleColors = 4096; HashSize = 32768; AlphaWeight = 1024; RedWeight = 612; GreenWeight = 1202; BlueWeight = 234; type PColorBin = ^TColorBin; TColorBin = record Color: TColor32Rec; Number: LongInt; Next: PColorBin; end; THashTable = array[0..HashSize - 1] of PColorBin; TColorBox = record AMin, AMax, RMin, RMax, GMin, GMax, BMin, BMax: LongInt; Total: LongInt; Represented: TColor32Rec; List: PColorBin; end; var Table: THashTable; Box: array[0..MaxPossibleColors - 1] of TColorBox; Boxes: LongInt; BoxesCreated: Boolean = False; procedure ReduceColorsMedianCut(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo; MaxColors: LongInt; ChannelMask: Byte; DstPal: PPalette32; Actions: TReduceColorsActions); procedure CreateHistogram (Src: PByte; SrcInfo: PImageFormatInfo; ChannelMask: Byte); var A, R, G, B: Byte; I, Addr: LongInt; PC: PColorBin; Col: TColor32Rec; begin for I := 0 to NumPixels - 1 do begin Col := GetPixel32Generic(Src, SrcInfo, nil); A := Col.A and ChannelMask; R := Col.R and ChannelMask; G := Col.G and ChannelMask; B := Col.B and ChannelMask; Addr := (A + 11 * B + 59 * R + 119 * G) mod HashSize; PC := Table[Addr]; while (PC <> nil) and ((PC.Color.R <> R) or (PC.Color.G <> G) or (PC.Color.B <> B) or (PC.Color.A <> A)) do PC := PC.Next; if PC = nil then begin New(PC); PC.Color.R := R; PC.Color.G := G; PC.Color.B := B; PC.Color.A := A; PC.Number := 1; PC.Next := Table[Addr]; Table[Addr] := PC; end else Inc(PC^.Number); Inc(Src, SrcInfo.BytesPerPixel); end; end; procedure InitBox (var Box : TColorBox); begin Box.AMin := 256; Box.RMin := 256; Box.GMin := 256; Box.BMin := 256; Box.AMax := -1; Box.RMax := -1; Box.GMax := -1; Box.BMax := -1; Box.Total := 0; Box.List := nil; end; procedure ChangeBox (var Box: TColorBox; const C: TColorBin); begin with C.Color do begin if A < Box.AMin then Box.AMin := A; if A > Box.AMax then Box.AMax := A; if B < Box.BMin then Box.BMin := B; if B > Box.BMax then Box.BMax := B; if G < Box.GMin then Box.GMin := G; if G > Box.GMax then Box.GMax := G; if R < Box.RMin then Box.RMin := R; if R > Box.RMax then Box.RMax := R; end; Inc(Box.Total, C.Number); end; procedure MakeColormap; var I, J: LongInt; CP, Pom: PColorBin; Cut, LargestIdx, Largest, Size, S: LongInt; CutA, CutR, CutG, CutB: Boolean; SumA, SumR, SumG, SumB: LongInt; Temp: TColorBox; begin I := 0; Boxes := 1; LargestIdx := 0; while (I < HashSize) and (Table[I] = nil) do Inc(i); if I < HashSize then begin // put all colors into Box[0] InitBox(Box[0]); repeat CP := Table[I]; while CP.Next <> nil do begin ChangeBox(Box[0], CP^); CP := CP.Next; end; ChangeBox(Box[0], CP^); CP.Next := Box[0].List; Box[0].List := Table[I]; Table[I] := nil; repeat Inc(I) until (I = HashSize) or (Table[I] <> nil); until I = HashSize; // now all colors are in Box[0] repeat // cut one color box Largest := 0; for I := 0 to Boxes - 1 do with Box[I] do begin Size := (AMax - AMin) * AlphaWeight; S := (RMax - RMin) * RedWeight; if S > Size then Size := S; S := (GMax - GMin) * GreenWeight; if S > Size then Size := S; S := (BMax - BMin) * BlueWeight; if S > Size then Size := S; if Size > Largest then begin Largest := Size; LargestIdx := I; end; end; if Largest > 0 then begin // cutting Box[LargestIdx] into Box[LargestIdx] and Box[Boxes] CutR := False; CutG := False; CutB := False; CutA := False; with Box[LargestIdx] do begin if (AMax - AMin) * AlphaWeight = Largest then begin Cut := (AMax + AMin) shr 1; CutA := True; end else if (RMax - RMin) * RedWeight = Largest then begin Cut := (RMax + RMin) shr 1; CutR := True; end else if (GMax - GMin) * GreenWeight = Largest then begin Cut := (GMax + GMin) shr 1; CutG := True; end else begin Cut := (BMax + BMin) shr 1; CutB := True; end; CP := List; end; InitBox(Box[LargestIdx]); InitBox(Box[Boxes]); repeat // distribute one color Pom := CP.Next; with CP.Color do begin if (CutA and (A <= Cut)) or (CutR and (R <= Cut)) or (CutG and (G <= Cut)) or (CutB and (B <= Cut)) then I := LargestIdx else I := Boxes; end; CP.Next := Box[i].List; Box[i].List := CP; ChangeBox(Box[i], CP^); CP := Pom; until CP = nil; Inc(Boxes); end; until (Boxes = MaxColors) or (Largest = 0); // compute box representation for I := 0 to Boxes - 1 do begin SumR := 0; SumG := 0; SumB := 0; SumA := 0; repeat CP := Box[I].List; Inc(SumR, CP.Color.R * CP.Number); Inc(SumG, CP.Color.G * CP.Number); Inc(SumB, CP.Color.B * CP.Number); Inc(SumA, CP.Color.A * CP.Number); Box[I].List := CP.Next; Dispose(CP); until Box[I].List = nil; with Box[I] do begin Represented.A := SumA div Total; Represented.R := SumR div Total; Represented.G := SumG div Total; Represented.B := SumB div Total; AMin := AMin and ChannelMask; RMin := RMin and ChannelMask; GMin := GMin and ChannelMask; BMin := BMin and ChannelMask; AMax := (AMax and ChannelMask) + (not ChannelMask); RMax := (RMax and ChannelMask) + (not ChannelMask); GMax := (GMax and ChannelMask) + (not ChannelMask); BMax := (BMax and ChannelMask) + (not ChannelMask); end; end; // sort color boxes for I := 0 to Boxes - 2 do begin Largest := 0; for J := I to Boxes - 1 do if Box[J].Total > Largest then begin Largest := Box[J].Total; LargestIdx := J; end; if LargestIdx <> I then begin Temp := Box[I]; Box[I] := Box[LargestIdx]; Box[LargestIdx] := Temp; end; end; end; end; procedure FillOutputPalette; var I: LongInt; begin FillChar(DstPal^, SizeOf(TColor32Rec) * MaxColors, $FF); for I := 0 to MaxColors - 1 do begin if I < Boxes then with Box[I].Represented do begin DstPal[I].A := A; DstPal[I].R := R; DstPal[I].G := G; DstPal[I].B := B; end else DstPal[I].Color := $FF000000; end; end; function MapColor(const Col: TColor32Rec) : LongInt; var I: LongInt; begin I := 0; with Col do while (I < Boxes) and ((Box[I].AMin > A) or (Box[I].AMax < A) or (Box[I].RMin > R) or (Box[I].RMax < R) or (Box[I].GMin > G) or (Box[I].GMax < G) or (Box[I].BMin > B) or (Box[I].BMax < B)) do Inc(I); if I = Boxes then MapColor := 0 else MapColor := I; end; procedure MapImage(Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo); var I: LongInt; Col: TColor32Rec; begin for I := 0 to NumPixels - 1 do begin Col := GetPixel32Generic(Src, SrcInfo, nil); IndexSetDstPixel(Dst, DstInfo, MapColor(Col)); Inc(Src, SrcInfo.BytesPerPixel); Inc(Dst, DstInfo.BytesPerPixel); end; end; begin MaxColors := ClampInt(MaxColors, 2, MaxPossibleColors); if (raUpdateHistogram in Actions) or (raMapImage in Actions) then begin Assert(not SrcInfo.IsSpecial); Assert(not SrcInfo.IsIndexed); end; if raCreateHistogram in Actions then FillChar(Table, SizeOf(Table), 0); if raUpdateHistogram in Actions then CreateHistogram(Src, SrcInfo, ChannelMask); if raMakeColorMap in Actions then begin MakeColorMap; FillOutputPalette; end; if raMapImage in Actions then MapImage(Src, Dst, SrcInfo, DstInfo); end; procedure StretchNearest(const SrcImage: TImageData; SrcX, SrcY, SrcWidth, SrcHeight: LongInt; var DstImage: TImageData; DstX, DstY, DstWidth, DstHeight: LongInt); var Info: TImageFormatInfo; ScaleX, ScaleY, X, Y, Xp, Yp: LongInt; DstPixel, SrcLine: PByte; begin GetImageFormatInfo(SrcImage.Format, Info); Assert(SrcImage.Format = DstImage.Format); Assert(not Info.IsSpecial); // Use integers instead of floats for source image pixel coords // Xp and Yp coords must be shifted right to get read source image coords ScaleX := (SrcWidth shl 16) div DstWidth; ScaleY := (SrcHeight shl 16) div DstHeight; Yp := 0; for Y := 0 to DstHeight - 1 do begin Xp := 0; SrcLine := @PByteArray(SrcImage.Bits)[((SrcY + Yp shr 16) * SrcImage.Width + SrcX) * Info.BytesPerPixel]; DstPixel := @PByteArray(DstImage.Bits)[((DstY + Y) * DstImage.Width + DstX) * Info.BytesPerPixel]; for X := 0 to DstWidth - 1 do begin case Info.BytesPerPixel of 1: PByte(DstPixel)^ := PByteArray(SrcLine)[Xp shr 16]; 2: PWord(DstPixel)^ := PWordArray(SrcLine)[Xp shr 16]; 3: PColor24Rec(DstPixel)^ := PPalette24(SrcLine)[Xp shr 16]; 4: PColor32(DstPixel)^ := PLongWordArray(SrcLine)[Xp shr 16]; 6: PColor48Rec(DstPixel)^ := PColor48RecArray(SrcLine)[Xp shr 16]; 8: PColor64(DstPixel)^ := PInt64Array(SrcLine)[Xp shr 16]; 16: PColorFPRec(DstPixel)^ := PColorFPRecArray(SrcLine)[Xp shr 16]; end; Inc(DstPixel, Info.BytesPerPixel); Inc(Xp, ScaleX); end; Inc(Yp, ScaleY); end; end; { Filter function for nearest filtering. Also known as box filter.} function FilterNearest(Value: Single): Single; begin if (Value > -0.5) and (Value <= 0.5) then Result := 1 else Result := 0; end; { Filter function for linear filtering. Also known as triangle or Bartlett filter.} function FilterLinear(Value: Single): Single; begin if Value < 0.0 then Value := -Value; if Value < 1.0 then Result := 1.0 - Value else Result := 0.0; end; { Cosine filter.} function FilterCosine(Value: Single): Single; begin Result := 0; if Abs(Value) < 1 then Result := (Cos(Value * Pi) + 1) / 2; end; { f(t) = 2|t|^3 - 3|t|^2 + 1, -1 <= t <= 1 } function FilterHermite(Value: Single): Single; begin if Value < 0.0 then Value := -Value; if Value < 1 then Result := (2 * Value - 3) * Sqr(Value) + 1 else Result := 0; end; { Quadratic filter. Also known as Bell.} function FilterQuadratic(Value: Single): Single; begin if Value < 0.0 then Value := -Value; if Value < 0.5 then Result := 0.75 - Sqr(Value) else if Value < 1.5 then begin Value := Value - 1.5; Result := 0.5 * Sqr(Value); end else Result := 0.0; end; { Gaussian filter.} function FilterGaussian(Value: Single): Single; begin Result := Exp(-2.0 * Sqr(Value)) * Sqrt(2.0 / Pi); end; { 4th order (cubic) b-spline filter.} function FilterSpline(Value: Single): Single; var Temp: Single; begin if Value < 0.0 then Value := -Value; if Value < 1.0 then begin Temp := Sqr(Value); Result := 0.5 * Temp * Value - Temp + 2.0 / 3.0; end else if Value < 2.0 then begin Value := 2.0 - Value; Result := Sqr(Value) * Value / 6.0; end else Result := 0.0; end; { Lanczos-windowed sinc filter.} function FilterLanczos(Value: Single): Single; function SinC(Value: Single): Single; begin if Value <> 0.0 then begin Value := Value * Pi; Result := Sin(Value) / Value; end else Result := 1.0; end; begin if Value < 0.0 then Value := -Value; if Value < 3.0 then Result := SinC(Value) * SinC(Value / 3.0) else Result := 0.0; end; { Micthell cubic filter.} function FilterMitchell(Value: Single): Single; const B = 1.0 / 3.0; C = 1.0 / 3.0; var Temp: Single; begin if Value < 0.0 then Value := -Value; Temp := Sqr(Value); if Value < 1.0 then begin Value := (((12.0 - 9.0 * B - 6.0 * C) * (Value * Temp)) + ((-18.0 + 12.0 * B + 6.0 * C) * Temp) + (6.0 - 2.0 * B)); Result := Value / 6.0; end else if Value < 2.0 then begin Value := (((-B - 6.0 * C) * (Value * Temp)) + ((6.0 * B + 30.0 * C) * Temp) + ((-12.0 * B - 48.0 * C) * Value) + (8.0 * B + 24.0 * C)); Result := Value / 6.0; end else Result := 0.0; end; { CatmullRom spline filter.} function FilterCatmullRom(Value: Single): Single; begin if Value < 0.0 then Value := -Value; if Value < 1.0 then Result := 0.5 * (2.0 + Sqr(Value) * (-5.0 + 3.0 * Value)) else if Value < 2.0 then Result := 0.5 * (4.0 + Value * (-8.0 + Value * (5.0 - Value))) else Result := 0.0; end; procedure StretchResample(const SrcImage: TImageData; SrcX, SrcY, SrcWidth, SrcHeight: LongInt; var DstImage: TImageData; DstX, DstY, DstWidth, DstHeight: LongInt; Filter: TSamplingFilter; WrapEdges: Boolean); begin // Calls the other function with filter function and radius defined by Filter StretchResample(SrcImage, SrcX, SrcY, SrcWidth, SrcHeight, DstImage, DstX, DstY, DstWidth, DstHeight, SamplingFilterFunctions[Filter], SamplingFilterRadii[Filter], WrapEdges); end; var FullEdge: Boolean = True; { The following resampling code is modified and extended code from Graphics32 library by Alex A. Denisov.} function BuildMappingTable(DstLow, DstHigh, SrcLow, SrcHigh, SrcImageWidth: LongInt; Filter: TFilterFunction; Radius: Single; WrapEdges: Boolean): TMappingTable; var I, J, K, N: LongInt; Left, Right, SrcWidth, DstWidth: LongInt; Weight, Scale, Center, Count: Single; begin Result := nil; K := 0; SrcWidth := SrcHigh - SrcLow; DstWidth := DstHigh - DstLow; // Check some special cases if SrcWidth = 1 then begin SetLength(Result, DstWidth); for I := 0 to DstWidth - 1 do begin SetLength(Result[I], 1); Result[I][0].Pos := 0; Result[I][0].Weight := 1.0; end; Exit; end else if (SrcWidth = 0) or (DstWidth = 0) then Exit; if FullEdge then Scale := DstWidth / SrcWidth else Scale := (DstWidth - 1) / (SrcWidth - 1); SetLength(Result, DstWidth); // Pre-calculate filter contributions for a row or column if Scale = 0.0 then begin Assert(Length(Result) = 1); SetLength(Result[0], 1); Result[0][0].Pos := (SrcLow + SrcHigh) div 2; Result[0][0].Weight := 1.0; end else if Scale < 1.0 then begin // Sub-sampling - scales from bigger to smaller Radius := Radius / Scale; for I := 0 to DstWidth - 1 do begin if FullEdge then Center := SrcLow - 0.5 + (I + 0.5) / Scale else Center := SrcLow + I / Scale; Left := Floor(Center - Radius); Right := Ceil(Center + Radius); Count := -1.0; for J := Left to Right do begin Weight := Filter((Center - J) * Scale) * Scale; if Weight <> 0.0 then begin Count := Count + Weight; K := Length(Result[I]); SetLength(Result[I], K + 1); Result[I][K].Pos := ClampInt(J, SrcLow, SrcHigh - 1); Result[I][K].Weight := Weight; end; end; if Length(Result[I]) = 0 then begin SetLength(Result[I], 1); Result[I][0].Pos := Floor(Center); Result[I][0].Weight := 1.0; end else if Count <> 0.0 then Result[I][K div 2].Weight := Result[I][K div 2].Weight - Count; end; end else // if Scale > 1.0 then begin // Super-sampling - scales from smaller to bigger Scale := 1.0 / Scale; for I := 0 to DstWidth - 1 do begin if FullEdge then Center := SrcLow - 0.5 + (I + 0.5) * Scale else Center := SrcLow + I * Scale; Left := Floor(Center - Radius); Right := Ceil(Center + Radius); Count := -1.0; for J := Left to Right do begin Weight := Filter(Center - J); if Weight <> 0.0 then begin Count := Count + Weight; K := Length(Result[I]); SetLength(Result[I], K + 1); if WrapEdges then begin if J < 0 then N := SrcImageWidth + J else if J >= SrcImageWidth then N := J - SrcImageWidth else N := ClampInt(J, SrcLow, SrcHigh - 1); end else N := ClampInt(J, SrcLow, SrcHigh - 1); Result[I][K].Pos := N; Result[I][K].Weight := Weight; end; end; if Count <> 0.0 then Result[I][K div 2].Weight := Result[I][K div 2].Weight - Count; end; end; end; procedure FindExtremes(const Map: TMappingTable; var MinPos, MaxPos: LongInt); var I, J: LongInt; begin if Length(Map) > 0 then begin MinPos := Map[0][0].Pos; MaxPos := MinPos; for I := 0 to Length(Map) - 1 do for J := 0 to Length(Map[I]) - 1 do begin if MinPos > Map[I][J].Pos then MinPos := Map[I][J].Pos; if MaxPos < Map[I][J].Pos then MaxPos := Map[I][J].Pos; end; end; end; procedure StretchResample(const SrcImage: TImageData; SrcX, SrcY, SrcWidth, SrcHeight: LongInt; var DstImage: TImageData; DstX, DstY, DstWidth, DstHeight: LongInt; Filter: TFilterFunction; Radius: Single; WrapEdges: Boolean); const Channel8BitMax: Single = 255.0; var MapX, MapY: TMappingTable; I, J, X, Y: LongInt; XMinimum, XMaximum: LongInt; LineBufferFP: array of TColorFPRec; ClusterX, ClusterY: TCluster; Weight, AccumA, AccumR, AccumG, AccumB: Single; DstLine: PByte; SrcFloat: TColorFPRec; Info: TImageFormatInfo; BytesPerChannel: LongInt; begin GetImageFormatInfo(SrcImage.Format, Info); Assert(SrcImage.Format = DstImage.Format); Assert(not Info.IsSpecial and not Info.IsIndexed); BytesPerChannel := Info.BytesPerPixel div Info.ChannelCount; // Create horizontal and vertical mapping tables MapX := BuildMappingTable(DstX, DstX + DstWidth, SrcX, SrcX + SrcWidth, SrcImage.Width, Filter, Radius, WrapEdges); MapY := BuildMappingTable(DstY, DstY + DstHeight, SrcY, SrcY + SrcHeight, SrcImage.Height, Filter, Radius, WrapEdges); if (MapX = nil) or (MapY = nil) then Exit; ClusterX := nil; ClusterY := nil; try // Find min and max X coords of pixels that will contribute to target image FindExtremes(MapX, XMinimum, XMaximum); SetLength(LineBufferFP, XMaximum - XMinimum + 1); // Following code works for the rest of data formats for J := 0 to DstHeight - 1 do begin // First for each pixel in the current line sample vertically // and store results in LineBuffer. Then sample horizontally // using values in LineBuffer. ClusterY := MapY[J]; for X := XMinimum to XMaximum do begin // Clear accumulators AccumA := 0; AccumR := 0; AccumG := 0; AccumB := 0; // For each pixel in line compute weighted sum of pixels // in source column that will contribute to this pixel for Y := 0 to Length(ClusterY) - 1 do begin // Accumulate this pixel's weighted value Weight := ClusterY[Y].Weight; SrcFloat := Info.GetPixelFP(@PByteArray(SrcImage.Bits)[(ClusterY[Y].Pos * SrcImage.Width + X) * Info.BytesPerPixel], @Info, nil); AccumB := AccumB + SrcFloat.B * Weight; AccumG := AccumG + SrcFloat.G * Weight; AccumR := AccumR + SrcFloat.R * Weight; AccumA := AccumA + SrcFloat.A * Weight; end; // Store accumulated value for this pixel in buffer with LineBufferFP[X - XMinimum] do begin A := AccumA; R := AccumR; G := AccumG; B := AccumB; end; end; DstLine := @PByteArray(DstImage.Bits)[((J + DstY) * DstImage.Width + DstX) * Info.BytesPerPixel]; // Now compute final colors for targte pixels in the current row // by sampling horizontally for I := 0 to DstWidth - 1 do begin ClusterX := MapX[I]; // Clear accumulator AccumA := 0; AccumR := 0; AccumG := 0; AccumB := 0; // Compute weighted sum of values (which are already // computed weighted sums of pixels in source columns stored in LineBuffer) // that will contribute to the current target pixel for X := 0 to Length(ClusterX) - 1 do begin Weight := ClusterX[X].Weight; with LineBufferFP[ClusterX[X].Pos - XMinimum] do begin AccumB := AccumB + B * Weight; AccumG := AccumG + G * Weight; AccumR := AccumR + R * Weight; AccumA := AccumA + A * Weight; end; end; // Now compute final color to be written to dest image SrcFloat.A := AccumA; SrcFloat.R := AccumR; SrcFloat.G := AccumG; SrcFloat.B := AccumB; Info.SetPixelFP(DstLine, @Info, nil, SrcFloat); Inc(DstLine, Info.BytesPerPixel); end; end; finally MapX := nil; MapY := nil; end; end; procedure FillMipMapLevel(const BiggerLevel: TImageData; Width, Height: LongInt; var SmallerLevel: TImageData); var Filter: TSamplingFilter; Info: TImageFormatInfo; CompatibleCopy: TImageData; begin Assert(TestImage(BiggerLevel)); Filter := TSamplingFilter(GetOption(ImagingMipMapFilter)); // If we have special format image we must create copy to allow pixel access GetImageFormatInfo(BiggerLevel.Format, Info); if Info.IsSpecial then begin InitImage(CompatibleCopy); CloneImage(BiggerLevel, CompatibleCopy); ConvertImage(CompatibleCopy, ifDefault); end else CompatibleCopy := BiggerLevel; // Create new smaller image NewImage(Width, Height, CompatibleCopy.Format, SmallerLevel); GetImageFormatInfo(CompatibleCopy.Format, Info); // If input is indexed we must copy its palette if Info.IsIndexed then CopyPalette(CompatibleCopy.Palette, SmallerLevel.Palette, 0, 0, Info.PaletteEntries); if (Filter = sfNearest) or Info.IsIndexed then begin StretchNearest(CompatibleCopy, 0, 0, CompatibleCopy.Width, CompatibleCopy.Height, SmallerLevel, 0, 0, Width, Height); end else begin StretchResample(CompatibleCopy, 0, 0, CompatibleCopy.Width, CompatibleCopy.Height, SmallerLevel, 0, 0, Width, Height, Filter); end; // Free copy and convert result to special format if necessary if CompatibleCopy.Format <> BiggerLevel.Format then begin ConvertImage(SmallerLevel, BiggerLevel.Format); FreeImage(CompatibleCopy); end; end; { Various format support functions } procedure CopyPixel(Src, Dest: Pointer; BytesPerPixel: LongInt); begin case BytesPerPixel of 1: PByte(Dest)^ := PByte(Src)^; 2: PWord(Dest)^ := PWord(Src)^; 3: PColor24Rec(Dest)^ := PColor24Rec(Src)^; 4: PLongWord(Dest)^ := PLongWord(Src)^; 6: PColor48Rec(Dest)^ := PColor48Rec(Src)^; 8: PInt64(Dest)^ := PInt64(Src)^; 12: PColor96FPRec(Dest)^ := PColor96FPRec(Src)^; 16: PColorFPRec(Dest)^ := PColorFPRec(Src)^; end; end; function ComparePixels(PixelA, PixelB: Pointer; BytesPerPixel: LongInt): Boolean; begin case BytesPerPixel of 1: Result := PByte(PixelA)^ = PByte(PixelB)^; 2: Result := PWord(PixelA)^ = PWord(PixelB)^; 3: Result := (PWord(PixelA)^ = PWord(PixelB)^) and (PColor24Rec(PixelA).R = PColor24Rec(PixelB).R); 4: Result := PLongWord(PixelA)^ = PLongWord(PixelB)^; 6: Result := (PLongWord(PixelA)^ = PLongWord(PixelB)^) and (PColor48Rec(PixelA).R = PColor48Rec(PixelB).R); 8: Result := PInt64(PixelA)^ = PInt64(PixelB)^; 12: Result := (PFloatHelper(PixelA).Data = PFloatHelper(PixelB).Data) and (PFloatHelper(PixelA).Data32 = PFloatHelper(PixelB).Data32); 16: Result := (PFloatHelper(PixelA).Data = PFloatHelper(PixelB).Data) and (PFloatHelper(PixelA).Data64 = PFloatHelper(PixelB).Data64); else Result := False; end; end; procedure TranslatePixel(SrcPixel, DstPixel: Pointer; SrcFormat, DstFormat: TImageFormat; SrcPalette, DstPalette: PPalette32); var SrcInfo, DstInfo: PImageFormatInfo; PixFP: TColorFPRec; begin SrcInfo := FInfos[SrcFormat]; DstInfo := FInfos[DstFormat]; PixFP := GetPixelFPGeneric(SrcPixel, SrcInfo, SrcPalette); SetPixelFPGeneric(DstPixel, DstInfo, DstPalette, PixFP); end; procedure ClampFloatPixel(var PixF: TColorFPRec); begin if PixF.A > 1.0 then PixF.A := 1.0; if PixF.R > 1.0 then PixF.R := 1.0; if PixF.G > 1.0 then PixF.G := 1.0; if PixF.B > 1.0 then PixF.B := 1.0; if PixF.A < 0.0 then PixF.A := 0.0; if PixF.R < 0.0 then PixF.R := 0.0; if PixF.G < 0.0 then PixF.G := 0.0; if PixF.B < 0.0 then PixF.B := 0.0; end; procedure ConvertToPixel32(SrcPix: PByte; DestPix: PColor32Rec; const SrcInfo: TImageFormatInfo; SrcPalette: PPalette32); begin case SrcInfo.Format of ifIndex8: begin DestPix^ := SrcPalette[SrcPix^]; end; ifGray8: begin DestPix.R := SrcPix^; DestPix.G := SrcPix^; DestPix.B := SrcPix^; DestPix.A := 255; end; ifA8Gray8: begin DestPix.R := SrcPix^; DestPix.G := SrcPix^; DestPix.B := SrcPix^; DestPix.A := PWordRec(SrcPix).High; end; ifGray16: begin DestPix.R := PWord(SrcPix)^ shr 8; DestPix.G := DestPix.R; DestPix.B := DestPix.R; DestPix.A := 255; end; ifR8G8B8: begin DestPix.Color24Rec := PColor24Rec(SrcPix)^; DestPix.A := 255; end; ifA8R8G8B8: begin DestPix^ := PColor32Rec(SrcPix)^; end; ifR16G16B16: begin DestPix.R := PColor48Rec(SrcPix).R shr 8; DestPix.G := PColor48Rec(SrcPix).G shr 8; DestPix.B := PColor48Rec(SrcPix).B shr 8; DestPix.A := 255; end; ifA16R16G16B16: begin DestPix.R := PColor64Rec(SrcPix).R shr 8; DestPix.G := PColor64Rec(SrcPix).G shr 8; DestPix.B := PColor64Rec(SrcPix).B shr 8; DestPix.A := PColor64Rec(SrcPix).A shr 8; end; else DestPix^ := SrcInfo.GetPixel32(SrcPix, @SrcInfo, SrcPalette); end; end; procedure AddPadBytes(DataIn: Pointer; DataOut: Pointer; Width, Height, Bpp, WidthBytes: LongInt); var I, W: LongInt; begin W := Width * Bpp; for I := 0 to Height - 1 do Move(PByteArray(DataIn)[I * W], PByteArray(DataOut)[I * WidthBytes], W); end; procedure RemovePadBytes(DataIn: Pointer; DataOut: Pointer; Width, Height, Bpp, WidthBytes: LongInt); var I, W: LongInt; begin W := Width * Bpp; for I := 0 to Height - 1 do Move(PByteArray(DataIn)[I * WidthBytes], PByteArray(DataOut)[I * W], W); end; procedure Convert1To8(DataIn, DataOut: PByte; Width, Height, WidthBytes: LongInt; ScaleTo8Bits: Boolean); const Mask1: array[0..7] of Byte = ($80, $40, $20, $10, $08, $04, $02, $01); Shift1: array[0..7] of Byte = (7, 6, 5, 4, 3, 2, 1, 0); Scaling: Byte = 255; var X, Y: LongInt; InArray: PByteArray absolute DataIn; begin for Y := 0 to Height - 1 do for X := 0 to Width - 1 do begin DataOut^ := (InArray[Y * WidthBytes + X shr 3] and Mask1[X and 7]) shr Shift1[X and 7]; if ScaleTo8Bits then DataOut^ := DataOut^ * Scaling; Inc(DataOut); end; end; procedure Convert2To8(DataIn, DataOut: PByte; Width, Height, WidthBytes: LongInt; ScaleTo8Bits: Boolean); const Mask2: array[0..3] of Byte = ($C0, $30, $0C, $03); Shift2: array[0..3] of Byte = (6, 4, 2, 0); Scaling: Byte = 85; var X, Y: LongInt; InArray: PByteArray absolute DataIn; begin for Y := 0 to Height - 1 do for X := 0 to Width - 1 do begin DataOut^ := (InArray[Y * WidthBytes + X shr 2] and Mask2[X and 3]) shr Shift2[X and 3]; if ScaleTo8Bits then DataOut^ := DataOut^ * Scaling; Inc(DataOut); end; end; procedure Convert4To8(DataIn, DataOut: PByte; Width, Height, WidthBytes: LongInt; ScaleTo8Bits: Boolean); const Mask4: array[0..1] of Byte = ($F0, $0F); Shift4: array[0..1] of Byte = (4, 0); Scaling: Byte = 17; var X, Y: LongInt; InArray: PByteArray absolute DataIn; begin for Y := 0 to Height - 1 do for X := 0 to Width - 1 do begin DataOut^ := (InArray[Y * WidthBytes + X shr 1] and Mask4[X and 1]) shr Shift4[X and 1]; if ScaleTo8Bits then DataOut^ := DataOut^ * Scaling; Inc(DataOut); end; end; function Has16BitImageAlpha(NumPixels: LongInt; Data: PWord): Boolean; var I: LongInt; begin Result := False; for I := 0 to NumPixels - 1 do begin if Data^ >= 1 shl 15 then begin Result := True; Exit; end; Inc(Data); end; end; function Has32BitImageAlpha(NumPixels: LongInt; Data: PLongWord): Boolean; var I: LongInt; begin Result := False; for I := 0 to NumPixels - 1 do begin if Data^ >= 1 shl 24 then begin Result := True; Exit; end; Inc(Data); end; end; function PaletteHasAlpha(Palette: PPalette32; PaletteEntries: Integer): Boolean; var I: Integer; begin for I := 0 to PaletteEntries - 1 do begin if Palette[I].A <> 255 then begin Result := True; Exit; end; end; Result := False; end; function GetScanLine(ImageBits: Pointer; const FormatInfo: TImageFormatInfo; LineWidth, Index: LongInt): Pointer; var LineBytes: LongInt; begin Assert(not FormatInfo.IsSpecial); LineBytes := FormatInfo.GetPixelsSize(FormatInfo.Format, LineWidth, 1); Result := @PByteArray(ImageBits)[Index * LineBytes]; end; function IsImageFormatValid(Format: TImageFormat): Boolean; begin Result := FInfos[Format] <> nil; end; const HalfMin: Single = 5.96046448e-08; // Smallest positive half HalfMinNorm: Single = 6.10351562e-05; // Smallest positive normalized half HalfMax: Single = 65504.0; // Largest positive half HalfEpsilon: Single = 0.00097656; // Smallest positive e for which half (1.0 + e) != half (1.0) HalfNaN: THalfFloat = 65535; HalfPosInf: THalfFloat = 31744; HalfNegInf: THalfFloat = 64512; { Half/Float conversions inspired by half class from OpenEXR library. Float (Pascal Single type) is an IEEE 754 single-precision floating point number. Bit layout of Single: 31 (msb) | | 30 23 | | | | | | 22 0 (lsb) | | | | | X XXXXXXXX XXXXXXXXXXXXXXXXXXXXXXX s e m Bit layout of half: 15 (msb) | | 14 10 | | | | | | 9 0 (lsb) | | | | | X XXXXX XXXXXXXXXX s e m S is the sign-bit, e is the exponent and m is the significand (mantissa). } function HalfToFloat(Half: THalfFloat): Single; var Dst, Sign, Mantissa: LongWord; Exp: LongInt; begin // Extract sign, exponent, and mantissa from half number Sign := Half shr 15; Exp := (Half and $7C00) shr 10; Mantissa := Half and 1023; if (Exp > 0) and (Exp < 31) then begin // Common normalized number Exp := Exp + (127 - 15); Mantissa := Mantissa shl 13; Dst := (Sign shl 31) or (LongWord(Exp) shl 23) or Mantissa; // Result := Power(-1, Sign) * Power(2, Exp - 15) * (1 + Mantissa / 1024); end else if (Exp = 0) and (Mantissa = 0) then begin // Zero - preserve sign Dst := Sign shl 31; end else if (Exp = 0) and (Mantissa <> 0) then begin // Denormalized number - renormalize it while (Mantissa and $00000400) = 0 do begin Mantissa := Mantissa shl 1; Dec(Exp); end; Inc(Exp); Mantissa := Mantissa and not $00000400; // Now assemble normalized number Exp := Exp + (127 - 15); Mantissa := Mantissa shl 13; Dst := (Sign shl 31) or (LongWord(Exp) shl 23) or Mantissa; // Result := Power(-1, Sign) * Power(2, -14) * (Mantissa / 1024); end else if (Exp = 31) and (Mantissa = 0) then begin // +/- infinity Dst := (Sign shl 31) or $7F800000; end else //if (Exp = 31) and (Mantisa <> 0) then begin // Not a number - preserve sign and mantissa Dst := (Sign shl 31) or $7F800000 or (Mantissa shl 13); end; // Reinterpret LongWord as Single Result := PSingle(@Dst)^; end; function FloatToHalf(Float: Single): THalfFloat; var Src: LongWord; Sign, Exp, Mantissa: LongInt; begin Src := PLongWord(@Float)^; // Extract sign, exponent, and mantissa from Single number Sign := Src shr 31; Exp := LongInt((Src and $7F800000) shr 23) - 127 + 15; Mantissa := Src and $007FFFFF; if (Exp > 0) and (Exp < 30) then begin // Simple case - round the significand and combine it with the sign and exponent Result := (Sign shl 15) or (Exp shl 10) or ((Mantissa + $00001000) shr 13); end else if Src = 0 then begin // Input float is zero - return zero Result := 0; end else begin // Difficult case - lengthy conversion if Exp <= 0 then begin if Exp < -10 then begin // Input float's value is less than HalfMin, return zero Result := 0; end else begin // Float is a normalized Single whose magnitude is less than HalfNormMin. // We convert it to denormalized half. Mantissa := (Mantissa or $00800000) shr (1 - Exp); // Round to nearest if (Mantissa and $00001000) > 0 then Mantissa := Mantissa + $00002000; // Assemble Sign and Mantissa (Exp is zero to get denormalized number) Result := (Sign shl 15) or (Mantissa shr 13); end; end else if Exp = 255 - 127 + 15 then begin if Mantissa = 0 then begin // Input float is infinity, create infinity half with original sign Result := (Sign shl 15) or $7C00; end else begin // Input float is NaN, create half NaN with original sign and mantissa Result := (Sign shl 15) or $7C00 or (Mantissa shr 13); end; end else begin // Exp is > 0 so input float is normalized Single // Round to nearest if (Mantissa and $00001000) > 0 then begin Mantissa := Mantissa + $00002000; if (Mantissa and $00800000) > 0 then begin Mantissa := 0; Exp := Exp + 1; end; end; if Exp > 30 then begin // Exponent overflow - return infinity half Result := (Sign shl 15) or $7C00; end else // Assemble normalized half Result := (Sign shl 15) or (Exp shl 10) or (Mantissa shr 13); end; end; end; function ColorHalfToFloat(ColorHF: TColorHFRec): TColorFPRec; begin Result.A := HalfToFloat(ColorHF.A); Result.R := HalfToFloat(ColorHF.R); Result.G := HalfToFloat(ColorHF.G); Result.B := HalfToFloat(ColorHF.B); end; function ColorFloatToHalf(ColorFP: TColorFPRec): TColorHFRec; begin Result.A := FloatToHalf(ColorFP.A); Result.R := FloatToHalf(ColorFP.R); Result.G := FloatToHalf(ColorFP.G); Result.B := FloatToHalf(ColorFP.B); end; procedure VisualizePalette(Pal: PPalette32; Entries: Integer; out PalImage: TImageData); var I: Integer; Pix: PColor32; begin InitImage(PalImage); NewImage(Entries, 1, ifA8R8G8B8, PalImage); Pix := PalImage.Bits; for I := 0 to Entries - 1 do begin Pix^ := Pal[I].Color; Inc(Pix); end; end; { Pixel readers/writers for different image formats } procedure ChannelGetSrcPixel(Src: PByte; SrcInfo: PImageFormatInfo; var Pix: TColor64Rec); var A, R, G, B: Byte; begin FillChar(Pix, SizeOf(Pix), 0); // returns 64 bit color value with 16 bits for each channel case SrcInfo.BytesPerPixel of 1: begin PFGetARGB(SrcInfo.PixelFormat^, Src^, A, R, G, B); Pix.A := A shl 8; Pix.R := R shl 8; Pix.G := G shl 8; Pix.B := B shl 8; end; 2: begin PFGetARGB(SrcInfo.PixelFormat^, PWord(Src)^, A, R, G, B); Pix.A := A shl 8; Pix.R := R shl 8; Pix.G := G shl 8; Pix.B := B shl 8; end; 3: with Pix do begin R := MulDiv(PColor24Rec(Src).R, 65535, 255); G := MulDiv(PColor24Rec(Src).G, 65535, 255); B := MulDiv(PColor24Rec(Src).B, 65535, 255); end; 4: with Pix do begin A := MulDiv(PColor32Rec(Src).A, 65535, 255); R := MulDiv(PColor32Rec(Src).R, 65535, 255); G := MulDiv(PColor32Rec(Src).G, 65535, 255); B := MulDiv(PColor32Rec(Src).B, 65535, 255); end; 6: with Pix do begin R := PColor48Rec(Src).R; G := PColor48Rec(Src).G; B := PColor48Rec(Src).B; end; 8: Pix.Color := PColor64(Src)^; end; // if src has no alpha, we set it to max (otherwise we would have to // test if dest has alpha or not in each ChannelToXXX function) if not SrcInfo.HasAlphaChannel then Pix.A := 65535; if SrcInfo.IsRBSwapped then SwapValues(Pix.R, Pix.B); end; procedure ChannelSetDstPixel(Dst: PByte; DstInfo: PImageFormatInfo; const Pix: TColor64Rec); var PixW: TColor64Rec; begin PixW := Pix; if DstInfo.IsRBSwapped then SwapValues(PixW.R, PixW.B); // Pix contains 64 bit color value with 16 bit for each channel case DstInfo.BytesPerPixel of 1: Dst^ := PFSetARGB(DstInfo.PixelFormat^, PixW.A shr 8, PixW.R shr 8, PixW.G shr 8, PixW.B shr 8); 2: PWord(Dst)^ := PFSetARGB(DstInfo.PixelFormat^, PixW.A shr 8, PixW.R shr 8, PixW.G shr 8, PixW.B shr 8); 3: with PColor24Rec(Dst)^ do begin R := MulDiv(PixW.R, 255, 65535); G := MulDiv(PixW.G, 255, 65535); B := MulDiv(PixW.B, 255, 65535); end; 4: with PColor32Rec(Dst)^ do begin A := MulDiv(PixW.A, 255, 65535); R := MulDiv(PixW.R, 255, 65535); G := MulDiv(PixW.G, 255, 65535); B := MulDiv(PixW.B, 255, 65535); end; 6: with PColor48Rec(Dst)^ do begin R := PixW.R; G := PixW.G; B := PixW.B; end; 8: PColor64(Dst)^ := PixW.Color; end; end; procedure GrayGetSrcPixel(Src: PByte; SrcInfo: PImageFormatInfo; var Gray: TColor64Rec; var Alpha: Word); begin FillChar(Gray, SizeOf(Gray), 0); // Source alpha is scaled to 16 bits and stored in Alpha, // grayscale value is scaled to 64 bits and stored in Gray case SrcInfo.BytesPerPixel of 1: Gray.A := MulDiv(Src^, 65535, 255); 2: if SrcInfo.HasAlphaChannel then with PWordRec(Src)^ do begin Alpha := MulDiv(High, 65535, 255); Gray.A := MulDiv(Low, 65535, 255); end else Gray.A := PWord(Src)^; 4: if SrcInfo.HasAlphaChannel then with PLongWordRec(Src)^ do begin Alpha := High; Gray.A := Low; end else with PLongWordRec(Src)^ do begin Gray.A := High; Gray.R := Low; end; 8: Gray.Color := PColor64(Src)^; end; // if src has no alpha, we set it to max (otherwise we would have to // test if dest has alpha or not in each GrayToXXX function) if not SrcInfo.HasAlphaChannel then Alpha := 65535; end; procedure GraySetDstPixel(Dst: PByte; DstInfo: PImageFormatInfo; const Gray: TColor64Rec; Alpha: Word); begin // Gray contains grayscale value scaled to 64 bits, Alpha contains // alpha value scaled to 16 bits case DstInfo.BytesPerPixel of 1: Dst^ := MulDiv(Gray.A, 255, 65535); 2: if DstInfo.HasAlphaChannel then with PWordRec(Dst)^ do begin High := MulDiv(Alpha, 255, 65535); Low := MulDiv(Gray.A, 255, 65535); end else PWord(Dst)^ := Gray.A; 4: if DstInfo.HasAlphaChannel then with PLongWordRec(Dst)^ do begin High := Alpha; Low := Gray.A; end else with PLongWordRec(Dst)^ do begin High := Gray.A; Low := Gray.R; end; 8: PColor64(Dst)^ := Gray.Color; end; end; procedure FloatGetSrcPixel(Src: PByte; SrcInfo: PImageFormatInfo; var Pix: TColorFPRec); var PixHF: TColorHFRec; begin Assert(SrcInfo.BytesPerPixel in [2, 4, 8, 12, 16]); if SrcInfo.BytesPerPixel in [4, 12, 16] then begin // IEEE 754 single-precision channels FillChar(Pix, SizeOf(Pix), 0); case SrcInfo.BytesPerPixel of 4: Pix.R := PSingle(Src)^; 12: Pix.Color96Rec := PColor96FPRec(Src)^; 16: Pix := PColorFPRec(Src)^; end; end else begin // Half float channels FillChar(PixHF, SizeOf(PixHF), 0); case SrcInfo.BytesPerPixel of 2: PixHF.R := PHalfFloat(Src)^; 8: PixHF := PColorHFRec(Src)^; end; Pix := ColorHalfToFloat(PixHF); end; // If src has no alpha, we set it to max (otherwise we would have to // test if dest has alpha or not in each FloatToXXX function) if not SrcInfo.HasAlphaChannel then Pix.A := 1.0; if SrcInfo.IsRBSwapped then SwapValues(Pix.R, Pix.B); end; procedure FloatSetDstPixel(Dst: PByte; DstInfo: PImageFormatInfo; const Pix: TColorFPRec); var PixW: TColorFPRec; PixHF: TColorHFRec; begin Assert(DstInfo.BytesPerPixel in [2, 4, 8, 12, 16]); PixW := Pix; if DstInfo.IsRBSwapped then SwapValues(PixW.R, PixW.B); if DstInfo.BytesPerPixel in [4, 12, 16] then begin case DstInfo.BytesPerPixel of 4: PSingle(Dst)^ := PixW.R; 12: PColor96FPRec(Dst)^:= PixW.Color96Rec; 16: PColorFPRec(Dst)^ := PixW; end; end else begin PixHF := ColorFloatToHalf(PixW); case DstInfo.BytesPerPixel of 2: PHalfFloat(Dst)^ := PixHF.R; 8: PColorHFRec(Dst)^ := PixHF; end; end; end; procedure IndexGetSrcPixel(Src: PByte; SrcInfo: PImageFormatInfo; var Index: LongWord); begin case SrcInfo.BytesPerPixel of 1: Index := Src^; end; end; procedure IndexSetDstPixel(Dst: PByte; DstInfo: PImageFormatInfo; Index: LongWord); begin case DstInfo.BytesPerPixel of 1: Dst^ := Byte(Index); 2: PWord(Dst)^ := Word(Index); 4: PLongWord(Dst)^ := Index; end; end; { Pixel readers/writers for 32bit and FP colors} function GetPixel32Generic(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColor32Rec; var Pix64: TColor64Rec; PixF: TColorFPRec; Alpha: Word; Index: LongWord; begin if Info.Format = ifA8R8G8B8 then begin Result := PColor32Rec(Bits)^ end else if Info.Format = ifR8G8B8 then begin PColor24Rec(@Result)^ := PColor24Rec(Bits)^; Result.A := $FF; end else if Info.IsFloatingPoint then begin FloatGetSrcPixel(Bits, Info, PixF); Result.A := ClampToByte(Round(PixF.A * 255.0)); Result.R := ClampToByte(Round(PixF.R * 255.0)); Result.G := ClampToByte(Round(PixF.G * 255.0)); Result.B := ClampToByte(Round(PixF.B * 255.0)); end else if Info.HasGrayChannel then begin GrayGetSrcPixel(Bits, Info, Pix64, Alpha); Result.A := MulDiv(Alpha, 255, 65535); Result.R := MulDiv(Pix64.A, 255, 65535); Result.G := MulDiv(Pix64.A, 255, 65535); Result.B := MulDiv(Pix64.A, 255, 65535); end else if Info.IsIndexed then begin IndexGetSrcPixel(Bits, Info, Index); Result := Palette[Index]; end else begin ChannelGetSrcPixel(Bits, Info, Pix64); Result.A := MulDiv(Pix64.A, 255, 65535); Result.R := MulDiv(Pix64.R, 255, 65535); Result.G := MulDiv(Pix64.G, 255, 65535); Result.B := MulDiv(Pix64.B, 255, 65535); end; end; procedure SetPixel32Generic(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColor32Rec); var Pix64: TColor64Rec; PixF: TColorFPRec; Alpha: Word; Index: LongWord; begin if Info.Format = ifA8R8G8B8 then begin PColor32Rec(Bits)^ := Color end else if Info.Format = ifR8G8B8 then begin PColor24Rec(Bits)^ := Color.Color24Rec; end else if Info.IsFloatingPoint then begin PixF.A := Color.A * OneDiv8Bit; PixF.R := Color.R * OneDiv8Bit; PixF.G := Color.G * OneDiv8Bit; PixF.B := Color.B * OneDiv8Bit; FloatSetDstPixel(Bits, Info, PixF); end else if Info.HasGrayChannel then begin Alpha := MulDiv(Color.A, 65535, 255); Pix64.Color := 0; Pix64.A := MulDiv(Round(GrayConv.R * Color.R + GrayConv.G * Color.G + GrayConv.B * Color.B), 65535, 255); GraySetDstPixel(Bits, Info, Pix64, Alpha); end else if Info.IsIndexed then begin Index := FindColor(Palette, Info.PaletteEntries, Color.Color); IndexSetDstPixel(Bits, Info, Index); end else begin Pix64.A := MulDiv(Color.A, 65535, 255); Pix64.R := MulDiv(Color.R, 65535, 255); Pix64.G := MulDiv(Color.G, 65535, 255); Pix64.B := MulDiv(Color.B, 65535, 255); ChannelSetDstPixel(Bits, Info, Pix64); end; end; function GetPixelFPGeneric(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColorFPRec; var Pix32: TColor32Rec; Pix64: TColor64Rec; Alpha: Word; Index: LongWord; begin if Info.IsFloatingPoint then begin FloatGetSrcPixel(Bits, Info, Result); end else if Info.HasGrayChannel then begin GrayGetSrcPixel(Bits, Info, Pix64, Alpha); Result.A := Alpha * OneDiv16Bit; Result.R := Pix64.A * OneDiv16Bit; Result.G := Pix64.A * OneDiv16Bit; Result.B := Pix64.A * OneDiv16Bit; end else if Info.IsIndexed then begin IndexGetSrcPixel(Bits, Info, Index); Pix32 := Palette[Index]; Result.A := Pix32.A * OneDiv8Bit; Result.R := Pix32.R * OneDiv8Bit; Result.G := Pix32.G * OneDiv8Bit; Result.B := Pix32.B * OneDiv8Bit; end else begin ChannelGetSrcPixel(Bits, Info, Pix64); Result.A := Pix64.A * OneDiv16Bit; Result.R := Pix64.R * OneDiv16Bit; Result.G := Pix64.G * OneDiv16Bit; Result.B := Pix64.B * OneDiv16Bit; end; end; procedure SetPixelFPGeneric(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColorFPRec); var Pix32: TColor32Rec; Pix64: TColor64Rec; Alpha: Word; Index: LongWord; begin if Info.IsFloatingPoint then begin FloatSetDstPixel(Bits, Info, Color); end else if Info.HasGrayChannel then begin Alpha := ClampToWord(Round(Color.A * 65535.0)); Pix64.Color := 0; Pix64.A := ClampToWord(Round((GrayConv.R * Color.R + GrayConv.G * Color.G + GrayConv.B * Color.B) * 65535.0)); GraySetDstPixel(Bits, Info, Pix64, Alpha); end else if Info.IsIndexed then begin Pix32.A := ClampToByte(Round(Color.A * 255.0)); Pix32.R := ClampToByte(Round(Color.R * 255.0)); Pix32.G := ClampToByte(Round(Color.G * 255.0)); Pix32.B := ClampToByte(Round(Color.B * 255.0)); Index := FindColor(Palette, Info.PaletteEntries, Pix32.Color); IndexSetDstPixel(Bits, Info, Index); end else begin Pix64.A := ClampToWord(Round(Color.A * 65535.0)); Pix64.R := ClampToWord(Round(Color.R * 65535.0)); Pix64.G := ClampToWord(Round(Color.G * 65535.0)); Pix64.B := ClampToWord(Round(Color.B * 65535.0)); ChannelSetDstPixel(Bits, Info, Pix64); end; end; { Image format conversion functions } procedure ChannelToChannel(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo); var I: LongInt; Pix64: TColor64Rec; begin // two most common conversions (RGB->ARGB and ARGB->RGB for 24/32 bit // images) are made separately from general ARGB conversion to // make them faster if (SrcInfo.BytesPerPixel = 3) and (DstInfo.BytesPerPixel = 4) then for I := 0 to NumPixels - 1 do begin PColor24Rec(Dst)^ := PColor24Rec(Src)^; if DstInfo.HasAlphaChannel then PColor32Rec(Dst).A := 255; Inc(Src, SrcInfo.BytesPerPixel); Inc(Dst, DstInfo.BytesPerPixel); end else if (SrcInfo.BytesPerPixel = 4) and (DstInfo.BytesPerPixel = 3) then for I := 0 to NumPixels - 1 do begin PColor24Rec(Dst)^ := PColor24Rec(Src)^; Inc(Src, SrcInfo.BytesPerPixel); Inc(Dst, DstInfo.BytesPerPixel); end else for I := 0 to NumPixels - 1 do begin // general ARGB conversion ChannelGetSrcPixel(Src, SrcInfo, Pix64); ChannelSetDstPixel(Dst, DstInfo, Pix64); Inc(Src, SrcInfo.BytesPerPixel); Inc(Dst, DstInfo.BytesPerPixel); end; end; procedure ChannelToGray(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo); var I: LongInt; Pix64: TColor64Rec; Alpha: Word; begin // two most common conversions (R8G8B8->Gray8 nad A8R8G8B8->Gray8) // are made separately from general conversions to make them faster if (SrcInfo.BytesPerPixel in [3, 4]) and (DstInfo.Format = ifGray8) then for I := 0 to NumPixels - 1 do begin Dst^ := Round(GrayConv.R * PColor24Rec(Src).R + GrayConv.G * PColor24Rec(Src).G + GrayConv.B * PColor24Rec(Src).B); Inc(Src, SrcInfo.BytesPerPixel); Inc(Dst, DstInfo.BytesPerPixel); end else for I := 0 to NumPixels - 1 do begin ChannelGetSrcPixel(Src, SrcInfo, Pix64); // alpha is saved from source pixel to Alpha, // Gray value is computed and set to highest word of Pix64 so // Pix64.Color contains grayscale value scaled to 64 bits Alpha := Pix64.A; with GrayConv do Pix64.A := Round(R * Pix64.R + G * Pix64.G + B * Pix64.B); GraySetDstPixel(Dst, DstInfo, Pix64, Alpha); Inc(Src, SrcInfo.BytesPerPixel); Inc(Dst, DstInfo.BytesPerPixel); end; end; procedure ChannelToFloat(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo); var I: LongInt; Pix64: TColor64Rec; PixF: TColorFPRec; begin for I := 0 to NumPixels - 1 do begin ChannelGetSrcPixel(Src, SrcInfo, Pix64); // floating point channel values are scaled to 1.0 PixF.A := Pix64.A * OneDiv16Bit; PixF.R := Pix64.R * OneDiv16Bit; PixF.G := Pix64.G * OneDiv16Bit; PixF.B := Pix64.B * OneDiv16Bit; FloatSetDstPixel(Dst, DstInfo, PixF); Inc(Src, SrcInfo.BytesPerPixel); Inc(Dst, DstInfo.BytesPerPixel); end; end; procedure ChannelToIndex(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo; DstPal: PPalette32); begin ReduceColorsMedianCut(NumPixels, Src, Dst, SrcInfo, DstInfo, DstInfo.PaletteEntries, GetOption(ImagingColorReductionMask), DstPal); end; procedure GrayToGray(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo); var I: LongInt; Gray: TColor64Rec; Alpha: Word; begin // two most common conversions (Gray8->Gray16 nad Gray16->Gray8) // are made separately from general conversions to make them faster if (SrcInfo.Format = ifGray8) and (DstInfo.Format = ifGray16) then begin for I := 0 to NumPixels - 1 do PWordArray(Dst)[I] := PByteArray(Src)[I] shl 8; end else begin if (DstInfo.Format = ifGray8) and (SrcInfo.Format = ifGray16) then begin for I := 0 to NumPixels - 1 do PByteArray(Dst)[I] := PWordArray(Src)[I] shr 8; end else for I := 0 to NumPixels - 1 do begin // general grayscale conversion GrayGetSrcPixel(Src, SrcInfo, Gray, Alpha); GraySetDstPixel(Dst, DstInfo, Gray, Alpha); Inc(Src, SrcInfo.BytesPerPixel); Inc(Dst, DstInfo.BytesPerPixel); end; end; end; procedure GrayToChannel(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo); var I: LongInt; Pix64: TColor64Rec; Alpha: Word; begin // two most common conversions (Gray8->R8G8B8 nad Gray8->A8R8G8B8) // are made separately from general conversions to make them faster if (DstInfo.BytesPerPixel in [3, 4]) and (SrcInfo.Format = ifGray8) then for I := 0 to NumPixels - 1 do begin PColor24Rec(Dst).R := Src^; PColor24Rec(Dst).G := Src^; PColor24Rec(Dst).B := Src^; if DstInfo.HasAlphaChannel then PColor32Rec(Dst).A := $FF; Inc(Src, SrcInfo.BytesPerPixel); Inc(Dst, DstInfo.BytesPerPixel); end else for I := 0 to NumPixels - 1 do begin GrayGetSrcPixel(Src, SrcInfo, Pix64, Alpha); // most significant word of grayscale value is used for // each channel and alpha channel is set to Alpha Pix64.R := Pix64.A; Pix64.G := Pix64.A; Pix64.B := Pix64.A; Pix64.A := Alpha; ChannelSetDstPixel(Dst, DstInfo, Pix64); Inc(Src, SrcInfo.BytesPerPixel); Inc(Dst, DstInfo.BytesPerPixel); end; end; procedure GrayToFloat(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo); var I: LongInt; Gray: TColor64Rec; PixF: TColorFPRec; Alpha: Word; begin for I := 0 to NumPixels - 1 do begin GrayGetSrcPixel(Src, SrcInfo, Gray, Alpha); // most significant word of grayscale value is used for // each channel and alpha channel is set to Alpha // then all is scaled to 0..1 PixF.R := Gray.A * OneDiv16Bit; PixF.G := Gray.A * OneDiv16Bit; PixF.B := Gray.A * OneDiv16Bit; PixF.A := Alpha * OneDiv16Bit; FloatSetDstPixel(Dst, DstInfo, PixF); Inc(Src, SrcInfo.BytesPerPixel); Inc(Dst, DstInfo.BytesPerPixel); end; end; procedure GrayToIndex(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo; DstPal: PPalette32); var I: LongInt; Idx: LongWord; Gray: TColor64Rec; Alpha, Shift: Word; begin FillGrayscalePalette(DstPal, DstInfo.PaletteEntries); Shift := Log2Int(DstInfo.PaletteEntries); // most common conversion (Gray8->Index8) // is made separately from general conversions to make it faster if (SrcInfo.Format = ifGray8) and (DstInfo.Format = ifIndex8) then for I := 0 to NumPixels - 1 do begin Dst^ := Src^; Inc(Src, SrcInfo.BytesPerPixel); Inc(Dst, DstInfo.BytesPerPixel); end else for I := 0 to NumPixels - 1 do begin // gray value is read from src and index to precomputed // grayscale palette is computed and written to dst // (we assume here that there will be no more than 65536 palette // entries in dst format, gray value is shifted so the highest // gray value match the highest possible index in palette) GrayGetSrcPixel(Src, SrcInfo, Gray, Alpha); Idx := Gray.A shr (16 - Shift); IndexSetDstPixel(Dst, DstInfo, Idx); Inc(Src, SrcInfo.BytesPerPixel); Inc(Dst, DstInfo.BytesPerPixel); end; end; procedure FloatToFloat(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo); var I: LongInt; PixF: TColorFPRec; begin for I := 0 to NumPixels - 1 do begin // general floating point conversion FloatGetSrcPixel(Src, SrcInfo, PixF); FloatSetDstPixel(Dst, DstInfo, PixF); Inc(Src, SrcInfo.BytesPerPixel); Inc(Dst, DstInfo.BytesPerPixel); end; end; procedure FloatToChannel(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo); var I: LongInt; Pix64: TColor64Rec; PixF: TColorFPRec; begin for I := 0 to NumPixels - 1 do begin FloatGetSrcPixel(Src, SrcInfo, PixF); ClampFloatPixel(PixF); // floating point channel values are scaled to 1.0 Pix64.A := ClampToWord(Round(PixF.A * 65535)); Pix64.R := ClampToWord(Round(PixF.R * 65535)); Pix64.G := ClampToWord(Round(PixF.G * 65535)); Pix64.B := ClampToWord(Round(PixF.B * 65535)); ChannelSetDstPixel(Dst, DstInfo, Pix64); Inc(Src, SrcInfo.BytesPerPixel); Inc(Dst, DstInfo.BytesPerPixel); end; end; procedure FloatToGray(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo); var I: LongInt; PixF: TColorFPRec; Gray: TColor64Rec; Alpha: Word; begin for I := 0 to NumPixels - 1 do begin FloatGetSrcPixel(Src, SrcInfo, PixF); ClampFloatPixel(PixF); // alpha is saved from source pixel to Alpha, // Gray value is computed and set to highest word of Pix64 so // Pix64.Color contains grayscale value scaled to 64 bits Alpha := ClampToWord(Round(PixF.A * 65535.0)); Gray.A := ClampToWord(Round((GrayConv.R * PixF.R + GrayConv.G * PixF.G + GrayConv.B * PixF.B) * 65535.0)); GraySetDstPixel(Dst, DstInfo, Gray, Alpha); Inc(Src, SrcInfo.BytesPerPixel); Inc(Dst, DstInfo.BytesPerPixel); end; end; procedure FloatToIndex(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo; DstPal: PPalette32); begin ReduceColorsMedianCut(NumPixels, Src, Dst, SrcInfo, DstInfo, DstInfo.PaletteEntries, GetOption(ImagingColorReductionMask), DstPal); end; procedure IndexToIndex(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo; SrcPal, DstPal: PPalette32); var I: LongInt; begin // there is only one indexed format now, so it is just a copy for I := 0 to NumPixels - 1 do begin Dst^ := Src^; Inc(Src, SrcInfo.BytesPerPixel); Inc(Dst, DstInfo.BytesPerPixel); end; for I := 0 to SrcInfo.PaletteEntries - 1 do DstPal[I] := SrcPal[I]; end; procedure IndexToChannel(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo; SrcPal: PPalette32); var I: LongInt; Pix64: TColor64Rec; Idx: LongWord; begin // two most common conversions (Index8->R8G8B8 nad Index8->A8R8G8B8) // are made separately from general conversions to make them faster if (SrcInfo.Format = ifIndex8) and (DstInfo.Format in [ifR8G8B8, ifA8R8G8B8]) then for I := 0 to NumPixels - 1 do begin with PColor24Rec(Dst)^ do begin R := SrcPal[Src^].R; G := SrcPal[Src^].G; B := SrcPal[Src^].B; end; if DstInfo.Format = ifA8R8G8B8 then PColor32Rec(Dst).A := SrcPal[Src^].A; Inc(Src, SrcInfo.BytesPerPixel); Inc(Dst, DstInfo.BytesPerPixel); end else for I := 0 to NumPixels - 1 do begin // index to palette is read from source and color // is retrieved from palette entry. Color is then // scaled to 16bits and written to dest IndexGetSrcPixel(Src, SrcInfo, Idx); with Pix64 do begin A := SrcPal[Idx].A shl 8; R := SrcPal[Idx].R shl 8; G := SrcPal[Idx].G shl 8; B := SrcPal[Idx].B shl 8; end; ChannelSetDstPixel(Dst, DstInfo, Pix64); Inc(Src, SrcInfo.BytesPerPixel); Inc(Dst, DstInfo.BytesPerPixel); end; end; procedure IndexToGray(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo; SrcPal: PPalette32); var I: LongInt; Gray: TColor64Rec; Alpha: Word; Idx: LongWord; begin // most common conversion (Index8->Gray8) // is made separately from general conversions to make it faster if (SrcInfo.Format = ifIndex8) and (DstInfo.Format = ifGray8) then begin for I := 0 to NumPixels - 1 do begin Dst^ := Round(GrayConv.R * SrcPal[Src^].R + GrayConv.G * SrcPal[Src^].G + GrayConv.B * SrcPal[Src^].B); Inc(Src, SrcInfo.BytesPerPixel); Inc(Dst, DstInfo.BytesPerPixel); end end else for I := 0 to NumPixels - 1 do begin // index to palette is read from source and color // is retrieved from palette entry. Color is then // transformed to grayscale and assigned to the highest // byte of Gray value IndexGetSrcPixel(Src, SrcInfo, Idx); Alpha := SrcPal[Idx].A shl 8; Gray.A := MulDiv(Round(GrayConv.R * SrcPal[Idx].R + GrayConv.G * SrcPal[Idx].G + GrayConv.B * SrcPal[Idx].B), 65535, 255); GraySetDstPixel(Dst, DstInfo, Gray, Alpha); Inc(Src, SrcInfo.BytesPerPixel); Inc(Dst, DstInfo.BytesPerPixel); end; end; procedure IndexToFloat(NumPixels: LongInt; Src, Dst: PByte; SrcInfo, DstInfo: PImageFormatInfo; SrcPal: PPalette32); var I: LongInt; Idx: LongWord; PixF: TColorFPRec; begin for I := 0 to NumPixels - 1 do begin // index to palette is read from source and color // is retrieved from palette entry. Color is then // scaled to 0..1 and written to dest IndexGetSrcPixel(Src, SrcInfo, Idx); with PixF do begin A := SrcPal[Idx].A * OneDiv8Bit; R := SrcPal[Idx].R * OneDiv8Bit; G := SrcPal[Idx].G * OneDiv8Bit; B := SrcPal[Idx].B * OneDiv8Bit; end; FloatSetDstPixel(Dst, DstInfo, PixF); Inc(Src, SrcInfo.BytesPerPixel); Inc(Dst, DstInfo.BytesPerPixel); end; end; { Special formats conversion functions } type // DXT RGB color block TDXTColorBlock = packed record Color0, Color1: Word; Mask: LongWord; end; PDXTColorBlock = ^TDXTColorBlock; // DXT explicit alpha for a block TDXTAlphaBlockExp = packed record Alphas: array[0..3] of Word; end; PDXTAlphaBlockExp = ^TDXTAlphaBlockExp; // DXT interpolated alpha for a block TDXTAlphaBlockInt = packed record Alphas: array[0..7] of Byte; end; PDXTAlphaBlockInt = ^TDXTAlphaBlockInt; TPixelInfo = record Color: Word; Alpha: Byte; Orig: TColor32Rec; end; TPixelBlock = array[0..15] of TPixelInfo; function DecodeCol(Color: Word): TColor32Rec; {$IFDEF USE_INLINE} inline; {$ENDIF} begin Result.A := $FF; { Result.R := ((Color and $F800) shr 11) shl 3; Result.G := ((Color and $07E0) shr 5) shl 2; Result.B := (Color and $001F) shl 3;} // this color expansion is slower but gives better results Result.R := (Color shr 11) * 255 div 31; Result.G := ((Color shr 5) and $3F) * 255 div 63; Result.B := (Color and $1F) * 255 div 31; end; procedure DecodeDXT1(SrcBits, DestBits: PByte; Width, Height: LongInt); var Sel, X, Y, I, J, K: LongInt; Block: TDXTColorBlock; Colors: array[0..3] of TColor32Rec; begin for Y := 0 to Height div 4 - 1 do for X := 0 to Width div 4 - 1 do begin Block := PDXTColorBlock(SrcBits)^; Inc(SrcBits, SizeOf(Block)); // we read and decode endpoint colors Colors[0] := DecodeCol(Block.Color0); Colors[1] := DecodeCol(Block.Color1); // and interpolate between them if Block.Color0 > Block.Color1 then begin // interpolation for block without alpha Colors[2].A := $FF; Colors[2].R := (Colors[0].R shl 1 + Colors[1].R + 1) div 3; Colors[2].G := (Colors[0].G shl 1 + Colors[1].G + 1) div 3; Colors[2].B := (Colors[0].B shl 1 + Colors[1].B + 1) div 3; Colors[3].A := $FF; Colors[3].R := (Colors[0].R + Colors[1].R shl 1 + 1) div 3; Colors[3].G := (Colors[0].G + Colors[1].G shl 1 + 1) div 3; Colors[3].B := (Colors[0].B + Colors[1].B shl 1 + 1) div 3; end else begin // interpolation for block with alpha Colors[2].A := $FF; Colors[2].R := (Colors[0].R + Colors[1].R) shr 1; Colors[2].G := (Colors[0].G + Colors[1].G) shr 1; Colors[2].B := (Colors[0].B + Colors[1].B) shr 1; Colors[3].A := 0; Colors[3].R := (Colors[0].R + Colors[1].R shl 1 + 1) div 3; Colors[3].G := (Colors[0].G + Colors[1].G shl 1 + 1) div 3; Colors[3].B := (Colors[0].B + Colors[1].B shl 1 + 1) div 3; end; // we distribute the dxt block colors across the 4x4 block of the // destination image accroding to the dxt block mask K := 0; for J := 0 to 3 do for I := 0 to 3 do begin Sel := (Block.Mask and (3 shl (K shl 1))) shr (K shl 1); if ((X shl 2 + I) < Width) and ((Y shl 2 + J) < Height) then PPalette32(DestBits)[(Y shl 2 + J) * Width + X shl 2 + I] := Colors[Sel]; Inc(K); end; end; end; procedure DecodeDXT3(SrcBits, DestBits: PByte; Width, Height: LongInt); var Sel, X, Y, I, J, K: LongInt; Block: TDXTColorBlock; AlphaBlock: TDXTAlphaBlockExp; Colors: array[0..3] of TColor32Rec; AWord: Word; begin for Y := 0 to Height div 4 - 1 do for X := 0 to Width div 4 - 1 do begin AlphaBlock := PDXTAlphaBlockExp(SrcBits)^; Inc(SrcBits, SizeOf(AlphaBlock)); Block := PDXTColorBlock(SrcBits)^; Inc(SrcBits, SizeOf(Block)); // we read and decode endpoint colors Colors[0] := DecodeCol(Block.Color0); Colors[1] := DecodeCol(Block.Color1); // and interpolate between them Colors[2].R := (Colors[0].R shl 1 + Colors[1].R + 1) div 3; Colors[2].G := (Colors[0].G shl 1 + Colors[1].G + 1) div 3; Colors[2].B := (Colors[0].B shl 1 + Colors[1].B + 1) div 3; Colors[3].R := (Colors[0].R + Colors[1].R shl 1 + 1) div 3; Colors[3].G := (Colors[0].G + Colors[1].G shl 1 + 1) div 3; Colors[3].B := (Colors[0].B + Colors[1].B shl 1 + 1) div 3; // we distribute the dxt block colors and alphas // across the 4x4 block of the destination image // accroding to the dxt block mask and alpha block K := 0; for J := 0 to 3 do begin AWord := AlphaBlock.Alphas[J]; for I := 0 to 3 do begin Sel := (Block.Mask and (3 shl (K shl 1))) shr (K shl 1); if (X shl 2 + I < Width) and (Y shl 2 + J < Height) then begin Colors[Sel].A := AWord and $0F; Colors[Sel].A := Colors[Sel].A or (Colors[Sel].A shl 4); PPalette32(DestBits)[(Y shl 2 + J) * Width + X shl 2 + I] := Colors[Sel]; end; Inc(K); AWord := AWord shr 4; end; end; end; end; procedure GetInterpolatedAlphas(var AlphaBlock: TDXTAlphaBlockInt); begin with AlphaBlock do if Alphas[0] > Alphas[1] then begin // Interpolation of six alphas Alphas[2] := (6 * Alphas[0] + 1 * Alphas[1] + 3) div 7; Alphas[3] := (5 * Alphas[0] + 2 * Alphas[1] + 3) div 7; Alphas[4] := (4 * Alphas[0] + 3 * Alphas[1] + 3) div 7; Alphas[5] := (3 * Alphas[0] + 4 * Alphas[1] + 3) div 7; Alphas[6] := (2 * Alphas[0] + 5 * Alphas[1] + 3) div 7; Alphas[7] := (1 * Alphas[0] + 6 * Alphas[1] + 3) div 7; end else begin // Interpolation of four alphas, two alphas are set directly Alphas[2] := (4 * Alphas[0] + 1 * Alphas[1] + 2) div 5; Alphas[3] := (3 * Alphas[0] + 2 * Alphas[1] + 2) div 5; Alphas[4] := (2 * Alphas[0] + 3 * Alphas[1] + 2) div 5; Alphas[5] := (1 * Alphas[0] + 4 * Alphas[1] + 2) div 5; Alphas[6] := 0; Alphas[7] := $FF; end; end; procedure DecodeDXT5(SrcBits, DestBits: PByte; Width, Height: LongInt); var Sel, X, Y, I, J, K: LongInt; Block: TDXTColorBlock; AlphaBlock: TDXTAlphaBlockInt; Colors: array[0..3] of TColor32Rec; AMask: array[0..1] of LongWord; begin for Y := 0 to Height div 4 - 1 do for X := 0 to Width div 4 - 1 do begin AlphaBlock := PDXTAlphaBlockInt(SrcBits)^; Inc(SrcBits, SizeOf(AlphaBlock)); Block := PDXTColorBlock(SrcBits)^; Inc(SrcBits, SizeOf(Block)); // we read and decode endpoint colors Colors[0] := DecodeCol(Block.Color0); Colors[1] := DecodeCol(Block.Color1); // and interpolate between them Colors[2].R := (Colors[0].R shl 1 + Colors[1].R + 1) div 3; Colors[2].G := (Colors[0].G shl 1 + Colors[1].G + 1) div 3; Colors[2].B := (Colors[0].B shl 1 + Colors[1].B + 1) div 3; Colors[3].R := (Colors[0].R + Colors[1].R shl 1 + 1) div 3; Colors[3].G := (Colors[0].G + Colors[1].G shl 1 + 1) div 3; Colors[3].B := (Colors[0].B + Colors[1].B shl 1 + 1) div 3; // 6 bit alpha mask is copied into two long words for // easier usage AMask[0] := PLongWord(@AlphaBlock.Alphas[2])^ and $00FFFFFF; AMask[1] := PLongWord(@AlphaBlock.Alphas[5])^ and $00FFFFFF; // alpha interpolation between two endpoint alphas GetInterpolatedAlphas(AlphaBlock); // we distribute the dxt block colors and alphas // across the 4x4 block of the destination image // accroding to the dxt block mask and alpha block mask K := 0; for J := 0 to 3 do for I := 0 to 3 do begin Sel := (Block.Mask and (3 shl (K shl 1))) shr (K shl 1); if ((X shl 2 + I) < Width) and ((Y shl 2 + J) < Height) then begin Colors[Sel].A := AlphaBlock.Alphas[AMask[J shr 1] and 7]; PPalette32(DestBits)[(Y shl 2 + J) * Width + (X shl 2 + I)] := Colors[Sel]; end; Inc(K); AMask[J shr 1] := AMask[J shr 1] shr 3; end; end; end; procedure GetBlock(var Block: TPixelBlock; SrcBits: Pointer; XPos, YPos, Width, Height: LongInt); var X, Y, I: LongInt; Src: PColor32Rec; begin I := 0; // 4x4 pixel block is filled with information about every // pixel in the block: alpha, original color, 565 color for Y := 0 to 3 do for X := 0 to 3 do begin Src := @PPalette32(SrcBits)[(YPos shl 2 + Y) * Width + XPos shl 2 + X]; Block[I].Color := ((Src.R shr 3) shl 11) or ((Src.G shr 2) shl 5) or (Src.B shr 3); Block[I].Alpha := Src.A; Block[I].Orig := Src^; Inc(I); end; end; function ColorDistance(const C1, C2: TColor32Rec): LongInt; {$IFDEF USE_INLINE} inline;{$ENDIF} begin Result := (C1.R - C2.R) * (C1.R - C2.R) + (C1.G - C2.G) * (C1.G - C2.G) + (C1.B - C2.B) * (C1.B - C2.B); end; procedure GetEndpoints(const Block: TPixelBlock; var Ep0, Ep1: Word); var I, J, Farthest, Dist: LongInt; Colors: array[0..15] of TColor32Rec; begin // we choose two colors from the pixel block which has the // largest distance between them for I := 0 to 15 do Colors[I] := Block[I].Orig; Farthest := -1; for I := 0 to 15 do for J := I + 1 to 15 do begin Dist := ColorDistance(Colors[I], Colors[J]); if Dist > Farthest then begin Farthest := Dist; Ep0 := Block[I].Color; Ep1 := Block[J].Color; end; end; end; procedure GetAlphaEndpoints(const Block: TPixelBlock; var Min, Max: Byte); var I: LongInt; begin Min := 255; Max := 0; // we choose the lowest and the highest alpha values for I := 0 to 15 do begin if Block[I].Alpha < Min then Min := Block[I].Alpha; if Block[I].Alpha > Max then Max := Block[I].Alpha; end; end; procedure FixEndpoints(var Ep0, Ep1: Word; HasAlpha: Boolean); var Temp: Word; begin // if dxt block has alpha information, Ep0 must be smaller // than Ep1, if the block has no alpha Ep1 must be smaller if HasAlpha then begin if Ep0 > Ep1 then begin Temp := Ep0; Ep0 := Ep1; Ep1 := Temp; end; end else if Ep0 < Ep1 then begin Temp := Ep0; Ep0 := Ep1; Ep1 := Temp; end; end; function GetColorMask(Ep0, Ep1: Word; NumCols: LongInt; const Block: TPixelBlock): LongWord; var I, J, Closest, Dist: LongInt; Colors: array[0..3] of TColor32Rec; Mask: array[0..15] of Byte; begin // we decode endpoint colors Colors[0] := DecodeCol(Ep0); Colors[1] := DecodeCol(Ep1); // and interpolate colors between (3 for DXT1 with alpha, 4 for the others) if NumCols = 3 then begin Colors[2].R := (Colors[0].R + Colors[1].R) shr 1; Colors[2].G := (Colors[0].G + Colors[1].G) shr 1; Colors[2].B := (Colors[0].B + Colors[1].B) shr 1; Colors[3].R := (Colors[0].R + Colors[1].R) shr 1; Colors[3].G := (Colors[0].G + Colors[1].G) shr 1; Colors[3].B := (Colors[0].B + Colors[1].B) shr 1; end else begin Colors[2].R := (Colors[0].R shl 1 + Colors[1].R + 1) div 3; Colors[2].G := (Colors[0].G shl 1 + Colors[1].G + 1) div 3; Colors[2].B := (Colors[0].B shl 1 + Colors[1].B + 1) div 3; Colors[3].R := (Colors[0].R + Colors[1].R shl 1 + 1) div 3; Colors[3].G := (Colors[0].G + Colors[1].G shl 1 + 1) div 3; Colors[3].B := (Colors[0].B + Colors[1].B shl 1 + 1) div 3; end; for I := 0 to 15 do begin // this is only for DXT1 with alpha if (Block[I].Alpha < 128) and (NumCols = 3) then begin Mask[I] := 3; Continue; end; // for each of the 16 input pixels the nearest color in the // 4 dxt colors is found Closest := MaxInt; for J := 0 to NumCols - 1 do begin Dist := ColorDistance(Block[I].Orig, Colors[J]); if Dist < Closest then begin Closest := Dist; Mask[I] := J; end; end; end; Result := 0; for I := 0 to 15 do Result := Result or (Mask[I] shl (I shl 1)); end; procedure GetAlphaMask(Ep0, Ep1: Byte; var Block: TPixelBlock; Mask: PByteArray); var Alphas: array[0..7] of Byte; M: array[0..15] of Byte; I, J, Closest, Dist: LongInt; begin Alphas[0] := Ep0; Alphas[1] := Ep1; // interpolation between two given alpha endpoints // (I use 6 interpolated values mode) Alphas[2] := (6 * Alphas[0] + 1 * Alphas[1] + 3) div 7; Alphas[3] := (5 * Alphas[0] + 2 * Alphas[1] + 3) div 7; Alphas[4] := (4 * Alphas[0] + 3 * Alphas[1] + 3) div 7; Alphas[5] := (3 * Alphas[0] + 4 * Alphas[1] + 3) div 7; Alphas[6] := (2 * Alphas[0] + 5 * Alphas[1] + 3) div 7; Alphas[7] := (1 * Alphas[0] + 6 * Alphas[1] + 3) div 7; // the closest interpolated values for each of the input alpha // is found for I := 0 to 15 do begin Closest := MaxInt; for J := 0 to 7 do begin Dist := Abs(Alphas[J] - Block[I].Alpha); if Dist < Closest then begin Closest := Dist; M[I] := J; end; end; end; Mask[0] := M[0] or (M[1] shl 3) or ((M[2] and 3) shl 6); Mask[1] := ((M[2] and 4) shr 2) or (M[3] shl 1) or (M[4] shl 4) or ((M[5] and 1) shl 7); Mask[2] := ((M[5] and 6) shr 1) or (M[6] shl 2) or (M[7] shl 5); Mask[3] := M[8] or (M[9] shl 3) or ((M[10] and 3) shl 6); Mask[4] := ((M[10] and 4) shr 2) or (M[11] shl 1) or (M[12] shl 4) or ((M[13] and 1) shl 7); Mask[5] := ((M[13] and 6) shr 1) or (M[14] shl 2) or (M[15] shl 5); end; procedure EncodeDXT1(SrcBits: PByte; DestBits: PByte; Width, Height: LongInt); var X, Y, I: LongInt; HasAlpha: Boolean; Block: TDXTColorBlock; Pixels: TPixelBlock; begin for Y := 0 to Height div 4 - 1 do for X := 0 to Width div 4 - 1 do begin GetBlock(Pixels, SrcBits, X, Y, Width, Height); HasAlpha := False; for I := 0 to 15 do if Pixels[I].Alpha < 128 then begin HasAlpha := True; Break; end; GetEndpoints(Pixels, Block.Color0, Block.Color1); FixEndpoints(Block.Color0, Block.Color1, HasAlpha); if HasAlpha then Block.Mask := GetColorMask(Block.Color0, Block.Color1, 3, Pixels) else Block.Mask := GetColorMask(Block.Color0, Block.Color1, 4, Pixels); PDXTColorBlock(DestBits)^ := Block; Inc(DestBits, SizeOf(Block)); end; end; procedure EncodeDXT3(SrcBits: Pointer; DestBits: PByte; Width, Height: LongInt); var X, Y, I: LongInt; Block: TDXTColorBlock; AlphaBlock: TDXTAlphaBlockExp; Pixels: TPixelBlock; begin for Y := 0 to Height div 4 - 1 do for X := 0 to Width div 4 - 1 do begin GetBlock(Pixels, SrcBits, X, Y, Width, Height); for I := 0 to 7 do PByteArray(@AlphaBlock.Alphas)[I] := (Pixels[I shl 1].Alpha shr 4) or ((Pixels[I shl 1 + 1].Alpha shr 4) shl 4); GetEndpoints(Pixels, Block.Color0, Block.Color1); FixEndpoints(Block.Color0, Block.Color1, False); Block.Mask := GetColorMask(Block.Color0, Block.Color1, 4, Pixels); PDXTAlphaBlockExp(DestBits)^ := AlphaBlock; Inc(DestBits, SizeOf(AlphaBlock)); PDXTColorBlock(DestBits)^ := Block; Inc(DestBits, SizeOf(Block)); end; end; procedure EncodeDXT5(SrcBits: Pointer; DestBits: PByte; Width, Height: LongInt); var X, Y: LongInt; Block: TDXTColorBlock; AlphaBlock: TDXTAlphaBlockInt; Pixels: TPixelBlock; begin for Y := 0 to Height div 4 - 1 do for X := 0 to Width div 4 - 1 do begin GetBlock(Pixels, SrcBits, X, Y, Width, Height); GetEndpoints(Pixels, Block.Color0, Block.Color1); FixEndpoints(Block.Color0, Block.Color1, False); Block.Mask := GetColorMask(Block.Color0, Block.Color1, 4, Pixels); GetAlphaEndPoints(Pixels, AlphaBlock.Alphas[1], AlphaBlock.Alphas[0]); GetAlphaMask(AlphaBlock.Alphas[0], AlphaBlock.Alphas[1], Pixels, PByteArray(@AlphaBlock.Alphas[2])); PDXTAlphaBlockInt(DestBits)^ := AlphaBlock; Inc(DestBits, SizeOf(AlphaBlock)); PDXTColorBlock(DestBits)^ := Block; Inc(DestBits, SizeOf(Block)); end; end; type TBTCBlock = packed record MLower, MUpper: Byte; BitField: Word; end; PBTCBlock = ^TBTCBlock; procedure EncodeBTC(SrcBits: Pointer; DestBits: PByte; Width, Height: Integer); var X, Y, I, J: Integer; Block: TBTCBlock; M, MLower, MUpper, K: Integer; Pixels: array[0..15] of Byte; begin for Y := 0 to Height div 4 - 1 do for X := 0 to Width div 4 - 1 do begin M := 0; MLower := 0; MUpper := 0; FillChar(Block, SizeOf(Block), 0); K := 0; // Store 4x4 pixels and compute average, lower, and upper intensity levels for I := 0 to 3 do for J := 0 to 3 do begin Pixels[K] := PByteArray(SrcBits)[(Y shl 2 + I) * Width + X shl 2 + J]; Inc(M, Pixels[K]); Inc(K); end; M := M div 16; K := 0; // Now compute upper and lower levels, number of upper pixels, // and update bit field (1 when pixel is above avg. level M) for I := 0 to 15 do begin if Pixels[I] > M then begin Inc(MUpper, Pixels[I]); Inc(K); Block.BitField := Block.BitField or (1 shl I); end else Inc(MLower, Pixels[I]); end; // Scale levels and save them to block if K > 0 then Block.MUpper := ClampToByte(MUpper div K) else Block.MUpper := 0; Block.MLower := ClampToByte(MLower div (16 - K)); // Finally save block to dest data PBTCBlock(DestBits)^ := Block; Inc(DestBits, SizeOf(Block)); end; end; procedure GetOneChannelBlock(var Block: TPixelBlock; SrcBits: Pointer; XPos, YPos, Width, Height, BytesPP, ChannelIdx: Integer); var X, Y, I: Integer; Src: PByte; begin I := 0; // 4x4 pixel block is filled with information about every pixel in the block, // but only one channel value is stored in Alpha field for Y := 0 to 3 do for X := 0 to 3 do begin Src := @PByteArray(SrcBits)[(YPos * 4 + Y) * Width * BytesPP + (XPos * 4 + X) * BytesPP + ChannelIdx]; Block[I].Alpha := Src^; Inc(I); end; end; procedure EncodeATI1N(SrcBits: Pointer; DestBits: PByte; Width, Height: Integer); var X, Y: Integer; AlphaBlock: TDXTAlphaBlockInt; Pixels: TPixelBlock; begin for Y := 0 to Height div 4 - 1 do for X := 0 to Width div 4 - 1 do begin // Encode one channel GetOneChannelBlock(Pixels, SrcBits, X, Y, Width, Height, 1, 0); GetAlphaEndPoints(Pixels, AlphaBlock.Alphas[1], AlphaBlock.Alphas[0]); GetAlphaMask(AlphaBlock.Alphas[0], AlphaBlock.Alphas[1], Pixels, PByteArray(@AlphaBlock.Alphas[2])); PDXTAlphaBlockInt(DestBits)^ := AlphaBlock; Inc(DestBits, SizeOf(AlphaBlock)); end; end; procedure EncodeATI2N(SrcBits: Pointer; DestBits: PByte; Width, Height: Integer); var X, Y: Integer; AlphaBlock: TDXTAlphaBlockInt; Pixels: TPixelBlock; begin for Y := 0 to Height div 4 - 1 do for X := 0 to Width div 4 - 1 do begin // Encode Red/X channel GetOneChannelBlock(Pixels, SrcBits, X, Y, Width, Height, 4, ChannelRed); GetAlphaEndPoints(Pixels, AlphaBlock.Alphas[1], AlphaBlock.Alphas[0]); GetAlphaMask(AlphaBlock.Alphas[0], AlphaBlock.Alphas[1], Pixels, PByteArray(@AlphaBlock.Alphas[2])); PDXTAlphaBlockInt(DestBits)^ := AlphaBlock; Inc(DestBits, SizeOf(AlphaBlock)); // Encode Green/Y channel GetOneChannelBlock(Pixels, SrcBits, X, Y, Width, Height, 4, ChannelGreen); GetAlphaEndPoints(Pixels, AlphaBlock.Alphas[1], AlphaBlock.Alphas[0]); GetAlphaMask(AlphaBlock.Alphas[0], AlphaBlock.Alphas[1], Pixels, PByteArray(@AlphaBlock.Alphas[2])); PDXTAlphaBlockInt(DestBits)^ := AlphaBlock; Inc(DestBits, SizeOf(AlphaBlock)); end; end; procedure EncodeBinary(SrcBits: Pointer; DestBits: PByte; Width, Height: Integer); var Src: PByte absolute SrcBits; Bitmap: PByteArray absolute DestBits; X, Y, WidthBytes: Integer; PixelTresholded, Treshold: Byte; begin Treshold := ClampToByte(GetOption(ImagingBinaryTreshold)); WidthBytes := (Width + 7) div 8; for Y := 0 to Height - 1 do for X := 0 to Width - 1 do begin if Src^ > Treshold then PixelTresholded := 255 else PixelTresholded := 0; Bitmap[Y * WidthBytes + X div 8] := Bitmap[Y * WidthBytes + X div 8] or // OR current value of byte with following: (PixelTresholded and 1) // To make 1 from 255, 0 remains 0 shl (7 - (X mod 8)); // Put current bit to proper place in byte Inc(Src); end; end; procedure DecodeBTC(SrcBits, DestBits: PByte; Width, Height: Integer); var X, Y, I, J, K: Integer; Block: TBTCBlock; Dest: PByte; begin for Y := 0 to Height div 4 - 1 do for X := 0 to Width div 4 - 1 do begin Block := PBTCBlock(SrcBits)^; Inc(SrcBits, SizeOf(Block)); K := 0; // Just write MUpper when there is '1' in bit field and MLower // when there is '0' for I := 0 to 3 do for J := 0 to 3 do begin Dest := @PByteArray(DestBits)[(Y shl 2 + I) * Width + X shl 2 + J]; if Block.BitField and (1 shl K) <> 0 then Dest^ := Block.MUpper else Dest^ := Block.MLower; Inc(K); end; end; end; procedure DecodeATI1N(SrcBits, DestBits: PByte; Width, Height: Integer); var X, Y, I, J: Integer; AlphaBlock: TDXTAlphaBlockInt; AMask: array[0..1] of LongWord; begin for Y := 0 to Height div 4 - 1 do for X := 0 to Width div 4 - 1 do begin AlphaBlock := PDXTAlphaBlockInt(SrcBits)^; Inc(SrcBits, SizeOf(AlphaBlock)); // 6 bit alpha mask is copied into two long words for // easier usage AMask[0] := PLongWord(@AlphaBlock.Alphas[2])^ and $00FFFFFF; AMask[1] := PLongWord(@AlphaBlock.Alphas[5])^ and $00FFFFFF; // alpha interpolation between two endpoint alphas GetInterpolatedAlphas(AlphaBlock); // we distribute the dxt block alphas // across the 4x4 block of the destination image for J := 0 to 3 do for I := 0 to 3 do begin PByteArray(DestBits)[(Y shl 2 + J) * Width + (X shl 2 + I)] := AlphaBlock.Alphas[AMask[J shr 1] and 7]; AMask[J shr 1] := AMask[J shr 1] shr 3; end; end; end; procedure DecodeATI2N(SrcBits, DestBits: PByte; Width, Height: Integer); var X, Y, I, J: Integer; Color: TColor32Rec; AlphaBlock1, AlphaBlock2: TDXTAlphaBlockInt; AMask1: array[0..1] of LongWord; AMask2: array[0..1] of LongWord; begin for Y := 0 to Height div 4 - 1 do for X := 0 to Width div 4 - 1 do begin // Read the first alpha block and get masks AlphaBlock1 := PDXTAlphaBlockInt(SrcBits)^; Inc(SrcBits, SizeOf(AlphaBlock1)); AMask1[0] := PLongWord(@AlphaBlock1.Alphas[2])^ and $00FFFFFF; AMask1[1] := PLongWord(@AlphaBlock1.Alphas[5])^ and $00FFFFFF; // Read the secind alpha block and get masks AlphaBlock2 := PDXTAlphaBlockInt(SrcBits)^; Inc(SrcBits, SizeOf(AlphaBlock2)); AMask2[0] := PLongWord(@AlphaBlock2.Alphas[2])^ and $00FFFFFF; AMask2[1] := PLongWord(@AlphaBlock2.Alphas[5])^ and $00FFFFFF; // alpha interpolation between two endpoint alphas GetInterpolatedAlphas(AlphaBlock1); GetInterpolatedAlphas(AlphaBlock2); Color.A := $FF; Color.B := 0; // Distribute alpha block values across 4x4 pixel block, // first alpha block represents Red channel, second is Green. for J := 0 to 3 do for I := 0 to 3 do begin Color.R := AlphaBlock1.Alphas[AMask1[J shr 1] and 7]; Color.G := AlphaBlock2.Alphas[AMask2[J shr 1] and 7]; PColor32RecArray(DestBits)[(Y shl 2 + J) * Width + (X shl 2 + I)] := Color; AMask1[J shr 1] := AMask1[J shr 1] shr 3; AMask2[J shr 1] := AMask2[J shr 1] shr 3; end; end; end; procedure DecodeBinary(SrcBits, DestBits: PByte; Width, Height: Integer); {$IFDEF USE_INLINE}inline;{$ENDIF} begin Convert1To8(SrcBits, DestBits, Width, Height, (Width + 7) div 8, True); end; procedure SpecialToUnSpecial(const SrcImage: TImageData; DestBits: Pointer; SpecialFormat: TImageFormat); begin case SpecialFormat of ifDXT1: DecodeDXT1(SrcImage.Bits, DestBits, SrcImage.Width, SrcImage.Height); ifDXT3: DecodeDXT3(SrcImage.Bits, DestBits, SrcImage.Width, SrcImage.Height); ifDXT5: DecodeDXT5(SrcImage.Bits, DestBits, SrcImage.Width, SrcImage.Height); ifBTC: DecodeBTC (SrcImage.Bits, DestBits, SrcImage.Width, SrcImage.Height); ifATI1N: DecodeATI1N(SrcImage.Bits, DestBits, SrcImage.Width, SrcImage.Height); ifATI2N: DecodeATI2N(SrcImage.Bits, DestBits, SrcImage.Width, SrcImage.Height); ifBinary: DecodeBinary(SrcImage.Bits, DestBits, SrcImage.Width, SrcImage.Height); end; end; procedure UnSpecialToSpecial(SrcBits: Pointer; const DestImage: TImageData; SpecialFormat: TImageFormat); begin case SpecialFormat of ifDXT1: EncodeDXT1(SrcBits, DestImage.Bits, DestImage.Width, DestImage.Height); ifDXT3: EncodeDXT3(SrcBits, DestImage.Bits, DestImage.Width, DestImage.Height); ifDXT5: EncodeDXT5(SrcBits, DestImage.Bits, DestImage.Width, DestImage.Height); ifBTC: EncodeBTC (SrcBits, DestImage.Bits, DestImage.Width, DestImage.Height); ifATI1N: EncodeATI1N(SrcBits, DestImage.Bits, DestImage.Width, DestImage.Height); ifATI2N: EncodeATI2N(SrcBits, DestImage.Bits, DestImage.Width, DestImage.Height); ifBinary: EncodeBinary(SrcBits, DestImage.Bits, DestImage.Width, DestImage.Height); end; end; procedure ConvertSpecial(var Image: TImageData; SrcInfo, DstInfo: PImageFormatInfo); var WorkImage: TImageData; procedure CheckSize(var Img: TImageData; Info: PImageFormatInfo); var Width, Height: Integer; begin Width := Img.Width; Height := Img.Height; DstInfo.CheckDimensions(Info.Format, Width, Height); ResizeImage(Img, Width, Height, rfNearest); end; begin if SrcInfo.IsSpecial and DstInfo.IsSpecial then begin // Convert source to nearest 'normal' format InitImage(WorkImage); NewImage(Image.Width, Image.Height, SrcInfo.SpecialNearestFormat, WorkImage); SpecialToUnSpecial(Image, WorkImage.Bits, SrcInfo.Format); FreeImage(Image); // Make sure output of SpecialToUnSpecial is the same as input of // UnSpecialToSpecial if SrcInfo.SpecialNearestFormat <> DstInfo.SpecialNearestFormat then ConvertImage(WorkImage, DstInfo.SpecialNearestFormat); // Convert work image to dest special format CheckSize(WorkImage, DstInfo); NewImage(WorkImage.Width, WorkImage.Height, DstInfo.Format, Image); UnSpecialToSpecial(WorkImage.Bits, Image, DstInfo.Format); FreeImage(WorkImage); end else if SrcInfo.IsSpecial and not DstInfo.IsSpecial then begin // Convert source to nearest 'normal' format InitImage(WorkImage); NewImage(Image.Width, Image.Height, SrcInfo.SpecialNearestFormat, WorkImage); SpecialToUnSpecial(Image, WorkImage.Bits, SrcInfo.Format); FreeImage(Image); // Now convert to dest format ConvertImage(WorkImage, DstInfo.Format); Image := WorkImage; end else if not SrcInfo.IsSpecial and DstInfo.IsSpecial then begin // Convert source to nearest format WorkImage := Image; ConvertImage(WorkImage, DstInfo.SpecialNearestFormat); // Now convert from nearest to dest CheckSize(WorkImage, DstInfo); InitImage(Image); NewImage(WorkImage.Width, WorkImage.Height, DstInfo.Format, Image); UnSpecialToSpecial(WorkImage.Bits, Image, DstInfo.Format); FreeImage(WorkImage); end; end; function GetStdPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt; begin if FInfos[Format] <> nil then Result := Width * Height * FInfos[Format].BytesPerPixel else Result := 0; end; procedure CheckStdDimensions(Format: TImageFormat; var Width, Height: LongInt); begin end; function GetDXTPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt; begin // DXT can be used only for images with dimensions that are // multiples of four CheckDXTDimensions(Format, Width, Height); Result := Width * Height; if Format in [ifDXT1, ifATI1N] then Result := Result div 2; end; procedure CheckDXTDimensions(Format: TImageFormat; var Width, Height: LongInt); begin // DXT image dimensions must be multiples of four Width := (Width + 3) and not 3; // div 4 * 4; Height := (Height + 3) and not 3; // div 4 * 4; end; function GetBTCPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt; begin // BTC can be used only for images with dimensions that are // multiples of four CheckDXTDimensions(Format, Width, Height); Result := Width * Height div 4; // 2bits/pixel end; function GetBinaryPixelsSize(Format: TImageFormat; Width, Height: LongInt): LongInt; begin // Binary images are aligned on BYTE boundary Result := ((Width + 7) div 8) * Height; // 1bit/pixel end; { Optimized pixel readers/writers for 32bit and FP colors to be stored in TImageFormatInfo } function GetPixel32ifA8R8G8B8(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColor32Rec; begin Result.Color := PLongWord(Bits)^; end; procedure SetPixel32ifA8R8G8B8(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColor32Rec); begin PLongWord(Bits)^ := Color.Color; end; function GetPixelFPifA8R8G8B8(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColorFPRec; begin Result.A := PColor32Rec(Bits).A * OneDiv8Bit; Result.R := PColor32Rec(Bits).R * OneDiv8Bit; Result.G := PColor32Rec(Bits).G * OneDiv8Bit; Result.B := PColor32Rec(Bits).B * OneDiv8Bit; end; procedure SetPixelFPifA8R8G8B8(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColorFPRec); begin PColor32Rec(Bits).A := ClampToByte(Round(Color.A * 255.0)); PColor32Rec(Bits).R := ClampToByte(Round(Color.R * 255.0)); PColor32Rec(Bits).G := ClampToByte(Round(Color.G * 255.0)); PColor32Rec(Bits).B := ClampToByte(Round(Color.B * 255.0)); end; function GetPixel32Channel8Bit(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColor32Rec; begin case Info.Format of ifR8G8B8, ifX8R8G8B8: begin Result.A := $FF; PColor24Rec(@Result)^ := PColor24Rec(Bits)^; end; ifGray8, ifA8Gray8: begin if Info.HasAlphaChannel then Result.A := PWordRec(Bits).High else Result.A := $FF; Result.R := PWordRec(Bits).Low; Result.G := PWordRec(Bits).Low; Result.B := PWordRec(Bits).Low; end; end; end; procedure SetPixel32Channel8Bit(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColor32Rec); begin case Info.Format of ifR8G8B8, ifX8R8G8B8: begin PColor24Rec(Bits)^ := PColor24Rec(@Color)^; end; ifGray8, ifA8Gray8: begin if Info.HasAlphaChannel then PWordRec(Bits).High := Color.A; PWordRec(Bits).Low := Round(GrayConv.R * Color.R + GrayConv.G * Color.G + GrayConv.B * Color.B); end; end; end; function GetPixelFPChannel8Bit(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColorFPRec; begin case Info.Format of ifR8G8B8, ifX8R8G8B8: begin Result.A := 1.0; Result.R := PColor24Rec(Bits).R * OneDiv8Bit; Result.G := PColor24Rec(Bits).G * OneDiv8Bit; Result.B := PColor24Rec(Bits).B * OneDiv8Bit; end; ifGray8, ifA8Gray8: begin if Info.HasAlphaChannel then Result.A := PWordRec(Bits).High * OneDiv8Bit else Result.A := 1.0; Result.R := PWordRec(Bits).Low * OneDiv8Bit; Result.G := PWordRec(Bits).Low * OneDiv8Bit; Result.B := PWordRec(Bits).Low * OneDiv8Bit; end; end; end; procedure SetPixelFPChannel8Bit(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColorFPRec); begin case Info.Format of ifR8G8B8, ifX8R8G8B8: begin PColor24Rec(Bits).R := ClampToByte(Round(Color.R * 255.0)); PColor24Rec(Bits).G := ClampToByte(Round(Color.G * 255.0)); PColor24Rec(Bits).B := ClampToByte(Round(Color.B * 255.0)); end; ifGray8, ifA8Gray8: begin if Info.HasAlphaChannel then PWordRec(Bits).High := ClampToByte(Round(Color.A * 255.0)); PWordRec(Bits).Low := ClampToByte(Round((GrayConv.R * Color.R + GrayConv.G * Color.G + GrayConv.B * Color.B) * 255.0)); end; end; end; function GetPixelFPFloat32(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColorFPRec; begin case Info.Format of ifA32R32G32B32F, ifA32B32G32R32F: begin Result := PColorFPRec(Bits)^; end; ifR32G32B32F, ifB32G32R32F: begin Result.A := 1.0; Result.Color96Rec := PColor96FPRec(Bits)^; end; ifR32F: begin Result.A := 1.0; Result.R := PSingle(Bits)^; Result.G := 0.0; Result.B := 0.0; end; end; if Info.IsRBSwapped then SwapValues(Result.R, Result.B); end; procedure SetPixelFPFloat32(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColorFPRec); begin case Info.Format of ifA32R32G32B32F, ifA32B32G32R32F: begin PColorFPRec(Bits)^ := Color; end; ifR32G32B32F, ifB32G32R32F: begin PColor96FPRec(Bits)^ := Color.Color96Rec; end; ifR32F: begin PSingle(Bits)^ := Color.R; end; end; if Info.IsRBSwapped then SwapValues(PColor96FPRec(Bits).R, PColor96FPRec(Bits).B); end; initialization // Initialize default sampling filter function pointers and radii SamplingFilterFunctions[sfNearest] := FilterNearest; SamplingFilterFunctions[sfLinear] := FilterLinear; SamplingFilterFunctions[sfCosine] := FilterCosine; SamplingFilterFunctions[sfHermite] := FilterHermite; SamplingFilterFunctions[sfQuadratic] := FilterQuadratic; SamplingFilterFunctions[sfGaussian] := FilterGaussian; SamplingFilterFunctions[sfSpline] := FilterSpline; SamplingFilterFunctions[sfLanczos] := FilterLanczos; SamplingFilterFunctions[sfMitchell] := FilterMitchell; SamplingFilterFunctions[sfCatmullRom] := FilterCatmullRom; SamplingFilterRadii[sfNearest] := 1.0; SamplingFilterRadii[sfLinear] := 1.0; SamplingFilterRadii[sfCosine] := 1.0; SamplingFilterRadii[sfHermite] := 1.0; SamplingFilterRadii[sfQuadratic] := 1.5; SamplingFilterRadii[sfGaussian] := 1.25; SamplingFilterRadii[sfSpline] := 2.0; SamplingFilterRadii[sfLanczos] := 3.0; SamplingFilterRadii[sfMitchell] := 2.0; SamplingFilterRadii[sfCatmullRom] := 2.0; { File Notes: -- TODOS ---------------------------------------------------- - nothing now -- 0.77 Changes/Bug Fixes ------------------------------------- - Added ConvertToPixel32 helper function. -- 0.26.5 Changes/Bug Fixes ----------------------------------- - Removed optimized codepatch for few data formats from StretchResample function. It was quite buggy and not so much faster anyway. - Added PaletteHasAlpha function. - Added support functions for ifBinary data format. - Added optional pixel scaling to Convert1To8, Convert2To8, abd Convert4To8 functions. -- 0.26.3 Changes/Bug Fixes ----------------------------------- - Filtered resampling ~10% faster now. - Fixed DXT3 alpha encoding. - ifIndex8 format now has HasAlphaChannel=True. -- 0.25.0 Changes/Bug Fixes ----------------------------------- - Made some resampling stuff public so that it can be used in canvas class. - Added some color constructors. - Added VisualizePalette helper function. - Fixed ConvertSpecial, not very readable before and error when converting special->special. -- 0.24.3 Changes/Bug Fixes ----------------------------------- - Some refactorings a changes to DXT based formats. - Added ifATI1N and ifATI2N image data formats support structures and functions. -- 0.23 Changes/Bug Fixes ----------------------------------- - Added ifBTC image format support structures and functions. -- 0.21 Changes/Bug Fixes ----------------------------------- - FillMipMapLevel now works well with indexed and special formats too. - Moved Convert1To8 and Convert4To8 functions from ImagingBitmaps here and created new Convert2To8 function. They are now used by more than one file format loader. -- 0.19 Changes/Bug Fixes ----------------------------------- - StretchResample now uses pixel get/set functions stored in TImageFormatInfo so it is much faster for formats that override them with optimized ones - added pixel set/get functions optimized for various image formats (to be stored in TImageFormatInfo) - bug in ConvertSpecial caused problems when converting DXTC images to bitmaps in ImagingCoponents - bug in StretchRect caused that it didn't work with ifR32F and ifR16F formats - removed leftover code in FillMipMapLevel which disabled filtered resizing of images witch ChannelSize <> 8bits - added half float converting functions and support for half based image formats where needed - added TranslatePixel and IsImageFormatValid functions - fixed possible range overflows when converting from FP to integer images - added pixel set/get functions: GetPixel32Generic, GetPixelFPGeneric, SetPixel32Generic, SetPixelFPGeneric - fixed occasional range overflows in StretchResample -- 0.17 Changes/Bug Fixes ----------------------------------- - added StretchNearest, StretchResample and some sampling functions - added ChannelCount values to TImageFormatInfo constants - added resolution validity check to GetDXTPixelsSize -- 0.15 Changes/Bug Fixes ----------------------------------- - added RBSwapFormat values to some TImageFromatInfo definitions - fixed bug in ConvertSpecial (causing DXT images to convert only to 32bit) - added CopyPixel, ComparePixels helper functions -- 0.13 Changes/Bug Fixes ----------------------------------- - replaced pixel format conversions for colors not to be darkened when converting from low bit counts - ReduceColorsMedianCut was updated to support creating one optimal palette for more images and it is somewhat faster now too - there was ugly bug in DXTC dimensions checking } end. ================================================ FILE: lib/Imaging/ImagingIO.pas ================================================ { Vampyre Imaging Library by Marek Mauder http://imaginglib.sourceforge.net The contents of this file are used with permission, subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/MPL-1.1.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Alternatively, the contents of this file may be used under the terms of the GNU Lesser General Public License (the "LGPL License"), in which case the provisions of the LGPL License are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of the LGPL License and not to allow others to use your version of this file under the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the LGPL License. If you do not delete the provisions above, a recipient may use your version of this file under either the MPL or the LGPL License. For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html } { This unit contains default IO functions for reading from/writting to files, streams and memory.} unit ImagingIO; {$I ImagingOptions.inc} interface uses SysUtils, Classes, ImagingTypes, Imaging, ImagingUtility; type TMemoryIORec = record Data: ImagingUtility.PByteArray; Position: LongInt; Size: LongInt; end; PMemoryIORec = ^TMemoryIORec; var OriginalFileIO: TIOFunctions; FileIO: TIOFunctions; StreamIO: TIOFunctions; MemoryIO: TIOFunctions; { Helper function that returns size of input (from current position to the end) represented by Handle (and opened and operated on by members of IOFunctions).} function GetInputSize(IOFunctions: TIOFunctions; Handle: TImagingHandle): LongInt; { Helper function that initializes TMemoryIORec with given params.} function PrepareMemIO(Data: Pointer; Size: LongInt): TMemoryIORec; { Reads one text line from input (CR+LF, CR, or LF as line delimiter).} function ReadLine(IOFunctions: TIOFunctions; Handle: TImagingHandle; out Line: AnsiString; FailOnControlChars: Boolean = False): Boolean; { Writes one text line to input with optional line delimiter.} procedure WriteLine(IOFunctions: TIOFunctions; Handle: TImagingHandle; const Line: AnsiString; const LineEnding: AnsiString = sLineBreak); implementation const DefaultBufferSize = 16 * 1024; type { Based on TaaBufferedStream Copyright (c) Julian M Bucknall 1997, 1999 } TBufferedStream = class private FBuffer: PByteArray; FBufSize: Integer; FBufStart: Integer; FBufPos: Integer; FBytesInBuf: Integer; FSize: Integer; FDirty: Boolean; FStream: TStream; function GetPosition: Integer; function GetSize: Integer; procedure ReadBuffer; procedure WriteBuffer; procedure SetPosition(const Value: Integer); public constructor Create(AStream: TStream); destructor Destroy; override; function Read(var Buffer; Count: Integer): Integer; function Write(const Buffer; Count: Integer): Integer; function Seek(Offset: Integer; Origin: Word): Integer; procedure Commit; property Stream: TStream read FStream; property Position: Integer read GetPosition write SetPosition; property Size: Integer read GetSize; end; constructor TBufferedStream.Create(AStream: TStream); begin inherited Create; FStream := AStream; FBufSize := DefaultBufferSize; GetMem(FBuffer, FBufSize); FBufPos := 0; FBytesInBuf := 0; FBufStart := 0; FDirty := False; FSize := AStream.Size; end; destructor TBufferedStream.Destroy; begin if FBuffer <> nil then begin Commit; FreeMem(FBuffer); end; FStream.Position := Position; // Make sure source stream has right position inherited Destroy; end; function TBufferedStream.GetPosition: Integer; begin Result := FBufStart + FBufPos; end; procedure TBufferedStream.SetPosition(const Value: Integer); begin Seek(Value, soFromCurrent); end; function TBufferedStream.GetSize: Integer; begin Result := FSize; end; procedure TBufferedStream.ReadBuffer; var SeekResult: Integer; begin SeekResult := FStream.Seek(FBufStart, 0); if SeekResult = -1 then raise Exception.Create('TBufferedStream.ReadBuffer: seek failed'); FBytesInBuf := FStream.Read(FBuffer^, FBufSize); if FBytesInBuf <= 0 then raise Exception.Create('TBufferedStream.ReadBuffer: read failed'); end; procedure TBufferedStream.WriteBuffer; var SeekResult: Integer; BytesWritten: Integer; begin SeekResult := FStream.Seek(FBufStart, 0); if SeekResult = -1 then raise Exception.Create('TBufferedStream.WriteBuffer: seek failed'); BytesWritten := FStream.Write(FBuffer^, FBytesInBuf); if BytesWritten <> FBytesInBuf then raise Exception.Create('TBufferedStream.WriteBuffer: write failed'); end; procedure TBufferedStream.Commit; begin if FDirty then begin WriteBuffer; FDirty := False; end; end; function TBufferedStream.Read(var Buffer; Count: Integer): Integer; var BufAsBytes : TByteArray absolute Buffer; BufIdx, BytesToGo, BytesToRead: Integer; begin // Calculate the actual number of bytes we can read - this depends on // the current position and size of the stream as well as the number // of bytes requested. BytesToGo := Count; if FSize < (FBufStart + FBufPos + Count) then BytesToGo := FSize - (FBufStart + FBufPos); if BytesToGo <= 0 then begin Result := 0; Exit; end; // Remember to return the result of our calculation Result := BytesToGo; BufIdx := 0; if FBytesInBuf = 0 then ReadBuffer; // Calculate the number of bytes we can read prior to the loop BytesToRead := FBytesInBuf - FBufPos; if BytesToRead > BytesToGo then BytesToRead := BytesToGo; // Copy from the stream buffer to the caller's buffer Move(FBuffer^[FBufPos], BufAsBytes[BufIdx], BytesToRead); // Calculate the number of bytes still to read} Dec(BytesToGo, BytesToRead); // while we have bytes to read, read them while BytesToGo > 0 do begin Inc(BufIdx, BytesToRead); // As we've exhausted this buffer-full, advance to the next, check // to see whether we need to write the buffer out first if FDirty then begin WriteBuffer; FDirty := false; end; Inc(FBufStart, FBufSize); FBufPos := 0; ReadBuffer; // Calculate the number of bytes we can read in this cycle BytesToRead := FBytesInBuf; if BytesToRead > BytesToGo then BytesToRead := BytesToGo; // Ccopy from the stream buffer to the caller's buffer Move(FBuffer^, BufAsBytes[BufIdx], BytesToRead); // Calculate the number of bytes still to read Dec(BytesToGo, BytesToRead); end; // Remember our new position Inc(FBufPos, BytesToRead); if FBufPos = FBufSize then begin Inc(FBufStart, FBufSize); FBufPos := 0; FBytesInBuf := 0; end; end; function TBufferedStream.Seek(Offset: Integer; Origin: Word): Integer; var NewBufStart, NewPos: Integer; begin // Calculate the new position case Origin of soFromBeginning : NewPos := Offset; soFromCurrent : NewPos := FBufStart + FBufPos + Offset; soFromEnd : NewPos := FSize + Offset; else raise Exception.Create('TBufferedStream.Seek: invalid origin'); end; if (NewPos < 0) or (NewPos > FSize) then begin //NewPos := ClampInt(NewPos, 0, FSize); don't do this - for writing end; // Calculate which page of the file we need to be at NewBufStart := NewPos and not Pred(FBufSize); // If the new page is different than the old, mark the buffer as being // ready to be replenished, and if need be write out any dirty data if NewBufStart <> FBufStart then begin if FDirty then begin WriteBuffer; FDirty := False; end; FBufStart := NewBufStart; FBytesInBuf := 0; end; // Save the new position FBufPos := NewPos - NewBufStart; Result := NewPos; end; function TBufferedStream.Write(const Buffer; Count: Integer): Integer; var BufAsBytes: TByteArray absolute Buffer; BufIdx, BytesToGo, BytesToWrite: Integer; begin // When we write to this stream we always assume that we can write the // requested number of bytes: if we can't (eg, the disk is full) we'll // get an exception somewhere eventually. BytesToGo := Count; // Remember to return the result of our calculation Result := BytesToGo; BufIdx := 0; if (FBytesInBuf = 0) and (FSize > FBufStart) then ReadBuffer; // Calculate the number of bytes we can write prior to the loop BytesToWrite := FBufSize - FBufPos; if BytesToWrite > BytesToGo then BytesToWrite := BytesToGo; // Copy from the caller's buffer to the stream buffer Move(BufAsBytes[BufIdx], FBuffer^[FBufPos], BytesToWrite); // Mark our stream buffer as requiring a save to the actual stream, // note that this will suffice for the rest of the routine as well: no // inner routine will turn off the dirty flag. FDirty := True; // Calculate the number of bytes still to write Dec(BytesToGo, BytesToWrite); // While we have bytes to write, write them while BytesToGo > 0 do begin Inc(BufIdx, BytesToWrite); // As we've filled this buffer, write it out to the actual stream // and advance to the next buffer, reading it if required FBytesInBuf := FBufSize; WriteBuffer; Inc(FBufStart, FBufSize); FBufPos := 0; FBytesInBuf := 0; if FSize > FBufStart then ReadBuffer; // Calculate the number of bytes we can write in this cycle BytesToWrite := FBufSize; if BytesToWrite > BytesToGo then BytesToWrite := BytesToGo; // Copy from the caller's buffer to our buffer Move(BufAsBytes[BufIdx], FBuffer^, BytesToWrite); // Calculate the number of bytes still to write Dec(BytesToGo, BytesToWrite); end; // Remember our new position Inc(FBufPos, BytesToWrite); // Make sure the count of valid bytes is correct if FBytesInBuf < FBufPos then FBytesInBuf := FBufPos; // Make sure the stream size is correct if FSize < (FBufStart + FBytesInBuf) then FSize := FBufStart + FBytesInBuf; // If we're at the end of the buffer, write it out and advance to the // start of the next page if FBufPos = FBufSize then begin WriteBuffer; FDirty := False; Inc(FBufStart, FBufSize); FBufPos := 0; FBytesInBuf := 0; end; end; { File IO functions } function FileOpen(FileName: PChar; Mode: TOpenMode): TImagingHandle; cdecl; var Stream: TStream; begin Stream := nil; case Mode of omReadOnly: Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite); omCreate: Stream := TFileStream.Create(FileName, fmCreate); omReadWrite: begin if FileExists(FileName) then Stream := TFileStream.Create(FileName, fmOpenReadWrite or fmShareExclusive) else Stream := TFileStream.Create(FileName, fmCreate); end; end; Assert(Stream <> nil); Result := TBufferedStream.Create(Stream); end; procedure FileClose(Handle: TImagingHandle); cdecl; var Stream: TStream; begin Stream := TBufferedStream(Handle).Stream; TBufferedStream(Handle).Free; Stream.Free; end; function FileEof(Handle: TImagingHandle): Boolean; cdecl; begin Result := TBufferedStream(Handle).Position = TBufferedStream(Handle).Size; end; function FileSeek(Handle: TImagingHandle; Offset: LongInt; Mode: TSeekMode): LongInt; cdecl; begin Result := TBufferedStream(Handle).Seek(Offset, LongInt(Mode)); end; function FileTell(Handle: TImagingHandle): LongInt; cdecl; begin Result := TBufferedStream(Handle).Position; end; function FileRead(Handle: TImagingHandle; Buffer: Pointer; Count: LongInt): LongInt; cdecl; begin Result := TBufferedStream(Handle).Read(Buffer^, Count); end; function FileWrite(Handle: TImagingHandle; Buffer: Pointer; Count: LongInt): LongInt; cdecl; begin Result := TBufferedStream(Handle).Write(Buffer^, Count); end; { Stream IO functions } function StreamOpen(FileName: PChar; Mode: TOpenMode): TImagingHandle; cdecl; begin Result := FileName; end; procedure StreamClose(Handle: TImagingHandle); cdecl; begin end; function StreamEof(Handle: TImagingHandle): Boolean; cdecl; begin Result := TStream(Handle).Position = TStream(Handle).Size; end; function StreamSeek(Handle: TImagingHandle; Offset: LongInt; Mode: TSeekMode): LongInt; cdecl; begin Result := TStream(Handle).Seek(Offset, LongInt(Mode)); end; function StreamTell(Handle: TImagingHandle): LongInt; cdecl; begin Result := TStream(Handle).Position; end; function StreamRead(Handle: TImagingHandle; Buffer: Pointer; Count: LongInt): LongInt; cdecl; begin Result := TStream(Handle).Read(Buffer^, Count); end; function StreamWrite(Handle: TImagingHandle; Buffer: Pointer; Count: LongInt): LongInt; cdecl; begin Result := TStream(Handle).Write(Buffer^, Count); end; { Memory IO functions } function MemoryOpen(FileName: PChar; Mode: TOpenMode): TImagingHandle; cdecl; begin Result := FileName; end; procedure MemoryClose(Handle: TImagingHandle); cdecl; begin end; function MemoryEof(Handle: TImagingHandle): Boolean; cdecl; begin Result := PMemoryIORec(Handle).Position = PMemoryIORec(Handle).Size; end; function MemorySeek(Handle: TImagingHandle; Offset: LongInt; Mode: TSeekMode): LongInt; cdecl; begin Result := PMemoryIORec(Handle).Position; case Mode of smFromBeginning: Result := Offset; smFromCurrent: Result := PMemoryIORec(Handle).Position + Offset; smFromEnd: Result := PMemoryIORec(Handle).Size + Offset; end; //Result := ClampInt(Result, 0, PMemoryIORec(Handle).Size); don't do this - some file formats use it PMemoryIORec(Handle).Position := Result; end; function MemoryTell(Handle: TImagingHandle): LongInt; cdecl; begin Result := PMemoryIORec(Handle).Position; end; function MemoryRead(Handle: TImagingHandle; Buffer: Pointer; Count: LongInt): LongInt; cdecl; var Rec: PMemoryIORec; begin Rec := PMemoryIORec(Handle); Result := Count; if Rec.Position + Count > Rec.Size then Result := Rec.Size - Rec.Position; Move(Rec.Data[Rec.Position], Buffer^, Result); Rec.Position := Rec.Position + Result; end; function MemoryWrite(Handle: TImagingHandle; Buffer: Pointer; Count: LongInt): LongInt; cdecl; var Rec: PMemoryIORec; begin Rec := PMemoryIORec(Handle); Result := Count; if Rec.Position + Count > Rec.Size then Result := Rec.Size - Rec.Position; Move(Buffer^, Rec.Data[Rec.Position], Result); Rec.Position := Rec.Position + Result; end; { Helper IO functions } function GetInputSize(IOFunctions: TIOFunctions; Handle: TImagingHandle): LongInt; var OldPos: Int64; begin OldPos := IOFunctions.Tell(Handle); IOFunctions.Seek(Handle, 0, smFromEnd); Result := IOFunctions.Tell(Handle); IOFunctions.Seek(Handle, OldPos, smFromBeginning); end; function PrepareMemIO(Data: Pointer; Size: LongInt): TMemoryIORec; begin Result.Data := Data; Result.Position := 0; Result.Size := Size; end; function ReadLine(IOFunctions: TIOFunctions; Handle: TImagingHandle; out Line: AnsiString; FailOnControlChars: Boolean): Boolean; const MaxLine = 1024; var EolPos, Pos: Integer; C: AnsiChar; EolReached: Boolean; Endings: set of AnsiChar; begin Line := ''; Pos := 0; EolPos := 0; EolReached := False; Endings := [#10, #13]; Result := True; while not IOFunctions.Eof(Handle) do begin IOFunctions.Read(Handle, @C, SizeOf(C)); if FailOnControlChars and (Byte(C) < $20) then begin Break; end; if not (C in Endings) then begin if EolReached then begin IOFunctions.Seek(Handle, EolPos, smFromBeginning); Exit; end else begin SetLength(Line, Length(Line) + 1); Line[Length(Line)] := C; end; end else if not EolReached then begin EolReached := True; EolPos := IOFunctions.Tell(Handle); end; Inc(Pos); if Pos >= MaxLine then begin Break; end; end; Result := False; IOFunctions.Seek(Handle, -Pos, smFromCurrent); end; procedure WriteLine(IOFunctions: TIOFunctions; Handle: TImagingHandle; const Line: AnsiString; const LineEnding: AnsiString); var ToWrite: AnsiString; begin ToWrite := Line + LineEnding; IOFunctions.Write(Handle, @ToWrite[1], Length(ToWrite)); end; initialization OriginalFileIO.Open := FileOpen; OriginalFileIO.Close := FileClose; OriginalFileIO.Eof := FileEof; OriginalFileIO.Seek := FileSeek; OriginalFileIO.Tell := FileTell; OriginalFileIO.Read := FileRead; OriginalFileIO.Write := FileWrite; StreamIO.Open := StreamOpen; StreamIO.Close := StreamClose; StreamIO.Eof := StreamEof; StreamIO.Seek := StreamSeek; StreamIO.Tell := StreamTell; StreamIO.Read := StreamRead; StreamIO.Write := StreamWrite; MemoryIO.Open := MemoryOpen; MemoryIO.Close := MemoryClose; MemoryIO.Eof := MemoryEof; MemoryIO.Seek := MemorySeek; MemoryIO.Tell := MemoryTell; MemoryIO.Read := MemoryRead; MemoryIO.Write := MemoryWrite; ResetFileIO; { File Notes: -- TODOS ---------------------------------------------------- - nothing now -- 0.77.1 --------------------------------------------------- - Updated IO Open functions according to changes in ImagingTypes. - Added ReadLine and WriteLine functions. -- 0.23 Changes/Bug Fixes ----------------------------------- - Added merge between buffered read-only and write-only file stream adapters - TIFF saving needed both reading and writing. - Fixed bug causing wrong value of TBufferedWriteFile.Size (needed to add buffer pos to size). -- 0.21 Changes/Bug Fixes ----------------------------------- - Removed TMemoryIORec.Written, use Position to get proper memory position (Written didn't take Seeks into account). - Added TBufferedReadFile and TBufferedWriteFile classes for buffered file reading/writting. File IO functions now use these classes resulting in performance increase mainly in file formats that read/write many small chunks. - Added fmShareDenyWrite to FileOpenRead. You can now read files opened for reading by Imaging from other apps. - Added GetInputSize and PrepareMemIO helper functions. -- 0.19 Changes/Bug Fixes ----------------------------------- - changed behaviour of MemorySeek to act as TStream based Seeks } end. ================================================ FILE: lib/Imaging/ImagingNetworkGraphics.pas ================================================ { Vampyre Imaging Library by Marek Mauder http://imaginglib.sourceforge.net The contents of this file are used with permission, subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/MPL-1.1.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Alternatively, the contents of this file may be used under the terms of the GNU Lesser General Public License (the "LGPL License"), in which case the provisions of the LGPL License are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of the LGPL License and not to allow others to use your version of this file under the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the LGPL License. If you do not delete the provisions above, a recipient may use your version of this file under either the MPL or the LGPL License. For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html } { This unit contains image format loaders/savers for Network Graphics image file formats PNG, MNG, and JNG.} unit ImagingNetworkGraphics; interface {$I ImagingOptions.inc} { If MNG support is enabled we must make sure PNG and JNG are enabled too.} {$IFNDEF DONT_LINK_MNG} {$UNDEF DONT_LINK_PNG} {$UNDEF DONT_LINK_JNG} {$ENDIF} uses Types, SysUtils, Classes, ImagingTypes, Imaging, ImagingUtility, ImagingFormats, dzlib; type { Basic class for Network Graphics file formats loaders/savers.} TNetworkGraphicsFileFormat = class(TImageFileFormat) protected FSignature: TChar8; FPreFilter: LongInt; FCompressLevel: LongInt; FLossyCompression: LongBool; FLossyAlpha: LongBool; FQuality: LongInt; FProgressive: LongBool; FZLibStategy: Integer; function GetSupportedFormats: TImageFormats; override; procedure ConvertToSupported(var Image: TImageData; const Info: TImageFormatInfo); override; procedure Define; override; public function TestFormat(Handle: TImagingHandle): Boolean; override; procedure CheckOptionsValidity; override; published { Sets precompression filter used when saving images with lossless compression. Allowed values are: 0 (none), 1 (sub), 2 (up), 3 (average), 4 (paeth), 5 (use 0 for indexed/gray images and 4 for RGB/ARGB images), 6 (adaptive filtering - use best filter for each scanline - very slow). Note that filters 3 and 4 are much slower than filters 1 and 2. Default value is 5.} property PreFilter: LongInt read FPreFilter write FPreFilter; { Sets ZLib compression level used when saving images with lossless compression. Allowed values are in range 0 (no compresstion) to 9 (best compression). Default value is 5.} property CompressLevel: LongInt read FCompressLevel write FCompressLevel; { Specifies whether MNG animation frames are saved with lossy or lossless compression. Lossless frames are saved as PNG images and lossy frames are saved as JNG images. Allowed values are 0 (False) and 1 (True). Default value is 0.} property LossyCompression: LongBool read FLossyCompression write FLossyCompression; { Defines whether alpha channel of lossy MNG frames or JNG images is lossy compressed too. Allowed values are 0 (False) and 1 (True). Default value is 0.} property LossyAlpha: LongBool read FLossyAlpha write FLossyAlpha; { Specifies compression quality used when saving lossy MNG frames or JNG images. For details look at ImagingJpegQuality option.} property Quality: LongInt read FQuality write FQuality; { Specifies whether images are saved in progressive format when saving lossy MNG frames or JNG images. For details look at ImagingJpegProgressive.} property Progressive: LongBool read FProgressive write FProgressive; end; { Class for loading Portable Network Graphics Images. Loads all types of this image format (all images in png test suite) and saves all types with bitcount >= 8 (non-interlaced only). Compression level and filtering can be set by options interface. Supported ancillary chunks (loading): tRNS, bKGD (for indexed images transparency contains alpha values for palette, RGB/Gray images with transparency are converted to formats with alpha and pixels with transparent color are replaced with background color with alpha = 0).} TPNGFileFormat = class(TNetworkGraphicsFileFormat) private FLoadAnimated: LongBool; protected procedure Define; override; function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; override; function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray; Index: LongInt): Boolean; override; published property LoadAnimated: LongBool read FLoadAnimated write FLoadAnimated; end; {$IFNDEF DONT_LINK_MNG} { Class for loading Multiple Network Graphics files. This format has complex animation capabilities but Imaging only extracts frames. Individual frames are stored as standard PNG or JNG images. Loads all types of these frames stored in IHDR-IEND and JHDR-IEND streams (Note that there are MNG chunks like BASI which define images but does not contain image data itself, those are ignored). Imaging saves MNG files as MNG-VLC (very low complexity) so it is basicaly an array of image frames without MNG animation chunks. Frames can be saved as lossless PNG or lossy JNG images (look at TPNGFileFormat and TJNGFileFormat for info). Every frame can be in different data format. Many frame compression settings can be modified by options interface.} TMNGFileFormat = class(TNetworkGraphicsFileFormat) protected procedure Define; override; function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; override; function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray; Index: LongInt): Boolean; override; end; {$ENDIF} {$IFNDEF DONT_LINK_JNG} { Class for loading JPEG Network Graphics Images. Loads all types of this image format (all images in jng test suite) and saves all types except 12 bit JPEGs. Alpha channel in JNG images is stored separately from color/gray data and can be lossy (as JPEG image) or lossless (as PNG image) compressed. Type of alpha compression, compression level and quality, and filtering can be set by options interface. Supported ancillary chunks (loading): tRNS, bKGD (Images with transparency are converted to formats with alpha and pixels with transparent color are replaced with background color with alpha = 0).} TJNGFileFormat = class(TNetworkGraphicsFileFormat) protected procedure Define; override; function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; override; function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray; Index: LongInt): Boolean; override; end; {$ENDIF} implementation uses {$IFNDEF DONT_LINK_JNG} ImagingJpeg, ImagingIO, {$ENDIF} ImagingCanvases; const NGDefaultPreFilter = 5; NGDefaultCompressLevel = 5; NGDefaultLossyAlpha = False; NGDefaultLossyCompression = False; NGDefaultProgressive = False; NGDefaultQuality = 90; NGLosslessFormats: TImageFormats = [ifIndex8, ifGray8, ifA8Gray8, ifGray16, ifA16Gray16, ifR8G8B8, ifA8R8G8B8, ifR16G16B16, ifA16R16G16B16, ifB16G16R16, ifA16B16G16R16, ifBinary]; NGLossyFormats: TImageFormats = [ifGray8, ifA8Gray8, ifR8G8B8, ifA8R8G8B8]; PNGDefaultLoadAnimated = True; NGDefaultZLibStartegy = 1; // Z_FILTERED SPNGFormatName = 'Portable Network Graphics'; SPNGMasks = '*.png'; SMNGFormatName = 'Multiple Network Graphics'; SMNGMasks = '*.mng'; SJNGFormatName = 'JPEG Network Graphics'; SJNGMasks = '*.jng'; resourcestring SErrorLoadingChunk = 'Error when reading %s chunk data. File may be corrupted.'; type { Chunk header.} TChunkHeader = packed record DataSize: LongWord; ChunkID: TChar4; end; { IHDR chunk format - PNG header.} TIHDR = packed record Width: LongWord; // Image width Height: LongWord; // Image height BitDepth: Byte; // Bits per pixel or bits per sample (for truecolor) ColorType: Byte; // 0 = grayscale, 2 = truecolor, 3 = palette, // 4 = gray + alpha, 6 = truecolor + alpha Compression: Byte; // Compression type: 0 = ZLib Filter: Byte; // Used precompress filter Interlacing: Byte; // Used interlacing: 0 = no int, 1 = Adam7 end; PIHDR = ^TIHDR; { MHDR chunk format - MNG header.} TMHDR = packed record FrameWidth: LongWord; // Frame width FrameHeight: LongWord; // Frame height TicksPerSecond: LongWord; // FPS of animation NominalLayerCount: LongWord; // Number of layers in file NominalFrameCount: LongWord; // Number of frames in file NominalPlayTime: LongWord; // Play time of animation in ticks SimplicityProfile: LongWord; // Defines which MNG features are used in this file end; PMHDR = ^TMHDR; { JHDR chunk format - JNG header.} TJHDR = packed record Width: LongWord; // Image width Height: LongWord; // Image height ColorType: Byte; // 8 = grayscale (Y), 10 = color (YCbCr), // 12 = gray + alpha (Y-alpha), 14 = color + alpha (YCbCr-alpha) SampleDepth: Byte; // 8, 12 or 20 (8 and 12 samples together) bit Compression: Byte; // Compression type: 8 = Huffman coding Interlacing: Byte; // 0 = single scan, 8 = progressive AlphaSampleDepth: Byte; // 0, 1, 2, 4, 8, 16 if alpha compression is 0 (PNG) // 8 if alpha compression is 8 (JNG) AlphaCompression: Byte; // 0 = PNG graysscale IDAT, 8 = grayscale 8-bit JPEG AlphaFilter: Byte; // 0 = PNG filter or no filter (JPEG) AlphaInterlacing: Byte; // 0 = non interlaced end; PJHDR = ^TJHDR; { acTL chunk format - APNG animation control.} TacTL = packed record NumFrames: LongWord; // Number of frames NumPlay: LongWord; // Number of times to loop the animation (0 = inf) end; PacTL =^TacTL; { fcTL chunk format - APNG frame control.} TfcTL = packed record SeqNumber: LongWord; // Sequence number of the animation chunk, starting from 0 Width: LongWord; // Width of the following frame Height: LongWord; // Height of the following frame XOffset: LongWord; // X position at which to render the following frame YOffset: LongWord; // Y position at which to render the following frame DelayNumer: Word; // Frame delay fraction numerator DelayDenom: Word; // Frame delay fraction denominator DisposeOp: Byte; // Type of frame area disposal to be done after rendering this frame BlendOp: Byte; // Type of frame area rendering for this frame end; PfcTL = ^TfcTL; { pHYs chunk format - encodes the absolute or relative dimensions of pixels.} TpHYs = packed record PixelsPerUnitX: LongWord; PixelsPerUnitY: LongWord; UnitSpecifier: Byte; end; PpHYs = ^TpHYs; const { PNG file identifier.} PNGSignature: TChar8 = #$89'PNG'#$0D#$0A#$1A#$0A; { MNG file identifier.} MNGSignature: TChar8 = #$8A'MNG'#$0D#$0A#$1A#$0A; { JNG file identifier.} JNGSignature: TChar8 = #$8B'JNG'#$0D#$0A#$1A#$0A; { Constants for chunk identifiers and signature identifiers. They are in big-endian format.} IHDRChunk: TChar4 = 'IHDR'; IENDChunk: TChar4 = 'IEND'; MHDRChunk: TChar4 = 'MHDR'; MENDChunk: TChar4 = 'MEND'; JHDRChunk: TChar4 = 'JHDR'; IDATChunk: TChar4 = 'IDAT'; JDATChunk: TChar4 = 'JDAT'; JDAAChunk: TChar4 = 'JDAA'; JSEPChunk: TChar4 = 'JSEP'; PLTEChunk: TChar4 = 'PLTE'; BACKChunk: TChar4 = 'BACK'; DEFIChunk: TChar4 = 'DEFI'; TERMChunk: TChar4 = 'TERM'; tRNSChunk: TChar4 = 'tRNS'; bKGDChunk: TChar4 = 'bKGD'; gAMAChunk: TChar4 = 'gAMA'; acTLChunk: TChar4 = 'acTL'; fcTLChunk: TChar4 = 'fcTL'; fdATChunk: TChar4 = 'fdAT'; pHYsChunk: TChar4 = 'pHYs'; { APNG frame dispose operations.} DisposeOpNone = 0; DisposeOpBackground = 1; DisposeOpPrevious = 2; { APNG frame blending modes} BlendOpSource = 0; BlendOpOver = 1; { Interlace start and offsets.} RowStart: array[0..6] of LongInt = (0, 0, 4, 0, 2, 0, 1); ColumnStart: array[0..6] of LongInt = (0, 4, 0, 2, 0, 1, 0); RowIncrement: array[0..6] of LongInt = (8, 8, 8, 4, 4, 2, 2); ColumnIncrement: array[0..6] of LongInt = (8, 8, 4, 4, 2, 2, 1); type { Helper class that holds information about MNG frame in PNG or JNG format.} TFrameInfo = class public Index: Integer; FrameWidth, FrameHeight: LongInt; IsJpegFrame: Boolean; IHDR: TIHDR; JHDR: TJHDR; fcTL: TfcTL; pHYs: TpHYs; Palette: PPalette24; PaletteEntries: LongInt; Transparency: Pointer; TransparencySize: LongInt; Background: Pointer; BackgroundSize: LongInt; IDATMemory: TMemoryStream; JDATMemory: TMemoryStream; JDAAMemory: TMemoryStream; constructor Create(AIndex: Integer); destructor Destroy; override; procedure AssignSharedProps(Source: TFrameInfo); end; { Defines type of Network Graphics file.} TNGFileType = (ngPNG, ngAPNG, ngMNG, ngJNG); TNGFileHandler = class public FileFormat: TNetworkGraphicsFileFormat; FileType: TNGFileType; Frames: array of TFrameInfo; MHDR: TMHDR; // Main header for MNG files acTL: TacTL; // Global anim control for APNG files GlobalPalette: PPalette24; GlobalPaletteEntries: LongInt; GlobalTransparency: Pointer; GlobalTransparencySize: LongInt; constructor Create(AFileFormat: TNetworkGraphicsFileFormat); destructor Destroy; override; procedure Clear; function GetLastFrame: TFrameInfo; function AddFrameInfo: TFrameInfo; procedure LoadMetaData; end; { Network Graphics file parser and frame converter.} TNGFileLoader = class(TNGFileHandler) public function LoadFile(Handle: TImagingHandle): Boolean; procedure LoadImageFromPNGFrame(FrameWidth, FrameHeight: LongInt; const IHDR: TIHDR; IDATStream: TMemoryStream; var Image: TImageData); {$IFNDEF DONT_LINK_JNG} procedure LoadImageFromJNGFrame(FrameWidth, FrameHeight: LongInt; const JHDR: TJHDR; IDATStream, JDATStream, JDAAStream: TMemoryStream; var Image: TImageData); {$ENDIF} procedure ApplyFrameSettings(Frame: TFrameInfo; var Image: TImageData); end; TNGFileSaver = class(TNGFileHandler) public PreFilter: LongInt; CompressLevel: LongInt; LossyAlpha: Boolean; Quality: LongInt; Progressive: Boolean; ZLibStrategy: Integer; function SaveFile(Handle: TImagingHandle): Boolean; procedure AddFrame(const Image: TImageData; IsJpegFrame: Boolean); procedure StoreImageToPNGFrame(const IHDR: TIHDR; Bits: Pointer; FmtInfo: TImageFormatInfo; IDATStream: TMemoryStream); {$IFNDEF DONT_LINK_JNG} procedure StoreImageToJNGFrame(const JHDR: TJHDR; const Image: TImageData; IDATStream, JDATStream, JDAAStream: TMemoryStream); {$ENDIF} procedure SetFileOptions; end; {$IFNDEF DONT_LINK_JNG} TCustomIOJpegFileFormat = class(TJpegFileFormat) protected FCustomIO: TIOFunctions; procedure SetJpegIO(const JpegIO: TIOFunctions); override; procedure SetCustomIO(const CustomIO: TIOFunctions); end; {$ENDIF} TAPNGAnimator = class public class procedure Animate(var Images: TDynImageDataArray; const acTL: TacTL; const SrcFrames: array of TFrameInfo); end; { Helper routines } function PaethPredictor(A, B, C: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF} var P, PA, PB, PC: LongInt; begin P := A + B - C; PA := Abs(P - A); PB := Abs(P - B); PC := Abs(P - C); if (PA <= PB) and (PA <= PC) then Result := A else if PB <= PC then Result := B else Result := C; end; procedure SwapRGB(Line: PByte; Width, SampleDepth, BytesPerPixel: LongInt); var I: LongInt; Tmp: Word; begin case SampleDepth of 8: for I := 0 to Width - 1 do with PColor24Rec(Line)^ do begin Tmp := R; R := B; B := Tmp; Inc(Line, BytesPerPixel); end; 16: for I := 0 to Width - 1 do with PColor48Rec(Line)^ do begin Tmp := R; R := B; B := Tmp; Inc(Line, BytesPerPixel); end; end; end; {$IFNDEF DONT_LINK_JNG} { TCustomIOJpegFileFormat class implementation } procedure TCustomIOJpegFileFormat.SetCustomIO(const CustomIO: TIOFunctions); begin FCustomIO := CustomIO; end; procedure TCustomIOJpegFileFormat.SetJpegIO(const JpegIO: TIOFunctions); begin inherited SetJpegIO(FCustomIO); end; {$ENDIF} { TFrameInfo class implementation } constructor TFrameInfo.Create(AIndex: Integer); begin Index := AIndex; IDATMemory := TMemoryStream.Create; JDATMemory := TMemoryStream.Create; JDAAMemory := TMemoryStream.Create; end; destructor TFrameInfo.Destroy; begin FreeMem(Palette); FreeMem(Transparency); FreeMem(Background); IDATMemory.Free; JDATMemory.Free; JDAAMemory.Free; inherited Destroy; end; procedure TFrameInfo.AssignSharedProps(Source: TFrameInfo); begin IHDR := Source.IHDR; JHDR := Source.JHDR; PaletteEntries := Source.PaletteEntries; GetMem(Palette, PaletteEntries * SizeOf(TColor24Rec)); Move(Source.Palette^, Palette^, PaletteEntries * SizeOf(TColor24Rec)); TransparencySize := Source.TransparencySize; GetMem(Transparency, TransparencySize); Move(Source.Transparency^, Transparency^, TransparencySize); end; { TNGFileHandler class implementation} destructor TNGFileHandler.Destroy; begin Clear; inherited Destroy; end; procedure TNGFileHandler.Clear; var I: LongInt; begin for I := 0 to Length(Frames) - 1 do Frames[I].Free; SetLength(Frames, 0); FreeMemNil(GlobalPalette); GlobalPaletteEntries := 0; FreeMemNil(GlobalTransparency); GlobalTransparencySize := 0; end; constructor TNGFileHandler.Create(AFileFormat: TNetworkGraphicsFileFormat); begin FileFormat := AFileFormat; end; function TNGFileHandler.GetLastFrame: TFrameInfo; var Len: LongInt; begin Len := Length(Frames); if Len > 0 then Result := Frames[Len - 1] else Result := nil; end; procedure TNGFileHandler.LoadMetaData; var I: Integer; Delay, Denom: Integer; begin if FileType = ngAPNG then begin // Num plays of APNG animation FileFormat.FMetadata.SetMetaItem(SMetaAnimationLoops, acTL.NumPlay); end; for I := 0 to High(Frames) do begin if Frames[I].pHYs.UnitSpecifier = 1 then begin // Store physical pixel dimensions, in PNG stored as pixels per meter DPM FileFormat.FMetadata.SetPhysicalPixelSize(ruDpm, Frames[I].pHYs.PixelsPerUnitX, Frames[I].pHYs.PixelsPerUnitY); end; if FileType = ngAPNG then begin // Store frame delay of APNG file frame Denom := Frames[I].fcTL.DelayDenom; if Denom = 0 then Denom := 100; Delay := Round(1000 * (Frames[I].fcTL.DelayNumer / Denom)); FileFormat.FMetadata.SetMetaItem(SMetaFrameDelay, Delay, I); end; end; end; function TNGFileHandler.AddFrameInfo: TFrameInfo; var Len: LongInt; begin Len := Length(Frames); SetLength(Frames, Len + 1); Result := TFrameInfo.Create(Len); Frames[Len] := Result; end; { TNGFileLoader class implementation} function TNGFileLoader.LoadFile(Handle: TImagingHandle): Boolean; var Sig: TChar8; Chunk: TChunkHeader; ChunkData: Pointer; ChunkCrc: LongWord; procedure ReadChunk; begin GetIO.Read(Handle, @Chunk, SizeOf(Chunk)); Chunk.DataSize := SwapEndianLongWord(Chunk.DataSize); end; procedure ReadChunkData; var ReadBytes: LongWord; begin FreeMemNil(ChunkData); GetMem(ChunkData, Chunk.DataSize); ReadBytes := GetIO.Read(Handle, ChunkData, Chunk.DataSize); GetIO.Read(Handle, @ChunkCrc, SizeOf(ChunkCrc)); if ReadBytes <> Chunk.DataSize then RaiseImaging(SErrorLoadingChunk, [string(Chunk.ChunkID)]); end; procedure SkipChunkData; begin GetIO.Seek(Handle, Chunk.DataSize + SizeOf(ChunkCrc), smFromCurrent); end; procedure StartNewPNGImage; var Frame: TFrameInfo; begin ReadChunkData; if Chunk.ChunkID = fcTLChunk then begin if (Length(Frames) = 1) and (Frames[0].IDATMemory.Size = 0) then begin // First fcTL chunk maybe for first IDAT frame which is alredy created Frame := Frames[0]; end else begin // Subsequent APNG frames with data in fdAT Frame := AddFrameInfo; // Copy some shared props from first frame (IHDR is the same for all APNG frames, palette etc) Frame.AssignSharedProps(Frames[0]); end; Frame.fcTL := PfcTL(ChunkData)^; SwapEndianLongWord(@Frame.fcTL, 5); Frame.fcTL.DelayNumer := SwapEndianWord(Frame.fcTL.DelayNumer); Frame.fcTL.DelayDenom := SwapEndianWord(Frame.fcTL.DelayDenom); Frame.FrameWidth := Frame.fcTL.Width; Frame.FrameHeight := Frame.fcTL.Height; end else begin // This is frame defined by IHDR chunk Frame := AddFrameInfo; Frame.IHDR := PIHDR(ChunkData)^; SwapEndianLongWord(@Frame.IHDR, 2); Frame.FrameWidth := Frame.IHDR.Width; Frame.FrameHeight := Frame.IHDR.Height; end; Frame.IsJpegFrame := False; end; procedure StartNewJNGImage; var Frame: TFrameInfo; begin ReadChunkData; Frame := AddFrameInfo; Frame.IsJpegFrame := True; Frame.JHDR := PJHDR(ChunkData)^; SwapEndianLongWord(@Frame.JHDR, 2); Frame.FrameWidth := Frame.JHDR.Width; Frame.FrameHeight := Frame.JHDR.Height; end; procedure AppendIDAT; begin ReadChunkData; // Append current IDAT/fdAT chunk to storage stream if Chunk.ChunkID = IDATChunk then GetLastFrame.IDATMemory.Write(ChunkData^, Chunk.DataSize) else if Chunk.ChunkID = fdATChunk then GetLastFrame.IDATMemory.Write(PByteArray(ChunkData)[4], Chunk.DataSize - SizeOf(LongWord)); end; procedure AppendJDAT; begin ReadChunkData; // Append current JDAT chunk to storage stream GetLastFrame.JDATMemory.Write(ChunkData^, Chunk.DataSize); end; procedure AppendJDAA; begin ReadChunkData; // Append current JDAA chunk to storage stream GetLastFrame.JDAAMemory.Write(ChunkData^, Chunk.DataSize); end; procedure LoadPLTE; begin ReadChunkData; if GetLastFrame = nil then begin // Load global palette GetMem(GlobalPalette, Chunk.DataSize); Move(ChunkData^, GlobalPalette^, Chunk.DataSize); GlobalPaletteEntries := Chunk.DataSize div 3; end else if GetLastFrame.Palette = nil then begin if (Chunk.DataSize = 0) and (GlobalPalette <> nil) then begin // Use global palette GetMem(GetLastFrame.Palette, GlobalPaletteEntries * SizeOf(TColor24Rec)); Move(GlobalPalette^, GetLastFrame.Palette^, GlobalPaletteEntries * SizeOf(TColor24Rec)); GetLastFrame.PaletteEntries := GlobalPaletteEntries; end else begin // Load pal from PLTE chunk GetMem(GetLastFrame.Palette, Chunk.DataSize); Move(ChunkData^, GetLastFrame.Palette^, Chunk.DataSize); GetLastFrame.PaletteEntries := Chunk.DataSize div 3; end; end; end; procedure LoadtRNS; begin ReadChunkData; if GetLastFrame = nil then begin // Load global transparency GetMem(GlobalTransparency, Chunk.DataSize); Move(ChunkData^, GlobalTransparency^, Chunk.DataSize); GlobalTransparencySize := Chunk.DataSize; end else if GetLastFrame.Transparency = nil then begin if (Chunk.DataSize = 0) and (GlobalTransparency <> nil) then begin // Use global transparency GetMem(GetLastFrame.Transparency, GlobalTransparencySize); Move(GlobalTransparency^, GetLastFrame.Transparency^, Chunk.DataSize); GetLastFrame.TransparencySize := GlobalTransparencySize; end else begin // Load pal from tRNS chunk GetMem(GetLastFrame.Transparency, Chunk.DataSize); Move(ChunkData^, GetLastFrame.Transparency^, Chunk.DataSize); GetLastFrame.TransparencySize := Chunk.DataSize; end; end; end; procedure LoadbKGD; begin ReadChunkData; if GetLastFrame.Background = nil then begin GetMem(GetLastFrame.Background, Chunk.DataSize); Move(ChunkData^, GetLastFrame.Background^, Chunk.DataSize); GetLastFrame.BackgroundSize := Chunk.DataSize; end; end; procedure HandleacTL; begin FileType := ngAPNG; ReadChunkData; acTL := PacTL(ChunkData)^; SwapEndianLongWord(@acTL, SizeOf(acTL) div SizeOf(LongWord)); end; procedure LoadpHYs; begin ReadChunkData; with GetLastFrame do begin pHYs := PpHYs(ChunkData)^; SwapEndianLongWord(@pHYs, SizeOf(pHYs) div SizeOf(LongWord)); end; end; begin Result := False; Clear; ChunkData := nil; with GetIO do try Read(Handle, @Sig, SizeOf(Sig)); // Set file type according to the signature if Sig = PNGSignature then FileType := ngPNG else if Sig = MNGSignature then FileType := ngMNG else if Sig = JNGSignature then FileType := ngJNG else Exit; if FileType = ngMNG then begin // Store MNG header if present ReadChunk; ReadChunkData; MHDR := PMHDR(ChunkData)^; SwapEndianLongWord(@MHDR, SizeOf(MHDR) div SizeOf(LongWord)); end; // Read chunks until ending chunk or EOF is reached repeat ReadChunk; if (Chunk.ChunkID = IHDRChunk) or (Chunk.ChunkID = fcTLChunk) then StartNewPNGImage else if Chunk.ChunkID = JHDRChunk then StartNewJNGImage else if (Chunk.ChunkID = IDATChunk) or (Chunk.ChunkID = fdATChunk) then AppendIDAT else if Chunk.ChunkID = JDATChunk then AppendJDAT else if Chunk.ChunkID = JDAAChunk then AppendJDAA else if Chunk.ChunkID = PLTEChunk then LoadPLTE else if Chunk.ChunkID = tRNSChunk then LoadtRNS else if Chunk.ChunkID = bKGDChunk then LoadbKGD else if Chunk.ChunkID = acTLChunk then HandleacTL else if Chunk.ChunkID = pHYsChunk then LoadpHYs else SkipChunkData; until Eof(Handle) or (Chunk.ChunkID = MENDChunk) or ((FileType <> ngMNG) and (Chunk.ChunkID = IENDChunk)); Result := True; finally FreeMemNil(ChunkData); end; end; procedure TNGFileLoader.LoadImageFromPNGFrame(FrameWidth, FrameHeight: LongInt; const IHDR: TIHDR; IDATStream: TMemoryStream; var Image: TImageData); type TGetPixelFunc = function(Line: PByteArray; X: LongInt): Byte; var LineBuffer: array[Boolean] of PByteArray; ActLine: Boolean; Data, TotalBuffer, ZeroLine, PrevLine: Pointer; BitCount, TotalSize, TotalPos, BytesPerPixel, I, Pass, SrcDataSize, BytesPerLine, InterlaceLineBytes, InterlaceWidth: LongInt; Info: TImageFormatInfo; procedure DecodeAdam7; const BitTable: array[1..8] of LongInt = ($1, $3, 0, $F, 0, 0, 0, $FF); StartBit: array[1..8] of LongInt = (7, 6, 0, 4, 0, 0, 0, 0); var Src, Dst, Dst2: PByte; CurBit, Col: LongInt; begin Src := @LineBuffer[ActLine][1]; Col := ColumnStart[Pass]; with Image do case BitCount of 1, 2, 4: begin Dst := @PByteArray(Data)[I * BytesPerLine]; repeat CurBit := StartBit[BitCount]; repeat Dst2 := @PByteArray(Dst)[(BitCount * Col) shr 3]; Dst2^ := Dst2^ or ((Src^ shr CurBit) and BitTable[BitCount]) shl (StartBit[BitCount] - (Col * BitCount mod 8)); Inc(Col, ColumnIncrement[Pass]); Dec(CurBit, BitCount); until CurBit < 0; Inc(Src); until Col >= Width; end; else begin Dst := @PByteArray(Data)[I * BytesPerLine + Col * BytesPerPixel]; repeat CopyPixel(Src, Dst, BytesPerPixel); Inc(Dst, BytesPerPixel); Inc(Src, BytesPerPixel); Inc(Dst, ColumnIncrement[Pass] * BytesPerPixel - BytesPerPixel); Inc(Col, ColumnIncrement[Pass]); until Col >= Width; end; end; end; procedure FilterScanline(Filter: Byte; BytesPerPixel: LongInt; Line, PrevLine, Target: PByteArray; BytesPerLine: LongInt); var I: LongInt; begin case Filter of 0: begin // No filter Move(Line^, Target^, BytesPerLine); end; 1: begin // Sub filter Move(Line^, Target^, BytesPerPixel); for I := BytesPerPixel to BytesPerLine - 1 do Target[I] := (Line[I] + Target[I - BytesPerPixel]) and $FF; end; 2: begin // Up filter for I := 0 to BytesPerLine - 1 do Target[I] := (Line[I] + PrevLine[I]) and $FF; end; 3: begin // Average filter for I := 0 to BytesPerPixel - 1 do Target[I] := (Line[I] + PrevLine[I] shr 1) and $FF; for I := BytesPerPixel to BytesPerLine - 1 do Target[I] := (Line[I] + (Target[I - BytesPerPixel] + PrevLine[I]) shr 1) and $FF; end; 4: begin // Paeth filter for I := 0 to BytesPerPixel - 1 do Target[I] := (Line[I] + PaethPredictor(0, PrevLine[I], 0)) and $FF; for I := BytesPerPixel to BytesPerLine - 1 do Target[I] := (Line[I] + PaethPredictor(Target[I - BytesPerPixel], PrevLine[I], PrevLine[I - BytesPerPixel])) and $FF; end; end; end; procedure TransformLOCOToRGB(Data: PByte; NumPixels, BytesPerPixel: LongInt); var I: LongInt; begin for I := 0 to NumPixels - 1 do begin if IHDR.BitDepth = 8 then begin PColor32Rec(Data).R := Byte(PColor32Rec(Data).R + PColor32Rec(Data).G); PColor32Rec(Data).B := Byte(PColor32Rec(Data).B + PColor32Rec(Data).G); end else begin PColor64Rec(Data).R := Word(PColor64Rec(Data).R + PColor64Rec(Data).G); PColor64Rec(Data).B := Word(PColor64Rec(Data).B + PColor64Rec(Data).G); end; Inc(Data, BytesPerPixel); end; end; function CheckBinaryPalette: Boolean; begin with GetLastFrame do Result := (PaletteEntries = 2) and (Palette[0].R = 0) and (Palette[0].G = 0) and (Palette[0].B = 0) and (Palette[1].R = 255) and (Palette[1].G = 255) and (Palette[1].B = 255); end; begin Image.Width := FrameWidth; Image.Height := FrameHeight; Image.Format := ifUnknown; case IHDR.ColorType of 0: begin // Gray scale image case IHDR.BitDepth of 1: Image.Format := ifBinary; 2, 4, 8: Image.Format := ifGray8; 16: Image.Format := ifGray16; end; BitCount := IHDR.BitDepth; end; 2: begin // RGB image case IHDR.BitDepth of 8: Image.Format := ifR8G8B8; 16: Image.Format := ifR16G16B16; end; BitCount := IHDR.BitDepth * 3; end; 3: begin // Indexed image if (IHDR.BitDepth = 1) and CheckBinaryPalette then Image.Format := ifBinary else Image.Format := ifIndex8; BitCount := IHDR.BitDepth; end; 4: begin // Grayscale + alpha image case IHDR.BitDepth of 8: Image.Format := ifA8Gray8; 16: Image.Format := ifA16Gray16; end; BitCount := IHDR.BitDepth * 2; end; 6: begin // ARGB image case IHDR.BitDepth of 8: Image.Format := ifA8R8G8B8; 16: Image.Format := ifA16R16G16B16; end; BitCount := IHDR.BitDepth * 4; end; end; GetImageFormatInfo(Image.Format, Info); BytesPerPixel := (BitCount + 7) div 8; LineBuffer[True] := nil; LineBuffer[False] := nil; TotalBuffer := nil; ZeroLine := nil; ActLine := True; // Start decoding with Image do try BytesPerLine := (Width * BitCount + 7) div 8; SrcDataSize := Height * BytesPerLine; GetMem(Data, SrcDataSize); FillChar(Data^, SrcDataSize, 0); GetMem(ZeroLine, BytesPerLine); FillChar(ZeroLine^, BytesPerLine, 0); if IHDR.Interlacing = 1 then begin // Decode interlaced images TotalPos := 0; DecompressBuf(IDATStream.Memory, IDATStream.Size, 0, Pointer(TotalBuffer), TotalSize); GetMem(LineBuffer[True], BytesPerLine + 1); GetMem(LineBuffer[False], BytesPerLine + 1); for Pass := 0 to 6 do begin // Prepare next interlace run if Width <= ColumnStart[Pass] then Continue; InterlaceWidth := (Width + ColumnIncrement[Pass] - 1 - ColumnStart[Pass]) div ColumnIncrement[Pass]; InterlaceLineBytes := (InterlaceWidth * BitCount + 7) shr 3; I := RowStart[Pass]; FillChar(LineBuffer[True][0], BytesPerLine + 1, 0); FillChar(LineBuffer[False][0], BytesPerLine + 1, 0); while I < Height do begin // Copy line from decompressed data to working buffer Move(PByteArray(TotalBuffer)[TotalPos], LineBuffer[ActLine][0], InterlaceLineBytes + 1); Inc(TotalPos, InterlaceLineBytes + 1); // Swap red and blue channels if necessary if (IHDR.ColorType in [2, 6]) then SwapRGB(@LineBuffer[ActLine][1], InterlaceWidth, IHDR.BitDepth, BytesPerPixel); // Reverse-filter current scanline FilterScanline(LineBuffer[ActLine][0], BytesPerPixel, @LineBuffer[ActLine][1], @LineBuffer[not ActLine][1], @LineBuffer[ActLine][1], InterlaceLineBytes); // Decode Adam7 interlacing DecodeAdam7; ActLine := not ActLine; // Continue with next row in interlaced order Inc(I, RowIncrement[Pass]); end; end; end else begin // Decode non-interlaced images PrevLine := ZeroLine; DecompressBuf(IDATStream.Memory, IDATStream.Size, SrcDataSize + Height, Pointer(TotalBuffer), TotalSize); for I := 0 to Height - 1 do begin // Swap red and blue channels if necessary if IHDR.ColorType in [2, 6] then SwapRGB(@PByteArray(TotalBuffer)[I * (BytesPerLine + 1) + 1], Width, IHDR.BitDepth, BytesPerPixel); // reverse-filter current scanline FilterScanline(PByteArray(TotalBuffer)[I * (BytesPerLine + 1)], BytesPerPixel, @PByteArray(TotalBuffer)[I * (BytesPerLine + 1) + 1], PrevLine, @PByteArray(Data)[I * BytesPerLine], BytesPerLine); PrevLine := @PByteArray(Data)[I * BytesPerLine]; end; end; Size := Info.GetPixelsSize(Info.Format, Width, Height); if Size <> SrcDataSize then begin // If source data size is different from size of image in assigned // format we must convert it (it is in 1/2/4 bit count) GetMem(Bits, Size); case IHDR.BitDepth of 1: begin // Convert only indexed, keep black and white in ifBinary if IHDR.ColorType <> 0 then Convert1To8(Data, Bits, Width, Height, BytesPerLine, False); end; 2: Convert2To8(Data, Bits, Width, Height, BytesPerLine, IHDR.ColorType = 0); 4: Convert4To8(Data, Bits, Width, Height, BytesPerLine, IHDR.ColorType = 0); end; FreeMem(Data); end else begin // If source data size is the same as size of // image Bits in assigned format we simply copy pointer reference Bits := Data; end; // LOCO transformation was used too (only for color types 2 and 6) if (IHDR.Filter = 64) and (IHDR.ColorType in [2, 6]) then TransformLOCOToRGB(Bits, Width * Height, BytesPerPixel); // Images with 16 bit channels must be swapped because of PNG's big endianity if IHDR.BitDepth = 16 then SwapEndianWord(Bits, Width * Height * BytesPerPixel div SizeOf(Word)); finally FreeMem(LineBuffer[True]); FreeMem(LineBuffer[False]); FreeMem(TotalBuffer); FreeMem(ZeroLine); end; end; {$IFNDEF DONT_LINK_JNG} procedure TNGFileLoader.LoadImageFromJNGFrame(FrameWidth, FrameHeight: LongInt; const JHDR: TJHDR; IDATStream, JDATStream, JDAAStream: TMemoryStream; var Image: TImageData); var AlphaImage: TImageData; FakeIHDR: TIHDR; FmtInfo: TImageFormatInfo; I: LongInt; AlphaPtr: PByte; GrayPtr: PWordRec; ColorPtr: PColor32Rec; procedure LoadJpegFromStream(Stream: TStream; var DestImage: TImageData); var JpegFormat: TCustomIOJpegFileFormat; Handle: TImagingHandle; DynImages: TDynImageDataArray; begin if JHDR.SampleDepth <> 12 then begin JpegFormat := TCustomIOJpegFileFormat.Create; JpegFormat.SetCustomIO(StreamIO); Stream.Position := 0; Handle := StreamIO.Open(Pointer(Stream), omReadOnly); try JpegFormat.LoadData(Handle, DynImages, True); DestImage := DynImages[0]; finally StreamIO.Close(Handle); JpegFormat.Free; SetLength(DynImages, 0); end; end else NewImage(FrameWidth, FrameHeight, ifR8G8B8, DestImage); end; begin LoadJpegFromStream(JDATStream, Image); // If present separate alpha channel is processed if (JHDR.ColorType in [12, 14]) and (Image.Format in [ifGray8, ifR8G8B8]) then begin InitImage(AlphaImage); if JHDR.AlphaCompression = 0 then begin // Alpha channel is PNG compressed FakeIHDR.Width := JHDR.Width; FakeIHDR.Height := JHDR.Height; FakeIHDR.ColorType := 0; FakeIHDR.BitDepth := JHDR.AlphaSampleDepth; FakeIHDR.Filter := JHDR.AlphaFilter; FakeIHDR.Interlacing := JHDR.AlphaInterlacing; LoadImageFromPNGFrame(FrameWidth, FrameHeight, FakeIHDR, IDATStream, AlphaImage); end else begin // Alpha channel is JPEG compressed LoadJpegFromStream(JDAAStream, AlphaImage); end; // Check if alpha channel is the same size as image if (Image.Width <> AlphaImage.Width) and (Image.Height <> AlphaImage.Height) then ResizeImage(AlphaImage, Image.Width, Image.Height, rfNearest); // Check alpha channels data format GetImageFormatInfo(AlphaImage.Format, FmtInfo); if (FmtInfo.BytesPerPixel > 1) or (not FmtInfo.HasGrayChannel) then ConvertImage(AlphaImage, ifGray8); // Convert image to fromat with alpha channel if Image.Format = ifGray8 then ConvertImage(Image, ifA8Gray8) else ConvertImage(Image, ifA8R8G8B8); // Combine alpha channel with image AlphaPtr := AlphaImage.Bits; if Image.Format = ifA8Gray8 then begin GrayPtr := Image.Bits; for I := 0 to Image.Width * Image.Height - 1 do begin GrayPtr.High := AlphaPtr^; Inc(GrayPtr); Inc(AlphaPtr); end; end else begin ColorPtr := Image.Bits; for I := 0 to Image.Width * Image.Height - 1 do begin ColorPtr.A := AlphaPtr^; Inc(ColorPtr); Inc(AlphaPtr); end; end; FreeImage(AlphaImage); end; end; {$ENDIF} procedure TNGFileLoader.ApplyFrameSettings(Frame: TFrameInfo; var Image: TImageData); var FmtInfo: TImageFormatInfo; BackGroundColor: TColor64Rec; ColorKey: TColor64Rec; Alphas: PByteArray; AlphasSize: LongInt; IsColorKeyPresent: Boolean; IsBackGroundPresent: Boolean; IsColorFormat: Boolean; procedure ConverttRNS; begin if FmtInfo.IsIndexed then begin if Alphas = nil then begin GetMem(Alphas, Frame.TransparencySize); Move(Frame.Transparency^, Alphas^, Frame.TransparencySize); AlphasSize := Frame.TransparencySize; end; end else if not FmtInfo.HasAlphaChannel then begin FillChar(ColorKey, SizeOf(ColorKey), 0); Move(Frame.Transparency^, ColorKey, Min(Frame.TransparencySize, SizeOf(ColorKey))); if IsColorFormat then SwapValues(ColorKey.R, ColorKey.B); SwapEndianWord(@ColorKey, 3); // 1/2/4 bit images were converted to 8 bit so we must convert color key too if (not Frame.IsJpegFrame) and (Frame.IHDR.ColorType in [0, 4]) then case Frame.IHDR.BitDepth of 1: ColorKey.B := Word(ColorKey.B * 255); 2: ColorKey.B := Word(ColorKey.B * 85); 4: ColorKey.B := Word(ColorKey.B * 17); end; IsColorKeyPresent := True; end; end; procedure ConvertbKGD; begin FillChar(BackGroundColor, SizeOf(BackGroundColor), 0); Move(Frame.Background^, BackGroundColor, Min(Frame.BackgroundSize, SizeOf(BackGroundColor))); if IsColorFormat then SwapValues(BackGroundColor.R, BackGroundColor.B); SwapEndianWord(@BackGroundColor, 3); // 1/2/4 bit images were converted to 8 bit so we must convert back color too if (not Frame.IsJpegFrame) and (Frame.IHDR.ColorType in [0, 4]) then case Frame.IHDR.BitDepth of 1: BackGroundColor.B := Word(BackGroundColor.B * 255); 2: BackGroundColor.B := Word(BackGroundColor.B * 85); 4: BackGroundColor.B := Word(BackGroundColor.B * 17); end; IsBackGroundPresent := True; end; procedure ReconstructPalette; var I: LongInt; begin with Image do begin GetMem(Palette, FmtInfo.PaletteEntries * SizeOf(TColor32Rec)); FillChar(Palette^, FmtInfo.PaletteEntries * SizeOf(TColor32Rec), $FF); // if RGB palette was loaded from file then use it if Frame.Palette <> nil then for I := 0 to Min(Frame.PaletteEntries, FmtInfo.PaletteEntries) - 1 do with Palette[I] do begin R := Frame.Palette[I].B; G := Frame.Palette[I].G; B := Frame.Palette[I].R; end; // if palette alphas were loaded from file then use them if Alphas <> nil then begin for I := 0 to Min(AlphasSize, FmtInfo.PaletteEntries) - 1 do Palette[I].A := Alphas[I]; end; end; end; procedure ApplyColorKey; var DestFmt: TImageFormat; Col32, Bkg32: TColor32Rec; OldPixel, NewPixel: Pointer; begin case Image.Format of ifGray8: DestFmt := ifA8Gray8; ifGray16: DestFmt := ifA16Gray16; ifR8G8B8: DestFmt := ifA8R8G8B8; ifR16G16B16: DestFmt := ifA16R16G16B16; else DestFmt := ifUnknown; end; if DestFmt <> ifUnknown then begin if not IsBackGroundPresent then BackGroundColor := ColorKey; ConvertImage(Image, DestFmt); // Now back color and color key must be converted to image's data format, looks ugly case Image.Format of ifA8Gray8: begin Col32 := Color32(0, 0, $FF, Byte(ColorKey.B)); Bkg32 := Color32(0, 0, 0, Byte(BackGroundColor.B)); end; ifA16Gray16: begin ColorKey.G := $FFFF; end; ifA8R8G8B8: begin Col32 := Color32($FF, Byte(ColorKey.R), Byte(ColorKey.G), Byte(ColorKey.B)); Bkg32 := Color32(0, Byte(BackGroundColor.R), Byte(BackGroundColor.G), Byte(BackGroundColor.B)); end; ifA16R16G16B16: begin ColorKey.A := $FFFF; end; end; if Image.Format in [ifA8Gray8, ifA8R8G8B8] then begin OldPixel := @Col32; NewPixel := @Bkg32; end else begin OldPixel := @ColorKey; NewPixel := @BackGroundColor; end; ReplaceColor(Image, 0, 0, Image.Width, Image.Height, OldPixel, NewPixel); end; end; begin Alphas := nil; IsColorKeyPresent := False; IsBackGroundPresent := False; GetImageFormatInfo(Image.Format, FmtInfo); IsColorFormat := (Frame.IsJpegFrame and (Frame.JHDR.ColorType in [10, 14])) or (not Frame.IsJpegFrame and (Frame.IHDR.ColorType in [2, 6])); // Convert some chunk data to useful format if Frame.TransparencySize > 0 then ConverttRNS; if Frame.BackgroundSize > 0 then ConvertbKGD; // Build palette for indexed images if FmtInfo.IsIndexed then ReconstructPalette; // Apply color keying if IsColorKeyPresent and not FmtInfo.HasAlphaChannel then ApplyColorKey; FreeMemNil(Alphas); end; { TNGFileSaver class implementation } procedure TNGFileSaver.StoreImageToPNGFrame(const IHDR: TIHDR; Bits: Pointer; FmtInfo: TImageFormatInfo; IDATStream: TMemoryStream); var TotalBuffer, CompBuffer, ZeroLine, PrevLine: Pointer; FilterLines: array[0..4] of PByteArray; TotalSize, CompSize, I, BytesPerLine, BytesPerPixel: LongInt; Filter: Byte; Adaptive: Boolean; procedure FilterScanline(Filter: Byte; BytesPerPixel: LongInt; Line, PrevLine, Target: PByteArray); var I: LongInt; begin case Filter of 0: begin // No filter Move(Line^, Target^, BytesPerLine); end; 1: begin // Sub filter Move(Line^, Target^, BytesPerPixel); for I := BytesPerPixel to BytesPerLine - 1 do Target[I] := (Line[I] - Line[I - BytesPerPixel]) and $FF; end; 2: begin // Up filter for I := 0 to BytesPerLine - 1 do Target[I] := (Line[I] - PrevLine[I]) and $FF; end; 3: begin // Average filter for I := 0 to BytesPerPixel - 1 do Target[I] := (Line[I] - PrevLine[I] shr 1) and $FF; for I := BytesPerPixel to BytesPerLine - 1 do Target[I] := (Line[I] - (Line[I - BytesPerPixel] + PrevLine[I]) shr 1) and $FF; end; 4: begin // Paeth filter for I := 0 to BytesPerPixel - 1 do Target[I] := (Line[I] - PaethPredictor(0, PrevLine[I], 0)) and $FF; for I := BytesPerPixel to BytesPerLine - 1 do Target[I] := (Line[I] - PaethPredictor(Line[I - BytesPerPixel], PrevLine[I], PrevLine[I - BytesPerPixel])) and $FF; end; end; end; procedure AdaptiveFilter(var Filter: Byte; BytesPerPixel: LongInt; Line, PrevLine, Target: PByteArray); var I, J, BestTest: LongInt; Sums: array[0..4] of LongInt; begin // Compute the output scanline using all five filters, // and select the filter that gives the smallest sum of // absolute values of outputs FillChar(Sums, SizeOf(Sums), 0); BestTest := MaxInt; for I := 0 to 4 do begin FilterScanline(I, BytesPerPixel, Line, PrevLine, FilterLines[I]); for J := 0 to BytesPerLine - 1 do Sums[I] := Sums[I] + Abs(ShortInt(FilterLines[I][J])); if Sums[I] < BestTest then begin Filter := I; BestTest := Sums[I]; end; end; Move(FilterLines[Filter]^, Target^, BytesPerLine); end; begin // Select precompression filter and compression level Adaptive := False; Filter := 0; case PreFilter of 6: if not ((IHDR.BitDepth < 8) or (IHDR.ColorType = 3)) then Adaptive := True; 0..4: Filter := PreFilter; else if IHDR.ColorType in [2, 6] then Filter := 4 end; // Prepare data for compression CompBuffer := nil; FillChar(FilterLines, SizeOf(FilterLines), 0); BytesPerPixel := Max(1, FmtInfo.BytesPerPixel); BytesPerLine := FmtInfo.GetPixelsSize(FmtInfo.Format, LongInt(IHDR.Width), 1); TotalSize := (BytesPerLine + 1) * LongInt(IHDR.Height); GetMem(TotalBuffer, TotalSize); GetMem(ZeroLine, BytesPerLine); FillChar(ZeroLine^, BytesPerLine, 0); PrevLine := ZeroLine; if Adaptive then begin for I := 0 to 4 do GetMem(FilterLines[I], BytesPerLine); end; try // Process next scanlines for I := 0 to IHDR.Height - 1 do begin // Filter scanline if Adaptive then begin AdaptiveFilter(Filter, BytesPerPixel, @PByteArray(Bits)[I * BytesPerLine], PrevLine, @PByteArray(TotalBuffer)[I * (BytesPerLine + 1) + 1]); end else begin FilterScanline(Filter, BytesPerPixel, @PByteArray(Bits)[I * BytesPerLine], PrevLine, @PByteArray(TotalBuffer)[I * (BytesPerLine + 1) + 1]); end; PrevLine := @PByteArray(Bits)[I * BytesPerLine]; // Swap red and blue if necessary if (IHDR.ColorType in [2, 6]) and not FmtInfo.IsRBSwapped then begin SwapRGB(@PByteArray(TotalBuffer)[I * (BytesPerLine + 1) + 1], IHDR.Width, IHDR.BitDepth, BytesPerPixel); end; // Images with 16 bit channels must be swapped because of PNG's big endianess if IHDR.BitDepth = 16 then begin SwapEndianWord(@PByteArray(TotalBuffer)[I * (BytesPerLine + 1) + 1], BytesPerLine div SizeOf(Word)); end; // Set filter used for this scanline PByteArray(TotalBuffer)[I * (BytesPerLine + 1)] := Filter; end; // Compress IDAT data CompressBuf(TotalBuffer, TotalSize, CompBuffer, CompSize, CompressLevel, ZLibStrategy); // Write IDAT data to stream IDATStream.WriteBuffer(CompBuffer^, CompSize); finally FreeMem(TotalBuffer); FreeMem(CompBuffer); FreeMem(ZeroLine); if Adaptive then for I := 0 to 4 do FreeMem(FilterLines[I]); end; end; {$IFNDEF DONT_LINK_JNG} procedure TNGFileSaver.StoreImageToJNGFrame(const JHDR: TJHDR; const Image: TImageData; IDATStream, JDATStream, JDAAStream: TMemoryStream); var ColorImage, AlphaImage: TImageData; FmtInfo: TImageFormatInfo; AlphaPtr: PByte; GrayPtr: PWordRec; ColorPtr: PColor32Rec; I: LongInt; FakeIHDR: TIHDR; procedure SaveJpegToStream(Stream: TStream; const Image: TImageData); var JpegFormat: TCustomIOJpegFileFormat; Handle: TImagingHandle; DynImages: TDynImageDataArray; begin JpegFormat := TCustomIOJpegFileFormat.Create; JpegFormat.SetCustomIO(StreamIO); // Only JDAT stream can be saved progressive if Stream = JDATStream then JpegFormat.FProgressive := Progressive else JpegFormat.FProgressive := False; JpegFormat.FQuality := Quality; SetLength(DynImages, 1); DynImages[0] := Image; Handle := StreamIO.Open(Pointer(Stream), omCreate); try JpegFormat.SaveData(Handle, DynImages, 0); finally StreamIO.Close(Handle); SetLength(DynImages, 0); JpegFormat.Free; end; end; begin GetImageFormatInfo(Image.Format, FmtInfo); InitImage(ColorImage); InitImage(AlphaImage); if FmtInfo.HasAlphaChannel then begin // Create new image for alpha channel and color image without alpha CloneImage(Image, ColorImage); NewImage(Image.Width, Image.Height, ifGray8, AlphaImage); case Image.Format of ifA8Gray8: ConvertImage(ColorImage, ifGray8); ifA8R8G8B8: ConvertImage(ColorImage, ifR8G8B8); end; // Store source image's alpha to separate image AlphaPtr := AlphaImage.Bits; if Image.Format = ifA8Gray8 then begin GrayPtr := Image.Bits; for I := 0 to Image.Width * Image.Height - 1 do begin AlphaPtr^ := GrayPtr.High; Inc(GrayPtr); Inc(AlphaPtr); end; end else begin ColorPtr := Image.Bits; for I := 0 to Image.Width * Image.Height - 1 do begin AlphaPtr^ := ColorPtr.A; Inc(ColorPtr); Inc(AlphaPtr); end; end; // Write color image to stream as JPEG SaveJpegToStream(JDATStream, ColorImage); if LossyAlpha then begin // Write alpha image to stream as JPEG SaveJpegToStream(JDAAStream, AlphaImage); end else begin // Alpha channel is PNG compressed FakeIHDR.Width := JHDR.Width; FakeIHDR.Height := JHDR.Height; FakeIHDR.ColorType := 0; FakeIHDR.BitDepth := JHDR.AlphaSampleDepth; FakeIHDR.Filter := JHDR.AlphaFilter; FakeIHDR.Interlacing := JHDR.AlphaInterlacing; GetImageFormatInfo(AlphaImage.Format, FmtInfo); StoreImageToPNGFrame(FakeIHDR, AlphaImage.Bits, FmtInfo, IDATStream); end; FreeImage(ColorImage); FreeImage(AlphaImage); end else begin // Simply write JPEG to stream SaveJpegToStream(JDATStream, Image); end; end; {$ENDIF} procedure TNGFileSaver.AddFrame(const Image: TImageData; IsJpegFrame: Boolean); var Frame: TFrameInfo; FmtInfo: TImageFormatInfo; Index: Integer; procedure StorePalette; var Pal: PPalette24; Alphas: PByteArray; I, PalBytes: LongInt; AlphasDiffer: Boolean; begin // Fill and save RGB part of palette to PLTE chunk PalBytes := FmtInfo.PaletteEntries * SizeOf(TColor24Rec); GetMem(Pal, PalBytes); AlphasDiffer := False; for I := 0 to FmtInfo.PaletteEntries - 1 do begin Pal[I].B := Image.Palette[I].R; Pal[I].G := Image.Palette[I].G; Pal[I].R := Image.Palette[I].B; if Image.Palette[I].A < 255 then AlphasDiffer := True; end; Frame.Palette := Pal; Frame.PaletteEntries := FmtInfo.PaletteEntries; // Fill and save alpha part (if there are any alphas < 255) of palette to tRNS chunk if AlphasDiffer then begin PalBytes := FmtInfo.PaletteEntries * SizeOf(Byte); GetMem(Alphas, PalBytes); for I := 0 to FmtInfo.PaletteEntries - 1 do Alphas[I] := Image.Palette[I].A; Frame.Transparency := Alphas; Frame.TransparencySize := PalBytes; end; end; procedure FillFrameControlChunk(const IHDR: TIHDR; var fcTL: TfcTL); var Delay: Integer; begin fcTL.SeqNumber := 0; // Decided when writing to file fcTL.Width := IHDR.Width; fcTL.Height := IHDR.Height; fcTL.XOffset := 0; fcTL.YOffset := 0; fcTL.DelayNumer := 1; fcTL.DelayDenom := 3; if FileFormat.FMetadata.HasMetaItemForSaving(SMetaFrameDelay, Index) then begin // Metadata contains frame delay information in milliseconds Delay := FileFormat.FMetadata.MetaItemsForSavingMulti[SMetaFrameDelay, Index]; fcTL.DelayNumer := Delay; fcTL.DelayDenom := 1000; end; fcTL.DisposeOp := DisposeOpNone; fcTL.BlendOp := BlendOpSource; SwapEndianLongWord(@fcTL, 5); fcTL.DelayNumer := SwapEndianWord(fcTL.DelayNumer); fcTL.DelayDenom := SwapEndianWord(fcTL.DelayDenom); end; begin // Add new frame Frame := AddFrameInfo; Frame.IsJpegFrame := IsJpegFrame; Index := Length(Frames) - 1; with Frame do begin GetImageFormatInfo(Image.Format, FmtInfo); if IsJpegFrame then begin {$IFNDEF DONT_LINK_JNG} // Fill JNG header JHDR.Width := Image.Width; JHDR.Height := Image.Height; case Image.Format of ifGray8: JHDR.ColorType := 8; ifR8G8B8: JHDR.ColorType := 10; ifA8Gray8: JHDR.ColorType := 12; ifA8R8G8B8: JHDR.ColorType := 14; end; JHDR.SampleDepth := 8; // 8-bit samples and quantization tables JHDR.Compression := 8; // Huffman coding JHDR.Interlacing := Iff(Progressive, 8, 0); JHDR.AlphaSampleDepth := Iff(FmtInfo.HasAlphaChannel, 8, 0); JHDR.AlphaCompression := Iff(LossyAlpha, 8, 0); JHDR.AlphaFilter := 0; JHDR.AlphaInterlacing := 0; StoreImageToJNGFrame(JHDR, Image, IDATMemory, JDATMemory, JDAAMemory); // Finally swap endian SwapEndianLongWord(@JHDR, 2); {$ENDIF} end else begin // Fill PNG header IHDR.Width := Image.Width; IHDR.Height := Image.Height; IHDR.Compression := 0; IHDR.Filter := 0; IHDR.Interlacing := 0; IHDR.BitDepth := FmtInfo.BytesPerPixel * 8; // Select appropiate PNG color type and modify bitdepth if FmtInfo.HasGrayChannel then begin IHDR.ColorType := 0; if FmtInfo.HasAlphaChannel then begin IHDR.ColorType := 4; IHDR.BitDepth := IHDR.BitDepth div 2; end; end else if FmtInfo.Format = ifBinary then begin IHDR.ColorType := 0; IHDR.BitDepth := 1; end else if FmtInfo.IsIndexed then IHDR.ColorType := 3 else if FmtInfo.HasAlphaChannel then begin IHDR.ColorType := 6; IHDR.BitDepth := IHDR.BitDepth div 4; end else begin IHDR.ColorType := 2; IHDR.BitDepth := IHDR.BitDepth div 3; end; if FileType = ngAPNG then begin // Fill fcTL chunk of APNG file FillFrameControlChunk(IHDR, fcTL); end; // Compress PNG image and store it to stream StoreImageToPNGFrame(IHDR, Image.Bits, FmtInfo, IDATMemory); // Store palette if necesary if FmtInfo.IsIndexed then StorePalette; // Finally swap endian SwapEndianLongWord(@IHDR, 2); end; end; end; function TNGFileSaver.SaveFile(Handle: TImagingHandle): Boolean; var I: LongInt; Chunk: TChunkHeader; SeqNo: LongWord; function GetNextSeqNo: LongWord; begin // Seq numbers of fcTL and fdAT are "interleaved" as they share the counter. // Example: first fcTL for IDAT has seq=0, next is fcTL for seond frame with // seq=1, then first fdAT with seq=2, fcTL seq=3, fdAT=4, ... Result := SwapEndianLongWord(SeqNo); Inc(SeqNo); end; function CalcChunkCrc(const ChunkHdr: TChunkHeader; Data: Pointer; Size: LongInt): LongWord; begin Result := $FFFFFFFF; CalcCrc32(Result, @ChunkHdr.ChunkID, SizeOf(ChunkHdr.ChunkID)); CalcCrc32(Result, Data, Size); Result := SwapEndianLongWord(Result xor $FFFFFFFF); end; procedure WriteChunk(var Chunk: TChunkHeader; ChunkData: Pointer); var ChunkCrc: LongWord; SizeToWrite: LongInt; begin SizeToWrite := Chunk.DataSize; Chunk.DataSize := SwapEndianLongWord(Chunk.DataSize); ChunkCrc := CalcChunkCrc(Chunk, ChunkData, SizeToWrite); GetIO.Write(Handle, @Chunk, SizeOf(Chunk)); if SizeToWrite <> 0 then GetIO.Write(Handle, ChunkData, SizeToWrite); GetIO.Write(Handle, @ChunkCrc, SizeOf(ChunkCrc)); end; procedure WritefdAT(Frame: TFrameInfo); var ChunkCrc: LongWord; ChunkSeqNo: LongWord; begin Chunk.ChunkID := fdATChunk; ChunkSeqNo := GetNextSeqNo; // fdAT saves seq number LongWord before compressed pixels Chunk.DataSize := Frame.IDATMemory.Size + SizeOf(LongWord); Chunk.DataSize := SwapEndianLongWord(Chunk.DataSize); // Calc CRC ChunkCrc := $FFFFFFFF; CalcCrc32(ChunkCrc, @Chunk.ChunkID, SizeOf(Chunk.ChunkID)); CalcCrc32(ChunkCrc, @ChunkSeqNo, SizeOf(ChunkSeqNo)); CalcCrc32(ChunkCrc, Frame.IDATMemory.Memory, Frame.IDATMemory.Size); ChunkCrc := SwapEndianLongWord(ChunkCrc xor $FFFFFFFF); // Write out all fdAT data GetIO.Write(Handle, @Chunk, SizeOf(Chunk)); GetIO.Write(Handle, @ChunkSeqNo, SizeOf(ChunkSeqNo)); GetIO.Write(Handle, Frame.IDATMemory.Memory, Frame.IDATMemory.Size); GetIO.Write(Handle, @ChunkCrc, SizeOf(ChunkCrc)); end; procedure WriteGlobalMetaDataChunks(Frame: TFrameInfo); var XRes, YRes: Single; begin if FileFormat.FMetadata.GetPhysicalPixelSize(ruDpm, XRes, YRes, True) then begin // Save pHYs chunk Frame.pHYs.UnitSpecifier := 1; // PNG stores physical resolution as dots per meter Frame.pHYs.PixelsPerUnitX := Round(XRes); Frame.pHYs.PixelsPerUnitY := Round(YRes); Chunk.DataSize := SizeOf(Frame.pHYs); Chunk.ChunkID := pHYsChunk; SwapEndianLongWord(@Frame.pHYs, SizeOf(Frame.pHYs) div SizeOf(LongWord)); WriteChunk(Chunk, @Frame.pHYs); end; end; procedure WritePNGMainImageChunks(Frame: TFrameInfo); begin with Frame do begin // Write IHDR chunk Chunk.DataSize := SizeOf(IHDR); Chunk.ChunkID := IHDRChunk; WriteChunk(Chunk, @IHDR); // Write PLTE chunk if data is present if Palette <> nil then begin Chunk.DataSize := PaletteEntries * SizeOf(TColor24Rec); Chunk.ChunkID := PLTEChunk; WriteChunk(Chunk, Palette); end; // Write tRNS chunk if data is present if Transparency <> nil then begin Chunk.DataSize := TransparencySize; Chunk.ChunkID := tRNSChunk; WriteChunk(Chunk, Transparency); end; end; // Write metadata related chunks WriteGlobalMetaDataChunks(Frame); end; begin Result := False; SeqNo := 0; case FileType of ngPNG, ngAPNG: GetIO.Write(Handle, @PNGSignature, SizeOf(TChar8)); ngMNG: GetIO.Write(Handle, @MNGSignature, SizeOf(TChar8)); ngJNG: GetIO.Write(Handle, @JNGSignature, SizeOf(TChar8)); end; if FileType = ngMNG then begin // MNG - main header before frames SwapEndianLongWord(@MHDR, SizeOf(MHDR) div SizeOf(LongWord)); Chunk.DataSize := SizeOf(MHDR); Chunk.ChunkID := MHDRChunk; WriteChunk(Chunk, @MHDR); end else if FileType = ngAPNG then begin // APNG - IHDR and global chunks for all frames, then acTL chunk, then frames // (fcTL+IDAT, fcTL+fdAT, fcTL+fdAT, fcTL+fdAT, ....) WritePNGMainImageChunks(Frames[0]); // Animation control chunk acTL.NumFrames := Length(Frames); if FileFormat.FMetadata.HasMetaItemForSaving(SMetaAnimationLoops) then begin // Number of plays of APNG animation acTL.NumPlay:= FileFormat.FMetadata.MetaItemsForSaving[SMetaAnimationLoops]; end else acTL.NumPlay := 0; SwapEndianLongWord(@acTL, SizeOf(acTL) div SizeOf(LongWord)); Chunk.DataSize := SizeOf(acTL); Chunk.ChunkID := acTLChunk; WriteChunk(Chunk, @acTL); end; for I := 0 to Length(Frames) - 1 do with Frames[I] do begin if IsJpegFrame then begin // Write JHDR chunk Chunk.DataSize := SizeOf(JHDR); Chunk.ChunkID := JHDRChunk; WriteChunk(Chunk, @JHDR); // Write metadata related chunks WriteGlobalMetaDataChunks(Frames[I]); // Write JNG image data Chunk.DataSize := JDATMemory.Size; Chunk.ChunkID := JDATChunk; WriteChunk(Chunk, JDATMemory.Memory); // Write alpha channel if present if JHDR.AlphaSampleDepth > 0 then begin if JHDR.AlphaCompression = 0 then begin // Alpha is PNG compressed Chunk.DataSize := IDATMemory.Size; Chunk.ChunkID := IDATChunk; WriteChunk(Chunk, IDATMemory.Memory); end else begin // Alpha is JNG compressed Chunk.DataSize := JDAAMemory.Size; Chunk.ChunkID := JDAAChunk; WriteChunk(Chunk, JDAAMemory.Memory); end; end; // Write image end Chunk.DataSize := 0; Chunk.ChunkID := IENDChunk; WriteChunk(Chunk, nil); end else if FileType <> ngAPNG then begin // Regular PNG frame (single PNG image or MNG frame) WritePNGMainImageChunks(Frames[I]); // Write PNG image data Chunk.DataSize := IDATMemory.Size; Chunk.ChunkID := IDATChunk; WriteChunk(Chunk, IDATMemory.Memory); // Write image end Chunk.DataSize := 0; Chunk.ChunkID := IENDChunk; WriteChunk(Chunk, nil); end else if FileType = ngAPNG then begin // APNG frame - Write fcTL before frame data Chunk.DataSize := SizeOf(fcTL); Chunk.ChunkID := fcTLChunk; fcTl.SeqNumber := GetNextSeqNo; WriteChunk(Chunk, @fcTL); // Write data - IDAT for first frame and fdAT for following ones if I = 0 then begin Chunk.DataSize := IDATMemory.Size; Chunk.ChunkID := IDATChunk; WriteChunk(Chunk, IDATMemory.Memory); end else WritefdAT(Frames[I]); // Write image end after last frame if I = Length(Frames) - 1 then begin Chunk.DataSize := 0; Chunk.ChunkID := IENDChunk; WriteChunk(Chunk, nil); end; end; end; if FileType = ngMNG then begin Chunk.DataSize := 0; Chunk.ChunkID := MENDChunk; WriteChunk(Chunk, nil); end; end; procedure TNGFileSaver.SetFileOptions; begin PreFilter := FileFormat.FPreFilter; CompressLevel := FileFormat.FCompressLevel; LossyAlpha := FileFormat.FLossyAlpha; Quality := FileFormat.FQuality; Progressive := FileFormat.FProgressive; ZLibStrategy := FileFormat.FZLibStategy; end; { TAPNGAnimator class implementation } class procedure TAPNGAnimator.Animate(var Images: TDynImageDataArray; const acTL: TacTL; const SrcFrames: array of TFrameInfo); var I, SrcIdx, Offset, Len: Integer; DestFrames: TDynImageDataArray; SrcCanvas, DestCanvas: TImagingCanvas; PreviousCache: TImageData; function AnimatingNeeded: Boolean; var I: Integer; begin Result := False; for I := 0 to Len - 1 do with SrcFrames[I] do begin if (FrameWidth <> Integer(IHDR.Width)) or (FrameHeight <> Integer(IHDR.Height)) or (Len <> Integer(acTL.NumFrames)) or (not ((fcTL.DisposeOp = DisposeOpNone) and (fcTL.BlendOp = BlendOpSource)) and not ((fcTL.DisposeOp = DisposeOpBackground) and (fcTL.BlendOp = BlendOpSource)) and not ((fcTL.DisposeOp = DisposeOpBackground) and (fcTL.BlendOp = BlendOpOver))) then begin Result := True; Exit; end; end; end; begin Len := Length(SrcFrames); if (Len = 0) or not AnimatingNeeded then Exit; if (Len = Integer(acTL.NumFrames) + 1) and (SrcFrames[0].fcTL.Width = 0) then begin // If default image (stored in IDAT chunk) isn't part of animation we ignore it Offset := 1; Len := Len - 1; end else Offset := 0; SetLength(DestFrames, Len); DestCanvas := ImagingCanvases.FindBestCanvasForImage(Images[0]).Create; SrcCanvas := ImagingCanvases.FindBestCanvasForImage(Images[0]).Create; InitImage(PreviousCache); NewImage(SrcFrames[0].IHDR.Width, SrcFrames[0].IHDR.Height, Images[0].Format, PreviousCache); for I := 0 to Len - 1 do begin SrcIdx := I + Offset; NewImage(SrcFrames[SrcIdx].IHDR.Width, SrcFrames[SrcIdx].IHDR.Height, Images[SrcIdx].Format, DestFrames[I]); if DestFrames[I].Format = ifIndex8 then Move(Images[SrcIdx].Palette^, DestFrames[I].Palette^, 256 * SizeOf(TColor32)); DestCanvas.CreateForData(@DestFrames[I]); if (SrcFrames[SrcIdx].fcTL.DisposeOp = DisposeOpPrevious) and (SrcFrames[SrcIdx - 1].fcTL.DisposeOp <> DisposeOpPrevious) then begin // Cache current output buffer so we may return to it later (previous dispose op) CopyRect(DestFrames[I - 1], 0, 0, DestFrames[I - 1].Width, DestFrames[I - 1].Height, PreviousCache, 0, 0); end; if (I = 0) or (SrcIdx = 0) then begin // Clear whole frame with transparent black color (default for first frame) DestCanvas.FillColor32 := pcClear; DestCanvas.Clear; end else if SrcFrames[SrcIdx - 1].fcTL.DisposeOp = DisposeOpBackground then begin // Restore background color (clear) on previous frame's area and leave previous content outside of it CopyRect(DestFrames[I - 1], 0, 0, DestFrames[I - 1].Width, DestFrames[I - 1].Height, DestFrames[I], 0, 0); DestCanvas.FillColor32 := pcClear; DestCanvas.FillRect(BoundsToRect(SrcFrames[SrcIdx - 1].fcTL.XOffset, SrcFrames[SrcIdx - 1].fcTL.YOffset, SrcFrames[SrcIdx - 1].FrameWidth, SrcFrames[SrcIdx - 1].FrameHeight)); end else if SrcFrames[SrcIdx - 1].fcTL.DisposeOp = DisposeOpNone then begin // Clone previous frame - no change to output buffer CopyRect(DestFrames[I - 1], 0, 0, DestFrames[I - 1].Width, DestFrames[I - 1].Height, DestFrames[I], 0, 0); end else if SrcFrames[SrcIdx - 1].fcTL.DisposeOp = DisposeOpPrevious then begin // Revert to previous frame (cached, can't just restore DestFrames[I - 2]) CopyRect(PreviousCache, 0, 0, PreviousCache.Width, PreviousCache.Height, DestFrames[I], 0, 0); end; // Copy pixels or alpha blend them over if SrcFrames[SrcIdx].fcTL.BlendOp = BlendOpSource then begin CopyRect(Images[SrcIdx], 0, 0, Images[SrcIdx].Width, Images[SrcIdx].Height, DestFrames[I], SrcFrames[SrcIdx].fcTL.XOffset, SrcFrames[SrcIdx].fcTL.YOffset); end else if SrcFrames[SrcIdx].fcTL.BlendOp = BlendOpOver then begin SrcCanvas.CreateForData(@Images[SrcIdx]); SrcCanvas.DrawAlpha(SrcCanvas.ClipRect, DestCanvas, SrcFrames[SrcIdx].fcTL.XOffset, SrcFrames[SrcIdx].fcTL.YOffset); end; FreeImage(Images[SrcIdx]); end; DestCanvas.Free; SrcCanvas.Free; FreeImage(PreviousCache); // Assign dest frames to final output images Images := DestFrames; end; { TNetworkGraphicsFileFormat class implementation } procedure TNetworkGraphicsFileFormat.Define; begin inherited; FFeatures := [ffLoad, ffSave]; FPreFilter := NGDefaultPreFilter; FCompressLevel := NGDefaultCompressLevel; FLossyAlpha := NGDefaultLossyAlpha; FLossyCompression := NGDefaultLossyCompression; FQuality := NGDefaultQuality; FProgressive := NGDefaultProgressive; FZLibStategy := NGDefaultZLibStartegy; end; procedure TNetworkGraphicsFileFormat.CheckOptionsValidity; begin // Just check if save options has valid values if not (FPreFilter in [0..6]) then FPreFilter := NGDefaultPreFilter; if not (FCompressLevel in [0..9]) then FCompressLevel := NGDefaultCompressLevel; if not (FQuality in [1..100]) then FQuality := NGDefaultQuality; end; function TNetworkGraphicsFileFormat.GetSupportedFormats: TImageFormats; begin if FLossyCompression then Result := NGLossyFormats else Result := NGLosslessFormats; end; procedure TNetworkGraphicsFileFormat.ConvertToSupported(var Image: TImageData; const Info: TImageFormatInfo); var ConvFormat: TImageFormat; begin if not FLossyCompression then begin // Convert formats for lossless compression if Info.HasGrayChannel then begin if Info.HasAlphaChannel then begin if Info.BytesPerPixel <= 2 then // Convert <= 16bit grayscale images with alpha to ifA8Gray8 ConvFormat := ifA8Gray8 else // Convert > 16bit grayscale images with alpha to ifA16Gray16 ConvFormat := ifA16Gray16 end else // Convert grayscale images without alpha to ifGray16 ConvFormat := ifGray16; end else if Info.IsFloatingPoint then // Convert floating point images to 64 bit ARGB (or RGB if no alpha) ConvFormat := IffFormat(Info.HasAlphaChannel, ifA16B16G16R16, ifB16G16R16) else if Info.HasAlphaChannel or Info.IsSpecial then // Convert all other images with alpha or special images to A8R8G8B8 ConvFormat := ifA8R8G8B8 else // Convert images without alpha to R8G8B8 ConvFormat := ifR8G8B8; end else begin // Convert formats for lossy compression if Info.HasGrayChannel then ConvFormat := IffFormat(Info.HasAlphaChannel, ifA8Gray8, ifGray8) else ConvFormat := IffFormat(Info.HasAlphaChannel, ifA8R8G8B8, ifR8G8B8); end; ConvertImage(Image, ConvFormat); end; function TNetworkGraphicsFileFormat.TestFormat(Handle: TImagingHandle): Boolean; var ReadCount: LongInt; Sig: TChar8; begin Result := False; if Handle <> nil then with GetIO do begin FillChar(Sig, SizeOf(Sig), 0); ReadCount := Read(Handle, @Sig, SizeOf(Sig)); Seek(Handle, -ReadCount, smFromCurrent); Result := (ReadCount = SizeOf(Sig)) and (Sig = FSignature); end; end; { TPNGFileFormat class implementation } procedure TPNGFileFormat.Define; begin inherited; FName := SPNGFormatName; FFeatures := FFeatures + [ffMultiImage]; FLoadAnimated := PNGDefaultLoadAnimated; AddMasks(SPNGMasks); FSignature := PNGSignature; RegisterOption(ImagingPNGPreFilter, @FPreFilter); RegisterOption(ImagingPNGCompressLevel, @FCompressLevel); RegisterOption(ImagingPNGLoadAnimated, @FLoadAnimated); RegisterOption(ImagingPNGZLibStrategy, @FZLibStategy); end; function TPNGFileFormat.LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; var I, Len: LongInt; NGFileLoader: TNGFileLoader; begin Result := False; NGFileLoader := TNGFileLoader.Create(Self); try // Use NG file parser to load file if NGFileLoader.LoadFile(Handle) and (Length(NGFileLoader.Frames) > 0) then begin Len := Length(NGFileLoader.Frames); SetLength(Images, Len); for I := 0 to Len - 1 do with NGFileLoader.Frames[I] do begin // Build actual image bits if not IsJpegFrame then NGFileLoader.LoadImageFromPNGFrame(FrameWidth, FrameHeight, IHDR, IDATMemory, Images[I]); // Build palette, aply color key or background NGFileLoader.ApplyFrameSettings(NGFileLoader.Frames[I], Images[I]); Result := True; end; // Animate APNG images if (NGFileLoader.FileType = ngAPNG) and FLoadAnimated then TAPNGAnimator.Animate(Images, NGFileLoader.acTL, NGFileLoader.Frames); end; finally NGFileLoader.LoadMetaData; // Store metadata NGFileLoader.Free; end; end; function TPNGFileFormat.SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray; Index: LongInt): Boolean; var I: Integer; ImageToSave: TImageData; MustBeFreed: Boolean; NGFileSaver: TNGFileSaver; DefaultFormat: TImageFormat; Screen: TImageData; AnimWidth, AnimHeight: Integer; begin Result := False; DefaultFormat := ifDefault; AnimWidth := 0; AnimHeight := 0; NGFileSaver := TNGFileSaver.Create(Self); // Save images with more frames as APNG format if Length(Images) > 1 then begin NGFileSaver.FileType := ngAPNG; // Get max dimensions of frames AnimWidth := Images[FFirstIdx].Width; AnimHeight := Images[FFirstIdx].Height; for I := FFirstIdx + 1 to FLastIdx do begin AnimWidth := Max(AnimWidth, Images[I].Width); AnimHeight := Max(AnimHeight, Images[I].Height); end; end else NGFileSaver.FileType := ngPNG; NGFileSaver.SetFileOptions; with NGFileSaver do try // Store all frames to be saved frames file saver for I := FFirstIdx to FLastIdx do begin if MakeCompatible(Images[I], ImageToSave, MustBeFreed) then try if FileType = ngAPNG then begin // IHDR chunk is shared for all frames so all frames must have the // same data format as the first image. if I = FFirstIdx then begin DefaultFormat := ImageToSave.Format; // Subsequenet frames may be bigger than the first one. // APNG doens't support this - max allowed size is what's written in // IHDR - size of main/default/first image. If some frame is // bigger than the first one we need to resize (create empty bigger // image and copy) the first frame so all following frames could fit to // its area. if (ImageToSave.Width <> AnimWidth) or (ImageToSave.Height <> AnimHeight) then begin InitImage(Screen); NewImage(AnimWidth, AnimHeight, ImageToSave.Format, Screen); CopyRect(ImageToSave, 0, 0, ImageToSave.Width, ImageToSave.Height, Screen, 0, 0); if MustBeFreed then FreeImage(ImageToSave); ImageToSave := Screen; end; end else if ImageToSave.Format <> DefaultFormat then begin if MustBeFreed then ConvertImage(ImageToSave, DefaultFormat) else begin CloneImage(Images[I], ImageToSave); ConvertImage(ImageToSave, DefaultFormat); MustBeFreed := True; end; end; end; // Add image as PNG frame AddFrame(ImageToSave, False); finally if MustBeFreed then FreeImage(ImageToSave); end else Exit; end; // Finally save PNG file SaveFile(Handle); Result := True; finally NGFileSaver.Free; end; end; {$IFNDEF DONT_LINK_MNG} { TMNGFileFormat class implementation } procedure TMNGFileFormat.Define; begin inherited; FName := SMNGFormatName; FFeatures := FFeatures + [ffMultiImage]; AddMasks(SMNGMasks); FSignature := MNGSignature; RegisterOption(ImagingMNGLossyCompression, @FLossyCompression); RegisterOption(ImagingMNGLossyAlpha, @FLossyAlpha); RegisterOption(ImagingMNGPreFilter, @FPreFilter); RegisterOption(ImagingMNGCompressLevel, @FCompressLevel); RegisterOption(ImagingMNGQuality, @FQuality); RegisterOption(ImagingMNGProgressive, @FProgressive); end; function TMNGFileFormat.LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; var NGFileLoader: TNGFileLoader; I, Len: LongInt; begin Result := False; NGFileLoader := TNGFileLoader.Create(Self); try // Use NG file parser to load file if NGFileLoader.LoadFile(Handle) then begin Len := Length(NGFileLoader.Frames); if Len > 0 then begin SetLength(Images, Len); for I := 0 to Len - 1 do with NGFileLoader.Frames[I] do begin // Build actual image bits if IsJpegFrame then NGFileLoader.LoadImageFromJNGFrame(FrameWidth, FrameHeight, JHDR, IDATMemory, JDATMemory, JDAAMemory, Images[I]) else NGFileLoader.LoadImageFromPNGFrame(FrameWidth, FrameHeight, IHDR, IDATMemory, Images[I]); // Build palette, aply color key or background NGFileLoader.ApplyFrameSettings(NGFileLoader.Frames[I], Images[I]); end; end else begin // Some MNG files (with BASI-IEND streams) dont have actual pixel data SetLength(Images, 1); NewImage(NGFileLoader.MHDR.FrameWidth, NGFileLoader.MHDR.FrameWidth, ifDefault, Images[0]); end; Result := True; end; finally NGFileLoader.LoadMetaData; // Store metadata NGFileLoader.Free; end; end; function TMNGFileFormat.SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray; Index: LongInt): Boolean; var NGFileSaver: TNGFileSaver; I, LargestWidth, LargestHeight: LongInt; ImageToSave: TImageData; MustBeFreed: Boolean; begin Result := False; LargestWidth := 0; LargestHeight := 0; NGFileSaver := TNGFileSaver.Create(Self); NGFileSaver.FileType := ngMNG; NGFileSaver.SetFileOptions; with NGFileSaver do try // Store all frames to be saved frames file saver for I := FFirstIdx to FLastIdx do begin if MakeCompatible(Images[I], ImageToSave, MustBeFreed) then try // Add image as PNG or JNG frame AddFrame(ImageToSave, FLossyCompression); // Remember largest frame width and height LargestWidth := Iff(LargestWidth < ImageToSave.Width, ImageToSave.Width, LargestWidth); LargestHeight := Iff(LargestHeight < ImageToSave.Height, ImageToSave.Height, LargestHeight); finally if MustBeFreed then FreeImage(ImageToSave); end else Exit; end; // Fill MNG header MHDR.FrameWidth := LargestWidth; MHDR.FrameHeight := LargestHeight; MHDR.TicksPerSecond := 0; MHDR.NominalLayerCount := 0; MHDR.NominalFrameCount := Length(Frames); MHDR.NominalPlayTime := 0; MHDR.SimplicityProfile := 473; // 111011001 binary, defines MNG-VLC with transparency and JNG support // Finally save MNG file SaveFile(Handle); Result := True; finally NGFileSaver.Free; end; end; {$ENDIF} {$IFNDEF DONT_LINK_JNG} { TJNGFileFormat class implementation } procedure TJNGFileFormat.Define; begin inherited; FName := SJNGFormatName; AddMasks(SJNGMasks); FSignature := JNGSignature; FLossyCompression := True; RegisterOption(ImagingJNGLossyAlpha, @FLossyAlpha); RegisterOption(ImagingJNGAlphaPreFilter, @FPreFilter); RegisterOption(ImagingJNGAlphaCompressLevel, @FCompressLevel); RegisterOption(ImagingJNGQuality, @FQuality); RegisterOption(ImagingJNGProgressive, @FProgressive); end; function TJNGFileFormat.LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; var NGFileLoader: TNGFileLoader; begin Result := False; NGFileLoader := TNGFileLoader.Create(Self); try // Use NG file parser to load file if NGFileLoader.LoadFile(Handle) and (Length(NGFileLoader.Frames) > 0) then with NGFileLoader.Frames[0] do begin SetLength(Images, 1); // Build actual image bits if IsJpegFrame then NGFileLoader.LoadImageFromJNGFrame(FrameWidth, FrameHeight, JHDR, IDATMemory, JDATMemory, JDAAMemory, Images[0]); // Build palette, aply color key or background NGFileLoader.ApplyFrameSettings(NGFileLoader.Frames[0], Images[0]); Result := True; end; finally NGFileLoader.LoadMetaData; // Store metadata NGFileLoader.Free; end; end; function TJNGFileFormat.SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray; Index: LongInt): Boolean; var NGFileSaver: TNGFileSaver; ImageToSave: TImageData; MustBeFreed: Boolean; begin // Make image JNG compatible, store it in saver, and save it to file Result := MakeCompatible(Images[Index], ImageToSave, MustBeFreed); if Result then begin NGFileSaver := TNGFileSaver.Create(Self); with NGFileSaver do try FileType := ngJNG; SetFileOptions; AddFrame(ImageToSave, True); SaveFile(Handle); finally // Free NG saver and compatible image NGFileSaver.Free; if MustBeFreed then FreeImage(ImageToSave); end; end; end; {$ENDIF} initialization RegisterImageFileFormat(TPNGFileFormat); {$IFNDEF DONT_LINK_MNG} RegisterImageFileFormat(TMNGFileFormat); {$ENDIF} {$IFNDEF DONT_LINK_JNG} RegisterImageFileFormat(TJNGFileFormat); {$ENDIF} finalization { File Notes: -- TODOS ---------------------------------------------------- - nothing now -- 0.77 Changes/Bug Fixes ----------------------------------- - Reads and writes APNG animation loop count metadata. - Writes frame delays of APNG from metadata. - Fixed color keys in 8bit depth PNG/MNG loading. - Fixed needless (and sometimes buggy) conversion to format with alpha channel in FPC (GetMem(0) <> nil!). - Added support for optional ZLib compression strategy. - Added loading and saving of ifBinary (1bit black and white) format images. During loading grayscale 1bpp and indexed 1bpp (with only black and white colors in palette) are treated as ifBinary. ifBinary are saved as 1bpp grayscale PNGs. -- 0.26.5 Changes/Bug Fixes --------------------------------- - Reads frame delays from APNG files into metadata. - Added loading and saving of metadata from these chunks: pHYs. - Simplified decoding of 1/2/4 bit images a bit (less code). -- 0.26.3 Changes/Bug Fixes --------------------------------- - Added APNG saving support. - Added APNG support to NG loader and animating to PNG loader. -- 0.26.1 Changes/Bug Fixes --------------------------------- - Changed file format conditional compilation to reflect changes in LINK symbols. -- 0.24.3 Changes/Bug Fixes --------------------------------- - Changes for better thread safety. -- 0.23 Changes/Bug Fixes ----------------------------------- - Added loading of global palettes and transparencies in MNG files (and by doing so fixed crash when loading images with global PLTE or tRNS). -- 0.21 Changes/Bug Fixes ----------------------------------- - Small changes in converting to supported formats. - MakeCompatible method moved to base class, put ConvertToSupported here. GetSupportedFormats removed, it is now set in constructor. - Made public properties for options registered to SetOption/GetOption functions. - Changed extensions to filename masks. - Changed SaveData, LoadData, and MakeCompatible methods according to changes in base class in Imaging unit. -- 0.17 Changes/Bug Fixes ----------------------------------- - MNG and JNG support added, PNG support redesigned to support NG file handlers - added classes for working with NG file formats - stuff from old ImagingPng unit added and that unit was deleted - unit created and initial stuff added -- 0.15 Changes/Bug Fixes ----------------------------------- - when saving indexed images save alpha to tRNS? - added some defines and ifdefs to dzlib unit to allow choosing impaszlib, fpc's paszlib, zlibex or other zlib implementation - added colorkeying support - fixed 16bit channel image handling - pixels were not swapped - fixed arithmetic overflow (in paeth filter) in FPC - data of unknown chunks are skipped and not needlesly loaded -- 0.13 Changes/Bug Fixes ----------------------------------- - adaptive filtering added to PNG saving - TPNGFileFormat class added } end. ================================================ FILE: lib/Imaging/ImagingOptions.inc ================================================ { User Options Following defines and options can be changed by user. } { Source options } {$DEFINE USE_INLINE} // Use function inlining for some functions // works in Free Pascal and Delphi 9+. {$DEFINE USE_ASM} // Ff defined, assembler versions of some // functions will be used (only for x86). // Debug options: If none of these two are defined // your project settings are used. { $DEFINE IMAGING_DEBUG} // If defined, debug info, range/IO/overflow // checking, stack frames, assertions, and // other debugging options will be turned on. { $DEFINE IMAGING_RELEASE} // If defined, all debug info is off. (* File format support linking options. Define formats which you don't want to be registred automatically. Default: all formats are registered = no symbols defined. Example: If you want to disable JPEG support just uncomment //{$DEFINE DONT_LINK_JPEG} line *) {$DEFINE DONT_LINK_JPEG} // link support for Jpeg images //{$DEFINE DONT_LINK_PNG} // link support for PNG images //{$DEFINE DONT_LINK_TARGA} // link support for Targa images //{$DEFINE DONT_LINK_BITMAP} // link support for Windows Bitmap images //{$DEFINE DONT_LINK_DDS} // link support for DDS images {$DEFINE DONT_LINK_GIF} // link support for GIF images {$DEFINE DONT_LINK_MNG} // link support for MNG images {$DEFINE DONT_LINK_JNG} // link support for JNG images {$DEFINE DONT_LINK_PNM} // link support for PortableMap images (PBM, PGM, PPM, PAM, PFM) {$DEFINE DONT_LINK_RADHDR} // link support for Radiance HDR/RGBE file format {$DEFINE DONT_LINK_EXTRAS} // link support for file formats defined in // Extras package. Exactly which formats will be // registered depends on settings in // ImagingExtras.pas unit. { Component set used in ImagignComponents.pas unit. You usually don't need to be concerned with this - proper component library is selected automatically according to your compiler. } {$DEFINE COMPONENT_SET_VCL} // use Delphi VCL { $DEFINE COMPONENT_SET_LCL} // use Lazarus LCL (set automatically when compiling with FPC) { Auto Options Following options and defines are set automatically and some are required for Imaging to compile successfully. Do not change anything here if you don't know what you are doing. } { Compiler options } {$ALIGN ON} // Field alignment: 8 Bytes (in D6+) {$BOOLEVAL OFF} // Boolean eval: off {$EXTENDEDSYNTAX ON} // Extended syntax: on {$LONGSTRINGS ON} // string = AnsiString: on {$MINENUMSIZE 4} // Min enum size: 4 B {$TYPEDADDRESS OFF} // Typed pointers: off {$WRITEABLECONST OFF} // Writeable constants: off {$IFNDEF FPC} {$DEFINE DCC} // if not using FPC then DCC compiler is used (Delphi/BCB) // others are not supported {$ENDIF} {$IFDEF DCC} {$DEFINE DELPHI} {$ENDIF} {$IF (Defined(DCC) and (CompilerVersion >= 18.5))} {$IFDEF RELEASE} {$UNDEF DEBUG} // If we are using Delphi 2007+ where you can set // DEBUG/RELEASE mode in project options and RELEASE // is currently set we undef DEBUG mode {$ENDIF} {$IFEND} {$IF Defined(IMAGING_DEBUG)} {$ASSERTIONS ON} {$DEBUGINFO ON} {$RANGECHECKS ON} {$IOCHECKS ON} {$OVERFLOWCHECKS ON} {$IFDEF DCC} {$OPTIMIZATION OFF} {$STACKFRAMES ON} {$LOCALSYMBOLS ON} {$DEFINE MEMCHECK} {$ENDIF} {$IFDEF FPC} {$S+} {$CHECKPOINTER ON} {$ENDIF} {$ELSEIF Defined(IMAGING_RELEASE)} {$ASSERTIONS OFF} {$DEBUGINFO OFF} {$RANGECHECKS OFF} {$IOCHECKS OFF} {$OVERFLOWCHECKS OFF} {$IFDEF DCC} {$OPTIMIZATION ON} {$STACKFRAMES OFF} {$LOCALSYMBOLS OFF} {$ENDIF} {$IFDEF FPC} {$S-} {$ENDIF} {$IFEND} {$IF Defined (CPU86) and not Defined(CPUX86)} {$DEFINE CPUX86} // Compatibility with Delphi {$IFEND} {$IF Defined (CPUX86_64) and not Defined(CPUX64)} {$DEFINE CPUX64} // Compatibility with Delphi {$IFEND} {$IF Defined (DARWIN) and not Defined(MACOSX)} {$DEFINE MACOS} // Compatibility with Delphi {$IFEND} {$IF Defined(DCC) and (CompilerVersion < 23)} {$DEFINE CPUX86} // Compatibility with older Delphi {$IFEND} { Compiler capabilities } // Define if compiler supports inlining of functions and procedures {$IF (Defined(DCC) and (CompilerVersion >= 17)) or Defined(FPC)} {$DEFINE HAS_INLINE} {$IFEND} // Define if compiler supports advanced records with methods {$IF (Defined(DCC) and (CompilerVersion >= 18)) or (Defined(FPC) and (FPC_FULLVERSION >= 20600))} {$DEFINE HAS_ADVANCED_RECORDS} {$IFEND} // Define if compiler supports operator overloading // (unfortunately Delphi and FPC operator overloading is not compatible). // FPC supports Delphi compatible operator overloads since 2.6.0 {$IF (Defined(DCC) and (CompilerVersion >= 18)) or (Defined(FPC) and (FPC_FULLVERSION >= 20600))} {$DEFINE HAS_OPERATOR_OVERLOADING} {$IFEND} // Anonymous methods {$IF Defined(DCC) and (CompilerVersion >= 20) } {$DEFINE HAS_ANON_METHODS} {$IFEND} // Generic types (Delphi and FPC implementations incompatible). // Update: FPC supports Delphi compatible generics since 2.6.0 {$IF (Defined(DCC) and (CompilerVersion >= 20)) or (Defined(FPC) and (FPC_FULLVERSION >= 20600))} {$DEFINE HAS_GENERICS} {$IFEND} { Imaging options check} {$IFNDEF HAS_INLINE} {$UNDEF USE_INLINE} {$ENDIF} {$IF not Defined(CPUX86)} {$UNDEF USE_ASM} {$IFEND} {$IFDEF FPC} {$DEFINE COMPONENT_SET_LCL} {$UNDEF COMPONENT_SET_VCL} {$ENDIF} {$IFDEF DELPHI} {$UNDEF COMPONENT_SET_LCL} {$DEFINE COMPONENT_SET_VCL} {$ENDIF} { Platform options } {$IF Defined(WIN32) or Defined(WIN64)} {$DEFINE MSWINDOWS} {$IFEND} {$IFDEF LINUX} {$DEFINE UNIX} {$ENDIF} { More compiler options } {$IFDEF FPC} // Free Pascal options - some options set above (like min enum size) // are reset to defaults by setting {$MODE} so they are // redeclared here {$MODE DELPHI} // compatible with delphi {$GOTO ON} // alow goto {$PACKRECORDS 8} // same as ALING 8 for Delphi {$PACKENUM 4} // Min enum size: 4 B {$IFDEF CPU86} {$ASMMODE INTEL} // intel assembler mode {$ENDIF} {$ENDIF} {$IFDEF HAS_INLINE} {$INLINE ON} // turns inlining on for compilers that support it {$ENDIF} ================================================ FILE: lib/Imaging/ImagingTarga.pas ================================================ { Vampyre Imaging Library by Marek Mauder http://imaginglib.sourceforge.net The contents of this file are used with permission, subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/MPL-1.1.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Alternatively, the contents of this file may be used under the terms of the GNU Lesser General Public License (the "LGPL License"), in which case the provisions of the LGPL License are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of the LGPL License and not to allow others to use your version of this file under the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the LGPL License. If you do not delete the provisions above, a recipient may use your version of this file under either the MPL or the LGPL License. For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html } { This unit contains image format loader/saver for Targa images.} unit ImagingTarga; {$I ImagingOptions.inc} interface uses ImagingTypes, Imaging, ImagingFormats, ImagingUtility; type { Class for loading and saving Truevision Targa images. It can load/save 8bit indexed or grayscale, 16 bit RGB or grayscale, 24 bit RGB and 32 bit ARGB images with or without RLE compression.} TTargaFileFormat = class(TImageFileFormat) protected FUseRLE: LongBool; procedure Define; override; function LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; override; function SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray; Index: LongInt): Boolean; override; procedure ConvertToSupported(var Image: TImageData; const Info: TImageFormatInfo); override; public function TestFormat(Handle: TImagingHandle): Boolean; override; published { Controls that RLE compression is used during saving. Accessible trough ImagingTargaRLE option.} property UseRLE: LongBool read FUseRLE write FUseRLE; end; implementation const STargaFormatName = 'Truevision Targa Image'; STargaMasks = '*.tga'; TargaSupportedFormats: TImageFormats = [ifIndex8, ifGray8, ifA1R5G5B5, ifR8G8B8, ifA8R8G8B8]; TargaDefaultRLE = False; const STargaSignature = 'TRUEVISION-XFILE'; type { Targa file header.} TTargaHeader = packed record IDLength: Byte; ColorMapType: Byte; ImageType: Byte; ColorMapOff: Word; ColorMapLength: Word; ColorEntrySize: Byte; XOrg: SmallInt; YOrg: SmallInt; Width: SmallInt; Height: SmallInt; PixelSize: Byte; Desc: Byte; end; { Footer at the end of TGA file.} TTargaFooter = packed record ExtOff: LongWord; // Extension Area Offset DevDirOff: LongWord; // Developer Directory Offset Signature: TChar16; // TRUEVISION-XFILE Reserved: Byte; // ASCII period '.' NullChar: Byte; // 0 end; { TTargaFileFormat class implementation } procedure TTargaFileFormat.Define; begin inherited; FName := STargaFormatName; FFeatures := [ffLoad, ffSave]; FSupportedFormats := TargaSupportedFormats; FUseRLE := TargaDefaultRLE; AddMasks(STargaMasks); RegisterOption(ImagingTargaRLE, @FUseRLE); end; function TTargaFileFormat.LoadData(Handle: TImagingHandle; var Images: TDynImageDataArray; OnlyFirstLevel: Boolean): Boolean; var Hdr: TTargaHeader; Foo: TTargaFooter; FooterFound, ExtFound: Boolean; I, PSize, PalSize: LongWord; Pal: Pointer; FmtInfo: TImageFormatInfo; WordValue: Word; procedure LoadRLE; var I, CPixel, Cnt: LongInt; Bpp, Rle: Byte; Buffer, Dest, Src: PByte; BufSize: LongInt; begin with GetIO, Images[0] do begin // Alocates buffer large enough to hold the worst case // RLE compressed data and reads then from input BufSize := Width * Height * FmtInfo.BytesPerPixel; BufSize := BufSize + BufSize div 2 + 1; GetMem(Buffer, BufSize); Src := Buffer; Dest := Bits; BufSize := Read(Handle, Buffer, BufSize); Cnt := Width * Height; Bpp := FmtInfo.BytesPerPixel; CPixel := 0; while CPixel < Cnt do begin Rle := Src^; Inc(Src); if Rle < 128 then begin // Process uncompressed pixel Rle := Rle + 1; CPixel := CPixel + Rle; for I := 0 to Rle - 1 do begin // Copy pixel from src to dest case Bpp of 1: Dest^ := Src^; 2: PWord(Dest)^ := PWord(Src)^; 3: PColor24Rec(Dest)^ := PColor24Rec(Src)^; 4: PLongWord(Dest)^ := PLongWord(Src)^; end; Inc(Src, Bpp); Inc(Dest, Bpp); end; end else begin // Process compressed pixels Rle := Rle - 127; CPixel := CPixel + Rle; // Copy one pixel from src to dest (many times there) for I := 0 to Rle - 1 do begin case Bpp of 1: Dest^ := Src^; 2: PWord(Dest)^ := PWord(Src)^; 3: PColor24Rec(Dest)^ := PColor24Rec(Src)^; 4: PLongWord(Dest)^ := PLongWord(Src)^; end; Inc(Dest, Bpp); end; Inc(Src, Bpp); end; end; // set position in source to real end of compressed data Seek(Handle, -(BufSize - LongInt(LongWord(Src) - LongWord(Buffer))), smFromCurrent); FreeMem(Buffer); end; end; begin SetLength(Images, 1); with GetIO, Images[0] do begin // Read targa header Read(Handle, @Hdr, SizeOf(Hdr)); // Skip image ID info Seek(Handle, Hdr.IDLength, smFromCurrent); // Determine image format Format := ifUnknown; case Hdr.ImageType of 1, 9: Format := ifIndex8; 2, 10: case Hdr.PixelSize of 15: Format := ifX1R5G5B5; 16: Format := ifA1R5G5B5; 24: Format := ifR8G8B8; 32: Format := ifA8R8G8B8; end; 3, 11: Format := ifGray8; end; // Format was not assigned by previous testing (it should be in // well formed targas), so formats which reflects bit dept are selected if Format = ifUnknown then case Hdr.PixelSize of 8: Format := ifGray8; 15: Format := ifX1R5G5B5; 16: Format := ifA1R5G5B5; 24: Format := ifR8G8B8; 32: Format := ifA8R8G8B8; end; NewImage(Hdr.Width, Hdr.Height, Format, Images[0]); FmtInfo := GetFormatInfo(Format); if (Hdr.ColorMapType = 1) and (Hdr.ImageType in [1, 9]) then begin // Read palette PSize := Hdr.ColorMapLength * (Hdr.ColorEntrySize shr 3); GetMem(Pal, PSize); try Read(Handle, Pal, PSize); // Process palette PalSize := Iff(Hdr.ColorMapLength > FmtInfo.PaletteEntries, FmtInfo.PaletteEntries, Hdr.ColorMapLength); for I := 0 to PalSize - 1 do case Hdr.ColorEntrySize of 24: with Palette[I] do begin A := $FF; R := PPalette24(Pal)[I].R; G := PPalette24(Pal)[I].G; B := PPalette24(Pal)[I].B; end; // I've never seen tga with these palettes so they are untested 16: with Palette[I] do begin A := (PWordArray(Pal)[I] and $8000) shr 12; R := (PWordArray(Pal)[I] and $FC00) shr 7; G := (PWordArray(Pal)[I] and $03E0) shr 2; B := (PWordArray(Pal)[I] and $001F) shl 3; end; 32: with Palette[I] do begin A := PPalette32(Pal)[I].A; R := PPalette32(Pal)[I].R; G := PPalette32(Pal)[I].G; B := PPalette32(Pal)[I].B; end; end; finally FreeMemNil(Pal); end; end; case Hdr.ImageType of 0, 1, 2, 3: // Load uncompressed mode images Read(Handle, Bits, Size); 9, 10, 11: // Load RLE compressed mode images LoadRLE; end; // Check if there is alpha channel present in A1R5GB5 images, if it is not // change format to X1R5G5B5 if Format = ifA1R5G5B5 then begin if not Has16BitImageAlpha(Width * Height, Bits) then Format := ifX1R5G5B5; end; // We must find true end of file and set input' position to it // paint programs appends extra info at the end of Targas // some of them multiple times (PSP Pro 8) repeat ExtFound := False; FooterFound := False; if Read(Handle, @WordValue, 2) = 2 then begin // 495 = size of Extension Area if WordValue = 495 then begin Seek(Handle, 493, smFromCurrent); ExtFound := True; end else Seek(Handle, -2, smFromCurrent); end; if Read(Handle, @Foo, SizeOf(Foo)) = SizeOf(Foo) then begin if Foo.Signature = STargaSignature then FooterFound := True else Seek(Handle, -SizeOf(Foo), smFromCurrent); end; until (not ExtFound) and (not FooterFound); // Some editors save targas flipped if Hdr.Desc < 31 then FlipImage(Images[0]); Result := True; end; end; function TTargaFileFormat.SaveData(Handle: TImagingHandle; const Images: TDynImageDataArray; Index: LongInt): Boolean; var I: LongInt; Hdr: TTargaHeader; FmtInfo: TImageFormatInfo; Pal: PPalette24; ImageToSave: TImageData; MustBeFreed: Boolean; procedure SaveRLE; var Dest: PByte; WidthBytes, Written, I, Total, DestSize: LongInt; function CountDiff(Data: PByte; Bpp, PixelCount: Longint): LongInt; var Pixel: LongWord; NextPixel: LongWord; N: LongInt; begin N := 0; Pixel := 0; NextPixel := 0; if PixelCount = 1 then begin Result := PixelCount; Exit; end; case Bpp of 1: Pixel := Data^; 2: Pixel := PWord(Data)^; 3: PColor24Rec(@Pixel)^ := PColor24Rec(Data)^; 4: Pixel := PLongWord(Data)^; end; while PixelCount > 1 do begin Inc(Data, Bpp); case Bpp of 1: NextPixel := Data^; 2: NextPixel := PWord(Data)^; 3: PColor24Rec(@NextPixel)^ := PColor24Rec(Data)^; 4: NextPixel := PLongWord(Data)^; end; if NextPixel = Pixel then Break; Pixel := NextPixel; N := N + 1; PixelCount := PixelCount - 1; end; if NextPixel = Pixel then Result := N else Result := N + 1; end; function CountSame(Data: PByte; Bpp, PixelCount: LongInt): LongInt; var Pixel: LongWord; NextPixel: LongWord; N: LongInt; begin N := 1; Pixel := 0; NextPixel := 0; case Bpp of 1: Pixel := Data^; 2: Pixel := PWord(Data)^; 3: PColor24Rec(@Pixel)^ := PColor24Rec(Data)^; 4: Pixel := PLongWord(Data)^; end; PixelCount := PixelCount - 1; while PixelCount > 0 do begin Inc(Data, Bpp); case Bpp of 1: NextPixel := Data^; 2: NextPixel := PWord(Data)^; 3: PColor24Rec(@NextPixel)^ := PColor24Rec(Data)^; 4: NextPixel := PLongWord(Data)^; end; if NextPixel <> Pixel then Break; N := N + 1; PixelCount := PixelCount - 1; end; Result := N; end; procedure RleCompressLine(Data: PByte; PixelCount, Bpp: LongInt; Dest: PByte; var Written: LongInt); const MaxRun = 128; var DiffCount: LongInt; SameCount: LongInt; RleBufSize: LongInt; begin RleBufSize := 0; while PixelCount > 0 do begin DiffCount := CountDiff(Data, Bpp, PixelCount); SameCount := CountSame(Data, Bpp, PixelCount); if (DiffCount > MaxRun) then DiffCount := MaxRun; if (SameCount > MaxRun) then SameCount := MaxRun; if (DiffCount > 0) then begin Dest^ := Byte(DiffCount - 1); Inc(Dest); PixelCount := PixelCount - DiffCount; RleBufSize := RleBufSize + (DiffCount * Bpp) + 1; Move(Data^, Dest^, DiffCount * Bpp); Inc(Data, DiffCount * Bpp); Inc(Dest, DiffCount * Bpp); end; if SameCount > 1 then begin Dest^ := Byte((SameCount - 1) or $80); Inc(Dest); PixelCount := PixelCount - SameCount; RleBufSize := RleBufSize + Bpp + 1; Inc(Data, (SameCount - 1) * Bpp); case Bpp of 1: Dest^ := Data^; 2: PWord(Dest)^ := PWord(Data)^; 3: PColor24Rec(Dest)^ := PColor24Rec(Data)^; 4: PLongWord(Dest)^ := PLongWord(Data)^; end; Inc(Data, Bpp); Inc(Dest, Bpp); end; end; Written := RleBufSize; end; begin with ImageToSave do begin // Allocate enough space to hold the worst case compression // result and then compress source's scanlines WidthBytes := Width * FmtInfo.BytesPerPixel; DestSize := WidthBytes * Height; DestSize := DestSize + DestSize div 2 + 1; GetMem(Dest, DestSize); Total := 0; try for I := 0 to Height - 1 do begin RleCompressLine(@PByteArray(Bits)[I * WidthBytes], Width, FmtInfo.BytesPerPixel, @PByteArray(Dest)[Total], Written); Total := Total + Written; end; GetIO.Write(Handle, Dest, Total); finally FreeMem(Dest); end; end; end; begin Result := False; if MakeCompatible(Images[Index], ImageToSave, MustBeFreed) then with GetIO, ImageToSave do try FmtInfo := GetFormatInfo(Format); // Fill targa header FillChar(Hdr, SizeOf(Hdr), 0); Hdr.IDLength := 0; Hdr.ColorMapType := Iff(FmtInfo.PaletteEntries > 0, 1, 0); Hdr.Width := Width; Hdr.Height := Height; Hdr.PixelSize := FmtInfo.BytesPerPixel * 8; Hdr.ColorMapLength := FmtInfo.PaletteEntries; Hdr.ColorEntrySize := Iff(FmtInfo.PaletteEntries > 0, 24, 0); Hdr.ColorMapOff := 0; // This indicates that targa is stored in top-left format // as our images -> no flipping is needed. Hdr.Desc := 32; // Set alpha channel size in descriptor (mostly ignored by other software though) if Format = ifA8R8G8B8 then Hdr.Desc := Hdr.Desc or 8 else if Format = ifA1R5G5B5 then Hdr.Desc := Hdr.Desc or 1; // Choose image type if FmtInfo.IsIndexed then Hdr.ImageType := Iff(FUseRLE, 9, 1) else if FmtInfo.HasGrayChannel then Hdr.ImageType := Iff(FUseRLE, 11, 3) else Hdr.ImageType := Iff(FUseRLE, 10, 2); Write(Handle, @Hdr, SizeOf(Hdr)); // Write palette if FmtInfo.PaletteEntries > 0 then begin GetMem(Pal, FmtInfo.PaletteEntries * SizeOf(TColor24Rec)); try for I := 0 to FmtInfo.PaletteEntries - 1 do with Pal[I] do begin R := Palette[I].R; G := Palette[I].G; B := Palette[I].B; end; Write(Handle, Pal, FmtInfo.PaletteEntries * SizeOf(TColor24Rec)); finally FreeMemNil(Pal); end; end; if FUseRLE then // Save rle compressed mode images SaveRLE else // Save uncompressed mode images Write(Handle, Bits, Size); Result := True; finally if MustBeFreed then FreeImage(ImageToSave); end; end; procedure TTargaFileFormat.ConvertToSupported(var Image: TImageData; const Info: TImageFormatInfo); var ConvFormat: TImageFormat; begin if Info.HasGrayChannel then // Convert all grayscale images to Gray8 (preserve alpha of AxGrayx formats) ConvFormat := IffFormat(not Info.HasAlphaChannel, ifGray8, ifA8R8G8B8) else if Info.IsIndexed then // Convert all indexed images to Index8 ConvFormat := ifIndex8 else if Info.HasAlphaChannel then // Convert images with alpha channel to A8R8G8B8 ConvFormat := ifA8R8G8B8 else if Info.UsePixelFormat then // Convert 16bit images (without alpha channel) to A1R5G5B5 ConvFormat := ifA1R5G5B5 else // Convert all other formats to R8G8B8 ConvFormat := ifR8G8B8; ConvertImage(Image, ConvFormat); end; function TTargaFileFormat.TestFormat(Handle: TImagingHandle): Boolean; var Hdr: TTargaHeader; ReadCount: LongInt; begin Result := False; if Handle <> nil then begin ReadCount := GetIO.Read(Handle, @Hdr, SizeOf(Hdr)); GetIO.Seek(Handle, -ReadCount, smFromCurrent); Result := (ReadCount >= SizeOf(Hdr)) and (Hdr.ImageType in [0, 1, 2, 3, 9, 10, 11]) and (Hdr.PixelSize in [1, 8, 15, 16, 24, 32]) and (Hdr.ColorEntrySize in [0, 16, 24, 32]); end; end; initialization RegisterImageFileFormat(TTargaFileFormat); { File Notes: -- TODOS ---------------------------------------------------- - nothing now -- 0.21 Changes/Bug Fixes ----------------------------------- - MakeCompatible method moved to base class, put ConvertToSupported here. GetSupportedFormats removed, it is now set in constructor. - Made public properties for options registered to SetOption/GetOption functions. - Changed extensions to filename masks. - Changed SaveData, LoadData, and MakeCompatible methods according to changes in base class in Imaging unit. -- 0.17 Changes/Bug Fixes ----------------------------------- - 16 bit images are usually without alpha but some has alpha channel and there is no indication of it - so I have added a check: if all pixels of image are with alpha = 0 image is treated as X1R5G5B5 otherwise as A1R5G5B5 - fixed problems with some nonstandard 15 bit images } end. ================================================ FILE: lib/Imaging/ImagingTypes.pas ================================================ { Vampyre Imaging Library by Marek Mauder http://imaginglib.sourceforge.net The contents of this file are used with permission, subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/MPL-1.1.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Alternatively, the contents of this file may be used under the terms of the GNU Lesser General Public License (the "LGPL License"), in which case the provisions of the LGPL License are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of the LGPL License and not to allow others to use your version of this file under the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the LGPL License. If you do not delete the provisions above, a recipient may use your version of this file under either the MPL or the LGPL License. For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html } { This unit contains basic types and constants used by Imaging library.} unit ImagingTypes; {$I ImagingOptions.inc} interface const { Current Major version of Imaging.} ImagingVersionMajor = 0; { Current Minor version of Imaging.} ImagingVersionMinor = 77; { Current patch of Imaging.} ImagingVersionPatch = 1; { Imaging Option Ids whose values can be set/get by SetOption/ GetOption functions.} { Defines Jpeg compression quality, ranges from 1 (ugly/small) to 100 (nice/large). Default value is 90.} ImagingJpegQuality = 10; { Specifies whether Jpeg images are saved in progressive format, can be 0 or 1. Default value is 0.} ImagingJpegProgressive = 11; { Specifies whether Windows Bitmaps are saved using RLE compression (only for 1/4/8 bit images), can be 0 or 1. Default value is 1.} ImagingBitmapRLE = 12; { Specifies whether Targa images are saved using RLE compression, can be 0 or 1. Default value is 0.} ImagingTargaRLE = 13; { Value of this option is non-zero if last loaded DDS file was cube map.} ImagingDDSLoadedCubeMap = 14; { Value of this option is non-zero if last loaded DDS file was volume texture.} ImagingDDSLoadedVolume = 15; { Value of this option is number of mipmap levels of last loaded DDS image.} ImagingDDSLoadedMipMapCount = 16; { Value of this option is depth (slices of volume texture or faces of cube map) of last loaded DDS image.} ImagingDDSLoadedDepth = 17; { If it is non-zero next saved DDS file should be stored as cube map.} ImagingDDSSaveCubeMap = 18; { If it is non-zero next saved DDS file should be stored as volume texture.} ImagingDDSSaveVolume = 19; { Sets the number of mipmaps which should be stored in the next saved DDS file. Only applies to cube maps and volumes, ordinary 2D textures save all levels present in input.} ImagingDDSSaveMipMapCount = 20; { Sets the depth (slices of volume texture or faces of cube map) of the next saved DDS file.} ImagingDDSSaveDepth = 21; { Sets precompression filter used when saving PNG images. Allowed values are: 0 (none), 1 (sub), 2 (up), 3 (average), 4 (paeth), 5 (use 0 for indexed/gray images and 4 for RGB/ARGB images), 6 (adaptive filtering - use best filter for each scanline - very slow). Note that filters 3 and 4 are much slower than filters 1 and 2. Default value is 5.} ImagingPNGPreFilter = 25; { Sets ZLib compression level used when saving PNG images. Allowed values are in range 0 (no compresstion) to 9 (best compression). Default value is 5.} ImagingPNGCompressLevel = 26; { Boolean option that specifies whether PNG images with more frames (APNG format) are animated by Imaging (according to frame disposal/blend methods) or just raw frames are loaded and sent to user (if you want to animate APNG yourself). Default value is 1.} ImagingPNGLoadAnimated = 27; { Sets ZLib compression strategy used when saving PNG files (see deflateInit2() in ZLib for details). Allowed values are: 0 (default), 1 (filtered), 2 (huffman only). Default value is 0.} ImagingPNGZLibStrategy = 28; { Specifies whether MNG animation frames are saved with lossy or lossless compression. Lossless frames are saved as PNG images and lossy frames are saved as JNG images. Allowed values are 0 (False) and 1 (True). Default value is 0.} ImagingMNGLossyCompression = 32; { Defines whether alpha channel of lossy compressed MNG frames (when ImagingMNGLossyCompression is 1) is lossy compressed too. Allowed values are 0 (False) and 1 (True). Default value is 0.} ImagingMNGLossyAlpha = 33; { Sets precompression filter used when saving MNG frames as PNG images. For details look at ImagingPNGPreFilter.} ImagingMNGPreFilter = 34; { Sets ZLib compression level used when saving MNG frames as PNG images. For details look at ImagingPNGCompressLevel.} ImagingMNGCompressLevel = 35; { Specifies compression quality used when saving MNG frames as JNG images. For details look at ImagingJpegQuality.} ImagingMNGQuality = 36; { Specifies whether images are saved in progressive format when saving MNG frames as JNG images. For details look at ImagingJpegProgressive.} ImagingMNGProgressive = 37; { Specifies whether alpha channels of JNG images are lossy compressed. Allowed values are 0 (False) and 1 (True). Default value is 0.} ImagingJNGLossyAlpha = 40; { Sets precompression filter used when saving lossless alpha channels. For details look at ImagingPNGPreFilter.} ImagingJNGAlphaPreFilter = 41; { Sets ZLib compression level used when saving lossless alpha channels. For details look at ImagingPNGCompressLevel.} ImagingJNGAlphaCompressLevel = 42; { Defines compression quality used when saving JNG images (and lossy alpha channels). For details look at ImagingJpegQuality.} ImagingJNGQuality = 43; { Specifies whether JNG images are saved in progressive format. For details look at ImagingJpegProgressive.} ImagingJNGProgressive = 44; { Specifies whether PGM files are stored in text or in binary format. Allowed values are 0 (store as text - very! large files) and 1 (save binary). Default value is 1.} ImagingPGMSaveBinary = 50; { Specifies whether PPM files are stored in text or in binary format. Allowed values are 0 (store as text - very! large files) and 1 (save binary). Default value is 1.} ImagingPPMSaveBinary = 51; { Boolean option that specifies whether GIF images with more frames are animated by Imaging (according to frame disposal methods) or just raw frames are loaded and sent to user (if you want to animate GIF yourself). Default value is 1. Raw frames are 256 color indexed images (ifIndex8), whereas animated frames are always in 32bit ifA8R8G8B8 format (simplifies animating).} ImagingGIFLoadAnimated = 56; { This option is used when reducing number of colors used in image (mainly when converting from ARGB image to indexed format). Mask is 'anded' (bitwise AND) with every pixel's channel value when creating color histogram. If $FF is used all 8bits of color channels are used which can result in very slow proccessing of large images with many colors so you can use lower masks to speed it up (FC, F8 and F0 are good choices). Allowed values are in range <0, $FF> and default is $FE. } ImagingColorReductionMask = 128; { This option can be used to override image data format during image loading. If set to format different from ifUnknown all loaded images are automaticaly converted to this format. Useful when you have many files in various formats but you want them all in one format for further proccessing. Allowed values are in range and default value is ifUnknown.} ImagingLoadOverrideFormat = 129; { This option can be used to override image data format during image saving. If set to format different from ifUnknown all images to be saved are automaticaly internaly converted to this format. Note that image file formats support only a subset of Imaging data formats so final saved file may in different format than this override. Allowed values are in range and default value is ifUnknown.} ImagingSaveOverrideFormat = 130; { Specifies resampling filter used when generating mipmaps. It is used in GenerateMipMaps low level function and Direct3D and OpenGL extensions. Allowed values are in range and default value is 1 (linear filter).} ImagingMipMapFilter = 131; { Specifies treshold value used when automatically converting images to ifBinary format. For adaptive tresholding see ImagingBinary.pas unit. Default value is 128 and allowed range is 0..255.} ImagingBinaryTreshold = 132; { Returned by GetOption if given Option Id is invalid.} InvalidOption = -$7FFFFFFF; { Indices that can be used to access channel values in array parts of structures like TColor32Rec. Note that this order can be used only for ARGB images. For ABGR image you must swap Red and Blue.} ChannelBlue = 0; ChannelGreen = 1; ChannelRed = 2; ChannelAlpha = 3; type { Enum defining image data format. In formats with more channels, first channel after "if" is stored in the most significant bits and channel before end is stored in the least significant.} TImageFormat = ( ifUnknown = 0, ifDefault = 1, { Indexed formats using palette } ifIndex8 = 10, { Grayscale/Luminance formats } ifGray8 = 40, ifA8Gray8 = 41, ifGray16 = 42, ifGray32 = 43, ifGray64 = 44, ifA16Gray16 = 45, { ARGB formats } ifX5R1G1B1 = 80, ifR3G3B2 = 81, ifR5G6B5 = 82, ifA1R5G5B5 = 83, ifA4R4G4B4 = 84, ifX1R5G5B5 = 85, ifX4R4G4B4 = 86, ifR8G8B8 = 87, ifA8R8G8B8 = 88, ifX8R8G8B8 = 89, ifR16G16B16 = 90, ifA16R16G16B16 = 91, ifB16G16R16 = 92, ifA16B16G16R16 = 93, { Floating point formats } ifR32F = 160, ifA32R32G32B32F = 161, ifA32B32G32R32F = 162, ifR16F = 163, ifA16R16G16B16F = 164, ifA16B16G16R16F = 165, ifR32G32B32F = 166, ifB32G32R32F = 167, { Special formats } ifDXT1 = 200, ifDXT3 = 201, ifDXT5 = 202, ifBTC = 203, ifATI1N = 204, ifATI2N = 205, ifBinary = 206, { Passtrough formats } ifETC1 = 220, ifETC2RGB = 221, ifETC2RGBA = 222, ifETC2PA = 223, ifDXBC6 = 224, ifDXBC7 = 225 ); { Color value for 32 bit images.} TColor32 = LongWord; PColor32 = ^TColor32; { Color value for 64 bit images.} TColor64 = type Int64; PColor64 = ^TColor64; { Color record for 24 bit images, which allows access to individual color channels.} TColor24Rec = packed record case LongInt of 0: (B, G, R: Byte); 1: (Channels: array[0..2] of Byte); end; PColor24Rec = ^TColor24Rec; TColor24RecArray = array[0..MaxInt div SizeOf(TColor24Rec) - 1] of TColor24Rec; PColor24RecArray = ^TColor24RecArray; { Color record for 32 bit images, which allows access to individual color channels.} TColor32Rec = packed record case LongInt of 0: (Color: TColor32); 1: (B, G, R, A: Byte); 2: (Channels: array[0..3] of Byte); 3: (Color24Rec: TColor24Rec); end; PColor32Rec = ^TColor32Rec; TColor32RecArray = array[0..MaxInt div SizeOf(TColor32Rec) - 1] of TColor32Rec; PColor32RecArray = ^TColor32RecArray; { Color record for 48 bit images, which allows access to individual color channels.} TColor48Rec = packed record case LongInt of 0: (B, G, R: Word); 1: (Channels: array[0..2] of Word); end; PColor48Rec = ^TColor48Rec; TColor48RecArray = array[0..MaxInt div SizeOf(TColor48Rec) - 1] of TColor48Rec; PColor48RecArray = ^TColor48RecArray; { Color record for 64 bit images, which allows access to individual color channels.} TColor64Rec = packed record case LongInt of 0: (Color: TColor64); 1: (B, G, R, A: Word); 2: (Channels: array[0..3] of Word); 3: (Color48Rec: TColor48Rec); end; PColor64Rec = ^TColor64Rec; TColor64RecArray = array[0..MaxInt div SizeOf(TColor64Rec) - 1] of TColor64Rec; PColor64RecArray = ^TColor64RecArray; { Color record for 96 bit floating point images, which allows access to individual color channels.} TColor96FPRec = packed record case Integer of 0: (B, G, R: Single); 1: (Channels: array[0..2] of Single); end; PColor96FPRec = ^TColor96FPRec; TColor96FPRecArray = array[0..MaxInt div SizeOf(TColor96FPRec) - 1] of TColor96FPRec; PColor96FPRecArray = ^TColor96FPRecArray; { Color record for 128 bit floating point images, which allows access to individual color channels.} TColorFPRec = packed record case LongInt of 0: (B, G, R, A: Single); 1: (Channels: array[0..3] of Single); 2: (Color96Rec: TColor96FPRec); end; PColorFPRec = ^TColorFPRec; TColorFPRecArray = array[0..MaxInt div SizeOf(TColorFPRec) - 1] of TColorFPRec; PColorFPRecArray = ^TColorFPRecArray; { 16 bit floating-point value. It has 1 sign bit, 5 exponent bits, and 10 mantissa bits.} THalfFloat = type Word; PHalfFloat = ^THalfFloat; { Color record for 64 bit floating point images, which allows access to individual color channels.} TColorHFRec = packed record case LongInt of 0: (B, G, R, A: THalfFloat); 1: (Channels: array[0..3] of THalfFloat); end; PColorHFRec = ^TColorHFRec; TColorHFRecArray = array[0..MaxInt div SizeOf(TColorHFRec) - 1] of TColorHFRec; PColorHFRecArray = ^TColorHFRecArray; { Palette for indexed mode images with 32 bit colors.} TPalette32 = TColor32RecArray; TPalette32Size256 = array[0..255] of TColor32Rec; PPalette32 = ^TPalette32; { Palette for indexd mode images with 24 bit colors.} TPalette24 = TColor24RecArray; TPalette24Size256 = array[0..255] of TColor24Rec; PPalette24 = ^TPalette24; { Record that stores single image data and information describing it.} TImageData = packed record Width: LongInt; // Width of image in pixels Height: LongInt; // Height of image in pixels Format: TImageFormat; // Data format of image Size: LongInt; // Size of image bits in Bytes Bits: Pointer; // Pointer to memory containing image bits Palette: PPalette32; // Image palette for indexed images Tag: Pointer; // User data end; PImageData = ^TImageData; { Pixel format information used in conversions to/from 16 and 8 bit ARGB image formats.} TPixelFormatInfo = packed record ABitCount, RBitCount, GBitCount, BBitCount: Byte; ABitMask, RBitMask, GBitMask, BBitMask: LongWord; AShift, RShift, GShift, BShift: Byte; ARecDiv, RRecDiv, GRecDiv, BRecDiv: Byte; end; PPixelFormatInfo = ^TPixelFormatInfo; PImageFormatInfo = ^TImageFormatInfo; { Look at TImageFormatInfo.GetPixelsSize for details.} TFormatGetPixelsSizeFunc = function(Format: TImageFormat; Width, Height: LongInt): LongInt; { Look at TImageFormatInfo.CheckDimensions for details.} TFormatCheckDimensionsProc = procedure(Format: TImageFormat; var Width, Height: LongInt); { Function for getting pixel colors. Native pixel is read from Image and then translated to 32 bit ARGB.} TGetPixel32Func = function(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColor32Rec; { Function for getting pixel colors. Native pixel is read from Image and then translated to FP ARGB.} TGetPixelFPFunc = function(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32): TColorFPRec; { Procedure for setting pixel colors. Input 32 bit ARGB color is translated to native format and then written to Image.} TSetPixel32Proc = procedure(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32;const Color: TColor32Rec); { Procedure for setting pixel colors. Input FP ARGB color is translated to native format and then written to Image.} TSetPixelFPProc = procedure(Bits: Pointer; Info: PImageFormatInfo; Palette: PPalette32; const Color: TColorFPRec); { Additional information for each TImageFormat value.} TImageFormatInfo = packed record Format: TImageFormat; // Format described by this record Name: array[0..15] of Char; // Symbolic name of format BytesPerPixel: LongInt; // Number of bytes per pixel (note: it is // 0 for formats where BitsPerPixel < 8 (e.g. DXT). // Use GetPixelsSize function to get size of // image data. ChannelCount: LongInt; // Number of image channels (R, G, B, A, Gray) PaletteEntries: LongInt; // Number of palette entries HasGrayChannel: Boolean; // True if image has grayscale channel HasAlphaChannel: Boolean; // True if image has alpha channel IsFloatingPoint: Boolean; // True if image has floating point pixels UsePixelFormat: Boolean; // True if image uses pixel format IsRBSwapped: Boolean; // True if Red and Blue channels are swapped // e.g. A16B16G16R16 has IsRBSwapped True RBSwapFormat: TImageFormat; // Indicates supported format with swapped // Red and Blue channels, ifUnknown if such // format does not exist IsIndexed: Boolean; // True if image uses palette IsSpecial: Boolean; // True if image is in special format IsPasstrough: Boolean; // True if image is in passtrough program (Imaging // iself doesn't know how to decode and encode it - // complex texture compressions etc.) PixelFormat: PPixelFormatInfo; // Pixel format structure GetPixelsSize: TFormatGetPixelsSizeFunc; // Returns size in bytes of // Width * Height pixels of image CheckDimensions: TFormatCheckDimensionsProc; // some formats have limited // values of Width and Height. This // procedure checks and changes dimensions // to be valid for given format. GetPixel32: TGetPixel32Func; // 32bit ARGB pixel get function GetPixelFP: TGetPixelFPFunc; // FP ARGB pixel get function SetPixel32: TSetPixel32Proc; // 32bit ARGB pixel set procedure SetPixelFP: TSetPixelFPProc; // FP ARGB pixel set procedure SpecialNearestFormat: TImageFormat; // Regular image format used when // compressing/decompressing special images // as source/target end; { Handle to list of image data records.} TImageDataList = Pointer; PImageDataList = ^TImageDataList; { Handle to input/output.} TImagingHandle = Pointer; { Filters used in functions that resize images or their portions.} TResizeFilter = ( rfNearest = 0, rfBilinear = 1, rfBicubic = 2, rfLanczos = 3); { Seek origin mode for IO function Seek.} TSeekMode = ( smFromBeginning = 0, smFromCurrent = 1, smFromEnd = 2); TOpenMode = ( omReadOnly = 0, // Opens file for reading only omCreate = 1, // Creates new file (overwriting any existing) and opens it for writing omReadWrite = 2 // Opens for reading and writing. Non existing file is created. ); { IO functions used for reading and writing images from/to input/output.} TOpenProc = function(Source: PChar; Mode: TOpenMode): TImagingHandle; cdecl; TCloseProc = procedure(Handle: TImagingHandle); cdecl; TEofProc = function(Handle: TImagingHandle): Boolean; cdecl; TSeekProc = function(Handle: TImagingHandle; Offset: LongInt; Mode: TSeekMode): LongInt; cdecl; TTellProc = function(Handle: TImagingHandle): LongInt; cdecl; TReadProc = function(Handle: TImagingHandle; Buffer: Pointer; Count: LongInt): LongInt; cdecl; TWriteProc = function(Handle: TImagingHandle; Buffer: Pointer; Count: LongInt): LongInt; cdecl; {$IFNDEF FPC} type {$IF CompilerVersion <= 18.5} PtrUInt = LongWord; {$ELSE} PtrUInt = NativeUInt; {$IFEND} {$ENDIF} implementation { File Notes: -- TODOS ---------------------------------------------------- - add lookup tables to pixel formats for fast conversions -- 0.77.1 --------------------------------------------------- - Added "Passtrough" image data formats. - Added Tag to TImageData for storing user data. - Added ImagingPNGZLibStrategy option. - Changed IO functions. Merged open functions to one and added third open mode R/W (for TIFF append etc.). - Added new image data formats and related structures: ifR32G32B32F, ifB32G32G32F. -- 0.26.5 Changes/Bug Fixes --------------------------------- - Added ifBinary image format and ImagingBinaryTreshold option. - Lanczos filter added to TResizeFilter enum. -- 0.24.3 Changes/Bug Fixes --------------------------------- - Added ifATI1N and ifATI2N image data formats. -- 0.23 Changes/Bug Fixes ----------------------------------- - Added ifBTC image format and SpecialNearestFormat field to TImageFormatInfo. -- 0.21 Changes/Bug Fixes ----------------------------------- - Added option constants for PGM and PPM file formats. - Added TPalette32Size256 and TPalette24Size256 types. -- 0.19 Changes/Bug Fixes ----------------------------------- - added ImagingVersionPatch constant so bug fix only releases can be distinguished from ordinary major/minor releases - renamed TPixelFormat to TPixelFormatInfo to avoid name collisions with Graphics.TPixelFormat - added new image data formats: ifR16F, ifA16R16G16B16F, ifA16B16G16R16F - added pixel get/set function pointers to TImageFormatInfo - added 16bit half float type and color record - renamed TColorFRec to TColorFPRec (and related types too) -- 0.17 Changes/Bug Fixes ----------------------------------- - added option ImagingMipMapFilter which now controls resampling filter used when generating mipmaps - added TResizeFilter type - added ChannelCount to TImageFormatInfo - added new option constants for MNG and JNG images -- 0.15 Changes/Bug Fixes ----------------------------------- - added RBSwapFormat to TImageFormatInfo for faster conversions between swapped formats (it just calls SwapChannels now if RBSwapFormat is not ifUnknown) - moved TImageFormatInfo and required types from Imaging unit here, removed TImageFormatShortInfo - added new options: ImagingLoadOverrideFormat, ImagingSaveOverrideFormat -- 0.13 Changes/Bug Fixes ----------------------------------- - new ImagingColorReductionMask option added - new image format added: ifA16Gray16 } end. ================================================ FILE: lib/Imaging/ImagingUtility.pas ================================================ { Vampyre Imaging Library by Marek Mauder http://imaginglib.sourceforge.net The contents of this file are used with permission, subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/MPL-1.1.html Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. Alternatively, the contents of this file may be used under the terms of the GNU Lesser General Public License (the "LGPL License"), in which case the provisions of the LGPL License are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of the LGPL License and not to allow others to use your version of this file under the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the LGPL License. If you do not delete the provisions above, a recipient may use your version of this file under either the MPL or the LGPL License. For more information about the LGPL: http://www.gnu.org/copyleft/lesser.html } { This unit contains utility functions and types for Imaging library.} unit ImagingUtility; {$I ImagingOptions.inc} interface uses SysUtils, Classes, Types; const STrue = 'True'; SFalse = 'False'; type TByteArray = array[0..MaxInt - 1] of Byte; PByteArray = ^TByteArray; TWordArray = array[0..MaxInt div 2 - 1] of Word; PWordArray = ^TWordArray; TLongIntArray = array[0..MaxInt div 4 - 1] of LongInt; PLongIntArray = ^TLongIntArray; TLongWordArray = array[0..MaxInt div 4 - 1] of LongWord; PLongWordArray = ^TLongWordArray; TInt64Array = array[0..MaxInt div 8 - 1] of Int64; PInt64Array = ^TInt64Array; TSingleArray = array[0..MaxInt div 4 - 1] of Single; PSingleArray = ^TSingleArray; TBooleanArray = array[0..MaxInt - 1] of Boolean; PBooleanArray = ^TBooleanArray; TDynByteArray = array of Byte; TDynIntegerArray = array of Integer; TDynBooleanArray = array of Boolean; TDynStringArray = array of string; TWordRec = packed record case Integer of 0: (WordValue: Word); 1: (Low, High: Byte); end; PWordRec = ^TWordRec; TWordRecArray = array[0..MaxInt div 2 - 1] of TWordRec; PWordRecArray = ^TWordRecArray; TLongWordRec = packed record case Integer of 0: (LongWordValue: LongWord); 1: (Low, High: Word); { Array variants - Index 0 means lowest significant byte (word, ...).} 2: (Words: array[0..1] of Word); 3: (Bytes: array[0..3] of Byte); end; PLongWordRec = ^TLongWordRec; TLongWordRecArray = array[0..MaxInt div 4 - 1] of TLongWordRec; PLongWordRecArray = ^TLongWordRecArray; TInt64Rec = packed record case Integer of 0: (Int64Value: Int64); 1: (Low, High: LongWord); { Array variants - Index 0 means lowest significant byte (word, ...).} 2: (Words: array[0..3] of Word); 3: (Bytes: array[0..7] of Byte); end; PInt64Rec = ^TInt64Rec; TInt64RecArray = array[0..MaxInt div 8 - 1] of TInt64Rec; PInt64RecArray = ^TInt64RecArray; TFloatHelper = record Data: Int64; case Integer of 0: (Data64: Int64); 1: (Data32: LongWord); end; PFloatHelper = ^TFloatHelper; TFloatRect = record Left, Top, Right, Bottom: Single; end; TChar2 = array[0..1] of AnsiChar; TChar3 = array[0..2] of AnsiChar; TChar4 = array[0..3] of AnsiChar; TChar8 = array[0..7] of AnsiChar; TChar16 = array[0..15] of AnsiChar; TAnsiCharSet = set of AnsiChar; ENotImplemented = class(Exception) public constructor Create; end; { Options for BuildFileList function: flFullNames - file names in result will have full path names (ExtractFileDir(Path) + FileName) flRelNames - file names in result will have names relative to ExtractFileDir(Path) dir flRecursive - adds files in subdirectories found in Path.} TFileListOption = (flFullNames, flRelNames, flRecursive); TFileListOptions = set of TFileListOption; { Frees class instance and sets its reference to nil.} procedure FreeAndNil(var Obj); { Frees pointer and sets it to nil.} procedure FreeMemNil(var P); {$IFDEF USE_INLINE}inline;{$ENDIF} { Replacement of standard System.FreeMem procedure which checks if P is nil (this is only needed for Free Pascal, Delphi makes checks in its FreeMem).} procedure FreeMem(P: Pointer); {$IFDEF USE_INLINE}inline;{$ENDIF} { Returns current exception object. Do not call outside exception handler.} function GetExceptObject: Exception; {$IFDEF USE_INLINE}inline;{$ENDIF} { Returns time value with microsecond resolution.} function GetTimeMicroseconds: Int64; { Returns time value with milisecond resolution.} function GetTimeMilliseconds: Int64; { Returns file extension (without "." dot)} function GetFileExt(const FileName: string): string; { Returns file name of application's executable.} function GetAppExe: string; { Returns directory where application's exceutable is located without path delimiter at the end.} function GetAppDir: string; { Works like SysUtils.ExtractFileName but supports '/' and '\' dir delimiters at the same time (whereas ExtractFileName supports on default delimiter on current platform).} function GetFileName(const FileName: string): string; { Works like SysUtils.ExtractFileDir but supports '/' and '\' dir delimiters at the same time (whereas ExtractFileDir supports on default delimiter on current platform).} function GetFileDir(const FileName: string): string; { Returns True if Subject matches given Mask with optional case sensitivity. Mask can contain ? and * special characters: ? matches one character, * matches zero or more characters.} function StrMaskMatch(const Subject, Mask: string; CaseSensitive: Boolean = False): Boolean; { This function fills Files string list with names of files found with FindFirst/FindNext functions (See details on Path/Atrr here). - BuildFileList('c:\*.*', faAnyFile, List, [flRecursive]) returns list of all files (only name.ext - no path) on C drive - BuildFileList('d:\*.*', faDirectory, List, [flFullNames]) returns list of all directories (d:\dirxxx) in root of D drive.} function BuildFileList(Path: string; Attr: LongInt; Files: TStrings; Options: TFileListOptions = []): Boolean; { Similar to RTL's Pos function but with optional Offset where search will start. This function is in the RTL StrUtils unit but } function PosEx(const SubStr, S: string; Offset: LongInt = 1): LongInt; { Same as PosEx but without case sensitivity.} function PosNoCase(const SubStr, S: string; Offset: LongInt = 1): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF} { Returns a sub-string from S which is followed by Sep separator and deletes the sub-string from S including the separator.} function StrToken(var S: string; Sep: Char): string; { Same as StrToken but searches from the end of S string.} function StrTokenEnd(var S: string; Sep: Char): string; { Fills instance of TStrings with tokens from string S where tokens are separated by one of Seps characters.} procedure StrTokensToList(const S: string; Sep: Char; Tokens: TStrings); { Returns string representation of integer number (with digit grouping). Uses current locale.} function IntToStrFmt(const I: Int64): string; {$IFDEF USE_INLINE}inline;{$ENDIF} { Returns string representation of float number (with digit grouping). Uses current locale.} function FloatToStrFmt(const F: Double; Precision: Integer = 2): string; {$IFDEF USE_INLINE}inline;{$ENDIF} { Returns format settings for parsing floats (dot as decimal separator). Useful when fomatting/parsing floats etc.} function GetFormatSettingsForFloats: TFormatSettings; { Returns True if S contains at least one of the substrings in SubStrs array. Case sensitive.} function ContainsAnySubStr(const S: string; const SubStrs: array of string): Boolean; { Extracts substring starting at IdxStart ending at IdxEnd. S[IdxEnd] is not included in the result.} function SubString(const S: string; IdxStart, IdxEnd: Integer): string; {$IFDEF USE_INLINE}inline;{$ENDIF} { Clamps integer value to range } function ClampInt(Number: LongInt; Min, Max: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF} { Clamps float value to range } function ClampFloat(Number: Single; Min, Max: Single): Single; {$IFDEF USE_INLINE}inline;{$ENDIF} { Clamps integer value to Byte boundaries.} function ClampToByte(Value: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF} { Clamps integer value to Word boundaries.} function ClampToWord(Value: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF} { Returns True if Num is power of 2.} function IsPow2(Num: LongInt): Boolean; {$IFDEF USE_INLINE}inline;{$ENDIF} { Returns next power of 2 greater than or equal to Num (if Num itself is power of 2 then it retuns Num).} function NextPow2(Num: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF} { Raises 2 to the given integer power (in range [0, 30]).} function Pow2Int(Exponent: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF} { Raises Base to any power.} function Power(const Base, Exponent: Single): Single; { Returns log base 2 of integer X (max 2^30) or -1 if X is not power of 2.} function Log2Int(X: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF} { Returns log base 2 of X.} function Log2(X: Single): Single; { Returns log base 10 of X.} function Log10(X: Single): Single; { Returns largest integer <= Val (for 5.9 returns 5).} function Floor(Value: Single): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF} { Returns smallest integer >= Val (for 5.1 returns 6).} function Ceil(Value: Single): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF} { Returns lesser of two integer numbers.} function Min(A, B: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF} { Returns lesser of two float numbers.} function MinFloat(A, B: Single): Single; {$IFDEF USE_INLINE}inline;{$ENDIF} { Returns greater of two integer numbers.} function Max(A, B: LongInt): LongInt; {$IFDEF USE_INLINE}inline;{$ENDIF} { Returns greater of two float numbers.} function MaxFloat(A, B: Single): Single; {$IFDEF USE_INLINE}inline;{$ENDIF} { Returns result from multiplying Number by Numerator and then dividing by Denominator. Denominator must be greater than 0.} function MulDiv(Number, Numerator, Denominator: Word): Word; {$IFDEF USE_INLINE}inline;{$ENDIF} { Switches Boolean value.} procedure Switch(var Value: Boolean); {$IFDEF USE_INLINE}inline;{$ENDIF} { If Condition is True then TruePart is retured, otherwise FalsePart is returned.} function Iff(Condition: Boolean; TruePart, FalsePart: LongInt): LongInt; overload; {$IFDEF USE_INLINE}inline;{$ENDIF} { If Condition is True then TruePart is retured, otherwise FalsePart is returned.} function IffUnsigned(Condition: Boolean; TruePart, FalsePart: LongWord): LongWord; overload; {$IFDEF USE_INLINE}inline;{$ENDIF} { If Condition is True then TruePart is retured, otherwise FalsePart is returned.} function Iff(Condition, TruePart, FalsePart: Boolean): Boolean; overload; {$IFDEF USE_INLINE}inline;{$ENDIF} { If Condition is True then TruePart is retured, otherwise FalsePart is returned.} function Iff(Condition: Boolean; const TruePart, FalsePart: string): string; overload; {$IFDEF USE_INLINE}inline;{$ENDIF} { If Condition is True then TruePart is retured, otherwise FalsePart is returned.} function Iff(Condition: Boolean; TruePart, FalsePart: Char): Char; overload; {$IFDEF USE_INLINE}inline;{$ENDIF} { If Condition is True then TruePart is retured, otherwise FalsePart is returned.} function Iff(Condition: Boolean; TruePart, FalsePart: Pointer): Pointer; overload; {$IFDEF USE_INLINE}inline;{$ENDIF} { If Condition is True then TruePart is retured, otherwise FalsePart is returned.} function Iff(Condition: Boolean; const TruePart, FalsePart: Int64): Int64; overload; {$IFDEF USE_INLINE}inline;{$ENDIF} { If Condition is True then TruePart is retured, otherwise FalsePart is returned.} function IffFloat(Condition: Boolean; TruePart, FalsePart: Single): Single; {$IFDEF USE_INLINE}inline;{$ENDIF} { Swaps two Boolean values} procedure SwapValues(var A, B: Boolean); overload; { Swaps two Byte values} procedure SwapValues(var A, B: Byte); overload; { Swaps two Word values} procedure SwapValues(var A, B: Word); overload; { Swaps two LongInt values} procedure SwapValues(var A, B: LongInt); overload; { Swaps two Single values} procedure SwapValues(var A, B: Single); overload; { Swaps two LongInt values if necessary to ensure that Min <= Max.} procedure SwapMin(var Min, Max: LongInt); {$IFDEF USE_INLINE}inline;{$ENDIF} { This function returns True if running on little endian machine.} function IsLittleEndian: Boolean; {$IFDEF USE_INLINE}inline;{$ENDIF} { Swaps byte order of Word value.} function SwapEndianWord(Value: Word): Word; overload; {$IFDEF USE_INLINE}inline;{$ENDIF} { Swaps byte order of multiple Word values.} procedure SwapEndianWord(P: PWordArray; Count: LongInt); overload; { Swaps byte order of LongWord value.} function SwapEndianLongWord(Value: LongWord): LongWord; overload; {$IFDEF USE_INLINE}inline;{$ENDIF} { Swaps byte order of multiple LongWord values.} procedure SwapEndianLongWord(P: PLongWord; Count: LongInt); overload; { Calculates CRC32 for the given data.} procedure CalcCrc32(var Crc: LongWord; Data: Pointer; Size: LongInt); { Fills given memory with given Byte value. Size is size of buffer in bytes.} procedure FillMemoryByte(Data: Pointer; Size: LongInt; Value: Byte); { Fills given memory with given Word value. Size is size of buffer in bytes.} procedure FillMemoryWord(Data: Pointer; Size: LongInt; Value: Word); { Fills given memory with given LongWord value. Size is size of buffer in bytes.} procedure FillMemoryLongWord(Data: Pointer; Size: LongInt; Value: LongWord); { Fills given memory zeroes.} {$EXTERNALSYM ZeroMemory} // Conflicts with WinAPI ZeroMemory in C++ Builder procedure ZeroMemory(Data: Pointer; Size: Integer); {$IFDEF USE_INLINE}inline;{$ENDIF} { Returns how many mipmap levels can be created for image of given size.} function GetNumMipMapLevels(Width, Height: LongInt): LongInt; { Returns total number of levels of volume texture with given depth and mipmap count (this is not depth * mipmaps!).} function GetVolumeLevelCount(Depth, MipMaps: LongInt): LongInt; { Returns rectangle (X, Y, X + Width, Y + Height).} function BoundsToRect(X, Y, Width, Height: LongInt): TRect; overload; {$IFDEF USE_INLINE}inline;{$ENDIF} { Returns rectangle (R.Left, R.Top, R.Left + R.Right, R.Top + R.Bottom).} function BoundsToRect(const R: TRect): TRect; overload; {$IFDEF USE_INLINE}inline;{$ENDIF} { Returns rectangle (R.Left, R.Top, R.Right - R.Left, R.Bottom - R.Top).} function RectToBounds(const R: TRect): TRect; overload; {$IFDEF USE_INLINE}inline;{$ENDIF} { Clips given bounds to Clip rectangle.} procedure ClipRectBounds(var X, Y, Width, Height: LongInt; const Clip: TRect); { Clips given source bounds and dest position. It is used by various CopyRect functions that copy rect from one image to another. It handles clipping the same way as Win32 BitBlt function. } procedure ClipCopyBounds(var SrcX, SrcY, Width, Height, DstX, DstY: LongInt; SrcImageWidth, SrcImageHeight: LongInt; const DstClip: TRect); { Clips given source bounds and dest bounds. It is used by various StretchRect functions that stretch rectangle of pixels from one image to another. It handles clipping the same way as Win32 StretchBlt function. } procedure ClipStretchBounds(var SrcX, SrcY, SrcWidth, SrcHeight, DstX, DstY, DstWidth, DstHeight: LongInt; SrcImageWidth, SrcImageHeight: LongInt; const DstClip: TRect); { Scales one rectangle to fit into another. Proportions are preserved so it could be used for 'Stretch To Fit Window' image drawing for instance.} function ScaleRectToRect(const SourceRect, TargetRect: TRect): TRect; { Scales given size to fit into max size while keeping the original ascpect ration. Useful for calculating thumbnail dimensions etc.} function ScaleSizeToFit(const CurrentSize, MaxSize: TSize): TSize; { Returns width of given rect. Part of RTL in newer Delphi.} function RectWidth(const Rect: TRect): Integer; { Returns height of given rect. Part of RTL in newer Delphi.} function RectHeight(const Rect: TRect): Integer; { Returns True if R1 fits into R2.} function RectInRect(const R1, R2: TRect): Boolean; { Returns True if R1 and R2 intersects.} function RectIntersects(const R1, R2: TRect): Boolean; { Converts pixel size in micrometers to corrensponding DPI.} function PixelSizeToDpi(SizeInMicroMeters: Single): Single; { Converts DPI to corrensponding pixel size in micrometers.} function DpiToPixelSize(Dpi: Single): Single; function FloatRect(ALeft, ATop, ARight, ABottom: Single): TFloatRect; function FloatRectWidth(const R: TFloatRect): Single; function FloatRectHeight(const R: TFloatRect): Single; { Formats given message for usage in Exception.Create(..). Use only in except block - returned message contains message of last raised exception.} function FormatExceptMsg(const Msg: string; const Args: array of const): string; { Outputs debug message - shows message dialog in Windows and writes to console in Linux/Unix.} procedure DebugMsg(const Msg: string; const Args: array of const); implementation uses {$IF Defined(MSWINDOWS)} Windows; {$ELSEIF Defined(FPC)} Dos, BaseUnix, Unix; {$ELSEIF Defined(DELPHI)} Posix.SysTime; {$IFEND} var FloatFormatSettings: TFormatSettings; constructor ENotImplemented.Create; begin inherited Create('Not implemented'); end; procedure FreeAndNil(var Obj); var Temp: TObject; begin Temp := TObject(Obj); Pointer(Obj) := nil; Temp.Free; end; procedure FreeMemNil(var P); begin FreeMem(Pointer(P)); Pointer(P) := nil; end; procedure FreeMem(P: Pointer); begin if P <> nil then System.FreeMem(P); end; function GetExceptObject: Exception; begin Result := Exception(ExceptObject); end; {$IF Defined(MSWINDOWS)} var PerfFrequency: Int64; InvPerfFrequency: Single; function GetTimeMicroseconds: Int64; var Time: Int64; begin QueryPerformanceCounter(Time); Result := Round(1000000 * InvPerfFrequency * Time); end; {$ELSEIF Defined(DELPHI)} function GetTimeMicroseconds: Int64; var Time: TimeVal; begin Posix.SysTime.GetTimeOfDay(Time, nil); Result := Int64(Time.tv_sec) * 1000000 + Time.tv_usec; end; {$ELSEIF Defined(FPC)} function GetTimeMicroseconds: Int64; var TimeVal: TTimeVal; begin fpGetTimeOfDay(@TimeVal, nil); Result := Int64(TimeVal.tv_sec) * 1000000 + TimeVal.tv_usec; end; {$IFEND} function GetTimeMilliseconds: Int64; begin Result := GetTimeMicroseconds div 1000; end; function GetFileExt(const FileName: string): string; begin Result := ExtractFileExt(FileName); if Length(Result) > 1 then Delete(Result, 1, 1); end; function GetAppExe: string; {$IF Defined(MSWINDOWS)} var FileName: array[0..MAX_PATH] of Char; begin SetString(Result, FileName, Windows.GetModuleFileName(MainInstance, FileName, SizeOf(FileName))); {$ELSEIF Defined(DELPHI)} // Delphi non Win targets var FileName: array[0..1024] of Char; begin SetString(Result, FileName, System.GetModuleFileName(MainInstance, FileName, SizeOf(FileName))); {$ELSE} begin Result := ParamStr(0); {$IFEND} end; function GetAppDir: string; begin Result := ExtractFileDir(GetAppExe); end; function GetFileName(const FileName: string): string; var I: Integer; begin I := LastDelimiter('\/' + DriveDelim, FileName); Result := Copy(FileName, I + 1, MaxInt); end; function GetFileDir(const FileName: string): string; const Delims = '\/' + DriveDelim; var I: Integer; begin I := LastDelimiter(Delims, Filename); if (I > 1) and ((FileName[I] = Delims[1]) or (FileName[I] = Delims[2])) and (not IsDelimiter(Delims, FileName, I - 1)) then Dec(I); Result := Copy(FileName, 1, I); end; function StrMaskMatch(const Subject, Mask: string; CaseSensitive: Boolean): Boolean; var MaskLen, KeyLen : LongInt; function CharMatch(A, B: Char): Boolean; begin if CaseSensitive then Result := A = B else Result := AnsiUpperCase (A) = AnsiUpperCase (B); end; function MatchAt(MaskPos, KeyPos: LongInt): Boolean; begin while (MaskPos <= MaskLen) and (KeyPos <= KeyLen) do begin case Mask[MaskPos] of '?' : begin Inc(MaskPos); Inc(KeyPos); end; '*' : begin while (MaskPos <= MaskLen) and (Mask[MaskPos] = '*') do Inc(MaskPos); if MaskPos > MaskLen then begin Result := True; Exit; end; repeat if MatchAt(MaskPos, KeyPos) then begin Result := True; Exit; end; Inc(KeyPos); until KeyPos > KeyLen; Result := False; Exit; end; else if not CharMatch(Mask[MaskPos], Subject[KeyPos]) then begin Result := False; Exit; end else begin Inc(MaskPos); Inc(KeyPos); end; end; end; while (MaskPos <= MaskLen) and (AnsiChar(Mask[MaskPos]) in ['?', '*']) do Inc(MaskPos); if (MaskPos <= MaskLen) or (KeyPos <= KeyLen) then begin Result := False; Exit; end; Result := True; end; begin MaskLen := Length(Mask); KeyLen := Length(Subject); if MaskLen = 0 then begin Result := True; Exit; end; Result := MatchAt(1, 1); end; function BuildFileList(Path: string; Attr: LongInt; Files: TStrings; Options: TFileListOptions): Boolean; var FileMask: string; RootDir: string; Folders: TStringList; CurrentItem: LongInt; Counter: LongInt; LocAttr: LongInt; procedure BuildFolderList; var FindInfo: TSearchRec; Rslt: LongInt; begin Counter := Folders.Count - 1; CurrentItem := 0; while CurrentItem <= Counter do begin // Searching for subfolders Rslt := SysUtils.FindFirst(Folders[CurrentItem] + '*', faDirectory, FindInfo); try while Rslt = 0 do begin if (FindInfo.Name <> '.') and (FindInfo.Name <> '..') and (FindInfo.Attr and faDirectory = faDirectory) then Folders.Add(Folders[CurrentItem] + FindInfo.Name + PathDelim); Rslt := SysUtils.FindNext(FindInfo); end; finally SysUtils.FindClose(FindInfo); end; Counter := Folders.Count - 1; Inc(CurrentItem); end; end; procedure FillFileList(CurrentCounter: LongInt); var FindInfo: TSearchRec; Res: LongInt; CurrentFolder: string; begin CurrentFolder := Folders[CurrentCounter]; Res := SysUtils.FindFirst(CurrentFolder + FileMask, LocAttr, FindInfo); if flRelNames in Options then CurrentFolder := ExtractRelativePath(RootDir, CurrentFolder); try while Res = 0 do begin if (FindInfo.Name <> '.') and (FindInfo.Name <> '..') then begin if (flFullNames in Options) or (flRelNames in Options) then Files.Add(CurrentFolder + FindInfo.Name) else Files.Add(FindInfo.Name); end; Res := SysUtils.FindNext(FindInfo); end; finally SysUtils.FindClose(FindInfo); end; end; begin FileMask := ExtractFileName(Path); RootDir := ExtractFilePath(Path); Folders := TStringList.Create; Folders.Add(RootDir); Files.Clear; {$IFDEF DCC} {$WARN SYMBOL_PLATFORM OFF} {$ENDIF} if Attr = faAnyFile then LocAttr := faSysFile or faHidden or faArchive or faReadOnly else LocAttr := Attr; {$IFDEF DCC} {$WARN SYMBOL_PLATFORM ON} {$ENDIF} // Here's the recursive search for nested folders if flRecursive in Options then BuildFolderList; if Attr <> faDirectory then for Counter := 0 to Folders.Count - 1 do FillFileList(Counter) else Files.AddStrings(Folders); Folders.Free; Result := True; end; function PosEx(const SubStr, S: string; Offset: LongInt = 1): LongInt; var I, X: LongInt; Len, LenSubStr: LongInt; begin I := Offset; LenSubStr := Length(SubStr); Len := Length(S) - LenSubStr + 1; while I <= Len do begin if S[I] = SubStr[1] then begin X := 1; while (X < LenSubStr) and (S[I + X] = SubStr[X + 1]) do Inc(X); if (X = LenSubStr) then begin Result := I; Exit; end; end; Inc(I); end; Result := 0; end; function PosNoCase(const SubStr, S: string; Offset: LongInt): LongInt; begin Result := PosEx(AnsiLowerCase(SubStr), AnsiLowerCase(S), Offset); end; function StrToken(var S: string; Sep: Char): string; var I: LongInt; begin I := Pos(Sep, S); if I <> 0 then begin Result := Copy(S, 1, I - 1); Delete(S, 1, I); end else begin Result := S; S := ''; end; end; function StrTokenEnd(var S: string; Sep: Char): string; var I, J: LongInt; begin J := 0; I := Pos(Sep, S); while I <> 0 do begin J := I; I := PosEx(Sep, S, J + 1); end; if J <> 0 then begin Result := Copy(S, J + 1, MaxInt); Delete(S, J, MaxInt); end else begin Result := S; S := ''; end; end; procedure StrTokensToList(const S: string; Sep: Char; Tokens: TStrings); var Token, Str: string; begin Tokens.Clear; Str := S; while Str <> '' do begin Token := StrToken(Str, Sep); Tokens.Add(Token); end; end; function IntToStrFmt(const I: Int64): string; begin Result := Format('%.0n', [I * 1.0]); end; function FloatToStrFmt(const F: Double; Precision: Integer): string; begin Result := Format('%.' + IntToStr(Precision) + 'n', [F]); end; function GetFormatSettingsForFloats: TFormatSettings; begin Result := FloatFormatSettings; end; function ContainsAnySubStr(const S: string; const SubStrs: array of string): Boolean; var I: Integer; begin Result := False; for I := 0 to High(SubStrs) do begin Result := Pos(SubStrs[I], S) > 0; if Result then Exit; end; end; function SubString(const S: string; IdxStart, IdxEnd: Integer): string; begin Result := Copy(S, IdxStart, IdxEnd - IdxStart); end; function ClampInt(Number: LongInt; Min, Max: LongInt): LongInt; begin Result := Number; if Result < Min then Result := Min else if Result > Max then Result := Max; end; function ClampFloat(Number: Single; Min, Max: Single): Single; begin Result := Number; if Result < Min then Result := Min else if Result > Max then Result := Max; end; function ClampToByte(Value: LongInt): LongInt; begin Result := Value; if Result > 255 then Result := 255 else if Result < 0 then Result := 0; end; function ClampToWord(Value: LongInt): LongInt; begin Result := Value; if Result > 65535 then Result := 65535 else if Result < 0 then Result := 0; end; function IsPow2(Num: LongInt): Boolean; begin Result := (Num and -Num) = Num; end; function NextPow2(Num: LongInt): LongInt; begin Result := Num and -Num; while Result < Num do Result := Result shl 1; end; function Pow2Int(Exponent: LongInt): LongInt; begin Result := 1 shl Exponent; end; function Power(const Base, Exponent: Single): Single; begin if Exponent = 0.0 then Result := 1.0 else if (Base = 0.0) and (Exponent > 0.0) then Result := 0.0 else Result := Exp(Exponent * Ln(Base)); end; function Log2Int(X: LongInt): LongInt; begin case X of 1: Result := 0; 2: Result := 1; 4: Result := 2; 8: Result := 3; 16: Result := 4; 32: Result := 5; 64: Result := 6; 128: Result := 7; 256: Result := 8; 512: Result := 9; 1024: Result := 10; 2048: Result := 11; 4096: Result := 12; 8192: Result := 13; 16384: Result := 14; 32768: Result := 15; 65536: Result := 16; 131072: Result := 17; 262144: Result := 18; 524288: Result := 19; 1048576: Result := 20; 2097152: Result := 21; 4194304: Result := 22; 8388608: Result := 23; 16777216: Result := 24; 33554432: Result := 25; 67108864: Result := 26; 134217728: Result := 27; 268435456: Result := 28; 536870912: Result := 29; 1073741824: Result := 30; else Result := -1; end; end; function Log2(X: Single): Single; {$IFDEF USE_ASM} asm FLD1 FLD X FYL2X FWAIT end; {$ELSE} const Ln2: Single = 0.6931471; begin Result := Ln(X) / Ln2; end; {$ENDIF} function Log10(X: Single): Single; {$IFDEF USE_ASM} asm FLDLG2 FLD X FYL2X FWAIT end; {$ELSE} const Ln10: Single = 2.30258509299405; begin Result := Ln(X) / Ln10; end; {$ENDIF} function Floor(Value: Single): LongInt; begin Result := Trunc(Value); if Frac(Value) < 0.0 then Dec(Result); end; function Ceil(Value: Single): LongInt; begin Result := Trunc(Value); if Frac(Value) > 0.0 then Inc(Result); end; procedure Switch(var Value: Boolean); begin Value := not Value; end; function Iff(Condition: Boolean; TruePart, FalsePart: LongInt): LongInt; begin if Condition then Result := TruePart else Result := FalsePart; end; function IffUnsigned(Condition: Boolean; TruePart, FalsePart: LongWord): LongWord; begin if Condition then Result := TruePart else Result := FalsePart; end; function Iff(Condition, TruePart, FalsePart: Boolean): Boolean; begin if Condition then Result := TruePart else Result := FalsePart; end; function Iff(Condition: Boolean; const TruePart, FalsePart: string): string; begin if Condition then Result := TruePart else Result := FalsePart; end; function Iff(Condition: Boolean; TruePart, FalsePart: Char): Char; begin if Condition then Result := TruePart else Result := FalsePart; end; function Iff(Condition: Boolean; TruePart, FalsePart: Pointer): Pointer; begin if Condition then Result := TruePart else Result := FalsePart; end; function Iff(Condition: Boolean; const TruePart, FalsePart: Int64): Int64; begin if Condition then Result := TruePart else Result := FalsePart; end; function IffFloat(Condition: Boolean; TruePart, FalsePart: Single): Single; begin if Condition then Result := TruePart else Result := FalsePart; end; procedure SwapValues(var A, B: Boolean); var Tmp: Boolean; begin Tmp := A; A := B; B := Tmp; end; procedure SwapValues(var A, B: Byte); var Tmp: Byte; begin Tmp := A; A := B; B := Tmp; end; procedure SwapValues(var A, B: Word); var Tmp: Word; begin Tmp := A; A := B; B := Tmp; end; procedure SwapValues(var A, B: LongInt); var Tmp: LongInt; begin Tmp := A; A := B; B := Tmp; end; procedure SwapValues(var A, B: Single); var Tmp: Single; begin Tmp := A; A := B; B := Tmp; end; procedure SwapMin(var Min, Max: LongInt); var Tmp: LongInt; begin if Min > Max then begin Tmp := Min; Min := Max; Max := Tmp; end; end; function Min(A, B: LongInt): LongInt; begin if A < B then Result := A else Result := B; end; function MinFloat(A, B: Single): Single; begin if A < B then Result := A else Result := B; end; function Max(A, B: LongInt): LongInt; begin if A > B then Result := A else Result := B; end; function MaxFloat(A, B: Single): Single; begin if A > B then Result := A else Result := B; end; function MulDiv(Number, Numerator, Denominator: Word): Word; {$IF Defined(USE_ASM) and (not Defined(USE_INLINE))} asm MUL DX DIV CX end; {$ELSE} begin Result := Number * Numerator div Denominator; end; {$IFEND} function IsLittleEndian: Boolean; var W: Word; begin W := $00FF; Result := PByte(@W)^ = $FF; end; function SwapEndianWord(Value: Word): Word; {$IF Defined(USE_ASM) and (not Defined(USE_INLINE))} asm XCHG AH, AL end; {$ELSE} begin TWordRec(Result).Low := TWordRec(Value).High; TWordRec(Result).High := TWordRec(Value).Low; end; {$IFEND} procedure SwapEndianWord(P: PWordArray; Count: LongInt); {$IFDEF USE_ASM} asm @Loop: MOV CX, [EAX] XCHG CH, CL MOV [EAX], CX ADD EAX, 2 DEC EDX JNZ @Loop end; {$ELSE} var I: LongInt; Temp: Word; begin for I := 0 to Count - 1 do begin Temp := P[I]; TWordRec(P[I]).Low := TWordRec(Temp).High; TWordRec(P[I]).High := TWordRec(Temp).Low; end; end; {$ENDIF} function SwapEndianLongWord(Value: LongWord): LongWord; {$IF Defined(USE_ASM) and (not Defined(USE_INLINE))} asm BSWAP EAX end; {$ELSE} begin TLongWordRec(Result).Bytes[0] := TLongWordRec(Value).Bytes[3]; TLongWordRec(Result).Bytes[1] := TLongWordRec(Value).Bytes[2]; TLongWordRec(Result).Bytes[2] := TLongWordRec(Value).Bytes[1]; TLongWordRec(Result).Bytes[3] := TLongWordRec(Value).Bytes[0]; end; {$IFEND} procedure SwapEndianLongWord(P: PLongWord; Count: LongInt); {$IFDEF USE_ASM} asm @Loop: MOV ECX, [EAX] BSWAP ECX MOV [EAX], ECX ADD EAX, 4 DEC EDX JNZ @Loop end; {$ELSE} var I: LongInt; Temp: LongWord; begin for I := 0 to Count - 1 do begin Temp := PLongWordArray(P)[I]; TLongWordRec(PLongWordArray(P)[I]).Bytes[0] := TLongWordRec(Temp).Bytes[3]; TLongWordRec(PLongWordArray(P)[I]).Bytes[1] := TLongWordRec(Temp).Bytes[2]; TLongWordRec(PLongWordArray(P)[I]).Bytes[2] := TLongWordRec(Temp).Bytes[1]; TLongWordRec(PLongWordArray(P)[I]).Bytes[3] := TLongWordRec(Temp).Bytes[0]; end; end; {$ENDIF} type TCrcTable = array[Byte] of LongWord; var CrcTable: TCrcTable; procedure InitCrcTable; const Polynom = $EDB88320; var I, J: LongInt; C: LongWord; begin for I := 0 to 255 do begin C := I; for J := 0 to 7 do begin if (C and $01) <> 0 then C := Polynom xor (C shr 1) else C := C shr 1; end; CrcTable[I] := C; end; end; procedure CalcCrc32(var Crc: LongWord; Data: Pointer; Size: LongInt); var I: LongInt; B: PByte; begin B := Data; for I := 0 to Size - 1 do begin Crc := (Crc shr 8) xor CrcTable[B^ xor Byte(Crc)]; Inc(B); end end; procedure FillMemoryByte(Data: Pointer; Size: LongInt; Value: Byte); {$IFDEF USE_ASM} asm PUSH EDI MOV EDI, EAX MOV EAX, ECX MOV AH, AL MOV CX, AX SHL EAX, 16 MOV AX, CX MOV ECX, EDX SAR ECX, 2 JS @Exit REP STOSD MOV ECX, EDX AND ECX, 3 REP STOSB POP EDI @Exit: end; {$ELSE} begin FillChar(Data^, Size, Value); end; {$ENDIF} procedure FillMemoryWord(Data: Pointer; Size: LongInt; Value: Word); {$IFDEF USE_ASM} asm PUSH EDI PUSH EBX MOV EBX, EDX MOV EDI, EAX MOV EAX, ECX MOV CX, AX SHL EAX, 16 MOV AX, CX MOV ECX, EDX SHR ECX, 2 JZ @Word REP STOSD @Word: MOV ECX, EBX AND ECX, 2 JZ @Byte MOV [EDI], AX ADD EDI, 2 @Byte: MOV ECX, EBX AND ECX, 1 JZ @Exit MOV [EDI], AL @Exit: POP EBX POP EDI end; {$ELSE} var I, V: LongWord; begin V := Value * $10000 + Value; for I := 0 to Size div 4 - 1 do PLongWordArray(Data)[I] := V; case Size mod 4 of 1: PByteArray(Data)[Size - 1] := Lo(Value); 2: PWordArray(Data)[Size div 2] := Value; 3: begin PWordArray(Data)[Size div 2 - 1] := Value; PByteArray(Data)[Size - 1] := Lo(Value); end; end; end; {$ENDIF} procedure FillMemoryLongWord(Data: Pointer; Size: LongInt; Value: LongWord); {$IFDEF USE_ASM} asm PUSH EDI PUSH EBX MOV EBX, EDX MOV EDI, EAX MOV EAX, ECX MOV ECX, EDX SHR ECX, 2 JZ @Word REP STOSD @Word: MOV ECX, EBX AND ECX, 2 JZ @Byte MOV [EDI], AX ADD EDI, 2 @Byte: MOV ECX, EBX AND ECX, 1 JZ @Exit MOV [EDI], AL @Exit: POP EBX POP EDI end; {$ELSE} var I: LongInt; begin for I := 0 to Size div 4 - 1 do PLongWordArray(Data)[I] := Value; case Size mod 4 of 1: PByteArray(Data)[Size - 1] := TLongWordRec(Value).Bytes[0]; 2: PWordArray(Data)[Size div 2] := TLongWordRec(Value).Words[0]; 3: begin PWordArray(Data)[Size div 2 - 1] := TLongWordRec(Value).Words[0]; PByteArray(Data)[Size - 1] := TLongWordRec(Value).Bytes[0]; end; end; end; {$ENDIF} procedure ZeroMemory(Data: Pointer; Size: Integer); begin FillMemoryByte(Data, Size, 0); end; function GetNumMipMapLevels(Width, Height: LongInt): LongInt; begin Result := 0; if (Width > 0) and (Height > 0) then begin Result := 1; while (Width <> 1) or (Height <> 1) do begin Width := Width div 2; Height := Height div 2; if Width < 1 then Width := 1; if Height < 1 then Height := 1; Inc(Result); end; end; end; function GetVolumeLevelCount(Depth, MipMaps: LongInt): LongInt; var I: LongInt; begin Result := Depth; for I := 1 to MipMaps - 1 do Inc(Result, ClampInt(Depth shr I, 1, Depth)); end; function BoundsToRect(X, Y, Width, Height: LongInt): TRect; begin Result.Left := X; Result.Top := Y; Result.Right := X + Width; Result.Bottom := Y + Height; end; function BoundsToRect(const R: TRect): TRect; begin Result.Left := R.Left; Result.Top := R.Top; Result.Right := R.Left + R.Right; Result.Bottom := R.Top + R.Bottom; end; function RectToBounds(const R: TRect): TRect; begin Result.Left := R.Left; Result.Top := R.Top; Result.Right := R.Right - R.Left; Result.Bottom := R.Bottom - R.Top; end; procedure ClipRectBounds(var X, Y, Width, Height: LongInt; const Clip: TRect); procedure ClipDim(var AStart, ALength: LongInt; ClipMin, ClipMax: LongInt); begin if AStart < ClipMin then begin ALength := ALength - (ClipMin - AStart); AStart := ClipMin; end; if AStart + ALength > ClipMax then ALength := Max(0, ClipMax - AStart); end; begin ClipDim(X, Width, Clip.Left, Clip.Right); ClipDim(Y, Height, Clip.Top, Clip.Bottom); end; procedure ClipCopyBounds(var SrcX, SrcY, Width, Height, DstX, DstY: LongInt; SrcImageWidth, SrcImageHeight: LongInt; const DstClip: TRect); procedure ClipDim(var SrcPos, DstPos, Size: LongInt; SrcClipMax, DstClipMin, DstClipMax: LongInt); var OldDstPos: LongInt; Diff: LongInt; begin OldDstPos := Iff(DstPos < 0, DstPos, 0); if DstPos < DstClipMin then begin Diff := DstClipMin - DstPos; Size := Size - Diff; SrcPos := SrcPos + Diff; DstPos := DstClipMin; end; if SrcPos < 0 then begin Size := Size + SrcPos - OldDstPos; DstPos := DstPos - SrcPos + OldDstPos; SrcPos := 0; end; if SrcPos + Size > SrcClipMax then Size := SrcClipMax - SrcPos; if DstPos + Size > DstClipMax then Size := DstClipMax - DstPos; end; begin ClipDim(SrcX, DstX, Width, SrcImageWidth, DstClip.Left, DstClip.Right); ClipDim(SrcY, DstY, Height, SrcImageHeight, DstClip.Top, DstClip.Bottom); end; procedure ClipStretchBounds(var SrcX, SrcY, SrcWidth, SrcHeight, DstX, DstY, DstWidth, DstHeight: LongInt; SrcImageWidth, SrcImageHeight: LongInt; const DstClip: TRect); procedure ClipDim(var SrcPos, DstPos, SrcSize, DstSize: LongInt; SrcClipMax, DstClipMin, DstClipMax: LongInt); var OldSize: LongInt; Diff: LongInt; Scale: Single; begin Scale := DstSize / SrcSize; if DstPos < DstClipMin then begin Diff := DstClipMin - DstPos; DstSize := DstSize - Diff; SrcPos := SrcPos + Round(Diff / Scale); SrcSize := SrcSize - Round(Diff / Scale); DstPos := DstClipMin; end; if SrcPos < 0 then begin SrcSize := SrcSize + SrcPos; DstPos := DstPos - Round(SrcPos * Scale); DstSize := DstSize + Round(SrcPos * Scale); SrcPos := 0; end; if SrcPos + SrcSize > SrcClipMax then begin OldSize := SrcSize; SrcSize := SrcClipMax - SrcPos; DstSize := Round(DstSize * (SrcSize / OldSize)); end; if DstPos + DstSize > DstClipMax then begin OldSize := DstSize; DstSize := DstClipMax - DstPos; SrcSize := Round(SrcSize * (DstSize / OldSize)); end; end; begin ClipDim(SrcX, DstX, SrcWidth, DstWidth, SrcImageWidth, DstClip.Left, DstClip.Right); ClipDim(SrcY, DstY, SrcHeight, DstHeight, SrcImageHeight, DstClip.Top, DstClip.Bottom); end; function ScaleRectToRect(const SourceRect, TargetRect: TRect): TRect; var SourceWidth: LongInt; SourceHeight: LongInt; TargetWidth: LongInt; TargetHeight: LongInt; ScaledWidth: LongInt; ScaledHeight: LongInt; begin SourceWidth := SourceRect.Right - SourceRect.Left; SourceHeight := SourceRect.Bottom - SourceRect.Top; TargetWidth := TargetRect.Right - TargetRect.Left; TargetHeight := TargetRect.Bottom - TargetRect.Top; if SourceWidth * TargetHeight < SourceHeight * TargetWidth then begin ScaledWidth := (SourceWidth * TargetHeight) div SourceHeight; Result := BoundsToRect(TargetRect.Left + ((TargetWidth - ScaledWidth) div 2), TargetRect.Top, ScaledWidth, TargetHeight); end else begin ScaledHeight := (SourceHeight * TargetWidth) div SourceWidth; Result := BoundsToRect(TargetRect.Left, TargetRect.Top + ((TargetHeight - ScaledHeight) div 2), TargetWidth, ScaledHeight); end; end; function ScaleSizeToFit(const CurrentSize, MaxSize: Types.TSize): Types.TSize; var SR, TR, ScaledRect: TRect; begin SR := Types.Rect(0, 0, CurrentSize.CX, CurrentSize.CY); TR := Types.Rect(0, 0, MaxSize.CX, MaxSize.CY); ScaledRect := ScaleRectToRect(SR, TR); Result.CX := ScaledRect.Right - ScaledRect.Left; Result.CY := ScaledRect.Bottom - ScaledRect.Top; end; function RectWidth(const Rect: TRect): Integer; begin Result := Rect.Right - Rect.Left; end; function RectHeight(const Rect: TRect): Integer; begin Result := Rect.Bottom - Rect.Top; end; function RectInRect(const R1, R2: TRect): Boolean; begin Result:= (R1.Left >= R2.Left) and (R1.Top >= R2.Top) and (R1.Right <= R2.Right) and (R1.Bottom <= R2.Bottom); end; function RectIntersects(const R1, R2: TRect): Boolean; begin Result := not (R1.Left > R2.Right) and not (R1.Top > R2.Bottom) and not (R1.Right < R2.Left) and not (R1.Bottom < R2.Top); end; function PixelSizeToDpi(SizeInMicroMeters: Single): Single; begin Result := 25400 / SizeInMicroMeters; end; function DpiToPixelSize(Dpi: Single): Single; begin Result := 1e03 / (Dpi / 25.4); end; function FloatRect(ALeft, ATop, ARight, ABottom: Single): TFloatRect; begin with Result do begin Left := ALeft; Top := ATop; Right := ARight; Bottom := ABottom; end; end; function FloatRectWidth(const R: TFloatRect): Single; begin Result := R.Right - R.Left; end; function FloatRectHeight(const R: TFloatRect): Single; begin Result := R.Bottom - R.Top; end; function FormatExceptMsg(const Msg: string; const Args: array of const): string; begin Result := Format(Msg + SLineBreak + 'Message: ' + GetExceptObject.Message, Args); end; procedure DebugMsg(const Msg: string; const Args: array of const); var FmtMsg: string; begin FmtMsg := Format(Msg, Args); {$IFDEF MSWINDOWS} if IsConsole then WriteLn('DebugMsg: ' + FmtMsg) else MessageBox(GetActiveWindow, PChar(FmtMsg), 'DebugMsg', MB_OK); {$ENDIF} {$IFDEF UNIX} WriteLn('DebugMsg: ' + FmtMsg); {$ENDIF} {$IFDEF MSDOS} WriteLn('DebugMsg: ' + FmtMsg); {$ENDIF} end; initialization InitCrcTable; {$IFDEF MSWINDOWS} QueryPerformanceFrequency(PerfFrequency); InvPerfFrequency := 1.0 / PerfFrequency; {$ENDIF} {$IF Defined(DELPHI)} {$IF CompilerVersion >= 23} FloatFormatSettings := TFormatSettings.Create('en-US'); {$ELSE} GetLocaleFormatSettings(1033, FloatFormatSettings); {$IFEND} {$ELSE FPC} FloatFormatSettings := DefaultFormatSettings; FloatFormatSettings.DecimalSeparator := '.'; {$IFEND} { File Notes: -- TODOS ---------------------------------------------------- - nothing now -- 0.77.1 ---------------------------------------------------- - Added GetFileName, GetFileDir, RectWidth, RectHeight function. - Added ScaleSizeToFit function. - Added ZeroMemory and SwapValues for Booleans. - Added Substring function. - Renamed MatchFileNameMask to StrMaskMatch (it's for general use not just filenames). - Delphi XE2 new targets (Win64, OSX32) compatibility changes. - Added GetFormatSettingsForFloats function. -- 0.26.5 Changes/Bug Fixes ----------------------------------- - Added Log10 function. - Added TFloatRect type and helper functions FloatRect, FloatRectWidth, FloatRectHeight. - Added string function ContainsAnySubStr. - Added functions PixelSizeToDpi, DpiToPixelSize. -- 0.26.1 Changes/Bug Fixes ----------------------------------- - Some formatting changes. - Changed some string functions to work with localized strings. - ASM version of PosEx had bugs, removed it. - Added StrTokensToList function. -- 0.25.0 Changes/Bug Fixes ----------------------------------- - Fixed error in ClipCopyBounds which was causing ... bad clipping! -- 0.24.3 Changes/Bug Fixes ----------------------------------- - Added GetTimeMilliseconds function. - Added IntToStrFmt and FloatToStrFmt helper functions. -- 0.23 Changes/Bug Fixes ----------------------------------- - Added RectInRect and RectIntersects functions - Added some string utils: StrToken, StrTokenEnd, PosEx, PosNoCase. - Moved BuildFileList here from DemoUtils. -- 0.21 Changes/Bug Fixes ----------------------------------- - Moved GetVolumeLevelCount from ImagingDds here. - Renamed FillMemory to FillMemoryByte to avoid name collision in C++ Builder. - Added Iff function for Char, Pointer, and Int64 types. - Added IsLittleEndian function. - Added array types for TWordRec, TLongWordRec, and TInt64Rec. - Added MatchFileNameMask function. -- 0.19 Changes/Bug Fixes ----------------------------------- - added ScaleRectToRect (thanks to Paul Michell) - added BoundsToRect, ClipBounds, ClipCopyBounds, ClipStretchBounds functions - added MulDiv function - FreeAndNil is not inline anymore - caused AV in one program -- 0.17 Changes/Bug Fixes ----------------------------------- - GetAppExe didn't return absolute path in FreeBSD, fixed - added debug message output - fixed Unix compatibility issues (thanks to Ales Katona). Imaging now compiles in FreeBSD and maybe in other Unixes as well. -- 0.15 Changes/Bug Fixes ----------------------------------- - added some new utility functions -- 0.13 Changes/Bug Fixes ----------------------------------- - added many new utility functions - minor change in SwapEndian to avoid range check error } end. ================================================ FILE: lib/Imaging/ZLib/dzlib.pas ================================================ {*******************************************************} { } { Delphi Supplemental Components } { ZLIB Data Compression Interface Unit } { } { Copyright (c) 1997 Borland International } { Copyright (c) 1998 Jacques Nomssi Nzali } { } {*******************************************************} { Modified for Vampyre Imaging Library by Marek Mauder http://imaginglib.sourceforge.net You can choose which pascal zlib implementation will be used. IMPASZLIB and FPCPASZLIB are translations of zlib to pascal so they don't need any *.obj files. The others are interfaces to *.obj files (Windows) or *.so libraries (Linux). Default implementation is IMPASZLIB because it can be compiled by all supported compilers and works on all supported platforms. I usually use implementation with the fastest decompression when building release Win32 binaries. FPCPASZLIB is useful for Lazarus applications. FPC's zlib is linked to exe by default so there is no need to link additional (and almost identical) IMPASZLIB. There is a small speed comparison table of some of the supported implementations (TGA image 28311570 bytes, compression level = 6, Delphi 9, Win32, Athlon XP 1900). ZLib version Decompression Compression Comp. Size IMPASZLIB | 1.1.2 | 824 ms | 4 280 ms | 18 760 133 B ZLIBEX | 1.2.2 | 710 ms | 1 590 ms* | 19 056 621 B DELPHIZLIB | 1.0.4 | 976 ms | 9 190 ms | 18 365 562 B ZLIBPAS | 1.2.3 | 680 ms | 3 790 ms | 18 365 387 B * obj files are compiled with compression level hardcoded to 1 (fastest) } unit dzlib; {$I ImagingOptions.inc} interface {$DEFINE IMPASZLIB} { $DEFINE ZLIBPAS} { $DEFINE FPCPASZLIB} { $DEFINE ZLIBEX} { $DEFINE DELPHIZLIB} { Automatically use FPC's PasZLib when compiling with FPC.} {$IFDEF FPC} {$UNDEF IMPASZLIB} {$DEFINE FPCPASZLIB} {$ENDIF} uses {$IF Defined(IMPASZLIB)} { Use paszlib modified by me for Delphi and FPC } imzdeflate, imzinflate, impaszlib, {$ELSEIF Defined(FPCPASZLIB)} { Use FPC's paszlib } zbase, paszlib, {$ELSEIF Defined(ZLIBPAS)} { Pascal interface to ZLib shipped with ZLib C source } zlibpas, {$ELSEIF Defined(ZLIBEX)} { Use ZlibEx unit } ZLibEx, {$ELSEIF Defined(DELPHIZLIB)} { Use ZLib unit shipped with Delphi } ZLib, {$IFEND} ImagingTypes, SysUtils, Classes; {$IF Defined(IMPASZLIB) or Defined(FPCPASZLIB) or Defined(ZLIBPAS)} type TZStreamRec = z_stream; {$IFEND} const Z_NO_FLUSH = 0; Z_PARTIAL_FLUSH = 1; Z_SYNC_FLUSH = 2; Z_FULL_FLUSH = 3; Z_FINISH = 4; Z_OK = 0; Z_STREAM_END = 1; Z_NEED_DICT = 2; Z_ERRNO = -1; Z_STREAM_ERROR = -2; Z_DATA_ERROR = -3; Z_MEM_ERROR = -4; Z_BUF_ERROR = -5; Z_VERSION_ERROR = -6; Z_NO_COMPRESSION = 0; Z_BEST_SPEED = 1; Z_BEST_COMPRESSION = 9; Z_DEFAULT_COMPRESSION = -1; Z_FILTERED = 1; Z_HUFFMAN_ONLY = 2; Z_RLE = 3; Z_DEFAULT_STRATEGY = 0; Z_BINARY = 0; Z_ASCII = 1; Z_UNKNOWN = 2; Z_DEFLATED = 8; type { Abstract ancestor class } TCustomZlibStream = class(TStream) private FStrm: TStream; FStrmPos: Integer; FOnProgress: TNotifyEvent; FZRec: TZStreamRec; FBuffer: array [Word] of Byte; protected procedure Progress(Sender: TObject); dynamic; property OnProgress: TNotifyEvent read FOnProgress write FOnProgress; constructor Create(Strm: TStream); end; { TCompressionStream compresses data on the fly as data is written to it, and stores the compressed data to another stream. TCompressionStream is write-only and strictly sequential. Reading from the stream will raise an exception. Using Seek to move the stream pointer will raise an exception. Output data is cached internally, written to the output stream only when the internal output buffer is full. All pending output data is flushed when the stream is destroyed. The Position property returns the number of uncompressed bytes of data that have been written to the stream so far. CompressionRate returns the on-the-fly percentage by which the original data has been compressed: (1 - (CompressedBytes / UncompressedBytes)) * 100 If raw data size = 100 and compressed data size = 25, the CompressionRate is 75% The OnProgress event is called each time the output buffer is filled and written to the output stream. This is useful for updating a progress indicator when you are writing a large chunk of data to the compression stream in a single call.} TCompressionLevel = (clNone, clFastest, clDefault, clMax); TCompressionStream = class(TCustomZlibStream) private function GetCompressionRate: Single; public constructor Create(CompressionLevel: TCompressionLevel; Dest: TStream); destructor Destroy; override; function Read(var Buffer; Count: Longint): Longint; override; function Write(const Buffer; Count: Longint): Longint; override; function Seek(Offset: Longint; Origin: Word): Longint; override; property CompressionRate: Single read GetCompressionRate; property OnProgress; end; { TDecompressionStream decompresses data on the fly as data is read from it. Compressed data comes from a separate source stream. TDecompressionStream is read-only and unidirectional; you can seek forward in the stream, but not backwards. The special case of setting the stream position to zero is allowed. Seeking forward decompresses data until the requested position in the uncompressed data has been reached. Seeking backwards, seeking relative to the end of the stream, requesting the size of the stream, and writing to the stream will raise an exception. The Position property returns the number of bytes of uncompressed data that have been read from the stream so far. The OnProgress event is called each time the internal input buffer of compressed data is exhausted and the next block is read from the input stream. This is useful for updating a progress indicator when you are reading a large chunk of data from the decompression stream in a single call.} TDecompressionStream = class(TCustomZlibStream) public constructor Create(Source: TStream); destructor Destroy; override; function Read(var Buffer; Count: Longint): Longint; override; function Write(const Buffer; Count: Longint): Longint; override; function Seek(Offset: Longint; Origin: Word): Longint; override; property OnProgress; end; { CompressBuf compresses data, buffer to buffer, in one call. In: InBuf = ptr to compressed data InBytes = number of bytes in InBuf Out: OutBuf = ptr to newly allocated buffer containing decompressed data OutBytes = number of bytes in OutBuf } procedure CompressBuf(const InBuf: Pointer; InBytes: Integer; var OutBuf: Pointer; var OutBytes: Integer; CompressLevel: Integer = Z_DEFAULT_COMPRESSION; CompressStrategy: Integer = Z_DEFAULT_STRATEGY); { DecompressBuf decompresses data, buffer to buffer, in one call. In: InBuf = ptr to compressed data InBytes = number of bytes in InBuf OutEstimate = zero, or est. size of the decompressed data Out: OutBuf = ptr to newly allocated buffer containing decompressed data OutBytes = number of bytes in OutBuf } procedure DecompressBuf(const InBuf: Pointer; InBytes: Integer; OutEstimate: Integer; var OutBuf: Pointer; var OutBytes: Integer); type EZlibError = class(Exception); ECompressionError = class(EZlibError); EDecompressionError = class(EZlibError); implementation const ZErrorMessages: array[0..9] of PAnsiChar = ( 'need dictionary', // Z_NEED_DICT (2) 'stream end', // Z_STREAM_END (1) '', // Z_OK (0) 'file error', // Z_ERRNO (-1) 'stream error', // Z_STREAM_ERROR (-2) 'data error', // Z_DATA_ERROR (-3) 'insufficient memory', // Z_MEM_ERROR (-4) 'buffer error', // Z_BUF_ERROR (-5) 'incompatible version', // Z_VERSION_ERROR (-6) ''); function zlibAllocMem(AppData: Pointer; Items, Size: Cardinal): Pointer; begin GetMem(Result, Items*Size); end; procedure zlibFreeMem(AppData, Block: Pointer); begin FreeMem(Block); end; function CCheck(code: Integer): Integer; begin Result := code; if code < 0 then raise ECompressionError.Create('zlib: ' + ZErrorMessages[2 - code]); end; function DCheck(code: Integer): Integer; begin Result := code; if code < 0 then raise EDecompressionError.Create('zlib: ' + ZErrorMessages[2 - code]); end; procedure CompressBuf(const InBuf: Pointer; InBytes: Integer; var OutBuf: Pointer; var OutBytes: Integer; CompressLevel, CompressStrategy: Integer); var strm: TZStreamRec; P: Pointer; begin FillChar(strm, sizeof(strm), 0); {$IFNDEF FPCPASZLIB} strm.zalloc := @zlibAllocMem; strm.zfree := @zlibFreeMem; {$ENDIF} OutBytes := ((InBytes + (InBytes div 10) + 12) + 255) and not 255; GetMem(OutBuf, OutBytes); try strm.next_in := InBuf; strm.avail_in := InBytes; strm.next_out := OutBuf; strm.avail_out := OutBytes; CCheck(deflateInit2(strm, CompressLevel, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, CompressStrategy)); try while CCheck(deflate(strm, Z_FINISH)) <> Z_STREAM_END do begin P := OutBuf; Inc(OutBytes, 256); ReallocMem(OutBuf, OutBytes); strm.next_out := Pointer(PtrUInt(OutBuf) + (PtrUInt(strm.next_out) - PtrUInt(P))); strm.avail_out := 256; end; finally CCheck(deflateEnd(strm)); end; ReallocMem(OutBuf, strm.total_out); OutBytes := strm.total_out; except zlibFreeMem(nil, OutBuf); raise end; end; procedure DecompressBuf(const InBuf: Pointer; InBytes: Integer; OutEstimate: Integer; var OutBuf: Pointer; var OutBytes: Integer); var strm: TZStreamRec; P: Pointer; BufInc: Integer; begin FillChar(strm, sizeof(strm), 0); {$IFNDEF FPCPASZLIB} strm.zalloc := @zlibAllocMem; strm.zfree := @zlibFreeMem; {$ENDIF} BufInc := (InBytes + 255) and not 255; if OutEstimate = 0 then OutBytes := BufInc else OutBytes := OutEstimate; GetMem(OutBuf, OutBytes); try strm.next_in := InBuf; strm.avail_in := InBytes; strm.next_out := OutBuf; strm.avail_out := OutBytes; DCheck(inflateInit_(strm, zlib_version, sizeof(strm))); try while DCheck(inflate(strm, Z_NO_FLUSH)) <> Z_STREAM_END do begin P := OutBuf; Inc(OutBytes, BufInc); ReallocMem(OutBuf, OutBytes); strm.next_out := Pointer(PtrUInt(OutBuf) + (PtrUInt(strm.next_out) - PtrUInt(P))); strm.avail_out := BufInc; end; finally DCheck(inflateEnd(strm)); end; ReallocMem(OutBuf, strm.total_out); OutBytes := strm.total_out; except zlibFreeMem(nil, OutBuf); raise end; end; { TCustomZlibStream } constructor TCustomZLibStream.Create(Strm: TStream); begin inherited Create; FStrm := Strm; FStrmPos := Strm.Position; {$IFNDEF FPCPASZLIB} FZRec.zalloc := @zlibAllocMem; FZRec.zfree := @zlibFreeMem; {$ENDIF} end; procedure TCustomZLibStream.Progress(Sender: TObject); begin if Assigned(FOnProgress) then FOnProgress(Sender); end; { TCompressionStream } constructor TCompressionStream.Create(CompressionLevel: TCompressionLevel; Dest: TStream); const Levels: array [TCompressionLevel] of ShortInt = (Z_NO_COMPRESSION, Z_BEST_SPEED, Z_DEFAULT_COMPRESSION, Z_BEST_COMPRESSION); begin inherited Create(Dest); FZRec.next_out := @FBuffer; FZRec.avail_out := sizeof(FBuffer); CCheck(deflateInit_(FZRec, Levels[CompressionLevel], zlib_version, sizeof(FZRec))); end; destructor TCompressionStream.Destroy; begin FZRec.next_in := nil; FZRec.avail_in := 0; try if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos; while (CCheck(deflate(FZRec, Z_FINISH)) <> Z_STREAM_END) and (FZRec.avail_out = 0) do begin FStrm.WriteBuffer(FBuffer, sizeof(FBuffer)); FZRec.next_out := @FBuffer; FZRec.avail_out := sizeof(FBuffer); end; if FZRec.avail_out < sizeof(FBuffer) then FStrm.WriteBuffer(FBuffer, sizeof(FBuffer) - FZRec.avail_out); finally deflateEnd(FZRec); end; inherited Destroy; end; function TCompressionStream.Read(var Buffer; Count: Longint): Longint; begin raise ECompressionError.Create('Invalid stream operation'); end; function TCompressionStream.Write(const Buffer; Count: Longint): Longint; begin FZRec.next_in := @Buffer; FZRec.avail_in := Count; if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos; while (FZRec.avail_in > 0) do begin CCheck(deflate(FZRec, 0)); if FZRec.avail_out = 0 then begin FStrm.WriteBuffer(FBuffer, sizeof(FBuffer)); FZRec.next_out := @FBuffer; FZRec.avail_out := sizeof(FBuffer); FStrmPos := FStrm.Position; Progress(Self); end; end; Result := Count; end; function TCompressionStream.Seek(Offset: Longint; Origin: Word): Longint; begin if (Offset = 0) and (Origin = soFromCurrent) then Result := FZRec.total_in else raise ECompressionError.Create('Invalid stream operation'); end; function TCompressionStream.GetCompressionRate: Single; begin if FZRec.total_in = 0 then Result := 0 else Result := (1.0 - (FZRec.total_out / FZRec.total_in)) * 100.0; end; { TDecompressionStream } constructor TDecompressionStream.Create(Source: TStream); begin inherited Create(Source); FZRec.next_in := @FBuffer; FZRec.avail_in := 0; DCheck(inflateInit_(FZRec, zlib_version, sizeof(FZRec))); end; destructor TDecompressionStream.Destroy; begin inflateEnd(FZRec); inherited Destroy; end; function TDecompressionStream.Read(var Buffer; Count: Longint): Longint; begin FZRec.next_out := @Buffer; FZRec.avail_out := Count; if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos; while (FZRec.avail_out > 0) do begin if FZRec.avail_in = 0 then begin FZRec.avail_in := FStrm.Read(FBuffer, sizeof(FBuffer)); if FZRec.avail_in = 0 then begin Result := Count - Integer(FZRec.avail_out); Exit; end; FZRec.next_in := @FBuffer; FStrmPos := FStrm.Position; Progress(Self); end; CCheck(inflate(FZRec, 0)); end; Result := Count; end; function TDecompressionStream.Write(const Buffer; Count: Longint): Longint; begin raise EDecompressionError.Create('Invalid stream operation'); end; function TDecompressionStream.Seek(Offset: Longint; Origin: Word): Longint; var I: Integer; Buf: array [0..4095] of Byte; begin if (Offset = 0) and (Origin = soFromBeginning) then begin DCheck(inflateReset(FZRec)); FZRec.next_in := @FBuffer; FZRec.avail_in := 0; FStrm.Position := 0; FStrmPos := 0; end else if ( (Offset >= 0) and (Origin = soFromCurrent)) or ( ((Offset - Integer(FZRec.total_out)) > 0) and (Origin = soFromBeginning)) then begin if Origin = soFromBeginning then Dec(Offset, FZRec.total_out); if Offset > 0 then begin for I := 1 to Offset div sizeof(Buf) do ReadBuffer(Buf, sizeof(Buf)); ReadBuffer(Buf, Offset mod sizeof(Buf)); end; end else raise EDecompressionError.Create('Invalid stream operation'); Result := FZRec.total_out; end; end. ================================================ FILE: lib/Imaging/ZLib/imadler.pas ================================================ Unit imadler; { adler32.c -- compute the Adler-32 checksum of a data stream Copyright (C) 1995-1998 Mark Adler Pascal tranlastion Copyright (C) 1998 by Jacques Nomssi Nzali For conditions of distribution and use, see copyright notice in readme.txt } interface {$I imzconf.inc} uses imzutil; function adler32(adler : uLong; buf : pBytef; len : uInt) : uLong; { Update a running Adler-32 checksum with the bytes buf[0..len-1] and return the updated checksum. If buf is NIL, this function returns the required initial value for the checksum. An Adler-32 checksum is almost as reliable as a CRC32 but can be computed much faster. Usage example: var adler : uLong; begin adler := adler32(0, Z_NULL, 0); while (read_buffer(buffer, length) <> EOF) do adler := adler32(adler, buffer, length); if (adler <> original_adler) then error(); end; } implementation const BASE = uLong(65521); { largest prime smaller than 65536 } {NMAX = 5552; original code with unsigned 32 bit integer } { NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 } NMAX = 3854; { code with signed 32 bit integer } { NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^31-1 } { The penalty is the time loss in the extra MOD-calls. } { ========================================================================= } function adler32(adler : uLong; buf : pBytef; len : uInt) : uLong; var s1, s2 : uLong; k : int; begin s1 := adler and $ffff; s2 := (adler shr 16) and $ffff; if not Assigned(buf) then begin adler32 := uLong(1); exit; end; while (len > 0) do begin if len < NMAX then k := len else k := NMAX; Dec(len, k); { while (k >= 16) do begin DO16(buf); Inc(buf, 16); Dec(k, 16); end; if (k <> 0) then repeat Inc(s1, buf^); Inc(puf); Inc(s2, s1); Dec(k); until (k = 0); } while (k > 0) do begin Inc(s1, buf^); Inc(s2, s1); Inc(buf); Dec(k); end; s1 := s1 mod BASE; s2 := s2 mod BASE; end; adler32 := (s2 shl 16) or s1; end; { #define DO1(buf,i) begin Inc(s1, buf[i]); Inc(s2, s1); end; #define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); #define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); #define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); #define DO16(buf) DO8(buf,0); DO8(buf,8); } end. ================================================ FILE: lib/Imaging/ZLib/iminfblock.pas ================================================ Unit iminfblock; { infblock.h and infblock.c -- interpret and process block types to last block Copyright (C) 1995-1998 Mark Adler Pascal tranlastion Copyright (C) 1998 by Jacques Nomssi Nzali For conditions of distribution and use, see copyright notice in readme.txt } interface {$I imzconf.inc} uses {$IFDEF DEBUG} SysUtils, strutils, {$ENDIF} imzutil, impaszlib; function inflate_blocks_new(var z : z_stream; c : check_func; { check function } w : uInt { window size } ) : pInflate_blocks_state; function inflate_blocks (var s : inflate_blocks_state; var z : z_stream; r : int { initial return code } ) : int; procedure inflate_blocks_reset (var s : inflate_blocks_state; var z : z_stream; c : puLong); { check value on output } function inflate_blocks_free(s : pInflate_blocks_state; var z : z_stream) : int; procedure inflate_set_dictionary(var s : inflate_blocks_state; const d : array of byte; { dictionary } n : uInt); { dictionary length } function inflate_blocks_sync_point(var s : inflate_blocks_state) : int; implementation uses iminfcodes, iminftrees, iminfutil; { Tables for deflate from PKZIP's appnote.txt. } Const border : Array [0..18] Of Word { Order of the bit length code lengths } = (16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15); { Notes beyond the 1.93a appnote.txt: 1. Distance pointers never point before the beginning of the output stream. 2. Distance pointers can point back across blocks, up to 32k away. 3. There is an implied maximum of 7 bits for the bit length table and 15 bits for the actual data. 4. If only one code exists, then it is encoded using one bit. (Zero would be more efficient, but perhaps a little confusing.) If two codes exist, they are coded using one bit each (0 and 1). 5. There is no way of sending zero distance codes--a dummy must be sent if there are none. (History: a pre 2.0 version of PKZIP would store blocks with no distance codes, but this was discovered to be too harsh a criterion.) Valid only for 1.93a. 2.04c does allow zero distance codes, which is sent as one code of zero bits in length. 6. There are up to 286 literal/length codes. Code 256 represents the end-of-block. Note however that the static length tree defines 288 codes just to fill out the Huffman codes. Codes 286 and 287 cannot be used though, since there is no length base or extra bits defined for them. Similarily, there are up to 30 distance codes. However, static trees define 32 codes (all 5 bits) to fill out the Huffman codes, but the last two had better not show up in the data. 7. Unzip can check dynamic Huffman blocks for complete code sets. The exception is that a single code would not be complete (see #4). 8. The five bits following the block type is really the number of literal codes sent minus 257. 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits (1+6+6). Therefore, to output three times the length, you output three codes (1+1+1), whereas to output four times the same length, you only need two codes (1+3). Hmm. 10. In the tree reconstruction algorithm, Code = Code + Increment only if BitLength(i) is not zero. (Pretty obvious.) 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) 12. Note: length code 284 can represent 227-258, but length code 285 really is 258. The last length deserves its own, short code since it gets used a lot in very redundant files. The length 258 is special since 258 - 3 (the min match length) is 255. 13. The literal/length and distance code bit lengths are read as a single stream of lengths. It is possible (and advantageous) for a repeat code (16, 17, or 18) to go across the boundary between the two sets of lengths. } procedure inflate_blocks_reset (var s : inflate_blocks_state; var z : z_stream; c : puLong); { check value on output } begin if (c <> Z_NULL) then c^ := s.check; if (s.mode = BTREE) or (s.mode = DTREE) then ZFREE(z, s.sub.trees.blens); if (s.mode = CODES) then inflate_codes_free(s.sub.decode.codes, z); s.mode := ZTYPE; s.bitk := 0; s.bitb := 0; s.write := s.window; s.read := s.window; if Assigned(s.checkfn) then begin s.check := s.checkfn(uLong(0), pBytef(NIL), 0); z.adler := s.check; end; {$IFDEF DEBUG} Tracev('inflate: blocks reset'); {$ENDIF} end; function inflate_blocks_new(var z : z_stream; c : check_func; { check function } w : uInt { window size } ) : pInflate_blocks_state; var s : pInflate_blocks_state; begin s := pInflate_blocks_state( ZALLOC(z,1, sizeof(inflate_blocks_state)) ); if (s = Z_NULL) then begin inflate_blocks_new := s; exit; end; s^.hufts := huft_ptr( ZALLOC(z, sizeof(inflate_huft), MANY) ); if (s^.hufts = Z_NULL) then begin ZFREE(z, s); inflate_blocks_new := Z_NULL; exit; end; s^.window := pBytef( ZALLOC(z, 1, w) ); if (s^.window = Z_NULL) then begin ZFREE(z, s^.hufts); ZFREE(z, s); inflate_blocks_new := Z_NULL; exit; end; s^.zend := s^.window; Inc(s^.zend, w); s^.checkfn := c; s^.mode := ZTYPE; {$IFDEF DEBUG} Tracev('inflate: blocks allocated'); {$ENDIF} inflate_blocks_reset(s^, z, Z_NULL); inflate_blocks_new := s; end; function inflate_blocks (var s : inflate_blocks_state; var z : z_stream; r : int) : int; { initial return code } label start_btree, start_dtree, start_blkdone, start_dry, start_codes; var t : uInt; { temporary storage } b : uLong; { bit buffer } k : uInt; { bits in bit buffer } p : pBytef; { input data pointer } n : uInt; { bytes available there } q : pBytef; { output window write pointer } m : uInt; { bytes to end of window or read pointer } { fixed code blocks } var bl, bd : uInt; tl, td : pInflate_huft; var h : pInflate_huft; i, j, c : uInt; var cs : pInflate_codes_state; begin { copy input/output information to locals } p := z.next_in; n := z.avail_in; b := s.bitb; k := s.bitk; q := s.write; if ptr2int(q) < ptr2int(s.read) then m := uInt(ptr2int(s.read)-ptr2int(q)-1) else m := uInt(ptr2int(s.zend)-ptr2int(q)); { decompress an inflated block } { process input based on current state } while True do Case s.mode of ZTYPE: begin {NEEDBITS(3);} while (k < 3) do begin {NEEDBYTE;} if (n <> 0) then r :=Z_OK else begin {UPDATE} s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_blocks := inflate_flush(s,z,r); exit; end; Dec(n); b := b or (uLong(p^) shl k); Inc(p); Inc(k, 8); end; t := uInt(b) and 7; s.last := boolean(t and 1); case (t shr 1) of 0: { stored } begin {$IFDEF DEBUG} if s.last then Tracev('inflate: stored block (last)') else Tracev('inflate: stored block'); {$ENDIF} {DUMPBITS(3);} b := b shr 3; Dec(k, 3); t := k and 7; { go to byte boundary } {DUMPBITS(t);} b := b shr t; Dec(k, t); s.mode := LENS; { get length of stored block } end; 1: { fixed } begin begin {$IFDEF DEBUG} if s.last then Tracev('inflate: fixed codes blocks (last)') else Tracev('inflate: fixed codes blocks'); {$ENDIF} inflate_trees_fixed(bl, bd, tl, td, z); s.sub.decode.codes := inflate_codes_new(bl, bd, tl, td, z); if (s.sub.decode.codes = Z_NULL) then begin r := Z_MEM_ERROR; { update pointers and return } s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_blocks := inflate_flush(s,z,r); exit; end; end; {DUMPBITS(3);} b := b shr 3; Dec(k, 3); s.mode := CODES; end; 2: { dynamic } begin {$IFDEF DEBUG} if s.last then Tracev('inflate: dynamic codes block (last)') else Tracev('inflate: dynamic codes block'); {$ENDIF} {DUMPBITS(3);} b := b shr 3; Dec(k, 3); s.mode := TABLE; end; 3: begin { illegal } {DUMPBITS(3);} b := b shr 3; Dec(k, 3); s.mode := BLKBAD; z.msg := 'invalid block type'; r := Z_DATA_ERROR; { update pointers and return } s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_blocks := inflate_flush(s,z,r); exit; end; end; end; LENS: begin {NEEDBITS(32);} while (k < 32) do begin {NEEDBYTE;} if (n <> 0) then r :=Z_OK else begin {UPDATE} s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_blocks := inflate_flush(s,z,r); exit; end; Dec(n); b := b or (uLong(p^) shl k); Inc(p); Inc(k, 8); end; if (((not b) shr 16) and $ffff) <> (b and $ffff) then begin s.mode := BLKBAD; z.msg := 'invalid stored block lengths'; r := Z_DATA_ERROR; { update pointers and return } s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_blocks := inflate_flush(s,z,r); exit; end; s.sub.left := uInt(b) and $ffff; k := 0; b := 0; { dump bits } {$IFDEF DEBUG} Tracev('inflate: stored length '+IntToStr(s.sub.left)); {$ENDIF} if s.sub.left <> 0 then s.mode := STORED else if s.last then s.mode := DRY else s.mode := ZTYPE; end; STORED: begin if (n = 0) then begin { update pointers and return } s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_blocks := inflate_flush(s,z,r); exit; end; {NEEDOUT} if (m = 0) then begin {WRAP} if (q = s.zend) and (s.read <> s.window) then begin q := s.window; if ptr2int(q) < ptr2int(s.read) then m := uInt(ptr2int(s.read)-ptr2int(q)-1) else m := uInt(ptr2int(s.zend)-ptr2int(q)); end; if (m = 0) then begin {FLUSH} s.write := q; r := inflate_flush(s,z,r); q := s.write; if ptr2int(q) < ptr2int(s.read) then m := uInt(ptr2int(s.read)-ptr2int(q)-1) else m := uInt(ptr2int(s.zend)-ptr2int(q)); {WRAP} if (q = s.zend) and (s.read <> s.window) then begin q := s.window; if ptr2int(q) < ptr2int(s.read) then m := uInt(ptr2int(s.read)-ptr2int(q)-1) else m := uInt(ptr2int(s.zend)-ptr2int(q)); end; if (m = 0) then begin {UPDATE} s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_blocks := inflate_flush(s,z,r); exit; end; end; end; r := Z_OK; t := s.sub.left; if (t > n) then t := n; if (t > m) then t := m; zmemcpy(q, p, t); Inc(p, t); Dec(n, t); Inc(q, t); Dec(m, t); Dec(s.sub.left, t); if (s.sub.left = 0) then begin {$IFDEF DEBUG} if (ptr2int(q) >= ptr2int(s.read)) then Tracev('inflate: stored end '+ IntToStr(z.total_out + ptr2int(q) - ptr2int(s.read)) + ' total out') else Tracev('inflate: stored end '+ IntToStr(z.total_out + ptr2int(s.zend) - ptr2int(s.read) + ptr2int(q) - ptr2int(s.window)) + ' total out'); {$ENDIF} if s.last then s.mode := DRY else s.mode := ZTYPE; end; end; TABLE: begin {NEEDBITS(14);} while (k < 14) do begin {NEEDBYTE;} if (n <> 0) then r :=Z_OK else begin {UPDATE} s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_blocks := inflate_flush(s,z,r); exit; end; Dec(n); b := b or (uLong(p^) shl k); Inc(p); Inc(k, 8); end; t := uInt(b) and $3fff; s.sub.trees.table := t; {$ifndef PKZIP_BUG_WORKAROUND} if ((t and $1f) > 29) or (((t shr 5) and $1f) > 29) then begin s.mode := BLKBAD; z.msg := 'too many length or distance symbols'; r := Z_DATA_ERROR; { update pointers and return } s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_blocks := inflate_flush(s,z,r); exit; end; {$endif} t := 258 + (t and $1f) + ((t shr 5) and $1f); s.sub.trees.blens := puIntArray( ZALLOC(z, t, sizeof(uInt)) ); if (s.sub.trees.blens = Z_NULL) then begin r := Z_MEM_ERROR; { update pointers and return } s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_blocks := inflate_flush(s,z,r); exit; end; {DUMPBITS(14);} b := b shr 14; Dec(k, 14); s.sub.trees.index := 0; {$IFDEF DEBUG} Tracev('inflate: table sizes ok'); {$ENDIF} s.mode := BTREE; { fall trough case is handled by the while } { try GOTO for speed - Nomssi } goto start_btree; end; BTREE: begin start_btree: while (s.sub.trees.index < 4 + (s.sub.trees.table shr 10)) do begin {NEEDBITS(3);} while (k < 3) do begin {NEEDBYTE;} if (n <> 0) then r :=Z_OK else begin {UPDATE} s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_blocks := inflate_flush(s,z,r); exit; end; Dec(n); b := b or (uLong(p^) shl k); Inc(p); Inc(k, 8); end; s.sub.trees.blens^[border[s.sub.trees.index]] := uInt(b) and 7; Inc(s.sub.trees.index); {DUMPBITS(3);} b := b shr 3; Dec(k, 3); end; while (s.sub.trees.index < 19) do begin s.sub.trees.blens^[border[s.sub.trees.index]] := 0; Inc(s.sub.trees.index); end; s.sub.trees.bb := 7; t := inflate_trees_bits(s.sub.trees.blens^, s.sub.trees.bb, s.sub.trees.tb, s.hufts^, z); if (t <> Z_OK) then begin ZFREE(z, s.sub.trees.blens); r := t; if (r = Z_DATA_ERROR) then s.mode := BLKBAD; { update pointers and return } s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_blocks := inflate_flush(s,z,r); exit; end; s.sub.trees.index := 0; {$IFDEF DEBUG} Tracev('inflate: bits tree ok'); {$ENDIF} s.mode := DTREE; { fall through again } goto start_dtree; end; DTREE: begin start_dtree: while TRUE do begin t := s.sub.trees.table; if not (s.sub.trees.index < 258 + (t and $1f) + ((t shr 5) and $1f)) then break; t := s.sub.trees.bb; {NEEDBITS(t);} while (k < t) do begin {NEEDBYTE;} if (n <> 0) then r :=Z_OK else begin {UPDATE} s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_blocks := inflate_flush(s,z,r); exit; end; Dec(n); b := b or (uLong(p^) shl k); Inc(p); Inc(k, 8); end; h := s.sub.trees.tb; Inc(h, uInt(b) and inflate_mask[t]); t := h^.Bits; c := h^.Base; if (c < 16) then begin {DUMPBITS(t);} b := b shr t; Dec(k, t); s.sub.trees.blens^[s.sub.trees.index] := c; Inc(s.sub.trees.index); end else { c = 16..18 } begin if c = 18 then begin i := 7; j := 11; end else begin i := c - 14; j := 3; end; {NEEDBITS(t + i);} while (k < t + i) do begin {NEEDBYTE;} if (n <> 0) then r :=Z_OK else begin {UPDATE} s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_blocks := inflate_flush(s,z,r); exit; end; Dec(n); b := b or (uLong(p^) shl k); Inc(p); Inc(k, 8); end; {DUMPBITS(t);} b := b shr t; Dec(k, t); Inc(j, uInt(b) and inflate_mask[i]); {DUMPBITS(i);} b := b shr i; Dec(k, i); i := s.sub.trees.index; t := s.sub.trees.table; if (i + j > 258 + (t and $1f) + ((t shr 5) and $1f)) or ((c = 16) and (i < 1)) then begin ZFREE(z, s.sub.trees.blens); s.mode := BLKBAD; z.msg := 'invalid bit length repeat'; r := Z_DATA_ERROR; { update pointers and return } s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_blocks := inflate_flush(s,z,r); exit; end; if c = 16 then c := s.sub.trees.blens^[i - 1] else c := 0; repeat s.sub.trees.blens^[i] := c; Inc(i); Dec(j); until (j=0); s.sub.trees.index := i; end; end; { while } s.sub.trees.tb := Z_NULL; begin bl := 9; { must be <= 9 for lookahead assumptions } bd := 6; { must be <= 9 for lookahead assumptions } t := s.sub.trees.table; t := inflate_trees_dynamic(257 + (t and $1f), 1 + ((t shr 5) and $1f), s.sub.trees.blens^, bl, bd, tl, td, s.hufts^, z); ZFREE(z, s.sub.trees.blens); if (t <> Z_OK) then begin if (t = uInt(Z_DATA_ERROR)) then s.mode := BLKBAD; r := t; { update pointers and return } s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_blocks := inflate_flush(s,z,r); exit; end; {$IFDEF DEBUG} Tracev('inflate: trees ok'); {$ENDIF} { c renamed to cs } cs := inflate_codes_new(bl, bd, tl, td, z); if (cs = Z_NULL) then begin r := Z_MEM_ERROR; { update pointers and return } s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_blocks := inflate_flush(s,z,r); exit; end; s.sub.decode.codes := cs; end; s.mode := CODES; { yet another falltrough } goto start_codes; end; CODES: begin start_codes: { update pointers } s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in)); z.next_in := p; s.write := q; r := inflate_codes(s, z, r); if (r <> Z_STREAM_END) then begin inflate_blocks := inflate_flush(s, z, r); exit; end; r := Z_OK; inflate_codes_free(s.sub.decode.codes, z); { load local pointers } p := z.next_in; n := z.avail_in; b := s.bitb; k := s.bitk; q := s.write; if ptr2int(q) < ptr2int(s.read) then m := uInt(ptr2int(s.read)-ptr2int(q)-1) else m := uInt(ptr2int(s.zend)-ptr2int(q)); {$IFDEF DEBUG} if (ptr2int(q) >= ptr2int(s.read)) then Tracev('inflate: codes end '+ IntToStr(z.total_out + ptr2int(q) - ptr2int(s.read)) + ' total out') else Tracev('inflate: codes end '+ IntToStr(z.total_out + ptr2int(s.zend) - ptr2int(s.read) + ptr2int(q) - ptr2int(s.window)) + ' total out'); {$ENDIF} if (not s.last) then begin s.mode := ZTYPE; continue; { break for switch statement in C-code } end; {$ifndef patch112} if (k > 7) then { return unused byte, if any } begin {$IFDEF DEBUG} Assert(k < 16, 'inflate_codes grabbed too many bytes'); {$ENDIF} Dec(k, 8); Inc(n); Dec(p); { can always return one } end; {$endif} s.mode := DRY; { another falltrough } goto start_dry; end; DRY: begin start_dry: {FLUSH} s.write := q; r := inflate_flush(s,z,r); q := s.write; { not needed anymore, we are done: if ptr2int(q) < ptr2int(s.read) then m := uInt(ptr2int(s.read)-ptr2int(q)-1) else m := uInt(ptr2int(s.zend)-ptr2int(q)); } if (s.read <> s.write) then begin { update pointers and return } s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_blocks := inflate_flush(s,z,r); exit; end; s.mode := BLKDONE; goto start_blkdone; end; BLKDONE: begin start_blkdone: r := Z_STREAM_END; { update pointers and return } s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_blocks := inflate_flush(s,z,r); exit; end; BLKBAD: begin r := Z_DATA_ERROR; { update pointers and return } s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_blocks := inflate_flush(s,z,r); exit; end; else begin r := Z_STREAM_ERROR; { update pointers and return } s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_blocks := inflate_flush(s,z,r); exit; end; end; { Case s.mode of } end; function inflate_blocks_free(s : pInflate_blocks_state; var z : z_stream) : int; begin inflate_blocks_reset(s^, z, Z_NULL); ZFREE(z, s^.window); ZFREE(z, s^.hufts); ZFREE(z, s); {$IFDEF DEBUG} Trace('inflate: blocks freed'); {$ENDIF} inflate_blocks_free := Z_OK; end; procedure inflate_set_dictionary(var s : inflate_blocks_state; const d : array of byte; { dictionary } n : uInt); { dictionary length } begin zmemcpy(s.window, pBytef(@d), n); s.write := s.window; Inc(s.write, n); s.read := s.write; end; { Returns true if inflate is currently at the end of a block generated by Z_SYNC_FLUSH or Z_FULL_FLUSH. IN assertion: s <> Z_NULL } function inflate_blocks_sync_point(var s : inflate_blocks_state) : int; begin inflate_blocks_sync_point := int(s.mode = LENS); end; end. ================================================ FILE: lib/Imaging/ZLib/iminfcodes.pas ================================================ Unit iminfcodes; { infcodes.c -- process literals and length/distance pairs Copyright (C) 1995-1998 Mark Adler Pascal tranlastion Copyright (C) 1998 by Jacques Nomssi Nzali For conditions of distribution and use, see copyright notice in readme.txt } interface {$I imzconf.inc} uses {$IFDEF DEBUG} SysUtils, strutils, {$ENDIF} imzutil, impaszlib; function inflate_codes_new (bl : uInt; bd : uInt; tl : pInflate_huft; td : pInflate_huft; var z : z_stream): pInflate_codes_state; function inflate_codes(var s : inflate_blocks_state; var z : z_stream; r : int) : int; procedure inflate_codes_free(c : pInflate_codes_state; var z : z_stream); implementation uses iminfutil, iminffast; function inflate_codes_new (bl : uInt; bd : uInt; tl : pInflate_huft; td : pInflate_huft; var z : z_stream): pInflate_codes_state; var c : pInflate_codes_state; begin c := pInflate_codes_state( ZALLOC(z,1,sizeof(inflate_codes_state)) ); if (c <> Z_NULL) then begin c^.mode := START; c^.lbits := Byte(bl); c^.dbits := Byte(bd); c^.ltree := tl; c^.dtree := td; {$IFDEF DEBUG} Tracev('inflate: codes new'); {$ENDIF} end; inflate_codes_new := c; end; function inflate_codes(var s : inflate_blocks_state; var z : z_stream; r : int) : int; var j : uInt; { temporary storage } t : pInflate_huft; { temporary pointer } e : uInt; { extra bits or operation } b : uLong; { bit buffer } k : uInt; { bits in bit buffer } p : pBytef; { input data pointer } n : uInt; { bytes available there } q : pBytef; { output window write pointer } m : uInt; { bytes to end of window or read pointer } f : pBytef; { pointer to copy strings from } var c : pInflate_codes_state; begin c := s.sub.decode.codes; { codes state } { copy input/output information to locals } p := z.next_in; n := z.avail_in; b := s.bitb; k := s.bitk; q := s.write; if ptr2int(q) < ptr2int(s.read) then m := uInt(ptr2int(s.read)-ptr2int(q)-1) else m := uInt(ptr2int(s.zend)-ptr2int(q)); { process input and output based on current state } while True do case (c^.mode) of { waiting for "i:"=input, "o:"=output, "x:"=nothing } START: { x: set up for LEN } begin {$ifndef SLOW} if (m >= 258) and (n >= 10) then begin {UPDATE} s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); z.next_in := p; s.write := q; r := inflate_fast(c^.lbits, c^.dbits, c^.ltree, c^.dtree, s, z); {LOAD} p := z.next_in; n := z.avail_in; b := s.bitb; k := s.bitk; q := s.write; if ptr2int(q) < ptr2int(s.read) then m := uInt(ptr2int(s.read)-ptr2int(q)-1) else m := uInt(ptr2int(s.zend)-ptr2int(q)); if (r <> Z_OK) then begin if (r = Z_STREAM_END) then c^.mode := WASH else c^.mode := BADCODE; continue; { break for switch-statement in C } end; end; {$endif} { not SLOW } c^.sub.code.need := c^.lbits; c^.sub.code.tree := c^.ltree; c^.mode := LEN; { falltrough } end; LEN: { i: get length/literal/eob next } begin j := c^.sub.code.need; {NEEDBITS(j);} while (k < j) do begin {NEEDBYTE;} if (n <> 0) then r :=Z_OK else begin {UPDATE} s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_codes := inflate_flush(s,z,r); exit; end; Dec(n); b := b or (uLong(p^) shl k); Inc(p); Inc(k, 8); end; t := c^.sub.code.tree; Inc(t, uInt(b) and inflate_mask[j]); {DUMPBITS(t^.bits);} b := b shr t^.bits; Dec(k, t^.bits); e := uInt(t^.exop); if (e = 0) then { literal } begin c^.sub.lit := t^.base; {$IFDEF DEBUG} if (t^.base >= $20) and (t^.base < $7f) then Tracevv('inflate: literal '+AnsiChar(t^.base)) else Tracevv('inflate: literal '+IntToStr(t^.base)); {$ENDIF} c^.mode := LIT; continue; { break switch statement } end; if (e and 16 <> 0) then { length } begin c^.sub.copy.get := e and 15; c^.len := t^.base; c^.mode := LENEXT; continue; { break C-switch statement } end; if (e and 64 = 0) then { next table } begin c^.sub.code.need := e; c^.sub.code.tree := @huft_ptr(t)^[t^.base]; continue; { break C-switch statement } end; if (e and 32 <> 0) then { end of block } begin {$IFDEF DEBUG} Tracevv('inflate: end of block'); {$ENDIF} c^.mode := WASH; continue; { break C-switch statement } end; c^.mode := BADCODE; { invalid code } z.msg := 'invalid literal/length code'; r := Z_DATA_ERROR; {UPDATE} s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_codes := inflate_flush(s,z,r); exit; end; LENEXT: { i: getting length extra (have base) } begin j := c^.sub.copy.get; {NEEDBITS(j);} while (k < j) do begin {NEEDBYTE;} if (n <> 0) then r :=Z_OK else begin {UPDATE} s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_codes := inflate_flush(s,z,r); exit; end; Dec(n); b := b or (uLong(p^) shl k); Inc(p); Inc(k, 8); end; Inc(c^.len, uInt(b and inflate_mask[j])); {DUMPBITS(j);} b := b shr j; Dec(k, j); c^.sub.code.need := c^.dbits; c^.sub.code.tree := c^.dtree; {$IFDEF DEBUG} Tracevv('inflate: length '+IntToStr(c^.len)); {$ENDIF} c^.mode := DIST; { falltrough } end; DIST: { i: get distance next } begin j := c^.sub.code.need; {NEEDBITS(j);} while (k < j) do begin {NEEDBYTE;} if (n <> 0) then r :=Z_OK else begin {UPDATE} s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_codes := inflate_flush(s,z,r); exit; end; Dec(n); b := b or (uLong(p^) shl k); Inc(p); Inc(k, 8); end; t := @huft_ptr(c^.sub.code.tree)^[uInt(b) and inflate_mask[j]]; {DUMPBITS(t^.bits);} b := b shr t^.bits; Dec(k, t^.bits); e := uInt(t^.exop); if (e and 16 <> 0) then { distance } begin c^.sub.copy.get := e and 15; c^.sub.copy.dist := t^.base; c^.mode := DISTEXT; continue; { break C-switch statement } end; if (e and 64 = 0) then { next table } begin c^.sub.code.need := e; c^.sub.code.tree := @huft_ptr(t)^[t^.base]; continue; { break C-switch statement } end; c^.mode := BADCODE; { invalid code } z.msg := 'invalid distance code'; r := Z_DATA_ERROR; {UPDATE} s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_codes := inflate_flush(s,z,r); exit; end; DISTEXT: { i: getting distance extra } begin j := c^.sub.copy.get; {NEEDBITS(j);} while (k < j) do begin {NEEDBYTE;} if (n <> 0) then r :=Z_OK else begin {UPDATE} s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_codes := inflate_flush(s,z,r); exit; end; Dec(n); b := b or (uLong(p^) shl k); Inc(p); Inc(k, 8); end; Inc(c^.sub.copy.dist, uInt(b) and inflate_mask[j]); {DUMPBITS(j);} b := b shr j; Dec(k, j); {$IFDEF DEBUG} Tracevv('inflate: distance '+ IntToStr(c^.sub.copy.dist)); {$ENDIF} c^.mode := COPY; { falltrough } end; COPY: { o: copying bytes in window, waiting for space } begin f := q; Dec(f, c^.sub.copy.dist); if (uInt(ptr2int(q) - ptr2int(s.window)) < c^.sub.copy.dist) then begin f := s.zend; Dec(f, c^.sub.copy.dist - uInt(ptr2int(q) - ptr2int(s.window))); end; while (c^.len <> 0) do begin {NEEDOUT} if (m = 0) then begin {WRAP} if (q = s.zend) and (s.read <> s.window) then begin q := s.window; if ptr2int(q) < ptr2int(s.read) then m := uInt(ptr2int(s.read)-ptr2int(q)-1) else m := uInt(ptr2int(s.zend)-ptr2int(q)); end; if (m = 0) then begin {FLUSH} s.write := q; r := inflate_flush(s,z,r); q := s.write; if ptr2int(q) < ptr2int(s.read) then m := uInt(ptr2int(s.read)-ptr2int(q)-1) else m := uInt(ptr2int(s.zend)-ptr2int(q)); {WRAP} if (q = s.zend) and (s.read <> s.window) then begin q := s.window; if ptr2int(q) < ptr2int(s.read) then m := uInt(ptr2int(s.read)-ptr2int(q)-1) else m := uInt(ptr2int(s.zend)-ptr2int(q)); end; if (m = 0) then begin {UPDATE} s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_codes := inflate_flush(s,z,r); exit; end; end; end; r := Z_OK; {OUTBYTE( *f++)} q^ := f^; Inc(q); Inc(f); Dec(m); if (f = s.zend) then f := s.window; Dec(c^.len); end; c^.mode := START; { C-switch break; not needed } end; LIT: { o: got literal, waiting for output space } begin {NEEDOUT} if (m = 0) then begin {WRAP} if (q = s.zend) and (s.read <> s.window) then begin q := s.window; if ptr2int(q) < ptr2int(s.read) then m := uInt(ptr2int(s.read)-ptr2int(q)-1) else m := uInt(ptr2int(s.zend)-ptr2int(q)); end; if (m = 0) then begin {FLUSH} s.write := q; r := inflate_flush(s,z,r); q := s.write; if ptr2int(q) < ptr2int(s.read) then m := uInt(ptr2int(s.read)-ptr2int(q)-1) else m := uInt(ptr2int(s.zend)-ptr2int(q)); {WRAP} if (q = s.zend) and (s.read <> s.window) then begin q := s.window; if ptr2int(q) < ptr2int(s.read) then m := uInt(ptr2int(s.read)-ptr2int(q)-1) else m := uInt(ptr2int(s.zend)-ptr2int(q)); end; if (m = 0) then begin {UPDATE} s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_codes := inflate_flush(s,z,r); exit; end; end; end; r := Z_OK; {OUTBYTE(c^.sub.lit);} q^ := c^.sub.lit; Inc(q); Dec(m); c^.mode := START; {break;} end; WASH: { o: got eob, possibly more output } begin {$ifdef patch112} if (k > 7) then { return unused byte, if any } begin {$IFDEF DEBUG} Assert(k < 16, 'inflate_codes grabbed too many bytes'); {$ENDIF} Dec(k, 8); Inc(n); Dec(p); { can always return one } end; {$endif} {FLUSH} s.write := q; r := inflate_flush(s,z,r); q := s.write; if ptr2int(q) < ptr2int(s.read) then m := uInt(ptr2int(s.read)-ptr2int(q)-1) else m := uInt(ptr2int(s.zend)-ptr2int(q)); if (s.read <> s.write) then begin {UPDATE} s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_codes := inflate_flush(s,z,r); exit; end; c^.mode := ZEND; { falltrough } end; ZEND: begin r := Z_STREAM_END; {UPDATE} s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_codes := inflate_flush(s,z,r); exit; end; BADCODE: { x: got error } begin r := Z_DATA_ERROR; {UPDATE} s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_codes := inflate_flush(s,z,r); exit; end; else begin r := Z_STREAM_ERROR; {UPDATE} s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_codes := inflate_flush(s,z,r); exit; end; end; {NEED_DUMMY_RETURN - Delphi2+ dumb compilers complain without this } inflate_codes := Z_STREAM_ERROR; end; procedure inflate_codes_free(c : pInflate_codes_state; var z : z_stream); begin ZFREE(z, c); {$IFDEF DEBUG} Tracev('inflate: codes free'); {$ENDIF} end; end. ================================================ FILE: lib/Imaging/ZLib/iminffast.pas ================================================ Unit iminffast; { inffast.h and inffast.c -- process literals and length/distance pairs fast Copyright (C) 1995-1998 Mark Adler Pascal tranlastion Copyright (C) 1998 by Jacques Nomssi Nzali For conditions of distribution and use, see copyright notice in readme.txt } interface {$I imzconf.inc} uses {$ifdef DEBUG} SysUtils, strutils, {$ENDIF} imzutil, impaszlib; function inflate_fast( bl : uInt; bd : uInt; tl : pInflate_huft; td : pInflate_huft; var s : inflate_blocks_state; var z : z_stream) : int; implementation uses iminfutil; { Called with number of bytes left to write in window at least 258 (the maximum string length) and number of input bytes available at least ten. The ten bytes are six bytes for the longest length/ distance pair plus four bytes for overloading the bit buffer. } function inflate_fast( bl : uInt; bd : uInt; tl : pInflate_huft; td : pInflate_huft; var s : inflate_blocks_state; var z : z_stream) : int; var t : pInflate_huft; { temporary pointer } e : uInt; { extra bits or operation } b : uLong; { bit buffer } k : uInt; { bits in bit buffer } p : pBytef; { input data pointer } n : uInt; { bytes available there } q : pBytef; { output window write pointer } m : uInt; { bytes to end of window or read pointer } ml : uInt; { mask for literal/length tree } md : uInt; { mask for distance tree } c : uInt; { bytes to copy } d : uInt; { distance back to copy from } r : pBytef; { copy source pointer } begin { load input, output, bit values (macro LOAD) } p := z.next_in; n := z.avail_in; b := s.bitb; k := s.bitk; q := s.write; if ptr2int(q) < ptr2int(s.read) then m := uInt(ptr2int(s.read)-ptr2int(q)-1) else m := uInt(ptr2int(s.zend)-ptr2int(q)); { initialize masks } ml := inflate_mask[bl]; md := inflate_mask[bd]; { do until not enough input or output space for fast loop } repeat { assume called with (m >= 258) and (n >= 10) } { get literal/length code } {GRABBITS(20);} { max bits for literal/length code } while (k < 20) do begin Dec(n); b := b or (uLong(p^) shl k); Inc(p); Inc(k, 8); end; t := @(huft_ptr(tl)^[uInt(b) and ml]); e := t^.exop; if (e = 0) then begin {DUMPBITS(t^.bits);} b := b shr t^.bits; Dec(k, t^.bits); {$IFDEF DEBUG} if (t^.base >= $20) and (t^.base < $7f) then Tracevv('inflate: * literal '+AnsiChar(t^.base)) else Tracevv('inflate: * literal '+ IntToStr(t^.base)); {$ENDIF} q^ := Byte(t^.base); Inc(q); Dec(m); continue; end; repeat {DUMPBITS(t^.bits);} b := b shr t^.bits; Dec(k, t^.bits); if (e and 16 <> 0) then begin { get extra bits for length } e := e and 15; c := t^.base + (uInt(b) and inflate_mask[e]); {DUMPBITS(e);} b := b shr e; Dec(k, e); {$IFDEF DEBUG} Tracevv('inflate: * length ' + IntToStr(c)); {$ENDIF} { decode distance base of block to copy } {GRABBITS(15);} { max bits for distance code } while (k < 15) do begin Dec(n); b := b or (uLong(p^) shl k); Inc(p); Inc(k, 8); end; t := @huft_ptr(td)^[uInt(b) and md]; e := t^.exop; repeat {DUMPBITS(t^.bits);} b := b shr t^.bits; Dec(k, t^.bits); if (e and 16 <> 0) then begin { get extra bits to add to distance base } e := e and 15; {GRABBITS(e);} { get extra bits (up to 13) } while (k < e) do begin Dec(n); b := b or (uLong(p^) shl k); Inc(p); Inc(k, 8); end; d := t^.base + (uInt(b) and inflate_mask[e]); {DUMPBITS(e);} b := b shr e; Dec(k, e); {$IFDEF DEBUG} Tracevv('inflate: * distance '+IntToStr(d)); {$ENDIF} { do the copy } Dec(m, c); if (uInt(ptr2int(q) - ptr2int(s.window)) >= d) then { offset before dest } begin { just copy } r := q; Dec(r, d); q^ := r^; Inc(q); Inc(r); Dec(c); { minimum count is three, } q^ := r^; Inc(q); Inc(r); Dec(c); { so unroll loop a little } end else { else offset after destination } begin e := d - uInt(ptr2int(q) - ptr2int(s.window)); { bytes from offset to end } r := s.zend; Dec(r, e); { pointer to offset } if (c > e) then { if source crosses, } begin Dec(c, e); { copy to end of window } repeat q^ := r^; Inc(q); Inc(r); Dec(e); until (e=0); r := s.window; { copy rest from start of window } end; end; repeat { copy all or what's left } q^ := r^; Inc(q); Inc(r); Dec(c); until (c = 0); break; end else if (e and 64 = 0) then begin Inc(t, t^.base + (uInt(b) and inflate_mask[e])); e := t^.exop; end else begin z.msg := 'invalid distance code'; {UNGRAB} c := z.avail_in-n; if (k shr 3) < c then c := k shr 3; Inc(n, c); Dec(p, c); Dec(k, c shl 3); {UPDATE} s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_fast := Z_DATA_ERROR; exit; end; until FALSE; break; end; if (e and 64 = 0) then begin {t += t->base; e = (t += ((uInt)b & inflate_mask[e]))->exop;} Inc(t, t^.base + (uInt(b) and inflate_mask[e])); e := t^.exop; if (e = 0) then begin {DUMPBITS(t^.bits);} b := b shr t^.bits; Dec(k, t^.bits); {$IFDEF DEBUG} if (t^.base >= $20) and (t^.base < $7f) then Tracevv('inflate: * literal '+AnsiChar(t^.base)) else Tracevv('inflate: * literal '+IntToStr(t^.base)); {$ENDIF} q^ := Byte(t^.base); Inc(q); Dec(m); break; end; end else if (e and 32 <> 0) then begin {$IFDEF DEBUG} Tracevv('inflate: * end of block'); {$ENDIF} {UNGRAB} c := z.avail_in-n; if (k shr 3) < c then c := k shr 3; Inc(n, c); Dec(p, c); Dec(k, c shl 3); {UPDATE} s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_fast := Z_STREAM_END; exit; end else begin z.msg := 'invalid literal/length code'; {UNGRAB} c := z.avail_in-n; if (k shr 3) < c then c := k shr 3; Inc(n, c); Dec(p, c); Dec(k, c shl 3); {UPDATE} s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_fast := Z_DATA_ERROR; exit; end; until FALSE; until (m < 258) or (n < 10); { not enough input or output--restore pointers and return } {UNGRAB} c := z.avail_in-n; if (k shr 3) < c then c := k shr 3; Inc(n, c); Dec(p, c); Dec(k, c shl 3); {UPDATE} s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, ptr2int(p)-ptr2int(z.next_in)); z.next_in := p; s.write := q; inflate_fast := Z_OK; end; end. ================================================ FILE: lib/Imaging/ZLib/iminftrees.pas ================================================ Unit iminftrees; { inftrees.h -- header to use inftrees.c inftrees.c -- generate Huffman trees for efficient decoding Copyright (C) 1995-1998 Mark Adler WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Pascal tranlastion Copyright (C) 1998 by Jacques Nomssi Nzali For conditions of distribution and use, see copyright notice in readme.txt } Interface {$I imzconf.inc} uses imzutil, impaszlib; { Maximum size of dynamic tree. The maximum found in a long but non- exhaustive search was 1004 huft structures (850 for length/literals and 154 for distances, the latter actually the result of an exhaustive search). The actual maximum is not known, but the value below is more than safe. } const MANY = 1440; {$ifdef DEBUG} var inflate_hufts : uInt; {$endif} function inflate_trees_bits( var c : array of uIntf; { 19 code lengths } var bb : uIntf; { bits tree desired/actual depth } var tb : pinflate_huft; { bits tree result } var hp : array of Inflate_huft; { space for trees } var z : z_stream { for messages } ) : int; function inflate_trees_dynamic( nl : uInt; { number of literal/length codes } nd : uInt; { number of distance codes } var c : Array of uIntf; { that many (total) code lengths } var bl : uIntf; { literal desired/actual bit depth } var bd : uIntf; { distance desired/actual bit depth } var tl : pInflate_huft; { literal/length tree result } var td : pInflate_huft; { distance tree result } var hp : array of Inflate_huft; { space for trees } var z : z_stream { for messages } ) : int; function inflate_trees_fixed ( var bl : uInt; { literal desired/actual bit depth } var bd : uInt; { distance desired/actual bit depth } var tl : pInflate_huft; { literal/length tree result } var td : pInflate_huft; { distance tree result } var z : z_stream { for memory allocation } ) : int; implementation const inflate_copyright = 'inflate 1.1.2 Copyright 1995-1998 Mark Adler'; { If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot include such an acknowledgment, I would appreciate that you keep this copyright string in the executable of your product. } const { Tables for deflate from PKZIP's appnote.txt. } cplens : Array [0..30] Of uInt { Copy lengths for literal codes 257..285 } = (3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0); { actually lengths - 2; also see note #13 above about 258 } invalid_code = 112; cplext : Array [0..30] Of uInt { Extra bits for literal codes 257..285 } = (0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, invalid_code, invalid_code); cpdist : Array [0..29] Of uInt { Copy offsets for distance codes 0..29 } = (1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577); cpdext : Array [0..29] Of uInt { Extra bits for distance codes } = (0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13); { Huffman code decoding is performed using a multi-level table lookup. The fastest way to decode is to simply build a lookup table whose size is determined by the longest code. However, the time it takes to build this table can also be a factor if the data being decoded is not very long. The most common codes are necessarily the shortest codes, so those codes dominate the decoding time, and hence the speed. The idea is you can have a shorter table that decodes the shorter, more probable codes, and then point to subsidiary tables for the longer codes. The time it costs to decode the longer codes is then traded against the time it takes to make longer tables. This results of this trade are in the variables lbits and dbits below. lbits is the number of bits the first level table for literal/ length codes can decode in one step, and dbits is the same thing for the distance codes. Subsequent tables are also less than or equal to those sizes. These values may be adjusted either when all of the codes are shorter than that, in which case the longest code length in bits is used, or when the shortest code is *longer* than the requested table size, in which case the length of the shortest code in bits is used. There are two different values for the two tables, since they code a different number of possibilities each. The literal/length table codes 286 possible values, or in a flat code, a little over eight bits. The distance table codes 30 possible values, or a little less than five bits, flat. The optimum values for speed end up being about one bit more than those, so lbits is 8+1 and dbits is 5+1. The optimum values may differ though from machine to machine, and possibly even between compilers. Your mileage may vary. } { If BMAX needs to be larger than 16, then h and x[] should be uLong. } const BMAX = 15; { maximum bit length of any code } {$DEFINE USE_PTR} function huft_build( var b : array of uIntf; { code lengths in bits (all assumed <= BMAX) } n : uInt; { number of codes (assumed <= N_MAX) } s : uInt; { number of simple-valued codes (0..s-1) } const d : array of uIntf; { list of base values for non-simple codes } { array of word } const e : array of uIntf; { list of extra bits for non-simple codes } { array of byte } t : ppInflate_huft; { result: starting table } var m : uIntf; { maximum lookup bits, returns actual } var hp : array of inflate_huft; { space for trees } var hn : uInt; { hufts used in space } var v : array of uIntf { working area: values in order of bit length } ) : int; { Given a list of code lengths and a maximum table size, make a set of tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR if the given code set is incomplete (the tables are still built in this case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of lengths), or Z_MEM_ERROR if not enough memory. } Var a : uInt; { counter for codes of length k } c : Array [0..BMAX] Of uInt; { bit length count table } f : uInt; { i repeats in table every f entries } g : int; { maximum code length } h : int; { table level } i : uInt; {register} { counter, current code } j : uInt; {register} { counter } k : Int; {register} { number of bits in current code } l : int; { bits per table (returned in m) } mask : uInt; { (1 shl w) - 1, to avoid cc -O bug on HP } p : ^uIntf; {register} { pointer into c[], b[], or v[] } q : pInflate_huft; { points to current table } r : inflate_huft; { table entry for structure assignment } u : Array [0..BMAX-1] Of pInflate_huft; { table stack } w : int; {register} { bits before this table = (l*h) } x : Array [0..BMAX] Of uInt; { bit offsets, then code stack } {$IFDEF USE_PTR} xp : puIntf; { pointer into x } {$ELSE} xp : uInt; {$ENDIF} y : int; { number of dummy codes added } z : uInt; { number of entries in current table } Begin { Generate counts for each bit length } FillChar(c,SizeOf(c),0) ; { clear c[] } for i := 0 to n-1 do Inc (c[b[i]]); { assume all entries <= BMAX } If (c[0] = n) Then { null input--all zero length codes } Begin t^ := pInflate_huft(NIL); m := 0 ; huft_build := Z_OK ; Exit; End ; { Find minimum and maximum length, bound [m] by those } l := m; for j:=1 To BMAX do if (c[j] <> 0) then break; k := j ; { minimum code length } if (uInt(l) < j) then l := j; for i := BMAX downto 1 do if (c[i] <> 0) then break ; g := i ; { maximum code length } if (uInt(l) > i) then l := i; m := l; { Adjust last length count to fill out codes, if needed } y := 1 shl j ; while (j < i) do begin Dec(y, c[j]) ; if (y < 0) then begin huft_build := Z_DATA_ERROR; { bad input: more codes than bits } exit; end ; Inc(j) ; y := y shl 1 end; Dec (y, c[i]) ; if (y < 0) then begin huft_build := Z_DATA_ERROR; { bad input: more codes than bits } exit; end; Inc(c[i], y); { Generate starting offsets into the value table FOR each length } {$IFDEF USE_PTR} x[1] := 0; j := 0; p := @c[1]; xp := @x[2]; dec(i); { note that i = g from above } WHILE (i > 0) DO BEGIN inc(j, p^); xp^ := j; inc(p); inc(xp); dec(i); END; {$ELSE} x[1] := 0; j := 0 ; for i := 1 to g do begin x[i] := j; Inc(j, c[i]); end; {$ENDIF} { Make a table of values in order of bit lengths } for i := 0 to n-1 do begin j := b[i]; if (j <> 0) then begin v[ x[j] ] := i; Inc(x[j]); end; end; n := x[g]; { set n to length of v } { Generate the Huffman codes and for each, make the table entries } i := 0 ; x[0] := 0 ; { first Huffman code is zero } p := Addr(v) ; { grab values in bit order } h := -1 ; { no tables yet--level -1 } w := -l ; { bits decoded = (l*h) } u[0] := pInflate_huft(NIL); { just to keep compilers happy } q := pInflate_huft(NIL); { ditto } z := 0 ; { ditto } { go through the bit lengths (k already is bits in shortest code) } while (k <= g) Do begin a := c[k] ; while (a<>0) Do begin Dec (a) ; { here i is the Huffman code of length k bits for value p^ } { make tables up to required level } while (k > w + l) do begin Inc (h) ; Inc (w, l); { add bits already decoded } { previous table always l bits } { compute minimum size table less than or equal to l bits } { table size upper limit } z := g - w; If (z > uInt(l)) Then z := l; { try a k-w bit table } j := k - w; f := 1 shl j; if (f > a+1) Then { too few codes for k-w bit table } begin Dec(f, a+1); { deduct codes from patterns left } {$IFDEF USE_PTR} xp := Addr(c[k]); if (j < z) then begin Inc(j); while (j < z) do begin { try smaller tables up to z bits } f := f shl 1; Inc (xp) ; If (f <= xp^) Then break; { enough codes to use up j bits } Dec(f, xp^); { else deduct codes from patterns } Inc(j); end; end; {$ELSE} xp := k; if (j < z) then begin Inc (j) ; While (j < z) Do begin { try smaller tables up to z bits } f := f * 2; Inc (xp) ; if (f <= c[xp]) then Break ; { enough codes to use up j bits } Dec (f, c[xp]) ; { else deduct codes from patterns } Inc (j); end; end; {$ENDIF} end; z := 1 shl j; { table entries for j-bit table } { allocate new table } if (hn + z > MANY) then { (note: doesn't matter for fixed) } begin huft_build := Z_MEM_ERROR; { not enough memory } exit; end; q := @hp[hn]; u[h] := q; Inc(hn, z); { connect to last table, if there is one } if (h <> 0) then begin x[h] := i; { save pattern for backing up } r.bits := Byte(l); { bits to dump before this table } r.exop := Byte(j); { bits in this table } j := i shr (w - l); {r.base := uInt( q - u[h-1] -j);} { offset to this table } r.base := (ptr2int(q) - ptr2int(u[h-1]) ) div sizeof(q^) - j; huft_Ptr(u[h-1])^[j] := r; { connect to last table } end else t^ := q; { first table is returned result } end; { set up table entry in r } r.bits := Byte(k - w); { C-code: if (p >= v + n) - see ZUTIL.PAS for comments } if ptr2int(p)>=ptr2int(@(v[n])) then { also works under DPMI ?? } r.exop := 128 + 64 { out of values--invalid code } else if (p^ < s) then begin if (p^ < 256) then { 256 is end-of-block code } r.exop := 0 Else r.exop := 32 + 64; { EOB_code; } r.base := p^; { simple code is just the value } Inc(p); end Else begin r.exop := Byte(e[p^-s] + 16 + 64); { non-simple--look up in lists } r.base := d[p^-s]; Inc (p); end ; { fill code-like entries with r } f := 1 shl (k - w); j := i shr w; while (j < z) do begin huft_Ptr(q)^[j] := r; Inc(j, f); end; { backwards increment the k-bit code i } j := 1 shl (k-1) ; while (i and j) <> 0 do begin i := i xor j; { bitwise exclusive or } j := j shr 1 end ; i := i xor j; { backup over finished tables } mask := (1 shl w) - 1; { needed on HP, cc -O bug } while ((i and mask) <> x[h]) do begin Dec(h); { don't need to update q } Dec(w, l); mask := (1 shl w) - 1; end; end; Inc(k); end; { Return Z_BUF_ERROR if we were given an incomplete table } if (y <> 0) And (g <> 1) then huft_build := Z_BUF_ERROR else huft_build := Z_OK; end; { huft_build} function inflate_trees_bits( var c : array of uIntf; { 19 code lengths } var bb : uIntf; { bits tree desired/actual depth } var tb : pinflate_huft; { bits tree result } var hp : array of Inflate_huft; { space for trees } var z : z_stream { for messages } ) : int; var r : int; hn : uInt; { hufts used in space } v : PuIntArray; { work area for huft_build } begin hn := 0; v := PuIntArray( ZALLOC(z, 19, sizeof(uInt)) ); if (v = Z_NULL) then begin inflate_trees_bits := Z_MEM_ERROR; exit; end; r := huft_build(c, 19, 19, cplens, cplext, {puIntf(Z_NULL), puIntf(Z_NULL),} @tb, bb, hp, hn, v^); if (r = Z_DATA_ERROR) then z.msg := 'oversubscribed dynamic bit lengths tree' else if (r = Z_BUF_ERROR) or (bb = 0) then begin z.msg := 'incomplete dynamic bit lengths tree'; r := Z_DATA_ERROR; end; ZFREE(z, v); inflate_trees_bits := r; end; function inflate_trees_dynamic( nl : uInt; { number of literal/length codes } nd : uInt; { number of distance codes } var c : Array of uIntf; { that many (total) code lengths } var bl : uIntf; { literal desired/actual bit depth } var bd : uIntf; { distance desired/actual bit depth } var tl : pInflate_huft; { literal/length tree result } var td : pInflate_huft; { distance tree result } var hp : array of Inflate_huft; { space for trees } var z : z_stream { for messages } ) : int; var r : int; hn : uInt; { hufts used in space } v : PuIntArray; { work area for huft_build } begin hn := 0; { allocate work area } v := PuIntArray( ZALLOC(z, 288, sizeof(uInt)) ); if (v = Z_NULL) then begin inflate_trees_dynamic := Z_MEM_ERROR; exit; end; { build literal/length tree } r := huft_build(c, nl, 257, cplens, cplext, @tl, bl, hp, hn, v^); if (r <> Z_OK) or (bl = 0) then begin if (r = Z_DATA_ERROR) then z.msg := 'oversubscribed literal/length tree' else if (r <> Z_MEM_ERROR) then begin z.msg := 'incomplete literal/length tree'; r := Z_DATA_ERROR; end; ZFREE(z, v); inflate_trees_dynamic := r; exit; end; { build distance tree } r := huft_build(puIntArray(@c[nl])^, nd, 0, cpdist, cpdext, @td, bd, hp, hn, v^); if (r <> Z_OK) or ((bd = 0) and (nl > 257)) then begin if (r = Z_DATA_ERROR) then z.msg := 'oversubscribed literal/length tree' else if (r = Z_BUF_ERROR) then begin {$ifdef PKZIP_BUG_WORKAROUND} r := Z_OK; end; {$else} z.msg := 'incomplete literal/length tree'; r := Z_DATA_ERROR; end else if (r <> Z_MEM_ERROR) then begin z.msg := 'empty distance tree with lengths'; r := Z_DATA_ERROR; end; ZFREE(z, v); inflate_trees_dynamic := r; exit; {$endif} end; { done } ZFREE(z, v); inflate_trees_dynamic := Z_OK; end; {$UNDEF BUILDFIXED} { build fixed tables only once--keep them here } {$IFNDEF BUILDFIXED} { locals } var fixed_built : Boolean = false; const FIXEDH = 544; { number of hufts used by fixed tables } var fixed_mem : array[0..FIXEDH-1] of inflate_huft; fixed_bl : uInt; fixed_bd : uInt; fixed_tl : pInflate_huft; fixed_td : pInflate_huft; {$ELSE} { inffixed.h -- table for decoding fixed codes } {local} const fixed_bl = uInt(9); {local} const fixed_bd = uInt(5); {local} const fixed_tl : array [0..288-1] of inflate_huft = ( Exop, { number of extra bits or operation } bits : Byte; { number of bits in this code or subcode } {pad : uInt;} { pad structure to a power of 2 (4 bytes for } { 16-bit, 8 bytes for 32-bit int's) } base : uInt; { literal, length base, or distance base } { or table offset } ((96,7),256), ((0,8),80), ((0,8),16), ((84,8),115), ((82,7),31), ((0,8),112), ((0,8),48), ((0,9),192), ((80,7),10), ((0,8),96), ((0,8),32), ((0,9),160), ((0,8),0), ((0,8),128), ((0,8),64), ((0,9),224), ((80,7),6), ((0,8),88), ((0,8),24), ((0,9),144), ((83,7),59), ((0,8),120), ((0,8),56), ((0,9),208), ((81,7),17), ((0,8),104), ((0,8),40), ((0,9),176), ((0,8),8), ((0,8),136), ((0,8),72), ((0,9),240), ((80,7),4), ((0,8),84), ((0,8),20), ((85,8),227), ((83,7),43), ((0,8),116), ((0,8),52), ((0,9),200), ((81,7),13), ((0,8),100), ((0,8),36), ((0,9),168), ((0,8),4), ((0,8),132), ((0,8),68), ((0,9),232), ((80,7),8), ((0,8),92), ((0,8),28), ((0,9),152), ((84,7),83), ((0,8),124), ((0,8),60), ((0,9),216), ((82,7),23), ((0,8),108), ((0,8),44), ((0,9),184), ((0,8),12), ((0,8),140), ((0,8),76), ((0,9),248), ((80,7),3), ((0,8),82), ((0,8),18), ((85,8),163), ((83,7),35), ((0,8),114), ((0,8),50), ((0,9),196), ((81,7),11), ((0,8),98), ((0,8),34), ((0,9),164), ((0,8),2), ((0,8),130), ((0,8),66), ((0,9),228), ((80,7),7), ((0,8),90), ((0,8),26), ((0,9),148), ((84,7),67), ((0,8),122), ((0,8),58), ((0,9),212), ((82,7),19), ((0,8),106), ((0,8),42), ((0,9),180), ((0,8),10), ((0,8),138), ((0,8),74), ((0,9),244), ((80,7),5), ((0,8),86), ((0,8),22), ((192,8),0), ((83,7),51), ((0,8),118), ((0,8),54), ((0,9),204), ((81,7),15), ((0,8),102), ((0,8),38), ((0,9),172), ((0,8),6), ((0,8),134), ((0,8),70), ((0,9),236), ((80,7),9), ((0,8),94), ((0,8),30), ((0,9),156), ((84,7),99), ((0,8),126), ((0,8),62), ((0,9),220), ((82,7),27), ((0,8),110), ((0,8),46), ((0,9),188), ((0,8),14), ((0,8),142), ((0,8),78), ((0,9),252), ((96,7),256), ((0,8),81), ((0,8),17), ((85,8),131), ((82,7),31), ((0,8),113), ((0,8),49), ((0,9),194), ((80,7),10), ((0,8),97), ((0,8),33), ((0,9),162), ((0,8),1), ((0,8),129), ((0,8),65), ((0,9),226), ((80,7),6), ((0,8),89), ((0,8),25), ((0,9),146), ((83,7),59), ((0,8),121), ((0,8),57), ((0,9),210), ((81,7),17), ((0,8),105), ((0,8),41), ((0,9),178), ((0,8),9), ((0,8),137), ((0,8),73), ((0,9),242), ((80,7),4), ((0,8),85), ((0,8),21), ((80,8),258), ((83,7),43), ((0,8),117), ((0,8),53), ((0,9),202), ((81,7),13), ((0,8),101), ((0,8),37), ((0,9),170), ((0,8),5), ((0,8),133), ((0,8),69), ((0,9),234), ((80,7),8), ((0,8),93), ((0,8),29), ((0,9),154), ((84,7),83), ((0,8),125), ((0,8),61), ((0,9),218), ((82,7),23), ((0,8),109), ((0,8),45), ((0,9),186), ((0,8),13), ((0,8),141), ((0,8),77), ((0,9),250), ((80,7),3), ((0,8),83), ((0,8),19), ((85,8),195), ((83,7),35), ((0,8),115), ((0,8),51), ((0,9),198), ((81,7),11), ((0,8),99), ((0,8),35), ((0,9),166), ((0,8),3), ((0,8),131), ((0,8),67), ((0,9),230), ((80,7),7), ((0,8),91), ((0,8),27), ((0,9),150), ((84,7),67), ((0,8),123), ((0,8),59), ((0,9),214), ((82,7),19), ((0,8),107), ((0,8),43), ((0,9),182), ((0,8),11), ((0,8),139), ((0,8),75), ((0,9),246), ((80,7),5), ((0,8),87), ((0,8),23), ((192,8),0), ((83,7),51), ((0,8),119), ((0,8),55), ((0,9),206), ((81,7),15), ((0,8),103), ((0,8),39), ((0,9),174), ((0,8),7), ((0,8),135), ((0,8),71), ((0,9),238), ((80,7),9), ((0,8),95), ((0,8),31), ((0,9),158), ((84,7),99), ((0,8),127), ((0,8),63), ((0,9),222), ((82,7),27), ((0,8),111), ((0,8),47), ((0,9),190), ((0,8),15), ((0,8),143), ((0,8),79), ((0,9),254), ((96,7),256), ((0,8),80), ((0,8),16), ((84,8),115), ((82,7),31), ((0,8),112), ((0,8),48), ((0,9),193), ((80,7),10), ((0,8),96), ((0,8),32), ((0,9),161), ((0,8),0), ((0,8),128), ((0,8),64), ((0,9),225), ((80,7),6), ((0,8),88), ((0,8),24), ((0,9),145), ((83,7),59), ((0,8),120), ((0,8),56), ((0,9),209), ((81,7),17), ((0,8),104), ((0,8),40), ((0,9),177), ((0,8),8), ((0,8),136), ((0,8),72), ((0,9),241), ((80,7),4), ((0,8),84), ((0,8),20), ((85,8),227), ((83,7),43), ((0,8),116), ((0,8),52), ((0,9),201), ((81,7),13), ((0,8),100), ((0,8),36), ((0,9),169), ((0,8),4), ((0,8),132), ((0,8),68), ((0,9),233), ((80,7),8), ((0,8),92), ((0,8),28), ((0,9),153), ((84,7),83), ((0,8),124), ((0,8),60), ((0,9),217), ((82,7),23), ((0,8),108), ((0,8),44), ((0,9),185), ((0,8),12), ((0,8),140), ((0,8),76), ((0,9),249), ((80,7),3), ((0,8),82), ((0,8),18), ((85,8),163), ((83,7),35), ((0,8),114), ((0,8),50), ((0,9),197), ((81,7),11), ((0,8),98), ((0,8),34), ((0,9),165), ((0,8),2), ((0,8),130), ((0,8),66), ((0,9),229), ((80,7),7), ((0,8),90), ((0,8),26), ((0,9),149), ((84,7),67), ((0,8),122), ((0,8),58), ((0,9),213), ((82,7),19), ((0,8),106), ((0,8),42), ((0,9),181), ((0,8),10), ((0,8),138), ((0,8),74), ((0,9),245), ((80,7),5), ((0,8),86), ((0,8),22), ((192,8),0), ((83,7),51), ((0,8),118), ((0,8),54), ((0,9),205), ((81,7),15), ((0,8),102), ((0,8),38), ((0,9),173), ((0,8),6), ((0,8),134), ((0,8),70), ((0,9),237), ((80,7),9), ((0,8),94), ((0,8),30), ((0,9),157), ((84,7),99), ((0,8),126), ((0,8),62), ((0,9),221), ((82,7),27), ((0,8),110), ((0,8),46), ((0,9),189), ((0,8),14), ((0,8),142), ((0,8),78), ((0,9),253), ((96,7),256), ((0,8),81), ((0,8),17), ((85,8),131), ((82,7),31), ((0,8),113), ((0,8),49), ((0,9),195), ((80,7),10), ((0,8),97), ((0,8),33), ((0,9),163), ((0,8),1), ((0,8),129), ((0,8),65), ((0,9),227), ((80,7),6), ((0,8),89), ((0,8),25), ((0,9),147), ((83,7),59), ((0,8),121), ((0,8),57), ((0,9),211), ((81,7),17), ((0,8),105), ((0,8),41), ((0,9),179), ((0,8),9), ((0,8),137), ((0,8),73), ((0,9),243), ((80,7),4), ((0,8),85), ((0,8),21), ((80,8),258), ((83,7),43), ((0,8),117), ((0,8),53), ((0,9),203), ((81,7),13), ((0,8),101), ((0,8),37), ((0,9),171), ((0,8),5), ((0,8),133), ((0,8),69), ((0,9),235), ((80,7),8), ((0,8),93), ((0,8),29), ((0,9),155), ((84,7),83), ((0,8),125), ((0,8),61), ((0,9),219), ((82,7),23), ((0,8),109), ((0,8),45), ((0,9),187), ((0,8),13), ((0,8),141), ((0,8),77), ((0,9),251), ((80,7),3), ((0,8),83), ((0,8),19), ((85,8),195), ((83,7),35), ((0,8),115), ((0,8),51), ((0,9),199), ((81,7),11), ((0,8),99), ((0,8),35), ((0,9),167), ((0,8),3), ((0,8),131), ((0,8),67), ((0,9),231), ((80,7),7), ((0,8),91), ((0,8),27), ((0,9),151), ((84,7),67), ((0,8),123), ((0,8),59), ((0,9),215), ((82,7),19), ((0,8),107), ((0,8),43), ((0,9),183), ((0,8),11), ((0,8),139), ((0,8),75), ((0,9),247), ((80,7),5), ((0,8),87), ((0,8),23), ((192,8),0), ((83,7),51), ((0,8),119), ((0,8),55), ((0,9),207), ((81,7),15), ((0,8),103), ((0,8),39), ((0,9),175), ((0,8),7), ((0,8),135), ((0,8),71), ((0,9),239), ((80,7),9), ((0,8),95), ((0,8),31), ((0,9),159), ((84,7),99), ((0,8),127), ((0,8),63), ((0,9),223), ((82,7),27), ((0,8),111), ((0,8),47), ((0,9),191), ((0,8),15), ((0,8),143), ((0,8),79), ((0,9),255) ); {local} const fixed_td : array[0..32-1] of inflate_huft = ( (Exop:80;bits:5;base:1), (Exop:87;bits:5;base:257), (Exop:83;bits:5;base:17), (Exop:91;bits:5;base:4097), (Exop:81;bits:5;base), (Exop:89;bits:5;base:1025), (Exop:85;bits:5;base:65), (Exop:93;bits:5;base:16385), (Exop:80;bits:5;base:3), (Exop:88;bits:5;base:513), (Exop:84;bits:5;base:33), (Exop:92;bits:5;base:8193), (Exop:82;bits:5;base:9), (Exop:90;bits:5;base:2049), (Exop:86;bits:5;base:129), (Exop:192;bits:5;base:24577), (Exop:80;bits:5;base:2), (Exop:87;bits:5;base:385), (Exop:83;bits:5;base:25), (Exop:91;bits:5;base:6145), (Exop:81;bits:5;base:7), (Exop:89;bits:5;base:1537), (Exop:85;bits:5;base:97), (Exop:93;bits:5;base:24577), (Exop:80;bits:5;base:4), (Exop:88;bits:5;base:769), (Exop:84;bits:5;base:49), (Exop:92;bits:5;base:12289), (Exop:82;bits:5;base:13), (Exop:90;bits:5;base:3073), (Exop:86;bits:5;base:193), (Exop:192;bits:5;base:24577) ); {$ENDIF} function inflate_trees_fixed( var bl : uInt; { literal desired/actual bit depth } var bd : uInt; { distance desired/actual bit depth } var tl : pInflate_huft; { literal/length tree result } var td : pInflate_huft; { distance tree result } var z : z_stream { for memory allocation } ) : int; type pFixed_table = ^fixed_table; fixed_table = array[0..288-1] of uIntf; var k : int; { temporary variable } c : pFixed_table; { length list for huft_build } v : PuIntArray; { work area for huft_build } var f : uInt; { number of hufts used in fixed_mem } begin { build fixed tables if not already (multiple overlapped executions ok) } if not fixed_built then begin f := 0; { allocate memory } c := pFixed_table( ZALLOC(z, 288, sizeof(uInt)) ); if (c = Z_NULL) then begin inflate_trees_fixed := Z_MEM_ERROR; exit; end; v := PuIntArray( ZALLOC(z, 288, sizeof(uInt)) ); if (v = Z_NULL) then begin ZFREE(z, c); inflate_trees_fixed := Z_MEM_ERROR; exit; end; { literal table } for k := 0 to Pred(144) do c^[k] := 8; for k := 144 to Pred(256) do c^[k] := 9; for k := 256 to Pred(280) do c^[k] := 7; for k := 280 to Pred(288) do c^[k] := 8; fixed_bl := 9; huft_build(c^, 288, 257, cplens, cplext, @fixed_tl, fixed_bl, fixed_mem, f, v^); { distance table } for k := 0 to Pred(30) do c^[k] := 5; fixed_bd := 5; huft_build(c^, 30, 0, cpdist, cpdext, @fixed_td, fixed_bd, fixed_mem, f, v^); { done } ZFREE(z, v); ZFREE(z, c); fixed_built := True; end; bl := fixed_bl; bd := fixed_bd; tl := fixed_tl; td := fixed_td; inflate_trees_fixed := Z_OK; end; { inflate_trees_fixed } end. ================================================ FILE: lib/Imaging/ZLib/iminfutil.pas ================================================ Unit iminfutil; { types and macros common to blocks and codes Copyright (C) 1995-1998 Mark Adler WARNING: this file should *not* be used by applications. It is part of the implementation of the compression library and is subject to change. Pascal tranlastion Copyright (C) 1998 by Jacques Nomssi Nzali For conditions of distribution and use, see copyright notice in readme.txt } interface {$I imzconf.inc} uses imzutil, impaszlib; { copy as much as possible from the sliding window to the output area } function inflate_flush(var s : inflate_blocks_state; var z : z_stream; r : int) : int; { And'ing with mask[n] masks the lower n bits } const inflate_mask : array[0..17-1] of uInt = ( $0000, $0001, $0003, $0007, $000f, $001f, $003f, $007f, $00ff, $01ff, $03ff, $07ff, $0fff, $1fff, $3fff, $7fff, $ffff); {procedure GRABBITS(j : int);} {procedure DUMPBITS(j : int);} {procedure NEEDBITS(j : int);} implementation { macros for bit input with no checking and for returning unused bytes } procedure GRABBITS(j : int); begin {while (k < j) do begin Dec(z^.avail_in); Inc(z^.total_in); b := b or (uLong(z^.next_in^) shl k); Inc(z^.next_in); Inc(k, 8); end;} end; procedure DUMPBITS(j : int); begin {b := b shr j; Dec(k, j);} end; procedure NEEDBITS(j : int); begin (* while (k < j) do begin {NEEDBYTE;} if (n <> 0) then r :=Z_OK else begin {UPDATE} s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, LongInt(p)-LongInt(z.next_in)); z.next_in := p; s.write := q; result := inflate_flush(s,z,r); exit; end; Dec(n); b := b or (uLong(p^) shl k); Inc(p); Inc(k, 8); end; *) end; procedure NEEDOUT; begin (* if (m = 0) then begin {WRAP} if (q = s.zend) and (s.read <> s.window) then begin q := s.window; if LongInt(q) < LongInt(s.read) then m := uInt(LongInt(s.read)-LongInt(q)-1) else m := uInt(LongInt(s.zend)-LongInt(q)); end; if (m = 0) then begin {FLUSH} s.write := q; r := inflate_flush(s,z,r); q := s.write; if LongInt(q) < LongInt(s.read) then m := uInt(LongInt(s.read)-LongInt(q)-1) else m := uInt(LongInt(s.zend)-LongInt(q)); {WRAP} if (q = s.zend) and (s.read <> s.window) then begin q := s.window; if LongInt(q) < LongInt(s.read) then m := uInt(LongInt(s.read)-LongInt(q)-1) else m := uInt(LongInt(s.zend)-LongInt(q)); end; if (m = 0) then begin {UPDATE} s.bitb := b; s.bitk := k; z.avail_in := n; Inc(z.total_in, LongInt(p)-LongInt(z.next_in)); z.next_in := p; s.write := q; result := inflate_flush(s,z,r); exit; end; end; end; r := Z_OK; *) end; { copy as much as possible from the sliding window to the output area } function inflate_flush(var s : inflate_blocks_state; var z : z_stream; r : int) : int; var n : uInt; p : pBytef; q : pBytef; begin { local copies of source and destination pointers } p := z.next_out; q := s.read; { compute number of bytes to copy as far as end of window } if ptr2int(q) <= ptr2int(s.write) then n := uInt(ptr2int(s.write) - ptr2int(q)) else n := uInt(ptr2int(s.zend) - ptr2int(q)); if (n > z.avail_out) then n := z.avail_out; if (n <> 0) and (r = Z_BUF_ERROR) then r := Z_OK; { update counters } Dec(z.avail_out, n); Inc(z.total_out, n); { update check information } if Assigned(s.checkfn) then begin s.check := s.checkfn(s.check, q, n); z.adler := s.check; end; { copy as far as end of window } zmemcpy(p, q, n); Inc(p, n); Inc(q, n); { see if more to copy at beginning of window } if (q = s.zend) then begin { wrap pointers } q := s.window; if (s.write = s.zend) then s.write := s.window; { compute bytes to copy } n := uInt(ptr2int(s.write) - ptr2int(q)); if (n > z.avail_out) then n := z.avail_out; if (n <> 0) and (r = Z_BUF_ERROR) then r := Z_OK; { update counters } Dec( z.avail_out, n); Inc( z.total_out, n); { update check information } if Assigned(s.checkfn) then begin s.check := s.checkfn(s.check, q, n); z.adler := s.check; end; { copy } zmemcpy(p, q, n); Inc(p, n); Inc(q, n); end; { update pointers } z.next_out := p; s.read := q; { done } inflate_flush := r; end; end. ================================================ FILE: lib/Imaging/ZLib/impaszlib.pas ================================================ Unit impaszlib; { Original: zlib.h -- interface of the 'zlib' general purpose compression library version 1.1.0, Feb 24th, 1998 Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Jean-loup Gailly Mark Adler jloup@gzip.org madler@alumni.caltech.edu The data format used by the zlib library is described by RFCs (Request for Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). Pascal tranlastion Copyright (C) 1998 by Jacques Nomssi Nzali For conditions of distribution and use, see copyright notice in readme.txt } interface {$I imzconf.inc} uses imzutil; { zconf.h -- configuration of the zlib compression library } { zutil.c -- target dependent utility functions for the compression library } { The 'zlib' compression library provides in-memory compression and decompression functions, including integrity checks of the uncompressed data. This version of the library supports only one compression method (deflation) but other algorithms will be added later and will have the same stream interface. Compression can be done in a single step if the buffers are large enough (for example if an input file is mmap'ed), or can be done by repeated calls of the compression function. In the latter case, the application must provide more input and/or consume the output (providing more output space) before each call. The library also supports reading and writing files in gzip (.gz) format with an interface similar to that of stdio. The library does not install any signal handler. The decoder checks the consistency of the compressed data, so the library should never crash even in case of corrupted input. } { Compile with -DMAXSEG_64K if the alloc function cannot allocate more than 64k bytes at a time (needed on systems with 16-bit int). } { Maximum value for memLevel in deflateInit2 } const MAX_MEM_LEVEL = 9; DEF_MEM_LEVEL = 8; { if MAX_MEM_LEVEL > 8 } { Maximum value for windowBits in deflateInit2 and inflateInit2 } const MAX_WBITS = 15; { 32K LZ77 window } { default windowBits for decompression. MAX_WBITS is for compression only } const DEF_WBITS = MAX_WBITS; { The memory requirements for deflate are (in bytes): 1 shl (windowBits+2) + 1 shl (memLevel+9) that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) plus a few kilobytes for small objects. For example, if you want to reduce the default memory requirements from 256K to 128K, compile with DMAX_WBITS=14 DMAX_MEM_LEVEL=7 Of course this will generally degrade compression (there's no free lunch). The memory requirements for inflate are (in bytes) 1 shl windowBits that is, 32K for windowBits=15 (default value) plus a few kilobytes for small objects. } { Huffman code lookup table entry--this entry is four bytes for machines that have 16-bit pointers (e.g. PC's in the small or medium model). } type pInflate_huft = ^inflate_huft; inflate_huft = Record Exop, { number of extra bits or operation } bits : Byte; { number of bits in this code or subcode } {pad : uInt;} { pad structure to a power of 2 (4 bytes for } { 16-bit, 8 bytes for 32-bit int's) } base : uInt; { literal, length base, or distance base } { or table offset } End; type huft_field = Array[0..(MaxInt div SizeOf(inflate_huft))-1] of inflate_huft; huft_ptr = ^huft_field; type ppInflate_huft = ^pInflate_huft; type inflate_codes_mode = ( { waiting for "i:"=input, "o:"=output, "x:"=nothing } START, { x: set up for LEN } LEN, { i: get length/literal/eob next } LENEXT, { i: getting length extra (have base) } DIST, { i: get distance next } DISTEXT, { i: getting distance extra } COPY, { o: copying bytes in window, waiting for space } LIT, { o: got literal, waiting for output space } WASH, { o: got eob, possibly still output waiting } ZEND, { x: got eob and all data flushed } BADCODE); { x: got error } { inflate codes private state } type pInflate_codes_state = ^inflate_codes_state; inflate_codes_state = record mode : inflate_codes_mode; { current inflate_codes mode } { mode dependent information } len : uInt; sub : record { submode } Case Byte of 0:(code : record { if LEN or DIST, where in tree } tree : pInflate_huft; { pointer into tree } need : uInt; { bits needed } end); 1:(lit : uInt); { if LIT, literal } 2:(copy: record { if EXT or COPY, where and how much } get : uInt; { bits to get for extra } dist : uInt; { distance back to copy from } end); end; { mode independent information } lbits : Byte; { ltree bits decoded per branch } dbits : Byte; { dtree bits decoder per branch } ltree : pInflate_huft; { literal/length/eob tree } dtree : pInflate_huft; { distance tree } end; type check_func = function(check : uLong; buf : pBytef; {const buf : array of byte;} len : uInt) : uLong; type inflate_block_mode = (ZTYPE, { get type bits (3, including end bit) } LENS, { get lengths for stored } STORED, { processing stored block } TABLE, { get table lengths } BTREE, { get bit lengths tree for a dynamic block } DTREE, { get length, distance trees for a dynamic block } CODES, { processing fixed or dynamic block } DRY, { output remaining window bytes } BLKDONE, { finished last block, done } BLKBAD); { got a data error--stuck here } type pInflate_blocks_state = ^inflate_blocks_state; { inflate blocks semi-private state } inflate_blocks_state = record mode : inflate_block_mode; { current inflate_block mode } { mode dependent information } sub : record { submode } case Byte of 0:(left : uInt); { if STORED, bytes left to copy } 1:(trees : record { if DTREE, decoding info for trees } table : uInt; { table lengths (14 bits) } index : uInt; { index into blens (or border) } blens : PuIntArray; { bit lengths of codes } bb : uInt; { bit length tree depth } tb : pInflate_huft; { bit length decoding tree } end); 2:(decode : record { if CODES, current state } tl : pInflate_huft; td : pInflate_huft; { trees to free } codes : pInflate_codes_state; end); end; last : boolean; { true if this block is the last block } { mode independent information } bitk : uInt; { bits in bit buffer } bitb : uLong; { bit buffer } hufts : huft_ptr; {pInflate_huft;} { single malloc for tree space } window : pBytef; { sliding window } zend : pBytef; { one byte after sliding window } read : pBytef; { window read pointer } write : pBytef; { window write pointer } checkfn : check_func; { check function } check : uLong; { check on output } end; type inflate_mode = ( METHOD, { waiting for method byte } FLAG, { waiting for flag byte } DICT4, { four dictionary check bytes to go } DICT3, { three dictionary check bytes to go } DICT2, { two dictionary check bytes to go } DICT1, { one dictionary check byte to go } DICT0, { waiting for inflateSetDictionary } BLOCKS, { decompressing blocks } CHECK4, { four check bytes to go } CHECK3, { three check bytes to go } CHECK2, { two check bytes to go } CHECK1, { one check byte to go } DONE, { finished check, done } BAD); { got an error--stay here } { inflate private state } type pInternal_state = ^internal_state; { or point to a deflate_state record } internal_state = record mode : inflate_mode; { current inflate mode } { mode dependent information } sub : record { submode } case byte of 0:(method : uInt); { if FLAGS, method byte } 1:(check : record { if CHECK, check values to compare } was : uLong; { computed check value } need : uLong; { stream check value } end); 2:(marker : uInt); { if BAD, inflateSync's marker bytes count } end; { mode independent information } nowrap : boolean; { flag for no wrapper } wbits : uInt; { log2(window size) (8..15, defaults to 15) } blocks : pInflate_blocks_state; { current inflate_blocks state } end; type alloc_func = function(opaque : voidpf; items : uInt; size : uInt) : voidpf; free_func = procedure(opaque : voidpf; address : voidpf); type z_streamp = ^z_stream; z_stream = record next_in : pBytef; { next input byte } avail_in : uInt; { number of bytes available at next_in } total_in : uLong; { total nb of input bytes read so far } next_out : pBytef; { next output byte should be put there } avail_out : uInt; { remaining free space at next_out } total_out : uLong; { total nb of bytes output so far } msg : string[255]; { last error message, '' if no error } state : pInternal_state; { not visible by applications } zalloc : alloc_func; { used to allocate the internal state } zfree : free_func; { used to free the internal state } opaque : voidpf; { private data object passed to zalloc and zfree } data_type : int; { best guess about the data type: ascii or binary } adler : uLong; { adler32 value of the uncompressed data } reserved : uLong; { reserved for future use } end; { The application must update next_in and avail_in when avail_in has dropped to zero. It must update next_out and avail_out when avail_out has dropped to zero. The application must initialize zalloc, zfree and opaque before calling the init function. All other fields are set by the compression library and must not be updated by the application. The opaque value provided by the application will be passed as the first parameter for calls of zalloc and zfree. This can be useful for custom memory management. The compression library attaches no meaning to the opaque value. zalloc must return Z_NULL if there is not enough memory for the object. On 16-bit systems, the functions zalloc and zfree must be able to allocate exactly 65536 bytes, but will not be required to allocate more than this if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers returned by zalloc for objects of exactly 65536 bytes *must* have their offset normalized to zero. The default allocation function provided by this library ensures this (see zutil.c). To reduce memory requirements and avoid any allocation of 64K objects, at the expense of compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). The fields total_in and total_out can be used for statistics or progress reports. After compression, total_in holds the total size of the uncompressed data and may be saved for use in the decompressor (particularly if the decompressor wants to decompress everything in a single step). } const { constants } Z_NO_FLUSH = 0; Z_PARTIAL_FLUSH = 1; Z_SYNC_FLUSH = 2; Z_FULL_FLUSH = 3; Z_FINISH = 4; { Allowed flush values; see deflate() below for details } Z_OK = 0; Z_STREAM_END = 1; Z_NEED_DICT = 2; Z_ERRNO = (-1); Z_STREAM_ERROR = (-2); Z_DATA_ERROR = (-3); Z_MEM_ERROR = (-4); Z_BUF_ERROR = (-5); Z_VERSION_ERROR = (-6); { Return codes for the compression/decompression functions. Negative values are errors, positive values are used for special but normal events.} Z_NO_COMPRESSION = 0; Z_BEST_SPEED = 1; Z_BEST_COMPRESSION = 9; Z_DEFAULT_COMPRESSION = (-1); { compression levels } Z_FILTERED = 1; Z_HUFFMAN_ONLY = 2; Z_DEFAULT_STRATEGY = 0; { compression strategy; see deflateInit2() below for details } Z_BINARY = 0; Z_ASCII = 1; Z_UNKNOWN = 2; { Possible values of the data_type field } Z_DEFLATED = 8; { The deflate compression method (the only one supported in this version) } Z_NULL = NIL; { for initializing zalloc, zfree, opaque } {$IFDEF GZIO} var errno : int; {$ENDIF} { common constants } { The three kinds of block type } const STORED_BLOCK = 0; STATIC_TREES = 1; DYN_TREES = 2; { The minimum and maximum match lengths } const MIN_MATCH = 3; MAX_MATCH = 258; const PRESET_DICT = $20; { preset dictionary flag in zlib header } {$IFDEF DEBUG} procedure Assert(cond : boolean; msg : AnsiString); {$ENDIF} procedure Trace(x : AnsiString); procedure Tracev(x : AnsiString); procedure Tracevv(x : AnsiString); procedure Tracevvv(x : AnsiString); procedure Tracec(c : boolean; x : AnsiString); procedure Tracecv(c : boolean; x : AnsiString); function zlibVersion : AnsiString; { The application can compare zlibVersion and ZLIB_VERSION for consistency. If the first character differs, the library code actually used is not compatible with the zlib.h header file used by the application. This check is automatically made by deflateInit and inflateInit. } function zError(err : int) : AnsiString; function ZALLOC (var strm : z_stream; items : uInt; size : uInt) : voidpf; procedure ZFREE (var strm : z_stream; ptr : voidpf); procedure TRY_FREE (var strm : z_stream; ptr : voidpf); const ZLIB_VERSION : string[10] = '1.1.2'; const z_errbase = Z_NEED_DICT; z_errmsg : Array[0..9] of string[21] = { indexed by 2-zlib_error } ('need dictionary', { Z_NEED_DICT 2 } 'stream end', { Z_STREAM_END 1 } '', { Z_OK 0 } 'file error', { Z_ERRNO (-1) } 'stream error', { Z_STREAM_ERROR (-2) } 'data error', { Z_DATA_ERROR (-3) } 'insufficient memory', { Z_MEM_ERROR (-4) } 'buffer error', { Z_BUF_ERROR (-5) } 'incompatible version',{ Z_VERSION_ERROR (-6) } ''); const z_verbose : int = 1; function deflateInit_(var Stream: z_stream; Level: LongInt; const Version: AnsiString; Stream_size: LongInt): LongInt; function inflateInit_(var Stream: z_stream; const Version: AnsiString; Stream_size: Longint): LongInt; {$IFDEF DEBUG} procedure z_error (m : string); {$ENDIF} implementation uses imzdeflate, imzinflate; function deflateInit_(var Stream: z_stream; Level: LongInt; const Version: AnsiString; Stream_size: LongInt): LongInt; begin Result := imzdeflate.deflateInit_(@Stream, Level, Version, Stream_size); end; function inflateInit_(var Stream: z_stream; const Version: AnsiString; Stream_size: Longint): LongInt; begin Result := imzinflate.inflateInit_(@Stream, Version, Stream_size); end; function zError(err : int) : AnsiString; begin zError := z_errmsg[Z_NEED_DICT-err]; end; function zlibVersion : AnsiString; begin zlibVersion := ZLIB_VERSION; end; procedure z_error (m : AnsiString); begin WriteLn(output, m); Write('Zlib - Halt...'); ReadLn; Halt(1); end; procedure Assert(cond : boolean; msg : AnsiString); begin if not cond then z_error(msg); end; procedure Trace(x : AnsiString); begin WriteLn(x); end; procedure Tracev(x : AnsiString); begin if (z_verbose>0) then WriteLn(x); end; procedure Tracevv(x : AnsiString); begin if (z_verbose>1) then WriteLn(x); end; procedure Tracevvv(x : AnsiString); begin if (z_verbose>2) then WriteLn(x); end; procedure Tracec(c : boolean; x : AnsiString); begin if (z_verbose>0) and (c) then WriteLn(x); end; procedure Tracecv(c : boolean; x : AnsiString); begin if (z_verbose>1) and c then WriteLn(x); end; function ZALLOC (var strm : z_stream; items : uInt; size : uInt) : voidpf; begin ZALLOC := strm.zalloc(strm.opaque, items, size); end; procedure ZFREE (var strm : z_stream; ptr : voidpf); begin strm.zfree(strm.opaque, ptr); end; procedure TRY_FREE (var strm : z_stream; ptr : voidpf); begin {if @strm <> Z_NULL then} strm.zfree(strm.opaque, ptr); end; end. ================================================ FILE: lib/Imaging/ZLib/imtrees.pas ================================================ Unit imtrees; {$T-} {$define ORG_DEBUG} { trees.c -- output deflated data using Huffman coding Copyright (C) 1995-1998 Jean-loup Gailly Pascal tranlastion Copyright (C) 1998 by Jacques Nomssi Nzali For conditions of distribution and use, see copyright notice in readme.txt } { * ALGORITHM * * The "deflation" process uses several Huffman trees. The more * common source values are represented by shorter bit sequences. * * Each code tree is stored in a compressed form which is itself * a Huffman encoding of the lengths of all the code strings (in * ascending order by source values). The actual code strings are * reconstructed from the lengths in the inflate process, as described * in the deflate specification. * * REFERENCES * * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc * * Storer, James A. * Data Compression: Methods and Theory, pp. 49-50. * Computer Science Press, 1988. ISBN 0-7167-8156-5. * * Sedgewick, R. * Algorithms, p290. * Addison-Wesley, 1983. ISBN 0-201-06672-6. } interface {$I imzconf.inc} uses {$ifdef DEBUG} SysUtils, strutils, {$ENDIF} imzutil, impaszlib; { =========================================================================== Internal compression state. } const LENGTH_CODES = 29; { number of length codes, not counting the special END_BLOCK code } LITERALS = 256; { number of literal bytes 0..255 } L_CODES = (LITERALS+1+LENGTH_CODES); { number of Literal or Length codes, including the END_BLOCK code } D_CODES = 30; { number of distance codes } BL_CODES = 19; { number of codes used to transfer the bit lengths } HEAP_SIZE = (2*L_CODES+1); { maximum heap size } MAX_BITS = 15; { All codes must not exceed MAX_BITS bits } const INIT_STATE = 42; BUSY_STATE = 113; FINISH_STATE = 666; { Stream status } { Data structure describing a single value and its code string. } type ct_data_ptr = ^ct_data; ct_data = record fc : record case byte of 0:(freq : ush); { frequency count } 1:(code : ush); { bit string } end; dl : record case byte of 0:(dad : ush); { father node in Huffman tree } 1:(len : ush); { length of bit string } end; end; { Freq = fc.freq Code = fc.code Dad = dl.dad Len = dl.len } type ltree_type = array[0..HEAP_SIZE-1] of ct_data; { literal and length tree } dtree_type = array[0..2*D_CODES+1-1] of ct_data; { distance tree } htree_type = array[0..2*BL_CODES+1-1] of ct_data; { Huffman tree for bit lengths } { generic tree type } tree_type = array[0..(MaxInt div SizeOf(ct_data))-1] of ct_data; tree_ptr = ^tree_type; ltree_ptr = ^ltree_type; dtree_ptr = ^dtree_type; htree_ptr = ^htree_type; type static_tree_desc_ptr = ^static_tree_desc; static_tree_desc = record {const} static_tree : tree_ptr; { static tree or NIL } {const} extra_bits : pzIntfArray; { extra bits for each code or NIL } extra_base : int; { base index for extra_bits } elems : int; { max number of elements in the tree } max_length : int; { max bit length for the codes } end; tree_desc_ptr = ^tree_desc; tree_desc = record dyn_tree : tree_ptr; { the dynamic tree } max_code : int; { largest code with non zero frequency } stat_desc : static_tree_desc_ptr; { the corresponding static tree } end; type Pos = ush; Posf = Pos; {FAR} IPos = uInt; pPosf = ^Posf; zPosfArray = array[0..(MaxInt div SizeOf(Posf))-1] of Posf; pzPosfArray = ^zPosfArray; { A Pos is an index in the character window. We use short instead of int to save space in the various tables. IPos is used only for parameter passing.} type deflate_state_ptr = ^deflate_state; deflate_state = record strm : z_streamp; { pointer back to this zlib stream } status : int; { as the name implies } pending_buf : pzByteArray; { output still pending } pending_buf_size : ulg; { size of pending_buf } pending_out : pBytef; { next pending byte to output to the stream } pending : int; { nb of bytes in the pending buffer } noheader : int; { suppress zlib header and adler32 } data_type : Byte; { UNKNOWN, BINARY or ASCII } method : Byte; { STORED (for zip only) or DEFLATED } last_flush : int; { value of flush param for previous deflate call } { used by deflate.pas: } w_size : uInt; { LZ77 window size (32K by default) } w_bits : uInt; { log2(w_size) (8..16) } w_mask : uInt; { w_size - 1 } window : pzByteArray; { Sliding window. Input bytes are read into the second half of the window, and move to the first half later to keep a dictionary of at least wSize bytes. With this organization, matches are limited to a distance of wSize-MAX_MATCH bytes, but this ensures that IO is always performed with a length multiple of the block size. Also, it limits the window size to 64K, which is quite useful on MSDOS. To do: use the user input buffer as sliding window. } window_size : ulg; { Actual size of window: 2*wSize, except when the user input buffer is directly used as sliding window. } prev : pzPosfArray; { Link to older string with same hash index. To limit the size of this array to 64K, this link is maintained only for the last 32K strings. An index in this array is thus a window index modulo 32K. } head : pzPosfArray; { Heads of the hash chains or NIL. } ins_h : uInt; { hash index of string to be inserted } hash_size : uInt; { number of elements in hash table } hash_bits : uInt; { log2(hash_size) } hash_mask : uInt; { hash_size-1 } hash_shift : uInt; { Number of bits by which ins_h must be shifted at each input step. It must be such that after MIN_MATCH steps, the oldest byte no longer takes part in the hash key, that is: hash_shift * MIN_MATCH >= hash_bits } block_start : long; { Window position at the beginning of the current output block. Gets negative when the window is moved backwards. } match_length : uInt; { length of best match } prev_match : IPos; { previous match } match_available : boolean; { set if previous match exists } strstart : uInt; { start of string to insert } match_start : uInt; { start of matching string } lookahead : uInt; { number of valid bytes ahead in window } prev_length : uInt; { Length of the best match at previous step. Matches not greater than this are discarded. This is used in the lazy match evaluation. } max_chain_length : uInt; { To speed up deflation, hash chains are never searched beyond this length. A higher limit improves compression ratio but degrades the speed. } { moved to the end because Borland Pascal won't accept the following: max_lazy_match : uInt; max_insert_length : uInt absolute max_lazy_match; } level : int; { compression level (1..9) } strategy : int; { favor or force Huffman coding} good_match : uInt; { Use a faster search when the previous match is longer than this } nice_match : int; { Stop searching when current match exceeds this } { used by trees.pas: } { Didn't use ct_data typedef below to supress compiler warning } dyn_ltree : ltree_type; { literal and length tree } dyn_dtree : dtree_type; { distance tree } bl_tree : htree_type; { Huffman tree for bit lengths } l_desc : tree_desc; { desc. for literal tree } d_desc : tree_desc; { desc. for distance tree } bl_desc : tree_desc; { desc. for bit length tree } bl_count : array[0..MAX_BITS+1-1] of ush; { number of codes at each bit length for an optimal tree } heap : array[0..2*L_CODES+1-1] of int; { heap used to build the Huffman trees } heap_len : int; { number of elements in the heap } heap_max : int; { element of largest frequency } { The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. The same heap array is used to build all trees. } depth : array[0..2*L_CODES+1-1] of uch; { Depth of each subtree used as tie breaker for trees of equal frequency } l_buf : puchfArray; { buffer for literals or lengths } lit_bufsize : uInt; { Size of match buffer for literals/lengths. There are 4 reasons for limiting lit_bufsize to 64K: - frequencies can be kept in 16 bit counters - if compression is not successful for the first block, all input data is still in the window so we can still emit a stored block even when input comes from standard input. (This can also be done for all blocks if lit_bufsize is not greater than 32K.) - if compression is not successful for a file smaller than 64K, we can even emit a stored file instead of a stored block (saving 5 bytes). This is applicable only for zip (not gzip or zlib). - creating new Huffman trees less frequently may not provide fast adaptation to changes in the input data statistics. (Take for example a binary file with poorly compressible code followed by a highly compressible string table.) Smaller buffer sizes give fast adaptation but have of course the overhead of transmitting trees more frequently. - I can't count above 4 } last_lit : uInt; { running index in l_buf } d_buf : pushfArray; { Buffer for distances. To simplify the code, d_buf and l_buf have the same number of elements. To use different lengths, an extra flag array would be necessary. } opt_len : ulg; { bit length of current block with optimal trees } static_len : ulg; { bit length of current block with static trees } compressed_len : ulg; { total bit length of compressed file } matches : uInt; { number of string matches in current block } last_eob_len : int; { bit length of EOB code for last block } {$ifdef DEBUG} bits_sent : ulg; { bit length of the compressed data } {$endif} bi_buf : ush; { Output buffer. bits are inserted starting at the bottom (least significant bits). } bi_valid : int; { Number of valid bits in bi_buf. All bits above the last valid bit are always zero. } case byte of 0:(max_lazy_match : uInt); { Attempt to find a better match only when the current match is strictly smaller than this value. This mechanism is used only for compression levels >= 4. } 1:(max_insert_length : uInt); { Insert new strings in the hash table only if the match length is not greater than this length. This saves time but degrades compression. max_insert_length is used only for compression levels <= 3. } end; procedure _tr_init (var s : deflate_state); function _tr_tally (var s : deflate_state; dist : unsigned; lc : unsigned) : boolean; function _tr_flush_block (var s : deflate_state; buf : pcharf; stored_len : ulg; eof : boolean) : ulg; procedure _tr_align(var s : deflate_state); procedure _tr_stored_block(var s : deflate_state; buf : pcharf; stored_len : ulg; eof : boolean); implementation { #define GEN_TREES_H } {$ifndef GEN_TREES_H} { header created automatically with -DGEN_TREES_H } const DIST_CODE_LEN = 512; { see definition of array dist_code below } { The static literal tree. Since the bit lengths are imposed, there is no need for the L_CODES extra codes used during heap construction. However The codes 286 and 287 are needed to build a canonical tree (see _tr_init below). } var static_ltree : array[0..L_CODES+2-1] of ct_data = ( { fc:(freq, code) dl:(dad,len) } (fc:(freq: 12);dl:(len: 8)), (fc:(freq:140);dl:(len: 8)), (fc:(freq: 76);dl:(len: 8)), (fc:(freq:204);dl:(len: 8)), (fc:(freq: 44);dl:(len: 8)), (fc:(freq:172);dl:(len: 8)), (fc:(freq:108);dl:(len: 8)), (fc:(freq:236);dl:(len: 8)), (fc:(freq: 28);dl:(len: 8)), (fc:(freq:156);dl:(len: 8)), (fc:(freq: 92);dl:(len: 8)), (fc:(freq:220);dl:(len: 8)), (fc:(freq: 60);dl:(len: 8)), (fc:(freq:188);dl:(len: 8)), (fc:(freq:124);dl:(len: 8)), (fc:(freq:252);dl:(len: 8)), (fc:(freq: 2);dl:(len: 8)), (fc:(freq:130);dl:(len: 8)), (fc:(freq: 66);dl:(len: 8)), (fc:(freq:194);dl:(len: 8)), (fc:(freq: 34);dl:(len: 8)), (fc:(freq:162);dl:(len: 8)), (fc:(freq: 98);dl:(len: 8)), (fc:(freq:226);dl:(len: 8)), (fc:(freq: 18);dl:(len: 8)), (fc:(freq:146);dl:(len: 8)), (fc:(freq: 82);dl:(len: 8)), (fc:(freq:210);dl:(len: 8)), (fc:(freq: 50);dl:(len: 8)), (fc:(freq:178);dl:(len: 8)), (fc:(freq:114);dl:(len: 8)), (fc:(freq:242);dl:(len: 8)), (fc:(freq: 10);dl:(len: 8)), (fc:(freq:138);dl:(len: 8)), (fc:(freq: 74);dl:(len: 8)), (fc:(freq:202);dl:(len: 8)), (fc:(freq: 42);dl:(len: 8)), (fc:(freq:170);dl:(len: 8)), (fc:(freq:106);dl:(len: 8)), (fc:(freq:234);dl:(len: 8)), (fc:(freq: 26);dl:(len: 8)), (fc:(freq:154);dl:(len: 8)), (fc:(freq: 90);dl:(len: 8)), (fc:(freq:218);dl:(len: 8)), (fc:(freq: 58);dl:(len: 8)), (fc:(freq:186);dl:(len: 8)), (fc:(freq:122);dl:(len: 8)), (fc:(freq:250);dl:(len: 8)), (fc:(freq: 6);dl:(len: 8)), (fc:(freq:134);dl:(len: 8)), (fc:(freq: 70);dl:(len: 8)), (fc:(freq:198);dl:(len: 8)), (fc:(freq: 38);dl:(len: 8)), (fc:(freq:166);dl:(len: 8)), (fc:(freq:102);dl:(len: 8)), (fc:(freq:230);dl:(len: 8)), (fc:(freq: 22);dl:(len: 8)), (fc:(freq:150);dl:(len: 8)), (fc:(freq: 86);dl:(len: 8)), (fc:(freq:214);dl:(len: 8)), (fc:(freq: 54);dl:(len: 8)), (fc:(freq:182);dl:(len: 8)), (fc:(freq:118);dl:(len: 8)), (fc:(freq:246);dl:(len: 8)), (fc:(freq: 14);dl:(len: 8)), (fc:(freq:142);dl:(len: 8)), (fc:(freq: 78);dl:(len: 8)), (fc:(freq:206);dl:(len: 8)), (fc:(freq: 46);dl:(len: 8)), (fc:(freq:174);dl:(len: 8)), (fc:(freq:110);dl:(len: 8)), (fc:(freq:238);dl:(len: 8)), (fc:(freq: 30);dl:(len: 8)), (fc:(freq:158);dl:(len: 8)), (fc:(freq: 94);dl:(len: 8)), (fc:(freq:222);dl:(len: 8)), (fc:(freq: 62);dl:(len: 8)), (fc:(freq:190);dl:(len: 8)), (fc:(freq:126);dl:(len: 8)), (fc:(freq:254);dl:(len: 8)), (fc:(freq: 1);dl:(len: 8)), (fc:(freq:129);dl:(len: 8)), (fc:(freq: 65);dl:(len: 8)), (fc:(freq:193);dl:(len: 8)), (fc:(freq: 33);dl:(len: 8)), (fc:(freq:161);dl:(len: 8)), (fc:(freq: 97);dl:(len: 8)), (fc:(freq:225);dl:(len: 8)), (fc:(freq: 17);dl:(len: 8)), (fc:(freq:145);dl:(len: 8)), (fc:(freq: 81);dl:(len: 8)), (fc:(freq:209);dl:(len: 8)), (fc:(freq: 49);dl:(len: 8)), (fc:(freq:177);dl:(len: 8)), (fc:(freq:113);dl:(len: 8)), (fc:(freq:241);dl:(len: 8)), (fc:(freq: 9);dl:(len: 8)), (fc:(freq:137);dl:(len: 8)), (fc:(freq: 73);dl:(len: 8)), (fc:(freq:201);dl:(len: 8)), (fc:(freq: 41);dl:(len: 8)), (fc:(freq:169);dl:(len: 8)), (fc:(freq:105);dl:(len: 8)), (fc:(freq:233);dl:(len: 8)), (fc:(freq: 25);dl:(len: 8)), (fc:(freq:153);dl:(len: 8)), (fc:(freq: 89);dl:(len: 8)), (fc:(freq:217);dl:(len: 8)), (fc:(freq: 57);dl:(len: 8)), (fc:(freq:185);dl:(len: 8)), (fc:(freq:121);dl:(len: 8)), (fc:(freq:249);dl:(len: 8)), (fc:(freq: 5);dl:(len: 8)), (fc:(freq:133);dl:(len: 8)), (fc:(freq: 69);dl:(len: 8)), (fc:(freq:197);dl:(len: 8)), (fc:(freq: 37);dl:(len: 8)), (fc:(freq:165);dl:(len: 8)), (fc:(freq:101);dl:(len: 8)), (fc:(freq:229);dl:(len: 8)), (fc:(freq: 21);dl:(len: 8)), (fc:(freq:149);dl:(len: 8)), (fc:(freq: 85);dl:(len: 8)), (fc:(freq:213);dl:(len: 8)), (fc:(freq: 53);dl:(len: 8)), (fc:(freq:181);dl:(len: 8)), (fc:(freq:117);dl:(len: 8)), (fc:(freq:245);dl:(len: 8)), (fc:(freq: 13);dl:(len: 8)), (fc:(freq:141);dl:(len: 8)), (fc:(freq: 77);dl:(len: 8)), (fc:(freq:205);dl:(len: 8)), (fc:(freq: 45);dl:(len: 8)), (fc:(freq:173);dl:(len: 8)), (fc:(freq:109);dl:(len: 8)), (fc:(freq:237);dl:(len: 8)), (fc:(freq: 29);dl:(len: 8)), (fc:(freq:157);dl:(len: 8)), (fc:(freq: 93);dl:(len: 8)), (fc:(freq:221);dl:(len: 8)), (fc:(freq: 61);dl:(len: 8)), (fc:(freq:189);dl:(len: 8)), (fc:(freq:125);dl:(len: 8)), (fc:(freq:253);dl:(len: 8)), (fc:(freq: 19);dl:(len: 9)), (fc:(freq:275);dl:(len: 9)), (fc:(freq:147);dl:(len: 9)), (fc:(freq:403);dl:(len: 9)), (fc:(freq: 83);dl:(len: 9)), (fc:(freq:339);dl:(len: 9)), (fc:(freq:211);dl:(len: 9)), (fc:(freq:467);dl:(len: 9)), (fc:(freq: 51);dl:(len: 9)), (fc:(freq:307);dl:(len: 9)), (fc:(freq:179);dl:(len: 9)), (fc:(freq:435);dl:(len: 9)), (fc:(freq:115);dl:(len: 9)), (fc:(freq:371);dl:(len: 9)), (fc:(freq:243);dl:(len: 9)), (fc:(freq:499);dl:(len: 9)), (fc:(freq: 11);dl:(len: 9)), (fc:(freq:267);dl:(len: 9)), (fc:(freq:139);dl:(len: 9)), (fc:(freq:395);dl:(len: 9)), (fc:(freq: 75);dl:(len: 9)), (fc:(freq:331);dl:(len: 9)), (fc:(freq:203);dl:(len: 9)), (fc:(freq:459);dl:(len: 9)), (fc:(freq: 43);dl:(len: 9)), (fc:(freq:299);dl:(len: 9)), (fc:(freq:171);dl:(len: 9)), (fc:(freq:427);dl:(len: 9)), (fc:(freq:107);dl:(len: 9)), (fc:(freq:363);dl:(len: 9)), (fc:(freq:235);dl:(len: 9)), (fc:(freq:491);dl:(len: 9)), (fc:(freq: 27);dl:(len: 9)), (fc:(freq:283);dl:(len: 9)), (fc:(freq:155);dl:(len: 9)), (fc:(freq:411);dl:(len: 9)), (fc:(freq: 91);dl:(len: 9)), (fc:(freq:347);dl:(len: 9)), (fc:(freq:219);dl:(len: 9)), (fc:(freq:475);dl:(len: 9)), (fc:(freq: 59);dl:(len: 9)), (fc:(freq:315);dl:(len: 9)), (fc:(freq:187);dl:(len: 9)), (fc:(freq:443);dl:(len: 9)), (fc:(freq:123);dl:(len: 9)), (fc:(freq:379);dl:(len: 9)), (fc:(freq:251);dl:(len: 9)), (fc:(freq:507);dl:(len: 9)), (fc:(freq: 7);dl:(len: 9)), (fc:(freq:263);dl:(len: 9)), (fc:(freq:135);dl:(len: 9)), (fc:(freq:391);dl:(len: 9)), (fc:(freq: 71);dl:(len: 9)), (fc:(freq:327);dl:(len: 9)), (fc:(freq:199);dl:(len: 9)), (fc:(freq:455);dl:(len: 9)), (fc:(freq: 39);dl:(len: 9)), (fc:(freq:295);dl:(len: 9)), (fc:(freq:167);dl:(len: 9)), (fc:(freq:423);dl:(len: 9)), (fc:(freq:103);dl:(len: 9)), (fc:(freq:359);dl:(len: 9)), (fc:(freq:231);dl:(len: 9)), (fc:(freq:487);dl:(len: 9)), (fc:(freq: 23);dl:(len: 9)), (fc:(freq:279);dl:(len: 9)), (fc:(freq:151);dl:(len: 9)), (fc:(freq:407);dl:(len: 9)), (fc:(freq: 87);dl:(len: 9)), (fc:(freq:343);dl:(len: 9)), (fc:(freq:215);dl:(len: 9)), (fc:(freq:471);dl:(len: 9)), (fc:(freq: 55);dl:(len: 9)), (fc:(freq:311);dl:(len: 9)), (fc:(freq:183);dl:(len: 9)), (fc:(freq:439);dl:(len: 9)), (fc:(freq:119);dl:(len: 9)), (fc:(freq:375);dl:(len: 9)), (fc:(freq:247);dl:(len: 9)), (fc:(freq:503);dl:(len: 9)), (fc:(freq: 15);dl:(len: 9)), (fc:(freq:271);dl:(len: 9)), (fc:(freq:143);dl:(len: 9)), (fc:(freq:399);dl:(len: 9)), (fc:(freq: 79);dl:(len: 9)), (fc:(freq:335);dl:(len: 9)), (fc:(freq:207);dl:(len: 9)), (fc:(freq:463);dl:(len: 9)), (fc:(freq: 47);dl:(len: 9)), (fc:(freq:303);dl:(len: 9)), (fc:(freq:175);dl:(len: 9)), (fc:(freq:431);dl:(len: 9)), (fc:(freq:111);dl:(len: 9)), (fc:(freq:367);dl:(len: 9)), (fc:(freq:239);dl:(len: 9)), (fc:(freq:495);dl:(len: 9)), (fc:(freq: 31);dl:(len: 9)), (fc:(freq:287);dl:(len: 9)), (fc:(freq:159);dl:(len: 9)), (fc:(freq:415);dl:(len: 9)), (fc:(freq: 95);dl:(len: 9)), (fc:(freq:351);dl:(len: 9)), (fc:(freq:223);dl:(len: 9)), (fc:(freq:479);dl:(len: 9)), (fc:(freq: 63);dl:(len: 9)), (fc:(freq:319);dl:(len: 9)), (fc:(freq:191);dl:(len: 9)), (fc:(freq:447);dl:(len: 9)), (fc:(freq:127);dl:(len: 9)), (fc:(freq:383);dl:(len: 9)), (fc:(freq:255);dl:(len: 9)), (fc:(freq:511);dl:(len: 9)), (fc:(freq: 0);dl:(len: 7)), (fc:(freq: 64);dl:(len: 7)), (fc:(freq: 32);dl:(len: 7)), (fc:(freq: 96);dl:(len: 7)), (fc:(freq: 16);dl:(len: 7)), (fc:(freq: 80);dl:(len: 7)), (fc:(freq: 48);dl:(len: 7)), (fc:(freq:112);dl:(len: 7)), (fc:(freq: 8);dl:(len: 7)), (fc:(freq: 72);dl:(len: 7)), (fc:(freq: 40);dl:(len: 7)), (fc:(freq:104);dl:(len: 7)), (fc:(freq: 24);dl:(len: 7)), (fc:(freq: 88);dl:(len: 7)), (fc:(freq: 56);dl:(len: 7)), (fc:(freq:120);dl:(len: 7)), (fc:(freq: 4);dl:(len: 7)), (fc:(freq: 68);dl:(len: 7)), (fc:(freq: 36);dl:(len: 7)), (fc:(freq:100);dl:(len: 7)), (fc:(freq: 20);dl:(len: 7)), (fc:(freq: 84);dl:(len: 7)), (fc:(freq: 52);dl:(len: 7)), (fc:(freq:116);dl:(len: 7)), (fc:(freq: 3);dl:(len: 8)), (fc:(freq:131);dl:(len: 8)), (fc:(freq: 67);dl:(len: 8)), (fc:(freq:195);dl:(len: 8)), (fc:(freq: 35);dl:(len: 8)), (fc:(freq:163);dl:(len: 8)), (fc:(freq: 99);dl:(len: 8)), (fc:(freq:227);dl:(len: 8)) ); { The static distance tree. (Actually a trivial tree since all lens use 5 bits.) } static_dtree : array[0..D_CODES-1] of ct_data = ( (fc:(freq: 0); dl:(len:5)), (fc:(freq:16); dl:(len:5)), (fc:(freq: 8); dl:(len:5)), (fc:(freq:24); dl:(len:5)), (fc:(freq: 4); dl:(len:5)), (fc:(freq:20); dl:(len:5)), (fc:(freq:12); dl:(len:5)), (fc:(freq:28); dl:(len:5)), (fc:(freq: 2); dl:(len:5)), (fc:(freq:18); dl:(len:5)), (fc:(freq:10); dl:(len:5)), (fc:(freq:26); dl:(len:5)), (fc:(freq: 6); dl:(len:5)), (fc:(freq:22); dl:(len:5)), (fc:(freq:14); dl:(len:5)), (fc:(freq:30); dl:(len:5)), (fc:(freq: 1); dl:(len:5)), (fc:(freq:17); dl:(len:5)), (fc:(freq: 9); dl:(len:5)), (fc:(freq:25); dl:(len:5)), (fc:(freq: 5); dl:(len:5)), (fc:(freq:21); dl:(len:5)), (fc:(freq:13); dl:(len:5)), (fc:(freq:29); dl:(len:5)), (fc:(freq: 3); dl:(len:5)), (fc:(freq:19); dl:(len:5)), (fc:(freq:11); dl:(len:5)), (fc:(freq:27); dl:(len:5)), (fc:(freq: 7); dl:(len:5)), (fc:(freq:23); dl:(len:5)) ); { Distance codes. The first 256 values correspond to the distances 3 .. 258, the last 256 values correspond to the top 8 bits of the 15 bit distances. } _dist_code : array[0..DIST_CODE_LEN-1] of uch = ( 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, 18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 ); { length code for each normalized match length (0 == MIN_MATCH) } _length_code : array[0..MAX_MATCH-MIN_MATCH+1-1] of uch = ( 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 ); { First normalized length for each code (0 = MIN_MATCH) } base_length : array[0..LENGTH_CODES-1] of int = ( 0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 0 ); { First normalized distance for each code (0 = distance of 1) } base_dist : array[0..D_CODES-1] of int = ( 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 ); {$endif} { Output a byte on the stream. IN assertion: there is enough room in pending_buf. macro put_byte(s, c) begin s^.pending_buf^[s^.pending] := (c); Inc(s^.pending); end } const MIN_LOOKAHEAD = (MAX_MATCH+MIN_MATCH+1); { Minimum amount of lookahead, except at the end of the input file. See deflate.c for comments about the MIN_MATCH+1. } {macro d_code(dist) if (dist) < 256 then := _dist_code[dist] else := _dist_code[256+((dist) shr 7)]); Mapping from a distance to a distance code. dist is the distance - 1 and must not have side effects. _dist_code[256] and _dist_code[257] are never used. } {$ifndef ORG_DEBUG} { Inline versions of _tr_tally for speed: } #if defined(GEN_TREES_H) || !defined(STDC) extern uch _length_code[]; extern uch _dist_code[]; #else extern const uch _length_code[]; extern const uch _dist_code[]; #endif macro _tr_tally_lit(s, c, flush) var cc : uch; begin cc := (c); s^.d_buf[s^.last_lit] := 0; s^.l_buf[s^.last_lit] := cc; Inc(s^.last_lit); Inc(s^.dyn_ltree[cc].fc.Freq); flush := (s^.last_lit = s^.lit_bufsize-1); end; macro _tr_tally_dist(s, distance, length, flush) \ var len : uch; dist : ush; begin len := (length); dist := (distance); s^.d_buf[s^.last_lit] := dist; s^.l_buf[s^.last_lit] = len; Inc(s^.last_lit); Dec(dist); Inc(s^.dyn_ltree[_length_code[len]+LITERALS+1].fc.Freq); Inc(s^.dyn_dtree[d_code(dist)].Freq); flush := (s^.last_lit = s^.lit_bufsize-1); end; {$endif} { =========================================================================== Constants } const MAX_BL_BITS = 7; { Bit length codes must not exceed MAX_BL_BITS bits } const END_BLOCK = 256; { end of block literal code } const REP_3_6 = 16; { repeat previous bit length 3-6 times (2 bits of repeat count) } const REPZ_3_10 = 17; { repeat a zero length 3-10 times (3 bits of repeat count) } const REPZ_11_138 = 18; { repeat a zero length 11-138 times (7 bits of repeat count) } {local} const extra_lbits : array[0..LENGTH_CODES-1] of int { extra bits for each length code } = (0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0); {local} const extra_dbits : array[0..D_CODES-1] of int { extra bits for each distance code } = (0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13); {local} const extra_blbits : array[0..BL_CODES-1] of int { extra bits for each bit length code } = (0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7); {local} const bl_order : array[0..BL_CODES-1] of uch = (16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15); { The lengths of the bit length codes are sent in order of decreasing probability, to avoid transmitting the lengths for unused bit length codes. } const Buf_size = (8 * 2*sizeof(uch)); { Number of bits used within bi_buf. (bi_buf might be implemented on more than 16 bits on some systems.) } { =========================================================================== Local data. These are initialized only once. } {$ifdef GEN_TREES_H)} { non ANSI compilers may not accept trees.h } const DIST_CODE_LEN = 512; { see definition of array dist_code below } {local} var static_ltree : array[0..L_CODES+2-1] of ct_data; { The static literal tree. Since the bit lengths are imposed, there is no need for the L_CODES extra codes used during heap construction. However The codes 286 and 287 are needed to build a canonical tree (see _tr_init below). } {local} static_dtree : array[0..D_CODES-1] of ct_data; { The static distance tree. (Actually a trivial tree since all codes use 5 bits.) } _dist_code : array[0..DIST_CODE_LEN-1] of uch; { Distance codes. The first 256 values correspond to the distances 3 .. 258, the last 256 values correspond to the top 8 bits of the 15 bit distances. } _length_code : array[0..MAX_MATCH-MIN_MATCH+1-1] of uch; { length code for each normalized match length (0 == MIN_MATCH) } {local} base_length : array[0..LENGTH_CODES-1] of int; { First normalized length for each code (0 = MIN_MATCH) } {local} base_dist : array[0..D_CODES-1] of int; { First normalized distance for each code (0 = distance of 1) } {$endif} { GEN_TREES_H } {local} const static_l_desc : static_tree_desc = (static_tree: {tree_ptr}(@(static_ltree)); { pointer to array of ct_data } extra_bits: {pzIntfArray}(@(extra_lbits)); { pointer to array of int } extra_base: LITERALS+1; elems: L_CODES; max_length: MAX_BITS); {local} const static_d_desc : static_tree_desc = (static_tree: {tree_ptr}(@(static_dtree)); extra_bits: {pzIntfArray}(@(extra_dbits)); extra_base : 0; elems: D_CODES; max_length: MAX_BITS); {local} const static_bl_desc : static_tree_desc = (static_tree: {tree_ptr}(NIL); extra_bits: {pzIntfArray}@(extra_blbits); extra_base : 0; elems: BL_CODES; max_length: MAX_BL_BITS); (* =========================================================================== Local (static) routines in this file. } procedure tr_static_init; procedure init_block(var deflate_state); procedure pqdownheap(var s : deflate_state; var tree : ct_data; k : int); procedure gen_bitlen(var s : deflate_state; var desc : tree_desc); procedure gen_codes(var tree : ct_data; max_code : int; bl_count : pushf); procedure build_tree(var s : deflate_state; var desc : tree_desc); procedure scan_tree(var s : deflate_state; var tree : ct_data; max_code : int); procedure send_tree(var s : deflate_state; var tree : ct_data; max_code : int); function build_bl_tree(var deflate_state) : int; procedure send_all_trees(var deflate_state; lcodes : int; dcodes : int; blcodes : int); procedure compress_block(var s : deflate_state; var ltree : ct_data; var dtree : ct_data); procedure set_data_type(var s : deflate_state); function bi_reverse(value : unsigned; length : int) : unsigned; procedure bi_windup(var deflate_state); procedure bi_flush(var deflate_state); procedure copy_block(var deflate_state; buf : pcharf; len : unsigned; header : int); *) {$ifdef GEN_TREES_H} {local} procedure gen_trees_header; {$endif} (* { =========================================================================== Output a short LSB first on the stream. IN assertion: there is enough room in pendingBuf. } macro put_short(s, w) begin {put_byte(s, (uch)((w) & 0xff));} s.pending_buf^[s.pending] := uch((w) and $ff); Inc(s.pending); {put_byte(s, (uch)((ush)(w) >> 8));} s.pending_buf^[s.pending] := uch(ush(w) shr 8);; Inc(s.pending); end *) { =========================================================================== Send a value on a given number of bits. IN assertion: length <= 16 and value fits in length bits. } {$ifdef ORG_DEBUG} {local} procedure send_bits(var s : deflate_state; value : int; { value to send } length : int); { number of bits } begin {$ifdef DEBUG} Tracevv(' l '+IntToStr(length)+ ' v '+IntToStr(value)); Assert((length > 0) and (length <= 15), 'invalid length'); Inc(s.bits_sent, ulg(length)); {$ENDIF} { If not enough room in bi_buf, use (valid) bits from bi_buf and (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) unused bits in value. } {$IFOPT Q+} {$Q-} {$DEFINE NoOverflowCheck} {$ENDIF} {$IFOPT R+} {$R-} {$DEFINE NoRangeCheck} {$ENDIF} if (s.bi_valid > int(Buf_size) - length) then begin s.bi_buf := s.bi_buf or int(value shl s.bi_valid); {put_short(s, s.bi_buf);} s.pending_buf^[s.pending] := uch(s.bi_buf and $ff); Inc(s.pending); s.pending_buf^[s.pending] := uch(ush(s.bi_buf) shr 8);; Inc(s.pending); s.bi_buf := ush(value) shr (Buf_size - s.bi_valid); Inc(s.bi_valid, length - Buf_size); end else begin s.bi_buf := s.bi_buf or int(value shl s.bi_valid); Inc(s.bi_valid, length); end; {$IFDEF NoOverflowCheck} {$Q+} {$UNDEF NoOverflowCheck} {$ENDIF} {$IFDEF NoRangeCheck} {$Q+} {$UNDEF NoRangeCheck} {$ENDIF} end; {$else} { !DEBUG } macro send_code(s, c, tree) begin send_bits(s, tree[c].Code, tree[c].Len); { Send a code of the given tree. c and tree must not have side effects } end macro send_bits(s, value, length) \ begin int len := length;\ if (s^.bi_valid > (int)Buf_size - len) begin\ int val := value;\ s^.bi_buf |= (val << s^.bi_valid);\ {put_short(s, s.bi_buf);} s.pending_buf^[s.pending] := uch(s.bi_buf and $ff); Inc(s.pending); s.pending_buf^[s.pending] := uch(ush(s.bi_buf) shr 8);; Inc(s.pending); s^.bi_buf := (ush)val >> (Buf_size - s^.bi_valid);\ s^.bi_valid += len - Buf_size;\ end else begin\ s^.bi_buf |= (value) << s^.bi_valid;\ s^.bi_valid += len;\ end\ end; {$endif} { DEBUG } { =========================================================================== Reverse the first len bits of a code, using straightforward code (a faster method would use a table) IN assertion: 1 <= len <= 15 } {local} function bi_reverse(code : unsigned; { the value to invert } len : int) : unsigned; { its bit length } var res : unsigned; {register} begin res := 0; repeat res := res or (code and 1); code := code shr 1; res := res shl 1; Dec(len); until (len <= 0); bi_reverse := res shr 1; end; { =========================================================================== Generate the codes for a given tree and bit counts (which need not be optimal). IN assertion: the array bl_count contains the bit length statistics for the given tree and the field len is set for all tree elements. OUT assertion: the field code is set for all tree elements of non zero code length. } {local} procedure gen_codes(tree : tree_ptr; { the tree to decorate } max_code : int; { largest code with non zero frequency } var bl_count : array of ushf); { number of codes at each bit length } var next_code : array[0..MAX_BITS+1-1] of ush; { next code value for each bit length } code : ush; { running code value } bits : int; { bit index } n : int; { code index } var len : int; begin code := 0; { The distribution counts are first used to generate the code values without bit reversal. } for bits := 1 to MAX_BITS do begin code := ((code + bl_count[bits-1]) shl 1); next_code[bits] := code; end; { Check that the bit counts in bl_count are consistent. The last code must be all ones. } {$IFDEF DEBUG} Assert (code + bl_count[MAX_BITS]-1 = (1 shl MAX_BITS)-1, 'inconsistent bit counts'); Tracev(#13'gen_codes: max_code '+IntToStr(max_code)); {$ENDIF} for n := 0 to max_code do begin len := tree^[n].dl.Len; if (len = 0) then continue; { Now reverse the bits } tree^[n].fc.Code := bi_reverse(next_code[len], len); Inc(next_code[len]); {$ifdef DEBUG} if (n>31) and (n<128) then Tracecv(tree <> tree_ptr(@static_ltree), (^M'n #'+IntToStr(n)+' '+AnsiChar(n)+' l '+IntToStr(len)+' c '+ IntToStr(tree^[n].fc.Code)+' ('+IntToStr(next_code[len]-1)+')')) else Tracecv(tree <> tree_ptr(@static_ltree), (^M'n #'+IntToStr(n)+' l '+IntToStr(len)+' c '+ IntToStr(tree^[n].fc.Code)+' ('+IntToStr(next_code[len]-1)+')')); {$ENDIF} end; end; { =========================================================================== Genererate the file trees.h describing the static trees. } {$ifdef GEN_TREES_H} macro SEPARATOR(i, last, width) if (i) = (last) then ( ^M');'^M^M else \ if (i) mod (width) = (width)-1 then ','^M else ', ' procedure gen_trees_header; var header : system.text; i : int; begin system.assign(header, 'trees.inc'); {$I-} ReWrite(header); {$I+} Assert (IOresult <> 0, 'Can''t open trees.h'); WriteLn(header, '{ header created automatically with -DGEN_TREES_H }'^M); WriteLn(header, 'local const ct_data static_ltree[L_CODES+2] := ('); for i := 0 to L_CODES+2-1 do begin WriteLn(header, '((%3u),(%3u))%s', static_ltree[i].Code, static_ltree[i].Len, SEPARATOR(i, L_CODES+1, 5)); end; WriteLn(header, 'local const ct_data static_dtree[D_CODES] := ('); for i := 0 to D_CODES-1 do begin WriteLn(header, '((%2u),(%2u))%s', static_dtree[i].Code, static_dtree[i].Len, SEPARATOR(i, D_CODES-1, 5)); end; WriteLn(header, 'const uch _dist_code[DIST_CODE_LEN] := ('); for i := 0 to DIST_CODE_LEN-1 do begin WriteLn(header, '%2u%s', _dist_code[i], SEPARATOR(i, DIST_CODE_LEN-1, 20)); end; WriteLn(header, 'const uch _length_code[MAX_MATCH-MIN_MATCH+1]= ('); for i := 0 to MAX_MATCH-MIN_MATCH+1-1 do begin WriteLn(header, '%2u%s', _length_code[i], SEPARATOR(i, MAX_MATCH-MIN_MATCH, 20)); end; WriteLn(header, 'local const int base_length[LENGTH_CODES] := ('); for i := 0 to LENGTH_CODES-1 do begin WriteLn(header, '%1u%s', base_length[i], SEPARATOR(i, LENGTH_CODES-1, 20)); end; WriteLn(header, 'local const int base_dist[D_CODES] := ('); for i := 0 to D_CODES-1 do begin WriteLn(header, '%5u%s', base_dist[i], SEPARATOR(i, D_CODES-1, 10)); end; close(header); end; {$endif} { GEN_TREES_H } { =========================================================================== Initialize the various 'constant' tables. } {local} procedure tr_static_init; {$ifdef GEN_TREES_H} const static_init_done : boolean = FALSE; var n : int; { iterates over tree elements } bits : int; { bit counter } length : int; { length value } code : int; { code value } dist : int; { distance index } bl_count : array[0..MAX_BITS+1-1] of ush; { number of codes at each bit length for an optimal tree } begin if (static_init_done) then exit; { Initialize the mapping length (0..255) -> length code (0..28) } length := 0; for code := 0 to LENGTH_CODES-1-1 do begin base_length[code] := length; for n := 0 to (1 shl extra_lbits[code])-1 do begin _length_code[length] := uch(code); Inc(length); end; end; Assert (length = 256, 'tr_static_init: length <> 256'); { Note that the length 255 (match length 258) can be represented in two different ways: code 284 + 5 bits or code 285, so we overwrite length_code[255] to use the best encoding: } _length_code[length-1] := uch(code); { Initialize the mapping dist (0..32K) -> dist code (0..29) } dist := 0; for code := 0 to 16-1 do begin base_dist[code] := dist; for n := 0 to (1 shl extra_dbits[code])-1 do begin _dist_code[dist] := uch(code); Inc(dist); end; end; Assert (dist = 256, 'tr_static_init: dist <> 256'); dist := dist shr 7; { from now on, all distances are divided by 128 } for code := 16 to D_CODES-1 do begin base_dist[code] := dist shl 7; for n := 0 to (1 shl (extra_dbits[code]-7))-1 do begin _dist_code[256 + dist] := uch(code); Inc(dist); end; end; Assert (dist = 256, 'tr_static_init: 256+dist <> 512'); { Construct the codes of the static literal tree } for bits := 0 to MAX_BITS do bl_count[bits] := 0; n := 0; while (n <= 143) do begin static_ltree[n].dl.Len := 8; Inc(n); Inc(bl_count[8]); end; while (n <= 255) do begin static_ltree[n].dl.Len := 9; Inc(n); Inc(bl_count[9]); end; while (n <= 279) do begin static_ltree[n].dl.Len := 7; Inc(n); Inc(bl_count[7]); end; while (n <= 287) do begin static_ltree[n].dl.Len := 8; Inc(n); Inc(bl_count[8]); end; { Codes 286 and 287 do not exist, but we must include them in the tree construction to get a canonical Huffman tree (longest code all ones) } gen_codes(tree_ptr(@static_ltree), L_CODES+1, bl_count); { The static distance tree is trivial: } for n := 0 to D_CODES-1 do begin static_dtree[n].dl.Len := 5; static_dtree[n].fc.Code := bi_reverse(unsigned(n), 5); end; static_init_done := TRUE; gen_trees_header; { save to include file } {$else} begin {$endif} { GEN_TREES_H) } end; { =========================================================================== Initialize a new block. } {local} procedure init_block(var s : deflate_state); var n : int; { iterates over tree elements } begin { Initialize the trees. } for n := 0 to L_CODES-1 do s.dyn_ltree[n].fc.Freq := 0; for n := 0 to D_CODES-1 do s.dyn_dtree[n].fc.Freq := 0; for n := 0 to BL_CODES-1 do s.bl_tree[n].fc.Freq := 0; s.dyn_ltree[END_BLOCK].fc.Freq := 1; s.static_len := Long(0); s.opt_len := Long(0); s.matches := 0; s.last_lit := 0; end; const SMALLEST = 1; { Index within the heap array of least frequent node in the Huffman tree } { =========================================================================== Initialize the tree data structures for a new zlib stream. } procedure _tr_init(var s : deflate_state); begin tr_static_init; s.compressed_len := Long(0); s.l_desc.dyn_tree := tree_ptr(@s.dyn_ltree); s.l_desc.stat_desc := @static_l_desc; s.d_desc.dyn_tree := tree_ptr(@s.dyn_dtree); s.d_desc.stat_desc := @static_d_desc; s.bl_desc.dyn_tree := tree_ptr(@s.bl_tree); s.bl_desc.stat_desc := @static_bl_desc; s.bi_buf := 0; s.bi_valid := 0; s.last_eob_len := 8; { enough lookahead for inflate } {$ifdef DEBUG} s.bits_sent := Long(0); {$endif} { Initialize the first block of the first file: } init_block(s); end; { =========================================================================== Remove the smallest element from the heap and recreate the heap with one less element. Updates heap and heap_len. macro pqremove(s, tree, top) begin top := s.heap[SMALLEST]; s.heap[SMALLEST] := s.heap[s.heap_len]; Dec(s.heap_len); pqdownheap(s, tree, SMALLEST); end } { =========================================================================== Compares to subtrees, using the tree depth as tie breaker when the subtrees have equal frequency. This minimizes the worst case length. macro smaller(tree, n, m, depth) ( (tree[n].Freq < tree[m].Freq) or ((tree[n].Freq = tree[m].Freq) and (depth[n] <= depth[m])) ) } { =========================================================================== Restore the heap property by moving down the tree starting at node k, exchanging a node with the smallest of its two sons if necessary, stopping when the heap property is re-established (each father smaller than its two sons). } {local} procedure pqdownheap(var s : deflate_state; var tree : tree_type; { the tree to restore } k : int); { node to move down } var v : int; j : int; begin v := s.heap[k]; j := k shl 1; { left son of k } while (j <= s.heap_len) do begin { Set j to the smallest of the two sons: } if (j < s.heap_len) and {smaller(tree, s.heap[j+1], s.heap[j], s.depth)} ( (tree[s.heap[j+1]].fc.Freq < tree[s.heap[j]].fc.Freq) or ((tree[s.heap[j+1]].fc.Freq = tree[s.heap[j]].fc.Freq) and (s.depth[s.heap[j+1]] <= s.depth[s.heap[j]])) ) then begin Inc(j); end; { Exit if v is smaller than both sons } if {(smaller(tree, v, s.heap[j], s.depth))} ( (tree[v].fc.Freq < tree[s.heap[j]].fc.Freq) or ((tree[v].fc.Freq = tree[s.heap[j]].fc.Freq) and (s.depth[v] <= s.depth[s.heap[j]])) ) then break; { Exchange v with the smallest son } s.heap[k] := s.heap[j]; k := j; { And continue down the tree, setting j to the left son of k } j := j shl 1; end; s.heap[k] := v; end; { =========================================================================== Compute the optimal bit lengths for a tree and update the total bit length for the current block. IN assertion: the fields freq and dad are set, heap[heap_max] and above are the tree nodes sorted by increasing frequency. OUT assertions: the field len is set to the optimal bit length, the array bl_count contains the frequencies for each bit length. The length opt_len is updated; static_len is also updated if stree is not null. } {local} procedure gen_bitlen(var s : deflate_state; var desc : tree_desc); { the tree descriptor } var tree : tree_ptr; max_code : int; stree : tree_ptr; {const} extra : pzIntfArray; {const} base : int; max_length : int; h : int; { heap index } n, m : int; { iterate over the tree elements } bits : int; { bit length } xbits : int; { extra bits } f : ush; { frequency } overflow : int; { number of elements with bit length too large } begin tree := desc.dyn_tree; max_code := desc.max_code; stree := desc.stat_desc^.static_tree; extra := desc.stat_desc^.extra_bits; base := desc.stat_desc^.extra_base; max_length := desc.stat_desc^.max_length; overflow := 0; for bits := 0 to MAX_BITS do s.bl_count[bits] := 0; { In a first pass, compute the optimal bit lengths (which may overflow in the case of the bit length tree). } tree^[s.heap[s.heap_max]].dl.Len := 0; { root of the heap } for h := s.heap_max+1 to HEAP_SIZE-1 do begin n := s.heap[h]; bits := tree^[tree^[n].dl.Dad].dl.Len + 1; if (bits > max_length) then begin bits := max_length; Inc(overflow); end; tree^[n].dl.Len := ush(bits); { We overwrite tree[n].dl.Dad which is no longer needed } if (n > max_code) then continue; { not a leaf node } Inc(s.bl_count[bits]); xbits := 0; if (n >= base) then xbits := extra^[n-base]; f := tree^[n].fc.Freq; Inc(s.opt_len, ulg(f) * (bits + xbits)); if (stree <> NIL) then Inc(s.static_len, ulg(f) * (stree^[n].dl.Len + xbits)); end; if (overflow = 0) then exit; {$ifdef DEBUG} Tracev(^M'bit length overflow'); {$endif} { This happens for example on obj2 and pic of the Calgary corpus } { Find the first bit length which could increase: } repeat bits := max_length-1; while (s.bl_count[bits] = 0) do Dec(bits); Dec(s.bl_count[bits]); { move one leaf down the tree } Inc(s.bl_count[bits+1], 2); { move one overflow item as its brother } Dec(s.bl_count[max_length]); { The brother of the overflow item also moves one step up, but this does not affect bl_count[max_length] } Dec(overflow, 2); until (overflow <= 0); { Now recompute all bit lengths, scanning in increasing frequency. h is still equal to HEAP_SIZE. (It is simpler to reconstruct all lengths instead of fixing only the wrong ones. This idea is taken from 'ar' written by Haruhiko Okumura.) } h := HEAP_SIZE; { Delphi3: compiler warning w/o this } for bits := max_length downto 1 do begin n := s.bl_count[bits]; while (n <> 0) do begin Dec(h); m := s.heap[h]; if (m > max_code) then continue; if (tree^[m].dl.Len <> unsigned(bits)) then begin {$ifdef DEBUG} Trace('code '+IntToStr(m)+' bits '+IntToStr(tree^[m].dl.Len) +'.'+IntToStr(bits)); {$ENDIF} Inc(s.opt_len, (long(bits) - long(tree^[m].dl.Len)) * long(tree^[m].fc.Freq) ); tree^[m].dl.Len := ush(bits); end; Dec(n); end; end; end; { =========================================================================== Construct one Huffman tree and assigns the code bit strings and lengths. Update the total bit length for the current block. IN assertion: the field freq is set for all tree elements. OUT assertions: the fields len and code are set to the optimal bit length and corresponding code. The length opt_len is updated; static_len is also updated if stree is not null. The field max_code is set. } {local} procedure build_tree(var s : deflate_state; var desc : tree_desc); { the tree descriptor } var tree : tree_ptr; stree : tree_ptr; {const} elems : int; n, m : int; { iterate over heap elements } max_code : int; { largest code with non zero frequency } node : int; { new node being created } begin tree := desc.dyn_tree; stree := desc.stat_desc^.static_tree; elems := desc.stat_desc^.elems; max_code := -1; { Construct the initial heap, with least frequent element in heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. } s.heap_len := 0; s.heap_max := HEAP_SIZE; for n := 0 to elems-1 do begin if (tree^[n].fc.Freq <> 0) then begin max_code := n; Inc(s.heap_len); s.heap[s.heap_len] := n; s.depth[n] := 0; end else begin tree^[n].dl.Len := 0; end; end; { The pkzip format requires that at least one distance code exists, and that at least one bit should be sent even if there is only one possible code. So to avoid special checks later on we force at least two codes of non zero frequency. } while (s.heap_len < 2) do begin Inc(s.heap_len); if (max_code < 2) then begin Inc(max_code); s.heap[s.heap_len] := max_code; node := max_code; end else begin s.heap[s.heap_len] := 0; node := 0; end; tree^[node].fc.Freq := 1; s.depth[node] := 0; Dec(s.opt_len); if (stree <> NIL) then Dec(s.static_len, stree^[node].dl.Len); { node is 0 or 1 so it does not have extra bits } end; desc.max_code := max_code; { The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, establish sub-heaps of increasing lengths: } for n := s.heap_len div 2 downto 1 do pqdownheap(s, tree^, n); { Construct the Huffman tree by repeatedly combining the least two frequent nodes. } node := elems; { next internal node of the tree } repeat {pqremove(s, tree, n);} { n := node of least frequency } n := s.heap[SMALLEST]; s.heap[SMALLEST] := s.heap[s.heap_len]; Dec(s.heap_len); pqdownheap(s, tree^, SMALLEST); m := s.heap[SMALLEST]; { m := node of next least frequency } Dec(s.heap_max); s.heap[s.heap_max] := n; { keep the nodes sorted by frequency } Dec(s.heap_max); s.heap[s.heap_max] := m; { Create a new node father of n and m } tree^[node].fc.Freq := tree^[n].fc.Freq + tree^[m].fc.Freq; { maximum } if (s.depth[n] >= s.depth[m]) then s.depth[node] := uch (s.depth[n] + 1) else s.depth[node] := uch (s.depth[m] + 1); tree^[m].dl.Dad := ush(node); tree^[n].dl.Dad := ush(node); {$ifdef DUMP_BL_TREE} if (tree = tree_ptr(@s.bl_tree)) then begin WriteLn(#13'node ',node,'(',tree^[node].fc.Freq,') sons ',n, '(',tree^[n].fc.Freq,') ', m, '(',tree^[m].fc.Freq,')'); end; {$endif} { and insert the new node in the heap } s.heap[SMALLEST] := node; Inc(node); pqdownheap(s, tree^, SMALLEST); until (s.heap_len < 2); Dec(s.heap_max); s.heap[s.heap_max] := s.heap[SMALLEST]; { At this point, the fields freq and dad are set. We can now generate the bit lengths. } gen_bitlen(s, desc); { The field len is now set, we can generate the bit codes } gen_codes (tree, max_code, s.bl_count); end; { =========================================================================== Scan a literal or distance tree to determine the frequencies of the codes in the bit length tree. } {local} procedure scan_tree(var s : deflate_state; var tree : array of ct_data; { the tree to be scanned } max_code : int); { and its largest code of non zero frequency } var n : int; { iterates over all tree elements } prevlen : int; { last emitted length } curlen : int; { length of current code } nextlen : int; { length of next code } count : int; { repeat count of the current code } max_count : int; { max repeat count } min_count : int; { min repeat count } begin prevlen := -1; nextlen := tree[0].dl.Len; count := 0; max_count := 7; min_count := 4; if (nextlen = 0) then begin max_count := 138; min_count := 3; end; tree[max_code+1].dl.Len := ush($ffff); { guard } for n := 0 to max_code do begin curlen := nextlen; nextlen := tree[n+1].dl.Len; Inc(count); if (count < max_count) and (curlen = nextlen) then continue else if (count < min_count) then Inc(s.bl_tree[curlen].fc.Freq, count) else if (curlen <> 0) then begin if (curlen <> prevlen) then Inc(s.bl_tree[curlen].fc.Freq); Inc(s.bl_tree[REP_3_6].fc.Freq); end else if (count <= 10) then Inc(s.bl_tree[REPZ_3_10].fc.Freq) else Inc(s.bl_tree[REPZ_11_138].fc.Freq); count := 0; prevlen := curlen; if (nextlen = 0) then begin max_count := 138; min_count := 3; end else if (curlen = nextlen) then begin max_count := 6; min_count := 3; end else begin max_count := 7; min_count := 4; end; end; end; { =========================================================================== Send a literal or distance tree in compressed form, using the codes in bl_tree. } {local} procedure send_tree(var s : deflate_state; var tree : array of ct_data; { the tree to be scanned } max_code : int); { and its largest code of non zero frequency } var n : int; { iterates over all tree elements } prevlen : int; { last emitted length } curlen : int; { length of current code } nextlen : int; { length of next code } count : int; { repeat count of the current code } max_count : int; { max repeat count } min_count : int; { min repeat count } begin prevlen := -1; nextlen := tree[0].dl.Len; count := 0; max_count := 7; min_count := 4; { tree[max_code+1].dl.Len := -1; } { guard already set } if (nextlen = 0) then begin max_count := 138; min_count := 3; end; for n := 0 to max_code do begin curlen := nextlen; nextlen := tree[n+1].dl.Len; Inc(count); if (count < max_count) and (curlen = nextlen) then continue else if (count < min_count) then begin repeat {$ifdef DEBUG} Tracevvv(#13'cd '+IntToStr(curlen)); {$ENDIF} send_bits(s, s.bl_tree[curlen].fc.Code, s.bl_tree[curlen].dl.Len); Dec(count); until (count = 0); end else if (curlen <> 0) then begin if (curlen <> prevlen) then begin {$ifdef DEBUG} Tracevvv(#13'cd '+IntToStr(curlen)); {$ENDIF} send_bits(s, s.bl_tree[curlen].fc.Code, s.bl_tree[curlen].dl.Len); Dec(count); end; {$IFDEF DEBUG} Assert((count >= 3) and (count <= 6), ' 3_6?'); {$ENDIF} {$ifdef DEBUG} Tracevvv(#13'cd '+IntToStr(REP_3_6)); {$ENDIF} send_bits(s, s.bl_tree[REP_3_6].fc.Code, s.bl_tree[REP_3_6].dl.Len); send_bits(s, count-3, 2); end else if (count <= 10) then begin {$ifdef DEBUG} Tracevvv(#13'cd '+IntToStr(REPZ_3_10)); {$ENDIF} send_bits(s, s.bl_tree[REPZ_3_10].fc.Code, s.bl_tree[REPZ_3_10].dl.Len); send_bits(s, count-3, 3); end else begin {$ifdef DEBUG} Tracevvv(#13'cd '+IntToStr(REPZ_11_138)); {$ENDIF} send_bits(s, s.bl_tree[REPZ_11_138].fc.Code, s.bl_tree[REPZ_11_138].dl.Len); send_bits(s, count-11, 7); end; count := 0; prevlen := curlen; if (nextlen = 0) then begin max_count := 138; min_count := 3; end else if (curlen = nextlen) then begin max_count := 6; min_count := 3; end else begin max_count := 7; min_count := 4; end; end; end; { =========================================================================== Construct the Huffman tree for the bit lengths and return the index in bl_order of the last bit length code to send. } {local} function build_bl_tree(var s : deflate_state) : int; var max_blindex : int; { index of last bit length code of non zero freq } begin { Determine the bit length frequencies for literal and distance trees } scan_tree(s, s.dyn_ltree, s.l_desc.max_code); scan_tree(s, s.dyn_dtree, s.d_desc.max_code); { Build the bit length tree: } build_tree(s, s.bl_desc); { opt_len now includes the length of the tree representations, except the lengths of the bit lengths codes and the 5+5+4 bits for the counts. } { Determine the number of bit length codes to send. The pkzip format requires that at least 4 bit length codes be sent. (appnote.txt says 3 but the actual value used is 4.) } for max_blindex := BL_CODES-1 downto 3 do begin if (s.bl_tree[bl_order[max_blindex]].dl.Len <> 0) then break; end; { Update opt_len to include the bit length tree and counts } Inc(s.opt_len, 3*(max_blindex+1) + 5+5+4); {$ifdef DEBUG} Tracev(^M'dyn trees: dyn %ld, stat %ld {s.opt_len, s.static_len}'); {$ENDIF} build_bl_tree := max_blindex; end; { =========================================================================== Send the header for a block using dynamic Huffman trees: the counts, the lengths of the bit length codes, the literal tree and the distance tree. IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. } {local} procedure send_all_trees(var s : deflate_state; lcodes : int; dcodes : int; blcodes : int); { number of codes for each tree } var rank : int; { index in bl_order } begin {$IFDEF DEBUG} Assert ((lcodes >= 257) and (dcodes >= 1) and (blcodes >= 4), 'not enough codes'); Assert ((lcodes <= L_CODES) and (dcodes <= D_CODES) and (blcodes <= BL_CODES), 'too many codes'); Tracev(^M'bl counts: '); {$ENDIF} send_bits(s, lcodes-257, 5); { not +255 as stated in appnote.txt } send_bits(s, dcodes-1, 5); send_bits(s, blcodes-4, 4); { not -3 as stated in appnote.txt } for rank := 0 to blcodes-1 do begin {$ifdef DEBUG} Tracev(^M'bl code '+IntToStr(bl_order[rank])); {$ENDIF} send_bits(s, s.bl_tree[bl_order[rank]].dl.Len, 3); end; {$ifdef DEBUG} Tracev(^M'bl tree: sent '+IntToStr(s.bits_sent)); {$ENDIF} send_tree(s, s.dyn_ltree, lcodes-1); { literal tree } {$ifdef DEBUG} Tracev(^M'lit tree: sent '+IntToStr(s.bits_sent)); {$ENDIF} send_tree(s, s.dyn_dtree, dcodes-1); { distance tree } {$ifdef DEBUG} Tracev(^M'dist tree: sent '+IntToStr(s.bits_sent)); {$ENDIF} end; { =========================================================================== Flush the bit buffer and align the output on a byte boundary } {local} procedure bi_windup(var s : deflate_state); begin if (s.bi_valid > 8) then begin {put_short(s, s.bi_buf);} s.pending_buf^[s.pending] := uch(s.bi_buf and $ff); Inc(s.pending); s.pending_buf^[s.pending] := uch(ush(s.bi_buf) shr 8);; Inc(s.pending); end else if (s.bi_valid > 0) then begin {put_byte(s, (Byte)s^.bi_buf);} s.pending_buf^[s.pending] := Byte(s.bi_buf); Inc(s.pending); end; s.bi_buf := 0; s.bi_valid := 0; {$ifdef DEBUG} s.bits_sent := (s.bits_sent+7) and (not 7); {$endif} end; { =========================================================================== Copy a stored block, storing first the length and its one's complement if requested. } {local} procedure copy_block(var s : deflate_state; buf : pcharf; { the input data } len : unsigned; { its length } header : boolean); { true if block header must be written } begin bi_windup(s); { align on byte boundary } s.last_eob_len := 8; { enough lookahead for inflate } if (header) then begin {put_short(s, (ush)len);} s.pending_buf^[s.pending] := uch(ush(len) and $ff); Inc(s.pending); s.pending_buf^[s.pending] := uch(ush(len) shr 8);; Inc(s.pending); {put_short(s, (ush)~len);} s.pending_buf^[s.pending] := uch(ush(not len) and $ff); Inc(s.pending); s.pending_buf^[s.pending] := uch(ush(not len) shr 8);; Inc(s.pending); {$ifdef DEBUG} Inc(s.bits_sent, 2*16); {$endif} end; {$ifdef DEBUG} Inc(s.bits_sent, ulg(len shl 3)); {$endif} while (len <> 0) do begin Dec(len); {put_byte(s, *buf++);} s.pending_buf^[s.pending] := buf^; Inc(buf); Inc(s.pending); end; end; { =========================================================================== Send a stored block } procedure _tr_stored_block(var s : deflate_state; buf : pcharf; { input block } stored_len : ulg; { length of input block } eof : boolean); { true if this is the last block for a file } begin send_bits(s, (STORED_BLOCK shl 1)+ord(eof), 3); { send block type } s.compressed_len := (s.compressed_len + 3 + 7) and ulg(not Long(7)); Inc(s.compressed_len, (stored_len + 4) shl 3); copy_block(s, buf, unsigned(stored_len), TRUE); { with header } end; { =========================================================================== Flush the bit buffer, keeping at most 7 bits in it. } {local} procedure bi_flush(var s : deflate_state); begin if (s.bi_valid = 16) then begin {put_short(s, s.bi_buf);} s.pending_buf^[s.pending] := uch(s.bi_buf and $ff); Inc(s.pending); s.pending_buf^[s.pending] := uch(ush(s.bi_buf) shr 8);; Inc(s.pending); s.bi_buf := 0; s.bi_valid := 0; end else if (s.bi_valid >= 8) then begin {put_byte(s, (Byte)s^.bi_buf);} s.pending_buf^[s.pending] := Byte(s.bi_buf); Inc(s.pending); s.bi_buf := s.bi_buf shr 8; Dec(s.bi_valid, 8); end; end; { =========================================================================== Send one empty static block to give enough lookahead for inflate. This takes 10 bits, of which 7 may remain in the bit buffer. The current inflate code requires 9 bits of lookahead. If the last two codes for the previous block (real code plus EOB) were coded on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode the last real code. In this case we send two empty static blocks instead of one. (There are no problems if the previous block is stored or fixed.) To simplify the code, we assume the worst case of last real code encoded on one bit only. } procedure _tr_align(var s : deflate_state); begin send_bits(s, STATIC_TREES shl 1, 3); {$ifdef DEBUG} Tracevvv(#13'cd '+IntToStr(END_BLOCK)); {$ENDIF} send_bits(s, static_ltree[END_BLOCK].fc.Code, static_ltree[END_BLOCK].dl.Len); Inc(s.compressed_len, Long(10)); { 3 for block type, 7 for EOB } bi_flush(s); { Of the 10 bits for the empty block, we have already sent (10 - bi_valid) bits. The lookahead for the last real code (before the EOB of the previous block) was thus at least one plus the length of the EOB plus what we have just sent of the empty static block. } if (1 + s.last_eob_len + 10 - s.bi_valid < 9) then begin send_bits(s, STATIC_TREES shl 1, 3); {$ifdef DEBUG} Tracevvv(#13'cd '+IntToStr(END_BLOCK)); {$ENDIF} send_bits(s, static_ltree[END_BLOCK].fc.Code, static_ltree[END_BLOCK].dl.Len); Inc(s.compressed_len, Long(10)); bi_flush(s); end; s.last_eob_len := 7; end; { =========================================================================== Set the data type to ASCII or BINARY, using a crude approximation: binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. IN assertion: the fields freq of dyn_ltree are set and the total of all frequencies does not exceed 64K (to fit in an int on 16 bit machines). } {local} procedure set_data_type(var s : deflate_state); var n : int; ascii_freq : unsigned; bin_freq : unsigned; begin n := 0; ascii_freq := 0; bin_freq := 0; while (n < 7) do begin Inc(bin_freq, s.dyn_ltree[n].fc.Freq); Inc(n); end; while (n < 128) do begin Inc(ascii_freq, s.dyn_ltree[n].fc.Freq); Inc(n); end; while (n < LITERALS) do begin Inc(bin_freq, s.dyn_ltree[n].fc.Freq); Inc(n); end; if (bin_freq > (ascii_freq shr 2)) then s.data_type := Byte(Z_BINARY) else s.data_type := Byte(Z_ASCII); end; { =========================================================================== Send the block data compressed using the given Huffman trees } {local} procedure compress_block(var s : deflate_state; var ltree : array of ct_data; { literal tree } var dtree : array of ct_data); { distance tree } var dist : unsigned; { distance of matched string } lc : int; { match length or unmatched char (if dist == 0) } lx : unsigned; { running index in l_buf } code : unsigned; { the code to send } extra : int; { number of extra bits to send } begin lx := 0; if (s.last_lit <> 0) then repeat dist := s.d_buf^[lx]; lc := s.l_buf^[lx]; Inc(lx); if (dist = 0) then begin { send a literal byte } {$ifdef DEBUG} Tracevvv(#13'cd '+IntToStr(lc)); Tracecv((lc > 31) and (lc < 128), ' '+AnsiChar(lc)+' '); {$ENDIF} send_bits(s, ltree[lc].fc.Code, ltree[lc].dl.Len); end else begin { Here, lc is the match length - MIN_MATCH } code := _length_code[lc]; { send the length code } {$ifdef DEBUG} Tracevvv(#13'cd '+IntToStr(code+LITERALS+1)); {$ENDIF} send_bits(s, ltree[code+LITERALS+1].fc.Code, ltree[code+LITERALS+1].dl.Len); extra := extra_lbits[code]; if (extra <> 0) then begin Dec(lc, base_length[code]); send_bits(s, lc, extra); { send the extra length bits } end; Dec(dist); { dist is now the match distance - 1 } {code := d_code(dist);} if (dist < 256) then code := _dist_code[dist] else code := _dist_code[256+(dist shr 7)]; {$IFDEF DEBUG} Assert (code < D_CODES, 'bad d_code'); {$ENDIF} { send the distance code } {$ifdef DEBUG} Tracevvv(#13'cd '+IntToStr(code)); {$ENDIF} send_bits(s, dtree[code].fc.Code, dtree[code].dl.Len); extra := extra_dbits[code]; if (extra <> 0) then begin Dec(dist, base_dist[code]); send_bits(s, dist, extra); { send the extra distance bits } end; end; { literal or match pair ? } { Check that the overlay between pending_buf and d_buf+l_buf is ok: } {$IFDEF DEBUG} Assert(s.pending < s.lit_bufsize + 2*lx, 'pendingBuf overflow'); {$ENDIF} until (lx >= s.last_lit); {$ifdef DEBUG} Tracevvv(#13'cd '+IntToStr(END_BLOCK)); {$ENDIF} send_bits(s, ltree[END_BLOCK].fc.Code, ltree[END_BLOCK].dl.Len); s.last_eob_len := ltree[END_BLOCK].dl.Len; end; { =========================================================================== Determine the best encoding for the current block: dynamic trees, static trees or store, and output the encoded block to the zip file. This function returns the total compressed length for the file so far. } function _tr_flush_block (var s : deflate_state; buf : pcharf; { input block, or NULL if too old } stored_len : ulg; { length of input block } eof : boolean) : ulg; { true if this is the last block for a file } var opt_lenb, static_lenb : ulg; { opt_len and static_len in bytes } max_blindex : int; { index of last bit length code of non zero freq } begin max_blindex := 0; { Build the Huffman trees unless a stored block is forced } if (s.level > 0) then begin { Check if the file is ascii or binary } if (s.data_type = Z_UNKNOWN) then set_data_type(s); { Construct the literal and distance trees } build_tree(s, s.l_desc); {$ifdef DEBUG} Tracev(^M'lit data: dyn %ld, stat %ld {s.opt_len, s.static_len}'); {$ENDIF} build_tree(s, s.d_desc); {$ifdef DEBUG} Tracev(^M'dist data: dyn %ld, stat %ld {s.opt_len, s.static_len}'); {$ENDIF} { At this point, opt_len and static_len are the total bit lengths of the compressed block data, excluding the tree representations. } { Build the bit length tree for the above two trees, and get the index in bl_order of the last bit length code to send. } max_blindex := build_bl_tree(s); { Determine the best encoding. Compute first the block length in bytes} opt_lenb := (s.opt_len+3+7) shr 3; static_lenb := (s.static_len+3+7) shr 3; {$ifdef DEBUG} Tracev(^M'opt %lu(%lu) stat %lu(%lu) stored %lu lit %u '+ '{opt_lenb, s.opt_len, static_lenb, s.static_len, stored_len,'+ 's.last_lit}'); {$ENDIF} if (static_lenb <= opt_lenb) then opt_lenb := static_lenb; end else begin {$IFDEF DEBUG} Assert(buf <> pcharf(NIL), 'lost buf'); {$ENDIF} static_lenb := stored_len + 5; opt_lenb := static_lenb; { force a stored block } end; { If compression failed and this is the first and last block, and if the .zip file can be seeked (to rewrite the local header), the whole file is transformed into a stored file: } {$ifdef STORED_FILE_OK} {$ifdef FORCE_STORED_FILE} if eof and (s.compressed_len = Long(0)) then begin { force stored file } {$else} if (stored_len <= opt_lenb) and eof and (s.compressed_len=Long(0)) and seekable()) do begin {$endif} { Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: } if (buf = pcharf(0)) then error ('block vanished'); copy_block(buf, unsigned(stored_len), 0); { without header } s.compressed_len := stored_len shl 3; s.method := STORED; end else {$endif} { STORED_FILE_OK } {$ifdef FORCE_STORED} if (buf <> pcharf(0)) then begin { force stored block } {$else} if (stored_len+4 <= opt_lenb) and (buf <> pcharf(0)) then begin { 4: two words for the lengths } {$endif} { The test buf <> NULL is only necessary if LIT_BUFSIZE > WSIZE. Otherwise we can't have processed more than WSIZE input bytes since the last block flush, because compression would have been successful. If LIT_BUFSIZE <= WSIZE, it is never too late to transform a block into a stored block. } _tr_stored_block(s, buf, stored_len, eof); {$ifdef FORCE_STATIC} end else if (static_lenb >= 0) then begin { force static trees } {$else} end else if (static_lenb = opt_lenb) then begin {$endif} send_bits(s, (STATIC_TREES shl 1)+ord(eof), 3); compress_block(s, static_ltree, static_dtree); Inc(s.compressed_len, 3 + s.static_len); end else begin send_bits(s, (DYN_TREES shl 1)+ord(eof), 3); send_all_trees(s, s.l_desc.max_code+1, s.d_desc.max_code+1, max_blindex+1); compress_block(s, s.dyn_ltree, s.dyn_dtree); Inc(s.compressed_len, 3 + s.opt_len); end; {$ifdef DEBUG} Assert (s.compressed_len = s.bits_sent, 'bad compressed size'); {$ENDIF} init_block(s); if (eof) then begin bi_windup(s); Inc(s.compressed_len, 7); { align on byte boundary } end; {$ifdef DEBUG} Tracev(#13'comprlen %lu(%lu) {s.compressed_len shr 3,'+ 's.compressed_len-7*ord(eof)}'); {$ENDIF} _tr_flush_block := s.compressed_len shr 3; end; { =========================================================================== Save the match info and tally the frequency counts. Return true if the current block must be flushed. } function _tr_tally (var s : deflate_state; dist : unsigned; { distance of matched string } lc : unsigned) : boolean; { match length-MIN_MATCH or unmatched char (if dist=0) } var {$IFDEF DEBUG} MAX_DIST : ush; {$ENDIF} code : ush; {$ifdef TRUNCATE_BLOCK} var out_length : ulg; in_length : ulg; dcode : int; {$endif} begin s.d_buf^[s.last_lit] := ush(dist); s.l_buf^[s.last_lit] := uch(lc); Inc(s.last_lit); if (dist = 0) then begin { lc is the unmatched char } Inc(s.dyn_ltree[lc].fc.Freq); end else begin Inc(s.matches); { Here, lc is the match length - MIN_MATCH } Dec(dist); { dist := match distance - 1 } {macro d_code(dist)} if (dist) < 256 then code := _dist_code[dist] else code := _dist_code[256+(dist shr 7)]; {$IFDEF DEBUG} {macro MAX_DIST(s) <=> ((s)^.w_size-MIN_LOOKAHEAD) In order to simplify the code, particularly on 16 bit machines, match distances are limited to MAX_DIST instead of WSIZE. } MAX_DIST := ush(s.w_size-MIN_LOOKAHEAD); Assert((dist < ush(MAX_DIST)) and (ush(lc) <= ush(MAX_MATCH-MIN_MATCH)) and (ush(code) < ush(D_CODES)), '_tr_tally: bad match'); {$ENDIF} Inc(s.dyn_ltree[_length_code[lc]+LITERALS+1].fc.Freq); {s.dyn_dtree[d_code(dist)].Freq++;} Inc(s.dyn_dtree[code].fc.Freq); end; {$ifdef TRUNCATE_BLOCK} { Try to guess if it is profitable to stop the current block here } if (s.last_lit and $1fff = 0) and (s.level > 2) then begin { Compute an upper bound for the compressed length } out_length := ulg(s.last_lit)*Long(8); in_length := ulg(long(s.strstart) - s.block_start); for dcode := 0 to D_CODES-1 do begin Inc(out_length, ulg(s.dyn_dtree[dcode].fc.Freq * (Long(5)+extra_dbits[dcode])) ); end; out_length := out_length shr 3; {$ifdef DEBUG} Tracev(^M'last_lit %u, in %ld, out ~%ld(%ld%%) '); { s.last_lit, in_length, out_length, Long(100) - out_length*Long(100) div in_length)); } {$ENDIF} if (s.matches < s.last_lit div 2) and (out_length < in_length div 2) then begin _tr_tally := TRUE; exit; end; end; {$endif} _tr_tally := (s.last_lit = s.lit_bufsize-1); { We avoid equality with lit_bufsize because of wraparound at 64K on 16 bit machines and because stored blocks are restricted to 64K-1 bytes. } end; end. ================================================ FILE: lib/Imaging/ZLib/imzconf.inc ================================================ { -------------------------------------------------------------------- } {$DEFINE MAX_MATCH_IS_258} { Compile with -DMAXSEG_64K if the alloc function cannot allocate more than 64k bytes at a time (needed on systems with 16-bit int). } {$UNDEF MAXSEG_64K} {$DEFINE UNALIGNED_OK} { requires SizeOf(ush) = 2 ! } {$UNDEF DYNAMIC_CRC_TABLE} {$UNDEF FASTEST} {$DEFINE Use32} {$DEFINE patch112} { apply patch from the zlib home page } {$IFDEF FPC} {$MODE DELPHI} {$ENDIF} {$UNDEF DEBUG} // for Delphi 2007 in DEBUG mode {$RANGECHECKS OFF} {$OVERFLOWCHECKS OFF} { -------------------------------------------------------------------- } ================================================ FILE: lib/Imaging/ZLib/imzdeflate.pas ================================================ Unit imzdeflate; { Orginal: deflate.h -- internal compression state deflate.c -- compress data using the deflation algorithm Copyright (C) 1995-1996 Jean-loup Gailly. Pascal tranlastion Copyright (C) 1998 by Jacques Nomssi Nzali For conditions of distribution and use, see copyright notice in readme.txt } { ALGORITHM The "deflation" process depends on being able to identify portions of the input text which are identical to earlier input (within a sliding window trailing behind the input currently being processed). The most straightforward technique turns out to be the fastest for most input files: try all possible matches and select the longest. The key feature of this algorithm is that insertions into the string dictionary are very simple and thus fast, and deletions are avoided completely. Insertions are performed at each input character, whereas string matches are performed only when the previous match ends. So it is preferable to spend more time in matches to allow very fast string insertions and avoid deletions. The matching algorithm for small strings is inspired from that of Rabin & Karp. A brute force approach is used to find longer strings when a small match has been found. A similar algorithm is used in comic (by Jan-Mark Wams) and freeze (by Leonid Broukhis). A previous version of this file used a more sophisticated algorithm (by Fiala and Greene) which is guaranteed to run in linear amortized time, but has a larger average cost, uses more memory and is patented. However the F&G algorithm may be faster for some highly redundant files if the parameter max_chain_length (described below) is too large. ACKNOWLEDGEMENTS The idea of lazy evaluation of matches is due to Jan-Mark Wams, and I found it in 'freeze' written by Leonid Broukhis. Thanks to many people for bug reports and testing. REFERENCES Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc A description of the Rabin and Karp algorithm is given in the book "Algorithms" by R. Sedgewick, Addison-Wesley, p252. Fiala,E.R., and Greene,D.H. Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595} interface {$I imzconf.inc} uses imzutil, impaszlib; function deflateInit_(strm : z_streamp; level : int; const version : AnsiString; stream_size : int) : int; function deflateInit (var strm : z_stream; level : int) : int; { Initializes the internal stream state for compression. The fields zalloc, zfree and opaque must be initialized before by the caller. If zalloc and zfree are set to Z_NULL, deflateInit updates them to use default allocation functions. The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: 1 gives best speed, 9 gives best compression, 0 gives no compression at all (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION requests a default compromise between speed and compression (currently equivalent to level 6). deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if level is not a valid compression level, Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible with the version assumed by the caller (ZLIB_VERSION). msg is set to null if there is no error message. deflateInit does not perform any compression: this will be done by deflate(). } {EXPORT} function deflate (var strm : z_stream; flush : int) : int; { Performs one or both of the following actions: - Compress more input starting at next_in and update next_in and avail_in accordingly. If not all input can be processed (because there is not enough room in the output buffer), next_in and avail_in are updated and processing will resume at this point for the next call of deflate(). - Provide more output starting at next_out and update next_out and avail_out accordingly. This action is forced if the parameter flush is non zero. Forcing flush frequently degrades the compression ratio, so this parameter should be set only when necessary (in interactive applications). Some output may be provided even if flush is not set. Before the call of deflate(), the application should ensure that at least one of the actions is possible, by providing more input and/or consuming more output, and updating avail_in or avail_out accordingly; avail_out should never be zero before the call. The application can consume the compressed output when it wants, for example when the output buffer is full (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. If the parameter flush is set to Z_PARTIAL_FLUSH, the current compression block is terminated and flushed to the output buffer so that the decompressor can get all input data available so far. For method 9, a future variant on method 8, the current block will be flushed but not terminated. Z_SYNC_FLUSH has the same effect as partial flush except that the compressed output is byte aligned (the compressor can clear its internal bit buffer) and the current block is always terminated; this can be useful if the compressor has to be restarted from scratch after an interruption (in which case the internal state of the compressor may be lost). If flush is set to Z_FULL_FLUSH, the compression block is terminated, a special marker is output and the compression dictionary is discarded; this is useful to allow the decompressor to synchronize if one compressed block has been damaged (see inflateSync below). Flushing degrades compression and so should be used only when necessary. Using Z_FULL_FLUSH too often can seriously degrade the compression. If deflate returns with avail_out == 0, this function must be called again with the same value of the flush parameter and more output space (updated avail_out), until the flush is complete (deflate returns with non-zero avail_out). If the parameter flush is set to Z_FINISH, all pending input is processed, all pending output is flushed and deflate returns with Z_STREAM_END if there was enough output space; if deflate returns with Z_OK, this function must be called again with Z_FINISH and more output space (updated avail_out) but no more input data, until it returns with Z_STREAM_END or an error. After deflate has returned Z_STREAM_END, the only possible operations on the stream are deflateReset or deflateEnd. Z_FINISH can be used immediately after deflateInit if all the compression is to be done in a single step. In this case, avail_out must be at least 0.1% larger than avail_in plus 12 bytes. If deflate does not return Z_STREAM_END, then it must be called again as described above. deflate() may update data_type if it can make a good guess about the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered binary. This field is only for information purposes and does not affect the compression algorithm in any manner. deflate() returns Z_OK if some progress has been made (more input processed or more output produced), Z_STREAM_END if all input has been consumed and all output has been produced (only when flush is set to Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible. } function deflateEnd (var strm : z_stream) : int; { All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any pending output. deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state was inconsistent, Z_DATA_ERROR if the stream was freed prematurely (some input or output was discarded). In the error case, msg may be set but then points to a static string (which must not be deallocated). } { Advanced functions } { The following functions are needed only in some special applications. } {EXPORT} function deflateInit2 (var strm : z_stream; level : int; method : int; windowBits : int; memLevel : int; strategy : int) : int; { This is another version of deflateInit with more compression options. The fields next_in, zalloc, zfree and opaque must be initialized before by the caller. The method parameter is the compression method. It must be Z_DEFLATED in this version of the library. (Method 9 will allow a 64K history buffer and partial block flushes.) The windowBits parameter is the base two logarithm of the window size (the size of the history buffer). It should be in the range 8..15 for this version of the library (the value 16 will be allowed for method 9). Larger values of this parameter result in better compression at the expense of memory usage. The default value is 15 if deflateInit is used instead. The memLevel parameter specifies how much memory should be allocated for the internal compression state. memLevel=1 uses minimum memory but is slow and reduces compression ratio; memLevel=9 uses maximum memory for optimal speed. The default value is 8. See zconf.h for total memory usage as a function of windowBits and memLevel. The strategy parameter is used to tune the compression algorithm. Use the value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no string match). Filtered data consists mostly of small values with a somewhat random distribution. In this case, the compression algorithm is tuned to compress them better. The effect of Z_FILTERED is to force more Huffman coding and less string matching; it is somewhat intermediate between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects the compression ratio but not the correctness of the compressed output even if it is not set appropriately. If next_in is not null, the library will use this buffer to hold also some history information; the buffer must either hold the entire input data, or have at least 1<<(windowBits+1) bytes and be writable. If next_in is null, the library will allocate its own history buffer (and leave next_in null). next_out need not be provided here but must be provided by the application for the next call of deflate(). If the history buffer is provided by the application, next_in must must never be changed by the application since the compressor maintains information inside this buffer from call to call; the application must provide more input only by increasing avail_in. next_in is always reset by the library in this case. deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid method). msg is set to null if there is no error message. deflateInit2 does not perform any compression: this will be done by deflate(). } {EXPORT} function deflateSetDictionary (var strm : z_stream; dictionary : pBytef; {const bytes} dictLength : uint) : int; { Initializes the compression dictionary (history buffer) from the given byte sequence without producing any compressed output. This function must be called immediately after deflateInit or deflateInit2, before any call of deflate. The compressor and decompressor must use exactly the same dictionary (see inflateSetDictionary). The dictionary should consist of strings (byte sequences) that are likely to be encountered later in the data to be compressed, with the most commonly used strings preferably put towards the end of the dictionary. Using a dictionary is most useful when the data to be compressed is short and can be predicted with good accuracy; the data can then be compressed better than with the default empty dictionary. In this version of the library, only the last 32K bytes of the dictionary are used. Upon return of this function, strm->adler is set to the Adler32 value of the dictionary; the decompressor may later use this value to determine which dictionary has been used by the compressor. (The Adler32 value applies to the whole dictionary even if only a subset of the dictionary is actually used by the compressor.) deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a parameter is invalid (such as NULL dictionary) or the stream state is inconsistent (for example if deflate has already been called for this stream). deflateSetDictionary does not perform any compression: this will be done by deflate(). } {EXPORT} function deflateCopy (dest : z_streamp; source : z_streamp) : int; { Sets the destination stream as a complete copy of the source stream. If the source stream is using an application-supplied history buffer, a new buffer is allocated for the destination stream. The compressed output buffer is always application-supplied. It's the responsibility of the application to provide the correct values of next_out and avail_out for the next call of deflate. This function can be useful when several compression strategies will be tried, for example when there are several ways of pre-processing the input data with a filter. The streams that will be discarded should then be freed by calling deflateEnd. Note that deflateCopy duplicates the internal compression state which can be quite large, so this strategy is slow and can consume lots of memory. deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc being NULL). msg is left unchanged in both source and destination. } {EXPORT} function deflateReset (var strm : z_stream) : int; { This function is equivalent to deflateEnd followed by deflateInit, but does not free and reallocate all the internal compression state. The stream will keep the same compression level and any other attributes that may have been set by deflateInit2. deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being NIL). } {EXPORT} function deflateParams (var strm : z_stream; level : int; strategy : int) : int; { Dynamically update the compression level and compression strategy. This can be used to switch between compression and straight copy of the input data, or to switch to a different kind of input data requiring a different strategy. If the compression level is changed, the input available so far is compressed with the old level (and may be flushed); the new level will take effect only at the next call of deflate(). Before the call of deflateParams, the stream state must be set as for a call of deflate(), since the currently available input may have to be compressed and flushed. In particular, strm->avail_out must be non-zero. deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if strm->avail_out was zero. } const deflate_copyright : string = ' deflate 1.1.2 Copyright 1995-1998 Jean-loup Gailly '; { If you use the zlib library in a product, an acknowledgment is welcome in the documentation of your product. If for some reason you cannot include such an acknowledgment, I would appreciate that you keep this copyright string in the executable of your product. } implementation uses imtrees, imadler; { =========================================================================== Function prototypes. } type block_state = ( need_more, { block not completed, need more input or more output } block_done, { block flush performed } finish_started, { finish started, need only more output at next deflate } finish_done); { finish done, accept no more input or output } { Compression function. Returns the block state after the call. } type compress_func = function(var s : deflate_state; flush : int) : block_state; {local} procedure fill_window(var s : deflate_state); forward; {local} function deflate_stored(var s : deflate_state; flush : int) : block_state; forward; {local} function deflate_fast(var s : deflate_state; flush : int) : block_state; forward; {local} function deflate_slow(var s : deflate_state; flush : int) : block_state; forward; {local} procedure lm_init(var s : deflate_state); forward; {local} procedure putShortMSB(var s : deflate_state; b : uInt); forward; {local} procedure flush_pending (var strm : z_stream); forward; {local} function read_buf(strm : z_streamp; buf : pBytef; size : unsigned) : int; forward; {$ifdef ASMV} procedure match_init; { asm code initialization } function longest_match(var deflate_state; cur_match : IPos) : uInt; forward; {$else} {local} function longest_match(var s : deflate_state; cur_match : IPos) : uInt; forward; {$endif} {$ifdef DEBUG} {local} procedure check_match(var s : deflate_state; start, match : IPos; length : int); forward; {$endif} { ========================================================================== local data } const ZNIL = 0; { Tail of hash chains } const TOO_FAR = 4096; { Matches of length 3 are discarded if their distance exceeds TOO_FAR } const MIN_LOOKAHEAD = (MAX_MATCH+MIN_MATCH+1); { Minimum amount of lookahead, except at the end of the input file. See deflate.c for comments about the MIN_MATCH+1. } {macro MAX_DIST(var s : deflate_state) : uInt; begin MAX_DIST := (s.w_size - MIN_LOOKAHEAD); end; In order to simplify the code, particularly on 16 bit machines, match distances are limited to MAX_DIST instead of WSIZE. } { Values for max_lazy_match, good_match and max_chain_length, depending on the desired pack level (0..9). The values given below have been tuned to exclude worst case performance for pathological files. Better values may be found for specific files. } type config = record good_length : ush; { reduce lazy search above this match length } max_lazy : ush; { do not perform lazy search above this match length } nice_length : ush; { quit search above this match length } max_chain : ush; func : compress_func; end; {local} const configuration_table : array[0..10-1] of config = ( { good lazy nice chain } {0} (good_length:0; max_lazy:0; nice_length:0; max_chain:0; func:deflate_stored), { store only } {1} (good_length:4; max_lazy:4; nice_length:8; max_chain:4; func:deflate_fast), { maximum speed, no lazy matches } {2} (good_length:4; max_lazy:5; nice_length:16; max_chain:8; func:deflate_fast), {3} (good_length:4; max_lazy:6; nice_length:32; max_chain:32; func:deflate_fast), {4} (good_length:4; max_lazy:4; nice_length:16; max_chain:16; func:deflate_slow), { lazy matches } {5} (good_length:8; max_lazy:16; nice_length:32; max_chain:32; func:deflate_slow), {6} (good_length:8; max_lazy:16; nice_length:128; max_chain:128; func:deflate_slow), {7} (good_length:8; max_lazy:32; nice_length:128; max_chain:256; func:deflate_slow), {8} (good_length:32; max_lazy:128; nice_length:258; max_chain:1024; func:deflate_slow), {9} (good_length:32; max_lazy:258; nice_length:258; max_chain:4096; func:deflate_slow)); { maximum compression } { Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 For deflate_fast() (levels <= 3) good is ignored and lazy has a different meaning. } const EQUAL = 0; { result of memcmp for equal strings } { ========================================================================== Update a hash value with the given input byte IN assertion: all calls to to UPDATE_HASH are made with consecutive input characters, so that a running hash key can be computed from the previous key instead of complete recalculation each time. macro UPDATE_HASH(s,h,c) h := (( (h) shl s^.hash_shift) xor (c)) and s^.hash_mask; } { =========================================================================== Insert string str in the dictionary and set match_head to the previous head of the hash chain (the most recent string with same hash key). Return the previous length of the hash chain. If this file is compiled with -DFASTEST, the compression level is forced to 1, and no hash chains are maintained. IN assertion: all calls to to INSERT_STRING are made with consecutive input characters and the first MIN_MATCH bytes of str are valid (except for the last MIN_MATCH-1 bytes of the input file). } procedure INSERT_STRING(var s : deflate_state; str : uInt; var match_head : IPos); begin {$ifdef FASTEST} {UPDATE_HASH(s, s.ins_h, s.window[(str) + (MIN_MATCH-1)])} s.ins_h := ((s.ins_h shl s.hash_shift) xor (s.window^[(str) + (MIN_MATCH-1)])) and s.hash_mask; match_head := s.head[s.ins_h] s.head[s.ins_h] := Pos(str); {$else} {UPDATE_HASH(s, s.ins_h, s.window[(str) + (MIN_MATCH-1)])} s.ins_h := ((s.ins_h shl s.hash_shift) xor (s.window^[(str) + (MIN_MATCH-1)])) and s.hash_mask; match_head := s.head^[s.ins_h]; s.prev^[(str) and s.w_mask] := match_head; s.head^[s.ins_h] := Pos(str); {$endif} end; { ========================================================================= Initialize the hash table (avoiding 64K overflow for 16 bit systems). prev[] will be initialized on the fly. macro CLEAR_HASH(s) s^.head[s^.hash_size-1] := ZNIL; zmemzero(pBytef(s^.head), unsigned(s^.hash_size-1)*sizeof(s^.head^[0])); } { ======================================================================== } function deflateInit2_(var strm : z_stream; level : int; method : int; windowBits : int; memLevel : int; strategy : int; const version : AnsiString; stream_size : int) : int; var s : deflate_state_ptr; noheader : int; overlay : pushfArray; { We overlay pending_buf and d_buf+l_buf. This works since the average output size for (length,distance) codes is <= 24 bits. } begin noheader := 0; if (version = '') or (version[1] <> ZLIB_VERSION[1]) or (stream_size <> sizeof(z_stream)) then begin deflateInit2_ := Z_VERSION_ERROR; exit; end; { if (strm = Z_NULL) then begin deflateInit2_ := Z_STREAM_ERROR; exit; end; } { SetLength(strm.msg, 255); } strm.msg := ''; if not Assigned(strm.zalloc) then begin {$IFDEF FPC} strm.zalloc := @zcalloc; {$ELSE} strm.zalloc := zcalloc; {$ENDIF} strm.opaque := voidpf(0); end; if not Assigned(strm.zfree) then {$IFDEF FPC} strm.zfree := @zcfree; {$ELSE} strm.zfree := zcfree; {$ENDIF} if (level = Z_DEFAULT_COMPRESSION) then level := 6; {$ifdef FASTEST} level := 1; {$endif} if (windowBits < 0) then { undocumented feature: suppress zlib header } begin noheader := 1; windowBits := -windowBits; end; if (memLevel < 1) or (memLevel > MAX_MEM_LEVEL) or (method <> Z_DEFLATED) or (windowBits < 8) or (windowBits > 15) or (level < 0) or (level > 9) or (strategy < 0) or (strategy > Z_HUFFMAN_ONLY) then begin deflateInit2_ := Z_STREAM_ERROR; exit; end; s := deflate_state_ptr (ZALLOC(strm, 1, sizeof(deflate_state))); if (s = Z_NULL) then begin deflateInit2_ := Z_MEM_ERROR; exit; end; strm.state := pInternal_state(s); s^.strm := @strm; s^.noheader := noheader; s^.w_bits := windowBits; s^.w_size := 1 shl s^.w_bits; s^.w_mask := s^.w_size - 1; s^.hash_bits := memLevel + 7; s^.hash_size := 1 shl s^.hash_bits; s^.hash_mask := s^.hash_size - 1; s^.hash_shift := ((s^.hash_bits+MIN_MATCH-1) div MIN_MATCH); s^.window := pzByteArray (ZALLOC(strm, s^.w_size, 2*sizeof(Byte))); s^.prev := pzPosfArray (ZALLOC(strm, s^.w_size, sizeof(Pos))); s^.head := pzPosfArray (ZALLOC(strm, s^.hash_size, sizeof(Pos))); s^.lit_bufsize := 1 shl (memLevel + 6); { 16K elements by default } overlay := pushfArray (ZALLOC(strm, s^.lit_bufsize, sizeof(ush)+2)); s^.pending_buf := pzByteArray (overlay); s^.pending_buf_size := ulg(s^.lit_bufsize) * (sizeof(ush)+Long(2)); if (s^.window = Z_NULL) or (s^.prev = Z_NULL) or (s^.head = Z_NULL) or (s^.pending_buf = Z_NULL) then begin {ERR_MSG(Z_MEM_ERROR);} strm.msg := z_errmsg[z_errbase-Z_MEM_ERROR]; deflateEnd (strm); deflateInit2_ := Z_MEM_ERROR; exit; end; s^.d_buf := pushfArray( @overlay^[s^.lit_bufsize div sizeof(ush)] ); s^.l_buf := puchfArray( @s^.pending_buf^[(1+sizeof(ush))*s^.lit_bufsize] ); s^.level := level; s^.strategy := strategy; s^.method := Byte(method); deflateInit2_ := deflateReset(strm); end; { ========================================================================= } function deflateInit2(var strm : z_stream; level : int; method : int; windowBits : int; memLevel : int; strategy : int) : int; { a macro } begin deflateInit2 := deflateInit2_(strm, level, method, windowBits, memLevel, strategy, ZLIB_VERSION, sizeof(z_stream)); end; { ========================================================================= } function deflateInit_(strm : z_streamp; level : int; const version : AnsiString; stream_size : int) : int; begin if (strm = Z_NULL) then deflateInit_ := Z_STREAM_ERROR else deflateInit_ := deflateInit2_(strm^, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, version, stream_size); { To do: ignore strm^.next_in if we use it as window } end; { ========================================================================= } function deflateInit(var strm : z_stream; level : int) : int; { deflateInit is a macro to allow checking the zlib version and the compiler's view of z_stream: } begin deflateInit := deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, ZLIB_VERSION, sizeof(z_stream)); end; { ======================================================================== } function deflateSetDictionary (var strm : z_stream; dictionary : pBytef; dictLength : uInt) : int; var s : deflate_state_ptr; length : uInt; n : uInt; hash_head : IPos; var MAX_DIST : uInt; {macro} begin length := dictLength; hash_head := 0; if {(@strm = Z_NULL) or} (strm.state = Z_NULL) or (dictionary = Z_NULL) or (deflate_state_ptr(strm.state)^.status <> INIT_STATE) then begin deflateSetDictionary := Z_STREAM_ERROR; exit; end; s := deflate_state_ptr(strm.state); strm.adler := adler32(strm.adler, dictionary, dictLength); if (length < MIN_MATCH) then begin deflateSetDictionary := Z_OK; exit; end; MAX_DIST := (s^.w_size - MIN_LOOKAHEAD); if (length > MAX_DIST) then begin length := MAX_DIST; {$ifndef USE_DICT_HEAD} Inc(dictionary, dictLength - length); { use the tail of the dictionary } {$endif} end; zmemcpy( pBytef(s^.window), dictionary, length); s^.strstart := length; s^.block_start := long(length); { Insert all strings in the hash table (except for the last two bytes). s^.lookahead stays null, so s^.ins_h will be recomputed at the next call of fill_window. } s^.ins_h := s^.window^[0]; {UPDATE_HASH(s, s^.ins_h, s^.window[1]);} s^.ins_h := ((s^.ins_h shl s^.hash_shift) xor (s^.window^[1])) and s^.hash_mask; for n := 0 to length - MIN_MATCH do begin INSERT_STRING(s^, n, hash_head); end; {if (hash_head <> 0) then hash_head := 0; - to make compiler happy } deflateSetDictionary := Z_OK; end; { ======================================================================== } function deflateReset (var strm : z_stream) : int; var s : deflate_state_ptr; begin if {(@strm = Z_NULL) or} (strm.state = Z_NULL) or (not Assigned(strm.zalloc)) or (not Assigned(strm.zfree)) then begin deflateReset := Z_STREAM_ERROR; exit; end; strm.total_out := 0; strm.total_in := 0; strm.msg := ''; { use zfree if we ever allocate msg dynamically } strm.data_type := Z_UNKNOWN; s := deflate_state_ptr(strm.state); s^.pending := 0; s^.pending_out := pBytef(s^.pending_buf); if (s^.noheader < 0) then begin s^.noheader := 0; { was set to -1 by deflate(..., Z_FINISH); } end; if s^.noheader <> 0 then s^.status := BUSY_STATE else s^.status := INIT_STATE; strm.adler := 1; s^.last_flush := Z_NO_FLUSH; _tr_init(s^); lm_init(s^); deflateReset := Z_OK; end; { ======================================================================== } function deflateParams(var strm : z_stream; level : int; strategy : int) : int; var s : deflate_state_ptr; func : compress_func; err : int; begin err := Z_OK; if {(@strm = Z_NULL) or} (strm.state = Z_NULL) then begin deflateParams := Z_STREAM_ERROR; exit; end; s := deflate_state_ptr(strm.state); if (level = Z_DEFAULT_COMPRESSION) then begin level := 6; end; if (level < 0) or (level > 9) or (strategy < 0) or (strategy > Z_HUFFMAN_ONLY) then begin deflateParams := Z_STREAM_ERROR; exit; end; func := configuration_table[s^.level].func; if (@func <> @configuration_table[level].func) and (strm.total_in <> 0) then begin { Flush the last buffer: } err := deflate(strm, Z_PARTIAL_FLUSH); end; if (s^.level <> level) then begin s^.level := level; s^.max_lazy_match := configuration_table[level].max_lazy; s^.good_match := configuration_table[level].good_length; s^.nice_match := configuration_table[level].nice_length; s^.max_chain_length := configuration_table[level].max_chain; end; s^.strategy := strategy; deflateParams := err; end; { ========================================================================= Put a short in the pending buffer. The 16-bit value is put in MSB order. IN assertion: the stream state is correct and there is enough room in pending_buf. } {local} procedure putShortMSB (var s : deflate_state; b : uInt); begin s.pending_buf^[s.pending] := Byte(b shr 8); Inc(s.pending); s.pending_buf^[s.pending] := Byte(b and $ff); Inc(s.pending); end; { ========================================================================= Flush as much pending output as possible. All deflate() output goes through this function so some applications may wish to modify it to avoid allocating a large strm^.next_out buffer and copying into it. (See also read_buf()). } {local} procedure flush_pending(var strm : z_stream); var len : unsigned; s : deflate_state_ptr; begin s := deflate_state_ptr(strm.state); len := s^.pending; if (len > strm.avail_out) then len := strm.avail_out; if (len = 0) then exit; zmemcpy(strm.next_out, s^.pending_out, len); Inc(strm.next_out, len); Inc(s^.pending_out, len); Inc(strm.total_out, len); Dec(strm.avail_out, len); Dec(s^.pending, len); if (s^.pending = 0) then begin s^.pending_out := pBytef(s^.pending_buf); end; end; { ========================================================================= } function deflate (var strm : z_stream; flush : int) : int; var old_flush : int; { value of flush param for previous deflate call } s : deflate_state_ptr; var header : uInt; level_flags : uInt; var bstate : block_state; begin if {(@strm = Z_NULL) or} (strm.state = Z_NULL) or (flush > Z_FINISH) or (flush < 0) then begin deflate := Z_STREAM_ERROR; exit; end; s := deflate_state_ptr(strm.state); if (strm.next_out = Z_NULL) or ((strm.next_in = Z_NULL) and (strm.avail_in <> 0)) or ((s^.status = FINISH_STATE) and (flush <> Z_FINISH)) then begin {ERR_RETURN(strm^, Z_STREAM_ERROR);} strm.msg := z_errmsg[z_errbase - Z_STREAM_ERROR]; deflate := Z_STREAM_ERROR; exit; end; if (strm.avail_out = 0) then begin {ERR_RETURN(strm^, Z_BUF_ERROR);} strm.msg := z_errmsg[z_errbase - Z_BUF_ERROR]; deflate := Z_BUF_ERROR; exit; end; s^.strm := @strm; { just in case } old_flush := s^.last_flush; s^.last_flush := flush; { Write the zlib header } if (s^.status = INIT_STATE) then begin header := (Z_DEFLATED + ((s^.w_bits-8) shl 4)) shl 8; level_flags := (s^.level-1) shr 1; if (level_flags > 3) then level_flags := 3; header := header or (level_flags shl 6); if (s^.strstart <> 0) then header := header or PRESET_DICT; Inc(header, 31 - (header mod 31)); s^.status := BUSY_STATE; putShortMSB(s^, header); { Save the adler32 of the preset dictionary: } if (s^.strstart <> 0) then begin putShortMSB(s^, uInt(strm.adler shr 16)); putShortMSB(s^, uInt(strm.adler and $ffff)); end; strm.adler := long(1); end; { Flush as much pending output as possible } if (s^.pending <> 0) then begin flush_pending(strm); if (strm.avail_out = 0) then begin { Since avail_out is 0, deflate will be called again with more output space, but possibly with both pending and avail_in equal to zero. There won't be anything to do, but this is not an error situation so make sure we return OK instead of BUF_ERROR at next call of deflate: } s^.last_flush := -1; deflate := Z_OK; exit; end; { Make sure there is something to do and avoid duplicate consecutive flushes. For repeated and useless calls with Z_FINISH, we keep returning Z_STREAM_END instead of Z_BUFF_ERROR. } end else if (strm.avail_in = 0) and (flush <= old_flush) and (flush <> Z_FINISH) then begin {ERR_RETURN(strm^, Z_BUF_ERROR);} strm.msg := z_errmsg[z_errbase - Z_BUF_ERROR]; deflate := Z_BUF_ERROR; exit; end; { User must not provide more input after the first FINISH: } if (s^.status = FINISH_STATE) and (strm.avail_in <> 0) then begin {ERR_RETURN(strm^, Z_BUF_ERROR);} strm.msg := z_errmsg[z_errbase - Z_BUF_ERROR]; deflate := Z_BUF_ERROR; exit; end; { Start a new block or continue the current one. } if (strm.avail_in <> 0) or (s^.lookahead <> 0) or ((flush <> Z_NO_FLUSH) and (s^.status <> FINISH_STATE)) then begin bstate := configuration_table[s^.level].func(s^, flush); if (bstate = finish_started) or (bstate = finish_done) then s^.status := FINISH_STATE; if (bstate = need_more) or (bstate = finish_started) then begin if (strm.avail_out = 0) then s^.last_flush := -1; { avoid BUF_ERROR next call, see above } deflate := Z_OK; exit; { If flush != Z_NO_FLUSH && avail_out == 0, the next call of deflate should use the same flush parameter to make sure that the flush is complete. So we don't have to output an empty block here, this will be done at next call. This also ensures that for a very small output buffer, we emit at most one empty block. } end; if (bstate = block_done) then begin if (flush = Z_PARTIAL_FLUSH) then _tr_align(s^) else begin { FULL_FLUSH or SYNC_FLUSH } _tr_stored_block(s^, pcharf(NIL), Long(0), FALSE); { For a full flush, this empty block will be recognized as a special marker by inflate_sync(). } if (flush = Z_FULL_FLUSH) then begin {macro CLEAR_HASH(s);} { forget history } s^.head^[s^.hash_size-1] := ZNIL; zmemzero(pBytef(s^.head), unsigned(s^.hash_size-1)*sizeof(s^.head^[0])); end; end; flush_pending(strm); if (strm.avail_out = 0) then begin s^.last_flush := -1; { avoid BUF_ERROR at next call, see above } deflate := Z_OK; exit; end; end; end; {$IFDEF DEBUG} Assert(strm.avail_out > 0, 'bug2'); {$ENDIF} if (flush <> Z_FINISH) then begin deflate := Z_OK; exit; end; if (s^.noheader <> 0) then begin deflate := Z_STREAM_END; exit; end; { Write the zlib trailer (adler32) } putShortMSB(s^, uInt(strm.adler shr 16)); putShortMSB(s^, uInt(strm.adler and $ffff)); flush_pending(strm); { If avail_out is zero, the application will call deflate again to flush the rest. } s^.noheader := -1; { write the trailer only once! } if s^.pending <> 0 then deflate := Z_OK else deflate := Z_STREAM_END; end; { ========================================================================= } function deflateEnd (var strm : z_stream) : int; var status : int; s : deflate_state_ptr; begin if {(@strm = Z_NULL) or} (strm.state = Z_NULL) then begin deflateEnd := Z_STREAM_ERROR; exit; end; s := deflate_state_ptr(strm.state); status := s^.status; if (status <> INIT_STATE) and (status <> BUSY_STATE) and (status <> FINISH_STATE) then begin deflateEnd := Z_STREAM_ERROR; exit; end; { Deallocate in reverse order of allocations: } TRY_FREE(strm, s^.pending_buf); TRY_FREE(strm, s^.head); TRY_FREE(strm, s^.prev); TRY_FREE(strm, s^.window); ZFREE(strm, s); strm.state := Z_NULL; if status = BUSY_STATE then deflateEnd := Z_DATA_ERROR else deflateEnd := Z_OK; end; { ========================================================================= Copy the source state to the destination state. To simplify the source, this is not supported for 16-bit MSDOS (which doesn't have enough memory anyway to duplicate compression states). } { ========================================================================= } function deflateCopy (dest, source : z_streamp) : int; {$ifndef MAXSEG_64K} var ds : deflate_state_ptr; ss : deflate_state_ptr; overlay : pushfArray; {$endif} begin {$ifdef MAXSEG_64K} deflateCopy := Z_STREAM_ERROR; exit; {$else} if (source = Z_NULL) or (dest = Z_NULL) or (source^.state = Z_NULL) then begin deflateCopy := Z_STREAM_ERROR; exit; end; ss := deflate_state_ptr(source^.state); dest^ := source^; ds := deflate_state_ptr( ZALLOC(dest^, 1, sizeof(deflate_state)) ); if (ds = Z_NULL) then begin deflateCopy := Z_MEM_ERROR; exit; end; dest^.state := pInternal_state(ds); ds^ := ss^; ds^.strm := dest; ds^.window := pzByteArray ( ZALLOC(dest^, ds^.w_size, 2*sizeof(Byte)) ); ds^.prev := pzPosfArray ( ZALLOC(dest^, ds^.w_size, sizeof(Pos)) ); ds^.head := pzPosfArray ( ZALLOC(dest^, ds^.hash_size, sizeof(Pos)) ); overlay := pushfArray ( ZALLOC(dest^, ds^.lit_bufsize, sizeof(ush)+2) ); ds^.pending_buf := pzByteArray ( overlay ); if (ds^.window = Z_NULL) or (ds^.prev = Z_NULL) or (ds^.head = Z_NULL) or (ds^.pending_buf = Z_NULL) then begin deflateEnd (dest^); deflateCopy := Z_MEM_ERROR; exit; end; { following zmemcpy do not work for 16-bit MSDOS } zmemcpy(pBytef(ds^.window), pBytef(ss^.window), ds^.w_size * 2 * sizeof(Byte)); zmemcpy(pBytef(ds^.prev), pBytef(ss^.prev), ds^.w_size * sizeof(Pos)); zmemcpy(pBytef(ds^.head), pBytef(ss^.head), ds^.hash_size * sizeof(Pos)); zmemcpy(pBytef(ds^.pending_buf), pBytef(ss^.pending_buf), uInt(ds^.pending_buf_size)); ds^.pending_out := @ds^.pending_buf^[ptr2int(ss^.pending_out) - ptr2int(ss^.pending_buf)]; ds^.d_buf := pushfArray (@overlay^[ds^.lit_bufsize div sizeof(ush)] ); ds^.l_buf := puchfArray (@ds^.pending_buf^[(1+sizeof(ush))*ds^.lit_bufsize]); ds^.l_desc.dyn_tree := tree_ptr(@ds^.dyn_ltree); ds^.d_desc.dyn_tree := tree_ptr(@ds^.dyn_dtree); ds^.bl_desc.dyn_tree := tree_ptr(@ds^.bl_tree); deflateCopy := Z_OK; {$endif} end; { =========================================================================== Read a new buffer from the current input stream, update the adler32 and total number of bytes read. All deflate() input goes through this function so some applications may wish to modify it to avoid allocating a large strm^.next_in buffer and copying from it. (See also flush_pending()). } {local} function read_buf(strm : z_streamp; buf : pBytef; size : unsigned) : int; var len : unsigned; begin len := strm^.avail_in; if (len > size) then len := size; if (len = 0) then begin read_buf := 0; exit; end; Dec(strm^.avail_in, len); if deflate_state_ptr(strm^.state)^.noheader = 0 then begin strm^.adler := adler32(strm^.adler, strm^.next_in, len); end; zmemcpy(buf, strm^.next_in, len); Inc(strm^.next_in, len); Inc(strm^.total_in, len); read_buf := int(len); end; { =========================================================================== Initialize the "longest match" routines for a new zlib stream } {local} procedure lm_init (var s : deflate_state); begin s.window_size := ulg( uLong(2)*s.w_size); {macro CLEAR_HASH(s);} s.head^[s.hash_size-1] := ZNIL; zmemzero(pBytef(s.head), unsigned(s.hash_size-1)*sizeof(s.head^[0])); { Set the default configuration parameters: } s.max_lazy_match := configuration_table[s.level].max_lazy; s.good_match := configuration_table[s.level].good_length; s.nice_match := configuration_table[s.level].nice_length; s.max_chain_length := configuration_table[s.level].max_chain; s.strstart := 0; s.block_start := long(0); s.lookahead := 0; s.prev_length := MIN_MATCH-1; s.match_length := MIN_MATCH-1; s.match_available := FALSE; s.ins_h := 0; {$ifdef ASMV} match_init; { initialize the asm code } {$endif} end; { =========================================================================== Set match_start to the longest match starting at the given string and return its length. Matches shorter or equal to prev_length are discarded, in which case the result is equal to prev_length and match_start is garbage. IN assertions: cur_match is the head of the hash chain for the current string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 OUT assertion: the match length is not greater than s^.lookahead. } {$ifndef ASMV} { For 80x86 and 680x0, an optimized version will be provided in match.asm or match.S. The code will be functionally equivalent. } {$ifndef FASTEST} {local} function longest_match(var s : deflate_state; cur_match : IPos { current match } ) : uInt; label nextstep; var chain_length : unsigned; { max hash chain length } {register} scan : pBytef; { current string } {register} match : pBytef; { matched string } {register} len : int; { length of current match } best_len : int; { best match length so far } nice_match : int; { stop if match long enough } limit : IPos; prev : pzPosfArray; wmask : uInt; {$ifdef UNALIGNED_OK} {register} strend : pBytef; {register} scan_start : ush; {register} scan_end : ush; {$else} {register} strend : pBytef; {register} scan_end1 : Byte; {register} scan_end : Byte; {$endif} var MAX_DIST : uInt; begin chain_length := s.max_chain_length; { max hash chain length } scan := @(s.window^[s.strstart]); best_len := s.prev_length; { best match length so far } nice_match := s.nice_match; { stop if match long enough } MAX_DIST := s.w_size - MIN_LOOKAHEAD; {In order to simplify the code, particularly on 16 bit machines, match distances are limited to MAX_DIST instead of WSIZE. } if s.strstart > IPos(MAX_DIST) then limit := s.strstart - IPos(MAX_DIST) else limit := ZNIL; { Stop when cur_match becomes <= limit. To simplify the code, we prevent matches with the string of window index 0. } prev := s.prev; wmask := s.w_mask; {$ifdef UNALIGNED_OK} { Compare two bytes at a time. Note: this is not always beneficial. Try with and without -DUNALIGNED_OK to check. } strend := pBytef(@(s.window^[s.strstart + MAX_MATCH - 1])); scan_start := pushf(scan)^; scan_end := pushfArray(scan)^[best_len-1]; { fix } {$else} strend := pBytef(@(s.window^[s.strstart + MAX_MATCH])); {$IFOPT R+} {$R-} {$DEFINE NoRangeCheck} {$ENDIF} scan_end1 := pzByteArray(scan)^[best_len-1]; {$IFDEF NoRangeCheck} {$R+} {$UNDEF NoRangeCheck} {$ENDIF} scan_end := pzByteArray(scan)^[best_len]; {$endif} { The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. It is easy to get rid of this optimization if necessary. } {$IFDEF DEBUG} Assert((s.hash_bits >= 8) and (MAX_MATCH = 258), 'Code too clever'); {$ENDIF} { Do not waste too much time if we already have a good match: } if (s.prev_length >= s.good_match) then begin chain_length := chain_length shr 2; end; { Do not look for matches beyond the end of the input. This is necessary to make deflate deterministic. } if (uInt(nice_match) > s.lookahead) then nice_match := s.lookahead; {$IFDEF DEBUG} Assert(ulg(s.strstart) <= s.window_size-MIN_LOOKAHEAD, 'need lookahead'); {$ENDIF} repeat {$IFDEF DEBUG} Assert(cur_match < s.strstart, 'no future'); {$ENDIF} match := @(s.window^[cur_match]); { Skip to next match if the match length cannot increase or if the match length is less than 2: } {$undef DO_UNALIGNED_OK} {$ifdef UNALIGNED_OK} {$ifdef MAX_MATCH_IS_258} {$define DO_UNALIGNED_OK} {$endif} {$endif} {$ifdef DO_UNALIGNED_OK} { This code assumes sizeof(unsigned short) = 2. Do not use UNALIGNED_OK if your compiler uses a different size. } {$IFOPT R+} {$R-} {$DEFINE NoRangeCheck} {$ENDIF} if (pushfArray(match)^[best_len-1] <> scan_end) or (pushf(match)^ <> scan_start) then goto nextstep; {continue;} {$IFDEF NoRangeCheck} {$R+} {$UNDEF NoRangeCheck} {$ENDIF} { It is not necessary to compare scan[2] and match[2] since they are always equal when the other bytes match, given that the hash keys are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at strstart+3, +5, ... up to strstart+257. We check for insufficient lookahead only every 4th comparison; the 128th check will be made at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is necessary to put more guard bytes at the end of the window, or to check more often for insufficient lookahead. } {$IFDEF DEBUG} Assert(pzByteArray(scan)^[2] = pzByteArray(match)^[2], 'scan[2]?'); {$ENDIF} Inc(scan); Inc(match); repeat Inc(scan,2); Inc(match,2); if (pushf(scan)^<>pushf(match)^) then break; Inc(scan,2); Inc(match,2); if (pushf(scan)^<>pushf(match)^) then break; Inc(scan,2); Inc(match,2); if (pushf(scan)^<>pushf(match)^) then break; Inc(scan,2); Inc(match,2); if (pushf(scan)^<>pushf(match)^) then break; until (ptr2int(scan) >= ptr2int(strend)); { The funny "do while" generates better code on most compilers } { Here, scan <= window+strstart+257 } {$IFDEF DEBUG} {$ifopt R+} {$define RangeCheck} {$endif} {$R-} Assert(ptr2int(scan) <= ptr2int(@(s.window^[unsigned(s.window_size-1)])), 'wild scan'); {$ifdef RangeCheck} {$R+} {$undef RangeCheck} {$endif} {$ENDIF} if (scan^ = match^) then Inc(scan); len := (MAX_MATCH - 1) - int(ptr2int(strend)) + int(ptr2int(scan)); scan := strend; Dec(scan, (MAX_MATCH-1)); {$else} { UNALIGNED_OK } {$IFOPT R+} {$R-} {$DEFINE NoRangeCheck} {$ENDIF} if (pzByteArray(match)^[best_len] <> scan_end) or (pzByteArray(match)^[best_len-1] <> scan_end1) or (match^ <> scan^) then goto nextstep; {continue;} {$IFDEF NoRangeCheck} {$R+} {$UNDEF NoRangeCheck} {$ENDIF} Inc(match); if (match^ <> pzByteArray(scan)^[1]) then goto nextstep; {continue;} { The check at best_len-1 can be removed because it will be made again later. (This heuristic is not always a win.) It is not necessary to compare scan[2] and match[2] since they are always equal when the other bytes match, given that the hash keys are equal and that HASH_BITS >= 8. } Inc(scan, 2); Inc(match); {$IFDEF DEBUG} Assert( scan^ = match^, 'match[2]?'); {$ENDIF} { We check for insufficient lookahead only every 8th comparison; the 256th check will be made at strstart+258. } repeat Inc(scan); Inc(match); if (scan^ <> match^) then break; Inc(scan); Inc(match); if (scan^ <> match^) then break; Inc(scan); Inc(match); if (scan^ <> match^) then break; Inc(scan); Inc(match); if (scan^ <> match^) then break; Inc(scan); Inc(match); if (scan^ <> match^) then break; Inc(scan); Inc(match); if (scan^ <> match^) then break; Inc(scan); Inc(match); if (scan^ <> match^) then break; Inc(scan); Inc(match); if (scan^ <> match^) then break; until (ptr2int(scan) >= ptr2int(strend)); {$IFDEF DEBUG} Assert(ptr2int(scan) <= ptr2int(@(s.window^[unsigned(s.window_size-1)])), 'wild scan'); {$ENDIF} len := MAX_MATCH - int(ptr2int(strend) - ptr2int(scan)); scan := strend; Dec(scan, MAX_MATCH); {$endif} { UNALIGNED_OK } if (len > best_len) then begin s.match_start := cur_match; best_len := len; if (len >= nice_match) then break; {$IFOPT R+} {$R-} {$DEFINE NoRangeCheck} {$ENDIF} {$ifdef UNALIGNED_OK} scan_end := pzByteArray(scan)^[best_len-1]; {$else} scan_end1 := pzByteArray(scan)^[best_len-1]; scan_end := pzByteArray(scan)^[best_len]; {$endif} {$IFDEF NoRangeCheck} {$R+} {$UNDEF NoRangeCheck} {$ENDIF} end; nextstep: cur_match := prev^[cur_match and wmask]; Dec(chain_length); until (cur_match <= limit) or (chain_length = 0); if (uInt(best_len) <= s.lookahead) then longest_match := uInt(best_len) else longest_match := s.lookahead; end; {$endif} { ASMV } {$else} { FASTEST } { --------------------------------------------------------------------------- Optimized version for level = 1 only } {local} function longest_match(var s : deflate_state; cur_match : IPos { current match } ) : uInt; var {register} scan : pBytef; { current string } {register} match : pBytef; { matched string } {register} len : int; { length of current match } {register} strend : pBytef; begin scan := @s.window^[s.strstart]; strend := @s.window^[s.strstart + MAX_MATCH]; { The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. It is easy to get rid of this optimization if necessary. } {$IFDEF DEBUG} Assert((s.hash_bits >= 8) and (MAX_MATCH = 258), 'Code too clever'); Assert(ulg(s.strstart) <= s.window_size-MIN_LOOKAHEAD, 'need lookahead'); Assert(cur_match < s.strstart, 'no future'); {$ENDIF} match := s.window + cur_match; { Return failure if the match length is less than 2: } if (match[0] <> scan[0]) or (match[1] <> scan[1]) then begin longest_match := MIN_MATCH-1; exit; end; { The check at best_len-1 can be removed because it will be made again later. (This heuristic is not always a win.) It is not necessary to compare scan[2] and match[2] since they are always equal when the other bytes match, given that the hash keys are equal and that HASH_BITS >= 8. } scan += 2, match += 2; Assert(scan^ = match^, 'match[2]?'); { We check for insufficient lookahead only every 8th comparison; the 256th check will be made at strstart+258. } repeat Inc(scan); Inc(match); if scan^<>match^ then break; Inc(scan); Inc(match); if scan^<>match^ then break; Inc(scan); Inc(match); if scan^<>match^ then break; Inc(scan); Inc(match); if scan^<>match^ then break; Inc(scan); Inc(match); if scan^<>match^ then break; Inc(scan); Inc(match); if scan^<>match^ then break; Inc(scan); Inc(match); if scan^<>match^ then break; Inc(scan); Inc(match); if scan^<>match^ then break; until (ptr2int(scan) >= ptr2int(strend)); Assert(scan <= s.window+unsigned(s.window_size-1), 'wild scan'); len := MAX_MATCH - int(strend - scan); if (len < MIN_MATCH) then begin return := MIN_MATCH - 1; exit; end; s.match_start := cur_match; if len <= s.lookahead then longest_match := len else longest_match := s.lookahead; end; {$endif} { FASTEST } {$ifdef DEBUG} { =========================================================================== Check that the match at match_start is indeed a match. } {local} procedure check_match(var s : deflate_state; start, match : IPos; length : int); begin exit; { check that the match is indeed a match } if (zmemcmp(pBytef(@s.window^[match]), pBytef(@s.window^[start]), length) <> EQUAL) then begin WriteLn(' start ',start,', match ',match ,' length ', length); repeat Write(AnsiChar(s.window^[match]), AnsiChar(s.window^[start])); Inc(match); Inc(start); Dec(length); Until (length = 0); z_error('invalid match'); end; if (z_verbose > 1) then begin Write('\\[',start-match,',',length,']'); repeat Write(AnsiChar(s.window^[start])); Inc(start); Dec(length); Until (length = 0); end; end; {$endif} { =========================================================================== Fill the window when the lookahead becomes insufficient. Updates strstart and lookahead. IN assertion: lookahead < MIN_LOOKAHEAD OUT assertions: strstart <= window_size-MIN_LOOKAHEAD At least one byte has been read, or avail_in = 0; reads are performed for at least two bytes (required for the zip translate_eol option -- not supported here). } {local} procedure fill_window(var s : deflate_state); var {register} n, m : unsigned; {register} p : pPosf; more : unsigned; { Amount of free space at the end of the window. } wsize : uInt; begin wsize := s.w_size; repeat more := unsigned(s.window_size -ulg(s.lookahead) -ulg(s.strstart)); { Deal with !@#$% 64K limit: } if (more = 0) and (s.strstart = 0) and (s.lookahead = 0) then more := wsize else if (more = unsigned(-1)) then begin { Very unlikely, but possible on 16 bit machine if strstart = 0 and lookahead = 1 (input done one byte at time) } Dec(more); { If the window is almost full and there is insufficient lookahead, move the upper half to the lower one to make room in the upper half.} end else if (s.strstart >= wsize+ {MAX_DIST}(wsize-MIN_LOOKAHEAD)) then begin zmemcpy( pBytef(s.window), pBytef(@(s.window^[wsize])), unsigned(wsize)); Dec(s.match_start, wsize); Dec(s.strstart, wsize); { we now have strstart >= MAX_DIST } Dec(s.block_start, long(wsize)); { Slide the hash table (could be avoided with 32 bit values at the expense of memory usage). We slide even when level = 0 to keep the hash table consistent if we switch back to level > 0 later. (Using level 0 permanently is not an optimal usage of zlib, so we don't care about this pathological case.) } n := s.hash_size; p := @s.head^[n]; repeat Dec(p); m := p^; if (m >= wsize) then p^ := Pos(m-wsize) else p^ := Pos(ZNIL); Dec(n); Until (n=0); n := wsize; {$ifndef FASTEST} p := @s.prev^[n]; repeat Dec(p); m := p^; if (m >= wsize) then p^ := Pos(m-wsize) else p^:= Pos(ZNIL); { If n is not on any hash chain, prev^[n] is garbage but its value will never be used. } Dec(n); Until (n=0); {$endif} Inc(more, wsize); end; if (s.strm^.avail_in = 0) then exit; {* If there was no sliding: * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && * more == window_size - lookahead - strstart * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) * => more >= window_size - 2*WSIZE + 2 * In the BIG_MEM or MMAP case (not yet supported), * window_size == input_size + MIN_LOOKAHEAD && * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. * Otherwise, window_size == 2*WSIZE so more >= 2. * If there was sliding, more >= WSIZE. So in all cases, more >= 2. } {$IFDEF DEBUG} Assert(more >= 2, 'more < 2'); {$ENDIF} n := read_buf(s.strm, pBytef(@(s.window^[s.strstart + s.lookahead])), more); Inc(s.lookahead, n); { Initialize the hash value now that we have some input: } if (s.lookahead >= MIN_MATCH) then begin s.ins_h := s.window^[s.strstart]; {UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]);} s.ins_h := ((s.ins_h shl s.hash_shift) xor s.window^[s.strstart+1]) and s.hash_mask; {$ifdef MIN_MATCH <> 3} Call UPDATE_HASH() MIN_MATCH-3 more times {$endif} end; { If the whole input has less than MIN_MATCH bytes, ins_h is garbage, but this is not important since only literal bytes will be emitted. } until (s.lookahead >= MIN_LOOKAHEAD) or (s.strm^.avail_in = 0); end; { =========================================================================== Flush the current block, with given end-of-file flag. IN assertion: strstart is set to the end of the current match. } procedure FLUSH_BLOCK_ONLY(var s : deflate_state; eof : boolean); {macro} begin if (s.block_start >= Long(0)) then _tr_flush_block(s, pcharf(@s.window^[unsigned(s.block_start)]), ulg(long(s.strstart) - s.block_start), eof) else _tr_flush_block(s, pcharf(Z_NULL), ulg(long(s.strstart) - s.block_start), eof); s.block_start := s.strstart; flush_pending(s.strm^); {$IFDEF DEBUG} Tracev('[FLUSH]'); {$ENDIF} end; { Same but force premature exit if necessary. macro FLUSH_BLOCK(var s : deflate_state; eof : boolean) : boolean; var result : block_state; begin FLUSH_BLOCK_ONLY(s, eof); if (s.strm^.avail_out = 0) then begin if eof then result := finish_started else result := need_more; exit; end; end; } { =========================================================================== Copy without compression as much as possible from the input stream, return the current block state. This function does not insert new strings in the dictionary since uncompressible data is probably not useful. This function is used only for the level=0 compression option. NOTE: this function should be optimized to avoid extra copying from window to pending_buf. } {local} function deflate_stored(var s : deflate_state; flush : int) : block_state; { Stored blocks are limited to 0xffff bytes, pending_buf is limited to pending_buf_size, and each stored block has a 5 byte header: } var max_block_size : ulg; max_start : ulg; begin max_block_size := $ffff; if (max_block_size > s.pending_buf_size - 5) then max_block_size := s.pending_buf_size - 5; { Copy as much as possible from input to output: } while TRUE do begin { Fill the window as much as possible: } if (s.lookahead <= 1) then begin {$IFDEF DEBUG} Assert( (s.strstart < s.w_size + {MAX_DIST}s.w_size-MIN_LOOKAHEAD) or (s.block_start >= long(s.w_size)), 'slide too late'); {$ENDIF} fill_window(s); if (s.lookahead = 0) and (flush = Z_NO_FLUSH) then begin deflate_stored := need_more; exit; end; if (s.lookahead = 0) then break; { flush the current block } end; {$IFDEF DEBUG} Assert(s.block_start >= long(0), 'block gone'); {$ENDIF} Inc(s.strstart, s.lookahead); s.lookahead := 0; { Emit a stored block if pending_buf will be full: } max_start := s.block_start + max_block_size; if (s.strstart = 0) or (ulg(s.strstart) >= max_start) then begin { strstart = 0 is possible when wraparound on 16-bit machine } s.lookahead := s.strstart - uInt(max_start); s.strstart := uInt(max_start); {FLUSH_BLOCK(s, FALSE);} FLUSH_BLOCK_ONLY(s, FALSE); if (s.strm^.avail_out = 0) then begin deflate_stored := need_more; exit; end; end; { Flush if we may have to slide, otherwise block_start may become negative and the data will be gone: } if (s.strstart - uInt(s.block_start) >= {MAX_DIST} s.w_size-MIN_LOOKAHEAD) then begin {FLUSH_BLOCK(s, FALSE);} FLUSH_BLOCK_ONLY(s, FALSE); if (s.strm^.avail_out = 0) then begin deflate_stored := need_more; exit; end; end; end; {FLUSH_BLOCK(s, flush = Z_FINISH);} FLUSH_BLOCK_ONLY(s, flush = Z_FINISH); if (s.strm^.avail_out = 0) then begin if flush = Z_FINISH then deflate_stored := finish_started else deflate_stored := need_more; exit; end; if flush = Z_FINISH then deflate_stored := finish_done else deflate_stored := block_done; end; { =========================================================================== Compress as much as possible from the input stream, return the current block state. This function does not perform lazy evaluation of matches and inserts new strings in the dictionary only for unmatched strings or for short matches. It is used only for the fast compression options. } {local} function deflate_fast(var s : deflate_state; flush : int) : block_state; var hash_head : IPos; { head of the hash chain } bflush : boolean; { set if current block must be flushed } begin hash_head := ZNIL; while TRUE do begin { Make sure that we always have enough lookahead, except at the end of the input file. We need MAX_MATCH bytes for the next match, plus MIN_MATCH bytes to insert the string following the next match. } if (s.lookahead < MIN_LOOKAHEAD) then begin fill_window(s); if (s.lookahead < MIN_LOOKAHEAD) and (flush = Z_NO_FLUSH) then begin deflate_fast := need_more; exit; end; if (s.lookahead = 0) then break; { flush the current block } end; { Insert the string window[strstart .. strstart+2] in the dictionary, and set hash_head to the head of the hash chain: } if (s.lookahead >= MIN_MATCH) then begin INSERT_STRING(s, s.strstart, hash_head); end; { Find the longest match, discarding those <= prev_length. At this point we have always match_length < MIN_MATCH } if (hash_head <> ZNIL) and (s.strstart - hash_head <= (s.w_size-MIN_LOOKAHEAD){MAX_DIST}) then begin { To simplify the code, we prevent matches with the string of window index 0 (in particular we have to avoid a match of the string with itself at the start of the input file). } if (s.strategy <> Z_HUFFMAN_ONLY) then begin s.match_length := longest_match (s, hash_head); end; { longest_match() sets match_start } end; if (s.match_length >= MIN_MATCH) then begin {$IFDEF DEBUG} check_match(s, s.strstart, s.match_start, s.match_length); {$ENDIF} {_tr_tally_dist(s, s.strstart - s.match_start, s.match_length - MIN_MATCH, bflush);} bflush := _tr_tally(s, s.strstart - s.match_start, s.match_length - MIN_MATCH); Dec(s.lookahead, s.match_length); { Insert new strings in the hash table only if the match length is not too large. This saves time but degrades compression. } {$ifndef FASTEST} if (s.match_length <= s.max_insert_length) and (s.lookahead >= MIN_MATCH) then begin Dec(s.match_length); { string at strstart already in hash table } repeat Inc(s.strstart); INSERT_STRING(s, s.strstart, hash_head); { strstart never exceeds WSIZE-MAX_MATCH, so there are always MIN_MATCH bytes ahead. } Dec(s.match_length); until (s.match_length = 0); Inc(s.strstart); end else {$endif} begin Inc(s.strstart, s.match_length); s.match_length := 0; s.ins_h := s.window^[s.strstart]; {UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]);} s.ins_h := (( s.ins_h shl s.hash_shift) xor s.window^[s.strstart+1]) and s.hash_mask; if MIN_MATCH <> 3 then { the linker removes this } begin {Call UPDATE_HASH() MIN_MATCH-3 more times} end; { If lookahead < MIN_MATCH, ins_h is garbage, but it does not matter since it will be recomputed at next deflate call. } end; end else begin { No match, output a literal byte } {$IFDEF DEBUG} Tracevv(AnsiChar(s.window^[s.strstart])); {$ENDIF} {_tr_tally_lit (s, 0, s.window^[s.strstart], bflush);} bflush := _tr_tally (s, 0, s.window^[s.strstart]); Dec(s.lookahead); Inc(s.strstart); end; if bflush then begin {FLUSH_BLOCK(s, FALSE);} FLUSH_BLOCK_ONLY(s, FALSE); if (s.strm^.avail_out = 0) then begin deflate_fast := need_more; exit; end; end; end; {FLUSH_BLOCK(s, flush = Z_FINISH);} FLUSH_BLOCK_ONLY(s, flush = Z_FINISH); if (s.strm^.avail_out = 0) then begin if flush = Z_FINISH then deflate_fast := finish_started else deflate_fast := need_more; exit; end; if flush = Z_FINISH then deflate_fast := finish_done else deflate_fast := block_done; end; { =========================================================================== Same as above, but achieves better compression. We use a lazy evaluation for matches: a match is finally adopted only if there is no better match at the next window position. } {local} function deflate_slow(var s : deflate_state; flush : int) : block_state; var hash_head : IPos; { head of hash chain } bflush : boolean; { set if current block must be flushed } var max_insert : uInt; begin hash_head := ZNIL; { Process the input block. } while TRUE do begin { Make sure that we always have enough lookahead, except at the end of the input file. We need MAX_MATCH bytes for the next match, plus MIN_MATCH bytes to insert the string following the next match. } if (s.lookahead < MIN_LOOKAHEAD) then begin fill_window(s); if (s.lookahead < MIN_LOOKAHEAD) and (flush = Z_NO_FLUSH) then begin deflate_slow := need_more; exit; end; if (s.lookahead = 0) then break; { flush the current block } end; { Insert the string window[strstart .. strstart+2] in the dictionary, and set hash_head to the head of the hash chain: } if (s.lookahead >= MIN_MATCH) then begin INSERT_STRING(s, s.strstart, hash_head); end; { Find the longest match, discarding those <= prev_length. } s.prev_length := s.match_length; s.prev_match := s.match_start; s.match_length := MIN_MATCH-1; if (hash_head <> ZNIL) and (s.prev_length < s.max_lazy_match) and (s.strstart - hash_head <= {MAX_DIST}(s.w_size-MIN_LOOKAHEAD)) then begin { To simplify the code, we prevent matches with the string of window index 0 (in particular we have to avoid a match of the string with itself at the start of the input file). } if (s.strategy <> Z_HUFFMAN_ONLY) then begin s.match_length := longest_match (s, hash_head); end; { longest_match() sets match_start } if (s.match_length <= 5) and ((s.strategy = Z_FILTERED) or ((s.match_length = MIN_MATCH) and (s.strstart - s.match_start > TOO_FAR))) then begin { If prev_match is also MIN_MATCH, match_start is garbage but we will ignore the current match anyway. } s.match_length := MIN_MATCH-1; end; end; { If there was a match at the previous step and the current match is not better, output the previous match: } if (s.prev_length >= MIN_MATCH) and (s.match_length <= s.prev_length) then begin max_insert := s.strstart + s.lookahead - MIN_MATCH; { Do not insert strings in hash table beyond this. } {$ifdef DEBUG} check_match(s, s.strstart-1, s.prev_match, s.prev_length); {$endif} {_tr_tally_dist(s, s->strstart -1 - s->prev_match, s->prev_length - MIN_MATCH, bflush);} bflush := _tr_tally(s, s.strstart -1 - s.prev_match, s.prev_length - MIN_MATCH); { Insert in hash table all strings up to the end of the match. strstart-1 and strstart are already inserted. If there is not enough lookahead, the last two strings are not inserted in the hash table. } Dec(s.lookahead, s.prev_length-1); Dec(s.prev_length, 2); repeat Inc(s.strstart); if (s.strstart <= max_insert) then begin INSERT_STRING(s, s.strstart, hash_head); end; Dec(s.prev_length); until (s.prev_length = 0); s.match_available := FALSE; s.match_length := MIN_MATCH-1; Inc(s.strstart); if (bflush) then {FLUSH_BLOCK(s, FALSE);} begin FLUSH_BLOCK_ONLY(s, FALSE); if (s.strm^.avail_out = 0) then begin deflate_slow := need_more; exit; end; end; end else if (s.match_available) then begin { If there was no match at the previous position, output a single literal. If there was a match but the current match is longer, truncate the previous match to a single literal. } {$IFDEF DEBUG} Tracevv(AnsiChar(s.window^[s.strstart-1])); {$ENDIF} bflush := _tr_tally (s, 0, s.window^[s.strstart-1]); if bflush then begin FLUSH_BLOCK_ONLY(s, FALSE); end; Inc(s.strstart); Dec(s.lookahead); if (s.strm^.avail_out = 0) then begin deflate_slow := need_more; exit; end; end else begin { There is no previous match to compare with, wait for the next step to decide. } s.match_available := TRUE; Inc(s.strstart); Dec(s.lookahead); end; end; {$IFDEF DEBUG} Assert (flush <> Z_NO_FLUSH, 'no flush?'); {$ENDIF} if (s.match_available) then begin {$IFDEF DEBUG} Tracevv(AnsiChar(s.window^[s.strstart-1])); bflush := {$ENDIF} _tr_tally (s, 0, s.window^[s.strstart-1]); s.match_available := FALSE; end; {FLUSH_BLOCK(s, flush = Z_FINISH);} FLUSH_BLOCK_ONLY(s, flush = Z_FINISH); if (s.strm^.avail_out = 0) then begin if flush = Z_FINISH then deflate_slow := finish_started else deflate_slow := need_more; exit; end; if flush = Z_FINISH then deflate_slow := finish_done else deflate_slow := block_done; end; end. ================================================ FILE: lib/Imaging/ZLib/imzinflate.pas ================================================ Unit imzinflate; { inflate.c -- zlib interface to inflate modules Copyright (C) 1995-1998 Mark Adler Pascal tranlastion Copyright (C) 1998 by Jacques Nomssi Nzali For conditions of distribution and use, see copyright notice in readme.txt } interface {$I imzconf.inc} uses imzutil, impaszlib, iminfblock, iminfutil; function inflateInit(var z : z_stream) : int; { Initializes the internal stream state for decompression. The fields zalloc, zfree and opaque must be initialized before by the caller. If zalloc and zfree are set to Z_NULL, inflateInit updates them to use default allocation functions. inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_VERSION_ERROR if the zlib library version is incompatible with the version assumed by the caller. msg is set to null if there is no error message. inflateInit does not perform any decompression: this will be done by inflate(). } function inflateInit_(z : z_streamp; const version : AnsiString; stream_size : int) : int; function inflateInit2_(var z: z_stream; w : int; const version : AnsiString; stream_size : int) : int; function inflateInit2(var z: z_stream; windowBits : int) : int; { This is another version of inflateInit with an extra parameter. The fields next_in, avail_in, zalloc, zfree and opaque must be initialized before by the caller. The windowBits parameter is the base two logarithm of the maximum window size (the size of the history buffer). It should be in the range 8..15 for this version of the library. The default value is 15 if inflateInit is used instead. If a compressed stream with a larger window size is given as input, inflate() will return with the error code Z_DATA_ERROR instead of trying to allocate a larger window. inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative memLevel). msg is set to null if there is no error message. inflateInit2 does not perform any decompression apart from reading the zlib header if present: this will be done by inflate(). (So next_in and avail_in may be modified, but next_out and avail_out are unchanged.) } function inflateEnd(var z : z_stream) : int; { All dynamically allocated data structures for this stream are freed. This function discards any unprocessed input and does not flush any pending output. inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state was inconsistent. In the error case, msg may be set but then points to a static string (which must not be deallocated). } function inflateReset(var z : z_stream) : int; { This function is equivalent to inflateEnd followed by inflateInit, but does not free and reallocate all the internal decompression state. The stream will keep attributes that may have been set by inflateInit2. inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source stream state was inconsistent (such as zalloc or state being NULL). } function inflate(var z : z_stream; f : int) : int; { inflate decompresses as much data as possible, and stops when the input buffer becomes empty or the output buffer becomes full. It may introduce some output latency (reading input without producing any output) except when forced to flush. The detailed semantics are as follows. inflate performs one or both of the following actions: - Decompress more input starting at next_in and update next_in and avail_in accordingly. If not all input can be processed (because there is not enough room in the output buffer), next_in is updated and processing will resume at this point for the next call of inflate(). - Provide more output starting at next_out and update next_out and avail_out accordingly. inflate() provides as much output as possible, until there is no more input data or no more space in the output buffer (see below about the flush parameter). Before the call of inflate(), the application should ensure that at least one of the actions is possible, by providing more input and/or consuming more output, and updating the next_* and avail_* values accordingly. The application can consume the uncompressed output when it wants, for example when the output buffer is full (avail_out == 0), or after each call of inflate(). If inflate returns Z_OK and with zero avail_out, it must be called again after making room in the output buffer because there might be more output pending. If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much output as possible to the output buffer. The flushing behavior of inflate is not specified for values of the flush parameter other than Z_SYNC_FLUSH and Z_FINISH, but the current implementation actually flushes as much output as possible anyway. inflate() should normally be called until it returns Z_STREAM_END or an error. However if all decompression is to be performed in a single step (a single call of inflate), the parameter flush should be set to Z_FINISH. In this case all pending input is processed and all pending output is flushed; avail_out must be large enough to hold all the uncompressed data. (The size of the uncompressed data may have been saved by the compressor for this purpose.) The next operation on this stream must be inflateEnd to deallocate the decompression state. The use of Z_FINISH is never required, but can be used to inform inflate that a faster routine may be used for the single inflate() call. If a preset dictionary is needed at this point (see inflateSetDictionary below), inflate sets strm-adler to the adler32 checksum of the dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise it sets strm->adler to the adler32 checksum of all output produced so far (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described below. At the end of the stream, inflate() checks that its computed adler32 checksum is equal to that saved by the compressor and returns Z_STREAM_END only if the checksum is correct. inflate() returns Z_OK if some progress has been made (more input processed or more output produced), Z_STREAM_END if the end of the compressed data has been reached and all uncompressed output has been produced, Z_NEED_DICT if a preset dictionary is needed at this point, Z_DATA_ERROR if the input data was corrupted (input stream not conforming to the zlib format or incorrect adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, Z_BUF_ERROR if no progress is possible or if there was not enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR case, the application may then call inflateSync to look for a good compression block. } function inflateSetDictionary(var z : z_stream; dictionary : pBytef; {const array of byte} dictLength : uInt) : int; { Initializes the decompression dictionary from the given uncompressed byte sequence. This function must be called immediately after a call of inflate if this call returned Z_NEED_DICT. The dictionary chosen by the compressor can be determined from the Adler32 value returned by this call of inflate. The compressor and decompressor must use exactly the same dictionary (see deflateSetDictionary). inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a parameter is invalid (such as NULL dictionary) or the stream state is inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the expected one (incorrect Adler32 value). inflateSetDictionary does not perform any decompression: this will be done by subsequent calls of inflate(). } function inflateSync(var z : z_stream) : int; { Skips invalid compressed data until a full flush point (see above the description of deflate with Z_FULL_FLUSH) can be found, or until all available input is skipped. No output is provided. inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR if no more input was provided, Z_DATA_ERROR if no flush point has been found, or Z_STREAM_ERROR if the stream structure was inconsistent. In the success case, the application may save the current current value of total_in which indicates where valid compressed data was found. In the error case, the application may repeatedly call inflateSync, providing more input each time, until success or end of the input data. } function inflateSyncPoint(var z : z_stream) : int; implementation uses imadler; function inflateReset(var z : z_stream) : int; begin if (z.state = Z_NULL) then begin inflateReset := Z_STREAM_ERROR; exit; end; z.total_out := 0; z.total_in := 0; z.msg := ''; if z.state^.nowrap then z.state^.mode := BLOCKS else z.state^.mode := METHOD; inflate_blocks_reset(z.state^.blocks^, z, Z_NULL); {$IFDEF DEBUG} Tracev('inflate: reset'); {$ENDIF} inflateReset := Z_OK; end; function inflateEnd(var z : z_stream) : int; begin if (z.state = Z_NULL) or not Assigned(z.zfree) then begin inflateEnd := Z_STREAM_ERROR; exit; end; if (z.state^.blocks <> Z_NULL) then inflate_blocks_free(z.state^.blocks, z); ZFREE(z, z.state); z.state := Z_NULL; {$IFDEF DEBUG} Tracev('inflate: end'); {$ENDIF} inflateEnd := Z_OK; end; function inflateInit2_(var z: z_stream; w : int; const version : AnsiString; stream_size : int) : int; begin if (version = '') or (version[1] <> ZLIB_VERSION[1]) or (stream_size <> sizeof(z_stream)) then begin inflateInit2_ := Z_VERSION_ERROR; exit; end; { initialize state } { SetLength(strm.msg, 255); } z.msg := ''; if not Assigned(z.zalloc) then begin {$IFDEF FPC} z.zalloc := @zcalloc; {$ELSE} z.zalloc := zcalloc; {$endif} z.opaque := voidpf(0); end; if not Assigned(z.zfree) then {$IFDEF FPC} z.zfree := @zcfree; {$ELSE} z.zfree := zcfree; {$ENDIF} z.state := pInternal_state( ZALLOC(z,1,sizeof(internal_state)) ); if (z.state = Z_NULL) then begin inflateInit2_ := Z_MEM_ERROR; exit; end; z.state^.blocks := Z_NULL; { handle undocumented nowrap option (no zlib header or check) } z.state^.nowrap := FALSE; if (w < 0) then begin w := - w; z.state^.nowrap := TRUE; end; { set window size } if (w < 8) or (w > 15) then begin inflateEnd(z); inflateInit2_ := Z_STREAM_ERROR; exit; end; z.state^.wbits := uInt(w); { create inflate_blocks state } if z.state^.nowrap then z.state^.blocks := inflate_blocks_new(z, NIL, uInt(1) shl w) else {$IFDEF FPC} z.state^.blocks := inflate_blocks_new(z, @adler32, uInt(1) shl w); {$ELSE} z.state^.blocks := inflate_blocks_new(z, adler32, uInt(1) shl w); {$ENDIF} if (z.state^.blocks = Z_NULL) then begin inflateEnd(z); inflateInit2_ := Z_MEM_ERROR; exit; end; {$IFDEF DEBUG} Tracev('inflate: allocated'); {$ENDIF} { reset state } inflateReset(z); inflateInit2_ := Z_OK; end; function inflateInit2(var z: z_stream; windowBits : int) : int; begin inflateInit2 := inflateInit2_(z, windowBits, ZLIB_VERSION, sizeof(z_stream)); end; function inflateInit(var z : z_stream) : int; { inflateInit is a macro to allow checking the zlib version and the compiler's view of z_stream: } begin inflateInit := inflateInit2_(z, DEF_WBITS, ZLIB_VERSION, sizeof(z_stream)); end; function inflateInit_(z : z_streamp; const version : AnsiString; stream_size : int) : int; begin { initialize state } if (z = Z_NULL) then inflateInit_ := Z_STREAM_ERROR else inflateInit_ := inflateInit2_(z^, DEF_WBITS, version, stream_size); end; function inflate(var z : z_stream; f : int) : int; var r : int; b : uInt; begin if (z.state = Z_NULL) or (z.next_in = Z_NULL) then begin inflate := Z_STREAM_ERROR; exit; end; if f = Z_FINISH then f := Z_BUF_ERROR else f := Z_OK; r := Z_BUF_ERROR; while True do case (z.state^.mode) of BLOCKS: begin r := inflate_blocks(z.state^.blocks^, z, r); if (r = Z_DATA_ERROR) then begin z.state^.mode := BAD; z.state^.sub.marker := 0; { can try inflateSync } continue; { break C-switch } end; if (r = Z_OK) then r := f; if (r <> Z_STREAM_END) then begin inflate := r; exit; end; r := f; inflate_blocks_reset(z.state^.blocks^, z, @z.state^.sub.check.was); if (z.state^.nowrap) then begin z.state^.mode := DONE; continue; { break C-switch } end; z.state^.mode := CHECK4; { falltrough } end; CHECK4: begin {NEEDBYTE} if (z.avail_in = 0) then begin inflate := r; exit; end; r := f; {z.state^.sub.check.need := uLong(NEXTBYTE(z)) shl 24;} Dec(z.avail_in); Inc(z.total_in); z.state^.sub.check.need := uLong(z.next_in^) shl 24; Inc(z.next_in); z.state^.mode := CHECK3; { falltrough } end; CHECK3: begin {NEEDBYTE} if (z.avail_in = 0) then begin inflate := r; exit; end; r := f; {Inc( z.state^.sub.check.need, uLong(NEXTBYTE(z)) shl 16);} Dec(z.avail_in); Inc(z.total_in); Inc(z.state^.sub.check.need, uLong(z.next_in^) shl 16); Inc(z.next_in); z.state^.mode := CHECK2; { falltrough } end; CHECK2: begin {NEEDBYTE} if (z.avail_in = 0) then begin inflate := r; exit; end; r := f; {Inc( z.state^.sub.check.need, uLong(NEXTBYTE(z)) shl 8);} Dec(z.avail_in); Inc(z.total_in); Inc(z.state^.sub.check.need, uLong(z.next_in^) shl 8); Inc(z.next_in); z.state^.mode := CHECK1; { falltrough } end; CHECK1: begin {NEEDBYTE} if (z.avail_in = 0) then begin inflate := r; exit; end; r := f; {Inc( z.state^.sub.check.need, uLong(NEXTBYTE(z)) );} Dec(z.avail_in); Inc(z.total_in); Inc(z.state^.sub.check.need, uLong(z.next_in^) ); Inc(z.next_in); if (z.state^.sub.check.was <> z.state^.sub.check.need) then begin z.state^.mode := BAD; z.msg := 'incorrect data check'; z.state^.sub.marker := 5; { can't try inflateSync } continue; { break C-switch } end; {$IFDEF DEBUG} Tracev('inflate: zlib check ok'); {$ENDIF} z.state^.mode := DONE; { falltrough } end; DONE: begin inflate := Z_STREAM_END; exit; end; METHOD: begin {NEEDBYTE} if (z.avail_in = 0) then begin inflate := r; exit; end; r := f; {} {z.state^.sub.method := NEXTBYTE(z);} Dec(z.avail_in); Inc(z.total_in); z.state^.sub.method := z.next_in^; Inc(z.next_in); if ((z.state^.sub.method and $0f) <> Z_DEFLATED) then begin z.state^.mode := BAD; z.msg := 'unknown compression method'; z.state^.sub.marker := 5; { can't try inflateSync } continue; { break C-switch } end; if ((z.state^.sub.method shr 4) + 8 > z.state^.wbits) then begin z.state^.mode := BAD; z.msg := 'invalid window size'; z.state^.sub.marker := 5; { can't try inflateSync } continue; { break C-switch } end; z.state^.mode := FLAG; { fall trough } end; FLAG: begin {NEEDBYTE} if (z.avail_in = 0) then begin inflate := r; exit; end; r := f; {} {b := NEXTBYTE(z);} Dec(z.avail_in); Inc(z.total_in); b := z.next_in^; Inc(z.next_in); if (((z.state^.sub.method shl 8) + b) mod 31) <> 0 then {% mod ?} begin z.state^.mode := BAD; z.msg := 'incorrect header check'; z.state^.sub.marker := 5; { can't try inflateSync } continue; { break C-switch } end; {$IFDEF DEBUG} Tracev('inflate: zlib header ok'); {$ENDIF} if ((b and PRESET_DICT) = 0) then begin z.state^.mode := BLOCKS; continue; { break C-switch } end; z.state^.mode := DICT4; { falltrough } end; DICT4: begin if (z.avail_in = 0) then begin inflate := r; exit; end; r := f; {z.state^.sub.check.need := uLong(NEXTBYTE(z)) shl 24;} Dec(z.avail_in); Inc(z.total_in); z.state^.sub.check.need := uLong(z.next_in^) shl 24; Inc(z.next_in); z.state^.mode := DICT3; { falltrough } end; DICT3: begin if (z.avail_in = 0) then begin inflate := r; exit; end; r := f; {Inc(z.state^.sub.check.need, uLong(NEXTBYTE(z)) shl 16);} Dec(z.avail_in); Inc(z.total_in); Inc(z.state^.sub.check.need, uLong(z.next_in^) shl 16); Inc(z.next_in); z.state^.mode := DICT2; { falltrough } end; DICT2: begin if (z.avail_in = 0) then begin inflate := r; exit; end; r := f; {Inc(z.state^.sub.check.need, uLong(NEXTBYTE(z)) shl 8);} Dec(z.avail_in); Inc(z.total_in); Inc(z.state^.sub.check.need, uLong(z.next_in^) shl 8); Inc(z.next_in); z.state^.mode := DICT1; { falltrough } end; DICT1: begin if (z.avail_in = 0) then begin inflate := r; exit; end; { r := f; --- wird niemals benutzt } {Inc(z.state^.sub.check.need, uLong(NEXTBYTE(z)) );} Dec(z.avail_in); Inc(z.total_in); Inc(z.state^.sub.check.need, uLong(z.next_in^) ); Inc(z.next_in); z.adler := z.state^.sub.check.need; z.state^.mode := DICT0; inflate := Z_NEED_DICT; exit; end; DICT0: begin z.state^.mode := BAD; z.msg := 'need dictionary'; z.state^.sub.marker := 0; { can try inflateSync } inflate := Z_STREAM_ERROR; exit; end; BAD: begin inflate := Z_DATA_ERROR; exit; end; else begin inflate := Z_STREAM_ERROR; exit; end; end; {$ifdef NEED_DUMMY_result} result := Z_STREAM_ERROR; { Some dumb compilers complain without this } {$endif} end; function inflateSetDictionary(var z : z_stream; dictionary : pBytef; {const array of byte} dictLength : uInt) : int; var length : uInt; begin length := dictLength; if (z.state = Z_NULL) or (z.state^.mode <> DICT0) then begin inflateSetDictionary := Z_STREAM_ERROR; exit; end; if (adler32(Long(1), dictionary, dictLength) <> z.adler) then begin inflateSetDictionary := Z_DATA_ERROR; exit; end; z.adler := Long(1); if (length >= (uInt(1) shl z.state^.wbits)) then begin length := (1 shl z.state^.wbits)-1; Inc( dictionary, dictLength - length); end; inflate_set_dictionary(z.state^.blocks^, dictionary^, length); z.state^.mode := BLOCKS; inflateSetDictionary := Z_OK; end; function inflateSync(var z : z_stream) : int; const mark : packed array[0..3] of byte = (0, 0, $ff, $ff); var n : uInt; { number of bytes to look at } p : pBytef; { pointer to bytes } m : uInt; { number of marker bytes found in a row } r, w : uLong; { temporaries to save total_in and total_out } begin { set up } if (z.state = Z_NULL) then begin inflateSync := Z_STREAM_ERROR; exit; end; if (z.state^.mode <> BAD) then begin z.state^.mode := BAD; z.state^.sub.marker := 0; end; n := z.avail_in; if (n = 0) then begin inflateSync := Z_BUF_ERROR; exit; end; p := z.next_in; m := z.state^.sub.marker; { search } while (n <> 0) and (m < 4) do begin if (p^ = mark[m]) then Inc(m) else if (p^ <> 0) then m := 0 else m := 4 - m; Inc(p); Dec(n); end; { restore } Inc(z.total_in, ptr2int(p) - ptr2int(z.next_in)); z.next_in := p; z.avail_in := n; z.state^.sub.marker := m; { return no joy or set up to restart on a new block } if (m <> 4) then begin inflateSync := Z_DATA_ERROR; exit; end; r := z.total_in; w := z.total_out; inflateReset(z); z.total_in := r; z.total_out := w; z.state^.mode := BLOCKS; inflateSync := Z_OK; end; { returns true if inflate is currently at the end of a block generated by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH but removes the length bytes of the resulting empty stored block. When decompressing, PPP checks that at the end of input packet, inflate is waiting for these length bytes. } function inflateSyncPoint(var z : z_stream) : int; begin if (z.state = Z_NULL) or (z.state^.blocks = Z_NULL) then begin inflateSyncPoint := Z_STREAM_ERROR; exit; end; inflateSyncPoint := inflate_blocks_sync_point(z.state^.blocks^); end; end. ================================================ FILE: lib/Imaging/ZLib/imzutil.pas ================================================ Unit imzutil; { Copyright (C) 1998 by Jacques Nomssi Nzali For conditions of distribution and use, see copyright notice in readme.txt } interface {$I imzconf.inc} { Type declarations } type {Byte = usigned char; 8 bits} Bytef = byte; charf = byte; int = longint; intf = int; uInt = cardinal; { 16 bits or more } uIntf = uInt; Long = longint; uLong = Cardinal; uLongf = uLong; voidp = pointer; voidpf = voidp; pBytef = ^Bytef; pIntf = ^intf; puIntf = ^uIntf; puLong = ^uLongf; ptr2int = uInt; { a pointer to integer casting is used to do pointer arithmetic. ptr2int must be an integer type and sizeof(ptr2int) must be less than sizeof(pointer) - Nomssi } type zByteArray = array[0..(MaxInt div SizeOf(Bytef))-1] of Bytef; pzByteArray = ^zByteArray; type zIntfArray = array[0..(MaxInt div SizeOf(Intf))-1] of Intf; pzIntfArray = ^zIntfArray; type zuIntArray = array[0..(MaxInt div SizeOf(uInt))-1] of uInt; PuIntArray = ^zuIntArray; { Type declarations - only for deflate } type uch = Byte; uchf = uch; { FAR } ush = Word; ushf = ush; ulg = LongInt; unsigned = uInt; pcharf = ^charf; puchf = ^uchf; pushf = ^ushf; type zuchfArray = zByteArray; puchfArray = ^zuchfArray; type zushfArray = array[0..(MaxInt div SizeOf(ushf))-1] of ushf; pushfArray = ^zushfArray; procedure zmemcpy(destp : pBytef; sourcep : pBytef; len : uInt); function zmemcmp(s1p, s2p : pBytef; len : uInt) : int; procedure zmemzero(destp : pBytef; len : uInt); procedure zcfree(opaque : voidpf; ptr : voidpf); function zcalloc (opaque : voidpf; items : uInt; size : uInt) : voidpf; implementation procedure zmemcpy(destp : pBytef; sourcep : pBytef; len : uInt); begin Move(sourcep^, destp^, len); end; function zmemcmp(s1p, s2p : pBytef; len : uInt) : int; var j : uInt; source, dest : pBytef; begin source := s1p; dest := s2p; for j := 0 to pred(len) do begin if (source^ <> dest^) then begin zmemcmp := 2*Ord(source^ > dest^)-1; exit; end; Inc(source); Inc(dest); end; zmemcmp := 0; end; procedure zmemzero(destp : pBytef; len : uInt); begin FillChar(destp^, len, 0); end; procedure zcfree(opaque : voidpf; ptr : voidpf); {$ifdef Delphi16} var Handle : THandle; {$endif} {$IFDEF FPC} var memsize : uint; {$ENDIF} begin (* {$IFDEF DPMI} {h :=} GlobalFreePtr(ptr); {$ELSE} {$IFDEF CALL_DOS} dosFree(ptr); {$ELSE} {$ifdef HugeMem} FreeMemHuge(ptr); {$else} {$ifdef Delphi16} Handle := GlobalHandle(LH(ptr).H); { HiWord(LongInt(ptr)) } GlobalUnLock(Handle); GlobalFree(Handle); {$else} {$IFDEF FPC} Dec(puIntf(ptr)); memsize := puIntf(ptr)^; FreeMem(ptr, memsize+SizeOf(uInt)); {$ELSE} FreeMem(ptr); { Delphi 2,3,4 } {$ENDIF} {$endif} {$endif} {$ENDIF} {$ENDIF} *) FreeMem(ptr); end; function zcalloc (opaque : voidpf; items : uInt; size : uInt) : voidpf; var p : voidpf; memsize : uLong; {$ifdef Delphi16} handle : THandle; {$endif} begin memsize := uLong(items) * size; (* { $IFDEF DPMI} p := GlobalAllocPtr(gmem_moveable, memsize); { $ELSE} { $IFDEF CALLDOS} p := dosAlloc(memsize); { $ELSE} {$ifdef HugeMem} GetMemHuge(p, memsize); { $else} { $ifdef Delphi16} Handle := GlobalAlloc(HeapAllocFlags, memsize); p := GlobalLock(Handle); { $else} { $IFDEF FPC} GetMem(p, memsize+SizeOf(uInt)); puIntf(p)^:= memsize; Inc(puIntf(p)); { $ELSE} GetMem(p, memsize); { Delphi: p := AllocMem(memsize); } { $ENDIF} { $endif} { $endif} { $ENDIF} { $ENDIF} *) GetMem(p, memsize); zcalloc := p; end; end. ================================================ FILE: lib/Imaging/ZLib/readme.txt ================================================ _____________________________________________________________________________ PASZLIB 1.0 May 11th, 1998 Based on the zlib 1.1.2, a general purpose data compression library. Copyright (C) 1998,1999,2000 by NOMSSI NZALI Jacques H. C. [kn&n DES] See "Legal issues" for conditions of distribution and use. _____________________________________________________________________________ Introduction ============ The 'zlib' compression library provides in-memory compression and decompression functions, including integrity checks of the uncompressed data. This version of the library supports only one compression method (deflation) but other algorithms will be added later and will have the same stream interface. Compression can be done in a single step if the buffers are large enough (for example if an input file is mmap'ed), or can be done by repeated calls of the compression function. In the latter case, the application must provide more input and/or consume the output (providing more output space) before each call. The default memory requirements for deflate are 256K plus a few kilobytes for small objects. The default memory requirements for inflate are 32K plus a few kilobytes for small objects. Change Log ========== March 24th 2000 - minizip code by Gilles Vollant ported to Pascal. z_stream.msg defined as string[255] to avoid problems with Delphi 2+ dynamic string handling. changes to silence Delphi 5 compiler warning. If you have Delphi 5, defines Delphi5 in zconf.inc May 7th 1999 - Some changes for FPC deflateCopy() has new parameters trees.pas - record constant definition June 17th 1998 - Applied official 1.1.2 patch. Memcheck turned off by default. zutil.pas patch for Delphi 1 memory allocation corrected. dzlib.txt file added. compress2() is now exported June 25th 1998 - fixed a conversion bug: in inftrees.pas, ZFREE(z, v) was missing in line 574; File list ========= Here is a road map to the files in the Paszlib distribution. readme.txt Introduction, Documentation dzlib.txt Changes to Delphi sources for Paszlib stream classes include file zconf.inc Configuration declarations. Pascal source code files: adler.pas compute the Adler-32 checksum of a data stream crc.pas compute the CRC-32 of a data stream gzio.pas IO on .gz files infblock.pas interpret and process block types to last block infcodes.pas process literals and length/distance pairs inffast.pas process literals and length/distance pairs fast inftrees.pas generate Huffman trees for efficient decoding infutil.pas types and macros common to blocks and codes strutils.pas string utilities trees.pas output deflated data using Huffman coding zcompres.pas compress a memory buffer zdeflate.pas compress data using the deflation algorithm zinflate.pas zlib interface to inflate modules zlib.pas zlib data structures. read the comments there! zuncompr.pas decompress a memory buffer zutil.pas minizip/ziputils.pas data structure and IO on .zip file minizip/unzip.pas minizip/zip.pas Test applications example.pas usage example of the zlib compression library minigzip.pas simulate gzip using the zlib compression library minizip/miniunz.pas simulates unzip using the zlib compression library minizip/minizip.pas simulates zip using the zlib compression library Legal issues ============ Copyright (C) 1998,1999,2000 by Jacques Nomssi Nzali This software is provided 'as-is', without any express or implied warranty. In no event will the author be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Archive Locations: ================== Check the Paszlib home page with links http://www.tu-chemnitz.de/~nomssi/paszlib.html The data format used by the zlib library is described by RFCs (Request for Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). These documents are also available in other formats from ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html. ____________________________________________________________________________ Jacques Nomssi Nzali March 24th, 2000 ================================================ FILE: lib/abbrevia/MPL-1_1.txt ================================================ MOZILLA PUBLIC LICENSE Version 1.1 --------------- 1. Definitions. 1.0.1. "Commercial Use" means distribution or otherwise making the Covered Code available to a third party. 1.1. "Contributor" means each entity that creates or contributes to the creation of Modifications. 1.2. "Contributor Version" means the combination of the Original Code, prior Modifications used by a Contributor, and the Modifications made by that particular Contributor. 1.3. "Covered Code" means the Original Code or Modifications or the combination of the Original Code and Modifications, in each case including portions thereof. 1.4. "Electronic Distribution Mechanism" means a mechanism generally accepted in the software development community for the electronic transfer of data. 1.5. "Executable" means Covered Code in any form other than Source Code. 1.6. "Initial Developer" means the individual or entity identified as the Initial Developer in the Source Code notice required by Exhibit A. 1.7. "Larger Work" means a work which combines Covered Code or portions thereof with code not governed by the terms of this License. 1.8. "License" means this document. 1.8.1. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently acquired, any and all of the rights conveyed herein. 1.9. "Modifications" means any addition to or deletion from the substance or structure of either the Original Code or any previous Modifications. When Covered Code is released as a series of files, a Modification is: A. Any addition to or deletion from the contents of a file containing Original Code or previous Modifications. B. Any new file that contains any part of the Original Code or previous Modifications. 1.10. "Original Code" means Source Code of computer software code which is described in the Source Code notice required by Exhibit A as Original Code, and which, at the time of its release under this License is not already Covered Code governed by this License. 1.10.1. "Patent Claims" means any patent claim(s), now owned or hereafter acquired, including without limitation, method, process, and apparatus claims, in any patent Licensable by grantor. 1.11. "Source Code" means the preferred form of the Covered Code for making modifications to it, including all modules it contains, plus any associated interface definition files, scripts used to control compilation and installation of an Executable, or source code differential comparisons against either the Original Code or another well known, available Covered Code of the Contributor's choice. The Source Code can be in a compressed or archival form, provided the appropriate decompression or de-archiving software is widely available for no charge. 1.12. "You" (or "Your") means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License or a future version of this License issued under Section 6.1. For legal entities, "You" includes any entity which controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. 2. Source Code License. 2.1. The Initial Developer Grant. The Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license, subject to third party intellectual property claims: (a) under intellectual property rights (other than patent or trademark) Licensable by Initial Developer to use, reproduce, modify, display, perform, sublicense and distribute the Original Code (or portions thereof) with or without Modifications, and/or as part of a Larger Work; and (b) under Patents Claims infringed by the making, using or selling of Original Code, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Code (or portions thereof). (c) the licenses granted in this Section 2.1(a) and (b) are effective on the date Initial Developer first distributes Original Code under the terms of this License. (d) Notwithstanding Section 2.1(b) above, no patent license is granted: 1) for code that You delete from the Original Code; 2) separate from the Original Code; or 3) for infringements caused by: i) the modification of the Original Code or ii) the combination of the Original Code with other software or devices. 2.2. Contributor Grant. Subject to third party intellectual property claims, each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license (a) under intellectual property rights (other than patent or trademark) Licensable by Contributor, to use, reproduce, modify, display, perform, sublicense and distribute the Modifications created by such Contributor (or portions thereof) either on an unmodified basis, with other Modifications, as Covered Code and/or as part of a Larger Work; and (b) under Patent Claims infringed by the making, using, or selling of Modifications made by that Contributor either alone and/or in combination with its Contributor Version (or portions of such combination), to make, use, sell, offer for sale, have made, and/or otherwise dispose of: 1) Modifications made by that Contributor (or portions thereof); and 2) the combination of Modifications made by that Contributor with its Contributor Version (or portions of such combination). (c) the licenses granted in Sections 2.2(a) and 2.2(b) are effective on the date Contributor first makes Commercial Use of the Covered Code. (d) Notwithstanding Section 2.2(b) above, no patent license is granted: 1) for any code that Contributor has deleted from the Contributor Version; 2) separate from the Contributor Version; 3) for infringements caused by: i) third party modifications of Contributor Version or ii) the combination of Modifications made by that Contributor with other software (except as part of the Contributor Version) or other devices; or 4) under Patent Claims infringed by Covered Code in the absence of Modifications made by that Contributor. 3. Distribution Obligations. 3.1. Application of License. The Modifications which You create or to which You contribute are governed by the terms of this License, including without limitation Section 2.2. The Source Code version of Covered Code may be distributed only under the terms of this License or a future version of this License released under Section 6.1, and You must include a copy of this License with every copy of the Source Code You distribute. You may not offer or impose any terms on any Source Code version that alters or restricts the applicable version of this License or the recipients' rights hereunder. However, You may include an additional document offering the additional rights described in Section 3.5. 3.2. Availability of Source Code. Any Modification which You create or to which You contribute must be made available in Source Code form under the terms of this License either on the same media as an Executable version or via an accepted Electronic Distribution Mechanism to anyone to whom you made an Executable version available; and if made available via Electronic Distribution Mechanism, must remain available for at least twelve (12) months after the date it initially became available, or at least six (6) months after a subsequent version of that particular Modification has been made available to such recipients. You are responsible for ensuring that the Source Code version remains available even if the Electronic Distribution Mechanism is maintained by a third party. 3.3. Description of Modifications. You must cause all Covered Code to which You contribute to contain a file documenting the changes You made to create that Covered Code and the date of any change. You must include a prominent statement that the Modification is derived, directly or indirectly, from Original Code provided by the Initial Developer and including the name of the Initial Developer in (a) the Source Code, and (b) in any notice in an Executable version or related documentation in which You describe the origin or ownership of the Covered Code. 3.4. Intellectual Property Matters (a) Third Party Claims. If Contributor has knowledge that a license under a third party's intellectual property rights is required to exercise the rights granted by such Contributor under Sections 2.1 or 2.2, Contributor must include a text file with the Source Code distribution titled "LEGAL" which describes the claim and the party making the claim in sufficient detail that a recipient will know whom to contact. If Contributor obtains such knowledge after the Modification is made available as described in Section 3.2, Contributor shall promptly modify the LEGAL file in all copies Contributor makes available thereafter and shall take other steps (such as notifying appropriate mailing lists or newsgroups) reasonably calculated to inform those who received the Covered Code that new knowledge has been obtained. (b) Contributor APIs. If Contributor's Modifications include an application programming interface and Contributor has knowledge of patent licenses which are reasonably necessary to implement that API, Contributor must also include this information in the LEGAL file. (c) Representations. Contributor represents that, except as disclosed pursuant to Section 3.4(a) above, Contributor believes that Contributor's Modifications are Contributor's original creation(s) and/or Contributor has sufficient rights to grant the rights conveyed by this License. 3.5. Required Notices. You must duplicate the notice in Exhibit A in each file of the Source Code. If it is not possible to put such notice in a particular Source Code file due to its structure, then You must include such notice in a location (such as a relevant directory) where a user would be likely to look for such a notice. If You created one or more Modification(s) You may add your name as a Contributor to the notice described in Exhibit A. You must also duplicate this License in any documentation for the Source Code where You describe recipients' rights or ownership rights relating to Covered Code. You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Code. However, You may do so only on Your own behalf, and not on behalf of the Initial Developer or any Contributor. You must make it absolutely clear than any such warranty, support, indemnity or liability obligation is offered by You alone, and You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of warranty, support, indemnity or liability terms You offer. 3.6. Distribution of Executable Versions. You may distribute Covered Code in Executable form only if the requirements of Section 3.1-3.5 have been met for that Covered Code, and if You include a notice stating that the Source Code version of the Covered Code is available under the terms of this License, including a description of how and where You have fulfilled the obligations of Section 3.2. The notice must be conspicuously included in any notice in an Executable version, related documentation or collateral in which You describe recipients' rights relating to the Covered Code. You may distribute the Executable version of Covered Code or ownership rights under a license of Your choice, which may contain terms different from this License, provided that You are in compliance with the terms of this License and that the license for the Executable version does not attempt to limit or alter the recipient's rights in the Source Code version from the rights set forth in this License. If You distribute the Executable version under a different license You must make it absolutely clear that any terms which differ from this License are offered by You alone, not by the Initial Developer or any Contributor. You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of any such terms You offer. 3.7. Larger Works. You may create a Larger Work by combining Covered Code with other code not governed by the terms of this License and distribute the Larger Work as a single product. In such a case, You must make sure the requirements of this License are fulfilled for the Covered Code. 4. Inability to Comply Due to Statute or Regulation. If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Code due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be included in the LEGAL file described in Section 3.4 and must be included with all distributions of the Source Code. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. 5. Application of this License. This License applies to code to which the Initial Developer has attached the notice in Exhibit A and to related Covered Code. 6. Versions of the License. 6.1. New Versions. Netscape Communications Corporation ("Netscape") may publish revised and/or new versions of the License from time to time. Each version will be given a distinguishing version number. 6.2. Effect of New Versions. Once Covered Code has been published under a particular version of the License, You may always continue to use it under the terms of that version. You may also choose to use such Covered Code under the terms of any subsequent version of the License published by Netscape. No one other than Netscape has the right to modify the terms applicable to Covered Code created under this License. 6.3. Derivative Works. If You create or use a modified version of this License (which you may only do in order to apply it to code which is not already Covered Code governed by this License), You must (a) rename Your license so that the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape", "MPL", "NPL" or any confusingly similar phrase do not appear in your license (except to note that your license differs from this License) and (b) otherwise make it clear that Your version of the license contains terms which differ from the Mozilla Public License and Netscape Public License. (Filling in the name of the Initial Developer, Original Code or Contributor in the notice described in Exhibit A shall not of themselves be deemed to be modifications of this License.) 7. DISCLAIMER OF WARRANTY. COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. 8. TERMINATION. 8.1. This License and the rights granted hereunder will terminate automatically if You fail to comply with terms herein and fail to cure such breach within 30 days of becoming aware of the breach. All sublicenses to the Covered Code which are properly granted shall survive any termination of this License. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive. 8.2. If You initiate litigation by asserting a patent infringement claim (excluding declatory judgment actions) against Initial Developer or a Contributor (the Initial Developer or Contributor against whom You file such action is referred to as "Participant") alleging that: (a) such Participant's Contributor Version directly or indirectly infringes any patent, then any and all rights granted by such Participant to You under Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice from Participant terminate prospectively, unless if within 60 days after receipt of notice You either: (i) agree in writing to pay Participant a mutually agreeable reasonable royalty for Your past and future use of Modifications made by such Participant, or (ii) withdraw Your litigation claim with respect to the Contributor Version against such Participant. If within 60 days of notice, a reasonable royalty and payment arrangement are not mutually agreed upon in writing by the parties or the litigation claim is not withdrawn, the rights granted by Participant to You under Sections 2.1 and/or 2.2 automatically terminate at the expiration of the 60 day notice period specified above. (b) any software, hardware, or device, other than such Participant's Contributor Version, directly or indirectly infringes any patent, then any rights granted to You by such Participant under Sections 2.1(b) and 2.2(b) are revoked effective as of the date You first made, used, sold, distributed, or had made, Modifications made by that Participant. 8.3. If You assert a patent infringement claim against Participant alleging that such Participant's Contributor Version directly or indirectly infringes any patent where such claim is resolved (such as by license or settlement) prior to the initiation of patent infringement litigation, then the reasonable value of the licenses granted by such Participant under Sections 2.1 or 2.2 shall be taken into account in determining the amount or value of any payment or license. 8.4. In the event of termination under Sections 8.1 or 8.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or any distributor hereunder prior to termination shall survive termination. 9. LIMITATION OF LIABILITY. UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. 10. U.S. GOVERNMENT END USERS. The Covered Code is a "commercial item," as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer software" and "commercial computer software documentation," as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government End Users acquire Covered Code with only those rights set forth herein. 11. MISCELLANEOUS. This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. This License shall be governed by California law provisions (except to the extent applicable law, if any, provides otherwise), excluding its conflict-of-law provisions. With respect to disputes in which at least one party is a citizen of, or an entity chartered or registered to do business in the United States of America, any litigation relating to this License shall be subject to the jurisdiction of the Federal Courts of the Northern District of California, with venue lying in Santa Clara County, California, with the losing party responsible for costs, including without limitation, court costs and reasonable attorneys' fees and expenses. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not apply to this License. 12. RESPONSIBILITY FOR CLAIMS. As between Initial Developer and the Contributors, each party is responsible for claims and damages arising, directly or indirectly, out of its utilization of rights under this License and You agree to work with Initial Developer and Contributors to distribute such responsibility on an equitable basis. Nothing herein is intended or shall be deemed to constitute any admission of liability. 13. MULTIPLE-LICENSED CODE. Initial Developer may designate portions of the Covered Code as "Multiple-Licensed". "Multiple-Licensed" means that the Initial Developer permits you to utilize portions of the Covered Code under Your choice of the NPL or the alternative licenses, if any, specified by the Initial Developer in the file described in Exhibit A. EXHIBIT A -Mozilla Public License. ``The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. The Original Code is ______________________________________. The Initial Developer of the Original Code is ________________________. Portions created by ______________________ are Copyright (C) ______ _______________________. All Rights Reserved. Contributor(s): ______________________________________. Alternatively, the contents of this file may be used under the terms of the _____ license (the "[___] License"), in which case the provisions of [______] License are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of the [____] License and not to allow others to use your version of this file under the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the [___] License. If you do not delete the provisions above, a recipient may use your version of this file under either the MPL or the [___] License." [NOTE: The text of this Exhibit A may differ slightly from the text of the notices in the Source Code files of the Original Code. You should use the text of this Exhibit A rather than the text found in the Original Code Source Code for Your Modifications.] ================================================ FILE: lib/abbrevia/Readme.html ================================================ Abbrevia v5.0

Abbrevia

Version 5.0
December 6, 2011
Home Page


Table of contents


Introduction

Abbrevia is a compression toolkit for Embarcadero Delphi, C++ Builder, and Kylix, and FreePascal. It supports PKZip, Microsoft CAB, tar, gzip, bzip2 and zlib compression formats, and the creation of self-extracting executables. It includes several visual components that simplify displaying zip files.

Abbrevia 5.0 adds a number of new features and support for more platforms:

  • RAD Studio XE2 support, including both 64-bit Windows and OS X
  • FreePascal support on Windows, OS X, and Linux
  • TAbTreeView and TAbListView VCL controls that provide an Explorer/WinZip-like interface
  • ZIP64 support, for archives larger than 2GB
  • Improved split/spanned zip support
  • Expanded LZMA support
  • Unicode filenames in tar and gzip archives

This is a source-only release. It includes design-time and run-time packages for Delphi 6 through Delphi XE2, C++Builder 2009 through XE2, and Kylix 3. FreePascal is supported, but runtime/design time packages are not included. The LZMA, PPMd, and WavPack algorithms are only supported on Delphi/C++Builder for Windows (32 and 64-bit).


Packages

Abbrevia includes the following packages:

  • Abbrevia.bpl: Runtime non-visual components. TAbZipBrowse, TAbZipKit, TAbMakeCab, etc.
  • AbbreviaVCL.bpl: Runtime visual components. TAbTreeView, TAbListView, TAbProgressBar.
  • AbbreviaVCLDesign.bpl: Designtime support.
  • AbbreviaCLX.bpl, AbbreviaCLXDesign.bpl (Delphi 6/7): CLX visual components.

$LIBSUFFIX is used, so each .bpl/.bpi will have a version number after it corresponding to the compiler version (e.g. 160 for Delphi XE2).

The Kylix 3 AbbreviaCLX package includes all of the non-visual runtime units, and the Abbrevia package is not included separately.


Installation

To install TurboPower Abbrevia into your IDE:

  1. Unzip the release files into a directory (e.g., d:\abbrevia).
  2. Start Delphi or C++Builder.
  3. Add the source subdirectory (e.g. d:\abbrevia\source) to the Delphi Library path. When using XE2 or later, add it to all platforms.
  4. If using C++Builder, add the source subdirectory to C++Builder's Include and Library paths.
  5. Open the project group in the packages directory that corresponds to the IDE being used (e.g. "Delphi XE2.groupproj").
  6. Start at the top of the project group and compile each package in turn. If using C++Builder, install each one after compiling.
  7. Select the "AbbreviaVCLDesign" package and install it. The IDE should notify you that the components have been installed. If you are using Delphi 7 you can install "AbbreviaCLXDesign" as well to get CLX designtime support.
  8. Make sure the PATH environmental variable contains the directory in which the compiled packages (i.e. BPL or DPL files) were placed.

Support and feedback

Support forums are available on the SourceForge project site.

Bug reports can be entered in the bug tracker. If possible please include a small test case that reproduces the issue. Sample files can be attached to the bug report, and confidential data can be emailed to the project administrator.

If you have something you would like to see in the product feel free to add a feature request.


Development sources

The current source code is available in the Subversion repository. The code here may not be as stable or tested as the official releases, but may include bug fixes or new features not yet included in the downloadable releases.

The repository also includes DUnit tests, the source code to the third-party libraries, and the Help source code.


Getting involved

If you want to help make Abbrevia better, there are several ways to get involved. We welcome help with features and bug fixes. Just look in the issue tracker to see what's needed. We're also looking for help for:

  • C++Builder maintainer
  • FreePascal maintainer
  • Webmaster
  • Documentation
  • Examples

License

Abbrevia is licensed under the Mozilla Public License, version 1.1. It can be used in commercial and closed-source applications provided any changes to Abbrevia units are made available electronically.

The WavPack library used for zipx decompression has its own license, included as "WavPack License.txt". Redistribution requires a copyright notice in your documentation or elsewhere in your distribution. WavPack support can be removed by disabling the UnzipZipxSupport or UnzipWavPackSupport conditional define in AbDefine.inc.


Changes from 4.0

These are the most significant features, fixes and changes made since v4.0. Information on earlier versions is available in the full changelog.

Features

  • Added support for Delphi/C++Builder XE2, including the 64-bit Windows and OS X platforms.
  • Added support for FreePascal 2.4/2.6 on Windows, OS X, and Linux.
  • Added TAbTreeView and TAbListView VCL controls that provide an Explorer/WinZip-like interface, and ComCtrlsDemo Delphi example to demonstrate their usage.
  • Added ZIP64 support (reading/writing zip archives larger than 2GB, containing files larger than 2GB, or containing more than 65K files).
  • Significantly improved split/spanned zip support.
  • Added LZMA buffer-to-buffer compression/decompression (LzmaEncodeBuffer and LzmaDecodeBuffer) and compression/decompression stream descendants (TAbLZMACompressionStream and TAbLZMADecompressionStream). Thanks to Pierre le Riche.
  • Added support for tar and gzip archives containing filenames encoded in the system ANSI and OEM codepage and UTF-8. New archives are written using UTF-8.
  • Added icon/text to RAD Studio's splash screen and about box. Thanks to Lance Rasmussen.
  • Added VCL TAbProgressBar control that can replace TAbMeter.
  • Added 64-bit COM dll and support for per-user registration.

API Changes

  • Renamed LzEncode/LzDecode to LzmaEncodeStream/LzmaDecodeStream.
  • Renamed LzmaDecode to LzmaDecodeStream.
  • Various changes due to split/spanned zip changes (see below).

Bug Fixes

  • Fixed support for opening paths with a "\\?\" prefix.
  • Fixed buffer overflow in AbUtils.pas.
  • Fixed freshening/replacing items using absolute paths.
  • Fixed CAB files created with Delphi 2009 and later incorrectly including the "has next volume" flag.
  • Fixed Delphi 6 support. Thanks to Peter Luijer.
  • Fixed AbFindFiles so it finds system and hidden folders if the SearchAttr parameter includes them [3372355].
  • Fixed hang when trying to extract files that cross CAB boundaries when the next cab is not available [3370538].
  • Fixed extracting CAB archives so OnProcessItemFailure isn't called after a successful extraction.
  • Fixed LZMA support for streams larger than 2GB.
  • Fixed AbGetDriveFreeSpace buffer overflow and fixed support for free space larger than 2GB.
  • Fixed support for modifying SFX zips with non-native stubs (Linux on Windows and vice versa).
  • Fixed TAbBitBucketStream so it doesn't fault on writes larger than the buffer size, and supports sizes over 2GB.
  • Zip local file headers are now preserved when copying unmodified files to a new archive.
  • Local file headers are no longer copies of the central directory headers, since many of the defined extra data fields have different values in the two locations.
  • Fixed IZipKit (COM) support for enumerations (for each).

Split/Spanned Zip Changes

  • Bug Fixes
    • Added support for reading/writing unequally sized spans.
    • Split/spanned zips are now written to the final location as they're compressed, rather than writing everything to a virtual memory stream first.
    • Fixed writing headers that can't be spanned so they trigger a new span if necessary.
  • API Changes
    • Converting from an unspanned archive to a spanned one is no longer supported.
    • OnRequestImage's span numbers are now 1-based instead of 0-based to match OnRequestNthDisk.
    • OnArchiveSaveProgress is now called at the same time as OnArchiveProgress, since there isn't a lengthy copy after a spanned archive is written.
    • TAbSpanStream has been replaced by TAbSpanReadStream and TAbSpanWriteStream.
================================================ FILE: lib/abbrevia/WavPack License.txt ================================================ Copyright (c) 1998 - 2009 Conifer Software All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Conifer Software nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ================================================ FILE: lib/abbrevia/examples/Delphi/Abbrexam.dpr ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: ABBREXAM.DPR *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} program Abbrexam; {$R *.res} uses Forms, udemodlg in 'udemodlg.pas' {DemoDlg}, uexample in 'Uexample.pas' {Form1}; begin Application.CreateForm(TForm1, Form1); Application.CreateForm(TForm1, Form1); Application.CreateForm(TDemoDlg, DemoDlg); Application.Run; end. ================================================ FILE: lib/abbrevia/examples/Delphi/BaseDlgu.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) unit Basedlgu; interface uses WinTypes, WinProcs, Classes, Graphics, Forms, Controls, Buttons, StdCtrls, FileCtrl, ExtCtrls; type TBaseDlg = class(TForm) Bevel1: TBevel; DirectoryListBox1: TDirectoryListBox; CancelBtn: TButton; OkBtn: TButton; procedure DirectoryListBox1Change(Sender: TObject); procedure FormShow(Sender: TObject); private { Private declarations } public BaseDirectory : string; end; var BaseDlg: TBaseDlg; implementation {$R *.DFM} procedure TBaseDlg.DirectoryListBox1Change(Sender: TObject); begin BaseDirectory := DirectoryListBox1.Directory; end; procedure TBaseDlg.FormShow(Sender: TObject); begin DirectoryListBox1.Directory := BaseDirectory; end; end. ================================================ FILE: lib/abbrevia/examples/Delphi/CabExt.dpr ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: UNZIP.DPR *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} program CabExt; uses Forms, CabExt1 in 'CabExt1.pas' {Form1}; begin Application.CreateForm(TForm1, Form1); Application.CreateForm(TForm1, Form1); Application.Run; end. ================================================ FILE: lib/abbrevia/examples/Delphi/CabExt1.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: EXTCAB.PAS *} {* Copyright (c) TurboPower Software Co 1997 *} {* All rights reserved. *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} unit CabExt1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, AbArcTyp, AbCBrows, ComCtrls, AbCabExt, AbCabTyp, AbBase, AbBrowse, AbMeter, AbUtils; type TForm1 = class(TForm) Button1: TButton; OpenDialog1: TOpenDialog; Memo1: TMemo; Label1: TLabel; Button2: TButton; AbMeter1: TAbMeter; AbCabExtractor1: TAbCabExtractor; procedure Button1Click(Sender: TObject); procedure AbCabExtractor1ConfirmProcessItem(Sender: TObject; Item: TAbArchiveItem; ProcessType: TAbProcessType; var Confirm: Boolean); procedure Button2Click(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} const MainCaption = 'Cabinet Extractor'; var AbortFlag : Boolean; procedure TForm1.Button1Click(Sender: TObject); begin if OpenDialog1.Execute then begin with AbCabExtractor1 do begin FileName := OpenDialog1.FileName; BaseDirectory := ExtractFilePath(FileName); Cursor := crHourglass; try ExtractFiles('*.*'); except {swallow exception if aborted} end; Cursor := crDefault; end; end; Caption := MainCaption; AbortFlag := False; end; procedure TForm1.AbCabExtractor1ConfirmProcessItem(Sender: TObject; Item: TAbArchiveItem; ProcessType: TAbProcessType; var Confirm: Boolean); begin Caption := 'Extracting ' + Item.Filename; Confirm := not AbortFlag; end; procedure TForm1.Button2Click(Sender: TObject); begin AbortFlag := True; end; procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin AbCabExtractor1.FileName := ''; end; end. ================================================ FILE: lib/abbrevia/examples/Delphi/CabFind.dpr ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: FINDER.DPR *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} program CabFind; uses Forms, CabFind1 in 'CabFind1.pas' {Form1}; begin Application.CreateForm(TForm1, Form1); Application.Run; end. ================================================ FILE: lib/abbrevia/examples/Delphi/CabFind1.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: CABFIND1.PAS *} {* Copyright (c) TurboPower Software Co 1997 *} {* All rights reserved. *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} unit CabFind1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, FileCtrl, Buttons, ExtCtrls, AbArcTyp, AbBrowse, AbCBrows, AbBase; type TForm1 = class(TForm) Edit1: TEdit; Label1: TLabel; Memo1: TMemo; DriveComboBox1: TDriveComboBox; DirectoryListBox1: TDirectoryListBox; FileListBox1: TFileListBox; Memo2: TMemo; Label2: TLabel; AbCabBrowser1: TAbCabBrowser; Button1: TButton; Button2: TButton; procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure Edit1Change(Sender: TObject); procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); private { Private declarations } Aborted: Boolean; public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin Aborted := True; end; procedure TForm1.Edit1Change(Sender: TObject); begin Button1.Enabled := Length( Edit1.Text ) > 0; end; procedure TForm1.Button1Click(Sender: TObject); var i : Integer; CurFile : string; begin Button1.Enabled := False; Memo1.Clear; try Button2.Enabled := True; Aborted := False; {look in the file list box for the file} for i := 0 to pred( FileListBox1.Items.Count ) do begin Application.ProcessMessages; if Aborted then break; if CompareText( Edit1.Text, FileListBox1.Items[i] ) = 0 then begin Memo1.Lines.Add( 'Found in ' + FileListBox1.Directory ); break; end; {now add search of zip and self extracting files} CurFile := UpperCase( FileListBox1.Items[i] ); if ( Pos( '.CAB', CurFile ) > 0 ) then begin try AbCabBrowser1.FileName := FileListBox1.Items[i]; if AbCabBrowser1.FindFile(Edit1.Text) >= 0 then Memo1.Lines.Add( 'Found in ' + FileListBox1.Items[i] ); except end; end; end; finally Memo1.Lines.Add( 'Done!' ); Edit1.Enabled := True; Button1.Enabled := True; Button2.Enabled := False; end; end; procedure TForm1.Button2Click(Sender: TObject); begin Aborted := True; end; end. ================================================ FILE: lib/abbrevia/examples/Delphi/CabView.dpr ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) program CabView; uses Forms, CabView1 in 'CabView1.PAS' {Form1}; begin Application.Initialize; Application.CreateForm(TForm1, Form1); Application.Run; end. ================================================ FILE: lib/abbrevia/examples/Delphi/CabView1.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: CABVIEW1.PAS *} {* Copyright (c) TurboPower Software Co 1997 *} {* All rights reserved. *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} unit CabView1; interface uses SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls, Forms, Dialogs, Grids, StdCtrls, ExtCtrls, Menus, FileCtrl, AbArcTyp, AbCabTyp, AbMeter, AbDlgDir, AbView, AbCView, AbCBrows, AbBrowse, AbCabMak, AbCabKit, AbBase, AbUtils; type TForm1 = class(TForm) OpenDialog1: TOpenDialog; Panel1: TPanel; FontDialog1: TFontDialog; MainMenu1: TMainMenu; File1: TMenuItem; Open1: TMenuItem; Close1: TMenuItem; N1: TMenuItem; Print1: TMenuItem; Exit1: TMenuItem; ColorDialog1: TColorDialog; CabView1: TMenuItem; Attributes1: TMenuItem; Itemname1: TMenuItem; Packed1: TMenuItem; Method1: TMenuItem; Ratio1: TMenuItem; CRC1: TMenuItem; Fileattributes1: TMenuItem; Filetype1: TMenuItem; Encryption1: TMenuItem; Timestamp1: TMenuItem; Filesize1: TMenuItem; Versionmade1: TMenuItem; Versionneeded1: TMenuItem; Path1: TMenuItem; Display1: TMenuItem; Columnlines1: TMenuItem; Columnmoving1: TMenuItem; Columnresizing1: TMenuItem; MultiSelect1: TMenuItem; Rowlines1: TMenuItem; Thumbtracking1: TMenuItem; Trackactiverow1: TMenuItem; Sort1: TMenuItem; Itemname2: TMenuItem; Packed2: TMenuItem; Ratio2: TMenuItem; Timestamp2: TMenuItem; Filesize2: TMenuItem; Select1: TMenuItem; SelectAll1: TMenuItem; ClearSelections1: TMenuItem; Rows1: TMenuItem; Rowheight1: TMenuItem; Headerheight1: TMenuItem; Font1: TMenuItem; Alternatecolors1: TMenuItem; Action1: TMenuItem; Extract1: TMenuItem; ShowIcons1: TMenuItem; Colors1: TMenuItem; Selectedcolor: TMenuItem; Selectedtextcolor: TMenuItem; Alternatecolor1: TMenuItem; Alternatetextcolor1: TMenuItem; Panel2: TPanel; AbMeter1: TAbMeter; Label1: TLabel; Label2: TLabel; PopupMenu1: TPopupMenu; Extract2: TMenuItem; AbMeter2: TAbMeter; AbCabView1: TAbCabView; Extractoptions1: TMenuItem; CreateDirs1: TMenuItem; RestorePath1: TMenuItem; AbCabKit1: TAbCabKit; Additems1: TMenuItem; procedure AbCabView1Click(Sender: TObject); procedure AttributeClick(Sender: TObject); procedure DisplayOptionClick(Sender: TObject); procedure SortAttributeClick(Sender: TObject); procedure SetAttribute(Attr : TAbViewAttribute; Value : Boolean); procedure SetDisplayOption(Option : TAbDisplayOption; Value : Boolean); procedure SetExtractOption(Option : TAbExtractOption; Value : Boolean); procedure SetSortAttribute(Option : TAbSortAttribute; Value : Boolean); procedure Open1Click(Sender: TObject); procedure Close1Click(Sender: TObject); procedure SelectAll1Click(Sender: TObject); procedure ClearSelections1Click(Sender: TObject); procedure Font1Click(Sender: TObject); procedure Exit1Click(Sender: TObject); procedure ExtractOptionClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure Selected1Click(Sender: TObject); procedure Selectedtext1Click(Sender: TObject); procedure Rowheight1Click(Sender: TObject); procedure Headerheight1Click(Sender: TObject); procedure Extract1Click(Sender: TObject); procedure AbCabKit1ConfirmProcessItem(Sender: TObject; Item: TAbArchiveItem; ProcessType: TAbProcessType; var Confirm: Boolean); procedure AbCabView1Change(Sender: TObject); procedure Alternatecolor1Click(Sender: TObject); procedure Alternatetextcolor1Click(Sender: TObject); procedure AbCabKit1Save(Sender: TObject); procedure Additems1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} const MainCaption = ' TAbCabView example'; { -------------------------------------------------------------------------- } procedure TForm1.SetAttribute(Attr : TAbViewAttribute; Value : Boolean); procedure SetMenu(Item : TMenuItem); begin Item.Checked := Value; if Item.Checked then AbCabView1.Attributes := AbCabView1.Attributes + [Attr] else AbCabView1.Attributes := AbCabView1.Attributes - [Attr]; end; begin case Attr of vaItemName : SetMenu(ItemName1); vaPacked : SetMenu(Packed1); vaMethod : SetMenu(Method1); vaRatio : SetMenu(Ratio1); vaCRC : SetMenu(CRC1); vaFileAttributes : SetMenu(FileAttributes1); vaFileType : SetMenu(FileType1); vaEncryption : SetMenu(Encryption1); vaTimeStamp : SetMenu(TimeStamp1); vaFileSize : SetMenu(FileSize1); vaVersionMade : SetMenu(VersionMade1); vaVersionNeeded : SetMenu(VersionNeeded1); vaPath : SetMenu(Path1); end; end; { -------------------------------------------------------------------------- } procedure TForm1.SetDisplayOption(Option : TAbDisplayOption; Value : Boolean); procedure SetMenu(Item : TMenuItem); begin Item.Checked := Value; if Item.Checked then AbCabView1.DisplayOptions := AbCabView1.DisplayOptions + [Option] else AbCabView1.DisplayOptions := AbCabView1.DisplayOptions - [Option] end; begin case Option of doAlternateColors : SetMenu(AlternateColors1); doColLines : SetMenu(ColumnLines1); doColMove : SetMenu(ColumnMoving1); doColSizing : SetMenu(ColumnResizing1); doMultiSelect : SetMenu(MultiSelect1); doRowLines : SetMenu(RowLines1); doShowIcons : SetMenu(ShowIcons1); doThumbTrack : SetMenu(ThumbTracking1); doTrackActiveRow : SetMenu(TrackActiveRow1); end; end; { -------------------------------------------------------------------------- } procedure TForm1.SetExtractOption(Option : TAbExtractOption; Value : Boolean); procedure SetMenu(Item : TMenuItem); begin Item.Checked := Value; if Item.Checked then AbCabKit1.ExtractOptions := AbCabKit1.ExtractOptions + [Option] else AbCabKit1.ExtractOptions := AbCabKit1.ExtractOptions - [Option] end; begin case Option of eoCreateDirs : SetMenu(CreateDirs1); eoRestorePath : SetMenu(RestorePath1); end; end; { -------------------------------------------------------------------------- } procedure TForm1.SetSortAttribute(Option : TAbSortAttribute; Value : Boolean); procedure SetMenu(Item : TMenuItem); begin Item.Checked := Value; if Item.Checked then AbCabView1.SortAttributes := AbCabView1.SortAttributes + [Option] else AbCabView1.SortAttributes := AbCabView1.SortAttributes - [Option]; end; begin case Option of saItemName : SetMenu(ItemName2); saPacked : SetMenu(Packed2); saRatio : SetMenu(Ratio2); saTimeStamp : SetMenu(TimeStamp2); saFileSize : SetMenu(FileSize2); end; end; { -------------------------------------------------------------------------- } procedure TForm1.AbCabView1Click(Sender: TObject); begin Panel1.Caption := AbCabView1.Items[AbCabView1.ActiveRow].Filename; end; { -------------------------------------------------------------------------- } procedure TForm1.Open1Click(Sender: TObject); begin OpenDialog1.Filename := '*.cab'; if OpenDialog1.Execute then begin AbCabKit1.Filename := OpenDialog1.Filename; { AbCabKit1.BaseDirectory := ExtractFilePath(AbCabKit1.Filename);} Caption := AbCabKit1.Filename + ' ' + IntToStr(AbCabView1.Count) + ' items'; Action1.Enabled := True; end; end; { -------------------------------------------------------------------------- } procedure TForm1.Close1Click(Sender: TObject); begin AbCabKit1.Filename := ''; Caption := MainCaption; Panel1.Caption := ''; Action1.Enabled := False; end; { -------------------------------------------------------------------------- } procedure TForm1.AttributeClick(Sender: TObject); begin with TMenuItem(Sender) do SetAttribute(TAbViewAttribute(Tag), not Checked); end; { -------------------------------------------------------------------------- } procedure TForm1.DisplayOptionClick(Sender: TObject); begin with TMenuItem(Sender) do SetDisplayOption(TAbDisplayOption(Tag), not Checked); end; { -------------------------------------------------------------------------- } procedure TForm1.SortAttributeClick(Sender: TObject); begin with TMenuItem(Sender) do SetSortAttribute(TAbSortAttribute(Tag), not Checked); end; { -------------------------------------------------------------------------- } procedure TForm1.SelectAll1Click(Sender: TObject); begin AbCabView1.SelectAll; AbCabView1Click(nil); end; { -------------------------------------------------------------------------- } procedure TForm1.ClearSelections1Click(Sender: TObject); begin AbCabView1.ClearSelections; AbCabView1Click(nil); end; { -------------------------------------------------------------------------- } procedure TForm1.ExtractOptionClick(Sender: TObject); begin with TMenuItem(Sender) do SetExtractOption(TAbExtractOption(Tag), not Checked); end; { -------------------------------------------------------------------------- } procedure TForm1.Font1Click(Sender: TObject); begin FontDialog1.Font := AbCabView1.Font; if FontDialog1.Execute then AbCabView1.Font := FontDialog1.Font; end; { -------------------------------------------------------------------------- } procedure TForm1.Exit1Click(Sender: TObject); begin Close; end; { -------------------------------------------------------------------------- } procedure TForm1.FormCreate(Sender: TObject); var i : TAbViewAttribute; j : TAbDisplayOption; k : TAbSortAttribute; m : TAbExtractOption; begin for i := Low(TAbViewAttribute) to High(TAbViewAttribute) do SetAttribute(i, i in AbCabView1.Attributes); for j := Low(TAbDisplayOption) to High(TAbDisplayOption) do SetDisplayOption(j, j in AbCabView1.DisplayOptions); for k := Low(TAbSortAttribute) to High(TAbSortAttribute) do SetSortAttribute(k, k in AbCabView1.SortAttributes); for m := Low(TAbExtractOption) to High(TAbExtractOption) do SetExtractOption(m, m in AbCabKit1.ExtractOptions); Caption := MainCaption; Action1.Enabled := AbCabKit1.FileName <> ''; end; { -------------------------------------------------------------------------- } procedure TForm1.Selected1Click(Sender: TObject); begin if ColorDialog1.Execute then AbCabView1.Colors.Selected := ColorDialog1.Color; end; { -------------------------------------------------------------------------- } procedure TForm1.Selectedtext1Click(Sender: TObject); begin if ColorDialog1.Execute then AbCabView1.Colors.SelectedText := ColorDialog1.Color; end; { -------------------------------------------------------------------------- } procedure TForm1.Rowheight1Click(Sender: TObject); var s : string; begin s := IntToStr(AbCabView1.DefaultRowHeight); if InputQuery(MainCaption, 'Row Height', s) then AbCabView1.DefaultRowHeight := StrToIntDef(s, 18); end; { -------------------------------------------------------------------------- } procedure TForm1.Headerheight1Click(Sender: TObject); var s : string; begin s := IntToStr(AbCabView1.HeaderRowHeight); if InputQuery(MainCaption, 'Header Height', s) then AbCabView1.HeaderRowHeight := StrToIntDef(s, 18); end; { -------------------------------------------------------------------------- } procedure TForm1.Extract1Click(Sender: TObject); var i : Longint; Continue : Boolean; begin with TAbDirDlg.Create(Self) do begin Caption := 'Directory'; AdditionalText := 'Select folder to extract into'; Continue := Execute; if Continue then AbCabKit1.BaseDirectory := SelectedFolder; Free; end; if not Continue then Exit; Panel1.Caption := ''; with AbCabView1 do for i := 0 to Pred(Count) do Items[i].Tagged := Selected[i]; AbCabKit1.ExtractTaggedItems; AbCabView1.ClearSelections; Panel1.Caption := ''; end; { -------------------------------------------------------------------------- } procedure TForm1.AbCabKit1ConfirmProcessItem(Sender: TObject; Item: TAbArchiveItem; ProcessType: TAbProcessType; var Confirm: Boolean); var s : string; begin if (ProcessType = ptExtract) then s := 'Extracting ' else s := '??? '; Panel1.Caption := s + Item.Filename; Confirm := True; end; { -------------------------------------------------------------------------- } procedure TForm1.AbCabView1Change(Sender: TObject); begin Caption := AbCabKit1.Filename + ' ' + IntToStr(AbCabView1.Count) + ' items'; end; { -------------------------------------------------------------------------- } procedure TForm1.Alternatecolor1Click(Sender: TObject); begin if ColorDialog1.Execute then AbCabView1.Colors.Alternate := ColorDialog1.Color; end; { -------------------------------------------------------------------------- } procedure TForm1.Alternatetextcolor1Click(Sender: TObject); begin if ColorDialog1.Execute then AbCabView1.Colors.AlternateText := ColorDialog1.Color; end; { -------------------------------------------------------------------------- } procedure TForm1.AbCabKit1Save(Sender: TObject); begin Panel1.Caption := 'Saving ' + AbCabKit1.Filename; end; { -------------------------------------------------------------------------- } procedure TForm1.Additems1Click(Sender: TObject); var i : Integer; begin with OpenDialog1 do begin FileName := '*.*'; Title := 'Select files to add'; if Execute then if (Files.Count > 0) then for i := 0 to Pred(Files.Count) do AbCabKit1.AddFiles(Files[i], 0); end; end; end. ================================================ FILE: lib/abbrevia/examples/Delphi/ComCtrlsDemo.dpr ================================================ program ComCtrlsDemo; uses Forms, ComCtrlsMain in 'ComCtrlsMain.pas' {frmComCtrls}; {$R *.res} begin Application.Initialize; Application.MainFormOnTaskbar := True; Application.CreateForm(TfrmComCtrls, frmComCtrls); Application.Run; end. ================================================ FILE: lib/abbrevia/examples/Delphi/ComCtrlsMain.dfm ================================================ object frmComCtrls: TfrmComCtrls Left = 0 Top = 0 Caption = 'AbComCtrls Example' ClientHeight = 524 ClientWidth = 699 Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'Tahoma' Font.Style = [] Menu = MainMenu OldCreateOrder = False PixelsPerInch = 96 TextHeight = 13 object Splitter1: TSplitter Left = 153 Top = 0 Height = 524 ExplicitLeft = 360 ExplicitTop = 240 ExplicitHeight = 100 end object AbTreeView: TAbTreeView Left = 0 Top = 0 Width = 153 Height = 524 Align = alLeft Indent = 19 TabOrder = 0 Items.NodeData = { 0301000000200000000000000000000000FFFFFFFFFFFFFFFF00000000000000 000000000001015C00} Archive = AbUnZipper ListView = AbListView end object Panel1: TPanel Left = 156 Top = 0 Width = 543 Height = 524 Align = alClient Caption = 'Panel1' TabOrder = 1 ExplicitLeft = 264 ExplicitTop = 272 ExplicitWidth = 185 ExplicitHeight = 41 object Splitter2: TSplitter Left = 1 Top = 335 Width = 541 Height = 3 Cursor = crVSplit Align = alBottom ExplicitLeft = 539 ExplicitTop = 1 ExplicitWidth = 337 end object Memo1: TMemo Left = 1 Top = 338 Width = 541 Height = 185 Align = alBottom Lines.Strings = ( 'Memo1') TabOrder = 0 ExplicitLeft = 354 ExplicitTop = 1 ExplicitWidth = 522 end object AbListView: TAbListView Left = 1 Top = 1 Width = 541 Height = 334 Align = alClient Archive = AbUnZipper TabOrder = 1 TreeView = AbTreeView OnSelectItem = ListViewSelectItem ExplicitLeft = 328 ExplicitTop = 112 ExplicitWidth = 250 ExplicitHeight = 150 end end object AbUnZipper: TAbUnZipper Left = 96 Top = 24 end object MainMenu: TMainMenu Left = 16 Top = 24 object mnuFile: TMenuItem Caption = 'File' object mnuOpenArchive: TMenuItem Caption = 'Open...' OnClick = OpenArchiveClick end end object mnuView: TMenuItem Caption = 'View' object mnuAllFiles: TMenuItem AutoCheck = True Caption = 'All Files (WinZip Style)' GroupIndex = 1 RadioItem = True OnClick = FolderStyleClick end object mnuFilesByFolder: TMenuItem AutoCheck = True Caption = 'Files By Folder (Explorer Style)' Checked = True GroupIndex = 1 RadioItem = True OnClick = FolderStyleClick end object N1: TMenuItem Caption = '-' GroupIndex = 1 end object mnuIcons: TMenuItem AutoCheck = True Caption = 'Icons' Checked = True GroupIndex = 2 RadioItem = True OnClick = ViewStyleClick end object mnuList: TMenuItem AutoCheck = True Caption = 'List' GroupIndex = 2 RadioItem = True OnClick = ViewStyleClick end object mnuDetails: TMenuItem AutoCheck = True Caption = 'Details' GroupIndex = 2 RadioItem = True OnClick = ViewStyleClick end end end object OpenDialog: TOpenDialog Filter = 'Archive Files|*.zip;*.tar;*.gz;*.tgz;*.bz2;*.tbz' Options = [ofEnableSizing] Left = 56 Top = 24 end end ================================================ FILE: lib/abbrevia/examples/Delphi/ComCtrlsMain.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * Craig Peterson * * Portions created by the Initial Developer are Copyright (C) 2011 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* This demonstrates the TAbTreeView and TAbListView *} {* components. By setting references to each other and *} {* a shared TAbBaseBrowser descendant (e.g., TAbZipKit *} {* you can have a WinZip/Explorer-like interface without *} {* any code. *} {*********************************************************} unit ComCtrlsMain; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, Menus, ComCtrls, AbComCtrls, AbBase, AbBrowse, AbZBrows, AbUnzper; type TfrmComCtrls = class(TForm) AbUnZipper: TAbUnZipper; AbTreeView: TAbTreeView; AbListView: TAbListView; MainMenu: TMainMenu; mnuFile: TMenuItem; mnuOpenArchive: TMenuItem; Splitter1: TSplitter; Splitter2: TSplitter; Memo1: TMemo; OpenDialog: TOpenDialog; mnuView: TMenuItem; mnuAllFiles: TMenuItem; mnuFilesByFolder: TMenuItem; N1: TMenuItem; mnuIcons: TMenuItem; mnuList: TMenuItem; mnuDetails: TMenuItem; Panel1: TPanel; procedure FolderStyleClick(Sender: TObject); procedure ListViewSelectItem(Sender: TObject; Item: TListItem; Selected: Boolean); procedure OpenArchiveClick(Sender: TObject); procedure ViewStyleClick(Sender: TObject); private { Private declarations } public { Public declarations } end; var frmComCtrls: TfrmComCtrls; implementation {$R *.dfm} procedure TfrmComCtrls.FolderStyleClick(Sender: TObject); begin AbTreeView.Visible := mnuFilesByFolder.Checked; Splitter1.Visible := mnuFilesByFolder.Checked; AbListView.FlatList := mnuAllFiles.Checked; end; procedure TfrmComCtrls.ListViewSelectItem(Sender: TObject; Item: TListItem; Selected: Boolean); var Stream: TMemoryStream; begin if TAbListItem(Item).IsDirectory then Memo1.Clear else begin Stream := TMemoryStream.Create; try AbUnZipper.ExtractToStream(TAbListItem(Item).ArchiveItem.FileName, Stream); Stream.Position := 0; Memo1.Lines.LoadFromStream(Stream); finally Stream.Free; end; end; end; procedure TfrmComCtrls.OpenArchiveClick(Sender: TObject); begin if OpenDialog.Execute then AbUnZipper.FileName := OpenDialog.FileName; end; procedure TfrmComCtrls.ViewStyleClick(Sender: TObject); begin if mnuIcons.Checked then AbListView.ViewStyle := vsIcon else if mnuList.Checked then AbListView.ViewStyle := vsList else AbListView.ViewStyle := vsReport; end; end. ================================================ FILE: lib/abbrevia/examples/Delphi/CompPad.dpr ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: COMPPAD.DPR *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} program CompPad; uses Forms, ucomppad in 'UCOMPPAD.PAS' {Form1}; begin Application.Initialize; Application.CreateForm(TForm1, Form1); Application.Run; end. ================================================ FILE: lib/abbrevia/examples/Delphi/Contents.dpr ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: CONTENTS.DPR *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} program Contents; uses Forms, UContent in 'UCONTENT.PAS' {Form1}; begin Application.CreateForm(TForm1, Form1); Application.Run; end. ================================================ FILE: lib/abbrevia/examples/Delphi/ExCBrows.dpr ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: CONTENTS.DPR *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} program ExCBrows; uses Forms, ExCBrowu in 'ExCBrowu.pas' {Form1}; begin Application.CreateForm(TForm1, Form1); Application.Run; end. ================================================ FILE: lib/abbrevia/examples/Delphi/ExCBrowu.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: UCONTENT.PAS *} {* Copyright (c) TurboPower Software Co 1997 *} {* All rights reserved. *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} unit ExCBrowu; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, AbArcTyp, AbCBrows, AbMeter, AbBrowse, AbBase; type TForm1 = class(TForm) OpenDialog1: TOpenDialog; AbCabBrowser1: TAbCabBrowser; Memo1: TMemo; Panel1: TPanel; Button1: TButton; Button2: TButton; Label1: TLabel; Panel2: TPanel; AbMeter1: TAbMeter; AbMeter2: TAbMeter; Label2: TLabel; Label3: TLabel; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure AbCabBrowser1Load(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} const BoolToStr : array[Boolean] of string = ('No', 'Yes'); procedure TForm1.Button1Click(Sender: TObject); begin if OpenDialog1.Execute then AbCabBrowser1.FileName := OpenDialog1.FileName; end; procedure TForm1.Button2Click(Sender: TObject); begin AbCabBrowser1.Filename := ''; Memo1.Clear; end; procedure TForm1.AbCabBrowser1Load(Sender: TObject); var i : Integer; LI : Longint; DT : TDateTime; s : string; begin Memo1.Clear; with AbCabBrowser1 do begin Memo1.Lines.Add(Filename); Memo1.Lines.Add('----------------------------------------------'); Memo1.Lines.Add(' Size: ' + #9 + #9 + IntToStr(CabSize)); Memo1.Lines.Add(' Folders: ' + #9 + #9 + IntToStr(FolderCount)); Memo1.Lines.Add(' Files: ' + #9 + #9 + IntToStr(Count)); Memo1.Lines.Add(' SetID: ' + #9 + #9 + IntToStr(SetID)); Memo1.Lines.Add(' Cab #: ' + #9 + #9 + IntToStr(CurrentCab)); Memo1.Lines.Add(' hasPrev: ' + #9 + BoolToStr[HasPrev]); Memo1.Lines.Add(' hasNext: ' + #9 + BoolToStr[HasNext]); Memo1.Lines.Add(' '); if (Count > 0) then begin Memo1.Lines.Add('Files' + #9 + #9 + 'Size' + #9 + 'Timestamp' + #9 + #9 + 'Attributes' + #9 +'Partial File'); Memo1.Lines.Add('--------------------------------------------' + '--------------------------------------------' + '--------------------------------------------'); for i := 0 to Pred(Count) do begin LI := LongInt(Items[i].LastModFileDate) shl 16 + Items[i].LastModFileTime; DT := FileDateToDateTime(LI); s := Items[i].FileName + #9 + IntToStr(Items[i].UnCompressedSize) + #9 + DateTimeToStr(DT) + #9 + IntToStr(Items[i].ExternalFileAttributes) + #9 + BoolToStr[Items[i].PartialFile]; Memo1.Lines.Add(s); end; end; end; end; end. ================================================ FILE: lib/abbrevia/examples/Delphi/ExCf.dpr ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) program ExCf; uses Forms, uCfMain in 'uCfMain.pas' {fmCfMain}, uCfGenDg in 'uCfGenDg.pas' {frmCfGenDlg}, uCfNewDg in 'uCfNewDg.pas' {frmCfNewDlg}; {$R *.RES} begin Application.Initialize; Application.CreateForm(TfmCfMain, fmCfMain); Application.CreateForm(TfrmCfGenDlg, frmCfGenDlg); Application.CreateForm(TfrmCfNewDlg, frmCfNewDlg); Application.Run; end. ================================================ FILE: lib/abbrevia/examples/Delphi/ExFilter.dpr ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: EXFILTER.DPR *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} program Exfilter; uses Forms, Exfiltru in 'EXFILTRU.PAS' {Form1}; begin Application.CreateForm(TForm1, Form1); Application.Run; end. ================================================ FILE: lib/abbrevia/examples/Delphi/ExFiltru.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: EXFILTRU.PAS *} {* Copyright (c) TurboPower Software Co 1997 *} {* All rights reserved. *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} unit Exfiltru; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Gauges, Grids, ExtCtrls, FileCtrl, AbZipper, AbArcTyp, AbZBrows, AbMeter, AbZipKit, AbView, AbZView, AbBrowse, AbBase, AbUtils; type TForm1 = class(TForm) OpenDialog1: TOpenDialog; OpenBtn: TButton; AbZipView1: TAbZipView; CloseBtn: TButton; AddGroup: TGroupBox; Label1: TLabel; FileMask1: TEdit; Label2: TLabel; FilterMask1: TEdit; AddBtn: TButton; Label3: TLabel; DirectoryListBox1: TDirectoryListBox; Bevel1: TBevel; Label4: TLabel; DeleteGroup: TGroupBox; Label5: TLabel; FileMask2: TEdit; Label6: TLabel; FilterMask2: TEdit; DeleteBtn: TButton; Bevel2: TBevel; AbortBtn: TButton; ExitBtn: TButton; ExtractGroup: TGroupBox; Label7: TLabel; Label8: TLabel; Label9: TLabel; Bevel3: TBevel; FileMask3: TEdit; FilterMask3: TEdit; ExtractBtn: TButton; DirectoryListBox2: TDirectoryListBox; AbZipKit1: TAbZipKit; AbMeter1: TAbMeter; procedure AddBtnClick(Sender: TObject); procedure OpenBtnClick(Sender: TObject); procedure DeleteBtnClick(Sender: TObject); procedure CloseBtnClick(Sender: TObject); procedure AbortBtnClick(Sender: TObject); procedure ExitBtnClick(Sender: TObject); procedure FormCreate(Sender: TObject); procedure ExtractBtnClick(Sender: TObject); procedure AbZipKit1ConfirmProcessItem(Sender: TObject; Item: TAbArchiveItem; ProcessType: TAbProcessType; var Confirm: Boolean); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} const MainCaption = ' ExFilter : Exception list example'; AddCaption = ' Add files to zip archive '; DeleteCaption = ' Delete files from zip archive '; ExtractCaption = ' Extract files from zip archive '; var AbortFlag : Boolean; procedure TForm1.OpenBtnClick(Sender: TObject); begin AbZipKit1.Filename := ''; AddBtn.Enabled := False; DeleteBtn.Enabled := False; OpenDialog1.Filename := '*.zip'; if OpenDialog1.Execute then begin AbZipKit1.Filename := OpenDialog1.Filename; OpenBtn.Enabled := False; CloseBtn.Enabled := True; AddBtn.Enabled := True; DeleteBtn.Enabled := True; ExtractBtn.Enabled := True; AbZipView1.Enabled := True; Caption := ' ' + AbZipKit1.Filename; end; end; procedure TForm1.CloseBtnClick(Sender: TObject); begin Screen.Cursor := crHourglass; Caption := 'Saving ' + AbZipKit1.Filename; AbZipKit1.CloseArchive; Screen.Cursor := crDefault; OpenBtn.Enabled := True; CloseBtn.Enabled := False; AddBtn.Enabled := False; DeleteBtn.Enabled := False; ExtractBtn.Enabled := False; AbZipView1.Enabled := False; Caption := MainCaption; end; procedure TForm1.AddBtnClick(Sender: TObject); var SavedColor : TColor; begin AbortFlag := False; AbZipKit1.BaseDirectory := DirectoryListBox1.Directory; SavedColor := AddGroup.Font.Color; AddGroup.Font.Color := clRed; try AbZipKit1.AddFilesEx(FileMask1.Text, FilterMask1.Text, 0 ); AbZipKit1.Save; finally AddGroup.Font.Color := SavedColor; AddGroup.Caption := AddCaption; end; end; procedure TForm1.DeleteBtnClick(Sender: TObject); var SavedColor : TColor; begin AbortFlag := False; SavedColor := DeleteGroup.Font.Color; DeleteGroup.Font.Color := clRed; try AbZipKit1.DeleteFilesEx(FileMask2.Text, FilterMask2.Text); AbZipKit1.Save; finally DeleteGroup.Font.Color := SavedColor; DeleteGroup.Caption := DeleteCaption; end; end; procedure TForm1.ExtractBtnClick(Sender: TObject); var SavedColor : TColor; begin AbortFlag := False; AbZipKit1.BaseDirectory := DirectoryListBox2.Directory; SavedColor := ExtractGroup.Font.Color; ExtractGroup.Font.Color := clRed; try AbZipKit1.ExtractFilesEx(FileMask3.Text, FilterMask3.Text); finally ExtractGroup.Font.Color := SavedColor; ExtractGroup.Caption := ExtractCaption; end; end; procedure TForm1.AbortBtnClick(Sender: TObject); begin AbortFlag := True; end; procedure TForm1.ExitBtnClick(Sender: TObject); begin AbZipKit1.CloseArchive; Close; end; procedure TForm1.FormCreate(Sender: TObject); begin Caption := MainCaption; AddGroup.Caption := AddCaption; DeleteGroup.Caption := DeleteCaption; ExtractGroup.Caption := ExtractCaption; end; procedure TForm1.AbZipKit1ConfirmProcessItem(Sender: TObject; Item: TAbArchiveItem; ProcessType: TAbProcessType; var Confirm: Boolean); begin case ProcessType of ptAdd : AddGroup.Caption := ' Adding ' + Item.Filename + ' '; ptDelete : DeleteGroup.Caption := ' Deleting ' + Item.Filename + ' '; ptExtract : ExtractGroup.Caption := ' Extracting ' + Item.Filename + ' '; end; Confirm := not AbortFlag; end; end. ================================================ FILE: lib/abbrevia/examples/Delphi/ExZipper.dpr ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) program ExZipper; uses Forms, Exzippru in 'EXZIPPRU.PAS' {Form1}; begin Application.CreateForm(TForm1, Form1); Application.Run; end. ================================================ FILE: lib/abbrevia/examples/Delphi/ExZippru.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: EXZIPPRU.PAS *} {* Copyright (c) TurboPower Software Co 1997 *} {* All rights reserved. *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} unit ExZippru; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, FileCtrl, AbArcTyp, AbZipOut, AbZBrows, AbZipper, AbBrowse, AbBase, AbMeter, AbUtils; type TForm1 = class(TForm) Button1: TButton; Button2: TButton; OpenDialog1: TOpenDialog; DirectoryListBox1: TDirectoryListBox; DriveComboBox1: TDriveComboBox; Label1: TLabel; AbZipper1: TAbZipper; Button3: TButton; AbMeter1: TAbMeter; procedure Button1Click(Sender: TObject); procedure DirectoryListBox1Change(Sender: TObject); procedure FormCreate(Sender: TObject); procedure Button2Click(Sender: TObject); procedure AbZipper1ConfirmProcessItem(Sender: TObject; Item: TAbArchiveItem; ProcessType: TAbProcessType; var Confirm: Boolean); procedure Button3Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} procedure TForm1.FormCreate(Sender: TObject); begin DirectoryListBox1Change(nil); AbZipper1.LogFile := ExtractFilePath(Application.ExeName) + 'Log.txt'; end; procedure TForm1.DirectoryListBox1Change(Sender: TObject); begin AbZipper1.BaseDirectory := DirectoryListBox1.Directory; end; procedure TForm1.Button1Click(Sender: TObject); begin OpenDialog1.Filename := '*.zip'; OpenDialog1.InitialDir := DirectoryListBox1.Directory; if OpenDialog1.Execute then AbZipper1.Filename := OpenDialog1.Filename; end; procedure TForm1.Button2Click(Sender: TObject); begin AbZipper1.AddFiles('*.*', 0); Caption := 'ExZipper'; end; procedure TForm1.AbZipper1ConfirmProcessItem(Sender: TObject; Item: TAbArchiveItem; ProcessType: TAbProcessType; var Confirm: Boolean); begin Caption := 'adding ' + Item.Filename; end; procedure TForm1.Button3Click(Sender: TObject); begin Cursor := crHourGlass; AbZipper1.CloseArchive; Cursor := crDefault; end; end. ================================================ FILE: lib/abbrevia/examples/Delphi/FCITest1.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) unit FCITest1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, AbCabKit{, TestCab}; type TForm1 = class(TForm) Button1: TButton; Button2: TButton; Button3: TButton; OpenDialog1: TOpenDialog; Memo1: TMemo; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button3Click(Sender: TObject); private { Private declarations } public end; var Form1: TForm1; implementation {$R *.DFM} procedure TForm1.Button1Click(Sender: TObject); begin OpenDialog1.Filename := '*.cab'; if OpenDialog1.Execute then begin Memo1.Clear; MakeCab(OpenDialog1.Filename); Memo1.Lines.Assign(TestCab.AuditTrail); end; end; procedure TForm1.Button2Click(Sender: TObject); var i : Integer; begin OpenDialog1.Filename := '*.*'; if OpenDialog1.Execute then if OpenDialog1.Files.Count > 0 then for i := 0 to Pred(OpenDialog1.Files.Count) do begin try AddFile(OpenDialog1.Files[i]); finally end; end; Memo1.Lines.Assign(TestCab.AuditTrail); end; procedure TForm1.Button3Click(Sender: TObject); begin CloseArchive; Memo1.Lines.Assign(TestCab.AuditTrail); end; end. ================================================ FILE: lib/abbrevia/examples/Delphi/Finder.dpr ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: FINDER.DPR *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} program finder; uses Forms, ufinder in 'ufinder.pas' {Form1}; begin Application.CreateForm(TForm1, Form1); Application.Run; end. ================================================ FILE: lib/abbrevia/examples/Delphi/MakeCab.dpr ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: MAKECAB.DPR *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} program MakeCab; uses Forms, MakeCab1 in 'MakeCab1.pas' {Form1}; begin Application.CreateForm(TForm1, Form1); Application.Run; end. ================================================ FILE: lib/abbrevia/examples/Delphi/MakeCab1.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: MAKECAB1.PAS *} {* Copyright (c) TurboPower Software Co 1997 *} {* All rights reserved. *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} unit MakeCab1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Gauges, ExtCtrls, ComCtrls, AbArcTyp, AbCBrows, AbCabMak, AbCabTyp, AbMeter, AbBrowse, AbBase; type TForm1 = class(TForm) AddBtn: TButton; OpenDialog1: TOpenDialog; Label1: TLabel; CreateBtn: TButton; CloseBtn: TButton; Panel1: TPanel; NewFolderBtn: TButton; Label2: TLabel; NewCabBtn: TButton; AbMeter1: TAbMeter; AbMakeCab1: TAbMakeCab; procedure AddBtnClick(Sender: TObject); procedure CreateBtnClick(Sender: TObject); procedure CloseBtnClick(Sender: TObject); procedure NewFolderBtnClick(Sender: TObject); procedure NewCabBtnClick(Sender: TObject); procedure AbMakeCab1ArchiveItemProgress(Sender: TObject; Item: TAbArchiveItem; Progress: Byte; var Abort: Boolean); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} const MainCaption = 'Make Cabinet Archive'; procedure TForm1.CreateBtnClick(Sender: TObject); begin OpenDialog1.Filename := '*.Cab'; OpenDialog1.Title := 'Name of 1st cabinet'; if OpenDialog1.Execute then begin Panel1.Caption := 'Creating ' + OpenDialog1.FileName; AbMakeCab1.OpenArchive(OpenDialog1.FileName); Caption := AbMakeCab1.FileName; Panel1.Caption := 'Idle'; end; end; procedure TForm1.AddBtnClick(Sender: TObject); var i : Integer; SC : TCursor; FileList : TStringList; begin OpenDialog1.Filename := '*.*'; OpenDialog1.Title := 'Add files to cabinet'; if OpenDialog1.Execute then if (OpenDialog1.Files.Count > 0) then begin SC := Cursor; Cursor := crHourglass; FileList := TStringList.Create; try FileList.Assign(OpenDialog1.Files); for i := 0 to Pred(FileList.Count) do AbMakeCab1.AddFiles(FileList.Strings[i], 0); finally FileList.Free; end; Cursor := SC; Panel1.Caption := 'Idle'; end; end; procedure TForm1.CloseBtnClick(Sender: TObject); begin Panel1.Caption := 'Closing ' + AbMakeCab1.FileName; AbMakeCab1.CloseArchive; Caption := MainCaption; Panel1.Caption := 'Idle'; end; procedure TForm1.NewFolderBtnClick(Sender: TObject); begin AbMakeCab1.StartNewFolder; end; procedure TForm1.NewCabBtnClick(Sender: TObject); begin AbMakeCab1.StartNewCabinet; end; procedure TForm1.AbMakeCab1ArchiveItemProgress(Sender: TObject; Item: TAbArchiveItem; Progress: Byte; var Abort: Boolean); begin Panel1.Caption := 'Adding ' + ExtractFilename(Item.Filename); Abort := False; end; end. ================================================ FILE: lib/abbrevia/examples/Delphi/SelfStbv.dpr ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: SELFEXV.DPR *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} program Selfstbv; uses Forms, Slfstbv1 in 'SLFSTBV1.PAS' {Form1}; begin Application.CreateForm(TForm1, Form1); Application.Run; end. ================================================ FILE: lib/abbrevia/examples/Delphi/SelfStub.dpr ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: SELFSTUB.DPR *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} (* This program creates a ZIP stub called SELFEX.EXE. This stub can then be used to create self-extracting ZIP files. For more information on self-extracting ZIPs and ZIP stubs see page 112 in the Abbrevia manual. *) program Selfstub; {$APPTYPE CONSOLE} uses AbArcTyp, AbUnzPrc, AbUtils, AbZipTyp, SysUtils; type THelper = class public procedure UnzipProc(Sender : TObject; Item : TAbArchiveItem; const NewName : string); end; procedure THelper.UnzipProc(Sender : TObject; Item : TAbArchiveItem; const NewName : string); begin AbUnzip(Sender, TAbZipItem(Item), NewName); end; {Build this app using the Define "BuildingStub", to keep it smaller!} var ZipArchive : TAbZipArchive; Helper : THelper; begin WriteLn( 'Abbrevia Self Extracting Archive' ); ZipArchive := TAbZipArchive.Create(ParamStr(0), fmOpenRead or fmShareDenyNone); ChDir( ExtractFilePath(ParamStr(0))); Helper := THelper.Create; try ZipArchive.Load; ZipArchive.ExtractHelper := Helper.UnzipProc; ZipArchive.ExtractFiles('*.*'); finally Helper.Free; ZipArchive.Free; end; end. ================================================ FILE: lib/abbrevia/examples/Delphi/SlfStbv1.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: SLFSTBV1.PAS *} {* Copyright (c) TurboPower Software Co 1997 *} {* All rights reserved. *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} unit Slfstbv1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, AbZBrows, AbUnZper, AbArcTyp, AbBrowse, AbBase, AbUtils; type TForm1 = class(TForm) Button1: TButton; AbUnZipper1: TAbUnZipper; Memo1: TMemo; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} procedure TForm1.Button1Click(Sender: TObject); begin AbUnzipper1.FileName := ExtractFilePath(Application.ExeName) + 'abtest.exe'; AbUnzipper1.ArchiveType := atSelfExtZip; AbUnzipper1.ExtractFiles( '*.*' ); end; end. ================================================ FILE: lib/abbrevia/examples/Delphi/Streams.dpr ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: STREAMS.DPR *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} program Streams; uses Forms, Streams1 in 'Streams1.pas' {Form1}; begin Application.CreateForm(TForm1, Form1); Application.Run; end. ================================================ FILE: lib/abbrevia/examples/Delphi/Streams1.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: STREAMS1.PAS *} {* Copyright (c) TurboPower Software Co 1997 *} {* All rights reserved. *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} unit Streams1; interface uses Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Grids, AbView, AbZView, Menus, AbArcTyp, AbZBrows, AbUnZper, AbZipper, AbZipKit, AbBrowse, AbBase; type TForm1 = class(TForm) MainMenu1: TMainMenu; File1: TMenuItem; Open1: TMenuItem; Exit1: TMenuItem; Action1: TMenuItem; Extract1: TMenuItem; AbZipView1: TAbZipView; Memo1: TMemo; OpenDialog1: TOpenDialog; Close1: TMenuItem; N1: TMenuItem; Add1: TMenuItem; AbZipKit1: TAbZipKit; Clearmemo1: TMenuItem; procedure Open1Click(Sender: TObject); procedure Extract1Click(Sender: TObject); procedure Close1Click(Sender: TObject); procedure Exit1Click(Sender: TObject); procedure AbZipView1DblClick(Sender: TObject); procedure Clearmemo1Click(Sender: TObject); procedure Add1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} const MainCaption = ' Compressed Memo'; procedure TForm1.Open1Click(Sender: TObject); begin OpenDialog1.Filename := '*.zip'; if OpenDialog1.Execute then AbZipKit1.OpenArchive(OpenDialog1.Filename); end; procedure TForm1.Extract1Click(Sender: TObject); var ToStream : TMemoryStream; Item : TAbArchiveItem; begin Memo1.Clear; ToStream := TMemoryStream.Create; try Item := AbZipView1.Items[AbZipView1.ActiveRow]; Caption := Item.Filename; AbZipKit1.ExtractToStream(Item.FileName, ToStream); ToStream.Position := 0; Memo1.Lines.LoadFromStream(ToStream); finally ToStream.Free; end; end; procedure TForm1.Close1Click(Sender: TObject); begin AbZipKit1.CloseArchive; Caption := MainCaption; end; procedure TForm1.Exit1Click(Sender: TObject); begin Close1Click(nil); Close; end; procedure TForm1.AbZipView1DblClick(Sender: TObject); begin Extract1Click(nil); end; procedure TForm1.Clearmemo1Click(Sender: TObject); begin Memo1.Clear; end; procedure TForm1.Add1Click(Sender: TObject); var FromStream : TMemoryStream; FN : string; begin FromStream := TMemoryStream.Create; try Memo1.Lines.SaveToStream(FromStream); if InputQuery('Streams', 'Give it a filename', FN) then begin Caption := FN; AbZipKit1.AddFromStream(FN, FromStream); end; finally FromStream.Free; end; end; end. ================================================ FILE: lib/abbrevia/examples/Delphi/StrmBmp.dpr ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: STRMBMP.DPR *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} program StrmBmp; uses Forms, StrmBmpU in 'StrmBmpU.pas' {Form1}; begin Application.CreateForm(TForm1, Form1); Application.Run; end. ================================================ FILE: lib/abbrevia/examples/Delphi/StrmBmpU.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: STRMBMPU.DPR *} {* Copyright (c) TurboPower Software Co 1997 *} {* All rights reserved. *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} unit StrmBmpU; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls; type TForm1 = class(TForm) Image1: TImage; Button1: TButton; Memo1: TMemo; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation uses AbUnzPrc, AbZipPrc; {$R *.DFM} procedure TForm1.Button1Click(Sender: TObject); var UStrm : TMemoryStream; CStrm : TMemoryStream; Image2 : TImage; begin { Create the compressed stream and the uncompressed stream. } UStrm := TMemoryStream.Create; CStrm := TMemoryStream.Create; { Copy the bitmap image to the memory stream. } Image1.Picture.Bitmap.SaveToStream(UStrm); { Set the stream position to the beginning. } UStrm.Position := 0; { Compress the stream. } DeflateStream(UStrm, CStrm); { Remove all data from the uncompressed stream. } UStrm.Clear; { Reset the compressed stream back to the beginning. } CStrm.Position := 0; { Decompress the stream back to the original uncompressed } { stream and then reset the stream position back to 0. } InflateStream(CStrm, UStrm); UStrm.Position := 0; { Now create a new TImage. Make it the same size as the } { original image but move it down and to the left. } Image2 := TImage.Create(Self); Image2.Top := Image1.Top + 20; Image2.Left := Image1.Left + 20; Image2.Width := Image1.Width; Image2.Height := Image1.Height; Image2.Parent := Self; { Delete the original TImage. } Image1.Free; { Load the new bitmap with the data from the stream } { that contains the decompressed image. } Image2.Picture.Bitmap.LoadFromStream(UStrm); { Free the memory streams. } UStrm.Free; CStrm.Free; end; end. ================================================ FILE: lib/abbrevia/examples/Delphi/StrmPad.dpr ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: STRMPAD.DPR *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} program StrmPad; uses Forms, Ustrpad in 'Ustrpad.pas' {Form1}; begin Application.CreateForm(TForm1, Form1); Application.Run; end. ================================================ FILE: lib/abbrevia/examples/Delphi/TpZip.RC ================================================ ;{*********************************************************} ;{* ABBREVIA: TPZIP.RC *} ;{* Copyright (c) TurboPower Software Co 1997 *} ;{* All rights reserved. *} ;{*********************************************************} ;{* ABBREVIA Example program file *} ;{*********************************************************} MAINICON ICON "tpzip.ico" ================================================ FILE: lib/abbrevia/examples/Delphi/TpZip.dpr ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: TPZIP.DPR *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} program TPZip; uses Forms, ubasedlg in 'UBASEDLG.PAS' {BaseDirDlg}, udemodlg in 'UDEMODLG.PAS' {DemoDlg}, dgAbout in 'DGABOUT.PAS' {dlgAboutBox}, usplash in 'USPLASH.PAS' {Splash}, UMain in 'Umain.pas' {Form1}; {$R *.R32} begin Application.Title := 'TP Zip'; Application.HelpFile := 'Tpzip31.hlp'; Application.CreateForm(TForm1, Form1); Splash := TSplash.Create( Application ); Splash.Show; Splash.Refresh; Application.Run; end. ================================================ FILE: lib/abbrevia/examples/Delphi/UContent.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: UCONTENT.PAS *} {* Copyright (c) TurboPower Software Co 1997 *} {* All rights reserved. *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} unit UContent; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, AbZBrows, AbArcTyp, AbBrowse, AbBase; type TForm1 = class(TForm) ListBox1: TListBox; Button1: TButton; OpenDialog1: TOpenDialog; AbZipBrowser1: TAbZipBrowser; Label1: TLabel; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} procedure TForm1.Button1Click(Sender: TObject); var i : Integer; begin ListBox1.Clear; if OpenDialog1.Execute then begin try with AbZipBrowser1 do begin FileName := OpenDialog1.FileName; if Count > 0 then for i := 0 to pred( Count ) do ListBox1.Items.Add( Items[i].FileName ); end; except ListBox1.Items.Add( OpenDialog1.FileName + ' is not a valid archive.' ); end; end; end; end. ================================================ FILE: lib/abbrevia/examples/Delphi/UMain.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: UMAIN.PAS *} {* Copyright (c) TurboPower Software Co 1997 *} {* All rights reserved. *} {*********************************************************} {* ABBREVIA: TPZip *} {*********************************************************} {$I AbDefine.inc} unit UMain; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Menus, ExtCtrls, FileCtrl, StdCtrls, Gauges, Buttons, AbArcTyp, AbUtils, AbZipOut, AbMeter, AbBase, AbBrowse; type TForm1 = class(TForm) MainMenu1: TMainMenu; File1: TMenuItem; Open1: TMenuItem; Save1: TMenuItem; N1: TMenuItem; Exit1: TMenuItem; Items1: TMenuItem; Help1: TMenuItem; Contents1: TMenuItem; N2: TMenuItem; About1: TMenuItem; Preferences1: TMenuItem; View1: TMenuItem; Attributes1: TMenuItem; za0: TMenuItem; za1: TMenuItem; za8: TMenuItem; Hierarchy1: TMenuItem; Style1: TMenuItem; Panel1: TPanel; Panel2: TPanel; za2: TMenuItem; za3: TMenuItem; za4: TMenuItem; za5: TMenuItem; za6: TMenuItem; za7: TMenuItem; za9: TMenuItem; za10: TMenuItem; N3: TMenuItem; None1: TMenuItem; All1: TMenuItem; Panel3: TPanel; Panel4: TPanel; DriveComboBox1: TDriveComboBox; FilterComboBox1: TFilterComboBox; DirectoryListBox1: TDirectoryListBox; FileListBox1: TFileListBox; Panel5: TPanel; FontDialog1: TFontDialog; Font1: TMenuItem; Panel6: TPanel; OpenDialog1: TOpenDialog; CompressionMethodToUse1: TMenuItem; Store1: TMenuItem; Deflate1: TMenuItem; Best1: TMenuItem; DeflationOption1: TMenuItem; Maximum1: TMenuItem; Normal1: TMenuItem; Fast1: TMenuItem; SuperFast1: TMenuItem; ExtractOptions1: TMenuItem; CreateDirs1: TMenuItem; RestorePath1: TMenuItem; Password1: TMenuItem; StoreOptions1: TMenuItem; RemoveDots1: TMenuItem; RecurseTree1: TMenuItem; StripPath1: TMenuItem; AddFiles1: TMenuItem; DeleteFiles1: TMenuItem; ExtractFiles1: TMenuItem; FreshenFiles1: TMenuItem; PopupMenu1: TPopupMenu; Delete1: TMenuItem; Run1: TMenuItem; Move1: TMenuItem; Freshen1: TMenuItem; Extract1: TMenuItem; Confirmations1: TMenuItem; Close1: TMenuItem; Convert1: TMenuItem; N4: TMenuItem; Default1: TMenuItem; Panel8: TPanel; SpeedButton1: TSpeedButton; SpeedButton2: TSpeedButton; SpeedButton3: TSpeedButton; SpeedButton4: TSpeedButton; SpeedButton5: TSpeedButton; SpeedButton7: TSpeedButton; SpeedButton8: TSpeedButton; SpeedButton9: TSpeedButton; SpeedButton10: TSpeedButton; SpeedButton11: TSpeedButton; SpeedButton12: TSpeedButton; SpeedButton13: TSpeedButton; SpeedButton14: TSpeedButton; Image1: TImage; ArchiveLabel: TLabel; Label1: TLabel; Label2: TLabel; FileComment1: TMenuItem; sbNone: TSpeedButton; sbAll: TSpeedButton; sbDef: TSpeedButton; Edit1: TEdit; Label3: TLabel; N5: TMenuItem; OS3: TMenuItem; OS4: TMenuItem; OS2: TMenuItem; OS1: TMenuItem; OS6: TMenuItem; OS5: TMenuItem; AbbreviaontheWeb1: TMenuItem; AbMeter1: TAbMeter; AbMeter2: TAbMeter; ShowEmptyfolders1: TMenuItem; TempDirectory1: TMenuItem; Logging1: TMenuItem; AbZipOutline1: TAbZipOutline; procedure AbZipOutline1Change(Sender: TObject); procedure AbZipOutline1ConfirmSave(Sender: TObject; var Confirm: Boolean); procedure AbZipOutline1DblClick(Sender: TObject); procedure AbZipOutline1DragDrop(Sender, Source: TObject; X, Y: Integer); procedure AbZipOutline1DragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); procedure AbZipOutline1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure AbZipOutline1WindowsDrop(Sender: TObject; FileName: string); procedure All1Click(Sender: TObject); procedure Best1Click(Sender: TObject); procedure Confirmations1Click(Sender: TObject); procedure CreateDirs1Click(Sender: TObject); procedure Exit1Click(Sender: TObject); procedure FileListBox1DragDrop(Sender, Source: TObject; X, Y: Integer); procedure FileListBox1DragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); procedure Font1Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure Hierarchy1Click(Sender: TObject); procedure None1Click(Sender: TObject); procedure Open1Click(Sender: TObject); procedure RestorePath1Click(Sender: TObject); procedure Save1Click(Sender: TObject); procedure StripPath1Click(Sender: TObject); procedure SuperFast1Click(Sender: TObject); procedure za10Click(Sender: TObject); procedure Delete1Click(Sender: TObject); procedure Extract1Click(Sender: TObject); procedure Freshen1Click(Sender: TObject); procedure Move1Click(Sender: TObject); procedure Password1Click(Sender: TObject); procedure AddFiles1Click(Sender: TObject); procedure FreshenFiles1Click(Sender: TObject); procedure SelectBaseDirectory1Click(Sender: TObject); procedure AbZipOutline1ArchiveItemProgress(Sender: TObject; Item: TAbArchiveItem; Progress: Byte; var Abort: Boolean); procedure AbZipOutline1NeedPassword(Sender: TObject; var NewPassword: AnsiString); procedure DeleteFiles1Click(Sender: TObject); procedure ExtractFiles1Click(Sender: TObject); procedure FormDestroy(Sender: TObject); procedure Close1Click(Sender: TObject); procedure AbZipOutline1Load(Sender: TObject); procedure Convert1Click(Sender: TObject); procedure AbZipOutline1ConfirmOverwrite(var Name: string; var Confirm: Boolean); procedure Default1Click(Sender: TObject); procedure Contents1Click(Sender: TObject); procedure About1Click(Sender: TObject); procedure FileListBox1DblClick(Sender: TObject); procedure AbZipOutline1EndDrag(Sender, Target: TObject; X, Y: Integer); procedure FileListBox1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure FileListBox1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure AbZipOutline1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure Edit1Exit(Sender: TObject); procedure FormKeyPress(Sender: TObject; var Key: Char); procedure OS5Click(Sender: TObject); procedure AbZipOutline1ConfirmProcessItem(Sender: TObject; Item: TAbArchiveItem; ProcessType: TAbProcessType; var Confirm: Boolean); procedure AbZipOutline1ProcessItemFailure(Sender: TObject; Item: TAbArchiveItem; const ProcessType: TAbProcessType; ErrorClass: TAbErrorClass; ErrorCode: Integer); procedure TurboPowerontheWeb1Click(Sender: TObject); procedure AbbreviaontheWeb1Click(Sender: TObject); procedure TempDirectory1Click(Sender: TObject); procedure Logging1Click(Sender: TObject); private { Private declarations } OutlineX, OutlineY, FileX, FileY : Integer; StubName : string; IgnoreDuplicateWarning : Boolean; procedure ReadIniSettings; procedure SaveIniSettings; procedure SetCaption; procedure UpdateMenu; procedure DoConfirm( Sender : TObject; Item : TAbArchiveItem; var Confirm : Boolean; Caption : string ); procedure GetMinMaxInfo( var Msg: TWMGetMinMaxInfo ); message WM_GETMINMAXINFO; public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} uses AbConst, AbDlgDir, AbDlgPwd, AbZBrows, AbZipTyp, dgAbout, IniFiles, Outline, ShellAPI, UBaseDlg, UDemoDlg, uSplash; procedure TForm1.All1Click(Sender: TObject); var i : Integer; begin for i := 0 to Ord( High( TAbZipAttribute ) ) do Attributes1.Items[i].Checked := True; AbZipOutline1.Attributes := [zaCompressedSize, zaCompressionMethod, zaCompressionRatio, zaCRC, zaExternalFileAttributes, zaInternalFileAttributes, zaEncryption, zaTimeStamp, zaUncompressedSize, zaVersionMade, zaVersionNeeded, zaComment]; AbZipOutline1.Update; end; procedure TForm1.Exit1Click(Sender: TObject); begin Close; end; procedure TForm1.FormCreate(Sender: TObject); begin ReadIniSettings; SetCaption; UpdateMenu; if ParamCount > 0 then try AbZipOutline1.FileName := ParamStr( 1 ); except end; end; procedure TForm1.Hierarchy1Click(Sender: TObject); begin Hierarchy1.Checked := not Hierarchy1.Checked; AbZipOutline1.Hierarchy := Hierarchy1.Checked; end; procedure TForm1.None1Click(Sender: TObject); var i : Integer; begin for i := 0 to pred( Attributes1.Count ) do Attributes1.Items[i].Checked := False; AbZipOutline1.Attributes := []; AbZipOutline1.Update; end; procedure TForm1.Save1Click(Sender: TObject); begin AbZipOutline1.Save; end; procedure TForm1.SetCaption; begin Caption := 'TPZip ' + AbZipOutline1.Version + ' - ' + AbZipOutline1.FileName; end; procedure TForm1.UpdateMenu; var i : TAbZipAttribute; begin with AbZipOutline1 do begin i := Low( TAbZipAttribute ); while i <> High( TAbZipAttribute ) do begin Attributes1.Items[Ord(i)].Checked := i in Attributes; i := succ( i ); end; Hierarchy1.Checked := Hierarchy; // OS1.Checked := Ord( OutlineStyle ) = 0; // OS2.Checked := Ord( OutlineStyle ) = 1; // OS3.Checked := Ord( OutlineStyle ) = 2; // OS4.Checked := Ord( OutlineStyle ) = 3; // OS5.Checked := Ord( OutlineStyle ) = 4; // OS6.Checked := Ord( OutlineStyle ) = 5; Best1.Checked := CompressionMethodToUse = smBestMethod; Deflate1.Checked := CompressionMethodToUse = smDeflated; Store1.Checked := CompressionMethodToUse = smStored; {deflation options} Normal1.Checked := DeflationOption = doNormal; Maximum1.Checked := DeflationOption = doMaximum; Fast1.Checked := DeflationOption = doFast; SuperFast1.Checked := DeflationOption = doSuperFast; {extractOptions} CreateDirs1.Checked := eoCreateDirs in ExtractOptions; RestorePath1.Checked := eoRestorePath in ExtractOptions; {StoreOptions} RecurseTree1.Checked := soRecurse in StoreOptions; StripPath1.Checked := soStripPath in StoreOptions; RemoveDots1.Checked := soRemoveDots in StoreOptions; end; end; procedure TForm1.za10Click(Sender: TObject); var Item : TMenuItem; begin Item := (Sender as TMenuItem); Item.Checked := not Item.Checked; with AbZipOutline1 do if Item.Checked then Attributes := Attributes + [TAbZipAttribute( Item.Tag )] else Attributes := Attributes - [TAbZipAttribute( Item.Tag )]; AbZipOutline1.Update; end; procedure TForm1.Font1Click(Sender: TObject); begin if FontDialog1.Execute then with FontDialog1 do begin AbZipOutline1.Font := Font; DirectoryListBox1.Font := Font; FileListBox1.Font := Font; DriveComboBox1.Font := Font; FilterComboBox1.Font := Font; end; end; procedure TForm1.Open1Click(Sender: TObject); begin if OpenDialog1.Execute then begin AbZipOutline1.FileName := OpenDialog1.FileName; end; end; procedure TForm1.AbZipOutline1DragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); begin Accept := Source is TFileListBox; end; procedure TForm1.AbZipOutline1DragDrop(Sender, Source: TObject; X, Y: Integer); var i, j : Integer; ZB : TAbZipBrowser; IsZip : Boolean; ZipName : string; begin if Source is TFileListBox then with (Source as TFileListBox ) do if SelCount = 1 then begin for i := 0 to pred( Items.Count ) do if FileListBox1.Selected[i] then begin IsZip := False; ZB := TAbZipBrowser.Create( Self ); try try ZB.FileName := Directory + '\' + Items[i]; IsZip := True; except end; finally ZB.Free; end; if IsZip then {only one file, and it is a zip file} AbZipOutline1.FileName := Directory + '\' + Items[i] else if AbZipOutline1.FileName <> '' then {only one file, and it's not a zip file} AbZipOutline1.AddFiles( Directory + '\' + Items[i], 0 ) else begin if OpenDialog1.Execute then begin AbZipOutline1.FileName := OpenDialog1.FileName; AbZipOutline1.AddFiles( Directory + '\' + Items[i], 0 ); end; end; break; end; end else begin {multiple files dropped...} IsZip := False; ZB := TAbZipBrowser.Create( Self ); try for i := 0 to pred( Items.Count ) do if FileListBox1.Selected[i] then begin try ZB.FileName := Directory + '\' + Items[i]; IsZip := True; ZipName := ZB.FileName; break; except end; end; finally ZB.Free; end; if IsZip and ( Application.MessageBox( 'One of the dropped files is a Zip Archive. Open it?', 'Open or Add Files?', MB_YESNO ) = IDYES ) then AbZipOutline1.FileName := ZipName else begin if AbZipOutline1.FileName <> '' then begin for i := 0 to pred( Items.Count ) do if FileListBox1.Selected[i] then AbZipOutline1.AddFiles( Directory + '\' + Items[i], 0 ); end else begin if OpenDialog1.Execute then begin AbZipOutline1.FileName := OpenDialog1.FileName; for j := 0 to pred( Items.Count ) do if FileListBox1.Selected[j] then AbZipOutline1.AddFiles( Directory + '\' + Items[j], 0 ) end; end; end; end; end; procedure TForm1.AbZipOutline1DblClick(Sender: TObject); var Restoring : Boolean; zFileName : array[0..79] of Char; TempDir, SaveDir : string; TempPath : array [0..255] of Char; TempName : string; begin GetTempPath( sizeof( TempPath ), TempPath ); SaveDir := StrPas( TempPath ); if SaveDir[Length(SaveDir)] = '\' then Delete( SaveDir, Length(SaveDir), 1 ); StrPCopy( TempPath, SaveDir ); with AbZipOutline1 do begin if SelectedZipItem <> nil then begin TempDir := BaseDirectory; Restoring := eoRestorePath in ExtractOptions; ExtractOptions := ExtractOptions - [eoRestorePath]; BaseDirectory := SaveDir; try ExtractFiles( SelectedZipItem.FileName ); TempName := SelectedZipItem.FileName; AbUnfixName( TempName ); ShellExecute( Application.MainForm.Handle, nil, StrPCopy( zFileName, ExtractFileName( TempName ) ), '', TempPath, SW_SHOWNORMAL ); finally BaseDirectory := TempDir; if Restoring then ExtractOptions := ExtractOptions + [eoRestorePath]; end; end; end; end; procedure TForm1.AbZipOutline1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var i : Integer; PS, PC : TPoint; begin if Button = mbLeft then begin OutlineX := X; OutlineY := Y; end else if Button = mbRight then begin {enable appropriate popup menu items.} {prepare popup menu} if AbZipOutline1.Count > 0 then begin {there are items in the outline - select the item under the mouse} i := AbZipOutline1.GetOutlineItem( X, Y ); if i <> -1 then AbZipOutline1.SelectedItem := i; end; if AbZipOutline1.SelectedZipItem <> nil then begin PC.X := X; PC.Y := Y; PS := AbZipOutline1.ClientToScreen( PC ); AbZipOutline1.PopupMenu.Popup( PS.X, PS.Y ); end; end; end; procedure TForm1.FileListBox1DragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); begin Accept := Source is TAbZipOutline; end; procedure TForm1.FileListBox1DragDrop(Sender, Source: TObject; X, Y: Integer); var TempDir : string; begin if Source is TAbZipOutline then with (Source as TAbZipOutline ) do begin TempDir := BaseDirectory; BaseDirectory := FileListBox1.Directory; try ExtractFiles( SelectedZipItem.FileName ); FileListBox1.Update; finally BaseDirectory := TempDir; end; end; end; procedure TForm1.AbZipOutline1WindowsDrop(Sender: TObject; FileName: string); var ZB : TAbZipBrowser; IsZip : Boolean; begin IsZip := False; ZB := TAbZipBrowser.Create( Self ); try try ZB.FileName := FileName; IsZip := True; except end; finally ZB.Free; end; if IsZip and ( AbZipOutline1.FileName = '' ) then AbZipOutline1.FileName := FileName else if AbZipOutline1.FileName = '' then begin if OpenDialog1.Execute then begin AbZipOutline1.FileName := OpenDialog1.FileName; AbZipOutline1.AddFiles( FileName, 0 ); end; end else begin {This is a Zip file, but there's already an open archive} if Application.MessageBox( 'Open this file as an archive?', 'Open or Add File', MB_YESNO ) = IDYES then AbZipOutline1.FileName := FileName else AbZipOutline1.AddFiles( FileName, 0 ); end; end; procedure TForm1.Best1Click(Sender: TObject); var Item : TMenuItem; begin Store1.Checked := False; Deflate1.Checked := False; Best1.Checked := False; Item := (Sender as TMenuItem); Item.Checked := True; AbZipOutline1.CompressionMethodToUse := TAbZipSupportedMethod( Item.Tag ); end; procedure TForm1.SuperFast1Click(Sender: TObject); var Item : TMenuItem; begin Normal1.Checked := False; Maximum1.Checked := False; Fast1.Checked := False; SuperFast1.Checked := False; Item := (Sender as TMenuItem); Item.Checked := True; AbZipOutline1.DeflationOption := TAbZipDeflationOption( Item.Tag ); end; procedure TForm1.CreateDirs1Click(Sender: TObject); var Item : TMenuItem; begin Item := Sender as TMenuItem; Item.Checked := not Item.Checked; if Item.Checked then AbZipOutline1.ExtractOptions := AbZipOutline1.ExtractOptions + [eoCreateDirs] else AbZipOutline1.ExtractOptions := AbZipOutline1.ExtractOptions - [eoCreateDirs]; end; procedure TForm1.RestorePath1Click(Sender: TObject); var Item : TMenuItem; begin Item := Sender as TMenuItem; Item.Checked := not Item.Checked; if Item.Checked then AbZipOutline1.ExtractOptions := AbZipOutline1.ExtractOptions + [eoRestorePath] else AbZipOutline1.ExtractOptions := AbZipOutline1.ExtractOptions - [eoRestorePath]; end; procedure TForm1.StripPath1Click(Sender: TObject); var Item : TMenuItem; begin Item := Sender as TMenuItem; Item.Checked := not Item.Checked; if Item.Checked then AbZipOutline1.StoreOptions := AbZipOutline1.StoreOptions + [TAbStoreOption(Item.Tag)] else AbZipOutline1.StoreOptions := AbZipOutline1.StoreOptions - [TAbStoreOption(Item.Tag)]; end; procedure TForm1.AbZipOutline1Change(Sender: TObject); begin if AbZipOutline1.FileName <> '' then ArchiveLabel.Caption := Format( 'Archive %s contains %d items.', [AbZipOutline1.FileName, AbZipOutline1.Count] ) else ArchiveLabel.Caption := 'No Archive Open'; end; procedure TForm1.Confirmations1Click(Sender: TObject); begin Confirmations1.Checked := not Confirmations1.Checked; SpeedButton7.Down := Confirmations1.Checked; end; procedure TForm1.DoConfirm( Sender : TObject; Item : TAbArchiveItem; var Confirm : Boolean; Caption : string ); var pMessage : array [0..255] of Char; pCaption : array [0..80] of Char; begin if Confirmations1.Checked then Confirm := MessageBox( 0, StrPCopy( pMessage, Format( '%s %s?', [Caption, Item.FileName] ) ), StrPCopy( pCaption, 'Confirmation' ), MB_ICONQUESTION or MB_OKCANCEL ) = IDOK; end; procedure TForm1.AbZipOutline1ConfirmSave(Sender: TObject; var Confirm: Boolean); var pMessage : array [0..255] of Char; pCaption : array [0..80] of Char; begin if Confirmations1.Checked then Confirm := MessageBox( 0, StrPCopy( pMessage, Format( 'Save %s?', [TAbZipOutline(Sender).FileName] ) ), StrPCopy( pCaption, 'Confirmation' ), MB_ICONQUESTION or MB_OKCANCEL ) = IDOK; end; procedure TForm1.Delete1Click(Sender: TObject); begin if AbZipOutline1.SelectedZipItem <> nil then with AbZipOutline1 do begin AbZipOutline1.ClearTags; SelectedZipItem.Tagged := True; try DeleteTaggedItems; finally ClearTags; end; end; end; procedure TForm1.Extract1Click(Sender: TObject); begin if AbZipOutline1.SelectedZipItem <> nil then begin BaseDirDlg := TBaseDirDlg.Create( Application ); try with BaseDirDlg, AbZipOutline1 do begin Caption := 'Extract Selected File'; Edit1.Text := SelectedZipItem.FileName; Edit1.Enabled := False; ActionLabel.Caption := 'Target Directory:'; if BaseDirectory <> '' then DLB.Directory := BaseDirectory; CheckBox1.Caption := 'Restore Path'; CheckBox1.Checked := eoRestorePath in ExtractOptions; CheckBox2.Caption := 'Create Directories'; CheckBox2.Checked := eoCreateDirs in ExtractOptions; ShowModal; if ModalResult = mrOK then begin BaseDirectory := DirLabel.Caption; if CheckBox1.Checked then ExtractOptions := ExtractOptions + [eoRestorePath] else ExtractOptions := ExtractOptions - [eoRestorePath]; if CheckBox2.Checked then ExtractOptions := ExtractOptions + [eoCreateDirs] else ExtractOptions := ExtractOptions - [eoCreateDirs]; ClearTags; SelectedZipItem.Tagged := True; try ExtractTaggedItems; finally ClearTags; end; FileListBox1.Update; end; end; finally BaseDirDlg.Free; end; end; end; procedure TForm1.Freshen1Click(Sender: TObject); begin if AbZipOutline1.SelectedZipItem <> nil then begin BaseDirDlg := TBaseDirDlg.Create( Application ); try with BaseDirDlg, AbZipOutline1 do begin Caption := 'Freshen Selected File'; Edit1.Text := SelectedZipItem.FileName; Edit1.Enabled := False; ActionLabel.Caption := 'Source Directory:'; if BaseDirectory <> '' then DLB.Directory := BaseDirectory; CheckBox1.Caption := 'Recurse'; CheckBox1.Checked := soRecurse in StoreOptions; CheckBox2.Caption := 'Strip Path'; CheckBox2.Checked := soStripPath in StoreOptions; ShowModal; if ModalResult = mrOK then begin if CheckBox1.Checked then StoreOptions := StoreOptions + [soRecurse] else StoreOptions := StoreOptions - [soRecurse]; if CheckBox2.Checked then StoreOptions := StoreOptions + [soStripPath] else StoreOptions := StoreOptions - [soStripPath]; BaseDirectory := DirLabel.Caption; ClearTags; SelectedZipItem.Tagged := True; try FreshenTaggedItems; finally ClearTags; end; FileListBox1.Update; end; end; finally BaseDirDlg.Free; end; end; end; procedure TForm1.Move1Click(Sender: TObject); begin DemoDlg := TDemoDlg.Create( Application ); try with DemoDlg do begin Caption := 'Move File to New Path'; Edit1.Text := AbZipOutline1.SelectedZipItem.FileName; ShowModal; if ModalResult = mrOK then AbZipOutline1.Move( AbZipOutline1.SelectedZipItem, Edit1.Text ); end; finally DemoDlg.Free; end; end; procedure TForm1.Password1Click(Sender: TObject); var Dlg : TPassWordDlg; begin Dlg := TPassWordDlg.Create( Application ); try Dlg.Edit1.Text := string(AbZipOutline1.Password); Dlg.ShowModal; if Dlg.ModalResult = mrOK then AbZipOutline1.Password := AnsiString(Dlg.Edit1.Text); finally Dlg.Free; end; if Length( AbZipOutline1.Password ) > 0 then Image1.Visible := True else Image1.Visible := False; end; procedure TForm1.AddFiles1Click(Sender: TObject); begin BaseDirDlg := TBaseDirDlg.Create( Application ); try with BaseDirDlg, AbZipOutline1 do begin Caption := 'Add Files with FileMask'; Edit1.Text := '*.*'; ActionLabel.Caption := 'Source Directory'; CheckBox1.Caption := 'Recurse'; CheckBox1.Checked := soRecurse in StoreOptions; CheckBox2.Caption := 'Strip Path'; CheckBox2.Checked := soStripPath in StoreOptions; if BaseDirectory <> '' then DLB.Directory := BaseDirectory; ShowModal; if ModalResult = mrOK then begin if CheckBox1.Checked then StoreOptions := StoreOptions + [soRecurse] else StoreOptions := StoreOptions - [soRecurse]; if CheckBox2.Checked then StoreOptions := StoreOptions + [soStripPath] else StoreOptions := StoreOptions - [soStripPath]; BaseDirectory := DirLabel.Caption; AddFiles( Edit1.Text, 0 ); end; end; finally BaseDirDlg.Free; end; end; procedure TForm1.FreshenFiles1Click(Sender: TObject); begin BaseDirDlg := TBaseDirDlg.Create( Application ); try with BaseDirDlg, AbZipOutline1 do begin Caption := 'Freshen Files with FileMask'; Edit1.Text := '*.*'; ActionLabel.Caption := 'Source Directory'; CheckBox1.Caption := 'Recurse'; CheckBox1.Checked := soRecurse in StoreOptions; CheckBox2.Caption := 'Strip Path'; CheckBox2.Checked := soStripPath in StoreOptions; if BaseDirectory <> '' then DLB.Directory := BaseDirectory; ShowModal; if ModalResult = mrOK then begin if CheckBox1.Checked then StoreOptions := StoreOptions + [soRecurse] else StoreOptions := StoreOptions - [soRecurse]; if CheckBox2.Checked then StoreOptions := StoreOptions + [soStripPath] else StoreOptions := StoreOptions - [soStripPath]; BaseDirectory := DirLabel.Caption; FreshenFiles( Edit1.Text ); end; end; finally BaseDirDlg.Free; end; end; procedure TForm1.SelectBaseDirectory1Click(Sender: TObject); begin with TAbDirDlg.Create(Self) do begin Caption := 'Directory'; AdditionalText := 'Select folder to extract into'; if Execute then AbZipOutline1.BaseDirectory := SelectedFolder; Free; end; end; procedure TForm1.AbZipOutline1ArchiveItemProgress(Sender: TObject; Item: TAbArchiveItem; Progress: Byte; var Abort: Boolean); var ActionString : string; begin case Item.Action of aaAdd : ActionString := 'Adding '; aaFreshen : ActionString := 'Freshening '; else ActionString :='Extracting '; end; Panel5.Caption := ActionString + Item.FileName + ' '; if Progress = 100 then begin Panel5.Caption := 'Finished '; end; end; procedure TForm1.AbZipOutline1NeedPassword(Sender: TObject; var NewPassword: AnsiString); var Dlg : TPassWordDlg; begin Dlg := TPassWordDlg.Create( Application ); try Dlg.ShowModal; if Dlg.ModalResult = mrOK then NewPassword := AnsiString(Dlg.Edit1.Text); finally Dlg.Free; end; if Length( NewPassword ) > 0 then Image1.Visible := True; end; procedure TForm1.DeleteFiles1Click(Sender: TObject); begin DemoDlg := TDemoDlg.Create( Application ); try with DemoDlg do begin Caption := 'Delete Files with FileMask'; Edit1.Text := '*.*'; ShowModal; if ModalResult = mrOK then AbZipOutline1.DeleteFiles( Edit1.Text ); end; finally DemoDlg.Free; end; end; procedure TForm1.ExtractFiles1Click(Sender: TObject); begin BaseDirDlg := TBaseDirDlg.Create( Application ); try with BaseDirDlg, AbZipOutline1 do begin Caption := 'Extract Files with FileMask'; Edit1.Text := '*.*'; ActionLabel.Caption := 'Target Directory:'; if BaseDirectory <> '' then DLB.Directory := BaseDirectory; CheckBox1.Caption := 'Restore Path'; CheckBox1.Checked := eoRestorePath in ExtractOptions; CheckBox2.Caption := 'Create Directories'; CheckBox2.Checked := eoCreateDirs in ExtractOptions; ShowModal; if ModalResult = mrOK then begin BaseDirectory := BaseDirDlg.DLB.Directory; if CheckBox1.Checked then ExtractOptions := ExtractOptions + [eoRestorePath] else ExtractOptions := ExtractOptions - [eoRestorePath]; if CheckBox2.Checked then ExtractOptions := ExtractOptions + [eoCreateDirs] else ExtractOptions := ExtractOptions - [eoCreateDirs]; ExtractFiles( Edit1.Text ); FileListBox1.Update; end; end; finally BaseDirDlg.Free; end; end; procedure TForm1.FormDestroy(Sender: TObject); begin AbZipOutline1.Save; SaveIniSettings; end; procedure TForm1.ReadIniSettings; var Value : Integer; Exists : Boolean; begin with TIniFile.Create( ChangeFileExt( Application.ExeName, '.INI' ) ) do begin try {view menu} Exists := ReadBool( 'General', 'Exists', False ); if Exists then begin AbZipOutline1.Attributes := []; if ReadBool( 'View', 'CSize', False ) then AbZipOutline1.Attributes := AbZipOutline1.Attributes + [zaCompressedSize]; if ReadBool( 'View', 'CMethod', False ) then AbZipOutline1.Attributes := AbZipOutline1.Attributes + [zaCompressionMethod]; if ReadBool( 'View', 'CRatio', False ) then AbZipOutline1.Attributes := AbZipOutline1.Attributes + [zaCompressionRatio]; if ReadBool( 'View', 'CRC', False ) then AbZipOutline1.Attributes := AbZipOutline1.Attributes + [zaCRC]; if ReadBool( 'View', 'EFA', False ) then AbZipOutline1.Attributes := AbZipOutline1.Attributes + [zaExternalFileAttributes]; if ReadBool( 'View', 'IFA', False ) then AbZipOutline1.Attributes := AbZipOutline1.Attributes + [zaInternalFileAttributes]; if ReadBool( 'View', 'Encryption', False ) then AbZipOutline1.Attributes := AbZipOutline1.Attributes + [zaEncryption]; if ReadBool( 'View', 'TimeStamp', False ) then AbZipOutline1.Attributes := AbZipOutline1.Attributes + [zaTimeStamp]; if ReadBool( 'View', 'USize', False ) then AbZipOutline1.Attributes := AbZipOutline1.Attributes + [zaUnCompressedSize]; if ReadBool( 'View', 'MadeBy', False ) then AbZipOutline1.Attributes := AbZipOutline1.Attributes + [zaVersionMade]; if ReadBool( 'View', 'Needed', False ) then AbZipOutline1.Attributes := AbZipOutline1.Attributes + [zaVersionNeeded]; if ReadBool( 'View', 'Comment', False ) then AbZipOutline1.Attributes := AbZipOutline1.Attributes + [zaComment]; AbZipOutline1.Hierarchy := ReadBool( 'View', 'Hierarchy', True ); // Value := ReadInteger( 'View', 'OutlineStyle', -1 ); // if Value <> -1 then // AbZipOutline1.OutlineStyle := TOutlineStyle( Value ); {preferences menu} AbZipOutline1.BaseDirectory := ReadString( 'Preferences', 'BaseDirectory', ExtractFilePath( Application.ExeName ) ); if not DirectoryExists( AbZipOutline1.BaseDirectory ) then AbZipOutline1.BaseDirectory := ExtractFilePath( Application.ExeName ); Confirmations1.Checked := ReadBool( 'Preferences', 'Confirmations', False ); SpeedButton7.Down := Confirmations1.Checked; Value := ReadInteger( 'Preferences', 'CompressionMethodToUse', Ord( smBestMethod ) ); AbZipOutline1.CompressionMethodToUse := TAbZipSupportedMethod( Value ); Value := ReadInteger( 'Preferences', 'DeflationOption', Ord( doNormal)); AbZipOutline1.DeflationOption := TAbZipDeflationOption( Value ); AbZipOutline1.ExtractOptions := []; if ReadBool( 'Preferences', 'CreateDirs', False ) then AbZipOutline1.ExtractOptions := AbZipOutline1.ExtractOptions + [eoCreateDirs]; if ReadBool( 'Preferences', 'RestorePath', False ) then AbZipOutline1.ExtractOptions := AbZipOutline1.ExtractOptions + [eoRestorePath]; AbZipOutline1.StoreOptions := []; if ReadBool( 'Preferences', 'StripPath', False ) then AbZipOutline1.StoreOptions := AbZipOutline1.StoreOptions + [soStripPath]; if ReadBool( 'Preferences', 'RemoveDots', False ) then AbZipOutline1.StoreOptions := AbZipOutline1.StoreOptions + [soRemoveDots]; if ReadBool( 'Preferences', 'Recurse', False ) then AbZipOutline1.StoreOptions := AbZipOutline1.StoreOptions + [soRecurse]; StubName := ReadString( 'Self Extracting', 'StubName', 'selfex.exe' ); FilterComboBox1.Filter := ReadString( 'Navigator', 'Filter', 'All files (*.*)|*.*|Zip Files (*.ZIP)|*.ZIP|' + 'Executable Files (*.EXE)|*.EXE|Text files (*.TXT)|*.TXT|' + 'Pascal files (*.PAS)|*.PAS' ); end; finally Free; end; end; end; procedure TForm1.SaveIniSettings; begin with TIniFile.Create( ChangeFileExt( Application.ExeName, '.INI' ) ) do begin try {view menu} WriteBool( 'General', 'Exists', True ); with AbZipOutline1 do begin WriteBool( 'View', 'CSize', zaCompressedSize in Attributes ); WriteBool( 'View', 'CMethod', zaCompressionMethod in Attributes ); WriteBool( 'View', 'CRatio', zaCompressionRatio in Attributes ); WriteBool( 'View', 'CRC', zaCRC in Attributes ); WriteBool( 'View', 'EFA', zaExternalFileAttributes in Attributes ); WriteBool( 'View', 'IFA', zaInternalFileAttributes in Attributes ); WriteBool( 'View', 'Encryption', zaEncryption in Attributes ); WriteBool( 'View', 'TimeStamp', zaTimeStamp in Attributes ); WriteBool( 'View', 'USize', zaUnCompressedSize in Attributes ); WriteBool( 'View', 'MadeBy', zaVersionMade in Attributes ); WriteBool( 'View', 'Needed', zaVersionNeeded in Attributes ); WriteBool( 'View', 'Comment', zaComment in Attributes ); WriteBool( 'View', 'Hierarchy', Hierarchy ); // WriteInteger( 'View', 'OutlineStyle', Ord( OutlineStyle ) ); {preferences menu} WriteString( 'Preferences', 'BaseDirectory', BaseDirectory ); WriteBool( 'Preferences', 'Confirmations', Confirmations1.Checked ); WriteInteger( 'Preferences', 'CompressionMethodToUse', Ord( CompressionMethodToUse ) ); WriteInteger( 'Preferences', 'DeflationOption', Ord( DeflationOption )); WriteBool( 'Preferences', 'CreateDirs', eoCreateDirs in ExtractOptions ); WriteBool( 'Preferences', 'RestorePath', eoRestorePath in ExtractOptions ); WriteBool( 'Preferences', 'StripPath', soStripPath in StoreOptions ); WriteBool( 'Preferences', 'RemoveDots', soRemoveDots in StoreOptions ); WriteBool( 'Preferences', 'Recurse', soRecurse in StoreOptions ); end; finally Free; end; end; end; procedure TForm1.Close1Click(Sender: TObject); begin AbZipOutline1.FileName := ''; AbZipOutline1.Color := clBtnFace; end; procedure TForm1.AbZipOutline1Load(Sender: TObject); begin IgnoreDuplicateWarning := False; AbZipOutline1.Color := clWindow; SetCaption; end; procedure TForm1.Convert1Click(Sender: TObject); var ZipName : string; ExeName : string; StubSpec : string; StubStream, ZipStream, SelfExtractingStream : TStream; begin AbZipOutline1.Save; ZipName := ExpandFileName( AbZipOutline1.FileName ); AbZipOutline1.FileName := ''; ExeName := ChangeFileExt( ZipName, '.exe' ); StubSpec := ExtractFilePath( Application.ExeName ) + StubName; StubStream := TFileStream.Create( StubSpec, fmOpenRead or fmShareDenyWrite ); ZipStream := TFileStream.Create( ZipName , fmOpenRead or fmShareDenyWrite ); SelfExtractingStream := TFileStream.Create( ExeName, fmCreate or fmShareExclusive ); try MakeSelfExtracting( StubStream, ZipStream, SelfExtractingStream ); finally SelfExtractingStream.Free; StubStream.Free; ZipStream.Free; end; {and reload...} AbZipOutline1.FileName := ExeName; end; procedure TForm1.GetMinMaxInfo( var Msg: TWMGetMinMaxInfo ); begin with Msg.MinMaxInfo^ do begin ptMinTrackSize := Point( 700, 400 ); ptMaxTrackSize := Point( 1600, 1200 ); end; end; procedure TForm1.AbZipOutline1ConfirmOverwrite(var Name: string; var Confirm: Boolean); var pMessage : array [0..255] of Char; pCaption : array [0..80] of Char; begin Confirm := MessageBox( 0, StrPCopy( pMessage, Format( 'Overwrite %s?', [Name] ) ), StrPCopy( pCaption, 'Confirmation' ), MB_ICONQUESTION or MB_OKCANCEL ) = IDOK; end; procedure TForm1.Default1Click(Sender: TObject); var i : Integer; begin AbZipOutline1.Attributes := AbDefZipAttributes; for i := 0 to Ord( High( TAbZipAttribute ) ) do Attributes1.Items[i].Checked := TAbZipAttribute(i) in AbDefZipAttributes; AbZipOutline1.Update; end; procedure TForm1.Contents1Click(Sender: TObject); begin Application.HelpCommand(HELP_CONTENTS, 0); end; procedure TForm1.About1Click(Sender: TObject); begin dlgAboutBox := TDlgAboutBox.Create( Self ); try dlgAboutBox.ShowModal; finally dlgAboutBox.Free; end; end; procedure TForm1.FileListBox1DblClick(Sender: TObject); var Browser : TAbZipBrowser; Filename : string; OK : Boolean; begin Filename := IncludeTrailingPathDelimiter(DirectoryListBox1.Directory) + FileListBox1.Items[FileListBox1.ItemIndex]; if AbZipOutline1.FileName = '' then try AbZipOutline1.FileName := Filename; except AbZipOutline1.FileName := ''; end else begin Browser := TAbZipBrowser.Create( Self ); OK := True; try try Browser.FileName := Filename; except OK := False; end; finally Browser.Free; end; if OK then AbZipOutline1.FileName := Filename; end; end; procedure TForm1.AbZipOutline1EndDrag(Sender, Target: TObject; X, Y: Integer); begin FileListBox1.Update; end; procedure TForm1.FileListBox1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if Button = mbLeft then begin FileX := X; FileY := Y; end; end; procedure TForm1.FileListBox1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); begin if ssLeft in Shift then if ( ( X - FileX ) * ( X - FileX ) + ( Y - FileY ) * ( Y - FileY ) > 100 ) then if FileListBox1.SelCount > 0 then if ( not FileListBox1.Dragging ) then FileListBox1.BeginDrag( True ); end; procedure TForm1.AbZipOutline1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); begin if ssLeft in Shift then if ( ( X - OutlineX ) * ( X - OutlineX ) + ( Y - OutlineY ) * ( Y - OutlineY ) > 100 ) then if AbZipOutline1.SelectedZipItem <> nil then if ( not FileListBox1.Dragging ) then AbZipOutline1.BeginDrag( True ); end; procedure TForm1.Edit1Exit(Sender: TObject); begin FileListBox1.ApplyFilePath(Edit1.Text); end; procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char); begin if Key = #13 then Edit1Exit( Self ); end; procedure TForm1.OS5Click(Sender: TObject); var Item : TMenuItem; begin OS1.Checked := False; OS2.Checked := False; OS3.Checked := False; OS4.Checked := False; OS5.Checked := False; OS6.Checked := False; Item := (Sender as TMenuItem); Item.Checked := True; // AbZipOutline1.OutlineStyle := TOutlineStyle( Item.Tag ); end; procedure TForm1.AbZipOutline1ConfirmProcessItem(Sender: TObject; Item: TAbArchiveItem; ProcessType: TAbProcessType; var Confirm: Boolean); var Process : string; begin Confirm := True; case ProcessType of ptAdd : Process := 'Add'; ptDelete : Process := 'Delete'; ptExtract : Process := 'Extract'; ptFreshen : Process := 'Freshen'; ptMove : Process := 'Move'; end; DoConfirm( Sender, Item, Confirm, Process ); end; procedure TForm1.AbZipOutline1ProcessItemFailure(Sender: TObject; Item: TAbArchiveItem; const ProcessType: TAbProcessType; ErrorClass: TAbErrorClass; ErrorCode: Integer); var S : string; pMessage : array [0..128] of Char; begin if ( ErrorClass = ecAbbrevia ) and ( ErrorCode = AbDuplicateName ) then begin if not IgnoreDuplicateWarning then begin if ProcessType = ptAdd then s := 'Cannot add ' else s := 'Cannot move '; s := s + Item.FileName + '. Would create a duplicate name. Ignore future warnings?'; if (Application.MessageBox( StrPCopy( pMessage, s ), 'Warning', MB_YESNO ) = IDYES ) then IgnoreDuplicateWarning := True; end; Exit; end; case ProcessType of ptAdd : ShowMessage( 'Cannot add ' + Item.FileName + ' to ' + TAbZipOutline(Sender).FileName ); ptExtract : ShowMessage( 'Cannot extract ' + Item.FileName + ' from ' + TAbZipOutline(Sender).FileName ); ptFreshen : ShowMessage( 'Cannot freshen ' + Item.FileName + ' in ' + TAbZipOutline(Sender).FileName ); ptMove : ShowMessage( 'Cannot move ' + Item.FileName + ' to ' + TAbZipOutline(Sender).FileName ); end; if ErrorClass = ecAbbrevia then ShowMessage( AbStrRes(ErrorCode) ); end; procedure TForm1.TurboPowerontheWeb1Click(Sender: TObject); begin if ShellExecute(0, 'open', 'http://www.turbopower.com', '', '', SW_SHOWNORMAL) <= 32 then ShowMessage('Unable to start web browser. Make sure you have it properly set-up on your system.'); end; procedure TForm1.AbbreviaontheWeb1Click(Sender: TObject); begin if ShellExecute(0, 'open', 'http://sf.net/projects/tpabbrevia', '', '', SW_SHOWNORMAL) <= 32 then ShowMessage('Unable to start web browser. Make sure you have it properly set-up on your system.'); end; procedure TForm1.TempDirectory1Click(Sender: TObject); begin with TAbDirDlg.Create(Self) do begin Caption := 'Directory'; AdditionalText := 'Select temporary directory'; if Execute then AbZipOutline1.TempDirectory := SelectedFolder; Free; end; end; procedure TForm1.Logging1Click(Sender: TObject); var E, F : string; begin AbZipOutline1.Logging := False; Logging1.Checked := not Logging1.Checked; if Logging1.Checked then with OpenDialog1 do begin Title := 'Select Text File for Logging'; E := DefaultExt; DefaultExt := ''; F := Filter; Filter := ''; Filename := AbZipOutline1.LogFile; if Execute then begin AbZipOutline1.LogFile := Filename; AbZipOutline1.Logging := True; end; DefaultExt := E; Filter := F; end; Logging1.Checked := AbZipOutline1.Logging; end; end. ================================================ FILE: lib/abbrevia/examples/Delphi/Uexample.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: UEXAMPLE.PAS *} {* Copyright (c) TurboPower Software Co 1997 *} {* All rights reserved. *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} unit uexample; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Menus, ExtCtrls, Gauges, StdCtrls, AbZipOut, AbArcTyp, AbMeter, AbBase, AbUtils; type TForm1 = class(TForm) BottomStatus: TPanel; MainMenu1: TMainMenu; File1: TMenuItem; Open1: TMenuItem; N1: TMenuItem; Exit1: TMenuItem; OpenDialog1: TOpenDialog; TopStatus: TPanel; PopupMenu1: TPopupMenu; Add1: TMenuItem; Delete1: TMenuItem; Extract1: TMenuItem; Freshen1: TMenuItem; Move1: TMenuItem; Panel1: TPanel; Memo1: TMemo; AbMeter1: TAbMeter; AbMeter2: TAbMeter; Label1: TLabel; Label2: TLabel; AbZipOutline1: TAbZipOutline; procedure Open1Click(Sender: TObject); procedure Exit1Click(Sender: TObject); procedure AbZipOutline1Load(Sender: TObject); procedure AbZipOutline1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure Delete1Click(Sender: TObject); procedure Extract1Click(Sender: TObject); procedure Freshen1Click(Sender: TObject); procedure Add1Click(Sender: TObject); procedure Move1Click(Sender: TObject); procedure FormCreate(Sender: TObject); procedure AbZipOutline1ProcessItemFailure(Sender: TObject; Item: TAbArchiveItem; ProcessType: TAbProcessType; ErrorClass: TAbErrorClass; ErrorCode: Integer); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation uses udemodlg; {$R *.DFM} procedure TForm1.Open1Click(Sender: TObject); begin if OpenDialog1.Execute then begin AbZipOutline1.OpenArchive(OpenDialog1.FileName); end; end; procedure TForm1.Exit1Click(Sender: TObject); begin Close; end; procedure TForm1.AbZipOutline1Load(Sender: TObject); begin TopStatus.Caption := ' ' + AbZipOutline1.FileName; end; procedure TForm1.AbZipOutline1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var i : LongInt; begin if Button = mbRight then begin {prepare popup menu} if AbZipOutline1.Count > 0 then begin {there are items in the outline - select the item under the mouse} i := AbZipOutline1.GetOutlineItem( X, Y ); if i <> -1 then AbZipOutline1.SelectedItem := i; end; if AbZipOutline1.FileName <> '' then Add1.Enabled := True else {archive has to be initialized before we can add to it} Add1.Enabled := False; if AbZipOutline1.SelectedZipItem <> nil then begin {pointing at a file - allow file operations} Delete1.Enabled := True; Extract1.Enabled := True; Freshen1.Enabled := True; Move1.Enabled := True; end else begin {pointing at a directory - don't allow file operations} Delete1.Enabled := False; Extract1.Enabled := False; Freshen1.Enabled := False; Move1.Enabled := False; end; end; end; procedure TForm1.Delete1Click(Sender: TObject); begin AbZipOutline1.DeleteFiles(AbZipOutline1.SelectedZipItem.FileName); end; procedure TForm1.Extract1Click(Sender: TObject); begin AbZipOutline1.ExtractFiles(AbZipOutline1.SelectedZipItem.FileName); end; procedure TForm1.Freshen1Click(Sender: TObject); begin AbZipOutline1.FreshenFiles(AbZipOutline1.SelectedZipItem.FileName); end; procedure TForm1.Add1Click(Sender: TObject); begin DemoDlg.Caption := 'Add Files with FileMask'; DemoDlg.Edit1.Text := '*.*'; DemoDlg.ShowModal; if DemoDlg.ModalResult = mrOK then AbZipOutline1.AddFiles(DemoDlg.Edit1.Text, 0); end; procedure TForm1.Move1Click(Sender: TObject); begin DemoDlg.Caption := 'Move File to New Name'; DemoDlg.Edit1.Text := AbZipOutline1.SelectedZipItem.FileName; DemoDlg.ShowModal; if DemoDlg.ModalResult = mrOK then AbZipOutline1.Move(AbZipOutline1.SelectedZipItem, DemoDlg.Edit1.Text); end; procedure TForm1.FormCreate(Sender: TObject); begin AbZipOutline1.BaseDirectory := ExtractFilePath( Application.ExeName ); end; procedure TForm1.AbZipOutline1ProcessItemFailure(Sender: TObject; Item: TAbArchiveItem; ProcessType: TAbProcessType; ErrorClass: TAbErrorClass; ErrorCode: Integer); begin case ProcessType of ptAdd : ShowMessage( 'Failed to add ' + Item.Filename ); ptExtract : ShowMessage('Failed to extract ' + Item.Filename); ptFreshen : ShowMessage('Failed to freshen ' + Item.Filename); end; end; end. ================================================ FILE: lib/abbrevia/examples/Delphi/Unzip.dpr ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: UNZIP.DPR *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} program Unzip; uses Forms, Uunzip in 'Uunzip.pas' {Form1}; begin Application.CreateForm(TForm1, Form1); Application.Run; end. ================================================ FILE: lib/abbrevia/examples/Delphi/Unzip.dproj ================================================  {4193EA89-8316-4EA6-824B-CD35E8A098C8} Unzip.dpr True Debug Win32 Application VCL DCC32 12.3 true true Base true true Base true false 00400000 WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;$(DCC_UnitAlias) false false false false false RELEASE;$(DCC_Define) 0 false DEBUG;$(DCC_Define) false true MainSource
Form1
Cfg_2 Base Base Cfg_1 Base
Delphi.Personality.12 VCLApplication Unzip.dpr False False 1 0 0 0 False False False False False 1033 1252 1.0.0.0 1.0.0.0 True 12
================================================ FILE: lib/abbrevia/examples/Delphi/Unzip.dproj.2007 ================================================  {4193EA89-8316-4EA6-824B-CD35E8A098C8} Unzip.dpr True Debug Win32 Application VCL DCC32 true true Base true true Base true false false 00400000 false false false false RELEASE;$(DCC_Define) 0 false DEBUG;$(DCC_Define) false true MainSource
Form1
Cfg_2 Base Base Cfg_1 Base
Delphi.Personality.12 VCLApplication Unzip.dpr False False 1 0 0 0 False False False False False 1033 1252 1.0.0.0 1.0.0.0 True 12
================================================ FILE: lib/abbrevia/examples/Delphi/UsingApi.dpr ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: USINGAPI.DPR *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} {$APPTYPE CONSOLE} program UsingAPI; {Build this app using the Define "BuildingStub", to keep it smaller!} uses AbArcTyp, AbZipTyp, AbZipPrc, AbUnzPrc, Classes, SysUtils, AbUtils; type THelper = class public procedure UnzipProc( Sender : TObject; Item : TAbArchiveItem; const NewName : string ); procedure ZipProc( Sender : TObject; Item : TAbArchiveItem; OutStream : TStream ); procedure ArchiveItemProgress( Sender: TObject; Item: TAbArchiveItem; Progress: Byte; var Abort: Boolean); end; procedure THelper.ArchiveItemProgress( Sender: TObject; Item: TAbArchiveItem; Progress: Byte; var Abort: Boolean); type TMethodStrings = array [ cmStored..cmDCLImploded ] of string; const MethodStrings : TMethodStrings = ('UnStoring', 'UnShrinking', 'UnReducing', 'UnReducing', 'UnReducing', 'UnReducing', 'Exploding', 'DeTokenizing', 'Inflating', 'Enhanced Inflating', 'DCL Exploding'); var ActionString : string; CompMethod: TAbZipCompressionMethod; begin case Item.Action of aaAdd : ActionString := 'Adding '; aaFreshen : ActionString := 'Freshening '; else begin CompMethod := (Item as TAbZipItem).CompressionMethod; if CompMethod in [cmStored..cmDCLImploded] then ActionString := MethodStrings[(Item as TAbZipItem).CompressionMethod] + ' ' else ActionString := 'Decompressing '; end; end; WriteLn( ActionString + Item.FileName ); end; procedure THelper.UnzipProc( Sender : TObject; Item : TAbArchiveItem; const NewName : string ); begin AbUnzip( Sender, TAbZipItem(Item), NewName ); end; procedure THelper.ZipProc( Sender : TObject; Item : TAbArchiveItem; OutStream : TStream ); begin AbZip( TAbZipArchive(Sender), TAbZipItem(Item), OutStream ); end; var ZipFileName : string; OutDirectory : string; InDirectory : string; Mask : string; Archive : TAbZipArchive; Helper : THelper; begin WriteLn; {usage: UsingAPI ZipFileName InDirectory Mask OutDirectory} if (ParamCount < 4) or ((ParamCount > 0) and (Pos('?', ParamStr(1))>0)) then begin WriteLn; WriteLn( ' Syntax: UsingAPI ZipFileName InDirectory Mask OutDirectory'); Halt; end; ZipFileName := ParamStr(1); InDirectory := ParamStr(2); Mask := ParamStr(3); OutDirectory := ParamStr(4); {open the file} if FileExists( ZipFileName ) then begin Archive := TAbZipArchive.Create( ZipFileName, fmOpenReadWrite or fmShareDenyWrite ); Archive.Load; end else Archive := TAbZipArchive.Create( ZipFileName, fmCreate or fmShareDenyNone ); try Helper := THelper.Create; try {set the event handlers} Archive.InsertHelper := Helper.ZipProc; Archive.ExtractHelper := Helper.UnzipProc; Archive.OnArchiveItemProgress := Helper.ArchiveItemProgress; {set the BaseDirectory for input files} Archive.BaseDirectory := InDirectory; {add all the files in the BaseDirectory to the archive} Archive.AddFiles( Mask, 0 ); {save the files to the zipfile} Archive.Save; {now, change the base directory to the output} Archive.BaseDirectory := OutDirectory; Archive.ExtractFiles( Mask ); finally Helper.Free; end; finally Archive.Free; end; end. ================================================ FILE: lib/abbrevia/examples/Delphi/Ustrpad.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: USTRPAD.PAS *} {* Copyright (c) TurboPower Software Co 1997 *} {* All rights reserved. *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} unit Ustrpad; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls; type TForm1 = class(TForm) Memo1: TMemo; Panel1: TPanel; Memo2: TMemo; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private { Private declarations } ZnfName : string; TxtName : string; ZnfStream : TFileStream; TxtStream : TStream; public { Public declarations } end; var Form1: TForm1; implementation uses AbUnzPrc, AbZipPrc; {$R *.DFM} procedure TForm1.FormCreate(Sender: TObject); begin ZnfName := ChangeFileExt(Application.ExeName, '.zst'); TxtName := ExtractFileName( ChangeFileExt(Application.ExeName, '.pad') ); ChDir( ExtractFilePath( Application.ExeName ) ); if FileExists( ZnfName ) then begin TxtStream := TMemoryStream.Create; try ZnfStream := TFileStream.Create( ZnfName, fmOpenRead or fmShareExclusive ); try InflateStream( ZnfStream, TxtStream ); finally ZnfStream.Free; end; TxtStream.Position := 0; Memo1.Lines.LoadFromStream( TxtStream ); finally TxtStream.Free; end; end; end; procedure TForm1.FormDestroy(Sender: TObject); begin TxtStream := TMemoryStream.Create; try Memo1.Lines.SaveToStream( TxtStream ); TxtStream.Position := 0; if FileExists( ZnfName ) then ZnfStream := TFileStream.Create( ZnfName, fmOpenWrite or fmShareExclusive ) else ZnfStream := TFileStream.Create( ZnfName, fmCreate or fmShareExclusive ); try DeflateStream( TxtStream, ZnfStream ); finally ZnfStream.Free; end; finally TxtStream.Free; end; end; end. ================================================ FILE: lib/abbrevia/examples/Delphi/Uunzip.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: UUNZIP.PAS *} {* Copyright (c) TurboPower Software Co 1997 *} {* All rights reserved. *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} unit Uunzip; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, AbZBrows, AbUnZper, AbArcTyp, AbMeter, AbBrowse, AbBase; type TForm1 = class(TForm) Button1: TButton; OpenDialog1: TOpenDialog; AbUnZipper1: TAbUnZipper; Memo1: TMemo; AbMeter1: TAbMeter; AbMeter2: TAbMeter; Label1: TLabel; Label2: TLabel; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} procedure TForm1.Button1Click(Sender: TObject); begin if OpenDialog1.Execute then begin with AbUnzipper1 do begin FileName := OpenDialog1.FileName; BaseDirectory := ExtractFilePath( FileName ); ExtractFiles( '*.*' ); end; end; end; end. ================================================ FILE: lib/abbrevia/examples/Delphi/Uzip.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: UZIP.PAS *} {* Copyright (c) TurboPower Software Co 1997 *} {* All rights reserved. *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} unit Uzip; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Gauges, AbZipper, AbArcTyp, AbZBrows, AbMeter, AbBrowse, AbBase; type TForm1 = class(TForm) AbZipper1: TAbZipper; Button1: TButton; OpenDialog1: TOpenDialog; Memo1: TMemo; AbMeter1: TAbMeter; AbMeter2: TAbMeter; Label1: TLabel; Label2: TLabel; procedure Button1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} procedure TForm1.Button1Click(Sender: TObject); begin if OpenDialog1.Execute then AbZipper1.AddFiles( OpenDialog1.FileName, 0 ); end; end. ================================================ FILE: lib/abbrevia/examples/Delphi/ZipReg.dpr ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: ZIPREG.DPR *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} program ZipReg; uses Forms, ZipReg1 in 'ZipReg1.pas' {ExZipAssociation}; begin Application.CreateForm(TExZipAssociation, ExZipAssociation); Application.Run; end. ================================================ FILE: lib/abbrevia/examples/Delphi/ZipReg.dproj ================================================  {623B6B04-BBC3-4044-85BC-8C225B160F0E} ZipReg.dpr True Debug Win32 Application VCL DCC32 12.3 true true Base true true Base true false 00400000 WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;$(DCC_UnitAlias) false false false false false RELEASE;$(DCC_Define) 0 false DEBUG;$(DCC_Define) false true MainSource
ExZipAssociation
Cfg_2 Base Base Cfg_1 Base
Delphi.Personality.12 VCLApplication ZipReg.dpr False False 1 0 0 0 False False False False False 1033 1252 1.0.0.0 1.0.0.0 True 12
================================================ FILE: lib/abbrevia/examples/Delphi/ZipReg.dproj.2007 ================================================  {623B6B04-BBC3-4044-85BC-8C225B160F0E} ZipReg.dpr True Debug Win32 Application VCL DCC32 true true Base true true Base true false false 00400000 false false false false RELEASE;$(DCC_Define) 0 false DEBUG;$(DCC_Define) false true MainSource
ExZipAssociation
Cfg_2 Base Base Cfg_1 Base
Delphi.Personality.12 VCLApplication ZipReg.dpr False False 1 0 0 0 False False False False False 1033 1252 1.0.0.0 1.0.0.0 True 12
================================================ FILE: lib/abbrevia/examples/Delphi/ZipReg1.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: ZIPREG1.PAS *} {* Copyright (c) TurboPower Software Co 1997 *} {* All rights reserved. *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} unit ZipReg1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ExtCtrls, Buttons; type TExZipAssociation = class(TForm) CheckZipReg: TButton; RegZipExt: TButton; Replace: TCheckBox; ExitBtn: TButton; GroupBox1: TGroupBox; Label1: TLabel; Label2: TLabel; Label3: TLabel; Label4: TLabel; Icon1: TImage; ID1: TEdit; FileType1: TEdit; App1: TEdit; Browse1: TSpeedButton; OpenDialog1: TOpenDialog; procedure CheckZipRegClick(Sender: TObject); procedure RegZipExtClick(Sender: TObject); procedure ExitBtnClick(Sender: TObject); procedure Browse1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var ExZipAssociation: TExZipAssociation; implementation {$R *.DFM} uses AbZipExt, ShellApi; var App, ID, FileType : string; FN : array[0..255] of char; IconIndex : Word; procedure TExZipAssociation.CheckZipRegClick(Sender: TObject); begin App := ''; ID := ''; FileType := ''; if AbGetZipAssociation(App, ID, FileType) then begin GroupBox1.Caption := ' ''zip'' is currently registered '; StrPCopy(FN, App); {$IFNDEF Win32} Icon1.Picture.Icon.Handle := ExtractIcon(HInstance, FN, 0); {$ELSE} Icon1.Picture.Icon.Handle := ExtractAssociatedIcon(HInstance, FN, IconIndex); {$ENDIF} end else begin GroupBox1.Caption := ' ''zip'' is not registered '; Icon1.Picture.Icon.Handle := 0; end; ID1.Text := ID; FileType1.Text := FileType; App1.Text := App; end; procedure TExZipAssociation.RegZipExtClick(Sender: TObject); begin if (AbExistingZipAssociation and not Replace.Checked) then CheckZipRegClick(nil) else begin App := App1.Text; FileType := FileType1.Text; ID := ID1.Text; if AbRegisterZipExtension(App, ID, FileType, Replace.Checked) then CheckZipRegClick(nil) else begin GroupBox1.Caption := ' Error occurred during registration '; Icon1.Picture.Icon.Handle := 0; end; end; end; procedure TExZipAssociation.ExitBtnClick(Sender: TObject); begin Close; end; procedure TExZipAssociation.Browse1Click(Sender: TObject); begin OpenDialog1.Title := 'Select application to associate with ''zip'' files'; OpenDialog1.Filename := '*.exe'; if OpenDialog1.Execute then begin App := OpenDialog1.Filename; App1.Text := App; end; end; end. ================================================ FILE: lib/abbrevia/examples/Delphi/ZipView.dpr ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: ZIPVIEW.DPR *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} program ZipView; uses Forms, ZipView1 in 'ZipView1.PAS' {Form1}; begin Application.CreateForm(TForm1, Form1); Application.Run; end. ================================================ FILE: lib/abbrevia/examples/Delphi/ZipView1.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: ZIPVIEW1.PAS *} {* Copyright (c) TurboPower Software Co 1997 *} {* All rights reserved. *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} unit ZipView1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Grids, StdCtrls, ExtCtrls, Menus, FileCtrl, Gauges, ComCtrls, AbArcTyp, AbUtils, AbZipper, AbZipKit, AbZipTyp, AbZBrows, AbMeter, AbDlgDir, AbView, AbZView, AbBrowse, AbBase; type TForm1 = class(TForm) OpenDialog1: TOpenDialog; Panel1: TPanel; FontDialog1: TFontDialog; MainMenu1: TMainMenu; File1: TMenuItem; Open1: TMenuItem; Close1: TMenuItem; N1: TMenuItem; Print1: TMenuItem; Exit1: TMenuItem; ColorDialog1: TColorDialog; ZipView1: TMenuItem; Attributes1: TMenuItem; Itemname1: TMenuItem; Packed1: TMenuItem; Method1: TMenuItem; Ratio1: TMenuItem; CRC1: TMenuItem; Fileattributes1: TMenuItem; Filetype1: TMenuItem; Encryption1: TMenuItem; Timestamp1: TMenuItem; Filesize1: TMenuItem; Versionmade1: TMenuItem; Versionneeded1: TMenuItem; Path1: TMenuItem; Display1: TMenuItem; Columnlines1: TMenuItem; Columnmoving1: TMenuItem; Columnresizing1: TMenuItem; MultiSelect1: TMenuItem; Rowlines1: TMenuItem; Thumbtracking1: TMenuItem; Trackactiverow1: TMenuItem; Sort1: TMenuItem; Itemname2: TMenuItem; Packed2: TMenuItem; Ratio2: TMenuItem; Timestamp2: TMenuItem; Filesize2: TMenuItem; Select1: TMenuItem; SelectAll1: TMenuItem; ClearSelections1: TMenuItem; Rows1: TMenuItem; Rowheight1: TMenuItem; Headerheight1: TMenuItem; Font1: TMenuItem; Alternatecolors1: TMenuItem; Action1: TMenuItem; Add1: TMenuItem; Delete1: TMenuItem; Extract1: TMenuItem; Freshen1: TMenuItem; AbZipView1: TAbZipView; AbZipKit1: TAbZipKit; ZipKit1: TMenuItem; Compress1: TMenuItem; N2: TMenuItem; Store1: TMenuItem; Stored1: TMenuItem; Deflated1: TMenuItem; Best1: TMenuItem; Deflation1: TMenuItem; Normal1: TMenuItem; Maximum1: TMenuItem; Fast1: TMenuItem; SuperFast1: TMenuItem; CreateDirs1: TMenuItem; RestorePath1: TMenuItem; StripPath1: TMenuItem; RemoveDots1: TMenuItem; Recurse1: TMenuItem; ShowIcons1: TMenuItem; Colors1: TMenuItem; Selectedcolor: TMenuItem; Selectedtextcolor: TMenuItem; AlternateColor1: TMenuItem; AlternateTextColor1: TMenuItem; Freshen2: TMenuItem; Panel2: TPanel; AbMeter1: TAbMeter; Label1: TLabel; Label2: TLabel; Moveselecteditem1: TMenuItem; Replace1: TMenuItem; PopupMenu1: TPopupMenu; Delete2: TMenuItem; Extract2: TMenuItem; Freshen3: TMenuItem; Move1: TMenuItem; AbMeter2: TAbMeter; Save1: TMenuItem; Testselecteditems1: TMenuItem; Logging1: TMenuItem; DeletedColor1: TMenuItem; DeletedTextColor1: TMenuItem; procedure AbZipView1Click(Sender: TObject); procedure AttributeClick(Sender: TObject); procedure DisplayOptionClick(Sender: TObject); procedure SortAttributeClick(Sender: TObject); procedure Open1Click(Sender: TObject); procedure Close1Click(Sender: TObject); procedure SelectAll1Click(Sender: TObject); procedure ClearSelections1Click(Sender: TObject); procedure Font1Click(Sender: TObject); procedure Exit1Click(Sender: TObject); procedure Selected1Click(Sender: TObject); procedure Selectedtext1Click(Sender: TObject); procedure Rowheight1Click(Sender: TObject); procedure Headerheight1Click(Sender: TObject); procedure Add1Click(Sender: TObject); procedure Delete1Click(Sender: TObject); procedure Extract1Click(Sender: TObject); procedure ExtractOptionClick(Sender: TObject); procedure StoreOptionClick(Sender: TObject); procedure MethodClick(Sender: TObject); procedure DeflationOptionClick(Sender: TObject); procedure AbZipKit1ConfirmProcessItem(Sender: TObject; Item: TAbArchiveItem; ProcessType: TAbProcessType; var Confirm: Boolean); procedure AbZipView1Change(Sender: TObject); procedure AlternateColor1Click(Sender: TObject); procedure AlternateTextColor1Click(Sender: TObject); procedure Freshen1Click(Sender: TObject); procedure Moveselecteditem1Click(Sender: TObject); procedure AbZipKit1Save(Sender: TObject); procedure Save1Click(Sender: TObject); procedure Testselecteditems1Click(Sender: TObject); procedure Logging1Click(Sender: TObject); procedure DeletedColor1Click(Sender: TObject); procedure DeletedTextColor1Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} const MainCaption = ' TAbZipView example'; { -------------------------------------------------------------------------- } procedure TForm1.AbZipView1Click(Sender: TObject); begin Panel1.Caption := AbZipView1.Items[AbZipView1.ActiveRow].Filename; end; { -------------------------------------------------------------------------- } procedure TForm1.Open1Click(Sender: TObject); begin OpenDialog1.Filename := '*.zip'; if OpenDialog1.Execute then begin AbZipView1.BeginUpdate; // AbZipKit1.FileName := ''; AbZipKit1.Filename := OpenDialog1.Filename; Caption := AbZipKit1.Filename + ' ' + IntToStr(AbZipView1.Count) + ' items'; Action1.Enabled := True; AbZipView1.EndUpdate; end; end; { -------------------------------------------------------------------------- } procedure TForm1.Close1Click(Sender: TObject); begin AbZipKit1.Filename := ''; Caption := MainCaption; Panel1.Caption := ''; Action1.Enabled := False; end; { -------------------------------------------------------------------------- } procedure TForm1.AttributeClick(Sender: TObject); begin with TMenuItem(Sender) do begin Checked := not Checked; if Checked then AbZipView1.Attributes := AbZipView1.Attributes + [TAbViewAttribute(Tag)] else AbZipView1.Attributes := AbZipView1.Attributes - [TAbViewAttribute(Tag)]; end; end; { -------------------------------------------------------------------------- } procedure TForm1.DisplayOptionClick(Sender: TObject); begin with TMenuItem(Sender) do begin Checked := not Checked; if Checked then AbZipView1.DisplayOptions := AbZipView1.DisplayOptions + [TAbDisplayOption(Tag)] else AbZipView1.DisplayOptions := AbZipView1.DisplayOptions - [TAbDisplayOption(Tag)] end; end; { -------------------------------------------------------------------------- } procedure TForm1.SortAttributeClick(Sender: TObject); begin with TMenuItem(Sender) do begin Checked := not Checked; if Checked then AbZipView1.SortAttributes := AbZipView1.SortAttributes + [TAbSortAttribute(Tag)] else AbZipView1.SortAttributes := AbZipView1.SortAttributes - [TAbSortAttribute(Tag)] end; end; { -------------------------------------------------------------------------- } procedure TForm1.StoreOptionClick(Sender: TObject); begin with TMenuItem(Sender) do begin Checked := not Checked; if Checked then AbZipKit1.StoreOptions := AbZipKit1.StoreOptions + [TAbStoreOption(Tag)] else AbZipKit1.StoreOptions := AbZipKit1.StoreOptions - [TAbStoreOption(Tag)] end; end; { -------------------------------------------------------------------------- } procedure TForm1.ExtractOptionClick(Sender: TObject); begin with TMenuItem(Sender) do begin Checked := not Checked; if Checked then AbZipKit1.ExtractOptions := AbZipKit1.ExtractOptions + [TAbExtractOption(Tag)] else AbZipKit1.ExtractOptions := AbZipKit1.ExtractOptions - [TAbExtractOption(Tag)] end; end; { -------------------------------------------------------------------------- } procedure TForm1.MethodClick(Sender: TObject); begin with TMenuItem(Sender) do begin Checked := true; AbZipKit1.CompressionMethodToUse := TAbZipSupportedMethod(Tag); end; end; { -------------------------------------------------------------------------- } procedure TForm1.DeflationOptionClick(Sender: TObject); begin with TMenuItem(Sender) do begin Checked := true; AbZipKit1.DeflationOption := TAbZipDeflationOption(Tag); end; end; { -------------------------------------------------------------------------- } procedure TForm1.SelectAll1Click(Sender: TObject); begin AbZipView1.SelectAll; AbZipView1Click(nil); end; { -------------------------------------------------------------------------- } procedure TForm1.ClearSelections1Click(Sender: TObject); begin AbZipView1.ClearSelections; AbZipView1Click(nil); end; { -------------------------------------------------------------------------- } procedure TForm1.Font1Click(Sender: TObject); begin FontDialog1.Font := AbZipView1.Font; if FontDialog1.Execute then AbZipView1.Font := FontDialog1.Font; end; { -------------------------------------------------------------------------- } procedure TForm1.Exit1Click(Sender: TObject); begin Close; end; { -------------------------------------------------------------------------- } procedure TForm1.DeletedColor1Click(Sender: TObject); begin if ColorDialog1.Execute then AbZipView1.Colors.Deleted := ColorDialog1.Color; end; { -------------------------------------------------------------------------- } procedure TForm1.DeletedTextColor1Click(Sender: TObject); begin if ColorDialog1.Execute then AbZipView1.Colors.DeletedText := ColorDialog1.Color; end; { -------------------------------------------------------------------------- } procedure TForm1.Selected1Click(Sender: TObject); begin if ColorDialog1.Execute then AbZipView1.Colors.Selected := ColorDialog1.Color; end; { -------------------------------------------------------------------------- } procedure TForm1.Selectedtext1Click(Sender: TObject); begin if ColorDialog1.Execute then AbZipView1.Colors.SelectedText := ColorDialog1.Color; end; { -------------------------------------------------------------------------- } procedure TForm1.Rowheight1Click(Sender: TObject); var s : string; begin s := IntToStr(AbZipView1.DefaultRowHeight); if InputQuery(MainCaption, 'Row Height', s) then AbZipView1.DefaultRowHeight := StrToIntDef(s, 18); end; { -------------------------------------------------------------------------- } procedure TForm1.Headerheight1Click(Sender: TObject); var s : string; begin s := IntToStr(AbZipView1.HeaderRowHeight); if InputQuery(MainCaption, 'Header Height', s) then AbZipView1.HeaderRowHeight := StrToIntDef(s, 18); end; { -------------------------------------------------------------------------- } procedure TForm1.Add1Click(Sender: TObject); var i : Integer; begin with OpenDialog1 do begin Filename := '*.*'; Options := Options + [ofAllowMultiSelect]; AbZipView1.BeginUpdate; if Execute then for i := 0 to Pred(Files.Count) do AbZipKit1.AddFiles(Files[i], 0); AbZipView1.EndUpdate; Panel1.Caption := ''; Options := Options - [ofAllowMultiSelect]; end; end; { -------------------------------------------------------------------------- } procedure TForm1.Delete1Click(Sender: TObject); var i : Longint; begin Panel1.Caption := ''; with AbZipView1 do for i := 0 to Pred(Count) do Items[i].Tagged := Selected[i]; AbZipKit1.DeleteTaggedItems; Panel1.Caption := ''; end; { -------------------------------------------------------------------------- } procedure TForm1.Extract1Click(Sender: TObject); var i : Longint; Continue : Boolean; begin {$IFDEF Win32} with TAbDirDlg.Create(Self) do begin Caption := 'Directory'; AdditionalText := 'Select folder to extract into'; SelectedFolder := AbZipKit1.BaseDirectory; Continue := Execute; if Continue then AbZipKit1.BaseDirectory := SelectedFolder; {$ELSE} with TDirDlg.Create(Self) do begin SelectedFolder := AbZipKit1.BaseDirectory; Continue := (ShowModal = mrOK); if Continue then AbZipKit1.BaseDirectory := SelectedFolder; {$ENDIF} Free; end; if not Continue then Exit; Panel1.Caption := ''; with AbZipView1 do for i := 0 to Pred(Count) do Items[i].Tagged := Selected[i]; AbZipKit1.ExtractTaggedItems; AbZipView1.ClearSelections; Panel1.Caption := ''; end; { -------------------------------------------------------------------------- } procedure TForm1.Freshen1Click(Sender: TObject); var i : Longint; begin Panel1.Caption := ''; with AbZipView1 do for i := 0 to Pred(Count) do Items[i].Tagged := Selected[i]; AbZipKit1.FreshenTaggedItems; AbZipKit1.Save; AbZipView1.ClearSelections; Panel1.Caption := ''; end; { -------------------------------------------------------------------------- } procedure TForm1.TestSelecteditems1Click(Sender: TObject); var i : Longint; begin Panel1.Caption := ''; with AbZipView1 do for i := 0 to Pred(Count) do Items[i].Tagged := Selected[i]; AbZipKit1.TestTaggedItems; AbZipView1.ClearSelections; Panel1.Caption := ''; end; { -------------------------------------------------------------------------- } procedure TForm1.AbZipKit1ConfirmProcessItem(Sender: TObject; Item: TAbArchiveItem; ProcessType: TAbProcessType; var Confirm: Boolean); var s : string; begin case ProcessType of ptAdd : s := 'Adding '; ptDelete : s := 'Deleting '; ptExtract : s := 'Extracting '; ptFreshen : s := 'Freshening '; else s := '??? '; end; Panel1.Caption := s + Item.Filename; Confirm := True; end; { -------------------------------------------------------------------------- } procedure TForm1.AbZipView1Change(Sender: TObject); begin Caption := AbZipKit1.Filename + ' ' + IntToStr(AbZipView1.Count) + ' items'; end; { -------------------------------------------------------------------------- } procedure TForm1.AlternateColor1Click(Sender: TObject); begin if ColorDialog1.Execute then AbZipView1.Colors.Alternate := ColorDialog1.Color; end; { -------------------------------------------------------------------------- } procedure TForm1.AlternateTextColor1Click(Sender: TObject); begin if ColorDialog1.Execute then AbZipView1.Colors.AlternateText := ColorDialog1.Color; end; { -------------------------------------------------------------------------- } procedure TForm1.Moveselecteditem1Click(Sender: TObject); var i : Longint; s : string; begin with AbZipView1 do if (SelCount > 0) then begin for i := 0 to Pred(Count) do if Selected[i] then begin s := Items[i].Filename; if InputQuery(MainCaption, 'Rename file', s) then AbZipKit1.Move(Items[i], s); end; AbZipKit1.Save; AbZipView1.ClearSelections; Panel1.Caption := ''; end; end; { -------------------------------------------------------------------------- } procedure TForm1.AbZipKit1Save(Sender: TObject); begin Panel1.Caption := 'Saving ' + AbZipKit1.Filename; end; { -------------------------------------------------------------------------- } procedure TForm1.Save1Click(Sender: TObject); begin if (AbZipKit1.Filename <> '') then AbZipKit1.Save; end; { -------------------------------------------------------------------------- } procedure TForm1.Logging1Click(Sender: TObject); begin Logging1.Checked := not Logging1.Checked; if Logging1.Checked then begin OpenDialog1.Title := 'Select log file'; if AbZipKit1.LogFile = '' then OpenDialog1.Filename := '*.txt' else OpenDialog1.Filename := AbZipKit1.LogFile; Logging1.Checked := OpenDialog1.Execute; if Logging1.Checked then AbZipKit1.LogFile := OpenDialog1.Filename; end; AbZipKit1.Logging := Logging1.Checked; end; end. ================================================ FILE: lib/abbrevia/examples/Delphi/Zipper.dpr ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: ZIPPER.DPR *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} program zipper; uses Forms, Uzip in 'Uzip.pas' {Form1}; begin Application.CreateForm(TForm1, Form1); Application.Run; end. ================================================ FILE: lib/abbrevia/examples/Delphi/Zipper.dproj ================================================  {3B87EA3D-333F-41D2-A7EE-A559DF4E7347} Zipper.dpr True Debug Win32 Application VCL DCC32 12.3 true true Base true true Base true false 00400000 WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;$(DCC_UnitAlias) false false false false false RELEASE;$(DCC_Define) 0 false DEBUG;$(DCC_Define) false true MainSource
Form1
Cfg_2 Base Base Cfg_1 Base
Delphi.Personality.12 VCLApplication Zipper.dpr False False 1 0 0 0 False False False False False 1033 1252 1.0.0.0 1.0.0.0 True 12
================================================ FILE: lib/abbrevia/examples/Delphi/Zipper.dproj.2007 ================================================  {3B87EA3D-333F-41D2-A7EE-A559DF4E7347} Zipper.dpr True Debug Win32 Application VCL DCC32 true true Base true true Base true false false 00400000 false false false false RELEASE;$(DCC_Define) 0 false DEBUG;$(DCC_Define) false true MainSource
Form1
Cfg_2 Base Base Cfg_1 Base
Delphi.Personality.12 VCLApplication Zipper.dpr False False 1 0 0 0 False False False False False 1033 1252 1.0.0.0 1.0.0.0 True 12
================================================ FILE: lib/abbrevia/examples/Delphi/dgAbout.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: DGABOUT.PAS *} {* Copyright (c) TurboPower Software Co 1997 *} {* All rights reserved. *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} unit dgAbout; interface uses Windows, Classes, Graphics, Forms, Controls, StdCtrls, Buttons, ExtCtrls; type TdlgAboutBox = class(TForm) Panel1: TPanel; ProgramIcon: TImage; Label7: TLabel; Label8: TLabel; Panel2: TPanel; lnTitleShadow: TLabel; lblTitle: TLabel; Label5: TLabel; OKButton: TButton; Version: TLabel; Label1: TLabel; Label2: TLabel; Label3: TLabel; Label4: TLabel; Label6: TLabel; procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end; var dlgAboutBox: TdlgAboutBox; implementation {$R *.DFM} uses AbConst; procedure TdlgAboutBox.FormCreate(Sender: TObject); begin Version.Caption := 'Abbrevia ' + AbVersionS; end; end. ================================================ FILE: lib/abbrevia/examples/Delphi/makesfx.dpr ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: MAKESFX.DPR *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} program makesfx; uses Forms, umakesfx in 'umakesfx.pas' {Form1}; begin Application.CreateForm(TForm1, Form1); Application.Run; end. ================================================ FILE: lib/abbrevia/examples/Delphi/spntst0.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) unit spntst0; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, {IpStrms,} {StStrms,} AbBufStm, AbBase, AbBrowse, AbZBrows, AbZipper, AbZipKit, AbSpanSt, ExtCtrls; type TForm1 = class(TForm) AbZipKit1: TAbZipKit; Button1: TButton; OpenDialog1: TOpenDialog; Button3: TButton; Bevel1: TBevel; SaveDialog1: TSaveDialog; procedure Button1Click(Sender: TObject); procedure Button3Click(Sender: TObject); procedure DoRequestImage(Sender: TObject; ImageNumber: Integer; var ImageName: String; var Abort: Boolean); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} procedure TForm1.Button1Click(Sender: TObject); var Span: TAbSpanStream; SrcFile : TFileStream; Src, Dest : string; begin OpenDialog1.FileName := '*.*'; OpenDialog1.Title := 'Select Source File'; if OpenDialog1.Execute then begin Src := OpenDialog1.FileName; OpenDialog1.Title := 'Specify Destination File'; if OpenDialog1.Execute then begin Dest := OpenDialog1.FileName; Span := TAbSpanStream.Create(Dest, fmCreate); SrcFile := TFileStream.Create(Src, fmOpenRead); Span.CopyFrom(SrcFile, SrcFile.Size); Span.Free; SrcFile.Free; end; end; end; procedure TForm1.Button3Click(Sender: TObject); var Span: TAbSpanStream; DestFile : TFileStream; Src, Dest : string; begin OpenDialog1.FileName := '*.*'; OpenDialog1.Title := 'Select Source File'; if OpenDialog1.Execute then begin Src := OpenDialog1.FileName; SaveDialog1.Title := 'Specify Destination File'; if SaveDialog1.Execute then begin Dest := SaveDialog1.FileName; Span := TAbSpanStream.Create(Src, fmOpenRead); Span.SpanType := stLocal; Span.OnRequestImage := DoRequestImage; DestFile := TFileStream.Create(Dest, fmCreate); DestFile.CopyFrom(Span, 3145728{Span.Size}); Span.Free; DestFile.Free; end; end; end; procedure TForm1.DoRequestImage(Sender: TObject; ImageNumber: Integer; var ImageName: String; var Abort: Boolean); begin Abort := not OpenDialog1.Execute; if not Abort then ImageName := OpenDialog1.FileName; end; end. ================================================ FILE: lib/abbrevia/examples/Delphi/uCfGenDg.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) unit uCfGenDg; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TfrmCfGenDlg = class(TForm) Label1: TLabel; Edit1: TEdit; btnCancel: TButton; btnOK: TButton; procedure btnOKClick(Sender: TObject); procedure FormShow(Sender: TObject); private { Private declarations } public { Public declarations } end; var frmCfGenDlg: TfrmCfGenDlg; implementation {$R *.DFM} procedure TfrmCfGenDlg.btnOKClick(Sender: TObject); begin if Edit1.Text <> '' then ModalResult := mrOK; end; procedure TfrmCfGenDlg.FormShow(Sender: TObject); begin Edit1.Text := ''; Edit1.SetFocus; end; end. ================================================ FILE: lib/abbrevia/examples/Delphi/uCfMain.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: UCFMAIN.PAS *} {* Copyright (c) TurboPower Software Co 1997 *} {* All rights reserved. *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} unit uCfMain; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, Menus, ImgList, ComCtrls, AbHexVw, AbCompnd; type TfmCfMain = class(TForm) StatusBar1: TStatusBar; tvDirectory: TTreeView; tvImages: TImageList; OpenDialog1: TOpenDialog; mnuMain: TMainMenu; mnuFile: TMenuItem; mnuFileNew: TMenuItem; mnuFileOpen: TMenuItem; N6: TMenuItem; mnuFileExit: TMenuItem; mnuEdit: TMenuItem; mnuEditAddFile: TMenuItem; mnuEditAddFolder: TMenuItem; mnuEditDelete: TMenuItem; N1: TMenuItem; mnuEditChangeDir: TMenuItem; mnuPopupMenu: TPopupMenu; puAddFile: TMenuItem; puAddFolder: TMenuItem; puViewFile: TMenuItem; puChangeDir: TMenuItem; puViewCompoundFile: TMenuItem; puDelete: TMenuItem; Rename1: TMenuItem; SaveDialog1: TSaveDialog; OpenDialog2: TOpenDialog; pnlHexView: TPanel; procedure mnuFileNewClick(Sender: TObject); procedure mnuFileOpenClick(Sender: TObject); procedure mnuFileExitClick(Sender: TObject); procedure mnuEditAddFileClick(Sender: TObject); procedure mnuEditAddFolderClick(Sender: TObject); procedure mnuEditDeleteClick(Sender: TObject); procedure mnuEditChangeDirClick(Sender: TObject); procedure puViewFileClick(Sender: TObject); procedure puViewCompoundFileClick(Sender: TObject); procedure Rename1Click(Sender: TObject); procedure tvDirectoryClick(Sender: TObject); procedure FormDestroy(Sender: TObject); private { Private declarations } public { Public declarations } end; var fmCfMain: TfmCfMain; AbCompoundFile1 : TAbCompoundFile; HexV : THexView; implementation uses uCfNewDg, uCfGenDg; {$R *.DFM} procedure TfmCfMain.mnuFileNewClick(Sender: TObject); var AllocSize : Integer; begin if SaveDialog1.Execute then begin if frmCfNewDlg.ShowModal = mrOK then begin if AbCompoundFile1 <> nil then AbCompoundFile1.Free; AllocSize := StrToInt(frmCfNewDlg.lbAllocSize. Items[frmCfNewDlg.lbAllocSize.ItemIndex]); AbCompoundFile1 := TAbCompoundFile.Create(SaveDialog1.FileName, frmCfNewDlg.edtVolLbl.Text, AllocSize); Caption := 'Abbrevia 3 Compound File Example (' + SaveDialog1.FileName + ')'; HexV := THexView.Create(Self); HexV.BlockSize := AllocSize; HexV.Parent := pnlHexView; HexV.Align := alClient; HexV.Stream := AbCompoundFile1.Stream; AbCompoundFile1.PopulateTreeView(tvDirectory); end; end; end; procedure TfmCfMain.mnuFileOpenClick(Sender: TObject); begin {OpenExisting compound file} if OpenDialog1.Execute then begin if AbCompoundFile1 <> nil then AbCompoundFile1.Free; AbCompoundFile1 := TAbCompoundFile.Create('', '', 512); AbCompoundFile1.Open(OpenDialog1.FileName); Caption := 'Abbrevia 3 Compound File Example (' + OpenDialog1.FileName + ')'; HexV := THexView.Create(Self); HexV.BlockSize := AbCompoundFile1.AllocationSize; HexV.Parent := pnlHexView; HexV.Align := alClient; HexV.Stream := AbCompoundFile1.Stream; AbCompoundFile1.PopulateTreeView(tvDirectory); end; end; procedure TfmCfMain.mnuFileExitClick(Sender: TObject); begin Application.Terminate; end; procedure TfmCfMain.mnuEditAddFileClick(Sender: TObject); var i : Integer; Strm : TFileStream; begin if OpenDialog2.Execute then begin Strm := TFileStream.Create(OpenDialog2.FileName, fmOpenRead or fmShareDenyNone); AbCompoundFile1.AddFile(OpenDialog2.FileName, Strm, Strm.Size); Strm.Free; AbCompoundFile1.PopulateTreeView(tvDirectory); for i := 0 to tvDirectory.Items.Count - 1 do tvDirectory.Items.Item[i].Expand(True); HexV.Stream := AbCompoundFile1.Stream; end; end; procedure TfmCfMain.mnuEditAddFolderClick(Sender: TObject); var i : Integer; begin if frmCfGenDlg.ShowModal = mrOK then begin AbCompoundFile1.AddFolder(frmCfGenDlg.Edit1.Text); AbCompoundFile1.PopulateTreeView(tvDirectory); for i := 0 to tvDirectory.Items.Count - 1 do tvDirectory.Items.Item[i].Expand(True); end; HexV.Stream := AbCompoundFile1.Stream; end; procedure TfmCfMain.mnuEditDeleteClick(Sender: TObject); var i : Integer; begin if tvDirectory.Selected.ImageIndex = 0 then AbCompoundFile1.DeleteFolder(tvDirectory.Selected.Text) else AbCompoundFile1.DeleteFile(tvDirectory.Selected.Text); HexV.Stream := AbCompoundFile1.Stream; AbCompoundFile1.PopulateTreeView(tvDirectory); for i := 0 to tvDirectory.Items.Count - 1 do tvDirectory.Items.Item[i].Expand(True); end; procedure TfmCfMain.mnuEditChangeDirClick(Sender: TObject); begin frmCfGenDlg.Caption := AbCompoundFile1.CurrentDirectory; if frmCfGenDlg.ShowModal = mrOK then begin AbCompoundFile1.CurrentDirectory := frmCfGenDlg.Edit1.Text; StatusBar1.SimpleText := ' Current Directory: ' + AbCompoundFile1.CurrentDirectory; end; end; procedure TfmCfMain.puViewFileClick(Sender: TObject); var Strm : TStream; begin Strm := TMemoryStream.Create; AbCompoundFile1.OpenFile(tvDirectory.Selected.Text, Strm); Hexv.SetStream(Strm); Strm.Free; end; procedure TfmCfMain.puViewCompoundFileClick(Sender: TObject); begin HexV.Stream := AbCompoundFile1.Stream; end; procedure TfmCfMain.Rename1Click(Sender: TObject); begin frmCfGenDlg.Caption := 'Rename'; frmCfGenDlg.Label1.Caption := 'New Name'; if frmCfGenDlg.ShowModal = mrOK then begin if tvDirectory.Selected.ImageIndex = 0 then AbCompoundFile1.RenameFolder(tvDirectory.Selected.Text, frmCfGenDlg.Edit1.Text) else AbCompoundFile1.RenameFile(tvDirectory.Selected.Text, frmCfGenDlg.Edit1.Text); end; frmCfGenDlg.Caption := 'Change Directory'; frmCfGenDlg.Label1.Caption := 'New Directory'; end; procedure TfmCfMain.tvDirectoryClick(Sender: TObject); begin if not Assigned(tvDirectory.Selected) then tvDirectory.Selected := tvDirectory.TopItem; if (tvDirectory.Selected.ImageIndex = 0) then begin AbCompoundFile1.CurrentDirectory := tvDirectory.Selected.Text; StatusBar1.SimpleText := ' Current Directory: ' + AbCompoundFile1.CurrentDirectory; end; end; procedure TfmCfMain.FormDestroy(Sender: TObject); begin if AbCompoundFile1 <> nil then AbCompoundFile1.Free; end; end. ================================================ FILE: lib/abbrevia/examples/Delphi/uCfNewDg.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) unit uCfNewDg; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TfrmCfNewDlg = class(TForm) Label1: TLabel; edtVolLbl: TEdit; Label2: TLabel; lbAllocSize: TListBox; btnCancel: TButton; btnOK: TButton; procedure FormShow(Sender: TObject); procedure btnOKClick(Sender: TObject); private { Private declarations } public { Public declarations } end; var frmCfNewDlg: TfrmCfNewDlg; implementation {$R *.DFM} procedure TfrmCfNewDlg.FormShow(Sender: TObject); begin lbAllocSize.ItemIndex := 2; edtVolLbl.SetFocus; end; procedure TfrmCfNewDlg.btnOKClick(Sender: TObject); begin if edtVolLbl.Text = '' then begin ShowMessage('Volume label required'); edtVolLbl.SetFocus; end else ModalResult := mrOK; end; end. ================================================ FILE: lib/abbrevia/examples/Delphi/ubasedlg.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: UBASEDLG.PAS *} {* Copyright (c) TurboPower Software Co 1997 *} {* All rights reserved. *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} unit ubasedlg; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, FileCtrl; type TBaseDirDlg = class(TForm) Button1: TButton; Button2: TButton; Edit1: TEdit; DriveComboBox1: TDriveComboBox; DLB: TDirectoryListBox; DirLabel: TLabel; ActionLabel: TLabel; CheckBox2: TCheckBox; CheckBox1: TCheckBox; Button3: TButton; procedure Button3Click(Sender: TObject); private { Private declarations } public { Public declarations } end; var BaseDirDlg: TBaseDirDlg; implementation {$R *.DFM} uses AbUtils, uDemoDlg; procedure TBaseDirDlg.Button3Click(Sender: TObject); begin DemoDlg := TDemoDlg.Create( Self ); try DemoDlg.Caption := 'Create Subdirectory'; DemoDlg.Edit1.Text := ''; DemoDlg.ShowModal; if ( DemoDlg.ModalResult = mrOK ) and ( DemoDlg.Edit1.Text <> '' ) then AbCreateDirectory( DLB.Directory + '\' + DemoDlg.Edit1.Text ); DLB.Update; finally DemoDlg.Free; end; end; end. ================================================ FILE: lib/abbrevia/examples/Delphi/ucomppad.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: UCOMPPAD.PAS *} {* Copyright (c) TurboPower Software Co 1997 *} {* All rights reserved. *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} unit ucomppad; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, Menus, ExtCtrls, AbZBrows, AbZipper, AbZipKit, AbArcTyp, AbBrowse, AbBase; type TForm1 = class(TForm) Memo1: TMemo; AbZipKit1: TAbZipKit; Panel1: TPanel; Memo2: TMemo; procedure FormCreate(Sender: TObject); procedure FormDestroy(Sender: TObject); private { Private declarations } ZnfName : string; TxtName : string; public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} procedure TForm1.FormCreate(Sender: TObject); begin ZnfName := ChangeFileExt(Application.ExeName, '.zip'); TxtName := ExtractFileName( ChangeFileExt(Application.ExeName, '.txt') ); with AbZipKit1 do begin BaseDirectory := ExtractFilePath( Application.ExeName ); ChDir( BaseDirectory ); FileName := ZnfName; if Count > 0 then begin ExtractFiles( TxtName ); Memo1.Lines.LoadFromFile( TxtName ); end; end; end; procedure TForm1.FormDestroy(Sender: TObject); begin Memo1.Lines.SaveToFile( TxtName ); with AbZipKit1 do begin if Count = 0 then AddFiles( TxtName, 0 ) else FreshenFiles( TxtName ); Save; end; DeleteFile( TxtName ); end; end. ================================================ FILE: lib/abbrevia/examples/Delphi/udemodlg.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: UDEMODLG.PAS *} {* Copyright (c) TurboPower Software Co 1997 *} {* All rights reserved. *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} unit udemodlg; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls; type TDemoDlg = class(TForm) Button1: TButton; Button2: TButton; Edit1: TEdit; private { Private declarations } public { Public declarations } end; var DemoDlg: TDemoDlg; implementation {$R *.DFM} end. ================================================ FILE: lib/abbrevia/examples/Delphi/ufinder.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: UFINDER.PAS *} {* Copyright (c) TurboPower Software Co 1997 *} {* All rights reserved. *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} unit ufinder; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, FileCtrl, Buttons, ExtCtrls, AbZBrows, AbArcTyp, AbBrowse, AbBase; type TForm1 = class(TForm) Edit1: TEdit; Label1: TLabel; Memo1: TMemo; DriveComboBox1: TDriveComboBox; DirectoryListBox1: TDirectoryListBox; AbZipBrowser1: TAbZipBrowser; Memo2: TMemo; Label2: TLabel; Button1: TButton; Button2: TButton; FileListBox1: TFileListBox; procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure Edit1Change(Sender: TObject); procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); private { Private declarations } Aborted: Boolean; public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction); begin Aborted := True; end; procedure TForm1.Edit1Change(Sender: TObject); begin Button1.Enabled := Length( Edit1.Text ) > 0; end; procedure TForm1.Button1Click(Sender: TObject); var i, j : Integer; CurFile : string; begin Button1.Enabled := False; Memo1.Clear; try Button2.Enabled := True; Aborted := False; {look in the file list box for the file} for i := 0 to pred( FileListBox1.Items.Count ) do begin Application.ProcessMessages; if Aborted then Break; {now add search of zip and self extracting files} try AbZipBrowser1.FileName := FileListBox1.Directory + '\' + FileListBox1.Items[i]; for j := 0 to AbZipBrowser1.Count - 1 do if AbZipBrowser1[j].MatchesStoredName(Edit1.Text) then begin Memo1.Lines.Add( 'Found in ' + FileListBox1.Items[i] ); Break; end; except end; end; finally Memo1.Lines.Add( 'Done!' ); Edit1.Enabled := True; Button1.Enabled := True; Button2.Enabled := False; end; end; procedure TForm1.Button2Click(Sender: TObject); begin Aborted := True; end; end. ================================================ FILE: lib/abbrevia/examples/Delphi/umakesfx.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: UMAKESFX.PAS *} {* Copyright (c) TurboPower Software Co 1997 *} {* All rights reserved. *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} unit umakesfx; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, AbArcTyp, AbSelfEx, AbBase; type TForm1 = class(TForm) Memo1: TMemo; Button1: TButton; AbMakeSelfExe1: TAbMakeSelfExe; OpenDialog1: TOpenDialog; procedure Button1Click(Sender: TObject); procedure AbMakeSelfExe1GetStubExe(Sender: TObject; var aFilename: string; var Abort: Boolean); procedure AbMakeSelfExe1GetZipFile(Sender: TObject; var aFilename: string; var Abort: Boolean); private { Private declarations } public { Public declarations } end; var Form1: TForm1; implementation {$R *.DFM} uses AbZipTyp; procedure TForm1.Button1Click(Sender: TObject); begin if AbMakeSelfExe1.Execute then ShowMessage(AbMakeSelfExe1.SelfExe + ' has been created'); end; procedure TForm1.AbMakeSelfExe1GetStubExe(Sender: TObject; var aFilename: string; var Abort: Boolean); begin OpenDialog1.Title := 'Select executable stub'; OpenDialog1.Filename := ''; OpenDialog1.Filter := 'Exe files|*.exe'; Abort := not OpenDialog1.Execute; if not Abort then aFileName := OpenDialog1.Filename; end; procedure TForm1.AbMakeSelfExe1GetZipFile(Sender: TObject; var aFilename: string; var Abort: Boolean); begin OpenDialog1.Title := 'Select Zip File'; OpenDialog1.Filename := ''; OpenDialog1.Filter := 'Zip files|*.zip'; Abort := not OpenDialog1.Execute; if not Abort then aFileName := OpenDialog1.Filename; end; end. ================================================ FILE: lib/abbrevia/examples/Delphi/usplash.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: USPLASH.PAS *} {* Copyright (c) TurboPower Software Co 1997 *} {* All rights reserved. *} {*********************************************************} {* ABBREVIA Example program file *} {*********************************************************} unit usplash; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls; type TSplash = class(TForm) Image1: TImage; Timer1: TTimer; procedure Timer1Timer(Sender: TObject); private { Private declarations } public { Public declarations } end; var Splash: TSplash; implementation {$R *.DFM} procedure TSplash.Timer1Timer(Sender: TObject); begin Close; end; end. ================================================ FILE: lib/abbrevia/localization/AbResString.pas.afr ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Henri Hakl, Roman Kassebaum * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* Abbrevia: AbResString.pas *} {*********************************************************} {* Abbrevia: Resource strings, Africaans localization *} {*********************************************************} unit AbResString; interface resourcestring AbErrZipInvalidS = 'Ongeldig - geen PKZIP bestaan nie'; AbZipVersionNeededS = 'Ler kannie ontpak word nie - kry nuwer weergawe van PKZIP'; AbUnknownCompressionMethodS = 'Ler kannie ontpak word nie - onbekende kompressiemetode'; AbNoExtractionMethodS = 'Ler kannie ontpak word nie - geen ondersteunende metode'; AbInvalidPasswordS = 'Ler kannie ontpak word nie - ongeldige paswoord'; AbNoInsertionMethodS = 'Ler kannie bygevoeg word nie - byvoeging is nie ondersteun nie'; AbInvalidFactorS = 'Ongeldige reduksiefaktoor'; AbDuplicateNameS = 'Ler kannie bygevoeg word nie - tweevoud by name gevind'; AbUnsupportedCompressionMethodS = 'Ler kannie bygevoeg word nie - nie ondersteunde kompressiemetode'; AbUserAbortS = 'Proses is deur gebruiker onderbreek'; AbArchiveBusyS = 'Argief is besig - kan nuwe aanvrag nie bewerk nie'; AbLastDiskRequestS = 'Benodig laaste skyf van gedeelde argief'; AbDiskRequestS = 'Benodig skyf'; AbImageRequestS = 'Benodig naam'; AbBadSpanStreamS = 'Gedeelde argief moet als bestandsstroom geopen word'; AbDiskNumRequestS = 'Benodig skyf %d van gedeelde argief'; AbImageNumRequestS = 'Benodig segment %d van gedeelde argief'; AbNoOverwriteSpanStreamS = 'Kannie bestaande gedeelde argief verander nie'; AbNoSpannedSelfExtractS = 'Kannie selfontpakkende gedeelde argief maak nie'; AbBlankDiskS = 'Benodig le skyf'; AbStreamFullS = 'Stroom skryffout'; AbNoSuchDirectoryS = 'Gids bestaan nie'; AbInflateBlockErrorS = 'Kannie blok ontpak nie'; AbBadStreamTypeS = 'Ongeldige stroom'; AbTruncateErrorS = 'Daar bestaan in afknottings fout in zip-ler'; AbZipBadCRCS = 'CRC kontroole his misluk'; AbZipBadStubS = 'Stomp moet uitvoerbaar wees'; AbFileNotFoundS = 'Ler nie gevind nie'; AbInvalidLFHS = 'Ongeldige lokaale ler obskrif element'; AbNoArchiveS = 'Argief bestaan nie'; AbReadErrorS = 'Leesfout in argief'; AbInvalidIndexS = 'Ongeldige indeks van argiefelement'; AbInvalidThresholdS = 'Ongeldige drempel van argiefgroote'; AbUnhandledFileTypeS = 'Onbekende argieftype'; AbSpanningNotSupportedS = 'Argief deeling is nie ondersteun nie'; AbLogCreateErrorS = 'Fout gedurende protokol skepping'; AbMoveFileErrorS = 'Fout gedurende verplasing van ler van %s na %s'; AbFileSizeTooBigS = 'Ler is te groot vir argieftype'; AbNoCabinetDllErrorS = 'Kannie ler cabinet.dll laai nie'; AbFCIFileOpenErrorS = 'FCI kannie ler oopmaak nie'; AbFCIFileReadErrorS = 'FCI kannie ler lees nie'; AbFCIFileWriteErrorS = 'FCI kannie ler skryf nie'; AbFCIFileCloseErrorS = 'FCI kannie ler toemaak nie'; AbFCIFileSeekErrorS = 'FCI kannie posisie verander nie'; AbFCIFileDeleteErrorS = 'FCI kannie ler verwyder nie'; AbFCIAddFileErrorS = 'FCI kannie ler byvoeg nie'; AbFCICreateErrorS = 'FCI kannie conteks skep nie'; AbFCIFlushCabinetErrorS = 'FCI kannie kabinet spoel nie'; AbFCIFlushFolderErrorS = 'FCI kannie gids spoel nie'; AbFDICopyErrorS = 'FDI kannie ler opsom nie'; AbFDICreateErrorS = 'FDI kannie konteks skep nie'; AbInvalidCabTemplateS = 'Ongeldige kabinet sjabloon'; AbInvalidCabFileS = 'Ongeldiger ler - geen kabinet bestaan nie'; AbZipStored = 'Opgeslagen'; AbZipShrunk = 'Gekrimp'; AbZipReduced = 'Verminder'; AbZipImploded = 'Gemplodeerd'; AbZipTokenized = 'In simboole gepak'; AbZipDeflated = 'Gedeflationeerd'; AbZipDeflate64 = 'Uitgebreid gedeflationeerd'; AbZipDCLImploded = 'DCL gemplodeerd'; AbZipBzip2 = 'Bzip2'; AbZipLZMA = 'LZMA'; AbZipIBMTerse = 'IBM Terse'; AbZipLZ77 = 'IBM LZ77'; AbZipJPEG = 'JPEG'; AbZipWavPack = 'WavPack'; AbZipPPMd = 'PPMd'; AbZipUnknown = 'Onbekend (%d)'; AbZipBestMethod = 'Beste metode'; AbVersionFormatS = 'Weergawe'; AbCompressedSizeFormatS = 'Gekomprimeerde groote: %d'; AbUncompressedSizeFormatS = 'Ongekomprimeerde groote: %d'; AbCompressionMethodFormatS = 'Kompressie metode: %s'; AbCompressionRatioFormatS = 'Kompressieverhouding: %2.0f%%'; AbCRCFormatS = 'CRC: %x'; AbReadOnlyS = 'r'; AbHiddenS = 'h'; AbSystemS = 's'; AbArchivedS = 'a'; AbEFAFormatS = 'Eksterne lerattribute: %s'; AbIFAFormatS = 'Lertype'; AbTextS = 'Teks'; AbBinaryS = 'Binre'; AbEncryptionFormatS = 'Versleuteling: %s'; AbEncryptedS = 'Versleuteld'; AbNotEncryptedS = 'Nie versleuteld nie'; AbUnknownS = 'Onbekend'; AbTimeStampFormatS = 'Tydstempel: %s'; AbMadeByFormatS = 'Gemaak met weergawe: %f'; AbNeededFormatS = 'Weergawe benodig vir ontpakking: %f'; AbCommentFormatS = 'Opmerking: %s'; AbDefaultExtS = '*.zip'; AbFilterS = 'PKZIP argief (*.zip)|*.zip|Selfontpakkende Argief (*.exe)|*.exe|Alle Lers (*.*)|*.*'; AbFileNameTitleS = 'Kies lernaam'; AbOKS = 'OK'; AbCancelS = 'Verlaat'; AbSelectDirectoryS = 'Kies ler'; AbEnterPasswordS = 'Voeg paswoord in'; AbPasswordS = '&Paswoord'; AbVerifyS = '&Verifiseer'; AbCabExtS = '*.cab'; AbCabFilterS = 'Kabinetsargiewe (*.cab)|*.CAB|Alle Lers (*.*)|*.*'; AbLogExtS = '*.txt'; AbLogFilterS = 'Tekslers (*.cab)|*.CAB|Alle Lers (*.*)|*.*'; AbExeExtS = '*.exe'; AbExeFilterS = 'Selfontpakkende Zip Lers (*.cab)|*.CAB|Alle Lers (*.*)|*.*'; AbVMSReadTooManyBytesS = 'VMS: Te veel byte gelees'; AbVMSInvalidOriginS = 'VMS: Ongeldige oorsprong %d, moet 0, 1 or 2 wees'; AbVMSErrorOpenSwapS = 'VMS: Kannie wisseller oopmaak nie'; AbVMSSeekFailS = 'VMS: Kannie wisseller posisie verander nie'; AbVMSReadFailS = 'VMS: Kan %d byte in wisseller nie lees nie'; AbVMSWriteFailS = 'VMS: Kan %d byte in wisseller nie skryf nie'; AbVMSWriteTooManyBytesS = 'VMS: Aanvraag om te veel byte [%d] te skryf'; AbBBSReadTooManyBytesS = 'BBS: Aanvraag om te veel byte [%d] te lees'; AbBBSSeekOutsideBufferS = 'BBS: Nuwe posisie is buite die buffer'; AbBBSInvalidOriginS = 'BBS: Ongeldige oorsprongswaarde'; AbBBSWriteTooManyBytesS = 'BBS: Aanvrag om te veel byte [%d] te skryf'; AbSWSNotEndofStreamS = 'TabSlidingWindowStream.Write: Nie by stroom einde nie'; AbSWSSeekFailedS = 'TabSlidingWindowStream.bsWriteChunk: Posisioneering misluk'; AbSWSWriteFailedS = 'TabSlidingWindowStream.bsWriteCunk: Skryf misluk'; AbSWSInvalidOriginS = 'TabSlidingWindowStream.Seek: Ongeldige oorsprong'; AbSWSInvalidNewOriginS = 'TabSlidingWindowStream.Seek: Ongeldige nuwe posisie'; AbItemNameHeadingS = 'Naam'; AbPackedHeadingS = 'Gepak'; AbMethodHeadingS = 'Metode'; AbRatioHeadingS ='Besparing (%)'; AbCRCHeadingS = 'CRC32'; AbFileAttrHeadingS = 'Attribuut'; AbFileFormatHeadingS = 'Formaat'; AbEncryptionHeadingS = 'Versleuteld'; AbTimeStampHeadingS = 'Tydstempel'; AbFileSizeHeadingS = 'Groote'; AbVersionMadeHeadingS = 'Gebruikte weergawe'; AbVersionNeededHeadingS = 'Benodigde weergawe'; AbPathHeadingS = 'Pad'; AbPartialHeadingS = 'Partieel'; AbExecutableHeadingS = 'Uitvoerbaar'; AbCabMethod0S = 'Geen'; AbCabMethod1S = 'MSZip'; AbLtAddS = ' toegevoegd '; AbLtDeleteS = ' gewist '; AbLtExtractS = ' ontpakt '; AbLtFreshenS = ' geaktualiseerd '; AbLtMoveS = ' verplaas '; AbLtReplaceS = ' vervang '; AbLtStartS = ' geprotocoleerd '; AbGzipInvalidS = 'Ongeldige Gzip'; AbGzipBadCRCS = 'Ongeldige CRC'; AbGzipBadFileSizeS = 'Ongeldige bestaandsgroote'; AbTarInvalidS = 'Tar ongeldig'; AbTarBadFileNameS = 'Ler naam te lang'; AbTarBadLinkNameS = 'Skakel naam te lang'; AbTarBadOpS = 'Operasie nie ondersteun nie'; AbUnhandledEntityS = 'Nie behandelde entiteit'; { pre-defined "operating system" (really more FILE system) identifiers for the Gzip header } AbGzOsFat = 'FAT Lersisteem (MS-DOS, OS/2, NT/Win32)'; AbGzOsAmiga = 'Amiga'; AbGzOsVMS = 'VMS (of OpenVMS)'; AbGzOsUnix = 'Unix'; AbGzOsVM_CMS = 'VM/CMS'; AbGzOsAtari = 'Atari TOS'; AbGzOsHPFS = 'HPFS Lersisteem (OS/2, NT)'; AbGzOsMacintosh = 'Macintosh'; AbGzOsZ_System = 'Z-System'; AbGzOsCP_M = 'CP/M'; AbGzOsTOPS_20 = 'TOPS-20'; AbGzOsNTFS = 'NTFS Lersisteem (NT)'; AbGzOsQDOS = 'QDOS'; AbGzOsAcornRISCOS = 'Acorn RISCOS'; AbGzOsVFAT = 'VFAT Lersisteem (Win95, NT)'; AbGzOsMVS = 'MVS'; AbGzOsBeOS = 'BeOS (BeBox of PowerMac)'; AbGzOsTandem = 'Tandem/NSK'; AbGzOsTHEOS = 'THEOS'; AbGzOsunknown = 'onbekend'; AbGzOsUndefined = 'ID is Gzip nie bekend nie'; {!!.03 - Moved from AbCompnd.inc } { Compound File specific error messages } resourcestring AbCmpndIndexOutOfBounds = 'Indeks buite toegelate bereik'; AbCmpndBusyUpdating = 'Saamgestelde ler word geaktualiseer'; AbCmpndInvalidFile = 'Ongeldige saamgestelde ler'; AbCmpndFileNotFound = 'Ler/gids nie gevind nie'; AbCmpndFolderNotEmpty = 'Gids nie leeg nie'; AbCmpndExceedsMaxFileSize = 'Lergroote oorskryf toegelate maksimum'; {!!.03 - End Moved } implementation end. ================================================ FILE: lib/abbrevia/localization/AbResString.pas.de ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Roman Kassebaum * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* Abbrevia: AbResString.pas *} {*********************************************************} {* Abbrevia: Resource strings, German localization *} {*********************************************************} unit AbResString; interface resourcestring AbErrZipInvalidS = 'Ungltige Datei - keine PKZip Datei'; AbZipVersionNeededS = 'Kann die Datei nicht entpacken - neuere Version bentigt'; AbUnknownCompressionMethodS = 'Kann die Datei nicht entpacken - nicht untersttzte Kommpressionsmethode'; AbNoExtractionMethodS = 'Kann die Datei nicht entpacken - keine Entpackuntersttzung angeboten'; AbInvalidPasswordS = 'Kann die Datei nicht entpacken - ungltiges Passwort'; AbNoInsertionMethodS = 'Kann die Datei nicht entpacken - keine Einfgeuntersttzung angeboten'; AbInvalidFactorS = 'Ungltiger Reduzierungsfaktor'; AbDuplicateNameS = 'Kann die Datei nicht einfgen - doppelter gespeicherter Name'; AbUnsupportedCompressionMethodS = 'Kann die Datei nicht einfgen - nicht untersttzt Kompressionsmethode'; AbUserAbortS = 'Prozess wurde durch den Benutzer abgebrochen'; AbArchiveBusyS = 'Das Archiv ist beschftigt - kann nicht die neue Anforderung bearbeiten'; AbLastDiskRequestS = 'Legen Sie die letzte Diskette ein'; AbDiskRequestS = 'Diskette einlegen '; AbImageRequestS = 'Name des Abbildes'; AbBadSpanStreamS = 'Segmentierte Archive mssen als Datei-Strom geffnet werden'; AbDiskNumRequestS = 'Legen Sie die Diskette %d des segmentierten Archivs ein'; AbImageNumRequestS = 'Legen Sie das Segment %d des segmentierten Archivs ein'; AbNoOverwriteSpanStreamS = 'Kann kein existierendes segmentiertes Archiv verndern'; AbNoSpannedSelfExtractS = 'Kann kein selbstentpackendes segmentiertes Archiv erstellen'; AbBlankDiskS = 'Legen Sie eine leere Diskette ein'; AbStreamFullS = 'Strom Schreibfehler'; AbNoSuchDirectoryS = 'Verzeichnis existiert nicht'; AbInflateBlockErrorS = 'Kann den Bereich nicht entpacken'; AbBadStreamTypeS = 'Ungltiger Strom'; AbTruncateErrorS = 'Fehler beim Abschneiden der zip Datei'; AbZipBadCRCS = 'Fehlgeschalgene CRC berprfung'; AbZipBadStubS = 'Der Stamm muss ausfhrbar sein'; AbFileNotFoundS = 'Datei nicht gefunden'; AbInvalidLFHS = 'Ungltiger lokaler Dateianfang'; AbNoArchiveS = 'Das Archiv existiert nicht- leerer Dateinahme'; AbReadErrorS = 'Fehler beim Lesen des Archivse'; AbInvalidIndexS = 'Ungltiger Archiv Element Eintrag'; AbInvalidThresholdS = 'Ungltige Archivgren Schwelle'; AbUnhandledFileTypeS = 'Unbekannter Archiv'; AbSpanningNotSupportedS = 'Aufteilen wird bei diesem Archivtyp nicht untersttzt'; AbLogCreateErrorS = 'Fehler beim Erzeugen der Protokolldatei'; AbMoveFileErrorS = 'Fehler beim Verschieben der Datei %s nach %s'; AbFileSizeTooBigS = 'Datei ist zu gro fr diesen Archivtypen'; AbNoCabinetDllErrorS = 'Kann die Datei cabinet.dll nicht laden'; AbFCIFileOpenErrorS = 'FCI kann die Datei nicht ffnen'; AbFCIFileReadErrorS = 'FCI kann die Datei nicht lesen'; AbFCIFileWriteErrorS = 'FCI kann die Datei nicht schreiben'; AbFCIFileCloseErrorS = 'FCI Fehler beim Schlieen der Datei'; AbFCIFileSeekErrorS = 'FCI Fehler beim Durchsuchen der Datei'; AbFCIFileDeleteErrorS = 'FCI Fehler beim Lschen der Datei'; AbFCIAddFileErrorS = 'FCI kann die Datei nicht hinzufgen'; AbFCICreateErrorS = 'FCI kann den Zusammenhang nicht erstellen'; AbFCIFlushCabinetErrorS = 'FCI kann das Cabinet-Archiv nicht leeren'; AbFCIFlushFolderErrorS = 'FCI kann das Verzeichnis nicht leeren'; AbFDICopyErrorS = 'FDI kann die Dateien nicht aufzhlen'; AbFDICreateErrorS = 'FDI kann den Zusammenhang nicht herstellen'; AbInvalidCabTemplateS = 'Ungltige Vorlage fr eine Cabinet-Datei'; AbInvalidCabFileS = 'Ungltige Datei - keine Kabinett Datei'; AbZipStored = 'Gespeichert'; AbZipShrunk = 'Geschrumpft'; AbZipReduced = 'Reduziert'; AbZipImploded = 'Implodiert'; AbZipTokenized = 'In Merkmale aufgeteilt'; AbZipDeflated = 'Gepackt'; AbZipDeflate64 = 'Strker gepackt'; AbZipDCLImploded = 'DCL Implodiert'; AbZipBzip2 = 'Bzip2'; AbZipLZMA = 'LZMA'; AbZipIBMTerse = 'IBM Terse'; AbZipLZ77 = 'IBM LZ77'; AbZipJPEG = 'JPEG'; AbZipWavPack = 'WavPack'; AbZipPPMd = 'PPMd'; AbZipUnknown = 'Unbekannt (%d)'; AbZipBestMethod = 'Beste Methode'; AbVersionFormatS = 'Version %s'; AbCompressedSizeFormatS = 'Komprimierte Gre: %d'; AbUncompressedSizeFormatS = 'Komprimierte Gre: %d'; AbCompressionMethodFormatS = 'Kompressions-Methode: %s'; AbCompressionRatioFormatS = 'Kompressions-Verhltnis: %2.0f%%'; AbCRCFormatS = 'CRC: %x'; AbReadOnlyS = 'r'; AbHiddenS = 'h'; AbSystemS = 's'; AbArchivedS = 'a'; AbEFAFormatS = 'Externe Datei Attribute: %s'; AbIFAFormatS = 'Dateityp: %s'; AbTextS = 'Text'; AbBinaryS = 'Binr'; AbEncryptionFormatS = 'Verschlsselung: %s'; AbEncryptedS = 'Verschlsselt'; AbNotEncryptedS = 'Nicht verschlsselt'; AbUnknownS = 'Unbekannt'; AbTimeStampFormatS = 'Zeitstemple: %s'; AbMadeByFormatS = 'Erzeugt mit der Version: %f'; AbNeededFormatS = 'Version bentigt zum Extrahieren: %f'; AbCommentFormatS = 'Kommentar: %s'; AbDefaultExtS = '*.zip'; AbFilterS = 'PKZip Archive (*.zip)|*.zip|Selbstentpackende Archive (*.exe)|*.exe|Alle Dateien (*.*)|*.*'; AbFileNameTitleS = 'Dateinamen auswhlen'; AbOKS = 'OK'; AbCancelS = 'Abbrechen'; AbSelectDirectoryS = 'Verzeichnis auswhlen'; AbEnterPasswordS = 'Passwort eingeben'; AbPasswordS = '&Passwort'; AbVerifyS = '&berprfen'; AbCabExtS = '*.cab'; AbCabFilterS = 'Cabinet Archive (*.cab)|*.CAB|Alle Dateien (*.*)|*.*'; AbLogExtS = '*.txt'; AbLogFilterS = 'Text Dateien (*.txt)|*.TXT|Alle Dateien (*.*)|*.*'; AbExeExtS = '*.exe'; AbExeFilterS = 'Selbstentpackende Zip Dateien (*.exe)|*.EXE|Alle Dateien (*.*)|*.*'; AbVMSReadTooManyBytesS = 'VMS: Anforderung, zu viele Bytes [%d] zu lesen'; AbVMSInvalidOriginS = 'VMS: Ungltiger Ursprung %d, sollte 0, 1, 2 sein'; AbVMSErrorOpenSwapS = 'VMS: Kann die Auslagerungsdatei %s nicht ffnen'; AbVMSSeekFailS = 'VMS: Konnte nicht in der Auslagerungsdatei %s suchen'; AbVMSReadFailS = 'VMS: Konnte nicht %d Bytes in der Auslagerungsdatei %s lesen'; AbVMSWriteFailS = 'VMS: Konnte nicht %d Bytes in die Auslagerungsdatei %s schreiben'; AbVMSWriteTooManyBytesS = 'VMS: Anforderung, zu viele Bytes [%d] zu schreiben'; AbBBSReadTooManyBytesS = 'BBS: Anforderung, zu viele Bytes [%d] zu lesen'; AbBBSSeekOutsideBufferS = 'BBS: Die neue Position ist auerhalb des Puffers'; AbBBSInvalidOriginS = 'BBS: Ungltiger Ursprungswert'; AbBBSWriteTooManyBytesS = 'BBS: Anforderung, zu viele Bytes [%d] zu schreiben'; AbSWSNotEndofStreamS = 'TabSlidingWindowStream.Write: Nicht am Ende des Datenstroms'; AbSWSSeekFailedS = 'TabSlidingWindowStream.bsWriteChunk: Suche fehlgeschlagen'; AbSWSWriteFailedS = 'TabSlidingWindowStream.bsWriteChunk: Schreiben fehlgeschlagen'; AbSWSInvalidOriginS = 'TabSlidingWindowStream.Seek: Ungltiger Ursprung'; AbSWSInvalidNewOriginS = 'TabSlidingWindowStream.Seek: Ungltige neue Position'; AbItemNameHeadingS = 'Name'; AbPackedHeadingS = 'Gepacked'; AbMethodHeadingS = 'Methode'; AbRatioHeadingS = 'Einsparung (%)'; AbCRCHeadingS = 'CRC32'; AbFileAttrHeadingS = 'Attribute'; AbFileFormatHeadingS = 'Format'; AbEncryptionHeadingS = 'Verschlsselt'; AbTimeStampHeadingS = 'Zeitstempel'; AbFileSizeHeadingS = 'Gre'; AbVersionMadeHeadingS = 'Version genutzt'; AbVersionNeededHeadingS = 'Version bentigt'; AbPathHeadingS = 'Pfad'; AbPartialHeadingS = 'Teilweise'; AbExecutableHeadingS = 'Ausfhrbar'; AbFileTypeHeadingS = 'Typ'; AbLastModifiedHeadingS = 'Modifiziert'; AbCabMethod0S = 'Keine'; AbCabMethod1S = 'MSZip'; AbLtAddS = ' hinzugefgt '; AbLtDeleteS = ' gelscht '; AbLtExtractS = ' extrahiert '; AbLtFreshenS = ' aktualisiert '; AbLtMoveS = ' verschoben '; AbLtReplaceS = ' ersetzt '; AbLtStartS = ' protokolliert '; AbGzipInvalidS = 'Ungltiges Gzip'; AbGzipBadCRCS = 'Ungltiger CRC'; AbGzipBadFileSizeS = 'Ungltige Datei Gre'; AbTarInvalidS = 'Ungltiges Tar'; AbTarBadFileNameS = 'Dateiname zu lang'; AbTarBadLinkNameS = 'Linkname zu lang'; AbTarBadOpS = 'Nicht untersttzte Operation'; AbUnhandledEntityS = 'Nicht behandelte Entitt'; { pre-defined "operating system" (really more FILE system) identifiers for the Gzip header } AbGzOsFat = 'FAT Datei-System (MS-DOS, OS/2, NT/Win32)'; AbGzOsAmiga = 'Amiga'; AbGzOsVMS = 'VMS (oder OpenVMS)'; AbGzOsUnix = 'Unix'; AbGzOsVM_CMS = 'VM/CMS'; AbGzOsAtari = 'Atari TOS'; AbGzOsHPFS = 'HPFS Datei-System (OS/2, NT)'; AbGzOsMacintosh = 'Macintosh'; AbGzOsZ_System = 'Z-System'; AbGzOsCP_M = 'CP/M'; AbGzOsTOPS_20 = 'TOPS-20'; AbGzOsNTFS = 'NTFS Datei-System (NT)'; AbGzOsQDOS = 'QDOS'; AbGzOsAcornRISCOS = 'Acorn RISCOS'; AbGzOsVFAT = 'VFAT Datei-System (Win95, NT)'; AbGzOsMVS = 'MVS'; AbGzOsBeOS = 'BeOS (BeBox oder PowerMac)'; AbGzOsTandem = 'Tandem/NSK'; AbGzOsTHEOS = 'THEOS'; AbGzOsunknown = 'unkekannt'; AbGzOsUndefined = 'ID ist Gzip nicht bekannt'; {!!.03 - Moved from AbCompnd.inc } { Compound File specific error messages } resourcestring AbCmpndIndexOutOfBounds = 'Index auerhalb des zulssigen Bereichs'; AbCmpndBusyUpdating = 'Verbindungsdatei wird aktualisiert'; AbCmpndInvalidFile = 'Ungltige Verbindungsdatei'; AbCmpndFileNotFound = 'Datei/Verzeichnis nicht gefunden'; AbCmpndFolderNotEmpty = 'Verzeichnis ist nicht leer'; AbCmpndExceedsMaxFileSize = 'Dateigre berschreitet das erlaubte Maximum'; {!!.03 - End Moved } implementation end. ================================================ FILE: lib/abbrevia/localization/AbResString.pas.fr ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Hichem BOUKSANI, John Riche, Roman Kassebaum * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* Abbrevia: AbResString.pas *} {*********************************************************} {* Abbrevia: Resource strings *} {*********************************************************} unit AbResString; interface resourcestring AbErrZipInvalidS = 'Fichier non valide - N''est pas un fichier PKZip'; AbZipVersionNeededS = 'Impossible d''extraire le fichier - nouvelle version requise'; AbUnknownCompressionMethodS = 'Impossible d''extraire le fichier - mthode de compression non supporte'; AbNoExtractionMethodS = 'Impossible d''extraire le fichier - aucun support d''extraction fourni'; AbInvalidPasswordS = 'Impossible d''extraire le fichier - Mot de passe incorrect'; AbNoInsertionMethodS = 'Imossible d''insrer le fichier - aucun support d''insertion fourni'; AbInvalidFactorS = 'Facteur de rduction Invalide'; AbDuplicateNameS = 'Impossible d''insrer le fichier - Nom du fichier existe en double'; AbUnsupportedCompressionMethodS = 'Impossible d''insrer le fichier - mthode de compression non suppote'; AbUserAbortS = 'Processus abandonn par l''utilisateur'; AbArchiveBusyS = 'Archivage en cours - ne peut traiter de nouvelles demandes'; AbLastDiskRequestS = 'Insrer la dernire disquette du jeu multi-disquettes'; AbDiskRequestS = 'Insrer une disquette'; AbImageRequestS = 'Nom du fichier image'; AbBadSpanStreamS = 'Archives multi-disquettes doivent tre ouvertes comme fichiers de flux'; AbDiskNumRequestS = 'Insrer la disquette %d du jeu multi-disquettes'; AbImageNumRequestS = 'Insrer la disquette %d du jeu multi-disquettes'; AbNoOverwriteSpanStreamS = 'Impossible de mettre jour un jeu multi-disquettes existant'; AbNoSpannedSelfExtractS = 'Impossible de crer un fichier auto-extractible partir d''une archive multi-disquettes'; AbBlankDiskS = 'Insrer une disquette vierge'; AbStreamFullS = 'Erreur d''criture du flux'; AbNoSuchDirectoryS = 'Dossier inexistant'; AbInflateBlockErrorS = 'Dcompression du bloc impossible'; AbBadStreamTypeS = 'Flux Invalide'; AbTruncateErrorS = 'Erreur de troncage du fichier ZIP'; AbZipBadCRCS = 'Echec du contrle CRC'; AbZipBadStubS = 'La souche doit tre un executable'; AbFileNotFoundS = 'Fichier inexistant'; AbInvalidLFHS = 'Entre de l''entte du fichier local invalide'; AbNoArchiveS = 'L''archive n''existe pas - Nom de fichier non spcifi'; AbReadErrorS = 'Erreur de l''ecture de l''archive'; AbInvalidIndexS = 'L''indice de l''lment de l''archive est invalide'; AbInvalidThresholdS = 'Le seuil de la taille de l''archive est invalide'; AbUnhandledFileTypeS = 'Type d''archive non support'; AbSpanningNotSupportedS = 'Multi-disquette non support par ce type d''archive'; AbLogCreateErrorS = 'Erreur de cration du fichier log'; AbMoveFileErrorS = 'Erreur de dplacement du fichier %s vers %s'; AbFileSizeTooBigS = 'Taille du fichier trop grande pour le type d''archive'; AbNoCabinetDllErrorS = 'Impossible de charger cabinet.dll'; AbFCIFileOpenErrorS = 'FCI impossible d''ouvrir le fichier'; AbFCIFileReadErrorS = 'FCI impossible de lire le fichier'; AbFCIFileWriteErrorS = 'FCI Ecriture impossible sur le fichier'; AbFCIFileCloseErrorS = 'FCI erreur de fermeture du fichier'; AbFCIFileSeekErrorS = 'FCI Erreur de recherche de fichier'; AbFCIFileDeleteErrorS = 'FCI erreur de suppression du fichier'; AbFCIAddFileErrorS = 'FCI impossible d''ajouter le fichier'; AbFCICreateErrorS = 'FCI impossible de crer le contexte'; AbFCIFlushCabinetErrorS = 'FCI impossible de vider le cabinet'; AbFCIFlushFolderErrorS = 'FCI Impossible de vider le dossier'; AbFDICopyErrorS = 'FDI impossible d''enumrer les fichiers'; AbFDICreateErrorS = 'FDI impossible de crer le contexte'; AbInvalidCabTemplateS = 'Modle du fichier CAB invalide'; AbInvalidCabFileS = 'Fichier invalide - n''est pas un fichier cabinet'; AbZipStored = 'Stock'; AbZipShrunk = 'Compact'; AbZipReduced = 'Rduit'; AbZipImploded = 'Implos'; AbZipTokenized = 'Divis en plusieurs parties'; AbZipDeflated = 'Dflation'; AbZipDeflate64 = 'Dflation amliore'; AbZipDCLImploded = 'DCL Implos'; AbZipBzip2 = 'Bzip2'; AbZipLZMA = 'LZMA'; AbZipIBMTerse = 'IBM Terse'; AbZipLZ77 = 'IBM LZ77'; AbZipJPEG = 'JPEG'; AbZipWavPack = 'WavPack'; AbZipPPMd = 'PPMd'; AbZipUnknown = 'Inconnu (%d)'; AbZipBestMethod = 'Meilleure Mthode'; AbVersionFormatS = 'Version %s'; AbCompressedSizeFormatS = 'Taille compresse: %d'; AbUncompressedSizeFormatS = 'Taille non compresse: %d'; AbCompressionMethodFormatS = 'Mthode de compression: %s'; AbCompressionRatioFormatS = 'Ratio de compression: %2.0f%%'; AbCRCFormatS = 'CRC: %x'; AbReadOnlyS = 'r'; AbHiddenS = 'h'; AbSystemS = 's'; AbArchivedS = 'a'; AbEFAFormatS = 'Attribut du fichier externe: %s'; AbIFAFormatS = 'Type du fichier: %s'; AbTextS = 'Text'; AbBinaryS = 'Binaire'; AbEncryptionFormatS = 'Crypt: %s'; AbEncryptedS = 'Crypt'; AbNotEncryptedS = 'Non crypt'; AbUnknownS = 'Inconnu'; AbTimeStampFormatS = 'Heure: %s'; AbMadeByFormatS = 'Version utilise: %f'; AbNeededFormatS = 'Version d''extraction: %f'; AbCommentFormatS = 'Commentaire: %s'; AbDefaultExtS = '*.zip'; AbFilterS = 'Archives PKZip (*.zip)|*.zip|Archives Auto extractibles (*.exe)|*.exe|Tous les fichiers (*.*)|*.*'; AbFileNameTitleS = 'Slectionner un fichier'; AbOKS = 'OK'; AbCancelS = 'Annuler'; AbSelectDirectoryS = 'Slectionner un Dossier'; AbEnterPasswordS = 'Saisir Mot de passe'; AbPasswordS = '&Mot de passe'; AbVerifyS = '&Vrifier'; AbCabExtS = '*.cab'; AbCabFilterS = 'Archives Cabinet (*.cab)|*.CAB|Tous les fichiers (*.*)|*.*'; AbLogExtS = '*.txt'; AbLogFilterS = 'Fichiers Text (*.txt)|*.TXT|Tous les fichiers (*.*)|*.*'; AbExeExtS = '*.exe'; AbExeFilterS = 'Fichiers Zip auto-extractibles (*.exe)|*.EXE|Tous les fichiers (*.*)|*.*'; AbVMSReadTooManyBytesS = VMS: Tentative de l''ecture de trop d''octets [%d]'; AbVMSInvalidOriginS = 'VMS: Origine invalide %d, doit tre 0, 1, 2'; AbVMSErrorOpenSwapS = 'VMS: Impossible d''ouvrir le fichier d''change %s'; AbVMSSeekFailS = 'VMS: Impossible de se dplacer dans le fichier d''change %s'; AbVMSReadFailS = 'VMS: impossible de lire %d octets du fichier d''change %s'; AbVMSWriteFailS = 'VMS: impossible d''crire %d octets dans le fichier d''change %s'; AbVMSWriteTooManyBytesS = 'VMS: tentative d''crire trop d''octets [%d]'; AbBBSReadTooManyBytesS = 'BBS: tentative de lecture de trop d''octets [%d]'; AbBBSSeekOutsideBufferS = 'BBS: la nouvelle position est en dehors du buffer'; AbBBSInvalidOriginS = 'BBS: Valeur d''origine invalide'; AbBBSWriteTooManyBytesS = 'BBS: tentative d''crire de trop d''octets [%d]'; AbSWSNotEndofStreamS = 'TabSlidingWindowStream.Write: Pas la fin du flux'; AbSWSSeekFailedS = 'TabSlidingWindowStream.bsWriteChunk: chec de recherche'; AbSWSWriteFailedS = 'TabSlidingWindowStream.bsWriteChunk: chec d''criture'; AbSWSInvalidOriginS = 'TabSlidingWindowStream.Seek: Origine incorrecte'; AbSWSInvalidNewOriginS = 'TabSlidingWindowStream.Seek: Nouvelle position incorrecte'; AbItemNameHeadingS = 'Nom'; AbPackedHeadingS = 'Compress'; AbMethodHeadingS = 'Mthode'; AbRatioHeadingS = 'Ratio (%)'; AbCRCHeadingS = 'CRC32'; AbFileAttrHeadingS = 'Attribut'; AbFileFormatHeadingS = 'Format'; AbEncryptionHeadingS = 'Crypt'; AbTimeStampHeadingS = 'Heure'; AbFileSizeHeadingS = 'Taille'; AbVersionMadeHeadingS = 'Version Utilise'; AbVersionNeededHeadingS = 'Version ncessaire'; AbPathHeadingS = 'Chemin'; AbPartialHeadingS = 'Partiel'; AbExecutableHeadingS = 'Excutable'; AbCabMethod0S = 'Aucune'; AbCabMethod1S = 'MSZip'; AbLtAddS = ' Ajout '; AbLtDeleteS = ' Supprim '; AbLtExtractS = ' Extrait '; AbLtFreshenS = ' Rafraichir '; AbLtMoveS = ' Dplac '; AbLtReplaceS = ' Remplac '; AbLtStartS = ' Connexion '; AbGzipInvalidS = 'Gzip Invalide'; AbGzipBadCRCS = 'Mauvais CRC'; AbGzipBadFileSizeS = 'Taille du fichier errone'; AbTarInvalidS = 'Tar invalide'; AbTarBadFileNameS = 'Nom de fichier trop long'; AbTarBadLinkNameS = 'Chemin du lien symbolique trop long'; AbTarBadOpS = 'Opration non supporte'; AbUnhandledEntityS = 'Entit non prise en charge'; { pre-defined "operating system" (really more FILE system) identifiers for the Gzip header } AbGzOsFat = 'Systme de fichier FAT (MS-DOS, OS/2, NT/Win32)'; AbGzOsAmiga = 'Amiga'; AbGzOsVMS = 'VMS (ou OpenVMS)'; AbGzOsUnix = 'Unix'; AbGzOsVM_CMS = 'VM/CMS'; AbGzOsAtari = 'Atari TOS'; AbGzOsHPFS = 'Systme de fichier HPFS (OS/2, NT)'; AbGzOsMacintosh = 'Macintosh'; AbGzOsZ_System = 'Z-System'; AbGzOsCP_M = 'CP/M'; AbGzOsTOPS_20 = 'TOPS-20'; AbGzOsNTFS = 'Systme de fichier NTFS (NT)'; AbGzOsQDOS = 'QDOS'; AbGzOsAcornRISCOS = 'Acorn RISCOS'; AbGzOsVFAT = 'Systme de fichier VFAT (Win95, NT)'; AbGzOsMVS = 'MVS'; AbGzOsBeOS = 'BeOS (BeBox ou PowerMac)'; AbGzOsTandem = 'Tandem/NSK'; AbGzOsTHEOS = 'THEOS'; AbGzOsunknown = 'Inconnu'; AbGzOsUndefined = 'ID non dfini par gzip'; {!!.03 - Moved from AbCompnd.inc } { Compound File specific error messages } resourcestring AbCmpndIndexOutOfBounds = 'Indice hors limite'; AbCmpndBusyUpdating = 'Fichier compos est occup par la mise jour'; AbCmpndInvalidFile = 'Fichier compos invalide'; AbCmpndFileNotFound = 'Fichier/Dossier introuvable'; AbCmpndFolderNotEmpty = 'Dossier n''est pas vide'; AbCmpndExceedsMaxFileSize = 'Taille du fichier dpasse la limite maximale'; {!!.03 - End Moved } implementation end. ================================================ FILE: lib/abbrevia/localization/AbResString.pas.nl ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Rudy Velthuis * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* Abbrevia: AbResString.pas 3.05 *} {*********************************************************} {* Abbrevia: Resource strings, Dutch localization *} {*********************************************************} unit AbResString; interface resourcestring AbErrZipInvalidS = 'Ongeldig bestand - geen PKZip bestand'; AbZipVersionNeededS = 'Kan bestand niet ontpakken - nieuwere versie nodig'; AbUnknownCompressionMethodS = 'Kan bestand niet ontpakken - niet ondersteunde compressiemethode'; AbNoExtractionMethodS = 'Kan bestand niet ontpakken - ontpakken wordt niet ondersteund'; AbInvalidPasswordS = 'Kan bestand niet ontpakken - ongeldig paswoord'; AbNoInsertionMethodS = 'Kan bestand niet invoegen - invoegen wordt niet ondersteund'; AbInvalidFactorS = 'Ongeldige reductiefactor'; AbDuplicateNameS = 'Kan het bestand niet invoegen - dupliceert opgeslagen naam'; AbUnsupportedCompressionMethodS = 'Kan het bestand niet invoegen - niet ondersteunde compressiemethode'; AbUserAbortS = 'Proces werd door gebruiker afgebroken'; AbArchiveBusyS = 'Archief is bezig - kan nieuwe aanvraag niet bewerken'; AbLastDiskRequestS = 'Plaats laatste diskette van opgesplitst archief'; AbDiskRequestS = 'Plaats diskette'; AbImageRequestS = 'Bestandsnaam afbeelding'; AbBadSpanStreamS = 'Opgesplitste archieven moeten als bestandsstroom geopend worden'; AbDiskNumRequestS = 'Plaats diskette %d van opgesplitst archief'; AbImageNumRequestS = 'Plaats segment %d van opgesplitst archief'; AbNoOverwriteSpanStreamS = 'Kan bestaand opgesplitst archief niet veranderen'; AbNoSpannedSelfExtractS = 'Kan geen zelfontpakkend opgesplitst archief aanmaken'; AbBlankDiskS = 'Plaats een lege diskette'; AbStreamFullS = 'Schrijffout stroom'; AbNoSuchDirectoryS = 'Directory bestaat niet'; AbInflateBlockErrorS = 'Kan blok niet ontpakken'; AbBadStreamTypeS = 'Ongeldige stroom'; AbTruncateErrorS = 'Fout bij het afknotten van het zip bestand'; AbZipBadCRCS = 'Mislukte CRC controle'; AbZipBadStubS = 'Stomp moet uitvoerbaar bestand zijn'; AbFileNotFoundS = 'Bestand niet gevonden'; AbInvalidLFHS = 'Ongeldig Local File Header element'; AbNoArchiveS = 'Archief bestaat niet - lege bestandsnaam'; AbReadErrorS = 'Fout tijdens lezen van archief'; AbInvalidIndexS = 'Ongeldige index van archiefelement'; AbInvalidThresholdS = 'Ongeldige drempel van archiefgrootte'; AbUnhandledFileTypeS = 'Onbekend archieftype'; AbSpanningNotSupportedS = 'Opsplitsen wordt voor dit archieftype niet ondersteund'; AbLogCreateErrorS = 'Fout tijdens aanmaken van protocolbestand'; AbMoveFileErrorS = 'Fout tijdens het verplaatsen van bestand %s naar %s'; AbFileSizeTooBigS = 'Bestand is te groot voor dit archieftype'; AbNoCabinetDllErrorS = 'Kan bestand cabinet.dll niet laden'; AbFCIFileOpenErrorS = 'FCI kan bestand niet openen'; AbFCIFileReadErrorS = 'FCI kan bestand niet lezen'; AbFCIFileWriteErrorS = 'FCI kan bestand niet schrijven'; AbFCIFileCloseErrorS = 'FCI fout tijdens sluiten van bestand'; AbFCIFileSeekErrorS = 'FCI fout tijdens positioneren in bestand'; AbFCIFileDeleteErrorS = 'FCI fout tijdens wissen van bestand'; AbFCIAddFileErrorS = 'FCI kan bestand niet toevoegen'; AbFCICreateErrorS = 'FCI kan context niet aanmaken'; AbFCIFlushCabinetErrorS = 'FCI kan cabinet niet legen'; AbFCIFlushFolderErrorS = 'FCI kan folder niet legen'; AbFDICopyErrorS = 'FDI kann bestanden niet opsommen'; AbFDICreateErrorS = 'FDI kan context niet aanmaken'; AbInvalidCabTemplateS = 'Ongeldige sjabloon voor cabinetsbestand'; AbInvalidCabFileS = 'Ongeldig bestand - geen cabinetsbestand'; AbZipStored = 'Opgeslagen'; AbZipShrunk = 'Gekrompen'; AbZipReduced = 'Gereduceerd'; AbZipImploded = 'Gemplodeerd'; AbZipTokenized = 'In symbolen gepakt'; AbZipDeflated = 'Gedeflationeerd'; AbZipDeflate64 = 'Uitgebreid gedeflationeerd'; AbZipDCLImploded = 'DCL gemplodeerd'; AbZipBzip2 = 'Bzip2'; AbZipLZMA = 'LZMA'; AbZipIBMTerse = 'IBM Terse'; AbZipLZ77 = 'IBM LZ77'; AbZipJPEG = 'JPEG'; AbZipWavPack = 'WavPack'; AbZipPPMd = 'PPMd'; AbZipUnknown = 'Onbekend (%d)'; AbZipBestMethod = 'Beste methode'; AbVersionFormatS = 'Versie %s'; AbCompressedSizeFormatS = 'Gecomprimeerde grootte: %d'; AbUncompressedSizeFormatS = 'Ongecomprimeerde grootte: %d'; AbCompressionMethodFormatS = 'Compressiemethode: %s'; AbCompressionRatioFormatS = 'Compressieverhouding: %2.0f%%'; AbCRCFormatS = 'CRC: %x'; AbReadOnlyS = 'r'; AbHiddenS = 'h'; AbSystemS = 's'; AbArchivedS = 'a'; AbEFAFormatS = 'Externe bestandsattributen: %s'; AbIFAFormatS = 'Bestandstype: %s'; AbTextS = 'Tekst'; AbBinaryS = 'Binair'; AbEncryptionFormatS = 'Versleuteling: %s'; AbEncryptedS = 'Versleuteld'; AbNotEncryptedS = 'Niet versleuteld'; AbUnknownS = 'Onbekend'; AbTimeStampFormatS = 'Tijdstempel: %s'; AbMadeByFormatS = 'Gemaakt met versie: %f'; AbNeededFormatS = 'Versie benodigd voor ontpakken: %f'; AbCommentFormatS = 'Opmerking: %s'; AbDefaultExtS = '*.zip'; AbFilterS = 'PKZip Archieven (*.zip)|*.zip|Zelfontpakkende Archieven (*.exe)|*.exe|Alle Bestanden (*.*)|*.*'; AbFileNameTitleS = 'Bestandsnaam Kiezen'; AbOKS = 'OK'; AbCancelS = 'Verlaten'; AbSelectDirectoryS = 'Bestand kiezen'; AbEnterPasswordS = 'Paswoord ingeven'; AbPasswordS = '&Paswoord'; AbVerifyS = '&Verificeren'; AbCabExtS = '*.cab'; AbCabFilterS = 'Cabinetsarchieven (*.cab)|*.CAB|Alle Bestanden (*.*)|*.*'; AbLogExtS = '*.txt'; AbLogFilterS = 'Tekstbestanden (*.txt)|*.TXT|Alle Bestanden (*.*)|*.*'; AbExeExtS = '*.exe'; AbExeFilterS = 'Zelfontpakkende Zip Bestanden (*.exe)|*.EXE|Alle Bestanden (*.*)|*.*'; AbVMSReadTooManyBytesS = 'VMS: Anvraag om te veel byte [%d] te lezen'; AbVMSInvalidOriginS = 'VMS: Ongeldige oorsprong %d, moet 0, 1 of 2 zijn'; AbVMSErrorOpenSwapS = 'VMS: Kan wisselbestand %s niet openen'; AbVMSSeekFailS = 'VMS: Kon niet in wisselbestand %s positioneren'; AbVMSReadFailS = 'VMS: Kon %d byte in wisselbestand %s niet lezen'; AbVMSWriteFailS = 'VMS: Kon %d byte niet in wisselbestand %s schrijven'; AbVMSWriteTooManyBytesS = 'VMS: Anvraag om te veel byte [%d] te schrijven'; AbBBSReadTooManyBytesS = 'BBS: Anvraag om te veel byte [%d] te lezen'; AbBBSSeekOutsideBufferS = 'BBS: Nieuwe positie is buiten de buffer'; AbBBSInvalidOriginS = 'BBS: Ongeldige oorsprongswaarde'; AbBBSWriteTooManyBytesS = 'BBS: Anvraag om te veel byte [%d] te schrijven'; AbSWSNotEndofStreamS = 'TabSlidingWindowStream.Write: Niet aan eind van stroom'; AbSWSSeekFailedS = 'TabSlidingWindowStream.bsWriteChunk: Positioneren mislukt'; AbSWSWriteFailedS = 'TabSlidingWindowStream.bsWriteChunk: Schrijven mislukt'; AbSWSInvalidOriginS = 'TabSlidingWindowStream.Seek: Ongeldige oorsprong'; AbSWSInvalidNewOriginS = 'TabSlidingWindowStream.Seek: Ongeldige nieuwe positie'; AbItemNameHeadingS = 'Naam'; AbPackedHeadingS = 'Gepakt'; AbMethodHeadingS = 'Methode'; AbRatioHeadingS = 'Besparing (%)'; AbCRCHeadingS = 'CRC32'; AbFileAttrHeadingS = 'Attribuut'; AbFileFormatHeadingS = 'Formaat'; AbEncryptionHeadingS = 'Versleuteld'; AbTimeStampHeadingS = 'Tijdstempel'; AbFileSizeHeadingS = 'Grootte'; AbVersionMadeHeadingS = 'Gebruikte versie'; AbVersionNeededHeadingS = 'Benodigde versie'; AbPathHeadingS = 'Pad'; AbPartialHeadingS = 'Partieel'; AbExecutableHeadingS = 'Uitvoerbaar'; AbCabMethod0S = 'Geen'; AbCabMethod1S = 'MSZip'; AbLtAddS = ' toegevoegd '; AbLtDeleteS = ' gewist '; AbLtExtractS = ' ontpakt '; AbLtFreshenS = ' geactualiseerd '; AbLtMoveS = ' verplaatst '; AbLtReplaceS = ' vervangen '; AbLtStartS = ' geprotocolleerd '; AbGzipInvalidS = 'Ongeldige Gzip'; AbGzipBadCRCS = 'Ongeldige CRC'; AbGzipBadFileSizeS = 'Ongeldige bestandsgrootte'; AbTarInvalidS = 'Ongeldige Tar'; AbTarBadFileNameS = 'Bestandsnaam te lang'; AbTarBadLinkNameS = 'Link naam te lang'; AbTarBadOpS = 'Niet ondersteunde functie'; AbUnhandledEntityS = 'Niet behandelde entiteit'; { pre-defined "operating system" (really more FILE system) identifiers for the Gzip header } AbGzOsFat = 'FAT Bestandssysteem (MS-DOS, OS/2, NT/Win32)'; AbGzOsAmiga = 'Amiga'; AbGzOsVMS = 'VMS (oder OpenVMS)'; AbGzOsUnix = 'Unix'; AbGzOsVM_CMS = 'VM/CMS'; AbGzOsAtari = 'Atari TOS'; AbGzOsHPFS = 'HPFS Bestandssysteem (OS/2, NT)'; AbGzOsMacintosh = 'Macintosh'; AbGzOsZ_System = 'Z-System'; AbGzOsCP_M = 'CP/M'; AbGzOsTOPS_20 = 'TOPS-20'; AbGzOsNTFS = 'NTFS Bestandssysteem (NT)'; AbGzOsQDOS = 'QDOS'; AbGzOsAcornRISCOS = 'Acorn RISC OS'; AbGzOsVFAT = 'VFAT Bestandssysteem (Win95, NT)'; AbGzOsMVS = 'MVS'; AbGzOsBeOS = 'BeOS (BeBox of PowerMac)'; AbGzOsTandem = 'Tandem/NSK'; AbGzOsTHEOS = 'THEOS'; AbGzOsunknown = 'onbekend'; AbGzOsUndefined = 'ID is Gzip niet bekend'; {!!.03 - Moved from AbCompnd.inc } { Compound File specific error messages } resourcestring AbCmpndIndexOutOfBounds = 'Index niet in toegelaten bereik'; AbCmpndBusyUpdating = 'Samengesteld bestand wordt geactualiseerd'; AbCmpndInvalidFile = 'Ongeldig samengesteld bestand '; AbCmpndFileNotFound = 'Bestand/directory niet gevonden'; AbCmpndFolderNotEmpty = 'Directory is niet leeg'; AbCmpndExceedsMaxFileSize = 'Bestandsgrootte overschrijdt toegelaten maximum'; {!!.03 - End Moved } implementation end. ================================================ FILE: lib/abbrevia/localization/AbResString.pas.ru ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Pavel Koptev, Roman Kassebaum * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* Abbrevia: AbResString.pas *} {*********************************************************} {* Abbrevia: Resource strings, Russian localization *} {*********************************************************} {* Warning: This file is UTF-8 encoded *} {*********************************************************} {* You need D2009 or higher to compile this unit *} {*********************************************************} unit AbResString; interface resourcestring AbErrZipInvalidS = 'Формат архива не соответствует PKZip-формату'; AbZipVersionNeededS = 'Действие невозможно. Файл запакован более новой версией программы'; AbUnknownCompressionMethodS = 'Действие невозможно. Нераспознанный метод сжатия'; AbNoExtractionMethodS = 'Действие невозможно. Не доступен метод распаковки архива'; AbInvalidPasswordS = 'Действие невозможно. Неверный пароль'; AbNoInsertionMethodS = 'Действие невозможно. Архивом не поддерживается добавление новых файлов'; AbInvalidFactorS = 'Недействительный фактор сжатия'; AbDuplicateNameS = 'Действие невозможно. Файл с таким именем в архиве уже присутствует'; AbUnsupportedCompressionMethodS = 'Действие невозможно. Неподдерживаемый метод сжатия'; AbUserAbortS = 'Действие отменено пользователем'; AbArchiveBusyS = 'Действие невозможно. Архив поврежден'; AbLastDiskRequestS = 'Вставьте последнюю дискету в дисковод'; AbDiskRequestS = 'Вставьте дискету в дисковод'; AbImageRequestS = 'Имя образа'; AbBadSpanStreamS = 'Многотомные архивы открываются как файловый поток'; AbDiskNumRequestS = 'Вставьте %d дискету в дисковод'; AbImageNumRequestS = 'Укажите расположение %d тома архива'; AbNoOverwriteSpanStreamS = 'Невозможно изменить существующий многотомный архив'; AbNoSpannedSelfExtractS = 'Невозможно создать многотомный SFX-Архив'; AbBlankDiskS = 'Вставьте чистую дискету в дисковод'; AbStreamFullS = 'Ошибка записи в память'; AbNoSuchDirectoryS = 'Папка не существует'; AbInflateBlockErrorS = 'Блок данных не может быть распакован'; AbBadStreamTypeS = 'Недействительный поток'; AbTruncateErrorS = 'Ошибка при разделении Zip-Файла'; AbZipBadCRCS = 'Не верная контрольная сумма'; AbZipBadStubS = 'Корневой элемент архива должен быть исполняемым файлом'; AbFileNotFoundS = 'Файл не найден'; AbInvalidLFHS = 'Неверное начало файла'; AbNoArchiveS = 'Архив не существует'; AbReadErrorS = 'Ошибка чтения архива'; AbInvalidIndexS = 'Неверный индекс елемента архива'; AbInvalidThresholdS = 'Неверный размер частей архива'; AbUnhandledFileTypeS = 'Неизвестный архив'; AbSpanningNotSupportedS = 'Многотомность не поддерживается этим типом архивов'; AbLogCreateErrorS = 'Ошибка при создании файла протокола'; AbMoveFileErrorS = 'Ошибка при перемещении файла %s в %s'; AbFileSizeTooBigS = 'Файл слишком велик для выбранного типа архива'; AbNoCabinetDllErrorS = 'Библиотека cabinet.dll не может быть загружена'; AbFCIFileOpenErrorS = 'FCI невозможно открыть файл'; AbFCIFileReadErrorS = 'FCI невозможно прочитать файл'; AbFCIFileWriteErrorS = 'FCI невозможно записать файл'; AbFCIFileCloseErrorS = 'FCI ошибка при закрытии файла'; AbFCIFileSeekErrorS = 'FCI ошибка при поиске в файле'; AbFCIFileDeleteErrorS = 'FCI ошибка при удалении файла'; AbFCIAddFileErrorS = 'FCI невозможно добавить файл'; AbFCICreateErrorS = 'FCI ошибка создания'; AbFCIFlushCabinetErrorS = 'FCI Cabinet-архив не может быть создан'; AbFCIFlushFolderErrorS = 'FCI невозможно удалить все файлы из папки'; AbFDICopyErrorS = 'FDI невозможно пересчитать файлы'; AbFDICreateErrorS = 'FDI ошибка создания'; AbInvalidCabTemplateS = 'Неверный шаблон Cabinet-файла'; AbInvalidCabFileS = ' Неверный Cabinet-файл'; AbZipStored = 'Сохранено'; AbZipShrunk = 'Сжато'; AbZipReduced = 'Сжато'; AbZipImploded = 'Сжато'; AbZipTokenized = 'Разделен на части'; AbZipDeflated = 'Сжато'; AbZipDeflate64 = 'Лучшее сжатие'; AbZipDCLImploded = 'DCL Сжато'; AbZipBzip2 = 'Bzip2'; AbZipLZMA = 'LZMA'; AbZipIBMTerse = 'IBM Terse'; AbZipLZ77 = 'IBM LZ77'; AbZipJPEG = 'JPEG'; AbZipWavPack = 'WavPack'; AbZipPPMd = 'PPMd'; AbZipUnknown = 'Неизвестно (%d)'; AbZipBestMethod = 'Лучший метод'; AbVersionFormatS = 'Версия %s'; AbCompressedSizeFormatS = 'Размер в архиве: %d'; AbUncompressedSizeFormatS = 'Размер: %d'; AbCompressionMethodFormatS = 'Метод сжатия: %s'; AbCompressionRatioFormatS = 'Степень сжатия: %2.0f%%'; AbCRCFormatS = 'CRC: %x'; AbReadOnlyS = 'r'; AbHiddenS = 'h'; AbSystemS = 's'; AbArchivedS = 'a'; AbEFAFormatS = 'Внешние атрибуты файла: %s'; AbIFAFormatS = 'Тип файла: %s'; AbTextS = 'Текст'; AbBinaryS = 'Двоичный'; AbEncryptionFormatS = 'Шифрование: %s'; AbEncryptedS = 'Зашифрован'; AbNotEncryptedS = 'Не зашифрован'; AbUnknownS = 'Неизвестно'; AbTimeStampFormatS = 'Формат времени: %s'; AbMadeByFormatS = 'Версия программы создания: %f'; AbNeededFormatS = 'Для распаковки требуется версия: %f'; AbCommentFormatS = 'Комментарии: %s'; AbDefaultExtS = '*.zip'; AbFilterS = 'PKZip-архив (*.zip)|*.zip|SFX-Архив (*.exe)|*.exe|Все файлы (*.*)|*.*'; AbFileNameTitleS = 'Выберите имя файла'; AbOKS = 'OK'; AbCancelS = 'Отмена'; AbSelectDirectoryS = 'Выберете папку'; AbEnterPasswordS = 'Введите пароль'; AbPasswordS = '&Пароль'; AbVerifyS = '&Проверка'; AbCabExtS = '*.cab'; AbCabFilterS = 'Cabinet-архив (*.cab)|*.CAB|Все файлы (*.*)|*.*'; AbLogExtS = '*.txt'; AbLogFilterS = 'Текстовые файлы (*.txt)|*.TXT|Все файлы (*.*)|*.*'; AbExeExtS = '*.exe'; AbExeFilterS = 'SFX-архивы (*.exe)|*.EXE|Все файлы (*.*)|*.*'; AbVMSReadTooManyBytesS = 'VMS: попытка чтения слишком большого числа байт [%d]'; AbVMSInvalidOriginS = 'VMS: недействительный источник %d, разрешены 0, 1, 2'; AbVMSErrorOpenSwapS = 'VMS: Невозможно открыть файл %s'; AbVMSSeekFailS = 'VMS: Невозможно осуществить поиск в файле %s'; AbVMSReadFailS = 'VMS: Невозможно прочитать файл %s'; AbVMSWriteFailS = 'VMS: Невозможно %d байт записать в файл %s'; AbVMSWriteTooManyBytesS = 'VMS: попытка записи слишком большого числа байт [%d]'; AbBBSReadTooManyBytesS = 'BBS: попытка чтения слишком большого числа байт [%d]'; AbBBSSeekOutsideBufferS = 'BBS: позиция находится вне буфера'; AbBBSInvalidOriginS = 'BBS: недействительно предыдущее значение'; AbBBSWriteTooManyBytesS = 'BBS: попытка записи слишком большого числа байт [%d]'; AbSWSNotEndofStreamS = 'TabSlidingWindowStream.Write: попытка записи данных не в конец потока'; AbSWSSeekFailedS = 'TabSlidingWindowStream.bsWriteChunk: поиск не удался'; AbSWSWriteFailedS = 'TabSlidingWindowStream.bsWriteChunk: запись не удалась'; AbSWSInvalidOriginS = 'TabSlidingWindowStream.Seek: Недействительный источник'; AbSWSInvalidNewOriginS = 'TabSlidingWindowStream.Seek: недействительная новая позиция'; AbItemNameHeadingS = 'Имя'; AbPackedHeadingS = 'Сжато'; AbMethodHeadingS = 'Метод'; AbRatioHeadingS = 'Коэффициент сжатия (%)'; AbCRCHeadingS = 'CRC32'; AbFileAttrHeadingS = 'Атрибуты'; AbFileFormatHeadingS = 'Формат'; AbEncryptionHeadingS = 'Шифрование'; AbTimeStampHeadingS = 'Время'; AbFileSizeHeadingS = 'Размер'; AbVersionMadeHeadingS = 'Использована версия'; AbVersionNeededHeadingS = 'Необходима версия'; AbPathHeadingS = 'Путь'; AbPartialHeadingS = 'Частично'; AbExecutableHeadingS = 'Выполнимо'; AbCabMethod0S = 'нет'; AbCabMethod1S = 'MSZip'; AbLtAddS = ' вставлен '; AbLtDeleteS = ' удален '; AbLtExtractS = ' распакован '; AbLtFreshenS = ' обновлен '; AbLtMoveS = ' перемещен '; AbLtReplaceS = ' заменено '; AbLtStartS = ' запротоколировано '; AbGzipInvalidS = 'Недействительный Gzip'; AbGzipBadCRCS = 'Недействительная контрольная сумма'; AbGzipBadFileSizeS = 'Недействительный размер файла'; AbTarInvalidS = 'Недествительный Tar-архив'; AbTarBadFileNameS = 'Слишком длинное имя файла'; AbTarBadLinkNameS = 'Слишком длинная ссылка'; AbTarBadOpS = 'Неподдерживаемая операция'; AbUnhandledEntityS = 'Необрабатываемый объект'; { pre-defined "operating system" (really more FILE system) identifiers for the Gzip header } AbGzOsFat = 'FAT файловая система (MS-DOS, OS/2, NT/Win32)'; AbGzOsAmiga = 'Amiga'; AbGzOsVMS = 'VMS (или OpenVMS)'; AbGzOsUnix = 'Unix'; AbGzOsVM_CMS = 'VM/CMS'; AbGzOsAtari = 'Atari TOS'; AbGzOsHPFS = 'HPFS файловая система (OS/2, NT)'; AbGzOsMacintosh = 'Macintosh'; AbGzOsZ_System = 'Z-System'; AbGzOsCP_M = 'CP/M'; AbGzOsTOPS_20 = 'TOPS-20'; AbGzOsNTFS = 'NTFS файловая система (NT)'; AbGzOsQDOS = 'QDOS'; AbGzOsAcornRISCOS = 'Acorn RISCOS'; AbGzOsVFAT = 'VFAT файловая система (Win95, NT)'; AbGzOsMVS = 'MVS'; AbGzOsBeOS = 'BeOS (BeBox или PowerMac)'; AbGzOsTandem = 'Tandem/NSK'; AbGzOsTHEOS = 'THEOS'; AbGzOsunknown = 'неизвестно'; AbGzOsUndefined = 'Идентификационный номер для Gzip не известен'; {!!.03 - Moved from AbCompnd.inc } { Compound File specific error messages } resourcestring AbCmpndIndexOutOfBounds = 'Индекс выходит за пределы допустимого диапазона'; AbCmpndBusyUpdating = 'Обновляется файл связок'; AbCmpndInvalidFile = 'Недействительный файл связок'; AbCmpndFileNotFound = 'Файл или папка не найдены'; AbCmpndFolderNotEmpty = 'Папка не пуста'; AbCmpndExceedsMaxFileSize = 'Допустимый размер файла был превышен'; {!!.03 - End Moved } implementation end. ================================================ FILE: lib/abbrevia/localization/AbResString.pas.tr ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Durali Kiraz 2014-05-06 * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* Abbrevia: AbResString.pas *} {*********************************************************} {* Abbrevia: Resource strings, Turkish localization *} {*********************************************************} {* Encoded in Code Page 1252 (Windows Latin 5 Turkish) *} {*********************************************************} unit AbResString; {$I AbDefine.inc} interface resourcestring AbErrZipInvalidS = 'Geersiz dosya - bir PKZip dosyas deil'; AbZipVersionNeededS = 'Dosya Ayklanamyor - daha yeni bir srm gerekli.'; AbUnknownCompressionMethodS = 'Dosya Ayklanamyor - desteklenmeyen sktrma yntemi'; AbNoExtractionMethodS = 'Dosya Ayklanamyor - salanan bir karma destei yok'; AbInvalidPasswordS = 'Dosya Ayklanamyor - geersiz ifre'; AbNoInsertionMethodS = 'Dosya Eklenemiyor - salanan bir ekleme destei yok'; AbInvalidFactorS = 'Geersiz Faktr azaltn'; AbDuplicateNameS = 'Dosya Eklenemiyor - saklanan dosya ad ift'; AbUnsupportedCompressionMethodS = 'Dosya Eklenemiyor - desteklenmeyen sktrma yntemi'; AbUserAbortS = 'Sre kullanc tarafndan iptal edildi'; AbArchiveBusyS = 'Ariv megul - yeni istekleri ileyemiyor'; AbLastDiskRequestS = 'Yaylm disk setinde son diski yerletirin'; AbDiskRequestS = 'Disket takn'; AbImageRequestS = 'Kalp dosya ad'; AbBadSpanStreamS = 'Yaylm arivler dosya akkanlar gibi almaldr'; AbDiskNumRequestS = 'Yaylm disk setinin %d numaral diskini ekleyin'; AbImageNumRequestS = 'Yaylm dosya setinin aralkl %d numaral dosyasn ekleyin '; AbNoOverwriteSpanStreamS = 'Varolan Yaylm disk seti gncelleme yaplamaz'; AbNoSpannedSelfExtractS = 'Bir kendi kendini ayklayan(exe dosyas) disk seti yaplamaz'; AbBlankDiskS = 'Bo bir disket ekle'; AbStreamFullS = 'Akkan yazma hatas'; AbNoSuchDirectoryS = 'Klasr mevcut deil'; AbInflateBlockErrorS = 'Blou iiremezsin (connot inflate)'; AbBadStreamTypeS = 'Geersiz Akkan'; AbTruncateErrorS = 'Zip dosyas hata ile kesiliyor'; AbZipBadCRCS = 'Baarsz CRC kontrol'; AbZipBadStubS = 'Stub bir altrlabilir(exe) olmal'; AbFileNotFoundS = 'Dosya bulunamad'; AbInvalidLFHS = 'Geersiz Yerel Dosya Bal giri'; AbNoArchiveS = 'Ariv mevcut deil - Dosyaad bo'; AbReadErrorS = 'Okuma hatas arivi'; AbInvalidIndexS = 'Geersiz ariv e Endeksi'; AbInvalidThresholdS = 'Geersiz ariv boyutu eii'; AbUnhandledFileTypeS = 'lenmeyen Ariv Tr'; AbSpanningNotSupportedS = 'Yaylma bu Ariv tr tarafndan desteklenmiyor '; AbLogCreateErrorS = 'Gnlk Dosyas olutururken hata'; AbMoveFileErrorS = '%s kaynandan %s hedefine Dosya Tamada Hata'; AbFileSizeTooBigS = 'Dosya boyutu ariv tr iin ok byk'; AbNoCabinetDllErrorS = 'cabinet.dll yklenemedi'; AbFCIFileOpenErrorS = 'FCI dosya alamad'; AbFCIFileReadErrorS = 'FCI dosya okunmad'; AbFCIFileWriteErrorS = 'FCI dosya yazlamad'; AbFCIFileCloseErrorS = 'FCI dosya kapatmada hata'; AbFCIFileSeekErrorS = 'FCI dosya konumlanma hatas'; AbFCIFileDeleteErrorS = 'FCI dosya silme hatas'; AbFCIAddFileErrorS = 'FCI dosya eklenemedi'; AbFCICreateErrorS = 'FCI ierii oluturulamyor'; AbFCIFlushCabinetErrorS = 'FCI kabini flush yaplamyor'; AbFCIFlushFolderErrorS = 'FCI klasr flush yaplamyor'; AbFDICopyErrorS = 'FDI dosyalar numaralandrma yaplamyor'; AbFDICreateErrorS = 'FDI ierii oluturulamyor'; AbInvalidCabTemplateS = 'Geersiz cab dosya ablonu'; AbInvalidCabFileS = 'Geersiz Dosya - bir kabin dosyas deil'; AbZipStored = 'Depoland'; AbZipShrunk = 'Bzlm'; AbZipReduced = 'Azaltlm'; AbZipImploded = 'ine kt'; AbZipTokenized = 'Simgeletirilmi'; AbZipDeflated = 'nik'; AbZipDeflate64 = 'Gelitirilmi niklik'; AbZipDCLImploded = 'DCL Bzlm'; AbZipBzip2 = 'Bzip2'; AbZipLZMA = 'LZMA'; AbZipIBMTerse = 'IBM Terse'; AbZipLZ77 = 'IBM LZ77'; AbZipJPEG = 'JPEG'; AbZipWavPack = 'WavPack'; AbZipPPMd = 'PPMd'; AbZipUnknown = 'Bilinmeyen (%d)'; AbZipBestMethod = 'En yi Yntem'; AbVersionFormatS = 'Srm %s'; AbCompressedSizeFormatS = 'Sktrlm uzunluk: %d'; AbUncompressedSizeFormatS = 'Sktrlmam uzunluk: %d'; AbCompressionMethodFormatS = 'Sktrma Yntemi: %s'; AbCompressionRatioFormatS = 'Sktrma Oran: %2.0f%%'; AbCRCFormatS = 'CRC: %x'; AbReadOnlyS = 'r'; AbHiddenS = 'h'; AbSystemS = 's'; AbArchivedS = 'a'; AbEFAFormatS = 'Harici Dosya zellikleri: %s'; AbIFAFormatS = 'Dosya Tr: %s'; AbTextS = 'Text'; AbBinaryS = 'Binary'; AbEncryptionFormatS = 'ifreleme: %s'; AbEncryptedS = 'ifrelenmi'; AbNotEncryptedS = 'ifreli Deil'; AbUnknownS = 'Bilinmiyor'; AbTimeStampFormatS = 'Zaman Damgas: %s'; AbMadeByFormatS = 'Srm Yapan: %f'; AbNeededFormatS = 'Ayklamaya Gerekli Srm: %f'; AbCommentFormatS = 'Aklama: %s'; AbDefaultExtS = '*.zip'; AbFilterS = 'PKZip Arivleri (*.zip)|*.zip|Kendinden Ayklanabilen Arivler (*.exe)|*.exe|Tm Dosyalar (*.*)|*.*'; AbFileNameTitleS = 'Dosya Ad Se'; AbOKS = 'Tamam'; AbCancelS = 'Vazge'; AbSelectDirectoryS = 'Klasr Se'; AbEnterPasswordS = 'ifre Gir'; AbPasswordS = 'i&fre'; AbVerifyS = '&Dorula'; AbCabExtS = '*.cab'; AbCabFilterS = 'Kabin Arivleri (*.cab)|*.CAB|Tm Dosyalar (*.*)|*.*'; AbLogExtS = '*.txt'; AbLogFilterS = 'Metin Dosyalar (*.txt)|*.TXT|Tm Dosyalar (*.*)|*.*'; AbExeExtS = '*.exe'; AbExeFilterS = 'Kendinden-Ayklanabilen Zip Dosyalar (*.exe)|*.EXE|Tm Dosyalar (*.*)|*.*'; AbVMSReadTooManyBytesS = 'VMS: ok bayt okuma istei [%d]'; AbVMSInvalidOriginS = 'VMS: %d kkeni geersiz. Geerli deerler 0, 1, 2 olmaldr'; AbVMSErrorOpenSwapS = 'VMS: %s takas dosyas alamyor'; AbVMSSeekFailS = 'VMS: %s takas dosyasnda arama baarsz oldu'; AbVMSReadFailS = 'VMS: %d bayt %s takas dosyasndan okunurken baarsz oldu'; AbVMSWriteFailS = 'VMS: %d bayt %s takas dosyasndan yazlrken baarsz oldu'; AbVMSWriteTooManyBytesS = 'VMS: ok fazla bayt yazma istei [%d]'; AbBBSReadTooManyBytesS = 'BBS: ok fazla bayt okuma istei [%d]'; AbBBSSeekOutsideBufferS = 'BBS: Yeni konum arabellek dndadr'; AbBBSInvalidOriginS = 'BBS: Geersiz Kken deeri'; AbBBSWriteTooManyBytesS = 'BBS: ok fazla bayt yazma istei [%d]'; AbSWSNotEndofStreamS = 'TabSlidingWindowStream.Write: Akn sonunda deil'; AbSWSSeekFailedS = 'TabSlidingWindowStream.bsWriteChunk: Arama baarsz oldu'; AbSWSWriteFailedS = 'TabSlidingWindowStream.bsWriteChunk: Yazma baarsz oldu'; AbSWSInvalidOriginS = 'TabSlidingWindowStream.Seek: Geersiz kken'; AbSWSInvalidNewOriginS = 'TabSlidingWindowStream.Seek: Geersiz yeni konum'; AbItemNameHeadingS = 'Ad'; AbPackedHeadingS = 'Paketli'; AbMethodHeadingS = 'Yntemi'; AbRatioHeadingS = 'Oran (%)'; AbCRCHeadingS = 'CRC32'; AbFileAttrHeadingS = 'Nitelikler'; AbFileFormatHeadingS = 'Biim'; AbEncryptionHeadingS = 'ifrelenmi'; AbTimeStampHeadingS = 'Zaman Damgas'; AbFileSizeHeadingS = 'Uzunluk'; AbVersionMadeHeadingS = 'Srm Yapm'; AbVersionNeededHeadingS = 'Srm Gerekli'; AbPathHeadingS = 'Yolu'; AbPartialHeadingS = 'Ksmi'; AbExecutableHeadingS = 'altrlabilir'; AbFileTypeHeadingS = 'Tr'; AbLastModifiedHeadingS = 'Deitirilmi'; AbCabMethod0S = 'None'; AbCabMethod1S = 'MSZip'; AbLtAddS = ' eklendi '; AbLtDeleteS = ' silindi '; AbLtExtractS = ' aykland '; AbLtFreshenS = ' tazelendi '; AbLtMoveS = ' tand '; AbLtReplaceS = ' deitirildi '; AbLtStartS = ' gnlklendi '; AbGzipInvalidS = 'Geersiz Gzip'; AbGzipBadCRCS = 'Bozuk CRC'; AbGzipBadFileSizeS = 'Bozuk Dosya Uzunluu'; AbTarInvalidS = 'Geersiz Tar'; AbTarBadFileNameS = 'Dosya ad ok uzun'; AbTarBadLinkNameS = 'ok uzun sembolik balant yolu'; AbTarBadOpS = 'Desteklenmeyen Operasyon'; AbUnhandledEntityS = 'lenmeyen Varlk'; { pre-defined "operating system" (really more FILE system) identifiers for the Gzip header } AbGzOsFat = 'FAT Dosya Sistemi (MS-DOS, OS/2, NT/Win32)'; AbGzOsAmiga = 'Amiga'; AbGzOsVMS = 'VMS (veya OpenVMS)'; AbGzOsUnix = 'Unix'; AbGzOsVM_CMS = 'VM/CMS'; AbGzOsAtari = 'Atari TOS'; AbGzOsHPFS = 'HPFS Dosya Sistemi (OS/2, NT)'; AbGzOsMacintosh = 'Macintosh'; AbGzOsZ_System = 'Z-System'; AbGzOsCP_M = 'CP/M'; AbGzOsTOPS_20 = 'TOPS-20'; AbGzOsNTFS = 'NTFS Dosya Sistemi (NT)'; AbGzOsQDOS = 'QDOS'; AbGzOsAcornRISCOS = 'Acorn RISCOS'; AbGzOsVFAT = 'VFAT Dosya Sistemi (Win95, NT)'; AbGzOsMVS = 'MVS'; AbGzOsBeOS = 'BeOS (BeBox veya PowerMac)'; AbGzOsTandem = 'Tandem/NSK'; AbGzOsTHEOS = 'THEOS'; AbGzOsunknown = 'bilinmeyen'; AbGzOsUndefined = 'gzip tarafndan tanmsz ID'; { Compound File specific error messages } resourcestring AbCmpndIndexOutOfBounds = 'Endeks araln dndadr'; AbCmpndBusyUpdating = 'Bileik dosya gncelleme ile megul'; AbCmpndInvalidFile = 'Geersiz bileik dosya'; AbCmpndFileNotFound = 'Dosya/Klasr bulunamad'; AbCmpndFolderNotEmpty = 'Klasr bo deil'; AbCmpndExceedsMaxFileSize = 'Dosya boyutu izin verilen Azami deeri ayor'; implementation end. ================================================ FILE: lib/abbrevia/packages/Delphi XE/Abbrevia.dpk ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) package Abbrevia; {$R *.res} {$ALIGN 8} {$ASSERTIONS ON} {$BOOLEVAL OFF} {$DEBUGINFO OFF} {$EXTENDEDSYNTAX ON} {$IMPORTEDDATA ON} {$IOCHECKS ON} {$LOCALSYMBOLS OFF} {$LONGSTRINGS ON} {$OPENSTRINGS ON} {$OPTIMIZATION ON} {$OVERFLOWCHECKS OFF} {$RANGECHECKS OFF} {$REFERENCEINFO OFF} {$SAFEDIVIDE OFF} {$STACKFRAMES OFF} {$TYPEDADDRESS OFF} {$VARSTRINGCHECKS ON} {$WRITEABLECONST ON} {$MINENUMSIZE 1} {$IMAGEBASE $400000} {$DESCRIPTION 'Abbrevia Run-time package - RTL XE'} {$LIBSUFFIX '150'} {$RUNONLY} {$IMPLICITBUILD OFF} requires rtl; contains AbArcTyp in '..\..\source\AbArcTyp.pas', AbBase in '..\..\source\AbBase.pas', AbBitBkt in '..\..\source\AbBitBkt.pas', AbBrowse in '..\..\source\AbBrowse.pas', AbBzip2 in '..\..\source\AbBzip2.pas', AbBzip2Typ in '..\..\source\AbBzip2Typ.pas', AbCabExt in '..\..\source\AbCabExt.pas', AbCabKit in '..\..\source\AbCabKit.pas', AbCabMak in '..\..\source\AbCabMak.pas', AbCabTyp in '..\..\source\AbCabTyp.pas', AbCBrows in '..\..\source\AbCBrows.pas', AbCharset in '..\..\source\AbCharset.pas', AbConst in '..\..\source\AbConst.pas', AbCrtl in '..\..\source\AbCrtl.pas', AbDfBase in '..\..\source\AbDfBase.pas', AbDfCryS in '..\..\source\AbDfCryS.pas', AbDfDec in '..\..\source\AbDfDec.pas', AbDfEnc in '..\..\source\AbDfEnc.pas', AbDfHufD in '..\..\source\AbDfHufD.pas', AbDfInW in '..\..\source\AbDfInW.pas', AbDfOutW in '..\..\source\AbDfOutW.pas', AbDfPkMg in '..\..\source\AbDfPkMg.pas', AbDfStrm in '..\..\source\AbDfStrm.pas', AbDfXlat in '..\..\source\AbDfXlat.pas', AbExcept in '..\..\source\AbExcept.pas', AbFciFdi in '..\..\source\AbFciFdi.pas', AbGzTyp in '..\..\source\AbGzTyp.pas', AbLzma in '..\..\source\AbLzma.pas', AbPPMd in '..\..\source\AbPPMd.pas', AbResString in '..\..\source\AbResString.pas', AbSelfEx in '..\..\source\AbSelfEx.pas', AbSpanSt in '..\..\source\AbSpanSt.pas', AbSWStm in '..\..\source\AbSWStm.pas', AbTarTyp in '..\..\source\AbTarTyp.pas', AbUnzOutStm in '..\..\source\AbUnzOutStm.pas', AbUnzper in '..\..\source\AbUnzper.pas', AbUnzPrc in '..\..\source\AbUnzPrc.pas', AbUtils in '..\..\source\AbUtils.pas', AbVMStrm in '..\..\source\AbVMStrm.pas', AbWavPack in '..\..\source\AbWavPack.pas', AbZBrows in '..\..\source\AbZBrows.pas', AbZipExt in '..\..\source\AbZipExt.pas', AbZipKit in '..\..\source\AbZipKit.pas', AbZipper in '..\..\source\AbZipper.pas', AbZipPrc in '..\..\source\AbZipPrc.pas', AbZipTyp in '..\..\source\AbZipTyp.pas', AbZLTyp in '..\..\source\AbZLTyp.pas'; end. ================================================ FILE: lib/abbrevia/packages/Delphi XE/Abbrevia.dproj ================================================  {F41FD54F-C677-468D-B2F6-F7DEE8EEF36C} Abbrevia.dpk Debug DCC32 12.2 True Win32 Package None Win32 true true Base true true Base true $(BDSCOMMONDIR)\Bpl Abbrevia.bpl WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;$(DCC_UnitAlias) true false Abbrevia Run-time package - RTL XE true true true true 150 false 0 00400000 x86 false RELEASE;$(DCC_Define) 0 false DEBUG;$(DCC_Define) MainSource Cfg_2 Base Base Cfg_1 Base Delphi.Personality.12 Package Abbrevia.dpk True False 4 0 0 0 False False False False False 1033 1252 Abbrevia Components 5.0.0.0 Copyright (c) Abbrevia Group 2011 Abbrevia 5.0 Microsoft Office 2000 Sample Automation Server Wrapper Components Microsoft Office XP Sample Automation Server Wrapper Components True 12 ================================================ FILE: lib/abbrevia/packages/Delphi XE/AbbreviaVCL.dpk ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) package AbbreviaVCL; {$R *.res} {$ALIGN 8} {$ASSERTIONS ON} {$BOOLEVAL OFF} {$DEBUGINFO OFF} {$EXTENDEDSYNTAX ON} {$IMPORTEDDATA ON} {$IOCHECKS ON} {$LOCALSYMBOLS OFF} {$LONGSTRINGS ON} {$OPENSTRINGS ON} {$OPTIMIZATION ON} {$OVERFLOWCHECKS OFF} {$RANGECHECKS OFF} {$REFERENCEINFO OFF} {$SAFEDIVIDE OFF} {$STACKFRAMES OFF} {$TYPEDADDRESS OFF} {$VARSTRINGCHECKS ON} {$WRITEABLECONST ON} {$MINENUMSIZE 1} {$IMAGEBASE $400000} {$DESCRIPTION 'Abbrevia Run-time package - VCLXE'} {$LIBSUFFIX '150'} {$RUNONLY} {$IMPLICITBUILD OFF} requires rtl, vcl, vclx, Abbrevia; contains AbBseVCL in '..\..\source\AbBseVCL.pas', AbMeter in '..\..\source\AbMeter.pas', AbView in '..\..\source\AbView.pas', AbZipOut in '..\..\source\AbZipOut.pas', AbCView in '..\..\source\AbCView.pas', AbZView in '..\..\source\AbZView.pas', AbCompnd in '..\..\source\AbCompnd.pas', AbHexVw in '..\..\source\AbHexVw.pas', AbComCtrls in '..\..\source\AbComCtrls.pas'; end. ================================================ FILE: lib/abbrevia/packages/Delphi XE/AbbreviaVCL.dproj ================================================  {8F5900DA-6C2D-4EFA-96A5-D5AD0C68D886} AbbreviaVCL.dpk Debug DCC32 12.2 True Win32 Package VCL Win32 true true Base true true Base true C:\Users\Public\Documents\RAD Studio\7.0\Bpl\B305vr2010.bpl WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;$(DCC_UnitAlias) true false Abbrevia Run-time package - VCLXE true true true true 150 false 0 00400000 x86 false RELEASE;$(DCC_Define) 0 false DEBUG;$(DCC_Define) MainSource Cfg_2 Base Base Cfg_1 Base Delphi.Personality.12 Package AbbreviaVCL.dpk True False 4 0 0 0 False False False False False 1033 1252 Abbrevia Components 5.0.0.0 Copyright (c) Abbrevia Group Abbrevia 5.0 True 12 ================================================ FILE: lib/abbrevia/packages/Delphi XE/AbbreviaVCLDesign.dpk ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) package AbbreviaVCLDesign; {$R *.res} {$ALIGN 8} {$ASSERTIONS ON} {$BOOLEVAL OFF} {$DEBUGINFO OFF} {$EXTENDEDSYNTAX ON} {$IMPORTEDDATA ON} {$IOCHECKS ON} {$LOCALSYMBOLS OFF} {$LONGSTRINGS ON} {$OPENSTRINGS ON} {$OPTIMIZATION ON} {$OVERFLOWCHECKS OFF} {$RANGECHECKS OFF} {$REFERENCEINFO OFF} {$SAFEDIVIDE OFF} {$STACKFRAMES OFF} {$TYPEDADDRESS OFF} {$VARSTRINGCHECKS ON} {$WRITEABLECONST ON} {$MINENUMSIZE 1} {$IMAGEBASE $400000} {$DESCRIPTION 'Abbrevia Design-time package - VCLXE'} {$LIBSUFFIX '150'} {$DESIGNONLY} {$IMPLICITBUILD OFF} requires designide, AbbreviaVCL; contains AbPeCol in '..\..\source\AbPeCol.pas', AbPeDir in '..\..\source\AbPeDir.pas', AbPeFn in '..\..\source\AbPeFn.pas', AbPePass in '..\..\source\AbPePass.pas', AbPeVer in '..\..\source\AbPeVer.pas', AbRegVcl in '..\..\source\AbRegVcl.pas', AbDlgDir in '..\..\source\AbDlgDir.pas' {DirDlg}, AbDlgPwd in '..\..\source\AbDlgPwd.pas' {PassWordDlg}; end. ================================================ FILE: lib/abbrevia/packages/Delphi XE/AbbreviaVCLDesign.dproj ================================================  {24BE4180-8AB3-4667-927F-163D8C1A0D54} AbbreviaVCLDesign.dpk Debug DCC32 12.2 True Win32 Package None Win32 true true Base true true Base true ..\..\..\..\..\..\Public\Documents\RAD Studio\7.0\Bpl\B305vd2010.bpl true Abbrevia Design-time package - VCLXE WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;$(DCC_UnitAlias) false true 150 true true true false 0 00400000 x86 false RELEASE;$(DCC_Define) 0 false DEBUG;$(DCC_Define) MainSource
DirDlg
PassWordDlg
Cfg_2 Base Base Cfg_1 Base
Delphi.Personality.12 Package AbbreviaVCLDesign.dpk True False 4 0 0 0 False False False False False 1033 1252 Abbrevia Components 5.0.0.0 Copyright (c) Abbrevia Group Abbrevia 5.0 True 12
================================================ FILE: lib/abbrevia/packages/Delphi XE.groupproj ================================================  {3FC8294C-9FE8-49B9-9FF0-C33C59C18002} Default.Personality.12 ================================================ FILE: lib/abbrevia/source/AbArcTyp.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbArcTyp.pas *} {*********************************************************} {* ABBREVIA: TABArchive, TABArchiveItem classes *} {*********************************************************} unit AbArcTyp; {$I AbDefine.inc} interface uses {$IFDEF MSWINDOWS} Windows, {$ENDIF MSWINDOWS} Classes, Types, AbUtils; { ===== TAbArchiveItem ====================================================== } type TAbArchiveItem = class(TObject) protected {private} NextItem : TAbArchiveItem; FAction : TAbArchiveAction; FCompressedSize : Int64; FCRC32 : Longint; FDiskFileName : string; FExternalFileAttributes : LongWord; FFileName : string; FIsEncrypted : Boolean; FLastModFileTime : Word; FLastModFileDate : Word; FTagged : Boolean; FUncompressedSize : Int64; protected {property methods} function GetCompressedSize : Int64; virtual; function GetCRC32 : Longint; virtual; function GetDiskPath : string; function GetExternalFileAttributes : LongWord; virtual; function GetFileName : string; virtual; function GetIsDirectory: Boolean; virtual; function GetIsEncrypted : Boolean; virtual; function GetLastModFileDate : Word; virtual; function GetLastModFileTime : Word; virtual; function GetNativeFileAttributes : LongInt; virtual; function GetStoredPath : string; function GetUncompressedSize : Int64; virtual; procedure SetCompressedSize(const Value : Int64); virtual; procedure SetCRC32(const Value : Longint); virtual; procedure SetExternalFileAttributes( Value : LongWord ); virtual; procedure SetFileName(const Value : string); virtual; procedure SetIsEncrypted(Value : Boolean); virtual; procedure SetLastModFileDate(const Value : Word); virtual; procedure SetLastModFileTime(const Value : Word); virtual; procedure SetUncompressedSize(const Value : Int64); virtual; function GetLastModTimeAsDateTime: TDateTime; virtual; procedure SetLastModTimeAsDateTime(const Value: TDateTime); virtual; public {methods} constructor Create; destructor Destroy; override; function MatchesDiskName(const FileMask : string) : Boolean; function MatchesStoredName(const FileMask : string) : Boolean; function MatchesStoredNameEx(const FileMask : string) : Boolean; public {properties} property Action : TAbArchiveAction read FAction write FAction; property CompressedSize : Int64 read GetCompressedSize write SetCompressedSize; property CRC32 : Longint read GetCRC32 write SetCRC32; property DiskFileName : string read FDiskFileName write FDiskFileName; property DiskPath : string read GetDiskPath; property ExternalFileAttributes : LongWord read GetExternalFileAttributes write SetExternalFileAttributes; property FileName : string read GetFileName write SetFileName; property IsDirectory: Boolean read GetIsDirectory; property IsEncrypted : Boolean read GetIsEncrypted write SetIsEncrypted; property LastModFileDate : Word read GetLastModFileDate write SetLastModFileDate; property LastModFileTime : Word read GetLastModFileTime write SetLastModFileTime; property NativeFileAttributes : LongInt read GetNativeFileAttributes; property StoredPath : string read GetStoredPath; property Tagged : Boolean read FTagged write FTagged; property UncompressedSize : Int64 read GetUncompressedSize write SetUncompressedSize; property LastModTimeAsDateTime : TDateTime read GetLastModTimeAsDateTime write SetLastModTimeAsDateTime; end; { ===== TAbArchiveListEnumerator ============================================ } type TAbArchiveList = class; TAbArchiveListEnumerator = class private FIndex: Integer; FList: TAbArchiveList; public constructor Create(aList: TAbArchiveList); function GetCurrent: TAbArchiveItem; function MoveNext: Boolean; property Current: TAbArchiveItem read GetCurrent; end; { ===== TAbArchiveList ====================================================== } TAbArchiveList = class protected {private} FList : TList; FOwnsItems: Boolean; HashTable : array[0..1020] of TAbArchiveItem; protected {methods} function GenerateHash(const S : string) : LongInt; function GetCount : Integer; function Get(Index : Integer) : TAbArchiveItem; procedure Put(Index : Integer; Item : TAbArchiveItem); procedure UpdateHash(aItem: TAbArchiveItem; const aOldFileName: string); public {methods} constructor Create(AOwnsItems: Boolean); destructor Destroy; override; function Add(aItem : TAbArchiveItem): Integer; procedure Clear; procedure Delete(Index : Integer); function Find(const FN : string) : Integer; function GetEnumerator: TAbArchiveListEnumerator; function IsActiveDupe(const FN : string) : Boolean; public {properties} property Count : Integer read GetCount; property Items[Index : Integer] : TAbArchiveItem read Get write Put; default; end; { ===== TAbArchive specific types =========================================== } type TAbStoreOption = (soStripDrive, soStripPath, soRemoveDots, soRecurse, soFreshen, soReplace); TAbStoreOptions = set of TAbStoreOption; TAbExtractOption = (eoCreateDirs, eoRestorePath); TAbExtractOptions = set of TAbExtractOption; TAbArchiveStatus = (asInvalid, asIdle, asBusy); TAbArchiveEvent = procedure(Sender : TObject) of object; TAbArchiveConfirmEvent = procedure (Sender : TObject; var Confirm : Boolean) of object; TAbArchiveProgressEvent = procedure(Sender : TObject; Progress : Byte; var Abort : Boolean) of object; TAbArchiveItemEvent = procedure(Sender : TObject; Item : TAbArchiveItem) of object; TAbArchiveItemConfirmEvent = procedure(Sender : TObject; Item : TAbArchiveItem; ProcessType : TAbProcessType; var Confirm : Boolean) of object; TAbConfirmOverwriteEvent = procedure(var Name : string; var Confirm : Boolean) of object; TAbArchiveItemFailureEvent = procedure(Sender : TObject; Item : TAbArchiveItem; ProcessType : TAbProcessType; ErrorClass : TAbErrorClass; ErrorCode : Integer) of object; TAbArchiveItemExtractEvent = procedure(Sender : TObject; Item : TAbArchiveItem; const NewName : string) of object; TAbArchiveItemExtractToStreamEvent = procedure(Sender : TObject; Item : TAbArchiveItem; OutStream : TStream) of object; TAbArchiveItemTestEvent = procedure(Sender : TObject; Item : TAbArchiveItem) of object; TAbArchiveItemInsertEvent = procedure(Sender : TObject; Item : TAbArchiveItem; OutStream : TStream) of object; TAbArchiveItemInsertFromStreamEvent = procedure(Sender : TObject; Item : TAbArchiveItem; OutStream, InStream : TStream) of object; TAbArchiveItemProgressEvent = procedure(Sender : TObject; Item : TAbArchiveItem; Progress : Byte; var Abort : Boolean) of object; TAbProgressEvent = procedure(Progress : Byte; var Abort : Boolean) of object; TAbRequestDiskEvent = procedure(Sender : TObject; var Abort : Boolean) of object; TAbRequestImageEvent = procedure(Sender : TObject; ImageNumber : Integer; var ImageName : string; var Abort : Boolean) of object; TAbRequestNthDiskEvent = procedure(Sender : TObject; DiskNumber : Byte; var Abort : Boolean) of object; type TAbArchiveStreamHelper = class protected FStream : TStream; public constructor Create(AStream : TStream); procedure ExtractItemData(AStream : TStream); virtual; abstract; function FindFirstItem : Boolean; virtual; abstract; function FindNextItem : Boolean; virtual; abstract; procedure ReadHeader; virtual; abstract; procedure ReadTail; virtual; abstract; function SeekItem(Index : Integer): Boolean; virtual; abstract; procedure WriteArchiveHeader; virtual; abstract; procedure WriteArchiveItem(AStream : TStream); virtual; abstract; procedure WriteArchiveTail; virtual; abstract; function GetItemCount : Integer; virtual; abstract; end; { ===== TAbArchive ========================================================== } type TAbArchive = class(TObject) public FStream : TStream; FStatus : TAbArchiveStatus; protected {property variables} //These break Encapsulation FArchiveName : string; FAutoSave : Boolean; FBaseDirectory : string; FCurrentItem : TAbArchiveItem; FDOSMode : Boolean; FExtractOptions : TAbExtractOptions; FImageNumber : Word; FInStream : TStream; FIsDirty : Boolean; FSpanningThreshold : Int64; FItemList : TAbArchiveList; FLogFile : string; FLogging : Boolean; FLogStream : TFileStream; FMode : Word; FOwnsStream : Boolean; FSpanned : Boolean; FStoreOptions : TAbStoreOptions; FTempDir : string; protected {event variables} FOnProcessItemFailure : TAbArchiveItemFailureEvent; FOnArchiveProgress : TAbArchiveProgressEvent; FOnArchiveSaveProgress : TAbArchiveProgressEvent; FOnArchiveItemProgress : TAbArchiveItemProgressEvent; FOnConfirmProcessItem : TAbArchiveItemConfirmEvent; FOnConfirmOverwrite : TAbConfirmOverwriteEvent; FOnConfirmSave : TAbArchiveConfirmEvent; FOnLoad : TAbArchiveEvent; FOnProgress : TAbProgressEvent; FOnRequestImage : TAbRequestImageEvent; FOnSave : TAbArchiveEvent; protected {methods} constructor CreateInit; procedure CheckValid; function ConfirmPath(Item : TAbArchiveItem; const NewName : string; out UseName : string) : Boolean; procedure FreshenAt(Index : Integer); function FreshenRequired(Item : TAbArchiveItem) : Boolean; procedure GetFreshenTarget(Item : TAbArchiveItem); function GetItemCount : Integer; procedure MakeLogEntry(const FN: string; LT : TAbLogType); procedure ReplaceAt(Index : Integer); procedure SaveIfNeeded(aItem : TAbArchiveItem); procedure SetBaseDirectory(Value : string); procedure SetLogFile(const Value : string); procedure SetLogging(Value : Boolean); protected {abstract methods} function CreateItem(const FileSpec : string): TAbArchiveItem; virtual; abstract; procedure ExtractItemAt(Index : Integer; const UseName : string); virtual; abstract; procedure ExtractItemToStreamAt(Index : Integer; aStream : TStream); virtual; abstract; procedure LoadArchive; virtual; abstract; procedure SaveArchive; virtual; abstract; procedure TestItemAt(Index : Integer); virtual; abstract; protected {virtual methods} procedure DoProcessItemFailure(Item : TAbArchiveItem; ProcessType : TAbProcessType; ErrorClass : TAbErrorClass; ErrorCode : Integer); virtual; procedure DoArchiveSaveProgress(Progress : Byte; var Abort : Boolean); virtual; procedure DoArchiveProgress(Progress : Byte; var Abort : Boolean); virtual; procedure DoArchiveItemProgress(Item : TAbArchiveItem; Progress : Byte; var Abort : Boolean); virtual; procedure DoConfirmOverwrite(var FileName : string; var Confirm : Boolean); virtual; procedure DoConfirmProcessItem(Item : TAbArchiveItem; const ProcessType : TAbProcessType; var Confirm : Boolean); virtual; procedure DoConfirmSave(var Confirm : Boolean); virtual; procedure DoLoad; virtual; procedure DoProgress(Progress : Byte; var Abort : Boolean); virtual; procedure DoSave; virtual; function FixName(const Value : string) : string; virtual; function GetSpanningThreshold : Int64; virtual; function GetSupportsEmptyFolders : Boolean; virtual; procedure SetSpanningThreshold( Value : Int64 ); virtual; protected {properties and events} property InStream : TStream read FInStream; public {methods} constructor Create(const FileName : string; Mode : Word); virtual; constructor CreateFromStream(aStream : TStream; const aArchiveName : string); virtual; destructor Destroy; override; procedure Add(aItem : TAbArchiveItem); virtual; procedure AddFiles(const FileMask : string; SearchAttr : Integer); procedure AddFilesEx(const FileMask, ExclusionMask : string; SearchAttr : Integer); procedure AddFromStream(const NewName : string; aStream : TStream); procedure ClearTags; procedure Delete(aItem : TAbArchiveItem); procedure DeleteAt(Index : Integer); procedure DeleteFiles(const FileMask : string); procedure DeleteFilesEx(const FileMask, ExclusionMask : string); procedure DeleteTaggedItems; procedure Extract(aItem : TAbArchiveItem; const NewName : string); procedure ExtractAt(Index : Integer; const NewName : string); procedure ExtractFiles(const FileMask : string); procedure ExtractFilesEx(const FileMask, ExclusionMask : string); procedure ExtractTaggedItems; procedure ExtractToStream(const aFileName : string; aStream : TStream); function FindFile(const aFileName : string): Integer; function FindItem(aItem : TAbArchiveItem): Integer; procedure Freshen(aItem : TAbArchiveItem); procedure FreshenFiles(const FileMask : string); procedure FreshenFilesEx(const FileMask, ExclusionMask : string); procedure FreshenTaggedItems; procedure Load; virtual; procedure Move(aItem : TAbArchiveItem; const NewStoredPath : string); virtual; procedure Replace(aItem : TAbArchiveItem); procedure Save; virtual; procedure TagItems(const FileMask : string); procedure TestTaggedItems; procedure UnTagItems(const FileMask : string); procedure DoDeflateProgress(aPercentDone : integer); virtual; procedure DoInflateProgress(aPercentDone : integer); virtual; procedure DoSpanningMediaRequest(Sender : TObject; ImageNumber : Integer; var ImageName : string; var Abort : Boolean); virtual; public {properties} property OnProgress : TAbProgressEvent read FOnProgress write FOnProgress; property ArchiveName : string read FArchiveName; property AutoSave : Boolean read FAutoSave write FAutoSave; property BaseDirectory : string read FBaseDirectory write SetBaseDirectory; property Count : Integer read GetItemCount; property DOSMode : Boolean read FDOSMode write FDOSMode; property ExtractOptions : TAbExtractOptions read FExtractOptions write FExtractOptions; property IsDirty : Boolean read FIsDirty write FIsDirty; property ItemList : TAbArchiveList read FItemList; property LogFile : string read FLogFile write SetLogFile; property Logging : Boolean read FLogging write SetLogging; property Mode : Word read FMode; property Spanned : Boolean read FSpanned; property SpanningThreshold : Int64 read GetSpanningThreshold write SetSpanningThreshold; property Status : TAbArchiveStatus read FStatus; property StoreOptions : TAbStoreOptions read FStoreOptions write FStoreOptions; property SupportsEmptyFolders : Boolean read GetSupportsEmptyFolders; property TempDirectory : string read FTempDir write FTempDir; public {events} property OnProcessItemFailure : TAbArchiveItemFailureEvent read FOnProcessItemFailure write FOnProcessItemFailure; property OnArchiveProgress : TAbArchiveProgressEvent read FOnArchiveProgress write FOnArchiveProgress; property OnArchiveSaveProgress : TAbArchiveProgressEvent read FOnArchiveSaveProgress write FOnArchiveSaveProgress; property OnArchiveItemProgress : TAbArchiveItemProgressEvent read FOnArchiveItemProgress write FOnArchiveItemProgress; property OnConfirmProcessItem : TAbArchiveItemConfirmEvent read FOnConfirmProcessItem write FOnConfirmProcessItem; property OnConfirmOverwrite : TAbConfirmOverwriteEvent read FOnConfirmOverwrite write FOnConfirmOverwrite; property OnConfirmSave : TAbArchiveConfirmEvent read FOnConfirmSave write FOnConfirmSave; property OnLoad : TAbArchiveEvent read FOnLoad write FOnLoad; property OnRequestImage : TAbRequestImageEvent read FOnRequestImage write FOnRequestImage; property OnSave : TAbArchiveEvent read FOnSave write FOnSave; end; { ===== TAbExtraField ======================================================= } type PAbExtraSubField = ^TAbExtraSubField; TAbExtraSubField = packed record ID : Word; Len : Word; Data : record end; end; TAbExtraField = class private {fields} FBuffer : TByteDynArray; private {methods} procedure DeleteField(aSubField : PAbExtraSubField); function FindField(aID : Word; out aSubField : PAbExtraSubField) : Boolean; function FindNext(var aCurField : PAbExtraSubField) : Boolean; function GetCount : Integer; function GetID(aIndex : Integer): Word; procedure SetBuffer(const aValue : TByteDynArray); protected {methods} procedure Changed; virtual; public {methods} procedure Assign(aSource : TAbExtraField); procedure Clear; procedure CloneFrom(aSource : TAbExtraField; aID : Word); procedure Delete(aID : Word); function Get(aID : Word; out aData : Pointer; out aDataSize : Word) : Boolean; function GetStream(aID : Word; out aStream : TStream): Boolean; function Has(aID : Word): Boolean; procedure LoadFromStream(aStream : TStream; aSize : Word); procedure Put(aID : Word; const aData; aDataSize : Word); public {properties} property Count : Integer read GetCount; property Buffer : TByteDynArray read FBuffer write SetBuffer; property IDs[aIndex : Integer]: Word read GetID; end; const AbDefAutoSave = False; AbDefExtractOptions = [eoCreateDirs]; AbDefStoreOptions = [soStripDrive, soRemoveDots]; AbBufferSize = 32768; AbLastDisk = -1; AbLastImage = -1; implementation {.$R ABRES.R32} uses RTLConsts, SysUtils, AbExcept, AbDfBase, AbConst, AbResString; { TAbArchiveItem implementation ============================================ } { TAbArchiveItem } constructor TAbArchiveItem.Create; begin inherited Create; FCompressedSize := 0; FUncompressedSize := 0; FFileName := ''; FAction := aaNone; FLastModFileTime := 0; FLastModFileDate := 0; end; { -------------------------------------------------------------------------- } destructor TAbArchiveItem.Destroy; begin inherited Destroy; end; { -------------------------------------------------------------------------- } function TAbArchiveItem.GetCompressedSize : Int64; begin Result := FCompressedSize; end; { -------------------------------------------------------------------------- } function TAbArchiveItem.GetCRC32 : LongInt; begin Result := FCRC32; end; { -------------------------------------------------------------------------- } function TAbArchiveItem.GetDiskPath : string; begin Result := ExtractFilePath(DiskFileName); end; { -------------------------------------------------------------------------- } function TAbArchiveItem.GetExternalFileAttributes : LongWord; begin Result := FExternalFileAttributes; end; { -------------------------------------------------------------------------- } function TAbArchiveItem.GetFileName : string; begin Result := FFileName; end; { -------------------------------------------------------------------------- } function TAbArchiveItem.GetIsDirectory: Boolean; begin Result := False; end; { -------------------------------------------------------------------------- } function TAbArchiveItem.GetIsEncrypted : Boolean; begin Result := FIsEncrypted; end; { -------------------------------------------------------------------------- } function TAbArchiveItem.GetLastModFileTime : Word; begin Result := FLastModFileTime; end; { -------------------------------------------------------------------------- } function TAbArchiveItem.GetLastModFileDate : Word; begin Result := FLastModFileDate; end; { -------------------------------------------------------------------------- } function TAbArchiveItem.GetNativeFileAttributes : LongInt; begin {$IFDEF MSWINDOWS} if IsDirectory then Result := faDirectory else Result := 0; {$ENDIF} {$IFDEF UNIX} if IsDirectory then Result := AB_FPERMISSION_GENERIC or AB_FPERMISSION_OWNEREXECUTE else Result := AB_FPERMISSION_GENERIC; {$ENDIF} end; { -------------------------------------------------------------------------- } function TAbArchiveItem.GetStoredPath : string; begin Result := ExtractFilePath(DiskFileName); end; { -------------------------------------------------------------------------- } function TAbArchiveItem.GetUnCompressedSize : Int64; begin Result := FUnCompressedSize; end; { -------------------------------------------------------------------------- } function TAbArchiveItem.MatchesDiskName(const FileMask : string) : Boolean; var DiskName, Mask : string; begin DiskName := DiskFileName; AbUnfixName(DiskName); Mask := FileMask; AbUnfixName(Mask); Result := AbFileMatch(DiskName, Mask); end; { -------------------------------------------------------------------------- } function TAbArchiveItem.MatchesStoredName(const FileMask : string) : Boolean; var Value : string; Drive, Dir, Name : string; begin Value := FileMask; AbUnfixName(Value); AbParseFileName(Value, Drive, Dir, Name); Value := Dir + Name; Name := FileName; AbUnfixName(Name); if IsDirectory then Name := ExcludeTrailingPathDelimiter(Name); Result := AbFileMatch(Name, Value); end; { -------------------------------------------------------------------------- } function TAbArchiveItem.MatchesStoredNameEx(const FileMask : string) : Boolean; var I, J: Integer; MaskPart: string; begin Result := True; I := 1; while I <= Length(FileMask) do begin J := I; while (I <= Length(FileMask)) and (FileMask[I] <> PathSep {';'}) do Inc(I); MaskPart := Trim(Copy(FileMask, J, I - J)); if (I <= Length(FileMask)) and (FileMask[I] = PathSep {';'}) then Inc(I); if MatchesStoredName(MaskPart) then Exit; end; Result := False; end; { -------------------------------------------------------------------------- } procedure TAbArchiveItem.SetCompressedSize(const Value : Int64); begin FCompressedSize := Value; end; { -------------------------------------------------------------------------- } procedure TAbArchiveItem.SetCRC32(const Value : LongInt); begin FCRC32 := Value; end; { -------------------------------------------------------------------------- } procedure TAbArchiveItem.SetExternalFileAttributes( Value : LongWord ); begin FExternalFileAttributes := Value; end; { -------------------------------------------------------------------------- } procedure TAbArchiveItem.SetFileName(const Value : string); begin FFileName := Value; end; { -------------------------------------------------------------------------- } procedure TAbArchiveItem.SetIsEncrypted(Value : Boolean); begin FIsEncrypted := Value; end; { -------------------------------------------------------------------------- } procedure TAbArchiveItem.SetLastModFileDate(const Value : Word); begin FLastModFileDate := Value; end; { -------------------------------------------------------------------------- } procedure TAbArchiveItem.SetLastModFileTime(const Value : Word); begin FLastModFileTime := Value; end; { -------------------------------------------------------------------------- } procedure TAbArchiveItem.SetUnCompressedSize(const Value : Int64); begin FUnCompressedSize := Value; end; { -------------------------------------------------------------------------- } function TAbArchiveItem.GetLastModTimeAsDateTime: TDateTime; begin Result := AbDosFileDateToDateTime(LastModFileDate, LastModFileTime); end; { -------------------------------------------------------------------------- } procedure TAbArchiveItem.SetLastModTimeAsDateTime(const Value: TDateTime); var FileDate : Integer; begin FileDate := AbDateTimeToDosFileDate(Value); LastModFileTime := LongRec(FileDate).Lo; LastModFileDate := LongRec(FileDate).Hi; end; { -------------------------------------------------------------------------- } { TAbArchiveEnumeratorList implementation ================================== } { TAbArchiveEnumeratorList } constructor TAbArchiveListEnumerator.Create(aList: TAbArchiveList); begin inherited Create; FIndex := -1; FList := aList; end; { -------------------------------------------------------------------------- } function TAbArchiveListEnumerator.GetCurrent: TAbArchiveItem; begin Result := FList[FIndex]; end; { -------------------------------------------------------------------------- } function TAbArchiveListEnumerator.MoveNext: Boolean; begin Result := FIndex < FList.Count - 1; if Result then Inc(FIndex); end; { -------------------------------------------------------------------------- } { TAbArchiveList implementation ============================================ } { TAbArchiveList } constructor TAbArchiveList.Create(AOwnsItems: Boolean); begin inherited Create; FList := TList.Create; FOwnsItems := AOwnsItems; end; { -------------------------------------------------------------------------- } destructor TAbArchiveList.Destroy; begin Clear; FList.Free; inherited Destroy; end; { -------------------------------------------------------------------------- } function TAbArchiveList.Add(aItem : TAbArchiveItem) : Integer; var H : LongInt; begin if FOwnsItems then begin H := GenerateHash(aItem.FileName); aItem.NextItem := HashTable[H]; HashTable[H] := aItem; end; Result := FList.Add(aItem); end; { -------------------------------------------------------------------------- } procedure TAbArchiveList.Clear; var i : Integer; begin if FOwnsItems then for i := 0 to Count - 1 do TObject(FList[i]).Free; FList.Clear; FillChar(HashTable, SizeOf(HashTable), #0); end; { -------------------------------------------------------------------------- } procedure TAbArchiveList.Delete(Index: Integer); var Look : TAbArchiveItem; Last : ^TAbArchiveItem; FN : string; begin if FOwnsItems then begin FN := TAbArchiveItem(FList[Index]).FileName; Last := @HashTable[GenerateHash(FN)]; Look := Last^; while Look <> nil do begin if CompareText(Look.FileName, FN) = 0 then begin Last^ := Look.NextItem; Break; end; Last := @Look.NextItem; Look := Last^; end; TObject(FList[Index]).Free; end; FList.Delete(Index); end; { -------------------------------------------------------------------------- } function TAbArchiveList.Find(const FN : string) : Integer; var Look : TAbArchiveItem; I : Integer; begin if FOwnsItems then begin Look := HashTable[GenerateHash(FN)]; while Look <> nil do begin if CompareText(Look.FileName, FN) = 0 then begin Result := FList.IndexOf(Look); Exit; end; Look := Look.NextItem; end; end else begin for I := 0 to FList.Count - 1 do if CompareText(Items[I].FileName, FN) = 0 then begin Result := I; Exit; end; end; Result := -1; end; { -------------------------------------------------------------------------- } {$IFOPT Q+}{$DEFINE OVERFLOW_CHECKS_ON}{$Q-}{$ENDIF} function TAbArchiveList.GenerateHash(const S : string) : LongInt; var G : LongInt; I : Integer; U : string; begin Result := 0; U := AnsiUpperCase(S); for I := 1 to Length(U) do begin Result := (Result shl 4) + Ord(U[I]); G := LongInt(Result and $F0000000); if (G <> 0) then Result := Result xor (G shr 24); Result := Result and (not G); end; Result := Result mod 1021; end; {$IFDEF OVERFLOW_CHECKS_ON}{$Q+}{$ENDIF} { -------------------------------------------------------------------------- } function TAbArchiveList.Get(Index : Integer): TAbArchiveItem; begin Result := TAbArchiveItem(FList[Index]); end; { -------------------------------------------------------------------------- } function TAbArchiveList.GetCount : Integer; begin Result := FList.Count; end; { -------------------------------------------------------------------------- } function TAbArchiveList.GetEnumerator: TAbArchiveListEnumerator; begin Result := TAbArchiveListEnumerator.Create(Self); end; { -------------------------------------------------------------------------- } function TAbArchiveList.IsActiveDupe(const FN : string) : Boolean; var Look : TAbArchiveItem; I : Integer; begin if FOwnsItems then begin Look := HashTable[GenerateHash(FN)]; while Look <> nil do begin if (CompareText(Look.FileName, FN) = 0) and (Look.Action <> aaDelete) then begin Result := True; Exit; end; Look := Look.NextItem; end; end else begin for I := 0 to Count - 1 do if (CompareText(Items[I].FileName, FN) = 0) and (Items[I].Action <> aaDelete) then begin Result := True; Exit; end; end; Result := False; end; { -------------------------------------------------------------------------- } procedure TAbArchiveList.Put(Index : Integer; Item : TAbArchiveItem); var H : LongInt; Look : TAbArchiveItem; Last : ^TAbArchiveItem; FN : string; begin if FOwnsItems then begin FN := TAbArchiveItem(FList[Index]).FileName; Last := @HashTable[GenerateHash(FN)]; Look := Last^; { Delete old index } while Look <> nil do begin if CompareText(Look.FileName, FN) = 0 then begin Last^ := Look.NextItem; Break; end; Last := @Look.NextItem; Look := Last^; end; { Free old instance } TObject(FList[Index]).Free; { Add new index } H := GenerateHash(Item.FileName); Item.NextItem := HashTable[H]; HashTable[H] := Item; end; { Replace pointer } FList[Index] := Item; end; { -------------------------------------------------------------------------- } procedure TAbArchiveList.UpdateHash(aItem: TAbArchiveItem; const aOldFileName: string); var H : LongInt; Last : ^TAbArchiveItem; Look : TAbArchiveItem; begin if FOwnsItems then begin { Remove from old hash position } Last := @HashTable[GenerateHash(aOldFileName)]; Look := Last^; while Look <> nil do begin if Look = aItem then begin Last^ := Look.NextItem; Break end; Last := @Look.NextItem; Look := Last^ end; { Add to new hash position } H := GenerateHash(aItem.FileName); aItem.NextItem := HashTable[H]; HashTable[H] := aItem end; end; { TAbArchive implementation ================================================ } { TAbArchive } constructor TAbArchive.CreateInit; begin inherited Create; FIsDirty := False; FAutoSave := False; FItemList := TAbArchiveList.Create(True); StoreOptions := []; ExtractOptions := []; FStatus := asIdle; FOnProgress := DoProgress; BaseDirectory := ExtractFilePath(ParamStr(0)); end; { -------------------------------------------------------------------------- } constructor TAbArchive.Create(const FileName : string; Mode : Word); {create an archive by opening a filestream on filename with the given mode} begin FOwnsStream := True; CreateFromStream(TFileStream.Create(FileName, Mode), FileName); FMode := Mode; end; { -------------------------------------------------------------------------- } constructor TAbArchive.CreateFromStream(aStream : TStream; const aArchiveName : string); {create an archive based on an existing stream} begin CreateInit; FArchiveName := aArchiveName; FStream := aStream; end; { -------------------------------------------------------------------------- } destructor TAbArchive.Destroy; begin FItemList.Free; if FOwnsStream then FStream.Free; FLogStream.Free; inherited Destroy; end; { -------------------------------------------------------------------------- } procedure TAbArchive.Add(aItem : TAbArchiveItem); var Confirm, ItemAdded : Boolean; begin ItemAdded := False; try CheckValid; if FItemList.IsActiveDupe(aItem.FileName) then begin if (soFreshen in StoreOptions) then Freshen(aItem) else if (soReplace in StoreOptions) then Replace(aItem) else DoProcessItemFailure(aItem, ptAdd, ecAbbrevia, AbDuplicateName); Exit; end; DoConfirmProcessItem(aItem, ptAdd, Confirm); if not Confirm then Exit; aItem.Action := aaAdd; FItemList.Add(aItem); ItemAdded := True; FIsDirty := True; if AutoSave then Save; finally if not ItemAdded then aItem.Free; end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.AddFiles(const FileMask : string; SearchAttr : Integer); {Add files to the archive where the disk filespec matches} begin AddFilesEx(FileMask, '', SearchAttr); end; { -------------------------------------------------------------------------- } procedure TAbArchive.AddFilesEx(const FileMask, ExclusionMask : string; SearchAttr : Integer); {Add files matching Filemask except those matching ExclusionMask} var PathType : TAbPathType; IsWild : Boolean; SaveDir : string; Mask : string; MaskF : string; procedure CreateItems(Wild, Recursing : Boolean); var i : Integer; Files : TStrings; FilterList : TStringList; Item : TAbArchiveItem; begin FilterList := TStringList.Create; try if (MaskF <> '') then AbFindFilesEx(MaskF, SearchAttr, FilterList, Recursing); Files := TStringList.Create; try AbFindFilesEx(Mask, SearchAttr, Files, Recursing); if (Files.Count > 0) then for i := 0 to pred(Files.Count) do if FilterList.IndexOf(Files[i]) < 0 then if not Wild then begin if (Files[i] <> FArchiveName) then begin Item := CreateItem(Files[i]); Add(Item); end; end else begin if (AbAddBackSlash(FBaseDirectory) + Files[i]) <> FArchiveName then begin Item := CreateItem(Files[i]); Add(Item); end; end; finally Files.Free; end; finally FilterList.Free; end; end; begin if not SupportsEmptyFolders then SearchAttr := SearchAttr and not faDirectory; CheckValid; IsWild := (Pos('*', FileMask) > 0) or (Pos('?', FileMask) > 0); PathType := AbGetPathType(FileMask); Mask := FileMask; AbUnfixName(Mask); MaskF := ExclusionMask; AbUnfixName(MaskF); case PathType of ptNone, ptRelative : begin GetDir(0, SaveDir); if BaseDirectory <> '' then ChDir(BaseDirectory); try CreateItems(IsWild, soRecurse in StoreOptions); finally if BaseDirectory <> '' then ChDir(SaveDir); end; end; ptAbsolute : begin CreateItems(IsWild, soRecurse in StoreOptions); end; end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.AddFromStream(const NewName : string; aStream : TStream); {Add an item to the archive directly from a TStream descendant} var Confirm : Boolean; Item : TAbArchiveItem; PT : TAbProcessType; begin Item := CreateItem(NewName); CheckValid; PT := ptAdd; if FItemList.IsActiveDupe(NewName) then begin if ((soFreshen in StoreOptions) or (soReplace in StoreOptions)) then begin Item.Free; Item := FItemList[FItemList.Find(NewName)]; PT := ptReplace; end else begin DoProcessItemFailure(Item, ptAdd, ecAbbrevia, AbDuplicateName); Item.Free; Exit; end; end; DoConfirmProcessItem(Item, PT, Confirm); if not Confirm then Exit; FInStream := aStream; Item.Action := aaStreamAdd; if (PT = ptAdd) then FItemList.Add(Item); FIsDirty := True; Save; FInStream := nil; end; { -------------------------------------------------------------------------- } procedure TAbArchive.CheckValid; begin if Status = asInvalid then raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbArchive.ClearTags; {Clear all tags from the archive} var i : Integer; begin if Count > 0 then for i := 0 to pred(Count) do TAbArchiveItem(FItemList[i]).Tagged := False; end; { -------------------------------------------------------------------------- } function TAbArchive.ConfirmPath(Item : TAbArchiveItem; const NewName : string; out UseName : string) : Boolean; var Path : string; begin if Item.IsDirectory and not (ExtractOptions >= [eoRestorePath, eoCreateDirs]) then begin Result := False; Exit; end; if (NewName = '') then begin UseName := Item.FileName; AbUnfixName(UseName); if Item.IsDirectory then UseName := ExcludeTrailingPathDelimiter(UseName); if (not (eoRestorePath in ExtractOptions)) then UseName := ExtractFileName(UseName); end else UseName := NewName; if (AbGetPathType(UseName) <> ptAbsolute) then UseName := AbAddBackSlash(BaseDirectory) + UseName; Path := ExtractFileDir(UseName); if (Path <> '') and not DirectoryExists(Path) then if (eoCreateDirs in ExtractOptions) then AbCreateDirectory(Path) else raise EAbNoSuchDirectory.Create; Result := True; if not Item.IsDirectory and FileExists(UseName) then DoConfirmOverwrite(UseName, Result); end; { -------------------------------------------------------------------------- } procedure TAbArchive.Delete(aItem : TAbArchiveItem); {delete an item from the archive} var Index : Integer; begin CheckValid; Index := FindItem(aItem); if Index <> -1 then DeleteAt(Index); end; { -------------------------------------------------------------------------- } procedure TAbArchive.DeleteAt(Index : Integer); {delete the item at the index from the archive} var Confirm : Boolean; begin CheckValid; SaveIfNeeded(FItemList[Index]); DoConfirmProcessItem(FItemList[Index], ptDelete, Confirm); if not Confirm then Exit; TAbArchiveItem(FItemList[Index]).Action := aaDelete; FIsDirty := True; if AutoSave then Save; end; { -------------------------------------------------------------------------- } procedure TAbArchive.DeleteFiles(const FileMask : string); {delete all files from the archive that match the file mask} begin DeleteFilesEx(FileMask, ''); end; { -------------------------------------------------------------------------- } procedure TAbArchive.DeleteFilesEx(const FileMask, ExclusionMask : string); {Delete files matching Filemask except those matching ExclusionMask} var i : Integer; begin CheckValid; if Count > 0 then begin for i := pred(Count) downto 0 do begin with TAbArchiveItem(FItemList[i]) do if MatchesStoredNameEx(FileMask) then if not MatchesStoredNameEx(ExclusionMask) then DeleteAt(i); end; end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.DeleteTaggedItems; {delete all tagged items from the archive} var i : Integer; begin CheckValid; if Count > 0 then begin for i := pred(Count) downto 0 do begin with TAbArchiveItem(FItemList[i]) do if Tagged then DeleteAt(i); end; end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.DoProcessItemFailure(Item : TAbArchiveItem; ProcessType : TAbProcessType; ErrorClass : TAbErrorClass; ErrorCode : Integer); begin if Assigned(FOnProcessItemFailure) then FOnProcessItemFailure(Self, Item, ProcessType, ErrorClass, ErrorCode); end; { -------------------------------------------------------------------------- } procedure TAbArchive.DoArchiveSaveProgress(Progress : Byte; var Abort : Boolean); begin Abort := False; if Assigned(FOnArchiveSaveProgress) then FOnArchiveSaveProgress(Self, Progress, Abort); end; { -------------------------------------------------------------------------- } procedure TAbArchive.DoArchiveProgress(Progress : Byte; var Abort : Boolean); begin Abort := False; if Assigned(FOnArchiveProgress) then FOnArchiveProgress(Self, Progress, Abort); end; { -------------------------------------------------------------------------- } procedure TAbArchive.DoArchiveItemProgress(Item : TAbArchiveItem; Progress : Byte; var Abort : Boolean); begin Abort := False; if Assigned(FOnArchiveItemProgress) then FOnArchiveItemProgress(Self, Item, Progress, Abort); end; { -------------------------------------------------------------------------- } procedure TAbArchive.DoConfirmOverwrite(var FileName : string; var Confirm : Boolean); begin Confirm := True; if Assigned(FOnConfirmOverwrite) then FOnConfirmOverwrite(FileName, Confirm); end; { -------------------------------------------------------------------------- } procedure TAbArchive.DoConfirmProcessItem(Item : TAbArchiveItem; const ProcessType : TAbProcessType; var Confirm : Boolean); const ProcessTypeToLogType : array[TAbProcessType] of TAbLogType = (ltAdd, ltDelete, ltExtract, ltFreshen, ltMove, ltReplace, ltFoundUnhandled); begin Confirm := True; if Assigned(FOnConfirmProcessItem) then FOnConfirmProcessItem(Self, Item, ProcessType, Confirm); if (Confirm and FLogging) then MakeLogEntry(Item.Filename, ProcessTypeToLogType[ProcessType]); end; { -------------------------------------------------------------------------- } procedure TAbArchive.DoConfirmSave(var Confirm : Boolean); begin Confirm := True; if Assigned(FOnConfirmSave) then FOnConfirmSave(Self, Confirm); end; { -------------------------------------------------------------------------- } procedure TAbArchive.DoDeflateProgress(aPercentDone: integer); var Abort : Boolean; begin DoProgress(aPercentDone, Abort); if Abort then raise EAbAbortProgress.Create(AbUserAbortS); end; { -------------------------------------------------------------------------- } procedure TAbArchive.DoInflateProgress(aPercentDone: integer); var Abort : Boolean; begin DoProgress(aPercentDone, Abort); if Abort then raise EAbAbortProgress.Create(AbUserAbortS); end; { -------------------------------------------------------------------------- } procedure TAbArchive.DoLoad; begin if Assigned(FOnLoad) then FOnLoad(Self); end; { -------------------------------------------------------------------------- } procedure TAbArchive.DoProgress(Progress : Byte; var Abort : Boolean); begin Abort := False; DoArchiveItemProgress(FCurrentItem, Progress, Abort); end; { -------------------------------------------------------------------------- } procedure TAbArchive.DoSave; begin if Assigned(FOnSave) then FOnSave(Self); end; { -------------------------------------------------------------------------- } procedure TAbArchive.Extract(aItem : TAbArchiveItem; const NewName : string); {extract an item from the archive} var Index : Integer; begin CheckValid; Index := FindItem(aItem); if Index <> -1 then ExtractAt(Index, NewName); end; { -------------------------------------------------------------------------- } procedure TAbArchive.ExtractAt(Index : Integer; const NewName : string); {extract an item from the archive at Index} var Confirm : Boolean; ErrorClass : TAbErrorClass; ErrorCode : Integer; UseName : string; begin CheckValid; SaveIfNeeded(FItemList[Index]); DoConfirmProcessItem(FItemList[Index], ptExtract, Confirm); if not Confirm then Exit; if not ConfirmPath(FItemList[Index], NewName, UseName) then Exit; try FCurrentItem := FItemList[Index]; ExtractItemAt(Index, UseName); except on E : Exception do begin AbConvertException(E, ErrorClass, ErrorCode); DoProcessItemFailure(FItemList[Index], ptExtract, ErrorClass, ErrorCode); end; end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.ExtractToStream(const aFileName : string; aStream : TStream); {extract an item from the archive at Index directly to a stream} var Confirm : Boolean; ErrorClass : TAbErrorClass; ErrorCode : Integer; Index : Integer; begin CheckValid; Index := FindFile(aFileName); if (Index = -1) then Exit; SaveIfNeeded(FItemList[Index]); DoConfirmProcessItem(FItemList[Index], ptExtract, Confirm); if not Confirm then Exit; FCurrentItem := FItemList[Index]; try ExtractItemToStreamAt(Index, aStream); except on E : Exception do begin AbConvertException(E, ErrorClass, ErrorCode); DoProcessItemFailure(FItemList[Index], ptExtract, ErrorClass, ErrorCode); end; end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.ExtractFiles(const FileMask : string); {extract all files from the archive that match the mask} begin ExtractFilesEx(FileMask, ''); end; { -------------------------------------------------------------------------- } procedure TAbArchive.ExtractFilesEx(const FileMask, ExclusionMask : string); {Extract files matching Filemask except those matching ExclusionMask} var i : Integer; Abort : Boolean; begin CheckValid; if Count > 0 then begin for i := 0 to pred(Count) do begin with TAbArchiveItem(FItemList[i]) do if MatchesStoredNameEx(FileMask) and not MatchesStoredNameEx(ExclusionMask) and ((eoCreateDirs in ExtractOptions) or not IsDirectory) then ExtractAt(i, ''); DoArchiveProgress(AbPercentage(succ(i), Count), Abort); if Abort then raise EAbUserAbort.Create; end; DoArchiveProgress(100, Abort); end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.ExtractTaggedItems; {extract all tagged items from the archive} var i : Integer; Abort : Boolean; begin CheckValid; if Count > 0 then begin for i := 0 to pred(Count) do begin with TAbArchiveItem(FItemList[i]) do if Tagged then ExtractAt(i, ''); DoArchiveProgress(AbPercentage(succ(i), Count), Abort); if Abort then raise EAbUserAbort.Create; end; DoArchiveProgress(100, Abort); end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.TestTaggedItems; {test all tagged items in the archive} var i : Integer; Abort : Boolean; begin CheckValid; if Count > 0 then begin for i := 0 to pred(Count) do begin with TAbArchiveItem(FItemList[i]) do if Tagged then begin FCurrentItem := FItemList[i]; TestItemAt(i); end; DoArchiveProgress(AbPercentage(succ(i), Count), Abort); if Abort then raise EAbUserAbort.Create; end; DoArchiveProgress(100, Abort); end; end; { -------------------------------------------------------------------------- } function TAbArchive.FindFile(const aFileName : string): Integer; {find the index of the specified file} begin Result := FItemList.Find(aFileName); end; { -------------------------------------------------------------------------- } function TAbArchive.FindItem(aItem : TAbArchiveItem): Integer; {find the index of the specified item} begin Result := FItemList.Find(aItem.FileName); end; { -------------------------------------------------------------------------- } function TAbArchive.FixName(const Value : string) : string; var lValue: string; begin lValue := Value; {$IFDEF MSWINDOWS} if DOSMode then begin {Add the base directory to the filename before converting } {the file spec to the short filespec format. } if BaseDirectory <> '' then begin {Does the filename contain a drive or a leading backslash? } if not ((Pos(':', lValue) = 2) or (Pos(AbPathDelim, lValue) = 1)) then {If not, add the BaseDirectory to the filename.} lValue := AbAddBackSlash(BaseDirectory) + lValue; end; lValue := AbGetShortFileSpec(lValue); end; {$ENDIF} {strip drive stuff} if soStripDrive in StoreOptions then AbStripDrive(lValue); {check for a leading backslash} if lValue[1] = AbPathDelim then System.Delete(lValue, 1, 1); if soStripPath in StoreOptions then begin lValue := ExtractFileName(lValue); end; if soRemoveDots in StoreOptions then AbStripDots(lValue); Result := lValue; end; { -------------------------------------------------------------------------- } procedure TAbArchive.Freshen(aItem : TAbArchiveItem); {freshen the item} var Index : Integer; begin CheckValid; Index := FindItem(aItem); if Index <> -1 then begin {point existing item at the new file} if AbGetPathType(aItem.DiskFileName) = ptAbsolute then FItemList[Index].DiskFileName := aItem.DiskFileName; FreshenAt(Index); end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.FreshenAt(Index : Integer); {freshen item at index} var Confirm : Boolean; FR : Boolean; ErrorClass : TAbErrorClass; ErrorCode : Integer; begin CheckValid; SaveIfNeeded(FItemList[Index]); GetFreshenTarget(FItemList[Index]); FR := False; try FR := FreshenRequired(FItemList[Index]); except on E : Exception do begin AbConvertException(E, ErrorClass, ErrorCode); DoProcessItemFailure(FItemList[Index], ptFreshen, ErrorClass, ErrorCode); end; end; if not FR then Exit; DoConfirmProcessItem(FItemList[Index], ptFreshen, Confirm); if not Confirm then Exit; TAbArchiveItem(FItemList[Index]).Action := aaFreshen; FIsDirty := True; if AutoSave then Save; end; { -------------------------------------------------------------------------- } procedure TAbArchive.FreshenFiles(const FileMask : string); {freshen all items that match the file mask} begin FreshenFilesEx(FileMask, ''); end; { -------------------------------------------------------------------------- } procedure TAbArchive.FreshenFilesEx(const FileMask, ExclusionMask : string); {freshen all items that match the file mask} var i : Integer; begin CheckValid; if Count > 0 then begin for i := pred(Count) downto 0 do begin with TAbArchiveItem(FItemList[i]) do if MatchesStoredNameEx(FileMask) then if not MatchesStoredNameEx(ExclusionMask) then FreshenAt(i); end; end; end; { -------------------------------------------------------------------------- } function TAbArchive.FreshenRequired(Item : TAbArchiveItem) : Boolean; var FS : TFileStream; DateTime : LongInt; FileTime : Word; FileDate : Word; Matched : Boolean; SaveDir : string; begin GetDir(0, SaveDir); if BaseDirectory <> '' then ChDir(BaseDirectory); try FS := TFileStream.Create(Item.DiskFileName, fmOpenRead or fmShareDenyWrite); try DateTime := FileGetDate(FS.Handle); FileTime := LongRec(DateTime).Lo; FileDate := LongRec(DateTime).Hi; Matched := (Item.LastModFileDate = FileDate) and (Item.LastModFileTime = FileTime) and (Item.UncompressedSize = FS.Size); Result := not Matched; finally FS.Free; end; finally if BaseDirectory <> '' then ChDir(SaveDir); end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.FreshenTaggedItems; {freshen all tagged items} var i : Integer; begin CheckValid; if Count > 0 then begin for i := pred(Count) downto 0 do begin with TAbArchiveItem(FItemList[i]) do if Tagged then FreshenAt(i); end; end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.GetFreshenTarget(Item : TAbArchiveItem); var PathType : TAbPathType; Files : TStrings; SaveDir : string; DName : string; begin PathType := AbGetPathType(Item.DiskFileName); if (soRecurse in StoreOptions) and (PathType = ptNone) then begin GetDir(0, SaveDir); if BaseDirectory <> '' then ChDir(BaseDirectory); try Files := TStringList.Create; try // even if archive supports empty folder we don't have to // freshen it because there is no data, although, the timestamp // can be update since the folder was added AbFindFiles(Item.FileName, faAnyFile and not faDirectory, Files, True); if Files.Count > 0 then begin DName := AbAddBackSlash(BaseDirectory) + Files[0]; AbUnfixName(DName); Item.DiskFileName := DName; end else Item.DiskFileName := ''; finally Files.Free; end; finally if BaseDirectory <> '' then ChDir(SaveDir); end; end else begin if (BaseDirectory <> '') then DName := AbAddBackSlash(BaseDirectory) + Item.FileName else if AbGetPathType(Item.DiskFileName) = ptAbsolute then DName := Item.DiskFileName else DName := Item.FileName; AbUnfixName(DName); Item.DiskFileName := DName; end; end; { -------------------------------------------------------------------------- } function TAbArchive.GetSpanningThreshold : Int64; begin Result := FSpanningThreshold; end; { -------------------------------------------------------------------------- } function TAbArchive.GetSupportsEmptyFolders : Boolean; begin Result := False; end; { -------------------------------------------------------------------------- } function TAbArchive.GetItemCount : Integer; begin if Assigned(FItemList) then Result := FItemList.Count else Result := 0; end; { -------------------------------------------------------------------------- } procedure TAbArchive.Load; {load the archive} begin try LoadArchive; FStatus := asIdle; finally DoLoad; end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.MakeLogEntry(const FN: string; LT : TAbLogType); const LogTypeRes : array[TAbLogType] of string = (AbLtAddS, AbLtDeleteS, AbLtExtractS, AbLtFreshenS, AbLtMoveS, AbLtReplaceS, AbLtStartS, AbUnhandledEntityS); var Buf : string; begin if Assigned(FLogStream) then begin Buf := FN + LogTypeRes[LT] + DateTimeToStr(Now) + sLineBreak; FLogStream.Write(Buf[1], Length(Buf) * SizeOf(Char)); end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.Move(aItem : TAbArchiveItem; const NewStoredPath : string); var Confirm : Boolean; Found : Boolean; i : Integer; FixedPath, OldFileName: string; begin CheckValid; FixedPath := FixName(NewStoredPath); Found := False; if Count > 0 then for i := 0 to pred(Count) do if (ItemList[i] <> aItem) and SameText(FixedPath, ItemList[i].FileName) and (ItemList[i].Action <> aaDelete) then begin Found := True; Break; end; if Found then begin DoProcessItemFailure(aItem, ptMove, ecAbbrevia, AbDuplicateName); {even if something gets done in the AddItemFailure, we don't want to continue...} Exit; end; SaveIfNeeded(aItem); DoConfirmProcessItem(aItem, ptMove, Confirm); if not Confirm then Exit; OldFileName := aItem.FileName; aItem.FileName := FixedPath; aItem.Action := aaMove; ItemList.UpdateHash(aItem, OldFileName); FIsDirty := True; if AutoSave then Save; end; { -------------------------------------------------------------------------- } procedure TAbArchive.Replace(aItem : TAbArchiveItem); {replace the item} var Index : Integer; begin CheckValid; Index := FindItem(aItem); if Index <> -1 then begin {point existing item at the new file} if AbGetPathType(aItem.DiskFileName) = ptAbsolute then FItemList[Index].DiskFileName := aItem.DiskFileName; ReplaceAt(Index); end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.ReplaceAt(Index : Integer); {replace item at Index} var Confirm : Boolean; begin CheckValid; SaveIfNeeded(FItemList[Index]); GetFreshenTarget(FItemList[Index]); DoConfirmProcessItem(FItemList[Index], ptReplace, Confirm); if not Confirm then Exit; TAbArchiveItem(FItemList[Index]).Action := aaReplace; FIsDirty := True; if AutoSave then Save; end; { -------------------------------------------------------------------------- } procedure TAbArchive.Save; {save the archive} var Confirm : Boolean; begin if Status = asInvalid then Exit; if (not FIsDirty) and (Count > 0) then Exit; DoConfirmSave(Confirm); if not Confirm then Exit; SaveArchive; FIsDirty := False; DoSave; end; { -------------------------------------------------------------------------- } procedure TAbArchive.SaveIfNeeded(aItem : TAbArchiveItem); begin if (aItem.Action <> aaNone) then Save; end; { -------------------------------------------------------------------------- } procedure TAbArchive.SetBaseDirectory(Value : string); begin if (Value <> '') then if Value[Length(Value)] = AbPathDelim then if (Length(Value) > 1) and (Value[Length(Value) - 1] <> ':') then System.Delete(Value, Length(Value), 1); if (Length(Value) = 0) or DirectoryExists(Value) then FBaseDirectory := Value else raise EAbNoSuchDirectory.Create; end; { -------------------------------------------------------------------------- } procedure TAbArchive.SetSpanningThreshold( Value : Int64 ); begin FSpanningThreshold := Value; end; { -------------------------------------------------------------------------- } procedure TAbArchive.SetLogFile(const Value : string); begin FLogFile := Value; end; { -------------------------------------------------------------------------- } procedure TAbArchive.SetLogging(Value : Boolean); begin FLogging := Value; if Assigned(FLogStream) then begin FLogStream.Free; FLogStream := nil; end; if FLogging and (FLogFile <> '') then begin try FLogStream := TFileStream.Create(FLogFile, fmCreate or fmOpenWrite); MakeLogEntry(FArchiveName, ltStart); except raise EAbException.Create(AbLogCreateErrorS); end; end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.TagItems(const FileMask : string); {tag all items that match the mask} var i : Integer; begin if Count > 0 then for i := 0 to pred(Count) do with TAbArchiveItem(FItemList[i]) do begin if MatchesStoredNameEx(FileMask) then Tagged := True; end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.UnTagItems(const FileMask : string); {clear tags for all items that match the mask} var i : Integer; begin if Count > 0 then for i := 0 to pred(Count) do with TAbArchiveItem(FItemList[i]) do begin if MatchesStoredNameEx(FileMask) then Tagged := False; end; end; { -------------------------------------------------------------------------- } procedure TAbArchive.DoSpanningMediaRequest(Sender: TObject; ImageNumber: Integer; var ImageName: string; var Abort: Boolean); begin raise EAbSpanningNotSupported.Create; end; { -------------------------------------------------------------------------- } { TAbExtraField implementation ============================================= } procedure TAbExtraField.Assign(aSource : TAbExtraField); begin SetBuffer(aSource.Buffer); end; { -------------------------------------------------------------------------- } procedure TAbExtraField.Changed; begin // No-op end; { -------------------------------------------------------------------------- } procedure TAbExtraField.Clear; begin FBuffer := nil; Changed; end; { -------------------------------------------------------------------------- } procedure TAbExtraField.CloneFrom(aSource : TAbExtraField; aID : Word); var Data : Pointer; DataSize : Word; begin if aSource.Get(aID, Data, DataSize) then Put(aID, Data, DataSize) else Delete(aID); end; { -------------------------------------------------------------------------- } procedure TAbExtraField.Delete(aID : Word); var SubField : PAbExtraSubField; begin if FindField(aID, SubField) then begin DeleteField(SubField); Changed; end; end; { -------------------------------------------------------------------------- } procedure TAbExtraField.DeleteField(aSubField : PAbExtraSubField); var Len, Offset : Integer; begin Len := SizeOf(TAbExtraSubField) + aSubField.Len; Offset := PtrInt(aSubField) - PtrInt(Pointer(FBuffer)); if Offset + Len < Length(FBuffer) then Move(FBuffer[Offset + Len], aSubField^, Length(FBuffer) - Offset - Len); SetLength(FBuffer, Length(FBuffer) - Len); end; { -------------------------------------------------------------------------- } function TAbExtraField.FindField(aID : Word; out aSubField : PAbExtraSubField) : Boolean; begin Result := False; aSubField := nil; while FindNext(aSubField) do if aSubField.ID = aID then begin Result := True; Break; end; end; { -------------------------------------------------------------------------- } function TAbExtraField.FindNext(var aCurField : PAbExtraSubField) : Boolean; var BytesLeft : Integer; begin if aCurField = nil then begin aCurField := PAbExtraSubField(FBuffer); BytesLeft := Length(FBuffer); end else begin BytesLeft := Length(FBuffer) - Integer(PtrInt(aCurField) - PtrInt(Pointer(FBuffer))) - SizeOf(TAbExtraSubField) - aCurField.Len; aCurField := Pointer(PtrInt(aCurField) + aCurField.Len + SizeOf(TAbExtraSubField)); end; Result := (BytesLeft >= SizeOf(TAbExtraSubField)); if Result and (BytesLeft < SizeOf(TAbExtraSubField) + aCurField.Len) then aCurField.Len := BytesLeft - SizeOf(TAbExtraSubField); end; { -------------------------------------------------------------------------- } function TAbExtraField.Get(aID : Word; out aData : Pointer; out aDataSize : Word) : Boolean; var SubField : PAbExtraSubField; begin Result := FindField(aID, SubField); if Result then begin aData := @SubField.Data; aDataSize := SubField.Len; end else begin aData := nil; aDataSize := 0; end; end; { -------------------------------------------------------------------------- } function TAbExtraField.GetCount : Integer; var SubField : PAbExtraSubField; begin Result := 0; SubField := nil; while FindNext(SubField) do Inc(Result); end; { -------------------------------------------------------------------------- } function TAbExtraField.GetID(aIndex : Integer): Word; var i: Integer; SubField : PAbExtraSubField; begin i := 0; SubField := nil; while FindNext(SubField) do if i = aIndex then begin Result := SubField.ID; Exit; end else Inc(i); raise EListError.CreateFmt(SListIndexError, [aIndex]); end; { -------------------------------------------------------------------------- } function TAbExtraField.GetStream(aID : Word; out aStream : TStream): Boolean; var Data: Pointer; DataSize: Word; begin Result := Get(aID, Data, DataSize); if Result then begin aStream := TMemoryStream.Create; aStream.WriteBuffer(Data^, DataSize); aStream.Position := 0; end; end; { -------------------------------------------------------------------------- } function TAbExtraField.Has(aID : Word): Boolean; var SubField : PAbExtraSubField; begin Result := FindField(aID, SubField); end; { -------------------------------------------------------------------------- } procedure TAbExtraField.LoadFromStream(aStream : TStream; aSize : Word); begin SetLength(FBuffer, aSize); if aSize > 0 then aStream.ReadBuffer( FBuffer[0], aSize); end; { -------------------------------------------------------------------------- } procedure TAbExtraField.Put(aID : Word; const aData; aDataSize : Word); var Offset : Cardinal; SubField : PAbExtraSubField; begin if FindField(aID, SubField) then begin if SubField.Len = aDataSize then begin Move(aData, SubField.Data, aDataSize); Changed; Exit; end else DeleteField(SubField); end; Offset := Length(FBuffer); SetLength(FBuffer, Length(FBuffer) + SizeOf(TAbExtraSubField) + aDataSize); SubField := PAbExtraSubField(@FBuffer[Offset]); SubField.ID := aID; SubField.Len := aDataSize; Move(aData, SubField.Data, aDataSize); Changed; end; { -------------------------------------------------------------------------- } procedure TAbExtraField.SetBuffer(const aValue : TByteDynArray); begin SetLength(FBuffer, Length(aValue)); if Length(FBuffer) > 0 then Move(aValue[0], FBuffer[0], Length(FBuffer)); Changed; end; { -------------------------------------------------------------------------- } { ========================================================================== } { TAbArchiveStreamHelper } constructor TAbArchiveStreamHelper.Create(AStream: TStream); begin if Assigned(AStream) then FStream := AStream else raise Exception.Create('nil stream'); end; end. ================================================ FILE: lib/abbrevia/source/AbBase.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbBase.pas *} {*********************************************************} {* ABBREVIA: Base component class *} {*********************************************************} unit AbBase; {$I AbDefine.inc} interface uses Classes; type TAbBaseComponent = class(TComponent) protected {methods} function GetVersion : string; procedure SetVersion(const Value : string); protected {properties} property Version : string read GetVersion write SetVersion stored False; end; implementation uses AbConst; { -------------------------------------------------------------------------- } function TAbBaseComponent.GetVersion : string; begin Result := AbVersionS; end; { -------------------------------------------------------------------------- } procedure TAbBaseComponent.SetVersion(const Value : string); begin {NOP} end; end. ================================================ FILE: lib/abbrevia/source/AbBitBkt.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbBitBkt.pas *} {*********************************************************} {* ABBREVIA: Bit bucket memory stream class *} {*********************************************************} unit AbBitBkt; {$I AbDefine.inc} interface uses Classes, AbUtils; type TAbBitBucketStream = class(TStream) private FBuffer : {$IFDEF UNICODE}PByte{$ELSE}PAnsiChar{$ENDIF}; FBufSize : longint; FBufPosn : longint; FPosn : Int64; FSize : Int64; FTail : longint; protected public constructor Create(aBufSize : cardinal); destructor Destroy; override; function Read(var Buffer; Count : Longint) : Longint; override; function Write(const Buffer; Count : Longint) : Longint; override; function Seek(const Offset : Int64; Origin : TSeekOrigin) : Int64; override; procedure ForceSize(aSize : Int64); end; implementation uses Math, SysUtils, AbExcept; {Notes: The buffer is a circular queue without a head pointer; FTail is where data is next going to be written and it wraps indescriminately. The buffer can never be empty--it is always full (initially it is full of binary zeros. The class is designed to act as a bit bucket for the test feature of Abbrevia's zip code; it is not intended as a complete class with many possible applications. It is designed to be written to in a steady progression with some reading back in the recently written stream (the buffer size details how far back the Seek method will work). Seeking outside this buffer will result in exceptions being generated. For testing deflated files, the buffer size should be 32KB, for imploded files, either 8KB or 4KB. The Create constructor limits the buffer size to these values.} {===TAbBitBucketStream===============================================} constructor TAbBitBucketStream.Create(aBufSize : cardinal); begin inherited Create; if (aBufSize <> 4096) and (aBufSize <> 8192) and (aBufSize <> 32768) then FBufSize := 32768 else FBufSize := aBufSize; {add a 1KB leeway} inc(FBufSize, 1024); GetMem(FBuffer, FBufSize); end; {--------} destructor TAbBitBucketStream.Destroy; begin if (FBuffer <> nil) then FreeMem(FBuffer, FBufSize); inherited Destroy; end; {--------} procedure TAbBitBucketStream.ForceSize(aSize : Int64); begin FSize := aSize; end; {--------} function TAbBitBucketStream.Read(var Buffer; Count : Longint) : Longint; var Chunk2Size : longint; Chunk1Size : longint; OutBuffer : PByte; begin OutBuffer := @Buffer; {we cannot read more bytes than there is buffer} if (Count > FBufSize) then raise EAbBBSReadTooManyBytes.Create(Count); {calculate the size of the chunks} if (FBufPosn <= FTail) then begin Chunk1Size := FTail - FBufPosn; if (Chunk1Size > Count) then Chunk1Size := Count; Chunk2Size := 0; end else begin Chunk1Size := FBufSize - FBufPosn; if (Chunk1Size > Count) then begin Chunk1Size := Count; Chunk2Size := 0; end else begin Chunk2Size := FTail; if (Chunk2Size > (Count - Chunk1Size)) then Chunk2Size := Count - Chunk1Size; end end; {we cannot read more bytes than there are available} if (Count > (Chunk1Size + Chunk2Size)) then raise EAbBBSReadTooManyBytes.Create(Count); {perform the read} if (Chunk1Size > 0) then begin Move(FBuffer[FBufPosn], OutBuffer^, Chunk1Size); inc(FBufPosn, Chunk1Size); inc(FPosn, Chunk1Size); end; if (Chunk2Size > 0) then begin {we've wrapped} Move(FBuffer[0], PByte(PtrInt(OutBuffer) + PtrInt(Chunk1Size))^, Chunk2Size); FBufPosn := Chunk2Size; inc(FPosn, Chunk2Size); end; Result := Count; end; {--------} function TAbBitBucketStream.Write(const Buffer; Count : Longint) : Longint; var Chunk2Size : longint; Chunk1Size : longint; InBuffer : PByte; Overage : longint; begin Result := Count; InBuffer := @Buffer; {we cannot write more bytes than there is buffer} while Count > FBufSize do begin Overage := Min(FBufSize, Count - FBufSize); Write(InBuffer^, Overage); Inc(PtrInt(InBuffer), Overage); Dec(Count, Overage); end; {calculate the size of the chunks} Chunk1Size := FBufSize - FTail; if (Chunk1Size > Count) then begin Chunk1Size := Count; Chunk2Size := 0; end else begin Chunk2Size := Count - Chunk1Size; end; {write the first chunk} if (Chunk1Size > 0) then begin Move(InBuffer^, FBuffer[FTail], Chunk1Size); inc(FTail, Chunk1Size); end; {if the second chunk size is not zero, write the second chunk; note that we have wrapped} if (Chunk2Size > 0) then begin Move(PByte(PtrInt(InBuffer) + PtrInt(Chunk1Size))^, FBuffer[0], Chunk2Size); FTail := Chunk2Size; end; {the stream size and position have changed} inc(FSize, Count); FPosn := FSize; FBufPosn := FTail; end; {--------} function TAbBitBucketStream.Seek(const Offset : Int64; Origin : TSeekOrigin): Int64; var Posn : Int64; BytesBack : longint; begin {calculate the new position} case Origin of soBeginning : Posn := Offset; soCurrent : Posn := FPosn + Offset; soEnd : if (Offset = 0) then begin {special case: position at end of stream} FBufPosn := FTail; FPosn := FSize; Result := FSize; Exit; end else begin Posn := FSize + Offset; end; else raise EAbBBSInvalidOrigin.Create; end; {calculate whether the new position is within the buffer; if not, raise exception} if (Posn > FSize) or (Posn <= (FSize - FBufSize)) then raise EAbBBSSeekOutsideBuffer.Create; {set the internal fields for the new position} FPosn := Posn; BytesBack := FSize - Posn; if (BytesBack <= FTail) then FBufPosn := FTail - BytesBack else FBufPosn := longint(FTail) + FBufSize - BytesBack; {return the new position} Result := Posn; end; {====================================================================} end. ================================================ FILE: lib/abbrevia/source/AbBrowse.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbBrowse.pas *} {*********************************************************} {* ABBREVIA: Base Browser Component *} {*********************************************************} unit AbBrowse; {$I AbDefine.inc} interface uses Classes, AbBase, AbUtils, AbArcTyp; type IAbProgressMeter = interface ['{4B766704-FD20-40BF-BA40-2EC2DD77B178}'] procedure DoProgress(Progress : Byte); procedure Reset; end; TAbBaseBrowser = class(TAbBaseComponent) public FArchive : TAbArchive; protected {private} FSpanningThreshold : Longint; FItemProgressMeter : IAbProgressMeter; FArchiveProgressMeter : IAbProgressMeter; FBaseDirectory : string; FFileName : string; FLogFile : string; FLogging : Boolean; FOnArchiveProgress : TAbArchiveProgressEvent; FOnArchiveItemProgress : TAbArchiveItemProgressEvent; FOnChange : TNotifyEvent; FOnConfirmProcessItem : TAbArchiveItemConfirmEvent; FOnLoad : TAbArchiveEvent; FOnProcessItemFailure : TAbArchiveItemFailureEvent; FOnRequestImage : TAbRequestImageEvent; FTempDirectory : string; { detected compression type } FArchiveType : TAbArchiveType; FForceType : Boolean; protected {private methods} function GetCount : Integer; function GetItem(Value : Longint) : TAbArchiveItem; function GetSpanned : Boolean; function GetStatus : TAbArchiveStatus; procedure ResetMeters; virtual; procedure SetArchiveProgressMeter(const Value: IAbProgressMeter); procedure SetCompressionType(const Value: TAbArchiveType); procedure SetBaseDirectory(const Value : string); procedure SetItemProgressMeter(const Value: IAbProgressMeter); procedure SetSpanningThreshold(Value : Longint); procedure SetLogFile(const Value : string); procedure SetLogging(Value : Boolean); procedure SetTempDirectory(const Value : string); procedure Loaded; override; procedure Notification(Component: TComponent; Operation: TOperation); override; protected {virtual methods} procedure DoArchiveItemProgress(Sender : TObject; Item : TAbArchiveItem; Progress : Byte; var Abort : Boolean); virtual; procedure DoArchiveProgress(Sender : TObject; Progress : Byte; var Abort : Boolean); virtual; procedure DoChange; virtual; procedure DoConfirmProcessItem(Sender : TObject; Item : TAbArchiveItem; ProcessType : TAbProcessType; var Confirm : Boolean); virtual; procedure DoLoad(Sender : TObject); virtual; procedure DoProcessItemFailure(Sender : TObject; Item : TAbArchiveItem; ProcessType : TAbProcessType; ErrorClass : TAbErrorClass; ErrorCode : Integer); virtual; procedure SetOnRequestImage(Value : TAbRequestImageEvent); virtual; procedure InitArchive; virtual; {This method must be defined in descendent classes} procedure SetFileName(const aFileName : string); virtual; abstract; protected {properties} property Archive : TAbArchive read FArchive; property ArchiveProgressMeter : IAbProgressMeter read FArchiveProgressMeter write SetArchiveProgressMeter; property BaseDirectory : string read FBaseDirectory write SetBaseDirectory; property FileName : string read FFileName write SetFileName; property SpanningThreshold : Longint read FSpanningThreshold write SetSpanningThreshold default 0; property ItemProgressMeter : IAbProgressMeter read FItemProgressMeter write SetItemProgressMeter; property LogFile : string read FLogFile write SetLogFile; property Logging : Boolean read FLogging write SetLogging default False; property Spanned : Boolean read GetSpanned; property TempDirectory : string read FTempDirectory write SetTempDirectory; protected {events} property OnArchiveProgress : TAbArchiveProgressEvent read FOnArchiveProgress write FOnArchiveProgress; property OnArchiveItemProgress : TAbArchiveItemProgressEvent read FOnArchiveItemProgress write FOnArchiveItemProgress; property OnConfirmProcessItem : TAbArchiveItemConfirmEvent read FOnConfirmProcessItem write FOnConfirmProcessItem; property OnProcessItemFailure : TAbArchiveItemFailureEvent read FOnProcessItemFailure write FOnProcessItemFailure; property OnRequestImage : TAbRequestImageEvent read FOnRequestImage write SetOnRequestImage; public {methods} constructor Create(AOwner : TComponent); override; destructor Destroy; override; procedure ClearTags; {Clear all tags from the archive} function FindItem(aItem : TAbArchiveItem) : Integer; function FindFile(const aFileName : string) : Integer; procedure TagItems(const FileMask : string); {tag all items that match the mask} procedure UnTagItems(const FileMask : string); {clear tags for all items that match the mask} procedure CloseArchive; {closes the archive by setting FileName to ''} procedure OpenArchive(const aFileName : string); {opens the archive} public {properties} property Count : Integer read GetCount; property Items[Index : Integer] : TAbArchiveItem read GetItem; default; property Status : TAbArchiveStatus read GetStatus; property ArchiveType : TAbArchiveType read FArchiveType write SetCompressionType default atUnknown; property ForceType : Boolean read FForceType write FForceType default False; public {events} property OnChange : TNotifyEvent read FOnChange write FOnChange; property OnLoad : TAbArchiveEvent read FOnLoad write FOnLoad; end; function AbDetermineArcType(const FN : string; AssertType : TAbArchiveType) : TAbArchiveType; overload; function AbDetermineArcType(aStream: TStream) : TAbArchiveType; overload; implementation uses SysUtils, AbExcept, {$IFDEF MSWINDOWS} AbCabTyp, {$ENDIF} AbZipTyp, AbTarTyp, AbGzTyp, AbBzip2Typ; { TAbBaseBrowser implementation ======================================= } { -------------------------------------------------------------------------- } constructor TAbBaseBrowser.Create(AOwner : TComponent); begin inherited Create(AOwner); FLogFile := ''; FLogging := False; FSpanningThreshold := 0; FArchiveType := atUnknown; FForceType := False; end; { -------------------------------------------------------------------------- } destructor TAbBaseBrowser.Destroy; begin FArchive.Free; FArchive := nil; inherited Destroy; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.ClearTags; {Clear all tags from the archive} begin if Assigned(FArchive) then FArchive.ClearTags else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.CloseArchive; {closes the archive by setting FileName to ''} begin if FFileName <> '' then FileName := ''; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.DoArchiveItemProgress(Sender : TObject; Item : TAbArchiveItem; Progress : Byte; var Abort : Boolean); begin Abort := False; if Assigned(FItemProgressMeter) then FItemProgressMeter.DoProgress(Progress); if Assigned(FOnArchiveItemProgress) then FOnArchiveItemProgress(Self, Item, Progress, Abort); end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.DoArchiveProgress(Sender : TObject; Progress : Byte; var Abort : Boolean); begin Abort := False; if Assigned(FArchiveProgressMeter) then FArchiveProgressMeter.DoProgress(Progress); if Assigned(FOnArchiveProgress) then FOnArchiveProgress(Self, Progress, Abort); end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.DoChange; begin if Assigned(FOnChange) then begin FOnChange(Self); end; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.DoConfirmProcessItem(Sender : TObject; Item : TAbArchiveItem; ProcessType : TAbProcessType; var Confirm : Boolean); begin Confirm := True; if Assigned(FItemProgressMeter) then FItemProgressMeter.Reset; if Assigned(FOnConfirmProcessItem) then FOnConfirmProcessItem(Self, Item, ProcessType, Confirm); end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.DoLoad(Sender : TObject); begin if Assigned(FOnLoad) then FOnLoad(Self); end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.DoProcessItemFailure(Sender : TObject; Item : TAbArchiveItem; ProcessType : TAbProcessType; ErrorClass : TAbErrorClass; ErrorCode : Integer); begin if Assigned(FOnProcessItemFailure) then FOnProcessItemFailure(Self, Item, ProcessType, ErrorClass, ErrorCode); end; { -------------------------------------------------------------------------- } function TAbBaseBrowser.FindItem(aItem : TAbArchiveItem) : Integer; begin if Assigned(FArchive) then Result := FArchive.FindItem(aItem) else Result := -1; end; { -------------------------------------------------------------------------- } function TAbBaseBrowser.FindFile(const aFileName : string) : Integer; begin if Assigned(FArchive) then Result := FArchive.FindFile(aFileName) else Result := -1; end; { -------------------------------------------------------------------------- } function TAbBaseBrowser.GetSpanned : Boolean; begin if Assigned(FArchive) then Result := FArchive.Spanned else Result := False; end; { -------------------------------------------------------------------------- } function TAbBaseBrowser.GetStatus : TAbArchiveStatus; begin if Assigned(FArchive) then Result := FArchive.Status else Result := asInvalid; end; { -------------------------------------------------------------------------- } function TAbBaseBrowser.GetCount : Integer; begin if Assigned(FArchive) then Result := FArchive.Count else Result := 0; end; { -------------------------------------------------------------------------- } function TAbBaseBrowser.GetItem(Value : Longint) : TAbArchiveItem; begin if Assigned(FArchive) then Result := FArchive.ItemList[Value] else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.InitArchive; begin ResetMeters; if Assigned(FArchive) then begin {properties} FArchive.SpanningThreshold := FSpanningThreshold; FArchive.LogFile := FLogFile; FArchive.Logging := FLogging; FArchive.TempDirectory := FTempDirectory; SetBaseDirectory(FBaseDirectory); {events} FArchive.OnArchiveProgress := DoArchiveProgress; FArchive.OnArchiveItemProgress := DoArchiveItemProgress; FArchive.OnConfirmProcessItem := DoConfirmProcessItem; FArchive.OnLoad := DoLoad; FArchive.OnProcessItemFailure := DoProcessItemFailure; FArchive.OnRequestImage := FOnRequestImage; end; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.Loaded; begin inherited Loaded; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.Notification(Component: TComponent; Operation: TOperation); begin inherited Notification(Component, Operation); if (Operation = opRemove) then begin if Assigned(ItemProgressMeter) and Component.IsImplementorOf(ItemProgressMeter) then ItemProgressMeter := nil; if Assigned(ArchiveProgressMeter) and Component.IsImplementorOf(ArchiveProgressMeter) then ArchiveProgressMeter := nil; end; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.OpenArchive(const aFileName : string); {opens the archive} begin FileName := AFileName; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.ResetMeters; begin if Assigned(FArchiveProgressMeter) then FArchiveProgressMeter.Reset; if Assigned(FItemProgressMeter) then FItemProgressMeter.Reset; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.SetBaseDirectory(const Value : string); begin if Assigned(FArchive) then begin FArchive.BaseDirectory := Value; FBaseDirectory := FArchive.BaseDirectory; end else FBaseDirectory := Value; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.SetSpanningThreshold(Value : Longint); begin FSpanningThreshold := Value; if Assigned(FArchive) then FArchive.SpanningThreshold := Value; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.SetLogFile(const Value : string); begin FLogFile := Value; if (csDesigning in ComponentState) then Exit; if Assigned(FArchive) then FArchive.LogFile := Value; SetLogging(Value <> ''); end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.SetLogging(Value : Boolean); begin FLogging := Value; if (csDesigning in ComponentState) then Exit; if Assigned(FArchive) then FArchive.Logging:= Value; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.SetOnRequestImage(Value : TAbRequestImageEvent); begin FOnRequestImage := Value; if Assigned(FArchive) then FArchive.OnRequestImage := Value; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.SetTempDirectory(const Value : string); begin FTempDirectory := Value; if Assigned(FArchive) then FArchive.TempDirectory := Value; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.TagItems(const FileMask : string); {tag all items that match the mask} begin if Assigned(FArchive) then FArchive.TagItems(FileMask) else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.UnTagItems(const FileMask : string); {clear tags for all items that match the mask} begin if Assigned(FArchive) then FArchive.UnTagItems(FileMask) else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.SetCompressionType(const Value: TAbArchiveType); begin if not Assigned(FArchive) or (Status <> asInvalid) then FArchiveType := Value else raise EAbArchiveBusy.Create; end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.SetArchiveProgressMeter(const Value: IAbProgressMeter); begin ReferenceInterface(FArchiveProgressMeter, opRemove); FArchiveProgressMeter := Value; ReferenceInterface(FArchiveProgressMeter, opInsert); end; { -------------------------------------------------------------------------- } procedure TAbBaseBrowser.SetItemProgressMeter(const Value: IAbProgressMeter); begin ReferenceInterface(FItemProgressMeter, opRemove); FItemProgressMeter := Value; ReferenceInterface(FItemProgressMeter, opInsert); end; { -------------------------------------------------------------------------- } function AbDetermineArcType(const FN : string; AssertType : TAbArchiveType) : TAbArchiveType; var Ext : string; FS : TFileStream; begin Result := AssertType; if Result = atUnknown then begin { Guess archive type based on it's extension } Ext := UpperCase(ExtractFileExt(FN)); if (Ext = '.ZIP') or (Ext = '.JAR') then Result := atZip; if (Ext = '.EXE') then Result := atSelfExtZip; if (Ext = '.TAR') then Result := atTar; if (Ext = '.GZ') then Result := atGzip; if (Ext = '.TGZ') then Result := atGzippedTar; if (Ext = '.CAB') then Result := atCab; if (Ext = '.BZ2') then Result := atBzip2; if (Ext = '.TBZ') then Result := atBzippedTar; end; {$IFNDEF MSWINDOWS} if Result = atCab then Result := atUnknown; {$ENDIF} if FileExists(FN) and (AbFileGetSize(FN) > 0) then begin { If the file doesn't exist (or is empty) presume to make one, otherwise guess or verify the contents } FS := TFileStream.Create(FN, fmOpenRead or fmShareDenyNone); try if Result = atUnknown then Result := AbDetermineArcType(FS) else begin case Result of atZip : begin Result := VerifyZip(FS); end; atSelfExtZip : begin Result := VerifySelfExtracting(FS); end; atTar : begin Result := VerifyTar(FS); end; atGzip, atGzippedTar: begin Result := VerifyGzip(FS); end; {$IFDEF MSWINDOWS} atCab : begin Result := VerifyCab(FS); end; {$ENDIF} atBzip2, atBzippedTar: begin Result := VerifyBzip2(FS); end; end; end; finally FS.Free; end; end; end; { -------------------------------------------------------------------------- } function AbDetermineArcType(aStream: TStream): TAbArchiveType; begin { VerifyZip returns true for self-extracting zips too, so test those first } Result := VerifySelfExtracting(aStream); if Result = atUnknown then Result := VerifyZip(aStream); if Result = atUnknown then Result := VerifyTar(aStream); if Result = atUnknown then Result := VerifyGzip(aStream); if Result = atUnknown then Result := VerifyBzip2(aStream); {$IFDEF MSWINDOWS} if Result = atUnknown then Result := VerifyCab(aStream); {$ENDIF} end; { -------------------------------------------------------------------------- } end. ================================================ FILE: lib/abbrevia/source/AbBseCLX.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbBaseCLX.pas *} {*********************************************************} {* ABBREVIA: Base component class (CLX) *} {*********************************************************} unit AbBseCLX; {$I AbDefine.inc} interface uses Classes, {$IFNDEF BuildingStub} QControls, {$ENDIF BuildingStub} AbConst, AbBase; {$IFNDEF BuildingStub} type TAbBaseWinControl = class(TWidgetControl); {$ENDIF BuildingStub} implementation end. ================================================ FILE: lib/abbrevia/source/AbBseVCL.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbBaseVCL.pas *} {*********************************************************} {* ABBREVIA: Base component class (VCL) *} {*********************************************************} unit AbBseVCL; {$I AbDefine.inc} interface uses Classes {$IFNDEF BuildingStub} , Controls {$ENDIF BuildingStub} ; {$IFNDEF BuildingStub} type TAbBaseWinControl = class(TWinControl); {$ENDIF BuildingStub} implementation end. ================================================ FILE: lib/abbrevia/source/AbBzip2.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * This program, "bzip2", the associated library "libbzip2", and all * documentation, are copyright (C) 1996-2007 Julian R Seward. All * rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. The origin of this software must not be misrepresented; you must * not claim that you wrote the original software. If you use this * software in a product, an acknowledgment in the product * documentation would be appreciated but is not required. * * 3. Altered source versions must be plainly marked as such, and must * not be misrepresented as being the original software. * * 4. The name of the author may not be used to endorse or promote * products derived from this software without specific prior written * permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Julian Seward, jseward@bzip.org * bzip2/libbzip2 version 1.0.5 of 10 December 2007 * * Pascal wrapper created by Edison Mera, version 1.04 * http://edisonlife.homelinux.com/ * * Dynamic and runtime linking and Win64/OS X/Linux support by Craig Peterson * http://tpabbrevia.sourceforge.net/ * ***** END LICENSE BLOCK ***** *) unit AbBzip2; {$I AbDefine.inc} interface uses SysUtils, Classes; type TAlloc = function(opaque: Pointer; Items, Size: Integer): Pointer; cdecl; TFree = procedure(opaque, Block: Pointer); cdecl; // Internal structure. Ignore. TBZStreamRec = record next_in: PByte; // next input byte avail_in: Integer; // number of bytes available at next_in total_in_lo32: Integer; // total nb of input bytes read so far total_in_hi32: Integer; next_out: PByte; // next output byte should be put here avail_out: Integer; // remaining free space at next_out total_out_lo32: Integer; // total nb of bytes output so far total_out_hi32: Integer; state: Pointer; bzalloc: TAlloc; // used to allocate the internal state bzfree: TFree; // used to free the internal state opaque: Pointer; end; // Abstract ancestor class TCustomBZip2Stream = class(TStream) private FStrm: TStream; FStrmPos: Int64; FOnProgress: TNotifyEvent; FBZRec: TBZStreamRec; FBuffer: array[Word] of Byte; protected procedure Progress(Sender: TObject); dynamic; property OnProgress: TNotifyEvent read FOnProgress write FOnProgress; constructor Create(Strm: TStream); end; { TBZCompressionStream compresses data on the fly as data is written to it, and stores the compressed data to another stream. TBZCompressionStream is write-only and strictly sequential. Reading from the stream will raise an exception. Using Seek to move the stream pointer will raise an exception. Output data is cached internally, written to the output stream only when the internal output buffer is full. All pending output data is flushed when the stream is destroyed. The Position property returns the number of uncompressed bytes of data that have been written to the stream so far. CompressionRate returns the on-the-fly percentage by which the original data has been compressed: (1 - (CompressedBytes / UncompressedBytes)) * 100 If raw data size = 100 and compressed data size = 25, the CompressionRate is 75% The OnProgress event is called each time the output buffer is filled and written to the output stream. This is useful for updating a progress indicator when you are writing a large chunk of data to the compression stream in a single call.} TBlockSize100k = (bs1, bs2, bs3, bs4, bs5, bs6, bs7, bs8, bs9); TBZCompressionStream = class(TCustomBZip2Stream) private function GetCompressionRate: Single; public constructor Create(BlockSize100k: TBlockSize100k; Dest: TStream); destructor Destroy; override; function Read(var Buffer; Count: Longint): Longint; override; function Write(const Buffer; Count: Longint): Longint; override; function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override; property CompressionRate: Single read GetCompressionRate; property OnProgress; end; { TDecompressionStream decompresses data on the fly as data is read from it. Compressed data comes from a separate source stream. TDecompressionStream is read-only and unidirectional; you can seek forward in the stream, but not backwards. The special case of setting the stream position to zero is allowed. Seeking forward decompresses data until the requested position in the uncompressed data has been reached. Seeking backwards, seeking relative to the end of the stream, requesting the size of the stream, and writing to the stream will raise an exception. The Position property returns the number of bytes of uncompressed data that have been read from the stream so far. The OnProgress event is called each time the internal input buffer of compressed data is exhausted and the next block is read from the input stream. This is useful for updating a progress indicator when you are reading a large chunk of data from the decompression stream in a single call.} TBZDecompressionStream = class(TCustomBZip2Stream) public constructor Create(Source: TStream); destructor Destroy; override; function Read(var Buffer; Count: Longint): Longint; override; function Write(const Buffer; Count: Longint): Longint; override; function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override; property OnProgress; end; { CompressBuf compresses data, buffer to buffer, in one call. In: InBuf = ptr to compressed data InBytes = number of bytes in InBuf Out: OutBuf = ptr to newly allocated buffer containing decompressed data OutBytes = number of bytes in OutBuf } procedure BZCompressBuf(const InBuf: Pointer; InBytes: Integer; out OutBuf: Pointer; out OutBytes: Integer); { DecompressBuf decompresses data, buffer to buffer, in one call. In: InBuf = ptr to compressed data InBytes = number of bytes in InBuf OutEstimate = zero, or est. size of the decompressed data Out: OutBuf = ptr to newly allocated buffer containing decompressed data OutBytes = number of bytes in OutBuf } procedure BZDecompressBuf(const InBuf: Pointer; InBytes: Integer; OutEstimate: Integer; out OutBuf: Pointer; out OutBytes: Integer); type EBZip2Error = class(Exception); EBZCompressionError = class(EBZip2Error); EBZDecompressionError = class(EBZip2Error); implementation // Compile for Win64 using MSVC // \bin\x86_amd64\cl.exe -c -nologo -GS- -Z7 -wd4086 -Gs32768 // -DBZ_NO_STDIO blocksort.c huffman.c compress.c decompress.c bzlib.c uses {$IFDEF Bzip2Runtime} {$IF DEFINED(FPC)} dynlibs, {$ELSEIF DEFINED(MSWINDOWS)} Windows, {$IFEND} {$ENDIF} AbUtils; {$IFDEF Bzip2Static} {$IF DEFINED(WIN32)} {$L Win32\blocksort.obj} {$L Win32\huffman.obj} {$L Win32\compress.obj} {$L Win32\decompress.obj} {$L Win32\bzlib.obj} {$ELSEIF DEFINED(WIN64)} {$L Win64\blocksort.obj} {$L Win64\huffman.obj} {$L Win64\compress.obj} {$L Win64\decompress.obj} {$L Win64\bzlib.obj} {$IFEND} procedure BZ2_hbMakeCodeLengths; external; procedure BZ2_blockSort; external; procedure BZ2_hbCreateDecodeTables; external; procedure BZ2_hbAssignCodes; external; procedure BZ2_compressBlock; external; procedure BZ2_decompress; external; {$ENDIF} type TLargeInteger = record case Integer of 0: ( LowPart: LongWord; HighPart: LongWord); 1: ( QuadPart: Int64); end; const BZ_RUN = 0; BZ_FLUSH = 1; BZ_FINISH = 2; BZ_OK = 0; BZ_RUN_OK = 1; BZ_FLUSH_OK = 2; BZ_FINISH_OK = 3; BZ_STREAM_END = 4; BZ_SEQUENCE_ERROR = (-1); BZ_PARAM_ERROR = (-2); BZ_MEM_ERROR = (-3); BZ_DATA_ERROR = (-4); BZ_DATA_ERROR_MAGIC = (-5); BZ_IO_ERROR = (-6); BZ_UNEXPECTED_EOF = (-7); BZ_OUTBUFF_FULL = (-8); BZ_BLOCK_SIZE_100K = 9; {$IFDEF Bzip2Static} BZ2_rNums: array[0..511] of Longint = ( 619, 720, 127, 481, 931, 816, 813, 233, 566, 247, 985, 724, 205, 454, 863, 491, 741, 242, 949, 214, 733, 859, 335, 708, 621, 574, 73, 654, 730, 472, 419, 436, 278, 496, 867, 210, 399, 680, 480, 51, 878, 465, 811, 169, 869, 675, 611, 697, 867, 561, 862, 687, 507, 283, 482, 129, 807, 591, 733, 623, 150, 238, 59, 379, 684, 877, 625, 169, 643, 105, 170, 607, 520, 932, 727, 476, 693, 425, 174, 647, 73, 122, 335, 530, 442, 853, 695, 249, 445, 515, 909, 545, 703, 919, 874, 474, 882, 500, 594, 612, 641, 801, 220, 162, 819, 984, 589, 513, 495, 799, 161, 604, 958, 533, 221, 400, 386, 867, 600, 782, 382, 596, 414, 171, 516, 375, 682, 485, 911, 276, 98, 553, 163, 354, 666, 933, 424, 341, 533, 870, 227, 730, 475, 186, 263, 647, 537, 686, 600, 224, 469, 68, 770, 919, 190, 373, 294, 822, 808, 206, 184, 943, 795, 384, 383, 461, 404, 758, 839, 887, 715, 67, 618, 276, 204, 918, 873, 777, 604, 560, 951, 160, 578, 722, 79, 804, 96, 409, 713, 940, 652, 934, 970, 447, 318, 353, 859, 672, 112, 785, 645, 863, 803, 350, 139, 93, 354, 99, 820, 908, 609, 772, 154, 274, 580, 184, 79, 626, 630, 742, 653, 282, 762, 623, 680, 81, 927, 626, 789, 125, 411, 521, 938, 300, 821, 78, 343, 175, 128, 250, 170, 774, 972, 275, 999, 639, 495, 78, 352, 126, 857, 956, 358, 619, 580, 124, 737, 594, 701, 612, 669, 112, 134, 694, 363, 992, 809, 743, 168, 974, 944, 375, 748, 52, 600, 747, 642, 182, 862, 81, 344, 805, 988, 739, 511, 655, 814, 334, 249, 515, 897, 955, 664, 981, 649, 113, 974, 459, 893, 228, 433, 837, 553, 268, 926, 240, 102, 654, 459, 51, 686, 754, 806, 760, 493, 403, 415, 394, 687, 700, 946, 670, 656, 610, 738, 392, 760, 799, 887, 653, 978, 321, 576, 617, 626, 502, 894, 679, 243, 440, 680, 879, 194, 572, 640, 724, 926, 56, 204, 700, 707, 151, 457, 449, 797, 195, 791, 558, 945, 679, 297, 59, 87, 824, 713, 663, 412, 693, 342, 606, 134, 108, 571, 364, 631, 212, 174, 643, 304, 329, 343, 97, 430, 751, 497, 314, 983, 374, 822, 928, 140, 206, 73, 263, 980, 736, 876, 478, 430, 305, 170, 514, 364, 692, 829, 82, 855, 953, 676, 246, 369, 970, 294, 750, 807, 827, 150, 790, 288, 923, 804, 378, 215, 828, 592, 281, 565, 555, 710, 82, 896, 831, 547, 261, 524, 462, 293, 465, 502, 56, 661, 821, 976, 991, 658, 869, 905, 758, 745, 193, 768, 550, 608, 933, 378, 286, 215, 979, 792, 961, 61, 688, 793, 644, 986, 403, 106, 366, 905, 644, 372, 567, 466, 434, 645, 210, 389, 550, 919, 135, 780, 773, 635, 389, 707, 100, 626, 958, 165, 504, 920, 176, 193, 713, 857, 265, 203, 50, 668, 108, 645, 990, 626, 197, 510, 357, 358, 850, 858, 364, 936, 638 ); BZ2_crc32Table: array[0..255] of Longint = ( $00000000, $04C11DB7, $09823B6E, $0D4326D9, $130476DC, $17C56B6B, $1A864DB2, $1E475005, $2608EDB8, $22C9F00F, $2F8AD6D6, $2B4BCB61, $350C9B64, $31CD86D3, $3C8EA00A, $384FBDBD, $4C11DB70, $48D0C6C7, $4593E01E, $4152FDA9, $5F15ADAC, $5BD4B01B, $569796C2, $52568B75, $6A1936C8, $6ED82B7F, $639B0DA6, $675A1011, $791D4014, $7DDC5DA3, $709F7B7A, $745E66CD, -$67DC4920, -$631D54A9, -$6E5E7272, -$6A9F6FC7, -$74D83FC4, -$70192275, -$7D5A04AE, -$799B191B, -$41D4A4A8, -$4515B911, -$48569FCA, -$4C97827F, -$52D0D27C, -$5611CFCD, -$5B52E916, -$5F93F4A3, -$2BCD9270, -$2F0C8FD9, -$224FA902, -$268EB4B7, -$38C9E4B4, -$3C08F905, -$314BDFDE, -$358AC26B, -$0DC57FD8, -$09046261, -$044744BA, -$0086590F, -$1EC1090C, -$1A0014BD, -$17433266, -$13822FD3, $34867077, $30476DC0, $3D044B19, $39C556AE, $278206AB, $23431B1C, $2E003DC5, $2AC12072, $128E9DCF, $164F8078, $1B0CA6A1, $1FCDBB16, $018AEB13, $054BF6A4, $0808D07D, $0CC9CDCA, $7897AB07, $7C56B6B0, $71159069, $75D48DDE, $6B93DDDB, $6F52C06C, $6211E6B5, $66D0FB02, $5E9F46BF, $5A5E5B08, $571D7DD1, $53DC6066, $4D9B3063, $495A2DD4, $44190B0D, $40D816BA, -$535A3969, -$579B24E0, -$5AD80207, -$5E191FB2, -$405E4FB5, -$449F5204, -$49DC74DB, -$4D1D696E, -$7552D4D1, -$7193C968, -$7CD0EFBF, -$7811F20A, -$6656A20D, -$6297BFBC, -$6FD49963, -$6B1584D6, -$1F4BE219, -$1B8AFFB0, -$16C9D977, -$1208C4C2, -$0C4F94C5, -$088E8974, -$05CDAFAB, -$010CB21E, -$39430FA1, -$3D821218, -$30C134CF, -$3400297A, -$2A47797D, -$2E8664CC, -$23C54213, -$27045FA6, $690CE0EE, $6DCDFD59, $608EDB80, $644FC637, $7A089632, $7EC98B85, $738AAD5C, $774BB0EB, $4F040D56, $4BC510E1, $46863638, $42472B8F, $5C007B8A, $58C1663D, $558240E4, $51435D53, $251D3B9E, $21DC2629, $2C9F00F0, $285E1D47, $36194D42, $32D850F5, $3F9B762C, $3B5A6B9B, $0315D626, $07D4CB91, $0A97ED48, $0E56F0FF, $1011A0FA, $14D0BD4D, $19939B94, $1D528623, -$0ED0A9F2, -$0A11B447, -$075292A0, -$03938F29, -$1DD4DF2E, -$1915C29B, -$1456E444, -$1097F9F5, -$28D8444A, -$2C1959FF, -$215A7F28, -$259B6291, -$3BDC3296, -$3F1D2F23, -$325E09FC, -$369F144D, -$42C17282, -$46006F37, -$4B4349F0, -$4F825459, -$51C5045E, -$550419EB, -$58473F34, -$5C862285, -$64C99F3A, -$6008828F, -$6D4BA458, -$698AB9E1, -$77CDE9E6, -$730CF453, -$7E4FD28C, -$7A8ECF3D, $5D8A9099, $594B8D2E, $5408ABF7, $50C9B640, $4E8EE645, $4A4FFBF2, $470CDD2B, $43CDC09C, $7B827D21, $7F436096, $7200464F, $76C15BF8, $68860BFD, $6C47164A, $61043093, $65C52D24, $119B4BE9, $155A565E, $18197087, $1CD86D30, $029F3D35, $065E2082, $0B1D065B, $0FDC1BEC, $3793A651, $3352BBE6, $3E119D3F, $3AD08088, $2497D08D, $2056CD3A, $2D15EBE3, $29D4F654, -$3A56D987, -$3E97C432, -$33D4E2E9, -$3715FF60, -$2952AF5B, -$2D93B2EE, -$20D09435, -$24118984, -$1C5E343F, -$189F298A, -$15DC0F51, -$111D12E8, -$0F5A42E3, -$0B9B5F56, -$06D8798D, -$0219643C, -$764702F7, -$72861F42, -$7FC53999, -$7B042430, -$6543742B, -$6182699E, -$6CC14F45, -$680052F4, -$504FEF4F, -$548EF2FA, -$59CDD421, -$5D0CC998, -$434B9993, -$478A8426, -$4AC9A2FD, -$4E08BF4C ); procedure bz_internal_error(errcode: Integer); cdecl; begin raise EBZip2Error.CreateFmt('Compression Error %d', [errcode]); end; { _bz_internal_error } function malloc(size: Integer): Pointer; cdecl; begin GetMem(Result, Size); end; { _malloc } procedure free(block: Pointer); cdecl; begin FreeMem(block); end; { _free } {$ENDIF} const libbz2 = {$IF DEFINED(MSWINDOWS)}'libbz2.dll' {$ELSEIF DEFINED(DARWIN)}'libbz2.dylib' {$ELSE}'libbz2.so.1'{$IFEND}; {$IFDEF Bzip2Runtime} var hBzip2: HMODULE; // deflate compresses data BZ2_bzCompressInit: function(var strm: TBZStreamRec; blockSize100k: Integer; verbosity: Integer; workFactor: Integer): Integer; {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} BZ2_bzCompress: function(var strm: TBZStreamRec; action: Integer): Integer; {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} BZ2_bzCompressEnd: function (var strm: TBZStreamRec): Integer; {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} BZ2_bzBuffToBuffCompress: function(dest: Pointer; var destLen: Integer; source: Pointer; sourceLen, blockSize100k, verbosity, workFactor: Integer): Integer; {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} // inflate decompresses data BZ2_bzDecompressInit: function(var strm: TBZStreamRec; verbosity: Integer; small: Integer): Integer; {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} BZ2_bzDecompress: function(var strm: TBZStreamRec): Integer; {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} BZ2_bzDecompressEnd: function(var strm: TBZStreamRec): Integer; {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} BZ2_bzBuffToBuffDecompress: function(dest: Pointer; var destLen: Integer; source: Pointer; sourceLen, small, verbosity: Integer): Integer; {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} {$ELSE} // deflate compresses data function BZ2_bzCompressInit(var strm: TBZStreamRec; blockSize100k: Integer; verbosity: Integer; workFactor: Integer): Integer; {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} external {$IFDEF Bzip2Dynamic}libbz2{$ENDIF} {$IFDEF DARWIN}name '_BZ2_bzCompressInit'{$ENDIF}; function BZ2_bzCompress(var strm: TBZStreamRec; action: Integer): Integer; {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} external {$IFDEF Bzip2Dynamic}libbz2{$ENDIF} {$IFDEF DARWIN}name '_BZ2_bzCompress'{$ENDIF}; function BZ2_bzCompressEnd(var strm: TBZStreamRec): Integer; {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} external {$IFDEF Bzip2Dynamic}libbz2{$ENDIF} {$IFDEF DARWIN}name '_BZ2_bzCompressEnd'{$ENDIF}; function BZ2_bzBuffToBuffCompress(dest: Pointer; var destLen: Integer; source: Pointer; sourceLen, blockSize100k, verbosity, workFactor: Integer): Integer; {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} external {$IFDEF Bzip2Dynamic}libbz2{$ENDIF} {$IFDEF DARWIN}name '_BZ2_bzBuffToBuffCompress'{$ENDIF}; // inflate decompresses data function BZ2_bzDecompressInit(var strm: TBZStreamRec; verbosity: Integer; small: Integer): Integer; {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} external {$IFDEF Bzip2Dynamic}libbz2{$ENDIF} {$IFDEF DARWIN}name '_BZ2_bzDecompressInit'{$ENDIF}; function BZ2_bzDecompress(var strm: TBZStreamRec): Integer; {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} external {$IFDEF Bzip2Dynamic}libbz2{$ENDIF} {$IFDEF DARWIN}name '_BZ2_bzDecompress'{$ENDIF}; function BZ2_bzDecompressEnd(var strm: TBZStreamRec): Integer; {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} external {$IFDEF Bzip2Dynamic}libbz2{$ENDIF} {$IFDEF DARWIN}name '_BZ2_bzDecompressEnd'{$ENDIF}; function BZ2_bzBuffToBuffDecompress(dest: Pointer; var destLen: Integer; source: Pointer; sourceLen, small, verbosity: Integer): Integer; {$IFDEF MSWINDOWS}stdcall;{$ELSE}cdecl;{$ENDIF} external {$IFDEF Bzip2Dynamic}libbz2{$ENDIF} {$IFDEF DARWIN}name '_BZ2_bzBuffToBuffDecompress'{$ENDIF}; {$ENDIF} procedure LoadBzip2DLL; begin {$IFDEF Bzip2Runtime} if hBzip2 <> 0 then Exit; hBzip2 := LoadLibrary(libbz2); if hBzip2 = 0 then raise EBZip2Error.Create('Bzip2 shared library not found'); @BZ2_bzCompressInit := GetProcAddress(hBzip2, 'BZ2_bzCompressInit'); @BZ2_bzCompress := GetProcAddress(hBzip2, 'BZ2_bzCompress'); @BZ2_bzCompressEnd := GetProcAddress(hBzip2, 'BZ2_bzCompressEnd'); @BZ2_bzBuffToBuffCompress := GetProcAddress(hBzip2, 'BZ2_bzBuffToBuffCompress'); @BZ2_bzDecompressInit := GetProcAddress(hBzip2, 'BZ2_bzDecompressInit'); @BZ2_bzDecompress := GetProcAddress(hBzip2, 'BZ2_bzDecompress'); @BZ2_bzDecompressEnd := GetProcAddress(hBzip2, 'BZ2_bzDecompressEnd'); @BZ2_bzBuffToBuffDecompress := GetProcAddress(hBzip2, 'BZ2_bzBuffToBuffDecompress'); {$ENDIF} end; function bzip2AllocMem(AppData: Pointer; Items, Size: Integer): Pointer; cdecl; begin GetMem(Result, Items * Size); end; { bzip2AllocMem } procedure bzip2FreeMem(AppData, Block: Pointer); cdecl; begin FreeMem(Block); end; { bzip2FreeMem } function CCheck(code: Integer): Integer; begin Result := code; if code < 0 then raise EBZCompressionError.CreateFmt('error %d', [code]); //!! end; { CCheck } function DCheck(code: Integer): Integer; begin Result := code; if code < 0 then raise EBZDecompressionError.CreateFmt('error %d', [code]); //!! end; { DCheck } procedure BZCompressBuf(const InBuf: Pointer; InBytes: Integer; out OutBuf: Pointer; out OutBytes: Integer); var strm: TBZStreamRec; P: Pointer; begin LoadBzip2DLL; FillChar(strm, sizeof(strm), 0); strm.bzalloc := bzip2AllocMem; strm.bzfree := bzip2FreeMem; OutBytes := ((InBytes + (InBytes div 10) + 12) + 255) and not 255; GetMem(OutBuf, OutBytes); try strm.next_in := InBuf; strm.avail_in := InBytes; strm.next_out := OutBuf; strm.avail_out := OutBytes; CCheck(BZ2_bzCompressInit(strm, 9, 0, 0)); try while CCheck(BZ2_bzCompress(strm, BZ_FINISH)) <> BZ_STREAM_END do begin P := OutBuf; Inc(OutBytes, 256); ReallocMem(OutBuf, OutBytes); strm.next_out := PByte(PtrInt(OutBuf) + (PtrInt(strm.next_out) - PtrInt(P))); strm.avail_out := 256; end; finally CCheck(BZ2_bzCompressEnd(strm)); end; ReallocMem(OutBuf, strm.total_out_lo32); OutBytes := strm.total_out_lo32; except FreeMem(OutBuf); raise end; end; procedure BZDecompressBuf(const InBuf: Pointer; InBytes: Integer; OutEstimate: Integer; out OutBuf: Pointer; out OutBytes: Integer); var strm: TBZStreamRec; P: Pointer; BufInc: Integer; begin LoadBzip2DLL; FillChar(strm, sizeof(strm), 0); strm.bzalloc := bzip2AllocMem; strm.bzfree := bzip2FreeMem; BufInc := (InBytes + 255) and not 255; if OutEstimate = 0 then OutBytes := BufInc else OutBytes := OutEstimate; GetMem(OutBuf, OutBytes); try strm.next_in := InBuf; strm.avail_in := InBytes; strm.next_out := OutBuf; strm.avail_out := OutBytes; DCheck(BZ2_bzDecompressInit(strm, 0, 0)); try while DCheck(BZ2_bzDecompress(strm)) <> BZ_STREAM_END do begin P := OutBuf; Inc(OutBytes, BufInc); ReallocMem(OutBuf, OutBytes); strm.next_out := PByte(PtrInt(OutBuf) + (PtrInt(strm.next_out) - PtrInt(P))); strm.avail_out := BufInc; end; finally DCheck(BZ2_bzDecompressEnd(strm)); end; ReallocMem(OutBuf, strm.total_out_lo32); OutBytes := strm.total_out_lo32; except FreeMem(OutBuf); raise end; end; // TCustomBZip2Stream constructor TCustomBZip2Stream.Create(Strm: TStream); begin inherited Create; FStrm := Strm; FStrmPos := Strm.Position; FBZRec.bzalloc := bzip2AllocMem; FBZRec.bzfree := bzip2FreeMem; end; procedure TCustomBZip2Stream.Progress(Sender: TObject); begin if Assigned(FOnProgress) then FOnProgress(Sender); end; { TCustomBZip2Stream } // TBZCompressionStream constructor TBZCompressionStream.Create(BlockSize100k: TBlockSize100k; Dest: TStream); const BlockSizes: array[TBlockSize100k] of ShortInt = (1, 2, 3, 4, 5, 6, 7, 8, 9); begin inherited Create(Dest); LoadBzip2DLL; FBZRec.next_out := @FBuffer[0]; FBZRec.avail_out := sizeof(FBuffer); CCheck(BZ2_bzCompressInit(FBZRec, BlockSizes[BlockSize100k], 0, 0)); end; destructor TBZCompressionStream.Destroy; begin if FBZRec.state <> nil then begin FBZRec.next_in := nil; FBZRec.avail_in := 0; try if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos; while (CCheck(BZ2_bzCompress(FBZRec, BZ_FINISH)) <> BZ_STREAM_END) and (FBZRec.avail_out = 0) do begin FStrm.WriteBuffer(FBuffer, sizeof(FBuffer)); FBZRec.next_out := @FBuffer[0]; FBZRec.avail_out := sizeof(FBuffer); end; if FBZRec.avail_out < sizeof(FBuffer) then FStrm.WriteBuffer(FBuffer, sizeof(FBuffer) - FBZRec.avail_out); finally BZ2_bzCompressEnd(FBZRec); end; end; inherited Destroy; end; function TBZCompressionStream.Read(var Buffer; Count: Longint): Longint; begin raise EBZCompressionError.Create('Invalid stream operation'); end; { TBZCompressionStream } function TBZCompressionStream.Write(const Buffer; Count: Longint): Longint; begin FBZRec.next_in := @Buffer; FBZRec.avail_in := Count; if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos; while (FBZRec.avail_in > 0) do begin CCheck(BZ2_bzCompress(FBZRec, BZ_RUN)); if FBZRec.avail_out = 0 then begin FStrm.WriteBuffer(FBuffer, sizeof(FBuffer)); FBZRec.next_out := @FBuffer[0]; FBZRec.avail_out := sizeof(FBuffer); FStrmPos := FStrm.Position; end; Progress(Self); end; Result := Count; end; { TBZCompressionStream } function TBZCompressionStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; var conv64 : TLargeInteger; begin if (Offset = 0) and (Origin = soCurrent) then begin conv64.LowPart := FBZRec.total_in_lo32; conv64.HighPart := FBZRec.total_in_hi32; Result := conv64.QuadPart end else raise EBZCompressionError.Create('Invalid stream operation'); end; { TBZCompressionStream } function TBZCompressionStream.GetCompressionRate: Single; var conv64In : TLargeInteger; conv64Out: TLargeInteger; begin conv64In.LowPart := FBZRec.total_in_lo32; conv64In.HighPart := FBZRec.total_in_hi32; conv64Out.LowPart := FBZRec.total_out_lo32; conv64Out.HighPart := FBZRec.total_out_hi32; if conv64In.QuadPart = 0 then Result := 0 else Result := (1.0 - (conv64Out.QuadPart / conv64In.QuadPart)) * 100.0; end; { TBZCompressionStream } // TDecompressionStream constructor TBZDecompressionStream.Create(Source: TStream); begin inherited Create(Source); LoadBzip2DLL; FBZRec.next_in := @FBuffer[0]; FBZRec.avail_in := 0; DCheck(BZ2_bzDecompressInit(FBZRec, 0, 0)); end; destructor TBZDecompressionStream.Destroy; begin if FBZRec.state <> nil then BZ2_bzDecompressEnd(FBZRec); inherited Destroy; end; function TBZDecompressionStream.Read(var Buffer; Count: Longint): Longint; begin FBZRec.next_out := @Buffer; FBZRec.avail_out := Count; if FStrm.Position <> FStrmPos then FStrm.Position := FStrmPos; while (FBZRec.avail_out > 0) do begin if FBZRec.avail_in = 0 then begin FBZRec.avail_in := FStrm.Read(FBuffer, sizeof(FBuffer)); if FBZRec.avail_in = 0 then begin Result := Count - FBZRec.avail_out; Exit; end; FBZRec.next_in := @FBuffer[0]; FStrmPos := FStrm.Position; end; CCheck(BZ2_bzDecompress(FBZRec)); Progress(Self); end; Result := Count; end; { TBZDecompressionStream } function TBZDecompressionStream.Write(const Buffer; Count: Longint): Longint; begin raise EBZDecompressionError.Create('Invalid stream operation'); end; { TBZDecompressionStream } function TBZDecompressionStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; var I : Integer; Buf : array[0..4095] of Char; conv64: TLargeInteger; NewOff: Int64; begin conv64.LowPart := FBZRec.total_out_lo32; conv64.HighPart := FBZRec.total_out_hi32; if (Offset = 0) and (Origin = soBeginning) then begin DCheck(BZ2_bzDecompressEnd(FBZRec)); DCheck(BZ2_bzDecompressInit(FBZRec, 0, 0)); FBZRec.next_in := @FBuffer[0]; FBZRec.avail_in := 0; FStrm.Position := 0; FStrmPos := 0; end else if ((Offset >= 0) and (Origin = soCurrent)) or (((Offset - conv64.QuadPart) > 0) and (Origin = soBeginning)) then begin NewOff := Offset; if Origin = soBeginning then Dec(NewOff, conv64.QuadPart); if NewOff > 0 then begin for I := 1 to NewOff div sizeof(Buf) do ReadBuffer(Buf, sizeof(Buf)); ReadBuffer(Buf, NewOff mod sizeof(Buf)); end; end else raise EBZDecompressionError.Create('Invalid stream operation'); Result := conv64.QuadPart; end; { TBZDecompressionStream } end. ================================================ FILE: lib/abbrevia/source/AbBzip2Typ.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * Joel Haynie * Craig Peterson * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbBzip2Typ.pas *} {*********************************************************} {* ABBREVIA: TAbBzip2Archive, TAbBzip2Item classes *} {*********************************************************} {* Misc. constants, types, and routines for working *} {* with Bzip2 files *} {*********************************************************} unit AbBzip2Typ; {$I AbDefine.inc} interface uses Classes, AbArcTyp, AbTarTyp, AbUtils; const { Default Stream Header for Bzip2s is 'BZhX', where X is the block size setting 1-9 in ASCII } { Each block has the following header: '1AY&SY', and are in units of 100kilobytes NOT 100kibiBytes } AB_BZIP2_FILE_HEADER = 'BZh'; AB_BZIP2_BLOCK_SIZE = ['1','2','3','4','5','6','7','8','9']; AB_BZIP2_BLOCK_HEADER = '1AY&SY'; { Note: $314159265359, BCD for Pi :) } { Note that Blocks are bit aligned, as such the only time you will "for sure" see the block header is on the start of stream/File } AB_BZIP2_FILE_TAIL =#23#114#36#83#133#9#0; { $1772245385090, BCD for sqrt(Pi) :) } { This is odd as the blocks are bit allgned so this is a string that is 13*4 bits = 52 bits } type PAbBzip2Header = ^TAbBzip2Header; { File Header } TAbBzip2Header = packed record { SizeOf(TAbBzip2Header) = 10 } FileHeader : array[0..2] of AnsiChar;{ 'BZh'; $42,5A,68 } BlockSize : AnsiChar; { '1'..'9'; $31-$39 } BlockHeader : array[0..5] of AnsiChar;{ '1AY&SY'; $31,41,59,26,53,59 } end; { The Purpose for this Item is the placeholder for aaAdd and aaDelete Support. } { For all intents and purposes we could just use a TAbArchiveItem } type TAbBzip2Item = class(TabArchiveItem); TAbBzip2ArchiveState = (gsBzip2, gsTar); TAbBzip2Archive = class(TAbTarArchive) private FBzip2Stream : TStream; { stream for Bzip2 file} FBzip2Item : TAbArchiveList; { item in bzip2 (only one, but need polymorphism of class)} FTarStream : TStream; { stream for possible contained Tar } FTarList : TAbArchiveList; { items in possible contained Tar } FTarAutoHandle: Boolean; FState : TAbBzip2ArchiveState; FIsBzippedTar : Boolean; procedure DecompressToStream(aStream: TStream); procedure SetTarAutoHandle(const Value: Boolean); procedure SwapToBzip2; procedure SwapToTar; protected { Inherited Abstract functions } function CreateItem(const FileSpec : string): TAbArchiveItem; override; procedure ExtractItemAt(Index : Integer; const NewName : string); override; procedure ExtractItemToStreamAt(Index : Integer; aStream : TStream); override; procedure LoadArchive; override; procedure SaveArchive; override; procedure TestItemAt(Index : Integer); override; function GetSupportsEmptyFolders : Boolean; override; public {methods} constructor CreateFromStream(aStream : TStream; const aArchiveName : string); override; destructor Destroy; override; procedure DoSpanningMediaRequest(Sender : TObject; ImageNumber : Integer; var ImageName : string; var Abort : Boolean); override; { Properties } property TarAutoHandle : Boolean read FTarAutoHandle write SetTarAutoHandle; property IsBzippedTar : Boolean read FIsBzippedTar write FIsBzippedTar; end; function VerifyBzip2(Strm : TStream) : TAbArchiveType; implementation uses {$IFDEF MSWINDOWS} Windows, // Fix inline warnings {$ENDIF} StrUtils, SysUtils, AbBzip2, AbExcept, AbVMStrm, AbBitBkt; { ****************** Helper functions Not from Classes Above ***************** } function VerifyHeader(const Header : TAbBzip2Header) : Boolean; begin Result := (Header.FileHeader = AB_BZIP2_FILE_HEADER) and (Header.BlockSize in AB_BZIP2_BLOCK_SIZE) and (Header.BlockHeader = AB_BZIP2_BLOCK_HEADER); end; { -------------------------------------------------------------------------- } function VerifyBzip2(Strm : TStream) : TAbArchiveType; var Hdr : TAbBzip2Header; CurPos : int64; DecompStream, TarStream: TStream; begin Result := atUnknown; CurPos := Strm.Position; Strm.Seek(0, soBeginning); try if (Strm.Read(Hdr, SizeOf(Hdr)) = SizeOf(Hdr)) and VerifyHeader(Hdr) then begin Result := atBzip2; { Check for embedded TAR } Strm.Seek(0, soBeginning); DecompStream := TBZDecompressionStream.Create(Strm); try TarStream := TMemoryStream.Create; try TarStream.CopyFrom(DecompStream, 512 * 2); TarStream.Seek(0, soBeginning); if VerifyTar(TarStream) = atTar then Result := atBzippedTar; finally TarStream.Free; end; finally DecompStream.Free; end; end; except on EReadError do Result := atUnknown; end; Strm.Position := CurPos; { Return to original position. } end; { ****************************** TAbBzip2Archive ***************************** } constructor TAbBzip2Archive.CreateFromStream(aStream: TStream; const aArchiveName: string); begin inherited CreateFromStream(aStream, aArchiveName); FState := gsBzip2; FBzip2Stream := FStream; FBzip2Item := FItemList; FTarStream := TAbVirtualMemoryStream.Create; FTarList := TAbArchiveList.Create(True); end; { -------------------------------------------------------------------------- } procedure TAbBzip2Archive.SwapToTar; begin FStream := FTarStream; FItemList := FTarList; FState := gsTar; end; { -------------------------------------------------------------------------- } procedure TAbBzip2Archive.SwapToBzip2; begin FStream := FBzip2Stream; FItemList := FBzip2Item; FState := gsBzip2; end; { -------------------------------------------------------------------------- } function TAbBzip2Archive.CreateItem(const FileSpec: string): TAbArchiveItem; begin if IsBzippedTar and TarAutoHandle then begin SwapToTar; Result := inherited CreateItem(FileSpec); end else begin SwapToBzip2; Result := TAbBzip2Item.Create; try Result.DiskFileName := ExpandFileName(FileSpec); Result.FileName := FixName(FileSpec); except Result.Free; raise; end; end; end; { -------------------------------------------------------------------------- } destructor TAbBzip2Archive.Destroy; begin SwapToBzip2; FTarList.Free; FTarStream.Free; inherited Destroy; end; { -------------------------------------------------------------------------- } procedure TAbBzip2Archive.ExtractItemAt(Index: Integer; const NewName: string); var OutStream : TFileStream; begin if IsBzippedTar and TarAutoHandle then begin SwapToTar; inherited ExtractItemAt(Index, NewName); end else begin SwapToBzip2; OutStream := TFileStream.Create(NewName, fmCreate or fmShareDenyNone); try try ExtractItemToStreamAt(Index, OutStream); finally OutStream.Free; end; { Bz2 doesn't store the last modified time or attributes, so don't set them } except on E : EAbUserAbort do begin FStatus := asInvalid; if FileExists(NewName) then DeleteFile(NewName); raise; end else begin if FileExists(NewName) then DeleteFile(NewName); raise; end; end; end; end; { -------------------------------------------------------------------------- } procedure TAbBzip2Archive.ExtractItemToStreamAt(Index: Integer; aStream: TStream); begin if IsBzippedTar and TarAutoHandle then begin SwapToTar; inherited ExtractItemToStreamAt(Index, aStream); end else begin SwapToBzip2; { Index ignored as there's only one item in a Bz2 } DecompressToStream(aStream); end; end; { -------------------------------------------------------------------------- } function TAbBzip2Archive.GetSupportsEmptyFolders : Boolean; begin Result := IsBzippedTar and TarAutoHandle; end; { -------------------------------------------------------------------------- } procedure TAbBzip2Archive.LoadArchive; var Item: TAbBzip2Item; Abort: Boolean; ItemName: string; begin if FBzip2Stream.Size = 0 then Exit; if IsBzippedTar and TarAutoHandle then begin { Decompress and send to tar LoadArchive } DecompressToStream(FTarStream); SwapToTar; inherited LoadArchive; end else begin SwapToBzip2; Item := TAbBzip2Item.Create; Item.Action := aaNone; { Filename isn't stored, so constuct one based on the archive name } ItemName := ExtractFileName(ArchiveName); if ItemName = '' then Item.FileName := 'unknown' else if AnsiEndsText('.tbz', ItemName) or AnsiEndsText('.tbz2', ItemName) then Item.FileName := ChangeFileExt(ItemName, '.tar') else Item.FileName := ChangeFileExt(ItemName, ''); Item.DiskFileName := Item.FileName; FItemList.Add(Item); end; DoArchiveProgress(100, Abort); FIsDirty := False; end; { -------------------------------------------------------------------------- } procedure TAbBzip2Archive.SaveArchive; var CompStream: TStream; i: Integer; CurItem: TAbBzip2Item; InputFileStream: TStream; begin if IsBzippedTar and TarAutoHandle then begin SwapToTar; inherited SaveArchive; FTarStream.Position := 0; FBzip2Stream.Size := 0; CompStream := TBZCompressionStream.Create(bs9, FBzip2Stream); try CompStream.CopyFrom(FTarStream, 0); finally CompStream.Free; end; end else begin { Things we know: There is only one file per archive.} { Actions we have to address in SaveArchive: } { aaNone & aaMove do nothing, as the file does not change, only the meta data } { aaDelete could make a zero size file unless there are two files in the list.} { aaAdd, aaStreamAdd, aaFreshen, & aaReplace will be the only ones to take action. } SwapToBzip2; for i := 0 to pred(Count) do begin FCurrentItem := ItemList[i]; CurItem := TAbBzip2Item(ItemList[i]); case CurItem.Action of aaNone, aaMove: Break;{ Do nothing; bz2 doesn't store metadata } aaDelete: ; {doing nothing omits file from new stream} aaAdd, aaFreshen, aaReplace, aaStreamAdd: begin FBzip2Stream.Size := 0; CompStream := TBZCompressionStream.Create(bs9, FBzip2Stream); try if CurItem.Action = aaStreamAdd then CompStream.CopyFrom(InStream, 0){ Copy/compress entire Instream to FBzip2Stream } else begin InputFileStream := TFileStream.Create(CurItem.DiskFileName, fmOpenRead or fmShareDenyWrite ); try CompStream.CopyFrom(InputFileStream, 0);{ Copy/compress entire Instream to FBzip2Stream } finally InputFileStream.Free; end; end; finally CompStream.Free; end; Break; end; { End aaAdd, aaFreshen, aaReplace, & aaStreamAdd } end; { End of CurItem.Action Case } end; { End Item for loop } end; { End Tar Else } end; { -------------------------------------------------------------------------- } procedure TAbBzip2Archive.SetTarAutoHandle(const Value: Boolean); begin if Value then SwapToTar else SwapToBzip2; FTarAutoHandle := Value; end; { -------------------------------------------------------------------------- } procedure TAbBzip2Archive.DecompressToStream(aStream: TStream); const BufSize = $F000; var DecompStream: TBZDecompressionStream; Buffer: PByte; N: Integer; begin DecompStream := TBZDecompressionStream.Create(FBzip2Stream); try GetMem(Buffer, BufSize); try N := DecompStream.Read(Buffer^, BufSize); while N > 0 do begin aStream.WriteBuffer(Buffer^, N); N := DecompStream.Read(Buffer^, BufSize); end; finally FreeMem(Buffer, BufSize); end; finally DecompStream.Free; end; end; { -------------------------------------------------------------------------- } procedure TAbBzip2Archive.TestItemAt(Index: Integer); var Bzip2Type: TAbArchiveType; BitBucket: TAbBitBucketStream; begin if IsBzippedTar and TarAutoHandle then begin SwapToTar; inherited TestItemAt(Index); end else begin { note Index ignored as there's only one item in a GZip } Bzip2Type := VerifyBzip2(FBzip2Stream); if not (Bzip2Type in [atBzip2, atBzippedTar]) then raise EAbGzipInvalid.Create;// TODO: Add bzip2-specific exceptions } BitBucket := TAbBitBucketStream.Create(1024); try DecompressToStream(BitBucket); finally BitBucket.Free; end; end; end; { -------------------------------------------------------------------------- } procedure TAbBzip2Archive.DoSpanningMediaRequest(Sender: TObject; ImageNumber: Integer; var ImageName: string; var Abort: Boolean); begin Abort := False; end; end. ================================================ FILE: lib/abbrevia/source/AbCBrows.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbCBrows.pas *} {*********************************************************} {* ABBREVIA: Cabinet file browser component *} {*********************************************************} unit AbCBrows; {$I AbDefine.inc} interface uses Classes, AbBrowse, AbCabTyp; type TAbCustomCabBrowser = class(TAbBaseBrowser) protected {private} FSetID : Word; function GetCabArchive : TAbCabArchive; function GetCabSize : Longint; function GetCurrentCab : Word; function GetFolderCount : Word; function GetItem(Index : Integer) : TAbCabItem; virtual; function GetHasNext : Boolean; function GetHasPrev : Boolean; function GetSetID : Word; procedure InitArchive; override; procedure SetFileName(const aFileName : string); override; procedure SetSetID(Value : Word); protected {properties} property CabSize : Longint read GetCabSize; property CurrentCab : Word read GetCurrentCab; property FolderCount : Word read GetFolderCount; property HasNext : Boolean read GetHasNext; property HasPrev : Boolean read GetHasPrev; property SetID : Word read GetSetID write SetSetID; public {methods} constructor Create(AOwner : TComponent); override; destructor Destroy; override; public {properties} property CabArchive : TAbCabArchive read GetCabArchive; property Items[Index : Integer] : TAbCabItem read GetItem; default; end; type {$IFDEF HasPlatformsAttribute} [ComponentPlatformsAttribute(pidWin32 or pidWin64)] {$ENDIF} TAbCabBrowser = class(TAbCustomCabBrowser) published property ArchiveProgressMeter; property BaseDirectory; property CabSize; property CurrentCab; property FolderCount; property HasNext; property HasPrev; property ItemProgressMeter; property LogFile; property Logging; property OnArchiveProgress; property OnArchiveItemProgress; property OnChange; property OnLoad; property SetID; property TempDirectory; property Version; property FileName; {must be after OnLoad} end; {.Z+} implementation uses SysUtils, AbArcTyp, AbUtils; { TAbCustomCabBrowser ====================================================== } constructor TAbCustomCabBrowser.Create(AOwner : TComponent); begin inherited Create(AOwner); FArchiveType := atCab; end; { -------------------------------------------------------------------------- } destructor TAbCustomCabBrowser.Destroy; begin inherited Destroy; end; { -------------------------------------------------------------------------- } function TAbCustomCabBrowser.GetCabArchive : TAbCabArchive; begin if Assigned(Archive) then Result := TAbCabArchive(Archive) else Result := nil; end; { -------------------------------------------------------------------------- } function TAbCustomCabBrowser.GetCabSize : Longint; begin if Assigned(Archive) then Result := TAbCabArchive(Archive).CabSize else Result := 0; end; { -------------------------------------------------------------------------- } function TAbCustomCabBrowser.GetCurrentCab : Word; begin if Assigned(Archive) then Result := TAbCabArchive(Archive).CurrentCab else Result := 0; end; { -------------------------------------------------------------------------- } function TAbCustomCabBrowser.GetFolderCount : Word; begin if Assigned(Archive) then Result := TAbCabArchive(Archive).FolderCount else Result := 0; end; { -------------------------------------------------------------------------- } function TAbCustomCabBrowser.GetHasNext : Boolean; begin if Assigned(Archive) then Result := TAbCabArchive(Archive).HasNext else Result := False; end; { -------------------------------------------------------------------------- } function TAbCustomCabBrowser.GetHasPrev : Boolean; begin if Assigned(Archive) then Result := TAbCabArchive(Archive).HasPrev else Result := False; end; { -------------------------------------------------------------------------- } function TAbCustomCabBrowser.GetItem(Index : Integer) : TAbCabItem; {return cabinet item} begin if Assigned(CabArchive) then Result := CabArchive.Items[Index] else Result := nil; end; { -------------------------------------------------------------------------- } function TAbCustomCabBrowser.GetSetID : Word; begin if Assigned(Archive) then Result := TAbCabArchive(Archive).SetID else Result := 0; end; { -------------------------------------------------------------------------- } procedure TAbCustomCabBrowser.InitArchive; begin inherited InitArchive; if Assigned(Archive) then TAbCabArchive(Archive).SetID := FSetID; end; { -------------------------------------------------------------------------- } procedure TAbCustomCabBrowser.SetFileName(const aFileName : string); {open/create cabinet archive} begin FFileName := aFileName; if (csDesigning in ComponentState) then Exit; if Assigned(FArchive) then begin FArchive.Free; FArchive := nil; end; if (aFileName <> '') and FileExists(aFilename) and (AbDetermineArcType(aFileName, atCab) = atCab) then begin FArchive := TAbCabArchive.Create(aFileName, fmOpenRead); InitArchive; FArchive.Load; end; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomCabBrowser.SetSetID(Value : Word); begin FSetID := Value; if Assigned(Archive) then TAbCabArchive(Archive).SetID := Value; end; { -------------------------------------------------------------------------- } end. ================================================ FILE: lib/abbrevia/source/AbCView.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbCView.pas *} {*********************************************************} {* ABBREVIA: Cabinet archive viewer component *} {* Use AbQCView.pas for CLX *} {*********************************************************} {$IFNDEF UsingCLX} Unit AbCView; {$ENDIF} {$I AbDefine.inc} interface uses Windows, Classes, {$IFDEF UsingClx} AbQView, {$ELSE} AbView, {$ENDIF} AbCBrows, AbCabTyp, AbArcTyp; type TAbCabView = class(TAbBaseViewer) protected FCabComponent : TAbCustomCabBrowser; FEmptyItemList: TAbArchiveList; function GetItem(RowNum : Longint) : TAbCabItem; procedure SetCabComponent(Value : TAbCustomCabBrowser); procedure Notification(AComponent : TComponent; Operation : TOperation); override; procedure DoChange(Sender : TObject); override; public constructor Create(AOwner : TComponent); override; destructor Destroy; override; property Items[RowNum : Longint] : TAbCabItem read GetItem; published {properties} property Align; property Attributes; property BorderStyle; property Color; property Colors; {$IFNDEF UsingClx} property Ctl3D; {$ENDIF} property Cursor; property Headings; property DefaultColWidth; property DefaultRowHeight; property DisplayOptions; property HeaderRowHeight; property SortAttributes; {$IFNDEF UsingClx} property DragCursor; {$ENDIF} property DragMode; property Enabled; property Font; property ParentColor; {$IFNDEF UsingClx} property ParentCtl3D; {$ENDIF} property ParentFont; property ParentShowHint; property PopupMenu; property ShowHint; property TabOrder; property TabStop; property Version; property CabComponent : TAbCustomCabBrowser read FCabComponent write SetCabComponent; published {Events} property OnChange; property OnClick; property OnDblClick; property OnEnter; property OnExit; property OnKeyDown; property OnKeyPress; property OnKeyUp; property OnMouseDown; property OnMouseMove; property OnMouseUp; property OnSorted; property OnDrawSortArrow; end; implementation type TAbCabBrowserFriend = class(TAbCustomCabBrowser); { ===== TAbCabView ========================================================= } constructor TAbCabView.Create(AOwner : TComponent); begin inherited; FEmptyItemList := FItemList; end; { -------------------------------------------------------------------------- } destructor TAbCabView.Destroy; begin FItemList := FEmptyItemList; inherited; end; { -------------------------------------------------------------------------- } function TAbCabView.GetItem(RowNum : Longint) : TAbCabItem; begin if Assigned(FItemList) then Result := TAbCabItem(FItemList.Items[FRowMap[RowNum]]) else Result := nil; end; { -------------------------------------------------------------------------- } procedure TAbCabView.Notification(AComponent : TComponent; Operation : TOperation); begin inherited Notification(AComponent, Operation); if Operation = opRemove then if Assigned(FCabComponent) and (AComponent = FCabComponent) then begin FCabComponent := nil; Refresh; end; end; { -------------------------------------------------------------------------- } procedure TAbCabView.SetCabComponent(Value : TAbCustomCabBrowser); begin FCabComponent := Value; FCabComponent.OnChange := DoChange; FCabComponent.OnLoad := DoLoad; DoChange(Self); end; { -------------------------------------------------------------------------- } procedure TAbCabView.DoChange(Sender : TObject); begin if Assigned(FCabComponent) and Assigned(TAbCabBrowserFriend(FCabComponent).Archive) then FItemList := TAbCabBrowserFriend(FCabComponent).Archive.ItemList else if FEmptyItemList <> nil then FItemList := FEmptyItemList; inherited DoChange(Sender); end; end. ================================================ FILE: lib/abbrevia/source/AbCabExt.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbCabExt.pas *} {*********************************************************} {* ABBREVIA: Cabinet file extractor component *} {*********************************************************} unit AbCabExt; {$I AbDefine.inc} interface uses Classes, AbCBrows, AbArcTyp; type TAbCustomCabExtractor = class(TAbCustomCabBrowser) protected {private} FExtractOptions : TAbExtractOptions; FOnConfirmOverwrite : TAbConfirmOverwriteEvent; procedure DoConfirmOverwrite(var Name : string; var Confirm : Boolean); procedure InitArchive; override; procedure SetExtractOptions( Value : TAbExtractOptions ); protected {properties} property ExtractOptions : TAbExtractOptions read FExtractOptions write SetExtractOptions default AbDefExtractOptions; property OnConfirmOverwrite : TAbConfirmOverwriteEvent read FOnConfirmOverwrite write FOnConfirmOverwrite; public constructor Create( AOwner : TComponent ); override; destructor Destroy; override; procedure ExtractAt(Index : Integer; const NewName : string); procedure ExtractFiles(const FileMask : string); procedure ExtractFilesEx(const FileMask, ExclusionMask : string); procedure ExtractTaggedItems; end; {$IFDEF HasPlatformsAttribute} [ComponentPlatformsAttribute(pidWin32 or pidWin64)] {$ENDIF} TAbCabExtractor = class(TAbCustomCabExtractor) published property ArchiveProgressMeter; property BaseDirectory; property CabSize; property CurrentCab; property ExtractOptions; property FolderCount; property HasNext; property HasPrev; property ItemProgressMeter; property OnArchiveProgress; property OnArchiveItemProgress; property OnChange; property OnConfirmOverwrite; property OnConfirmProcessItem; property OnLoad; property OnProcessItemFailure; property OnRequestImage; property SetID; property TempDirectory; property Version; property FileName; {must be after OnLoad} end; {.Z+} implementation uses AbExcept; { TAbCustomCabExtractor ==================================================== } constructor TAbCustomCabExtractor.Create(AOwner : TComponent); begin inherited Create( AOwner ); ExtractOptions := AbDefExtractOptions; end; { -------------------------------------------------------------------------- } destructor TAbCustomCabExtractor.Destroy; begin inherited Destroy; end; { -------------------------------------------------------------------------- } procedure TAbCustomCabExtractor.DoConfirmOverwrite (var Name : string; var Confirm : Boolean); begin if Assigned(FOnConfirmOverwrite) then FOnConfirmOverwrite(Name, Confirm); end; { -------------------------------------------------------------------------- } procedure TAbCustomCabExtractor.ExtractAt(Index : Integer; const NewName : string); {extract a file from the archive that match the index} begin if Assigned( CabArchive ) then CabArchive.ExtractAt( Index, NewName ) else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomCabExtractor.ExtractFiles(const FileMask : string); {Extract files from the cabinet matching the filemask} begin if Assigned( CabArchive ) then CabArchive.ExtractFiles( FileMask ) else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomCabExtractor.ExtractFilesEx(const FileMask, ExclusionMask : string); {Extract files from the cabinet matching the FileMask, exluding those matching ExclusionMask} begin if Assigned( CabArchive ) then CabArchive.ExtractFilesEx( FileMask, ExclusionMask ) else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomCabExtractor.ExtractTaggedItems; {Extract items in the archive that have been tagged} begin if Assigned( CabArchive ) then CabArchive.ExtractTaggedItems else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomCabExtractor.InitArchive; {Archive now points to the Cab file, update all Archive's properties...} begin inherited InitArchive; if Assigned( CabArchive ) then begin {poperties} CabArchive.ExtractOptions := FExtractOptions; {events} CabArchive.OnConfirmOverwrite := DoConfirmOverwrite; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomCabExtractor.SetExtractOptions( Value : TAbExtractOptions ); begin FExtractOptions := Value; if Assigned( FArchive ) then FArchive.ExtractOptions := Value; end; { -------------------------------------------------------------------------- } end. ================================================ FILE: lib/abbrevia/source/AbCabKit.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbCabKit.PAS *} {*********************************************************} {* ABBREVIA: Cabinet file builder/extractor component *} {*********************************************************} unit AbCabKit; {$I AbDefine.inc} interface uses Classes, AbArcTyp, AbCabMak; type TAbCustomCabKit = class(TAbCustomMakeCab) protected {private} FExtractOptions : TAbExtractOptions; FOnConfirmOverwrite : TAbConfirmOverwriteEvent; procedure DoConfirmOverwrite(var Name : string; var Confirm : Boolean); procedure InitArchive; override; procedure SetExtractOptions( Value : TAbExtractOptions ); procedure SetFileName(const aFileName : string); override; protected {properties} property ExtractOptions : TAbExtractOptions read FExtractOptions write SetExtractOptions default AbDefExtractOptions; protected {events} property OnConfirmOverwrite : TAbConfirmOverwriteEvent read FOnConfirmOverwrite write FOnConfirmOverwrite; public {methods} constructor Create( AOwner : TComponent ); override; destructor Destroy; override; procedure ExtractAt(Index : Integer; const NewName : string); procedure ExtractFiles(const FileMask : string); procedure ExtractFilesEx(const FileMask, ExclusionMask : string); procedure ExtractTaggedItems; end; {$IFDEF HasPlatformsAttribute} [ComponentPlatformsAttribute(pidWin32 or pidWin64)] {$ENDIF} TAbCabKit = class(TAbCustomCabKit) published property ArchiveProgressMeter; property BaseDirectory; property CabSize; property CompressionType; property CurrentCab; property ExtractOptions; property FolderCount; property FolderThreshold; property HasNext; property HasPrev; property ItemProgressMeter; property OnArchiveProgress; property OnArchiveItemProgress; property OnChange; property OnConfirmOverwrite; property OnConfirmProcessItem; property OnLoad; property OnProcessItemFailure; property OnRequestImage; property OnSave; property SetID; property SpanningThreshold; property TempDirectory; property Version; property FileName; {must be after OnLoad} end; implementation uses SysUtils, AbExcept, AbCabTyp, AbCBrows; { TAbCustomCabKit ==================================================== } constructor TAbCustomCabKit.Create(AOwner : TComponent); begin inherited Create( AOwner ); ExtractOptions := AbDefExtractOptions; end; { -------------------------------------------------------------------------- } destructor TAbCustomCabKit.Destroy; begin inherited Destroy; end; { -------------------------------------------------------------------------- } procedure TAbCustomCabKit.DoConfirmOverwrite(var Name : string; var Confirm : Boolean); begin if Assigned(FOnConfirmOverwrite) then FOnConfirmOverwrite(Name, Confirm); end; { -------------------------------------------------------------------------- } procedure TAbCustomCabKit.ExtractAt(Index : Integer; const NewName : string); {extract a file from the archive that match the index} begin if Assigned( CabArchive ) then CabArchive.ExtractAt( Index, NewName ) else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomCabKit.ExtractFiles(const FileMask : string); {Extract files from the cabinet matching the filemask} begin if Assigned(CabArchive) then CabArchive.ExtractFiles(FileMask) else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomCabKit.ExtractFilesEx(const FileMask, ExclusionMask : string); {Extract files from the cabinet matching the FileMask, exluding those matching ExclusionMask} begin if Assigned(CabArchive) then CabArchive.ExtractFilesEx(FileMask, ExclusionMask) else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomCabKit.ExtractTaggedItems; {Extract items in the archive that have been tagged} begin if Assigned(CabArchive) then CabArchive.ExtractTaggedItems else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomCabKit.InitArchive; begin inherited InitArchive; if Assigned( CabArchive ) then begin {poperties} CabArchive.ExtractOptions := FExtractOptions; {events} CabArchive.OnConfirmOverwrite := DoConfirmOverwrite; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomCabKit.SetExtractOptions( Value : TAbExtractOptions ); begin FExtractOptions := Value; if Assigned( FArchive ) then FArchive.ExtractOptions := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomCabKit.SetFileName(const aFileName : string); {Create or open the specified cabinet file} begin FFilename := aFileName; if csDesigning in ComponentState then Exit; if Assigned(FArchive) then begin FArchive.Free; FArchive := nil; end; if (aFileName <> '') then begin if (aFileName <> '') and FileExists(aFilename) then FArchive := TAbCabArchive.Create(aFileName, fmOpenRead) else FArchive := TAbCabArchive.Create(aFileName, fmOpenWrite); InitArchive; FArchive.Load; end; DoChange; end; { -------------------------------------------------------------------------- } end. ================================================ FILE: lib/abbrevia/source/AbCabMak.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbCabMak.pas *} {*********************************************************} {* ABBREVIA: Cabinet builder component (VCL) *} {* See AbQCabMk.pas for the CLX header *} {*********************************************************} unit AbCabMak; {$I AbDefine.inc} interface uses Classes, AbCBrows, AbArcTyp, AbCabTyp; type TAbCustomMakeCab = class(TAbCustomCabBrowser) protected {private} FFolderThreshold : Longint; FCompressionType : TAbCabCompressionType; FStoreOptions : TAbStoreOptions; FOnSave : TAbArchiveEvent; protected {methods} procedure DoSave(Sender : TObject); virtual; procedure InitArchive; override; procedure SetFolderThreshold(Value : Longint); procedure SetCompressionType(Value : TAbCabCompressionType); procedure SetFileName(const aFileName : string); override; procedure SetStoreOptions( Value : TAbStoreOptions ); protected {properties} property CompressionType : TAbCabCompressionType read FCompressionType write SetCompressionType; property FolderThreshold : Longint read FFolderThreshold write SetFolderThreshold; property StoreOptions : TAbStoreOptions read FStoreOptions write SetStoreOptions default AbDefStoreOptions; protected {events} property OnSave : TAbArchiveEvent read FOnSave write FOnSave; public {methods} constructor Create( AOwner : TComponent ); override; procedure AddFiles(const FileMask : string; SearchAttr : Integer ); procedure AddFilesEx(const FileMask : string; const ExclusionMask : string; SearchAttr : Integer ); procedure StartNewFolder; procedure StartNewCabinet; end; type {$IFDEF HasPlatformsAttribute} [ComponentPlatformsAttribute(pidWin32 or pidWin64)] {$ENDIF} TAbMakeCab = class(TAbCustomMakeCab) published property ArchiveProgressMeter; property BaseDirectory; property CabSize; property CompressionType; property FolderThreshold; property ItemProgressMeter; property StoreOptions; property OnArchiveProgress; property OnArchiveItemProgress; property OnChange; property OnConfirmProcessItem; property OnLoad; property OnProcessItemFailure; property OnRequestImage; property OnSave; property SetID; property SpanningThreshold; property TempDirectory; property Version; property FileName; {must be after OnLoad} end; {.Z+} implementation uses SysUtils, AbExcept, AbUtils; { TAbCustomMakeCab ========================================================= } constructor TAbCustomMakeCab.Create( AOwner : TComponent ); begin inherited Create( AOwner ); FCompressionType := AbDefCompressionType; FSpanningThreshold := AbDefCabSpanningThreshold; FFolderThreshold := AbDefFolderThreshold; FSetID := 0; FStoreOptions := AbDefStoreOptions; end; { -------------------------------------------------------------------------- } procedure TAbCustomMakeCab.AddFiles(const FileMask : string; SearchAttr : Integer ); {Add files to the cabinet where the disk filespec matches} begin if Assigned(CabArchive) then CabArchive.AddFiles(FileMask, SearchAttr) else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomMakeCab.AddFilesEx(const FileMask : string; const ExclusionMask : string; SearchAttr : Integer); {Add files that match Filemask except those matching ExclusionMask} begin if Assigned(CabArchive) then CabArchive.AddFilesEx(FileMask, ExclusionMask, SearchAttr) else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomMakeCab.DoSave(Sender : TObject); begin if Assigned(FOnSave) then FOnSave(Self); end; { -------------------------------------------------------------------------- } procedure TAbCustomMakeCab.InitArchive; begin inherited InitArchive; if Assigned(CabArchive) then begin {properties} CabArchive.FolderThreshold := FFolderThreshold; CabArchive.CompressionType := FCompressionType; CabArchive.SetID := FSetID; CabArchive.StoreOptions := FStoreOptions; {events} CabArchive.OnSave := DoSave; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomMakeCab.SetCompressionType(Value : TAbCabCompressionType); {Set the type of compression to use} begin FCompressionType := Value; if Assigned(CabArchive) then CabArchive.CompressionType := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomMakeCab.SetFileName(const aFileName : string); {Create the specified cabinet file} begin FFilename := aFileName; if csDesigning in ComponentState then Exit; if Assigned(FArchive) then begin FArchive.Free; FArchive := nil; end; if (aFileName <> '') then begin FArchive := TAbCabArchive.Create(aFileName, fmOpenWrite); InitArchive; FArchive.Load; FArchiveType := atCab; end; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomMakeCab.SetFolderThreshold(Value : Longint); {Set folder compression boundary} begin FFolderThreshold := Value; if Assigned(CabArchive) then CabArchive.FolderThreshold := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomMakeCab.SetStoreOptions(Value : TAbStoreOptions); begin FStoreOptions := Value; if Assigned(CabArchive) then CabArchive.StoreOptions := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomMakeCab.StartNewCabinet; {Flush current cabinet and start a new one} begin if Assigned(CabArchive) then CabArchive.NewCabinet else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomMakeCab.StartNewFolder; {Flush current folder and start a new one} begin if Assigned(CabArchive) then CabArchive.NewFolder else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } end. ================================================ FILE: lib/abbrevia/source/AbCabTyp.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Craig Peterson * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbCabTyp.pas *} {*********************************************************} {* ABBREVIA: Cabinet Archive *} {* Based on info from the FCI/FDI Library Description, *} {* included in the Microsoft Cabinet SDK *} {*********************************************************} unit AbCabTyp; {$I AbDefine.inc} interface uses Windows, Classes, AbFciFdi, AbArcTyp, AbUtils; type TAbCabItem = class(TAbArchiveItem) protected {private} FPartialFile : Boolean; FRawFileName : AnsiString; public property PartialFile : Boolean read FPartialFile write FPartialFile; property RawFileName : AnsiString read FRawFileName write FRawFileName; end; type TAbCabCompressionType = (ctNone, ctMSZIP, ctLZX); TAbCabinetMode = (cmRead, cmWrite); TAbCabStatus = (csFile, csFolder, csCabinet); const faExtractAndExecute = $040; faUTF8Name = $080; AbDefCabSpanningThreshold = 0; AbDefFolderThreshold = 0; AbDefCompressionType = ctMSZIP; AbDefReserveHeaderSize = 0; AbDefReserveFolderSize = 0; AbDefReserveDataSize = 0; AbDefLZXWindowSize = 18; CompressionTypeMap : array[TAbCabCompressionType] of Word = (0, 1, 4611); type TAbCabArchive = class(TAbArchive) protected {private} {internal variables} FCabName : AnsiString; FCabPath : AnsiString; FFCICabInfo : FCICabInfo; FFCIContext : HFCI; FFDIContext : HFDI; FFDICabInfo : FDICabInfo; FErrors : CabErrorRecord; FItemInProgress : TAbCabItem; FItemStream : TStream; FIIPName : string; FItemProgress : DWord; FNextCabinet : string; FNextDisk : string; FTempFileID : Integer; {property variables} FCurrentCab : Word; FCabSize : Longint; FCompressionType : TAbCabCompressionType; FFileCount : Word; FFolderThreshold : LongWord; FFolderCount : Word; FHasPrev : Boolean; FHasNext : Boolean; FSetID : Word; {internal methods} procedure CloseCabFile; procedure CreateCabFile; function CreateItem( const FileSpec : string ): TAbArchiveItem; override; procedure DoCabItemProgress(BytesCompressed : DWord; var Abort : Boolean); procedure DoGetNextCabinet(CabIndex : Integer; var CabName : string; var Abort : Boolean); procedure ExtractItemAt(Index : Integer; const NewName : string); override; procedure ExtractItemToStreamAt(Index : Integer; OutStream : TStream); override; function GetItem(ItemIndex : Integer) : TAbCabItem; procedure LoadArchive; override; procedure OpenCabFile; procedure PutItem( Index : Integer; Value : TAbCabItem ); procedure SaveArchive; override; procedure SetFolderThreshold(Value : LongWord); procedure SetSetID(Value : Word); procedure SetSpanningThreshold(Value : Int64); override; procedure TestItemAt(Index : Integer); override; public {methods} constructor Create(const FileName : string; Mode : Word); override; constructor CreateFromStream(aStream : TStream; const aArchiveName : string); override; destructor Destroy; override; procedure Add(aItem : TAbArchiveItem); override; procedure NewCabinet; procedure NewFolder; public {properties} property CurrentCab : Word read FCurrentCab; property CabSize : Longint read FCabSize; property CompressionType : TAbCabCompressionType read FCompressionType write FCompressionType; property FolderThreshold : LongWord read FFolderThreshold write SetFolderThreshold; property FolderCount : Word read FFolderCount; property HasPrev : Boolean read FHasPrev; property HasNext : Boolean read FHasNext; property Items[Index : Integer] : TAbCabItem read GetItem write PutItem; default; property ItemProgress : DWord read FItemProgress write FItemProgress; property SetID : Word read FSetID write SetSetID; end; function VerifyCab(const Fn : string) : TAbArchiveType; overload; function VerifyCab(Strm : TStream) : TAbArchiveType; overload; implementation uses SysUtils, {$IFDEF HasAnsiStrings} System.AnsiStrings, {$ENDIF} AbCharset, AbConst, AbExcept; {$WARN UNIT_PLATFORM OFF} {$WARN SYMBOL_PLATFORM OFF} type PWord = ^Word; PInteger = ^Integer; { == FDI/FCI Callback Functions - cdecl calling convention ================= } function FXI_GetMem(uBytes : Integer) : Pointer; cdecl; {allocate memory} begin Result := nil; if (uBytes > 0) then GetMem(Result, uBytes); end; { -------------------------------------------------------------------------- } procedure FXI_FreeMem(lpBuffer : Pointer); cdecl; {free memory} begin FreeMem(lpBuffer); end; { == FCI Callback Functions - cdecl calling convention ===================== } function FCI_FileOpen(lpPathName: PAnsiChar; Flag, Mode: Integer; PError: PInteger; Archive: TAbCabArchive) : PtrInt; cdecl; {open a file} begin Result := _lcreat(lpPathName, 0); if (Result = -1) then raise EAbFCIFileOpenError.Create; end; { -------------------------------------------------------------------------- } function FCI_FileRead(hFile: PtrInt; lpBuffer: Pointer; uBytes: UINT; PError: PInteger; Archive: TAbCabArchive) : UINT; cdecl; {read from a file} begin Result := _lread(hFile, lpBuffer, uBytes); if (Result = UINT(-1)) then raise EAbFCIFileReadError.Create; end; { -------------------------------------------------------------------------- } function FCI_FileWrite(hFile: PtrInt; lpBuffer: Pointer; uBytes: UINT; PError: PInteger; Archive: TAbCabArchive) : UINT; cdecl; {write to a file} begin Result := _lwrite(hFile, lpBuffer, uBytes); if (Result = UINT(-1)) then raise EAbFCIFileWriteError.Create; end; { -------------------------------------------------------------------------- } function FCI_FileClose(hFile: PtrInt; PError: PInteger; Archive: TAbCabArchive) : Integer; cdecl; {close a file} begin Result := _lclose(hFile); if (Result = -1) then raise EAbFCIFileCloseError.Create; end; { -------------------------------------------------------------------------- } function FCI_FileSeek(hFile: PtrInt; Offset: Longint; Origin: Integer; PError: PInteger; Archive: TAbCabArchive) : Longint; cdecl; {reposition file pointer} begin Result := _llseek(hFile, Offset, Origin); if (Result = -1) then raise EAbFCIFileSeekError.Create; end; { -------------------------------------------------------------------------- } function FCI_FileDelete(lpFilename: PAnsiChar; PError: PInteger; Archive: TAbCabArchive) : Boolean; cdecl; {delete a file} begin Result := SysUtils.DeleteFile(string(lpFilename)); if not Result then raise EAbFCIFileDeleteError.Create; end; { -------------------------------------------------------------------------- } function FCI_GetNextCab(lpCCab: PFCICabInfo; PrevCab: Longint; Archive: TAbCabArchive) : Boolean; cdecl; {get next cabinet filename} var CabName : string; Abort : Boolean; begin Abort := False; with lpCCab^ do begin CabName := string(szCab); {obtain next cabinet. Make index zero-based} Archive.DoGetNextCabinet(Pred(iCab), CabName, Abort); if not Abort then AbStrPLCopy(szCab, AnsiString(CabName), Length(szCab)); end; Result := not Abort; end; { -------------------------------------------------------------------------- } function FCI_FileDest(PCCab: PFCICabInfo; PFilename: PAnsiChar; cbFile: Longint; Continuation: Boolean; Archive: TAbCabArchive) : Integer; cdecl; {currently not used} begin Result := 0; end; { -------------------------------------------------------------------------- } function FCI_GetOpenInfo(lpPathname: Pointer; PDate, PTime, PAttribs : PWord; PError: PInteger; Archive: TAbCabArchive) : PtrInt; cdecl; {open a file and return date/attributes} var AttrEx: TAbAttrExRec; I, DT: Integer; RawName: RawByteString; begin Result := FileOpen(string(lpPathname), fmOpenRead or fmShareDenyNone); if (Result = -1) then raise EAbFCIFileOpenError.Create; if not AbFileGetAttrEx(string(lpPathname), AttrEx) then raise EAbFileNotFound.Create; PAttribs^ := AttrEx.Attr; DT := DateTimeToFileDate(AttrEx.Time); PDate^ := DT shr 16; PTime^ := DT and $0FFFF; Archive.ItemProgress := 0; Archive.FItemInProgress.UncompressedSize := AttrEx.Size; RawName := Archive.FItemInProgress.RawFileName; for I := 1 to Length(RawName) do if Ord(RawName[I]) > 127 then PAttribs^ := PAttribs^ or faUTF8Name; end; { -------------------------------------------------------------------------- } function FCI_Status(Status: Word; cb1, cb2: DWord; Archive: TAbCabArchive) : Longint; cdecl; {keep archive informed} var Abort : Boolean; begin Result := 0; if (Status = Word(csCabinet)) then begin Archive.DoSave; Archive.FCabSize := cb2; Result := cb2; end else if (Status = Word(csFolder)) then Archive.FCabSize := Archive.FCabSize + Longint(cb2) else if (Status = Word(csFile)) then begin Archive.DoCabItemProgress(cb2, Abort); Result := Longint(Abort); end; end; { -------------------------------------------------------------------------- } function FCI_GetTempFile(lpTempName: PAnsiChar; TempNameSize: Integer; Archive: TAbCabArchive) : PtrInt; cdecl; {obtain temporary filename} var TempPath : array[0..255] of AnsiChar; begin Archive.FTempFileID := Archive.FTempFileID + 1; if (Archive.TempDirectory <> '') then AbStrPLCopy(TempPath, AnsiString(Archive.TempDirectory), Length(TempPath)) else GetTempPathA(255, TempPath); GetTempFileNameA(TempPath, 'VMS', Archive.FTempFileID, lpTempName); Result := 1; end; { == FDI Callback Functions - cdecl calling convention ===================== } function FDI_FileOpen(lpPathName: PAnsiChar; Flag, Mode: Integer) : PtrInt; cdecl; {open a file} begin try Result := PtrInt(TFileStream.Create(string(lpPathName), fmOpenRead or fmShareDenyWrite)); except on EFOpenError do Result := -1; end; end; { -------------------------------------------------------------------------- } function FDI_FileRead(hFile: PtrInt; lpBuffer: Pointer; uBytes: UINT) : UINT; cdecl; {read from a file} begin Result := TStream(hFile).Read(lpBuffer^, uBytes); end; { -------------------------------------------------------------------------- } function FDI_FileWrite(hFile: PtrInt; lpBuffer: Pointer; uBytes: UINT) : UINT; cdecl; {write to a file} begin Result := TStream(hFile).Write(lpBuffer^, uBytes); end; { -------------------------------------------------------------------------- } function FDI_FileClose(hFile : PtrInt) : Longint; cdecl; {close a file} begin try TStream(hFile).Free; Result := 0; except Result := -1; end; end; { -------------------------------------------------------------------------- } function FDI_FileSeek(hFile : PtrInt; Offset : Longint; Origin : Integer) : Longint; cdecl; {reposition file pointer} begin Result := TStream(hFile).Seek(Offset, Origin); end; { -------------------------------------------------------------------------- } function FDI_EnumerateFiles(fdint : FDINOTIFICATIONTYPE; pfdin : PFDINotification) : PtrInt; cdecl; {Enumerate the files and build the archive file list} var Item : TAbCabItem; Archive : TAbCabArchive; begin Result := 0; Archive := pfdin^.pv; with Archive do case fdint of FDINT_Cabinet_Info : begin FSetID := pfdin^.setID; FCurrentCab := pfdin^.iCabinet; FNextCabinet := string(pfdin^.psz1); FNextDisk := string(pfdin^.psz2); Result := 0; end; FDINT_Copy_File, FDINT_Partial_File : begin Item := TAbCabItem.Create; with Item do begin RawFileName := AnsiString(pfdin^.psz1); if (pfdin^.attribs and faUTF8Name) = faUTF8Name then Filename := UTF8ToString(RawFileName) else Filename := string(RawFileName); UnCompressedSize := pfdin^.cb; LastModFileDate := pfdin^.date; LastModFileTime := pfdin^.time; ExternalFileAttributes := pfdin^.attribs; IsEncrypted := False; {encryption not implemented at this time} PartialFile := (fdint = FDINT_Partial_File); end; FItemList.Add(Item); Result := 0; end; end; end; { -------------------------------------------------------------------------- } function FDI_ExtractFiles(fdint : FDINOTIFICATIONTYPE; pfdin : PFDINotification) : PtrInt; cdecl; {extract file from cabinet} var Archive : TAbCabArchive; begin Result := 0; Archive := pfdin^.pv; case fdint of FDINT_Copy_File : begin if (AnsiString(pfdin^.psz1) = Archive.FItemInProgress.RawFileName) then if Archive.FIIPName <> '' then Result := Integer(TFileStream.Create(Archive.FIIPName, fmCreate)) else Result := Integer(Archive.FItemStream) else Result := 0; end; FDINT_Next_Cabinet : begin if pfdin^.fdie = FDIError_None then Result := 0 else Result := -1; end; FDINT_Close_File_Info : begin if Archive.FIIPName <> '' then begin FileSetDate(TFileStream(pfdin^.hf).Handle, Longint(pfdin^.date) shl 16 + pfdin^.time); TFileStream(pfdin^.hf).Free; FileSetAttr(Archive.FIIPName, pfdin^.attribs); end; Result := 1; end; end; end; { == TAbCabArchive ========================================================= } function VerifyCab(const Fn : string) : TAbArchiveType; var Stream : TFileStream; begin Stream := TFileStream.Create(FN, fmOpenRead or fmShareDenyNone); try Result := VerifyCab(Stream); finally Stream.Free; end; end; { -------------------------------------------------------------------------- } function VerifyCab(Strm : TStream) : TAbArchiveType; overload; var Context : HFDI; Info : FDICabInfo; Errors : CabErrorRecord; StartPos : int64; begin Result := atUnknown; Context := FDICreate(@FXI_GetMem, @FXI_FreeMem, @FDI_FileOpen, @FDI_FileRead, @FDI_FileWrite, @FDI_FileClose, @FDI_FileSeek, cpuDefault, @Errors); if Context = nil then Exit; try StartPos := Strm.Position; if FDIIsCabinet(Context, Integer(Strm), @Info) then Result := atCab; Strm.Position := StartPos; finally FDIDestroy(Context); end; end; { == TAbCabArchive ========================================================= } constructor TAbCabArchive.Create(const FileName : string; Mode : Word ); begin {Mode is used to identify which interface to use: } { fmOpenWrite - FCI, fmOpenRead - FDI} inherited CreateInit; if (Mode and fmCreate) = fmCreate then FMode := fmOpenWrite else FMode := Mode and fmOpenWrite; FArchiveName := FileName; FCabName := AnsiString(ExtractFileName(FileName)); FCabPath := AnsiString(ExtractFilePath(FileName)); SpanningThreshold := AbDefCabSpanningThreshold; FFolderThreshold := AbDefFolderThreshold; FItemInProgress := nil; FItemProgress := 0; end; { -------------------------------------------------------------------------- } constructor TAbCabArchive.CreateFromStream(aStream : TStream; const aArchiveName : string); begin raise EAbCabException.Create('TAbCabArchive does not support CreateFromStream'); end; { -------------------------------------------------------------------------- } destructor TAbCabArchive.Destroy; begin CloseCabFile; inherited Destroy; end; { -------------------------------------------------------------------------- } procedure TAbCabArchive.Add(aItem : TAbArchiveItem); {add a file to the cabinet} var Confirm, ItemAdded : Boolean; Item : TAbCabItem; begin ItemAdded := False; try CheckValid; if (FMode <> fmOpenWrite) then begin DoProcessItemFailure(aItem, ptAdd, ecCabError, 0); Exit; end; if FItemList.IsActiveDupe(aItem.FileName) then begin DoProcessItemFailure(aItem, ptAdd, ecAbbrevia, AbDuplicateName); Exit; end; DoConfirmProcessItem(aItem, ptAdd, Confirm); if not Confirm then Exit; Item := TAbCabItem(aItem); FItemInProgress := Item; Item.Action := aaAdd; Item.RawFileName := UTF8Encode(Item.FileName); if not FCIAddFile(FFCIContext, Pointer(Item.DiskFileName), PAnsiChar(Item.RawFileName), False, @FCI_GetNextCab, @FCI_Status, @FCI_GetOpenInfo, CompressionTypeMap[FCompressionType]) then raise EAbFCIAddFileError.Create; FItemList.Add(Item); ItemAdded := True; FIsDirty := True; finally if not ItemAdded then aItem.Free; end; end; { -------------------------------------------------------------------------- } procedure TAbCabArchive.CloseCabFile; {Make sure the Cabinet DLL is shut down} var Abort : Boolean; begin if (FFDIContext <> nil) then begin FDIDestroy(FFDIContext); FFDIContext := nil; end; if (FFCIContext <> nil) then begin FCIFlushCabinet(FFCIContext, False, @FCI_GetNextCab, @FCI_Status); FCIDestroy(FFCIContext); FFCIContext := nil; end; DoArchiveProgress(0, Abort); end; { -------------------------------------------------------------------------- } procedure TAbCabArchive.CreateCabFile; {create a new cabinet} begin {set cabinet parameters} with FFCICabInfo do begin if (SpanningThreshold > 0) then cb := SpanningThreshold else cb := AbDefCabSpanningThreshold; if (FolderThreshold > 0) then cbFolderThresh := FolderThreshold else cbFolderThresh := AbDefFolderThreshold; cbReserveCFHeader := AbDefReserveHeaderSize; cbReserveCFFolder := AbDefReserveFolderSize; cbReserveCFData := AbDefReserveDataSize; iCab := 1; iDisk := 0; fFailOnIncompressible := 0; setID := SetID; AbStrPCopy(szDisk, ''); AbStrPLCopy(szCab, FCabName, Length(szCab)); AbStrPLCopy(szCabPath, FCabPath, Length(szCabPath)); end; {obtain an FCI context} FFCIContext := FCICreate(@FErrors, @FCI_FileDest, @FXI_GetMem, @FXI_FreeMem, @FCI_FileOpen, @FCI_FileRead, @FCI_FileWrite, @FCI_FileClose, @FCI_FileSeek, @FCI_FileDelete, @FCI_GetTempFile, @FFCICabInfo, Self); if (FFCIContext = nil) then if FErrors.ErrorPresent then begin CloseCabFile; raise EAbFCICreateError.Create; end; end; { -------------------------------------------------------------------------- } function TAbCabArchive.CreateItem( const FileSpec : string ): TAbArchiveItem; {create a new item for the file list} begin Result := TAbCabItem.Create; with TAbCabItem(Result) do begin CompressedSize := 0; DiskFileName := ExpandFileName(FileSpec); FileName := FixName(FileSpec); end; end; { -------------------------------------------------------------------------- } procedure TAbCabArchive.DoCabItemProgress(BytesCompressed : DWord; var Abort : Boolean); {fire OnCabItemProgress event} var Progress : Byte; begin Abort := False; if Assigned(FOnArchiveItemProgress) then begin Inc(FItemProgress, BytesCompressed); Progress := AbPercentage(FItemProgress, FItemInProgress.UnCompressedSize); FOnArchiveItemProgress(Self, FItemInProgress, Progress, Abort); end; end; { -------------------------------------------------------------------------- } procedure TAbCabArchive.DoGetNextCabinet(CabIndex : Integer; var CabName : string; var Abort : Boolean); {fire OnRequestImage event} begin Abort := False; if Assigned(FOnRequestImage) then FOnRequestImage(Self, CabIndex, CabName, Abort) else AbIncFilename(CabName, CabIndex); end; {----------------------------------------------------------------------------} procedure TAbCabArchive.ExtractItemAt(Index : Integer; const NewName : string); {extract a file from the cabinet} begin FItemInProgress := GetItem(Index); FIIPName := NewName; try if not FDICopy(FFDIContext, PAnsiChar(FCabName), PAnsiChar(FCabPath), 0, @FDI_ExtractFiles, nil, Self) then DoProcessItemFailure(FItemInProgress, ptExtract, ecCabError, FErrors.ErrorCode); finally FIIPName := ''; end; end; {----------------------------------------------------------------------------} procedure TAbCabArchive.ExtractItemToStreamAt(Index : Integer; OutStream : TStream); begin FItemInProgress := GetItem(Index); FItemStream := OutStream; try if not FDICopy(FFDIContext, PAnsiChar(FCabName), PAnsiChar(FCabPath), 0, @FDI_ExtractFiles, nil, Self) then DoProcessItemFailure(FItemInProgress, ptExtract, ecCabError, FErrors.ErrorCode); finally FItemStream := nil; end; end; {----------------------------------------------------------------------------} function TAbCabArchive.GetItem(ItemIndex : Integer) : TAbCabItem; {fetch an item from the file list} begin Result := TAbCabItem(FItemList.Items[ItemIndex]); end; {----------------------------------------------------------------------------} procedure TAbCabArchive.LoadArchive; {Open existing cabinet or create a new one} begin if (FMode = fmOpenRead) then begin FFDIContext := FDICreate(@FXI_GetMem, @FXI_FreeMem, @FDI_FileOpen, @FDI_FileRead, @FDI_FileWrite, @FDI_FileClose, @FDI_FileSeek, cpuDefault, @FErrors); if (FFDIContext = nil) then raise EAbFDICreateError.Create; OpenCabFile; end else CreateCabFile; end; {----------------------------------------------------------------------------} procedure TAbCabArchive.NewCabinet; {flush current cabinet and start a new one} begin if not FCIFlushCabinet(FFCIContext, True, @FCI_GetNextCab, @FCI_Status) then raise EAbFCIFlushCabinetError.Create; end; {----------------------------------------------------------------------------} procedure TAbCabArchive.NewFolder; {flush current folder and start a new one} begin if not FCIFlushFolder(FFCIContext, @FCI_GetNextCab, @FCI_Status) then raise EAbFCIFlushFolderError.Create; end; {----------------------------------------------------------------------------} procedure TAbCabArchive.OpenCabFile; {Open an existing cabinet} var Abort : Boolean; Stream : TFileStream; begin {verify that the archive can be opened and is a cabinet} Stream := TFileStream.Create(FArchiveName, fmOpenRead or fmShareDenyNone); try if not FDIIsCabinet(FFDIContext, PtrInt(Stream), @FFDICabInfo) then begin CloseCabFile; raise EAbInvalidCabFile.Create; end; finally Stream.Free; end; {store information about the cabinet} FCabSize := FFDICabInfo.cbCabinet; FFolderCount := FFDICabInfo.cFolders; FFileCount := FFDICabInfo.cFiles; FCurrentCab := FFDICabInfo.iCabinet; FHasPrev := FFDICabInfo.hasPrev; FHasNext := FFDICabInfo.hasNext; {Enumerate the files and build the file list} if not FDICopy(FFDIContext, PAnsiChar(FCabName), PAnsiChar(FCabPath), 0, @FDI_EnumerateFiles, nil, Self) then begin CloseCabFile; raise EAbFDICopyError.Create; end; DoArchiveProgress(100, Abort); end; { -------------------------------------------------------------------------- } procedure TAbCabArchive.PutItem( Index : Integer; Value : TAbCabItem ); {replace an existing item in the file list} begin FItemList.Items[Index] := Value; end; { -------------------------------------------------------------------------- } procedure TAbCabArchive.SaveArchive; begin { No-op; file is flushed in destructor } end; { -------------------------------------------------------------------------- } procedure TAbCabArchive.SetFolderThreshold(Value : LongWord); {set maximum compression boundary} begin if (Value > 0) then FFolderThreshold := Value else FFolderThreshold := AbDefFolderThreshold; FFCICabInfo.cbFolderThresh := FFolderThreshold; end; { -------------------------------------------------------------------------- } procedure TAbCabArchive.SetSetID(Value : Word); {set cabinet SetID} begin FSetID := Value; FFCICabInfo.SetID := Value; end; { -------------------------------------------------------------------------- } procedure TAbCabArchive.SetSpanningThreshold(Value : Int64); {set maximum cabinet size} begin if (Value > 0) then FSpanningThreshold := Value else FSpanningThreshold := AbDefCabSpanningThreshold; FFCICabInfo.cb := FSpanningThreshold; end; { -------------------------------------------------------------------------- } procedure TAbCabArchive.TestItemAt(Index : Integer); begin {not implemented for cabinet archives} end; end. ================================================ FILE: lib/abbrevia/source/AbCharset.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * Craig Peterson * * Portions created by the Initial Developer are Copyright (C) 2011 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbCharset.pas *} {*********************************************************} {* ABBREVIA: Types and routines for working with various *} {* character encodings. *} {*********************************************************} unit AbCharset; {$I AbDefine.inc} interface {$IFDEF MSWINDOWS} uses Windows; {$ENDIF} { Unicode backwards compatibility types } {$IF NOT DECLARED(RawByteString)} type RawByteString = AnsiString; {$IFEND} {$IF NOT DECLARED(UnicodeString)} type UnicodeString = WideString; {$IFEND} type TAbCharSet = (csASCII, csANSI, csUTF8); function AbDetectCharSet(const aValue: RawByteString): TAbCharSet; function AbIsOEM(const aValue: RawByteString): Boolean; function AbRawBytesToString(const aValue: RawByteString): string; function AbStringToUnixBytes(const aValue: string): RawByteString; function AbSysCharSetIsUTF8: Boolean; {$IFDEF MSWINDOWS} function AbTryEncode(const aValue: UnicodeString; aCodePage: UINT; aAllowBestFit: Boolean; out aResult: AnsiString): Boolean; {$ENDIF} { Unicode backwards compatibility functions } {$IFNDEF UNICODE} function UTF8ToString(const S: RawByteString): string; {$ENDIF} implementation uses {$IFDEF LibcAPI} Libc, {$ENDIF} SysUtils; function AbDetectCharSet(const aValue: RawByteString): TAbCharSet; var i, TrailCnt: Integer; begin Result := csASCII; TrailCnt := 0; for i := 1 to Length(aValue) do begin if Byte(aValue[i]) >= $80 then Result := csANSI; if TrailCnt > 0 then if Byte(aValue[i]) in [$80..$BF] then Dec(TrailCnt) else Exit else if Byte(aValue[i]) in [$80..$BF] then Exit else case Byte(aValue[i]) of $C0..$C1, $F5..$FF: Exit; $C2..$DF: TrailCnt := 1; $E0..$EF: TrailCnt := 2; $F0..$F4: TrailCnt := 3; end; end; if (TrailCnt = 0) and (Result = csANSI) then Result := csUTF8; end; { -------------------------------------------------------------------------- } function AbIsOEM(const aValue: RawByteString): Boolean; // Detect whether a string of bytes is likely to be the system's ANSI or OEM codepage {$IFDEF MSWINDOWS} const // Byte values of alpha-numeric characters in OEM and ANSI codepages. // Excludes NBSP, ordinal indicators, exponents, the florin symbol, and, for // ANSI codepages matched to certain OEM ones, the micro character. // // US (OEM 437, ANSI 1252) Oem437AnsiChars = [138, 140, 142, 154, 156, 158, 159, 181, 192..214, 216..246, 248..255]; Oem437OemChars = [128..154, 160..165, 224..235, 237, 238]; // Arabic (OEM 720, ANSI 1256) Oem720AnsiChars = [129, 138, 140..144, 152, 154, 156, 159, 170, 181, 192..214, 216..239, 244, 249, 251, 252, 255]; Oem720OemChars = [130, 131, 133, 135..140, 147, 149..155, 157..173, 224..239]; // Greek (OEM 737, ANSI 1253) Oem737AnsiChars = [162, 181, 184..186, 188, 190..209, 211..254]; Oem737OemChars = [128..175, 224..240, 244, 245]; // Baltic Rim (OEM 775, ANSI 1257) Oem775AnsiChars = [168, 170, 175, 184, 186, 191..214, 216..246, 248..254]; Oem775OemChars = [128..149, 151..155, 157, 160..165, 173, 181..184, 189, 190, 198, 199, 207..216, 224..238]; // Western European (OEM 850, ANSI 1252) Oem850AnsiChars = [138, 140, 142, 154, 156, 158, 159, 192..214, 216..246, 248..255]; Oem850OemChars = [128..155, 157, 160..165, 181..183, 198, 199, 208..216, 222, 224..237]; // Central & Eastern European (OEM 852, ANSI 1250) Oem852AnsiChars = [138, 140..143, 154, 156..159, 163, 165, 170, 175, 179, 185, 186, 188, 190..214, 216..246, 248..254]; Oem852OemChars = [128..157, 159..169, 171..173, 181..184, 189, 190, 198, 199, 208..216, 221, 222, 224..238, 251..253]; // Cyrillic (OEM 855, ANSI 1251) Oem855AnsiChars = [128, 129, 131, 138, 140..144, 154, 156..159, 161..163, 165, 168, 170, 175, 178..180, 184, 186, 188..255]; Oem855OemChars = [128..173, 181..184, 189, 190, 198, 199, 208..216, 221, 222, 224..238, 241..252]; // Turkish (OEM 857, ANSI 1254) Oem857AnsiChars = [138, 140, 154, 156, 159, 192..214, 216..246, 248..255]; Oem857OemChars = [128..155, 157..167, 181..183, 198, 199, 210..212, 214..216, 222, 224..230, 233..237]; // Hebrew (OEM 862, ANSI 1255) Oem862AnsiChars = [181, 212..214, 224..250]; Oem862OemChars = [128..154, 160..165, 224..235, 237, 238]; // Cyrillic CIS (OEM 866, ANSI 1251) Oem866AnsiChars = [128, 129, 131, 138, 140..144, 154, 156..159, 161..163, 165, 168, 170, 175, 178..181, 184, 186, 188..255]; Oem866OemChars = [128..175, 224..247]; var AnsiChars, OemChars: set of Byte; IsANSI: Boolean; i: Integer; begin case GetOEMCP of 437: begin AnsiChars := Oem437AnsiChars; OemChars := Oem437OemChars; end; 720: begin AnsiChars := Oem720AnsiChars; OemChars := Oem720OemChars; end; 737: begin AnsiChars := Oem737AnsiChars; OemChars := Oem737OemChars; end; 775: begin AnsiChars := Oem775AnsiChars; OemChars := Oem775OemChars; end; 850: begin AnsiChars := Oem850AnsiChars; OemChars := Oem850OemChars; end; 852: begin AnsiChars := Oem852AnsiChars; OemChars := Oem852OemChars; end; 855: begin AnsiChars := Oem855AnsiChars; OemChars := Oem855OemChars; end; 857: begin AnsiChars := Oem857AnsiChars; OemChars := Oem857OemChars; end; 862: begin AnsiChars := Oem862AnsiChars; OemChars := Oem862OemChars; end; 866: begin AnsiChars := Oem866AnsiChars; OemChars := Oem866OemChars; end; else begin Result := False; Exit; end; end; IsANSI := True; Result := True; for i := 0 to Length(aValue) do if Ord(aValue[i]) >= $80 then begin if IsANSI then IsANSI := Ord(aValue[i]) in AnsiChars; if Result then Result := Ord(aValue[i]) in OemChars; if not IsANSI and not Result then Break end; if IsANSI then Result := False; end; {$ELSE !MSWINDOWS} begin Result := False; end; {$ENDIF !MSWINDOWS} { -------------------------------------------------------------------------- } function AbSysCharSetIsUTF8: Boolean; begin {$IFDEF DARWIN} Result := True; {$ENDIF} {$IFDEF MSWINDOWS} Result := False; {$ENDIF} {$IFDEF LINUX} Result := StrComp(nl_langinfo(_NL_CTYPE_CODESET_NAME), 'UTF-8') = 0; {$ENDIF} end; { -------------------------------------------------------------------------- } function AbRawBytesToString(const aValue: RawByteString): string; // Detect encoding of raw bytes and convert to a string begin case AbDetectCharSet(aValue) of csASCII: Result := string(aValue); csANSI: begin {$IFDEF MSWINDOWS} if AbIsOEM(aValue) then begin SetLength(Result, Length(aValue)); OemToCharBuff(PAnsiChar(aValue), PChar(Result), Length(Result)); end else {$ENDIF} Result := string(aValue); end; csUTF8: Result := UTF8ToString(aValue); end; end; { -------------------------------------------------------------------------- } function AbStringToUnixBytes(const aValue: string): RawByteString; // Convert from a string to an appropriate encoding for Unix archive types (tar/gz) // Based on testing the system encoding should be used on Linux, and UTF-8 // everywhere else. Windows apps don't agree on whether to use ANSI, OEM, or UTF-8. begin // Delphi XE2+ Posix platforms only support the UTF-8 locale {$IF DEFINED(LINUX) AND (DEFINED(FPC) OR DEFINED(KYLIX))} Result := AnsiString(aValue); {$ELSE} Result := UTF8Encode(aValue); {$IFEND} end; { -------------------------------------------------------------------------- } {$IFDEF MSWINDOWS} function AbTryEncode(const aValue: UnicodeString; aCodePage: UINT; aAllowBestFit: Boolean; out aResult: AnsiString): Boolean; // Try to encode the given Unicode string as the requested codepage const WC_NO_BEST_FIT_CHARS = $00000400; Flags: array[Boolean] of DWORD = (WC_NO_BEST_FIT_CHARS, 0); var UsedDefault: BOOL; begin if not aAllowBestFit and not CheckWin32Version(4, 1) then Result := False else begin SetLength(aResult, WideCharToMultiByte(aCodePage, Flags[aAllowBestFit], PWideChar(aValue), Length(aValue), nil, 0, nil, @UsedDefault)); SetLength(aResult, WideCharToMultiByte(aCodePage, Flags[aAllowBestFit], PWideChar(aValue), Length(aValue), PAnsiChar(aResult), Length(aResult), nil, @UsedDefault)); Result := not UsedDefault; end; end; {$ENDIF MSWINDOWS} { == Unicode backwards compatibility functions ============================= } {$IFNDEF UNICODE} function UTF8ToString(const S: RawByteString): string; begin Result := UTf8ToAnsi(S); end; {$ENDIF} end. ================================================ FILE: lib/abbrevia/source/AbComCtrls.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is Craig Peterson * * Portions created by the Initial Developer are Copyright (C) 2011 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Craig Peterson * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbComCtrls.pas *} {*********************************************************} {* ABBREVIA: Listview and treeview components that work *} {* with an archive component. The treeview can have a *} {* listview associated, in which case the listview will*} {* only show items in the selected folder. *} {*********************************************************} unit AbComCtrls; interface {$I AbDefine.inc} uses Windows, Messages, SysUtils, Classes, Controls, ComCtrls, Graphics, AbBrowse, AbArcTyp; const AbTreeArchiveImage = 0; AbTreeFolderImage = 1; AbTreeFolderExpandedImage = 2; type { ===== TAbListItem ========================================================= } TAbListItem = class(TListItem) protected {private} FArchiveItem : TAbArchiveItem; protected {methods} function GetIsDirectory : Boolean; function GetIsEncrypted : Boolean; public {properties} property ArchiveItem : TAbArchiveItem read FArchiveItem write FArchiveItem; property IsDirectory : Boolean read GetIsDirectory; property IsEncrypted : Boolean read GetIsEncrypted; end; { ===== TAbListItems ======================================================== } TAbListItems = class(TListItems) protected {methods} function GetItem(aIndex: Integer): TAbListItem; procedure SetItem(aIndex: Integer; aValue: TAbListItem); public {properties} property Item[Index: Integer]: TAbListItem read GetItem write SetItem; default; end; { ===== TAbCustomListView =================================================== } type TAbViewColumn = (vcName, vcFileType, vcLastModified, vcSize, vcRatio, vcPacked, vcCRC, vcAttributes, vcEncrypted, vcMethod, vcPath); TAbViewColumns = set of TAbViewColumn; const AbDefVisibleColumns = [Low(TAbViewColumn)..High(TAbViewColumn)]; type TAbCustomTreeView = class; {$IF NOT DECLARED(TWindowProcPtr)} TWindowProcPtr = Pointer; {$IFEND} TAbCustomListView = class(TCustomListView) protected {private} FArchive : TAbBaseBrowser; FDefHeaderProc : TWindowProcPtr; FFlatList: Boolean; FHeaderHandle : HWND; FHeaderImages : TImageList; FHeaderInstance : Pointer; FInUpdateSortArrows: Boolean; FPath : string; FSortAscending : Boolean; FSortColIndex : Integer; FSortColumn : TAbViewColumn; FSortUpBmp : HBITMAP; FSortDownBmp : HBITMAP; FTreeView : TAbCustomTreeView; FVisibleColumns : TAbViewColumns; protected {methods} procedure ColClick(aColumn: TListColumn); override; function CreateListItem: TListItem; override; function CreateListItems: TListItems; override; procedure CreateWnd; override; function CustomDrawSubItem(Item: TListItem; SubItem: Integer; State: TCustomDrawState; Stage: TCustomDrawStage): Boolean; override; procedure DblClick; override; procedure DoChange(Sender : TObject); virtual; function GetListItems: TAbListItems; function GetVersion: string; procedure HeaderWndProc(var Msg: TMessage); virtual; function IsCustomDrawn(Target: TCustomDrawTarget; Stage: TCustomDrawStage): Boolean; override; procedure Notification(aComponent : TComponent; aOperation : TOperation); override; procedure SetArchive(aValue : TAbBaseBrowser); procedure SetFlatList(aValue : Boolean); procedure SetPath(aValue : string); procedure SetTreeView(aValue : TAbCustomTreeView); procedure SetVisibleColumns(aValue : TAbViewColumns); procedure UpdateColumns; procedure UpdateSortArrow; procedure UpdateView; protected {properties} property HeaderImages : TImageList read FHeaderImages; public {methods} constructor Create(aOwner: TComponent); override; destructor Destroy; override; procedure Sort(aColumn: TAbViewColumn; aAscending: Boolean); public {properties} property Archive : TAbBaseBrowser read FArchive write SetArchive; property Columns; // Show only items in the current path property FlatList : Boolean read FFlatList write SetFlatList; property Items: TAbListItems read GetListItems stored False; property TreeView : TAbCustomTreeView read FTreeView write SetTreeView; property Path : string read FPath write SetPath; property Version : string read GetVersion stored False; property VisibleColumns : TAbViewColumns read FVisibleColumns write SetVisibleColumns default AbDefVisibleColumns; end; { ===== TAbListView ========================================================= } TAbListView = class(TAbCustomListView) published property Action; property Align; property AllocBy; property Anchors; property Archive; property BevelEdges; property BevelInner; property BevelOuter; property BevelKind default bkNone; property BevelWidth; property BiDiMode; property BorderStyle; property BorderWidth; property Checkboxes; property Color; property ColumnClick; property Constraints; property Ctl3D; property DoubleBuffered; property DragCursor; property DragKind; property DragMode; property Enabled; property Font; property FlatScrollBars; property FullDrag; property GridLines; {$IFDEF HasListViewGroups} property Groups; {$ENDIF} property HideSelection; property HotTrack; property HotTrackStyles; property HoverTime; property IconOptions; property Items; property LargeImages; property MultiSelect; {$IFDEF HasListViewGroups} property GroupHeaderImages; property GroupView default False; {$ENDIF} property ReadOnly default False; property RowSelect; property ParentBiDiMode; property ParentColor default False; {$IFDEF HasParentDoubleBuffered} property ParentDoubleBuffered; {$ENDIF} property ParentFont; property ParentShowHint; property Path; property PopupMenu; property ShowColumnHeaders; property ShowWorkAreas; property ShowHint; property TabOrder; property TabStop default True; property TreeView; property Version; property ViewStyle; property Visible; property VisibleColumns; property OnClick; property OnColumnClick; property OnColumnDragged; property OnColumnRightClick; property OnContextPopup; property OnDblClick; property OnEdited; property OnEditing; property OnEndDock; property OnEndDrag; property OnEnter; property OnExit; property OnDragDrop; property OnDragOver; property OnInfoTip; property OnKeyDown; property OnKeyPress; property OnKeyUp; {$IFDEF HasOnMouseActivate} property OnMouseActivate; {$ENDIF} property OnMouseDown; {$IFDEF HasOnMouseEnter} property OnMouseEnter; property OnMouseLeave; {$ENDIF} property OnMouseMove; property OnMouseUp; property OnResize; property OnSelectItem; {$IFDEF HasListViewOnItemChecked} property OnItemChecked; {$ENDIF} property OnStartDock; property OnStartDrag; end; { ===== TAbCustomTreeView =================================================== } TAbCustomTreeView = class(TTreeView) protected {private} FArchive: TAbBaseBrowser; FListView: TAbCustomListView; FPath: string; protected {methods} procedure Change(aNode: TTreeNode); override; procedure DoChange(Sender : TObject); virtual; procedure GetSelectedIndex(aNode: TTreeNode); override; function GetVersion: string; procedure Notification(aComponent : TComponent; aOperation : TOperation); override; procedure SelectPathNode; procedure SetArchive(aValue: TAbBaseBrowser); procedure SetListView(aValue: TAbCustomListView); procedure SetPath(const aValue: string); public {methods} constructor Create(aOwner: TComponent); override; public {properties} property Archive: TAbBaseBrowser read FArchive write SetArchive; property HideSelection default False; property ListView: TAbCustomListView read FListView write SetListView; property Path: string read FPath write SetPath; property Version: string read GetVersion stored False; end; { ===== TAbTreeView ========================================================= } TAbTreeView = class(TAbCustomTreeView) published property Align; property Anchors; property Archive; property AutoExpand; property BevelEdges; property BevelInner; property BevelOuter; property BevelKind default bkNone; property BevelWidth; property BiDiMode; property BorderStyle; property BorderWidth; property ChangeDelay; property Color; property Ctl3D; property Constraints; property DoubleBuffered; property DragKind; property DragCursor; property DragMode; property Enabled; property Font; property HideSelection; property HotTrack; property Indent; property Items; property ListView; property ParentBiDiMode; property ParentColor default False; property ParentCtl3D; {$IFDEF HasParentDoubleBuffered} property ParentDoubleBuffered; {$ENDIF} property ParentFont; property ParentShowHint; property Path; property PopupMenu; property ReadOnly; property RightClickSelect; property RowSelect; property ShowButtons; property ShowHint; property ShowLines; property ShowRoot; property TabOrder; property TabStop default True; property ToolTips; property Version; property Visible; property OnChanging; property OnClick; property OnCollapsed; property OnCollapsing; property OnContextPopup; property OnDblClick; property OnDeletion; property OnDragDrop; property OnDragOver; property OnEdited; property OnEditing; property OnEndDock; property OnEndDrag; property OnEnter; property OnExit; property OnExpanding; property OnExpanded; property OnKeyDown; property OnKeyPress; property OnKeyUp; {$IFDEF HasOnMouseActivate} property OnMouseActivate; {$ENDIF} property OnMouseDown; {$IFDEF HasOnMouseEnter} property OnMouseEnter; property OnMouseLeave; {$ENDIF} property OnMouseMove; property OnMouseUp; property OnStartDock; property OnStartDrag; end; { ===== TAbProgressBar ====================================================== } TAbProgressBar = class(TProgressBar, IAbProgressMeter) protected {private} function GetVersion : string; public {methods} procedure DoProgress(Progress : Byte); procedure Reset; published {properties} property Version: string read GetVersion stored False; end; implementation {$R AbComCtrls.res} uses CommCtrl, Contnrs, Forms, ShellAPI, StrUtils, AbConst, AbResString, AbUtils, AbZipTyp; const HDF_SORTDOWN = $0200; HDF_SORTUP = $0400; { -------------------------------------------------------------------------- } {$IF NOT DECLARED(StartsText)} function StartsText(const aSubText, aText: string): Boolean; begin Result := (Length(aText) > Length(aSubText)) and SameText(aSubText, Copy(aText, 1, Length(aSubText))); end; {$IFEND} { -------------------------------------------------------------------------- } function AbNormalizeFilename(const aFilename: string): string; var i: Integer; begin Result := aFilename; for i := 1 to Length(Result) do if IsDelimiter('\/', Result, i) then Result[i] := PathDelim; if IsDelimiter(PathDelim, Result, Length(Result)) then SetLength(Result, Length(Result) - 1); end; { -------------------------------------------------------------------------- } var ComCtl32MajorVer: Integer = -1; function IsComCtl32Version6: Boolean; type PDllVersionInfo = ^TDllVersionInfo; TDllVersionInfo = packed record cbSize: DWORD; dwMajorVersion: DWORD; dwMinorVersion: DWORD; dwBuildNumber: DWORD; dwPlatformId: DWORD; end; var DllGetVersion: function(pdvi: PDllVersionInfo): HRESULT; stdcall; dvi: TDllVersionInfo; hComCtl32: HMODULE; begin if ComCtl32MajorVer = -1 then begin ComCtl32MajorVer := 0; hComCtl32 := LoadLibrary(comctl32); if hComCtl32 <> 0 then begin DllGetVersion := GetProcAddress(hComCtl32, 'DllGetVersion'); if Assigned(DllGetVersion) then begin dvi.cbSize := SizeOf(dvi); if Succeeded(DllGetVersion(@dvi)) then ComCtl32MajorVer := dvi.dwMajorVersion; end; FreeLibrary(hComCtl32); end; end; Result := ComCtl32MajorVer >= 6; end; { -------------------------------------------------------------------------- } function SameEvent(const aEvent1, aEvent2: TNotifyEvent): Boolean; begin Result := (TMethod(aEvent1).Code = TMethod(aEvent2).Code) and (TMethod(aEvent1).Data = TMethod(aEvent2).Data); end; { ===== TAbListItem ========================================================= } function TAbListItem.GetIsDirectory: Boolean; begin Result := (ArchiveItem = nil) or ArchiveItem.IsDirectory; end; { -------------------------------------------------------------------------- } function TAbListItem.GetIsEncrypted: Boolean; begin Result := (ArchiveItem <> nil) and ArchiveItem.IsEncrypted; end; { ===== TAbListItems ======================================================== } function TAbListItems.GetItem(aIndex: Integer): TAbListItem; begin Result := inherited Item[aIndex] as TAbListItem; end; { -------------------------------------------------------------------------- } procedure TAbListItems.SetItem(aIndex: Integer; aValue: TAbListItem); begin inherited Item[aIndex] := aValue; end; { ===== TAbCustomListView =================================================== } constructor TAbCustomListView.Create(aOwner: TComponent); var Bmp : TBitmap; sfi: SHFILEINFO; begin inherited; FHeaderInstance := MakeObjectInstance(HeaderWndProc); // Load header image into an image list; the header's hbm property // doesn't support transparency FHeaderImages := TImageList.Create(Self); Bmp := TBitmap.Create; try Bmp.LoadFromResourceName(HInstance, 'AbComCtrls_Lock'); FHeaderImages.AddMasked(Bmp, clFuchsia); finally Bmp.Free; end; // Load system image lists LargeImages := TImageList.Create(Self); LargeImages.ShareImages := True; LargeImages.Handle := SHGetFileInfo('', 0, sfi, SizeOf(sfi), SHGFI_LARGEICON or SHGFI_SYSICONINDEX); SmallImages := TImageList.Create(Self); SmallImages.ShareImages := True; SmallImages.Handle := SHGetFileInfo('', 0, sfi, SizeOf(sfi), SHGFI_SMALLICON or SHGFI_SYSICONINDEX); // Load sort arrow bitmaps for older comctrl32.dll versions FSortAscending := True; FSortColumn := vcName; if not IsComCtl32Version6 then begin FSortUpBmp := LoadImage(HInstance, 'AbComCtrls_SortUp', IMAGE_BITMAP, 0, 0, LR_LOADMAP3DCOLORS); FSortDownBmp := LoadImage(HInstance, 'AbComCtrls_SortDown', IMAGE_BITMAP, 0, 0, LR_LOADMAP3DColors); end; // Set default column visibility VisibleColumns := AbDefVisibleColumns; end; { -------------------------------------------------------------------------- } destructor TAbCustomListView.Destroy; begin if FHeaderHandle <> 0 then SetWindowLong(FHeaderHandle, GWL_WNDPROC, LongInt(FDefHeaderProc)); FreeObjectInstance(FHeaderInstance); if FSortUpBmp <> 0 then DeleteObject(FSortUpBmp); if FSortDownBmp <> 0 then DeleteObject(FSortDownBmp); inherited; end; { -------------------------------------------------------------------------- } procedure TAbCustomListView.ColClick(aColumn: TListColumn); var Col: TAbViewColumn; begin inherited; Col := TAbViewColumn(aColumn.Tag); Sort(Col, (Col <> FSortColumn) or not FSortAscending); end; { -------------------------------------------------------------------------- } function TAbCustomListView.CreateListItem: TListItem; begin Result := TAbListItem.Create(Items); end; { -------------------------------------------------------------------------- } function TAbCustomListView.CreateListItems: TListItems; begin Result := TAbListItems.Create(Self); end; { -------------------------------------------------------------------------- } procedure TAbCustomListView.CreateWnd; begin inherited; FHeaderHandle := ListView_GetHeader(Handle); if FHeaderHandle <> 0 then begin FDefHeaderProc := TWindowProcPtr(GetWindowLong(FHeaderHandle, GWL_WNDPROC)); SetWindowLong(FHeaderHandle, GWL_WNDPROC, LongInt(FHeaderInstance)); end; Header_SetImageList(ListView_GetHeader(Handle), FHeaderImages.Handle); UpdateColumns; UpdateView; end; { -------------------------------------------------------------------------- } function TAbCustomListView.CustomDrawSubItem(Item: TListItem; SubItem: Integer; State: TCustomDrawState; Stage: TCustomDrawStage): Boolean; var i: Integer; R: TRect; begin Result := True; if (Stage = cdPrePaint) and TAbListItem(Item).IsEncrypted then if TAbViewColumn(Columns[SubItem].Tag) = vcEncrypted then begin Result := False; R := Item.DisplayRect(drBounds); Inc(R.Left, 6); for i := 0 to SubItem - 1 do Inc(R.Left, Columns[i].Width); HeaderImages.Draw(Canvas, R.Left, R.Top, 0); end else begin Result := True; // Fixed other columns drawing with wrong font after using TImageList.Draw Canvas.Brush.Color := ColorToRGB(Color); SetBkMode(Canvas.Handle, TRANSPARENT); end; end; { -------------------------------------------------------------------------- } procedure TAbCustomListView.DblClick; begin inherited; if TAbListItem(Selected).IsDirectory then if Path = '' then Path := Selected.Caption else Path := Path + PathDelim + Selected.Caption; end; { -------------------------------------------------------------------------- } procedure TAbCustomListView.DoChange(Sender: TObject); begin UpdateView; if (Sender = FArchive) and Assigned(FTreeView) then FTreeView.DoChange(Self); end; { -------------------------------------------------------------------------- } function TAbCustomListView.GetListItems: TAbListItems; begin Result := inherited Items as TAbListItems; end; { -------------------------------------------------------------------------- } function TAbCustomListView.GetVersion: string; begin Result := AbVersionS; end; { -------------------------------------------------------------------------- } procedure TAbCustomListView.HeaderWndProc(var Msg: TMessage); const FMT_MASK = HDF_BITMAP or HDF_BITMAP_ON_RIGHT or HDF_SORTDOWN or HDF_SORTUP; var Item: THDItem; begin if (Msg.Msg = HDM_SETITEM) and not FInUpdateSortArrows then begin Item.Mask := HDI_FORMAT; if Header_GetItem(FHeaderHandle, Msg.WParam, Item) then begin PHDItem(Msg.LParam).Mask := PHDItem(Msg.LParam).Mask and not HDI_BITMAP; PHDItem(Msg.LParam).fmt := PHDItem(Msg.LParam).fmt and not FMT_MASK or (Item.fmt and FMT_MASK); end; end; Msg.Result := CallWindowProc(FDefHeaderProc, FHeaderHandle, Msg.Msg, Msg.WParam, Msg.LParam); if Msg.Msg = WM_DESTROY then FHeaderHandle := 0; end; { -------------------------------------------------------------------------- } function TAbCustomListView.IsCustomDrawn(Target: TCustomDrawTarget; Stage: TCustomDrawStage): Boolean; begin Result := (vcEncrypted in VisibleColumns) and (Stage = cdPrePaint) and (Target = dtSubItem); end; { -------------------------------------------------------------------------- } procedure TAbCustomListView.Notification(aComponent: TComponent; aOperation: TOperation); begin inherited; if aOperation = opRemove then begin if aComponent = FArchive then begin FArchive := nil; Clear; end; if aComponent = FTreeView then begin if Assigned(FArchive) and SameEvent(FArchive.OnChange, FTreeView.DoChange) then FArchive.OnChange := DoChange; FTreeView := nil; end; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomListView.SetArchive(aValue: TAbBaseBrowser); begin if aValue <> FArchive then begin if Assigned(FArchive) then begin FArchive.RemoveFreeNotification(Self); if SameEvent(FArchive.OnChange, DoChange) then if Assigned(TreeView) and (TreeView.Archive = FArchive) then FArchive.OnChange := TreeView.DoChange else FArchive.OnChange := nil; end; FArchive := aValue; if Assigned(FArchive) then begin FArchive.FreeNotification(Self); FArchive.OnChange := DoChange; DoChange(Self); end else Items.Clear; if Assigned(TreeView) then TreeView.Archive := aValue; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomListView.SetFlatList(aValue : Boolean); begin if aValue <> FFlatList then begin FFlatList := aValue; UpdateView; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomListView.SetPath(aValue: string); begin if aValue <> FPath then begin FPath := ExcludeTrailingPathDelimiter(aValue); if Assigned(TreeView) then TreeView.Path := aValue; if not FlatList then UpdateView; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomListView.SetTreeView(aValue: TAbCustomTreeView); begin if aValue <> FTreeView then begin if Assigned(FTreeView) then begin FTreeView.RemoveFreeNotification(Self); FTreeView.ListView := nil; end; FTreeView := aValue; if Assigned(FTreeView) then begin FTreeView.FreeNotification(Self); if Assigned(FArchive) then FTreeView.Archive := FArchive else if Assigned(FTreeView.Archive) then Archive := FTreeView.Archive; FTreeView.ListView := Self; end; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomListView.SetVisibleColumns(aValue : TAbViewColumns); begin if aValue <> FVisibleColumns then begin FVisibleColumns := aValue; UpdateColumns; UpdateView; end; end; { -------------------------------------------------------------------------- } function TAbCustomListView_SortProc(aItem1, aItem2: TAbListItem; aListView: TAbCustomListView): Integer; stdcall; var Item1, Item2: TAbArchiveItem; Ratio1, Ratio2: Single; begin if aItem1.IsDirectory <> aItem2.IsDirectory then if aItem1.IsDirectory then Result := -1 else Result := 1 else begin Result := 0; if aListView.FSortColumn in [vcFileType, vcPath] then begin Result := CompareText(aItem1.SubItems[aListView.FSortColIndex], aItem2.SubItems[aListView.FSortColIndex]); end else if not aItem1.IsDirectory then begin // Don't do more advanced sorts for directories, since they may be // implicitly stored and won't have corresponding archive items Item1 := aItem1.ArchiveItem; Item2 := aItem2.ArchiveItem; case aListView.FSortColumn of vcLastModified: begin if Item1.LastModTimeAsDateTime < Item2.LastModTimeAsDateTime then Result := -1 else if Item1.LastModTimeAsDateTime > Item2.LastModTimeAsDateTime then Result := 1; end; vcSize: begin if Item1.UncompressedSize < Item2.UncompressedSize then Result := -1 else if Item1.UncompressedSize > Item2.UncompressedSize then Result := 1; end; vcRatio: begin if Item1.UncompressedSize > 0 then Ratio1 := Item1.CompressedSize / Item1.UncompressedSize else Ratio1 := 1; if Item2.UncompressedSize > 0 then Ratio2 := Item2.CompressedSize / Item2.UncompressedSize else Ratio2 := 1; if Ratio1 > Ratio2 then Result := -1 else if Ratio1 < Ratio2 then Result := 1 end; vcPacked: begin if Item1.CompressedSize < Item2.CompressedSize then Result := -1 else if Item1.CompressedSize > Item2.CompressedSize then Result := 1; end; vcCRC: begin if Longword(Item1.CRC32) < Longword(Item2.CRC32) then Result := -1 else if Longword(Item1.CRC32) > Longword(Item2.CRC32) then Result := 1; end; vcAttributes, vcMethod: begin Result := CompareText(aItem1.SubItems[aListView.FSortColIndex], aItem2.SubItems[aListView.FSortColIndex]); end; vcEncrypted: begin if not Item1.IsEncrypted and Item2.IsEncrypted then Result := -1 else if Item1.IsEncrypted and not Item2.IsEncrypted then Result := 1 end; end; end; if Result = 0 then Result := AnsiCompareText(aItem1.Caption, aItem2.Caption); end; if not aListView.FSortAscending then Result := -Result; end; { -------------------------------------------------------------------------- } procedure TAbCustomListView.Sort(aColumn: TAbViewColumn; aAscending: Boolean); begin if (aColumn <> FSortColumn) or (aAscending <> FSortAscending) then begin FSortColumn := aColumn; FSortAscending := aAscending; UpdateSortArrow; CustomSort(TLVCompare(@TAbCustomListView_SortProc), LPARAM(Self)); end; end; { -------------------------------------------------------------------------- } procedure TAbCustomListView.UpdateColumns; const ColWidths: array[TAbViewColumn] of Integer = ( 180{vcName}, 110{vcFileType}, 130{vcLastModified}, 80{vcSize}, 50{vcRatio}, 80{vcPacked}, 70{vcCRC}, 30{vcAttributes}, 28{vcEncrypted}, 60{vcMethod}, 300{vcPath}); var Col: TAbViewColumn; Column: TListColumn; begin if HandleAllocated then Items.BeginUpdate; Columns.BeginUpdate; try Columns.Clear; for Col := Low(Col) to High(Col) do begin if not (Col in FVisibleColumns) then Continue; Column := Columns.Add; case Col of vcName: Column.Caption := AbItemNameHeadingS; vcFileType: Column.Caption := AbFileTypeHeadingS; vcLastModified: Column.Caption := AbLastModifiedHeadingS; vcSize: Column.Caption := AbFileSizeHeadingS; vcRatio: Column.Caption := AbRatioHeadingS; vcPacked: Column.Caption := AbPackedHeadingS; vcCRC: Column.Caption := AbCRCHeadingS; vcAttributes: Column.Caption := AbFileAttrHeadingS; vcEncrypted: Column.ImageIndex := 0; vcMethod: Column.Caption := AbMethodHeadingS; vcPath: Column.Caption := AbPathHeadingS; end; Column.Width := ColWidths[Col]; Column.Tag := Ord(Col); if Col in [vcSize, vcRatio, vcPacked] then Column.Alignment := taRightJustify; end; finally Columns.EndUpdate; if HandleAllocated then Items.EndUpdate; end; UpdateSortArrow; end; { -------------------------------------------------------------------------- } procedure TAbCustomListView.UpdateSortArrow; var i: Integer; Item: THDITEM; begin if not HandleAllocated then Exit; FInUpdateSortArrows := True; try for i := 0 to Columns.Count - 1 do begin FillChar(Item, SizeOf(Item), 0); Item.Mask := HDI_FORMAT; if not IsComCtl32Version6 then Item.Mask := Item.Mask or HDI_BITMAP; Header_GetItem(FHeaderHandle, Columns[i].Index, Item); // Add sort arrow to requested column if TAbViewColumn(Columns[i].Tag) = FSortColumn then begin FSortColIndex := i - 1; if IsComCtl32Version6 then begin Item.fmt := Item.fmt and not (HDF_SORTDOWN or HDF_SORTUP); if FSortAscending then Item.fmt := Item.fmt or HDF_SORTUP else Item.fmt := Item.fmt or HDF_SORTDOWN; end else begin Item.fmt := Item.fmt or HDF_BITMAP or HDF_BITMAP_ON_RIGHT; if FSortAscending then Item.hbm := FSortUpBmp else Item.hbm := FSortDownBmp; end; end // Remove sort arrow from other columns else begin if IsComCtl32Version6 then Item.fmt := Item.fmt and not (HDF_SORTDOWN or HDF_SORTUP) else begin Item.Mask := Item.Mask and not HDI_BITMAP; Item.fmt := Item.fmt and not (HDF_BITMAP OR HDF_BITMAP_ON_RIGHT); end; end; Header_SetItem(FHeaderHandle, Columns[i].Index, Item); end; finally FInUpdateSortArrows := False; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomListView.UpdateView; var ArcItem: TAbArchiveItem; Col: TAbViewColumn; ColImage: Integer; ColText, Filename, FolderName: string; DOSAttr: Integer; Folders: TStringList; i, j: Integer; ListItem: TAbListItem; ParentDir: string; sfi: SHFILEINFO; begin ListItem := nil; // Suppress compiler warning if (Items.Count = 0) and (FArchive = nil) then Exit; Items.BeginUpdate; try Items.Clear; if Assigned(FArchive) then begin Folders := TStringList.Create; try for i := 0 to FArchive.Count - 1 do if FArchive[i].Action <> aaDelete then begin ArcItem := FArchive[i]; Filename := AbNormalizeFilename(ArcItem.FileName); // Exclude unwanted items if FlatList and ArcItem.IsDirectory then Continue; // Create new ListItem ParentDir := ExtractFileDir(FileName); if FlatList or (ParentDir = Path) then begin // If an ListItem has already been created for a folder, use it if ArcItem.IsDirectory then begin FolderName := ExtractFileName(FileName); if Folders.Find(FolderName, j) then ListItem := Folders.Objects[j] as TAbListItem else begin ListItem := Items.Add as TAbListItem; Folders.AddObject(FolderName, ListItem); end end else ListItem := Items.Add as TAbListItem; ListItem.ArchiveItem := FArchive[i]; end else if (Path = '') or StartsText(Path + PathDelim, ParentDir) then begin // Create folder for implicitly stored directories, // if one hasn't been created already while ParentDir <> Path do begin FileName := ParentDir; ParentDir := ExtractFileDir(FileName); end; FolderName := ExtractFileName(FileName); if Folders.IndexOf(FolderName) <> -1 then Continue; ListItem := Items.Add as TAbListItem; Folders.AddObject(FolderName, ListItem); ArcItem := nil; end else // ListItem isn't below Path Continue; // Get file type information from the shell if ListItem.IsDirectory then DOSAttr := FILE_ATTRIBUTE_DIRECTORY else DOSAttr := FILE_ATTRIBUTE_NORMAL; SHGetFileInfo(PChar(ExtractFileName(Filename)), DOSAttr, sfi, sizeof(sfi), SHGFI_TYPENAME or SHGFI_SYSICONINDEX or SHGFI_USEFILEATTRIBUTES); // Fill in columns ListItem.Caption := ExtractFileName(Filename); ListItem.ImageIndex := sfi.iIcon; ListItem.SubItems.Clear; for Col := Succ(Low(Col)) to High(Col) do if Col in FVisibleColumns then begin ColText := ''; ColImage := -1; case Col of vcFileType: ColText := sfi.szTypeName; vcLastModified: if ArcItem <> nil then ColText := DateToStr(ArcItem.LastModTimeAsDateTime) + ' ' + TimeToStr(ArcItem.LastModTimeAsDateTime); vcSize: if not ListItem.IsDirectory then ColText := FormatFloat('#,##0', ArcItem.UncompressedSize); vcRatio: if not ListItem.IsDirectory then if ArcItem.UncompressedSize > 0 then ColText := Format('%d%%', [100 - Round(ArcItem.CompressedSize * 100 / ArcItem.UncompressedSize)]) else ColText := '0%'; vcPacked: if not ListItem.IsDirectory then ColText := FormatFloat('#,##0', ArcItem.CompressedSize); vcCRC: if not ListItem.IsDirectory then ColText := IntToHex(ArcItem.CRC32, 8); vcAttributes: if ArcItem <> nil then begin {$WARN SYMBOL_PLATFORM OFF} if (faReadOnly and ArcItem.ExternalFileAttributes) = faReadOnly then ColText := ColText + AbReadOnlyS; if (faHidden and ArcItem.ExternalFileAttributes) = faHidden then ColText := ColText + AbHiddenS; if (faSysFile and ArcItem.ExternalFileAttributes) = faSysFile then ColText := ColText + AbSystemS; if (faArchive and ArcItem.ExternalFileAttributes) = faArchive then ColText := ColText + AbArchivedS; {$WARN SYMBOL_PLATFORM ON} end; vcMethod: if ArcItem is TAbZipItem then ColText := ZipCompressionMethodToString( TAbZipItem(ArcItem).CompressionMethod); vcPath: ColText := ExtractFileDir(FileName); end; ListItem.SubItems.Add(ColText); ListItem.SubItemImages[ListItem.SubItems.Count - 1] := ColImage; end; end; finally Folders.Free; end; CustomSort(TLVCompare(@TAbCustomListView_SortProc), LPARAM(Self)); end; finally Items.EndUpdate; end; end; { ===== TAbCustomTreeView =================================================== } constructor TAbCustomTreeView.Create(aOwner: TComponent); var Bmp : TBitmap; Icon : TIcon; sfi: SHFILEINFO; begin inherited; HideSelection := False; Images := TImageList.Create(Self); Bmp := TBitmap.Create; try Bmp.LoadFromResourceName(HInstance, 'AbComCtrls_Zip'); Images.AddMasked(Bmp, clFuchsia); Icon := TIcon.Create; try // On Windows 7 an empty filename returns the drive icon instead of a folder SHGetFileInfo('Folder', FILE_ATTRIBUTE_DIRECTORY, sfi, sizeof(sfi), SHGFI_ICON or SHGFI_SMALLICON or SHGFI_USEFILEATTRIBUTES); Icon.Handle := sfi.hIcon; Bmp.PixelFormat := pf24bit; Bmp.Canvas.Brush.Color := clWindow; Bmp.Canvas.FillRect(Rect(0, 0, 16, 16)); Bmp.Canvas.Draw(0, 0, Icon); Images.AddMasked(Bmp, clWindow); SHGetFileInfo('Folder', FILE_ATTRIBUTE_DIRECTORY, sfi, sizeof(sfi), SHGFI_ICON or SHGFI_OPENICON or SHGFI_SMALLICON or SHGFI_USEFILEATTRIBUTES); Icon.Handle := sfi.hIcon; Bmp.Canvas.FillRect(Rect(0, 0, 16, 16)); Bmp.Canvas.Draw(0, 0, Icon); Images.AddMasked(Bmp, clWindow); finally Icon.Free; end; finally Bmp.Free; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomTreeView.Change(aNode: TTreeNode); var Filename: string; begin inherited; if aNode.Selected then begin Filename := ''; if aNode <> Items.GetFirstNode then begin Filename := aNode.Text; aNode := aNode.Parent; while aNode <> Items.GetFirstNode do begin Filename := aNode.Text + PathDelim + Filename; aNode := aNode.Parent; end; end; Path := Filename; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomTreeView.DoChange(Sender: TObject); var Nodes: TStringList; ZipNode: TTreeNode; function GetNode(const aFilename: string): TTreeNode; var i: Integer; begin if aFilename = '' then Result := ZipNode else if Nodes.Find(aFilename, i) then Result := TTreeNode(Nodes.Objects[i]) else begin Result := Items.AddChild(GetNode(ExtractFileDir(aFilename)), ExtractFileName(aFilename)); {$IFDEF HasTreeViewExpandedImageIndex} Result.ExpandedImageIndex := AbTreeFolderExpandedImage; {$ENDIF} Result.ImageIndex := AbTreeFolderImage; Nodes.AddObject(aFilename, Result); end; end; var i: Integer; Filename: string; begin Items.BeginUpdate; try Items.Clear; if Assigned(FArchive) then begin Nodes := TStringList.Create; try Nodes.Sorted := True; if Archive.FArchive <> nil then Filename := ExtractFileName(Archive.FArchive.ArchiveName) else Filename := PathDelim; ZipNode := Items.AddChild(nil, Filename); {$IFDEF HasTreeViewExpandedImageIndex} ZipNode.ExpandedImageIndex := AbTreeArchiveImage; {$ENDIF} ZipNode.ImageIndex := AbTreeArchiveImage; for i := 0 to FArchive.Count - 1 do if FArchive[i].Action <> aaDelete then begin Filename := AbNormalizeFilename(FArchive[i].FileName); if not FArchive[i].IsDirectory then Filename := ExtractFileDir(Filename); GetNode(Filename); end; finally Nodes.Free; end; Items.AlphaSort(True); ZipNode.Expand(False); SelectPathNode; end; finally Items.EndUpdate; end; if (Sender = FArchive) and Assigned(FListView) then FListView.DoChange(Self); end; { -------------------------------------------------------------------------- } procedure TAbCustomTreeView.GetSelectedIndex(aNode: TTreeNode); begin {$IFDEF HasTreeViewExpandedImageIndex} if aNode.Expanded then aNode.SelectedIndex := aNode.ExpandedImageIndex else {$ENDIF} aNode.SelectedIndex := aNode.ImageIndex; end; { -------------------------------------------------------------------------- } function TAbCustomTreeView.GetVersion: string; begin Result := AbVersionS; end; { -------------------------------------------------------------------------- } procedure TAbCustomTreeView.Notification(aComponent: TComponent; aOperation: TOperation); begin inherited; if aOperation = opRemove then begin if aComponent = FArchive then begin FArchive := nil; Items.Clear; end; if aComponent = FListView then begin if Assigned(FArchive) and SameEvent(FArchive.OnChange, FListView.DoChange) then FArchive.OnChange := DoChange; FListView := nil; end; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomTreeView.SelectPathNode; var Filename, Remaining: string; i: Integer; Node: TTreeNode; begin // Find selected node, expanding parents along the way Node := Items.GetFirstNode; Remaining := FPath; if StartsText(PathDelim, Remaining) then System.Delete(Remaining, 1, 1); while Remaining <> '' do begin Node.Expand(False); i := Pos(PathDelim, Remaining); if i = 0 then i := Length(Remaining) + 1; Filename := Copy(Remaining, 1, i - 1); Remaining := Copy(Remaining, i + 1, MaxInt); if Filename = '' then Continue; Node := Node.getFirstChild; while (Node <> nil) and not SameText(Filename, Node.Text) do Node := Node.getNextSibling; if Node = nil then begin Node := Items.GetFirstNode; Break; end; end; Selected := Node; end; { -------------------------------------------------------------------------- } procedure TAbCustomTreeView.SetArchive(aValue: TAbBaseBrowser); begin if aValue <> FArchive then begin if Assigned(FArchive) then begin FArchive.RemoveFreeNotification(Self); if SameEvent(FArchive.OnChange, DoChange) then if Assigned(ListView) and (ListView.Archive = FArchive) then FArchive.OnChange := ListView.DoChange else FArchive.OnChange := nil; end; FArchive := aValue; if Assigned(FArchive) then begin FArchive.FreeNotification(Self); FArchive.OnChange := DoChange; DoChange(Self); end else Items.Clear; if Assigned(ListView) then ListView.Archive := aValue; SelectPathNode; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomTreeView.SetListView(aValue: TAbCustomListView); begin if aValue <> FListView then begin if Assigned(FListView) then begin FListView.RemoveFreeNotification(Self); FListView.TreeView := nil; end; FListView := aValue; if Assigned(FListView) then begin FListView.FreeNotification(Self); if Assigned(FArchive) then FListView.Archive := FArchive else if Assigned(FListView.Archive) then Archive := FListView.Archive; FListView.TreeView := Self; end; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomTreeView.SetPath(const aValue: string); begin if FPath <> aValue then begin FPath := ExcludeTrailingPathDelimiter(aValue); SelectPathNode; if Assigned(FListView) then FListView.Path := aValue; end; end; { ===== TAbProgressBar ====================================================== } procedure TAbProgressBar.DoProgress(Progress : Byte); begin Position := Progress; Application.ProcessMessages; end; { -------------------------------------------------------------------------- } function TAbProgressBar.GetVersion : string; begin Result := AbVersionS; end; { -------------------------------------------------------------------------- } procedure TAbProgressBar.Reset; begin DoProgress(0); end; end. ================================================ FILE: lib/abbrevia/source/AbCompnd.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbCompnd.pas *} {*********************************************************} {* ABBREVIA: Compound File classes and component *} {* Use AbQCmpnd.pas for CLX *} {*********************************************************} {$IFNDEF UsingCLX} unit AbCompnd; {$ENDIF} {$I AbDefine.inc} interface uses Classes, SysUtils, {$IFDEF UsingClx} QComCtrls, {$ELSE} ComCtrls, {$ENDIF} AbBase, AbResString, AbDfDec, AbDfEnc, AbDfBase; const AbCompoundFileVersion = '3.1'; const {SystemBlock constants} sbSignatureSize = 40; {byte size of Signature field} sbVolumeLabelSize = 40; {byte size of Volume Label field} sbAllocationSizeSize = 4; {byte size of Allocation Size field} sbVersionSize = 4; {byte size of Version field} sbUpdateSize = 1; {byte size of Updating Flag field} {Total size of System Block} SizeOfSystemBlock = sbSignatureSize + sbVolumeLabelSize + sbAllocationSizeSize + sbVersionSize + sbUpdateSize; {RootDir constants} rdEntryNameSize = 28; {byte size of Name field} rdEntryIDSize = 4; {byte size of EntryID field} rdParentFolderSize = 4; {byte size of ParentFolder field} rdEntryTypeSize = 4; {byte size of EntryType field} rdAttributesSize = 4; {byte size of Attributes field} rdStartBlockSize = 4; {byte size of StartBlock field} rdLastModifiedSize = 8; {byte size of LastModified field} rdSizeSize = 4; {byte size of UncompressedSize field} rdCompressedSizeSize = 4; {byte size of CompressedSize field} {Total size of a single Root Directory Entry} rdSizeOfDirEntry = rdEntryNameSize + rdEntryIDSize + rdParentFolderSize + rdEntryTypeSize + rdAttributesSize + rdStartBlockSize + rdLastModifiedSize + rdSizeSize + rdCompressedSizeSize; rdUnUsed = -2; {Constant used to flag an RD entry as unused} {Total size of a Root Directory entry} SizeOfRootDirBlock = rdEntryNameSize + rdEntryIDSize + rdParentFolderSize + rdEntryTypeSize + rdAttributesSize + rdStartBlockSize + rdLastModifiedSize + rdSizeSize + rdCompressedSizeSize; {FAT table constants} ftEndOfBlock = -1; {End of Block} ftUnusedBlock = -2; {Unused Block} {General constants} cfAllocationSize = 512; {Default AllocationSize (bytes)} type ECompoundFileError = class(Exception); TrdEntryType = (etFolder, etFile); {dynamic array parameter for returning FAT chain sequences} type TFATChainArray = array of Integer; {forwards} {$M+} TAbCompoundFile = class; {$M-} TBeforeDirDeleteEvent = procedure(Sender : TAbCompoundFile; Dir : AnsiString; var AllowDelete : Boolean) of object; TBeforeDirModifiedEvent = procedure(Sender : TAbCompoundFile; Dir : AnsiString; var AllowModify : Boolean) of object; TBeforeFileDeleteEvent = procedure(Sender : TAbCompoundFile;FileName : AnsiString; var AllowDelete : Boolean) of object; TBeforeFileModifiedEvent = procedure(Sender : TAbCompoundFile; FileName : AnsiString; var AllowModify : Boolean) of object; TMultiNode = class(TObject) protected {private} FParent : Pointer; {pointer to the parent node} FKey : AnsiString; {node identifier} FChildren : TStringList; {list for child keys & nodes} FData : TObject; {contained object} function GetChildCount : Integer; public constructor Create(const Key : AnsiString); destructor Destroy; override; function AddChild(const Key : AnsiString) : TMultiNode; procedure DeleteChild(Index : Integer); function DeleteChildByName(const ChildKey : AnsiString) : Boolean; function DeleteChildren : Boolean; function GetChild(Index : integer) : TMultiNode; function GetChildByName(const Key : AnsiString) : TMultiNode; function HasParent : Boolean; function HasChildren : Boolean; function Contains(const Key : AnsiString) : Boolean; property Parent : Pointer read FParent write FParent; property ChildCount : Integer read GetChildCount; property Children[Index : Integer] : TMultiNode read GetChild; property Data : TObject read FData write FData; property Key : AnsiString read FKey write FKey; end; TMultiTree = class(TObject) protected {private} FRoot : TMultiNode; {reference to root node} FCount : Integer; {count of nodes in the tree} FCurrentNode : TMultiNode; {analogous to current directory} FSepChar : AnsiChar; {directory separator character} FIDCount : Integer; {counter incremented during preorder trav.} {(used to assign unique ID to each node)} procedure VisitSubNodesPost(Node : TMultiNode; ID : Integer); procedure VisitSubNodesPre(Node : TMultiNode; Strm : TStream); procedure VisitNode(Node : TMultiNode; Strm : TStream); procedure ParseDirStr(const Key : AnsiString; Lst : TStringList); procedure PopulateSubNodes(ParentNode : TMultiNode; TreeView : TTreeView; TreeNode : TTreeNode); procedure TraversePost(ID : Integer); procedure TraversePre(Strm : TStream); public constructor Create; destructor Destroy; override; function Insert(ParentNode : TMultiNode; const Key : AnsiString) : TMultiNode; function GetNode(const Key : AnsiString) : TMultiNode; function DeleteNode(const Key : AnsiString) : Boolean; procedure ChangeDir(const Key : AnsiString); function PopulateTreeView(TreeView : TTreeView) : Integer; property Root : TMultiNode read FRoot; property Count : Integer read FCount; property CurrentNode : TMultiNode read FCurrentNode; property SepChar : AnsiChar read FSepChar write FSepChar; end; TAbSystemBlock = class(TObject) protected {private} FSignature : AnsiString; {identifies the compound file structure} FVolumeLabel : AnsiString; {file identification in addition to filename} FAllocationSize : Integer; {size of allocation block} FVersion : AnsiString; {version string identifier} FUpdating : Boolean; {internal processing indicator} {protected methods} procedure BeginUpdate; procedure EndUpdate; procedure WriteToStream(Strm : TMemoryStream); {properties} property Signature : AnsiString read FSignature write FSignature; property VolumeLabel : AnsiString read FVolumeLabel write FVolumeLabel; property Updating : Boolean read FUpdating; property AllocationSize : Integer read FAllocationSize write FAllocationSize; property Version : AnsiString read FVersion; public constructor Create(const VolLabel : AnsiString; AllocationSz : Integer); end; TAbDirectoryEntry = class(TObject) protected {private} FName : AnsiString; {name of file or folder} FEntryID : Integer; {unique ID for this dir. entry} FParentFolder : LongInt; {unique ID of parent folder} FEntryType : TrdEntryType; {folder or file} FAttributes : LongInt; {file system attributes} FStartBlock : LongInt; {starting allocation block} FLastModified : TDateTime; {last modification date/time} FSize : LongInt; {uncompressed file size} FCompressedSize : LongInt; {compressed file size} procedure WriteToStream(Strm : TMemoryStream); function IsReadOnly : Boolean; function IsHidden : Boolean; function IsSysFile : Boolean; function IsVolumeID : Boolean; function IsDirectory : Boolean; function IsArchive : Boolean; function GetIsFree : Boolean; public constructor Create(AsFile : Boolean); property EntryName : AnsiString read FName write FName; property ParentFolder : LongInt read FParentFolder write FParentFolder; property Attributes : LongInt read FAttributes write FAttributes; property StartBlock : LongInt read FStartBlock write FStartBlock; property LastModified : TDateTime read FLastModified write FLastModified; property Size : LongInt read FSize write FSize; property CompressedSize : LongInt read FCompressedSize write FCompressedSize; property IsFree : Boolean read GetIsFree; property EntryType : TrdEntryType read FEntryType write FEntryType; end; TAbRootDir = class(TMultiTree) fAllocSize : Integer; protected {private} function AddFolder(FolderName : AnsiString) : TAbDirectoryEntry; function AddFile(FileName : AnsiString) : TAbDirectoryEntry; procedure DeleteFolder(FolderName : AnsiString); procedure DeleteFile(FileName : AnsiString); procedure WriteToStream(Strm : TMemoryStream); procedure GoToEntryID(ID : Integer); public constructor Create(VolLabel : AnsiString; AllocSize : Integer); destructor Destroy; override; end; TAbFATTable = class(TObject) protected {private} fFATArray : Array of Integer; {dynamic array for the FAT} fAllocSize : Integer; procedure WriteToStream(Strm : TMemoryStream); public constructor Create(AllocSize : Integer); destructor Destroy; override; function IsEndOfFile(Ndx : Integer) : Boolean; function IsUnUsed(Ndx : Integer) : Boolean; function GetNextUnusedBlock : Integer; procedure GetNewChain(NumBytes : Integer; var ChainArray : TFATChainArray); procedure GetExistingChain(StartNdx : Integer; var ChainArray : TFATChainArray); procedure ClearExistingChain(StartNdx : Integer); procedure GetRootDirChain(var ChainArray : TFATChainArray); procedure GetFATChain(var ChainArray : TFATChainArray); procedure GetNewRootDirChain(NumBytes : Integer; var ChainArray : TFATChainArray); procedure GetNewFATChain(NumBytes : Integer; var ChainArray : TFATChainArray); procedure ClearRootDirChain; procedure ClearFATChain; end; TAbCompoundFile = class(TObject) protected {private} FSystemBlock : TAbSystemBlock; {system block} FFATTable : TAbFATTable; {FAT table} FRootDir : TAbRootDir; {root directory} FDiskFile : string; {compound file name} FSizeOnDisk : Integer; {sum total of compressed sizes + uncompressed Sys, RootDir, & FAT blks} FStream : TFileStream; {Compound file stream (*.cf)} FOnAfterOpen : TNotifyEvent; FOnBeforeClose : TNotifyEvent; FOnBeforeDirDelete : TBeforeDirDeleteEvent; FOnBeforeDirModified : TBeforeDirModifiedEvent; FOnBeforeFileDelete : TBeforeFileDeleteEvent; FOnBeforeFileModified : TBeforeFileModifiedEvent; function GetVolumeLabel : AnsiString; procedure SetVolumeLabel(Val : AnsiString); function GetDirectoryEntries : Integer; function GetSizeOnDisk : Integer; procedure PersistFileData(FileData : TStream; var ChainArray : TFATChainArray); procedure PersistSystemBlock; procedure PersistRootDirBlock; procedure PersistFATBlock; procedure BuildSysBlock; procedure BuildFat; procedure BuildRootDir; procedure AddDirEntriesFromList(Lst : TStringList); procedure Defrag; {not implemented} public constructor Create(const FileName : string; const VolLabel : AnsiString; AllocSize : Integer); overload; constructor Create(const FileName : string; const VolLabel : AnsiString; AllocSize : Integer; const Signature: AnsiString); overload; destructor Destroy; override; procedure EnumerateFiles(Lst : TStringList); procedure EnumerateFolders(Lst : TStringList); procedure AddFile(FName : AnsiString; FileData : TStream; FileSize : Integer); function AddFolder(FName : AnsiString) : Boolean; procedure UpdateFile(FName : AnsiString; FData : TStream); procedure DeleteFile(FName : AnsiString); procedure DeleteFolder(FName : AnsiString); procedure Open(const FName : string); overload; procedure Open(const FName : string; const Signature: AnsiString); overload; function OpenFile(FileName : AnsiString; var Strm : TStream) : Integer; function PopulateTreeView(TreeView : TTreeView) : Integer; procedure PopulateSubNodes(ParentNode : TMultiNode; TreeView : TTreeView; TreeNode : TTreeNode); procedure RenameFile(OrigName, NewName : AnsiString); procedure RenameFolder(OrigName, NewName : AnsiString); procedure SetCurrentDirectory(val : AnsiString); function GetCurrentDirectory : AnsiString; function GetAllocationSize : Integer; property CurrentDirectory : AnsiString read GetCurrentDirectory write SetCurrentDirectory; property DirectoryEntries : Integer read GetDirectoryEntries; property SizeOnDisk : Integer read GetSizeOnDisk; property Stream : TFileStream read FStream write FStream; published property VolumeLabel : AnsiString read GetVolumeLabel write SetVolumeLabel; property FileName : string read FDiskFile; property AllocationSize : Integer read GetAllocationSize; property OnAfterOpen : TNotifyEvent read FOnAfterOpen write FOnAfterOpen; property OnBeforeClose : TNotifyEvent read FOnBeforeClose write FOnBeforeClose; property OnBeforeDirDelete : TBeforeDirDeleteEvent read FOnBeforeDirDelete write FOnBeforeDirDelete; property OnBeforeDirModified : TBeforeDirModifiedEvent read FOnBeforeDirModified write FOnBeforeDirModified; property OnBeforeFileDelete : TBeforeFileDeleteEvent read FOnBeforeFileDelete write FOnBeforeFileDelete; property OnBeforeFileModified : TBeforeFileModifiedEvent read FOnBeforeFileModified write FOnBeforeFileModified; end; implementation uses StrUtils, {$IFDEF HasAnsiStrings}AnsiStrings,{$ENDIF} ABUtils; {-----------------------------------------------------------------------------} {-----------------------------------------------------------------------------} {TMultiNode} {-----------------------------------------------------------------------------} {-----------------------------------------------------------------------------} constructor TMultiNode.Create(const Key : AnsiString); {- Creates and initializes a new node} begin inherited Create; FKey := Key; FChildren := TStringList.Create; FChildren.Sorted := True; FChildren.Duplicates := dupError; end; {-----------------------------------------------------------------------------} destructor TMultiNode.Destroy; {- Destroys the node and all of the children} var i : integer; begin {free children} for i := FChildren.Count - 1 downto 0 do FChildren.Objects[i].Free; FChildren.Free; if Assigned(FData) then TAbDirectoryEntry(FData).Free; inherited Destroy; end; {-----------------------------------------------------------------------------} function TMultiNode.AddChild(const Key : AnsiString) : TMultiNode; {- Creates and adds a new node - returns the newly added node} begin if Contains(Key) then Result := nil else begin Result := TMultiNode.Create(Key); Result.Parent := self; FChildren.AddObject(string(Key), Result); end; end; {-----------------------------------------------------------------------------} function TMultiNode.Contains(const Key : AnsiString) : Boolean; {- Returns true if the node contains a child of the name specified by 'Key'} begin Result := (FChildren.IndexOf(string(Key)) >= 0); end; {-----------------------------------------------------------------------------} procedure TMultiNode.DeleteChild(Index : Integer); {- Deletes the child node specified by 'Index'} begin if ((Index < 0) or (Index > FChildren.Count - 1)) then raise ECompoundFileError.Create(AbCmpndIndexOutOfBounds); FChildren.Objects[Index].Free; FChildren.Delete(Index); end; {-----------------------------------------------------------------------------} function TMultiNode.DeleteChildByName(const ChildKey : AnsiString) : Boolean; {- If node found, node is deleted and true is returned, else returns false} begin Result := Contains(ChildKey); if Result then begin FChildren.Objects[FChildren.IndexOf(string(ChildKey))].Free; FChildren.Delete(FChildren.IndexOf(string(ChildKey))); end; end; {-----------------------------------------------------------------------------} function TMultiNode.DeleteChildren : Boolean; {- Deletes all child nodes} var i : Integer; begin Result := FChildren.Count > 0; for i := FChildren.Count - 1 downto 0 do begin FChildren.Objects[i].Free; FChildren.Delete(i); end; end; {-----------------------------------------------------------------------------} function TMultiNode.GetChild(Index : integer) : TMultiNode; {- Returns the node specified by Index} begin if ((Index < 0) or (Index > FChildren.Count - 1)) then raise ECompoundFileError.Create(AbCmpndIndexOutOfBounds); Result := (FChildren.Objects[Index] as TMultiNode); end; {-----------------------------------------------------------------------------} function TMultiNode.GetChildByName(const Key : AnsiString) : TMultiNode; {- Returns the child node specified by 'Key'. If not found, result = nil} begin Result := nil; if Contains(Key) then Result := (FChildren.Objects[FChildren.IndexOf(string(Key))] as TMultiNode); end; {-----------------------------------------------------------------------------} function TMultiNode.GetChildCount : Integer; {- Returns the node's children count} begin Result := FChildren.Count; end; {-----------------------------------------------------------------------------} function TMultiNode.HasParent : Boolean; {- Returns true if parent is assigned, else returns false} begin Result := (FParent <> nil); end; {-----------------------------------------------------------------------------} function TMultiNode.HasChildren : Boolean; {- Returns true if the node contains 1 or more child nodes.} begin Result := (FChildren.Count > 0); end; {-----------------------------------------------------------------------------} {-----------------------------------------------------------------------------} {TMultiTree} {-----------------------------------------------------------------------------} {-----------------------------------------------------------------------------} constructor TMultiTree.Create; {- creates an empty tree} begin inherited Create; FSepChar := '\'; end; {-----------------------------------------------------------------------------} destructor TMultiTree.Destroy; {- destroys all nodes (post-order)} var Curr : TMultiNode; begin Curr := Root; while Curr <> nil do begin if Curr.HasChildren then Curr := Curr.Children[0] else begin if Curr = Root then begin Curr.Free; exit; end else begin Curr := Curr.Parent; Curr.DeleteChild(0); end; end; end; end; {-----------------------------------------------------------------------------} procedure TMultiTree.ChangeDir(const Key : AnsiString); {- Sets current directory of tree if path('Key') is valid} var Node : TMultiNode; Lst : TStringList; i, Ndx : integer; NotFound : Boolean; begin if Root = nil then exit; NotFound := False; Lst := TStringList.Create; try ParseDirStr(Key, Lst); Node := CurrentNode; for i := 0 to Lst.Count - 1 do begin if Lst.Strings[i] = '\' then begin Node := Root; Continue; end else if Lst.Strings[i] = '.' then Continue else if Lst.Strings[i] = '..' then begin if Node <> Root then Node := TMultiNode(Node.Parent); end else begin Ndx := Node.FChildren.IndexOf(Lst.Strings[i]); if Ndx >= 0 then Node := Node.GetChild(Ndx) else begin NotFound := True; Break; end; end; end; finally Lst.Free; end; if NotFound = false then FCurrentNode := Node; end; {-----------------------------------------------------------------------------} function TMultiTree.DeleteNode(const Key : AnsiString) : Boolean; {- If node found, deletes the node & returns true, else returns false} begin Result := False; if CurrentNode <> nil then if CurrentNode.Contains(Key) then begin Result := CurrentNode.DeleteChildByName(Key); Dec(FCount); end; end; {-----------------------------------------------------------------------------} function TMultiTree.GetNode(const Key : AnsiString) : TMultiNode; {- Returns the node if found, else returns nil} begin Result := nil; if CurrentNode <> nil then if CurrentNode.Contains(Key) then Result := CurrentNode.GetChildByName(Key); end; {-----------------------------------------------------------------------------} function TMultiTree.Insert(ParentNode : TMultiNode; const Key : AnsiString) : TMultiNode; {- Adds child node to specified ParentNode} var NewNode : TMultiNode; begin Result := nil; if CurrentNode = nil then begin {adding root node} NewNode := TMultiNode.Create(Key); FRoot := NewNode; FCurrentNode := NewNode; Result := NewNode; end else begin if not CurrentNode.Contains(Key) then begin Result := CurrentNode.AddChild(Key); Result.Parent := CurrentNode; end; end; Inc(FCount); end; {-----------------------------------------------------------------------------} procedure TMultiTree.ParseDirStr(const Key : AnsiString; Lst : TStringList); {- parses Key into individual dir commands adding each to Lst} var LocKey : AnsiString; Counter : integer; begin LocKey := Key; Lst.Clear; if LocKey = '' then LocKey := '\'; {- are we to start from the root folder} Counter := 0; while LocKey[Counter+1] = '\' do inc(Counter); if Counter = 1 then Lst.Add('\'); {- begin parsing} while Length(LocKey) > 0 do begin while LocKey[1] = '\' do begin Delete(LocKey, 1, 1); if Length(LocKey) = 0 then exit; end; if pos(SepChar,LocKey) > 0 then begin Lst.Add(string(copy(LocKey, 1, Pos(SepChar, LocKey) - 1))); Delete(LocKey, 1, Pos(SepChar, LocKey)); end else if Length(LocKey) > 0 then begin Lst.Add(string(LocKey)); LocKey := ''; end; end; end; {-----------------------------------------------------------------------------} procedure TMultiTree.PopulateSubNodes(ParentNode : TMultiNode; TreeView : TTreeView; TreeNode : TTreeNode); {- Visits sub-nodes recursively - pre order} var Curr : TMultiNode; i : Integer; Node : TTreeNode; begin Node := TreeView.Items.AddChild(TreeNode, string(ParentNode.Key)); Curr := ParentNode; if Curr <> nil then begin if Curr.HasChildren then begin for i := 0 to Curr.ChildCount -1 do PopulateSubNodes(Curr.Children[i], TreeView, Node); end; end; end; {-----------------------------------------------------------------------------} function TMultiTree.PopulateTreeView(TreeView : TTreeView) : Integer; {- Populates a user-supplied TTreeView with multiway tree nodes} var i : Integer; TreeNode : TTreeNode; begin TreeView.Items.Clear; if Root <> nil then begin TreeNode := TreeView.Items.Add(nil, string(Root.Key)); if Root.HasChildren then begin for i := 0 to Root.ChildCount - 1 do PopulateSubNodes(Root.Children[i], TreeView, TreeNode); end; end; Result := TreeView.Items.Count end; {-----------------------------------------------------------------------------} procedure TMultiTree.TraversePost(ID : Integer); {- Traverses tree post-order - CurrentNode after traversal will be the node whose EntryID = ID} var i : Integer; begin if Root <> nil then begin if Root.HasChildren then begin for i := 0 to Root.ChildCount - 1 do VisitSubNodesPost(Root.Children[i], ID); end; if (TAbDirectoryEntry(Root.FData).FEntryID = ID) then FCurrentNode := Root; end; end; {-----------------------------------------------------------------------------} procedure TMultiTree.TraversePre(Strm : TStream); {- Traverses tree pre-order} var i : Integer; begin if Root <> nil then begin FIDCount := 1; TAbDirectoryEntry(Root.Data).FEntryID := FIDCount; VisitNode(Root, Strm); if Root.HasChildren then begin for i := 0 to Root.ChildCount - 1 do VisitSubNodesPre(Root.Children[i], Strm); end; end; end; {-----------------------------------------------------------------------------} procedure TMultiTree.VisitNode(Node : TMultiNode; Strm : TStream); {- Called recursively from VisitSubNodesPre. Assigns unique entry ID's for each directory entry to maintain hierarchy} begin if Node.Parent = nil then TAbDirectoryEntry(Node.Data).ParentFolder := -1 else TAbDirectoryEntry(Node.Data).ParentFolder := TAbDirectoryEntry(TMultiNode(Node.Parent).Data).FEntryID; TAbDirectoryEntry(Node.Data).WriteToStream(TMemoryStream(Strm)); end; {-----------------------------------------------------------------------------} procedure TMultiTree.VisitSubNodesPost(Node : TMultiNode; ID : Integer); {- Visits sub-nodes recursively - post order} var Curr : TMultiNode; i : Integer; begin Curr := Node; if Curr <> nil then begin if Curr.HasChildren then begin for i := 0 to Curr.ChildCount -1 do VisitSubNodesPost(Curr.Children[i], ID); end; if (TAbDirectoryEntry(Curr.FData).FEntryID = ID) then FCurrentNode := Curr; end; end; {-----------------------------------------------------------------------------} procedure TMultiTree.VisitSubNodesPre(Node : TMultiNode; Strm : TStream); {- Visits sub-nodes recursively - pre order} var Curr : TMultiNode; i : Integer; begin Curr := Node; if Curr <> nil then begin Inc(FIDCount); TAbDirectoryEntry(Curr.Data).FEntryID := FIDCount; VisitNode(Curr, Strm); if Curr.HasChildren then begin for i := 0 to Curr.ChildCount -1 do VisitSubNodesPre(Curr.Children[i], Strm); end; end; end; {-----------------------------------------------------------------------------} {-----------------------------------------------------------------------------} {TAbSystemBlock} {-----------------------------------------------------------------------------} {-----------------------------------------------------------------------------} constructor TAbSystemBlock.Create(const VolLabel : AnsiString; AllocationSz : Integer); {- Creates the System block structure of the compound file} begin inherited Create; FSignature := 'AbCompoundFile'; FVolumeLabel := VolLabel; FAllocationSize := AllocationSz; FVersion := AbCompoundFileVersion; FUpdating := False; end; {-----------------------------------------------------------------------------} procedure TAbSystemBlock.BeginUpdate; {- Sets updating to true - temporarily blocking other actions} begin FUpdating := True; end; {-----------------------------------------------------------------------------} procedure TAbSystemBlock.EndUpdate; {- Clears updating flag & allows for other actions} begin FUpdating := False; end; {-----------------------------------------------------------------------------} procedure TAbSystemBlock.WriteToStream(Strm : TMemoryStream); {- writes the contents to the stream parameter} var Sig : Array[0..sbSignatureSize - 1] of AnsiChar; VolLabel : Array[0..sbVolumeLabelSize - 1] of AnsiChar; AllocSize : Integer; Version : Array[0..sbVersionSize - 1] of AnsiChar; Updt : Byte; begin FillChar(Sig, sbSignatureSize, #0); AbStrPCopy(Sig, FSignature); FillChar(VolLabel[0], sbVolumeLabelSize, #0); AbStrPCopy(VolLabel, FVolumeLabel); AllocSize := FAllocationSize; FillChar(Version[0], sbVersionSize, #0); AbStrPCopy(Version, FVersion); if FUpdating then Updt := $01 else Updt := $00; Strm.Write(Sig[0], sbSignatureSize); Strm.Write(VolLabel[0], sbVolumeLabelSize); Strm.Write(AllocSize, SizeOf(Integer)); Strm.Write(Version[0], sbVersionSize); Strm.Write(Updt, sbUpdateSize); end; {-----------------------------------------------------------------------------} {-----------------------------------------------------------------------------} {TAbDirectoryEntry} {-----------------------------------------------------------------------------} {-----------------------------------------------------------------------------} constructor TAbDirectoryEntry.Create(AsFile : Boolean); {- Creates & initializes a new TAbDirectoryEntry} begin inherited Create; FName := ''; FParentFolder := rdUnused; if AsFile then begin FEntryType := etFile; {$WARN SYMBOL_PLATFORM OFF} FAttributes := faArchive; {$WARN SYMBOL_PLATFORM ON} end else begin FEntryType := etFolder; FAttributes := faDirectory; end; FStartBlock := rdUnused; FLastModified := 0; FSize := rdUnused; FCompressedSize := rdUnused; end; {-----------------------------------------------------------------------------} function TAbDirectoryEntry.GetIsFree : Boolean; {- returns true if the entry has been marked for deletion} begin Result := (FName = ''); end; {-----------------------------------------------------------------------------} function TAbDirectoryEntry.IsArchive : Boolean; {- returns true if the entry is an archive} begin {$WARN SYMBOL_PLATFORM OFF} Result := ((FAttributes and faArchive) > 0); {$WARN SYMBOL_PLATFORM ON} end; {-----------------------------------------------------------------------------} function TAbDirectoryEntry.IsDirectory : Boolean; {- returns true if the entry is a directory} begin Result := ((FAttributes and faDirectory) > 0); end; {-----------------------------------------------------------------------------} function TAbDirectoryEntry.IsHidden : Boolean; {- returns true if the entry is hidden} begin {$WARN SYMBOL_PLATFORM OFF} Result := ((FAttributes and faHidden) > 0); {$WARN SYMBOL_PLATFORM ON} end; {-----------------------------------------------------------------------------} function TAbDirectoryEntry.IsReadOnly : Boolean; {- returns true if the entry is read-only} begin {$WARN SYMBOL_PLATFORM OFF} Result := ((FAttributes and faReadOnly) > 0); {$WARN SYMBOL_PLATFORM ON} end; {-----------------------------------------------------------------------------} function TAbDirectoryEntry.IsSysFile : Boolean; {- returns true if the entry is a system file} begin {$WARN SYMBOL_PLATFORM OFF} Result := ((FAttributes and faSysFile) > 0); {$WARN SYMBOL_PLATFORM ON} end; {-----------------------------------------------------------------------------} function TAbDirectoryEntry.IsVolumeID : Boolean; {- returns true if the entry is a volume ID} begin {$WARN SYMBOL_DEPRECATED OFF} {$WARN SYMBOL_PLATFORM OFF} Result := ((FAttributes and faVolumeID) > 0); {$WARN SYMBOL_PLATFORM ON} {$WARN SYMBOL_DEPRECATED ON} end; {-----------------------------------------------------------------------------} procedure TAbDirectoryEntry.WriteToStream(Strm : TMemoryStream); {- writes properties to stream} var EntryName : Array[0..rdEntryNameSize] of AnsiChar; FType : Integer; begin FillChar(EntryName, rdEntryNameSize - 1, #0); AbStrPCopy(EntryName, FName); Strm.Write(EntryName[0], rdEntryNameSize); Strm.Write(FEntryID, rdEntryIDSize); Strm.Write(FParentFolder, rdParentFolderSize); if EntryType = etFolder then FType := $00000000 else FType := $00000001; Strm.Write(FType, rdEntryTypeSize); Strm.Write(FAttributes, rdAttributesSize); Strm.Write(FStartBlock, rdStartBlockSize); Strm.Write(FLastModified, rdLastModifiedSize); Strm.Write(FSize, rdSizeSize); Strm.Write(FCompressedSize, rdCompressedSizeSize); end; {-----------------------------------------------------------------------------} {-----------------------------------------------------------------------------} {TAbRootDir} {-----------------------------------------------------------------------------} {-----------------------------------------------------------------------------} constructor TAbRootDir.Create(VolLabel : AnsiString; AllocSize : Integer); {- Creates a single-entry (vol-label) root directory structure} begin inherited Create; fAllocSize := AllocSize; if VolLabel <> '' then AddFolder(VolLabel); end; {-----------------------------------------------------------------------------} destructor TAbRootDir.Destroy; {- Destroys the root dir.} begin inherited Destroy; end; {-----------------------------------------------------------------------------} function TAbRootDir.AddFile(FileName : AnsiString) : TAbDirectoryEntry; {- Adds a file to the current directory of the compound file} var NewNode : TMultiNode; NewData : TAbDirectoryEntry; begin NewData := nil; NewNode := Insert(CurrentNode, FileName); if NewNode <> nil then begin NewData := TAbDirectoryEntry.Create(True); NewData.FName := FileName; NewData.ParentFolder := 1; {$WARN SYMBOL_PLATFORM OFF} NewData.Attributes := faArchive; {$WARN SYMBOL_PLATFORM ON} NewData.StartBlock := 3; NewData.LastModified := Now; NewData.Size := 4; NewData.CompressedSize := 5; NewData.EntryType := etFile; NewNode.Data := NewData; end; Result := NewData; end; {-----------------------------------------------------------------------------} function TAbRootDir.AddFolder(FolderName : AnsiString) : TAbDirectoryEntry; {- Adds a folder to the current directory of the compound file} var NewNode : TMultiNode; NewData : TAbDirectoryEntry; begin Result := nil; NewNode := Insert(CurrentNode, FolderName); if NewNode <> nil then begin NewData := TAbDirectoryEntry.Create(False); NewData.FName := FolderName; NewData.ParentFolder := 1; NewData.Attributes := faDirectory; NewData.StartBlock := rdUnUsed; NewData.LastModified := Now; NewData.Size := 0; NewData.CompressedSize := 0; NewData.EntryType := etFolder; NewNode.Data := NewData; Result :=NewData; end; end; {-----------------------------------------------------------------------------} procedure TAbRootDir.DeleteFile(FileName : AnsiString); {- Deletes the specified file if found} begin DeleteNode(FileName); end; {-----------------------------------------------------------------------------} procedure TAbRootDir.DeleteFolder(FolderName : AnsiString); {- Deletes the specifed folder if found & empty} begin if not CurrentNode.Contains(FolderName) then raise ECompoundFileError.Create(AbCmpndFileNotFound); if CurrentNode.ChildCount > 0 then raise ECompoundFileError.Create(AbCmpndFolderNotEmpty); DeleteFolder(FolderName); end; {-----------------------------------------------------------------------------} procedure TAbRootDir.WriteToStream(Strm : TMemoryStream); {- Streams and writes the root directory entries to the stream parameter} begin TraversePre(Strm); end; {-----------------------------------------------------------------------------} {-----------------------------------------------------------------------------} {TAbFATTable} {-----------------------------------------------------------------------------} {-----------------------------------------------------------------------------} constructor TAbFATTable.Create(AllocSize : Integer); {- Creates the FAT table structure} var i : Integer; begin {Sets FAT length equal to one allocation block} fAllocSize := AllocSize; SetLength(fFATArray, AllocSize div SizeOf(Integer)); for i := 0 to High(fFATArray) do fFATArray[i] := ftUnusedBlock; for i := 0 to 2 do fFATArray[i] := ftEndOfBlock; end; {-----------------------------------------------------------------------------} destructor TAbFATTable.Destroy; {- Destroys the FAT table} begin Finalize(fFATArray); end; {-----------------------------------------------------------------------------} procedure TAbFATTable.ClearExistingChain(StartNdx : Integer); {- Sets all of the FAT entries pertaining to the sequence starting at StartNds to ftUnUsedBlock} var ChainArray : TFATChainArray; i : Integer; begin SetLength(ChainArray, 0); GetExistingChain(StartNdx, ChainArray); for i := 0 to High(ChainArray) do fFATArray[ChainArray[i]] := ftUnUsedBlock; end; {-----------------------------------------------------------------------------} procedure TAbFATTable.ClearFATChain; {- Sets the FAT entries pertaining to the FAT table to unused} begin ClearExistingChain(2); end; {-----------------------------------------------------------------------------} procedure TAbFATTable.ClearRootDirChain; {- Sets the FAT entries pertaining the the RootDir to unused} begin ClearExistingChain(1); end; {-----------------------------------------------------------------------------} procedure TAbFATTable.GetExistingChain(StartNdx : Integer; var ChainArray : TFATChainArray); {- Walks the FAT table starting at the index specified, and populates the chain array parameter with the results} var BlkCount, i, ChainNdx : Integer; begin if fFATArray[StartNdx] = ftUnUsedBlock then begin SetLength(ChainArray, 0); exit; end; {determine count} if StartNdx < 1 then SetLength(ChainArray, 0) else begin BlkCount := 1; i := StartNdx; while fFATArray[i] <> ftEndOfBlock do begin i := fFATArray[i]; Inc(BlkCount); end; {set up array} SetLength(ChainArray, BlkCount); for i := 0 to High(ChainArray) do ChainArray[i] := ftUnusedBlock; {walk FAT & populate array} ChainNdx := 0; ChainArray[ChainNdx] := StartNdx; i := StartNdx; while fFATArray[i] <> ftEndOfBlock do begin Inc(ChainNdx); ChainArray[ChainNdx] := fFATArray[i]; i := fFATArray[i]; end; end; end; {-----------------------------------------------------------------------------} procedure TAbFATTable.GetFATChain(var ChainArray : TFATChainArray); {- Returns the sequence of FAT blocks used by the FAT table in the ChainArray parameter} begin GetExistingChain(2, ChainArray); end; {-----------------------------------------------------------------------------} procedure TAbFATTable.GetNewChain(NumBytes : Integer; var ChainArray : TFATChainArray); {- Finds sequence of free blocks required of a file of size NumBytes The new FAT chain is commited and passed back in the ChainArray parameter} var FirstBlock : Integer; TotalBlocksRequired : Integer; i, j, BlocksFound : Integer; begin if ((NumBytes mod fAllocSize) <> 0) then TotalBlocksRequired := (NumBytes div fAllocSize) + 1 else TotalBlocksRequired := (NumBytes div fAllocSize); if TotalBlocksRequired = 0 then exit; FirstBlock := GetNextUnusedBlock; {set up array} SetLength(ChainArray, TotalBlocksRequired); for i := 0 to High(ChainArray) do ChainArray[i] := ftUnusedBlock; ChainArray[0] := FirstBlock; BlocksFound := 1; i := FirstBlock + 1; while BlocksFound < TotalBlocksRequired do begin if ((fFATArray[i] = ftUnusedBlock) and (i > 2)) then begin ChainArray[BlocksFound] := i; inc(BlocksFound); end; Inc(i); if i > High(fFATArray) then begin {grow FAT (allocate another block)} SetLength(fFATArray, Length(fFATArray) + (fAllocSize div SizeOf(Integer))); for j := High(fFATArray) downto (Length(fFATArray) - (fAllocSize div SizeOf(Integer))) do fFATArray[j] := ftUnUsedBlock; end; end; {Update FAT} for i := 0 to High(ChainArray) do begin if i = High(ChainArray) then fFATArray[ChainArray[i]] := -1 else fFATArray[ChainArray[i]] := ChainArray[i+1]; end; end; {-----------------------------------------------------------------------------} procedure TAbFATTable.GetNewFATChain(NumBytes : Integer; var ChainArray : TFATChainArray); {- Finds and commits a new chain starting at the 3rd block. The new chain is returned in the ChainArray parameter} var FirstBlock : Integer; TotalBlocksRequired : Integer; i, j, BlocksFound : Integer; begin if ((NumBytes mod fAllocSize) <> 0) then TotalBlocksRequired := (NumBytes div fAllocSize) + 1 else TotalBlocksRequired := (NumBytes div fAllocSize); if TotalBlocksRequired = 0 then exit; FirstBlock := 2; {set up array} SetLength(ChainArray, TotalBlocksRequired); for i := 0 to High(ChainArray) do ChainArray[i] := ftUnusedBlock; ChainArray[0] := FirstBlock; BlocksFound := 1; i := FirstBlock + 1; while BlocksFound < TotalBlocksRequired do begin if ((fFATArray[i] = ftUnusedBlock) and (i > 2)) then begin ChainArray[BlocksFound] := i; inc(BlocksFound); end; Inc(i); if i > High(fFATArray) then begin {grow FAT (allocate another block)} SetLength(fFATArray, Length(fFATArray) + (fAllocSize div SizeOf(Integer))); for j := High(fFATArray) downto (Length(fFATArray) - (fAllocSize div SizeOf(Integer))) do fFATArray[j] := ftUnUsedBlock; end; end; {Update FAT} for i := 0 to High(ChainArray) do begin if i = High(ChainArray) then fFATArray[ChainArray[i]] := -1 else fFATArray[ChainArray[i]] := ChainArray[i+1]; end; end; {-----------------------------------------------------------------------------} procedure TAbFATTable.GetNewRootDirChain(NumBytes : Integer; var ChainArray : TFATChainArray); {- Finds and commits a new chain starting at the 2nd block. The new chain is returned in the ChainArray parameter} var FirstBlock : Integer; TotalBlocksRequired : Integer; i, j, BlocksFound : Integer; begin if ((NumBytes mod fAllocSize) <> 0) then TotalBlocksRequired := (NumBytes div fAllocSize) + 1 else TotalBlocksRequired := (NumBytes div fAllocSize); if TotalBlocksRequired = 0 then exit; FirstBlock := 1; {set up array} SetLength(ChainArray, TotalBlocksRequired); for i := 0 to High(ChainArray) do ChainArray[i] := ftUnusedBlock; ChainArray[0] := FirstBlock; BlocksFound := 1; i := FirstBlock + 1; while BlocksFound < TotalBlocksRequired do begin if ((fFATArray[i] = ftUnusedBlock) and (i > 2)) then begin ChainArray[BlocksFound] := i; inc(BlocksFound); end; Inc(i); if i > High(fFATArray) then begin {grow FAT (allocate another block)} SetLength(fFATArray, Length(fFATArray) + (fAllocSize div SizeOf(Integer))); for j := High(fFATArray) downto (Length(fFATArray) - (fAllocSize div SizeOf(Integer))) do fFATArray[j] := ftUnUsedBlock; end; end; {Update FAT} for i := 0 to High(ChainArray) do begin if i = High(ChainArray) then fFATArray[ChainArray[i]] := -1 else fFATArray[ChainArray[i]] := ChainArray[i+1]; end; end; {-----------------------------------------------------------------------------} function TAbFATTable.GetNextUnusedBlock : Integer; {- Returns the index into the FAT table of the next block marked as unused} var i, j : Integer; begin if Length(fFATArray) = 0 then Result := -1 else begin Result := -1; i := 3; while i <= High(fFATArray) do begin if fFATArray[i] = ftUnusedBlock then begin Result := i; exit; end; inc(i); if i > High(fFATArray) then begin {grow FAT (allocate another block)} SetLength(fFATArray, Length(fFATArray) + (fAllocSize div SizeOf(Integer))); for j := High(fFATArray) downto (Length(fFATArray) - (fAllocSize div SizeOf(Integer))) do fFATArray[j] := ftUnUsedBlock; end; end; end; end; {-----------------------------------------------------------------------------} procedure TAbFATTable.GetRootDirChain(var ChainArray : TFATChainArray); {- Returns the sequence of FAT blocks used by the RootDir in the ChainArray parameter} begin GetExistingChain(1, ChainArray); end; {-----------------------------------------------------------------------------} function TAbFATTable.IsEndOfFile(Ndx : Integer) : Boolean; {- Returns true if Ndx into FAT signifies end of file} begin if ((Ndx < 0) or (Ndx > High(fFATArray)) or (Length(fFATArray) = 0)) then raise ECompoundFileError.Create(AbCmpndIndexOutOfBounds) else Result := (fFATArray[Ndx] = ftEndOfBlock); end; {-----------------------------------------------------------------------------} function TAbFATTable.IsUnUsed(Ndx : Integer) : Boolean; {- Returns true if Ndx into FAT signifies an unused block} begin if ((Ndx < 0) or (Ndx > High(fFATArray)) or (Length(fFATArray) = 0)) then raise ECompoundFileError.Create(AbCmpndIndexOutOfBounds) else Result := (fFATArray[Ndx] = ftUnUsedBlock); end; {-----------------------------------------------------------------------------} procedure TAbFATTable.WriteToStream(Strm : TMemoryStream); {- Streams and writes the FAT entries to the stream parameter} begin Strm.Write(fFATArray[0], Length(fFATArray) * SizeOf(Integer)); end; {-----------------------------------------------------------------------------} {-----------------------------------------------------------------------------} {TAbCompoundFile} {-----------------------------------------------------------------------------} {-----------------------------------------------------------------------------} constructor TAbCompoundFile.Create(const FileName : string; const VolLabel : AnsiString; AllocSize : Integer); {- Creates a new instance} var Buff : Array of Byte; begin inherited Create; FSystemBlock := TAbSystemBlock.Create(VolLabel, AllocSize); FFATTable := TAbFATTable.Create(AllocSize); FRootDir := TAbRootDir.Create(VolLabel, AllocSize); {create file} if FileName <> '' then begin FDiskFile := FileName; FStream := TFileStream.Create(FileName, fmOpenReadWrite or fmCreate or fmShareDenyNone); {fill first 3 blocks of file} SetLength(Buff, 3 * AllocSize); FStream.Write(Buff, 3 * AllocSize); {write System, RootDir, and FAT blocks} PersistSystemBlock; PersistRootDirBlock; PersistFATBlock; if Assigned(FOnAfterOpen) then FOnAfterOpen(self); end; end; constructor TAbCompoundFile.Create(const FileName : string; const VolLabel : AnsiString; AllocSize : Integer; const Signature: AnsiString); {- Creates a new instance} var Buff : Array of Byte; begin inherited Create; FSystemBlock := TAbSystemBlock.Create(VolLabel, AllocSize); FSystemBlock.Signature := AbLeftStr(Signature, sbSignatureSize); FFATTable := TAbFATTable.Create(AllocSize); FRootDir := TAbRootDir.Create(VolLabel, AllocSize); {create file} if FileName <> '' then begin FDiskFile := FileName; FStream := TFileStream.Create(FileName, fmOpenReadWrite or fmCreate or fmShareDenyNone); {fill first 3 blocks of file} SetLength(Buff, 3 * AllocSize); FStream.Write(Buff, 3 * AllocSize); {write System, RootDir, and FAT blocks} PersistSystemBlock; PersistRootDirBlock; PersistFATBlock; if Assigned(FOnAfterOpen) then FOnAfterOpen(self); end; end; {-----------------------------------------------------------------------------} destructor TAbCompoundFile.Destroy; {- Persists and then destroys the instance of the compound file} begin PersistSystemBlock; PersistRootDirBlock; PersistFATBlock; if Assigned(FOnBeforeClose) then FOnBeforeClose(self); FSystemBlock.Free; FFATTable.Free; FRootDir.Free; FStream.Free; inherited; end; {-----------------------------------------------------------------------------} procedure TAbCompoundFile.AddFile(FName : AnsiString; FileData : TStream; FileSize : Integer); function JustFilename(const PathName : AnsiString) : AnsiString; {-Return just the filename and extension of a pathname.} var I : Cardinal; begin Result := ''; if PathName = '' then Exit; I := Succ(Word(Length(PathName))); repeat Dec(I); until (PathName[I] in ['\',':']) or (I = 0); Result := System.Copy(PathName, Succ(I), rdEntryNameSize); end; {- Compresses, adds & persists the data (FileData)} var DirEntry : TAbDirectoryEntry; CompStream : TStream; CompHelper : TAbDeflateHelper; ChainArray : TFATChainArray; begin FName := JustFileName(FName); if ((FStream.Size + FileData.Size + (4 * FSystemBlock.AllocationSize)) >= MaxLongInt) then raise ECompoundFileError.Create(AbCmpndExceedsMaxFileSize); if FSystemBlock.Updating then raise ECompoundFileError.Create(AbCmpndBusyUpdating); FSystemBlock.BeginUpdate; CompStream := TMemoryStream.Create; CompHelper := TAbDeflateHelper.Create; try DirEntry := FRootDir.AddFile(FName); if DirEntry <> nil then begin DirEntry.FSize := FileSize; {compress & update dir entry's compressed size} FileData.Seek(0, soBeginning); Deflate(FileData, CompStream, CompHelper); DirEntry.FCompressedSize := CompStream.Size; {Get new FAT chain & persist the data} SetLength(ChainArray, 0); FFATTable.GetNewChain(CompStream.Size, ChainArray); DirEntry.FStartBlock := ChainArray[0]; PersistFileData(CompStream, ChainArray); PersistRootDirBlock; PersistFATBlock; end; finally CompStream.Free; CompHelper.Free; FSystemBlock.EndUpdate; end; end; {-----------------------------------------------------------------------------} procedure TAbCompoundFile.AddDirEntriesFromList(Lst : TStringList); {- Add individual root directory entries to RootDir structure maintaining seq.} var i : Integer; LstEntry : TAbDirectoryEntry; Entry : TAbDirectoryEntry; begin for i := 0 to Lst.Count - 1 do begin LstEntry := (Lst.Objects[i] as TAbDirectoryEntry); {locate parent folder} FRootDir.GoToEntryID(LstEntry.FParentFolder); {Add file or folder} if LstEntry.EntryType = etFolder then Entry := FRootDir.AddFolder(LstEntry.FName) else Entry := FRootDir.AddFile(LstEntry.FName); {assign values} Entry.FName := LstEntry.FName; Entry.FEntryID := LstEntry.FEntryID; Entry.FParentFolder := LstEntry.FParentFolder; Entry.FEntryType := LstEntry.FEntryType; Entry.FAttributes := LstEntry.FAttributes; Entry.FStartBlock := LstEntry.FStartBlock; Entry.FLastModified := LstEntry.FLastModified; Entry.FSize := LstEntry.FSize; Entry.FCompressedSize := LstEntry.FCompressedSize; end; end; {-----------------------------------------------------------------------------} function TAbCompoundFile.AddFolder(FName : AnsiString) : Boolean; {- Adds a new folder (directory) to the compound file} var EntryCount : Integer; begin if ((FStream.Size + FSystemBlock.AllocationSize) >= MaxLongInt) then raise ECompoundFileError.Create(AbCmpndExceedsMaxFileSize); EntryCount := FRootDir.Count; FSystemBlock.BeginUpdate; try FRootDir.AddFolder(FName); PersistRootDirBlock; PersistFATBlock; finally FSystemBlock.EndUpdate; end; Result := ((FRootDir.Count - EntryCount) = 1); end; {-----------------------------------------------------------------------------} procedure TAbCompoundFile.BuildFat; {- Extracts FAT from this string, writes it to DestStrm(TMemoryStream) and ultimately updates/persists the FAT table} var Buff : Array of Integer; IntBuff : Array[0..0] of Integer; DestStrm : TMemoryStream; i, CurrPos : Integer; NextBlock : Integer; begin DestStrm := TMemoryStream.Create; try {Dim Buff to allocation block size} SetLength(Buff, FSystemBlock.AllocationSize div SizeOf(Integer)); {Clear Buff} for i := Low(Buff) to High(Buff) do Buff[i] := ftUnusedBlock; {read 1st FAT block into Buff -> Write Buff to DestStrm} FStream.Seek(2 * FSystemBlock.AllocationSize, soBeginning); FStream.Read(Buff[0], FSystemBlock.AllocationSize); DestStrm.Write(Buff[0], FSystemBlock.AllocationSize); {Determine next block of FAT chain} NextBlock := Buff[2]; {read remaining FAT blocks if they exist} While NextBlock <> ftEndOfBlock do begin FStream.Seek((NextBlock) * FSystemBlock.AllocationSize, soBeginning); {Clear buff} for i := Low(Buff) to High(Buff) do Buff[i] := ftUnusedBlock; FStream.Read(Buff[0], FSystemBlock.AllocationSize); DestStrm.Write(Buff[0], FSystemBlock.AllocationSize); {Determine the next FAT block - we'll return to this position in stream} CurrPos := DestStrm.Position; DestStrm.Seek((NextBlock - 1) * SizeOf(Integer), soBeginning); DestStrm.Read(IntBuff[0], SizeOf(Integer)); NextBlock := IntBuff[0]; DestStrm.Seek(CurrPos, soBeginning); end; {Set length of and populate the FFATTable.fFATArray in mem structure} DestStrm.Seek(0, soBeginning); SetLength(FFATTable.fFATArray, DestStrm.Size div SizeOf(Integer)); for i := 1 to DestStrm.Size div SizeOf(Integer) do begin DestStrm.Read(IntBuff[0], SizeOf(Integer)); FFATTable.fFATArray[i-1] := IntBuff[0]; end; finally DestStrm.Free; end; PersistFATBlock; end; {-----------------------------------------------------------------------------} procedure TAbCompoundFile.BuildRootDir; {- Builds list of root directory entries & passes list to AddDirEntriesFromList} var ChainArray : TFATChainArray; DestStrm : TMemoryStream; Buff : Array of Byte; i : Integer; Entry : TAbDirectoryEntry; Lst : TStringList; {RootDirEntry buffers} EName : Array[0..rdEntryNameSize - 1] of AnsiChar; EID : Array[0..0] of Integer; EPF : Array[0..0] of Integer; EType : Array[0..0] of Integer; EAttrib : Array[0..0] of Integer; EStartBlk : Array[0..0] of Integer; EMod : Array[0..0] of TDateTime; ESz : Array[0..0] of Integer; ECompSz : Array[0..0] of Integer; begin {Get RootDir FAT chain} FFATTable.GetRootDirChain(ChainArray); SetLength(Buff, FSystemBlock.AllocationSize); DestStrm := TMemoryStream.Create; Lst := TStringList.Create; Lst.Duplicates := dupAccept; Lst.Sorted := False; try {Read entire RotDir block to DestStrm} for i := 0 to High(ChainArray) do begin FStream.Seek(FSystemBlock.AllocationSize * ChainArray[i], soBeginning); FStream.Read(Buff[0], FSystemBlock.AllocationSize); DestStrm.Write(Buff[0], FSystemBlock.AllocationSize); end; {Reset DestStrm} DestStrm.Seek(0, soBeginning); {For all directory entries, read entry, create object, & add to Lst} for i := 0 to (DestStrm.Size div rdSizeOfDirEntry) - 1 do begin {read a single directory entry} DestStrm.Read(EName[0], rdEntryNameSize); if EName = '' then continue; DestStrm.Read(EID[0], SizeOf(Integer)); DestStrm.Read(EPF[0], SizeOf(Integer)); DestStrm.Read(EType[0], SizeOf(Integer)); DestStrm.Read(EAttrib[0], SizeOf(Integer)); DestStrm.Read(EStartBlk[0], SizeOf(Integer)); DestStrm.Read(EMod[0], SizeOf(TDateTime)); DestStrm.Read(ESz[0], SizeOf(Integer)); DestStrm.Read(ECompSz[0], SizeOf(Integer)); if EType[0] = 0 then Entry := TAbDirectoryEntry.Create(False) else Entry := TAbDirectoryEntry.Create(True); Entry.FName := EName; Entry.FEntryID := EID[0]; Entry.FParentFolder := EPF[0]; if EType[0] = 0 then Entry.FEntryType := etFolder else Entry.FEntryType := etFile; Entry.FAttributes := EAttrib[0]; Entry.FStartBlock := EStartBlk[0]; Entry.FLastModified := EMod[0]; Entry.FSize := ESz[0]; Entry.FCompressedSize := ECompSz[0]; {Don't add an empty dir entry} if Entry.FName <> '' then Lst.AddObject(IntToStr(i), TObject(Entry)); end; {Add individual root directory entries to RootDir structure maintaining seq.} AddDirEntriesFromList(Lst); finally DestStrm.Free; for i := 0 to Lst.Count - 1 do if Lst.Objects[i] <> nil then TAbDirectoryEntry(Lst.Objects[i]).Free; Lst.Free; end; {Save updates} PersistRootDirBlock; PersistFATBlock; end; {-----------------------------------------------------------------------------} procedure TAbCompoundFile.BuildSysBlock; {- Constructs System block from the contents of FStream (used when opening an existing compound file)} var Sig : Array[0..sbSignatureSize - 1] of AnsiChar; VolLabel : Array[0..sbVolumeLabelSize - 1] of AnsiChar; Version : Array[0..sbVersionSize - 1] of AnsiChar; AllocationSz : Array[0..0] of Integer; begin FStream.Seek(0, soBeginning); FStream.Read(Sig[0], sbSignatureSize); FStream.Read(VolLabel[0], sbVolumeLabelSize); FStream.Read(AllocationSz[0], sbAllocationSizeSize); FStream.Read(Version[0], sbVersionSize); FSystemBlock.Signature := Sig; FSystemBlock.VolumeLabel := VolLabel; FSystemBlock.AllocationSize := AllocationSz[0]; FSystemBlock.FVersion := Version; PersistSystemBlock; end; {-----------------------------------------------------------------------------} procedure TAbCompoundFile.Defrag; {- Optimizes disk storage} begin { not implemeneted } end; {-----------------------------------------------------------------------------} procedure TAbCompoundFile.DeleteFile(FName : AnsiString); {- Deletes the file from the RootDirectory and FAT blocks (data remains)} var StartBlock : Integer; Allow : Boolean; AllowDirMod : Boolean; begin Allow := True; AllowDirMod := True; if not FRootDir.CurrentNode.Contains(FName) then raise ECompoundFileError.Create(AbCmpndFileNotFound); if Assigned(FOnBeforeFileDelete) then FOnBeforeFileDelete(self, FName, Allow); if Assigned(FOnBeforeDirModified) then FOnBeforeDirModified(self, TMultiNode(FRootDir.CurrentNode.Parent).Key, AllowDirMod); if (Allow and AllowDirMod) then begin StartBlock := TAbDirectoryEntry(FRootDir.GetNode(FName).FData).StartBlock; FFATTable.ClearExistingChain(StartBlock); FRootDir.DeleteFile(FName); PersistRootDirBlock; PersistFATBlock; end; end; {-----------------------------------------------------------------------------} procedure TAbCompoundFile.DeleteFolder(FName : AnsiString); {- Deletes the folder from the RootDirectory block} var Allow : Boolean; AllowDirMod : Boolean; begin Allow := True; AllowDirMod := True; if not FRootDir.CurrentNode.Contains(FName) then raise ECompoundFileError.Create(AbCmpndFileNotFound); if Assigned(FOnBeforeDirDelete) then FOnBeforeDirDelete(self, FName, Allow); if Assigned(FOnBeforeDirModified) then FOnBeforeDirModified(self, TMultiNode(FRootDir.CurrentNode.Parent).Key, AllowDirMod); if (Allow and AllowDirMod) then begin FRootDir.DeleteFolder(FName); PersistRootDirBlock; PersistFATBlock; end; end; {-----------------------------------------------------------------------------} procedure TAbCompoundFile.EnumerateFiles(Lst : TStringList); var i : Integer; begin Lst.Clear; for i := 0 to FRootDir.CurrentNode.ChildCount - 1 do begin if (FRootDir.CurrentNode.Children[i].Data as TAbDirectoryEntry).EntryType = etFile then Lst.Add(string((FRootDir.CurrentNode.Children[i].Data as TAbDirectoryEntry).EntryName)); end; end; {-----------------------------------------------------------------------------} procedure TAbCompoundFile.EnumerateFolders(Lst : TStringList); var i : Integer; begin Lst.Clear; for i := 0 to FRootDir.CurrentNode.ChildCount - 1 do begin if (FRootDir.CurrentNode.Children[i].Data as TAbDirectoryEntry).EntryType = etFolder then Lst.Add(string((FRootDir.CurrentNode.Children[i].Data as TAbDirectoryEntry).EntryName)); end; end; {-----------------------------------------------------------------------------} function TAbCompoundFile.GetAllocationSize : Integer; {- Returns the block allocation size used by the compound file} begin result := FSystemBlock.AllocationSize; end; {-----------------------------------------------------------------------------} function TAbCompoundFile.GetCurrentDirectory : AnsiString; {- Returns the current directory} begin Result := FRootDir.CurrentNode.Key; end; {-----------------------------------------------------------------------------} function TAbCompoundFile.GetDirectoryEntries : Integer; {- Returns the total number of directory entries (files and folders)} begin Result := FRootDir.Count; end; {-----------------------------------------------------------------------------} function TAbCompoundFile.GetSizeOnDisk : Integer; {- Returns the compound file size (FStream.Size)} begin Result := FStream.Size; end; {-----------------------------------------------------------------------------} function TAbCompoundFile.GetVolumeLabel : AnsiString; {- Returns the volume label of the compound file} begin Result := FSystemBlock.VolumeLabel; end; {-----------------------------------------------------------------------------} procedure TAbRootDir.GoToEntryID(ID : Integer); {- Traverses tree and sets the current node to the node whose EntryID = ID} begin TraversePost(ID); end; {-----------------------------------------------------------------------------} procedure TAbCompoundFile.Open(const FName : string); {- Opens an existing compound file and builds Sys, Root Dir, and FAT blocks} var Sig : Array[0..sbSignatureSize - 1] of AnsiChar; begin if FStream <> nil then FStream.Free; FStream := TFileStream.Create(FName, fmOpenReadWrite or fmShareDenyNone); {Ensure valid signature} FStream.Read(Sig[0], sbSignatureSize); if Sig <> AbLeftStr(FSystemBlock.Signature, sbSignatureSize) then begin raise ECompoundFileError.Create(AbCmpndInvalidFile); exit; end; FDiskFile := FName; {populate Compound File structure} BuildSysBlock; BuildFat; BuildRootDir; if Assigned(FOnAfterOpen) then FOnAfterOpen(self); end; procedure TAbCompoundFile.Open(const FName : string; const Signature: AnsiString); {- Opens an existing compound file and builds Sys, Root Dir, and FAT blocks} var Sig : Array[0..sbSignatureSize - 1] of AnsiChar; begin if FStream <> nil then FStream.Free; FStream := TFileStream.Create(FName, fmOpenReadWrite or fmShareDenyNone); {Ensure valid signature} FStream.Read(Sig[0], sbSignatureSize); if Sig <> AbLeftStr(Signature, sbSignatureSize) then begin raise ECompoundFileError.Create(AbCmpndInvalidFile); exit; end; FDiskFile := FName; {populate Compound File structure} BuildSysBlock; BuildFat; BuildRootDir; if Assigned(FOnAfterOpen) then FOnAfterOpen(self); end; {-----------------------------------------------------------------------------} function TAbCompoundFile.OpenFile(FileName : AnsiString; var Strm : TStream) : Integer; {- Opens the file and writes the file contents to Strm} var ChainArray : TFatChainArray; i, j : Integer; Buff : Array of Byte; RemainingBytes : Integer; CompStream : TStream; CompHelper : TAbDeflateHelper; begin if not FRootDir.CurrentNode.Contains(FileName) then raise ECompoundFileError.Create(AbCmpndFileNotFound); CompStream := TMemoryStream.Create; CompHelper := TAbDeflateHelper.Create; try {Read the existing (compressed) file into CompStream} FFATTable.GetExistingChain((FRootDir.GetNode(FileName).FData as TAbDirectoryEntry).StartBlock, ChainArray); SetLength(Buff, FSystemBlock.AllocationSize); for i := 0 to high(ChainArray) do begin for j := 0 to Pred(FSystemBlock.AllocationSize) do Buff[j] := Byte(chr(0)); FStream.Seek((ChainArray[i]) * FSystemBlock.AllocationSize, soBeginning); if i <> High(ChainArray) then begin FStream.Read(buff[0], FSystemBlock.AllocationSize); CompStream.Write(Buff[0], FSystemBlock.AllocationSize); end else begin {read less than entire block} RemainingBytes := (FRootDir.GetNode(FileName).FData as TAbDirectoryEntry). CompressedSize mod FSystemBlock.AllocationSize; FStream.Read(Buff[0], RemainingBytes); CompStream.Write(Buff[0], RemainingBytes); end; end; {CompStream now contains the entire compressed file stream} CompStream.Seek(0, soBeginning); Inflate(CompStream, Strm, CompHelper); finally CompStream.Free; CompHelper.Free; end; Result := Strm.Size; end; {-----------------------------------------------------------------------------} procedure TAbCompoundFile.PersistFATBlock; {- Saves the FAT table to disk} var FATStrm : TMemoryStream; Buff : Array of Byte; i : Integer; ChainArray : TFATChainArray; begin {Init Buffer} SetLength(Buff, FSystemBlock.AllocationSize); {Init & fill RootDir stream} FATStrm := TMemoryStream.Create; try FFATTable.WriteToStream(FATStrm); {prep FAT Table} fFATTable.ClearFATChain; fFATTable.GetNewFATChain(FATStrm.Size, ChainArray); FATStrm.Seek(0, soBeginning); for i := 0 to High(ChainArray) do begin {Clear block contents} FillChar(Buff[0], FSystemBlock.AllocationSize, #0); FStream.Seek(FSystemBlock.FAllocationSize * ChainArray[i], soBeginning); FStream.Write(Buff[0], FSystemBlock.AllocationSize); {write new contents} FATStrm.Read(Buff[0], FSystemBlock.AllocationSize); FStream.Seek(FSystemBlock.FAllocationSize * ChainArray[i], soBeginning); FStream.Write(Buff[0], FSystemBlock.AllocationSize); end; finally FATStrm.Free; end; end; {-----------------------------------------------------------------------------} procedure TAbCompoundFile.PersistFileData(FileData : TStream; var ChainArray : TFATChainArray); {- Walks FAT chain and persists data (FileData) to the corresponding blocks} var Buff : Array of Byte; i : Integer; j : Integer; begin if FileData <> nil then begin FileData.Seek(0, soBeginning); SetLength(Buff, FSystemBlock.AllocationSize); for i := 0 to High(ChainArray) do begin for j := 0 to FSystemBlock.AllocationSize - 1 do Buff[j] := Byte(chr(0)); FileData.Read(Buff[0], FSystemBlock.AllocationSize); FStream.Seek(FSystemBlock.AllocationSize * ChainArray[i], soBeginning); FStream.Write(Buff[0],FSystemBlock.AllocationSize); end; end; end; {-----------------------------------------------------------------------------} procedure TAbCompoundFile.PersistRootDirBlock; {- Saves the RootDirectory block to disk} var RdStrm : TMemoryStream; Buff : Array of Byte; i : Integer; ChainArray : TFATChainArray; begin {Init Buffer} SetLength(Buff, FSystemBlock.AllocationSize); {Init & fill RootDir stream} RdStrm := TMemoryStream.Create; try FRootDir.WriteToStream(RdStrm); {prep FAT Table} fFATTable.ClearRootDirChain; fFATTable.GetNewRootDirChain(RdStrm.Size, ChainArray); RdStrm.Seek(0, soBeginning); for i := 0 to High(ChainArray) do begin {Clear block contents} FillChar(Buff[0], FSystemBlock.AllocationSize, #0); FStream.Seek(FSystemBlock.FAllocationSize * ChainArray[i], soBeginning); FStream.Write(Buff[0], FSystemBlock.AllocationSize); {write new contents} RdStrm.Read(Buff[0], FSystemBlock.AllocationSize); FStream.Seek(FSystemBlock.FAllocationSize * ChainArray[i], soBeginning); FStream.Write(Buff[0], FSystemBlock.AllocationSize); end; finally RdStrm.Free; end; end; {-----------------------------------------------------------------------------} procedure TAbCompoundFile.PersistSystemBlock; {- Saves the System block to disk} var Strm : TMemoryStream; Buff : Array of Byte; begin SetLength(Buff, FSystemBlock.AllocationSize); Strm := TMemoryStream.Create; try FSystemBlock.WriteToStream(Strm); Strm.Seek(0, soBeginning); Strm.Read(Buff[0], Strm.Size); FStream.Seek(0, soBeginning); FStream.Write(Buff[0], FSystemBlock.AllocationSize); finally Strm.Free; end; end; {-----------------------------------------------------------------------------} procedure TAbCompoundFile.SetCurrentDirectory(val : AnsiString); {- Changes the current directory to the val parameter} begin FRootDir.ChangeDir(Val); end; {-----------------------------------------------------------------------------} procedure TAbCompoundFile.SetVolumeLabel(Val : AnsiString); {- Sets the volume label of the compound file} begin FSystemBlock.VolumeLabel := Val; PersistSystemBlock; end; {-----------------------------------------------------------------------------} procedure TAbCompoundFile.UpdateFile(FName : AnsiString; FData : TStream); var StartBlk : Integer; ChainArray : TFATChainArray; DirEntry : TAbDirectoryEntry; CompStream : TStream; CompHelper : TAbDeflateHelper; Allow : Boolean; AllowDirMod : Boolean; begin Allow := True; AllowDirMod := True; if not FRootDir.CurrentNode.Contains(FName) then raise ECompoundFileError.Create(AbCmpndFileNotFound); if ((FStream.Size + FData.Size + (4 * FSystemBlock.AllocationSize)) >= MaxLongInt) then raise ECompoundFileError.Create(AbCmpndExceedsMaxFileSize); if Assigned(FOnBeforeFileModified) then FOnBeforeFileModified(self, FName, Allow); if Assigned(FOnBeforeDirModified) then FOnBeforeDirModified(self, TMultiNode(FRootDir.CurrentNode.Parent).Key, AllowDirMod); if (Allow and AllowDirMod) then begin {get dir entry & start block} DirEntry := TAbDirectoryEntry(FRootDir.CurrentNode.GetChildByName(FName).Data); StartBlk := DirEntry.StartBlock; CompStream := TMemoryStream.Create; CompHelper := TAbDeflateHelper.Create; try {clear existing FAT chain} FFATTable.ClearExistingChain(StartBlk); SetLength(ChainArray, 0); {Deflate data} FData.Seek(0, soBeginning); Deflate(FData, CompStream, CompHelper); {Commit new FAT chain} FFATTable.GetNewChain(CompStream.Size, ChainArray); {update start block, size, compressed size} DirEntry.FStartBlock := ChainArray[0]; DirEntry.Size := FData.Size; DirEntry.CompressedSize := CompStream.Size; {persist changes} PersistFileData(CompStream, ChainArray); PersistRootDirBlock; PersistFATBlock; finally CompStream.Free; CompHelper.Free; end; end; end; {-----------------------------------------------------------------------------} function TAbCompoundFile.PopulateTreeView(TreeView : TTreeView) : Integer; {- Populates the tree view parameter with all root directory entries} var i : Integer; TreeNode : TTreeNode; begin TreeView.Items.Clear; if FRootDir.Root <> nil then begin TreeNode := TreeView.Items.Add(nil, string(FRootDir.Root.Key)); TreeNode.ImageIndex := 0; TreeNode.SelectedIndex := 0; if FRootDir.Root.HasChildren then begin for i := 0 to FRootDir.Root.ChildCount - 1 do PopulateSubNodes(FRootDir.Root.Children[i], TreeView, TreeNode); end; end; Result := TreeView.Items.Count; end; {-----------------------------------------------------------------------------} procedure TAbCompoundFile.PopulateSubNodes(ParentNode : TMultiNode; TreeView : TTreeView; TreeNode : TTreeNode); {- Visits sub-nodes recursively - pre order} var Curr : TMultiNode; i : Integer; Node : TTreeNode; begin Node := TreeView.Items.AddChild(TreeNode, string(ParentNode.Key)); if TAbDirectoryEntry(ParentNode.Data).EntryType = etFolder then begin Node.ImageIndex := 0; Node.SelectedIndex := 0; end else begin Node.ImageIndex := 1; Node.SelectedIndex := 1; end; Curr := ParentNode; if Curr <> nil then begin if Curr.HasChildren then begin for i := 0 to Curr.ChildCount -1 do PopulateSubNodes(Curr.Children[i], TreeView, Node); end; end; end; {-----------------------------------------------------------------------------} procedure TAbCompoundFile.RenameFile(OrigName, NewName : AnsiString); {- Renames the file if file is found} var MultNode : TMultiNode; Allow : Boolean; AllowDirMod : Boolean; begin Allow := True; AllowDirMod := True; {confirm valid names} if ((OrigName = '') or (NewName = '')) then exit; {prevent duplicate names} if ((FRootDir.FCurrentNode.Contains(NewName)) or (FRootDir.FCurrentNode.Key = NewName)) then exit; if Assigned(FOnBeforeFileModified) then FOnBeforeFileModified(self, OrigName, Allow); if Assigned(FOnBeforeDirModified) then FOnBeforeDirModified(self, TMultiNode(FRootDir.CurrentNode.Parent).Key, AllowDirMod); if (Allow and AllowDirMod) then begin if FRootDir.FCurrentNode.Contains(OrigName) then begin MultNode := FRootDir.FCurrentNode.GetChildByName(OrigName); MultNode.Key := NewName; TAbDirectoryEntry(MultNode.Data).FName := NewName; PersistRootDirBlock; end else if FRootDir.FCurrentNode.Key = OrigName then begin MultNode := FRootDir.FCurrentNode; MultNode.Key := NewName; TAbDirectoryEntry(MultNode.Data).FName := NewName; PersistRootDirBlock; end else raise ECompoundFileError.Create(AbCmpndFileNotFound); end; end; {-----------------------------------------------------------------------------} procedure TAbCompoundFile.RenameFolder(OrigName, NewName : AnsiString); {- Renames the folder if the folder is found} var MultNode : TMultiNode; Allow : Boolean; AllowDirMod : Boolean; begin Allow := True; AllowDirMod := True; {confirm valid names} if ((OrigName = '') or (NewName = '')) then exit; {prevent duplicate names} if ((FRootDir.FCurrentNode.Contains(NewName)) or (FRootDir.FCurrentNode.Key = NewName)) then exit; if Assigned(FOnBeforeFileModified) then FOnBeforeFileModified(self, OrigName, Allow); if Assigned(FOnBeforeDirModified) then FOnBeforeDirModified(self, TMultiNode(FRootDir.CurrentNode.Parent).Key, AllowDirMod); if (Allow and AllowDirMod) then begin if FRootDir.FCurrentNode.Contains(OrigName) then begin MultNode := FRootDir.FCurrentNode.GetChildByName(OrigName); if (TAbDirectoryEntry(MultNode.Data).EntryType <> etFolder) then exit; MultNode.Key := NewName; TAbDirectoryEntry(MultNode.Data).FName := NewName; PersistRootDirBlock; end else if FRootDir.FCurrentNode.Key = OrigName then begin MultNode := FRootDir.FCurrentNode; if (TAbDirectoryEntry(MultNode.Data).EntryType <> etFolder) then exit; MultNode.Key := NewName; TAbDirectoryEntry(MultNode.Data).FName := NewName; PersistRootDirBlock; end else raise ECompoundFileError.Create(AbCmpndFileNotFound); end; end; {-----------------------------------------------------------------------------} end. ================================================ FILE: lib/abbrevia/source/AbConst.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* Abbrevia: AbConst.pas *} {*********************************************************} {* Abbrevia: Constants *} {*********************************************************} unit AbConst; {$I AbDefine.inc} interface const AbVersion = 5.0; AbVersionS = '5.0'; Ab_MessageLen = 255; Ab_CaptionLen = 80; AB_ZIPPATHDELIM = '/'; const AbZipVersionNeeded = 1; AbUnknownCompressionMethod = 2; AbNoExtractionMethod = 3; AbInvalidPassword = 4; AbNoInsertionMethod = 5; AbInvalidFactor = 6; AbDuplicateName = 7; AbUnsupportedCompressionMethod = 8; AbUserAbort = 9; AbArchiveBusy = 10; AbBadSpanStream = 11; AbNoOverwriteSpanStream = 12; AbNoSpannedSelfExtract = 13; AbStreamFull = 14; AbNoSuchDirectory = 15; AbInflateBlockError = 16; AbBadStreamType = 17; AbTruncateError = 18; AbZipBadCRC = 19; AbZipBadStub = 20; AbFileNotFound = 21; AbInvalidLFH = 22; AbNoArchive = 23; AbErrZipInvalid = 24; AbReadError = 25; AbInvalidIndex = 26; AbInvalidThreshold = 27; AbUnhandledFileType = 28; AbSpanningNotSupported = 29; AbBBSReadTooManyBytes = 40; AbBBSSeekOutsideBuffer = 41; AbBBSInvalidOrigin = 42; AbBBSWriteTooManyBytes = 43; AbNoCabinetDllError = 50; AbFCIFileOpenError = 51; AbFCIFileReadError = 52; AbFCIFileWriteError = 53; AbFCIFileCloseError = 54; AbFCIFileSeekError = 55; AbFCIFileDeleteError = 56; AbFCIAddFileError = 57; AbFCICreateError = 58; AbFCIFlushCabinetError = 59; AbFCIFlushFolderError = 60; AbFDICopyError = 61; AbFDICreateError = 62; AbInvalidCabTemplate = 63; AbInvalidCabFile = 64; AbSWSNotEndofStream = 80; AbSWSSeekFailed = 81; AbSWSWriteFailed = 82; AbSWSInvalidOrigin = 83; AbSWSInvalidNewOrigin = 84; AbVMSReadTooManyBytes = 100; AbVMSInvalidOrigin = 101; AbVMSErrorOpenSwap = 102; AbVMSSeekFail = 103; AbVMSReadFail = 104; AbVMSWriteFail = 105; AbVMSWriteTooManyBytes = 106; AbGZipInvalid = 200; AbGzipBadCRC = 201; AbGzipBadFileSize = 202; AbTarInvalid = 220; AbTarBadFileName = 221; AbTarBadLinkName = 222; AbTarBadOp = 223; function AbStrRes(Index : Integer) : string; implementation uses AbResString; type AbStrRec = record ID: Integer; Str: string; end; const AbStrArray : array [0..66] of AbStrRec = ( (ID: AbZipVersionNeeded; Str: AbZipVersionNeededS), (ID: AbUnknownCompressionMethod; Str: AbUnknownCompressionMethodS), (ID: AbNoExtractionMethod; Str: AbNoExtractionMethodS), (ID: AbInvalidPassword; Str: AbInvalidPasswordS), (ID: AbNoInsertionMethod; Str: AbNoInsertionMethodS), (ID: AbInvalidFactor; Str: AbInvalidFactorS), (ID: AbDuplicateName; Str: AbDuplicateNameS), (ID: AbUnsupportedCompressionMethod; Str: AbUnsupportedCompressionMethodS), (ID: AbUserAbort; Str: AbUserAbortS), (ID: AbArchiveBusy; Str: AbArchiveBusyS), (ID: AbBadSpanStream; Str: AbBadSpanStreamS), (ID: AbNoOverwriteSpanStream; Str: AbNoOverwriteSpanStreamS), (ID: AbNoSpannedSelfExtract; Str: AbNoSpannedSelfExtractS), (ID: AbStreamFull; Str: AbStreamFullS), (ID: AbNoSuchDirectory; Str: AbNoSuchDirectoryS), (ID: AbInflateBlockError; Str: AbInflateBlockErrorS), (ID: AbBadStreamType; Str: AbBadStreamTypeS), (ID: AbTruncateError; Str: AbTruncateErrorS), (ID: AbZipBadCRC; Str: AbZipBadCRCS), (ID: AbZipBadStub; Str: AbZipBadStubS), (ID: AbFileNotFound; Str: AbFileNotFoundS), (ID: AbInvalidLFH; Str: AbInvalidLFHS), (ID: AbNoArchive; Str: AbNoArchiveS), (ID: AbErrZipInvalid; Str: AbErrZipInvalidS), (ID: AbReadError; Str: AbReadErrorS), (ID: AbInvalidIndex; Str: AbInvalidIndexS), (ID: AbInvalidThreshold; Str: AbInvalidThresholdS), (ID: AbUnhandledFileType; Str: AbUnhandledFileTypeS), (ID: AbSpanningNotSupported; Str: AbSpanningNotSupportedS), (ID: AbBBSReadTooManyBytes; Str: AbBBSReadTooManyBytesS), (ID: AbBBSSeekOutsideBuffer; Str: AbBBSSeekOutsideBufferS), (ID: AbBBSInvalidOrigin; Str: AbBBSInvalidOriginS), (ID: AbBBSWriteTooManyBytes; Str: AbBBSWriteTooManyBytesS), (ID: AbNoCabinetDllError; Str: AbNoCabinetDllErrorS), (ID: AbFCIFileOpenError; Str: AbFCIFileOpenErrorS), (ID: AbFCIFileReadError; Str: AbFCIFileReadErrorS), (ID: AbFCIFileWriteError; Str: AbFCIFileWriteErrorS), (ID: AbFCIFileCloseError; Str: AbFCIFileCloseErrorS), (ID: AbFCIFileSeekError; Str: AbFCIFileSeekErrorS), (ID: AbFCIFileDeleteError; Str: AbFCIFileDeleteErrorS), (ID: AbFCIAddFileError; Str: AbFCIAddFileErrorS), (ID: AbFCICreateError; Str: AbFCICreateErrorS), (ID: AbFCIFlushCabinetError; Str: AbFCIFlushCabinetErrorS), (ID: AbFCIFlushFolderError; Str: AbFCIFlushFolderErrorS), (ID: AbFDICopyError; Str: AbFDICopyErrorS), (ID: AbFDICreateError; Str: AbFDICreateErrorS), (ID: AbInvalidCabTemplate; Str: AbInvalidCabTemplateS), (ID: AbInvalidCabFile; Str: AbInvalidCabFileS), (ID: AbSWSNotEndofStream; Str: AbSWSNotEndofStreamS), (ID: AbSWSSeekFailed; Str: AbSWSSeekFailedS), (ID: AbSWSWriteFailed; Str: AbSWSWriteFailedS), (ID: AbSWSInvalidOrigin; Str: AbSWSInvalidOriginS), (ID: AbSWSInvalidNewOrigin; Str: AbSWSInvalidNewOriginS), (ID: AbVMSReadTooManyBytes; Str: AbVMSReadTooManyBytesS), (ID: AbVMSInvalidOrigin; Str: AbVMSInvalidOriginS), (ID: AbVMSErrorOpenSwap; Str: AbVMSErrorOpenSwapS), (ID: AbVMSSeekFail; Str: AbVMSSeekFailS), (ID: AbVMSReadFail; Str: AbVMSReadFailS), (ID: AbVMSWriteFail; Str: AbVMSWriteFailS), (ID: AbVMSWriteTooManyBytes; Str: AbVMSWriteTooManyBytesS), (ID: AbGzipInvalid; Str: AbGzipInvalidS), (ID: AbGzipBadCRC; Str: AbGzipBadCRCS), (ID: AbGzipBadFileSize; Str: AbGzipBadFileSizeS), (ID: AbTarInvalid; Str: AbTarInvalidS), (ID: AbTarBadFileName; Str: AbTarBadFileNameS), (ID: AbTarBadLinkName; Str: AbTarBadLinkNameS), (ID: AbTarBadOp; Str: AbTarBadOpS) ); function AbStrRes(Index : Integer) : string; var i : Integer; begin for i := Low(AbStrArray) to High(AbStrArray) do if AbStrArray[i].ID = Index then Result := AbStrArray[i].Str; end; end. ================================================ FILE: lib/abbrevia/source/AbCrtl.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Craig Peterson * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbCrtl.pas *} {*********************************************************} {* ABBREVIA: C++Builder C runtime functions *} {*********************************************************} unit AbCrtl; {$I AbDefine.inc} interface uses Windows; type UInt32 = LongWord; size_t = {$IF defined(CPUX64)}Int64{$ELSE}Integer{$IFEND}; // NativeInt is 8 bytes in Delphi 2007 const __turboFloat: LongInt = 0; _fltused: LongInt = 0; procedure abs; cdecl; external 'msvcrt.dll'; procedure _llshl; cdecl; external 'msvcrt.dll'; procedure _llushr; cdecl; external 'msvcrt.dll'; procedure _ftol; cdecl; external 'msvcrt.dll' {$IFDEF BCB}name '__ftol'{$ENDIF}; { ctype.h declarations ===================================================== } function isdigit(ch: Integer): Integer; cdecl; { string.h declarations ==================================================== } function memcpy(Dest, Src: Pointer; Count: size_t): Pointer; cdecl; function memmove(Dest, Src: Pointer; Count: size_t): Pointer; cdecl; function memset(Dest: Pointer; Value: Byte; Count: size_t): Pointer; cdecl; function strlen(P: PAnsiChar): Integer; cdecl; function strcpy(Des, Src: PAnsiChar): PAnsiChar; cdecl; function strncpy(Des, Src: PAnsiChar; MaxLen: Integer): PAnsiChar; cdecl; function memcmp(s1,s2: Pointer; numBytes: LongWord): integer; cdecl; external 'msvcrt.dll'; function wcscpy(strDestination, strSource: PWideChar): PWideChar; cdecl; external 'msvcrt.dll'; { stdlib.h declarations ==================================================== } function malloc(Size: Integer): Pointer; cdecl; procedure free(Ptr: Pointer); cdecl; function realloc(Ptr: Pointer; Size: Integer): Pointer; cdecl; { intrin.h declarations ==================================================== } procedure ___cpuid(CPUInfo: PInteger; InfoType: Integer); cdecl; external 'msvcrt.dll'; { stdio.h declarations ===================================================== } function sprintf(S: PChar; const Format: PChar): Integer; cdecl; varargs; external 'msvcrt.dll' {$IFDEF BCB}name '_sprintf'{$ENDIF}; { process.h declarations =================================================== } function _beginthreadex(security: Pointer; stack_size: Cardinal; start_address: Pointer; arglist: Pointer; initflag: Cardinal; var thrdaddr: Cardinal): THandle; cdecl; { MSVC/Win64 declarations ================================================== } procedure __C_specific_handler; cdecl; external 'msvcrt.dll'; implementation { ctype.h declarations ===================================================== } function isdigit(ch: Integer): Integer; cdecl; begin if AnsiChar(ch) in ['0'..'9'] then Result := 1 else Result := 0; end; { string.h declarations ==================================================== } function memcpy(Dest, Src: Pointer; Count: size_t): Pointer; cdecl; begin System.Move(Src^, Dest^, Count); Result := Dest; end; { -------------------------------------------------------------------------- } function memmove(Dest, Src: Pointer; Count: size_t): Pointer; cdecl; begin System.Move(Src^, Dest^, Count); Result := Dest; end; { -------------------------------------------------------------------------- } function memset(Dest: Pointer; Value: Byte; Count: size_t): Pointer; cdecl; begin FillChar(Dest^, Count, Value); Result := Dest; end; { -------------------------------------------------------------------------- } function strlen(P: PAnsiChar): Integer; cdecl; {$IF RTLVersion >= 20} asm jmp System.@PCharLen end; {$ELSE} begin Result := 0; while P^ <> #0 do Inc(P); end; {$IFEND} { -------------------------------------------------------------------------- } function strcpy(Des, Src: PAnsiChar): PAnsiChar; cdecl; begin Result := Des; Move(Src^, Des^, strlen(Src) + 1); end; { -------------------------------------------------------------------------- } function strncpy(Des, Src: PAnsiChar; MaxLen: Integer): PAnsiChar; cdecl; var Len: Integer; begin Len := strlen(Src); if Len > MaxLen then Len := MaxLen; Move(Src^, Des^, Len); if Len < MaxLen then FillChar(Des[Len], MaxLen - Len, 0); Result := Des; end; { stdlib.h declarations ==================================================== } function malloc(Size: Integer): Pointer; cdecl; begin GetMem(Result, Size); end; { -------------------------------------------------------------------------- } procedure free(Ptr: Pointer); cdecl; begin FreeMem(Ptr) end; { -------------------------------------------------------------------------- } function realloc(Ptr: Pointer; Size: Integer): Pointer; cdecl; begin Result := ReallocMemory(Ptr, Size); end; { process.h declarations =================================================== } function _beginthreadex(security: Pointer; stack_size: Cardinal; start_address: Pointer; arglist: Pointer; initflag: Cardinal; var thrdaddr: Cardinal): THandle; cdecl; begin Result := CreateThread(security, stack_size, start_address, arglist, initflag, thrdaddr); end; { -------------------------------------------------------------------------- } end. ================================================ FILE: lib/abbrevia/source/AbDefine.inc ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbDefine.inc *} {*********************************************************} {* ABBREVIA: Compiler options/directives include file *} {*********************************************************} {NOTE: ABDEFINE.INC is included in all ABBREVIA units; hence you can specify global compiler options here. ABDEFINE.INC is included *before* each unit's own required compiler options, so options specified here could be overridden by hardcoded options in the unit source file.} {====Compiler options that can be changed====} {$A+ Force alignment on word/dword boundaries} {$S- No stack checking} {---Global compiler defines for 32-bit OS's---} {====Global fixed compiler options (do NOT change)====} {$B- Incomplete boolean evaluation} {$H+ Long string support} {$P- No open string parameters} {$Q- Arithmetic overflow checking} {!! - Needs to be turned on!} {$R- Range checking} {!! - Needs to be turned on!} {$T+ No type-checked pointers} {$V- No var string checking} {$X+ Extended syntax} {$Z1 Enumerations are byte sized} {====Platform defines================================================} { map Delphi platform defines to FreePascal's (MSWINDOWS/UNIX/LINUX/DARWIN) } {$IFNDEF FPC} {$IF DEFINED(LINUX) AND (CompilerVersion < 15)} {$DEFINE KYLIX} {$DEFINE UNIX} {$IFEND} {$IFDEF MACOS} {$DEFINE DARWIN} {$ENDIF} {$IFDEF POSIX} {$DEFINE UNIX} {$ENDIF} {$ENDIF} { Unix API (Kylix/Delphi/FreePascal) } {$IFDEF UNIX} {$IF DEFINED(FPC)} {$DEFINE FPCUnixAPI} {$ELSEIF DEFINED(KYLIX)} {$DEFINE LibcAPI} {$ELSE} {$DEFINE PosixAPI} {$IFEND} {$ENDIF} {$IFDEF FPC} {$MODE DELPHI} {$PACKRECORDS C} {$ENDIF} {Activate this define to show CLX/LCL dialogs for spanning media requests. The default behavior will abort the operation instead. This define is only safe when using Abbrevia from the foreground thread. If using it from a background thread override OnRequestLastDisk, OnRequestNthDisk, and OnRequestBlankDisk and synchronize to the foreground yourself. The Windows version always MessageBox so it's thread-safe.} {.$DEFINE UnixDialogs} {====RTL defines=====================================================} {$IFNDEF FPC} {$IF RTLVersion >= 18} // Delphi 2006 {$DEFINE HasAdvancedRecords} {$IFEND} {$IF RTLVersion >= 20} // Delphi 2009 {$DEFINE HasThreadFinished} {$DEFINE HasInline} {$IFEND} {$IF RTLVersion >= 21} // Delphi 2010 {$DEFINE HasThreadStart} {$IFEND} {$IF RTLVersion >= 23} // Delphi XE2 {$DEFINE HasPlatformsAttribute} {$IFEND} {$ENDIF} {====Widgetset defines===============================================} { VCL version specific defines } {$IFNDEF FPC} {$IF RTLVersion >= 17} // Delphi 2005 {$DEFINE HasOnMouseActivate} {$IFEND} {$IF RTLVersion >= 18} // Delphi 2006 {$DEFINE HasOnMouseEnter} {$IFEND} {$IF RTLVersion >= 20} // Delphi 2009 {$DEFINE HasListViewGroups} {$DEFINE HasListViewOnItemChecked} {$DEFINE HasParentDoubleBuffered} {$DEFINE HasTreeViewExpandedImageIndex} {$IFEND} {$IF RTLVersion >= 21} // Delphi 2010 {$DEFINE HasGridDrawingStyle} {$DEFINE HasTouch} {$IFEND} {$IF RTLVersion >= 24} // Delphi XE3 {$DEFINE HasUITypes} {$IFEND} {$IF RTLVersion >= 25} // Delphi XE4 {$DEFINE HasAnsiStrings} {$IFEND} {$ENDIF} {====General defines=================================================} {Activate the following define to include extra code to get rid of all hints and warnings. Parts of ABBREVIA are written in such a way that the hint/warning algorithms of the Delphi compilers are fooled and report things like variables being used before initialisation and so on when in reality the problem does not exist.} {$DEFINE DefeatWarnings} { Disable warnings for explicit string casts } {$IFDEF UNICODE} {$WARN EXPLICIT_STRING_CAST OFF} {$WARN EXPLICIT_STRING_CAST_LOSS OFF} {$ENDIF} { Disable hints on Delphi XE2/Mac to prevent unexpanded inline messages } {$IFDEF POSIX} {$HINTS OFF} {$ENDIF} {====Bzip2 defines===================================================} {Activate this define to statically link bzip2 .obj files into the application. Curerntly only supported by Delphi/Win32.} {.$DEFINE Bzip2Static} {Activate this define to dynamically link to a libbz2.dll/libbbz2.so.1} {.$DEFINE Bzip2Dynamic} {Activate this define to load libbz2.dll/libbz2.so.1 at runtime using LoadLibrary} {.$DEFINE Bzip2Runtime} {Pick an appropriate linking method if none of the above are activate} {$IF NOT DEFINED(Bzip2Static) AND NOT DEFINED(Bzip2Dynamic) AND NOT DEFINED(Bzip2Runtime)} {$IFDEF FPC} {$DEFINE Bzip2Runtime} {$ELSE} {$IFDEF MSWINDOWS} {$DEFINE Bzip2Static} {$ELSE} {$DEFINE Bzip2Dynamic} {$ENDIF} {$ENDIF} {$IFEND} {====Zip defines=====================================================} {Activate the following define when you don't want Visual parts of the VCL library included for a program using a TAbArchive or TAbZipArchive} {.$DEFINE BuildingStub} {Activate the following define to include support for extracting files using PKzip compatible unShrink.} {.$DEFINE UnzipShrinkSupport} {Activate the following define to include support for extracting files using PKZip compatible unReduce.} {.$DEFINE UnzipReduceSupport} {Activate the following define to include support for extracting files using PKZip compatible unImplode.} {.$DEFINE UnzipImplodeSupport} {Activate the following to include support for extracting files using all older PKZip compatible methods (Shrink, Reduce, Implode} {$DEFINE UnzipBackwardSupport} {Activate the following to include support for extracting files using BZIP2 compression. Added in AppNote.txt v4.6. } {.$DEFINE UnzipBzip2Support} {Activate the following to include support for extracting files using 7-zip compatible Lzma compression. Added in AppNote.txt v6.3.} {.$DEFINE UnzipLzmaSupport} {Activate the following to include support for extracting files using zipx PPMd I compression. Added in AppNote.txt v6.3.} {.$DEFINE UnzipPPMdSupport} {Activate the following to include support for extracting .wav files using zipx WavPack compression. Requires copyright notice in your documentation. Check "WavPack License.txt" for details. Added in AppNote.txt v6.3. } {.$DEFINE UnzipWavPackSupport} {Activate the following to include support for extracting files using all newer (zipx) compatible methods (Bzip2, Lzma, PPMd, WavPack)} {$DEFINE UnzipZipxSupport} {Activate the following to include logging support in the deflate/ inflate code. Since this logging support is a by-product of assertion checking, you should only activate it if that is also on: $C+} {$IFOPT C+} //if Assertions are on {.$DEFINE UseLogging} {$ENDIF} { According to http://www.gzip.org/zlib/rfc1952.txt A compliant gzip compressor should calculate and set the CRC32 and ISIZE. However, a compliant decompressor should not check these values. If you want to check the the values of the CRC32 and ISIZE in a GZIP file when decompressing enable the STRICTGZIP define below. } {.$DEFINE STRICTGZIP} { The following define is ONLY used for Abbrevia Unit Tests. It has no effect on the Abbrevia Library. If defined it uses Winzip to create and test archives for compatability. The winzip tests require Systools stSpawn.pas It can be downloaded at http://sf.net/projects/tpsystools } {$IFDEF MSWINDOWS} {.$DEFINE WINZIPTESTS} {$ENDIF} {-------- !! DO NOT CHANGE DEFINES BELOW THIS LINE !! --------} {$IFDEF UnzipBackwardSupport} {$DEFINE UnzipShrinkSupport} {$DEFINE UnzipReduceSupport} {$DEFINE UnzipImplodeSupport} {$ENDIF} {$IFDEF UnzipZipxSupport} {$DEFINE UnzipBzip2Support} {$DEFINE UnzipLzmaSupport} {$DEFINE UnzipPPMdSupport} {$DEFINE UnzipWavPackSupport} {$ENDIF} { Linking .obj files isn't currently supported in Kylix or FPC } {$IF DEFINED(FPC) OR NOT DEFINED(MSWINDOWS)} {$UNDEF UnzipLzmaSupport} {$UNDEF UnzipPPMdSupport} {$UNDEF UnzipWavPackSupport} {$IFEND} ================================================ FILE: lib/abbrevia/source/AbDfBase.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbDfBase.pas *} {*********************************************************} {* Deflate base unit *} {*********************************************************} unit AbDfBase; {$I AbDefine.inc} interface uses SysUtils, Classes; type PAbDfLongintList = ^TAbDfLongintList; TAbDfLongintList = array [0..pred(MaxInt div sizeof(longint))] of longint; const dfc_CodeLenCodeLength = 7; dfc_LitDistCodeLength = 15; dfc_MaxCodeLength = 15; const dfc_MaxMatchLen = 258; {lengths are 3..258 for deflate} dfc_MaxMatchLen64 = 64 * 1024; {lengths are 3..65536 for deflate64} const dfc_LitExtraOffset = 257; dfc_LitExtraBits : array [0..30] of byte = (0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 16, 99, 99); { note: the last two are required to avoid going beyond the end} { of the array when generating static trees} dfc_DistExtraOffset = 0; dfc_DistExtraBits : array [0..31] of byte = (0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14); { note: the last two are only use for deflate64} dfc_LengthBase : array [0..28] of word = (3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 3); { note: the final 3 is correct for deflate64; for symbol 285,} { lengths are stored as (length - 3)} { for deflate it's very wrong, but there's special code in} { the (de)compression code to cater for this} dfc_DistanceBase : array [0..31] of word = (1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 32769, 49153); dfc_CodeLengthIndex : array [0..18] of byte = (16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15); const dfc_CanUseStored = $01; dfc_CanUseStatic = $02; dfc_CanUseDynamic = $04; dfc_UseLazyMatch = $08; dfc_UseDeflate64 = $10; dfc_UseAdler32 = $20; dfc_CanUseHuffman = dfc_CanUseStatic or dfc_CanUseDynamic; dfc_TestOnly = $40000000; type TAbProgressStep = procedure (aPercentDone : integer) of object; {-progress metering of deflate/inflate; abort with AbortProgress} TAbDeflateHelper = class private FAmpleLength : longint; FChainLength : longint; FLogFile : string; FMaxLazy : longint; FOnProgressStep : TAbProgressStep; FOptions : longint; FPartSize : Int64; FSizeCompressed : Int64; FSizeNormal : Int64; FStreamSize : Int64; FWindowSize : longint; FZipOption : AnsiChar; protected procedure dhSetAmpleLength(aValue : longint); procedure dhSetChainLength(aValue : longint); procedure dhSetLogFile(const aValue : string); procedure dhSetMaxLazy(aValue : longint); procedure dhSetOnProgressStep(aValue : TAbProgressStep); procedure dhSetOptions(aValue : longint); procedure dhSetWindowSize(aValue : longint); procedure dhSetZipOption(aValue : AnsiChar); public constructor Create; procedure Assign(aHelper : TAbDeflateHelper); property AmpleLength : longint read FAmpleLength write dhSetAmpleLength; property ChainLength : longint read FChainLength write dhSetChainLength; property LogFile : string read FLogFile write dhSetLogFile; property MaxLazyLength : longint read FMaxLazy write dhSetMaxLazy; property Options : longint read FOptions write dhSetOptions; property PartialSize : Int64 read FPartSize write FPartSize; property PKZipOption : AnsiChar read FZipOption write dhSetZipOption; property StreamSize : Int64 read FStreamSize write FStreamSize; property WindowSize : longint read FWindowSize write dhSetWindowSize; property CompressedSize : Int64 read FSizeCompressed write FSizeCompressed; property NormalSize : Int64 read FSizeNormal write FSizeNormal; property OnProgressStep : TAbProgressStep read FOnProgressStep write dhSetOnProgressStep; end; type TAbLineDelimiter = (ldCRLF, ldLF); TAbLogger = class(TStream) private FBuffer : PAnsiChar; FCurPos : PAnsiChar; FLineDelim : TAbLineDelimiter; FStream : TFileStream; protected function logWriteBuffer : boolean; public constructor Create(const aLogName : string); destructor Destroy; override; function Read(var Buffer; Count : longint) : longint; override; function Seek(const Offset : Int64; Origin : TSeekOrigin) : Int64; override; function Write(const Buffer; Count : longint) : longint; override; procedure WriteLine(const S : string); procedure WriteStr(const S : string); property LineDelimiter : TAbLineDelimiter read FLineDelim write FLineDelim; end; type TAbNodeManager = class private FFreeList : pointer; FNodeSize : cardinal; FNodesPerPage : cardinal; FPageHead : pointer; FPageSize : cardinal; protected function nmAllocNewPage : pointer; public constructor Create(aNodeSize : cardinal); destructor Destroy; override; function AllocNode : pointer; function AllocNodeClear : pointer; procedure FreeNode(aNode : pointer); end; {---exception classes---} type EAbAbortProgress = class(Exception); EAbPartSizedInflate = class(Exception); EAbInflatePasswordError = class(Exception); EAbInternalInflateError = class(Exception); EAbInflateError = class(Exception) public constructor Create(const aMsg : string); constructor CreateUnknown(const aMsg : string; const aErrorMsg : string); end; EAbInternalDeflateError = class(Exception); EAbDeflateError = class(Exception) public constructor Create(const aMsg : string); constructor CreateUnknown(const aMsg : string; const aErrorMsg : string); end; {---aborting a process---} procedure AbortProgress; {---calculation of checksums---} procedure AbUpdateAdlerBuffer(var aAdler : longint; var aBuffer; aCount : integer); procedure AbUpdateCRCBuffer(var aCRC : longint; var aBuffer; aCount : integer); implementation uses AbUtils; {===TAbDeflateHelper=================================================} constructor TAbDeflateHelper.Create; begin inherited Create; FAmpleLength := 8; FChainLength := 32; {FLogFile := '';} FMaxLazy := 16; {FOnProgressStep := nil;} FOptions := $F; {FStreamSize := 0;} FWindowSize := 32 * 1024; FZipOption := 'n'; end; {--------} procedure TAbDeflateHelper.Assign(aHelper : TAbDeflateHelper); begin FAmpleLength := aHelper.FAmpleLength; FChainLength := aHelper.FChainLength; FLogFile := aHelper.FLogFile; FMaxLazy := aHelper.FMaxLazy; FOnProgressStep := aHelper.FOnProgressStep; FOptions := aHelper.FOptions; FPartSize := aHelper.FPartSize; FStreamSize := aHelper.FStreamSize; FWindowSize := aHelper.FWindowSize; FZipOption := aHelper.FZipOption; end; {--------} procedure TAbDeflateHelper.dhSetAmpleLength(aValue : longint); begin if (aValue <> AmpleLength) then begin if (aValue <> -1) and (aValue < 4) then aValue := 4; FAmpleLength := aValue; FZipOption := '?'; end; end; {--------} procedure TAbDeflateHelper.dhSetChainLength(aValue : longint); begin if (aValue <> ChainLength) then begin if (aValue <> -1) and (aValue < 4) then aValue := 4; FChainLength := aValue; FZipOption := '?'; end; end; {--------} procedure TAbDeflateHelper.dhSetLogFile(const aValue : string); begin FLogFile := aValue; end; {--------} procedure TAbDeflateHelper.dhSetMaxLazy(aValue : longint); begin if (aValue <> MaxLazyLength) then begin if (aValue <> -1) and (aValue < 4) then aValue := 4; FMaxLazy := aValue; FZipOption := '?'; end; end; {--------} procedure TAbDeflateHelper.dhSetOnProgressStep(aValue : TAbProgressStep); begin FOnProgressStep := aValue; end; {--------} procedure TAbDeflateHelper.dhSetOptions(aValue : longint); begin if (aValue <> Options) then begin FOptions := aValue; FZipOption := '?'; end; end; {--------} procedure TAbDeflateHelper.dhSetWindowSize(aValue : longint); var NewValue : longint; begin if (aValue <> WindowSize) then begin {calculate the window size rounded to nearest 1024 bytes} NewValue := ((aValue + 1023) div 1024) * 1024; {if the new window size is greater than 32KB...} if (NewValue > 32 * 1024) then {if the Deflate64 option is set, force to 64KB} if ((Options and dfc_UseDeflate64) <> 0) then NewValue := 64 * 1024 {otherwise, force to 32KB} else NewValue := 32 * 1024; {set the new window size} FWindowSize := NewValue; end; end; {--------} procedure TAbDeflateHelper.dhSetZipOption(aValue : AnsiChar); begin {notes: The original Abbrevia code used the following table for setting the equivalent values: Good Lazy Chain UseLazy Option 4 4 4 N s ^ 4 5 8 N | 4 6 32 N f faster 4 4 16 Y slower 8 16 32 Y n | 8 16 128 Y | 8 32 256 Y | 32 128 1024 Y | 32 258 4096 Y x V The new Abbrevia 3 code follows these values to a certain extent. } {force to lower case} if ('A' <= aValue) and (aValue <= 'Z') then aValue := AnsiChar(ord(aValue) + ord('a') - ord('A')); {if the value has changed...} if (aValue <> PKZipOption) then begin {switch on the new value...} case aValue of '0' : {no compression} begin FZipOption := aValue; FOptions := (FOptions and (not $0F)) or dfc_CanUseStored; FAmpleLength := 8; { not actually needed} FChainLength := 32; { not actually needed} FMaxLazy := 16; { not actually needed} end; '2' : {hidden option: Abbrevia 2 compatibility} begin FZipOption := aValue; FOptions := FOptions or $0F; FAmpleLength := 8; FChainLength := 32; FMaxLazy := 16; end; 'f' : {fast compression} begin FZipOption := aValue; FOptions := FOptions or $07; { no lazy matching} FAmpleLength := 4; FChainLength := 32; FMaxLazy := 6; end; 'n' : {normal compression} begin FZipOption := aValue; FOptions := FOptions or $0F; FAmpleLength := 16; FChainLength := 32; FMaxLazy := 24; end; 's' : {super fast compression} begin FZipOption := aValue; FOptions := FOptions or $07; { no lazy matching} FAmpleLength := 4; FChainLength := 4; FMaxLazy := 4; end; 'x' : {maximum compression} begin FZipOption := aValue; FOptions := FOptions or $0F; FAmpleLength := 64;{32;} FChainLength := 4096; FMaxLazy := 258; end; end; end; end; {====================================================================} {===TAbLogger========================================================} const LogBufferSize = 4096; {--------} constructor TAbLogger.Create(const aLogName : string); begin Assert(aLogName <> '', 'TAbLogger.Create: a filename must be provided for the logger'); {create the ancestor} inherited Create; {set the default line terminator} {$IFDEF MSWINDOWS} FLineDelim := ldCRLF; {$ENDIF} {$IFDEF UNIX} FLineDelim := ldLF; {$ENDIF} {create and initialize the buffer} GetMem(FBuffer, LogBufferSize); FCurPos := FBuffer; {create the log file} FStream := TFileStream.Create(aLogName, fmCreate); end; {--------} destructor TAbLogger.Destroy; begin {if there is a buffer ensure that it is flushed before freeing it} if (FBuffer <> nil) then begin if (FCurPos <> FBuffer) then logWriteBuffer; FreeMem(FBuffer, LogBufferSize); end; {free the stream} FStream.Free; {destroy the ancestor} inherited Destroy; end; {--------} function TAbLogger.logWriteBuffer : boolean; var BytesToWrite : longint; BytesWritten : longint; begin BytesToWrite := FCurPos - FBuffer; BytesWritten := FStream.Write(FBuffer^, BytesToWrite); if (BytesWritten = BytesToWrite) then begin Result := true; FCurPos := FBuffer; end else begin Result := false; if (BytesWritten <> 0) then begin Move(FBuffer[BytesWritten], FBuffer^, BytesToWrite - BytesWritten); FCurPos := FBuffer + (BytesToWrite - BytesWritten); end; end; end; {--------} function TAbLogger.Read(var Buffer; Count : longint) : longint; begin Assert(false, 'TAbLogger.Read: loggers are write-only, no reading allowed'); Result := 0; end; {--------} function TAbLogger.Seek(const Offset : Int64; Origin : TSeekOrigin) : Int64; begin case Origin of soBeginning : begin end; soCurrent : if (Offset = 0) then begin Result := FStream.Position + (FCurPos - FBuffer); Exit; end; soEnd : if (Offset = 0) then begin Result := FStream.Position + (FCurPos - FBuffer); Exit; end; end; Assert(false, 'TAbLogger.Seek: loggers are write-only, no seeking allowed'); Result := 0; end; {--------} function TAbLogger.Write(const Buffer; Count : longint) : longint; var UserBuf : PAnsiChar; BytesToGo : longint; BytesToWrite : longint; begin {reference the user's buffer as a PChar} UserBuf := @Buffer; {start the counter for the number of bytes written} Result := 0; {if needed, empty the internal buffer into the underlying stream} if (LogBufferSize = FCurPos - FBuffer) then if not logWriteBuffer then Exit; {calculate the number of bytes to copy this time from the user's buffer to the internal buffer} BytesToGo := Count; BytesToWrite := LogBufferSize - (FCurPos - FBuffer); if (BytesToWrite > BytesToGo) then BytesToWrite := BytesToGo; {copy the bytes} Move(UserBuf^, FCurPos^, BytesToWrite); {adjust the counters} inc(FCurPos, BytesToWrite); dec(BytesToGo, BytesToWrite); inc(Result, BytesToWrite); {while there are still more bytes to copy, do so} while (BytesToGo <> 0) do begin {advance the user's buffer} inc(UserBuf, BytesToWrite); {empty the internal buffer into the underlying stream} if not logWriteBuffer then Exit; {calculate the number of bytes to copy this time from the user's buffer to the internal buffer} BytesToWrite := LogBufferSize; if (BytesToWrite > BytesToGo) then BytesToWrite := BytesToGo; {copy the bytes} Move(UserBuf^, FCurPos^, BytesToWrite); {adjust the counters} inc(FCurPos, BytesToWrite); dec(BytesToGo, BytesToWrite); inc(Result, BytesToWrite); end; end; {--------} procedure TAbLogger.WriteLine(const S : string); const cLF : AnsiChar = ^J; cCRLF : array [0..1] of AnsiChar = ^M^J; begin if (length(S) > 0) then Write(S[1], length(S)); case FLineDelim of ldLF : Write(cLF, sizeof(cLF)); ldCRLF : Write(cCRLF, sizeof(cCRLF)); end; end; {--------} procedure TAbLogger.WriteStr(const S : string); begin if (length(S) > 0) then Write(S[1], length(S)); end; {====================================================================} {===Calculate checksums==============================================} procedure AbUpdateAdlerBuffer(var aAdler : longint; var aBuffer; aCount : integer); var S1 : LongWord; S2 : LongWord; i : integer; Buffer : PAnsiChar; BytesToUse : integer; begin {Note: this algorithm will *only* work if the buffer is 4KB or less, which is why we go to such lengths to chop up the user buffer into usable chunks of 4KB. However, for Delphi 3 there is no proper 32-bit longword. Although the additions pose no problems in this situation, the mod operations below (especially for S2) will be signed integer divisions, producing an (invalid) signed result. In this case, the buffer is chopped up into 2KB chunks to avoid any signed problems.} {split the current Adler checksum into its halves} S1 := LongWord(aAdler) and $FFFF; S2 := LongWord(aAdler) shr 16; {reference the user buffer as a PChar: it makes it easier} Buffer := @aBuffer; {while there's still data to checksum...} while (aCount <> 0) do begin {calculate the number of bytes to checksum this time} {$IFDEF HasLongWord} BytesToUse := 4096; {$ELSE} BytesToUse := 2048; {$ENDIF} if (BytesToUse > aCount) then BytesToUse := aCount; {checksum the bytes} for i := 0 to pred(BytesToUse) do begin inc(S1, ord(Buffer^)); inc(S2, S1); inc(Buffer); end; {recalibrate the Adler checksum halves} S1 := S1 mod 65521; S2 := S2 mod 65521; {calculate the number of bytes still to go} dec(aCount, BytesToUse); end; {join the halves to produce the complete Adler checksum} aAdler := longint((S2 shl 16) or S1); end; {--------} procedure AbUpdateCRCBuffer(var aCRC : longint; var aBuffer; aCount : integer); var i : integer; CRC : LongWord; Buffer : PAnsiChar; begin {$R-}{$Q-} {reference the user buffer as a PChar: it makes it easier} Buffer := @aBuffer; {get the current CRC as a local variable, it's faster} CRC := aCRC; {checksum the bytes in the buffer} for i := 0 to pred(aCount) do begin CRC := AbCrc32Table[byte(CRC) xor byte(Buffer^)] xor (CRC shr 8); inc(Buffer); end; {return the new CRC} aCRC := CRC; {$R+}{$Q+} end; {====================================================================} {===EAbInflateError==================================================} constructor EAbInflateError.Create(const aMsg : string); begin inherited Create( 'Abbrevia inflate error, possibly a corrupted compressed stream. ' + '(Internal cause: ' + aMsg + ')'); end; {--------} constructor EAbInflateError.CreateUnknown(const aMsg : string; const aErrorMsg : string); begin inherited Create(aMsg + ': ' + aErrorMsg); end; {====================================================================} {===EAbDeflateError==================================================} constructor EAbDeflateError.Create(const aMsg : string); begin inherited Create( 'Abbrevia deflate error. ' + '(Internal cause: ' + aMsg + ')'); end; {--------} constructor EAbDeflateError.CreateUnknown(const aMsg : string; const aErrorMsg : string); begin inherited Create(aMsg + ': ' + aErrorMsg); end; {====================================================================} {===Node manager=====================================================} const PageSize = 8 * 1024; type PGenericNode = ^TGenericNode; TGenericNode = packed record gnNext : PGenericNode; gnData : record end; end; {--------} constructor TAbNodeManager.Create(aNodeSize : cardinal); const Gran = sizeof(pointer); Mask = not (Gran - 1); begin {create the ancestor} inherited Create; {save the node size rounded to nearest 4 bytes} if (aNodeSize <= sizeof(pointer)) then aNodeSize := sizeof(pointer) else aNodeSize := (aNodeSize + Gran - 1) and Mask; FNodeSize := aNodeSize; {calculate the page size (default 1024 bytes) and the number of nodes per page; if the default page size is not large enough for two or more nodes, force a single node per page} FNodesPerPage := (PageSize - sizeof(pointer)) div aNodeSize; if (FNodesPerPage > 1) then FPageSize := PageSize else begin FNodesPerPage := 1; FPagesize := aNodeSize + sizeof(pointer); end; end; {--------} destructor TAbNodeManager.Destroy; var Temp : pointer; begin {dispose of all the pages, if there are any} while (FPageHead <> nil) do begin Temp := PGenericNode(FPageHead)^.gnNext; FreeMem(FPageHead, FPageSize); FPageHead := Temp; end; {destroy the ancestor} inherited Destroy; end; {--------} function TAbNodeManager.AllocNode : pointer; begin Result := FFreeList; if (Result = nil) then Result := nmAllocNewPage else FFreeList := PGenericNode(Result)^.gnNext; end; {--------} function TAbNodeManager.AllocNodeClear : pointer; begin Result := FFreeList; if (Result = nil) then Result := nmAllocNewPage else FFreeList := PGenericNode(Result)^.gnNext; FillChar(Result^, FNodeSize, 0); end; {--------} procedure TAbNodeManager.FreeNode(aNode : pointer); begin {add the node (if non-nil) to the top of the free list} if (aNode <> nil) then begin PGenericNode(aNode)^.gnNext := FFreeList; FFreeList := aNode; end; end; {--------} function TAbNodeManager.nmAllocNewPage : pointer; var NewPage : PAnsiChar; i : integer; FreeList : pointer; NodeSize : integer; begin {allocate a new page and add it to the front of the page list} GetMem(NewPage, FPageSize); PGenericNode(NewPage)^.gnNext := FPageHead; FPageHead := NewPage; {now split up the new page into nodes and push them all onto the free list; note that the first 4 bytes of the page is a pointer to the next page, so remember to skip over it} inc(NewPage, sizeof(pointer)); FreeList := FFreeList; NodeSize := FNodeSize; for i := 0 to pred(FNodesPerPage) do begin PGenericNode(NewPage)^.gnNext := FreeList; FreeList := NewPage; inc(NewPage, NodeSize); end; {return the top of the list} Result := FreeList; FFreeList := PGenericNode(Result)^.gnNext; end; {====================================================================} {====================================================================} procedure AbortProgress; begin raise EAbAbortProgress.Create('Abort'); end; {====================================================================} end. ================================================ FILE: lib/abbrevia/source/AbDfCryS.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbDfCryS.pas *} {*********************************************************} {* Deflate encryption streams *} {*********************************************************} unit AbDfCryS; {$I AbDefine.inc} interface uses Classes; type TAbZipEncryptHeader = array [0..11] of byte; TAbZipDecryptEngine = class private FReady : boolean; FState : array [0..2] of longint; protected procedure zdeInitState(const aPassphrase : AnsiString); public constructor Create; function Decode(aCh : byte) : byte; {-decodes a byte} procedure DecodeBuffer(var aBuffer; aCount : integer); {-decodes a buffer} function VerifyHeader(const aHeader : TAbZipEncryptHeader; const aPassphrase : AnsiString; aCheckValue : longint) : boolean; {-validate an encryption header} end; TAbDfDecryptStream = class(TStream) private FCheckValue : longint; FEngine : TAbZipDecryptEngine; FOwnsStream : Boolean; FPassphrase : AnsiString; FReady : boolean; FStream : TStream; protected public constructor Create(aStream : TStream; aCheckValue : longint; const aPassphrase : AnsiString); destructor Destroy; override; function IsValid : boolean; function Read(var aBuffer; aCount : longint) : longint; override; function Seek(aOffset : longint; aOrigin : word) : longint; override; function Write(const aBuffer; aCount : longint) : longint; override; property OwnsStream : Boolean read FOwnsStream write FOwnsStream; end; TAbZipEncryptEngine = class private FReady : boolean; FState : array [0..2] of longint; protected procedure zeeInitState(const aPassphrase : AnsiString); public constructor Create; function Encode(aCh : byte) : byte; {-encodes a byte} procedure EncodeBuffer(var aBuffer; aCount : integer); {-encodes a buffer} procedure CreateHeader(var aHeader : TAbZipEncryptHeader; const aPassphrase : AnsiString; aCheckValue : longint); {-generate an encryption header} end; TAbDfEncryptStream = class(TStream) private FBuffer : PAnsiChar; FBufSize : integer; FEngine : TAbZipEncryptEngine; FStream : TStream; protected public constructor Create(aStream : TStream; aCheckValue : longint; const aPassphrase : AnsiString); destructor Destroy; override; function Read(var aBuffer; aCount : longint) : longint; override; function Seek(aOffset : longint; aOrigin : word) : longint; override; function Write(const aBuffer; aCount : longint) : longint; override; end; implementation {Notes: the ZIP spec defines a couple of primitive routines for performing encryption. For speed Abbrevia inlines them into the respective methods of the encryption/decryption engines char crc32(long,char) return updated CRC from current CRC and next char update_keys(char): Key(0) <- crc32(key(0),char) Key(1) <- Key(1) + (Key(0) & 000000ffH) Key(1) <- Key(1) * 134775813 + 1 Key(2) <- crc32(key(2),key(1) >> 24) end update_keys char decrypt_byte() local unsigned short temp temp <- Key(2) | 2 decrypt_byte <- (temp * (temp ^ 1)) >> 8 end decrypt_byte } uses AbUtils; {---magic numbers from ZIP spec---} const StateInit1 = 305419896; StateInit2 = 591751049; StateInit3 = 878082192; MagicNumber = 134775813; {===internal encryption class========================================} constructor TAbZipDecryptEngine.Create; begin {create the ancestor} inherited Create; {we're not ready for decryption yet since a header hasn't been properly verified with VerifyHeader} FReady := false; end; {--------} function TAbZipDecryptEngine.Decode(aCh : byte) : byte; var Temp : longint; begin {check for programming error} Assert(FReady, 'TAbZipDecryptEngine.Decode: must successfully call VerifyHeader first'); {calculate the decoded byte (uses inlined decrypt_byte)} Temp := (FState[2] and $FFFF) or 2; Result := aCh xor ((Temp * (Temp xor 1)) shr 8); {mix the decoded byte into the state (uses inlined update_keys)} FState[0] := AbUpdateCrc32(Result, FState[0]); FState[1] := FState[1] + (FState[0] and $FF); FState[1] := (FState[1] * MagicNumber) + 1; FState[2] := AbUpdateCrc32(FState[1] shr 24, FState[2]); end; {--------} procedure TAbZipDecryptEngine.DecodeBuffer(var aBuffer; aCount : integer); var i : integer; Temp : longint; Buffer : PAnsiChar; WorkState : array [0..2] of longint; begin {check for programming error} Assert(FReady, 'TAbZipDecryptEngine.Decode: must successfully call VerifyHeader first'); {move the state to a local variable--for better speed} WorkState[0] := FState[0]; WorkState[1] := FState[1]; WorkState[2] := FState[2]; {reference the buffer as a PChar--easier arithmetic} Buffer := @aBuffer; {for each byte in the buffer...} for i := 0 to pred(aCount) do begin {calculate the next decoded byte (uses inlined decrypt_byte)} Temp := (WorkState[2] and $FFFF) or 2; Buffer^ := AnsiChar( byte(Buffer^) xor ((Temp * (Temp xor 1)) shr 8)); {mix the decoded byte into the state (uses inlined update_keys)} WorkState[0] := AbUpdateCrc32(byte(Buffer^), WorkState[0]); WorkState[1] := WorkState[1] + (WorkState[0] and $FF); WorkState[1] := (WorkState[1] * MagicNumber) + 1; WorkState[2] := AbUpdateCrc32(WorkState[1] shr 24, WorkState[2]); {move onto the next byte} inc(Buffer); end; {save the state} FState[0] := WorkState[0]; FState[1] := WorkState[1]; FState[2] := WorkState[2]; end; {--------} function TAbZipDecryptEngine.VerifyHeader(const aHeader : TAbZipEncryptHeader; const aPassphrase : AnsiString; aCheckValue : longint) : boolean; type TLongAsBytes = packed record L1, L2, L3, L4 : byte end; var i : integer; Temp : longint; WorkHeader : TAbZipEncryptHeader; begin {check for programming errors} Assert(aPassphrase <> '', 'TAbZipDecryptEngine.VerifyHeader: need a passphrase'); {initialize the decryption state} zdeInitState(aPassphrase); {decrypt the bytes in the header} for i := 0 to 11 do begin {calculate the next decoded byte (uses inlined decrypt_byte)} Temp := (FState[2] and $FFFF) or 2; WorkHeader[i] := aHeader[i] xor ((Temp * (Temp xor 1)) shr 8); {mix the decoded byte into the state (uses inlined update_keys)} FState[0] := AbUpdateCrc32(WorkHeader[i], FState[0]); FState[1] := FState[1] + (FState[0] and $FF); FState[1] := (FState[1] * MagicNumber) + 1; FState[2] := AbUpdateCrc32(FState[1] shr 24, FState[2]); end; {the header is valid if the twelfth byte of the decrypted header equals the fourth byte of the check value} Result := WorkHeader[11] = TLongAsBytes(aCheckValue).L4; {note: zips created with PKZIP prior to version 2.0 also checked that the tenth byte of the decrypted header equals the third byte of the check value} FReady := Result; end; {--------} procedure TAbZipDecryptEngine.zdeInitState(const aPassphrase : AnsiString); var i : integer; begin {initialize the decryption state} FState[0] := StateInit1; FState[1] := StateInit2; FState[2] := StateInit3; {mix in the passphrase to the state (uses inlined update_keys)} for i := 1 to length(aPassphrase) do begin FState[0] := AbUpdateCrc32(byte(aPassphrase[i]), FState[0]); FState[1] := FState[1] + (FState[0] and $FF); FState[1] := (FState[1] * MagicNumber) + 1; FState[2] := AbUpdateCrc32(FState[1] shr 24, FState[2]); end; end; {====================================================================} {====================================================================} constructor TAbDfDecryptStream.Create(aStream : TStream; aCheckValue : longint; const aPassphrase : AnsiString); begin {create the ancestor} inherited Create; {save the parameters} FStream := aStream; FCheckValue := aCheckValue; FPassphrase := aPassphrase; {create the decryption engine} FEngine := TAbZipDecryptEngine.Create; end; {--------} destructor TAbDfDecryptStream.Destroy; {new !!.02} begin FEngine.Free; if FOwnsStream then FStream.Free; inherited Destroy; end; {--------} function TAbDfDecryptStream.IsValid : boolean; var Header : TAbZipEncryptHeader; begin {read the header from the stream} FStream.ReadBuffer(Header, sizeof(Header)); {check to see if the decryption engine agrees it's valid} Result := FEngine.VerifyHeader(Header, FPassphrase, FCheckValue); {if it isn't valid, reposition the stream, ready for the next try} if not Result then begin FStream.Seek(-sizeof(Header), soCurrent); FReady := false; end {otherwise, the stream is ready for decrypting data} else FReady := true; end; {--------} function TAbDfDecryptStream.Read(var aBuffer; aCount : longint) : longint; begin {check for programming error} Assert(FReady, 'TAbDfDecryptStream.Read: the stream header has not been verified'); {read the data from the underlying stream} Result := FStream.Read(aBuffer, aCount); {decrypt the data} FEngine.DecodeBuffer(aBuffer, Result); end; {--------} function TAbDfDecryptStream.Seek(aOffset : longint; aOrigin : word) : longint; begin Result := FStream.Seek(aOffset, aOrigin); end; {--------} function TAbDfDecryptStream.Write(const aBuffer; aCount : longint) : longint; begin {check for programming error} Assert(false, 'TAbDfDecryptStream.Write: the stream is read-only'); Result := 0; end; {====================================================================} {===TAbZipEncryptEngine==============================================} constructor TAbZipEncryptEngine.Create; begin {create the ancestor} inherited Create; {we're not ready for encryption yet since a header hasn't been properly generated with CreateHeader} FReady := false; end; {--------} procedure TAbZipEncryptEngine.CreateHeader( var aHeader : TAbZipEncryptHeader; const aPassphrase : AnsiString; aCheckValue : longint); type TLongAsBytes = packed record L1, L2, L3, L4 : byte end; var Ch : byte; i : integer; Temp : longint; WorkHeader : TAbZipEncryptHeader; begin {check for programming errors} Assert(aPassphrase <> '', 'TAbZipEncryptEngine.CreateHeader: need a passphrase'); {set the first ten bytes of the header with random values (in fact, we use a random value for each byte and mix it in with the state)} {initialize the decryption state} zeeInitState(aPassphrase); {for the first ten bytes...} for i := 0 to 9 do begin {get a random value} Ch := Random( 256 ); {calculate the XOR encoding byte (uses inlined decrypt_byte)} Temp := (FState[2] and $FFFF) or 2; Temp := (Temp * (Temp xor 1)) shr 8; {mix the unencoded byte into the state (uses inlined update_keys)} FState[0] := AbUpdateCrc32(Ch, FState[0]); FState[1] := FState[1] + (FState[0] and $FF); FState[1] := (FState[1] * MagicNumber) + 1; FState[2] := AbUpdateCrc32(FState[1] shr 24, FState[2]); {set the current byte of the header} WorkHeader[i] := Ch xor Temp; end; {now encrypt the first ten bytes of the header (this merely sets up the state so that we can encrypt the last two bytes)} {reinitialize the decryption state} zeeInitState(aPassphrase); {for the first ten bytes...} for i := 0 to 9 do begin {calculate the XOR encoding byte (uses inlined decrypt_byte)} Temp := (FState[2] and $FFFF) or 2; Temp := (Temp * (Temp xor 1)) shr 8; {mix the unencoded byte into the state (uses inlined update_keys)} FState[0] := AbUpdateCrc32(WorkHeader[i], FState[0]); FState[1] := FState[1] + (FState[0] and $FF); FState[1] := (FState[1] * MagicNumber) + 1; FState[2] := AbUpdateCrc32(FState[1] shr 24, FState[2]); {set the current byte of the header} WorkHeader[i] := WorkHeader[i] xor Temp; end; {now initialize byte 10 of the header, and encrypt it} Ch := TLongAsBytes(aCheckValue).L3; Temp := (FState[2] and $FFFF) or 2; Temp := (Temp * (Temp xor 1)) shr 8; FState[0] := AbUpdateCrc32(Ch, FState[0]); FState[1] := FState[1] + (FState[0] and $FF); FState[1] := (FState[1] * MagicNumber) + 1; FState[2] := AbUpdateCrc32(FState[1] shr 24, FState[2]); WorkHeader[10] := Ch xor Temp; {now initialize byte 11 of the header, and encrypt it} Ch := TLongAsBytes(aCheckValue).L4; Temp := (FState[2] and $FFFF) or 2; Temp := (Temp * (Temp xor 1)) shr 8; FState[0] := AbUpdateCrc32(Ch, FState[0]); FState[1] := FState[1] + (FState[0] and $FF); FState[1] := (FState[1] * MagicNumber) + 1; FState[2] := AbUpdateCrc32(FState[1] shr 24, FState[2]); WorkHeader[11] := Ch xor Temp; {we're now ready to encrypt} FReady := true; {return the header} aHeader := WorkHeader; end; {--------} function TAbZipEncryptEngine.Encode(aCh : byte) : byte; var Temp : longint; begin {check for programming error} Assert(FReady, 'TAbZipEncryptEngine.Encode: must call CreateHeader first'); {calculate the encoded byte (uses inlined decrypt_byte)} Temp := (FState[2] and $FFFF) or 2; Result := aCh xor (Temp * (Temp xor 1)) shr 8; {mix the unencoded byte into the state (uses inlined update_keys)} FState[0] := AbUpdateCrc32(aCh, FState[0]); FState[1] := FState[1] + (FState[0] and $FF); FState[1] := (FState[1] * MagicNumber) + 1; FState[2] := AbUpdateCrc32(FState[1] shr 24, FState[2]); end; {--------} procedure TAbZipEncryptEngine.EncodeBuffer(var aBuffer; aCount : integer); var Ch : byte; i : integer; Temp : longint; Buffer : PAnsiChar; WorkState : array [0..2] of longint; begin {check for programming error} Assert(FReady, 'TAbZipEncryptEngine.EncodeBuffer: must call CreateHeader first'); {move the state to a local variable--for better speed} WorkState[0] := FState[0]; WorkState[1] := FState[1]; WorkState[2] := FState[2]; {reference the buffer as a PChar--easier arithmetic} Buffer := @aBuffer; {for each byte in the buffer...} for i := 0 to pred(aCount) do begin {calculate the next encoded byte (uses inlined decrypt_byte)} Temp := (WorkState[2] and $FFFF) or 2; Ch := byte(Buffer^); Buffer^ := AnsiChar(Ch xor ((Temp * (Temp xor 1)) shr 8)); {mix the decoded byte into the state (uses inlined update_keys)} WorkState[0] := AbUpdateCrc32(Ch, WorkState[0]); WorkState[1] := WorkState[1] + (WorkState[0] and $FF); WorkState[1] := (WorkState[1] * MagicNumber) + 1; WorkState[2] := AbUpdateCrc32(WorkState[1] shr 24, WorkState[2]); {move onto the next byte} inc(Buffer); end; {save the state} FState[0] := WorkState[0]; FState[1] := WorkState[1]; FState[2] := WorkState[2]; end; {--------} procedure TAbZipEncryptEngine.zeeInitState(const aPassphrase : AnsiString); var i : integer; begin {initialize the decryption state} FState[0] := StateInit1; FState[1] := StateInit2; FState[2] := StateInit3; {mix in the passphrase to the state (uses inlined update_keys)} for i := 1 to length(aPassphrase) do begin FState[0] := AbUpdateCrc32(byte(aPassphrase[i]), FState[0]); FState[1] := FState[1] + (FState[0] and $FF); FState[1] := (FState[1] * MagicNumber) + 1; FState[2] := AbUpdateCrc32(FState[1] shr 24, FState[2]); end; end; {====================================================================} {===TAbDfEncryptStream===============================================} constructor TAbDfEncryptStream.Create(aStream : TStream; aCheckValue : longint; const aPassphrase : AnsiString); var Header : TAbZipEncryptHeader; begin {create the ancestor} inherited Create; {save the stream parameter} FStream := aStream; {create the encryption engine} FEngine := TAbZipEncryptEngine.Create; {generate the encryption header, write it to the stream} FEngine.CreateHeader(Header, aPassphrase, aCheckValue); aStream.WriteBuffer(Header, sizeof(Header)); end; {--------} destructor TAbDfEncryptStream.Destroy; begin {free the internal buffer if used} if (FBuffer <> nil) then FreeMem(FBuffer); {free the engine} FEngine.Free; {destroy the ancestor} inherited Destroy; end; {--------} function TAbDfEncryptStream.Read(var aBuffer; aCount : longint) : longint; begin {check for programming error} Assert(false, 'TAbDfEncryptStream.Read: the stream is write-only'); Result := 0; end; {--------} function TAbDfEncryptStream.Seek(aOffset : longint; aOrigin : word) : longint; begin Result := FStream.Seek(aOffset, aOrigin); end; {--------} function TAbDfEncryptStream.Write(const aBuffer; aCount : longint) : longint; begin {note: since we cannot alter a const parameter, we should copy the data to our own buffer, encrypt it and then write it} {check that our buffer is large enough} if (FBufSize < aCount) then begin if (FBuffer <> nil) then FreeMem(FBuffer); GetMem(FBuffer, aCount); FBufSize := aCount; end; {copy the data to our buffer} Move(aBuffer, FBuffer^, aCount); {encrypt the data in our buffer} FEngine.EncodeBuffer(FBuffer^, aCount); {write the data in our buffer to the underlying stream} Result := FStream.Write(FBuffer^, aCount); end; {====================================================================} end. ================================================ FILE: lib/abbrevia/source/AbDfDec.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbDfDec.pas *} {*********************************************************} {* Deflate decoding unit *} {*********************************************************} unit AbDfDec; {$I AbDefine.inc} interface uses Classes, AbDfBase; function Inflate(aSource : TStream; aDest : TStream; aHelper : TAbDeflateHelper) : longint; implementation uses SysUtils, AbDfStrm, AbDfHufD, AbDfOutW, AbDfCryS; {===Helper routines==================================================} procedure ReadLitDistCodeLengths(aInStrm : TAbDfInBitStream; aCodeLenTree : TAbDfDecodeHuffmanTree; var aCodeLens : array of integer; aCount : integer; var aTotalBits : integer); var i : integer; SymbolCount : integer; LookupValue : integer; EncodedSymbol : longint; Symbol : integer; SymbolCodeLen : integer; RepeatCount : integer; BitBuffer : TAb32bit; BitCount : integer; begin {$IFDEF UseLogging} {we need to calculate the total number of bits in the code lengths for reporting purposes, so zero the count} aTotalBits := 0; {$ENDIF} {clear the code lengths array} FillChar(aCodeLens, sizeof(aCodeLens), 0); {read all the Symbols required in the bit stream} SymbolCount := 0; while (SymbolCount < aCount) do begin {grab the lookup set of bits} BitCount := aCodeLenTree.LookupBitLength + 7; {$IFOPT C+} BitBuffer := aInStrm.PeekBits(BitCount); {$ELSE} if (aInStrm.BitsLeft < BitCount) then BitBuffer := aInStrm.PeekMoreBits(BitCount) else BitBuffer := aInStrm.BitBuffer and AbExtractMask[BitCount]; {$ENDIF} LookupValue := BitBuffer and AbExtractMask[aCodeLenTree.LookupBitLength]; {get the encoded Symbol} {$IFOPT C+} {if Assertions are on} EncodedSymbol := aCodeLenTree.Decode(LookupValue); {$ELSE} EncodedSymbol := aCodeLenTree.Decodes^[LookupValue]; {$ENDIF} {extract the data} Symbol := EncodedSymbol and $FFFF; SymbolCodeLen := (EncodedSymbol shr 16) and $FF; {$IFDEF UseLogging} {keep count of the total number of bits read} inc(aTotalBits, SymbolCodeLen); {$ENDIF} {check that the symbol is between 0 and 18} if not ((0 <= Symbol) and (Symbol <= 18)) then raise EAbInternalInflateError.Create( 'decoded a symbol not between 0 and 18 {ReadLitDistCodeLengths}'); {check that the codelength is in range} if not ((0 < SymbolCodeLen) and (SymbolCodeLen <= aCodeLenTree.LookupBitLength)) then raise EAbInternalInflateError.Create( 'decoded a code length out of range {ReadLitDistCodeLengths}'); {for a Symbol of 0..15, just save the value} if (Symbol <= 15) then begin aCodeLens[SymbolCount] := Symbol; inc(SymbolCount); {$IFOPT C+} aInStrm.DiscardBits(SymbolCodeLen); {$ELSE} if (aInStrm.BitsLeft < SymbolCodeLen) then aInStrm.DiscardMoreBits(SymbolCodeLen) else begin aInStrm.BitBuffer := aInStrm.BitBuffer shr SymbolCodeLen; aInStrm.BitsLeft := aInStrm.BitsLeft - SymbolCodeLen; end; {$ENDIF} end {for a Symbol of 16, get two more bits and copy the previous code length that many times + 3} else if (Symbol = 16) then begin RepeatCount := 3 + ((BitBuffer shr SymbolCodeLen) and $3); Symbol := aCodeLens[SymbolCount-1]; for i := 0 to pred(RepeatCount) do aCodeLens[SymbolCount+i] := Symbol; inc(SymbolCount, RepeatCount); BitCount := SymbolCodeLen + 2; {$IFOPT C+} aInStrm.DiscardBits(BitCount); {$ELSE} if (aInStrm.BitsLeft < BitCount) then aInStrm.DiscardMoreBits(BitCount) else begin aInStrm.BitBuffer := aInStrm.BitBuffer shr BitCount; aInStrm.BitsLeft := aInStrm.BitsLeft - BitCount; end; {$ENDIF} {$IFDEF UseLogging} inc(aTotalBits, 2); {$ENDIF} end {for a Symbol of 17, get three more bits and copy a zero code length that many times + 3} else if (Symbol = 17) then begin RepeatCount := 3 + ((BitBuffer shr SymbolCodeLen) and $7); {note: the codelengths array was aet to zeros at the start so the following two lines are not needed for i := 0 to pred(RepeatCount) do aCodeLens[SymbolCount+i] := 0;} inc(SymbolCount, RepeatCount); BitCount := SymbolCodeLen + 3; {$IFOPT C+} aInStrm.DiscardBits(BitCount); {$ELSE} if (aInStrm.BitsLeft < BitCount) then aInStrm.DiscardMoreBits(BitCount) else begin aInStrm.BitBuffer := aInStrm.BitBuffer shr BitCount; aInStrm.BitsLeft := aInStrm.BitsLeft - BitCount; end; {$ENDIF} {$IFDEF UseLogging} inc(aTotalBits, 3); {$ENDIF} end {for a Symbol of 18, get seven more bits and copy a zero code length that many times + 11} else if (Symbol = 18) then begin RepeatCount := 11 + ((BitBuffer shr SymbolCodeLen) and $7F); {note: the codelengths array was aet to zeros at the start so the following two lines are not needed for i := 0 to pred(RepeatCount) do aCodeLens[SymbolCount+i] := 0;} inc(SymbolCount, RepeatCount); BitCount := SymbolCodeLen + 7; {$IFOPT C+} aInStrm.DiscardBits(BitCount); {$ELSE} if (aInStrm.BitsLeft < BitCount) then aInStrm.DiscardMoreBits(BitCount) else begin aInStrm.BitBuffer := aInStrm.BitBuffer shr BitCount; aInStrm.BitsLeft := aInStrm.BitsLeft - BitCount; end; {$ENDIF} {$IFDEF UseLogging} inc(aTotalBits, 7); {$ENDIF} end; end; end; {--------} procedure DecodeData(aInStrm : TAbDfInBitStream; aOutWindow : TAbDfOutputWindow; aLiteralTree : TAbDfDecodeHuffmanTree; aDistanceTree : TAbDfDecodeHuffmanTree; aDeflate64 : boolean); var LookupValue : integer; EncodedSymbol : longint; Symbol : integer; SymbolCodeLen : integer; ExtraBitCount : integer; Length : integer; Distance : integer; BitBuffer : TAb32bit; BitCount : integer; begin {extract the first symbol (it's got to be a literal/length symbol)} {..grab the lookup set of bits} if aDeflate64 then BitCount := aLiteralTree.LookupBitLength + 16 else BitCount := aLiteralTree.LookupBitLength + 5; {$IFOPT C+} BitBuffer := aInStrm.PeekBits(BitCount); {$ELSE} if (aInStrm.BitsLeft < BitCount) then BitBuffer := aInStrm.PeekMoreBits(BitCount) else BitBuffer := aInStrm.BitBuffer and AbExtractMask[BitCount]; {$ENDIF} LookupValue := BitBuffer and AbExtractMask[aLiteralTree.LookupBitLength]; {..get the encoded symbol} {$IFOPT C+} {if Assertions are on} EncodedSymbol := aLiteralTree.Decode(LookupValue); {$ELSE} EncodedSymbol := aLiteralTree.Decodes^[LookupValue]; {$ENDIF} {..extract the data} Symbol := EncodedSymbol and $FFFF; SymbolCodeLen := (EncodedSymbol shr 16) and $FF; // ExtraBitCount := EncodedSymbol shr 24; {repeat until we get the end-of-block symbol} while ((Symbol <> 256) {and (ExtraBitCount <> 15)}) do begin {for a literal, just output it to the sliding window} if (Symbol < 256) then begin aOutWindow.AddLiteral(AnsiChar(Symbol)); {$IFOPT C+} aInStrm.DiscardBits(SymbolCodeLen); {$ELSE} if (aInStrm.BitsLeft < SymbolCodeLen) then aInStrm.DiscardMoreBits(SymbolCodeLen) else begin aInStrm.BitBuffer := aInStrm.BitBuffer shr SymbolCodeLen; aInStrm.BitsLeft := aInStrm.BitsLeft - SymbolCodeLen; end; {$ENDIF} end {for a length value, we need to get any extra bits, and then the distance (plus any extra bits for that), and then add the duplicated characters to the sliding window} else begin {check that the length symbol is less than or equal to 285} if (Symbol > 285) then raise EAbInternalInflateError.Create( 'decoded an invalid length symbol: greater than 285 [DecodeData]'); {calculate the length (if need be, by calculating the number of extra bits that encode the length)} if (not aDeflate64) and (Symbol = 285) then begin Length := 258; {$IFOPT C+} aInStrm.DiscardBits(SymbolCodeLen); {$ELSE} if (aInStrm.BitsLeft < SymbolCodeLen) then aInStrm.DiscardMoreBits(SymbolCodeLen) else begin aInStrm.BitBuffer := aInStrm.BitBuffer shr SymbolCodeLen; aInStrm.BitsLeft := aInStrm.BitsLeft - SymbolCodeLen; end; {$ENDIF} end else begin ExtraBitCount := EncodedSymbol shr 24; if (ExtraBitCount = 0) then begin Length := dfc_LengthBase[Symbol - 257]; {$IFOPT C+} aInStrm.DiscardBits(SymbolCodeLen); {$ELSE} if (aInStrm.BitsLeft < SymbolCodeLen) then aInStrm.DiscardMoreBits(SymbolCodeLen) else begin aInStrm.BitBuffer := aInStrm.BitBuffer shr SymbolCodeLen; aInStrm.BitsLeft := aInStrm.BitsLeft - SymbolCodeLen; end; {$ENDIF} end else begin Length := dfc_LengthBase[Symbol - 257] + ((BitBuffer shr SymbolCodeLen) and AbExtractMask[ExtraBitCount]); BitCount := SymbolCodeLen + ExtraBitCount; {$IFOPT C+} aInStrm.DiscardBits(BitCount); {$ELSE} if (aInStrm.BitsLeft < BitCount) then aInStrm.DiscardMoreBits(BitCount) else begin aInStrm.BitBuffer := aInStrm.BitBuffer shr BitCount; aInStrm.BitsLeft := aInStrm.BitsLeft - BitCount; end; {$ENDIF} end; end; {extract the distance} {..grab the lookup set of bits} BitCount := aDistanceTree.LookupBitLength + 14; {$IFOPT C+} BitBuffer := aInStrm.PeekBits(BitCount); {$ELSE} if (aInStrm.BitsLeft < BitCount) then BitBuffer := aInStrm.PeekMoreBits(BitCount) else BitBuffer := aInStrm.BitBuffer and AbExtractMask[BitCount]; {$ENDIF} LookupValue := BitBuffer and AbExtractMask[aDistanceTree.LookupBitLength]; {..get the encoded symbol} {$IFOPT C+} {if Assertions are on} EncodedSymbol := aDistanceTree.Decode(LookupValue); {$ELSE} EncodedSymbol := aDistanceTree.Decodes^[LookupValue]; {$ENDIF} {..extract the data} Symbol := EncodedSymbol and $FFFF; SymbolCodeLen := (EncodedSymbol shr 16) and $FF; {check that the distance symbol is less than or equal to 29} if (not aDeflate64) and (Symbol > 29) then raise EAbInternalInflateError.Create( 'decoded an invalid distance symbol: greater than 29 [DecodeData]'); {..calculate the extra bits for the distance} ExtraBitCount := EncodedSymbol shr 24; {..calculate the distance} if (ExtraBitCount = 0) then begin Distance := dfc_DistanceBase[Symbol]; {$IFOPT C+} aInStrm.DiscardBits(SymbolCodeLen); {$ELSE} if (aInStrm.BitsLeft < SymbolCodeLen) then aInStrm.DiscardMoreBits(SymbolCodeLen) else begin aInStrm.BitBuffer := aInStrm.BitBuffer shr SymbolCodeLen; aInStrm.BitsLeft := aInStrm.BitsLeft - SymbolCodeLen; end; {$ENDIF} end else begin Distance := dfc_DistanceBase[Symbol] + ((BitBuffer shr SymbolCodeLen) and AbExtractMask[ExtraBitCount]); BitCount := SymbolCodeLen + ExtraBitCount; {$IFOPT C+} aInStrm.DiscardBits(BitCount); {$ELSE} if (aInStrm.BitsLeft < BitCount) then aInStrm.DiscardMoreBits(BitCount) else begin aInStrm.BitBuffer := aInStrm.BitBuffer shr BitCount; aInStrm.BitsLeft := aInStrm.BitsLeft - BitCount; end; {$ENDIF} end; {duplicate the characters in the sliding window} aOutWindow.AddLenDist(Length, Distance); end; {extract the next symbol} {..grab the lookup set of bits} if aDeflate64 then BitCount := aLiteralTree.LookupBitLength + 16 else BitCount := aLiteralTree.LookupBitLength + 5; {$IFOPT C+} BitBuffer := aInStrm.PeekBits(BitCount); {$ELSE} if (aInStrm.BitsLeft < BitCount) then BitBuffer := aInStrm.PeekMoreBits(BitCount) else BitBuffer := aInStrm.BitBuffer and AbExtractMask[BitCount]; {$ENDIF} LookupValue := BitBuffer and AbExtractMask[aLiteralTree.LookupBitLength]; {..get the encoded symbol} {$IFOPT C+} {if Assertions are on} EncodedSymbol := aLiteralTree.Decode(LookupValue); {$ELSE} EncodedSymbol := aLiteralTree.Decodes^[LookupValue]; {$ENDIF} {..extract the data} Symbol := EncodedSymbol and $FFFF; SymbolCodeLen := (EncodedSymbol shr 16) and $FF; end; {discard the bits for the end-of-block marker} {$IFOPT C+} aInStrm.DiscardBits(SymbolCodeLen); {$ELSE} if (aInStrm.BitsLeft < SymbolCodeLen) then aInStrm.DiscardMoreBits(SymbolCodeLen) else begin aInStrm.BitBuffer := aInStrm.BitBuffer shr SymbolCodeLen; aInStrm.BitsLeft := aInStrm.BitsLeft - SymbolCodeLen; end; {$ENDIF} end; {--------} procedure InflateStoredBlock(aInStrm : TAbDfInBitStream; aOutWindow : TAbDfOutputWindow; aLog : TAbLogger); const BufferSize = 16 * 1024; var LenNotLen : packed record Len : word; NotLen : word; end; BytesToGo : integer; BytesToWrite : integer; Buffer : pointer; begin {$IFDEF UseLogging} {log it} if (aLog <> nil) then aLog.WriteLine('....a stored block'); {$ENDIF} {align the input bit stream to the nearest byte boundary} aInStrm.AlignToByte; {read the length of the stored data and the notted length} aInStrm.ReadBuffer(LenNotLen, sizeof(LenNotLen)); {$IFDEF UseLogging} {log it} if (aLog <> nil) then aLog.WriteLine(Format('..block length: %d (%-4x, NOT %-4x)', [LenNotLen.Len, LenNotLen.Len, LenNotLen.NotLen])); {$ENDIF} {check that NOT of the length equals the notted length} if ((not LenNotLen.Len) <> LenNotLen.NotLen) then raise EAbInternalInflateError.Create( 'invalid stored block (length and NOT length do not match) [InflateStoredBlock]'); {calculate the number of bytes to copy from the stored block} BytesToGo := LenNotLen.Len; {allocate a large buffer} GetMem(Buffer, BufferSize); {copy all the data in the stored block to the output window} try {while there are still some bytes to copy...} while (BytesToGo <> 0) do begin {calculate the number of bytes this time} if (BytesToGo > BufferSize) then BytesToWrite := BufferSize else BytesToWrite := BytesToGo; {read that many bytes and write them to the output window} aInStrm.ReadBuffer(Buffer^, BytesToWrite); aOutWindow.AddBuffer(Buffer^, BytesToWrite); {calculate the number of bytes still to copy} dec(BytesToGo, BytesToWrite); end; finally FreeMem(Buffer); end; end; {--------} procedure InflateStaticBlock(aInStrm : TAbDfInBitStream; aOutWindow : TAbDfOutputWindow; aLog : TAbLogger; aDeflate64 : boolean); begin {$IFDEF UseLogging} {log it} if (aLog <> nil) then aLog.WriteLine('....a static huffman tree block'); {$ENDIF} {decode the data with the static trees} DecodeData(aInStrm, aOutWindow, AbStaticLiteralTree, AbStaticDistanceTree, aDeflate64); end; {--------} procedure InflateDynamicBlock(aInStrm : TAbDfInBitStream; aOutWindow : TAbDfOutputWindow; aLog : TAbLogger; aDeflate64 : boolean); var i : integer; LitCount : integer; DistCount : integer; CodeLenCount : integer; CodeLens : array [0..285+32] of integer; CodeLenTree : TAbDfDecodeHuffmanTree; LiteralTree : TAbDfDecodeHuffmanTree; DistanceTree : TAbDfDecodeHuffmanTree; TotalBits : integer; begin {$IFDEF UseLogging} {log it} if (aLog <> nil) then aLog.WriteLine('....a dynamic huffman tree block'); {$ENDIF} {prepare for the try..finally} CodeLenTree := nil; LiteralTree := nil; DistanceTree := nil; try {decode the number of literal, distance and codelength codes} LitCount := aInStrm.ReadBits(5) + 257; DistCount := aInStrm.ReadBits(5) + 1; CodeLenCount := aInStrm.ReadBits(4) + 4; {$IFDEF UseLogging} {log it} if (aLog <> nil) then begin aLog.WriteLine(Format('Count of literals: %d', [LitCount])); aLog.WriteLine(Format('Count of distances: %d', [DistCount])); aLog.WriteLine(Format('Count of code lengths: %d', [CodeLenCount])); end; {$ENDIF} {verify that the counts are valid} if (LitCount > 286) then raise EAbInternalInflateError.Create( 'count of literal codes in dynamic block is greater than 286 [InflateDynamicBlock]'); if (not aDeflate64) and (DistCount > 30) then raise EAbInternalInflateError.Create( 'count of distance codes in dynamic block is greater than 30 [InflateDynamicBlock]'); {read the codelengths} FillChar(CodeLens, 19 * sizeof(integer), 0); for i := 0 to pred(CodeLenCount) do CodeLens[dfc_CodeLengthIndex[i]] := aInStrm.ReadBits(3); {$IFDEF UseLogging} {log them} if (aLog <> nil) then begin aLog.WriteLine('CodeLength Huffman tree: code lengths'); for i := 0 to 18 do aLog.WriteStr(Format('%-3d', [CodeLens[i]])); aLog.WriteLine(''); aLog.WriteLine(Format('..total bits: %d', [CodeLenCount * 3])); end; {$ENDIF} {create the codelength huffman tree} CodeLenTree := TAbDfDecodeHuffmanTree.Create(19, 7, huDecoding); CodeLenTree.Build(CodeLens, 0, 19, [0], $FFFF); {$IFDEF UseLogging} {log the tree} if (aLog <> nil) then begin aLog.WriteLine('Code lengths tree'); CodeLenTree.DebugPrint(aLog); end; {$ENDIF} {read the codelengths for both the literal/length and distance huffman trees} ReadLitDistCodeLengths(aInStrm, CodeLenTree, CodeLens, LitCount + DistCount, TotalBits); {$IFDEF UseLoggingx} {log them} if (aLog <> nil) then begin aLog.WriteLine('Literal/length & Dist Huffman trees: code lengths'); for i := 0 to pred(LitCount + DistCount) do aLog.WriteLine(Format('%3d: %3d', [i, CodeLens[i]])); aLog.WriteLine(''); aLog.WriteLine(Format('..total bits: %d', [TotalBits])); end; {$ENDIF} {create the literal huffman tree} LiteralTree := TAbDfDecodeHuffmanTree.Create(286, 15, huDecoding); LiteralTree.Build(CodeLens, 0, LitCount, dfc_LitExtraBits, dfc_LitExtraOffset); {$IFDEF UseLogging} {log the tree} if (aLog <> nil) then begin aLog.WriteLine('Literal/length tree'); LiteralTree.DebugPrint(aLog); end; {$ENDIF} {create the distance huffman tree} if aDeflate64 then DistanceTree := TAbDfDecodeHuffmanTree.Create(32, 15, huDecoding) else DistanceTree := TAbDfDecodeHuffmanTree.Create(30, 15, huDecoding); DistanceTree.Build(CodeLens, LitCount, DistCount, dfc_DistExtraBits, dfc_DistExtraOffset); {$IFDEF UseLogging} {log the tree} if (aLog <> nil) then begin aLog.WriteLine('Distance tree'); DistanceTree.DebugPrint(aLog); end; {$ENDIF} {using the literal and distance trees, decode the bit stream} DecodeData(aInStrm, aOutWindow, LiteralTree, DistanceTree, aDeflate64); finally CodeLenTree.Free; LiteralTree.Free; DistanceTree.Free; end; end; {====================================================================} {===Interfaced routine===============================================} function Inflate(aSource : TStream; aDest : TStream; aHelper : TAbDeflateHelper) : longint; var Helper : TAbDeflateHelper; InBitStrm : TAbDfInBitStream; OutWindow : TAbDfOutputWindow; Log : TAbLogger; UseDeflate64 : boolean; UseCRC32 : boolean; IsFinalBlock : boolean; BlockType : integer; TestOnly : boolean; SourceStartPos : longint; DestStartPos : longint; {$IFDEF UseLogging} StartPosn : longint; {$ENDIF} begin {$IFDEF DefeatWarnings} Result := 0; SourceStartPos := 0; DestStartPos := 0; TestOnly := False; {$ENDIF} {$IFDEF UseLogging} StartPosn := 0; {$ENDIF} {pre-conditions: streams must be allocated of course} Assert(aSource <> nil, 'Deflate: aSource stream cannot be nil'); Assert(aDest <> nil, 'Deflate: aDest stream cannot be nil'); {prepare for the try..finally} Helper := nil; InBitStrm := nil; OutWindow := nil; Log := nil; try {finally} try {except} {create our helper; assign the passed one to it} Helper := TAbDeflateHelper.Create; if (aHelper <> nil) then Helper.Assign(aHelper); {get the initial start positions of both streams} SourceStartPos := aSource.Position; DestStartPos := aDest.Position; {if the helper's stream size is -1, and it has a progress event handler, calculate the stream size from the stream itself} if Assigned(Helper.OnProgressStep) then begin if (Helper.StreamSize = -1) then Helper.StreamSize := aSource.Size; end {otherwise we certainly can't do any progress reporting} else begin Helper.OnProgressStep := nil; Helper.StreamSize := 0; end; {create the logger, if requested} if (Helper.LogFile <> '') then begin Log := TAbLogger.Create(Helper.LogFile); Log.WriteLine('INFLATING STREAM...'); {$IFNDEF UseLogging} Log.WriteLine('Need to recompile the app with UseLogging turned on'); {$ENDIF} end; InBitStrm := TAbDfInBitStream.Create(aSource, Helper.OnProgressStep, Helper.StreamSize); {create the output sliding window} UseDeflate64 := (Helper.Options and dfc_UseDeflate64) <> 0; UseCRC32 := (Helper.Options and dfc_UseAdler32) = 0; TestOnly := (Helper.Options and dfc_TestOnly) <> 0; OutWindow := TAbDfOutputWindow.Create( aDest, UseDeflate64, UseCRC32, Helper.PartialSize, TestOnly, Log); {start decoding the deflated stream} repeat {read the final block flag and the block type} IsFinalBlock := InBitStrm.ReadBit; BlockType := InBitStrm.ReadBits(2); {$IFDEF UseLogging} {log it} if (Log <> nil) then begin Log.WriteLine(''); Log.WriteLine('Starting new block'); Log.WriteLine(Format('..final block? %d', [ord(IsFinalBlock)])); Log.WriteLine(Format('..block type? %d', [BlockType])); StartPosn := OutWindow.Position; end; {$ENDIF} case BlockType of 0 : InflateStoredBlock(InBitStrm, OutWindow, Log); 1 : InflateStaticBlock(InBitStrm, OutWindow, Log, UseDeflate64); 2 : InflateDynamicBlock(InBitStrm, OutWindow, Log, UseDeflate64); else raise EAbInternalInflateError.Create( 'starting new block, but invalid block type [Inflate]'); end; {$IFDEF UseLogging} {log it} if (Log <> nil) then Log.WriteLine(Format('---block end--- (decoded size %d bytes)', [OutWindow.Position - StartPosn])); {$ENDIF} until IsFinalBlock; {get the uncompressed stream's checksum} Result := OutWindow.Checksum; if TestOnly and (aHelper <> nil) then aHelper.NormalSize := OutWindow.Position; {$IFDEF UseLogging} {log it} if (Log <> nil) then Log.WriteLine(Format('End of compressed stream, checksum %-8x', [Result])); {$ENDIF} except on E : EAbPartSizedInflate do begin {nothing, just swallow the exception} Result := 0; end; on E : EAbAbortProgress do begin {nothing, just swallow the exception} Result := 0; end; on E : EAbInternalInflateError do begin if (Log <> nil) then Log.WriteLine(Format('Internal exception raised: %s', [E.Message])); raise EAbInflateError.Create(E.Message); end; end; finally Helper.Free; OutWindow.Free; InBitStrm.Free; Log.Free; end; {if there's a helper return the compressed and uncompressed sizes} if (aHelper <> nil) then begin if not TestOnly then aHelper.NormalSize := aDest.Position - DestStartPos; aHelper.CompressedSize := aSource.Position - SourceStartPos; end; {WARNING NOTE: the compiler will warn that the return value of this function might be undefined. However, it is wrong: it has been fooled by the code. If you don't want to see this warning again, enable the DefeatWarnings compiler define in AbDefine.inc.} end; {====================================================================} end. ================================================ FILE: lib/abbrevia/source/AbDfEnc.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbDfEnc.pas *} {*********************************************************} {* Deflate encoding unit *} {*********************************************************} unit AbDfEnc; {$I AbDefine.inc} interface uses Classes, AbDfBase; function Deflate(aSource : TStream; aDest : TStream; aHelper : TAbDeflateHelper) : longint; implementation uses AbDfInW, AbDfHufD, AbDfStrm, AbDfCryS, AbDfPkMg; {====================================================================} function CalcDynamicBitCount(aUseDeflate64: boolean; aLitBuckets : PAbDfLitBuckets; aDistBuckets : PAbDfDistBuckets; aCodeBuckets : PAbDfCodeLenBuckets; const aCodeLens : array of integer; const aCLCodeLens : array of integer; aLitCount : integer; aDistCount : integer; aCodeCount : integer) : longint; var Symbol : integer; LastSymbol : integer; Inx : integer; begin {note: this routine calculates the number of bits required to compress a given block} {a dynamic block starts off with 5 bits of literal symbol count, 5 bits of distance symbol count, 4 bits of codelength symbol count, and then 3 bits for every codelength symbol used} Result := 5 + 5 + 4 + (aCodeCount * 3); {add in the bits needed to compress the literal and distance trees} inc(Result, aCodeBuckets^[16] * (aCLCodeLens[16] + 2)); inc(Result, aCodeBuckets^[17] * (aCLCodeLens[16] + 3)); inc(Result, aCodeBuckets^[18] * (aCLCodeLens[16] + 7)); for Symbol := 3 to pred(aCodeCount) do begin Inx := dfc_CodeLengthIndex[Symbol]; Assert(Inx <=15, 'CalcDynamicBitCount: the index array of codelengths is corrupted'); inc(Result, aCodeBuckets^[Inx] * aCLCodeLens[Inx]) end; {make the literal symbol 285 a special case} LastSymbol := pred(aLitCount); if (LastSymbol = 285) then LastSymbol := 284; {add in all the bits needed to compress the literals (except 285)} for Symbol := 0 to LastSymbol do if (Symbol < dfc_LitExtraOffset) then inc(Result, aLitBuckets^[Symbol] * aCodeLens[Symbol]) else inc(Result, aLitBuckets^[Symbol] * (aCodeLens[Symbol] + dfc_LitExtraBits[Symbol - dfc_LitExtraOffset])); {add in all the bits needed to compress the literal symbol 285} if (pred(aLitCount) = 285) then if (not aUseDeflate64) then inc(Result, aLitBuckets^[285] * aCodeLens[285]) else inc(Result, aLitBuckets^[285] * (aCodeLens[285] + 16)); {add in all the bits needed to compress the distances} for Symbol := 0 to pred(aDistCount) do inc(Result, aDistBuckets^[Symbol] * (aCodeLens[aLitCount + Symbol] + dfc_DistExtraBits[Symbol])); end; {====================================================================} {====================================================================} procedure OutputEndOfBlock(aBitStrm : TAbDfOutBitStream; aLitTree : TAbDfDecodeHuffmanTree); var Code : longint; begin {note: this routine encodes the end-of-block character (symbol 256) and then writes out the code to the bit stream} {encode the end-of-block character as a symbol} {$IFOPT C+} {if Assertions are on } Code := aLitTree.Encode(256); {$ELSE} Code := aLitTree.Encodes^[256]; {$ENDIF} {write the code out to the bit stream} aBitStrm.WriteBits(Code and $FFFF, (Code shr 16) and $FF); end; {--------} procedure EncodeLZStreamStored(aFinalBlock : boolean; aStream : TAbDfLZStream; aBitStrm : TAbDfOutBitStream; aDataSize : integer; aLog : TAbLogger); var BlockHeader : packed record bhSize : word; bhNotSize : word; end; Buffer : pointer; Code : integer; BlockSize : integer; begin {note: this routine writes out an incompressible block to the bit stream (the store algorithm)} {allocate the maximum buffer we can write at once} GetMem(Buffer, 64 * 1024); try {while there's more incompressible data to store...} while (aDataSize <> 0) do begin {calculate the block size to write this time} if (aDataSize > $FFFF) then begin BlockSize := $FFFF; dec(aDataSize, $FFFF); end else begin BlockSize := aDataSize; aDataSize := 0; end; {$IFDEF UseLogging} {log it} if (aLog <> nil) then begin aLog.WriteLine('..Writing new block...'); aLog.WriteLine(Format('..final block? %d', [ord(aFinalBlock)])); aLog.WriteLine('..block type? 0'); aLog.WriteLine(Format('..block size: %d', [BlockSize])); end; {$ENDIF} {output the block information to the bit stream} if aFinalBlock then Code := 1 + (0 shl 1) else Code := 0 + (0 shl 1); aBitStrm.WriteBits(Code, 3); {align the bit stream to the nearest byte} aBitStrm.AlignToByte; {write the stored block header} BlockHeader.bhSize := BlockSize; BlockHeader.bhNotSize := not BlockHeader.bhSize; aBitStrm.WriteBuffer(BlockHeader, sizeof(BlockHeader)); {get and write this block} aStream.ReadStoredBuffer(Buffer^, BlockSize); aBitStrm.WriteBuffer(Buffer^, BlockSize); end; finally FreeMem(Buffer); end; {clear the stream, ready for the next block} aStream.Clear; end; {--------} procedure EncodeLZStreamStatic(aFinalBlock : boolean; aUseDeflate64 : boolean; aStream : TAbDfLZStream; aBitStrm : TAbDfOutBitStream; aLog : TAbLogger); var Code : integer; begin {note: this routine writes out the stream of LZ77 tokens for the current block to the bit stream, using the static huffman trees to encode the token symbols} {$IFDEF UseLogging} {log it} if (aLog <> nil) then begin aLog.WriteLine('..Writing new block...'); aLog.WriteLine(Format('..final block? %d', [ord(aFinalBlock)])); aLog.WriteLine('..block type? 1'); end; {$ENDIF} {output the block information to the bit stream} if aFinalBlock then Code := 1 + (1 shl 1) else Code := 0 + (1 shl 1); aBitStrm.WriteBits(Code, 3); {encode the LZ77 stream} aStream.Encode(aBitStrm, AbStaticLiteralTree, AbStaticDistanceTree, aUseDeflate64); {output the end-of-block marker to the bit stream} OutputEndOfBlock(aBitStrm, AbStaticLiteralTree); {$IFDEF UseLogging} if (aLog <> nil) then aLog.WriteLine('Char: end-of-block marker (#256)'); {$ENDIF} end; {--------} procedure EncodeLZStreamDynamic(aFinalBlock : boolean; aUseDeflate64 : boolean; aUseBest : boolean; aStream : TAbDfLZStream; aBitStrm : TAbDfOutBitStream; aLog : TAbLogger); var i : integer; LitTree : TAbDfDecodeHuffmanTree; DistTree : TAbDfDecodeHuffmanTree; CodeLenTree : TAbDfDecodeHuffmanTree; CodeLenStream : TAbDfCodeLenStream; CodeLens : array [0..285+32] of integer; CLCodeLens : array [0..18] of integer; LitCodeCount : integer; DistCodeCount : integer; LenCodeCount : integer; BitCount : integer; Code : integer; StaticSize : integer; StoredSize : integer; begin {note: this routine writes out the stream of LZ77 tokens for the current block to the bit stream, using the dynamic huffman trees to encode the token symbols; if the routine determines that the data can better be compressed using the static huffman trees or should be stored as is, it'll switch algorithms} {prepare for the try..finally} LitTree := nil; DistTree := nil; CodeLenTree := nil; CodeLenStream := nil; try {calculate the code lengths for the literal symbols} GenerateCodeLengths(15, aStream.LitBuckets^, CodeLens, 0, aLog); {calculate the number of the used codelengths for the literals} LitCodeCount := 286; repeat dec(LitCodeCount); until (CodeLens[LitCodeCount] <> 0); inc(LitCodeCount); {calculate the code lengths for the distance symbols} GenerateCodeLengths(15, aStream.DistBuckets^, CodeLens, LitCodeCount, aLog); {calculate the number of the used codelengths for the distances} DistCodeCount := 32; repeat dec(DistCodeCount); until (CodeLens[DistCodeCount + LitCodeCount] <> 0); inc(DistCodeCount); {calculate the code lengths array as a stream of items} CodeLenStream := TAbDfCodeLenStream.Create(aLog); CodeLenStream.Build(CodeLens, LitCodeCount + DistCodeCount); {calculate the codelengths for the code lengths} GenerateCodeLengths(7, CodeLenStream.Buckets^, CLCodeLens, 0, nil); {calculate the number of the used codelengths for the code lengths} LenCodeCount := 19; repeat dec(LenCodeCount); until (CLCodeLens[dfc_CodeLengthIndex[LenCodeCount]] <> 0); inc(LenCodeCount); {..there's a minimum of four, though} if (LenCodeCount < 4) then LenCodeCount := 4; {if we have to work out and use the best method...} if aUseBest then begin {calculate the number of bits required for the compressed data using dynamic huffman trees} BitCount := CalcDynamicBitCount(aUseDeflate64, aStream.LitBuckets, aStream.DistBuckets, CodeLenStream.Buckets, CodeLens, CLCodeLens, LitCodeCount, DistCodeCount, LenCodeCount); {choose the algorithm with the smallest size} StaticSize := aStream.StaticSize; StoredSize := (aStream.StoredSize + 4) * 8; if (StaticSize < BitCount) then begin if (StoredSize < StaticSize) then EncodeLZStreamStored(aFinalBlock, aStream, aBitStrm, (StoredSize div 8) - 4, aLog) else EncodeLZStreamStatic(aFinalBlock, aUseDeflate64, aStream, aBitStrm, aLog); Exit; end else if (StoredSize < BitCount) then begin EncodeLZStreamStored(aFinalBlock, aStream, aBitStrm, (StoredSize div 8) - 4, aLog); Exit; end; end; {create the code lengths tree} CodeLenTree := TAbDfDecodeHuffmanTree.Create(19, 7, huEncoding); CodeLenTree.Build(CLCodeLens, 0, 19, [0], $FFFF); {$IFDEF UseLogging} {log the tree} if (aLog <> nil) then begin aLog.WriteLine('Code lengths tree'); CodeLenTree.DebugPrint(aLog); end; {$ENDIF} {calculate the literal encoding tree} LitTree := TAbDfDecodeHuffmanTree.Create(286, 15, huEncoding); LitTree.Build(CodeLens, 0, LitCodeCount, dfc_LitExtraBits, dfc_LitExtraOffset); {$IFDEF UseLogging} {log the tree} if (aLog <> nil) then begin aLog.WriteLine('Literal/length tree'); LitTree.DebugPrint(aLog); end; {$ENDIF} {calculate the distance tree} if aUseDeflate64 then DistTree := TAbDfDecodeHuffmanTree.Create(32, 15, huEncoding) else DistTree := TAbDfDecodeHuffmanTree.Create(30, 15, huEncoding); DistTree.Build(CodeLens, LitCodeCount, DistCodeCount, dfc_DistExtraBits, dfc_DistExtraOffset); {$IFDEF UseLogging} if (aLog <> nil) then begin {log the tree} aLog.WriteLine('Distance tree'); DistTree.DebugPrint(aLog); {log the new block} aLog.WriteLine('..Writing new block...'); aLog.WriteLine(Format('..final block? %d', [ord(aFinalBlock)])); aLog.WriteLine('..block type? 2'); aLog.WriteLine(Format('Count of literals: %d', [LitCodeCount])); aLog.WriteLine(Format('Count of distances: %d', [DistCodeCount])); aLog.WriteLine(Format('Count of code lengths: %d', [LenCodeCount])); end; {$ENDIF} {output the block information to the bit stream} if aFinalBlock then Code := 1 + (2 shl 1) else Code := 0 + (2 shl 1); aBitStrm.WriteBits(Code, 3); {output the various counts to the bit stream} Code := (LitCodeCount - 257) + ((DistCodeCount - 1) shl 5) + ((LenCodeCount - 4) shl 10); aBitStrm.WriteBits(Code, 14); {output the code length codelengths to the bit stream} for i := 0 to pred(LenCodeCount) do aBitStrm.WriteBits(CLCodeLens[dfc_CodeLengthIndex[i]], 3); {encode and write the codelength stream to the bit stream} CodeLenStream.Encode(aBitStrm, CodeLenTree); {encode and write the LZ77 stream to the bit stream} aStream.Encode(aBitStrm, LitTree, DistTree, aUseDeflate64); {output the end-of-block marker to the bit stream} OutputEndOfBlock(aBitStrm, LitTree); {$IFDEF UseLogging} if (aLog <> nil) then aLog.WriteLine('Char: end-of-block marker (#256)'); {$ENDIF} finally LitTree.Free; DistTree.Free; CodeLenTree.Free; CodeLenStream.Free; end; end; {====================================================================} {===Single algorithm Static/Dynamic Huffman tree deflate=============} function DeflateStaticDynamic(aStatic : boolean; aUseBest: boolean; aSource : TStream; aDest : TStream; aHelper : TAbDeflateHelper; aLog : TAbLogger) : longint; var i : integer; SlideWin : TAbDfInputWindow; BitStrm : TAbDfOutBitStream; LZ77Stream : TAbDfLZStream; KeyLen : integer; Match : TAbDfMatch; PrevMatch : TAbDfMatch; UseDeflate64 : boolean; UseCRC32 : boolean; GotMatch : boolean; LZStrmIsFull : boolean; TestForBinary: boolean; begin {note: turn on the following define to see when and how the lazy matching algorithm works} {$IFDEF UseLogging} {$DEFINE UseLazyMatchLogging} {$ENDIF} {$IFDEF UseLogging} if (aLog <> nil) then if aStatic then aLog.WriteLine('..compressing source data with static huffman trees') else aLog.WriteLine('..compressing source data with dynamic huffman trees'); {$ENDIF} {prepare for the try..finally} SlideWin := nil; BitStrm := nil; LZ77Stream := nil; try {create the sliding window} UseDeflate64 := (aHelper.Options and dfc_UseDeflate64) <> 0; UseCRC32 := (aHelper.Options and dfc_UseAdler32) = 0; SlideWin := TAbDfInputWindow.Create(aSource, aHelper.StreamSize, aHelper.WindowSize, aHelper.ChainLength, UseDeflate64, UseCRC32); SlideWin.OnProgress := aHelper.OnProgressStep; {create the bit stream} BitStrm := TAbDfOutBitStream.Create(aDest); {create the LZ77 stream} LZ77Stream := TAbDfLZStream.Create(SlideWin, UseDeflate64, aLog); LZStrmIsFull := false; TestForBinary := true; {set the previous match to be a literal character: this will ensure that no lazy matching goes on with the first key read} PrevMatch.maLen := 0; {get the first key length} KeyLen := SlideWin.GetNextKeyLength; {while the current key is three characters long...} while (KeyLen = 3) do begin {tweak for binary/text} {note: the test for whether a stream is binary or not is to check whether there are any #0 characters in the first 1024 bytes: if there are the stream is binary. this test and tweaking is based on experimentation compression ratios for binary and text files based on the PKZIP 'n' option.} if TestForBinary and (LZ77Stream.StoredSize = 1024) then begin if (aHelper.PKZipOption = 'n') then if (LZ77Stream.LitBuckets^[0] = 0) then begin aHelper.AmpleLength := aHelper.AmpleLength * 2; aHelper.MaxLazyLength := aHelper.MaxLazyLength * 2; aHelper.ChainLength := aHelper.ChainLength * 2; SlideWin.ChainLen := aHelper.ChainLength; end; TestForBinary := false; end; {if the LZ77 stream is full, empty it} if LZStrmIsFull then begin if aStatic then EncodeLZStreamStatic(false, UseDeflate64, LZ77Stream, BitStrm, aLog) else EncodeLZStreamDynamic(false, UseDeflate64, aUseBest, LZ77Stream, BitStrm, aLog); LZ77Stream.Clear; LZStrmIsFull := false; end; {try and find a match of three or more characters (note: this has the side effect of adding the current key to the internal hash table); this routine will only return true if it finds a match greater than the previous match} GotMatch := SlideWin.FindLongestMatch(aHelper.AmpleLength, Match, PrevMatch); {if the maximum match length were three and the distance exceeds 4096 bytes, it's most likely that we'll get better compression by outputting the three literal bytes rather than by outputting a length symbol, a distance symbol, and at least ten extra bits for the extra distance value} if (Match.maLen = 3) and (Match.maDist > 4096) then GotMatch := false; {if we found a match...} if GotMatch then begin {if there were no previous match, we can't do any lazy match processing now, so save the current match details ready for lazy matching the next time through, and advance the sliding window} if (PrevMatch.maLen = 0) then begin PrevMatch.maLen := Match.maLen; PrevMatch.maDist := Match.maDist; PrevMatch.maLit := Match.maLit; SlideWin.AdvanceByOne; end {otherwise the previous match is smaller than this one, so we're going to accept this match in preference; throw away the previous match, output the previous literal character instead and save these match details} else begin {$IFDEF UseLazyMatchLogging} if (aLog <> nil) then aLog.WriteLine( Format( '..this match longer, rejecting previous one (%d,%d)', [PrevMatch.maLen, PrevMatch.maDist])); {$ENDIF} LZStrmIsFull := LZ77Stream.AddLiteral(PrevMatch.maLit); PrevMatch.maLen := Match.maLen; PrevMatch.maDist := Match.maDist; PrevMatch.maLit := Match.maLit; SlideWin.AdvanceByOne; end; {if, by this point, we're storing up a match, check to see if it equals or exceeds the maximum lazy match length; if it does then output the match right now and avoid checking for a lazy match} if (PrevMatch.maLen >= aHelper.MaxLazyLength) then begin {$IFDEF UseLazyMatchLogging} if (aLog <> nil) then if ((aHelper.Options and dfc_UseLazyMatch) <> 0) then aLog.WriteLine('..match longer than max lazy match, using it'); {$ENDIF} LZStrmIsFull := LZ77Stream.AddLenDist(PrevMatch.maLen, PrevMatch.maDist); SlideWin.Advance(PrevMatch.maLen - 1, PrevMatch.maLen - 1); PrevMatch.maLen := 0; end; end {otherwise, we don't have a match at all: so we possibly just need to output a literal character} else begin {if there was a previous match, output it and discard the results of this match} if (PrevMatch.maLen <> 0) then begin LZStrmIsFull := LZ77Stream.AddLenDist(PrevMatch.maLen, PrevMatch.maDist); SlideWin.Advance(PrevMatch.maLen - 1, PrevMatch.maLen - 2); PrevMatch.maLen := 0; end {otherwise there was no previous match or it's already been output, so output this literal} else begin LZStrmIsFull := LZ77Stream.AddLiteral(Match.maLit); SlideWin.AdvanceByOne; PrevMatch.maLen := 0; end; end; {get the next key} KeyLen := SlideWin.GetNextKeyLength; end; {if the last key read were one or two characters in length, save them as literal character encodings} if (KeyLen > 0) then begin {if there's a match pending, it'll be of length 3: output it} if (PrevMatch.maLen <> 0) then begin Assert(PrevMatch.maLen = 3, 'DeflateStaticDynamic: previous match should be length 3'); LZ77Stream.AddLenDist(PrevMatch.maLen, PrevMatch.maDist); end {otherwise, output the one or two final literals} else for i := 1 to KeyLen do LZ77Stream.AddLiteral(SlideWin.GetNextChar); end; {empty the LZ77 stream} if aStatic then EncodeLZStreamStatic(true, UseDeflate64, LZ77Stream, BitStrm, aLog) else EncodeLZStreamDynamic(true, UseDeflate64, aUseBest, LZ77Stream, BitStrm, aLog); {calculate the checksum of the input stream} Result := SlideWin.Checksum; finally {free the objects} SlideWin.Free; BitStrm.Free; LZ77Stream.Free; end;{try..finally} {$IFDEF UseLogging} {log it} if (aLog <> nil) then aLog.WriteLine(Format('..checksum: %8x', [Result])) {$ENDIF} end; {====================================================================} {===Simple storing===================================================} function DeflateStored(aSource : TStream; aDest : TStream; aHelper : TAbDeflateHelper; aLog : TAbLogger) : longint; const StoredBlockSize = $FFFF; var Buffer : PAnsiChar; BytesRead : LongWord; ByteCount : Int64; BytesToGo : Int64; CurPos : Int64; Size : Int64; Percent : longint; CheckSum : longint; UseCRC32 : boolean; BlockHeader : packed record bhInfo : byte; bhSize : word; bhNotSize : word; end; begin {note: this routine merely stores the aSource stream data, no compression is attempted or done} {$IFDEF UseLogging} if (aLog <> nil) then aLog.WriteLine('..storing source data to destination, no compression'); {$ENDIF} {initialize} ByteCount := 0; UseCRC32 := (aHelper.Options and dfc_UseAdler32) = 0; if UseCRC32 then Checksum := -1 { CRC32 starts off with all bits set} else CheckSum := 1; { Adler32 starts off with a value of 1} if (aHelper.StreamSize > 0) then BytesToGo := aHelper.StreamSize else begin CurPos := aSource.Seek(0, soCurrent); Size := aSource.Seek(0, soEnd); aSource.Seek(CurPos, soBeginning); BytesToGo := Size - CurPos; end; {get a buffer} GetMem(Buffer, StoredBlockSize); try {while there is still data to be stored...} while (BytesToGo <> 0) do begin {read the next block} BytesRead := aSource.Read(Buffer^, StoredBlockSize); {fire the progress event} if Assigned(aHelper.OnProgressStep) then begin inc(ByteCount, BytesRead); Percent := Round((100.0 * ByteCount) / aHelper.StreamSize); aHelper.OnProgressStep(Percent); end; {update the checksum} if UseCRC32 then AbUpdateCRCBuffer(Checksum, Buffer^, BytesRead) else AbUpdateAdlerBuffer(Checksum, Buffer^, BytesRead); {write the block header} if (BytesRead = BytesToGo) then BlockHeader.bhInfo := 1 {ie, final block, stored} else BlockHeader.bhInfo := 0; {ie, not final block, stored} BlockHeader.bhSize := BytesRead; BlockHeader.bhNotSize := not BlockHeader.bhSize; aDest.WriteBuffer(BlockHeader, sizeof(BlockHeader)); {write the block of data} aDest.WriteBuffer(Buffer^, BytesRead); {$IFDEF UseLogging} {log it} if (aLog <> nil) then begin if (BlockHeader.bhInfo = 0) then aLog.WriteLine(Format('..block size: %d', [BytesRead])) else aLog.WriteLine(Format('..block size: %d (final block)', [BytesRead])); end; {$ENDIF} {decrement the number of bytes to go} dec(BytesToGo, BytesRead); end; finally FreeMem(Buffer); end; {return the checksum} {note: the CRC32 checksum algorithm requires a post-conditioning step after being calculated (the result is NOTted), whereas Adler32 does not} if UseCRC32 then Result := not Checksum else Result := Checksum; {$IFDEF UseLogging} {log it} if (aLog <> nil) then aLog.WriteLine(Format('..checksum: %8x', [Result])) {$ENDIF} end; {====================================================================} {===Interfaced routine===============================================} function Deflate(aSource : TStream; aDest : TStream; aHelper : TAbDeflateHelper) : longint; var Helper : TAbDeflateHelper; Log : TAbLogger; SourceStartPos : longint; DestStartPos : longint; begin {pre-conditions: streams are allocated, options enable some kind of archiving} Assert(aSource <> nil, 'Deflate: aSource stream cannot be nil'); Assert(aDest <> nil, 'Deflate: aDest stream cannot be nil'); Assert((aHelper = nil) or ((aHelper.Options and $07) <> 0), 'Deflate: aHelper.Options must enable some kind of archiving'); {$IFDEF DefeatWarnings} Result := 0; {$ENDIF} {prepare for the try..finally} Helper := nil; Log := nil; try {finally} try {except} {create our helper; assign the passed one to it} Helper := TAbDeflateHelper.Create; if (aHelper <> nil) then Helper.Assign(aHelper); {save the current positions of both streams} SourceStartPos := aSource.Position; DestStartPos := aDest.Position; {if the helper's stream size is -1, and it has a progress event handler, calculate the stream size from the stream itself} if Assigned(Helper.OnProgressStep) then begin if (Helper.StreamSize = -1) then Helper.StreamSize := aSource.Size; end {otherwise we certainly can't do any progress reporting} else begin Helper.OnProgressStep := nil; Helper.StreamSize := 0; end; {if lazy matching is not requested, ensure the maximum lazy match length is zero: this make the LZ77 code a little easier to understand} if ((Helper.Options and dfc_UseLazyMatch) = 0) then Helper.MaxLazyLength := 0; {patch up the various lengths in the helper if they specify the maximum (that is, are equal to -1)} if (Helper.AmpleLength = -1) then Helper.AmpleLength := MaxLongInt; if (Helper.MaxLazyLength = -1) then Helper.MaxLazyLength := MaxLongInt; if (Helper.ChainLength = -1) then Helper.ChainLength := MaxLongInt; {create the logger, if requested} if (Helper.LogFile <> '') then begin Log := TAbLogger.Create(Helper.LogFile); Log.WriteLine('DEFLATING STREAM...'); {$IFNDEF UseLogging} Log.WriteLine('Need to recompile the app with UseLogging turned on'); {$ENDIF} end; {use the helper's options property to decide what to do} case (Helper.Options and $07) of dfc_CanUseStored : Result := DeflateStored(aSource, aDest, Helper, Log); dfc_CanUseStatic : Result := DeflateStaticDynamic(true, false, aSource, aDest, Helper, Log); dfc_CanUseDynamic : Result := DeflateStaticDynamic(false, false, aSource, aDest, Helper, Log); else Result := DeflateStaticDynamic(false, true, aSource, aDest, Helper, Log); end; {save the uncompressed and compressed sizes} if (aHelper <> nil) then begin aHelper.NormalSize := aSource.Position - SourceStartPos; aHelper.CompressedSize := aDest.Position - DestStartPos; end; except on E : EAbInternalDeflateError do begin {$IFDEF UseLogging} if (Log <> nil) then Log.WriteLine(Format('Internal exception raised: %s', [E.Message])); {$ENDIF} raise EAbDeflateError.Create(E.Message); end; end; finally Helper.Free; Log.Free; end; {WARNING NOTE: the compiler will warn that the return value of this function might be undefined. However, it is wrong: it has been fooled by the code. If you don't want to see this warning again, enable the DefeatWarnings compiler define in AbDefine.inc.} end; {====================================================================} end. ================================================ FILE: lib/abbrevia/source/AbDfHufD.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbDfHufD.pas *} {*********************************************************} {* Deflate Huffman tree for decoder *} {*********************************************************} unit AbDfHufD; {$I AbDefine.inc} {Activate this compiler define and rebuild if you want the complete huffman tree output to print to the current log. The output is voluminous to say the least...} {$IFDEF UseLogging} {.$DEFINE EnableMegaLog} {$ENDIF} {Notes: The object of this class is to build a decoder array, not to build a Huffman tree particularly. We don't want to decode huffman strings bit by bit. moving down the Huffman tree sometimes left, sometimes right. Instead we want to grab a set of bits and look them up in an array. Sometimes we'll grab too many bits, sure, but we can deal with that later. So, the object of the exercise is to calculate the code for a symbol, reverse it ('cos that's how the input bit stream will present it to us) and set that element of the array to the decoded symbol value (plus some extra information: bit lengths). If the alphabet size were 19 (the codelengths huffman tree) and the maximum code length 5, for example, the decoder array would be 2^5 elements long, much larger than the alphabet size. The user of this class will be presenting sets of 5 bits for us to decode. We would like to look up these 5 bits in the array (as an index) and have the symbol returned. Now, since the alphabet size is much less than the number of elements in the decoder array, we must set the other elements in the array as well. Consider a symbol that has a code of 110 in this scenario. The reversed code is 011, or 3, so we'd be setting element 3. However we should also be setting elements 01011, 10011, and 11011 to this symbol information as well, since the lookup will be 5 bits long. Because the code is a huffman code from a prefix tree, we won't get any index clashes between actual codes by this "filling in" process. For the codelength Huffman tree, the maximum code length is at most 7. This equates to a 128 element array. For the literal and distance trees, the max code length is at most 15. This equates to a 32768 element array. For a given lookup value the decoder will return a 32-bit value. The lower 16 bits is the decoded symbol, the next 8 bits is the code length for that symbol, the last 8 bits (the most significant) are the number of extra bits that must be extracted from the input bit stream. } interface uses AbDfBase; type TAbDfHuffmanUsage = ( {usage of a huffman decoder..} huEncoding, {..encoding} huDecoding, {..decoding} huBoth); {..both (used for static trees)} TAbDfDecodeHuffmanTree = class private FAlphaSize : integer; FDecodes : PAbDfLongintList; FDefMaxCodeLen : integer; FEncodes : PAbDfLongintList; {$IFOPT C+} FMask : integer; {$ENDIF} FMaxCodeLen : integer; FUsage : TAbDfHuffmanUsage; protected public constructor Create(aAlphabetSize : integer; aDefMaxCodeLen: integer; aUsage : TAbDfHuffmanUsage); destructor Destroy; override; procedure Build(const aCodeLengths : array of integer; aStartInx : integer; aCount : integer; const aExtraBits : array of byte; aExtraOffset : integer); function Decode(aLookupBits : integer) : longint; function Encode(aSymbol : integer) : longint; {$IFDEF UseLogging} procedure DebugPrint(aLog : TAbLogger); {$ENDIF} property LookupBitLength : integer read FMaxCodeLen; property Decodes : PAbDfLongintList read FDecodes; property Encodes : PAbDfLongintList read FEncodes; end; var AbStaticLiteralTree : TAbDfDecodeHuffmanTree; AbStaticDistanceTree : TAbDfDecodeHuffmanTree; implementation uses SysUtils; const PowerOfTwo : array [0..dfc_MaxCodeLength] of integer = (1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768); {===Debug helper routine=============================================} {$IFDEF EnableMegaLog} function CodeToStr(aCode : longint; aLen : integer) : string; var i : integer; begin if (aLen = 0) then Result := 'no code' else begin SetLength(Result, 32); FillChar(Result[1], 32, ' '); for i := 32 downto (33-aLen) do begin if Odd(aCode) then Result[i] := '1' else Result[i] := '0'; aCode := aCode shr 1; end; end; end; {$ENDIF} {====================================================================} {===TAbDfDecodeHuffmanTree===========================================} constructor TAbDfDecodeHuffmanTree.Create( aAlphabetSize : integer; aDefMaxCodeLen: integer; aUsage : TAbDfHuffmanUsage); begin {protect against dumb programming mistakes} Assert(aAlphabetSize >= 2, 'TAbDfDecodeHuffmanTree.Create: a huffman tree must be for at least two symbols'); {let the ancestor initialize} inherited Create; {save the alphabet size, etc} FAlphaSize := aAlphabetSize; FDefMaxCodeLen := aDefMaxCodeLen; FUsage := aUsage; {allocate the encoder array (needs to be initialized to zeros)} if (aUsage <> huDecoding) then FEncodes := AllocMem(FAlphaSize * sizeof(longint)); end; {--------} destructor TAbDfDecodeHuffmanTree.Destroy; begin {destroy the codes arrays} if (FDecodes <> nil) then FreeMem(FDecodes); if (FEncodes <> nil) then FreeMem(FEncodes); {let the ancestor die} inherited Destroy; end; {--------} procedure TAbDfDecodeHuffmanTree.Build( const aCodeLengths : array of integer; aStartInx : integer; aCount : integer; const aExtraBits : array of byte; aExtraOffset : integer); const ByteRevTable : array [0..255] of byte = ( $00, $80, $40, $C0, $20, $A0, $60, $E0, $10, $90, $50, $D0, $30, $B0, $70, $F0, $08, $88, $48, $C8, $28, $A8, $68, $E8, $18, $98, $58, $D8, $38, $B8, $78, $F8, $04, $84, $44, $C4, $24, $A4, $64, $E4, $14, $94, $54, $D4, $34, $B4, $74, $F4, $0C, $8C, $4C, $CC, $2C, $AC, $6C, $EC, $1C, $9C, $5C, $DC, $3C, $BC, $7C, $FC, $02, $82, $42, $C2, $22, $A2, $62, $E2, $12, $92, $52, $D2, $32, $B2, $72, $F2, $0A, $8A, $4A, $CA, $2A, $AA, $6A, $EA, $1A, $9A, $5A, $DA, $3A, $BA, $7A, $FA, $06, $86, $46, $C6, $26, $A6, $66, $E6, $16, $96, $56, $D6, $36, $B6, $76, $F6, $0E, $8E, $4E, $CE, $2E, $AE, $6E, $EE, $1E, $9E, $5E, $DE, $3E, $BE, $7E, $FE, $01, $81, $41, $C1, $21, $A1, $61, $E1, $11, $91, $51, $D1, $31, $B1, $71, $F1, $09, $89, $49, $C9, $29, $A9, $69, $E9, $19, $99, $59, $D9, $39, $B9, $79, $F9, $05, $85, $45, $C5, $25, $A5, $65, $E5, $15, $95, $55, $D5, $35, $B5, $75, $F5, $0D, $8D, $4D, $CD, $2D, $AD, $6D, $ED, $1D, $9D, $5D, $DD, $3D, $BD, $7D, $FD, $03, $83, $43, $C3, $23, $A3, $63, $E3, $13, $93, $53, $D3, $33, $B3, $73, $F3, $0B, $8B, $4B, $CB, $2B, $AB, $6B, $EB, $1B, $9B, $5B, $DB, $3B, $BB, $7B, $FB, $07, $87, $47, $C7, $27, $A7, $67, $E7, $17, $97, $57, $D7, $37, $B7, $77, $F7, $0F, $8F, $4F, $CF, $2F, $AF, $6F, $EF, $1F, $9F, $5F, $DF, $3F, $BF, $7F, $FF); var i : integer; Symbol : integer; LengthCount : array [0..dfc_MaxCodeLength] of integer; NextCode : array [0..dfc_MaxCodeLength] of integer; Code : longint; CodeLen : integer; CodeData : longint; DecoderLen : integer; CodeIncr : integer; Decodes : PAbDfLongintList; Encodes : PAbDfLongintList; {$IFDEF CPU386} DecodesEnd : pointer; {$ENDIF} TablePtr : pointer; begin {count the number of instances of each code length and calculate the maximum code length at the same time} FillChar(LengthCount, sizeof(LengthCount), 0); FMaxCodeLen := 0; for i := 0 to pred(aCount) do begin CodeLen := aCodeLengths[i + aStartInx]; Assert((CodeLen <= FDefMaxCodeLen), Format('TAbDfDecodeHuffmanTree.Build: a code length is greater than %d', [FDefMaxCodeLen])); if (CodeLen > FMaxCodeLen) then FMaxCodeLen := CodeLen; inc(LengthCount[CodeLen]); end; {now we know the maximum code length we can allocate our decoder array} {$IFNDEF CPU386} DecoderLen := 0; {$ENDIF} if (FUsage <> huEncoding) then begin DecoderLen := PowerOfTwo[FMaxCodeLen]; GetMem(FDecodes, DecoderLen * sizeof(longint)); {$IFDEF CPU386} DecodesEnd := PAnsiChar(FDecodes) + (DecoderLen * sizeof(longint)); {$ENDIF} {$IFOPT C+} FillChar(FDecodes^, DecoderLen * sizeof(longint), $FF); FMask := not (DecoderLen - 1); {$ENDIF} end; {calculate the start codes for each code length} Code := 0; LengthCount[0] := 0; for i := 1 to FDefMaxCodeLen do begin Code := (Code + LengthCount[i-1]) shl 1; NextCode[i] := Code; end; {for speed and convenience} Decodes := FDecodes; Encodes := FEncodes; TablePtr := @ByteRevTable; {for each symbol...} for Symbol := 0 to pred(aCount) do begin {calculate the code length} CodeLen := aCodeLengths[Symbol + aStartInx]; {if the code length were zero, just set the relevant entry in the encoder array; the decoder array doesn't need anything} if (CodeLen = 0) then begin if (FUsage <> huDecoding) then Encodes^[Symbol] := -1 end {otherwise we need to fill elements in both the encoder and decoder arrays} else begin {calculate *reversed* code} Code := NextCode[CodeLen]; {$IFDEF CPU386} asm push esi mov eax, Code mov esi, TablePtr xor ecx, ecx xor edx, edx mov cl, ah mov dl, al mov al, [esi+ecx] mov ah, [esi+edx] mov ecx, 16 pop esi sub ecx, CodeLen shr eax, cl mov Code, eax end; {$ELSE} CodeData:= Code; LongRec(Code).Bytes[1]:= ByteRevTable[LongRec(CodeData).Bytes[0]]; LongRec(Code).Bytes[0]:= ByteRevTable[LongRec(CodeData).Bytes[1]]; Code:= Code shr (16-CodeLen); {$ENDIF} {set the code data (bit count, extra bits required, symbol), everywhere the reversed code would appear in the decoder array; set the code data in the encoder array as well} if (Symbol >= aExtraOffset) then begin if (FUsage <> huEncoding) then CodeData := Symbol + { symbol} (CodeLen shl 16) + { code length} (aExtraBits[Symbol-aExtraOffset] shl 24); { extra bits required} if (FUsage <> huDecoding) then Encodes^[Symbol] := Code + { code} (CodeLen shl 16) + { code length} (aExtraBits[Symbol-aExtraOffset] shl 24) { extra bits required} end else begin if (FUsage <> huEncoding) then CodeData := Symbol + { symbol} (CodeLen shl 16); { code length} if (FUsage <> huDecoding) then Encodes^[Symbol] := Code + { code} (CodeLen shl 16); { code length} end; {OPTIMIZATION NOTE: the following code CodeIncr := PowerOfTwo[CodeLen]; while Code < DecoderLen do begin Decodes^[Code] := CodeData; inc(Code, CodeIncr); end; was replaced by the asm code below to improve the speed. The code in the loop is the big time sink in this routine so it was best to replace it.} if (FUsage <> huEncoding) then begin {$IFDEF CPU386} CodeIncr := PowerOfTwo[CodeLen] * sizeof(longint); asm push edi { save edi} mov eax, Decodes { get the Decodes array} mov edi, DecodesEnd { get the end of the Decodes array} mov edx, Code { get Code and..} shl edx, 1 { ..multiply by 4} shl edx, 1 add eax, edx { eax => first element to be set} mov edx, CodeData { get the CodeData} mov ecx, CodeIncr { get the increment per loop} @@1: mov [eax], edx { set the element} add eax, ecx { move to the next element} cmp eax, edi { if we haven't gone past the end..} jl @@1 { ..go back for the next one} pop edi { retrieve edi} end; {$ELSE} CodeIncr := PowerOfTwo[CodeLen]; while Code < DecoderLen do begin Decodes^[Code] := CodeData; inc(Code, CodeIncr); end; {$ENDIF} end; {we've used this code up for this symbol, so increment for the next symbol at this code length} inc(NextCode[CodeLen]); end; end; end; {--------} {$IFDEF UseLogging} procedure TAbDfDecodeHuffmanTree.DebugPrint(aLog : TAbLogger); {$IFDEF EnableMegaLog} var i : integer; Code : longint; {$ENDIF} begin {to print the huffman tree, we must have a logger...} Assert(aLog <> nil, 'TAbDfDecodeHuffmanTree.DebugPrint needs a logger object to which to print'); if (FUsage <> huEncoding) then begin aLog.WriteLine('Huffman decoder array'); aLog.WriteLine(Format('Alphabet size: %d', [FAlphaSize])); aLog.WriteLine(Format('Max codelength: %d', [FMaxCodeLen])); {$IFDEF EnableMegaLog} aLog.WriteLine('Index Len Xtra Symbol Reversed Code'); for i := 0 to pred(PowerOfTwo[FMaxCodeLen]) do begin Code := FDecodes^[i]; if (Code = -1) then aLog.WriteLine(Format('%5d%49s', [i, 'no code'])) else aLog.WriteLine(Format('%5d%4d%5d%7d%33s', [i, ((Code shr 16) and $FF), ((Code shr 24) and $FF), (Code and $FFFF), CodeToStr(i, ((Code shr 16) and $FF))])); end; aLog.WriteLine('---end decoder array---'); {$ENDIF} end; if (FUsage <> huDecoding) then begin aLog.WriteLine('Huffman encoder array'); aLog.WriteLine(Format('Alphabet size: %d', [FAlphaSize])); {$IFDEF EnableMegaLog} aLog.WriteLine('Symbol Len Xtra Reversed Code'); for i := 0 to pred(FAlphaSize) do begin Code := FEncodes^[i]; if (Code = -1) then aLog.WriteLine(Format('%6d%42s', [i, 'no code'])) else aLog.WriteLine(Format('%6d%4d%5d%33s', [i, ((Code shr 16) and $FF), ((Code shr 24) and $FF), CodeToStr((Code and $FFFF), ((Code shr 16) and $FF))])); end; aLog.WriteLine('---end encoder array---'); {$ENDIF} end; end; {$ENDIF} {--------} function TAbDfDecodeHuffmanTree.Decode(aLookupBits : integer) : longint; begin {protect against dumb programming mistakes (note: FMask only exists if assertions are on)} {$IFOPT C+} Assert((aLookupBits and FMask) = 0, 'TAbDfDecodeHuffmanTree.Decode: trying to decode too many bits, use LookupBitLength property'); {$ENDIF} {return the code data} Result := FDecodes^[aLookupBits]; end; {--------} function TAbDfDecodeHuffmanTree.Encode(aSymbol : integer) : longint; begin {protect against dumb programming mistakes} Assert((0 <= aSymbol) and (aSymbol < FAlphaSize), 'TAbDfDecodeHuffmanTree.Encode: trying to encode a symbol that is not in the alphabet'); {return the code data} Result := FEncodes^[aSymbol]; {if the result is -1, it's another programming mistake: the user is attempting to get a code for a symbol that wasn't being used} Assert(Result <> -1, 'TAbDfDecodeHuffmanTree.Encode: trying to encode a symbol that was not used'); end; {====================================================================} {===BuildStaticTrees=================================================} procedure BuildStaticTrees; var i : integer; CodeLens : array [0..287] of integer; begin {this routine builds the static huffman trees, those whose code lengths are determined by the deflate spec} {the static literal tree first} for i := 0 to 143 do CodeLens[i] := 8; for i := 144 to 255 do CodeLens[i] := 9; for i := 256 to 279 do CodeLens[i] := 7; for i := 280 to 287 do CodeLens[i] := 8; AbStaticLiteralTree := TAbDfDecodeHuffmanTree.Create(288, 15, huBoth); AbStaticLiteralTree.Build(CodeLens, 0, 288, dfc_LitExtraBits, dfc_LitExtraOffset); {the static distance tree afterwards} for i := 0 to 31 do CodeLens[i] := 5; AbStaticDistanceTree := TAbDfDecodeHuffmanTree.Create(32, 15, huBoth); AbStaticDistanceTree.Build(CodeLens, 0, 32, dfc_DistExtraBits, dfc_DistExtraOffset); end; {====================================================================} initialization BuildStaticTrees; finalization AbStaticLiteralTree.Free; AbStaticDistanceTree.Free; end. ================================================ FILE: lib/abbrevia/source/AbDfInW.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbDfInW.pas *} {*********************************************************} {* Deflate input sliding window unit *} {*********************************************************} unit AbDfInW; {$I AbDefine.inc} interface uses Classes, AbDfBase; {Notes: TdfInputWindow implements a sliding window on data for the LZ77 dictionary encoding. The stream passed to the class is automatically read when required to keep the internal buffer fully loaded. } type TAbDfMatch = record maLen : integer; maDist : integer; maLit : AnsiChar; end; type PAbPointerList = ^TAbPointerList; TAbPointerList = array[0..MaxInt div SizeOf(Pointer) - 1] of Pointer; TAbDfInputWindow = class private FAdvanceStart : boolean; FBuffer : PAnsiChar; FBufferEnd : PAnsiChar; FBytesUsed : longint; FChainLen : integer; FHashChains : PAbPointerList; FHashHeads : PAbPointerList; FHashIndex : integer; FChecksum : longint; FCurrent : PAnsiChar; FLookAheadEnd : PAnsiChar; FMaxMatchLen : integer; FMustSlide : boolean; FOnProgress : TAbProgressStep; FSlidePoint : PAnsiChar; FStart : PAnsiChar; FStartOffset : longint; FStream : TStream; FStreamSize : Int64; FUseCRC32 : boolean; FUseDeflate64 : boolean; FWinMask : integer; FWinSize : integer; protected function iwGetChecksum : longint; procedure iwReadFromStream; procedure iwSetCapacity(aValue : longint); procedure iwSlide; public constructor Create(aStream : TStream; aStreamSize : Int64; aWinSize : integer; aChainLength : integer; aUseDeflate64 : boolean; aUseCRC32 : boolean); destructor Destroy; override; procedure Advance(aCount : integer; aHashCount : integer); procedure AdvanceByOne; function FindLongestMatch(aAmpleLength : integer; var aMatch : TAbDfMatch; const aPrevMatch : TAbDfMatch) : boolean; function GetNextChar : AnsiChar; function GetNextKeyLength : integer; function Position : longint; procedure ReadBuffer(var aBuffer; aCount : longint; aOffset : Int64); property ChainLen : integer read FChainLen write FChainLen; property Checksum : longint read iwGetChecksum; property OnProgress : TAbProgressStep read FOnProgress write FOnProgress; end; implementation uses SysUtils; {Notes: Meaning of the internal pointers: |----------+===================+==+--------------------------| | | | | | FBuffer FStart FCurrent FLookAheadEnd FBufferEnd FCurrent is the current match position. The valid data that can be matched is between FStart and FLookAheadEnd, The data between FStart and FCurrent has already been seen; the data between FCurrent and FLookAheadEnd can be used for matching. The buffer size depends on the requested window size (a multiple of 1KB, up to 32KB for deflate, up to 64KB for deflate64) and the lookahead size (up to 258 bytes for deflate and 64KB for deflate64.) The window of data continuously slides to the right, and is slid back to FBuffer whenever FStart reaches a point 16KB away, this point being given by FSlidePoint. The hash table: This is a chained hash table with some peculiarities. First the table itself, FHashHeads. It contains pointers to strings in the window buffer, not to chains. The chains are held is a separate structure, FHashChains. The hash function on the three-character keys is a Rabin-Karp function: ((((Ch1 shl 5) xor Ch2) shl 5) xor Ch3) and $3FFF designed so that a running hash value can be kept and calculated per character. The hash table is $4000 elements long (obviously, given the hash function). On insertion, the previous pointer in the hash table at the calculated index is saved and replaced by the new pointer. The old pointer is saved in the chains array. This has the same number of elements as the sliding window has characters. The pointer is placed at (Ptr and (WindowsSize-1)) overwriting the value that's already there. In this fashion the individual chains in the standard hash table are interwoven with each other in this hash table, like a skein of threads. } const c_HashCount = $4000; {the number of hash entries} c_HashMask = c_HashCount - 1; {a mask for the hash function} c_HashShift = 5; {shift value for the hash function} {===TAbDfInputWindow=================================================} constructor TAbDfInputWindow.Create(aStream : TStream; aStreamSize : Int64; aWinSize : integer; aChainLength : integer; aUseDeflate64 : boolean; aUseCRC32 : boolean); begin {create the ancestor} inherited Create; {save parameters} FStreamSize := aStreamSize; FWinSize := aWinSize; FWinMask := aWinSize - 1; FStream := aStream; FChainLen := aChainLength; FUseDeflate64 := aUseDeflate64; FUseCRC32 := aUseCRC32; if aUseCRC32 then FChecksum := -1 { CRC32 starts off with all bits set } else FCheckSum := 1; { Adler32 starts off with a value of 1 } {set capacity of sliding window} iwSetCapacity(aWinSize); {create the hash table, first the hash table itself (and set all entries to nil)} FHashHeads := AllocMem(c_HashCount * sizeof(pointer)); {..now the chains (there's no need to set the entries to nil, since the chain entries get fed from the head entries before searching)} GetMem(FHashChains, aWinSize * sizeof(pointer)); {read the first chunk of data from the stream} FMustSlide := true; iwReadFromStream; {if there are at least two bytes, prime the hash index} if ((FLookAheadEnd - FBuffer) >= 2) then FHashIndex := ((longint(FBuffer[0]) shl c_HashShift) xor longint(FBuffer[1])) and c_HashMask; end; {--------} destructor TAbDfInputWindow.Destroy; begin {free the hash table} FreeMem(FHashHeads); FreeMem(FHashChains); {free the buffer} FreeMem(FBuffer); {destroy the ancestor} inherited Destroy; end; {--------} procedure TAbDfInputWindow.Advance(aCount : integer; aHashCount : integer); var i : integer; ByteCount : integer; Percent : integer; HashChains: PAbPointerList; HashHeads : PAbPointerList; HashInx : integer; CurPos : PAnsiChar; begin Assert((FLookAheadEnd - FCurrent) >= aCount, 'TAbDfInputWindow.Advance: seem to be advancing into the unknown'); Assert((aHashCount = aCount) or (aHashCount = pred(aCount)), 'TAbDfInputWindow.Advance: the parameters are plain wrong'); {use local var for speed} CurPos := FCurrent; {advance the current pointer if needed} if (aCount > aHashCount) then inc(CurPos); {make sure we update the hash table; remember that the string[3] at the current position has already been added to the hash table (for notes on updating the hash table, see FindLongestMatch} {use local vars for speed} HashChains := FHashChains; HashHeads := FHashHeads; HashInx := FHashIndex; {update the hash table} for i := 0 to pred(aHashCount) do begin HashInx := ((HashInx shl c_HashShift) xor longint(CurPos[2])) and c_HashMask; HashChains^[longint(CurPos) and FWinMask] := HashHeads^[HashInx]; HashHeads^[HashInx] := CurPos; inc(CurPos); end; {replace old values} FHashChains := HashChains; FHashHeads := HashHeads; FHashIndex := HashInx; FCurrent := CurPos; {if we've seen at least FWinSize bytes...} if FAdvanceStart then begin {advance the start of the sliding window} inc(FStart, aCount); inc(FStartOffset, aCount); {check to see if we have advanced into the slide zone} if FMustSlide and (FStart >= FSlidePoint) then iwSlide; end {otherwise check to see if we've seen at least FWinSize bytes} else if ((CurPos - FStart) >= FWinSize) then begin FAdvanceStart := true; {note: we can't advance automatically aCount bytes here, we need to calculate the actual count} ByteCount := (CurPos - FWinSize) - FStart; inc(FStart, ByteCount); inc(FStartOffset, ByteCount); end; {show progress} if Assigned(FOnProgress) then begin inc(FBytesUsed, aCount); if ((FBytesUsed and $FFF) = 0) then begin Percent := Round((100.0 * FBytesUsed) / FStreamSize); FOnProgress(Percent); end; end; {check to see if we have advanced into the slide zone} if (FStart >= FSlidePoint) then iwSlide; end; {--------} procedure TAbDfInputWindow.AdvanceByOne; var Percent : integer; begin {advance the current pointer} inc(FCurrent); {if we've seen at least FWinSize bytes...} if FAdvanceStart then begin {advance the start of the sliding window} inc(FStart, 1); inc(FStartOffset, 1); {check to see if we have advanced into the slide zone} if FMustSlide and (FStart >= FSlidePoint) then iwSlide; end {otherwise check to see if we've seen FWinSize bytes} else if ((FCurrent - FStart) = FWinSize) then FAdvanceStart := true; {show progress} if Assigned(FOnProgress) then begin inc(FBytesUsed, 1); if ((FBytesUsed and $FFF) = 0) then begin Percent := Round((100.0 * FBytesUsed) / FStreamSize); FOnProgress(Percent); end; end; end; {--------} function TAbDfInputWindow.FindLongestMatch(aAmpleLength : integer; var aMatch : TAbDfMatch; const aPrevMatch : TAbDfMatch) : boolean; {Note: this routine implements a greedy algorithm and is by far the time sink for compression. There are two versions, one written in Pascal for understanding, one in assembler for speed. Activate one and only one of the following compiler defines.} {$IFDEF CPU386} {$DEFINE UseGreedyAsm} {$ELSE} {$DEFINE UseGreedyPascal} {$ENDIF} {Check to see that all is correct} {$IFDEF UseGreedyAsm} {$IFDEF UseGreedyPascal} !! Compile Error: only one of the greedy compiler defines can be used {$ENDIF} {$ELSE} {$IFNDEF UseGreedyPascal} !! Compile Error: one of the greedy compiler defines must be used {$ENDIF} {$ENDIF} type PLongint = ^longint; PWord = ^word; var MaxLen : longint; MaxDist : longint; MaxMatch : integer; ChainLen : integer; PrevStrPos : PAnsiChar; CurPos : PAnsiChar; {$IFDEF UseGreedyAsm} CurWord : word; MaxWord : word; {$ENDIF} {$IFDEF UseGreedyPascal} Len : longint; MatchStr : PAnsiChar; CurrentCh : PAnsiChar; CurCh : AnsiChar; MaxCh : AnsiChar; {$ENDIF} begin {calculate the hash index for the current position; using the Rabin-Karp algorithm this is equal to the previous index less the effect of the character just lost plus the effect of the character just gained} CurPos := FCurrent; FHashIndex := ((FHashIndex shl c_HashShift) xor longint(CurPos[2])) and c_HashMask; {get the head of the hash chain: this is the position in the sliding window of the previous 3-character string with this hash value} PrevStrPos := FHashHeads^[FHashIndex]; {set the head of the hash chain equal to our current position} FHashHeads^[FHashIndex] := CurPos; {update the chain itself: set the entry for this position equal to the previous string position} FHashChains^[longint(CurPos) and FWinMask] := PrevStrPos; {calculate the maximum match we could do at this position} MaxMatch := (FLookAheadEnd - CurPos); if (MaxMatch > FMaxMatchLen) then MaxMatch := FMaxMatchLen; if (aAmpleLength > MaxMatch) then aAmpleLength := MaxMatch; {calculate the current match length} if (aPrevMatch.maLen = 0) then MaxLen := 2 else begin if (MaxMatch < aPrevMatch.maLen) then begin Result := false; aMatch.maLen := 0; aMatch.maLit := CurPos^; Exit; end; MaxLen := aPrevMatch.maLen; end; {get the bytes at the current position and at the end of the maximum match we have to better} {$IFDEF UseGreedyAsm} CurWord := PWord(CurPos)^; MaxWord := PWord(CurPos + pred(MaxLen))^; {$ENDIF} {$IFDEF UseGreedyPascal} CurCh := CurPos^; MaxCh := (CurPos + pred(MaxLen))^; {$ENDIF} {set the chain length to search based on the current maximum match (basically: if we've already satisfied the ample length requirement, don't search as far)} if (MaxLen >= aAmpleLength) then ChainLen := FChainLen div 4 else ChainLen := FChainLen; {get ready for the loop} {$IFDEF DefeatWarnings} MaxDist := 0; {$ENDIF} {$IFDEF UseGreedyAsm} { slip into assembler for speed...} asm push ebx { save those registers we should} push esi push edi mov ebx, Self { ebx will store the Self pointer} mov edi, PrevStrPos { edi => previous string} mov esi, CurPos { esi => current string} @@TestThisPosition: { check previous string is in range} or edi, edi je @@Exit cmp edi, [ebx].TAbDfInputWindow.FStart jb @@Exit cmp edi, CurPos jae @@Exit mov ax, [edi] { check previous string starts with same} cmp CurWord, ax { two bytes as current} jne @@GetNextPosition { ..nope, they don't match} mov edx, edi { check previous string ends with same} add edi, MaxLen { two bytes as current (by "ends" we} dec edi { mean the last two bytes at the} mov ax, [edi] { current match length)} cmp MaxWord, ax mov edi, edx jne @@GetNextPosition { ..nope, they don't match} push edi { compare the previous string with the} push esi { current string} mov eax, MaxMatch add edi, 2 { (we've already checked that the first} sub eax, 2 { two characters are the same)} add esi, 2 mov ecx, eax @@CmpQuads: cmp ecx, 4 jb @@CmpSingles mov edx, [esi] cmp edx, [edi] jne @@CmpSingles add esi, 4 add edi, 4 sub ecx, 4 jnz @@CmpQuads jmp @@MatchCheck @@CmpSingles: or ecx, ecx jb @@MatchCheck mov dl, [esi] cmp dl, [edi] jne @@MatchCheck inc esi inc edi dec ecx jnz @@CmpSingles @@MatchCheck: sub eax, ecx add eax, 2 pop esi pop edi cmp eax, MaxLen { have we found a longer match?} jbe @@GetNextPosition { ..no} mov MaxLen, eax { ..yes, so save it} mov eax, esi { calculate the dist for this new match} sub eax, edi mov MaxDist, eax cmp eax, aAmpleLength { if this match is ample enough, exit} jae @@Exit mov eax, esi { calculate the two bytes at the end of} add eax, MaxLen { this new match} dec eax mov ax, [eax] mov MaxWord, ax @@GetNextPosition: mov eax, ChainLen { we've visited one more link on the} dec eax { chain, if that's the last one we} je @@Exit { should visit, exit} mov ChainLen, eax { advance along the chain} mov edx, [ebx].TAbDfInputWindow.FHashChains mov eax, [ebx].TAbDfInputWindow.FWinMask and edi, eax shl edi, 2 mov edi, [edx+edi] jmp @@TestThisPosition @@Exit: pop edi pop esi pop ebx end; {$ENDIF} {$IFDEF UseGreedyPascal} {for all possible hash nodes in the chain...} while (FStart <= PrevStrPos) and (PrevStrPos < CurPos) do begin {if the initial and maximal characters match...} if (PrevStrPos[0] = CurCh) and (PrevStrPos[pred(MaxLen)] = MaxCh) then begin {compare more characters} Len := 1; CurrentCh := CurPos + 1; MatchStr := PrevStrPos + 1; {compare away, but don't go above the maximum length} while (Len < MaxMatch) and (MatchStr^ = CurrentCh^) do begin inc(CurrentCh); inc(MatchStr); inc(Len); end; {have we reached another maximum for the length?} if (Len > MaxLen) then begin MaxLen := Len; {calculate the distance} MaxDist := CurPos - PrevStrPos; MaxCh := CurPos[pred(MaxLen)]; {is the new best length ample enough?} if MaxLen >= aAmpleLength then Break; end; end; {have we reached the end of this chain?} dec(ChainLen); if (ChainLen = 0) then Break; {otherwise move onto the next position} PrevStrPos := FHashChains^[longint(PrevStrPos) and FWinMask]; end; {$ENDIF} {based on the results of our investigation, return the match values} if (MaxLen < 3) or (MaxLen <= aPrevMatch.maLen) then begin Result := false; aMatch.maLen := 0; aMatch.maLit := CurPos^; end else begin Result := true; aMatch.maLen := MaxLen; aMatch.maDist := MaxDist; aMatch.maLit := CurPos^; { just in case...} end; end; {--------} function TAbDfInputWindow.GetNextChar : AnsiChar; begin Result := FCurrent^; inc(FCurrent); end; {--------} function TAbDfInputWindow.GetNextKeyLength : integer; begin Result := FLookAheadEnd - FCurrent; if (Result > 3) then Result := 3; end; {--------} function TAbDfInputWindow.iwGetChecksum : longint; begin {the CRC32 checksum algorithm requires a post-conditioning step after being calculated (the result is NOTted), whereas Adler32 does not} if FUseCRC32 then Result := not FChecksum else Result := FChecksum; end; {--------} procedure TAbDfInputWindow.iwReadFromStream; var BytesRead : longint; BytesToRead : longint; begin {read some more data into the look ahead zone} BytesToRead := FBufferEnd - FLookAheadEnd; BytesRead := FStream.Read(FLookAheadEnd^, BytesToRead); {if nothing was read, we reached the end of the stream; hence there's no more need to slide the window since we have all the data} if (BytesRead = 0) then FMustSlide := false {otherwise something was actually read...} else begin {update the checksum} if FUseCRC32 then AbUpdateCRCBuffer(FChecksum, FLookAheadEnd^, BytesRead) else AbUpdateAdlerBuffer(FChecksum, FLookAheadEnd^, BytesRead); {reposition the pointer for the end of the lookahead area} inc(FLookAheadEnd, BytesRead); end; end; {--------} procedure TAbDfInputWindow.iwSetCapacity(aValue : longint); var ActualSize : integer; begin {calculate the actual size; this will be the value passed in, plus the correct look ahead size, plus 16KB} ActualSize := aValue + (16 * 1024); if FUseDeflate64 then begin inc(ActualSize, dfc_MaxMatchLen64); FMaxMatchLen := dfc_MaxMatchLen64; end else begin inc(ActualSize, dfc_MaxMatchLen); FMaxMatchLen := dfc_MaxMatchLen; end; {get the new buffer} GetMem(FBuffer, ActualSize); {set the other buffer pointers} FStart := FBuffer; FCurrent := FBuffer; FLookAheadEnd := FBuffer; FBufferEnd := FBuffer + ActualSize; FSlidePoint := FBuffer + (16 * 1024); end; {--------} procedure TAbDfInputWindow.iwSlide; type PLongint = ^longint; var i : integer; ByteCount : integer; Buffer : longint; ListItem : PLongint; begin {move current valid data back to the start of the buffer} ByteCount := FLookAheadEnd - FStart; Move(FStart^, FBuffer^, ByteCount); {reset the various pointers} ByteCount := FStart - FBuffer; FStart := FBuffer; dec(FCurrent, ByteCount); dec(FLookAheadEnd, ByteCount); {patch up the hash table: the head pointers} Buffer := longint(FBuffer); ListItem := PLongint(@FHashHeads^[0]); for i := 0 to pred(c_HashCount) do begin dec(ListItem^, ByteCount); if (ListItem^ < Buffer) then ListItem^ := 0; inc(PAnsiChar(ListItem), sizeof(pointer)); end; {..the chain pointers} ListItem := PLongint(@FHashChains^[0]); for i := 0 to pred(FWinSize) do begin dec(ListItem^, ByteCount); if (ListItem^ < Buffer) then ListItem^ := 0; inc(PAnsiChar(ListItem), sizeof(pointer)); end; {now read some more data from the stream} iwReadFromStream; end; {--------} function TAbDfInputWindow.Position : longint; begin Result := (FCurrent - FStart) + FStartOffset; end; {--------} procedure TAbDfInputWindow.ReadBuffer(var aBuffer; aCount : longint; aOffset : Int64); var CurPos : Int64; begin CurPos := FStream.Seek(0, soCurrent); FStream.Seek(aOffSet, soBeginning); FStream.ReadBuffer(aBuffer, aCount); FStream.Seek(CurPos, soBeginning); end; {====================================================================} end. ================================================ FILE: lib/abbrevia/source/AbDfOutW.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbDfOutW.pas *} {*********************************************************} {* Deflate output sliding window *} {*********************************************************} unit AbDfOutW; {$I AbDefine.inc} interface uses Classes, AbDfBase; {Notes: TAbDfOutputWindow implements a sliding window on previously written data for the LZ77 dictionary decoding. AddLiteral will add a literal character at the current position and advance by one. AddLenDist will copy the required number of characters from the given position to the current position, and advance the stream on by the length. The class will periodically update the stream from the internal buffer. For normal Deflate, the internal buffer is 48K + 512 bytes in size. Once there is 48Kb worth of data, 16KB is written to file, and the buffer is shifted left by 16KB. We need to keep the last decoded 32KB in memory at all times. For Deflate64, the internal buffer is 96K + 512 bytes in size. Once there is 96Kb worth of data, 32KB is written to file, and the buffer is shifted left by 32KB. We need to keep the last decoded 64KB in memory at all times. } type TAbDfOutputWindow = class private FBuffer : PAnsiChar; FChecksum : longint; FCurrent : PAnsiChar; FLog : TAbLogger; FPartSize : longint; FSlideCount : integer; FStream : TStream; FStreamPos : longint; FTestOnly : boolean; FUseCRC32 : boolean; FWritePoint : PAnsiChar; protected function swGetChecksum : longint; procedure swWriteToStream(aFlush : boolean); public constructor Create(aStream : TStream; aUseDeflate64 : boolean; aUseCRC32 : boolean; aPartSize : longint; aTestOnly : boolean; aLog : TAbLogger); destructor Destroy; override; procedure AddBuffer(var aBuffer; aCount : integer); procedure AddLiteral(aCh : AnsiChar); procedure AddLenDist(aLen : integer; aDist : integer); function Position : longint; property Checksum : longint read swGetChecksum; property Log : TAbLogger read FLog; end; implementation uses SysUtils; {Notes: Meaning of the internal pointers: |==============================+------------------------+----| | | | FBuffer FCurrent FWritePoint Once FCurrent reaches or exceeds FWritePoint, FSlideCount bytes of data from FBuffer are written to the stream and the remaining data is moved back FSlideCount bytes, moving FCurrent along with it as well. } {===TAbDfOutputWindow==================================================} constructor TAbDfOutputWindow.Create(aStream : TStream; aUseDeflate64 : boolean; aUseCRC32 : boolean; aPartSize : longint; aTestOnly : boolean; aLog : TAbLogger); var Size : integer; LookAheadSize : integer; begin {allow the ancestor to initialize} inherited Create; {save parameters} FLog := aLog; FStream := aStream; FTestOnly := aTestOnly; if (aPartSize <= 0) then FPartSize := 0 else FPartSize := aPartSize; FUseCRC32 := aUseCRC32; if aUseCRC32 then FChecksum := -1 { CRC32 starts off with all bits set} else FCheckSum := 1; { Adler32 starts off with a value of 1} {set capacity of sliding window} if aUseDeflate64 then begin Size := 96 * 1024; FSlideCount := 32 * 1024; LookAheadSize := 64 * 1024; end else begin Size := 64 * 1024; FSlideCount := 32 * 1024; LookAheadSize := 258; end; GetMem(FBuffer, Size + LookAheadSize); {set the other internal pointers} FCurrent := FBuffer; FWritePoint := FBuffer + Size; if (FPartSize > Size) then FPartSize := Size; end; {--------} destructor TAbDfOutputWindow.Destroy; begin {write remaining data and free the buffer} if (FBuffer <> nil) then begin if (FCurrent <> FBuffer) then swWriteToStream(true); FreeMem(FBuffer); end; {destroy the ancestor} inherited Destroy; end; {--------} procedure TAbDfOutputWindow.AddBuffer(var aBuffer; aCount : integer); var Buffer : PAnsiChar; BytesToWrite : integer; begin {if we've advanced to the point when we need to write, do so} if (FCurrent >= FWritePoint) then swWriteToStream(false); {cast the user buffer to a PChar, it's easier to use} Buffer := @aBuffer; {calculate the number of bytes to copy} BytesToWrite := FWritePoint - FCurrent; if (BytesToWrite > aCount) then BytesToWrite := aCount; {move this block of bytes} Move(Buffer^, FCurrent^, BytesToWrite); {advance pointers and counters} inc(FCurrent, BytesToWrite); dec(aCount, BytesToWrite); {while there is still data to copy...} while (aCount > 0) do begin {advance the user buffer pointer} inc(Buffer, BytesToWrite); {write the sliding window chunk to the stream} swWriteToStream(false); {calculate the number of bytes to copy} BytesToWrite := FWritePoint - FCurrent; if (BytesToWrite > aCount) then BytesToWrite := aCount; {move this block of bytes} Move(Buffer^, FCurrent^, BytesToWrite); {advance pointers and counters} inc(FCurrent, BytesToWrite); dec(aCount, BytesToWrite); end; end; {--------} procedure AddLenDistToLog(aLog : TAbLogger; aPosn : longint; aLen : integer; aDist : integer; aOverLap : boolean); begin {NOTE the reason for this separate routine is to avoid string allocations and try..finally blocks in the main method: an optimization issue} if aOverLap then aLog.WriteLine(Format('%8x Len: %-3d, Dist: %-5d **overlap**', [aPosn, aLen, aDist])) else aLog.WriteLine(Format('%8x Len: %-3d, Dist: %-5d', [aPosn, aLen, aDist])); end; {--------} procedure TAbDfOutputWindow.AddLenDist(aLen : integer; aDist : integer); var i : integer; ToChar : PAnsiChar; FromChar : PAnsiChar; begin {log it} {$IFDEF UseLogging} if (FLog <> nil) then AddLenDistToLog(FLog, Position, aLen, aDist, (aLen > aDist)); {$ENDIF} {if the length to copy is less than the distance, just do a move} if (aLen <= aDist) then begin Move((FCurrent - aDist)^ , FCurrent^, aLen); end {otherwise we have to use a byte-by-byte copy} else begin FromChar := FCurrent - aDist; ToChar := FCurrent; for i := 1 to aLen do begin ToChar^ := FromChar^; inc(FromChar); inc(ToChar); end; end; {increment the current pointer} inc(FCurrent, aLen); {if we've reached the point requested, abort} if (FPartSize > 0) and ((FCurrent - FBuffer) >= FPartSize) then raise EAbPartSizedInflate.Create(''); {NOTE: This exception is expected during detection of .GZ and .TGZ files. (VerifyGZip)} {if we've advanced to the point when we need to write, do so} if (FCurrent >= FWritePoint) then swWriteToStream(false); end; {--------} procedure AddLiteralToLog(aLog : TAbLogger; aPosn : longint; aCh : AnsiChar); begin {NOTE the reason for this separate routine is to avoid string allocations and try..finally blocks in the main method: an optimization issue} if (' ' < aCh) and (aCh <= '~') then aLog.WriteLine(Format('%8x Char: %3d $%2x [%s]', [aPosn, ord(aCh), ord(aCh), aCh])) else aLog.WriteLine(Format('%8x Char: %3d $%2x', [aPosn, ord(aCh), ord(aCh)])); end; {--------} procedure TAbDfOutputWindow.AddLiteral(aCh : AnsiChar); begin {log it} {$IFDEF UseLogging} if (FLog <> nil) then AddLiteralToLog(FLog, Position, aCh); {$ENDIF} {add the literal to the buffer} FCurrent^ := aCh; {increment the current pointer} inc(FCurrent); {if we've reached the point requested, abort} if (FPartSize > 0) and ((FCurrent - FBuffer) >= FPartSize) then raise EAbPartSizedInflate.Create(''); {if we've advanced to the point when we need to write, do so} if (FCurrent >= FWritePoint) then swWriteToStream(false); end; {--------} function TAbDfOutputWindow.Position : longint; begin if FTestOnly then Result := FStreamPos + (FCurrent - FBuffer) else Result := FStream.Position + (FCurrent - FBuffer); end; {--------} function TAbDfOutputWindow.swGetChecksum : longint; begin {since the checksum is calculated by the method that flushes to the stream, make sure any buffered data is written out first} if (FCurrent <> FBuffer) then swWriteToStream(true); {the CRC32 checksum algorithm requires a post-conditioning step after being calculated (the result is NOTted), whereas Adler32 does not} if FUseCRC32 then Result := not FChecksum else Result := FChecksum; end; {--------} procedure TAbDfOutputWindow.swWriteToStream(aFlush : boolean); var FromPtr : PAnsiChar; begin {if the request was to flush, write all remaining data after updating the checksum} if aFlush then begin if FUseCRC32 then AbUpdateCRCBuffer(FChecksum, FBuffer^, FCurrent - FBuffer) else AbUpdateAdlerBuffer(FChecksum, FBuffer^, FCurrent - FBuffer); if FTestOnly then inc(FStreamPos, FCurrent - FBuffer) else FStream.WriteBuffer(FBuffer^, FCurrent - FBuffer); FCurrent := FBuffer; end {otherwise, update the checksum with the data in the sliding window chunk, write it out to the stream, and move the rest of the buffer back} else begin if FUseCRC32 then AbUpdateCRCBuffer(FChecksum, FBuffer^, FSlideCount) else AbUpdateAdlerBuffer(FChecksum, FBuffer^, FSlideCount); if FTestOnly then inc(FStreamPos, FSlideCount) else FStream.WriteBuffer(FBuffer^, FSlideCount); FromPtr := FBuffer + FSlideCount; Move(FromPtr^, FBuffer^, FCurrent - FromPtr); FCurrent := FCurrent - FSlideCount; end; end; {====================================================================} end. ================================================ FILE: lib/abbrevia/source/AbDfPkMg.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbDfPkMg.pas *} {*********************************************************} {* Deflate package-merge algorithm *} {*********************************************************} unit AbDfPkMg; {$I AbDefine.inc} interface uses AbDfBase; procedure GenerateCodeLengths(aMaxCodeLen : integer; const aWeights : array of integer; var aCodeLengths : array of integer; aStartInx : integer; aLog : TAbLogger); implementation type PPkgNode = ^TPkgNode; TPkgNode = packed record pnWeight : integer; pnCount : integer; pnLeft : PPkgNode; pnRight : PPkgNode; end; PPkgNodeList = ^TPkgNodeList; TPkgNodeList = array [0..pred(286 * 2)] of PPkgNode; {Note: the "286" is the number of literal/length symbols, the maximum number of weights we'll be calculating the optimal code lengths for} {===helper routines==================================================} function IsCalcFeasible(aCount : integer; aMaxCodeLen : integer) : boolean; begin {works out if length-limited codes can be calculated for a given number of symbols and the maximum code length} {return whether 2^aMaxCodeLen > aCount} Result := (1 shl aMaxCodeLen) > aCount; end; {--------} procedure QSS(aList : PPkgNodeList; aFirst : integer; aLast : integer); var L, R : integer; Pivot : integer; Temp : pointer; begin {while there are at least two items to sort} while (aFirst < aLast) do begin {the pivot is the middle item} Pivot := aList^[(aFirst+aLast) div 2]^.pnWeight; {set indexes and partition} L := pred(aFirst); R := succ(aLast); while true do begin repeat dec(R); until (aList^[R]^.pnWeight <= Pivot); repeat inc(L); until (aList^[L]^.pnWeight >= Pivot); if (L >= R) then Break; Temp := aList^[L]; aList^[L] := aList^[R]; aList^[R] := Temp; end; {quicksort the first subfile} if (aFirst < R) then QSS(aList, aFirst, R); {quicksort the second subfile - recursion removal} aFirst := succ(R); end; end; {--------} procedure SortList(aList : PPkgNodeList; aCount : integer); begin QSS(aList, 0, pred(aCount)); end; {--------} procedure Accumulate(aNode : PPkgNode); begin while (aNode^.pnLeft <> nil) do begin Accumulate(aNode^.pnLeft); aNode := aNode^.pnRight; end; inc(aNode^.pnCount); end; {====================================================================} {===Interfaced routine===============================================} procedure GenerateCodeLengths(aMaxCodeLen : integer; const aWeights : array of integer; var aCodeLengths : array of integer; aStartInx : integer; aLog : TAbLogger); var i : integer; Bit : integer; WeightCount : integer; OrigList : PPkgNodeList; OrigListCount : integer; MergeList : PPkgNodeList; MergeListCount : integer; PkgList : PPkgNodeList; PkgListCount : integer; OrigInx : integer; PkgInx : integer; Node : PPkgNode; NodeMgr : TAbNodeManager; begin {calculate the number of weights} WeightCount := succ(high(aWeights)); {check for dumb programming errors} Assert((0 < aMaxCodeLen) and (aMaxCodeLen <= 15), 'GenerateCodeLengths: the maximum code length should be in the range 1..15'); Assert((1 <= WeightCount) and (WeightCount <= 286), 'GenerateCodeLengths: the weight array must have 1..286 elements'); Assert(IsCalcFeasible(WeightCount, aMaxCodeLen), 'GenerateCodeLengths: the package-merge algorithm should always be feasible'); {clear the code lengths array} FillChar(aCodeLengths[aStartInx], WeightCount * sizeof(integer), 0); {prepare for the try..finally} OrigList := nil; MergeList := nil; PkgList := nil; NodeMgr := nil; try {create the node manager} NodeMgr := TAbNodeManager.Create(sizeof(TPkgNode)); {create the original list of nodes} GetMem(OrigList, WeightCount * sizeof(PPkgNode)); OrigListCount := 0; for i := 0 to pred(WeightCount) do if (aWeights[i] <> 0) then begin Node := NodeMgr.AllocNode; Node^.pnLeft := nil; { this will indicate a leaf} Node^.pnRight := pointer(i); { the index of the weight} Node^.pnWeight := aWeights[i]; { the weight itself} Node^.pnCount := 1; { how many times used} OrigList^[OrigListCount] := Node; inc(OrigListCount); end; {we need at least 2 items, so make anything less a special case} if (OrigListCount <= 1) then begin {if there are no items at all in the original list, we need to pretend that there is one, since we shall eventually need to calculate a Count-1 value that cannot be negative} if (OrigListCount = 0) then begin aCodeLengths[aStartInx] := 1; Exit; end; {otherwise there is only one item: set its code length directly} for i := 0 to pred(WeightCount) do if (aWeights[i] <> 0) then begin aCodeLengths[aStartInx + i] := 1; Exit; end; end; {there are at least 2 items in the list; so sort the list} SortList(OrigList, OrigListCount); {create the merge and package lists} GetMem(MergeList, OrigListCount * 2 * sizeof(PPkgNode)); GetMem(PkgList, OrigListCount * 2 * sizeof(PPkgNode)); {initialize the merge list to have the same items as the original list} Move(OrigList^, MergeList^, OrigListCount * sizeof(PPkgNode)); MergeListCount := OrigListCount; {do aMaxCodeLen - 2 times...} for Bit := 1 to pred(aMaxCodeLen) do begin {generate the package list from the merge list by grouping pairs from the merge list and adding them to the package list} PkgListCount := 0; for i := 0 to pred(MergeListCount div 2) do begin Node := NodeMgr.AllocNode; Node^.pnLeft := MergeList^[i * 2]; Node^.pnRight := MergeList^[i * 2 + 1]; Node^.pnWeight := Node^.pnLeft^.pnWeight + Node^.pnRight^.pnWeight; {$IFOPT C+} Node^.pnCount := 0; {$ENDIF} PkgList^[PkgListCount] := Node; inc(PkgListCount); end; {merge the original list and the package list} MergeListCount := 0; OrigInx := 0; PkgInx := 0; {note the optimization here: the package list will *always* be last to empty in the merge process since it will have at least one item whose accumulated weight is greater than all of the items in the original list} while (OrigInx < OrigListCount) and (PkgInx < PkgListCount) do begin if (OrigList^[OrigInx]^.pnWeight <= PkgList^[PkgInx]^.pnWeight) then begin MergeList^[MergeListCount] := OrigList^[OrigInx]; inc(OrigInx); end else begin MergeList^[MergeListCount] := PkgList^[PkgInx]; inc(PkgInx); end; inc(MergeListCount); end; if (OrigInx < OrigListCount) then begin Move(OrigList^[OrigInx], MergeList^[MergeListCount], (OrigListCount - OrigInx) * sizeof(PPkgNode)); inc(MergeListCount, (OrigListCount - OrigInx)); end else begin Move(PkgList^[PkgInx], MergeList^[MergeListCount], (PkgListCount - PkgInx) * sizeof(PPkgNode)); inc(MergeListCount, (PkgListCount - PkgInx)); end; end; {calculate the code lengths} for i := 0 to (OrigListCount * 2) - 3 do begin Node := MergeList^[i]; if (Node^.pnLeft <> nil) then Accumulate(Node); end; for i := 0 to pred(OrigListCount) do aCodeLengths[aStartInx + integer(OrigList^[i].pnRight)] := OrigList^[i].pnCount; finally FreeMem(OrigList); FreeMem(MergeList); FreeMem(PkgList); NodeMgr.Free; end; end; {====================================================================} end. ================================================ FILE: lib/abbrevia/source/AbDfStrm.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbDfStrm.pas *} {*********************************************************} {* Deflate streams unit for various streams *} {*********************************************************} unit AbDfStrm; {$I AbDefine.inc} interface uses Classes, AbDfBase, AbDfInW, AbDfHufD; type TAb32bit = longint; { a 32-bit type} PAbDfLitBuckets = ^TAbDfLitBuckets; TAbDfLitBuckets = array [0..285] of integer; PAbDfDistBuckets = ^TAbDfDistBuckets; TAbDfDistBuckets = array [0..31] of integer; PAbDfCodeLenBuckets = ^TAbDfCodeLenBuckets; TAbDfCodeLenBuckets = array [0..18] of integer; const AbExtractMask : array [1..31] of TAb32bit = ($00000001, $00000003, $00000007, $0000000F, $0000001F, $0000003F, $0000007F, $000000FF, $000001FF, $000003FF, $000007FF, $00000FFF, $00001FFF, $00003FFF, $00007FFF, $0000FFFF, $0001FFFF, $0003FFFF, $0007FFFF, $000FFFFF, $001FFFFF, $003FFFFF, $007FFFFF, $00FFFFFF, $01FFFFFF, $03FFFFFF, $07FFFFFF, $0FFFFFFF, $1FFFFFFF, $3FFFFFFF, $7FFFFFFF); type TAbDfInBitStream = class { input bit stream} private FBitBuffer : TAb32bit; FBitsLeft : integer; FBufEnd : PAnsiChar; FBuffer : PAnsiChar; FBufPos : PAnsiChar; FByteCount : longint; FFakeCount : integer; FOnProgress: TAbProgressStep; {$IFOPT C+} FPeekCount : integer; {$ENDIF} FStream : TStream; FStreamSize: longint; protected function ibsFillBuffer : boolean; public constructor Create(aStream : TStream; aOnProgress : TAbProgressStep; aStreamSize : longint); destructor Destroy; override; procedure AlignToByte; procedure DiscardBits(aCount : integer); procedure DiscardMoreBits(aCount : integer); function PeekBits(aCount : integer) : integer; function PeekMoreBits(aCount : integer) : integer; function ReadBit : boolean; function ReadBits(aCount : integer) : integer; procedure ReadBuffer(var aBuffer; aCount : integer); property BitBuffer : TAb32bit read FBitBuffer write FBitBuffer; property BitsLeft : integer read FBitsLeft write FBitsLeft; end; type TAbDfOutBitStream = class { output bit stream} private FBitBuffer : TAb32bit; FBitsUsed : integer; FBufEnd : PAnsiChar; FBuffer : PAnsiChar; FBufPos : PAnsiChar; FStream : TStream; protected procedure obsEmptyBuffer; public constructor Create(aStream : TStream); destructor Destroy; override; procedure AlignToByte; function Position : longint; procedure WriteBit(aBit : boolean); procedure WriteBits(aBits : integer; aCount : integer); procedure WriteBuffer(var aBuffer; aCount : integer); procedure WriteMoreBits(aBits : integer; aCount : integer); property BitBuffer : TAb32bit read FBitBuffer write FBitBuffer; property BitsUsed : integer read FBitsUsed write FBitsUsed; end; type TAbDfLZStream = class { LZ77 token stream} private FCurPos : PAnsiChar; FDistBuckets : PAbDfDistBuckets; FDistCount : integer; FLitBuckets : PAbDfLitBuckets; FLitCount : integer; FLog : TAbLogger; FSlideWin : TAbDfInputWindow; FStartOfs : Int64; FStoredSize : LongWord; FStream : PAnsiChar; FStrmEnd : PAnsiChar; {$IFDEF UseLogging} FSWPos : longint; {$ENDIF} FUseDeflate64: boolean; protected function lzsGetApproxSize : LongWord; function lzsGetStaticSize : integer; function lzsGetStoredSize : integer; function lzsIsFull : boolean; public constructor Create(aSlideWin : TAbDfInputWindow; aUseDeflate64 : boolean; aLog : TAbLogger); destructor Destroy; override; function AddLenDist(aLen : integer; aDist : integer) : boolean; { returns true if the stream is "full"} function AddLiteral(aCh : AnsiChar) : boolean; { returns true if the stream is "full"} procedure Clear; procedure Encode(aBitStrm : TAbDfOutBitStream; aLitTree : TAbDfDecodeHuffmanTree; aDistTree : TAbDfDecodeHuffmanTree; aUseDeflate64 : boolean); procedure Rewind; procedure ReadStoredBuffer(var aBuffer; aCount : integer); property LenDistCount : integer read FDistCount; property LiteralCount : integer read FLitCount; property DistBuckets : PAbDfDistBuckets read FDistBuckets; property LitBuckets : PAbDfLitBuckets read FLitBuckets; property StaticSize : integer read lzsGetStaticSize;{ in bits} property StoredSize : integer read lzsGetStoredSize;{ in bytes} end; type TAbDfCodeLenStream = class { codelength token stream} private FBuckets : PAbDfCodeLenBuckets; FPosition : PAnsiChar; FStream : PAnsiChar; {array [0..285+32*2] of byte;} FStrmEnd : PAnsiChar; protected public constructor Create(aLog : TAbLogger); destructor Destroy; override; procedure Build(const aCodeLens : array of integer; aCount : integer); procedure Encode(aBitStrm : TAbDfOutBitStream; aTree : TAbDfDecodeHuffmanTree); property Buckets : PAbDfCodeLenBuckets read FBuckets; end; implementation uses SysUtils, AbDfXlat; type PAb32bit = ^TAb32bit; const BitStreamBufferSize = 16*1024; {===TAbDfInBitStream=================================================} constructor TAbDfInBitStream.Create(aStream : TStream; aOnProgress : TAbProgressStep; aStreamSize : longint); begin {protect against dumb programming mistakes} Assert(aStream <> nil, 'TAbDfInBitStream.Create: Cannot create a bit stream wrapping a nil stream'); {create the ancestor} inherited Create; {save the stream instance, allocate the buffer} FStream := aStream; GetMem(FBuffer, BitStreamBufferSize); {save the on progress handler} if Assigned(aOnProgress) and (aStreamSize > 0) then begin FOnProgress := aOnProgress; FStreamSize := aStreamSize; end; end; {--------} destructor TAbDfInBitStream.Destroy; begin {if we did some work...} if (FBuffer <> nil) then begin {reposition the underlying stream to the point where we stopped; this position is equal to... the position of the underlying stream, PLUS the number of fake bytes we added, LESS the number of bytes in the buffer, PLUS the position in the buffer, PLUS the number of complete bytes in the bit buffer} FStream.Seek(FStream.Position + FFakeCount - (FBufEnd - FBuffer) + (FBufPos - FBuffer) - (FBitsLeft div 8), soBeginning); {free the buffer} FreeMem(FBuffer); end; {destroy the ancestor} inherited Destroy; end; {--------} procedure TAbDfInBitStream.AlignToByte; begin {get rid of the odd bits by shifting them out of the bit cache} FBitBuffer := FBitBuffer shr (FBitsLeft mod 8); dec(FBitsLeft, FBitsLeft mod 8); end; {--------} procedure TAbDfInBitStream.DiscardBits(aCount : integer); var BitsToGo : integer; begin {aCount comes from a (possibly corrupt) stream, so check that it is the correct range, 1..32} if (aCount <= 0) or (aCount > 32) then raise EAbInternalInflateError.Create( 'count of bits must be between 1 and 32 inclusive [TAbDfInBitStream.DiscardBits]'); {$IFOPT C+} {verify that the count of bits to discard is less than or equal to the recent count from PeekBits--a programming error} Assert((aCount <= FPeekCount), 'TAbDfInBitStream.DiscardBits: discarding more bits than peeked'); {since we're discarding bits already peeked, reset the peek count} FPeekCount := 0; {$ENDIF} {if we have more than enough bits in our bit buffer, update the bitbuffer and the number of bits left} if (aCount <= FBitsLeft) then begin FBitBuffer := FBitBuffer shr aCount; dec(FBitsLeft, aCount); end {otherwise we shall have to read another integer out of the buffer to satisfy the request} else begin {check that there is data in the buffer, if not it's indicates a corrupted stream: PeekBits should have filled it} if (FBufPos = FBufEnd) then raise EAbInternalInflateError.Create( 'no more compressed data in stream [TAbDfInBitStream.DiscardBits]'); {refill the bit buffer} BitsToGo := aCount - FBitsLeft; FBitBuffer := PAb32bit(FBufPos)^; inc(FBufPos, sizeof(TAb32bit)); FBitBuffer := FBitBuffer shr BitsToGo; FBitsLeft := 32 - BitsToGo; end; end; {--------} procedure TAbDfInBitStream.DiscardMoreBits(aCount : integer); var BitsToGo : integer; begin {aCount comes from a (possibly corrupt) stream, so check that it is the correct range, 1..32} if (aCount <= 0) or (aCount > 32) then raise EAbInternalInflateError.Create( 'count of bits must be between 1 and 32 inclusive [TAbDfInBitStream.DiscardMoreBits]'); {$IFOPT C+} {verify that the count of bits to discard is less than or equal to the recent count from PeekBits--a programming error} Assert((aCount <= FPeekCount), 'TAbDfInBitStream.DiscardBits: discarding more bits than peeked'); {since we're discarding bits already peeked, reset the peek count} FPeekCount := 0; {$ENDIF} {check that there is data in the buffer, if not it's indicates a corrupted stream: PeekBits/PeekMoreBits should have filled it} if (FBufPos = FBufEnd) then raise EAbInternalInflateError.Create( 'no more compressed data in stream [TAbDfInBitStream.DiscardBits]'); {refill the bit buffer} BitsToGo := aCount - FBitsLeft; FBitBuffer := PAb32bit(FBufPos)^; inc(FBufPos, sizeof(TAb32bit)); FBitBuffer := FBitBuffer shr BitsToGo; FBitsLeft := 32 - BitsToGo; end; {--------} function TAbDfInBitStream.ibsFillBuffer : boolean; var BytesRead : longint; BytesToRead : longint; i : integer; Percent : integer; Buffer : PAnsiChar; BufferCount : integer; begin {check for dumb programming mistakes: this routine should only be called if there are less than 4 bytes unused in the buffer} Assert((FBufEnd - FBufPos) < sizeof(longint), 'TAbDfInBitStream.ibsFillBuffer: the buffer should be almost empty'); {if there are still 1, 2, or three bytes unused, move them to the front of the buffer} Buffer := FBuffer; while (FBufPos <> FBufEnd) do begin Buffer^ := FBufPos^; inc(FBufPos); inc(Buffer); end; {fill the buffer} BytesToRead := BitStreamBufferSize - (Buffer - FBuffer); BytesRead := FStream.Read(Buffer^, BytesToRead); {reset the internal pointers} FBufPos := FBuffer; FBufEnd := Buffer + BytesRead; BufferCount := FBufEnd - FBuffer; {if, as a result of the read, no data is in the buffer, return false; the caller will decide what to do about the problem} if (BufferCount = 0) then Result := false {otherwise there is data to be processed} else begin Result := true; {if we didn't read anything from the stream, we need to make sure that enough buffer is zeroed out so that reading longint values don't produce (dreadfully) bogus values} if (BytesRead = 0) and ((BufferCount mod 4) <> 0) then begin FFakeCount := 4 - (BufferCount mod 4); for i := 0 to pred(FFakeCount) do begin FBufEnd^ := #0; inc(FBufEnd); end; end; {fire the progress event} if Assigned(FOnProgress) then begin inc(FByteCount, BytesRead); Percent := Round((100.0 * FByteCount) / FStreamSize); FOnProgress(Percent); end; end; end; {--------} function TAbDfInBitStream.PeekBits(aCount : integer) : integer; var BitsToGo : integer; TempBuffer : integer; begin {check that aCount is in the correct range 1..32} Assert((0 <= aCount) and (aCount <= 32), 'TAbDfInBitStream.PeekBits: count of bits must be between 1 and 32 inclusive'); {if we have more than enough bits in our bit buffer, return as many as needed} if (aCount <= FBitsLeft) then Result := FBitBuffer and AbExtractMask[aCount] {otherwise we shall have to read another integer out of the buffer to satisfy the request; note that this will fill the stream buffer if required} else begin BitsToGo := aCount - FBitsLeft; Result := FBitBuffer; if ((FBufEnd - FBufPos) < sizeof(TAb32bit)) then if not ibsFillBuffer then TempBuffer := 0 else TempBuffer := PAb32bit(FBufPos)^ else TempBuffer := PAb32bit(FBufPos)^; Result := Result + ((TempBuffer and AbExtractMask[BitsToGo]) shl FBitsLeft); end; {$IFOPT C+} {save the number of bits peeked for an assertion check later} FPeekCount := aCount; {$ENDIF} end; {--------} function TAbDfInBitStream.PeekMoreBits(aCount : integer) : integer; var BitsToGo : integer; TempBuffer : integer; begin BitsToGo := aCount - FBitsLeft; Result := FBitBuffer; if ((FBufEnd - FBufPos) < sizeof(TAb32bit)) then if not ibsFillBuffer then TempBuffer := 0 else TempBuffer := PAb32bit(FBufPos)^ else TempBuffer := PAb32bit(FBufPos)^; Result := Result + ((TempBuffer and AbExtractMask[BitsToGo]) shl FBitsLeft); end; {--------} function TAbDfInBitStream.ReadBit : boolean; begin if (FBitsLeft = 0) then begin if ((FBufEnd - FBufPos) < sizeof(TAb32bit)) then if not ibsFillBuffer then raise EAbInternalInflateError.Create( 'no more compressed data in stream [TAbDfInBitStream.ReadBit]'); FBitBuffer := PAb32bit(FBufPos)^; inc(FBufPos, sizeof(TAb32bit)); FBitsLeft := 32; end; Result := Odd(FBitBuffer); FBitBuffer := FBitBuffer shr 1; dec(FBitsLeft); end; {--------} function TAbDfInBitStream.ReadBits(aCount : integer) : integer; var BitsToGo : integer; begin {aCount comes from a (possibly corrupt) stream, so check that it is the correct range, 1..16} if (aCount <= 0) or (aCount > 16) then raise EAbInternalInflateError.Create( 'count of bits must be between 1 and 16 inclusive [TAbDfInBitStream.ReadBits]'); {if we have more than enough bits in our bit buffer, return as many as needed, and update the bitbuffer and the number of bits left} if (aCount <= FBitsLeft) then begin Result := FBitBuffer and AbExtractMask[aCount]; FBitBuffer := FBitBuffer shr aCount; dec(FBitsLeft, aCount); end {if we have exactly enough bits in our bit buffer, return them all, and update the bitbuffer and the number of bits left} else if (aCount = FBitsLeft) then begin Result := FBitBuffer; FBitBuffer := 0; FBitsLeft := 0; end {otherwise we shall have to read another integer out of the buffer to satisfy the request} else begin BitsToGo := aCount - FBitsLeft; Result := FBitBuffer; if ((FBufEnd - FBufPos) < sizeof(TAb32bit)) then if not ibsFillBuffer then raise EAbInternalInflateError.Create( 'no more compressed data in stream [TAbDfInBitStream.ReadBits]'); FBitBuffer := PAb32bit(FBufPos)^; inc(FBufPos, sizeof(TAb32bit)); Result := Result + ((FBitBuffer and AbExtractMask[BitsToGo]) shl FBitsLeft); FBitBuffer := FBitBuffer shr BitsToGo; FBitsLeft := 32 - BitsToGo; end; end; {--------} procedure TAbDfInBitStream.ReadBuffer(var aBuffer; aCount : integer); var i : integer; Buffer : PAnsiChar; BytesToRead : integer; BytesInBuffer : integer; begin {this method is designed to read a set of bytes and this can only be done if the stream has been byte aligned--if it isn't, it's a programming error} Assert((FBitsLeft mod 8) = 0, 'TAbDfInBitStream.ReadBuffer. cannot read a buffer unless the stream is byte-aligned'); {get the address of the user buffer as a PChar: easier arithmetic} Buffer := @aBuffer; {if we have some bits left in the bit buffer, we need to copy those first} if (FBitsLeft > 0) then begin BytesToRead := FBitsLeft div 8; for i := 0 to pred(BytesToRead) do begin Buffer^ := AnsiChar(FBitBuffer and $FF); inc(Buffer); FBitBuffer := FBitBuffer shr 8; end; {calculate the count of bytes still to read} dec(aCount, BytesToRead); end; {calculate the number of bytes to copy} BytesInBuffer := FBufEnd - FBufPos; if (aCount <= BytesInBuffer) then BytesToRead := aCount else BytesToRead := BytesInBuffer; {copy the data from our buffer to the user buffer} Move(FBufPos^, Buffer^, BytesToRead); {update variables} dec(aCount, BytesToRead); inc(FBufPos, BytesToRead); {while there is still data to copy, keep on filling our internal buffer and copy it to the user buffer} while (aCount <> 0) do begin {increment the user buffer pointer past the data just copied} inc(Buffer, BytesToRead); {fill our buffer} if not ibsFillBuffer then raise EAbInternalInflateError.Create( 'no more compressed data in stream [TAbDfInBitStream.ReadBuffer]'); {calculate the number of bytes to copy} BytesInBuffer := FBufEnd - FBufPos; if (aCount <= BytesInBuffer) then BytesToRead := aCount else BytesToRead := BytesInBuffer; {copy the data from our buffer to the user buffer} Move(FBufPos^, Buffer^, BytesToRead); {update variables} dec(aCount, BytesToRead); inc(FBufPos, BytesToRead); end; {now we've copied everything over, reset the bit variables: they're empty and need refilling} FBitBuffer := 0; FBitsLeft := 0; end; {====================================================================} {===TAbDfOutBitStream================================================} constructor TAbDfOutBitStream.Create(aStream : TStream); begin {protect against dumb programming mistakes} Assert(aStream <> nil, 'TAbDfOutBitStream.Create: Cannot create a bit stream wrapping a nil stream'); {create the ancestor} inherited Create; {save the stream instance, allocate the buffer} FStream := aStream; GetMem(FBuffer, BitStreamBufferSize); FBufEnd := FBuffer + BitStreamBufferSize; FBufPos := FBuffer; end; {--------} destructor TAbDfOutBitStream.Destroy; var i : integer; begin {if the buffer was allocated...} if (FBuffer <> nil) then begin {if there are still some bits in the bit buffer...} if (FBitsUsed <> 0) then begin {pad the bit buffer to a byte boundary} AlignToByte; {empty the main buffer if there isn't enough room to copy over the 1 to 4 bytes in the bit buffer} if ((FBufEnd - FBufPos) < FBitsUsed div 8) then obsEmptyBuffer; {flush the bit buffer} for i := 1 to (FBitsUsed div 8) do begin FBufPos^ := AnsiChar(FBitBuffer); FBitBuffer := FBitBuffer shr 8; inc(FBufPos); end; end; {if there is some data in the main buffer, empty it} if (FBufPos <> FBuffer) then obsEmptyBuffer; {free the buffer} FreeMem(FBuffer); end; {destroy the ancestor} inherited Destroy; end; {--------} procedure TAbDfOutBitStream.AlignToByte; begin {round up the number of bits used to the nearest 8} FBitsUsed := (FBitsUsed + 7) and $F8; {if the bit buffer is now full, flush it to the main buffer} if (FBitsUsed = 32) then begin if ((FBufEnd - FBufPos) < sizeof(TAb32bit)) then obsEmptyBuffer; PAb32bit(FBufPos)^ := FBitBuffer; inc(FBufPos, sizeof(TAb32bit)); FBitBuffer := 0; FBitsUsed := 0; end; end; {--------} procedure TAbDfOutBitStream.obsEmptyBuffer; var ByteCount : integer; BytesWritten : longint; begin {empty the buffer} ByteCount := FBufPos - FBuffer; BytesWritten := FStream.Write(FBuffer^, ByteCount); {if we couldn't write the correct number of bytes, it's an error} if (BytesWritten <> ByteCount) then raise EAbInternalDeflateError.Create( 'could not write to the output stream [TAbDfInBitStream.obsEmptyBuffer]'); {reset the pointers} FBufPos := FBuffer; end; {--------} function TAbDfOutBitStream.Position : longint; begin Assert(false, 'TAbDfOutBitStream.Position: not implemented yet!'); Result := -1; end; {--------} procedure TAbDfOutBitStream.WriteBit(aBit : boolean); begin {only set the corresponding bit in the bit buffer if the passed bit is set (the bit buffer is set to zero when emptied, so we don't actually have to record clear bits)} if aBit then FBitBuffer := FBitBuffer or (1 shl FBitsUsed); {we've now got one more bit} inc(FBitsUsed); {if the bit buffer is now full, flush it to the main buffer} if (FBitsUsed = 32) then begin if ((FBufEnd - FBufPos) < sizeof(TAb32bit)) then obsEmptyBuffer; PAb32bit(FBufPos)^ := FBitBuffer; inc(FBufPos, sizeof(TAb32bit)); FBitBuffer := 0; FBitsUsed := 0; end; end; {--------} procedure TAbDfOutBitStream.WriteBits(aBits : integer; aCount : integer); begin {protect against programming mistakes...} {..the count should be in the range 1 to 16 (BTW, the latter is only used once: Deflate64 with length symbol 258)} Assert((0 < aCount) and (aCount <= 16), 'TAbDfOutBitStream.WriteBits: aCount should be from 1 to 16'); {..there shouldn't be more than aCount bits} Assert((aBits shr aCount) = 0, 'TAbDfOutBitStream.WriteBits: aBits has more than aCount bits'); {copy as many bits as we can to the bit buffer} FBitBuffer := FBitBuffer or (aBits shl FBitsUsed); {increment the number of bits used} inc(FBitsUsed, aCount); {if we've overshot...} if (FBitsUsed >= 32) then begin {the bit buffer is now full, so flush it} if ((FBufEnd - FBufPos) < sizeof(TAb32bit)) then obsEmptyBuffer; PAb32bit(FBufPos)^ := FBitBuffer; inc(FBufPos, sizeof(TAb32bit)); {patch up the bit buffer and the number of bits used} dec(FBitsUsed, 32); FBitBuffer := aBits shr (aCount - FBitsUsed); end; end; {--------} procedure TAbDfOutBitStream.WriteBuffer(var aBuffer; aCount : integer); var Buffer : PAnsiChar; BytesToCopy : integer; begin {guard against dumb programming errors: we must be byte aligned} Assert((FBitsUsed and $7) = 0, 'TAbDfOutBitStream.WriteBuffer: must be byte aligned'); {use the user buffer as a PChar} Buffer := @aBuffer; {flush the bit buffer to the underlying stream} while (FBitsUsed <> 0) do begin if (FBufEnd = FBufPos) then obsEmptyBuffer; FBufPos^ := AnsiChar(FBitBuffer and $FF); inc(FBufPos); FBitBuffer := FBitBuffer shr 8; dec(FBitsUsed, 8); end; {copy over the data to the underlying stream} BytesToCopy := FBufEnd - FBufPos; if (BytesToCopy > aCount) then BytesToCopy := aCount; Move(Buffer^, FBufPos^, BytesToCopy); inc(FBufPos, BytesToCopy); dec(aCount, BytesToCopy); while (aCount <> 0) do begin inc(Buffer, BytesToCopy); obsEmptyBuffer; BytesToCopy := FBufEnd - FBufPos; if (BytesToCopy > aCount) then BytesToCopy := aCount; Move(Buffer^, FBufPos^, BytesToCopy); inc(FBufPos, BytesToCopy); dec(aCount, BytesToCopy); end; {finish with a flushed buffer} obsEmptyBuffer; end; {--------} procedure TAbDfOutBitStream.WriteMoreBits(aBits : integer; aCount : integer); begin {the bit buffer is now full, so flush it} if ((FBufEnd - FBufPos) < sizeof(TAb32bit)) then obsEmptyBuffer; PAb32bit(FBufPos)^ := FBitBuffer; inc(FBufPos, sizeof(TAb32bit)); {patch up the bit buffer and the number of bits used} dec(FBitsUsed, 32); FBitBuffer := aBits shr (aCount - FBitsUsed); end; {====================================================================} {===TAbDfLZStream====================================================} const {Implementation note: this stream size has been chosen so that if the data must be stored, a block size of about 64K will result} StreamSize = 160 * 1024; type PWord = ^word; {--------} constructor TAbDfLZStream.Create(aSlideWin : TAbDfInputWindow; aUseDeflate64 : boolean; aLog : TAbLogger); begin {create the ancestor} inherited Create; {save the sliding window and the logger} FSlideWin := aSlideWin; FUseDeflate64 := aUseDeflate64; FLog := aLog; {create the buckets} New(FDistBuckets); New(FLitBuckets); {create the memory stream, allocate its buffer, position at start} GetMem(FStream, StreamSize); Clear; end; {--------} destructor TAbDfLZStream.Destroy; begin {free the buckets} if (FDistBuckets <> nil) then Dispose(FDistBuckets); if (FLitBuckets <> nil) then Dispose(FLitBuckets); {free the memory stream} if (FStream <> nil) then FreeMem(FStream); {destroy the ancestor} inherited Destroy; end; {--------} {$IFDEF UseLogging} procedure AddLenDistToLog(aLog : TAbLogger; aPosn : longint; aLen : integer; aDist : integer; aOverLap : boolean); begin {NOTE the reason for this separate routine is to avoid string allocations and try..finally blocks in the main method: an optimization issue} if aOverLap then aLog.WriteLine(Format('%8x Len: %-3d, Dist: %-5d **overlap**', [aPosn, aLen, aDist])) else aLog.WriteLine(Format('%8x Len: %-3d, Dist: %-5d', [aPosn, aLen, aDist])); end; {$ENDIF} {--------} function TAbDfLZStream.AddLenDist(aLen : integer; aDist : integer) : boolean; var LenSymbol : integer; DistSymbol : integer; CurPos : PAnsiChar; begin {$IFDEF UseLogging} {log it} if (FLog <> nil) then begin if (aLen > aDist) then AddLenDistToLog(FLog, FSWPos, aLen, aDist, true) else AddLenDistToLog(FLog, FSWPos, aLen, aDist, false); inc(FSWPos, aLen); end; {$ENDIF} {write a length/distance record to the stream} CurPos := FCurPos; CurPos^ := AnsiChar(false); inc(CurPos); PWord(CurPos)^ := word(aLen - 1); inc(CurPos, sizeof(word)); PWord(CurPos)^ := word(aDist - 1); inc(CurPos, sizeof(word)); FCurPos := CurPos; {increment the various counters} inc(FDistCount); inc(FStoredSize, aLen); {convert the length and distance to their symbols} {$IFOPT C+} {if Assertions are on} LenSymbol := AbSymbolTranslator.TranslateLength(aLen); DistSymbol := AbSymbolTranslator.TranslateDistance(aDist); {$ELSE} if (3 <= aLen) and (aLen <= 258) then LenSymbol := AbSymbolTranslator.LenSymbols[aLen-3] + 257 else LenSymbol := 285; if (aDist <= 256) then DistSymbol := AbSymbolTranslator.ShortDistSymbols[aDist - 1] else if (aDist <= 32768) then DistSymbol := AbSymbolTranslator.MediumDistSymbols[((aDist - 1) div 128) - 2] else DistSymbol := AbSymbolTranslator.LongDistSymbols[((aDist - 1) div 16384) - 2]; {$ENDIF} {increment the buckets} inc(FLitBuckets^[LenSymbol]); inc(FDistBuckets^[DistSymbol]); {return whether the stream is full and needs encoding} Result := lzsIsFull; end; {--------} {$IFDEF UseLogging} procedure AddLiteralToLog(aLog : TAbLogger; aPosn : longint; aCh : AnsiChar); begin {NOTE the reason for this separate routine is to avoid string allocations and try..finally blocks in the main method: an optimization issue} if (' ' < aCh) and (aCh <= '~') then aLog.WriteLine(Format('%8x Char: %3d $%2x [%s]', [aPosn, ord(aCh), ord(aCh), aCh])) else aLog.WriteLine(Format('%8x Char: %3d $%2x', [aPosn, ord(aCh), ord(aCh)])); end; {$ENDIF} {--------} function TAbDfLZStream.AddLiteral(aCh : AnsiChar) : boolean; var CurPos : PAnsiChar; begin {$IFDEF UseLogging} {log it} if (FLog <> nil) then begin AddLiteralToLog(FLog, FSWPos, aCh); inc(FSWPos); end; {$ENDIF} {write a literal to the internal stream} CurPos := FCurPos; CurPos^ := AnsiChar(true); inc(CurPos); CurPos^ := aCh; inc(CurPos); FCurPos := CurPos; {increment the various counters} inc(FLitCount); inc(FLitBuckets^[byte(aCh)]); inc(FStoredSize); {return whether the stream is full and needs encoding} Result := lzsIsFull; end; {--------} procedure TAbDfLZStream.Clear; begin {position the stream at the start} Rewind; {reset all variables} FStrmEnd := nil; FLitCount := 0; FDistCount := 0; FStartOfs := FSlideWin.Position; FStoredSize := 0; {$IFDEF UseLogging} FSWPos := FStartOfs; {$ENDIF} {reset the buckets} FillChar(FLitBuckets^, sizeof(FLitBuckets^), 0); FLitBuckets^[256] := 1; { end-of-block marker: it's always there...} FillChar(FDistBuckets^, sizeof(FDistBuckets^), 0); end; {--------} procedure TAbDfLZStream.Encode(aBitStrm : TAbDfOutBitStream; aLitTree : TAbDfDecodeHuffmanTree; aDistTree : TAbDfDecodeHuffmanTree; aUseDeflate64 : boolean); var Len : integer; Dist : integer; Symbol : integer; CurPos : PAnsiChar; StrmEnd : PAnsiChar; Code : longint; ExtraBits : longint; begin {rewind the LZ77 stream} Rewind; {for speed use local variables} CurPos := FCurPos; StrmEnd := FStrmEnd; {while there are still items in the stream...} while (CurPos < StrmEnd) do begin {if the next item is a literal...} if boolean(CurPos^) then begin {encode the literal character as a symbol} inc(CurPos); {$IFOPT C+} {if Assertions are on} Code := aLitTree.Encode(byte(CurPos^)); {$ELSE} Code := aLitTree.Encodes^[byte(CurPos^)]; {$ENDIF} inc(CurPos); {write the code out to the bit stream} {$IFOPT C+} aBitStrm.WriteBits(Code and $FFFF, (Code shr 16) and $FF); {$ELSE} with aBitStrm do begin BitBuffer := BitBuffer or ((Code and $FFFF) shl BitsUsed); BitsUsed := BitsUsed + ((Code shr 16) and $FF); if (BitsUsed >= 32) then WriteMoreBits(Code and $FFFF, (Code shr 16) and $FF); end; {$ENDIF} end {otherwise it's a length/distance pair} else begin {DO THE LENGTH FIRST-------------------------------------------} {get the length from the stream} inc(CurPos); Len := integer(PWord(CurPos)^) + 1; inc(CurPos, sizeof(word)); {translate it to a symbol and convert that to a code using the literal/length huffman tree} {$IFOPT C+} {if Assertions are on} Symbol := AbSymbolTranslator.TranslateLength(Len); Code := aLitTree.Encode(Symbol); {$ELSE} if (3 <= Len) and (Len <= 258) then Symbol := AbSymbolTranslator.LenSymbols[Len-3] + 257 else Symbol := 285; Code := aLitTree.Encodes^[Symbol]; {$ENDIF} {output the length code} {$IFOPT C+} aBitStrm.WriteBits(Code and $FFFF, (Code shr 16) and $FF); {$ELSE} with aBitStrm do begin BitBuffer := BitBuffer or ((Code and $FFFF) shl BitsUsed); BitsUsed := BitsUsed + ((Code shr 16) and $FF); if (BitsUsed >= 32) then WriteMoreBits(Code and $FFFF, (Code shr 16) and $FF); end; {$ENDIF} {if the length symbol were 285, its definition changes from Deflate to Deflate64, so make it a special case: for Deflate there are no extra bits, for Deflate64 output the (length - 3) as 16 bits} if (Symbol = 285) then begin if aUseDeflate64 then begin {$IFOPT C+} aBitStrm.WriteBits(Len - 3, 16); {$ELSE} with aBitStrm do begin BitBuffer := BitBuffer or ((Len - 3) shl BitsUsed); BitsUsed := BitsUsed + 16; if (BitsUsed >= 32) then WriteMoreBits(Len - 3, 16); end; {$ENDIF} end; end {otherwise if there are extra bits to be output for this length, calculate them and output them} else begin ExtraBits := Code shr 24; if (ExtraBits <> 0) then begin {$IFOPT C+} aBitStrm.WriteBits((Len - dfc_LengthBase[Symbol - 257]), ExtraBits); {$ELSE} with aBitStrm do begin BitBuffer := BitBuffer or ((Len - dfc_LengthBase[Symbol - 257]) shl BitsUsed); BitsUsed := BitsUsed + ExtraBits; if (BitsUsed >= 32) then WriteMoreBits((Len - dfc_LengthBase[Symbol - 257]), ExtraBits); end; {$ENDIF} end; end; {DO THE DISTANCE NEXT------------------------------------------} {get the distance from the stream} Dist := integer(PWord(CurPos)^) + 1; inc(CurPos, sizeof(word)); {translate it to a symbol and convert that to a code using the distance huffman tree} {$IFOPT C+} {if Assertions are on} Symbol := AbSymbolTranslator.TranslateDistance(Dist); Assert(aUseDeflate64 or (Symbol < 30), 'TAbDfLZStream.Encode: a Deflate64 distance symbol has been generated for Deflate'); Code := aDistTree.Encode(Symbol); {$ELSE} if (Dist <= 256) then Symbol := AbSymbolTranslator.ShortDistSymbols[Dist - 1] else if (Dist <= 32768) then Symbol := AbSymbolTranslator.MediumDistSymbols[((Dist - 1) div 128) - 2] else Symbol := AbSymbolTranslator.LongDistSymbols[((Dist - 1) div 16384) - 2]; Code := aDistTree.Encodes^[Symbol]; {$ENDIF} {output the distance code} {$IFOPT C+} aBitStrm.WriteBits(Code and $FFFF, (Code shr 16) and $FF); {$ELSE} with aBitStrm do begin BitBuffer := BitBuffer or ((Code and $FFFF) shl BitsUsed); BitsUsed := BitsUsed + ((Code shr 16) and $FF); if (BitsUsed >= 32) then WriteMoreBits(Code and $FFFF, (Code shr 16) and $FF); end; {$ENDIF} {if there are extra bits to be output for this distance, calculate them and output them} ExtraBits := Code shr 24; if (ExtraBits <> 0) then begin {$IFOPT C+} aBitStrm.WriteBits((Dist - dfc_DistanceBase[Symbol]), ExtraBits); {$ELSE} with aBitStrm do begin BitBuffer := BitBuffer or ((Dist - dfc_DistanceBase[Symbol]) shl BitsUsed); BitsUsed := BitsUsed + ExtraBits; if (BitsUsed >= 32) then WriteMoreBits((Dist - dfc_DistanceBase[Symbol]), ExtraBits); end; {$ENDIF} end; end; end; {clear the stream; ready for some more items} { Clear;} end; {--------} function TAbDfLZStream.lzsGetApproxSize : LongWord; var i : integer; begin {note: calculates an approximate compressed size without taking too long about it. The average encoded bit length for literals and lengths is assumed to be 8. Distances are assumed to follow the static tree definition (ie, 5 bits per distance, plus any extra bits). There are FLitCount literals, FDistCount lengths, and FDistCount distances} Result := (13 * FDistCount) + (8 * FLitCount); for i := 4 to 31 do inc(Result, FDistBuckets^[i] * dfc_DistExtraBits[i]); Result := Result div 8; end; {--------} function TAbDfLZStream.lzsGetStaticSize : integer; var i : integer; begin Result := 0; for i := 0 to 143 do inc(Result, FLitBuckets^[i] * 8); for i := 144 to 255 do inc(Result, FLitBuckets^[i] * 9); inc(Result, FLitBuckets^[256] * 7); for i := 257 to 279 do inc(Result, FLitBuckets^[i] * (7 + dfc_LitExtraBits[i - dfc_LitExtraOffset])); for i := 280 to 284 do inc(Result, FLitBuckets^[i] * (8 + dfc_LitExtraBits[i - dfc_LitExtraOffset])); if FUseDeflate64 then inc(Result, FLitBuckets^[285] * (8 + 16)) else inc(Result, FLitBuckets^[285] * 8); for i := 0 to 31 do inc(Result, FDistBuckets^[i] * (5 + dfc_DistExtraBits[i])); end; {--------} function TAbDfLZStream.lzsGetStoredSize : integer; begin Result := FStoredSize; {Result := FSlideWin.Position - FStartOfs;} end; {--------} function TAbDfLZStream.lzsIsFull : boolean; begin {if the number of hits on the (eventual) literal tree is a multiple of 8192, the stream is full if the majority were straight literals and we're getting approx 50% compression} if (((FLitCount + FDistCount) and $1FFF) = 0) then begin Result := (FDistCount < FLitCount) and (lzsGetApproxSize < (FStoredSize div 2)); if Result then Exit; end; {otherwise the stream is full if the number of hits on the literal tree or on the distance tree is 32768} { Result := (FCurPos - FStream) > (StreamSIze - 100);} Result := (FDistCount >= 32768) or ((FLitCount + FDistCount) >= 32768); end; {--------} procedure TAbDfLZStream.ReadStoredBuffer(var aBuffer; aCount : integer); begin FSlideWin.ReadBuffer(aBuffer, aCount, FStartOfs); inc(FStartOfs, aCount); end; {--------} procedure TAbDfLZStream.Rewind; begin {position the stream at the beginning} FStrmEnd := FCurPos; FCurPos := FStream; end; {====================================================================} {===TAbDfCodeLenStream===============================================} constructor TAbDfCodeLenStream.Create(aLog : TAbLogger); begin {create the ancestor} inherited Create; {allocate the stream (to contain all literals and distances and possible extra data} GetMem(FStream, (285 + 32) * 2); FPosition := FStream; {allocate the buckets} FBuckets := AllocMem(sizeof(TAbDfCodeLenBuckets)); end; {--------} destructor TAbDfCodeLenStream.Destroy; begin {free the stream} if (FStream <> nil) then FreeMem(FStream); {free the buckets} if (FBuckets <> nil) then Dispose(FBuckets); {destroy the ancestor} inherited Destroy; end; {--------} procedure TAbDfCodeLenStream.Build(const aCodeLens : array of integer; aCount : integer); var i : integer; State : (ScanStart, ScanNormal, Got2nd, Got3rd); Count : integer; ThisCount : integer; CodeLen : integer; PrevCodeLen : integer; CurPos : PAnsiChar; Buckets : PAbDfCodeLenBuckets; begin {start the automaton} State := ScanStart; CurPos := FStream; Buckets := FBuckets; Count := 0; PrevCodeLen := 0; {for all the codelengths in the array (plus a fake one at the end to ensure all codeslengths are counted)...} for i := 0 to aCount do begin {get the current codelength} if (i = aCount) then CodeLen := -1 else CodeLen := aCodeLens[i]; {switch based on the state...} case State of ScanStart : begin PrevCodeLen := CodeLen; State := ScanNormal; end; ScanNormal : begin {if the current code is the same as the previous, move to the next state} if (CodeLen = PrevCodeLen) then State := Got2nd {otherwise output the previous code} else begin CurPos^ := AnsiChar(PrevCodeLen); inc(CurPos); inc(Buckets^[PrevCodeLen]); PrevCodeLen := CodeLen; end; end; Got2nd : begin {if the current code is the same as the previous, move to the next state; we now have three similar codes in a row} if (CodeLen = PrevCodeLen) then begin State := Got3rd; Count := 3; end {otherwise output the previous two similar codes, move back to the initial state} else begin CurPos^ := AnsiChar(PrevCodeLen); inc(CurPos); CurPos^ := AnsiChar(PrevCodeLen); inc(CurPos); inc(Buckets^[PrevCodeLen], 2); PrevCodeLen := CodeLen; State := ScanNormal; end; end; Got3rd: begin {if the current code is the same as the previous, increment the count of similar codes} if (CodeLen = PrevCodeLen) then inc(Count) {otherwise we need to output the repeat values...} else begin {if the previous code were a zero code...} if (PrevCodeLen = 0) then begin {while there are zero codes to be output...} while (Count <> 0) do begin {if there are less than three zero codes, output them individually} if (Count < 3) then begin while (Count <> 0) do begin CurPos^ := #0; inc(CurPos); inc(Buckets^[0]); dec(Count); end; end {if there are less than 11 successive zero codes, output a 17 code and the count of zeros} else if (Count < 11) then begin CurPos^ := #17; inc(CurPos); inc(Buckets^[17]); CurPos^ := AnsiChar(Count - 3); inc(CurPos); Count := 0; end {otherwise output an 18 code and the count of zeros} else begin ThisCount := Count; if (ThisCount > 138) then ThisCount := 138; CurPos^ := #18; inc(CurPos); inc(Buckets^[18]); CurPos^ := AnsiChar(ThisCount - 11); inc(CurPos); dec(Count, ThisCount); end; end; end {otherwise the previous code was a non-zero code...} else begin {output the first code} CurPos^ := AnsiChar(PrevCodeLen); inc(CurPos); inc(Buckets^[PrevCodeLen]); dec(Count); {while there are more codes to be output...} while (Count <> 0) do begin {if there are less than three codes, output them individually} if (Count < 3) then begin while (Count <> 0) do begin CurPos^ := AnsiChar(PrevCodeLen); inc(CurPos); inc(Buckets^[PrevCodeLen]); dec(Count); end; end {otherwise output an 16 code and the count} else begin ThisCount := Count; if (ThisCount > 6) then ThisCount := 6; CurPos^ := #16; inc(CurPos); inc(Buckets^[16]); CurPos^ := AnsiChar(ThisCount - 3); inc(CurPos); dec(Count, ThisCount); end; end; end; {move back to the initial state} PrevCodeLen := CodeLen; State := ScanNormal; end; end; end; end; {set the read position} FStrmEnd := CurPos; FPosition := FStream; end; {--------} procedure TAbDfCodeLenStream.Encode(aBitStrm : TAbDfOutBitStream; aTree : TAbDfDecodeHuffmanTree); var Symbol : integer; ExtraData : integer; Code : longint; CurPos : PAnsiChar; StrmEnd : PAnsiChar; begin {prepare for the loop} CurPos := FPosition; StrmEnd := FStrmEnd; {while there are tokens in the stream...} while (CurPos <> StrmEnd) do begin {get the next symbol} Symbol := ord(CurPos^); inc(CurPos); {if the symbol is 0..15, get the code and output it} if (Symbol <= 15) then begin {$IFOPT C+} {if Assertions are on} Code := aTree.Encode(Symbol); {$ELSE} Code:= aTree.Encodes^[Symbol]; {$ENDIF} aBitStrm.WriteBits(Code and $FFFF, (Code shr 16) and $FF); end {otherwise the symbol is 16, 17, or 18} else begin {get the extra data} ExtraData := ord(CurPos^); inc(CurPos); {get the code and output it} {$IFOPT C+} {if Assertions are on} Code := aTree.Encode(Symbol); {$ELSE} Code:= aTree.Encodes^[Symbol]; {$ENDIF} aBitStrm.WriteBits(Code and $FFFF, (Code shr 16) and $FF); if (Symbol = 16) then aBitStrm.WriteBits(ExtraData, 2) else if (Symbol = 17) then aBitStrm.WriteBits(ExtraData, 3) else {Symbol = 18} aBitStrm.WriteBits(ExtraData, 7); end; end; end; {====================================================================} end. ================================================ FILE: lib/abbrevia/source/AbDfXlat.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbDfXlat.pas *} {*********************************************************} {* Deflate length/dist to symbol translator *} {*********************************************************} unit AbDfXlat; {$I AbDefine.inc} interface uses SysUtils; type TAbDfTranslator = class private FBuffer : PAnsiChar; FLenSymbols : PByteArray; {for lengths 3..258} FLongDistSymbols : PByteArray; {for distances 32769..65536 (deflate64)} FMediumDistSymbols : PByteArray; {for distances 257..32768} FShortDistSymbols : PByteArray; {for distances 1..256} protected procedure trBuild; public constructor Create; destructor Destroy; override; function TranslateLength(aLen : integer): integer; function TranslateDistance(aDist : integer) : integer; property LenSymbols : PByteArray read FLenSymbols; property LongDistSymbols : PByteArray read FLongDistSymbols; property MediumDistSymbols : PByteArray read FMediumDistSymbols; property ShortDistSymbols : PByteArray read FShortDistSymbols; end; var AbSymbolTranslator : TAbDfTranslator; implementation uses AbDfBase; {====================================================================} constructor TAbDfTranslator.Create; begin {create the ancestor} inherited Create; {allocate the translation arrays (the buffer *must* be zeroed)} FBuffer := AllocMem(256 + 2 + 256 + 256); FLenSymbols := PByteArray(FBuffer); FLongDistSymbols := PByteArray(FBuffer + 256); FMediumDistSymbols := PByteArray(FBuffer + 256 + 2); FShortDistSymbols := PByteArray(FBuffer + 256 + 2 + 256); {build the translation arrays} trBuild; end; {--------} destructor TAbDfTranslator.Destroy; begin if (FBuffer <> nil) then FreeMem(FBuffer); inherited Destroy; end; {--------} function TAbDfTranslator.TranslateDistance(aDist : integer) : integer; begin {save against dumb programming mistakes} Assert((1 <= aDist) and (aDist <= 65536), 'TAbDfTranslator.Translate: distance should be 1..65536'); {translate the distance} if (aDist <= 256) then Result := FShortDistSymbols[aDist - 1] else if (aDist <= 32768) then Result := FMediumDistSymbols[((aDist - 1) div 128) - 2] else Result := FLongDistSymbols[((aDist - 1) div 16384) - 2]; end; {--------} function TAbDfTranslator.TranslateLength(aLen : integer): integer; begin {save against dumb programming mistakes} Assert((3 <= aLen) and (aLen <= 65536), 'TAbDfTranslator.Translate: length should be 3..65536'); {translate the length} dec(aLen, 3); if (0 <= aLen) and (aLen <= 255) then Result := FLenSymbols[aLen] + 257 else Result := 285; end; {--------} procedure TAbDfTranslator.trBuild; var i : integer; Len : integer; Dist : integer; Value : integer; begin {initialize the length translation array; elements will contain (Symbol - 257) for a given (length - 3)} for i := low(dfc_LengthBase) to pred(high(dfc_LengthBase)) do begin Len := dfc_LengthBase[i] - 3; FLenSymbols[Len] := i; end; FLenSymbols[255] := 285 - 257; Value := -1; for i := 0 to 255 do begin if (Value < FLenSymbols[i]) then Value := FLenSymbols[i] else FLenSymbols[i] := Value; end; {initialize the short distance translation array: it will contain the Symbol for a given (distance - 1) where distance <= 256} for i := 0 to 15 do begin Dist := dfc_DistanceBase[i] - 1; FShortDistSymbols[Dist] := i; end; Value := -1; for i := 0 to 255 do begin if (Value < FShortDistSymbols[i]) then Value := FShortDistSymbols[i] else FShortDistSymbols[i] := Value; end; {initialize the medium distance translation array: it will contain the Symbol for a given (((distance - 1) div 128) - 2) where distance is in the range 256..32768} for i := 16 to 29 do begin Dist := ((dfc_DistanceBase[i] - 1) div 128) - 2; FMediumDistSymbols[Dist] := i; end; Value := -1; for i := 0 to 255 do begin if (Value < FMediumDistSymbols[i]) then Value := FMediumDistSymbols[i] else FMediumDistSymbols[i] := Value; end; {initialize the long distance translation array: it will contain the Symbol for a given ((distance - 1) div 16384) - 2) for distances over 32768 in deflate64} FLongDistSymbols[0] := 30; FLongDistSymbols[1] := 31; end; {====================================================================} initialization AbSymbolTranslator := TAbDfTranslator.Create; finalization AbSymbolTranslator.Free; end. ================================================ FILE: lib/abbrevia/source/AbDlgDir.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbDlgDir.pas *} {*********************************************************} {* ABBREVIA: Dialog - Directory *} {* Use AbQDgDir.pas for CLX *} {*********************************************************} {$IFNDEF UsingCLX} unit AbDlgDir; {$ENDIF} {$I AbDefine.inc} interface uses {$IFDEF MSWINDOWS} Windows, Messages, ShlObj, ActiveX, {$ENDIF} SysUtils, Classes, {$IFDEF UsingClx} QButtons, QExtCtrls, QGraphics, QForms, QControls, QStdCtrls, {$ELSE} Buttons, ExtCtrls, Graphics, Forms, Controls, StdCtrls, {$WARN UNIT_PLATFORM OFF} FileCtrl, {$WARN UNIT_PLATFORM ON} {$ENDIF} AbResString; type {$IFNDEF UsingClx} TDirDlg = class(TForm) OKBtn: TButton; CancelBtn: TButton; Bevel1: TBevel; DriveComboBox1: TDriveComboBox; DirectoryListBox1: TDirectoryListBox; Panel1: TPanel; procedure DirectoryListBox1Change(Sender: TObject); procedure FormCreate(Sender: TObject); public SelectedFolder: string; end; {$ELSE} TDirDlg = class(TForm) OKBtn: TButton; CancelBtn: TButton; Bevel1: TBevel; Panel1: TPanel; procedure DirectoryListBox1Change(Sender: TObject); procedure FormCreate(Sender: TObject); public SelectedFolder: string; end; {$ENDIF} {$IFDEF MSWINDOWS} type TAbDirDlg = class(TComponent) protected {private} FAdditionalText : string; FCaption : string; FHandle : Integer; FIDList : PItemIDList; FSelectedFolder : string; procedure SetSelectedFolder(const Value : string); procedure FreeIDList; public {properties} property AdditionalText : string read FAdditionalText write FAdditionalText; property Caption : string read FCaption write FCaption; property Handle : Integer read FHandle; property IDList : PItemIDList read FIDList; property SelectedFolder : string read FSelectedFolder write SetSelectedFolder; public {methods} constructor Create(AOwner : TComponent); override; destructor Destroy; override; function Execute : Boolean; end; {$ENDIF} var DirDlg: TDirDlg; implementation {$IFNDEF UsingCLX} {$R *.dfm} {$ENDIF} {== TAbDirDlg ========================================================} {$IFDEF MSWINDOWS} function AbDirDlgCallbackProc(hWnd : HWND; Msg : UINT; lParam : LPARAM; Data : LPARAM): Integer; stdcall; var X, Y : Integer; R : TRect; Buf : array[0..MAX_PATH-1] of Char; begin Result := 0; with TAbDirDlg(Data) do begin case Msg of BFFM_INITIALIZED : begin FHandle := hWnd; if (FCaption <> '') then SendMessage(hWnd, WM_SETTEXT, 0, Integer(PChar(FCaption))); SendMessage(hWnd, BFFM_SETSELECTION, 1, Integer(PChar(SelectedFolder))); GetWindowRect(hWnd, R); X := (Screen.Width div 2) - ((R.Right - R.Left) div 2); Y := (Screen.Height div 2) - ((R.Bottom - R.Top) div 2); SetWindowPos(hWnd, 0, X, Y, 0, 0, SWP_NOSIZE or SWP_NOZORDER); end; BFFM_SELCHANGED : if (FHandle <> 0) then begin FIDList := PItemIDList(lParam); SHGetPathFromIDList(IDList, Buf); SelectedFolder := Buf; end; end; end; end; { -------------------------------------------------------------------------- } constructor TAbDirDlg.Create(AOwner : TComponent); begin inherited Create(AOwner); end; { -------------------------------------------------------------------------- } destructor TAbDirDlg.Destroy; begin if FIDList <> nil then FreeIDList; inherited Destroy; end; { -------------------------------------------------------------------------- } function TAbDirDlg.Execute : Boolean; var Info : TBrowseInfo; Buf : array[0..MAX_PATH-1] of Char; begin if (FIDList <> nil) then FreeIDList; {$IFNDEF UsingClx} if (Owner is TWinControl) then Info.hwndOwner := (Owner as TWinControl).Handle else if Owner is TApplication then Info.hwndOwner := (Owner as TApplication).Handle else {$ENDIF} Info.hwndOwner := 0; Info.pidlRoot := nil; Info.pszDisplayName := Buf; Info.lpszTitle := PChar(FAdditionalText); Info.ulFlags := BIF_RETURNONLYFSDIRS; Info.lpfn := AbDirDlgCallbackProc; Info.lParam := Integer(Self); Info.iImage := 0; FIDList := SHBrowseForFolder(Info); FHandle := 0; Result := (FIDList <> nil); end; { -------------------------------------------------------------------------- } procedure TAbDirDlg.FreeIDList; var Malloc : IMalloc; begin if coGetMalloc(MEMCTX_TASK, Malloc) = NOERROR then begin Malloc.Free(FIDList); FIDList := nil; end; end; { -------------------------------------------------------------------------- } procedure TAbDirDlg.SetSelectedFolder(const Value : string); begin FSelectedFolder := Value; if FSelectedFolder <> '' then if FSelectedFolder[Length(FSelectedFolder)] = '\' then Delete(FSelectedFolder, Length(FSelectedFolder), 1); if (Length(FSelectedFolder) = 2) then FSelectedFolder := FSelectedFolder + '\'; end; {$ENDIF} {== TDirDlg ========================================================} { TDirDlg } procedure TDirDlg.FormCreate(Sender: TObject); begin DirectoryListBox1Change(nil); OKBtn.Caption := AbOKS; CancelBtn.Caption := AbCancelS; Caption := AbSelectDirectoryS; end; { -------------------------------------------------------------------------- } procedure TDirDlg.DirectoryListBox1Change(Sender: TObject); begin {$IFNDEF UsingClx} SelectedFolder := DirectoryListBox1.Directory; {$ENDIF} Panel1.Caption := SelectedFolder; end; end. ================================================ FILE: lib/abbrevia/source/AbDlgPwd.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbDlgPwd.pas *} {*********************************************************} {* ABBREVIA: Dialog - Password *} {* Use AbQDgPwd.pas for CLX *} {*********************************************************} {$IFNDEF UsingCLX} unit AbDlgPwd; {$R *.dfm} {$ENDIF} {$I AbDefine.inc} interface uses SysUtils, {$IFDEF MSWINDOWS} Windows, {$ENDIF} {$IFDEF LibcAPI} Libc, {$ENDIF} {$IFDEF UsingClx} QGraphics, QForms, QControls, QStdCtrls, QButtons, QExtCtrls, {$ELSE} Graphics, Forms, Controls, StdCtrls, Buttons, ExtCtrls, {$ENDIF} Classes; type TPassWordDlg = class(TForm) OKBtn: TButton; CancelBtn: TButton; Bevel1: TBevel; Edit1: TEdit; {$IFDEF MSWINDOWS} Edit2: TEdit; {$ENDIF} Label1: TLabel; {$IFDEF MSWINDOWS} Label2: TLabel; {$ENDIF} procedure Edit1Change(Sender: TObject); procedure Edit2Change(Sender: TObject); procedure FormActivate(Sender: TObject); procedure FormCreate(Sender: TObject); private { Private declarations } public { Public declarations } end; var PassWordDlg: TPassWordDlg; implementation uses AbResString; procedure TPassWordDlg.Edit1Change(Sender: TObject); begin {$IFDEF MSWINDOWS} Edit2.Text := ''; OKBtn.Enabled := ( CompareStr( Edit1.Text, Edit2.Text ) = 0); {$ELSE} OKBtn.Enabled := true; {$ENDIF} end; procedure TPassWordDlg.Edit2Change(Sender: TObject); begin {$IFDEF MSWINDOWS} OKBtn.Enabled := ( CompareStr( Edit1.Text, Edit2.Text ) = 0); {$ELSE} OKBtn.Enabled := true; {$ENDIF} end; procedure TPassWordDlg.FormActivate(Sender: TObject); begin {$IFDEF MSWINDOWS} OKBtn.Enabled := ( CompareStr( Edit1.Text, Edit2.Text ) = 0); {$ELSE} OKBtn.Enabled := true; {$ENDIF} end; procedure TPassWordDlg.FormCreate(Sender: TObject); begin Caption := AbEnterPasswordS; OKBtn.Caption := AbOKS; CancelBtn.Caption := AbCancelS; Label1.Caption := AbPasswordS; {$IFDEF MSWINDOWS} Label2.Caption := AbVerifyS; {$ENDIF} end; end. ================================================ FILE: lib/abbrevia/source/AbExcept.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbExcept.pas *} {*********************************************************} {* ABBREVIA: Exception classes *} {*********************************************************} unit AbExcept; {$I AbDefine.inc} interface uses SysUtils, AbUtils; type EAbException = class( Exception ) public ErrorCode : Integer; end; EAbArchiveBusy = class( EAbException ) public constructor Create; end; EAbBadStream = class( EAbException ) protected FInnerException : Exception; public constructor Create; constructor CreateInner(aInnerException : Exception); property InnerException : Exception read FInnerException; end; EAbDuplicateName = class( EAbException ) public constructor Create; end; EAbFileNotFound = class( EAbException ) public constructor Create; end; EAbNoArchive = class( EAbException ) public constructor Create; end; EAbUserAbort = class( EAbException ) public constructor Create; end; EAbNoSuchDirectory = class( EAbException ) public constructor Create; end; EAbUnhandledType = class( EAbException ) public constructor Create; end; EAbSpanningNotSupported = class (EAbException) public constructor Create; end; EAbInvalidSpanningThreshold = class ( EAbException ) public constructor Create; end; EAbZipException = class( EAbException ); {Zip exception} EAbCabException = class( EAbException ); {Cab exception} EAbTarException = class( EAbException ); {Tar Exception} EAbGzipException = class( EAbException); {GZip exception} EAbZipBadSpanStream = class( EAbZipException ) public constructor Create; end; EAbZipBadCRC = class( EAbZipException ) public constructor Create; end; EAbZipInflateBlock = class( EAbZipException ) public constructor Create; end; EAbZipInvalid = class( EAbZipException ) public constructor Create; end; EAbInvalidIndex = class( EAbZipException ) public constructor Create; end; EAbZipInvalidFactor = class( EAbZipException ) public constructor Create; end; EAbZipInvalidLFH = class( EAbZipException ) public constructor Create; end; EAbZipInvalidMethod = class( EAbZipException ) public constructor Create; end; EAbZipInvalidPassword = class( EAbZipException ) public constructor Create; end; EAbZipInvalidStub= class( EAbZipException ) public constructor Create; end; EAbZipNoExtraction = class( EAbZipException ) public constructor Create; end; EAbZipNoInsertion = class( EAbZipException ) public constructor Create; end; EAbZipSpanOverwrite= class( EAbZipException ) public constructor Create; end; EAbZipStreamFull = class( EAbZipException ) public constructor Create; end; EAbZipTruncate = class( EAbZipException ) public constructor Create; end; EAbZipUnsupported = class( EAbZipException ) public constructor Create; end; EAbZipVersion = class( EAbZipException ) public constructor Create; end; EAbReadError = class( EAbZipException ) public constructor Create; end; EAbGzipBadCRC = class( EAbGZipException ) public constructor Create; end; EAbGzipBadFileSize = class( EAbGZipException ) public constructor Create; end; EAbGzipInvalid = class( EAbGZipException ) public constructor Create; end; EAbTarInvalid = class( EAbTarException) public constructor Create; end; EAbTarBadFileName = class( EAbTarException) public constructor Create; end; EAbTarBadLinkName = class( EAbTarException) public constructor Create; end; EAbTarBadOp = class( EAbTarException) public constructor Create; end; EAbVMSInvalidOrigin = class( EAbZipException ) public constructor Create( Value : Integer ); end; EAbVMSErrorOpenSwap = class( EAbZipException ) public constructor Create( const Value : string ); end; EAbVMSSeekFail = class( EAbZipException ) public constructor Create( const Value : string ); end; EAbVMSReadFail = class( EAbZipException ) public constructor Create( Count : Integer; const Value : string ); end; EAbVMSWriteFail = class( EAbZipException ) public constructor Create( Count : Integer; const Value : string ); end; EAbVMSWriteTooManyBytes = class( EAbZipException ) public constructor Create( Count : Integer ); end; EAbBBSReadTooManyBytes = class( EAbZipException ) public constructor Create(Count : Integer ); end; EAbBBSSeekOutsideBuffer = class( EAbZipException ) public constructor Create; end; EAbBBSInvalidOrigin = class( EAbZipException ) public constructor Create; end; EAbBBSWriteTooManyBytes = class( EAbZipException ) public constructor Create(Count : Integer ); end; EAbSWSNotEndofStream = class( EAbZipException ) public constructor Create; end; EAbSWSSeekFailed = class( EAbZipException ) public constructor Create; end; EAbSWSWriteFailed = class( EAbZipException ) public constructor Create; end; EAbSWSInvalidOrigin = class( EAbZipException ) public constructor Create; end; EAbSWSInvalidNewOrigin = class( EAbZipException ) public constructor Create; end; EAbNoCabinetDll = class( EAbCabException ) public constructor Create; end; EAbFCIFileOpenError = class( EAbCabException ) public constructor Create; end; EAbFCIFileReadError = class( EAbCabException ) public constructor Create; end; EAbFCIFileWriteError = class( EAbCabException ) public constructor Create; end; EAbFCIFileCloseError = class( EAbCabException ) public constructor Create; end; EAbFCIFileSeekError = class( EAbCabException ) public constructor Create; end; EAbFCIFileDeleteError = class( EAbCabException ) public constructor Create; end; EAbFCIAddFileError = class( EAbCabException ) public constructor Create; end; EAbFCICreateError = class( EAbCabException ) public constructor Create; end; EAbFCIFlushCabinetError = class( EAbCabException ) public constructor Create; end; EAbFCIFlushFolderError = class( EAbCabException ) public constructor Create; end; EAbFDICopyError = class( EAbCabException ) public constructor Create; end; EAbFDICreateError = class( EAbCabException ) public constructor Create; end; EAbInvalidCabTemplate = class( EAbCabException ) public constructor Create; end; EAbInvalidCabFile = class( EAbCabException ) public constructor Create; end; EAbFileTooLarge = class(EAbException) public constructor Create; end; procedure AbConvertException( const E : Exception; var eClass : TAbErrorClass; var eErrorCode : Integer ); implementation uses Classes, AbConst, AbResString; constructor EAbArchiveBusy.Create; begin inherited Create(AbArchiveBusyS); ErrorCode := AbArchiveBusy; end; constructor EAbBadStream.Create; begin inherited Create(AbBadStreamTypeS); FInnerException := nil; ErrorCode := AbBadStreamType; end; constructor EAbBadStream.CreateInner(aInnerException: Exception); begin inherited Create(AbBadStreamTypeS + #13#10 + aInnerException.Message); FInnerException := aInnerException; ErrorCode := AbBadStreamType; end; constructor EAbDuplicateName.Create; begin inherited Create(AbDuplicateNameS); ErrorCode := AbDuplicateName; end; constructor EAbNoSuchDirectory.Create; begin inherited Create(AbNoSuchDirectoryS); ErrorCode := AbNoSuchDirectory; end; constructor EAbInvalidSpanningThreshold.Create; begin inherited Create(AbInvalidThresholdS); ErrorCode := AbInvalidThreshold; end; constructor EAbFileNotFound.Create; begin inherited Create(AbFileNotFoundS); ErrorCode := AbFileNotFound; end; constructor EAbNoArchive.Create; begin inherited Create(AbNoArchiveS); ErrorCode := AbNoArchive; end; constructor EAbUserAbort.Create; begin inherited Create(AbUserAbortS); ErrorCode := AbUserAbort; end; constructor EAbZipBadSpanStream.Create; begin inherited Create(AbBadSpanStreamS); ErrorCode := AbBadSpanStream; end; constructor EAbZipBadCRC.Create; begin inherited Create(AbZipBadCRCS); ErrorCode := AbZipBadCRC; end; constructor EAbZipInflateBlock.Create; begin inherited Create(AbInflateBlockErrorS); ErrorCode := AbInflateBlockError; end; constructor EAbZipInvalid.Create; begin inherited Create(AbErrZipInvalidS); ErrorCode := AbErrZipInvalid; end; constructor EAbInvalidIndex.Create; begin inherited Create(AbInvalidIndexS); ErrorCode := AbInvalidIndex; end; constructor EAbZipInvalidFactor.Create; begin inherited Create(AbInvalidFactorS); ErrorCode := AbInvalidFactor; end; constructor EAbZipInvalidLFH.Create; begin inherited Create(AbInvalidLFHS); ErrorCode := AbInvalidLFH; end; constructor EAbZipInvalidMethod.Create; begin inherited Create(AbUnknownCompressionMethodS); ErrorCode := AbUnknownCompressionMethod; end; constructor EAbZipInvalidPassword.Create; begin inherited Create(AbInvalidPasswordS); ErrorCode := AbInvalidPassword; end; constructor EAbZipInvalidStub.Create; begin inherited Create(AbZipBadStubS); ErrorCode := AbZipBadStub; end; constructor EAbZipNoExtraction.Create; begin inherited Create(AbNoExtractionMethodS); ErrorCode := AbNoExtractionMethod; end; constructor EAbZipNoInsertion.Create; begin inherited Create(AbNoInsertionMethodS); ErrorCode := AbNoInsertionMethod; end; constructor EAbZipSpanOverwrite.Create; begin inherited Create(AbNoOverwriteSpanStreamS); ErrorCode := AbNoOverwriteSpanStream; end; constructor EAbZipStreamFull.Create; begin inherited Create(AbStreamFullS); ErrorCode := AbStreamFull; end; constructor EAbZipTruncate.Create; begin inherited Create(AbTruncateErrorS); ErrorCode := AbTruncateError; end; constructor EAbZipUnsupported.Create; begin inherited Create(AbUnsupportedCompressionMethodS); ErrorCode := AbUnsupportedCompressionMethod; end; constructor EAbZipVersion.Create; begin inherited Create(AbZipVersionNeededS); ErrorCode := AbZipVersionNeeded; end; constructor EAbReadError.Create; begin inherited Create(AbReadErrorS); ErrorCode := AbReadError; end; constructor EAbVMSInvalidOrigin.Create( Value : Integer ); begin inherited Create(Format(AbVMSInvalidOriginS, [Value])); ErrorCode := AbVMSInvalidOrigin; end; constructor EAbBBSReadTooManyBytes.Create(Count : Integer ); begin inherited Create(Format(AbBBSReadTooManyBytesS, [Count])); ErrorCode := AbBBSReadTooManyBytes; end; constructor EAbBBSSeekOutsideBuffer.Create; begin inherited Create(AbBBSSeekOutsideBufferS); ErrorCode := AbBBSSeekOutsideBuffer; end; constructor EAbBBSInvalidOrigin.Create; begin inherited Create(AbBBSInvalidOriginS); ErrorCode := AbBBSInvalidOrigin; end; constructor EAbBBSWriteTooManyBytes.Create(Count : Integer); begin inherited Create(Format(AbBBSWriteTooManyBytesS, [Count])); ErrorCode := AbBBSWriteTooManyBytes; end; constructor EAbVMSErrorOpenSwap.Create( const Value : string ); begin inherited Create(Format(AbVMSErrorOpenSwapS, [Value])); ErrorCode := AbVMSErrorOpenSwap; end; constructor EAbVMSSeekFail.Create( const Value : string ); begin inherited Create(Format(AbVMSSeekFailS, [Value])); ErrorCode := AbVMSSeekFail; end; constructor EAbVMSReadFail.Create( Count : Integer; const Value : string ); begin inherited Create(Format(AbVMSReadFailS, [Count, Value])); ErrorCode := AbVMSReadFail; end; constructor EAbVMSWriteFail.Create( Count : Integer; const Value : string ); begin inherited Create(Format(AbVMSWriteFailS, [Count, Value])); ErrorCode := AbVMSWriteFail; end; constructor EAbVMSWriteTooManyBytes.Create( Count : Integer ); begin inherited Create(Format(AbVMSWriteTooManyBytesS, [Count])); ErrorCode := AbVMSWriteTooManyBytes; end; constructor EAbSWSNotEndofStream.Create; begin inherited Create(AbSWSNotEndofStreamS); ErrorCode := AbSWSNotEndofStream; end; constructor EAbSWSSeekFailed.Create; begin inherited Create(AbSWSSeekFailedS); ErrorCode := AbSWSSeekFailed; end; constructor EAbSWSWriteFailed.Create; begin inherited Create(AbSWSWriteFailedS); ErrorCode := AbSWSWriteFailed; end; constructor EAbSWSInvalidOrigin.Create; begin inherited Create(AbSWSInvalidOriginS); ErrorCode := AbSWSInvalidOrigin; end; constructor EAbSWSInvalidNewOrigin.Create; begin inherited Create(AbSWSInvalidNewOriginS); ErrorCode := AbSWSInvalidNewOrigin; end; constructor EAbFCIFileOpenError.Create; begin inherited Create(AbFCIFileOpenErrorS); ErrorCode := AbFCIFileOpenError; end; constructor EAbNoCabinetDll.Create; begin inherited Create(AbNoCabinetDllErrorS); ErrorCode := AbNoCabinetDllError; end; constructor EAbFCIFileReadError.Create; begin inherited Create(AbFCIFileReadErrorS); ErrorCode := AbFCIFileReadError; end; constructor EAbFCIFileWriteError.Create; begin inherited Create(AbFCIFileWriteErrorS); ErrorCode := AbFCIFileWriteError; end; constructor EAbFCIFileCloseError.Create; begin inherited Create(AbFCIFileCloseErrorS); ErrorCode := AbFCIFileCloseError; end; constructor EAbFCIFileSeekError.Create; begin inherited Create(AbFCIFileSeekErrorS); ErrorCode := AbFCIFileSeekError; end; constructor EAbFCIFileDeleteError.Create; begin inherited Create(AbFCIFileDeleteErrorS); ErrorCode := AbFCIFileDeleteError; end; constructor EAbFCIAddFileError.Create; begin inherited Create(AbFCIAddFileErrorS); ErrorCode := AbFCIAddFileError; end; constructor EAbFCICreateError.Create; begin inherited Create(AbFCICreateErrorS); ErrorCode := AbFCICreateError; end; constructor EAbFCIFlushCabinetError.Create; begin inherited Create(AbFCIFlushCabinetErrorS); ErrorCode := AbFCIFlushCabinetError; end; constructor EAbFCIFlushFolderError.Create; begin inherited Create(AbFCIFlushFolderErrorS); ErrorCode := AbFCIFlushFolderError; end; constructor EAbFDICopyError.Create; begin inherited Create(AbFDICopyErrorS); ErrorCode := AbFDICopyError; end; constructor EAbFDICreateError.Create; begin inherited Create(AbFDICreateErrorS); ErrorCode := AbFDICreateError; end; constructor EAbInvalidCabTemplate.Create; begin inherited Create(AbInvalidCabTemplateS); ErrorCode := AbInvalidCabTemplate; end; constructor EAbInvalidCabFile.Create; begin inherited Create(AbInvalidCabFileS); ErrorCode := AbInvalidCabFile; end; procedure AbConvertException( const E : Exception; var eClass : TAbErrorClass; var eErrorCode : Integer ); begin eClass := ecOther; eErrorCode := 0; if E is EAbException then begin eClass := ecAbbrevia; eErrorCode := (E as EAbException).ErrorCode; end else if E is EInOutError then begin eClass := ecInOutError; eErrorCode := (E as EInOutError).ErrorCode; end else if E is EFilerError then eClass := ecFilerError else if E is EFOpenError then eClass := ecFileOpenError else if E is EFCreateError then eClass := ecFileCreateError; end; { EAbUnhandledType } constructor EAbUnhandledType.Create; begin inherited Create(AbUnhandledFileTypeS); ErrorCode := AbUnhandledFileType; end; { EAbGzipBadCRC } constructor EAbGzipBadCRC.Create; begin inherited Create(AbGzipBadCRCS); ErrorCode := AbGzipBadCRC; end; { EAbGzipBadFileSize } constructor EAbGzipBadFileSize.Create; begin inherited Create(AbGzipBadFileSizeS); ErrorCode := AbGzipBadFileSize; end; { EAbGzipInvalid } constructor EAbGzipInvalid.Create; begin inherited Create(AbSpanningNotSupportedS); ErrorCode := AbSpanningNotSupported; end; { EAbTarInvalid } constructor EAbTarInvalid.Create; begin inherited Create(AbTarInvalidS); ErrorCode := AbTarInvalid; end; { EAbTarBadFileName } constructor EAbTarBadFileName.Create; begin inherited Create(AbTarBadFileNameS); ErrorCode := AbTarBadFileName; end; { EAbTarBadLinkName } constructor EAbTarBadLinkName.Create; begin inherited Create(AbTarBadLinkNameS); ErrorCode := AbTarBadLinkName; end; { EAbTarBadOp } constructor EAbTarBadOp.Create; begin inherited Create(AbTarBadOpS); ErrorCode := AbTarBadOp; end; { EAbSpanningNotSupported } constructor EAbSpanningNotSupported.Create; begin inherited Create(AbSpanningNotSupportedS); ErrorCode := AbSpanningNotSupported; end; { EAbFileTooLarge } constructor EAbFileTooLarge.Create; begin {TODO Create const and fix wording} inherited Create(AbFileSizeTooBigS); end; end. ================================================ FILE: lib/abbrevia/source/AbFciFdi.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbFciFdi.pas *} {*********************************************************} {* ABBREVIA: Cabinet DLL wrapper *} {* Based on info from the FCI/FDI Library Description, *} {* included in the Microsoft Cabinet SDK *} {*********************************************************} unit AbFciFdi; {$I AbDefine.inc} interface uses Windows, AbUtils; const CabinetDLL = 'cabinet.dll'; cpuUnknown = -1; cpu80286 = 0; cpu80386 = 1; cpuDefault = cpuUnknown; type {FDI errors} FDIError = (FDIError_None, FDIError_Cabinet_Not_Found, FDIError_Not_A_Cabinet, FDIError_Unknown_Cabinet_Version, FDIError_Corrupt_Cabinet, FDIError_Alloc_Fail, FDIError_Bad_Compr_Type, FDIError_MDI_Fail, FDIError_Target_File, FDIError_Reserve_Mismatch, FDIError_Wrong_Cabinet, FDIError_User_Abort); {FCI errors} FCIError = (FCIError_NONE, FCIError_Open_SRC, FCIError_Read_SRC, FCIError_Alloc_Fail, FCIError_Temp_File, FCIError_Bad_Compr_Type, FCIError_Cab_File, FCIError_User_Abort, FCIERRor_MCI_Fail); {FDI notifications} FDINotificationType = (FDINT_Cabinet_Info, FDINT_Partial_File, FDINT_Copy_File, FDINT_Close_File_Info, FDINT_Next_Cabinet, FDINT_Enumerate); {FDI/FCI error structure} PCabErrorRecord = ^CabErrorRecord; CabErrorRecord = record ErrorCode : Integer; ErrorType : Integer; ErrorPresent : BOOL; end; {FDI cabinet information structure} PFDICabInfo = ^FDICabInfo; FDICabInfo = record cbCabinet : Longint; cFolders : Word; cFiles : Word; setID : Word; iCabinet : Word; fReserve : BOOL; hasprev : BOOL; hasnext : BOOL; end; {FCI cabinet information structure} PFCICabInfo = ^FCICabInfo; FCICabInfo = record cb : Longint; cbFolderThresh : Longint; cbReserveCFHeader : Integer; cbReserveCFFolder : Integer; cbReserveCFData : Integer; iCab : Integer; iDisk : Integer; fFailOnIncompressible : Integer; setID : Word; szDisk : array[0..255] of AnsiChar; szCab : array[0..255] of AnsiChar; szCabPath : array[0..255] of AnsiChar; end; {FDI notification structure} PFDINotification = ^FDINotification; FDINotification = record cb : Longint; psz1 : PAnsiChar; psz2 : PAnsiChar; psz3 : PAnsiChar; pv : Pointer; hf : PtrInt; date : Word; time : Word; attribs : Word; setID : Word; iCabinet : Word; iFolder : Word; fdie : FDIERROR; end; {misc defines} HFDI = Pointer; HFCI = Pointer; FARPROC = Pointer; {== Cabinet DLL routine prototypes ==========================================} type TFDICreate = function (pfnalloc, pfnfree, pfnopen, pfnread, pfnwrite, pfnclose, pfnseek : FARPROC; cpuType : Integer; pError : PCabErrorRecord) : HFDI; cdecl; {----------------------------------------------------------------------------} TFDIIsCabinet = function(hfdi : HFDI; hf : PtrInt; pfdici : PFDICabInfo) : BOOL; cdecl; {----------------------------------------------------------------------------} TFDICopy = function(hfdi : HFDI; pszCabinet, pszCabPath : PAnsiChar; flags : Integer; pfnfdin, pfnfdid : FARPROC; Archive : Pointer) : BOOL; cdecl; {----------------------------------------------------------------------------} TFDIDestroy = function(hfdi : HFDI) : BOOL; cdecl; {----------------------------------------------------------------------------} TFCICreate = function(pError : PCabErrorRecord; pfnfcifp, pfnalloc, pfnfree, pfnopen, pfnread, pfnwrite, pfnclose, pfnseek, pfndelete, pfnfcigtf : FARPROC; pccab : PFCICabInfo; Archive : Pointer) : HFCI; cdecl; {----------------------------------------------------------------------------} TFCIAddFile = function(hfci : HFCI; pszFilePath, pszFileName : PAnsiChar; fExecute : BOOL; pfnfcignc, pfnfcis, pfnfcigoi : FARPROC; typeCompress : Word) : BOOL; cdecl; {----------------------------------------------------------------------------} TFCIFlushCabinet = function(hfci : HFCI; fGetNextCab : BOOL; pfnfcignc, pfnfcis : FARPROC) : BOOL; cdecl; {----------------------------------------------------------------------------} TFCIFlushFolder = function(hfci : HFCI; pfnfcignc, pfnfcis : FARPROC) : BOOL; cdecl; {----------------------------------------------------------------------------} TFCIDestroy = function(hfci : HFCI) : BOOL; cdecl; {== DLL routine wrappers ====================================================} function FDICreate(pfnalloc, pfnfree, pfnopen, pfnread, pfnwrite, pfnclose, pfnseek : FARPROC; cpuType : Integer; pError : PCabErrorRecord) : HFDI; {returns an FDI context for opening an existing cabinet} { pfnalloc - heap allocation callback function } { pfnfree - heap deallocation callback function } { pfnopen - open file callback function } { pfnwrite - write file callback function } { pfnclose - close file callback function } { pfnseek - reposition file pointer callback function } { cpuType - -1: unknown, 0: 80286, 1: 80386 } { pError - pointer to error record } {----------------------------------------------------------------------------} function FDIIsCabinet(hfdi : HFDI; hf : PtrInt; pfdici : PFDICabInfo) : BOOL; {checks cabinet file for validity} { hfdi - FDI context } { hf - cabinet file handle } { pfdici - pointer to FDI cabinet info structure } {----------------------------------------------------------------------------} function FDICopy(hfdi : HFDI; pszCabinet, pszCabPath : PAnsiChar; flags : Integer; pfnfdin, pfnfdid : FARPROC; Archive : Pointer) : BOOL; {enumerates every file in the cabinet. The callback function } {should indicate whether or not to extract a given file} { hfdi - FDI context } { pszCabinet - cabinet file name } { pszCabPath - cabinet file path } { flags - currently not used } { pfnfdin - FDI notifaction callback function } { pfnfdid - decryption callback (currently not used)} { Archive - the calling TAbCabArchive instance } {----------------------------------------------------------------------------} function FDIDestroy(hfdi : HFDI) : BOOL; {releases FDI context and frees resources} { hfdi - FDI context } {----------------------------------------------------------------------------} function FCICreate(pError : PCabErrorRecord; pfnfcifp, pfnalloc, pfnfree, pfnopen, pfnread, pfnwrite, pfnclose, pfnseek, pfndelete, pfnfcigtf : FARPROC; pccab : PFCICabInfo; Archive : Pointer) : HFCI; {creates a new cabinet file and returns the FCI context} { pError - pointer to error record } { pfnfcifp - callback notification when file has been placed in cabinet } { pfnalloc - callback function to allocate memory } { pfnfree - callback function to free memory } { pfnopen - callback function to open a file } { pfnwrite - callback function to write to a file } { pfnclose - callback function to close a file } { pfnseek - callback function to reposition file pointer } { pfndelete - callback function to delete a file } { pfnfcigtf - callback function to obtain temp filename } { pccab - pointer to FCI cabinet infor structure } { Archive - the calling TAbCabArchive instance } {----------------------------------------------------------------------------} function FCIAddFile(hfci : HFCI; pszFilePath, pszFileName : PAnsiChar; fExecute : BOOL; pfnfcignc, pfnfcis, pfnfcigoi : FARPROC; typeCompress : Word) : BOOL; {adds a file to the cabinet} { hfci - FCI context } { pszFilePath - full pathname of file being added } { pszFileName - just the file name } { fExecute - flag to indicate if file is executable } { pfnfcignc - callback function to obtain next cabinet info } { pfnfcis - callback function to relay progress } { pfnfcigoi - callback function to open file and get attributes } { typeCompress - compression type to use } {----------------------------------------------------------------------------} function FCIFlushCabinet(hfci : HFCI; fGetNextCab : BOOL; pfnfcignc, pfnfcis : FARPROC) : BOOL; {writes current cabinet file out to disk and optionally starts a new one} { hfci - FCI context } { fGetNextCab - flag indicating whether to start a new cabinet } { pfnfcignc - callback function to obtain next cabinet info } { pfnfcis - callback function to relay progress } {----------------------------------------------------------------------------} function FCIFlushFolder(hfci : HFCI; pfnfcignc, pfnfcis : FARPROC) : BOOL; {close current compression block and start a new one} { hfci - FCI context } { pfnfcignc - callback function to obtain next cabinet info } { pfnfcis - callback function to relay progress } {----------------------------------------------------------------------------} function FCIDestroy(hfci : HFCI) : BOOL; {releases FCI context and frees resources} { hfdi - FDI context } {----------------------------------------------------------------------------} implementation uses AbExcept; var CabDLLLoaded : Boolean; CabDLLHandle : THandle; FDICreateProc : TFDICreate; FDIIsCabinetProc : TFDIIsCabinet; FDICopyProc : TFDICopy; FDIDestroyProc : TFDIDestroy; FCICreateProc : TFCICreate; FCIAddFileProc : TFCIAddFile; FCIFlushCabinetProc : TFCIFlushCabinet; FCIFlushFolderProc : TFCIFlushFolder; FCIDestroyProc : TFCIDestroy; {============================================================================} procedure LoadCabinetDLL; begin if CabDllLoaded then Exit; CabDllHandle := LoadLibrary(CabinetDLL); if (CabDllHandle = 0) then raise EAbNoCabinetDLL.Create; @FDICreateProc := GetProcAddress(CabDllHandle, 'FDICreate'); @FDIIsCabinetProc := GetProcAddress(CabDllHandle, 'FDIIsCabinet'); @FDICopyProc := GetProcAddress(CabDllHandle, 'FDICopy'); @FDIDestroyProc := GetProcAddress(CabDllHandle, 'FDIDestroy'); @FCICreateProc := GetProcAddress(CabDllHandle, 'FCICreate'); @FCIAddFileProc := GetProcAddress(CabDllHandle, 'FCIAddFile'); @FCIFlushCabinetProc := GetProcAddress(CabDllHandle, 'FCIFlushCabinet'); @FCIFlushFolderProc := GetProcAddress(CabDllHandle, 'FCIFlushFolder'); @FCIDestroyProc := GetProcAddress(CabDllHandle, 'FCIDestroy'); CabDllLoaded := True; end; {----------------------------------------------------------------------------} function FDICreate(pfnalloc, pfnfree, pfnopen, pfnread, pfnwrite, pfnclose, pfnseek : FARPROC; cpuType : Integer; pError : PCabErrorRecord) : HFDI; begin LoadCabinetDLL; if Assigned(FDICreateProc) then Result := FDICreateProc(pfnalloc, pfnfree, pfnopen, pfnread, pfnwrite, pfnclose, pfnseek, cpuType, pError) else Result := nil; end; {----------------------------------------------------------------------------} function FDIIsCabinet(hfdi : HFDI; hf : PtrInt; pfdici : PFDICabInfo) : BOOL; begin LoadCabinetDLL; if Assigned(FDIIsCabinetProc) then Result := FDIIsCabinetProc(hfdi, hf, pfdici) else Result := False; end; {----------------------------------------------------------------------------} function FDICopy(hfdi : HFDI; pszCabinet, pszCabPath : PAnsiChar; flags : Integer; pfnfdin, pfnfdid : FARPROC; Archive : Pointer) : BOOL; begin LoadCabinetDLL; if Assigned(FDICopyProc) then Result := FDICopyProc(hfdi, pszCabinet, pszCabPath, flags, pfnfdin, pfnfdid, Archive) else Result := False; end; {----------------------------------------------------------------------------} function FDIDestroy(hfdi : HFDI) : BOOL; begin LoadCabinetDLL; if Assigned(FDIDestroyProc) then Result := FDIDestroyProc(hfdi) else Result := False; end; {----------------------------------------------------------------------------} function FCICreate(pError : PCabErrorRecord; pfnfcifp, pfnalloc, pfnfree, pfnopen, pfnread, pfnwrite, pfnclose, pfnseek, pfndelete, pfnfcigtf : FARPROC; pccab : PFCICabInfo; Archive : Pointer) : HFCI; begin LoadCabinetDLL; if Assigned(FCICreateProc) then Result := FCICreateProc(pError, pfnfcifp, pfnalloc, pfnfree, pfnopen, pfnread, pfnwrite, pfnclose, pfnseek, pfndelete, pfnfcigtf, pccab, Archive) else Result := nil; end; {----------------------------------------------------------------------------} function FCIAddFile(hfci : HFCI; pszFilePath, pszFileName : PAnsiChar; fExecute : BOOL; pfnfcignc, pfnfcis, pfnfcigoi : FARPROC; typeCompress : Word) : BOOL; begin LoadCabinetDLL; if Assigned(FCIAddFileProc) then Result := FCIAddFileProc(hfci, pszFilePath, pszFileName, fExecute, pfnfcignc, pfnfcis, pfnfcigoi, typeCompress) else Result := False; end; {----------------------------------------------------------------------------} function FCIFlushCabinet(hfci : HFCI; fGetNextCab : BOOL; pfnfcignc, pfnfcis : FARPROC) : BOOL; begin LoadCabinetDLL; if Assigned(FCIFlushCabinetProc) then Result := FCIFlushCabinetProc(hfci, fGetNextCab, pfnfcignc, pfnfcis) else Result := False; end; {----------------------------------------------------------------------------} function FCIFlushFolder(hfci : HFCI; pfnfcignc, pfnfcis : FARPROC) : BOOL; begin LoadCabinetDLL; if Assigned(FCIFlushFolderProc) then Result := FCIFlushFolderProc(hfci, pfnfcignc, pfnfcis) else Result := False; end; {----------------------------------------------------------------------------} function FCIDestroy(hfci : HFCI) : BOOL; begin LoadCabinetDLL; if Assigned(FCIDestroyProc) then Result := FCIDestroyProc(hfci) else Result := False; end; {----------------------------------------------------------------------------} initialization CabDllLoaded := False; end. ================================================ FILE: lib/abbrevia/source/AbGzTyp.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Craig Peterson * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbGzTyp.pas *} {*********************************************************} {* ABBREVIA: TAbGzipArchive, TAbGzipItem classes *} {*********************************************************} {* Misc. constants, types, and routines for working *} {* with GZip files *} {* See: RFC 1952 *} {* "GZIP file format specification version 4.3" *} {* for more information on GZip *} {* See "algorithm.doc" in Gzip source and "format.txt" *} {* on gzip.org for differences from RFC *} {*********************************************************} unit AbGzTyp; {$I AbDefine.inc} interface uses Classes, AbUtils, AbArcTyp, AbTarTyp, AbVMStrm; type { pre-defined "operating system" (really more FILE system) types for the Gzip header } TAbGzFileSystem = (osFat, osAmiga, osVMS, osUnix, osVM_CMS, osAtariTOS, osHPFS, osMacintosh, osZSystem, osCP_M, osTOPS20, osNTFS, osQDOS, osAcornRISCOS, osVFAT, osMVS, osBeOS, osTandem, osTHEOS, osUnknown, osUndefined); type PAbGzHeader = ^TAbGzHeader; TAbGzHeader = packed record { SizeOf(TGzHeader) = 10} ID1 : Byte; { ID Byte, should always be $1F} ID2 : Byte; { ID Byte, should always be $8B} CompMethod : Byte; { compression method used} { 0..7 reserved, 8 = deflate, others undefined as of this writing (4/27/2001)} Flags : Byte; { misc flags} { Bit 0: FTEXT compressed file contains text, can be used for} { cross platform line termination translation} { Bit 1: FCONTINUATION file is a continuation of a multi-part gzip file} { RFC 1952 says this is the header CRC16 flag, but gzip} { reserves it and won't extract the file if this is set} { header data includes part number after header record} { Bit 2: FEXTRA header data contains Extra Data, starts after part} { number (if any)} { Bit 3: FNAME header data contains FileName, null terminated} { string starting immediately after Extra Data (if any)} { RFC 1952 says this is ISO 8859-1 encoded, but gzip} { always uses the system encoding} { Bit 4: FCOMMENT header data contains Comment, null terminated string} { starting immediately after FileName (if any)} { Bit 5: FENCRYPTED file is encrypted using zip-1.9 encryption } { header data contains a 12-byte encryption header } { starting immediately after Comment. Documented in} { "algorithm.doc", but unsupported in gzip} { Bits 6..7 are undefined and reserved as of this writing (8/25/2009)} ModTime : LongInt; { File Modification (Creation) time,} { UNIX cdate format} XtraFlags : Byte; { additional flags} { XtraFlags = 2 -- Deflate compressor used maximum compression algorithm} { XtraFlags = 4 -- Deflate compressor used fastest algorithm} OS : Byte; { Operating system that created file,} { see GZOsToStr routine for values} end; TAbGzTailRec = packed record CRC32 : LongInt; { crc for uncompressed data } ISize : LongWord; { size of uncompressed data } end; TAbGzExtraFieldSubID = array[0..1] of AnsiChar; type TAbGzipExtraField = class(TAbExtraField) private FGZHeader : PAbGzHeader; function GetID(aIndex : Integer): TAbGzExtraFieldSubID; protected procedure Changed; override; public constructor Create(aGZHeader : PAbGzHeader); procedure Delete(aID : TAbGzExtraFieldSubID); function Get(aID : TAbGzExtraFieldSubID; out aData : Pointer; out aDataSize : Word) : Boolean; procedure Put(aID : TAbGzExtraFieldSubID; const aData; aDataSize : Word); public property IDs[aIndex : Integer]: TAbGzExtraFieldSubID read GetID; end; TAbGzipItem = class(TAbArchiveItem) protected {private} FGZHeader : TAbGzHeader; FExtraField : TAbGzipExtraField; FFileComment : AnsiString; FRawFileName : AnsiString; protected function GetFileSystem: TAbGzFileSystem; function GetHasExtraField: Boolean; function GetHasFileComment: Boolean; function GetHasFileName: Boolean; function GetIsText: Boolean; procedure SetFileComment(const Value : AnsiString); procedure SetFileSystem(const Value: TAbGzFileSystem); procedure SetIsText(const Value: Boolean); function GetExternalFileAttributes : LongWord; override; function GetIsEncrypted : Boolean; override; function GetLastModFileDate : Word; override; function GetLastModFileTime : Word; override; function GetLastModTimeAsDateTime: TDateTime; override; procedure SetExternalFileAttributes( Value : LongWord ); override; procedure SetFileName(const Value : string); override; procedure SetIsEncrypted(Value : Boolean); override; procedure SetLastModFileDate(const Value : Word); override; procedure SetLastModFileTime(const Value : Word); override; procedure SetLastModTimeAsDateTime(const Value: TDateTime); override; procedure SaveGzHeaderToStream(AStream : TStream); procedure LoadGzHeaderFromStream(AStream : TStream); public property CompressionMethod : Byte read FGZHeader.CompMethod; property ExtraFlags : Byte {Default: 2} read FGZHeader.XtraFlags write FGZHeader.XtraFlags; property Flags : Byte read FGZHeader.Flags; property FileComment : AnsiString read FFileComment write SetFileComment; property FileSystem : TAbGzFileSystem {Default: osFat (Windows); osUnix (Linux)} read GetFileSystem write SetFileSystem; property ExtraField : TAbGzipExtraField read FExtraField; property IsEncrypted : Boolean read GetIsEncrypted; property HasExtraField : Boolean read GetHasExtraField; property HasFileName : Boolean read GetHasFileName; property HasFileComment : Boolean read GetHasFileComment; property IsText : Boolean read GetIsText write SetIsText; property GZHeader : TAbGzHeader read FGZHeader; constructor Create; destructor Destroy; override; end; TAbGzipStreamHelper = class(TAbArchiveStreamHelper) private function GetGzCRC: LongInt; function GetFileSize: LongInt; protected {private} FItem : TAbGzipItem; FTail : TAbGzTailRec; public constructor Create(AStream : TStream); destructor Destroy; override; procedure ExtractItemData(AStream : TStream); override; function FindFirstItem : Boolean; override; function FindNextItem : Boolean; override; function SeekItem(Index : Integer): Boolean; override; procedure SeekToItemData; procedure WriteArchiveHeader; override; procedure WriteArchiveItem(AStream : TStream); override; procedure WriteArchiveTail; override; function GetItemCount : Integer; override; procedure ReadHeader; override; procedure ReadTail; override; property CRC : LongInt read GetGzCRC; property FileSize : LongInt read GetFileSize; property TailCRC : LongInt read FTail.CRC32; property TailSize : LongWord read FTail.ISize; end; TAbGzipArchiveState = (gsGzip, gsTar); TAbGzipArchive = class(TAbTarArchive) private FGZStream : TStream; { stream for GZip file} FGZItem : TAbArchiveList; { item in Gzip (only one, but need polymorphism of class)} FTarStream : TAbVirtualMemoryStream; { stream for possible contained Tar } FTarList : TAbArchiveList; { items in possible contained Tar } FTarAutoHandle: Boolean; FState : TAbGzipArchiveState; FIsGzippedTar : Boolean; procedure SetTarAutoHandle(const Value: Boolean); function GetIsGzippedTar: Boolean; procedure SwapToGzip; procedure SwapToTar; protected function CreateItem(const FileSpec : string): TAbArchiveItem; override; procedure ExtractItemAt(Index : Integer; const UseName : string); override; procedure ExtractItemToStreamAt(Index : Integer; aStream : TStream); override; procedure LoadArchive; override; procedure SaveArchive; override; procedure TestItemAt(Index : Integer); override; function FixName(const Value : string) : string; override; function GetSupportsEmptyFolders : Boolean; override; function GetItem(Index: Integer): TAbGzipItem; procedure PutItem(Index: Integer; const Value: TAbGzipItem); public {methods} constructor CreateFromStream(aStream : TStream; const aArchiveName : string); override; destructor Destroy; override; procedure DoSpanningMediaRequest(Sender : TObject; ImageNumber : Integer; var ImageName : string; var Abort : Boolean); override; property TarAutoHandle : Boolean read FTarAutoHandle write SetTarAutoHandle; property IsGzippedTar : Boolean read GetIsGzippedTar write FIsGzippedTar; property Items[Index : Integer] : TAbGzipItem read GetItem write PutItem; default; end; function VerifyGZip(Strm : TStream) : TAbArchiveType; function GZOsToStr(OS: Byte) : string; implementation uses {$IFDEF MSWINDOWS} Windows, {$ENDIF} {$IFDEF HasAnsiStrings} System.AnsiStrings, {$ENDIF} SysUtils, AbBitBkt, AbCharset, AbDfBase, AbDfDec, AbDfEnc, AbExcept, AbResString; const { Header Signature Values} AB_GZ_HDR_ID1 = $1F; AB_GZ_HDR_ID2 = $8B; { Test bits for TGzHeader.Flags field } AB_GZ_FLAG_FTEXT = $01; AB_GZ_FLAG_FCONTINUATION = $02; AB_GZ_FLAG_FEXTRA = $04; AB_GZ_FLAG_FNAME = $08; AB_GZ_FLAG_FCOMMENT = $10; AB_GZ_FLAG_FENCRYPTED = $20; AB_GZ_UNSUPPORTED_FLAGS = $E2; { GZip OS source flags } AB_GZ_OS_ID_FAT = 0; AB_GZ_OS_ID_Amiga = 1; AB_GZ_OS_ID_VMS = 2; AB_GZ_OS_ID_Unix = 3; AB_GZ_OS_ID_VM_CMS = 4; AB_GZ_OS_ID_AtariTOS = 5; AB_GZ_OS_ID_HPFS = 6; AB_GZ_OS_ID_Macintosh = 7; AB_GZ_OS_ID_Z_System = 8; AB_GZ_OS_ID_CP_M = 9; AB_GZ_OS_ID_TOPS20 = 10; AB_GZ_OS_ID_NTFS = 11; AB_GZ_OS_ID_QDOS = 12; AB_GZ_OS_ID_AcornRISCOS = 13; AB_GZ_OS_ID_VFAT = 14; AB_GZ_OS_ID_MVS = 15; AB_GZ_OS_ID_BEOS = 16; AB_GZ_OS_ID_TANDEM = 17; AB_GZ_OS_ID_THEOS = 18; AB_GZ_OS_ID_unknown = 255; function GZOsToStr(OS: Byte) : string; { Return a descriptive string for TGzHeader.OS field } begin case OS of AB_GZ_OS_ID_FAT : Result := AbGzOsFat; AB_GZ_OS_ID_Amiga : Result := AbGzOsAmiga; AB_GZ_OS_ID_VMS : Result := AbGzOsVMS; AB_GZ_OS_ID_Unix : Result := AbGzOsUnix; AB_GZ_OS_ID_VM_CMS : Result := AbGzOsVM_CMS; AB_GZ_OS_ID_AtariTOS : Result := AbGzOsAtari; AB_GZ_OS_ID_HPFS : Result := AbGzOsHPFS; AB_GZ_OS_ID_Macintosh : Result := AbGzOsMacintosh; AB_GZ_OS_ID_Z_System : Result := AbGzOsZ_System; AB_GZ_OS_ID_CP_M : Result := AbGzOsCP_M; AB_GZ_OS_ID_TOPS20 : Result := AbGzOsTOPS_20; AB_GZ_OS_ID_NTFS : Result := AbGzOsNTFS; AB_GZ_OS_ID_QDOS : Result := AbGzOsQDOS; AB_GZ_OS_ID_AcornRISCOS : Result := AbGzOsAcornRISCOS; AB_GZ_OS_ID_VFAT : Result := AbGzOsVFAT; AB_GZ_OS_ID_MVS : Result := AbGzOsMVS; AB_GZ_OS_ID_BEOS : Result := AbGzOsBeOS; AB_GZ_OS_ID_TANDEM : Result := AbGzOsTandem; AB_GZ_OS_ID_THEOS : Result := AbGzOsTHEOS; AB_GZ_OS_ID_unknown : Result := AbGzOsunknown; else Result := AbGzOsUndefined; end; end; function VerifyHeader(const Header : TAbGzHeader) : Boolean; begin { check id fields and if deflated (only handle deflate anyway)} Result := (Header.ID1 = AB_GZ_HDR_ID1) and (Header.ID2 = AB_GZ_HDR_ID2) and (Header.CompMethod = 8 {deflate}); end; function VerifyGZip(Strm : TStream) : TAbArchiveType; var GHlp : TAbGzipStreamHelper; Hlpr : TAbDeflateHelper; PartialTarData : TMemoryStream; CurPos : Int64; begin Result := atUnknown; CurPos := Strm.Position; try Strm.Seek(0, soBeginning); {prepare for the try..finally} Hlpr := nil; PartialTarData := nil; GHlp := TAbGzipStreamHelper.Create(Strm); try {create the stream helper and read the item header} GHlp.ReadHeader; { check id fields and if deflated (only handle deflate anyway)} if VerifyHeader(GHlp.FItem.FGZHeader) then begin Result := atGZip; { provisional } { check if is actually a Gzipped Tar } { partial extract contents, verify vs. Tar } PartialTarData := TMemoryStream.Create; GHlp.SeekToItemData; Hlpr := TAbDeflateHelper.Create; Hlpr.PartialSize := 512; PartialTarData.SetSize(512 * 2); Inflate(Strm, PartialTarData, Hlpr); {set to beginning of extracted data} PartialTarData.Position := 0; if (VerifyTar(PartialTarData) = atTar) then Result := atGZippedTar; end; finally GHlp.Free; Hlpr.Free; PartialTarData.Free; end; except on EReadError do Result := atUnknown; end; Strm.Position := CurPos; end; { TAbGzipExtraField } constructor TAbGzipExtraField.Create(aGZHeader : PAbGzHeader); begin inherited Create; FGZHeader := aGZHeader; end; procedure TAbGzipExtraField.Changed; begin if Buffer = nil then FGzHeader.Flags := FGzHeader.Flags and not AB_GZ_FLAG_FEXTRA else FGzHeader.Flags := FGzHeader.Flags or AB_GZ_FLAG_FEXTRA; end; procedure TAbGzipExtraField.Delete(aID : TAbGzExtraFieldSubID); begin inherited Delete(Word(aID)); end; function TAbGzipExtraField.GetID(aIndex : Integer): TAbGzExtraFieldSubID; begin Result := TAbGzExtraFieldSubID(inherited IDs[aIndex]); end; function TAbGzipExtraField.Get(aID : TAbGzExtraFieldSubID; out aData : Pointer; out aDataSize : Word) : Boolean; begin Result := inherited Get(Word(aID), aData, aDataSize); end; procedure TAbGzipExtraField.Put(aID : TAbGzExtraFieldSubID; const aData; aDataSize : Word); begin inherited Put(Word(aID), aData, aDataSize); end; { TAbGzipStreamHelper } constructor TAbGzipStreamHelper.Create(AStream : TStream); begin inherited Create(AStream); FItem := TAbGzipItem.Create; end; destructor TAbGzipStreamHelper.Destroy; begin FItem.Free; inherited; end; function ReadCStringInStream(AStream: TStream): AnsiString; { locate next instance of a null character in a stream leaves stream positioned just past that, or at end of stream if not found or null is last byte in stream. Result is the entire read string. } const BuffSiz = 1024; var Buff : array [0..BuffSiz-1] of AnsiChar; Len, DataRead : LongInt; begin { basically what this is supposed to do is...} { repeat AStream.Read(C, 1); Result := Result + C; until (AStream.Position = AStream.Size) or (C = #0); } Result := ''; repeat DataRead := AStream.Read(Buff, BuffSiz - 1); Buff[DataRead] := #0; Len := AbStrLen(Buff); if Len > 0 then begin SetLength(Result, Length(Result) + Len); Move(Buff, Result[Length(Result) - Len + 1], Len); end; if Len < DataRead then begin AStream.Seek(Len - DataRead + 1, soCurrent); Break; end; until DataRead = 0; end; procedure TAbGzipStreamHelper.SeekToItemData; {find end of header data, including FileName etc.} begin {** Seek to Compressed Data **} FStream.Seek(0, soBeginning); FItem.LoadGzHeaderFromStream(FStream); end; procedure TAbGzipStreamHelper.ExtractItemData(AStream: TStream); var Helper : TAbDeflateHelper; begin Helper := TAbDeflateHelper.Create; try SeekToItemData; if (AStream is TAbBitBucketStream) then Helper.Options := Helper.Options or dfc_TestOnly; FItem.CRC32 := Inflate(FStream, AStream, Helper); FItem.UncompressedSize := AStream.Size{Helper.NormalSize}; finally Helper.Free; end; end; function TAbGzipStreamHelper.FindFirstItem: Boolean; var GZH : TAbGzHeader; DataRead : Integer; begin Result := False; FStream.Seek(0, soBeginning); DataRead := FStream.Read(GZH, SizeOf(TAbGzHeader)); if (DataRead = SizeOf(TAbGzHeader)) and VerifyHeader(GZH) then begin FItem.FGZHeader := GZH; Result := True; end; FStream.Seek(0, soBeginning); end; function TAbGzipStreamHelper.FindNextItem: Boolean; begin { only one item in a GZip } Result := False; end; function TAbGzipStreamHelper.SeekItem(Index: Integer): Boolean; begin if Index > 0 then Result := False else Result := FindFirstItem; end; procedure TAbGzipStreamHelper.WriteArchiveHeader; begin FItem.SaveGzHeaderToStream(FStream); end; procedure TAbGzipStreamHelper.WriteArchiveItem(AStream: TStream); var Helper : TAbDeflateHelper; begin Helper := TAbDeflateHelper.Create; try FItem.CRC32 := Deflate(AStream, FStream, Helper); FItem.UncompressedSize := AStream.Size; finally Helper.Free; end; end; procedure TAbGzipStreamHelper.WriteArchiveTail; var Tail : TAbGzTailRec; begin Tail.CRC32 := FItem.CRC32; Tail.ISize := FItem.UncompressedSize; FStream.Write(Tail, SizeOf(TAbGzTailRec)); end; function TAbGzipStreamHelper.GetItemCount: Integer; begin { only one item in a gzip } Result := 1; end; procedure TAbGzipStreamHelper.ReadHeader; begin FItem.LoadGzHeaderFromStream(FStream); end; procedure TAbGzipStreamHelper.ReadTail; begin FStream.Read(FTail, SizeOf(TAbGzTailRec)); end; function TAbGzipStreamHelper.GetGzCRC: LongInt; begin Result := FItem.CRC32; end; function TAbGzipStreamHelper.GetFileSize: LongInt; begin Result := FItem.UncompressedSize; end; { TAbGzipItem } constructor TAbGzipItem.Create; begin inherited Create; { default ID fields } FGzHeader.ID1 := AB_GZ_HDR_ID1; FGzHeader.ID2 := AB_GZ_HDR_ID2; { compression method } FGzHeader.CompMethod := 8; { deflate } { Maxium Compression } FGzHeader.XtraFlags := 2; FFileName := ''; FFileComment := ''; FExtraField := TAbGzipExtraField.Create(@FGzHeader); { source OS ID } {$IFDEF LINUX } {assume EXT2 system } FGzHeader.OS := AB_GZ_OS_ID_Unix; {$ENDIF LINUX } {$IFDEF MSWINDOWS } {assume FAT system } FGzHeader.OS := AB_GZ_OS_ID_FAT; {$ENDIF MSWINDOWS } end; destructor TAbGzipItem.Destroy; begin FExtraField.Free; inherited; end; function TAbGzipItem.GetExternalFileAttributes: LongWord; begin { GZip has no provision for storing attributes } Result := 0; end; function TAbGzipItem.GetFileSystem: TAbGzFileSystem; begin case FGzHeader.OS of 0..18: Result := TAbGzFileSystem(FGzHeader.OS); 255: Result := osUnknown; else Result := osUndefined; end; { case } end; function TAbGzipItem.GetIsEncrypted: Boolean; begin Result := (FGZHeader.Flags and AB_GZ_FLAG_FENCRYPTED) = AB_GZ_FLAG_FENCRYPTED; end; function TAbGzipItem.GetHasExtraField: Boolean; begin Result := (FGZHeader.Flags and AB_GZ_FLAG_FEXTRA) = AB_GZ_FLAG_FEXTRA; end; function TAbGzipItem.GetHasFileComment: Boolean; begin Result := (FGZHeader.Flags and AB_GZ_FLAG_FCOMMENT) = AB_GZ_FLAG_FCOMMENT; end; function TAbGzipItem.GetHasFileName: Boolean; begin Result := (FGZHeader.Flags and AB_GZ_FLAG_FNAME) = AB_GZ_FLAG_FNAME; end; function TAbGzipItem.GetIsText: Boolean; begin Result := (FGZHeader.Flags and AB_GZ_FLAG_FTEXT) = AB_GZ_FLAG_FTEXT; end; function TAbGzipItem.GetLastModFileDate: Word; begin { convert to local DOS file Date } Result := LongRec(AbDateTimeToDosFileDate(LastModTimeAsDateTime)).Hi; end; function TAbGzipItem.GetLastModFileTime: Word; begin { convert to local DOS file Time } Result := LongRec(AbDateTimeToDosFileDate(LastModTimeAsDateTime)).Lo; end; function TAbGzipItem.GetLastModTimeAsDateTime: TDateTime; begin Result := AbUnixTimeToLocalDateTime(FGZHeader.ModTime); end; procedure TAbGzipItem.LoadGzHeaderFromStream(AStream: TStream); var LenW : Word; begin AStream.Read(FGzHeader, SizeOf(TAbGzHeader)); if not VerifyHeader(FGzHeader) then Exit; { Skip part number, if any } if (FGzHeader.Flags and AB_GZ_FLAG_FCONTINUATION) = AB_GZ_FLAG_FCONTINUATION then AStream.Seek(SizeOf(Word), soCurrent); if HasExtraField then begin { get length of extra data } AStream.Read(LenW, SizeOf(Word)); FExtraField.LoadFromStream(AStream, LenW); end else FExtraField.Clear; { Get Filename, if any } if HasFileName then begin FRawFileName := ReadCStringInStream(AStream); FFileName := AbRawBytesToString(FRawFileName) end else FFileName := 'unknown'; { any comment present? } if HasFileComment then FFileComment := ReadCStringInStream(AStream) else FFileComment := ''; {Assert: stream should now be located at start of compressed data } {If file was compressed with 3.3 spec this will be invalid so use with care} CompressedSize := AStream.Size - AStream.Position - SizeOf(TAbGzTailRec); FDiskFileName := FileName; AbUnfixName(FDiskFileName); Action := aaNone; Tagged := False; end; procedure TAbGzipItem.SaveGzHeaderToStream(AStream: TStream); var LenW : Word; begin { default ID fields } FGzHeader.ID1 := AB_GZ_HDR_ID1; FGzHeader.ID2 := AB_GZ_HDR_ID2; { compression method } FGzHeader.CompMethod := 8; { deflate } { reset unsupported flags } FGzHeader.Flags := FGzHeader.Flags and not AB_GZ_UNSUPPORTED_FLAGS; { main header data } AStream.Write(FGzHeader, SizeOf(TAbGzHeader)); { add extra field if any } if HasExtraField then begin LenW := Length(FExtraField.Buffer); AStream.Write(LenW, SizeOf(LenW)); if LenW > 0 then AStream.Write(FExtraField.Buffer[0], LenW); end; { add filename if any (and include final #0 from string) } if HasFileName then AStream.Write(FRawFileName[1], Length(FRawFileName) + 1); { add file comment if any (and include final #0 from string) } if HasFileComment then AStream.Write(FFileComment[1], Length(FFileComment) + 1); end; procedure TAbGzipItem.SetExternalFileAttributes(Value: LongWord); begin { do nothing } end; procedure TAbGzipItem.SetFileComment(const Value: AnsiString); begin FFileComment := Value; if FFileComment <> '' then FGzHeader.Flags := FGzHeader.Flags or AB_GZ_FLAG_FCOMMENT else FGzHeader.Flags := FGzHeader.Flags and not AB_GZ_FLAG_FCOMMENT; end; procedure TAbGzipItem.SetFileName(const Value: string); begin FFileName := Value; FRawFileName := AbStringToUnixBytes(Value); if Value <> '' then FGzHeader.Flags := FGzHeader.Flags or AB_GZ_FLAG_FNAME else FGzHeader.Flags := FGzHeader.Flags and not AB_GZ_FLAG_FNAME; end; procedure TAbGzipItem.SetFileSystem(const Value: TAbGzFileSystem); begin if Value = osUnknown then FGzHeader.OS := 255 else FGzHeader.OS := Ord(Value); end; procedure TAbGzipItem.SetIsEncrypted(Value: Boolean); begin { do nothing } end; procedure TAbGzipItem.SetIsText(const Value: Boolean); begin if Value then FGzHeader.Flags := FGzHeader.Flags or AB_GZ_FLAG_FTEXT else FGzHeader.Flags := FGzHeader.Flags and not AB_GZ_FLAG_FTEXT; end; procedure TAbGzipItem.SetLastModFileDate(const Value: Word); begin { replace date, keep existing time } LastModTimeAsDateTime := EncodeDate( Value shr 9 + 1980, Value shr 5 and 15, Value and 31) + Frac(LastModTimeAsDateTime); end; procedure TAbGzipItem.SetLastModFileTime(const Value: Word); begin { keep current date, replace time } LastModTimeAsDateTime := Trunc(LastModTimeAsDateTime) + EncodeTime( Value shr 11, Value shr 5 and 63, Value and 31 shl 1, 0); end; procedure TAbGzipItem.SetLastModTimeAsDateTime(const Value: TDateTime); begin FGZHeader.ModTime := AbLocalDateTimeToUnixTime(Value); end; { TAbGzipArchive } constructor TAbGzipArchive.CreateFromStream(aStream : TStream; const aArchiveName : string); begin inherited CreateFromStream(aStream, aArchiveName); FState := gsGzip; FGZStream := FStream; FGZItem := FItemList; FTarStream := TAbVirtualMemoryStream.Create; FTarList := TAbArchiveList.Create(True); end; procedure TAbGzipArchive.SwapToTar; begin FStream := FTarStream; FItemList := FTarList; FState := gsTar; end; procedure TAbGzipArchive.SwapToGzip; begin FStream := FGzStream; FItemList := FGzItem; FState := gsGzip; end; function TAbGzipArchive.CreateItem(const FileSpec: string): TAbArchiveItem; var GzItem : TAbGzipItem; begin if IsGZippedTar and TarAutoHandle then begin SwapToTar; Result := inherited CreateItem(FileSpec); end else begin SwapToGzip; GzItem := TAbGzipItem.Create; try GzItem.CompressedSize := 0; GzItem.CRC32 := 0; GzItem.DiskFileName := ExpandFileName(FileSpec); GzItem.FileName := FixName(FileSpec); Result := GzItem; except Result := nil; end; end; end; destructor TAbGzipArchive.Destroy; begin SwapToGzip; FTarList.Free; FTarStream.Free; inherited Destroy; end; procedure TAbGzipArchive.ExtractItemAt(Index: Integer; const UseName: string); var OutStream : TFileStream; CurItem : TAbGzipItem; begin if IsGZippedTar and TarAutoHandle then begin SwapToTar; inherited ExtractItemAt(Index, UseName); end else begin SwapToGzip; if Index > 0 then Index := 0; { only one item in a GZip} CurItem := TAbGzipItem(ItemList[Index]); OutStream := TFileStream.Create(UseName, fmCreate or fmShareDenyNone); try try {OutStream} ExtractItemToStreamAt(Index, OutStream); finally {OutStream} OutStream.Free; end; {OutStream} AbSetFileTime(UseName, CurItem.LastModTimeAsDateTime); AbSetFileAttr(UseName, CurItem.NativeFileAttributes); except on E : EAbUserAbort do begin FStatus := asInvalid; if FileExists(UseName) then DeleteFile(UseName); raise; end else begin if FileExists(UseName) then DeleteFile(UseName); raise; end; end; end; end; procedure TAbGzipArchive.ExtractItemToStreamAt(Index: Integer; aStream: TStream); var GzHelp : TAbGzipStreamHelper; begin if IsGzippedTar and TarAutoHandle then begin SwapToTar; inherited ExtractItemToStreamAt(Index, aStream); end else begin SwapToGzip; { note Index ignored as there's only one item in a GZip } GZHelp := TAbGzipStreamHelper.Create(FGzStream); try { read GZip Header } GzHelp.ReadHeader; { extract copy data from GZip} GzHelp.ExtractItemData(aStream); { Get validation data } GzHelp.ReadTail; {$IFDEF STRICTGZIP} { According to http://www.gzip.org/zlib/rfc1952.txt A compliant gzip compressor should calculate and set the CRC32 and ISIZE. However, a compliant decompressor should not check these values. If you want to check the the values of the CRC32 and ISIZE in a GZIP file when decompressing enable the STRICTGZIP define contained in AbDefine.inc } { validate against CRC } if GzHelp.FItem.Crc32 <> GzHelp.TailCRC then raise EAbGzipBadCRC.Create; { validate against file size } if GzHelp.FItem.UncompressedSize <> GZHelp.TailSize then raise EAbGzipBadFileSize.Create; {$ENDIF} finally GzHelp.Free; end; end; end; function TAbGzipArchive.FixName(const Value: string): string; { fix up fileaname for storage } begin if FState = gsTar then Result := inherited FixName( Value ) else begin {GZip files Always strip the file path} StoreOptions := StoreOptions + [soStripDrive, soStripPath]; Result := ''; if Value <> '' then Result := ExtractFileName(Value); end; end; function TAbGzipArchive.GetIsGzippedTar: Boolean; begin Result := FIsGzippedTar; end; function TAbGzipArchive.GetItem(Index: Integer): TAbGzipItem; begin Result := nil; if Index = 0 then Result := TAbGzipItem(FItemList.Items[Index]); end; function TAbGzipArchive.GetSupportsEmptyFolders : Boolean; begin Result := IsGzippedTar and TarAutoHandle; end; procedure TAbGzipArchive.LoadArchive; var GzHelp : TAbGzipStreamHelper; Item : TAbGzipItem; Abort : Boolean; begin SwapToGzip; if FGzStream.Size > 0 then begin GzHelp := TAbGzipStreamHelper.Create(FGzStream); try if GzHelp.FindFirstItem then begin Item := TAbGzipItem.Create; Item.LoadGzHeaderFromStream(FGzStream); FGzStream.Seek(-SizeOf(TAbGzTailRec), soEnd); GZHelp.ReadTail; Item.CRC32 := GZHelp.TailCRC; Item.UncompressedSize := GZHelp.TailSize; Item.Action := aaNone; FGZItem.Add(Item); if IsGzippedTar and TarAutoHandle then begin { extract Tar and set stream up } FTarStream.SwapFileDirectory := FTempDir; GzHelp.SeekToItemData; GzHelp.ExtractItemData(FTarStream); SwapToTar; inherited LoadArchive; end; end; DoArchiveProgress(100, Abort); FIsDirty := False; finally { Clean Up } GzHelp.Free; end; end; end; procedure TAbGzipArchive.PutItem(Index: Integer; const Value: TAbGzipItem); begin if Index = 0 then FItemList.Items[Index] := Value; end; procedure TAbGzipArchive.SaveArchive; var InGzHelp, OutGzHelp : TAbGzipStreamHelper; Abort : Boolean; i : Integer; NewStream : TAbVirtualMemoryStream; UncompressedStream : TStream; SaveDir : string; CurItem : TAbGzipItem; begin {prepare for the try..finally} OutGzHelp := nil; NewStream := nil; try InGzHelp := TAbGzipStreamHelper.Create(FGzStream); try {init new archive stream} NewStream := TAbVirtualMemoryStream.Create; OutGzHelp := TAbGzipStreamHelper.Create(NewStream); { create helper } NewStream.SwapFileDirectory := FTempDir; { save the Tar data } if IsGzippedTar and TarAutoHandle then begin SwapToTar; inherited SaveArchive; if FGZItem.Count = 0 then begin CurItem := TAbGzipItem.Create; FGZItem.Add(CurItem); end; CurItem := FGZItem[0] as TAbGzipItem; CurItem.Action := aaNone; CurItem.LastModTimeAsDateTime := Now; CurItem.SaveGzHeaderToStream(NewStream); FTarStream.Position := 0; OutGzHelp.WriteArchiveItem(FTarStream); CurItem.CRC32 := OutGzHelp.CRC; CurItem.UncompressedSize := OutGzHelp.FileSize; OutGzHelp.WriteArchiveTail; end else begin SwapToGzip; {build new archive from existing archive} for i := 0 to pred(Count) do begin FCurrentItem := ItemList[i]; CurItem := TAbGzipItem(ItemList[i]); InGzHelp.SeekToItemData; case CurItem.Action of aaNone, aaMove : begin {just copy the file to new stream} CurItem.SaveGzHeaderToStream(NewStream); InGzHelp.SeekToItemData; NewStream.CopyFrom(FGZStream, FGZStream.Size - FGZStream.Position); end; aaDelete: {doing nothing omits file from new stream} ; aaAdd, aaFreshen, aaReplace, aaStreamAdd: begin try if (CurItem.Action = aaStreamAdd) then begin { adding from a stream } CurItem.SaveGzHeaderToStream(NewStream); CurItem.UncompressedSize := InStream.Size; OutGzHelp.WriteArchiveItem(InStream); OutGzHelp.WriteArchiveTail; end else begin { it's coming from a file } GetDir(0, SaveDir); try {SaveDir} if (BaseDirectory <> '') then ChDir(BaseDirectory); CurItem.LastModTimeAsDateTime := AbGetFileTime(CurItem.DiskFileName); UncompressedStream := TFileStream.Create(CurItem.DiskFileName, fmOpenRead or fmShareDenyWrite ); finally {SaveDir} ChDir( SaveDir ); end; {SaveDir} try CurItem.UncompressedSize := UncompressedStream.Size; CurItem.SaveGzHeaderToStream(NewStream); OutGzHelp.WriteArchiveItem(UncompressedStream); OutGzHelp.WriteArchiveTail; finally {UncompressedStream} UncompressedStream.Free; end; {UncompressedStream} end; except ItemList[i].Action := aaDelete; DoProcessItemFailure(ItemList[i], ptAdd, ecFileOpenError, 0); end; end; end; {case} end; { for } end; finally InGzHelp.Free; end; {copy new stream to FStream} SwapToGzip; NewStream.Position := 0; if (FStream is TMemoryStream) then TMemoryStream(FStream).LoadFromStream(NewStream) else if FOwnsStream then begin { need new stream to write } FreeAndNil(FStream); FGZStream := nil; FStream := TFileStream.Create(FArchiveName, fmCreate or fmShareDenyWrite); FGZStream := FStream; FStream.CopyFrom(NewStream, NewStream.Size); end else begin FStream.Size := 0; FStream.Position := 0; FStream.CopyFrom(NewStream, NewStream.Size); end; {update Items list} for i := pred( Count ) downto 0 do begin if ItemList[i].Action = aaDelete then FItemList.Delete( i ) else if ItemList[i].Action <> aaFailed then ItemList[i].Action := aaNone; end; if IsGzippedTar and TarAutoHandle then SwapToTar; DoArchiveSaveProgress( 100, Abort ); DoArchiveProgress( 100, Abort ); finally {NewStream} OutGzHelp.Free; NewStream.Free; end; end; procedure TAbGzipArchive.SetTarAutoHandle(const Value: Boolean); begin if Value then SwapToTar else SwapToGzip; FTarAutoHandle := Value; end; procedure TAbGzipArchive.TestItemAt(Index: Integer); var SavePos : LongInt; GZType : TAbArchiveType; BitBucket : TAbBitBucketStream; GZHelp : TAbGzipStreamHelper; begin if IsGzippedTar and TarAutoHandle then begin inherited TestItemAt(Index); end else begin { note Index ignored as there's only one item in a GZip } SavePos := FGzStream.Position; GZType := VerifyGZip(FGZStream); if not (GZType in [atGZip, atGZippedTar]) then raise EAbGzipInvalid.Create; BitBucket := nil; GZHelp := nil; try BitBucket := TAbBitBucketStream.Create(1024); GZHelp := TAbGzipStreamHelper.Create(FGZStream); GZHelp.ExtractItemData(BitBucket); GZHelp.ReadTail; { validate against CRC } if GzHelp.FItem.Crc32 <> GZHelp.TailCRC then raise EAbGzipBadCRC.Create; { validate against file size } if GzHelp.FItem.UncompressedSize <> GZHelp.TailSize then raise EAbGzipBadFileSize.Create; finally GZHelp.Free; BitBucket.Free; end; FGzStream.Position := SavePos; end; end; procedure TAbGzipArchive.DoSpanningMediaRequest(Sender: TObject; ImageNumber: Integer; var ImageName: string; var Abort: Boolean); begin Abort := False; end; end. ================================================ FILE: lib/abbrevia/source/AbHexVw.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* Abbrevia: AbHexVw.pas *} {*********************************************************} {* Abbrevia: Hex View utility *} {*********************************************************} {$I AbDefine.inc} {$IFNDEF UsingCLX} unit AbHexVw; {$ENDIF} interface uses Classes, {$IFDEF UsingCLX} QStdCtrls, QGraphics, {$ELSE} StdCtrls, Graphics, {$ENDIF} SysUtils; type THexView = class(TMemo) protected FBlockSize : Integer; public procedure SetStream(Strm : TStream); constructor Create(AOwner : TComponent); override; destructor Destroy; override; property Stream : TStream write SetStream; property BlockSize : Integer read FBlockSize write FBlockSize; end; implementation {$IFDEF HasUITypes} uses System.UITypes; {$ENDIF} constructor THexView.Create(AOwner : TComponent); begin Inherited Create(AOwner); Font.Style := Font.Style + [fsBold]; ReadOnly := True; ScrollBars := ssVertical; WordWrap := False; WantTabs := True; FBlockSize := 512; end; destructor THexView.Destroy; begin inherited Destroy; end; procedure THexView.SetStream(Strm : TStream); var Buff : Array[0..15] of Byte; i, j : Integer; Str : String; StrList : TStringList; begin Strm.Seek(0, soBeginning); StrList := TStringList.Create; Clear; while Strm.Position < Strm.Size do begin if ((Strm.Position mod FBlockSize) = 0) then StrList.Add('==========================================================='); Str := ''; for j := 0 to 15 do Buff[j] := Byte(chr(0)); Strm.Read(Buff, 16); Str := Str + Format('%4.4X', [strm.Position - $10]) + ':' + #9; for i := 0 to 15 do begin Str := Str + Format('%2.2X', [Buff[i]]) + ' '; if i = 7 then Str := Str + #9; end; Str := Str + #9; for i := 0 to 15 do begin if (Buff[i] < $30) then Buff[i] := byte('.'); Str := Str + Char(Buff[i]); end; StrList.Add(Str); end; SetLines(StrList); StrList.Free; end; end. ================================================ FILE: lib/abbrevia/source/AbLZMA.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is Craig Peterson * * Portions created by the Initial Developer are Copyright (C) 2011 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Craig Peterson * Pierre le Riche * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbLZMA.pas *} {*********************************************************} {* ABBREVIA: Lzma compression/decompression procedures. *} {*********************************************************} unit AbLZMA; {$I AbDefine.inc} interface uses Classes, Windows, SysUtils, AbCrtl, AbUtils; { Raw LZMA decompression =================================================== } { Decompresses the LZMA compressed data in ASrc to ADes. ASrc should not have the header used by the other compression/decompression routines, and AProperties should contain any necessary data. } procedure LzmaDecodeStream(AProperties: PByte; APropSize: Integer; ASrc, ADes: TStream; AUncompressedSize: Int64 = -1); overload; { Stream compression and decompression (taken from LzmaUtil.c) ============= } procedure LzmaDecodeStream(ASourceStream, ATargetStream: TStream); overload; procedure LzmaEncodeStream(ASourceStream, ATargetStream: TStream; ASourceSize: Int64); { In-memory compression and decompression ================================== } { Given a pointer to the compressed data, this will return the size of the decompressed data. } function LzmaGetUncompressedSize(APCompressedData: Pointer; ACompressedSize: Integer): Integer; { Decompresses the LZMA compressed data at APCompressedData to the buffer pointed to by APUncompressedData. The buffer at APUncompressedData should be large enough to hold the number of bytes as returned by LzmaGetDecompressedSize. } procedure LzmaDecodeBuffer(APCompressedData: Pointer; ACompressedSize: Integer; APUncompressedData: Pointer); { Compresses the data at APUncompressedData to the buffer at APCompressedData, and returns the number of bytes written. If ACompressedDataBufferCapacity is less than the number of bytes required to store the entire compressed stream, or any other error occurs, then an exception is raised. (A safe number for ACompressedDataBufferCapacity is slightly more than AUncompressedDataBufferSize.) Leave ACompressionLevel and ADictionarySize at -1 in order to use the default values (5 and 16MB respectively). } function LzmaEncodeBuffer(APUncompressedData: Pointer; AUncompressedSize: Integer; APCompressedData: Pointer; ACompressedDataBufferCapacity: Integer; ACompressionLevel: Integer = -1; ADictionarySize: Integer = -1): Integer; { Types.h declarations ===================================================== } const SZ_OK = 0; SZ_ERROR_DATA = 1; SZ_ERROR_MEM = 2; SZ_ERROR_CRC = 3; SZ_ERROR_UNSUPPORTED = 4; SZ_ERROR_PARAM = 5; SZ_ERROR_INPUT_EOF = 6; SZ_ERROR_OUTPUT_EOF = 7; SZ_ERROR_READ = 8; SZ_ERROR_WRITE = 9; SZ_ERROR_PROGRESS = 10; SZ_ERROR_FAIL = 11; SZ_ERROR_THREAD = 12; SZ_ERROR_ARCHIVE = 16; SZ_ERROR_NO_ARCHIVE = 17; type SRes = Integer; ISeqInStream = packed record Read: function(p: Pointer; var buf; var size: size_t): SRes; cdecl; end; PISeqInStream = ^ISeqInStream; ISeqOutStream = packed record Write: function(p: Pointer; const buf; size: size_t): size_t; cdecl; end; PISeqOutStream = ^ISeqOutStream; ICompressProgress = packed record Progress: function(p: Pointer; inSize, outSize: Int64): SRes; cdecl; end; PICompressProgress = ^ICompressProgress; ISzAlloc = packed record Alloc: function(p: Pointer; size: size_t): Pointer; cdecl; Free: procedure(p: Pointer; address: Pointer); cdecl; end; PISzAlloc = ^ISzAlloc; { LzmaDec.h declarations =================================================== } type CLzmaProb = Word; // LZMA Properties const LZMA_PROPS_SIZE = 5; type CLzmaProps = packed record lc, lp, pb: Cardinal; dicSize: UInt32; end; // LZMA Decoder state const LZMA_REQUIRED_INPUT_MAX = 20; type CLzmaDec = packed record prop: CLzmaProps; probs: ^CLzmaProb; dic: PByte; buf: PByte; range, code: UInt32; dicPos: size_t; dicBufSize: size_t; processedPos: UInt32; checkDicSize: UInt32; state: Cardinal; reps: array[0..3] of UInt32; remainLen: Cardinal; needFlush: Integer; needInitState: Integer; numProbs: UInt32; tempBufSize: Cardinal; tempBuf: array[0..LZMA_REQUIRED_INPUT_MAX - 1] of Byte; end; type ELzmaFinishMode = LongInt; const LZMA_FINISH_ANY = 0; // finish at any point LZMA_FINISH_END = 1; // block must be finished at the end type ELzmaStatus = LongInt; const LZMA_STATUS_NOT_SPECIFIED = 0; // use main error code instead LZMA_STATUS_FINISHED_WITH_MARK = 1; // stream was finished with end mark. LZMA_STATUS_NOT_FINISHED = 3; // stream was not finished LZMA_STATUS_NEEDS_MORE_INPUT = 4; // you must provide more input bytes LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK = 5; // there is probability that stream was finished without end mark procedure LzmaDec_Construct(var p: CLzmaDec); cdecl; procedure LzmaDec_Init(var p: CLzmaDec); cdecl; external; function LzmaDec_DecodeToBuf(var p: CLzmaDec; dest: PByte; var destLen: size_t; src: PByte; var srcLen: size_t; finishMode: ELzmaFinishMode; var status: ELzmaStatus): SRes; cdecl; external; function LzmaDec_Allocate(var state: CLzmaDec; prop: PByte; propsSize: Integer; alloc: PISzAlloc): SRes; cdecl; external; procedure LzmaDec_Free(var state: CLzmaDec; alloc: PISzAlloc); cdecl; external; // One call decoding interface function LzmaDecode(dest: PByte; var destLen: size_t; src: PByte; var srcLen: size_t; propData: PByte; propSize: Integer; finishMode: ELzmaFinishMode; var status: ELzmaStatus; alloc: PISzAlloc): SRes; cdecl; external; { LzmaEnc.h declarations =================================================== } type CLzmaEncHandle = Pointer; CLzmaEncProps = packed record level: Integer; // 0 <= level <= 9 dictSize: UInt32; // (1 << 12) <= dictSize <= (1 << 27) for 32-bit version // (1 << 12) <= dictSize <= (1 << 30) for 64-bit version // default = (1 << 24) lc: Integer; // 0 <= lc <= 8, default = 3 lp: Integer; // 0 <= lp <= 4, default = 0 pb: Integer; // 0 <= pb <= 4, default = 2 algo: Integer; // 0 - fast, 1 - normal, default = 1 fb: Integer; // 5 <= fb <= 273, default = 32 btMode: Integer; // 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 numHashBytes: Integer; // 2, 3 or 4, default = 4 mc: UInt32; // 1 <= mc <= (1 << 30), default = 32 writeEndMark: Cardinal; // 0 - do not write EOPM, 1 - write EOPM, default = 0 numThreads: Integer; // 1 or 2, default = 2 end; procedure LzmaEncProps_Init(var p: CLzmaEncProps); cdecl; external; function LzmaEnc_Create(Alloc: PISzAlloc): CLzmaEncHandle; cdecl; external; procedure LzmaEnc_Destroy(p: CLzmaEncHandle; Alloc, allocBig: PISzAlloc); cdecl; external; function LzmaEnc_SetProps(p: CLzmaEncHandle; var props: CLzmaEncProps): SRes; cdecl; external; function LzmaEnc_WriteProperties(p: CLzmaEncHandle; properties: PByte; var size: size_t): SRes; cdecl; external; function LzmaEnc_Encode(p: CLzmaEncHandle; outStream: PISeqOutStream; inStream: PISeqInStream; Progress: PICompressProgress; Alloc, allocBig: PISzAlloc): SRes; cdecl; external; function LzmaEnc_MemEncode(p: CLzmaEncHandle; dest: PByte; var destLen: size_t; src: PByte; srcLen: size_t; writeEndMark: Integer; Progress: PICompressProgress; Alloc, allocBig: PISzAlloc): SRes; cdecl; external; // One call encoding interface function LzmaEncode(dest: PByte; var destLen: size_t; src: PByte; srcLen: size_t; var props: CLzmaEncProps; propsEncoded: PByte; var propsSize: size_t; writeEndMark: Integer; progress: PICompressProgress; alloc: pISzAlloc; allocBig: PISzAlloc): SRes; cdecl; external; { LzFind.h declarations ==================================================== } procedure MatchFinder_NeedMove; external; procedure MatchFinder_GetPointerToCurrentPos; external; procedure MatchFinder_MoveBlock; external; procedure MatchFinder_ReadIfRequired; external; procedure MatchFinder_Construct; external; procedure MatchFinder_Create; external; procedure MatchFinder_Free; external; procedure MatchFinder_Normalize3; external; procedure MatchFinder_ReduceOffsets; external; procedure GetMatchesSpec1; external; procedure MatchFinder_Init; external; procedure MatchFinder_CreateVTable; external; { LzFindMt.h declarations ================================================== } procedure MatchFinderMt_Construct; external; procedure MatchFinderMt_Destruct; external; procedure MatchFinderMt_Create; external; procedure MatchFinderMt_CreateVTable; external; procedure MatchFinderMt_ReleaseStream; external; { Lzma header fields ======================================================= } type // The condensed compression properties TLZMAPropertyData = array[0..LZMA_PROPS_SIZE - 1] of Byte; // The header usually stored in front of LZMA compressed data TLZMAHeader = packed record PropertyData: TLZMAPropertyData; UncompressedSize: Int64; end; PLZMAHeader = ^TLZMAHeader; { Error handling =========================================================== } type EAbLZMAException = class(Exception); procedure LzmaCheck(AResultCode: SRes); procedure RaiseLzmaException(AResultCode: SRes); { Linker directives ======================================================== } {$WARN BAD_GLOBAL_SYMBOL OFF} {$IF DEFINED(WIN32)} {$L Win32\LzFind.obj} {$L Win32\LzFindMt.obj} {$L Win32\LzmaDec.obj} {$L Win32\LzmaEnc.obj} {$L Win32\Threads.obj} {$ELSEIF DEFINED(WIN64)} {$L Win64\LzFind.obj} {$L Win64\LzFindMt.obj} {$L Win64\LzmaDec.obj} {$L Win64\LzmaEnc.obj} {$L Win64\Threads.obj} {$IFEND} implementation { Error handling =========================================================== } procedure LzmaCheck(AResultCode: SRes); begin if AResultCode <> SZ_OK then RaiseLzmaException(AResultCode); end; { -------------------------------------------------------------------------- } procedure RaiseLzmaException(AResultCode: SRes); begin case AResultCode of SZ_ERROR_DATA: raise EAbLZMAException.Create('LZMA Data Error.'); SZ_ERROR_MEM: raise EAbLZMAException.Create('LZMA Memory Error.'); SZ_ERROR_CRC: raise EAbLZMAException.Create('LZMA CRC Error.'); SZ_ERROR_UNSUPPORTED: raise EAbLZMAException.Create('LZMA "Unsupported" Error.'); SZ_ERROR_PARAM: raise EAbLZMAException.Create('LZMA Parameter Error.'); SZ_ERROR_INPUT_EOF: raise EAbLZMAException.Create('LZMA Input EOF Error.'); SZ_ERROR_OUTPUT_EOF: raise EAbLZMAException.Create('LZMA Output EOF Error.'); SZ_ERROR_READ: raise EAbLZMAException.Create('LZMA Read Error.'); SZ_ERROR_WRITE: raise EAbLZMAException.Create('LZMA Write Error.'); SZ_ERROR_PROGRESS: raise EAbLZMAException.Create('LZMA Progress Error.'); SZ_ERROR_FAIL: raise EAbLZMAException.Create('LZMA "Fail" Error.'); SZ_ERROR_THREAD: raise EAbLZMAException.Create('LZMA Thread Error.'); SZ_ERROR_ARCHIVE: raise EAbLZMAException.Create('LZMA Archive Error.'); SZ_ERROR_NO_ARCHIVE: raise EAbLZMAException.Create('LZMA "No Archive" Error.'); else raise EAbLZMAException.CreateFmt('Unknown LZMA error (%d)', [AResultCode]); end; end; { Helper Routines ========================================================== } procedure LzmaDec_Construct(var p: CLzmaDec); cdecl; begin p.dic := nil; p.probs := nil; end; { -------------------------------------------------------------------------- } function SzAlloc(p: Pointer; size: size_t): Pointer; cdecl; begin Result := GetMemory(size); end; { -------------------------------------------------------------------------- } procedure SzFree(p, address: Pointer); cdecl; begin FreeMemory(address); end; var DelphiMMInterface: ISzAlloc = (Alloc: SzAlloc; Free: SzFree); { CSeq*Stream implementation =============================================== } type CSeqInStream = packed record Intf: ISeqInStream; Stream: TStream; end; CSeqOutStream = packed record Intf: ISeqOutStream; Stream: TStream; end; { -------------------------------------------------------------------------- } function ISeqInStream_Read(p: Pointer; var buf; var size: size_t): SRes; cdecl; begin try size := CSeqInStream(p^).Stream.Read(buf, size); Result := SZ_OK; except Result := SZ_ERROR_DATA; end; end; { -------------------------------------------------------------------------- } function ISeqOutStream_Write(p: Pointer; const buf; size: size_t): size_t; cdecl; begin try Result := CSeqOutStream(p^).Stream.Write(buf, size); except Result := 0; end; end; { Raw LZMA decompression =================================================== } { Decompress an Lzma compressed stream. Based on LzmaUtil.c::Decode2 } function LzmaDecode2(var aState: CLzmaDec; aOutStream, aInStream: TStream; aUncompressedSize: Int64 = -1): SRes; const IN_BUF_SIZE = 1 shl 16; OUT_BUF_SIZE = 1 shl 16; var LHasSize: Boolean; LInBuf: array [0..IN_BUF_SIZE - 1] of Byte; LOutBuf: array [0..OUT_BUF_SIZE - 1] of Byte; LInPos, LInSize, LOutPos: size_t; LInProcessed, LOutProcessed: size_t; LFinishMode: ELzmaFinishMode; LStatus: ELzmaStatus; begin Result := 0; LHasSize := aUncompressedSize <> -1; LInPos := 0; LInSize := 0; LOutPos := 0; LzmaDec_Init(aState); while True do begin if LInPos = LInSize then begin LInSize := aInStream.Read(LInBuf, IN_BUF_SIZE); LInPos := 0; if LInSize = 0 then Break; end else begin LInProcessed := LInSize - LInPos; LOutProcessed := OUT_BUF_SIZE - LOutPos; LFinishMode := LZMA_FINISH_ANY; if LHasSize and (LOutProcessed > aUncompressedSize) then begin LOutProcessed := size_t(aUncompressedSize); LFinishMode := LZMA_FINISH_END; end; Result := LzmaDec_DecodeToBuf(aState, @LOutBuf[LOutPos], LOutProcessed, @LInBuf[LInPos], LInProcessed, LFinishMode, LStatus); Inc(LInPos, LInProcessed); Inc(LOutPos, LOutProcessed); Dec(aUncompressedSize, LOutProcessed); if (aOutStream <> nil) and (aOutStream.Write(LOutBuf, LOutPos) <> LOutPos) then begin Result := SZ_ERROR_WRITE; Exit; end; LOutPos := 0; if (Result <> SZ_OK) or (LHasSize and (aUncompressedSize = 0)) then Exit; if (LInProcessed = 0) and (LOutProcessed = 0) then begin if LHasSize or (LStatus <> LZMA_STATUS_FINISHED_WITH_MARK) then Result := SZ_ERROR_DATA; Exit; end; end; end; end; { -------------------------------------------------------------------------- } { Decompress an LZMA compressed stream. Pass AUncompressedSize = -1 if the uncompressed size is not known. } procedure LzmaDecodeStream(AProperties: PByte; APropSize: Integer; ASrc, ADes: TStream; AUncompressedSize: Int64); var LLZMADecState: CLzmaDec; begin LzmaDec_Construct(LLZMADecState); try LzmaCheck(LzmaDec_Allocate(LLZMADecState, AProperties, APropSize, @DelphiMMInterface)); LzmaCheck(LzmaDecode2(LLZMADecState, ADes, ASrc, AUncompressedSize)); finally LzmaDec_Free(LLZMADecState, @DelphiMMInterface); end; end; { Stream to stream compression and decompression =========================== } { Decompresses streams compressed with the LZMA SDK's LzmaUtil.exe. Based on LzmaUtil.c::Decode } procedure LzmaDecodeStream(ASourceStream, ATargetStream: TStream); var LUncompressedSize: Int64; // Header: 5 bytes of LZMA properties and 8 bytes of uncompressed size LHeader: TLZMAHeader; begin // Read and parse header ASourceStream.ReadBuffer(LHeader, SizeOf(LHeader)); LUncompressedSize := LHeader.UncompressedSize; LzmaDecodeStream(PByte(@LHeader.PropertyData), LZMA_PROPS_SIZE, ASourceStream, ATargetStream, LUncompressedSize); end; { -------------------------------------------------------------------------- } { Compresses a stream so it's compatible with the LZMA SDK's LzmaUtil.exe. Based on LzmaUtil.c::Encode } procedure LzmaEncodeStream(ASourceStream, ATargetStream: TStream; ASourceSize: Int64); var LEncHandle: CLzmaEncHandle; LEncProps: CLzmaEncProps; LHeader: TLZMAHeader; LPropDataSize: size_t; LInStreamRec: CSeqInStream; LOutStreamRec: CSeqOutStream; begin LInStreamRec.Intf.Read := ISeqInStream_Read; LInStreamRec.Stream := ASourceStream; LOutStreamRec.Intf.Write := ISeqOutStream_Write; LOutStreamRec.Stream := ATargetStream; LEncHandle := LzmaEnc_Create(@DelphiMMInterface); if LEncHandle = nil then LzmaCheck(SZ_ERROR_MEM); try LzmaEncProps_Init(LEncProps); LzmaCheck(LzmaEnc_SetProps(LEncHandle, LEncProps)); LPropDataSize := LZMA_PROPS_SIZE; LzmaCheck(LzmaEnc_WriteProperties(LEncHandle, PByte(@LHeader.PropertyData), LPropDataSize)); LHeader.UncompressedSize := ASourceSize; ATargetStream.WriteBuffer(LHeader, SizeOf(LHeader)); LzmaCheck(LzmaEnc_Encode(LEncHandle, @LOutStreamRec.Intf, @LInStreamRec.Intf, nil, @DelphiMMInterface, @DelphiMMInterface)); finally LzmaEnc_Destroy(LEncHandle, @DelphiMMInterface, @DelphiMMInterface); end; end; { In-memory compression and decompression ================================== } { Given a pointer to the compressed data, this will return the size of the decompressed data. } function LzmaGetUncompressedSize(APCompressedData: Pointer; ACompressedSize: Integer): Integer; begin if ACompressedSize <= SizeOf(TLZMAHeader) then raise EAbLZMAException.Create('The LZMA compressed data is invalid (not enough bytes)'); Result := PLZMAHeader(APCompressedData).UncompressedSize; end; { -------------------------------------------------------------------------- } { Decompresses the LZMA compressed data at APCompressedData to the buffer pointed to by APUncompressedData. The buffer at APUncompressedData should be large enough to hold the number of bytes as returned by LzGetDecompressedSize. } procedure LzmaDecodeBuffer(APCompressedData: Pointer; ACompressedSize: Integer; APUncompressedData: Pointer); var LPropertyData: TLZMAPropertyData; LUncompressedSize: Int64; LInputByteCount, LOutputByteCount: size_t; LStatus: ELzmaStatus; begin if ACompressedSize <= SizeOf(TLZMAHeader) then raise EAbLZMAException.Create('The LZMA compressed data is invalid (not enough bytes)'); // Read the header from the compressed data. LPropertyData := PLZMAHeader(APCompressedData).PropertyData; LUncompressedSize := PLZMAHeader(APCompressedData).UncompressedSize; Inc(PAnsiChar(APCompressedData), SizeOf(TLZMAHeader)); Dec(ACompressedSize, SizeOf(TLZMAHeader)); // Decompress from the input to the output buffer. This will change the byte // count variables to the actual number of bytes consumed/written. LInputByteCount := ACompressedSize; LOutputByteCount := LUncompressedSize; LzmaCheck(LzmaDecode(APUncompressedData, LOutputByteCount, APCompressedData, LInputByteCount, PByte(@LPropertyData), LZMA_PROPS_SIZE, LZMA_FINISH_END, LStatus, @DelphiMMInterface)); // Check that the input buffer was fully consumed and the output buffer was filled up. if (LOutputByteCount <> LUncompressedSize) or (LInputByteCount <> ACompressedSize) then raise EAbLZMAException.Create('LZMA decompression data error'); end; { -------------------------------------------------------------------------- } { Compresses the data at APUncompressedData to the buffer at APCompressedData, and returns the number of bytes written. If ACompressedDataBufferCapacity is less than the number of bytes required to store the entire compressed stream, or any other error occurs, then an exception is raised. (A safe number for ACompressedDataBufferCapacity is slightly more than AUncompressedDataBufferSize.) Leave ACompressionLevel and ADictionarySize at -1 in order to use the default values (5 and 16MB respectively). } function LzmaEncodeBuffer(APUncompressedData: Pointer; AUncompressedSize: Integer; APCompressedData: Pointer; ACompressedDataBufferCapacity, ACompressionLevel, ADictionarySize: Integer): Integer; var LEncProps: CLzmaEncProps; LPropsSize: size_t; LPOutBuf: PByte; LOutputBytes: size_t; begin if ACompressedDataBufferCapacity <= SizeOf(TLZMAHeader) then raise EAbLZMAException.Create('LZMA output buffer too small'); // Set the uncompressed size in the header PLZMAHeader(APCompressedData).UncompressedSize := AUncompressedSize; // Set the properties LzmaEncProps_Init(LEncProps); if ACompressionLevel >= 0 then LEncProps.level := ACompressionLevel; if ADictionarySize >= 0 then LEncProps.dictSize := ADictionarySize; LPOutBuf := PByte(PtrUInt(APCompressedData) + SizeOf(TLZMAHeader)); LOutputBytes := ACompressedDataBufferCapacity - SizeOf(TLZMAHeader); LPropsSize := LZMA_PROPS_SIZE; LzmaCheck(LzmaEncode(LPOutBuf, LOutputBytes, APUncompressedData, AUncompressedSize, LEncProps, APCompressedData, LPropsSize, 0, nil, @DelphiMMInterface, @DelphiMMInterface)); Result := LOutputBytes + SizeOf(TLZMAHeader); end; initialization // The LZMA routines are multithreaded and use the Delphi memory manager. IsMultiThread := True; end. ================================================ FILE: lib/abbrevia/source/AbLZMAStream.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is Pierre le Riche * * Portions created by the Initial Developer are Copyright (C) 2011 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Pierre le Riche * Craig Peterson * * ***** END LICENSE BLOCK ***** Usage: LZMA Compression: 1) Create a TAbLZMACompressionStream, passing as parameter to the constructor the output stream where you want the compressed data stored. 2) Write the data that you want to compress to the TAbLZMACompressionStream. Compression occurs in a background thread. 3) (Optional) Notify the background compression thread that no more data will be written by calling NoMoreDataToCompress. Poll the IsBusy method to determine whether the background thread is still busy. 4) Free the TAbLZMACompressionStream to finish up and release resources. The compressed data will now be available in the output stream. LZMA Decompression: 1) Create a TAbLZMADecompressionStream, passing as parameter to the constructor the stream that contains the compressed data. 2) Read the decompressed data from TAbLZMADecompressionStream. 3) Free the TAbLZMADecompressionStream to finish up and release resources. *) unit AbLZMAStream; {$I AbDefine.inc} interface uses Windows, Classes, SysUtils, AbLZMA, AbUtils; const {The size of the intermediate buffers for compressed and decompressed data.} CompressedDataBufferSize = 16 * 1024; UncompressedDataBufferSize = 32 * 1024; {When reading/writing very small blocks from/to a (de)compression stream an intermediate buffer is used to buffer the small IO operations in order to improve performance. Reads and writes larger than this size are unbuffered and handled by the (de)compression algorithm directly. This value must be smaller than the compressed and uncompressed data buffers.} MaximumBlockSizeForBufferedIO = 1024; type {------------LZMA compression stream------------} TAbLZMACompressionStream = class; {The background compression thread.} TAbLZMACompressionThread = class(TThread) protected FCompressionStream: TAbLZMACompressionStream; {$IFNDEF HasThreadFinished} FFinished: Boolean; procedure DoTerminate; override; property Finished: Boolean read FFinished; {$ENDIF} public procedure Execute; override; end; {Buffers queued for compression by the background compression thread.} PAbQueuedBuffer = ^TAbQueuedBuffer; TAbQueuedBuffer = packed record PreviousBuffer, NextBuffer: PAbQueuedBuffer; DataSize: Integer; {Adds this buffer to the compression queue for the given compression stream. It is assumed that the compression stream has acquired the buffer critical section.} procedure QueueBuffer(ACompressionStream: TAbLZMACompressionStream); {Removes this buffer from the compression queue} procedure UnQueueBuffer; {Returns a pointer to the data the given offset into the buffer} function GetDataPointer(AOffset: Integer): Pointer; end; TAbLZMACompressionStream = class(TStream) protected FOutputStream: TStream; {The critical section used to control access to the buffers that are queued for compression. The main thread and the compression thread may not access the buffer queue at the same time.} FBufferCriticalSection: TRTLCriticalSection; {This semaphore is signalled by the main thread when it added a workload for the compression thread (usually when a buffer has been added to compress).} FPendingWorkSemaphore: THandle; {The LZMA compression handle} FLZMAEncHandle: CLzmaEncHandle; {The background thread used to perform the compression} FCompressionThread: TAbLZMACompressionThread; {The error code returned by the compression method. 0 = Success.} FCompressionErrorCode: Integer; {The intermediate compression buffer used to aggregate small writes. When NoMoreDataToCompress is called this buffer is freed, so no more data may be written.} FPIntermediateCompressionBuffer: PAbQueuedBuffer; FIntermediateCompressionBufferAvailableBytes: Integer; {The circular linked list of buffers that are queued for compression.} FQueuedData: TAbQueuedBuffer; {The number of bytes of buffer FQueuedData.NextBuffer that has already been submitted to the compressor.} FCurrentBufferBytesSubmitted: Integer; {The position in the output stream where the uncompressed size must be stored.} FOutputStreamHeaderSizeFieldPosition: Int64; {The total number of bytes written to the compression stream} FTotalBytesWritten: Int64; {Wakes up the compression thread by signalling the "pending work semaphore"} procedure WakeCompressionThread; inline; public constructor Create(AOutputStream: TStream; ACompressionLevel: Integer = 5; ADictionarySize: Integer = 65536); destructor Destroy; override; {Reading is not supported and will raise an exception.} function Read(var ABuffer; ACount: Longint): Longint; override; {Submits data to the compression queue.} function Write(const ABuffer; ACount: Longint): Longint; override; {Will raise an exception if an attempt is made to seek off the current position.} function Seek(AOffset: Integer; AOrigin: Word): Integer; override; function Seek(const AOffset: Int64; AOrigin: TSeekOrigin): Int64; override; {Signals the compression thread that no more data will be submitted. Calling write after NoMoreDataToCompress has been called will raise an exception.} procedure NoMoreDataToCompress; {Calls NoMoreDataToCompress and then waits for the background compression process to complete, returning the value of ErrorCode (0 = success).} function WaitForCompressionToFinish: Integer; {Returns True if the background thread is still busy compressing data. Will always return True until NoMoreDataToCompress is called.} function IsBusy: Boolean; {-------------Public properties---------------} {The error code returned by the compression method. 0 = Success.} property ErrorCode: Integer read FCompressionErrorCode; end; {------------LZMA decompression stream------------} TAbLZMADecompressionStream = class(TStream) protected FSourceStream: TStream; {The intermediate buffers for compressed and uncompressed data respectively.} FCompressedDataBuffer: array[0..CompressedDataBufferSize - 1] of Byte; FUncompressedDataBuffer: array[0..UncompressedDataBufferSize - 1] of Byte; {Read buffer control: Used to speed up frequent small reads via FUncompressedDataBuffer.} FReadBufferSize: Integer; FReadBufferAvailableBytes: Integer; {The current size and position into FCompressedDataBuffer} FCompressedDataBufferSize: Integer; FCompressedDataBufferPosition: Integer; {The uncompressed size according to the header.} FUncompressedSize: Int64; {The total number of bytes that have been decompressed.} FBytesDecompressed: Int64; {The LZMA decompression state} FLzmaState: CLzmaDec; {Decompresses data from the compressed source to the buffer pointed to by APBuffer. Returns the number of actual bytes stored (which may be less than the requested size if the end of the compressed stream was reached).} function InternalDecompressToBuffer(APBuffer: Pointer; ABufferSize: Integer): Integer; {---Property getters/setters---} function GetBytesRead: Int64; function GetSize: Int64; override; public constructor Create(ASourceStream: TStream); destructor Destroy; override; function Read(var ABuffer; ACount: Integer): Integer; override; {Writing to a decompression stream is not allowed} function Write(const ABuffer; ACount: Integer): Integer; override; {Will raise an exception if an attempt is made to seek off the current position.} function Seek(AOffset: Integer; AOrigin: Word): Integer; override; function Seek(const AOffset: Int64; AOrigin: TSeekOrigin): Int64; override; {---Public properties---} {The number of decompressed bytes read from the decompression stream.} property BytesRead: Int64 read GetBytesRead; end; implementation uses AbCrtl; {------------Memory management-------------} function SzAlloc(p: Pointer; size: size_t): Pointer; cdecl; begin Result := GetMemory(size); end; procedure SzFree(p, address: Pointer); cdecl; begin FreeMemory(address); end; var DelphiMMInterface: ISzAlloc = (Alloc: SzAlloc; Free: SzFree); {------------Compression "interface"-------------} type {The "interfaces" for the input and output streams} CSeqInStream_Compress = packed record Intf: ISeqInStream; CompressionStream: TAbLZMACompressionStream; end; CSeqOutStream_Compress = packed record Intf: ISeqOutStream; OutputStream: TStream; end; function ISeqInStream_Compress_Read(p: Pointer; var buf; var size: size_t): SRes; cdecl; var LDoNotWaitForMoreData: Boolean; LStream: TAbLZMACompressionStream; LPSourceBuf, LPTargetBuf: PAnsiChar; LTargetSpace, LSourceBytesAvail: Integer; LPCurBuf: PAbQueuedBuffer; begin try LTargetSpace := size; LPTargetBuf := @buf; LStream := CSeqInStream_Compress(p^).CompressionStream; while True do begin {Copy any buffered data to the LZMA buffer, returning the number of bytes written} EnterCriticalSection(LStream.FBufferCriticalSection); try {If the write buffer has been freed that the main thread will not add any more buffers for compression.} LDoNotWaitForMoreData := LStream.FPIntermediateCompressionBuffer = nil; {Copy as much queued data to the LZMA compression buffer as we have (or will fit).} while True do begin LPCurBuf := LStream.FQueuedData.NextBuffer; {No buffers left? -> Break the loop} if LPCurBuf = @LStream.FQueuedData then Break; {Can this buffer be submitted in its entirety, or only a part?} LPSourceBuf := LPCurBuf.GetDataPointer(LStream.FCurrentBufferBytesSubmitted); LSourceBytesAvail := LPCurBuf.DataSize - LStream.FCurrentBufferBytesSubmitted; if LSourceBytesAvail > LTargetSpace then begin {Submit only part of the buffer} System.Move(LPSourceBuf^, LPTargetBuf^, LTargetSpace); Inc(LStream.FCurrentBufferBytesSubmitted, LTargetSpace); LTargetSpace := 0; Break; end else begin {Submit all the remaining bytes in the buffer and free it.} System.Move(LPSourceBuf^, LPTargetBuf^, LSourceBytesAvail); Inc(LPTargetBuf, LSourceBytesAvail); Dec(LTargetSpace, LSourceBytesAvail); LStream.FCurrentBufferBytesSubmitted := 0; LPCurBuf.UnQueueBuffer; FreeMem(LPCurBuf); end; end; finally LeaveCriticalSection(LStream.FBufferCriticalSection); end; {If data was submitted to the compressor, or the main thread indicated that compression is complete then the loop is broken.} if (LTargetSpace <> size) or LDoNotWaitForMoreData then Break; {No data currently queued, but there may still be more coming: Wait for the main thread to notify this thread that more work is pending.} WaitForSingleObject(LStream.FPendingWorkSemaphore, INFINITE); end; {Update the number of bytes written} Dec(size, LTargetSpace); Result := SZ_OK; except Result := SZ_ERROR_DATA; end; end; function ISeqOutStream_Compress_Write(p: Pointer; const buf; size: size_t): size_t; cdecl; begin try Result := CSeqOutStream_Compress(p^).OutputStream.Write(buf, size); except Result := 0; end; end; { TAbQueuedBuffer } function TAbQueuedBuffer.GetDataPointer(AOffset: Integer): Pointer; begin Result := Pointer(PtrUInt(@Self) + SizeOf(TAbQueuedBuffer) + PtrUInt(AOffset)); end; procedure TAbQueuedBuffer.QueueBuffer(ACompressionStream: TAbLZMACompressionStream); begin PreviousBuffer:= ACompressionStream.FQueuedData.PreviousBuffer; NextBuffer:= @ACompressionStream.FQueuedData; ACompressionStream.FQueuedData.PreviousBuffer.NextBuffer := @Self; ACompressionStream.FQueuedData.PreviousBuffer := @Self; end; procedure TAbQueuedBuffer.UnQueueBuffer; begin PreviousBuffer.NextBuffer := NextBuffer; NextBuffer.PreviousBuffer := PreviousBuffer; PreviousBuffer := nil; NextBuffer := nil; end; { TAbLZMACompressionStream } constructor TAbLZMACompressionStream.Create(AOutputStream: TStream; ACompressionLevel, ADictionarySize: Integer); var LLZMAProps: CLzmaEncProps; LLZMAPropData: TLZMAPropertyData; LHeaderSize: size_t; begin inherited Create; FOutputStream := AOutputStream; {Initialize the linked list of buffers.} FQueuedData.PreviousBuffer := @FQueuedData; FQueuedData.NextBuffer := @FQueuedData; {Allocate the intermediate compression buffer} GetMem(FPIntermediateCompressionBuffer, UncompressedDataBufferSize + SizeOf(TAbQueuedBuffer)); FIntermediateCompressionBufferAvailableBytes := UncompressedDataBufferSize; {Initialize the critical section used to control access to the queued data buffer.} InitializeCriticalSection(FBufferCriticalSection); {Create the semaphore used to put the worker thread to sleep when the input buffer is empty.} FPendingWorkSemaphore := CreateSemaphore(nil, 0, 1, nil); {Create the LZMA encoder} FLZMAEncHandle := LzmaEnc_Create(@DelphiMMInterface); if FLZMAEncHandle = nil then raise Exception.Create('Unable to allocate memory for the LZMA compressor.'); {Set the compression properties} LzmaEncProps_Init(LLZMAProps); LLZMAProps.level := ACompressionLevel; LLZMAProps.dictSize := ADictionarySize; LzmaCheck(LzmaEnc_SetProps(FLZMAEncHandle, LLZMAProps)); {Store the header in the output stream, making note of the position in the stream where the uncompressed size will be stored when compression is completed.} LHeaderSize := LZMA_PROPS_SIZE; LzmaCheck(LzmaEnc_WriteProperties(FLZMAEncHandle, PByte(@LLZMAPropData), LHeaderSize)); FOutputStream.WriteBuffer(LLZMAPropData, LHeaderSize); FOutputStreamHeaderSizeFieldPosition := FOutputStream.Position; FOutputStream.WriteBuffer(FTotalBytesWritten, SizeOf(FTotalBytesWritten)); {Create and start the compression thread.} FCompressionThread := TAbLZMACompressionThread.Create(True); FCompressionThread.FCompressionStream := Self; {$IFDEF HasThreadStart} FCompressionThread.Start; {$ELSE} FCompressionThread.Resume; {$ENDIF} end; destructor TAbLZMACompressionStream.Destroy; var LPBuf: PAbQueuedBuffer; LOldPos: Int64; begin WaitForCompressionToFinish; {If something went wrong during creation of this object before the thread was created, then the encoder handle may be non-nil.} if FLZMAEncHandle <> nil then begin LzmaEnc_Destroy(FLZMAEncHandle, @DelphiMMInterface, @DelphiMMInterface); FLZMAEncHandle := nil; end; {Free the critical section and semaphore} DeleteCriticalSection(FBufferCriticalSection); CloseHandle(FPendingWorkSemaphore); {Free the intermediate compression buffer if something went wrong before the thread could be created.} FreeMem(FPIntermediateCompressionBuffer); {If compression failed there may be uncompressed data in the queue: free those buffers.} while True do begin LPBuf := FQueuedData.NextBuffer; if LPBuf = @FQueuedData then Break; LPBuf.UnQueueBuffer; FreeMem(LPBuf); end; {Unpdate the uncompressed size in the header} if FTotalBytesWritten > 0 then begin LOldPos := FOutputStream.Position; FOutputStream.Position := FOutputStreamHeaderSizeFieldPosition; FOutputStream.WriteBuffer(FTotalBytesWritten, SizeOf(FTotalBytesWritten)); FOutputStream.Position := LOldPos; end; inherited Destroy; end; function TAbLZMACompressionStream.IsBusy: Boolean; begin Result := (FCompressionThread <> nil) and (not FCompressionThread.Finished); end; procedure TAbLZMACompressionStream.NoMoreDataToCompress; var LUnqueuedBytes: Integer; begin if FPIntermediateCompressionBuffer <> nil then begin EnterCriticalSection(FBufferCriticalSection); try {No more data may be submitted at this point. Set the flag to indicate this, and wake the compression thread so that it can finish up.} LUnqueuedBytes := UncompressedDataBufferSize - FIntermediateCompressionBufferAvailableBytes; if LUnqueuedBytes > 0 then begin FPIntermediateCompressionBuffer.DataSize := LUnqueuedBytes; FPIntermediateCompressionBuffer.QueueBuffer(Self); end else FreeMem(FPIntermediateCompressionBuffer); {The temporary buffer is always released, so no further writes may be performed.} FPIntermediateCompressionBuffer := nil; finally LeaveCriticalSection(FBufferCriticalSection); end; {Wake up the compression thread so it can finish the compression process.} WakeCompressionThread; end; end; function TAbLZMACompressionStream.Read(var ABuffer; ACount: Integer): Longint; begin raise Exception.Create('The compression stream does not support reading.'); end; function TAbLZMACompressionStream.Seek(const AOffset: Int64; AOrigin: TSeekOrigin): Int64; begin Result := FTotalBytesWritten; if ((AOrigin <> soBeginning) or (AOffset <> Result)) and ((AOrigin = soBeginning) or (AOffset <> 0)) then begin raise Exception.Create('The compression stream does not support seeking away from the current position.'); end; end; function TAbLZMACompressionStream.Seek(AOffset: Integer; AOrigin: Word): Integer; begin Result := Seek(Int64(AOffset), TSeekOrigin(AOrigin)); end; function TAbLZMACompressionStream.WaitForCompressionToFinish: Integer; begin if FCompressionThread <> nil then begin {Notify the thread that no further data will be submitted.} NoMoreDataToCompress; {Wait for the compression thread to complete normally and then free it.} FCompressionThread.WaitFor; FreeAndNil(FCompressionThread); end; Result := FCompressionErrorCode; end; procedure TAbLZMACompressionStream.WakeCompressionThread; begin ReleaseSemaphore(FPendingWorkSemaphore, 1, nil); end; function TAbLZMACompressionStream.Write(const ABuffer; ACount: Integer): Longint; var LPSource: PAnsiChar; LPBufData: Pointer; LPLargeBuf: PAbQueuedBuffer; begin if FPIntermediateCompressionBuffer = nil then raise Exception.Create('Write may not be called after NoMoreDataToCompress.'); if ACount <= 0 then begin Result := 0; Exit; end; LPSource := @ABuffer; {Get a pointer to the position in the intermediate buffer to be written.} LPBufData := FPIntermediateCompressionBuffer.GetDataPointer( UncompressedDataBufferSize - FIntermediateCompressionBufferAvailableBytes); if FIntermediateCompressionBufferAvailableBytes > ACount then begin {Copy the data into the intermediate buffer and exit.} System.Move(LPSource^, LPBufData^, ACount); Dec(FIntermediateCompressionBufferAvailableBytes, ACount); Result := ACount; end else begin {Fill up the intermediate buffer} System.Move(LPSource^, LPBufData^, FIntermediateCompressionBufferAvailableBytes); Dec(ACount, FIntermediateCompressionBufferAvailableBytes); Inc(LPSource, FIntermediateCompressionBufferAvailableBytes); Result := FIntermediateCompressionBufferAvailableBytes; {If we get here the current intermediate buffer is now full, and must be queued.} EnterCriticalSection(FBufferCriticalSection); try {Insert this buffer into the compression queue.} FPIntermediateCompressionBuffer.DataSize := UncompressedDataBufferSize; FPIntermediateCompressionBuffer.QueueBuffer(Self); {Allocate a new intermediate compression buffer} GetMem(FPIntermediateCompressionBuffer, UncompressedDataBufferSize + SizeOf(TAbQueuedBuffer)); FIntermediateCompressionBufferAvailableBytes := UncompressedDataBufferSize; {Should the remaining data be copied into the intermediate compression buffer, or is it too large and must it be queued separately?} if ACount < UncompressedDataBufferSize then begin LPBufData := FPIntermediateCompressionBuffer.GetDataPointer(0); System.Move(LPSource^, LPBufData^, ACount); Dec(FIntermediateCompressionBufferAvailableBytes, ACount); end else begin {The remaining data is larger than the intermediate buffer: queue it separately} GetMem(LPLargeBuf, ACount + SizeOf(TAbQueuedBuffer)); LPLargeBuf.DataSize := ACount; LPLargeBuf.QueueBuffer(Self); {Copy the data across} LPBufData := LPLargeBuf.GetDataPointer(0); System.Move(LPSource^, LPBufData^, ACount); end; {Update the number of bytes written} Inc(Result, ACount); finally LeaveCriticalSection(FBufferCriticalSection); end; {Wake up the compression thread to compress the newly queued data} WakeCompressionThread; end; Inc(FTotalBytesWritten, Result); end; { TAbLZMACompressionThread } {$IFNDEF HasThreadFinished} procedure TAbLZMACompressionThread.DoTerminate; begin inherited DoTerminate; FFinished := True; end; {$ENDIF} procedure TAbLZMACompressionThread.Execute; var LInStreamRec: CSeqInStream_Compress; LOutStreamRec: CSeqOutStream_Compress; begin {Call the compression function and save the error code} LInStreamRec.Intf.Read := ISeqInStream_Compress_Read; LInStreamRec.CompressionStream := FCompressionStream; LOutStreamRec.Intf.Write := ISeqOutStream_Compress_Write; LOutStreamRec.OutputStream := FCompressionStream.FOutputStream; FCompressionStream.FCompressionErrorCode := LzmaEnc_Encode(FCompressionStream.FLZMAEncHandle, @LOutStreamRec.Intf, @LInStreamRec.Intf, nil, @DelphiMMInterface, @DelphiMMInterface); {Free the compression handle} LzmaEnc_Destroy(FCompressionStream.FLZMAEncHandle, @DelphiMMInterface, @DelphiMMInterface); FCompressionStream.FLZMAEncHandle := nil; end; { TAbLZMADecompressionStream } constructor TAbLZMADecompressionStream.Create(ASourceStream: TStream); var LLZMAPropData: TLZMAPropertyData; begin inherited Create; FSourceStream := ASourceStream; {Read the header and uncompressed size from the compressed data stream.} FSourceStream.ReadBuffer(LLZMAPropData, LZMA_PROPS_SIZE); FSourceStream.ReadBuffer(FUncompressedSize, SizeOf(FUncompressedSize)); {Initialize the decompressor using the information from the header} LzmaDec_Construct(FLzmaState); LzmaCheck(LzmaDec_Allocate(FLzmaState, PByte(@LLZMAPropData), LZMA_PROPS_SIZE, @DelphiMMInterface)); LzmaDec_Init(FLzmaState); end; destructor TAbLZMADecompressionStream.Destroy; var LUnusedBytes: Integer; begin {Release all decompression resources.} LzmaDec_Free(FLzmaState, @DelphiMMInterface); {Any unconsumed bytes in the compressed input buffer should be returned to the source stream.} LUnusedBytes := FCompressedDataBufferSize - FCompressedDataBufferPosition; if LUnusedBytes > 0 then FSourceStream.Position := FSourceStream.Position - LUnusedBytes; inherited Destroy; end; function TAbLZMADecompressionStream.GetBytesRead: Int64; begin Result := FBytesDecompressed - FReadBufferAvailableBytes; end; function TAbLZMADecompressionStream.GetSize: Int64; begin Result := FUncompressedSize; end; function TAbLZMADecompressionStream.InternalDecompressToBuffer(APBuffer: Pointer; ABufferSize: Integer): Integer; var LInputBytesProcessed, LOutputBytesProcessed: size_t; LFinishMode: Integer; LStatus: ELzmaStatus; begin Result := 0; {Any more data to decompress to the output buffer?} while ABufferSize > 0 do begin {Read more compressed data into the compressed data buffer, if required.} if FCompressedDataBufferPosition >= FCompressedDataBufferSize then begin FCompressedDataBufferSize := FSourceStream.Read(FCompressedDataBuffer, CompressedDataBufferSize); FCompressedDataBufferPosition := 0; end; {Initialize the "processed byte count" variables to the sizes of the input and output buffers.} LInputBytesProcessed := FCompressedDataBufferSize - FCompressedDataBufferPosition; LOutputBytesProcessed := ABufferSize; {We may not read more bytes than the number of uncompressed bytes according to the header.} if (FUncompressedSize - FBytesDecompressed) <= LOutputBytesProcessed then begin LOutputBytesProcessed := FUncompressedSize - FBytesDecompressed; LFinishMode := LZMA_FINISH_END; end else LFinishMode := LZMA_FINISH_ANY; {Decompress from the input to the output buffer} LzmaCheck(LzmaDec_DecodeToBuf(FLzmaState, APBuffer, LOutputBytesProcessed, @FCompressedDataBuffer[FCompressedDataBufferPosition], LInputBytesProcessed, LFinishMode, LStatus)); {Update the input and output buffer stats} Inc(FCompressedDataBufferPosition, LInputBytesProcessed); Inc(PAnsiChar(APBuffer), LOutputBytesProcessed); Dec(ABufferSize, LOutputBytesProcessed); {Update the number of bytes decompressed} Inc(Result, LOutputBytesProcessed); Inc(FBytesDecompressed, LOutputBytesProcessed); {Was all the data decompressed? If so, break the loop.} if FUncompressedSize = FBytesDecompressed then Break; {Was nothing from the input or output streams processed? If so, then something has gone wrong.} if (LInputBytesProcessed = 0) and (LOutputBytesProcessed = 0) then raise Exception.Create('LZMA decompression data error'); end; end; function TAbLZMADecompressionStream.Read(var ABuffer; ACount: Integer): Integer; var LBytesAlreadyRead: Integer; begin {Anything to read?} if ACount > 0 then begin {Do we have enough data in the read buffer to satisfy the request?} if FReadBufferAvailableBytes >= ACount then begin {Enough data in the buffer: Fill the output buffer.} System.Move(PAnsiChar(@FUncompressedDataBuffer)[FReadBufferSize - FReadBufferAvailableBytes], ABuffer, ACount); {Subtract from the available bytes in the read buffer.} Dec(FReadBufferAvailableBytes, ACount); {Successfully read the number of bytes requested} Result := ACount; end else begin {Not enough bytes available in the read buffer: Is there anything available in the uncompressed data buffer? If so, then transfer what we have.} if FReadBufferAvailableBytes > 0 then begin {There is some data in the buffer: Read everything} System.Move(PAnsiChar(@FUncompressedDataBuffer)[FReadBufferSize - FReadBufferAvailableBytes], ABuffer, FReadBufferAvailableBytes); LBytesAlreadyRead := FReadBufferAvailableBytes; FReadBufferAvailableBytes := 0; end else LBytesAlreadyRead := 0; {If we get here it means the read buffer has been emptied and some data still has to be read: Do we need to fill up the read buffer again, or do we read directly into the target buffer? Large reads bypass the read buffering mechanism.} if ACount <= MaximumBlockSizeForBufferedIO then begin {Try to fill the read buffer again} FReadBufferSize := InternalDecompressToBuffer(@FUncompressedDataBuffer, UncompressedDataBufferSize); FReadBufferAvailableBytes := FReadBufferSize; {No more data available? If so we're done.} if FReadBufferAvailableBytes = 0 then begin Result := LBytesAlreadyRead; Exit; end; {Is enough data now available?} if FReadBufferAvailableBytes >= (ACount - LBytesAlreadyRead) then begin {Enough data in the buffer: Fill the output buffer.} System.Move(FUncompressedDataBuffer, PAnsiChar(@ABuffer)[LBytesAlreadyRead], ACount - LBytesAlreadyRead); {Subtract from the available bytes in the read buffer and return the number of bytes read.} Dec(FReadBufferAvailableBytes, ACount - LBytesAlreadyRead); {Successfully read the number of bytes requested} Result := ACount; end else begin {Enough data is still not available (the end of the compressed stream has been reached): Read what we can.} System.Move(FUncompressedDataBuffer, PAnsiChar(@ABuffer)[LBytesAlreadyRead], FReadBufferAvailableBytes); Inc(LBytesAlreadyRead, FReadBufferAvailableBytes); FReadBufferAvailableBytes := 0; Result := LBytesAlreadyRead; end; end else begin {Decompress directly into the output buffer.} Result := InternalDecompressToBuffer( @PAnsiChar(@ABuffer)[LBytesAlreadyRead], ACount - LBytesAlreadyRead) + LBytesAlreadyRead; end; end; end else Result := 0; end; function TAbLZMADecompressionStream.Seek(const AOffset: Int64; AOrigin: TSeekOrigin): Int64; begin Result := GetBytesRead; if ((AOrigin <> soBeginning) or (AOffset <> Result)) and ((AOrigin <> soCurrent) or (AOffset <> 0)) then begin raise Exception.Create('Decompression streams do not support seeking away ' + 'from the current position.'); end; end; function TAbLZMADecompressionStream.Seek(AOffset: Integer; AOrigin: Word): Integer; begin Result := Seek(Int64(AOffset), TSeekOrigin(AOrigin)); end; function TAbLZMADecompressionStream.Write(const ABuffer; ACount: Integer): Integer; begin raise Exception.Create('Writing to a LZMA decompression stream is not supported.'); end; end. ================================================ FILE: lib/abbrevia/source/AbMeter.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbMeter.pas *} {*********************************************************} {* ABBREVIA: Progress meter *} {* Use AbQMeter.pas for CLX *} {*********************************************************} {$IFNDEF UsingCLX} unit AbMeter; {$ENDIF} {$I AbDefine.inc} interface uses Classes, {$IFDEF MSWINDOWS} Windows, {$ENDIF} {$IFDEF LibcAPI} Libc, {$ENDIF} {$IFDEF UsingCLX } QControls, QGraphics, QForms, QExtCtrls, {$ELSE} Controls, Graphics, Forms, ExtCtrls, {$ENDIF} AbBrowse; type TAbMeterOrientation = (moHorizontal, moVertical); TAbCustomMeter = class(TGraphicControl, IAbProgressMeter) {.Z+} protected {private} {property variables} FBorderStyle : TBorderStyle; FCtl3D : Boolean; FOrientation : TAbMeterOrientation; FPercent : Integer; FTickMarks : Byte; FUsedColor : TColor; FUnusedColor : TColor; {internal methods} function GetVersion : string; procedure Paint; override; procedure SetBorderStyle(const Value : TBorderStyle); procedure SetCtl3D(const Value : Boolean); procedure SetOrientation(const O : TAbMeterOrientation); procedure SetTickMarks(const Value: Byte); procedure SetUnusedColor(const C : TColor); procedure SetUsedColor(const C : TColor); procedure SetVersion(Value : string); property Version : string read GetVersion write SetVersion stored False; {.Z-} public {methods} constructor Create(AOwner : TComponent); override; procedure DoProgress(Progress : Byte); procedure Reset; public {properties} property BorderStyle : TBorderStyle read FBorderStyle write SetBorderStyle default bsSingle; property Ctl3D : Boolean read FCtl3D write SetCtl3D default True; property Orientation : TAbMeterOrientation read FOrientation write SetOrientation; property TickMarks: Byte read FTickMarks write SetTickMarks default 10; property UnusedColor : TColor read FUnusedColor write SetUnusedColor; property UsedColor : TColor read FUsedColor write SetUsedColor; end; TAbMeter = class(TAbCustomMeter) published property Anchors; property Constraints; property Align; property BorderStyle; property Ctl3D; property Font; property OnClick; property OnDblClick; property OnMouseDown; property OnMouseMove; property OnMouseUp; property Orientation; property ParentFont; property ParentShowHint; property ShowHint; property TickMarks; property UnusedColor; property UsedColor; property Version; property Visible; end; {.Z+} implementation uses Types, AbConst; { == TAbCustomMeter ======================================================== } constructor TAbCustomMeter.Create(AOwner : TComponent); begin inherited Create(AOwner); {$IFNDEF UsingCLX} if NewStyleControls then ControlStyle := ControlStyle + [csOpaque] else ControlStyle := ControlStyle + [csOpaque, csFramed]; {$ELSE} ControlStyle := ControlStyle + [csOpaque, csFramed]; {$ENDIF} FBorderStyle := bsSingle; FCtl3D := True; FOrientation := moHorizontal; FTickMarks := 10; FUnusedColor := clBtnFace; FUsedColor := clNavy; Width := 150; Height := 16; end; { -------------------------------------------------------------------------- } function TAbCustomMeter.GetVersion : string; begin Result := AbVersionS; end; { -------------------------------------------------------------------------- } procedure TAbCustomMeter.DoProgress(Progress : Byte); begin if (Progress <> FPercent) then begin FPercent := Progress; if (FPercent >= 100) then FPercent := 0; Refresh; Application.ProcessMessages; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomMeter.Paint; const VSpace = 2; HSpace = 1; LSpace = 1; RSpace = 1; var ClRect, R : TRect; ClWidth : Integer; ClHeight : Integer; BlockWidth : Integer; BlockCount : Integer; i : Integer; begin ClRect := ClientRect; ClWidth := ClRect.Right - CLRect.Left + 1; ClHeight := ClRect.Bottom - ClRect.Top + 1; if (Orientation = moHorizontal) then BlockWidth := ((ClWidth - LSpace - RSpace - (9 * VSpace)) div FTickMarks) + 1 else BlockWidth := ((ClHeight - LSpace - RSpace - (9 * HSpace)) div FTickMarks) + 1; BlockCount := FPercent div FTickMarks; if not Assigned((Canvas as TControlCanvas).Control) then begin TControlCanvas(Canvas).Control := self; end; with Canvas do begin Brush.Color := FUnusedColor; FillRect(Rect(ClRect.Left, ClRect.Top, ClRect.Left + ClWidth - 1, ClRect.Top + ClHeight - 1)); Brush.Color := FUsedColor; if (BlockCount > 0) then begin if (Orientation = moHorizontal) then begin R.Top := ClRect.Top + HSpace; R.Bottom := ClRect.Bottom - HSpace; for i := 0 to Pred(BlockCount) do begin R.Left := ClRect.Left + LSpace + (i * VSpace) + (i * BlockWidth); R.Right := R.Left + BlockWidth; FillRect(R); end; end else begin {moVertical} R.Left := ClRect.Left + VSpace; R.Right := ClRect.Right - VSpace; for i := 0 to Pred(BlockCount) do begin R.Bottom := ClRect.Bottom - LSpace - (i * HSpace) - (i * BlockWidth); R.Top := R.Bottom - BlockWidth; FillRect(R); end; end; end; end; {$IFNDEF LCL} if (BorderStyle <> bsNone) then begin if Ctl3D then Frame3D(Canvas, ClRect, clBtnShadow, clBtnHighlight, 1) else Frame3D(Canvas, ClRect, clBlack, clBlack, 1); end; {$ENDIF} end; { -------------------------------------------------------------------------- } procedure TAbCustomMeter.Reset; begin DoProgress(0); end; { -------------------------------------------------------------------------- } procedure TAbCustomMeter.SetBorderStyle(const Value : TBorderStyle); begin if (Value <> FBorderStyle) then begin FBorderStyle := Value; Invalidate; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomMeter.SetCtl3D(const Value : Boolean); begin if (Value <> FCtl3D) then begin FCtl3D := Value; Invalidate; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomMeter.SetOrientation(const O : TAbMeterOrientation); var Temp : Integer; begin if (O <> FOrientation) then begin FOrientation := O; if not (csLoading in ComponentState) then begin Temp := Width; Width := Height; Height := Temp; end; Invalidate; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomMeter.SetTickMarks(const Value: Byte); begin if Value <= 0 then FTickMarks := 10 else FTickMarks := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomMeter.SetUnusedColor(const C : TColor); begin if (C <> FUnusedColor) then begin FUnusedColor := C; Invalidate; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomMeter.SetUsedColor(const C : TColor); begin if (C <> FUsedColor) then begin FUsedColor := C; Invalidate; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomMeter.SetVersion(Value : string); begin {NOP} end; end. ================================================ FILE: lib/abbrevia/source/AbPPMd.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is Craig Peterson * * Portions created by the Initial Developer are Copyright (C) 2011 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Craig Peterson * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbPPMd.pas *} {*********************************************************} {* ABBREVIA: PPMd decompression *} {*********************************************************} unit AbPPMd; {$I AbDefine.inc} interface uses Classes; procedure DecompressPPMd(aSrc, aDes: TStream); implementation uses AbCrtl, SysUtils, AbExcept; // Compiled with: // Release: bcc32 -q -c *.c // Debug: bcc32 -q -c -v -y *.c { Linker derectives ======================================================== } // Don't re-order these; it will cause linker errors {$IF DEFINED(WIN32)} {$L Win32\PPMdVariantI.obj} {$L Win32\PPMdContext.obj} {$L Win32\PPMdSubAllocatorVariantI.obj} {$L Win32\CarrylessRangeCoder.obj} {$ELSEIF DEFINED(WIN64)} {$L Win64\PPMdVariantI.obj} {$L Win64\PPMdContext.obj} {$L Win64\PPMdSubAllocatorVariantI.obj} {$L Win64\CarrylessRangeCoder.obj} {$IFEND} { CarrylessRangeCoder.h ==================================================== } type PInStream = ^TInStream; TInStream = record nextByte: function(Self: PInStream): Byte; cdecl; // Private data stream: TStream; InPos: Integer; InCount: Integer; InBuf: array[0..4097] of Byte; end; { -------------------------------------------------------------------------- } function TInStream_NextByte(Self: PInStream): Byte; cdecl; begin if Self.InPos = Self.InCount then begin Self.InCount := Self.stream.Read(Self.InBuf, SizeOf(Self.InBuf)); if Self.InCount = 0 then raise EAbReadError.Create; Self.InPos := 0; end; Result := Self.InBuf[Self.InPos]; Inc(Self.InPos); end; { -------------------------------------------------------------------------- } function TInStream_Create(aStream: TStream): PInStream; begin GetMem(Result, SizeOf(TInStream)); Result.nextByte := TInStream_NextByte; Result.stream := aStream; Result.InPos := 0; Result.InCount := 0; end; { PPMdVariantI.h =========================================================== } type PPMdModelVariantI = Pointer; function CreatePPMdModelVariantI(const input: TInStream; suballocsize, maxorder, restoration: Integer): PPMdModelVariantI; cdecl; external; procedure FreePPMdModelVariantI(Self: PPMdModelVariantI); cdecl; external; function NextPPMdVariantIByte(Self: PPMdModelVariantI): Integer; cdecl; external; { Decompression routines =================================================== } procedure DecompressPPMd(aSrc, aDes: TStream); const OutBufSize = 4096; var nextByte: Integer; params: word; ppmd: PPMdModelVariantI; Src: PInStream; OutBuf: PByteArray; OutPos: Integer; begin Src := TInStream_Create(aSrc); try GetMem(OutBuf, OutBufSize); try OutPos := 0; ASrc.ReadBuffer(Params, SizeOf(Params));// Pkzip stream header ppmd := CreatePPMdModelVariantI(Src^, (((Params shr 4) and $FF) + 1) shl 20,// sub-allocator size (Params and $0F) + 1, // model order Params shr 12); // model restoration method try while True do begin nextByte := NextPPMdVariantIByte(ppmd); if nextByte < 0 then Break; OutBuf[OutPos] := Byte(nextByte); Inc(OutPos); if OutPos = OutBufSize then begin aDes.WriteBuffer(OutBuf^, OutBufSize); OutPos := 0; end; end; if OutPos > 0 then aDes.WriteBuffer(OutBuf^, OutPos); finally FreePPMdModelVariantI(ppmd); end; finally FreeMem(OutBuf); end; finally FreeMem(Src); end; end; end. ================================================ FILE: lib/abbrevia/source/AbPeCol.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbPeCol.pas *} {*********************************************************} {* ABBREVIA: Property Editor - ZipView column headings *} {* Use AbQPeCol.pas for CLX *} {*********************************************************} {$IFNDEF UsingCLX} unit AbPeCol; {$ENDIF} {$I AbDefine.inc} interface uses {$IFDEF MSWINDOWS} Windows, {$ENDIF} {$IFDEF UsingClx} QGraphics, QForms, QControls, QStdCtrls, QButtons, QExtCtrls, AbQView, AbBseCLX, {$ELSE} Graphics, Forms, Controls, StdCtrls, Buttons, ExtCtrls, AbView, AbBseVcl, {$ENDIF} DesignIntf, DesignEditors, AbConst, SysUtils, Classes; type TAbColHeadingsEditor = class(TForm) Panel1: TPanel; Label1: TLabel; Attribute1: TComboBox; Done1: TBitBtn; Apply1: TBitBtn; Label2: TLabel; Heading1: TEdit; Button1: TButton; procedure FormShow(Sender: TObject); procedure Attribute1Click(Sender: TObject); procedure Apply1Click(Sender: TObject); procedure Heading1Exit(Sender: TObject); private { Private declarations } public Viewer : TAbBaseViewer; end; TAbColHeadingsProperty = class(TClassProperty) public procedure Edit; override; function GetAttributes: TPropertyAttributes; override; end; var AbColHeadingsEditor: TAbColHeadingsEditor; implementation uses AbResString; {$IFNDEF UsingCLX} {$R *.dfm} {$ENDIF} type TAbViewerFriend = class(TAbBaseViewer); {===TAbColHeadingsProperty==========================================} procedure TAbColHeadingsProperty.Edit; var hEditor : TAbColHeadingsEditor; begin hEditor := TAbColHeadingsEditor.Create(Application); try hEditor.Viewer := TAbViewerFriend(GetComponent(0)); hEditor.ShowModal; Designer.Modified; finally hEditor.Free; end; end; { -------------------------------------------------------------------------- } function TAbColHeadingsProperty.GetAttributes: TPropertyAttributes; begin Result := inherited GetAttributes + [paDialog, paAutoUpdate]; end; {===TAbColHeadingsEditor============================================} procedure TAbColHeadingsEditor.FormShow(Sender: TObject); const cResString: array[TAbViewAttribute] of string = (AbItemNameHeadingS, AbPackedHeadingS, AbMethodHeadingS, AbRatioHeadingS, AbCRCHeadingS, AbFileAttrHeadingS, AbFileFormatHeadingS, AbEncryptionHeadingS, AbTimeStampHeadingS, AbFileSizeHeadingS, AbVersionMadeHeadingS, AbVersionNeededHeadingS, AbPathHeadingS); var i : TAbViewAttribute; begin with Attribute1 do begin Clear; for i := Low(TAbViewAttribute) to High(TAbViewAttribute) do Items.Add(cResString[i]); ItemIndex := 0; end; Attribute1Click(nil); end; procedure TAbColHeadingsEditor.Attribute1Click(Sender: TObject); begin if (Attribute1.ItemIndex > -1) then Heading1.Text := TAbViewerFriend(Viewer).Headings[Attribute1.ItemIndex]; end; procedure TAbColHeadingsEditor.Apply1Click(Sender: TObject); begin if (Attribute1.ItemIndex > -1) then begin TAbViewerFriend(Viewer).Headings[Attribute1.ItemIndex] := Heading1.Text; TAbViewerFriend(Viewer).InvalidateRow(0); end; end; procedure TAbColHeadingsEditor.Heading1Exit(Sender: TObject); begin Apply1Click(nil); end; end. ================================================ FILE: lib/abbrevia/source/AbPeDir.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbPeDir.pas *} {*********************************************************} {* ABBREVIA: Property Editor - Directory *} {* Use AbQPeDir.pas for CLX *} {*********************************************************} {$IFNDEF UsingCLX} unit AbPeDir; {$ENDIF} {$I AbDefine.inc} interface uses {$IFDEF MSWINDOWS} Windows, {$ENDIF} {$IFDEF UsingClx} QGraphics, QForms, QControls, QStdCtrls, QButtons, QExtCtrls, {$ELSE} Graphics, Forms, Controls, StdCtrls, Buttons, ExtCtrls, {$ENDIF} DesignIntf, DesignEditors, SysUtils, Classes; type TAbDirectoryProperty = class( TStringProperty ) public function GetAttributes: TPropertyAttributes; override; procedure Edit; override; end; implementation uses {$IFDEF UsingClx} AbQDgDir; {$ELSE} AbDlgDir; {$ENDIF} function TAbDirectoryProperty.GetAttributes: TPropertyAttributes; begin Result := [paDialog]; end; {$IFDEF MSWINDOWS} procedure TAbDirectoryProperty.Edit; var D : TAbDirDlg; begin D := TAbDirDlg.Create(Application); try D.Caption := 'Directory'; D.AdditionalText := 'Select Directory'; if D.Execute then Value := D.SelectedFolder; finally D.Free; end; end; {$ELSE} procedure TAbDirectoryProperty.Edit; var D : TDirDlg; begin D := TDirDlg.Create(Application); try {$IFDEF MSWINDOWS} D.DirectoryListBox1.Directory := Value; {$ENDIF} D.ShowModal; if D.ModalResult = mrOK then Value := D.SelectedFolder; finally D.Free; end; end; {$ENDIF} end. ================================================ FILE: lib/abbrevia/source/AbPeFn.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbPeFn.pas *} {*********************************************************} {* ABBREVIA: Property Editor - FileName *} {* Use AbQPeFn.pas for CLX *} {*********************************************************} {$IFNDEF UsingCLX} unit AbPeFn; {$ENDIF} {$I AbDefine.inc} interface uses {$IFDEF UsingClx } QDialogs, QForms, {$ELSE} Dialogs, Forms, {$ENDIF} DesignIntf, DesignEditors, SysUtils; type TAbFileNameProperty = class(TStringProperty) public function GetAttributes: TPropertyAttributes; override; procedure Edit; override; end; TAbExeNameProperty = class(TStringProperty) public function GetAttributes: TPropertyAttributes; override; procedure Edit; override; end; TAbCabNameProperty = class( TStringProperty ) public function GetAttributes: TPropertyAttributes; override; procedure Edit; override; end; TAbLogNameProperty = class( TStringProperty ) public function GetAttributes: TPropertyAttributes; override; procedure Edit; override; end; implementation uses AbResString, AbArcTyp; { -------------------------------------------------------------------------- } procedure AbGetFilename(const Ext : string; const Filter : string; const Title : string; var aFilename : string); var D : TOpenDialog; begin D := TOpenDialog.Create( Application ); try D.DefaultExt := Ext; D.Filter := Filter; D.FilterIndex := 0; D.Options := []; D.Title := Title; D.FileName := aFilename; if D.Execute then aFilename := D.FileName; finally D.Free; end; end; { == for zip files ========================================================= } function TAbFileNameProperty.GetAttributes: TPropertyAttributes; begin Result := [paDialog]; end; { -------------------------------------------------------------------------- } procedure TAbFileNameProperty.Edit; var FN : string; begin FN := Value; AbGetFilename(AbDefaultExtS, AbFilterS, AbFileNameTitleS, FN); Value := FN; end; { == for exe files ========================================================= } function TAbExeNameProperty.GetAttributes: TPropertyAttributes; begin Result := [paDialog]; end; { -------------------------------------------------------------------------- } procedure TAbExeNameProperty.Edit; var FN : string; begin FN := Value; AbGetFilename(AbExeExtS, AbExeFilterS, AbFileNameTitleS, FN); Value := FN; end; { == for cab files ========================================================= } function TAbCabNameProperty.GetAttributes: TPropertyAttributes; begin Result := [paDialog]; end; { -------------------------------------------------------------------------- } procedure TAbCabNameProperty.Edit; var FN : string; begin FN := Value; AbGetFilename(AbCabExtS, AbCabFilterS, AbFileNameTitleS, FN); Value := FN; end; { == for log files ========================================================= } function TAbLogNameProperty.GetAttributes: TPropertyAttributes; begin Result := [paDialog]; end; { -------------------------------------------------------------------------- } procedure TAbLogNameProperty.Edit; var FN : string; begin FN := Value; AbGetFilename(AbLogExtS, AbLogFilterS, AbFileNameTitleS, FN); Value := FN; end; { -------------------------------------------------------------------------- } end. ================================================ FILE: lib/abbrevia/source/AbPePass.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbPePass.pas *} {*********************************************************} {* ABBREVIA: Password property editor *} {* Use AbQPePas.pas for CLX *} {*********************************************************} {$IFNDEF UsingCLX} unit AbPePass; {$ENDIF} {$I AbDefine.inc} interface uses {$IFDEF MSWINDOWS} Windows, {$ENDIF} {$IFDEF UsingClx} QGraphics, QForms, QControls, QStdCtrls, QButtons, QExtCtrls, {$ELSE} Graphics, Forms, Controls, StdCtrls, Buttons, ExtCtrls, {$ENDIF} DesignIntf, DesignEditors, SysUtils, Classes; type TAbPasswordProperty = class( TStringProperty ) public function GetAttributes: TPropertyAttributes; override; procedure Edit; override; end; implementation uses {$IFDEF UsingClx} AbQDgPwd; {$ELSE} AbDlgPwd; {$ENDIF} function TAbPasswordProperty.GetAttributes: TPropertyAttributes; begin Result := [paDialog]; end; procedure TAbPasswordProperty.Edit; var D : TPasswordDlg; begin D := TPasswordDlg.Create( Application ); try D.Edit1.Text := Value; D.ShowModal; if D.ModalResult = mrOK then Value := D.Edit1.Text; finally D.Free; end; end; end. ================================================ FILE: lib/abbrevia/source/AbPeVer.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbPeVer.pas *} {*********************************************************} {* ABBREVIA: Property Editor - Version *} {* Use AbQPeVer.pas for CLX *} {*********************************************************} {$IFNDEF UsingCLX} unit AbPeVer; {$ENDIF} {$I AbDefine.inc} interface uses {$IFDEF MSWINDOWS} Windows, ShellAPI, {$ENDIF} {$IFDEF LibcAPI} Libc, {$ENDIF} {$IFDEF UsingClx} QGraphics, QForms, QControls, QStdCtrls, QButtons, QExtCtrls, QDialogs, {$ELSE} Graphics, Forms, Controls, StdCtrls, Buttons, ExtCtrls, Dialogs, {$ENDIF} DesignIntf, DesignEditors, SysUtils, Classes; type TAbAboutBox = class(TForm) lblVersion: TLabel; Panel1: TPanel; Image1: TImage; btnOK: TButton; Panel2: TPanel; WebLbl: TLabel; NewsLbl: TLabel; Bevel1: TBevel; Label1: TLabel; Label2: TLabel; Label3: TLabel; Label5: TLabel; Label6: TLabel; Label7: TLabel; Label10: TLabel; Label11: TLabel; procedure FormCreate(Sender: TObject); procedure btnOKClick(Sender: TObject); procedure WebLblClick(Sender: TObject); procedure WebLblMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure NewsLblClick(Sender: TObject); procedure NewsLblMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure Panel2MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); private { Private declarations } public { Public declarations } end; TAbVersionProperty = class( TStringProperty ) public function GetAttributes: TPropertyAttributes; override; procedure Edit; override; end; var AbAboutBox : TAbAboutBox; implementation {$IFNDEF UsingCLX} {$R *.dfm} {$ENDIF} uses AbArcTyp, AbConst, AbResString; {$IFDEF LINUX} const { String Constants } sCannotStartBrowser = 'Unable to start web browser. Make sure you have it properly set-up on your system.'; const MaxBrowsers = 1; type ECannotStartBrowser = class(Exception); type TBrowserStartCmd = record Command : string [64]; Parameters : string [255]; XTerm : Boolean; { Start browser in an XTerm } end; const { The list of browsers we can launch. } BrowserList : array [1..MaxBrowsers] of TBrowserStartCmd = ((Command : 'netscape'; Parameters : ''; Xterm : False)); procedure GetCurrentPath (PathList : TStringList); var WorkPath : PChar; StartPos : PChar; CurrentPath : PChar; State : (Scanning, GotColon); begin WorkPath := getenv ('PATH'); PathList.Clear; StartPos := WorkPath; State := Scanning; while (WorkPath^ <> #0) do begin case State of Scanning : begin if (WorkPath^ = ':') then begin State := GotColon; if (WorkPath <> StartPos) then begin CurrentPath := StrAlloc(WorkPath - StartPos + 1); StrLCopy(CurrentPath, StartPos, WorkPath-StartPos); PathList.Add (CurrentPath); StrDispose(CurrentPath); end; end; end; GotColon : begin if (WorkPath^ <> ':') then begin StartPos := WorkPath; State := Scanning; end; end; end;{case} inc(WorkPath); end; if (State = Scanning) and (WorkPath <> StartPos) then begin CurrentPath := StrAlloc(WorkPath - StartPos + 1); StrLCopy(CurrentPath, StartPos, WorkPath-StartPos); PathList.Add (CurrentPath); StrDispose(CurrentPath); end; end; function IsBrowserPresent (PathList : TStringList; Browser : string) : Boolean; var i : integer; begin Result := False; for i := 0 to PathList.Count - 1 do begin if FileExists (PathList[i] + '/' + Browser) then begin Result := True; exit; end; end; end; procedure CallBrowser (Browser : string; Parameters : string; Website : string; XTerm : Boolean); begin if Pos ('', Parameters) > 0 then begin Parameters := Copy (Parameters, 1, Pos ('', Parameters) - 1) + Website + Copy (Parameters, Pos ('', Parameters) + 6, 255); end else Parameters := Parameters + ' ' + Website; if XTerm then begin Parameters := '-e ' + Browser + ' ' + Parameters; Browser := 'xterm'; end; Libc.system (PChar (Browser + ' ' + Parameters + ' &')); end; procedure StartBrowser (Website : string); var PathList : TStringList; i : integer; begin PathList := TStringList.Create; try GetCurrentPath (PathList); for i := 1 to MaxBrowsers do begin if IsBrowserPresent (PathList, BrowserList[i].Command) then begin CallBrowser (BrowserList[i].Command, BrowserList[i].Parameters, Website, BrowserList[i].XTerm); exit; end; end; raise ECannotStartBrowser.Create(sCannotStartBrowser); finally PathList.Free; end; end; {$ENDIF} procedure TAbAboutBox.FormCreate(Sender: TObject); begin Top := (Screen.Height - Height ) div 3; Left := (Screen.Width - Width ) div 2; lblVersion.Caption := Format(AbVersionFormatS, [AbVersionS] ); end; function TAbVersionProperty.GetAttributes: TPropertyAttributes; begin Result := [paDialog, paReadOnly]; end; procedure TAbVersionProperty.Edit; begin with TAbAboutBox.Create( Application ) do try ShowModal; finally Free; end; end; procedure TAbAboutBox.btnOKClick(Sender: TObject); begin Close; end; procedure TAbAboutBox.WebLblClick(Sender: TObject); begin {$IFDEF MSWINDOWS } if ShellExecute(0, 'open', 'http://www.sourceforge.net/projects/tpabbrevia', '', '', SW_SHOWNORMAL) <= 32 then ShowMessage('Unable to start web browser'); {$ENDIF MSWINDOWS } {$IFDEF LINUX } try StartBrowser('http://www.sourceforge.net/projects/tpabbrevia'); except on ECannotStartBrowser do ShowMessage('Unable to start web browser'); end; {$ENDIF LINUX } WebLbl.Font.Color := clNavy; end; procedure TAbAboutBox.WebLblMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); begin WebLbl.Font.Color := clRed; end; procedure TAbAboutBox.NewsLblClick(Sender: TObject); begin {$IFDEF MSWINDOWS } if ShellExecute(0, 'open', 'http://www.sourceforge.net/forum/forum.php?forum_id=241865', '', '', SW_SHOWNORMAL) <= 32 then ShowMessage('Unable to start web browser'); {$ENDIF MSWINDOWS } {$IFDEF LINUX } try StartBrowser('http://www.sourceforge.net/forum/forum.php?forum_id=241865'); except on ECannotStartBrowser do ShowMessage('Unable to start web browser'); end; {$ENDIF LINUX } NewsLbl.Font.Color := clNavy; end; procedure TAbAboutBox.NewsLblMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); begin NewsLbl.Font.Color := clRed; end; procedure TAbAboutBox.Panel2MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); begin NewsLbl.Font.Color := clNavy; end; procedure TAbAboutBox.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); begin WebLbl.Font.Color := clNavy; NewsLbl.Font.Color := clNavy; end; end. ================================================ FILE: lib/abbrevia/source/AbQCView.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbQCView.pas *} {*********************************************************} {* ABBREVIA: Cabinet archive viewer component (CLX) *} {* Use AbCView.pas for VCL *} {*********************************************************} Unit AbQCView; {$DEFINE UsingCLX} {$I AbCView.pas} ================================================ FILE: lib/abbrevia/source/AbQCmpnd.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbQCmpnd.pas *} {*********************************************************} {* ABBREVIA: Compound File classes and component (CLX) *} {* Use AbCompnd.pas for VCL *} {*********************************************************} unit AbQCmpnd; {$DEFINE UsingCLX} {$I AbCompnd.pas} ================================================ FILE: lib/abbrevia/source/AbQDgDir.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbQDgDir.pas *} {*********************************************************} {* ABBREVIA: Dialog - Directory (CLX) *} {* Use AbDlgDir.pas for VCL *} {*********************************************************} {$DEFINE UsingClx } unit AbQDgDir; {$R *.xfm} {$I AbDlgDir.pas} ================================================ FILE: lib/abbrevia/source/AbQDgPwd.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbQDgPwd.pas *} {*********************************************************} {* ABBREVIA: Dialog - Password (CLX) *} {* Use AbDlgPwd.pas for VCL *} {*********************************************************} {$DEFINE UsingClx} unit AbQDgPwd; {$R *.xfm} {$I AbDlgPwd.pas} ================================================ FILE: lib/abbrevia/source/AbQHexVw.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbQCmpnd.pas *} {*********************************************************} {* ABBREVIA: Compound File classes and component (CLX) *} {* Use AbCompnd.pas for VCL *} {*********************************************************} unit AbQHexVw; {$DEFINE UsingCLX} {$I AbHexVw.pas} ================================================ FILE: lib/abbrevia/source/AbQMeter.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbQMeter.pas *} {*********************************************************} {* ABBREVIA: Progress meter (CLX) *} {* Use AbMeter.pas for VCL *} {*********************************************************} {$DEFINE UsingCLX} unit AbQMeter; {$I AbMeter.pas} ================================================ FILE: lib/abbrevia/source/AbQPeCol.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbQPeCol.pas *} {*********************************************************} {* ABBREVIA: Property Editor - ZipView column headings *} {* (CLX) *} {* Use AbPeCol.pas for VCL *} {*********************************************************} {$DEFINE UsingClx} unit AbQPeCol; {$R *.xfm} {$I AbPeCol.pas} ================================================ FILE: lib/abbrevia/source/AbQPeDir.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbPeDir.pas *} {*********************************************************} {* ABBREVIA: Property Editor - Directory (CLX) *} {* Use AbPeDir.pas for VCL *} {*********************************************************} {$DEFINE UsingCLX} unit AbQPeDir; {$I AbPeDir.pas} ================================================ FILE: lib/abbrevia/source/AbQPeFn.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbQPeFn.PAS *} {*********************************************************} {* ABBREVIA: Property Editor - FileName (CLX) *} {* Use AbPeFn.pas for VCL *} {*********************************************************} {$DEFINE UsingClx} unit AbQPeFn; {$I AbPeFn.pas} ================================================ FILE: lib/abbrevia/source/AbQPePas.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbQPePas.pas *} {*********************************************************} {* ABBREVIA: Password property editor (CLX) *} {* Use AbPePass.pas for VCL *} {*********************************************************} {$DEFINE UsingClx} unit AbQPePas; {$I AbPePass.pas} ================================================ FILE: lib/abbrevia/source/AbQPeVer.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbQPeVer.pas *} {*********************************************************} {* ABBREVIA: Property Editor - Version (CLX) *} {* See AbPeVer.pas for the VCL header *} {*********************************************************} {$DEFINE UsingClx} unit AbQPeVer; {$R *.xfm} {$I AbPeVer.pas} ================================================ FILE: lib/abbrevia/source/AbQView.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbQView.pas *} {*********************************************************} {* ABBREVIA: Base archive viewer component (CLX) *} {* Use AbView.pas for VCL *} {*********************************************************} {$DEFINE UsingCLX} unit AbQView; {$I AbView.pas} ================================================ FILE: lib/abbrevia/source/AbQZView.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbQZView.pas *} {*********************************************************} {* ABBREVIA: Zip archive viewer component (CLX) *} {* Use AbZView.pas for VCL *} {*********************************************************} {$DEFINE UsingCLX} unit AbQZView; {$I AbZView.pas} ================================================ FILE: lib/abbrevia/source/AbQZpOut.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbQZpOut.pas *} {*********************************************************} {* ABBREVIA: Visual Component with Zip and unzip support *} {* (CLX) *} {* Use AbZipOut.pas for VCL *} {*********************************************************} {$DEFINE UsingCLX} unit AbQZpOut; {$I AbZipOut.pas} ================================================ FILE: lib/abbrevia/source/AbReg.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbReg.pas *} {*********************************************************} {* ABBREVIA: Registrations (VCL) *} {*********************************************************} unit AbReg; {$I AbDefine.inc} {$UNDEF UsingClx } {$R AbReg.res} interface uses Classes, {$IFDEF LCL} LResources, {$ENDIF} {$IFDEF MSWINDOWS} AbCBrows, AbCabExt, AbCabMak, AbCabKit, {$ENDIF} AbZBrows, AbUnzper, AbZipper, AbZipKit, AbSelfEx; procedure Register; implementation {$IFNDEF FPC} uses AbUtils, AbPeDir, AbPeFn, AbPePass, AbPeVer, AbPeCol, DesignIntf, DesignEditors, SysUtils; {$ENDIF} procedure Register; begin {$IFNDEF FPC} RegisterPropertyEditor( TypeInfo( string ), TAbZipBrowser, 'FileName', TAbFileNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipper, 'FileName', TAbFileNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbUnZipper, 'FileName', TAbFileNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipKit, 'FileName', TAbFileNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipBrowser, 'LogFile', TAbLogNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipper, 'LogFile', TAbLogNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbUnZipper, 'LogFile', TAbLogNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipKit, 'LogFile', TAbLogNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbMakeSelfExe, 'SelfExe', TAbExeNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbMakeSelfExe, 'StubExe', TAbExeNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbMakeSelfExe, 'ZipFile', TAbFileNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipBrowser, 'BaseDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipper, 'BaseDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbUnZipper, 'BaseDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipKit, 'BaseDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipBrowser, 'TempDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipper, 'TempDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbUnZipper, 'TempDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipKit, 'TempDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipBrowser, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipper, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbUnZipper, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipKit, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbMakeSelfExe, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipBrowser, 'Password', TAbPasswordProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipper, 'Password', TAbPasswordProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbUnZipper, 'Password', TAbPasswordProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipKit, 'Password', TAbPasswordProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabBrowser, 'FileName', TAbCabNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbMakeCab, 'FileName', TAbCabNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabExtractor, 'FileName', TAbCabNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabKit, 'FileName', TAbCabNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabBrowser, 'BaseDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbMakeCab, 'BaseDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabExtractor, 'BaseDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabKit, 'BaseDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabBrowser, 'LogFile', TAbLogNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbMakeCab, 'LogFile', TAbLogNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabExtractor, 'LogFile', TAbLogNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabKit, 'LogFile', TAbLogNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabBrowser, 'TempDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbMakeCab, 'TempDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabExtractor, 'TempDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabKit, 'TempDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabBrowser, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbMakeCab, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabExtractor, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabKit, 'Version', TAbVersionProperty ); {$ENDIF} RegisterComponents( 'Abbrevia', [ TAbZipBrowser, TAbUnzipper, TAbZipper, TAbZipKit, {$IFDEF MSWINDOWS} TAbCabBrowser, TAbCabExtractor, TAbMakeCab, TAbCabKit, {$ENDIF} TAbMakeSelfExe ]); end; {$IFDEF LCL} initialization {$I abbrevia.lrs} {$ENDIF} end. ================================================ FILE: lib/abbrevia/source/AbRegClx.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbRegClx.pas *} {*********************************************************} {* ABBREVIA: Registrations (CLX) *} {*********************************************************} unit AbRegClx; {$I AbDefine.inc} {$DEFINE UsingCLX} {$R AbReg.res} interface {$IFDEF LINUX} !! Error, this unit is for CLX on Windows, use AbRegLinux.pas for Linux {$ENDIF} uses Classes, AbCBrows, AbCabExt, AbCabMak, AbCabKit, AbZBrows, AbUnzper, AbZipper, AbZipKit, AbSelfEx, AbQCView, AbQZpOut, AbQView, AbQZView, AbQMeter; procedure Register; implementation uses AbUtils, AbQPeDir, AbQPeFn, AbQPePas, AbQPeVer, AbQPeCol, AbQDgDir, AbQDgPwd, DesignIntf, DesignEditors, SysUtils; procedure Register; begin RegisterPropertyEditor( TypeInfo( string ), TAbZipBrowser, 'FileName', TAbFileNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipper, 'FileName', TAbFileNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbUnZipper, 'FileName', TAbFileNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipKit, 'FileName', TAbFileNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipOutline, 'FileName', TAbFileNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipBrowser, 'LogFile', TAbLogNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipper, 'LogFile', TAbLogNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbUnZipper, 'LogFile', TAbLogNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipKit, 'LogFile', TAbLogNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipOutline, 'LogFile', TAbLogNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbMakeSelfExe, 'SelfExe', TAbExeNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbMakeSelfExe, 'StubExe', TAbExeNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbMakeSelfExe, 'ZipFile', TAbFileNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipBrowser, 'BaseDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipper, 'BaseDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbUnZipper, 'BaseDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipKit, 'BaseDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipOutline, 'BaseDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipBrowser, 'TempDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipper, 'TempDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbUnZipper, 'TempDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipKit, 'TempDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipOutline, 'TempDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipBrowser, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipper, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbUnZipper, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipKit, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipOutline, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipView, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbMeter, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbMakeSelfExe, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipBrowser, 'Password', TAbPasswordProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipper, 'Password', TAbPasswordProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbUnZipper, 'Password', TAbPasswordProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipKit, 'Password', TAbPasswordProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipOutline, 'Password', TAbPasswordProperty ); RegisterPropertyEditor( TypeInfo( TAbColHeadings ), TAbZipView, 'Headings', TAbColHeadingsProperty ); {$IFDEF MSWINDOWS} RegisterPropertyEditor( TypeInfo( string ), TAbCabBrowser, 'FileName', TAbCabNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbMakeCab, 'FileName', TAbCabNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabExtractor, 'FileName', TAbCabNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabKit, 'FileName', TAbCabNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabBrowser, 'BaseDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbMakeCab, 'BaseDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabExtractor, 'BaseDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabKit, 'BaseDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabBrowser, 'LogFile', TAbLogNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbMakeCab, 'LogFile', TAbLogNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabExtractor, 'LogFile', TAbLogNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabKit, 'LogFile', TAbLogNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabBrowser, 'TempDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbMakeCab, 'TempDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabExtractor, 'TempDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabKit, 'TempDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabBrowser, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbMakeCab, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabExtractor, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabKit, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabView, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( TAbColHeadings ), TAbCabView, 'Headings', TAbColHeadingsProperty ); {$ENDIF} RegisterComponents( 'Abbrevia', [ TAbZipBrowser, TAbUnzipper, TAbZipper, TAbZipKit, TAbZipView, TAbZipOutline, {$IFDEF MSWINDOWS} TAbCabBrowser, TAbCabExtractor, TAbMakeCab, TAbCabKit, TAbCabView, {$ENDIF} TAbMeter, TAbMakeSelfExe ]); RegisterPropertyEditor( TypeInfo( string ), TAbZipOutline, 'FileName', TAbFileNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipOutline, 'LogFile', TAbLogNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipOutline, 'BaseDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipOutline, 'TempDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipOutline, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipView, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( TAbColHeadings ), TAbZipView, 'Headings', TAbColHeadingsProperty ); RegisterComponents( 'Abbrevia', [ TAbMeter, TAbCabView, TAbZipView, TAbZipOutline ]); end; end. ================================================ FILE: lib/abbrevia/source/AbRegLinux.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbRegLinux.pas *} {*********************************************************} {* ABBREVIA: Registrations *} {*********************************************************} unit AbRegLinux; {$I AbDefine.inc} {$R AbReg.res} interface {$IFDEF MSWINDOWS} !! Error, this unit is for CLX on Linux, use AbRegClx.pas for Windows {$ENDIF} uses Classes, AbQZpOut, AbQView, AbQZView, AbQMeter; procedure Register; implementation uses AbUtils, AbQPeDir, AbQPeFn, AbQPePas, AbQPeVer, AbQPeCol, AbZBrows, AbZipper, AbUnzper, AbZipKit, AbSelfEx, DesignIntf, DesignEditors; procedure Register; begin RegisterPropertyEditor( TypeInfo( string ), TAbZipBrowser, 'FileName', TAbFileNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipper, 'FileName', TAbFileNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbUnZipper, 'FileName', TAbFileNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipKit, 'FileName', TAbFileNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipOutline, 'FileName', TAbFileNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipBrowser, 'LogFile', TAbLogNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipper, 'LogFile', TAbLogNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbUnZipper, 'LogFile', TAbLogNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipKit, 'LogFile', TAbLogNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipOutline, 'LogFile', TAbLogNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbMakeSelfExe, 'SelfExe', TAbExeNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbMakeSelfExe, 'StubExe', TAbExeNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbMakeSelfExe, 'ZipFile', TAbFileNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipBrowser, 'BaseDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipper, 'BaseDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbUnZipper, 'BaseDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipKit, 'BaseDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipOutline, 'BaseDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipBrowser, 'TempDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipper, 'TempDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbUnZipper, 'TempDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipKit, 'TempDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipOutline, 'TempDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipBrowser, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipper, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbUnZipper, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipKit, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipOutline, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipView, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbMeter, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbMakeSelfExe, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipBrowser, 'Password', TAbPasswordProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipper, 'Password', TAbPasswordProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbUnZipper, 'Password', TAbPasswordProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipKit, 'Password', TAbPasswordProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipOutline, 'Password', TAbPasswordProperty ); RegisterPropertyEditor( TypeInfo( TAbColHeadings ), TAbZipView, 'Headings', TAbColHeadingsProperty ); RegisterComponents( 'Abbrevia', [TAbZipBrowser, TAbUnzipper, TAbZipper, TAbZipKit, TAbZipOutline, TAbZipView, TAbMeter, TAbMakeSelfExe]); end; end. ================================================ FILE: lib/abbrevia/source/AbRegVcl.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbRegVcl.pas *} {*********************************************************} {* ABBREVIA: Registrations (VCL) *} {*********************************************************} unit AbRegVcl; {$I AbDefine.inc} {$UNDEF UsingClx } {$R AbReg.res} interface uses Classes, AbCBrows, AbCabExt, AbCabMak, AbCabKit, AbCView, AbCompnd, AbHexVw, AbZBrows, AbUnzper, AbZipper, AbZipKit, AbZipOut, AbView, AbComCtrls, AbZView, AbMeter, AbSelfEx, AbZipExt; procedure Register; implementation uses AbConst, AbUtils, AbPeDir, AbPeFn, AbPePass, AbPeVer, AbPeCol, DesignIntf, DesignEditors, Graphics, ToolsAPI, SysUtils, Windows; procedure Register; begin RegisterPropertyEditor( TypeInfo( string ), TAbZipBrowser, 'FileName', TAbFileNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipper, 'FileName', TAbFileNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbUnZipper, 'FileName', TAbFileNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipKit, 'FileName', TAbFileNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipOutline, 'FileName', TAbFileNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipBrowser, 'LogFile', TAbLogNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipper, 'LogFile', TAbLogNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbUnZipper, 'LogFile', TAbLogNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipKit, 'LogFile', TAbLogNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipOutline, 'LogFile', TAbLogNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbMakeSelfExe, 'SelfExe', TAbExeNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbMakeSelfExe, 'StubExe', TAbExeNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbMakeSelfExe, 'ZipFile', TAbFileNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipBrowser, 'BaseDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipper, 'BaseDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbUnZipper, 'BaseDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipKit, 'BaseDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipOutline, 'BaseDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipBrowser, 'TempDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipper, 'TempDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbUnZipper, 'TempDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipKit, 'TempDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipOutline, 'TempDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipBrowser, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipper, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbUnZipper, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipKit, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipOutline, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbListView, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbTreeView, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipView, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbMeter, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbProgressBar, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbMakeSelfExe, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipBrowser, 'Password', TAbPasswordProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipper, 'Password', TAbPasswordProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbUnZipper, 'Password', TAbPasswordProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipKit, 'Password', TAbPasswordProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbZipOutline, 'Password', TAbPasswordProperty ); RegisterPropertyEditor( TypeInfo( TAbColHeadings ), TAbZipView, 'Headings', TAbColHeadingsProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabBrowser, 'FileName', TAbCabNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbMakeCab, 'FileName', TAbCabNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabExtractor, 'FileName', TAbCabNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabKit, 'FileName', TAbCabNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabBrowser, 'BaseDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbMakeCab, 'BaseDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabExtractor, 'BaseDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabKit, 'BaseDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabBrowser, 'LogFile', TAbLogNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbMakeCab, 'LogFile', TAbLogNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabExtractor, 'LogFile', TAbLogNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabKit, 'LogFile', TAbLogNameProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabBrowser, 'TempDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbMakeCab, 'TempDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabExtractor, 'TempDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabKit, 'TempDirectory', TAbDirectoryProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabBrowser, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbMakeCab, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabExtractor, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabKit, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( string ), TAbCabView, 'Version', TAbVersionProperty ); RegisterPropertyEditor( TypeInfo( TAbColHeadings ), TAbCabView, 'Headings', TAbColHeadingsProperty ); RegisterComponents( 'Abbrevia', [ TAbZipBrowser, TAbUnzipper, TAbZipper, TAbZipKit, TAbZipView, TAbZipOutline, TAbTreeView, TAbListView, TAbCabBrowser, TAbCabExtractor, TAbMakeCab, TAbCabKit, TAbCabView, TAbProgressBar, TAbMeter, TAbMakeSelfExe ]); end; {$IF DECLARED(IOTAAboutBoxServices)} var AboutBoxIndex: Integer = -1; procedure RegisterAboutBox; begin SplashScreenServices.AddPluginBitmap( 'Abbrevia: Advanced data compression toolkit, v' + AbVersionS, LoadBitmap(HInstance, 'SPLASH')); AboutBoxIndex := (BorlandIDEServices as IOTAAboutBoxServices).AddPluginInfo( 'Abbrevia ' + AbVersionS, 'Abbrevia: Advanced data compression toolkit, v' + AbVersionS + sLineBreak + 'http://tpabbrevia.sourceforge.net/' + sLineBreak + sLineBreak + 'Copyright (c) 1997-2011 Abbrevia development team' + sLineBreak + 'Covered under the Mozilla Public License (MPL) v1.1' + sLineBreak + 'Abbrevia includes source code from bzip2, the LZMA SDK,' + sLineBreak + 'Dag gren''s version of PPMd, and the WavPack SDK.', LoadBitmap(HInstance, 'SPLASH')); end; procedure UnregisterAboutBox; begin if AboutBoxIndex <> -1 then (BorlandIDEServices as IOTAAboutBoxServices).RemovePluginInfo(AboutBoxIndex); end; initialization RegisterAboutBox; finalization UnRegisterAboutBox; {$IFEND} end. ================================================ FILE: lib/abbrevia/source/AbResString.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Roman Kassebaum * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* Abbrevia: AbResString.pas *} {*********************************************************} {* Abbrevia: Resource strings *} {*********************************************************} unit AbResString; {$I AbDefine.inc} interface resourcestring AbErrZipInvalidS = 'Invalid file - not a PKZip file'; AbZipVersionNeededS = 'Cannot extract file - newer version required'; AbUnknownCompressionMethodS = 'Cannot extract file - unsupported compression method'; AbNoExtractionMethodS = 'Cannot extract file - no extraction support provided'; AbInvalidPasswordS = 'Cannot extract file - invalid password'; AbNoInsertionMethodS = 'Cannot insert file - no insertion support provided'; AbInvalidFactorS = 'Invalid Reduce Factor'; AbDuplicateNameS = 'Cannot insert file - duplicates stored name'; AbUnsupportedCompressionMethodS = 'Cannot insert file - unsupported compression method'; AbUserAbortS = 'Process aborted by user'; AbArchiveBusyS = 'Archive is busy - cannot process new requests'; AbLastDiskRequestS = 'Insert the last disk in the spanned disk set'; AbDiskRequestS = 'Insert floppy'; AbImageRequestS = 'Image file name'; AbBadSpanStreamS = 'Spanned archives must be opened as file streams'; AbDiskNumRequestS = 'Insert disk number %d of the spanned disk set'; AbImageNumRequestS = 'Insert span number %d of the spanned file set'; AbNoOverwriteSpanStreamS = 'Cannot update an existing spanned disk set'; AbNoSpannedSelfExtractS = 'Cannot make a self-extracting spanned disk set'; AbBlankDiskS = 'Insert a blank floppy disk'; AbStreamFullS = 'Stream write error'; AbNoSuchDirectoryS = 'Directory does not exist'; AbInflateBlockErrorS = 'Cannot inflate block'; AbBadStreamTypeS = 'Invalid Stream'; AbTruncateErrorS = 'Error truncating Zip File'; AbZipBadCRCS = 'Failed CRC Check'; AbZipBadStubS = 'Stub must be an executable'; AbFileNotFoundS = 'File not found'; AbInvalidLFHS = 'Invalid Local File Header entry'; AbNoArchiveS = 'Archive does not exist - Filename is blank'; AbReadErrorS = 'Error reading archive'; AbInvalidIndexS = 'Invalid archive item index'; AbInvalidThresholdS = 'Invalid archive size threshold'; AbUnhandledFileTypeS = 'Unhandled Archive Type'; AbSpanningNotSupportedS = 'Spanning not supported by this Archive type'; AbLogCreateErrorS = 'Error creating Log File'; AbMoveFileErrorS = 'Error Moving File %s to %s'; AbFileSizeTooBigS = 'File size is too big for archive type'; AbNoCabinetDllErrorS = 'Cannot load cabinet.dll'; AbFCIFileOpenErrorS = 'FCI cannot open file'; AbFCIFileReadErrorS = 'FCI cannot read file'; AbFCIFileWriteErrorS = 'FCI cannot write file'; AbFCIFileCloseErrorS = 'FCI close file error'; AbFCIFileSeekErrorS = 'FCI file seek error'; AbFCIFileDeleteErrorS = 'FCI file delete error'; AbFCIAddFileErrorS = 'FCI cannot add file'; AbFCICreateErrorS = 'FCI cannot create context'; AbFCIFlushCabinetErrorS = 'FCI cannot flush cabinet'; AbFCIFlushFolderErrorS = 'FCI cannot flush folder'; AbFDICopyErrorS = 'FDI cannot enumerate files'; AbFDICreateErrorS = 'FDI cannot create context'; AbInvalidCabTemplateS = 'Invalid cab file template'; AbInvalidCabFileS = 'Invalid file - not a cabinet file'; AbZipStored = 'Stored'; AbZipShrunk = 'Shrunk'; AbZipReduced = 'Reduced'; AbZipImploded = 'Imploded'; AbZipTokenized = 'Tokenized'; AbZipDeflated = 'Deflated'; AbZipDeflate64 = 'Enhanced Deflation'; AbZipDCLImploded = 'DCL Imploded'; AbZipBzip2 = 'Bzip2'; AbZipLZMA = 'LZMA'; AbZipIBMTerse = 'IBM Terse'; AbZipLZ77 = 'IBM LZ77'; AbZipJPEG = 'JPEG'; AbZipWavPack = 'WavPack'; AbZipPPMd = 'PPMd'; AbZipUnknown = 'Unknown (%d)'; AbZipBestMethod = 'Best Method'; AbVersionFormatS = 'Version %s'; AbCompressedSizeFormatS = 'Compressed Size: %d'; AbUncompressedSizeFormatS = 'Uncompressed Size: %d'; AbCompressionMethodFormatS = 'Compression Method: %s'; AbCompressionRatioFormatS = 'Compression Ratio: %2.0f%%'; AbCRCFormatS = 'CRC: %x'; AbReadOnlyS = 'r'; AbHiddenS = 'h'; AbSystemS = 's'; AbArchivedS = 'a'; AbEFAFormatS = 'External File Attributes: %s'; AbIFAFormatS = 'File Type: %s'; AbTextS = 'Text'; AbBinaryS = 'Binary'; AbEncryptionFormatS = 'Encryption: %s'; AbEncryptedS = 'Encrypted'; AbNotEncryptedS = 'Not Encrypted'; AbUnknownS = 'Unknown'; AbTimeStampFormatS = 'Time Stamp: %s'; AbMadeByFormatS = 'Made by Version: %f'; AbNeededFormatS = 'Version Needed to Extract: %f'; AbCommentFormatS = 'Comment: %s'; AbDefaultExtS = '*.zip'; AbFilterS = 'PKZip Archives (*.zip)|*.zip|Self Extracting Archives (*.exe)|*.exe|All Files (*.*)|*.*'; AbFileNameTitleS = 'Select File Name'; AbOKS = 'OK'; AbCancelS = 'Cancel'; AbSelectDirectoryS = 'Select Directory'; AbEnterPasswordS = 'Enter Password'; AbPasswordS = '&Password'; AbVerifyS = '&Verify'; AbCabExtS = '*.cab'; AbCabFilterS = 'Cabinet Archives (*.cab)|*.CAB|All Files (*.*)|*.*'; AbLogExtS = '*.txt'; AbLogFilterS = 'Text Files (*.txt)|*.TXT|All Files (*.*)|*.*'; AbExeExtS = '*.exe'; AbExeFilterS = 'Self-Extracting Zip Files (*.exe)|*.EXE|All Files (*.*)|*.*'; AbVMSReadTooManyBytesS = 'VMS: request to read too many bytes [%d]'; AbVMSInvalidOriginS = 'VMS: invalid origin %d, should be 0, 1, 2'; AbVMSErrorOpenSwapS = 'VMS: Cannot open swap file %s'; AbVMSSeekFailS = 'VMS: Failed to seek in swap file %s'; AbVMSReadFailS = 'VMS: Failed to read %d bytes from swap file %s'; AbVMSWriteFailS = 'VMS: Failed to write %d bytes to swap file %s'; AbVMSWriteTooManyBytesS = 'VMS: request to write too many bytes [%d]'; AbBBSReadTooManyBytesS = 'BBS: request to read too many bytes [%d]'; AbBBSSeekOutsideBufferS = 'BBS: New position is outside the buffer'; AbBBSInvalidOriginS = 'BBS: Invalid Origin value'; AbBBSWriteTooManyBytesS = 'BBS: request to write too many bytes [%d]'; AbSWSNotEndofStreamS = 'TabSlidingWindowStream.Write: Not at end of stream'; AbSWSSeekFailedS = 'TabSlidingWindowStream.bsWriteChunk: seek failed'; AbSWSWriteFailedS = 'TabSlidingWindowStream.bsWriteChunk: write failed'; AbSWSInvalidOriginS = 'TabSlidingWindowStream.Seek: invalid origin'; AbSWSInvalidNewOriginS = 'TabSlidingWindowStream.Seek: invalid new position'; AbItemNameHeadingS = 'Name'; AbPackedHeadingS = 'Packed'; AbMethodHeadingS = 'Method'; AbRatioHeadingS = 'Ratio (%)'; AbCRCHeadingS = 'CRC32'; AbFileAttrHeadingS = 'Attributes'; AbFileFormatHeadingS = 'Format'; AbEncryptionHeadingS = 'Encrypted'; AbTimeStampHeadingS = 'Time Stamp'; AbFileSizeHeadingS = 'Size'; AbVersionMadeHeadingS = 'Version Made'; AbVersionNeededHeadingS = 'Version Needed'; AbPathHeadingS = 'Path'; AbPartialHeadingS = 'Partial'; AbExecutableHeadingS = 'Executable'; AbFileTypeHeadingS = 'Type'; AbLastModifiedHeadingS = 'Modified'; AbCabMethod0S = 'None'; AbCabMethod1S = 'MSZip'; AbLtAddS = ' added '; AbLtDeleteS = ' deleted '; AbLtExtractS = ' extracted '; AbLtFreshenS = ' freshened '; AbLtMoveS = ' moved '; AbLtReplaceS = ' replaced '; AbLtStartS = ' logging '; AbGzipInvalidS = 'Invalid Gzip'; AbGzipBadCRCS = 'Bad CRC'; AbGzipBadFileSizeS = 'Bad File Size'; AbTarInvalidS = 'Invalid Tar'; AbTarBadFileNameS = 'File name too long'; AbTarBadLinkNameS = 'Symbolic link path too long'; AbTarBadOpS = 'Unsupported Operation'; AbUnhandledEntityS = 'Unhandled Entity'; { pre-defined "operating system" (really more FILE system) identifiers for the Gzip header } AbGzOsFat = 'FAT File System (MS-DOS, OS/2, NT/Win32)'; AbGzOsAmiga = 'Amiga'; AbGzOsVMS = 'VMS (or OpenVMS)'; AbGzOsUnix = 'Unix'; AbGzOsVM_CMS = 'VM/CMS'; AbGzOsAtari = 'Atari TOS'; AbGzOsHPFS = 'HPFS File System (OS/2, NT)'; AbGzOsMacintosh = 'Macintosh'; AbGzOsZ_System = 'Z-System'; AbGzOsCP_M = 'CP/M'; AbGzOsTOPS_20 = 'TOPS-20'; AbGzOsNTFS = 'NTFS File System (NT)'; AbGzOsQDOS = 'QDOS'; AbGzOsAcornRISCOS = 'Acorn RISCOS'; AbGzOsVFAT = 'VFAT File System (Win95, NT)'; AbGzOsMVS = 'MVS'; AbGzOsBeOS = 'BeOS (BeBox or PowerMac)'; AbGzOsTandem = 'Tandem/NSK'; AbGzOsTHEOS = 'THEOS'; AbGzOsunknown = 'unknown'; AbGzOsUndefined = 'ID undefined by gzip'; { Compound File specific error messages } resourcestring AbCmpndIndexOutOfBounds = 'Index out of bounds'; AbCmpndBusyUpdating = 'Compound file is busy updating'; AbCmpndInvalidFile = 'Invalid compound file'; AbCmpndFileNotFound = 'File/Directory not found'; AbCmpndFolderNotEmpty = 'Folder not empty'; AbCmpndExceedsMaxFileSize = 'File size exceeds maximum allowable'; implementation end. ================================================ FILE: lib/abbrevia/source/AbSWStm.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbSWStm.pas *} {*********************************************************} {* ABBREVIA: TabSlidingWindowStream class *} {*********************************************************} unit AbSWStm; {$I AbDefine.inc} {Notes: The TabSlidingWindowStream class provides a simple buffered stream for sliding window compression/decompression routines. The sliding window stream is limited when compared with a true buffered stream: - it is assumed that the underlying stream is just going to be written to and is initially empty - the buffer is fixed in size to 40KB - write operations can only occur at the end of the stream - the stream can only be positioned with a certain limited range - we can only read up to 32KB - we can only write up to 32KB The stream is written as a wrapper around another stream (presumably a file stream) which is used for actual reads to the buffer and writes from the buffer. The stream buffer is organized as five 8KB chunks in an array. The last chunk is the only one used for writing, the other four are a 32KB buffer for reading. As the final chunk gets filled, the class will drop off the first chunk (writing it to the underlying stream, and shift the other chunks in the array.} {Define this if you wish to see a trace of the stream usage in a file called C:\SlideWin.LOG} {.$DEFINE DebugTrace} interface uses SysUtils, Classes; const abSWChunkCount = 5; type TabSlidingWindowStream = class(TStream) protected {private} bsChunks : array [0..pred(abSWChunkCount)] of PByteArray; bsBufferStart : longint; bsLastPos : integer; bsCurChunk : integer; bsPosInChunk : integer; bsPosInBuffer : longint; bsSize : Longint; {count of bytes in stream} bsDirty : boolean; {whether the buffer is dirty or not} bsStream : TStream; {actual stream containing data} {$IFDEF DebugTrace} bsF : System.Text; {$ENDIF} protected procedure bsWriteChunk(aIndex : integer); procedure bsSlide; public constructor Create(aStream : TStream); {-create the buffered stream} destructor Destroy; override; {-destroy the buffered stream} procedure Flush; {-ensures that all dirty buffered data is flushed} function Read(var Buffer; Count : Longint) : Longint; override; {-read from the stream into a buffer} function Seek(Offset : Longint; Origin : Word) : Longint; override; {-seek to a particular point in the stream} function Write(const Buffer; Count : Longint) : Longint; override; {-write to the stream from a buffer} end; implementation const ChunkSize = 8192; {cannot be greater than MaxInt} {===Helper routines==================================================} procedure RaiseException(const S : string); begin raise Exception.Create(S); end; {====================================================================} {===TabSlidingWindowStream===========================================} constructor TabSlidingWindowStream.Create(aStream : TStream); var i : integer; begin inherited Create; {save the actual stream} bsStream := aStream; {allocate the chunks-they must be set to binary zeros} for i := 0 to pred(abSWChunkCount) do bsChunks[i] := AllocMem(ChunkSize); {set the page/buffer variables to the start of the stream; remember we only write to the last chunk--the previous chunks are set to binary zeros} aStream.Position := 0; bsSize := 0; bsBufferStart := -ChunkSize * pred(abSWChunkCount); bsPosInBuffer := ChunkSize * pred(abSWChunkCount); bsCurChunk := pred(abSWChunkCount); bsPosInChunk := 0; bsDirty := false; {$IFDEF DebugTrace} System.Assign(bsF, 'c:\SlideWin.LOG'); if FileExists('c:\SlideWin.LOG') then System.Append(bsF) else System.Rewrite(bsF); writeln(bsF, '---NEW LOG---'); {$ENDIF} end; {--------} destructor TabSlidingWindowStream.Destroy; var i : integer; begin {destroy the buffer, after writing it to the actual stream} if bsDirty then Flush; for i := 0 to pred(abSWChunkCount) do if (bsChunks[i] <> nil) then FreeMem(bsChunks[i], ChunkSize); {$IFDEF DebugTrace} System.Close(bsF); {$ENDIF} {let our ancestor clean up} inherited Destroy; end; {--------} procedure TabSlidingWindowStream.bsSlide; var SavePtr : PByteArray; i : integer; begin {write out the first chunk} bsWriteChunk(0); {slide the chunks around} SavePtr := bsChunks[0]; for i := 0 to abSWChunkCount-2 do bsChunks[i] := bsChunks[i+1]; bsChunks[pred(abSWChunkCount)] := SavePtr; {advance the buffer start position} inc(bsBufferStart, ChunkSize); {reset the write position} bsPosInChunk := 0; bsPosInBuffer := ChunkSize * pred(abSWChunkCount); bsLastPos := 0; end; {--------} procedure TabSlidingWindowStream.bsWriteChunk(aIndex : integer); var SeekResult : longint; BytesWrit : longint; Offset : longint; BytesToWrite : integer; begin Offset := bsBufferStart + (longint(aIndex) * ChunkSize); if (Offset >= 0) then begin SeekResult := bsStream.Seek(Offset, 0); if (SeekResult = -1) then RaiseException('TabSlidingWindowStream.bsWriteChunk: seek failed'); if (aIndex <> pred(abSWChunkCount)) then BytesToWrite := ChunkSize else BytesToWrite := bsLastPos; BytesWrit := bsStream.Write(bsChunks[aIndex]^, BytesToWrite); if (BytesWrit <> BytesToWrite) then RaiseException('TabSlidingWindowStream.bsWriteChunk: write failed'); end; end; {--------} procedure TabSlidingWindowStream.Flush; var i : integer; begin if bsDirty then begin for i := 0 to pred(abSWChunkCount) do bsWriteChunk(i); bsDirty := false; end; end; {--------} function TabSlidingWindowStream.Read(var Buffer; Count : Longint) : Longint; var BufPtr : PByte; BytesToGo : Longint; BytesToRead : integer; begin BufPtr := @Buffer; {$IFDEF DebugTrace} System.Writeln(bsF, 'Read: ', Count, ' bytes'); {$ENDIF} {we do not support reads greater than 32KB bytes} if (Count > 32*1024) then Count := 32*1024; {reading is complicated by the fact we can only read in chunks of ChunkSize: we need to partition out the overall read into a read from part of the chunk, zero or more reads from complete chunks and then a possible read from part of a chunk} {calculate the actual number of bytes we can read - this depends on the current position and size of the stream as well as the number of bytes requested} BytesToGo := Count; if (bsSize < (bsBufferStart + bsPosInBuffer + Count)) then BytesToGo := bsSize - (bsBufferStart + bsPosInBuffer); if (BytesToGo <= 0) then begin Result := 0; Exit; end; {remember to return the result of our calculation} Result := BytesToGo; {calculate the number of bytes we can read prior to the loop} BytesToRead := ChunkSize - bsPosInChunk; if (BytesToRead > BytesToGo) then BytesToRead := BytesToGo; {copy from the stream buffer to the caller's buffer} if (BytesToRead = 1) then BufPtr^ := bsChunks[bsCurChunk]^[bsPosInChunk] else Move(bsChunks[bsCurChunk]^[bsPosInChunk], BufPtr^, BytesToRead); {calculate the number of bytes still to read} dec(BytesToGo, BytesToRead); {while we have bytes to read, read them} while (BytesToGo > 0) do begin {advance the pointer for the caller's buffer} inc(BufPtr, BytesToRead); {as we've exhausted this chunk, advance to the next} inc(bsCurChunk); bsPosInChunk := 0; {calculate the number of bytes we can read in this cycle} BytesToRead := ChunkSize; if (BytesToRead > BytesToGo) then BytesToRead := BytesToGo; {copy from the stream buffer to the caller's buffer} Move(bsChunks[bsCurChunk]^, BufPtr^, BytesToRead); {calculate the number of bytes still to read} dec(BytesToGo, BytesToRead); end; {remember our new position} inc(bsPosInChunk, BytesToRead); end; {--------} function TabSlidingWindowStream.Seek(Offset : Longint; Origin : Word) : Longint; {$IFDEF DebugTrace} const OriginStr : array [0..2] of string[7] = ('start', 'current', 'end'); {$ENDIF} var NewPos : Longint; begin {$IFDEF DebugTrace} System.Writeln(bsF, 'Seek: ', Offset, ' bytes from ', OriginStr[Origin]); {$ENDIF} {calculate the new position} case Origin of soFromBeginning : NewPos := Offset; soFromCurrent : NewPos := bsBufferStart + bsPosInBuffer + Offset; soFromEnd : NewPos := bsSize + Offset; else NewPos := 0; RaiseException('TabSlidingWindowStream.Seek: invalid origin'); end; {if the new position is invalid, say so} if (NewPos < bsBufferStart) or (NewPos > bsSize) then RaiseException('TabSlidingWindowStream.Seek: invalid new position'); {calculate the chunk number and the position in buffer & chunk} bsPosInBuffer := NewPos - bsBufferStart; bsCurChunk := bsPosInBuffer div ChunkSize; bsPosInChunk := bsPosInBuffer mod ChunkSize; {return the new position} Result := NewPos; end; {--------} function TabSlidingWindowStream.Write(const Buffer; Count : Longint) : Longint; var BufPtr : PByte; BytesToGo : Longint; BytesToWrite: integer; begin BufPtr := @Buffer; {$IFDEF DebugTrace} System.Writeln(bsF, 'Write: ', Count, ' bytes'); {$ENDIF} {we ONLY write at the end of the stream} if ((bsBufferStart + bsPosInBuffer) <> bsSize) then RaiseException('TabSlidingWindowStream.Write: Not at end of stream'); {we do not support writes greater than 32KB bytes} if (Count > 32*1024) then Count := 32*1024; {writing is complicated by the fact we write in chunks of Chunksize bytes: we need to partition out the overall write into a write to part of the chunk, zero or more writes to complete chunks and then a possible write to part of a chunk; every time we fill a chunk we have toi slide the buffer} {when we write to this stream we always assume that we can write the requested number of bytes: if we can't (eg, the disk is full) we'll get an exception somewhere eventually} BytesToGo := Count; {remember to return the result of our calculation} Result := BytesToGo; {calculate the number of bytes we can write prior to the loop} BytesToWrite := ChunkSize - bsPosInChunk; if (BytesToWrite > BytesToGo) then BytesToWrite := BytesToGo; {copy from the caller's buffer to the stream buffer} if (BytesToWrite = 1) then bsChunks[pred(abSWChunkCount)]^[bsPosInChunk] := BufPtr^ else Move(BufPtr^, bsChunks[pred(abSWChunkCount)]^[bsPosInChunk], BytesToWrite); {mark our buffer as requiring a save to the actual stream} bsDirty := true; {calculate the number of bytes still to write} dec(BytesToGo, BytesToWrite); {while we have bytes to write, write them} while (BytesToGo > 0) do begin {slide the buffer} bsSlide; {advance the pointer for the caller's buffer} inc(BufPtr, BytesToWrite); {calculate the number of bytes we can write in this cycle} BytesToWrite := ChunkSize; if (BytesToWrite > BytesToGo) then BytesToWrite := BytesToGo; {copy from the caller's buffer to our buffer} Move(BufPtr^, bsChunks[pred(abSWChunkCount)]^, BytesToWrite); {calculate the number of bytes still to write} dec(BytesToGo, BytesToWrite); end; {remember our new position} inc(bsPosInChunk, BytesToWrite); bsPosInBuffer := (longint(ChunkSize) * pred(abSWChunkCount)) + bsPosInChunk; bsLastPos := bsPosInChunk; {make sure the stream size is correct} inc(bsSize, Result); {if we're at the end of the chunk, slide the buffer ready for next time we write} if (bsPosInChunk = ChunkSize) then bsSlide; end; {====================================================================} end. ================================================ FILE: lib/abbrevia/source/AbSelfEx.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbSelfEx.pas *} {*********************************************************} {* ABBREVIA: Component for building self-extracting zips *} {*********************************************************} unit AbSelfEx; {$I AbDefine.inc} interface uses Classes, AbBase; type TAbGetFileEvent = procedure(Sender : TObject; var aFilename : string; var Abort : Boolean) of object; type TAbMakeSelfExe = class(TAbBaseComponent) protected {private} FStubExe : string; FZipFile : string; FSelfExe : string; FStubStream : TFileStream; FZipStream : TFileStream; FSelfStream : TFileStream; FOnGetStubExe : TAbGetFileEvent; FOnGetZipFile : TAbGetFileEvent; procedure DoGetStubExe(var Abort : Boolean); procedure DoGetZipFile(var Abort : Boolean); public function Execute : Boolean; published property SelfExe : string read FSelfExe write FSelfExe; property StubExe : string read FStubExe write FStubExe; property ZipFile : string read FZipFile write FZipFile; property OnGetStubExe : TAbGetFileEvent read FOnGetStubExe write FOnGetStubExe; property OnGetZipFile : TAbGetFileEvent read FOnGetZipFile write FOnGetZipFile; property Version; end; implementation uses SysUtils, {$IFDEF LibcAPI} Libc, {$ENDIF} AbExcept, AbZipTyp; { -------------------------------------------------------------------------- } function TAbMakeSelfExe.Execute : Boolean; var Abort : Boolean; begin Abort := False; if (FStubExe = '') then DoGetStubExe(Abort); if Abort then raise EAbUserAbort.Create; if not FileExists(FStubExe) then raise EAbFileNotFound.Create; if (FZipFile = '') then DoGetZipFile(Abort); if Abort then raise EAbUserAbort.Create; if not FileExists(FZipFile) then raise EAbFileNotFound.Create; FStubStream := TFileStream.Create(FStubExe, fmOpenRead or fmShareDenyWrite); FZipStream := TFileStream.Create(FZipFile, fmOpenRead or fmShareDenyWrite); if (FSelfExe = '') then FSelfExe := ChangeFileExt(FZipFile, '.exe'); FSelfStream := TFileStream.Create(FSelfExe, fmCreate or fmShareExclusive); try MakeSelfExtracting(FStubStream, FZipStream, FSelfStream); Result := True; finally FStubStream.Free; FZipStream.Free; FSelfStream.Free; end; end; { -------------------------------------------------------------------------- } procedure TAbMakeSelfExe.DoGetStubExe(var Abort: Boolean); begin if Assigned(FOnGetStubExe) then FOnGetStubExe(Self, FStubExe, Abort); end; { -------------------------------------------------------------------------- } procedure TAbMakeSelfExe.DoGetZipFile(var Abort : Boolean); begin if Assigned(FOnGetZipFile) then FOnGetZipFile(Self, FZipFile, Abort); end; { -------------------------------------------------------------------------- } end. ================================================ FILE: lib/abbrevia/source/AbSpanSt.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Craig Peterson * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbSpanSt.pas *} {*********************************************************} {* ABBREVIA: TAbSpan*Stream Classes *} {*********************************************************} {* Streams to handle splitting ZIP files or spanning *} {* them to diskettes *} {*********************************************************} unit AbSpanSt; {$I AbDefine.inc} interface uses Classes, AbArcTyp; type { TAbSpanBaseStream interface ============================================== } TAbSpanBaseStream = class(TStream) protected {private} FArchiveName: string; FOnRequestImage: TAbRequestImageEvent; protected {methods} function GetImageName( ImageNumber: Integer ): string; public {methods} constructor Create( const ArchiveName: string ); public {events} property OnRequestImage : TAbRequestImageEvent read FOnRequestImage write FOnRequestImage; end; { TAbSpanReadStream interface ============================================== } TAbSpanReadStream = class(TAbSpanBaseStream) protected {private} FCurrentImage: LongWord; FIsSplit: Boolean; FLastImage: LongWord; FStream: TStream; FOnRequestNthDisk : TAbRequestNthDiskEvent; protected {methods} procedure GotoImage( ImageNumber: Integer ); procedure SetOnRequestImage(Value: TAbRequestImageEvent); public {methods} constructor Create( const ArchiveName: string; CurrentImage: LongWord; Stream: TStream ); destructor Destroy; override; function Read(var Buffer; Count: Longint): Longint; override; function Write(const Buffer; Count: Longint): Longint; override; function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override; procedure SeekImage( Image: LongWord; const Offset: Int64); public {events} property OnRequestImage write SetOnRequestImage; property OnRequestNthDisk : TAbRequestNthDiskEvent read FOnRequestNthDisk write FOnRequestNthDisk; end; { TAbSpanWriteStream interface ============================================= } TAbSpanWriteStream = class(TAbSpanBaseStream) protected {private} FCurrentImage: LongWord; FImageSize: Int64; FStream: TStream; FThreshold: Int64; FOnRequestBlankDisk : TAbRequestDiskEvent; protected {methods} procedure NewImage; public {methods} constructor Create( const ArchiveName: string; Stream: TStream; Threshold: Int64 ); destructor Destroy; override; function Read(var Buffer; Count: Longint): Longint; override; function Write(const Buffer; Count: Longint): Longint; override; function WriteUnspanned(const Buffer; Count: Longint; FailOnSpan: Boolean = False): Boolean; function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override; function ReleaseStream: TStream; public {properties} property CurrentImage : LongWord read FCurrentImage; public {events} property OnRequestBlankDisk : TAbRequestDiskEvent read FOnRequestBlankDisk write FOnRequestBlankDisk; end; implementation uses {$IFDEF MSWINDOWS} Windows, {$ENDIF} Math, RTLConsts, SysUtils, AbUtils, AbExcept; {============================================================================} { TAbSpanBaseStream implementation ========================================= } constructor TAbSpanBaseStream.Create( const ArchiveName: string ); begin inherited Create; FArchiveName := ArchiveName; end; {------------------------------------------------------------------------------} function TAbSpanBaseStream.GetImageName( ImageNumber: Integer ): string; var Abort : Boolean; Ext : string; begin {generate default name} Ext := ExtractFileExt(FArchiveName); if (Length(Ext) < 2) then Ext := '.' + Format('%.2d', [ImageNumber]) else Ext := Ext[1] + Ext[2] + Format('%.2d', [ImageNumber]); Result := ChangeFileExt(FArchiveName, Ext); {call event} if Assigned(FOnRequestImage) then begin Abort := False; FOnRequestImage(Self, ImageNumber, Result, Abort); if Abort then raise EAbUserAbort.Create; end; end; {============================================================================} { TAbSpanReadStream implementation ========================================= } constructor TAbSpanReadStream.Create( const ArchiveName: string; CurrentImage: LongWord; Stream: TStream ); begin inherited Create(ArchiveName); FCurrentImage := CurrentImage; FIsSplit := FileExists(GetImageName(1)) or not AbDriveIsRemovable(ArchiveName); FLastImage := CurrentImage; FStream := Stream; end; {------------------------------------------------------------------------------} destructor TAbSpanReadStream.Destroy; begin FreeAndNil(FStream); inherited; end; {------------------------------------------------------------------------------} procedure TAbSpanReadStream.GotoImage( ImageNumber: Integer ); var Abort: Boolean; ImageName: string; begin { switch to the requested image. ImageNumber is passed in as 0-based to match the zip spec, but all of the callbacks receive 1-based values. } FreeAndNil(FStream); FCurrentImage := ImageNumber; Inc(ImageNumber); ImageName := FArchiveName; if FIsSplit then begin { the last image uses the original filename } if FCurrentImage <> FLastImage then ImageName := GetImageName(ImageNumber) end else if Assigned(FOnRequestNthDisk) then begin Abort := False; repeat FOnRequestNthDisk(Self, ImageNumber, Abort); if Abort then raise EAbUserAbort.Create; until AbGetDriveFreeSpace(ImageName) <> -1; end else raise EAbUserAbort.Create; FStream := TFileStream.Create(ImageName, fmOpenRead or fmShareDenyWrite); end; {------------------------------------------------------------------------------} function TAbSpanReadStream.Read(var Buffer; Count: Longint): Longint; var BytesRead, BytesLeft: LongInt; PBuf: PByte; begin { read until the buffer's full, switching images if necessary } Result := 0; if FStream = nil then Exit; PBuf := @Buffer; BytesLeft := Count; while Result < Count do begin BytesRead := FStream.Read(PBuf^, BytesLeft); Inc(Result, BytesRead); Inc(PBuf, BytesRead); Dec(BytesLeft, BytesRead); if BytesRead < BytesLeft then begin if FCurrentImage <> FLastImage then GotoImage(FCurrentImage + 1) else Break; end; end; end; {------------------------------------------------------------------------------} function TAbSpanReadStream.Write(const Buffer; Count: Longint): Longint; begin raise EAbException.Create('TAbSpanReadStream.Write unsupported'); end; {------------------------------------------------------------------------------} function TAbSpanReadStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; begin if FStream = nil then Result := 0 else if (Offset = 0) and (Origin = soCurrent) then Result := FStream.Position else raise EAbException.Create('TAbSpanReadStream.Seek unsupported'); end; {------------------------------------------------------------------------------} procedure TAbSpanReadStream.SeekImage( Image: LongWord; const Offset: Int64); begin if FStream = nil then Exit; if FCurrentImage <> Image then GotoImage(Image); FStream.Position := Offset; end; {------------------------------------------------------------------------------} procedure TAbSpanReadStream.SetOnRequestImage(Value: TAbRequestImageEvent); begin FOnRequestImage := Value; FIsSplit := FileExists(GetImageName(1)) or not AbDriveIsRemovable(FArchiveName); end; {============================================================================} { TAbSpanWriteStream implementation ======================================== } constructor TAbSpanWriteStream.Create( const ArchiveName: string; Stream: TStream; Threshold: Int64 ); begin inherited Create(ArchiveName); FCurrentImage := 0; FStream := Stream; FThreshold := Threshold; end; {------------------------------------------------------------------------------} destructor TAbSpanWriteStream.Destroy; begin FStream.Free; inherited; end; {------------------------------------------------------------------------------} procedure TAbSpanWriteStream.NewImage; var Abort: Boolean; begin { start a new span or blank disk. FCurrentImage is 0-based to match the zip spec, but all of the callbacks receive 1-based values. } FreeAndNil(FStream); Inc(FCurrentImage); if FThreshold > 0 then RenameFile(FArchiveName, GetImageName(FCurrentImage)) else begin if Assigned(FOnRequestBlankDisk) then begin Abort := False; repeat FOnRequestBlankDisk(Self, Abort); if Abort then raise EAbUserAbort.Create; until AbGetDriveFreeSpace(FArchiveName) <> -1; end else raise EAbUserAbort.Create; AbSetSpanVolumeLabel(AbDrive(FArchiveName), FCurrentImage); end; FStream := TFileStream.Create(FArchiveName, fmCreate or fmShareDenyWrite); FImageSize := 0; end; {------------------------------------------------------------------------------} function TAbSpanWriteStream.Read(var Buffer; Count: Longint): Longint; begin raise EAbException.Create('TAbSpanWriteStream.Read unsupported'); end; {------------------------------------------------------------------------------} function TAbSpanWriteStream.Write(const Buffer; Count: Longint): Longint; var BytesWritten, BytesLeft: LongInt; PBuf: PByte; begin { write until the buffer is done, starting new spans if necessary } Result := 0; if FStream = nil then Exit; PBuf := @Buffer; BytesLeft := Count; while Result < Count do begin if FThreshold > 0 then BytesWritten := FStream.Write(PBuf^, Min(BytesLeft, FThreshold - FImageSize)) else BytesWritten := FStream.Write(PBuf^, BytesLeft); Inc(FImageSize, BytesWritten); Inc(Result, BytesWritten); Inc(PBuf, BytesWritten); Dec(BytesLeft, BytesWritten); if BytesWritten < BytesLeft then NewImage; end; end; {------------------------------------------------------------------------------} function TAbSpanWriteStream.WriteUnspanned(const Buffer; Count: Longint; FailOnSpan: Boolean = False): Boolean; var BytesWritten: LongInt; begin { write as a contiguous block, starting a new span if there isn't room. FailOnSpan (and result = false) can be used to update data before it's written again } if FStream = nil then raise EWriteError.Create(SWriteError); if (FThreshold > 0) and (FThreshold - FImageSize < Count) then BytesWritten := 0 else BytesWritten := FStream.Write(Buffer, Count); if BytesWritten < Count then begin if BytesWritten > 0 then FStream.Size := FStream.Size - BytesWritten; NewImage; if FailOnSpan then BytesWritten := 0 else begin BytesWritten := Count; FStream.WriteBuffer(Buffer, Count); end; end; Inc(FImageSize, BytesWritten); Result := (BytesWritten = Count); end; {------------------------------------------------------------------------------} function TAbSpanWriteStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; begin if FStream = nil then Result := 0 else if (Offset = 0) and (Origin = soCurrent) then Result := FStream.Position else raise EAbException.Create('TAbSpanWriteStream.Seek unsupported'); end; {------------------------------------------------------------------------------} function TAbSpanWriteStream.ReleaseStream: TStream; begin Result := FStream; FStream := nil; end; {------------------------------------------------------------------------------} end. ================================================ FILE: lib/abbrevia/source/AbTarTyp.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Joel Haynie * Craig Peterson * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbTarTyp.pas *} {*********************************************************} {* ABBREVIA: TAbTarArchive, TAbTarItem classes *} {*********************************************************} {* Misc. constants, types, and routines for working *} {* with Tar files *} {*********************************************************} unit AbTarTyp; {$I AbDefine.inc} interface uses Classes, AbUtils, AbArcTyp; const AB_TAR_RECORDSIZE = 512; {Note: SizeOf(TAbTarHeaderRec) = AB_TAR_RECORDSIZE} AB_TAR_NAMESIZE = 100; AB_TAR_V7_EMPTY_SIZE = 167; AB_TAR_USTAR_PREFIX_SIZE = 155; AB_TAR_STAR_PREFIX_SIZE = 131; AB_TAR_OLD_GNU_EMPTY1_SIZE = 5; AB_TAR_OLD_GNU_SPARSE_SIZE = 96; AB_TAR_OLD_GNU_EMPTY2_SIZE = 17; AB_TAR_SIZE_AFTER_STDHDR = 167; AB_TAR_TUSRNAMELEN = 32; AB_TAR_TGRPNAMELEN = 32; { The checksum field is filled with this while the checksum is computed. } AB_TAR_CHKBLANKS = ' '; { 8 blank spaces(#20), no null } AB_TAR_L_HDR_NAME = '././@LongLink'; { As seen in the GNU File Examples} AB_TAR_L_HDR_USR_NAME='root'; { On Cygwin this is #0, Redhat it is 'root' } AB_TAR_L_HDR_GRP_NAME='root'; { Same on all OS's } AB_TAR_L_HDR_ARR8_0 ='0000000'#0; { 7 zeros and one null } AB_TAR_L_HDR_ARR12_0 ='00000000000'#0;{ 11 zeros and one null } AB_TAR_MAGIC_VAL = 'ustar'#0; { 5 chars & a nul } AB_TAR_MAGIC_VER = '00'; { 2 chars } AB_TAR_MAGIC_GNUOLD = 'ustar '#0; { 7 chars & a null } AB_TAR_MAGIC_V7_NONE = #0#0#0#0#0#0#0#0;{ 8, #0 } { The linkflag defines the type of file(FH), and Meta Data about File(MDH) } AB_TAR_LF_OLDNORMAL = #0; { FH, Normal disk file, Unix compatible } { Historically used for V7 } AB_TAR_LF_NORMAL = '0'; { FH, Normal disk file } AB_TAR_LF_LINK = '1'; { FH, Link to previously archived file } AB_TAR_LF_SYMLINK = '2'; { FH, Symbolic(soft) link } AB_TAR_LF_CHR = '3'; { FH, Character special file }{ Used for device nodes, Conditionally compiled into GNUTAR } AB_TAR_LF_BLK = '4'; { FH, Block special file }{ Used for device nodes, Conditionally compiled into GNUTAR } AB_TAR_LF_DIR = '5'; { FH, Directory, Zero size File } AB_TAR_LF_FIFO = '6'; { FH, FIFO special file }{ Used for fifo files(pipe like), Conditionally complied into GNUTAR } AB_TAR_LF_CONTIG = '7'; { FH, Contiguous file } { Normal File, but All blocks should be contiguos on the disk } AB_TAR_LF_XHDR = 'x'; { MDH, POSIX, Next File has Extended Header } AB_TAR_LF_XGL = 'g'; { MDH, POSIX, Global Extended Header } AB_TAR_LF_DUMPDIR = 'D'; { FH, Extra GNU, Dump Directory} { Generated Dump of Files in a directory, has a size } AB_TAR_LF_LONGLINK = 'K'; { MDH, Extra GNU, Next File has Long LinkName} AB_TAR_LF_LONGNAME = 'L'; { MDH, Extra GNU, Next File has Long Name} AB_TAR_LF_MULTIVOL = 'M'; { FH, Extra GNU, MultiVolume File Cont.}{ End of a file that spans multiple TARs } AB_TAR_LF_SPARSE = 'S'; { FH, Extra GNU, Sparse File Cont.} AB_TAR_LF_VOLHDR = 'V'; { FH, Extra GNU, File is Volume Header } AB_TAR_LF_EXHDR = 'X'; { MDH, Extra GNU, Solaris Extended Header } { The only questionable MetaData type is 'V', file or meta-data? will treat as file header } AB_SUPPORTED_F_HEADERS = [AB_TAR_LF_OLDNORMAL, AB_TAR_LF_NORMAL, AB_TAR_LF_LINK, AB_TAR_LF_SYMLINK, AB_TAR_LF_DIR]; AB_UNSUPPORTED_F_HEADERS = [AB_TAR_LF_CHR, AB_TAR_LF_BLK, AB_TAR_LF_FIFO, AB_TAR_LF_CONTIG, AB_TAR_LF_DUMPDIR, AB_TAR_LF_MULTIVOL, AB_TAR_LF_SPARSE, AB_TAR_LF_VOLHDR]; AB_SUPPORTED_MD_HEADERS = [AB_TAR_LF_LONGNAME, AB_TAR_LF_LONGLINK]; AB_UNSUPPORTED_MD_HEADERS= [AB_TAR_LF_XHDR, AB_TAR_LF_XGL, AB_TAR_LF_EXHDR]; AB_GNU_MD_HEADERS = [AB_TAR_LF_LONGLINK, AB_TAR_LF_LONGNAME]; { If present then OLD_/GNU_FORMAT } AB_PAX_MD_HEADERS = [AB_TAR_LF_XHDR, AB_TAR_LF_XGL]; { If present then POSIX_FORMAT } AB_IGNORE_SIZE_HEADERS = [AB_TAR_LF_LINK, AB_TAR_LF_SYMLINK, AB_TAR_LF_CHR, AB_TAR_LF_BLK, AB_TAR_LF_DIR, AB_TAR_LF_FIFO]; { The rest of the Chars are unsupported and unknown types Treat those headers as File types } { Further link types may be defined later. } { Bits used in the mode field - values in octal } AB_TAR_TSUID = $0800; { Set UID on execution } AB_TAR_TSGID = $0400; { Set GID on execution } AB_TAR_TSVTX = $0200; { Save text (sticky bit) } type Arr8 = array [0..7] of AnsiChar; Arr12 = array [0..11] of AnsiChar; Arr12B = array[0..11] of Byte; ArrName = array [0..AB_TAR_NAMESIZE-1] of AnsiChar; TAbTarHeaderFormat = (UNKNOWN_FORMAT, V7_FORMAT, OLDGNU_FORMAT, GNU_FORMAT, USTAR_FORMAT, STAR_FORMAT, POSIX_FORMAT); TAbTarItemType = (SUPPORTED_ITEM, UNSUPPORTED_ITEM, UNKNOWN_ITEM); TAbTarHeaderType = (FILE_HEADER, META_DATA_HEADER, MD_DATA_HEADER, UNKNOWN_HEADER); TAbTarMagicType = (GNU_OLD, NORMAL); TAbTarMagicRec = packed record case TAbTarMagicType of GNU_OLD: (gnuOld : array[0..7] of AnsiChar); { Old GNU magic: (Magic.gnuOld) } NORMAL : (value : array[0..5] of AnsiChar; { Magic value: (Magic.value)} version: array[0..1] of AnsiChar); { Version: (Magic.version) } end; { Notes from GNU Tar & POSIX Spec.: } {All the first 345 bytes are the same. } { "USTAR_header": Prefix(155): 345-499, empty(12): 500-511 } { "old_gnu_header": atime(12): 345-356, ctime(12): 357-368, offset(12): 369-380, longnames(4): 381-384, empty(1): 385, sparse structs(4x(12+12)=96): 386-481, isextended(1): 482, realsize(12): 483-494, empty(16): 495-511 } { "star_header": Prefix(131): 345-475, atime(12): 476-487, ctime(12): 488-499, empty(12): 500-511 } { "star_in_header": prefix(1): 345, empty(9): 346-354, isextended(1): 355, sparse structs(4x(12+12)=96): 356-451, realsize(12): 452-463, offset(12): 464-475, atime(12): 476-487, ctime(12): 488-499, empty(8): 500-507, xmagic(4): 508-511 } { "sparse_header": These two structs are the same, and they are Meta data about file. } {"star_ext_header": sparse structs(21x(12+12)=504): 0-503, isextended(1): 504 } {POSIX(PAX) extended header: is a buffer packed with content of this form: This if from the POSIX spec. References the C printf command string. "%d %s=%s\n". Then they are simply concatenated. } { PAX Extended Header Keywords: } { 'atime', 'charset', 'comment', 'ctime', 'gid', 'gname', 'linkpath', 'mtime', 'path', 'realtime.', 'security.', 'size', 'uid', 'uname' } { GNU Added PAX Extended Header Keywords: } { 'GNU.sparse.name', 'GNU.sparse.major', 'GNU.sparse.minor', 'GNU.sparse.realsize', 'GNU.sparse.numblocks', 'GNU.sparse.size', 'GNU.sparse.offset', 'GNU.sparse.numbytes', 'GNU.sparse.map', 'GNU.dumpdir', 'GNU.volume.label', 'GNU.volume.filename', 'GNU.volume.size', 'GNU.volume.offset' } { V7 uses AB_TAR_LF_OLDNORMAL linkflag, has no magic field & no Usr/Grp Names } { V7 Format ends Empty(padded with zeros), as does the POSIX record. } TAbTarEnd_Empty_Rec = packed record Empty: array[0..AB_TAR_V7_EMPTY_SIZE-1] of Byte; { 345-511, $159-1FF, Empty Space } end; { UStar End Format } TAbTarEnd_UStar_Rec = packed record Prefix: array[0..AB_TAR_USTAR_PREFIX_SIZE-1] of AnsiChar; { 345-499, $159-1F3, Prefix of file & path name, null terminated ASCII string } Empty : Arr12B;{ 500-512, $1F4-1FF, Empty Space } end; { Old GNU End Format } TAbTarEnd_GNU_old_Rec = packed record Atime : Arr12; { 345-356, $159-164, time of last access (UNIX Date in ASCII coded Octal)} Ctime : Arr12; { 357-368, $165-170, time of last status change (UNIX Date in ASCII coded Octal)} Offset: Arr12; { 369-380, $171-17C, Multirecord specific value } Empty1: array[0..AB_TAR_OLD_GNU_EMPTY1_SIZE-1] of Byte; { 381-385, $17D-181, Empty Space, Once contained longname ref. } Sparse: array[0..AB_TAR_OLD_GNU_SPARSE_SIZE-1] of Byte; { 386-481, $182-1E1, Sparse File specific values } IsExtended: byte;{ 482, $ 1E2, Flag to signify Sparse file headers follow } RealSize: Arr12;{ 483-494, $1E3-1EE, Real size of a Sparse File. } Empty2: array[0..AB_TAR_OLD_GNU_EMPTY2_SIZE-1] of Byte; { 495-511, $1EF-1FF, Empty Space } end; { Star End Format } TAbTarEnd_Star_Rec = packed record Prefix: array[0..AB_TAR_STAR_PREFIX_SIZE-1] of AnsiChar; { 345-499, $159-1F3, prefix of file & path name, null terminated ASCII string } Atime : Arr12; { 476-487, $1DC-1E7, time of last access (UNIX Date in ASCII coded Octal)} Ctime : Arr12; { 488-499, $1E8-1F3, time of last status change (UNIX Date in ASCII coded Octal)} Empty : Arr12B;{ 500-512, $1F4-1FF, Empty Space } end; { When support for sparse files is added, Add another record for sparse in header } { Note: SizeOf(TAbTarHeaderRec) = AB_TAR_RECORDSIZE by design } PAbTarHeaderRec = ^TAbTarHeaderRec; { Declare pointer type for use in the list } TAbTarHeaderRec = packed record Name : ArrName; { 0- 99, $ 0- 63, filename, null terminated ASCII string, unless length is 100 } Mode : Arr8; { 100-107, $ 64- 6B, file mode (UNIX style, ASCII coded Octal) } uid : Arr8; { 108-115, $ 6C- 73, usrid # (UNIX style, ASCII coded Octal) } gid : Arr8; { 116-123, $ 74- 7B, grpid # (UNIX style, ASCII coded Octal) } Size : Arr12; { 124-135, $ 7C- 87, size of TARred file (ASCII coded Octal) } ModTime : Arr12; { 136-147, $ 88- 93, time of last modification.(UNIX Date in ASCII coded Octal) UTC time } ChkSum : Arr8; { 148-155, $ 94- 9B, checksum of header (6 bytes ASCII coded Octal, #00, #20) } LinkFlag: AnsiChar; { 156, $ 9C, type of item, one of the Link Flag constants from above } LinkName: ArrName; { 157-256, $ 9D-100, name of link, null terminated ASCII string } Magic : TAbTarMagicRec; { 257-264, $101-108, identifier, usually 'ustar'#00'00' } UsrName : array [0..AB_TAR_TUSRNAMELEN-1] of AnsiChar; { 265-296, $109-128, username, null terminated ASCII string } GrpName : array [0..AB_TAR_TGRPNAMELEN-1] of AnsiChar; { 297-328, $129-148, groupname, null terminated ASCII string } DevMajor: Arr8; { 329-336, $149-150, major device ID (UNIX style, ASCII coded Octal) } DevMinor: Arr8; { 337-344, $151-158, minor device ID (UNIX style, ASCII coded Octal) } case TAbTarHeaderFormat of{ 345-511, $159-1FF See byte Definitions above.} V7_FORMAT : ( v7 : TAbTarEnd_Empty_Rec ); OLDGNU_FORMAT: ( gnuOld: TAbTarEnd_GNU_old_Rec ); GNU_FORMAT : ( gnu : TAbTarEnd_GNU_old_Rec ); USTAR_FORMAT : ( ustar : TAbTarEnd_UStar_Rec ); STAR_FORMAT : ( star : TAbTarEnd_Star_Rec ); POSIX_FORMAT : ( pax : TAbTarEnd_Empty_Rec ); end;{ end TAbTarHeaderRec } { There are three main types of headers we will see in a Tar file } { TAbTarHeaderType = (STANDARD_HDR, SPARSE_HDR, POSIX_EXTENDED_HDR); } { The 1st is defined above, The later two are simply organized data types. } TAbTarItemRec = record { Note: that the actual The name needs to be coherient with the name Inherited from parent type TAbArchiveItem } Name : string; { Path & File name. } Mode : LongWord; { File Permissions } uid : Integer; { User ID } gid : Integer; { Group ID } Size : Int64; { Tared File size } ModTime : Int64; { Last time of Modification, in UnixTime } ChkSumPass : Boolean; { Header Check sum found to be good } LinkFlag : AnsiChar; { Link Flag, Echos the actual File Type of this Item. } ItemType : TAbTarItemType; { Item Type Assigned from LinkFlag Header Types. } LinkName : string; { Link Name } Magic : AnsiString; { Magic value } Version : Integer; { Version Number } UsrName : string; { User Name, for User ID } GrpName : string; { Group Name, for Group ID } DevMajor : Integer; { Major Device ID } DevMinor : Integer; { Minor Device ID } { Additional Types used for holding info. } AccessTime : Int64; { Time of Last Access, in UnixTime } ChangeTime : Int64; { Time of Last Status Change, in UnixTime } ArchiveFormat: TAbTarHeaderFormat; { Type of Archive of this record } StreamPosition: Int64; { Pointer to the top of the item in the file. } Dirty : Boolean; { Indication if this record needs to have its headers CheckSum recalculated } ItemReadOnly: Boolean; { Indication if this record is READ ONLY } FileHeaderCount:Integer;{ Number of Headers in the Orginal TarHeaders in the File Stream } end; type PTAbTarItem = ^TAbTarItem; TAbTarItem = class(TAbArchiveItem) private { The following private members are used for Stuffing FTarItem struct } procedure ParseTarHeaders; { Error in header if } procedure DetectHeaderFormat; { Helper to stuff HeaderFormat } procedure GetFileNameFromHeaders; { Helper to pull name from Headers } procedure GetLinkNameFromHeaders; { Helper to pull name from Headers } function TestCheckSum: Boolean; { Helper to Calculate Checksum of a header. } procedure DoGNUExistingLongNameLink(LinkFlag: AnsiChar; I: Integer; const Value: AnsiString); procedure DoGNUNewLongNameLink(LinkFlag: AnsiChar; I: Integer; const Value: AnsiString); protected {private} PTarHeader: PAbTarHeaderRec;{ Points to FTarHeaderList.Items[FTarHeaderList.Count-1] } FTarHeaderList: TList; { List of The Headers } FTarHeaderTypeList: TList; { List of the Header Types } FTarItem: TAbTarItemRec; { Data about current TAR Item } protected function GetDevMajor: Integer; function GetDevMinor: Integer; function GetGroupID: Integer; function GetGroupName: string; function GetLinkName: string; function GetUserID: Integer; function GetUserName: string; function GetModTime: Int64; function GetNumHeaders: Integer; function GetMagic: string; { All Sets shall update the headers Or add headers as needed. } procedure SetDevMajor(const Value: Integer); procedure SetDevMinor(const Value: Integer); procedure SetGroupID(const Value: Integer); { Extended Headers } procedure SetGroupName(const Value: string); { Extended Headers } procedure SetLinkFlag(Value: AnsiChar); procedure SetLinkName(const Value: string); { Extended Headers } procedure SetUserID(const Value: Integer); { Extended Headers } procedure SetUserName(const Value: string); { Extended Headers } procedure SetModTime(const Value: Int64); Procedure SetMagic(const Value: string); { TODO: add support for Atime and Ctime here } { Overrides for Inherited Properties from type TAbArchiveItem } function GetCompressedSize : Int64; override; function GetExternalFileAttributes : LongWord; override; function GetFileName : string; override; function GetIsDirectory: Boolean; override; function GetIsEncrypted : Boolean; override; function GetLastModFileDate : Word; override; function GetLastModFileTime : Word; override; function GetLastModTimeAsDateTime: TDateTime; override; function GetNativeFileAttributes : LongInt; override; function GetUncompressedSize : Int64; override; procedure SetCompressedSize(const Value : Int64); override; { Extended Headers } procedure SetExternalFileAttributes( Value : LongWord ); override; procedure SetFileName(const Value : string); override; { Extended Headers } procedure SetIsEncrypted(Value : Boolean); override; procedure SetLastModFileDate(const Value : Word); override; { Extended Headers } procedure SetLastModFileTime(const Value : Word); override; { Extended Headers } procedure SetLastModTimeAsDateTime(const Value: TDateTime); override; procedure SetUncompressedSize(const Value : Int64); override; { Extended Headers } procedure SaveTarHeaderToStream(AStream : TStream); procedure LoadTarHeaderFromStream(AStream : TStream); property Magic : string { Magic value } read GetMagic write SetMagic; public { property Name : STRING; Path & File name. Inherited from parent type TAbArchiveItem } { read GetFileName write SetFileName; overridden above} property Mode : LongWord { File Permissions } read GetExternalFileAttributes write SetExternalFileAttributes; property UserID : Integer { User ID } read GetUserID write SetUserID; property GroupID : Integer { Group ID } read GetGroupID write SetGroupID; property ModTime : Int64 read GetModTime write SetModTime; { property UncompressedSize/CompressedSize(Size): Int64; File size (comp/uncomp) Inherited from parent type TAbArchiveItem } { read GetUncompressedSize, GetCompressedSize; overridden above } { write SetUncompressedSize, SetCompressedSize; overridden above } { property LastModFileTime/LastModFileDate(ModeTime): TDateTime; Last time of Modification Inherited from parent type TAbArchiveItem } { read GetLastModFileTime, GetLastModFileDate; overridden above } { write SetLastModFileTime, SetLastModFileDate; overridden above } property CheckSumGood: Boolean read FTarItem.ChkSumPass; { Header Check sum found to be good } property LinkFlag : AnsiChar { Link Flag of File Header } read FTarItem.LinkFlag write SetLinkFlag; property LinkName : string { Link Name } read GetLinkName write SetLinkName; property UserName : string { User Name, for User ID } read GetUserName write SetUserName; property GroupName : string { Group Name, for Group ID } read GetGroupName write SetGroupName; property DevMajor : Integer { Major Device ID } read GetDevMajor write SetDevMajor; property DevMinor : Integer { Minor Device ID } read GetDevMinor write SetDevMinor; { TODO: Add support ATime and CTime } {AccessTime : TDateTime;} { Time of Last Access } {ChangeTime : TDateTime;} { Time of Last Status Change } { Additional Types used for holding info. } property ExternalFileAttributes; property ArchiveFormat: TAbTarHeaderFormat read FTarItem.ArchiveFormat write FTarItem.ArchiveFormat; property ItemType: TAbTarItemType read FTarItem.ItemType write FTarItem.ItemType; property ItemReadOnly: Boolean read FTarItem.ItemReadOnly write FTarItem.ItemReadOnly; property FileHeaderCount: Integer read FTarItem.FileHeaderCount; property HeaderCount: Integer read GetNumHeaders; property StreamPosition: Int64 read FTarItem.StreamPosition write FTarItem.StreamPosition; constructor Create; destructor Destroy; override; end; { end TAbArchiveItem } TAbTarStreamHelper = class(TAbArchiveStreamHelper) private function FindItem: Boolean; { Tool for FindFirst/NextItem functions } protected FTarHeader : TAbTarHeaderRec; { Speed-up Buffer only } FCurrItemSize : Int64; { Current Item size } FCurrItemPreHdrs: Integer; { Number of Meta-data Headers before the Item } public destructor Destroy; override; procedure ExtractItemData(AStream : TStream); override; function FindFirstItem : Boolean; override; function FindNextItem : Boolean; override; procedure ReadHeader; override; procedure ReadTail; override; function SeekItem(Index : Integer): Boolean; override; procedure WriteArchiveHeader; override; procedure WriteArchiveItem(AStream : TStream); override; procedure WriteArchiveItemSize(AStream : TStream; Size: Int64); procedure WriteArchiveTail; override; function GetItemCount : Integer; override; end; TAbTarArchive = class(TAbArchive) private FArchReadOnly : Boolean; FArchFormat: TAbTarHeaderFormat; protected function CreateItem(const FileSpec : string): TAbArchiveItem; override; procedure ExtractItemAt(Index : Integer; const UseName : string); override; procedure ExtractItemToStreamAt(Index : Integer; aStream : TStream); override; procedure LoadArchive; override; procedure SaveArchive; override; procedure TestItemAt(Index : Integer); override; function FixName(const Value: string): string; override; function GetSupportsEmptyFolders: Boolean; override; function GetItem(Index: Integer): TAbTarItem; procedure PutItem(Index: Integer; const Value: TAbTarItem); public {methods} constructor CreateFromStream(aStream : TStream; const aArchiveName : string); override; property UnsupportedTypesDetected : Boolean read FArchReadOnly; property Items[Index : Integer] : TAbTarItem read GetItem write PutItem; default; end; function VerifyTar(Strm : TStream) : TAbArchiveType; implementation uses {$IFDEF MSWINDOWS} Windows, // Fix inline warnings {$ENDIF MSWINDOWS} Math, RTLConsts, SysUtils, {$IFDEF HasAnsiStrings}AnsiStrings, {$ENDIF} AbCharset, AbVMStrm, AbExcept; { ****************** Helper functions Not from Classes Above ***************** } function OctalToInt(const Oct : PAnsiChar; aLen : integer): Int64; var i : integer; begin Result := 0; i := 0; while (i < aLen) and (Oct[i] = ' ') do inc(i); if (i = aLen) then Exit; while (i < aLen) and (Oct[i] in ['0'..'7']) do begin Result := (Result * 8) + (Ord(Oct[i]) - Ord('0')); inc(i); end; end; function IntToOctal(Value : Int64): AnsiString; const OctDigits : array[0..7] of AnsiChar = '01234567'; begin if Value = 0 then Result := '0' else begin Result := ''; while Value > 0 do begin Result := OctDigits[Value and 7] + Result; Value := Value shr 3; end; end; end; function CalcTarHeaderChkSum(const TarH : TAbTarHeaderRec): LongInt; var HdrBuffer : PAnsiChar; HdrChkSum : LongInt; j : Integer; begin { prepare for the checksum calculation } HdrBuffer := PAnsiChar(@TarH); HdrChkSum := 0; {calculate the checksum, a simple sum of the bytes in the header} for j := 0 to Pred(SizeOf(TAbTarHeaderRec)) do HdrChkSum := HdrChkSum + Ord(HdrBuffer[j]); Result := HdrChkSum; end; function VerifyTar(Strm : TStream) : TAbArchiveType; { assumes Tar positioned correctly for test of item } var TarItem : TAbTarItem; StartPos : Int64; begin StartPos := Strm.Position; try { Verifies that the header checksum is valid, and Item type is understood. This does not mean that extraction is supported. } TarItem := TAbTarItem.Create; try { get current Tar Header } TarItem.LoadTarHeaderFromStream(Strm); if TarItem.CheckSumGood then Result := atTar else Result := atUnknown; finally TarItem.Free; end; except on EReadError do Result := atUnknown; end; Strm.Position := StartPos; end; function PadString(const S : AnsiString; Places : Integer) : AnsiString; { Pads a string (S) with one right space and as many left spaces as needed to fill Places If length S greater than Places, just returns S Some TAR utilities evidently expect Octal numeric fields to be in this format } begin if Length(S) >= LongInt(Places) then Result := S else begin Result := S + ' '; Result := StringOfChar(AnsiChar(' '), Places - Length(Result)) + Result; end; end; { Round UP to the nearest Tar Block Boundary. } function RoundToTarBlock(Size: Int64) : Int64; begin Result := (Size + (AB_TAR_RECORDSIZE - 1)) and not (AB_TAR_RECORDSIZE - 1); end; { ****************************** TAbTarItem ********************************** } constructor TAbTarItem.Create; begin inherited Create; FTarHeaderList := TList.Create; FTarHeaderTypeList := TList.Create; GetMem(PTarHeader, AB_TAR_RECORDSIZE); { PTarHeader is our new Header } FillChar(PTarHeader^, AB_TAR_RECORDSIZE, #0); FTarHeaderList.Add(PTarHeader); FTarHeaderTypeList.Add(Pointer(FILE_HEADER)); FTarItem.FileHeaderCount := 1; { set defaults } FTarItem.ArchiveFormat := UNKNOWN_FORMAT; FileName := ''; Mode := AB_FPERMISSION_GENERIC; UserID := 0; GroupID := 0; UncompressedSize := 0; { ModTime } LinkFlag := AB_TAR_LF_OLDNORMAL; { Link Name } PTarHeader.Magic.gnuOld := AB_TAR_MAGIC_V7_NONE; { Default to GNU type } UserName := ''; GroupName := ''; DevMajor := 0; DevMinor := 0; { TODO: atime, ctime } FTarItem.ItemType := SUPPORTED_ITEM; FTarItem.Dirty := True; { Checksum needs to be generated } FTarItem.ItemReadOnly := False; end; destructor TAbTarItem.Destroy; var i : Integer; begin if Assigned(FTarHeaderList) then begin for i := 0 to FTarHeaderList.Count - 1 do FreeMem(FTarHeaderList.Items[i]); { This list holds PAbTarHeaderRec's } FTarHeaderList.Free; end; FTarHeaderTypeList.Free; inherited Destroy; end; function TAbTarItem.GetCompressedSize: Int64; { TAR includes no internal compression, returns same value as GetUncompressedSize } begin Result := FTarItem.Size; end; function TAbTarItem.GetDevMajor: Integer; begin Result := FTarItem.DevMajor; end; function TAbTarItem.GetDevMinor: Integer; begin Result := FTarItem.DevMinor; end; function TAbTarItem.GetExternalFileAttributes: LongWord; begin Result := FTarItem.Mode; end; function TAbTarItem.GetFileName: string; begin Result := FTarItem.Name; { Inherited String from Parent Class } end; function TAbTarItem.GetGroupID: Integer; begin Result := FTarItem.gid; end; function TAbTarItem.GetGroupName: string; begin Result := FTarItem.GrpName; end; function TAbTarItem.GetIsDirectory: Boolean; begin Result := (LinkFlag = AB_TAR_LF_DIR); end; function TAbTarItem.GetIsEncrypted: Boolean; begin { TAR has no native encryption } Result := False; end; function TAbTarItem.GetLastModFileDate: Word; begin { convert to local DOS file Date } Result := LongRec(AbDateTimeToDosFileDate(LastModTimeAsDateTime)).Hi; end; function TAbTarItem.GetLastModFileTime: Word; begin { convert to local DOS file Time } Result := LongRec(AbDateTimeToDosFileDate(LastModTimeAsDateTime)).Lo; end; function TAbTarItem.GetLastModTimeAsDateTime: TDateTime; begin Result := AbUnixTimeToLocalDateTime(FTarItem.ModTime); end; function TAbTarItem.GetLinkName: string; begin Result := FTarItem.LinkName; end; function TAbTarItem.GetMagic: string; begin Result := string(FTarItem.Magic); end; function TAbTarItem.GetNativeFileAttributes : LongInt; begin Result := GetExternalFileAttributes; {$IFDEF MSWINDOWS} Result := AbUnix2DosFileAttributes(Result); {$ENDIF} end; function TAbTarItem.GetUncompressedSize: Int64; { TAR includes no internal compression, returns same value as GetCompressedSize } begin Result := FTarItem.Size; end; function TAbTarItem.GetUserID: Integer; begin Result := FTarItem.uid; end; function TAbTarItem.GetUserName: string; begin Result := FTarItem.UsrName; end; function TAbTarItem.GetModTime: Int64; begin Result := FTarItem.ModTime; end; { Get Number of tar headers currently for this item } function TAbTarItem.GetNumHeaders: Integer; begin Result := FTarHeaderList.Count; end; { Takes data from Supported Header types stored in TAbTarItem.FTarHeaderList } { and updates values in the TAbTarItem.FTarItem.X } procedure TAbTarItem.DetectHeaderFormat; begin if FTarItem.ArchiveFormat <> UNKNOWN_FORMAT then Exit;{ We have already set the format. } { In the previous header parsing if pax headers are detected the format is changed } { GNU_FORMAT is detected by the presence of GNU extended headers. } { These detections are similar to GNU tar's. } if (PTarHeader.Magic.value = AB_TAR_MAGIC_VAL) then begin { We have one of three types, STAR_FORMAT, USTAR_FORMAT, POSIX_FORMAT } { Detect STAR format. Leave disabled until explicit STAR support is added. } {if (PTarHeader.star.Prefix[130] = #00) and (PTarHeader.star.Atime[0] in ['0'..'7']) and (PTarHeader.star.Atime[11] = #20) and (PTarHeader.star.Ctime[0]in ['0'..'7']) and (PTarHeader.star.Ctime[11] = #20) then begin FTarItme.ArchiveType := STAR_FORMAT; end } { else if } { POSIX uses the existance of x headers } { This can define false positives, Pax headers/ STAR format could be detected as this } FTarItem.ArchiveFormat := USTAR_FORMAT; end else if (PTarHeader.Magic.gnuOld = AB_TAR_MAGIC_GNUOLD) then begin FTarItem.ArchiveFormat := OLDGNU_FORMAT; end else { V7 uses AB_TAR_LF_OLDNORMAL linkflag, has no magic field & no Usr/Grp Names } begin FTarItem.ArchiveFormat := V7_FORMAT; { Lowest Common Denominator } end; end; { Extract the file name from the headers } procedure TAbTarItem.GetFileNameFromHeaders; var I, J : Integer; PHeader: PAbTarHeaderRec; FoundName: Boolean; NameLength : Int64; NumMHeaders: integer; ExtraName: integer; RawFileName, TempStr: AnsiString; begin { UNKNOWN_FORMAT, V7_FORMAT, OLDGNU_FORMAT, GNU_FORMAT, USTAR_FORMAT, STAR_FORMAT, POSIX_FORMAT } FoundName := False; I := 0; while (not FoundName) and (I <= (FTarHeaderList.Count - 1)) do begin PHeader := FTarHeaderList.Items[I]; if PHeader.LinkFlag = AB_TAR_LF_LONGNAME then begin FoundName := True; RawFileName := ''; NameLength := OctalToInt(PHeader.Size, SizeOf(PHeader.Size)); NumMHeaders := NameLength div AB_TAR_RECORDSIZE; ExtraName := NameLength mod AB_TAR_RECORDSIZE; { Chars in the last Header } { NumMHeaders should never be zero } { It appears that it is not null terminated in the blocks } for J := 1 to NumMHeaders do begin { Copy entire content of Header to String } PHeader := FTarHeaderList.Items[I+J]; SetString(TempStr, PAnsiChar(PHeader), AB_TAR_RECORDSIZE); RawFileName := RawFileName + TempStr; end; if ExtraName <> 0 then begin PHeader := FTarHeaderList.Items[I+NumMHeaders+1]; SetString(TempStr, PAnsiChar(PHeader), ExtraName-1); RawFileName := RawFileName + TempStr; end else { We already copied the entire name, but the string is still null terminated. } begin { Removed the last zero } SetLength(RawFileName, (Length(RawFileName)-1)); end; end { end long filename link flag } else I := I + 1; end; { End While } if not FoundName then begin if (FTarItem.ArchiveFormat = USTAR_FORMAT) and (PTarHeader.ustar.Prefix[0] <> #0) then RawFileName := PTarHeader.ustar.Prefix+'/'+PTarHeader.Name else { V7_FORMAT, OLDGNU_FORMAT } RawFileName := PTarHeader.Name; end; { End not FoundName } FTarItem.Name := AbRawBytesToString(RawFileName); end; { Extract the file name from the headers } procedure TAbTarItem.GetLinkNameFromHeaders; var I, J : Integer; PHeader: PAbTarHeaderRec; FoundName: Boolean; NameLength : Int64; NumMHeaders: integer; ExtraName: integer; RawLinkName, TempStr: AnsiString; begin { UNKNOWN_FORMAT, V7_FORMAT, OLDGNU_FORMAT, GNU_FORMAT, USTAR_FORMAT, STAR_FORMAT, POSIX_FORMAT } PHeader := nil; FoundName := False; I := 0; { Note that: FTarHeaderList.Count <= 1, always } while (not FoundName) and (I <= (FTarHeaderList.Count - 1)) do begin PHeader := FTarHeaderList.Items[I]; if PHeader.LinkFlag = AB_TAR_LF_LONGLINK then begin FoundName := True; RawLinkName := ''; NameLength := OctalToInt(PHeader.Size, SizeOf(PHeader.Size)); NumMHeaders := NameLength div AB_TAR_RECORDSIZE; ExtraName := NameLength mod AB_TAR_RECORDSIZE; { Chars in the last Header } { NumMHeaders should never be zero } { It appears that it is not null terminated in the blocks } for J := 1 to NumMHeaders do begin { Copy entire content of Header to String } PHeader := FTarHeaderList.Items[I+J]; SetString(TempStr, PAnsiChar(PHeader), AB_TAR_RECORDSIZE); RawLinkName := RawLinkName + TempStr; end; if ExtraName <> 0 then begin PHeader := FTarHeaderList.Items[I+NumMHeaders+1]; SetString(TempStr, PAnsiChar(PHeader), ExtraName-1); RawLinkName := RawLinkName + TempStr; end else { We already copied the entire name, but the string is still null terminated. } begin { Removed the last zero } SetLength(RawLinkName, (Length(RawLinkName)-1)); end; end { end long filename link flag } else I := I + 1; end; { End While } if not FoundName then RawLinkName := PHeader.LinkName; FTarItem.LinkName := AbRawBytesToString(RawLinkName); end; { Return True if CheckSum passes out. } function TAbTarItem.TestCheckSum : Boolean; var TarChkSum : LongInt; TarChkSumArr : Arr8; { ChkSum field is Arr8 } PHeader: PAbTarHeaderRec; I: Integer; begin Result := True; { Check sums are in valid headers but NOT in the data headers. } for I := 0 to FTarHeaderList.Count - 1 do begin if TAbTarHeaderType(FTarHeaderTypeList.Items[I]) in [FILE_HEADER, META_DATA_HEADER] then begin PHeader := FTarHeaderList.Items[i]; { Save off old Check sum } Move(PHeader.ChkSum, TarChkSumArr, SizeOf(PHeader.ChkSum)); TarChkSum := OctalToInt(TarChkSumArr, SizeOf(TarChkSumArr)); { Set to Generator Value } PHeader.ChkSum := AB_TAR_CHKBLANKS; if CalcTarHeaderChkSum(PHeader^) <> TarChkSum then Result := False; { Pass unless one miss-compares } { Save back old checksum } Move(TarChkSumArr, PHeader.ChkSum, SizeOf(TarChkSumArr)); end; end; end; procedure TAbTarItem.ParseTarHeaders; begin { The final index is the Item index } DetectHeaderFormat; { Long term this parsing is not correct, as the values in extended headers override the later values in this header } FTarItem.Mode := OctalToInt(PTarHeader.Mode, SizeOf(PTarHeader.Mode)); FTarItem.uid := OctalToInt(PTarHeader.uid, SizeOf(PTarHeader.uid)); { Extended in PAX Headers } FTarItem.gid := OctalToInt(PTarHeader.gid, SizeOf(PTarHeader.gid)); { Extended in PAX Headers } FTarItem.Size := OctalToInt(PTarHeader.Size, SizeOf(PTarHeader.Size)); { Extended in PAX Headers } { ModTime should be an Int64 but no tool support, No issues until Feb 6th, 2106 :) } { ModTime is Extended in PAX Headers } FTarItem.ModTime := OctalToInt(PTarHeader.ModTime, SizeOf(PTarHeader.ModTime)); FTarItem.ChkSumPass := TestCheckSum(); FTarItem.LinkFlag := PTarHeader.LinkFlag; GetLinkNameFromHeaders; { Extended in PAX Headers } FTarItem.Magic := PTarHeader.Magic.value; FTarItem.Version := OctalToInt(PTarHeader.Magic.version, SizeOf(PTarHeader.Magic.version)); FTarItem.UsrName := string(PTarHeader.UsrName); { Extended in PAX Headers } FTarItem.GrpName := string(PTarHeader.GrpName); { Extended in PAX Headers } FTarItem.DevMajor := OctalToInt(PTarHeader.DevMajor, SizeOf(PTarHeader.DevMajor)); FTarItem.DevMinor := OctalToInt(PTarHeader.DevMinor, SizeOf(PTarHeader.DevMinor)); GetFileNameFromHeaders; { FTarItem.ArchiveFormat; Already stuffed } { FTarItem.StreamPosition: Already Stuffed } { FTarItem.Dirty; Stuffed upon creaction } end; procedure TAbTarItem.LoadTarHeaderFromStream(AStream: TStream); var NumMHeaders : Integer; I : Integer; FoundItem : Boolean; begin { Note: The SizeOf(TAbTarHeaderRec) = AB_TAR_RECORDSIZE } { We should expect FindNext/FirstItem, and next check for bounds. } if FTarHeaderList.Count > 0 then begin { We're Going to stomp over the headers that are already present } { We need to destory the memory we've used } PTarHeader := nil; for i := 0 to FTarHeaderList.Count - 1 do FreeMem(FTarHeaderList.Items[i]); { This list holds PAbTarHeaderRec's } FTarHeaderList.Clear; FTarHeaderTypeList.Clear; FTarItem.FileHeaderCount := 0; { All pointers should now be removed from those headers } end; { Now lets start filling up that list. } FTarItem.ItemType := UNKNOWN_ITEM; { We don't know what we have yet } FoundItem := False; while not FoundItem do begin { Create a Header to be Stored in the Items List } GetMem(PTarHeader, AB_TAR_RECORDSIZE); AStream.ReadBuffer(PTarHeader^, AB_TAR_RECORDSIZE); FTarHeaderList.Add(PTarHeader); { Store the Header to the list } { Parse header based on LinkFlag } if PTarHeader.LinkFlag in (AB_SUPPORTED_MD_HEADERS+AB_UNSUPPORTED_MD_HEADERS) then begin { This Header type is in the Set of un/supported Meta data type headers } if PTarHeader.LinkFlag in AB_UNSUPPORTED_MD_HEADERS then FTarItem.ItemReadOnly := True; { We don't fully support this meta-data type } if (PTarHeader.LinkFlag in AB_PAX_MD_HEADERS) and (PTarHeader.Magic.value = AB_TAR_MAGIC_VAL) then FTarItem.ArchiveFormat := POSIX_FORMAT; { We have a POSIX_FORMAT, has x headers, and Magic matches } if PTarHeader.LinkFlag in AB_GNU_MD_HEADERS then FTarItem.ArchiveFormat := OLDGNU_FORMAT; { We have a OLDGNU_FORMAT, has L/K headers } { There can be a unknown number of Headers of data } { We are for sure going to read at least one more header, but are we going to read more than that? } FTarHeaderTypeList.Add(Pointer(META_DATA_HEADER)); NumMHeaders := Ceil(OctalToInt(PTarHeader.Size, SizeOf(PTarHeader.Size)) / AB_TAR_RECORDSIZE); { NumMHeasder should never be zero } for I := 1 to NumMHeaders do begin GetMem(PTarHeader, AB_TAR_RECORDSIZE); { Create a new Header } AStream.ReadBuffer(PTarHeader^, AB_TAR_RECORDSIZE); { Get the Meta Data } FTarHeaderList.Add(PTarHeader); { Store the Header to the list } FTarHeaderTypeList.Add(Pointer(MD_DATA_HEADER)); end; { Loop and reparse } end else if PTarHeader.LinkFlag in AB_SUPPORTED_F_HEADERS then begin { This Header type is in the Set of supported File type Headers } FoundItem := True; { Exit Criterion } FTarItem.ItemType := SUPPORTED_ITEM; if FTarItem.ItemReadOnly then { Since some of the Headers are read only. } FTarItem.ItemType := UNSUPPORTED_ITEM; { This Item is unsupported } FTarHeaderTypeList.Add(Pointer(FILE_HEADER)); end else if PTarHeader.LinkFlag in AB_UNSUPPORTED_F_HEADERS then begin { This Header type is in the Set of unsupported File type Headers } FoundItem := True; { Exit Criterion } FTarItem.ItemType := UNSUPPORTED_ITEM; FTarHeaderTypeList.Add(Pointer(FILE_HEADER)); end else { These are unknown header types } begin { Note: Some of these unknown types could have known Meta-data headers } FoundItem := True; FTarItem.ItemType := UNKNOWN_ITEM; FTarHeaderTypeList.Add(Pointer(UNKNOWN_HEADER)); end;{ end LinkFlag parsing } end; { end Found Item While } { PTarHeader points to FTarHeaderList.Items[FTarHeaderList.Count-1]; } { Re-wind the Stream back to the begining of this Item inc. all headers } AStream.Seek(-(FTarHeaderList.Count*AB_TAR_RECORDSIZE), soCurrent); { AStream.Position := FTarItem.StreamPosition; } { This should be equivalent as above } FTarItem.FileHeaderCount := FTarHeaderList.Count; if FTarItem.ItemType <> UNKNOWN_ITEM then begin ParseTarHeaders; { Update FTarItem values } FFileName := FTarItem.Name; {FTarHeader.Name;} FDiskFileName := FileName; AbUnfixName(FDiskFileName); end; Action := aaNone; Tagged := False; end; { ****************** BEGIN SET ********************** } procedure TAbTarItem.SaveTarHeaderToStream(AStream: TStream); var i : Integer; j : Integer; PHeader : PAbTarHeaderRec; HdrChkSum : Integer; HdrChkStr : AnsiString; HdrBuffer : PAnsiChar; SkipNextChkSum: Integer; SkipChkSum: Boolean; begin if FTarItem.ItemReadOnly then { Read Only - Do Not Save } Exit; { Note: The SizeOf(TAbTarHeaderRec) = AB_TAR_RECORDSIZE } if FTarItem.Dirty then SkipNextChkSum := 0 else SkipNextChkSum := FTarHeaderList.Count; { Don't recalc any chkSums } { The first header in the Item list must have a checksum calculation } for i := 0 to (FTarHeaderList.Count-1) do begin SkipChkSum := False; PHeader := FTarHeaderList.Items[i]; if (SkipNextChkSum = 0) then begin { We need to parse this header } if PHeader.LinkFlag in (AB_SUPPORTED_MD_HEADERS+AB_UNSUPPORTED_MD_HEADERS) then begin { We have a Meta-Data Header, Calculate how many headers to skip. } { These meta-data headers have non-Header buffers after this Header } SkipNextChkSum := Ceil(OctalToInt(PHeader.Size, SizeOf(PHeader.Size)) / AB_TAR_RECORDSIZE); { Ceil will mandate one run through, and will handle 512 correctly } end else if PHeader.LinkFlag in AB_SUPPORTED_F_HEADERS then begin SkipNextChkSum := 0; end else begin { Un-Supported Header type, Copy but do nothing to the data } SkipNextChkSum := 0; SkipChkSum := True; end;{ end LinkFlag parsing } end else begin { Do not calcuate the check sum on this meta Data header buffer } SkipNextChkSum := SkipNextChkSum - 1; SkipChkSum := True; end;{ end SkipNextChkSum } if not SkipChkSum then begin { We are Calculating the Checksum for this Header } {Tar ChkSum is "odd" The check sum field is filled with #20 chars as empty } { ChkSum field itself is #20'd and has an effect on the sum } PHeader.ChkSum := AB_TAR_CHKBLANKS; { Set up the buffers } HdrBuffer := PAnsiChar(PHeader); HdrChkSum := 0; { Calculate the checksum, a simple sum of the bytes in the header } for j := 0 to (AB_TAR_RECORDSIZE-1) do HdrChkSum := HdrChkSum + Ord(HdrBuffer[j]); { set the checksum in the header } HdrChkStr := PadString(IntToOctal(HdrChkSum), SizeOf(PHeader.ChkSum)); Move(HdrChkStr[1], PHeader.ChkSum, Length(HdrChkStr)); end; { end Skip Check Sum } { write header to the file } AStream.Write(PHeader^, AB_TAR_RECORDSIZE); end; { End for the number of headers in the list } { Updated here as the stream is now updated to the latest number of headers } FTarItem.FileHeaderCount := FTarHeaderList.Count; end; procedure TAbTarItem.SetCompressedSize(const Value: Int64); var S : AnsiString; begin if FTarItem.ItemReadOnly then { Read Only - Do Not Save } Exit; { Size is extendable in PAX Headers, Remember PAX extended Header Over Rule File Headers } FTarItem.Size := Value; { Store our Vitrual Copy } S := PadString(IntToOctal(Value), SizeOf(Arr12));{ Stuff to header } Move(S[1], PTarHeader.Size, Length(S)); FTarItem.Dirty := True; end; procedure TAbTarItem.SetDevMajor(const Value: Integer); var S : AnsiString; begin if FTarItem.ItemReadOnly then { Read Only - Do Not Save } Exit; { Dev Major and Minor are Only used for AB_TAR_LF_CHR, AB_TAR_LF_BLK } { Otherwise they are stuffed with #00 } FTarItem.DevMajor := Value; { Store to the struct } S := PadString(IntToOctal(Value), SizeOf(Arr8)); Move(S[1], PTarHeader.DevMajor, Length(S)); FTarItem.Dirty := True; end; procedure TAbTarItem.SetDevMinor(const Value: Integer); var S : AnsiString; begin if FTarItem.ItemReadOnly then { Read Only - Do Not Save } Exit; { Dev Major and Minor are Only used for AB_TAR_LF_CHR, AB_TAR_LF_BLK } { Otherwise they are stuffed with #00 } FTarItem.DevMinor := Value; S := PadString(IntToOctal(Value), SizeOf(Arr8)); Move(S[1], PTarHeader.DevMinor, Length(S)); FTarItem.Dirty := True; end; procedure TAbTarItem.SetExternalFileAttributes(Value: LongWord); var S : AnsiString; I: Integer; begin if FTarItem.ItemReadOnly then { Read Only - Do Not Save } Exit; FTarItem.Mode := Value; S := PadString(IntToOctal(Value), SizeOf(Arr8)); for I := 0 to FTarHeaderList.Count - 1 do if TAbTarHeaderType(FTarHeaderTypeList.Items[I]) in [FILE_HEADER, META_DATA_HEADER] then Move(S[1], PAbTarHeaderRec(FTarHeaderList.Items[I]).Mode, Length(S)); FTarItem.Dirty := True; end; { Add/Remove Headers as needed To/From Existing GNU Long (Link/Name) TarItems } procedure TAbTarItem.DoGNUExistingLongNameLink(LinkFlag: AnsiChar; I: Integer; const Value: AnsiString); var PHeader: PAbTarHeaderRec; J: Integer; OldNameLength: Integer; TotalOldNumHeaders: Integer; TotalNewNumHeaders: Integer; NumHeaders: Integer; ExtraName: Integer; tempStr: AnsiString; begin PHeader := FTarHeaderList.Items[I]; { Need this data from the old header } OldNameLength := OctalToInt(PHeader.Size, SizeOf(PHeader.Size));{ inlcudes Null termination } { Length(FTarItem.Name)+1 = OldNameLength; }{ This should be true, always } { Save off the new Length, so we don't have to change the pointers later. } tempStr := PadString(IntToOctal(Length(Value)+1), SizeOf(PHeader.Size)); Move(tempStr[1], PHeader.Size, Length(tempStr)); TotalOldNumHeaders := Ceil(OldNameLength / AB_TAR_RECORDSIZE); TotalNewNumHeaders := Ceil((Length(Value)+1) / AB_TAR_RECORDSIZE);{ Null terminated } {Length(Value)+1: 1-512 = 1, 513-1024 = 2 ... } J := TotalOldNumHeaders - TotalNewNumHeaders; while J <> 0 do begin if J > 0 then begin { Old > New, Have to many Headers, Remove } FreeMem(FTarHeaderList.Items[I+J]); { Free the Memory for the extra Header } FTarHeaderList.Delete(I+J); { Delete the List index } FTarHeaderTypeList.Delete(I+J); J := J - 1; end else { if J < 0 then } begin { Old < New, Need more Headers, Insert } GetMem(PHeader, AB_TAR_RECORDSIZE); FTarHeaderList.Insert(I+1,PHeader);{ Insert: Inserts at index } FTarHeaderTypeList.Insert(I+1,Pointer(MD_DATA_HEADER));{ We are only adding MD Data headers here } J := J + 1; end; end;{ end numHeaders while } { Yes, GNU Tar adds a Nil filled MD data header if Length(Value) mod AB_TAR_RECORDSIZE = 0 } NumHeaders := (Length(Value)+1) div AB_TAR_RECORDSIZE; { Include Null terminator } ExtraName := (Length(Value)+1) mod AB_TAR_RECORDSIZE; { Chars in the last Header } { Now we have the number of headers set up, stuff the name in the Headers } TempStr := AnsiString(Value); for J := 1 to NumHeaders do begin { Copy entire next AB_TAR_RECORDSIZE bytes of tempString to content of Header } { There may only be AB_TAR_RECORDSIZE-1 bytes if this is the last rounded header } PHeader := FTarHeaderList.Items[I+J]; Move(TempStr[1], PHeader^, AB_TAR_RECORDSIZE); if Length(TempStr) >= AB_TAR_RECORDSIZE then Delete(TempStr, 1, AB_TAR_RECORDSIZE);{ Crop string } end; if ExtraName <> 0 then begin { Copy whatever is left in tempStr into the rest of the buffer } PHeader := FTarHeaderList.Items[I+NumHeaders+1]; FillChar(PHeader^, AB_TAR_RECORDSIZE, #0); { Zero the whole block } Move(TempStr[1], PHeader^, ExtraName-1); { The string is null terminated } end else { We already copied the entire name, but it must be null terminated } begin FillChar(Pointer(PtrInt(PHeader)+AB_TAR_RECORDSIZE-1)^, 1, #0); { Zero rest of the block } end; { Finally we need to stuff the file type Header. } { Note: Value.length > AB_TAR_NAMESIZE(100) } if LinkFlag = AB_TAR_LF_LONGNAME then Move(Value[1], PTarHeader.Name, AB_TAR_NAMESIZE) else Move(Value[1], PTarHeader.LinkName, AB_TAR_NAMESIZE); end; { Always inserts the L/K Headers at index 0+ } procedure TAbTarItem.DoGNUNewLongNameLink(LinkFlag: AnsiChar; I: Integer; const Value: AnsiString); var PHeader: PAbTarHeaderRec; J: Integer; NumHeaders: Integer; ExtraName: Integer; tempStr: AnsiString; begin { We have a GNU_FORMAT, and no L/K Headers.} { Add a new MD Header and MD Data Headers } { Make an L/K header } GetMem(PHeader, AB_TAR_RECORDSIZE); FTarHeaderList.Insert(I, PHeader);{ Insert: Inserts at base index } FTarHeaderTypeList.Insert(I, Pointer( META_DATA_HEADER));{ This is the L/K Header } FillChar(PHeader^, AB_TAR_RECORDSIZE, #0); { Zero the whole block } AbStrPCopy(PHeader.Name, AB_TAR_L_HDR_NAME); { Stuff L/K String Name } AbStrPCopy(PHeader.Mode, AB_TAR_L_HDR_ARR8_0); { Stuff zeros } AbStrPCopy(PHeader.uid, AB_TAR_L_HDR_ARR8_0); { Stuff zeros } AbStrPCopy(PHeader.gid, AB_TAR_L_HDR_ARR8_0); { Stuff zeros } tempStr := PadString(IntToOctal(Length(Value)+1), SizeOf(PHeader.Size)); { Stuff Size } Move(tempStr[1], PHeader.Size, Length(tempStr)); AbStrPCopy(PHeader.ModTime, AB_TAR_L_HDR_ARR12_0); { Stuff zeros } { Check sum will be calculated as the Dirty flag is in caller. } PHeader.LinkFlag := LinkFlag; { Stuff Link FlagSize } AbStrPCopy(PHeader.Magic.gnuOld, AB_TAR_MAGIC_GNUOLD); { Stuff the magic } AbStrPCopy(PHeader.UsrName, AB_TAR_L_HDR_USR_NAME); AbStrPCopy(PHeader.GrpName, AB_TAR_L_HDR_GRP_NAME); { All else stays as Zeros. } { Completed with L/K Header } { OK, now we need to add the proper number of MD Data Headers, and intialize to new name } { Yes, GNU Tar adds an extra Nil filled MD data header if Length(Value) mod AB_TAR_RECORDSIZE = 0 } NumHeaders := Ceil((Length(Value)+1) / AB_TAR_RECORDSIZE); { Include Null terminator } ExtraName := (Length(Value)+1) mod AB_TAR_RECORDSIZE; { Chars in the last Header } { Now we have the number of headers set up, stuff the name in the Headers } TempStr := AnsiString(Value); for J := 1 to NumHeaders-1 do begin { Make a buffer, and copy entire next AB_TAR_RECORDSIZE bytes of tempStr to content of Header } { There may only be AB_TAR_RECORDSIZE-1 bytes if this is the last rounded header } GetMem(PHeader, AB_TAR_RECORDSIZE); FTarHeaderList.Insert(J+I, PHeader); FTarHeaderTypeList.Insert(J+I, Pointer(MD_DATA_HEADER));{ We are adding MD Data headers here } Move(TempStr[1], PHeader^, AB_TAR_RECORDSIZE); if Length(TempStr) >= AB_TAR_RECORDSIZE then Delete(TempStr, 1, AB_TAR_RECORDSIZE);{ Crop string } end; if ExtraName <> 0 then begin { Copy what ever is left in tempStr into the rest of the buffer } { Create the last MD Data Header } GetMem(PHeader, AB_TAR_RECORDSIZE); FTarHeaderList.Insert(I+NumHeaders, PHeader);{ Insert: Inserts at base index } FTarHeaderTypeList.Insert(I+NumHeaders, Pointer(MD_DATA_HEADER));{ We are only adding MD Data headers here } FillChar(PHeader^, AB_TAR_RECORDSIZE, #0); { Zero the whole block } Move(TempStr[1], PHeader^, ExtraName-1); { The string is null terminated in the header } end else { We already copied the entire name, but it must be null terminated } begin FillChar(Pointer(PtrInt(PHeader)+AB_TAR_RECORDSIZE-1)^, 1, #0); { Zero rest of the block } end; { Finally we need to stuff the file type Header. } { Note: Value.length > AB_TAR_NAMESIZE(100) } if LinkFlag = AB_TAR_LF_LONGNAME then Move(Value[1], PHeader.Name, AB_TAR_NAMESIZE) else Move(Value[1], PHeader.LinkName, AB_TAR_NAMESIZE); end; procedure TAbTarItem.SetFileName(const Value: string); var FoundMetaDataHeader: Boolean; PHeader: PAbTarHeaderRec; I, J: Integer; TotalOldNumHeaders: Integer; RawFileName: AnsiString; begin if FTarItem.ItemReadOnly then { Read Only - Do Not Save } Exit; { Assume ItemReadOnly is set for all Unsupported Type. } { Cases: New File Name is short, Length <= 100, All formats: Zero Name field and move new name to field. V7: Work complete, 1 header USTAR: zero prefix field, 1 Header OLD_GNU & GNU: Remove old name headers, 1 header. STAR & PAX: And should not yet get here. New File Name is Long, Length >=101 Note: The Header Parsing sets any V7 to GNU if 'L'/'K" Headers are present V7: Raise an exception, as this can NOT be done, no change to header. USTAR: if new length <= 254 zero fill header, update name fields, 1 updated Header if new Length >= 255 raise an exception, as this can NOT be done, no change to header if old was Short, Add files to match format, OLD_GNU & GNU: Create new Name header, Add N Headers for name, Update name in file header, update name fields, min 3 headers STAR & PAX: And should not yet get here. if old was Long, OLD_GNU & GNU: Add N Headers for name, Update name in MD header, update name field in File Headers, min 3 headers Add headers to length of new Name Length, update name in file header, update name fields } RawFileName := AbStringToUnixBytes(Value); { In all cases zero out the name fields in the File Header. } if Length(RawFileName) > AB_TAR_NAMESIZE then begin { Must be null terminated except at 100 char length } { Look for long name meta-data headers already in the archive. } FoundMetaDataHeader := False; I := 0; { FTarHeaderList.Count <= 1 always } while (not FoundMetaDataHeader) and (I <= (FTarHeaderList.Count - 1)) do begin PHeader := FTarHeaderList.Items[I]; if PHeader.LinkFlag = AB_TAR_LF_LONGNAME then begin { We are growing or Shriking the Name MD Data fields. } FoundMetaDataHeader := True; DoGNUExistingLongNameLink(AB_TAR_LF_LONGNAME, I, RawFileName); { Need to copy the Name to the header. } FTarItem.Name := Value; end else I := I + 1; end; { End While } { MD Headers & MD Data Headers have been stuffed if FoundMetaDataHeader } { Still need to stuff the File type header contents. } if not FoundMetaDataHeader then begin case FTarItem.ArchiveFormat of V7_FORMAT: raise EAbTarBadFileName.Create; { File Name to Long } USTAR_FORMAT: begin { Longest file name is AB_TAR_NAMESIZE(100) chars } { Longest Prefix is AB_TAR_USTAR_PREFIX_SIZE(155) chars } { These two fields are delimted by a '/' char } {0123456789012345, Length = 15, NameLength = 5, PrefixLength = 9} { AAAA/BBBB/C.txt, Stored as Name := 'C.txt', Prefix := 'AAAA/BBBB' } { That means Theoretical maximum is 256 for Length(RawFileName) } if Length(RawFileName) > (AB_TAR_NAMESIZE+AB_TAR_USTAR_PREFIX_SIZE+1) then { Check the obvious one. } raise EAbTarBadFileName.Create; { File Name to Long } for I := Length(RawFileName) downto Length(RawFileName)-AB_TAR_NAMESIZE-1 do begin if RawFileName[I] = '/' then begin if (I <= AB_TAR_USTAR_PREFIX_SIZE+1) and (Length(RawFileName)-I <= AB_TAR_NAMESIZE) then begin { We have a successfull parse. } FillChar(PTarHeader.Name, SizeOf(PTarHeader.Name), #0); FillChar(PTarHeader.ustar.Prefix, SizeOf(PTarHeader.ustar.Prefix), #0); Move(RawFileName[I+1], PTarHeader.Name, Length(RawFileName)-I); Move(RawFileName[1], PTarHeader.ustar.Prefix, I); break; end else if (Length(RawFileName)-I > AB_TAR_NAMESIZE) then raise EAbTarBadFileName.Create { File Name not splittable } { else continue; } end; end;{ End for I... } end; { End USTAR Format } OLDGNU_FORMAT: DoGNUNewLongNameLink(AB_TAR_LF_LONGNAME, 0, RawFileName); {GNU_FORMAT} else begin { UNKNOWN_FORMAT, STAR_FORMAT, POSIX_FORMAT } raise EAbTarBadOp.Create; { Unknown Archive Format } end;{ End of Else for case statement } end;{ End of case statement } FTarItem.Name := Value; end; { if no Meta data header found } end { End "name length larger than 100" } else begin { Short new name, Simple Case Just put it in the Name Field & remove any headers } { PTarHeader Points to the File type Header } { Zero the Name field } FillChar(PTarHeader.Name, SizeOf(PTarHeader.Name), #0); if FTarItem.ArchiveFormat in [USTAR_FORMAT] then { Zero the prefix field } FillChar(PTarHeader.ustar.Prefix, SizeOf(PTarHeader.ustar.Prefix), #0); if FTarItem.ArchiveFormat in [GNU_FORMAT, OLDGNU_FORMAT] then begin { We may have AB_TAR_LF_LONGNAME Headers to be removed } { Remove long file names Headers if they exist} FoundMetaDataHeader := False; I := 0; while not FoundMetaDataHeader and (I <= (FTarHeaderList.Count - 1)) do begin PHeader := FTarHeaderList.Items[I]; if PHeader.LinkFlag in [AB_TAR_LF_LONGNAME] then begin { Delete this Header, and the data Headers. } FoundMetaDataHeader := True; TotalOldNumHeaders := Ceil( OctalToInt(PHeader.Size, SizeOf(PHeader.Size)) / AB_TAR_RECORDSIZE); for J := TotalOldNumHeaders downto 0 do begin { Note 0 will delete the Long Link MD Header } FreeMem(FTarHeaderList.Items[I+J]); { This list holds PAbTarHeaderRec's } FTarHeaderList.Delete(I+J); FTarHeaderTypeList.Delete(I+J); end; end else I := I + 1; { Got to next header } end;{ End While not found... } end; { End if GNU... } { Save off the new name and store to the Header } FTarItem.Name := Value; { Must add Null Termination before we store to Header } AbStrPLCopy(PTarHeader.Name, RawFileName, AB_TAR_NAMESIZE); end;{ End else Short new name,... } { Update the inherited file names. } FFileName := FTarItem.Name; DiskFileName := FFileName; AbUnfixName(FDiskFileName); FTarItem.Dirty := True; end; procedure TAbTarItem.SetGroupID(const Value: Integer); var S : AnsiString; begin if FTarItem.ItemReadOnly then { Read Only - Do Not Save } Exit; { gid is extendable in PAX Headers, Rember PAX extended Header Over Rule File Headers } FTarItem.gid := Value; S := PadString(IntToOctal(Value), SizeOf(Arr8)); Move(S[1], PTarHeader.gid, Length(S)); FTarItem.Dirty := True; end; procedure TAbTarItem.SetGroupName(const Value: string); begin if FTarItem.ItemReadOnly then { Read Only - Do Not Save } Exit; { GrpName is extendable in PAX Headers, Rember PAX extended Header Over Rule File Headers } FTarItem.GrpName := Value; AbStrPLCopy(PTarHeader.GrpName, AnsiString(Value), SizeOf(PTarHeader.GrpName)); FTarItem.Dirty := True; end; procedure TAbTarItem.SetIsEncrypted(Value: Boolean); begin { do nothing, TAR has no native encryption } end; procedure TAbTarItem.SetLastModFileDate(const Value: Word); begin { replace date, keep existing time } LastModTimeAsDateTime := EncodeDate( Value shr 9 + 1980, Value shr 5 and 15, Value and 31) + Frac(LastModTimeAsDateTime); end; procedure TAbTarItem.SetLastModFileTime(const Value: Word); begin { keep current date, replace time } LastModTimeAsDateTime := Trunc(LastModTimeAsDateTime) + EncodeTime( Value shr 11, Value shr 5 and 63, Value and 31 shl 1, 0); end; procedure TAbTarItem.SetLastModTimeAsDateTime(const Value: TDateTime); begin // TAR stores always Unix time. SetModTime(AbLocalDateTimeToUnixTime(Value)); // also updates headers end; procedure TAbTarItem.SetLinkFlag(Value: AnsiChar); begin if FTarItem.ItemReadOnly then Exit; FTarItem.LinkFlag := Value; PTarHeader.LinkFlag := Value; FTarItem.Dirty := True; end; procedure TAbTarItem.SetLinkName(const Value: string); var FoundMetaDataHeader: Boolean; PHeader: PAbTarHeaderRec; I, J: Integer; TotalOldNumHeaders: Integer; RawLinkName: AnsiString; begin if FTarItem.ItemReadOnly then { Read Only - Do Not Save } Exit; { Cases: New Link Name is short, Length <= 100, All formats: Zero Name field and move new name to field. V7: Work complete, 1 header USTAR: Work complete, 1 Header OLD_GNU & GNU: Remove old link headers, 1 header. STAR & PAX: And should not yet get here. New File Name is Long, Length >=101 Note: The Header Parsing sets any V7 to GNU if 'L'/'K' Headers are present V7: Raise an exception, as this can NOT be done, no change to header. USTAR: Raise an exception, as this can NOT be done, no change to header. if old was Short, Add files to match format, OLD_GNU & GNU: Create new Link header, Add N Headers for name, Update name in file header, update name fields, min 3 headers if old was Long, OLD_GNU & GNU: Add N Headers for name, Update name in MD header, update name field in File Headers, min 3 headers STAR & PAX: And should not yet get here.} RawLinkName := AbStringToUnixBytes(Value); if Length(RawLinkName) > AB_TAR_NAMESIZE then { Must be null terminated except at 100 char length } begin { Look for long name meta-data headers already in the archive. } FoundMetaDataHeader := False; I := 0; { FTarHeaderList.Count <= 1 always } while (not FoundMetaDataHeader) and (I <= (FTarHeaderList.Count - 1)) do begin PHeader := FTarHeaderList.Items[I]; if PHeader.LinkFlag = AB_TAR_LF_LONGLINK then begin { We are growing or Shriking the Name MD Data fields. } FoundMetaDataHeader := True; DoGNUExistingLongNameLink(AB_TAR_LF_LONGLINK, I, RawLinkName); { Need to copy the Name to the header. } FTarItem.LinkName := Value; end else I := I + 1; end; { End While } { MD Headers & MD Data Headers have been stuffed if FoundMetaDataHeader } { Still need to stuff the File type header contents. } if not FoundMetaDataHeader then begin case FTarItem.ArchiveFormat of V7_FORMAT: raise EAbTarBadLinkName.Create; { Link Name to Long } USTAR_FORMAT: raise EAbTarBadLinkName.Create; { Link Name to Long } OLDGNU_FORMAT: DoGNUNewLongNameLink(AB_TAR_LF_LONGLINK, 0, RawLinkName); {GNU_FORMAT} else begin { UNKNOWN_FORMAT, STAR_FORMAT, POSIX_FORMAT } raise EAbTarBadOp.Create; { Unknown Archive Format } end;{ End of Else for case statement } end;{ End of case statement } FTarItem.LinkName := Value; end; { if no Meta data header found } end { End "name length larger than 100" } else begin { Short new name, Simple Case Just put it in the Link Field & remove any headers } { PTarHeader Points to the File type Header } { Zero the Link field } FillChar(PTarHeader.LinkName, SizeOf(PTarHeader.LinkName), #0); if FTarItem.ArchiveFormat in [GNU_FORMAT, OLDGNU_FORMAT] then begin { We may have AB_TAR_LF_LONGNAME Headers to be removed } { Remove long file names Headers if they exist} FoundMetaDataHeader := False; I := 0; while not FoundMetaDataHeader and (I <= (FTarHeaderList.Count - 1)) do begin PHeader := FTarHeaderList.Items[I]; if PHeader.LinkFlag in [AB_TAR_LF_LONGLINK] then begin { Delete this Header, and the data Headers. } FoundMetaDataHeader := True; TotalOldNumHeaders := Ceil( OctalToInt(PHeader.Size, SizeOf(PHeader.Size)) / AB_TAR_RECORDSIZE); for J := TotalOldNumHeaders downto 0 do begin { Note 0 will delete the Long Link MD Header } FreeMem(FTarHeaderList.Items[I+J]); { This list holds PAbTarHeaderRec's } FTarHeaderList.Delete(I+J); FTarHeaderTypeList.Delete(I+J); end; end else I := I + 1; { Got to next header } end;{ End While not found... } end; { End if GNU... } { Save off the new name and store to the Header } FTarItem.LinkName := Value; AbStrPLCopy(PTarHeader.LinkName, RawLinkName, AB_TAR_NAMESIZE); end;{ End else Short new name,... } FTarItem.Dirty := True; end; procedure TAbTarItem.SetMagic(const Value: String); begin if FTarItem.ItemReadOnly then { Read Only - Do Not Save } Exit; FTarItem.Magic := AnsiString(Value); Move(Value[1], PTarHeader.Magic, SizeOf(TAbTarMagicRec)); FTarItem.Dirty := True; end; procedure TAbTarItem.SetUncompressedSize(const Value: Int64); var S : AnsiString; begin if FTarItem.ItemReadOnly then { Read Only - Do Not Save } Exit; { Size is extendable in PAX Headers, Remember PAX extended Header Over Rule File Headers } FTarItem.Size := Value; { Store our Vitrual Copy } S := PadString(IntToOctal(Value), SizeOf(Arr12));{ Stuff to header } Move(S[1], PTarHeader.Size, Length(S)); FTarItem.Dirty := True; end; procedure TAbTarItem.SetUserID(const Value: Integer); var S : AnsiString; begin if FTarItem.ItemReadOnly then { Read Only - Do Not Save } Exit; { uid is extendable in PAX Headers, Remember PAX extended Header Over Rule File Headers } FTarItem.uid := Value; S := PadString(IntToOctal(Value), SizeOf(Arr8)); Move(S[1], PTarHeader.uid, Length(S)); FTarItem.Dirty := True; end; procedure TAbTarItem.SetUserName(const Value: string); begin if FTarItem.ItemReadOnly then { Read Only - Do Not Save } Exit; { UsrName is extendable in PAX Headers, Remember PAX extended Header Over Rule File Headers } FTarItem.UsrName := Value; AbStrPLCopy(PTarHeader.UsrName, AnsiString(Value), SizeOf(PTarHeader.UsrName)); FTarItem.Dirty := True; end; procedure TAbTarItem.SetModTime(const Value: Int64); var S: AnsiString; begin if FTarItem.ItemReadOnly then { Read Only - Do Not Save } Exit; { ModTime is extendable in PAX Headers, Remember PAX extended Header Over Rule File Headers } FTarItem.ModTime := Value; { Store our Virtual Copy } S := PadString(IntToOctal(Value), SizeOf(Arr12));{ Stuff to header } Move(S[1], PTarHeader.ModTime, Length(S)); FTarItem.Dirty := True; end; { ************************** TAbTarStreamHelper ****************************** } destructor TAbTarStreamHelper.Destroy; begin inherited Destroy; end; { This is slow, use the archive class instead } procedure TAbTarStreamHelper.ExtractItemData(AStream: TStream); begin { Note: The SizeOf(TAbTarHeaderRec) = AB_TAR_RECORDSIZE } if FCurrItemSize <> 0 then begin { copy stored data to output } AStream.CopyFrom(FStream, FCurrItemSize); {reset the stream to the start of the item} FStream.Seek(-(FCurrItemPreHdrs*AB_TAR_RECORDSIZE+FCurrItemSize), soCurrent); end; { else do nothing } end; { This function Should only be used from LoadArchive, as it is slow. } function TAbTarStreamHelper.FindItem: Boolean; var DataRead : LongInt; FoundItem: Boolean; SkipHdrs : Integer; begin { Note: The SizeOf(TAbTarHeaderRec) = AB_TAR_RECORDSIZE } { Note: Standard LBA size of hard disks is 512 bytes = AB_TAR_RECORDSIZE } FoundItem := False; { Getting an new Item reset these numbers } FCurrItemSize := 0; FCurrItemPreHdrs := 0; DataRead := FStream.Read(FTarHeader, AB_TAR_RECORDSIZE); { Read in a header } { DataRead <> AB_TAR_RECORDSIZE means end of stream, and the End Of Archive record is all #0's, which the StrLen(FTarHeader.Name) check will catch } while (DataRead = AB_TAR_RECORDSIZE) and (AbStrLen(FTarHeader.Name) > 0) and not FoundItem do begin { Either exit when we find a supported file or end of file or an invalid header name. } if FTarHeader.LinkFlag in (AB_SUPPORTED_MD_HEADERS+AB_UNSUPPORTED_MD_HEADERS) then begin { We have a un/supported Meta-Data Header } { FoundItem := False } { Value remains False. } SkipHdrs := Ceil(OctalToInt(FTarHeader.Size, SizeOf(FTarHeader.Size))/AB_TAR_RECORDSIZE); FStream.Seek(SkipHdrs*AB_TAR_RECORDSIZE, soCurrent); { Tally new Headers: Consumed + Current } FCurrItemPreHdrs := FCurrItemPreHdrs + SkipHdrs + 1; { Read our next header, Loop, and re-parse } DataRead := FStream.Read(FTarHeader, AB_TAR_RECORDSIZE); end else if FTarHeader.LinkFlag in (AB_SUPPORTED_F_HEADERS+AB_UNSUPPORTED_F_HEADERS) then begin { We have a un/supported File Header. } FoundItem := True; if not (FTarHeader.LinkFlag in AB_IGNORE_SIZE_HEADERS) then FCurrItemSize := OctalToInt(FTarHeader.Size, SizeOf(FTarHeader.Size)) else FCurrItemSize := 0; { Per The spec these Headers do not have file content } FCurrItemPreHdrs := FCurrItemPreHdrs + 1; { Tally current header } end else begin{ We Have an Unknown header } FoundItem := True; FCurrItemSize := 0; { We could have many un/supported headers before this unknown type } FCurrItemPreHdrs := FCurrItemPreHdrs + 1; { Tally current header } { These Headers should throw exceptions when TAbTarItem.LoadTarHeaderFromStream is called } end; { End of Link Flag parsing } end; { Rewind to the "The Beginning" of this Item } { Really that means to the first supported Header Type before a supported Item Type } if FoundItem then FStream.Seek(-(FCurrItemPreHdrs*AB_TAR_RECORDSIZE), soCurrent); Result := FoundItem; end; { Should only be used from LoadArchive, as it is slow. } function TAbTarStreamHelper.FindFirstItem: Boolean; begin FStream.Seek(0, soBeginning); Result := FindItem; end; { Should only be used from LoadArchive, as it is slow. } function TAbTarStreamHelper.FindNextItem: Boolean; begin { Fast Forward Past the current Item } FStream.Seek((FCurrItemPreHdrs*AB_TAR_RECORDSIZE + RoundToTarBlock(FCurrItemSize)), soCurrent); Result := FindItem; end; { This is slow, use the archive class instead } function TAbTarStreamHelper.GetItemCount : Integer; var Found : Boolean; begin Result := 0; Found := FindFirstItem; while Found do begin Inc(Result); Found := FindNextItem; end; end; procedure TAbTarStreamHelper.ReadHeader; begin { do nothing } { Tar archives have no overall header data } end; procedure TAbTarStreamHelper.ReadTail; begin { do nothing } { Tar archives have no overall tail data } end; { This is slow, use the archive class instead } function TAbTarStreamHelper.SeekItem(Index: Integer): Boolean; var i : Integer; begin Result := FindFirstItem; { see if can get to first item } i := 1; while Result and (i < Index) do begin Result := FindNextItem; Inc(i); end; end; procedure TAbTarStreamHelper.WriteArchiveHeader; begin { do nothing } { Tar archives have no overall header data } end; procedure TAbTarStreamHelper.WriteArchiveItem(AStream: TStream); begin WriteArchiveItemSize(AStream, AStream.Size); end; procedure TAbTarStreamHelper.WriteArchiveItemSize(AStream: TStream; Size: Int64); var PadBuff : PAnsiChar; PadSize : Integer; begin if Size = 0 then Exit; { transfer actual item data } FStream.CopyFrom(AStream, Size); { Pad to Next block } PadSize := RoundToTarBlock(Size) - Size; GetMem(PadBuff, PadSize); FillChar(PadBuff^, PadSize, #0); FStream.Write(PadBuff^, PadSize); FreeMem(PadBuff, PadSize); end; procedure TAbTarStreamHelper.WriteArchiveTail; var PadBuff : PAnsiChar; PadSize : Integer; begin { append 2 terminating null blocks } PadSize := AB_TAR_RECORDSIZE; GetMem(PadBuff, PadSize); try FillChar(PadBuff^, PadSize, #0); FStream.Write(PadBuff^, PadSize); FStream.Write(PadBuff^, PadSize); finally FreeMem(PadBuff, PadSize); end; end; { ***************************** TAbTarArchive ******************************** } constructor TAbTarArchive.CreateFromStream(aStream : TStream; const aArchiveName : string); begin inherited; FArchFormat := V7_FORMAT; // Default for new archives end; function TAbTarArchive.CreateItem(const FileSpec: string): TAbArchiveItem; var Item : TAbTarItem; S : String; I: Integer; begin if FArchReadOnly then raise EAbTarBadOp.Create; { Create Item Unsupported in this Archive } S := FixName(FileSpec); Item := TAbTarItem.Create; try // HeaderFormat = (UNKNOWN_FORMAT, V7_FORMAT, OLDGNU_FORMAT, GNU_FORMAT, USTAR_FORMAT, STAR_FORMAT, POSIX_FORMAT); if FArchFormat in [OLDGNU_FORMAT, GNU_FORMAT] then begin Item.ArchiveFormat := FArchFormat; Item.LinkFlag := AB_TAR_LF_NORMAL; Item.Magic := AB_TAR_MAGIC_GNUOLD; end else if FArchFormat in [USTAR_FORMAT] then begin Item.ArchiveFormat := USTAR_FORMAT; Item.LinkFlag := AB_TAR_LF_NORMAL; Item.Magic := AB_TAR_MAGIC_VAL+AB_TAR_MAGIC_VER; end else if (FArchFormat = V7_FORMAT) and (Length(S) > 100) then begin { Switch the rep over to GNU so it can have long file names. } FArchFormat := OLDGNU_FORMAT; Item.ArchiveFormat := OLDGNU_FORMAT; { Leave the Defaults for LinkFlag, and Magic } { Update all the rest so that it can transistion to GNU_FORMAT } for I := 0 to FItemList.Count - 1 do TAbTarItem(FItemList.Items[i]).ArchiveFormat := OLDGNU_FORMAT; end;{ This should not execute... }{ else if FArchFormat in [STAR_FORMAT, POSIX_FORMAT] then begin Item.ArchiveFormat := FArchFormat; Item.LinkFlag := AB_TAR_LF_NORMAL; Item.Magic := AB_TAR_MAGIC_VAL+AB_TAR_MAGIC_VER; end; }{ else FArchFormat in [ UNKNOWN_FORMAT, V7_FORMAT and Length(S) <= 100 ] } { This is the default. } { Most others are initialized in the .Create } Item.CRC32 := 0; { Note this can raise exceptions for file name lengths. } Item.FileName := FixName(FileSpec); Item.DiskFileName := ExpandFileName(FileSpec); Item.Action := aaNone; finally Result := Item; end; end; procedure TAbTarArchive.ExtractItemAt(Index: Integer; const UseName: string); var OutStream : TFileStream; CurItem : TAbTarItem; begin { Check the index is not out of range. } if(Index >= ItemList.Count) then raise EListError.CreateFmt(SListIndexError, [Index]); CurItem := TAbTarItem(ItemList[Index]); if CurItem.ItemType in [UNKNOWN_ITEM] then raise EAbTarBadOp.Create; { Unsupported Type, Cannot Extract } if (CurItem.ItemType = UNSUPPORTED_ITEM) and ((Length(CurItem.FileName) >= AB_TAR_NAMESIZE) or (Length(CurItem.LinkName) >= AB_TAR_NAMESIZE)) then raise EAbTarBadOp.Create; { Unsupported Type, Cannot Extract } { We will allow extractions if the file name/Link name are strickly less than 100 chars } if CurItem.IsDirectory then AbCreateDirectory(UseName) else begin OutStream := TFileStream.Create(UseName, fmCreate or fmShareDenyNone); try try {OutStream} ExtractItemToStreamAt(Index, OutStream); finally {OutStream} OutStream.Free; end; {OutStream} except if ExceptObject is EAbUserAbort then FStatus := asInvalid; DeleteFile(UseName); raise; end; end; AbSetFileTime(UseName, CurItem.LastModTimeAsDateTime); AbSetFileAttr(UseName, CurItem.NativeFileAttributes); end; procedure TAbTarArchive.ExtractItemToStreamAt(Index: Integer; aStream: TStream); var CurItem : TAbTarItem; begin if(Index >= ItemList.Count) then raise EListError.CreateFmt(SListIndexError, [Index]); CurItem := TAbTarItem(ItemList[Index]); if CurItem.ItemType in [UNKNOWN_ITEM] then raise EAbTarBadOp.Create; { Unsupported Type, Cannot Extract } if (CurItem.ItemType = UNSUPPORTED_ITEM) and ((Length(CurItem.FileName) >= AB_TAR_NAMESIZE) or (Length(CurItem.LinkName) >= AB_TAR_NAMESIZE)) then raise EAbTarBadOp.Create; { Unsupported Type, Cannot Extract } { We will allow extractions if the file name is strictly less than 100 chars } FStream.Position := CurItem.StreamPosition+CurItem.FileHeaderCount*AB_TAR_RECORDSIZE; if CurItem.UncompressedSize <> 0 then aStream.CopyFrom(FStream, CurItem.UncompressedSize); { Else there is nothing to copy. } end; procedure TAbTarArchive.LoadArchive; var TarHelp : TAbTarStreamHelper; Item : TAbTarItem; ItemFound : Boolean; Abort : Boolean; Confirm : Boolean; i : Integer; Progress : Byte; begin { create helper } TarHelp := TAbTarStreamHelper.Create(FStream); try {TarHelp} {build Items list from tar header records} { reset Tar } ItemFound := (FStream.Size > 0) and TarHelp.FindFirstItem; if ItemFound then FArchFormat := UNKNOWN_FORMAT else FArchFormat := V7_FORMAT; { while more data in Tar } while (FStream.Position < FStream.Size) and ItemFound do begin {create new Item} Item := TAbTarItem.Create; Item.FTarItem.StreamPosition := FStream.Position; try {Item} Item.LoadTarHeaderFromStream(FStream); if Item.ItemReadOnly then FArchReadOnly := True; { Set Archive as Read Only } if Item.ItemType in [SUPPORTED_ITEM, UNSUPPORTED_ITEM] then begin { List of supported Item/File Types. } { Add the New Supported Item to the List } if FArchFormat < Item.ArchiveFormat then FArchFormat := Item.ArchiveFormat; { Take the max format } Item.Action := aaNone; FItemList.Add(Item); end { end if } else begin { unhandled Tar file system entity, notify user, but otherwise ignore } if Assigned(FOnConfirmProcessItem) then FOnConfirmProcessItem(self, Item, ptFoundUnhandled, Confirm); end; { show progress and allow for aborting } Progress := (FStream.Position*100) div FStream.Size; DoArchiveProgress(Progress, Abort); if Abort then begin FStatus := asInvalid; raise EAbUserAbort.Create; end; { get the next item } ItemFound := TarHelp.FindNextItem; except {Item} raise EAbTarBadOp.Create; { Invalid Item } end; {Item} end; {end while } { All the items need to reflect this information. } for i := 0 to FItemList.Count - 1 do begin TAbTarItem(FItemList.Items[i]).ArchiveFormat := FArchFormat; TAbTarItem(FItemList.Items[i]).ItemReadOnly := FArchReadOnly; end; DoArchiveProgress(100, Abort); FIsDirty := False; finally {TarHelp} { Clean Up } TarHelp.Free; end; {TarHelp} end; function TAbTarArchive.FixName(const Value: string): string; { fixup filename for storage } var lValue : string; begin lValue := Value; {$IFDEF MSWINDOWS} if DOSMode then begin {Add the base directory to the filename before converting } {the file spec to the short filespec format. } if BaseDirectory <> '' then begin {Does the filename contain a drive or a leading backslash? } if not ((Pos(':', lValue) = 2) or (Pos(AbPathDelim, lValue) = 1)) then {If not, add the BaseDirectory to the filename.} lValue := BaseDirectory + AbPathDelim + lValue; end; lValue := AbGetShortFileSpec( lValue ); end; {$ENDIF MSWINDOWS} { Should always trip drive info if on a Win/Dos system } StoreOptions := StoreOptions + [soStripDrive]; { strip drive stuff } if soStripDrive in StoreOptions then AbStripDrive( lValue ); { check for a leading slash } if lValue[1] = AbPathDelim then System.Delete( lValue, 1, 1 ); if soStripPath in StoreOptions then lValue := ExtractFileName(lValue); if soRemoveDots in StoreOptions then AbStripDots(lValue); AbFixName(lValue); Result := lValue; end; function TAbTarArchive.GetItem(Index: Integer): TAbTarItem; begin Result := TAbTarItem(FItemList.Items[Index]); end; function TAbTarArchive.GetSupportsEmptyFolders: Boolean; begin Result := True; end; procedure TAbTarArchive.PutItem(Index: Integer; const Value: TAbTarItem); begin //TODO: Remove this from all archives FItemList.Items[Index] := Value; end; procedure TAbTarArchive.SaveArchive; var OutTarHelp : TAbTarStreamHelper; Abort : Boolean; i : Integer; NewStream : TAbVirtualMemoryStream; TempStream : TStream; SaveDir : string; CurItem : TAbTarItem; AttrEx : TAbAttrExRec; begin if FArchReadOnly then raise EAbTarBadOp.Create; { Archive is read only } {init new archive stream} NewStream := TAbVirtualMemoryStream.Create; OutTarHelp := TAbTarStreamHelper.Create(NewStream); try {NewStream/OutTarHelp} { create helper } NewStream.SwapFileDirectory := FTempDir; {build new archive from existing archive} for i := 0 to pred(Count) do begin FCurrentItem := ItemList[i]; CurItem := TAbTarItem(ItemList[i]); case CurItem.Action of aaNone, aaMove : begin {just copy the file to new stream} { "Seek" to the Item Data } { SaveTarHeaders, Updates FileHeaderCount } FStream.Position := CurItem.StreamPosition+CurItem.FileHeaderCount*AB_TAR_RECORDSIZE; CurItem.StreamPosition := NewStream.Position;{ Reset the Stream Pointer. } { Flush The Headers to the new stream } CurItem.SaveTarHeaderToStream(NewStream); { Copy to new Stream, Round to the AB_TAR_RECORDSIZE boundry, and Pad zeros} outTarhelp.WriteArchiveItemSize(FStream, CurItem.UncompressedSize); end; aaDelete: {doing nothing omits file from new stream} ; aaStreamAdd : begin try { adding from a stream } CurItem.StreamPosition := NewStream.Position;{ Reset the Stream Pointer. } CurItem.UncompressedSize := InStream.Size; CurItem.SaveTarHeaderToStream(NewStream); OutTarHelp.WriteArchiveItemSize(InStream, InStream.Size); except ItemList[i].Action := aaDelete; DoProcessItemFailure(ItemList[i], ptAdd, ecFileOpenError, 0); end; end; aaAdd, aaFreshen, aaReplace: begin try { it's coming from a file } GetDir(0, SaveDir); try {SaveDir} if (BaseDirectory <> '') then ChDir(BaseDirectory); { update metadata } if not AbFileGetAttrEx(CurItem.DiskFileName, AttrEx) then raise EAbFileNotFound.Create; CurItem.ExternalFileAttributes := AttrEx.Mode; CurItem.LastModTimeAsDateTime := AttrEx.Time; { TODO: uid, gid, uname, gname should be added here } { TODO: Add support for different types of files here } if (AttrEx.Mode and AB_FMODE_DIR) <> 0 then begin CurItem.LinkFlag := AB_TAR_LF_DIR; CurItem.UncompressedSize := 0; CurItem.SaveTarHeaderToStream(NewStream); end else begin TempStream := TFileStream.Create(CurItem.DiskFileName, fmOpenRead or fmShareDenyWrite ); try { TempStream } CurItem.UncompressedSize := TempStream.Size; CurItem.StreamPosition := NewStream.Position;{ Reset the Stream Pointer. } CurItem.SaveTarHeaderToStream(NewStream); OutTarHelp.WriteArchiveItemSize(TempStream, TempStream.Size); finally { TempStream } TempStream.Free; end; { TempStream } end; finally {SaveDir} ChDir( SaveDir ); end; {SaveDir} except ItemList[i].Action := aaDelete; DoProcessItemFailure(ItemList[i], ptAdd, ecFileOpenError, 0); end; end; { aaAdd ... } end; { case } end; { for i ... } if NewStream.Size <> 0 then OutTarHelp.WriteArchiveTail; { Terminate the TAR } { Size of NewStream is still 0, and max of the stream will also be 0 } {copy new stream to FStream} NewStream.Position := 0; if (FStream is TMemoryStream) then TMemoryStream(FStream).LoadFromStream(NewStream) else if (FStream is TAbVirtualMemoryStream) or not FOwnsStream then begin FStream.Size := 0; FStream.Position := 0; FStream.CopyFrom(NewStream, NewStream.Size); end else begin { write to a new stream } FreeAndNil(FStream); FStream := TFileStream.Create(FArchiveName, fmCreate or fmShareDenyWrite); FStream.CopyFrom(NewStream, NewStream.Size); end; {update Items list} for i := pred( Count ) downto 0 do begin if ItemList[i].Action = aaDelete then FItemList.Delete( i ) else if ItemList[i].Action <> aaFailed then ItemList[i].Action := aaNone; end; DoArchiveSaveProgress( 100, Abort ); DoArchiveProgress( 100, Abort ); finally {NewStream/OutTarHelp} OutTarHelp.Free; NewStream.Free; end; end; { This assumes that LoadArchive has been called. } procedure TAbTarArchive.TestItemAt(Index: Integer); begin FStream.Position := TAbTarItem(FItemList[Index]).StreamPosition; if VerifyTar(FStream) <> atTar then raise EAbTarInvalid.Create; { Invalid Tar } end; end. ================================================ FILE: lib/abbrevia/source/AbUnzOutStm.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is Craig Peterson * * Portions created by the Initial Developer are Copyright (C) 2011 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Craig Peterson * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbUnzOutStm.pas *} {*********************************************************} {* ABBREVIA: UnZip output stream; progress and CRC32 *} {*********************************************************} unit AbUnzOutStm; {$I AbDefine.inc} interface uses SysUtils, Classes, AbArcTyp; type // Fixed-length read-only stream, limits reads to the range between // the input stream's starting position and a specified size. Seek/Position // are adjusted to be 0 based. TAbUnzipSubsetStream = class( TStream ) private FStream : TStream; FStartPos: Int64; FCurPos: Int64; FEndPos: Int64; public constructor Create(aStream: TStream; aStreamSize: Int64); function Read(var Buffer; Count: Longint): Longint; override; function Write(const Buffer; Count: Longint): Longint; override; function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override; end; // Write-only output stream, computes CRC32 and calls progress event TAbUnzipOutputStream = class( TStream ) private FBytesWritten : Int64; FCRC32 : LongInt; FCurrentProgress : Byte; FStream : TStream; FUncompressedSize : Int64; FOnProgress : TAbProgressEvent; function GetCRC32 : LongInt; public constructor Create(aStream : TStream); function Read(var Buffer; Count: Longint): Longint; override; function Write(const Buffer; Count: Longint): Longint; override; function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override; property CRC32 : LongInt read GetCRC32; property Stream : TStream read FStream write FStream; property UncompressedSize : Int64 read FUncompressedSize write FUncompressedSize; property OnProgress : TAbProgressEvent read FOnProgress write FOnProgress; end; implementation uses Math, AbExcept, AbUtils; { TAbUnzipSubsetStream implementation ====================================== } { -------------------------------------------------------------------------- } constructor TAbUnzipSubsetStream.Create(aStream: TStream; aStreamSize: Int64); begin inherited Create; FStream := aStream; FStartPos := FStream.Position; FCurPos := FStartPos; FEndPos := FStartPos + aStreamSize; end; { -------------------------------------------------------------------------- } function TAbUnzipSubsetStream.Read(var Buffer; Count: Longint): Longint; begin if Count > FEndPos - FCurPos then Count := FEndPos - FCurPos; if Count > 0 then begin Result := FStream.Read(Buffer, Count); Inc(FCurPos, Result); end else Result := 0; end; { -------------------------------------------------------------------------- } function TAbUnzipSubsetStream.Write(const Buffer; Count: Longint): Longint; begin raise EAbException.Create('TAbUnzipSubsetStream.Write not supported'); end; { -------------------------------------------------------------------------- } function TAbUnzipSubsetStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; var OldPos: Int64; begin OldPos := FCurPos; case Origin of soBeginning: FCurPos := FStartPos + Offset; soCurrent: FCurPos := FCurPos + Offset; soEnd: FCurPos := FEndPos + Offset; end; if FCurPos < FStartPos then FCurPos := FStartPos; if FCurPos > FEndPos then FCurPos := FEndPos; if OldPos <> FCurPos then FStream.Position := FCurPos; Result := FCurPos - FStartPos; end; { -------------------------------------------------------------------------- } { TAbUnzipOutputStream implementation ====================================== } { -------------------------------------------------------------------------- } constructor TAbUnzipOutputStream.Create(aStream: TStream); begin inherited Create; FStream := aStream; FCRC32 := -1; end; { -------------------------------------------------------------------------- } function TAbUnzipOutputStream.Read(var Buffer; Count: Integer): Longint; begin raise EAbException.Create('TAbUnzipOutputStream.Read not supported'); end; { -------------------------------------------------------------------------- } function TAbUnzipOutputStream.Write(const Buffer; Count: Longint): Longint; var Abort : Boolean; NewProgress : Byte; begin AbUpdateCRC( FCRC32, Buffer, Count ); Result := FStream.Write(Buffer, Count); Inc( FBytesWritten, Result ); if Assigned( FOnProgress ) then begin Abort := False; NewProgress := AbPercentage(FBytesWritten, FUncompressedSize); if (NewProgress <> FCurrentProgress) then begin FOnProgress( NewProgress, Abort ); FCurrentProgress := NewProgress; end; if Abort then raise EAbUserAbort.Create; end; end; { -------------------------------------------------------------------------- } function TAbUnzipOutputStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; begin Result := FStream.Seek(Offset, Origin); end; { -------------------------------------------------------------------------- } function TAbUnzipOutputStream.GetCRC32: LongInt; begin Result := not FCRC32; end; end. ================================================ FILE: lib/abbrevia/source/AbUnzPrc.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Craig Peterson * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbUnzPrc.pas *} {*********************************************************} {* ABBREVIA: UnZip procedures *} {*********************************************************} unit AbUnzPrc; {$I AbDefine.inc} interface uses Classes, AbArcTyp, AbZipTyp; type TAbUnzipHelper = class( TObject ) protected {private} {internal variables} FOutWriter : TStream; FOutStream : TStream; FUnCompressedSize : LongInt; FCompressionMethod : TAbZipCompressionMethod; FDictionarySize : TAbZipDictionarySize; FShannonFanoTreeCount : Byte; FOutBuf : PAbByteArray; {output buffer} FOutSent : LongInt; {number of bytes sent to output buffer} FOutPos : Cardinal; {current position in output buffer} FBitSValid : Byte; {Number of valid bits} FInBuf : TAbByteArray4K; FInPos : Integer; {current position in input buffer} FInCnt : Integer; {number of bytes in input buffer} FInEof : Boolean; {set when stream read returns 0} FCurByte : Byte; {current input byte} FBitsLeft : Byte; {bits left to process in FCurByte} FZStream : TStream; protected procedure uzFlushOutBuf; {-Flushes the output buffer} function uzReadBits(Bits : Byte) : Integer; {-Read the specified number of bits} procedure uzReadNextPrim; {-does less likely part of uzReadNext} {$IFDEF UnzipImplodeSupport} procedure uzUnImplode; {-Extract an imploded file} {$ENDIF} {$IFDEF UnzipReduceSupport} procedure uzUnReduce; {-Extract a reduced file} {$ENDIF} {$IFDEF UnzipShrinkSupport} procedure uzUnShrink; {-Extract a shrunk file} {$ENDIF} procedure uzWriteByte(B : Byte); {write to output} public constructor Create( InputStream, OutputStream : TStream ); destructor Destroy; override; procedure Execute; property UnCompressedSize : LongInt read FUncompressedSize write FUncompressedSize; property CompressionMethod : TAbZipCompressionMethod read FCompressionMethod write FCompressionMethod; property DictionarySize : TAbZipDictionarySize read FDictionarySize write FDictionarySize; property ShannonFanoTreeCount : Byte read FShannonFanoTreeCount write FShannonFanoTreeCount; end; procedure AbUnzipToStream( Sender : TObject; Item : TAbZipItem; OutStream : TStream); procedure AbUnzip(Sender : TObject; Item : TAbZipItem; const UseName : string); procedure AbTestZipItem(Sender : TObject; Item : TAbZipItem); procedure InflateStream(CompressedStream, UnCompressedStream : TStream); {-Inflates everything in CompressedStream to UncompressedStream no encryption is tried, no check on CRC is done, uses the whole compressedstream - no Progress events - no Frills!} implementation uses {$IFDEF MSWINDOWS} Windows, {$ENDIF} SysUtils, {$IFDEF UnzipBzip2Support} AbBzip2, {$ENDIF} {$IFDEF UnzipLzmaSupport} AbLzma, {$ENDIF} {$IFDEF UnzipPPMdSupport} AbPPMd, {$ENDIF} {$IFDEF UnzipWavPackSupport} AbWavPack, {$ENDIF} AbBitBkt, AbConst, AbDfBase, AbDfCryS, AbDfDec, AbExcept, AbSpanSt, AbSWStm, AbUnzOutStm, AbUtils; { -------------------------------------------------------------------------- } procedure AbReverseBits(var W : Word); {-Reverse the order of the bits in W} register; const RevTable : array[0..255] of Byte = ($00, $80, $40, $C0, $20, $A0, $60, $E0, $10, $90, $50, $D0, $30, $B0, $70, $F0, $08, $88, $48, $C8, $28, $A8, $68, $E8, $18, $98, $58, $D8, $38, $B8, $78, $F8, $04, $84, $44, $C4, $24, $A4, $64, $E4, $14, $94, $54, $D4, $34, $B4, $74, $F4, $0C, $8C, $4C, $CC, $2C, $AC, $6C, $EC, $1C, $9C, $5C, $DC, $3C, $BC, $7C, $FC, $02, $82, $42, $C2, $22, $A2, $62, $E2, $12, $92, $52, $D2, $32, $B2, $72, $F2, $0A, $8A, $4A, $CA, $2A, $AA, $6A, $EA, $1A, $9A, $5A, $DA, $3A, $BA, $7A, $FA, $06, $86, $46, $C6, $26, $A6, $66, $E6, $16, $96, $56, $D6, $36, $B6, $76, $F6, $0E, $8E, $4E, $CE, $2E, $AE, $6E, $EE, $1E, $9E, $5E, $DE, $3E, $BE, $7E, $FE, $01, $81, $41, $C1, $21, $A1, $61, $E1, $11, $91, $51, $D1, $31, $B1, $71, $F1, $09, $89, $49, $C9, $29, $A9, $69, $E9, $19, $99, $59, $D9, $39, $B9, $79, $F9, $05, $85, $45, $C5, $25, $A5, $65, $E5, $15, $95, $55, $D5, $35, $B5, $75, $F5, $0D, $8D, $4D, $CD, $2D, $AD, $6D, $ED, $1D, $9D, $5D, $DD, $3D, $BD, $7D, $FD, $03, $83, $43, $C3, $23, $A3, $63, $E3, $13, $93, $53, $D3, $33, $B3, $73, $F3, $0B, $8B, $4B, $CB, $2B, $AB, $6B, $EB, $1B, $9B, $5B, $DB, $3B, $BB, $7B, $FB, $07, $87, $47, $C7, $27, $A7, $67, $E7, $17, $97, $57, $D7, $37, $B7, $77, $F7, $0F, $8F, $4F, $CF, $2F, $AF, $6F, $EF, $1F, $9F, $5F, $DF, $3F, $BF, $7F, $FF); begin W := RevTable[Byte(W shr 8)] or Word(RevTable[Byte(W)] shl 8); end; { TAbUnzipHelper implementation ============================================ } { -------------------------------------------------------------------------- } constructor TAbUnzipHelper.Create( InputStream, OutputStream : TStream ); begin inherited Create; FOutBuf := AllocMem( AbBufferSize ); FOutPos := 0; FZStream := InputStream; FOutStream := OutputStream; FUncompressedSize := 0; FDictionarySize := dsInvalid; FShannonFanoTreeCount := 0; FCompressionMethod := cmDeflated; end; { -------------------------------------------------------------------------- } destructor TAbUnzipHelper.Destroy; begin FreeMem( FOutBuf, AbBufferSize ); inherited Destroy; end; { -------------------------------------------------------------------------- } procedure TAbUnzipHelper.Execute; begin {parent class handles exceptions via OnExtractFailure} FBitsLeft := 0; FCurByte := 0; FInCnt := 0; FOutSent := 0; FOutPos := 0; FInEof := False; {set the output stream; for Imploded/Reduced files this has to be buffered, for all other types of compression, the code buffers the output data nicely and so the given output stream can be used.} {$IFDEF UnzipImplodeSupport} if (FCompressionMethod = cmImploded) then FOutWriter := TabSlidingWindowStream.Create(FOutStream) else {$ENDIF} {$IFDEF UnzipReduceSupport} if (FCompressionMethod >= cmReduced1) and (FCompressionMethod <= cmReduced4) then FOutWriter := TabSlidingWindowStream.Create(FOutStream) else {$ENDIF} FOutWriter := FOutStream; FInPos := 1+SizeOf(FInBuf); { GetMem( FInBuf, SizeOf(FInBuf^) );} try {uncompress it with the appropriate method} case FCompressionMethod of {$IFDEF UnzipShrinkSupport} cmShrunk : uzUnshrink; {$ENDIF} {$IFDEF UnzipReduceSupport} cmReduced1..cmReduced4 : uzUnReduce; {$ENDIF} {$IFDEF UnzipImplodeSupport} cmImploded : uzUnImplode; {$ENDIF} {cmTokenized} {cmEnhancedDeflated} {cmDCLImploded} else raise EAbZipInvalidMethod.Create; end; finally uzFlushOutBuf; {free any memory} if (FOutWriter <> FOutStream) then FOutWriter.Free; end; end; { -------------------------------------------------------------------------- } procedure TAbUnzipHelper.uzReadNextPrim; begin FInCnt := FZStream.Read( FInBuf, sizeof( FInBuf ) ); FInEof := FInCnt = 0; {load first byte in buffer and set position counter} FCurByte := FInBuf[1]; FInPos := 2; end; { -------------------------------------------------------------------------- } procedure TAbUnzipHelper.uzFlushOutBuf; {-flushes the output buffer} begin if (FOutPos <> 0) then begin FOutWriter.Write( FOutBuf^, FOutPos ); Inc( FOutSent, FOutPos ); FOutPos := 0; end; end; { -------------------------------------------------------------------------- } procedure TAbUnzipHelper.uzWriteByte(B : Byte); {-Write one byte to the output buffer} begin FOutBuf^[FOutPos] := B; inc(FOutPos); if (FOutPos = AbBufferSize) or (LongInt(FOutPos) + FOutSent = FUncompressedSize) then uzFlushOutBuf; end; { -------------------------------------------------------------------------- } function TAbUnzipHelper.uzReadBits(Bits : Byte) : Integer; {-Read the specified number of bits} var SaveCurByte, Delta, SaveBitsLeft : Byte; begin {read next byte if we're out of bits} if FBitsLeft = 0 then begin {do we still have a byte buffered?} if FInPos <= FInCnt then begin {get next byte out of buffer and advance position counter} FCurByte := FInBuf[FInPos]; Inc(FInPos); end {are there any left to read?} else uzReadNextPrim; FBitsLeft := 8; end; if ( Bits < FBitsLeft ) then begin Dec( FBitsLeft, Bits ); Result := ((1 shl Bits) - 1) and FCurByte; FCurByte := FCurByte shr Bits; end else if ( Bits = FBitsLeft ) then begin Result := FCurByte; FCurByte := 0; FBitsLeft := 0; end else begin SaveCurByte := FCurByte; SaveBitsLeft := FBitsLeft; {number of additional bits that we need} Delta := Bits - FBitsLeft; {do we still have a byte buffered?} if FInPos <= FInCnt then begin {get next byte out of buffer and advance position counter} FCurByte := FInBuf[FInPos]; Inc(FInPos); end {are there any left to read?} else uzReadNextPrim; FBitsLeft := 8; Result := ( uzReadBits( Delta ) shl SaveBitsLeft ) or SaveCurByte; end; end; {$IFDEF UnzipImplodeSupport} { -------------------------------------------------------------------------- } procedure TAbUnzipHelper.uzUnImplode; {-Extract an imploded file} const szLengthTree = SizeOf(TAbSfTree)-(192*SizeOf(TAbSfEntry)); szDistanceTree = SizeOf(TAbSfTree)-(192*SizeOf(TAbSfEntry)); szLitTree = SizeOf(TAbSfTree); var Length : Integer; DIndex : LongInt; Distance : Integer; SPos : LongInt; MyByte : Byte; DictBits : Integer; {number of bits used in sliding dictionary} MinMatchLength : Integer; {minimum match length} LitTree : PAbSfTree; {Literal tree} LengthTree : PAbSfTree; {Length tree} DistanceTree : PAbSfTree; {Distance tree} procedure uzLoadTree(var T; TreeSize : Integer); {-Load one Shannon-Fano tree} var I : Word; Tree : TAbSfTree absolute T; procedure GenerateTree; {-Generate a Shannon-Fano tree} var C : Word; CodeIncrement : Integer; LastBitLength : Integer; I : Integer; begin C := 0; CodeIncrement := 0; LastBitLength := 0; for I := Tree.Entries-1 downto 0 do with Tree.Entry[I] do begin Inc(C, CodeIncrement); if BitLength <> LastBitLength then begin LastBitLength := BitLength; CodeIncrement := 1 shl (16-LastBitLength); end; Code := C; end; end; procedure SortLengths; {-Sort the bit lengths in ascending order, while retaining the order of the original lengths stored in the file} var XL : Integer; XGL : Integer; TXP : PAbSfEntry; TXGP : PAbSfEntry; X, Gap : Integer; Done : Boolean; LT : LongInt; begin Gap := Tree.Entries shr 1; repeat repeat Done := True; for X := 0 to (Tree.Entries-1)-Gap do begin TXP := @Tree.Entry[X]; TXGP := @Tree.Entry[X+Gap]; XL := TXP^.BitLength; XGL := TXGP^.BitLength; if (XL > XGL) or ((XL = XGL) and (TXP^.Value > TXGP^.Value)) then begin LT := TXP^.L; TXP^.L := TXGP^.L; TXGP^.L := LT; Done := False; end; end; until Done; Gap := Gap shr 1; until (Gap = 0); end; procedure uzReadLengths; {-Read bit lengths for a tree} var TreeBytes : Integer; I, J, K : Integer; Num, Len : Integer; B : Byte; begin {get number of bytes in compressed tree} TreeBytes := uzReadBits(8)+1; I := 0; Tree.MaxLength := 0; {High nibble: Number of values at this bit length + 1. Low nibble: Bits needed to represent value + 1} for J := 1 to TreeBytes do begin B := uzReadBits(8); Len := (B and $0F)+1; Num := (B shr 4)+1; for K := I to I+Num-1 do with Tree, Entry[K] do begin if Len > MaxLength then MaxLength := Len; BitLength := Len; Value := K; end; Inc(I, Num); end; end; begin Tree.Entries := TreeSize; uzReadLengths; SortLengths; GenerateTree; for I := 0 to TreeSize-1 do AbReverseBits(Tree.Entry[I].Code); end; function uzReadTree(var T) : Byte; {-Read next byte using a Shannon-Fano tree} var Bits : Integer; CV : Word; E : Integer; Cur : Integer; var Tree : TAbSfTree absolute T; begin Result := 0; Bits := 0; CV := 0; Cur := 0; E := Tree.Entries; repeat CV := CV or (uzReadBits(1) shl Bits); Inc(Bits); while Tree.Entry[Cur].BitLength < Bits do begin Inc(Cur); if Cur >= E then Exit; end; while Tree.Entry[Cur].BitLength = Bits do begin if Tree.Entry[Cur].Code = CV then begin Result := Tree.Entry[Cur].Value; Exit; end; Inc(Cur); if Cur >= E then Exit; end; until False; end; begin {do we have an 8K dictionary?} if FDictionarySize = ds8K then DictBits := 7 else DictBits := 6; {allocate trees} LengthTree := AllocMem(szLengthTree); DistanceTree := AllocMem(szDistanceTree); LitTree := nil; try {do we have a Literal tree?} MinMatchLength := FShannonFanoTreeCount; if MinMatchLength = 3 then begin LitTree := AllocMem(szLitTree); uzLoadTree(LitTree^, 256); end; {load the other two trees} uzLoadTree(LengthTree^, 64); uzLoadTree(DistanceTree^, 64); while (not FInEof) and (FOutSent + LongInt(FOutPos) < FUncompressedSize) do {is data literal?} if Boolean(uzReadBits(1)) then begin {if MinMatchLength = 3 then we have a Literal tree} if (MinMatchLength = 3) then uzWriteByte( uzReadTree(LitTree^) ) else uzWriteByte( uzReadBits(8) ); end else begin {data is a sliding dictionary} Distance := uzReadBits(DictBits); {using the Distance Shannon-Fano tree, read and decode the upper 6 bits of the Distance value} Distance := Distance or (uzReadTree(DistanceTree^) shl DictBits); {using the Length Shannon-Fano tree, read and decode the Length value} Length := uzReadTree(LengthTree^); if Length = 63 then Inc(Length, uzReadBits(8)); Inc(Length, MinMatchLength); {move backwards Distance+1 bytes in the output stream, and copy Length characters from this position to the output stream. (if this position is before the start of the output stream, then assume that all the data before the start of the output stream is filled with zeros)} DIndex := (FOutSent + LongInt(FOutPos))-(Distance+1); while Length > 0 do begin if DIndex < 0 then uzWriteByte(0) else begin uzFlushOutBuf; SPos := FOutWriter.Position; FOutWriter.Position := DIndex; FOutWriter.Read( MyByte, 1 ); FOutWriter.Position := SPos; uzWriteByte(MyByte); end; Inc(DIndex); Dec(Length); end; end; finally if (LitTree <> nil) then FreeMem(LitTree, szLitTree); FreeMem(LengthTree, szLengthTree); FreeMem(DistanceTree, szDistanceTree); end; end; {$ENDIF UnzipImplodeSupport} { -------------------------------------------------------------------------- } {$IFDEF UnzipReduceSupport} procedure TAbUnzipHelper.uzUnReduce; const FactorMasks : array[1..4] of Byte = ($7F, $3F, $1F, $0F); DLE = 144; var C, Last : Byte; OpI : LongInt; I, J, Sz : Integer; D : Word; SPos : LongInt; MyByte : Byte; Factor : Byte; {reduction Factor} FactorMask : Byte; {bit mask to use based on Factor} Followers : PAbFollowerSets; {array of follower sets} State : Integer; {used while processing reduced files} V : Integer; {"} Len : Integer; {"} function BitsNeeded( i : Byte ) : Word; begin dec( i ); Result := 0; repeat inc( Result ); i := i shr 1; until i = 0; end; begin GetMem(Followers, SizeOf(TAbFollowerSets)); try Factor := Ord( FCompressionMethod ) - 1; FactorMask := FactorMasks[Factor]; State := 0; C := 0; V := 0; Len := 0; D := 0; {load follower sets} for I := 255 downto 0 do begin Sz := uzReadBits(6); Followers^[I].Size := Sz; Dec(Sz); for J := 0 to Sz do Followers^[I].FSet[J] := uzReadBits(8); end; while (not FInEof) and ((FOutSent + LongInt(FOutPos)) < FUncompressedSize) do begin Last := C; with Followers^[Last] do if Size = 0 then C := uzReadBits(8) else begin C := uzReadBits(1); if C <> 0 then C := uzReadBits(8) else C := FSet[uzReadBits(BitsNeeded(Size))]; end; if FInEof then Exit; case State of 0 : if C <> DLE then uzWriteByte(C) else State := 1; 1 : if C <> 0 then begin V := C; Len := V and FactorMask; if Len = FactorMask then State := 2 else State := 3; end else begin uzWriteByte(DLE); State := 0; end; 2 : begin Inc(Len, C); State := 3; end; 3 : begin case Factor of 1 : D := (V shr 7) and $01; 2 : D := (V shr 6) and $03; 3 : D := (V shr 5) and $07; 4 : D := (V shr 4) and $0f; else raise EAbZipInvalidFactor.Create; end; {Delphi raises compiler Hints here, saying D might be undefined... If Factor is not in [1..4], the exception gets raised, and we never execute the following line} OpI := (FOutSent + LongInt(FOutPos))-(Swap(D)+C+1); for I := 0 to Len+2 do begin if OpI < 0 then uzWriteByte(0) else if OpI >= FOutSent then uzWriteByte(FOutBuf[OpI - FOutSent]) else begin SPos := FOutWriter.Position; FOutWriter.Position := OpI; FOutWriter.Read( MyByte, 1 ); FOutWriter.Position := SPos; uzWriteByte(MyByte); end; Inc(OpI); end; State := 0; end; end; end; finally FreeMem(Followers, SizeOf(Followers^)); end; end; {$ENDIF UnzipReduceSupport} { -------------------------------------------------------------------------- } {$IFDEF UnzipShrinkSupport} procedure TAbUnzipHelper.uzUnShrink; {-Extract a file that was shrunk} const MaxBits = 13; InitBits = 9; FirstFree = 257; Clear = 256; MaxCodeMax = 8192; {= 1 shl MaxBits} Unused = -1; var CodeSize : SmallInt; NextFree : SmallInt; BaseChar : SmallInt; NewCode : SmallInt; OldCode : SmallInt; SaveCode : SmallInt; N, R : SmallInt; I : Integer; PrefixTable : PAbIntArray8K; {used while processing shrunk files} SuffixTable : PAbByteArray8K; {"} Stack : PAbByteArray8K; {"} StackIndex : Integer; {"} begin CodeSize := InitBits; { MaxCode := (1 shl InitBits)-1;} NextFree := FirstFree; PrefixTable := nil; SuffixTable := nil; Stack := nil; try GetMem(PrefixTable, SizeOf(PrefixTable^)); SuffixTable := AllocMem(SizeOf(SuffixTable^)); GetMem(Stack, SizeOf(Stack^)); FillChar(PrefixTable^, SizeOf(PrefixTable^), $FF); for NewCode := 255 downto 0 do begin PrefixTable^[NewCode] := 0; SuffixTable^[NewCode] := NewCode; end; OldCode := uzReadBits(CodeSize); if FInEof then Exit; BaseChar := OldCode; uzWriteByte(BaseChar); StackIndex := 0; while (not FInEof) do begin NewCode := uzReadBits(CodeSize); while (NewCode = Clear) and (not FInEof) do begin case uzReadBits(CodeSize) of 1 : begin Inc(CodeSize); end; 2 : begin {mark all nodes as potentially unused} for I := FirstFree to pred( NextFree ) do PrefixTable^[I] := PrefixTable^[I] or LongInt($8000); {unmark those used by other nodes} for N := FirstFree to NextFree-1 do begin {reference to another node?} R := PrefixTable^[N] and $7FFF; {flag node as referenced} if R >= FirstFree then PrefixTable^[R] := PrefixTable^[R] and $7FFF; end; {clear the ones that are still marked} for I := FirstFree to pred( NextFree ) do if PrefixTable^[I] < 0 then PrefixTable^[I] := -1; {recalculate NextFree} NextFree := FirstFree; while (NextFree < MaxCodeMax) and (PrefixTable^[NextFree] <> -1) do Inc(NextFree); end; end; NewCode := uzReadBits(CodeSize); end; if FInEof then Exit; {save current code} SaveCode := NewCode; {special case} if PrefixTable^[NewCode] = Unused then begin Stack^[StackIndex] := BaseChar; Inc(StackIndex); NewCode := OldCode; end; {generate output characters in reverse order} while (NewCode >= FirstFree) do begin if PrefixTable^[NewCode] = Unused then begin Stack^[StackIndex] := BaseChar; Inc(StackIndex); NewCode := OldCode; end else begin Stack^[StackIndex] := SuffixTable^[NewCode]; Inc(StackIndex); NewCode := PrefixTable^[NewCode]; end; end; BaseChar := SuffixTable^[NewCode]; uzWriteByte(BaseChar); {put them out in forward order} while (StackIndex > 0) do begin Dec(StackIndex); uzWriteByte(Stack^[StackIndex]); end; {add new entry to tables} NewCode := NextFree; if NewCode < MaxCodeMax then begin PrefixTable^[NewCode] := OldCode; SuffixTable^[NewCode] := BaseChar; while (NextFree < MaxCodeMax) and (PrefixTable^[NextFree] <> Unused) do Inc(NextFree); end; {remember previous code} OldCode := SaveCode; end; finally FreeMem(PrefixTable, SizeOf(PrefixTable^)); FreeMem(SuffixTable, SizeOf(SuffixTable^)); FreeMem(Stack, SizeOf(Stack^)); end; end; {$ENDIF} { -------------------------------------------------------------------------- } procedure RequestPassword(Archive : TAbZipArchive; var Abort : Boolean); var APassPhrase : AnsiString; begin APassPhrase := Archive.Password; Abort := False; if Assigned(Archive.OnNeedPassword) then begin Archive.OnNeedPassword(Archive, APassPhrase); if APassPhrase = '' then Abort := True else Archive.Password := APassPhrase; end; end; { -------------------------------------------------------------------------- } procedure CheckPassword(Archive : TAbZipArchive; var Tries : Integer; var Abort : Boolean); begin { if current password empty } if Archive.Password = '' then begin { request password } RequestPassword(Archive, Abort); { increment tries } Inc(Tries); end; { if current password still empty } if Archive.Password = '' then begin { abort } raise EAbZipInvalidPassword.Create; end; end; { -------------------------------------------------------------------------- } procedure DoInflate(Archive : TAbZipArchive; Item : TAbZipItem; InStream, OutStream : TStream); var Hlpr : TAbDeflateHelper; begin Hlpr := TAbDeflateHelper.Create; try if Item.CompressionMethod = cmEnhancedDeflated then Hlpr.Options := Hlpr.Options or dfc_UseDeflate64; Hlpr.StreamSize := Item.CompressedSize; Inflate(InStream, OutStream, Hlpr); finally Hlpr.Free; end; end; { -------------------------------------------------------------------------- } procedure DoLegacyUnzip(Archive : TAbZipArchive; Item : TAbZipItem; InStream, OutStream : TStream); var Helper : TAbUnzipHelper; begin Helper := TAbUnzipHelper.Create(InStream, OutStream); try {Helper} Helper.DictionarySize := Item.DictionarySize; Helper.UnCompressedSize := Item.UncompressedSize; Helper.CompressionMethod := Item.CompressionMethod; Helper.ShannonFanoTreeCount := Item.ShannonFanoTreeCount; Helper.Execute; finally Helper.Free; end; end; { -------------------------------------------------------------------------- } {$IFDEF UnzipBzip2Support} procedure DoExtractBzip2(Archive : TAbZipArchive; Item : TAbZipItem; InStream, OutStream : TStream); var Bzip2Stream: TStream; begin Bzip2Stream := TBZDecompressionStream.Create(InStream); try OutStream.CopyFrom(Bzip2Stream, Item.UncompressedSize); finally Bzip2Stream.Free; end; end; {$ENDIF} { -------------------------------------------------------------------------- } {$IFDEF UnzipLzmaSupport} procedure DoExtractLzma(Archive : TAbZipArchive; Item : TAbZipItem; InStream, OutStream : TStream); var Header: packed record MajorVer, MinorVer: Byte; PropSize: Word; end; Properties: array of Byte; begin InStream.ReadBuffer(Header, SizeOf(Header)); SetLength(Properties, Header.PropSize); InStream.ReadBuffer(Properties[0], Header.PropSize); LzmaDecodeStream(PByte(Properties), Header.PropSize, InStream, OutStream, Item.UncompressedSize); end; {$ENDIF} { -------------------------------------------------------------------------- } function ExtractPrep(ZipArchive: TAbZipArchive; Item: TAbZipItem): TStream; var LFH : TAbZipLocalFileHeader; Abort : Boolean; Tries : Integer; CheckValue : LongInt; DecryptStream: TAbDfDecryptStream; begin { validate } if (Lo(Item.VersionNeededToExtract) > Ab_ZipVersion) then raise EAbZipVersion.Create; { seek to compressed file } if ZipArchive.FStream is TAbSpanReadStream then TAbSpanReadStream(ZipArchive.FStream).SeekImage(Item.DiskNumberStart, Item.RelativeOffset) else ZipArchive.FStream.Position := Item.RelativeOffset; { get local header info for Item} LFH := TAbZipLocalFileHeader.Create; try { select appropriate CRC value based on General Purpose Bit Flag } { also get whether the file is stored, while we've got the local file header } LFH.LoadFromStream(ZipArchive.FStream); if (LFH.GeneralPurposeBitFlag and AbHasDataDescriptorFlag = AbHasDataDescriptorFlag) then { if bit 3 is set, then the data descriptor record is appended to the compressed data } CheckValue := LFH.LastModFileTime shl $10 else CheckValue := Item.CRC32; finally LFH.Free; end; Result := TAbUnzipSubsetStream.Create(ZipArchive.FStream, Item.CompressedSize); { get decrypting stream } if Item.IsEncrypted then begin try { need to decrypt } Tries := 0; Abort := False; CheckPassword(ZipArchive, Tries, Abort); while True do begin if Abort then raise EAbUserAbort.Create; { check for valid password } DecryptStream := TAbDfDecryptStream.Create(Result, CheckValue, ZipArchive.Password); if DecryptStream.IsValid then begin DecryptStream.OwnsStream := True; Result := DecryptStream; Break; end; FreeAndNil(DecryptStream); { prompt again } Inc(Tries); if (Tries > ZipArchive.PasswordRetries) then raise EAbZipInvalidPassword.Create; RequestPassword(ZipArchive, Abort); end; except Result.Free; raise; end; end; end; { -------------------------------------------------------------------------- } procedure DoExtract(aZipArchive: TAbZipArchive; aItem: TAbZipItem; aInStream, aOutStream: TStream); var OutStream : TAbUnzipOutputStream; begin if aItem.UncompressedSize = 0 then Exit; OutStream := TAbUnzipOutputStream.Create(aOutStream); try OutStream.UncompressedSize := aItem.UncompressedSize; OutStream.OnProgress := aZipArchive.OnProgress; { determine storage type } case aItem.CompressionMethod of cmStored: begin { unstore aItem } OutStream.CopyFrom(aInStream, aItem.UncompressedSize); end; cmDeflated, cmEnhancedDeflated: begin { inflate aItem } DoInflate(aZipArchive, aItem, aInStream, OutStream); end; {$IFDEF UnzipBzip2Support} cmBzip2: begin DoExtractBzip2(aZipArchive, aItem, aInStream, OutStream); end; {$ENDIF} {$IFDEF UnzipLzmaSupport} cmLZMA: begin DoExtractLzma(aZipArchive, aItem, aInStream, OutStream); end; {$ENDIF} {$IFDEF UnzipPPMdSupport} cmPPMd: begin DecompressPPMd(aInStream, OutStream); end; {$ENDIF} {$IFDEF UnzipWavPackSupport} cmWavPack: begin DecompressWavPack(aInStream, OutStream); end; {$ENDIF} cmShrunk..cmImploded: begin DoLegacyUnzip(aZipArchive, aItem, aInStream, OutStream); end; else raise EAbZipInvalidMethod.Create; end; { check CRC } if OutStream.CRC32 <> aItem.CRC32 then if Assigned(aZipArchive.OnProcessItemFailure) then aZipArchive.OnProcessItemFailure(aZipArchive, aItem, ptExtract, ecAbbrevia, AbZipBadCRC) else raise EAbZipBadCRC.Create; finally OutStream.Free; end; end; { -------------------------------------------------------------------------- } procedure AbUnzipToStream( Sender : TObject; Item : TAbZipItem; OutStream : TStream); var ZipArchive : TAbZipArchive; InStream : TStream; begin ZipArchive := Sender as TAbZipArchive; if not Assigned(OutStream) then raise EAbBadStream.Create; InStream := ExtractPrep(ZipArchive, Item); try DoExtract(ZipArchive, Item, InStream, OutStream); finally InStream.Free end; end; { -------------------------------------------------------------------------- } procedure AbUnzip(Sender : TObject; Item : TAbZipItem; const UseName : string); {create the output filestream and pass it to DoExtract} var InStream, OutStream : TStream; ZipArchive : TAbZipArchive; begin ZipArchive := TAbZipArchive(Sender); if Item.IsDirectory then AbCreateDirectory(UseName) else begin InStream := ExtractPrep(ZipArchive, Item); try OutStream := TFileStream.Create(UseName, fmCreate or fmShareDenyWrite); try try {OutStream} DoExtract(ZipArchive, Item, InStream, OutStream); finally {OutStream} OutStream.Free; end; {OutStream} except if ExceptObject is EAbUserAbort then ZipArchive.FStatus := asInvalid; DeleteFile(UseName); raise; end; finally InStream.Free end; end; AbSetFileTime(UseName, Item.LastModTimeAsDateTime); AbSetFileAttr(UseName, Item.NativeFileAttributes); end; { -------------------------------------------------------------------------- } procedure AbTestZipItem(Sender : TObject; Item : TAbZipItem); {extract item to bit bucket and verify its local file header} var BitBucket : TAbBitBucketStream; FieldSize : Word; LFH : TAbZipLocalFileHeader; Zip64Field : PZip64LocalHeaderRec; ZipArchive : TAbZipArchive; begin ZipArchive := TAbZipArchive(Sender); if (Lo(Item.VersionNeededToExtract) > Ab_ZipVersion) then raise EAbZipVersion.Create; { seek to compressed file } if ZipArchive.FStream is TAbSpanReadStream then TAbSpanReadStream(ZipArchive.FStream).SeekImage(Item.DiskNumberStart, Item.RelativeOffset) else ZipArchive.FStream.Position := Item.RelativeOffset; BitBucket := nil; LFH := nil; try BitBucket := TAbBitBucketStream.Create(0); LFH := TAbZipLocalFileHeader.Create; {get the item's local file header} ZipArchive.FStream.Seek(Item.RelativeOffset, soBeginning); LFH.LoadFromStream(ZipArchive.FStream); ZipArchive.FStream.Seek(Item.RelativeOffset, soBeginning); {currently a single exception is raised for any LFH error} if (LFH.VersionNeededToExtract <> Item.VersionNeededToExtract) then raise EAbZipInvalidLFH.Create; if (LFH.GeneralPurposeBitFlag <> Item.GeneralPurposeBitFlag) then raise EAbZipInvalidLFH.Create; if (LFH.LastModFileTime <> Item.LastModFileTime) then raise EAbZipInvalidLFH.Create; if (LFH.LastModFileDate <> Item.LastModFileDate) then raise EAbZipInvalidLFH.Create; if (LFH.CRC32 <> Item.CRC32) then raise EAbZipInvalidLFH.Create; if LFH.ExtraField.Get(Ab_Zip64SubfieldID, Pointer(Zip64Field), FieldSize) then begin if (Zip64Field.CompressedSize <> Item.CompressedSize) then raise EAbZipInvalidLFH.Create; if (Zip64Field.UncompressedSize <> Item.UncompressedSize) then raise EAbZipInvalidLFH.Create; end else begin if (LFH.CompressedSize <> Item.CompressedSize) then raise EAbZipInvalidLFH.Create; if (LFH.UncompressedSize <> Item.UncompressedSize) then raise EAbZipInvalidLFH.Create; end; if (LFH.FileName <> Item.RawFileName) then raise EAbZipInvalidLFH.Create; {any CRC errors will raise exception during extraction} AbUnZipToStream(Sender, Item, BitBucket); finally BitBucket.Free; LFH.Free; end; end; { -------------------------------------------------------------------------- } procedure InflateStream( CompressedStream, UnCompressedStream : TStream ); {-Inflates everything in CompressedStream to UncompressedStream no encryption is tried, no check on CRC is done, uses the whole compressedstream - no Progress events - no Frills!} begin Inflate(CompressedStream, UncompressedStream, nil); end; end. ================================================ FILE: lib/abbrevia/source/AbUnzper.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: ABUnzper.pas *} {*********************************************************} {* ABBREVIA: Non-visual Component with UnZip support *} {*********************************************************} unit AbUnzper; {$I AbDefine.inc} interface uses Classes, AbZBrows, AbArcTyp, AbZipTyp; type TAbCustomUnZipper = class(TAbCustomZipBrowser) protected {private} FExtractOptions : TAbExtractOptions; FOnConfirmOverwrite : TAbConfirmOverwriteEvent; FOnNeedPassword : TAbNeedPasswordEvent; FPasswordRetries : Byte; protected {methods} procedure DoConfirmOverwrite(var Name : string; var Confirm : Boolean); virtual; procedure DoNeedPassword(Sender : TObject; var NewPassword : AnsiString); virtual; procedure InitArchive; override; procedure SetExtractOptions(Value : TAbExtractOptions); procedure SetPasswordRetries(Value : Byte); procedure UnzipProc(Sender : TObject; Item : TAbArchiveItem; const NewName : string ); procedure UnzipToStreamProc(Sender : TObject; Item : TAbArchiveItem; OutStream : TStream); procedure TestItemProc(Sender : TObject; Item : TAbArchiveItem); procedure SetFileName(const aFileName : string); override; protected {properties} property ExtractOptions : TAbExtractOptions read FExtractOptions write SetExtractOptions default AbDefExtractOptions; property OnConfirmOverwrite : TAbConfirmOverwriteEvent read FOnConfirmOverwrite write FOnConfirmOverwrite; property OnNeedPassword : TAbNeedPasswordEvent read FOnNeedPassword write FOnNeedPassword; property PasswordRetries : Byte read FPasswordRetries write SetPasswordRetries default AbDefPasswordRetries; public {methods} constructor Create( AOwner : TComponent ); override; destructor Destroy; override; procedure ExtractAt(Index : Integer; const NewName : string); procedure ExtractFiles(const FileMask : string); procedure ExtractFilesEx(const FileMask, ExclusionMask : string); procedure ExtractToStream(const aFileName : string; ToStream : TStream); procedure ExtractTaggedItems; procedure TestTaggedItems; end; TAbUnZipper = class(TAbCustomUnZipper) published property ArchiveProgressMeter; property ItemProgressMeter; property BaseDirectory; property ExtractOptions; property LogFile; property Logging; property OnArchiveProgress; property OnArchiveItemProgress; property OnChange; property OnConfirmOverwrite; property OnConfirmProcessItem; property OnLoad; property OnNeedPassword; property OnRequestImage; property OnProcessItemFailure; property OnRequestLastDisk; property OnRequestNthDisk; property Password; property PasswordRetries; property TempDirectory; property Version; property FileName; {must be after OnLoad} end; implementation uses SysUtils, AbUtils, AbExcept, AbUnzPrc; { -------------------------------------------------------------------------- } constructor TAbCustomUnZipper.Create( AOwner : TComponent ); begin inherited Create(AOwner); ExtractOptions := AbDefExtractOptions; PasswordRetries := AbDefPasswordRetries; end; { -------------------------------------------------------------------------- } destructor TAbCustomUnZipper.Destroy; begin inherited Destroy; end; { -------------------------------------------------------------------------- } procedure TAbCustomUnZipper.DoConfirmOverwrite(var Name : string; var Confirm : Boolean); begin Confirm := True; if Assigned(FOnConfirmOverwrite) then FOnConfirmOverwrite( Name, Confirm ); end; { -------------------------------------------------------------------------- } procedure TAbCustomUnZipper.DoNeedPassword(Sender : TObject; var NewPassword : AnsiString); begin if Assigned(FOnNeedPassword) then begin FOnNeedPassword(Self, NewPassword); Password := NewPassword; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomUnZipper.ExtractAt(Index : Integer; const NewName : string); {extract a file from the archive that match the index} begin if (FArchive <> nil) then FArchive.ExtractAt(Index, NewName) else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomUnZipper.ExtractFiles(const FileMask : string); {extract all files from the archive that match the mask} begin if (FArchive <> nil) then FArchive.ExtractFiles( FileMask ) else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomUnZipper.ExtractFilesEx(const FileMask, ExclusionMask : string); {extract files matching FileMask except those matching ExclusionMask} begin if (FArchive <> nil) then FArchive.ExtractFilesEx(FileMask, ExclusionMask) else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomUnZipper.ExtractToStream(const aFileName : string; ToStream : TStream); begin if (FArchive <> nil) then FArchive.ExtractToStream(aFileName, ToStream) else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomUnZipper.ExtractTaggedItems; {extract all tagged items from the archive} begin if (FArchive <> nil) then FArchive.ExtractTaggedItems else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomUnZipper.InitArchive; begin inherited InitArchive; if FArchive <> nil then begin FArchive.ExtractOptions := FExtractOptions; FArchive.OnConfirmOverwrite := DoConfirmOverwrite; end; if FArchive is TAbZipArchive then begin TAbZipArchive(FArchive).PasswordRetries := FPasswordRetries; TAbZipArchive(FArchive).OnNeedPassword := DoNeedPassword; TAbZipArchive(FArchive).TestHelper := TestItemProc; TAbZipArchive(FArchive).ExtractHelper := UnzipProc; TAbZipArchive(FArchive).ExtractToStreamHelper := UnzipToStreamProc; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomUnZipper.SetExtractOptions(Value : TAbExtractOptions); begin FExtractOptions := Value; if (FArchive <> nil) then FArchive.ExtractOptions := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomUnZipper.SetPasswordRetries(Value : Byte); begin FPasswordRetries := Value; if FArchive is TAbZipArchive then TAbZipArchive(FArchive).PasswordRetries := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomUnZipper.TestTaggedItems; {Test specified items} begin if (FArchive <> nil) then FArchive.TestTaggedItems else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomUnZipper.UnzipProc(Sender : TObject; Item : TAbArchiveItem; const NewName : string); begin AbUnzip( TAbZipArchive(Sender), TAbZipItem(Item), NewName); end; { -------------------------------------------------------------------------- } procedure TAbCustomUnZipper.UnzipToStreamProc(Sender : TObject; Item : TAbArchiveItem; OutStream : TStream); begin AbUnzipToStream(TAbZipArchive(Sender), TAbZipItem(Item), OutStream); end; { -------------------------------------------------------------------------- } procedure TAbCustomUnZipper.TestItemProc(Sender : TObject; Item : TAbArchiveItem); begin AbTestZipItem(TAbZipArchive(Sender), TAbZipItem(Item)); end; { -------------------------------------------------------------------------- } procedure TAbCustomUnZipper.SetFileName(const aFileName: string); begin if aFileName <> '' then begin if not FileExists(aFileName) then raise EAbFileNotFound.Create; if AbFileGetSize(aFileName) <= 0 then raise EAbBadStream.Create; end; inherited SetFileName(aFileName); end; end. ================================================ FILE: lib/abbrevia/source/AbUtils.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbUtils.pas *} {*********************************************************} {* ABBREVIA: Utility classes and routines *} {*********************************************************} unit AbUtils; {$I AbDefine.inc} interface uses {$IFDEF MSWINDOWS} Windows, {$ENDIF} {$IFDEF LibcAPI} Libc, {$ENDIF} {$IFDEF FPCUnixAPI} baseunix, {$IFDEF Linux} initc, {$ENDIF} unix, {$ENDIF} {$IFDEF PosixAPI} Posix.SysStatvfs, Posix.SysStat, Posix.Utime, Posix.Base, Posix.Unistd, Posix.Fcntl, Posix.SysTypes, {$ENDIF} {$IFDEF UNIX} DateUtils, {$ENDIF} {$IFDEF HasAnsiStrings} System.AnsiStrings, {$ENDIF} SysUtils, Classes, AbCharset; type {describe the pending action for an archive item} TAbArchiveAction = (aaFailed, aaNone, aaAdd, aaDelete, aaFreshen, aaMove, aaReplace, aaStreamAdd); TAbProcessType = (ptAdd, ptDelete, ptExtract, ptFreshen, ptMove, ptReplace, ptFoundUnhandled); TAbLogType = (ltAdd, ltDelete, ltExtract, ltFreshen, ltMove, ltReplace, ltStart, ltFoundUnhandled); TAbErrorClass = (ecAbbrevia, ecInOutError, ecFilerError, ecFileCreateError, ecFileOpenError, ecCabError, ecOther); const AbPathDelim = PathDelim; { Delphi/Linux constant } AbPathSep = PathSep; { Delphi/Linux constant } AbDosPathDelim = '\'; AbUnixPathDelim = '/'; AbDosPathSep = ';'; AbUnixPathSep = ':'; AbDosAnyFile = '*.*'; AbUnixAnyFile = '*'; AbAnyFile = {$IFDEF UNIX} AbUnixAnyFile; {$ELSE} AbDosAnyFile; {$ENDIF} AbThisDir = '.'; AbParentDir = '..'; type TAbArchiveType = (atUnknown, atZip, atSpannedZip, atSelfExtZip, atTar, atGzip, atGzippedTar, atCab, atBzip2, atBzippedTar); {$IF NOT DECLARED(DWORD)} type DWORD = LongWord; {$IFEND} {$IF NOT DECLARED(PtrInt)} type // Delphi 7-2007 declared NativeInt incorrectly {$IFDEF CPU386} PtrInt = LongInt; PtrUInt = LongWord; {$ELSE} PtrInt = NativeInt; PtrUInt = NativeUInt; {$ENDIF} {$IFEND} { System-encoded SBCS string (formerly AnsiString) } type AbSysString = {$IFDEF Posix}UTF8String{$ELSE}AnsiString{$ENDIF}; const AbCrc32Table : array[0..255] of DWord = ( $00000000, $77073096, $ee0e612c, $990951ba, $076dc419, $706af48f, $e963a535, $9e6495a3, $0edb8832, $79dcb8a4, $e0d5e91e, $97d2d988, $09b64c2b, $7eb17cbd, $e7b82d07, $90bf1d91, $1db71064, $6ab020f2, $f3b97148, $84be41de, $1adad47d, $6ddde4eb, $f4d4b551, $83d385c7, $136c9856, $646ba8c0, $fd62f97a, $8a65c9ec, $14015c4f, $63066cd9, $fa0f3d63, $8d080df5, $3b6e20c8, $4c69105e, $d56041e4, $a2677172, $3c03e4d1, $4b04d447, $d20d85fd, $a50ab56b, $35b5a8fa, $42b2986c, $dbbbc9d6, $acbcf940, $32d86ce3, $45df5c75, $dcd60dcf, $abd13d59, $26d930ac, $51de003a, $c8d75180, $bfd06116, $21b4f4b5, $56b3c423, $cfba9599, $b8bda50f, $2802b89e, $5f058808, $c60cd9b2, $b10be924, $2f6f7c87, $58684c11, $c1611dab, $b6662d3d, $76dc4190, $01db7106, $98d220bc, $efd5102a, $71b18589, $06b6b51f, $9fbfe4a5, $e8b8d433, $7807c9a2, $0f00f934, $9609a88e, $e10e9818, $7f6a0dbb, $086d3d2d, $91646c97, $e6635c01, $6b6b51f4, $1c6c6162, $856530d8, $f262004e, $6c0695ed, $1b01a57b, $8208f4c1, $f50fc457, $65b0d9c6, $12b7e950, $8bbeb8ea, $fcb9887c, $62dd1ddf, $15da2d49, $8cd37cf3, $fbd44c65, $4db26158, $3ab551ce, $a3bc0074, $d4bb30e2, $4adfa541, $3dd895d7, $a4d1c46d, $d3d6f4fb, $4369e96a, $346ed9fc, $ad678846, $da60b8d0, $44042d73, $33031de5, $aa0a4c5f, $dd0d7cc9, $5005713c, $270241aa, $be0b1010, $c90c2086, $5768b525, $206f85b3, $b966d409, $ce61e49f, $5edef90e, $29d9c998, $b0d09822, $c7d7a8b4, $59b33d17, $2eb40d81, $b7bd5c3b, $c0ba6cad, $edb88320, $9abfb3b6, $03b6e20c, $74b1d29a, $ead54739, $9dd277af, $04db2615, $73dc1683, $e3630b12, $94643b84, $0d6d6a3e, $7a6a5aa8, $e40ecf0b, $9309ff9d, $0a00ae27, $7d079eb1, $f00f9344, $8708a3d2, $1e01f268, $6906c2fe, $f762575d, $806567cb, $196c3671, $6e6b06e7, $fed41b76, $89d32be0, $10da7a5a, $67dd4acc, $f9b9df6f, $8ebeeff9, $17b7be43, $60b08ed5, $d6d6a3e8, $a1d1937e, $38d8c2c4, $4fdff252, $d1bb67f1, $a6bc5767, $3fb506dd, $48b2364b, $d80d2bda, $af0a1b4c, $36034af6, $41047a60, $df60efc3, $a867df55, $316e8eef, $4669be79, $cb61b38c, $bc66831a, $256fd2a0, $5268e236, $cc0c7795, $bb0b4703, $220216b9, $5505262f, $c5ba3bbe, $b2bd0b28, $2bb45a92, $5cb36a04, $c2d7ffa7, $b5d0cf31, $2cd99e8b, $5bdeae1d, $9b64c2b0, $ec63f226, $756aa39c, $026d930a, $9c0906a9, $eb0e363f, $72076785, $05005713, $95bf4a82, $e2b87a14, $7bb12bae, $0cb61b38, $92d28e9b, $e5d5be0d, $7cdcefb7, $0bdbdf21, $86d3d2d4, $f1d4e242, $68ddb3f8, $1fda836e, $81be16cd, $f6b9265b, $6fb077e1, $18b74777, $88085ae6, $ff0f6a70, $66063bca, $11010b5c, $8f659eff, $f862ae69, $616bffd3, $166ccf45, $a00ae278, $d70dd2ee, $4e048354, $3903b3c2, $a7672661, $d06016f7, $4969474d, $3e6e77db, $aed16a4a, $d9d65adc, $40df0b66, $37d83bf0, $a9bcae53, $debb9ec5, $47b2cf7f, $30b5ffe9, $bdbdf21c, $cabac28a, $53b39330, $24b4a3a6, $bad03605, $cdd70693, $54de5729, $23d967bf, $b3667a2e, $c4614ab8, $5d681b02, $2a6f2b94, $b40bbe37, $c30c8ea1, $5a05df1b, $2d02ef8d ); type TAbPathType = ( ptNone, ptRelative, ptAbsolute ); {===Helper functions===} function AbCopyFile(const Source, Destination: string; FailIfExists: Boolean): Boolean; procedure AbCreateDirectory( const Path : string ); {creates the requested directory tree. CreateDir is insufficient, because if you have a path x:\dir, and request x:\dir\sub1\sub2, (/dir and /dir/sub1/sub2 on Unix) it fails.} function AbCreateTempFile(const Dir : string) : string; function AbGetTempDirectory : string; {-Return the system temp directory} function AbGetTempFile(const Dir : string; CreateIt : Boolean) : string; function AbDrive(const ArchiveName : string) : Char; function AbDriveIsRemovable(const ArchiveName : string) : Boolean; function AbFileMatch(FileName : string; FileMask : string ) : Boolean; {see if FileName matches FileMask} procedure AbFindFiles(const FileMask : string; SearchAttr : Integer; FileList : TStrings; Recurse : Boolean ); procedure AbFindFilesEx( const FileMask : string; SearchAttr : Integer; FileList : TStrings; Recurse : Boolean ); function AbAddBackSlash(const DirName : string) : string; function AbFindNthSlash( const Path : string; n : Integer ) : Integer; {return the position of the character just before the nth backslash} function AbGetDriveFreeSpace(const ArchiveName : string) : Int64; {return the available space on the specified drive } function AbGetPathType( const Value : string ) : TAbPathType; {returns path type - none, relative or absolute} {$IFDEF MSWINDOWS} function AbGetShortFileSpec(const LongFileSpec : string ) : string; {$ENDIF} procedure AbIncFilename( var Filename : string; Value : Word ); procedure AbParseFileName( FileSpec : string; out Drive : string; out Path : string; out FileName : string ); procedure AbParsePath( Path : string; SubPaths : TStrings ); {- break abart path into subpaths --- Path : abbrevia/examples -> SubPaths[0] = abbrevia SubPaths[1] = examples} function AbPatternMatch(const Source : string; iSrc : Integer; const Pattern : string; iPat : Integer ) : Boolean; { recursive routine to see if the source string matches the pattern. Both ? and * wildcard characters are allowed.} function AbPercentage(V1, V2 : Int64) : Byte; {-Returns the ratio of V1 to V2 * 100} procedure AbStripDots( var FName : string ); {-strips relative path information} procedure AbStripDrive( var FName : string ); {-strips the drive off a filename} procedure AbFixName( var FName : string ); {-changes backslashes to forward slashes} procedure AbUnfixName( var FName : string ); {-changes forward slashes to backslashes} procedure AbUpdateCRC( var CRC : LongInt; const Buffer; Len : Integer ); function AbUpdateCRC32(CurByte : Byte; CurCrc : LongInt) : LongInt; {-Returns an updated crc32} function AbCRC32Of( const aValue : RawByteString ) : LongInt; function AbWriteVolumeLabel(const VolName : string; Drive : Char) : Cardinal; const AB_SPAN_VOL_LABEL = 'PKBACK# %3.3d'; function AbGetVolumeLabel(Drive : Char) : string; procedure AbSetSpanVolumeLabel(Drive: Char; VolNo : Integer); function AbTestSpanVolumeLabel(Drive: Char; VolNo : Integer): Boolean; procedure AbSetFileAttr(const aFileName : string; aAttr: Integer); {-Sets platform-native file attributes (DOS attr or Unix mode)} function AbFileGetSize(const aFileName : string) : Int64; type TAbAttrExRec = record Time: TDateTime; Size: Int64; Attr: Integer; Mode: {$IFDEF UNIX}mode_t{$ELSE}Cardinal{$ENDIF}; end; function AbFileGetAttrEx(const aFileName: string; out aAttr: TAbAttrExRec) : Boolean; function AbSwapLongEndianness(Value : LongInt): LongInt; { date and time stuff } const Date1900 {: LongInt} = $0001AC05; {Julian day count for 01/01/1900 -- TDateTime Start Date} Date1970 {: LongInt} = $00020FE4; {Julian day count for 01/01/1970 -- Unix Start Date} Unix0Date: TDateTime = 25569; {Date1970 - Date1900} SecondsInDay = 86400; {Number of seconds in a day} SecondsInHour = 3600; {Number of seconds in an hour} SecondsInMinute = 60; {Number of seconds in a minute} HoursInDay = 24; {Number of hours in a day} MinutesInHour = 60; {Number of minutes in an hour} MinutesInDay = 1440; {Number of minutes in a day} function AbUnixTimeToLocalDateTime(UnixTime : LongInt) : TDateTime; function AbLocalDateTimeToUnixTime(DateTime : TDateTime) : LongInt; function AbDosFileDateToDateTime(FileDate, FileTime : Word) : TDateTime; function AbDateTimeToDosFileDate(Value : TDateTime) : LongInt; function AbGetFileTime(const aFileName: string): TDateTime; function AbSetFileTime(const aFileName: string; aValue: TDateTime): Boolean; { file attributes } function AbDOS2UnixFileAttributes(Attr: LongInt): LongInt; function AbUnix2DosFileAttributes(Attr: LongInt): LongInt; { AnisStrings } function AbLeftStr(const AText: AnsiString; const ACount: Integer): AnsiString; {$IFDEF HasInline}inline;{$ENDIF} function AbStrLen(const Str: PAnsiChar): Cardinal; {$IFDEF HasInline}inline;{$ENDIF} function AbStrPCopy(Dest: PAnsiChar; const Source: AnsiString): PAnsiChar; {$IFDEF HasInline}inline;{$ENDIF} function AbStrPLCopy(Dest: PAnsiChar; const Source: AnsiString; MaxLen: Cardinal): PAnsiChar; {$IFDEF HasInline}inline;{$ENDIF} { UNIX File Types and Permissions } const AB_FMODE_FILE = $0000; AB_FMODE_FIFO = $1000; AB_FMODE_CHARSPECFILE = $2000; AB_FMODE_DIR = $4000; AB_FMODE_BLOCKSPECFILE = $6000; AB_FMODE_FILE2 = $8000; AB_FMODE_FILELINK = $A000; AB_FMODE_SOCKET = $C000; AB_FPERMISSION_OWNERREAD = $0100; { read by owner } AB_FPERMISSION_OWNERWRITE = $0080; { write by owner } AB_FPERMISSION_OWNEREXECUTE = $0040; { execute/search by owner } AB_FPERMISSION_GROUPREAD = $0020; { read by group } AB_FPERMISSION_GROUPWRITE = $0010; { write by group } AB_FPERMISSION_GROUPEXECUTE = $0008; { execute/search by group } AB_FPERMISSION_OTHERREAD = $0004; { read by other } AB_FPERMISSION_OTHERWRITE = $0002; { write by other } AB_FPERMISSION_OTHEREXECUTE = $0001; { execute/search by other } AB_FPERMISSION_GENERIC = AB_FPERMISSION_OWNERREAD or AB_FPERMISSION_OWNERWRITE or AB_FPERMISSION_GROUPREAD or AB_FPERMISSION_OTHERREAD; { Unicode backwards compatibility functions } {$IFNDEF UNICODE} function CharInSet(C: AnsiChar; CharSet: TSysCharSet): Boolean; {$ENDIF} implementation uses StrUtils, AbConst, AbExcept; {$IF DEFINED(FPCUnixAPI)} function mktemp(template: PAnsiChar): PAnsiChar; cdecl; external clib name 'mktemp'; {$ELSEIF DEFINED(PosixAPI)} function mktemp(template: PAnsiChar): PAnsiChar; cdecl; external libc name _PU + 'mktemp'; {$IFEND} {$IF DEFINED(FPCUnixAPI) AND DEFINED(Linux)} // FreePascal libc definitions type nl_item = cint; const __LC_CTYPE = 0; _NL_CTYPE_CLASS = (__LC_CTYPE shl 16); _NL_CTYPE_CODESET_NAME = (_NL_CTYPE_CLASS)+14; function nl_langinfo(__item: nl_item): PAnsiChar; cdecl; external clib name 'nl_langinfo'; {$IFEND} {===platform independent routines for platform dependent stuff=======} function ExtractShortName(const SR : TSearchRec) : string; begin {$IFDEF MSWINDOWS} {$WARN SYMBOL_PLATFORM OFF} if SR.FindData.cAlternateFileName[0] <> #0 then Result := SR.FindData.cAlternateFileName else Result := SR.FindData.cFileName; {$WARN SYMBOL_PLATFORM ON} {$ENDIF} {$IFDEF UNIX} Result := SR.Name; {$ENDIF} end; {====================================================================} { ========================================================================== } function AbCopyFile(const Source, Destination: string; FailIfExists: Boolean): Boolean; {$IFDEF UNIX} var DesStream, SrcStream: TFileStream; {$ENDIF} begin {$IFDEF UNIX} Result := False; if not FailIfExists or not FileExists(Destination) then try SrcStream := TFileStream.Create(Source, fmOpenRead or fmShareDenyWrite); try DesStream := TFileStream.Create(Destination, fmCreate); try DesStream.CopyFrom(SrcStream, 0); Result := True; finally DesStream.Free; end; finally SrcStream.Free; end; except // Ignore errors and just return false end; {$ENDIF UNIX} {$IFDEF MSWINDOWS} Result := CopyFile(PChar(Source), PChar(Destination), FailIfExists); {$ENDIF MSWINDOWS} end; { -------------------------------------------------------------------------- } procedure AbCreateDirectory( const Path : string ); {creates the requested directory tree. CreateDir is insufficient, because if you have a path x:\dir, and request x:\dir\sub1\sub2, (/dir and /dir/sub1/sub2 on Unix) it fails.} var iStartSlash : Integer; i : Integer; TempPath : string; begin if DirectoryExists( Path ) then Exit; {see how much of the path currently exists} if Pos( '\\', Path ) > 0 then {UNC Path \\computername\sharename\path1..\pathn} iStartSlash := 5 else {standard Path drive:\path1..\pathn} iStartSlash := 2; repeat {find the Slash at iStartSlash} i := AbFindNthSlash( Path, iStartSlash ); {get a temp path to try: drive:\path1} TempPath := Copy( Path, 1, i ); {if it doesn't exist, create it} if not DirectoryExists( TempPath ) then MkDir( TempPath ); inc( iStartSlash ); until ( Length( TempPath ) = Length( Path ) ); end; { -------------------------------------------------------------------------- } function AbCreateTempFile(const Dir : string) : string; begin Result := AbGetTempFile(Dir, True); end; { -------------------------------------------------------------------------- } function AbGetTempDirectory : string; begin {$IFDEF MSWiNDOWS} SetLength(Result, MAX_PATH); SetLength(Result, GetTempPath(Length(Result), PChar(Result))); {$ENDIF} {$IFDEF UNIX} Result := '/tmp/'; {$ENDIF} end; { -------------------------------------------------------------------------- } function AbGetTempFile(const Dir : string; CreateIt : Boolean) : string; var TempPath : string; {$IFDEF MSWINDOWS} FileNameZ : array [0..259] of char; {$ENDIF} {$IFDEF UNIX} hFile: Integer; FileName: AbSysString; {$ENDIF} begin if DirectoryExists(Dir) then TempPath := Dir else TempPath := AbGetTempDirectory; {$IFDEF MSWINDOWS} GetTempFileName(PChar(TempPath), 'VMS', Word(not CreateIt), FileNameZ); Result := string(FileNameZ); {$ENDIF} {$IFDEF UNIX} FileName := AbSysString(TempPath) + 'VMSXXXXXX'; mktemp(PAnsiChar(AbSysString(FileName))); Result := string(FileName); if CreateIt then begin hFile := FileCreate(Result); if hFile <> -1 then FileClose(hFile); end; {$ENDIF} end; { -------------------------------------------------------------------------- } function AbDrive(const ArchiveName : string) : Char; var iPos: Integer; Path : string; begin Path := ExpandFileName(ArchiveName); iPos := Pos(':', Path); if (iPos <= 0) then Result := 'A' else Result := Path[1]; end; { -------------------------------------------------------------------------- } function AbDriveIsRemovable(const ArchiveName : string) : Boolean; {$IFDEF MSWINDOWS} var Path: string; {$ENDIF} begin {$IFDEF MSWINDOWS} Path := ExpandFileName(ArchiveName); if AnsiStartsText('\\?\UNC\', Path) then Delete(Path, 1, 8) else if AnsiStartsText('\\?\', Path) then Delete(Path, 1, 4); Path := IncludeTrailingPathDelimiter(ExtractFileDrive(Path)); Result := GetDriveType(PChar(Path)) = DRIVE_REMOVABLE; {$ENDIF} {$IFDEF LINUX} {LINUX -- Following may not cover all the bases} Result := AnsiStartsText('/mnt/floppy', ExtractFilePath(ExpandFileName(ArchiveName))); {$ENDIF} {$IFDEF DARWIN} Result := False; {$ENDIF} end; { -------------------------------------------------------------------------- } function AbGetDriveFreeSpace(const ArchiveName : string) : Int64; { attempt to find free space (in bytes) on drive/volume, returns -1 if fails for some reason } {$IFDEF MSWINDOWS} var FreeAvailable, TotalSpace: Int64; begin if GetDiskFreeSpaceEx(PChar(ExtractFilePath(ExpandFileName(ArchiveName))), FreeAvailable, TotalSpace, nil) then Result := FreeAvailable else Result := -1; {$ENDIF} {$IFDEF UNIX} var FStats : {$IFDEF PosixAPI}_statvfs{$ELSE}TStatFs{$ENDIF}; begin {$IF DEFINED(LibcAPI)} if statfs(PAnsiChar(ExtractFilePath(ArchiveName)), FStats) = 0 then Result := Int64(FStats.f_bAvail) * Int64(FStats.f_bsize) {$ELSEIF DEFINED(FPCUnixAPI)} if fpStatFS(PAnsiChar(ExtractFilePath(ArchiveName)), @FStats) = 0 then Result := Int64(FStats.bAvail) * Int64(FStats.bsize) {$ELSEIF DEFINED(PosixAPI)} if statvfs(PAnsiChar(AbSysString(ExtractFilePath(ArchiveName))), FStats) = 0 then Result := Int64(FStats.f_bavail) * Int64(FStats.f_bsize) {$IFEND} else Result := -1; {$ENDIF} end; { -------------------------------------------------------------------------- } function AbFileMatch(FileName: string; FileMask: string ): Boolean; {see if FileName matches FileMask} var DirMatch : Boolean; MaskDir : string; begin FileName := UpperCase( FileName ); FileMask := UpperCase( FileMask ); MaskDir := ExtractFilePath( FileMask ); if MaskDir = '' then DirMatch := True else DirMatch := AbPatternMatch( ExtractFilePath( FileName ), 1, MaskDir, 1 ); Result := DirMatch and AbPatternMatch( ExtractFileName( FileName ), 1, ExtractFileName( FileMask ), 1 ); end; { -------------------------------------------------------------------------- } procedure AbFindFiles( const FileMask : string; SearchAttr : Integer; FileList : TStrings; Recurse : Boolean ); var NewFile : string; SR : TSearchRec; Found : Integer; NameMask: string; begin Found := FindFirst( FileMask, SearchAttr, SR ); if Found = 0 then begin try NameMask := UpperCase(ExtractFileName(FileMask)); while Found = 0 do begin NewFile := ExtractFilePath( FileMask ) + SR.Name; if (SR.Name <> AbThisDir) and (SR.Name <> AbParentDir) and AbPatternMatch(UpperCase(SR.Name), 1, NameMask, 1) then if (SR.Attr and faDirectory) <> 0 then FileList.Add( NewFile + PathDelim ) else FileList.Add( NewFile ); Found := FindNext( SR ); end; finally FindClose( SR ); end; end; if not Recurse then Exit; NewFile := ExtractFilePath( FileMask ); if ( NewFile <> '' ) and ( NewFile[Length(NewFile)] <> AbPathDelim) then NewFile := NewFile + AbPathDelim; NewFile := NewFile + AbAnyFile; Found := FindFirst( NewFile, faDirectory or SearchAttr, SR ); if Found = 0 then begin try while ( Found = 0 ) do begin if ( SR.Name <> AbThisDir ) and ( SR.Name <> AbParentDir ) and ((SR.Attr and faDirectory) > 0 ) then AbFindFiles( ExtractFilePath( NewFile ) + SR.Name + AbPathDelim + ExtractFileName( FileMask ), SearchAttr, FileList, True ); Found := FindNext( SR ); end; finally FindClose( SR ); end; end; end; { -------------------------------------------------------------------------- } procedure AbFindFilesEx( const FileMask : string; SearchAttr : Integer; FileList : TStrings; Recurse : Boolean ); var I, J: Integer; MaskPart: string; begin I := 1; while I <= Length(FileMask) do begin J := I; while (I <= Length(FileMask)) and (FileMask[I] <> AbPathSep) do Inc(I); MaskPart := Trim(Copy(FileMask, J, I - J)); if (I <= Length(FileMask)) and (FileMask[I] = AbPathSep) then Inc(I); AbFindFiles(MaskPart, SearchAttr, FileList, Recurse); end; end; { -------------------------------------------------------------------------- } function AbAddBackSlash(const DirName : string) : string; { Add a default slash to a directory name } const AbDelimSet : set of AnsiChar = [AbPathDelim, ':', #0]; begin Result := DirName; if Length(DirName) = 0 then Exit; if not CharInSet(DirName[Length(DirName)], AbDelimSet) then Result := DirName + AbPathDelim; end; { -------------------------------------------------------------------------- } function AbFindNthSlash( const Path : string; n : Integer ) : Integer; { return the position of the character just before the nth slash } var i : Integer; Len : Integer; iSlash : Integer; begin Len := Length( Path ); Result := Len; iSlash := 0; i := 0; while i <= Len do begin if Path[i] = AbPathDelim then begin inc( iSlash ); if iSlash = n then begin Result := pred( i ); break; end; end; inc( i ); end; end; { -------------------------------------------------------------------------- } function AbGetPathType( const Value : string ) : TAbPathType; { returns path type - none, relative or absolute } begin Result := ptNone; {$IFDEF MSWINDOWS} {check for drive/unc info} if ( Pos( '\\', Value ) > 0 ) or ( Pos( ':', Value ) > 0 ) then {$ENDIF MSWINDOWS} {$IFDEF UNIX} { UNIX absolute paths start with a slash } if (Value[1] = AbPathDelim) then {$ENDIF UNIX} Result := ptAbsolute else if ( Pos( AbPathDelim, Value ) > 0 ) or ( Pos( AB_ZIPPATHDELIM, Value ) > 0 ) then Result := ptRelative; end; { -------------------------------------------------------------------------- } {$IFDEF MSWINDOWS} {$WARN SYMBOL_PLATFORM OFF} function AbGetShortFileSpec(const LongFileSpec : string ) : string; var SR : TSearchRec; Search : string; Drive : string; Path : string; FileName : string; Found : Integer; SubPaths : TStrings; i : Integer; begin AbParseFileName( LongFileSpec, Drive, Path, FileName ); SubPaths := TStringList.Create; try AbParsePath( Path, SubPaths ); Search := Drive; Result := Search + AbPathDelim; if SubPaths.Count > 0 then for i := 0 to pred( SubPaths.Count ) do begin Search := Search + AbPathDelim + SubPaths[i]; Found := FindFirst( Search, faHidden + faSysFile + faDirectory, SR ); if Found <> 0 then raise EAbException.Create( 'Path not found' ); try Result := Result + ExtractShortName(SR) + AbPathDelim; finally FindClose( SR ); end; end; Search := Search + AbPathDelim + FileName; Found := FindFirst( Search, faReadOnly + faHidden + faSysFile + faArchive, SR ); if Found <> 0 then raise EAbFileNotFound.Create; try Result := Result + ExtractShortName(SR); finally FindClose( SR ); end; finally SubPaths.Free; end; end; {$WARN SYMBOL_PLATFORM ON} {$ENDIF} { -------------------------------------------------------------------------- } procedure AbIncFilename( var Filename : string; Value : Word ); { place value at the end of filename, e.g. Files.C04 } var Ext : string; I : Word; begin I := (Value + 1) mod 100; Ext := ExtractFileExt(Filename); if (Length(Ext) < 2) then Ext := '.' + Format('%.2d', [I]) else Ext := Ext[1] + Ext[2] + Format('%.2d', [I]); Filename := ChangeFileExt(Filename, Ext); end; { -------------------------------------------------------------------------- } procedure AbParseFileName( FileSpec : string; out Drive : string; out Path : string; out FileName : string ); var i : Integer; iColon : Integer; iStartSlash : Integer; begin if Pos( AB_ZIPPATHDELIM, FileSpec ) > 0 then AbUnfixName( FileSpec ); FileName := ExtractFileName( FileSpec ); Path := ExtractFilePath( FileSpec ); {see how much of the path currently exists} iColon := Pos( ':', Path ); if Pos( '\\', Path ) > 0 then begin {UNC Path \\computername\sharename\path1..\pathn} {everything up to the 4th slash is the drive} iStartSlash := 4; i := AbFindNthSlash( Path, iStartSlash ); Drive := Copy( Path, 1, i ); Delete( Path, 1, i + 1 ); end else if iColon > 0 then begin Drive := Copy( Path, 1, iColon ); Delete( Path, 1, iColon ); if Path[1] = AbPathDelim then Delete( Path, 1, 1 ); end; end; { -------------------------------------------------------------------------- } procedure AbParsePath( Path : string; SubPaths : TStrings ); { break abart path into subpaths --- Path : abbrevia/examples > SubPaths[0] = abbrevia SubPaths[1] = examples} var i : Integer; iStart : Integer; iStartSlash : Integer; SubPath : string; begin if Path = '' then Exit; if Path[ Length( Path ) ] = AbPathDelim then Delete( Path, Length( Path ), 1 ); iStart := 1; iStartSlash := 1; repeat {find the Slash at iStartSlash} i := AbFindNthSlash( Path, iStartSlash ); {get the subpath} SubPath := Copy( Path, iStart, i - iStart + 1 ); iStart := i + 2; inc( iStartSlash ); SubPaths.Add( SubPath ); until ( i = Length( Path ) ); end; { -------------------------------------------------------------------------- } function AbPatternMatch(const Source : string; iSrc : Integer; const Pattern : string; iPat : Integer ) : Boolean; { recursive routine to see if the source string matches the pattern. Both ? and * wildcard characters are allowed. Compares Source from iSrc to Length(Source) to Pattern from iPat to Length(Pattern)} var Matched : Boolean; k : Integer; begin if Length( Source ) = 0 then begin Result := Length( Pattern ) = 0; Exit; end; if iPat = 1 then begin if ( CompareStr( Pattern, AbDosAnyFile) = 0 ) or ( CompareStr( Pattern, AbUnixAnyFile ) = 0 ) then begin Result := True; Exit; end; end; if Length( Pattern ) = 0 then begin Result := (Length( Source ) - iSrc + 1 = 0); Exit; end; while True do begin if ( Length( Source ) < iSrc ) and ( Length( Pattern ) < iPat ) then begin Result := True; Exit; end; if Length( Pattern ) < iPat then begin Result := False; Exit; end; if Pattern[iPat] = '*' then begin k := iPat; if ( Length( Pattern ) < iPat + 1 ) then begin Result := True; Exit; end; while True do begin Matched := AbPatternMatch( Source, k, Pattern, iPat + 1 ); if Matched or ( Length( Source ) < k ) then begin Result := Matched; Exit; end; inc( k ); end; end else begin if ( (Pattern[iPat] = '?') and ( Length( Source ) <> iSrc - 1 ) ) or ( Pattern[iPat] = Source[iSrc] ) then begin inc( iPat ); inc( iSrc ); end else begin Result := False; Exit; end; end; end; end; { -------------------------------------------------------------------------- } function AbPercentage(V1, V2 : Int64) : Byte; { Returns the ratio of V1 to V2 * 100 } begin if V2 <= 0 then Result := 0 else if V1 >= V2 then Result := 100 else Result := (V1 * 100) div V2; end; { -------------------------------------------------------------------------- } procedure AbStripDots( var FName : string ); { strips relative path information, e.g. ".."} begin while Pos( AbParentDir + AbPathDelim, FName ) = 1 do System.Delete( FName, 1, 3 ); end; { -------------------------------------------------------------------------- } procedure AbStripDrive( var FName : string ); { strips the drive off a filename } var Drive, Path, Name : string; begin AbParseFileName( FName, Drive, Path, Name ); FName := Path + Name; end; { -------------------------------------------------------------------------- } procedure AbFixName( var FName : string ); { changes backslashes to forward slashes } var i : Integer; begin for i := 1 to Length( FName ) do if FName[i] = AbPathDelim then FName[i] := AB_ZIPPATHDELIM; end; { -------------------------------------------------------------------------- } procedure AbUnfixName( var FName : string ); { changes forward slashes to backslashes } var i : Integer; begin for i := 1 to Length( FName ) do if FName[i] = AB_ZIPPATHDELIM then FName[i] := AbPathDelim; end; { -------------------------------------------------------------------------- } procedure AbUpdateCRC( var CRC : LongInt; const Buffer; Len : Integer ); var BufPtr : PByte; i : Integer; CRCTemp : DWORD; begin BufPtr := @Buffer; CRCTemp := CRC; for i := 0 to pred( Len ) do begin CRCTemp := AbCrc32Table[ Byte(CrcTemp) xor (BufPtr^) ] xor ((CrcTemp shr 8) and $00FFFFFF); Inc(BufPtr); end; CRC := CRCTemp; end; { -------------------------------------------------------------------------- } function AbUpdateCRC32(CurByte : Byte; CurCrc : LongInt) : LongInt; { Return the updated 32bit CRC } { Normally a good candidate for basm, but Delphi32's code generation couldn't be beat on this one!} begin Result := DWORD(AbCrc32Table[ Byte(CurCrc xor LongInt( CurByte ) ) ] xor ((CurCrc shr 8) and DWORD($00FFFFFF))); end; { -------------------------------------------------------------------------- } function AbCRC32Of( const aValue : RawByteString ) : LongInt; begin Result := -1; AbUpdateCRC(Result, aValue[1], Length(aValue)); Result := not Result; end; { -------------------------------------------------------------------------- } function AbWriteVolumeLabel(const VolName : string; Drive : Char) : Cardinal; var Temp : string; Vol : array[0..11] of Char; Root : array[0..3] of Char; begin Temp := VolName; StrCopy(Root, '%:' + AbPathDelim); Root[0] := Drive; if Length(Temp) > 11 then SetLength(Temp, 11); StrPCopy(Vol, Temp); {$IFDEF MSWINDOWS} if Windows.SetVolumeLabel(Root, Vol) then Result := 0 else Result := GetLastError; {$ENDIF MSWINDOWS} {$IFDEF UNIX} { Volume labels not supported on Unix } Result := 0; {$ENDIF UNIX} end; { -------------------------------------------------------------------------- } {$IFDEF MSWINDOWS} function AbOffsetFromUTC: LongInt; { local timezone's offset from UTC in seconds (UTC = local + bias) } var TZI: TTimeZoneInformation; begin case GetTimeZoneInformation(TZI) of TIME_ZONE_ID_UNKNOWN: Result := TZI.Bias; TIME_ZONE_ID_DAYLIGHT: Result := TZI.Bias + TZI.DaylightBias; TIME_ZONE_ID_STANDARD: Result := TZI.Bias + TZI.StandardBias else Result := 0 end; Result := Result * SecondsInMinute; end; {$ENDIF} { -------------------------------------------------------------------------- } function AbUnixTimeToLocalDateTime(UnixTime : LongInt) : TDateTime; { convert UTC unix date to Delphi TDateTime in local timezone } {$IFDEF MSWINDOWS} var Hrs, Mins, Secs : Word; TodaysSecs : LongInt; Time: TDateTime; begin UnixTime := UnixTime - AbOffsetFromUTC; TodaysSecs := UnixTime mod SecondsInDay; Hrs := TodaysSecs div SecondsInHour; TodaysSecs := TodaysSecs - (Hrs * SecondsInHour); Mins := TodaysSecs div SecondsInMinute; Secs := TodaysSecs - (Mins * SecondsInMinute); if TryEncodeTime(Hrs, Mins, Secs, 0, Time) then Result := Unix0Date + (UnixTime div SecondsInDay) + Time else Result := 0; {$ENDIF} {$IFDEF UNIX} begin Result := FileDateToDateTime(UnixTime); {$ENDIF} end; { -------------------------------------------------------------------------- } function AbLocalDateTimeToUnixTime(DateTime : TDateTime) : LongInt; { convert local Delphi TDateTime to UTC unix date } {$IFDEF MSWINDOWS} var Hrs, Mins, Secs, MSecs : Word; Dt, Tm : TDateTime; begin Dt := Trunc(DateTime); Tm := DateTime - Dt; if Dt < Unix0Date then Result := 0 else Result := Trunc(Dt - Unix0Date) * SecondsInDay; DecodeTime(Tm, Hrs, Mins, Secs, MSecs); Result := Result + (Hrs * SecondsInHour) + (Mins * SecondsInMinute) + Secs; Result := Result + AbOffsetFromUTC; {$ENDIF} {$IFDEF UNIX} begin Result := DateTimeToFileDate(DateTime); {$ENDIF} end; { -------------------------------------------------------------------------- } function AbDosFileDateToDateTime(FileDate, FileTime : Word) : TDateTime; {$IFDEF MSWINDOWS} var Temp : LongInt; begin LongRec(Temp).Lo := FileTime; LongRec(Temp).Hi := FileDate; Result := FileDateToDateTime(Temp); {$ENDIF MSWINDOWS} {$IFDEF UNIX} var Yr, Mo, Dy : Word; Hr, Mn, S : Word; begin Yr := FileDate shr 9 + 1980; Mo := FileDate shr 5 and 15; if Mo < 1 then Mo := 1; if Mo > 12 then Mo := 12; Dy := FileDate and 31; if Dy < 1 then Dy := 1; if Dy > DaysInAMonth(Yr, Mo) then Dy := DaysInAMonth(Yr, Mo); Hr := FileTime shr 11; if Hr > 23 then Hr := 23; Mn := FileTime shr 5 and 63; if Mn > 59 then Mn := 59; S := FileTime and 31 shl 1; if S > 59 then S := 59; Result := EncodeDate(Yr, Mo, Dy) + EncodeTime(Hr, Mn, S, 0); {$ENDIF UNIX} end; function AbDateTimeToDosFileDate(Value : TDateTime) : LongInt; {$IFDEF MSWINDOWS} begin Result := DateTimeToFileDate(Value); {$ENDIF MSWINDOWS} {$IFDEF UNIX} var Yr, Mo, Dy : Word; Hr, Mn, S, MS: Word; begin DecodeDate(Value, Yr, Mo, Dy); if (Yr < 1980) or (Yr > 2107) then { outside DOS file date year range } Yr := 1980; DecodeTime(Value, Hr, Mn, S, MS); LongRec(Result).Lo := (S shr 1) or (Mn shl 5) or (Hr shl 11); LongRec(Result).Hi := Dy or (Mo shl 5) or (Word(Yr - 1980) shl 9); {$ENDIF UNIX} end; { -------------------------------------------------------------------------- } function AbGetFileTime(const aFileName: string): TDateTime; var Attr: TAbAttrExRec; begin AbFileGetAttrEx(aFileName, Attr); Result := Attr.Time; end; function AbSetFileTime(const aFileName: string; aValue: TDateTime): Boolean; begin {$IFDEF MSWINDOWS} Result := FileSetDate(aFileName, AbDateTimeToDosFileDate(aValue)) = 0; {$ENDIF} {$IFDEF UNIX} Result := FileSetDate(aFileName, AbLocalDateTimeToUnixTime(aValue)) = 0; {$ENDIF} end; { -------------------------------------------------------------------------- } function AbSwapLongEndianness(Value : LongInt): LongInt; { convert BigEndian <-> LittleEndian 32-bit value } type TCastArray = array [0..3] of Byte; var i : Integer; begin for i := 3 downto 0 do TCastArray(Result)[3-i] := TCastArray(Value)[i]; end; { -------------------------------------------------------------------------- } function AbDOS2UnixFileAttributes(Attr: LongInt): LongInt; begin {$WARN SYMBOL_PLATFORM OFF} Result := { default permissions } AB_FPERMISSION_OWNERREAD or AB_FPERMISSION_GROUPREAD or AB_FPERMISSION_OTHERREAD; if (Attr and faReadOnly) = 0 then Result := Result or AB_FPERMISSION_OWNERWRITE; if (Attr and faDirectory) <> 0 then Result := Result or AB_FMODE_DIR or AB_FPERMISSION_OWNEREXECUTE or AB_FPERMISSION_GROUPEXECUTE or AB_FPERMISSION_OTHEREXECUTE else Result := Result or AB_FMODE_FILE; {$WARN SYMBOL_PLATFORM ON} end; { -------------------------------------------------------------------------- } function AbUnix2DosFileAttributes(Attr: LongInt): LongInt; begin {$WARN SYMBOL_PLATFORM OFF} Result := 0; case (Attr and $F000) of AB_FMODE_FILE, AB_FMODE_FILE2: { standard file } Result := 0; AB_FMODE_DIR: { directory } Result := Result or faDirectory; AB_FMODE_FIFO, AB_FMODE_CHARSPECFILE, AB_FMODE_BLOCKSPECFILE, AB_FMODE_FILELINK, AB_FMODE_SOCKET: Result := Result or faSysFile; end; if (Attr and AB_FPERMISSION_OWNERWRITE) <> AB_FPERMISSION_OWNERWRITE then Result := Result or faReadOnly; {$WARN SYMBOL_PLATFORM ON} end; { -------------------------------------------------------------------------- } procedure AbSetFileAttr(const aFileName : string; aAttr: Integer); begin {$WARN SYMBOL_PLATFORM OFF} {$IFDEF MSWINDOWS} FileSetAttr(aFileName, aAttr); {$ENDIF} {$IF DEFINED(LibcAPI) OR DEFINED(PosixAPI)} chmod(PAnsiChar(AbSysString(aFileName)), aAttr); {$ELSEIF DEFINED(FPCUnixAPI)} fpchmod(aFileName, aAttr); {$IFEND} {$WARN SYMBOL_PLATFORM ON} end; { -------------------------------------------------------------------------- } function AbFileGetSize(const aFileName : string) : Int64; var SR: TAbAttrExRec; begin if AbFileGetAttrEx(aFileName, SR) then Result := SR.Size else Result := -1; end; { -------------------------------------------------------------------------- } function AbFileGetAttrEx(const aFileName: string; out aAttr: TAbAttrExRec) : Boolean; var {$IFDEF MSWINDOWS} FileDate: LongRec; FindData: TWin32FindData; LocalFileTime: TFileTime; {$ENDIF} {$IFDEF FPCUnixAPI} StatBuf: stat; {$ENDIF} {$IFDEF LibcAPI} StatBuf: TStatBuf64; {$ENDIF} {$IFDEF PosixAPI} StatBuf: _stat; {$ENDIF} begin aAttr.Time := 0; aAttr.Size := -1; aAttr.Attr := -1; aAttr.Mode := 0; {$IFDEF MSWINDOWS} Result := GetFileAttributesEx(PChar(aFileName), GetFileExInfoStandard, @FindData); if Result then begin if FileTimeToLocalFileTime(FindData.ftLastWriteTime, LocalFileTime) and FileTimeToDosDateTime(LocalFileTime, FileDate.Hi, FileDate.Lo) then aAttr.Time := FileDateToDateTime(Integer(FileDate)); LARGE_INTEGER(aAttr.Size).LowPart := FindData.nFileSizeLow; LARGE_INTEGER(aAttr.Size).HighPart := FindData.nFileSizeHigh; aAttr.Attr := FindData.dwFileAttributes; aAttr.Mode := AbDOS2UnixFileAttributes(FindData.dwFileAttributes); end; {$ENDIF} {$IFDEF UNIX} {$IFDEF FPCUnixAPI} Result := (FpStat(aFileName, StatBuf) = 0); {$ENDIF} {$IFDEF LibcAPI} // Work around Kylix QC#2761: Stat64, et al., are defined incorrectly Result := (__lxstat64(_STAT_VER, PAnsiChar(aFileName), StatBuf) = 0); {$ENDIF} {$IFDEF PosixAPI} Result := (stat(PAnsiChar(AbSysString(aFileName)), StatBuf) = 0); {$ENDIF} if Result then begin aAttr.Time := FileDateToDateTime(StatBuf.st_mtime); aAttr.Size := StatBuf.st_size; aAttr.Attr := AbUnix2DosFileAttributes(StatBuf.st_mode); aAttr.Mode := StatBuf.st_mode; end; {$ENDIF UNIX} end; const MAX_VOL_LABEL = 16; function AbGetVolumeLabel(Drive : Char) : string; {-Get the volume label for the specified drive.} {$IFDEF MSWINDOWS} var Root : string; Flags, MaxLength : DWORD; NameSize : Integer; VolName : string; {$ENDIF} begin {$IFDEF MSWINDOWS} NameSize := 0; Root := Drive + ':\'; SetLength(VolName, MAX_VOL_LABEL); Result := ''; if GetVolumeInformation(PChar(Root), PChar(VolName), Length(VolName), nil, MaxLength, Flags, nil, NameSize) then Result := VolName; {$ELSE} Result := ''; //Stop Gap, spanning support needs to be rethought for Unix {$ENDIF} end; procedure AbSetSpanVolumeLabel(Drive: Char; VolNo : Integer); begin AbWriteVolumeLabel(Format(AB_SPAN_VOL_LABEL, [VolNo]), Drive); end; function AbTestSpanVolumeLabel(Drive: Char; VolNo : Integer): Boolean; var VolLabel, TestLabel : string; begin TestLabel := Format(AB_SPAN_VOL_LABEL, [VolNo]); VolLabel := UpperCase(AbGetVolumeLabel(Drive)); Result := VolLabel = TestLabel; end; { Unicode backwards compatibility functions } {$IFNDEF UNICODE} function CharInSet(C: AnsiChar; CharSet: TSysCharSet): Boolean; begin Result := C in CharSet; end; {$ENDIF} function AbLeftStr(const AText: AnsiString; const ACount: Integer): AnsiString; begin {$IFDEF HasAnsiStrings} Result := System.AnsiStrings.LeftStr(AText, ACount); {$ELSE} Result := StrUtils.LeftStr(AText, ACount); {$ENDIF} end; function AbStrLen(const Str: PAnsiChar): Cardinal; begin {$IFDEF HasAnsiStrings} Result := System.AnsiStrings.StrLen(Str); {$ELSE} Result := SysUtils.StrLen(Str); {$ENDIF} end; function AbStrPCopy(Dest: PAnsiChar; const Source: AnsiString): PAnsiChar; begin {$IFDEF HasAnsiStrings} Result := System.AnsiStrings.StrPCopy(Dest, Source); {$ELSE} Result := SysUtils.StrPCopy(Dest, Source); {$ENDIF} end; function AbStrPLCopy(Dest: PAnsiChar; const Source: AnsiString; MaxLen: Cardinal): PAnsiChar; begin {$IFDEF HasAnsiStrings} Result := System.AnsiStrings.StrPLCopy(Dest, Source, MaxLen); {$ELSE} Result := SysUtils.StrPLCopy(Dest, Source, MaxLen); {$ENDIF} end; end. ================================================ FILE: lib/abbrevia/source/AbVMStrm.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbVMStrm.pas *} {*********************************************************} {* ABBREVIA: Virtual Memory Stream *} {*********************************************************} unit AbVMStrm; {$I AbDefine.inc} interface uses Classes; const AB_VMSPageSize = 4096; {must be a power of two} AB_VMSMaxPages = 2048; {makes 8MB with the above value} type PvmsPage = ^TvmsPage; TvmsPage = packed record vpStmOfs : Int64; {value will be multiple of AB_VMSPageSize} vpLRU : integer; {'time' page was last accessed} vpDirty : Boolean; {has the page been changed?} vpData : array [0..pred(AB_VMSPageSize)] of byte; {stream data} end; type TAbVirtualMemoryStream = class(TStream) protected {private} vmsCachePage : PvmsPage; {the latest page used} vmsLRU : Longint; {'tick' value} vmsMaxMemToUse : Longword; {maximum memory to use for data} vmsMaxPages : Integer; {maximum data pages} vmsPageList : TList; {page array, sorted by offset} vmsPosition : Int64; {position of stream} vmsSize : Int64; {size of stream} vmsSwapFileDir : string; {swap file directory} vmsSwapFileName : string; {swap file name} vmsSwapFileSize : Int64; {size of swap file} vmsSwapStream : TFileStream;{swap file stream} protected procedure vmsSetMaxMemToUse(aNewMem : Longword); function vmsAlterPageList(aNewMem : Longword) : Longword; procedure vmsFindOldestPage(out OldestInx : Longint; out OldestPage: PvmsPage); function vmsGetNextLRU : Longint; function vmsGetPageForOffset(aOffset : Int64) : PvmsPage; procedure vmsSwapFileCreate; procedure vmsSwapFileDestroy; procedure vmsSwapFileRead(aPage : PvmsPage); procedure vmsSwapFileWrite(aPage : PvmsPage); public constructor Create; {-create the virtual memory stream} destructor Destroy; override; {-destroy the virtual memory stream} function Read(var Buffer; Count : Longint) : Longint; override; {-read from the stream into a buffer} function Write(const Buffer; Count : Longint) : Longint; override; {-write to the stream from a buffer} function Seek(const Offset : Int64; Origin : TSeekOrigin) : Int64; override; {-seek to a particular point in the stream} procedure SetSize(const NewSize : Int64); override; {-set the stream size} property MaxMemToUse : Longword read vmsMaxMemToUse write vmsSetMaxMemToUse; {-maximum memory to use for data before swapping to disk} property SwapFileDirectory : string read vmsSwapFileDir write vmsSwapFileDir; end; implementation uses {$IFDEF MSWINDOWS} Windows, // Fix warning about unexpanded inline functions {$ENDIF} SysUtils, AbExcept, AbUtils; const LastLRUValue = $7FFFFFFF; {===TAbVirtualMemoryStream===========================================} constructor TAbVirtualMemoryStream.Create; var Page : PvmsPage; begin inherited Create; {create the page array} vmsPageList := TList.Create; {create the first page} New(Page); with Page^ do begin vpStmOfs := 0; vpLRU := vmsGetNextLRU; vpDirty := False; FillChar(vpData, AB_VMSPageSize, 0); end; vmsPageList.Insert(0, pointer(Page)); {prime the cache, from now on the cache will never be nil} vmsCachePage := Page; {default to using all allowed pages} MaxMemToUse := AB_VMSMaxPages * AB_VMSPageSize; end; {--------} destructor TAbVirtualMemoryStream.Destroy; var Inx : integer; begin {destroy the swap file} vmsSwapFileDestroy; {throw away all pages in the list} if (vmsPageList <> nil) then begin for Inx := 0 to pred(vmsPageList.Count) do Dispose(PvmsPage(vmsPageList[Inx])); vmsPageList.Destroy; end; {let our ancestor clean up} inherited Destroy; end; {--------} function TAbVirtualMemoryStream.Read(var Buffer; Count : Longint) : Longint; var BufPtr : PByte; Page : PvmsPage; PageDataInx : integer; Posn : int64; BytesToGo : int64; BytesToRead : int64; StartOfs : int64; begin {reading is complicated by the fact we can only read in chunks of AB_VMSPageSize: we need to partition out the overall read into a read from a partial page, zero or more reads from complete pages and then a possible read from a partial page} {initialise some variables, note that the complex calc in the expression for PageDataInx is the offset of the start of the page where Posn is found.} BufPtr := @Buffer; Posn := vmsPosition; PageDataInx := Posn - (Posn and (not pred(AB_VMSPageSize))); BytesToRead := AB_VMSPageSize - PageDataInx; {calculate the actual number of bytes to read - this depends on the current position and size of the stream} BytesToGo := Count; if (vmsSize < (vmsPosition + Count)) then BytesToGo := vmsSize - vmsPosition; if (BytesToGo < 0) then BytesToGo := 0; Result := BytesToGo; {while we have bytes to read, read them} while (BytesToGo <> 0) do begin if (BytesToRead > BytesToGo) then BytesToRead := BytesToGo; StartOfs := Posn and (not pred(AB_VMSPageSize)); if (vmsCachePage^.vpStmOfs = StartOfs) then Page := vmsCachePage else Page := vmsGetPageForOffset(StartOfs); Move(Page^.vpData[PageDataInx], BufPtr^, BytesToRead); dec(BytesToGo, BytesToRead); inc(Posn, BytesToRead); inc(BufPtr, BytesToRead); PageDataInx := 0; BytesToRead := AB_VMSPageSize; end; {remember our new position} vmsPosition := Posn; end; {--------} function TAbVirtualMemoryStream.Seek(const Offset : Int64; Origin : TSeekOrigin) : Int64; begin case Origin of soBeginning : vmsPosition := Offset; soCurrent : inc(vmsPosition, Offset); soEnd : vmsPosition := vmsSize + Offset; else raise EAbVMSInvalidOrigin.Create( Integer(Origin)); end; Result := vmsPosition; end; {--------} procedure TAbVirtualMemoryStream.SetSize(const NewSize : Int64); var Page : PvmsPage; Inx : integer; NewFileSize : Int64; begin if (NewSize < vmsSize) then begin {go through the page list discarding pages whose offset is greater than our new size; don't bother saving any data from them since it be beyond the end of the stream anyway} {never delete the last page here} for Inx := pred(vmsPageList.Count) downto 1 do begin Page := PvmsPage(vmsPageList[Inx]); if (Page^.vpStmOfs >= NewSize) then begin Dispose(Page); vmsPageList.Delete(Inx); end else begin Break; end; end; { Reset cache to the first page in case the cached page was deleted. } vmsCachePage := vmsPageList[0]; {force the swap file file size in range, it'll be a multiple of AB_VMSPageSize} NewFileSize := pred(NewSize + AB_VMSPageSize) and (not pred(AB_VMSPageSize)); if (NewFileSize < vmsSwapFileSize) then vmsSwapFileSize := NewFileSize; {ignore the swap file itself} end; vmsSize := NewSize; if (vmsPosition > NewSize) then vmsPosition := NewSize; end; {--------} function TAbVirtualMemoryStream.vmsAlterPageList(aNewMem : Longword) : Longword; var NumPages : Longint; Page : PvmsPage; i : integer; OldestPageNum : Longint; begin {calculate the max number of pages required} if aNewMem = 0 then NumPages := 1 // always have at least one page else NumPages := pred(aNewMem + AB_VMSPageSize) div AB_VMSPageSize; if (NumPages > AB_VMSMaxPages) then NumPages := AB_VMSMaxPages; {if the maximum number of pages means we have to shrink the current list, do so, tossing out the oldest pages first} if (NumPages < vmsPageList.Count) then begin for i := 1 to (vmsPageList.Count - NumPages) do begin {find the oldest page} vmsFindOldestPage(OldestPageNum, Page); {if it is dirty, write it out to the swap file} if Page^.vpDirty then begin vmsSwapFileWrite(Page); end; {remove it from the page list} vmsPageList.Delete(OldestPageNum); {free the page memory} Dispose(Page); end; { Reset cache to the first page in case the cached page was deleted. } vmsCachePage := vmsPageList[0]; end; {remember our new max number of pages} vmsMaxPages := NumPages; Result := NumPages * AB_VMSPageSize; end; {--------} procedure TAbVirtualMemoryStream.vmsFindOldestPage(out OldestInx : Longint; out OldestPage: PvmsPage); var OldestLRU : Longint; Inx : integer; Page : PvmsPage; begin OldestInx := -1; OldestLRU := LastLRUValue; for Inx := 0 to pred(vmsPageList.Count) do begin Page := PvmsPage(vmsPageList[Inx]); if (Page^.vpLRU < OldestLRU) then begin OldestInx := Inx; OldestLRU := Page^.vpLRU; OldestPage := Page; end; end; end; {--------} function TAbVirtualMemoryStream.vmsGetNextLRU : Longint; var Inx : integer; begin if (vmsLRU = LastLRUValue) then begin {reset all LRUs in list} for Inx := 0 to pred(vmsPageList.Count) do PvmsPage(vmsPageList[Inx])^.vpLRU := 0; vmsLRU := 0; end; inc(vmsLRU); Result := vmsLRU; end; {--------} function TAbVirtualMemoryStream.vmsGetPageForOffset(aOffset : Int64) : PvmsPage; var Page : PvmsPage; PageOfs : Int64; L, M, R : integer; OldestPageNum : integer; CreatedNewPage: boolean; begin {using a sequential or a binary search (depending on the number of pages), try to find the page in the cache; we'll do a sequential search if the number of pages is very small, eg less than 4} if (vmsPageList.Count < 4) then begin L := vmsPageList.Count; for M := 0 to pred(vmsPageList.Count) do begin Page := PvmsPage(vmsPageList[M]); PageOfs := Page^.vpStmOfs; if (aOffset < PageOfs) then begin L := M; Break; end; if (aOffset = PageOfs) then begin Page^.vpLRU := vmsGetNextLRU; vmsCachePage := Page; Result := Page; Exit; end; end; end else {we need to do a binary search} begin L := 0; R := pred(vmsPageList.Count); repeat M := (L + R) div 2; Page := PvmsPage(vmsPageList[M]); PageOfs := Page^.vpStmOfs; if (aOffset < PageOfs) then R := pred(M) else if (aOffset > PageOfs) then L := succ(M) else {aOffset = PageOfs} begin Page^.vpLRU := vmsGetNextLRU; vmsCachePage := Page; Result := Page; Exit; end; until (L > R); end; {if we get here the page for the offset is not present in the page list, and once created/loaded, the page should be inserted at L} {enter a try..except block so that if a new page is created and an exception occurs, the page is freed} CreatedNewPage := false; Result := nil; try {if there is room to insert a new page, create one ready} if (vmsPageList.Count < vmsMaxPages) then begin New(Page); CreatedNewPage := true; end {otherwise there is no room for the insertion, so find the oldest page in the list and discard it} else {vmsMaxPages <= vmsPageList.Count} begin {find the oldest page} vmsFindOldestPage(OldestPageNum, Page); {if it is dirty, write it out to the swap file} if Page^.vpDirty then begin vmsSwapFileWrite(Page); end; {remove it from the page list} vmsPageList.Delete(OldestPageNum); {patch up the insertion point, in case the page just deleted was before it} if (OldestPageNum < L) then dec(L); end; {set all the page fields} with Page^ do begin vpStmOfs := aOffset; vpLRU := vmsGetNextLRU; vpDirty := False; vmsSwapFileRead(Page); end; {insert the page into the correct spot} vmsPageList.Insert(L, pointer(Page)); {return the page, remembering to save it in the cache} vmsCachePage := Page; Result := Page; except if CreatedNewPage then Dispose(Page); end;{try..except} end; {--------} procedure TAbVirtualMemoryStream.vmsSetMaxMemToUse(aNewMem : Longword); begin vmsMaxMemToUse := vmsAlterPageList(aNewMem); end; {--------} procedure TAbVirtualMemoryStream.vmsSwapFileCreate; begin if (vmsSwapStream = nil) then begin vmsSwapFileName := AbCreateTempFile(vmsSwapFileDir); try vmsSwapStream := TFileStream.Create(vmsSwapFileName, fmCreate); except DeleteFile(vmsSwapFileName); raise EAbVMSErrorOpenSwap.Create( vmsSwapFileName ); end; vmsSwapFileSize := 0; end; end; {--------} procedure TAbVirtualMemoryStream.vmsSwapFileDestroy; begin if (vmsSwapStream <> nil) then begin FreeAndNil(vmsSwapStream); DeleteFile(vmsSwapFileName); end; end; {--------} procedure TAbVirtualMemoryStream.vmsSwapFileRead(aPage : PvmsPage); var BytesRead : Longint; SeekResult: Int64; begin if (vmsSwapStream = nil) or (aPage^.vpStmOfs >= vmsSwapFileSize) then begin {there is nothing to be read from the disk (either the swap file doesn't exist or it's too small) so zero out the page data} FillChar(aPage^.vpData, AB_VMSPageSize, 0) end else {there is something to be read from the swap file} begin SeekResult := vmsSwapStream.Seek(aPage^.vpStmOfs, soBeginning); if (SeekResult = -1) then raise EAbVMSSeekFail.Create( vmsSwapFileName ); BytesRead := vmsSwapStream.Read(aPage^.vpData, AB_VMSPageSize); if (BytesRead <> AB_VMSPageSize) then raise EAbVMSReadFail.Create( AB_VMSPageSize, vmsSwapFileName ); end; end; {--------} procedure TAbVirtualMemoryStream.vmsSwapFileWrite(aPage : PvmsPage); var NewPos : Int64; SeekResult: Int64; BytesWritten : Longint; begin if (vmsSwapStream = nil) then vmsSwapFileCreate; SeekResult := vmsSwapStream.Seek(aPage^.vpStmOfs, soBeginning); if (SeekResult = -1) then raise EAbVMSSeekFail.Create( vmsSwapFileName ); BytesWritten := vmsSwapStream.Write(aPage^.vpData, AB_VMSPageSize); if BytesWritten <> AB_VMSPageSize then raise EAbVMSWriteFail.Create( AB_VMSPageSize, vmsSwapFileName ); NewPos := aPage^.vpStmOfs + AB_VMSPageSize; if (NewPos > vmsSwapFileSize) then vmsSwapFileSize := NewPos; end; {--------} function TAbVirtualMemoryStream.Write(const Buffer; Count : Longint) : Longint; var BufPtr : PByte; Page : PvmsPage; PageDataInx : integer; Posn : Int64; BytesToGo : Int64; BytesToWrite: Int64; StartOfs : Int64; begin {writing is complicated by the fact we can only write in chunks of AB_VMSPageSize: we need to partition out the overall write into a write to a partial page, zero or more writes to complete pages and then a possible write to a partial page} {initialise some variables, note that the complex calc in the expression for PageDataInx is the offset of the start of the page where Posn is found.} BufPtr := @Buffer; Posn := vmsPosition; PageDataInx := Posn - (Posn and (not pred(AB_VMSPageSize))); BytesToWrite := AB_VMSPageSize - PageDataInx; {calculate the actual number of bytes to write} BytesToGo := Count; Result := BytesToGo; {while we have bytes to write, write them} while (BytesToGo <> 0) do begin if (BytesToWrite > BytesToGo) then BytesToWrite := BytesToGo; StartOfs := Posn and (not pred(AB_VMSPageSize)); if (vmsCachePage^.vpStmOfs = StartOfs) then Page := vmsCachePage else Page := vmsGetPageForOffset(StartOfs); Move(BufPtr^, Page^.vpData[PageDataInx], BytesToWrite); Page^.vpDirty := True; dec(BytesToGo, BytesToWrite); inc(Posn, BytesToWrite); inc(BufPtr, BytesToWrite); PageDataInx := 0; BytesToWrite := AB_VMSPageSize; end; {remember our new position} vmsPosition := Posn; {if we've grown the stream, make a note of it} if (vmsPosition > vmsSize) then vmsSize := vmsPosition; end; {====================================================================} end. ================================================ FILE: lib/abbrevia/source/AbView.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbView.pas *} {*********************************************************} {* ABBREVIA: Base archive viewer component *} {* Use AbQView.pas for CLX *} {*********************************************************} {$IFNDEF UsingCLX} unit AbView; {$ENDIF} {$I AbDefine.inc} interface uses Classes, Types, {$IFDEF MSWINDOWS} Windows, Messages, {$ENDIF} {$IFDEF LibcAPI} Libc, {$ENDIF} {$IFDEF UsingCLX } Qt, QControls, QGraphics, QGrids, {$ELSE} Controls, Graphics, Grids, {$ENDIF} AbArcTyp; type TAbViewAttribute = (vaItemName, vaPacked, vaMethod, vaRatio, vaCRC, vaFileAttributes, vaFileType, vaEncryption, vaTimeStamp, vaFileSize, vaVersionMade, vaVersionNeeded, vaPath); TAbViewAttributes = set of TAbViewAttribute; TAbDisplayOption = (doAlternateColors, doColLines, doColMove, doColSizing, doMultiSelect, doRowLines, doShowIcons, doThumbTrack, doTrackActiveRow); TAbDisplayOptions = set of TAbDisplayOption; TAbSortAttribute = (saItemName, saPacked, saPath, saRatio, saTimeStamp, saFileSize); TAbSortAttributes = set of TAbSortAttribute; const AbDefColWidth = 150; AbDefRowHeight = 24; AbHeaderRow = 0; AbDefSelColor = clHighlight; AbDefSelTextColor = clHighlightText; AbDefHighColor = clAqua; AbDefHighTextColor = clRed; AbDefDelColor = clYellow; AbDefDelTextColor = clNavy; { ===== TAbColors ========================================================== } type TAbColors = class(TPersistent) protected {private} FSelected : TColor; FSelectedText : TColor; FAlternate : TColor; FAlternateText : TColor; FDeleted : TColor; FDeletedText : TColor; FUpdating : Boolean; FOnChange : TNotifyEvent; procedure DoOnChange; procedure SetSelected(Value : TColor); procedure SetSelectedText(Value : TColor); procedure SetAlternate(Value : TColor); procedure SetAlternateText(Value : TColor); procedure SetDeleted(Value : TColor); procedure SetDeletedText(Value : TColor); public procedure BeginUpdate; procedure EndUpdate; property OnChange : TNotifyEvent read FOnChange write FOnChange; published property Selected : TColor read FSelected write SetSelected; property SelectedText : TColor read FSelectedText write SetSelectedText; property Alternate : TColor read FAlternate write SetAlternate; property AlternateText : TColor read FAlternateText write SetAlternateText; property Deleted : TColor read FDeleted write SetDeleted; property DeletedText : TColor read FDeletedText write SetDeletedText; end; { ===== TAbSelList ========================================================= } type TAbSelList = class protected {private} FList : TList; FCurrent : Longint; public {methods} constructor Create; destructor Destroy; override; procedure Clear; procedure Deselect(Index : Longint); function IsSelected(Index : Longint) : Boolean; procedure Select(Index : Longint); procedure SelectAll(Count : Longint); function SelCount : Longint; procedure Toggle(Index : Longint); function FindFirst : Longint; function FindNext : Longint; end; { ===== TAbRowMap ========================================================== } type TAbRowMap = class protected {private} FRows : TList; FInvRows : TList; FSortAscending : Boolean; function GetRow(RowNum : Longint) : Longint; function GetInvRow(RowNum : Longint) : Longint; procedure SortOnItemName(ItemList : TAbArchiveList); procedure SortOnItemDir(ItemList : TAbArchiveList); public {methods} constructor Create; destructor Destroy; override; procedure Clear; procedure Init(RowCount : Longint); procedure SortBy(Attr : TAbSortAttribute; ItemList : TAbArchiveList); public {properties} property Rows[RowNum : Longint] : Longint read GetRow; default; property InvRows[RowNum : Longint] : Longint read GetInvRow; property SortAscending : Boolean read FSortAscending; end; { ===== TAbBaseViewer ==================================================== } type TAbColHeadings = class(TStringList) end; TAbSortedEvent = procedure (Sender : TObject; Attr : TAbViewAttribute) of object; TAbDrawSortArrowEvent = procedure (Sender : TObject; Column : Integer; Ascending: Boolean; Cnv: TCanvas; Rect : TRect) of object; TAbBaseViewer = class(TCustomGrid) protected {private} FAllowInvalidate : Boolean; FAttributes : TAbViewAttributes; FDisplayOptions : TAbDisplayOptions; FSortAttributes : TAbSortAttributes; FColMap : array[TAbViewAttribute] of Integer; FColSizing : Boolean; FColMoving : Boolean; FHeadings : TAbColHeadings; FItemList : TAbArchiveList; FRowMap : TAbRowMap; FFileName : string; FFontSize : Integer; FItemIndex : Longint; FColors : TAbColors; FButtonDown : Boolean; FIcons : TStringList; FSelList : TAbSelList; FMultiSelecting : Boolean; FShiftState : TShiftState; FSortCol : Integer; RowAnchor : Longint; ViewMouseCoord : TGridCoord; FOnChange : TNotifyEvent; FOnClick : TNotifyEvent; FOnDblClick : TNotifyEvent; FOnSorted : TAbSortedEvent; FOnDrawSortArrow : TAbDrawSortArrowEvent; function AttrToSortAttribute(Attr : TAbViewAttribute; var SortAttr : TAbSortAttribute) : Boolean; function AttrToStr(Attr : TAbViewAttribute; aItem : TAbArchiveItem) : string; function ColMap(ColNum : Integer) : Integer; procedure ColorsChange(Sender : TObject); procedure DrawHeaderButton(ACol : Integer; const AText : string); procedure DrawSortArrow; function DrawTextFormat(Attr : TAbViewAttribute; var Rect : TRect) : Word; function GetCount : Longint; function GetActiveRow : Longint; function GetHeaderRowHeight : Integer; {$IFDEF MSWINDOWS} function GetIcon(const ItemName : string) : HIcon; {$ENDIF} {$IFDEF UsingClx} { no file type icons in Clx } {$ENDIF} function GetSelCount : Longint; function GetSelected(RowNum : Longint) : Boolean; function GetVersion : string; procedure InitColMap; procedure InvalidateRow(ARow: Longint); procedure MoveColumn(FromCol, ToCol : Integer); procedure RefreshCell(ARow, ACol: Longint); procedure RefreshRow(ARow: Longint); procedure SetActiveRow(RowNum : Longint); procedure SetAttributes(Value : TAbViewAttributes); procedure SetDisplayOptions(Value : TAbDisplayOptions); procedure SetSortAttributes(Value : TAbSortAttributes); procedure SetHeaderRowHeight(Value : Integer); procedure SetHeadings(Value: TAbColHeadings); procedure SetSelected(RowNum : Longint; Value : Boolean); procedure SetVersion(const Value : string); function UpdateColCount(Attributes : TAbViewAttributes) : Integer; {$IFDEF UsingCLX} procedure FontChanged; override; procedure SizeChanged(OldColCount, OldRowCount: Longint); override; {$ELSE} procedure WMSize(var Msg: TWMSize); message WM_SIZE; procedure WMEraseBkgnd(var Msg: TWMEraseBkgnd); message WM_ERASEBKGND; procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED; {$ENDIF UsingCLX} protected {overridden methods} procedure Click; override; procedure DblClick; override; procedure KeyDown(var Key: Word; Shift: TShiftState); override; procedure KeyUp(var Key: Word; Shift: TShiftState); override; procedure Loaded; override; procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y : Integer); override; procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; procedure MouseMove(Shift: TShiftState; X, Y: Integer); override; procedure ColumnMoved(FromIndex, ToIndex: Longint); override; {$IFDEF HasGridDrawingStyle} procedure Paint; override; {$ENDIF} procedure DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState); override; procedure TopLeftChanged; override; protected {virtual methods} procedure DoChange(Sender : TObject); virtual; procedure DoLoad(Sender : TObject); virtual; procedure DoSorted(Attr : TAbViewAttribute); virtual; protected {properties} property Attributes : TAbViewAttributes read FAttributes write SetAttributes; property DisplayOptions : TAbDisplayOptions read FDisplayOptions write SetDisplayOptions; property HeaderRowHeight : Integer read GetHeaderRowHeight write SetHeaderRowHeight; property Headings : TAbColHeadings read FHeadings write SetHeadings; property ItemList : TAbArchiveList read FItemList write FItemList; property SortAttributes : TAbSortAttributes read FSortAttributes write SetSortAttributes; property Version : string read GetVersion write SetVersion stored False; protected {events} property OnChange : TNotifyEvent read FOnChange write FOnChange; property OnClick : TNotifyEvent read FOnClick write FOnClick; property OnDblClick : TNotifyEvent read FOnDblClick write FOnDblClick; property OnSorted : TAbSortedEvent read FOnSorted write FOnSorted; property OnDrawSortArrow : TAbDrawSortArrowEvent read FOnDrawSortArrow write FOnDrawSortArrow; public {methods} constructor Create(AOwner : TComponent); override; destructor Destroy; override; procedure BeginUpdate; procedure EndUpdate; procedure ClearSelections; procedure SelectAll; public {run-time properties} property ActiveRow : Longint read GetActiveRow write SetActiveRow; property Colors : TAbColors read FColors write FColors; property Count : Longint read GetCount; property SelCount : Longint read GetSelCount; property Selected[RowNum : Longint] : Boolean read GetSelected write SetSelected; property ColWidths; property RowHeights; published property OnDragDrop; property OnDragOver; end; implementation uses {$IFDEF MSWINDOWS} ShellApi, {$ENDIF} {$IFDEF HasUITypes} UITypes, {$ENDIF} SysUtils, AbUtils, AbConst, AbResString, AbZipTyp; { ===== TAbColors ========================================================== } procedure TAbColors.BeginUpdate; begin FUpdating := True; end; { -------------------------------------------------------------------------- } procedure TAbColors.EndUpdate; begin FUpdating := False; DoOnChange; end; { -------------------------------------------------------------------------- } procedure TAbColors.DoOnChange; begin if not FUpdating and Assigned(FOnChange) then FOnChange(Self); end; { -------------------------------------------------------------------------- } procedure TAbColors.SetSelected(Value : TColor); begin if (Value <> FSelected) then begin FSelected := Value; DoOnChange; end; end; { -------------------------------------------------------------------------- } procedure TAbColors.SetSelectedText(Value : TColor); begin if (Value <> FSelectedText) then begin FSelectedText := Value; DoOnChange; end; end; { -------------------------------------------------------------------------- } procedure TAbColors.SetAlternate(Value : TColor); begin if (Value <> FAlternate) then begin FAlternate := Value; DoOnChange; end; end; { -------------------------------------------------------------------------- } procedure TAbColors.SetAlternateText(Value : TColor); begin if (Value <> FAlternateText) then begin FAlternateText := Value; DoOnChange; end; end; { -------------------------------------------------------------------------- } procedure TAbColors.SetDeleted(Value : TColor); begin if (Value <> FDeleted) then begin FDeleted := Value; DoOnChange; end; end; { -------------------------------------------------------------------------- } procedure TAbColors.SetDeletedText(Value : TColor); begin if (Value <> FDeletedText) then begin FDeletedText := Value; DoOnChange; end; end; { ===== TAbSelList ========================================================= } constructor TAbSelList.Create; begin FList := TList.Create; FCurrent := -1; end; { -------------------------------------------------------------------------- } destructor TAbSelList.Destroy; begin FList.Free; inherited Destroy; end; { -------------------------------------------------------------------------- } procedure TAbSelList.Clear; begin FList.Clear; FCurrent := -1; end; { -------------------------------------------------------------------------- } procedure TAbSelList.Select(Index: Longint); begin if FList.IndexOf(Pointer(Index)) < 0 then FList.Add(Pointer(Index)); end; { -------------------------------------------------------------------------- } procedure TAbSelList.Deselect(Index: Longint); var i : Longint; begin i := FList.IndexOf(Pointer(Index)); if (i >= 0) then FList.Delete(i); end; { -------------------------------------------------------------------------- } function TAbSelList.IsSelected(Index : Longint) : Boolean; begin Result := FList.IndexOf(Pointer(Index)) >= 0; end; { -------------------------------------------------------------------------- } procedure TAbSelList.Toggle(Index: Longint); begin if IsSelected(Index) then Deselect(Index) else Select(Index); end; { -------------------------------------------------------------------------- } function TAbSelList.SelCount : Longint; begin Result := FList.Count; end; { -------------------------------------------------------------------------- } procedure TAbSelList.SelectAll(Count : Longint); var i : Longint; begin for i := 0 to Pred(Count) do Select(i); end; { -------------------------------------------------------------------------- } function TAbSelList.FindFirst : Longint; begin FCurrent := -1; if (FList.Count > 0) then Result := FindNext else Result := -1; end; { -------------------------------------------------------------------------- } function TAbSelList.FindNext : Longint; begin if (FList.Count > 0) and (FCurrent < Pred(FList.Count)) then begin Inc(FCurrent); Result := Longint(FList[FCurrent]); end else Result := -1; end; { ===== TAbRowMap ========================================================== } procedure TAbRowMap.Clear; begin FRows.Clear; FInvRows.Clear; end; { -------------------------------------------------------------------------- } function TAbRowMap.GetRow(RowNum : Longint) : Longint; begin if (RowNum >= 0) and (RowNum < FRows.Count) then Result := Longint(FRows[RowNum]) else Result := 0; end; { -------------------------------------------------------------------------- } function TAbRowMap.GetInvRow(RowNum : Longint) : Longint; begin if (RowNum >= 0) and (RowNum < FInvRows.Count) then Result := Longint(FInvRows[RowNum]) else Result := 0; end; { -------------------------------------------------------------------------- } constructor TAbRowMap.Create; begin inherited Create; FRows := TList.Create; FInvRows := TList.Create; end; { -------------------------------------------------------------------------- } procedure TAbRowMap.Init(RowCount : Longint); var i : Longint; begin Clear; if (RowCount > 0) then for i := 0 to Pred(RowCount) do begin FRows.Add(Pointer(i)); FInvRows.Add(Pointer(i)); end; end; { -------------------------------------------------------------------------- } destructor TAbRowMap.Destroy; begin FRows.Free; FInvRows.Free; inherited Destroy; end; { -------------------------------------------------------------------------- } procedure TAbRowMap.SortBy(Attr : TAbSortAttribute; ItemList : TAbArchiveList); type PSortRec = ^TSortRec; TSortRec = record Val : Double; Index : Longint; end; var i, LI : Longint; SL : TList; RowCount : Longint; P : PSortRec; DT : TDateTime; aItem : TAbArchiveItem; procedure QuickSort(SL : TList; L, R: Integer); var i, j: Integer; P: PSortRec; begin i := L; j := R; P := SL[(L + R) shr 1]; repeat while PSortRec(SL[i])^.Val < P^.Val do Inc(i); while PSortRec(SL[j])^.Val > P^.Val do Dec(j); if (i <= j) then begin SL.Exchange(i, j); Inc(i); Dec(j); end; until i > j; if L < j then QuickSort(SL, L, j); if i < R then QuickSort(SL, i, R); end; begin if (ItemList.Count <= 0) then Exit; case Attr of saItemName : SortOnItemName(ItemList); saPath : SortOnItemDir(ItemList); else begin RowCount := ItemList.Count; SL := TList.Create; try {SL} SL.Capacity := RowCount; for i := 0 to Pred(RowCount) do begin GetMem(P, SizeOf(TSortRec)); aItem := TAbArchiveItem(ItemList.Items[i]); case Attr of saPacked : P^.Val := aItem.CompressedSize; saRatio : begin if (aItem is TAbZipItem) then P^.Val := TAbZipItem(aItem).CompressionRatio else P^.Val := 0; end; saFileSize : P^.Val := aItem.UnCompressedSize; saTimeStamp : begin LI := LongInt(aItem.LastModFileDate) shl 16 + aItem.LastModFileTime; DT := FileDateToDateTime(LI); P^.Val := Double(DT); end; end; P^.Index := i; SL.Add(P); end; QuickSort(SL, 0, Pred(SL.Count)); for i := 0 to Pred(SL.Count) do begin if FSortAscending then P := SL[i] else P := SL[Pred(SL.Count) - i]; FRows[i] := Pointer(P^.Index) end; finally {SL} while (SL.Count > 0) do begin FreeMem(SL[0], Sizeof(TSortRec)); SL.Delete(0); end; SL.Free; end; {SL} end; end; FSortAscending := not FSortAscending; for i := 0 to Pred(ItemList.Count) do FInvRows[Rows[i]] := Pointer(i); end; { -------------------------------------------------------------------------- } procedure TAbRowMap.SortOnItemName(ItemList : TAbArchiveList); var i, RowCount : Longint; SL : TStringList; FN : string; begin RowCount := ItemList.Count; SL := TStringList.Create; try {SL} for i := 0 to Pred(RowCount) do begin FN := TAbArchiveItem(ItemList.Items[i]).Filename; AbUnFixName(FN); SL.AddObject(ExtractFilename(FN), Pointer(i)); end; SL.Sort; for i := 0 to Pred(RowCount) do begin if FSortAscending then FRows[i] := SL.Objects[i] else FRows[i] := SL.Objects[Pred(RowCount) - i]; end; finally {SL} SL.Free; end; {SL} end; { -------------------------------------------------------------------------- } procedure TAbRowMap.SortOnItemDir(ItemList : TAbArchiveList); var i, RowCount : Longint; SL : TStringList; FN : string; begin RowCount := ItemList.Count; SL := TStringList.Create; try {SL} for i := 0 to Pred(RowCount) do begin FN := TAbArchiveItem(ItemList.Items[i]).DiskPath; AbUnFixName(FN); SL.AddObject(ExtractFilePath(FN), Pointer(i)); end; SL.Sort; for i := 0 to Pred(RowCount) do begin if FSortAscending then FRows[i] := SL.Objects[i] else FRows[i] := SL.Objects[Pred(RowCount) - i]; end; finally {SL} SL.Free; end; {SL} end; {===== TAbBaseViewer ===============================================} constructor TAbBaseViewer.Create(AOwner : TComponent); begin inherited Create(AOwner); FItemList := TAbArchiveList.Create(False); RowCount := 2; FixedCols := 0; FixedRows := 1; {Header Row} FSortCol := -1; Color := clWindow; FColors := TAbColors.Create; FColors.OnChange := ColorsChange; FColors.Selected := AbDefSelColor; FColors.SelectedText := AbDefSelTextColor; FColors.Alternate := AbDefHighColor; FColors.AlternateText := AbDefHighTextColor; FColors.Deleted := AbDefDelColor; FColors.DeletedText := AbDefDelTextColor; DefaultColWidth := AbDefColWidth; DefaultRowHeight := AbDefRowHeight; DefaultDrawing := False; ParentColor := False; {$IFNDEF UsingCLX} ParentCtl3D := True; {$ENDIF} ParentFont := True; ParentShowHint := True; FHeadings := TAbColHeadings.Create; InitColMap; FColSizing := False; FColMoving := False; FAllowInvalidate := True; FRowMap := TAbRowMap.Create; FIcons := TStringList.Create; FSelList := TAbSelList.Create; Attributes := [vaItemname, vaPacked, vaTimeStamp, vaFileSize, vaPath]; SetDisplayOptions([doColSizing]); Visible := True; end; { -------------------------------------------------------------------------- } destructor TAbBaseViewer.Destroy; begin FRowMap.Free; FHeadings.Free; FColors.Free; FIcons.Free; FSelList.Free; FItemList.Free; inherited Destroy; end; { -------------------------------------------------------------------------- } function TAbBaseViewer.AttrToSortAttribute(Attr : TAbViewAttribute; var SortAttr : TAbSortAttribute) : Boolean; begin Result := True; case Attr of vaItemName : SortAttr := saItemName; vaPacked : SortAttr := saPacked; vaFileSize : SortAttr := saFileSize; vaRatio : SortAttr := saRatio; vaTimeStamp : SortAttr := saTimeStamp; vaPath : SortAttr := saPath; else Result := False; end; end; { -------------------------------------------------------------------------- } function TAbBaseViewer.AttrToStr(Attr : TAbViewAttribute; aItem : TAbArchiveItem) : string; var FN : string; LI : Longint; begin Result := ''; if Attr in [vaItemName, vaPath] then begin FN := aItem.Filename; AbUnFixName(FN); end; {first take care of common attributes} with aItem do case Attr of vaCRC : Result := IntToHex(CRC32, 8); vaItemname : Result := ExtractFilename(FN); vaPacked : Result := IntToStr(CompressedSize); vaFileSize : Result := IntToStr(UncompressedSize); vaFileAttributes : begin {$IFDEF MSWINDOWS} {$WARN SYMBOL_PLATFORM OFF} if (faReadOnly and ExternalFileAttributes) = faReadOnly then Result := Result + AbReadOnlyS; if (faHidden and ExternalFileAttributes) = faHidden then Result := Result + AbHiddenS; if (faSysFile and ExternalFileAttributes) = faSysFile then Result := Result + AbSystemS; if (faArchive and ExternalFileAttributes) = faArchive then Result := Result + AbArchivedS; {$WARN SYMBOL_PLATFORM OFF} {$ENDIF MSWINDOWS} end; vaEncryption : if IsEncrypted then Result := AbEncryptedS; vaTimeStamp : if (LastModFileDate + LastModFileTime = 0) then Result := AbUnknownS else begin LI := LongInt(LastModFileDate) shl 16 + LastModFileTime; Result := DateTimeToStr(FileDateToDateTime(LI)); end; vaPath : Result := DiskPath; end; {now handle the zip specific attributes} if (aItem is TAbZipItem) then with TAbZipItem(aItem) do case Attr of vaFileType : if (InternalFileAttributes = 1) then Result := AbTextS else Result := AbBinaryS; vaMethod : Result := ZipCompressionMethodToString(CompressionMethod); vaRatio : Result := IntToStr(Round(CompressionRatio)); vaVersionMade : Result := IntToStr(Round(Lo(VersionMadeBy)/ 10.0)); vaVersionNeeded : Result := IntToStr(Round(Lo(VersionNeededToExtract)/ 10.0)); end; {$IFDEF LINUX} Result := ' ' + Result; {$ENDIF} end; { -------------------------------------------------------------------------- } procedure TAbBaseViewer.BeginUpdate; begin FAllowInvalidate := False; end; { -------------------------------------------------------------------------- } procedure TAbBaseViewer.EndUpdate; begin FAllowInvalidate := True; Refresh; end; { -------------------------------------------------------------------------- } procedure TAbBaseViewer.ClearSelections; var i : Longint; begin if (FSelList.SelCount > 0) then begin i := FSelList.FindFirst; repeat InvalidateRow(FRowMap.InvRows[i]+1); i := FSelList.FindNext; until (i < 0); FSelList.Clear; end; end; { -------------------------------------------------------------------------- } procedure TAbBaseViewer.Click; {Here is the logic for MultiSelect} var i : Longint; begin inherited Click; if Assigned(FItemList) and (FItemList.Count > 0) then begin if (ssCtrl in FShiftState) and (doMultiSelect in FDisplayOptions) then Selected[ActiveRow] := not Selected[ActiveRow] else begin if not ((ssShift in FShiftState) and (doMultiSelect in FDisplayOptions)) then begin ClearSelections; Selected[ActiveRow] := True; end else begin ClearSelections; if (RowAnchor < ActiveRow) then for i := RowAnchor to ActiveRow do Selected[i] := True else for i := ActiveRow to RowAnchor do Selected[i] := True; end; end; Update; if Assigned(FOnClick) then FOnClick(Self); end; end; { -------------------------------------------------------------------------- } {$IFDEF UsingCLX} procedure TAbBaseViewer.FontChanged; {$ELSE} procedure TAbBaseViewer.CMFontChanged(var Message: TMessage); {$ENDIF} begin inherited; if not (csLoading in ComponentState) then begin Canvas.Font := Font; DefaultRowHeight := Canvas.TextHeight('W') + 2; HeaderRowHeight := Canvas.TextHeight('W') + 4; end; end; { -------------------------------------------------------------------------- } function TAbBaseViewer.ColMap(ColNum : Integer) : Integer; begin Result := FColMap[TAbViewAttribute(ColNum)]; end; { -------------------------------------------------------------------------- } procedure TAbBaseViewer.ColorsChange(Sender : TObject); begin Invalidate; end; { -------------------------------------------------------------------------- } procedure TAbBaseViewer.ColumnMoved(FromIndex, ToIndex : Longint); begin MoveColumn(FromIndex, ToIndex); Invalidate; end; { -------------------------------------------------------------------------- } procedure TAbBaseViewer.DblClick; {Dont pass along the event if double click in header} begin inherited DblClick; if (ViewMouseCoord.Y <> abHeaderRow) then if Assigned(FItemList) and (FItemList.Count > 0) then if Assigned(FOnDblClick) then FOnDblClick(Self); end; { -------------------------------------------------------------------------- } procedure TAbBaseViewer.DoChange; begin RowCount := 2; {HeaderRow + 1} FSelList.Clear; if Assigned(FItemList) then begin FRowMap.Init(FItemList.Count); if (FItemList.Count > 0) then RowCount := FItemList.Count + 1 else begin { RefreshRow(1);} FSortCol := -1; end; end; if FAllowInvalidate then Refresh; if Assigned(FOnChange) then FOnChange(Self); end; { -------------------------------------------------------------------------- } procedure TAbBaseViewer.DoLoad; begin FIcons.Clear; FSelList.Clear; end; { -------------------------------------------------------------------------- } procedure TAbBaseViewer.DoSorted(Attr : TAbViewAttribute); begin DrawSortArrow; if Assigned(FOnSorted) then FOnSorted(Self, Attr); end; { -------------------------------------------------------------------------- } {$IFDEF HasGridDrawingStyle} procedure TAbBaseViewer.Paint; begin DefaultDrawing := FInternalDrawingStyle <> gdsClassic; inherited; end; {$ENDIF} { -------------------------------------------------------------------------- } procedure TAbBaseViewer.DrawCell(ACol, ARow: Longint; ARect: TRect; AState: TGridDrawState); var s : string; aItem : TAbArchiveItem; TxtRect : TRect; Attr : TAbViewAttribute; DTFormat : Word; {$IFNDEF UsingClx} H : Integer; Icon : HIcon; {$ENDIF} begin {$IFDEF LINUX} if not DefaultDrawing then DefaultDrawing := true; {$ENDIF} Canvas.Font := Font; if (ARow = AbHeaderRow) then begin DrawHeaderButton(ACol, FHeadings[ColMap(ACol)]) end else if not FAllowInvalidate then {waiting for EndUpdate} Exit else with Canvas do begin if not (doColLines in DisplayOptions) then ARect.Right := ARect.Right + 1; Brush.Color := clWindow; if (not Assigned(FItemList)) or (FItemList.Count = 0) then begin if not DefaultDrawing then Canvas.FillRect(ARect); Exit; end; aItem := FItemList.Items[FRowMap[ARow-1]]; Attr := TAbViewAttribute(ColMap(ACol)); S := AttrToStr(Attr, aItem); if (gdSelected in AState) or FSelList.IsSelected(FRowMap[ARow-1]) then begin if not DefaultDrawing then begin Brush.Color := FColors.Selected; Font.Color := FColors.SelectedText; end {$IFDEF HasGridDrawingStyle} else begin if DrawingStyle = gdsGradient then Canvas.Font.Color := clHighlightText; if not (gdSelected in AState) then begin if (goRowSelect in Options) then Include(AState, gdRowSelected); DrawCellHighlight(ARect, AState, ACol, ARow); end; end; {$ENDIF} end else if aItem.Action = aaDelete then begin Brush.Color := FColors.Deleted; Font.Color := FColors.DeletedText; end else if ((doAlternateColors in FDisplayOptions) and not Odd(ARow)) then begin Brush.Color := FColors.Alternate; Font.Color := FColors.AlternateText; end; if not DefaultDrawing then Canvas.FillRect(ARect); Canvas.Brush.Style := bsClear; TxtRect := ARect; {$IFNDEF UsingCLX} Icon := 0; if (Attr = vaItemName) then Icon := GetIcon(aItem.Filename); if (Icon <> 0) then begin H := ARect.Bottom - ARect.Top; DrawIconEx(Canvas.Handle, ARect.Left+1, ARect.Top+1, Icon, H - 2, H - 2, 0, 0, DI_NORMAL); TxtRect.Left := TxtRect.Left + H; end; {$ENDIF} DTFormat := DrawTextFormat(Attr, TxtRect); {$IFNDEF UsingCLX} DrawText(Canvas.Handle, PChar(s), -1, TxtRect, DTFormat); {$ELSE} Canvas.TextRect(TxtRect, TxtRect.Left, TxtRect.Top, s, DTFormat); {$ENDIF} end; end; { -------------------------------------------------------------------------- } procedure TAbBaseViewer.DrawHeaderButton(ACol : Integer; const AText : string); var ARect : TRect; DTFormat : Word; begin ARect := CellRect(ACol, 0); if not DefaultDrawing then with Canvas do begin Brush.Style := bsSolid; Brush.Color := clBtnface; FillRect(ARect); if FButtonDown then Pen.Color := clBtnHighlight else Pen.Color := clBtnShadow; MoveTo(ARect.Left, ARect.Bottom - 1); LineTo(ARect.Right - 1, ARect.Bottom - 1); LineTo(ARect.Right - 1, ARect.Top -1); if FButtonDown then Pen.Color := clBtnShadow else Pen.Color := clBtnHighlight; MoveTo(ARect.Left, ARect.Bottom - 2); LineTo(ARect.Left, ARect.Top); LineTo(ARect.Right - 1, ARect.Top); Brush.Style := bsClear; end; ARect.Right := ARect.Left + ColWidths[ACol]; if FSortCol = ACol then ARect.Right := ARect.Right - 5 - (2 * (ARect.Bottom - ARect.Top) div 10); {$IFDEF UsingCLX} { prefix is off by default in Qt} DTFormat := Integer(AlignmentFlags_AlignVCenter) or Integer(AlignmentFlags_SingleLine) or Integer(AlignmentFlags_AlignHCenter); {$ELSE} DTFormat := DT_VCENTER or DT_SINGLELINE or DT_NOPREFIX or DT_CENTER; {$ENDIF} if FButtonDown then ARect := Rect(ARect.Left+1, ARect.Top+1, ARect.Right, ARect.Bottom); {$IFDEF UsingCLX} Canvas.TextRect(ARect, ARect.Left, ARect.Top, AText, DTFormat); {$ELSE} DrawText(Canvas.Handle, PChar(AText), -1, ARect, DTFormat); {$ENDIF} if FSortCol = ACol then DrawSortArrow; end; { -------------------------------------------------------------------------- } procedure TAbBaseViewer.DrawSortArrow; var ARect : TRect; SavedColor : TColor; begin if (FSortCol > -1) then begin { set up Rect for the OnDrawSortArrow event } ARect := CellRect(FSortCol, 0); ARect.Top := (ARect.Bottom - ARect.Top) div 10; ARect.Bottom := ARect.Bottom - ARect.Top; ARect.Right := ARect.Left + ColWidths[FSortCol] - 5; ARect.Left := ARect.Right - ((ARect.Bottom - ARect.Top)); if Assigned(FOnDrawSortArrow) then begin FOnDrawSortArrow(Self, FSortCol, FRowMap.SortAscending, Canvas, ARect); Exit; end; { make ARect smaller for our own drawing } inc(ARect.Left, 10); inc(ARect.Top, 5); dec(ARect.Bottom, 5); with Canvas do begin Pen.Color := clBtnShadow; SavedColor := Brush.Color; Brush.Color := clBtnFace; with ARect do if FRowMap.SortAscending then begin Polygon([Point(((Right-Left)div 2)+Left, Bottom), Point(Right, Top), Point(Left, Top)]); {$IFNDEF UsingCLX} if Ctl3D then begin Pen.Color := clBtnHighlight; MoveTo(((Right-Left)div 2)+Left, Bottom); LineTo(Right, Top); end; {$ENDIF} end else begin Polygon([Point(((Right-Left)div 2)+Left, Top), Point(Right, Bottom), Point(Left, Bottom)]); {$IFNDEF UsingCLX} if Ctl3D then begin Pen.Color := clBtnHighlight; MoveTo(((Right-Left)div 2)+Left, Top); LineTo(Right, Bottom); LineTo(Left, Bottom); Pen.Color := clBtnShadow; LineTo(((Right-Left)div 2)+Left, Top); end; {$ENDIF} end; Brush.Color := SavedColor; end; end; end; { -------------------------------------------------------------------------- } function TAbBaseViewer.DrawTextFormat(Attr : TAbViewAttribute; var Rect : TRect) : Word; begin {$IFDEF MSWINDOWS} Result := DT_VCENTER or DT_SINGLELINE or DT_NOPREFIX; case Attr of vaItemname : Result := Result or DT_LEFT; vaPacked : Result := Result or DT_RIGHT; vaFileSize : Result := Result or DT_RIGHT; vaMethod : Result := Result or DT_CENTER; vaRatio : Result := Result or DT_CENTER; vaCRC : Result := Result or DT_CENTER; vaFileAttributes : Result := Result or DT_CENTER; vaFileType : Result := Result or DT_CENTER; vaEncryption : Result := Result or DT_CENTER; vaTimeStamp : Result := Result or DT_LEFT; vaVersionMade : Result := Result or DT_CENTER; vaVersionNeeded : Result := Result or DT_CENTER; vaPath : Result := Result or DT_LEFT; end; if (Result and 3) = DT_LEFT then OffsetRect(Rect, 5, 0) else if (Result and 3) = DT_RIGHT then OffsetRect(Rect, -5, 0); {$ENDIF} {$IFDEF LINUX} Result := Integer(AlignmentFlags_AlignVCenter) or Integer(AlignmentFlags_SingleLine); case Attr of vaItemname : Result := Result or Integer(AlignmentFlags_AlignLeft); vaPacked : Result := Result or Integer(AlignmentFlags_AlignRight); vaFileSize : Result := Result or Integer(AlignmentFlags_AlignRight); vaMethod : Result := Result or Integer(AlignmentFlags_AlignCenter); vaRatio : Result := Result or Integer(AlignmentFlags_AlignCenter); vaCRC : Result := Result or Integer(AlignmentFlags_AlignCenter); vaFileAttributes : Result := Result or Integer(AlignmentFlags_AlignCenter); vaFileType : Result := Result or Integer(AlignmentFlags_AlignCenter); vaEncryption : Result := Result or Integer(AlignmentFlags_AlignCenter); vaTimeStamp : Result := Result or Integer(AlignmentFlags_AlignLeft); vaVersionMade : Result := Result or Integer(AlignmentFlags_AlignCenter); vaVersionNeeded : Result := Result or Integer(AlignmentFlags_AlignCenter); vaPath : Result := Result or Integer(AlignmentFlags_AlignLeft); end; {$ENDIF} end; { -------------------------------------------------------------------------- } function TAbBaseViewer.GetActiveRow : Longint; begin Result := Row - 1; end; { -------------------------------------------------------------------------- } function TAbBaseViewer.GetCount : Longint; begin if Assigned(FItemList) then Result := FItemList.Count else Result := 0; end; { -------------------------------------------------------------------------- } function TAbBaseViewer.GetHeaderRowHeight : Integer; begin Result := RowHeights[AbHeaderRow]; end; { -------------------------------------------------------------------------- } {$IFDEF MSWINDOWS} function TAbBaseViewer.GetIcon(const ItemName : string) : HIcon; var i : Longint; t : string; sfi : SHFILEINFO; begin Result := 0; if not (doShowIcons in FDisplayOptions) then Exit; t := ExtractFileExt(ItemName); i := FIcons.IndexOf(t); if (i > -1) then Result := HIcon(FIcons.Objects[i]) else begin SHGetFileInfo(PChar(t), FILE_ATTRIBUTE_NORMAL, sfi, sizeof(sfi), SHGFI_ICON or SHGFI_USEFILEATTRIBUTES); Result := sfi.hIcon; FIcons.AddObject(t, Pointer(Result)); end; end; {$ENDIF} {$IFDEF UsingCLX } { no file type icons in CLX } {$ENDIF} { -------------------------------------------------------------------------- } function TAbBaseViewer.GetSelCount : Longint; begin Result := FSelList.SelCount; end; { -------------------------------------------------------------------------- } function TAbBaseViewer.GetSelected(RowNum : Longint) : Boolean; begin if Assigned(FItemList) then Result := FSelList.IsSelected(FRowMap[RowNum]) else Result := False; end; { -------------------------------------------------------------------------- } function TAbBaseViewer.GetVersion : string; begin Result := AbVersionS; end; { -------------------------------------------------------------------------- } procedure TAbBaseViewer.InitColMap; const cResString: array[TAbViewAttribute] of string = (AbItemNameHeadingS, AbPackedHeadingS, AbMethodHeadingS, AbRatioHeadingS, AbCRCHeadingS, AbFileAttrHeadingS, AbFileFormatHeadingS, AbEncryptionHeadingS, AbTimeStampHeadingS, AbFileSizeHeadingS, AbVersionMadeHeadingS, AbVersionNeededHeadingS, AbPathHeadingS); var i : TAbViewAttribute; begin FHeadings.Clear; for i := Low(TAbViewAttribute) to High(TAbViewAttribute) do begin FHeadings.Add(cResString[i]); FColMap[i] := Ord(i); end; end; { -------------------------------------------------------------------------- } procedure TAbBaseViewer.InvalidateRow(ARow: Longint); var Rect: TRect; begin if not HandleAllocated then Exit; if ((ARow < TopRow) or (ARow > TopRow + VisibleRowCount)) and (ARow <> 0) then Exit; Rect := CellRect(0, ARow); Rect.Right := ClientWidth; {$IFDEF UsingCLX} InvalidateRect(Rect, False); {$ELSE} InvalidateRect(Handle, @Rect, True); {$ENDIF} end; { -------------------------------------------------------------------------- } procedure TAbBaseViewer.KeyDown(var Key: Word; Shift: TShiftState); begin FShiftState := Shift; inherited KeyDown(Key, Shift); end; { -------------------------------------------------------------------------- } procedure TAbBaseViewer.KeyUp(var Key: Word; Shift: TShiftState); begin FShiftState := Shift; inherited KeyUp(Key, Shift); end; { -------------------------------------------------------------------------- } procedure TAbBaseViewer.Loaded; begin inherited Loaded; end; { -------------------------------------------------------------------------- } procedure TAbBaseViewer.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y : Integer); function GetMinLen(Col: Integer): Word; var I, L : Integer; s : String; aItem : TAbArchiveItem; Attr : TAbViewAttribute; Sorted : Boolean; begin Attr := TAbViewAttribute(ColMap(Col)); Result := Canvas.TextWidth(FHeadings[ColMap(Col)]); case Attr of vaItemName : Sorted := saItemName in FSortAttributes; vaPacked : Sorted := saPacked in FSortAttributes; vaRatio : Sorted := saRatio in FSortAttributes; vaTimeStamp: Sorted := saTimeStamp in FSortAttributes; vaFileSize : Sorted := saFileSize in FSortAttributes; vaPath : Sorted := saPath in FSortAttributes; else Sorted := False; end; if Sorted then Result := Result + RowHeights[0] + 16 else Result := Result + 8; if Assigned(FItemList) then for I := 0 to (FItemList.Count-1) do begin aItem := FItemList.Items[I]; S := AttrToStr(Attr, aItem); L := Canvas.TextWidth(S) + 8; if (doShowIcons in FDisplayOptions) and (Attr = vaItemName) then inc(L, RowHeights[I]); if L > Result then Result := L; end; end; var ACol : Longint; ARow : Longint; Rect : TRect; begin ViewMouseCoord := MouseCoord(X, Y); inherited MouseDown(Button, Shift, X, Y); FShiftState := Shift; { handle double clicks on header row dividers } if (ssDouble in FShiftState) and (ViewMouseCoord.Y = AbHeaderRow) then begin FColSizing := True; Rect := CellRect(ViewMouseCoord.X, ViewMouseCoord.Y); Rect.Left := Rect.Right - 3; if PtInRect(Rect, Point(X, Y)) then begin ColWidths[MouseCoord(Rect.Left, Y).X] := GetMinLen(MouseCoord(Rect.Left, Y).X) end else begin Rect := CellRect(ViewMouseCoord.X, ViewMouseCoord.Y); Rect.Right := Rect.Left + 4; if PtInRect(Rect, Point(X, Y)) then ColWidths[MouseCoord(Rect.Left, Y).X-1] := GetMinLen(MouseCoord(Rect.Left, Y).X-1); end; end; { if grid is being resized } if (FGridState = gsColSizing) then begin FColSizing := True; Exit; {dont press button when resizing column} end; { refresh the headers} if Assigned(FItemList) then if (FItemList.Count > 0) then begin ARow := ViewMouseCoord.Y; ACol := ViewMouseCoord.X; if (ARow = abHeaderRow) then begin {if not (doColMove in FDisplayOptions) then} if not (doColMove in FDisplayOptions) and not FColSizing then FButtonDown := True; RefreshCell(0, ACol); end else if not (ssShift in Shift) then RowAnchor := ActiveRow; end; end; { -------------------------------------------------------------------------- } procedure TAbBaseViewer.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var ACol : Longint; ARow : Longint; Attr : TAbViewAttribute; SortAttribute : TAbSortAttribute; begin inherited MouseUp(Button, Shift, X, Y); if csDesigning in ComponentState then Exit; FShiftState := Shift; FButtonDown := False; if FColSizing then begin Refresh; FColSizing := False; end else if Assigned(FItemList) then if (FItemList.Count > 0) then begin ARow := ViewMouseCoord.Y; ACol := ViewMouseCoord.X; if (ARow = abHeaderRow) then begin Attr := TAbViewAttribute(ColMap(ACol)); if not FColMoving and AttrToSortAttribute(Attr, SortAttribute) and (SortAttribute in FSortAttributes) then begin FSortCol := ACol; FItemIndex := FRowMap[Row-1]; FRowMap.SortBy(SortAttribute, FItemList); FButtonDown := False; RefreshCell(0, ACol); if (doTrackActiveRow in FDisplayOptions) then Row := FRowMap.InvRows[FItemIndex] + 1; Refresh; DoSorted(Attr); end else begin FButtonDown := False; RefreshCell(0, ACol); end; end else Paint; end; FColMoving := False; end; { -------------------------------------------------------------------------- } procedure TAbBaseViewer.MouseMove(Shift: TShiftState; X, Y: Integer); begin inherited MouseMove(Shift, X, Y); if (FGridState = gsColMoving) then FColMoving := True; end; { -------------------------------------------------------------------------- } procedure TAbBaseViewer.MoveColumn(FromCol, ToCol : Integer); var temp, i : Integer; begin Temp := ColMap(FromCol); if (FromCol < ToCol) then begin for i := (FromCol + 1) to ToCol do FColMap[TAbViewAttribute(i-1)] := FColMap[TAbViewAttribute(i)]; {Shift left} end else begin for i := (FromCol - 1) downto ToCol do FColMap[TAbViewAttribute(i+1)] := FColMap[TAbViewAttribute(i)]; {Shift right} end; FColMap[TAbViewAttribute(ToCol)] := Temp; end; { -------------------------------------------------------------------------- } procedure TAbBaseViewer.RefreshCell(ARow, ACol: Longint); var Rect: TRect; begin if not HandleAllocated then Exit; Rect := CellRect(ACol, ARow); {$IFDEF UsingCLX} InvalidateRect(Rect, False); {$ELSE} InvalidateRect(Handle, @Rect, False); {$ENDIF} Update; end; { -------------------------------------------------------------------------- } procedure TAbBaseViewer.RefreshRow(ARow: Longint); begin InvalidateRow(ARow); Update; end; { -------------------------------------------------------------------------- } procedure TAbBaseViewer.SelectAll; begin if Assigned(FItemList) then if (FItemList.Count > 0) then begin FSelList.SelectAll(FItemList.Count); Invalidate; end; end; { -------------------------------------------------------------------------- } procedure TAbBaseViewer.SetActiveRow(RowNum : Longint); begin if Assigned(FItemList) then if (RowNum >= 0) and (RowNum < FItemList.Count) then Row := RowNum + 1; end; { -------------------------------------------------------------------------- } procedure TAbBaseViewer.SetAttributes(Value : TAbViewAttributes); begin FAttributes := Value; ColCount := UpdateColCount(FAttributes); DoChange(Self); end; { -------------------------------------------------------------------------- } procedure TAbBaseViewer.SetDisplayOptions(Value : TAbDisplayOptions); {maps DisplayOptions to TGridOptions} begin FDisplayOptions := Value; Options := [goFixedVertLine, goFixedHorzLine, goRowSelect]; {$IFDEF HasGridDrawingStyle} Options := Options + [goFixedRowClick]; // Highlight pressed header when themed {$ENDIF} if (doColLines in Value) then Options := Options + [goVertLine]; if (doColMove in Value) then Options := Options + [goColMoving]; if (doColSizing in Value) then Options := Options + [goColSizing]; if (doRowLines in Value) then Options := Options + [goHorzLine]; if (doThumbTrack in Value) then Options := Options + [goThumbTracking]; DoChange(nil); end; { -------------------------------------------------------------------------- } procedure TAbBaseViewer.SetHeaderRowHeight(Value : Integer); begin RowHeights[abHeaderRow] := Value; end; { -------------------------------------------------------------------------- } procedure TAbBaseViewer.SetHeadings(Value: TAbColHeadings); begin Headings.Assign(Value); Refresh; end; { -------------------------------------------------------------------------- } procedure TAbBaseViewer.SetSortAttributes(Value : TAbSortAttributes); begin FSortAttributes := Value; end; { -------------------------------------------------------------------------- } procedure TAbBaseViewer.SetSelected(RowNum : Longint; Value: Boolean); begin if Assigned(FItemList) then case Value of True : FSelList.Select(FRowMap[RowNum]); False : FSelList.Deselect(FRowMap[RowNum]); end; end; { -------------------------------------------------------------------------- } procedure TAbBaseViewer.SetVersion(const Value : string); begin {NOP} end; { -------------------------------------------------------------------------- } procedure TAbBaseViewer.TopLeftChanged; begin if FAllowInvalidate then Invalidate; end; { -------------------------------------------------------------------------- } function TAbBaseViewer.UpdateColCount(Attributes : TAbViewAttributes) : Integer; var i : TAbViewAttribute; begin Result := 0; for i := Low(TAbViewAttribute) to High(TAbViewAttribute) do begin if (i in Attributes) then begin FColMap[TAbViewAttribute(Result)] := Ord(i); Inc(Result); end; end; end; { -------------------------------------------------------------------------- } {$IFDEF UsingCLX} procedure TAbBaseViewer.SizeChanged(OldColCount, OldRowCount: Longint); begin inherited SizeChanged(OldColCount, OldRowCount); Refresh; end; {$ELSE} procedure TAbBaseViewer.WMSize(var Msg: TWMSize); begin inherited; Refresh; end; {$ENDIF} { -------------------------------------------------------------------------- } {$IFNDEF UsingCLX} procedure TAbBaseViewer.WMEraseBkgnd(var Msg: TWMEraseBkgnd); begin Msg.Result := -1; end; {$ENDIF} end. ================================================ FILE: lib/abbrevia/source/AbWavPack.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is Craig Peterson * * Portions created by the Initial Developer are Copyright (C) 2011 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Craig Peterson * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbWavPack.pas *} {*********************************************************} {* ABBREVIA: WavPack decompression procedures *} {*********************************************************} unit AbWavPack; {$I AbDefine.inc} interface uses Classes; // Decompress a WavPack compressed stream from aSrc and write to aDes. // aSrc must not allow reads past the compressed data. procedure DecompressWavPack(aSrc, aDes: TStream); implementation uses AbCrtl, Math, SysUtils; // Compile using // bcc32 -DWIN32 -DNO_USE_FSTREAMS -c -w-8004 -w-8012 -w-8017 -w-8057 -w-8065 *.c // // In wavpack_local.h remove the line "#define FASTCALL __fastcall" { C runtime library ======================================================== } function fabs(x: Double): Double; cdecl; begin if x < 0 then Result := -1 else Result := x end; function floor(x: Double): Integer; cdecl; begin Result := Floor(x); end; function labs(n: Integer): Integer; cdecl; begin if n < 0 then Result := -n else Result := n; end; function _stricmp(str1, str2: PAnsiChar): Integer; cdecl; external 'msvcrt.dll' name '_stricmp'; function strncmp(str1, str2: PAnsiChar; num: Integer): Integer; cdecl; external 'msvcrt.dll' {$IFDEF BCB}name '_strncmp'{$ENDIF}; { Forward declarations ===================================================== } // bits.c procedure bs_open_read; external; procedure bs_close_read; external; procedure bs_open_write; external; procedure bs_close_write; external; procedure little_endian_to_native; external; procedure native_to_little_endian; external; // extra1.c procedure execute_mono; external; // extra2.c procedure execute_stereo; external; // float.c procedure float_values; external; procedure read_float_info; external; procedure scan_float_data; external; procedure send_float_data; external; procedure WavpackFloatNormalize; external; procedure write_float_info; external; // metadata.c procedure add_to_metadata; external; procedure copy_metadata; external; procedure free_metadata; external; procedure process_metadata; external; procedure read_metadata_buff; external; procedure write_metadata_block; external; // pack.c procedure pack_block; external; procedure pack_init; external; // tags.c procedure load_tag; external; procedure valid_tag; external; // unpack.c procedure check_crc_error; external; procedure free_tag; external; procedure unpack_init; external; procedure unpack_samples; external; // unpack3.c procedure free_stream3; external; procedure get_version3; external; procedure get_sample_index3; external; procedure open_file3; external; procedure seek_sample3; external; procedure unpack_samples3; external; // words.c procedure exp2s; external; procedure flush_word; external; procedure get_word; external; procedure get_words_lossless; external; procedure init_words; external; procedure log2s; external; procedure log2buffer; external; procedure nosend_word; external; procedure read_hybrid_profile; external; procedure read_entropy_vars; external; procedure restore_weight; external; procedure scan_word; external; procedure send_word; external; procedure send_words_lossless; external; procedure store_weight; external; procedure write_entropy_vars; external; procedure write_hybrid_profile; external; { Linker derectives ======================================================== } {$IF DEFINED(WIN32)} {$L Win32\wv_bits.obj} {$L Win32\wv_extra1.obj} {$L Win32\wv_extra2.obj} {$L Win32\wv_float.obj} {$L Win32\wv_metadata.obj} {$L Win32\wv_pack.obj} {$L Win32\wv_tags.obj} {$L Win32\wv_unpack.obj} {$L Win32\wv_unpack3.obj} {$L Win32\wv_words.obj} {$L Win32\wv_wputils.obj} {$ELSEIF DEFINED(WIN64)} {$L Win64\wv_bits.obj} {$L Win64\wv_extra1.obj} {$L Win64\wv_extra2.obj} {$L Win64\wv_float.obj} {$L Win64\wv_metadata.obj} {$L Win64\wv_pack.obj} {$L Win64\wv_tags.obj} {$L Win64\wv_unpack.obj} {$L Win64\wv_unpack3.obj} {$L Win64\wv_words.obj} {$L Win64\wv_wputils.obj} {$IFEND} { wavpack_local.h ========================================================== } const OPEN_WVC = $1; // open/read "correction" file OPEN_TAGS = $2; // read ID3v1 / APEv2 tags (seekable file) OPEN_WRAPPER = $4; // make audio wrapper available (i.e. RIFF) OPEN_2CH_MAX = $8; // open multichannel as stereo (no downmix) OPEN_NORMALIZE = $10; // normalize floating point data to +/- 1.0 OPEN_STREAMING = $20; // "streaming" mode blindly unpacks blocks // w/o regard to header file position info OPEN_EDIT_TAGS = $40; // allow editing of tags type int32_t = LongInt; uint32_t = LongWord; WavpackStreamReader = record read_bytes: function(id, data: Pointer; bcount: int32_t): int32_t; cdecl; get_pos: function(id: Pointer): uint32_t; cdecl; set_pos_abs: function(id: Pointer; pos: uint32_t): Integer; cdecl; set_pos_rel: function(id: Pointer; delta: int32_t; mode: Integer): Integer; cdecl; push_back_byte: function(id: Pointer; c: Integer): Integer; cdecl; get_length: function(id: Pointer): uint32_t; cdecl; can_seek: function(id: Pointer): Integer; cdecl; write_bytes: function(id, data: Pointer; bcount: int32_t): int32_t; cdecl; end; WavpackContext = Pointer; { wputils.c ================================================================ } function WavpackOpenFileInputEx(const reader: WavpackStreamReader; wv_id, wvc_id: Pointer; error: PAnsiChar; flags, norm_offset: Integer): WavpackContext; cdecl; external; function WavpackGetWrapperBytes(wpc: WavpackContext): uint32_t; cdecl; external; function WavpackGetWrapperData(wpc: WavpackContext): PByte; cdecl; external; procedure WavpackFreeWrapper (wpc: WavpackContext); cdecl; external; procedure WavpackSeekTrailingWrapper(wpc: WavpackContext); cdecl; external; function WavpackGetNumSamples(wpc: WavpackContext): uint32_t; cdecl; external; function WavpackGetNumChannels(wpc: WavpackContext): Integer; cdecl; external; function WavpackGetBytesPerSample (wpc: WavpackContext): Integer; cdecl; external; function WavpackUnpackSamples(wpc: WavpackContext; buffer: Pointer; samples: uint32_t): uint32_t; cdecl; external; function WavpackCloseFile(wpc: WavpackContext): WavpackContext; cdecl; external; { TWavPackStream implementation ============================================ } type PWavPackStream = ^TWavPackStream; TWavPackStream = record HasPushedByte: Boolean; PushedByte: Byte; Stream: TStream; end; { -------------------------------------------------------------------------- } function TWavPackStream_read_bytes(id, data: Pointer; bcount: int32_t): int32_t; cdecl; begin if PWavPackStream(id).HasPushedByte then begin PByte(data)^ := PWavPackStream(id).PushedByte; PWavPackStream(id).HasPushedByte := False; Inc(PByte(data)); Dec(bcount); if bcount = 0 then Result := 1 else Result := PWavPackStream(id).Stream.Read(data^, bcount) + 1; end else Result := PWavPackStream(id).Stream.Read(data^, bcount); end; { -------------------------------------------------------------------------- } function TWavPackStream_get_pos(id: Pointer): uint32_t; cdecl; begin Result := PWavPackStream(id).Stream.Position; end; { -------------------------------------------------------------------------- } function TWavPackStream_set_pos_abs(id: Pointer; pos: uint32_t): Integer; cdecl; begin PWavPackStream(id).Stream.Position := pos; Result := 0; end; { -------------------------------------------------------------------------- } function TWavPackStream_set_pos_rel(id: Pointer; delta: int32_t; mode: Integer): Integer; cdecl; begin PWavPackStream(id).Stream.Seek(delta, mode); Result := 1; end; { -------------------------------------------------------------------------- } function TWavPackStream_push_back_byte(id: Pointer; c: Integer): Integer; cdecl; begin Assert(not PWavPackStream(id).HasPushedByte); PWavPackStream(id).HasPushedByte := True; PWavPackStream(id).PushedByte := Byte(c); Result := 1; end; { -------------------------------------------------------------------------- } function TWavPackStream_get_length(id: Pointer): uint32_t; cdecl; begin Result := PWavPackStream(id).Stream.Size; end; { -------------------------------------------------------------------------- } function TWavPackStream_can_seek(id: Pointer): Integer; cdecl; begin Result := 1; end; { -------------------------------------------------------------------------- } function TWavPackStream_write_bytes(id, data: Pointer; bcount: int32_t): int32_t; cdecl; begin Result := PWavPackStream(id).Stream.Write(data^, bcount); end; { Decompression routines =================================================== } { -------------------------------------------------------------------------- } // Reformat samples from longs in processor's native endian mode to // little-endian data with (possibly) less than 4 bytes / sample. // // Based on wvunpack.c::format_samples. // Conversions simplified since we only support little-endian processors function FormatSamples(bps: Integer; dst, src: PByte; samcnt: uint32_t): PByte; var sample: LongWord; begin while samcnt > 0 do begin Dec(samcnt); // Get next sample sample := PLongWord(src)^; // Convert and write to output case bps of 1: begin dst^ := sample + 128; end; 2: begin PWord(dst)^ := sample; end; 3: begin PByteArray(dst)[0] := sample; PByteArray(dst)[1] := sample shr 8; PByteArray(dst)[2] := sample shr 16; end; 4: begin PLongWord(dst)^ := sample; end; end; Inc(src, SizeOf(LongWord)); Inc(dst, bps); end; Result := dst; end; { -------------------------------------------------------------------------- } // Decompress a WavPack compressed stream from aSrc and write to aDes. // aSrc must not allow reads past the compressed data. // // Based on wvunpack.c::unpack_file() procedure DecompressWavPack(aSrc, aDes: TStream); type PtrInt = {$IF DEFINED(CPUX64)}Int64{$ELSE}LongInt{$IFEND}; const OutputBufSize = 256 * 1024; var StreamReader: WavpackStreamReader; Context: WavpackContext; Src: TWavpackStream; Error: array[0..79] of AnsiChar; SamplesToUnpack, SamplesUnpacked: uint32_t; NumChannels, bps, BytesPerSample: Integer; OutputBuf, OutputPtr: PByte; DecodeBuf: Pointer; begin OutputBuf := nil; DecodeBuf := nil; StreamReader.read_bytes := TWavPackStream_read_bytes; StreamReader.get_pos := TWavPackStream_get_pos; StreamReader.set_pos_abs := TWavPackStream_set_pos_abs; StreamReader.set_pos_rel := TWavPackStream_set_pos_rel; StreamReader.push_back_byte := TWavPackStream_push_back_byte; StreamReader.get_length := TWavPackStream_get_length; StreamReader.can_seek := TWavPackStream_can_seek; StreamReader.write_bytes := TWavPackStream_write_bytes; FillChar(Src, SizeOf(Src), 0); Src.Stream := aSrc; Context := WavpackOpenFileInputEx(StreamReader, @Src, nil, Error, OPEN_WRAPPER, 0); if Context = nil then raise Exception.Create('WavPack decompression failed: ' + Error); try // Write .wav header if WavpackGetWrapperBytes(Context) > 0 then begin aDes.WriteBuffer(WavpackGetWrapperData(Context)^, WavpackGetWrapperBytes(Context)); WavpackFreeWrapper(Context); end; NumChannels := WavpackGetNumChannels(Context); bps := WavpackGetBytesPerSample(Context); BytesPerSample := NumChannels * bps; GetMem(OutputBuf, OutputBufSize); OutputPtr := OutputBuf; GetMem(DecodeBuf, 4096 * NumChannels * SizeOf(Integer)); repeat // Unpack samples SamplesToUnpack := (OutputBufSize - (PtrInt(OutputPtr) - PtrInt(OutputBuf))) div BytesPerSample; if (SamplesToUnpack > 4096) then SamplesToUnpack := 4096; SamplesUnpacked := WavpackUnpackSamples(Context, DecodeBuf, SamplesToUnpack); // Convert from 32-bit integers down to appriopriate bit depth // and copy to output buffer. if (SamplesUnpacked > 0) then OutputPtr := FormatSamples(bps, OutputPtr, DecodeBuf, SamplesUnpacked * uint32_t(NumChannels)); // Write output when it's full or when we're done if (SamplesUnpacked = 0) or ((OutputBufSize - (PtrInt(OutputPtr) - PtrInt(OutputBuf))) < BytesPerSample) then begin aDes.WriteBuffer(OutputBuf^, PtrInt(OutputPtr) - PtrInt(OutputBuf)); OutputPtr := OutputBuf; end; until (SamplesUnpacked = 0); // Write .wav footer while WavpackGetWrapperBytes(Context) > 0 do begin try aDes.WriteBuffer(WavpackGetWrapperData(Context)^, WavpackGetWrapperBytes(Context)); finally WavpackFreeWrapper(Context); end; // Check for more RIFF data WavpackUnpackSamples (Context, DecodeBuf, 1); end; finally if DecodeBuf <> nil then FreeMemory(DecodeBuf); if OutputBuf <> nil then FreeMemory(OutputBuf); WavpackCloseFile(Context); end; end; end. ================================================ FILE: lib/abbrevia/source/AbZBrows.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Craig Peterson * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbZBrows.pas *} {*********************************************************} {* ABBREVIA: Zip file Browser Component *} {*********************************************************} unit AbZBrows; {$I AbDefine.inc} interface uses Classes, AbArcTyp, AbBrowse, AbSpanSt, AbZipTyp; type TAbCustomZipBrowser = class(TAbBaseBrowser) private function GetTarAutoHandle: Boolean; procedure SetTarAutoHandle(const Value: Boolean); protected {private} FPassword : AnsiString; FOnRequestLastDisk : TAbRequestDiskEvent; FOnRequestNthDisk : TAbRequestNthDiskEvent; FOnRequestBlankDisk : TAbRequestDiskEvent; FTarAutoHandle : Boolean; protected {methods} function GetItem(Index : Integer) : TAbZipItem; virtual; function GetStream: TStream; function GetZipfileComment : AnsiString; procedure InitArchive; override; procedure SetFileName(const aFileName : string); override; procedure SetStream(aValue: TStream); procedure SetOnRequestLastDisk(Value : TAbRequestDiskEvent); procedure SetOnRequestNthDisk(Value : TAbRequestNthDiskEvent); procedure SetOnRequestBlankDisk(Value : TAbRequestDiskEvent); procedure SetPassword(const Value : AnsiString); procedure SetZipfileComment(const Value : AnsiString); virtual; protected {properties} property Password : AnsiString read FPassword write SetPassword; protected {events} property OnRequestLastDisk : TAbRequestDiskEvent read FOnRequestLastDisk write SetOnRequestLastDisk; property OnRequestNthDisk : TAbRequestNthDiskEvent read FOnRequestNthDisk write SetOnRequestNthDisk; property OnRequestBlankDisk : TAbRequestDiskEvent read FOnRequestBlankDisk write SetOnRequestBlankDisk; public {methods} constructor Create(AOwner : TComponent); override; destructor Destroy; override; public {properties} property Items[Index : Integer] : TAbZipItem read GetItem; default; property Stream : TStream // This can be used instead of Filename read GetStream write SetStream; property ZipArchive : {TAbZipArchive} TAbArchive read FArchive; property ZipfileComment : AnsiString read GetZipfileComment write SetZipfileComment; property TarAutoHandle : Boolean read GetTarAutoHandle write SetTarAutoHandle; end; TAbZipBrowser = class(TAbCustomZipBrowser) published property ArchiveProgressMeter; property ItemProgressMeter; property BaseDirectory; property LogFile; property Logging; property OnArchiveProgress; property OnArchiveItemProgress; property OnChange; property OnConfirmProcessItem; property OnLoad; property OnProcessItemFailure; property OnRequestLastDisk; property OnRequestNthDisk; property Version; property TarAutoHandle; property FileName; {must be after OnLoad} end; implementation uses SysUtils, AbBzip2Typ, AbExcept, AbGzTyp, AbTarTyp, AbUtils; { TAbCustomZipBrowser implementation ======================================= } { -------------------------------------------------------------------------- } constructor TAbCustomZipBrowser.Create(AOwner : TComponent); begin inherited Create(AOwner); end; { -------------------------------------------------------------------------- } destructor TAbCustomZipBrowser.Destroy; begin inherited Destroy; end; { -------------------------------------------------------------------------- } function TAbCustomZipBrowser.GetItem(Index : Integer) : TAbZipItem; begin Result := TAbZipItem(ZipArchive.ItemList[Index]); end; { -------------------------------------------------------------------------- } function TAbCustomZipBrowser.GetStream: TStream; begin if FArchive <> nil then Result := FArchive.FStream else Result := nil end; { -------------------------------------------------------------------------- } function TAbCustomZipBrowser.GetTarAutoHandle: Boolean; begin Result := False; if FArchive is TAbGzipArchive then Result := TAbGzipArchive(FArchive).TarAutoHandle else if FArchive is TAbBzip2Archive then Result := TAbBzip2Archive(FArchive).TarAutoHandle; end; { -------------------------------------------------------------------------- } function TAbCustomZipBrowser.GetZipfileComment : AnsiString; begin if FArchive is TAbZipArchive then Result := TAbZipArchive(FArchive).ZipfileComment else Result := ''; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipBrowser.InitArchive; begin inherited InitArchive; if FArchive is TAbZipArchive then begin {properties} TAbZipArchive(FArchive).Password := FPassword; {events} TAbZipArchive(FArchive).OnRequestLastDisk := FOnRequestLastDisk; TAbZipArchive(FArchive).OnRequestNthDisk := FOnRequestNthDisk; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipBrowser.SetFileName(const aFileName : string); var ArcType : TAbArchiveType; begin FFileName := aFileName; if csDesigning in ComponentState then Exit; try if Assigned(FArchive) then begin FArchive.Save; end; except end; FArchive.Free; FArchive := nil; if FileName <> '' then begin if FileExists(FileName) then begin { open it } ArcType := ArchiveType; if not ForceType then ArcType := AbDetermineArcType(FileName, atUnknown); case ArcType of atZip, atSpannedZip, atSelfExtZip : begin FArchive := TAbZipArchive.Create(FileName, fmOpenRead or fmShareDenyNone); InitArchive; end; atTar : begin FArchive := TAbTarArchive.Create(FileName, fmOpenRead or fmShareDenyNone); inherited InitArchive; end; atGZip : begin FArchive := TAbGzipArchive.Create(FileName, fmOpenRead or fmShareDenyNone); TAbGzipArchive(FArchive).TarAutoHandle := FTarAutoHandle; TAbGzipArchive(FArchive).IsGzippedTar := False; inherited InitArchive; end; atGZippedTar : begin FArchive := TAbGzipArchive.Create(FileName, fmOpenRead or fmShareDenyNone); TAbGzipArchive(FArchive).TarAutoHandle := FTarAutoHandle; TAbGzipArchive(FArchive).IsGzippedTar := True; inherited InitArchive; end; atBzip2 : begin FArchive := TAbBzip2Archive.Create(FileName, fmOpenRead or fmShareDenyNone); TAbBzip2Archive(FArchive).TarAutoHandle := FTarAutoHandle; TAbBzip2Archive(FArchive).IsBzippedTar := False; inherited InitArchive; end; atBzippedTar : begin FArchive := TAbBzip2Archive.Create(FileName, fmOpenRead or fmShareDenyNone); TAbBzip2Archive(FArchive).TarAutoHandle := FTarAutoHandle; TAbBzip2Archive(FArchive).IsBzippedTar := True; inherited InitArchive; end; else raise EAbUnhandledType.Create; end {case}; FArchive.Load; FArchiveType := ArcType; end; end; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipBrowser.SetStream(aValue: TStream); var ArcType : TAbArchiveType; begin FFileName := ''; try if FArchive <> nil then FArchive.Save; except end; FreeAndNil(FArchive); if aValue <> nil then begin ArcType := ArchiveType; if not ForceType then ArcType := AbDetermineArcType(aValue); case ArcType of atZip, atSpannedZip, atSelfExtZip : begin FArchive := TAbZipArchive.CreateFromStream(aValue, ''); end; atTar : begin FArchive := TAbTarArchive.CreateFromStream(aValue, ''); end; atGZip, atGZippedTar : begin FArchive := TAbGzipArchive.CreateFromStream(aValue, ''); TAbGzipArchive(FArchive).TarAutoHandle := FTarAutoHandle; TAbGzipArchive(FArchive).IsGzippedTar := (ArcType = atGZippedTar); end; atBzip2, atBzippedTar : begin FArchive := TAbBzip2Archive.CreateFromStream(aValue, ''); TAbBzip2Archive(FArchive).TarAutoHandle := FTarAutoHandle; TAbBzip2Archive(FArchive).IsBzippedTar := (ArcType = atBzippedTar); end; else raise EAbUnhandledType.Create; end {case}; InitArchive; FArchive.Load; FArchiveType := ArcType; end; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipBrowser.SetOnRequestBlankDisk(Value : TAbRequestDiskEvent); begin FOnRequestBlankDisk := Value; if FArchive is TAbZipArchive then TAbZipArchive(FArchive).OnRequestBlankDisk := FOnRequestBlankDisk; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipBrowser.SetOnRequestLastDisk(Value : TAbRequestDiskEvent); begin FOnRequestLastDisk := Value; if FArchive is TAbZipArchive then TAbZipArchive(FArchive).OnRequestLastDisk := FOnRequestLastDisk; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipBrowser.SetOnRequestNthDisk(Value : TAbRequestNthDiskEvent); begin FOnRequestNthDisk := Value; if FArchive is TAbZipArchive then TAbZipArchive(FArchive).OnRequestNthDisk := FOnRequestNthDisk; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipBrowser.SetPassword(const Value : AnsiString); begin FPassword := Value; if FArchive is TAbZipArchive then TAbZipArchive(FArchive).Password := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipBrowser.SetTarAutoHandle(const Value: Boolean); begin FTarAutoHandle := Value; if FArchive is TAbGzipArchive then begin if TAbGzipArchive(FArchive).TarAutoHandle <> Value then begin TAbGzipArchive(FArchive).TarAutoHandle := Value; InitArchive; FArchive.Load; DoChange; end; end; if FArchive is TAbBzip2Archive then begin if TAbBzip2Archive(FArchive).TarAutoHandle <> Value then begin TAbBzip2Archive(FArchive).TarAutoHandle := Value; InitArchive; FArchive.Load; DoChange; end; end; end; procedure TAbCustomZipBrowser.SetZipfileComment(const Value : AnsiString); begin {NOP - descendents wishing to set this property should override} end; { -------------------------------------------------------------------------- } end. ================================================ FILE: lib/abbrevia/source/AbZLTyp.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbZLTyp.pas *} {*********************************************************} {* ABBREVIA: TAbZlItem class *} {*********************************************************} {* Misc. constants, types, and routines for working *} {* with ZLib compressed data *} {* See: RFC 1950 *} {* "ZLIB Compressed Data Format Specification *} {* version 3.3" for more information on ZLib *} {*********************************************************} unit AbZLTyp; {$I AbDefine.inc} interface uses SysUtils, Classes, AbUtils, AbArcTyp, AbZipPrc, AbDfBase, AbDfDec, AbDfEnc; const AB_ZL_PRESET_DICT = $20; AB_ZL_DEF_COMPRESSIONMETHOD = $8; { Deflate } AB_ZL_DEF_COMPRESSIONINFO = $7; { 32k window for Deflate } AB_ZL_FASTEST_COMPRESSION = $0; AB_ZL_FAST_COMPRESSION = $1; AB_ZL_DEFAULT_COMPRESSION = $2; AB_ZL_MAXIMUM_COMPRESSION = $3; AB_ZL_FCHECK_MASK = $1F; AB_ZL_CINFO_MASK = $F0; { mask out leftmost 4 bits } AB_ZL_FLEVEL_MASK = $C0; { mask out leftmost 2 bits } AB_ZL_CM_MASK = $0F; { mask out rightmost 4 bits } type TAbZLHeader = packed record CMF : Byte; FLG : Byte; end; TAbZLItem = class(TAbArchiveItem) private function GetCompressionInfo: Byte; function GetCompressionLevel: Byte; function GetIsPresetDictionaryPresent: Boolean; procedure SetCompressionInfo(Value: Byte); procedure SetCompressionLevel(Value: Byte); function GetCompressionMethod: Byte; procedure SetCompressionMethod(Value: Byte); function GetFCheck: Byte; procedure MakeFCheck; protected { private } FZLHeader : TAbZlHeader; FAdler32 : LongInt; public constructor Create; property IsPresetDictionaryPresent : Boolean read GetIsPresetDictionaryPresent; property CompressionLevel : Byte read GetCompressionLevel write SetCompressionLevel; property CompressionInfo : Byte read GetCompressionInfo write SetCompressionInfo; property CompressionMethod : Byte read GetCompressionMethod write SetCompressionMethod; property Adler32 : LongInt read FAdler32 write FAdler32; property FCheck : Byte read GetFCheck; procedure SaveZLHeaderToStream(AStream : TStream); procedure ReadZLHeaderFromStream(AStream : TStream); end; TAbZLStreamHelper = class(TAbArchiveStreamHelper) protected { private } FItem : TAbZLItem; public constructor Create(AStream : TStream); destructor Destroy; override; property Item : TAbZLItem read FItem; procedure ExtractItemData(AStream : TStream); override; function FindFirstItem : Boolean; override; function FindNextItem : Boolean; override; procedure ReadHeader; override; procedure ReadTail; override; function SeekItem(Index : Integer): Boolean; override; procedure WriteArchiveHeader; override; procedure WriteArchiveItem(AStream : TStream); override; procedure WriteArchiveTail; override; function GetItemCount : Integer; override; end; implementation { TAbZLStreamHelper } constructor TAbZLStreamHelper.Create(AStream: TStream); begin inherited Create(AStream); FItem := TAbZLItem.Create; end; destructor TAbZLStreamHelper.Destroy; begin FItem.Free; inherited Destroy; end; procedure TAbZLStreamHelper.ExtractItemData(AStream: TStream); { assumes already positioned appropriately } var Hlpr : TAbDeflateHelper; begin Hlpr := TAbDeflateHelper.Create; Hlpr.Options := Hlpr.Options or dfc_UseAdler32; if not FItem.IsPresetDictionaryPresent then Inflate(FStream, AStream, Hlpr) else raise Exception.Create('preset dictionaries unsupported'); Hlpr.Free; end; function TAbZLStreamHelper.FindFirstItem: Boolean; var ZLH : TAbZLHeader; begin FStream.Seek(0, soBeginning); Result := FStream.Read(ZLH, SizeOf(TAbZLHeader)) = SizeOf(TAbZLHeader); FItem.FZLHeader := ZLH; FStream.Seek(0, soBeginning); end; function TAbZLStreamHelper.FindNextItem: Boolean; begin { only one item in a ZLib Stream } Result := FindFirstItem; end; function TAbZLStreamHelper.GetItemCount: Integer; begin { only one item in a ZLib Stream } Result := 1; end; procedure TAbZLStreamHelper.ReadHeader; { assumes already positioned appropriately } var ZLH : TAbZLHeader; begin FStream.Read(ZLH, SizeOf(TAbZlHeader)); FItem.FZLHeader := ZLH; end; procedure TAbZLStreamHelper.ReadTail; { assumes already positioned appropriately } var Adler: LongInt; begin FStream.Read(Adler, SizeOf(LongInt)); FItem.Adler32 := Adler; end; function TAbZLStreamHelper.SeekItem(Index: Integer): Boolean; begin { only one item in a ZLib Stream } if Index <> 1 then Result := False else Result := FindFirstItem; end; procedure TAbZLStreamHelper.WriteArchiveHeader; begin Item.SaveZLHeaderToStream(FStream); end; procedure TAbZLStreamHelper.WriteArchiveItem(AStream: TStream); var Hlpr : TAbDeflateHelper; begin { Compress file } Hlpr := TAbDeflateHelper.Create; Hlpr.Options := Hlpr.Options or dfc_UseAdler32; Item.Adler32 := AbDfEnc.Deflate(AStream, FStream, Hlpr); Hlpr.Free; end; procedure TAbZLStreamHelper.WriteArchiveTail; var Ad32 : LongInt; begin Ad32 := AbSwapLongEndianness(Item.Adler32); FStream.Write(Ad32, SizeOf(LongInt)); end; { TAbZLItem } constructor TAbZLItem.Create; begin { Set default Values for fields } FillChar(FZLHeader, SizeOf(TAbZlHeader), #0); FZLHeader.CMF := (AB_ZL_DEF_COMPRESSIONINFO shl 4); { 32k Window size } FZLHeader.CMF := FZLHeader.CMF or AB_ZL_DEF_COMPRESSIONMETHOD; { Deflate } FZLHeader.FLG := FZLHeader.FLG and not AB_ZL_PRESET_DICT; { no preset dictionary} FZLHeader.FLG := FZLHeader.FLG or (AB_ZL_DEFAULT_COMPRESSION shl 6); { assume default compression } MakeFCheck; end; function TAbZLItem.GetCompressionInfo: Byte; begin Result := FZLHeader.CMF shr 4; end; function TAbZLItem.GetCompressionLevel: Byte; begin Result := FZLHeader.FLG shr 6; end; function TAbZLItem.GetCompressionMethod: Byte; begin Result := FZLHeader.CMF and AB_ZL_CM_MASK; end; function TAbZLItem.GetFCheck: Byte; begin Result := FZLHeader.FLG and AB_ZL_FCHECK_MASK; end; function TAbZLItem.GetIsPresetDictionaryPresent: Boolean; begin Result := (FZLHeader.FLG and AB_ZL_PRESET_DICT) = AB_ZL_PRESET_DICT; end; procedure TAbZLItem.MakeFCheck; { create the FCheck value for the current Header } var zlh : Word; begin FZLHeader.FLG := FZLHeader.FLG and not AB_ZL_FCHECK_MASK; zlh := (FZLHeader.CMF * 256) + FZLHeader.FLG; Inc(FZLHeader.FLG, 31 - (zlh mod 31)); end; procedure TAbZLItem.ReadZLHeaderFromStream(AStream: TStream); begin AStream.Read(FZLHeader, SizeOf(TAbZLHeader)); end; procedure TAbZLItem.SaveZLHeaderToStream(AStream: TStream); begin MakeFCheck; AStream.Write(FZLHeader, SizeOf(TAbZlHeader)); end; procedure TAbZLItem.SetCompressionInfo(Value: Byte); begin FZLHeader.CMF := FZLHeader.CMF and not AB_ZL_CINFO_MASK; FZLHeader.CMF := FZLHeader.CMF or (Value shl 4); { shift value and add to bit field } end; procedure TAbZLItem.SetCompressionLevel(Value: Byte); var Temp : Byte; begin Temp := Value; if not Temp in [AB_ZL_FASTEST_COMPRESSION..AB_ZL_MAXIMUM_COMPRESSION] then Temp := AB_ZL_DEFAULT_COMPRESSION; FZLHeader.FLG := FZLHeader.FLG and not AB_ZL_FLEVEL_MASK; FZLHeader.FLG := FZLHeader.FLG or (Temp shl 6); { shift value and add to bit field } end; procedure TAbZLItem.SetCompressionMethod(Value: Byte); begin if Value > AB_ZL_CM_MASK then Value := (Value shl 4) shr 4; FZLHeader.CMF := FZLHeader.CMF and not AB_ZL_CM_MASK; FZLHeader.CMF := FZLHeader.CMF or Value; end; end. ================================================ FILE: lib/abbrevia/source/AbZView.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbZView.pas *} {*********************************************************} {* ABBREVIA: Zip archive viewer component *} {* Use AbQZView.pas for CLX *} {*********************************************************} {$IFNDEF UsingCLX} unit AbZView; {$ENDIF} {$I AbDefine.inc} interface uses Classes, {$IFDEF MSWINDOWS} Windows, {$ENDIF} {$IFDEF UsingCLX } QControls, AbQView, {$ELSE} Controls, AbView, {$ENDIF} AbZBrows, AbZipTyp; type TAbIncludeItemEvent = procedure (Sender: TObject; Item: TAbZipItem; var Include: Boolean) of object; TAbZipView = class(TAbBaseViewer) protected FZipComponent : TAbCustomZipBrowser; FOnIncludeItem: TAbIncludeItemEvent; function GetItem(RowNum : Longint) : TAbZipItem; procedure SetZipComponent(Value : TAbCustomZipBrowser); procedure Notification(AComponent : TComponent; Operation : TOperation); override; procedure DoChange(Sender : TObject); override; public property Items[RowNum : Longint] : TAbZipItem read GetItem; published {properties} property Align; property Anchors; property Attributes; {$IFNDEF UsingCLX} property BevelEdges; property BevelInner; property BevelKind; property BevelOuter; property BevelWidth; {$ENDIF} property BorderStyle; property Color; property Colors; {$IFNDEF UsingCLX} property Ctl3D; property ParentCtl3D; property DragCursor; {$ENDIF} property Cursor; property Headings; property DefaultColWidth; property DefaultRowHeight; property DisplayOptions; property HeaderRowHeight; property SortAttributes; property DragMode; {$IFDEF HasGridDrawingStyle} property DrawingStyle; {$ENDIF} property Enabled; property Font; {$IFDEF HasGridDrawingStyle} property GradientEndColor; property GradientStartColor; {$ENDIF} property ParentColor; property ParentFont; property ParentShowHint; property PopupMenu; property ShowHint; property TabOrder; property TabStop; {$IFDEF HasTouch} property Touch; {$ENDIF} property Version; property ZipComponent : TAbCustomZipBrowser read FZipComponent write SetZipComponent; published {Events} property OnChange; property OnClick; property OnDblClick; property OnEnter; property OnExit; {$IFDEF HasTouch} property OnGesture; {$ENDIF} property OnKeyDown; property OnKeyPress; property OnKeyUp; {$IFDEF HasOnMouseActivate} property OnMouseActivate; {$ENDIF} property OnMouseDown; {$IFDEF HasOnMouseEnter} property OnMouseEnter; property OnMouseLeave; {$ENDIF} property OnMouseMove; property OnMouseUp; property OnSorted; property OnDrawSortArrow; property OnIncludeItem: TAbIncludeItemEvent read FOnIncludeItem write FOnIncludeItem; end; implementation uses AbArcTyp; { ===== TAbZipView ========================================================= } function TAbZipView.GetItem(RowNum : Longint) : TAbZipItem; begin if Assigned(FItemList) then Result := TAbZipItem(FItemList.Items[FRowMap[RowNum]]) else Result := nil; end; { -------------------------------------------------------------------------- } procedure TAbZipView.Notification(AComponent : TComponent; Operation : TOperation); begin inherited Notification(AComponent, Operation); if Operation = opRemove then if Assigned(FZipComponent) and (AComponent = FZipComponent) then begin FZipComponent := nil; Refresh; end; end; { -------------------------------------------------------------------------- } procedure TAbZipView.SetZipComponent(Value : TAbCustomZipBrowser); begin if Value <> nil then begin FZipComponent := Value; if not (csDesigning in ComponentState) then begin FZipComponent.OnChange := DoChange; FZipComponent.OnLoad := DoLoad; DoChange(Self); end; end else FZipComponent := nil; end; { -------------------------------------------------------------------------- } procedure TAbZipView.DoChange(Sender : TObject); var i : Integer; TheArchive : TAbArchive; Include : Boolean; begin FItemList.Clear; if Assigned(FZipComponent) then begin { let's make this a bit easier to read } TheArchive := FZipComponent.FArchive; if Assigned(TheArchive) then begin for i := 0 to Pred(TheArchive.ItemList.Count) do begin if Assigned(FOnIncludeItem) then begin FOnIncludeItem(self, TAbZipItem(TheArchive.ItemList[i]), Include); if Include then FItemList.Add(TheArchive.ItemList[i]); end else begin { if it doesn't look like a folder place holder... } if TAbZipItem(TheArchive.ItemList[i]).DiskFileName <> TAbZipItem(TheArchive.ItemList[i]).DiskPath then { ...add it to the display list } FItemList.Add(TheArchive.ItemList[i]); end; end; end else FItemList.Clear; end else FItemList.Clear; inherited DoChange(Sender); end; end. ================================================ FILE: lib/abbrevia/source/AbZipExt.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbZipExt.pas *} {*********************************************************} {* ABBREVIA: Zip file registration *} {*********************************************************} unit AbZipExt; {$I AbDefine.inc} interface uses SysUtils, Classes; function AbExistingZipAssociation : Boolean; function AbGetZipAssociation(var App, ID, FileType : string) : Boolean; function AbRegisterZipExtension(const App : string; ID, FileType : string; Replace : Boolean) : Boolean; implementation uses {$IFDEF MSWINDOWS} Windows, Messages, Registry, ShellAPI, {$ENDIF} {$IFDEF LibcAPI} Libc, {$ENDIF} AbConst; const ZipExt = '.zip'; DefZipID = 'Zip'; DefZipType = 'Zip File'; OpenCommand = 'Shell\Open\Command'; DefaultIcon = 'DefaultIcon'; var Reg : TRegistry; { -------------------------------------------------------------------------- } function AbExistingZipAssociation : Boolean; var App, ID, FileType : string; begin Result := False; Reg := TRegistry.Create; Reg.RootKey := HKEY_CLASSES_ROOT; Reg.OpenKey('',False); if Reg.OpenKey(ZipExt, False) then begin ID := Reg.ReadString(''); if Reg.OpenKey('\' + ID, False) then begin FileType := Reg.ReadString(''); if Reg.OpenKey(OpenCommand, False) then begin App := Reg.ReadString(''); if (App <> '') then Result := True; end; end; end; Reg.Free; end; { -------------------------------------------------------------------------- } function AbGetZipAssociation(var App, ID, FileType : string) : Boolean; begin Result := False; Reg := TRegistry.Create; Reg.RootKey := HKEY_CLASSES_ROOT; Reg.OpenKey('',False); if Reg.OpenKey(ZipExt, False) then begin ID := Reg.ReadString(''); if Reg.OpenKey('\' + ID, False) then begin FileType := Reg.ReadString(''); if Reg.OpenKey(OpenCommand, False) then begin App := Reg.ReadString(''); Result := True; end; end; end; Reg.Free; end; { -------------------------------------------------------------------------- } function AbRegisterZipExtension(const App : string; ID, FileType : string; Replace : Boolean) : Boolean; begin Result := False; if AbExistingZipAssociation and not Replace then Exit; try if (ID = '') then ID := DefZipID; if (FileType = '') then FileType := DefZipType; Reg := TRegistry.Create; Reg.RootKey := HKEY_CLASSES_ROOT; Reg.OpenKey('',False); Reg.OpenKey(ZipExt, True); Reg.WriteString('', ID); Reg.OpenKey('\' + ID, True); Reg.WriteString('', FileType); Reg.OpenKey(OpenCommand, True); Reg.WriteString('', App); Reg.OpenKey('\' + DefaultIcon, True); Reg.WriteString('', App + ',0'); Result := True; finally Reg.Free; end; end; { -------------------------------------------------------------------------- } end. ================================================ FILE: lib/abbrevia/source/AbZipKit.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbZipKit.pas *} {*********************************************************} {* ABBREVIA: TABZipKit component *} {*********************************************************} unit AbZipKit; {$I AbDefine.inc} interface uses Classes, AbZipper, AbArcTyp, AbZipTyp; type TAbCustomZipKit = class(TAbCustomZipper) protected {private} FExtractOptions : TAbExtractOptions; FOnConfirmOverwrite : TAbConfirmOverwriteEvent; FOnNeedPassword : TAbNeedPasswordEvent; FPasswordRetries : Byte; protected {methods} procedure DoConfirmOverwrite(var Name : string; var Confirm : Boolean); virtual; procedure DoNeedPassword(Sender : TObject; var NewPassword : AnsiString); virtual; procedure InitArchive; override; procedure SetExtractOptions(Value : TAbExtractOptions); procedure SetPasswordRetries(Value : Byte); procedure UnzipProc(Sender : TObject; Item : TAbArchiveItem; const NewName : string ); procedure UnzipToStreamProc(Sender : TObject; Item : TAbArchiveItem; OutStream : TStream); procedure TestItemProc(Sender : TObject; Item : TAbArchiveItem); protected {properties} property ExtractOptions : TAbExtractOptions read FExtractOptions write SetExtractOptions default AbDefExtractOptions; property PasswordRetries : Byte read FPasswordRetries write SetPasswordRetries default AbDefPasswordRetries; protected {events} property OnConfirmOverwrite : TAbConfirmOverwriteEvent read FOnConfirmOverwrite write FOnConfirmOverwrite; property OnNeedPassword : TAbNeedPasswordEvent read FOnNeedPassword write FOnNeedPassword; public {methods} constructor Create(AOwner : TComponent); override; destructor Destroy; override; procedure ExtractAt(Index : Integer; const NewName : string); procedure ExtractFiles(const FileMask : string); {extract all files from the archive that match the mask} procedure ExtractFilesEx(const FileMask, ExclusionMask : string); {extract files matching FileMask except those matching ExclusionMask} procedure ExtractTaggedItems; {extract all tagged items from the archive} procedure ExtractToStream(const aFileName : string; ToStream : TStream); {extract the specified item to TStream descendant} procedure TestTaggedItems; {test all tagged items in the archive} public {property} property Spanned; end; TAbZipKit = class(TAbCustomZipKit) published property ArchiveProgressMeter; property ArchiveSaveProgressMeter; property AutoSave; property BaseDirectory; property CompressionMethodToUse; property DeflationOption; {$IFDEF MSWINDOWS} property DOSMode; {$ENDIF} property ExtractOptions; property SpanningThreshold; property ItemProgressMeter; property LogFile; property Logging; property OnArchiveProgress; property OnArchiveSaveProgress; property OnArchiveItemProgress; property OnChange; property OnConfirmOverwrite; property OnConfirmProcessItem; property OnConfirmSave; property OnLoad; property OnNeedPassword; property OnProcessItemFailure; property OnRequestBlankDisk; property OnRequestImage; property OnRequestLastDisk; property OnRequestNthDisk; property OnSave; property Password; property PasswordRetries; property StoreOptions; property TempDirectory; property Version; property FileName; {must be after OnLoad} end; implementation uses AbExcept, AbUnzPrc, AbZBrows; { -------------------------------------------------------------------------- } constructor TAbCustomZipKit.Create( AOwner : TComponent ); begin inherited Create( AOwner ); PasswordRetries := AbDefPasswordRetries; end; { -------------------------------------------------------------------------- } destructor TAbCustomZipKit.Destroy; begin inherited Destroy; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipKit.DoConfirmOverwrite( var Name : string; var Confirm : Boolean ); begin Confirm := True; if Assigned( FOnConfirmOverwrite ) then FOnConfirmOverwrite( Name, Confirm ); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipKit.DoNeedPassword( Sender : TObject; var NewPassword : AnsiString ); begin if Assigned( FOnNeedPassword ) then begin FOnNeedPassword( Self, NewPassword ); FPassword := NewPassword; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipKit.ExtractAt(Index : Integer; const NewName : string); {extract a file from the archive that match the index} begin if (FArchive <> nil) then FArchive.ExtractAt( Index, NewName ) else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipKit.ExtractFiles(const FileMask : string); {extract all files from the archive that match the mask} begin if (FArchive <> nil) then FArchive.ExtractFiles( FileMask ) else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipKit.ExtractFilesEx(const FileMask, ExclusionMask : string); {extract files matching FileMask except those matching ExclusionMask} begin if (FArchive <> nil) then FArchive.ExtractFilesEx( FileMask, ExclusionMask ) else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipKit.ExtractTaggedItems; {extract all tagged items from the archive} begin if (FArchive <> nil) then FArchive.ExtractTaggedItems else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipKit.ExtractToStream(const aFileName : string; ToStream : TStream); begin if (FArchive <> nil) then FArchive.ExtractToStream(aFileName, ToStream) else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipKit.InitArchive; begin inherited InitArchive; if (FArchive <> nil) then begin FArchive.ExtractOptions := FExtractOptions; FArchive.OnConfirmOverwrite := DoConfirmOverwrite; end; if FArchive is TAbZipArchive then begin {properties} TAbZipArchive(FArchive).PasswordRetries := FPasswordRetries; {events} TAbZipArchive(FArchive).OnNeedPassword := DoNeedPassword; TAbZipArchive(FArchive).ExtractHelper := UnzipProc; TAbZipArchive(FArchive).ExtractToStreamHelper := UnzipToStreamProc; TAbZipArchive(FArchive).TestHelper := TestItemProc; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipKit.SetExtractOptions( Value : TAbExtractOptions ); begin FExtractOptions := Value; if (FArchive <> nil) then FArchive.ExtractOptions := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipKit.SetPasswordRetries( Value : Byte ); begin FPasswordRetries := Value; if (FArchive <> nil) then (FArchive as TAbZipArchive).PasswordRetries := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipKit.TestTaggedItems; {test all tagged items in the archive} begin if (FArchive <> nil) then FArchive.TestTaggedItems else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipKit.UnzipProc( Sender : TObject; Item : TAbArchiveItem; const NewName : string ); begin AbUnzip( TAbZipArchive(Sender), TAbZipItem(Item), NewName); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipKit.UnzipToStreamProc(Sender : TObject; Item : TAbArchiveItem; OutStream : TStream); begin AbUnzipToStream(TAbZipArchive(Sender), TAbZipItem(Item), OutStream); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipKit.TestItemProc(Sender : TObject; Item : TAbArchiveItem); begin AbTestZipItem(TAbZipArchive(Sender), TAbZipItem(Item)); end; { -------------------------------------------------------------------------- } end. ================================================ FILE: lib/abbrevia/source/AbZipOut.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbZipOut.pas *} {*********************************************************} {* ABBREVIA: Visual Component with Zip and unzip support *} {* Use AbQZpOut.pas for CLX *} {*********************************************************} {$IFNDEF UsingCLX} unit AbZipOut; {$ENDIF} {$I AbDefine.inc} interface uses Classes, {$IFDEF MSWINDOWS} Windows, Messages, {$ENDIF} Types, {$IFDEF UsingCLX} QGraphics, QComCtrls, QImglist, QControls, QForms, {$ELSE} Graphics, Controls, Forms, ComCtrls, Imglist, {$ENDIF} AbArcTyp, AbBrowse, AbUtils, AbZipTyp; const cBitmapHeight = 16; cBitmapWidth = 16; type TAbZipAttribute = (zaCompressedSize, zaCompressionMethod, zaCompressionRatio, zaCRC, zaExternalFileAttributes, zaInternalFileAttributes, zaEncryption, zaTimeStamp, zaUncompressedSize, zaVersionMade, zaVersionNeeded, zaComment); TAbZipAttributes = set of TAbZipAttribute; const AbDefZipAttributes = [zaCompressedSize, zaCompressionMethod, zaCompressionRatio, zaCRC, zaExternalFileAttributes, zaEncryption, zaTimeStamp, zaUncompressedSize]; AbDefColor = clWindow; AbDefHierarchy = True; AbDefParentColor = False; {.Z+} type TTreeNodeFriend = class(TTreeNode) end; {.Z-} type TWindowsDropEvent = procedure(Sender : TObject; FileName : string) of object; {TAbZipDisplayOutline does not support Owner-Draw} type TAbZipDisplayOutline = class(TTreeView) private FDirBitMap : TBitMap; FFileBitMap : TBitMap; FAttrBitMap : TBitMap; FDirBitMapSelected : TBitMap; FFileBitMapSelected : TBitMap; FAttrBitMapSelected : TBitMap; FImageList : TImageList; FFileIndex : integer; FFileSelectedIndex : integer; FDirectoryIndex : integer; FDirSelectedIndex : integer; FAttrIndex : integer; FBitMapHeight : integer; FBitMapWidth : integer; FAttrSelectedIndex : integer; FOnWindowsDrop : TWindowsDropEvent; {$IFNDEF UsingCLX} procedure WMDropFiles(var Msg : TWMDropFiles); message WM_DROPFILES; {$ENDIF} procedure IndexBitmaps; procedure SetDirectoryBitMap(Value : TBitmap); procedure SetFileBitMap(Value : TBitmap); procedure SetAttributeBitMap(Value : TBitmap); procedure SetDirectoryBitMapSelected(Value : TBitmap); procedure SetFileBitMapSelected(Value : TBitmap); procedure SetAttributeBitMapSelected(Value : TBitmap); procedure SetBitMapHeight(Value : Integer); procedure SetBitMapWidth(Value : Integer); protected procedure DoOnWindowsDrop(FileName : string); virtual; {$IFDEF UsingCLX} function DoMouseWheel(Shift: TShiftState; WheelDelta: Integer; const MousePos: TPoint): Boolean; override; {$ELSE} function DoMouseWheel(Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint): Boolean; override; {$ENDIF} procedure Loaded; override; procedure SetOnWindowsDrop(Value : TWindowsDropEvent); public constructor Create(AOwner : TComponent); override; destructor Destroy; override; public property zdPictureDirectory : TBitmap read FDirBitMap write SetDirectoryBitMap; property zdPictureFile : TBitmap read FFileBitMap write SetFileBitMap; property zdPictureZipAttribute : TBitmap read FAttrBitMap write SetAttributeBitMap; property zdPictureDirectorySelected : TBitmap read FDirBitMapSelected write SetDirectoryBitMapSelected; property zdPictureFileSelected : TBitmap read FFileBitMapSelected write SetFileBitMapSelected; property zdPictureZipAttributeSelected : TBitmap read FAttrBitMapSelected write SetAttributeBitMapSelected; property BitMapHeight : Integer read FBitMapHeight write SetBitMapHeight; property BitMapWidth : Integer read FBitMapWidth write SetBitMapWidth; property OnWindowsDrop : TWindowsDropEvent read FOnWindowsDrop write SetOnWindowsDrop; end; type {$IFDEF UsingClx} TAbCustomZipOutline = class(TWidgetControl) {$ELSE} TAbCustomZipOutline = class(TWinControl) {$ENDIF} protected {private} FArchive : TAbZipArchive; FItemProgressMeter : IAbProgressMeter; FArchiveProgressMeter : IAbProgressMeter; FAttributes : TAbZipAttributes; FAutoSave : Boolean; FBaseDirectory : string; FCompressionMethodToUse : TAbZipSupportedMethod; FDeflationOption : TAbZipDeflationOption; {$IFDEF MSWINDOWS} FDOSMode : Boolean; {$ENDIF} FFileName : string; FExtractOptions : TAbExtractOptions; FHierarchy : Boolean; FLogFile : string; FLogging : Boolean; FSpanningThreshold : Longint; FOutline : TAbZipDisplayOutline; FPassword : AnsiString; FPasswordRetries : Byte; FStoreOptions : TAbStoreOptions; FTempDirectory : string; FOnProcessItemFailure : TAbArchiveItemFailureEvent; FOnArchiveItemProgress : TAbArchiveItemProgressEvent; FOnArchiveProgress : TAbArchiveProgressEvent; FOnChange : TNotifyEvent; FOnClick : TNotifyEvent; FOnCollapse : TTVExpandedEvent; FOnConfirmOverwrite : TAbConfirmOverwriteEvent; FOnConfirmProcessItem : TAbArchiveItemConfirmEvent; FOnConfirmSave : TAbArchiveConfirmEvent; FOnDblClick : TNotifyEvent; FOnDragDrop : TDragDropEvent; FOnDragOver : TDragOverEvent; FOnEndDrag : TEndDragEvent; FOnEnter : TNotifyEvent; FOnExit : TNotifyEvent; FOnExpand : TTVExpandedEvent; FOnKeyDown : TKeyEvent; FOnKeyPress : TKeyPressEvent; FOnKeyUp : TKeyEvent; FOnLoad : TAbArchiveEvent; FOnMouseDown : TMouseEvent; FOnMouseMove : TMouseMoveEvent; FOnMouseUp : TMouseEvent; FOnNeedPassword : TAbNeedPasswordEvent; FOnRequestImage : TAbRequestImageEvent; FOnRequestLastDisk : TAbRequestDiskEvent; FOnRequestNthDisk : TAbRequestNthDiskEvent; FOnRequestBlankDisk : TAbRequestDiskEvent; FOnSave : TAbArchiveEvent; {$IFDEF MSWINDOWS} FOnStartDrag : TStartDragEvent; {$ENDIF MSWINDOWS} FOnWindowsDrop : TWindowsDropEvent; protected {methods} procedure AddAttributeNodes(Item : TAbZipItem; oNode : TTreeNode); procedure DoProcessItemFailure(Sender : TObject; Item : TAbArchiveItem; ProcessType : TAbProcessType; ErrorClass : TAbErrorClass; ErrorCode : Integer); virtual; procedure DoArchiveItemProgress(Sender : TObject; Item : TAbArchiveItem; Progress : Byte; var Abort : Boolean); virtual; procedure DoArchiveProgress(Sender : TObject; Progress : Byte; var Abort : Boolean); virtual; procedure DoChange; virtual; procedure DoClick(Sender : TObject); virtual; procedure DoCollapse(Sender : TObject; Node: TTreeNode); virtual; procedure DoConfirmProcessItem(Sender : TObject; Item : TAbArchiveItem; ProcessType : TAbProcessType; var Confirm : Boolean); virtual; procedure DoConfirmOverwrite(var Name : string; var Confirm : Boolean); virtual; procedure DoConfirmSave(Sender : TObject; var Confirm : Boolean); virtual; procedure DoDblClick(Sender : TObject); virtual; procedure DoDragDrop(Sender, Source: TObject; X, Y: Integer); virtual; procedure DoDragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); virtual; procedure DoOnEndDrag(Sender, Target: TObject; X, Y: Integer); virtual; procedure DoOnEnter(Sender : TObject); virtual; procedure DoOnExit(Sender : TObject); virtual; procedure DoExpand(Sender: TObject; Node : TTreeNode); virtual; procedure DoKeyDown(Sender : TObject; var Key: Word; Shift: TShiftState); virtual; procedure DoKeyPress(Sender : TObject; var Key: Char); virtual; procedure DoKeyUp(Sender : TObject; var Key: Word; Shift: TShiftState); virtual; procedure DoLoad(Sender : TObject); virtual; procedure DoMouseDown(Sender : TObject; Button: TMouseButton; Shift: TShiftState; X, Y : Integer); virtual; procedure DoMouseMove(Sender : TObject; Shift: TShiftState; X, Y: Integer); virtual; procedure DoMouseUp(Sender : TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); virtual; procedure DoNeedPassword(Sender : TObject; var NewPassword : AnsiString); virtual; procedure DoSave(Sender : TObject); virtual; {$IFDEF MSWINDOWS} procedure DoOnStartDrag(Sender: TObject; var DragObject: TDragObject); virtual; {$ENDIF} procedure DoWindowsDrop(Sender : TObject; FileName : string); virtual; function GetBorderStyle : TBorderStyle; function GetCount : Integer; function GetCursor : TCursor; {$IFNDEF UsingCLX} function GetDragCursor : TCursor; {$ENDIF} function GetDragMode : TDragMode; function GetItem(Index : Integer) : TAbZipItem; function GetPictureDirectory : TBitmap; function GetPictureFile : TBitmap; function GetPictureZipAttribute: TBitmap; function GetPictureDirectorySelected : TBitmap; function GetPictureFileSelected : TBitmap; function GetPictureZipAttributeSelected : TBitmap; function GetPictureHeight : Integer; function GetPictureWidth : Integer; function GetSelectedItem : LongInt; function GetSelectedZipItem : TAbZipItem; function GetStatus : TAbArchiveStatus; function GetVersion : string; function GetZipfileComment : AnsiString; procedure InitArchive; procedure Loaded; override; procedure Notification(Component: TComponent; Operation: TOperation); override; procedure PutItem(Index : Integer; Value : TAbZipItem); procedure SetArchiveProgressMeter(const Value: IAbProgressMeter); procedure SetAttributes(Value : TAbZipAttributes); procedure SetAutoSave(Value : Boolean); procedure SetBaseDirectory(Value : string); procedure SetBorderStyle(Value : TBorderStyle); procedure SetCompressionMethodToUse(Value : TAbZipSupportedMethod); procedure SetDeflationOption(Value : TAbZipDeflationOption); {$IFDEF MSWINDOWS} procedure SetDOSMode(Value : Boolean); {$ENDIF} procedure SetCursor(Value : TCursor); {$IFNDEF UsingCLX} procedure SetDragCursor(Value : TCursor); {$ENDIF} {$IFNDEF UsingCLX} procedure SetDragMode(Value : TDragMode); override; {$ENDIF} procedure SetExtractOptions(Value : TAbExtractOptions); procedure SetFileName(const aFileName : string); virtual; procedure SetHierarchy(Value : Boolean); procedure SetItemProgressMeter(const Value: IAbProgressMeter); procedure SetLogFile(Value : string); procedure SetLogging(Value : Boolean); procedure SetOnRequestImage(Value : TAbRequestImageEvent); procedure SetOnRequestLastDisk(Value : TAbRequestDiskEvent); procedure SetOnRequestNthDisk(Value : TAbRequestNthDiskEvent); procedure SetOnRequestBlankDisk(Value : TAbRequestDiskEvent); procedure SetOnWindowsDrop(Value : TWindowsDropEvent); procedure SetPassword(Value : AnsiString); procedure SetPasswordRetries(Value : Byte); procedure SetPictureDirectory(Value : TBitmap); procedure SetPictureFile(Value : TBitmap); procedure SetPictureZipAttribute(Value : TBitmap); procedure SetPictureDirectorySelected(Value : TBitmap); procedure SetPictureFileSelected(Value : TBitmap); procedure SetPictureZipAttributeSelected(Value : TBitmap); procedure SetPictureHeight(Value : Integer); procedure SetPictureWidth(Value : Integer); procedure SetSelectedItem(Value : LongInt); procedure SetStoreOptions(Value : TAbStoreOptions); procedure SetTempDirectory(Value : string); procedure SetSpanningThreshold(Value : Longint); procedure SetVersion(Value : string); procedure SetZipfileComment(Value : AnsiString); procedure TestItemProc(Sender : TObject; Item : TAbArchiveItem); procedure UnzipProc(Sender : TObject; Item : TAbArchiveItem; const NewName : string); procedure UnzipToStreamProc(Sender : TObject; Item : TAbArchiveItem; OutStream : TStream); procedure UpdateOutline; procedure ZipProc(Sender : TObject; Item : TAbArchiveItem; OutStream : TStream); procedure ZipFromStreamProc(Sender : TObject; Item : TAbArchiveItem; OutStream, InStream : TStream); protected {properties} property ArchiveProgressMeter : IAbProgressMeter read FArchiveProgressMeter write SetArchiveProgressMeter; property Attributes : TAbZipAttributes read FAttributes write SetAttributes default AbDefZipAttributes; property AutoSave : Boolean read FAutoSave write SetAutoSave default AbDefAutoSave; property BaseDirectory : string read FBaseDirectory write SetBaseDirectory; property BorderStyle : TBorderStyle read GetBorderStyle write SetBorderStyle; property CompressionMethodToUse : TAbZipSupportedMethod read FCompressionMethodToUse write SetCompressionMethodToUse default AbDefCompressionMethodToUse; property Cursor : TCursor read GetCursor write SetCursor; property DeflationOption : TAbZipDeflationOption read FDeflationOption write SetDeflationOption default AbDefDeflationOption; {$IFDEF MSWINDOWS} property DOSMode : Boolean read FDOSMode write SetDOSMode; {$ENDIF} {$IFNDEF UsingCLX} property DragCursor : TCursor read GetDragCursor write SetDragCursor; property DragMode : TDragMode read GetDragMode write SetDragMode; {$ENDIF} property ExtractOptions : TAbExtractOptions read FExtractOptions write SetExtractOptions default AbDefExtractOptions; property FileName : string read FFileName write SetFileName; property Hierarchy : Boolean read FHierarchy write SetHierarchy default AbDefHierarchy; property SpanningThreshold : Longint read FSpanningThreshold write SetSpanningThreshold default 0; property ItemProgressMeter : IAbProgressMeter read FItemProgressMeter write SetItemProgressMeter; property LogFile : string read FLogFile write SetLogFile; property Logging : Boolean read FLogging write SetLogging; property OnWindowsDrop : TWindowsDropEvent read FOnWindowsDrop write SetOnWindowsDrop; property Password : AnsiString read FPassword write SetPassword; property PasswordRetries : Byte read FPasswordRetries write SetPasswordRetries default AbDefPasswordRetries; property PictureDirectory : TBitmap read GetPictureDirectory write SetPictureDirectory; property PictureFile : TBitmap read GetPictureFile write SetPictureFile; property PictureZipAttribute : TBitmap read GetPictureZipAttribute write SetPictureZipAttribute; property PictureDirectorySelected : TBitmap read GetPictureDirectorySelected write SetPictureDirectorySelected; property PictureFileSelected : TBitmap read GetPictureFileSelected write SetPictureFileSelected; property PictureZipAttributeSelected : TBitmap read GetPictureZipAttributeSelected write SetPictureZipAttributeSelected; property PictureHeight : Integer read GetPictureHeight write SetPictureHeight; property PictureWidth : Integer read GetPictureWidth write SetPictureWidth; property StoreOptions : TAbStoreOptions read FStoreOptions write SetStoreOptions default AbDefStoreOptions; property Version : string read GetVersion write SetVersion stored False; protected {events} property OnProcessItemFailure : TAbArchiveItemFailureEvent read FOnProcessItemFailure write FOnProcessItemFailure; property OnArchiveItemProgress : TAbArchiveItemProgressEvent read FOnArchiveItemProgress write FOnArchiveItemProgress; property OnArchiveProgress : TAbArchiveProgressEvent read FOnArchiveProgress write FOnArchiveProgress; property OnChange : TNotifyEvent read FOnChange write FOnChange; property OnClick : TNotifyEvent read FOnClick write FOnClick; property OnConfirmProcessItem : TAbArchiveItemConfirmEvent read FOnConfirmProcessItem write FOnConfirmProcessItem; property OnConfirmOverwrite : TAbConfirmOverwriteEvent read FOnConfirmOverwrite write FOnConfirmOverwrite; property OnConfirmSave : TAbArchiveConfirmEvent read FOnConfirmSave write FOnConfirmSave; property OnCollapse : TTVExpandedEvent read FOnCollapse write FOnCollapse; property OnDblClick : TNotifyEvent read FOnDblClick write FOnDblClick; property OnDragDrop : TDragDropEvent read FOnDragDrop write FOnDragDrop; property OnDragOver : TDragOverEvent read FOnDragOver write FOnDragOver; property OnEndDrag : TEndDragEvent read FOnEndDrag write FOnEndDrag; property OnEnter : TNotifyEvent read FOnEnter write FOnEnter; property OnExit : TNotifyEvent read FOnExit write FOnExit; property OnExpand : TTVExpandedEvent read FOnExpand write FOnExpand; property OnKeyDown : TKeyEvent read FOnKeyDown write FOnKeyDown; property OnKeyPress : TKeyPressEvent read FOnKeyPress write FOnKeyPress; property OnKeyUp : TKeyEvent read FOnKeyUp write FOnKeyUp; property OnLoad : TAbArchiveEvent read FOnLoad write FOnLoad; property OnMouseDown : TMouseEvent read FOnMouseDown write FOnMouseDown; property OnMouseMove : TMouseMoveEvent read FOnMouseMove write FOnMouseMove; property OnMouseUp : TMouseEvent read FOnMouseUp write FOnMouseUp; property OnNeedPassword : TAbNeedPasswordEvent read FOnNeedPassword write FOnNeedPassword; property OnRequestImage : TAbRequestImageEvent read FOnRequestImage write SetOnRequestImage; property OnRequestLastDisk : TAbRequestDiskEvent read FOnRequestLastDisk write SetOnRequestLastDisk; property OnRequestNthDisk : TAbRequestNthDiskEvent read FOnRequestNthDisk write SetOnRequestNthDisk; property OnRequestBlankDisk : TAbRequestDiskEvent read FOnRequestBlankDisk write SetOnRequestBlankDisk; property OnSave : TAbArchiveEvent read FOnSave write FOnSave; {$IFDEF MSWINDOWS} property OnStartDrag : TStartDragEvent read FOnStartDrag write FOnStartDrag; {$ENDIF MSWINDOWS} public {methods} constructor Create(AOwner : TComponent); override; destructor Destroy; override; procedure AddFiles(const FileMask : string; SearchAttr : Integer); {Add files to the archive where the disk filespec matches} procedure AddFilesEx(const FileMask, ExclusionMask : string; SearchAttr : Integer); {Add files that match Filemask except those matching ExclusionMask} procedure AddFromStream(const NewName : string; FromStream : TStream); {Create and add a zip item directly from a stream} procedure ClearTags; {Clear all tags from the archive} procedure CloseArchive; {closes the archive by setting FileName to ''} procedure DeleteAt(Index : Integer); {delete item specified by index} procedure DeleteFiles(const FileMask : string); {Delete all files from the archive that match the file mask} procedure DeleteFilesEx(const FileMask, ExclusionMask : string); {Delete files that match Filemask except those matching ExclusionMask} procedure DeleteTaggedItems; {delete all tagged items from the archive} procedure ExtractAt(Index : Integer; const NewName : string); {extract item specified by index} procedure ExtractFiles(const FileMask : string); {extract all files from the archive that match the mask} procedure ExtractFilesEx(const FileMask, ExclusionMask : string); {Extract files that match Filemask except those matching ExclusionMask} procedure ExtractTaggedItems; {extract all tagged items from the archive} procedure ExtractToStream(const aFileName : string; ToStream : TStream); {extract an item directly to a stream} function FindItem(aItem : TAbArchiveItem) : Integer; {extract specified item} function FindFile(const aFileName : string) : Integer; {find the item with the given file name} procedure FreshenFiles(const FileMask : string); {freshen all items that match the file mask} procedure FreshenFilesEx(const FileMask, ExclusionMask : string); {freshen items matching FileMask but not ExclusionMask} procedure FreshenTaggedItems; {freshen all tagged items} procedure FullCollapse; procedure FullExpand; function GetTextItem(const Value: string): LongInt; function GetOutLineItem(X, Y : Integer): LongInt; procedure Move(aItem : TAbArchiveItem; NewStoredPath : string); procedure OpenArchive(const aFileName : String); {opens the archive} procedure Replace(aItem : TAbArchiveItem); procedure Save; {saves the archive} procedure TagItems(const FileMask : string); procedure TestTaggedItems; procedure UnTagItems(const FileMask : string); public {properties} property Count : Integer read GetCount; property Items[Index : Integer] : TAbZipItem read GetItem write PutItem; default; property SelectedItem: LongInt read GetSelectedItem write SetSelectedItem; property SelectedZipItem : TAbZipItem read GetSelectedZipItem; property Status : TAbArchiveStatus read GetStatus; property TempDirectory : string read FTempDirectory write SetTempDirectory; property ZipfileComment : AnsiString read GetZipfileComment write SetZipfileComment; end; type TAbZipOutline = class(TAbCustomZipOutline) published property Align; property ArchiveProgressMeter; property ItemProgressMeter; property Attributes; property AutoSave; property BaseDirectory; property BorderStyle; property Color default AbDefColor; property CompressionMethodToUse; property Count; {$IFNDEF UsingCLX} property Ctl3D; {$ENDIF} property Cursor; property DeflationOption; {$IFDEF MSWINDOWS} property DOSMode; {$ENDIF} {$IFNDEF UsingCLX} property DragCursor; {$ENDIF} property DragMode; property Enabled; property ExtractOptions; property Font; property Hierarchy; property LogFile; property Logging; property OnProcessItemFailure; property OnArchiveItemProgress; property OnArchiveProgress; property OnChange; property OnClick; property OnConfirmProcessItem; property OnConfirmOverwrite; property OnConfirmSave; property OnCollapse; property OnDblClick; property OnDragDrop; property OnDragOver; property OnEndDrag; property OnEnter; property OnExit; property OnExpand; property OnKeyDown; property OnKeyPress; property OnKeyUp; property OnLoad; property OnMouseDown; property OnMouseMove; property OnMouseUp; {$IFNDEF UsingCLX} property OnMouseWheel; property OnMouseWheelDown; property OnMouseWheelUp; {$ENDIF} property OnNeedPassword; property OnRequestImage; property OnRequestLastDisk; property OnRequestNthDisk; property OnRequestBlankDisk; property OnSave; {$IFDEF MSWINDOWS} property OnStartDrag; {$ENDIF MSWINDOWS} property OnWindowsDrop; property ParentColor default AbDefParentColor; {$IFNDEF UsingCLX} property ParentCtl3D; {$ENDIF} property ParentFont; property ParentShowHint; property Password; property PasswordRetries; property PictureDirectory; property PictureDirectorySelected; property PictureFile; property PictureFileSelected; property PictureZipAttribute; property PictureZipAttributeSelected; property PopupMenu; property ShowHint; property StoreOptions; property TabOrder; property TabStop; property SpanningThreshold; property Version; property TempDirectory; property Visible; property FileName; {must be after OnLoad} end; implementation uses {$IFDEF MSWINDOWS} ShellApi, {$ENDIF} SysUtils, AbConst, AbExcept, AbResString, AbUnzPrc, AbZipPrc; {$R AbZipOut.res} type TAbZipArchiveFriend = class(TAbZipArchive) end; { -------------------------------------------------------------------------- } { ========================================================================== } { -------------------------------------------------------------------------- } procedure TAbZipDisplayOutline.IndexBitmaps; begin FImageList.Clear; FImageList.Height := FBitMapHeight; FImageList.Width := FBitMapWidth; if not FAttrBitMap.Empty then FAttrIndex := FImageList.Add( FAttrBitMap, nil ); if not FAttrBitMap.Empty then FAttrSelectedIndex := FImageList.Add( FAttrBitMapSelected, nil ); if not FAttrBitMap.Empty then FDirectoryIndex := FImageList.Add( FDirBitMap, nil ); if not FAttrBitMap.Empty then FDirSelectedIndex := FImageList.Add( FDirBitMapSelected , nil ); if not FAttrBitMap.Empty then FFileIndex := FImageList.Add( FFileBitMap, nil ); if not FAttrBitMap.Empty then FFileSelectedIndex := FImageList.Add( FFileBitMapSelected, nil ); end; { -------------------------------------------------------------------------- } constructor TAbZipDisplayOutline.Create(AOwner : TComponent); begin FBitMapHeight := cBitmapHeight; FBitMapWidth := cBitmapWidth; FDirBitMap := TBitMap.Create; FFileBitMap := TBitMap.Create; FAttrBitMap := TBitMap.Create; FDirBitMapSelected := TBitMap.Create; FFileBitMapSelected := TBitMap.Create; FAttrBitMapSelected := TBitMap.Create; FDirBitMap.LoadFromResourceName( HInstance, 'DIR' ); FFileBitMap.LoadFromResourceName( HInstance, 'FILEFIX' ); FAttrBitMap.LoadFromResourceName( HInstance, 'ATTR' ); FDirBitMapSelected.LoadFromResourceName ( HInstance, 'DIRS' ); FFileBitMapSelected.LoadFromResourceName( HInstance, 'FILES' ); FAttrBitMapSelected.LoadFromResourceName( HInstance, 'ATTRS' ); inherited Create(AOwner); FImageList := TImageList.Create(Self); end; { -------------------------------------------------------------------------- } procedure TAbZipDisplayOutline.Loaded; begin inherited Loaded; {$IFNDEF UsingCLX} if Assigned(FOnWindowsDrop) then DragAcceptFiles(Handle, True); {$ENDIF} end; { -------------------------------------------------------------------------- } destructor TAbZipDisplayOutline.Destroy; begin FImageList.Free; FDirBitMap.Free; FFileBitMap.Free; FAttrBitMap.Free; FDirBitMapSelected.Free; FFileBitMapSelected.Free; FAttrBitMapSelected.Free; inherited Destroy; end; { -------------------------------------------------------------------------- } procedure TAbZipDisplayOutline.SetAttributeBitMap(Value : TBitmap); begin if Value <> nil then begin FAttrBitMap.assign( Value ) end else begin FAttrBitMap.LoadFromResourceName( HInstance, 'ATTR' ); end; end; { -------------------------------------------------------------------------- } procedure TAbZipDisplayOutline.SetDirectoryBitMap(Value : TBitmap); begin if Value <> nil then begin FDirBitMap.assign( Value ) end else begin FDirBitMap.LoadFromResourceName( HInstance, 'DIR' ); end; end; { -------------------------------------------------------------------------- } procedure TAbZipDisplayOutline.SetFileBitMap(Value : TBitmap); begin if Value <> nil then begin FFileBitMap.assign( Value ) end else begin FFileBitMap.LoadFromResourceName( HInstance, 'FILEFIX' ); end; end; { -------------------------------------------------------------------------- } procedure TAbZipDisplayOutline.SetAttributeBitMapSelected(Value : TBitmap); begin if Value <> nil then FAttrBitMapSelected.assign( Value ) else begin FAttrBitMapSelected.LoadFromResourceName( HInstance, 'ATTRS' ); end; end; { -------------------------------------------------------------------------- } procedure TAbZipDisplayOutline.SetDirectoryBitMapSelected(Value : TBitmap); begin if Value <> nil then FDirBitMapSelected.assign( Value ) else begin FDirBitMapSelected.LoadFromResourceName ( HInstance, 'DIRS' ); end; end; { -------------------------------------------------------------------------- } procedure TAbZipDisplayOutline.SetFileBitMapSelected(Value : TBitmap); begin if Value <> nil then FFileBitMapSelected.assign( Value ) else begin FFileBitMapSelected.LoadFromResourceName( HInstance, 'FILES' ); end; end; { -------------------------------------------------------------------------- } procedure TAbZipDisplayOutline.SetBitMapHeight(Value : Integer); begin if FBitMapHeight <> Value then FBitMapHeight := Value; end; { -------------------------------------------------------------------------- } procedure TAbZipDisplayOutline.SetBitMapWidth(Value : Integer); begin if FBitMapWidth <> Value then FBitMapWidth := Value; end; {$IFNDEF UsingCLX} { -------------------------------------------------------------------------- } procedure TAbZipDisplayOutline.WMDropFiles(var Msg : TWMDropFiles); var FileName : string; I : Integer; NumFiles : Integer; begin Msg.Result := 1; NumFiles := DragQueryFile(Msg.Drop, Cardinal(-1), nil, 0); try for I := 0 to pred(NumFiles) do begin SetLength(FileName, DragQueryFile(Msg.Drop, I, nil, 0)); DragQueryFile(Msg.Drop, I, PChar(FileName), Length(FileName) + 1); DoOnWindowsDrop(FileName); end; finally DragFinish(Msg.Drop); end; if IsIconic(Application.Handle) then ShowWindow(Application.Handle, SW_SHOWNORMAL) else BringWindowToTop(Handle); end; {$ENDIF} { -------------------------------------------------------------------------- } procedure TAbZipDisplayOutline.DoOnWindowsDrop(FileName : string); begin if csDesigning in ComponentState then Exit; if csLoading in ComponentState then Exit; if Assigned(FOnWindowsDrop) then FOnWindowsDrop(Self, FileName); end; { -------------------------------------------------------------------------- } {$IFDEF UsingCLX} function TAbZipDisplayOutline.DoMouseWheel(Shift: TShiftState; WheelDelta: Integer; const MousePos: TPoint): Boolean; {$ELSE} function TAbZipDisplayOutline.DoMouseWheel(Shift: TShiftState; WheelDelta: Integer; MousePos: TPoint): Boolean; {$ENDIF} const WHEEL_DELTA = 120; var oHold : TTreeNode; oNode : TTreeNode; begin { We always return true - if there's an event handler that returns } { false, we'll do the work; if it returns true, the work has been } { done, ergo this routine should return true. } Result := True; if not inherited DoMouseWheel(Shift, WheelDelta, MousePos) then begin if Items.Count = 0 then Exit; if Selected = nil then exit; if Selected.HasChildren then Selected.Expand( false ); oNode := nil; oHold := Selected; if WheelDelta < 0 then begin if oHold.HasChildren then oNode := oHold.getFirstChild; if oNode = nil then oNode := oHold.GetNextChild( oHold ); if oNode = nil then oNode := oHold.GetNext; end else begin oNode := oHold.GetPrevChild( oHold ); if oNode <> nil then begin if oNode.HasChildren then oNode := oNode.GetLastChild; end else oNode := oHold.GetPrev; end; if oNode <> nil then Selected := oNode; end; end; { -------------------------------------------------------------------------- } procedure TAbZipDisplayOutline.SetOnWindowsDrop(Value : TWindowsDropEvent); {$IFNDEF UsingCLX} var WasAccepting : Boolean; {$ENDIF} begin {$IFNDEF UsingCLX} WasAccepting := Assigned(FOnWindowsDrop); FOnWindowsDrop := Value; if csLoading in ComponentState then Exit; if csDestroying in ComponentState then Exit; if Assigned(Value) then DragAcceptFiles(Handle, True) else if WasAccepting then DragAcceptFiles(Handle, False); {$ENDIF} end; { -------------------------------------------------------------------------- } { ========================================================================== } { -------------------------------------------------------------------------- } constructor TAbCustomZipOutline.Create(AOwner : TComponent); begin inherited Create(AOwner); Width := 300; Height := 143; Color := AbDefColor; ParentColor := AbDefParentColor; FOutline := TAbZipDisplayOutline.Create(Self); FOutline.Parent := Self; FOutline.Visible := True; FOutline.Align := alClient; FOutline.ParentColor := True; {$IFNDEF UsingCLX} FOutline.ParentCtl3D := True; {$ENDIF} FOutline.ParentFont := True; FOutline.ParentShowHint := True; FOutline.Images := FOutline.FImageList; AutoSave := AbDefAutoSave; Attributes := AbDefZipAttributes; CompressionMethodToUse := AbDefCompressionMethodToUse; DeflationOption := AbDefDeflationOption; ExtractOptions := AbDefExtractOptions; Hierarchy := AbDefHierarchy; PasswordRetries := AbDefPasswordRetries; StoreOptions := AbDefStoreOptions; end; { -------------------------------------------------------------------------- } destructor TAbCustomZipOutline.Destroy; begin FArchive.Free; inherited Destroy; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.AddAttributeNodes( Item : TAbZipItem; oNode : TTreeNode ); var ExtAttrString : string; dt : TDateTime; li : LongInt; s : string; tmpNode : TTreeNode; begin with Item do begin if zaCompressedSize in Attributes then begin tmpNode := FOutline.Items.AddChild(oNode, Format(AbCompressedSizeFormatS, [CompressedSize])); tmpNode.ImageIndex := FOutline.FAttrIndex; tmpNode.SelectedIndex := FOutline.FAttrSelectedIndex; end; if zaUnCompressedSize in Attributes then begin tmpNode := FOutline.Items.AddChild(oNode, Format(AbUncompressedSizeFormatS, [UncompressedSize])); tmpNode.ImageIndex := FOutline.FAttrIndex; tmpNode.SelectedIndex := FOutline.FAttrSelectedIndex; end; if zaCompressionMethod in Attributes then begin tmpNode := FOutline.Items.AddChild(oNode, Format(AbCompressionMethodFormatS, [ZipCompressionMethodToString(CompressionMethod)])); tmpNode.ImageIndex := FOutline.FAttrIndex; tmpNode.SelectedIndex := FOutline.FAttrSelectedIndex; end; if zaCompressionRatio in Attributes then begin tmpNode := FOutline.Items.AddChild(oNode, Format(AbCompressionRatioFormatS, [CompressionRatio])); tmpNode.ImageIndex := FOutline.FAttrIndex; tmpNode.SelectedIndex := FOutline.FAttrSelectedIndex; end; if zaCRC in Attributes then begin tmpNode := FOutline.Items.AddChild(oNode, Format(AbCRCFormatS, [CRC32])); tmpNode.ImageIndex := FOutline.FAttrIndex; tmpNode.SelectedIndex := FOutline.FAttrSelectedIndex; end; if zaExternalFileAttributes in Attributes then begin ExtAttrString := ''; {$IFDEF MSWINDOWS} {$WARN SYMBOL_PLATFORM OFF} if (faReadOnly and ExternalFileAttributes) = faReadOnly then ExtAttrString := ExtAttrString + AbReadOnlyS; if (faHidden and ExternalFileAttributes) = faHidden then ExtAttrString := ExtAttrString + AbHiddenS; if (faSysFile and ExternalFileAttributes) = faSysFile then ExtAttrString := ExtAttrString + AbSystemS; if (faArchive and ExternalFileAttributes) = faArchive then ExtAttrString := ExtAttrString + AbArchivedS; {$WARN SYMBOL_PLATFORM ON} {$ENDIF} tmpNode := FOutline.Items.AddChild(oNode, Format(AbEFAFormatS, [ExtAttrString])); tmpNode.ImageIndex := FOutline.FAttrIndex; tmpNode.SelectedIndex := FOutline.FAttrSelectedIndex; end; if zaInternalFileAttributes in Attributes then if InternalFileAttributes = 1 then begin tmpNode := FOutline.Items.AddChild(oNode, Format(AbIFAFormatS, [AbTextS])); tmpNode.ImageIndex := FOutline.FAttrIndex; tmpNode.SelectedIndex := FOutline.FAttrSelectedIndex; end else begin tmpNode := FOutline.Items.AddChild(oNode, Format(AbIFAFormatS, [AbBinaryS])); tmpNode.ImageIndex := FOutline.FAttrIndex; tmpNode.SelectedIndex := FOutline.FAttrSelectedIndex; end; if zaEncryption in Attributes then if IsEncrypted then begin tmpNode := FOutline.Items.AddChild(oNode, Format(AbEncryptionFormatS, [AbEncryptedS])); tmpNode.ImageIndex := FOutline.FAttrIndex; tmpNode.SelectedIndex := FOutline.FAttrSelectedIndex; end else begin tmpNode := FOutline.Items.AddChild(oNode, Format(AbEncryptionFormatS, [AbNotEncryptedS])); tmpNode.ImageIndex := FOutline.FAttrIndex; tmpNode.SelectedIndex := FOutline.FAttrSelectedIndex; end; if zaTimeStamp in Attributes then begin if (LastModFileDate + LastModFileTime = 0) then s := AbUnknownS else begin li := LongInt(LastModFileDate) shl 16 + LastModFileTime; dt := FileDateToDateTime(li); s := DateTimeToStr(dt); end; tmpNode := FOutline.Items.AddChild(oNode, Format(AbTimeStampFormatS, [s])); tmpNode.ImageIndex := FOutline.FAttrIndex; tmpNode.SelectedIndex := FOutline.FAttrSelectedIndex; end; if zaVersionMade in Attributes then begin tmpNode := FOutline.Items.AddChild(oNode, Format(AbMadeByFormatS, [Lo(VersionMadeBy)/ 10.0])); tmpNode.ImageIndex := FOutline.FAttrIndex; tmpNode.SelectedIndex := FOutline.FAttrSelectedIndex; end; if zaVersionNeeded in Attributes then begin tmpNode := FOutline.Items.AddChild(oNode, Format(AbNeededFormatS, [Lo(VersionNeededToExtract)/ 10.0])); tmpNode.ImageIndex := FOutline.FAttrIndex; tmpNode.SelectedIndex := FOutline.FAttrSelectedIndex; end; if zaComment in Attributes then begin tmpNode := FOutline.Items.AddChild(oNode, Format(AbCommentFormatS, [FileComment])); tmpNode.ImageIndex := FOutline.FAttrIndex; tmpNode.SelectedIndex := FOutline.FAttrSelectedIndex; end; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.AddFiles(const FileMask : string; SearchAttr : Integer); {Add files to the archive where the disk filespec matches} begin if Assigned(FArchive) then FArchive.AddFiles(FileMask, SearchAttr) else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.AddFilesEx(const FileMask, ExclusionMask : string; SearchAttr : Integer); {Add files that match Filemask except those matching ExclusionMask} begin if Assigned(FArchive) then FArchive.AddFilesEx(FileMask, ExclusionMask, SearchAttr) else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.AddFromStream(const NewName : string; FromStream : TStream); {Add zip item directly from TStream descendant} begin if Assigned(FArchive) then begin FromStream.Position := 0; FArchive.AddFromStream(NewName, FromStream); end else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.ClearTags; {Clear all tags from the archive} begin if Assigned(FArchive) then FArchive.ClearTags else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.DeleteAt(Index : Integer); {delete item at Index} begin if Assigned( FArchive ) then FArchive.DeleteAt( Index ) else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.DeleteFiles(const FileMask : string); {delete all files from the archive that match the file mask} begin if Assigned(FArchive) then FArchive.DeleteFiles(FileMask) else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.DeleteFilesEx(const FileMask, ExclusionMask : string); {Delete files that match Filemask except those matching ExclusionMask} begin if Assigned(FArchive) then FArchive.DeleteFilesEx(FileMask, ExclusionMask) else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.DeleteTaggedItems; {delete all tagged items from the archive} begin if Assigned(FArchive) then FArchive.DeleteTaggedItems else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.DoProcessItemFailure(Sender : TObject; Item : TAbArchiveItem; ProcessType : TAbProcessType; ErrorClass : TAbErrorClass; ErrorCode : Integer); begin if Assigned(FOnProcessItemFailure) then FOnProcessItemFailure(Self, Item, ProcessType, ErrorClass, ErrorCode); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.DoArchiveItemProgress(Sender : TObject; Item : TAbArchiveItem; Progress : Byte; var Abort : Boolean); begin Abort := False; if Assigned(FItemProgressMeter) then FItemProgressMeter.DoProgress(Progress); if Assigned(FOnArchiveItemProgress) then FOnArchiveItemProgress(Self, Item, Progress, Abort); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.DoArchiveProgress(Sender : TObject; Progress : Byte; var Abort : Boolean); begin Abort := False; if Assigned(FArchiveProgressMeter) then FArchiveProgressMeter.DoProgress(Progress); if Assigned(FOnArchiveProgress) then FOnArchiveProgress(Self, Progress, Abort); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.DoChange; begin {Archive now points to the new zip file} UpdateOutline; {then, call the FOnChange event...} if Assigned(FOnChange) then FOnChange(Self); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.DoClick(Sender : TObject); begin if Assigned(FOnClick) then FOnClick(Self); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.DoCollapse(Sender: TObject; Node: TTreeNode); begin if Assigned(FOnCollapse) then FOnCollapse(Self, Node); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.DoConfirmProcessItem(Sender : TObject; Item : TAbArchiveItem; ProcessType : TAbProcessType; var Confirm : Boolean); begin Confirm := True; if Assigned(FItemProgressMeter) then FItemProgressMeter.Reset; if Assigned(FOnConfirmProcessItem) then FOnConfirmProcessItem(Self, Item, ProcessType, Confirm); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.DoConfirmOverwrite(var Name : string; var Confirm : Boolean); begin Confirm := True; if Assigned(FOnConfirmOverwrite) then FOnConfirmOverwrite(Name, Confirm); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.DoConfirmSave(Sender : TObject; var Confirm : Boolean); begin Confirm := True; if Assigned(FOnConfirmSave) then FOnConfirmSave(Self, Confirm); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.DoDblClick(Sender : TObject); begin if Assigned(FOnDblClick) then FOnDblClick(Self); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.DoDragDrop(Sender, Source: TObject; X, Y: Integer); begin if Assigned(FOnDragDrop) then FOnDragDrop(Self, Source, X, Y); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.DoDragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean); begin Accept := False; if Assigned(FOnDragOver) then FOnDragOver(Self, Source, X, Y, State, Accept); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.DoOnEndDrag(Sender, Target: TObject; X, Y: Integer); begin if Assigned(FOnEndDrag) then FOnEndDrag(Self, Target, X, Y); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.DoOnEnter(Sender : TObject); begin if Assigned(FOnEnter) then FOnEnter(Self); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.DoOnExit(Sender : TObject); begin if Assigned(FOnExit) then FOnExit(Self); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.DoExpand(Sender: TObject; Node : TTreeNode); begin if Assigned(FOnExpand) then FOnExpand(Self, Node); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.DoKeyDown(Sender : TObject; var Key: Word; Shift: TShiftState); begin if Assigned(FOnKeyDown) then FOnKeyDown(Self, Key, Shift); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.DoKeyPress(Sender : TObject; var Key: Char); begin if Assigned(FOnKeyPress) then FOnKeyPress(Self, Key); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.DoKeyUp(Sender : TObject; var Key: Word; Shift: TShiftState); begin if Assigned(FOnKeyUp) then FOnKeyUp(Self, Key, Shift); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.DoLoad(Sender : TObject); begin if Assigned(FOnLoad) then FOnLoad(Self); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.DoMouseDown(Sender : TObject; Button: TMouseButton; Shift: TShiftState; X, Y : Integer); begin if Assigned(FOnMouseDown) then FOnMouseDown(Self, Button, Shift, X, Y); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.DoMouseMove(Sender : TObject; Shift: TShiftState; X, Y: Integer); begin if Assigned(FOnMouseMove) then FOnMouseMove(Self, Shift, X, Y); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.DoMouseUp(Sender : TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if Assigned(FOnMouseUp) then FOnMouseUp(Self, Button, Shift, X, Y); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.DoNeedPassword(Sender : TObject; var NewPassword : AnsiString); begin if Assigned(FOnNeedPassword) then begin FOnNeedPassword(Sender, NewPassword); Password := NewPassword; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.DoSave(Sender : TObject); begin if Assigned(FOnSave) then FOnSave(Self); end; { -------------------------------------------------------------------------- } {$IFDEF MSWINDOWS} procedure TAbCustomZipOutline.DoOnStartDrag(Sender: TObject; var DragObject: TDragObject); begin if Assigned(FOnStartDrag) then FOnStartDrag(Self, DragObject); end; {$ENDIF} { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.DoWindowsDrop(Sender : TObject; FileName : string); begin if csDesigning in ComponentState then Exit; if csLoading in ComponentState then Exit; if Assigned(FOnWindowsDrop) then FOnWindowsDrop(Self, FileName); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.ExtractAt(Index : Integer; const NewName : string); {extract a file from the archive that match the index} begin if Assigned(FArchive) then FArchive.ExtractAt(Index, NewName) else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.ExtractFiles(const FileMask : string); {extract all files from the archive that match the mask} begin if Assigned(FArchive) then FArchive.ExtractFiles(FileMask) else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.ExtractFilesEx(const FileMask, ExclusionMask : string); {extract files that match FileMask except those matching ExclusionMask} begin if Assigned(FArchive) then FArchive.ExtractFilesEx(FileMask, ExclusionMask) else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.ExtractTaggedItems; {extract all tagged items from the archive} begin if Assigned(FArchive) then FArchive.ExtractTaggedItems else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.ExtractToStream(const aFileName : string; ToStream : TStream); begin if Assigned(FArchive) then FArchive.ExtractToStream(aFileName, ToStream) else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } function TAbCustomZipOutline.FindFile(const aFileName : string) : Integer; begin if Assigned(FArchive) then Result := FArchive.FindFile(aFileName) else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } function TAbCustomZipOutline.FindItem(aItem : TAbArchiveItem) : Integer; begin if Assigned(FArchive) then Result := FArchive.FindItem(aItem) else Result := -1; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.FreshenFiles(const FileMask : string); {freshen all items that match the file mask} begin if Assigned(FArchive) then FArchive.FreshenFiles(FileMask) else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.FreshenFilesEx(const FileMask, ExclusionMask : string); {freshen all items matching FileMask except those matching ExclusionMask} begin if Assigned(FArchive) then FArchive.FreshenFilesEx(FileMask, ExclusionMask) else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.FreshenTaggedItems; {freshen all tagged items} begin if Assigned(FArchive) then FArchive.FreshenTaggedItems else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.FullCollapse; begin FOutline.FullCollapse; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.FullExpand; begin FOutline.FullExpand; end; { -------------------------------------------------------------------------- } function TAbCustomZipOutline.GetBorderStyle : TBorderStyle; begin Result := FOutline.BorderStyle; end; { -------------------------------------------------------------------------- } function TAbCustomZipOutline.GetCount : Integer; begin if Assigned(FArchive) then Result := FArchive.Count else Result := 0; end; { -------------------------------------------------------------------------- } function TAbCustomZipOutline.GetCursor : TCursor; begin Result := FOutline.Cursor; end; { -------------------------------------------------------------------------- } {$IFNDEF UsingCLX} function TAbCustomZipOutline.GetDragCursor : TCursor; begin Result := FOutline.DragCursor; end; {$ENDIF} { -------------------------------------------------------------------------- } function TAbCustomZipOutline.GetDragMode : TDragMode; begin Result := FOutline.DragMode; end; { -------------------------------------------------------------------------- } function TAbCustomZipOutline.GetItem(Index : Integer) : TAbZipItem; begin if Assigned(FArchive) then Result := TAbZipItem(FArchive.ItemList[Index]) else Result := nil; end; { -------------------------------------------------------------------------- } function TAbCustomZipOutline.GetPictureDirectory : TBitmap; begin Result := FOutline.zdPictureDirectory; end; { -------------------------------------------------------------------------- } function TAbCustomZipOutline.GetPictureFile : TBitmap; begin Result := FOutline.zdPictureFile; end; { -------------------------------------------------------------------------- } function TAbCustomZipOutline.GetPictureZipAttribute: TBitmap; begin Result := FOutline.zdPictureZipAttribute; end; { -------------------------------------------------------------------------- } function TAbCustomZipOutline.GetPictureDirectorySelected : TBitmap; begin Result := FOutline.zdPictureDirectorySelected; end; { -------------------------------------------------------------------------- } function TAbCustomZipOutline.GetPictureFileSelected : TBitmap; begin Result := FOutline.zdPictureFileSelected; end; { -------------------------------------------------------------------------- } function TAbCustomZipOutline.GetPictureZipAttributeSelected: TBitmap; begin Result := FOutline.zdPictureZipAttributeSelected; end; { -------------------------------------------------------------------------- } function TAbCustomZipOutline.GetPictureHeight: Integer; begin Result := FOutline.FBitMapHeight; end; { -------------------------------------------------------------------------- } function TAbCustomZipOutline.GetPictureWidth: Integer; begin Result := FOutline.FBitMapWidth; end; { -------------------------------------------------------------------------- } function TAbCustomZipOutline.GetSelectedItem : LongInt; begin Result := FOutline.Selected.AbsoluteIndex; end; { -------------------------------------------------------------------------- } function TAbCustomZipOutline.GetSelectedZipItem : TAbZipItem; begin {returns nil if the currently selected item of the outline is a folder or a zip attribute} if FOutline.Items.Count > 0 then Result := FOutline.Selected.Data else Result := nil; end; { -------------------------------------------------------------------------- } function TAbCustomZipOutline.GetStatus : TAbArchiveStatus; begin if Assigned(FArchive) then Result := FArchive.Status else Result := asInvalid; end; { -------------------------------------------------------------------------- } function TAbCustomZipOutline.GetTextItem(const Value: string): LongInt; var oNode : TTreeNode; oHold : TTreeNode; begin Result := -1; if FOutline.Items.Count <= 0 then exit; oNode := FOutline.Items[0]; while oNode <> nil do begin if oNode.Text = Value then break; oHold := oNode; oNode := nil; if oHold.HasChildren then oNode := oHold.getFirstChild; if oNode = nil then oNode := oHold.GetNextChild( oHold ); if oNode = nil then oNode := oHold.GetNext; end; if oNode <> nil then Result := oNode.AbsoluteIndex end; { -------------------------------------------------------------------------- } function TAbCustomZipOutline.GetOutLineItem(X, Y : Integer): LongInt; var oNode : TTreeNode; begin oNode := FOutLine.GetNodeAt(X, X); if oNode <> nil then Result := oNode.AbsoluteIndex else Result := -1; end; { -------------------------------------------------------------------------- } function TAbCustomZipOutline.GetVersion : string; begin Result := AbVersionS; end; { -------------------------------------------------------------------------- } function TAbCustomZipOutline.GetZipfileComment : AnsiString; begin if Assigned(FArchive) then Result := TAbZipArchive(FArchive).ZipfileComment else Result := ''; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.InitArchive; begin if Assigned(FArchive) then begin {properties} FArchive.AutoSave := FAutoSave; FArchive.CompressionMethodToUse := FCompressionMethodToUse; SetBaseDirectory(FBaseDirectory); FArchive.DeflationOption := FDeflationOption; {$IFDEF MSWINDOWS} FArchive.DOSMode := FDOSMode; {$ENDIF} FArchive.ExtractOptions := FExtractOptions; FArchive.LogFile := FLogFile; FArchive.Logging := FLogging; FArchive.Password := FPassword; FArchive.PasswordRetries := FPasswordRetries; FArchive.StoreOptions := FStoreOptions; FArchive.TempDirectory := FTempDirectory; FArchive.SpanningThreshold := FSpanningThreshold; {events} TAbZipArchiveFriend(FArchive).ExtractHelper := UnzipProc; TAbZipArchiveFriend(FArchive).ExtractToStreamHelper := UnzipToStreamProc; TAbZipArchiveFriend(FArchive).InsertHelper := ZipProc; TAbZipArchiveFriend(FArchive).InsertFromStreamHelper := ZipFromStreamProc; FArchive.OnProcessItemFailure := DoProcessItemFailure; FArchive.OnArchiveItemProgress := DoArchiveItemProgress; FArchive.OnArchiveProgress := DoArchiveProgress; FArchive.OnConfirmProcessItem := DoConfirmProcessItem; FArchive.OnConfirmOverwrite := DoConfirmOverwrite; FArchive.OnConfirmSave := DoConfirmSave; FArchive.OnLoad := DoLoad; FArchive.OnSave := DoSave; FArchive.OnRequestImage := FOnRequestImage; FArchive.OnNeedPassword := DoNeedPassword; FArchive.OnRequestBlankDisk := FOnRequestBlankDisk; FArchive.OnRequestLastDisk := FOnRequestLastDisk; FArchive.OnRequestNthDisk := FOnRequestNthDisk; TAbZipArchiveFriend(FArchive).TestHelper := TestItemProc; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.Loaded; begin inherited Loaded; FOutline.OnClick := DoClick; FOutline.OnCollapsed := DoCollapse; FOutline.OnDblClick := DoDblClick; FOutline.OnDragDrop := DoDragDrop; FOutline.OnDragOver := DoDragOver; FOutline.OnEndDrag := DoOnEndDrag; FOutline.OnEnter := DoOnEnter; FOutline.OnExit := DoOnExit; FOutline.OnExpanded := DoExpand; FOutline.OnKeyDown := DoKeyDown; FOutline.OnKeyPress := DoKeyPress; FOutline.OnKeyUp := DoKeyUp; FOutline.OnMouseDown := DoMouseDown; FOutline.OnMouseMove := DoMouseMove; FOutline.OnMouseUp := DoMouseUp; {$IFDEF MSWINDOWS} FOutline.OnStartDrag := DoOnStartDrag; {$ENDIF MSWINDOWS} if Assigned(FOnWindowsDrop) then FOutline.OnWindowsDrop := DoWindowsDrop else FOutline.OnWindowsDrop := nil; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.Move(aItem : TAbArchiveItem; NewStoredPath : string); begin if Assigned(FArchive) then FArchive.Move(aItem, NewStoredPath) else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.Notification(Component: TComponent; Operation: TOperation); begin inherited Notification(Component, Operation); if (Operation = opRemove) then begin if Assigned(ItemProgressMeter) and Component.IsImplementorOf(ItemProgressMeter) then ItemProgressMeter := nil; if Assigned(ArchiveProgressMeter) and Component.IsImplementorOf(ArchiveProgressMeter) then ArchiveProgressMeter := nil; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.PutItem(Index : Integer; Value : TAbZipItem); begin if Assigned(FArchive) then FArchive.ItemList[Index] := Value else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.Replace(aItem : TAbArchiveItem); {replace the item} begin if Assigned( FArchive ) then FArchive.Replace( aItem ) else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.Save; begin if Assigned(FArchive) then begin FArchive.Save; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.SetArchiveProgressMeter(const Value: IAbProgressMeter); begin ReferenceInterface(FArchiveProgressMeter, opRemove); FArchiveProgressMeter := Value; ReferenceInterface(FArchiveProgressMeter, opInsert); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.SetAttributes(Value : TAbZipAttributes); begin FAttributes := Value; UpdateOutline; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.SetAutoSave(Value : Boolean); begin FAutoSave := Value; if Assigned(FArchive) then FArchive.AutoSave := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.SetBaseDirectory(Value : string); begin if Assigned(FArchive) then begin FArchive.BaseDirectory := Value; FBaseDirectory := FArchive.BaseDirectory; end else FBaseDirectory := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.SetBorderStyle(Value : TBorderStyle); begin FOutline.BorderStyle := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.SetCompressionMethodToUse( Value : TAbZipSupportedMethod); begin FCompressionMethodToUse := Value; if Assigned(FArchive) then FArchive.CompressionMethodToUse := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.SetCursor(Value : TCursor); begin FOutline.Cursor := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.SetDeflationOption(Value : TAbZipDeflationOption); begin FDeflationOption := Value; if Assigned(FArchive) then FArchive.DeflationOption := Value; end; { -------------------------------------------------------------------------- } {$IFDEF MSWINDOWS} procedure TAbCustomZipOutline.SetDOSMode(Value : Boolean); begin FDOSMode := Value; if Assigned(FArchive) then FArchive.DOSMode := Value; end; {$ENDIF} { -------------------------------------------------------------------------- } {$IFNDEF UsingCLX} procedure TAbCustomZipOutline.SetDragCursor(Value : TCursor); begin FOutline.DragCursor := Value; end; {$ENDIF} { -------------------------------------------------------------------------- } {$IFNDEF UsingCLX} procedure TAbCustomZipOutline.SetDragMode(Value : TDragMode); begin {$IFDEF MSWINDOWS} inherited SetDragMode(Value); {$ENDIF} FOutline.DragMode := Value; end; {$ENDIF} { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.SetExtractOptions(Value : TAbExtractOptions); begin FExtractOptions := Value; if Assigned(FArchive) then FArchive.ExtractOptions := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.SetFileName(const aFileName : string); begin if Assigned(FArchive) and (Status = asBusy) then raise EAbArchiveBusy.Create; FFileName := aFileName; try if Assigned(FArchive) then FArchive.Save; except end; FArchive.Free; FArchive := nil; if FileName <> '' then if FileExists(FileName) then begin if csDesigning in ComponentState then FArchive := TAbZipArchive.Create(FileName, fmOpenRead or fmShareDenyNone) else begin try FArchive := TAbZipArchive.Create(FileName, fmOpenReadWrite or fmShareDenyWrite); except {deals with read-only files} FArchive := TAbZipArchive.Create(FileName, fmOpenRead or fmShareDenyWrite); end; InitArchive; end; FArchive.Load; end else begin FArchive := TAbZipArchive.Create(FileName, fmCreate or fmShareDenyNone); InitArchive; try FArchive.Load; except end; end; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.SetHierarchy(Value : Boolean); begin FHierarchy := Value; UpdateOutline; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.SetItemProgressMeter(const Value: IAbProgressMeter); begin ReferenceInterface(FItemProgressMeter, opRemove); FItemProgressMeter := Value; ReferenceInterface(FItemProgressMeter, opInsert); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.SetLogFile(Value : string); begin FLogFile := Value; if (csDesigning in ComponentState) then Exit; if Assigned(FArchive) then FArchive.LogFile := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.SetLogging(Value : Boolean); begin FLogging := Value; if (csDesigning in ComponentState) then Exit; if Assigned(FArchive) then FArchive.Logging:= Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.SetOnRequestImage(Value : TAbRequestImageEvent); begin FOnRequestImage := Value; if Assigned(FArchive) then FArchive.OnRequestImage := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.SetOnRequestLastDisk(Value : TAbRequestDiskEvent); begin FOnRequestLastDisk := Value; if Assigned(FArchive) then FArchive.OnRequestLastDisk := FOnRequestLastDisk; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.SetOnRequestNthDisk(Value : TAbRequestNthDiskEvent); begin FOnRequestNthDisk := Value; if Assigned(FArchive) then FArchive.OnRequestNthDisk := FOnRequestNthDisk; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.SetOnRequestBlankDisk(Value : TAbRequestDiskEvent); begin FOnRequestBlankDisk := Value; if Assigned(FArchive) then FArchive.OnRequestBlankDisk := FOnRequestBlankDisk; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.SetOnWindowsDrop(Value : TWindowsDropEvent); begin FOnWindowsDrop := Value; if csLoading in ComponentState then Exit; if csDestroying in ComponentState then Exit; if Assigned(Value) then FOutline.OnWindowsDrop := DoWindowsDrop else FOutline.OnWindowsDrop := nil; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.SetPassword(Value : AnsiString); begin FPassword := Value; if Assigned(FArchive) then FArchive.Password := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.SetPasswordRetries(Value : Byte); begin FPasswordRetries := Value; if Assigned(FArchive) then FArchive.PasswordRetries := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.SetPictureDirectory(Value : TBitmap); begin if Value <> nil then begin if (Value.Height = FOutline.FBitMapHeight) and (Value.Width = FOutline.FBitMapWidth) then FOutline.zdPictureDirectory := Value; end else FOutline.zdPictureDirectory := nil; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.SetPictureFile(Value : TBitmap); begin if Value <> nil then begin if (Value.Height = FOutline.FBitMapHeight) and (Value.Width = FOutline.FBitMapWidth) then FOutline.zdPictureFile := Value; end else FOutline.zdPictureFile := nil; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.SetPictureZipAttribute(Value : TBitmap); begin if Value <> nil then begin if (Value.Height = FOutline.FBitMapHeight) and (Value.Width = FOutline.FBitMapWidth) then FOutline.zdPictureZipAttribute := Value; end else FOutline.zdPictureZipAttribute := nil; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.SetPictureDirectorySelected(Value : TBitmap); begin if Value <> nil then begin if (Value.Height = FOutline.FBitMapHeight) and (Value.Width = FOutline.FBitMapWidth) then FOutline.zdPictureDirectorySelected := Value; end else FOutline.zdPictureDirectorySelected := nil; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.SetPictureFileSelected(Value : TBitmap); begin if Value <> nil then begin if (Value.Height = FOutline.FBitMapHeight) and (Value.Width = FOutline.FBitMapWidth) then FOutline.zdPictureFileSelected := Value; end else FOutline.zdPictureFileSelected := nil; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.SetPictureZipAttributeSelected(Value : TBitmap); begin if Value <> nil then begin if (Value.Height = FOutline.FBitMapHeight) and (Value.Width = FOutline.FBitMapWidth) then FOutline.zdPictureZipAttributeSelected := Value; end else FOutline.zdPictureZipAttributeSelected := nil; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.SetPictureHeight(Value : Integer); begin FOutline.FBitMapHeight := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.SetPictureWidth(Value : Integer); begin FOutline.FBitMapWidth := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.SetSelectedItem(Value : LongInt); begin if ( Value >= 0 ) and ( Value <= pred( FOutline.Items.Count )) then FOutline.Selected := FOutline.Items[ Value ]; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.SetStoreOptions(Value : TAbStoreOptions); begin FStoreOptions := Value; if Assigned(FArchive) then FArchive.StoreOptions := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.SetTempDirectory(Value : string); begin FTempDirectory := Value; if Assigned(FArchive) then FArchive.TempDirectory := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.SetSpanningThreshold(Value : Longint); begin FSpanningThreshold := Value; if Assigned(FArchive) then FArchive.SpanningThreshold := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.SetVersion(Value : string); begin {NOP} end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.SetZipfileComment(Value : AnsiString); begin if Assigned(FArchive) then TAbZipArchive(FArchive).ZipfileComment := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.TagItems(const FileMask : string); {tag all items that match the mask} begin if Assigned(FArchive) then FArchive.TagItems(FileMask) else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.UnTagItems(const FileMask : string); {clear tags for all items that match the mask} begin if Assigned(FArchive) then FArchive.UnTagItems(FileMask) else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.UnzipProc(Sender : TObject; Item : TAbArchiveItem; const NewName : string); begin AbUnzip( TAbZipArchive(Sender), TAbZipItem(Item), NewName); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.UnzipToStreamProc(Sender : TObject; Item : TAbArchiveItem; OutStream : TStream); begin if Assigned(OutStream) then AbUnzipToStream(TAbZipArchive(Sender), TAbZipItem(Item), OutStream); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.UpdateOutline; var Found : Boolean; i : Integer; CurRoot : TTreeNode; CurParent : TTreeNode; CurChild : TTreeNode; RootNode : TTreeNode; oNode : TTreeNode; SubDir : string; ItemString : string; function GetSubDir(var ItemString : string) : string; var i : Integer; begin i := Pos(AbPathDelim, ItemString); Result := ''; if i > 0 then begin Result := Copy(ItemString, 1, pred(i)); System.Delete(ItemString, 1, i); end; end; begin RootNode := nil; CurRoot := nil; FOutline.Items.Clear; if not Assigned(FArchive) then Exit; if FArchive.Count = 0 then Exit; FOutline.IndexBitmaps; if Hierarchy then begin for i := 0 to pred(FArchive.Count) do begin {do not display deleted items...} if FArchive.ItemList[i].Action = aaDelete then continue; ItemString := FArchive.ItemList[i].FileName; AbUnfixName(ItemString); if ItemString[ Length( ItemString )] = AbPathDelim then Continue; if ( FOutline.Items.Count <> 0 ) and ( CurRoot <> nil ) then begin SubDir := GetSubDir(ItemString); if RootNode = nil then RootNode := FOutline.TopItem; CurParent := RootNode; while CurParent <> nil do begin if CurParent.Text = SubDir then begin CurRoot := CurParent; break; end else begin CurParent := CurParent.getNextSibling; end; end; if CurParent = nil then begin ItemString := FArchive.ItemList[i].FileName; AbUnfixName(ItemString); end; end else CurParent := nil; SubDir := GetSubDir(ItemString); while SubDir <> '' do begin if CurParent <> nil then begin Found := False; CurChild := CurParent.GetFirstChild; while CurChild <> nil do begin if CurChild.Text <> SubDir then CurChild := CurParent.GetNextChild( CurChild ) else begin Found := True; break; end; end; if Found then CurParent := CurChild else begin if ItemString <> '' then begin CurParent := FOutline.Items.AddChild( CurParent, SubDir ); CurParent.ImageIndex := FOutline.FDirectoryIndex; CurParent.SelectedIndex := FOutline.FDirSelectedIndex; end; end; end else begin if ItemString <> '' then begin CurRoot := FOutline.Items.Add( nil, SubDir ); if FOutline.Items.Count = 1 then RootNode := CurRoot; CurRoot.ImageIndex := FOutline.FDirectoryIndex; CurRoot.SelectedIndex := FOutline.FDirSelectedIndex; CurParent := CurRoot end; end; SubDir := GetSubDir(ItemString); end; if ItemString <> '' then begin oNode := FOutline.Items.AddChildObject(CurParent, ItemString, FArchive.ItemList[i]); if FOutline.Items.Count = 1 then RootNode := oNode; oNode.ImageIndex := FOutline.FFileIndex; oNode.SelectedIndex := FOutline.FFileSelectedIndex; AddAttributeNodes(TAbZipItem(FArchive.ItemList[i]), oNode); end; end; end else begin for i := 0 to pred(FArchive.Count) do begin ItemString := FArchive.ItemList[i].FileName; AbUnfixName(ItemString); oNode := FOutline.Items.AddObject(FOutline.Selected, ItemString, FArchive.ItemList[i]); oNode.ImageIndex := FOutline.FFileIndex; oNode.SelectedIndex := FOutline.FFileSelectedIndex; AddAttributeNodes(TAbZipItem(FArchive.ItemList[i]), oNode); end; end; FullExpand; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.TestItemProc(Sender : TObject; Item : TAbArchiveItem); begin AbTestZipItem(TAbZipArchive(Sender), TAbZipItem(Item)); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.TestTaggedItems; {Test specified items} begin if Assigned(FArchive) then FArchive.TestTaggedItems else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.ZipProc(Sender : TObject; Item : TAbArchiveItem; OutStream : TStream); begin AbZip(TAbZipArchive(Sender), TAbZipItem(Item), OutStream); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.ZipFromStreamProc(Sender : TObject; Item : TAbArchiveItem; OutStream, InStream : TStream); begin if Assigned(InStream) then AbZipFromStream(TAbZipArchive(Sender), TAbZipItem(Item), OutStream, InStream) else raise EAbZipNoInsertion.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.CloseArchive; {closes the archive by setting FileName to ''} begin if FFileName <> '' then FileName := ''; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipOutline.OpenArchive(const aFileName : String); {opens the archive} begin FileName := AFileName; end; { -------------------------------------------------------------------------- } end. ================================================ FILE: lib/abbrevia/source/AbZipPrc.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbZipPrc.pas *} {*********************************************************} {* ABBREVIA: TABZipHelper class *} {*********************************************************} unit AbZipPrc; {$I AbDefine.inc} interface uses Classes, AbZipTyp; procedure AbZip( Sender : TAbZipArchive; Item : TAbZipItem; OutStream : TStream ); procedure AbZipFromStream(Sender : TAbZipArchive; Item : TAbZipItem; OutStream, InStream : TStream); procedure DeflateStream( UncompressedStream, CompressedStream : TStream ); {-Deflates everything in UncompressedStream to CompressedStream no encryption is tried, no check on CRC is done, uses the whole compressedstream - no Progress events - no Frills! } implementation uses {$IFDEF MSWINDOWS} Windows, {$ENDIF} {$IFDEF LibcAPI} Libc, {$ENDIF} SysUtils, AbArcTyp, AbExcept, AbUtils, AbDfCryS, AbVMStrm, AbDfBase, AbDfEnc, AbSpanSt; { ========================================================================== } procedure DoDeflate(Archive : TAbZipArchive; Item : TAbZipItem; OutStream, InStream : TStream); const DEFLATE_NORMAL_MASK = $00; DEFLATE_MAXIMUM_MASK = $02; DEFLATE_FAST_MASK = $04; DEFLATE_SUPERFAST_MASK = $06; var Hlpr : TAbDeflateHelper; begin Item.CompressionMethod := cmDeflated; Hlpr := TAbDeflateHelper.Create; {anything dealing with store options, etc. should already be done.} try {Hlpr} Hlpr.StreamSize := InStream.Size; { set deflation level desired } Hlpr.PKZipOption := '0'; case Archive.DeflationOption of doNormal : begin Hlpr.PKZipOption := 'n'; Item.GeneralPurposeBitFlag := Item.GeneralPurposeBitFlag or DEFLATE_NORMAL_MASK; end; doMaximum : begin Hlpr.PKZipOption := 'x'; Item.GeneralPurposeBitFlag := Item.GeneralPurposeBitFlag or DEFLATE_MAXIMUM_MASK; end; doFast : begin Hlpr.PKZipOption := 'f'; Item.GeneralPurposeBitFlag := Item.GeneralPurposeBitFlag or DEFLATE_FAST_MASK; end; doSuperFast : begin Hlpr.PKZipOption := 's'; Item.GeneralPurposeBitFlag := Item.GeneralPurposeBitFlag or DEFLATE_SUPERFAST_MASK; end; end; { attach progress notification method } Hlpr.OnProgressStep := Archive.DoInflateProgress; { provide encryption check value } Item.CRC32 := Deflate(InStream, OutStream, Hlpr); finally {Hlpr} Hlpr.Free; end; {Hlpr} end; { ========================================================================== } procedure DoStore(Archive : TAbZipArchive; Item : TAbZipItem; OutStream, InStream : TStream); var CRC32 : LongInt; Percent : LongInt; LastPercent : LongInt; InSize : Int64; DataRead : Int64; Total : Int64; Abort : Boolean; Buffer : array [0..8191] of byte; begin { setup } Item.CompressionMethod := cmStored; Abort := False; CRC32 := -1; Total := 0; Percent := 0; LastPercent := 0; InSize := InStream.Size; { get first bufferful } DataRead := InStream.Read(Buffer, SizeOf(Buffer)); { while more data has been read and we're not told to bail } while (DataRead <> 0) and not Abort do begin {report the progress} if Assigned(Archive.OnProgress) then begin Total := Total + DataRead; Percent := Round((100.0 * Total) / InSize); if (LastPercent <> Percent) then Archive.OnProgress(Percent, Abort); LastPercent := Percent; end; { update CRC} AbUpdateCRCBuffer(CRC32, Buffer, DataRead); { write data (encrypting if needed) } OutStream.WriteBuffer(Buffer, DataRead); { get next bufferful } DataRead := InStream.Read(Buffer, SizeOf(Buffer)); end; { finish CRC calculation } Item.CRC32 := not CRC32; { show final progress increment } if (Percent < 100) and Assigned(Archive.OnProgress) then Archive.OnProgress(100, Abort); { User wants to bail } if Abort then begin raise EAbUserAbort.Create; end; end; { ========================================================================== } procedure DoZipFromStream(Sender : TAbZipArchive; Item : TAbZipItem; OutStream, InStream : TStream); var ZipArchive : TAbZipArchive; InStartPos : LongInt; TempOut : TAbVirtualMemoryStream; DestStrm : TStream; begin ZipArchive := TAbZipArchive(Sender); { configure Item } Item.UncompressedSize := InStream.Size; Item.GeneralPurposeBitFlag := Item.GeneralPurposeBitFlag and AbLanguageEncodingFlag; if ZipArchive.Password <> '' then { encrypt the stream } DestStrm := TAbDfEncryptStream.Create(OutStream, LongInt(Item.LastModFileTime shl $10), ZipArchive.Password) else DestStrm := OutStream; try if InStream.Size > 0 then begin { determine how to store Item based on specified CompressionMethodToUse } case ZipArchive.CompressionMethodToUse of smDeflated : begin { Item is to be deflated regarless } { deflate item } DoDeflate(ZipArchive, Item, DestStrm, InStream); end; smStored : begin { Item is to be stored regardless } { store item } DoStore(ZipArchive, Item, DestStrm, InStream); end; smBestMethod : begin { Item is to be archived using method producing best compression } TempOut := TAbVirtualMemoryStream.Create; try TempOut.SwapFileDirectory := Sender.TempDirectory; { save starting points } InStartPos := InStream.Position; { try deflating item } DoDeflate(ZipArchive, Item, TempOut, InStream); { if deflated size > input size then got negative compression } { so storing the item is more efficient } if TempOut.Size > InStream.Size then begin { store item instead } { reset streams to original positions } InStream.Position := InStartPos; TempOut.Free; TempOut := TAbVirtualMemoryStream.Create; TempOut.SwapFileDirectory := Sender.TempDirectory; { store item } DoStore(ZipArchive, Item, TempOut, InStream); end {if}; TempOut.Seek(0, soBeginning); DestStrm.CopyFrom(TempOut, TempOut.Size); finally TempOut.Free; end; end; end; { case } end else begin { InStream is zero length} Item.CRC32 := 0; { ignore any storage indicator and treat as stored } DoStore(ZipArchive, Item, DestStrm, InStream); end; finally if DestStrm <> OutStream then DestStrm.Free; end; { update item } Item.CompressedSize := OutStream.Size; Item.InternalFileAttributes := 0; { don't care } if (ZipArchive.Password <> '') then Item.GeneralPurposeBitFlag := Item.GeneralPurposeBitFlag or AbFileIsEncryptedFlag or AbHasDataDescriptorFlag; end; { -------------------------------------------------------------------------- } procedure AbZipFromStream(Sender : TAbZipArchive; Item : TAbZipItem; OutStream, InStream : TStream); var FileTimeStamp : LongInt; begin // Set item properties for non-file streams Item.ExternalFileAttributes := 0; FileTimeStamp := DateTimeToFileDate(SysUtils.Now); Item.LastModFileTime := LongRec(FileTimeStamp).Lo; Item.LastModFileDate := LongRec(FileTimeStamp).Hi; DoZipFromStream(Sender, Item, OutStream, InStream); end; { -------------------------------------------------------------------------- } procedure AbZip( Sender : TAbZipArchive; Item : TAbZipItem; OutStream : TStream ); var UncompressedStream : TStream; SaveDir : string; AttrEx : TAbAttrExRec; begin UncompressedStream := nil; GetDir(0, SaveDir); try {SaveDir} if (Sender.BaseDirectory <> '') then ChDir(Sender.BaseDirectory); if not AbFileGetAttrEx(Item.DiskFileName, AttrEx) then raise EAbFileNotFound.Create; if ((AttrEx.Attr and faDirectory) <> 0) then UncompressedStream := TMemoryStream.Create else UncompressedStream := TFileStream.Create(Item.DiskFileName, fmOpenRead or fmShareDenyWrite); finally {SaveDir} ChDir( SaveDir ); end; {SaveDir} try {UncompressedStream} {$IFDEF UNIX} Item.ExternalFileAttributes := LongWord(AttrEx.Mode) shl 16 + LongWord(AttrEx.Attr); {$ELSE} Item.ExternalFileAttributes := AttrEx.Attr; {$ENDIF} Item.LastModTimeAsDateTime := AttrEx.Time; DoZipFromStream(Sender, Item, OutStream, UncompressedStream); finally {UncompressedStream} UncompressedStream.Free; end; {UncompressedStream} end; { -------------------------------------------------------------------------- } procedure DeflateStream( UncompressedStream, CompressedStream : TStream ); {-Deflates everything in CompressedStream to UncompressedStream no encryption is tried, no check on CRC is done, uses the whole Uncompressedstream - no Progress events - no Frills! } begin Deflate(UncompressedStream, CompressedStream, nil); end; { -------------------------------------------------------------------------- } end. ================================================ FILE: lib/abbrevia/source/AbZipTyp.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Craig Peterson * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbZipTyp.pas *} {*********************************************************} {* ABBREVIA: PKZip types *} {* Based on information from Appnote.txt, shipped with *} {* PKWare's PKZip for Windows 2.5 *} {*********************************************************} unit AbZipTyp; {$I AbDefine.inc} interface uses Classes, AbArcTyp, AbUtils, AbSpanSt; const { note #$50 = 'P', #$4B = 'K'} Ab_ZipVersion = 63; Ab_ZipLocalFileHeaderSignature : Longint = $04034B50; Ab_ZipDataDescriptorSignature : Longint = $08074B50; Ab_ZipCentralDirectoryFileHeaderSignature : Longint = $02014B50; Ab_Zip64EndCentralDirectorySignature : Longint = $06064B50; Ab_Zip64EndCentralDirectoryLocatorSignature:Longint = $07064B50; Ab_ZipEndCentralDirectorySignature : Longint = $06054B50; Ab_ZipSpannedSetSignature : Longint = $08074B50; Ab_ZipPossiblySpannedSignature : Longint = $30304B50; Ab_GeneralZipSignature : Word = $4B50; Ab_ArchiveExtraDataRecord : Longint = $08064B50; Ab_DigitalSignature : Longint = $05054B50; Ab_WindowsExeSignature : Word = $5A4D; Ab_LinuxExeSignature : Longint = $464C457F; AbDefZipSpanningThreshold = 0; AbDefPasswordRetries = 3; AbFileIsEncryptedFlag = $0001; AbHasDataDescriptorFlag = $0008; AbLanguageEncodingFlag = $0800; Ab_Zip64SubfieldID : Word = $0001; Ab_InfoZipUnicodePathSubfieldID : Word = $7075; Ab_XceedUnicodePathSubfieldID : Word = $554E; Ab_XceedUnicodePathSignature : LongWord= $5843554E; type PAbByteArray4K = ^TAbByteArray4K; TAbByteArray4K = array[1..4096] of Byte; PAbByteArray8K = ^TAbByteArray8K; TAbByteArray8K = array[0..8192] of Byte; PAbIntArray8K = ^TAbIntArray8K; TAbIntArray8K = array[0..8192] of SmallInt; PAbWordArray = ^TAbWordArray; TAbWordArray = array[0..65535 div SizeOf(Word)-1] of Word; PAbByteArray = ^TAbByteArray; TAbByteArray = array[0..65535-1] of Byte; PAbSmallIntArray = ^TAbSmallIntArray; TAbSmallIntArray = array[0..65535 div SizeOf(SmallInt)-1] of SmallInt; PAbIntegerArray = ^TAbIntegerArray; TAbIntegerArray = array[0..65535 div sizeof(integer)-1] of integer; TAbZip64EndOfCentralDirectoryRecord = packed record Signature : Longint; RecordSize : Int64; VersionMadeBy : Word; VersionNeededToExtract : Word; DiskNumber : LongWord; StartDiskNumber : LongWord; EntriesOnDisk : Int64; TotalEntries : Int64; DirectorySize : Int64; DirectoryOffset : Int64; end; TAbZip64EndOfCentralDirectoryLocator = packed record Signature : Longint; StartDiskNumber : Longint; RelativeOffset : Int64; TotalDisks : Longint; end; TAbZipEndOfCentralDirectoryRecord = packed record Signature : Longint; DiskNumber : Word; StartDiskNumber : Word; EntriesOnDisk : Word; TotalEntries : Word; DirectorySize : LongWord; DirectoryOffset : LongWord; CommentLength : Word; end; TAbFollower = {used to expand reduced files} packed record Size : Byte; {size of follower set} FSet : array[0..31] of Byte; {follower set} end; PAbFollowerSets = ^TAbFollowerSets; TAbFollowerSets = array[0..255] of TAbFollower; PAbSfEntry = ^TAbSfEntry; TAbSfEntry = {entry in a Shannon-Fano tree} packed record case Byte of 0 : (Code : Word; Value, BitLength : Byte); 1 : (L : Longint); end; PAbSfTree = ^TAbSfTree; TAbSfTree = packed record {a Shannon-Fano tree} Entries : SmallInt; MaxLength : SmallInt; Entry : array[0..256] of TAbSfEntry; end; PInfoZipUnicodePathRec = ^TInfoZipUnicodePathRec; TInfoZipUnicodePathRec = packed record Version: Byte; NameCRC32: LongInt; UnicodeName: array[0..0] of AnsiChar; end; PXceedUnicodePathRec = ^TXceedUnicodePathRec; TXceedUnicodePathRec = packed record Signature: LongWord; Length: Integer; UnicodeName: array[0..0] of WideChar; end; PZip64LocalHeaderRec = ^TZip64LocalHeaderRec; TZip64LocalHeaderRec = packed record UncompressedSize: Int64; CompressedSize: Int64; end; type TAbZipCompressionMethod = (cmStored, cmShrunk, cmReduced1, cmReduced2, cmReduced3, cmReduced4, cmImploded, cmTokenized, cmDeflated, cmEnhancedDeflated, cmDCLImploded, cmBzip2 = 12, cmLZMA = 14, cmIBMTerse = 18, cmLZ77, cmJPEG = 96, cmWavPack = 97, cmPPMd); TAbZipSupportedMethod = (smStored, smDeflated, smBestMethod); {ExternalFileAttributes compatibility; aliases are Info-ZIP/PKZIP overlaps} TAbZipHostOS = (hosDOS, hosAmiga, hosVAX, hosUnix, hosVMCMS, hosAtari, hosOS2, hosMacintosh, hosZSystem, hosCPM, hosNTFS, hosTOPS20 = hosNTFS, hosMVS, hosWinNT = hosMVS, hosVSE, hosQDOS = hosVSE, hosRISC, hosVFAT, hosAltMVS, hosBeOS, hosTandem, hosOS400, hosTHEOS = hosOS400, hosDarwin, hosAtheOS = 30); {for method 6 - imploding} TAbZipDictionarySize = (dsInvalid, ds4K, ds8K); {for method 8 - deflating} TAbZipDeflationOption = (doInvalid, doNormal, doMaximum, doFast, doSuperFast ); type TAbNeedPasswordEvent = procedure(Sender : TObject; var NewPassword : AnsiString) of object; const AbDefCompressionMethodToUse = smBestMethod; AbDefDeflationOption = doNormal; type TAbZipDataDescriptor = class( TObject ) protected {private} FCRC32 : Longint; FCompressedSize : Int64; FUncompressedSize : Int64; public {methods} procedure SaveToStream( Stream : TStream ); public {properties} property CRC32 : Longint read FCRC32 write FCRC32; property CompressedSize : Int64 read FCompressedSize write FCompressedSize; property UncompressedSize : Int64 read FUncompressedSize write FUncompressedSize; end; type { TAbZipFileHeader interface =============================================== } {ancestor class for ZipLocalFileHeader and DirectoryFileHeader} TAbZipFileHeader = class( TObject ) protected {private} FValidSignature : Longint; FSignature : Longint; FVersionNeededToExtract : Word; FGeneralPurposeBitFlag : Word; FCompressionMethod : Word; FLastModFileTime : Word; FLastModFileDate : Word; FCRC32 : Longint; FCompressedSize : LongWord; FUncompressedSize : LongWord; FFileName : AnsiString; FExtraField : TAbExtraField; protected {methods} function GetCompressionMethod : TAbZipCompressionMethod; function GetCompressionRatio : Double; function GetDataDescriptor : Boolean; function GetDeflationOption : TAbZipDeflationOption; function GetDictionarySize : TAbZipDictionarySize; function GetEncrypted : Boolean; function GetIsUTF8 : Boolean; function GetShannonFanoTreeCount : Byte; function GetValid : Boolean; procedure SetCompressionMethod( Value : TAbZipCompressionMethod ); procedure SetIsUTF8( Value : Boolean ); public {methods} constructor Create; destructor Destroy; override; public {properties} property Signature : Longint read FSignature write FSignature; property VersionNeededToExtract : Word read FVersionNeededToExtract write FVersionNeededToExtract; property GeneralPurposeBitFlag : Word read FGeneralPurposeBitFlag write FGeneralPurposeBitFlag; property CompressionMethod : TAbZipCompressionMethod read GetCompressionMethod write SetCompressionMethod; property LastModFileTime : Word read FLastModFileTime write FLastModFileTime; property LastModFileDate : Word read FLastModFileDate write FLastModFileDate; property CRC32 : Longint read FCRC32 write FCRC32; property CompressedSize : LongWord read FCompressedSize write FCompressedSize; property UncompressedSize : LongWord read FUncompressedSize write FUncompressedSize; property FileName : AnsiString read FFileName write FFileName; property ExtraField : TAbExtraField read FExtraField; property CompressionRatio : Double read GetCompressionRatio; property DeflationOption : TAbZipDeflationOption read GetDeflationOption; property DictionarySize : TAbZipDictionarySize read GetDictionarySize; property HasDataDescriptor : Boolean read GetDataDescriptor; property IsValid : Boolean read GetValid; property IsEncrypted : Boolean read GetEncrypted; property IsUTF8 : Boolean read GetIsUTF8 write SetIsUTF8; property ShannonFanoTreeCount : Byte read GetShannonFanoTreeCount; end; { TAbZipLocalFileHeader interface ========================================== } TAbZipLocalFileHeader = class( TAbZipFileHeader ) public {methods} constructor Create; destructor Destroy; override; procedure LoadFromStream( Stream : TStream ); procedure SaveToStream( Stream : TStream ); end; { TAbZipDirectoryFileHeader interface ====================================== } TAbZipDirectoryFileHeader = class( TAbZipFileHeader ) protected {private} FVersionMadeBy : Word; FDiskNumberStart : Word; FInternalFileAttributes : Word; FExternalFileAttributes : LongWord; FRelativeOffset : LongWord; FFileComment : AnsiString; public {methods} constructor Create; destructor Destroy; override; procedure LoadFromStream( Stream : TStream ); procedure SaveToStream( Stream : TStream ); public {properties} property VersionMadeBy : Word read FVersionMadeBy write FVersionMadeBy; property DiskNumberStart : Word read FDiskNumberStart write FDiskNumberStart; property InternalFileAttributes : Word read FInternalFileAttributes write FInternalFileAttributes; property ExternalFileAttributes : LongWord read FExternalFileAttributes write FExternalFileAttributes; property RelativeOffset : LongWord read FRelativeOffset write FRelativeOffset; property FileComment : AnsiString read FFileComment write FFileComment; end; { TAbZipDirectoryFileFooter interface ====================================== } TAbZipDirectoryFileFooter = class( TObject ) protected {private} FDiskNumber : LongWord; FStartDiskNumber : LongWord; FEntriesOnDisk : Int64; FTotalEntries : Int64; FDirectorySize : Int64; FDirectoryOffset : Int64; FZipfileComment : AnsiString; function GetIsZip64: Boolean; public {methods} procedure LoadFromStream( Stream : TStream ); procedure LoadZip64FromStream( Stream : TStream ); procedure SaveToStream( Stream : TStream; aZip64TailOffset : Int64 = -1 ); public {properties} property DiskNumber : LongWord read FDiskNumber write FDiskNumber; property EntriesOnDisk : Int64 read FEntriesOnDisk write FEntriesOnDisk; property TotalEntries : Int64 read FTotalEntries write FTotalEntries; property DirectorySize : Int64 read FDirectorySize write FDirectorySize; property DirectoryOffset : Int64 read FDirectoryOffset write FDirectoryOffset; property StartDiskNumber : LongWord read FStartDiskNumber write FStartDiskNumber; property ZipfileComment : AnsiString read FZipfileComment write FZipfileComment; property IsZip64: Boolean read GetIsZip64; end; { TAbZipItem interface ===================================================== } TAbZipItem = class( TAbArchiveItem ) protected {private} FItemInfo : TAbZipDirectoryFileHeader; FDiskNumberStart : LongWord; FLFHExtraField : TAbExtraField; FRelativeOffset : Int64; protected {methods} function GetCompressionMethod : TAbZipCompressionMethod; function GetCompressionRatio : Double; function GetDeflationOption : TAbZipDeflationOption; function GetDictionarySize : TAbZipDictionarySize; function GetExtraField : TAbExtraField; function GetFileComment : AnsiString; function GetGeneralPurposeBitFlag : Word; function GetHostOS: TAbZipHostOS; function GetInternalFileAttributes : Word; function GetRawFileName : AnsiString; function GetShannonFanoTreeCount : Byte; function GetVersionMadeBy : Word; function GetVersionNeededToExtract : Word; procedure SaveCDHToStream( Stream : TStream ); procedure SaveDDToStream( Stream : TStream ); procedure SaveLFHToStream( Stream : TStream ); procedure SetCompressionMethod( Value : TAbZipCompressionMethod ); procedure SetDiskNumberStart( Value : LongWord ); procedure SetFileComment(const Value : AnsiString ); procedure SetGeneralPurposeBitFlag( Value : Word ); procedure SetHostOS( Value : TAbZipHostOS ); procedure SetInternalFileAttributes( Value : Word ); procedure SetRelativeOffset( Value : Int64 ); procedure SetVersionMadeBy( Value : Word ); procedure SetVersionNeededToExtract( Value : Word ); procedure UpdateVersionNeededToExtract; procedure UpdateZip64ExtraHeader; protected {redefined property methods} function GetCRC32 : Longint; override; function GetExternalFileAttributes : LongWord; override; function GetIsDirectory: Boolean; override; function GetIsEncrypted : Boolean; override; function GetLastModFileDate : Word; override; function GetLastModFileTime : Word; override; function GetNativeFileAttributes : LongInt; override; procedure SetCompressedSize( const Value : Int64 ); override; procedure SetCRC32( const Value : Longint ); override; procedure SetExternalFileAttributes( Value : LongWord ); override; procedure SetFileName(const Value : string ); override; procedure SetLastModFileDate(const Value : Word ); override; procedure SetLastModFileTime(const Value : Word ); override; procedure SetUncompressedSize( const Value : Int64 ); override; public {methods} constructor Create; destructor Destroy; override; procedure LoadFromStream( Stream : TStream ); public {properties} property CompressionMethod : TAbZipCompressionMethod read GetCompressionMethod write SetCompressionMethod; property CompressionRatio : Double read GetCompressionRatio; property DeflationOption : TAbZipDeflationOption read GetDeflationOption; property DictionarySize : TAbZipDictionarySize read GetDictionarySize; property DiskNumberStart : LongWord read FDiskNumberStart write SetDiskNumberStart; property ExtraField : TAbExtraField read GetExtraField; property FileComment : AnsiString read GetFileComment write SetFileComment; property HostOS: TAbZipHostOS read GetHostOS write SetHostOS; property InternalFileAttributes : Word read GetInternalFileAttributes write SetInternalFileAttributes; property GeneralPurposeBitFlag : Word read GetGeneralPurposeBitFlag write SetGeneralPurposeBitFlag; property LFHExtraField : TAbExtraField read FLFHExtraField; property RawFileName : AnsiString read GetRawFileName; property RelativeOffset : Int64 read FRelativeOffset write SetRelativeOffset; property ShannonFanoTreeCount : Byte read GetShannonFanoTreeCount; property VersionMadeBy : Word read GetVersionMadeBy write SetVersionMadeBy; property VersionNeededToExtract : Word read GetVersionNeededToExtract write SetVersionNeededToExtract; end; { TAbZipArchive interface ================================================== } TAbZipArchive = class( TAbArchive ) protected {private} FCompressionMethodToUse : TAbZipSupportedMethod; FDeflationOption : TAbZipDeflationOption; FInfo : TAbZipDirectoryFileFooter; FIsExecutable : Boolean; FPassword : AnsiString; FPasswordRetries : Byte; FStubSize : LongWord; FExtractHelper : TAbArchiveItemExtractEvent; FExtractToStreamHelper : TAbArchiveItemExtractToStreamEvent; FTestHelper : TAbArchiveItemTestEvent; FInsertHelper : TAbArchiveItemInsertEvent; FInsertFromStreamHelper : TAbArchiveItemInsertFromStreamEvent; FOnNeedPassword : TAbNeedPasswordEvent; FOnRequestLastDisk : TAbRequestDiskEvent; FOnRequestNthDisk : TAbRequestNthDiskEvent; FOnRequestBlankDisk : TAbRequestDiskEvent; protected {methods} procedure DoExtractHelper(Index : Integer; const NewName : string); procedure DoExtractToStreamHelper(Index : Integer; aStream : TStream); procedure DoTestHelper(Index : Integer); procedure DoInsertHelper(Index : Integer; OutStream : TStream); procedure DoInsertFromStreamHelper(Index : Integer; OutStream : TStream); function GetItem( Index : Integer ) : TAbZipItem; function GetZipfileComment : AnsiString; procedure PutItem( Index : Integer; Value : TAbZipItem ); procedure DoRequestDisk(const AMessage: string; var Abort : Boolean); procedure DoRequestLastDisk( var Abort : Boolean ); virtual; procedure DoRequestNthDisk(Sender: TObject; DiskNumber : Byte; var Abort : Boolean ); virtual; procedure DoRequestBlankDisk(Sender: TObject; var Abort : Boolean ); virtual; procedure ExtractItemAt(Index : Integer; const UseName : string); override; procedure ExtractItemToStreamAt(Index : Integer; aStream : TStream); override; procedure TestItemAt(Index : Integer); override; function FixName(const Value : string ) : string; override; function GetSupportsEmptyFolders: Boolean; override; procedure LoadArchive; override; procedure SaveArchive; override; procedure SetZipfileComment(const Value : AnsiString ); protected {properties} property IsExecutable : Boolean read FIsExecutable write FIsExecutable; public {protected} procedure DoRequestImage(Sender: TObject; ImageNumber: Integer; var ImageName: string; var Abort: Boolean); public {methods} constructor CreateFromStream( aStream : TStream; const ArchiveName : string ); override; destructor Destroy; override; function CreateItem(const FileName : string): TAbArchiveItem; override; public {properties} property CompressionMethodToUse : TAbZipSupportedMethod read FCompressionMethodToUse write FCompressionMethodToUse; property DeflationOption : TAbZipDeflationOption read FDeflationOption write FDeflationOption; property ExtractHelper : TAbArchiveItemExtractEvent read FExtractHelper write FExtractHelper; property ExtractToStreamHelper : TAbArchiveItemExtractToStreamEvent read FExtractToStreamHelper write FExtractToStreamHelper; property TestHelper : TAbArchiveItemTestEvent read FTestHelper write FTestHelper; property InsertHelper : TAbArchiveItemInsertEvent read FInsertHelper write FInsertHelper; property InsertFromStreamHelper : TAbArchiveItemInsertFromStreamEvent read FInsertFromStreamHelper write FInsertFromStreamHelper; property Password : AnsiString read FPassword write FPassword; property PasswordRetries : Byte read FPasswordRetries write FPasswordRetries default AbDefPasswordRetries; property StubSize : LongWord read FStubSize; property ZipfileComment : AnsiString read GetZipfileComment write SetZipfileComment; property Items[Index : Integer] : TAbZipItem read GetItem write PutItem; default; public {events} property OnNeedPassword : TAbNeedPasswordEvent read FOnNeedPassword write FOnNeedPassword; property OnRequestLastDisk : TAbRequestDiskEvent read FOnRequestLastDisk write FOnRequestLastDisk; property OnRequestNthDisk : TAbRequestNthDiskEvent read FOnRequestNthDisk write FOnRequestNthDisk; property OnRequestBlankDisk : TAbRequestDiskEvent read FOnRequestBlankDisk write FOnRequestBlankDisk; end; {============================================================================} procedure MakeSelfExtracting( StubStream, ZipStream, SelfExtractingStream : TStream ); {-takes an executable stub, and a .zip format stream, and creates a SelfExtracting stream. The stub should create a TAbZipArchive passing itself as the file, using a read-only open mode. It should then perform operations as needed - like ExtractFiles( '*.*' ). This routine updates the RelativeOffset of each item in the archive} function FindCentralDirectoryTail(aStream : TStream) : Int64; function VerifyZip(Strm : TStream) : TAbArchiveType; function VerifySelfExtracting(Strm : TStream) : TAbArchiveType; function ZipCompressionMethodToString(aMethod: TAbZipCompressionMethod): string; implementation uses {$IFDEF MSWINDOWS} Windows, {$ENDIF} {$IFDEF LibcAPI} Libc, {$ENDIF} {$IFDEF UnixDialogs} {$IFDEF KYLIX} QControls, QDialogs, {$ENDIF} {$IFDEF LCL} Controls, Dialogs, {$ENDIF} {$ENDIF} Math, AbCharset, AbResString, AbExcept, AbVMStrm, SysUtils; function VerifyZip(Strm : TStream) : TAbArchiveType; { determine if stream appears to be in PkZip format } var Footer : TAbZipEndOfCentralDirectoryRecord; Sig : LongInt; TailPosition : int64; StartPos : int64; begin StartPos := Strm.Position; Result := atUnknown; try Strm.Position := 0; Strm.Read(Sig, SizeOf(Sig)); if (Sig = Ab_ZipSpannedSetSignature) then Result := atSpannedZip else begin { attempt to find Central Directory Tail } TailPosition := FindCentralDirectoryTail( Strm ); if TailPosition <> -1 then begin { check Central Directory Signature } Strm.ReadBuffer(Footer, SizeOf(Footer)); if Footer.Signature = Ab_ZipEndCentralDirectorySignature then if Footer.DiskNumber = 0 then Result := atZip else Result := atSpannedZip; end; end; except on EReadError do Result := atUnknown; end; Strm.Position := StartPos; end; function VerifySelfExtracting(Strm : TStream) : TAbArchiveType; { determine if stream appears to be an executable with appended PkZip data } var FileSignature : Longint; StartPos : Int64; IsWinExe, IsLinuxExe : Boolean; begin StartPos := Strm.Position; { verify presence of executable stub } {check file type of stub stream} Strm.Position := 0; Strm.Read( FileSignature, sizeof( FileSignature ) ); Result := atSelfExtZip; { detect executable type } IsLinuxExe := FileSignature = Ab_LinuxExeSignature; IsWinExe := LongRec(FileSignature).Lo = Ab_WindowsExeSignature; if not (IsWinExe or IsLinuxExe) then Result := atUnknown; { Check for central directory tail } if VerifyZip(Strm) <> atZip then Result := atUnknown; Strm.Position := StartPos; end; {============================================================================} function ZipCompressionMethodToString(aMethod: TAbZipCompressionMethod): string; begin case aMethod of cmStored: Result := AbZipStored; cmShrunk: Result := AbZipShrunk; cmReduced1..cmReduced4: Result := AbZipReduced; cmImploded: Result := AbZipImploded; cmTokenized: Result := AbZipTokenized; cmDeflated: Result := AbZipDeflated; cmEnhancedDeflated: Result := AbZipDeflate64; cmDCLImploded: Result := AbZipDCLImploded; cmBzip2: Result := AbZipBzip2; cmLZMA: Result := AbZipLZMA; cmIBMTerse: Result := AbZipIBMTerse; cmLZ77: Result := AbZipLZ77; cmJPEG: Result := AbZipJPEG; cmWavPack: Result := AbZipWavPack; cmPPMd: Result := AbZipPPMd; else Result := Format(AbZipUnknown, [Ord(aMethod)]); end; end; {============================================================================} function FindCentralDirectoryTail(aStream : TStream) : Int64; { search end of aStream looking for ZIP Central Directory structure returns position in stream if found (otherwise returns -1), leaves stream positioned at start of structure or at original position if not found } const StartBufSize = 512; MaxBufSize = 64 * 1024; var StartPos : Int64; TailRec : TAbZipEndOfCentralDirectoryRecord; Buffer : PAnsiChar; Offset : Int64; TestPos : PAnsiChar; Done : boolean; BytesRead : Int64; BufSize : Int64; CommentLen: integer; begin {save the starting position} StartPos := aStream.Seek(0, soCurrent); {start off with the majority case: no zip file comment, so the central directory tail is the last thing in the stream and it's a fixed size and doesn't indicate a zip file comment} Result := aStream.Seek(-sizeof(TailRec), soEnd); if (Result >= 0) then begin aStream.ReadBuffer(TailRec, sizeof(TailRec)); if (TailRec.Signature = Ab_ZipEndCentralDirectorySignature) and (TailRec.CommentLength = 0) then begin aStream.Seek(Result, soBeginning); Exit; end; end; {the zip stream seems to have a comment, or it has null padding bytes from some flaky program, or it's not even a zip formatted stream; we need to search for the tail signature} {get a buffer} BufSize := StartBufSize; GetMem(Buffer, BufSize); try {start out searching backwards} Offset := -BufSize; {while there is still data to search ...} Done := false; while not Done do begin {seek to the search position} Result := aStream.Seek(Offset, soEnd); if (Result <= 0) then begin Result := aStream.Seek(0, soBeginning); Done := true; end; {read a buffer full} BytesRead := aStream.Read(Buffer^, BufSize); if BytesRead < sizeOf(TailRec) then begin Result := -1; Exit; end; {search backwards through the buffer looking for the signature} TestPos := Buffer + BytesRead - sizeof(TailRec); while (TestPos <> Buffer) and (PLongint(TestPos)^ <> Ab_ZipEndCentralDirectorySignature) do dec(TestPos); {if we found the signature...} if (PLongint(TestPos)^ = Ab_ZipEndCentralDirectorySignature) then begin {get the tail record at this position} Move(TestPos^, TailRec, sizeof(TailRec)); {if it's as valid a tail as we can check here...} CommentLen := -Offset - (TestPos - Buffer + sizeof(TailRec)); if (TailRec.CommentLength <= CommentLen) then begin {calculate its position and exit} Result := Result + (TestPos - Buffer); aStream.Seek(Result, soBeginning); Exit; end; end; {otherwise move back one step, doubling the buffer} if (BufSize < MaxBufSize) then begin FreeMem(Buffer); BufSize := BufSize * 2; if BufSize > MaxBufSize then BufSize := MaxBufSize; GetMem(Buffer, BufSize); end; dec(Offset, BufSize - SizeOf(TailRec)); end; {if we reach this point, the CD tail is not present} Result := -1; aStream.Seek(StartPos, soBeginning); finally FreeMem(Buffer); end; end; {============================================================================} procedure MakeSelfExtracting( StubStream, ZipStream, SelfExtractingStream : TStream ); {-takes an executable stub, and a .zip format stream, and creates a SelfExtracting stream. The stub should create a TAbZipArchive passing itself as the file, using a read-only open mode. It should then perform operations as needed - like ExtractFiles( '*.*' ). This routine updates the RelativeOffset of each item in the archive} var DirectoryStart : Int64; FileSignature : Longint; StubSize : LongWord; TailPosition : Int64; ZDFF : TAbZipDirectoryFileFooter; ZipItem : TAbZipItem; IsWinExe, IsLinuxExe : Boolean; begin {check file type of stub stream} StubStream.Position := 0; StubStream.Read(FileSignature, SizeOf(FileSignature)); {detect executable type } IsLinuxExe := FileSignature = Ab_LinuxExeSignature; IsWinExe := LongRec(FileSignature).Lo = Ab_WindowsExeSignature; if not (IsWinExe or IsLinuxExe) then raise EAbZipInvalidStub.Create; StubStream.Position := 0; StubSize := StubStream.Size; ZipStream.Position := 0; ZipStream.Read( FileSignature, sizeof( FileSignature ) ); if LongRec(FileSignature).Lo <> Ab_GeneralZipSignature then raise EAbZipInvalid.Create; ZipStream.Position := 0; {copy the stub into the selfex stream} SelfExtractingStream.Position := 0; SelfExtractingStream.CopyFrom( StubStream, 0 ); TailPosition := FindCentralDirectoryTail( ZipStream ); if TailPosition = -1 then raise EAbZipInvalid.Create; {load the ZipDirectoryFileFooter} ZDFF := TAbZipDirectoryFileFooter.Create; try ZDFF.LoadFromStream( ZipStream ); DirectoryStart := ZDFF.DirectoryOffset; finally ZDFF.Free; end; {copy everything up to the CDH into the SelfExtractingStream} ZipStream.Position := 0; SelfExtractingStream.CopyFrom( ZipStream, DirectoryStart ); ZipStream.Position := DirectoryStart; repeat ZipItem := TAbZipItem.Create; try ZipItem.LoadFromStream( ZipStream ); ZipItem.RelativeOffset := ZipItem.RelativeOffset + StubSize; {save the modified entry into the Self Extracting Stream} ZipItem.SaveCDHToStream( SelfExtractingStream ); finally ZipItem.Free; end; until ZipStream.Position = TailPosition; {save the CDH Footer.} ZDFF := TAbZipDirectoryFileFooter.Create; try ZDFF.LoadFromStream( ZipStream ); ZDFF.DirectoryOffset := ZDFF.DirectoryOffset + StubSize; ZDFF.SaveToStream( SelfExtractingStream ); finally ZDFF.Free; end; end; {============================================================================} { TAbZipDataDescriptor implementation ====================================== } procedure TAbZipDataDescriptor.SaveToStream( Stream : TStream ); begin Stream.Write( Ab_ZipDataDescriptorSignature, sizeof( Ab_ZipDataDescriptorSignature ) ); Stream.Write( FCRC32, sizeof( FCRC32 ) ); if (FCompressedSize >= $FFFFFFFF) or (FUncompressedSize >= $FFFFFFFF) then begin Stream.Write( FCompressedSize, sizeof( FCompressedSize ) ); Stream.Write( FUncompressedSize, sizeof( FUncompressedSize ) ); end else begin Stream.Write( FCompressedSize, sizeof( LongWord ) ); Stream.Write( FUncompressedSize, sizeof( LongWord ) ); end; end; { -------------------------------------------------------------------------- } { TAbZipFileHeader implementation ========================================== } constructor TAbZipFileHeader.Create; begin inherited Create; FExtraField := TAbExtraField.Create; FValidSignature := $0; end; { -------------------------------------------------------------------------- } destructor TAbZipFileHeader.Destroy; begin FreeAndNil(FExtraField); inherited Destroy; end; { -------------------------------------------------------------------------- } function TAbZipFileHeader.GetCompressionMethod : TAbZipCompressionMethod; begin Result := TAbZipCompressionMethod( FCompressionMethod ); end; { -------------------------------------------------------------------------- } function TAbZipFileHeader.GetDataDescriptor : Boolean; begin Result := ( CompressionMethod = cmDeflated ) and ( ( FGeneralPurposeBitFlag and AbHasDataDescriptorFlag ) <> 0 ); end; { -------------------------------------------------------------------------- } function TAbZipFileHeader.GetCompressionRatio : Double; var CompSize : Int64; begin {adjust for encrypted headers - ensures we never get negative compression ratios for stored, encrypted files - no guarantees about negative compression ratios in other cases} if isEncrypted then CompSize := CompressedSize - 12 else CompSize := CompressedSize; if UncompressedSize > 0 then Result := 100.0 * ( 1 - ( ( 1.0 * CompSize ) / UncompressedSize ) ) else Result := 0.0; end; { -------------------------------------------------------------------------- } function TAbZipFileHeader.GetDeflationOption : TAbZipDeflationOption; begin if CompressionMethod = cmDeflated then if ( ( FGeneralPurposeBitFlag and $02 ) <> 0 ) then if ( ( FGeneralPurposeBitFlag and $04 ) <> 0 ) then Result := doSuperFast else Result := doMaximum else if ( ( FGeneralPurposeBitFlag and $04 ) <> 0 ) then Result := doFast else Result := doNormal else Result := doInvalid; end; { -------------------------------------------------------------------------- } function TAbZipFileHeader.GetDictionarySize : TAbZipDictionarySize; begin if CompressionMethod = cmImploded then if ( ( FGeneralPurposeBitFlag and $02 ) <> 0 ) then Result := ds8K else Result := ds4K else Result := dsInvalid; end; { -------------------------------------------------------------------------- } function TAbZipFileHeader.GetEncrypted : Boolean; begin {bit 0 of the GeneralPurposeBitFlag} Result := ( ( FGeneralPurposeBitFlag and AbFileIsEncryptedFlag ) <> 0 ); end; { -------------------------------------------------------------------------- } function TAbZipFileHeader.GetIsUTF8 : Boolean; begin Result := ( ( GeneralPurposeBitFlag and AbLanguageEncodingFlag ) <> 0 ); end; { -------------------------------------------------------------------------- } function TAbZipFileHeader.GetShannonFanoTreeCount : Byte; begin if CompressionMethod = cmImploded then if ( ( FGeneralPurposeBitFlag and $04 ) <> 0 ) then Result := 3 else Result := 2 else Result := 0; end; { -------------------------------------------------------------------------- } function TAbZipFileHeader.GetValid : Boolean; begin Result := ( FValidSignature = FSignature ); end; { -------------------------------------------------------------------------- } procedure TAbZipFileHeader.SetCompressionMethod( Value : TAbZipCompressionMethod ); begin FCompressionMethod := Ord( Value ); end; { -------------------------------------------------------------------------- } procedure TAbZipFileHeader.SetIsUTF8( Value : Boolean ); begin if Value then GeneralPurposeBitFlag := GeneralPurposeBitFlag or AbLanguageEncodingFlag else GeneralPurposeBitFlag := GeneralPurposeBitFlag and not AbLanguageEncodingFlag; end; { -------------------------------------------------------------------------- } { TAbZipLocalFileHeader implementation ===================================== } constructor TAbZipLocalFileHeader.Create; begin inherited Create; FValidSignature := Ab_ZipLocalFileHeaderSignature; end; { -------------------------------------------------------------------------- } destructor TAbZipLocalFileHeader.Destroy; begin inherited Destroy; end; { -------------------------------------------------------------------------- } procedure TAbZipLocalFileHeader.LoadFromStream( Stream : TStream ); var ExtraFieldLength, FileNameLength : Word; begin with Stream do begin Read( FSignature, sizeof( FSignature ) ); Read( FVersionNeededToExtract, sizeof( FVersionNeededToExtract ) ); Read( FGeneralPurposeBitFlag, sizeof( FGeneralPurposeBitFlag ) ); Read( FCompressionMethod, sizeof( FCompressionMethod ) ); Read( FLastModFileTime, sizeof( FLastModFileTime ) ); Read( FLastModFileDate, sizeof( FLastModFileDate ) ); Read( FCRC32, sizeof( FCRC32 ) ); Read( FCompressedSize, sizeof( FCompressedSize ) ); Read( FUncompressedSize, sizeof( FUncompressedSize ) ); Read( FileNameLength, sizeof( FileNameLength ) ); Read( ExtraFieldLength, sizeof( ExtraFieldLength ) ); SetLength( FFileName, FileNameLength ); if FileNameLength > 0 then Read( FFileName[1], FileNameLength ); FExtraField.LoadFromStream( Stream, ExtraFieldLength ); end; if not IsValid then raise EAbZipInvalid.Create; end; { -------------------------------------------------------------------------- } procedure TAbZipLocalFileHeader.SaveToStream( Stream : TStream ); var ExtraFieldLength, FileNameLength: Word; begin with Stream do begin {write the valid signature from the constant} Write( FValidSignature, sizeof( FValidSignature ) ); Write( FVersionNeededToExtract, sizeof( FVersionNeededToExtract ) ); Write( FGeneralPurposeBitFlag, sizeof( FGeneralPurposeBitFlag ) ); Write( FCompressionMethod, sizeof( FCompressionMethod ) ); Write( FLastModFileTime, sizeof( FLastModFileTime ) ); Write( FLastModFileDate, sizeof( FLastModFileDate ) ); Write( FCRC32, sizeof( FCRC32 ) ); Write( FCompressedSize, sizeof( FCompressedSize ) ); Write( FUncompressedSize, sizeof( FUncompressedSize ) ); FileNameLength := Word( Length( FFileName ) ); Write( FileNameLength, sizeof( FileNameLength ) ); ExtraFieldLength := Length(FExtraField.Buffer); Write( ExtraFieldLength, sizeof( ExtraFieldLength ) ); if FileNameLength > 0 then Write( FFileName[1], FileNameLength ); if ExtraFieldLength > 0 then Write(FExtraField.Buffer[0], ExtraFieldLength); end; end; { -------------------------------------------------------------------------- } { TAbZipDirectoryFileHeader implementation ================================= } constructor TAbZipDirectoryFileHeader.Create; begin inherited Create; FValidSignature := Ab_ZipCentralDirectoryFileHeaderSignature; end; { -------------------------------------------------------------------------- } destructor TAbZipDirectoryFileHeader.Destroy; begin inherited Destroy; end; { -------------------------------------------------------------------------- } procedure TAbZipDirectoryFileHeader.LoadFromStream( Stream : TStream ); var ExtraFieldLength, FileCommentLength, FileNameLength : Word; begin with Stream do begin Read( FSignature, sizeof( FSignature ) ); Read( FVersionMadeBy, sizeof( FVersionMadeBy ) ); Read( FVersionNeededToExtract, sizeof( FVersionNeededToExtract ) ); Read( FGeneralPurposeBitFlag, sizeof( FGeneralPurposeBitFlag ) ); Read( FCompressionMethod, sizeof( FCompressionMethod ) ); Read( FLastModFileTime, sizeof( FLastModFileTime ) ); Read( FLastModFileDate, sizeof( FLastModFileDate ) ); Read( FCRC32, sizeof( FCRC32 ) ); Read( FCompressedSize, sizeof( FCompressedSize ) ); Read( FUncompressedSize, sizeof( FUncompressedSize ) ); Read( FileNameLength, sizeof( FileNameLength ) ); Read( ExtraFieldLength, sizeof( ExtraFieldLength ) ); Read( FileCommentLength, sizeof( FileCommentLength ) ); Read( FDiskNumberStart, sizeof( FDiskNumberStart ) ); Read( FInternalFileAttributes, sizeof( FInternalFileAttributes ) ); Read( FExternalFileAttributes, sizeof( FExternalFileAttributes ) ); Read( FRelativeOffset, sizeof( FRelativeOffset ) ); SetLength( FFileName, FileNameLength ); if FileNameLength > 0 then Read( FFileName[1], FileNameLength ); FExtraField.LoadFromStream( Stream, ExtraFieldLength ); SetLength( FFileComment, FileCommentLength ); if FileCommentLength > 0 then Read( FFileComment[1], FileCommentLength ); end; if not IsValid then raise EAbZipInvalid.Create; end; { -------------------------------------------------------------------------- } procedure TAbZipDirectoryFileHeader.SaveToStream( Stream : TStream ); var ExtraFieldLength, FileCommentLength, FileNameLength : Word; begin with Stream do begin {write the valid signature from the constant} Write( FValidSignature, sizeof( FValidSignature ) ); Write( FVersionMadeBy, sizeof( FVersionMadeBy ) ); Write( FVersionNeededToExtract, sizeof( FVersionNeededToExtract ) ); Write( FGeneralPurposeBitFlag, sizeof( FGeneralPurposeBitFlag ) ); Write( FCompressionMethod, sizeof( FCompressionMethod ) ); Write( FLastModFileTime, sizeof( FLastModFileTime ) ); Write( FLastModFileDate, sizeof( FLastModFileDate ) ); Write( FCRC32, sizeof( FCRC32 ) ); Write( FCompressedSize, sizeof( FCompressedSize ) ); Write( FUncompressedSize, sizeof( FUncompressedSize ) ); FileNameLength := Word( Length( FFileName ) ); Write( FileNameLength, sizeof( FileNameLength ) ); ExtraFieldLength := Length(FExtraField.Buffer); Write( ExtraFieldLength, sizeof( ExtraFieldLength ) ); FileCommentLength := Word( Length( FFileComment ) ); Write( FileCommentLength, sizeof( FileCommentLength ) ); Write( FDiskNumberStart, sizeof( FDiskNumberStart ) ); Write( FInternalFileAttributes, sizeof( FInternalFileAttributes ) ); Write( FExternalFileAttributes, sizeof( FExternalFileAttributes ) ); Write( FRelativeOffset, sizeof( FRelativeOffset ) ); if FileNameLength > 0 then Write( FFileName[1], FileNameLength ); if ExtraFieldLength > 0 then Write( FExtraField.Buffer[0], ExtraFieldLength ); if FileCommentLength > 0 then Write( FFileComment[1], FileCommentLength ); end; end; { -------------------------------------------------------------------------- } { TAbZipDirectoryFileFooter implementation ================================= } function TAbZipDirectoryFileFooter.GetIsZip64: Boolean; begin Result := (DiskNumber >= $FFFF) or (StartDiskNumber >= $FFFF) or (EntriesOnDisk >= $FFFF) or (TotalEntries >= $FFFF) or (DirectorySize >= $FFFFFFFF) or (DirectoryOffset >= $FFFFFFFF); end; { -------------------------------------------------------------------------- } procedure TAbZipDirectoryFileFooter.LoadFromStream( Stream : TStream ); var Footer: TAbZipEndOfCentralDirectoryRecord; begin Stream.ReadBuffer( Footer, SizeOf(Footer) ); if Footer.Signature <> Ab_ZipEndCentralDirectorySignature then raise EAbZipInvalid.Create; FDiskNumber := Footer.DiskNumber; FStartDiskNumber := Footer.StartDiskNumber; FEntriesOnDisk := Footer.EntriesOnDisk; FTotalEntries := Footer.TotalEntries; FDirectorySize := Footer.DirectorySize; FDirectoryOffset := Footer.DirectoryOffset; SetLength( FZipfileComment, Footer.CommentLength ); if Footer.CommentLength > 0 then Stream.ReadBuffer( FZipfileComment[1], Footer.CommentLength ); end; { -------------------------------------------------------------------------- } procedure TAbZipDirectoryFileFooter.LoadZip64FromStream( Stream : TStream ); {load the ZIP64 end of central directory record. LoadFromStream() must be called first to load the standard record} var Footer: TAbZip64EndOfCentralDirectoryRecord; begin Stream.ReadBuffer( Footer, SizeOf(Footer) ); if Footer.Signature <> Ab_Zip64EndCentralDirectorySignature then raise EAbZipInvalid.Create; if FDiskNumber = $FFFF then FDiskNumber := Footer.DiskNumber; if FStartDiskNumber = $FFFF then FStartDiskNumber := Footer.StartDiskNumber; if FEntriesOnDisk = $FFFF then FEntriesOnDisk := Footer.EntriesOnDisk; if FTotalEntries = $FFFF then FTotalEntries := Footer.TotalEntries; if FDirectorySize = $FFFFFFFF then FDirectorySize := Footer.DirectorySize; if FDirectoryOffset = $FFFFFFFF then FDirectoryOffset := Footer.DirectoryOffset; {RecordSize, VersionMadeBy, and VersionNeededToExtract are currently ignored} end; { -------------------------------------------------------------------------- } procedure TAbZipDirectoryFileFooter.SaveToStream( Stream : TStream; aZip64TailOffset: Int64 = -1); {write end of central directory record, along with Zip64 records if necessary. aZip64TailOffset is the value to use for the Zip64 locator's directory offset, and is only necessary when writing to an intermediate stream} var Footer: TAbZipEndOfCentralDirectoryRecord; Zip64Footer: TAbZip64EndOfCentralDirectoryRecord; Zip64Locator: TAbZip64EndOfCentralDirectoryLocator; begin if IsZip64 then begin {setup Zip64 end of central directory record} Zip64Footer.Signature := Ab_Zip64EndCentralDirectorySignature; Zip64Footer.RecordSize := SizeOf(Zip64Footer) - SizeOf(Zip64Footer.Signature) - SizeOf(Zip64Footer.RecordSize); Zip64Footer.VersionMadeBy := 45; Zip64Footer.VersionNeededToExtract := 45; Zip64Footer.DiskNumber := DiskNumber; Zip64Footer.StartDiskNumber := StartDiskNumber; Zip64Footer.EntriesOnDisk := EntriesOnDisk; Zip64Footer.TotalEntries := TotalEntries; Zip64Footer.DirectorySize := DirectorySize; Zip64Footer.DirectoryOffset := DirectoryOffset; {setup Zip64 end of central directory locator} Zip64Locator.Signature := Ab_Zip64EndCentralDirectoryLocatorSignature; Zip64Locator.StartDiskNumber := DiskNumber; if aZip64TailOffset = -1 then Zip64Locator.RelativeOffset := Stream.Position else Zip64Locator.RelativeOffset := aZip64TailOffset; Zip64Locator.TotalDisks := DiskNumber + 1; {write Zip64 records} Stream.WriteBuffer(Zip64Footer, SizeOf(Zip64Footer)); Stream.WriteBuffer(Zip64Locator, SizeOf(Zip64Locator)); end; Footer.Signature := Ab_ZipEndCentralDirectorySignature; Footer.DiskNumber := Min(FDiskNumber, $FFFF); Footer.StartDiskNumber := Min(FStartDiskNumber, $FFFF); Footer.EntriesOnDisk := Min(FEntriesOnDisk, $FFFF); Footer.TotalEntries := Min(FTotalEntries, $FFFF); Footer.DirectorySize := Min(FDirectorySize, $FFFFFFFF); Footer.DirectoryOffset := Min(FDirectoryOffset, $FFFFFFFF); Footer.CommentLength := Length( FZipfileComment ); Stream.WriteBuffer( Footer, SizeOf(Footer) ); if FZipfileComment <> '' then Stream.Write( FZipfileComment[1], Length(FZipfileComment) ); end; { -------------------------------------------------------------------------- } { TAbZipItem implementation ================================================ } constructor TAbZipItem.Create; begin inherited Create; FItemInfo := TAbZipDirectoryFileHeader.Create; FLFHExtraField := TAbExtraField.Create; end; { -------------------------------------------------------------------------- } destructor TAbZipItem.Destroy; begin FLFHExtraField.Free; FItemInfo.Free; FItemInfo := nil; inherited Destroy; end; { -------------------------------------------------------------------------- } function TAbZipItem.GetCompressionMethod : TAbZipCompressionMethod; begin Result := FItemInfo.CompressionMethod; end; { -------------------------------------------------------------------------- } function TAbZipItem.GetCompressionRatio : Double; begin Result := FItemInfo.CompressionRatio; end; { -------------------------------------------------------------------------- } function TAbZipItem.GetCRC32 : Longint; begin Result := FItemInfo.CRC32; end; { -------------------------------------------------------------------------- } function TAbZipItem.GetDeflationOption : TAbZipDeflationOption; begin Result := FItemInfo.DeflationOption; end; { -------------------------------------------------------------------------- } function TAbZipItem.GetDictionarySize : TAbZipDictionarySize; begin Result := FItemInfo.DictionarySize; end; { -------------------------------------------------------------------------- } function TAbZipItem.GetGeneralPurposeBitFlag : Word; begin Result := FItemInfo.GeneralPurposeBitFlag; end; { -------------------------------------------------------------------------- } function TAbZipItem.GetHostOS: TAbZipHostOS; begin Result := TAbZipHostOS(Hi(VersionMadeBy)); end; { -------------------------------------------------------------------------- } function TAbZipItem.GetExternalFileAttributes : LongWord; begin Result := FItemInfo.ExternalFileAttributes; end; { -------------------------------------------------------------------------- } function TAbZipItem.GetExtraField : TAbExtraField; begin Result := FItemInfo.ExtraField; end; { -------------------------------------------------------------------------- } function TAbZipItem.GetFileComment : AnsiString; begin Result := FItemInfo.FileComment; end; { -------------------------------------------------------------------------- } function TAbZipItem.GetInternalFileAttributes : Word; begin Result := FItemInfo.InternalFileAttributes; end; { -------------------------------------------------------------------------- } function TAbZipItem.GetIsDirectory: Boolean; begin Result := ((ExternalFileAttributes and faDirectory) <> 0) or ((FileName <> '') and CharInSet(Filename[Length(FFilename)], ['\','/'])); end; { -------------------------------------------------------------------------- } function TAbZipItem.GetIsEncrypted : Boolean; begin Result := FItemInfo.IsEncrypted; end; { -------------------------------------------------------------------------- } function TAbZipItem.GetLastModFileDate : Word; begin Result := FItemInfo.LastModFileDate; end; { -------------------------------------------------------------------------- } function TAbZipItem.GetLastModFileTime : Word; begin Result := FItemInfo.LastModFileTime; end; { -------------------------------------------------------------------------- } function TAbZipItem.GetNativeFileAttributes : LongInt; begin {$IFDEF MSWINDOWS} if (HostOS = hosUnix) or (ExternalFileAttributes > $1FFFF) then Result := AbUnix2DosFileAttributes(ExternalFileAttributes shr 16) else Result := Byte(ExternalFileAttributes); {$ENDIF} {$IFDEF UNIX} if HostOS in [hosDOS, hosNTFS, hosWinNT] then Result := AbDOS2UnixFileAttributes(ExternalFileAttributes) else Result := ExternalFileAttributes shr 16; {$ENDIF} end; { -------------------------------------------------------------------------- } function TAbZipItem.GetRawFileName : AnsiString; begin Result := FItemInfo.FileName; end; { -------------------------------------------------------------------------- } function TAbZipItem.GetShannonFanoTreeCount : Byte; begin Result := FItemInfo.ShannonFanoTreeCount; end; { -------------------------------------------------------------------------- } function TAbZipItem.GetVersionMadeBy : Word; begin Result := FItemInfo.VersionMadeBy; end; { -------------------------------------------------------------------------- } function TAbZipItem.GetVersionNeededToExtract : Word; begin Result := FItemInfo.VersionNeededToExtract; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.LoadFromStream( Stream : TStream ); var FieldSize: Word; FieldStream: TStream; InfoZipField: PInfoZipUnicodePathRec; UnicodeName: UnicodeString; UTF8Name: AnsiString; XceedField: PXceedUnicodePathRec; begin FItemInfo.LoadFromStream( Stream ); { decode filename (ANSI/OEM/UTF-8) } if FItemInfo.IsUTF8 or (AbDetectCharSet(FItemInfo.FileName) = csUTF8) then FFileName := UTF8ToString(FItemInfo.FileName) else if FItemInfo.ExtraField.Get(Ab_InfoZipUnicodePathSubfieldID, Pointer(InfoZipField), FieldSize) and (FieldSize > SizeOf(TInfoZipUnicodePathRec)) and (InfoZipField.Version = 1) and (InfoZipField.NameCRC32 = AbCRC32Of(FItemInfo.FileName)) then begin SetString(UTF8Name, InfoZipField.UnicodeName, FieldSize - SizeOf(TInfoZipUnicodePathRec) + 1); FFileName := UTF8ToString(UTF8Name); end else if FItemInfo.ExtraField.Get(Ab_XceedUnicodePathSubfieldID, Pointer(XceedField), FieldSize) and (FieldSize > SizeOf(TXceedUnicodePathRec)) and (XceedField.Signature = Ab_XceedUnicodePathSignature) and (XceedField.Length * SizeOf(WideChar) = FieldSize - SizeOf(TXceedUnicodePathRec) + SizeOf(WideChar)) then begin SetString(UnicodeName, XceedField.UnicodeName, XceedField.Length); FFileName := string(UnicodeName); end {$IFDEF MSWINDOWS} else if (GetACP <> GetOEMCP) and ((HostOS = hosDOS) or AbIsOEM(FItemInfo.FileName)) then begin SetLength(FFileName, Length(FItemInfo.FileName)); OemToCharBuff(PAnsiChar(FItemInfo.FileName), PChar(FFileName), Length(FFileName)); end {$ENDIF} else FFileName := string(FItemInfo.FileName); { read ZIP64 extended header } FUncompressedSize := FItemInfo.UncompressedSize; FCompressedSize := FItemInfo.CompressedSize; FRelativeOffset := FItemInfo.RelativeOffset; FDiskNumberStart := FItemInfo.DiskNumberStart; if FItemInfo.ExtraField.GetStream(Ab_Zip64SubfieldID, FieldStream) then try if FItemInfo.UncompressedSize = $FFFFFFFF then FieldStream.ReadBuffer(FUncompressedSize, SizeOf(Int64)); if FItemInfo.CompressedSize = $FFFFFFFF then FieldStream.ReadBuffer(FCompressedSize, SizeOf(Int64)); if FItemInfo.RelativeOffset = $FFFFFFFF then FieldStream.ReadBuffer(FRelativeOffset, SizeOf(Int64)); if FItemInfo.DiskNumberStart = $FFFF then FieldStream.ReadBuffer(FDiskNumberStart, SizeOf(LongWord)); finally FieldStream.Free; end; LastModFileTime := FItemInfo.LastModFileTime; LastModFileDate := FItemInfo.LastModFileDate; FDiskFileName := FileName; AbUnfixName( FDiskFileName ); Action := aaNone; Tagged := False; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.SaveLFHToStream( Stream : TStream ); var LFH : TAbZipLocalFileHeader; Zip64Field: TZip64LocalHeaderRec; begin LFH := TAbZipLocalFileHeader.Create; try LFH.VersionNeededToExtract := VersionNeededToExtract; LFH.GeneralPurposeBitFlag := GeneralPurposeBitFlag; LFH.CompressionMethod := CompressionMethod; LFH.LastModFileTime := LastModFileTime; LFH.LastModFileDate := LastModFileDate; LFH.CRC32 := CRC32; LFH.FileName := RawFileName; LFH.ExtraField.Assign(LFHExtraField); LFH.ExtraField.CloneFrom(ExtraField, Ab_InfoZipUnicodePathSubfieldID); LFH.ExtraField.CloneFrom(ExtraField, Ab_XceedUnicodePathSubfieldID); { setup sizes; unlike the central directory header, the ZIP64 local header needs to store both compressed and uncompressed sizes if either needs it } if (CompressedSize >= $FFFFFFFF) or (UncompressedSize >= $FFFFFFFF) then begin LFH.UncompressedSize := $FFFFFFFF; LFH.CompressedSize := $FFFFFFFF; Zip64Field.UncompressedSize := UncompressedSize; Zip64Field.CompressedSize := CompressedSize; LFH.ExtraField.Put(Ab_Zip64SubfieldID, Zip64Field, SizeOf(Zip64Field)); end else begin LFH.UncompressedSize := UncompressedSize; LFH.CompressedSize := CompressedSize; LFH.ExtraField.Delete(Ab_Zip64SubfieldID); end; LFH.SaveToStream( Stream ); finally LFH.Free; end; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.SaveCDHToStream( Stream : TStream ); {-Save a ZipCentralDirectorHeader entry to Stream} begin FItemInfo.SaveToStream( Stream ); end; { -------------------------------------------------------------------------- } procedure TAbZipItem.SaveDDToStream( Stream : TStream ); var DD : TAbZipDataDescriptor; begin DD := TAbZipDataDescriptor.Create; try DD.CRC32 := CRC32; DD.CompressedSize := CompressedSize; DD.UncompressedSize := UncompressedSize; DD.SaveToStream( Stream ); finally DD.Free; end; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.SetCompressedSize( const Value : Int64 ); begin FCompressedSize := Value; FItemInfo.CompressedSize := Min(Value, $FFFFFFFF); UpdateZip64ExtraHeader; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.SetCompressionMethod( Value : TAbZipCompressionMethod ); begin FItemInfo.CompressionMethod := Value; UpdateVersionNeededToExtract; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.SetCRC32( const Value : Longint ); begin FItemInfo.CRC32 := Value; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.SetDiskNumberStart( Value : LongWord ); begin FDiskNumberStart := Value; FItemInfo.DiskNumberStart := Min(Value, $FFFF); UpdateZip64ExtraHeader; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.SetExternalFileAttributes( Value : LongWord ); begin FItemInfo.ExternalFileAttributes := Value; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.SetFileComment(const Value : AnsiString ); begin FItemInfo.FileComment := Value; end; { -------------------------------------------------------------------------- } {$IFDEF KYLIX}{$IFOPT O+}{$DEFINE OPTIMIZATIONS_ON}{$O-}{$ENDIF}{$ENDIF} procedure TAbZipItem.SetFileName(const Value : string ); var {$IFDEF MSWINDOWS} AnsiName : AnsiString; {$ENDIF} UTF8Name : AnsiString; FieldSize : Word; I : Integer; InfoZipField : PInfoZipUnicodePathRec; UseExtraField: Boolean; begin inherited SetFileName(Value); {$IFDEF MSWINDOWS} FItemInfo.IsUTF8 := False; HostOS := hosDOS; if AbTryEncode(Value, CP_OEMCP, False, AnsiName) then {no-op} else if (GetACP <> GetOEMCP) and AbTryEncode(Value, CP_ACP, False, AnsiName) then HostOS := hosWinNT else if AbTryEncode(Value, CP_OEMCP, True, AnsiName) then {no-op} else if (GetACP <> GetOEMCP) and AbTryEncode(Value, CP_ACP, True, AnsiName) then HostOS := hosWinNT else FItemInfo.IsUTF8 := True; if FItemInfo.IsUTF8 then FItemInfo.FileName := Utf8Encode(Value) else FItemInfo.FileName := AnsiName; {$ENDIF} {$IFDEF UNIX} FItemInfo.FileName := AnsiString(Value); FItemInfo.IsUTF8 := AbSysCharSetIsUTF8; {$ENDIF} UseExtraField := False; if not FItemInfo.IsUTF8 then for i := 1 to Length(Value) do begin if Ord(Value[i]) > 127 then begin UseExtraField := True; Break; end; end; if UseExtraField then begin UTF8Name := AnsiToUTF8(Value); FieldSize := SizeOf(TInfoZipUnicodePathRec) + Length(UTF8Name) - 1; GetMem(InfoZipField, FieldSize); try InfoZipField.Version := 1; InfoZipField.NameCRC32 := AbCRC32Of(FItemInfo.FileName); Move(UTF8Name[1], InfoZipField.UnicodeName, Length(UTF8Name)); FItemInfo.ExtraField.Put(Ab_InfoZipUnicodePathSubfieldID, InfoZipField^, FieldSize); finally FreeMem(InfoZipField); end; end else FItemInfo.ExtraField.Delete(Ab_InfoZipUnicodePathSubfieldID); FItemInfo.ExtraField.Delete(Ab_XceedUnicodePathSubfieldID); end; {$IFDEF OPTIMIZATIONS_ON}{$O+}{$ENDIF} { -------------------------------------------------------------------------- } procedure TAbZipItem.SetGeneralPurposeBitFlag( Value : Word ); begin FItemInfo.GeneralPurposeBitFlag := Value; UpdateVersionNeededToExtract; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.SetHostOS( Value : TAbZipHostOS ); begin FItemInfo.VersionMadeBy := Low(FItemInfo.VersionMadeBy) or Word(Ord(Value)) shl 8; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.SetInternalFileAttributes( Value : Word ); begin FItemInfo.InternalFileAttributes := Value; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.SetLastModFileDate( const Value : Word ); begin FItemInfo.LastModFileDate := Value; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.SetLastModFileTime( const Value : Word ); begin FItemInfo.LastModFileTime := Value; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.SetRelativeOffset( Value : Int64 ); begin FRelativeOffset := Value; FItemInfo.RelativeOffset := Min(Value, $FFFFFFFF); UpdateZip64ExtraHeader; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.SetUncompressedSize( const Value : Int64 ); begin FUncompressedSize := Value; FItemInfo.UncompressedSize:= Min(Value, $FFFFFFFF); UpdateZip64ExtraHeader; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.SetVersionMadeBy( Value : Word ); begin FItemInfo.VersionMadeBy := Value; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.SetVersionNeededToExtract( Value : Word ); begin FItemInfo.VersionNeededToExtract := Value; end; { -------------------------------------------------------------------------- } procedure TAbZipItem.UpdateVersionNeededToExtract; {calculates VersionNeededToExtract and VersionMadeBy based on used features} begin {According to AppNote.txt zipx compression methods should set the Version Needed To Extract to the AppNote version the method was introduced in (e.g., 6.3 for PPMd). Most utilities just set it to 2.0 and rely on the extractor detecting unsupported compression methods, since it's easier to add support for decompression methods without implementing the entire newer spec. } if ExtraField.Has(Ab_Zip64SubfieldID) then VersionNeededToExtract := 45 else if IsDirectory or IsEncrypted or not (CompressionMethod in [cmStored..cmImploded]) then VersionNeededToExtract := 20 else VersionNeededToExtract := 10; VersionMadeBy := (VersionMadeBy and $FF00) + Max(20, VersionNeededToExtract); end; { -------------------------------------------------------------------------- } procedure TAbZipItem.UpdateZip64ExtraHeader; var Changed: Boolean; FieldStream: TMemoryStream; begin FieldStream := TMemoryStream.Create; try if UncompressedSize >= $FFFFFFFF then FieldStream.WriteBuffer(FUncompressedSize, SizeOf(Int64)); if CompressedSize >= $FFFFFFFF then FieldStream.WriteBuffer(FCompressedSize, SizeOf(Int64)); if RelativeOffset >= $FFFFFFFF then FieldStream.WriteBuffer(FRelativeOffset, SizeOf(Int64)); if DiskNumberStart >= $FFFF then FieldStream.WriteBuffer(FDiskNumberStart, SizeOf(LongWord)); Changed := (FieldStream.Size > 0) <> ExtraField.Has(Ab_Zip64SubfieldID); if FieldStream.Size > 0 then ExtraField.Put(Ab_Zip64SubfieldID, FieldStream.Memory^, FieldStream.Size) else ExtraField.Delete(Ab_Zip64SubfieldID); if Changed then UpdateVersionNeededToExtract; finally FieldStream.Free; end; end; { -------------------------------------------------------------------------- } { TAbZipArchive implementation ============================================= } constructor TAbZipArchive.CreateFromStream( aStream : TStream; const ArchiveName : string ); begin inherited CreateFromStream( aStream, ArchiveName ); FCompressionMethodToUse := smBestMethod; FInfo := TAbZipDirectoryFileFooter.Create; StoreOptions := StoreOptions + [soStripDrive]; FDeflationOption := doNormal; FPasswordRetries := AbDefPasswordRetries; FTempDir := ''; SpanningThreshold := AbDefZipSpanningThreshold; end; { -------------------------------------------------------------------------- } destructor TAbZipArchive.Destroy; begin FInfo.Free; FInfo := nil; inherited Destroy; end; { -------------------------------------------------------------------------- } function TAbZipArchive.CreateItem( const FileName : string ): TAbArchiveItem; var FileSpec : string; begin FileSpec := FileName; Result := TAbZipItem.Create; with TAbZipItem( Result ) do begin CompressionMethod := cmDeflated; GeneralPurposeBitFlag := 0; CompressedSize := 0; CRC32 := 0; DiskFileName := ExpandFileName(FileSpec); FileName := FixName(FileSpec); RelativeOffset := 0; end; end; { -------------------------------------------------------------------------- } procedure TAbZipArchive.DoExtractHelper(Index : Integer; const NewName : string); begin if Assigned(FExtractHelper) then FExtractHelper(Self, ItemList[Index], NewName) else raise EAbZipNoExtraction.Create; end; { -------------------------------------------------------------------------- } procedure TAbZipArchive.DoExtractToStreamHelper(Index : Integer; aStream : TStream); begin if Assigned(FExtractToStreamHelper) then FExtractToStreamHelper(Self, ItemList[Index], aStream) else raise EAbZipNoExtraction.Create; end; { -------------------------------------------------------------------------- } procedure TAbZipArchive.DoTestHelper(Index : Integer); begin if Assigned(FTestHelper) then FTestHelper(Self, ItemList[Index]) else raise EAbZipNoExtraction.Create; end; { -------------------------------------------------------------------------- } procedure TAbZipArchive.DoInsertHelper(Index : Integer; OutStream : TStream); begin if Assigned(FInsertHelper) then FInsertHelper(Self, ItemList[Index], OutStream) else raise EAbZipNoInsertion.Create; end; { -------------------------------------------------------------------------- } procedure TAbZipArchive.DoInsertFromStreamHelper(Index : Integer; OutStream : TStream); begin if Assigned(FInsertFromStreamHelper) then FInsertFromStreamHelper(Self, ItemList[Index], OutStream, InStream) else raise EAbZipNoInsertion.Create; end; { -------------------------------------------------------------------------- } procedure TAbZipArchive.DoRequestDisk(const AMessage: string; var Abort : Boolean); begin {$IFDEF MSWINDOWS} Abort := Windows.MessageBox( 0, PChar(AMessage), PChar(AbDiskRequestS), MB_TASKMODAL or MB_OKCANCEL ) = IDCANCEL; {$ENDIF} {$IFDEF UnixDialogs} {$IFDEF KYLIX} Abort := QDialogs.MessageDlg(AbDiskRequestS, AMessage, mtWarning, mbOKCancel, 0) = mrCancel; {$ENDIF} {$IFDEF LCL} Abort := Dialogs.MessageDlg(AbDiskRequestS, AMessage, mtWarning, mbOKCancel, 0) = mrCancel; {$ENDIF} {$ELSE} Abort := True; {$ENDIF} end; { -------------------------------------------------------------------------- } procedure TAbZipArchive.DoRequestLastDisk( var Abort : Boolean ); begin Abort := False; if Assigned( FOnRequestLastDisk ) then FOnRequestLastDisk( Self, Abort ) else DoRequestDisk( AbLastDiskRequestS, Abort ); end; { -------------------------------------------------------------------------- } procedure TAbZipArchive.DoRequestNthDisk( Sender: TObject; DiskNumber : Byte; var Abort : Boolean ); begin Abort := False; if Assigned( FOnRequestNthDisk ) then FOnRequestNthDisk( Self, DiskNumber, Abort ) else DoRequestDisk( Format(AbDiskNumRequestS, [DiskNumber]), Abort ); end; { -------------------------------------------------------------------------- } procedure TAbZipArchive.DoRequestBlankDisk(Sender: TObject; var Abort : Boolean ); begin Abort := False; FSpanned := True; if Assigned( FOnRequestBlankDisk ) then FOnRequestBlankDisk( Self, Abort ) else DoRequestDisk( AbBlankDiskS, Abort ); end; { -------------------------------------------------------------------------- } procedure TAbZipArchive.DoRequestImage(Sender: TObject; ImageNumber : Integer; var ImageName : string ; var Abort : Boolean); begin if Assigned(FOnRequestImage) then FOnRequestImage(Self, ImageNumber, ImageName, Abort); end; { -------------------------------------------------------------------------- } procedure TAbZipArchive.ExtractItemAt(Index : Integer; const UseName : string); begin DoExtractHelper(Index, UseName); end; { -------------------------------------------------------------------------- } procedure TAbZipArchive.ExtractItemToStreamAt(Index : Integer; aStream : TStream); begin DoExtractToStreamHelper(Index, aStream); end; { -------------------------------------------------------------------------- } function TAbZipArchive.FixName(const Value : string ) : string; {-changes backslashes to forward slashes} var i : SmallInt; lValue : string; begin lValue := Value; {$IFDEF MSWINDOWS} if DOSMode then begin {Add the base directory to the filename before converting } {the file spec to the short filespec format. } if BaseDirectory <> '' then begin {Does the filename contain a drive or a leading backslash? } if not ((Pos(':', lValue) = 2) or (Pos(AbPathDelim, lValue) = 1)) then {If not, add the BaseDirectory to the filename.} lValue := AbAddBackSlash(BaseDirectory) + lValue; end; lValue := AbGetShortFileSpec( lValue ); end; {$ENDIF MSWINDOWS} {Zip files Always strip the drive path} StoreOptions := StoreOptions + [soStripDrive]; {strip drive stuff} if soStripDrive in StoreOptions then AbStripDrive( lValue ); {check for a leading backslash} if (Length(lValue) > 1) and (lValue[1] = AbPathDelim) then System.Delete( lValue, 1, 1 ); if soStripPath in StoreOptions then begin lValue := ExtractFileName( lValue ); end; if soRemoveDots in StoreOptions then AbStripDots( lValue ); for i := 1 to Length( lValue ) do if lValue[i] = '\' then lValue[i] := '/'; Result := lValue; end; { -------------------------------------------------------------------------- } function TAbZipArchive.GetItem( Index : Integer ) : TAbZipItem; begin Result := TAbZipItem(FItemList.Items[Index]); end; { -------------------------------------------------------------------------- } function TAbZipArchive.GetSupportsEmptyFolders: Boolean; begin Result := True; end; { -------------------------------------------------------------------------- } function TAbZipArchive.GetZipfileComment : AnsiString; begin Result := FInfo.ZipfileComment; end; { -------------------------------------------------------------------------- } procedure TAbZipArchive.LoadArchive; var Abort : Boolean; TailPosition : int64; Item : TAbZipItem; Progress : Byte; FileSignature : Longint; Zip64Locator : TAbZip64EndOfCentralDirectoryLocator; begin Abort := False; if FStream.Size = 0 then Exit; {Get signature info} FStream.Position := 0; FStream.Read( FileSignature, sizeof( FileSignature ) ); {Get Executable Type; allow non-native stubs} IsExecutable := (LongRec(FileSignature).Lo = Ab_WindowsExeSignature) or (FileSignature = Ab_LinuxExeSignature); { try to locate central directory tail } TailPosition := FindCentralDirectoryTail( FStream ); if (TailPosition = -1) and (FileSignature = Ab_ZipSpannedSetSignature) and FOwnsStream and AbDriveIsRemovable(ArchiveName) then begin while TailPosition = -1 do begin FreeAndNil(FStream); DoRequestLastDisk(Abort); if Abort then begin FStatus := asInvalid; //TODO: Status updates are extremely inconsistent raise EAbUserAbort.Create; end; FStream := TFileStream.Create( ArchiveName, Mode ); TailPosition := FindCentralDirectoryTail( FStream ); end; end; if TailPosition = -1 then begin FStatus := asInvalid; raise EAbZipInvalid.Create; end; { load the ZipDirectoryFileFooter } FInfo.LoadFromStream(FStream); { find Zip64 end of central directory locator; it will usually occur immediately before the standard end of central directory record. the actual Zip64 end of central directory may be on another disk } if FInfo.IsZip64 then begin Dec(TailPosition, SizeOf(Zip64Locator)); repeat if TailPosition < 0 then raise EAbZipInvalid.Create; FStream.Position := TailPosition; FStream.ReadBuffer(Zip64Locator, SizeOf(Zip64Locator)); Dec(TailPosition); until Zip64Locator.Signature = Ab_Zip64EndCentralDirectoryLocatorSignature; { update current image number } FInfo.DiskNumber := Zip64Locator.TotalDisks - 1; end; { setup spanning support and move to the start of the central directory } FSpanned := FInfo.DiskNumber > 0; if FSpanned then begin if FOwnsStream then begin FStream := TAbSpanReadStream.Create( ArchiveName, FInfo.DiskNumber, FStream ); TAbSpanReadStream(FStream).OnRequestImage := DoRequestImage; TAbSpanReadStream(FStream).OnRequestNthDisk := DoRequestNthDisk; if FInfo.IsZip64 then begin TAbSpanReadStream(FStream).SeekImage(Zip64Locator.StartDiskNumber, Zip64Locator.RelativeOffset); FInfo.LoadZip64FromStream(FStream); end; TAbSpanReadStream(FStream).SeekImage(FInfo.StartDiskNumber, FInfo.DirectoryOffset); end else raise EAbZipBadSpanStream.Create; end else begin if FInfo.IsZip64 then begin FStream.Position := Zip64Locator.RelativeOffset; FInfo.LoadZip64FromStream(FStream); end; FStream.Position := FInfo.DirectoryOffset; end; { build Items list from central directory records } FStubSize := High(LongWord); while Count < FInfo.TotalEntries do begin { create new Item } Item := TAbZipItem.Create; try Item.LoadFromStream(FStream); Item.Action := aaNone; FItemList.Add(Item); except Item.Free; raise; end; if IsExecutable and (Item.DiskNumberStart = 0) and (Item.RelativeOffset < FStubSize) then FStubSize := Item.RelativeOffset; Progress := (Count * 100) div FInfo.TotalEntries; DoArchiveProgress( Progress, Abort ); if Abort then begin FStatus := asInvalid; raise EAbUserAbort.Create; end; end; DoArchiveProgress(100, Abort); FIsDirty := False; end; { -------------------------------------------------------------------------- } procedure TAbZipArchive.PutItem( Index : Integer; Value : TAbZipItem ); begin FItemList.Items[Index] := Value; end; { -------------------------------------------------------------------------- } procedure TAbZipArchive.SaveArchive; {builds a new archive and copies it to FStream} var Abort : Boolean; MemStream : TMemoryStream; HasDataDescriptor : Boolean; i : LongWord; LFH : TAbZipLocalFileHeader; NewStream : TStream; WorkingStream : TAbVirtualMemoryStream; CurrItem : TAbZipItem; Progress : Byte; begin if Count = 0 then Exit; {shouldn't be trying to overwrite an existing spanned archive} if Spanned then begin for i := 0 to Pred(Count) do if ItemList[i].Action <> aaFailed then ItemList[i].Action := aaNone; FIsDirty := False; raise EAbZipSpanOverwrite.Create; end; {init new zip archive stream can span only new archives, if SpanningThreshold > 0 or removable drive spanning writes to original location, rather than writing to a temp stream first} if FOwnsStream and (FStream.Size = 0) and not IsExecutable and ((SpanningThreshold > 0) or AbDriveIsRemovable(ArchiveName)) then begin NewStream := TAbSpanWriteStream.Create(ArchiveName, FStream, SpanningThreshold); FStream := nil; TAbSpanWriteStream(NewStream).OnRequestBlankDisk := DoRequestBlankDisk; TAbSpanWriteStream(NewStream).OnRequestImage := DoRequestImage; end else begin NewStream := TAbVirtualMemoryStream.Create; TAbVirtualMemoryStream(NewStream).SwapFileDirectory := FTempDir; end; try {NewStream} {copy the executable stub over to the output} if IsExecutable then NewStream.CopyFrom( FStream, StubSize ) {assume spanned for spanning stream} else if NewStream is TAbSpanWriteStream then NewStream.Write(Ab_ZipSpannedSetSignature, SizeOf(Ab_ZipSpannedSetSignature)); {build new zip archive from existing archive} for i := 0 to pred( Count ) do begin CurrItem := (ItemList[i] as TAbZipItem); FCurrentItem := ItemList[i]; case CurrItem.Action of aaNone, aaMove: begin {just copy the file to new stream} Assert(not (NewStream is TAbSpanWriteStream)); FStream.Position := CurrItem.RelativeOffset; CurrItem.DiskNumberStart := 0; CurrItem.RelativeOffset := NewStream.Position; {toss old local file header} LFH := TAbZipLocalFileHeader.Create; try {LFH} LFH.LoadFromStream( FStream ); if CurrItem.LFHExtraField.Count = 0 then CurrItem.LFHExtraField.Assign(LFH.ExtraField); finally {LFH} LFH.Free; end; {LFH} {write out new local file header and append compressed data} CurrItem.SaveLFHToStream( NewStream ); if (CurrItem.CompressedSize > 0) then NewStream.CopyFrom(FStream, CurrItem.CompressedSize); end; aaDelete: begin {doing nothing omits file from new stream} end; aaAdd, aaFreshen, aaReplace, aaStreamAdd: begin {compress the file and add it to new stream} try WorkingStream := TAbVirtualMemoryStream.Create; try {WorkingStream} WorkingStream.SwapFileDirectory := FTempDir; {compress the file} if (CurrItem.Action = aaStreamAdd) then DoInsertFromStreamHelper(i, WorkingStream) else DoInsertHelper(i, WorkingStream); {write local header} if NewStream is TAbSpanWriteStream then begin MemStream := TMemoryStream.Create; try CurrItem.SaveLFHToStream(MemStream); TAbSpanWriteStream(NewStream).WriteUnspanned( MemStream.Memory^, MemStream.Size); {calculate positions after the write in case it triggered a new span} CurrItem.DiskNumberStart := TAbSpanWriteStream(NewStream).CurrentImage; CurrItem.RelativeOffset := NewStream.Position - MemStream.Size; finally MemStream.Free; end; end else begin CurrItem.DiskNumberStart := 0; CurrItem.RelativeOffset := NewStream.Position; CurrItem.SaveLFHToStream(NewStream); end; {copy compressed data} NewStream.CopyFrom(WorkingStream, 0); if CurrItem.IsEncrypted then CurrItem.SaveDDToStream(NewStream); finally WorkingStream.Free; end; except on E : Exception do begin { Exception was caused by a User Abort and Item Failure should not be called Question: Do we want an New Event when this occurs or should the exception just be re-raised [783614] } if (E is EAbUserAbort) then raise; CurrItem.Action := aaDelete; DoProcessItemFailure(CurrItem, ptAdd, ecFileOpenError, 0); end; end; end; end; { case } { TODO: Check HasDataDescriptior behavior; seems like it's getting written twice for encrypted files } {Now add the data descriptor record to new stream} HasDataDescriptor := (CurrItem.CompressionMethod = cmDeflated) and ((CurrItem.GeneralPurposeBitFlag and AbHasDataDescriptorFlag) <> 0); if (CurrItem.Action <> aaDelete) and HasDataDescriptor then CurrItem.SaveDDToStream(NewStream); Progress := AbPercentage(9 * succ( i ), 10 * Count); DoArchiveSaveProgress(Progress, Abort); DoArchiveProgress(Progress, Abort); if Abort then raise EAbUserAbort.Create; end; {write the central directory} if NewStream is TAbSpanWriteStream then FInfo.DiskNumber := TAbSpanWriteStream(NewStream).CurrentImage else FInfo.DiskNumber := 0; FInfo.StartDiskNumber := FInfo.DiskNumber; FInfo.DirectoryOffset := NewStream.Position; FInfo.DirectorySize := 0; FInfo.EntriesOnDisk := 0; FInfo.TotalEntries := 0; MemStream := TMemoryStream.Create; try {write central directory entries} for i := 0 to Count - 1 do begin if not (FItemList[i].Action in [aaDelete, aaFailed]) then begin (FItemList[i] as TAbZipItem).SaveCDHToStream(MemStream); if NewStream is TAbSpanWriteStream then begin TAbSpanWriteStream(NewStream).WriteUnspanned(MemStream.Memory^, MemStream.Size); {update tail info on span change} if FInfo.DiskNumber <> TAbSpanWriteStream(NewStream).CurrentImage then begin FInfo.DiskNumber := TAbSpanWriteStream(NewStream).CurrentImage; FInfo.EntriesOnDisk := 0; if FInfo.TotalEntries = 0 then begin FInfo.StartDiskNumber := FInfo.DiskNumber; FInfo.DirectoryOffset := NewStream.Position - MemStream.Size; end; end; end else NewStream.WriteBuffer(MemStream.Memory^, MemStream.Size); FInfo.DirectorySize := FInfo.DirectorySize + MemStream.Size; FInfo.EntriesOnDisk := FInfo.EntriesOnDisk + 1; FInfo.TotalEntries := FInfo.TotalEntries + 1; MemStream.Clear; end; end; {append the central directory footer} FInfo.SaveToStream(MemStream, NewStream.Position); if NewStream is TAbSpanWriteStream then begin {update the footer if writing it would trigger a new span} if not TAbSpanWriteStream(NewStream).WriteUnspanned(MemStream.Memory^, MemStream.Size) then begin FInfo.DiskNumber := TAbSpanWriteStream(NewStream).CurrentImage; FInfo.EntriesOnDisk := 0; FInfo.SaveToStream(NewStream); end; end else NewStream.WriteBuffer(MemStream.Memory^, MemStream.Size); finally {MemStream} MemStream.Free; end; {MemStream} FSpanned := (FInfo.DiskNumber > 0); {update output stream} if NewStream is TAbSpanWriteStream then begin {zip has already been written to target location} FStream := TAbSpanWriteStream(NewStream).ReleaseStream; if Spanned then begin {switch to read stream} FStream := TAbSpanReadStream.Create(ArchiveName, FInfo.DiskNumber, FStream); TAbSpanReadStream(FStream).OnRequestImage := DoRequestImage; TAbSpanReadStream(FStream).OnRequestNthDisk := DoRequestNthDisk; end else begin {replace spanned signature} FStream.Position := 0; FStream.Write(Ab_ZipPossiblySpannedSignature, SizeOf(Ab_ZipPossiblySpannedSignature)); end; end else begin {copy new stream to FStream (non-spanned only)} NewStream.Position := 0; if (FStream is TMemoryStream) then TMemoryStream(FStream).LoadFromStream(NewStream) else begin if FOwnsStream then begin {need new stream to write} FreeAndNil(FStream); FStream := TFileStream.Create(FArchiveName, fmOpenReadWrite or fmShareDenyWrite); end; FStream.Size := 0; FStream.Position := 0; FStream.CopyFrom(NewStream, 0) end; end; {update Items list} for i := pred( Count ) downto 0 do begin if FItemList[i].Action = aaDelete then FItemList.Delete( i ) else if FItemList[i].Action <> aaFailed then FItemList[i].Action := aaNone; end; DoArchiveSaveProgress( 100, Abort ); DoArchiveProgress( 100, Abort ); finally {NewStream} NewStream.Free; end; end; { -------------------------------------------------------------------------- } procedure TAbZipArchive.SetZipfileComment(const Value : AnsiString ); begin FInfo.FZipfileComment := Value; FIsDirty := True; end; { -------------------------------------------------------------------------- } procedure TAbZipArchive.TestItemAt(Index : Integer); begin DoTestHelper(Index); end; end. ================================================ FILE: lib/abbrevia/source/AbZipper.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) {*********************************************************} {* ABBREVIA: AbZipper.pas *} {*********************************************************} {* ABBREVIA: Non-visual Component with Zip support *} {*********************************************************} unit AbZipper; {$I AbDefine.inc} interface uses Classes, AbBrowse, AbZBrows, AbArcTyp, AbZipTyp; type TAbCustomZipper = class(TAbCustomZipBrowser) protected {private} FAutoSave : Boolean; FCompressionMethodToUse : TAbZipSupportedMethod; FDeflationOption : TAbZipDeflationOption; FDOSMode : Boolean; FOnConfirmSave : TAbArchiveConfirmEvent; FOnSave : TAbArchiveEvent; FOnArchiveSaveProgress : TAbArchiveProgressEvent; FArchiveSaveProgressMeter : IAbProgressMeter; FStoreOptions : TAbStoreOptions; protected {methods} procedure DoConfirmSave(Sender : TObject; var Confirm : Boolean); virtual; procedure DoSave(Sender : TObject); virtual; procedure DoArchiveSaveProgress(Sender : TObject; Progress : Byte; var Abort : Boolean); procedure InitArchive; override; procedure SetAutoSave(Value : Boolean); procedure SetCompressionMethodToUse(Value : TAbZipSupportedMethod); procedure SetDeflationOption(Value : TAbZipDeflationOption); procedure SetDOSMode( Value : Boolean ); procedure SetFileName(const aFileName : string); override; procedure SetStoreOptions( Value : TAbStoreOptions ); procedure SetArchiveSaveProgressMeter(const Value: IAbProgressMeter); procedure SetZipfileComment(const Value : AnsiString); override; procedure ZipProc(Sender : TObject; Item : TAbArchiveItem; OutStream : TStream); procedure ZipFromStreamProc(Sender : TObject; Item : TAbArchiveItem; OutStream, InStream : TStream ); procedure Notification(Component: TComponent; Operation: TOperation); override; procedure ResetMeters; override; protected {properties} property AutoSave : Boolean read FAutoSave write SetAutoSave; property CompressionMethodToUse : TAbZipSupportedMethod read FCompressionMethodToUse write SetCompressionMethodToUse default AbDefCompressionMethodToUse; property DeflationOption : TAbZipDeflationOption read FDeflationOption write SetDeflationOption default AbDefDeflationOption; property DOSMode : Boolean read FDOSMode write SetDOSMode; property StoreOptions : TAbStoreOptions read FStoreOptions write SetStoreOptions default AbDefStoreOptions; property ArchiveSaveProgressMeter : IAbProgressMeter read FArchiveSaveProgressMeter write SetArchiveSaveProgressMeter; protected {events} property OnConfirmSave : TAbArchiveConfirmEvent read FOnConfirmSave write FOnConfirmSave; property OnSave : TAbArchiveEvent read FOnSave write FOnSave; property OnArchiveSaveProgress : TAbArchiveProgressEvent read FOnArchiveSaveProgress write FOnArchiveSaveProgress; public {methods} constructor Create(AOwner : TComponent); override; destructor Destroy; override; procedure AddFiles(const FileMask : string; SearchAttr : Integer); procedure AddFilesEx(const FileMask, ExclusionMask : string; SearchAttr : Integer); procedure AddFromStream(const NewName : string; FromStream : TStream); procedure DeleteAt(Index : Integer); procedure DeleteFiles(const FileMask : string); procedure DeleteFilesEx(const FileMask, ExclusionMask : string); procedure DeleteTaggedItems; procedure FreshenFiles(const FileMask : string); procedure FreshenFilesEx(const FileMask, ExclusionMask : string); procedure FreshenTaggedItems; procedure Move(aItem : TAbArchiveItem; const NewStoredPath : string); procedure Save; procedure Replace(aItem : TAbArchiveItem); end; type TAbZipper = class(TAbCustomZipper) published property ArchiveProgressMeter; property ArchiveSaveProgressMeter; property ItemProgressMeter; property AutoSave; property BaseDirectory; property CompressionMethodToUse; property DeflationOption; property DOSMode; property SpanningThreshold; property LogFile; property Logging; property OnArchiveProgress; property OnArchiveSaveProgress; property OnArchiveItemProgress; property OnChange; property OnConfirmProcessItem; property OnConfirmSave; property OnLoad; property OnProcessItemFailure; property OnRequestBlankDisk; property OnRequestImage; property OnRequestLastDisk; property OnRequestNthDisk; property OnSave; property Password; property StoreOptions; property TempDirectory; property Version; property FileName; {must be after OnLoad} end; implementation uses SysUtils, AbUtils, AbTarTyp, AbGzTyp, AbBzip2Typ, AbExcept, AbZipPrc; { -------------------------------------------------------------------------- } constructor TAbCustomZipper.Create( AOwner : TComponent ); begin inherited Create( AOwner ); CompressionMethodToUse := AbDefCompressionMethodToUse; DeflationOption := AbDefDeflationOption; StoreOptions := AbDefStoreOptions; end; { -------------------------------------------------------------------------- } destructor TAbCustomZipper.Destroy; begin inherited Destroy; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.AddFiles(const FileMask : string; SearchAttr : Integer); {Add files to the archive where the disk filespec matches} begin if (FArchive <> nil) then FArchive.AddFiles(FileMask, SearchAttr) else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.AddFilesEx(const FileMask, ExclusionMask : string; SearchAttr : Integer); {Add files that match Filemask except those matching ExclusionMask} begin if (FArchive <> nil) then FArchive.AddFilesEx(FileMask, ExclusionMask, SearchAttr) else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.AddFromStream(const NewName : string; FromStream : TStream); {Add stream directly to archive} begin if (FArchive <> nil) then begin FromStream.Position := 0; FArchive.AddFromStream(NewName, FromStream); end else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.DeleteFiles(const FileMask : string); {delete all files from the archive that match the file mask} begin if (FArchive <> nil) then FArchive.DeleteFiles( FileMask ) else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.DeleteAt(Index : Integer); {delete item at Index} begin if (FArchive <> nil) then FArchive.DeleteAt( Index ) else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.DeleteFilesEx(const FileMask, ExclusionMask : string); {Delete files that match Filemask except those matching ExclusionMask} begin if (FArchive <> nil) then FArchive.DeleteFilesEx(FileMask, ExclusionMask) else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.DeleteTaggedItems; {delete all tagged items from the archive} begin if (FArchive <> nil) then FArchive.DeleteTaggedItems else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.DoConfirmSave(Sender : TObject; var Confirm : Boolean); begin Confirm := True; if Assigned(FOnConfirmSave) then FOnConfirmSave(Self, Confirm); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.DoSave(Sender : TObject); begin if Assigned(FOnSave) then FOnSave(Self); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.FreshenFiles(const FileMask : string); {freshen all items that match the file mask} begin if (FArchive <> nil) then FArchive.FreshenFiles( FileMask ) else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.FreshenFilesEx(const FileMask, ExclusionMask : string); {freshen all items matching FileMask except those matching ExclusionMask} begin if (FArchive <> nil) then FArchive.FreshenFilesEx( FileMask, ExclusionMask ) else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.FreshenTaggedItems; {freshen all tagged items} begin if (FArchive <> nil) then FArchive.FreshenTaggedItems else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.InitArchive; begin inherited InitArchive; if FArchive <> nil then begin {properties} FArchive.AutoSave := FAutoSave; FArchive.DOSMode := FDOSMode; FArchive.StoreOptions := FStoreOptions; {events} FArchive.OnArchiveSaveProgress := DoArchiveSaveProgress; FArchive.OnConfirmSave := DoConfirmSave; FArchive.OnSave := DoSave; end; if (FArchive is TAbZipArchive) then begin {properties} TAbZipArchive(FArchive).CompressionMethodToUse := FCompressionMethodToUse; TAbZipArchive(FArchive).DeflationOption := FDeflationOption; {events} TAbZipArchive(FArchive).OnRequestBlankDisk := OnRequestBlankDisk; TAbZipArchive(FArchive).InsertHelper := ZipProc; TAbZipArchive(FArchive).InsertFromStreamHelper := ZipFromStreamProc; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.Move(aItem : TAbArchiveItem; const NewStoredPath : string); {renames the item} begin if (FArchive <> nil) then FArchive.Move(aItem, NewStoredPath) else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.Replace(aItem : TAbArchiveItem); {replace the item} begin if (FArchive <> nil) then FArchive.Replace( aItem ) else raise EAbNoArchive.Create; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.Save; begin if (FArchive <> nil) then begin FArchive.Save; DoChange; end; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.SetAutoSave(Value : Boolean); begin FAutoSave := Value; if (FArchive <> nil) then FArchive.AutoSave := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.SetCompressionMethodToUse( Value : TAbZipSupportedMethod); begin FCompressionMethodToUse := Value; if (FArchive is TAbZipArchive) then TAbZipArchive(FArchive).CompressionMethodToUse := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.SetDeflationOption(Value : TAbZipDeflationOption); begin FDeflationOption := Value; if (FArchive is TAbZipArchive) then TAbZipArchive(FArchive).DeflationOption := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.SetDOSMode(Value : Boolean); begin FDOSMode := Value; if (FArchive <> nil) then FArchive.DOSMode := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.SetFileName(const aFileName : string); var ArcType : TAbArchiveType; begin FFileName := aFileName; if (csDesigning in ComponentState) then Exit; if Assigned(FArchive) then begin FArchive.Save; FreeAndNil(FArchive); end; ArcType := ArchiveType; if (FileName <> '') then if FileExists(FileName) then begin { open it } if not ForceType then ArcType := AbDetermineArcType(FileName, atUnknown); case ArcType of atZip, atSpannedZip, atSelfExtZip : begin FArchive := TAbZipArchive.Create(FileName, fmOpenRead or fmShareDenyNone); InitArchive; end; atTar : begin FArchive := TAbTarArchive.Create(FileName, fmOpenReadWrite or fmShareDenyNone); inherited InitArchive; end; atGZip : begin FArchive := TAbGzipArchive.Create(FileName, fmOpenReadWrite or fmShareDenyNone); TAbGzipArchive(FArchive).TarAutoHandle := FTarAutoHandle; TAbGzipArchive(FArchive).IsGzippedTar := False; inherited InitArchive; end; atGZippedTar : begin FArchive := TAbGzipArchive.Create(FileName, fmOpenReadWrite or fmShareDenyNone); TAbGzipArchive(FArchive).TarAutoHandle := FTarAutoHandle; TAbGzipArchive(FArchive).IsGzippedTar := True; inherited InitArchive; end; atBzip2 : begin FArchive := TAbBzip2Archive.Create(FileName, fmOpenReadWrite or fmShareDenyNone); TAbBzip2Archive(FArchive).TarAutoHandle := FTarAutoHandle; TAbBzip2Archive(FArchive).IsBzippedTar := False; inherited InitArchive; end; atBzippedTar : begin FArchive := TAbBzip2Archive.Create(FileName, fmOpenReadWrite or fmShareDenyNone); TAbBzip2Archive(FArchive).TarAutoHandle := FTarAutoHandle; TAbBzip2Archive(FArchive).IsBzippedTar := True; inherited InitArchive; end; else raise EAbUnhandledType.Create; end {case}; FArchive.Load; FArchiveType := ArcType; end else begin { file doesn't exist, so create a new one } if not ForceType then ArcType := AbDetermineArcType(FileName, atUnknown); case ArcType of atZip : begin FArchive := TAbZipArchive.Create(FileName, fmCreate); InitArchive; end; atTar : begin FArchive := TAbTarArchive.Create(FileName, fmCreate or fmShareDenyNone); inherited InitArchive; end; atGZip : begin FArchive := TAbGzipArchive.Create(FileName, fmCreate or fmShareDenyNone); TAbGzipArchive(FArchive).TarAutoHandle := FTarAutoHandle; TAbGzipArchive(FArchive).IsGzippedTar := False; inherited InitArchive; end; atGZippedTar : begin FArchive := TAbGzipArchive.Create(FileName, fmCreate or fmShareDenyNone); TAbGzipArchive(FArchive).TarAutoHandle := FTarAutoHandle; TAbGzipArchive(FArchive).IsGzippedTar := True; inherited InitArchive; end; atBzip2 : begin FArchive := TAbBzip2Archive.Create(FileName, fmCreate or fmShareDenyNone); TAbBzip2Archive(FArchive).TarAutoHandle := FTarAutoHandle; TAbBzip2Archive(FArchive).IsBzippedTar := False; inherited InitArchive; end; atBzippedTar : begin FArchive := TAbBzip2Archive.Create(FileName, fmCreate or fmShareDenyNone); TAbBzip2Archive(FArchive).TarAutoHandle := FTarAutoHandle; TAbBzip2Archive(FArchive).IsBzippedTar := True; inherited InitArchive; end; else raise EAbUnhandledType.Create; end {case}; FArchiveType := ArcType; end; DoChange; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.SetStoreOptions(Value : TAbStoreOptions); begin FStoreOptions := Value; if (FArchive <> nil) then FArchive.StoreOptions := Value; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.SetArchiveSaveProgressMeter(const Value: IAbProgressMeter); begin ReferenceInterface(FArchiveSaveProgressMeter, opRemove); FArchiveSaveProgressMeter := Value; ReferenceInterface(FArchiveSaveProgressMeter, opInsert); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.SetZipfileComment(const Value : AnsiString); begin if (FArchive is TAbZipArchive) then TAbZipArchive(FArchive).ZipfileComment := Value else raise EAbNoArchive.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.ZipProc(Sender : TObject; Item : TAbArchiveItem; OutStream : TStream); begin AbZip(TAbZipArchive(Sender), TAbZipItem(Item), OutStream); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.ZipFromStreamProc(Sender : TObject; Item : TAbArchiveItem; OutStream, InStream : TStream); begin if Assigned(InStream) then AbZipFromStream(TAbZipArchive(Sender), TAbZipItem(Item), OutStream, InStream) else raise EAbZipNoInsertion.Create; end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.DoArchiveSaveProgress(Sender : TObject; Progress : Byte; var Abort : Boolean); begin Abort := False; if Assigned(FArchiveSaveProgressMeter) then FArchiveSaveProgressMeter.DoProgress(Progress); if Assigned(FOnArchiveSaveProgress) then FOnArchiveSaveProgress(Self, Progress, Abort); end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.Notification(Component: TComponent; Operation: TOperation); begin inherited Notification(Component, Operation); if (Operation = opRemove) then if Assigned(ArchiveSaveProgressMeter) and Component.IsImplementorOf(ArchiveSaveProgressMeter) then ArchiveSaveProgressMeter := nil end; { -------------------------------------------------------------------------- } procedure TAbCustomZipper.ResetMeters; begin inherited ResetMeters; if Assigned(FArchiveSaveProgressMeter) then FArchiveSaveProgressMeter.Reset; end; { -------------------------------------------------------------------------- } end. ================================================ FILE: lib/abbrevia/source/COM/Abbrevia.dpr ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) library Abbrevia; uses ComServ, _ZipKit in '_ZipKit.pas', _ZipItem in '_ZipItem.pas', _GZipItem in '_GZipItem.pas', _TarItem in '_TarItem.pas', Abbrevia_TLB in 'Abbrevia_TLB.pas'; exports DllGetClassObject, DllCanUnloadNow, DllRegisterServer, DllUnregisterServer, DllInstall; {$R *.TLB} {$R *.RES} begin end. ================================================ FILE: lib/abbrevia/source/COM/Abbrevia.dproj ================================================  {EDA07E3C-7B07-4B14-9B53-64A70EF3F00A} Abbrevia.dpr True Release 3 Library None 13.4 Win32 true true Base true true Base true true Base true true Cfg_1 true true true Cfg_1 true true true Base true true Cfg_2 true true true Cfg_2 true true .\$(Platform) ..\;$(DCC_UnitSearchPath) None true 5 1033 false CompanyName=;FileDescription=Abbrevia COM components;FileVersion=5.0.0.0;InternalName=;LegalCopyright=Copyright (c) Abbrevia Group 2011;LegalTrademarks=;OriginalFilename=;ProductName=Abbrevia;ProductVersion=5.0;Comments= System;Xml;Data;Datasnap;Web;Soap;System.Win;Winapi;Vcl;$(DCC_Namespace) 00400000 false true false false false Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;$(DCC_Namespace) CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= Abbrevia_Icon.ico /i:user /n Abbrevia.dll C:\Windows\System32\regsvr32.exe Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace) CompanyName=;FileDescription=;FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= false false 0 RELEASE;$(DCC_Define) CompanyName=;FileDescription=Abbrevia COM components;FileVersion=5.0;InternalName=;LegalCopyright=Copyright (c) 2011 Abbrevia Group;LegalTrademarks=;OriginalFilename=Abbrevia.dll;ProductName=Abbrevia;ProductVersion=5.0;Comments=http://tpabbrevia.sourceforge.net/ CompanyName=;FileDescription=Abbrevia COM components;FileVersion=5.0;InternalName=;LegalCopyright=Copyright (c) 2011 Abbrevia Group;LegalTrademarks=;OriginalFilename=Abbrevia.dll;ProductName=Abbrevia;ProductVersion=5.0;Comments=http://tpabbrevia.sourceforge.net/ DEBUG;$(DCC_Define) false true true true CompanyName=;FileDescription=;FileVersion=5.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProductName=;ProductVersion=1.0.0.0;Comments= MainSource Cfg_2 Base Base Cfg_1 Base Delphi.Personality.12 Abbrevia.dpr False False 1 0 0 0 False False False False False 1033 1252 1.0.0.0 1.0.0.0 True False True 1 12 ================================================ FILE: lib/abbrevia/source/COM/Abbrevia.ridl ================================================ // ************************************************************************ // // WARNING // ------- // This file is generated by the Type Library importer or Type Libary Editor. // Barring syntax errors, the Editor will parse modifications made to the file. // However, when applying changes via the Editor this file will be regenerated // and comments or formatting changes will be lost. // ************************************************************************ // // File generated on 12/6/2011 11:22:23 AM (- $Rev: 12980 $, 51698824). [ uuid(AF804E20-4043-499E-BB14-237B9F26F89F), version(3.0), helpstring("TurboPower Abbrevia Compression Library v3.03"), helpfile("C:\\Abbrevia\\COM\\abrv-com.hlp"), helpcontext(0x00000001) ] library Abbrevia { importlib("stdole2.tlb"); interface IZipItem; interface IGZipItem; interface ITarItem; interface IZipKit; dispinterface IZipKitEvents; coclass ZipItem; coclass GZipItem; coclass TarItem; coclass ZipKit; [ uuid(6CABD61B-653C-4CEB-807C-C80E8DE8163D), version(3.0) ] enum TArchiveAction { aaFailed = 0, aaNone = 1, aaAdd = 2, aaDelete = 3, aaFreshen = 4, aaMove = 5, aaStreamAdd = 6 }; [ uuid(148F84A1-2B70-4A63-B561-FF0EE49E74B3), version(3.0) ] enum TArchiveStatus { asInvalid = 0, asIdle = 1, asBusy = 2 }; [ uuid(5D495174-DB09-4C59-A26D-FEBDE3EAE100), version(3.0) ] enum TErrorClass { eclAbbrevia = 0, eclInOutError = 1, eclFileError = 2, eclFileCreateError = 3, eclFileOpenError = 4, eclOther = 5 }; [ uuid(6A4738B9-69F1-4717-8393-681FF21E8DB7), version(3.0) ] enum TFileAttributes { faReadOnly = 1, faHidden = 2, faSysFile = 4, faVolumeID = 8, faDirectory = 16, faArchive = 32 }; [ uuid(F77BBE04-0859-4F18-9DEA-B2887C1F6AF7), version(3.0) ] enum TProcessType { ptAdd = 0, ptDelete = 1, ptExtract = 2, ptFreshen = 3, ptMove = 4, ptReplace = 5 }; [ uuid(D78287A7-65FA-4391-8F5A-C7D3A11E9970), version(3.0) ] enum TStoreOptions { soStripDrive = 1, soStripPath = 2, soRemoveDots = 4, soRecurse = 8, soFreshen = 16, soReplace = 32 }; [ uuid(192C6697-A38D-4F48-B32B-F33500460E62), version(3.0) ] enum TZipCompressionMethod { cmStored = 0, cmShrunk = 1, cmReduced1 = 2, cmReduced2 = 3, cmReduced3 = 4, cmReduced4 = 5, cmImploded = 6, cmTokenized = 7, cmDeflated = 8, cmEnhancedDeflated = 9, cmDCLImploded = 10, cmBestMethod = 11 }; [ uuid(800F8CDC-2F0F-4020-BCBB-FEDA82D0EFEF), version(3.0) ] enum TZipDeflateOption { doInvalid = 0, doNormal = 1, doMaximum = 2, doFast = 3, doSuperFast = 4 }; [ uuid(D697ED2A-F088-409F-962A-57D8324EEDD6), version(3.0) ] enum TZipDictionarySize { dsInvalid = 0, ds4K = 1, ds8K = 2 }; [ uuid(B9889806-26F9-47E7-AC1F-906AA161B078), version(3.0) ] enum TZipExtractOptions { eoCreateDirs = 0, eoRestorePath = 1 }; [ uuid(D40E0708-AE71-4A44-A6C8-430EDF760DE2), version(3.0) ] enum TZipSupportMethod { smStored = 0, smDeflated = 1, smBestMethod = 2 }; [ uuid(EFD2C909-BF04-4C54-9ACB-38D872B95C9F), version(3.0) ] enum TErrorCode { ecDuplicateName = 0, ecInvalidPassword = 1, ecNoSuchDirectory = 2, ecUnknownCompressionMethod = 3, ecUserAbort = 4, ecZipBadCRC = 5, ecZipVersionNumber = 6, ecSpannedItemNotFound = 7 }; [ uuid(44EB05F9-CED9-46D0-84E2-BD3362977437), version(3.0) ] enum TArchiveType { atUnknown = 0, atZip = 1, atSelfExtZip = 2, atTar = 3, atGZip = 4, atGZippedTar = 5, atCab = 6 }; [ uuid(36568A72-3B4B-41C4-8E34-19931A8EAF63), version(3.0) ] enum TFileSystem { fsFAT = 0, fsAmiga = 1, fsVMS = 2, fsUnix = 3, fsVM_CMS = 4, fsAtariTOS = 5, fsHPFS = 6, fsMacintosh = 7, fsZSystem = 8, fsCP_M = 9, fsTOPS20 = 10, fsNTFS = 11, fsQDOS = 12, fsAcornRISCOS = 13, fsUnknown = 14, fsUndefined = 15 }; [ uuid(851699A1-422A-4C65-8E08-D0499ACDD834), version(3.0), helpstring("Dispatch interface for ZipItem Object"), helpcontext(0x00000005), dual, oleautomation ] interface IZipItem: IDispatch { [propget, id(0x00000001)] HRESULT _stdcall Action([out, retval] enum TArchiveAction* Value); [propget, id(0x00000002)] HRESULT _stdcall CompressedSize([out, retval] long* Value); [propget, id(0x00000003)] HRESULT _stdcall CRC32([out, retval] long* Value); [propget, id(0x00000004)] HRESULT _stdcall DiskFileName([out, retval] BSTR* Value); [propget, id(0x00000005)] HRESULT _stdcall DiskPath([out, retval] BSTR* Value); [propget, id(0x00000006)] HRESULT _stdcall ExternalFileAttributes([out, retval] enum TFileAttributes* Value); [propput, id(0x00000006)] HRESULT _stdcall ExternalFileAttributes([in] enum TFileAttributes Value); [propget, id(0x00000007)] HRESULT _stdcall FileName([out, retval] BSTR* Value); [propput, id(0x00000007)] HRESULT _stdcall FileName([in] BSTR Value); [propget, id(0x00000008)] HRESULT _stdcall IsEncrypted([out, retval] VARIANT_BOOL* Value); [propget, id(0x00000009)] HRESULT _stdcall LastModFileDateTime([out, retval] DATE* Value); [propget, id(0x0000000A)] HRESULT _stdcall StoredPath([out, retval] BSTR* Value); [propget, id(0x0000000B)] HRESULT _stdcall Tagged([out, retval] VARIANT_BOOL* Value); [propput, id(0x0000000B)] HRESULT _stdcall Tagged([in] VARIANT_BOOL Value); [propget, id(0x0000000C)] HRESULT _stdcall UnCompressedSize([out, retval] long* Value); [propget, id(0x0000000D)] HRESULT _stdcall CRC32St([out, retval] BSTR* Value); [propget, id(0x0000000E)] HRESULT _stdcall Password([out, retval] BSTR* Value); [propput, id(0x0000000E)] HRESULT _stdcall Password([in] BSTR Value); [propget, id(0x0000000F)] HRESULT _stdcall CompressionMethod([out, retval] enum TZipCompressionMethod* Value); [propget, id(0x00000010)] HRESULT _stdcall CompressionRatio([out, retval] double* Value); [propget, id(0x00000011)] HRESULT _stdcall DeflateOption([out, retval] enum TZipDeflateOption* Value); [propget, id(0x00000012)] HRESULT _stdcall DictionarySize([out, retval] enum TZipDictionarySize* Value); [propget, id(0x00000013)] HRESULT _stdcall DiskNumberStart([out, retval] long* Value); [propget, id(0x00000014)] HRESULT _stdcall ExtraField([out, retval] BSTR* Value); [propput, id(0x00000014)] HRESULT _stdcall ExtraField([in] BSTR Value); [propget, id(0x00000015)] HRESULT _stdcall FileComment([out, retval] BSTR* Value); [propput, id(0x00000015)] HRESULT _stdcall FileComment([in] BSTR Value); [propget, id(0x00000016)] HRESULT _stdcall InternalFileAttributes([out, retval] long* Value); [propput, id(0x00000016)] HRESULT _stdcall InternalFileAttributes([in] long Value); [propget, id(0x00000017)] HRESULT _stdcall VersionMadeBy([out, retval] long* Value); [propget, id(0x00000018)] HRESULT _stdcall VersionNeededToExtract([out, retval] long* Value); }; [ uuid(8FA78CE0-FD29-441E-9777-93B63EF1A9EE), version(3.0), dual, oleautomation ] interface IGZipItem: IDispatch { [propget, id(0x00000001)] HRESULT _stdcall Action([out, retval] enum TArchiveAction* Value); [propget, id(0x00000002)] HRESULT _stdcall CompressedSize([out, retval] long* Value); [propget, id(0x00000003)] HRESULT _stdcall CRC32([out, retval] long* Value); [propget, id(0x00000004)] HRESULT _stdcall DiskFileName([out, retval] BSTR* Value); [propget, id(0x00000005)] HRESULT _stdcall DiskPath([out, retval] BSTR* Value); [propget, id(0x00000006)] HRESULT _stdcall ExternalFileAttributes([out, retval] enum TFileAttributes* Value); [propput, id(0x00000006)] HRESULT _stdcall ExternalFileAttributes([in] enum TFileAttributes Value); [propget, id(0x00000007)] HRESULT _stdcall FileName([out, retval] BSTR* Value); [propput, id(0x00000007)] HRESULT _stdcall FileName([in] BSTR Value); [propget, id(0x00000008)] HRESULT _stdcall IsEncrypted([out, retval] VARIANT_BOOL* Value); [propget, id(0x00000009)] HRESULT _stdcall LastModFileDateTime([out, retval] DATE* Value); [propget, id(0x0000000A)] HRESULT _stdcall StoredPath([out, retval] BSTR* Value); [propget, id(0x0000000B)] HRESULT _stdcall Tagged([out, retval] VARIANT_BOOL* Value); [propput, id(0x0000000B)] HRESULT _stdcall Tagged([in] VARIANT_BOOL Value); [propget, id(0x0000000C)] HRESULT _stdcall UnCompressedSize([out, retval] long* Value); [propget, id(0x0000000D)] HRESULT _stdcall CRC32St([out, retval] BSTR* Value); [propget, id(0x0000000E)] HRESULT _stdcall Password([out, retval] BSTR* Value); [propput, id(0x0000000E)] HRESULT _stdcall Password([in] BSTR Value); [propget, id(0x0000000F)] HRESULT _stdcall CompressionMethod([out, retval] unsigned char* Value); [propput, id(0x0000000F)] HRESULT _stdcall CompressionMethod([in] unsigned char Value); [propget, id(0x00000010)] HRESULT _stdcall ExtraField([out, retval] BSTR* Value); [propput, id(0x00000010)] HRESULT _stdcall ExtraField([in] BSTR Value); [propget, id(0x00000011)] HRESULT _stdcall ExtraFlags([out, retval] unsigned char* Value); [propput, id(0x00000011)] HRESULT _stdcall ExtraFlags([in] unsigned char Value); [propget, id(0x00000012)] HRESULT _stdcall FileComment([out, retval] BSTR* Value); [propput, id(0x00000012)] HRESULT _stdcall FileComment([in] BSTR Value); [propget, id(0x00000013)] HRESULT _stdcall FileSystem([out, retval] enum TFileSystem* Value); [propput, id(0x00000013)] HRESULT _stdcall FileSystem([in] enum TFileSystem Value); [propget, id(0x00000014)] HRESULT _stdcall Flags([out, retval] unsigned char* Value); [propput, id(0x00000014)] HRESULT _stdcall Flags([in] unsigned char Value); [propget, id(0x00000015)] HRESULT _stdcall HeaderCRC([out, retval] long* Value); }; [ uuid(729E9F52-C489-4A41-A770-4E2C5282AE39), version(3.0), dual, oleautomation ] interface ITarItem: IDispatch { [propget, id(0x00000001)] HRESULT _stdcall Action([out, retval] enum TArchiveAction* Value); [propget, id(0x00000002)] HRESULT _stdcall CompressedSize([out, retval] long* Value); [propget, id(0x00000003)] HRESULT _stdcall CRC32([out, retval] long* Value); [propget, id(0x00000004)] HRESULT _stdcall DiskFileName([out, retval] BSTR* Value); [propget, id(0x00000005)] HRESULT _stdcall DiskPath([out, retval] BSTR* Value); [propget, id(0x00000006)] HRESULT _stdcall ExternalFileAttributes([out, retval] enum TFileAttributes* Value); [propput, id(0x00000006)] HRESULT _stdcall ExternalFileAttributes([in] enum TFileAttributes Value); [propget, id(0x00000007)] HRESULT _stdcall FileName([out, retval] BSTR* Value); [propput, id(0x00000007)] HRESULT _stdcall FileName([in] BSTR Value); [propget, id(0x00000008)] HRESULT _stdcall IsEncrypted([out, retval] VARIANT_BOOL* Value); [propget, id(0x00000009)] HRESULT _stdcall LastModFileDateTime([out, retval] DATE* Value); [propget, id(0x0000000A)] HRESULT _stdcall StoredPath([out, retval] BSTR* Value); [propget, id(0x0000000B)] HRESULT _stdcall Tagged([out, retval] VARIANT_BOOL* Value); [propput, id(0x0000000B)] HRESULT _stdcall Tagged([in] VARIANT_BOOL Value); [propget, id(0x0000000C)] HRESULT _stdcall UnCompressedSize([out, retval] long* Value); [propget, id(0x0000000D)] HRESULT _stdcall CRC32St([out, retval] BSTR* Value); [propget, id(0x0000000E)] HRESULT _stdcall Password([out, retval] BSTR* Value); [propput, id(0x0000000E)] HRESULT _stdcall Password([in] BSTR Value); [propget, id(0x0000000F)] HRESULT _stdcall DevMajor([out, retval] long* Value); [propput, id(0x0000000F)] HRESULT _stdcall DevMajor([in] long Value); [propget, id(0x00000010)] HRESULT _stdcall DevMinor([out, retval] long* Value); [propput, id(0x00000010)] HRESULT _stdcall DevMinor([in] long Value); [propget, id(0x00000011)] HRESULT _stdcall GroupID([out, retval] long* Value); [propput, id(0x00000011)] HRESULT _stdcall GroupID([in] long Value); [propget, id(0x00000012)] HRESULT _stdcall GroupName([out, retval] BSTR* Value); [propput, id(0x00000012)] HRESULT _stdcall GroupName([in] BSTR Value); [propget, id(0x00000013)] HRESULT _stdcall LinkFlag([out, retval] unsigned char* Value); [propput, id(0x00000013)] HRESULT _stdcall LinkFlag([in] unsigned char Value); [propget, id(0x00000014)] HRESULT _stdcall LinkName([out, retval] BSTR* Value); [propput, id(0x00000014)] HRESULT _stdcall LinkName([in] BSTR Value); [propget, id(0x00000015)] HRESULT _stdcall Mode([out, retval] long* Value); [propput, id(0x00000015)] HRESULT _stdcall Mode([in] long Value); [propget, id(0x00000016)] HRESULT _stdcall UserID([out, retval] long* Value); [propput, id(0x00000016)] HRESULT _stdcall UserID([in] long Value); [propget, id(0x00000017)] HRESULT _stdcall UserName([out, retval] BSTR* Value); [propput, id(0x00000017)] HRESULT _stdcall UserName([in] BSTR Value); }; [ uuid(B7480A7F-4E27-4B45-9FE6-224B60295A0C), version(3.0), helpstring("Dispatch interface for ZipKit Object"), helpcontext(0x00000006), dual, oleautomation ] interface IZipKit: IDispatch { [id(0x00000001)] HRESULT _stdcall Add([in] BSTR FileMask, [in] BSTR ExclusionMask, [in] long SearchAttr); [id(0x00000007)] HRESULT _stdcall AddFromStream([in] BSTR FileName, [in] VARIANT Stream); [propget, id(0x00000003)] HRESULT _stdcall AutoSave([out, retval] VARIANT_BOOL* Value); [propput, id(0x00000003)] HRESULT _stdcall AutoSave([in] VARIANT_BOOL Value); [propget, id(0x00000004)] HRESULT _stdcall BaseDirectory([out, retval] BSTR* Value); [propput, id(0x00000004)] HRESULT _stdcall BaseDirectory([in] BSTR Value); [id(0x00000005)] HRESULT _stdcall ClearTags(void); [propget, id(0x00000006)] HRESULT _stdcall CompressionMethodToUse([out, retval] enum TZipSupportMethod* Value); [propput, id(0x00000006)] HRESULT _stdcall CompressionMethodToUse([in] enum TZipSupportMethod Value); [propget, id(0x00000002)] HRESULT _stdcall Count([out, retval] long* Value); [propget, id(0x00000008)] HRESULT _stdcall DeflateOption([out, retval] enum TZipDeflateOption* Value); [propput, id(0x00000008)] HRESULT _stdcall DeflateOption([in] enum TZipDeflateOption Value); [id(0x00000009)] HRESULT _stdcall Delete([in] BSTR FileMask, [in] BSTR ExclusionMask); [id(0x0000000A)] HRESULT _stdcall DeleteAt([in] long Index); [id(0x0000000B)] HRESULT _stdcall DeleteTaggedItems(void); [propget, id(0x0000000C)] HRESULT _stdcall DOSMode([out, retval] VARIANT_BOOL* Value); [propput, id(0x0000000C)] HRESULT _stdcall DOSMode([in] VARIANT_BOOL Value); [id(0x0000000D)] HRESULT _stdcall Extract([in] BSTR FileMask, [in] BSTR ExclusionMask); [id(0x0000000E)] HRESULT _stdcall ExtractAt([in] long Index, [in] BSTR NewName); [propget, id(0x0000000F)] HRESULT _stdcall ExtractOptions([out, retval] enum TZipExtractOptions* Value); [propput, id(0x0000000F)] HRESULT _stdcall ExtractOptions([in] enum TZipExtractOptions Value); [id(0x00000010)] HRESULT _stdcall ExtractTaggedItems(void); [propget, id(0x00000011)] HRESULT _stdcall FileName([out, retval] BSTR* Value); [propput, id(0x00000011)] HRESULT _stdcall FileName([in] BSTR Value); [id(0x00000012)] HRESULT _stdcall Find([in] BSTR FileName, [out, retval] long* Value); [id(0x00000013)] HRESULT _stdcall Freshen([in] BSTR FileMask, [in] BSTR ExclusionMask); [id(0x00000014)] HRESULT _stdcall FreshenTaggedItems(void); [propget, id(0x00000000)] HRESULT _stdcall Item([in] long Index, [out, retval] IDispatch** Value); [propget, id(0x00000017)] HRESULT _stdcall LogFile([out, retval] BSTR* Value); [propput, id(0x00000017)] HRESULT _stdcall LogFile([in] BSTR Value); [propget, id(0x00000018)] HRESULT _stdcall Logging([out, retval] VARIANT_BOOL* Value); [propput, id(0x00000018)] HRESULT _stdcall Logging([in] VARIANT_BOOL Value); [propget, id(0x00000019)] HRESULT _stdcall Password([out, retval] BSTR* Value); [propput, id(0x00000019)] HRESULT _stdcall Password([in] BSTR Value); [propget, id(0x0000001A)] HRESULT _stdcall PasswordRetries([out, retval] unsigned char* Value); [propput, id(0x0000001A)] HRESULT _stdcall PasswordRetries([in] unsigned char Value); [id(0x0000001B)] HRESULT _stdcall Replace([in] BSTR FileMask); [id(0x0000001C)] HRESULT _stdcall Save(void); [propget, id(0x0000001D)] HRESULT _stdcall Spanned([out, retval] VARIANT_BOOL* Value); [propget, id(0x0000001E)] HRESULT _stdcall SpanningThreshold([out, retval] long* Value); [propput, id(0x0000001E)] HRESULT _stdcall SpanningThreshold([in] long Value); [propget, id(0x0000001F)] HRESULT _stdcall Status([out, retval] enum TArchiveStatus* Value); [propget, id(0x00000020)] HRESULT _stdcall StoreOptions([out, retval] enum TStoreOptions* Value); [propput, id(0x00000020)] HRESULT _stdcall StoreOptions([in] enum TStoreOptions Value); [id(0x00000021)] HRESULT _stdcall TagItems([in] BSTR FileMask); [propget, id(0x00000022)] HRESULT _stdcall TempDirectory([out, retval] BSTR* Value); [propput, id(0x00000022)] HRESULT _stdcall TempDirectory([in] BSTR Value); [id(0x00000023)] HRESULT _stdcall TestTaggedItems(void); [id(0x00000024)] HRESULT _stdcall UntagItems([in] BSTR FileMask); [propget, id(0x00000025)] HRESULT _stdcall ZipFileComment([out, retval] BSTR* Value); [propput, id(0x00000025)] HRESULT _stdcall ZipFileComment([in] BSTR Value); [id(0x00000026)] HRESULT _stdcall License([in] BSTR Key, [out, retval] VARIANT_BOOL* Value); [propget, id(0xFFFFFFFC), restricted, hidden] HRESULT _stdcall _NewEnum([out, retval] IUnknown** Value); [id(0x00000015)] HRESULT _stdcall ExtractToStream([in] BSTR FileName, [out, retval] VARIANT* Value); [propget, id(0x00000028)] HRESULT _stdcall CompressionType([out, retval] enum TArchiveType* Value); [propput, id(0x00000028)] HRESULT _stdcall CompressionType([in] enum TArchiveType Value); [propget, id(0x00000029)] HRESULT _stdcall TarAutoHandle([out, retval] VARIANT_BOOL* Value); [propput, id(0x00000029)] HRESULT _stdcall TarAutoHandle([in] VARIANT_BOOL Value); }; [ uuid(F094D5F4-3A52-45AE-9D86-4409611DD29E), version(3.0), helpstring("Events interface for ZipKit Object") ] dispinterface IZipKitEvents { properties: methods: [id(0x00000001)] void OnArchiveItemProgress([in] IDispatch* Item, [in] unsigned char Progress, [in, out] VARIANT_BOOL* Abort); [id(0x00000002)] void OnArchiveProgress([in] unsigned char Progress, [in, out] VARIANT_BOOL* Abort); [id(0x00000003)] void OnChange(void); [id(0x00000004)] void OnConfirmOverwrite([in, out] BSTR* Name, [in, out] VARIANT_BOOL* Confirm); [id(0x00000005)] void OnConfirmProcessItem([in] IDispatch* Item, [in] enum TProcessType ProcessType, [in, out] VARIANT_BOOL* Confirm); [id(0x00000006)] void OnConfirmSave([in, out] VARIANT_BOOL* Confirm); [id(0x00000007)] void OnLoad(void); [id(0x00000008)] void OnNeedPassword([in, out] BSTR* NewPassword); [id(0x00000009)] void OnProcessItemFailure([in] IDispatch* Item, [in] enum TProcessType ProcessType, [in] enum TErrorClass ErrorClass, [in] enum TErrorCode ErrorCode, [in] BSTR ErrorString); [id(0x0000000A)] void OnRequestBlankDisk([in, out] VARIANT_BOOL* Abort); [id(0x0000000B)] void OnRequestImage([in] long ImageNumber, [in, out] BSTR* ImageName, [in, out] VARIANT_BOOL* Abort); [id(0x0000000C)] void OnRequestLastDisk([in, out] VARIANT_BOOL* Abort); [id(0x0000000D)] void OnRequestNthDisk([in] long DiskNumber, [in, out] VARIANT_BOOL* Abort); [id(0x0000000E)] void OnSave(void); }; [ uuid(650989D8-F0FF-4C71-83C3-92556F4329F5), version(3.0) ] coclass ZipItem { [default] interface IZipItem; }; [ uuid(2B35BB50-D9C7-4669-B18E-943B5199FD8E), version(3.0) ] coclass GZipItem { [default] interface IGZipItem; }; [ uuid(2DF3E624-0E6C-42CF-8041-676B9A06375E), version(3.0) ] coclass TarItem { [default] interface ITarItem; }; [ uuid(730B4B32-9127-492A-BF02-196A7E6B4E1B), version(3.0), helpstring("ZipKit Object"), helpcontext(0x00000006) ] coclass ZipKit { [default] interface IZipKit; [default, source] dispinterface IZipKitEvents; }; }; ================================================ FILE: lib/abbrevia/source/COM/Abbrevia_TLB.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) unit Abbrevia_TLB; // ************************************************************************ // // WARNING // ------- // The types declared in this file were generated from data read from a // Type Library. If this type library is explicitly or indirectly (via // another type library referring to this type library) re-imported, or the // 'Refresh' command of the Type Library Editor activated while editing the // Type Library, the contents of this file will be regenerated and all // manual modifications will be lost. // ************************************************************************ // // $Rev: 491 $ // File generated on 7/23/2009 9:45:45 PM from Type Library described below. // ************************************************************************ // // Type Lib: C:\Abbrevia\COM\abbrevia.dll // LIBID: {AF804E20-4043-499E-BB14-237B9F26F89F} // LCID: 0 // Helpfile: C:\Abbrevia\COM\abrv-com.hlp // HelpString: TurboPower Abbrevia Compression Library v3.03 // DepndLst: // (1) v2.0 stdole, (C:\WINDOWS\System32\stdole2.tlb) // ************************************************************************ // {$TYPEDADDRESS OFF} // Unit must be compiled without type-checked pointers. {$WARN SYMBOL_PLATFORM OFF} {$WRITEABLECONST ON} {$VARPROPSETTER ON} interface uses Windows, ActiveX, Classes, Graphics, StdVCL, Variants; // *********************************************************************// // GUIDS declared in the TypeLibrary. Following prefixes are used: // Type Libraries : LIBID_xxxx // CoClasses : CLASS_xxxx // DISPInterfaces : DIID_xxxx // Non-DISP interfaces: IID_xxxx // *********************************************************************// const // TypeLibrary Major and minor versions AbbreviaMajorVersion = 5; AbbreviaMinorVersion = 0; LIBID_Abbrevia: TGUID = '{AF804E20-4043-499E-BB14-237B9F26F89F}'; IID_IZipItem: TGUID = '{851699A1-422A-4C65-8E08-D0499ACDD834}'; IID_IGZipItem: TGUID = '{8FA78CE0-FD29-441E-9777-93B63EF1A9EE}'; IID_ITarItem: TGUID = '{729E9F52-C489-4A41-A770-4E2C5282AE39}'; IID_IZipKit: TGUID = '{B7480A7F-4E27-4B45-9FE6-224B60295A0C}'; DIID_IZipKitEvents: TGUID = '{F094D5F4-3A52-45AE-9D86-4409611DD29E}'; CLASS_ZipItem: TGUID = '{650989D8-F0FF-4C71-83C3-92556F4329F5}'; CLASS_GZipItem: TGUID = '{2B35BB50-D9C7-4669-B18E-943B5199FD8E}'; CLASS_TarItem: TGUID = '{2DF3E624-0E6C-42CF-8041-676B9A06375E}'; CLASS_ZipKit: TGUID = '{730B4B32-9127-492A-BF02-196A7E6B4E1B}'; // *********************************************************************// // Declaration of Enumerations defined in Type Library // *********************************************************************// // Constants for enum TArchiveAction type TArchiveAction = TOleEnum; const aaFailed = $00000000; aaNone = $00000001; aaAdd = $00000002; aaDelete = $00000003; aaFreshen = $00000004; aaMove = $00000005; aaStreamAdd = $00000006; // Constants for enum TArchiveStatus type TArchiveStatus = TOleEnum; const asInvalid = $00000000; asIdle = $00000001; asBusy = $00000002; // Constants for enum TErrorClass type TErrorClass = TOleEnum; const eclAbbrevia = $00000000; eclInOutError = $00000001; eclFileError = $00000002; eclFileCreateError = $00000003; eclFileOpenError = $00000004; eclOther = $00000005; // Constants for enum TFileAttributes type TFileAttributes = TOleEnum; const faReadOnly = $00000001; faHidden = $00000002; faSysFile = $00000004; faVolumeID = $00000008; faDirectory = $00000010; faArchive = $00000020; // Constants for enum TProcessType type TProcessType = TOleEnum; const ptAdd = $00000000; ptDelete = $00000001; ptExtract = $00000002; ptFreshen = $00000003; ptMove = $00000004; ptReplace = $00000005; // Constants for enum TStoreOptions type TStoreOptions = TOleEnum; const soStripDrive = $00000001; soStripPath = $00000002; soRemoveDots = $00000004; soRecurse = $00000008; soFreshen = $00000010; soReplace = $00000020; // Constants for enum TZipCompressionMethod type TZipCompressionMethod = TOleEnum; const cmStored = $00000000; cmShrunk = $00000001; cmReduced1 = $00000002; cmReduced2 = $00000003; cmReduced3 = $00000004; cmReduced4 = $00000005; cmImploded = $00000006; cmTokenized = $00000007; cmDeflated = $00000008; cmEnhancedDeflated = $00000009; cmDCLImploded = $0000000A; cmBestMethod = $0000000B; // Constants for enum TZipDeflateOption type TZipDeflateOption = TOleEnum; const doInvalid = $00000000; doNormal = $00000001; doMaximum = $00000002; doFast = $00000003; doSuperFast = $00000004; // Constants for enum TZipDictionarySize type TZipDictionarySize = TOleEnum; const dsInvalid = $00000000; ds4K = $00000001; ds8K = $00000002; // Constants for enum TZipExtractOptions type TZipExtractOptions = TOleEnum; const eoCreateDirs = $00000000; eoRestorePath = $00000001; // Constants for enum TZipSupportMethod type TZipSupportMethod = TOleEnum; const smStored = $00000000; smDeflated = $00000001; smBestMethod = $00000002; // Constants for enum TErrorCode type TErrorCode = TOleEnum; const ecDuplicateName = $00000000; ecInvalidPassword = $00000001; ecNoSuchDirectory = $00000002; ecUnknownCompressionMethod = $00000003; ecUserAbort = $00000004; ecZipBadCRC = $00000005; ecZipVersionNumber = $00000006; ecSpannedItemNotFound = $00000007; // Constants for enum TArchiveType type TArchiveType = TOleEnum; const atUnknown = $00000000; atZip = $00000001; atSelfExtZip = $00000002; atTar = $00000003; atGZip = $00000004; atGZippedTar = $00000005; atCab = $00000006; // Constants for enum TFileSystem type TFileSystem = TOleEnum; const fsFAT = $00000000; fsAmiga = $00000001; fsVMS = $00000002; fsUnix = $00000003; fsVM_CMS = $00000004; fsAtariTOS = $00000005; fsHPFS = $00000006; fsMacintosh = $00000007; fsZSystem = $00000008; fsCP_M = $00000009; fsTOPS20 = $0000000A; fsNTFS = $0000000B; fsQDOS = $0000000C; fsAcornRISCOS = $0000000D; fsUnknown = $0000000E; fsUndefined = $0000000F; type // *********************************************************************// // Forward declaration of types defined in TypeLibrary // *********************************************************************// IZipItem = interface; IZipItemDisp = dispinterface; IGZipItem = interface; IGZipItemDisp = dispinterface; ITarItem = interface; ITarItemDisp = dispinterface; IZipKit = interface; IZipKitDisp = dispinterface; IZipKitEvents = dispinterface; // *********************************************************************// // Declaration of CoClasses defined in Type Library // (NOTE: Here we map each CoClass to its Default Interface) // *********************************************************************// ZipItem = IZipItem; GZipItem = IGZipItem; TarItem = ITarItem; ZipKit = IZipKit; // *********************************************************************// // Interface: IZipItem // Flags: (4416) Dual OleAutomation Dispatchable // GUID: {851699A1-422A-4C65-8E08-D0499ACDD834} // *********************************************************************// IZipItem = interface(IDispatch) ['{851699A1-422A-4C65-8E08-D0499ACDD834}'] function Get_Action: TArchiveAction; safecall; function Get_CompressedSize: Integer; safecall; function Get_CRC32: Integer; safecall; function Get_DiskFileName: WideString; safecall; function Get_DiskPath: WideString; safecall; function Get_ExternalFileAttributes: TFileAttributes; safecall; procedure Set_ExternalFileAttributes(Value: TFileAttributes); safecall; function Get_FileName: WideString; safecall; procedure Set_FileName(const Value: WideString); safecall; function Get_IsEncrypted: WordBool; safecall; function Get_LastModFileDateTime: TDateTime; safecall; function Get_StoredPath: WideString; safecall; function Get_Tagged: WordBool; safecall; procedure Set_Tagged(Value: WordBool); safecall; function Get_UnCompressedSize: Integer; safecall; function Get_CRC32St: WideString; safecall; function Get_Password: WideString; safecall; procedure Set_Password(const Value: WideString); safecall; function Get_CompressionMethod: TZipCompressionMethod; safecall; function Get_CompressionRatio: Double; safecall; function Get_DeflateOption: TZipDeflateOption; safecall; function Get_DictionarySize: TZipDictionarySize; safecall; function Get_DiskNumberStart: Integer; safecall; function Get_ExtraField: WideString; safecall; procedure Set_ExtraField(const Value: WideString); safecall; function Get_FileComment: WideString; safecall; procedure Set_FileComment(const Value: WideString); safecall; function Get_InternalFileAttributes: Integer; safecall; procedure Set_InternalFileAttributes(Value: Integer); safecall; function Get_VersionMadeBy: Integer; safecall; function Get_VersionNeededToExtract: Integer; safecall; property Action: TArchiveAction read Get_Action; property CompressedSize: Integer read Get_CompressedSize; property CRC32: Integer read Get_CRC32; property DiskFileName: WideString read Get_DiskFileName; property DiskPath: WideString read Get_DiskPath; property ExternalFileAttributes: TFileAttributes read Get_ExternalFileAttributes write Set_ExternalFileAttributes; property FileName: WideString read Get_FileName write Set_FileName; property IsEncrypted: WordBool read Get_IsEncrypted; property LastModFileDateTime: TDateTime read Get_LastModFileDateTime; property StoredPath: WideString read Get_StoredPath; property Tagged: WordBool read Get_Tagged write Set_Tagged; property UnCompressedSize: Integer read Get_UnCompressedSize; property CRC32St: WideString read Get_CRC32St; property Password: WideString read Get_Password write Set_Password; property CompressionMethod: TZipCompressionMethod read Get_CompressionMethod; property CompressionRatio: Double read Get_CompressionRatio; property DeflateOption: TZipDeflateOption read Get_DeflateOption; property DictionarySize: TZipDictionarySize read Get_DictionarySize; property DiskNumberStart: Integer read Get_DiskNumberStart; property ExtraField: WideString read Get_ExtraField write Set_ExtraField; property FileComment: WideString read Get_FileComment write Set_FileComment; property InternalFileAttributes: Integer read Get_InternalFileAttributes write Set_InternalFileAttributes; property VersionMadeBy: Integer read Get_VersionMadeBy; property VersionNeededToExtract: Integer read Get_VersionNeededToExtract; end; // *********************************************************************// // DispIntf: IZipItemDisp // Flags: (4416) Dual OleAutomation Dispatchable // GUID: {851699A1-422A-4C65-8E08-D0499ACDD834} // *********************************************************************// IZipItemDisp = dispinterface ['{851699A1-422A-4C65-8E08-D0499ACDD834}'] property Action: TArchiveAction readonly dispid 1; property CompressedSize: Integer readonly dispid 2; property CRC32: Integer readonly dispid 3; property DiskFileName: WideString readonly dispid 4; property DiskPath: WideString readonly dispid 5; property ExternalFileAttributes: TFileAttributes dispid 6; property FileName: WideString dispid 7; property IsEncrypted: WordBool readonly dispid 8; property LastModFileDateTime: TDateTime readonly dispid 9; property StoredPath: WideString readonly dispid 10; property Tagged: WordBool dispid 11; property UnCompressedSize: Integer readonly dispid 12; property CRC32St: WideString readonly dispid 13; property Password: WideString dispid 14; property CompressionMethod: TZipCompressionMethod readonly dispid 15; property CompressionRatio: Double readonly dispid 16; property DeflateOption: TZipDeflateOption readonly dispid 17; property DictionarySize: TZipDictionarySize readonly dispid 18; property DiskNumberStart: Integer readonly dispid 19; property ExtraField: WideString dispid 20; property FileComment: WideString dispid 21; property InternalFileAttributes: Integer dispid 22; property VersionMadeBy: Integer readonly dispid 23; property VersionNeededToExtract: Integer readonly dispid 24; end; // *********************************************************************// // Interface: IGZipItem // Flags: (4416) Dual OleAutomation Dispatchable // GUID: {8FA78CE0-FD29-441E-9777-93B63EF1A9EE} // *********************************************************************// IGZipItem = interface(IDispatch) ['{8FA78CE0-FD29-441E-9777-93B63EF1A9EE}'] function Get_Action: TArchiveAction; safecall; function Get_CompressedSize: Integer; safecall; function Get_CRC32: Integer; safecall; function Get_DiskFileName: WideString; safecall; function Get_DiskPath: WideString; safecall; function Get_ExternalFileAttributes: TFileAttributes; safecall; procedure Set_ExternalFileAttributes(Value: TFileAttributes); safecall; function Get_FileName: WideString; safecall; procedure Set_FileName(const Value: WideString); safecall; function Get_IsEncrypted: WordBool; safecall; function Get_LastModFileDateTime: TDateTime; safecall; function Get_StoredPath: WideString; safecall; function Get_Tagged: WordBool; safecall; procedure Set_Tagged(Value: WordBool); safecall; function Get_UnCompressedSize: Integer; safecall; function Get_CRC32St: WideString; safecall; function Get_Password: WideString; safecall; procedure Set_Password(const Value: WideString); safecall; function Get_CompressionMethod: Byte; safecall; procedure Set_CompressionMethod(Value: Byte); safecall; function Get_ExtraField: WideString; safecall; procedure Set_ExtraField(const Value: WideString); safecall; function Get_ExtraFlags: Byte; safecall; procedure Set_ExtraFlags(Value: Byte); safecall; function Get_FileComment: WideString; safecall; procedure Set_FileComment(const Value: WideString); safecall; function Get_FileSystem: TFileSystem; safecall; procedure Set_FileSystem(Value: TFileSystem); safecall; function Get_Flags: Byte; safecall; procedure Set_Flags(Value: Byte); safecall; function Get_HeaderCRC: Integer; safecall; property Action: TArchiveAction read Get_Action; property CompressedSize: Integer read Get_CompressedSize; property CRC32: Integer read Get_CRC32; property DiskFileName: WideString read Get_DiskFileName; property DiskPath: WideString read Get_DiskPath; property ExternalFileAttributes: TFileAttributes read Get_ExternalFileAttributes write Set_ExternalFileAttributes; property FileName: WideString read Get_FileName write Set_FileName; property IsEncrypted: WordBool read Get_IsEncrypted; property LastModFileDateTime: TDateTime read Get_LastModFileDateTime; property StoredPath: WideString read Get_StoredPath; property Tagged: WordBool read Get_Tagged write Set_Tagged; property UnCompressedSize: Integer read Get_UnCompressedSize; property CRC32St: WideString read Get_CRC32St; property Password: WideString read Get_Password write Set_Password; property CompressionMethod: Byte read Get_CompressionMethod write Set_CompressionMethod; property ExtraField: WideString read Get_ExtraField write Set_ExtraField; property ExtraFlags: Byte read Get_ExtraFlags write Set_ExtraFlags; property FileComment: WideString read Get_FileComment write Set_FileComment; property FileSystem: TFileSystem read Get_FileSystem write Set_FileSystem; property Flags: Byte read Get_Flags write Set_Flags; property HeaderCRC: Integer read Get_HeaderCRC; end; // *********************************************************************// // DispIntf: IGZipItemDisp // Flags: (4416) Dual OleAutomation Dispatchable // GUID: {8FA78CE0-FD29-441E-9777-93B63EF1A9EE} // *********************************************************************// IGZipItemDisp = dispinterface ['{8FA78CE0-FD29-441E-9777-93B63EF1A9EE}'] property Action: TArchiveAction readonly dispid 1; property CompressedSize: Integer readonly dispid 2; property CRC32: Integer readonly dispid 3; property DiskFileName: WideString readonly dispid 4; property DiskPath: WideString readonly dispid 5; property ExternalFileAttributes: TFileAttributes dispid 6; property FileName: WideString dispid 7; property IsEncrypted: WordBool readonly dispid 8; property LastModFileDateTime: TDateTime readonly dispid 9; property StoredPath: WideString readonly dispid 10; property Tagged: WordBool dispid 11; property UnCompressedSize: Integer readonly dispid 12; property CRC32St: WideString readonly dispid 13; property Password: WideString dispid 14; property CompressionMethod: Byte dispid 15; property ExtraField: WideString dispid 16; property ExtraFlags: Byte dispid 17; property FileComment: WideString dispid 18; property FileSystem: TFileSystem dispid 19; property Flags: Byte dispid 20; property HeaderCRC: Integer readonly dispid 21; end; // *********************************************************************// // Interface: ITarItem // Flags: (4416) Dual OleAutomation Dispatchable // GUID: {729E9F52-C489-4A41-A770-4E2C5282AE39} // *********************************************************************// ITarItem = interface(IDispatch) ['{729E9F52-C489-4A41-A770-4E2C5282AE39}'] function Get_Action: TArchiveAction; safecall; function Get_CompressedSize: Integer; safecall; function Get_CRC32: Integer; safecall; function Get_DiskFileName: WideString; safecall; function Get_DiskPath: WideString; safecall; function Get_ExternalFileAttributes: TFileAttributes; safecall; procedure Set_ExternalFileAttributes(Value: TFileAttributes); safecall; function Get_FileName: WideString; safecall; procedure Set_FileName(const Value: WideString); safecall; function Get_IsEncrypted: WordBool; safecall; function Get_LastModFileDateTime: TDateTime; safecall; function Get_StoredPath: WideString; safecall; function Get_Tagged: WordBool; safecall; procedure Set_Tagged(Value: WordBool); safecall; function Get_UnCompressedSize: Integer; safecall; function Get_CRC32St: WideString; safecall; function Get_Password: WideString; safecall; procedure Set_Password(const Value: WideString); safecall; function Get_DevMajor: Integer; safecall; procedure Set_DevMajor(Value: Integer); safecall; function Get_DevMinor: Integer; safecall; procedure Set_DevMinor(Value: Integer); safecall; function Get_GroupID: Integer; safecall; procedure Set_GroupID(Value: Integer); safecall; function Get_GroupName: WideString; safecall; procedure Set_GroupName(const Value: WideString); safecall; function Get_LinkFlag: Byte; safecall; procedure Set_LinkFlag(Value: Byte); safecall; function Get_LinkName: WideString; safecall; procedure Set_LinkName(const Value: WideString); safecall; function Get_Mode: Integer; safecall; procedure Set_Mode(Value: Integer); safecall; function Get_UserID: Integer; safecall; procedure Set_UserID(Value: Integer); safecall; function Get_UserName: WideString; safecall; procedure Set_UserName(const Value: WideString); safecall; property Action: TArchiveAction read Get_Action; property CompressedSize: Integer read Get_CompressedSize; property CRC32: Integer read Get_CRC32; property DiskFileName: WideString read Get_DiskFileName; property DiskPath: WideString read Get_DiskPath; property ExternalFileAttributes: TFileAttributes read Get_ExternalFileAttributes write Set_ExternalFileAttributes; property FileName: WideString read Get_FileName write Set_FileName; property IsEncrypted: WordBool read Get_IsEncrypted; property LastModFileDateTime: TDateTime read Get_LastModFileDateTime; property StoredPath: WideString read Get_StoredPath; property Tagged: WordBool read Get_Tagged write Set_Tagged; property UnCompressedSize: Integer read Get_UnCompressedSize; property CRC32St: WideString read Get_CRC32St; property Password: WideString read Get_Password write Set_Password; property DevMajor: Integer read Get_DevMajor write Set_DevMajor; property DevMinor: Integer read Get_DevMinor write Set_DevMinor; property GroupID: Integer read Get_GroupID write Set_GroupID; property GroupName: WideString read Get_GroupName write Set_GroupName; property LinkFlag: Byte read Get_LinkFlag write Set_LinkFlag; property LinkName: WideString read Get_LinkName write Set_LinkName; property Mode: Integer read Get_Mode write Set_Mode; property UserID: Integer read Get_UserID write Set_UserID; property UserName: WideString read Get_UserName write Set_UserName; end; // *********************************************************************// // DispIntf: ITarItemDisp // Flags: (4416) Dual OleAutomation Dispatchable // GUID: {729E9F52-C489-4A41-A770-4E2C5282AE39} // *********************************************************************// ITarItemDisp = dispinterface ['{729E9F52-C489-4A41-A770-4E2C5282AE39}'] property Action: TArchiveAction readonly dispid 1; property CompressedSize: Integer readonly dispid 2; property CRC32: Integer readonly dispid 3; property DiskFileName: WideString readonly dispid 4; property DiskPath: WideString readonly dispid 5; property ExternalFileAttributes: TFileAttributes dispid 6; property FileName: WideString dispid 7; property IsEncrypted: WordBool readonly dispid 8; property LastModFileDateTime: TDateTime readonly dispid 9; property StoredPath: WideString readonly dispid 10; property Tagged: WordBool dispid 11; property UnCompressedSize: Integer readonly dispid 12; property CRC32St: WideString readonly dispid 13; property Password: WideString dispid 14; property DevMajor: Integer dispid 15; property DevMinor: Integer dispid 16; property GroupID: Integer dispid 17; property GroupName: WideString dispid 18; property LinkFlag: Byte dispid 19; property LinkName: WideString dispid 20; property Mode: Integer dispid 21; property UserID: Integer dispid 22; property UserName: WideString dispid 23; end; // *********************************************************************// // Interface: IZipKit // Flags: (4416) Dual OleAutomation Dispatchable // GUID: {B7480A7F-4E27-4B45-9FE6-224B60295A0C} // *********************************************************************// IZipKit = interface(IDispatch) ['{B7480A7F-4E27-4B45-9FE6-224B60295A0C}'] procedure Add(const FileMask: WideString; const ExclusionMask: WideString; SearchAttr: Integer); safecall; procedure AddFromStream(const FileName: WideString; Stream: OleVariant); safecall; function Get_AutoSave: WordBool; safecall; procedure Set_AutoSave(Value: WordBool); safecall; function Get_BaseDirectory: WideString; safecall; procedure Set_BaseDirectory(const Value: WideString); safecall; procedure ClearTags; safecall; function Get_CompressionMethodToUse: TZipSupportMethod; safecall; procedure Set_CompressionMethodToUse(Value: TZipSupportMethod); safecall; function Get_Count: Integer; safecall; function Get_DeflateOption: TZipDeflateOption; safecall; procedure Set_DeflateOption(Value: TZipDeflateOption); safecall; procedure Delete(const FileMask: WideString; const ExclusionMask: WideString); safecall; procedure DeleteAt(Index: Integer); safecall; procedure DeleteTaggedItems; safecall; function Get_DOSMode: WordBool; safecall; procedure Set_DOSMode(Value: WordBool); safecall; procedure Extract(const FileMask: WideString; const ExclusionMask: WideString); safecall; procedure ExtractAt(Index: Integer; const NewName: WideString); safecall; function Get_ExtractOptions: TZipExtractOptions; safecall; procedure Set_ExtractOptions(Value: TZipExtractOptions); safecall; procedure ExtractTaggedItems; safecall; function Get_FileName: WideString; safecall; procedure Set_FileName(const Value: WideString); safecall; function Find(const FileName: WideString): Integer; safecall; procedure Freshen(const FileMask: WideString; const ExclusionMask: WideString); safecall; procedure FreshenTaggedItems; safecall; function Get_Item(Index: Integer): IDispatch; safecall; function Get_LogFile: WideString; safecall; procedure Set_LogFile(const Value: WideString); safecall; function Get_Logging: WordBool; safecall; procedure Set_Logging(Value: WordBool); safecall; function Get_Password: WideString; safecall; procedure Set_Password(const Value: WideString); safecall; function Get_PasswordRetries: Byte; safecall; procedure Set_PasswordRetries(Value: Byte); safecall; procedure Replace(const FileMask: WideString); safecall; procedure Save; safecall; function Get_Spanned: WordBool; safecall; function Get_SpanningThreshold: Integer; safecall; procedure Set_SpanningThreshold(Value: Integer); safecall; function Get_Status: TArchiveStatus; safecall; function Get_StoreOptions: TStoreOptions; safecall; procedure Set_StoreOptions(Value: TStoreOptions); safecall; procedure TagItems(const FileMask: WideString); safecall; function Get_TempDirectory: WideString; safecall; procedure Set_TempDirectory(const Value: WideString); safecall; procedure TestTaggedItems; safecall; procedure UntagItems(const FileMask: WideString); safecall; function Get_ZipFileComment: WideString; safecall; procedure Set_ZipFileComment(const Value: WideString); safecall; function License(const Key: WideString): WordBool; safecall; function Get__NewEnum: IUnknown; safecall; function ExtractToStream(const FileName: WideString): OleVariant; safecall; function Get_CompressionType: TArchiveType; safecall; procedure Set_CompressionType(Value: TArchiveType); safecall; function Get_TarAutoHandle: WordBool; safecall; procedure Set_TarAutoHandle(Value: WordBool); safecall; property AutoSave: WordBool read Get_AutoSave write Set_AutoSave; property BaseDirectory: WideString read Get_BaseDirectory write Set_BaseDirectory; property CompressionMethodToUse: TZipSupportMethod read Get_CompressionMethodToUse write Set_CompressionMethodToUse; property Count: Integer read Get_Count; property DeflateOption: TZipDeflateOption read Get_DeflateOption write Set_DeflateOption; property DOSMode: WordBool read Get_DOSMode write Set_DOSMode; property ExtractOptions: TZipExtractOptions read Get_ExtractOptions write Set_ExtractOptions; property FileName: WideString read Get_FileName write Set_FileName; property Item[Index: Integer]: IDispatch read Get_Item; property LogFile: WideString read Get_LogFile write Set_LogFile; property Logging: WordBool read Get_Logging write Set_Logging; property Password: WideString read Get_Password write Set_Password; property PasswordRetries: Byte read Get_PasswordRetries write Set_PasswordRetries; property Spanned: WordBool read Get_Spanned; property SpanningThreshold: Integer read Get_SpanningThreshold write Set_SpanningThreshold; property Status: TArchiveStatus read Get_Status; property StoreOptions: TStoreOptions read Get_StoreOptions write Set_StoreOptions; property TempDirectory: WideString read Get_TempDirectory write Set_TempDirectory; property ZipFileComment: WideString read Get_ZipFileComment write Set_ZipFileComment; property _NewEnum: IUnknown read Get__NewEnum; property CompressionType: TArchiveType read Get_CompressionType write Set_CompressionType; property TarAutoHandle: WordBool read Get_TarAutoHandle write Set_TarAutoHandle; end; // *********************************************************************// // DispIntf: IZipKitDisp // Flags: (4416) Dual OleAutomation Dispatchable // GUID: {B7480A7F-4E27-4B45-9FE6-224B60295A0C} // *********************************************************************// IZipKitDisp = dispinterface ['{B7480A7F-4E27-4B45-9FE6-224B60295A0C}'] procedure Add(const FileMask: WideString; const ExclusionMask: WideString; SearchAttr: Integer); dispid 1; procedure AddFromStream(const FileName: WideString; Stream: OleVariant); dispid 7; property AutoSave: WordBool dispid 3; property BaseDirectory: WideString dispid 4; procedure ClearTags; dispid 5; property CompressionMethodToUse: TZipSupportMethod dispid 6; property Count: Integer readonly dispid 2; property DeflateOption: TZipDeflateOption dispid 8; procedure Delete(const FileMask: WideString; const ExclusionMask: WideString); dispid 9; procedure DeleteAt(Index: Integer); dispid 10; procedure DeleteTaggedItems; dispid 11; property DOSMode: WordBool dispid 12; procedure Extract(const FileMask: WideString; const ExclusionMask: WideString); dispid 13; procedure ExtractAt(Index: Integer; const NewName: WideString); dispid 14; property ExtractOptions: TZipExtractOptions dispid 15; procedure ExtractTaggedItems; dispid 16; property FileName: WideString dispid 17; function Find(const FileName: WideString): Integer; dispid 18; procedure Freshen(const FileMask: WideString; const ExclusionMask: WideString); dispid 19; procedure FreshenTaggedItems; dispid 20; property Item[Index: Integer]: IDispatch readonly dispid 0; property LogFile: WideString dispid 23; property Logging: WordBool dispid 24; property Password: WideString dispid 25; property PasswordRetries: Byte dispid 26; procedure Replace(const FileMask: WideString); dispid 27; procedure Save; dispid 28; property Spanned: WordBool readonly dispid 29; property SpanningThreshold: Integer dispid 30; property Status: TArchiveStatus readonly dispid 31; property StoreOptions: TStoreOptions dispid 32; procedure TagItems(const FileMask: WideString); dispid 33; property TempDirectory: WideString dispid 34; procedure TestTaggedItems; dispid 35; procedure UntagItems(const FileMask: WideString); dispid 36; property ZipFileComment: WideString dispid 37; function License(const Key: WideString): WordBool; dispid 38; property _NewEnum: IUnknown readonly dispid $FFFFFFFC; function ExtractToStream(const FileName: WideString): OleVariant; dispid 21; property CompressionType: TArchiveType dispid 40; property TarAutoHandle: WordBool dispid 41; end; // *********************************************************************// // DispIntf: IZipKitEvents // Flags: (4096) Dispatchable // GUID: {F094D5F4-3A52-45AE-9D86-4409611DD29E} // *********************************************************************// IZipKitEvents = dispinterface ['{F094D5F4-3A52-45AE-9D86-4409611DD29E}'] procedure OnArchiveItemProgress(const Item: IDispatch; Progress: Byte; var Abort: WordBool); dispid 1; procedure OnArchiveProgress(Progress: Byte; var Abort: WordBool); dispid 2; procedure OnChange; dispid 3; procedure OnConfirmOverwrite(var Name: WideString; var Confirm: WordBool); dispid 4; procedure OnConfirmProcessItem(const Item: IDispatch; ProcessType: TProcessType; var Confirm: WordBool); dispid 5; procedure OnConfirmSave(var Confirm: WordBool); dispid 6; procedure OnLoad; dispid 7; procedure OnNeedPassword(var NewPassword: WideString); dispid 8; procedure OnProcessItemFailure(const Item: IDispatch; ProcessType: TProcessType; ErrorClass: TErrorClass; ErrorCode: TErrorCode; const ErrorString: WideString); dispid 9; procedure OnRequestBlankDisk(var Abort: WordBool); dispid 10; procedure OnRequestImage(ImageNumber: Integer; var ImageName: WideString; var Abort: WordBool); dispid 11; procedure OnRequestLastDisk(var Abort: WordBool); dispid 12; procedure OnRequestNthDisk(DiskNumber: Integer; var Abort: WordBool); dispid 13; procedure OnSave; dispid 14; end; // *********************************************************************// // The Class CoZipItem provides a Create and CreateRemote method to // create instances of the default interface IZipItem exposed by // the CoClass ZipItem. The functions are intended to be used by // clients wishing to automate the CoClass objects exposed by the // server of this typelibrary. // *********************************************************************// CoZipItem = class class function Create: IZipItem; class function CreateRemote(const MachineName: string): IZipItem; end; // *********************************************************************// // The Class CoGZipItem provides a Create and CreateRemote method to // create instances of the default interface IGZipItem exposed by // the CoClass GZipItem. The functions are intended to be used by // clients wishing to automate the CoClass objects exposed by the // server of this typelibrary. // *********************************************************************// CoGZipItem = class class function Create: IGZipItem; class function CreateRemote(const MachineName: string): IGZipItem; end; // *********************************************************************// // The Class CoTarItem provides a Create and CreateRemote method to // create instances of the default interface ITarItem exposed by // the CoClass TarItem. The functions are intended to be used by // clients wishing to automate the CoClass objects exposed by the // server of this typelibrary. // *********************************************************************// CoTarItem = class class function Create: ITarItem; class function CreateRemote(const MachineName: string): ITarItem; end; // *********************************************************************// // The Class CoZipKit provides a Create and CreateRemote method to // create instances of the default interface IZipKit exposed by // the CoClass ZipKit. The functions are intended to be used by // clients wishing to automate the CoClass objects exposed by the // server of this typelibrary. // *********************************************************************// CoZipKit = class class function Create: IZipKit; class function CreateRemote(const MachineName: string): IZipKit; end; implementation uses ComObj; class function CoZipItem.Create: IZipItem; begin Result := CreateComObject(CLASS_ZipItem) as IZipItem; end; class function CoZipItem.CreateRemote(const MachineName: string): IZipItem; begin Result := CreateRemoteComObject(MachineName, CLASS_ZipItem) as IZipItem; end; class function CoGZipItem.Create: IGZipItem; begin Result := CreateComObject(CLASS_GZipItem) as IGZipItem; end; class function CoGZipItem.CreateRemote(const MachineName: string): IGZipItem; begin Result := CreateRemoteComObject(MachineName, CLASS_GZipItem) as IGZipItem; end; class function CoTarItem.Create: ITarItem; begin Result := CreateComObject(CLASS_TarItem) as ITarItem; end; class function CoTarItem.CreateRemote(const MachineName: string): ITarItem; begin Result := CreateRemoteComObject(MachineName, CLASS_TarItem) as ITarItem; end; class function CoZipKit.Create: IZipKit; begin Result := CreateComObject(CLASS_ZipKit) as IZipKit; end; class function CoZipKit.CreateRemote(const MachineName: string): IZipKit; begin Result := CreateRemoteComObject(MachineName, CLASS_ZipKit) as IZipKit; end; end. ================================================ FILE: lib/abbrevia/source/COM/Readme.txt ================================================ The COM DLLs for v5.0 are compiled using Delphi XE2 (including extended RTTI) and include zipx support. Recompiling with Delphi 2009 and without zipx support should roughly halve the size of the 32-bit DLL. They can be registered for all users (requires admin rights) using: regsvr32 Abbrevia.dll And for the current user using: regsvr32 /i:user /n Abbrevia.dll To uninstall use: regsvr32 /u Abbrevia.dll or regsvr32 /i:user /n /u Abbrevia.dll ================================================ FILE: lib/abbrevia/source/COM/_GZipItem.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) unit _GZipItem; interface uses ComObj, Abbrevia_TLB, AbGzTyp, AbZipKit; type TGZipItem = class(TAutoIntfObject, IGZipItem) private FOwner : TAbGzipItem; FParent : TAbZipKit; public constructor Create(AOwner : TAbGzipItem; AParent : TAbZipKit); protected {IArchiveItem} function Get_Action: TArchiveAction; safecall; function Get_CompressedSize: Integer; safecall; function Get_CRC32: Integer; safecall; function Get_CRC32St: WideString; safecall; function Get_DiskFileName: WideString; safecall; function Get_DiskPath: WideString; safecall; function Get_ExternalFileAttributes: TFileAttributes; safecall; procedure Set_ExternalFileAttributes(Value: TFileAttributes); safecall; function Get_FileName: WideString; safecall; procedure Set_FileName(const Value: WideString); safecall; function Get_IsEncrypted: WordBool; safecall; function Get_LastModFileDateTime: TDateTime; safecall; function Get_StoredPath: WideString; safecall; function Get_Tagged: WordBool; safecall; procedure Set_Tagged(Value: WordBool); safecall; function Get_UnCompressedSize: Integer; safecall; function Get_Password: WideString; safecall; procedure Set_Password(const Value: WideString); safecall; {IGZipItem} function Get_CompressionMethod: Byte; safecall; procedure Set_CompressionMethod(Value: Byte); safecall; function Get_ExtraField: WideString; safecall; procedure Set_ExtraField(const Value: WideString); safecall; function Get_ExtraFlags: Byte; safecall; procedure Set_ExtraFlags(Value: Byte); safecall; function Get_FileComment: WideString; safecall; procedure Set_FileComment(const Value: WideString); safecall; function Get_FileSystem: TFileSystem; safecall; procedure Set_FileSystem(Value: TFileSystem); safecall; function Get_Flags: Byte; safecall; procedure Set_Flags(Value: Byte); safecall; function Get_HeaderCRC: Integer; safecall; end; implementation uses ComServ, {StStrL,} SysUtils; {------------------------------------------------------------------------------} constructor TGzipItem.Create(AOwner : TAbGzipItem; AParent : TAbZipKit); begin inherited Create(ComServer.TypeLib, IGZipItem); FOwner := AOwner; FParent := AParent; end; {------------------------------------------------------------------------------} {IArchiveItem} {------------------------------------------------------------------------------} function TGzipItem.Get_Action: TArchiveAction; begin Result := TArchiveAction(FOwner.Action); end; {------------------------------------------------------------------------------} function TGzipItem.Get_CompressedSize: Integer; begin result := FOwner.CompressedSize; end; {------------------------------------------------------------------------------} function TGzipItem.Get_CRC32: Integer; begin result := FOwner.CRC32; end; {------------------------------------------------------------------------------} function TGzipItem.Get_CRC32St: WideString; begin result := IntToHex(FOwner.CRC32, 8); end; {------------------------------------------------------------------------------} function TGzipItem.Get_DiskFileName: WideString; begin result := FOwner.DiskFileName; end; {------------------------------------------------------------------------------} function TGzipItem.Get_DiskPath: WideString; begin result := FOwner.DiskPath; end; {------------------------------------------------------------------------------} function TGzipItem.Get_ExternalFileAttributes: TFileAttributes; begin result := TFileAttributes(FOwner.ExternalFileAttributes); end; {------------------------------------------------------------------------------} procedure TGzipItem.Set_ExternalFileAttributes(Value: TFileAttributes); begin FOwner.ExternalFileAttributes := LongInt(Value); FParent.ZipArchive.IsDirty := True; end; {------------------------------------------------------------------------------} function TGzipItem.Get_FileName: WideString; begin result := FOwner.FileName; end; {------------------------------------------------------------------------------} procedure TGzipItem.Set_FileName(const Value: WideString); begin FOwner.FileName := Value; end; {------------------------------------------------------------------------------} function TGzipItem.Get_IsEncrypted: WordBool; begin result := FOwner.IsEncrypted; end; {------------------------------------------------------------------------------} function TGzipItem.Get_LastModFileDateTime: TDateTime; begin result := FileDateToDateTime((FOwner.LastModFileDate shl 16) + FOwner.LastModFileTime); end; {------------------------------------------------------------------------------} function TGzipItem.Get_StoredPath: WideString; begin result := FOwner.StoredPath; end; {------------------------------------------------------------------------------} function TGzipItem.Get_Tagged: WordBool; begin result := FOwner.Tagged; end; {------------------------------------------------------------------------------} procedure TGzipItem.Set_Tagged(Value: WordBool); begin FOwner.Tagged := Value; end; {------------------------------------------------------------------------------} function TGzipItem.Get_UnCompressedSize: Integer; begin result := FOwner.UncompressedSize; end; {------------------------------------------------------------------------------} function TGzipItem.Get_Password: WideString; begin {!!!} //result := FOwner.Password; end; {------------------------------------------------------------------------------} procedure TGzipItem.Set_Password(const Value: WideString); begin {!!!} //FOwner.Password := Value; //FParent.ZipArchive.IsDirty := True; end; {------------------------------------------------------------------------------} {IGZipItem} {------------------------------------------------------------------------------} function TGzipItem.Get_CompressionMethod: Byte; begin result := FOwner.CompressionMethod; end; {------------------------------------------------------------------------------} procedure TGzipItem.Set_CompressionMethod(Value: Byte); begin end; {------------------------------------------------------------------------------} function TGzipItem.Get_ExtraField: WideString; begin result := ''; end; {------------------------------------------------------------------------------} procedure TGzipItem.Set_ExtraField(const Value: WideString); begin end; {------------------------------------------------------------------------------} function TGzipItem.Get_ExtraFlags: Byte; begin result := FOwner.ExtraFlags; end; {------------------------------------------------------------------------------} procedure TGzipItem.Set_ExtraFlags(Value: Byte); begin FOwner.ExtraFlags := Value; FParent.ZipArchive.IsDirty := True; end; {------------------------------------------------------------------------------} function TGzipItem.Get_FileComment: WideString; begin result := WideString(FOwner.FileComment); end; {------------------------------------------------------------------------------} procedure TGzipItem.Set_FileComment(const Value: WideString); begin FOwner.FileComment := AnsiString(Value); FParent.ZipArchive.IsDirty := True; end; {------------------------------------------------------------------------------} function TGzipItem.Get_FileSystem: TFileSystem; begin result := TFileSystem(FOwner.FileSystem); end; {------------------------------------------------------------------------------} procedure TGzipItem.Set_FileSystem(Value: TFileSystem); begin FOwner.FileSystem := TAbGzFileSystem(Value); FParent.ZipArchive.IsDirty := True; end; {------------------------------------------------------------------------------} function TGzipItem.Get_Flags: Byte; begin result := FOwner.Flags; end; {------------------------------------------------------------------------------} procedure TGzipItem.Set_Flags(Value: Byte); begin end; {------------------------------------------------------------------------------} function TGzipItem.Get_HeaderCRC: Integer; begin result := 0; end; {------------------------------------------------------------------------------} end. ================================================ FILE: lib/abbrevia/source/COM/_TarItem.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) unit _TarItem; interface uses ComObj, Abbrevia_TLB, AbTarTyp, AbZipKit; type TTarItem = class(TAutoIntfObject, ITarItem) private FOwner : TAbTarItem; FParent : TAbZipKit; public constructor Create(AOwner : TAbTarItem; AParent : TAbZipKit); protected {IArchiveItem} function Get_Action: TArchiveAction; safecall; function Get_CompressedSize: Integer; safecall; function Get_CRC32: Integer; safecall; function Get_CRC32St: WideString; safecall; function Get_DiskFileName: WideString; safecall; function Get_DiskPath: WideString; safecall; function Get_ExternalFileAttributes: TFileAttributes; safecall; procedure Set_ExternalFileAttributes(Value: TFileAttributes); safecall; function Get_FileName: WideString; safecall; procedure Set_FileName(const Value: WideString); safecall; function Get_IsEncrypted: WordBool; safecall; function Get_LastModFileDateTime: TDateTime; safecall; function Get_StoredPath: WideString; safecall; function Get_Tagged: WordBool; safecall; procedure Set_Tagged(Value: WordBool); safecall; function Get_UnCompressedSize: Integer; safecall; function Get_Password: WideString; safecall; procedure Set_Password(const Value: WideString); safecall; {ITarItem} function Get_DevMajor: Integer; safecall; procedure Set_DevMajor(Value: Integer); safecall; function Get_DevMinor: Integer; safecall; procedure Set_DevMinor(Value: Integer); safecall; function Get_GroupID: Integer; safecall; procedure Set_GroupID(Value: Integer); safecall; function Get_GroupName: WideString; safecall; procedure Set_GroupName(const Value: WideString); safecall; function Get_LinkFlag: Byte; safecall; procedure Set_LinkFlag(Value: Byte); safecall; function Get_LinkName: WideString; safecall; procedure Set_LinkName(const Value: WideString); safecall; function Get_Mode: Integer; safecall; procedure Set_Mode(Value: Integer); safecall; function Get_UserID: Integer; safecall; procedure Set_UserID(Value: Integer); safecall; function Get_UserName: WideString; safecall; procedure Set_UserName(const Value: WideString); safecall; end; implementation uses ComServ, {StStrL,} SysUtils; {------------------------------------------------------------------------------} constructor TTarItem.Create(AOwner : TAbTarItem; AParent : TAbZipKit); begin inherited Create(ComServer.TypeLib, ITarItem); FOwner := AOwner; FParent := AParent; end; {------------------------------------------------------------------------------} {IArchiveItem} {------------------------------------------------------------------------------} function TTarItem.Get_Action: TArchiveAction; begin Result := TArchiveAction(FOwner.Action); end; {------------------------------------------------------------------------------} function TTarItem.Get_CompressedSize: Integer; begin result := FOwner.CompressedSize; end; {------------------------------------------------------------------------------} function TTarItem.Get_CRC32: Integer; begin result := FOwner.CRC32; end; {------------------------------------------------------------------------------} function TTarItem.Get_CRC32St: WideString; begin result := IntToHex(FOwner.CRC32, 8); end; {------------------------------------------------------------------------------} function TTarItem.Get_DiskFileName: WideString; begin result := FOwner.DiskFileName; end; {------------------------------------------------------------------------------} function TTarItem.Get_DiskPath: WideString; begin result := FOwner.DiskPath; end; {------------------------------------------------------------------------------} function TTarItem.Get_ExternalFileAttributes: TFileAttributes; begin result := TFileAttributes(FOwner.ExternalFileAttributes); end; {------------------------------------------------------------------------------} procedure TTarItem.Set_ExternalFileAttributes(Value: TFileAttributes); begin FOwner.ExternalFileAttributes := LongInt(Value); FParent.ZipArchive.IsDirty := True; end; {------------------------------------------------------------------------------} function TTarItem.Get_FileName: WideString; begin result := FOwner.FileName; end; {------------------------------------------------------------------------------} procedure TTarItem.Set_FileName(const Value: WideString); begin FOwner.FileName := Value; end; {------------------------------------------------------------------------------} function TTarItem.Get_IsEncrypted: WordBool; begin result := FOwner.IsEncrypted; end; {------------------------------------------------------------------------------} function TTarItem.Get_LastModFileDateTime: TDateTime; begin result := FileDateToDateTime((FOwner.LastModFileDate shl 16) + FOwner.LastModFileTime); end; {------------------------------------------------------------------------------} function TTarItem.Get_StoredPath: WideString; begin result := FOwner.StoredPath; end; {------------------------------------------------------------------------------} function TTarItem.Get_Tagged: WordBool; begin result := FOwner.Tagged; end; {------------------------------------------------------------------------------} procedure TTarItem.Set_Tagged(Value: WordBool); begin FOwner.Tagged := Value; end; {------------------------------------------------------------------------------} function TTarItem.Get_UnCompressedSize: Integer; begin result := FOwner.UncompressedSize; end; {------------------------------------------------------------------------------} function TTarItem.Get_Password: WideString; begin {!!!} //result := FOwner.Password; end; {------------------------------------------------------------------------------} procedure TTarItem.Set_Password(const Value: WideString); begin {!!!} //FOwner.Password := Value; //FParent.ZipArchive.IsDirty := True; end; {------------------------------------------------------------------------------} {ITarItem} {------------------------------------------------------------------------------} function TTarItem.Get_DevMajor: Integer; begin result := FOwner.DevMajor; end; {------------------------------------------------------------------------------} procedure TTarItem.Set_DevMajor(Value: Integer); begin FOwner.DevMajor := Value; FParent.ZipArchive.IsDirty := True; end; {------------------------------------------------------------------------------} function TTarItem.Get_DevMinor: Integer; begin result := FOwner.DevMinor; end; {------------------------------------------------------------------------------} procedure TTarItem.Set_DevMinor(Value: Integer); begin FOwner.DevMinor := Value; FParent.ZipArchive.IsDirty := True; end; {------------------------------------------------------------------------------} function TTarItem.Get_GroupID: Integer; begin result := FOwner.GroupID; end; {------------------------------------------------------------------------------} procedure TTarItem.Set_GroupID(Value: Integer); begin FOwner.GroupID := Value; FParent.ZipArchive.IsDirty := True; end; {------------------------------------------------------------------------------} function TTarItem.Get_GroupName: WideString; begin result := FOwner.GroupName; end; {------------------------------------------------------------------------------} procedure TTarItem.Set_GroupName(const Value: WideString); begin FOwner.GroupName := Value; FParent.ZipArchive.IsDirty := True; end; {------------------------------------------------------------------------------} function TTarItem.Get_LinkFlag: Byte; begin result := Byte(FOwner.LinkFlag); end; {------------------------------------------------------------------------------} procedure TTarItem.Set_LinkFlag(Value: Byte); begin FOwner.LinkFlag := AnsiChar(Value); FParent.ZipArchive.IsDirty := True; end; {------------------------------------------------------------------------------} function TTarItem.Get_LinkName: WideString; begin result := FOwner.LinkName; end; {------------------------------------------------------------------------------} procedure TTarItem.Set_LinkName(const Value: WideString); begin FOwner.LinkName := Value; FParent.ZipArchive.IsDirty := True; end; {------------------------------------------------------------------------------} function TTarItem.Get_Mode: Integer; begin result := FOwner.Mode; end; {------------------------------------------------------------------------------} procedure TTarItem.Set_Mode(Value: Integer); begin FOwner.Mode := Value; FParent.ZipArchive.IsDirty := True; end; {------------------------------------------------------------------------------} function TTarItem.Get_UserID: Integer; begin result := FOwner.UserID; end; {------------------------------------------------------------------------------} procedure TTarItem.Set_UserID(Value: Integer); begin FOwner.UserID := Value; FParent.ZipArchive.IsDirty := True; end; {------------------------------------------------------------------------------} function TTarItem.Get_UserName: WideString; begin result := FOwner.UserName; end; {------------------------------------------------------------------------------} procedure TTarItem.Set_UserName(const Value: WideString); begin FOwner.UserName := Value; FParent.ZipArchive.IsDirty := True; end; {------------------------------------------------------------------------------} end. ================================================ FILE: lib/abbrevia/source/COM/_ZipItem.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) unit _ZipItem; interface uses ComObj, Abbrevia_TLB, AbZipTyp, AbZipKit; type TZipItem = class(TAutoIntfObject, IZipItem) private FOwner : TAbZipItem; FParent : TAbZipKit; public constructor Create(AOwner : TAbZipItem; AParent : TAbZipKit); protected {IArchiveItem} function Get_Action: TArchiveAction; safecall; function Get_CompressedSize: Integer; safecall; function Get_CRC32: Integer; safecall; function Get_CRC32St: WideString; safecall; function Get_DiskFileName: WideString; safecall; function Get_DiskPath: WideString; safecall; function Get_ExternalFileAttributes: TFileAttributes; safecall; procedure Set_ExternalFileAttributes(Value: TFileAttributes); safecall; function Get_FileName: WideString; safecall; procedure Set_FileName(const Value: WideString); safecall; function Get_IsEncrypted: WordBool; safecall; function Get_LastModFileDateTime: TDateTime; safecall; function Get_StoredPath: WideString; safecall; function Get_Tagged: WordBool; safecall; procedure Set_Tagged(Value: WordBool); safecall; function Get_UnCompressedSize: Integer; safecall; function Get_Password: WideString; safecall; procedure Set_Password(const Value: WideString); safecall; {IZipItem} function Get_CompressionMethod: TZipCompressionMethod; safecall; function Get_CompressionRatio: Double; safecall; function Get_DeflateOption: TZipDeflateOption; safecall; function Get_DictionarySize: TZipDictionarySize; safecall; function Get_DiskNumberStart: Integer; safecall; function Get_ExtraField: WideString; safecall; procedure Set_ExtraField(const Value: WideString); safecall; function Get_FileComment: WideString; safecall; procedure Set_FileComment(const Value: WideString); safecall; function Get_InternalFileAttributes: Integer; safecall; procedure Set_InternalFileAttributes(Value: Integer); safecall; function Get_VersionMadeBy: Integer; safecall; function Get_VersionNeededToExtract: Integer; safecall; end; implementation uses ComServ, SysUtils; {------------------------------------------------------------------------------} constructor TZipItem.Create(AOwner : TAbZipItem; AParent : TAbZipKit); begin inherited Create(ComServer.TypeLib, IZipItem); FOwner := AOwner; FParent := AParent; end; {------------------------------------------------------------------------------} {IArchiveItem} {------------------------------------------------------------------------------} function TZipItem.Get_Action: TArchiveAction; begin Result := TArchiveAction(FOwner.Action); end; {------------------------------------------------------------------------------} function TZipItem.Get_CompressedSize: Integer; begin result := FOwner.CompressedSize; end; {------------------------------------------------------------------------------} function TZipItem.Get_CRC32: Integer; begin result := FOwner.CRC32; end; {------------------------------------------------------------------------------} function TZipItem.Get_CRC32St: WideString; begin result := IntToHex(FOwner.CRC32, 8); end; {------------------------------------------------------------------------------} function TZipItem.Get_DiskFileName: WideString; begin result := FOwner.DiskFileName; end; {------------------------------------------------------------------------------} function TZipItem.Get_DiskPath: WideString; begin result := FOwner.DiskPath; end; {------------------------------------------------------------------------------} function TZipItem.Get_ExternalFileAttributes: TFileAttributes; begin result := TFileAttributes(FOwner.ExternalFileAttributes); end; {------------------------------------------------------------------------------} procedure TZipItem.Set_ExternalFileAttributes(Value: TFileAttributes); begin FOwner.ExternalFileAttributes := LongInt(Value); FParent.ZipArchive.IsDirty := True; end; {------------------------------------------------------------------------------} function TZipItem.Get_FileName: WideString; begin result := FOwner.FileName; end; {------------------------------------------------------------------------------} procedure TZipItem.Set_FileName(const Value: WideString); begin FOwner.FileName := Value; end; {------------------------------------------------------------------------------} function TZipItem.Get_IsEncrypted: WordBool; begin result := FOwner.IsEncrypted; end; {------------------------------------------------------------------------------} function TZipItem.Get_LastModFileDateTime: TDateTime; begin result := FileDateToDateTime((FOwner.LastModFileDate shl 16) + FOwner.LastModFileTime); end; {------------------------------------------------------------------------------} function TZipItem.Get_StoredPath: WideString; begin result := FOwner.StoredPath; end; {------------------------------------------------------------------------------} function TZipItem.Get_Tagged: WordBool; begin result := FOwner.Tagged; end; {------------------------------------------------------------------------------} procedure TZipItem.Set_Tagged(Value: WordBool); begin FOwner.Tagged := Value; end; {------------------------------------------------------------------------------} function TZipItem.Get_UnCompressedSize: Integer; begin result := FOwner.UncompressedSize; end; {------------------------------------------------------------------------------} function TZipItem.Get_Password: WideString; begin Result := WideString(FParent.Password); end; {------------------------------------------------------------------------------} procedure TZipItem.Set_Password(const Value: WideString); begin FParent.Password := AnsiString(Value); FParent.ZipArchive.IsDirty := True; end; {------------------------------------------------------------------------------} {IZipItem} {------------------------------------------------------------------------------} function TZipItem.Get_CompressionMethod: TZipCompressionMethod; begin Result := TZipCompressionMethod(FOwner.CompressionMethod); end; {------------------------------------------------------------------------------} function TZipItem.Get_CompressionRatio: Double; begin result := FOwner.CompressionRatio; end; {------------------------------------------------------------------------------} function TZipItem.Get_DeflateOption: TZipDeflateOption; begin result := TZipDeflateOption(FOwner.DeflationOption); end; {------------------------------------------------------------------------------} function TZipItem.Get_DictionarySize: TZipDictionarySize; begin result := TZipDictionarySize(FOwner.DictionarySize); end; {------------------------------------------------------------------------------} function TZipItem.Get_DiskNumberStart: Integer; begin result := FOwner.DiskNumberStart; end; {------------------------------------------------------------------------------} function TZipItem.Get_ExtraField: WideString; begin result := ''; end; {------------------------------------------------------------------------------} procedure TZipItem.Set_ExtraField(const Value: WideString); begin end; {------------------------------------------------------------------------------} function TZipItem.Get_FileComment: WideString; begin result := WideString(FOwner.FileComment); end; {------------------------------------------------------------------------------} procedure TZipItem.Set_FileComment(const Value: WideString); begin FOwner.FileComment := AnsiString(Value); FParent.ZipArchive.IsDirty := True; end; {------------------------------------------------------------------------------} function TZipItem.Get_InternalFileAttributes: Integer; begin result := FOwner.InternalFileAttributes; end; {------------------------------------------------------------------------------} procedure TZipItem.Set_InternalFileAttributes(Value: Integer); begin FOwner.InternalFileAttributes := Value; FParent.ZipArchive.IsDirty := True; end; {------------------------------------------------------------------------------} function TZipItem.Get_VersionMadeBy: Integer; begin result := FOwner.VersionMadeBy; end; {------------------------------------------------------------------------------} function TZipItem.Get_VersionNeededToExtract: Integer; begin result := FOwner.VersionNeededToExtract; end; {------------------------------------------------------------------------------} end. ================================================ FILE: lib/abbrevia/source/COM/_ZipKit.pas ================================================ (* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is TurboPower Abbrevia * * The Initial Developer of the Original Code is * TurboPower Software * * Portions created by the Initial Developer are Copyright (C) 1997-2002 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * ***** END LICENSE BLOCK ***** *) unit _ZipKit; interface uses ComObj, Classes, Windows, Abbrevia_TLB, ActiveX, axctrls, AbZipKit, AbArcTyp, AbUtils, _ZipItem, _GZipItem, _TarItem, AbZipTyp, AbTarTyp, AbGzTyp, AbConst, AbBrowse; type {$IFNDEF VER130}{$WARN SYMBOL_PLATFORM OFF}{$ENDIF} TZipKit = class(TAutoObject, IConnectionPointContainer, IEnumVariant, IZipKit) private {private declarations} FConnectionPoints : TConnectionPoints; FEvents : IZipKitEvents; FOwner : TAbZipKit; FEnumPos : Integer; {Events for FOwner} procedure _OnArchiveItemProgress(Sender : TObject; Item : TAbArchiveItem; Progress : Byte; var Abort : Boolean); procedure _OnArchiveProgress(Sender : TObject; Progress : Byte; var Abort : Boolean); procedure _OnChange(Sender : TObject); procedure _OnConfirmOverwrite(var Name : string; var confirm : Boolean); procedure _OnConfirmProcessItem(Sender : TObject; Item : TAbArchiveItem; ProcessType : TAbProcessType; var Confirm : Boolean); procedure _OnConfirmSave(Sender : TObject; var Confirm : Boolean); procedure _OnLoad(Sender : TObject); procedure _OnNeedPassword(Sender : TObject; var NewPassword : AnsiString); procedure _OnProcessItemFailure(Sender : TObject; Item : TAbArchiveItem; ProcessType : TAbProcessType; ErrorClass : TAbErrorClass; ErrorCode : Integer); procedure _OnRequestBlankDisk(Sender : TObject; var Abort : Boolean); procedure _OnRequestImage(Sender : TObject; ImageNumber : Integer; var ImageName : string; var Abort : Boolean); procedure _OnRequestLastDisk(Sender : TObject; var Abort : Boolean); procedure _OnRequestNthDisk(Sender : TObject; DiskNumber : Byte; var Abort : Boolean); procedure _OnSave(Sender : TObject); public procedure Initialize; override; destructor Destroy; override; protected {IConnectionPointContainer} property ConnectionPoints: TConnectionPoints read FConnectionPoints implements IConnectionPointContainer; procedure EventSinkChanged(const EventSink: IUnknown); override; {IEnumVariant} function Next(celt: LongWord; var rgvar : OleVariant; out pceltFetched: LongWord): HResult; stdcall; function Skip(celt: LongWord): HResult; stdcall; function Reset: HResult; stdcall; function Clone(out Enum: IEnumVariant): HResult; stdcall; {IZipKit} procedure Add(const FileMask: WideString; const ExclusionMask: WideString; SearchAttr: Integer); safecall; procedure AddFromStream(const FileName: WideString; Stream: OleVariant); safecall; function Get_AutoSave: WordBool; safecall; procedure Set_AutoSave(Value: WordBool); safecall; function Get_BaseDirectory: WideString; safecall; procedure Set_BaseDirectory(const Value: WideString); safecall; procedure ClearTags; safecall; function Get_CompressionMethodToUse: TZipSupportMethod; safecall; procedure Set_CompressionMethodToUse(Value: TZipSupportMethod); safecall; function Get_Count: Integer; safecall; function Get_DeflateOption: TZipDeflateOption; safecall; procedure Set_DeflateOption(Value: TZipDeflateOption); safecall; procedure Delete(const FileMask: WideString; const ExclusionMask: WideString); safecall; procedure DeleteAt(Index: Integer); safecall; procedure DeleteTaggedItems; safecall; function Get_DOSMode: WordBool; safecall; procedure Set_DOSMode(Value: WordBool); safecall; procedure Extract(const FileMask: WideString; const ExclusionMask: WideString); safecall; procedure ExtractAt(Index: Integer; const NewName: WideString); safecall; function Get_ExtractOptions: TZipExtractOptions; safecall; procedure Set_ExtractOptions(Value: TZipExtractOptions); safecall; procedure ExtractTaggedItems; safecall; function Get_FileName: WideString; safecall; procedure Set_FileName(const Value: WideString); safecall; function Find(const FileName: WideString): Integer; safecall; procedure Freshen(const FileMask: WideString; const ExclusionMask: WideString); safecall; procedure FreshenTaggedItems; safecall; function Get_Item(Index: Integer): IDispatch; safecall; function Get_LogFile: WideString; safecall; procedure Set_LogFile(const Value: WideString); safecall; function Get_Logging: WordBool; safecall; procedure Set_Logging(Value: WordBool); safecall; function Get_Password: WideString; safecall; procedure Set_Password(const Value: WideString); safecall; function Get_PasswordRetries: Byte; safecall; procedure Set_PasswordRetries(Value: Byte); safecall; procedure Replace(const FileMask: WideString); safecall; procedure Save; safecall; function Get_Spanned: WordBool; safecall; function Get_SpanningThreshold: Integer; safecall; procedure Set_SpanningThreshold(Value: Integer); safecall; function Get_Status: TArchiveStatus; safecall; function Get_StoreOptions: TStoreOptions; safecall; procedure Set_StoreOptions(Value: TStoreOptions); safecall; procedure TagItems(const FileMask: WideString); safecall; function Get_TempDirectory: WideString; safecall; procedure Set_TempDirectory(const Value: WideString); safecall; procedure TestTaggedItems; safecall; procedure UntagItems(const FileMask: WideString); safecall; function Get_ZipFileComment: WideString; safecall; procedure Set_ZipFileComment(const Value: WideString); safecall; function License(const Key: WideString): WordBool; safecall; function Get__NewEnum: IUnknown; safecall; function ExtractToStream(const FileName: WideString): OleVariant; safecall; function Get_CompressionType: TArchiveType; safecall; procedure Set_CompressionType(Value: TArchiveType); safecall; function Get_TarAutoHandle: WordBool; safecall; procedure Set_TarAutoHandle(Value: WordBool); safecall; end; implementation uses ComServ; {------------------------------------------------------------------------------} {IConnectionPointContainer} {------------------------------------------------------------------------------} procedure TZipKit.EventSinkChanged(const EventSink: IUnknown); begin FEvents := EventSink as IZipKitEvents; end; {------------------------------------------------------------------------------} {IEnumVariant} {------------------------------------------------------------------------------} function TZipKit.Next(celt: LongWord; var rgvar : OleVariant; out pceltFetched: LongWord): HResult; stdcall; var V : OleVariant; I : Integer; begin Result := S_FALSE; try if @pceltFetched <> nil then pceltFetched := 0; for I := 0 to celt - 1 do begin if FEnumPos >= FOwner.Count then begin FEnumPos := 0; Exit; end; V := Get_Item(FEnumPos); PVariantArgList(@rgvar)[I] := TVariantArg(V); { Prevent COM garbage collection } TVarData(V).VType := varEmpty; TVarData(V).VInteger := 0; Inc(FEnumPos); if @pceltFetched <> nil then Inc(pceltFetched); end; except end; if (@pceltFetched = nil) or (pceltFetched = celt) then Result := S_OK; end; {------------------------------------------------------------------------------} function TZipKit.Skip(celt: LongWord): HResult; begin Inc(FEnumPos, celt); Result := S_OK; end; {------------------------------------------------------------------------------} function TZipKit.Reset: HResult; begin FEnumPos := 0; Result := S_OK; end; {------------------------------------------------------------------------------} function TZipKit.Clone(out Enum: IEnumVariant): HResult; begin Enum := nil; Result := S_OK; try Enum := Self.Create; TZipKit(Enum).FOwner := FOwner; except Result := E_OUTOFMEMORY; end; end; {------------------------------------------------------------------------------} {IZipKit} {------------------------------------------------------------------------------} procedure TZipKit.Add(const FileMask: WideString; const ExclusionMask: WideString; SearchAttr: Integer); begin FOwner.AddFilesEx(FileMask, ExclusionMask, SearchAttr); end; {------------------------------------------------------------------------------} procedure TZipKit.AddFromStream(const FileName: WideString; Stream: OleVariant); var InStream : TMemoryStream; Info : array of Byte; begin Info := nil; InStream := TMemoryStream.Create; try Info := Stream; InStream.Write(Info[0], Length(Info)); InStream.Position := 0; FOwner.AddFromStream(FileName, InStream); finally InStream.Free; end; end; {------------------------------------------------------------------------------} function TZipKit.Get_AutoSave: WordBool; begin Result := FOwner.AutoSave; end; {------------------------------------------------------------------------------} procedure TZipKit.Set_AutoSave(Value: WordBool); begin FOwner.AutoSave := Value; end; {------------------------------------------------------------------------------} function TZipKit.Get_BaseDirectory: WideString; begin Result := FOwner.BaseDirectory; end; {------------------------------------------------------------------------------} procedure TZipKit.Set_BaseDirectory(const Value: WideString); begin FOwner.BaseDirectory := Value; end; {------------------------------------------------------------------------------} procedure TZipKit.ClearTags; begin FOwner.ClearTags; end; {------------------------------------------------------------------------------} function TZipKit.Get_CompressionMethodToUse: TZipSupportMethod; begin Result := TZipCompressionMethod(FOwner.CompressionMethodToUse); end; {------------------------------------------------------------------------------} procedure TZipKit.Set_CompressionMethodToUse(Value: TZipSupportMethod); begin FOwner.CompressionMethodToUse := TAbZipSupportedMethod(Value); end; {------------------------------------------------------------------------------} function TZipKit.Get_Count: Integer; begin Result := FOwner.Count; end; {------------------------------------------------------------------------------} function TZipKit.Get_DeflateOption: TZipDeflateOption; begin Result := TZipDeflateOption(FOwner.DeflationOption); end; {------------------------------------------------------------------------------} procedure TZipKit.Set_DeflateOption(Value: TZipDeflateOption); begin FOwner.DeflationOption := TAbZipDeflationOption(Value); end; {------------------------------------------------------------------------------} procedure TZipKit.Delete(const FileMask: WideString; const ExclusionMask: WideString); begin FOwner.DeleteFilesEx(FileMask, ExclusionMask); end; {------------------------------------------------------------------------------} procedure TZipKit.DeleteAt(Index: Integer); begin FOwner.DeleteAt(Index); end; {------------------------------------------------------------------------------} procedure TZipKit.DeleteTaggedItems; begin FOwner.DeleteTaggedItems; end; {------------------------------------------------------------------------------} function TZipKit.Get_DOSMode: WordBool; begin Result := FOwner.DOSMode; end; {------------------------------------------------------------------------------} procedure TZipKit.Set_DOSMode(Value: WordBool); begin FOwner.DOSMode := Value; end; {------------------------------------------------------------------------------} procedure TZipKit.Extract(const FileMask: WideString; const ExclusionMask: WideString); begin FOwner.ExtractFilesEx(FileMask, ExclusionMask); end; {------------------------------------------------------------------------------} procedure TZipKit.ExtractAt(Index: Integer; const NewName: WideString); begin FOwner.ExtractAt(Index, NewName); end; {------------------------------------------------------------------------------} function TZipKit.Get_ExtractOptions: TZipExtractOptions; begin Result := 0; if TAbExtractOption(eoCreateDirs) in FOwner.ExtractOptions then Result := Result + TZipExtractOptions(eoCreateDirs); if TAbExtractOption(eoRestorePath) in FOwner.ExtractOptions then Result := Result + TZipExtractOptions(eoRestorePath); end; {------------------------------------------------------------------------------} procedure TZipKit.Set_ExtractOptions(Value: TZipExtractOptions); var TempOptions : TAbExtractOptions; begin TempOptions := []; if (Value or Abbrevia_TLB.eoCreateDirs) = Value then Include(TempOptions, AbArcTyp.eoCreateDirs); if (Value or Abbrevia_TLB.eoRestorePath) = Value then Include(TempOptions, AbArcTyp.eoRestorePath); FOwner.ExtractOptions := TempOptions end; {------------------------------------------------------------------------------} procedure TZipKit.ExtractTaggedItems; begin FOwner.ExtractTaggedItems; end; {------------------------------------------------------------------------------} function TZipKit.Get_FileName: WideString; begin Result := FOwner.FileName; end; {------------------------------------------------------------------------------} procedure TZipKit.Set_FileName(const Value: WideString); begin FOwner.FileName := Value; end; {------------------------------------------------------------------------------} function TZipKit.Find(const FileName: WideString): Integer; begin Result := FOwner.FindFile(FileName); end; {------------------------------------------------------------------------------} procedure TZipKit.Freshen(const FileMask: WideString; const ExclusionMask: WideString); begin FOwner.FreshenFilesEx(FileMask, ExclusionMask); end; {------------------------------------------------------------------------------} procedure TZipKit.FreshenTaggedItems; begin FOwner.FreshenTaggedItems; end; {------------------------------------------------------------------------------} function TZipKit.Get_Item(Index: Integer): IDispatch; begin Result := TZipItem.Create(FOwner.Items[Index], FOwner); end; {------------------------------------------------------------------------------} function TZipKit.Get_LogFile: WideString; begin Result := FOwner.LogFile; end; {------------------------------------------------------------------------------} procedure TZipKit.Set_LogFile(const Value: WideString); begin FOwner.LogFile := Value; end; {------------------------------------------------------------------------------} function TZipKit.Get_Logging: WordBool; begin Result := FOwner.Logging; end; {------------------------------------------------------------------------------} procedure TZipKit.Set_Logging(Value: WordBool); begin FOwner.Logging := Value; end; {------------------------------------------------------------------------------} function TZipKit.Get_Password: WideString; begin Result := WideString(FOwner.Password); end; {------------------------------------------------------------------------------} procedure TZipKit.Set_Password(const Value: WideString); begin FOwner.Password := AnsiString(Value); end; {------------------------------------------------------------------------------} function TZipKit.Get_PasswordRetries: Byte; begin Result := FOwner.PasswordRetries; end; {------------------------------------------------------------------------------} procedure TZipKit.Set_PasswordRetries(Value: Byte); begin FOwner.PasswordRetries := Value; end; {------------------------------------------------------------------------------} procedure TZipKit.Replace(const FileMask: WideString); begin FOwner.Replace(FOwner.Items[FOwner.FindFile(FileMask)]); end; {------------------------------------------------------------------------------} procedure TZipKit.Save; begin FOwner.Save; end; {------------------------------------------------------------------------------} function TZipKit.Get_Spanned: WordBool; begin Result := FOwner.Spanned; end; {------------------------------------------------------------------------------} function TZipKit.Get_SpanningThreshold: Integer; begin Result := FOwner.SpanningThreshold; end; {------------------------------------------------------------------------------} procedure TZipKit.Set_SpanningThreshold(Value: Integer); begin FOwner.SpanningThreshold := Value; end; {------------------------------------------------------------------------------} function TZipKit.Get_Status: TArchiveStatus; begin Result := TArchiveStatus(FOwner.Status); end; {------------------------------------------------------------------------------} function TZipKit.Get_StoreOptions: TStoreOptions; begin Result := 0; if TAbStoreOption(soStripDrive) in FOwner.StoreOptions then Result := Result + TStoreOptions(soStripDrive); if TAbStoreOption(soStripPath) in FOwner.StoreOptions then Result := Result + TStoreOptions(soStripPath); if TAbStoreOption(soRemoveDots) in FOwner.StoreOptions then Result := Result + TStoreOptions(soRemoveDots); if TAbStoreOption(soRecurse) in FOwner.StoreOptions then Result := Result + TStoreOptions(soRecurse); if TAbStoreOption(soFreshen) in FOwner.StoreOptions then Result := Result + TStoreOptions(soFreshen); if TAbStoreOption(soReplace) in FOwner.StoreOptions then Result := Result + TStoreOptions(soReplace); end; {------------------------------------------------------------------------------} procedure TZipKit.Set_StoreOptions(Value: TStoreOptions); var TempOptions : TAbStoreOptions; begin TempOptions := []; if (Value or Abbrevia_TLB.soStripDrive) = Value then Include(TempOptions, AbArcTyp.soStripDrive); if (Value or Abbrevia_TLB.soStripPath) = Value then Include(TempOptions, AbArcTyp.soStripPath); if (Value or Abbrevia_TLB.soRemoveDots) = Value then Include(TempOptions, AbArcTyp.soRemoveDots); if (Value or Abbrevia_TLB.soRecurse) = Value then Include(TempOptions, AbArcTyp.soRecurse); if (Value or Abbrevia_TLB.soFreshen) = Value then Include(TempOptions, AbArcTyp.soFreshen); if (Value or Abbrevia_TLB.soReplace) = Value then Include(TempOptions, AbArcTyp.soReplace); FOwner.StoreOptions := TempOptions end; {------------------------------------------------------------------------------} procedure TZipKit.TagItems(const FileMask: WideString); begin FOwner.TagItems(FileMask); end; {------------------------------------------------------------------------------} function TZipKit.Get_TempDirectory: WideString; begin Result := FOwner.TempDirectory; end; {------------------------------------------------------------------------------} procedure TZipKit.Set_TempDirectory(const Value: WideString); begin FOwner.TempDirectory := Value; end; {------------------------------------------------------------------------------} procedure TZipKit.TestTaggedItems; begin FOwner.TestTaggedItems; end; {------------------------------------------------------------------------------} procedure TZipKit.UntagItems(const FileMask: WideString); begin FOwner.UnTagItems(FileMask); end; {------------------------------------------------------------------------------} function TZipKit.Get_ZipFileComment: WideString; begin Result := WideString(FOwner.ZipFileComment); end; {------------------------------------------------------------------------------} procedure TZipKit.Set_ZipFileComment(const Value: WideString); begin FOwner.ZipfileComment := AnsiString(Value); end; {------------------------------------------------------------------------------} function TZipKit.License(const Key: WideString): WordBool; begin Result := True; end; {------------------------------------------------------------------------------} function TZipKit.Get__NewEnum: IUnknown; begin Result := Self; end; {------------------------------------------------------------------------------} function TZipKit.ExtractToStream(const FileName: WideString): OleVariant; var Stream : TMemoryStream; Info : array of Byte; begin Stream := TMemoryStream.Create; try FOwner.ExtractToStream(FileName, Stream); Stream.Position := 0; SetLength(Info, Stream.Size); Stream.Read(Info[0], Stream.Size); Result := Info; finally Stream.Free; end; end; {------------------------------------------------------------------------------} function TZipKit.Get_CompressionType: TArchiveType; begin Result := TArchiveType((FOwner as TAbBaseBrowser).ArchiveType); end; {------------------------------------------------------------------------------} procedure TZipKit.Set_CompressionType(Value: TArchiveType); begin (FOwner as TAbBaseBrowser).ArchiveType := TAbArchiveType(ord(Value)); end; {------------------------------------------------------------------------------} function TZipKit.Get_TarAutoHandle: WordBool; begin Result := FOwner.TarAutoHandle; end; {------------------------------------------------------------------------------} procedure TZipKit.Set_TarAutoHandle(Value: WordBool); begin FOwner.TarAutoHandle := Value; end; {------------------------------------------------------------------------------} {TZipKit Events} {------------------------------------------------------------------------------} procedure TZipKit._OnArchiveItemProgress(Sender : TObject; Item : TAbArchiveItem; Progress : Byte; var Abort : Boolean); var FAbort : WordBool; begin FAbort := Abort; if Assigned(FEvents) then begin if ((FOwner as TAbBaseBrowser).ArchiveType = atZip) then FEvents.OnArchiveItemProgress(TZipItem.Create(TAbZipItem(Item), FOwner), Progress, FAbort) else if ((FOwner as TAbBaseBrowser).ArchiveType = atTar) then FEvents.OnArchiveItemProgress(TTarItem.Create(TAbTarItem(Item), FOwner), Progress, FAbort) else if ((FOwner as TAbBaseBrowser).ArchiveType = atGZip) then FEvents.OnArchiveItemProgress(TGZipItem.Create(TAbGZipItem(Item), FOwner), Progress, FAbort); end; Abort := FAbort; end; {------------------------------------------------------------------------------} procedure TZipKit._OnArchiveProgress(Sender : TObject; Progress : Byte; var Abort : Boolean); var FAbort : WordBool; begin FAbort := Abort; if Assigned(FEvents) then FEvents.OnArchiveProgress(Progress, FAbort); Abort := FAbort; end; {------------------------------------------------------------------------------} procedure TZipKit._OnChange(Sender : TObject); begin if Assigned(FEvents) then FEvents.OnChange; end; {------------------------------------------------------------------------------} procedure TZipKit._OnConfirmOverwrite(var Name : string; var confirm : Boolean); var FConfirm : WordBool; FName : WideString; begin FConfirm := Confirm; FName := Name; if Assigned(FEvents) then FEvents.OnConfirmOverwrite(FName, FConfirm); Name := FName; Confirm := FConfirm; end; {------------------------------------------------------------------------------} procedure TZipKit._OnConfirmProcessItem(Sender : TObject; Item : TAbArchiveItem; ProcessType : TAbProcessType; var Confirm : Boolean); var FConfirm : WordBool; begin FConfirm := Confirm; if Assigned(FEvents) then begin if ((FOwner as TAbBaseBrowser).ArchiveType = atZip) then FEvents.OnConfirmProcessItem(TZipItem.Create(TAbZipItem(Item), FOwner), TProcessType(ProcessType), FConfirm) else if ((FOwner as TAbBaseBrowser).ArchiveType = atTar) then FEvents.OnConfirmProcessItem(TTarItem.Create(TAbTarItem(Item), FOwner), TProcessType(ProcessType), FConfirm) else if ((FOwner as TAbBaseBrowser).ArchiveType = atGZip) then FEvents.OnConfirmProcessItem(TGZipItem.Create(TAbGZipItem(Item), FOwner), TProcessType(ProcessType), FConfirm); end; Confirm := FConfirm end; {------------------------------------------------------------------------------} procedure TZipKit._OnConfirmSave(Sender : TObject; var Confirm : Boolean); var FConfirm : WordBool; begin FConfirm := Confirm; if Assigned(FEvents) then FEvents.OnConfirmSave(FConfirm); Confirm := FConfirm; end; {------------------------------------------------------------------------------} procedure TZipKit._OnLoad(Sender : TObject); begin if Assigned(FEvents) then FEvents.OnLoad; end; {------------------------------------------------------------------------------} procedure TZipKit._OnNeedPassword(Sender : TObject; var NewPassword : AnsiString); var FNewPassword : WideString; begin FNewPassword := WideString(NewPassword); if Assigned(FEvents) then FEvents.OnNeedPassword(FNewPassword); NewPassword := AnsiString(FNewPassword); end; {------------------------------------------------------------------------------} procedure TZipKit._OnProcessItemFailure(Sender : TObject; Item : TAbArchiveItem; ProcessType : TAbProcessType; ErrorClass : TAbErrorClass; ErrorCode : Integer); begin if Assigned(FEvents) then begin if ((FOwner as TAbBaseBrowser).ArchiveType = atZip) then FEvents.OnProcessItemFailure(TZipItem.Create(TAbZipItem(Item), FOwner), TProcessType(ProcessType), TErrorClass(ErrorClass), TErrorCode(ErrorCode), AbStrRes(ErrorCode)) else if ((FOwner as TAbBaseBrowser).ArchiveType = atTar) then FEvents.OnProcessItemFailure(TTarItem.Create(TAbTarItem(Item), FOwner), TProcessType(ProcessType), TErrorClass(ErrorClass), TErrorCode(ErrorCode),AbStrRes(ErrorCode)) else if ((FOwner as TAbBaseBrowser).ArchiveType = atGZip) then FEvents.OnProcessItemFailure(TGZipItem.Create(TAbGZipItem(Item), FOwner), TProcessType(ProcessType), TErrorClass(ErrorClass), TErrorCode(ErrorCode),AbStrRes(ErrorCode)); end; end; {------------------------------------------------------------------------------} procedure TZipKit._OnRequestBlankDisk(Sender : TObject; var Abort : Boolean); var FAbort : WordBool; begin FAbort := Abort; if Assigned(FEvents) then FEvents.OnRequestBlankDisk(FAbort); Abort := FAbort; end; {------------------------------------------------------------------------------} procedure TZipKit._OnRequestImage(Sender : TObject; ImageNumber : Integer; var ImageName : string; var Abort : Boolean); var FImageName : WideString; FAbort : WordBool; begin FImageName := ImageName; FAbort := Abort; if Assigned(FEvents) then FEvents.OnRequestImage(ImageNumber, FImageName, FAbort); Abort := FAbort; ImageName := FImageName; end; {------------------------------------------------------------------------------} procedure TZipKit._OnRequestLastDisk(Sender : TObject; var Abort : Boolean); var FAbort : WordBool; begin FAbort := Abort; if Assigned(FEvents) then FEvents.OnRequestLastDisk(FAbort); Abort := FAbort; end; {------------------------------------------------------------------------------} procedure TZipKit._OnRequestNthDisk(Sender : TObject; DiskNumber : Byte; var Abort : Boolean); var FAbort : WordBool; begin FAbort := Abort; if Assigned(FEvents) then FEvents.OnRequestNthDisk(DiskNumber, FAbort); Abort := FAbort; end; {------------------------------------------------------------------------------} procedure TZipKit._OnSave(Sender : TObject); begin if Assigned(FEvents) then FEvents.OnSave; end; {------------------------------------------------------------------------------} procedure TZipKit.Initialize; begin inherited Initialize; FConnectionPoints := TConnectionPoints.Create(Self); if AutoFactory.EventTypeInfo <> nil then FConnectionPoints.CreateConnectionPoint(AutoFactory.EventIID, ckSingle, EventConnect); FOwner := AbZipKit.TAbZipKit.Create(nil); FOwner.OnArchiveItemProgress := _OnArchiveItemProgress; FOwner.OnArchiveProgress := _OnArchiveProgress; FOwner.OnChange := _OnChange; FOwner.OnConfirmOverwrite := _OnConfirmOverwrite; FOwner.OnConfirmProcessItem := _OnConfirmProcessItem; FOwner.OnConfirmSave := _OnConfirmSave; FOwner.OnLoad := _OnLoad; FOwner.OnNeedPassword := _OnNeedPassword; FOwner.OnProcessItemFailure := _OnProcessItemFailure; FOwner.OnRequestBlankDisk := _OnRequestBlankDisk; FOwner.OnRequestImage := _OnRequestImage; FOwner.OnRequestLastDisk := _OnRequestLastDisk; FOwner.OnRequestNthDisk := _OnRequestNthDisk; FOwner.OnSave := _OnSave; FEnumPos := 0; end; {------------------------------------------------------------------------------} destructor TZipKit.Destroy; begin FOwner.Free; inherited Destroy; end; {------------------------------------------------------------------------------} initialization TAutoObjectFactory.Create(ComServer, TZipKit, Class_ZipKit, ciMultiInstance, tmBoth); end. ================================================ FILE: lib/mte/CRC32.pas ================================================ unit CRC32; interface type Long = record LoWord: Word; HiWord: Word; end; // exported functions function FileCRC32(FileName: string): string; function StrCRC32(input: string): string; const CRCPOLY = $EDB88320; var CRCTable: array[0..512] Of Longint; implementation {$WARNINGS OFF} uses SysUtils; procedure BuildCRCTable; var i, j: Word; r: Longint; begin FillChar(CRCTable, SizeOf(CRCTable), 0); for i := 0 to 255 do begin r := i shl 1; for j := 8 downto 0 do if (r and 1) <> 0 then r := (r Shr 1) xor CRCPOLY else r := r shr 1; CRCTable[i] := r; end; end; function RecountCRC(b: byte; CrcOld: Longint): Longint; begin RecountCRC := CRCTable[byte(CrcOld xor Longint(b))] xor ((CrcOld shr 8) and $00FFFFFF) end; function HextW(w: Word): string; const h: array[0..15] Of char = '0123456789ABCDEF'; begin HextW := ''; HextW := h[Hi(w) shr 4] + h[Hi(w) and $F] + h[Lo(w) shr 4]+h[Lo(w) and $F]; end; function HextL(l: Longint): string; begin with Long(l) do HextL := HextW(HiWord) + HextW(LoWord); end; function FileCRC32(FileName: string): string; var Buffer: PChar; F: File of Byte; B: array[0..255] of Byte; CRC: Longint; e, i: Integer; begin BuildCRCTable; CRC := $FFFFFFFF; AssignFile(F, FileName); FileMode := 0; Reset(F); GetMem(Buffer, SizeOf(B)); repeat FillChar(B, SizeOf(B), 0); BlockRead(F, B, SizeOf(B), e); for i := 0 to (e-1) do CRC := RecountCRC(b[i], CRC); until (e < 255) or (IOresult <> 0); FreeMem(Buffer, SizeOf(B)); CloseFile(F); CRC := Not CRC; Result := HextL(CRC); end; function StrCRC32(input: string): string; var B: TArray; CRC: Longint; i: Integer; begin BuildCRCTable; CRC := $FFFFFFFF; B := TEncoding.UTF8.GetBytes(input); for i := 0 to Pred(Length(B)) do CRC := RecountCRC(B[i], CRC); CRC := Not CRC; Result := HextL(CRC); end; end. ================================================ FILE: lib/mte/RttiIni.pas ================================================ unit RttiIni; interface uses SysUtils, Classes, Rtti, TypInfo, IniFiles; type IniSectionAttribute = class(TCustomAttribute) private FSection: string; public constructor Create(const aSection: String); property Section: string read FSection write FSection; end; TRttiIni = class (TObject) private class function ReadValue(section: string; var ini: TMemIniFile; field: TRttiField): TValue; class procedure WriteValue(section: string; var ini: TMemIniFile; field: TRttiField; aValue: TValue); class function GetIniAttribute(Obj: TRttiObject): IniSectionAttribute; public class procedure Load(filename: string; obj: TObject); class procedure Save(filename: string; obj: TObject); end; implementation { TIniSection } constructor IniSectionAttribute.Create(const aSection: String); begin FSection := aSection; end; { TIniPersist } class function TRttiIni.GetIniAttribute(Obj: TRttiObject): IniSectionAttribute; var Attr: TCustomAttribute; begin for Attr in Obj.GetAttributes do begin if Attr is IniSectionAttribute then exit(IniSectionAttribute(Attr)); end; result := nil; end; class procedure TRttiIni.Load(filename: string; obj: TObject); var ctx: TRttiContext; objType: TRttiType; Field: TRttiField; IniSection: IniSectionAttribute; Ini: TMemIniFile; CurrentSection: string; value: TValue; begin ctx := TRttiContext.Create; try Ini := TMemIniFile.Create(FileName); try objType := ctx.GetType(Obj.ClassInfo); for Field in objType.GetFields do begin IniSection := GetIniAttribute(Field); if Assigned(IniSection) then CurrentSection := IniSection.Section; value := ReadValue(CurrentSection, ini, Field); if not value.IsEmpty then field.SetValue(obj, value); end; finally Ini.Free; end; finally ctx.Free; end; end; class function TRttiIni.ReadValue(section: string; var ini: TMemIniFile; field: TRttiField): TValue; var fieldType: string; begin Result := TValue.Empty; fieldType := field.FieldType.Name; // exit if value doesn't exist in ini being loaded // this allows us to use default values from the object's constructor if not ini.ValueExists(section, field.Name) then exit; // load string, Integer, and Boolean fields from ini if fieldType = 'string' then Result := TValue.From(ini.ReadString(section, field.Name, '')) else if fieldType = 'Integer' then Result := TValue.From(ini.ReadInteger(section, field.Name, 0)) else if fieldType = 'Int64' then Result := TValue.From(ini.ReadInteger(section, field.Name, 0)) else if fieldType = 'TDateTime' then Result := TValue.From(ini.ReadFloat(section, field.Name, 0)) else if fieldType = 'Boolean' then Result := TValue.From(ini.ReadBool(section, field.Name, false)); end; class procedure TRttiIni.WriteValue(section: string; var ini: TMemIniFile; field: TRttiField; aValue: TValue); var fieldType: string; begin fieldType := field.FieldType.Name; if fieldType = 'string' then ini.WriteString(section, field.Name, aValue.AsString) else if fieldType = 'Integer' then ini.WriteInteger(section, field.Name, aValue.AsInteger) else if fieldType = 'Int64' then ini.WriteInteger(section, field.Name, aValue.AsInt64) else if fieldType = 'TDateTime' then ini.WriteFloat(section, field.Name, aValue.AsType) else if fieldType = 'Boolean' then ini.WriteBool(section, field.Name, aValue.AsBoolean) end; class procedure TRttiIni.Save(filename: string; obj: TObject); var ctx: TRttiContext; objType: TRttiType; field: TRttiField; IniSection: IniSectionAttribute; ini: TMemIniFile; CurrentSection: string; begin ctx := TRttiContext.Create; try ini := TMemIniFile.Create(FileName); try objType := ctx.GetType(Obj.ClassInfo); for field in objType.GetFields do begin IniSection := GetIniAttribute(Field); if Assigned(IniSection) then CurrentSection := IniSection.Section; WriteValue(CurrentSection, ini, field, Field.GetValue(obj)); end; finally Ini.UpdateFile; Ini.Free; end; finally ctx.Free; end; end; end. ================================================ FILE: lib/mte/RttiJson.pas ================================================ unit RttiJson; interface uses SysUtils, Rtti, // superobject json library superobject; type TRttiJson = class (TObject) public class function ToJson(obj: TObject): string; class function FromJson(json: string; classType: TClass): TObject; end; implementation class function TRttiJson.ToJson(obj: TObject): string; var rtype: TRTTIType; field: TRTTIField; fieldType: string; jsonObj: ISuperObject; date: TDateTime; begin jsonObj := SO; rtype := TRTTIContext.Create.GetType(obj.ClassType); // loop through fields for field in rType.GetFields do begin fieldType := field.FieldType.ToString; // handle datatypes I use if (fieldType = 'string') then jsonObj.S[field.Name] := field.GetValue(obj).ToString else if (fieldType = 'Integer') then jsonObj.I[field.Name] := field.GetValue(obj).AsInteger else if (fieldType = 'TDateTime') then begin date := StrToFloat(field.GetValue(obj).ToString); jsonObj.S[field.Name] := DateTimeToStr(date); end; end; Result := jsonObj.AsJSon; end; { Example usage: report := TReport(FromJson(reportJson, TReport)); } class function TRttiJson.FromJson(json: string; classType: TClass): TObject; var rtype: TRTTIType; field: TRTTIField; fieldType: string; context: TRTTIContext; jsonObj: ISuperObject; date: TDateTime; begin jsonObj := SO(PChar(json)); context := TRTTIContext.Create; rtype := context.GetType(classType); Result := classType.Create; // loop through fields for field in rType.GetFields do begin fieldType := field.FieldType.ToString; // handle datatypes I use if (fieldType = 'string') then field.SetValue(Result, jsonObj.S[field.Name]) else if (fieldType = 'Integer') then field.SetValue(Result, jsonObj.I[field.Name]) else if (fieldType = 'TDateTime') then begin date := StrToDateTime(jsonObj.S[field.Name]); field.SetValue(Result, TValue.From(date)); end; end; context.Free; end; end. ================================================ FILE: lib/mte/RttiTranslation.pas ================================================ unit RttiTranslation; interface uses SysUtils, Classes, StdCtrls, ComCtrls, Buttons, Menus, Rtti, TypInfo; type FormPrefixAttribute = class(TCustomAttribute) private FPrefix: string; public constructor Create(const aPrefix: String); property Prefix: string read FPrefix write FPrefix; end; FormSectionAttribute = class(TCustomAttribute) private FSection: string; public constructor Create(const aSection: String); property Section: string read FSection write FSection; end; TRttiTranslation = class (TObject) private class function ReadValue(section: string; var sl: TStringList; field: TRttiField; subfield: string): string; class procedure WriteValue(section: string; value: string; var sl: TStringList; field: TRttiField; subfield: string); class function GetPrefixAttribute(Obj: TRttiObject): FormPrefixAttribute; class function GetSectionAttribute(Obj: TRttiObject): FormSectionAttribute; public class procedure Load(filename: string; obj: TObject); overload; class procedure Load(var sl: TStringList; obj: TObject); overload; class procedure Save(filename: string; obj: TObject); end; implementation { FormPrefixAttribute } constructor FormPrefixAttribute.Create(const aPrefix: String); begin FPrefix := aPrefix; end; { FormSectionAttribute } constructor FormSectionAttribute.Create(const aSection: String); begin FSection := aSection; end; { TRttiTranslation } class function TRttiTranslation.GetPrefixAttribute(Obj: TRttiObject): FormPrefixAttribute; var Attr: TCustomAttribute; begin for Attr in Obj.GetAttributes do begin if Attr is FormPrefixAttribute then exit(FormPrefixAttribute(Attr)); end; result := nil; end; class function TRttiTranslation.GetSectionAttribute(Obj: TRttiObject): FormSectionAttribute; var Attr: TCustomAttribute; begin for Attr in Obj.GetAttributes do begin if Attr is FormSectionAttribute then exit(FormSectionAttribute(Attr)); end; result := nil; end; class procedure TRttiTranslation.Load(filename: string; obj: TObject); var sl: TStringList; begin sl := TStringList.Create; try sl.LoadFromFile(filename); TRttiTranslation.Load(sl, obj); finally sl.Free; end; end; class procedure TRttiTranslation.Load(var sl: TStringList; obj: TObject); var ctx: TRttiContext; objType: TRttiType; Field: TRttiField; FormPrefix: FormPrefixAttribute; FormSection: FormSectionAttribute; CurrentPrefix, CurrentSection, FieldName, value: string; aCheckBox: TCheckBox; aButton: TButton; aLabel: TLabel; aTabSheet: TTabSheet; aGroupBox: TGroupBox; aSpeedButton: TSpeedButton; aMenuItem: TMenuItem; aComboBox: TComboBox; aListView: TListView; i: Integer; begin FormPrefix := nil; ctx := TRttiContext.Create; try objType := ctx.GetType(Obj.ClassInfo); for Field in objType.GetFields do begin // START BY FINDING FORM PREFIX, SKIP FIELDS UNTIL FOUND if not Assigned(FormPrefix) then begin FormPrefix := GetPrefixAttribute(Field); if Assigned(FormPrefix) then CurrentPrefix := FormPrefix.Prefix else continue; end; // IF FORM SECTION, DUMP SECTION FormSection := GetSectionAttribute(Field); if Assigned(FormSection) then CurrentSection := FormSection.Section; // SKIP ALL ITEMS IN 'DontTranslate' SECTION if CurrentSection = 'DontTranslate' then continue; // LOAD VALUES FieldName := Field.FieldType.Name; if FieldName = 'TCheckBox' then begin aCheckBox := TCheckBox(field.GetValue(obj).AsType); if Assigned(aCheckBox) then begin value := ReadValue(CurrentPrefix, sl, Field, 'Caption'); if value <> '' then aCheckBox.Caption := value; value := ReadValue(CurrentPrefix, sl, Field, 'Hint'); aCheckBox.ShowHint := value <> ''; if aCheckBox.ShowHint then aCheckBox.Hint := value; end; end else if FieldName = 'TButton' then begin aButton := TButton(field.GetValue(obj).AsType); if Assigned(aButton) then begin value := ReadValue(CurrentPrefix, sl, Field, 'Caption'); if value <> '' then aButton.Caption := value; value := ReadValue(CurrentPrefix, sl, Field, 'Hint'); aButton.ShowHint := value <> ''; if aButton.ShowHint then aButton.Hint := value; end; end else if FieldName = 'TLabel' then begin aLabel := TLabel(field.GetValue(obj).AsType); if Assigned(aLabel) then begin value := ReadValue(CurrentPrefix, sl, Field, 'Caption'); if value <> '' then aLabel.Caption := value; value := ReadValue(CurrentPrefix, sl, Field, 'Hint'); aLabel.ShowHint := value <> ''; if aLabel.ShowHint then aLabel.Hint := value; end; end else if FieldName = 'TTabSheet' then begin aTabSheet := TTabSheet(field.GetValue(obj).AsType); if Assigned(aTabSheet) then begin value := ReadValue(CurrentPrefix, sl, Field, 'Caption'); if value <> '' then aTabSheet.Caption := value; value := ReadValue(CurrentPrefix, sl, Field, 'Hint'); aTabSheet.ShowHint := value <> ''; if aTabSheet.ShowHint then aTabSheet.Hint := value; end; end else if FieldName = 'TGroupBox' then begin aGroupBox := TGroupBox(field.GetValue(obj).AsType); if Assigned(aGroupBox) then begin value := ReadValue(CurrentPrefix, sl, Field, 'Caption'); if value <> '' then aGroupBox.Caption := value; value := ReadValue(CurrentPrefix, sl, Field, 'Hint'); aGroupBox.ShowHint := value <> ''; if aGroupBox.ShowHint then aGroupBox.Hint := value; end; end else if FieldName = 'TSpeedButton' then begin aSpeedButton := TSpeedButton(field.GetValue(obj).AsType); if Assigned(aSpeedButton) then begin value := ReadValue(CurrentPrefix, sl, Field, 'Hint'); aSpeedButton.ShowHint := value <> ''; if aSpeedButton.ShowHint then aSpeedButton.Hint := value; end; end else if FieldName = 'TMenuItem' then begin aMenuItem := TMenuItem(field.GetValue(obj).AsType); if Assigned(aMenuItem) then begin value := ReadValue(CurrentPrefix, sl, Field, 'Caption'); if value <> '' then aMenuItem.Caption := value; end; end else if FieldName = 'TComboBox' then begin aComboBox := TComboBox(field.GetValue(obj).AsType); if Assigned(aComboBox) then begin for i := 0 to Pred(aComboBox.Items.Count) do begin value := ReadValue(CurrentPrefix, sl, Field, 'Item'+IntToStr(i)); if value <> '' then aComboBox.Items[i] := value; end; end; end else if FieldName = 'TListView' then begin aListView := TListView(field.GetValue(obj).AsType); if Assigned(aListView) then begin if not aListView.ShowColumnHeaders then continue; for i := 0 to Pred(aListView.Columns.Count) do begin value := ReadValue(CurrentPrefix, sl, Field, 'Column'+IntToStr(i)); if value <> '' then aListView.Columns[i].Caption := value; end; end; end; end; finally ctx.Free; end; end; class function TRttiTranslation.ReadValue(section: string; var sl: TStringList; field: TRttiField; subfield: string): string; var name: string; begin // load value from stringlist name := Format('%s_%s_%s', [section, field.Name, subfield]); Result := StringReplace(sl.Values[name], '#13#10', #13#10, [rfReplaceAll]); end; class procedure TRttiTranslation.WriteValue(section: string; value: string; var sl: TStringList; field: TRttiField; subfield: string); var name: string; begin if value = '' then exit; name := Format('%s_%s_%s', [section, field.Name, subfield]); sl.Values[name] := StringReplace(value, #13#10, '#13#10', [rfReplaceAll]); end; class procedure TRttiTranslation.Save(filename: string; obj: TObject); var ctx: TRttiContext; objType: TRttiType; Field: TRttiField; FormPrefix: FormPrefixAttribute; FormSection: FormSectionAttribute; sl: TStringList; i: Integer; Header, CurrentPrefix, CurrentSection, FieldName: string; bNewObject: boolean; aCheckBox: TCheckBox; aButton: TButton; aLabel: TLabel; aTabSheet: TTabSheet; aGroupBox: TGroupBox; aSpeedButton: TSpeedButton; aMenuItem: TMenuItem; aComboBox: TComboBox; aListView: TListView; begin FormPrefix := nil; ctx := TRttiContext.Create; try // LOAD FILE IF IT EXISTS sl := TStringList.Create; if FileExists(filename) then sl.LoadFromFile(filename); // ADD HEADER IF NEW OBJECT Header := Format('{ %s }', [obj.ClassName]); bNewObject := sl.IndexOf(Header) = -1; if bNewObject then sl.Add(Header); try objType := ctx.GetType(Obj.ClassInfo); for Field in objType.GetFields do begin // START BY FINDING FORM PREFIX, SKIP FIELDS UNTIL FOUND if not Assigned(FormPrefix) then begin FormPrefix := GetPrefixAttribute(Field); if Assigned(FormPrefix) then CurrentPrefix := FormPrefix.Prefix else continue; end; // IF FORM SECTION, DUMP SECTION FormSection := GetSectionAttribute(Field); if Assigned(FormSection) then begin CurrentSection := FormSection.Section; if CurrentSection = 'DontTranslate' then continue; Header := Format('{ ## %s ## }', [FormSection.Section]); if (sl.IndexOf(Header) = -1) then sl.Add(Header); end; // SKIP ALL ITEMS IN 'DontTranslate' SECTION if CurrentSection = 'DontTranslate' then continue; // HANDLE COMPONENTS FieldName := Field.FieldType.Name; // Handle TCheckBox if FieldName = 'TCheckBox' then begin aCheckBox := TCheckBox(field.GetValue(obj).AsType); if Assigned(aCheckBox) then begin WriteValue(CurrentPrefix, aCheckBox.Caption, sl, field, 'Caption'); WriteValue(CurrentPrefix, aCheckBox.Hint, sl, field, 'Hint'); end; end // Handle TButton else if FieldName = 'TButton' then begin aButton := TButton(field.GetValue(obj).AsType); if Assigned(aButton) then begin WriteValue(CurrentPrefix, aButton.Caption, sl, field, 'Caption'); WriteValue(CurrentPrefix, aButton.Hint, sl, field, 'Hint'); end; end // Handle TLabel else if FieldName = 'TLabel' then begin aLabel := TLabel(field.GetValue(obj).AsType); if Assigned(aLabel) then begin WriteValue(CurrentPrefix, aLabel.Caption, sl, field, 'Caption'); WriteValue(CurrentPrefix, aLabel.Hint, sl, field, 'Hint'); end; end // Handle TTabSheet else if FieldName = 'TTabSheet' then begin aTabSheet := TTabSheet(field.GetValue(obj).AsType); if Assigned(aTabSheet) then begin WriteValue(CurrentPrefix, aTabSheet.Caption, sl, field, 'Caption'); WriteValue(CurrentPrefix, aTabSheet.Hint, sl, field, 'Hint'); end; end // Handle TGroupBox else if FieldName = 'TGroupBox' then begin aGroupBox := TGroupBox(field.GetValue(obj).AsType); if Assigned(aGroupBox) then begin WriteValue(CurrentPrefix, aGroupBox.Caption, sl, field, 'Caption'); WriteValue(CurrentPrefix, aGroupBox.Hint, sl, field, 'Hint'); end; end // Handle TSpeedButton else if FieldName = 'TSpeedButton' then begin aSpeedButton := TSpeedButton(field.GetValue(obj).AsType); if Assigned(aSpeedButton) then begin WriteValue(CurrentPrefix, aSpeedButton.Caption, sl, field, 'Caption'); WriteValue(CurrentPrefix, aSpeedButton.Hint, sl, field, 'Hint'); end; end // Handle TMenuItem else if FieldName = 'TMenuItem' then begin aMenuItem := TMenuItem(field.GetValue(obj).AsType); if Assigned(aMenuItem) then WriteValue(CurrentPrefix, aMenuItem.Caption, sl, field, 'Caption'); end // Handle TComboBox else if FieldName = 'TComboBox' then begin aComboBox := TComboBox(field.GetValue(obj).AsType); if Assigned(aComboBox) then for i := 0 to Pred(aComboBox.Items.Count) do WriteValue(CurrentPrefix, aComboBox.Items[i], sl, field, 'Item'+IntToStr(i)); end // Handle TListView else if FieldName = 'TListView' then begin aListView := TListView(field.GetValue(obj).AsType); if Assigned(aListView) then begin if not aListView.ShowColumnHeaders then continue; for i := 0 to Pred(aListView.Columns.Count) do WriteValue(CurrentPrefix, aListView.Columns[i].Caption, sl, field, 'Column'+IntToStr(i)); end; end; end; finally if bNewObject then sl.Add(' '); ForceDirectories(ExtractFilePath(filename)); sl.SaveToFile(fileName); sl.Free; end; finally ctx.Free; end; end; end. ================================================ FILE: lib/mte/W7Taskbar.pas ================================================ unit W7Taskbar; interface uses Forms, Types, Windows, SysUtils, ComObj, Controls, Graphics; type TTaskBarProgressState = (tbpsNone, tbpsIndeterminate, tbpsNormal, tbpsError, tbpsPaused); function InitializeTaskbarAPI: boolean; function SetTaskbarProgressState(const AState: TTaskBarProgressState): boolean; function SetTaskbarProgressValue(const ACurrent: UInt64; const AMax: UInt64): boolean; function SetTaskbarOverlayIcon(const AIcon: THandle; const ADescription: String): boolean; implementation const TASKBAR_CID: TGUID = '{56FDF344-FD6D-11d0-958A-006097C9A090}'; TBPF_NOPROGRESS = 0; TBPF_INDETERMINATE = 1; TBPF_NORMAL = 2; TBPF_ERROR = 4; TBPF_PAUSED = 8; type ITaskBarList3 = interface(IUnknown) ['{EA1AFB91-9E28-4B86-90E9-9E9F8A5EEFAF}'] function HrInit(): HRESULT; stdcall; function AddTab(hwnd: THandle): HRESULT; stdcall; function DeleteTab(hwnd: THandle): HRESULT; stdcall; function ActivateTab(hwnd: THandle): HRESULT; stdcall; function SetActiveAlt(hwnd: THandle): HRESULT; stdcall; function MarkFullscreenWindow(hwnd: THandle; fFullscreen: Boolean): HRESULT; stdcall; function SetProgressValue(hwnd: THandle; ullCompleted: UInt64; ullTotal: UInt64): HRESULT; stdcall; function SetProgressState(hwnd: THandle; tbpFlags: Cardinal): HRESULT; stdcall; function RegisterTab(hwnd: THandle; hwndMDI: THandle): HRESULT; stdcall; function UnregisterTab(hwndTab: THandle): HRESULT; stdcall; function SetTabOrder(hwndTab: THandle; hwndInsertBefore: THandle): HRESULT; stdcall; function SetTabActive(hwndTab: THandle; hwndMDI: THandle; tbatFlags: Cardinal): HRESULT; stdcall; function ThumbBarAddButtons(hwnd: THandle; cButtons: Cardinal; pButtons: Pointer): HRESULT; stdcall; function ThumbBarUpdateButtons(hwnd: THandle; cButtons: Cardinal; pButtons: Pointer): HRESULT; stdcall; function ThumbBarSetImageList(hwnd: THandle; himl: THandle): HRESULT; stdcall; function SetOverlayIcon(hwnd: THandle; hIcon: THandle; pszDescription: PChar): HRESULT; stdcall; function SetThumbnailTooltip(hwnd: THandle; pszDescription: PChar): HRESULT; stdcall; function SetThumbnailClip(hwnd: THandle; var prcClip: TRect): HRESULT; stdcall; end; var TaskBarInterface: ITaskBarList3; function InitializeTaskbarAPI: Boolean; var Unknown: IInterface; Temp: ITaskBarList3; begin // return true and exit if already initialized if Assigned(TaskBarInterface) then begin Result := True; Exit; end; // create COM object for taskbar CID try Unknown := CreateComObject(TASKBAR_CID); if Assigned(Unknown) then begin Temp := Unknown as ITaskBarList3; if Temp.HrInit() = S_OK then TaskBarInterface := Temp; end; except TaskBarInterface := nil; end; // if we got the interface, return true Result := Assigned(TaskBarInterface); end; { Check to see if the API has been initialized } function CheckAPI: boolean; begin Result := Assigned(TaskBarInterface); end; function SetTaskbarProgressState(const AState: TTaskBarProgressState): boolean; var Flag: Cardinal; begin Result := False; // exit if api not initialized if not CheckAPI then exit; // check if state is valid, else use no progress case AState of tbpsIndeterminate: Flag := TBPF_INDETERMINATE; tbpsNormal: Flag := TBPF_NORMAL; tbpsError: Flag := TBPF_ERROR; tbpsPaused: Flag := TBPF_PAUSED; else Flag := TBPF_NOPROGRESS; end; // set progress state Result := TaskBarInterface.SetProgressState(Application.Handle, Flag) = S_OK; end; function SetTaskbarProgressValue(const ACurrent:UInt64; const AMax: UInt64): boolean; begin Result := False; // exit if api not initialized if not CheckAPI then exit; // set progress value Result := TaskBarInterface.SetProgressValue(Application.Handle, ACurrent, AMax) = S_OK; end; function SetTaskbarOverlayIcon(const AIcon: THandle; const ADescription: String): boolean; begin Result := False; // exit if api not initialized if not CheckAPI then exit; // set icon Result := TaskBarInterface.SetOverlayIcon(Application.Handle, AIcon, PWideChar(ADescription)) = S_OK; end; initialization TaskBarInterface := nil; finalization TaskBarInterface := nil; end. ================================================ FILE: lib/mte/mteBase.pas ================================================ unit mteBase; interface uses Classes, Menus, // third party libraries superobject, // mte units mteTracker, // xEdit units wbHelpers, wbInterface, wbImplementation; type TSmashType = ( stUnknown, stRecord, stString, stInteger, stFlag, stFloat, stStruct, stUnsortedArray, stUnsortedStructArray, stSortedArray, stSortedStructArray, stByteArray, stUnion ); TBasePlugin = class(TObject) public _File: IwbFile; hasData: boolean; hash: string; fileSize: Int64; dateModified: string; filename: string; numRecords: Integer; numOverrides: Integer; author: string; dataPath: string; description: TStringList; masters: TStringList; requiredBy: TStringList; constructor Create; virtual; destructor Destroy; override; procedure GetData(var lst: TList); procedure UpdateData; virtual; procedure GetHash; function GetFormIndex: Integer; end; TPluginHelpers = class class function CreateNewBasePlugin(var list: TList; filename: string): TBasePlugin; class function BasePluginByFilename(var list: TList; filename: string): TBasePlugin; class function BasePluginLoadOrder(var list: TList; filename: string): integer; end; THeaderHelpers = class class procedure LoadPluginHeaders(var sl: TStringList); class procedure GetPluginMasters(filename: string; var sl: TStringList); class procedure GetPluginDependencies(filename: string; var sl: TStringList); end; { General Helper Functions } function etToString(et: TwbElementType): string; function dtToString(dt: TwbDefType): string; function ctToString(ct: TConflictThis): string; function stToString(st: TSmashType): string; function SmashType(def: IwbNamedDef): TSmashtype; function GetSmashType(element: IwbElement): TSmashType; function ElementByIndexedPath(e: IwbElement; ip: string): IwbElement; function IndexedPath(e: IwbElement): string; function GetAllValues(e: IwbElement): string; function IsSortedDef(def: IwbNamedDef): boolean; function IsSorted(e: IwbElement): boolean; function HasStructChildren(e: IwbElement): boolean; function HasStructChildrenDef(def: IwbNamedDef): boolean; function WinningOverrideInFiles(rec: IwbMainRecord; var sl: TStringList): IwbMainRecord; function IsOverride(aRecord: IwbMainRecord): boolean; function ExtractFormID(filename: string): string; function RemoveFileIndex(formID: string): string; function LocalFormID(aRecord: IwbMainRecord): integer; function LoadOrderPrefix(aRecord: IwbMainRecord): integer; function CountOverrides(aFile: IwbFile): integer; function OverrideCountInFiles(rec: IwbMainRecord; var files: TStringList): Integer; procedure AddRequiredBy(var lst: TList; filename: string; var masters: TStringList); procedure GetMasters(aFile: IwbFile; var sl: TStringList); procedure AddMasters(aFile: IwbFile; var sl: TStringList); function RemoveSelfOrContainer(const aElement: IwbElement): boolean; procedure UndeleteAndDisable(const aRecord: IwbMainRecord); function LoadOrderCompare(List: TStringList; Index1, Index2: Integer): Integer; { Record Prototyping Functions } function GetElementObj(var obj: ISuperObject; name: string): ISuperObject; function CreateRecordObj(var tree: ISuperObject; rec: IwbMainRecord): ISuperObject; function GetRecordObj(var tree: ISuperObject; name: string): ISuperObject; function GetRecordDef(sig: TwbSignature): TwbRecordDefEntry; function BuildDef(def: IwbNamedDef; name: string): ISuperObject; function BuildRecordDef(sName: string; mrDef: IwbRecordDef; out recObj: ISuperObject): boolean; overload; function BuildRecordDef(sName: string; out recObj: ISuperObject): boolean; overload; function GetEditableFileContainer: IwbContainerElementRef; { Plugin Error Functions } function FixErrors(const aElement: IwbElement; lastRecord: IwbMainRecord; var errors: TStringList): IwbMainRecord; function CheckForErrors(const aElement: IwbElement; lastRecord: IwbMainRecord; var errors: TStringList): IwbMainRecord; { Asset Handling Functions } procedure ExtractBSA(ContainerName, folder, destination: string); overload; procedure ExtractBSA(ContainerName, destination: string; var ignore: TStringList); overload; function BSAExists(filename: string): boolean; function INIExists(filename: string): boolean; function TranslationExists(filename: string): boolean; function FaceDataExists(filename: string): boolean; function VoiceDataExists(filename: string): boolean; function FragmentsExist(f: IwbFile): boolean; function ReferencesSelf(f: IwbFile): boolean; var PluginsList: TList; HeaderList: TList; implementation uses SysUtils, Dialogs, mteHelpers, msConfiguration; constructor TBasePlugin.Create; begin hasData := false; dataPath := wbDataPath; description := TStringList.Create; masters := TStringList.Create; requiredBy := TStringList.Create; end; destructor TBasePlugin.Destroy; begin description.Free; masters.Free; requiredBy.Free; end; procedure TBasePlugin.GetData(var lst: TList); var Container: IwbContainer; s: string; begin hasData := true; // get data filename := _File.FileName; Container := _File as IwbContainer; Container := Container.Elements[0] as IwbContainer; author := Container.GetElementEditValue('CNAM - Author'); // we have to subtract 1 because this count includes the // file header for some reason numRecords := Container.GetElementNativeValue('HEDR - Header\Number of Records') - 1; // get masters, required by GetMasters(_File, masters); AddRequiredBy(lst, filename, masters); // get description s := Container.GetElementEditValue('SNAM - Description'); description.Text := Wordwrap(s, 80); // get file attributes fileSize := GetFileSize(wbDataPath + filename); dateModified := DateTimeToStr(GetLastModified(wbDataPath + filename)); end; procedure TBasePlugin.UpdateData; begin // virtual method to be overridden end; procedure TBasePlugin.GetHash; begin hash := IntToHex(wbCRC32File(wbDataPath + filename), 8); end; function TBasePlugin.GetFormIndex: Integer; var Container, MasterFiles: IwbContainer; begin Result := 0; Container := self._File as IwbContainer; Container := Container.Elements[0] as IwbContainer; if Container.ElementExists['Master Files'] then begin MasterFiles := Container.ElementByPath['Master Files'] as IwbContainer; Result := MasterFiles.ElementCount; end; end; {*****************************************************************************} { PLUGIN HELPERS Helper methods for dealing with TBasePlugins. } {*****************************************************************************} { Create a new plugin } class function TPluginHelpers.CreateNewBasePlugin(var list: TList; filename: string): TBasePlugin; var aFile: IwbFile; LoadOrder: integer; plugin: TBasePlugin; begin Result := nil; LoadOrder := PluginsList.Count + 1; // fail if maximum load order reached if LoadOrder > 254 then begin Tracker.Write('Maximum load order reached! Can''t create file '+filename); exit; end; // create new plugin file SysUtils.FormatSettings.DecimalSeparator := '.'; aFile := wbNewFile(wbDataPath + filename, LoadOrder); aFile._AddRef; // create new plugin object plugin := TBasePlugin.Create; plugin.filename := filename; plugin._File := aFile; Result := plugin; end; { Gets the load order of the plugin matching the given name } class function TPluginHelpers.BasePluginLoadOrder(var list: TList; filename: string): integer; var i: integer; plugin: TBasePlugin; begin Result := -1; for i := 0 to Pred(list.Count) do begin plugin := TBasePlugin(list[i]); if plugin.filename = filename then begin Result := i; exit; end; end; end; { Gets a plugin matching the given name. } class function TPluginHelpers.BasePluginByFilename(var list: TList; filename: string): TBasePlugin; var i: integer; plugin: TBasePlugin; begin Result := nil; for i := 0 to Pred(list.count) do begin plugin := TBasePlugin(list[i]); if plugin.filename = filename then begin Result := plugin; exit; end; end; end; class procedure THeaderHelpers.LoadPluginHeaders(var sl: TStringList); var i: Integer; aFile: IwbFile; plugin: TBasePlugin; begin // create header list HeaderList := TList.Create; // load plugin headers for each plugin in @sl for i := 0 to Pred(sl.Count) do try aFile := wbFile(wbDataPath + sl[i], -1, '', False, True); plugin := TBasePlugin.Create; plugin._File := aFile; HeaderList.Add(plugin); except on x: Exception do begin Tracker.Write('Failed to load '+sl[i]); end; end; // get data for each plugin in the header list for i := 0 to Pred(HeaderList.Count) do begin plugin := TBasePlugin(HeaderList[i]); plugin.GetData(HeaderList); end; end; class procedure THeaderHelpers.GetPluginMasters(filename: string; var sl: TStringList); var plugin: TBasePlugin; i: integer; begin // get plugin plugin := TPluginHelpers.BasePluginByFilename(HeaderList, filename); if not Assigned(plugin) then exit; // add its masters to @sl for i := 0 to Pred(plugin.masters.Count) do begin if sl.IndexOf(plugin.masters[i]) > -1 then continue; sl.Add(plugin.masters[i]); GetPluginMasters(plugin.masters[i], sl); end; end; class procedure THeaderHelpers.GetPluginDependencies(filename: string; var sl: TStringList); var plugin: TBasePlugin; i: integer; begin // get plugin plugin := TPluginHelpers.BasePluginByFilename(HeaderList, filename); if not Assigned(plugin) then exit; // add its required by to @sl for i := 0 to Pred(plugin.requiredBy.Count) do begin if sl.IndexOf(plugin.requiredBy[i]) > -1 then continue; sl.Add(plugin.requiredBy[i]); GetPluginDependencies(plugin.requiredBy[i], sl); end; end; {******************************************************************************} { General Helper Functions Set of functions that read bethesda plugin files for various attributes. List of functions: - etToString - dtToString - ctToString - stToString - GetSmashType - ElementByIndexedPath - IndexedPath - GetAllValues - IsSorted - HasStructChildren - WinningOverrideInFiles - IsOverride - LocalFormID -LoadOrderPrefix - CountOverrides - GetMasters - AddMasters - BSAExists - TranslationExists - FaceDataExists - VoiceDataExists - FragmentsExist - ExtractBSA - CheckForErorrsLinear - CheckForErrors - PluginsModified - CreatSEQFile } {*****************************************************************************} { Converts a TwbElementType to a string } function etToString(et: TwbElementType): string; begin case Ord(et) of Ord(etFile): Result := 'etFile'; Ord(etMainRecord): Result := 'etMainRecord'; Ord(etGroupRecord): Result := 'etGroupRecord'; Ord(etSubRecord): Result := 'etSubRecord'; Ord(etSubRecordStruct): Result := 'etSubRecordStruct'; Ord(etSubRecordArray): Result := 'etSubRecordArray'; Ord(etSubRecordUnion): Result := 'etSubRecordUnion'; Ord(etArray): Result := 'etArray'; Ord(etStruct): Result := 'etStruct'; Ord(etValue): Result := 'etValue'; Ord(etFlag): Result := 'etFlag'; Ord(etStringListTerminator): Result := 'etStringListTerminator'; Ord(etUnion): Result := 'etUnion'; end; end; { Converts a TwbDefType to a string } function dtToString(dt: TwbDefType): string; begin case Ord(dt) of Ord(dtRecord): Result := 'dtRecord'; Ord(dtSubRecord): Result := 'dtSubRecord'; Ord(dtSubRecordArray): Result := 'dtSubRecordArray'; Ord(dtSubRecordStruct): Result := 'dtSubRecordStruct'; Ord(dtSubRecordUnion): Result := 'dtSubRecordUnion'; Ord(dtString): Result := 'dtString'; Ord(dtLString): Result := 'dtLString'; Ord(dtLenString): Result := 'dtLenString'; Ord(dtByteArray): Result := 'dtByteArray'; Ord(dtInteger): Result := 'dtInteger'; Ord(dtIntegerFormater): Result := 'dtIntegerFormatter'; Ord(dtFloat): Result := 'dtFloat'; Ord(dtArray): Result := 'dtArray'; Ord(dtStruct): Result := 'dtStruct'; Ord(dtUnion): Result := 'dtUnion'; Ord(dtEmpty): Result := 'dtEmpty'; end; end; function ctToString(ct: TConflictThis): string; begin case Ord(ct) of Ord(ctUnknown): Result := 'ctUnknown'; Ord(ctIgnored): Result := 'ctIgnored'; Ord(ctNotDefined): Result := 'ctNotDefined'; Ord(ctIdenticalToMaster): Result := 'ctIdenticalToMaster'; Ord(ctOnlyOne): Result := 'ctOnlyOne'; Ord(ctHiddenByModGroup): Result := 'ctHiddenByModGroup'; Ord(ctMaster): Result := 'ctMaster'; Ord(ctConflictBenign): Result := 'ctConflictBenign'; Ord(ctOverride): Result := 'ctOverride'; Ord(ctIdenticalToMasterWinsConflict): Result := 'ctIdenticalToMasterWinsConflict'; Ord(ctConflictWins): Result := 'ctConflictWins'; Ord(ctConflictLoses): Result := 'ctConflictLoses'; end; end; function stToString(st: TSmashType): string; begin case Ord(st) of Ord(stUnknown): Result := 'Unknown'; Ord(stRecord): Result := 'Record'; Ord(stString): Result := 'String'; Ord(stInteger): Result := 'Integer'; Ord(stFlag): Result := 'Flag'; Ord(stFloat): Result := 'Float'; Ord(stStruct): Result := 'Struct'; Ord(stUnsortedArray): Result := 'Unsorted Array'; Ord(stUnsortedStructArray): Result := 'Unsorted Struct Array'; Ord(stSortedArray): Result := 'Sorted Array'; Ord(stSortedStructArray): Result := 'Sorted Struct Array'; Ord(stByteArray): Result := 'Byte Array'; Ord(stUnion): Result := 'Union'; else Result := 'Unknown'; end; end; function SmashType(def: IwbNamedDef): TSmashtype; var subDef: IwbSubRecordDef; dt: TwbDefType; bIsSorted, bHasStructChildren: boolean; begin dt := def.DefType; if Supports(def, IwbSubrecordDef, subDef) then dt := subDef.GetValue.DefType; case Ord(dt) of Ord(dtRecord): Result := stRecord; Ord(dtSubRecord): Result := stUnknown; Ord(dtSubRecordStruct): Result := stStruct; Ord(dtSubRecordUnion): Result := stUnion; Ord(dtString): Result := stString; Ord(dtLString): Result := stString; Ord(dtLenString): Result := stString; Ord(dtByteArray): Result := stByteArray; Ord(dtInteger): Result := stInteger; Ord(dtIntegerFormater): Result := stInteger; Ord(dtIntegerFormaterUnion): Result := stInteger; Ord(dtFlag): Result := stFlag; Ord(dtFloat): Result := stFloat; Ord(dtSubRecordArray), Ord(dtArray): begin bIsSorted := IsSortedDef(def); bHasStructChildren := HasStructChildrenDef(def); if bIsSorted then begin if bHasStructChildren then Result := stSortedStructArray else Result := stSortedArray; end else begin if bHasStructChildren then Result := stUnsortedStructArray else Result := stUnsortedArray; end; end; Ord(dtStruct): Result := stStruct; Ord(dtUnion): Result := stUnion; Ord(dtEmpty): Result := stUnknown; Ord(dtStructChapter): Result := stStruct; else Result := stUnknown; end; end; function GetSmashType(element: IwbElement): TSmashType; begin Result := SmashType(element.Def); end; function ElementByIndexedPath(e: IwbElement; ip: string): IwbElement; var i, index: integer; path: TStringList; c: IwbContainerElementRef; begin // replace forward slashes with backslashes ip := StringReplace(ip, '/', '\', [rfReplaceAll]); // prepare path stringlist delimited by backslashes path := TStringList.Create; path.Delimiter := '\'; path.StrictDelimiter := true; path.DelimitedText := ip; // treat e as a container if not Supports(e, IwbContainerElementRef, c) then exit; // traverse path for i := 0 to Pred(path.count) do begin if Pos('[', path[i]) > 0 then begin index := StrToInt(GetTextIn(path[i], '[', ']')); e := c.Elements[index]; if not Supports(e, IwbContainerElementRef, c) then exit; end else begin e := c.ElementByPath[path[i]]; if not Supports(e, IwbContainerElementRef, c) then exit; end; end; // set result Result := e; end; function IndexedPath(e: IwbElement): string; var c: IwbContainer; a: string; begin c := e.Container; while (e.ElementType <> etMainRecord) do begin if c.ElementType = etSubRecordArray then a := '['+IntToStr(c.IndexOf(e))+']' else a := e.Name; if Result <> '' then Result := a + '\' + Result else Result := a; e := c; c := e.Container; end; end; { Returns a string hash of all of the values contained in an element } function GetAllValues(e: IwbElement): string; var i: integer; c: IwbContainerElementRef; begin Result := e.EditValue; if not Supports(e, IwbContainerElementRef, c) then exit; // loop through children elements for i := 0 to Pred(c.ElementCount) do begin if (Result <> '') then Result := Result + ';' + GetAllValues(c.Elements[i]) else Result := GetAllValues(c.Elements[i]); end; end; function IsSortedDef(def: IwbNamedDef): boolean; var sraDef: IwbSubRecordArrayDef; arDef: IwbArrayDef; begin Result := false; if Supports(def, IwbSubRecordArrayDef, sraDef) then Result := Supports(sraDef.Element, IwbHasSortKeyDef) else if Supports(def, IwbArrayDef, arDef) then Result := Supports(arDef.Element, IwbHasSortKeyDef); end; { Returns true if @e is a sorted container } function IsSorted(e: IwbElement): boolean; var Container: IwbSortableContainer; begin Result := false; if Supports(e, IwbSortableContainer, Container) then Result := Container.Sorted; end; function HasStructChildrenDef(def: IwbNamedDef): boolean; begin Result := Supports(def, IwbSubRecordArrayDef); end; { Returns true if @e is a container with struct children } function HasStructChildren(e: IwbElement): boolean; var Container: IwbContainerElementRef; begin Result := false; if Supports(e, IwbContainerElementRef, Container) and (Container.ElementCount > 0) then Result := GetSmashType(Container.Elements[0]) = stStruct; end; { Returns the most-winning override of @rec from the files listed in @sl } function WinningOverrideInFiles(rec: IwbMainRecord; var sl: TStringList): IwbMainRecord; var i: Integer; ovr: IwbMainRecord; begin Result := rec; for i := Pred(rec.OverrideCount) downto 0 do begin ovr := rec.Overrides[i]; if sl.IndexOf(ovr._file.FileName) > -1 then begin Result := ovr; exit; end; end; end; { Returns true if the input record is an override record } function IsOverride(aRecord: IwbMainRecord): boolean; begin Result := not aRecord.IsMaster; end; function ExtractFormID(filename: string): string; const HexChars = ['0'..'9', 'A'..'F', 'a'..'f']; var i, counter: Integer; begin counter := 0; // we loop from the back because the formID is usually at the // end of the filename for i := Length(filename) downto 1 do begin if (filename[i] in HexChars) then Inc(counter) else counter := 0; // set result and exit if counter has reached 8 if counter = 8 then begin Result := Copy(filename, i, 8); exit; end; end; end; function RemoveFileIndex(formID: string): string; begin if Length(formID) <> 8 then raise Exception.Create('RemoveFileIndex: FormID must be 8 characters long'); Result := '00' + Copy(formID, 3, 6); end; { Gets the local formID of a record (so no load order prefix) } function LocalFormID(aRecord: IwbMainRecord): integer; begin Result := aRecord.LoadOrderFormID and $00FFFFFF; end; { Gets the load order prefix from the FormID of a record } function LoadOrderPrefix(aRecord: IwbMainRecord): integer; begin Result := aRecord.LoadOrderFormID and $FF000000; end; { Returns the number of override records in a file } function CountOverrides(aFile: IwbFile): integer; var i: Integer; aRecord: IwbMainRecord; begin Result := 0; for i := 0 to Pred(aFile.GetRecordCount) do begin aRecord := aFile.GetRecord(i); if IsOverride(aRecord) then Inc(Result); end; end; { Returns the number of overrides of the specified record in the specified file set } function OverrideCountInFiles(rec: IwbMainRecord; var files: TStringList): Integer; var i: Integer; ovr: IwbMainRecord; begin Result := 0; for i := 0 to Pred(rec.OverrideCount) do begin ovr := rec.Overrides[i]; if files.IndexOf(ovr._File.FileName) > -1 then Inc(Result); end; end; { Populates required by field of @masters that are required by plugin @filename } procedure AddRequiredBy(var lst: TList; filename: string; var masters: TStringList); var i: Integer; plugin: TBasePlugin; begin for i := 0 to Pred(masters.Count) do begin plugin := TPluginHelpers.BasePluginByFilename(lst, masters[i]); if not Assigned(plugin) then continue; plugin.requiredBy.Add(filename); end; end; { Gets the masters in an IwbFile and puts them into a stringlist } procedure GetMasters(aFile: IwbFile; var sl: TStringList); var Container, MasterFiles, MasterFile: IwbContainer; i, iLoadOrder: integer; filename: string; begin Container := aFile as IwbContainer; Container := Container.Elements[0] as IwbContainer; if Container.ElementExists['Master Files'] then begin MasterFiles := Container.ElementByPath['Master Files'] as IwbContainer; for i := 0 to MasterFiles.ElementCount - 1 do begin MasterFile := MasterFiles.Elements[i] as IwbContainer; filename := MasterFile.GetElementEditValue('MAST - Filename'); if sl.IndexOf(filename) = -1 then begin iLoadOrder := TPluginHelpers.BasePluginLoadOrder(PluginsList, filename); sl.AddObject(filename, TObject(iLoadOrder)); end; end; end; end; { Gets the masters in an IwbFile and puts them into a stringlist } procedure AddMasters(aFile: IwbFile; var sl: TStringList); var i: integer; begin for i := 0 to Pred(sl.Count) do begin if Lowercase(aFile.FileName) = Lowercase(sl[i]) then continue; aFile.AddMasterIfMissing(sl[i]); end; end; { Checks if a BSA exists associated with the given filename } function BSAExists(filename: string): boolean; var bsaFilename, ContainerName: string; begin Result := false; bsaFilename := ChangeFileExt(filename, '.bsa'); if FileExists(wbDataPath + bsaFilename) then begin ContainerName := wbDataPath + bsaFilename; if not wbContainerHandler.ContainerExists(ContainerName) then wbContainerHandler.AddBSA(ContainerName); Result := true; end; end; { Check if an INI exists associated with the given filename } function INIExists(filename: string): boolean; var iniFilename: string; begin iniFilename := ChangeFileExt(filename, '.ini'); Result := FileExists(wbDataPath + iniFilename); end; { Returns true if a file exists at @path matching @filename } function MatchingFileExists(path: string; filename: string): boolean; var info: TSearchRec; begin Result := false; filename := Lowercase(filename); if FindFirst(path, faAnyFile, info) = 0 then begin repeat if Pos(filename, Lowercase(info.Name)) > 0 then begin Result := true; exit; end; until FindNext(info) <> 0; FindClose(info); end; end; { Return true if MCM translation files for @filename are found } function TranslationExists(filename: string): boolean; var searchPath, bsaFilename, ContainerName: string; ResourceList: TStringList; begin searchPath := wbDataPath + 'Interface\translations\*'; Result := MatchingFileExists(searchPath, ChangeFileExt(filename, '')); if Result then exit; // check in BSA if BSAExists(filename) then begin bsaFilename := ChangeFileExt(filename, '.bsa'); ContainerName := wbDataPath + bsaFilename; ResourceList := TStringList.Create; wbContainerHandler.ContainerResourceList(ContainerName, ResourceList, 'Interface\translations'); Result := ResourceList.Count > 0; end; end; { Return true if file-specific FaceGenData files for @filename are found } function FaceDataExists(filename: string): boolean; var facetintDir, facegeomDir, bsaFilename, ContainerName: string; ResourceList: TStringList; facetint, facegeom: boolean; begin facetintDir := 'textures\actors\character\facegendata\facetint\' + filename; facegeomDir := 'meshes\actors\character\facegendata\facegeom\' + filename; facetint := DirectoryExists(wbDataPath + facetintDir); facegeom := DirectoryExists(wbDataPath + facegeomDir); Result := facetint or facegeom; if Result then exit; // check in BSA if BSAExists(filename) then begin bsaFilename := ChangeFileExt(filename, '.bsa'); ContainerName := wbDataPath + bsaFilename; ResourceList := TStringList.Create; wbContainerHandler.ContainerResourceList(ContainerName, ResourceList, facetintDir); wbContainerHandler.ContainerResourceList(ContainerName, ResourceList, facegeomDir); Result := ResourceList.Count > 0; end; end; { Return true if file-specific Voice files for @filename are found } function VoiceDataExists(filename: string): boolean; var voiceDir, bsaFilename, ContainerName: string; ResourceList: TStringList; begin voiceDir := 'sound\voice\' + filename; Result := DirectoryExists(wbDataPath + voiceDir); if Result then exit; // check in BSA if BSAExists(filename) then begin bsaFilename := ChangeFileExt(filename, '.bsa'); ContainerName := wbDataPath + bsaFilename; ResourceList := TStringList.Create; wbContainerHandler.ContainerResourceList(ContainerName, ResourceList, voiceDir); Result := ResourceList.Count > 0; end; end; { Returns true if Topic Info Fragments exist in @f } function TopicInfoFragmentsExist(f: IwbFile): boolean; const infoFragmentsPath = 'VMAD - Virtual Machine Adapter\Data\Info VMAD\Script Fragments Info'; var rec: IwbMainRecord; group: IwbGroupRecord; subgroup, container: IwbContainer; element, fragments: IwbElement; i, j: Integer; begin Result := false; // exit if no DIAL records in file if not f.HasGroup('DIAL') then exit; // find all DIAL records group := f.GroupBySignature['DIAL']; for i := 0 to Pred(group.ElementCount) do begin element := group.Elements[i]; // find all INFO records if not Supports(element, IwbContainer, subgroup) then continue; for j := 0 to Pred(subgroup.ElementCount) do begin if not Supports(subgroup.Elements[j], IwbMainRecord, rec) then continue; if not rec.IsMaster then continue; if not Supports(rec, IwbContainer, container) then continue; fragments := container.ElementByPath[infoFragmentsPath]; if not Assigned(fragments) then continue; Result := true; end; end; end; { Returns true if Quest Fragments exist in @f } function QuestFragmentsExist(f: IwbFile): boolean; const questFragmentsPath = 'VMAD - Virtual Machine Adapter\Data\Quest VMAD\Script Fragments Quest'; var rec: IwbMainRecord; group: IwbGroupRecord; container: IwbContainer; fragments: IwbElement; i: Integer; begin Result := false; // exit if no QUST records in file if not f.HasGroup('QUST') then exit; // find all QUST records group := f.GroupBySignature['QUST']; for i := 0 to Pred(group.ElementCount) do begin if not Supports(group.Elements[i], IwbMainRecord, rec) then continue; if not rec.IsMaster then continue; if not Supports(rec, IwbContainer, container) then continue; fragments := container.ElementByPath[questFragmentsPath]; if not Assigned(fragments) then continue; Result := true; end; end; { Returns true if Quest Fragments exist in @f } function SceneFragmentsExist(f: IwbFile): boolean; const sceneFragmentsPath = 'VMAD - Virtual Machine Adapter\Data\Quest VMAD\Script Fragments Quest'; var rec: IwbMainRecord; group: IwbGroupRecord; container: IwbContainer; fragments: IwbElement; i: Integer; begin Result := false; // exit if no SCEN records in file if not f.HasGroup('SCEN') then exit; // find all SCEN records group := f.GroupBySignature['SCEN']; for i := 0 to Pred(group.ElementCount) do begin if not Supports(group.Elements[i], IwbMainRecord, rec) then continue; if not rec.IsMaster then continue; if not Supports(rec, IwbContainer, container) then continue; fragments := container.ElementByPath[sceneFragmentsPath]; if not Assigned(fragments) then continue; Result := true; end; end; { Returns true if file-specific Script Fragments for @f are found } function FragmentsExist(f: IwbFile): boolean; begin Result := TopicInfoFragmentsExist(f) or QuestFragmentsExist(f) or SceneFragmentsExist(f); end; { References self } function ReferencesSelf(f: IwbFile): boolean; var i: Integer; filename, source: string; scripts: IwbGroupRecord; container: IwbContainerElementRef; rec: IwbMainRecord; begin // exit if has no script records in file Result := false; if not f.HasGroup('SCPT') then exit; // get scripts, and check them all for self-reference filename := f.FileName; scripts := f.GroupBySignature['SCPT']; if not Supports(scripts, IwbContainerElementRef, container) then exit; for i := 0 to Pred(container.ElementCount) do begin if not Supports(container.Elements[i], IwbMainRecord, rec) then continue; source := rec.ElementEditValues['SCTX - Script Source']; if Pos(filename, source) > 0 then begin Result := true; break; end; end; end; { Extracts assets from @folder in the BSA @filename to @destination } procedure ExtractBSA(ContainerName, folder, destination: string); var ResourceList: TStringList; i: Integer; begin if not wbContainerHandler.ContainerExists(ContainerName) then begin Tracker.Write(' '+ContainerName+' not loaded.'); exit; end; ResourceList := TStringList.Create; wbContainerHandler.ContainerResourceList(ContainerName, ResourceList, folder); for i := 0 to Pred(ResourceList.Count) do wbContainerHandler.ResourceCopy(ContainerName, ResourceList[i], destination); end; { Extracts assets from the BSA @filename to @destination, ignoring assets matching items in @ignore } procedure ExtractBSA(ContainerName, destination: string; var ignore: TStringList); var ResourceList: TStringList; i, j: Integer; skip: boolean; begin if not wbContainerHandler.ContainerExists(ContainerName) then begin Tracker.Write(' '+ContainerName+' not loaded.'); exit; end; ResourceList := TStringList.Create; wbContainerHandler.ContainerResourceList(ContainerName, ResourceList, ''); for i := 0 to Pred(ResourceList.Count) do begin skip := false; for j := 0 to Pred(ignore.Count) do begin skip := Pos(ignore[j], ResourceList[i]) > 0; if skip then break; end; if skip then continue; wbContainerHandler.ResourceCopy(ContainerName, ResourceList[i], destination); end; end; function RemoveSelfOrContainer(const aElement: IwbElement): Boolean; var cElement: IwbElement; begin Result := false; if aElement.IsRemoveable then begin aElement.Remove; Result := true; end else begin if not Assigned(aElement.Container) then begin Tracker.Write(' Element has no container!'); exit; end; // if element isn't removable, try removing its container if Supports(aElement.Container, IwbMainRecord) then begin Tracker.Write(' Reached main record, cannot remove element'); exit; end; Tracker.Write(' Failed to remove '+aElement.Path+', removing container'); if Supports(aElement.Container, IwbElement, cElement) then Result := RemoveSelfOrContainer(cElement); end; end; procedure UndeleteAndDisable(const aRecord: IwbMainRecord); var xesp: IwbElement; sig: string; container: IwbContainerElementRef; begin try sig := aRecord.Signature; // undelete aRecord.IsDeleted := true; aRecord.IsDeleted := false; // set persistence flag depending on game if (wbGameMode in [gmFO3,gmFNV,gmTES5]) and ((sig = 'ACHR') or (sig = 'ACRE')) then aRecord.IsPersistent := true else if wbGameMode = gmTES4 then aRecord.IsPersistent := false; // place it below the ground if not aRecord.IsPersistent then aRecord.ElementNativeValues['DATA\Position\Z'] := -30000; // remove elements aRecord.RemoveElement('Enable Parent'); aRecord.RemoveElement('XTEL'); // add enabled opposite of player (true - silent) xesp := aRecord.Add('XESP', True); if Assigned(xesp) and Supports(xesp, IwbContainerElementRef, container) then begin container.ElementNativeValues['Reference'] := $14; // Player ref container.ElementNativeValues['Flags'] := 1; // opposite of parent flag end; // set to disable aRecord.IsInitiallyDisabled := true; except on x: Exception do Tracker.Write(' Exception: '+x.Message); end; end; function FixErrors(const aElement: IwbElement; lastRecord: IwbMainRecord; var errors: TStringList): IwbMainRecord; const cUDR = 'Record marked as deleted but contains:'; cUnresolved = '< Error: Could not be resolved >'; cNULL = 'Found a NULL reference, expected:'; var Error: string; Container: IwbContainerElementRef; i: Integer; begin if Tracker.Cancel then exit; // update progress based on number of main records processed if Supports(aElement, IwbMainRecord) then Tracker.UpdateProgress(1); Error := aElement.Check; if Error <> '' then begin Result := aElement.ContainingMainRecord; // fix record marked as deleted errors (UDRs) if Pos(cUDR, Error) = 1 then begin if Assigned(Result) then begin Tracker.Write(' Fixing UDR: '+Result.Name); UndeleteAndDisable(Result); end; end else begin // fix unresolved FormID errors by NULLing them out if Pos(cUnresolved, Error) > 0 then begin Tracker.Write(' Fixing Unresolved FormID: '+aElement.Path); aElement.NativeValue := 0; // we may end up with an invalid NULL reference, so we Check again Error := aElement.Check; if Error = '' then exit; end; // fix invalid NULL references by removal if Pos(cNULL, Error) = 1 then begin Tracker.Write(' Removing NULL reference: '+aElement.Path); if RemoveSelfOrContainer(aElement) then exit; end; // unhandled error Tracker.Write(Format(' Unhandled error: %s -> %s', [aElement.Path, error])); if Assigned(Result) and (lastRecord <> Result) then begin lastRecord := Result; errors.Add(Result.Name); end; errors.Add(' '+aElement.Path + ' -> ' + Error); end; end; // done if element doesn't have children if not Supports(aElement, IwbContainerElementRef, Container) then exit; // recurse through children elements for i := Pred(Container.ElementCount) downto 0 do begin Result := FixErrors(Container.Elements[i], Result, errors); // break if container got deleted if not Assigned(Container) then break; end; end; function CheckForErrors(const aElement: IwbElement; lastRecord: IwbMainRecord; var errors: TStringList): IwbMainRecord; var Error, msg: string; Container: IwbContainerElementRef; i: Integer; begin if Tracker.Cancel then exit; // update progress based on number of main records processed if Supports(aElement, IwbMainRecord) then Tracker.UpdateProgress(1); Error := aElement.Check; // log errors if Error <> '' then begin Result := aElement.ContainingMainRecord; if Assigned(Result) and (Result <> LastRecord) then begin Tracker.Write(' '+Result.Name); errors.Add(Result.Name); end; msg := ' '+aElement.Path + ' -> ' + Error; Tracker.Write(' '+msg); errors.Add(msg); end; // recursion if Supports(aElement, IwbContainerElementRef, Container) then for i := Pred(Container.ElementCount) downto 0 do Result := CheckForErrors(Container.Elements[i], Result, errors); end; { Comparator for sorting plugins } function LoadOrderCompare(List: TStringList; Index1, Index2: Integer): Integer; var LO1, LO2: Integer; begin LO1 := Integer(List.Objects[Index1]); LO2 := Integer(List.Objects[Index2]); Result := LO1 - LO2; end; {******************************************************************************} { Record Prototyping Functions - GetElementObj - CreateRecordObj - GetRecordObj - GetRecordDef - BuildElementDef - BuildRecordDef - GetEditableFileContainer } {******************************************************************************} { GetElementObj: Gets the child json object from a node in a TSmashSetting tree @obj matching @name. Returns nil if a matching child is not found. } function GetElementObj(var obj: ISuperObject; name: string): ISuperObject; var item: ISuperObject; begin Result := nil; if not Assigned(obj) then exit; if not Assigned(obj['c']) then exit; for item in obj['c'] do begin if item.S['n'] = name then begin Result := item; exit; end; end; end; function CreateRecordObj(var tree: ISuperObject; rec: IwbMainRecord): ISuperObject; var item: ISuperObject; begin item := SO; item.S['n'] := rec.Signature; item.I['t'] := Ord(stRecord); tree.A['records'].Add(item); Result := item; end; function GetRecordObj(var tree: ISuperObject; name: string): ISuperObject; var aSignature: TwbSignature; item: ISuperObject; begin Result := nil; aSignature := StrToSignature(name); for item in tree['records'] do begin if StrToSignature(item.S['n']) = aSignature then Result := item; end; end; function GetRecordDef(sig: TwbSignature): TwbRecordDefEntry; var i: Integer; def: TwbRecordDefEntry; begin for i := Low(wbRecordDefs) to High(wbRecordDefs) do begin def := wbRecordDefs[i]; if def.rdeSignature = sig then begin Result := def; exit; end; end; end; function BuildElementDef(element: IwbElement): ISuperObject; var container: IwbContainerElementRef; i: Integer; childElement: IwbElement; begin // release object if something goes wrong Result := SO; try Result.S['n'] := element.Name; Result.I['t'] := Ord(GetSmashType(element)); // populate element children, if it supports them if not Supports(element, IwbContainerElementRef, container) then exit; // assign to container if it doesn't have element but can hold them if (container.ElementCount = 0) and container.CanAssign(High(Integer), nil, false) then try container.Assign(High(Integer), nil, false); except // oops, container assignment failed // this catches an assertion error when assigning to a DOBJ record on x: Exception do exit; end; // if we have children, make children array and recurse if container.ElementCount > 0 then begin Result.O['c'] := SA([]); // traverse children for i := 0 to Pred(container.ElementCount) do begin childElement := container.Elements[i]; Result.A['c'].Add(BuildElementDef(childElement)); end; end; except on x: Exception do begin Result._Release; raise x; end; end; end; function IsUnionDef(def: IwbNamedDef; out unionDef: IwbUnionDef): Boolean; var subDef: IwbSubRecordDef; begin if Supports(def, IwbSubRecordDef, subDef) then Result := Supports(subDef.GetValue, IwbUnionDef, unionDef) else Result := Supports(def, IwbUnionDef, unionDef); end; function HasDef(recObj: ISuperObject; name: String): Boolean; var i: Integer; begin Result := False; for i := 0 to Pred(recObj.A['c'].Length) do if recObj.A['c'].O[i].S['n'] = name then begin Result := True; exit; end; end; procedure AddDefIfMissing(recObj: ISuperObject; def: IwbNamedDef; name: String); begin if not HasDef(recObj, name) then recObj.A['c'].Add(BuildDef(def, name)); end; function SigToStr(sig: TwbSignature): String; var i: Integer; begin for i := Low(sig) to High(sig) do if Ord(sig[i]) < 32 then sig[i] := AnsiChar(Ord('a') + Ord(sig[i])); Result := sig; end; procedure BuildChildDef(def: IwbNamedDef; recObj: ISuperObject); var i: Integer; unionDef: IwbUnionDef; sigDef: IwbSignatureDef; recDef: IwbRecordDef; name: String; begin if IsUnionDef(def, unionDef) then begin for i := 0 to Pred(unionDef.MemberCount) do BuildChildDef(unionDef.Members[i] as IwbNamedDef, recObj); end else if Supports(def, IwbSubRecordUnionDef) and Supports(def, IwbRecordDef, recDef) then begin for i := 0 to Pred(recDef.MemberCount) do BuildChildDef(recDef.Members[i] as IwbNamedDef, recObj); end else if Supports(def, IwbSignatureDef, sigDef) then begin name := SigToStr(sigDef.DefaultSignature) + ' - ' + sigDef.Name; AddDefIfMissing(recObj, def, name); end else AddDefIfMissing(recObj, def, def.Name); end; procedure BuildChildDefs(obj: ISuperObject; def: IwbNamedDef); var i: Integer; subDef: IwbSubRecordDef; recDef: IwbRecordDef; unionDef: IwbUnionDef; structDef: IwbStructDef; intDef: IwbIntegerDefFormaterUnion; sraDef: IwbSubRecordArrayDef; aDef: IwbArrayDef; begin // try SubRecordDef ValueDef if Supports(def, IwbSubRecordDef, subDef) then BuildChildDefs(obj, subDef.GetValue as IwbNamedDef) // try IwbRecordDef else if Supports(def, IwbRecordDef, recDef) then begin if recDef.MemberCount = 0 then exit; obj.O['c'] := SA([]); for i := 0 to Pred(recDef.MemberCount) do BuildChildDef(recDef.Members[i] as IwbNamedDef, obj); end // try IwbUnionDef else if Supports(def, IwbUnionDef, unionDef) then begin if unionDef.MemberCount = 0 then exit; obj.O['c'] := SA([]); for i := 0 to Pred(unionDef.MemberCount) do BuildChildDef(unionDef.Members[i] as IwbNamedDef, obj); end // try IwbStructDef else if Supports(def, IwbStructDef, structDef) then begin if structDef.MemberCount = 0 then exit; obj.O['c'] := SA([]); for i := 0 to Pred(structDef.MemberCount) do BuildChildDef(structDef.Members[i] as IwbNamedDef, obj); end // try IwbIntegerDefFormaterUnion else if Supports(def, IwbIntegerDefFormaterUnion, intDef) then begin if intDef.MemberCount = 0 then exit; obj.O['c'] := SA([]); for i := 0 to Pred(intDef.MemberCount) do BuildChildDef(intDef.Members[i] as IwbNamedDef, obj); end // try IwbSubRecordArrayDef else if Supports(def, IwbSubRecordArrayDef, sraDef) then begin obj.O['c'] := SA([]); BuildChildDef(sraDef.Element as IwbNamedDef, obj); end // try IwbArrayDef else if Supports(def, IwbArrayDef, aDef) then begin obj.O['c'] := SA([]); BuildChildDef(aDef.Element as IwbNamedDef, obj); end; end; function BuildDef(def: IwbNamedDef; name: string): ISuperObject; begin // release object if something goes wrong Result := SO; try Result.S['n'] := name; Result.I['t'] := Ord(SmashType(def)); BuildChildDefs(Result, def); except on x: Exception do begin Result._Release; raise x; end; end; end; function BuildRecordDef(sName: string; mrDef: IwbRecordDef; out recObj: ISuperObject): boolean; overload; var i: Integer; begin recObj := SO; try recObj.S['n'] := sName; recObj.I['t'] := Ord(stRecord); recObj.O['c'] := SA([]); for i := 0 to Pred(mrDef.MemberCount) do BuildChildDef(mrDef.Members[i] as IwbNamedDef, recObj); except on x: Exception do begin recObj._Release; raise x; end; end; // if everything completed, result is object we made Result := true; end; function BuildRecordDef(sName: string; out recObj: ISuperObject): boolean; var def: TwbRecordDefEntry; begin def := GetRecordDef(StrToSignature(sName)); Result := BuildRecordDef(sName, def.rdeDef, recObj); end; function GetEditableFileContainer: IwbContainerElementRef; var i: Integer; aPlugin: TBasePlugin; aFile: IwbFile; Container: IwbContainerElementRef; begin Result := nil; i := 0; repeat // exit if max index reached if i > Pred(PluginsList.Count) then exit; // get next plugin aPlugin := TBasePlugin(PluginsList[i]); Inc(i); // exit if file is invalid aFile := aPlugin._File; if not Supports(aFile, IwbContainerElementRef, Container) then exit; until Container.IsElementEditable(nil); Result := Container; end; procedure PopulateAddList(var AddItem: TMenuItem; Event: TNotifyEvent); var i: Integer; RecordDef: PwbRecordDef; item: TMenuItem; begin // populate wbGroupOrder to additem with TStringList.Create do try Sorted := True; Duplicates := dupIgnore; // initialize list contents AddStrings(wbGroupOrder); Sorted := False; // get record def names, if available for i := Pred(Count) downto 0 do if wbFindRecordDef(AnsiString(Strings[i]), RecordDef) then Strings[i] := Strings[i] + ' - ' + RecordDef.Name else Delete(i); // populate menu items for i := 0 to Pred(Count) do begin if Length(Strings[i]) < 4 then continue; item := TMenuItem.Create(AddItem); item.Caption := Strings[i]; item.OnClick := Event; AddItem.Add(item); end; finally Free; end; end; initialization begin PluginsList := TList.Create; end; finalization begin FreeList(PluginsList); end; end. ================================================ FILE: lib/mte/mteChangeLogForm.dfm ================================================ object ChangeLogForm: TChangeLogForm Left = 0 Top = 0 Caption = 'Update Available' ClientHeight = 342 ClientWidth = 366 Color = clBtnFace Constraints.MaxHeight = 1000 Constraints.MaxWidth = 382 Constraints.MinHeight = 300 Constraints.MinWidth = 382 Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'Tahoma' Font.Style = [] OldCreateOrder = False Position = poScreenCenter OnCreate = FormCreate PixelsPerInch = 96 TextHeight = 13 object LabelPrompt: TLabel Left = 8 Top = 8 Width = 51 Height = 13 Caption = 'Changelog' WordWrap = True end object ScrollBox: TScrollBox Left = 8 Top = 27 Width = 350 Height = 276 HorzScrollBar.Visible = False VertScrollBar.Tracking = True Align = alCustom Anchors = [akLeft, akTop, akRight, akBottom] TabOrder = 0 end object ButtonInstall: TButton Left = 202 Top = 309 Width = 75 Height = 25 Align = alCustom Anchors = [akRight, akBottom] Caption = 'Install' ModalResult = 1 TabOrder = 1 end object ButtonSkip: TButton Left = 283 Top = 309 Width = 75 Height = 25 Align = alCustom Anchors = [akRight, akBottom] Caption = 'Skip' ModalResult = 2 TabOrder = 2 end end ================================================ FILE: lib/mte/mteChangeLogForm.pas ================================================ unit mteChangeLogForm; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, // mte units mteHelpers, RttiTranslation, mteLogger; type TChangeLogForm = class(TForm) [FormPrefix('mpCha')] ScrollBox: TScrollBox; LabelPrompt: TLabel; ButtonInstall: TButton; ButtonSkip: TButton; procedure FormCreate(Sender: TObject); procedure CreateVersionLabel(line: string; var top: Integer); procedure CreateLabel(line: string; var top: Integer); procedure DisplayChangelog; private { Private declarations } public { Public declarations } end; // public entry point function ChangeLogPrompt(AOwner: TComponent): boolean; const spacing = 5; bTranslationDump = false; var clChangeLogForm: TChangeLogForm; clChangelog: TStringList; clProgramVersion: string; implementation {$R *.dfm} procedure TChangeLogForm.FormCreate(Sender: TObject); begin {// do a translation dump? if bTranslationDump then TRttiTranslation.Save('lang\english.lang', self); // load translation TRttiTranslation.Load(language, self);} // display changelog DisplayChangelog; end; function IsVersionLine(line: string): boolean; begin Result := Pos('Version ', line) = 1; end; procedure TChangeLogForm.CreateVersionLabel(line: string; var top: Integer); var lbl: TLabel; begin // make version label lbl := TLabel.Create(ScrollBox); lbl.Parent := ScrollBox; lbl.Autosize := true; lbl.Top := top; lbl.Left := 8; lbl.Caption := line; lbl.Font.Style := [fsBold]; // increment top for next label Inc(top, lbl.Height + spacing); end; procedure TChangeLogForm.CreateLabel(line: string; var top: Integer); var lbl: TLabel; begin // make label lbl := TLabel.Create(ScrollBox); lbl.Parent := ScrollBox; lbl.AutoSize := true; lbl.WordWrap := true; lbl.Top := top; lbl.Left := 20; lbl.Width := ScrollBox.ClientWidth - 36; lbl.Caption := Trim(line); // increment top for next label Inc(top, lbl.Height + spacing); end; procedure TChangeLogForm.DisplayChangelog; var i, top, start: Integer; line, lineVersion: string; begin // find start line start := 0; if not Assigned(clChangelog) then exit; for i := 0 to Pred(clChangelog.Count) do begin line := clChangelog[i]; if not IsVersionLine(line) then continue; // identify start of changelog as first version newer than current version lineVersion := Copy(line, 9, Length(line)); if VersionCompare(clProgramVersion, lineVersion) then begin start := i; break; end; end; // loop through the changelog, creating labels in scrollbox // as necessary to render text top := 8; for i := start to Pred(clChangelog.Count) do begin line := clChangelog[i]; if IsVersionLine(line) then CreateVersionLabel(line, top) else CreateLabel(line, top); end; end; procedure LoadChangelog(var changelog: TStringList); begin // load changelog if not Assigned(changelog) then changelog := TStringList.Create; // don't attempt to load changelog if it doesn't exist if not FileExists('changelog.txt') then begin Logger.Write('GENERAL', 'Changelog', 'No changelog found'); exit; end; // load changelog changelog.LoadFromFile('changelog.txt'); end; function ChangeLogPrompt(AOwner: TComponent): boolean; var clForm: TChangeLogForm; begin Result := false; // if we don't have a changelog, exit returning false if not FileExists('changelog.txt') then exit; // create change log form LoadChangelog(clChangelog); clForm := TChangeLogForm.Create(AOwner); Result := clForm.ShowModal = mrOK; clForm.Free; end; end. ================================================ FILE: lib/mte/mteHelpers.pas ================================================ unit mteHelpers; interface uses Windows, SysUtils, Forms, Classes, ComCtrls, Grids, StdCtrls, Types; type TCallback = procedure of object; TAppHelpers = class class procedure GetHelp(var Msg: TMsg; var Handled: Boolean); class function HandleHelp(Command: Word; Data: Integer; var CallHelp: Boolean): Boolean; end; { General functions } function ShortenVersion(vs: string; numClauses: Integer): string; function IfThenInt(AValue: boolean; ATrue: Integer = 1; AFalse: Integer = 0): Integer; function TitleCase(sText: String): String; function SentenceCase(sText: string): string; function csvText(s: string): string; function CopyFromTo(str: string; first, last: Integer): string; function GetTextIn(str: string; open, close: char): string; function FormatByteSize(const bytes: Int64): string; function DateBuiltString(date: TDateTime): string; function DateTimeToSQL(date: TDateTime): string; function SQLToDateTime(date: string): TDateTime; function RateStr(date: TDateTime): string; function TimeStr(date: TDateTime): string; function AppendIfMissing(str, substr: string): string; function StrEndsWith(s1, s2: string): boolean; function RemoveFromEnd(s1, s2: string): string; function IntegerListSum(list: TStringList; maxIndex: integer): integer; function Wordwrap(s: string; charCount: integer): string; function ExtractPath(path: string; levels: integer): string; function ContainsMatch(var sl: TStringList; const s: string): boolean; procedure DeleteMatchingItems(item: string; var sl: TStringList); function IsURL(s: string): boolean; function IsDotFile(fn: string): boolean; procedure SaveStringToFile(s: string; fn: string); function ApplyTemplate(const template: string; var map: TStringList): string; function VersionCompare(v1, v2: string): boolean; procedure TryToFree(obj: TObject); procedure FreeList(var lst: TList); { Windows API functions } procedure ForceForeground(hWnd: THandle); function GetDriveList: TStringDynArray; function DOSDrive(const sDrive: String ): Integer; function DriveReady(const sDrive: String): Boolean; function TryRegistryKeys(var keys: TStringList): string; function FileNameValid(filename: string): boolean; function DirectoryValid(dir: string): boolean; function UpDirectory(sPath: string): string; function DeleteToRecycleBin(const path: string; Confirm: Boolean): Boolean; procedure ExecNewProcess(ProgramName: string; synchronous: Boolean); procedure BrowseForFile(var ed: TEdit; filter, initDir: string); procedure BrowseForFolder(var ed: TEdit; initDir: string); function GetCSIDLShellFolder(CSIDLFolder: integer): string; function GetFileSize(const aFilename: String): Int64; function GetLastModified(const aFileName: String): TDateTime; function SearchPathsForFile(sPaths, sFileName: string): string; function MultFileSearch(paths, filenames, ignore: array of string; maxDepth: integer): string; function RecursiveFileSearch(aPath: string; filenames, ignore: array of string; maxDepth: integer): string; procedure CopyDirectory(src, dst: string; fIgnore, dIgnore: TStringList); procedure GetFilesList(path: string; var fIgnore, dIgnore, list: TStringList); procedure CopyFiles(src, dst: string; var list: TStringList); function GetVersionMem: string; function FileVersion(const FileName: string): String; procedure DeleteDirectory(const path: string); procedure PerformFileSystemTests(sBasePath: string); { GUI Helper Functions } procedure StringGrid_CorrectWidth(var sg: TStringGrid); procedure ListView_CorrectWidth(var lv: TListView); function ListView_NextMatch(ListView: TListView; sSearch: string; iIndex: Integer): Integer; procedure ListView_HandleMatch(ListView: TListView; iFoundIndex: Integer; var sBuffer: string; sTempBuffer: string); const wndBorderSide = 8; wndBorderTop = 30; // TIME TRACKING days = 1.0; hours = 1.0 / 24.0; minutes = hours / 60.0; seconds = minutes / 60.0; var bAllowHelp: boolean; enFormatSettings: TFormatSettings; implementation uses Controls, Masks, Dialogs, StrUtils, FileCtrl, ShellApi, Messages, CommCtrl, DateUtils, shlObj, IOUtils, Registry; {******************************************************************************} { Application Helpers General helpers for applications } {******************************************************************************} class procedure TAppHelpers.GetHelp(var Msg: TMsg; var Handled: Boolean); var control: TControl; sKeyword: string; begin if (Msg.message = WM_KEYDOWN) and (LoWord(Msg.wParam) = VK_F1) then begin Screen.Cursor := crHelp; Handled := true; end else if (Msg.message = WM_LBUTTONDOWN) and (Screen.Cursor = crHelp) then begin // get control the user clicked on control := FindVCLWindow(Mouse.CursorPos); // if we found a control, jump to help keyword for that control if Assigned(control) then begin bAllowHelp := true; sKeyword := control.HelpKeyword; while (sKeyword = '') and Assigned(control.Parent) do begin control := control.Parent; sKeyword := control.HelpKeyword; end; Application.HelpKeyword(sKeyword); Screen.Cursor := crDefault; Handled := true; end; end; end; class function TAppHelpers.HandleHelp(Command: Word; Data: Integer; var CallHelp: Boolean): Boolean; begin CallHelp := bAllowHelp; bAllowHelp := false; Result := true; end; {******************************************************************************} { General functions Set of functions that help with converting data types and handling strings. List of functions: - IfThenInt - TitleCase - SentenceCase - csvText - CopyFromTo - GetTextIn - FormatByteSize - DateBuiltString - DateTimeToSQL - SQLToDateTime - RateStr - TimeStr - AppendIfMissing - StrEndsWith - RemoveFromEnd - IntegerListSum - Wordwrap - ExtractPath - ContainsMatch - IsURL - IsDotFile - SaveStringToFile - ApplyTemplate } {*****************************************************************************} function ShortenVersion(vs: string; numClauses: Integer): string; var i, numDots: Integer; begin Result := ''; numDots := 0; for i := 1 to Pred(Length(vs)) do begin if vs[i] = '.' then Inc(numDots); if numDots = numClauses then break; Result := Result + vs[i]; end; end; { Returns one of two integers based on a boolean argument. Like IfThen from StrUtils, but returns an Integer. } function IfThenInt(AValue: boolean; ATrue: Integer = 1; AFalse: Integer = 0): Integer; begin if AValue then Result := ATrue else Result := AFalse; end; { Capitalizes the first letter of each word } function TitleCase(sText: String): String; const cDelimiters = [#9, #10, #13, ' ', ',', '.', ':', ';', '"', '\', '/', '(', ')', '[', ']', '{', '}']; var iLoop: Integer; begin Result := sText; if (Result <> '') then begin Result := LowerCase(Result); Result[1] := UpCase(Result[1]); for iLoop := 2 to Length(Result) do if (Result[iLoop - 1] in cDelimiters) then Result[iLoop] := UpCase(Result[iLoop]); end; end; { Capitalizes first character of each sentence } function SentenceCase(sText: string): string; const cTerminators = ['!', '.', '?']; var iLoop: Integer; bTerminated: boolean; begin Result := sText; if (Result <> '') then begin Result := LowerCase(Result); Result[1] := UpCase(Result[1]); bTerminated := false; for iLoop := 2 to Length(Result) do begin if (Result[iLoop - 1] in cTerminators) then bTerminated := true; if bTerminated and (Result[iLoop] <> ' ') then Result[iLoop] := UpCase(Result[iLoop]); end; end; end; { Replaces newlines with a comma and space } function csvText(s: string): string; begin result := StringReplace(Trim(s), #13, ', ', [rfReplaceAll]); end; { Copies a substring in a string between two indexes } function CopyFromTo(str: string; first, last: Integer): string; begin Result := Copy(str, first, (last - first) + 1); end; { Returns a substring of @str between characters @open and @close } function GetTextIn(str: string; open, close: char): string; var i, openIndex: integer; bOpen: boolean; begin Result := ''; bOpen := false; openIndex := 0; for i := 0 to Length(str) do begin if not bOpen and (str[i] = open) then begin openIndex := i; bOpen := true; end; if bOpen and (str[i] = close) then begin Result := CopyFromTo(str, openIndex + 1, i - 1); break; end; end; end; { Format file byte size } function FormatByteSize(const bytes: Int64): string; const B = 1; //byte KB = 1024 * B; //kilobyte MB = 1024 * KB; //megabyte GB = 1024 * MB; //gigabyte begin if bytes > GB then result := FormatFloat('#.## GB', bytes / GB) else if bytes > MB then result := FormatFloat('#.## MB', bytes / MB) else if bytes > KB then result := FormatFloat('#.## KB', bytes / KB) else if bytes > 0 then result := FormatFloat('#.## bytes', bytes) else result := '0 bytes'; end; { Converts a TDateTime to a string, with 0 being the string 'Never' } function DateBuiltString(date: TDateTime): string; begin if date = 0 then Result := 'Never' else begin Result := DateTimeToStr(date); end; end; function DateTimeToSQL(date: TDateTime): string; begin Result := FormatDateTime('yyyy-mm-dd hh:mm:ss', date); end; function SQLToDateTime(date: string): TDateTime; var fs: TFormatSettings; begin GetLocaleFormatSettings(GetThreadLocale, fs); fs.DateSeparator := '-'; fs.ShortDateFormat := 'yyyy-mm-dd'; fs.TimeSeparator := ':'; fs.LongTimeFormat := 'hh:nn:ss'; Result := StrToDateTime(date, fs); end; { Converts a TDateTime to a rate string, e.g. Every 24.0 hours } function RateStr(date: TDateTime): string; begin if date > 1.0 then Result := Format('Every %0.2f days', [date]) else if date * 24.0 > 1.0 then Result := Format('Every %0.1f hours', [date * 24.0]) else if date * 24.0 * 60.0 > 1.0 then Result := Format('Every %0.1f minutes', [date * 24.0 * 60.0]) else Result := Format('Every %0.1f seconds', [date * 24.0 * 60.0 * 60.0]); end; { Converts a TDateTime to a time string, e.g. 19d 20h 3m 30s } function TimeStr(date: TDateTime): string; begin Result := Format('%dd %dh %dm', [Trunc(date), HourOf(date), MinuteOf(date)]); end; { StrEndsWith: Checks to see if a string ends with an entered substring. Example usage: s := 'This is a sample string.'; if StrEndsWith(s, 'string.') then AddMessage('It works!'); } function StrEndsWith(s1, s2: string): boolean; var n1, n2: integer; begin Result := false; n1 := Length(s1); n2 := Length(s2); if n1 < n2 then exit; Result := (Copy(s1, n1 - n2 + 1, n2) = s2); end; { AppendIfMissing: Appends substr to the end of str if it's not already there. Example usage: s := 'This is a sample string.'; Logger.Write(AppendIfMissing(s, 'string.')); //'This is a sample string.' Logger.Write(AppendIfMissing(s, ' Hello.')); //'This is a sample string. Hello.' } function AppendIfMissing(str, substr: string): string; begin Result := str; if not StrEndsWith(str, substr) then Result := str + substr; end; { RemoveFromEnd: Creates a new string with s1 removed from the end of s2, if found. Example usage: s := 'This is a sample string.'; AddMessage(RemoveFromEnd(s, 'string.')); //'This is a sample ' } function RemoveFromEnd(s1, s2: string): string; begin Result := s1; if StrEndsWith(s1, s2) then Result := Copy(s1, 1, Length(s1) - Length(s2)); end; { Calculates the integer sum of all values in a TStringList to maxIndex } function IntegerListSum(list: TStringList; maxIndex: integer): integer; var i: Integer; begin Result := 0; for i := 0 to maxIndex do Inc(result, StrToInt(list[i])); end; { Inserts line breaks in string @s before @charCount has been exceeded } function Wordwrap(s: string; charCount: integer): string; var i, lastSpace, counter: Integer; begin counter := 0; lastSpace := 0; for i := 1 to Length(s) - 1 do begin Inc(counter); if (s[i] = ' ') or (s[i] = ',') then lastSpace := i; if (s[i] = #13) or (s[i] = #10) or (s[i + 1] = #13) or (s[i + 1] = #10) then begin lastSpace := 0; counter := 0; end; if (counter = charCount) and (lastSpace > 0) then begin Insert(#13#10, s, lastSpace + 1); lastSpace := 0; counter := 0; end; end; Result := s; end; { Like ExtractFilePath, but will allow the user to specify how many @levels they want to traverse back. Specifying @levels = 0 is equivalent to ExtractFilePath. Example usage: path := 'C:\Program Files (x86)\Test\Test.exe'; ShowMessage(ExtractPath(path, 0)); // 'C:\Program Files (x86)\Test\' ShowMessage(ExtractPath(path, 1)); // 'C:\Program Files (x86)\' ShowMessage(ExtractPath(path, 2)); // 'C:\' } function ExtractPath(path: string; levels: integer): string; var i, n: integer; begin n := 0; for i := Length(path) downto 1 do if IsPathDelimiter(path, i) then begin if n = levels then break else Inc(n); end; Result := Copy(path, 1, i); end; { Checks to see if any mask in @sl matches the string @s } function ContainsMatch(var sl: TStringList; const s: string): boolean; var i: Integer; begin Result := false; for i := 0 to Pred(sl.Count) do if MatchesMask(s, sl[i]) then begin Result := true; break; end; end; { Deletes items from @sl that match the input string @item } procedure DeleteMatchingItems(item: string; var sl: TStringList); var i: Integer; begin for i := Pred(sl.Count) downto 0 do begin if sl[i] = item then sl.Delete(i); end; end; { Returns true if the string is an http:// or https:// url } function IsURL(s: string): boolean; begin Result := (Pos('http://', s) = 1) or (Pos('https://', s) = 1); end; { Returns true if @fn is . or .. } function IsDotFile(fn: string): boolean; begin Result := (fn = '.') or (fn = '..'); end; { Saves a string @s to a file at @fn } procedure SaveStringToFile(s: string; fn: string); var sl: TStringList; begin sl := TStringList.Create; sl.Text := s; sl.SaveToFile(fn); sl.Free; end; function ApplyTemplate(const template: string; var map: TStringList): string; const openTag = '{{'; closeTag = '}}'; var i: Integer; name, value: string; begin Result := template; for i := 0 to Pred(map.Count) do begin name := map.Names[i]; value := map.ValueFromIndex[i]; Result := StringReplace(Result, openTag + name + closeTag, value, [rfReplaceAll]); end; end; function VersionCompare(v1, v2: string): boolean; var sl1, sl2: TStringList; i, c1, c2: integer; begin Result := false; // parse versions with . as delimiter sl1 := TStringList.Create; sl1.LineBreak := '.'; sl1.Text := v1; sl2 := TStringList.Create; sl2.LineBreak := '.'; sl2.Text := v2; // look through each version clause and perform comparisons i := 0; while (i < sl1.Count) and (i < sl2.Count) do begin c1 := StrToInt(sl1[i]); c2 := StrToInt(sl2[i]); if (c1 < c2) then begin Result := true; break; end else if (c1 > c2) then begin Result := false; break; end; Inc(i); end; // free ram sl1.Free; sl2.Free; end; procedure TryToFree(obj: TObject); begin if Assigned(obj) then try obj.Free; except on x: Exception do // nothing end; end; procedure FreeList(var lst: TList); var i: Integer; obj: TObject; begin for i := Pred(lst.Count) downto 0 do begin obj := TObject(lst[i]); TryToFree(obj); end; lst.Free; end; {******************************************************************************} { Windows API functions Set of functions that help deal with the Windows File System. List of functions: - ForceForeground - FileNameValid - RecycleDirectory - ExecNewProcess - BrowseForFile - BrowseForFolder - GetCSIDLShellFolder - GetFileSize - GetLastModified - MultFileSearch - RecursiveFileSearch - CopyDirectory - GetFilesList - CopyFiles - CorrectListViewWidth - GetVersionMem - FileVersion - DeleteDirectory } {******************************************************************************} { ForceForeground: Forces a hWnd to the foreground. } procedure ForceForeground(hWnd: THandle); begin SetWindowPos(hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOSIZE or SWP_NOACTIVATE or SWP_NOMOVE); SetWindowPos(hWnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOSIZE or SWP_NOACTIVATE or SWP_NOMOVE); end; { GetDriveList: Returns an array filled wit the assigned drive letters on the current computer. } function GetDriveList: TStringDynArray; var Buff: array[0..128] of Char; ptr: PChar; Idx: Integer; begin if (GetLogicalDriveStrings(Length(Buff), Buff) = 0) then RaiseLastOSError; // There can't be more than 26 lettered drives (A..Z). SetLength(Result, 26); Idx := 0; ptr := @Buff; while StrLen(ptr) > 0 do begin Result[Idx] := ptr; ptr := StrEnd(ptr); Inc(ptr); Inc(Idx); end; SetLength(Result, Idx); end; { DOSDrive: Converts a drive letter into the integer drive # required by DiskSize(). } function DOSDrive( const sDrive: String ): Integer; begin if (Length(sDrive) < 1) then Result := -1 else Result := (Ord(UpCase(sDrive[1])) - 64); end; { DriveReady: Tests the status of a drive to see if it's ready to access. } function DriveReady(const sDrive: String): Boolean; var ErrMode: Word; begin ErrMode := SetErrorMode(0); SetErrorMode(ErrMode or SEM_FAILCRITICALERRORS); try Result := (DiskSize(DOSDrive(sDrive)) > -1); finally SetErrorMode(ErrMode); end; end; { TryRegistryKeys: Tries to load various registry keys. } function TryRegistryKeys(var keys: TStringList): string; var i: Integer; path, name: string; begin Result := ''; with TRegistry.Create do try RootKey := HKEY_LOCAL_MACHINE; // try all keys for i := 0 to Pred(keys.Count) do begin path := ExtractFilePath(keys[i]); name := ExtractFileName(keys[i]); if OpenKeyReadOnly(path) then begin Result := ReadString(name); break; end; end; finally Free; end; end; { DirectoryValid: Returns true if the input directory path is valid. } function DirectoryValid(dir: string): boolean; begin Result := false; if (dir = '') then exit; dir := ExcludeTrailingPathDelimiter(dir); {$IFDEF MSWINDOWS} if (Length(dir) < 3) or (ExtractFilePath(dir) = dir) then exit; // avoid 'xyz:\' problem. {$ENDIF} {$IFDEF POSIX} if (dir = '') then exit; {$ENDIF POSIX}; Result := true; end; { UpDirectory: Returns the path of the directory holding a directory. } function UpDirectory(sPath: string): string; begin if not StrEndsWith(sPath, '\') then sPath := ExtractFilePath(sPath); Result := ExtractFilePath(RemoveFromEnd(sPath, '\')); end; { FileNameValid: Returns true if the input filename is valid. } function FileNameValid(filename: string): boolean; begin Result := (Length(Trim(filename)) > 0) and TPath.HasValidFileNameChars(filename, false); end; { ExecNewProcess: Create a new synchronous or asynchronous process. } procedure ExecNewProcess(ProgramName: string; synchronous: Boolean); var StartInfo : TStartupInfo; ProcInfo : TProcessInformation; CreateOK : Boolean; begin { fill with known state } FillChar(StartInfo, SizeOf(TStartupInfo), #0); FillChar(ProcInfo, SizeOf(TProcessInformation), #0); StartInfo.cb := SizeOf(TStartupInfo); CreateOK := CreateProcess(PChar(ProgramName), nil, nil, nil,False, CREATE_NEW_PROCESS_GROUP+NORMAL_PRIORITY_CLASS, nil, nil, StartInfo, ProcInfo); // check if successful if CreateOK then begin if synchronous then WaitForSingleObject(ProcInfo.hProcess, INFINITE); end else ShowMessage('Unable to run '+ProgramName); // close handles CloseHandle(ProcInfo.hProcess); CloseHandle(ProcInfo.hThread); end; { BrowseForFile: Links a file selection through a TOpenDialog to the text stored in @ed, applying filter @filter. } procedure BrowseForFile(var ed: TEdit; filter, initDir: string); var openDialog: TOpenDialog; begin openDialog := TOpenDialog.Create(ed.Parent); if FileExists(ed.Text) then openDialog.InitialDir := ExtractFilePath(ed.Text) else if DirectoryExists(ed.Text) then openDialog.InitialDir := ed.Text else openDialog.InitialDir := initDir; openDialog.Filter := filter; if openDialog.Execute then ed.Text := openDialog.FileName; end; { BrowseForFolder: Links a file selection through a TOpenDialog to the text stored in @ed, applying filter @filter } procedure BrowseForFolder(var ed: TEdit; initDir: string); var s: string; begin // start in current directory value if valid if DirectoryExists(ed.Text) then s := ed.Text else s := initDir; // prompt user to select a directory SelectDirectory('Select a directory', '', s, []); // save text to TEdit if s <> '' then ed.Text := AppendIfMissing(s, '\'); end; { GetCSIDLShellFolder: Gets a folder by its integer CSID. } function GetCSIDLShellFolder(CSIDLFolder: integer): string; begin SetLength(Result, MAX_PATH); SHGetSpecialFolderPath(0, PChar(Result), CSIDLFolder, True); SetLength(Result, StrLen(PChar(Result))); if (Result <> '') then Result := IncludeTrailingBackslash(Result); end; { GetFileSize: Gets the size of a file at @aFilename through the windows API. } function GetFileSize(const aFilename: String): Int64; var info: TWin32FileAttributeData; begin result := -1; if NOT GetFileAttributesEx(PWideChar(aFileName), GetFileExInfoStandard, @info) then EXIT; result := Int64(info.nFileSizeLow) or Int64(info.nFileSizeHigh shl 32); end; { GetLastModified: Gets the last time a file was modified. } function GetLastModified(const aFileName: String): TDateTime; var info: TWin32FileAttributeData; FileTime: TFileTime; LocalTime, SystemTime: TSystemTime; begin result := 0; // exit if can't get attributes if not GetFileAttributesEx(PWideChar(aFileName), GetFileExInfoStandard, @info) then exit; // get last modified FileTime := info.ftLastWriteTime; // convert to system time if not FileTimeToSystemTime(FileTime, SystemTime) then RaiseLastOSError; if not SystemTimeToTzSpecificLocalTime(nil, SystemTime, LocalTime) then RaiseLastOSError; Result := SystemTimeToDateTime(LocalTime); end; { SearchPathsForFile: Searches for a file @sFileName in each path in @sPaths. } function SearchPathsForFile(sPaths, sFileName: string): string; var slPaths: TStringList; i: Integer; info: TSearchRec; begin slPaths := TStringList.Create; try while (Pos(';', sPaths) > 0) do begin slPaths.Add(Copy(sPaths, 1, Pos(';', sPaths) - 1)); sPaths := Copy(sPaths, Pos(';', sPaths) + 1, Length(sPaths)); end; for i := 0 to slPaths.Count - 1 do begin if FindFirst(slPaths[i] + '\*', faDirectory, info) = 0 then begin repeat Result := FileSearch(sFileName, slPaths[i] + '\' + info.Name); if (Result <> '') then break; until FindNext(info) <> 0; FindClose(info); // break if we found it if (Result <> '') then break; end; end; finally slPaths.Free; end; end; { MultFileSearch: Wraps around RecursiveFileSearch, allowing the searching of multiple paths. } function MultFileSearch(paths, filenames, ignore: array of string; maxDepth: integer): string; var i: Integer; path: string; begin for i := Low(paths) to High(paths) do begin path := RecursiveFileSearch(paths[i], filenames, ignore, maxDepth); if path <> '' then break; end; Result := path; end; { RecursiveFileSearch: Recursively searches a path for a file matching @filenames, ignoring directories in @ignore, and not traversing deeper than maxDepth. Example usage: p := RecursiveFileSearch(GamePath, filenames, ignore, 1); AddMessage(p); } function RecursiveFileSearch(aPath: string; filenames, ignore: array of string; maxDepth: integer): string; var skip: boolean; i: integer; info: TSearchRec; begin Result := ''; aPath := AppendIfMissing(aPath, PathDelim); if Result <> '' then exit; // exit if no files in path if FindFirst(aPath + '*', faAnyFile, info) <> 0 then exit; // else loop through all files in path repeat if IsDotFile(info.Name) then continue; // skip . and .. skip := false; for i := Low(ignore) to High(ignore) do begin skip := Lowercase(info.Name) = ignore[i]; if skip then break; end; if not skip then begin if ((info.attr and faDirectory) = faDirectory) and (maxDepth > 0) then begin Result := RecursiveFileSearch(aPath+info.Name, filenames, ignore, maxDepth - 1); end else if MatchStr(info.Name, filenames) then Result := aPath + info.Name; end; if (Result <> '') then break; until FindNext(info) <> 0; FindClose(info); end; { CopyDirectory: Recursively copies all of the contents of a directory. Example usage: slIgnore := TStringList.Create; slIgnore.Add('mteFunctions.pas'); CopyDirectory(ScriptsPath, 'C:\ScriptsBackup', slIgnore); } procedure CopyDirectory(src, dst: string; fIgnore, dIgnore: TStringList); var info: TSearchRec; isDirectory: boolean; begin src := AppendIfMissing(src, PathDelim); dst := AppendIfMissing(dst, PathDelim); // if no files in source path, exit if (FindFirst(src + '*', faAnyFile, info) <> 0) then exit; repeat isDirectory := (info.Attr and faDirectory = faDirectory); // skip . and .. if (info.Name = '.') or (info.Name = '..') then continue; // skip if ignored if isDirectory and ContainsMatch(dIgnore, info.Name) then continue else if ContainsMatch(fIgnore, info.Name) then continue; // copy the file or recurse ForceDirectories(dst); if isDirectory then CopyDirectory(src+info.Name, dst+info.Name, fIgnore, dIgnore) else CopyFile(PChar(src+info.Name), PChar(dst+info.Name), false); until FindNext(info) <> 0; FindClose(info); end; { GetFilesList: Searches @path, recursively traversing subdirectories that don't match a mask in @dIgnore, adding files that don't match a mask in @fIgnore to @list. Example usage: FilesList := TStringList.Create; fileIgnore := TStringList.Create; fileIgnore.Add('*.esp'); dirIgnore := TStringList.Create; dirIgnore.Add('translations'); GetFilesList(wbDataPath, fileIgnore, dirIgnore, FilesList); } procedure GetFilesList(path: string; var fIgnore, dIgnore, list: TStringList); var info: TSearchRec; isDirectory: boolean; begin path := AppendIfMissing(path, PathDelim); // if no files in source path, exit if (FindFirst(path + '*', faAnyFile, info) <> 0) then exit; repeat isDirectory := (info.Attr and faDirectory = faDirectory); // skip . and .. if (info.Name = '.') or (info.Name = '..') then continue; // skip if ignored if isDirectory then begin if ContainsMatch(dIgnore, info.Name) then continue; end else if ContainsMatch(fIgnore, info.Name) then continue; // copy the file or recurse if isDirectory then GetFilesList(path + info.Name, fIgnore, dIgnore, list) else list.Add(path + info.Name); until FindNext(info) <> 0; FindClose(info); end; { Copies files in @list from @src to @dst } procedure CopyFiles(src, dst: string; var list: TStringList); var i: Integer; srcFile, dstFile: string; begin src := AppendIfMissing(src, PathDelim); dst := AppendIfMissing(dst, PathDelim); for i := 0 to Pred(list.Count) do begin srcFile := list[i]; dstFile := StringReplace(srcFile, src, dst, []); ForceDirectories(ExtractFilePath(dstFile)); CopyFile(PChar(srcFile), PChar(dstFile), false); end; end; { Get program version from memory } function GetVersionMem: string; var verblock: PVSFIXEDFILEINFO; versionMS, versionLS, verlen: cardinal; rs: TResourceStream; m: TMemoryStream; begin m := TMemoryStream.Create; try rs := TResourceStream.CreateFromID(HInstance, 1, RT_VERSION); try m.CopyFrom(rs, rs.Size); finally rs.Free; end; m.Position := 0; if VerQueryValue(m.Memory, '\', Pointer(verblock), verlen) then begin VersionMS := verblock.dwFileVersionMS; VersionLS := verblock.dwFileVersionLS; Result := Format('%s.%s.%s.%s', [IntToStr(versionMS shr 16), IntToStr(versionMS and $FFFF), IntToStr(VersionLS shr 16), IntToStr(VersionLS and $FFFF)]); end; finally m.Free; end; end; { Get program version from disk } function FileVersion(const FileName: string): String; var VerInfoSize: Cardinal; VerValueSize: Cardinal; Dummy: Cardinal; PVerInfo: Pointer; PVerValue: PVSFixedFileInfo; begin Result := ''; VerInfoSize := GetFileVersionInfoSize(PChar(FileName), Dummy); GetMem(PVerInfo, VerInfoSize); try if GetFileVersionInfo(PChar(FileName), 0, VerInfoSize, PVerInfo) then if VerQueryValue(PVerInfo, '\', Pointer(PVerValue), VerValueSize) then with PVerValue^ do Result := Format('%d.%d.%d.%d', [ HiWord(dwFileVersionMS), //Major LoWord(dwFileVersionMS), //Minor HiWord(dwFileVersionLS), //Release LoWord(dwFileVersionLS)]); //Build finally FreeMem(PVerInfo, VerInfoSize); end; end; { Sends the file/directory at @path to the recycle bin } function DeleteToRecycleBin(const path: string; Confirm: Boolean): Boolean; var sh: TSHFileOpStruct; begin FillChar(sh, SizeOf(sh), 0); with sh do begin Wnd := 0; wFunc := FO_DELETE; pFrom := PChar(path + #0); fFlags := FOF_SILENT or FOF_ALLOWUNDO; if not Confirm then fFlags := fFlags or FOF_NOCONFIRMATION; end; Result := SHFileOperation(sh) = 0; end; { Deletes the directory at @path and all files it contains } procedure DeleteDirectory(const path: string); var ShOp: TSHFileOpStruct; begin ShOp.Wnd := 0; ShOp.wFunc := FO_DELETE; ShOp.pFrom := PChar(path + #0); ShOp.pTo := nil; ShOp.fFlags := FOF_NOCONFIRMATION or FOF_ALLOWUNDO or FOF_NO_UI; SHFileOperation(ShOp); end; { Performs tests of directory creation and deletion, and file creation, reading, writing, and deletion at the specified @sBasePath } procedure PerformFileSystemTests(sBasePath: string); var sl1, sl2: TStringList; sExceptionBase, sPath, sTask: string; begin // initialize stringlists sl1 := TStringList.Create; sl2 := TStringList.Create; sExceptionBase := 'Could not %s at path "%s"'; try // try to create a new directory sTask := 'create directory'; sPath := sBasePath + 'test\'; ForceDirectories(sPath); if not DirectoryExists(sPath) then raise Exception.Create(Format(sExceptionBase, [sTask, sPath])); // try to create a new file sTask := 'create file'; sPath := sBasePath + 'test\Test.txt'; sl1.Text := sBasePath; sl1.SaveToFile(sPath); // if file doesn't exist after saving, raise an exception if not FileExists(sPath) then raise Exception.Create(Format(sExceptionBase, [sTask, sPath])); // try to read the file sTask := 'read file'; sl2.LoadFromFile(sPath); if sl2.Text <> sl1.Text then raise Exception.Create(Format(sExceptionBase, [sTask, sPath])); // try to write to the file sTask := 'write to file'; sl1.Text := 'Testing 123abc'; sl1.SaveToFile(sPath); sl2.LoadFromFile(sPath); if sl2.Text <> sl1.Text then raise Exception.Create(Format(sExceptionBase, [sTask, sPath])); // try to delete the file sTask := 'delete file'; DeleteFile(sPath); if FileExists(sPath) then raise Exception.Create(Format(sExceptionBase, [sTask, sPath])); // try to delete the directory sTask := 'delete directory'; sPath := sBasePath + 'test\'; DeleteDirectory(sPath); if DirectoryExists(sPath) then raise Exception.Create(Format(sExceptionBase, [sTask, sPath])); finally // always free memory sl1.Free; sl2.Free; end; end; {******************************************************************************} { GUI Helper Functions - ListView_CorrectWidth - ListView_FindNextMatch - ListView_HandleMatch } {******************************************************************************} procedure StringGrid_CorrectWidth(var sg: TStringGrid); var w: Integer; begin w := sg.ClientWidth; Dec(w, sg.ColWidths[0]); sg.ColWidths[1] := w; end; { Fixes @lv's width to fit client width if it has autosizable columns, which resolves an issue where autosize doesn't work on virtual vsReport TListViews when a scroll bar becomes visible. } procedure ListView_CorrectWidth(var lv: TListView); var i, w: Integer; col: TListColumn; AutoSizedColumns: TList; begin AutoSizedColumns := TList.Create; w := lv.ClientWidth; // loop through columns keeping track of remaining width for i := 0 to Pred(lv.Columns.Count) do begin col := lv.Columns[i]; if col.AutoSize then AutoSizedColumns.Add(col) else Dec(w, ListView_GetColumnWidth(lv.Handle, i)); end; // set auotsized columns to fit client width for i := 0 to Pred(AutoSizedColumns.Count) do begin col := TListColumn(AutoSizedColumns[i]); col.Width := w div AutoSizedColumns.Count; end; // clean up AutoSizedColumns.Free; end; { If @iIndex = 0, returns the index of the next @ListView item matching the input @sSearch string. Else returns the index of the next @ListView subitem at index @iIndex - 1 matching the input @sSearch string. } function ListView_NextMatch(ListView: TListView; sSearch: string; iIndex: Integer): Integer; var i, iStart: Integer; ListItem: TListITem; sCaption, sCompare: string; begin Result := -1; // Start at selected item's index, if there // is an item selected if Assigned(ListView.Selected) then iStart := ListView.Selected.Index // Else start at 0, the first item else iStart := 0; // Loop through items looking for a match for i := iStart to Pred(ListView.Items.Count) do begin ListItem := ListView.Items[i]; if iIndex = 0 then sCaption := ListItem.Caption else sCaption := ListItem.SubItems[iIndex - 1]; sCompare := Copy(sCaption, 1, Length(sSearch)); if SameText(sSearch, sCompare) then begin Result := i; break; end; end; end; { Sets @sBuffer to @sTempBuffer, then selects and jumps to the item at @iFoundIndex in @ListView } procedure ListView_HandleMatch(ListView: TListView; iFoundIndex: Integer; var sBuffer: string; sTempBuffer: string); begin // Set the actual buffer to our temporary buffer // and jump to the item we found sBuffer := sTempBuffer; if Assigned(ListView.Selected) then ListView.ClearSelection; ListView.Selected := ListView.Items[iFoundIndex]; ListView.Items[iFoundIndex].MakeVisible(false); end; initialization begin bAllowHelp := false; enFormatSettings := TFormatSettings.Create('en-us'); enFormatSettings.DecimalSeparator := '.'; enFormatSettings.ThousandSeparator := ','; end; end. ================================================ FILE: lib/mte/mteLogger.pas ================================================ unit mteLogger; interface uses Classes, SysUtils; type TLogEvent = procedure(const group, &label, text: string) of object; TLogger = class private FLogEvent : TLogEvent; public procedure Write(const group, &label, text: string); property OnLogEvent: TLogEvent read FLogEvent write FLogEvent; end; var Logger : TLogger; implementation procedure TLogger.Write(const group, &label, text: string); begin if Assigned(FLogEvent) then FLogEvent(group, &label, text); end; initialization Logger := TLogger.Create; finalization FreeAndNil(Logger); end. ================================================ FILE: lib/mte/mteLogging.pas ================================================ { mteLogging created by matortheeternal This unit contains the TFilter and TLogMessage types which offer filterable logging for Delphi VCL applications. Log messages have a group and a label, and filters can apply to groups or labels. } unit mteLogging; interface uses Classes, SysUtils, Forms, // mte units mteProgressForm, mteHelpers; type TFilter = class(TObject) public group: string; &label: string; enabled: boolean; constructor Create(group: string; enabled: boolean); Overload; constructor Create(group, &label: string; enabled: boolean); Overload; end; TLogMessage = class (TObject) public time: string; appTime: string; group: string; &label: string; text: string; constructor Create(time, appTime, group, &label, text: string); Overload; end; { Log methods } procedure RebuildLog; procedure SaveLog(var Log: TList); function MessageEnabled(msg: TLogMessage): boolean; procedure ShowProgressForm(parent: TForm; var pf: TProgressForm; sCaption, sLogSubPath: string); var BaseLog, Log, LabelFilters, GroupFilters: TList; LogPath: string; TimeCosts: TStringList; AppStartTime: TDateTime; implementation { TFilter } constructor TFilter.Create(group: string; enabled: boolean); begin self.group := group; self.enabled := enabled; end; constructor TFilter.Create(group, &label: string; enabled: boolean); begin self.group := group; self.&label := &label; self.enabled := enabled; end; { TLogMessage } constructor TLogMessage.Create(time, appTime, group, &label, text: string); begin self.time := time; self.appTime := appTime; self.group := group; self.&label := &label; self.text := text; end; {******************************************************************************} { Log methods Set of methods for logging List of methods: - InitLog - RebuildLog - SaveLog - MessageGroupEnabled } {******************************************************************************} procedure RebuildLog; var i: Integer; msg: TLogMessage; begin Log.Clear; for i := 0 to Pred(BaseLog.Count) do begin msg := TLogMessage(BaseLog[i]); if MessageEnabled(msg) then Log.Add(msg); end; end; procedure SaveLog(var Log: TList); var sl: TStringList; i: Integer; msg: TLogMessage; fdt: string; begin sl := TStringList.Create; for i := 0 to Pred(Log.Count) do begin msg := TLogMessage(Log[i]); sl.Add(Format('[%s] (%s) %s: %s', [msg.time, msg.group, msg.&label, msg.text])); end; fdt := FormatDateTime('mmddyy_hhnnss', TDateTime(Now)); ForceDirectories(LogPath+'main\'); sl.SaveToFile(LogPath+'main\log_'+fdt+'.txt'); sl.Free; end; function GetGroupFilter(msg: TLogMessage): TFilter; var i: Integer; filter: TFilter; begin Result := nil; for i := 0 to Pred(GroupFilters.Count) do begin filter := TFilter(GroupFilters[i]); if filter.group = msg.group then begin Result := filter; exit; end; end; end; function GetLabelFilter(msg: TLogMessage): TFilter; var i: Integer; filter: TFilter; begin Result := nil; for i := 0 to Pred(LabelFilters.Count) do begin filter := TFilter(LabelFilters[i]); if (filter.&label = msg.&label) and (filter.group = msg.group) then begin Result := filter; exit; end; end; end; function MessageEnabled(msg: TLogMessage): boolean; var GroupFilter, LabelFilter: TFilter; begin Result := true; GroupFilter := GetGroupFilter(msg); LabelFilter := GetLabelFilter(msg); if GroupFilter <> nil then Result := Result and GroupFilter.enabled; if LabelFilter <> nil then Result := Result and LabelFilter.enabled; end; procedure ShowProgressForm(parent: TForm; var pf: TProgressForm; sCaption, sLogSubPath: string); begin pf := TProgressForm.Create(parent); pf.pfLogPath := LogPath + sLogSubPath + '\'; pf.PopupParent := parent; pf.Caption := sCaption; pf.SetMaxProgress(IntegerListSum(timeCosts, Pred(timeCosts.Count))); pf.Show; end; initialization begin BaseLog := TList.Create; Log := TList.Create; LabelFilters := TList.Create; GroupFilters := TList.Create; end; finalization begin FreeList(BaseLog); Log.Free; end; end. ================================================ FILE: lib/mte/mtePluginSelectionForm.dfm ================================================ object PluginSelectionForm: TPluginSelectionForm Left = 0 Top = 0 HelpType = htKeyword HelpKeyword = 'Plugin Selection Window' Caption = 'Plugin Selection' ClientHeight = 647 ClientWidth = 504 Color = clBtnFace Constraints.MinHeight = 400 Constraints.MinWidth = 400 Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'Tahoma' Font.Style = [] OldCreateOrder = False Position = poScreenCenter OnClose = FormClose OnShow = FormShow PixelsPerInch = 96 TextHeight = 13 object lvPlugins: TListView Left = 8 Top = 8 Width = 488 Height = 600 HelpType = htKeyword HelpKeyword = 'Plugin Selection Styles' Align = alCustom Anchors = [akLeft, akTop, akRight, akBottom] Columns = <> ColumnClick = False DoubleBuffered = True MultiSelect = True OwnerData = True OwnerDraw = True ReadOnly = True RowSelect = True ParentDoubleBuffered = False ParentShowHint = False PopupMenu = PluginsPopupMenu ShowHint = False StateImages = StateImages TabOrder = 0 ViewStyle = vsReport OnChange = lvPluginsChange OnData = lvPluginsData OnDrawItem = lvPluginsDrawItem OnKeyPress = lvPluginsKeyPress OnMouseDown = lvPluginsMouseDown OnMouseMove = lvPluginsMouseMove end object btnCancel: TButton Left = 421 Top = 614 Width = 75 Height = 25 HelpType = htKeyword HelpKeyword = 'Plugin Selection Actions' Align = alCustom Anchors = [akRight, akBottom] Caption = 'Cancel' ModalResult = 2 TabOrder = 1 end object btnOK: TButton Left = 340 Top = 614 Width = 75 Height = 25 HelpType = htKeyword HelpKeyword = 'Plugin Selection Actions' Align = alCustom Anchors = [akRight, akBottom] Caption = 'OK' Default = True ModalResult = 1 TabOrder = 2 OnClick = btnOKClick end object PluginsPopupMenu: TPopupMenu OnPopup = PluginsPopupMenuPopup Left = 48 Top = 24 object CheckAllItem: TMenuItem Caption = 'Check all' OnClick = CheckAllItemClick end object UncheckAllItem: TMenuItem Caption = 'Uncheck all' OnClick = UncheckAllItemClick end object ToggleAllItem: TMenuItem Caption = 'Toggle all' OnClick = ToggleAllItemClick end object N1: TMenuItem Caption = '-' end object MastersItem: TMenuItem Caption = 'Masters' object CheckMastersItem: TMenuItem Caption = 'Check masters' OnClick = CheckMastersItemClick end object UncheckMastersItem: TMenuItem Caption = 'Uncheck masters' OnClick = UncheckMastersItemClick end end object DependenciesItem: TMenuItem Caption = 'Dependencies' object CheckDependenciesItem: TMenuItem Caption = 'Check dependencies' OnClick = CheckDependenciesItemClick end object UncheckDependenciesItem: TMenuItem Caption = 'Uncheck dependencies' OnClick = UncheckDependenciesItemClick end end end object StateImages: TImageList Height = 17 Width = 17 Left = 136 Top = 24 Bitmap = { 494C010103003400600011001100FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600 0000000000003600000028000000440000001100000001002000000000001012 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000008F8F8E008F8F 8E008F8F8E008F8F8E008F8F8E008F8F8E008F8F8E008F8F8E008F8F8E008F8F 8E008F8F8E008F8F8E008F8F8E00000000000000000000000000000000008F8F 8E008F8F8E008F8F8E008F8F8E008F8F8E008F8F8E008F8F8E008F8F8E008F8F 8E008F8F8E008F8F8E008F8F8E008F8F8E000000000000000000000000000000 00008F8F8E008F8F8E008F8F8E008F8F8E008F8F8E008F8F8E008F8F8E008F8F 8E008F8F8E008F8F8E008F8F8E008F8F8E008F8F8E0000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000008F8F8E00F4F4F400F4F4F400F4F4F400F5F5F500F9F9 F900F8F8F800F5F5F500F4F4F400F4F4F400F4F4F400F4F4F4008F8F8E000000 00000000000000000000000000008F8F8E00F4F4F400F4F4F400F4F4F400F5F5 F500F9F9F900F8F8F800F5F5F500F4F4F400F4F4F400F4F4F400F4F4F4008F8F 8E00000000000000000000000000000000008F8F8E00F4F4F400F4F4F400F4F4 F400F4F4F400F4F4F400F4F4F400F4F4F400F4F4F400F4F4F400F4F4F400F4F4 F4008F8F8E000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000008F8F8E00F4F4 F400CCCBCA00DBDADA00E9E2DF00BA998C00BD9D9000F6F3F200EDEDEC00ECEB EB00EAE9E900F4F4F4008F8F8E00000000000000000000000000000000008F8F 8E00F4F4F400CCCBCA00DBDADA00E9E2DF00BA998C00BD9D9000F6F3F200EDED EC00ECEBEB00EAE9E900F4F4F4008F8F8E000000000000000000000000000000 00008F8F8E00F4F4F400CCCBCA00D5D4D400DCDBDB00E1E1E000E7E7E600EBEB EA00ECECEB00ECEBEB00EAE9E900F4F4F4008F8F8E0000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000008F8F8E00F4F4F400CAC8C600F0ECEA00BB998B00975F 4A0098614C00D1B9B000F9F9F900F6F6F600E6E6E600F4F4F4008F8F8E000000 00000000000000000000000000008F8F8E00F4F4F400CAC8C600F0ECEA00BB99 8B00975F4A0098614C00D1B9B000F9F9F900F6F6F600E6E6E600F4F4F4008F8F 8E00000000000000000000000000000000008F8F8E00F4F4F400C6C4C200E9E9 E900EDEDED00F0F0F000F4F4F400F6F6F600F6F6F600F6F6F600E6E6E600F4F4 F4008F8F8E000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000008F8F8E00F4F4 F400D1CFCD00E9E1DE00955D4800965F490097604B00A4736100FAF9F800F4F4 F400E2E2E100F4F4F4008F8F8E00000000000000000000000000000000008F8F 8E00F4F4F400D1CFCD00E9E1DE00955D4800965F490097604B00A4736100FAF9 F800F4F4F400E2E2E100F4F4F4008F8F8E000000000000000000000000000000 00008F8F8E00F4F4F400C2BFBC00E5E4E300E9E9E900EDEDED00F2F2F200F4F4 F400F5F5F500F4F4F400E2E2E100F4F4F4008F8F8E0000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000008F8F8E00F4F4F400E1E0DE00AA7F6E00945C4700E2D4 CF00A778670097604B00D5BFB700F6F6F600DEDDDC00F4F4F4008F8F8E000000 00000000000000000000000000008F8F8E00F4F4F400E1E0DE00AA7F6E00945C 4700E2D4CF00A778670097604B00D5BFB700F6F6F600DEDDDC00F4F4F4008F8F 8E00000000000000000000000000000000008F8F8E00F4F4F400BFBBB800E1DF DD00E5E5E400EAEAEA00EFEFEF00F2F2F200F2F2F200F2F2F200DEDDDC00F4F4 F4008F8F8E000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000008F8F8E00F4F4 F400CDC9C500DDCFC900C8AEA300EEEEED00D5C1BA00965E4900A5766400F8F8 F800D6D5D500F4F4F4008F8F8E00000000000000000000000000000000008F8F 8E00F4F4F400CDC9C500DDCFC900C8AEA300EEEEED00D5C1BA00965E4900A576 6400F8F8F800D6D5D500F4F4F4008F8F8E000000000000000000000000000000 00008F8F8E00F4F4F400BCB7B200DCD8D500DFDCDA00E3E1E000E8E8E800ECEC EC00EDEDED00EDEDED00D6D5D400F4F4F4008F8F8E0000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000008F8F8E00F4F4F400B9B3AE00DDD9D500E5E2DF00DCD8 D500F4F3F200A1715E00945C4700D6C3BC00DCDCDB00F4F4F4008F8F8E000000 00000000000000000000000000008F8F8E00F4F4F400B9B3AE00DDD9D500E5E2 DF00DCD8D500F4F3F200A1715E00945C4700D6C3BC00DCDCDB00F4F4F4008F8F 8E00000000000000000000000000000000008F8F8E00F4F4F400B9B3AE00D7D1 CD00D9D4D000DBD7D400DFDDDB00E3E2E100E6E6E500E8E8E800CDCDCC00F4F4 F4008F8F8E000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000008F8F8E00F4F4 F400B9B3AE00D5CFCB00D5CFCB00D6D1CD00E6E2E000CFB8AF00925A4500A577 6500E8E7E700F4F4F4008F8F8E00000000000000000000000000000000008F8F 8E00F4F4F400B9B3AE00D5CFCB00D5CFCB00D6D1CD00E6E2E000CFB8AF00925A 4500A5776500E8E7E700F4F4F4008F8F8E000000000000000000000000000000 00008F8F8E00F4F4F400B9B3AE00D5CFCB00D5CFCB00D6D1CD00DAD5D200DEDB D800E1DFDD00E4E3E200C8C7C600F4F4F4008F8F8E0000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000008F8F8E00F4F4F400B9B3AE00D5CFCB00D5CFCB00D5CF CB00D6D0CC00F1EEED009D6A5700925A4400D0BFB900F6F6F6008F8F8E000000 00000000000000000000000000008F8F8E00F4F4F400B9B3AE00D5CFCB00D5CF CB00D5CFCB00D6D0CC00F1EEED009D6A5700925A4400D0BFB900F6F6F6008F8F 8E00000000000000000000000000000000008F8F8E00F4F4F400B9B3AE00D5CF CB00D5CFCB00D5CFCB00D5CFCB00D8D3D000DCD8D500DFDDDB00C5C3C100F4F4 F4008F8F8E000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000008F8F8E00F4F4 F400B9B3AE00B9B3AE00B9B3AE00B9B3AE00B9B3AE00D0CCC900C0A79D00AB86 7700E4DFDC00F5F5F5008F8F8E00000000000000000000000000000000008F8F 8E00F4F4F400B9B3AE00B9B3AE00B9B3AE00B9B3AE00B9B3AE00D0CCC900C0A7 9D00AB867700E4DFDC00F5F5F5008F8F8E000000000000000000000000000000 00008F8F8E00F4F4F400B9B3AE00B9B3AE00B9B3AE00B9B3AE00B9B3AE00B9B3 AE00BAB4AF00BDB9B400C1BEBB00F4F4F4008F8F8E0000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 000000000000000000008F8F8E00F4F4F400F4F4F400F4F4F400F4F4F400F4F4 F400F4F4F400F4F4F400F8F8F800F9F9F900F6F6F600F4F4F4008F8F8E000000 00000000000000000000000000008F8F8E00F4F4F400F4F4F400F4F4F400F4F4 F400F4F4F400F4F4F400F4F4F400F8F8F800F9F9F900F6F6F600F4F4F4008F8F 8E00000000000000000000000000000000008F8F8E00F4F4F400F4F4F400F4F4 F400F4F4F400F4F4F400F4F4F400F4F4F400F4F4F400F4F4F400F4F4F400F4F4 F4008F8F8E000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 00000000000000000000000000000000000000000000000000008F8F8E008F8F 8E008F8F8E008F8F8E008F8F8E008F8F8E008F8F8E008F8F8E008F8F8E008F8F 8E008F8F8E008F8F8E008F8F8E00000000000000000000000000000000008F8F 8E008F8F8E008F8F8E008F8F8E008F8F8E008F8F8E008F8F8E008F8F8E008F8F 8E008F8F8E008F8F8E008F8F8E008F8F8E000000000000000000000000000000 00008F8F8E008F8F8E008F8F8E008F8F8E008F8F8E008F8F8E008F8F8E008F8F 8E008F8F8E008F8F8E008F8F8E008F8F8E008F8F8E0000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000000000000000000000000000000000000000000000000000000000000000 0000424D3E000000000000003E00000028000000440000001100000001000100 00000000CC0000000000000000000000000000000000000000000000FFFFFF00 FFFFFFFFFFFFE00000000000FFFFFFFFFFFFE00000000000C001E000F0006000 00000000C001E000F000600000000000C001E000F000600000000000C001E000 F000600000000000C001E000F000600000000000C001E000F000600000000000 C001E000F000600000000000C001E000F000600000000000C001E000F0006000 00000000C001E000F000600000000000C001E000F000600000000000C001E000 F000600000000000C001E000F000600000000000FFFFFFFFFFFFE00000000000 FFFFFFFFFFFFE000000000000000000000000000000000000000000000000000 0000} end end ================================================ FILE: lib/mte/mtePluginSelectionForm.pas ================================================ unit mtePluginSelectionForm; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, CommCtrl, Menus, ComCtrls, ImgList; type TPluginListItem = class(TObject) public StateIndex: Integer; Fields: TStringList; constructor Create; virtual; destructor Destroy; override; end; TStringFunction = function(s: string): string of object; TStringListProcedure = procedure(fn: string; var sl: TStringList) of object; TPluginSelectionForm = class(TForm) lvPlugins: TListView; btnCancel: TButton; btnOK: TButton; PluginsPopupMenu: TPopupMenu; CheckAllItem: TMenuItem; UncheckAllItem: TMenuItem; ToggleAllItem: TMenuItem; StateImages: TImageList; MastersItem: TMenuItem; N1: TMenuItem; CheckMastersItem: TMenuItem; UncheckMastersItem: TMenuItem; CheckDependenciesItem: TMenuItem; UncheckDependenciesItem: TMenuItem; DependenciesItem: TMenuItem; procedure LoadFields(aListItem: TPluginListItem; sPlugin: string); procedure UpdateDisabled; procedure FormShow(Sender: TObject); procedure btnOKClick(Sender: TObject); procedure CheckAllItemClick(Sender: TObject); procedure UncheckAllItemClick(Sender: TObject); procedure ToggleAllItemClick(Sender: TObject); procedure lvPluginsMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure lvPluginsChange(Sender: TObject; Item: TListItem; Change: TItemChange); procedure lvPluginsKeyPress(Sender: TObject; var Key: Char); procedure DrawCheckbox(aCanvas: TCanvas; var x, y: Integer; state: Integer); procedure DrawSubItems(ListView: TListView; var R: TRect; Item: TListItem); procedure DrawItem(ListView: TListView; var R: TRect; Item: TListItem); procedure lvPluginsDrawItem(Sender: TCustomListView; Item: TListItem; Rect: TRect; State: TOwnerDrawState); procedure lvPluginsMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); function GetMasterStatus(filename: string): Integer; procedure lvPluginsData(Sender: TObject; Item: TListItem); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure CheckMastersItemClick(Sender: TObject); procedure UncheckMastersItemClick(Sender: TObject); procedure CheckDependenciesItemClick(Sender: TObject); procedure UncheckDependenciesItemClick(Sender: TObject); procedure PluginsPopupMenuPopup(Sender: TObject); private { Private declarations } slMasters, slDependencies, slMissing, slDisabled: TStringList; ListItems: TList; sLastHint: string; sBuffer: string; fLastBufferTime: TDateTime; public { Public declarations } GetPluginInfo: TStringFunction; GetPluginMasters: TStringListProcedure; GetPluginDependencies: TStringListProcedure; sColumns: string; slAllPlugins, slCheckedPlugins: TStringList; end; var PluginSelectionForm: TPluginSelectionForm; implementation uses mteHelpers; const // delay for clearing keystroke buffer when // performing a text search on a list view fBufferDelay = 1.1 * seconds; // checkbox states cChecked = 1; cUnChecked = 2; // master states mstNone = 0; mstMaster = 1; mstDependency = 2; mstBoth = 3; mstMissing = 4; mstDisabled = 5; {$R *.dfm} constructor TPluginListItem.Create; begin StateIndex := cUnChecked; Fields := TStringList.Create; end; destructor TPluginListItem.Destroy; begin Fields.Free; end; procedure TPluginSelectionForm.btnOKClick(Sender: TObject); var i: Integer; ListItem: TListItem; begin // clear checked plugins list slCheckedPlugins.Clear; // add checked plugins to slCheckedPlugins for i := 0 to Pred(lvPlugins.Items.Count) do begin ListItem := lvPlugins.Items[i]; if ListItem.StateIndex = cChecked then slCheckedPlugins.Add(ListItem.Caption); end; end; procedure TPluginSelectionForm.LoadFields(aListItem: TPluginListItem; sPlugin: string); var sl: TStringList; i: Integer; begin // add plugin filename aListItem.fields.Add(sPlugin); // get comma separated plugin info in a TStringList sl := TStringList.Create; sl.StrictDelimiter := true; try sl.CommaText := GetPluginInfo(sPlugin); for i := 0 to Pred(sl.Count) do aListItem.Fields.Add(sl[i]); finally sl.Free; end; end; procedure TPluginSelectionForm.UpdateDisabled; var i, j, index: Integer; filename: string; ListItem, MasterItem: TPluginListItem; sl: TStringList; begin // update slDisabled slDisabled.Clear; sl := TStringList.Create; try for i := 0 to Pred(lvPlugins.Items.Count) do begin ListItem := TPluginListItem(ListItems[i]); filename := ListItem.Fields[0]; // if unchecked, skip if ListItem.StateIndex = cUnChecked then continue; // if checked, make sure its masters are checked GetPluginMasters(filename, sl); for j := 0 to Pred(sl.Count) do begin index := slAllPlugins.IndexOf(sl[j]); // if master is not found, continue if (index = -1) then continue; // if master is unchecked, add to slDisabled MasterItem := TPluginListItem(ListItems[index]); if MasterItem.StateIndex = cUnChecked then slDisabled.Add(sl[j]); end; // clear masters sl.Clear; end; finally sl.Free; end; // disable OK button if there are any disabled masters btnOK.Enabled := slDisabled.Count = 0; end; procedure ToggleState(ListItem: TPluginListItem); begin case ListItem.StateIndex of cChecked: ListItem.StateIndex := cUnChecked; cUnChecked: ListItem.StateIndex := cChecked; end; end; procedure TPluginSelectionForm.lvPluginsChange(Sender: TObject; Item: TListItem; Change: TItemChange); var i: Integer; filename: string; begin // update slMasters and slDependencies slMasters.Clear; slDependencies.Clear; for i := 0 to Pred(lvPlugins.Items.Count) do begin filename := TPluginListItem(ListItems[i]).Fields[0]; with lvPlugins.Items[i] do if Selected then begin GetPluginMasters(filename, slMasters); GetPluginDependencies(filename, slDependencies); end; end; // repaint to update master/dependency colors lvPlugins.Repaint; end; function TPluginSelectionForm.GetMasterStatus(filename: string): Integer; var bIsDependency, bIsMaster: boolean; begin // if file has masters that are missing from slAllPlugins, // return mstMissing if slMissing.IndexOf(filename) > -1 then begin Result := mstMissing; exit; end; // if file has masters that are disabled, // return mstDisabled if slDisabled.IndexOf(filename) > -1 then begin Result := mstDisabled; exit; end; // compute master or dependency status based on selection bIsMaster := slMasters.IndexOf(filename) > -1; bIsDependency := slDependencies.IndexOf(filename) > -1; Result := IfThenInt(bIsMaster, 1, 0) + IfThenInt(bIsDependency, 2, 0); end; procedure TPluginSelectionForm.lvPluginsData(Sender: TObject; Item: TListItem); var aListItem: TPluginListItem; MasterStatus: Integer; i: Integer; begin // get item data aListItem := ListItems[Item.Index]; Item.Caption := aListItem.Fields[0]; Item.StateIndex := aListItem.StateIndex; // get subitems for i := 1 to Pred(aListItem.fields.Count) do Item.SubItems.Add(aListItem.fields[i]); // set font color based on master status of item lvPlugins.Canvas.Font.Style := [fsBold]; MasterStatus := GetMasterStatus(Item.Caption); case MasterStatus of mstNone: begin lvPlugins.Canvas.Font.Style := []; lvPlugins.Canvas.Font.Color := clBlack; end; mstMaster: lvPlugins.Canvas.Font.Color := clGreen; mstDependency: lvPlugins.Canvas.Font.Color := clMaroon; mstBoth: lvPlugins.Canvas.Font.Color := clPurple; mstMissing: begin lvPlugins.Canvas.Font.Style := [fsItalic]; lvPlugins.Canvas.Font.Color := clGray; end; mstDisabled: begin lvPlugins.Canvas.Font.Style := [fsItalic]; lvPlugins.Canvas.Font.Color := clRed; end; end; end; procedure TPluginSelectionForm.DrawCheckbox(aCanvas: TCanvas; var x, y: Integer; state: Integer); var icon: TIcon; begin if state = 0 then exit; icon := TIcon.Create; StateImages.GetIcon(state, icon); aCanvas.Draw(x, y, icon); Inc(x, 17); icon.Free; end; procedure TPluginSelectionForm.DrawSubItems(ListView: TListView; var R: TRect; Item: TListItem); var i: Integer; begin for i := 0 to Pred(Item.SubItems.Count) do begin // redefine rect to draw in the space for the column // use trailing padding to keep items lined up on columns R.Left := R.Right; R.Right := R.Left + ListView_GetColumnWidth(ListView.Handle, i) - 3; // padding between items Inc(R.Left, 3); // draw text ListView.Canvas.TextRect(R, R.Left, R.Top, Item.SubItems[i]); end; end; procedure TPluginSelectionForm.DrawItem(ListView: TListView; var R: TRect; Item: TListItem); begin // redefine rect to draw until the end of the first column // use trailing padding to keep items lined up on columns R.Right := R.Left + ListView.Columns[0].Width - 3; // draw the checkbox DrawCheckbox(ListView.Canvas, R.Left, R.Top, Item.StateIndex); // move text down 1 pixel Inc(R.Top, 1); // padding between checkbox and text Inc(R.Left, 6); // draw text ListView.Canvas.TextRect(R, R.Left, R.Top, Item.Caption); end; procedure TPluginSelectionForm.lvPluginsDrawItem(Sender: TCustomListView; Item: TListItem; Rect: TRect; State: TOwnerDrawState); var ListView: TListView; begin // draw background color ListView := TListView(Sender); if Item.Selected then begin ListView.Canvas.Brush.Color := $FFEEDD; ListView.Canvas.FillRect(Rect); end; // draw item DrawItem(ListView, Rect, Item); // draw subitem DrawSubItems(ListView, Rect, Item); end; procedure TPluginSelectionForm.lvPluginsKeyPress(Sender: TObject; var Key: Char); var i, iFoundIndex: Integer; ListItem: TListItem; fBufferDiff: Real; sTempBuffer: string; begin // Calculate time between current keystroke and last // keystroke we buffered fBufferDiff := Now - fLastBufferTime; // If we are within the buffer delay append the key to a // temporary buffer and search for next item matching the // buffer in the list view items. if fBufferDiff < fBufferDelay then begin fLastBufferTime := Now; sTempBuffer := sBuffer + Key; iFoundIndex := ListView_NextMatch(lvPlugins, sTempBuffer, 0); // If we found a match, handle it if iFoundIndex > -1 then begin ListView_HandleMatch(lvPlugins, iFoundIndex, sBuffer, sTempBuffer); Key := #0; end; end else begin // Allow user to use space to toggle checkbox state // for all selected items if Key = ' ' then begin for i := 0 to Pred(lvPlugins.Items.Count) do begin ListItem := lvPlugins.Items[i]; if ListItem.Selected then if slMissing.IndexOf(slAllPlugins[i]) = -1 then ToggleState(TPluginListItem(ListItems[i])); end; // repaint to show updated checkbox state and exit UpdateDisabled; lvPlugins.Repaint; exit; end; // Restart buffering if we didn't have an active buffer // or press space fLastBufferTime := Now; sTempBuffer := Key; lvPlugins.ClearSelection; iFoundIndex := ListView_NextMatch(lvPlugins, sTempBuffer, 0); // If we found a match, handle it if iFoundIndex > -1 then begin ListView_HandleMatch(lvPlugins, iFoundIndex, sBuffer, sTempBuffer); Key := #0; end; end; end; function OnStateIcon(X, Y: Integer): Boolean; begin Result := (x >= 2) and (x <= 14); end; procedure TPluginSelectionForm.lvPluginsMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var ListItem: TListItem; begin // toggle checkbox state ListItem := lvPlugins.GetItemAt(X, Y); if OnStateIcon(X, Y) then begin if slMissing.IndexOf(slAllPlugins[ListItem.Index]) = -1 then ToggleState(TPluginListItem(ListItems[ListItem.Index])); // repaint to show updated checkbox state UpdateDisabled; lvPlugins.Repaint; end; end; procedure TPluginSelectionForm.lvPluginsMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); var pt: TPoint; li : TListItem; hint, str: string; slTempMasters, slTempReq: TStringList; i: Integer; begin // get list item at mouse position li := lvPlugins.GetItemAt(X, Y); // if mouse not over an item, exit if not Assigned(li) then exit; slTempMasters := TStringList.Create; try GetPluginMasters(li.Caption, slTempMasters); if slMissing.IndexOf(li.Caption) > -1 then begin str := ''; for i := 0 to Pred(slTempMasters.Count) do if slAllPlugins.IndexOf(slTempMasters[i]) = -1 then str := str + slTempMasters[i] + #13#10; hint := Format('Missing masters:'#13#10'%s', [str]); end else if slTempMasters.Count > 0 then hint := Format('Masters:'#13#10'%s'#13#10, [slTempMasters.Text]); finally slTempMasters.Free; end; // get plugin dependencies and display them if they're present slTempReq := TStringList.Create; try GetPluginDependencies(li.Caption, slTempReq); if slTempReq.Count > 0 then hint := hint + Format('Required By:'#13#10'%s', [slTempReq.Text]); finally slTempReq.Free; end; // trim the hint hint := Trim(hint); // activate hint if it differs from previously displayed hint if (hint <> sLastHint) then begin sLastHint := hint; lvPlugins.ShowHint := True; lvPlugins.Hint := hint; Application.ActivateHint(Mouse.CursorPos); end; end; procedure TPluginSelectionForm.FormClose(Sender: TObject; var Action: TCloseAction); begin slMasters.Free; slDependencies.Free; slMissing.Free; slDisabled.Free; ListItems.Free; end; procedure TPluginSelectionForm.FormShow(Sender: TObject); var i, j, iColumnSize: Integer; aListItem: TPluginListItem; sPlugin: string; sl: TStringList; aColumn: TListColumn; begin // create lists slMasters := TStringList.Create; slDependencies := TStringList.Create; slMissing := TStringList.Create; slDisabled := TStringList.Create; ListItems := TList.Create; // create columns sl := TStringList.Create; try sl.CommaText := sColumns; iColumnSize := (lvPlugins.ClientWidth - 300) div (sl.Count - 1); for i := 0 to Pred(sl.Count) do begin aColumn := lvPlugins.Columns.Add; aColumn.Caption := sl[i]; aColumn.Width := IfThenInt(i = 0, 300, iColumnSize); end; // make first column autosize lvPlugins.Columns[0].AutoSize := true; finally sl.Free; end; // add plugin items to list for i := 0 to Pred(slAllPlugins.Count) do begin sPlugin := slAllPlugins[i]; aListItem := TPluginListItem.Create; // check ListItem if it's in the CheckedPlugins list if slCheckedPlugins.IndexOf(sPlugin) > -1 then aListItem.StateIndex := cChecked; // add patch subitems LoadFields(aListItem, sPlugin); ListItems.Add(aListItem); end; // determine which plugins can't be loaded because their masters // are missing sl := TStringList.Create; try for i := 0 to Pred(slAllPlugins.Count) do begin sPlugin := slAllPlugins[i]; aListItem := TPluginListItem(ListItems[i]); GetPluginMasters(sPlugin, sl); for j := 0 to Pred(sl.Count) do if slAllPlugins.IndexOf(sl[j]) = -1 then begin slMissing.Add(sPlugin); aListItem.StateIndex := cUnChecked; break; end; sl.Clear; end; finally sl.Free; end; // set plugin count for display lvPlugins.Items.Count := slAllPlugins.Count; ListView_CorrectWidth(lvPlugins); // update disabled UpdateDisabled; lvPlugins.Repaint; end; procedure TPluginSelectionForm.PluginsPopupMenuPopup(Sender: TObject); var bHasMasters, bHasDependencies: Boolean; begin bHasMasters := slMasters.Count > 0; bHasDependencies := slDependencies.Count > 0; MastersItem.Enabled := bHasMasters; DependenciesItem.Enabled := bHasDependencies; end; procedure TPluginSelectionForm.CheckAllItemClick(Sender: TObject); var i: Integer; begin for i := 0 to Pred(lvPlugins.Items.Count) do if slMissing.IndexOf(slAllPlugins[i]) = -1 then TPluginListItem(ListItems[i]).StateIndex := cChecked; // repaint to show updated checkbox state UpdateDisabled; lvPlugins.Repaint; end; procedure TPluginSelectionForm.UncheckAllItemClick(Sender: TObject); var i: Integer; begin for i := 0 to Pred(lvPlugins.Items.Count) do TPluginListItem(ListItems[i]).StateIndex := cUnChecked; // repaint to show updated checkbox state UpdateDisabled; lvPlugins.Repaint; end; procedure TPluginSelectionForm.ToggleAllItemClick(Sender: TObject); var i: Integer; begin for i := 0 to Pred(lvPlugins.Items.Count) do if slMissing.IndexOf(slAllPlugins[i]) = -1 then ToggleState(TPluginListItem(ListItems[i])); // repaint to show updated checkbox state UpdateDisabled; lvPlugins.Repaint; end; procedure TPluginSelectionForm.CheckMastersItemClick(Sender: TObject); var i, index: Integer; begin // loop through masters of selected plugins for i := 0 to Pred(slMasters.Count) do begin index := slAllPlugins.IndexOf(slMasters[i]); // if the masters isn't loaded, skip it if index = -1 then continue; // else check it TPluginListItem(ListItems[index]).StateIndex := cChecked; end; // repaint to show updated checkbox state UpdateDisabled; lvPlugins.Repaint; end; procedure TPluginSelectionForm.UncheckMastersItemClick(Sender: TObject); var i, index: Integer; begin // loop through masters of selected plugins for i := 0 to Pred(slMasters.Count) do begin index := slAllPlugins.IndexOf(slMasters[i]); // if the masters isn't loaded, skip it if index = -1 then continue; // else uncheck it TPluginListItem(ListItems[index]).StateIndex := cUnChecked; end; // repaint to show updated checkbox state UpdateDisabled; lvPlugins.Repaint; end; procedure TPluginSelectionForm.CheckDependenciesItemClick(Sender: TObject); var i, index: Integer; begin // loop through dependencies of selected plugins for i := 0 to Pred(slDependencies.Count) do begin index := slAllPlugins.IndexOf(slDependencies[i]); // check it TPluginListItem(ListItems[index]).StateIndex := cChecked; end; // repaint to show updated checkbox state UpdateDisabled; lvPlugins.Repaint; end; procedure TPluginSelectionForm.UncheckDependenciesItemClick(Sender: TObject); var i, index: Integer; begin // loop through dependencies of selected plugins for i := 0 to Pred(slDependencies.Count) do begin index := slAllPlugins.IndexOf(slDependencies[i]); // uncheck it TPluginListItem(ListItems[index]).StateIndex := cUnChecked; end; // repaint to show updated checkbox state UpdateDisabled; lvPlugins.Repaint; end; end. ================================================ FILE: lib/mte/mteProgressForm.dfm ================================================ object ProgressForm: TProgressForm Left = 0 Top = 0 Caption = 'Progress' ClientHeight = 342 ClientWidth = 624 Color = clBtnFace DoubleBuffered = True Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'Tahoma' Font.Style = [] OldCreateOrder = False Position = poMainFormCenter OnClose = FormClose OnCloseQuery = FormCloseQuery OnCreate = FormCreate OnShow = FormShow PixelsPerInch = 96 TextHeight = 13 object ProgressLabel: TLabel Left = 8 Top = 8 Width = 608 Height = 13 Align = alCustom Anchors = [akLeft, akTop, akRight] AutoSize = False Caption = 'Progress message' end object DetailsMemo: TMemo Left = 8 Top = 58 Width = 608 Height = 245 Align = alCustom Anchors = [akLeft, akTop, akRight, akBottom] ReadOnly = True ScrollBars = ssVertical TabOrder = 0 end object DetailsButton: TButton Left = 428 Top = 309 Width = 91 Height = 25 Align = alCustom Anchors = [akRight, akBottom] Caption = 'Hide details' TabOrder = 1 OnClick = ToggleDetails end object ProgressBar: TProgressBar Left = 8 Top = 27 Width = 608 Height = 25 Align = alCustom Anchors = [akLeft, akTop, akRight] TabOrder = 2 end object CancelButton: TButton Left = 525 Top = 309 Width = 91 Height = 25 Align = alCustom Anchors = [akRight, akBottom] Caption = 'Cancel' TabOrder = 3 OnClick = CancelButtonClick end end ================================================ FILE: lib/mte/mteProgressForm.pas ================================================ unit mteProgressForm; interface uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, ComCtrls, // mte components W7Taskbar, mteTracker; type TProgressForm = class(TForm) DetailsMemo: TMemo; DetailsButton: TButton; ProgressBar: TProgressBar; ProgressLabel: TLabel; CancelButton: TButton; procedure UpdateProgress(const i: Integer); procedure StatusMessage(const s: string); procedure Write(const s: string); procedure SaveLog; procedure SetProgress(const i: Integer); procedure SetMaxProgress(const i: Integer); function GetProgress: Integer; function GetMaxProgress: Integer; procedure FormCreate(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure ToggleDetails(Sender: TObject); procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); procedure CancelButtonClick(Sender: TObject); procedure FormShow(Sender: TObject); private { Private declarations } public bDetailsVisible: boolean; pfLogPath: string; end; implementation var lastHeight: integer; {$R *.dfm} procedure TProgressForm.ToggleDetails(Sender: TObject); begin bDetailsVisible := not bDetailsVisible; if bDetailsVisible then begin self.Height := lastHeight; DetailsMemo.Visible := true; DetailsButton.Caption := 'Hide details'; DetailsMemo.Height := self.Height - 135; end else begin DetailsMemo.Visible := false; DetailsButton.Caption := 'Show details'; lastHeight := self.Height; self.Height := 129; end; end; procedure TProgressForm.CancelButtonClick(Sender: TObject); begin Close; end; procedure TProgressForm.FormClose(Sender: TObject; var Action: TCloseAction); begin SetTaskbarProgressState(tbpsNone); Tracker.OnSetMaxEvent := nil; Tracker.OnUpdateEvent := nil; Tracker.OnLogEvent := nil; Tracker.OnSetEvent := nil; Tracker.OnGetEvent := nil; Tracker.OnGetMaxEvent := nil; Tracker.OnStatusEvent := nil; end; procedure TProgressForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin CanClose := (fsModal in FormState); //Tracker.Write('CanClose = '+BoolToStr(CanClose, true)); if not (CanClose or Tracker.Cancel) then begin Tracker.Write('Cancelling...'); SetTaskbarProgressState(tbpsError); Tracker.Cancel := true; end; end; procedure TProgressForm.FormCreate(Sender: TObject); begin lastHeight := 380; SetTaskbarProgressState(tbpsNormal); bDetailsVisible := true; DetailsMemo.ReadOnly := true; Tracker.OnSetMaxEvent := SetMaxProgress; Tracker.OnUpdateEvent := UpdateProgress; Tracker.OnLogEvent := Write; Tracker.OnSetEvent := SetProgress; Tracker.OnStatusEvent := StatusMessage; Tracker.OnGetEvent := GetProgress; Tracker.OnGetMaxEvent := GetMaxProgress; end; procedure TProgressForm.FormShow(Sender: TObject); begin if (fsModal in FormState) then begin CancelButton.Caption := 'Close'; if not bDetailsVisible then ToggleDetails(nil); end else if not bDetailsVisible then begin bDetailsVisible := false; DetailsMemo.Visible := false; DetailsButton.Caption := 'Show details'; lastHeight := self.Height; self.Height := 129; end; end; procedure TProgressForm.SetProgress(const i: Integer); begin ProgressBar.Position := i; SetTaskbarProgressValue(ProgressBar.Position, ProgressBar.Max); end; procedure TProgressForm.SetMaxProgress(const i: Integer); begin ProgressBar.Max := i; end; function TProgressForm.GetProgress: Integer; begin Result := ProgressBar.Position; end; function TProgressForm.GetMaxProgress: Integer; begin Result := ProgressBar.Max; end; procedure TProgressForm.UpdateProgress(const i: Integer); begin ProgressBar.StepBy(i); SetTaskbarProgressValue(ProgressBar.Position, ProgressBar.Max); end; procedure TProgressForm.SaveLog; var fdt: string; begin try ForceDirectories(pfLogPath); fdt := FormatDateTime('mmddyy_hhnnss', TDateTime(Now)); DetailsMemo.Lines.SaveToFile(pfLogPath + 'log_'+fdt+'.txt'); except on Exception do // nothing to do end; end; procedure TProgressForm.StatusMessage(const s: string); begin ProgressLabel.Caption := s; end; procedure TProgressForm.Write(const s: string); begin if Pos(' ', s) <> 1 then ProgressLabel.Caption := s; DetailsMemo.SelLength := 0; DetailsMemo.Lines.Add(s); end; end. ================================================ FILE: lib/mte/mteTaskHandler.pas ================================================ unit mteTaskHandler; interface uses Classes, SysUtils, // mte components mteLogger, mteHelpers; type TProcedure = procedure of object; TTask = class (TObject) private FExecute : TProcedure; public name: string; rate: real; lastExecuted: TDateTime; constructor Create(name: string; rate: real; FExecute: TProcedure); Overload; property OnExecute: TProcedure read FExecute write FExecute; procedure Execute; end; TTaskHandler = class(TObject) public TaskList: TList; bExecutingTasks: boolean; procedure RemoveTask(taskName: string); procedure AddTask(task: TTask); procedure ExecTasks; constructor Create; Overload; end; var bLogTasks: boolean; implementation procedure TTaskHandler.AddTask(task: TTask); begin TaskList.Add(task); end; procedure TTaskHandler.RemoveTask(taskName: string); var i: Integer; task: TTask; begin if not Assigned(TaskList) then exit; for i := Pred(TaskList.Count) downto 0 do begin task := TTask(TaskList[i]); if task.name = taskName then begin TaskList.Delete(i); break; end; end; end; procedure TTaskHandler.ExecTasks; var i: Integer; task: TTask; begin // exit if we're currently executing tasks if bExecutingTasks then exit; bExecutingTasks := true; // loop through task list, executing tasks that are ready to be executed for i := Pred(TaskList.Count) downto 0 do begin task := TTask(TaskList[i]); if (Now - task.lastExecuted >= task.rate) then begin if bLogTasks and (task.rate > 60.0 * seconds) then Logger.Write('TASK', 'Execute', task.name); task.lastExecuted := Now; task.Execute; end; end; // no longer executing tasks bExecutingTasks := false; end; constructor TTaskHandler.Create; begin TaskList := TList.Create; end; {******************************************************************************} { Task methods Object methods for TTask } {******************************************************************************} constructor TTask.Create(name: string; rate: real; FExecute: TProcedure); begin if bLogTasks then Logger.Write('TASK', 'Init', Format('%s, Rate: %s', [name, RateStr(rate)])); self.name := name; self.rate := rate; self.FExecute := FExecute; self.lastExecuted := Now; end; procedure TTask.Execute; begin if Assigned(FExecute) then FExecute; end; end. ================================================ FILE: lib/mte/mteTracker.pas ================================================ unit mteTracker; interface uses Classes, SysUtils; type TUpdateEvent = procedure(const i: integer) of object; TReadEvent = function: Integer of object; TLogEvent = procedure(const s: string) of object; TProgressTracker = class private FUpdateEvent : TUpdateEvent; FSetEvent : TUpdateEvent; FGetEvent : TReadEvent; FMaxEvent : TUpdateEvent; FGetMaxEvent : TReadEvent; FLogEvent : TLogEvent; FStatusEvent : TLogEvent; public Cancel: boolean; procedure SetMaxProgress(const i: integer); property OnSetMaxEvent: TUpdateEvent read FMaxEvent write FMaxEvent; procedure SetProgress(const i: integer); property OnSetEvent: TUpdateEvent read FSetEvent write FSetEvent; function GetProgress: Integer; property OnGetEvent: TReadEvent read FGetEvent write FGetEvent; function GetMaxProgress: Integer; property OnGetMaxEvent: TReadEvent read FGetMaxEvent write FGetMaxEvent; procedure UpdateProgress(const i: integer); property OnUpdateEvent: TUpdateEvent read FUpdateEvent write FUpdateEvent; procedure StatusMessage(const s: string); property OnStatusEvent: TLogEvent read FStatusEvent write FStatusEvent; procedure Write(const s: string); property OnLogEvent: TLogEvent read FLogEvent write FLogEvent; end; var Tracker: TProgressTracker; implementation procedure TProgressTracker.SetMaxProgress(const i: Integer); begin if Assigned(FMaxEvent) then FMaxEvent(i); end; procedure TProgressTracker.StatusMessage(const s: string); begin if Assigned(FStatusEvent) then FStatusEvent(s); end; procedure TProgressTracker.SetProgress(const i: integer); begin if Assigned(FSetEvent) then FSetEvent(i); end; function TProgressTracker.GetProgress: Integer; begin Result := FGetEvent(); end; function TProgressTracker.GetMaxProgress: Integer; begin Result := FGetMaxEvent(); end; procedure TProgressTracker.UpdateProgress(const i: integer); begin if Assigned(FUpdateEvent) then FUpdateEvent(i); end; procedure TProgressTracker.Write(const s: string); begin if s = '' then exit; if Assigned(FLogEvent) then FLogEvent(s); end; initialization Tracker := TProgressTracker.Create; finalization FreeAndNil(Tracker); end. ================================================ FILE: lib/superobject/superobject.pas ================================================ (* * Super Object Toolkit * * Usage allowed under the restrictions of the Lesser GNU General Public License * or alternatively the restrictions of the Mozilla Public License 1.1 * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for * the specific language governing rights and limitations under the License. * * Unit owner : Henri Gourvest * Web site : http://www.progdigy.com * * This unit is inspired from the json c lib: * Michael Clark * http://oss.metaparadigm.com/json-c/ * * CHANGES: * v1.2 * + support of currency data type * + right trim unquoted string * + read Unicode Files and streams (Litle Endian with BOM) * + Fix bug on javadate functions + windows nt compatibility * + Now you can force to parse only the canonical syntax of JSON using the stric parameter * + Delphi 2010 RTTI marshalling * v1.1 * + Double licence MPL or LGPL. * + Delphi 2009 compatibility & Unicode support. * + AsString return a string instead of PChar. * + Escaped and Unascaped JSON serialiser. * + Missed FormFeed added \f * - Removed @ trick, uses forcepath() method instead. * + Fixed parse error with uppercase E symbol in numbers. * + Fixed possible buffer overflow when enlarging array. * + Added "delete", "pack", "insert" methods for arrays and/or objects * + Multi parametters when calling methods * + Delphi Enumerator (for obj1 in obj2 do ...) * + Format method ex: obj.format('<%name%>%tab[1]%') * + ParseFile and ParseStream methods * + Parser now understand hexdecimal c syntax ex: \xFF * + Null Object Design Patern (ex: for obj in values.N['path'] do ...) * v1.0 * + renamed class * + interfaced object * + added a new data type: the method * + parser can now evaluate properties and call methods * - removed obselet rpc class * - removed "find" method, now you can use "parse" method instead * v0.6 * + refactoring * v0.5 * + new find method to get or set value using a path syntax * ex: obj.s['obj.prop[1]'] := 'string value'; * obj.a['@obj.array'].b[n] := true; // @ -> create property if necessary * v0.4 * + bug corrected: AVL tree badly balanced. * v0.3 * + New validator partially based on the Kwalify syntax. * + extended syntax to parse unquoted fields. * + Freepascal compatibility win32/64 Linux32/64. * + JavaToDelphiDateTime and DelphiToJavaDateTime improved for UTC. * + new TJsonObject.Compare function. * v0.2 * + Hashed string list replaced with a faster AVL tree * + JsonInt data type can be changed to int64 * + JavaToDelphiDateTime and DelphiToJavaDateTime helper fonctions * + from json-c v0.7 * + Add escaping of backslash to json output * + Add escaping of foward slash on tokenizing and output * + Changes to internal tokenizer from using recursion to * using a depth state structure to allow incremental parsing * v0.1 * + first release *) {$IFDEF FPC} {$MODE OBJFPC}{$H+} {$ENDIF} {$DEFINE SUPER_METHOD} {$DEFINE WINDOWSNT_COMPATIBILITY} {.$DEFINE DEBUG} // track memory leack unit superobject; interface uses Classes {$IFDEF VER210} ,Generics.Collections, RTTI, TypInfo {$ENDIF} ; type {$IFNDEF FPC} PtrInt = longint; PtrUInt = Longword; {$ENDIF} SuperInt = Int64; {$if (sizeof(Char) = 1)} SOChar = WideChar; SOIChar = Word; PSOChar = PWideChar; SOString = WideString; {$else} SOChar = Char; SOIChar = Word; PSOChar = PChar; SOString = string; {$ifend} const SUPER_ARRAY_LIST_DEFAULT_SIZE = 32; SUPER_TOKENER_MAX_DEPTH = 64; SUPER_AVL_MAX_DEPTH = sizeof(longint) * 8; SUPER_AVL_MASK_HIGH_BIT = not ((not longword(0)) shr 1); type // forward declarations TSuperObject = class; ISuperObject = interface; TSuperArray = class; (* AVL Tree * This is a "special" autobalanced AVL tree * It use a hash value for fast compare *) {$IFDEF SUPER_METHOD} TSuperMethod = procedure(const This, Params: ISuperObject; var Result: ISuperObject); {$ENDIF} TSuperAvlBitArray = set of 0..SUPER_AVL_MAX_DEPTH - 1; TSuperAvlSearchType = (stEQual, stLess, stGreater); TSuperAvlSearchTypes = set of TSuperAvlSearchType; TSuperAvlIterator = class; TSuperAvlEntry = class private FGt, FLt: TSuperAvlEntry; FBf: integer; FHash: Cardinal; FName: SOString; FPtr: Pointer; function GetValue: ISuperObject; procedure SetValue(const val: ISuperObject); public class function Hash(const k: SOString): Cardinal; virtual; constructor Create(const AName: SOString; Obj: Pointer); virtual; property Name: SOString read FName; property Ptr: Pointer read FPtr; property Value: ISuperObject read GetValue write SetValue; end; TSuperAvlTree = class private FRoot: TSuperAvlEntry; FCount: Integer; function balance(bal: TSuperAvlEntry): TSuperAvlEntry; protected procedure doDeleteEntry(Entry: TSuperAvlEntry; all: boolean); virtual; function CompareNodeNode(node1, node2: TSuperAvlEntry): integer; virtual; function CompareKeyNode(const k: SOString; h: TSuperAvlEntry): integer; virtual; function Insert(h: TSuperAvlEntry): TSuperAvlEntry; virtual; function Search(const k: SOString; st: TSuperAvlSearchTypes = [stEqual]): TSuperAvlEntry; virtual; public constructor Create; virtual; destructor Destroy; override; function IsEmpty: boolean; procedure Clear(all: boolean = false); virtual; procedure Pack(all: boolean); function Delete(const k: SOString): ISuperObject; function GetEnumerator: TSuperAvlIterator; property count: Integer read FCount; end; TSuperTableString = class(TSuperAvlTree) protected procedure doDeleteEntry(Entry: TSuperAvlEntry; all: boolean); override; procedure PutO(const k: SOString; const value: ISuperObject); function GetO(const k: SOString): ISuperObject; procedure PutS(const k: SOString; const value: SOString); function GetS(const k: SOString): SOString; procedure PutI(const k: SOString; value: SuperInt); function GetI(const k: SOString): SuperInt; procedure PutD(const k: SOString; value: Double); function GetD(const k: SOString): Double; procedure PutB(const k: SOString; value: Boolean); function GetB(const k: SOString): Boolean; {$IFDEF SUPER_METHOD} procedure PutM(const k: SOString; value: TSuperMethod); function GetM(const k: SOString): TSuperMethod; {$ENDIF} procedure PutN(const k: SOString; const value: ISuperObject); function GetN(const k: SOString): ISuperObject; procedure PutC(const k: SOString; value: Currency); function GetC(const k: SOString): Currency; public property O[const k: SOString]: ISuperObject read GetO write PutO; default; property S[const k: SOString]: SOString read GetS write PutS; property I[const k: SOString]: SuperInt read GetI write PutI; property D[const k: SOString]: Double read GetD write PutD; property B[const k: SOString]: Boolean read GetB write PutB; {$IFDEF SUPER_METHOD} property M[const k: SOString]: TSuperMethod read GetM write PutM; {$ENDIF} property N[const k: SOString]: ISuperObject read GetN write PutN; property C[const k: SOString]: Currency read GetC write PutC; function GetValues: ISuperObject; function GetNames: ISuperObject; end; TSuperAvlIterator = class private FTree: TSuperAvlTree; FBranch: TSuperAvlBitArray; FDepth: LongInt; FPath: array[0..SUPER_AVL_MAX_DEPTH - 2] of TSuperAvlEntry; public constructor Create(tree: TSuperAvlTree); virtual; procedure Search(const k: SOString; st: TSuperAvlSearchTypes = [stEQual]); procedure First; procedure Last; function GetIter: TSuperAvlEntry; procedure Next; procedure Prior; // delphi enumerator function MoveNext: Boolean; property Current: TSuperAvlEntry read GetIter; end; TSuperObjectArray = array[0..(high(PtrInt) div sizeof(TSuperObject))-1] of ISuperObject; PSuperObjectArray = ^TSuperObjectArray; TSuperArray = class private FArray: PSuperObjectArray; FLength: Integer; FSize: Integer; procedure Expand(max: Integer); protected function GetO(const index: integer): ISuperObject; procedure PutO(const index: integer; const Value: ISuperObject); function GetB(const index: integer): Boolean; procedure PutB(const index: integer; Value: Boolean); function GetI(const index: integer): SuperInt; procedure PutI(const index: integer; Value: SuperInt); function GetD(const index: integer): Double; procedure PutD(const index: integer; Value: Double); function GetC(const index: integer): Currency; procedure PutC(const index: integer; Value: Currency); function GetS(const index: integer): SOString; procedure PutS(const index: integer; const Value: SOString); {$IFDEF SUPER_METHOD} function GetM(const index: integer): TSuperMethod; procedure PutM(const index: integer; Value: TSuperMethod); {$ENDIF} function GetN(const index: integer): ISuperObject; procedure PutN(const index: integer; const Value: ISuperObject); public constructor Create; virtual; destructor Destroy; override; function Add(const Data: ISuperObject): Integer; function Delete(index: Integer): ISuperObject; procedure Insert(index: Integer; const value: ISuperObject); procedure Clear(all: boolean = false); procedure Pack(all: boolean); property Length: Integer read FLength; property N[const index: integer]: ISuperObject read GetN write PutN; property O[const index: integer]: ISuperObject read GetO write PutO; default; property B[const index: integer]: boolean read GetB write PutB; property I[const index: integer]: SuperInt read GetI write PutI; property D[const index: integer]: Double read GetD write PutD; property C[const index: integer]: Currency read GetC write PutC; property S[const index: integer]: SOString read GetS write PutS; {$IFDEF SUPER_METHOD} property M[const index: integer]: TSuperMethod read GetM write PutM; {$ENDIF} // property A[const index: integer]: TSuperArray read GetA; end; TSuperWriter = class public // abstact methods to overide function Append(buf: PSOChar; Size: Integer): Integer; overload; virtual; abstract; function Append(buf: PSOChar): Integer; overload; virtual; abstract; procedure Reset; virtual; abstract; end; TSuperWriterString = class(TSuperWriter) private FBuf: PSOChar; FBPos: integer; FSize: integer; public function Append(buf: PSOChar; Size: Integer): Integer; overload; override; function Append(buf: PSOChar): Integer; overload; override; procedure Reset; override; procedure TrimRight; constructor Create; virtual; destructor Destroy; override; function GetString: SOString; property Data: PSOChar read FBuf; property Size: Integer read FSize; property Position: integer read FBPos; end; TSuperWriterStream = class(TSuperWriter) private FStream: TStream; public function Append(buf: PSOChar): Integer; override; procedure Reset; override; constructor Create(AStream: TStream); reintroduce; virtual; end; TSuperAnsiWriterStream = class(TSuperWriterStream) public function Append(buf: PSOChar; Size: Integer): Integer; override; end; TSuperUnicodeWriterStream = class(TSuperWriterStream) public function Append(buf: PSOChar; Size: Integer): Integer; override; end; TSuperWriterFake = class(TSuperWriter) private FSize: Integer; public function Append(buf: PSOChar; Size: Integer): Integer; override; function Append(buf: PSOChar): Integer; override; procedure Reset; override; constructor Create; reintroduce; virtual; property size: integer read FSize; end; TSuperWriterSock = class(TSuperWriter) private FSocket: longint; FSize: Integer; public function Append(buf: PSOChar; Size: Integer): Integer; override; function Append(buf: PSOChar): Integer; override; procedure Reset; override; constructor Create(ASocket: longint); reintroduce; virtual; property Socket: longint read FSocket; property Size: Integer read FSize; end; TSuperTokenizerError = ( teSuccess, teContinue, teDepth, teParseEof, teParseUnexpected, teParseNull, teParseBoolean, teParseNumber, teParseArray, teParseObjectKeyName, teParseObjectKeySep, teParseObjectValueSep, teParseString, teParseComment, teEvalObject, teEvalArray, teEvalMethod, teEvalInt ); TSuperTokenerState = ( tsEatws, tsStart, tsFinish, tsNull, tsCommentStart, tsComment, tsCommentEol, tsCommentEnd, tsString, tsStringEscape, tsIdentifier, tsEscapeUnicode, tsEscapeHexadecimal, tsBoolean, tsNumber, tsArray, tsArrayAdd, tsArraySep, tsObjectFieldStart, tsObjectField, tsObjectUnquotedField, tsObjectFieldEnd, tsObjectValue, tsObjectValueAdd, tsObjectSep, tsEvalProperty, tsEvalArray, tsEvalMethod, tsParamValue, tsParamPut, tsMethodValue, tsMethodPut ); PSuperTokenerSrec = ^TSuperTokenerSrec; TSuperTokenerSrec = record state, saved_state: TSuperTokenerState; obj: ISuperObject; current: ISuperObject; field_name: SOString; parent: ISuperObject; gparent: ISuperObject; end; TSuperTokenizer = class public str: PSOChar; pb: TSuperWriterString; depth, is_double, floatcount, st_pos, char_offset: Integer; err: TSuperTokenizerError; ucs_char: Word; quote_char: SOChar; stack: array[0..SUPER_TOKENER_MAX_DEPTH-1] of TSuperTokenerSrec; line, col: Integer; public constructor Create; virtual; destructor Destroy; override; procedure ResetLevel(adepth: integer); procedure Reset; end; // supported object types TSuperType = ( stNull, stBoolean, stDouble, stCurrency, stInt, stObject, stArray, stString {$IFDEF SUPER_METHOD} ,stMethod {$ENDIF} ); TSuperValidateError = ( veRuleMalformated, veFieldIsRequired, veInvalidDataType, veFieldNotFound, veUnexpectedField, veDuplicateEntry, veValueNotInEnum, veInvalidLength, veInvalidRange ); TSuperFindOption = ( foCreatePath, foPutValue, foDelete {$IFDEF SUPER_METHOD} ,foCallMethod {$ENDIF} ); TSuperFindOptions = set of TSuperFindOption; TSuperCompareResult = (cpLess, cpEqu, cpGreat, cpError); TSuperOnValidateError = procedure(sender: Pointer; error: TSuperValidateError; const objpath: SOString); TSuperEnumerator = class private FObj: ISuperObject; FObjEnum: TSuperAvlIterator; FCount: Integer; public constructor Create(const obj: ISuperObject); virtual; destructor Destroy; override; function MoveNext: Boolean; function GetCurrent: ISuperObject; property Current: ISuperObject read GetCurrent; end; ISuperObject = interface ['{4B86A9E3-E094-4E5A-954A-69048B7B6327}'] function GetEnumerator: TSuperEnumerator; function GetDataType: TSuperType; function GetProcessing: boolean; procedure SetProcessing(value: boolean); function ForcePath(const path: SOString; dataType: TSuperType = stObject): ISuperObject; function Format(const str: SOString; BeginSep: SOChar = '%'; EndSep: SOChar = '%'): SOString; function GetO(const path: SOString): ISuperObject; procedure PutO(const path: SOString; const Value: ISuperObject); function GetB(const path: SOString): Boolean; procedure PutB(const path: SOString; Value: Boolean); function GetI(const path: SOString): SuperInt; procedure PutI(const path: SOString; Value: SuperInt); function GetD(const path: SOString): Double; procedure PutC(const path: SOString; Value: Currency); function GetC(const path: SOString): Currency; procedure PutD(const path: SOString; Value: Double); function GetS(const path: SOString): SOString; procedure PutS(const path: SOString; const Value: SOString); {$IFDEF SUPER_METHOD} function GetM(const path: SOString): TSuperMethod; procedure PutM(const path: SOString; Value: TSuperMethod); {$ENDIF} function GetA(const path: SOString): TSuperArray; // Null Object Design patern function GetN(const path: SOString): ISuperObject; procedure PutN(const path: SOString; const Value: ISuperObject); // Writers function Write(writer: TSuperWriter; indent: boolean; escape: boolean; level: integer): Integer; function SaveTo(stream: TStream; indent: boolean = false; escape: boolean = true): integer; overload; function SaveTo(const FileName: string; indent: boolean = false; escape: boolean = true): integer; overload; function SaveTo(socket: longint; indent: boolean = false; escape: boolean = true): integer; overload; function CalcSize(indent: boolean = false; escape: boolean = true): integer; // convert function AsBoolean: Boolean; function AsInteger: SuperInt; function AsDouble: Double; function AsCurrency: Currency; function AsString: SOString; function AsArray: TSuperArray; function AsObject: TSuperTableString; {$IFDEF SUPER_METHOD} function AsMethod: TSuperMethod; {$ENDIF} function AsJSon(indent: boolean = false; escape: boolean = true): SOString; procedure Clear(all: boolean = false); procedure Pack(all: boolean = false); property N[const path: SOString]: ISuperObject read GetN write PutN; property O[const path: SOString]: ISuperObject read GetO write PutO; default; property B[const path: SOString]: boolean read GetB write PutB; property I[const path: SOString]: SuperInt read GetI write PutI; property D[const path: SOString]: Double read GetD write PutD; property C[const path: SOString]: Currency read GetC write PutC; property S[const path: SOString]: SOString read GetS write PutS; {$IFDEF SUPER_METHOD} property M[const path: SOString]: TSuperMethod read GetM write PutM; {$ENDIF} property A[const path: SOString]: TSuperArray read GetA; {$IFDEF SUPER_METHOD} function call(const path: SOString; const param: ISuperObject = nil): ISuperObject; overload; function call(const path, param: SOString): ISuperObject; overload; {$ENDIF} // clone a node function Clone: ISuperObject; function Delete(const path: SOString): ISuperObject; // merges tow objects of same type, if reference is true then nodes are not cloned procedure Merge(const obj: ISuperObject; reference: boolean = false); overload; procedure Merge(const str: SOString); overload; // validate methods function Validate(const rules: SOString; const defs: SOString = ''; callback: TSuperOnValidateError = nil; sender: Pointer = nil): boolean; overload; function Validate(const rules: ISuperObject; const defs: ISuperObject = nil; callback: TSuperOnValidateError = nil; sender: Pointer = nil): boolean; overload; // compare function Compare(const obj: ISuperObject): TSuperCompareResult; overload; function Compare(const str: SOString): TSuperCompareResult; overload; // the data type function IsType(AType: TSuperType): boolean; property DataType: TSuperType read GetDataType; property Processing: boolean read GetProcessing write SetProcessing; function GetDataPtr: Pointer; procedure SetDataPtr(const Value: Pointer); property DataPtr: Pointer read GetDataPtr write SetDataPtr; end; TSuperObject = class(TObject, ISuperObject) private FRefCount: Integer; FProcessing: boolean; FDataType: TSuperType; FDataPtr: Pointer; {.$if true} FO: record case TSuperType of stBoolean: (c_boolean: boolean); stDouble: (c_double: double); stCurrency: (c_currency: Currency); stInt: (c_int: SuperInt); stObject: (c_object: TSuperTableString); stArray: (c_array: TSuperArray); {$IFDEF SUPER_METHOD} stMethod: (c_method: TSuperMethod); {$ENDIF} end; {.$ifend} FOString: SOString; function GetDataType: TSuperType; function GetDataPtr: Pointer; procedure SetDataPtr(const Value: Pointer); protected function QueryInterface(const IID: TGUID; out Obj): HResult; virtual; stdcall; function _AddRef: Integer; virtual; stdcall; function _Release: Integer; virtual; stdcall; function GetO(const path: SOString): ISuperObject; procedure PutO(const path: SOString; const Value: ISuperObject); function GetB(const path: SOString): Boolean; procedure PutB(const path: SOString; Value: Boolean); function GetI(const path: SOString): SuperInt; procedure PutI(const path: SOString; Value: SuperInt); function GetD(const path: SOString): Double; procedure PutD(const path: SOString; Value: Double); procedure PutC(const path: SOString; Value: Currency); function GetC(const path: SOString): Currency; function GetS(const path: SOString): SOString; procedure PutS(const path: SOString; const Value: SOString); {$IFDEF SUPER_METHOD} function GetM(const path: SOString): TSuperMethod; procedure PutM(const path: SOString; Value: TSuperMethod); {$ENDIF} function GetA(const path: SOString): TSuperArray; function Write(writer: TSuperWriter; indent: boolean; escape: boolean; level: integer): Integer; virtual; public function GetEnumerator: TSuperEnumerator; procedure AfterConstruction; override; procedure BeforeDestruction; override; class function NewInstance: TObject; override; property RefCount: Integer read FRefCount; function GetProcessing: boolean; procedure SetProcessing(value: boolean); // Writers function SaveTo(stream: TStream; indent: boolean = false; escape: boolean = true): integer; overload; function SaveTo(const FileName: string; indent: boolean = false; escape: boolean = true): integer; overload; function SaveTo(socket: longint; indent: boolean = false; escape: boolean = true): integer; overload; function CalcSize(indent: boolean = false; escape: boolean = true): integer; function AsJSon(indent: boolean = false; escape: boolean = true): SOString; // parser ... owned! class function ParseString(s: PSOChar; strict: Boolean; partial: boolean = true; const this: ISuperObject = nil; options: TSuperFindOptions = []; const put: ISuperObject = nil; dt: TSuperType = stNull): ISuperObject; class function ParseStream(stream: TStream; strict: Boolean; partial: boolean = true; const this: ISuperObject = nil; options: TSuperFindOptions = []; const put: ISuperObject = nil; dt: TSuperType = stNull): ISuperObject; class function ParseFile(const FileName: string; strict: Boolean; partial: boolean = true; const this: ISuperObject = nil; options: TSuperFindOptions = []; const put: ISuperObject = nil; dt: TSuperType = stNull): ISuperObject; class function ParseEx(tok: TSuperTokenizer; str: PSOChar; len: integer; strict: Boolean; const this: ISuperObject = nil; options: TSuperFindOptions = []; const put: ISuperObject = nil; dt: TSuperType = stNull): ISuperObject; // constructors / destructor constructor Create(jt: TSuperType = stObject); overload; virtual; constructor Create(b: boolean); overload; virtual; constructor Create(i: SuperInt); overload; virtual; constructor Create(d: double); overload; virtual; constructor CreateCurrency(c: Currency); overload; virtual; constructor Create(const s: SOString); overload; virtual; {$IFDEF SUPER_METHOD} constructor Create(m: TSuperMethod); overload; virtual; {$ENDIF} destructor Destroy; override; // convert function AsBoolean: Boolean; virtual; function AsInteger: SuperInt; virtual; function AsDouble: Double; virtual; function AsCurrency: Currency; virtual; function AsString: SOString; virtual; function AsArray: TSuperArray; virtual; function AsObject: TSuperTableString; virtual; {$IFDEF SUPER_METHOD} function AsMethod: TSuperMethod; virtual; {$ENDIF} procedure Clear(all: boolean = false); virtual; procedure Pack(all: boolean = false); virtual; function GetN(const path: SOString): ISuperObject; procedure PutN(const path: SOString; const Value: ISuperObject); function ForcePath(const path: SOString; dataType: TSuperType = stObject): ISuperObject; function Format(const str: SOString; BeginSep: SOChar = '%'; EndSep: SOChar = '%'): SOString; property N[const path: SOString]: ISuperObject read GetN write PutN; property O[const path: SOString]: ISuperObject read GetO write PutO; default; property B[const path: SOString]: boolean read GetB write PutB; property I[const path: SOString]: SuperInt read GetI write PutI; property D[const path: SOString]: Double read GetD write PutD; property C[const path: SOString]: Currency read GetC write PutC; property S[const path: SOString]: SOString read GetS write PutS; {$IFDEF SUPER_METHOD} property M[const path: SOString]: TSuperMethod read GetM write PutM; {$ENDIF} property A[const path: SOString]: TSuperArray read GetA; {$IFDEF SUPER_METHOD} function call(const path: SOString; const param: ISuperObject = nil): ISuperObject; overload; virtual; function call(const path, param: SOString): ISuperObject; overload; virtual; {$ENDIF} // clone a node function Clone: ISuperObject; virtual; function Delete(const path: SOString): ISuperObject; // merges tow objects of same type, if reference is true then nodes are not cloned procedure Merge(const obj: ISuperObject; reference: boolean = false); overload; procedure Merge(const str: SOString); overload; // validate methods function Validate(const rules: SOString; const defs: SOString = ''; callback: TSuperOnValidateError = nil; sender: Pointer = nil): boolean; overload; function Validate(const rules: ISuperObject; const defs: ISuperObject = nil; callback: TSuperOnValidateError = nil; sender: Pointer = nil): boolean; overload; // compare function Compare(const obj: ISuperObject): TSuperCompareResult; overload; function Compare(const str: SOString): TSuperCompareResult; overload; // the data type function IsType(AType: TSuperType): boolean; property DataType: TSuperType read GetDataType; // a data pointer to link to something ele, a treeview for example property DataPtr: Pointer read GetDataPtr write SetDataPtr; property Processing: boolean read GetProcessing; end; {$IFDEF VER210} TSuperRttiContext = class; TSerialFromJson = function(ctx: TSuperRttiContext; const obj: ISuperObject; var Value: TValue): Boolean; TSerialToJson = function(ctx: TSuperRttiContext; var value: TValue; const index: ISuperObject): ISuperObject; TSuperAttribute = class(TCustomAttribute) private FName: string; public constructor Create(const AName: string); property Name: string read FName; end; SOName = class(TSuperAttribute); SODefault = class(TSuperAttribute); TSuperRttiContext = class private class function GetFieldName(r: TRttiField): string; class function GetFieldDefault(r: TRttiField; const obj: ISuperObject): ISuperObject; public Context: TRttiContext; SerialFromJson: TDictionary; SerialToJson: TDictionary; constructor Create; virtual; destructor Destroy; override; function FromJson(TypeInfo: PTypeInfo; const obj: ISuperObject; var Value: TValue): Boolean; virtual; function ToJson(var value: TValue; const index: ISuperObject): ISuperObject; virtual; function AsType(const obj: ISuperObject): T; function AsJson(const obj: T; const index: ISuperObject = nil): ISuperObject; end; TSuperObjectHelper = class helper for TObject public function ToJson(ctx: TSuperRttiContext = nil): ISuperObject; constructor FromJson(const obj: ISuperObject; ctx: TSuperRttiContext = nil); overload; constructor FromJson(const str: string; ctx: TSuperRttiContext = nil); overload; end; {$ENDIF} TSuperObjectIter = record key: SOString; val: ISuperObject; Ite: TSuperAvlIterator; end; function ObjectIsError(obj: TSuperObject): boolean; function ObjectIsType(const obj: ISuperObject; typ: TSuperType): boolean; function ObjectGetType(const obj: ISuperObject): TSuperType; function ObjectFindFirst(const obj: ISuperObject; var F: TSuperObjectIter): boolean; function ObjectFindNext(var F: TSuperObjectIter): boolean; procedure ObjectFindClose(var F: TSuperObjectIter); function SO(const s: SOString = '{}'): ISuperObject; overload; function SO(const value: Variant): ISuperObject; overload; function SO(const Args: array of const): ISuperObject; overload; function SA(const Args: array of const): ISuperObject; overload; function JavaToDelphiDateTime(const dt: int64): TDateTime; function DelphiToJavaDateTime(const dt: TDateTime): int64; {$IFDEF VER210} type TSuperInvokeResult = ( irSuccess, irMethothodError, // method don't exist irParamError, // invalid parametters irError // other error ); function TrySOInvoke(var ctx: TSuperRttiContext; const obj: TValue; const method: string; const params: ISuperObject; var Return: ISuperObject): TSuperInvokeResult; overload; function SOInvoke(const obj: TValue; const method: string; const params: ISuperObject; ctx: TSuperRttiContext = nil): ISuperObject; overload; function SOInvoke(const obj: TValue; const method: string; const params: string; ctx: TSuperRttiContext = nil): ISuperObject; overload; {$ENDIF} implementation uses sysutils, {$IFDEF UNIX} baseunix, unix, DateUtils {$ELSE} Windows {$ENDIF} {$IFDEF FPC} ,sockets {$ELSE} ,WinSock {$ENDIF}; {$IFDEF DEBUG} var debugcount: integer = 0; {$ENDIF} const super_number_chars_set = ['0'..'9','.','+','-','e','E']; super_hex_chars: PSOChar = '0123456789abcdef'; super_hex_chars_set = ['0'..'9','a'..'f','A'..'F']; ESC_BS: PSOChar = '\b'; ESC_LF: PSOChar = '\n'; ESC_CR: PSOChar = '\r'; ESC_TAB: PSOChar = '\t'; ESC_FF: PSOChar = '\f'; ESC_QUOT: PSOChar = '\"'; ESC_SL: PSOChar = '\\'; ESC_SR: PSOChar = '\/'; ESC_ZERO: PSOChar = '\u0000'; TOK_CRLF: PSOChar = #13#10; TOK_SP: PSOChar = #32; TOK_BS: PSOChar = #8; TOK_TAB: PSOChar = #9; TOK_LF: PSOChar = #10; TOK_FF: PSOChar = #12; TOK_CR: PSOChar = #13; // TOK_SL: PSOChar = '\'; // TOK_SR: PSOChar = '/'; TOK_NULL: PSOChar = 'null'; TOK_CBL: PSOChar = '{'; // curly bracket left TOK_CBR: PSOChar = '}'; // curly bracket right TOK_ARL: PSOChar = '['; TOK_ARR: PSOChar = ']'; TOK_ARRAY: PSOChar = '[]'; TOK_OBJ: PSOChar = '{}'; // empty object TOK_COM: PSOChar = ','; // Comma TOK_DQT: PSOChar = '"'; // Double Quote TOK_TRUE: PSOChar = 'true'; TOK_FALSE: PSOChar = 'false'; {$if (sizeof(Char) = 1)} function StrLComp(const Str1, Str2: PSOChar; MaxLen: Cardinal): Integer; var P1, P2: PWideChar; I: Cardinal; C1, C2: WideChar; begin P1 := Str1; P2 := Str2; I := 0; while I < MaxLen do begin C1 := P1^; C2 := P2^; if (C1 <> C2) or (C1 = #0) then begin Result := Ord(C1) - Ord(C2); Exit; end; Inc(P1); Inc(P2); Inc(I); end; Result := 0; end; function StrComp(const Str1, Str2: PSOChar): Integer; var P1, P2: PWideChar; C1, C2: WideChar; begin P1 := Str1; P2 := Str2; while True do begin C1 := P1^; C2 := P2^; if (C1 <> C2) or (C1 = #0) then begin Result := Ord(C1) - Ord(C2); Exit; end; Inc(P1); Inc(P2); end; end; function StrLen(const Str: PSOChar): Cardinal; var p: PSOChar; begin Result := 0; if Str <> nil then begin p := Str; while p^ <> #0 do inc(p); Result := (p - Str); end; end; {$ifend} function CurrToStr(c: Currency): SOString; var p: PSOChar; i, len: Integer; begin Result := IntToStr(Abs(PInt64(@c)^)); len := Length(Result); SetLength(Result, len+1); if c <> 0 then begin while len <= 4 do begin Result := '0' + Result; inc(len); end; p := PSOChar(Result); inc(p, len-1); i := 0; repeat if p^ <> '0' then begin len := len - i + 1; repeat p[1] := p^; dec(p); inc(i); until i > 3; Break; end; dec(p); inc(i); if i > 3 then begin len := len - i + 1; Break; end; until false; p[1] := '.'; SetLength(Result, len); if c < 0 then Result := '-' + Result; end; end; {$IFDEF UNIX} {$linklib c} {$ENDIF} function gcvt(value: Double; ndigit: longint; buf: PAnsiChar): PAnsiChar; cdecl; external {$IFDEF MSWINDOWS} 'msvcrt.dll' name '_gcvt'{$ENDIF}; {$IFDEF UNIX} type ptm = ^tm; tm = record tm_sec: Integer; (* Seconds: 0-59 (K&R says 0-61?) *) tm_min: Integer; (* Minutes: 0-59 *) tm_hour: Integer; (* Hours since midnight: 0-23 *) tm_mday: Integer; (* Day of the month: 1-31 *) tm_mon: Integer; (* Months *since* january: 0-11 *) tm_year: Integer; (* Years since 1900 *) tm_wday: Integer; (* Days since Sunday (0-6) *) tm_yday: Integer; (* Days since Jan. 1: 0-365 *) tm_isdst: Integer; (* +1 Daylight Savings Time, 0 No DST, -1 don't know *) end; function mktime(p: ptm): LongInt; cdecl; external; function gmtime(const t: PLongint): ptm; cdecl; external; function localtime (const t: PLongint): ptm; cdecl; external; function DelphiToJavaDateTime(const dt: TDateTime): Int64; var p: ptm; l, ms: Integer; v: Int64; begin v := Round((dt - 25569) * 86400000); ms := v mod 1000; l := v div 1000; p := localtime(@l); Result := Int64(mktime(p)) * 1000 + ms; end; function JavaToDelphiDateTime(const dt: int64): TDateTime; var p: ptm; l, ms: Integer; begin l := dt div 1000; ms := dt mod 1000; p := gmtime(@l); Result := EncodeDateTime(p^.tm_year+1900, p^.tm_mon+1, p^.tm_mday, p^.tm_hour, p^.tm_min, p^.tm_sec, ms); end; {$ELSE} {$IFDEF WINDOWSNT_COMPATIBILITY} function DayLightCompareDate(const date: PSystemTime; const compareDate: PSystemTime): Integer; var limit_day, dayinsecs, weekofmonth: Integer; First: Word; begin if (date^.wMonth < compareDate^.wMonth) then begin Result := -1; (* We are in a month before the date limit. *) Exit; end; if (date^.wMonth > compareDate^.wMonth) then begin Result := 1; (* We are in a month after the date limit. *) Exit; end; (* if year is 0 then date is in day-of-week format, otherwise * it's absolute date. *) if (compareDate^.wYear = 0) then begin (* compareDate.wDay is interpreted as number of the week in the month * 5 means: the last week in the month *) weekofmonth := compareDate^.wDay; (* calculate the day of the first DayOfWeek in the month *) First := (6 + compareDate^.wDayOfWeek - date^.wDayOfWeek + date^.wDay) mod 7 + 1; limit_day := First + 7 * (weekofmonth - 1); (* check needed for the 5th weekday of the month *) if (limit_day > MonthDays[(date^.wMonth=2) and IsLeapYear(date^.wYear)][date^.wMonth - 1]) then dec(limit_day, 7); end else limit_day := compareDate^.wDay; (* convert to seconds *) limit_day := ((limit_day * 24 + compareDate^.wHour) * 60 + compareDate^.wMinute ) * 60; dayinsecs := ((date^.wDay * 24 + date^.wHour) * 60 + date^.wMinute ) * 60 + date^.wSecond; (* and compare *) if dayinsecs < limit_day then Result := -1 else if dayinsecs > limit_day then Result := 1 else Result := 0; (* date is equal to the date limit. *) end; function CompTimeZoneID(const pTZinfo: PTimeZoneInformation; lpFileTime: PFileTime; islocal: Boolean): LongWord; var ret: Integer; beforeStandardDate, afterDaylightDate: Boolean; llTime: Int64; SysTime: TSystemTime; ftTemp: TFileTime; begin llTime := 0; if (pTZinfo^.DaylightDate.wMonth <> 0) then begin (* if year is 0 then date is in day-of-week format, otherwise * it's absolute date. *) if ((pTZinfo^.StandardDate.wMonth = 0) or ((pTZinfo^.StandardDate.wYear = 0) and ((pTZinfo^.StandardDate.wDay < 1) or (pTZinfo^.StandardDate.wDay > 5) or (pTZinfo^.DaylightDate.wDay < 1) or (pTZinfo^.DaylightDate.wDay > 5)))) then begin SetLastError(ERROR_INVALID_PARAMETER); Result := TIME_ZONE_ID_INVALID; Exit; end; if (not islocal) then begin llTime := PInt64(lpFileTime)^; dec(llTime, Int64(pTZinfo^.Bias + pTZinfo^.DaylightBias) * 600000000); PInt64(@ftTemp)^ := llTime; lpFileTime := @ftTemp; end; FileTimeToSystemTime(lpFileTime^, SysTime); (* check for daylight savings *) ret := DayLightCompareDate(@SysTime, @pTZinfo^.StandardDate); if (ret = -2) then begin Result := TIME_ZONE_ID_INVALID; Exit; end; beforeStandardDate := ret < 0; if (not islocal) then begin dec(llTime, Int64(pTZinfo^.StandardBias - pTZinfo^.DaylightBias) * 600000000); PInt64(@ftTemp)^ := llTime; FileTimeToSystemTime(lpFileTime^, SysTime); end; ret := DayLightCompareDate(@SysTime, @pTZinfo^.DaylightDate); if (ret = -2) then begin Result := TIME_ZONE_ID_INVALID; Exit; end; afterDaylightDate := ret >= 0; Result := TIME_ZONE_ID_STANDARD; if( pTZinfo^.DaylightDate.wMonth < pTZinfo^.StandardDate.wMonth ) then begin (* Northern hemisphere *) if( beforeStandardDate and afterDaylightDate) then Result := TIME_ZONE_ID_DAYLIGHT; end else (* Down south *) if( beforeStandardDate or afterDaylightDate) then Result := TIME_ZONE_ID_DAYLIGHT; end else (* No transition date *) Result := TIME_ZONE_ID_UNKNOWN; end; function GetTimezoneBias(const pTZinfo: PTimeZoneInformation; lpFileTime: PFileTime; islocal: Boolean; pBias: PLongint): Boolean; var bias: LongInt; tzid: LongWord; begin bias := pTZinfo^.Bias; tzid := CompTimeZoneID(pTZinfo, lpFileTime, islocal); if( tzid = TIME_ZONE_ID_INVALID) then begin Result := False; Exit; end; if (tzid = TIME_ZONE_ID_DAYLIGHT) then inc(bias, pTZinfo^.DaylightBias) else if (tzid = TIME_ZONE_ID_STANDARD) then inc(bias, pTZinfo^.StandardBias); pBias^ := bias; Result := True; end; function SystemTimeToTzSpecificLocalTime( lpTimeZoneInformation: PTimeZoneInformation; lpUniversalTime, lpLocalTime: PSystemTime): BOOL; var ft: TFileTime; lBias: LongInt; llTime: Int64; tzinfo: TTimeZoneInformation; begin if (lpTimeZoneInformation <> nil) then tzinfo := lpTimeZoneInformation^ else if (GetTimeZoneInformation(tzinfo) = TIME_ZONE_ID_INVALID) then begin Result := False; Exit; end; if (not SystemTimeToFileTime(lpUniversalTime^, ft)) then begin Result := False; Exit; end; llTime := PInt64(@ft)^; if (not GetTimezoneBias(@tzinfo, @ft, False, @lBias)) then begin Result := False; Exit; end; (* convert minutes to 100-nanoseconds-ticks *) dec(llTime, Int64(lBias) * 600000000); PInt64(@ft)^ := llTime; Result := FileTimeToSystemTime(ft, lpLocalTime^); end; function TzSpecificLocalTimeToSystemTime( const lpTimeZoneInformation: PTimeZoneInformation; const lpLocalTime: PSystemTime; lpUniversalTime: PSystemTime): BOOL; var ft: TFileTime; lBias: LongInt; t: Int64; tzinfo: TTimeZoneInformation; begin if (lpTimeZoneInformation <> nil) then tzinfo := lpTimeZoneInformation^ else if (GetTimeZoneInformation(tzinfo) = TIME_ZONE_ID_INVALID) then begin Result := False; Exit; end; if (not SystemTimeToFileTime(lpLocalTime^, ft)) then begin Result := False; Exit; end; t := PInt64(@ft)^; if (not GetTimezoneBias(@tzinfo, @ft, True, @lBias)) then begin Result := False; Exit; end; (* convert minutes to 100-nanoseconds-ticks *) inc(t, Int64(lBias) * 600000000); PInt64(@ft)^ := t; Result := FileTimeToSystemTime(ft, lpUniversalTime^); end; {$ELSE} function TzSpecificLocalTimeToSystemTime( lpTimeZoneInformation: PTimeZoneInformation; lpLocalTime, lpUniversalTime: PSystemTime): BOOL; stdcall; external 'kernel32.dll'; function SystemTimeToTzSpecificLocalTime( lpTimeZoneInformation: PTimeZoneInformation; lpUniversalTime, lpLocalTime: PSystemTime): BOOL; stdcall; external 'kernel32.dll'; {$ENDIF} function JavaToDelphiDateTime(const dt: int64): TDateTime; var t: TSystemTime; begin DateTimeToSystemTime(25569 + (dt / 86400000), t); SystemTimeToTzSpecificLocalTime(nil, @t, @t); Result := SystemTimeToDateTime(t); end; function DelphiToJavaDateTime(const dt: TDateTime): int64; var t: TSystemTime; begin DateTimeToSystemTime(dt, t); TzSpecificLocalTimeToSystemTime(nil, @t, @t); Result := Round((SystemTimeToDateTime(t) - 25569) * 86400000) end; {$ENDIF} function SO(const s: SOString): ISuperObject; overload; begin Result := TSuperObject.ParseString(PSOChar(s), False); end; function SA(const Args: array of const): ISuperObject; overload; type TByteArray = array[0..sizeof(integer) - 1] of byte; PByteArray = ^TByteArray; var j: Integer; intf: IInterface; begin Result := TSuperObject.Create(stArray); for j := 0 to length(Args) - 1 do with Result.AsArray do case TVarRec(Args[j]).VType of vtInteger : Add(TSuperObject.Create(TVarRec(Args[j]).VInteger)); vtInt64 : Add(TSuperObject.Create(TVarRec(Args[j]).VInt64^)); vtBoolean : Add(TSuperObject.Create(TVarRec(Args[j]).VBoolean)); vtChar : Add(TSuperObject.Create(SOString(TVarRec(Args[j]).VChar))); vtWideChar: Add(TSuperObject.Create(SOChar(TVarRec(Args[j]).VWideChar))); vtExtended: Add(TSuperObject.Create(TVarRec(Args[j]).VExtended^)); vtCurrency: Add(TSuperObject.CreateCurrency(TVarRec(Args[j]).VCurrency^)); vtString : Add(TSuperObject.Create(SOString(TVarRec(Args[j]).VString^))); vtPChar : Add(TSuperObject.Create(SOString(TVarRec(Args[j]).VPChar^))); vtAnsiString: Add(TSuperObject.Create(SOString(AnsiString(TVarRec(Args[j]).VAnsiString)))); vtWideString: Add(TSuperObject.Create(SOString(PWideChar(TVarRec(Args[j]).VWideString)))); vtInterface: if TVarRec(Args[j]).VInterface = nil then Add(nil) else if IInterface(TVarRec(Args[j]).VInterface).QueryInterface(ISuperObject, intf) = 0 then Add(ISuperObject(intf)) else Add(nil); vtPointer : if TVarRec(Args[j]).VPointer = nil then Add(nil) else Add(TSuperObject.Create(PtrInt(TVarRec(Args[j]).VPointer))); vtVariant: Add(SO(TVarRec(Args[j]).VVariant^)); vtObject: if TVarRec(Args[j]).VPointer = nil then Add(nil) else Add(TSuperObject.Create(PtrInt(TVarRec(Args[j]).VPointer))); vtClass: if TVarRec(Args[j]).VPointer = nil then Add(nil) else Add(TSuperObject.Create(PtrInt(TVarRec(Args[j]).VPointer))); {$if declared(vtUnicodeString)} vtUnicodeString: Add(TSuperObject.Create(SOString(string(TVarRec(Args[j]).VUnicodeString)))); {$ifend} else assert(false); end; end; function SO(const Args: array of const): ISuperObject; overload; var j: Integer; arr: ISuperObject; begin Result := TSuperObject.Create(stObject); arr := SA(Args); with arr.AsArray do for j := 0 to (Length div 2) - 1 do Result.AsObject.PutO(O[j*2].AsString, O[(j*2) + 1]); end; function SO(const value: Variant): ISuperObject; overload; begin with TVarData(value) do case VType of varNull: Result := nil; varEmpty: Result := nil; varSmallInt: Result := TSuperObject.Create(VSmallInt); varInteger: Result := TSuperObject.Create(VInteger); varSingle: Result := TSuperObject.Create(VSingle); varDouble: Result := TSuperObject.Create(VDouble); varCurrency: Result := TSuperObject.CreateCurrency(VCurrency); varDate: Result := TSuperObject.Create(DelphiToJavaDateTime(vDate)); varOleStr: Result := TSuperObject.Create(SOString(VOleStr)); varBoolean: Result := TSuperObject.Create(VBoolean); varShortInt: Result := TSuperObject.Create(VShortInt); varByte: Result := TSuperObject.Create(VByte); varWord: Result := TSuperObject.Create(VWord); varLongWord: Result := TSuperObject.Create(VLongWord); varInt64: Result := TSuperObject.Create(VInt64); varString: Result := TSuperObject.Create(SOString(AnsiString(VString))); {$if declared(varUString)} varUString: Result := TSuperObject.Create(SOString(string(VUString))); {$ifend} else raise Exception.CreateFmt('Unsuported variant data type: %d', [VType]); end; end; function ObjectIsError(obj: TSuperObject): boolean; begin Result := PtrUInt(obj) > PtrUInt(-4000); end; function ObjectIsType(const obj: ISuperObject; typ: TSuperType): boolean; begin if obj <> nil then Result := typ = obj.DataType else Result := typ = stNull; end; function ObjectGetType(const obj: ISuperObject): TSuperType; begin if obj <> nil then Result := obj.DataType else Result := stNull; end; function ObjectFindFirst(const obj: ISuperObject; var F: TSuperObjectIter): boolean; var i: TSuperAvlEntry; begin if ObjectIsType(obj, stObject) then begin F.Ite := TSuperAvlIterator.Create(obj.AsObject); F.Ite.First; i := F.Ite.GetIter; if i <> nil then begin f.key := i.Name; f.val := i.Value; Result := true; end else Result := False; end else Result := False; end; function ObjectFindNext(var F: TSuperObjectIter): boolean; var i: TSuperAvlEntry; begin F.Ite.Next; i := F.Ite.GetIter; if i <> nil then begin f.key := i.FName; f.val := i.Value; Result := true; end else Result := False; end; procedure ObjectFindClose(var F: TSuperObjectIter); begin F.Ite.Free; F.val := nil; end; {$IFDEF VER210} function serialtoboolean(ctx: TSuperRttiContext; var value: TValue; const index: ISuperObject): ISuperObject; begin Result := TSuperObject.Create(TValueData(value).FAsSLong <> 0); end; function serialtodatetime(ctx: TSuperRttiContext; var value: TValue; const index: ISuperObject): ISuperObject; begin Result := TSuperObject.Create(DelphiToJavaDateTime(TValueData(value).FAsDouble)); end; function serialtoguid(ctx: TSuperRttiContext; var value: TValue; const index: ISuperObject): ISuperObject; var g: TGUID; begin value.ExtractRawData(@g); Result := TSuperObject.Create( format('%.8x-%.4x-%.4x-%.2x%.2x-%.2x%.2x%.2x%.2x%.2x%.2x', [g.D1, g.D2, g.D3, g.D4[0], g.D4[1], g.D4[2], g.D4[3], g.D4[4], g.D4[5], g.D4[6], g.D4[7]]) ); end; function serialfromboolean(ctx: TSuperRttiContext; const obj: ISuperObject; var Value: TValue): Boolean; var o: ISuperObject; begin case ObjectGetType(obj) of stBoolean: begin TValueData(Value).FAsSLong := obj.AsInteger; Result := True; end; stInt: begin TValueData(Value).FAsSLong := ord(obj.AsInteger <> 0); Result := True; end; stString: begin o := SO(obj.AsString); if not ObjectIsType(o, stString) then Result := serialfromboolean(ctx, SO(obj.AsString), Value) else Result := False; end; else Result := False; end; end; function serialfromdatetime(ctx: TSuperRttiContext; const obj: ISuperObject; var Value: TValue): Boolean; var dt: TDateTime; begin case ObjectGetType(obj) of stInt: begin TValueData(Value).FAsDouble := JavaToDelphiDateTime(obj.AsInteger); Result := True; end; stString: begin if TryStrToDateTime(obj.AsString, dt) then begin TValueData(Value).FAsDouble := dt; Result := True; end else Result := False; end; else Result := False; end; end; function UuidFromString(const s: PSOChar; Uuid: PGUID): Boolean; const hex2bin: array[#0..#102] of short = ( -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, (* 0x00 *) -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, (* 0x10 *) -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, (* 0x20 *) 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1,-1,-1,-1,-1, (* 0x30 *) -1,10,11,12,13,14,15,-1,-1,-1,-1,-1,-1,-1,-1,-1, (* 0x40 *) -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, (* 0x50 *) -1,10,11,12,13,14,15); (* 0x60 *) var i: Integer; begin if (strlen(s) <> 36) then Exit(False); if ((s[8] <> '-') or (s[13] <> '-') or (s[18] <> '-') or (s[23] <> '-')) then Exit(False); for i := 0 to 35 do begin if not i in [8,13,18,23] then if ((s[i] > 'f') or ((hex2bin[s[i]] = -1) and (s[i] <> ''))) then Exit(False); end; uuid.D1 := ((hex2bin[s[0]] shl 28) or (hex2bin[s[1]] shl 24) or (hex2bin[s[2]] shl 20) or (hex2bin[s[3]] shl 16) or (hex2bin[s[4]] shl 12) or (hex2bin[s[5]] shl 8) or (hex2bin[s[6]] shl 4) or hex2bin[s[7]]); uuid.D2 := (hex2bin[s[9]] shl 12) or (hex2bin[s[10]] shl 8) or (hex2bin[s[11]] shl 4) or hex2bin[s[12]]; uuid.D3 := (hex2bin[s[14]] shl 12) or (hex2bin[s[15]] shl 8) or (hex2bin[s[16]] shl 4) or hex2bin[s[17]]; uuid.D4[0] := (hex2bin[s[19]] shl 4) or hex2bin[s[20]]; uuid.D4[1] := (hex2bin[s[21]] shl 4) or hex2bin[s[22]]; uuid.D4[2] := (hex2bin[s[24]] shl 4) or hex2bin[s[25]]; uuid.D4[3] := (hex2bin[s[26]] shl 4) or hex2bin[s[27]]; uuid.D4[4] := (hex2bin[s[28]] shl 4) or hex2bin[s[29]]; uuid.D4[5] := (hex2bin[s[30]] shl 4) or hex2bin[s[31]]; uuid.D4[6] := (hex2bin[s[32]] shl 4) or hex2bin[s[33]]; uuid.D4[7] := (hex2bin[s[34]] shl 4) or hex2bin[s[35]]; Result := True; end; function serialfromguid(ctx: TSuperRttiContext; const obj: ISuperObject; var Value: TValue): Boolean; begin case ObjectGetType(obj) of stNull: begin FillChar(Value.GetReferenceToRawData^, SizeOf(TGUID), 0); Result := True; end; stString: Result := UuidFromString(PSOChar(obj.AsString), Value.GetReferenceToRawData); else Result := False; end; end; function SOInvoke(const obj: TValue; const method: string; const params: ISuperObject; ctx: TSuperRttiContext): ISuperObject; overload; var owned: Boolean; begin if ctx = nil then begin ctx := TSuperRttiContext.Create; owned := True; end else owned := False; try if TrySOInvoke(ctx, obj, method, params, Result) <> irSuccess then raise Exception.Create('Invalid method call'); finally if owned then ctx.Free; end; end; function SOInvoke(const obj: TValue; const method: string; const params: string; ctx: TSuperRttiContext): ISuperObject; overload; begin Result := SOInvoke(obj, method, so(params), ctx) end; function TrySOInvoke(var ctx: TSuperRttiContext; const obj: TValue; const method: string; const params: ISuperObject; var Return: ISuperObject): TSuperInvokeResult; var t: TRttiInstanceType; m: TRttiMethod; a: TArray; ps: TArray; v: TValue; index: ISuperObject; function GetParams: Boolean; var i: Integer; begin case ObjectGetType(params) of stArray: for i := 0 to Length(ps) - 1 do if (pfOut in ps[i].Flags) then TValue.Make(nil, ps[i].ParamType.Handle, a[i]) else if not ctx.FromJson(ps[i].ParamType.Handle, params.AsArray[i], a[i]) then Exit(False); stObject: for i := 0 to Length(ps) - 1 do if (pfOut in ps[i].Flags) then TValue.Make(nil, ps[i].ParamType.Handle, a[i]) else if not ctx.FromJson(ps[i].ParamType.Handle, params.AsObject[ps[i].Name], a[i]) then Exit(False); stNull: ; else Exit(False); end; Result := True; end; procedure SetParams; var i: Integer; begin case ObjectGetType(params) of stArray: for i := 0 to Length(ps) - 1 do if (ps[i].Flags * [pfVar, pfOut]) <> [] then params.AsArray[i] := ctx.ToJson(a[i], index); stObject: for i := 0 to Length(ps) - 1 do if (ps[i].Flags * [pfVar, pfOut]) <> [] then params.AsObject[ps[i].Name] := ctx.ToJson(a[i], index); end; end; begin Result := irSuccess; index := SO; case obj.Kind of tkClass: begin t := TRttiInstanceType(ctx.Context.GetType(obj.AsObject.ClassType)); m := t.GetMethod(method); if m = nil then Exit(irMethothodError); ps := m.GetParameters; SetLength(a, Length(ps)); if not GetParams then Exit(irParamError); if m.IsClassMethod then begin v := m.Invoke(obj.AsObject.ClassType, a); Return := ctx.ToJson(v, index); SetParams; end else begin v := m.Invoke(obj, a); Return := ctx.ToJson(v, index); SetParams; end; end; tkClassRef: begin t := TRttiInstanceType(ctx.Context.GetType(obj.AsClass)); m := t.GetMethod(method); if m = nil then Exit(irMethothodError); ps := m.GetParameters; SetLength(a, Length(ps)); if not GetParams then Exit(irParamError); if m.IsClassMethod then begin v := m.Invoke(obj, a); Return := ctx.ToJson(v, index); SetParams; end else Exit(irError); end; else Exit(irError); end; end; {$ENDIF} { TSuperEnumerator } constructor TSuperEnumerator.Create(const obj: ISuperObject); begin FObj := obj; FCount := -1; if ObjectIsType(FObj, stObject) then FObjEnum := FObj.AsObject.GetEnumerator else FObjEnum := nil; end; destructor TSuperEnumerator.Destroy; begin if FObjEnum <> nil then FObjEnum.Free; end; function TSuperEnumerator.MoveNext: Boolean; begin case ObjectGetType(FObj) of stObject: Result := FObjEnum.MoveNext; stArray: begin inc(FCount); if FCount < FObj.AsArray.Length then Result := True else Result := False; end; else Result := false; end; end; function TSuperEnumerator.GetCurrent: ISuperObject; begin case ObjectGetType(FObj) of stObject: Result := FObjEnum.Current.Value; stArray: Result := FObj.AsArray.GetO(FCount); else Result := FObj; end; end; { TSuperObject } constructor TSuperObject.Create(jt: TSuperType); begin inherited Create; {$IFDEF DEBUG} InterlockedIncrement(debugcount); {$ENDIF} FProcessing := false; FDataPtr := nil; FDataType := jt; case FDataType of stObject: FO.c_object := TSuperTableString.Create; stArray: FO.c_array := TSuperArray.Create; stString: FOString := ''; else FO.c_object := nil; end; end; constructor TSuperObject.Create(b: boolean); begin Create(stBoolean); FO.c_boolean := b; end; constructor TSuperObject.Create(i: SuperInt); begin Create(stInt); FO.c_int := i; end; constructor TSuperObject.Create(d: double); begin Create(stDouble); FO.c_double := d; end; constructor TSuperObject.CreateCurrency(c: Currency); begin Create(stCurrency); FO.c_currency := c; end; destructor TSuperObject.Destroy; begin {$IFDEF DEBUG} InterlockedDecrement(debugcount); {$ENDIF} case FDataType of stObject: FO.c_object.Free; stArray: FO.c_array.Free; end; inherited; end; function TSuperObject.Write(writer: TSuperWriter; indent: boolean; escape: boolean; level: integer): Integer; function DoEscape(str: PSOChar; len: Integer): Integer; var pos, start_offset: Integer; c: SOChar; buf: array[0..5] of SOChar; type TByteChar = record case integer of 0: (a, b: Byte); 1: (c: WideChar); end; begin if str = nil then begin Result := 0; exit; end; pos := 0; start_offset := 0; with writer do while pos < len do begin c := str[pos]; case c of #8,#9,#10,#12,#13,'"','\','/': begin if(pos - start_offset > 0) then Append(str + start_offset, pos - start_offset); if(c = #8) then Append(ESC_BS, 2) else if (c = #9) then Append(ESC_TAB, 2) else if (c = #10) then Append(ESC_LF, 2) else if (c = #12) then Append(ESC_FF, 2) else if (c = #13) then Append(ESC_CR, 2) else if (c = '"') then Append(ESC_QUOT, 2) else if (c = '\') then Append(ESC_SL, 2) else if (c = '/') then Append(ESC_SR, 2); inc(pos); start_offset := pos; end; else if (SOIChar(c) > 255) then begin if(pos - start_offset > 0) then Append(str + start_offset, pos - start_offset); buf[0] := '\'; buf[1] := 'u'; buf[2] := super_hex_chars[TByteChar(c).b shr 4]; buf[3] := super_hex_chars[TByteChar(c).b and $f]; buf[4] := super_hex_chars[TByteChar(c).a shr 4]; buf[5] := super_hex_chars[TByteChar(c).a and $f]; Append(@buf, 6); inc(pos); start_offset := pos; end else if (c < #32) or (c > #127) then begin if(pos - start_offset > 0) then Append(str + start_offset, pos - start_offset); buf[0] := '\'; buf[1] := 'u'; buf[2] := '0'; buf[3] := '0'; buf[4] := super_hex_chars[ord(c) shr 4]; buf[5] := super_hex_chars[ord(c) and $f]; Append(buf, 6); inc(pos); start_offset := pos; end else inc(pos); end; end; if(pos - start_offset > 0) then writer.Append(str + start_offset, pos - start_offset); Result := 0; end; function DoMinimalEscape(str: PSOChar; len: Integer): Integer; var pos, start_offset: Integer; c: SOChar; type TByteChar = record case integer of 0: (a, b: Byte); 1: (c: WideChar); end; begin if str = nil then begin Result := 0; exit; end; pos := 0; start_offset := 0; with writer do while pos < len do begin c := str[pos]; case c of #0: begin if(pos - start_offset > 0) then Append(str + start_offset, pos - start_offset); Append(ESC_ZERO, 6); inc(pos); start_offset := pos; end; '"': begin if(pos - start_offset > 0) then Append(str + start_offset, pos - start_offset); Append(ESC_QUOT, 2); inc(pos); start_offset := pos; end; '\': begin if(pos - start_offset > 0) then Append(str + start_offset, pos - start_offset); Append(ESC_SL, 2); inc(pos); start_offset := pos; end; '/': begin if(pos - start_offset > 0) then Append(str + start_offset, pos - start_offset); Append(ESC_SR, 2); inc(pos); start_offset := pos; end; else inc(pos); end; end; if(pos - start_offset > 0) then writer.Append(str + start_offset, pos - start_offset); Result := 0; end; procedure _indent(i: shortint; r: boolean); begin inc(level, i); if r then with writer do begin {$IFDEF MSWINDOWS} Append(TOK_CRLF, 2); {$ELSE} Append(TOK_LF, 1); {$ENDIF} for i := 0 to level - 1 do Append(TOK_SP, 1); end; end; var k,j: Integer; iter: TSuperObjectIter; st: AnsiString; val: ISuperObject; fbuffer: array[0..31] of AnsiChar; const ENDSTR_A: PSOChar = '": '; ENDSTR_B: PSOChar = '":'; begin if FProcessing then begin Result := writer.Append(TOK_NULL, 4); Exit; end; FProcessing := true; with writer do try case FDataType of stObject: if FO.c_object.FCount > 0 then begin k := 0; Append(TOK_CBL, 1); if indent then _indent(1, false); if ObjectFindFirst(Self, iter) then repeat {$IFDEF SUPER_METHOD} if (iter.val = nil) or not ObjectIsType(iter.val, stMethod) then begin {$ENDIF} if (iter.val = nil) or (not iter.val.Processing) then begin if(k <> 0) then Append(TOK_COM, 1); if indent then _indent(0, true); Append(TOK_DQT, 1); if escape then doEscape(PSOChar(iter.key), Length(iter.key)) else DoMinimalEscape(PSOChar(iter.key), Length(iter.key)); if indent then Append(ENDSTR_A, 3) else Append(ENDSTR_B, 2); if(iter.val = nil) then Append(TOK_NULL, 4) else iter.val.write(writer, indent, escape, level); inc(k); end; {$IFDEF SUPER_METHOD} end; {$ENDIF} until not ObjectFindNext(iter); ObjectFindClose(iter); if indent then _indent(-1, true); Result := Append(TOK_CBR, 1); end else Result := Append(TOK_OBJ, 2); stBoolean: begin if (FO.c_boolean) then Result := Append(TOK_TRUE, 4) else Result := Append(TOK_FALSE, 5); end; stInt: begin str(FO.c_int, st); Result := Append(PSOChar(SOString(st))); end; stDouble: Result := Append(PSOChar(SOString(gcvt(FO.c_double, 15, fbuffer)))); stCurrency: begin Result := Append(PSOChar(CurrToStr(FO.c_currency))); end; stString: begin Append(TOK_DQT, 1); if escape then doEscape(PSOChar(FOString), Length(FOString)) else DoMinimalEscape(PSOChar(FOString), Length(FOString)); Append(TOK_DQT, 1); Result := 0; end; stArray: if FO.c_array.FLength > 0 then begin Append(TOK_ARL, 1); if indent then _indent(1, true); k := 0; j := 0; while k < FO.c_array.FLength do begin val := FO.c_array.GetO(k); {$IFDEF SUPER_METHOD} if not ObjectIsType(val, stMethod) then begin {$ENDIF} if (val = nil) or (not val.Processing) then begin if (j <> 0) then Append(TOK_COM, 1); if(val = nil) then Append(TOK_NULL, 4) else val.write(writer, indent, escape, level); inc(j); end; {$IFDEF SUPER_METHOD} end; {$ENDIF} inc(k); end; if indent then _indent(-1, false); Result := Append(TOK_ARR, 1); end else Result := Append(TOK_ARRAY, 2); stNull: Result := Append(TOK_NULL, 4); else Result := 0; end; finally FProcessing := false; end; end; function TSuperObject.IsType(AType: TSuperType): boolean; begin Result := AType = FDataType; end; function TSuperObject.AsBoolean: boolean; begin case FDataType of stBoolean: Result := FO.c_boolean; stInt: Result := (FO.c_int <> 0); stDouble: Result := (FO.c_double <> 0); stCurrency: Result := (FO.c_currency <> 0); stString: Result := (Length(FOString) <> 0); stNull: Result := False; else Result := True; end; end; function TSuperObject.AsInteger: SuperInt; var code: integer; cint: SuperInt; begin case FDataType of stInt: Result := FO.c_int; stDouble: Result := round(FO.c_double); stCurrency: Result := round(FO.c_currency); stBoolean: Result := ord(FO.c_boolean); stString: begin Val(FOString, cint, code); if code = 0 then Result := cint else Result := 0; end; else Result := 0; end; end; function TSuperObject.AsDouble: Double; var code: integer; cdouble: double; begin case FDataType of stDouble: Result := FO.c_double; stCurrency: Result := FO.c_currency; stInt: Result := FO.c_int; stBoolean: Result := ord(FO.c_boolean); stString: begin Val(FOString, cdouble, code); if code = 0 then Result := cdouble else Result := 0.0; end; else Result := 0.0; end; end; function TSuperObject.AsCurrency: Currency; var code: integer; cdouble: double; begin case FDataType of stDouble: Result := FO.c_double; stCurrency: Result := FO.c_currency; stInt: Result := FO.c_int; stBoolean: Result := ord(FO.c_boolean); stString: begin Val(FOString, cdouble, code); if code = 0 then Result := cdouble else Result := 0.0; end; else Result := 0.0; end; end; function TSuperObject.AsString: SOString; begin if FDataType = stString then Result := FOString else Result := AsJSon(false, false); end; function TSuperObject.GetEnumerator: TSuperEnumerator; begin Result := TSuperEnumerator.Create(Self); end; procedure TSuperObject.AfterConstruction; begin InterlockedDecrement(FRefCount); end; procedure TSuperObject.BeforeDestruction; begin if RefCount <> 0 then raise Exception.Create('Invalid pointer'); end; function TSuperObject.AsArray: TSuperArray; begin if FDataType = stArray then Result := FO.c_array else Result := nil; end; function TSuperObject.AsObject: TSuperTableString; begin if FDataType = stObject then Result := FO.c_object else Result := nil; end; function TSuperObject.AsJSon(indent, escape: boolean): SOString; var pb: TSuperWriterString; begin pb := TSuperWriterString.Create; try if(Write(pb, indent, escape, 0) < 0) then begin Result := ''; Exit; end; if pb.FBPos > 0 then Result := pb.FBuf else Result := ''; finally pb.Free; end; end; class function TSuperObject.ParseString(s: PSOChar; strict: Boolean; partial: boolean; const this: ISuperObject; options: TSuperFindOptions; const put: ISuperObject; dt: TSuperType): ISuperObject; var tok: TSuperTokenizer; obj: ISuperObject; begin tok := TSuperTokenizer.Create; obj := ParseEx(tok, s, -1, strict, this, options, put, dt); if(tok.err <> teSuccess) or (not partial and (s[tok.char_offset] <> #0)) then Result := nil else Result := obj; tok.Free; end; class function TSuperObject.ParseStream(stream: TStream; strict: Boolean; partial: boolean; const this: ISuperObject; options: TSuperFindOptions; const put: ISuperObject; dt: TSuperType): ISuperObject; const BUFFER_SIZE = 1024; var tok: TSuperTokenizer; buffera: array[0..BUFFER_SIZE-1] of AnsiChar; bufferw: array[0..BUFFER_SIZE-1] of SOChar; bom: array[0..1] of byte; unicode: boolean; j, size: Integer; st: string; begin st := ''; tok := TSuperTokenizer.Create; if (stream.Read(bom, sizeof(bom)) = 2) and (bom[0] = $FF) and (bom[1] = $FE) then begin unicode := true; size := stream.Read(bufferw, BUFFER_SIZE * SizeOf(SoChar)) div SizeOf(SoChar); end else begin unicode := false; stream.Seek(0, soFromBeginning); size := stream.Read(buffera, BUFFER_SIZE); end; while size > 0 do begin if not unicode then for j := 0 to size - 1 do bufferw[j] := SOChar(buffera[j]); ParseEx(tok, bufferw, size, strict, this, options, put, dt); if tok.err = teContinue then begin if not unicode then size := stream.Read(buffera, BUFFER_SIZE) else size := stream.Read(bufferw, BUFFER_SIZE * SizeOf(SoChar)) div SizeOf(SoChar); end else Break; end; if(tok.err <> teSuccess) or (not partial and (st[tok.char_offset] <> #0)) then Result := nil else Result := tok.stack[tok.depth].current; tok.Free; end; class function TSuperObject.ParseFile(const FileName: string; strict: Boolean; partial: boolean; const this: ISuperObject; options: TSuperFindOptions; const put: ISuperObject; dt: TSuperType): ISuperObject; var stream: TFileStream; begin stream := TFileStream.Create(FileName, fmOpenRead, fmShareDenyWrite); try Result := ParseStream(stream, strict, partial, this, options, put, dt); finally stream.Free; end; end; class function TSuperObject.ParseEx(tok: TSuperTokenizer; str: PSOChar; len: integer; strict: Boolean; const this: ISuperObject; options: TSuperFindOptions; const put: ISuperObject; dt: TSuperType): ISuperObject; const spaces = [#32,#8,#9,#10,#12,#13]; delimiters = ['"', '.', '[', ']', '{', '}', '(', ')', ',', ':', #0]; reserved = delimiters + spaces; path = ['a'..'z', 'A'..'Z', '.', '_']; function hexdigit(x: SOChar): byte; begin if x <= '9' then Result := byte(x) - byte('0') else Result := (byte(x) and 7) + 9; end; function min(v1, v2: integer): integer; begin if v1 < v2 then result := v1 else result := v2 end; var obj: ISuperObject; v: SOChar; {$IFDEF SUPER_METHOD} sm: TSuperMethod; {$ENDIF} numi: SuperInt; numd: Double; code: integer; TokRec: PSuperTokenerSrec; evalstack: integer; p: PSOChar; function IsEndDelimiter(v: AnsiChar): Boolean; begin if tok.depth > 0 then case tok.stack[tok.depth - 1].state of tsArrayAdd: Result := v in [',', ']', #0]; tsObjectValueAdd: Result := v in [',', '}', #0]; else Result := v = #0; end else Result := v = #0; end; label out, redo_char; begin evalstack := 0; obj := nil; Result := nil; TokRec := @tok.stack[tok.depth]; tok.char_offset := 0; tok.err := teSuccess; repeat if (tok.char_offset = len) then begin if (tok.depth = 0) and (TokRec^.state = tsEatws) and (TokRec^.saved_state = tsFinish) then tok.err := teSuccess else tok.err := teContinue; goto out; end; v := str^; case v of #10: begin inc(tok.line); tok.col := 0; end; #9: inc(tok.col, 4); else inc(tok.col); end; redo_char: case TokRec^.state of tsEatws: begin if (SOIChar(v) < 256) and (AnsiChar(v) in spaces) then {nop} else if (v = '/') then begin tok.pb.Reset; tok.pb.Append(@v, 1); TokRec^.state := tsCommentStart; end else begin TokRec^.state := TokRec^.saved_state; goto redo_char; end end; tsStart: case v of '"', '''': begin TokRec^.state := tsString; tok.pb.Reset; tok.quote_char := v; end; '-': begin TokRec^.state := tsNumber; tok.pb.Reset; tok.is_double := 0; tok.floatcount := -1; goto redo_char; end; '0'..'9': begin if (tok.depth = 0) then case ObjectGetType(this) of stObject: begin TokRec^.state := tsIdentifier; TokRec^.current := this; goto redo_char; end; end; TokRec^.state := tsNumber; tok.pb.Reset; tok.is_double := 0; tok.floatcount := -1; goto redo_char; end; '{': begin TokRec^.state := tsEatws; TokRec^.saved_state := tsObjectFieldStart; TokRec^.current := TSuperObject.Create(stObject); end; '[': begin TokRec^.state := tsEatws; TokRec^.saved_state := tsArray; TokRec^.current := TSuperObject.Create(stArray); end; {$IFDEF SUPER_METHOD} '(': begin if (tok.depth = 0) and ObjectIsType(this, stMethod) then begin TokRec^.current := this; TokRec^.state := tsParamValue; end; end; {$ENDIF} 'N', 'n': begin TokRec^.state := tsNull; tok.pb.Reset; tok.st_pos := 0; goto redo_char; end; 'T', 't', 'F', 'f': begin TokRec^.state := tsBoolean; tok.pb.Reset; tok.st_pos := 0; goto redo_char; end; else TokRec^.state := tsIdentifier; tok.pb.Reset; goto redo_char; end; tsFinish: begin if(tok.depth = 0) then goto out; obj := TokRec^.current; tok.ResetLevel(tok.depth); dec(tok.depth); TokRec := @tok.stack[tok.depth]; goto redo_char; end; tsNull: begin tok.pb.Append(@v, 1); if (StrLComp(TOK_NULL, PSOChar(tok.pb.FBuf), min(tok.st_pos + 1, 4)) = 0) then begin if (tok.st_pos = 4) then if (((SOIChar(v) < 256) and (AnsiChar(v) in path)) or (SOIChar(v) >= 256)) then TokRec^.state := tsIdentifier else begin TokRec^.current := TSuperObject.Create(stNull); TokRec^.saved_state := tsFinish; TokRec^.state := tsEatws; goto redo_char; end; end else begin TokRec^.state := tsIdentifier; tok.pb.FBuf[tok.st_pos] := #0; dec(tok.pb.FBPos); goto redo_char; end; inc(tok.st_pos); end; tsCommentStart: begin if(v = '*') then begin TokRec^.state := tsComment; end else if (v = '/') then begin TokRec^.state := tsCommentEol; end else begin tok.err := teParseComment; goto out; end; tok.pb.Append(@v, 1); end; tsComment: begin if(v = '*') then TokRec^.state := tsCommentEnd; tok.pb.Append(@v, 1); end; tsCommentEol: begin if (v = #10) then TokRec^.state := tsEatws else tok.pb.Append(@v, 1); end; tsCommentEnd: begin tok.pb.Append(@v, 1); if (v = '/') then TokRec^.state := tsEatws else TokRec^.state := tsComment; end; tsString: begin if (v = tok.quote_char) then begin TokRec^.current := TSuperObject.Create(SOString(tok.pb.GetString)); TokRec^.saved_state := tsFinish; TokRec^.state := tsEatws; end else if (v = '\') then begin TokRec^.saved_state := tsString; TokRec^.state := tsStringEscape; end else begin tok.pb.Append(@v, 1); end end; tsEvalProperty: begin if (TokRec^.current = nil) and (foCreatePath in options) then begin TokRec^.current := TSuperObject.Create(stObject); TokRec^.parent.AsObject.PutO(tok.pb.Fbuf, TokRec^.current) end else if not ObjectIsType(TokRec^.current, stObject) then begin tok.err := teEvalObject; goto out; end; tok.pb.Reset; TokRec^.state := tsIdentifier; goto redo_char; end; tsEvalArray: begin if (TokRec^.current = nil) and (foCreatePath in options) then begin TokRec^.current := TSuperObject.Create(stArray); TokRec^.parent.AsObject.PutO(tok.pb.Fbuf, TokRec^.current) end else if not ObjectIsType(TokRec^.current, stArray) then begin tok.err := teEvalArray; goto out; end; tok.pb.Reset; TokRec^.state := tsParamValue; goto redo_char; end; {$IFDEF SUPER_METHOD} tsEvalMethod: begin if ObjectIsType(TokRec^.current, stMethod) and assigned(TokRec^.current.AsMethod) then begin tok.pb.Reset; TokRec^.obj := TSuperObject.Create(stArray); TokRec^.state := tsMethodValue; goto redo_char; end else begin tok.err := teEvalMethod; goto out; end; end; tsMethodValue: begin case v of ')': TokRec^.state := tsIdentifier; else if (tok.depth >= SUPER_TOKENER_MAX_DEPTH-1) then begin tok.err := teDepth; goto out; end; inc(evalstack); TokRec^.state := tsMethodPut; inc(tok.depth); tok.ResetLevel(tok.depth); TokRec := @tok.stack[tok.depth]; goto redo_char; end; end; tsMethodPut: begin TokRec^.obj.AsArray.Add(obj); case v of ',': begin tok.pb.Reset; TokRec^.saved_state := tsMethodValue; TokRec^.state := tsEatws; end; ')': begin if TokRec^.obj.AsArray.Length = 1 then TokRec^.obj := TokRec^.obj.AsArray.GetO(0); dec(evalstack); tok.pb.Reset; TokRec^.saved_state := tsIdentifier; TokRec^.state := tsEatws; end; else tok.err := teEvalMethod; goto out; end; end; {$ENDIF} tsParamValue: begin case v of ']': TokRec^.state := tsIdentifier; else if (tok.depth >= SUPER_TOKENER_MAX_DEPTH-1) then begin tok.err := teDepth; goto out; end; inc(evalstack); TokRec^.state := tsParamPut; inc(tok.depth); tok.ResetLevel(tok.depth); TokRec := @tok.stack[tok.depth]; goto redo_char; end; end; tsParamPut: begin dec(evalstack); TokRec^.obj := obj; tok.pb.Reset; TokRec^.saved_state := tsIdentifier; TokRec^.state := tsEatws; if v <> ']' then begin tok.err := teEvalArray; goto out; end; end; tsIdentifier: begin if (this = nil) then begin if (SOIChar(v) < 256) and IsEndDelimiter(AnsiChar(v)) then begin if not strict then begin tok.pb.TrimRight; TokRec^.current := TSuperObject.Create(tok.pb.Fbuf); TokRec^.saved_state := tsFinish; TokRec^.state := tsEatws; goto redo_char; end else begin tok.err := teParseString; goto out; end; end else if (v = '\') then begin TokRec^.saved_state := tsIdentifier; TokRec^.state := tsStringEscape; end else tok.pb.Append(@v, 1); end else begin if (SOIChar(v) < 256) and (AnsiChar(v) in reserved) then begin TokRec^.gparent := TokRec^.parent; if TokRec^.current = nil then TokRec^.parent := this else TokRec^.parent := TokRec^.current; case ObjectGetType(TokRec^.parent) of stObject: case v of '.': begin TokRec^.state := tsEvalProperty; if tok.pb.FBPos > 0 then TokRec^.current := TokRec^.parent.AsObject.GetO(tok.pb.Fbuf); end; '[': begin TokRec^.state := tsEvalArray; if tok.pb.FBPos > 0 then TokRec^.current := TokRec^.parent.AsObject.GetO(tok.pb.Fbuf); end; '(': begin TokRec^.state := tsEvalMethod; if tok.pb.FBPos > 0 then TokRec^.current := TokRec^.parent.AsObject.GetO(tok.pb.Fbuf); end; else if tok.pb.FBPos > 0 then TokRec^.current := TokRec^.parent.AsObject.GetO(tok.pb.Fbuf); if (foPutValue in options) and (evalstack = 0) then begin TokRec^.parent.AsObject.PutO(tok.pb.Fbuf, put); TokRec^.current := put end else if (foDelete in options) and (evalstack = 0) then begin TokRec^.current := TokRec^.parent.AsObject.Delete(tok.pb.Fbuf); end else if (TokRec^.current = nil) and (foCreatePath in options) then begin TokRec^.current := TSuperObject.Create(dt); TokRec^.parent.AsObject.PutO(tok.pb.Fbuf, TokRec^.current); end; TokRec^.current := TokRec^.parent.AsObject.GetO(tok.pb.Fbuf); TokRec^.state := tsFinish; goto redo_char; end; stArray: begin if TokRec^.obj <> nil then begin if not ObjectIsType(TokRec^.obj, stInt) or (TokRec^.obj.AsInteger < 0) then begin tok.err := teEvalInt; TokRec^.obj := nil; goto out; end; numi := TokRec^.obj.AsInteger; TokRec^.obj := nil; TokRec^.current := TokRec^.parent.AsArray.GetO(numi); case v of '.': if (TokRec^.current = nil) and (foCreatePath in options) then begin TokRec^.current := TSuperObject.Create(stObject); TokRec^.parent.AsArray.PutO(numi, TokRec^.current); end else if (TokRec^.current = nil) then begin tok.err := teEvalObject; goto out; end; '[': begin if (TokRec^.current = nil) and (foCreatePath in options) then begin TokRec^.current := TSuperObject.Create(stArray); TokRec^.parent.AsArray.Add(TokRec^.current); end else if (TokRec^.current = nil) then begin tok.err := teEvalArray; goto out; end; TokRec^.state := tsEvalArray; end; '(': TokRec^.state := tsEvalMethod; else if (foPutValue in options) and (evalstack = 0) then begin TokRec^.parent.AsArray.PutO(numi, put); TokRec^.current := put; end else if (foDelete in options) and (evalstack = 0) then begin TokRec^.current := TokRec^.parent.AsArray.Delete(numi); end else TokRec^.current := TokRec^.parent.AsArray.GetO(numi); TokRec^.state := tsFinish; goto redo_char end; end else begin case v of '.': begin if (foPutValue in options) then begin TokRec^.current := TSuperObject.Create(stObject); TokRec^.parent.AsArray.Add(TokRec^.current); end else TokRec^.current := TokRec^.parent.AsArray.GetO(TokRec^.parent.AsArray.FLength - 1); end; '[': begin if (foPutValue in options) then begin TokRec^.current := TSuperObject.Create(stArray); TokRec^.parent.AsArray.Add(TokRec^.current); end else TokRec^.current := TokRec^.parent.AsArray.GetO(TokRec^.parent.AsArray.FLength - 1); TokRec^.state := tsEvalArray; end; '(': begin if not (foPutValue in options) then TokRec^.current := TokRec^.parent.AsArray.GetO(TokRec^.parent.AsArray.FLength - 1) else TokRec^.current := nil; TokRec^.state := tsEvalMethod; end; else if (foPutValue in options) and (evalstack = 0) then begin TokRec^.parent.AsArray.Add(put); TokRec^.current := put; end else if tok.pb.FBPos = 0 then TokRec^.current := TokRec^.parent.AsArray.GetO(TokRec^.parent.AsArray.FLength - 1); TokRec^.state := tsFinish; goto redo_char end; end; end; {$IFDEF SUPER_METHOD} stMethod: case v of '.': begin TokRec^.current := nil; sm := TokRec^.parent.AsMethod; sm(TokRec^.gparent, TokRec^.obj, TokRec^.current); TokRec^.obj := nil; end; '[': begin TokRec^.current := nil; sm := TokRec^.parent.AsMethod; sm(TokRec^.gparent, TokRec^.obj, TokRec^.current); TokRec^.state := tsEvalArray; TokRec^.obj := nil; end; '(': begin TokRec^.current := nil; sm := TokRec^.parent.AsMethod; sm(TokRec^.gparent, TokRec^.obj, TokRec^.current); TokRec^.state := tsEvalMethod; TokRec^.obj := nil; end; else if not (foPutValue in options) or (evalstack > 0) then begin TokRec^.current := nil; sm := TokRec^.parent.AsMethod; sm(TokRec^.gparent, TokRec^.obj, TokRec^.current); TokRec^.obj := nil; TokRec^.state := tsFinish; goto redo_char end else begin tok.err := teEvalMethod; TokRec^.obj := nil; goto out; end; end; {$ENDIF} end; end else tok.pb.Append(@v, 1); end; end; tsStringEscape: case v of 'b', 'n', 'r', 't', 'f': begin if(v = 'b') then tok.pb.Append(TOK_BS, 1) else if(v = 'n') then tok.pb.Append(TOK_LF, 1) else if(v = 'r') then tok.pb.Append(TOK_CR, 1) else if(v = 't') then tok.pb.Append(TOK_TAB, 1) else if(v = 'f') then tok.pb.Append(TOK_FF, 1); TokRec^.state := TokRec^.saved_state; end; 'u': begin tok.ucs_char := 0; tok.st_pos := 0; TokRec^.state := tsEscapeUnicode; end; 'x': begin tok.ucs_char := 0; tok.st_pos := 0; TokRec^.state := tsEscapeHexadecimal; end else tok.pb.Append(@v, 1); TokRec^.state := TokRec^.saved_state; end; tsEscapeUnicode: begin if ((SOIChar(v) < 256) and (AnsiChar(v) in super_hex_chars_set)) then begin inc(tok.ucs_char, (Word(hexdigit(v)) shl ((3-tok.st_pos)*4))); inc(tok.st_pos); if (tok.st_pos = 4) then begin tok.pb.Append(@tok.ucs_char, 1); TokRec^.state := TokRec^.saved_state; end end else begin tok.err := teParseString; goto out; end end; tsEscapeHexadecimal: begin if ((SOIChar(v) < 256) and (AnsiChar(v) in super_hex_chars_set)) then begin inc(tok.ucs_char, (Word(hexdigit(v)) shl ((1-tok.st_pos)*4))); inc(tok.st_pos); if (tok.st_pos = 2) then begin tok.pb.Append(@tok.ucs_char, 1); TokRec^.state := TokRec^.saved_state; end end else begin tok.err := teParseString; goto out; end end; tsBoolean: begin tok.pb.Append(@v, 1); if (StrLComp('true', PSOChar(tok.pb.FBuf), min(tok.st_pos + 1, 4)) = 0) then begin if (tok.st_pos = 4) then if (((SOIChar(v) < 256) and (AnsiChar(v) in path)) or (SOIChar(v) >= 256)) then TokRec^.state := tsIdentifier else begin TokRec^.current := TSuperObject.Create(true); TokRec^.saved_state := tsFinish; TokRec^.state := tsEatws; goto redo_char; end end else if (StrLComp('false', PSOChar(tok.pb.FBuf), min(tok.st_pos + 1, 5)) = 0) then begin if (tok.st_pos = 5) then if (((SOIChar(v) < 256) and (AnsiChar(v) in path)) or (SOIChar(v) >= 256)) then TokRec^.state := tsIdentifier else begin TokRec^.current := TSuperObject.Create(false); TokRec^.saved_state := tsFinish; TokRec^.state := tsEatws; goto redo_char; end end else begin TokRec^.state := tsIdentifier; tok.pb.FBuf[tok.st_pos] := #0; dec(tok.pb.FBPos); goto redo_char; end; inc(tok.st_pos); end; tsNumber: begin if (SOIChar(v) < 256) and (AnsiChar(v) in super_number_chars_set) then begin tok.pb.Append(@v, 1); if (SOIChar(v) < 256) then case v of '.': begin tok.is_double := 1; tok.floatcount := 0; end; 'e','E': begin tok.is_double := 1; tok.floatcount := -1; end; '0'..'9': begin if (tok.is_double = 1) and (tok.floatcount >= 0) then begin inc(tok.floatcount); if tok.floatcount > 4 then tok.floatcount := -1; end; end; end; end else begin if (tok.is_double = 0) then begin val(tok.pb.FBuf, numi, code); if ObjectIsType(this, stArray) then begin if (foPutValue in options) and (evalstack = 0) then begin this.AsArray.PutO(numi, put); TokRec^.current := put; end else if (foDelete in options) and (evalstack = 0) then TokRec^.current := this.AsArray.Delete(numi) else TokRec^.current := this.AsArray.GetO(numi); end else TokRec^.current := TSuperObject.Create(numi); end else if (tok.is_double <> 0) then begin if tok.floatcount >= 0 then begin p := tok.pb.FBuf; while p^ <> '.' do inc(p); for code := 0 to tok.floatcount - 1 do begin p^ := p[1]; inc(p); end; p^ := #0; val(tok.pb.FBuf, numi, code); case tok.floatcount of 0: numi := numi * 10000; 1: numi := numi * 1000; 2: numi := numi * 100; 3: numi := numi * 10; end; TokRec^.current := TSuperObject.CreateCurrency(PCurrency(@numi)^); end else begin val(tok.pb.FBuf, numd, code); TokRec^.current := TSuperObject.Create(numd); end; end else begin tok.err := teParseNumber; goto out; end; TokRec^.saved_state := tsFinish; TokRec^.state := tsEatws; goto redo_char; end end; tsArray: begin if (v = ']') then begin TokRec^.saved_state := tsFinish; TokRec^.state := tsEatws; end else begin if(tok.depth >= SUPER_TOKENER_MAX_DEPTH-1) then begin tok.err := teDepth; goto out; end; TokRec^.state := tsArrayAdd; inc(tok.depth); tok.ResetLevel(tok.depth); TokRec := @tok.stack[tok.depth]; goto redo_char; end end; tsArrayAdd: begin TokRec^.current.AsArray.Add(obj); TokRec^.saved_state := tsArraySep; TokRec^.state := tsEatws; goto redo_char; end; tsArraySep: begin if (v = ']') then begin TokRec^.saved_state := tsFinish; TokRec^.state := tsEatws; end else if (v = ',') then begin TokRec^.saved_state := tsArray; TokRec^.state := tsEatws; end else begin tok.err := teParseArray; goto out; end end; tsObjectFieldStart: begin if (v = '}') then begin TokRec^.saved_state := tsFinish; TokRec^.state := tsEatws; end else if (SOIChar(v) < 256) and (AnsiChar(v) in ['"', '''']) then begin tok.quote_char := v; tok.pb.Reset; TokRec^.state := tsObjectField; end else if not((SOIChar(v) < 256) and ((AnsiChar(v) in reserved) or strict)) then begin TokRec^.state := tsObjectUnquotedField; tok.pb.Reset; goto redo_char; end else begin tok.err := teParseObjectKeyName; goto out; end end; tsObjectField: begin if (v = tok.quote_char) then begin TokRec^.field_name := tok.pb.FBuf; TokRec^.saved_state := tsObjectFieldEnd; TokRec^.state := tsEatws; end else if (v = '\') then begin TokRec^.saved_state := tsObjectField; TokRec^.state := tsStringEscape; end else begin tok.pb.Append(@v, 1); end end; tsObjectUnquotedField: begin if (SOIChar(v) < 256) and (AnsiChar(v) in [':', #0]) then begin TokRec^.field_name := tok.pb.FBuf; TokRec^.saved_state := tsObjectFieldEnd; TokRec^.state := tsEatws; goto redo_char; end else if (v = '\') then begin TokRec^.saved_state := tsObjectUnquotedField; TokRec^.state := tsStringEscape; end else tok.pb.Append(@v, 1); end; tsObjectFieldEnd: begin if (v = ':') then begin TokRec^.saved_state := tsObjectValue; TokRec^.state := tsEatws; end else begin tok.err := teParseObjectKeySep; goto out; end end; tsObjectValue: begin if (tok.depth >= SUPER_TOKENER_MAX_DEPTH-1) then begin tok.err := teDepth; goto out; end; TokRec^.state := tsObjectValueAdd; inc(tok.depth); tok.ResetLevel(tok.depth); TokRec := @tok.stack[tok.depth]; goto redo_char; end; tsObjectValueAdd: begin TokRec^.current.AsObject.PutO(TokRec^.field_name, obj); TokRec^.field_name := ''; TokRec^.saved_state := tsObjectSep; TokRec^.state := tsEatws; goto redo_char; end; tsObjectSep: begin if (v = '}') then begin TokRec^.saved_state := tsFinish; TokRec^.state := tsEatws; end else if (v = ',') then begin TokRec^.saved_state := tsObjectFieldStart; TokRec^.state := tsEatws; end else begin tok.err := teParseObjectValueSep; goto out; end end; end; inc(str); inc(tok.char_offset); until v = #0; if(TokRec^.state <> tsFinish) and (TokRec^.saved_state <> tsFinish) then tok.err := teParseEof; out: if(tok.err in [teSuccess]) then begin {$IFDEF SUPER_METHOD} if (foCallMethod in options) and ObjectIsType(TokRec^.current, stMethod) and assigned(TokRec^.current.AsMethod) then begin sm := TokRec^.current.AsMethod; sm(TokRec^.parent, put, Result); end else {$ENDIF} Result := TokRec^.current; end else Result := nil; end; procedure TSuperObject.PutO(const path: SOString; const Value: ISuperObject); begin ParseString(PSOChar(path), true, False, self, [foCreatePath, foPutValue], Value); end; procedure TSuperObject.PutB(const path: SOString; Value: Boolean); begin ParseString(PSOChar(path), true, False, self, [foCreatePath, foPutValue], TSuperObject.Create(Value)); end; procedure TSuperObject.PutD(const path: SOString; Value: Double); begin ParseString(PSOChar(path), true, False, self, [foCreatePath, foPutValue], TSuperObject.Create(Value)); end; procedure TSuperObject.PutC(const path: SOString; Value: Currency); begin ParseString(PSOChar(path), true, False, self, [foCreatePath, foPutValue], TSuperObject.CreateCurrency(Value)); end; procedure TSuperObject.PutI(const path: SOString; Value: SuperInt); begin ParseString(PSOChar(path), true, False, self, [foCreatePath, foPutValue], TSuperObject.Create(Value)); end; procedure TSuperObject.PutS(const path: SOString; const Value: SOString); begin ParseString(PSOChar(path), true, False, self, [foCreatePath, foPutValue], TSuperObject.Create(Value)); end; function TSuperObject.QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; begin if GetInterface(IID, Obj) then Result := 0 else Result := E_NOINTERFACE; end; function TSuperObject.SaveTo(stream: TStream; indent, escape: boolean): integer; var pb: TSuperWriterStream; begin if escape then pb := TSuperAnsiWriterStream.Create(stream) else pb := TSuperUnicodeWriterStream.Create(stream); if(Write(pb, indent, escape, 0) < 0) then begin pb.Reset; pb.Free; Result := 0; Exit; end; Result := stream.Size; pb.Free; end; function TSuperObject.CalcSize(indent, escape: boolean): integer; var pb: TSuperWriterFake; begin pb := TSuperWriterFake.Create; if(Write(pb, indent, escape, 0) < 0) then begin pb.Free; Result := 0; Exit; end; Result := pb.FSize; pb.Free; end; function TSuperObject.SaveTo(socket: Integer; indent, escape: boolean): integer; var pb: TSuperWriterSock; begin pb := TSuperWriterSock.Create(socket); if(Write(pb, indent, escape, 0) < 0) then begin pb.Free; Result := 0; Exit; end; Result := pb.FSize; pb.Free; end; constructor TSuperObject.Create(const s: SOString); begin Create(stString); FOString := s; end; procedure TSuperObject.Clear(all: boolean); begin if FProcessing then exit; FProcessing := true; try case FDataType of stBoolean: FO.c_boolean := false; stDouble: FO.c_double := 0.0; stCurrency: FO.c_currency := 0.0; stInt: FO.c_int := 0; stObject: FO.c_object.Clear(all); stArray: FO.c_array.Clear(all); stString: FOString := ''; {$IFDEF SUPER_METHOD} stMethod: FO.c_method := nil; {$ENDIF} end; finally FProcessing := false; end; end; procedure TSuperObject.Pack(all: boolean = false); begin if FProcessing then exit; FProcessing := true; try case FDataType of stObject: FO.c_object.Pack(all); stArray: FO.c_array.Pack(all); end; finally FProcessing := false; end; end; function TSuperObject.GetN(const path: SOString): ISuperObject; begin Result := ParseString(PSOChar(path), False, true, self); if Result = nil then Result := TSuperObject.Create(stNull); end; procedure TSuperObject.PutN(const path: SOString; const Value: ISuperObject); begin if Value = nil then ParseString(PSOChar(path), False, True, self, [foCreatePath, foPutValue], TSuperObject.Create(stNull)) else ParseString(PSOChar(path), False, True, self, [foCreatePath, foPutValue], Value); end; function TSuperObject.Delete(const path: SOString): ISuperObject; begin Result := ParseString(PSOChar(path), False, true, self, [foDelete]); end; function TSuperObject.Clone: ISuperObject; var ite: TSuperObjectIter; arr: TSuperArray; j: integer; begin case FDataType of stBoolean: Result := TSuperObject.Create(FO.c_boolean); stDouble: Result := TSuperObject.Create(FO.c_double); stCurrency: Result := TSuperObject.CreateCurrency(FO.c_currency); stInt: Result := TSuperObject.Create(FO.c_int); stString: Result := TSuperObject.Create(FOString); {$IFDEF SUPER_METHOD} stMethod: Result := TSuperObject.Create(FO.c_method); {$ENDIF} stObject: begin Result := TSuperObject.Create(stObject); if ObjectFindFirst(self, ite) then with Result.AsObject do repeat PutO(ite.key, ite.val.Clone); until not ObjectFindNext(ite); ObjectFindClose(ite); end; stArray: begin Result := TSuperObject.Create(stArray); arr := AsArray; with Result.AsArray do for j := 0 to arr.Length - 1 do Add(arr.GetO(j).Clone); end; else Result := nil; end; end; procedure TSuperObject.Merge(const obj: ISuperObject; reference: boolean); var prop1, prop2: ISuperObject; ite: TSuperObjectIter; arr: TSuperArray; j: integer; begin if ObjectIsType(obj, FDataType) then case FDataType of stBoolean: FO.c_boolean := obj.AsBoolean; stDouble: FO.c_double := obj.AsDouble; stCurrency: FO.c_currency := obj.AsCurrency; stInt: FO.c_int := obj.AsInteger; stString: FOString := obj.AsString; {$IFDEF SUPER_METHOD} stMethod: FO.c_method := obj.AsMethod; {$ENDIF} stObject: begin if ObjectFindFirst(obj, ite) then with FO.c_object do repeat prop1 := FO.c_object.GetO(ite.key); if (prop1 <> nil) and (ite.val <> nil) and (prop1.DataType = ite.val.DataType) then prop1.Merge(ite.val) else if reference then PutO(ite.key, ite.val) else PutO(ite.key, ite.val.Clone); until not ObjectFindNext(ite); ObjectFindClose(ite); end; stArray: begin arr := obj.AsArray; with FO.c_array do for j := 0 to arr.Length - 1 do begin prop1 := GetO(j); prop2 := arr.GetO(j); if (prop1 <> nil) and (prop2 <> nil) and (prop1.DataType = prop2.DataType) then prop1.Merge(prop2) else if reference then PutO(j, prop2) else PutO(j, prop2.Clone); end; end; end; end; procedure TSuperObject.Merge(const str: SOString); begin Merge(TSuperObject.ParseString(PSOChar(str), False), true); end; class function TSuperObject.NewInstance: TObject; begin Result := inherited NewInstance; TSuperObject(Result).FRefCount := 1; end; function TSuperObject.ForcePath(const path: SOString; dataType: TSuperType = stObject): ISuperObject; begin Result := ParseString(PSOChar(path), False, True, Self, [foCreatePath], nil, dataType); end; function TSuperObject.Format(const str: SOString; BeginSep: SOChar; EndSep: SOChar): SOString; var p1, p2: PSOChar; begin Result := ''; p2 := PSOChar(str); p1 := p2; while true do if p2^ = BeginSep then begin if p2 > p1 then Result := Result + Copy(p1, 0, p2-p1); inc(p2); p1 := p2; while true do if p2^ = EndSep then Break else if p2^ = #0 then Exit else inc(p2); Result := Result + GetS(copy(p1, 0, p2-p1)); inc(p2); p1 := p2; end else if p2^ = #0 then begin if p2 > p1 then Result := Result + Copy(p1, 0, p2-p1); Break; end else inc(p2); end; function TSuperObject.GetO(const path: SOString): ISuperObject; begin Result := ParseString(PSOChar(path), False, True, Self); end; function TSuperObject.GetA(const path: SOString): TSuperArray; var obj: ISuperObject; begin obj := ParseString(PSOChar(path), False, True, Self); if obj <> nil then Result := obj.AsArray else Result := nil; end; function TSuperObject.GetB(const path: SOString): Boolean; var obj: ISuperObject; begin obj := GetO(path); if obj <> nil then Result := obj.AsBoolean else Result := false; end; function TSuperObject.GetD(const path: SOString): Double; var obj: ISuperObject; begin obj := GetO(path); if obj <> nil then Result := obj.AsDouble else Result := 0.0; end; function TSuperObject.GetC(const path: SOString): Currency; var obj: ISuperObject; begin obj := GetO(path); if obj <> nil then Result := obj.AsCurrency else Result := 0.0; end; function TSuperObject.GetI(const path: SOString): SuperInt; var obj: ISuperObject; begin obj := GetO(path); if obj <> nil then Result := obj.AsInteger else Result := 0; end; function TSuperObject.GetDataPtr: Pointer; begin Result := FDataPtr; end; function TSuperObject.GetDataType: TSuperType; begin Result := FDataType end; function TSuperObject.GetS(const path: SOString): SOString; var obj: ISuperObject; begin obj := GetO(path); if obj <> nil then Result := obj.AsString else Result := ''; end; function TSuperObject.SaveTo(const FileName: string; indent, escape: boolean): integer; var stream: TFileStream; begin stream := TFileStream.Create(FileName, fmCreate); try Result := SaveTo(stream, indent, escape); finally stream.Free; end; end; function TSuperObject.Validate(const rules: SOString; const defs: SOString = ''; callback: TSuperOnValidateError = nil; sender: Pointer = nil): boolean; begin Result := Validate(TSuperObject.ParseString(PSOChar(rules), False), TSuperObject.ParseString(PSOChar(defs), False), callback, sender); end; function TSuperObject.Validate(const rules: ISuperObject; const defs: ISuperObject = nil; callback: TSuperOnValidateError = nil; sender: Pointer = nil): boolean; type TDataType = (dtUnknown, dtStr, dtInt, dtFloat, dtNumber, dtText, dtBool, dtMap, dtSeq, dtScalar, dtAny); var datatypes: ISuperObject; names: ISuperObject; function FindInheritedProperty(const prop: PSOChar; p: ISuperObject): ISuperObject; var o: ISuperObject; e: TSuperAvlEntry; begin o := p[prop]; if o <> nil then result := o else begin o := p['inherit']; if (o <> nil) and ObjectIsType(o, stString) then begin e := names.AsObject.Search(o.AsString); if (e <> nil) then Result := FindInheritedProperty(prop, e.Value) else Result := nil; end else Result := nil; end; end; function FindDataType(o: ISuperObject): TDataType; var e: TSuperAvlEntry; obj: ISuperObject; begin obj := FindInheritedProperty('type', o); if obj <> nil then begin e := datatypes.AsObject.Search(obj.AsString); if e <> nil then Result := TDataType(e.Value.AsInteger) else Result := dtUnknown; end else Result := dtUnknown; end; procedure GetNames(o: ISuperObject); var obj: ISuperObject; f: TSuperObjectIter; begin obj := o['name']; if ObjectIsType(obj, stString) then names[obj.AsString] := o; case FindDataType(o) of dtMap: begin obj := o['mapping']; if ObjectIsType(obj, stObject) then begin if ObjectFindFirst(obj, f) then repeat if ObjectIsType(f.val, stObject) then GetNames(f.val); until not ObjectFindNext(f); ObjectFindClose(f); end; end; dtSeq: begin obj := o['sequence']; if ObjectIsType(obj, stObject) then GetNames(obj); end; end; end; function FindInheritedField(const prop: SOString; p: ISuperObject): ISuperObject; var o: ISuperObject; e: TSuperAvlEntry; begin o := p['mapping']; if ObjectIsType(o, stObject) then begin o := o.AsObject.GetO(prop); if o <> nil then begin Result := o; Exit; end; end; o := p['inherit']; if ObjectIsType(o, stString) then begin e := names.AsObject.Search(o.AsString); if (e <> nil) then Result := FindInheritedField(prop, e.Value) else Result := nil; end else Result := nil; end; function InheritedFieldExist(const obj: ISuperObject; p: ISuperObject; const name: SOString = ''): boolean; var o: ISuperObject; e: TSuperAvlEntry; j: TSuperAvlIterator; begin Result := true; o := p['mapping']; if ObjectIsType(o, stObject) then begin j := TSuperAvlIterator.Create(o.AsObject); try j.First; e := j.GetIter; while e <> nil do begin if obj.AsObject.Search(e.Name) = nil then begin Result := False; if assigned(callback) then callback(sender, veFieldNotFound, name + '.' + e.Name); end; j.Next; e := j.GetIter; end; finally j.Free; end; end; o := p['inherit']; if ObjectIsType(o, stString) then begin e := names.AsObject.Search(o.AsString); if (e <> nil) then Result := InheritedFieldExist(obj, e.Value, name) and Result; end; end; function getInheritedBool(f: PSOChar; p: ISuperObject; default: boolean = false): boolean; var o: ISuperObject; begin o := FindInheritedProperty(f, p); case ObjectGetType(o) of stBoolean: Result := o.AsBoolean; stNull: Result := Default; else Result := default; if assigned(callback) then callback(sender, veRuleMalformated, f); end; end; procedure GetInheritedFieldList(list: ISuperObject; p: ISuperObject); var o: ISuperObject; e: TSuperAvlEntry; i: TSuperAvlIterator; begin Result := true; o := p['mapping']; if ObjectIsType(o, stObject) then begin i := TSuperAvlIterator.Create(o.AsObject); try i.First; e := i.GetIter; while e <> nil do begin if list.AsObject.Search(e.Name) = nil then list[e.Name] := e.Value; i.Next; e := i.GetIter; end; finally i.Free; end; end; o := p['inherit']; if ObjectIsType(o, stString) then begin e := names.AsObject.Search(o.AsString); if (e <> nil) then GetInheritedFieldList(list, e.Value); end; end; function CheckEnum(o: ISuperObject; p: ISuperObject; name: SOString = ''): boolean; var enum: ISuperObject; i: integer; begin Result := false; enum := FindInheritedProperty('enum', p); case ObjectGetType(enum) of stArray: for i := 0 to enum.AsArray.Length - 1 do if (o.AsString = enum.AsArray[i].AsString) then begin Result := true; exit; end; stNull: Result := true; else Result := false; if assigned(callback) then callback(sender, veRuleMalformated, ''); Exit; end; if (not Result) and assigned(callback) then callback(sender, veValueNotInEnum, name); end; function CheckLength(len: integer; p: ISuperObject; const objpath: SOString): boolean; var length, o: ISuperObject; begin result := true; length := FindInheritedProperty('length', p); case ObjectGetType(length) of stObject: begin o := length.AsObject.GetO('min'); if (o <> nil) and (o.AsInteger > len) then begin Result := false; if assigned(callback) then callback(sender, veInvalidLength, objpath); end; o := length.AsObject.GetO('max'); if (o <> nil) and (o.AsInteger < len) then begin Result := false; if assigned(callback) then callback(sender, veInvalidLength, objpath); end; o := length.AsObject.GetO('minex'); if (o <> nil) and (o.AsInteger >= len) then begin Result := false; if assigned(callback) then callback(sender, veInvalidLength, objpath); end; o := length.AsObject.GetO('maxex'); if (o <> nil) and (o.AsInteger <= len) then begin Result := false; if assigned(callback) then callback(sender, veInvalidLength, objpath); end; end; stNull: ; else Result := false; if assigned(callback) then callback(sender, veRuleMalformated, ''); end; end; function CheckRange(obj: ISuperObject; p: ISuperObject; const objpath: SOString): boolean; var length, o: ISuperObject; begin result := true; length := FindInheritedProperty('range', p); case ObjectGetType(length) of stObject: begin o := length.AsObject.GetO('min'); if (o <> nil) and (o.Compare(obj) = cpGreat) then begin Result := false; if assigned(callback) then callback(sender, veInvalidRange, objpath); end; o := length.AsObject.GetO('max'); if (o <> nil) and (o.Compare(obj) = cpLess) then begin Result := false; if assigned(callback) then callback(sender, veInvalidRange, objpath); end; o := length.AsObject.GetO('minex'); if (o <> nil) and (o.Compare(obj) in [cpGreat, cpEqu]) then begin Result := false; if assigned(callback) then callback(sender, veInvalidRange, objpath); end; o := length.AsObject.GetO('maxex'); if (o <> nil) and (o.Compare(obj) in [cpLess, cpEqu]) then begin Result := false; if assigned(callback) then callback(sender, veInvalidRange, objpath); end; end; stNull: ; else Result := false; if assigned(callback) then callback(sender, veRuleMalformated, ''); end; end; function process(o: ISuperObject; p: ISuperObject; objpath: SOString = ''): boolean; var ite: TSuperAvlIterator; ent: TSuperAvlEntry; p2, o2, sequence: ISuperObject; s: SOString; i: integer; uniquelist, fieldlist: ISuperObject; begin Result := true; if (o = nil) then begin if getInheritedBool('required', p) then begin if assigned(callback) then callback(sender, veFieldIsRequired, objpath); result := false; end; end else case FindDataType(p) of dtStr: case ObjectGetType(o) of stString: begin Result := Result and CheckLength(Length(o.AsString), p, objpath); Result := Result and CheckRange(o, p, objpath); end; else if assigned(callback) then callback(sender, veInvalidDataType, objpath); result := false; end; dtBool: case ObjectGetType(o) of stBoolean: begin Result := Result and CheckRange(o, p, objpath); end; else if assigned(callback) then callback(sender, veInvalidDataType, objpath); result := false; end; dtInt: case ObjectGetType(o) of stInt: begin Result := Result and CheckRange(o, p, objpath); end; else if assigned(callback) then callback(sender, veInvalidDataType, objpath); result := false; end; dtFloat: case ObjectGetType(o) of stDouble, stCurrency: begin Result := Result and CheckRange(o, p, objpath); end; else if assigned(callback) then callback(sender, veInvalidDataType, objpath); result := false; end; dtMap: case ObjectGetType(o) of stObject: begin // all objects have and match a rule ? ite := TSuperAvlIterator.Create(o.AsObject); try ite.First; ent := ite.GetIter; while ent <> nil do begin p2 := FindInheritedField(ent.Name, p); if ObjectIsType(p2, stObject) then result := process(ent.Value, p2, objpath + '.' + ent.Name) and result else begin if assigned(callback) then callback(sender, veUnexpectedField, objpath + '.' + ent.Name); result := false; // field have no rule end; ite.Next; ent := ite.GetIter; end; finally ite.Free; end; // all expected field exists ? Result := InheritedFieldExist(o, p, objpath) and Result; end; stNull: {nop}; else result := false; if assigned(callback) then callback(sender, veRuleMalformated, objpath); end; dtSeq: case ObjectGetType(o) of stArray: begin sequence := FindInheritedProperty('sequence', p); if sequence <> nil then case ObjectGetType(sequence) of stObject: begin for i := 0 to o.AsArray.Length - 1 do result := process(o.AsArray.GetO(i), sequence, objpath + '[' + IntToStr(i) + ']') and result; if getInheritedBool('unique', sequence) then begin // type is unique ? uniquelist := TSuperObject.Create(stObject); try for i := 0 to o.AsArray.Length - 1 do begin s := o.AsArray.GetO(i).AsString; if (s <> '') then begin if uniquelist.AsObject.Search(s) = nil then uniquelist[s] := nil else begin Result := False; if Assigned(callback) then callback(sender, veDuplicateEntry, objpath + '[' + IntToStr(i) + ']'); end; end; end; finally uniquelist := nil; end; end; // field is unique ? if (FindDataType(sequence) = dtMap) then begin fieldlist := TSuperObject.Create(stObject); try GetInheritedFieldList(fieldlist, sequence); ite := TSuperAvlIterator.Create(fieldlist.AsObject); try ite.First; ent := ite.GetIter; while ent <> nil do begin if getInheritedBool('unique', ent.Value) then begin uniquelist := TSuperObject.Create(stObject); try for i := 0 to o.AsArray.Length - 1 do begin o2 := o.AsArray.GetO(i); if o2 <> nil then begin s := o2.AsObject.GetO(ent.Name).AsString; if (s <> '') then if uniquelist.AsObject.Search(s) = nil then uniquelist[s] := nil else begin Result := False; if Assigned(callback) then callback(sender, veDuplicateEntry, objpath + '[' + IntToStr(i) + '].' + ent.name); end; end; end; finally uniquelist := nil; end; end; ite.Next; ent := ite.GetIter; end; finally ite.Free; end; finally fieldlist := nil; end; end; end; stNull: {nop}; else result := false; if assigned(callback) then callback(sender, veRuleMalformated, objpath); end; Result := Result and CheckLength(o.AsArray.Length, p, objpath); end; else result := false; if assigned(callback) then callback(sender, veRuleMalformated, objpath); end; dtNumber: case ObjectGetType(o) of stInt, stDouble, stCurrency: begin Result := Result and CheckRange(o, p, objpath); end; else if assigned(callback) then callback(sender, veInvalidDataType, objpath); result := false; end; dtText: case ObjectGetType(o) of stInt, stDouble, stCurrency, stString: begin result := result and CheckLength(Length(o.AsString), p, objpath); Result := Result and CheckRange(o, p, objpath); end; else if assigned(callback) then callback(sender, veInvalidDataType, objpath); result := false; end; dtScalar: case ObjectGetType(o) of stBoolean, stDouble, stCurrency, stInt, stString: begin result := result and CheckLength(Length(o.AsString), p, objpath); Result := Result and CheckRange(o, p, objpath); end; else if assigned(callback) then callback(sender, veInvalidDataType, objpath); result := false; end; dtAny:; else if assigned(callback) then callback(sender, veRuleMalformated, objpath); result := false; end; Result := Result and CheckEnum(o, p, objpath) end; var j: integer; begin Result := False; datatypes := TSuperObject.Create(stObject); names := TSuperObject.Create; try datatypes.I['str'] := ord(dtStr); datatypes.I['int'] := ord(dtInt); datatypes.I['float'] := ord(dtFloat); datatypes.I['number'] := ord(dtNumber); datatypes.I['text'] := ord(dtText); datatypes.I['bool'] := ord(dtBool); datatypes.I['map'] := ord(dtMap); datatypes.I['seq'] := ord(dtSeq); datatypes.I['scalar'] := ord(dtScalar); datatypes.I['any'] := ord(dtAny); if ObjectIsType(defs, stArray) then for j := 0 to defs.AsArray.Length - 1 do if ObjectIsType(defs.AsArray[j], stObject) then GetNames(defs.AsArray[j]) else begin if assigned(callback) then callback(sender, veRuleMalformated, ''); Exit; end; if ObjectIsType(rules, stObject) then GetNames(rules) else begin if assigned(callback) then callback(sender, veRuleMalformated, ''); Exit; end; Result := process(self, rules); finally datatypes := nil; names := nil; end; end; function TSuperObject._AddRef: Integer; stdcall; begin Result := InterlockedIncrement(FRefCount); end; function TSuperObject._Release: Integer; stdcall; begin Result := InterlockedDecrement(FRefCount); if Result = 0 then Destroy; end; function TSuperObject.Compare(const str: SOString): TSuperCompareResult; begin Result := Compare(TSuperObject.ParseString(PSOChar(str), False)); end; function TSuperObject.Compare(const obj: ISuperObject): TSuperCompareResult; function GetIntCompResult(const i: int64): TSuperCompareResult; begin if i < 0 then result := cpLess else if i = 0 then result := cpEqu else Result := cpGreat; end; function GetDblCompResult(const d: double): TSuperCompareResult; begin if d < 0 then result := cpLess else if d = 0 then result := cpEqu else Result := cpGreat; end; begin case DataType of stBoolean: case ObjectGetType(obj) of stBoolean: Result := GetIntCompResult(ord(FO.c_boolean) - ord(obj.AsBoolean)); stDouble: Result := GetDblCompResult(ord(FO.c_boolean) - obj.AsDouble); stCurrency:Result := GetDblCompResult(ord(FO.c_boolean) - obj.AsCurrency); stInt: Result := GetIntCompResult(ord(FO.c_boolean) - obj.AsInteger); stString: Result := GetIntCompResult(StrComp(PSOChar(AsString), PSOChar(obj.AsString))); else Result := cpError; end; stDouble: case ObjectGetType(obj) of stBoolean: Result := GetDblCompResult(FO.c_double - ord(obj.AsBoolean)); stDouble: Result := GetDblCompResult(FO.c_double - obj.AsDouble); stCurrency:Result := GetDblCompResult(FO.c_double - obj.AsCurrency); stInt: Result := GetDblCompResult(FO.c_double - obj.AsInteger); stString: Result := GetIntCompResult(StrComp(PSOChar(AsString), PSOChar(obj.AsString))); else Result := cpError; end; stCurrency: case ObjectGetType(obj) of stBoolean: Result := GetDblCompResult(FO.c_currency - ord(obj.AsBoolean)); stDouble: Result := GetDblCompResult(FO.c_currency - obj.AsDouble); stCurrency:Result := GetDblCompResult(FO.c_currency - obj.AsCurrency); stInt: Result := GetDblCompResult(FO.c_currency - obj.AsInteger); stString: Result := GetIntCompResult(StrComp(PSOChar(AsString), PSOChar(obj.AsString))); else Result := cpError; end; stInt: case ObjectGetType(obj) of stBoolean: Result := GetIntCompResult(FO.c_int - ord(obj.AsBoolean)); stDouble: Result := GetDblCompResult(FO.c_int - obj.AsDouble); stCurrency:Result := GetDblCompResult(FO.c_int - obj.AsCurrency); stInt: Result := GetIntCompResult(FO.c_int - obj.AsInteger); stString: Result := GetIntCompResult(StrComp(PSOChar(AsString), PSOChar(obj.AsString))); else Result := cpError; end; stString: case ObjectGetType(obj) of stBoolean, stDouble, stCurrency, stInt, stString: Result := GetIntCompResult(StrComp(PSOChar(AsString), PSOChar(obj.AsString))); else Result := cpError; end; else Result := cpError; end; end; {$IFDEF SUPER_METHOD} function TSuperObject.AsMethod: TSuperMethod; begin if FDataType = stMethod then Result := FO.c_method else Result := nil; end; {$ENDIF} {$IFDEF SUPER_METHOD} constructor TSuperObject.Create(m: TSuperMethod); begin Create(stMethod); FO.c_method := m; end; {$ENDIF} {$IFDEF SUPER_METHOD} function TSuperObject.GetM(const path: SOString): TSuperMethod; var v: ISuperObject; begin v := ParseString(PSOChar(path), False, True, Self); if (v <> nil) and (ObjectGetType(v) = stMethod) then Result := v.AsMethod else Result := nil; end; {$ENDIF} {$IFDEF SUPER_METHOD} procedure TSuperObject.PutM(const path: SOString; Value: TSuperMethod); begin ParseString(PSOChar(path), False, True, Self, [foCreatePath, foPutValue], TSuperObject.Create(Value)); end; {$ENDIF} {$IFDEF SUPER_METHOD} function TSuperObject.call(const path: SOString; const param: ISuperObject): ISuperObject; begin Result := ParseString(PSOChar(path), False, True, Self, [foCallMethod], param); end; {$ENDIF} {$IFDEF SUPER_METHOD} function TSuperObject.call(const path, param: SOString): ISuperObject; begin Result := ParseString(PSOChar(path), False, True, Self, [foCallMethod], TSuperObject.ParseString(PSOChar(param), False)); end; {$ENDIF} function TSuperObject.GetProcessing: boolean; begin Result := FProcessing; end; procedure TSuperObject.SetDataPtr(const Value: Pointer); begin FDataPtr := Value; end; procedure TSuperObject.SetProcessing(value: boolean); begin FProcessing := value; end; { TSuperArray } function TSuperArray.Add(const Data: ISuperObject): Integer; begin Result := FLength; PutO(Result, data); end; function TSuperArray.Delete(index: Integer): ISuperObject; begin if (Index >= 0) and (Index < FLength) then begin Result := FArray^[index]; FArray^[index] := nil; Dec(FLength); if Index < FLength then begin Move(FArray^[index + 1], FArray^[index], (FLength - index) * SizeOf(Pointer)); Pointer(FArray^[FLength]) := nil; end; end; end; procedure TSuperArray.Insert(index: Integer; const value: ISuperObject); begin if (Index >= 0) then if (index < FLength) then begin if FLength = FSize then Expand(index); if Index < FLength then Move(FArray^[index], FArray^[index + 1], (FLength - index) * SizeOf(Pointer)); Pointer(FArray^[index]) := nil; FArray^[index] := value; Inc(FLength); end else PutO(index, value); end; procedure TSuperArray.Clear(all: boolean); var j: Integer; begin for j := 0 to FLength - 1 do if FArray^[j] <> nil then begin if all then FArray^[j].Clear(all); FArray^[j] := nil; end; FLength := 0; end; procedure TSuperArray.Pack(all: boolean); var PackedCount, StartIndex, EndIndex, j: Integer; begin if FLength > 0 then begin PackedCount := 0; StartIndex := 0; repeat while (StartIndex < FLength) and (FArray^[StartIndex] = nil) do Inc(StartIndex); if StartIndex < FLength then begin EndIndex := StartIndex; while (EndIndex < FLength) and (FArray^[EndIndex] <> nil) do Inc(EndIndex); Dec(EndIndex); if StartIndex > PackedCount then Move(FArray^[StartIndex], FArray^[PackedCount], (EndIndex - StartIndex + 1) * SizeOf(Pointer)); Inc(PackedCount, EndIndex - StartIndex + 1); StartIndex := EndIndex + 1; end; until StartIndex >= FLength; FillChar(FArray^[PackedCount], (FLength - PackedCount) * sizeof(Pointer), 0); FLength := PackedCount; if all then for j := 0 to FLength - 1 do FArray^[j].Pack(all); end; end; constructor TSuperArray.Create; begin inherited Create; FSize := SUPER_ARRAY_LIST_DEFAULT_SIZE; FLength := 0; GetMem(FArray, sizeof(Pointer) * FSize); FillChar(FArray^, sizeof(Pointer) * FSize, 0); end; destructor TSuperArray.Destroy; begin Clear; FreeMem(FArray); inherited; end; procedure TSuperArray.Expand(max: Integer); var new_size: Integer; begin if (max < FSize) then Exit; if max < (FSize shl 1) then new_size := (FSize shl 1) else new_size := max + 1; ReallocMem(FArray, new_size * sizeof(Pointer)); FillChar(FArray^[FSize], (new_size - FSize) * sizeof(Pointer), 0); FSize := new_size; end; function TSuperArray.GetO(const index: Integer): ISuperObject; begin if(index >= FLength) then Result := nil else Result := FArray^[index]; end; function TSuperArray.GetB(const index: integer): Boolean; var obj: ISuperObject; begin obj := GetO(index); if obj <> nil then Result := obj.AsBoolean else Result := false; end; function TSuperArray.GetD(const index: integer): Double; var obj: ISuperObject; begin obj := GetO(index); if obj <> nil then Result := obj.AsDouble else Result := 0.0; end; function TSuperArray.GetI(const index: integer): SuperInt; var obj: ISuperObject; begin obj := GetO(index); if obj <> nil then Result := obj.AsInteger else Result := 0; end; function TSuperArray.GetS(const index: integer): SOString; var obj: ISuperObject; begin obj := GetO(index); if obj <> nil then Result := obj.AsString else Result := ''; end; procedure TSuperArray.PutO(const index: Integer; const Value: ISuperObject); begin Expand(index); FArray^[index] := value; if(FLength <= index) then FLength := index + 1; end; function TSuperArray.GetN(const index: integer): ISuperObject; begin Result := GetO(index); if Result = nil then Result := TSuperObject.Create(stNull); end; procedure TSuperArray.PutN(const index: integer; const Value: ISuperObject); begin if Value <> nil then PutO(index, Value) else PutO(index, TSuperObject.Create(stNull)); end; procedure TSuperArray.PutB(const index: integer; Value: Boolean); begin PutO(index, TSuperObject.Create(Value)); end; procedure TSuperArray.PutD(const index: integer; Value: Double); begin PutO(index, TSuperObject.Create(Value)); end; function TSuperArray.GetC(const index: integer): Currency; var obj: ISuperObject; begin obj := GetO(index); if obj <> nil then Result := obj.AsCurrency else Result := 0.0; end; procedure TSuperArray.PutC(const index: integer; Value: Currency); begin PutO(index, TSuperObject.CreateCurrency(Value)); end; procedure TSuperArray.PutI(const index: integer; Value: SuperInt); begin PutO(index, TSuperObject.Create(Value)); end; procedure TSuperArray.PutS(const index: integer; const Value: SOString); begin PutO(index, TSuperObject.Create(Value)); end; {$IFDEF SUPER_METHOD} function TSuperArray.GetM(const index: integer): TSuperMethod; var v: ISuperObject; begin v := GetO(index); if (ObjectGetType(v) = stMethod) then Result := v.AsMethod else Result := nil; end; {$ENDIF} {$IFDEF SUPER_METHOD} procedure TSuperArray.PutM(const index: integer; Value: TSuperMethod); begin PutO(index, TSuperObject.Create(Value)); end; {$ENDIF} { TSuperWriterString } function TSuperWriterString.Append(buf: PSOChar; Size: Integer): Integer; function max(a, b: Integer): integer; begin if a > b then Result := a else Result := b end; begin Result := size; if Size > 0 then begin if (FSize - FBPos <= size) then begin FSize := max(FSize * 2, FBPos + size + 8); ReallocMem(FBuf, FSize * SizeOf(SOChar)); end; // fast move case size of 1: FBuf[FBPos] := buf^; 2: PInteger(@FBuf[FBPos])^ := PInteger(buf)^; 4: PInt64(@FBuf[FBPos])^ := PInt64(buf)^; else move(buf^, FBuf[FBPos], size * SizeOf(SOChar)); end; inc(FBPos, size); FBuf[FBPos] := #0; end; end; function TSuperWriterString.Append(buf: PSOChar): Integer; begin Result := Append(buf, strlen(buf)); end; constructor TSuperWriterString.Create; begin inherited; FSize := 32; FBPos := 0; GetMem(FBuf, FSize * SizeOf(SOChar)); end; destructor TSuperWriterString.Destroy; begin inherited; if FBuf <> nil then FreeMem(FBuf) end; function TSuperWriterString.GetString: SOString; begin SetString(Result, FBuf, FBPos); end; procedure TSuperWriterString.Reset; begin FBuf[0] := #0; FBPos := 0; end; procedure TSuperWriterString.TrimRight; begin while (FBPos > 0) and (FBuf[FBPos-1] < #256) and (AnsiChar(FBuf[FBPos-1]) in [#32, #13, #10]) do begin dec(FBPos); FBuf[FBPos] := #0; end; end; { TSuperWriterStream } function TSuperWriterStream.Append(buf: PSOChar): Integer; begin Result := Append(buf, StrLen(buf)); end; constructor TSuperWriterStream.Create(AStream: TStream); begin inherited Create; FStream := AStream; end; procedure TSuperWriterStream.Reset; begin FStream.Size := 0; end; { TSuperWriterStream } function TSuperAnsiWriterStream.Append(buf: PSOChar; Size: Integer): Integer; var Buffer: array[0..1023] of AnsiChar; pBuffer: PAnsiChar; i: Integer; begin if Size = 1 then Result := FStream.Write(buf^, Size) else begin if Size > SizeOf(Buffer) then GetMem(pBuffer, Size) else pBuffer := @Buffer; try for i := 0 to Size - 1 do pBuffer[i] := AnsiChar(buf[i]); Result := FStream.Write(pBuffer^, Size); finally if pBuffer <> @Buffer then FreeMem(pBuffer); end; end; end; { TSuperUnicodeWriterStream } function TSuperUnicodeWriterStream.Append(buf: PSOChar; Size: Integer): Integer; begin Result := FStream.Write(buf^, Size * 2); end; { TSuperWriterFake } function TSuperWriterFake.Append(buf: PSOChar; Size: Integer): Integer; begin inc(FSize, Size); Result := FSize; end; function TSuperWriterFake.Append(buf: PSOChar): Integer; begin inc(FSize, Strlen(buf)); Result := FSize; end; constructor TSuperWriterFake.Create; begin inherited Create; FSize := 0; end; procedure TSuperWriterFake.Reset; begin FSize := 0; end; { TSuperWriterSock } function TSuperWriterSock.Append(buf: PSOChar; Size: Integer): Integer; var Buffer: array[0..1023] of AnsiChar; pBuffer: PAnsiChar; i: Integer; begin if Size = 1 then {$IFDEF FPC} Result := fpsend(FSocket, buf, size, 0) else {$ELSE} Result := send(FSocket, buf^, size, 0) else {$ENDIF} begin if Size > SizeOf(Buffer) then GetMem(pBuffer, Size) else pBuffer := @Buffer; try for i := 0 to Size - 1 do pBuffer[i] := AnsiChar(buf[i]); {$IFDEF FPC} Result := fpsend(FSocket, pBuffer, size, 0); {$ELSE} Result := send(FSocket, pBuffer^, size, 0); {$ENDIF} finally if pBuffer <> @Buffer then FreeMem(pBuffer); end; end; inc(FSize, Result); end; function TSuperWriterSock.Append(buf: PSOChar): Integer; begin Result := Append(buf, StrLen(buf)); end; constructor TSuperWriterSock.Create(ASocket: Integer); begin inherited Create; FSocket := ASocket; FSize := 0; end; procedure TSuperWriterSock.Reset; begin FSize := 0; end; { TSuperTokenizer } constructor TSuperTokenizer.Create; begin pb := TSuperWriterString.Create; line := 1; col := 0; Reset; end; destructor TSuperTokenizer.Destroy; begin Reset; pb.Free; inherited; end; procedure TSuperTokenizer.Reset; var i: integer; begin for i := depth downto 0 do ResetLevel(i); depth := 0; err := teSuccess; end; procedure TSuperTokenizer.ResetLevel(adepth: integer); begin stack[adepth].state := tsEatws; stack[adepth].saved_state := tsStart; stack[adepth].current := nil; stack[adepth].field_name := ''; stack[adepth].obj := nil; stack[adepth].parent := nil; stack[adepth].gparent := nil; end; { TSuperAvlTree } constructor TSuperAvlTree.Create; begin FRoot := nil; FCount := 0; end; destructor TSuperAvlTree.Destroy; begin Clear; inherited; end; function TSuperAvlTree.IsEmpty: boolean; begin result := FRoot = nil; end; function TSuperAvlTree.balance(bal: TSuperAvlEntry): TSuperAvlEntry; var deep, old: TSuperAvlEntry; bf: integer; begin if (bal.FBf > 0) then begin deep := bal.FGt; if (deep.FBf < 0) then begin old := bal; bal := deep.FLt; old.FGt := bal.FLt; deep.FLt := bal.FGt; bal.FLt := old; bal.FGt := deep; bf := bal.FBf; if (bf <> 0) then begin if (bf > 0) then begin old.FBf := -1; deep.FBf := 0; end else begin deep.FBf := 1; old.FBf := 0; end; bal.FBf := 0; end else begin old.FBf := 0; deep.FBf := 0; end; end else begin bal.FGt := deep.FLt; deep.FLt := bal; if (deep.FBf = 0) then begin deep.FBf := -1; bal.FBf := 1; end else begin deep.FBf := 0; bal.FBf := 0; end; bal := deep; end; end else begin (* "Less than" subtree is deeper. *) deep := bal.FLt; if (deep.FBf > 0) then begin old := bal; bal := deep.FGt; old.FLt := bal.FGt; deep.FGt := bal.FLt; bal.FGt := old; bal.FLt := deep; bf := bal.FBf; if (bf <> 0) then begin if (bf < 0) then begin old.FBf := 1; deep.FBf := 0; end else begin deep.FBf := -1; old.FBf := 0; end; bal.FBf := 0; end else begin old.FBf := 0; deep.FBf := 0; end; end else begin bal.FLt := deep.FGt; deep.FGt := bal; if (deep.FBf = 0) then begin deep.FBf := 1; bal.FBf := -1; end else begin deep.FBf := 0; bal.FBf := 0; end; bal := deep; end; end; Result := bal; end; function TSuperAvlTree.Insert(h: TSuperAvlEntry): TSuperAvlEntry; var unbal, parentunbal, hh, parent: TSuperAvlEntry; depth, unbaldepth: longint; cmp: integer; unbalbf: integer; branch: TSuperAvlBitArray; p: Pointer; begin inc(FCount); h.FLt := nil; h.FGt := nil; h.FBf := 0; branch := []; if (FRoot = nil) then FRoot := h else begin unbal := nil; parentunbal := nil; depth := 0; unbaldepth := 0; hh := FRoot; parent := nil; repeat if (hh.FBf <> 0) then begin unbal := hh; parentunbal := parent; unbaldepth := depth; end; if hh.FHash <> h.FHash then begin if hh.FHash < h.FHash then cmp := -1 else if hh.FHash > h.FHash then cmp := 1 else cmp := 0; end else cmp := CompareNodeNode(h, hh); if (cmp = 0) then begin Result := hh; //exchange data p := hh.Ptr; hh.FPtr := h.Ptr; h.FPtr := p; doDeleteEntry(h, false); dec(FCount); exit; end; parent := hh; if (cmp > 0) then begin hh := hh.FGt; include(branch, depth); end else begin hh := hh.FLt; exclude(branch, depth); end; inc(depth); until (hh = nil); if (cmp < 0) then parent.FLt := h else parent.FGt := h; depth := unbaldepth; if (unbal = nil) then hh := FRoot else begin if depth in branch then cmp := 1 else cmp := -1; inc(depth); unbalbf := unbal.FBf; if (cmp < 0) then dec(unbalbf) else inc(unbalbf); if cmp < 0 then hh := unbal.FLt else hh := unbal.FGt; if ((unbalbf <> -2) and (unbalbf <> 2)) then begin unbal.FBf := unbalbf; unbal := nil; end; end; if (hh <> nil) then while (h <> hh) do begin if depth in branch then cmp := 1 else cmp := -1; inc(depth); if (cmp < 0) then begin hh.FBf := -1; hh := hh.FLt; end else (* cmp > 0 *) begin hh.FBf := 1; hh := hh.FGt; end; end; if (unbal <> nil) then begin unbal := balance(unbal); if (parentunbal = nil) then FRoot := unbal else begin depth := unbaldepth - 1; if depth in branch then cmp := 1 else cmp := -1; if (cmp < 0) then parentunbal.FLt := unbal else parentunbal.FGt := unbal; end; end; end; result := h; end; function TSuperAvlTree.Search(const k: SOString; st: TSuperAvlSearchTypes): TSuperAvlEntry; var cmp, target_cmp: integer; match_h, h: TSuperAvlEntry; ha: Cardinal; begin ha := TSuperAvlEntry.Hash(k); match_h := nil; h := FRoot; if (stLess in st) then target_cmp := 1 else if (stGreater in st) then target_cmp := -1 else target_cmp := 0; while (h <> nil) do begin if h.FHash < ha then cmp := -1 else if h.FHash > ha then cmp := 1 else cmp := 0; if cmp = 0 then cmp := CompareKeyNode(PSOChar(k), h); if (cmp = 0) then begin if (stEqual in st) then begin match_h := h; break; end; cmp := -target_cmp; end else if (target_cmp <> 0) then if ((cmp xor target_cmp) and SUPER_AVL_MASK_HIGH_BIT) = 0 then match_h := h; if cmp < 0 then h := h.FLt else h := h.FGt; end; result := match_h; end; function TSuperAvlTree.Delete(const k: SOString): ISuperObject; var depth, rm_depth: longint; branch: TSuperAvlBitArray; h, parent, child, path, rm, parent_rm: TSuperAvlEntry; cmp, cmp_shortened_sub_with_path, reduced_depth, bf: integer; ha: Cardinal; begin ha := TSuperAvlEntry.Hash(k); cmp_shortened_sub_with_path := 0; branch := []; depth := 0; h := FRoot; parent := nil; while true do begin if (h = nil) then exit; if h.FHash < ha then cmp := -1 else if h.FHash > ha then cmp := 1 else cmp := 0; if cmp = 0 then cmp := CompareKeyNode(k, h); if (cmp = 0) then break; parent := h; if (cmp > 0) then begin h := h.FGt; include(branch, depth) end else begin h := h.FLt; exclude(branch, depth) end; inc(depth); cmp_shortened_sub_with_path := cmp; end; rm := h; parent_rm := parent; rm_depth := depth; if (h.FBf < 0) then begin child := h.FLt; exclude(branch, depth); cmp := -1; end else begin child := h.FGt; include(branch, depth); cmp := 1; end; inc(depth); if (child <> nil) then begin cmp := -cmp; repeat parent := h; h := child; if (cmp < 0) then begin child := h.FLt; exclude(branch, depth); end else begin child := h.FGt; include(branch, depth); end; inc(depth); until (child = nil); if (parent = rm) then cmp_shortened_sub_with_path := -cmp else cmp_shortened_sub_with_path := cmp; if cmp > 0 then child := h.FLt else child := h.FGt; end; if (parent = nil) then FRoot := child else if (cmp_shortened_sub_with_path < 0) then parent.FLt := child else parent.FGt := child; if parent = rm then path := h else path := parent; if (h <> rm) then begin h.FLt := rm.FLt; h.FGt := rm.FGt; h.FBf := rm.FBf; if (parent_rm = nil) then FRoot := h else begin depth := rm_depth - 1; if (depth in branch) then parent_rm.FGt := h else parent_rm.FLt := h; end; end; if (path <> nil) then begin h := FRoot; parent := nil; depth := 0; while (h <> path) do begin if (depth in branch) then begin child := h.FGt; h.FGt := parent; end else begin child := h.FLt; h.FLt := parent; end; inc(depth); parent := h; h := child; end; reduced_depth := 1; cmp := cmp_shortened_sub_with_path; while true do begin if (reduced_depth <> 0) then begin bf := h.FBf; if (cmp < 0) then inc(bf) else dec(bf); if ((bf = -2) or (bf = 2)) then begin h := balance(h); bf := h.FBf; end else h.FBf := bf; reduced_depth := integer(bf = 0); end; if (parent = nil) then break; child := h; h := parent; dec(depth); if depth in branch then cmp := 1 else cmp := -1; if (cmp < 0) then begin parent := h.FLt; h.FLt := child; end else begin parent := h.FGt; h.FGt := child; end; end; FRoot := h; end; if rm <> nil then begin Result := rm.GetValue; doDeleteEntry(rm, false); dec(FCount); end; end; procedure TSuperAvlTree.Pack(all: boolean); var node1, node2: TSuperAvlEntry; list: TList; i: Integer; begin node1 := FRoot; list := TList.Create; while node1 <> nil do begin if (node1.FLt = nil) then begin node2 := node1.FGt; if (node1.FPtr = nil) then list.Add(node1) else if all then node1.Value.Pack(all); end else begin node2 := node1.FLt; node1.FLt := node2.FGt; node2.FGt := node1; end; node1 := node2; end; for i := 0 to list.Count - 1 do Delete(TSuperAvlEntry(list[i]).FName); list.Free; end; procedure TSuperAvlTree.Clear(all: boolean); var node1, node2: TSuperAvlEntry; begin node1 := FRoot; while node1 <> nil do begin if (node1.FLt = nil) then begin node2 := node1.FGt; doDeleteEntry(node1, all); end else begin node2 := node1.FLt; node1.FLt := node2.FGt; node2.FGt := node1; end; node1 := node2; end; FRoot := nil; FCount := 0; end; function TSuperAvlTree.CompareKeyNode(const k: SOString; h: TSuperAvlEntry): integer; begin Result := StrComp(PSOChar(k), PSOChar(h.FName)); end; function TSuperAvlTree.CompareNodeNode(node1, node2: TSuperAvlEntry): integer; begin Result := StrComp(PSOChar(node1.FName), PSOChar(node2.FName)); end; { TSuperAvlIterator } (* Initialize depth to invalid value, to indicate iterator is ** invalid. (Depth is zero-base.) It's not necessary to initialize ** iterators prior to passing them to the "start" function. *) constructor TSuperAvlIterator.Create(tree: TSuperAvlTree); begin FDepth := not 0; FTree := tree; end; procedure TSuperAvlIterator.Search(const k: SOString; st: TSuperAvlSearchTypes); var h: TSuperAvlEntry; d: longint; cmp, target_cmp: integer; ha: Cardinal; begin ha := TSuperAvlEntry.Hash(k); h := FTree.FRoot; d := 0; FDepth := not 0; if (h = nil) then exit; if (stLess in st) then target_cmp := 1 else if (stGreater in st) then target_cmp := -1 else target_cmp := 0; while true do begin if h.FHash < ha then cmp := -1 else if h.FHash > ha then cmp := 1 else cmp := 0; if cmp = 0 then cmp := FTree.CompareKeyNode(k, h); if (cmp = 0) then begin if (stEqual in st) then begin FDepth := d; break; end; cmp := -target_cmp; end else if (target_cmp <> 0) then if ((cmp xor target_cmp) and SUPER_AVL_MASK_HIGH_BIT) = 0 then FDepth := d; if cmp < 0 then h := h.FLt else h := h.FGt; if (h = nil) then break; if (cmp > 0) then include(FBranch, d) else exclude(FBranch, d); FPath[d] := h; inc(d); end; end; procedure TSuperAvlIterator.First; var h: TSuperAvlEntry; begin h := FTree.FRoot; FDepth := not 0; FBranch := []; while (h <> nil) do begin if (FDepth <> not 0) then FPath[FDepth] := h; inc(FDepth); h := h.FLt; end; end; procedure TSuperAvlIterator.Last; var h: TSuperAvlEntry; begin h := FTree.FRoot; FDepth := not 0; FBranch := [0..SUPER_AVL_MAX_DEPTH - 1]; while (h <> nil) do begin if (FDepth <> not 0) then FPath[FDepth] := h; inc(FDepth); h := h.FGt; end; end; function TSuperAvlIterator.MoveNext: boolean; begin if FDepth = not 0 then First else Next; Result := GetIter <> nil; end; function TSuperAvlIterator.GetIter: TSuperAvlEntry; begin if (FDepth = not 0) then begin result := nil; exit; end; if FDepth = 0 then Result := FTree.FRoot else Result := FPath[FDepth - 1]; end; procedure TSuperAvlIterator.Next; var h: TSuperAvlEntry; begin if (FDepth <> not 0) then begin if FDepth = 0 then h := FTree.FRoot.FGt else h := FPath[FDepth - 1].FGt; if (h = nil) then repeat if (FDepth = 0) then begin FDepth := not 0; break; end; dec(FDepth); until (not (FDepth in FBranch)) else begin include(FBranch, FDepth); FPath[FDepth] := h; inc(FDepth); while true do begin h := h.FLt; if (h = nil) then break; exclude(FBranch, FDepth); FPath[FDepth] := h; inc(FDepth); end; end; end; end; procedure TSuperAvlIterator.Prior; var h: TSuperAvlEntry; begin if (FDepth <> not 0) then begin if FDepth = 0 then h := FTree.FRoot.FLt else h := FPath[FDepth - 1].FLt; if (h = nil) then repeat if (FDepth = 0) then begin FDepth := not 0; break; end; dec(FDepth); until (FDepth in FBranch) else begin exclude(FBranch, FDepth); FPath[FDepth] := h; inc(FDepth); while true do begin h := h.FGt; if (h = nil) then break; include(FBranch, FDepth); FPath[FDepth] := h; inc(FDepth); end; end; end; end; procedure TSuperAvlTree.doDeleteEntry(Entry: TSuperAvlEntry; all: boolean); begin Entry.Free; end; function TSuperAvlTree.GetEnumerator: TSuperAvlIterator; begin Result := TSuperAvlIterator.Create(Self); end; { TSuperAvlEntry } constructor TSuperAvlEntry.Create(const AName: SOString; Obj: Pointer); begin FName := AName; FPtr := Obj; FHash := Hash(FName); end; function TSuperAvlEntry.GetValue: ISuperObject; begin Result := ISuperObject(FPtr) end; class function TSuperAvlEntry.Hash(const k: SOString): Cardinal; var h: cardinal; i: Integer; begin h := 0; {$Q-} for i := 1 to Length(k) do h := h*129 + ord(k[i]) + $9e370001; {$Q+} Result := h; end; procedure TSuperAvlEntry.SetValue(const val: ISuperObject); begin ISuperObject(FPtr) := val; end; { TSuperTableString } function TSuperTableString.GetValues: ISuperObject; var ite: TSuperAvlIterator; obj: TSuperAvlEntry; begin Result := TSuperObject.Create(stArray); ite := TSuperAvlIterator.Create(Self); try ite.First; obj := ite.GetIter; while obj <> nil do begin Result.AsArray.Add(obj.Value); ite.Next; obj := ite.GetIter; end; finally ite.Free; end; end; function TSuperTableString.GetNames: ISuperObject; var ite: TSuperAvlIterator; obj: TSuperAvlEntry; begin Result := TSuperObject.Create(stArray); ite := TSuperAvlIterator.Create(Self); try ite.First; obj := ite.GetIter; while obj <> nil do begin Result.AsArray.Add(TSuperObject.Create(obj.FName)); ite.Next; obj := ite.GetIter; end; finally ite.Free; end; end; procedure TSuperTableString.doDeleteEntry(Entry: TSuperAvlEntry; all: boolean); begin if Entry.Ptr <> nil then begin if all then Entry.Value.Clear(true); Entry.Value := nil; end; inherited; end; function TSuperTableString.GetO(const k: SOString): ISuperObject; var e: TSuperAvlEntry; begin e := Search(k); if e <> nil then Result := e.Value else Result := nil end; procedure TSuperTableString.PutO(const k: SOString; const value: ISuperObject); var entry: TSuperAvlEntry; begin entry := Insert(TSuperAvlEntry.Create(k, Pointer(value))); if entry.FPtr <> nil then ISuperObject(entry.FPtr)._AddRef; end; procedure TSuperTableString.PutS(const k: SOString; const value: SOString); begin PutO(k, TSuperObject.Create(Value)); end; function TSuperTableString.GetS(const k: SOString): SOString; var obj: ISuperObject; begin obj := GetO(k); if obj <> nil then Result := obj.AsString else Result := ''; end; procedure TSuperTableString.PutI(const k: SOString; value: SuperInt); begin PutO(k, TSuperObject.Create(Value)); end; function TSuperTableString.GetI(const k: SOString): SuperInt; var obj: ISuperObject; begin obj := GetO(k); if obj <> nil then Result := obj.AsInteger else Result := 0; end; procedure TSuperTableString.PutD(const k: SOString; value: Double); begin PutO(k, TSuperObject.Create(Value)); end; procedure TSuperTableString.PutC(const k: SOString; value: Currency); begin PutO(k, TSuperObject.CreateCurrency(Value)); end; function TSuperTableString.GetC(const k: SOString): Currency; var obj: ISuperObject; begin obj := GetO(k); if obj <> nil then Result := obj.AsCurrency else Result := 0.0; end; function TSuperTableString.GetD(const k: SOString): Double; var obj: ISuperObject; begin obj := GetO(k); if obj <> nil then Result := obj.AsDouble else Result := 0.0; end; procedure TSuperTableString.PutB(const k: SOString; value: Boolean); begin PutO(k, TSuperObject.Create(Value)); end; function TSuperTableString.GetB(const k: SOString): Boolean; var obj: ISuperObject; begin obj := GetO(k); if obj <> nil then Result := obj.AsBoolean else Result := False; end; {$IFDEF SUPER_METHOD} procedure TSuperTableString.PutM(const k: SOString; value: TSuperMethod); begin PutO(k, TSuperObject.Create(Value)); end; {$ENDIF} {$IFDEF SUPER_METHOD} function TSuperTableString.GetM(const k: SOString): TSuperMethod; var obj: ISuperObject; begin obj := GetO(k); if obj <> nil then Result := obj.AsMethod else Result := nil; end; {$ENDIF} procedure TSuperTableString.PutN(const k: SOString; const value: ISuperObject); begin if value <> nil then PutO(k, TSuperObject.Create(stNull)) else PutO(k, value); end; function TSuperTableString.GetN(const k: SOString): ISuperObject; var obj: ISuperObject; begin obj := GetO(k); if obj <> nil then Result := obj else Result := TSuperObject.Create(stNull); end; {$IFDEF VER210} { TSuperAttribute } constructor TSuperAttribute.Create(const AName: string); begin FName := AName; end; { TSuperRttiContext } constructor TSuperRttiContext.Create; begin Context := TRttiContext.Create; SerialFromJson := TDictionary.Create; SerialToJson := TDictionary.Create; SerialFromJson.Add(TypeInfo(Boolean), serialfromboolean); SerialFromJson.Add(TypeInfo(TDateTime), serialfromdatetime); SerialFromJson.Add(TypeInfo(TGUID), serialfromguid); SerialToJson.Add(TypeInfo(Boolean), serialtoboolean); SerialToJson.Add(TypeInfo(TDateTime), serialtodatetime); SerialToJson.Add(TypeInfo(TGUID), serialtoguid); end; destructor TSuperRttiContext.Destroy; begin SerialFromJson.Free; SerialToJson.Free; Context.Free; end; class function TSuperRttiContext.GetFieldName(r: TRttiField): string; var o: TCustomAttribute; begin for o in r.GetAttributes do if o is SOName then Exit(SOName(o).Name); Result := r.Name; end; class function TSuperRttiContext.GetFieldDefault(r: TRttiField; const obj: ISuperObject): ISuperObject; var o: TCustomAttribute; begin if not ObjectIsType(obj, stNull) then Exit(obj); for o in r.GetAttributes do if o is SODefault then Exit(SO(SODefault(o).Name)); Result := obj; end; function TSuperRttiContext.AsType(const obj: ISuperObject): T; var ret: TValue; begin if FromJson(TypeInfo(T), obj, ret) then Result := ret.AsType else raise exception.Create('Marshalling error'); end; function TSuperRttiContext.AsJson(const obj: T; const index: ISuperObject = nil): ISuperObject; var v: TValue; begin TValue.MakeWithoutCopy(@obj, TypeInfo(T), v); if index <> nil then Result := ToJson(v, index) else Result := ToJson(v, so); end; function TSuperRttiContext.FromJson(TypeInfo: PTypeInfo; const obj: ISuperObject; var Value: TValue): Boolean; procedure FromChar; begin if ObjectIsType(obj, stString) and (Length(obj.AsString) = 1) then begin Value := string(AnsiString(obj.AsString)[1]); Result := True; end else Result := False; end; procedure FromWideChar; begin if ObjectIsType(obj, stString) and (Length(obj.AsString) = 1) then begin Value := obj.AsString[1]; Result := True; end else Result := False; end; procedure FromInt64; var i: Int64; begin case ObjectGetType(obj) of stInt: begin TValue.Make(nil, TypeInfo, Value); TValueData(Value).FAsSInt64 := obj.AsInteger; Result := True; end; stString: begin if TryStrToInt64(obj.AsString, i) then begin TValue.Make(nil, TypeInfo, Value); TValueData(Value).FAsSInt64 := i; Result := True; end else Result := False; end; else Result := False; end; end; procedure FromInt(const obj: ISuperObject); var TypeData: PTypeData; i: Integer; o: ISuperObject; begin case ObjectGetType(obj) of stInt, stBoolean: begin i := obj.AsInteger; TypeData := GetTypeData(TypeInfo); Result := (i >= TypeData.MinValue) and (i <= TypeData.MaxValue); if Result then TValue.Make(@i, TypeInfo, Value); end; stString: begin o := SO(obj.AsString); if not ObjectIsType(o, stString) then FromInt(o) else Result := False; end; else Result := False; end; end; procedure fromSet; begin if ObjectIsType(obj, stInt) then begin TValue.Make(nil, TypeInfo, Value); TValueData(Value).FAsSLong := obj.AsInteger; Result := True; end else Result := False; end; procedure FromFloat(const obj: ISuperObject); var o: ISuperObject; begin case ObjectGetType(obj) of stInt, stDouble, stCurrency: begin TValue.Make(nil, TypeInfo, Value); case GetTypeData(TypeInfo).FloatType of ftSingle: TValueData(Value).FAsSingle := obj.AsDouble; ftDouble: TValueData(Value).FAsDouble := obj.AsDouble; ftExtended: TValueData(Value).FAsExtended := obj.AsDouble; ftComp: TValueData(Value).FAsSInt64 := obj.AsInteger; ftCurr: TValueData(Value).FAsCurr := obj.AsCurrency; end; Result := True; end; stString: begin o := SO(obj.AsString); if not ObjectIsType(o, stString) then FromFloat(o) else Result := False; end else Result := False; end; end; procedure FromString; begin case ObjectGetType(obj) of stObject, stArray: Result := False; stnull: begin Value := ''; Result := True; end; else Value := obj.AsString; Result := True; end; end; procedure FromClass; var f: TRttiField; v: TValue; begin case ObjectGetType(obj) of stObject: begin Result := True; if Value.Kind <> tkClass then Value := GetTypeData(TypeInfo).ClassType.Create; for f in Context.GetType(Value.AsObject.ClassType).GetFields do if f.FieldType <> nil then begin Result := FromJson(f.FieldType.Handle, GetFieldDefault(f, obj.AsObject[GetFieldName(f)]), v); if Result then f.SetValue(Value.AsObject, v) else Exit; end; end; stNull: begin Value := nil; Result := True; end else // error Value := nil; Result := False; end; end; procedure FromRecord; var f: TRttiField; p: Pointer; v: TValue; begin Result := True; TValue.Make(nil, TypeInfo, Value); for f in Context.GetType(TypeInfo).GetFields do begin if ObjectIsType(obj, stObject) and (f.FieldType <> nil) then begin p := IValueData(TValueData(Value).FHeapData).GetReferenceToRawData; Result := FromJson(f.FieldType.Handle, GetFieldDefault(f, obj.AsObject[GetFieldName(f)]), v); if Result then f.SetValue(p, v) else Exit; end else begin Result := False; Exit; end; end; end; procedure FromDynArray; var i: Integer; p: Pointer; pb: PByte; val: TValue; typ: PTypeData; el: PTypeInfo; begin case ObjectGetType(obj) of stArray: begin i := obj.AsArray.Length; p := nil; DynArraySetLength(p, TypeInfo, 1, @i); pb := p; typ := GetTypeData(TypeInfo); if typ.elType <> nil then el := typ.elType^ else el := typ.elType2^; Result := True; for i := 0 to i - 1 do begin Result := FromJson(el, obj.AsArray[i], val); if not Result then Break; val.ExtractRawData(pb); val := TValue.Empty; Inc(pb, typ.elSize); end; if Result then TValue.MakeWithoutCopy(@p, TypeInfo, Value) else DynArrayClear(p, TypeInfo); end; stNull: begin TValue.MakeWithoutCopy(nil, TypeInfo, Value); Result := True; end; else i := 1; p := nil; DynArraySetLength(p, TypeInfo, 1, @i); pb := p; typ := GetTypeData(TypeInfo); if typ.elType <> nil then el := typ.elType^ else el := typ.elType2^; Result := FromJson(el, obj, val); val.ExtractRawData(pb); val := TValue.Empty; if Result then TValue.MakeWithoutCopy(@p, TypeInfo, Value) else DynArrayClear(p, TypeInfo); end; end; procedure FromArray; var ArrayData: PArrayTypeData; idx: Integer; function ProcessDim(dim: Byte; const o: ISuperobject): Boolean; var i: Integer; v: TValue; a: PTypeData; begin if ObjectIsType(o, stArray) and (ArrayData.Dims[dim-1] <> nil) then begin a := @GetTypeData(ArrayData.Dims[dim-1]^).ArrayData; if (a.MaxValue - a.MinValue + 1) <> o.AsArray.Length then begin Result := False; Exit; end; Result := True; if dim = ArrayData.DimCount then for i := a.MinValue to a.MaxValue do begin Result := FromJson(ArrayData.ElType^, o.AsArray[i], v); if not Result then Exit; Value.SetArrayElement(idx, v); inc(idx); end else for i := a.MinValue to a.MaxValue do begin Result := ProcessDim(dim + 1, o.AsArray[i]); if not Result then Exit; end; end else Result := False; end; var i: Integer; v: TValue; begin TValue.Make(nil, TypeInfo, Value); ArrayData := @GetTypeData(TypeInfo).ArrayData; idx := 0; if ArrayData.DimCount = 1 then begin if ObjectIsType(obj, stArray) and (obj.AsArray.Length = ArrayData.ElCount) then begin Result := True; for i := 0 to ArrayData.ElCount - 1 do begin Result := FromJson(ArrayData.ElType^, obj.AsArray[i], v); if not Result then Exit; Value.SetArrayElement(idx, v); v := TValue.Empty; inc(idx); end; end else Result := False; end else Result := ProcessDim(1, obj); end; procedure FromClassRef; var r: TRttiType; begin if ObjectIsType(obj, stString) then begin r := Context.FindType(obj.AsString); if r <> nil then begin Value := TRttiInstanceType(r).MetaclassType; Result := True; end else Result := False; end else Result := False; end; procedure FromUnknown; begin case ObjectGetType(obj) of stBoolean: begin Value := obj.AsBoolean; Result := True; end; stDouble: begin Value := obj.AsDouble; Result := True; end; stCurrency: begin Value := obj.AsCurrency; Result := True; end; stInt: begin Value := obj.AsInteger; Result := True; end; stString: begin Value := obj.AsString; Result := True; end else Value := nil; Result := False; end; end; procedure FromInterface; const soguid: TGuid = '{4B86A9E3-E094-4E5A-954A-69048B7B6327}'; var o: ISuperObject; begin if CompareMem(@GetTypeData(TypeInfo).Guid, @soguid, SizeOf(TGUID)) then begin if obj <> nil then TValue.Make(@obj, TypeInfo, Value) else begin o := TSuperObject.Create(stNull); TValue.Make(@o, TypeInfo, Value); end; Result := True; end else Result := False; end; var Serial: TSerialFromJson; begin if TypeInfo <> nil then begin if not SerialFromJson.TryGetValue(TypeInfo, Serial) then case TypeInfo.Kind of tkChar: FromChar; tkInt64: FromInt64; tkEnumeration, tkInteger: FromInt(obj); tkSet: fromSet; tkFloat: FromFloat(obj); tkString, tkLString, tkUString, tkWString: FromString; tkClass: FromClass; tkMethod: ; tkWChar: FromWideChar; tkRecord: FromRecord; tkPointer: ; tkInterface: FromInterface; tkArray: FromArray; tkDynArray: FromDynArray; tkClassRef: FromClassRef; else FromUnknown end else begin TValue.Make(nil, TypeInfo, Value); Result := Serial(Self, obj, Value); end; end else Result := False; end; function TSuperRttiContext.ToJson(var value: TValue; const index: ISuperObject): ISuperObject; procedure ToInt64; begin Result := TSuperObject.Create(SuperInt(Value.AsInt64)); end; procedure ToChar; begin Result := TSuperObject.Create(string(Value.AsType)); end; procedure ToInteger; begin Result := TSuperObject.Create(TValueData(Value).FAsSLong); end; procedure ToFloat; begin case Value.TypeData.FloatType of ftSingle: Result := TSuperObject.Create(TValueData(Value).FAsSingle); ftDouble: Result := TSuperObject.Create(TValueData(Value).FAsDouble); ftExtended: Result := TSuperObject.Create(TValueData(Value).FAsExtended); ftComp: Result := TSuperObject.Create(TValueData(Value).FAsSInt64); ftCurr: Result := TSuperObject.CreateCurrency(TValueData(Value).FAsCurr); end; end; procedure ToString; begin Result := TSuperObject.Create(string(Value.AsType)); end; procedure ToClass; var o: ISuperObject; f: TRttiField; v: TValue; begin if TValueData(Value).FAsObject <> nil then begin o := index[IntToStr(Integer(Value.AsObject))]; if o = nil then begin Result := TSuperObject.Create(stObject); index[IntToStr(Integer(Value.AsObject))] := Result; for f in Context.GetType(Value.AsObject.ClassType).GetFields do if f.FieldType <> nil then begin v := f.GetValue(Value.AsObject); Result.AsObject[GetFieldName(f)] := ToJson(v, index); end end else Result := o; end else Result := nil; end; procedure ToWChar; begin Result := TSuperObject.Create(string(Value.AsType)); end; procedure ToVariant; begin Result := SO(Value.AsVariant); end; procedure ToRecord; var f: TRttiField; v: TValue; begin Result := TSuperObject.Create(stObject); for f in Context.GetType(Value.TypeInfo).GetFields do begin v := f.GetValue(IValueData(TValueData(Value).FHeapData).GetReferenceToRawData); Result.AsObject[GetFieldName(f)] := ToJson(v, index); end; end; procedure ToArray; var idx: Integer; ArrayData: PArrayTypeData; procedure ProcessDim(dim: Byte; const o: ISuperObject); var dt: PTypeData; i: Integer; o2: ISuperObject; v: TValue; begin if ArrayData.Dims[dim-1] = nil then Exit; dt := GetTypeData(ArrayData.Dims[dim-1]^); if Dim = ArrayData.DimCount then for i := dt.MinValue to dt.MaxValue do begin v := Value.GetArrayElement(idx); o.AsArray.Add(toJSon(v, index)); inc(idx); end else for i := dt.MinValue to dt.MaxValue do begin o2 := TSuperObject.Create(stArray); o.AsArray.Add(o2); ProcessDim(dim + 1, o2); end; end; var i: Integer; v: TValue; begin Result := TSuperObject.Create(stArray); ArrayData := @Value.TypeData.ArrayData; idx := 0; if ArrayData.DimCount = 1 then for i := 0 to ArrayData.ElCount - 1 do begin v := Value.GetArrayElement(i); Result.AsArray.Add(toJSon(v, index)) end else ProcessDim(1, Result); end; procedure ToDynArray; var i: Integer; v: TValue; begin Result := TSuperObject.Create(stArray); for i := 0 to Value.GetArrayLength - 1 do begin v := Value.GetArrayElement(i); Result.AsArray.Add(toJSon(v, index)); end; end; procedure ToClassRef; begin if TValueData(Value).FAsClass <> nil then Result := TSuperObject.Create(string( TValueData(Value).FAsClass.UnitName + '.' + TValueData(Value).FAsClass.ClassName)) else Result := nil; end; procedure ToInterface; begin if TValueData(Value).FHeapData <> nil then TValueData(Value).FHeapData.QueryInterface(ISuperObject, Result) else Result := nil; end; var Serial: TSerialToJson; begin if not SerialToJson.TryGetValue(value.TypeInfo, Serial) then case Value.Kind of tkInt64: ToInt64; tkChar: ToChar; tkSet, tkInteger, tkEnumeration: ToInteger; tkFloat: ToFloat; tkString, tkLString, tkUString, tkWString: ToString; tkClass: ToClass; tkWChar: ToWChar; tkVariant: ToVariant; tkRecord: ToRecord; tkArray: ToArray; tkDynArray: ToDynArray; tkClassRef: ToClassRef; tkInterface: ToInterface; else result := nil; end else Result := Serial(Self, value, index); end; { TSuperObjectHelper } constructor TSuperObjectHelper.FromJson(const obj: ISuperObject; ctx: TSuperRttiContext = nil); var v: TValue; ctxowned: Boolean; begin if ctx = nil then begin ctx := TSuperRttiContext.Create; ctxowned := True; end else ctxowned := False; try v := Self; if not ctx.FromJson(v.TypeInfo, obj, v) then raise Exception.Create('Invalid object'); finally if ctxowned then ctx.Free; end; end; constructor TSuperObjectHelper.FromJson(const str: string; ctx: TSuperRttiContext = nil); begin FromJson(SO(str), ctx); end; function TSuperObjectHelper.ToJson(ctx: TSuperRttiContext = nil): ISuperObject; var v: TValue; ctxowned: boolean; begin if ctx = nil then begin ctx := TSuperRttiContext.Create; ctxowned := True; end else ctxowned := False; try v := Self; Result := ctx.ToJson(v, SO); finally if ctxowned then ctx.Free; end; end; {$ENDIF} {$IFDEF DEBUG} initialization finalization Assert(debugcount = 0, 'Memory leak'); {$ENDIF} end. ================================================ FILE: lib/xedit/lz4/lz4.pas ================================================ (* LZ4Delphi Copyright (C) 2015, Jose Pascoa (atelierwebgm@gmail.com) BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) ************************************************************************* LZ4 - Fast LZ compression algorithm xxHash - Fast Hash algorithm LZ4 source repository : http://code.google.com/p/lz4/ xxHash source repository : http://code.google.com/p/xxhash/ Copyright (c) 2011-2014, Yann Collet BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************************** *) unit lz4; {$POINTERMATH ON} interface uses Windows, lz4Common; const LZ4_VERSION_MAJOR = 1; LZ4_VERSION_MINOR = 5; LZ4_VERSION_RELEASE = 0; LZ4_MEMORY_USAGE = 14; LZ4_STREAMSIZE_U64 = (1 shl (LZ4_MEMORY_USAGE - 3)) + 4; LZ4_STREAMSIZE = LZ4_STREAMSIZE_U64 * sizeof(int64); LZ4_MAX_INPUT_SIZE = $7E000000; LZ4_UNALIGNED_ACCESS = 1; LZ4_STREAMDECODESIZE_U64 = 4; type PLZ4_stream_t = ^LZ4_stream_t; LZ4_stream_t = record table: array [0 .. LZ4_STREAMSIZE_U64 - 1] of int64; end; PLZ4_streamDecode_t = ^LZ4_streamDecode_t; LZ4_streamDecode_t = record table: array [0 .. LZ4_STREAMDECODESIZE_U64 - 1] of int64; end; function LZ4_versionNumber: integer; function LZ4_compressBound(iSize: cardinal): cardinal; function LZ4_create(inputBuffer: pAnsiChar): pointer; function LZ4_createStream: PLZ4_stream_t; procedure LZ4_freeStream(LZ4_streamPtr: PLZ4_stream_t); function LZ4_createStreamDecode: PLZ4_streamDecode_t; procedure LZ4_freeStreamDecode(LZ4_stream: PLZ4_streamDecode_t); function LZ4_compress(source: pAnsiChar; dest: pAnsiChar; sourceSize: integer): integer; function LZ4_decompress_safe(source: pAnsiChar; dest: pAnsiChar; compressedSize: integer; maxDecompressedSize: integer): integer; function LZ4_compress_continue(LZ4_stream: pointer; const ASource: pointer; ADestination: pointer; AInputSize: integer): integer; function LZ4_saveDict(LZ4_streamPtr: PLZ4_stream_t; safeBuffer: pointer; dictSize: integer): integer; function LZ4_decompress_safe_continue(LZ4_streamDecode: PLZ4_streamDecode_t; source: pointer; dest: pointer; compressedSize: integer; maxDecompressedSize: integer): integer; function LZ4_compress_limitedOutput(const source: pAnsiChar; dest: pAnsiChar; inputSize: integer; maxOutputSize: integer): integer; function LZ4_compress_withState(state: pointer; const source: pAnsiChar; dest: pAnsiChar; inputSize: integer): integer; function LZ4_compress_limitedOutput_withState(state: pointer; const source: pAnsiChar; dest: pAnsiChar; inputSize: integer; maxOutputSize: integer): integer; function LZ4_compress_limitedOutput_continue(LZ4_stream: PLZ4_stream_t; const source: pAnsiChar; dest: pAnsiChar; inputSize: integer; maxOutputSize: integer): integer; procedure LZ4_resetStream(LZ4_stream: PLZ4_stream_t); function LZ4_loadDict(LZ4_dict: PLZ4_stream_t; dictionary: pAnsiChar; dictSize: integer): integer; // debug function function LZ4_compress_forceExtDict(LZ4_dict: PLZ4_stream_t; const source: pAnsiChar; dest: pAnsiChar; inputSize: integer): integer; function LZ4_decompress_fast(source: pAnsiChar; dest: pAnsiChar; originalSize: integer): integer; function LZ4_decompress_fast_withPrefix64k(source: pAnsiChar; dest: pAnsiChar; originalSize: integer): integer; function LZ4_decompress_fast_usingDict(source: pAnsiChar; dest: pAnsiChar; originalSize: integer; const dictStart: pAnsiChar; dictSize: integer): integer; function LZ4_decompress_safe_withPrefix64k(source: pAnsiChar; dest: pAnsiChar; compressedSize: integer; maxOutputSize: integer): integer; function LZ4_decompress_safe_usingDict(const source: pAnsiChar; dest: pAnsiChar; compressedSize: integer; maxOutputSize: integer; const dictStart: pAnsiChar; dictSize: integer): integer; function LZ4_decompress_safe_partial(const source: pAnsiChar; dest: pAnsiChar; compressedSize: integer; targetOutputSize: integer; maxDecompressedSize: integer): integer; function LZ4_decompress_safe_forceExtDict(source: pAnsiChar; dest: pAnsiChar; compressedSize: integer; maxOutputSize: integer; const dictStart: pAnsiChar; dictSize: integer): integer; // replaced with move(source^, dest^, count) // procedure memmove(dest, source: pointer; count: integer); cdecl; external 'msvcrt.dll' name 'memmove'; implementation const LZ4_HASHLOG = LZ4_MEMORY_USAGE - 2; HASHTABLESIZE = 1 shl LZ4_MEMORY_USAGE; HASH_SIZE_U32 = 1 shl LZ4_HASHLOG; type limitedOutput_directive = (notLimited = 0, limitedOutput = 1); tableType_t = (byPtr, byU32, byU16); dict_directive = (noDict = 0, withPrefix64k, usingExtDict); dictIssue_directive = (noDictIssue = 0, dictSmall); endCondition_directive = (endOnOutputSize = 0, endOnInputSize = 1); earlyEnd_directive = (full = 0, partial = 1); PLZ4_stream_t_internal = ^LZ4_stream_t_internal; LZ4_stream_t_internal = record hashTable: array [0 .. HASH_SIZE_U32 - 1] of cardinal; currentOffset: cardinal; initCheck: cardinal; dictionary: pByte; bufferStart: pByte; dictSize: cardinal; end; PLZ4_streamDecode_t_internal = ^LZ4_streamDecode_t_internal; LZ4_streamDecode_t_internal = record externalDict: pByte; extDictSize: size_t; prefixEnd: pByte; prefixSize: size_t; end; var LZ4_64Klimit: integer = 65536 + _MFLIMIT - 1; LZ4_skipTrigger: cardinal = 6; LZ4_minLength: integer = (_MFLIMIT + 1); function LZ4_versionNumber: integer; begin result := LZ4_VERSION_MAJOR * 100 * 100 + LZ4_VERSION_MINOR * 100 + LZ4_VERSION_RELEASE; end; function LZ4_compressBound(iSize: cardinal): cardinal; begin if (iSize) > cardinal(LZ4_MAX_INPUT_SIZE) then result := 0 else result := iSize + (iSize div 255 + 16) end; procedure LZ4_copy8(const dstPtr: pointer; const srcPtr: pointer); inline; begin {$IFDEF WIN64} pUint64(dstPtr)^ := pUint64(srcPtr)^; {$ELSE} pCardinal(dstPtr)[0] := pCardinal(srcPtr)[0]; pCardinal(dstPtr)[1] := pCardinal(srcPtr)[1]; {$ENDIF} end; function LZ4_hashSequence(sequence: cardinal; tableType: tableType_t): cardinal; inline; const SHL1 = (MINMATCH * 8) - (LZ4_HASHLOG + 1); SHL2 = ((MINMATCH * 8) - LZ4_HASHLOG); begin if (tableType = byU16) then result := (sequence * 2654435761) shr SHL1 else result := (sequence * 2654435761) shr SHL2; end; function LZ4_hashPosition(const p: pByte; tableType: tableType_t): cardinal; inline; begin result := LZ4_hashSequence(pCardinal(p)^, tableType); end; procedure LZ4_putPositionOnHash(const p: pByte; h: cardinal; tableBase: pointer; tableType: tableType_t; const srcBase: pByte); inline; begin case tableType of byPtr: ppByte(tableBase)[h] := p; byU32: pCardinal(tableBase)[h] := cardinal(p - srcBase); byU16: pWord(tableBase)[h] := word(p - srcBase); end; end; function LZ4_getPositionOnHash(h: cardinal; tableBase: pointer; tableType: tableType_t; const srcBase: pByte): pByte; inline; begin if (tableType = byPtr) then result := ppByte(tableBase)[h] else if (tableType = byU32) then result := pCardinal(tableBase)[h] + srcBase else result := pWord(tableBase)[h] + srcBase; end; function LZ4_getPosition(const p: pByte; tableBase: pointer; tableType: tableType_t; const srcBase: pByte): pByte; inline; var h: cardinal; begin h := LZ4_hashPosition(p, tableType); result := LZ4_getPositionOnHash(h, tableBase, tableType, srcBase); end; procedure LZ4_putPosition(const p: pByte; tableBase: pointer; tableType: tableType_t; const srcBase: pByte); inline; var h: cardinal; begin h := LZ4_hashPosition(p, tableType); LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase); end; function LZ4_compress_generic(ctx: pointer; const source: pointer; dest: pointer; inputSize: integer; maxOutputSize: integer; outputLimited: limitedOutput_directive; tableType: tableType_t; dict: dict_directive; dictIssue: dictIssue_directive): integer; inline; var lowRefLimit: pByte; match: pByte; refDelta: size_t; ip: pByte; dictPtr: PLZ4_stream_t_internal; base: pByte; lowLimit: pByte; dictionary: pByte; dictEnd: pByte; dictDelta: size_t; anchor: pByte; iend: pByte; mflimit: pByte; matchlimit: pByte; op: pByte; olimit: pByte; forwardH: cardinal; lastRun: integer; token: pByte; forwardIp: pByte; step: cardinal; searchMatchNb: cardinal; h: cardinal; litLength: cardinal; len: integer; matchLength: cardinal; limit: pByte; more: cardinal; booleanValue: boolean; label _last_literals, _next_match; begin match := nil; dictPtr := ctx; ip := pByte(source); lowRefLimit := ip - dictPtr.dictSize; dictionary := dictPtr.dictionary; dictEnd := dictionary + dictPtr.dictSize; dictDelta := dictEnd - pByte(source); anchor := pByte(source); iend := ip + inputSize; mflimit := iend - _MFLIMIT; matchlimit := iend - LASTLITERALS; op := pByte(dest); olimit := op + maxOutputSize; refDelta := 0; if cardinal(inputSize) > cardinal(LZ4_MAX_INPUT_SIZE) then exit(0); case dict of withPrefix64k: begin base := pByte(source) - dictPtr.currentOffset; lowLimit := pByte(source) - dictPtr.dictSize; end; usingExtDict: begin base := pByte(source) - dictPtr.currentOffset; lowLimit := pByte(source); end; else begin base := pByte(source); lowLimit := pByte(source); end; end; if ((tableType = byU16) and (inputSize >= LZ4_64Klimit)) then exit(0); if (inputSize < LZ4_minLength) then goto _last_literals; LZ4_putPosition(ip, ctx, tableType, base); inc(ip); forwardH := LZ4_hashPosition(ip, tableType); while true do begin forwardIp := ip; step := 1; searchMatchNb := (1 shl LZ4_skipTrigger); while true do begin h := forwardH; ip := forwardIp; inc(forwardIp, step); step := searchMatchNb shr LZ4_skipTrigger; inc(searchMatchNb); if forwardIp > mflimit then goto _last_literals; match := LZ4_getPositionOnHash(h, ctx, tableType, base); if (dict = usingExtDict) then begin if match < pByte(source) then begin refDelta := dictDelta; lowLimit := dictionary; end else begin refDelta := 0; lowLimit := pByte(source); end; end; forwardH := LZ4_hashPosition(forwardIp, tableType); LZ4_putPositionOnHash(ip, h, ctx, tableType, base); if (dictIssue = dictSmall) and (match < lowRefLimit) then continue; if not(tableType = byU16) and (match + MAX_DISTANCE < ip) then continue; if (pCardinal(match + refDelta)^ <> pCardinal(ip)^) then continue; break; end; while (ip > anchor) and (match + refDelta > lowLimit) and (ip[-1] = match[refDelta - 1]) do begin dec(ip); dec(match); end; litLength := cardinal(ip - anchor); token := op; inc(op); if (outputLimited <> notLimited) and (op + litLength + (2 + 1 + LASTLITERALS) + (litLength div 255) > olimit) then exit(0); if (litLength >= RUN_MASK) then begin len := integer(litLength - RUN_MASK); token^ := (RUN_MASK shl ML_BITS); while len >= 255 do begin op^ := 255; inc(op); dec(len, 255); end; op^ := BYTE(len); inc(op); end else token^ := BYTE(litLength shl ML_BITS); LZ4_wildCopy(op, anchor, op + litLength); inc(op, litLength); _next_match: pWord(op)^ := word(ip - match); inc(op, 2); if (dict = usingExtDict) and (lowLimit = dictionary) then begin inc(match, refDelta); limit := ip + (dictEnd - match); if (limit > matchlimit) then limit := matchlimit; matchLength := LZ4_count(ip + MINMATCH, match + MINMATCH, limit); inc(ip, MINMATCH + matchLength); if (ip = limit) then begin more := LZ4_count(ip, pByte(source), matchlimit); inc(matchLength, more); inc(ip, more); end; end else begin matchLength := LZ4_count(ip + MINMATCH, match + MINMATCH, matchlimit); inc(ip, MINMATCH + matchLength); end; if (outputLimited <> notLimited) and (op + (1 + LASTLITERALS) + (matchLength shr 8) > olimit) then exit(0); if (matchLength >= ML_MASK) then begin inc(token^, ML_MASK); dec(matchLength, ML_MASK); while matchLength >= 510 do begin pWord(op)^ := $FFFF; inc(op, 2); // op^ := 255; // inc(op); // op^ := 255; // inc(op); dec(matchLength, 510); end; if (matchLength >= 255) then begin dec(matchLength, 255); op^ := 255; inc(op); end; op^ := BYTE(matchLength); inc(op); end else inc(token^, BYTE(matchLength)); anchor := ip; if (ip > mflimit) then break; LZ4_putPosition(ip - 2, ctx, tableType, base); match := LZ4_getPosition(ip, ctx, tableType, base); if (dict = usingExtDict) then begin if match < pByte(source) then begin refDelta := dictDelta; lowLimit := dictionary; end else begin refDelta := 0; lowLimit := pByte(source); end; end; LZ4_putPosition(ip, ctx, tableType, base); if dictIssue = dictSmall then booleanValue := match >= lowRefLimit else booleanValue := true; if (booleanValue and (match + MAX_DISTANCE >= ip) and (pCardinal(match + refDelta)^ = pCardinal(ip)^)) then begin token := op; inc(op); token^ := 0; goto _next_match; end; inc(ip); forwardH := LZ4_hashPosition(ip, tableType); end; _last_literals: lastRun := integer(iend - anchor); if (outputLimited <> notLimited) and ((op - pByte(dest)) + lastRun + 1 + ((lastRun + 255 - RUN_MASK) div 255) > maxOutputSize) then exit(0); if lastRun >= integer(RUN_MASK) then begin op^ := (RUN_MASK shl ML_BITS); inc(op); dec(lastRun, RUN_MASK); while lastRun >= 255 do begin op^ := 255; inc(op); dec(lastRun, 255); end; op^ := BYTE(lastRun); inc(op); end else begin op^ := BYTE(lastRun shl ML_BITS); inc(op); end; move(anchor^, op^, iend - anchor); inc(op, iend - anchor); result := integer(op - pByte(dest)); end; function LZ4_compress(source: pAnsiChar; dest: pAnsiChar; sourceSize: integer): integer; var ctx: array [0 .. LZ4_STREAMSIZE_U64 - 1] of uint64; begin fillchar(ctx, sizeof(ctx), 0); if sourceSize < LZ4_64Klimit then result := LZ4_compress_generic(@ctx, source, dest, sourceSize, 0, notLimited, byU16, noDict, noDictIssue) else begin {$IFDEF WIN64} result := LZ4_compress_generic(@ctx, source, dest, sourceSize, 0, notLimited, byU32, noDict, noDictIssue) {$ELSE} result := LZ4_compress_generic(@ctx, source, dest, sourceSize, 0, notLimited, byPtr, noDict, noDictIssue); {$ENDIF} end; end; function LZ4_decompress_generic(const source: pointer; const dest: pointer; inputSize: integer; outputSize: integer; endOnInput: integer; partialDecoding: integer; targetOutputSize: integer; dict: integer; const lowPrefix: pByte; const dictStart: pByte; const dictSize: size_t): integer; inline; var ip: pByte; iend: pByte; op: pByte; oend: pByte; cpy: pByte; oexit: pByte; lowLimit: pByte; dictEnd: pByte; safeDecode: boolean; checkOffset: boolean; token: cardinal; length: size_t; match: pByte; s: cardinal; booleantest: boolean; copySize: size_t; endOfMatch: pByte; copyFrom: pByte; dec64: size_t; const dec32table: array [0 .. 7] of size_t = (4, 1, 2, 1, 4, 4, 4, 4); dec64table: array [0 .. 7] of size_t = (0, 0, 0, size_t(-1), 0, 1, 2, 3); label _output_error; begin ip := pByte(source); iend := ip + inputSize; op := pByte(dest); oend := op + outputSize; oexit := op + targetOutputSize; lowLimit := lowPrefix - dictSize; dictEnd := pByte(dictStart) + dictSize; safeDecode := (endOnInput = integer(endOnInputSize)); checkOffset := ((safeDecode) and (dictSize < 65536)); if (partialDecoding <> 0) and (oexit > oend - _MFLIMIT) then oexit := oend - _MFLIMIT; if (endOnInput <> 0) and (outputSize = 0) then begin if (inputSize = 1) and (ip^ = 0) then exit(0) else exit(-1); end; if (endOnInput = 0) and (outputSize = 0) then begin if ip^ = 0 then exit(1) else exit(-1); end; while true do begin token := ip^; inc(ip); length := token shr ML_BITS; if length = RUN_MASK then begin while true do begin s := ip^; inc(ip); inc(length, s); if endOnInput <> 0 then begin if not(ip < iend - RUN_MASK) then break; end; if s <> 255 then break; end; if safeDecode and (size_t(op + length) < size_t(op)) then goto _output_error; if safeDecode and (size_t(ip + length) < size_t(ip)) then goto _output_error; end; cpy := op + length; if partialDecoding <> 0 then booleantest := cpy > oexit else booleantest := cpy > oend - _MFLIMIT; if ((endOnInput <> 0) and ((booleantest) or (ip + length > iend - (2 + 1 + LASTLITERALS)))) or ((endOnInput = 0) and (cpy > oend - COPYLENGTH)) then begin if partialDecoding <> 0 then begin if (cpy > oend) then goto _output_error; if ((endOnInput <> 0) and (ip + length > iend)) then goto _output_error; end else begin if ((endOnInput = 0) and (cpy <> oend)) then goto _output_error; if ((endOnInput <> 0) and ((ip + length <> iend) or (cpy > oend))) then goto _output_error; end; move(ip^, op^, length); inc(ip, length); inc(op, length); break; end; LZ4_wildCopy(op, ip, cpy); inc(ip, length); op := cpy; match := cpy - LZ4_read16(ip); // LZ4_readLE16 = LZ4_read16 for unaligned inc(ip, 2); if checkOffset and (match < lowLimit) then goto _output_error; length := token and ML_MASK; if length = ML_MASK then begin while true do begin if ((endOnInput <> 0) and (ip > iend - LASTLITERALS)) then goto _output_error; s := ip^; inc(ip); inc(length, s); if s <> 255 then break; end; if safeDecode and (size_t(op + length) < size_t(op)) then goto _output_error; end; inc(length, MINMATCH); if (dict = integer(usingExtDict)) and (match < lowPrefix) then begin if op + length > oend - LASTLITERALS then goto _output_error; if (length <= size_t(lowPrefix - match)) then begin match := dictEnd - (lowPrefix - match); move(match^, op^, length); inc(op, length); end else begin copySize := size_t(lowPrefix - match); move((dictEnd - copySize)^, op^, copySize); inc(op, copySize); copySize := length - copySize; if copySize > size_t(op - lowPrefix) then begin endOfMatch := op + copySize; copyFrom := lowPrefix; while (op < endOfMatch) do begin op^ := copyFrom^; inc(op); inc(copyFrom); end; end else begin move(lowPrefix^, op^, copySize); inc(op, copySize); end; end; continue; end; cpy := op + length; if (op - match) < 8 then begin dec64 := dec64table[op - match]; op[0] := match[0]; op[1] := match[1]; op[2] := match[2]; op[3] := match[3]; inc(match, dec32table[op - match]); pCardinal(op + 4)^ := pCardinal(match)^; inc(op, 8); dec(match, dec64); end else begin {$IFDEF WIN64} pUint64(op)^ := pUint64(match)^; {$ELSE} pCardinal(op)[0] := pCardinal(match)[0]; pCardinal(op)[1] := pCardinal(match)[1]; {$ENDIF} inc(op, 8); inc(match, 8); end; if cpy > oend - 12 then begin if (cpy > oend - LASTLITERALS) then goto _output_error; if (op < oend - 8) then begin LZ4_wildCopy(op, match, oend - 8); inc(match, (oend - 8) - op); op := oend - 8; end; while (op < cpy) do begin op^ := match^; inc(op); inc(match); end; end else LZ4_wildCopy(op, match, cpy); op := cpy; end; if (endOnInput <> 0) then result := integer(op - pByte(dest)) else result := integer(ip - pByte(source)); exit; _output_error: result := -(ip - pByte(source)) - 1; end; function LZ4_decompress_safe(source: pAnsiChar; dest: pAnsiChar; compressedSize: integer; maxDecompressedSize: integer): integer; begin result := LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, integer(endOnInputSize), integer(full), 0, integer(noDict), pByte(dest), nil, 0); end; function LZ4_createStream: PLZ4_stream_t; begin result := allocmem(8 * LZ4_STREAMSIZE_U64); end; procedure LZ4_freeStream(LZ4_streamPtr: PLZ4_stream_t); begin freemem(LZ4_streamPtr); end; function LZ4_createStreamDecode: PLZ4_streamDecode_t; begin result := allocmem(sizeof(uint64) * LZ4_STREAMDECODESIZE_U64); end; procedure LZ4_freeStreamDecode(LZ4_stream: PLZ4_streamDecode_t); begin freemem(LZ4_stream); end; procedure LZ4_renormDictT(LZ4_dict: PLZ4_stream_t_internal; src: pByte); var delta: cardinal; dictEnd: pByte; i: integer; begin if (LZ4_dict.currentOffset > $80000000) or (size_t(LZ4_dict.currentOffset) > size_t(src)) then begin delta := LZ4_dict.currentOffset - 65536; dictEnd := LZ4_dict.dictionary + LZ4_dict.dictSize; for i := 0 to HASH_SIZE_U32 - 1 do begin if (LZ4_dict.hashTable[i] < delta) then LZ4_dict.hashTable[i] := 0 else dec(LZ4_dict.hashTable[i], delta); end; LZ4_dict.currentOffset := 65536; if (LZ4_dict.dictSize > 65536) then LZ4_dict.dictSize := 65536; LZ4_dict.dictionary := dictEnd - LZ4_dict.dictSize; end; end; function LZ4_compress_continue_generic(LZ4_stream: pointer; source: pointer; dest: pointer; inputSize: integer; maxOutputSize: integer; limit: limitedOutput_directive): integer; inline; var streamPtr: PLZ4_stream_t_internal; dictEnd: pByte; smallest: pByte; sourceEnd: pByte; res: integer; begin streamPtr := PLZ4_stream_t_internal(LZ4_stream); dictEnd := streamPtr.dictionary + streamPtr.dictSize; smallest := pByte(source); if (streamPtr.initCheck <> 0) then exit(0); if (streamPtr.dictSize > 0) and (smallest > dictEnd) then smallest := dictEnd; LZ4_renormDictT(streamPtr, smallest); sourceEnd := pByte(source) + inputSize; if (sourceEnd > streamPtr.dictionary) and (sourceEnd < dictEnd) then begin streamPtr.dictSize := cardinal(dictEnd - sourceEnd); if (streamPtr.dictSize > 65536) then streamPtr.dictSize := 65536; if (streamPtr.dictSize < 4) then streamPtr.dictSize := 0; streamPtr.dictionary := dictEnd - streamPtr.dictSize; end; if dictEnd = pByte(source) then begin if (streamPtr.dictSize < 65536) and (streamPtr.dictSize < streamPtr.currentOffset) then res := LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limit, byU32, withPrefix64k, dictSmall) else res := LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limit, byU32, withPrefix64k, noDictIssue); inc(streamPtr.dictSize, cardinal(inputSize)); inc(streamPtr.currentOffset, cardinal(inputSize)); exit(res); end; if (streamPtr.dictSize < 65536) and (streamPtr.dictSize < streamPtr.currentOffset) then res := LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limit, byU32, usingExtDict, dictSmall) else res := LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limit, byU32, usingExtDict, noDictIssue); streamPtr.dictionary := pByte(source); streamPtr.dictSize := cardinal(inputSize); inc(streamPtr.currentOffset, cardinal(inputSize)); result := res; end; function LZ4_compress_continue(LZ4_stream: pointer; const ASource: pointer; ADestination: pointer; AInputSize: integer): integer; begin result := LZ4_compress_continue_generic(LZ4_stream, ASource, ADestination, AInputSize, 0, notLimited); end; function LZ4_saveDict(LZ4_streamPtr: PLZ4_stream_t; safeBuffer: pointer; dictSize: integer): integer; var dict: PLZ4_stream_t_internal; previousDictEnd: pByte; begin dict := PLZ4_stream_t_internal(LZ4_streamPtr); previousDictEnd := dict.dictionary + dict.dictSize; if cardinal(dictSize) > 65536 then dictSize := 65536; if cardinal(dictSize) > dict.dictSize then dictSize := dict.dictSize; move((previousDictEnd - dictSize)^, safeBuffer^, dictSize); // memmove(safeBuffer, (previousDictEnd - dictSize), dictSize); dict.dictionary := pByte(safeBuffer); dict.dictSize := cardinal(dictSize); result := dictSize; end; function LZ4_decompress_safe_continue(LZ4_streamDecode: PLZ4_streamDecode_t; source: pointer; dest: pointer; compressedSize: integer; maxDecompressedSize: integer): integer; var lz4sd: PLZ4_streamDecode_t_internal; res: integer; begin lz4sd := PLZ4_streamDecode_t_internal(LZ4_streamDecode); if lz4sd.prefixEnd = pByte(dest) then begin res := LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, integer(endOnInputSize), integer(full), 0, integer(usingExtDict), lz4sd.prefixEnd - lz4sd.prefixSize, lz4sd.externalDict, lz4sd.extDictSize); if (res <= 0) then exit(res); inc(lz4sd.prefixSize, res); inc(lz4sd.prefixEnd, res); end else begin lz4sd.extDictSize := lz4sd.prefixSize; lz4sd.externalDict := lz4sd.prefixEnd - lz4sd.extDictSize; res := LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, integer(endOnInputSize), integer(full), 0, integer(usingExtDict), pByte(dest), lz4sd.externalDict, lz4sd.extDictSize); if (res <= 0) then exit(res); lz4sd.prefixSize := res; lz4sd.prefixEnd := pByte(dest) + res; end; result := res; end; procedure LZ4_init(lz4ds: PLZ4_stream_t_internal; base: pByte); begin fillchar(lz4ds^, LZ4_STREAMSIZE, 0); lz4ds.bufferStart := base; end; function LZ4_create(inputBuffer: pAnsiChar): pointer; var lz4ds: pointer; begin lz4ds := allocmem(8 * LZ4_STREAMSIZE_U64); LZ4_init(PLZ4_stream_t_internal(lz4ds), pByte(inputBuffer)); result := lz4ds; end; function LZ4_compress_limitedOutput(const source: pAnsiChar; dest: pAnsiChar; inputSize: integer; maxOutputSize: integer): integer; var ctx: array [0 .. LZ4_STREAMSIZE_U64 - 1] of uint64; begin fillchar(ctx, sizeof(ctx), 0); if inputSize < LZ4_64Klimit then result := LZ4_compress_generic(@ctx, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue) else begin {$IFDEF WIN64} result := LZ4_compress_generic(@ctx, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, noDict, noDictIssue); {$ELSE} result := LZ4_compress_generic(@ctx, source, dest, inputSize, maxOutputSize, limitedOutput, byPtr, noDict, noDictIssue); {$ENDIF} end; end; function LZ4_compress_withState(state: pointer; const source: pAnsiChar; dest: pAnsiChar; inputSize: integer): integer; begin if ((size_t(state) and 3) <> 0) then exit(0); // Error : state is not aligned on 4-bytes boundary fillchar(state^, LZ4_STREAMSIZE, 0); if inputSize < LZ4_64Klimit then result := LZ4_compress_generic(state, source, dest, inputSize, 0, notLimited, byU16, noDict, noDictIssue) else begin {$IFDEF WIN64} result := LZ4_compress_generic(state, source, dest, inputSize, 0, notLimited, byU32, noDict, noDictIssue); {$ELSE} result := LZ4_compress_generic(state, source, dest, inputSize, 0, notLimited, byPtr, noDict, noDictIssue); {$ENDIF} end; end; function LZ4_compress_limitedOutput_withState(state: pointer; const source: pAnsiChar; dest: pAnsiChar; inputSize: integer; maxOutputSize: integer): integer; begin if ((size_t(state) and 3) <> 0) then exit(0); // Error : state is not aligned on 4-bytes boundary fillchar(state^, LZ4_STREAMSIZE, 0); if inputSize < LZ4_64Klimit then result := LZ4_compress_generic(state, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue) else begin {$IFDEF WIN64} result := LZ4_compress_generic(state, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, noDict, noDictIssue); {$ELSE} result := LZ4_compress_generic(state, source, dest, inputSize, maxOutputSize, limitedOutput, byPtr, noDict, noDictIssue); {$ENDIF} end; end; function LZ4_compress_limitedOutput_continue(LZ4_stream: PLZ4_stream_t; const source: pAnsiChar; dest: pAnsiChar; inputSize: integer; maxOutputSize: integer): integer; begin result := LZ4_compress_continue_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput); end; function LZ4_compress_forceExtDict(LZ4_dict: PLZ4_stream_t; const source: pAnsiChar; dest: pAnsiChar; inputSize: integer): integer; var streamPtr: PLZ4_stream_t_internal; dictEnd: pByte; smallest: pByte; begin streamPtr := PLZ4_stream_t_internal(LZ4_dict); dictEnd := streamPtr.dictionary + streamPtr.dictSize; smallest := dictEnd; if smallest > pByte(source) then smallest := pByte(source); LZ4_renormDictT(PLZ4_stream_t_internal(LZ4_dict), smallest); result := LZ4_compress_generic(LZ4_dict, source, dest, inputSize, 0, notLimited, byU32, usingExtDict, noDictIssue); streamPtr.dictionary := pByte(source); streamPtr.dictSize := cardinal(inputSize); inc(streamPtr.currentOffset, cardinal(inputSize)); end; procedure LZ4_resetStream(LZ4_stream: PLZ4_stream_t); begin fillchar(LZ4_stream^, sizeof(LZ4_stream_t), 0); end; function LZ4_loadDict(LZ4_dict: PLZ4_stream_t; dictionary: pAnsiChar; dictSize: integer): integer; var dict: PLZ4_stream_t_internal; p: pByte; dictEnd: pByte; base: pByte; begin dict := PLZ4_stream_t_internal(LZ4_dict); p := pByte(dictionary); dictEnd := p + dictSize; if (dict.initCheck <> 0) then LZ4_resetStream(LZ4_dict); // Uninitialized structure detected if dictSize < MINMATCH then begin dict.dictionary := Nil; dict.dictSize := 0; exit(0); end; if (p <= dictEnd - 65536) then p := dictEnd - 65536; base := p - dict.currentOffset; dict.dictionary := p; dict.dictSize := cardinal(dictEnd - p); inc(dict.currentOffset, dict.dictSize); while (p <= dictEnd - MINMATCH) do begin LZ4_putPosition(p, dict, byU32, base); inc(p, 3); end; result := dict.dictSize; end; function LZ4_decompress_fast(source: pAnsiChar; dest: pAnsiChar; originalSize: integer): integer; begin result := LZ4_decompress_generic(source, dest, 0, originalSize, integer(endOnOutputSize), integer(full), 0, integer(withPrefix64k), pByte(dest - 65536), Nil, 65536); end; function LZ4_decompress_fast_withPrefix64k(source: pAnsiChar; dest: pAnsiChar; originalSize: integer): integer; begin result := LZ4_decompress_generic(source, dest, 0, originalSize, integer(endOnOutputSize), integer(full), 0, integer(withPrefix64k), pByte(dest) - 65536, Nil, 65536); end; function LZ4_decompress_usingDict_generic(source: pAnsiChar; dest: pAnsiChar; compressedSize: integer; maxOutputSize: integer; safe: integer; dictStart: pAnsiChar; dictSize: integer): integer; inline; begin if dictSize = 0 then exit(LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, integer(full), 0, integer(noDict), pByte(dest), Nil, 0)); if (dictStart + dictSize = dest) then begin if dictSize >= integer(65536 - 1) then exit(LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, integer(full), 0, integer(withPrefix64k), pByte(dest) - 65536, Nil, 0)); exit(LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, integer(full), 0, integer(noDict), pByte(dest) - dictSize, Nil, 0)); end; result := LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, integer(full), 0, integer(usingExtDict), pByte(dest), pByte(dictStart), dictSize); end; function LZ4_decompress_fast_usingDict(source: pAnsiChar; dest: pAnsiChar; originalSize: integer; const dictStart: pAnsiChar; dictSize: integer): integer; begin result := LZ4_decompress_usingDict_generic(source, dest, 0, originalSize, 0, dictStart, dictSize); end; function LZ4_decompress_safe_withPrefix64k(source: pAnsiChar; dest: pAnsiChar; compressedSize: integer; maxOutputSize: integer): integer; begin result := LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, integer(endOnInputSize), integer(full), 0, integer(withPrefix64k), pByte(dest) - 65536, Nil, 65536); end; function LZ4_decompress_safe_usingDict(const source: pAnsiChar; dest: pAnsiChar; compressedSize: integer; maxOutputSize: integer; const dictStart: pAnsiChar; dictSize: integer): integer; begin result := LZ4_decompress_usingDict_generic(source, dest, compressedSize, maxOutputSize, 1, dictStart, dictSize); end; function LZ4_decompress_safe_partial(const source: pAnsiChar; dest: pAnsiChar; compressedSize: integer; targetOutputSize: integer; maxDecompressedSize: integer): integer; begin result := LZ4_decompress_generic(source, dest, compressedSize, maxDecompressedSize, integer(endOnInputSize), integer(partial), targetOutputSize, integer(noDict), pByte(dest), Nil, 0); end; function LZ4_decompress_safe_forceExtDict(source: pAnsiChar; dest: pAnsiChar; compressedSize: integer; maxOutputSize: integer; const dictStart: pAnsiChar; dictSize: integer): integer; begin result := LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, integer(endOnInputSize), integer(full), 0, integer(usingExtDict), pByte(dest), pByte(dictStart), dictSize); end; end. ================================================ FILE: lib/xedit/lz4/lz4Common.pas ================================================ (* LZ4Delphi Copyright (C) 2015, Jose Pascoa (atelierwebgm@gmail.com) BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) ************************************************************************* LZ4 - Fast LZ compression algorithm xxHash - Fast Hash algorithm LZ4 source repository : http://code.google.com/p/lz4/ xxHash source repository : http://code.google.com/p/xxhash/ Copyright (c) 2011-2014, Yann Collet BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************************** *) unit lz4common; {$POINTERMATH ON} interface uses Windows; type ppByte = ^pByte; {$IFDEF WIN32} size_t = Cardinal; {$ENDIF WIN32} {$IFDEF WIN64} size_t = UInt64; {$ENDIF WIN64} psize_t = ^size_t; const MINMATCH = 4; COPYLENGTH = 8; LASTLITERALS = 5; _MFLIMIT = COPYLENGTH + MINMATCH; MAXD_LOG = 16; MAX_DISTANCE = (1 shl MAXD_LOG) - 1; STEPSIZE = sizeof(size_t); ML_BITS = 4; ML_MASK = (1 shl ML_BITS) - 1; RUN_BITS = 8 - ML_BITS; RUN_MASK = (1 shl RUN_BITS) - 1; function LZ4_read32(const memPtr: pointer): cardinal; function LZ4_read64(const memPtr: pointer): uint64; inline; function LZ4_count(pIn: pByte; pMatch: pByte; const pInLimit: pByte): cardinal; function LZ4_read_ARCH(const p: pointer): size_t; inline; function LZ4_read16(const memPtr: pointer): word; inline; procedure LZ4_writeLE16(memPtr: pointer; value: word); inline; procedure LZ4_wildCopy(dstPtr: pointer; const srcPtr: pointer; dstEnd: pointer); implementation function LZ4_read32(const memPtr: pointer): cardinal; begin result := pCardinal(memPtr)^; end; {$IFDEF WIN64} function LZ4_NbCommonBytesx64(value: size_t): cardinal; asm bsf rax, rcx // value comes in rcx register shr eax, 3 end; {$ENDIF} function LZ4_count(pIn: pByte; pMatch: pByte; const pInLimit: pByte): cardinal; var pStart: pByte; diff: size_t; incValue: cardinal; calcedPByte: pByte; begin pStart := pIn; calcedPByte := pInLimit - (STEPSIZE - 1); while pIn < calcedPByte do begin diff := LZ4_read_ARCH(pMatch) xor LZ4_read_ARCH(pIn); if (diff = 0) then begin inc(pIn, STEPSIZE); inc(pMatch, STEPSIZE); continue; end; {$IFDEF WIN32} asm bsf eax, diff shr eax, 3 mov incValue, eax end; {$ELSE} incValue := LZ4_NbCommonBytesx64(diff); // x64 mode does not allow asm inline {$ENDIF} inc(pIn, incValue); exit(cardinal(pIn - pStart)); end; {$IFDEF WIN64} if (pIn < (pInLimit - 3)) and (pCardinal(pMatch)^ = pCardinal(pIn)^) then begin inc(pIn, 4); inc(pMatch, 4); end; {$ENDIF} if ((pIn < (pInLimit - 1)) and (pWord(pMatch)^ = pWord(pIn)^)) then begin inc(pIn, 2); inc(pMatch, 2); end; if ((pIn < pInLimit) and (pMatch^ = pIn^)) then inc(pIn); result := cardinal(pIn - pStart); end; function LZ4_read_ARCH(const p: pointer): size_t; inline; begin {$IFDEF WIN64} result := size_t(pUint64(p)^) {$ELSE} result := size_t(pCardinal(p)^); {$ENDIF} end; function LZ4_read16(const memPtr: pointer): word; inline; begin result := pWord(memPtr)^; end; function LZ4_read64(const memPtr: pointer): uint64; inline; begin result := pUint64(memPtr)^; end; {$IFDEF WILDCOPY_ASM} {$IFDEF WIN32} procedure LZ4_wildCopy; // (dstPtr: pointer; const srcPtr: pointer; dstEnd: pointer); asm push edi push esi mov edi, eax mov esi, edx // copyCount := (((e - d) - 1) div 8) * 8 + 8; sub ecx, eax // (e - d) dec ecx // e - d) - 1) shr ecx, 3 // ((e - d) - 1) div 8) shl ecx, 3 // ((e - d) - 1) div 8) * 8 add ecx, 8 // ((e - d) - 1) div 8) * 8 + 8 // if copyCount <= 0 then // copyCount := 8; mov eax, 8 cmp ecx, 0 cmovbe ecx, eax shr ecx, 2 rep movsd pop esi pop edi end; {$ELSE} procedure LZ4_wildCopy; // (dstPtr: pointer; const srcPtr: pointer; dstEnd: pointer); asm mov r10, rdi mov r11, rsi mov rdi, rcx mov rsi, rdx // copyCount := (((e - d) - 1) div 8) * 8 + 8; sub r8, rcx // (dstEnd - dest) mov rax, 8 dec r8 // e - d) - 1) shr r8, 3 // ((e - d) - 1) div 8) shl r8, 3 // ((e - d) - 1) div 8) * 8 add r8, rax // ((e - d) - 1) div 8) * 8 + 8 cmp r8, 0 cmovbe r8, rax mov rcx, r8 shr rcx, 3 rep movsq mov rdi, r10 mov rsi, r11 end; {$ENDIF} {$ELSE} procedure LZ4_wildCopy(dstPtr: pointer; const srcPtr: pointer; dstEnd: pointer); inline; var d: pByte; s: pByte; e: pByte; begin d := dstPtr; s := srcPtr; e := dstEnd; repeat {$IFDEF WIN32} pCardinal(d)[0] := pCardinal(s)[0]; pCardinal(d)[1] := pCardinal(s)[1]; {$ELSE} pUint64(d)^ := pUint64(s)^; {$ENDIF} inc(d, 8); inc(s, 8); until not(d < e); end; {$ENDIF} procedure LZ4_writeLE16(memPtr: pointer; value: word); inline; begin pWord(memPtr)^ := value; end; end. ================================================ FILE: lib/xedit/lz4/lz4HC.pas ================================================ (* LZ4Delphi Copyright (C) 2015, Jose Pascoa (atelierwebgm@gmail.com) BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) ************************************************************************* LZ4 - Fast LZ compression algorithm xxHash - Fast Hash algorithm LZ4 source repository : http://code.google.com/p/lz4/ xxHash source repository : http://code.google.com/p/xxhash/ Copyright (c) 2011-2014, Yann Collet BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************************** *) unit lz4HC; {$POINTERMATH ON} interface uses Windows, lz4Common; const LZ4_STREAMHCSIZE_U64 = 32774; type PLZ4_streamHC_t = ^LZ4_streamHC_t; LZ4_streamHC_t = record table: array [0 .. LZ4_STREAMHCSIZE_U64 - 1] of uint64; end; function LZ4_createStreamHC: PLZ4_streamHC_t; procedure LZ4_freeStreamHC(LZ4_streamHCPtr: PLZ4_streamHC_t); function LZ4_compressHC2(const source: pAnsiChar; dest: pAnsiChar; inputSize: integer; compressionLevel: integer): integer; function LZ4_compressHC(source: pAnsiChar; dest: pAnsiChar; inputSize: integer): integer; function LZ4_compressHC_limitedOutput(const source: pAnsiChar; dest: pAnsiChar; inputSize: integer; maxOutputSize: integer): integer; function LZ4_compressHC2_limitedOutput(const source: pAnsiChar; dest: pAnsiChar; inputSize: integer; maxOutputSize: integer; compressionLevel: integer): integer; function LZ4_compressHC_withStateHC(state: pointer; const source: pAnsiChar; dest: pAnsiChar; inputSize: integer): integer; function LZ4_compressHC2_withStateHC(state: pointer; const source: pAnsiChar; dest: pAnsiChar; inputSize: integer; compressionLevel: integer): integer; function LZ4_compressHC_limitedOutput_withStateHC(state: pointer; const source: pAnsiChar; dest: pAnsiChar; inputSize: integer; maxOutputSize: integer): integer; function LZ4_compressHC2_limitedOutput_withStateHC(state: pointer; const source: pAnsiChar; dest: pAnsiChar; inputSize: integer; maxOutputSize: integer; compressionLevel: integer): integer; function LZ4_createHC(inputBuffer: pAnsiChar): pointer; function LZ4_compressHC_continue(LZ4_streamHCPtr: PLZ4_streamHC_t; const source: pAnsiChar; dest: pAnsiChar; inputSize: integer): integer; function LZ4_loadDictHC(LZ4_streamHCPtr: PLZ4_streamHC_t; dictionary: pAnsiChar; dictSize: integer): integer; function LZ4_compressHC_limitedOutput_continue(LZ4_streamHCPtr: PLZ4_streamHC_t; const source: pAnsiChar; dest: pAnsiChar; inputSize: integer; maxOutputSize: integer): integer; procedure LZ4_resetStreamHC(LZ4_streamHCPtr: PLZ4_streamHC_t; compressionLevel: integer); function LZ4_saveDictHC(LZ4_streamHCPtr: PLZ4_streamHC_t; safeBuffer: pAnsiChar; dictSize: integer): integer; implementation const DICTIONARY_LOGSIZE = 16; MAXD = (1 shl DICTIONARY_LOGSIZE); HASH_LOG = (DICTIONARY_LOGSIZE - 1); HASHTABLESIZE = (1 shl HASH_LOG); OPTIMAL_ML = integer((ML_MASK - 1) + MINMATCH); g_maxCompressionLevel: integer = 16; LZ4HC_compressionLevel_default: integer = 8; type PLZ4HC_Data_Structure = ^LZ4HC_Data_Structure; LZ4HC_Data_Structure = record hashTable: array [0 .. HASHTABLESIZE - 1] of cardinal; chainTable: array [0 .. MAXD - 1] of word; _end: pByte; base: pByte; dictBase: pByte; inputBuffer: pByte; dictLimit: cardinal; lowLimit: cardinal; nextToUpdate: cardinal; compressionLevel: cardinal; end; limitedOutput_directive = (noLimit = 0, limitedOutput = 1); function LZ4_createStreamHC: PLZ4_streamHC_t; begin result := allocmem(sizeof(LZ4_streamHC_t)); end; procedure LZ4_freeStreamHC(LZ4_streamHCPtr: PLZ4_streamHC_t); begin freemem(LZ4_streamHCPtr); end; procedure LZ4HC_init(hc4: PLZ4HC_Data_Structure; const start: pByte); begin fillchar(hc4.hashTable, sizeof(hc4.hashTable), 0); fillchar(hc4.chainTable, sizeof(hc4.chainTable), 255); hc4.nextToUpdate := 65536; hc4.base := start - 65536; hc4.inputBuffer := start; hc4._end := start; hc4.dictBase := start - 65536; hc4.dictLimit := 65536; hc4.lowLimit := 65536; end; function HASH_FUNCTION(i: cardinal): cardinal; inline; begin result := (i * 2654435761) shr ((MINMATCH * 8) - HASH_LOG); end; function LZ4HC_hashPtr(const ptr: pointer): cardinal; inline; begin result := HASH_FUNCTION(pCardinal(ptr)^); end; procedure LZ4HC_Insert(hc4: PLZ4HC_Data_Structure; const ip: pByte); inline; var chainTable: pWord; hashTable: pCardinal; base: pByte; target: cardinal; idx: cardinal; h: cardinal; delta: size_t; begin chainTable := @hc4.chainTable; hashTable := @hc4.hashTable; base := hc4.base; target := cardinal(ip - base); idx := hc4.nextToUpdate; while idx < target do begin h := LZ4HC_hashPtr(base + idx); delta := idx - hashTable[h]; if (delta > MAX_DISTANCE) then delta := MAX_DISTANCE; chainTable[idx and $FFFF] := word(delta); hashTable[h] := idx; inc(idx); end; hc4.nextToUpdate := target; end; function LZ4HC_InsertAndFindBestMatch(hc4: PLZ4HC_Data_Structure; const ip: pByte; const iLimit: pByte; const matchpos: ppByte; const maxNbAttempts: integer): integer; inline; var chainTable: pWord; hashTable: pCardinal; base: pByte; dictBase: pByte; dictLimit: cardinal; lowLimit: cardinal; matchIndex: cardinal; match: pByte; nbAttempts: integer; ml: size_t; mlt: size_t; vLimit: pByte; begin chainTable := @hc4.chainTable; hashTable := @hc4.hashTable; base := hc4.base; dictBase := hc4.dictBase; dictLimit := hc4.dictLimit; if hc4.lowLimit + 65536 > cardinal(ip - base) then lowLimit := hc4.lowLimit else lowLimit := cardinal(ip - base) - 65535; nbAttempts := maxNbAttempts; ml := 0; LZ4HC_Insert(hc4, ip); matchIndex := hashTable[LZ4HC_hashPtr(ip)]; while (matchIndex >= lowLimit) and (nbAttempts > 0) do begin dec(nbAttempts); if matchIndex >= dictLimit then begin match := base + matchIndex; if ((match + ml)^ = (ip + ml)^) and (pCardinal(match)^ = pCardinal(ip)^) then begin mlt := LZ4_count(ip + MINMATCH, match + MINMATCH, iLimit) + MINMATCH; if mlt > ml then begin ml := mlt; matchpos^ := match; end; end; end else begin match := dictBase + matchIndex; if pCardinal(match)^ = pCardinal(ip)^ then begin vLimit := ip + (dictLimit - matchIndex); if (vLimit > iLimit) then vLimit := iLimit; mlt := LZ4_count(ip + MINMATCH, match + MINMATCH, vLimit) + MINMATCH; if ((ip + mlt = vLimit) and (vLimit < iLimit)) then inc(mlt, LZ4_count(ip + mlt, base + dictLimit, iLimit)); if (mlt > ml) then begin ml := mlt; matchpos^ := base + matchIndex; end; // virtual matchpos end; end; dec(matchIndex, chainTable[matchIndex and $FFFF]); end; result := integer(ml); end; function LZ4HC_InsertAndGetWiderMatch(hc4: PLZ4HC_Data_Structure; const ip: pByte; const iLowLimit: pByte; const iHighLimit: pByte; longest: integer; const matchpos: ppByte; const startpos: ppByte; const maxNbAttempts: integer): integer; inline; var chainTable: pWord; hashTable: pCardinal; base: pByte; dictLimit: cardinal; lowLimit: cardinal; dictBase: pByte; match: pByte; matchIndex: cardinal; nbAttempts: integer; delta: integer; startt: pByte; tmpMatch: pByte; matchEnd: pByte; mlt: size_t; back: integer; vLimit: pByte; begin chainTable := @hc4.chainTable; hashTable := @hc4.hashTable; base := hc4.base; dictLimit := hc4.dictLimit; if (hc4.lowLimit + 65536 > cardinal(ip - base)) then lowLimit := hc4.lowLimit else lowLimit := cardinal(ip - base) - 65535; dictBase := hc4.dictBase; nbAttempts := maxNbAttempts; delta := integer(ip - iLowLimit); LZ4HC_Insert(hc4, ip); matchIndex := hashTable[LZ4HC_hashPtr(ip)]; while (matchIndex >= lowLimit) and (nbAttempts > 0) do begin dec(nbAttempts); if matchIndex >= dictLimit then begin match := base + matchIndex; if ((iLowLimit + longest)^ = (match - delta + longest)^) then if pCardinal(match)^ = pCardinal(ip)^ then begin startt := ip; tmpMatch := match; matchEnd := ip + MINMATCH + LZ4_count(ip + MINMATCH, match + MINMATCH, iHighLimit); while (startt > iLowLimit) and (tmpMatch > iLowLimit) and (startt[-1] = tmpMatch[-1]) do begin dec(startt); dec(tmpMatch); end; if (matchEnd - startt) > longest then begin longest := integer(matchEnd - startt); matchpos^ := tmpMatch; startpos^ := startt; end; end; end else begin match := dictBase + matchIndex; if pCardinal(match)^ = pCardinal(ip)^ then begin back := 0; vLimit := ip + (dictLimit - matchIndex); if vLimit > iHighLimit then vLimit := iHighLimit; mlt := LZ4_count(ip + MINMATCH, match + MINMATCH, vLimit) + MINMATCH; if (ip + mlt = vLimit) and (vLimit < iHighLimit) then inc(mlt, LZ4_count(ip + mlt, base + dictLimit, iHighLimit)); while ((ip + back > iLowLimit) and (matchIndex + cardinal(back) > lowLimit) and (ip[back - 1] = match[back - 1])) do dec(back); dec(mlt, back); if integer(mlt) > longest then begin longest := integer(mlt); matchpos^ := base + matchIndex + back; startpos^ := ip + back; end; end; end; dec(matchIndex, chainTable[matchIndex and $FFFF]); end; result := longest; end; function LZ4HC_encodeSequence(const ip: ppByte; op: ppByte; const anchor: ppByte; matchLength: integer; const match: pByte; limitedOutputBuffer: limitedOutput_directive; oend: pByte): integer; inline; var length: integer; token: pByte; len: integer; begin length := integer(ip^ - anchor^); token := op^; inc(op^); if (limitedOutputBuffer <> noLimit) and ((op^ + (length shr 8) + length + (2 + 1 + LASTLITERALS)) > oend) then exit(1); if length >= integer(RUN_MASK) then begin token^ := (RUN_MASK shl ML_BITS); len := length - RUN_MASK; while len > 254 do begin op^^ := 255; inc(op^); dec(len, 255) end; op^^ := byte(len); inc(op^); end else token^ := byte(length shl ML_BITS); LZ4_wildCopy(op^, anchor^, op^ + length); inc(op^, length); pWord(op^)^ := word(ip^ - match); // ? inc(op^, 2); length := integer(matchLength - MINMATCH); if (limitedOutputBuffer <> noLimit) and (op^ + (length shr 8) + (1 + LASTLITERALS) > oend) then exit(1); if length >= integer(ML_MASK) then begin inc(token^, ML_MASK); dec(length, ML_MASK); while length > 509 do begin op^^ := 255; inc(op^); op^^ := 255; inc(op^); dec(length, 510); end; if (length > 254) then begin dec(length, 255); op^^ := 255; inc(op^); end; op^^ := byte(length); inc(op^); end else inc(token^, byte(length)); inc(ip^, matchLength); anchor^ := ip^; result := 0; end; function LZ4HC_compress_generic(ctxvoid: pointer; const source: pAnsiChar; dest: pAnsiChar; inputSize: integer; maxOutputSize: integer; compressionLevel: integer; limit: limitedOutput_directive): integer; var ctx: PLZ4HC_Data_Structure; ip: pByte; anchor: pByte; iend: pByte; mflimit: pByte; matchlimit: pByte; op: pByte; oend: pByte; maxNbAttempts: cardinal; ml, ml2, ml3, ml0: integer; ref: pByte; start2: pByte; ref2: pByte; start3: pByte; ref3: pByte; start0: pByte; ref0: pByte; correction: integer; new_ml: integer; lastRun: integer; label _Search2, _Search3; begin ctx := ctxvoid; ip := pByte(source); anchor := ip; iend := ip + inputSize; mflimit := iend - _MFLIMIT; matchlimit := (iend - LASTLITERALS); op := pByte(dest); oend := op + maxOutputSize; ref := nil; start2 := nil; ref2 := nil; start3 := nil; ref3 := nil; // init if compressionLevel > g_maxCompressionLevel then compressionLevel := g_maxCompressionLevel; if (compressionLevel < 1) then compressionLevel := LZ4HC_compressionLevel_default; maxNbAttempts := 1 shl (compressionLevel - 1); inc(ctx._end, inputSize); inc(ip); // Main Loop while ip < mflimit do begin ml := LZ4HC_InsertAndFindBestMatch(ctx, ip, matchlimit, (@ref), maxNbAttempts); if (ml = 0) then begin inc(ip); continue; end; // saved, in case we would skip too much start0 := ip; ref0 := ref; ml0 := ml; _Search2: if ip + ml < mflimit then ml2 := LZ4HC_InsertAndGetWiderMatch(ctx, ip + ml - 2, ip + 1, matchlimit, ml, @ref2, @start2, maxNbAttempts) else ml2 := ml; if (ml2 = ml) then // No better match begin if LZ4HC_encodeSequence(@ip, @op, @anchor, ml, ref, limit, oend) > 0 then exit(0); continue; end; if start0 < ip then begin if start2 < ip + ml0 then // empirical begin ip := start0; ref := ref0; ml := ml0; end; end; // Here, start0==ip if ((start2 - ip) < 3) then // First Match too small : removed begin ml := ml2; ip := start2; ref := ref2; goto _Search2; end; _Search3: if (start2 - ip) < OPTIMAL_ML then begin new_ml := ml; if new_ml > OPTIMAL_ML then new_ml := OPTIMAL_ML; if ip + new_ml > start2 + ml2 - MINMATCH then new_ml := integer(start2 - ip) + ml2 - MINMATCH; correction := new_ml - integer(start2 - ip); if (correction > 0) then begin inc(start2, correction); inc(ref2, correction); dec(ml2, correction); end; end; // Now, we have start2 = ip+new_ml, with new_ml = min(ml, OPTIMAL_ML=18) if start2 + ml2 < mflimit then ml3 := LZ4HC_InsertAndGetWiderMatch(ctx, start2 + ml2 - 3, start2, matchlimit, ml2, @ref3, @start3, maxNbAttempts) else ml3 := ml2; if (ml3 = ml2) then // No better match : 2 sequences to encode begin // ip & ref are known; Now for ml if start2 < ip + ml then ml := integer(start2 - ip); // Now, encode 2 sequences if LZ4HC_encodeSequence(@ip, @op, @anchor, ml, ref, limit, oend) <> 0 then exit(0); ip := start2; if LZ4HC_encodeSequence(@ip, @op, @anchor, ml2, ref2, limit, oend) <> 0 then exit(0); continue; end; if start3 < ip + ml + 3 then // Not enough space for match 2 : remove it begin if start3 >= (ip + ml) then // can write Seq1 immediately ==> Seq2 is removed, so Seq3 becomes Seq1 begin if start2 < ip + ml then begin correction := integer(ip + ml - start2); inc(start2, correction); inc(ref2, correction); dec(ml2, correction); if ml2 < MINMATCH then begin start2 := start3; ref2 := ref3; ml2 := ml3; end; end; if LZ4HC_encodeSequence(@ip, @op, @anchor, ml, ref, limit, oend) <> 0 then exit(0); ip := start3; ref := ref3; ml := ml3; start0 := start2; ref0 := ref2; ml0 := ml2; goto _Search2; end; start2 := start3; ref2 := ref3; ml2 := ml3; goto _Search3; end; (* * OK, now we have 3 ascending matches; let's write at least the first one * ip & ref are known; Now for ml *) if start2 < ip + ml then begin if (start2 - ip) < integer(ML_MASK) then begin if ml > OPTIMAL_ML then ml := OPTIMAL_ML; if ip + ml > start2 + ml2 - MINMATCH then ml := integer(start2 - ip) + ml2 - MINMATCH; correction := ml - integer(start2 - ip); if correction > 0 then begin inc(start2, correction); inc(ref2, correction); dec(ml2, correction); end; end else ml := integer(start2 - ip); end; if LZ4HC_encodeSequence(@ip, @op, @anchor, ml, ref, limit, oend) <> 0 then exit(0); ip := start2; ref := ref2; ml := ml2; start2 := start3; ref2 := ref3; ml2 := ml3; goto _Search3; end; lastRun := integer(iend - anchor); if (limit <> noLimit) and ((op - pByte(dest)) + lastRun + 1 + ((lastRun + 255 - RUN_MASK) div 255) > maxOutputSize) then exit(0); if lastRun >= integer(RUN_MASK) then begin op^ := RUN_MASK shl ML_BITS; inc(op); dec(lastRun, RUN_MASK); while lastRun > 254 do begin op^ := 255; inc(op); dec(lastRun, 255); end; op^ := byte(lastRun); inc(op); end else begin op^ := byte(lastRun shl ML_BITS); inc(op); end; move(anchor^, op^, iend - anchor); inc(op, iend - anchor); result := integer(op - pByte(dest)); end; function LZ4_compressHC2(const source: pAnsiChar; dest: pAnsiChar; inputSize: integer; compressionLevel: integer): integer; var ctx: LZ4HC_Data_Structure; begin fillchar(ctx, sizeof(LZ4HC_Data_Structure), 0); LZ4HC_init(@ctx, pByte(source)); result := LZ4HC_compress_generic(@ctx, source, dest, inputSize, 0, compressionLevel, noLimit); end; function LZ4_compressHC(source: pAnsiChar; dest: pAnsiChar; inputSize: integer): integer; begin result := LZ4_compressHC2(source, dest, inputSize, 0); end; function LZ4_compressHC_limitedOutput(const source: pAnsiChar; dest: pAnsiChar; inputSize: integer; maxOutputSize: integer): integer; begin result := LZ4_compressHC2_limitedOutput(source, dest, inputSize, maxOutputSize, 0); end; function LZ4_compressHC2_limitedOutput(const source: pAnsiChar; dest: pAnsiChar; inputSize: integer; maxOutputSize: integer; compressionLevel: integer): integer; var ctx: LZ4HC_Data_Structure; begin fillchar(ctx, sizeof(LZ4HC_Data_Structure), 0); LZ4HC_init(@ctx, pByte(source)); result := LZ4HC_compress_generic(@ctx, source, dest, inputSize, maxOutputSize, compressionLevel, limitedOutput); end; function LZ4_compressHC_withStateHC(state: pointer; const source: pAnsiChar; dest: pAnsiChar; inputSize: integer): integer; begin result := LZ4_compressHC2_withStateHC(state, source, dest, inputSize, 0); end; function LZ4_compressHC2_withStateHC(state: pointer; const source: pAnsiChar; dest: pAnsiChar; inputSize: integer; compressionLevel: integer): integer; begin if (size_t(state) and (sizeof(pointer) - 1)) <> 0 then exit(0); // Error : : state is not aligned for pointers (32 or 64 bits) */ LZ4HC_init(PLZ4HC_Data_Structure(state), pByte(source)); result := LZ4HC_compress_generic(state, source, dest, inputSize, 0, compressionLevel, noLimit); end; function LZ4_compressHC_limitedOutput_withStateHC(state: pointer; const source: pAnsiChar; dest: pAnsiChar; inputSize: integer; maxOutputSize: integer): integer; begin result := LZ4_compressHC2_limitedOutput_withStateHC(state, source, dest, inputSize, maxOutputSize, 0); end; function LZ4_compressHC2_limitedOutput_withStateHC(state: pointer; const source: pAnsiChar; dest: pAnsiChar; inputSize: integer; maxOutputSize: integer; compressionLevel: integer): integer; begin if (size_t(state) and (sizeof(pointer) - 1)) <> 0 then exit(0); // Error : : state is not aligned for pointers (32 or 64 bits) */ LZ4HC_init(PLZ4HC_Data_Structure(state), pByte(source)); result := LZ4HC_compress_generic(state, source, dest, inputSize, maxOutputSize, compressionLevel, limitedOutput); end; function LZ4_createHC(inputBuffer: pAnsiChar): pointer; var hc4: pointer; begin hc4 := allocmem(sizeof(LZ4HC_Data_Structure)); LZ4HC_init(PLZ4HC_Data_Structure(hc4), pByte(inputBuffer)); result := hc4; end; procedure LZ4HC_setExternalDict(ctxPtr: PLZ4HC_Data_Structure; const newBlock: pByte); begin if ctxPtr._end >= ctxPtr.base + 4 then LZ4HC_Insert(ctxPtr, ctxPtr._end - 3); // Referencing remaining dictionary content // Only one memory segment for extDict, so any previous extDict is lost at this stage ctxPtr.lowLimit := ctxPtr.dictLimit; ctxPtr.dictLimit := cardinal(ctxPtr._end - ctxPtr.base); ctxPtr.dictBase := ctxPtr.base; ctxPtr.base := newBlock - ctxPtr.dictLimit; ctxPtr._end := newBlock; ctxPtr.nextToUpdate := ctxPtr.dictLimit; // match referencing will resume from there end; function LZ4_compressHC_continue_generic(ctxPtr: PLZ4HC_Data_Structure; const source: pAnsiChar; dest: pAnsiChar; inputSize: integer; maxOutputSize: integer; limit: limitedOutput_directive): integer; var dictSize: size_t; sourceEnd: pByte; dictBegin: pByte; dictEnd: pByte; begin // auto-init if forgotten if (ctxPtr.base = Nil) then LZ4HC_init(ctxPtr, pByte(source)); // Check overflow if size_t(ctxPtr._end - ctxPtr.base) > 2147483648 then begin dictSize := size_t(ctxPtr._end - ctxPtr.base) - ctxPtr.dictLimit; if (dictSize > 65536) then dictSize := 65536; LZ4_loadDictHC(PLZ4_streamHC_t(ctxPtr), pAnsiChar(ctxPtr._end) - dictSize, integer(dictSize)); end; // Check if blocks follow each other if (pByte(source) <> ctxPtr._end) then LZ4HC_setExternalDict(ctxPtr, pByte(source)); // Check overlapping input/dictionary space sourceEnd := pByte(source) + inputSize; dictBegin := ctxPtr.dictBase + ctxPtr.lowLimit; dictEnd := ctxPtr.dictBase + ctxPtr.dictLimit; if (sourceEnd > dictBegin) and (pByte(source) < dictEnd) then begin if sourceEnd > dictEnd then sourceEnd := dictEnd; ctxPtr.lowLimit := cardinal(sourceEnd - ctxPtr.dictBase); if ctxPtr.dictLimit - ctxPtr.lowLimit < 4 then ctxPtr.lowLimit := ctxPtr.dictLimit; end; result := LZ4HC_compress_generic(ctxPtr, source, dest, inputSize, maxOutputSize, ctxPtr.compressionLevel, limit); end; function LZ4_compressHC_continue(LZ4_streamHCPtr: PLZ4_streamHC_t; const source: pAnsiChar; dest: pAnsiChar; inputSize: integer): integer; begin result := LZ4_compressHC_continue_generic(PLZ4HC_Data_Structure(LZ4_streamHCPtr), source, dest, inputSize, 0, noLimit); end; function LZ4_loadDictHC(LZ4_streamHCPtr: PLZ4_streamHC_t; dictionary: pAnsiChar; dictSize: integer): integer; var ctxPtr: PLZ4HC_Data_Structure; begin ctxPtr := PLZ4HC_Data_Structure(LZ4_streamHCPtr); if dictSize > 65536 then begin inc(dictionary, dictSize - 65536); dictSize := 65536; end; LZ4HC_init(ctxPtr, pByte(dictionary)); if (dictSize >= 4) then LZ4HC_Insert(ctxPtr, pByte(dictionary) + (dictSize - 3)); ctxPtr._end := pByte(dictionary) + dictSize; result := dictSize; end; function LZ4_compressHC_limitedOutput_continue(LZ4_streamHCPtr: PLZ4_streamHC_t; const source: pAnsiChar; dest: pAnsiChar; inputSize: integer; maxOutputSize: integer): integer; begin result := LZ4_compressHC_continue_generic(PLZ4HC_Data_Structure(LZ4_streamHCPtr), source, dest, inputSize, maxOutputSize, limitedOutput); end; procedure LZ4_resetStreamHC(LZ4_streamHCPtr: PLZ4_streamHC_t; compressionLevel: integer); begin PLZ4HC_Data_Structure(LZ4_streamHCPtr).base := Nil; PLZ4HC_Data_Structure(LZ4_streamHCPtr).compressionLevel := cardinal(compressionLevel); end; function LZ4_saveDictHC(LZ4_streamHCPtr: PLZ4_streamHC_t; safeBuffer: pAnsiChar; dictSize: integer): integer; var streamPtr: PLZ4HC_Data_Structure; prefixSize: integer; endIndex: cardinal; begin streamPtr := PLZ4HC_Data_Structure(LZ4_streamHCPtr); prefixSize := integer((streamPtr._end - (streamPtr.base + streamPtr.dictLimit))); if dictSize > 65536 then dictSize := 65536; if dictSize < 4 then dictSize := 0; if (dictSize > prefixSize) then dictSize := prefixSize; move((streamPtr._end - dictSize)^, safeBuffer^, dictSize); endIndex := cardinal(streamPtr._end - streamPtr.base); streamPtr._end := pByte(safeBuffer) + dictSize; streamPtr.base := streamPtr._end - endIndex; streamPtr.dictLimit := endIndex - cardinal(dictSize); streamPtr.lowLimit := endIndex - cardinal(dictSize); if streamPtr.nextToUpdate < streamPtr.dictLimit then streamPtr.nextToUpdate := streamPtr.dictLimit; result:=dictSize; end; end. ================================================ FILE: lib/xedit/lz4/lz4frame.pas ================================================ (* LZ4Delphi Copyright (C) 2015, Jose Pascoa (atelierwebgm@gmail.com) BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) ************************************************************************* LZ4 - Fast LZ compression algorithm xxHash - Fast Hash algorithm LZ4 source repository : http://code.google.com/p/lz4/ xxHash source repository : http://code.google.com/p/xxhash/ Copyright (c) 2011-2014, Yann Collet BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************************** *) unit lz4frame; {$POINTERMATH ON} interface uses Windows, xxHash, lz4frame_static, lz4, lz4HC, lz4common; const LZ4F_VERSION = 100; LZ4F_MAGICNUMBER = $184D2204; _1BIT = $01; _2BITS = $03; _3BITS = $07; _4BITS = $0F; _8BITS = $FF; LZ4F_BLOCKUNCOMPRESSED_FLAG: cardinal = $80000000; type LZ4F_errorCode_t = size_t; PLZ4F_decompressionContext_t = pointer; PLZ4F_compressionContext_t = pointer; blockSizeID_t = (LZ4F_default = 0, max64KB = 4, max256KB = 5, max1MB = 6, max4MB = 7); blockMode_t = (blockLinked = 0, blockIndependent); contentChecksum_t = (noContentChecksum = 0, contentChecksumEnabled); LZ4F_lastBlockStatus = (notDone, fromTmpBuffer, fromSrcBuffer); PLZ4F_frameInfo_t = ^LZ4F_frameInfo_t; LZ4F_frameInfo_t = record blockSizeID: blockSizeID_t; blockMode: blockMode_t; contentChecksumFlag: contentChecksum_t; reserved: array [0 .. 4] of cardinal; end; PLZ4F_preferences_t = ^LZ4F_preferences_t; LZ4F_preferences_t = record frameInfo: LZ4F_frameInfo_t; compressionLevel: cardinal; autoFlush: cardinal; reserved: array [0 .. 3] of cardinal; end; PLZ4F_compressOptions_t = ^LZ4F_compressOptions_t; LZ4F_compressOptions_t = record stableSrc: cardinal; reserved: array [0 .. 2] of cardinal; end; PLZ4F_cctx_internal_t = ^LZ4F_cctx_internal_t; LZ4F_cctx_internal_t = record prefs: LZ4F_preferences_t; version: cardinal; cStage: cardinal; maxBlockSize: size_t; maxBufferSize: size_t; tmpBuff: pByte; tmpIn: pByte; tmpInSize: size_t; xxh: XXH32_state_t; lz4CtxPtr: pointer; lz4CtxLevel: cardinal; end; PLZ4F_dctx_internal_t = ^LZ4F_dctx_internal_t; LZ4F_dctx_internal_t = record frameInfo: LZ4F_frameInfo_t; version: cardinal; dStage: cardinal; maxBlockSize: size_t; maxBufferSize: size_t; srcExpect: pByte; tmpIn: pByte; tmpInSize: size_t; tmpInTarget: size_t; tmpOutBuffer: pByte; dict: pByte; dictSize: size_t; tmpOut: pByte; tmpOutSize: size_t; tmpOutStart: size_t; xxh: XXH32_state_t; header: array [0 .. 7] of byte; end; PLZ4F_decompressOptions_t = ^LZ4F_decompressOptions_t; LZ4F_decompressOptions_t = record stableDst: cardinal; reserved: array [0 .. 2] of cardinal; end; const LZ4F_BLOCKSIZEID_DEFAULT = max64KB; LZ4F_MAXHEADERFRAME_SIZE = 7; function LZ4F_createDecompressionContext(var LZ4F_decompressionContextPtr: PLZ4F_compressionContext_t; versionNumber: cardinal) : LZ4F_errorCode_t; function LZ4F_isError(code: LZ4F_errorCode_t): boolean; function LZ4F_compressFrame(dstBuffer: pointer; dstMaxSize: size_t; const srcBuffer: pointer; srcSize: size_t; const preferencesPtr: PLZ4F_preferences_t): size_t; function LZ4F_compressBound(srcSize: size_t; const preferencesPtr: PLZ4F_preferences_t): size_t; function LZ4F_compressFrameBound(srcSize: size_t; const preferencesPtr: PLZ4F_preferences_t): size_t; function LZ4F_compressBegin(compressionContext: PLZ4F_compressionContext_t; dstBuffer: pointer; dstMaxSize: size_t; preferencesPtr: PLZ4F_preferences_t): size_t; function LZ4F_compressUpdate(compressionContext: PLZ4F_compressionContext_t; dstBuffer: pointer; dstMaxSize: size_t; const srcBuffer: pointer; srcSize: size_t; compressOptionsPtr: PLZ4F_compressOptions_t): size_t; function LZ4F_compressEnd(compressionContext: PLZ4F_compressionContext_t; dstBuffer: pointer; dstMaxSize: size_t; const compressOptionsPtr: PLZ4F_compressOptions_t): size_t; function LZ4F_flush(compressionContext: PLZ4F_compressionContext_t; dstBuffer: pointer; dstMaxSize: size_t; compressOptionsPtr: PLZ4F_compressOptions_t): size_t; function LZ4F_decompress(decompressionContext: PLZ4F_decompressionContext_t; dstBuffer: pointer; dstSizePtr: psize_t; const srcBuffer: pointer; srcSizePtr: psize_t; decompressOptionsPtr: PLZ4F_decompressOptions_t): size_t; function LZ4F_createCompressionContext(var LZ4F_compressionContextPtr: PLZ4F_compressionContext_t; version: cardinal): LZ4F_errorCode_t; function LZ4F_freeCompressionContext(LZ4F_compressionContext: PLZ4F_compressionContext_t): LZ4F_errorCode_t; function LZ4F_getFrameInfo(decompressionContext: PLZ4F_decompressionContext_t; frameInfoPtr: PLZ4F_frameInfo_t; const srcBuffer: pointer; srcSizePtr: psize_t): LZ4F_errorCode_t; function LZ4F_freeDecompressionContext(LZ4F_decompressionContext: PLZ4F_decompressionContext_t): LZ4F_errorCode_t; function LZ4F_getErrorName(code : LZ4F_errorCode_t ): pAnsiChar; implementation var minHClevel: cardinal = 3; type dStage_t = (dstage_getHeader = 0, dstage_storeHeader, dstage_decodeHeader, dstage_getCBlockSize, dstage_storeCBlockSize, dstage_decodeCBlockSize, dstage_copyDirect, dstage_getCBlock, dstage_storeCBlock, dstage_decodeCBlock, dstage_decodeCBlock_intoDst, dstage_decodeCBlock_intoTmp, dstage_flushOut, dstage_getSuffix, dstage_storeSuffix, dstage_checkSuffix); function LZ4F_getBlockSize(blockSizeID: cardinal): size_t; forward; function LZ4F_createDecompressionContext(var LZ4F_decompressionContextPtr: PLZ4F_compressionContext_t; versionNumber: cardinal) : LZ4F_errorCode_t; var dctxPtr: PLZ4F_dctx_internal_t; begin dctxPtr := allocmem(sizeof(LZ4F_dctx_internal_t)); if dctxPtr = nil then exit(LZ4F_errorCode_t(-integer(ERROR_GENERIC))); dctxPtr.version := versionNumber; LZ4F_decompressionContextPtr := dctxPtr; result := LZ4F_errorCode_t(OK_NoError); end; function LZ4F_isError(code: LZ4F_errorCode_t): boolean; begin result := code > LZ4F_errorCode_t(-integer(ERROR_maxCode)); end; function LZ4F_getErrorName(code : LZ4F_errorCode_t ): pAnsiChar; begin result:= 'Unspecified error code'; if LZ4F_isError(code) then exit (pAnsiChar(LZ4F_errorStrings[-integer(code)])); end; function LZ4F_compressFrameBound(srcSize: size_t; const preferencesPtr: PLZ4F_preferences_t): size_t; var prefs: LZ4F_preferences_t; headerSize: size_t; streamSize: size_t; proposedBSID: blockSizeID_t; maxBlockSize: size_t; begin fillchar(prefs, sizeof(LZ4F_preferences_t), 0); if (preferencesPtr <> Nil) then prefs := preferencesPtr^; proposedBSID := max64KB; maxBlockSize := 65536; while (prefs.frameInfo.blockSizeID > proposedBSID) do begin if srcSize <= maxBlockSize then begin prefs.frameInfo.blockSizeID := proposedBSID; break; end; inc(proposedBSID); maxBlockSize := maxBlockSize shl 2; end; prefs.autoFlush := 1; headerSize := 7; // basic header size (no option) including magic number streamSize := LZ4F_compressBound(srcSize, @prefs); result := headerSize + streamSize; end; function LZ4F_compressFrame(dstBuffer: pointer; dstMaxSize: size_t; const srcBuffer: pointer; srcSize: size_t; const preferencesPtr: PLZ4F_preferences_t): size_t; var cctxI: LZ4F_cctx_internal_t; prefs: LZ4F_preferences_t; options: LZ4F_compressOptions_t; errorCode: LZ4F_errorCode_t; dstStart: pByte; dstPtr: pByte; dstEnd: pByte; proposedBSID: blockSizeID_t; maxBlockSize: size_t; begin fillchar(cctxI, sizeof(LZ4F_cctx_internal_t), 0); fillchar(prefs, sizeof(LZ4F_preferences_t), 0); fillchar(options, sizeof(LZ4F_compressOptions_t), 0); dstStart := pByte(dstBuffer); dstPtr := dstStart; dstEnd := dstStart + dstMaxSize; cctxI.version := LZ4F_VERSION; cctxI.maxBufferSize := 5 * 1048576; if (preferencesPtr <> Nil) then prefs := preferencesPtr^; proposedBSID := max64KB; maxBlockSize := 65536; while (prefs.frameInfo.blockSizeID > proposedBSID) do begin if (srcSize <= maxBlockSize) then begin prefs.frameInfo.blockSizeID := proposedBSID; break; end; inc(proposedBSID); maxBlockSize := maxBlockSize shl 2; end; prefs.autoFlush := 1; if (srcSize <= LZ4F_getBlockSize(cardinal(prefs.frameInfo.blockSizeID))) then prefs.frameInfo.blockMode := blockIndependent; // no need for linked blocks options.stableSrc := 1; if (dstMaxSize < LZ4F_compressFrameBound(srcSize, @prefs)) then exit(size_t(-integer(ERROR_dstMaxSize_tooSmall))); errorCode := LZ4F_compressBegin(@cctxI, dstBuffer, dstMaxSize, @prefs); // write header if (LZ4F_isError(errorCode)) then exit(errorCode); inc(dstPtr, errorCode); // header size dec(dstMaxSize, errorCode); errorCode := LZ4F_compressUpdate(@cctxI, dstPtr, dstMaxSize, srcBuffer, srcSize, @options); if (LZ4F_isError(errorCode)) then exit(errorCode); inc(dstPtr, errorCode); errorCode := LZ4F_compressEnd(@cctxI, dstPtr, dstEnd - dstPtr, @options); // flush last block, and generate suffix if LZ4F_isError(errorCode) then exit(errorCode); inc(dstPtr, errorCode); freemem(cctxI.lz4CtxPtr); result := dstPtr - dstStart; end; function LZ4F_getBlockSize(blockSizeID: cardinal): size_t; const blockSizes: array [0 .. 3] of size_t = (65536, 4 * 65536, 16 * 65536, 64 * 65536); begin if (blockSizeID = 0) then blockSizeID := cardinal(LZ4F_BLOCKSIZEID_DEFAULT); dec(blockSizeID, 4); if (blockSizeID > 3) then exit(size_t(-integer(ERROR_maxBlockSize_invalid))); result := blockSizes[blockSizeID]; end; function LZ4F_compressBound(srcSize: size_t; const preferencesPtr: PLZ4F_preferences_t): size_t; var prefsNull: LZ4F_preferences_t; prefsPtr: PLZ4F_preferences_t; bid: blockSizeID_t; blockSize: size_t; nbBlocks: cardinal; lastBlockSize: size_t; blockInfo: size_t; frameEnd: size_t; begin fillchar(prefsNull, sizeof(LZ4F_preferences_t), 0); if preferencesPtr = Nil then prefsPtr := @prefsNull else prefsPtr := preferencesPtr; bid := prefsPtr.frameInfo.blockSizeID; blockSize := LZ4F_getBlockSize(cardinal(bid)); nbBlocks := cardinal(srcSize div blockSize) + 1; if prefsPtr.autoFlush <> 0 then lastBlockSize := srcSize mod blockSize else lastBlockSize := blockSize; blockInfo := 4; // default, without block CRC option frameEnd := 4 + (cardinal(prefsPtr.frameInfo.contentChecksumFlag) * 4); result := (blockInfo * nbBlocks) + (blockSize * (nbBlocks - 1)) + lastBlockSize + frameEnd; end; procedure LZ4F_writeLE32(dstPtr: pByte; value32: cardinal); begin dstPtr[0] := byte(value32); dstPtr[1] := byte(value32 shr 8); dstPtr[2] := byte(value32 shr 16); dstPtr[3] := byte(value32 shr 24); end; function LZ4F_headerChecksum(const header: pByte; length: size_t): byte; var xxh: cardinal; begin xxh := XXH32(header, cardinal(length), 0); result := byte(xxh shr 8); end; function LZ4F_compressBegin(compressionContext: PLZ4F_compressionContext_t; dstBuffer: pointer; dstMaxSize: size_t; preferencesPtr: PLZ4F_preferences_t): size_t; var prefNull: LZ4F_preferences_t; cctxPtr: PLZ4F_cctx_internal_t; dstStart: pByte; dstPtr: pByte; headerStart: pByte; requiredBuffSize: size_t; targetCtxLevel: cardinal; begin fillchar(prefNull, sizeof(LZ4F_preferences_t), 0); cctxPtr := PLZ4F_cctx_internal_t(compressionContext); dstStart := pByte(dstBuffer); dstPtr := dstStart; if (dstMaxSize < LZ4F_MAXHEADERFRAME_SIZE) then exit(size_t(-integer(ERROR_dstMaxSize_tooSmall))); if (cctxPtr.cStage <> 0) then exit(size_t(-integer(ERROR_GENERIC))); if (preferencesPtr = Nil) then preferencesPtr := @prefNull; cctxPtr.prefs := preferencesPtr^; // ctx Management if cctxPtr.prefs.compressionLevel < minHClevel then targetCtxLevel := 1 else targetCtxLevel := 2; if cctxPtr.lz4CtxLevel < targetCtxLevel then begin freemem(cctxPtr.lz4CtxPtr); if (cctxPtr.prefs.compressionLevel < minHClevel) then cctxPtr.lz4CtxPtr := LZ4_createStream() else cctxPtr.lz4CtxPtr := LZ4_createStreamHC(); cctxPtr.lz4CtxLevel := targetCtxLevel; end; // Buffer Management if cardinal(cctxPtr.prefs.frameInfo.blockSizeID) = 0 then cctxPtr.prefs.frameInfo.blockSizeID := LZ4F_BLOCKSIZEID_DEFAULT; cctxPtr.maxBlockSize := LZ4F_getBlockSize(cardinal(cctxPtr.prefs.frameInfo.blockSizeID)); requiredBuffSize := cctxPtr.maxBlockSize + (cardinal(cctxPtr.prefs.frameInfo.blockMode = blockLinked) * 131072); if preferencesPtr.autoFlush <> 0 then requiredBuffSize := cardinal(cctxPtr.prefs.frameInfo.blockMode = blockLinked) * 65536; // just needs dict if (cctxPtr.maxBufferSize < requiredBuffSize) then begin cctxPtr.maxBufferSize := requiredBuffSize; freemem(cctxPtr.tmpBuff); cctxPtr.tmpBuff := allocmem(requiredBuffSize); if (cctxPtr.tmpBuff = Nil) then exit(size_t(-integer(ERROR_allocation_failed))); end; cctxPtr.tmpIn := cctxPtr.tmpBuff; cctxPtr.tmpInSize := 0; XXH32_reset(@cctxPtr.xxh, 0); if cctxPtr.prefs.compressionLevel < minHClevel then LZ4_resetStream(PLZ4_stream_t(cctxPtr.lz4CtxPtr)) else LZ4_resetStreamHC(cctxPtr.lz4CtxPtr, cctxPtr.prefs.compressionLevel); // Magic Number LZ4F_writeLE32(dstPtr, LZ4F_MAGICNUMBER); inc(dstPtr, 4); headerStart := dstPtr; // FLG Byte dstPtr^ := ((1 and _2BITS) shl 6) // Version('01') + ((cardinal(cctxPtr.prefs.frameInfo.blockMode) and _1BIT) shl 5) // Block mode + byte((cardinal(cctxPtr.prefs.frameInfo.contentChecksumFlag) and _1BIT) shl 2); // Stream checksum inc(dstPtr); // BD Byte dstPtr^ := byte((cardinal(cctxPtr.prefs.frameInfo.blockSizeID) and _3BITS) shl 4); inc(dstPtr); // *CRC Byte dstPtr^ := LZ4F_headerChecksum(headerStart, 2); inc(dstPtr); cctxPtr.cStage := 1; // header written, wait for data block result := dstPtr - dstStart; end; type compressFunc_t = function(ctx: pointer; const src: pAnsiChar; dst: pAnsiChar; srcSize: integer; dstSize: integer; level: integer): integer; function LZ4F_localLZ4_compress_limitedOutput_withState(ctx: pointer; const src: pAnsiChar; dst: pAnsiChar; srcSize: integer; dstSize: integer; level: integer): integer; begin result := LZ4_compress_limitedOutput_withState(ctx, src, dst, srcSize, dstSize); end; function LZ4F_localLZ4_compress_limitedOutput_continue(ctx: pointer; const src: pAnsiChar; dst: pAnsiChar; srcSize: integer; dstSize: integer; level: integer): integer; begin result := LZ4_compress_limitedOutput_continue(PLZ4_stream_t(ctx), src, dst, srcSize, dstSize); end; function LZ4F_localLZ4_compressHC_limitedOutput_continue(ctx: pointer; const src: pAnsiChar; dst: pAnsiChar; srcSize: integer; dstSize: integer; level: integer): integer; begin result := LZ4_compressHC_limitedOutput_continue(PLZ4_streamHC_t(ctx), src, dst, srcSize, dstSize); end; function LZ4F_localSaveDict(cctxPtr: PLZ4F_cctx_internal_t): integer; begin if cctxPtr.prefs.compressionLevel < minHClevel then result := LZ4_saveDict(PLZ4_stream_t(cctxPtr.lz4CtxPtr), pAnsiChar(cctxPtr.tmpBuff), 65536) else result := LZ4_saveDictHC(PLZ4_streamHC_t(cctxPtr.lz4CtxPtr), pAnsiChar(cctxPtr.tmpBuff), 65536); end; function LZ4F_selectCompression(blockMode: blockMode_t; level: cardinal): compressFunc_t; begin if level < minHClevel then begin if (blockMode = blockIndependent) then exit(@LZ4F_localLZ4_compress_limitedOutput_withState); exit(@LZ4F_localLZ4_compress_limitedOutput_continue); end; if (blockMode = blockIndependent) then exit(@LZ4_compressHC2_limitedOutput_withStateHC); exit(@LZ4F_localLZ4_compressHC_limitedOutput_continue); end; function LZ4F_compressBlock(dst: pointer; const src: pointer; srcSize: size_t; compress: compressFunc_t; lz4ctx: pointer; level: integer): integer; var cSizePtr: pByte; cSize: cardinal; begin cSizePtr := dst; cSize := cardinal(compress(lz4ctx, src, pAnsiChar(cSizePtr + 4), integer(srcSize), integer(srcSize - 1), level)); LZ4F_writeLE32(cSizePtr, cSize); if (cSize = 0) then // compression failed begin cSize := srcSize; LZ4F_writeLE32(cSizePtr, cSize + LZ4F_BLOCKUNCOMPRESSED_FLAG); move(src^, (cSizePtr + 4)^, srcSize); end; result := cSize + 4; end; function LZ4F_compressUpdate(compressionContext: PLZ4F_compressionContext_t; dstBuffer: pointer; dstMaxSize: size_t; const srcBuffer: pointer; srcSize: size_t; compressOptionsPtr: PLZ4F_compressOptions_t): size_t; var cOptionsNull: LZ4F_compressOptions_t; cctxPtr: PLZ4F_cctx_internal_t; blockSize: size_t; srcPtr: pByte; srcEnd: pByte; dstStart: pByte; dstPtr: pByte; lastBlockCompressed: LZ4F_lastBlockStatus; compress: compressFunc_t; sizeToCopy: size_t; realDictSize: integer; begin fillchar(cOptionsNull, sizeof(LZ4F_compressOptions_t), 0); cctxPtr := PLZ4F_cctx_internal_t(compressionContext); blockSize := cctxPtr.maxBlockSize; srcPtr := srcBuffer; srcEnd := srcPtr + srcSize; dstStart := dstBuffer; dstPtr := dstStart; lastBlockCompressed := notDone; if cctxPtr.cStage <> 1 then exit(size_t(-integer(ERROR_GENERIC))); if dstMaxSize < LZ4F_compressBound(srcSize, @(cctxPtr.prefs)) then exit(size_t(-integer(ERROR_dstMaxSize_tooSmall))); if compressOptionsPtr = Nil then compressOptionsPtr := @cOptionsNull; // select compression function compress := LZ4F_selectCompression(cctxPtr.prefs.frameInfo.blockMode, cctxPtr.prefs.compressionLevel); // complete tmp buffer if cctxPtr.tmpInSize > 0 then // some data already within tmp buffer begin sizeToCopy := blockSize - cctxPtr.tmpInSize; if sizeToCopy > srcSize then begin // add src to tmpIn buffer move(srcBuffer^, (cctxPtr.tmpIn + cctxPtr.tmpInSize)^, srcSize); srcPtr := srcEnd; inc(cctxPtr.tmpInSize, srcSize); // still needs some CRC end else begin // complete tmpIn block and then compress it lastBlockCompressed := fromTmpBuffer; move(srcBuffer^, (cctxPtr.tmpIn + cctxPtr.tmpInSize)^, sizeToCopy); inc(srcPtr, sizeToCopy); inc(dstPtr, LZ4F_compressBlock(dstPtr, cctxPtr.tmpIn, blockSize, compress, cctxPtr.lz4CtxPtr, cctxPtr.prefs.compressionLevel)); if (cctxPtr.prefs.frameInfo.blockMode = blockLinked) then inc(cctxPtr.tmpIn, blockSize); cctxPtr.tmpInSize := 0; end; end; while size_t(srcEnd - srcPtr) >= blockSize do begin // compress full block lastBlockCompressed := fromSrcBuffer; inc(dstPtr, LZ4F_compressBlock(dstPtr, srcPtr, blockSize, compress, cctxPtr.lz4CtxPtr, cctxPtr.prefs.compressionLevel)); inc(srcPtr, blockSize); end; if ((cctxPtr.prefs.autoFlush <> 0) and (srcPtr < srcEnd)) then begin // compress remaining input < blockSize lastBlockCompressed := fromSrcBuffer; inc(dstPtr, LZ4F_compressBlock(dstPtr, srcPtr, srcEnd - srcPtr, compress, cctxPtr.lz4CtxPtr, cctxPtr.prefs.compressionLevel)); srcPtr := srcEnd; end; // preserve dictionary if necessary if ((cctxPtr.prefs.frameInfo.blockMode = blockLinked) and (lastBlockCompressed = fromSrcBuffer)) then begin if compressOptionsPtr.stableSrc <> 0 then cctxPtr.tmpIn := cctxPtr.tmpBuff else begin realDictSize := LZ4F_localSaveDict(cctxPtr); if (realDictSize = 0) then exit(size_t(-integer(ERROR_GENERIC))); cctxPtr.tmpIn := cctxPtr.tmpBuff + realDictSize; end; end; // keep tmpIn within limits if ((cctxPtr.tmpIn + blockSize) > (cctxPtr.tmpBuff + cctxPtr.maxBufferSize)) // necessarily blockLinked && lastBlockCompressed==fromTmpBuffer and (cctxPtr.prefs.autoFlush = 0) then begin LZ4F_localSaveDict(cctxPtr); cctxPtr.tmpIn := cctxPtr.tmpBuff + 65536; end; // some input data left, necessarily < blockSize if srcPtr < srcEnd then begin // fill tmp buffer sizeToCopy := srcEnd - srcPtr; move(srcPtr^, (cctxPtr.tmpIn)^, sizeToCopy); cctxPtr.tmpInSize := sizeToCopy; end; if (cctxPtr.prefs.frameInfo.contentChecksumFlag = contentChecksumEnabled) then XXH32_update(@(cctxPtr.xxh), srcBuffer, cardinal(srcSize)); result := dstPtr - dstStart; end; function LZ4F_flush(compressionContext: PLZ4F_compressionContext_t; dstBuffer: pointer; dstMaxSize: size_t; compressOptionsPtr: PLZ4F_compressOptions_t): size_t; var cOptionsNull: LZ4F_compressOptions_t; cctxPtr: PLZ4F_cctx_internal_t; dstStart: pByte; dstPtr: pByte; compress: compressFunc_t; begin fillchar(cOptionsNull, sizeof(LZ4F_compressOptions_t), 0); cctxPtr := PLZ4F_cctx_internal_t(compressionContext); dstStart := pByte(dstBuffer); dstPtr := dstStart; if cctxPtr.tmpInSize = 0 then exit(0); // nothing to flush if cctxPtr.cStage <> 1 then exit(size_t(-integer(ERROR_GENERIC))); if (dstMaxSize < (cctxPtr.tmpInSize + 16)) then exit(size_t(-integer(ERROR_dstMaxSize_tooSmall))); (* Not used if (compressOptionsPtr = Nil) then compressOptionsPtr := @cOptionsNull; *) // select compression function compress := LZ4F_selectCompression(cctxPtr.prefs.frameInfo.blockMode, cctxPtr.prefs.compressionLevel); // compress tmp buffer inc(dstPtr, LZ4F_compressBlock(dstPtr, cctxPtr.tmpIn, cctxPtr.tmpInSize, compress, cctxPtr.lz4CtxPtr, cctxPtr.prefs.compressionLevel)); if (cctxPtr.prefs.frameInfo.blockMode = blockLinked) then inc(cctxPtr.tmpIn, cctxPtr.tmpInSize); cctxPtr.tmpInSize := 0; // keep tmpIn within limits if ((cctxPtr.tmpIn + cctxPtr.maxBlockSize) > (cctxPtr.tmpBuff + cctxPtr.maxBufferSize)) then // necessarily blockLinked begin LZ4F_localSaveDict(cctxPtr); cctxPtr.tmpIn := cctxPtr.tmpBuff + 65536; end; result := dstPtr - dstStart; end; function LZ4F_compressEnd(compressionContext: PLZ4F_compressionContext_t; dstBuffer: pointer; dstMaxSize: size_t; const compressOptionsPtr: PLZ4F_compressOptions_t): size_t; var cctxPtr: PLZ4F_cctx_internal_t; dstStart: pByte; dstPtr: pByte; errorCode: size_t; xxh: cardinal; begin cctxPtr := PLZ4F_cctx_internal_t(compressionContext); dstStart := pByte(dstBuffer); dstPtr := dstStart; errorCode := LZ4F_flush(compressionContext, dstBuffer, dstMaxSize, compressOptionsPtr); if LZ4F_isError(errorCode) then exit(errorCode); inc(dstPtr, errorCode); LZ4F_writeLE32(dstPtr, 0); inc(dstPtr, 4); // endMark if cctxPtr.prefs.frameInfo.contentChecksumFlag = contentChecksumEnabled then begin xxh := XXH32_digest(@(cctxPtr.xxh)); LZ4F_writeLE32(dstPtr, xxh); inc(dstPtr, 4); // content Checksum end; cctxPtr.cStage := 0; // state is now re-usable (with identical preferences) result := dstPtr - dstStart; end; function LZ4F_readLE32(const srcPtr: pByte): cardinal; var value32: cardinal; begin value32 := srcPtr[0]; inc(value32, (srcPtr[1] shl 8)); inc(value32, (srcPtr[2] shl 16)); inc(value32, (srcPtr[3] shl 24)); result := value32; end; function LZ4F_decodeHeader(dctxPtr: PLZ4F_dctx_internal_t; srcPtr: pByte; srcSize: size_t): size_t; var FLG, BD, HC: byte; version, blockMode, blockChecksumFlag, contentSizeFlag, contentChecksumFlag, dictFlag, blockSizeID: cardinal; bufferNeeded: size_t; begin // need to decode header to get frameInfo if srcSize < 7 then exit(size_t(-integer(ERROR_GENERIC))); // minimal header size // control magic number if (LZ4F_readLE32(srcPtr) <> LZ4F_MAGICNUMBER) then exit(size_t(-integer(ERROR_GENERIC))); inc(srcPtr, 4); // Flags FLG := srcPtr[0]; version := (FLG shr 6) and _2BITS; blockMode := (FLG shr 5) and _1BIT; blockChecksumFlag := (FLG shr 4) and _1BIT; contentSizeFlag := (FLG shr 3) and _1BIT; contentChecksumFlag := (FLG shr 2) and _1BIT; dictFlag := (FLG shr 0) and _1BIT; BD := srcPtr[1]; blockSizeID := (BD shr 4) and _3BITS; // check HC := LZ4F_headerChecksum(srcPtr, 2); if (HC <> srcPtr[2]) then exit(size_t(-integer(ERROR_GENERIC))); // Bad header checksum error // validate if version <> 1 then exit(size_t(-integer(ERROR_GENERIC))); // Version Number, only supported value if blockChecksumFlag <> 0 then exit(size_t(-integer(ERROR_GENERIC))); // Only supported value for the time being if contentSizeFlag <> 0 then exit(size_t(-integer(ERROR_GENERIC))); // Only supported value for the time being if ((FLG shr 1) and _1BIT) <> 0 then exit(size_t(-integer(ERROR_GENERIC))); /// Reserved bit if dictFlag <> 0 then exit(size_t(-integer(ERROR_GENERIC))); // Only supported value for the time being if (BD shr 7) and _1BIT <> 0 then exit(size_t(-integer(ERROR_GENERIC))); /// Reserved bit if blockSizeID < 4 then exit(size_t(-integer(ERROR_GENERIC))); // Only supported values for the time being if (((BD shr 0) and _4BITS) <> 0) then exit(size_t(-integer(ERROR_GENERIC))); // Reserved bits // save dctxPtr.frameInfo.blockMode := blockMode_t(blockMode); dctxPtr.frameInfo.contentChecksumFlag := contentChecksum_t(contentChecksumFlag); dctxPtr.frameInfo.blockSizeID := blockSizeID_t(blockSizeID); dctxPtr.maxBlockSize := LZ4F_getBlockSize(blockSizeID); // init if (contentChecksumFlag <> 0) then XXH32_reset(@(dctxPtr.xxh), 0); // alloc bufferNeeded := dctxPtr.maxBlockSize + size_t (integer(dctxPtr.frameInfo.blockMode = blockLinked) * 131072); if bufferNeeded > dctxPtr.maxBufferSize then // tmp buffers too small begin freemem(dctxPtr.tmpIn); freemem(dctxPtr.tmpOutBuffer); dctxPtr.maxBufferSize := bufferNeeded; dctxPtr.tmpIn := allocmem(dctxPtr.maxBlockSize); if dctxPtr.tmpIn = Nil then exit(size_t(-integer(ERROR_GENERIC))); dctxPtr.tmpOutBuffer := allocmem(dctxPtr.maxBufferSize); if dctxPtr.tmpOutBuffer = Nil then exit(size_t(-integer(ERROR_GENERIC))); end; dctxPtr.tmpInSize := 0; dctxPtr.tmpInTarget := 0; dctxPtr.dict := dctxPtr.tmpOutBuffer; dctxPtr.dictSize := 0; dctxPtr.tmpOut := dctxPtr.tmpOutBuffer; dctxPtr.tmpOutStart := 0; dctxPtr.tmpOutSize := 0; result := 7; end; procedure LZ4F_updateDict(dctxPtr: PLZ4F_dctx_internal_t; const dstPtr: pByte; dstSize: size_t; const dstPtr0: pByte; withinTmp: cardinal); var preserveSize: size_t; copySize: size_t; oldDictEnd: pByte; begin if dctxPtr.dictSize = 0 then dctxPtr.dict := pByte(dstPtr); // priority to dictionary continuity if dctxPtr.dict + dctxPtr.dictSize = dstPtr then // dictionary continuity begin inc(dctxPtr.dictSize, dstSize); exit; end; if size_t(dstPtr - dstPtr0) + dstSize >= 65536 then // dstBuffer large enough to become dictionary begin dctxPtr.dict := pByte(dstPtr0); dctxPtr.dictSize := size_t(dstPtr - dstPtr0) + dstSize; exit; end; if ((withinTmp <> 0) and (dctxPtr.dict = dctxPtr.tmpOutBuffer)) then begin // assumption : dctxPtr->dict + dctxPtr->dictSize == dctxPtr->tmpOut + dctxPtr->tmpOutStart inc(dctxPtr.dictSize, dstSize); exit; end; if withinTmp <> 0 then // copy relevant dict portion in front of tmpOut within tmpOutBuffer begin preserveSize := dctxPtr.tmpOut - dctxPtr.tmpOutBuffer; copySize := 65536 - dctxPtr.tmpOutSize; oldDictEnd := dctxPtr.dict + dctxPtr.dictSize - dctxPtr.tmpOutStart; if dctxPtr.tmpOutSize > 65536 then copySize := 0; if copySize > preserveSize then copySize := preserveSize; move((oldDictEnd - copySize)^, (dctxPtr.tmpOutBuffer + preserveSize - copySize)^, copySize); dctxPtr.dict := dctxPtr.tmpOutBuffer; dctxPtr.dictSize := preserveSize + dctxPtr.tmpOutStart + dstSize; exit; end; if dctxPtr.dict = dctxPtr.tmpOutBuffer then // copy dst into tmp to complete dict begin if dctxPtr.dictSize + dstSize > dctxPtr.maxBufferSize then // tmp buffer not large enough begin preserveSize := 65536 - dstSize; // note : dstSize < 64 KB move((dctxPtr.dict + dctxPtr.dictSize - preserveSize)^, (dctxPtr.dict)^, preserveSize); dctxPtr.dictSize := preserveSize; end; move(dstPtr^, (dctxPtr.dict + dctxPtr.dictSize)^, dstSize); inc(dctxPtr.dictSize, dstSize); exit; end; // join dict & dest into tmp preserveSize := 65536 - dstSize; // note : dstSize < 64 KB if preserveSize > dctxPtr.dictSize then preserveSize := dctxPtr.dictSize; move((dctxPtr.dict + dctxPtr.dictSize - preserveSize)^, dctxPtr.tmpOutBuffer^, preserveSize); move(dstPtr^, (dctxPtr.tmpOutBuffer + preserveSize)^, dstSize); dctxPtr.dict := dctxPtr.tmpOutBuffer; dctxPtr.dictSize := preserveSize + dstSize; end; function LZ4F_decompress_safe(const source: pAnsiChar; dest: pAnsiChar; compressedSize: integer; maxDecompressedSize: integer; const dictStart: pAnsiChar; dictSize: integer): integer; begin result := LZ4_decompress_safe(source, dest, compressedSize, maxDecompressedSize); end; function LZ4F_decompress(decompressionContext: PLZ4F_decompressionContext_t; dstBuffer: pointer; dstSizePtr: psize_t; const srcBuffer: pointer; srcSizePtr: psize_t; decompressOptionsPtr: PLZ4F_decompressOptions_t): size_t; type Tdecoder = function(const c1: pAnsiChar; c2: pAnsiChar; c3: integer; c4: integer; const c5: pAnsiChar; c6: integer): integer; var dctxPtr: PLZ4F_dctx_internal_t; optionsNull: LZ4F_decompressOptions_t; srcStart: pByte; srcEnd: pByte; srcPtr: pByte; dstStart: pByte; dstEnd: pByte; dstPtr: pByte; selectedIn: pByte; doAnotherStage: cardinal; nextSrcSizeHint: size_t; sizeToCopy: size_t; errorCode: LZ4F_errorCode_t; nextCBlockSize: size_t; decodedSize: integer; decoder: Tdecoder; reservedDictSpace: size_t; suffixSize: size_t; readCRC: cardinal; resultCRC: cardinal; preserveSize: size_t; copySize: size_t; oldDictEnd: pByte; newDictSize: size_t; begin dctxPtr := PLZ4F_dctx_internal_t(decompressionContext); fillchar(optionsNull, sizeof(LZ4F_decompressOptions_t), 0); srcStart := pByte(srcBuffer); srcEnd := srcStart + srcSizePtr^; srcPtr := srcStart; dstStart := pByte(dstBuffer); dstEnd := dstStart + dstSizePtr^; dstPtr := dstStart; selectedIn := Nil; doAnotherStage := 1; nextSrcSizeHint := 1; if decompressOptionsPtr = Nil then decompressOptionsPtr := @optionsNull; srcSizePtr^ := 0; dstSizePtr^ := 0; // expect to continue decoding src buffer where it left previously if dctxPtr.srcExpect <> Nil then begin if (srcStart <> dctxPtr.srcExpect) then exit(size_t(-integer(ERROR_GENERIC))); end; // programmed as a state machine while (doAnotherStage <> 0) do begin case dctxPtr.dStage of cardinal(dstage_getHeader): begin if srcEnd - srcPtr >= 7 then begin selectedIn := srcPtr; inc(srcPtr, 7); dctxPtr.dStage := cardinal(dstage_decodeHeader); end else begin dctxPtr.tmpInSize := 0; dctxPtr.dStage := cardinal(dstage_storeHeader); end; end; cardinal(dstage_storeHeader): begin sizeToCopy := 7 - dctxPtr.tmpInSize; if sizeToCopy > size_t(srcEnd - srcPtr) then sizeToCopy := srcEnd - srcPtr; move(srcPtr^, (pByte(@dctxPtr.header) + dctxPtr.tmpInSize)^, sizeToCopy); inc(dctxPtr.tmpInSize, sizeToCopy); inc(srcPtr, sizeToCopy); if (dctxPtr.tmpInSize < 7) then begin nextSrcSizeHint := (7 - dctxPtr.tmpInSize) + 4; doAnotherStage := 0; // no enough src, wait to get some more end else begin selectedIn := @dctxPtr.header; dctxPtr.dStage := cardinal(dstage_decodeHeader); end; end; cardinal(dstage_decodeHeader): begin errorCode := LZ4F_decodeHeader(dctxPtr, selectedIn, 7); if LZ4F_isError(errorCode) then exit(errorCode); dctxPtr.dStage := cardinal(dstage_getCBlockSize); end; cardinal(dstage_getCBlockSize): begin if (srcEnd - srcPtr) >= 4 then begin selectedIn := srcPtr; inc(srcPtr, 4); dctxPtr.dStage := cardinal(dstage_decodeCBlockSize); end else begin // not enough input to read cBlockSize field dctxPtr.tmpInSize := 0; dctxPtr.dStage := cardinal(dstage_storeCBlockSize); end; end; cardinal(dstage_storeCBlockSize): begin sizeToCopy := 4 - dctxPtr.tmpInSize; if sizeToCopy > size_t(srcEnd - srcPtr) then sizeToCopy := srcEnd - srcPtr; move(srcPtr^, (dctxPtr.tmpIn + dctxPtr.tmpInSize)^, sizeToCopy); inc(srcPtr, sizeToCopy); inc(dctxPtr.tmpInSize, sizeToCopy); if dctxPtr.tmpInSize < 4 then // not enough input to get full cBlockSize; wait for more begin nextSrcSizeHint := 4 - dctxPtr.tmpInSize; doAnotherStage := 0; end else begin selectedIn := dctxPtr.tmpIn; dctxPtr.dStage := cardinal(dstage_decodeCBlockSize); end; end; cardinal(dstage_decodeCBlockSize): begin nextCBlockSize := LZ4F_readLE32(selectedIn) and $7FFFFFFF; if (nextCBlockSize = 0) then dctxPtr.dStage := cardinal(dstage_getSuffix) else begin if (nextCBlockSize > dctxPtr.maxBlockSize) then exit(size_t(-integer(ERROR_GENERIC))); // invalid cBlockSize dctxPtr.tmpInTarget := nextCBlockSize; if (LZ4F_readLE32(selectedIn) and LZ4F_BLOCKUNCOMPRESSED_FLAG) <> 0 then dctxPtr.dStage := cardinal(dstage_copyDirect) else begin dctxPtr.dStage := cardinal(dstage_getCBlock); if dstPtr = dstEnd then begin nextSrcSizeHint := nextCBlockSize + 4; doAnotherStage := 0; end; end; end; end; cardinal(dstage_copyDirect): // uncompressed block begin sizeToCopy := dctxPtr.tmpInTarget; if size_t(srcEnd - srcPtr) < sizeToCopy then sizeToCopy := srcEnd - srcPtr; // not enough input to read full block if size_t(dstEnd - dstPtr) < sizeToCopy then sizeToCopy := dstEnd - dstPtr; move(srcPtr^, dstPtr^, sizeToCopy); if (dctxPtr.frameInfo.contentChecksumFlag <> noContentChecksum) then XXH32_update(@(dctxPtr.xxh), srcPtr, cardinal(sizeToCopy)); // dictionary management if (dctxPtr.frameInfo.blockMode = blockLinked) then LZ4F_updateDict(dctxPtr, dstPtr, sizeToCopy, dstStart, 0); inc(srcPtr, sizeToCopy); inc(dstPtr, sizeToCopy); if sizeToCopy = dctxPtr.tmpInTarget then // all copied dctxPtr.dStage := cardinal(dstage_getCBlockSize) else begin dec(dctxPtr.tmpInTarget, sizeToCopy); // still need to copy more nextSrcSizeHint := dctxPtr.tmpInTarget + 4; doAnotherStage := 0; end; end; cardinal(dstage_getCBlock): begin if size_t(srcEnd - srcPtr) < dctxPtr.tmpInTarget then begin dctxPtr.tmpInSize := 0; dctxPtr.dStage := cardinal(dstage_storeCBlock); end else begin selectedIn := srcPtr; inc(srcPtr, dctxPtr.tmpInTarget); dctxPtr.dStage := cardinal(dstage_decodeCBlock); end; end; cardinal(dstage_storeCBlock): begin sizeToCopy := dctxPtr.tmpInTarget - dctxPtr.tmpInSize; if sizeToCopy > size_t(srcEnd - srcPtr) then sizeToCopy := srcEnd - srcPtr; move(srcPtr^, (dctxPtr.tmpIn + dctxPtr.tmpInSize)^, sizeToCopy); inc(dctxPtr.tmpInSize, sizeToCopy); inc(srcPtr, sizeToCopy); if (dctxPtr.tmpInSize < dctxPtr.tmpInTarget) then // need more input begin nextSrcSizeHint := (dctxPtr.tmpInTarget - dctxPtr.tmpInSize) + 4; doAnotherStage := 0; end else begin selectedIn := dctxPtr.tmpIn; dctxPtr.dStage := cardinal(dstage_decodeCBlock); end; end; cardinal(dstage_decodeCBlock): begin if (size_t(dstEnd - dstPtr) < dctxPtr.maxBlockSize) then // not enough place into dst : decode into tmpOut dctxPtr.dStage := cardinal(dstage_decodeCBlock_intoTmp) else dctxPtr.dStage := cardinal(dstage_decodeCBlock_intoDst); end; cardinal(dstage_decodeCBlock_intoDst): begin if (dctxPtr.frameInfo.blockMode = blockLinked) then decoder := LZ4_decompress_safe_usingDict else decoder := LZ4F_decompress_safe; decodedSize := decoder(pAnsiChar(selectedIn), pAnsiChar(dstPtr), integer(dctxPtr.tmpInTarget), integer(dctxPtr.maxBlockSize), pAnsiChar(dctxPtr.dict), integer(dctxPtr.dictSize)); if (decodedSize < 0) then exit(size_t(-integer(ERROR_GENERIC))); // decompression failed if (dctxPtr.frameInfo.contentChecksumFlag <> noContentChecksum) then XXH32_update(@(dctxPtr.xxh), dstPtr, decodedSize); // dictionary management if (dctxPtr.frameInfo.blockMode = blockLinked) then LZ4F_updateDict(dctxPtr, dstPtr, decodedSize, dstStart, 0); inc(dstPtr, decodedSize); dctxPtr.dStage := cardinal(dstage_getCBlockSize); end; cardinal(dstage_decodeCBlock_intoTmp): begin if (dctxPtr.frameInfo.blockMode = blockLinked) then decoder := LZ4_decompress_safe_usingDict else decoder := LZ4F_decompress_safe; // ensure enough place for tmpOut if dctxPtr.frameInfo.blockMode = blockLinked then begin if (dctxPtr.dict = dctxPtr.tmpOutBuffer) then begin if (dctxPtr.dictSize > 131072) then begin move((dctxPtr.dict + dctxPtr.dictSize - 65536)^, dctxPtr.dict^, 65536); dctxPtr.dictSize := 65536; end; dctxPtr.tmpOut := dctxPtr.dict + dctxPtr.dictSize; end else // dict not within tmp begin reservedDictSpace := dctxPtr.dictSize; if (reservedDictSpace > 65536) then reservedDictSpace := 65536; dctxPtr.tmpOut := dctxPtr.tmpOutBuffer + reservedDictSpace; end; end; // Decode decodedSize := decoder(pAnsiChar(selectedIn), pAnsiChar(dctxPtr.tmpOut), integer(dctxPtr.tmpInTarget), integer(dctxPtr.maxBlockSize), pAnsiChar(dctxPtr.dict), integer(dctxPtr.dictSize)); if decodedSize < 0 then exit(size_t(-integer(ERROR_decompressionFailed))); // decompression failed if (dctxPtr.frameInfo.contentChecksumFlag <> noContentChecksum) then XXH32_update(@(dctxPtr.xxh), dctxPtr.tmpOut, decodedSize); dctxPtr.tmpOutSize := decodedSize; dctxPtr.tmpOutStart := 0; dctxPtr.dStage := cardinal(dstage_flushOut); end; cardinal(dstage_flushOut): // flush decoded data from tmpOut to dstBuffer begin sizeToCopy := dctxPtr.tmpOutSize - dctxPtr.tmpOutStart; if (sizeToCopy > size_t(dstEnd - dstPtr)) then sizeToCopy := dstEnd - dstPtr; move((dctxPtr.tmpOut + dctxPtr.tmpOutStart)^, dstPtr^, sizeToCopy); // dictionary management if (dctxPtr.frameInfo.blockMode = blockLinked) then LZ4F_updateDict(dctxPtr, dstPtr, sizeToCopy, dstStart, 1); inc(dctxPtr.tmpOutStart, sizeToCopy); inc(dstPtr, sizeToCopy); // end of flush ? if (dctxPtr.tmpOutStart = dctxPtr.tmpOutSize) then dctxPtr.dStage := cardinal(dstage_getCBlockSize) else begin nextSrcSizeHint := 4; doAnotherStage := 0; // still some data to flush end; end; cardinal(dstage_getSuffix): begin suffixSize := cardinal(dctxPtr.frameInfo.contentChecksumFlag) * 4; if (suffixSize = 0) then // frame completed begin nextSrcSizeHint := 0; dctxPtr.dStage := cardinal(dstage_getHeader); doAnotherStage := 0; end else begin if ((srcEnd - srcPtr) >= 4) then // CRC present begin selectedIn := srcPtr; inc(srcPtr, 4); dctxPtr.dStage := cardinal(dstage_checkSuffix); end else begin dctxPtr.tmpInSize := 0; dctxPtr.dStage := cardinal(dstage_storeSuffix); end; end; end; cardinal(dstage_storeSuffix): begin sizeToCopy := 4 - dctxPtr.tmpInSize; if (sizeToCopy > size_t(srcEnd - srcPtr)) then sizeToCopy := srcEnd - srcPtr; move(srcPtr^, (dctxPtr.tmpIn + dctxPtr.tmpInSize)^, sizeToCopy); inc(srcPtr, sizeToCopy); inc(dctxPtr.tmpInSize, sizeToCopy); if (dctxPtr.tmpInSize < 4) then // not enough input to read complete suffix begin nextSrcSizeHint := 4 - dctxPtr.tmpInSize; doAnotherStage := 0; end else begin selectedIn := dctxPtr.tmpIn; dctxPtr.dStage := cardinal(dstage_checkSuffix); end; end; cardinal(dstage_checkSuffix): begin readCRC := LZ4F_readLE32(selectedIn); resultCRC := XXH32_digest(@(dctxPtr.xxh)); if (readCRC <> resultCRC) then exit(size_t(-integer(ERROR_checksum_invalid))); nextSrcSizeHint := 0; dctxPtr.dStage := cardinal(dstage_getHeader); doAnotherStage := 0; end; end; end; // preserve dictionary within tmp if necessary if (dctxPtr.frameInfo.blockMode = blockLinked) and (dctxPtr.dict <> dctxPtr.tmpOutBuffer) and (decompressOptionsPtr.stableDst = 0) and (cardinal(dctxPtr.dStage - 1) < cardinal(cardinal(dstage_getSuffix) - 1)) then begin if dctxPtr.dStage = cardinal(dstage_flushOut) then begin preserveSize := dctxPtr.tmpOut - dctxPtr.tmpOutBuffer; copySize := 65536 - dctxPtr.tmpOutSize; oldDictEnd := dctxPtr.dict + dctxPtr.dictSize - dctxPtr.tmpOutStart; if dctxPtr.tmpOutSize > 65536 then copySize := 0; if copySize > preserveSize then copySize := preserveSize; move((oldDictEnd - copySize)^, (dctxPtr.tmpOutBuffer + preserveSize - copySize)^, copySize); dctxPtr.dict := dctxPtr.tmpOutBuffer; dctxPtr.dictSize := preserveSize + dctxPtr.tmpOutStart; end else begin newDictSize := dctxPtr.dictSize; oldDictEnd := dctxPtr.dict + dctxPtr.dictSize; if newDictSize > 65536 then newDictSize := 65536; move((oldDictEnd - newDictSize)^, (dctxPtr.tmpOutBuffer)^, newDictSize); dctxPtr.dict := dctxPtr.tmpOutBuffer; dctxPtr.dictSize := newDictSize; dctxPtr.tmpOut := dctxPtr.tmpOutBuffer + newDictSize; end; end; if (srcPtr < srcEnd) then // function must be called again with following source data dctxPtr.srcExpect := srcPtr else dctxPtr.srcExpect := Nil; srcSizePtr^ := (srcPtr - srcStart); dstSizePtr^ := (dstPtr - dstStart); result := nextSrcSizeHint; end; function LZ4F_createCompressionContext(var LZ4F_compressionContextPtr: PLZ4F_compressionContext_t; version: cardinal): LZ4F_errorCode_t; var cctxPtr: PLZ4F_cctx_internal_t; begin cctxPtr := allocmem(sizeof(LZ4F_cctx_internal_t)); if cctxPtr = Nil then exit(LZ4F_errorCode_t(-integer(ERROR_allocation_failed))); cctxPtr.version := version; cctxPtr.cStage := 0; // Next stage : write header LZ4F_compressionContextPtr := PLZ4F_compressionContext_t(cctxPtr); result := cardinal(OK_NoError); end; function LZ4F_freeCompressionContext(LZ4F_compressionContext: PLZ4F_compressionContext_t): LZ4F_errorCode_t; var cctxPtr: PLZ4F_cctx_internal_t; begin cctxPtr := PLZ4F_cctx_internal_t(LZ4F_compressionContext); freemem(cctxPtr.lz4CtxPtr); freemem(cctxPtr.tmpBuff); freemem(LZ4F_compressionContext); result := cardinal(OK_NoError); end; function LZ4F_getFrameInfo(decompressionContext: PLZ4F_decompressionContext_t; frameInfoPtr: PLZ4F_frameInfo_t; const srcBuffer: pointer; srcSizePtr: psize_t): LZ4F_errorCode_t; var dctxPtr: PLZ4F_dctx_internal_t; errorCode: LZ4F_errorCode_t; begin dctxPtr := PLZ4F_dctx_internal_t(decompressionContext); if dctxPtr.dStage = cardinal(dstage_getHeader) then begin errorCode := LZ4F_decodeHeader(dctxPtr, srcBuffer, srcSizePtr^); if LZ4F_isError(errorCode) then exit(errorCode); srcSizePtr^ := errorCode; frameInfoPtr^ := dctxPtr.frameInfo; dctxPtr.srcExpect := Nil; dctxPtr.dStage := cardinal(dstage_getCBlockSize); exit(4); end; srcSizePtr^ := 0; frameInfoPtr^ := dctxPtr.frameInfo; result := 0; end; function LZ4F_freeDecompressionContext(LZ4F_decompressionContext: PLZ4F_decompressionContext_t): LZ4F_errorCode_t; var dctxPtr: PLZ4F_dctx_internal_t; begin dctxPtr := PLZ4F_dctx_internal_t(LZ4F_decompressionContext); freemem(dctxPtr.tmpIn); freemem(dctxPtr.tmpOutBuffer); freemem(dctxPtr); result := cardinal(OK_NoError); end; end. ================================================ FILE: lib/xedit/lz4/lz4frame_static.pas ================================================ (* LZ4Delphi Copyright (C) 2015, Jose Pascoa (atelierwebgm@gmail.com) BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) ************************************************************************* LZ4 - Fast LZ compression algorithm xxHash - Fast Hash algorithm LZ4 source repository : http://code.google.com/p/lz4/ xxHash source repository : http://code.google.com/p/xxhash/ Copyright (c) 2011-2014, Yann Collet BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************************** *) unit lz4frame_static; {$POINTERMATH ON} interface uses Windows; type LZ4F_LIST_ERRORS = ( OK_NoError = 0, ERROR_GENERIC, ERROR_maxBlockSize_invalid, ERROR_blockMode_invalid, ERROR_contentChecksumFlag_invalid, ERROR_compressionLevel_invalid, ERROR_allocation_failed, ERROR_srcSize_tooLarge, ERROR_dstMaxSize_tooSmall, ERROR_decompressionFailed, ERROR_checksum_invalid, ERROR_maxCode); const LZ4F_errorStrings : array[0..11] of AnsiString = ( 'OK_NoError', 'ERROR_GENERIC', 'ERROR_maxBlockSize_invalid', 'ERROR_blockMode_invalid', 'ERROR_contentChecksumFlag_invalid', 'ERROR_compressionLevel_invalid', 'ERROR_allocation_failed', 'ERROR_srcSize_tooLarge', 'ERROR_dstMaxSize_tooSmall', 'ERROR_decompressionFailed', 'ERROR_checksum_invalid', 'ERROR_maxCode' ); implementation end. ================================================ FILE: lib/xedit/lz4/lz4io.pas ================================================ (* LZ4Delphi Copyright (C) 2015, Jose Pascoa (atelierwebgm@gmail.com) BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) ************************************************************************* LZ4 - Fast LZ compression algorithm xxHash - Fast Hash algorithm LZ4 source repository : http://code.google.com/p/lz4/ xxHash source repository : http://code.google.com/p/xxhash/ Copyright (c) 2011-2014, Yann Collet BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************************** *) unit lz4io; {$POINTERMATH ON} interface uses Windows, Classes, SysUtils, Math, lz4frame_static, xxHash, lz4, lz4common, lz4frame, lz4HC; const LZ4_BLOCKSIZEID_DEFAULT = 7; ENDOFSTREAM = uint64(-1); LZ4S_MAGICNUMBER = $184D2204; LZ4S_SKIPPABLE0 = $184D2A50; LZ4S_SKIPPABLEMASK = $FFFFFFF0; LEGACY_MAGICNUMBER = $184C2102; MAGICNUMBER_SIZE = 4; LEGACY_BLOCKSIZE = 8388608; MIN_STREAM_BUFSIZE = 196608; var lz4_overwrite_file: boolean = true; globalblockSizeID: integer = LZ4_BLOCKSIZEID_DEFAULT; blockIndependence: integer = 1; streamChecksum: integer = 1; function LZ4IO_compressFilename_Legacy(input_filename: string; output_filename: string; compressionLevel: integer): integer; function LZ4IO_compressFilename(input_filename: string; output_filename: string; compressionLevel: integer): integer; function LZ4IO_decompressFilename(input_filename: string; output_filename: string): integer; procedure lz4DecompressToUserBuf(const InBuf: Pointer; InBytes: Integer; const OutBuf: Pointer; BufSize: Integer); implementation const minBlockSizeID: integer = 4; maxBlockSizeID: integer = 7; function reportError(err: string): integer; begin //LZ4Client.Memo.Lines.Add(err); result := 0; end; procedure LZ4IO_writeLE32(p: pointer; value32: cardinal); var dstPtr: pByte; begin dstPtr := p; dstPtr[0] := byte(value32); dstPtr[1] := byte(value32 shr 8); dstPtr[2] := byte(value32 shr 16); dstPtr[3] := byte(value32 shr 24); end; function LZ4IO_compressFilename_Legacy(input_filename: string; output_filename: string; compressionLevel: integer): integer; type TCompressionFunction = function(c1: pAnsiChar; c2: pAnsiChar; c3: integer): integer; var compressionFunction: TCompressionFunction; filesize: uint64; compressedfilesize: uint64; in_buff: pAnsiChar; out_buff: pAnsiChar; fileIn: TFileSTream; fileOut: TFileSTream; sizeCheck: size_t; outSize, inSize: cardinal; begin filesize := 0; compressedfilesize := MAGICNUMBER_SIZE; if (compressionLevel < 3) then compressionFunction := LZ4_compress else compressionFunction := LZ4_compressHC; fileIn := TFileSTream.Create(input_filename, fmOpenRead); fileOut := TFileSTream.Create(output_filename, fmCreate); in_buff := allocmem(LEGACY_BLOCKSIZE); out_buff := allocmem(LZ4_compressBound(LEGACY_BLOCKSIZE)); try if (in_buff = nil) or (out_buff = nil) then exit(reportError('Allocation error : not enough memory')); LZ4IO_writeLE32(out_buff, LEGACY_MAGICNUMBER); sizeCheck := fileOut.Write(out_buff^, MAGICNUMBER_SIZE); if sizeCheck <> MAGICNUMBER_SIZE then exit(reportError('Write error : cannot write header')); while true do begin inSize := fileIn.Read(in_buff^, LEGACY_BLOCKSIZE); if inSize <= 0 then break; inc(filesize, inSize); outSize := compressionFunction(in_buff, out_buff + 4, inSize); inc(compressedfilesize, outSize + 4); LZ4IO_writeLE32(out_buff, outSize); sizeCheck := fileOut.Write(out_buff^, outSize + 4); if sizeCheck <> size_t(outSize + 4) then exit(reportError('Write error : cannot write compressed block')); end; finally if in_buff <> nil then freemem(in_buff); if out_buff <> nil then freemem(out_buff); fileIn.Free; fileOut.Free; result := 0; end; end; function LZ4IO_setBlockSizeID(bsid: integer): integer; const blockSizeTable: array [0 .. 3] of integer = (65536, 262144, 1048576, 4194304); begin if (bsid < minBlockSizeID) or (bsid > maxBlockSizeID) then exit(-1); globalblockSizeID := bsid; result := blockSizeTable[globalblockSizeID - minBlockSizeID]; end; function LZ4IO_compressFilename(input_filename: string; output_filename: string; compressionLevel: integer): integer; var filesize: uint64; errorCode: LZ4F_errorCode_t; ctx: PLZ4F_compressionContext_t; blockSize: integer; fileIn: TFileSTream; fileOut: TFileSTream; prefs: LZ4F_preferences_t; in_buff: pAnsiChar; out_buff: pAnsiChar; outBuffSize: size_t; headerSize: size_t; sizeCheck: size_t; readSize: size_t; outSize: size_t; begin result := 0; filesize := 0; errorCode := LZ4F_createCompressionContext(ctx, LZ4F_VERSION); if (LZ4F_isError(errorCode)) then exit(reportError(format('Allocation error : can''t create LZ4F context: %s', [LZ4F_getErrorName(errorCode)]))); fileIn := TFileSTream.Create(input_filename, fmOpenRead); fileOut := TFileSTream.Create(output_filename, fmCreate); blockSize := 1 shl (8 + 2 * globalblockSizeID); fillchar(prefs, sizeof(LZ4F_preferences_t), 0); prefs.autoFlush := 1; prefs.compressionLevel := compressionLevel; prefs.frameInfo.blockMode := blockMode_t(blockIndependence); prefs.frameInfo.blockSizeID := blockSizeID_t(globalblockSizeID); prefs.frameInfo.contentChecksumFlag := contentChecksum_t(streamChecksum); // Allocate Memory in_buff := allocmem(blockSize); outBuffSize := LZ4F_compressBound(blockSize, @prefs); out_buff := allocmem(outBuffSize); try if (in_buff = nil) or (out_buff = nil) then exit(reportError('Allocation error : not enough memory')); // Write Archive Header headerSize := LZ4F_compressBegin(ctx, out_buff, outBuffSize, @prefs); if (LZ4F_isError(headerSize)) then exit(reportError(format('File header generation failed: %s', [LZ4F_getErrorName(errorCode)]))); sizeCheck := fileOut.Write(out_buff^, headerSize); if sizeCheck <> headerSize then exit(reportError('Write error : cannot write header')); readSize := fileIn.Read(in_buff^, blockSize); inc(filesize, readSize); while readSize > 0 do begin outSize := LZ4F_compressUpdate(ctx, out_buff, outBuffSize, in_buff, readSize, Nil); if (LZ4F_isError(outSize)) then exit(reportError(format('Compression failed: %s', [LZ4F_getErrorName(errorCode)]))); sizeCheck := fileOut.Write(out_buff^, outSize); if sizeCheck <> outSize then exit(reportError('Write error : cannot write compressed block')); readSize := fileIn.Read(in_buff^, blockSize); inc(filesize, readSize); end; // End of Stream mark headerSize := LZ4F_compressEnd(ctx, out_buff, outBuffSize, Nil); if LZ4F_isError(headerSize) then exit(reportError(format('End of file generation failed: %s', [LZ4F_getErrorName(errorCode)]))); sizeCheck := fileOut.Write(out_buff^, headerSize); if sizeCheck <> headerSize then exit(reportError('Write error : cannot write end of stream')); errorCode := LZ4F_freeCompressionContext(ctx); if LZ4F_isError(errorCode) then exit(reportError(format('Error : can''t free LZ4F context resource: %s', [LZ4F_getErrorName(errorCode)]))); finally if in_buff <> nil then freemem(in_buff); if out_buff <> nil then freemem(out_buff); fileIn.Free;; fileOut.Free; end; end; function LZ4IO_readLE32(s: pointer): cardinal; var srcPtr: pByte; value32: cardinal; begin srcPtr := s; value32 := srcPtr[0]; inc(value32, (srcPtr[1] shl 8)); inc(value32, (srcPtr[2] shl 16)); inc(value32, (srcPtr[3] shl 24)); result := value32; end; function LZ4S_isSkippableMagicNumber(magic: cardinal): boolean; begin result := (magic and LZ4S_SKIPPABLEMASK) = LZ4S_SKIPPABLE0; end; function decodeLZ4S(finput, foutput: TSTream): uint64; const HEADERMAX = 20; var filesize: uint64; inBuff: pAnsiChar; outBuff: pAnsiChar; headerBuff: array [0 .. HEADERMAX - 1] of ansiChar; sizeCheck, nextToRead, outBuffSize, inBuffSize: size_t; ctx: PLZ4F_decompressionContext_t; errorCode: LZ4F_errorCode_t; frameInfo: LZ4F_frameInfo_t; decodedBytes: size_t; begin filesize := 0; errorCode := LZ4F_createDecompressionContext(ctx, LZ4F_VERSION); if LZ4F_isError(errorCode) then exit(reportError(format('Allocation error : can''t create context: %s', [LZ4F_getErrorName(errorCode)]))); LZ4IO_writeLE32(@headerBuff, LZ4S_MAGICNUMBER); outBuffSize := 0; inBuffSize := 0; sizeCheck := MAGICNUMBER_SIZE; nextToRead := LZ4F_decompress(ctx, Nil, @outBuffSize, @headerBuff, @sizeCheck, Nil); if LZ4F_isError(nextToRead) then exit(reportError(format('Decompression error: %s', [LZ4F_getErrorName(errorCode)]))); if nextToRead > HEADERMAX then exit(reportError(format('Header too large (%d>%d)', [integer(nextToRead), HEADERMAX]))); sizeCheck := finput.Read(headerBuff, nextToRead); if sizeCheck <> nextToRead then exit(reportError('Read error')); nextToRead := LZ4F_decompress(ctx, Nil, @outBuffSize, @headerBuff, @sizeCheck, Nil); errorCode := LZ4F_getFrameInfo(ctx, @frameInfo, Nil, @inBuffSize); if LZ4F_isError(errorCode) then exit(reportError(format('can''t decode frame header: %s', [LZ4F_getErrorName(errorCode)]))); outBuffSize := LZ4IO_setBlockSizeID(integer(frameInfo.blockSizeID)); inBuffSize := outBuffSize + 4; inBuff := allocmem(inBuffSize); outBuff := allocmem(outBuffSize); try if (inBuff = nil) or (outBuff = nil) then exit(reportError('Allocation error : not enough memory')); while (nextToRead <> 0) do begin decodedBytes := outBuffSize; sizeCheck := finput.Read(inBuff^, nextToRead); if sizeCheck <> nextToRead then exit(reportError('Read error')); errorCode := LZ4F_decompress(ctx, outBuff, @decodedBytes, inBuff, @sizeCheck, Nil); if LZ4F_isError(errorCode) then exit(reportError(format('Decompression error: %s', [LZ4F_getErrorName(errorCode)]))); if sizeCheck <> nextToRead then exit(reportError('Synchronization error')); nextToRead := errorCode; inc(filesize, decodedBytes); sizeCheck := foutput.Write(outBuff^, decodedBytes); if sizeCheck <> decodedBytes then exit(reportError('Write error : cannot write decoded block')); end; errorCode := LZ4F_freeDecompressionContext(ctx); if LZ4F_isError(errorCode) then exit(reportError(format('Error : can''t free LZ4F context resource: %s', [LZ4F_getErrorName(errorCode)]))); finally if inBuff <> nil then freemem(inBuff); if outBuff <> nil then freemem(outBuff); result := filesize; end; end; function decodeLegacyStream(finput, foutput: TSTream): uint64; var filesize: uint64; in_buff: pAnsiChar; out_buff: pAnsiChar; decodeSize: integer; sizeCheck: size_t; blockSize: cardinal; begin filesize := 0; in_buff := allocmem(LZ4_compressBound(LEGACY_BLOCKSIZE)); out_buff := allocmem(LEGACY_BLOCKSIZE); try if (in_buff = nil) or (out_buff = nil) then exit(reportError('Allocation error : not enough memory')); while true do begin sizeCheck := finput.Read(in_buff^, 4); if sizeCheck = 0 then break; blockSize := LZ4IO_readLE32(in_buff); if blockSize > LZ4_compressBound(LEGACY_BLOCKSIZE) then begin finput.Seek(-4, soFromCurrent); break; end; sizeCheck := finput.Read(in_buff^, blockSize); if sizeCheck <> blockSize then exit(reportError('Error reading input file')); decodeSize := LZ4_decompress_safe(in_buff, out_buff, blockSize, LEGACY_BLOCKSIZE); if (decodeSize < 0) then exit(reportError('Decoding Failed ! Corrupted input detected')); inc(filesize, decodeSize); sizeCheck := foutput.Write(out_buff^, decodeSize); if sizeCheck <> size_t(decodeSize) then exit(reportError('Write error : cannot write decoded block into output')); end; finally if in_buff <> nil then freemem(in_buff); if out_buff <> nil then freemem(out_buff); result := filesize; end; end; function selectDecoder(finput, foutput: TSTream): uint64; var nbReadBytes: size_t; U32Store: array [0 .. MAGICNUMBER_SIZE - 1] of byte; magicNumber, Size: cardinal; newPos: uint64; begin nbReadBytes := finput.Read(U32Store, MAGICNUMBER_SIZE); if nbReadBytes = 0 then exit(ENDOFSTREAM); if nbReadBytes <> MAGICNUMBER_SIZE then exit(reportError('Unrecognized header : Magic Number unreadable')); magicNumber := LZ4IO_readLE32(@U32Store); if LZ4S_isSkippableMagicNumber(magicNumber) then magicNumber := LZ4S_SKIPPABLE0; case magicNumber of LZ4S_MAGICNUMBER: result := decodeLZ4S(finput, foutput); LEGACY_MAGICNUMBER: begin result := decodeLegacyStream(finput, foutput); end; LZ4S_SKIPPABLE0: begin nbReadBytes := finput.Read(U32Store, 4); if (nbReadBytes <> 4) then exit(reportError('Stream error : skippable size unreadable')); Size := LZ4IO_readLE32(@U32Store); newPos := finput.Seek(Size, soFromCurrent); if newPos <> finput.Position then exit(reportError('Stream error : cannot skip skippable area')); result := selectDecoder(finput, foutput); end; else begin if finput.Position = MAGICNUMBER_SIZE then exit(reportError('Unrecognized header : file cannot be decoded')); reportError('Stream followed by unrecognized data'); result := ENDOFSTREAM; end; end; end; function LZ4IO_decompressFilename(input_filename: string; output_filename: string): integer; var fileIn: TFileSTream; fileOut: TFileSTream; decodedSize: int64; filesize: int64; begin result := 0; filesize := 0; fileIn := TFileSTream.Create(input_filename, fmOpenRead); fileOut := TFileSTream.Create(output_filename, fmCreate); repeat decodedSize := selectDecoder(fileIn, fileOut); if decodedSize <> ENDOFSTREAM then inc(filesize, decodedSize); until decodedSize = ENDOFSTREAM; fileIn.Free;; fileOut.Free; end; type TPreallocatedMemoryStream = class(TCustomMemoryStream) public constructor Create(Ptr: Pointer; Size: Int64); function Write(const Buffer; Count: Longint): Longint; override; end; constructor TPreallocatedMemoryStream.Create(Ptr: Pointer; Size: Int64); begin inherited Create; SetPointer(Ptr, Size); end; function TPreallocatedMemoryStream.Write(const Buffer; Count: Integer): Longint; begin Result := Min(Count, Size-Position); System.Move(Buffer, Pointer(PByte(Memory) + Position)^, Result); Seek(Result, soCurrent); end; procedure lz4DecompressToUserBuf(const InBuf: Pointer; InBytes: Integer; const OutBuf: Pointer; BufSize: Integer); var stin, stout: TPreallocatedMemoryStream; decodedSize: int64; decompressedSize: int64; begin stin := TPreallocatedMemoryStream.Create(InBuf, InBytes); stout := TPreallocatedMemoryStream.Create(OutBuf, BufSize); try decompressedSize := 0; repeat decodedSize := selectDecoder(stin, stout); if decodedSize <> ENDOFSTREAM then Inc(decompressedSize, decodedSize); until decodedSize = ENDOFSTREAM; if decompressedSize <> BufSize then Exception.Create('lz4 decompression size mismatch'); //Move(stout.Memory^, OutBuf^, BufSize); finally stin.Free; stout.Free; end; end; end. ================================================ FILE: lib/xedit/lz4/xxHash.pas ================================================ (* LZ4Delphi Copyright (C) 2015, Jose Pascoa (atelierwebgm@gmail.com) BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) ************************************************************************* LZ4 - Fast LZ compression algorithm xxHash - Fast Hash algorithm LZ4 source repository : http://code.google.com/p/lz4/ xxHash source repository : http://code.google.com/p/xxhash/ Copyright (c) 2011-2014, Yann Collet BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ****************************************************************************** *) unit xxHash; {$POINTERMATH ON} interface uses Windows, lz4common; const PRIME32_1: cardinal = 2654435761; PRIME32_2: cardinal = 2246822519; PRIME32_3: cardinal = 3266489917; PRIME32_4: cardinal = 668265263; PRIME32_5: cardinal = 374761393; PRIME64_1: uint64 = 11400714785074694791; PRIME64_2: uint64 = 14029467366897019727; PRIME64_3: uint64 = 1609587929392839161; PRIME64_4: uint64 = 9650029242287828579; PRIME64_5: uint64 = 2870177450012600261; type XXH_errorcode = (XXH_OK = 0, XXH_ERROR); XXH_endianess = (XXH_bigEndian = 0, XXH_littleEndian = 1); XXH_alignment = (XXH_aligned, XXH_unaligned); PXXH32_state_t = ^XXH32_state_t; XXH32_state_t = record ll: array [0 .. 5] of int64; end; PXXH_istate32_t = ^XXH_istate32_t; XXH_istate32_t = record total_len: uint64; seed: cardinal; v1: cardinal; v2: cardinal; v3: cardinal; v4: cardinal; mem32: array [0 .. 3] of cardinal; memsize: cardinal; end; PXXH64_state_t = ^XXH64_state_t; XXH64_state_t = record ll: array [0 .. 10] of int64; end; PXXH_istate64_t = ^XXH_istate64_t; XXH_istate64_t = record total_len: uint64; seed: uint64; v1: uint64; v2: uint64; v3: uint64; v4: uint64; mem64: array [0 .. 3] of uint64; memsize: cardinal; end; function XXH32(input: pointer; len: size_t; seed: cardinal): cardinal; function XXH32_reset(statePtr: PXXH32_state_t; seed: cardinal): XXH_errorcode; function XXH32_update(statePtr: PXXH32_state_t; Ainput: pointer; ALength: size_t): XXH_errorcode; function XXH32_digest(statePtr: PXXH32_state_t): cardinal; function XXH32_createState: PXXH32_state_t; procedure XXH32_freeState(statePtr: PXXH32_state_t); // Obsolet in recent release function XXH32_init(seed: cardinal): PXXH32_state_t; function XXH64_reset(statePtr: PXXH64_state_t; seed: uint64): XXH_errorcode; function XXH64_update(statePtr: PXXH64_state_t; Ainput: pointer; ALength: size_t): XXH_errorcode; function XXH64_digest(statePtr: PXXH64_state_t): uint64; function XXH64_createState: PXXH64_state_t; procedure XXH64_freeState(statePtr: PXXH64_state_t); // Obsolet in recent release function XXH64_init(seed: uint64): PXXH64_state_t; implementation type PU32_S = ^U32_S; U32_S = packed record v: cardinal; end; PU64_S = ^U64_S; U64_S = packed record v: uint64; end; function XXH_rotl32(x, r: cardinal): cardinal; asm mov eax, x mov ecx, r rol eax, cl end; (* Alternative function XXH_rotl32(x, r: cardinal): cardinal; inline; var temp: cardinal; begin temp := x; result := (x shl r) or (temp shr (32 - r)); end; *) {$IFDEF CPUX64} function XXH_rotl64(x: uint64; r: cardinal): uint64; asm mov rax, x mov ecx, r rol rax, cl end; {$ELSE} function XXH_rotl64(x: uint64; r: cardinal): uint64; inline var temp: uint64; begin temp := x; result := (x shl r) or (temp shr (64 - r)); end; {$ENDIF} function A32(x: pointer): cardinal; inline; begin result := PU32_S(x).v; end; function A64(x: pointer): uint64; inline; begin result := PU64_S(x).v; end; function XXH_readLE32_align(ptr: pointer; endian: XXH_endianess; align: XXH_alignment): cardinal; inline; begin if align = XXH_unaligned then result := A32(ptr) else result := pcardinal(ptr)^; end; function XXH_readLE32(ptr: pointer): cardinal; inline; begin result := XXH_readLE32_align(ptr, XXH_littleEndian, XXH_unaligned); end; function XXH_readLE64_align(ptr: pointer; endian: XXH_endianess; align: XXH_alignment): uint64; inline; begin if align = XXH_unaligned then result := A64(ptr) else result := puint64(ptr)^; end; function XXH_readLE64(ptr: pointer): uint64; inline; begin result := XXH_readLE64_align(ptr, XXH_littleEndian, XXH_unaligned); end; function XXH32_reset(statePtr: PXXH32_state_t; seed: cardinal): XXH_errorcode; var state: PXXH_istate32_t; begin state := PXXH_istate32_t(statePtr); state.seed := seed; state.v1 := seed + PRIME32_1 + PRIME32_2; state.v2 := seed + PRIME32_2; state.v3 := seed + 0; state.v4 := seed - PRIME32_1; state.total_len := 0; state.memsize := 0; result := XXH_OK; end; function XXH64_reset(statePtr: PXXH64_state_t; seed: uint64): XXH_errorcode; var state: PXXH_istate64_t; begin state := PXXH_istate64_t(statePtr); state.seed := seed; state.v1 := seed + PRIME64_1 + PRIME64_2; state.v2 := seed + PRIME64_2; state.v3 := seed + 0; state.v4 := seed - PRIME64_1; state.total_len := 0; state.memsize := 0; result := XXH_OK; end; function XXH32_update(statePtr: PXXH32_state_t; Ainput: pointer; ALength: size_t): XXH_errorcode; var state: PXXH_istate32_t; p: pByte; bEnd: pByte; p32: pcardinal; limit: pByte; v1, v2, v3, v4: cardinal; begin state := PXXH_istate32_t(statePtr); p := Ainput; bEnd := p + ALength; inc(state.total_len, ALength); if (state.memsize + ALength < 16) then begin move(Ainput^, (pByte(@state.mem32) + state.memsize)^, ALength); inc(state.memsize, cardinal(ALength)); exit(XXH_OK); end; if state.memsize > 0 then begin move(Ainput^, (pByte(@state.mem32) + state.memsize)^, 16 - state.memsize); p32 := @state.mem32; inc(state.v1, XXH_readLE32(p32) * PRIME32_2); state.v1 := XXH_rotl32(state.v1, 13); state.v1 := state.v1 * PRIME32_1; inc(p32); inc(state.v2, XXH_readLE32(p32) * PRIME32_2); state.v2 := XXH_rotl32(state.v2, 13); state.v2 := state.v2 * PRIME32_1; inc(p32); inc(state.v3, XXH_readLE32(p32) * PRIME32_2); state.v3 := XXH_rotl32(state.v3, 13); state.v3 := state.v3 * PRIME32_1; inc(p32); inc(state.v4, XXH_readLE32(p32) * PRIME32_2); state.v4 := XXH_rotl32(state.v4, 13); state.v4 := state.v4 * PRIME32_1; // inc(p32); inc(p, 16 - state.memsize); state.memsize := 0; end; if p <= (bEnd - 16) then begin limit := bEnd - 16; v1 := state.v1; v2 := state.v2; v3 := state.v3; v4 := state.v4; repeat inc(v1, XXH_readLE32(p) * PRIME32_2); v1 := XXH_rotl32(v1, 13); v1 := v1 * PRIME32_1; inc(p, 4); inc(v2, XXH_readLE32(p) * PRIME32_2); v2 := XXH_rotl32(v2, 13); v2 := v2 * PRIME32_1; inc(p, 4); inc(v3, XXH_readLE32(p) * PRIME32_2); v3 := XXH_rotl32(v3, 13); v3 := v3 * PRIME32_1; inc(p, 4); inc(v4, XXH_readLE32(p) * PRIME32_2); v4 := XXH_rotl32(v4, 13); v4 := v4 * PRIME32_1; inc(p, 4); until p > limit; state.v1 := v1; state.v2 := v2; state.v3 := v3; state.v4 := v4; end; if p < bEnd then begin move(p^, state.mem32, bEnd - p); state.memsize := integer(bEnd - p); end; result := XXH_OK; end; function XXH64_update(statePtr: PXXH64_state_t; Ainput: pointer; ALength: size_t): XXH_errorcode; var state: PXXH_istate64_t; p: pByte; bEnd: pByte; p64: puint64; limit: pByte; v1, v2, v3, v4: uint64; begin state := PXXH_istate64_t(statePtr); p := Ainput; bEnd := p + ALength; inc(state.total_len, ALength); if (state.memsize + ALength < 32) then begin move(Ainput^, (pByte(@state.mem64) + state.memsize)^, ALength); inc(state.memsize, cardinal(ALength)); exit(XXH_OK); end; if state.memsize > 0 then begin move(Ainput^, (pByte(@state.mem64) + state.memsize)^, 32 - state.memsize); p64 := @state.mem64; inc(state.v1, XXH_readLE64(p64) * PRIME64_2); state.v1 := XXH_rotl64(state.v1, 31); state.v1 := state.v1 * PRIME64_1; inc(p64); inc(state.v2, XXH_readLE64(p64) * PRIME64_2); state.v2 := XXH_rotl64(state.v2, 31); state.v2 := state.v2 * PRIME64_1; inc(p64); inc(state.v3, XXH_readLE64(p64) * PRIME64_2); state.v3 := XXH_rotl64(state.v3, 31); state.v3 := state.v3 * PRIME64_1; inc(p64); inc(state.v4, XXH_readLE64(p64) * PRIME64_2); state.v4 := XXH_rotl64(state.v4, 31); state.v4 := state.v4 * PRIME64_1; inc(p, 32 - state.memsize); state.memsize := 0; end; if (p + 32) <= bEnd then begin limit := bEnd - 32; v1 := state.v1; v2 := state.v2; v3 := state.v3; v4 := state.v4; repeat inc(v1, XXH_readLE64(p) * PRIME64_2); v1 := XXH_rotl64(v1, 31); v1 := v1 * PRIME64_1; inc(p, 8); inc(v2, XXH_readLE64(p) * PRIME64_2); v2 := XXH_rotl64(v2, 31); v2 := v2 * PRIME64_1; inc(p, 8); inc(v3, XXH_readLE64(p) * PRIME64_2); v3 := XXH_rotl64(v3, 31); v3 := v3 * PRIME64_1; inc(p, 8); inc(v4, XXH_readLE64(p) * PRIME64_2); v4 := XXH_rotl64(v4, 31); v4 := v4 * PRIME64_1; inc(p, 8); until p > limit; state.v1 := v1; state.v2 := v2; state.v3 := v3; state.v4 := v4; end; if p < bEnd then begin move(p^, state.mem64, bEnd - p); state.memsize := integer(bEnd - p); end; result := XXH_OK; end; function XXH32_digest(statePtr: PXXH32_state_t): cardinal; var state: PXXH_istate32_t; p: pByte; bEnd: pByte; h32: cardinal; begin state := PXXH_istate32_t(statePtr); p := @state.mem32; bEnd := pByte(@state.mem32) + state.memsize; if (state.total_len >= 16) then h32 := XXH_rotl32(state.v1, 1) + XXH_rotl32(state.v2, 7) + XXH_rotl32(state.v3, 12) + XXH_rotl32(state.v4, 18) else h32 := state.seed + PRIME32_5; inc(h32, state.total_len); while (p + 4) <= bEnd do begin inc(h32, XXH_readLE32(p) * PRIME32_3); h32 := XXH_rotl32(h32, 17) * PRIME32_4; inc(p, 4); end; while p < bEnd do begin inc(h32, p^ * PRIME32_5); h32 := XXH_rotl32(h32, 11) * PRIME32_1; inc(p); end; h32 := h32 xor (h32 shr 15); h32 := h32 * PRIME32_2; h32 := h32 xor (h32 shr 13); h32 := h32 * PRIME32_3; h32 := h32 xor (h32 shr 16); result := h32; end; function XXH64_digest(statePtr: PXXH64_state_t): uint64; var state: PXXH_istate64_t; p: pByte; bEnd: pByte; h64: uint64; v1, v2, v3, v4: uint64; k1: uint64; begin state := PXXH_istate64_t(statePtr); p := @state.mem64; bEnd := pByte(@state.mem64) + state.memsize; if state.total_len >= 32 then begin v1 := state.v1; v2 := state.v2; v3 := state.v3; v4 := state.v4; h64 := XXH_rotl64(v1, 1) + XXH_rotl64(v2, 7) + XXH_rotl64(v3, 12) + XXH_rotl64(v4, 18); v1 := v1 * PRIME64_2; v1 := XXH_rotl64(v1, 31); v1 := v1 * PRIME64_1; h64 := h64 xor v1; h64 := h64 * PRIME64_1 + PRIME64_4; v2 := v2 * PRIME64_2; v2 := XXH_rotl64(v2, 31); v2 := v2 * PRIME64_1; h64 := h64 xor v2; h64 := h64 * PRIME64_1 + PRIME64_4; v3 := v3 * PRIME64_2; v3 := XXH_rotl64(v3, 31); v3 := v3 * PRIME64_1; h64 := h64 xor v3; h64 := h64 * PRIME64_1 + PRIME64_4; v4 := v4 * PRIME64_2; v4 := XXH_rotl64(v4, 31); v4 := v4 * PRIME64_1; h64 := h64 xor v4; h64 := h64 * PRIME64_1 + PRIME64_4; end else h64 := state.seed + PRIME64_5; inc(h64, state.total_len); while (p + 8) <= bEnd do begin k1 := XXH_readLE64(p); k1 := k1 * PRIME64_2; k1 := XXH_rotl64(k1, 31); k1 := k1 * PRIME64_1; h64 := h64 xor k1; h64 := XXH_rotl64(h64, 27) * PRIME64_1 + PRIME64_4; inc(p, 8); end; if (p + 4) <= bEnd then begin h64 := h64 xor (uint64(XXH_readLE32(p)) * PRIME64_1); h64 := XXH_rotl64(h64, 23) * PRIME64_2 + PRIME64_3; inc(p, 4); end; while (p < bEnd) do begin h64 := h64 xor (p^ * PRIME64_5); h64 := XXH_rotl64(h64, 11) * PRIME64_1; inc(p); end; h64 := h64 xor (h64 shr 33); h64 := h64 * PRIME64_2; h64 := h64 xor (h64 shr 29); h64 := h64 * PRIME64_3; h64 := h64 xor (h64 shr 32); result := h64; end; function XXH32_createState: PXXH32_state_t; begin result := allocmem(sizeof(XXH32_state_t)); end; function XXH64_createState: PXXH64_state_t; begin result := allocmem(sizeof(XXH64_state_t)); end; procedure XXH32_freeState(statePtr: PXXH32_state_t); begin freemem(statePtr); end; procedure XXH64_freeState(statePtr: PXXH64_state_t); begin freemem(statePtr); end; function XXH32_init(seed: cardinal): PXXH32_state_t; begin result := XXH32_createState; XXH32_reset(result, seed); end; function XXH64_init(seed: uint64): PXXH64_state_t; begin result := XXH64_createState; XXH64_reset(result, seed); end; function XXH32_endian_align(input: pointer; len: size_t; seed: cardinal; endian: XXH_endianess; align: XXH_alignment): cardinal; function XXH_get32bits(p: pByte): cardinal; begin result := XXH_readLE32_align(p, endian, align); end; var p: pByte; bEnd: pByte; h32: cardinal; limit: pByte; v1, v2, v3, v4: cardinal; begin p := input; bEnd := p + len; if (len >= 16) then begin limit := bEnd - 16; v1 := seed + PRIME32_1 + PRIME32_2; v2 := seed + PRIME32_2; v3 := seed + 0; v4 := seed - PRIME32_1; while true do begin inc(v1, XXH_get32bits(p) * PRIME32_2); v1 := XXH_rotl32(v1, 13); v1 := v1 * PRIME32_1; inc(p, 4); inc(v2, XXH_get32bits(p) * PRIME32_2); v2 := XXH_rotl32(v2, 13); v2 := v2 * PRIME32_1; inc(p, 4); inc(v3, XXH_get32bits(p) * PRIME32_2); v3 := XXH_rotl32(v3, 13); v3 := v3 * PRIME32_1; inc(p, 4); inc(v4, XXH_get32bits(p) * PRIME32_2); v4 := XXH_rotl32(v4, 13); v4 := v4 * PRIME32_1; inc(p, 4); if p > limit then break; end; h32 := XXH_rotl32(v1, 1) + XXH_rotl32(v2, 7) + XXH_rotl32(v3, 12) + XXH_rotl32(v4, 18); end else h32 := seed + PRIME32_5; inc(h32, cardinal(len)); while (p + 4 <= bEnd) do begin inc(h32, XXH_get32bits(p) * PRIME32_3); h32 := XXH_rotl32(h32, 17) * PRIME32_4; inc(p, 4); end; while (p < bEnd) do begin inc(h32, p^ * PRIME32_5); h32 := XXH_rotl32(h32, 11) * PRIME32_1; inc(p); end; h32 := h32 xor (h32 shr 15); h32 := h32 * PRIME32_2; h32 := h32 xor (h32 shr 13); h32 := h32 * PRIME32_3; h32 := h32 xor (h32 shr 16); result := h32; end; function XXH32(input: pointer; len: size_t; seed: cardinal): cardinal; begin result := XXH32_endian_align(input, len, seed, XXH_littleEndian, XXH_unaligned); end; end. ================================================ FILE: lib/xedit/wbBSA.pas ================================================ {******************************************************************************* The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. *******************************************************************************} unit wbBSA; {$I wbDefines.inc} interface uses Classes, SysUtils, IOUtils, wbInterface, ImagingDds; function wbCreateContainerHandler: IwbContainerHandler; implementation uses wbStreams, zlibEx, lz4io; const { https://github.com/Ethatron/bsaopt/blob/master/io/bsa.C } BSAHEADER_VERSION_OB = $67; // Oblivion BSAHEADER_VERSION_SK = $68; // Fallout3, Skyrim BSAHEADER_VERSION_SSE = $69; // Skyrim Special Edition BSAARCHIVE_COMPRESSFILES = $0004; // Whether the files are compressed in archive (invert file's compression flag) BSAARCHIVE_PREFIXFULLFILENAMES = $0100; // Whether the name is prefixed to the data? BSAFILE_COMPRESS = $40000000; // Whether the file is compressed { https://github.com/jonwd7/bae/blob/master/src/bsa.h } BA2HEADER_VERSION_FO4 = $01; // Fallout 4 type TwbContainerHandler = class(TInterfacedObject, IwbContainerHandler) private chContainers: array of IwbResourceContainer; protected procedure AddContainer(const aContainer: IwbResourceContainer); {---IwbContainerHandler---} procedure AddFolder(const aPath: string); procedure AddBSA(const aFileName: string); procedure AddBA2(const aFileName: string); function OpenResource(const aFileName: string): TDynResources; function OpenResourceData(const aContainerName, aFileName: string): TBytes; function ContainerExists(aContainerName: string): Boolean; procedure ContainerList(const aList: TStrings); procedure ContainerResourceList(const aContainerName: string; const aList: TStrings; const aFolder: string = ''); function ResourceExists(const aFileName: string): Boolean; function ResolveHash(const aHash: Int64): TDynStrings; function ResourceCount(const aFileName: string; aContainers: TStrings = nil): Integer; procedure ResourceCopy(const aContainerName, aFileName, aPathOut: string); end; TwbBSAFileRec = record Name : string; Hash : Int64; Size : Cardinal; Offset : Cardinal; end; TwbBSAFolderRec = record Name : string; Hash : Int64; Files : array of TwbBSAFileRec; Map : TStringList; end; IwbBSAFileInternal = interface(IwbBSAFile) ['{A360B348-8F6B-4FC1-A869-9D5B833DCA5F}'] function GetData(aOffset, aSize: Cardinal): TBytes; end; TwbBSAFile = class(TInterfacedObject, IwbResourceContainer, IwbBSAFile, IwbBSAFileInternal) private bfStream : TwbReadOnlyCachedFileStream; bfFileName : string; bfVersion : Cardinal; bfOffset : Cardinal; bfFlags : Cardinal; bfFileFlags : Cardinal; bfFolders : array of TwbBSAFolderRec; bfFolderMap : TStringList; procedure ReadDirectory; protected {---IwbResourceContainer---} function GetName: string; function OpenResource(const aFileName: string): IwbResource; function ResourceExists(const aFileName: string): Boolean; procedure ResourceList(const aList: TStrings; const aFolder: string = ''); procedure ResolveHash(const aHash: Int64; var Results: TDynStrings); {---IwbBSAFile---} function GetFileName: string; {---IwbBSAFileInternal---} function GetData(aOffset, aSize: Cardinal):TBytes; public constructor Create(const aFileName: string); destructor Destroy; override; end; TwbBSAResource = class(TInterfacedObject, IwbResource) brFile : IwbBSAFileInternal; brOffset : Cardinal; brSize : Cardinal; protected {---IwbResource---} function GetContainer: IwbResourceContainer; function GetData: TBytes; public constructor Create(aFile: TwbBSAFile; aSize, aOffset: Cardinal); end; TwbBA2TexChunkRec = record Size : Cardinal; PackedSize : Cardinal; Offset : Int64; StartMip : Word; EndMip : Word; end; TwbBA2FileRec = record Name : string; NameHash : Cardinal; DirHash : Cardinal; Size : Cardinal; PackedSize : Cardinal; Offset : Int64; Height : Word; Width : Word; NumMips : Byte; DXGIFormat : Byte; CubeMaps : Word; TexChunks : array of TwbBA2TexChunkRec; end; IwbBA2FileInternal = interface(IwbBA2File) ['{87D66150-746E-4B37-B295-45C4221CDCBE}'] procedure ReadData(var Buffer; Offset: Int64; Count: Longint); end; TwbBA2File = class(TInterfacedObject, IwbResourceContainer, IwbBA2File, IwbBA2FileInternal) private bfStream : TwbReadOnlyCachedFileStream; bfFileName : string; bfVersion : Cardinal; bfType : TwbSignature; bfFiles : array of TwbBA2FileRec; bfFolderMap : TStringList; procedure ReadDirectory; protected {---IwbResourceContainer---} function GetName: string; function OpenResource(const aFileName: string): IwbResource; function ResourceExists(const aFileName: string): Boolean; procedure ResourceList(const aList: TStrings; const aFolder: string = ''); procedure ResolveHash(const aHash: Int64; var Results: TDynStrings); {---IwbBA2File---} function GetFileName: string; {---IwbBA2FileInternal---} procedure ReadData(var Buffer; Offset: Int64; Count: Longint); public constructor Create(const aFileName: string); destructor Destroy; override; end; TwbBA2Resource = class(TInterfacedObject, IwbResource) brFile : IwbBA2FileInternal; brFileRec : TwbBA2FileRec; protected {---IwbResource---} function GetContainer: IwbResourceContainer; function GetData: TBytes; public constructor Create(aFile: TwbBA2File; var aFileRec: TwbBA2FileRec); end; IwbFolderInternal = interface(IwbFolder) ['{6DF2B964-5AF7-4732-BD28-CD7600407A83}'] end; TwbFolder = class(TInterfacedObject, IwbResourceContainer, IwbFolder, IwbFolderInternal) private fPath : string; protected {---IwbResourceContainer---} function GetName: string; function OpenResource(const aFileName: string): IwbResource; function ResourceExists(const aFileName: string): Boolean; procedure ResourceList(const aList: TStrings; const aFolder: string = ''); procedure ResolveHash(const aHash: Int64; var Results: TDynStrings); {---IwbFolder---} function GetPathName: string; public constructor Create(const aPath: string); destructor Destroy; override; end; TwbFolderResource = class(TInterfacedObject, IwbResource) frFolder : IwbFolderInternal; frFileName : string; protected {---IwbResource---} function GetContainer: IwbResourceContainer; function GetData: TBytes; public constructor Create(aFolder: IwbFolderInternal; const aFileName: string); destructor Destroy; override; end; function wbCreateContainerHandler: IwbContainerHandler; begin Result := TwbContainerHandler.Create; end; { TwbContainerHandler } procedure TwbContainerHandler.AddContainer(const aContainer: IwbResourceContainer); begin SetLength(chContainers, Succ(Length(chContainers))); chContainers[High(chContainers)] := aContainer; end; function TwbContainerHandler.ContainerExists(aContainerName: string): Boolean; var i: Integer; begin Result := True; for i := Low(chContainers) to High(chContainers) do if SameText(chContainers[i].Name, aContainerName) then Exit; Result := False; end; procedure TwbContainerHandler.AddBSA(const aFileName: string); begin if not ContainerExists(aFileName) then AddContainer(TwbBSAFile.Create(aFileName)); end; procedure TwbContainerHandler.AddBA2(const aFileName: string); begin if not ContainerExists(aFileName) then AddContainer(TwbBA2File.Create(aFileName)); end; procedure TwbContainerHandler.AddFolder(const aPath: string); begin if not ContainerExists(aPath) then AddContainer(TwbFolder.Create(aPath)); end; function TwbContainerHandler.OpenResource(const aFileName: string): TDynResources; var i, j: Integer; begin SetLength(Result, Length(chContainers)); j := 0; for i := Low(chContainers) to High(chContainers) do begin Result[j] := chContainers[i].OpenResource(aFileName); if Assigned(Result[j]) then Inc(j); end; SetLength(Result, j); end; function TwbContainerHandler.OpenResourceData(const aContainerName, aFileName: string): TBytes; var Res : TDynResources; i : Integer; begin Res := OpenResource(aFileName); if Length(Res) = 0 then Exit; for i := High(Res) downto Low(Res) do if (aContainerName = '') or SameText(Res[i].Container.Name, aContainerName) then begin Result := Res[i].GetData; Break; end; end; procedure TwbContainerHandler.ContainerList(const aList: TStrings); var i: Integer; begin if not Assigned(aList) then Exit; for i := Low(chContainers) to High(chContainers) do aList.Add(chContainers[i].Name); end; procedure TwbContainerHandler.ContainerResourceList(const aContainerName: string; const aList: TStrings; const aFolder: string = ''); var i: Integer; begin for i := Low(chContainers) to High(chContainers) do if SameText(chContainers[i].Name, aContainerName) then begin chContainers[i].ResourceList(aList, aFolder); Break; end; end; function TwbContainerHandler.ResourceExists(const aFileName: string): Boolean; var i: Integer; begin Result := False; for i := Low(chContainers) to High(chContainers) do if chContainers[i].ResourceExists(aFileName) then begin Result := True; Exit; end; end; function TwbContainerHandler.ResolveHash(const aHash: Int64): TDynStrings; var i: Integer; begin Result := nil; for i := Low(chContainers) to High(chContainers) do chContainers[i].ResolveHash(aHash, Result); end; function TwbContainerHandler.ResourceCount(const aFileName: string; aContainers: TStrings = nil): Integer; var i: Integer; begin Result := 0; for i := Low(chContainers) to High(chContainers) do if chContainers[i].ResourceExists(aFileName) then begin Inc(Result); if Assigned(aContainers) then aContainers.Add(chContainers[i].Name); end; end; procedure TwbContainerHandler.ResourceCopy(const aContainerName, aFileName, aPathOut: string); var fn, dir : string; aData : TBytes; res : TDynResources; i, residx : integer; begin if aPathOut = '' then raise Exception.Create('Destination path is not specified'); res := OpenResource(aFileName); if Length(res) = 0 then raise Exception.Create('Resource doesn''t exist'); residx := High(res); for i := High(res) to Low(res) do if (aContainerName = '') or SameText(res[i].Container.Name, aContainerName) then begin residx := i; Break; end; // file name is provided instead of path if TPath.HasExtension(aPathOut) then fn := aPathOut // destination path is provided else fn := IncludeTrailingPathDelimiter(aPathOut) + aFileName; // create distination directory dir := ExtractFilePath(fn); if not DirectoryExists(dir) then if not ForceDirectories(dir) then raise Exception.Create('Unable to create destination directory ' + dir); // direct copy if file is loose, with overwriting if ExtractFileExt(res[residx].Container.Name) = '' then begin TFile.Copy(res[residx].Container.Name + aFileName, fn, True); end // otherwise extract from BSA else begin aData := res[residx].GetData; // exception handled outside with TFileStream.Create(fn, fmCreate) do try WriteBuffer(aData[0], Length(aData)); finally Free; end; end; end; { TwbBSAFile } constructor TwbBSAFile.Create(const aFileName: string); begin bfFileName := aFileName; bfStream := TwbReadOnlyCachedFileStream.Create(aFileName); ReadDirectory; end; destructor TwbBSAFile.Destroy; var i: Integer; begin FreeAndNil(bfStream); for i := Low(bfFolders) to High(bfFolders) do with bfFolders[i] do FreeAndNil(Map); FreeAndNil(bfFolderMap); inherited; end; function TwbBSAFile.GetData(aOffset, aSize: Cardinal): TBytes; var IsCompressed : Boolean; Buffer : TBytes; begin IsCompressed := (aSize and BSAFILE_COMPRESS) <> 0; if IsCompressed then aSize := aSize and not BSAFILE_COMPRESS; if (bfFlags and BSAARCHIVE_COMPRESSFILES) <> 0 then IsCompressed := not IsCompressed; bfStream.Position := aOffset; if (bfVersion >= BSAHEADER_VERSION_SK) and ((bfFlags and BSAARCHIVE_PREFIXFULLFILENAMES) <> 0) then // size - file name length (no terminator) - string length prefix aSize := aSize - Length(bfStream.ReadStringLen(False)) - 1; if IsCompressed then begin SetLength(Result, bfStream.ReadCardinal); aSize := aSize - 4; if (Length(Result) > 0) and (aSize > 0) then begin SetLength(Buffer, aSize); bfStream.ReadBuffer(Buffer[0], Length(Buffer)); if bfVersion = BSAHEADER_VERSION_SSE then lz4DecompressToUserBuf(@Buffer[0], Length(Buffer), @Result[0], Length(Result)) else DecompressToUserBuf(@Buffer[0], Length(Buffer), @Result[0], Length(Result)); end; end else begin SetLength(Result, aSize); if aSize > 0 then bfStream.ReadBuffer(Result[0], aSize); end; end; function TwbBSAFile.GetFileName: string; begin Result := bfFileName; end; function TwbBSAFile.GetName: string; begin Result := GetFileName; end; function TwbBSAFile.OpenResource(const aFileName: string): IwbResource; var lPath, lName: string; i, j: Integer; begin Result := nil; lPath := ExtractFilePath(aFileName); SetLength(lPath, Pred(Length(lPath))); lName := ExtractFileName(aFileName); if bfFolderMap.Find(lPath, i) then with bfFolders[Integer(bfFolderMap.Objects[i])] do if Map.Find(lName, j) then with Files[Integer(Map.Objects[j])] do Result := TwbBSAResource.Create(Self, Size, Offset); end; function TwbBSAFile.ResourceExists(const aFileName: string): Boolean; var lPath, lName: string; i: Integer; begin Result := False; lPath := ExtractFilePath(aFileName); SetLength(lPath, Pred(Length(lPath))); lName := ExtractFileName(aFileName); if bfFolderMap.Find(lPath, i) then Result := bfFolders[Integer(bfFolderMap.Objects[i])].Map.IndexOf(lName) <> -1; end; procedure TwbBSAFile.ResourceList(const aList: TStrings; const aFolder: string = ''); var i, j: Integer; Folder: string; begin if not Assigned(aList) then Exit; Folder := ExcludeTrailingPathDelimiter(aFolder); for i := Low(bfFolders) to High(bfFolders) do with bfFolders[i] do if (aFolder = '') or SameText(Folder, Name) then for j := Low(Files) to High(Files) do aList.Add(Name + '\' + Files[j].Name); end; procedure TwbBSAFile.ReadDirectory; var i, j : Integer; OldPos : Int64; NewPos : Int64; // FileCount : Cardinal; // totalFolderNameLength : Cardinal; totalFileNameLength : Cardinal; begin if bfStream.ReadSignature <> 'BSA' then raise Exception.Create(bfFileName + ' is not a valid BSA file'); bfVersion := bfStream.ReadCardinal; if not (bfVersion in [BSAHEADER_VERSION_OB, BSAHEADER_VERSION_SK, BSAHEADER_VERSION_SSE]) then raise Exception.Create(bfFileName + ' has unknown version: ' + IntToStr(bfVersion) ); bfOffset := bfStream.ReadCardinal; if bfOffset <> $24 then raise Exception.Create(bfFileName + ' has unexpected Offset: ' + IntToStr(bfOffset) ); bfFlags := bfStream.ReadCardinal; SetLength(bfFolders, bfStream.ReadCardinal); {FileCount := } bfStream.ReadCardinal; //skip file count {totalFolderNameLength := } bfStream.ReadCardinal; //skip totalFolderNameLength totalFileNameLength := bfStream.ReadCardinal; //skip totalFileNameLength bfFileFlags := bfStream.ReadCardinal; OldPos := bfStream.Position; for i := Low(bfFolders) to High(bfFolders) do with bfFolders[i] do begin bfStream.Position := OldPos; Hash := bfStream.ReadInt64; // skip hash SetLength(Files, bfStream.ReadCardinal); if bfVersion = BSAHEADER_VERSION_SSE then begin bfStream.ReadCardinal; // skip unk32 NewPos := bfStream.ReadInt64; end else NewPos := bfStream.ReadCardinal; OldPos := bfStream.Position; bfStream.Position := NewPos - totalFileNameLength; Name := bfStream.ReadStringLen; for j := Low(Files) to High(Files) do with Files[j] do begin Hash := bfStream.ReadInt64; // skip hash Size := bfStream.ReadCardinal; Offset := bfStream.ReadCardinal; end; end; bfFolderMap := TwbFastStringList.Create; for i := Low(bfFolders) to High(bfFolders) do with bfFolders[i] do begin bfFolderMap.AddObject(Name, TObject(i)); Map := TwbFastStringList.Create; for j := Low(Files) to High(Files) do with Files[j] do begin Name := bfStream.ReadStringTerm; Map.AddObject(Name, TObject(j)); end; Map.Sorted := True; end; bfFolderMap.Sorted := True; end; procedure TwbBSAFile.ResolveHash(const aHash: Int64; var Results: TDynStrings); var i, j: Integer; begin for i := Low(bfFolders) to High(bfFolders) do with bfFolders[i] do begin if Hash = aHash then begin SetLength(Results, Succ(Length(Results))); Results[High(Results)] := Name; end; for j := Low(Files) to High(Files) do with Files[j] do begin if Hash = aHash then begin SetLength(Results, Succ(Length(Results))); Results[High(Results)] := Name; end; end; end; end; { TwbBSAResource } constructor TwbBSAResource.Create(aFile: TwbBSAFile; aSize, aOffset: Cardinal); begin brFile := aFile; brOffset := aOffset; brSize := aSize; end; function TwbBSAResource.GetContainer: IwbResourceContainer; begin Result := brFile; end; function TwbBSAResource.GetData: TBytes; begin Result := brFile.GetData(brOffset, brSize); end; { TwbBA2File } constructor TwbBA2File.Create(const aFileName: string); begin bfFileName := aFileName; bfStream := TwbReadOnlyCachedFileStream.Create(aFileName); ReadDirectory; end; destructor TwbBA2File.Destroy; var i: integer; begin FreeAndNil(bfStream); for i := 0 to Pred(bfFolderMap.Count) do TStringList(bfFolderMap.Objects[i]).Free; FreeAndNil(bfFolderMap); inherited; end; procedure TwbBA2File.ReadDirectory; var i, j : Integer; OldPos : Int64; FileCount : Cardinal; FileTablePosition: Int64; NumChunks: Byte; folder: string; begin if bfStream.ReadSignature <> 'BTDX' then raise Exception.Create(bfFileName + ' is not a valid BA2 file'); bfVersion := bfStream.ReadCardinal; if bfVersion <> BA2HEADER_VERSION_FO4 then raise Exception.Create(bfFileName + ' has unknown version: ' + IntToStr(bfVersion) ); bfType := bfStream.ReadSignature; if (bfType <> 'GNRL') and (bfType <> 'DX10') then raise Exception.Create(bfFileName + ' has unknown type: ' + String(bfType)); FileCount := bfStream.ReadCardinal; FileTablePosition := bfStream.ReadInt64; OldPos := bfStream.Position; bfStream.Position := FileTablePosition; SetLength(bfFiles, FileCount); for i := Low(bfFiles) to High(bfFiles) do begin bfFiles[i].Name := bfStream.ReadStringLen16; end; bfStream.Position := OldPos; if bfType = 'GNRL' then begin for i := Low(bfFiles) to High(bfFiles) do begin bfFiles[i].NameHash := bfStream.ReadCardinal; bfStream.ReadCardinal; // skip ext bfFiles[i].DirHash := bfStream.ReadCardinal; bfStream.ReadCardinal; // skip unk0C bfFiles[i].Offset := bfStream.ReadInt64; bfFiles[i].PackedSize := bfStream.ReadCardinal; bfFiles[i].Size := bfStream.ReadCardinal; bfStream.ReadCardinal; // skip BAADF00D end; end else if bfType = 'DX10' then begin for i := Low(bfFiles) to High(bfFiles) do begin bfFiles[i].NameHash := bfStream.ReadCardinal; bfStream.ReadCardinal; // skip ext bfFiles[i].DirHash := bfStream.ReadCardinal; bfStream.ReadByte; // skip unk0C NumChunks := bfStream.ReadByte; bfStream.ReadWord; // skip chunkHeaderSize bfFiles[i].Height := bfStream.ReadWord; bfFiles[i].Width := bfStream.ReadWord; bfFiles[i].NumMips := bfStream.ReadByte; bfFiles[i].DXGIFormat := bfStream.ReadByte; bfFiles[i].CubeMaps := bfStream.ReadWord; SetLength(bfFiles[i].TexChunks, NumChunks); for j := Low(bfFiles[i].TexChunks) to High(bfFiles[i].TexChunks) do with bfFiles[i].TexChunks[j] do begin Offset := bfStream.ReadInt64; PackedSize := bfStream.ReadCardinal; Size := bfStream.ReadCardinal; StartMip := bfStream.ReadWord; EndMip := bfStream.ReadWord; bfStream.ReadCardinal; // skip BAADF00D end; end; end; bfFolderMap := TwbFastStringList.Create; bfFolderMap.Sorted := True; for i := Low(bfFiles) to High(bfFiles) do begin folder := LowerCase(ExtractFilePath(bfFiles[i].Name)); SetLength(folder, Pred(Length(folder))); j := bfFolderMap.IndexOf(folder); if not bfFolderMap.Find(folder, j) then begin bfFolderMap.AddObject(folder, TwbFastStringList.Create); if not bfFolderMap.Find(folder, j) then raise Exception.Create('Indexing error'); end; TStringList(bfFolderMap.Objects[j]).AddObject(LowerCase(ExtractFileName(bfFiles[i].Name)), TObject(i)); end; for i := 0 to Pred(bfFolderMap.Count) do TStringList(bfFolderMap.Objects[i]).Sorted := True; end; function TwbBA2File.GetFileName: string; begin Result := bfFileName; end; function TwbBA2File.GetName: string; begin Result := GetFileName; end; procedure TwbBA2File.ReadData(var Buffer; Offset: Int64; Count: Longint); begin bfStream.Position := Offset; bfStream.ReadBuffer(Buffer, Count); end; function TwbBA2File.OpenResource(const aFileName: string): IwbResource; var lPath, lName: string; i, j: Integer; begin lPath := LowerCase(ExtractFilePath(aFileName)); SetLength(lPath, Pred(Length(lPath))); lName := LowerCase(ExtractFileName(aFileName)); if bfFolderMap.Find(lPath, i) then with TStringList(bfFolderMap.Objects[i]) do if Find(lName, j) then Result := TwbBA2Resource.Create(Self, bfFiles[Integer(Objects[j])]); end; procedure TwbBA2File.ResolveHash(const aHash: Int64; var Results: TDynStrings); begin // ... end; function TwbBA2File.ResourceExists(const aFileName: string): Boolean; var lPath, lName: string; i: Integer; begin Result := False; lPath := LowerCase(ExtractFilePath(aFileName)); SetLength(lPath, Pred(Length(lPath))); lName := LowerCase(ExtractFileName(aFileName)); if bfFolderMap.Find(lPath, i) then Result := TStringList(bfFolderMap.Objects[i]).IndexOf(lName) <> -1; end; procedure TwbBA2File.ResourceList(const aList: TStrings; const aFolder: string = ''); var i: Integer; begin if not Assigned(aList) then Exit; for i := Low(bfFiles) to High(bfFiles) do aList.Add(LowerCase(bfFiles[i].Name)); end; { TwbBA2Resource } constructor TwbBA2Resource.Create(aFile: TwbBA2File; var aFileRec: TwbBA2FileRec); begin brFile := aFile; brFileRec := aFileRec; end; function TwbBA2Resource.GetContainer: IwbResourceContainer; begin Result := brFile; end; function TwbBA2Resource.GetData: TBytes; const FOURCC_BC7 = LongWord(Byte('B') or (Byte('C') shl 8) or (Byte('7') shl 16) or (Byte(0) shl 24)); var Buffer : TBytes; Hdr: ^TDDSFileHeader; TexSize, i: integer; begin // GNRL resource if (brFileRec.Size <> 0) and (Length(brFileRec.TexChunks) = 0) then begin if brFileRec.PackedSize <> 0 then begin SetLength(Buffer, brFileRec.PackedSize); brFile.ReadData(Buffer[0], brFileRec.Offset, Length(Buffer)); SetLength(Result, brFileRec.Size); DecompressToUserBuf(@Buffer[0], Length(Buffer), @Result[0], Length(Result)); end else begin SetLength(Result, brFileRec.Size); brFile.ReadData(Result[0], brFileRec.Offset, Length(Result)); end; end // DX10 texture else if Length(brFileRec.TexChunks) <> 0 then begin // calculate texture size including header TexSize := SizeOf(TDDSFileHeader); for i := Low(brFileRec.TexChunks) to High(brFileRec.TexChunks) do Inc(TexSize, brFileRec.TexChunks[i].Size); SetLength(Result, TexSize); // fill DDS header Hdr := @Result[0]; hdr.Magic := DDSMagic; hdr.Desc.Size := SizeOf(hdr.Desc); hdr.Desc.Width := brFileRec.Width; hdr.Desc.Height := brFileRec.Height; hdr.Desc.Flags := DDS_SAVE_FLAGS or DDSD_MIPMAPCOUNT; hdr.Desc.Caps.Caps1 := DDSCAPS_TEXTURE or DDSCAPS_MIPMAP; hdr.Desc.MipMaps := brFileRec.NumMips; if brFileRec.CubeMaps = 2049 then hdr.Desc.Caps.Caps2 := DDSCAPS2_POSITIVEX or DDSCAPS2_NEGATIVEX or DDSCAPS2_POSITIVEY or DDSCAPS2_NEGATIVEY or DDSCAPS2_POSITIVEZ or DDSCAPS2_NEGATIVEZ or DDSCAPS2_CUBEMAP; hdr.Desc.PixelFormat.Size := SizeOf(hdr.Desc.PixelFormat); case TDXGIFormat(brFileRec.DXGIFormat) of DXGI_FORMAT_BC1_UNORM: begin hdr.Desc.PixelFormat.Flags := DDPF_FOURCC; hdr.Desc.PixelFormat.FourCC := FOURCC_DXT1; hdr.Desc.PitchOrLinearSize := brFileRec.Width * brFileRec.Height div 4; end; DXGI_FORMAT_BC2_UNORM: begin hdr.Desc.PixelFormat.Flags := DDPF_FOURCC; hdr.Desc.PixelFormat.FourCC := FOURCC_DXT3; hdr.Desc.PitchOrLinearSize := brFileRec.Width * brFileRec.Height; end; DXGI_FORMAT_BC3_UNORM: begin hdr.Desc.PixelFormat.Flags := DDPF_FOURCC; hdr.Desc.PixelFormat.FourCC := FOURCC_DXT5; hdr.Desc.PitchOrLinearSize := brFileRec.Width * brFileRec.Height; end; DXGI_FORMAT_BC5_UNORM: begin hdr.Desc.PixelFormat.Flags := DDPF_FOURCC; hdr.Desc.PixelFormat.FourCC := FOURCC_ATI2; hdr.Desc.PitchOrLinearSize := brFileRec.Width * brFileRec.Height; end; DXGI_FORMAT_BC7_UNORM: begin hdr.Desc.PixelFormat.Flags := DDPF_FOURCC; hdr.Desc.PixelFormat.FourCC := FOURCC_BC7; hdr.Desc.PitchOrLinearSize := brFileRec.Width * brFileRec.Height; end; DXGI_FORMAT_B8G8R8A8_UNORM: begin hdr.Desc.PixelFormat.Flags := DDPF_RGB; hdr.Desc.PixelFormat.BitCount := 32; hdr.Desc.PixelFormat.RedMask := $00FF0000; hdr.Desc.PixelFormat.GreenMask := $0000FF00; hdr.Desc.PixelFormat.BlueMask := $000000FF; hdr.Desc.PitchOrLinearSize := brFileRec.Width * brFileRec.Height * 4; end; DXGI_FORMAT_R8_UNORM: begin hdr.Desc.PixelFormat.Flags := DDPF_RGB; hdr.Desc.PixelFormat.BitCount := 8; hdr.Desc.PixelFormat.RedMask := $FF; hdr.Desc.PitchOrLinearSize := brFileRec.Width * brFileRec.Height; end; end; // append chunks TexSize := SizeOf(TDDSFileHeader); for i := Low(brFileRec.TexChunks) to High(brFileRec.TexChunks) do with brFileRec.TexChunks[i] do begin // compressed chunk if PackedSize <> 0 then begin SetLength(Buffer, PackedSize); brFile.ReadData(Buffer[0], Offset, Length(Buffer)); DecompressToUserBuf(@Buffer[0], Length(Buffer), @Result[TexSize], Size); end // uncompressed chunk else brFile.ReadData(Result[TexSize], Offset, Size); Inc(TexSize, Size); end; end; end; { TwbFolder } constructor TwbFolder.Create(const aPath: string); begin fPath := IncludeTrailingPathDelimiter(aPath); end; destructor TwbFolder.Destroy; begin inherited; end; function TwbFolder.GetPathName: string; begin Result := fPath; end; function TwbFolder.GetName: string; begin Result := GetPathName; end; function TwbFolder.OpenResource(const aFileName: string): IwbResource; var s: string; begin s := fPath + aFileName; if FileExists(s) then Result := TwbFolderResource.Create(Self, s); end; function TwbFolder.ResourceExists(const aFileName: string): Boolean; begin Result := FileExists(fPath + aFileName); end; procedure TwbFolder.ResourceList(const aList: TStrings; const aFolder: string = ''); var FileName: string; begin if not Assigned(aList) then Exit; if TDirectory.Exists(fPath + aFolder) then for FileName in TDirectory.GetFiles(fPath + aFolder, '*.*', TSearchOption.soAllDirectories) do aList.Add(LowerCase(Copy(FileName, Length(fPath) + 1, Length(FileName)))); end; procedure TwbFolder.ResolveHash(const aHash: Int64; var Results: TDynStrings); begin //... end; { TwbFolderResource } constructor TwbFolderResource.Create(aFolder: IwbFolderInternal; const aFileName: string); begin frFolder := aFolder; frFileName := aFileName; end; destructor TwbFolderResource.Destroy; begin inherited; end; function TwbFolderResource.GetContainer: IwbResourceContainer; begin Result := frFolder; end; function TwbFolderResource.GetData: TBytes; begin with TFileStream.Create(frFileName, fmOpenRead or fmShareDenyWrite) do try SetLength(Result, Size); if Length(Result) > 0 then ReadBuffer(Result[0], Length(Result)); finally Free; end; end; end. ================================================ FILE: lib/xedit/wbDefines.inc ================================================ {******************************************************************************* The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. *******************************************************************************} {.$DEFINE USE_CODESITE} ================================================ FILE: lib/xedit/wbDefinitionsFNV.pas ================================================ {******************************************************************************* The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. *******************************************************************************} unit wbDefinitionsFNV; {$I wbDefines.inc} interface uses wbInterface; var wbAggroRadiusFlags: IwbFlagsDef; wbPKDTFlags: IwbFlagsDef; wbRecordFlagsFlags: IwbFlagsDef; wbServiceFlags: IwbFlagsDef; wbTemplateFlags: IwbFlagsDef; wbAgressionEnum: IwbEnumDef; wbAlignmentEnum: IwbEnumDef; wbArchtypeEnum: IwbEnumDef; wbAssistanceEnum: IwbEnumDef; wbAttackAnimationEnum: IwbEnumDef; wbAxisEnum: IwbEnumDef; wbBlendModeEnum: IwbEnumDef; wbBlendOpEnum: IwbEnumDef; wbBodyLocationEnum: IwbEnumDef; wbBodyPartIndexEnum: IwbEnumDef; wbConfidenceEnum: IwbEnumDef; wbCreatureTypeEnum: IwbEnumDef; wbCrimeTypeEnum: IwbEnumDef; wbCriticalStageEnum: IwbEnumDef; wbEquipTypeEnum: IwbEnumDef; wbFormTypeEnum: IwbEnumDef; wbFunctionsEnum: IwbEnumDef; wbHeadPartIndexEnum: IwbEnumDef; wbImpactMaterialTypeEnum: IwbEnumDef; wbMenuModeEnum: IwbEnumDef; wbMiscStatEnum: IwbEnumDef; wbModEffectEnum: IwbEnumDef; wbMoodEnum: IwbEnumDef; wbMusicEnum: IwbEnumDef; wbObjectTypeEnum: IwbEnumDef; wbPKDTType: IwbEnumDef; wbPlayerActionEnum: IwbEnumDef; wbQuadrantEnum: IwbEnumDef; wbReloadAnimEnum: IwbEnumDef; wbSexEnum: IwbEnumDef; wbSkillEnum: IwbEnumDef; wbSoundLevelEnum: IwbEnumDef; wbSpecializationEnum: IwbEnumDef; wbVatsValueFunctionEnum: IwbEnumDef; wbWeaponAnimTypeEnum: IwbEnumDef; wbZTestFuncEnum: IwbEnumDef; function wbCreaLevelDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; procedure DefineFNV; implementation uses Types, Classes, SysUtils, Math, Variants, wbHelpers; const _00_IAD: TwbSignature = #$00'IAD'; _40_IAD: TwbSignature = #$40'IAD'; _01_IAD: TwbSignature = #$01'IAD'; _41_IAD: TwbSignature = #$41'IAD'; _02_IAD: TwbSignature = #$02'IAD'; _42_IAD: TwbSignature = #$42'IAD'; _03_IAD: TwbSignature = #$03'IAD'; _43_IAD: TwbSignature = #$43'IAD'; _04_IAD: TwbSignature = #$04'IAD'; _44_IAD: TwbSignature = #$44'IAD'; _05_IAD: TwbSignature = #$05'IAD'; _45_IAD: TwbSignature = #$45'IAD'; _06_IAD: TwbSignature = #$06'IAD'; _46_IAD: TwbSignature = #$46'IAD'; _07_IAD: TwbSignature = #$07'IAD'; _47_IAD: TwbSignature = #$47'IAD'; _08_IAD: TwbSignature = #$08'IAD'; _48_IAD: TwbSignature = #$48'IAD'; _09_IAD: TwbSignature = #$09'IAD'; _49_IAD: TwbSignature = #$49'IAD'; _0A_IAD: TwbSignature = #$0A'IAD'; _4A_IAD: TwbSignature = #$4A'IAD'; _0B_IAD: TwbSignature = #$0B'IAD'; _4B_IAD: TwbSignature = #$4B'IAD'; _0C_IAD: TwbSignature = #$0C'IAD'; _4C_IAD: TwbSignature = #$4C'IAD'; _0D_IAD: TwbSignature = #$0D'IAD'; _4D_IAD: TwbSignature = #$4D'IAD'; _0E_IAD: TwbSignature = #$0E'IAD'; _4E_IAD: TwbSignature = #$4E'IAD'; _0F_IAD: TwbSignature = #$0F'IAD'; _4F_IAD: TwbSignature = #$4F'IAD'; _10_IAD: TwbSignature = #$10'IAD'; _50_IAD: TwbSignature = #$50'IAD'; _11_IAD: TwbSignature = #$11'IAD'; _51_IAD: TwbSignature = #$51'IAD'; _12_IAD: TwbSignature = #$12'IAD'; _52_IAD: TwbSignature = #$52'IAD'; _13_IAD: TwbSignature = #$13'IAD'; _53_IAD: TwbSignature = #$53'IAD'; _14_IAD: TwbSignature = #$14'IAD'; _54_IAD: TwbSignature = #$54'IAD'; _0_IAD : TwbSignature = #0'IAD'; _1_IAD : TwbSignature = #1'IAD'; _2_IAD : TwbSignature = #2'IAD'; _3_IAD : TwbSignature = #3'IAD'; _4_IAD : TwbSignature = #4'IAD'; _5_IAD : TwbSignature = #5'IAD'; ACBS : TwbSignature = 'ACBS'; ACHR : TwbSignature = 'ACHR'; ACRE : TwbSignature = 'ACRE'; ACTI : TwbSignature = 'ACTI'; ADDN : TwbSignature = 'ADDN'; AIDT : TwbSignature = 'AIDT'; ALCH : TwbSignature = 'ALCH'; AMMO : TwbSignature = 'AMMO'; ANAM : TwbSignature = 'ANAM'; ANIO : TwbSignature = 'ANIO'; ARMA : TwbSignature = 'ARMA'; ARMO : TwbSignature = 'ARMO'; ASPC : TwbSignature = 'ASPC'; ATTR : TwbSignature = 'ATTR'; ATXT : TwbSignature = 'ATXT'; AVIF : TwbSignature = 'AVIF'; BIPL : TwbSignature = 'BIPL'; BMCT : TwbSignature = 'BMCT'; BMDT : TwbSignature = 'BMDT'; BNAM : TwbSignature = 'BNAM'; BOOK : TwbSignature = 'BOOK'; BPND : TwbSignature = 'BPND'; BPNI : TwbSignature = 'BPNI'; BPNN : TwbSignature = 'BPNN'; BPNT : TwbSignature = 'BPNT'; BPTD : TwbSignature = 'BPTD'; BPTN : TwbSignature = 'BPTN'; BTXT : TwbSignature = 'BTXT'; CAMS : TwbSignature = 'CAMS'; CELL : TwbSignature = 'CELL'; CLAS : TwbSignature = 'CLAS'; CLMT : TwbSignature = 'CLMT'; CNAM : TwbSignature = 'CNAM'; MMRK : TwbSignature = 'MMRK'; CNTO : TwbSignature = 'CNTO'; COBJ : TwbSignature = 'COBJ'; COED : TwbSignature = 'COED'; CONT : TwbSignature = 'CONT'; CPTH : TwbSignature = 'CPTH'; CRDT : TwbSignature = 'CRDT'; CREA : TwbSignature = 'CREA'; CSAD : TwbSignature = 'CSAD'; CSCR : TwbSignature = 'CSCR'; CSDC : TwbSignature = 'CSDC'; CSDI : TwbSignature = 'CSDI'; CSDT : TwbSignature = 'CSDT'; CSSD : TwbSignature = 'CSSD'; CSTD : TwbSignature = 'CSTD'; CSTY : TwbSignature = 'CSTY'; CTDA : TwbSignature = 'CTDA'; DATA : TwbSignature = 'DATA'; DAT2 : TwbSignature = 'DAT2'; DEBR : TwbSignature = 'DEBR'; DELE : TwbSignature = 'DELE'; DESC : TwbSignature = 'DESC'; DEST : TwbSignature = 'DEST'; DIAL : TwbSignature = 'DIAL'; DMDL : TwbSignature = 'DMDL'; DMDT : TwbSignature = 'DMDT'; DNAM : TwbSignature = 'DNAM'; DOBJ : TwbSignature = 'DOBJ'; DODT : TwbSignature = 'DODT'; DOOR : TwbSignature = 'DOOR'; DSTD : TwbSignature = 'DSTD'; DSTF : TwbSignature = 'DSTF'; EAMT : TwbSignature = 'EAMT'; ECZN : TwbSignature = 'ECZN'; EDID : TwbSignature = 'EDID'; EFID : TwbSignature = 'EFID'; EFIT : TwbSignature = 'EFIT'; EFSD : TwbSignature = 'EFSD'; EFSH : TwbSignature = 'EFSH'; EITM : TwbSignature = 'EITM'; ENAM : TwbSignature = 'ENAM'; ENCH : TwbSignature = 'ENCH'; ENIT : TwbSignature = 'ENIT'; EPF2 : TwbSignature = 'EPF2'; EPF3 : TwbSignature = 'EPF3'; EPFD : TwbSignature = 'EPFD'; EPFT : TwbSignature = 'EPFT'; ESCE : TwbSignature = 'ESCE'; ETYP : TwbSignature = 'ETYP'; EXPL : TwbSignature = 'EXPL'; EYES : TwbSignature = 'EYES'; FACT : TwbSignature = 'FACT'; FGGA : TwbSignature = 'FGGA'; FGGS : TwbSignature = 'FGGS'; FGTS : TwbSignature = 'FGTS'; FLST : TwbSignature = 'FLST'; FLTV : TwbSignature = 'FLTV'; FNAM : TwbSignature = 'FNAM'; FULL : TwbSignature = 'FULL'; FURN : TwbSignature = 'FURN'; GLOB : TwbSignature = 'GLOB'; RDID : TwbSignature = 'RDID'; RDSI : TwbSignature = 'RDSI'; RDSB : TwbSignature = 'RDSB'; GMST : TwbSignature = 'GMST'; GNAM : TwbSignature = 'GNAM'; GRAS : TwbSignature = 'GRAS'; HAIR : TwbSignature = 'HAIR'; HCLR : TwbSignature = 'HCLR'; HDPT : TwbSignature = 'HDPT'; HEDR : TwbSignature = 'HEDR'; HNAM : TwbSignature = 'HNAM'; ICO2 : TwbSignature = 'ICO2'; ICON : TwbSignature = 'ICON'; IDLA : TwbSignature = 'IDLA'; IDLB : TwbSignature = 'IDLB'; IDLC : TwbSignature = 'IDLC'; IDLE : TwbSignature = 'IDLE'; IDLF : TwbSignature = 'IDLF'; IDLM : TwbSignature = 'IDLM'; IDLT : TwbSignature = 'IDLT'; IMAD : TwbSignature = 'IMAD'; IMGS : TwbSignature = 'IMGS'; INAM : TwbSignature = 'INAM'; INDX : TwbSignature = 'INDX'; INFO : TwbSignature = 'INFO'; INGR : TwbSignature = 'INGR'; IPCT : TwbSignature = 'IPCT'; IPDS : TwbSignature = 'IPDS'; ITXT : TwbSignature = 'ITXT'; JNAM : TwbSignature = 'JNAM'; KEYM : TwbSignature = 'KEYM'; KFFZ : TwbSignature = 'KFFZ'; KNAM : TwbSignature = 'KNAM'; LAND : TwbSignature = 'LAND'; LGTM : TwbSignature = 'LGTM'; LIGH : TwbSignature = 'LIGH'; LNAM : TwbSignature = 'LNAM'; LSCR : TwbSignature = 'LSCR'; LTEX : TwbSignature = 'LTEX'; LTMP : TwbSignature = 'LTMP'; LVLC : TwbSignature = 'LVLC'; LVLD : TwbSignature = 'LVLD'; LVLF : TwbSignature = 'LVLF'; LVLG : TwbSignature = 'LVLG'; LVLI : TwbSignature = 'LVLI'; LVLN : TwbSignature = 'LVLN'; LVLO : TwbSignature = 'LVLO'; MAST : TwbSignature = 'MAST'; MESG : TwbSignature = 'MESG'; MGEF : TwbSignature = 'MGEF'; MICN : TwbSignature = 'MICN'; MICO : TwbSignature = 'MICO'; MIC2 : TwbSignature = 'MIC2'; MISC : TwbSignature = 'MISC'; MNAM : TwbSignature = 'MNAM'; MO2B : TwbSignature = 'MO2B'; MO2S : TwbSignature = 'MO2S'; MO2T : TwbSignature = 'MO2T'; MO3B : TwbSignature = 'MO3B'; MO3S : TwbSignature = 'MO3S'; MO3T : TwbSignature = 'MO3T'; MO4B : TwbSignature = 'MO4B'; MO4S : TwbSignature = 'MO4S'; MO4T : TwbSignature = 'MO4T'; MOD2 : TwbSignature = 'MOD2'; VANM : TwbSignature = 'VANM'; MOD3 : TwbSignature = 'MOD3'; MOD4 : TwbSignature = 'MOD4'; MODB : TwbSignature = 'MODB'; MODD : TwbSignature = 'MODD'; MODL : TwbSignature = 'MODL'; MODS : TwbSignature = 'MODS'; MODT : TwbSignature = 'MODT'; MOSD : TwbSignature = 'MOSD'; MSTT : TwbSignature = 'MSTT'; MUSC : TwbSignature = 'MUSC'; IMPS : TwbSignature = 'IMPS'; IMPF : TwbSignature = 'IMPF'; NAM0 : TwbSignature = 'NAM0'; NAM1 : TwbSignature = 'NAM1'; NAM2 : TwbSignature = 'NAM2'; NAM3 : TwbSignature = 'NAM3'; NAM4 : TwbSignature = 'NAM4'; NAM5 : TwbSignature = 'NAM5'; NAM6 : TwbSignature = 'NAM6'; NAM7 : TwbSignature = 'NAM7'; NAM8 : TwbSignature = 'NAM8'; NAM9 : TwbSignature = 'NAM9'; NAME : TwbSignature = 'NAME'; NAVI : TwbSignature = 'NAVI'; NAVM : TwbSignature = 'NAVM'; NEXT : TwbSignature = 'NEXT'; NIFT : TwbSignature = 'NIFT'; NIFZ : TwbSignature = 'NIFZ'; NNAM : TwbSignature = 'NNAM'; XSRF : TwbSignature = 'XSRF'; XSRD : TwbSignature = 'XSRD'; MWD1 : TwbSignature = 'MWD1'; MWD2 : TwbSignature = 'MWD2'; MWD3 : TwbSignature = 'MWD3'; MWD4 : TwbSignature = 'MWD4'; MWD5 : TwbSignature = 'MWD5'; MWD6 : TwbSignature = 'MWD6'; MWD7 : TwbSignature = 'MWD7'; WNM1 : TwbSignature = 'WNM1'; WNM2 : TwbSignature = 'WNM2'; WNM3 : TwbSignature = 'WNM3'; WNM4 : TwbSignature = 'WNM4'; WNM5 : TwbSignature = 'WNM5'; WNM6 : TwbSignature = 'WNM6'; WNM7 : TwbSignature = 'WNM7'; WMI1 : TwbSignature = 'WMI1'; WMI2 : TwbSignature = 'WMI2'; WMI3 : TwbSignature = 'WMI3'; WMS1 : TwbSignature = 'WMS1'; WMS2 : TwbSignature = 'WMS2'; NOTE : TwbSignature = 'NOTE'; NPC_ : TwbSignature = 'NPC_'; NULL : TwbSignature = 'NULL'; NVCA : TwbSignature = 'NVCA'; NVCI : TwbSignature = 'NVCI'; NVDP : TwbSignature = 'NVDP'; NVER : TwbSignature = 'NVER'; NVEX : TwbSignature = 'NVEX'; NVGD : TwbSignature = 'NVGD'; NVMI : TwbSignature = 'NVMI'; NVTR : TwbSignature = 'NVTR'; NVVX : TwbSignature = 'NVVX'; OBND : TwbSignature = 'OBND'; OFST : TwbSignature = 'OFST'; ONAM : TwbSignature = 'ONAM'; PACK : TwbSignature = 'PACK'; PBEA : TwbSignature = 'PBEA'; PERK : TwbSignature = 'PERK'; PFIG : TwbSignature = 'PFIG'; PFPC : TwbSignature = 'PFPC'; PGAG : TwbSignature = 'PGAG'; PGRE : TwbSignature = 'PGRE'; PMIS : TwbSignature = 'PMIS'; TRGT : TwbSignature = 'TRGT'; PGRI : TwbSignature = 'PGRI'; PGRL : TwbSignature = 'PGRL'; PGRP : TwbSignature = 'PGRP'; PGRR : TwbSignature = 'PGRR'; PKAM : TwbSignature = 'PKAM'; PKDD : TwbSignature = 'PKDD'; PKDT : TwbSignature = 'PKDT'; PKE2 : TwbSignature = 'PKE2'; PKED : TwbSignature = 'PKED'; PKFD : TwbSignature = 'PKFD'; PKID : TwbSignature = 'PKID'; PKPT : TwbSignature = 'PKPT'; PKW3 : TwbSignature = 'PKW3'; PLD2 : TwbSignature = 'PLD2'; PLDT : TwbSignature = 'PLDT'; PLYR : TwbSignature = 'PLYR'; PNAM : TwbSignature = 'PNAM'; TDUM : TwbSignature = 'TDUM'; POBA : TwbSignature = 'POBA'; POCA : TwbSignature = 'POCA'; POEA : TwbSignature = 'POEA'; PRKC : TwbSignature = 'PRKC'; PRKE : TwbSignature = 'PRKE'; PRKF : TwbSignature = 'PRKF'; PROJ : TwbSignature = 'PROJ'; PSDT : TwbSignature = 'PSDT'; PTD2 : TwbSignature = 'PTD2'; PTDT : TwbSignature = 'PTDT'; PUID : TwbSignature = 'PUID'; PWAT : TwbSignature = 'PWAT'; QNAM : TwbSignature = 'QNAM'; RCIL : TwbSignature = 'RCIL'; RCQY : TwbSignature = 'RCQY'; RCOD : TwbSignature = 'RCOD'; QOBJ : TwbSignature = 'QOBJ'; QSDT : TwbSignature = 'QSDT'; QSTA : TwbSignature = 'QSTA'; QSTI : TwbSignature = 'QSTI'; TPIC : TwbSignature = 'TPIC'; QSTR : TwbSignature = 'QSTR'; INFC : TwbSignature = 'INFC'; INFX : TwbSignature = 'INFX'; QUST : TwbSignature = 'QUST'; RACE : TwbSignature = 'RACE'; RADS : TwbSignature = 'RADS'; RAFB : TwbSignature = 'RAFB'; RAFD : TwbSignature = 'RAFD'; RAGA : TwbSignature = 'RAGA'; RAPS : TwbSignature = 'RAPS'; RCLR : TwbSignature = 'RCLR'; RDAT : TwbSignature = 'RDAT'; RDMD : TwbSignature = 'RDMD'; RDMO : TwbSignature = 'RDMO'; RDMP : TwbSignature = 'RDMP'; RDGS : TwbSignature = 'RDGS'; RDOT : TwbSignature = 'RDOT'; RDSD : TwbSignature = 'RDSD'; RDWT : TwbSignature = 'RDWT'; REFR : TwbSignature = 'REFR'; REGN : TwbSignature = 'REGN'; REPL : TwbSignature = 'REPL'; RGDL : TwbSignature = 'RGDL'; RNAM : TwbSignature = 'RNAM'; RPLD : TwbSignature = 'RPLD'; RPLI : TwbSignature = 'RPLI'; SCDA : TwbSignature = 'SCDA'; SCHR : TwbSignature = 'SCHR'; SCOL : TwbSignature = 'SCOL'; SCPT : TwbSignature = 'SCPT'; SCRI : TwbSignature = 'SCRI'; SCRN : TwbSignature = 'SCRN'; SCRO : TwbSignature = 'SCRO'; SCRV : TwbSignature = 'SCRV'; SCTX : TwbSignature = 'SCTX'; SCVR : TwbSignature = 'SCVR'; SLCP : TwbSignature = 'SLCP'; SLSD : TwbSignature = 'SLSD'; SNAM : TwbSignature = 'SNAM'; SNDD : TwbSignature = 'SNDD'; SNDX : TwbSignature = 'SNDX'; SOUL : TwbSignature = 'SOUL'; SOUN : TwbSignature = 'SOUN'; SPEL : TwbSignature = 'SPEL'; SPIT : TwbSignature = 'SPIT'; SPLO : TwbSignature = 'SPLO'; STAT : TwbSignature = 'STAT'; BRUS : TwbSignature = 'BRUS'; TACT : TwbSignature = 'TACT'; TCLF : TwbSignature = 'TCLF'; TCFU : TwbSignature = 'TCFU'; TCLT : TwbSignature = 'TCLT'; TERM : TwbSignature = 'TERM'; TES4 : TwbSignature = 'TES4'; TNAM : TwbSignature = 'TNAM'; TPLT : TwbSignature = 'TPLT'; TRDT : TwbSignature = 'TRDT'; TREE : TwbSignature = 'TREE'; TX00 : TwbSignature = 'TX00'; TX01 : TwbSignature = 'TX01'; INTV : TwbSignature = 'INTV'; TX02 : TwbSignature = 'TX02'; TX03 : TwbSignature = 'TX03'; TX04 : TwbSignature = 'TX04'; TX05 : TwbSignature = 'TX05'; TXST : TwbSignature = 'TXST'; UNAM : TwbSignature = 'UNAM'; VATS : TwbSignature = 'VATS'; VCLR : TwbSignature = 'VCLR'; VHGT : TwbSignature = 'VHGT'; VNAM : TwbSignature = 'VNAM'; VNML : TwbSignature = 'VNML'; VTCK : TwbSignature = 'VTCK'; VTEX : TwbSignature = 'VTEX'; VTXT : TwbSignature = 'VTXT'; VTYP : TwbSignature = 'VTYP'; WATR : TwbSignature = 'WATR'; WEAP : TwbSignature = 'WEAP'; WLST : TwbSignature = 'WLST'; WNAM : TwbSignature = 'WNAM'; XATO : TwbSignature = 'XATO'; WRLD : TwbSignature = 'WRLD'; WTHR : TwbSignature = 'WTHR'; XACT : TwbSignature = 'XACT'; XAMC : TwbSignature = 'XAMC'; XAMT : TwbSignature = 'XAMT'; XAPD : TwbSignature = 'XAPD'; XAPR : TwbSignature = 'XAPR'; XCAS : TwbSignature = 'XCAS'; XCCM : TwbSignature = 'XCCM'; XCET : TwbSignature = 'XCET'; XCHG : TwbSignature = 'XCHG'; XCIM : TwbSignature = 'XCIM'; XCLC : TwbSignature = 'XCLC'; XCLL : TwbSignature = 'XCLL'; XCLP : TwbSignature = 'XCLP'; XCLR : TwbSignature = 'XCLR'; XCLW : TwbSignature = 'XCLW'; XCMO : TwbSignature = 'XCMO'; XCMT : TwbSignature = 'XCMT'; XCNT : TwbSignature = 'XCNT'; XCWT : TwbSignature = 'XCWT'; XEMI : TwbSignature = 'XEMI'; XESP : TwbSignature = 'XESP'; XEZN : TwbSignature = 'XEZN'; XGLB : TwbSignature = 'XGLB'; XHLP : TwbSignature = 'XHLP'; XDCR : TwbSignature = 'XDCR'; XHLT : TwbSignature = 'XHLT'; XIBS : TwbSignature = 'XIBS'; XLCM : TwbSignature = 'XLCM'; XLKR : TwbSignature = 'XLKR'; XLOC : TwbSignature = 'XLOC'; XLOD : TwbSignature = 'XLOD'; XLRM : TwbSignature = 'XLRM'; XLTW : TwbSignature = 'XLTW'; XMBO : TwbSignature = 'XMBO'; XMBP : TwbSignature = 'XMBP'; XMBR : TwbSignature = 'XMBR'; XMRC : TwbSignature = 'XMRC'; XMRK : TwbSignature = 'XMRK'; XNAM : TwbSignature = 'XNAM'; XNDP : TwbSignature = 'XNDP'; XOCP : TwbSignature = 'XOCP'; XORD : TwbSignature = 'XORD'; XOWN : TwbSignature = 'XOWN'; XPOD : TwbSignature = 'XPOD'; XPTL : TwbSignature = 'XPTL'; XPPA : TwbSignature = 'XPPA'; XPRD : TwbSignature = 'XPRD'; XPRM : TwbSignature = 'XPRM'; XPWR : TwbSignature = 'XPWR'; XRAD : TwbSignature = 'XRAD'; XRDO : TwbSignature = 'XRDO'; XRDS : TwbSignature = 'XRDS'; XRGB : TwbSignature = 'XRGB'; XRGD : TwbSignature = 'XRGD'; XRMR : TwbSignature = 'XRMR'; XRNK : TwbSignature = 'XRNK'; XRTM : TwbSignature = 'XRTM'; XSCL : TwbSignature = 'XSCL'; XSED : TwbSignature = 'XSED'; XTEL : TwbSignature = 'XTEL'; XTRG : TwbSignature = 'XTRG'; XTRI : TwbSignature = 'XTRI'; XXXX : TwbSignature = 'XXXX'; YNAM : TwbSignature = 'YNAM'; ZNAM : TwbSignature = 'ZNAM'; IMOD : TwbSignature = 'IMOD'; REPU : TwbSignature = 'REPU'; RCPE : TwbSignature = 'RCPE'; RCCT : TwbSignature = 'RCCT'; CHIP : TwbSignature = 'CHIP'; CSNO : TwbSignature = 'CSNO'; LSCT : TwbSignature = 'LSCT'; MSET : TwbSignature = 'MSET'; ALOC : TwbSignature = 'ALOC'; CHAL : TwbSignature = 'CHAL'; AMEF : TwbSignature = 'AMEF'; CCRD : TwbSignature = 'CCRD'; CARD : TwbSignature = 'CARD'; CMNY : TwbSignature = 'CMNY'; CDCK : TwbSignature = 'CDCK'; DEHY : TwbSignature = 'DEHY'; HUNG : TwbSignature = 'HUNG'; SLPD : TwbSignature = 'SLPD'; var wbPKDTSpecificFlagsUnused : Boolean; wbEDID: IwbSubRecordDef; wbEDIDReq: IwbSubRecordDef; wbBMDT: IwbSubRecordDef; wbYNAM: IwbSubRecordDef; wbZNAM: IwbSubRecordDef; wbCOED: IwbSubRecordDef; wbXLCM: IwbSubRecordDef; wbEITM: IwbSubRecordDef; wbREPL: IwbSubRecordDef; wbBIPL: IwbSubRecordDef; wbOBND: IwbSubRecordDef; wbOBNDReq: IwbSubRecordDef; wbDEST: IwbSubRecordStructDef; wbDESTActor: IwbSubRecordStructDef; wbDODT: IwbSubRecordDef; wbXOWN: IwbSubRecordDef; wbXGLB: IwbSubRecordDef; wbXRGD: IwbSubRecordDef; wbXRGB: IwbSubRecordDef; wbSLSD: IwbSubRecordDef; wbSPLO: IwbSubRecordDef; wbSPLOs: IwbSubRecordArrayDef; wbCNTO: IwbSubRecordStructDef; wbCNTOs: IwbSubRecordArrayDef; wbAIDT: IwbSubRecordDef; wbCSDT: IwbSubRecordStructDef; wbCSDTs: IwbSubRecordArrayDef; wbFULL: IwbSubRecordDef; wbFULLActor: IwbSubRecordDef; wbFULLReq: IwbSubRecordDef; wbXNAM: IwbSubRecordDef; wbXNAMs: IwbSubRecordArrayDef; wbDESC: IwbSubRecordDef; wbDESCReq: IwbSubRecordDef; wbXSCL: IwbSubRecordDef; wbDATAPosRot : IwbSubRecordDef; wbPosRot : IwbStructDef; wbMODD: IwbSubRecordDef; wbMOSD: IwbSubRecordDef; wbMODL: IwbSubRecordStructDef; wbMODS: IwbSubRecordDef; wbMO2S: IwbSubRecordDef; wbMO3S: IwbSubRecordDef; wbMO4S: IwbSubRecordDef; wbMODLActor: IwbSubRecordStructDef; wbMODLReq: IwbSubRecordStructDef; wbCTDA: IwbSubRecordDef; wbSCHRReq: IwbSubRecordDef; wbCTDAs: IwbSubRecordArrayDef; wbCTDAsReq: IwbSubRecordArrayDef; wbSCROs: IwbSubRecordArrayDef; wbPGRP: IwbSubRecordDef; wbEmbeddedScript: IwbSubRecordStructDef; wbEmbeddedScriptPerk: IwbSubRecordStructDef; wbEmbeddedScriptReq: IwbSubRecordStructDef; wbSCRI: IwbSubRecordDef; wbSCRIActor: IwbSubRecordDef; wbFaceGen: IwbSubRecordStructDef; wbFaceGenNPC: IwbSubRecordStructDef; wbENAM: IwbSubRecordDef; wbFGGS: IwbSubRecordDef; wbXLOD: IwbSubRecordDef; wbXESP: IwbSubRecordDef; wbICON: IwbSubRecordStructDef; wbICONReq: IwbSubRecordStructDef; wbActorValue: IwbIntegerDef; wbETYP: IwbSubRecordDef; wbETYPReq: IwbSubRecordDef; wbEFID: IwbSubRecordDef; wbEFIT: IwbSubRecordDef; wbEffects: IwbSubRecordArrayDef; wbEffectsReq: IwbSubRecordArrayDef; wbBPNDStruct: IwbSubRecordDef; wbTimeInterpolator: IwbStructDef; wbColorInterpolator: IwbStructDef; function wbNVTREdgeToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Index : Integer; Flags : Cardinal; IsExternal : Boolean; Container : IwbContainerElementRef; begin Result := ''; IsExternal := False; if Supports(aElement, IwbContainerElementRef, Container) then begin Index := StrToIntDef(Copy(Container.Name, 11, 1), -1); if (Index >= 0) and (Index <= 2) then begin Flags := Container.ElementNativeValues['..\..\Flags']; IsExternal := Flags and (Cardinal(1) shl Index) <> 0; end; end; if IsExternal then begin case aType of ctToStr: begin Result := IntToStr(aInt); if Container.ElementExists['..\..\..\..\NVEX\Connection #' + IntToStr(aInt)] then Result := Result + ' (Triangle #' + Container.ElementValues['..\..\..\..\NVEX\Connection #' + IntToStr(aInt) + '\Triangle'] + ' in ' + Container.ElementValues['..\..\..\..\NVEX\Connection #' + IntToStr(aInt) + '\Navigation Mesh'] + ')' else Result := Result + ' '; end; ctToSortKey: if Container.ElementExists['..\..\..\..\NVEX\Connection #' + IntToStr(aInt)] then Result := Container.ElementSortKeys['..\..\..\..\NVEX\Connection #' + IntToStr(aInt) + '\Navigation Mesh', True] + '|' + Container.ElementSortKeys['..\..\..\..\NVEX\Connection #' + IntToStr(aInt) + '\Triangle', True]; ctCheck: if Container.ElementExists['..\..\..\..\NVEX\Connection #' + IntToStr(aInt)] then Result := '' else Result := 'NVEX\Connection #' + IntToStr(aInt) + ' is missing'; end end else case aType of ctToStr: Result := IntToStr(aInt); end; end; function wbNVTREdgeToInt(const aString: string; const aElement: IwbElement): Int64; begin Result := StrToInt64(aString); end; function wbEPFDActorValueToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var AsCardinal : Cardinal; AsFloat : Single; begin AsCardinal := aInt; AsFloat := PSingle(@AsCardinal)^; aInt := Round(AsFloat); case aType of ctToStr: Result := wbActorValueEnum.ToString(aInt, aElement); ctToSortKey: Result := wbActorValueEnum.ToSortKey(aInt, aElement); ctCheck: Result := wbActorValueEnum.Check(aInt, aElement); ctToEditValue: Result := wbActorValueEnum.ToEditValue(aInt, aElement); ctEditType: Result := 'ComboBox'; ctEditInfo: Result := wbActorValueEnum.EditInfo[aInt, aElement]; end; end; function wbEPFDActorValueToInt(const aString: string; const aElement: IwbElement): Int64; var AsCardinal : Cardinal; AsFloat : Single; begin AsFloat := wbActorValueEnum.FromEditValue(aString, aElement); PSingle(@AsCardinal)^ := AsFloat; Result := AsCardinal; end; function wbCTDAParam2VariableNameToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainerElementRef; //Container2 : IwbContainerElementRef; Param1 : IwbElement; MainRecord : IwbMainRecord; BaseRecord : IwbMainRecord; ScriptRef : IwbElement; Script : IwbMainRecord; Variables : TStringList; LocalVars : IwbContainerElementRef; LocalVar : IwbContainerElementRef; i, j : Integer; s : string; begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctToEditValue: Result := IntToStr(aInt); ctToSortKey: begin Result := IntToHex64(aInt, 8); Exit; end; ctCheck: Result := ''; ctEditType: Result := ''; ctEditInfo: Result := ''; end; if not Assigned(aElement) then Exit; Container := GetContainerRefFromUnionOrValue(aElement); if not Assigned(Container) then Exit; Param1 := Container.ElementByName['Parameter #1']; if not Assigned(Param1) then Exit; MainRecord := nil; if not Supports(Param1.LinksTo, IwbMainRecord, MainRecord) then Exit; { if Param1.NativeValue = 0 then if Supports(Container.Container, IwbContainerElementRef, Container) then for i := 0 to Pred(Container.ElementCount) do if Supports(Container.Elements[i], IwbContainerElementRef, Container2) then if SameText(Container2.ElementValues['Function'], 'GetIsID') then begin Param1 := Container2.ElementByName['Parameter #1']; if Supports(Param1.LinksTo, IwbMainRecord, MainRecord) then Break; end;} if not Assigned(MainRecord) then Exit; BaseRecord := MainRecord.BaseRecord; if Assigned(BaseRecord) then MainRecord := BaseRecord; ScriptRef := MainRecord.RecordBySignature['SCRI']; if not Assigned(ScriptRef) then begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end; Exit; end; if not Supports(ScriptRef.LinksTo, IwbMainRecord, Script) then begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end; Exit; end; Script := Script.HighestOverrideOrSelf[aElement._File.LoadOrder]; case aType of ctEditType: begin Result := 'ComboBox'; Exit; end; ctEditInfo: Variables := TStringList.Create; else Variables := nil; end; try if Supports(Script.ElementByName['Local Variables'], IwbContainerElementRef, LocalVars) then begin for i := 0 to Pred(LocalVars.ElementCount) do if Supports(LocalVars.Elements[i], IwbContainerElementRef, LocalVar) then begin j := LocalVar.ElementNativeValues['SLSD\Index']; s := LocalVar.ElementNativeValues['SCVR']; if Assigned(Variables) then Variables.AddObject(s, TObject(j)) else if j = aInt then begin case aType of ctToStr, ctToEditValue: Result := s; ctCheck: Result := ''; end; Exit; end; end; end; case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; ctEditInfo: begin Variables.Sort; Result := Variables.CommaText; end; end; finally FreeAndNil(Variables); end; end; function wbCTDAParam2VariableNameToInt(const aString: string; const aElement: IwbElement): Int64; var Container : IwbContainerElementRef; Param1 : IwbElement; MainRecord : IwbMainRecord; BaseRecord : IwbMainRecord; ScriptRef : IwbElement; Script : IwbMainRecord; LocalVars : IwbContainerElementRef; LocalVar : IwbContainerElementRef; i, j : Integer; s : string; begin Result := StrToInt64Def(aString, Low(Cardinal)); if Result <> Low(Cardinal) then Exit; if not Assigned(aElement) then raise Exception.Create('aElement not specified'); Container := GetContainerRefFromUnionOrValue(aElement); if not Assigned(Container) then raise Exception.Create('Container not assigned'); Param1 := Container.ElementByName['Parameter #1']; if not Assigned(Param1) then raise Exception.Create('Could not find "Parameter #1"'); if not Supports(Param1.LinksTo, IwbMainRecord, MainRecord) then raise Exception.Create('"Parameter #1" does not reference a valid main record'); BaseRecord := MainRecord.BaseRecord; if Assigned(BaseRecord) then MainRecord := BaseRecord; ScriptRef := MainRecord.RecordBySignature['SCRI']; if not Assigned(ScriptRef) then raise Exception.Create('"'+MainRecord.ShortName+'" does not contain a SCRI subrecord'); if not Supports(ScriptRef.LinksTo, IwbMainRecord, Script) then raise Exception.Create('"'+MainRecord.ShortName+'" does not have a valid script'); Script := Script.HighestOverrideOrSelf[aElement._File.LoadOrder]; if Supports(Script.ElementByName['Local Variables'], IwbContainerElementRef, LocalVars) then begin for i := 0 to Pred(LocalVars.ElementCount) do if Supports(LocalVars.Elements[i], IwbContainerElementRef, LocalVar) then begin j := LocalVar.ElementNativeValues['SLSD\Index']; s := LocalVar.ElementNativeValues['SCVR']; if SameText(s, Trim(aString)) then begin Result := j; Exit; end; end; end; raise Exception.Create('Variable "'+aString+'" was not found in "'+MainRecord.ShortName+'"'); end; function wbCTDAParam2QuestStageToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainerElementRef; Param1 : IwbElement; MainRecord : IwbMainRecord; EditInfos : TStringList; Stages : IwbContainerElementRef; Stage : IwbContainerElementRef; i, j : Integer; s, t : string; begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctToEditValue: Result := IntToStr(aInt); ctToSortKey: begin Result := IntToHex64(aInt, 8); Exit; end; ctCheck: Result := ''; ctEditType: Result := ''; ctEditInfo: Result := ''; end; if not Assigned(aElement) then Exit; Container := GetContainerRefFromUnionOrValue(aElement); if not Assigned(Container) then Exit; Param1 := Container.ElementByName['Parameter #1']; if not Assigned(Param1) then Exit; if not Supports(Param1.LinksTo, IwbMainRecord, MainRecord) then Exit; MainRecord := MainRecord.WinningOverride; if MainRecord.Signature <> QUST then begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end; Exit; end; case aType of ctEditType: begin Result := 'ComboBox'; Exit; end; ctEditInfo: EditInfos := TStringList.Create; else EditInfos := nil; end; try if Supports(MainRecord.ElementByName['Stages'], IwbContainerElementRef, Stages) then begin for i := 0 to Pred(Stages.ElementCount) do if Supports(Stages.Elements[i], IwbContainerElementRef, Stage) then begin j := Stage.ElementNativeValues['INDX']; s := Trim(Stage.ElementValues['Log Entries\Log Entry\CNAM']); t := IntToStr(j); while Length(t) < 3 do t := '0' + t; if s <> '' then t := t + ' ' + s; if Assigned(EditInfos) then EditInfos.AddObject(t, TObject(j)) else if j = aInt then begin case aType of ctToStr, ctToEditValue: Result := t; ctCheck: Result := ''; end; Exit; end; end; end; case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; ctEditInfo: begin EditInfos.Sort; Result := EditInfos.CommaText; end; end; finally FreeAndNil(EditInfos); end; end; function wbPerkDATAQuestStageToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainerElementRef; Param1 : IwbElement; MainRecord : IwbMainRecord; EditInfos : TStringList; Stages : IwbContainerElementRef; Stage : IwbContainerElementRef; i, j : Integer; s, t : string; begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctToEditValue: Result := IntToStr(aInt); ctToSortKey: begin Result := IntToHex64(aInt, 8); Exit; end; ctCheck: Result := ''; ctEditType: Result := ''; ctEditInfo: Result := ''; end; if not Assigned(aElement) then Exit; Container := GetContainerRefFromUnionOrValue(aElement); if not Assigned(Container) then Exit; Param1 := Container.ElementByName['Quest']; if not Assigned(Param1) then Exit; if not Supports(Param1.LinksTo, IwbMainRecord, MainRecord) then Exit; MainRecord := MainRecord.WinningOverride; if MainRecord.Signature <> QUST then begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end; Exit; end; case aType of ctEditType: begin Result := 'ComboBox'; Exit; end; ctEditInfo: EditInfos := TStringList.Create; else EditInfos := nil; end; try if Supports(MainRecord.ElementByName['Stages'], IwbContainerElementRef, Stages) then begin for i := 0 to Pred(Stages.ElementCount) do if Supports(Stages.Elements[i], IwbContainerElementRef, Stage) then begin j := Stage.ElementNativeValues['INDX']; s := Trim(Stage.ElementValues['Log Entries\Log Entry\CNAM']); t := IntToStr(j); while Length(t) < 3 do t := '0' + t; if s <> '' then t := t + ' ' + s; if Assigned(EditInfos) then EditInfos.AddObject(t, TObject(j)) else if j = aInt then begin case aType of ctToStr, ctToEditValue: Result := t; ctCheck: Result := ''; end; Exit; end; end; end; case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; ctEditInfo: begin EditInfos.Sort; Result := EditInfos.CommaText; end; end; finally FreeAndNil(EditInfos); end; end; function wbCTDAParam2QuestObjectiveToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainerElementRef; Param1 : IwbElement; MainRecord : IwbMainRecord; EditInfos : TStringList; Objectives : IwbContainerElementRef; Objective : IwbContainerElementRef; i, j : Integer; s, t : string; begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctToEditValue: Result := IntToStr(aInt); ctToSortKey: begin Result := IntToHex64(aInt, 8); Exit; end; ctCheck: Result := ''; ctEditType: Result := ''; ctEditInfo: Result := ''; end; if not Assigned(aElement) then Exit; Container := GetContainerRefFromUnionOrValue(aElement); if not Assigned(Container) then Exit; Param1 := Container.ElementByName['Parameter #1']; if not Assigned(Param1) then Exit; if not Supports(Param1.LinksTo, IwbMainRecord, MainRecord) then Exit; MainRecord := MainRecord.WinningOverride; if MainRecord.Signature <> QUST then begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end; Exit; end; case aType of ctEditType: begin Result := 'ComboBox'; Exit; end; ctEditInfo: EditInfos := TStringList.Create; else EditInfos := nil; end; try if Supports(MainRecord.ElementByName['Objectives'], IwbContainerElementRef, Objectives) then begin for i := 0 to Pred(Objectives.ElementCount) do if Supports(Objectives.Elements[i], IwbContainerElementRef, Objective) then begin j := Objective.ElementNativeValues['QOBJ']; s := Trim(Objective.ElementValues['NNAM']); t := IntToStr(j); while Length(t) < 3 do t := '0' + t; if s <> '' then t := t + ' ' + s; if Assigned(EditInfos) then EditInfos.AddObject(t, TObject(j)) else if j = aInt then begin case aType of ctToStr, ctToEditValue: Result := t; ctCheck: Result := ''; end; Exit; end; end; end; case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; ctEditInfo: begin EditInfos.Sort; Result := EditInfos.CommaText; end; end; finally FreeAndNil(EditInfos); end; end; function wbCTDAParam2QuestStageToInt(const aString: string; const aElement: IwbElement): Int64; var i : Integer; s : string; begin i := 1; s := Trim(aString); while (i <= Length(s)) and (s[i] in ['0'..'9']) do Inc(i); s := Copy(s, 1, Pred(i)); Result := StrToInt(s); end; function wbCTDAParam2QuestObjectiveToInt(const aString: string; const aElement: IwbElement): Int64; var i : Integer; s : string; begin i := 1; s := Trim(aString); while (i <= Length(s)) and (s[i] in ['0'..'9']) do Inc(i); s := Copy(s, 1, Pred(i)); Result := StrToInt(s); end; function wbClmtMoonsPhaseLength(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var PhaseLength : Byte; Masser : Boolean; Secunda : Boolean; begin Result := ''; if aType = ctToSortKey then begin Result := IntToHex64(aInt, 2); end else if aType = ctToStr then begin PhaseLength := aInt mod 64; Masser := (aInt and 64) <> 0; Secunda := (aInt and 128) <> 0; if Masser then if Secunda then Result := 'Masser, Secunda / ' else Result := 'Masser / ' else if Secunda then Result := 'Secunda / ' else Result := 'No Moon / '; Result := Result + IntToStr(PhaseLength); end; end; function wbClmtTime(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; begin if aType = ctToSortKey then Result := IntToHex64(aInt, 4) else if aType = ctToStr then Result := TimeToStr( EncodeTime(aInt div 6, (aInt mod 6) * 10, 0, 0) ) else Result := ''; end; function wbAlocTime(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; begin if aType = ctToSortKey then Result := IntToHex64(aInt, 4) else if aType = ctToStr then Result := TimeToStr( aInt / 256 ) else Result := ''; end; function wbREFRNavmeshTriangleToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainerElementRef; Navmesh : IwbElement; MainRecord : IwbMainRecord; Triangles : IwbContainerElementRef; begin case aType of ctToStr: Result := IntToStr(aInt); ctToEditValue: Result := IntToStr(aInt); ctToSortKey: begin Result := IntToHex64(aInt, 8); Exit; end; ctCheck: Result := ''; ctEditType: Result := ''; ctEditInfo: Result := ''; end; if not Assigned(aElement) then Exit; Container := GetContainerRefFromUnionOrValue(aElement); if not Assigned(Container) then Exit; Navmesh := Container.Elements[0]; if not Assigned(Navmesh) then Exit; if not Supports(Navmesh.LinksTo, IwbMainRecord, MainRecord) then Exit; MainRecord := MainRecord.WinningOverride; if MainRecord.Signature <> NAVM then begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end; Exit; end; if not wbSimpleRecords and (aType = ctCheck) and Supports(MainRecord.ElementByPath['NVTR'], IwbContainerElementRef, Triangles) then if aInt >= Triangles.ElementCount then Result := ''; end; function wbStringToInt(const aString: string; const aElement: IwbElement): Int64; begin Result := StrToIntDef(aString, 0); end; var wbCtdaTypeFlags : IwbFlagsDef; function wbCtdaTypeToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var s: string; begin Result := ''; case aType of ctEditType: Result := 'CheckComboBox'; ctEditInfo: Result := 'Equal,Greater,Lesser,Or,"Use Global","Run on Target"'; ctToEditValue: begin Result := '000000'; case aInt and $F0 of $00 : Result[1] := '1'; $40 : Result[2] := '1'; $60 : begin Result[1] := '1'; Result[2] := '1'; end; $80 : Result[3] := '1'; $A0 : begin Result[1] := '1'; Result[3] := '1'; end; end; if (aInt and $01) <> 0 then Result[4] := '1'; if (aInt and $02) <> 0 then Result[6] := '1'; if (aInt and $04) <> 0 then Result[5] := '1'; end; ctToStr: begin case aInt and $F0 of $00 : Result := 'Equal to'; $20 : Result := 'Not equal to'; $40 : Result := 'Greater than'; $60 : Result := 'Greater than or equal to'; $80 : Result := 'Less than'; $A0 : Result := 'Less than or equal to'; else Result := '' end; if not Assigned(wbCtdaTypeFlags) then wbCtdaTypeFlags := wbFlags([ {0x01} 'Or', {0x02} 'Run on target', {0x04} 'Use global' ]); s := wbCtdaTypeFlags.ToString(aInt and $0F, aElement); if s <> '' then Result := Result + ' / ' + s; end; ctToSortKey: begin Result := IntToHex64(aInt, 2); Exit; end; ctCheck: begin case aInt and $F0 of $00, $20, $40, $60, $80, $A0 : Result := ''; else Result := '' end; if not Assigned(wbCtdaTypeFlags) then wbCtdaTypeFlags := wbFlags([ {0x01} 'Or', {0x02} 'Run on target', {0x04} 'Use global' ]); s := wbCtdaTypeFlags.Check(aInt and $0F, aElement); if s <> '' then Result := Result + ' / ' + s; end; end; end; function wbCtdaTypeToInt(const aString: string; const aElement: IwbElement): Int64; var s: string; begin s := aString + '000000'; // Result := 0; if s[1] = '1' then begin if s[2] = '1' then begin if s[3] = '1' then begin Result := $00; end else begin Result := $60; end; end else begin if s[3] = '1' then begin Result := $A0; end else begin Result := $00; end; end; end else begin if s[2] = '1' then begin if s[3] = '1' then begin Result := $20; end else begin Result := $40; end; end else begin if s[3] = '1' then begin Result := $80; end else begin Result := $20; end; end; end; if s[4] = '1' then Result := Result or $01; if s[6] = '1' then Result := Result or $02; if s[5] = '1' then Result := Result or $04; end; procedure wbHeadPartsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var Container : IwbContainerElementRef; begin if wbBeginInternalEdit then try if Supports(aElement, IwbContainerElementRef, Container) then if (Container.Elements[0].NativeValue = 1) and (Container.ElementCount > 2) then Container.RemoveElement(1); finally wbEndInternalEdit; end; end; procedure wbMESGDNAMAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var OldValue, NewValue : Integer; Container : IwbContainerElementRef; begin if VarSameValue(aOldValue, aNewValue) then Exit; if Supports(aElement.Container, IwbContainerElementRef, Container) then begin OldValue := Integer(aOldValue) and 1; NewValue := Integer(aNewValue) and 1; if NewValue = OldValue then Exit; if NewValue = 1 then Container.RemoveElement('TNAM') else Container.Add('TNAM', True); end; end; procedure wbGMSTEDIDAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var OldValue, NewValue : string; Container : IwbContainerElementRef; begin if VarSameValue(aOldValue, aNewValue) then Exit; if Supports(aElement.Container, IwbContainerElementRef, Container) then begin OldValue := aOldValue; NewValue := aNewValue; if (Length(OldValue) < 1) or (Length(OldValue) < 1) or (OldValue[1] <> NewValue[1]) then begin Container.RemoveElement('DATA'); Container.Add('DATA', True); end; end; end; procedure wbFLSTEDIDAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var OldValue, NewValue : string; OldOrdered, NewOrdered : Boolean; Container : IwbContainerElementRef; const OrderedList = 'OrderedList'; begin if VarSameValue(aOldValue, aNewValue) then Exit; if Supports(aElement.Container, IwbContainerElementRef, Container) then begin OldValue := aOldValue; NewValue := aNewValue; if Length(OldValue) > Length(OrderedList) then Delete(OldValue, 1, Length(OldValue)-Length(OrderedList)); if Length(NewValue) > Length(OrderedList) then Delete(NewValue, 1, Length(NewValue)-Length(OrderedList)); OldOrdered := SameText(OldValue, OrderedList); NewOrdered := SameText(NewValue, OrderedList); if OldOrdered <> NewOrdered then Container.RemoveElement('FormIDs'); end; end; procedure wbCtdaTypeAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var OldValue, NewValue: Integer; Container: IwbContainerElementRef; begin if VarSameValue(aOldValue, aNewValue) then Exit; if not Supports(aElement, IwbContainerElementRef, Container) then Exit; OldValue := aOldValue and $04; NewValue := aNewValue and $04; if OldValue <> NewValue then Container.ElementNativeValues['..\Comparison Value'] := 0; if aNewValue and $02 then begin Container.ElementNativeValues['..\Run On'] := 1; if Integer(Container.ElementNativeValues['..\Run On']) = 1 then aElement.NativeValue := Byte(aNewValue) and not $02; end; end; function wbMODTCallback(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Strings: TDynStrings; i: Integer; begin Result := ''; if wbLoaderDone and (aType in [ctToStr, ctToSortKey] ) then begin Strings := wbContainerHandler.ResolveHash(aInt); for i := Low(Strings) to High(Strings) do Result := Result + Strings[i] + ', '; SetLength(Result, Length(Result) -2 ); end; end; function wbIdleAnam(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; begin Result := ''; case aType of ctToStr: begin case aInt and not $C0 of 0: Result := 'Idle'; 1: Result := 'Movement'; 2: Result := 'Left Arm'; 3: Result := 'Left Hand'; 4: Result := 'Weapon'; 5: Result := 'Weapon Up'; 6: Result := 'Weapon Down'; 7: Result := 'Special Idle'; 20: Result := 'Whole Body'; 21: Result := 'Upper Body'; else Result := ''; end; if (aInt and $80) = 0 then Result := Result + ', Must return a file'; if (aInt and $40) = 1 then Result := Result + ', Unknown Flag'; end; ctToSortKey: begin Result := IntToHex64(aInt, 2); end; ctCheck: begin case aInt and not $C0 of 0..7, 20, 21: Result := ''; else Result := ''; end; end; end; end; function wbScaledInt4ToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; const PlusMinus : array[Boolean] of string = ('+', '-'); begin Result := ''; case aType of ctToStr, ctToEditValue: Result := FloatToStrF(aInt / 10000, ffFixed, 99, 4); ctToSortKey: begin Result := FloatToStrF(aInt / 10000, ffFixed, 99, 4); if Length(Result) < 22 then Result := StringOfChar('0', 22 - Length(Result)) + Result; Result := PlusMinus[aInt < 0] + Result; end; ctCheck: Result := ''; end; end; function wbScaledInt4ToInt(const aString: string; const aElement: IwbElement): Int64; var f: Extended; begin f := StrToFloat(aString); f := f * 10000; Result := Round(f); end; function wbHideFFFF(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; begin Result := ''; if aType = ctToSortKey then Result := IntToHex64(aInt, 4) else if aType = ctToStr then if aInt = $FFFF then Result := 'None' else Result := IntToStr(aInt); end; function wbAtxtPosition(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; begin Result := ''; if aType = ctToSortKey then Result := IntToHex64(aInt div 17, 2) + IntToHex64(aInt mod 17, 2) else if aType = ctCheck then begin if (aInt < 0) or (aInt > 288) then Result := '' else Result := ''; end else if aType = ctToStr then Result := IntToStr(aInt) + ' -> ' + IntToStr(aInt div 17) + ':' + IntToStr(aInt mod 17); end; function wbGLOBFNAM(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; begin Result := ''; case aType of ctToStr: begin case aInt of Ord('s'): Result := 'Short'; Ord('l'): Result := 'Long'; Ord('f'): Result := 'Float'; else Result := ''; end; end; ctToSortKey: Result := Chr(aInt); ctCheck: begin case aInt of Ord('s'), Ord('l'), Ord('f'): Result := ''; else Result := ''; end; end; end; end; function wbPlacedAddInfo(const aMainRecord: IwbMainRecord): string; var Rec: IwbRecord; Container: IwbContainer; s: string; Cell: IwbMainRecord; Position: TwbVector; Grid: TwbGridCell; begin Result := ''; Rec := aMainRecord.RecordBySignature['NAME']; if Assigned(Rec) then begin s := Trim(Rec.Value); if s <> '' then Result := 'places ' + s; end; Container := aMainRecord.Container; while Assigned(Container) and (Container.ElementType <> etGroupRecord) do Container := Container.Container; if Assigned(Container) then begin s := Trim(Container.Name); if s <> '' then begin if Result <> '' then Result := Result + ' '; Result := Result + 'in ' + s; // grid position of persistent reference in exterior persistent cell (interior cells are not persistent) if Supports(aMainRecord.Container, IwbGroupRecord, Container) then Cell := IwbGroupRecord(Container).ChildrenOf; if Assigned(Cell) and Cell.IsPersistent and (Cell.Signature = 'CELL') then if aMainRecord.GetPosition(Position) then begin Grid := wbPositionToGridCell(Position); Result := Result + ' at ' + IntToStr(Grid.x) + ',' + IntToStr(Grid.y); end; end; end; end; function wbINFOAddInfo(const aMainRecord: IwbMainRecord): string; var Container: IwbContainer; s: string; begin Result := Trim(aMainRecord.ElementValues['Responses\Response\NAM1']); if Result <> '' then Result := '''' + Result + ''''; Container := aMainRecord.Container; while Assigned(Container) and (Container.ElementType <> etGroupRecord) do Container := Container.Container; if Assigned(Container) then begin s := Trim(Container.Name); if s <> '' then begin if Result <> '' then Result := Result + ' '; Result := Result + 'in ' + s; end; end; s := Trim(aMainRecord.ElementValues['QSTI']); if s <> '' then begin if Result <> '' then Result := Result + ' '; Result := Result + 'for ' + s; end; end; function wbNAVMAddInfo(const aMainRecord: IwbMainRecord): string; var Rec : IwbRecord; Element : IwbElement; s : string; begin Result := ''; Rec := aMainRecord.RecordBySignature['DATA']; if Assigned(Rec) then begin Element := Rec.ElementByName['Cell']; if Assigned(Element) then Element := Element.LinksTo; if Assigned(Element) then s := Trim(Element.Name); if s <> '' then Result := 'for ' + s; end; end; function wbCellAddInfo(const aMainRecord: IwbMainRecord): string; var Rec: IwbRecord; Container: IwbContainer; GroupRecord : IwbGroupRecord; s: string; begin Result := ''; if not aMainRecord.IsPersistent then begin Rec := aMainRecord.RecordBySignature['XCLC']; if Assigned(Rec) then Result := 'at ' + Rec.Elements[0].Value + ',' + Rec.Elements[1].Value; end; Container := aMainRecord.Container; while Assigned(Container) and not (Supports(Container, IwbGroupRecord, GroupRecord) and (GroupRecord.GroupType = 1)) do Container := Container.Container; if Assigned(Container) then begin s := wbFormID.ToString(GroupRecord.GroupLabel, aMainRecord); if s <> '' then begin if Result <> '' then s := s + ' '; Result := 'in ' + s + Result; end; end; end; function wbWthrDataClassification(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; begin Result := ''; case aType of ctToStr: begin case aInt and not 192 of 0: Result := 'None'; 1: Result := 'Pleasant'; 2: Result := 'Cloudy'; 4: Result := 'Rainy'; 8: Result := 'Snow'; else Result := ''; end; end; ctToSortKey: begin Result := IntToHex64(aInt, 2) end; ctCheck: begin case aInt and not 192 of 0, 1, 2, 4, 8: Result := ''; else Result := ''; end; end; end; end; function wbNOTETNAMDecide(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var rDATA: IwbRecord; begin Result := 0; rDATA := aElement.Container.RecordBySignature[DATA]; if Assigned(rDATA) then if rDATA.NativeValue = 3 then //Voice Result := 1; end; function wbNOTESNAMDecide(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var rDATA: IwbRecord; begin Result := 0; rDATA := aElement.Container.RecordBySignature[DATA]; if Assigned(rDATA) then if rDATA.NativeValue = 3 then //Voice Result := 1; end; function wbIPDSDATACount(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; begin if Assigned(aBasePtr) and Assigned(aEndPtr) then Result := (Cardinal(aBasePtr) - Cardinal(aBasePtr)) div 4 else Result := 12; end; function wbNAVINAVMGetCount1(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var DataContainer : IwbDataContainer; begin Result := 0; if Supports(aElement, IwbDataContainer, DataContainer) then begin if DataContainer.ElementType = etArray then if not Supports(DataContainer.Container, IwbDataContainer, DataContainer) then Exit; Assert(DataContainer.Name = 'Data'); Result := PWord(Cardinal(DataContainer.DataBasePtr) + 3*3*4)^; end; end; function wbNAVINAVMGetCount2(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var DataContainer : IwbDataContainer; begin Result := 0; if Supports(aElement, IwbDataContainer, DataContainer) then begin if DataContainer.ElementType = etArray then if not Supports(DataContainer.Container, IwbDataContainer, DataContainer) then Exit; Assert(DataContainer.Name = 'Data'); Result := PWord(Cardinal(DataContainer.DataBasePtr) + 3*3*4 + 2)^; end; end; procedure wbCTDARunOnAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin if aOldValue <> aNewValue then if aNewValue <> 2 then aElement.Container.ElementNativeValues['Reference'] := 0; end; procedure wbPERKPRKETypeAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var Container : IwbContainerElementRef; // rDATA : IwbRecord; begin if aOldValue <> aNewValue then if Supports(aElement.Container, IwbContainerElementRef, Container) then begin if Supports(Container.Container, IwbContainerElementRef, Container) then begin Container.RemoveElement('DATA'); Container.Add('DATA', True); Container.RemoveElement('Perk Conditions'); Container.RemoveElement('Entry Point Function Parameters'); if aNewValue = 2 then begin Container.Add('EPFT', True); Container.ElementNativeValues['DATA\Entry Point\Function'] := 2; end; end; end; end; function wbMGEFFAssocItemDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; Archtype : Variant; DataContainer : IwbDataContainer; Element : IwbElement; const OffsetArchtype = 56; begin Result := 1; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; VarClear(ArchType); Element := Container.ElementByName['Archtype']; if Assigned(Element) then ArchType := Element.NativeValue else if Supports(Container, IwbDataContainer, DataContainer) and DataContainer.IsValidOffset(aBasePtr, aEndPtr, OffsetArchtype) then begin // we are part of a proper structure aBasePtr := Pointer(Cardinal(aBasePtr) + OffsetArchtype); ArchType := PCardinal(aBasePtr)^; end; if not VarIsEmpty(ArchType) then case Integer(ArchType) of 01: Result := 2;//Script 18: Result := 3;//Bound Item 19: Result := 4;//Summon Creature else Result := 0; end; end; procedure wbMGEFFAssocItemAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var Container : IwbContainer; Element : IwbElement; begin if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; if (aNewValue <> 0) then begin Element := Container.ElementByName['Archtype']; if Assigned(Element) and Element.NativeValue = 0 then Element.NativeValue := $FF; // Signals ArchType that it should not mess with us on the next change! end; end; procedure wbMGEFArchtypeAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var Container: IwbContainerElementRef; begin if VarSameValue(aOldValue, aNewValue) then Exit; if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if (aNewValue < $FF) and (aOldValue < $FF) then begin Container.ElementNativeValues['..\Assoc. Item'] := 0; case Integer(aNewValue) of 11: Container.ElementNativeValues['..\Actor Value'] := 48;//Invisibility 12: Container.ElementNativeValues['..\Actor Value'] := 49;//Chameleon 24: Container.ElementNativeValues['..\Actor Value'] := 47;//Paralysis 36: Container.ElementNativeValues['..\Actor Value'] := 51;//Turbo else Container.ElementNativeValues['..\Actor Value'] := -1; end; end; end; procedure wbCounterEffectsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterByPathAfterSet('DATA - Data\Counter effect count', aElement); end; procedure wbMGEFAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterContainerByPathAfterSet('DATA - Data\Counter effect count', 'Counter Effects', aElement); end; function wbCTDAReferenceDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; if Integer(Container.ElementNativeValues['Run On']) = 2 then Result := 1; end; function wbNAVINVMIDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; case Integer(Container.ElementNativeValues['Type']) of $00: Result :=1; $20: Result :=2; $30: Result :=3; end; end; function wbIMGSSkinDimmerDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; SubRecord : IwbSubRecord; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; if Supports(Container, IwbSubRecord, SubRecord) then if SubRecord.SubRecordHeaderSize in [132, 148] then Result := 1; end; function wbCOEDOwnerDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; LinksTo : IwbElement; MainRecord : IwbMainRecord; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; LinksTo := Container.ElementByName['Owner'].LinksTo; if Supports(LinksTo, IwbMainRecord, MainRecord) then if MainRecord.Signature = 'NPC_' then Result := 1 else if MainRecord.Signature = 'FACT' then Result := 2; end; function wbCreaLevelDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container: IwbContainer; i: Int64; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; i := Container.ElementByName['Flags'].NativeValue; if i and $00000080 <> 0 then Result := 1; end; function wbGMSTUnionDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var rEDID: IwbRecord; s: string; begin Result := 1; rEDID := aElement.Container.RecordBySignature[EDID]; if Assigned(rEDID) then begin s := rEDID.Value; if Length(s) > 0 then case s[1] of 's': Result := 0; 'f': Result := 2; end; end; end; function wbFLSTLNAMIsSorted(const aContainer: IwbContainer): Boolean; var rEDID : IwbRecord; s : string; _File : IwbFile; MainRecord : IwbMainRecord; const OrderedList = 'OrderedList'; begin Result := wbSortFLST; {>>> Should not be sorted according to Arthmoor and JustinOther, left as sorted for compatibility <<<} rEDID := aContainer.RecordBySignature[EDID]; if Assigned(rEDID) then begin s := rEDID.Value; if Length(s) > Length(OrderedList) then Delete(s, 1, Length(s)-Length(OrderedList)); if SameText(s, OrderedList) then Result := False; end; if Result then begin MainRecord := aContainer.ContainingMainRecord; if not Assigned(MainRecord) then Exit; MainRecord := MainRecord.MasterOrSelf; if not Assigned(MainRecord) then Exit; _File := MainRecord._File; if not Assigned(_File) then Exit; if not SameText(_File.FileName, 'WeaponModKits.esp') then Exit; case (MainRecord.FormID and $FFFFFF) of $0130EB, $0130ED, $01522D, $01522E, $0158D5, $0158D6, $0158D7, $0158D8, $0158D9, $0158DA, $0158DC, $0158DD, $018E20: Result := False; end; end; end; function wbPerkDATADecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var rPRKE: IwbRecord; eType: IwbElement; begin Result := 0; rPRKE := aElement.Container.RecordBySignature[PRKE]; if Assigned(rPRKE) then begin eType := rPRKE.ElementByName['Type']; if Assigned(eType) then begin Result := eType.NativeValue; end; end; end; function wbEPFDDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container: IwbContainerElementRef; begin Result := 0; if not Assigned(aElement) then Exit; if not Supports(aElement.Container, IwbContainerElementRef, Container) then Exit; Result := Container.ElementNativeValues['EPFT']; if Result = 2 then if Integer(Container.ElementNativeValues['..\DATA\Entry Point\Function']) = 5 then Result := 5; end; type TCTDAFunctionParamType = ( ptNone, ptInteger, ptVariableName, //Integer ptSex, //Enum: Male, Female ptActorValue, //Enum: wbActorValue ptCrimeType, //?? Enum ptAxis, //?? Char ptQuestStage, //?? Integer ptMiscStat, //?? Enum ptAlignment, //?? Enum ptEquipType, //?? Enum ptFormType, //?? Enum ptCriticalStage, //?? Enum ptObjectReference, //REFR, ACHR, ACRE, PGRE ptInventoryObject, //ARMO, BOOK, MISC, WEAP, AMMO, KEYM, ALCH, NOTE, ARMA ptActor, //ACHR, ACRE ptVoiceType, //VTYP ptIdleForm, //IDLE ptFormList, //FLST ptNote, //NOTE ptQuest, //QUST ptFaction, //FACT ptWeapon, //WEAP ptCell, //CELL ptClass, //CLAS ptRace, //RACE ptActorBase, //NPC_, CREA ptGlobal, //GLOB ptWeather, //WTHR ptPackage, //PACK ptEncounterZone, //ECZN ptPerk, //PERK ptOwner, //FACT, NPC_ ptFurniture, //FURN ptMagicItem, //SPEL ptMagicEffect, //MGEF ptWorldspace, //WRLD ptVATSValueFunction, ptVATSValueParam, ptCreatureType, ptMenuMode, ptPlayerAction, ptBodyLocation, ptReferencableObject, //TREE, SOUN, ACTI, DOOR, STAT, FURN, CONT, ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, LIGH, GRAS, ASPC, IDLM, ARMA, MSTT, NOTE, PWAT, SCOL, TACT, TERM ptQuestObjective, //?? Integer ptReputation, //REPU ptRegion, //REGN ptChallenge, //CHAL ptCasino, //CSNO ptAnyForm // Any form ); PCTDAFunction = ^TCTDAFunction; TCTDAFunction = record Index: Integer; Name: string; ParamType1: TCTDAFunctionParamType; ParamType2: TCTDAFunctionParamType; end; const wbCTDAFunctions : array[0..288] of TCTDAFunction = ( (Index: 1; Name: 'GetDistance'; ParamType1: ptObjectReference), (Index: 5; Name: 'GetLocked'), (Index: 6; Name: 'GetPos'; ParamType1: ptAxis), (Index: 8; Name: 'GetAngle'; ParamType1: ptAxis), (Index: 10; Name: 'GetStartingPos'; ParamType1: ptAxis), (Index: 11; Name: 'GetStartingAngle'; ParamType1: ptAxis), (Index: 12; Name: 'GetSecondsPassed'), (Index: 14; Name: 'GetActorValue'; ParamType1: ptActorValue), (Index: 18; Name: 'GetCurrentTime'), (Index: 24; Name: 'GetScale'), (Index: 25; Name: 'IsMoving'), (Index: 26; Name: 'IsTurning'), (Index: 27; Name: 'GetLineOfSight'; ParamType1: ptObjectReference), (Index: 32; Name: 'GetInSameCell'; ParamType1: ptObjectReference), (Index: 35; Name: 'GetDisabled'), (Index: 36; Name: 'MenuMode'; ParamType1: ptMenuMode), (Index: 39; Name: 'GetDisease'), (Index: 40; Name: 'GetVampire'), (Index: 41; Name: 'GetClothingValue'), (Index: 42; Name: 'SameFaction'; ParamType1: ptActor), (Index: 43; Name: 'SameRace'; ParamType1: ptActor), (Index: 44; Name: 'SameSex'; ParamType1: ptActor), (Index: 45; Name: 'GetDetected'; ParamType1: ptActor), (Index: 46; Name: 'GetDead'), (Index: 47; Name: 'GetItemCount'; ParamType1: ptInventoryObject), (Index: 48; Name: 'GetGold'), (Index: 49; Name: 'GetSleeping'), (Index: 50; Name: 'GetTalkedToPC'), (Index: 53; Name: 'GetScriptVariable'; ParamType1: ptObjectReference; ParamType2: ptVariableName), (Index: 56; Name: 'GetQuestRunning'; ParamType1: ptQuest), (Index: 58; Name: 'GetStage'; ParamType1: ptQuest), (Index: 59; Name: 'GetStageDone'; ParamType1: ptQuest; ParamType2: ptQuestStage), (Index: 60; Name: 'GetFactionRankDifference'; ParamType1: ptFaction; ParamType2: ptActor), (Index: 61; Name: 'GetAlarmed'), (Index: 62; Name: 'IsRaining'), (Index: 63; Name: 'GetAttacked'), (Index: 64; Name: 'GetIsCreature'), (Index: 65; Name: 'GetLockLevel'), (Index: 66; Name: 'GetShouldAttack'; ParamType1: ptActor), (Index: 67; Name: 'GetInCell'; ParamType1: ptCell), (Index: 68; Name: 'GetIsClass'; ParamType1: ptClass), (Index: 69; Name: 'GetIsRace'; ParamType1: ptRace), (Index: 70; Name: 'GetIsSex'; ParamType1: ptSex), (Index: 71; Name: 'GetInFaction'; ParamType1: ptFaction), (Index: 72; Name: 'GetIsID'; ParamType1: ptReferencableObject), (Index: 73; Name: 'GetFactionRank'; ParamType1: ptFaction), (Index: 74; Name: 'GetGlobalValue'; ParamType1: ptGlobal), (Index: 75; Name: 'IsSnowing'), (Index: 76; Name: 'GetDisposition'; ParamType1: ptActor), (Index: 77; Name: 'GetRandomPercent'), (Index: 79; Name: 'GetQuestVariable'; ParamType1: ptQuest; ParamType2: ptVariableName), (Index: 80; Name: 'GetLevel'), (Index: 81; Name: 'GetArmorRating'), (Index: 84; Name: 'GetDeadCount'; ParamType1: ptActorBase), (Index: 91; Name: 'GetIsAlerted'), (Index: 98; Name: 'GetPlayerControlsDisabled'; ParamType1: ptInteger; ParamType2: ptInteger{; ParamType3: ptInteger; ParamType4: ptInteger; ParamType5: ptInteger; ParamType6: ptInteger; ParamType7: ptInteger}), (Index: 99; Name: 'GetHeadingAngle'; ParamType1: ptObjectReference), (Index: 101; Name: 'IsWeaponOut'), (Index: 102; Name: 'IsTorchOut'), (Index: 103; Name: 'IsShieldOut'), (Index: 106; Name: 'IsFacingUp'), (Index: 107; Name: 'GetKnockedState'), (Index: 108; Name: 'GetWeaponAnimType'), (Index: 109; Name: 'IsWeaponSkillType'; ParamType1: ptActorValue), (Index: 110; Name: 'GetCurrentAIPackage'), (Index: 111; Name: 'IsWaiting'), (Index: 112; Name: 'IsIdlePlaying'), (Index: 116; Name: 'GetMinorCrimeCount'), (Index: 117; Name: 'GetMajorCrimeCount'), (Index: 118; Name: 'GetActorAggroRadiusViolated'), (Index: 122; Name: 'GetCrime'; ParamType1: ptActor; ParamType2: ptCrimeType), (Index: 123; Name: 'IsGreetingPlayer'), (Index: 125; Name: 'IsGuard'), (Index: 127; Name: 'HasBeenEaten'), (Index: 128; Name: 'GetFatiguePercentage'), (Index: 129; Name: 'GetPCIsClass'; ParamType1: ptClass), (Index: 130; Name: 'GetPCIsRace'; ParamType1: ptRace), (Index: 131; Name: 'GetPCIsSex'; ParamType1: ptSex), (Index: 132; Name: 'GetPCInFaction'; ParamType1: ptFaction), (Index: 133; Name: 'SameFactionAsPC'), (Index: 134; Name: 'SameRaceAsPC'), (Index: 135; Name: 'SameSexAsPC'), (Index: 136; Name: 'GetIsReference'; ParamType1: ptObjectReference), (Index: 141; Name: 'IsTalking'), (Index: 142; Name: 'GetWalkSpeed'), (Index: 143; Name: 'GetCurrentAIProcedure'), (Index: 144; Name: 'GetTrespassWarningLevel'), (Index: 145; Name: 'IsTrespassing'), (Index: 146; Name: 'IsInMyOwnedCell'), (Index: 147; Name: 'GetWindSpeed'), (Index: 148; Name: 'GetCurrentWeatherPercent'), (Index: 149; Name: 'GetIsCurrentWeather'; ParamType1: ptWeather), (Index: 150; Name: 'IsContinuingPackagePCNear'), (Index: 153; Name: 'CanHaveFlames'), (Index: 154; Name: 'HasFlames'), (Index: 157; Name: 'GetOpenState'), (Index: 159; Name: 'GetSitting'), (Index: 160; Name: 'GetFurnitureMarkerID'), (Index: 161; Name: 'GetIsCurrentPackage'; ParamType1: ptPackage), (Index: 162; Name: 'IsCurrentFurnitureRef'; ParamType1: ptObjectReference), (Index: 163; Name: 'IsCurrentFurnitureObj'; ParamType1: ptFurniture), (Index: 170; Name: 'GetDayOfWeek'), (Index: 172; Name: 'GetTalkedToPCParam'; ParamType1: ptActor), (Index: 175; Name: 'IsPCSleeping'), (Index: 176; Name: 'IsPCAMurderer'), (Index: 180; Name: 'GetDetectionLevel'; ParamType1: ptActor), (Index: 182; Name: 'GetEquipped'; ParamType1: ptInventoryObject), (Index: 185; Name: 'IsSwimming'), (Index: 190; Name: 'GetAmountSoldStolen'), (Index: 192; Name: 'GetIgnoreCrime'), (Index: 193; Name: 'GetPCExpelled'; ParamType1: ptFaction), (Index: 195; Name: 'GetPCFactionMurder'; ParamType1: ptFaction), (Index: 197; Name: 'GetPCEnemyofFaction'; ParamType1: ptFaction), (Index: 199; Name: 'GetPCFactionAttack'; ParamType1: ptFaction), (Index: 203; Name: 'GetDestroyed'), (Index: 214; Name: 'HasMagicEffect'; ParamType1: ptMagicEffect), (Index: 215; Name: 'GetDefaultOpen'), (Index: 219; Name: 'GetAnimAction'), (Index: 223; Name: 'IsSpellTarget'; ParamType1: ptMagicItem), (Index: 224; Name: 'GetVATSMode'), (Index: 225; Name: 'GetPersuasionNumber'), (Index: 226; Name: 'GetSandman'), (Index: 227; Name: 'GetCannibal'), (Index: 228; Name: 'GetIsClassDefault'; ParamType1: ptClass), (Index: 229; Name: 'GetClassDefaultMatch'), (Index: 230; Name: 'GetInCellParam'; ParamType1: ptCell; ParamType2: ptObjectReference), (Index: 235; Name: 'GetVatsTargetHeight'), (Index: 237; Name: 'GetIsGhost'), (Index: 242; Name: 'GetUnconscious'), (Index: 244; Name: 'GetRestrained'), (Index: 246; Name: 'GetIsUsedItem'; ParamType1: ptReferencableObject), (Index: 247; Name: 'GetIsUsedItemType'; ParamType1: ptFormType), (Index: 254; Name: 'GetIsPlayableRace'), (Index: 255; Name: 'GetOffersServicesNow'), (Index: 258; Name: 'GetUsedItemLevel'), (Index: 259; Name: 'GetUsedItemActivate'), (Index: 264; Name: 'GetBarterGold'), (Index: 265; Name: 'IsTimePassing'), (Index: 266; Name: 'IsPleasant'), (Index: 267; Name: 'IsCloudy'), (Index: 274; Name: 'GetArmorRatingUpperBody'), (Index: 277; Name: 'GetBaseActorValue'; ParamType1: ptActorValue), (Index: 278; Name: 'IsOwner'; ParamType1: ptOwner), (Index: 280; Name: 'IsCellOwner'; ParamType1: ptCell; ParamType2: ptOwner), (Index: 282; Name: 'IsHorseStolen'), (Index: 285; Name: 'IsLeftUp'), (Index: 286; Name: 'IsSneaking'), (Index: 287; Name: 'IsRunning'), (Index: 288; Name: 'GetFriendHit'), (Index: 289; Name: 'IsInCombat'), (Index: 300; Name: 'IsInInterior'), (Index: 304; Name: 'IsWaterObject'), (Index: 306; Name: 'IsActorUsingATorch'), (Index: 309; Name: 'IsXBox'), (Index: 310; Name: 'GetInWorldspace'; ParamType1: ptWorldSpace), (Index: 312; Name: 'GetPCMiscStat'; ParamType1: ptMiscStat), (Index: 313; Name: 'IsActorEvil'), (Index: 314; Name: 'IsActorAVictim'), (Index: 315; Name: 'GetTotalPersuasionNumber'), (Index: 318; Name: 'GetIdleDoneOnce'), (Index: 320; Name: 'GetNoRumors'), (Index: 323; Name: 'WhichServiceMenu'), (Index: 327; Name: 'IsRidingHorse'), (Index: 332; Name: 'IsInDangerousWater'), (Index: 338; Name: 'GetIgnoreFriendlyHits'), (Index: 339; Name: 'IsPlayersLastRiddenHorse'), (Index: 353; Name: 'IsActor'), (Index: 354; Name: 'IsEssential'), (Index: 358; Name: 'IsPlayerMovingIntoNewSpace'), (Index: 361; Name: 'GetTimeDead'), (Index: 362; Name: 'GetPlayerHasLastRiddenHorse'), (Index: 365; Name: 'IsChild'), (Index: 367; Name: 'GetLastPlayerAction'), (Index: 368; Name: 'IsPlayerActionActive'; ParamType1: ptPlayerAction), (Index: 370; Name: 'IsTalkingActivatorActor'; ParamType1: ptActor), (Index: 372; Name: 'IsInList'; ParamType1: ptFormList), (Index: 382; Name: 'GetHasNote'; ParamType1: ptNote), (Index: 391; Name: 'GetHitLocation'), (Index: 392; Name: 'IsPC1stPerson'), (Index: 397; Name: 'GetCauseofDeath'), (Index: 398; Name: 'IsLimbGone'; ParamType1: ptBodyLocation), (Index: 399; Name: 'IsWeaponInList'; ParamType1: ptFormList), (Index: 403; Name: 'HasFriendDisposition'), (Index: 408; Name: 'GetVATSValue'; ParamType1: ptVATSValueFunction; ParamType2: ptVATSValueParam), (Index: 409; Name: 'IsKiller'; ParamType1: ptActor), (Index: 410; Name: 'IsKillerObject'; ParamType1: ptFormList), (Index: 411; Name: 'GetFactionCombatReaction'; ParamType1: ptFaction; ParamType2: ptFaction), (Index: 415; Name: 'Exists'; ParamType1: ptObjectReference), (Index: 416; Name: 'GetGroupMemberCount'), (Index: 417; Name: 'GetGroupTargetCount'), (Index: 420; Name: 'GetObjectiveCompleted'; ParamType1: ptQuest; ParamType2: ptQuestObjective), (Index: 421; Name: 'GetObjectiveDisplayed'; ParamType1: ptQuest; ParamType2: ptQuestObjective), (Index: 427; Name: 'GetIsVoiceType'; ParamType1: ptVoiceType), (Index: 428; Name: 'GetPlantedExplosive'), (Index: 430; Name: 'IsActorTalkingThroughActivator'), (Index: 431; Name: 'GetHealthPercentage'), (Index: 433; Name: 'GetIsObjectType'; ParamType1: ptFormType), (Index: 435; Name: 'GetDialogueEmotion'), (Index: 436; Name: 'GetDialogueEmotionValue'), (Index: 438; Name: 'GetIsCreatureType'; ParamType1: ptCreatureType), (Index: 446; Name: 'GetInZone'; ParamType1: ptEncounterZone), (Index: 449; Name: 'HasPerk'; ParamType1: ptPerk; ParamType2: ptInteger {boolean Alt}), // PlayerCharacter has 2 lists of perks (Index: 450; Name: 'GetFactionRelation'; ParamType1: ptActor), (Index: 451; Name: 'IsLastIdlePlayed'; ParamType1: ptIdleForm), (Index: 454; Name: 'GetPlayerTeammate'), (Index: 455; Name: 'GetPlayerTeammateCount'), (Index: 459; Name: 'GetActorCrimePlayerEnemy'), (Index: 460; Name: 'GetActorFactionPlayerEnemy'), (Index: 462; Name: 'IsPlayerTagSkill'; ParamType1: ptActorValue), (Index: 464; Name: 'IsPlayerGrabbedRef'; ParamType1: ptObjectReference), (Index: 471; Name: 'GetDestructionStage'), (Index: 474; Name: 'GetIsAlignment'; ParamType1: ptAlignment), (Index: 478; Name: 'GetThreatRatio'; ParamType1: ptActor), (Index: 480; Name: 'GetIsUsedItemEquipType'; ParamType1: ptEquipType), (Index: 489; Name: 'GetConcussed'), (Index: 492; Name: 'GetMapMarkerVisible'), (Index: 495; Name: 'GetPermanentActorValue'; ParamType1: ptActorValue), (Index: 496; Name: 'GetKillingBlowLimb'), (Index: 500; Name: 'GetWeaponHealthPerc'), (Index: 503; Name: 'GetRadiationLevel'), (Index: 510; Name: 'GetLastHitCritical'), (Index: 515; Name: 'IsCombatTarget'; ParamType1: ptActor), (Index: 518; Name: 'GetVATSRightAreaFree'; ParamType1: ptObjectReference), (Index: 519; Name: 'GetVATSLeftAreaFree'; ParamType1: ptObjectReference), (Index: 520; Name: 'GetVATSBackAreaFree'; ParamType1: ptObjectReference), (Index: 521; Name: 'GetVATSFrontAreaFree'; ParamType1: ptObjectReference), (Index: 522; Name: 'GetIsLockBroken'), (Index: 523; Name: 'IsPS3'), (Index: 524; Name: 'IsWin32'), (Index: 525; Name: 'GetVATSRightTargetVisible'; ParamType1: ptObjectReference), (Index: 526; Name: 'GetVATSLeftTargetVisible'; ParamType1: ptObjectReference), (Index: 527; Name: 'GetVATSBackTargetVisible'; ParamType1: ptObjectReference), (Index: 528; Name: 'GetVATSFrontTargetVisible'; ParamType1: ptObjectReference), (Index: 531; Name: 'IsInCriticalStage'; ParamType1: ptCriticalStage), (Index: 533; Name: 'GetXPForNextLevel'), (Index: 546; Name: 'GetQuestCompleted'; ParamType1: ptQuest), (Index: 550; Name: 'IsGoreDisabled'), (Index: 555; Name: 'GetSpellUsageNum'; ParamType1: ptMagicItem), (Index: 557; Name: 'GetActorsInHigh'), (Index: 558; Name: 'HasLoaded3D'), (Index: 573; Name: 'GetReputation'; ParamType1: ptReputation; ParamType2: ptInteger), (Index: 574; Name: 'GetReputationPct'; ParamType1: ptReputation; ParamType2: ptInteger), (Index: 575; Name: 'GetReputationThreshold'; ParamType1: ptReputation; ParamType2: ptInteger), (Index: 586; Name: 'IsHardcore'), (Index: 601; Name: 'GetForceHitReaction'), (Index: 607; Name: 'ChallengeLocked'; ParamType1: ptChallenge), (Index: 610; Name: 'GetCasinoWinningStage'; ParamType1: ptCasino), (Index: 612; Name: 'PlayerInRegion'; ParamType1: ptRegion), (Index: 614; Name: 'GetChallengeCompleted'; ParamType1: ptChallenge), (Index: 619; Name: 'IsAlwaysHardcore'), // Added by NVSE (Index: 1024; Name: 'GetNVSEVersion'; ), (Index: 1025; Name: 'GetNVSERevision'; ), (Index: 1026; Name: 'GetNVSEBeta'; ), (Index: 1028; Name: 'GetWeight'; ParamType1: ptInventoryObject; ), (Index: 1076; Name: 'GetWeaponHasScope'; ParamType1: ptInventoryObject; ), (Index: 1089; Name: 'ListGetFormIndex'; ParamType1: ptFormList; ParamType2: ptFormType;), (Index: 1107; Name: 'IsKeyPressed'; ParamType1: ptInteger; ParamType2: ptInteger;), (Index: 1131; Name: 'IsControlPressed'; ParamType1: ptInteger; ), (Index: 1271; Name: 'HasOwnership'; ParamType1: ptObjectReference; ), (Index: 1272; Name: 'IsOwned'; ParamType1: ptActor ), (Index: 1274; Name: 'GetDialogueTarget'; ParamType1: ptActor; ), (Index: 1275; Name: 'GetDialogueSubject'; ParamType1: ptActor; ), (Index: 1276; Name: 'GetDialogueSpeaker'; ParamType1: ptActor; ), (Index: 1278; Name: 'GetAgeClass'; ParamType1: ptActorBase; ), (Index: 1286; Name: 'GetTokenValue'; ParamType1: ptFormType; ), (Index: 1288; Name: 'GetTokenRef'; ParamType1: ptFormType; ), (Index: 1291; Name: 'GetPaired'; ParamType1: ptInventoryObject; ParamType2: ptActorBase;), (Index: 1292; Name: 'GetRespawn'; ParamType1: ptACtorBase; ), (Index: 1294; Name: 'GetPermanent'; ParamType1: ptObjectReference; ), (Index: 1297; Name: 'IsRefInList'; ParamType1: ptFormList; ParamType2: ptFormType;), (Index: 1301; Name: 'GetPackageCount'; ParamType1: ptObjectReference; ), (Index: 1440; Name: 'IsPlayerSwimming'; ), (Index: 1441; Name: 'GetTFC'; ), (Index: 1475; Name: 'GetPerkRank'; ParamType1: ptPerk; ParamType2: ptActor;), (Index: 1476; Name: 'GetAltPerkRank'; ParamType1: ptPerk; ParamType2: ptActor;), (Index: 1541; Name: 'GetActorFIKstatus'; ), // Added by nvse_plugin_ExtendedActorVariable (Index: 4352; Name: 'GetExtendedActorVariable'; ParamType1: ptInventoryObject; ), (Index: 4353; Name: 'GetBaseExtendedActorVariable'; ParamType1: ptInventoryObject; ), (Index: 4355; Name: 'GetModExtendedActorVariable'; ParamType1: ptInventoryObject; ), // Added by nvse_extender (Index: 4420; Name: 'NX_GetEVFl'; ParamType1: ptNone; ), // Actually ptString, but it cannot be used in GECK (Index: 4426; Name: 'NX_GetQVEVFl'; ParamType1: ptQuest; ParamType2: ptInteger;), // Added by lutana_nvse (Index: 4708; Name: 'GetArmorClass'; ParamType1: ptAnyForm; ), (Index: 4709; Name: 'IsRaceInList'; ParamType1: ptFormList; ), (Index: 4822; Name: 'GetReferenceFlag'; ParamType1: ptInteger; ), // Added by JIP NVSE Plugin (Index: 5637; Name: 'GetIsPoisoned'; ), (Index: 5708; Name: 'IsEquippedWeaponSilenced'; ), (Index: 5709; Name: 'IsEquippedWeaponScoped'; ), (Index: 5953; Name: 'GetPCInRegion'; ParamType1: ptRegion; ), (Index: 5962; Name: 'GetPCDetectionState'; ) ); var wbCTDAFunctionEditInfo: string; function wbCTDAParamDescFromIndex(aIndex: Integer): PCTDAFunction; var L, H, I, C: Integer; begin Result := nil; L := Low(wbCTDAFunctions); H := High(wbCTDAFunctions); while L <= H do begin I := (L + H) shr 1; C := CmpW32(wbCTDAFunctions[I].Index, aIndex); if C < 0 then L := I + 1 else begin H := I - 1; if C = 0 then begin L := I; Result := @wbCTDAFunctions[L]; end; end; end; end; function wbCTDACompValueDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container: IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; if Integer(Container.ElementByName['Type'].NativeValue) and $04 <> 0 then Result := 1; end; function wbCTDAParam1Decider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Desc: PCTDAFunction; Container: IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; Desc := wbCTDAParamDescFromIndex(Container.ElementByName['Function'].NativeValue); if Assigned(Desc) then Result := Succ(Integer(Desc.ParamType1)); end; function wbCTDAParam2VATSValueParam(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; Result := Container.ElementByName['Parameter #1'].NativeValue; end; function wbCTDAParam2Decider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Desc: PCTDAFunction; Container: IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; Desc := wbCTDAParamDescFromIndex(Container.ElementByName['Function'].NativeValue); if Assigned(Desc) then Result := Succ(Integer(Desc.ParamType2)); end; function wbCTDAFunctionToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Desc : PCTDAFunction; i : Integer; begin Result := ''; case aType of ctToStr, ctToEditValue: begin Desc := wbCTDAParamDescFromIndex(aInt); if Assigned(Desc) then Result := Desc.Name else if aType = ctToEditValue then Result := IntToStr(aInt) else Result := ''; end; ctToSortKey: Result := IntToHex(aInt, 8); ctCheck: begin Desc := wbCTDAParamDescFromIndex(aInt); if Assigned(Desc) then Result := '' else Result := ''; end; ctEditType: Result := 'ComboBox'; ctEditInfo: begin Result := wbCTDAFunctionEditInfo; if Result = '' then begin with TStringList.Create do try for i := Low(wbCTDAFunctions) to High(wbCTDAFunctions) do Add(wbCTDAFunctions[i].Name); Sort; Result := CommaText; finally Free; end; wbCTDAFunctionEditInfo := Result; end; end; end; end; function wbCTDAFunctionToInt(const aString: string; const aElement: IwbElement): Int64; var i: Integer; begin for i := Low(wbCTDAFunctions) to High(wbCTDAFunctions) do with wbCTDAFunctions[i] do if SameText(Name, aString) then begin Result := Index; Exit; end; Result := StrToInt64(aString); end; type TPERKEntryPointConditionType = ( epcDefault, epcItem, epcWeapon, epcWeaponTarget, epcTarget, epcAttacker, epcAttackerAttackee, epcAttackerAttackerWeapon ); TPERKEntryPointFunctionType = ( epfFloat, epfLeveledItem, epfScript, epfUnknown ); TPERKEntryPointFunctionParamType = ( epfpNone, epfpFloat, epfpFloatFloat, epfpLeveledItem, epfpScript ); PPERKEntryPoint = ^TPERKEntryPoint; TPERKEntryPoint = record Name : string; Condition : TPERKEntryPointConditionType; FunctionType : TPERKEntryPointFunctionType; end; PPERKCondition = ^TPERKCondition; TPERKCondition = record Count : Integer; Caption1 : string; Caption2 : string; Caption3 : string; end; PPERKFunction = ^TPERKFunction; TPERKFunction = record Name : string; FunctionType : TPERKEntryPointFunctionType; ParamType : TPERKEntryPointFunctionParamType; end; const wbPERKCondition : array[TPERKEntryPointConditionType] of TPERKCondition = ( (Count: 1; Caption1: 'Perk Owner'), (Count: 2; Caption1: 'Perk Owner'; Caption2: 'Item'), (Count: 2; Caption1: 'Perk Owner'; Caption2: 'Weapon'), (Count: 3; Caption1: 'Perk Owner'; Caption2: 'Weapon'; Caption3: 'Target'), (Count: 2; Caption1: 'Perk Owner'; Caption2: 'Target'), (Count: 2; Caption1: 'Perk Owner'; Caption2: 'Attacker'), (Count: 3; Caption1: 'Perk Owner'; Caption2: 'Attacker'; Caption3: 'Attackee'), (Count: 3; Caption1: 'Perk Owner'; Caption2: 'Attacker'; Caption3: 'Attacker Weapon') ); wbPERKFunctions : array[0..9] of TPERKFunction = ( (Name: ''; FunctionType: epfUnknown; ParamType: epfpNone), (Name: 'Set Value'; FunctionType: epfFloat; ParamType: epfpFloat), (Name: 'Add Value'; FunctionType: epfFloat; ParamType: epfpFloat), (Name: 'Multiply Value'; FunctionType: epfFloat; ParamType: epfpFloat), (Name: 'Add Range To Value'; FunctionType: epfFloat; ParamType: epfpFloatFloat), (Name: 'Add Actor Value Mult'; FunctionType: epfFloat; ParamType: epfpFloatFloat), (Name: 'Absolute Value'; FunctionType: epfFloat; ParamType: epfpNone), (Name: 'Negative Absolute Value'; FunctionType: epfFloat; ParamType: epfpNone), (Name: 'Add Leveled List'; FunctionType: epfLeveledItem; ParamType: epfpLeveledItem), (Name: 'Add Activate Choice'; FunctionType: epfScript; ParamType: epfpScript) ); wbPERKEntryPoints : array[0..73] of TPERKEntryPoint = ( (Name: 'Calculate Weapon Damage'; Condition: epcWeaponTarget), (Name: 'Calculate My Critical Hit Chance'; Condition: epcWeaponTarget), (Name: 'Calculate My Critical Hit Damage'; Condition: epcWeaponTarget), (Name: 'Calculate Weapon Attack AP Cost'; Condition: epcWeapon), (Name: 'Calculate Mine Explode Chance'; Condition: epcItem), (Name: 'Adjust Range Penalty'; Condition: epcWeapon), (Name: 'Adjust Limb Damage'; Condition: epcAttackerAttackerWeapon), (Name: 'Calculate Weapon Range'; Condition: epcWeapon), (Name: 'Calculate To Hit Chance'; Condition: epcWeaponTarget), (Name: 'Adjust Experience Points'), (Name: 'Adjust Gained Skill Points'), (Name: 'Adjust Book Skill Points'), (Name: 'Modify Recovered Health'), (Name: 'Calculate Inventory AP Cost'), (Name: 'Get Disposition'; Condition: epcTarget), (Name: 'Get Should Attack'; Condition: epcAttacker), (Name: 'Get Should Assist'; Condition: epcAttackerAttackee), (Name: 'Calculate Buy Price'; Condition: epcItem), (Name: 'Get Bad Karma'), (Name: 'Get Good Karma'), (Name: 'Ignore Locked Terminal'), (Name: 'Add Leveled List On Death'; Condition: epcTarget; FunctionType: epfLeveledItem), (Name: 'Get Max Carry Weight'), (Name: 'Modify Addiction Chance'), (Name: 'Modify Addiction Duration'), (Name: 'Modify Positive Chem Duration'), (Name: 'Adjust Drinking Radiation'), (Name: 'Activate'; Condition: epcTarget; FunctionType: epfScript), (Name: 'Mysterious Stranger'), (Name: 'Has Paralyzing Palm'), (Name: 'Hacking Science Bonus'), (Name: 'Ignore Running During Detection'), (Name: 'Ignore Broken Lock'), (Name: 'Has Concentrated Fire'), (Name: 'Calculate Gun Spread'; Condition: epcWeapon), (Name: 'Player Kill AP Reward'; Condition: epcWeaponTarget), {36}(Name: 'Modify Enemy Critical Hit Chance'; Condition: epcWeaponTarget), {37}(Name: 'Reload Speed'; Condition: epcWeapon), {38}(Name: 'Equip Speed'; Condition: epcWeapon), {39}(Name: 'Action Point Regen'; Condition: epcWeapon), {40}(Name: 'Action Point Cost'; Condition: epcWeapon), {41}(Name: 'Miss Fortune'; Condition: epcDefault), {42}(Name: 'Modify Run Speed'; Condition: epcDefault), {43}(Name: 'Modify Attack Speed'; Condition: epcWeapon), {44}(Name: 'Modify Radiation Consumed'; Condition: epcDefault), {45}(Name: 'Has Pip Hacker'; Condition: epcDefault), {46}(Name: 'Has Meltdown'; Condition: epcDefault), {47}(Name: 'See Enemy Health'; Condition: epcDefault), {48}(Name: 'Has Jury Rigging'; Condition: epcDefault), {49}(Name: 'Modify Threat Range'; Condition: epcWeapon), {50}(Name: 'Modify Thread'; Condition: epcWeapon), {51}(Name: 'Has Fast Travel Always'; Condition: epcDefault), {52}(Name: 'Knockdown Chance'; Condition: epcWeapon), {53}(Name: 'Modify Weapon Strength Req'; Condition: epcWeapon), {54}(Name: 'Modify Aiming Move Speed'; Condition: epcWeapon), {55}(Name: 'Modify Light Items'; Condition: epcDefault), {56}(Name: 'Modify Damage Threshold (defender)'; Condition: epcWeaponTarget), {57}(Name: 'Modify Chance for Ammo Item'; Condition: epcWeapon), {58}(Name: 'Modify Damage Threshold (attacker)'; Condition: epcWeaponTarget), {59}(Name: 'Modify Throwing Velocity'; Condition: epcWeapon), {60}(Name: 'Chance for Item on Fire'; Condition: epcWeapon), {61}(Name: 'Has Unarmed Forward Power Attack'; Condition: epcDefault), {62}(Name: 'Has Unarmed Back Power Attack'; Condition: epcWeaponTarget), {63}(Name: 'Has Unarmed Crouched Power Attack'; Condition: epcDefault), {64}(Name: 'Has Unarmed Counter Attack'; Condition: epcWeaponTarget), {65}(Name: 'Has Unarmed Left Power Attack'; Condition: epcDefault), {66}(Name: 'Has Unarmed Right Power Attack'; Condition: epcDefault), {67}(Name: 'VATS HelperChance'; Condition: epcDefault), {68}(Name: 'Modify Item Damage'; Condition: epcDefault), {69}(Name: 'Has Improved Detection'; Condition: epcDefault), {70}(Name: 'Has Improved Spotting'; Condition: epcDefault), {71}(Name: 'Has Improved Item Detection'; Condition: epcDefault), {72}(Name: 'Adjust Explosion Radius'; Condition: epcWeapon), {73}(Name: 'Reserved'; Condition: epcWeapon) ); wbPERKFunctionParams: array[TPERKEntryPointFunctionParamType] of string = ( 'None', 'Float', 'Float, Float', 'Leveled Item', 'Script' ); procedure wbPERKEntryPointAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var OldEntryPoint : PPERKEntryPoint; NewEntryPoint : PPERKEntryPoint; OldCondition : PPERKCondition; NewCondition : PPERKCondition; OldFunction : PPERKFunction; EntryPoint : IwbContainerElementRef; Effect : IwbContainerElementRef; PerkConditions : IwbContainerElementRef; PerkCondition : IwbContainerElementRef; Container : IwbContainerElementRef; i : Integer; begin if aOldValue <> aNewValue then begin OldEntryPoint := @wbPERKEntryPoints[Integer(aOldValue)]; NewEntryPoint := @wbPERKEntryPoints[Integer(aNewValue)]; OldCondition := @wbPERKCondition[OldEntryPoint.Condition]; NewCondition := @wbPERKCondition[NewEntryPoint.Condition]; if not Assigned(aElement) then Exit; if not Supports(aElement.Container, IwbContainerElementRef, EntryPoint) then Exit; i := EntryPoint.ElementNativeValues['Function']; if (i >= Low(wbPERKFunctions)) and (i <= High(wbPERKFunctions)) then OldFunction := @wbPERKFunctions[i] else OldFunction := nil; if not Assigned(OldFunction) or (OldFunction.FunctionType <> NewEntryPoint.FunctionType) then for i := Low(wbPERKFunctions) to High(wbPERKFunctions) do with wbPERKFunctions[i] do if FunctionType = NewEntryPoint.FunctionType then begin EntryPoint.ElementNativeValues['Function'] := i; Break; end; EntryPoint.ElementNativeValues['Perk Condition Tab Count'] := NewCondition.Count; if not Supports(EntryPoint.Container, IwbContainerElementRef, Container) then Exit; if not Supports(Container.Container, IwbContainerElementRef, Effect) then Exit; if not Supports(Effect.ElementByName['Perk Conditions'], IwbContainerElementRef, PerkConditions) then Exit; for i := Pred(PerkConditions.ElementCount) downto 0 do if Supports(PerkConditions.Elements[i], IwbContainerElementRef, PerkCondition) then if Integer(PerkCondition.ElementNativeValues['PRKC']) >= NewCondition.Count then PerkCondition.Remove else case Integer(PerkCondition.ElementNativeValues['PRKC']) of 2: if OldCondition.Caption2 <> NewCondition.Caption2 then PerkCondition.Remove; 3: if OldCondition.Caption3 <> NewCondition.Caption3 then PerkCondition.Remove; end; end; end; function wbPRKCToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainerElementRef; EntryPointVar : Variant; EntryPoint : Integer; begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctToEditValue: Result := IntToStr(aInt); ctToSortKey: begin Result := IntToHex64(aInt, 2); Exit; end; ctCheck: Result := ''; ctEditType: Result := ''; ctEditInfo: Result := ''; end; if not Supports(aElement, IwbContainerElementRef, Container) then Exit; EntryPointVar := Container.ElementNativeValues['..\..\..\DATA\Entry Point\Entry Point']; if VarIsNull(EntryPointVar) or VarIsClear(EntryPointVar) then Exit; EntryPoint := EntryPointVar; if (EntryPoint < Low(wbPERKEntryPoints)) or (EntryPoint > High(wbPERKEntryPoints)) then begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end; Exit; end; with wbPERKEntryPoints[EntryPoint] do begin with wbPERKCondition[Condition] do begin case aType of ctEditType: Result := 'ComboBox'; ctEditInfo: with TStringList.Create do try if Caption1 <> '' then Add(Caption1); if Caption2 <> '' then Add(Caption2); if Caption3 <> '' then Add(Caption3); Sort; Result := CommaText; finally Free; end; else if (aInt < 0) or (aInt >= Count) then case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end else case aType of ctToStr, ctToEditValue: case Integer(aInt) of 0: Result := Caption1; 1: Result := Caption2; 2: Result := Caption3; end; ctCheck: Result := ''; end; end; end; end; end; function wbPRKCToInt(const aString: string; const aElement: IwbElement): Int64; var Container : IwbContainerElementRef; EntryPointVar : Variant; EntryPoint : Integer; s : string; begin s := Trim(aString); Result := StrToInt64Def(s, Low(Integer)); if Result <> Low(Integer) then Exit; if s = '' then begin Result := 0; Exit; end; if not Supports(aElement, IwbContainerElementRef, Container) then raise Exception.Create('Could not resolve Entry Point'); EntryPointVar := Container.ElementNativeValues['..\..\..\DATA\Entry Point\Entry Point']; if VarIsNull(EntryPointVar) or VarIsClear(EntryPointVar) then raise Exception.Create('Could not resolve Entry Point'); EntryPoint := EntryPointVar; if (EntryPoint < Low(wbPERKEntryPoints)) or (EntryPoint > High(wbPERKEntryPoints)) then raise Exception.Create('Unknown Entry Point #'+IntToStr(EntryPoint)); with wbPERKEntryPoints[EntryPoint] do with wbPERKCondition[Condition] do if SameText(aString, Caption1) then Result := 0 else if SameText(aString, Caption2) then Result := 1 else if SameText(aString, Caption3) then Result := 2 else raise Exception.Create('"'+s+'" is not valid for this Entry Point'); end; function wbNeverShow(const aElement: IwbElement): Boolean; begin Result := wbHideNeverShow; end; function GetREGNType(aElement: IwbElement): Integer; var Container: IwbContainerElementRef; begin Result := -1; if not Assigned(aElement) then Exit; while aElement.Name <> 'Region Data Entry' do begin aElement := aElement.Container; if not Assigned(aElement) then Exit; end; if not Supports(aElement, IwbContainerElementRef, Container) then Exit; Result := Container.ElementNativeValues['RDAT\Type']; end; function wbREGNObjectsDontShow(const aElement: IwbElement): Boolean; begin Result := GetREGNType(aElement) <> 2; end; function wbREGNWeatherDontShow(const aElement: IwbElement): Boolean; begin Result := GetREGNType(aElement) <> 3; end; function wbREGNMapDontShow(const aElement: IwbElement): Boolean; begin Result := GetREGNType(aElement) <> 4; end; function wbREGNLandDontShow(const aElement: IwbElement): Boolean; begin Result := GetREGNType(aElement) <> 5; end; function wbREGNGrassDontShow(const aElement: IwbElement): Boolean; begin Result := GetREGNType(aElement) <> 6; end; function wbREGNSoundDontShow(const aElement: IwbElement): Boolean; begin Result := GetREGNType(aElement) <> 7; end; function wbREGNImposterDontShow(const aElement: IwbElement): Boolean; begin Result := GetREGNType(aElement) <> 8; end; function wbMESGTNAMDontShow(const aElement: IwbElement): Boolean; var Container : IwbContainerElementRef; MainRecord : IwbMainRecord; begin Result := False; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Integer(Container.ElementNativeValues['DNAM']) and 1 <> 0 then Result := True; end; function wbEPFDDontShow(const aElement: IwbElement): Boolean; var Container: IwbContainerElementRef; begin Result := False; if aElement.Name <> 'Entry Point Function Parameters' then Exit; if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if not (Integer(Container.ElementNativeValues['EPFT']) in [1..3]) then Result := True; end; function wbTES4ONAMDontShow(const aElement: IwbElement): Boolean; var MainRecord : IwbMainRecord; begin Result := False; if not Assigned(aElement) then Exit; MainRecord := aElement.ContainingMainRecord; if not Assigned(MainRecord) then Exit; if not MainRecord.IsESM then Result := True; end; function wbEPF2DontShow(const aElement: IwbElement): Boolean; var Container: IwbContainerElementRef; begin Result := False; if aElement.Name <> 'Entry Point Function Parameters' then Exit; if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if not (Integer(Container.ElementNativeValues['EPFT']) in [4]) then Result := True; end; function wbPERKPRKCDontShow(const aElement: IwbElement): Boolean; var Container: IwbContainerElementRef; begin Result := False; if aElement.Name <> 'Effect' then Exit; if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Integer(Container.ElementNativeValues['PRKE\Type']) <> 2 then Result := True; end; function wbPerkDATAFunctionToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainerElementRef; EntryPointVar : Variant; EntryPoint : Integer; i : Integer; begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctToEditValue: Result := IntToStr(aInt); ctToSortKey: begin Result := IntToHex64(aInt, 2); Exit; end; ctCheck: Result := ''; ctEditType: Result := ''; ctEditInfo: Result := ''; end; if not Supports(aElement, IwbContainerElementRef, Container) then Exit; EntryPointVar := Container.ElementNativeValues['..\Entry Point']; if VarIsNull(EntryPointVar) or VarIsClear(EntryPointVar) then Exit; EntryPoint := EntryPointVar; if (EntryPoint < Low(wbPERKEntryPoints)) or (EntryPoint > High(wbPERKEntryPoints)) then begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end; Exit; end; with wbPERKEntryPoints[EntryPoint] do begin case aType of ctEditType: Result := 'ComboBox'; ctEditInfo: with TStringList.Create do try for i := Low(wbPERKFunctions) to High(wbPERKFunctions) do if wbPERKFunctions[i].FunctionType = FunctionType then if (wbPERKFunctions[i].Name <> '') then Add(wbPERKFunctions[i].Name); Sort; Result := CommaText; finally Free; end; else if (aInt < Low(wbPERKFunctions)) or (aInt > High(wbPERKFunctions)) then case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end else case aType of ctToStr, ctToEditValue: begin Result := wbPERKFunctions[Integer(aInt)].Name; if (aType = ctToStr) and (wbPERKFunctions[Integer(aInt)].FunctionType <> FunctionType) then Result := Result + ' '; end; ctCheck: if wbPERKFunctions[Integer(aInt)].FunctionType <> FunctionType then Result := '' else Result := ''; end; end; end; end; function wbPerkDATAFunctionToInt(const aString: string; const aElement: IwbElement): Int64; var Container : IwbContainerElementRef; EntryPointVar : Variant; EntryPoint : Integer; s : string; i : Integer; begin s := Trim(aString); Result := StrToInt64Def(s, Low(Integer)); if Result <> Low(Integer) then Exit; if s = '' then raise Exception.Create('"" is not a valid value for this field'); if not Supports(aElement, IwbContainerElementRef, Container) then raise Exception.Create('Could not resolve Entry Point'); EntryPointVar := Container.ElementNativeValues['..\Entry Point']; if VarIsNull(EntryPointVar) or VarIsClear(EntryPointVar) then raise Exception.Create('Could not resolve Entry Point'); EntryPoint := EntryPointVar; if (EntryPoint < Low(wbPERKEntryPoints)) or (EntryPoint > High(wbPERKEntryPoints)) then raise Exception.Create('Unknown Entry Point #'+IntToStr(EntryPoint)); with wbPERKEntryPoints[EntryPoint] do for i := Low(wbPERKFunctions) to High(wbPERKFunctions) do if wbPERKFunctions[i].FunctionType = FunctionType then if SameText(s, wbPERKFunctions[i].Name) then begin Result := i; Exit; end; raise Exception.Create('"'+s+'" is not valid for this Entry Point'); end; procedure wbPerkDATAFunctionAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var NewFunction : Integer; Container : IwbContainerElementRef; OldParamType: Integer; NewParamType: Integer; begin NewFunction := aNewValue; if (NewFunction < Low(wbPERKFunctions)) or (NewFunction > High(wbPERKFunctions)) then Exit; if not Supports(aElement, IwbContainerElementRef, Container) then Exit; OldParamType := Container.ElementNativeValues['..\..\..\Entry Point Function Parameters\EPFT']; NewParamType := Ord(wbPERKFunctions[NewFunction].ParamType); if (OldParamType = NewParamType) and not VarSameValue(aOldValue, aNewValue) and (NewFunction in [4,5]) then Container.ElementNativeValues['..\..\..\Entry Point Function Parameters\EPFT'] := 0; Container.ElementNativeValues['..\..\..\Entry Point Function Parameters\EPFT'] := NewParamType; end; function wbPerkEPFTToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainerElementRef; FunctionTypeVar : Variant; FunctionType : Integer; // i : Integer; begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctToEditValue: Result := IntToStr(aInt); ctToSortKey: begin Result := IntToHex64(aInt, 2); Exit; end; ctCheck: Result := ''; ctEditType: Result := ''; ctEditInfo: Result := ''; end; if not Supports(aElement, IwbContainerElementRef, Container) then Exit; FunctionTypeVar := Container.ElementNativeValues['..\..\DATA\Entry Point\Function']; if VarIsNull(FunctionTypeVar) or VarIsClear(FunctionTypeVar) then Exit; FunctionType := FunctionTypeVar; if (FunctionType < Low(wbPERKFunctions)) or (FunctionType > High(wbPERKFunctions)) then begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end; Exit; end; with wbPERKFunctions[FunctionType] do begin case aType of ctEditType: Result := 'ComboBox'; ctEditInfo: Result := '"' + wbPERKFunctionParams[ParamType] + '"'; else if (aInt < Ord(Low(wbPERKFunctionParams))) or (aInt > Ord(High(wbPERKFunctionParams))) then case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end else case aType of ctToStr, ctToEditValue: begin Result := wbPERKFunctionParams[TPERKEntryPointFunctionParamType(aInt)]; if (aType = ctToStr) and (TPERKEntryPointFunctionParamType(aInt) <> ParamType) then Result := Result + ' '; end; ctCheck: if TPERKEntryPointFunctionParamType(aInt) <> ParamType then Result := Result + ' ' else Result := ''; end; end; end; end; function wbPerkEPFTToInt(const aString: string; const aElement: IwbElement): Int64; var Container : IwbContainerElementRef; FunctionTypeVar : Variant; FunctionType : Integer; s : string; // i : Integer; j : TPERKEntryPointFunctionParamType; begin s := Trim(aString); Result := StrToInt64Def(s, Low(Integer)); if Result <> Low(Integer) then Exit; if s = '' then raise Exception.Create('"" is not a valid value for this field'); if not Supports(aElement, IwbContainerElementRef, Container) then raise Exception.Create('Could not resolve Function'); FunctionTypeVar := Container.ElementNativeValues['..\..\DATA\Entry Point\Function']; if VarIsNull(FunctionTypeVar) or VarIsClear(FunctionTypeVar) then raise Exception.Create('Could not resolve Function'); FunctionType := FunctionTypeVar; if (FunctionType < Low(wbPERKFunctions)) or (FunctionType > High(wbPERKFunctions)) then raise Exception.Create('Unknown Function #'+IntToStr(FunctionType)); with wbPERKFunctions[FunctionType] do begin for j := Low(wbPERKFunctionParams) to High(wbPERKFunctionParams) do if SameText(s, wbPERKFunctionParams[j]) then begin if j <> ParamType then raise Exception.Create('"'+s+'" is not a valid Parameter Type for Function "'+Name+'"'); Result := Ord(j); Exit; end; end; raise Exception.Create('"'+s+'" is not a valid Parameter Type'); end; procedure wbPerkEPFTAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var i: Integer; Container: IwbContainerElementRef; begin if VarSameValue(aOldValue, aNewValue) then Exit; i := aNewValue; if (i < Ord(Low(wbPERKFunctionParams))) or (i> Ord(High(wbPERKFunctionParams))) then Exit; if not Supports(aElement.Container, IwbContainerElementRef, Container) then Exit; Container.RemoveElement('EPFD'); Container.RemoveElement('EPF2'); Container.RemoveElement('EPF3'); Container.RemoveElement('Embedded Script'); case TPERKEntryPointFunctionParamType(i) of epfpFloat, epfpFloatFloat, epfpLeveledItem: Container.Add('EPFD', True); epfpScript: begin Container.Add('EPF2', True); Container.Add('EPF3', True); Container.Add('SCHR', True); end; end; end; procedure wbRemoveOFST(const aElement: IwbElement); var Container: IwbContainer; rOFST: IwbRecord; begin if not wbRemoveOffsetData then Exit; if Supports(aElement, IwbContainer, Container) then begin if wbBeginInternalEdit then try Container.RemoveElement(OFST); finally wbEndInternalEdit; end else begin rOFST := Container.RecordBySignature[OFST]; if Assigned(rOFST) then Container.RemoveElement(rOFST); end; end; end; function wbActorTemplateUseTraits(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; if not wbActorTemplateHide then Exit; Element := GetElementFromUnion(aElement); MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000001) <> 0; end; end; function wbActorTemplateUseStats(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; if not wbActorTemplateHide then Exit; Element := GetElementFromUnion(aElement); MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000002) <> 0; end; end; function wbActorAutoCalcDontShow(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; if not wbActorTemplateHide then Exit; Element := GetElementFromUnion(aElement); MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Flags']; Result := (i and $00000010) <> 0; end; end; function wbActorTemplateUseStatsAutoCalc(const aElement: IwbElement): Boolean; begin if not wbActorTemplateHide then Result := False else Result := wbActorTemplateUseStats(aElement) or wbActorAutoCalcDontShow(aElement); end; function wbActorTemplateUseFactions(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; if not wbActorTemplateHide then Exit; Element := GetElementFromUnion(aElement); MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000004) <> 0; end; end; function wbActorTemplateUseActorEffectList(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; if not wbActorTemplateHide then Exit; Element := GetElementFromUnion(aElement); MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000008) <> 0; end; end; function wbActorTemplateUseAIData(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; if not wbActorTemplateHide then Exit; Element := GetElementFromUnion(aElement); MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000010) <> 0; end; end; function wbActorTemplateUseAIPackages(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; if not wbActorTemplateHide then Exit; Element := GetElementFromUnion(aElement); MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000020) <> 0; end; end; function wbActorTemplateUseModelAnimation(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; if not wbActorTemplateHide then Exit; Element := GetElementFromUnion(aElement); MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000040) <> 0; end; end; function wbActorTemplateUseBaseData(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; if not wbActorTemplateHide then Exit; Element := GetElementFromUnion(aElement); MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000080) <> 0; end; end; function wbActorTemplateUseInventory(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; if not wbActorTemplateHide then Exit; Element := GetElementFromUnion(aElement); MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000100) <> 0; end; end; function wbActorTemplateUseScript(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; if not wbActorTemplateHide then Exit; Element := GetElementFromUnion(aElement); MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000200) <> 0; end; end; procedure wbCTDAAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; //Size : Cardinal; TypeFlags : Cardinal; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; TypeFlags := Container.ElementNativeValues['Type']; if (TypeFlags and $02) <> 0 then begin if Container.DataSize = 20 then Container.DataSize := 28; Container.ElementNativeValues['Type'] := TypeFlags and not $02; Container.ElementEditValues['Run On'] := 'Target'; end; finally wbEndInternalEdit; end; end; procedure wbMGEFAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; MainRecord : IwbMainRecord; OldActorValue : Integer; NewActorValue : Integer; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; OldActorValue := Container.ElementNativeValues['DATA - Data\Actor Value']; NewActorValue := OldActorValue; case Integer(Container.ElementNativeValues['DATA - Data\Archtype']) of 01, //Script 02, //Dispel 03, //Cure Disease 13, //Light 16, //Lock 17, //Open 18, //Bound Item 19, //Summon Creature 30, //Cure Paralysis 31, //Cure Addiction 32, //Cure Poison 33, //Concussion 35: //Limb Condition NewActorValue := -1; 11: //Invisibility NewActorValue := 48; //Invisibility 12: //Chameleon NewActorValue := 49; //Chameleon 24: //Paralysis NewActorValue := 47; //Paralysis 36: //Turbo NewActorValue := 51; //Turbo end; if OldActorValue <> NewActorValue then Container.ElementNativeValues['DATA - Data\Actor Value'] := NewActorValue; finally wbEndInternalEdit; end; end; procedure wbPACKAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; MainRecord : IwbMainRecord; // OldContainer : IwbContainerElementRef; NewContainer : IwbContainerElementRef; // NewContainer2 : IwbContainerElementRef; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; case Integer(Container.ElementNativeValues['PKDT - General\Type']) of 0: begin {Find} Container.Add('PTDT'); end; 1: begin {Follow} Container.Add('PKFD'); end; 2: begin {Escort} end; 3: begin {Eat} Container.Add('PTDT'); Container.Add('PKED'); end; 4: begin {Sleep} if not Container.ElementExists['Locations'] then if Supports(Container.Add('Locations'), IwbContainerElementRef, NewContainer) then NewContainer.ElementEditValues['PLDT - Location 1\Type'] := 'Near editor location'; end; 5: begin {Wander} end; 6: begin {Travel} end; 7: begin {Accompany} end; 8: begin {Use Item At} end; 9: begin {Ambush} end; 10: begin {Flee Not Combat} end; 12: begin {Sandbox} end; 13: begin {Patrol} if not Container.ElementExists['Locations'] then if Supports(Container.Add('Locations'), IwbContainerElementRef, NewContainer) then NewContainer.ElementEditValues['PLDT - Location 1\Type'] := 'Near linked reference'; Container.Add('PKPT'); end; 14: begin {Guard} end; 15: begin {Dialogue} end; 16: begin {Use Weapon} end; end; finally wbEndInternalEdit; end; end; procedure wbNPCAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; MainRecord : IwbMainRecord; // BaseRecord : IwbMainRecord; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; if Container.ElementNativeValues['NAM5'] > 255 then Container.ElementNativeValues['NAM5'] := 255; finally wbEndInternalEdit; end; end; procedure wbREFRAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; MainRecord : IwbMainRecord; BaseRecord : IwbMainRecord; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; Container.RemoveElement('RCLR'); if Container.ElementExists['Ammo'] then begin BaseRecord := MainRecord.BaseRecord; if Assigned(BaseRecord) and (BaseRecord.Signature <> 'WEAP') then Container.RemoveElement('Ammo'); end; finally wbEndInternalEdit; end; end; procedure wbINFOAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; MainRecord : IwbMainRecord; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; if (Integer(Container.ElementNativeValues['DATA\Flags 1']) and $80) = 0 then Container.RemoveElement('DNAM'); Container.RemoveElement('SNDD'); if Container.ElementNativeValues['DATA\Type'] = 3 {Persuasion} then Container.ElementNativeValues['DATA\Type'] := 0 {Topic}; finally wbEndInternalEdit; end; end; procedure wbCELLAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; // Container2 : IwbContainerElementRef; MainRecord : IwbMainRecord; // i : Integer; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; if (not Container.ElementExists['XCLW']) and ((Integer(Container.ElementNativeValues['DATA']) and $02) <> 0) then begin Container.Add('XCLW', True); Container.ElementEditValues['XCLW'] := 'Default'; end; if (not Container.ElementExists['XNAM']) and ((Integer(Container.ElementNativeValues['DATA']) and $02) <> 0) then Container.Add('XNAM', True); // if Supports(Container.ElementBySignature[XCLR], IwbContainerElementRef, Container2) then begin // for i:= Pred(Container2.ElementCount) downto 0 do // if not Supports(Container2.Elements[i].LinksTo, IwbMainRecord, MainRecord) or (MainRecord.Signature <> 'REGN') then // Container2.RemoveElement(i); // if Container2.ElementCount < 1 then // Container2.Remove; // end; finally wbEndInternalEdit; end; end; procedure wbEmbeddedScriptAfterLoad(const aElement: IwbElement); var Container: IwbContainerElementRef; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if Container.ElementEditValues['SCHR\Type'] = 'Quest' then Container.ElementEditValues['SCHR\Type'] := 'Object'; finally wbEndInternalEdit; end; end; procedure wbSOUNAfterLoad(const aElement: IwbElement); var Container: IwbContainerElementRef; MainRecord : IwbMainRecord; OldCntr: IwbContainerElementRef; NewCntr: IwbContainerElementRef; NewCntr2: IwbContainerElementRef; i: Integer; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; if Container.ElementExists['SNDD'] then Exit; if not Supports(Container.RemoveElement('SNDX - Sound Data'), IwbContainerElementRef, OldCntr) then Exit; if not Supports(Container.Add('SNDD', True), IwbContainerElementRef, NewCntr) then Exit; for i := 0 to Pred(Min(OldCntr.ElementCount, NewCntr.ElementCount)) do NewCntr.Elements[i].Assign(Low(Integer), OldCntr.Elements[i], False); if not Supports(NewCntr.ElementByName['Attenuation Curve'], IwbContainerElementRef, NewCntr2) then Assert(False); Assert(NewCntr2.ElementCount = 5); if Supports(Container.RemoveElement('ANAM'), IwbContainerElementRef, OldCntr) then begin Assert(OldCntr.ElementCount = 5); for i := 0 to Pred(Min(OldCntr.ElementCount, NewCntr2.ElementCount)) do NewCntr2.Elements[i].Assign(Low(Integer), OldCntr.Elements[i], False); end else begin NewCntr2.Elements[0].NativeValue := 100; NewCntr2.Elements[1].NativeValue := 50; NewCntr2.Elements[2].NativeValue := 20; NewCntr2.Elements[3].NativeValue := 5; NewCntr2.Elements[4].NativeValue := 0; end; if not Supports(NewCntr.ElementByName['Reverb Attenuation Control'], IwbContainerElementRef, NewCntr2) then Assert(False); if Supports(Container.RemoveElement('GNAM'), IwbContainerElementRef, OldCntr) then NewCntr2.Assign(Low(Integer), OldCntr, False) else NewCntr2.NativeValue := 80; if not Supports(NewCntr.ElementByName['Priority'], IwbContainerElementRef, NewCntr2) then Assert(False); if Supports(Container.RemoveElement('HNAM'), IwbContainerElementRef, OldCntr) then NewCntr2.Assign(Low(Integer), OldCntr, False) else NewCntr2.NativeValue := 128; finally wbEndInternalEdit; end; end; procedure wbWATRAfterLoad(const aElement: IwbElement); var Container: IwbContainerElementRef; MainRecord : IwbMainRecord; // AnimationMultiplier : Extended; // AnimationAttackMultiplier : Extended; OldCntr: IwbContainerElementRef; NewCntr: IwbContainerElementRef; i: Integer; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; if Container.ElementExists['DNAM'] then Exit; if not Supports(Container.RemoveElement('DATA - Visual Data'), IwbContainerElementRef, OldCntr) then Exit; if not Supports(Container.Add('DNAM', True), IwbContainerElementRef, NewCntr) then Exit; for i := 0 to Pred(Min(OldCntr.ElementCount, NewCntr.ElementCount)) do if OldCntr.Elements[i].Name = 'Damage (Old Format)' then Container.ElementNativeValues['DATA - Damage'] := OldCntr.Elements[i].NativeValue else NewCntr.Elements[i].Assign(Low(Integer), OldCntr.Elements[i], False); NewCntr.ElementNativeValues['Noise Properties - Noise Layer One - Amplitude Scale'] := 1.0; NewCntr.ElementNativeValues['Noise Properties - Noise Layer Two - Amplitude Scale'] := 0.5; NewCntr.ElementNativeValues['Noise Properties - Noise Layer Three - Amplitude Scale'] := 0.25; finally wbEndInternalEdit; end; end; procedure wbWEAPAfterLoad(const aElement: IwbElement); var Container: IwbContainerElementRef; MainRecord : IwbMainRecord; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; if not Container.ElementExists['DNAM'] then Exit; if Container.ElementNativeValues['DNAM\Animation Multiplier'] = 0.0 then Container.ElementNativeValues['DNAM\Animation Multiplier'] := 1.0; if Container.ElementNativeValues['DNAM\Animation Attack Multiplier'] = 0.0 then Container.ElementNativeValues['DNAM\Animation Attack Multiplier'] := 1.0; finally wbEndInternalEdit; end; end; procedure wbMESGAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; MainRecord : IwbMainRecord; IsMessageBox : Boolean; HasTimeDelay : Boolean; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; IsMessageBox := (Integer(Container.ElementNativeValues['DNAM']) and 1) = 1; HasTimeDelay := Container.ElementExists['TNAM']; if IsMessageBox = HasTimeDelay then if IsMessageBox then Container.RemoveElement('TNAM') else begin if not Container.ElementExists['DNAM'] then Container.Add('DNAM', True); Container.ElementNativeValues['DNAM'] := Integer(Container.ElementNativeValues['DNAM']) or 1; end; finally wbEndInternalEdit; end; end; procedure wbEFSHAfterLoad(const aElement: IwbElement); var Container: IwbContainerElementRef; MainRecord : IwbMainRecord; FullParticleBirthRatio : Extended; PersistantParticleBirthRatio : Extended; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; if not Container.ElementExists['DATA'] then Exit; FullParticleBirthRatio := Container.ElementNativeValues['DATA\Particle Shader - Full Particle Birth Ratio']; PersistantParticleBirthRatio := Container.ElementNativeValues['DATA\Particle Shader - Persistant Particle Birth Ratio']; if ((FullParticleBirthRatio <> 0) and (FullParticleBirthRatio <= 1)) then begin FullParticleBirthRatio := FullParticleBirthRatio * 78.0; Container.ElementNativeValues['DATA\Particle Shader - Full Particle Birth Ratio'] := FullParticleBirthRatio; end; if ((PersistantParticleBirthRatio <> 0) and (PersistantParticleBirthRatio <= 1)) then begin PersistantParticleBirthRatio := PersistantParticleBirthRatio * 78.0; Container.ElementNativeValues['DATA\Particle Shader - Persistant Particle Birth Ratio'] := PersistantParticleBirthRatio; end; finally wbEndInternalEdit; end; end; procedure wbFACTAfterLoad(const aElement: IwbElement); var Container: IwbContainerElementRef; MainRecord : IwbMainRecord; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Container.ElementExists['CNAM'] then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; Container.RemoveElement('CNAM'); finally wbEndInternalEdit; end; end; procedure wbLIGHAfterLoad(const aElement: IwbElement); var Container: IwbContainerElementRef; MainRecord : IwbMainRecord; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; if not Container.ElementExists['FNAM'] then begin Container.Add('FNAM', True); Container.ElementNativeValues['FNAM'] := 1.0; end; if Container.ElementExists['DATA'] then begin if SameValue(Container.ElementNativeValues['DATA\Falloff Exponent'], 0.0) then Container.ElementNativeValues['DATA\Falloff Exponent'] := 1.0; if SameValue(Container.ElementNativeValues['DATA\FOV'], 0.0) then Container.ElementNativeValues['DATA\FOV'] := 90.0; end; finally wbEndInternalEdit; end; end; procedure wbEFITAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; Element : IwbElement; ActorValue: Variant; MainRecord: IwbMainRecord; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; MainRecord := Container.ContainingMainRecord; if not Assigned(MainRecord) or MainRecord.IsDeleted then Exit; Element := Container.ElementByPath['..\EFID']; if not Assigned(Element) then Exit; if not Supports(Element.LinksTo, IwbMainRecord, MainRecord) then Exit; if MainRecord.Signature <> 'MGEF' then Exit; ActorValue := MainRecord.ElementNativeValues['DATA - Data\Actor Value']; if VarIsNull(ActorValue) or VarIsClear(ActorValue) then Exit; if VarCompareValue(ActorValue, Container.ElementNativeValues['Actor Value']) <> vrEqual then Container.ElementNativeValues['Actor Value'] := ActorValue; finally wbEndInternalEdit; end; end; procedure wbRPLDAfterLoad(const aElement: IwbElement); var Container: IwbContainer; a, b: Single; NeedsFlip: Boolean; begin if wbBeginInternalEdit then try if Supports(aElement, IwbContainer, Container) then begin NeedsFlip := False; if Container.ElementCount > 1 then begin a := StrToFloat((Container.Elements[0] as IwbContainer).Elements[0].Value); b := StrToFloat((Container.Elements[Pred(Container.ElementCount)] as IwbContainer).Elements[0].Value); case CompareValue(a, b) of EqualsValue: begin a := StrToFloat((Container.Elements[0] as IwbContainer).Elements[1].Value); b := StrToFloat((Container.Elements[Pred(Container.ElementCount)] as IwbContainer).Elements[1].Value); NeedsFlip := CompareValue(a, b) = GreaterThanValue; end; GreaterThanValue: NeedsFlip := True; end; end; if NeedsFlip then Container.ReverseElements; end; finally wbEndInternalEdit; end; end; function wbPxDTLocationDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container: IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; Result := Container.ElementByName['Type'].NativeValue; end; function wbPKDTFalloutBehaviorFlagsDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; SubRecord : IwbSubRecord; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; if Supports(Container, IwbSubRecord, SubRecord) then if SubRecord.SubRecordHeaderSize = 8 then Result := 1; end; function wbPKDTSpecificFlagsDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; SubRecord : IwbSubRecord; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; if Supports(Container, IwbSubRecord, SubRecord) then if SubRecord.SubRecordHeaderSize = 8 then Exit; Result := Container.ElementByName['Type'].NativeValue + 1; end; procedure wbIDLAsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var Element : IwbElement; Container : IwbContainer; SelfAsContainer : IwbContainer; begin if wbBeginInternalEdit then try // if not wbCounterAfterSet('IDLC - Animation Count', aElement) then if Supports(aElement.Container, IwbContainer, Container) then begin Element := Container.ElementByPath['IDLC\Animation Count']; if Assigned(Element) and Supports(aElement, IwbContainer, SelfAsContainer) and (Element.GetNativeValue<>SelfAsContainer.GetElementCount) then Element.SetNativeValue(SelfAsContainer.GetElementCount); end; finally wbEndInternalEdit; end; end; procedure wbAnimationsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var Element : IwbElement; Elems : IwbElement; Container : IwbContainer; begin if wbBeginInternalEdit then try // if not wbCounterContainerAfterSet('IDLC - Animation Count', 'IDLA - Animations', aElement) then if Supports(aElement, IwbContainer, Container) then begin Element := Container.ElementByPath['IDLC\Animation Count']; Elems := Container.ElementByName['IDLA - Animations']; if Assigned(Element) and not Assigned(Elems) then if Element.GetNativeValue<>0 then Element.SetNativeValue(0); end; finally wbEndInternalEdit; end; end; function wbOffsetDataColsCounter(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Cardinal; var Container : IwbDataContainer; Element : IwbElement; fResult : Extended; begin Result := 0; if Supports(aElement.Container, IwbDataContainer, Container) and (Container.Name = 'OFST - Offset Data') and Supports(Container.Container, IwbDataContainer, Container) then begin Element := Container.ElementByPath['Object Bounds\NAM0 - Min\X']; if Assigned(Element) then begin fResult := Element.NativeValue; if fResult >= MaxInt then Result := 0 else Result := Trunc(fResult); Element := Container.ElementByPath['Object Bounds\NAM9 - Max\X']; if Assigned(Element) then begin fResult := Element.NativeValue; if fResult >= MaxInt then Result := 1 else Result := Trunc(fResult) - Result + 1; end; end; end; end; procedure DefineFNVa; begin wbRecordFlags := wbInteger('Record Flags', itU32, wbFlags([ {0x00000001}'ESM', {0x00000002}'', {0x00000004}'', // Plugin selected (Editor) {0x00000008}'Form initialized (Runtime only)', // Form cannot be saved (Runtime)/Plugin active (Editor) {0x00000010}'', // Plugin cannot be active or selected (Editor) {0x00000020}'Deleted', {0x00000040}'Border Region / Has Tree LOD / Constant / Hidden From Local Map / Plugin Endian', {0x00000080}'Turn Off Fire', {0x00000100}'Inaccessible', {0x00000200}'Casts shadows / On Local Map / Motion Blur', {0x00000400}'Quest item / Persistent reference', {0x00000800}'Initially disabled', {0x00001000}'Ignored', {0x00002000}'No Voice Filter', {0x00004000}'Cannot Save (Runtime only)', {0x00008000}'Visible when distant', {0x00010000}'Random Anim Start / High Priority LOD', {0x00020000}'Dangerous / Off limits (Interior cell) / Radio Station (Talking Activator)', {0x00040000}'Compressed', {0x00080000}'Can''t wait / Platform Specific Texture / Dead', {0x00100000}'Unknown 21', {0x00200000}'Load Started (Runtime Only)', // set when beginning to load the form from save {0x00400000}'Unknown 23', {0x00800000}'Unknown 24', // Runtime might use it for "Not dead" on non actors. {0x01000000}'Destructible (Runtime only)', {0x02000000}'Obstacle / No AI Acquire', {0x03000000}'NavMesh Generation - Filter', {0x08000000}'NavMesh Generation - Bounding Box', {0x10000000}'Non-Pipboy / Reflected by Auto Water', {0x20000000}'Child Can Use / Refracted by Auto Water', {0x40000000}'NavMesh Generation - Ground', {0x80000000}'Multibound' ])); (* wbInteger('Record Flags 2', itU32, wbFlags([ {0x00000001}'Unknown 1', {0x00000002}'Unknown 2', {0x00000004}'Unknown 3', {0x00000008}'Unknown 4', {0x00000010}'Unknown 5', {0x00000020}'Unknown 6', {0x00000040}'Unknown 7', {0x00000080}'Unknown 8', {0x00000100}'Unknown 9', {0x00000200}'Unknown 10', {0x00000400}'Unknown 11', {0x00000800}'Unknown 12', {0x00001000}'Unknown 13', {0x00002000}'Unknown 14', {0x00004000}'Unknown 15', {0x00008000}'Unknown 16', {0x00010000}'Unknown 17', {0x00020000}'Unknown 18', {0x00040000}'Unknown 19', {0x00080000}'Unknown 20', {0x00100000}'Unknown 21', {0x00200000}'Unknown 22', {0x00400000}'Unknown 23', {0x00800000}'Unknown 24', {0x01000000}'Unknown 25', {0x02000000}'Unknown 26', {0x03000000}'Unknown 27', {0x08000000}'Unknown 28', {0x10000000}'Unknown 29', {0x20000000}'Unknown 30', {0x40000000}'Unknown 31', {0x80000000}'Unknown 32' ])); (**) wbMainRecordHeader := wbStruct('Record Header', [ wbString('Signature', 4, cpCritical), wbInteger('Data Size', itU32, nil, cpIgnore), wbRecordFlags, wbFormID('FormID', cpFormID), wbInteger('Version Control Master FormID', itU32, nil, cpIgnore), wbInteger('Form Version', itU16, nil, cpIgnore), wbInteger('Version Control Info 2', itU16, nil, cpIgnore) // limited to values from 0 to 0xF ]); wbSizeOfMainRecordStruct := 24; wbIgnoreRecords.Add(XXXX); wbXRGD := wbByteArray(XRGD, 'Ragdoll Data'); wbXRGB := wbByteArray(XRGB, 'Ragdoll Biped Data'); wbMusicEnum := wbEnum(['Default', 'Public', 'Dungeon']); wbSoundLevelEnum := wbEnum([ 'Loud', 'Normal', 'Silent' ]); wbWeaponAnimTypeEnum := wbEnum([ {00} 'Hand to Hand', {01} 'Melee (1 Hand)', {02} 'Melee (2 Hand)', {03} 'Pistol - Balistic (1 Hand)', {04} 'Pistol - Energy (1 Hand)', {05} 'Rifle - Balistic (2 Hand)', {06} 'Rifle - Automatic (2 Hand)', {07} 'Rifle - Energy (2 Hand)', {08} 'Handle (2 Hand)', {09} 'Launcher (2 Hand)', {10} 'Grenade Throw (1 Hand)', {11} 'Land Mine (1 Hand)', {12} 'Mine Drop (1 Hand)', {13} 'Thrown (1 Hand)' ]); wbReloadAnimEnum := wbEnum([ 'ReloadA', 'ReloadB', 'ReloadC', 'ReloadD', 'ReloadE', 'ReloadF', 'ReloadG', 'ReloadH', 'ReloadI', 'ReloadJ', 'ReloadK', 'ReloadL', 'ReloadM', 'ReloadN', 'ReloadO', 'ReloadP', 'ReloadQ', 'ReloadR', 'ReloadS', // 'ReloadT', // 'ReloadU', // 'ReloadV', 'ReloadW', 'ReloadX', 'ReloadY', 'ReloadZ' ],[255, 'None']); // 255 seen in DLC, though Geck converts to 0 wbEDID := wbString(EDID, 'Editor ID', 0, cpNormal); // not cpBenign according to Arthmoor wbEDIDReq := wbString(EDID, 'Editor ID', 0, cpNormal, True); // not cpBenign according to Arthmoor wbFULL := wbString(FULL, 'Name', 0, cpTranslate); wbFULLActor := wbString(FULL, 'Name', 0, cpTranslate, False, wbActorTemplateUseBaseData); wbFULLReq := wbString(FULL, 'Name', 0, cpNormal, True); wbDESC := wbString(DESC, 'Description', 0, cpTranslate); wbDESCReq := wbString(DESC, 'Description', 0, cpTranslate, True); wbXSCL := wbFloat(XSCL, 'Scale'); wbOBND := wbStruct(OBND, 'Object Bounds', [ wbInteger('X1', itS16), wbInteger('Y1', itS16), wbInteger('Z1', itS16), wbInteger('X2', itS16), wbInteger('Y2', itS16), wbInteger('Z2', itS16) ]); wbOBNDReq := wbStruct(OBND, 'Object Bounds', [ wbInteger('X1', itS16), wbInteger('Y1', itS16), wbInteger('Z1', itS16), wbInteger('X2', itS16), wbInteger('Y2', itS16), wbInteger('Z2', itS16) ], cpNormal, True); wbREPL := wbFormIDCkNoReach(REPL, 'Repair List', [FLST]); wbEITM := wbFormIDCk(EITM, 'Object Effect', [ENCH, SPEL]); wbBIPL := wbFormIDCk(BIPL, 'Biped Model List', [FLST]); wbCOED := wbStructExSK(COED, [2], [0, 1], 'Extra Data', [ {00} wbFormIDCkNoReach('Owner', [NPC_, FACT, NULL]), {04} wbUnion('Global Variable / Required Rank', wbCOEDOwnerDecider, [ wbByteArray('Unused', 4, cpIgnore), wbFormIDCk('Global Variable', [GLOB, NULL]), wbInteger('Required Rank', itS32) ]), {08} wbFloat('Item Condition') ]); wbYNAM := wbFormIDCk(YNAM, 'Sound - Pick Up', [SOUN]); wbZNAM := wbFormIDCk(ZNAM, 'Sound - Drop', [SOUN]); wbPosRot := wbStruct('Position/Rotation', [ wbStruct('Position', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), wbStruct('Rotation', [ wbFloat('X', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Y', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Z', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize) ]) ]); wbDATAPosRot := wbStruct(DATA, 'Position/Rotation', [ wbStruct('Position', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), wbStruct('Rotation', [ wbFloat('X', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Y', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Z', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize) ]) ], cpNormal, True); wbMODS := wbArrayS(MODS, 'Alternate Textures', wbStructSK([0, 2], 'Alternate Texture', [ wbLenString('3D Name'), wbFormIDCk('New Texture', [TXST]), wbInteger('3D Index', itS32) ]), -1); wbMO2S := wbArrayS(MO2S, 'Alternate Textures', wbStructSK([0, 2], 'Alternate Texture', [ wbLenString('3D Name'), wbFormIDCk('New Texture', [TXST]), wbInteger('3D Index', itS32) ]), -1); wbMO3S := wbArrayS(MO3S, 'Alternate Textures', wbStructSK([0, 2], 'Alternate Texture', [ wbLenString('3D Name'), wbFormIDCk('New Texture', [TXST]), wbInteger('3D Index', itS32) ]), -1); wbMO4S := wbArrayS(MO4S, 'Alternate Textures', wbStructSK([0, 2], 'Alternate Texture', [ wbLenString('3D Name'), wbFormIDCk('New Texture', [TXST]), wbInteger('3D Index', itS32) ]), -1); wbMODD := wbInteger(MODD, 'FaceGen Model Flags', itU8, wbFlags([ 'Head', 'Torso', 'Right Hand', 'Left Hand' ])); wbMOSD := wbInteger(MOSD, 'FaceGen Model Flags', itU8, wbFlags([ 'Head', 'Torso', 'Right Hand', 'Left Hand' ])); wbMODL := wbRStructSK([0], 'Model', [ wbString(MODL, 'Model Filename', 0, cpNormal, True), wbByteArray(MODB, 'Unknown', 4, cpIgnore), wbByteArray(MODT, 'Texture Files Hashes', 0, cpIgnore), // wbArray(MODT, 'Texture Files Hashes', // wbByteArray('Unknown', 24, cpBenign), // wbArray('Hashes', wbInteger('Hash', itU64, wbMODTCallback), 3), // 0, nil, nil, cpBenign), wbMODS, wbMODD ], [], cpNormal, False, nil, True); wbMODLActor := wbRStructSK([0], 'Model', [ wbString(MODL, 'Model Filename', 0, cpNormal, True), wbByteArray(MODB, 'Unknown', 4, cpIgnore), wbByteArray(MODT, 'Texture Files Hashes', 0, cpIgnore), // wbArray(MODT, 'Texture Files Hashes', // wbByteArray('Unknown', 24, cpBenign), // wbArray('Hashes', wbInteger('Hash', itU64, wbMODTCallback), 3), // 0, nil, nil, cpBenign), wbMODS, wbMODD ], [], cpNormal, False, wbActorTemplateUseModelAnimation, True); wbMODLReq := wbRStructSK([0], 'Model', [ wbString(MODL, 'Model Filename', 0, cpNormal, True), wbByteArray(MODB, 'Unknown', 4, cpIgnore), wbByteArray(MODT, 'Texture Files Hashes', 0, cpIgnore), // wbArray(MODT, 'Texture Files', // wbByteArray('Unknown', 24, cpBenign), // wbArray('Hashes', wbInteger('Hash', itU64, wbMODTCallback), 3), // 0, nil, nil, cpBenign), wbMODS, wbMODD ], [], cpNormal, True, nil, True); wbDEST := wbRStruct('Destructable', [ wbStruct(DEST, 'Header', [ wbInteger('Health', itS32), wbInteger('Count', itU8), wbInteger('Flags', itU8, wbFlags([ 'VATS Targetable' ], True)), wbByteArray('Unused', 2) ]), wbRArray('Stages', wbRStruct('Stage', [ wbStruct(DSTD, 'Destruction Stage Data', [ wbInteger('Health %', itU8), wbInteger('Index', itU8), wbInteger('Damage Stage', itU8), wbInteger('Flags', itU8, wbFlags([ 'Cap Damage', 'Disable', 'Destroy' ])), wbInteger('Self Damage per Second', itS32), wbFormIDCk('Explosion', [EXPL, NULL]), wbFormIDCk('Debris', [DEBR, NULL]), wbInteger('Debris Count', itS32) ], cpNormal, True), wbRStructSK([0], 'Model', [ wbString(DMDL, 'Model Filename'), wbByteArray(DMDT, 'Texture Files Hashes', 0, cpIgnore) // wbArray(DMDT, 'Unknown', // wbByteArray('Unknown', 24, cpBenign), // 0, nil, nil, cpBenign) ], []), wbEmpty(DSTF, 'End Marker', cpNormal, True) ], []) ) ], []); wbDESTActor := wbRStruct('Destructable', [ wbStruct(DEST, 'Header', [ wbInteger('Health', itS32), wbInteger('Count', itU8), wbInteger('Flags', itU8, wbFlags([ 'VATS Targetable' ])), wbByteArray('Unused', 2) ]), wbRArray('Stages', wbRStruct('Stage', [ wbStruct(DSTD, 'Destruction Stage Data', [ wbInteger('Health %', itU8), wbInteger('Index', itU8), wbInteger('Damage Stage', itU8), wbInteger('Flags', itU8, wbFlags([ 'Cap Damage', 'Disable', 'Destroy' ])), wbInteger('Self Damage per Second', itS32), wbFormIDCk('Explosion', [EXPL, NULL]), wbFormIDCk('Debris', [DEBR, NULL]), wbInteger('Debris Count', itS32) ], cpNormal, True), wbRStructSK([0], 'Model', [ wbString(DMDL, 'Model Filename'), wbByteArray(DMDT, 'Texture Files Hashes', 0, cpIgnore) // wbArray(DMDT, 'Unknown', // wbByteArray('Unknown', 24, cpBenign), // 0, nil, nil, cpBenign) ], []), wbEmpty(DSTF, 'End Marker', cpNormal, True) ], []) ) ], [], cpNormal, False, wbActorTemplateUseModelAnimation); wbSCRI := wbFormIDCk(SCRI, 'Script', [SCPT]); wbSCRIActor := wbFormIDCk(SCRI, 'Script', [SCPT], False, cpNormal, False, wbActorTemplateUseScript); wbENAM := wbFormIDCk(ENAM, 'Object Effect', [ENCH]); wbXLOD := wbArray(XLOD, 'Distant LOD Data', wbFloat('Unknown'), 3); wbXESP := wbStruct(XESP, 'Enable Parent', [ wbFormIDCk('Reference', [PLYR, REFR, ACRE, ACHR, PGRE, PMIS, PBEA]), wbInteger('Flags', itU8, wbFlags([ 'Set Enable State to Opposite of Parent', 'Pop In' ])), wbByteArray('Unused', 3) ]); wbSCHRReq := wbStruct(SCHR, 'Basic Script Data', [ wbByteArray('Unused', 4), wbInteger('RefCount', itU32), wbInteger('CompiledSize', itU32), wbInteger('VariableCount', itU32), wbInteger('Type', itU16, wbEnum([ 'Object', 'Quest' ], [ $100, 'Effect' ])), wbInteger('Flags', itU16, wbFlags([ 'Enabled' ]), cpNormal, False, nil, nil, 1) ], cpNormal, True); wbSCROs := wbRArray('References', wbRUnion('', [ wbFormID(SCRO, 'Global Reference'), // wbFormIDCk(SCRO, 'Global Reference', // [ACTI, DOOR, STAT, FURN, CREA, SPEL, NPC_, CONT, ARMO, AMMO, MISC, WEAP, IMAD, // BOOK, KEYM, ALCH, LIGH, QUST, PLYR, PACK, LVLI, ECZN, EXPL, FLST, IDLM, PMIS, // FACT, ACHR, REFR, ACRE, GLOB, DIAL, CELL, SOUN, MGEF, WTHR, CLAS, EFSH, RACE, // LVLC, CSTY, WRLD, SCPT, IMGS, MESG, MSTT, MUSC, NOTE, PERK, PGRE, PROJ, LVLN, // WATR, ENCH, TREE, REPU, REGN, CSNO, CHAL, IMOD, RCCT, CMNY, CDCK, CHIP, CCRD, // TERM, HAIR, EYES, ADDN, RCPE, NULL]), wbInteger(SCRV, 'Local Variable', itU32) ], []) ); wbSLSD := wbStructSK(SLSD, [0], 'Local Variable Data', [ wbInteger('Index', itU32), wbByteArray('Unused', 12), wbInteger('Flags', itU8, wbFlags(['IsLongOrShort']), cpCritical), wbByteArray('Unused', 7) ]); wbEmbeddedScript := wbRStruct('Embedded Script', [ wbSCHRReq, wbByteArray(SCDA, 'Compiled Embedded Script', 0, cpNormal{, True}), wbStringScript(SCTX, 'Embedded Script Source', 0, cpNormal{, True}), wbRArrayS('Local Variables', wbRStructSK([0], 'Local Variable', [ wbSLSD, wbString(SCVR, 'Name', 0, cpCritical, True) ], [])), wbSCROs ], [], cpNormal, False, nil, False, wbEmbeddedScriptAfterLoad); wbEmbeddedScriptPerk := wbRStruct('Embedded Script', [ wbSCHRReq, wbByteArray(SCDA, 'Compiled Embedded Script', 0, cpNormal, True), wbStringScript(SCTX, 'Embedded Script Source', 0, cpNormal, True), wbRArrayS('Local Variables', wbRStructSK([0], 'Local Variable', [ wbSLSD, wbString(SCVR, 'Name', 0, cpCritical, True) ], [])), wbSCROs ], [], cpNormal, False, wbEPF2DontShow, False, wbEmbeddedScriptAfterLoad); wbEmbeddedScriptReq := wbRStruct('Embedded Script', [ wbSCHRReq, wbByteArray(SCDA, 'Compiled Embedded Script', 0, cpNormal{, True}), wbStringScript(SCTX, 'Embedded Script Source', 0, cpNormal{, True}), wbRArrayS('Local Variables', wbRStructSK([0], 'Local Variable', [ wbSLSD, wbString(SCVR, 'Name', 0, cpCritical, True) ], [])), wbSCROs ], [], cpNormal, True, nil, False, wbEmbeddedScriptAfterLoad); wbXLCM := wbInteger(XLCM, 'Level Modifier', itS32); wbRecord(ACHR, 'Placed NPC', [ wbEDID, wbFormIDCk(NAME, 'Base', [NPC_], False, cpNormal, True), wbFormIDCk(XEZN, 'Encounter Zone', [ECZN]), {--- Ragdoll ---} wbXRGD, wbXRGB, {--- Patrol Data ---} wbRStruct('Patrol Data', [ wbFloat(XPRD, 'Idle Time', cpNormal, True), wbEmpty(XPPA, 'Patrol Script Marker', cpNormal, True), wbFormIDCk(INAM, 'Idle', [IDLE, NULL], False, cpNormal, True), wbEmbeddedScriptReq, wbFormIDCk(TNAM, 'Topic', [DIAL, NULL], False, cpNormal, True) ], []), {--- Leveled Actor ----} wbXLCM, {--- Merchant Container ----} wbFormIDCk(XMRC, 'Merchant Container', [REFR], True), {--- Extra ---} wbInteger(XCNT, 'Count', itS32), wbFloat(XRDS, 'Radius'), wbFloat(XHLP, 'Health'), {--- Decals ---} wbRArrayS('Linked Decals', wbStructSK(XDCR, [0], 'Decal', [ wbFormIDCk('Reference', [REFR]), wbUnknown ]) ), {--- Linked Ref ---} wbFormIDCk(XLKR, 'Linked Reference', [REFR, ACRE, ACHR, PGRE, PMIS, PBEA, PLYR]), wbStruct(XCLP, 'Linked Reference Color', [ wbStruct('Link Start Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Link End Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]) ]), {--- Activate Parents ---} wbRStruct('Activate Parents', [ wbInteger(XAPD, 'Flags', itU8, wbFlags([ 'Parent Activate Only' ], True)), wbRArrayS('Activate Parent Refs', wbStructSK(XAPR, [0], 'Activate Parent Ref', [ wbFormIDCk('Reference', [REFR, ACRE, ACHR, PGRE, PMIS, PBEA, PLYR]), wbFloat('Delay') ]) ) ], []), wbString(XATO, 'Activation Prompt'), {--- Enable Parent ---} wbXESP, {--- Emittance ---} wbFormIDCk(XEMI, 'Emittance', [LIGH, REGN]), {--- MultiBound ---} wbFormIDCk(XMBR, 'MultiBound Reference', [REFR]), {--- Flags ---} wbEmpty(XIBS, 'Ignored By Sandbox'), {--- 3D Data ---} wbXSCL, wbDATAPosRot ], True, wbPlacedAddInfo); wbXOWN := wbFormIDCkNoReach(XOWN, 'Owner', [FACT, ACHR, CREA, NPC_]); // Ghouls can own too aparently ! wbXGLB := wbFormIDCk(XGLB, 'Global variable', [GLOB]); wbRecord(ACRE, 'Placed Creature', [ wbEDID, wbFormIDCk(NAME, 'Base', [CREA], False, cpNormal, True), wbFormIDCk(XEZN, 'Encounter Zone', [ECZN]), wbXRGD, wbXRGB, {--- Patrol Data ---} wbRStruct('Patrol Data', [ wbFloat(XPRD, 'Idle Time', cpNormal, True), wbEmpty(XPPA, 'Patrol Script Marker', cpNormal, True), wbFormIDCk(INAM, 'Idle', [IDLE, NULL], False, cpNormal, True), wbEmbeddedScriptReq, wbFormIDCk(TNAM, 'Topic', [DIAL, NULL], False, cpNormal, True) ], []), {--- Leveled Actor ----} wbXLCM, {--- Ownership ---} wbRStruct('Ownership', [ wbXOWN, wbInteger(XRNK, 'Faction rank', itS32) ], [XCMT, XCMO]), {--- Merchant Container ----} wbFormIDCk(XMRC, 'Merchant Container', [REFR], True), {--- Extra ---} wbInteger(XCNT, 'Count', itS32), wbFloat(XRDS, 'Radius'), wbFloat(XHLP, 'Health'), {--- Decals ---} wbRArrayS('Linked Decals', wbStructSK(XDCR, [0], 'Decal', [ wbFormIDCk('Reference', [REFR, ACRE, ACHR, PGRE, PMIS, PBEA]), wbUnknown ]) ), {--- Linked Ref ---} wbFormIDCk(XLKR, 'Linked Reference', [REFR, ACRE, ACHR, PGRE, PMIS, PBEA, PLYR]), wbStruct(XCLP, 'Linked Reference Color', [ wbStruct('Link Start Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Link End Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]) ]), {--- Activate Parents ---} wbRStruct('Activate Parents', [ wbInteger(XAPD, 'Flags', itU8, wbFlags([ 'Parent Activate Only' ], True)), wbRArrayS('Activate Parent Refs', wbStructSK(XAPR, [0], 'Activate Parent Ref', [ wbFormIDCk('Reference', [REFR, ACRE, ACHR, PGRE, PMIS, PBEA, PLYR]), wbFloat('Delay') ]) ) ], []), wbString(XATO, 'Activation Prompt'), {--- Enable Parent ---} wbXESP, {--- Emittance ---} wbFormIDCk(XEMI, 'Emittance', [LIGH, REGN]), {--- MultiBound ---} wbFormIDCk(XMBR, 'MultiBound Reference', [REFR]), {--- Flags ---} wbEmpty(XIBS, 'Ignored By Sandbox'), {--- 3D Data ---} wbXSCL, wbDATAPosRot ], True, wbPlacedAddInfo); wbRecord(ACTI, 'Activator', [ wbEDIDReq, wbOBNDReq, wbFULL, wbMODL, wbSCRI, wbDEST, wbFormIDCk(SNAM, 'Sound - Looping', [SOUN]), wbFormIDCk(VNAM, 'Sound - Activation', [SOUN]), wbFormIDCk(INAM, 'Radio Template', [SOUN]), wbFormIDCk(RNAM, 'Radio Station', [TACT]), wbFormIDCk(WNAM, 'Water Type', [WATR]), wbString(XATO, 'Activation Prompt') ]); wbICON := wbRStruct('Icon', [ wbString(ICON, 'Large Icon filename', 0, cpNormal, True), wbString(MICO, 'Small Icon filename') ], [], cpNormal, False, nil, True); wbICONReq := wbRStruct('Icon', [ wbString(ICON, 'Large Icon filename', 0, cpNormal, True), wbString(MICO, 'Small Icon filename') ], [], cpNormal, True, nil, True); wbVatsValueFunctionEnum := wbEnum([ 'Weapon Is', 'Weapon In List', 'Target Is', 'Target In List', 'Target Distance', 'Target Part', 'VATS Action', 'Is Success', 'Is Critical', 'Critical Effect Is', 'Critical Effect In List', 'Is Fatal', 'Explode Part', 'Dismember Part', 'Cripple Part', 'Weapon Type Is', 'Is Stranger', 'Is Paralyzing Palm' ]); wbActorValueEnum := wbEnum([ {00} 'Aggresion', {01} 'Confidence', {02} 'Energy', {03} 'Responsibility', {04} 'Mood', {05} 'Strength', {06} 'Perception', {07} 'Endurance', {08} 'Charisma', {09} 'Intelligence', {10} 'Agility', {11} 'Luck', {12} 'Action Points', {13} 'Carry Weight', {14} 'Critical Chance', {15} 'Heal Rate', {16} 'Health', {17} 'Melee Damage', {18} 'Damage Resistance', {19} 'Poison Resistance', {20} 'Rad Resistance', {21} 'Speed Multiplier', {22} 'Fatigue', {23} 'Karma', {24} 'XP', {25} 'Perception Condition', {26} 'Endurance Condition', {27} 'Left Attack Condition', {28} 'Right Attack Condition', {29} 'Left Mobility Condition', {30} 'Right Mobility Condition', {31} 'Brain Condition', {32} 'Barter', {33} 'Big Guns (obsolete)', {34} 'Energy Weapons', {35} 'Explosives', {36} 'Lockpick', {37} 'Medicine', {38} 'Melee Weapons', {39} 'Repair', {40} 'Science', {41} 'Guns', {42} 'Sneak', {43} 'Speech', {44} 'Survival', {45} 'Unarmed', {46} 'Inventory Weight', {47} 'Paralysis', {48} 'Invisibility', {49} 'Chameleon', {50} 'Night Eye', {51} 'Turbo', {52} 'Fire Resistance', {53} 'Water Breathing', {54} 'Rad Level', {55} 'Bloody Mess', {56} 'Unarmed Damage', {57} 'Assistance', {58} 'Electric Resistance', {59} 'Frost Resistance', {60} 'Energy Resistance', {61} 'EMP Resistance', {62} 'Variable01', {63} 'Variable02', {64} 'Variable03', {65} 'Variable04', {66} 'Variable05', {67} 'Variable06', {68} 'Variable07', {79} 'Variable08', {70} 'Variable09', {71} 'Variable10', {72} 'Ignore Crippled Limbs', {73} 'Dehydration', {74} 'Hunger', {75} 'Sleep Deprivation', {76} 'Damage Threshold' ], [ -1, 'None' ]); wbModEffectEnum := wbEnum([ {00} 'None', {01} 'Increase Weapon Damage', {02} 'Increase Clip Capacity', {03} 'Decrease Spread', {04} 'Decrease Weight', {05} 'Regenerate Ammo (shots)', {06} 'Regenerate Ammo (seconds)', {07} 'Decrease Equip Time', {08} 'Increase Rate of Fire', {09} 'Increase Projectile Speed', {10} 'Increase Max. Condition', {11} 'Silence', {12} 'Split Beam', {13} 'VATS Bonus', {14} 'Increase Zoom', {15} 'Decrease Equip Time', {16} 'Suppressor' ]); wbSkillEnum := wbEnum([ 'Barter', 'Big Guns (obsolete)', 'Energy Weapons', 'Explosives', 'Lockpick', 'Medicine', 'Melee Weapons', 'Repair', 'Science', 'Guns', 'Sneak', 'Speech', 'Survival', 'Unarmed' ], [ -1, 'None' ]); wbCrimeTypeEnum := wbEnum([ 'Steal', 'Pickpocket', 'Trespass', 'Attack', 'Murder' ], [ -1, 'None' ]); wbActorValue := wbInteger('Actor Value', itS32, wbActorValueEnum); wbEquipTypeEnum := wbEnum([ {00} 'Big Guns', {01} 'Energy Weapons', {02} 'Small Guns', {03} 'Melee Weapons', {04} 'Unarmed Weapon', {05} 'Thrown Weapons', {06} 'Mine', {07} 'Body Wear', {08} 'Head Wear', {09} 'Hand Wear', {10} 'Chems', {11} 'Stimpack', {12} 'Food', {13} 'Alcohol' ], [ -1, 'None' ]); wbETYP := wbInteger(ETYP, 'Equiptment Type', itS32, wbEquipTypeEnum); wbETYPReq := wbInteger(ETYP, 'Equiptment Type', itS32, wbEquipTypeEnum, cpNormal, True); wbFormTypeEnum := wbEnum([], [ $04, 'Texture Set', $05, 'Menu Icon', $06, 'Global', $07, 'Class', $08, 'Faction', $09, 'Head Part', $0A, 'Hair', $0B, 'Eyes', $0C, 'Race', $0D, 'Sound', $0E, 'Acoustic Space', $0F, 'Skill', $10, 'Base Effect', $11, 'Script', $12, 'Landscape Texture', $13, 'Object Effect', $14, 'Actor Effect', $15, 'Activator', $16, 'Talking Activator', $17, 'Terminal', $18, 'Armor', $19, 'Book', $1A, 'Clothing', $1B, 'Container', $1C, 'Door', $1D, 'Ingredient', $1E, 'Light', $1F, 'Misc', $20, 'Static', $21, 'Static Collection', $22, 'Movable Static', $23, 'Placeable Water', $24, 'Grass', $25, 'Tree', $26, 'Flora', $27, 'Furniture', $28, 'Weapon', $29, 'Ammo', $2A, 'NPC', $2B, 'Creature', $2C, 'Leveled Creature', $2D, 'Leveled NPC', $2E, 'Key', $2F, 'Ingestible', $30, 'Idle Marker', $31, 'Note', $32, 'Constructible Object', $33, 'Projectile', $34, 'Leveled Item', $35, 'Weather', $36, 'Climate', $37, 'Region', $39, 'Cell', $3A, 'Placed Object', $3B, 'Placed Character', $3C, 'Placed Creature', $3E, 'Placed Grenade', $41, 'Worldspace', $42, 'Landscape', $43, 'Navigation Mesh', $45, 'Dialog Topic', $46, 'Dialog Response', $47, 'Quest', $48, 'Idle Animation', $49, 'Package', $4A, 'Combat Style', $4B, 'Load Screen', $4C, 'Leveled Spell', $4D, 'Animated Object', $4E, 'Water', $4F, 'Effect Shader', $51, 'Explosion', $52, 'Debris', $53, 'Image Space', $54, 'Image Space Modifier', $55, 'FormID List', $56, 'Perk', $57, 'Body Part Data', $58, 'Addon Node', $59, 'Actor Value Info', $5A, 'Radiation Stage', $5B, 'Camera Shot', $5C, 'Camera Path', $5D, 'Voice Type', $5E, 'Impact Data', $5F, 'Impact DataSet', $60, 'Armor Addon', $61, 'Encounter Zone', $62, 'Message', $63, 'Ragdoll', $64, 'Default Object Manager', $65, 'Lighting Template', $66, 'Music Type', $67, 'Item Mod', $68, 'Reputation', $69, '?PCBE', //no such records in FalloutNV.esm $6A, 'Recipe', $6B, 'Recipe Category', $6C, 'Casino Chip', $6D, 'Casino', $6E, 'Load Screen Type', $6F, 'Media Set', $70, 'Media Location Controller', $71, 'Challenge', $72, 'Ammo Effect', $73, 'Caravan Card', $74, 'Caravan Money', $75, 'Caravan Deck', $76, 'Dehydration Stages', $77, 'Hunger Stages', $78, 'Sleep Deprivation Stages' ]); wbMenuModeEnum := wbEnum([],[ 1, 'Type: Character Interface', 2, 'Type: Other', 3, 'Type: Console', 1001, 'Specific: Message', 1002, 'Specific: Inventory', 1003, 'Specific: Stats', 1004, 'Specific: HUDMainMenu', 1007, 'Specific: Loading', 1008, 'Specific: Container', 1009, 'Specific: Dialog', 1012, 'Specific: Sleep/Wait', 1013, 'Specific: Pause', 1014, 'Specific: LockPick', 1016, 'Specific: Quantity', 1027, 'Specific: Level Up', 1035, 'Specific: Pipboy Repair', 1036, 'Specific: Race / Sex', 1047, 'Specific: Credits', 1048, 'Specific: CharGen', 1051, 'Specific: TextEdit', 1053, 'Specific: Barter', 1054, 'Specific: Surgery', 1055, 'Specific: Hacking', 1056, 'Specific: VATS', 1057, 'Specific: Computers', 1058, 'Specific: Vendor Repair', 1059, 'Specific: Tutorial', 1060, 'Specific: You''re SPECIAL book' ]); end; procedure DefineFNVb; begin wbMiscStatEnum := wbEnum([ 'Quests Completed', 'Locations Discovered', 'People Killed', 'Creatures Killed', 'Locks Picked', 'Computers Hacked', 'Stimpaks Taken', 'Rad-X Taken', 'RadAway Taken', 'Chems Taken', 'Times Addicted', 'Mines Disarmed', 'Speech Successes', 'Pockets Picked', 'Pants Exploded', 'Books Read', 'Bobbleheads Found', 'Weapons Created', 'People Mezzed', 'Captives Rescued', 'Sandman Kills', 'Paralyzing Punches', 'Robots Disabled', 'Contracts Completed', 'Corpses Eaten', 'Mysterious Stranger Visits', 'Doctor Bags Used', 'Challenges Completed', 'Miss Fortunate Occurrences', 'Disintegrations', 'Have Limbs Crippled', 'Speech Failures', 'Items Crafted', 'Weapon Modifications', 'Items Repaired', 'Total Things Killed', 'Dismembered Limbs', 'Caravan Games Won', 'Caravan Games Lost', 'Barter Amount Traded', 'Roulette Games Played', 'Blackjack Games Played', 'Slots Games Played' ]); wbAlignmentEnum := wbEnum([ 'Good', 'Neutral', 'Evil', 'Very Good', 'Very Evil' ]); wbAxisEnum := wbEnum([], [ 88, 'X', 89, 'Y', 90, 'Z' ]); wbCriticalStageEnum := wbEnum([ 'None', 'Goo Start', 'Goo End', 'Disintegrate Start', 'Disintegrate End' ]); wbSexEnum := wbEnum(['Male','Female']); wbCreatureTypeEnum := wbEnum([ 'Animal', 'Mutated Animal', 'Mutated Insect', 'Abomination', 'Super Mutant', 'Feral Ghoul', 'Robot', 'Giant' ]); wbPlayerActionEnum := wbEnum([ '', 'Swinging Melee Weapon', 'Throwing Grenade', 'Fire Weapon', 'Lay Mine', 'Z Key Object', 'Jumping', 'Knocking over Objects', 'Stand on Table/Chair', 'Iron Sites', 'Destroying Object' ]); wbBodyLocationEnum := wbEnum([ 'Torso', 'Head 1', 'Head 2', 'Left Arm 1', 'Left Arm 2', 'Right Arm 1', 'Right Arm 2', 'Left Leg 1', 'Left Leg 2', 'Left Leg 3', 'Right Leg 1', 'Right Leg 2', 'Right Leg 3', 'Brain' ], [ -1, 'None' ]); wbEFID := wbFormIDCk(EFID, 'Base Effect', [MGEF]); wbEFIT := wbStructSK(EFIT, [3, 4], '', [ wbInteger('Magnitude', itU32), wbInteger('Area', itU32), wbInteger('Duration', itU32), wbInteger('Type', itU32, wbEnum(['Self', 'Touch', 'Target'])), wbActorValue ], cpNormal, True, nil, -1, wbEFITAfterLoad); wbCTDA := wbStruct(CTDA, 'Condition', [ wbInteger('Type', itU8, wbCtdaTypeToStr, wbCtdaTypeToInt, cpNormal, False, nil, wbCtdaTypeAfterSet), wbByteArray('Unused', 3), wbUnion('Comparison Value', wbCTDACompValueDecider, [ wbFloat('Comparison Value - Float'), wbFormIDCk('Comparison Value - Global', [GLOB]) ]), wbInteger('Function', itU32, wbCTDAFunctionToStr, wbCTDAFunctionToInt), // Limited to itu16 wbUnion('Parameter #1', wbCTDAParam1Decider, [ {00} wbByteArray('Unknown', 4), {01} wbByteArray('None', 4, cpIgnore), {02} wbInteger('Integer', itS32), {03} wbInteger('Variable Name (INVALID)', itS32), {04} wbInteger('Sex', itU32, wbSexEnum), {05} wbInteger('Actor Value', itS32, wbActorValueEnum), {06} wbInteger('Crime Type', itU32, wbCrimeTypeEnum), {07} wbInteger('Axis', itU32, wbAxisEnum), {08} wbInteger('Quest Stage (INVALID)', itS32), {09} wbInteger('Misc Stat', itU32, wbMiscStatEnum), {10} wbInteger('Alignment', itU32, wbAlignmentEnum), {11} wbInteger('Equip Type', itU32, wbEquipTypeEnum), {12} wbInteger('Form Type', itU32, wbFormTypeEnum), {13} wbInteger('Critical Stage', itU32, wbCriticalStageEnum), {14} wbFormIDCkNoReach('Object Reference', [PLYR, REFR, ACHR, ACRE, PGRE, PMIS, PBEA, TRGT], True), {16} wbFormIDCkNoReach('Inventory Object', [ARMO, BOOK, MISC, WEAP, AMMO, KEYM, ALCH, NOTE, FLST, CHIP, CMNY, IMOD]), {17} wbFormIDCkNoReach('Actor', [PLYR, ACHR, ACRE, TRGT], True), {18} wbFormIDCkNoReach('Voice Type', [VTYP]), {19} wbFormIDCkNoReach('Idle', [IDLE]), {20} wbFormIDCkNoReach('Form List', [FLST]), {21} wbFormIDCkNoReach('Note', [NOTE]), {22} wbFormIDCkNoReach('Quest', [QUST]), {23} wbFormIDCkNoReach('Faction', [FACT]), {24} wbFormIDCkNoReach('Weapon', [WEAP]), {25} wbFormIDCkNoReach('Cell', [CELL]), {26} wbFormIDCkNoReach('Class', [CLAS]), {27} wbFormIDCkNoReach('Race', [RACE]), {28} wbFormIDCkNoReach('Actor Base', [NPC_, CREA, ACTI, TACT, NULL]), {29} wbFormIDCkNoReach('Global', [GLOB]), {30} wbFormIDCkNoReach('Weather', [WTHR]), {31} wbFormIDCkNoReach('Package', [PACK]), {32} wbFormIDCkNoReach('Encounter Zone', [ECZN]), {33} wbFormIDCkNoReach('Perk', [PERK]), {34} wbFormIDCkNoReach('Owner', [FACT, NPC_]), {35} wbFormIDCkNoReach('Furniture', [FURN, FLST]), {36} wbFormIDCkNoReach('Effect Item', [SPEL, ENCH, ALCH, INGR]), {37} wbFormIDCkNoReach('Base Effect', [MGEF]), {38} wbFormIDCkNoReach('Worldspace', [WRLD]), {39} wbInteger('VATS Value Function', itU32, wbVATSValueFunctionEnum), {40} wbInteger('VATS Value Param (INVALID)', itU32), {41} wbInteger('Creature Type', itU32, wbCreatureTypeEnum), {42} wbInteger('Menu Mode', itU32, wbMenuModeEnum), {43} wbInteger('Player Action', itU32, wbPlayerActionEnum), {44} wbInteger('Body Location', itS32, wbBodyLocationEnum), {45} wbFormIDCkNoReach('Referenceable Object', [CREA, NPC_, PROJ, TREE, SOUN, ACTI, DOOR, STAT, FURN, CONT, ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, LIGH, GRAS, ASPC, IDLM, ARMA, MSTT, NOTE, PWAT, SCOL, TACT, TERM, FLST, CHIP, CMNY, CCRD, IMOD, LVLC, LVLN], [CREA, NPC_, PROJ, TREE, SOUN, ACTI, DOOR, STAT, FURN, CONT, ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, LIGH, GRAS, ASPC, IDLM, ARMA, MSTT, NOTE, PWAT, SCOL, TACT, TERM, CHIP, CMNY, CCRD, IMOD, LVLC, LVLN]), {46} wbInteger('Quest Objective (INVALID)', itS32), {47} wbFormIDCkNoReach('Reputation', [REPU]), {48} wbFormIDCkNoReach('Region', [REGN]), {49} wbFormIDCkNoReach('Challenge', [CHAL]), {50} wbFormIDCkNoReach('Casino', [CSNO]), {51} wbFormID('Form') ]), wbUnion('Parameter #2', wbCTDAParam2Decider, [ {00} wbByteArray('Unknown', 4), {01} wbByteArray('None', 4, cpIgnore), {02} wbInteger('Integer', itS32), {03} wbInteger('Variable Name', itS32, wbCTDAParam2VariableNameToStr, wbCTDAParam2VariableNameToInt), {04} wbInteger('Sex', itU32, wbSexEnum), {05} wbInteger('Actor Value', itS32, wbActorValueEnum), {06} wbInteger('Crime Type', itU32, wbCrimeTypeEnum), {07} wbInteger('Axis', itU32, wbAxisEnum), {08} wbInteger('Quest Stage', itS32, wbCTDAParam2QuestStageToStr, wbCTDAParam2QuestStageToInt), {09} wbInteger('Misc Stat', itU32, wbMiscStatEnum), {10} wbInteger('Alignment', itU32, wbAlignmentEnum), {11} wbInteger('Equip Type', itU32, wbEquipTypeEnum), {12} wbInteger('Form Type', itU32, wbFormTypeEnum), {13} wbInteger('Critical Stage', itU32, wbCriticalStageEnum), {14} wbFormIDCkNoReach('Object Reference', [PLYR, REFR, PMIS, PBEA, ACHR, ACRE, PGRE, TRGT], True), {16} wbFormIDCkNoReach('Inventory Object', [ARMO, BOOK, MISC, WEAP, AMMO, KEYM, ALCH, NOTE, FLST, CHIP, CMNY, CCRD, IMOD]), {17} wbFormIDCkNoReach('Actor', [PLYR, ACHR, ACRE, TRGT], True), {18} wbFormIDCkNoReach('Voice Type', [VTYP]), {19} wbFormIDCkNoReach('Idle', [IDLE]), {20} wbFormIDCkNoReach('Form List', [FLST]), {21} wbFormIDCkNoReach('Note', [NOTE]), {22} wbFormIDCkNoReach('Quest', [QUST]), {23} wbFormIDCkNoReach('Faction', [FACT]), {24} wbFormIDCkNoReach('Weapon', [WEAP]), {25} wbFormIDCkNoReach('Cell', [CELL]), {26} wbFormIDCkNoReach('Class', [CLAS]), {27} wbFormIDCkNoReach('Race', [RACE]), {28} wbFormIDCkNoReach('Actor Base', [NPC_, CREA, ACTI, TACT]), {29} wbFormIDCkNoReach('Global', [GLOB]), {30} wbFormIDCkNoReach('Weather', [WTHR]), {31} wbFormIDCkNoReach('Package', [PACK]), {32} wbFormIDCkNoReach('Encounter Zone', [ECZN]), {33} wbFormIDCkNoReach('Perk', [PERK]), {34} wbFormIDCkNoReach('Owner', [FACT, NPC_]), {35} wbFormIDCkNoReach('Furniture', [FURN, FLST]), {36} wbFormIDCkNoReach('Effect Item', [SPEL, ENCH, ALCH, INGR]), {37} wbFormIDCkNoReach('Base Effect', [MGEF]), {38} wbFormIDCkNoReach('Worldspace', [WRLD]), {39} wbInteger('VATS Value Function (INVALID)', itU32), {40} wbUnion('VATS Value Param', wbCTDAParam2VATSValueParam, [ wbFormIDCkNoReach('Weapon', [WEAP]), wbFormIDCkNoReach('Weapon List', [FLST], [WEAP]), wbFormIDCkNoReach('Target', [NPC_, CREA]), wbFormIDCkNoReach('Target List', [FLST], [NPC_, CREA]), wbByteArray('Unused', 4, cpIgnore), wbInteger('Target Part', itS32, wbActorValueEnum), wbInteger('VATS Action', itU32, wbEnum([ 'Unarmed Attack', 'One Hand Melee Attack', 'Two Hand Melee Attack', 'Fire Pistol', 'Fire Rifle', 'Fire Handle Weapon', 'Fire Launcher', 'Throw Grenade', 'Place Mine', 'Reload', 'Crouch', 'Stand', 'Switch Weapon', 'Toggle Weapon Drawn', 'Heal', 'Player Death', 'Special Weapon Attack', 'Special Unarmed Attack', 'Kill Camera Shot', 'Throw Weapon' ])), wbByteArray('Unused', 4, cpIgnore), wbByteArray('Unused', 4, cpIgnore), wbFormIDCkNoReach('Critical Effect', [SPEL]), wbFormIDCkNoReach('Critical Effect List', [FLST], [SPEL]), wbByteArray('Unused', 4, cpIgnore), wbByteArray('Unused', 4, cpIgnore), wbByteArray('Unused', 4, cpIgnore), wbByteArray('Unused', 4, cpIgnore), wbInteger('Weapon Type', itU32, wbWeaponAnimTypeEnum), wbByteArray('Unused', 4, cpIgnore), wbByteArray('Unused', 4, cpIgnore) ]), {41} wbInteger('Creature Type', itU32, wbCreatureTypeEnum), {42} wbInteger('Menu Mode', itU32, wbMenuModeEnum), {43} wbInteger('Player Action', itU32, wbPlayerActionEnum), {44} wbInteger('Body Location', itS32, wbBodyLocationEnum), {45} wbFormIDCkNoReach('Referenceable Object', [CREA, NPC_, PROJ, TREE, SOUN, ACTI, DOOR, STAT, FURN, CONT, ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, LIGH, GRAS, ASPC, IDLM, ARMA, MSTT, NOTE, PWAT, SCOL, TACT, TERM, FLST, CHIP, CMNY, CCRD, IMOD, LVLC, LVLN], [CREA, NPC_, PROJ, TREE, SOUN, ACTI, DOOR, STAT, FURN, CONT, ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, LIGH, GRAS, ASPC, IDLM, ARMA, MSTT, NOTE, PWAT, SCOL, TACT, TERM, CHIP, CMNY, CCRD, IMOD, LVLC, LVLN]), {46} wbInteger('Quest Objective', itS32, wbCTDAParam2QuestObjectiveToStr, wbCTDAParam2QuestObjectiveToInt), {47} wbFormIDCkNoReach('Reputation', [REPU]), {48} wbFormIDCkNoReach('Region', [REGN]), {49} wbFormIDCkNoReach('Challenge', [CHAL]), {50} wbFormIDCkNoReach('Casino', [CSNO]), {51} wbFormID('Form') ]), wbInteger('Run On', itU32, wbEnum([ 'Subject', 'Target', 'Reference', 'Combat Target', 'Linked Reference' ]), cpNormal, False, nil, wbCTDARunOnAfterSet), wbUnion('Reference', wbCTDAReferenceDecider, [ wbInteger('Unused', itU32, nil, cpIgnore), wbFormIDCkNoReach('Reference', [PLYR, ACHR, ACRE, REFR, PMIS, PBEA, PGRE, NULL], True) // Can end up NULL if the original function requiring a reference is replaced by another who has no Run on prerequisite ]) ], cpNormal, False, nil, 6, wbCTDAAfterLoad); wbCTDAs := wbRArray('Conditions', wbCTDA); wbCTDAsReq := wbRArray('Conditions', wbCTDA, cpNormal, True); wbEffects := wbRStructs('Effects','Effect', [ wbEFID, wbEFIT, wbCTDAs ], []); wbEffectsReq := wbRStructs('Effects','Effect', [ wbEFID, wbEFIT, wbCTDAs ], [], cpNormal, True); wbRecord(ALCH, 'Ingestible', [ wbEDIDReq, wbOBNDReq, wbFULLReq, wbMODL, wbICON, wbSCRI, wbDEST, wbYNAM, wbZNAM, wbETYPReq, wbFloat(DATA, 'Weight', cpNormal, True), wbStruct(ENIT, 'Effect Data', [ wbInteger('Value', itS32), wbInteger('Flags?', itU8, wbFlags([ 'No Auto-Calc (Unused)', 'Food Item', 'Medicine' ])), wbByteArray('Unused', 3), wbFormIDCk('Withdrawal Effect', [SPEL, NULL]), wbFloat('Addiction Chance'), wbFormIDCk('Sound - Consume', [SOUN, NULL]) ], cpNormal, True), wbEffectsReq ]); wbRecord(AMMO, 'Ammunition', [ wbEDIDReq, wbOBNDReq, wbFULLReq, wbMODL, wbICON, wbSCRI, wbDEST, wbYNAM, wbZNAM, wbStruct(DATA, 'Data', [ wbFloat('Speed'), wbInteger('Flags', itU8, wbFlags([ 'Ignores Normal Weapon Resistance', 'Non-Playable' ])), wbByteArray('Unused', 3), wbInteger('Value', itS32), wbInteger('Clip Rounds', itU8) ], cpNormal, True), wbStruct(DAT2, 'Data 2', [ wbInteger('Proj. per Shot', itU32), wbFormIDCk('Projectile', [PROJ, NULL]), wbFloat('Weight'), wbFormIDCk('Consumed Ammo', [AMMO, MISC, NULL]), wbFloat('Consumed Percentage') ], cpNormal, False, nil, 3), wbString(ONAM, 'Short Name'), wbString(QNAM, 'Abbrev.'), wbRArray('Ammo Effects', wbFormIDCk(RCIL, 'Effect', [AMEF]) ) ]); wbRecord(ANIO, 'Animated Object', [ wbEDIDReq, wbMODLReq, wbFormIDCk(DATA, 'Animation', [IDLE], False, cpNormal, True) ]); wbBMDT := wbStruct(BMDT, 'Biped Data', [ wbInteger('Biped Flags', itU32, wbFlags([ {0x00000001} 'Head', {0x00000002} 'Hair', {0x00000004} 'Upper Body', {0x00000008} 'Left Hand', {0x00000010} 'Right Hand', {0x00000020} 'Weapon', {0x00000040} 'PipBoy', {0x00000080} 'Backpack', {0x00000100} 'Necklace', {0x00000200} 'Headband', {0x00000400} 'Hat', {0x00000800} 'Eye Glasses', {0x00001000} 'Nose Ring', {0x00002000} 'Earrings', {0x00004000} 'Mask', {0x00008000} 'Choker', {0x00010000} 'Mouth Object', {0x00020000} 'Body AddOn 1', {0x00040000} 'Body AddOn 2', {0x00080000} 'Body AddOn 3' ])), wbInteger('General Flags', itU8, wbFlags([ {0x0001} '1', {0x0002} '2', {0x0004} 'Has Backpack', {0x0008} 'Medium', {0x0010} '5', {0x0020} 'Power Armor', {0x0040} 'Non-Playable', {0x0080} 'Heavy' ], True)), wbByteArray('Unused') ], cpNormal, True); wbRecord(ARMO, 'Armor', [ wbEDIDReq, wbOBNDReq, wbFULL, wbSCRI, wbEITM, wbBMDT, wbRStruct('Male biped model', [ wbString(MODL, 'Model Filename', 0, cpNormal, True), wbByteArray(MODT, 'Texture Files Hashes', 0, cpIgnore), wbMODS, wbMODD ], [], cpNormal, False, nil, True), wbRStruct('Male world model', [ wbString(MOD2, 'Model Filename'), wbByteArray(MO2T, 'Texture Files Hashes', 0, cpIgnore), wbMO2S ], []), wbString(ICON, 'Male icon filename'), wbString(MICO, 'Male mico filename'), wbRStruct('Female biped model', [ wbString(MOD3, 'Model Filename', 0, cpNormal, True), wbByteArray(MO3T, 'Texture Files Hashes', 0, cpIgnore), wbMO3S, wbMOSD ], [], cpNormal, False, nil, True), wbRStruct('Female world model', [ wbString(MOD4, 'Model Filename'), wbByteArray(MO4T, 'Texture Files Hashes', 0, cpIgnore), wbMO4S ], []), wbString(ICO2, 'Female icon filename'), wbString(MIC2, 'Female mico filename'), wbString(BMCT, 'Ragdoll Constraint Template'), wbREPL, wbBIPL, wbETYPReq, wbYNAM, wbZNAM, wbStruct(DATA, 'Data', [ wbInteger('Value', itS32), wbInteger('Health', itS32), wbFloat('Weight') ], cpNormal, True), wbStruct(DNAM, '', [ wbInteger('AR', itS16, wbDiv(100)), wbInteger('Flags', itU16, wbFlags([ 'Modulates Voice' ])), wbFloat('DT'), wbByteArray('?', 4) ], cpNormal, True, nil, 2), wbInteger(BNAM, 'Overrides Animation Sounds', itU32, wbEnum(['No', 'Yes'])), wbRArray('Animation Sounds', wbStruct(SNAM, 'Animation Sound', [ wbFormIDCk('Sound', [SOUN]), wbInteger('Chance', itU8), wbByteArray('Unused', 3), wbInteger('Type', itU32, wbEnum([], [ 19, 'Run', 21, 'Run (Armor)', 18, 'Sneak', 20, 'Sneak (Armor)', 17, 'Walk', 22, 'Walk (Armor)' ])) ]) ), wbFormIDCk(TNAM, 'Animation Sounds Template', [ARMO]) ]); wbRecord(ARMA, 'Armor Addon', [ wbEDIDReq, wbOBNDReq, wbFULL, wbBMDT, wbRStruct('Male biped model', [ wbString(MODL, 'Model Filename', 0, cpNormal, True), wbByteArray(MODT, 'Texture Files Hashes', 0, cpIgnore), wbMODS, wbMODD ], [], cpNormal, False, nil, True), wbRStruct('Male world model', [ wbString(MOD2, 'Model Filename'), wbByteArray(MO2T, 'Texture Files Hashes', 0, cpIgnore), wbMO2S ], []), wbString(ICON, 'Male icon filename'), wbString(MICO, 'Male mico filename'), wbRStruct('Female biped model', [ wbString(MOD3, 'Model Filename', 0, cpNormal, True), wbByteArray(MO3T, 'Texture Files Hashes', 0, cpIgnore), wbMO3S, wbMOSD ], [], cpNormal, False, nil, True), wbRStruct('Female world model', [ wbString(MOD4, 'Model Filename'), wbByteArray(MO4T, 'Texture Files Hashes', 0, cpIgnore), wbMO4S ], []), wbString(ICO2, 'Female icon filename'), wbString(MIC2, 'Female mico filename'), wbETYPReq, wbStruct(DATA, 'Data', [ wbInteger('Value', itS32), wbInteger('Max Condition', itS32), wbFloat('Weight') ], cpNormal, True), wbStruct(DNAM, '', [ wbInteger('AR', itS16, wbDiv(100)), wbInteger('Flags', itU16, wbFlags([ // Only a byte or 2 distincts byte 'Modulates Voice' ])), wbFloat('DT'), wbByteArray('Unused', 4) ], cpNormal, True, nil, 2) ]); wbRecord(BOOK, 'Book', [ wbEDIDReq, wbOBNDReq, wbFULL, wbMODL, wbICON, wbSCRI, wbDESCReq, wbDEST, wbYNAM, wbZNAM, wbStruct(DATA, 'Data', [ wbInteger('Flags', itU8, wbFlags([ '', 'Can''t be Taken' ])), wbInteger('Skill', itS8, wbSkillEnum), wbInteger('Value', itS32), wbFloat('Weight') ], cpNormal, True) ]); wbSPLO := wbFormIDCk(SPLO, 'Actor Effect', [SPEL]); wbSPLOs := wbRArrayS('Actor Effects', wbSPLO, cpNormal, False, nil, nil, wbActorTemplateUseActorEffectList); wbRecord(CELL, 'Cell', [ wbEDID, wbFULL, wbInteger(DATA, 'Flags', itU8, wbFlags([ {0x01} 'Is Interior Cell', {0x02} 'Has water', {0x04} 'Invert Fast Travel behavior', {0x08} 'No LOD Water', {0x10} '', {0x20} 'Public place', {0x40} 'Hand changed', {0x80} 'Behave like exterior' ]), cpNormal, True), wbStruct(XCLC, 'Grid', [ wbInteger('X', itS32), wbInteger('Y', itS32), wbInteger('Force Hide Land', itU32, wbFlags([ 'Quad 1', 'Quad 2', 'Quad 3', 'Quad 4' ], True)) ], cpNormal, False, nil, 2), wbStruct(XCLL, 'Lighting', [ wbStruct('Ambient Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Directional Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Fog Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbFloat('Fog Near'), wbFloat('Fog Far'), wbInteger('Directional Rotation XY', itS32), wbInteger('Directional Rotation Z', itS32), wbFloat('Directional Fade'), wbFloat('Fog Clip Dist'), wbFloat('Fog Power') ], cpNormal, False, nil, 7), wbArray(IMPF, 'Footstep Materials', wbString('Unknown', 30), [ 'ConcSolid', 'ConcBroken', 'MetalSolid', 'MetalHollow', 'MetalSheet', 'Wood', 'Sand', 'Dirt', 'Grass', 'Water' ]), wbRStruct('Light Template', [ wbFormIDCk(LTMP, 'Template', [LGTM, NULL]), wbInteger(LNAM, 'Inherit', itU32, wbFlags([ {0x00000001}'Ambient Color', {0x00000002}'Directional Color', {0x00000004}'Fog Color', {0x00000008}'Fog Near', {0x00000010}'Fog Far', {0x00000020}'Directional Rotation', {0x00000040}'Directional Fade', {0x00000080}'Clip Distance', {0x00000100}'Fog Power' ]), cpNormal, True) ], [], cpNormal, True ), wbFloat(XCLW, 'Water Height'), wbString(XNAM, 'Water Noise Texture'), wbArrayS(XCLR, 'Regions', wbFormIDCk('Region', [REGN])), wbFormIDCk(XCIM, 'Image Space', [IMGS]), wbByteArray(XCET, 'Unknown', 1, cpIgnore), wbFormIDCk(XEZN, 'Encounter Zone', [ECZN]), wbFormIDCk(XCCM, 'Climate', [CLMT]), wbFormIDCk(XCWT, 'Water', [WATR]), wbRStruct('Ownership', [ wbXOWN, wbInteger(XRNK, 'Faction rank', itS32) ], [XCMT, XCMO]), wbFormIDCk(XCAS, 'Acoustic Space', [ASPC]), wbByteArray(XCMT, 'Unused', 1, cpIgnore), wbFormIDCk(XCMO, 'Music Type', [MUSC]) ], True, wbCellAddInfo, cpNormal, False, wbCELLAfterLoad); wbServiceFlags := wbFlags([ {0x00000001} 'Weapons', {0x00000002} 'Armor', {0x00000004} 'Alcohol', {0x00000008} 'Books', {0x00000010} 'Food', {0x00000020} 'Chems', {0x00000040} 'Stimpacks', {0x00000080} 'Lights?', {0x00000100} '', {0x00000200} '', {0x00000400} 'Miscellaneous', {0x00000800} '', {0x00001000} '', {0x00002000} 'Potions?', {0x00004000} 'Training', {0x00008000} '', {0x00010000} 'Recharge', {0x00020000} 'Repair' ]); wbSpecializationEnum := wbEnum(['Combat', 'Magic', 'Stealth']); wbRecord(CLAS, 'Class', [ wbEDIDReq, wbFULLReq, wbDESCReq, wbICON, wbStruct(DATA, '', [ wbArray('Tag Skills', wbInteger('Tag Skill', itS32, wbActorValueEnum), 4), wbInteger('Flags', itU32, wbFlags(['Playable', 'Guard'], True)), wbInteger('Buys/Sells and Services', itU32, wbServiceFlags), wbInteger('Teaches', itS8, wbSkillEnum), wbInteger('Maximum training level', itU8), wbByteArray('Unused', 2) ], cpNormal, True), wbArray(ATTR, 'Attributes', wbInteger('Attribute', itU8), [ 'Strength', 'Perception', 'Endurance', 'Charisma', 'Intelligence', 'Agility', 'Luck' ], cpNormal, True) ]); end; procedure DefineFNVc; begin wbRecord(CLMT, 'Climate', [ wbEDIDReq, wbArrayS(WLST, 'Weather Types', wbStructSK([0], 'Weather Type', [ wbFormIDCk('Weather', [WTHR, NULL]), wbInteger('Chance', itS32), wbFormIDCk('Global', [GLOB, NULL]) ])), wbString(FNAM, 'Sun Texture'), wbString(GNAM, 'Sun Glare Texture'), wbMODL, wbStruct(TNAM, 'Timing', [ wbStruct('Sunrise', [ wbInteger('Begin', itU8, wbClmtTime), wbInteger('End', itU8, wbClmtTime) ]), wbStruct('Sunset', [ wbInteger('Begin', itU8, wbClmtTime), wbInteger('End', itU8, wbClmtTime) ]), wbInteger('Volatility', itU8), wbInteger('Moons / Phase Length', itU8, wbClmtMoonsPhaseLength) ], cpNormal, True) ]); wbCNTO := wbRStructExSK([0], [1], 'Item', [ wbStructExSK(CNTO, [0], [1], 'Item', [ wbFormIDCk('Item', [ARMO, AMMO, MISC, WEAP, BOOK, LVLI, KEYM, ALCH, NOTE, IMOD, CMNY, CCRD, LIGH, CHIP{, MSTT{?}{, STAT{?}]), wbInteger('Count', itS32) ]), wbCOED ], []); wbCNTOs := wbRArrayS('Items', wbCNTO); wbRecord(CONT, 'Container', [ wbEDIDReq, wbOBNDReq, wbFULL, wbMODL, wbSCRI, wbCNTOs, wbDEST, wbStruct(DATA, '', [ wbInteger('Flags', itU8, wbFlags(['', 'Respawns'])), wbFloat('Weight') ], cpNormal, True), wbFormIDCk(SNAM, 'Sound - Open', [SOUN]), wbFormIDCk(QNAM, 'Sound - Close', [SOUN]), wbFormIDCk(RNAM, 'Sound - Random/Looping', [SOUN]) ], True); wbCSDT := wbRStructSK([0], 'Sound Type', [ wbInteger(CSDT, 'Type', itU32,wbEnum([ {00} 'Left Foot', {01} 'Right Foot', {02} 'Left Back Foot', {03} 'Right Back Foot', {04} 'Idle', {05} 'Aware', {06} 'Attack', {07} 'Hit', {08} 'Death', {09} 'Weapon', {10} 'Movement Loop', {11} 'Conscious Loop', {12} 'Auxiliary 1', {13} 'Auxiliary 2', {14} 'Auxiliary 3', {15} 'Auxiliary 4', {16} 'Auxiliary 5', {17} 'Auxiliary 6', {18} 'Auxiliary 7', {19} 'Auxiliary 8', {19} 'Auxiliary 8', {20} 'Jump', {21} 'PlayRandom/Loop' ])), wbRArrayS('Sounds', wbRStructSK([0], 'Sound', [ wbFormIDCk(CSDI, 'Sound', [SOUN, NULL], False, cpNormal, True), wbInteger(CSDC, 'Sound Chance', itU8, nil, cpNormal, True) ], []), cpNormal, True) ], []); wbCSDTs := wbRArrayS('Sound Types', wbCSDT, cpNormal, False, nil, nil, wbActorTemplateUseModelAnimation); wbAgressionEnum := wbEnum([ 'Unaggressive', 'Aggressive', 'Very Aggressive', 'Frenzied' ]); wbConfidenceEnum := wbEnum([ 'Cowardly', 'Cautious', 'Average', 'Brave', 'Foolhardy' ]); wbMoodEnum := wbEnum([ 'Neutral', 'Afraid', 'Annoyed', 'Cocky', 'Drugged', 'Pleasant', 'Angry', 'Sad' ]); wbAssistanceEnum := wbEnum([ 'Helps Nobody', 'Helps Allies', 'Helps Friends and Allies' ]); wbAggroRadiusFlags := wbFlags([ 'Aggro Radius Behavior' ]); wbAIDT := wbStruct(AIDT, 'AI Data', [ {00} wbInteger('Aggression', itU8, wbAgressionEnum), {01} wbInteger('Confidence', itU8, wbConfidenceEnum), {02} wbInteger('Energy Level', itU8), {03} wbInteger('Responsibility', itU8), {04} wbInteger('Mood', itU8, wbMoodEnum), {05} wbByteArray('Unused', 3), // Mood is stored as a DWord as shown by endianSwapping but is truncated to byte during load :) {08} wbInteger('Buys/Sells and Services', itU32, wbServiceFlags), {0C} wbInteger('Teaches', itS8, wbSkillEnum), {0D} wbInteger('Maximum training level', itU8), {0E} wbInteger('Assistance', itS8, wbAssistanceEnum), {0F} wbInteger('Aggro Radius Behavior', itU8, wbAggroRadiusFlags), {10} wbInteger('Aggro Radius', itS32) ], cpNormal, True, wbActorTemplateUseAIData); wbAttackAnimationEnum := wbEnum([ ], [ 26, 'AttackLeft', 27, 'AttackLeftUp', 28, 'AttackLeftDown', 29, 'AttackLeftIS', 30, 'AttackLeftISUp', 31, 'AttackLeftISDown', 32, 'AttackRight', 33, 'AttackRightUp', 34, 'AttackRightDown', 35, 'AttackRightIS', 36, 'AttackRightISUp', 37, 'AttackRightISDown', 38, 'Attack3', 39, 'Attack3Up', 40, 'Attack3Down', 41, 'Attack3IS', 42, 'Attack3ISUp', 43, 'Attack3ISDown', 44, 'Attack4', 45, 'Attack4Up', 46, 'Attack4Down', 47, 'Attack4IS', 48, 'Attack4ISUp', 49, 'Attack4ISDown', 50, 'Attack5', 51, 'Attack5Up', 52, 'Attack5Down', 53, 'Attack5IS', 54, 'Attack5ISUp', 55, 'Attack5ISDown', 56, 'Attack6', 57, 'Attack6Up', 58, 'Attack6Down', 59, 'Attack6IS', 60, 'Attack6ISUp', 61, 'Attack6ISDown', 62, 'Attack7', 63, 'Attack7Up', 64, 'Attack7Down', 65, 'Attack7IS', 66, 'Attack7ISUp', 67, 'Attack7ISDown', 68, 'Attack8', 69, 'Attack8Up', 70, 'Attack8Down', 71, 'Attack8IS', 72, 'Attack8ISUp', 73, 'Attack8ISDown', 74, 'AttackLoop', 75, 'AttackLoopUp', 76, 'AttackLoopDown', 77, 'AttackLoopIS', 78, 'AttackLoopISUp', 79, 'AttackLoopISDown', 80, 'AttackSpin', 81, 'AttackSpinUp', 82, 'AttackSpinDown', 83, 'AttackSpinIS', 84, 'AttackSpinISUp', 85, 'AttackSpinISDown', 86, 'AttackSpin2', 87, 'AttackSpin2Up', 88, 'AttackSpin2Down', 89, 'AttackSpin2IS', 90, 'AttackSpin2ISUp', 91, 'AttackSpin2ISDown', 92, 'AttackPower', 93, 'AttackForwardPower', 94, 'AttackBackPower', 95, 'AttackLeftPower', 96, 'AttackRightPower', 97, 'PlaceMine', 98, 'PlaceMineUp', 99, 'PlaceMineDown', 100, 'PlaceMineIS', 101, 'PlaceMineISUp', 102, 'PlaceMineISDown', 103, 'PlaceMine2', 104, 'PlaceMine2Up', 105, 'PlaceMine2Down', 106, 'PlaceMine2IS', 107, 'PlaceMine2ISUp', 108, 'PlaceMine2ISDown', 109, 'AttackThrow', 110, 'AttackThrowUp', 111, 'AttackThrowDown', 112, 'AttackThrowIS', 113, 'AttackThrowISUp', 114, 'AttackThrowISDown', 115, 'AttackThrow2', 116, 'AttackThrow2Up', 117, 'AttackThrow2Down', 118, 'AttackThrow2IS', 119, 'AttackThrow2ISUp', 120, 'AttackThrow2ISDown', 121, 'AttackThrow3', 122, 'AttackThrow3Up', 123, 'AttackThrow3Down', 124, 'AttackThrow3IS', 125, 'AttackThrow3ISUp', 126, 'AttackThrow3ISDown', 127, 'AttackThrow4', 128, 'AttackThrow4Up', 129, 'AttackThrow4Down', 130, 'AttackThrow4IS', 131, 'AttackThrow4ISUp', 132, 'AttackThrow4ISDown', 133, 'AttackThrow5', 134, 'AttackThrow5Up', 135, 'AttackThrow5Down', 136, 'AttackThrow5IS', 137, 'AttackThrow5ISUp', 138, 'AttackThrow5ISDown', 167, 'PipBoy', 178, 'PipBoyChild', 255, ' ANY' ]); wbImpactMaterialTypeEnum := wbEnum([ 'Stone', 'Dirt', 'Grass', 'Glass', 'Metal', 'Wood', 'Organic', 'Cloth', 'Water', 'Hollow Metal', 'Organic Bug', 'Organic Glow' ]); wbTemplateFlags := wbFlags([ 'Use Traits', 'Use Stats', 'Use Factions', 'Use Actor Effect List', 'Use AI Data', 'Use AI Packages', 'Use Model/Animation', 'Use Base Data', 'Use Inventory', 'Use Script' ]); wbRecord(CREA, 'Creature', [ wbEDIDReq, wbOBNDReq, wbFULLActor, wbMODLActor, wbSPLOs, wbFormIDCk(EITM, 'Unarmed Attack Effect', [ENCH, SPEL], False, cpNormal, False, wbActorTemplateUseActorEffectList), wbInteger(EAMT, 'Unarmed Attack Animation', itU16, wbAttackAnimationEnum, cpNormal, True, False, wbActorTemplateUseActorEffectList), wbArrayS(NIFZ, 'Model List', wbStringLC('Model'), 0, cpNormal, False, nil, nil, wbActorTemplateUseModelAnimation), wbByteArray(NIFT, 'Texture Files Hashes', 0, cpIgnore, False, False, wbActorTemplateUseModelAnimation), wbStruct(ACBS, 'Configuration', [ {00} wbInteger('Flags', itU32, wbFlags([ {0x000001} 'Biped', {0x000002} 'Essential', {0x000004} 'Weapon & Shield?', {0x000008} 'Respawn', {0x000010} 'Swims', {0x000020} 'Flies', {0x000040} 'Walks', {0x000080} 'PC Level Mult', {0x000100} 'Unknown 8', {0x000200} 'No Low Level Processing', {0x000400} '', {0x000800} 'No Blood Spray', {0x001000} 'No Blood Decal', {0x002000} '', {0x004000} '', {0x008000} 'No Head', {0x010000} 'No Right Arm', {0x020000} 'No Left Arm', {0x040000} 'No Combat in Water', {0x080000} 'No Shadow', {0x100000} 'No VATS Melee', {0x00200000} 'Allow PC Dialogue', {0x00400000} 'Can''t Open Doors', {0x00800000} 'Immobile', {0x01000000} 'Tilt Front/Back', {0x02000000} 'Tilt Left/Right', {0x03000000} 'No Knockdowns', {0x08000000} 'Not Pushable', {0x10000000} 'Allow Pickpocket', {0x20000000} 'Is Ghost', {0x40000000} 'No Rotating To Head-track', {0x80000000} 'Invulnerable' ], [ {0x000001 Biped} wbActorTemplateUseModelAnimation, {0x000002 Essential} wbActorTemplateUseBaseData, {0x000004 Weapon & Shield} nil, {0x000008 Respawn} wbActorTemplateUseBaseData, {0x000010 Swims} wbActorTemplateUseModelAnimation, {0x000020 Flies} wbActorTemplateUseModelAnimation, {0x000040 Walks} wbActorTemplateUseModelAnimation, {0x000080 PC Level Mult} wbActorTemplateUseStats, {0x000100 Unknown 8} nil, {0x000200 No Low Level Processing} wbActorTemplateUseBaseData, {0x000400 } nil, {0x000800 No Blood Spray} wbActorTemplateUseModelAnimation, {0x001000 No Blood Decal} wbActorTemplateUseModelAnimation, {0x002000 } nil, {0x004000 } nil, {0x008000 No Head} wbActorTemplateUseModelAnimation, {0x010000 No Right Arm} wbActorTemplateUseModelAnimation, {0x020000 No Left Arm} wbActorTemplateUseModelAnimation, {0x040000 No Combat in Water} wbActorTemplateUseModelAnimation, {0x080000 No Shadow} wbActorTemplateUseModelAnimation, {0x100000 No VATS Melee} nil, {0x00200000 Allow PC Dialogue} wbActorTemplateUseBaseData, {0x00400000 Can''t Open Doors} wbActorTemplateUseBaseData, {0x00800000 Immobile} wbActorTemplateUseModelAnimation, {0x01000000 Tilt Front/Back} wbActorTemplateUseModelAnimation, {0x02000000 Tilt Left/Right} wbActorTemplateUseModelAnimation, {0x03000000 No Knockdowns} nil, {0x08000000 Not Pushable} wbActorTemplateUseModelAnimation, {0x10000000 Allow Pickpocket} wbActorTemplateUseBaseData, {0x20000000 Is Ghost} nil, {0x40000000 No Rotating To Head-track} wbActorTemplateUseModelAnimation, {0x80000000 Invulnerable} nil ])), {04} wbInteger('Fatigue', itU16, nil, cpNormal, False, wbActorTemplateUseStats), {06} wbInteger('Barter gold', itU16, nil, cpNormal, False, wbActorTemplateUseAIData), {08} wbUnion('Level', wbCreaLevelDecider, [ wbInteger('Level', itS16, nil, cpNormal, False, wbActorTemplateUseStats), wbInteger('Level Mult', itS16, wbDiv(1000), cpNormal, False, wbActorTemplateUseStats) ], cpNormal, False, wbActorTemplateUseStats), {10} wbInteger('Calc min', itU16, nil, cpNormal, False, wbActorTemplateUseStats), {12} wbInteger('Calc max', itU16, nil, cpNormal, False, wbActorTemplateUseStats), {14} wbInteger('Speed Multiplier', itU16, nil, cpNormal, False, wbActorTemplateUseStats), {16} wbFloat('Karma (Alignment)', cpNormal, False, 1, -1, wbActorTemplateUseTraits), {20} wbInteger('Disposition Base', itS16, nil, cpNormal, False, wbActorTemplateUseTraits), {22} wbInteger('Template Flags', itU16, wbTemplateFlags) ], cpNormal, True), wbRArrayS('Factions', wbStructSK(SNAM, [0], 'Faction', [ wbFormIDCk('Faction', [FACT]), wbInteger('Rank', itU8), wbByteArray('Unused', 3) ]), cpNormal, False, nil, nil, wbActorTemplateUseFactions), wbFormIDCk(INAM, 'Death item', [LVLI], False, cpNormal, False, wbActorTemplateUseTraits), wbFormIDCk(VTCK, 'Voice', [VTYP], False, cpNormal, False, wbActorTemplateUseTraits), wbFormIDCk(TPLT, 'Template', [CREA, LVLC]), wbDESTActor, wbSCRIActor, wbRArrayS('Items', wbCNTO, cpNormal, False, nil, nil, wbActorTemplateUseInventory), wbAIDT, wbRArray('Packages', wbFormIDCk(PKID, 'Package', [PACK]), cpNormal, False, nil, nil, wbActorTemplateUseAIPackages), wbArrayS(KFFZ, 'Animations', wbStringLC('Animation'), 0, cpNormal, False, nil, nil, wbActorTemplateUseModelAnimation), wbStruct(DATA, '', [ {00} wbInteger('Type', itU8, wbCreatureTypeEnum, cpNormal, False, wbActorTemplateUseTraits), {01} wbInteger('Combat Skill', itU8, nil, cpNormal, False, wbActorTemplateUseStats), {02} wbInteger('Magic Skill', itU8, nil, cpNormal, False, wbActorTemplateUseStats), {03} wbInteger('Stealth Skill', itU8, nil, cpNormal, False, wbActorTemplateUseStats), {04} wbInteger('Health', itS16, nil, cpNormal, False, wbActorTemplateUseStats), {06} wbByteArray('Unused', 2), {08} wbInteger('Damage', itS16, nil, cpNormal, False, wbActorTemplateUseStats), {10} wbArray('Attributes', wbInteger('Attribute', itU8), [ 'Strength', 'Perception', 'Endurance', 'Charisma', 'Intelligence', 'Agility', 'Luck' ], cpNormal, False, wbActorTemplateUseStats) ], cpNormal, True), wbInteger(RNAM, 'Attack reach', itU8, nil, cpNormal, True, False, wbActorTemplateUseTraits), wbFormIDCk(ZNAM, 'Combat Style', [CSTY], False, cpNormal, False, wbActorTemplateUseTraits), wbFormIDCk(PNAM, 'Body Part Data', [BPTD], False, cpNormal, True, wbActorTemplateUseModelAnimation), wbFloat(TNAM, 'Turning Speed', cpNormal, True, 1, -1, wbActorTemplateUseStats), wbFloat(BNAM, 'Base Scale', cpNormal, True, 1, -1, wbActorTemplateUseStats), wbFloat(WNAM, 'Foot Weight', cpNormal, True, 1, -1, wbActorTemplateUseStats), wbInteger(NAM4, 'Impact Material Type', itU32, wbImpactMaterialTypeEnum, cpNormal, True, False, wbActorTemplateUseModelAnimation), wbInteger(NAM5, 'Sound Level', itU32, wbSoundLevelEnum, cpNormal, True, False, wbActorTemplateUseModelAnimation), wbFormIDCk(CSCR, 'Inherits Sounds from', [CREA], False, cpNormal, False, wbActorTemplateUseModelAnimation), wbCSDTs, wbFormIDCk(CNAM, 'Impact Dataset', [IPDS], False, cpNormal, False, wbActorTemplateUseModelAnimation), wbFormIDCk(LNAM, 'Melee Weapon List', [FLST], False, cpNormal, False, wbActorTemplateUseTraits) ], True); end; procedure DefineFNVd; begin wbRecord(CSTY, 'Combat Style', [ wbEDIDReq, wbStruct(CSTD, 'Advanced - Standard', [ {000}wbInteger('Maneuver Decision - Dodge % Chance', itU8), {001}wbInteger('Maneuver Decision - Left/Right % Chance', itU8), {002}wbByteArray('Unused', 2), {004}wbFloat('Maneuver Decision - Dodge L/R Timer (min)'), {008}wbFloat('Maneuver Decision - Dodge L/R Timer (max)'), {012}wbFloat('Maneuver Decision - Dodge Forward Timer (min)'), {016}wbFloat('Maneuver Decision - Dodge Forward Timer (max)'), {020}wbFloat('Maneuver Decision - Dodge Back Timer Min'), {024}wbFloat('Maneuver Decision - Dodge Back Timer Max'), {028}wbFloat('Maneuver Decision - Idle Timer min'), {032}wbFloat('Maneuver Decision - Idle Timer max'), {036}wbInteger('Melee Decision - Block % Chance', itU8), {037}wbInteger('Melee Decision - Attack % Chance', itU8), {038}wbByteArray('Unused', 2), {040}wbFloat('Melee Decision - Recoil/Stagger Bonus to Attack'), {044}wbFloat('Melee Decision - Unconscious Bonus to Attack'), {048}wbFloat('Melee Decision - Hand-To-Hand Bonus to Attack'), {052}wbInteger('Melee Decision - Power Attacks - Power Attack % Chance', itU8), {053}wbByteArray('Unused', 3), {056}wbFloat('Melee Decision - Power Attacks - Recoil/Stagger Bonus to Power'), {060}wbFloat('Melee Decision - Power Attacks - Unconscious Bonus to Power Attack'), {064}wbInteger('Melee Decision - Power Attacks - Normal', itU8), {065}wbInteger('Melee Decision - Power Attacks - Forward', itU8), {066}wbInteger('Melee Decision - Power Attacks - Back', itU8), {067}wbInteger('Melee Decision - Power Attacks - Left', itU8), {068}wbInteger('Melee Decision - Power Attacks - Right', itU8), {069}wbByteArray('Unused', 3), {072}wbFloat('Melee Decision - Hold Timer (min)'), {076}wbFloat('Melee Decision - Hold Timer (max)'), {080}wbInteger('Flags', itU16, wbFlags([ 'Choose Attack using % Chance', 'Melee Alert OK', 'Flee Based on Personal Survival', '', 'Ignore Threats', 'Ignore Damaging Self', 'Ignore Damaging Group', 'Ignore Damaging Spectators', 'Cannot Use Stealthboy' ])), {082}wbByteArray('Unused', 2), {085}wbInteger('Maneuver Decision - Acrobatic Dodge % Chance', itU8), {085}wbInteger('Melee Decision - Power Attacks - Rushing Attack % Chance', itU8), {086}wbByteArray('Unused', 2), {088}wbFloat('Melee Decision - Power Attacks - Rushing Attack Distance Mult') ], cpNormal, True), wbStruct(CSAD, 'Advanced - Advanced', [ wbFloat('Dodge Fatigue Mod Mult'), wbFloat('Dodge Fatigue Mod Base'), wbFloat('Encumb. Speed Mod Base'), wbFloat('Encumb. Speed Mod Mult'), wbFloat('Dodge While Under Attack Mult'), wbFloat('Dodge Not Under Attack Mult'), wbFloat('Dodge Back While Under Attack Mult'), wbFloat('Dodge Back Not Under Attack Mult'), wbFloat('Dodge Forward While Attacking Mult'), wbFloat('Dodge Forward Not Attacking Mult'), wbFloat('Block Skill Modifier Mult'), wbFloat('Block Skill Modifier Base'), wbFloat('Block While Under Attack Mult'), wbFloat('Block Not Under Attack Mult'), wbFloat('Attack Skill Modifier Mult'), wbFloat('Attack Skill Modifier Base'), wbFloat('Attack While Under Attack Mult'), wbFloat('Attack Not Under Attack Mult'), wbFloat('Attack During Block Mult'), wbFloat('Power Att. Fatigue Mod Base'), wbFloat('Power Att. Fatigue Mod Mult') ], cpNormal, True), wbStruct(CSSD, 'Simple', [ {00} wbFloat('Cover Search Radius'), {04} wbFloat('Take Cover Chance'), {08} wbFloat('Wait Timer (min)'), {12} wbFloat('Wait Timer (max)'), {16} wbFloat('Wait to Fire Timer (min)'), {20} wbFloat('Wait to Fire Timer (max)'), {24} wbFloat('Fire Timer (min)'), {28} wbFloat('Fire Timer (max)'), {32} wbFloat('Ranged Weapon Range Mult (min)'), {36} wbByteArray('Unused', 4), {40} wbInteger('Weapon Restrictions', itU32, wbEnum([ 'None', 'Melee Only', 'Ranged Only' ])), {44} wbFloat('Ranged Weapon Range Mult (max)'), {48} wbFloat('Max Targeting FOV'), {52} wbFloat('Combat Radius'), {56} wbFloat('Semi-Auto Firing Delay Mult (min)'), {60} wbFloat('Semi-Auto Firing Delay Mult (max)') ], cpNormal, True) ]); wbRecord(DIAL, 'Dialog Topic', [ wbEDIDReq, wbRArrayS('Added Quests', wbRStructSK([0], 'Added Quest', [ wbFormIDCkNoReach(QSTI, 'Quest', [QUST], False, cpBenign), wbRArray('Shared Infos', wbRStruct('Shared Info', [ wbFormIDCk(INFC, 'Info Connection', [INFO], False, cpBenign), wbInteger(INFX, 'Info Index', itS32, nil, cpBenign) ], [])) ], [])), // no QSTR in FNV, but keep it just in case wbRArrayS('Removed Quests', wbRStructSK([0], 'Removed Quest', [ wbFormIDCkNoReach(QSTR, 'Quest', [QUST], False, cpBenign) ], [])), // some records have INFC INFX (with absent formids) but no QSTI, probably error in GECK // i.e. [DIAL:001287C6] and [DIAL:000E9084] wbRArray('Unused', wbRStruct('Unused', [ wbUnknown(INFC, cpIgnore), wbUnknown(INFX, cpIgnore) ], []), cpIgnore, False, nil, nil, wbNeverShow), wbFULL, wbFloat(PNAM, 'Priority', cpNormal, True, 1, -1, nil, nil, 50.0), wbString(TDUM, 'Dumb Response'), wbStruct(DATA, '', [ wbInteger('Type', itU8, wbEnum([ {0} 'Topic', {1} 'Conversation', {2} 'Combat', {3} 'Persuasion', {4} 'Detection', {5} 'Service', {6} 'Miscellaneous', {7} 'Radio' ])), wbInteger('Flags', itU8, wbFlags([ 'Rumors', 'Top-level' ])) ], cpNormal, True, nil, 1) ], True); wbRecord(DOOR, 'Door', [ wbEDIDReq, wbOBNDReq, wbFULL, wbMODLReq, wbSCRI, wbDEST, wbFormIDCk(SNAM, 'Sound - Open', [SOUN]), wbFormIDCk(ANAM, 'Sound - Close', [SOUN]), wbFormIDCk(BNAM, 'Sound - Looping', [SOUN]), wbInteger(FNAM, 'Flags', itU8, wbFlags([ '', 'Automatic Door', 'Hidden', 'Minimal Use', 'Sliding Door' ]), cpNormal, True) ]); wbBlendModeEnum := wbEnum([ '', 'Zero', 'One', 'Source Color', 'Source Inverse Color', 'Source Alpha', 'Source Inverted Alpha', 'Dest Alpha', 'Dest Inverted Alpha', 'Dest Color', 'Dest Inverse Color', 'Source Alpha SAT' ]); wbBlendOpEnum := wbEnum([ '', 'Add', 'Subtract', 'Reverse Subtract', 'Minimum', 'Maximum' ]); wbZTestFuncEnum := wbEnum([ '', '', '', 'Equal To', 'Normal', 'Greater Than', '', 'Greater Than or Equal Than', 'Always Show' ]); wbRecord(EFSH, 'Effect Shader', [ wbEDID, wbString(ICON, 'Fill Texture'), wbString(ICO2, 'Particle Shader Texture'), wbString(NAM7, 'Holes Texture'), wbStruct(DATA, '', [ wbInteger('Flags', itU8, wbFlags([ {0} 'No Membrane Shader', {1} '', {2} '', {3} 'No Particle Shader', {4} 'Edge Effect - Inverse', {5} 'Membrane Shader - Affect Skin Only' ])), wbByteArray('Unused', 3), wbInteger('Membrane Shader - Source Blend Mode', itU32, wbBlendModeEnum), wbInteger('Membrane Shader - Blend Operation', itU32, wbBlendOpEnum), wbInteger('Membrane Shader - Z Test Function', itU32, wbZTestFuncEnum), wbStruct('Fill/Texture Effect - Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbFloat('Fill/Texture Effect - Alpha Fade In Time'), wbFloat('Fill/Texture Effect - Full Alpha Time'), wbFloat('Fill/Texture Effect - Alpha Fade Out Time'), wbFloat('Fill/Texture Effect - Presistent Alpha Ratio'), wbFloat('Fill/Texture Effect - Alpha Pulse Amplitude'), wbFloat('Fill/Texture Effect - Alpha Pulse Frequency'), wbFloat('Fill/Texture Effect - Texture Animation Speed (U)'), wbFloat('Fill/Texture Effect - Texture Animation Speed (V)'), wbFloat('Edge Effect - Fall Off'), wbStruct('Edge Effect - Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbFloat('Edge Effect - Alpha Fade In Time'), wbFloat('Edge Effect - Full Alpha Time'), wbFloat('Edge Effect - Alpha Fade Out Time'), wbFloat('Edge Effect - Persistent Alpha Ratio'), wbFloat('Edge Effect - Alpha Pulse Amplitude'), wbFloat('Edge Effect - Alpha Pusle Frequence'), wbFloat('Fill/Texture Effect - Full Alpha Ratio'), wbFloat('Edge Effect - Full Alpha Ratio'), wbInteger('Membrane Shader - Dest Blend Mode', itU32, wbBlendModeEnum), wbInteger('Particle Shader - Source Blend Mode', itU32, wbBlendModeEnum), wbInteger('Particle Shader - Blend Operation', itU32, wbBlendOpEnum), wbInteger('Particle Shader - Z Test Function', itU32, wbZTestFuncEnum), wbInteger('Particle Shader - Dest Blend Mode', itU32, wbBlendModeEnum), wbFloat('Particle Shader - Particle Birth Ramp Up Time'), wbFloat('Particle Shader - Full Particle Birth Time'), wbFloat('Particle Shader - Particle Birth Ramp Down Time'), wbFloat('Particle Shader - Full Particle Birth Ratio'), wbFloat('Particle Shader - Persistant Particle Birth Ratio'), wbFloat('Particle Shader - Particle Lifetime'), wbFloat('Particle Shader - Particle Lifetime +/-'), wbFloat('Particle Shader - Initial Speed Along Normal'), wbFloat('Particle Shader - Acceleration Along Normal'), wbFloat('Particle Shader - Initial Velocity #1'), wbFloat('Particle Shader - Initial Velocity #2'), wbFloat('Particle Shader - Initial Velocity #3'), wbFloat('Particle Shader - Acceleration #1'), wbFloat('Particle Shader - Acceleration #2'), wbFloat('Particle Shader - Acceleration #3'), wbFloat('Particle Shader - Scale Key 1'), wbFloat('Particle Shader - Scale Key 2'), wbFloat('Particle Shader - Scale Key 1 Time'), wbFloat('Particle Shader - Scale Key 2 Time'), wbStruct('Color Key 1 - Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Color Key 2 - Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Color Key 3 - Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbFloat('Color Key 1 - Color Alpha'), wbFloat('Color Key 2 - Color Alpha'), wbFloat('Color Key 3 - Color Alpha'), wbFloat('Color Key 1 - Color Key Time'), wbFloat('Color Key 2 - Color Key Time'), wbFloat('Color Key 3 - Color Key Time'), wbFloat('Particle Shader - Initial Speed Along Normal +/-'), wbFloat('Particle Shader - Initial Rotation (deg)'), wbFloat('Particle Shader - Initial Rotation (deg) +/-'), wbFloat('Particle Shader - Rotation Speed (deg/sec)'), wbFloat('Particle Shader - Rotation Speed (deg/sec) +/-'), wbFormIDCk('Addon Models', [DEBR, NULL]), wbFloat('Holes - Start Time'), wbFloat('Holes - End Time'), wbFloat('Holes - Start Val'), wbFloat('Holes - End Val'), wbFloat('Edge Width (alpha units)'), wbStruct('Edge Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbFloat('Explosion Wind Speed'), wbInteger('Texture Count U', itU32), wbInteger('Texture Count V', itU32), wbFloat('Addon Models - Fade In Time'), wbFloat('Addon Models - Fade Out Time'), wbFloat('Addon Models - Scale Start'), wbFloat('Addon Models - Scale End'), wbFloat('Addon Models - Scale In Time'), wbFloat('Addon Models - Scale Out Time') ], cpNormal, True, nil, 57) ], False, nil, cpNormal, False, wbEFSHAfterLoad); wbRecord(ENCH, 'Object Effect', [ wbEDIDReq, wbFULL, wbStruct(ENIT, 'Effect Data', [ wbInteger('Type', itU32, wbEnum([ {0} '', {1} '', {2} 'Weapon', {3} 'Apparel' ])), wbByteArray('Unused', 4), wbByteArray('Unused', 4), wbInteger('Flags', itU8, wbFlags([ 'No Auto-Calc', 'Auto Calculate', 'Hide Effect' ])), wbByteArray('Unused', 3) ], cpNormal, True), wbEffectsReq ]); wbRecord(EYES, 'Eyes', [ wbEDIDReq, wbFULLReq, wbString(ICON, 'Texture', 0{, cpNormal, True??}), wbInteger(DATA, 'Flags', itU8, wbFlags([ 'Playable', 'Not Male', 'Not Female' ]), cpNormal, True) ]); wbXNAM := wbStructSK(XNAM, [0], 'Relation', [ wbFormIDCkNoReach('Faction', [FACT, RACE]), wbInteger('Modifier', itS32), wbInteger('Group Combat Reaction', itU32, wbEnum([ 'Neutral', 'Enemy', 'Ally', 'Friend' ])) ]); wbXNAMs := wbRArrayS('Relations', wbXNAM); wbRecord(FACT, 'Faction', [ wbEDIDReq, wbFULL, wbXNAMs, wbStruct(DATA, '', [ wbInteger('Flags 1', itU8, wbFlags([ 'Hidden from PC', 'Evil', 'Special Combat' ])), wbInteger('Flags 2', itU8, wbFlags([ 'Track Crime', 'Allow Sell' ])), wbByteArray('Unused', 2) ], cpNormal, True, nil, 1), wbFloat(CNAM, 'Unused'), wbRStructsSK('Ranks', 'Rank', [0], [ wbInteger(RNAM, 'Rank#', itS32), wbString(MNAM, 'Male', 0, cpTranslate), wbString(FNAM, 'Female', 0, cpTranslate), wbString(INAM, 'Insignia (Unused)') ], []), wbFormIDCk(WMI1, 'Reputation', [REPU]) ], False, nil, cpNormal, False, wbFACTAfterLoad); wbRecord(FURN, 'Furniture', [ wbEDIDReq, wbOBNDReq, wbFULL, wbMODLReq, wbSCRI, wbDEST, wbByteArray(MNAM, 'Marker Flags', 0, cpNormal, True) ]); wbRecord(GLOB, 'Global', [ wbEDIDReq, wbInteger(FNAM, 'Type', itU8, wbGLOBFNAM, nil, cpNormal, True), wbFloat(FLTV, 'Value', cpNormal, True) ]); wbRecord(GMST, 'Game Setting', [ wbString(EDID, 'Editor ID', 0, cpCritical, True, nil, wbGMSTEDIDAfterSet), wbUnion(DATA, 'Value', wbGMSTUnionDecider, [ wbString('', 0, cpTranslate), wbInteger('', itS32), wbFloat('') ], cpNormal, True) ]); wbDODT := wbStruct(DODT, 'Decal Data', [ wbFloat('Min Width'), wbFloat('Max Width'), wbFloat('Min Height'), wbFloat('Max Height'), wbFloat('Depth'), wbFloat('Shininess'), wbStruct('Parallax', [ wbFloat('Scale'), wbInteger('Passes', itU8) ]), wbInteger('Flags', itU8, wbFlags([ 'Parallax', 'Alpha - Blending', 'Alpha - Testing' ], True)), wbByteArray('Unused', 2), wbStruct('Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]) ]); wbRecord(TXST, 'Texture Set', [ wbEDIDReq, wbOBNDReq, wbRStruct('Textures (RGB/A)', [ wbString(TX00,'Base Image / Transparency'), wbString(TX01,'Normal Map / Specular'), wbString(TX02,'Environment Map Mask / ?'), wbString(TX03,'Glow Map / Unused'), wbString(TX04,'Parallax Map / Unused'), wbString(TX05,'Environment Map / Unused') ], []), wbDODT, wbInteger(DNAM, 'Flags', itU16, wbFlags([ 'No Specular Map' ]), cpNormal, True) ]); wbRecord(MICN, 'Menu Icon', [ wbEDIDReq, wbICONReq ]); wbRecord(HDPT, 'Head Part', [ wbEDIDReq, wbFULLReq, wbMODL, wbInteger(DATA, 'Flags', itU8, wbFlags([ 'Playable' ]), cpNormal, True), wbRArrayS('Extra Parts', wbFormIDCk(HNAM, 'Part', [HDPT]) ) ]); wbRecord(ASPC, 'Acoustic Space', [ wbEDIDReq, wbOBNDReq, wbFormIDCk(SNAM, 'Dawn / Default Loop', [NULL, SOUN], False, cpNormal, True), wbFormIDCk(SNAM, 'Afternoon', [NULL, SOUN], False, cpNormal, True), wbFormIDCk(SNAM, 'Dusk', [NULL, SOUN], False, cpNormal, True), wbFormIDCk(SNAM, 'Night', [NULL, SOUN], False, cpNormal, True), wbFormIDCk(SNAM, 'Walla', [NULL, SOUN], False, cpNormal, True), wbInteger(WNAM, 'Walla Trigger Count', itU32, nil, cpNormal, True), wbFormIDCk(RDAT, 'Use Sound from Region (Interiors Only)', [REGN]), wbInteger(ANAM, 'Environment Type', itU32, wbEnum([ 'None', 'Default', 'Generic', 'Padded Cell', 'Room', 'Bathroom', 'Livingroom', 'Stone Room', 'Auditorium', 'Concerthall', 'Cave', 'Arena', 'Hangar', 'Carpeted Hallway', 'Hallway', 'Stone Corridor', 'Alley', 'Forest', 'City', 'Mountains', 'Quarry', 'Plain', 'Parkinglot', 'Sewerpipe', 'Underwater', 'Small Room', 'Medium Room', 'Large Room', 'Medium Hall', 'Large Hall', 'Plate' ]), cpNormal, True), wbInteger(INAM, 'Is Interior', itU32, wbEnum(['No', 'Yes']), cpNormal, True) ]); wbRecord(TACT, 'Talking Activator', [ wbEDIDReq, wbOBNDReq, wbFULL, wbMODLReq, wbSCRI, wbDEST, wbFormIDCk(SNAM, 'Looping Sound', [SOUN]), wbFormIDCk(VNAM, 'Voice Type', [VTYP]), wbFormIDCk(INAM, 'Radio Template', [SOUN]) ]); wbRecord(SCPT, 'Script', [ wbEDIDReq, wbSCHRReq, wbByteArray(SCDA, 'Compiled Script'), wbStringScript(SCTX, 'Script Source', 0, cpNormal{, True}), wbRArrayS('Local Variables', wbRStructSK([0], 'Local Variable', [ wbSLSD, wbString(SCVR, 'Name', 0, cpCritical, True) ], [])), wbSCROs ]); wbRecord(TERM, 'Terminal', [ wbEDIDReq, wbOBNDReq, wbFULL, wbMODL, wbSCRI, wbDEST, wbDESCReq, wbFormIDCk(SNAM, 'Sound - Looping', [SOUN]), wbFormIDCk(PNAM, 'Password Note', [NOTE]), wbStruct(DNAM, '', [ wbInteger('Base Hacking Difficulty', itU8, wbEnum([ 'Very Easy', 'Easy', 'Average', 'Hard', 'Very Hard', 'Requires Key' ])), wbInteger('Flags', itU8, wbFlags([ 'Leveled', 'Unlocked', 'Alternate Colors', 'Hide Welcome Text when displaying Image' ])), wbInteger('ServerType', itU8, wbEnum([ '-Server 1-', '-Server 2-', '-Server 3-', '-Server 4-', '-Server 5-', '-Server 6-', '-Server 7-', '-Server 8-', '-Server 9-', '-Server 10-' ])), wbByteArray('Unused', 1) ], cpNormal, True), wbRArray('Menu Items', wbRStruct('Menu Item', [ wbString(ITXT, 'Item Text'), wbString(RNAM, 'Result Text', 0, cpNormal, True), wbInteger(ANAM, 'Flags', itU8, wbFlags([ 'Add Note', 'Force Redraw' ]), cpNormal, True), wbFormIDCk(INAM, 'Display Note', [NOTE]), wbFormIDCk(TNAM, 'Sub Menu', [TERM]), wbEmbeddedScriptReq, wbCTDAs ], []) ) ]); wbRecord(SCOL, 'Static Collection', [ wbEDIDReq, wbOBNDReq, wbMODLReq, wbRStructsSK('Parts', 'Part', [0], [ wbFormIDCk(ONAM, 'Static', [STAT]), wbArrayS(DATA, 'Placements', wbStruct('Placement', [ wbStruct('Position', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), wbStruct('Rotation', [ wbFloat('X', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Y', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Z', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize) ]), wbFloat('Scale') ]), 0, cpNormal, True) ], [], cpNormal, True) ]); wbRecord(MSTT, 'Moveable Static', [ wbEDIDReq, wbOBNDReq, wbFULL, wbMODLReq, wbDEST, wbByteArray(DATA, 'Unknown', 1, cpNormal, True), wbFormIDCk(SNAM, 'Sound', [SOUN]) ]); wbRecord(PWAT, 'Placeable Water', [ wbEDIDReq, wbOBNDReq, wbMODLReq, wbStruct(DNAM, '', [ wbInteger('Flags', itU32, wbFlags([ {0x00000001}'Reflects', {0x00000002}'Reflects - Actors', {0x00000004}'Reflects - Land', {0x00000008}'Reflects - LOD Land', {0x00000010}'Reflects - LOD Buildings', {0x00000020}'Reflects - Trees', {0x00000040}'Reflects - Sky', {0x00000080}'Reflects - Dynamic Objects', {0x00000100}'Reflects - Dead Bodies', {0x00000200}'Refracts', {0x00000400}'Refracts - Actors', {0x00000800}'Refracts - Land', {0x00001000}'', {0x00002000}'', {0x00004000}'', {0x00008000}'', {0x00010000}'Refracts - Dynamic Objects', {0x00020000}'Refracts - Dead Bodies', {0x00040000}'Silhouette Reflections', {0x00080000}'', {0x00100000}'', {0x00200000}'', {0x00400000}'', {0x00800000}'', {0x01000000}'', {0x02000000}'', {0x03000000}'', {0x08000000}'', {0x10000000}'Depth', {0x20000000}'Object Texture Coordinates', {0x40000000}'', {0x80000000}'No Underwater Fog' ])), wbFormIDCk('Water', [WATR]) ], cpNormal, True) ]); wbRecord(IDLM, 'Idle Marker', [ wbEDIDReq, wbOBNDReq, wbInteger(IDLF, 'Flags', itU8, wbFlags([ 'Run in Sequence', '', 'Do Once' ]), cpNormal, True), wbStruct(IDLC, '', [ wbInteger('Animation Count', itU8), wbByteArray('Unused', 3) ], cpNormal, True, nil, 1), wbFloat(IDLT, 'Idle Timer Setting', cpNormal, True), wbArray(IDLA, 'Animations', wbFormIDCk('Animation', [IDLE, NULL]), 0, nil, wbIDLAsAfterSet, cpNormal, True) // NULL looks valid if IDLS\Animation Count is 0 ], False, nil, cpNormal, False, nil, wbAnimationsAfterSet); wbRecord(NOTE, 'Note', [ wbEDIDReq, wbOBNDReq, wbFULL, wbMODL, wbICON, wbYNAM, wbZNAM, wbInteger(DATA, 'Type', itU8, wbEnum([ 'Sound', 'Text', 'Image', 'Voice' ]), cpNormal, True), wbRArrayS('Quests', wbFormIDCkNoReach(ONAM, 'Quest', [QUST]) ), wbString(XNAM, 'Texture'), wbUnion(TNAM, 'Text / Topic', wbNOTETNAMDecide, [ wbString('Text'), wbFormIDCk('Topic', [DIAL]) ]), wbUnion(SNAM, 'Sound / NPC', wbNOTESNAMDecide, [ wbFormIDCk('Sound', [SOUN]), wbFormIDCk('Actor', [NPC_, CREA]) ]) ]); end; procedure DefineFNVe; begin wbRecord(PROJ, 'Projectile', [ wbEDIDReq, wbOBNDReq, wbFULL, wbMODLReq, wbDEST, wbStruct(DATA, 'Data', [ {00} wbInteger('Flags', itU16, wbFlags([ 'Hitscan', 'Explosion', 'Alt. Trigger', 'Muzzle Flash', '', 'Can Be Disabled', 'Can Be Picked Up', 'Supersonic', 'Pins Limbs', 'Pass Through Small Transparent', 'Detonates', 'Rotation' ])), {02} wbInteger('Type', itU16, wbEnum([ {00} '', {01} 'Missile', {02} 'Lobber', {03} '', {04} 'Beam', {05} '', {06} '', {07} '', {08} 'Flame', {09} '', {10} '', {11} '', {12} '', {13} '', {14} '', {15} '', {16} 'Continuous Beam' ])), {04} wbFloat('Gravity'), {08} wbFloat('Speed'), {12} wbFloat('Range'), {16} wbFormIDCk('Light', [LIGH, NULL]), {20} wbFormIDCk('Muzzle Flash - Light', [LIGH, NULL]), {24} wbFloat('Tracer Chance'), {28} wbFloat('Explosion - Alt. Trigger - Proximity'), {32} wbFloat('Explosion - Alt. Trigger - Timer'), {36} wbFormIDCk('Explosion', [EXPL, NULL]), {40} wbFormIDCk('Sound', [SOUN, NULL]), {44} wbFloat('Muzzle Flash - Duration'), {48} wbFloat('Fade Duration'), {52} wbFloat('Impact Force'), {56} wbFormIDCk('Sound - Countdown', [SOUN, NULL]), {60} wbFormIDCk('Sound - Disable', [SOUN, NULL]), {64} wbFormIDCk('Default Weapon Source', [WEAP, NULL]), {68} wbStruct('Rotation', [ {68} wbFloat('X'), {72} wbFloat('Y'), {76} wbFloat('Z') ]), {80} wbFloat('Bouncy Mult') ], cpNormal, True), wbRStructSK([0], 'Muzzle Flash Model', [ wbString(NAM1, 'Model Filename'), wbByteArray(NAM2, 'Texture Files Hashes', 0, cpIgnore) ], [], cpNormal, True), wbInteger(VNAM, 'Sound Level', itU32, wbSoundLevelEnum, cpNormal, True) ]); wbRecord(NAVI, 'Navigation Mesh Info Map', [ wbEDID, wbInteger(NVER, 'Version', itU32), wbRArray('Navigation Map Infos', wbStruct(NVMI, 'Navigation Map Info', [ wbByteArray('Unknown', 4), wbFormIDCk('Navigation Mesh', [NAVM]), wbFormIDCk('Location', [CELL, WRLD]), wbStruct('Grid', [ wbInteger('X', itS16), wbInteger('Y', itS16) ]), wbUnknown { wbUnion('Data', wbNAVINVMIDecider, [ wbStruct('Data', [ wbUnknown ]), wbStruct('Data', [ wbArray('Unknown', wbFloat('Unknown'), 3), wbByteArray('Unknown', 4) ]), wbStruct('Data', [ wbArray('Unknown', wbArray('Unknown', wbFloat('Unknown'), 3), 3), wbInteger('Count 1', itU16), wbInteger('Count 2', itU16), wbArray('Unknown', wbArray('Unknown', wbFloat('Unknown'), 3), [], wbNAVINAVMGetCount1), wbUnknown ]), wbStruct('Data', [ wbUnknown ]) ])} ]) ), wbRArray('Unknown', wbStruct(NVCI, 'Unknown', [ wbFormIDCk('Unknown', [NAVM]), wbArray('Unknown', wbFormIDCk('Unknown', [NAVM]), -1), wbArray('Unknown', wbFormIDCk('Unknown', [NAVM]), -1), wbArray('Doors', wbFormIDCk('Door', [REFR]), -1) ]) ) ]); if wbSimpleRecords then begin wbRecord(NAVM, 'Navigation Mesh', [ wbEDID, wbInteger(NVER, 'Version', itU32), wbStruct(DATA, '', [ wbFormIDCk('Cell', [CELL]), wbInteger('Vertex Count', itU32), wbInteger('Triangle Count', itU32), wbInteger('External Connections Count', itU32), wbInteger('NVCA Count', itU32), wbInteger('Doors Count', itU32) ]), wbByteArray(NVVX, 'Vertices'), wbByteArray(NVTR, 'Triangles'), wbByteArray(NVCA, 'Unknown'), wbArray(NVDP, 'Doors', wbStruct('Door', [ wbFormIDCk('Reference', [REFR]), wbInteger('Triangle', itU16), wbByteArray('Unused', 2) ])), wbByteArray(NVGD, 'Unknown'), wbArray(NVEX, 'External Connections', wbStruct('Connection', [ wbByteArray('Unknown', 4), wbFormIDCk('Navigation Mesh', [NAVM], False, cpNormal), wbInteger('Triangle', itU16, nil, cpNormal) ])) ], False, wbNAVMAddInfo); end else begin wbRecord(NAVM, 'Navigation Mesh', [ wbEDID, wbInteger(NVER, 'Version', itU32), wbStruct(DATA, '', [ wbFormIDCk('Cell', [CELL]), wbInteger('Vertex Count', itU32), wbInteger('Triangle Count', itU32), wbInteger('External Connections Count', itU32), wbInteger('NVCA Count', itU32), wbInteger('Doors Count', itU32) // as of version = 5 (earliest NavMesh version I saw (Fallout3 1.7) is already 11) ]), wbArray(NVVX, 'Vertices', wbStruct('Vertex', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ])), wbArray(NVTR, 'Triangles', wbStruct('Triangle', [ wbArray('Vertices', wbInteger('Vertex', itS16), 3), wbArray('Edges', wbInteger('Triangle', itS16, wbNVTREdgeToStr, wbNVTREdgeToInt), [ '0 <-> 1', '1 <-> 2', '2 <-> 0' ]), wbInteger('Flags', itU32, wbFlags([ 'Triangle #0 Is External', 'Triangle #1 Is External', 'Triangle #2 Is External', 'Unknown 4', 'Unknown 5', 'Unknown 6', 'Preferred pathing', 'Unknown 8', 'Unknown 9', 'Water', 'Contains door', 'Unknown 12', 'Unknown 13', // Cleared on LoadForm 'Unknown 14', // Cleared on LoadForm 'Unknown 15', // Cleared on LoadForm 'Unknown 16', 'Unknown 17', 'Unknown 18', 'Unknown 19', 'Unknown 20', 'Unknown 21', 'Unknown 22', 'Unknown 23', 'Unknown 24', 'Unknown 25', 'Unknown 26', 'Unknown 27', 'Unknown 28', 'Unknown 29', 'Unknown 30', 'Unknown 31', 'Unknown 32' ])) ])), wbArray(NVCA, 'Unknown', wbInteger('Triangle', itS16)), // Assumed triangle as the value fits the triangle id's wbArray(NVDP, 'Doors', wbStruct('Door', [ wbFormIDCk('Reference', [REFR]), wbInteger('Triangle', itU16), wbByteArray('Unused', 2) ])), wbStruct(NVGD, 'NavMesh Grid', [ wbInteger('NavMeshGrid Divisor', itU32), wbFloat('Max X Distance'), // Floats named after TES5 definition wbFloat('Max Y Distance'), wbFloat('Min X'), wbFloat('Min Y'), wbFloat('Min Z'), wbFloat('Max X'), wbFloat('Max Y'), wbFloat('Max Z'), wbArray('Cells', wbArray('Cell', wbInteger('Triangle', itS16), -2)) // Divisor is row count , assumed triangle as the values fit the triangle id's ]), wbArray(NVEX, 'External Connections', wbStruct('Connection', [ wbByteArray('Unknown', 4), // absent in ver<9, not endian swap in ver>=9, so char or byte array wbFormIDCk('Navigation Mesh', [NAVM, NULL], False, cpNormal), // NULL values are ignored silently. wbInteger('Triangle', itU16, nil, cpNormal) ])) // Different if ver<5: Length = $2E/$30 and contains other data between NavMesh and Triangle ], False, wbNAVMAddInfo); end; wbRecord(PGRE, 'Placed Grenade', [ wbEDID, wbFormIDCk(NAME, 'Base', [PROJ], False, cpNormal, True), wbFormIDCk(XEZN, 'Encounter Zone', [ECZN]), wbXRGD, wbXRGB, {--- Patrol Data ---} wbRStruct('Patrol Data', [ wbFloat(XPRD, 'Idle Time', cpNormal, True), wbEmpty(XPPA, 'Patrol Script Marker', cpNormal, True), wbFormIDCk(INAM, 'Idle', [IDLE, NULL], False, cpNormal, True), wbEmbeddedScriptReq, wbFormIDCk(TNAM, 'Topic', [DIAL, NULL], False, cpNormal, True) ], []), {--- Ownership ---} wbRStruct('Ownership', [ wbXOWN, wbInteger(XRNK, 'Faction rank', itS32) ], [XCMT, XCMO]), {--- Extra ---} wbInteger(XCNT, 'Count', itS32), wbFloat(XRDS, 'Radius'), wbFloat(XHLP, 'Health'), {--- Reflected By / Refracted By ---} wbRArrayS('Reflected/Refracted By', wbStructSK(XPWR, [0], 'Water', [ wbFormIDCk('Reference', [REFR]), wbInteger('Type', itU32, wbFlags([ 'Reflection', 'Refraction' ])) ]) ), {--- Decals ---} wbRArrayS('Linked Decals', wbStructSK(XDCR, [0], 'Decal', [ wbFormIDCk('Reference', [REFR]), wbUnknown ]) ), {--- Linked Ref ---} wbFormIDCk(XLKR, 'Linked Reference', [REFR, ACRE, ACHR, PGRE, PMIS, PBEA, PLYR]), wbStruct(XCLP, 'Linked Reference Color', [ wbStruct('Link Start Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Link End Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]) ]), {--- Activate Parents ---} wbRStruct('Activate Parents', [ wbInteger(XAPD, 'Flags', itU8, wbFlags([ 'Parent Activate Only' ], True)), wbRArrayS('Activate Parent Refs', wbStructSK(XAPR, [0], 'Activate Parent Ref', [ wbFormIDCk('Reference', [REFR, ACRE, ACHR, PGRE, PMIS, PBEA, PLYR]), wbFloat('Delay') ]) ) ], []), wbString(XATO, 'Activation Prompt'), {--- Enable Parent ---} wbXESP, {--- Emittance ---} wbFormIDCk(XEMI, 'Emittance', [LIGH, REGN]), {--- MultiBound ---} wbFormIDCk(XMBR, 'MultiBound Reference', [REFR]), {--- Flags ---} wbEmpty(XIBS, 'Ignored By Sandbox'), {--- 3D Data ---} wbXSCL, wbDATAPosRot ], True, wbPlacedAddInfo); wbRecord(PMIS, 'Placed Missile', [ wbEDID, wbFormIDCk(NAME, 'Base', [PROJ], False, cpNormal, True), wbFormIDCk(XEZN, 'Encounter Zone', [ECZN]), wbXRGD, wbXRGB, {--- Patrol Data ---} wbRStruct('Patrol Data', [ wbFloat(XPRD, 'Idle Time', cpNormal, True), wbEmpty(XPPA, 'Patrol Script Marker', cpNormal, True), wbFormIDCk(INAM, 'Idle', [IDLE, NULL], False, cpNormal, True), wbEmbeddedScriptReq, wbFormIDCk(TNAM, 'Topic', [DIAL, NULL], False, cpNormal, True) ], []), {--- Ownership ---} wbRStruct('Ownership', [ wbXOWN, wbInteger(XRNK, 'Faction rank', itS32) ], [XCMT, XCMO]), {--- Extra ---} wbInteger(XCNT, 'Count', itS32), wbFloat(XRDS, 'Radius'), wbFloat(XHLP, 'Health'), {--- Reflected By / Refracted By ---} wbRArrayS('Reflected/Refracted By', wbStructSK(XPWR, [0], 'Water', [ wbFormIDCk('Reference', [REFR]), wbInteger('Type', itU32, wbFlags([ 'Reflection', 'Refraction' ])) ]) ), {--- Decals ---} wbRArrayS('Linked Decals', wbStructSK(XDCR, [0], 'Decal', [ wbFormIDCk('Reference', [REFR]), wbUnknown ]) ), {--- Linked Ref ---} wbFormIDCk(XLKR, 'Linked Reference', [REFR, ACRE, ACHR, PGRE, PMIS, PBEA, PLYR]), wbStruct(XCLP, 'Linked Reference Color', [ wbStruct('Link Start Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Link End Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]) ]), {--- Activate Parents ---} wbRStruct('Activate Parents', [ wbInteger(XAPD, 'Flags', itU8, wbFlags([ 'Parent Activate Only' ], True)), wbRArrayS('Activate Parent Refs', wbStructSK(XAPR, [0], 'Activate Parent Ref', [ wbFormIDCk('Reference', [REFR, ACRE, ACHR, PGRE, PMIS, PBEA, PLYR]), wbFloat('Delay') ]) ) ], []), wbString(XATO, 'Activation Prompt'), {--- Enable Parent ---} wbXESP, {--- Emittance ---} wbFormIDCk(XEMI, 'Emittance', [LIGH, REGN]), {--- MultiBound ---} wbFormIDCk(XMBR, 'MultiBound Reference', [REFR]), {--- Flags ---} wbEmpty(XIBS, 'Ignored By Sandbox'), {--- 3D Data ---} wbXSCL, wbDATAPosRot ], True, wbPlacedAddInfo); wbRecord(PBEA, 'Placed Beam', [ wbEDID, wbFormIDCk(NAME, 'Base', [PROJ], False, cpNormal, True), wbFormIDCk(XEZN, 'Encounter Zone', [ECZN]), wbXRGD, wbXRGB, {--- Patrol Data ---} wbRStruct('Patrol Data', [ wbFloat(XPRD, 'Idle Time', cpNormal, True), wbEmpty(XPPA, 'Patrol Script Marker', cpNormal, True), wbFormIDCk(INAM, 'Idle', [IDLE, NULL], False, cpNormal, True), wbEmbeddedScriptReq, wbFormIDCk(TNAM, 'Topic', [DIAL, NULL], False, cpNormal, True) ], []), {--- Ownership ---} wbRStruct('Ownership', [ wbXOWN, wbInteger(XRNK, 'Faction rank', itS32) ], [XCMT, XCMO]), {--- Extra ---} wbInteger(XCNT, 'Count', itS32), wbFloat(XRDS, 'Radius'), wbFloat(XHLP, 'Health'), {--- Reflected By / Refracted By ---} wbRArrayS('Reflected/Refracted By', wbStructSK(XPWR, [0], 'Water', [ wbFormIDCk('Reference', [REFR]), wbInteger('Type', itU32, wbFlags([ 'Reflection', 'Refraction' ])) ]) ), {--- Decals ---} wbRArrayS('Linked Decals', wbStructSK(XDCR, [0], 'Decal', [ wbFormIDCk('Reference', [REFR]), wbUnknown ]) ), {--- Linked Ref ---} wbFormIDCk(XLKR, 'Linked Reference', [REFR, ACRE, ACHR, PGRE, PMIS, PBEA, PLYR]), wbStruct(XCLP, 'Linked Reference Color', [ wbStruct('Link Start Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Link End Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]) ]), {--- Activate Parents ---} wbRStruct('Activate Parents', [ wbInteger(XAPD, 'Flags', itU8, wbFlags([ 'Parent Activate Only' ], True)), wbRArrayS('Activate Parent Refs', wbStructSK(XAPR, [0], 'Activate Parent Ref', [ wbFormIDCk('Reference', [REFR, ACRE, ACHR, PGRE, PMIS, PBEA, PLYR]), wbFloat('Delay') ]) ) ], []), wbString(XATO, 'Activation Prompt'), {--- Enable Parent ---} wbXESP, {--- Emittance ---} wbFormIDCk(XEMI, 'Emittance', [LIGH, REGN]), {--- MultiBound ---} wbFormIDCk(XMBR, 'MultiBound Reference', [REFR]), {--- Flags ---} wbEmpty(XIBS, 'Ignored By Sandbox'), {--- 3D Data ---} wbXSCL, wbDATAPosRot ], True, wbPlacedAddInfo); wbRecord(EXPL, 'Explosion', [ wbEDIDReq, wbOBNDReq, wbFULL, wbMODL, wbEITM, wbFormIDCk(MNAM, 'Image Space Modifier', [IMAD]), wbStruct(DATA, 'Data', [ {00} wbFloat('Force'), {04} wbFloat('Damage'), {08} wbFloat('Radius'), {12} wbFormIDCk('Light', [LIGH, NULL]), {16} wbFormIDCk('Sound 1', [SOUN, NULL]), {20} wbInteger('Flags', itU32, wbFlags([ {0x00000001}'Unknown 1', {0x00000002}'Always Uses World Orientation', {0x00000004}'Knock Down - Always', {0x00000008}'Knock Down - By Formula', {0x00000010}'Ignore LOS Check', {0x00000020}'Push Explosion Source Ref Only', {0x00000040}'Ignore Image Space Swap' ])), {24} wbFloat('IS Radius'), {28} wbFormIDCk('Impact DataSet', [IPDS, NULL]), {32} wbFormIDCk('Sound 2', [SOUN, NULL]), wbStruct('Radiation', [ {36} wbFloat('Level'), {40} wbFloat('Dissipation Time'), {44} wbFloat('Radius') ]), {48} wbInteger('Sound Level', itU32, wbSoundLevelEnum, cpNormal, True) ], cpNormal, True), wbFormIDCk(INAM, 'Placed Impact Object', [TREE, SOUN, ACTI, DOOR, STAT, FURN, CONT, ARMO, AMMO, LVLN, LVLC, MISC, WEAP, BOOK, KEYM, ALCH, LIGH, GRAS, ASPC, IDLM, ARMA, MSTT, NOTE, PWAT, SCOL, TACT, TERM, TXST, CHIP, CMNY, CCRD, IMOD]) ]); wbRecord(DEBR, 'Debris', [ wbEDIDReq, wbRStructs('Models', 'Model', [ wbStruct(DATA, 'Data', [ wbInteger('Percentage', itU8), wbString('Model Filename'), wbInteger('Flags', itU8, wbFlags([ 'Has Collission Data' ])) ], cpNormal, True), wbByteArray(MODT, 'Texture Files Hashes', 0, cpIgnore) ], [], cpNormal, True) ]); wbRecord(IMGS, 'Image Space', [ wbEDIDReq, wbStruct(DNAM, '', [ wbStruct('HDR', [ {00} wbFloat('Eye Adapt Speed'), {04} wbFloat('Blur Radius'), {08} wbFloat('Blur Passes'), {12} wbFloat('Emissive Mult'), {16} wbFloat('Target LUM'), {20} wbFloat('Upper LUM Clamp'), {24} wbFloat('Bright Scale'), {28} wbFloat('Bright Clamp'), {32} wbFloat('LUM Ramp No Tex'), {36} wbFloat('LUM Ramp Min'), {40} wbFloat('LUM Ramp Max'), {44} wbFloat('Sunlight Dimmer'), {48} wbFloat('Grass Dimmer'), {52} wbFloat('Tree Dimmer'), {56} wbUnion('Skin Dimmer', wbIMGSSkinDimmerDecider, [ wbFloat('Skin Dimmer'), wbEmpty('Skin Dimmer', cpIgnore) ]) ], cpNormal, False, nil, 14), wbStruct('Bloom', [ {60} wbFloat('Blur Radius'), {64} wbFloat('Alpha Mult Interior'), {68} wbFloat('Alpha Mult Exterior') ]), wbStruct('Get Hit', [ {72} wbFloat('Blur Radius'), {76} wbFloat('Blur Damping Constant'), {80} wbFloat('Damping Constant') ]), wbStruct('Night Eye', [ wbStruct('Tint Color', [ {84} wbFloat('Red', cpNormal, False, 255, 0), {88} wbFloat('Green', cpNormal, False, 255, 0), {92} wbFloat('Blue', cpNormal, False, 255, 0) ]), {96} wbFloat('Brightness') ]), wbStruct('Cinematic', [ {100} wbFloat('Saturation'), wbStruct('Contrast', [ {104} wbFloat('Avg Lum Value'), {108} wbFloat('Value') ]), {112} wbFloat('Cinematic - Brightness - Value'), wbStruct('Tint', [ wbStruct('Color', [ {116} wbFloat('Red', cpNormal, False, 255, 0), {120} wbFloat('Green', cpNormal, False, 255, 0), {124} wbFloat('Blue', cpNormal, False, 255, 0) ]), {128} wbFloat('Value') ]) ]), wbByteArray('Unused', 4), wbByteArray('Unused', 4), wbByteArray('Unused', 4), wbByteArray('Unused', 4), wbInteger('Flags', itU8, wbFlags([ 'Saturation', 'Contrast', 'Tint', 'Brightness' ], True)), wbByteArray('Unused', 3) ], cpNormal, True, nil, 5) ]); wbTimeInterpolator := wbStruct('Data', [ wbFloat('Time'), wbFloat('Value') ]); wbColorInterpolator := wbStruct('Data', [ wbFloat('Time'), wbFloat('Red', cpNormal, False, 255, 0), wbFloat('Green', cpNormal, False, 255, 0), wbFloat('Blue', cpNormal, False, 255, 0), wbFloat('Alpha', cpNormal, False, 255, 0) ]); wbRecord(IMAD, 'Image Space Adapter', [ wbEDID, wbStruct(DNAM, 'Data Count', [ wbInteger('Flags', itU32, wbFlags(['Animatable'])), wbFloat('Duration'), wbStruct('HDR', [ wbInteger('Eye Adapt Speed Mult', itU32), wbInteger('Eye Adapt Speed Add', itU32), wbInteger('Bloom Blur Radius Mult', itU32), wbInteger('Bloom Blur Radius Add', itU32), wbInteger('Bloom Threshold Mult', itU32), wbInteger('Bloom Threshold Add', itU32), wbInteger('Bloom Scale Mult', itU32), wbInteger('Bloom Scale Add', itU32), wbInteger('Target Lum Min Mult', itU32), wbInteger('Target Lum Min Add', itU32), wbInteger('Target Lum Max Mult', itU32), wbInteger('Target Lum Max Add', itU32), wbInteger('Sunlight Scale Mult', itU32), wbInteger('Sunlight Scale Add', itU32), wbInteger('Sky Scale Mult', itU32), wbInteger('Sky Scale Add', itU32) ]), wbInteger('Unknown08 Mult', itU32), wbInteger('Unknown48 Add', itU32), wbInteger('Unknown09 Mult', itU32), wbInteger('Unknown49 Add', itU32), wbInteger('Unknown0A Mult', itU32), wbInteger('Unknown4A Add', itU32), wbInteger('Unknown0B Mult', itU32), wbInteger('Unknown4B Add', itU32), wbInteger('Unknown0C Mult', itU32), wbInteger('Unknown4C Add', itU32), wbInteger('Unknown0D Mult', itU32), wbInteger('Unknown4D Add', itU32), wbInteger('Unknown0E Mult', itU32), wbInteger('Unknown4E Add', itU32), wbInteger('Unknown0F Mult', itU32), wbInteger('Unknown4F Add', itU32), wbInteger('Unknown10 Mult', itU32), wbInteger('Unknown50 Add', itU32), wbStruct('Cinematic', [ wbInteger('Saturation Mult', itU32), wbInteger('Saturation Add', itU32), wbInteger('Brightness Mult', itU32), wbInteger('Brightness Add', itU32), wbInteger('Contrast Mult', itU32), wbInteger('Contrast Add', itU32) ]), wbInteger('Unknown14 Mult', itU32), wbInteger('Unknown54 Add', itU32), wbInteger('Tint Color', itU32), wbInteger('Blur Radius', itU32), wbInteger('Double Vision Strength', itU32), wbInteger('Radial Blur Strength', itU32), wbInteger('Radial Blur Ramp Up', itU32), wbInteger('Radial Blur Start', itU32), wbInteger('Radial Blur Flags', itU32, wbFlags(['Use Target'])), wbFloat('Radial Blur Center X'), wbFloat('Radial Blur Center Y'), wbInteger('DoF Strength', itU32), wbInteger('DoF Distance', itU32), wbInteger('DoF Range', itU32), wbInteger('DoF Flags', itU32, wbFlags(['Use Target'])), wbInteger('Radial Blur Ramp Down', itU32), wbInteger('Radial Blur Down Start', itU32), wbInteger('Fade Color', itU32), wbInteger('Motion Blur Strength', itU32) ], cpNormal, True, nil, 26), wbArray(BNAM, 'Blur Radius', wbTimeInterpolator), wbArray(VNAM, 'Double Vision Strength', wbTimeInterpolator), wbArray(TNAM, 'Tint Color', wbColorInterpolator), wbArray(NAM3, 'Fade Color', wbColorInterpolator), wbArray(RNAM, 'Radial Blur Strength', wbTimeInterpolator), wbArray(SNAM, 'Radial Blur Ramp Up', wbTimeInterpolator), wbArray(UNAM, 'Radial Blur Start', wbTimeInterpolator), wbArray(NAM1, 'Radial Blur Ramp Down', wbTimeInterpolator), wbArray(NAM2, 'Radial Blur Down Start', wbTimeInterpolator), wbArray(WNAM, 'DoF Strength', wbTimeInterpolator), wbArray(XNAM, 'DoF Distance', wbTimeInterpolator), wbArray(YNAM, 'DoF Range', wbTimeInterpolator), wbArray(NAM4, 'Motion Blur Strength', wbTimeInterpolator), wbRStruct('HDR', [ wbArray(_00_IAD, 'Eye Adapt Speed Mult', wbTimeInterpolator), wbArray(_40_IAD, 'Eye Adapt Speed Add', wbTimeInterpolator), wbArray(_01_IAD, 'Bloom Blur Radius Mult', wbTimeInterpolator), wbArray(_41_IAD, 'Bloom Blur Radius Add', wbTimeInterpolator), wbArray(_02_IAD, 'Bloom Threshold Mult', wbTimeInterpolator), wbArray(_42_IAD, 'Bloom Threshold Add', wbTimeInterpolator), wbArray(_03_IAD, 'Bloom Scale Mult', wbTimeInterpolator), wbArray(_43_IAD, 'Bloom Scale Add', wbTimeInterpolator), wbArray(_04_IAD, 'Target Lum Min Mult', wbTimeInterpolator), wbArray(_44_IAD, 'Target Lum Min Add', wbTimeInterpolator), wbArray(_05_IAD, 'Target Lum Max Mult', wbTimeInterpolator), wbArray(_45_IAD, 'Target Lum Max Add', wbTimeInterpolator), wbArray(_06_IAD, 'Sunlight Scale Mult', wbTimeInterpolator), wbArray(_46_IAD, 'Sunlight Scale Add', wbTimeInterpolator), wbArray(_07_IAD, 'Sky Scale Mult', wbTimeInterpolator), wbArray(_47_IAD, 'Sky Scale Add', wbTimeInterpolator) ], []), wbUnknown(_08_IAD), wbUnknown(_48_IAD), wbUnknown(_09_IAD), wbUnknown(_49_IAD), wbUnknown(_0A_IAD), wbUnknown(_4A_IAD), wbUnknown(_0B_IAD), wbUnknown(_4B_IAD), wbUnknown(_0C_IAD), wbUnknown(_4C_IAD), wbUnknown(_0D_IAD), wbUnknown(_4D_IAD), wbUnknown(_0E_IAD), wbUnknown(_4E_IAD), wbUnknown(_0F_IAD), wbUnknown(_4F_IAD), wbUnknown(_10_IAD), wbUnknown(_50_IAD), wbRStruct('Cinematic', [ wbArray(_11_IAD, 'Saturation Mult', wbTimeInterpolator), wbArray(_51_IAD, 'Saturation Add', wbTimeInterpolator), wbArray(_12_IAD, 'Brightness Mult', wbTimeInterpolator), wbArray(_52_IAD, 'Brightness Add', wbTimeInterpolator), wbArray(_13_IAD, 'Contrast Mult', wbTimeInterpolator), wbArray(_53_IAD, 'Contrast Add', wbTimeInterpolator) ], []), wbUnknown(_14_IAD), wbUnknown(_54_IAD), wbFormIDCk(RDSD, 'Sound - Intro', [SOUN]), wbFormIDCk(RDSI, 'Sound - Outro', [SOUN]) ]); wbRecord(FLST, 'FormID List', [ wbString(EDID, 'Editor ID', 0, cpBenign, True, nil, wbFLSTEDIDAfterSet), wbRArrayS('FormIDs', wbFormID(LNAM, 'FormID'), cpNormal, False, nil, nil, nil, wbFLSTLNAMIsSorted) ]); wbRecord(PERK, 'Perk', [ wbEDIDReq, wbFULL, wbDESCReq, wbICON, wbCTDAs, wbStruct(DATA, 'Data', [ wbInteger('Trait', itU8, wbEnum(['No', 'Yes'])), wbInteger('Min Level', itU8), wbInteger('Ranks', itU8), wbInteger('Playable', itU8, wbEnum(['No', 'Yes'])), wbInteger('Hidden', itU8, wbEnum(['No', 'Yes'])) ], cpNormal, True, nil, 4), wbRStructsSK('Effects', 'Effect', [0, 1], [ wbStructSK(PRKE, [1, 2, 0], 'Header', [ wbInteger('Type', itU8, wbEnum([ 'Quest + Stage', 'Ability', 'Entry Point' ]), cpNormal, False, nil, wbPERKPRKETypeAfterSet), wbInteger('Rank', itU8), wbInteger('Priority', itU8) ]), wbUnion(DATA, 'Effect Data', wbPerkDATADecider, [ wbStructSK([0, 1], 'Quest + Stage', [ wbFormIDCk('Quest', [QUST]), wbInteger('Quest Stage', itU8, wbPerkDATAQuestStageToStr, wbCTDAParam2QuestStageToInt), wbByteArray('Unused', 3) ]), wbFormIDCk('Ability', [SPEL]), wbStructSK([0, 1], 'Entry Point', [ wbInteger('Entry Point', itU8, wbEnum([ {00} 'Calculate Weapon Damage', {01} 'Calculate My Critical Hit Chance', {02} 'Calculate My Critical Hit Damage', {03} 'Calculate Weapon Attack AP Cost', {04} 'Calculate Mine Explode Chance', {05} 'Adjust Range Penalty', {06} 'Adjust Limb Damage', {07} 'Calculate Weapon Range', {08} 'Calculate To Hit Chance', {09} 'Adjust Experience Points', {10} 'Adjust Gained Skill Points', {11} 'Adjust Book Skill Points', {12} 'Modify Recovered Health', {13} 'Calculate Inventory AP Cost', {14} 'Get Disposition', {15} 'Get Should Attack', {16} 'Get Should Assist', {17} 'Calculate Buy Price', {18} 'Get Bad Karma', {19} 'Get Good Karma', {20} 'Ignore Locked Terminal', {21} 'Add Leveled List On Death', {22} 'Get Max Carry Weight', {23} 'Modify Addiction Chance', {24} 'Modify Addiction Duration', {25} 'Modify Positive Chem Duration', {26} 'Adjust Drinking Radiation', {27} 'Activate', {28} 'Mysterious Stranger', {29} 'Has Paralyzing Palm', {30} 'Hacking Science Bonus', {31} 'Ignore Running During Detection', {32} 'Ignore Broken Lock', {33} 'Has Concentrated Fire', {34} 'Calculate Gun Spread', {35} 'Player Kill AP Reward', {36} 'Modify Enemy Critical Hit Chance', {37} 'Reload Speed', {38} 'Equip Speed', {39} 'Action Point Regen', {40} 'Action Point Cost', {41} 'Miss Fortune', {42} 'Modify Run Speed', {43} 'Modify Attack Speed', {44} 'Modify Radiation Consumed', {45} 'Has Pip Hacker', {46} 'Has Meltdown', {47} 'See Enemy Health', {48} 'Has Jury Rigging', {49} 'Modify Threat Range', {50} 'Modify Thread', {51} 'Has Fast Travel Always', {52} 'Knockdown Chance', {53} 'Modify Weapon Strength Req', {54} 'Modify Aiming Move Speed', {55} 'Modify Light Items', {56} 'Modify Damage Threshold (defender)', {57} 'Modify Chance for Ammo Item', {58} 'Modify Damage Threshold (attacker)', {59} 'Modify Throwing Velocity', {60} 'Chance for Item on Fire', {61} 'Has Unarmed Forward Power Attack', {62} 'Has Unarmed Back Power Attack', {63} 'Has Unarmed Crouched Power Attack', {64} 'Has Unarmed Counter Attack', {65} 'Has Unarmed Left Power Attack', {66} 'Has Unarmed Right Power Attack', {67} 'VATS HelperChance', {68} 'Modify Item Damage', {69} 'Has Improved Detection', {70} 'Has Improved Spotting', {71} 'Has Improved Item Detection', {72} 'Adjust Explosion Radius', {73} 'Reserved' ]), cpNormal, True, nil, wbPERKEntryPointAfterSet), wbInteger('Function', itU8, wbPerkDATAFunctionToStr, wbPerkDATAFunctionToInt, cpNormal, False, nil, wbPerkDATAFunctionAfterSet), wbInteger('Perk Condition Tab Count', itU8, nil, cpIgnore) ]) ], cpNormal, True), wbRStructsSK('Perk Conditions', 'Perk Condition', [0], [ wbInteger(PRKC, 'Run On', itS8, wbPRKCToStr, wbPRKCToInt), wbCTDAsReq ], [], cpNormal, False, nil, nil, wbPERKPRKCDontShow), wbRStruct('Entry Point Function Parameters', [ wbInteger(EPFT, 'Type', itU8, wbPerkEPFTToStr, wbPerkEPFTToInt, cpIgnore, False, nil, wbPerkEPFTAfterSet), wbUnion(EPFD, 'Data', wbEPFDDecider, [ wbByteArray('Unknown'), wbFloat('Float'), wbStruct('Float, Float', [ wbFloat('Float 1'), wbFloat('Float 2') ]), wbFormIDCk('Leveled Item', [LVLI]), wbEmpty('None (Script)'), wbStruct('Actor Value, Float', [ wbInteger('Actor Value', itU32, wbEPFDActorValueToStr, wbEPFDActorValueToInt), wbFloat('Float') ]) ], cpNormal, False, wbEPFDDontShow), wbString(EPF2, 'Button Label', 0, cpNormal, False, wbEPF2DontShow), wbInteger(EPF3, 'Script Flags', itU16, wbFlags([ 'Run Immediately' ]), cpNormal, False, False, wbEPF2DontShow), wbEmbeddedScriptPerk ], [], cpNormal, False, wbPERKPRKCDontShow), wbEmpty(PRKF, 'End Marker', cpIgnore, True) ], []) ]); wbBPNDStruct := wbStruct(BPND, '', [ {00} wbFloat('Damage Mult'), {04} wbInteger('Flags', itU8, wbFlags([ 'Severable', 'IK Data', 'IK Data - Biped Data', 'Explodable', 'IK Data - Is Head', 'IK Data - Headtracking', 'To Hit Chance - Absolute' ])), {05} wbInteger('Part Type', itU8, wbEnum([ 'Torso', 'Head 1', 'Head 2', 'Left Arm 1', 'Left Arm 2', 'Right Arm 1', 'Right Arm 2', 'Left Leg 1', 'Left Leg 2', 'Left Leg 3', 'Right Leg 1', 'Right Leg 2', 'Right Leg 3', 'Brain', 'Weapon' ])), {06} wbInteger('Health Percent', itU8), {07} wbInteger('Actor Value', itS8, wbActorValueEnum), {08} wbInteger('To Hit Chance', itU8), {09} wbInteger('Explodable - Explosion Chance %', itU8), {10} wbInteger('Explodable - Debris Count', itU16), {12} wbFormIDCk('Explodable - Debris', [DEBR, NULL]), {16} wbFormIDCk('Explodable - Explosion', [EXPL, NULL]), {20} wbFloat('Tracking Max Angle'), {24} wbFloat('Explodable - Debris Scale'), {28} wbInteger('Severable - Debris Count', itS32), {32} wbFormIDCk('Severable - Debris', [DEBR, NULL]), {36} wbFormIDCk('Severable - Explosion', [EXPL, NULL]), {40} wbFloat('Severable - Debris Scale'), wbStruct('Gore Effects Positioning', [ wbStruct('Translate', [ {44} wbFloat('X'), {48} wbFloat('Y'), {52} wbFloat('Z') ]), wbStruct('Rotation', [ {56} wbFloat('X', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), {60} wbFloat('Y', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), {64} wbFloat('Z', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize) ]) ]), {68} wbFormIDCk('Severable - Impact DataSet', [IPDS, NULL]), {72} wbFormIDCk('Explodable - Impact DataSet', [IPDS, NULL]), {28} wbInteger('Severable - Decal Count', itU8), {28} wbInteger('Explodable - Decal Count', itU8), {76} wbByteArray('Unused', 2), {80} wbFloat('Limb Replacement Scale') ], cpNormal, True); wbRecord(BPTD, 'Body Part Data', [ wbEDIDReq, wbMODLReq, wbRStructS('Body Parts', 'Body Part', [ // When the Part Name is provided wbString(BPTN, 'Part Name', 0, cpNormal, True), wbString(BPNN, 'Part Node', 0, cpNormal, True), wbString(BPNT, 'VATS Target', 0, cpNormal, True), wbString(BPNI, 'IK Data - Start Node', 0, cpNormal, True), wbBPNDStruct, wbString(NAM1, 'Limb Replacement Model', 0, cpNormal, True), wbString(NAM4, 'Gore Effects - Target Bone', 0, cpNormal, True), wbByteArray(NAM5, 'Texture Files Hashes', 0, cpIgnore) ], [], cpNormal, False), wbRStructS('Unnamed Body Parts', 'Body Part', [ // When the Part Name is not provided wbString(BPNN, 'Part Node', 0, cpNormal, True), wbString(BPNT, 'VATS Target', 0, cpNormal, True), wbString(BPNI, 'IK Data - Start Node', 0, cpNormal, True), wbBPNDStruct, wbString(NAM1, 'Limb Replacement Model', 0, cpNormal, True), wbString(NAM4, 'Gore Effects - Target Bone', 0, cpNormal, True), wbByteArray(NAM5, 'Texture Files Hashes', 0, cpIgnore) ], [], cpNormal, False), wbFormIDCk(RAGA, 'Ragdoll', [RGDL]) ]); wbRecord(ADDN, 'Addon Node', [ wbEDIDReq, wbOBNDReq, wbMODLReq, wbInteger(DATA, 'Node Index', itS32, nil, cpNormal, True), wbFormIDCk(SNAM, 'Sound', [SOUN]), wbStruct(DNAM, 'Data', [ wbInteger('Master Particle System Cap', itU16), wbByteArray('Unknown', 2) ], cpNormal, True) ]); wbRecord(AVIF, 'ActorValue Information', [ wbEDIDReq, wbFULL, wbDESCReq, wbICON, wbString(ANAM, 'Short Name') ]); wbRecord(RADS, 'Radiation Stage', [ wbEDIDReq, wbStruct(DATA, '', [ wbInteger('Trigger Threshold', itU32), wbFormIDCk('Actor Effect', [SPEL]) ], cpNormal, True) ]); wbRecord(CAMS, 'Camera Shot', [ wbEDIDReq, wbMODL, wbStruct(DATA, 'Data', [ {00} wbInteger('Action', itU32, wbEnum([ 'Shoot', 'Fly', 'Hit', 'Zoom' ])), {04} wbInteger('Location', itU32, wbEnum([ 'Attacker', 'Projectile', 'Target' ])), {08} wbInteger('Target', itU32, wbEnum([ 'Attacker', 'Projectile', 'Target' ])), {12} wbInteger('Flags', itU32, wbFlags([ 'Position Follows Location', 'Rotation Follows Target', 'Don''t Follow Bone', 'First Person Camera', 'No Tracer', 'Start At Time Zero' ])), wbStruct('Time Multipliers', [ {16} wbFloat('Player'), {20} wbFloat('Target'), {24} wbFloat('Global') ]), {28} wbFloat('Max Time'), {32} wbFloat('Min Time'), {36} wbFloat('Target % Between Actors') ], cpNormal, True, nil, 7), wbFormIDCk(MNAM, 'Image Space Modifier', [IMAD]) ]); wbRecord(CPTH, 'Camera Path', [ wbEDIDReq, wbCTDAs, wbArray(ANAM, 'Related Camera Paths', wbFormIDCk('Related Camera Path', [CPTH, NULL]), ['Parent', 'Previous Sibling'], cpNormal, True), wbInteger(DATA, 'Camera Zoom', itU8, wbEnum([ 'Default', 'Disable', 'Shot List' ]), cpNormal, True), wbRArray('Camera Shots', wbFormIDCk(SNAM, 'Camera Shot', [CAMS])) ]); wbRecord(VTYP, 'Voice Type', [ wbEDIDReq, wbInteger(DNAM, 'Flags', itU8, wbFlags([ 'Allow Default Dialog', 'Female' ]), cpNormal, False) ]); wbRecord(IPCT, 'Impact', [ wbEDIDReq, wbMODL, wbStruct(DATA, '', [ wbFloat('Effect - Duration'), wbInteger('Effect - Orientation', itU32, wbEnum([ 'Surface Normal', 'Projectile Vector', 'Projectile Reflection' ])), wbFloat('Angle Threshold'), wbFloat('Placement Radius'), wbInteger('Sound Level', itU32, wbSoundLevelEnum), wbInteger('Flags', itU32, wbFlags([ 'No Decal Data' ])) ], cpNormal, True), wbDODT, wbFormIDCk(DNAM, 'Texture Set', [TXST]), wbFormIDCk(SNAM, 'Sound 1', [SOUN]), wbFormIDCk(NAM1, 'Sound 2', [SOUN]) ]); wbRecord(IPDS, 'Impact DataSet', [ wbEDIDReq, wbStruct(DATA, 'Impacts', [ wbFormIDCk('Stone', [IPCT, NULL]), wbFormIDCk('Dirt', [IPCT, NULL]), wbFormIDCk('Grass', [IPCT, NULL]), wbFormIDCk('Glass', [IPCT, NULL]), wbFormIDCk('Metal', [IPCT, NULL]), wbFormIDCk('Wood', [IPCT, NULL]), wbFormIDCk('Organic', [IPCT, NULL]), wbFormIDCk('Cloth', [IPCT, NULL]), wbFormIDCk('Water', [IPCT, NULL]), wbFormIDCk('Hollow Metal', [IPCT, NULL]), wbFormIDCk('Organic Bug', [IPCT, NULL]), wbFormIDCk('Organic Glow', [IPCT, NULL]) ], cpNormal, True, nil, 9) ]); wbRecord(ECZN, 'Encounter Zone', [ wbEDIDReq, wbStruct(DATA, '', [ wbFormIDCkNoReach('Owner', [NPC_, FACT, NULL]), wbInteger('Rank', itS8), wbInteger('Minimum Level', itS8), wbInteger('Flags', itU8, wbFlags([ 'Never Resets', 'Match PC Below Minimum Level' ])), wbByteArray('Unused', 1) ], cpNormal, True) ]); wbRecord(MESG, 'Message', [ wbEDIDReq, wbDESCReq, wbFULL, wbFormIDCk(INAM, 'Icon', [MICN, NULL], False, cpNormal, True), wbByteArray(NAM0, 'Unused', 0, cpIgnore), wbByteArray(NAM1, 'Unused', 0, cpIgnore), wbByteArray(NAM2, 'Unused', 0, cpIgnore), wbByteArray(NAM3, 'Unused', 0, cpIgnore), wbByteArray(NAM4, 'Unused', 0, cpIgnore), wbByteArray(NAM5, 'Unused', 0, cpIgnore), wbByteArray(NAM6, 'Unused', 0, cpIgnore), wbByteArray(NAM7, 'Unused', 0, cpIgnore), wbByteArray(NAM8, 'Unused', 0, cpIgnore), wbByteArray(NAM9, 'Unused', 0, cpIgnore), wbInteger(DNAM, 'Flags', itU32, wbFlags([ 'Message Box', 'Auto Display' ]), cpNormal, True, False, nil, wbMESGDNAMAfterSet), wbInteger(TNAM, 'Display Time', itU32, nil, cpNormal, False, False, wbMESGTNAMDontShow), wbRStructs('Menu Buttons', 'Menu Button', [ wbString(ITXT, 'Button Text'), wbCTDAs ], []) ], False, nil, cpNormal, False, wbMESGAfterLoad); wbRecord(RGDL, 'Ragdoll', [ wbEDIDReq, wbInteger(NVER, 'Version', itU32, nil, cpNormal, True), wbStruct(DATA, 'General Data', [ wbInteger('Dynamic Bone Count', itU32), wbByteArray('Unused', 4), wbStruct('Enabled', [ wbInteger('Feedback', itU8, wbEnum(['No', 'Yes'])), wbInteger('Foot IK (broken, don''t use)', itU8, wbEnum(['No', 'Yes'])), wbInteger('Look IK (broken, don''t use)', itU8, wbEnum(['No', 'Yes'])), wbInteger('Grab IK (broken, don''t use)', itU8, wbEnum(['No', 'Yes'])), wbInteger('Pose Matching', itU8, wbEnum(['No', 'Yes'])) ]), wbByteArray('Unused', 1) ], cpNormal, True), wbFormIDCk(XNAM, 'Actor Base', [CREA, NPC_], False, cpNormal, True), wbFormIDCk(TNAM, 'Body Part Data', [BPTD], False, cpNormal, True), wbStruct(RAFD, 'Feedback Data', [ {00} wbFloat('Dynamic/Keyframe Blend Amount'), {04} wbFloat('Hierarchy Gain'), {08} wbFloat('Position Gain'), {12} wbFloat('Velocity Gain'), {16} wbFloat('Acceleration Gain'), {20} wbFloat('Snap Gain'), {24} wbFloat('Velocity Damping'), wbStruct('Snap Max Settings', [ {28} wbFloat('Linear Velocity'), {32} wbFloat('Angular Velocity'), {36} wbFloat('Linear Distance'), {40} wbFloat('Angular Distance') ]), wbStruct('Position Max Velocity', [ {44} wbFloat('Linear'), {48} wbFloat('Angular') ]), wbStruct('Position Max Velocity', [ {52} wbInteger('Projectile', itS32, wbDiv(1000)), {56} wbInteger('Melee', itS32, wbDiv(1000)) ]) ], cpNormal, False), wbArray(RAFB, 'Feedback Dynamic Bones', wbInteger('Bone', itU16), 0, nil, nil, cpNormal, False), wbStruct(RAPS, 'Pose Matching Data', [ {00} wbArray('Match Bones', wbInteger('Bone', itU16, wbHideFFFF), 3), {06} wbInteger('Flags', itU8, wbFlags([ 'Disable On Move' ])), {07} wbByteArray('Unused', 1), {08} wbFloat('Motors Strength'), {12} wbFloat('Pose Activation Delay Time'), {16} wbFloat('Match Error Allowance'), {20} wbFloat('Displacement To Disable') ], cpNormal, True), wbString(ANAM, 'Death Pose') ]); wbRecord(DOBJ, 'Default Object Manager', [ wbEDIDReq, wbArray(DATA, 'Default Objects', wbFormID('Default Object'), [ 'Stimpack', 'SuperStimpack', 'RadX', 'RadAway', 'Morphine', 'Perk Paralysis', 'Player Faction', 'Mysterious Stranger NPC', 'Mysterious Stranger Faction', 'Default Music', 'Battle Music', 'Death Music', 'Success Music', 'Level Up Music', 'Player Voice (Male)', 'Player Voice (Male Child)', 'Player Voice (Female)', 'Player Voice (Female Child)', 'Eat Package Default Food', 'Every Actor Ability', 'Drug Wears Off Image Space', 'Doctor''s Bag', 'Miss Fortune NPC', 'Miss Fortune Faction', 'Meltdown Explosion', 'Unarmed Forward PA', 'Unarmed Backward PA', 'Unarmed Left PA', 'Unarmed Right PA', 'Unarmed Crouch PA', 'Unarmed Counter PA', 'Spotter Effect', 'Item Detected Effect', 'Cateye Mobile Effect (NYI)' ], cpNormal, True) ]); wbRecord(LGTM, 'Lighting Template', [ wbEDIDReq, wbStruct(DATA, 'Lighting', [ wbStruct('Ambient Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Directional Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Fog Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbFloat('Fog Near'), wbFloat('Fog Far'), wbInteger('Directional Rotation XY', itS32), wbInteger('Directional Rotation Z', itS32), wbFloat('Directional Fade'), wbFloat('Fog Clip Dist'), wbFloat('Fog Power') ], cpNormal, True) ]); wbRecord(MUSC, 'Music Type', [ wbEDIDReq, wbString(FNAM, 'Filename'), wbFloat(ANAM, 'dB (positive = Loop)') ]); wbRecord(GRAS, 'Grass', [ wbEDIDReq, wbOBNDReq, wbMODLReq, wbStruct(DATA, '', [ wbInteger('Density', itU8), wbInteger('Min Slope', itU8), wbInteger('Max Slope', itU8), wbByteArray('Unused', 1), wbInteger('Unit from water amount', itU16), wbByteArray('Unused', 2), wbInteger('Unit from water type', itU32, wbEnum([ 'Above - At Least', 'Above - At Most', 'Below - At Least', 'Below - At Most', 'Either - At Least', 'Either - At Most', 'Either - At Most Above', 'Either - At Most Below' ])), wbFloat('Position Range'), wbFloat('Height Range'), wbFloat('Color Range'), wbFloat('Wave Period'), wbInteger('Flags', itU8, wbFlags([ 'Vertex Lighting', 'Uniform Scaling', 'Fit to Slope' ])), wbByteArray('Unused', 3) ], cpNormal, True) ]); wbRecord(HAIR, 'Hair', [ wbEDIDReq, wbFULLReq, wbMODLReq, wbString(ICON, 'Texture', 0, cpNormal, True), wbInteger(DATA, 'Flags', itU8, wbFlags([ 'Playable', 'Not Male', 'Not Female', 'Fixed' ]), cpNormal, True) ]); wbRecord(IDLE, 'Idle Animation', [ wbEDID, wbMODLReq, wbCTDAs, wbArray(ANAM, 'Related Idle Animations', wbFormIDCk('Related Idle Animation', [IDLE, NULL]), ['Parent', 'Previous Sibling'], cpNormal, True), wbStruct(DATA, '', [ wbInteger('Animation Group Section', itU8, wbIdleAnam), wbStruct('Looping', [ wbInteger('Min', itU8), wbInteger('Max', itU8) ]), wbByteArray('Unused', 1), wbInteger('Replay Delay', itS16), wbInteger('Flags', itU8, wbFlags([ 'No attacking' ])), wbByteArray('Unused', 1) ], cpNormal, True, nil, 4) ]); wbRecord(INFO, 'Dialog response', [ wbStruct(DATA, '', [ wbInteger('Type', itU8, wbEnum([ {0} 'Topic', {1} 'Conversation', {2} 'Combat', {3} 'Persuasion', {4} 'Detection', {5} 'Service', {6} 'Miscellaneous', {7} 'Radio' ])), wbInteger('Next Speaker', itU8, wbEnum([ {0} 'Target', {1} 'Self', {2} 'Either' ])), wbInteger('Flags 1', itU8, wbFlags([ {0x01} 'Goodbye', {0x02} 'Random', {0x04} 'Say Once', {0x08} 'Run Immediately', {0x10} 'Info Refusal', {0x20} 'Random End', {0x40} 'Run for Rumors', {0x80} 'Speech Challenge' ])), wbInteger('Flags 2', itU8, wbFlags([ {0x01} 'Say Once a Day', {0x02} 'Always Darken', {0x04} 'Unknown 2', {0x08} 'Unknown 3', {0x10} 'Low Intelligence', {0x20} 'High Intelligence' ])) ], cpNormal, True, nil, 3), wbFormIDCkNoReach(QSTI, 'Quest', [QUST], False, cpNormal, True), wbFormIDCk(TPIC, 'Topic', [DIAL]), // The GECK ignores it for ESM wbFormIDCkNoReach(PNAM, 'Previous INFO', [INFO, NULL]), wbRArray('Add Topics', wbFormIDCk(NAME, 'Topic', [DIAL])), wbRArray('Responses', wbRStruct('Response', [ wbStruct(TRDT, 'Response Data', [ wbInteger('Emotion Type', itU32, wbEnum([ {0} 'Neutral', {1} 'Anger', {2} 'Disgust', {3} 'Fear', {4} 'Sad', {5} 'Happy', {6} 'Surprise', {7} 'Pained' ])), wbInteger('Emotion Value', itS32), wbByteArray('Unused', 4), wbInteger('Response number', itU8), wbByteArray('Unused', 3), wbFormIDCk('Sound', [SOUN, NULL]), wbInteger('Flags', itU8, wbFlags([ 'Use Emotion Animation' ])), wbByteArray('Unused', 3) ], cpNormal, False, nil, 5), wbStringKC(NAM1, 'Response Text', 0, cpTranslate, True), wbString(NAM2, 'Script Notes', 0, cpTranslate, True), wbString(NAM3, 'Edits'), wbFormIDCk(SNAM, 'Speaker Animation', [IDLE]), wbFormIDCk(LNAM, 'Listener Animation', [IDLE]) ], []) ), wbCTDAs, wbRArray('Choices', wbFormIDCk(TCLT, 'Choice', [DIAL])), wbRArray('Link From', wbFormIDCk(TCLF, 'Topic', [DIAL])), wbRArray('Unknown', wbFormIDCk(TCFU, 'Info', [INFO] )), wbRStruct('Script (Begin)', [ wbEmbeddedScriptReq ], [], cpNormal, True), wbRStruct('Script (End)', [ wbEmpty(NEXT, 'Marker'), wbEmbeddedScriptReq ], [], cpNormal, True), wbFormIDCk(SNDD, 'Unused', [SOUN]), wbString(RNAM, 'Prompt'), wbFormIDCk(ANAM, 'Speaker', [CREA, NPC_]), wbFormIDCk(KNAM, 'ActorValue/Perk', [AVIF, PERK]), wbInteger(DNAM, 'Speech Challenge', itU32, wbEnum([ '---', 'Very Easy', 'Easy', 'Average', 'Hard', 'Very Hard' ])) ], False, wbINFOAddInfo, cpNormal, False, wbINFOAfterLoad); wbRecord(INGR, 'Ingredient', [ wbEDIDReq, wbOBNDReq, wbFULL, wbMODL, wbICON, wbSCRI, wbETYPReq, wbFloat(DATA, 'Weight', cpNormal, True), wbStruct(ENIT, 'Effect Data', [ wbInteger('Value', itS32), wbInteger('Flags', itU8, wbFlags(['No auto-calculation', 'Food item'])), wbByteArray('Unused', 3) ], cpNormal, True), wbEffectsReq ]); wbRecord(KEYM, 'Key', [ wbEDIDReq, wbOBNDReq, wbFULLReq, wbMODL, wbICONReq, wbSCRI, wbDEST, wbYNAM, wbZNAM, wbStruct(DATA, '', [ wbInteger('Value', itS32), wbFloat('Weight') ], cpNormal, True), wbFormIDCk(RNAM, 'Sound - Random/Looping', [SOUN]) ]); wbQuadrantEnum := wbEnum([ {0} 'Bottom Left', {1} 'Bottom Right', {2} 'Top Left', {3} 'Top Right' ]); if wbSimpleRecords then begin wbRecord(LAND, 'Landscape', [ wbByteArray(DATA, 'Unknown'), wbByteArray(VNML, 'Vertex Normals'), wbByteArray(VHGT, 'Vertext Height Map'), wbByteArray(VCLR, 'Vertex Colours'), wbRArrayS('Layers', wbRUnion('Layer', [ wbRStructSK([0],'Base Layer', [ wbStructSK(BTXT, [1, 3], 'Base Layer Header', [ wbFormIDCk('Texture', [LTEX, NULL]), wbInteger('Quadrant', itU8, wbQuadrantEnum), wbByteArray('Unused', 1), wbInteger('Layer', itS16) ]) ], []), wbRStructSK([0],'Alpha Layer', [ wbStructSK(ATXT, [1, 3], 'Alpha Layer Header', [ wbFormIDCk('Texture', [LTEX, NULL]), wbInteger('Quadrant', itU8, wbQuadrantEnum), wbByteArray('Unused', 1), wbInteger('Layer', itS16) ]), wbByteArray(VTXT, 'Alpha Layer Data') ], []) ], [])), wbArray(VTEX, 'Textures', wbFormIDCk('Texture', [LTEX, NULL])) ]); end else begin wbRecord(LAND, 'Landscape', [ wbByteArray(DATA, 'Unknown'), wbArray(VNML, 'Vertex Normals', wbStruct('Row', [ wbArray('Columns', wbStruct('Column', [ wbInteger('X', itU8), wbInteger('Y', itU8), wbInteger('Z', itU8) ]), 33) ]), 33), wbStruct(VHGT, 'Vertext Height Map', [ wbFloat('Offset'), wbArray('Rows', wbStruct('Row', [ wbArray('Columns', wbInteger('Column', itU8), 33) ]), 33), wbByteArray('Unused', 3) ]), wbArray(VCLR, 'Vertex Colours', wbStruct('Row', [ wbArray('Columns', wbStruct('Column', [ wbInteger('X', itU8), wbInteger('Y', itU8), wbInteger('Z', itU8) ]), 33) ]), 33), wbRArrayS('Layers', wbRUnion('Layer', [ wbRStructSK([0],'Base Layer', [ wbStructSK(BTXT, [1, 3], 'Base Layer Header', [ wbFormIDCk('Texture', [LTEX, NULL]), wbInteger('Quadrant', itU8, wbQuadrantEnum), wbByteArray('Unused', 1), wbInteger('Layer', itS16) ]) ], []), wbRStructSK([0],'Alpha Layer', [ wbStructSK(ATXT, [1, 3], 'Alpha Layer Header', [ wbFormIDCk('Texture', [LTEX, NULL]), wbInteger('Quadrant', itU8, wbQuadrantEnum), wbByteArray('Unused', 1), wbInteger('Layer', itS16) ]), wbArrayS(VTXT, 'Alpha Layer Data', wbStructSK([0], 'Cell', [ wbInteger('Position', itU16, wbAtxtPosition), wbByteArray('Unused', 2), wbFloat('Opacity') ])) ], []) ], [])), wbArray(VTEX, 'Textures', wbFormIDCk('Texture', [LTEX, NULL])) ]); end; wbRecord(LIGH, 'Light', [ wbEDIDReq, wbOBNDReq, wbMODL, wbSCRI, wbDEST, wbFULL, wbICON, wbStruct(DATA, '', [ wbInteger('Time', itS32), wbInteger('Radius', itU32), wbStruct('Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbInteger('Unused', itU8) ]), wbInteger('Flags', itU32, wbFlags([ {0x00000001} 'Dynamic', {0x00000002} 'Can be Carried', {0x00000004} 'Negative', {0x00000008} 'Flicker', {0x00000010} 'Unused', {0x00000020} 'Off By Default', {0x00000040} 'Flicker Slow', {0x00000080} 'Pulse', {0x00000100} 'Pulse Slow', {0x00000200} 'Spot Light', {0x00000400} 'Spot Shadow' ])), wbFloat('Falloff Exponent'), wbFloat('FOV'), wbInteger('Value', itU32), wbFloat('Weight') ], cpNormal, True), wbFloat(FNAM, 'Fade value', cpNormal, True), wbFormIDCk(SNAM, 'Sound', [SOUN]) ], False, nil, cpNormal, False, wbLIGHAfterLoad); wbRecord(LSCR, 'Load Screen', [ wbEDIDReq, wbICONReq, wbDESCReq, wbRArrayS('Locations', wbStructSK(LNAM, [0, 1], 'Location', [ wbFormIDCk('Direct', [CELL, WRLD, NULL]), wbStructSK([0, 1], 'Indirect', [ wbFormIDCk('World', [NULL, WRLD]), wbStructSK([0,1], 'Grid', [ wbInteger('Y', itS16), wbInteger('X', itS16) ]) ]) ])), wbFormIDCk(WMI1, 'Load Screen Type', [LSCT]) ]); wbRecord(LTEX, 'Landscape Texture', [ wbEDIDReq, wbICON, wbFormIDCk(TNAM, 'Texture', [TXST], False, cpNormal, True), wbStruct(HNAM, 'Havok Data', [ wbInteger('Material Type', itU8, wbEnum([ {00} 'STONE', {01} 'CLOTH', {02} 'DIRT', {03} 'GLASS', {04} 'GRASS', {05} 'METAL', {06} 'ORGANIC', {07} 'SKIN', {08} 'WATER', {09} 'WOOD', {10} 'HEAVY STONE', {11} 'HEAVY METAL', {12} 'HEAVY WOOD', {13} 'CHAIN', {14} 'SNOW', {15} 'ELEVATOR', {16} 'HOLLOW METAL', {17} 'SHEET METAL', {18} 'SAND', {19} 'BRIKEN CONCRETE', {20} 'VEHILCE BODY', {21} 'VEHILCE PART SOLID', {22} 'VEHILCE PART HOLLOW', {23} 'BARREL', {24} 'BOTTLE', {25} 'SODA CAN', {26} 'PISTOL', {27} 'RIFLE', {28} 'SHOPPING CART', {29} 'LUNCHBOX', {30} 'BABY RATTLE', {31} 'RUBER BALL' ])), wbInteger('Friction', itU8), wbInteger('Restitution', itU8) ], cpNormal, True), wbInteger(SNAM, 'Texture Specular Exponent', itU8, nil, cpNormal, True), wbRArrayS('Grasses', wbFormIDCk(GNAM, 'Grass', [GRAS])) ]); wbRecord(LVLC, 'Leveled Creature', [ wbEDIDReq, wbOBNDReq, wbInteger(LVLD, 'Chance none', itU8, nil, cpNormal, True), wbInteger(LVLF, 'Flags', itU8, wbFlags([ {0x01} 'Calculate from all levels <= player''s level', {0x02} 'Calculate for each item in count' ]), cpNormal, True), wbRArrayS('Leveled List Entries', wbRStructExSK([0], [1], 'Leveled List Entry', [ wbStructExSK(LVLO , [0, 2], [3], 'Base Data', [ wbInteger('Level', itS16), wbByteArray('Unused', 2), wbFormIDCk('Reference', [CREA, LVLC]), wbInteger('Count', itS16), wbByteArray('Unused', 2) ]), wbCOED ], []), cpNormal, True), wbMODL ]); wbRecord(LVLN, 'Leveled NPC', [ wbEDIDReq, wbOBNDReq, wbInteger(LVLD, 'Chance none', itU8, nil, cpNormal, True), wbInteger(LVLF, 'Flags', itU8, wbFlags([ {0x01} 'Calculate from all levels <= player''s level', {0x02} 'Calculate for each item in count' ]), cpNormal, True), wbRArrayS('Leveled List Entries', wbRStructExSK([0], [1], 'Leveled List Entry', [ wbStructExSK(LVLO , [0, 2], [3], 'Base Data', [ wbInteger('Level', itS16), wbByteArray('Unused', 2), wbFormIDCk('Reference', [NPC_, LVLN]), wbInteger('Count', itS16), wbByteArray('Unused', 2) ]), wbCOED ], []), cpNormal, True), wbMODL ]); wbRecord(LVLI, 'Leveled Item', [ wbEDIDReq, wbOBNDReq, wbInteger(LVLD, 'Chance none', itU8, nil, cpNormal, True), wbInteger(LVLF, 'Flags', itU8, wbFlags([ {0x01} 'Calculate from all levels <= player''s level', {0x02} 'Calculate for each item in count', {0x04} 'Use All' ]), cpNormal, True), wbFormIDCk(LVLG, 'Global', [GLOB]), wbRArrayS('Leveled List Entries', wbRStructExSK([0], [1], 'Leveled List Entry', [ wbStructExSK(LVLO , [0, 2], [3], 'Base Data', [ wbInteger('Level', itS16), wbByteArray('Unused', 2), wbFormIDCk('Reference', [ARMO, AMMO, MISC, WEAP, BOOK, LVLI, KEYM, ALCH, NOTE, IMOD, CMNY, CCRD, CHIP]), wbInteger('Count', itS16), wbByteArray('Unused', 2) ]), wbCOED ], []) ) ]); wbArchtypeEnum := wbEnum([ {00} 'Value Modifier', {01} 'Script', {02} 'Dispel', {03} 'Cure Disease', {04} '', {05} '', {06} '', {07} '', {08} '', {09} '', {10} '', {11} 'Invisibility', {12} 'Chameleon', {13} 'Light', {14} '', {15} '', {16} 'Lock', {17} 'Open', {18} 'Bound Item', {19} 'Summon Creature', {20} '', {21} '', {22} '', {23} '', {24} 'Paralysis', {25} '', {26} '', {27} '', {28} '', {29} '', {30} 'Cure Paralysis', {31} 'Cure Addiction', {32} 'Cure Poison', {33} 'Concussion', {34} 'Value And Parts', {35} 'Limb Condition', {36} 'Turbo' ]); wbRecord(MGEF, 'Base Effect', [ wbEDIDReq, wbFULL, wbDESCReq, wbICON, wbMODL, wbStruct(DATA, 'Data', [ wbInteger('Flags', itU32, wbFlags([ {0x00000001} 'Hostile', {0x00000002} 'Recover', {0x00000004} 'Detrimental', {0x00000008} '', {0x00000010} 'Self', {0x00000020} 'Touch', {0x00000040} 'Target', {0x00000080} 'No Duration', {0x00000100} 'No Magnitude', {0x00000200} 'No Area', {0x00000400} 'FX Persist', {0x00000800} '', {0x00001000} 'Gory Visuals', {0x00002000} 'Display Name Only', {0x00004000} '', {0x00008000} 'Radio Broadcast ??', {0x00010000} '', {0x00020000} '', {0x00040000} '', {0x00080000} 'Use skill', {0x00100000} 'Use attribute', {0x00200000} '', {0x00400000} '', {0x00800000} '', {0x01000000} 'Painless', {0x02000000} 'Spray projectile type (or Fog if Bolt is specified as well)', {0x04000000} 'Bolt projectile type (or Fog if Spray is specified as well)', {0x08000000} 'No Hit Effect', {0x10000000} 'No Death Dispel', {0x20000000} '????' ])), {04} wbFloat('Base cost (Unused)'), {08} wbUnion('Assoc. Item', wbMGEFFAssocItemDecider, [ wbFormID('Unused', cpIgnore), wbFormID('Assoc. Item'), wbFormIDCk('Assoc. Script', [SCPT, NULL]), //Script wbFormIDCk('Assoc. Item', [WEAP, ARMO, NULL]), //Bound Item wbFormIDCk('Assoc. Creature', [CREA]) //Summon Creature ], cpNormal, false, nil, wbMGEFFAssocItemAfterSet), {12} wbInteger('Magic School (Unused)', itS32, wbEnum([ ], [ -1, 'None' ])), {16} wbInteger('Resistance Type', itS32, wbActorValueEnum), {20} wbInteger('Counter effect count', itU16), {22} wbByteArray('Unused', 2), {24} wbFormIDCk('Light', [LIGH, NULL]), {28} wbFloat('Projectile speed'), {32} wbFormIDCk('Effect Shader', [EFSH, NULL]), {36} wbFormIDCk('Object Display Shader', [EFSH, NULL]), {40} wbFormIDCk('Effect sound', [NULL, SOUN]), {44} wbFormIDCk('Bolt sound', [NULL, SOUN]), {48} wbFormIDCk('Hit sound', [NULL, SOUN]), {52} wbFormIDCk('Area sound', [NULL, SOUN]), {56} wbFloat('Constant Effect enchantment factor (Unused)'), {60} wbFloat('Constant Effect barter factor (Unused)'), {64} wbInteger('Archtype', itU32, wbArchtypeEnum, cpNormal, False, nil, wbMGEFArchtypeAfterSet), {68} wbActorValue ], cpNormal, True), wbRArrayS('Counter Effects', wbFormIDCk(ESCE, 'Effect', [MGEF]), cpNormal, False, nil, wbCounterEffectsAfterSet) ], False, nil, cpNormal, False, wbMGEFAfterLoad, wbMGEFAfterSet); wbRecord(MISC, 'Misc. Item', [ wbEDIDReq, wbOBNDReq, wbFULL, wbMODL, wbICON, wbSCRI, wbDEST, wbYNAM, wbZNAM, wbStruct(DATA, '', [ wbInteger('Value', itS32), wbFloat('Weight') ], cpNormal, True), wbFormIDCk(RNAM, 'Sound - Random/Looping', [SOUN]) ]); wbRecord(COBJ, 'Constructible Object', [ wbEDID, wbOBND, wbFULL, wbMODL, wbICON, wbSCRI, wbYNAM, wbZNAM, wbStruct(DATA, '', [ wbInteger('Value', itS32), wbFloat('Weight') ], cpNormal, True) ]); // floats are reported to change faces after copying if True {wbSimpleRecords} then begin wbFaceGen := wbRStruct('FaceGen Data', [ wbByteArray(FGGS, 'FaceGen Geometry-Symmetric', 0, cpNormal, True), wbByteArray(FGGA, 'FaceGen Geometry-Asymmetric', 0, cpNormal, True), wbByteArray(FGTS, 'FaceGen Texture-Symmetric', 0, cpNormal, True) ], [], cpNormal, True); wbFaceGenNPC := wbRStruct('FaceGen Data', [ // Arrays of 4bytes elements wbByteArray(FGGS, 'FaceGen Geometry-Symmetric', 0, cpNormal, True), wbByteArray(FGGA, 'FaceGen Geometry-Asymmetric', 0, cpNormal, True), wbByteArray(FGTS, 'FaceGen Texture-Symmetric', 0, cpNormal, True) ], [], cpNormal, True, wbActorTemplateUseModelAnimation); end else begin wbFaceGen := wbRStruct('FaceGen Data', [ wbArray(FGGS, 'FaceGen Geometry-Symmetric', wbFloat('Value'), [], cpNormal, True), wbArray(FGGA, 'FaceGen Geometry-Asymmetric', wbFloat('Value'), [], cpNormal, True), wbArray(FGTS, 'FaceGen Texture-Symmetric', wbFloat('Value'), [], cpNormal, True) ], [], cpNormal, True); wbFaceGenNPC := wbRStruct('FaceGen Data', [ wbArray(FGGS, 'FaceGen Geometry-Symmetric', wbFloat('Value'), [], cpNormal, True), wbArray(FGGA, 'FaceGen Geometry-Asymmetric', wbFloat('Value'), [], cpNormal, True), wbArray(FGTS, 'FaceGen Texture-Symmetric', wbFloat('Value'), [], cpNormal, True) ], [], cpNormal, True, wbActorTemplateUseModelAnimation); end; wbRecord(NPC_, 'Non-Player Character', [ wbEDIDReq, wbOBNDReq, wbFULLActor, wbMODLActor, wbStruct(ACBS, 'Configuration', [ {00} wbInteger('Flags', itU32, wbFlags([ {0x000001} 'Female', {0x000002} 'Essential', {0x000004} 'Is CharGen Face Preset', {0x000008} 'Respawn', {0x000010} 'Auto-calc stats', {0x000020} '', {0x000040} '', {0x000080} 'PC Level Mult', {0x000100} 'Use Template', {0x000200} 'No Low Level Processing', {0x000400} '', {0x000800} 'No Blood Spray', {0x001000} 'No Blood Decal', {0x002000} '', {0x004000} '', {0x008000} '', {0x010000} '', {0x020000} '', {0x040000} '', {0x080000} '', {0x100000} 'No VATS Melee', {0x00200000} '', {0x00400000} 'Can be all races', {0x00800000} 'Autocalc Service', {0x01000000} '', {0x02000000} '', {0x04000000} 'No Knockdowns', {0x08000000} 'Not Pushable', {0x10000000} 'Unknown 28', {0x20000000} '', {0x40000000} 'No Rotating To Head-track', {0x80000000} '' ], [ {0x000001 Female} wbActorTemplateUseTraits, {0x000002 Essential} wbActorTemplateUseBaseData, {0x000004 Is CharGen Face Preset} nil, {0x000008 Respawn} wbActorTemplateUseBaseData, {0x000010 Auto-calc stats} wbActorTemplateUseStats, {0x000020 } nil, {0x000040 } nil, {0x000080 PC Level Mult} wbActorTemplateUseStats, {0x000100 Use Template} nil, {0x000200 No Low Level Processing} wbActorTemplateUseBaseData, {0x000400 } nil, {0x000800 No Blood Spray} wbActorTemplateUseModelAnimation, {0x001000 No Blood Decal} wbActorTemplateUseModelAnimation, {0x002000 } nil, {0x004000 } nil, {0x008000 } nil, {0x010000 } nil, {0x020000 } nil, {0x040000 } nil, {0x080000 } nil, {0x100000 No VATS Melee} nil, {0x00200000 } nil, {0x00400000 Can be all races} nil, {0x00800000 } nil, {0x01000000 } nil, {0x02000000 } nil, {0x04000000 No Knockdowns} nil, {0x08000000 Not Pushable} wbActorTemplateUseModelAnimation, {0x10000000 } nil, {0x20000000 } nil, {0x40000000 No Rotating To Head-track} wbActorTemplateUseModelAnimation, {0x80000000 } nil ])), {04} wbInteger('Fatigue', itU16, nil, cpNormal, True, wbActorTemplateUseStats), {06} wbInteger('Barter gold', itU16, nil, cpNormal, False, wbActorTemplateUseAIData), {08} wbUnion('Level', wbCreaLevelDecider, [ wbInteger('Level', itS16, nil, cpNormal, True, wbActorTemplateUseStats), wbInteger('Level Mult', itS16, wbDiv(1000), cpNormal, True, wbActorTemplateUseStats) ], cpNormal, True, wbActorTemplateUseStats), {10} wbInteger('Calc min', itU16, nil, cpNormal, True, wbActorTemplateUseStats), {12} wbInteger('Calc max', itU16, nil, cpNormal, True, wbActorTemplateUseStats), {14} wbInteger('Speed Multiplier', itU16, nil, cpNormal, True, wbActorTemplateUseStats), {16} wbFloat('Karma (Alignment)', cpNormal, False, 1, -1, wbActorTemplateUseTraits), {20} wbInteger('Disposition Base', itS16, nil, cpNormal, False, wbActorTemplateUseTraits), {22} wbInteger('Template Flags', itU16, wbTemplateFlags) ], cpNormal, True), wbRArrayS('Factions', wbStructSK(SNAM, [0], 'Faction', [ wbFormIDCk('Faction', [FACT]), wbInteger('Rank', itU8), wbByteArray('Unused', 3) ]), cpNormal, False, nil, nil, wbActorTemplateUseFactions), wbFormIDCk(INAM, 'Death item', [LVLI], False, cpNormal, False, wbActorTemplateUseTraits), wbFormIDCk(VTCK, 'Voice', [VTYP], False, cpNormal, True, wbActorTemplateUseTraits), wbFormIDCk(TPLT, 'Template', [LVLN, NPC_]), wbFormIDCk(RNAM, 'Race', [RACE], False, cpNormal, True, wbActorTemplateUseTraits), wbSPLOs, wbFormIDCk(EITM, 'Unarmed Attack Effect', [ENCH, SPEL], False, cpNormal, False, wbActorTemplateUseActorEffectList), wbInteger(EAMT, 'Unarmed Attack Animation', itU16, wbAttackAnimationEnum, cpNormal, True, False, wbActorTemplateUseActorEffectList), wbDESTActor, wbSCRIActor, wbRArrayS('Items', wbCNTO, cpNormal, False, nil, nil, wbActorTemplateUseInventory), wbAIDT, wbRArray('Packages', wbFormIDCk(PKID, 'Package', [PACK]), cpNormal, False, nil, nil, wbActorTemplateUseAIPackages), wbArrayS(KFFZ, 'Animations', wbStringLC('Animation'), 0, cpNormal, False, nil, nil, wbActorTemplateUseModelAnimation), wbFormIDCk(CNAM, 'Class', [CLAS], False, cpNormal, True, wbActorTemplateUseTraits), wbStruct(DATA, '', [ {00} wbInteger('Base Health', itS32), {04} wbArray('Attributes', wbInteger('Attribute', itU8), [ 'Strength', 'Perception', 'Endurance', 'Charisma', 'Intelligence', 'Agility', 'Luck' ], cpNormal, False, wbActorAutoCalcDontShow), wbByteArray('Unused'{, 14 - only present in old record versions}) ], cpNormal, True, wbActorTemplateUseStats), wbStruct(DNAM, '', [ {00} wbArray('Skill Values', wbInteger('Skill', itU8), [ 'Barter', 'Big Guns (obsolete)', 'Energy Weapons', 'Explosives', 'Lockpick', 'Medicine', 'Melee Weapons', 'Repair', 'Science', 'Guns', 'Sneak', 'Speech', 'Survival', 'Unarmed' ]), {14} wbArray('Skill Offsets', wbInteger('Skill', itU8), [ 'Barter', 'Big Guns (obsolete)', 'Energy Weapons', 'Explosives', 'Lockpick', 'Medicine', 'Melee Weapons', 'Repair', 'Science', 'Guns', 'Sneak', 'Speech', 'Survival', 'Unarmed' ]) ], cpNormal, False, wbActorTemplateUseStatsAutoCalc), wbRArrayS('Head Parts', wbFormIDCk(PNAM, 'Head Part', [HDPT]), cpNormal, False, nil, nil, wbActorTemplateUseModelAnimation), wbFormIDCk(HNAM, 'Hair', [HAIR], False, cpNormal, False, wbActorTemplateUseModelAnimation), wbFloat(LNAM, 'Hair length', cpNormal, False, 1, -1, wbActorTemplateUseModelAnimation), wbFormIDCk(ENAM, 'Eyes', [EYES], False, cpNormal, False, wbActorTemplateUseModelAnimation), wbStruct(HCLR, 'Hair color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ], cpNormal, True, wbActorTemplateUseModelAnimation), wbFormIDCk(ZNAM, 'Combat Style', [CSTY], False, cpNormal, False, wbActorTemplateUseTraits), wbInteger(NAM4, 'Impact Material Type', itU32, wbImpactMaterialTypeEnum, cpNormal, True, False, wbActorTemplateUseModelAnimation), wbFaceGenNPC, wbInteger(NAM5, 'Unknown', itU16, nil, cpNormal, True, False, nil, nil, 255), wbFloat(NAM6, 'Height', cpNormal, True, 1, -1, wbActorTemplateUseTraits), wbFloat(NAM7, 'Weight', cpNormal, True, 1, -1, wbActorTemplateUseTraits) ], True, nil, cpNormal, False, wbNPCAfterLoad); wbPKDTFlags := wbFlags([ {0x00000001} 'Offers Services', {0x00000002} 'Must reach location', {0x00000004} 'Must complete', {0x00000008} 'Lock doors at package start', {0x00000010} 'Lock doors at package end', {0x00000020} 'Lock doors at location', {0x00000040} 'Unlock doors at package start', {0x00000080} 'Unlock doors at package end', {0x00000100} 'Unlock doors at location', {0x00000200} 'Continue if PC near', {0x00000400} 'Once per day', {0x00000800} '', {0x00001000} 'Skip fallout behavior', {0x00002000} 'Always run', {0x00004000} '', {0x00008000} '', {0x00010000} '', {0x00020000} 'Always sneak', {0x00040000} 'Allow swimming', {0x00080000} 'Allow falls', {0x00100000} 'Head-Tracking off', {0x00200000} 'Weapons unequipped', {0x00400000} 'Defensive combat', {0x00800000} 'Weapon Drawn', {0x01000000} 'No idle anims', {0x02000000} 'Pretend In Combat', {0x04000000} 'Continue During Combat', {0x08000000} 'No Combat Alert', {0x10000000} 'No Warn/Attack Behaviour', {0x20000000} '', {0x40000000} '', {0x80000000} '' ]); wbPKDTType := wbEnum([ {0} 'Find', {1} 'Follow', {2} 'Escort', {3} 'Eat', {4} 'Sleep', {5} 'Wander', {6} 'Travel', {7} 'Accompany', {8} 'Use Item At', {9} 'Ambush', {10} 'Flee Not Combat', {11} 'Package Type 11', {12} 'Sandbox', {13} 'Patrol', {14} 'Guard', {15} 'Dialogue', {16} 'Use Weapon', {17} 'Package Type 17', {18} 'Combat Controller', {19} 'Package Type 19', {20} 'Package Type 20', {21} 'Alarm', {22} 'Flee', {23} 'TressPass', {24} 'Spectator', {25} 'Package Type 25', {26} 'Package Type 26', {27} 'Package Type 27', {28} 'Dialogue 2', {29} 'Package Type 29', {30} 'Package Type 30', {31} 'Package Type 31', {32} 'Package Type 32', {33} 'Package Type 33', {34} 'Package Type 34', {35} 'Package Type 35', {36} 'Package Type 36', {37} 'Package Type 37', {38} 'Package Type 38', {39} 'Package Type 39', {40} 'Package Type 40' ]); wbObjectTypeEnum := wbEnum([ ' NONE', 'Activators', 'Armor', 'Books', 'Clothing', 'Containers', 'Doors', 'Ingredients', 'Lights', 'Misc', 'Flora', 'Furniture', 'Weapons: Any', 'Ammo', 'NPCs', 'Creatures', 'Keys', 'Alchemy', 'Food', ' All: Combat Wearable', ' All: Wearable', 'Weapons: Ranged', 'Weapons: Melee', 'Weapons: NONE', 'Actor Effects: Any', 'Actor Effects: Range Target', 'Actor Effects: Range Touch', 'Actor Effects: Range Self', // '', 'Actors: Any' ]); wbPKDTSpecificFlagsUnused := True; wbRecord(PACK, 'Package', [ wbEDIDReq, wbStruct(PKDT, 'General', [ wbInteger('General Flags', itU32, wbPKDTFlags), wbInteger('Type', itU8, wbPKDTType), wbByteArray('Unused', 1), wbInteger('Fallout Behavior Flags', itU16, wbFlags([ {0x00000001}'Hellos To Player', {0x00000002}'Random Conversations', {0x00000004}'Observe Combat Behavior', {0x00000008}'Unknown 4', {0x00000010}'Reaction To Player Actions', {0x00000020}'Friendly Fire Comments', {0x00000040}'Aggro Radius Behavior', {0x00000080}'Allow Idle Chatter', {0x00000100}'Avoid Radiation' ], True)), wbUnion('Type Specific Flags', wbPKDTSpecificFlagsDecider, [ wbEmpty('Type Specific Flags (missing)', cpIgnore, False, nil, True), wbInteger('Type Specific Flags - Find', itU16, wbFlags([ {0x00000001}'', {0x00000002}'', {0x00000004}'', {0x00000008}'', {0x00000010}'', {0x00000020}'', {0x00000040}'', {0x00000080}'', {0x00000100}'Find - Allow Buying', {0x00000200}'Find - Allow Killing', {0x00000400}'Find - Allow Stealing' ], wbPKDTSpecificFlagsUnused)), wbInteger('Type Specific Flags - Follow', itU16, wbFlags([], wbPKDTSpecificFlagsUnused)), wbInteger('Type Specific Flags - Escort', itU16, wbFlags([ {0x00000001}'', {0x00000002}'', {0x00000004}'', {0x00000008}'', {0x00000010}'', {0x00000020}'', {0x00000040}'', {0x00000080}'', {0x00000100}'Escort - Allow Buying', {0x00000200}'Escort - Allow Killing', {0x00000400}'Escort - Allow Stealing' ], wbPKDTSpecificFlagsUnused)), wbInteger('Type Specific Flags - Eat', itU16, wbFlags([ {0x00000001}'', {0x00000002}'', {0x00000004}'', {0x00000008}'', {0x00000010}'', {0x00000020}'', {0x00000040}'', {0x00000080}'', {0x00000100}'Eat - Allow Buying', {0x00000200}'Eat - Allow Killing', {0x00000400}'Eat - Allow Stealing' ], wbPKDTSpecificFlagsUnused)), wbInteger('Type Specific Flags - Sleep', itU16, wbFlags([], wbPKDTSpecificFlagsUnused)), wbInteger('Type Specific Flags - Wander', itU16, wbFlags([ {0x00000001}'Wander - No Eating', {0x00000002}'Wander - No Sleeping', {0x00000004}'Wander - No Conversation', {0x00000008}'Wander - No Idle Markers', {0x00000010}'Wander - No Furniture', {0x00000020}'Wander - No Wandering' ], wbPKDTSpecificFlagsUnused)), wbInteger('Type Specific Flags - Travel', itU16, wbFlags([], wbPKDTSpecificFlagsUnused)), wbInteger('Type Specific Flags - Accompany', itU16, wbFlags([], wbPKDTSpecificFlagsUnused)), wbInteger('Type Specific Flags - Use Item At', itU16, wbFlags([ {0x00000001}'', {0x00000002}'Use Item At - Sit Down', {0x00000004}'', {0x00000008}'', {0x00000010}'', {0x00000020}'', {0x00000040}'', {0x00000080}'', {0x00000100}'Use Item At - Allow Buying', {0x00000200}'Use Item At - Allow Killing', {0x00000400}'Use Item At - Allow Stealing' ], wbPKDTSpecificFlagsUnused)), wbInteger('Type Specific Flags - Ambush', itU16, wbFlags([ {0x00000001}'Ambush - Hide While Ambushing' ], wbPKDTSpecificFlagsUnused)), wbInteger('Type Specific Flags - Flee Not Combat', itU16, wbFlags([], wbPKDTSpecificFlagsUnused)), wbInteger('Type Specific Flags - ?', itU16, wbFlags([], wbPKDTSpecificFlagsUnused)), wbInteger('Type Specific Flags - Sandbox', itU16, wbFlags([ {0x00000001}'Sandbox - No Eating', {0x00000002}'Sandbox - No Sleeping', {0x00000004}'Sandbox - No Conversation', {0x00000008}'Sandbox - No Idle Markers', {0x00000010}'Sandbox - No Furniture', {0x00000020}'Sandbox - No Wandering' ], wbPKDTSpecificFlagsUnused)), wbInteger('Type Specific Flags - Patrol', itU16, wbFlags([], wbPKDTSpecificFlagsUnused)), wbInteger('Type Specific Flags - Guard', itU16, wbFlags([ {0x00000001}'', {0x00000002}'', {0x00000004}'Guard - Remain Near Reference to Guard' ], wbPKDTSpecificFlagsUnused)), wbInteger('Type Specific Flags - Dialogue', itU16, wbFlags([], wbPKDTSpecificFlagsUnused)), wbInteger('Type Specific Flags - Use Weapon', itU16, wbFlags([], wbPKDTSpecificFlagsUnused)) ]), wbByteArray('Unused', 2) ], cpNormal, True, nil, 2), wbRStruct('Locations', [ wbStruct(PLDT, 'Location 1', [ wbInteger('Type', itS32, wbEnum([ // Byte + filler {0} 'Near reference', {1} 'In cell', {2} 'Near current location', {3} 'Near editor location', {4} 'Object ID', {5} 'Object Type', {6} 'Near linked reference', {7} 'At package location' ])), wbUnion('Location', wbPxDTLocationDecider, [ wbFormIDCkNoReach('Reference', [REFR, PGRE, PMIS, PBEA, ACHR, ACRE, PLYR], True), wbFormIDCkNoReach('Cell', [CELL]), wbByteArray('Unused', 4, cpIgnore), wbByteArray('Unused', 4, cpIgnore), wbFormIDCkNoReach('Object ID', [ACTI, DOOR, STAT, FURN, CREA, SPEL, NPC_, CONT, ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, LIGH, CHIP, CMNY, CCRD, IMOD]), wbInteger('Object Type', itU32, wbObjectTypeEnum), wbByteArray('Unused', 4, cpIgnore), wbByteArray('Unused', 4, cpIgnore) ]), wbInteger('Radius', itS32) ], cpNormal, True), wbStruct(PLD2, 'Location 2', [ wbInteger('Type', itS32, wbEnum([ {0} 'Near reference', {1} 'In cell', {2} 'Near current location', {3} 'Near editor location', {4} 'Object ID', {5} 'Object Type', {6} 'Near linked reference', {7} 'At package location' ])), wbUnion('Location', wbPxDTLocationDecider, [ wbFormIDCkNoReach('Reference', [REFR, PGRE, PMIS, PBEA, ACHR, ACRE, PLYR], True), wbFormIDCkNoReach('Cell', [CELL]), wbByteArray('Unused', 4, cpIgnore), wbByteArray('Unused', 4, cpIgnore), wbFormIDCkNoReach('Object ID', [ACTI, DOOR, STAT, FURN, CREA, SPEL, NPC_, CONT, ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, LIGH, CHIP, CMNY, CCRD, IMOD]), wbInteger('Object Type', itU32, wbObjectTypeEnum), wbByteArray('Unused', 4, cpIgnore), wbByteArray('Unused', 4, cpIgnore) ]), wbInteger('Radius', itS32) ]) ], [], cpNormal, False, nil, True), wbStruct(PSDT, 'Schedule', [ wbInteger('Month', itS8), wbInteger('Day of week', itS8, wbEnum([ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Weekdays', 'Weekends', 'Monday, Wednesday, Friday', 'Tuesday, Thursday' ], [ -1, 'Any' ])), wbInteger('Date', itU8), wbInteger('Time', itS8), wbInteger('Duration', itS32) ], cpNormal, True), wbStruct(PTDT, 'Target 1', [ wbInteger('Type', itS32, wbEnum([ {0} 'Specific Reference', {1} 'Object ID', {2} 'Object Type', {3} 'Linked Reference' ]), cpNormal, False, nil, nil, 2), wbUnion('Target', wbPxDTLocationDecider, [ wbFormIDCkNoReach('Reference', [ACHR, ACRE, REFR, PGRE, PMIS, PBEA, PLYR], True), wbFormIDCkNoReach('Object ID', [ACTI, DOOR, STAT, FURN, CREA, SPEL, NPC_, LVLN, LVLC, CONT, ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, LIGH, FACT, FLST, IDLM, CHIP, CMNY, CCRD, IMOD]), wbInteger('Object Type', itU32, wbObjectTypeEnum), wbByteArray('Unused', 4, cpIgnore) ]), wbInteger('Count / Distance', itS32), wbFloat('Unknown') ], cpNormal, False, nil, 3), wbCTDAs, wbRStruct('Idle Animations', [ wbInteger(IDLF, 'Flags', itU8, wbFlags([ 'Run in Sequence', '', 'Do Once' ]), cpNormal, True), wbStruct(IDLC, '', [ wbInteger( 'Animation Count', itU8), wbByteArray('Unused', 3) ], cpNormal, True, nil, 1), wbFloat(IDLT, 'Idle Timer Setting', cpNormal, True), wbArray(IDLA, 'Animations', wbFormIDCk('Animation', [IDLE]), 0, nil, wbIDLAsAfterSet, cpNormal, True), wbByteArray(IDLB, 'Unused', 4, cpIgnore) ], [], cpNormal, False, nil, False, nil {cannot be totally removed , wbAnimationsAfterSet}), wbFormIDCk(CNAM, 'Combat Style', [CSTY]), wbEmpty(PKED, 'Eat Marker'), wbInteger(PKE2, 'Escort Distance', itU32), wbFloat(PKFD, 'Follow - Start Location - Trigger Radius'), wbStruct(PKPT, 'Patrol Flags', [ wbInteger('Repeatable', itU8, wbEnum(['No', 'Yes']), cpNormal, False, nil, nil, 1), wbByteArray('Unused', 1) ], cpNormal, False, nil, 1), wbStruct(PKW3, 'Use Weapon Data', [ wbInteger('Flags', itU32, wbFlags([ 'Always Hit', '', '', '', '', '', '', '', 'Do No Damage', '', '', '', '', '', '', '', 'Crouch To Reload', '', '', '', '', '', '', '', 'Hold Fire When Blocked' ])), wbInteger('Fire Rate', itU8, wbEnum([ 'Auto Fire', 'Volley Fire' ])), wbInteger('Fire Count', itU8, wbEnum([ 'Number of Bursts', 'Repeat Fire' ])), wbInteger('Number of Bursts', itU16), wbStruct('Shoots Per Volleys', [ wbInteger('Min', itU16), wbInteger('Max', itU16) ]), wbStruct('Pause Between Volleys', [ wbFloat('Min'), wbFloat('Max') ]), wbByteArray('Unused', 4) ]), wbStruct(PTD2, 'Target 2', [ wbInteger('Type', itS32, wbEnum([ {0} 'Specific reference', {1} 'Object ID', {2} 'Object Type', {3} 'Linked Reference' ])), wbUnion('Target', wbPxDTLocationDecider, [ wbFormIDCkNoReach('Reference', [ACHR, ACRE, REFR, PGRE, PMIS, PBEA, PLYR], True), wbFormIDCkNoReach('Object ID', [ACTI, DOOR, STAT, FURN, CREA, SPEL, NPC_, LVLN, LVLC, CONT, ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, LIGH, FACT, FLST, CHIP, CMNY, CCRD, IMOD]), wbInteger('Object Type', itU32, wbObjectTypeEnum), wbByteArray('Unused', 4, cpIgnore) ]), wbInteger('Count / Distance', itS32), wbFloat('Unknown') ], cpNormal, False, nil, 3), wbEmpty(PUID, 'Use Item Marker'), wbEmpty(PKAM, 'Ambush Marker'), wbStruct(PKDD, 'Dialogue Data', [ wbFloat('FOV'), wbFormIDCk('Topic', [DIAL, NULL]), wbInteger('Flags', itU32, wbFlags([ 'No Headtracking', '', '', '', '', '', '', '', 'Don''t Control Target Movement' ])), wbByteArray('Unused', 4), wbInteger('Dialogue Type', itU32, wbEnum([ 'Conversation', 'Say To' ])), wbByteArray('Unknown', 4) ], cpNormal, False, nil, 3), wbStruct(PLD2, 'Location 2 (again??)', [ wbInteger('Type', itS32, wbEnum([ {0} 'Near reference', {1} 'In cell', {2} 'Near current location', {3} 'Near editor location', {4} 'Object ID', {5} 'Object Type', {6} 'Near linked reference', {7} 'At package location' ])), wbUnion('Location', wbPxDTLocationDecider, [ wbFormIDCkNoReach('Reference', [REFR, PGRE, PMIS, PBEA, ACHR, ACRE, PLYR], True), wbFormIDCkNoReach('Cell', [CELL]), wbByteArray('Unused', 4, cpIgnore), wbByteArray('Unused', 4, cpIgnore), wbFormIDCkNoReach('Object ID', [ACTI, DOOR, STAT, FURN, CREA, SPEL, NPC_, CONT, ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, LIGH, CHIP, CMNY, CCRD, IMOD]), wbInteger('Object Type', itU32, wbObjectTypeEnum), wbByteArray('Unused', 4, cpIgnore), wbByteArray('Unused', 4, cpIgnore) ]), wbInteger('Radius', itS32) ]), wbRStruct('OnBegin', [ wbEmpty(POBA, 'OnBegin Marker', cpNormal, True), wbFormIDCk(INAM, 'Idle', [IDLE, NULL], False, cpNormal, True), wbEmbeddedScriptReq, wbFormIDCk(TNAM, 'Topic', [DIAL, NULL], False, cpNormal, True) ], [], cpNormal, True), wbRStruct('OnEnd', [ wbEmpty(POEA, 'OnEnd Marker', cpNormal, True), wbFormIDCk(INAM, 'Idle', [IDLE, NULL], False, cpNormal, True), wbEmbeddedScriptReq, wbFormIDCk(TNAM, 'Topic', [DIAL, NULL], False, cpNormal, True) ], [], cpNormal, True), wbRStruct('OnChange', [ wbEmpty(POCA, 'OnChange Marker', cpNormal, True), wbFormIDCk(INAM, 'Idle', [IDLE, NULL], False, cpNormal, True), wbEmbeddedScriptReq, wbFormIDCk(TNAM, 'Topic', [DIAL, NULL], False, cpNormal, True) ], [], cpNormal, True) ], False, nil, cpNormal, False, wbPACKAfterLoad); wbRecord(QUST, 'Quest', [ wbEDIDReq, wbSCRI, wbFULL, wbICON, wbStruct(DATA, 'General', [ wbInteger('Flags', itU8, wbFlags([ {0x01} 'Start game enabled', {0x02} '', {0x04} 'Allow repeated conversation topics', {0x08} 'Allow repeated stages', {0x10} 'Unknown 4' ])), wbInteger('Priority', itU8), wbByteArray('Unused', 2), wbFloat('Quest Delay') ], cpNormal, True, nil, 3), wbCTDAs, wbRArrayS('Stages', wbRStructSK([0], 'Stage', [ wbInteger(INDX, 'Stage Index', itS16), wbRArray('Log Entries', wbRStruct('Log Entry', [ wbInteger(QSDT, 'Stage Flags', itU8, wbFlags([ {0x01} 'Complete Quest', {0x02} 'Fail Quest' ])), wbCTDAs, wbString(CNAM, 'Log Entry', 0, cpTranslate), wbEmbeddedScriptReq, wbFormIDCk(NAM0, 'Next Quest', [QUST]) ], [])) ], [])), wbRArray('Objectives', wbRStruct('Objective', [ wbInteger(QOBJ, 'Objective Index', itS32), wbString(NNAM, 'Description', 0, cpNormal, True), wbRArray('Targets', wbRStruct('Target', [ wbStruct(QSTA, 'Target', [ wbFormIDCkNoReach('Target', [REFR, PGRE, PMIS, PBEA, ACRE, ACHR], True), wbInteger('Flags', itU8, wbFlags([ {0x01} 'Compass Marker Ignores Locks' ])), wbByteArray('Unused', 3) ]), wbCTDAs ], [])) ], [])) ]); wbHeadPartIndexEnum := wbEnum([ 'Head', 'Ears', 'Mouth', 'Teeth Lower', 'Teeth Upper', 'Tongue', 'Left Eye', 'Right Eye' ]); wbBodyPartIndexEnum := wbEnum([ 'Upper Body', 'Left Hand', 'Right Hand', 'Upper Body Texture' ]); wbRecord(RACE, 'Race', [ wbEDIDReq, wbFULLReq, wbDESCReq, wbXNAMs, wbStruct(DATA, '', [ wbArrayS('Skill Boosts', wbStructSK([0], 'Skill Boost', [ wbInteger('Skill', itS8, wbActorValueEnum), wbInteger('Boost', itS8) ]), 7), wbByteArray('Unused', 2), wbFloat('Male Height'), wbFloat('Female Height'), wbFloat('Male Weight'), wbFloat('Female Weight'), wbInteger('Flags', itU32, wbFlags([ 'Playable', '', 'Child' ])) ], cpNormal, True), wbFormIDCk(ONAM, 'Older', [RACE]), wbFormIDCk(YNAM, 'Younger', [RACE]), wbEmpty(NAM2, 'Unknown Marker', cpNormal, True), wbArray(VTCK, 'Voices', wbFormIDCk('Voice', [VTYP]), ['Male', 'Female'], cpNormal, True), wbArray(DNAM, 'Default Hair Styles', wbFormIDCk('Default Hair Style', [HAIR, NULL]), ['Male', 'Female'], cpNormal, True), wbArray(CNAM, 'Default Hair Colors', wbInteger('Default Hair Color', itU8, wbEnum([ 'Bleached', 'Brown', 'Chocolate', 'Platinum', 'Cornsilk', 'Suede', 'Pecan', 'Auburn', 'Ginger', 'Honey', 'Gold', 'Rosewood', 'Black', 'Chestnut', 'Steel', 'Champagne' ])), ['Male', 'Female'], cpNormal, True), wbFloat(PNAM, 'FaceGen - Main clamp', cpNormal, True), wbFloat(UNAM, 'FaceGen - Face clamp', cpNormal, True), wbByteArray(ATTR, 'Unused', 0, cpNormal, True), wbRStruct('Head Data', [ wbEmpty(NAM0, 'Head Data Marker', cpNormal, True), wbRStruct('Male Head Data', [ wbEmpty(MNAM, 'Male Data Marker', cpNormal, True), wbRArrayS('Parts', wbRStructSK([0], 'Part', [ wbInteger(INDX, 'Index', itU32, wbHeadPartIndexEnum), wbMODLReq, wbICON ], [], cpNormal, False, nil, False, nil, wbHeadPartsAfterSet), cpNormal, True) ], [], cpNormal, True), wbRStruct('Female Head Data', [ wbEmpty(FNAM, 'Female Data Marker', cpNormal, True), wbRArrayS('Parts', wbRStructSK([0], 'Part', [ wbInteger(INDX, 'Index', itU32, wbHeadPartIndexEnum), wbMODLReq, wbICON ], [], cpNormal, False, nil, False, nil, wbHeadPartsAfterSet), cpNormal, True) ], [], cpNormal, True) ], [], cpNormal, True), wbRStruct('Body Data', [ wbEmpty(NAM1, 'Body Data Marker', cpNormal, True), wbRStruct('Male Body Data', [ wbEmpty(MNAM, 'Male Data Marker'), wbRArrayS('Parts', wbRStructSK([0], 'Part', [ wbInteger(INDX, 'Index', itU32, wbBodyPartIndexEnum), wbICON, wbMODLReq ], []), cpNormal, True) ], [], cpNormal, True), wbRStruct('Female Body Data', [ wbEmpty(FNAM, 'Female Data Marker', cpNormal, True), wbRArrayS('Parts', wbRStructSK([0], 'Part', [ wbInteger(INDX, 'Index', itU32, wbBodyPartIndexEnum), wbICON, wbMODLReq ], []), cpNormal, True) ], [], cpNormal, True) ], [], cpNormal, True), wbArrayS(HNAM, 'Hairs', wbFormIDCk('Hair', [HAIR]), 0, cpNormal, True), wbArrayS(ENAM, 'Eyes', wbFormIDCk('Eye', [EYES]), 0, cpNormal, True), wbRStruct('FaceGen Data', [ wbRStruct('Male FaceGen Data', [ wbEmpty(MNAM, 'Male Data Marker', cpNormal, True), wbFaceGen, wbInteger(SNAM, 'Unknown', itU16, nil, cpNormal, True) ], [], cpNormal, True), wbRStruct('Female FaceGen Data', [ wbEmpty(FNAM, 'Female Data Marker', cpNormal, True), wbFaceGen, wbInteger(SNAM, 'Unknown', itU16, nil, cpNormal, True) // will effectivly overwrite the SNAM from the male :) ], [], cpNormal, True) ], [], cpNormal, True) ]); wbRecord(REFR, 'Placed Object', [ wbEDID, { wbStruct(RCLR, 'Linked Reference Color (Old Format?)', [ wbStruct('Link Start Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Link End Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]) ], cpIgnore),} wbByteArray(RCLR, 'Unused', 0, cpIgnore), wbFormIDCk(NAME, 'Base', [TREE, SOUN, ACTI, DOOR, STAT, FURN, CONT, ARMO, AMMO, LVLN, LVLC, MISC, WEAP, BOOK, KEYM, ALCH, LIGH, GRAS, ASPC, IDLM, ARMA, CHIP, MSTT, NOTE, PWAT, SCOL, TACT, TERM, TXST, CCRD, IMOD, CMNY], False, cpNormal, True), wbFormIDCk(XEZN, 'Encounter Zone', [ECZN]), {--- ?? ---} wbXRGD, wbXRGB, {--- Primitive ---} wbStruct(XPRM, 'Primitive', [ wbStruct('Bounds', [ wbFloat('X', cpNormal, True, 2, 4), wbFloat('Y', cpNormal, True, 2, 4), wbFloat('Z', cpNormal, True, 2, 4) ]), wbStruct('Color', [ {84} wbFloat('Red', cpNormal, False, 255, 0), {88} wbFloat('Green', cpNormal, False, 255, 0), {92} wbFloat('Blue', cpNormal, False, 255, 0) ]), wbFloat('Unknown'), wbInteger('Type', itU32, wbEnum([ 'None', 'Box', 'Sphere', 'Portal Box' ])) ]), wbInteger(XTRI, 'Collision Layer', itU32, wbEnum([ 'Unidentified', 'Static', 'AnimStatic', 'Transparent', 'Clutter', 'Weapon', 'Projectile', 'Spell', 'Biped', 'Trees', 'Props', 'Water', 'Trigger', 'Terrain', 'Trap', 'Non Collidable', 'Cloud Trap', 'Ground', 'Portal', 'Debris Small', 'Debris Large', 'Acustic Space', 'Actor Zone', 'Projectile Zone', 'Gas Trap', 'Shell Casing', 'Transparent Small', 'Invisible Wall', 'Transparent Small Anim', 'Dead Bip', 'Char Controller', 'Avoid Box', 'Collision Box', 'Camera Sphere', 'Door Detection', 'Camera Pick', 'Item Pick', 'Line Of Sight', 'Path Pick', 'Custom Pick 1', 'Custom Pick 2', 'Spell Explosion', 'Dropping Pick' ])), wbEmpty(XMBP, 'MultiBound Primitive Marker'), {--- Bound Contents ---} {--- Bound Data ---} wbStruct(XMBO, 'Bound Half Extents', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), {--- Teleport ---} wbStruct(XTEL, 'Teleport Destination', [ wbFormIDCk('Door', [REFR], True), wbPosRot, wbInteger('Flags', itU32, wbFlags([ 'No Alarm' ])) ]), {--- Map Data ---} wbRStruct('Map Marker', [ wbEmpty(XMRK, 'Map Marker Data'), wbInteger(FNAM, 'Flags', itU8, wbFlags([ {0x01} 'Visible', {0x02} 'Can Travel To', {0x04} '"Show All" Hidden' ]), cpNormal, True), wbFULLReq, wbStruct(TNAM, '', [ wbInteger('Type', itU8, wbEnum([ 'None', 'City', 'Settlement', 'Encampment', 'Natural Landmark', 'Cave', 'Factory', 'Monument', 'Military', 'Office', 'Town Ruins', 'Urban Ruins', 'Sewer Ruins', 'Metro', 'Vault' ])), wbByteArray('Unused', 1) ], cpNormal, True), wbFormIDCk(WMI1, 'Reputation', [REPU]) ], []), {--- Audio Data ---} wbRStruct('Audio Data', [ wbEmpty(MMRK, 'Audio Marker'), wbUnknown(FULL), wbFormIDCk(CNAM, 'Audio Location', [ALOC]), wbInteger(BNAM, 'Flags', itU32, wbFlags(['Use Controller Values'])), wbFloat(MNAM, 'Layer 2 Trigger %', cpNormal, True, 100), wbFloat(NNAM, 'Layer 3 Trigger %', cpNormal, True, 100) ], []), wbInteger(XSRF, 'Special Rendering Flags', itU32, wbFlags([ 'Unknown 0', 'Imposter', 'Use Full Shader in LOD' ])), wbByteArray(XSRD, 'Special Rendering Data', 4), {--- X Target Data ---} wbFormIDCk(XTRG, 'Target', [REFR, ACRE, ACHR, PGRE, PMIS, PBEA], True), {--- Leveled Actor ----} wbXLCM, {--- Patrol Data ---} wbRStruct('Patrol Data', [ wbFloat(XPRD, 'Idle Time', cpNormal, True), wbEmpty(XPPA, 'Patrol Script Marker', cpNormal, True), wbFormIDCk(INAM, 'Idle', [IDLE, NULL], False, cpNormal, True), wbEmbeddedScriptReq, wbFormIDCk(TNAM, 'Topic', [DIAL, NULL], False, cpNormal, True) ], []), {--- Radio ---} wbStruct(XRDO, 'Radio Data', [ wbFloat('Range Radius'), wbInteger('Broadcast Range Type', itU32, wbEnum([ 'Radius', 'Everywhere', 'Worldspace and Linked Interiors', 'Linked Interiors', 'Current Cell Only' ])), wbFloat('Static Percentage'), wbFormIDCkNoReach('Position Reference', [REFR, ACRE, ACHR, PGRE, PMIS, PBEA, NULL]) ]), {--- Ownership ---} wbRStruct('Ownership', [ wbXOWN, wbInteger(XRNK, 'Faction rank', itS32) ], [XCMT, XCMO]), {--- Lock ---} wbStruct(XLOC, 'Lock Data', [ wbInteger('Level', itU8), wbByteArray('Unused', 3), wbFormIDCkNoReach('Key', [KEYM, NULL]), wbInteger('Flags', itU8, wbFlags(['', '', 'Leveled Lock'])), wbByteArray('Unused', 3), wbByteArray('Unknown', 8) ], cpNormal, False, nil, 5), {--- Extra ---} wbInteger(XCNT, 'Count', itS32), wbFloat(XRDS, 'Radius'), wbFloat(XHLP, 'Health'), wbFloat(XRAD, 'Radiation'), wbFloat(XCHG, 'Charge'), wbRStruct('Ammo', [ wbFormIDCk(XAMT, 'Type', [AMMO], False, cpNormal, True), wbInteger(XAMC, 'Count', itS32, nil, cpNormal, True) ], []), {--- Reflected By / Refracted By ---} wbRArrayS('Reflected/Refracted By', wbStructSK(XPWR, [0], 'Water', [ wbFormIDCk('Reference', [REFR]), wbInteger('Type', itU32, wbFlags([ 'Reflection', 'Refraction' ])) ]) ), {--- Lit Water ---} wbRArrayS('Lit Water', wbFormIDCk(XLTW, 'Water', [REFR]) ), {--- Decals ---} wbRArrayS('Linked Decals', wbStructSK(XDCR, [0], 'Decal', [ wbFormIDCk('Reference', [REFR]), wbUnknown ]) ), {--- Linked Ref ---} wbFormIDCk(XLKR, 'Linked Reference', [REFR, ACRE, ACHR, PGRE, PMIS, PBEA, PLYR]), wbStruct(XCLP, 'Linked Reference Color', [ wbStruct('Link Start Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Link End Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]) ]), {--- Activate Parents ---} wbRStruct('Activate Parents', [ wbInteger(XAPD, 'Flags', itU8, wbFlags([ 'Parent Activate Only' ], True)), wbRArrayS('Activate Parent Refs', wbStructSK(XAPR, [0], 'Activate Parent Ref', [ wbFormIDCk('Reference', [REFR, ACRE, ACHR, PGRE, PMIS, PBEA, PLYR]), wbFloat('Delay') ]) ) ], []), wbString(XATO, 'Activation Prompt'), {--- Enable Parent ---} wbXESP, {--- Emittance ---} wbFormIDCk(XEMI, 'Emittance', [LIGH, REGN]), {--- MultiBound ---} wbFormIDCk(XMBR, 'MultiBound Reference', [REFR]), {--- Flags ---} wbInteger(XACT, 'Action Flag', itU32, wbFlags([ 'Use Default', 'Activate', 'Open', 'Open by Default' ])), wbEmpty(ONAM, 'Open by Default'), wbEmpty(XIBS, 'Ignored By Sandbox'), {--- Generated Data ---} wbStruct(XNDP, 'Navigation Door Link', [ wbFormIDCk('Navigation Mesh', [NAVM]), wbInteger('Teleport Marker Triangle', itS16, wbREFRNavmeshTriangleToStr, wbStringToInt), wbByteArray('Unused', 2) ]), wbArray(XPOD, 'Portal Data', wbFormIDCk('Room', [REFR, NULL]), 2), wbStruct(XPTL, 'Portal Data', [ wbStruct('Size', [ wbFloat('Width', cpNormal, False, 2), wbFloat('Height', cpNormal, False, 2) ]), wbStruct('Position', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), wbStruct('Rotation (Quaternion?)', [ wbFloat('q1'), wbFloat('q2'), wbFloat('q3'), wbFloat('q4') ]) ]), wbInteger(XSED, 'SpeedTree Seed', itU8), wbRStruct('Room Data', [ wbStruct(XRMR, 'Header', [ wbInteger('Linked Rooms Count', itU16), wbByteArray('Unknown', 2) ]), wbRArrayS('Linked Rooms', wbFormIDCk(XLRM, 'Linked Room', [REFR]) ) ], []), wbStruct(XOCP, 'Occlusion Plane Data', [ wbStruct('Size', [ wbFloat('Width', cpNormal, False, 2), wbFloat('Height', cpNormal, False, 2) ]), wbStruct('Position', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), wbStruct('Rotation (Quaternion?)', [ wbFloat('q1'), wbFloat('q2'), wbFloat('q3'), wbFloat('q4') ]) ]), wbArray(XORD, 'Linked Occlusion Planes', wbFormIDCk('Plane', [REFR, NULL]), [ 'Right', 'Left', 'Bottom', 'Top' ]), wbXLOD, {--- 3D Data ---} wbXSCL, wbDATAPosRot ], True, wbPlacedAddInfo, cpNormal, False, wbREFRAfterLoad); wbRecord(REGN, 'Region', [ wbEDID, wbICON, wbStruct(RCLR, 'Map Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ], cpNormal, True), wbFormIDCkNoReach(WNAM, 'Worldspace', [WRLD]), wbRArray('Region Areas', wbRStruct('Region Area', [ wbInteger(RPLI, 'Edge Fall-off', itU32), wbArray(RPLD, 'Region Point List Data', wbStruct('Point', [ wbFloat('X'), wbFloat('Y') ]), 0, wbRPLDAfterLoad) ], [])), wbRArrayS('Region Data Entries', wbRStructSK([0], 'Region Data Entry', [ {always starts with an RDAT} wbStructSK(RDAT, [0], 'Data Header', [ wbInteger('Type', itU32, wbEnum([ {0}'', {1}'', {2}'Objects', {3}'Weather', {4}'Map', {5}'Land', {6}'Grass', {7}'Sound', {8}'Imposter', {9}'' ])), wbInteger('Flags', itU8, wbFlags([ 'Override' ])), wbInteger('Priority', itU8), wbByteArray('Unused') ], cpNormal, True), {followed by one of these: } {--- Objects ---} wbArray(RDOT, 'Objects', wbStruct('Object', [ wbFormIDCk('Object', [TREE, STAT, LTEX]), wbInteger('Parent Index', itU16, wbHideFFFF), wbByteArray('Unused', 2), wbFloat('Density'), wbInteger('Clustering', itU8), wbInteger('Min Slope', itU8), wbInteger('Max Slope', itU8), wbInteger('Flags', itU8, wbFlags([ {0}'Conform to slope', {1}'Paint Vertices', {2}'Size Variance +/-', {3}'X +/-', {4}'Y +/-', {5}'Z +/-', {6}'Tree', {7}'Huge Rock' ])), wbInteger('Radius wrt Parent', itU16), wbInteger('Radius', itU16), wbFloat('Min Height'), wbFloat('Max Height'), wbFloat('Sink'), wbFloat('Sink Variance'), wbFloat('Size Variance'), wbStruct('Angle Variance', [ wbInteger('X', itU16), wbInteger('Y', itU16), wbInteger('Z', itU16) ]), wbByteArray('Unused', 2), wbByteArray('Unknown', 4) ]), 0, nil, nil, cpNormal, False, wbREGNObjectsDontShow), {--- Map ---} wbString(RDMP, 'Map Name', 0, cpTranslate, False, wbREGNMapDontShow), {--- Grass ---} wbArrayS(RDGS, 'Grasses', wbStructSK([0], 'Grass', [ wbFormIDCk('Grass', [GRAS]), wbByteArray('Unknown',4) ]), 0, cpNormal, False, nil, nil, wbREGNGrassDontShow), {--- Sound ---} wbInteger(RDMD, 'Music Type', itU32, wbMusicEnum, cpIgnore, False, False, wbNeverShow), wbFormIDCk(RDMO, 'Music', [MUSC], False, cpNormal, False, wbREGNSoundDontShow), wbFormIDCk(RDSI, 'Incidental MediaSet', [MSET], False, cpNormal, False, wbREGNSoundDontShow), wbRArray('Battle MediaSets', wbFormIDCk(RDSB, 'Battle MediaSet', [MSET]), cpNormal, False, nil, nil, wbREGNSoundDontShow), wbArrayS(RDSD, 'Sounds', wbStructSK([0], 'Sound', [ wbFormIDCk('Sound', [SOUN]), wbInteger('Flags', itU32, wbFlags([ 'Pleasant', 'Cloudy', 'Rainy', 'Snowy' ])), wbInteger('Chance', itU32, wbScaledInt4ToStr, wbScaledInt4ToInt) ]), 0, cpNormal, False, nil, nil, wbREGNSoundDontShow), {--- Weather ---} wbArrayS(RDWT, 'Weather Types', wbStructSK([0], 'Weather Type', [ wbFormIDCk('Weather', [WTHR]), wbInteger('Chance', itU32), wbFormIDCk('Global', [GLOB, NULL]) ]), 0, cpNormal, False, nil, nil, wbREGNWeatherDontShow), {--- Imposter ---} wbArrayS(RDID, 'Imposters', wbFormIDCk('Imposter', [REFR]), 0, cpNormal, False, nil, nil, wbREGNImposterDontShow) ], [])) ], True); wbRecord(SOUN, 'Sound', [ wbEDIDReq, wbOBNDReq, wbString(FNAM, 'Sound Filename'), wbInteger(RNAM, 'Random Chance %', itU8), wbRUnion('Sound Data', [ wbStruct(SNDD, 'Sound Data', [ wbInteger('Minimum Attentuation Distance', itU8, wbMul(5)), wbInteger('Maximum Attentuation Distance', itU8, wbMul(100)), wbInteger('Frequency Adjustment %', itS8), wbByteArray('Unused', 1), wbInteger('Flags', itU32, wbFlags([ {0x0001} 'Random Frequency Shift', {0x0002} 'Play At Random', {0x0004} 'Environment Ignored', {0x0008} 'Random Location', {0x0010} 'Loop', {0x0020} 'Menu Sound', {0x0040} '2D', {0x0080} '360 LFE', {0x0100} 'Dialogue Sound', {0x0200} 'Envelope Fast', {0x0400} 'Envelope Slow', {0x0800} '2D Radius', {0x1000} 'Mute When Submerged', {0x2000} 'Start at Random Position' ])), wbInteger('Static attentuation cdB', itS16), wbInteger('Stop time ', itU8), wbInteger('Start time ', itU8), wbArray('Attenuation Curve', wbInteger('Point', itS16), 5), wbInteger('Reverb Attenuation Control', itS16), wbInteger('Priority', itS32), // wbByteArray('Unknown', 8) wbInteger('x', itS32), wbInteger('y', itS32) ], cpNormal, True), wbStruct(SNDX, 'Sound Data', [ wbInteger('Minimum attentuation distance', itU8, wbMul(5)), wbInteger('Maximum attentuation distance', itU8, wbMul(100)), wbInteger('Frequency adjustment %', itS8), wbByteArray('Unused', 1), wbInteger('Flags', itU32, wbFlags([ {0x0001} 'Random Frequency Shift', {0x0002} 'Play At Random', {0x0004} 'Environment Ignored', {0x0008} 'Random Location', {0x0010} 'Loop', {0x0020} 'Menu Sound', {0x0040} '2D', {0x0080} '360 LFE', {0x0100} 'Dialogue Sound', {0x0200} 'Envelope Fast', {0x0400} 'Envelope Slow', {0x0800} '2D Radius', {0x1000} 'Mute When Submerged' ])), wbInteger('Static attentuation cdB', itS16), wbInteger('Stop time ', itU8), wbInteger('Start time ', itU8) ], cpNormal, True) ], [], cpNormal, True), wbArray(ANAM, 'Attenuation Curve', wbInteger('Point', itS16), 5, nil, nil, cpNormal, False, wbNeverShow), wbInteger(GNAM, 'Reverb Attenuation Control', itS16, nil, cpNormal, False, False, wbNeverShow), wbInteger(HNAM, 'Priority', itS32, nil, cpNormal, False, False, wbNeverShow) ], False, nil, cpNormal, False, wbSOUNAfterLoad); wbRecord(SPEL, 'Actor Effect', [ wbEDIDReq, wbFULL, wbStruct(SPIT, '', [ wbInteger('Type', itU32, wbEnum([ {0} 'Actor Effect', {1} 'Disease', {2} 'Power', {3} 'Lesser Power', {4} 'Ability', {5} 'Poison', {6} '', {7} '', {8} '', {9} '', {10} 'Addiction' ])), wbInteger('Cost (Unused)', itU32), wbInteger('Level (Unused)', itU32, wbEnum([ {0} 'Unused' ])), wbInteger('Flags', itU8, wbFlags([ {0x00000001} 'No Auto-Calc', {0x00000002} 'Immune to Silence 1?', {0x00000004} 'PC Start Effect', {0x00000008} 'Immune to Silence 2?', {0x00000010} 'Area Effect Ignores LOS', {0x00000020} 'Script Effect Always Applies', {0x00000040} 'Disable Absorb/Reflect', {0x00000080} 'Force Touch Explode' ])), wbByteArray('Unused', 3) ], cpNormal, True), wbEffectsReq ]); wbRecord(STAT, 'Static', [ wbEDIDReq, wbOBNDReq, wbMODL, wbInteger(BRUS, 'Passthrough Sound', itS8, wbEnum([ 'BushA', 'BushB', 'BushC', 'BushD', 'BushE', 'BushF', 'BushG', 'BushH', 'BushI', 'BushJ' ], [ -1, 'NONE' ])), wbFormIDCk(RNAM, 'Sound - Looping/Random', [SOUN]) ]); wbRecord(TES4, 'Main File Header', [ wbStruct(HEDR, 'Header', [ wbFloat('Version'), wbInteger('Number of Records', itU32), wbInteger('Next Object ID', itU32) ], cpNormal, True), wbByteArray(OFST, 'Unknown', 0, cpIgnore), wbByteArray(DELE, 'Unknown', 0, cpIgnore), wbString(CNAM, 'Author', 0, cpTranslate, True), wbString(SNAM, 'Description', 0, cpTranslate), wbRArray('Master Files', wbRStruct('Master File', [ wbString(MAST, 'Filename', 0, cpNormal, True), wbByteArray(DATA, 'Unused', 8, cpIgnore, True) ], [ONAM])), wbArray(ONAM, 'Overriden Forms', wbFormIDCk('Form', [REFR, ACHR, ACRE, PMIS, PBEA, PGRE, LAND, NAVM]), 0, nil, nil, cpNormal, False, wbTES4ONAMDontShow), wbByteArray(SCRN, 'Screenshot') ], True, nil, cpNormal, True, wbRemoveOFST); wbRecord(TREE, 'Tree', [ wbEDIDReq, wbOBNDReq, wbMODLReq, wbICONReq, wbArrayS(SNAM, 'SpeedTree Seeds', wbInteger('SpeedTree Seed', itU32), 0, cpNormal, True), wbStruct(CNAM, 'Tree Data', [ wbFloat('Leaf Curvature'), wbFloat('Minimum Leaf Angle'), wbFloat('Maximum Leaf Angle'), wbFloat('Branch Dimming Value'), wbFloat('Leaf Dimming Value'), wbInteger('Shadow Radius', itS32), wbFloat('Rock Speed'), wbFloat('Rustle Speed') ], cpNormal, True), wbStruct(BNAM, 'Billboard Dimensions', [ wbFloat('Width'), wbFloat('Height') ], cpNormal, True) ]); end; procedure DefineFNVf; begin wbRecord(WATR, 'Water', [ wbEDIDReq, wbFULL, wbString(NNAM, 'Noise Map', 0, cpNormal, True), wbInteger(ANAM, 'Opacity', itU8, nil, cpNormal, True), wbInteger(FNAM, 'Flags', itU8, wbFlags([ {0}'Causes Damage', {1}'Reflective' ]), cpNormal, True), wbString(MNAM, 'Material ID', 0, cpNormal, True), wbFormIDCk(SNAM, 'Sound', [SOUN]), wbFormIDCk(XNAM, 'Actor Effect', [SPEL]), wbInteger(DATA, 'Damage', itU16, nil, cpNormal, True, True), wbRUnion('Visual Data', [ wbStruct(DNAM, 'Visual Data', [ wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Water Properties - Sun Power'), wbFloat('Water Properties - Reflectivity Amount'), wbFloat('Water Properties - Fresnel Amount'), wbByteArray('Unused', 4), wbFloat('Fog Properties - Above Water - Fog Distance - Near Plane'), wbFloat('Fog Properties - Above Water - Fog Distance - Far Plane'), wbStruct('Shallow Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Deep Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Reflection Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbByteArray('Unused', 4), wbFloat('Rain Simulator - Force'), wbFloat('Rain Simulator - Velocity'), wbFloat('Rain Simulator - Falloff'), wbFloat('Rain Simulator - Dampner'), wbFloat('Displacement Simulator - Starting Size'), wbFloat('Displacement Simulator - Force'), wbFloat('Displacement Simulator - Velocity'), wbFloat('Displacement Simulator - Falloff'), wbFloat('Displacement Simulator - Dampner'), wbFloat('Rain Simulator - Starting Size'), wbFloat('Noise Properties - Normals - Noise Scale'), wbFloat('Noise Properties - Noise Layer One - Wind Direction'), wbFloat('Noise Properties - Noise Layer Two - Wind Direction'), wbFloat('Noise Properties - Noise Layer Three - Wind Direction'), wbFloat('Noise Properties - Noise Layer One - Wind Speed'), wbFloat('Noise Properties - Noise Layer Two - Wind Speed'), wbFloat('Noise Properties - Noise Layer Three - Wind Speed'), wbFloat('Noise Properties - Normals - Depth Falloff Start'), wbFloat('Noise Properties - Normals - Depth Falloff End'), wbFloat('Fog Properties - Above Water - Fog Amount'), wbFloat('Noise Properties - Normals - UV Scale'), wbFloat('Fog Properties - Under Water - Fog Amount'), wbFloat('Fog Properties - Under Water - Fog Distance - Near Plane'), wbFloat('Fog Properties - Under Water - Fog Distance - Far Plane'), wbFloat('Water Properties - Distortion Amount'), wbFloat('Water Properties - Shininess'), wbFloat('Water Properties - Reflection HDR Multiplier'), wbFloat('Water Properties - Light Radius'), wbFloat('Water Properties - Light Brightness'), wbFloat('Noise Properties - Noise Layer One - UV Scale'), wbFloat('Noise Properties - Noise Layer Two - UV Scale'), wbFloat('Noise Properties - Noise Layer Three - UV Scale'), wbFloat('Noise Properties - Noise Layer One - Amplitude Scale'), wbFloat('Noise Properties - Noise Layer Two - Amplitude Scale'), wbFloat('Noise Properties - Noise Layer Three - Amplitude Scale') ], cpNormal, True, nil, 46), wbStruct(DATA, 'Visual Data', [ wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Water Properties - Sun Power'), wbFloat('Water Properties - Reflectivity Amount'), wbFloat('Water Properties - Fresnel Amount'), wbByteArray('Unused', 4), wbFloat('Fog Properties - Above Water - Fog Distance - Near Plane'), wbFloat('Fog Properties - Above Water - Fog Distance - Far Plane'), wbStruct('Shallow Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Deep Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Reflection Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbByteArray('Unused', 4), wbFloat('Rain Simulator - Force'), wbFloat('Rain Simulator - Velocity'), wbFloat('Rain Simulator - Falloff'), wbFloat('Rain Simulator - Dampner'), wbFloat('Displacement Simulator - Starting Size'), wbFloat('Displacement Simulator - Force'), wbFloat('Displacement Simulator - Velocity'), wbFloat('Displacement Simulator - Falloff'), wbFloat('Displacement Simulator - Dampner'), wbFloat('Rain Simulator - Starting Size'), wbFloat('Noise Properties - Normals - Noise Scale'), wbFloat('Noise Properties - Noise Layer One - Wind Direction'), wbFloat('Noise Properties - Noise Layer Two - Wind Direction'), wbFloat('Noise Properties - Noise Layer Three - Wind Direction'), wbFloat('Noise Properties - Noise Layer One - Wind Speed'), wbFloat('Noise Properties - Noise Layer Two - Wind Speed'), wbFloat('Noise Properties - Noise Layer Three - Wind Speed'), wbFloat('Noise Properties - Normals - Depth Falloff Start'), wbFloat('Noise Properties - Normals - Depth Falloff End'), wbFloat('Fog Properties - Above Water - Fog Amount'), wbFloat('Noise Properties - Normals - UV Scale'), wbFloat('Fog Properties - Under Water - Fog Amount'), wbFloat('Fog Properties - Under Water - Fog Distance - Near Plane'), wbFloat('Fog Properties - Under Water - Fog Distance - Far Plane'), wbFloat('Water Properties - Distortion Amount'), wbFloat('Water Properties - Shininess'), wbFloat('Water Properties - Reflection HDR Multiplier'), wbFloat('Water Properties - Light Radius'), wbFloat('Water Properties - Light Brightness'), wbFloat('Noise Properties - Noise Layer One - UV Scale'), wbFloat('Noise Properties - Noise Layer Two - UV Scale'), wbFloat('Noise Properties - Noise Layer Three - UV Scale'), wbEmpty('Noise Properties - Noise Layer One - Amplitude Scale'), wbEmpty('Noise Properties - Noise Layer Two - Amplitude Scale'), wbEmpty('Noise Properties - Noise Layer Three - Amplitude Scale'), wbInteger('Damage (Old Format)', itU16) ], cpNormal, True) ], [], cpNormal, True), wbStruct(GNAM, 'Related Waters (Unused)', [ wbFormIDCk('Daytime', [WATR, NULL]), wbFormIDCk('Nighttime', [WATR, NULL]), wbFormIDCk('Underwater', [WATR, NULL]) ], cpNormal, True) ], False, nil, cpNormal, False, wbWATRAfterLoad); wbRecord(WEAP, 'Weapon', [ wbEDIDReq, wbOBNDReq, wbFULL, wbMODL, wbICON, wbSCRI, wbEITM, wbInteger(EAMT, 'Enchantment Charge Amount', itS16), wbFormIDCkNoReach(NAM0, 'Ammo', [AMMO, FLST]), wbDEST, wbREPL, wbETYPReq, wbBIPL, wbYNAM, wbZNAM, wbRStruct('Shell Casing Model', [ wbString(MOD2, 'Model Filename'), wbByteArray(MO2T, 'Texture Files Hashes', 0, cpIgnore), wbMO2S ], []), wbRStruct('Scope Model', [ wbString(MOD3, 'Model Filename'), wbByteArray(MO3T, 'Texture Files Hashes', 0, cpIgnore), wbMO3S ], []), wbFormIDCK(EFSD, 'Scope Effect', [EFSH]), wbRStruct('World Model', [ wbString(MOD4, 'Model Filename'), wbByteArray(MO4T, 'Texture Files Hashes', 0, cpIgnore), wbMO4S ], []), wbString(MWD1, 'Model - Mod 1'), wbString(MWD2, 'Model - Mod 2'), wbString(MWD3, 'Model - Mod 1 and 2'), wbString(MWD4, 'Model - Mod 3'), wbString(MWD5, 'Model - Mod 1 and 3'), wbString(MWD6, 'Model - Mod 2 and 3'), wbString(MWD7, 'Model - Mod 1, 2 and 3'), {wbRStruct( 'Model with Mods', [ wbString(MWD1, 'Mod 1'), wbString(MWD2, 'Mod 2'), wbString(MWD3, 'Mod 1 and 2'), wbString(MWD4, 'Mod 3'), wbString(MWD5, 'Mod 1 and 3'), wbString(MWD6, 'Mod 2 and 3'), wbString(MWD7, 'Mod 1, 2 and 3') ], [], cpNormal, False, nil, True),} wbString(VANM, 'VATS Attack Name'), wbString(NNAM, 'Embedded Weapon Node'), wbFormIDCk(INAM, 'Impact DataSet', [IPDS]), wbFormIDCk(WNAM, '1st Person Model', [STAT]), wbFormIDCk(WNM1, '1st Person Model - Mod 1', [STAT]), wbFormIDCk(WNM2, '1st Person Model - Mod 2', [STAT]), wbFormIDCk(WNM3, '1st Person Model - Mod 1 and 2', [STAT]), wbFormIDCk(WNM4, '1st Person Model - Mod 3', [STAT]), wbFormIDCk(WNM5, '1st Person Model - Mod 1 and 3', [STAT]), wbFormIDCk(WNM6, '1st Person Model - Mod 2 and 3', [STAT]), wbFormIDCk(WNM7, '1st Person Model - Mod 1, 2 and 3', [STAT]), {wbRStruct('1st Person Models with Mods', [ wbFormIDCk(WNM1, 'Mod 1', [STAT]), wbFormIDCk(WNM2, 'Mod 2', [STAT]), wbFormIDCk(WNM3, 'Mod 1 and 2', [STAT]), wbFormIDCk(WNM4, 'Mod 3', [STAT]), wbFormIDCk(WNM5, 'Mod 1 and 3', [STAT]), wbFormIDCk(WNM6, 'Mod 2 and 3', [STAT]), wbFormIDCk(WNM7, 'Mod 1, 2 and 3', [STAT]) ], [], cpNormal, False, nil, True),} wbFormIDCk(WMI1, 'Weapon Mod 1', [IMOD]), wbFormIDCk(WMI2, 'Weapon Mod 2', [IMOD]), wbFormIDCk(WMI3, 'Weapon Mod 3', [IMOD]), {wbRStruct('Weapon Mods', [ wbFormIDCk(WMI1, 'Mod 1', [IMOD]), wbFormIDCk(WMI2, 'Mod 2', [IMOD]), wbFormIDCk(WMI3, 'Mod 3', [IMOD]) ], [], cpNormal, False, nil, True),} wbRStruct('Sound - Gun', [ wbFormIDCk(SNAM, 'Shoot 3D', [SOUN]), wbFormIDCk(SNAM, 'Shoot Dist', [SOUN]) ], []), //wbFormIDCk(SNAM, 'Sound - Gun - Shoot 3D', [SOUN]), //wbFormIDCk(SNAM, 'Sound - Gun - Shoot Dist', [SOUN]), wbFormIDCk(XNAM, 'Sound - Gun - Shoot 2D', [SOUN]), wbFormIDCk(NAM7, 'Sound - Gun - Shoot 3D Looping', [SOUN]), wbFormIDCk(TNAM, 'Sound - Melee - Swing / Gun - No Ammo', [SOUN]), wbFormIDCk(NAM6, 'Sound - Block', [SOUN]), wbFormIDCk(UNAM, 'Sound - Idle', [SOUN]), wbFormIDCk(NAM9, 'Sound - Equip', [SOUN]), wbFormIDCk(NAM8, 'Sound - Unequip', [SOUN]), wbRStruct('Sound - Mod 1', [ wbFormIDCk(WMS1, 'Shoot 3D', [SOUN]), wbFormIDCk(WMS1, 'Shoot Dist', [SOUN]) ], []), //wbFormIDCk(WMS1, 'Sound - Mod 1 - Shoot 3D', [SOUN]), //wbFormIDCk(WMS1, 'Sound - Mod 1 - Shoot Dist', [SOUN]), wbFormIDCk(WMS2, 'Sound - Mod 1 - Shoot 2D', [SOUN]), wbStruct(DATA, '', [ wbInteger('Value', itS32), wbInteger('Health', itS32), wbFloat('Weight'), wbInteger('Base Damage', itS16), wbInteger('Clip Size', itU8) ], cpNormal, True), wbStruct(DNAM, '', [ {00} wbInteger('Animation Type', itU32, wbWeaponAnimTypeEnum), {04} wbFloat('Animation Multiplier'), {08} wbFloat('Reach'), {12} wbInteger('Flags 1', itU8, wbFlags([ 'Ignores Normal Weapon Resistance', 'Is Automatic', 'Has Scope', 'Can''t Drop', 'Hide Backpack', 'Embedded Weapon', 'Don''t Use 1st Person IS Animations', 'Non-Playable' ])), {13} wbInteger('Grip Animation', itU8, wbEnum([ ], [ 230, 'HandGrip1', 231, 'HandGrip2', 232, 'HandGrip3', 233, 'HandGrip4', 234, 'HandGrip5', 235, 'HandGrip6', 255, 'DEFAULT' ])), {14} wbInteger('Ammo Use', itU8), {15} wbInteger('Reload Animation', itU8, wbReloadAnimEnum), {16} wbFloat('Min Spread'), {20} wbFloat('Spread'), {24} wbFloat('Unknown'), {28} wbFloat('Sight FOV'), {32} wbFloat, {36} wbFormIDCk('Projectile', [PROJ, NULL]), {40} wbInteger('Base VATS To-Hit Chance', itU8), {41} wbInteger('Attack Animation', itU8, wbEnum([ ], [ 26, 'AttackLeft', 32, 'AttackRight', 38, 'Attack3', 44, 'Attack4', 50, 'Attack5', 56, 'Attack6', 62, 'Attack7', 68, 'Attack8', 144, 'Attack9', 74, 'AttackLoop', 80, 'AttackSpin', 86, 'AttackSpin2', 114, 'AttackThrow', 120, 'AttackThrow2', 126, 'AttackThrow3', 132, 'AttackThrow4', 138, 'AttackThrow5', 150, 'AttackThrow6', 156, 'AttackThrow7', 162, 'AttackThrow8', 102, 'PlaceMine', 108, 'PlaceMine2', 255, 'DEFAULT' ])), {42} wbInteger('Projectile Count', itU8), {43} wbInteger('Embedded Weapon - Actor Value', itU8, wbEnum([ {00} 'Perception', {01} 'Endurance', {02} 'Left Attack', {03} 'Right Attack', {04} 'Left Mobility', {05} 'Right Mobilty', {06} 'Brain' ])), {44} wbFloat('Min Range'), {48} wbFloat('Max Range'), {52} wbInteger('On Hit', itU32, wbEnum([ 'Normal formula behavior', 'Dismember Only', 'Explode Only', 'No Dismember/Explode' ])), {56} wbInteger('Flags 2', itU32, wbFlags([ {0x00000001}'Player Only', {0x00000002}'NPCs Use Ammo', {0x00000004}'No Jam After Reload', {0x00000008}'Override - Action Points', {0x00000010}'Minor Crime', {0x00000020}'Range - Fixed', {0x00000040}'Not Used In Normal Combat', {0x00000080}'Override - Damage to Weapon Mult', {0x00000100}'Don''t Use 3rd Person IS Animations', {0x00000200}'Short Burst', {0x00000400}'Rumble Alternate', {0x00000800}'Long Burst', {0x00001000}'Scope has NightVision', {0x00002000}'Scope from Mod' ])), {60} wbFloat('Animation Attack Multiplier'), {64} wbFloat('Fire Rate'), {68} wbFloat('Override - Action Points'), {72} wbFloat('Rumble - Left Motor Strength'), {76} wbFloat('Rumble - Right Motor Strength'), {80} wbFloat('Rumble - Duration'), {84} wbFloat('Override - Damage to Weapon Mult'), {88} wbFloat('Attack Shots/Sec'), {92} wbFloat('Reload Time'), {96} wbFloat('Jam Time'), {100} wbFloat('Aim Arc'), {104} wbInteger('Skill', itS32, wbActorValueEnum), {108} wbInteger('Rumble - Pattern', itU32, wbEnum([ 'Constant', 'Square', 'Triangle', 'Sawtooth' ])), {112} wbFloat('Rumble - Wavelength'), {116} wbFloat('Limb Dmg Mult'), {120} wbInteger('Resist Type', itS32, wbActorValueEnum), {124} wbFloat('Sight Usage'), {128} wbFloat('Semi-Automatic Fire Delay Min'), {132} wbFloat('Semi-Automatic Fire Delay Max'), wbFloat, wbInteger('Effect - Mod 1', itU32, wbModEffectEnum), wbInteger('Effect - Mod 2', itU32, wbModEffectEnum), wbInteger('Effect - Mod 3', itU32, wbModEffectEnum), wbFloat('Value A - Mod 1'), wbFloat('Value A - Mod 2'), wbFloat('Value A - Mod 3'), wbInteger('Power Attack Animation Override', itU32, wbEnum([ ], [ 0, '0?', 97, 'AttackCustom1Power', 98, 'AttackCustom2Power', 99, 'AttackCustom3Power', 100, 'AttackCustom4Power', 101, 'AttackCustom5Power', 255, 'DEFAULT' ])), wbInteger('Strength Req', itU32), wbByteArray('Unknown', 1), wbInteger('Reload Animation - Mod', itU8, wbReloadAnimEnum), wbByteArray('Unknown', 2), wbFloat('Regen Rate'), wbFloat('Kill Impulse'), wbFloat('Value B - Mod 1'), wbFloat('Value B - Mod 2'), wbFloat('Value B - Mod 3'), wbFloat('Impulse Dist'), wbInteger('Skill Req', itU32) ], cpNormal, True, nil, 36), wbStruct(CRDT, 'Critical Data', [ {00} wbInteger('Critical Damage', itU16), {09} wbByteArray('Unused', 2), {04} wbFloat('Crit % Mult'), {08} wbInteger('Flags', itU8, wbFlags([ 'On Death' ])), {09} wbByteArray('Unused', 3), {12} wbFormIDCk('Effect', [SPEL, NULL]) ], cpNormal, True), wbStruct(VATS, 'VATS', [ wbFormIDCk('Effect',[SPEL, NULL]), wbFloat('Skill'), wbFloat('Dam. Mult'), wbFloat('AP'), wbInteger('Silent', itU8, wbEnum(['No', 'Yes'])), wbInteger('Mod Required', itU8, wbEnum(['No', 'Yes'])), wbByteArray('Unused', 2) ]), wbInteger(VNAM, 'Sound Level', itU32, wbSoundLevelEnum, cpNormal, True) ], True, nil, cpNormal, False, wbWEAPAfterLoad); if wbSimpleRecords then wbRecord(WRLD, 'Worldspace', [ wbEDIDReq, wbFULL, wbFormIDCk(XEZN, 'Encounter Zone', [ECZN]), wbRStruct('Parent', [ wbFormIDCk(WNAM, 'Worldspace', [WRLD]), wbInteger(PNAM, 'Flags', itU16, wbFlags([ {0x00000001}'Use Land Data', {0x00000002}'Use LOD Data', {0x00000004}'Use Map Data', {0x00000008}'Use Water Data', {0x00000010}'Use Climate Data', {0x00000020}'Use Image Space Data' ], True), cpNormal, True) ], []), wbFormIDCk(CNAM, 'Climate', [CLMT]), wbFormIDCk(NAM2, 'Water', [WATR]), wbFormIDCk(NAM3, 'LOD Water Type', [WATR]), wbFloat(NAM4, 'LOD Water Height'), wbStruct(DNAM, 'Land Data', [ wbFloat('Default Land Height'), wbFloat('Default Water Height') ]), wbICON, wbStruct(MNAM, 'Map Data', [ wbStruct('Usable Dimensions', [ wbInteger('X', itS32), wbInteger('Y', itS32) ]), wbStruct('Cell Coordinates', [ wbStruct('NW Cell', [ wbInteger('X', itS16), wbInteger('Y', itS16) ]), wbStruct('SE Cell', [ wbInteger('X', itS16), wbInteger('Y', itS16) ]) ]) ]), wbStruct(ONAM, 'World Map Offset Data', [ wbFloat('World Map Scale'), wbFloat('Cell X Offset'), wbFloat('Cell Y Offset') ], cpNormal, True), wbFormIDCk(INAM, 'Image Space', [IMGS]), wbInteger(DATA, 'Flags', itU8, wbFlags([ // LoadForm supports a DWord here, but only first byte would be used. {0x01} 'Small World', {0x02} 'Can''t Fast Travel', {0x04} '', {0x08} '', {0x10} 'No LOD Water', {0x20} 'No LOD Noise', {0x40} 'Don''t Allow NPC Fall Damage', {0x80} 'Needs Water Adjustment' ]), cpNormal, True), wbRStruct('Object Bounds', [ wbStruct(NAM0, 'Min', [ wbFloat('X', cpNormal, False, 1/4096), wbFloat('Y', cpNormal, False, 1/4096) ], cpIgnore, True), wbStruct(NAM9, 'Max', [ wbFloat('X', cpNormal, False, 1/4096), wbFloat('Y', cpNormal, False, 1/4096) ], cpIgnore, True) ], []), wbFormIDCk(ZNAM, 'Music', [MUSC]), wbString(NNAM, 'Canopy Shadow', 0, cpNormal, True), wbString(XNAM, 'Water Noise Texture', 0, cpNormal, True), wbRArrayS('Swapped Impacts', wbStructExSK(IMPS, [0, 1], [2], 'Swapped Impact', [ wbInteger('Material Type', itU32, wbImpactMaterialTypeEnum), wbFormIDCkNoReach('Old', [IPCT]), wbFormIDCk('New', [IPCT, NULL]) ])), wbArray(IMPF, 'Footstep Materials', wbString('Unknown', 30), [ 'ConcSolid', 'ConcBroken', 'MetalSolid', 'MetalHollow', 'MetalSheet', 'Wood', 'Sand', 'Dirt', 'Grass', 'Water' ]), wbByteArray(OFST, 'Offset Data') ], False, nil, cpNormal, False, wbRemoveOFST) else wbRecord(WRLD, 'Worldspace', [ wbEDIDReq, wbFULL, wbFormIDCk(XEZN, 'Encounter Zone', [ECZN]), wbRStruct('Parent', [ wbFormIDCk(WNAM, 'Worldspace', [WRLD]), wbInteger(PNAM, 'Flags', itU16, wbFlags([ {0x00000001}'Use Land Data', {0x00000002}'Use LOD Data', {0x00000004}'Use Map Data', {0x00000008}'Use Water Data', {0x00000010}'Use Climate Data', {0x00000020}'Use Image Space Data' // in order to use this "Image Space" needs to be NULL. // Other parent flags are checked before the form value. ], True), cpNormal, True) ], []), wbFormIDCk(CNAM, 'Climate', [CLMT]), wbFormIDCk(NAM2, 'Water', [WATR]), wbFormIDCk(NAM3, 'LOD Water Type', [WATR]), wbFloat(NAM4, 'LOD Water Height'), wbStruct(DNAM, 'Land Data', [ wbFloat('Default Land Height'), wbFloat('Default Water Height') ]), wbICON, wbStruct(MNAM, 'Map Data', [ wbStruct('Usable Dimensions', [ wbInteger('X', itS32), wbInteger('Y', itS32) ]), wbStruct('Cell Coordinates', [ wbStruct('NW Cell', [ wbInteger('X', itS16), wbInteger('Y', itS16) ]), wbStruct('SE Cell', [ wbInteger('X', itS16), wbInteger('Y', itS16) ]) ]) ]), wbStruct(ONAM, 'World Map Offset Data', [ wbFloat('World Map Scale'), wbFloat('Cell X Offset'), wbFloat('Cell Y Offset') ], cpNormal, True), wbFormIDCk(INAM, 'Image Space', [IMGS]), wbInteger(DATA, 'Flags', itU8, wbFlags([ // LoadForm supports a DWord here, but only first byte would be used. {0x01} 'Small World', {0x02} 'Can''t Fast Travel', {0x04} '', {0x08} '', {0x10} 'No LOD Water', {0x20} 'No LOD Noise', {0x40} 'Don''t Allow NPC Fall Damage', {0x80} 'Needs Water Adjustment' ]), cpNormal, True), wbRStruct('Object Bounds', [ wbStruct(NAM0, 'Min', [ wbFloat('X', cpNormal, False, 1/4096), wbFloat('Y', cpNormal, False, 1/4096) ], cpIgnore, True), wbStruct(NAM9, 'Max', [ wbFloat('X', cpNormal, False, 1/4096), wbFloat('Y', cpNormal, False, 1/4096) ], cpIgnore, True) ], []), wbFormIDCk(ZNAM, 'Music', [MUSC]), wbString(NNAM, 'Canopy Shadow', 0, cpNormal, True), wbString(XNAM, 'Water Noise Texture', 0, cpNormal, True), wbRArrayS('Swapped Impacts', wbStructExSK(IMPS, [0, 1], [2], 'Swapped Impact', [ wbInteger('Material Type', itU32, wbImpactMaterialTypeEnum), wbFormIDCkNoReach('Old', [IPCT]), wbFormIDCk('New', [IPCT, NULL]) ])), wbArray(IMPF, 'Footstep Materials', wbString('Unknown', 30), [ 'ConcSolid', 'ConcBroken', 'MetalSolid', 'MetalHollow', 'MetalSheet', 'Wood', 'Sand', 'Dirt', 'Grass', 'Water' ]), wbArray(OFST, 'Offset Data', wbArray('Rows', wbInteger('Offset', itU32), wbOffsetDataColsCounter), 0) // cannot be saved by GECK ], False, nil, cpNormal, False, wbRemoveOFST); wbRecord(WTHR, 'Weather', [ wbEDIDReq, wbFormIDCk(_0_IAD, 'Sunrise Image Space Modifier', [IMAD]), wbFormIDCk(_1_IAD, 'Day Image Space Modifier', [IMAD]), wbFormIDCk(_2_IAD, 'Sunset Image Space Modifier', [IMAD]), wbFormIDCk(_3_IAD, 'Night Image Space Modifier', [IMAD]), wbFormIDCk(_4_IAD, 'Unknown', [IMAD]), wbFormIDCk(_5_IAD, 'Unknown', [IMAD]), wbString(DNAM, 'Cloud Textures - Layer 0', 0, cpNormal, True), wbString(CNAM, 'Cloud Textures - Layer 1', 0, cpNormal, True), wbString(ANAM, 'Cloud Textures - Layer 2', 0, cpNormal, True), wbString(BNAM, 'Cloud Textures - Layer 3', 0, cpNormal, True), wbMODL, wbByteArray(LNAM, 'Unknown', 4, cpNormal, True), wbArray(ONAM, 'Cloud Speed', wbInteger('Layer', itU8{, wbDiv(2550)}), 4, nil, nil, cpNormal, True), wbArray(PNAM, 'Cloud Layer Colors', wbArray('Layer', wbStruct('Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), ['Sunrise', 'Day', 'Sunset', 'Night', 'High Noon', 'Midnight'] ), 4), wbArray(NAM0, 'Colors by Types/Times', wbArray('Type', wbStruct('Time', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), ['Sunrise', 'Day', 'Sunset', 'Night', 'High Noon', 'Midnight'] ), ['Sky-Upper','Fog','Unused','Ambient','Sunlight','Sun','Stars','Sky-Lower','Horizon','Unused'] , cpNormal, True), wbStruct(FNAM, 'Fog Distance', [ wbFloat('Day - Near'), wbFloat('Day - Far'), wbFloat('Night - Near'), wbFloat('Night - Far'), wbFloat('Day - Power'), wbFloat('Night - Fower') ], cpNormal, True), wbByteArray(INAM, 'Unused', 304, cpIgnore, True), wbStruct(DATA, '', [ wbInteger('Wind Speed', itU8), wbInteger('Cloud Speed (Lower)', itU8), wbInteger('Cloud Speed (Upper)', itU8), wbInteger('Trans Delta', itU8), wbInteger('Sun Glare', itU8), wbInteger('Sun Damage', itU8), wbInteger('Precipitation - Begin Fade In', itU8), wbInteger('Precipitation - End Fade Out', itU8), wbInteger('Thunder/Lightning - Begin Fade In', itU8), wbInteger('Thunder/Lightning - End Fade Out', itU8), wbInteger('Thunder/Lightning - Frequency', itU8), wbInteger('Weather Classification', itU8, wbWthrDataClassification), wbStruct('Lightning Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8) ]) ], cpNormal, True), wbRArray('Sounds', wbStruct(SNAM, 'Sound', [ wbFormIDCk('Sound', [SOUN]), wbInteger('Type', itU32, wbEnum([ {0}'Default', {1}'Precip', {2}'Wind', {3}'Thunder' ])) ])) ]); wbRecord(IMOD, 'Item Mod', [ wbEDIDReq, wbOBNDReq, wbFULL, wbMODL, wbICON, wbSCRI, wbDESC, wbDEST, wbYNAM, wbZNAM, wbStruct(DATA, 'Data', [ wbInteger('Value', itU32), wbFloat('Weight') ]) ]); wbRecord(ALOC, 'Media Location Controller', [ wbEDIDReq, wbFULL, wbByteArray(NAM1, 'Flags and Enums, messily combined'), wbUnknown(NAM2), wbUnknown(NAM3), wbFloat(NAM4, 'Location Delay'), wbInteger(NAM5, 'Day Start', itU32, wbAlocTime), wbInteger(NAM6, 'Night Start', itU32, wbAlocTime), wbFloat(NAM7, 'Retrigger Delay'), wbRArrayS('Neutral Sets', wbFormIDCk(HNAM, 'Media Set', [MSET]) ), wbRArrayS('Ally Sets', wbFormIDCk(ZNAM, 'Media Set', [MSET]) ), wbRArrayS('Friend Sets', wbFormIDCk(XNAM, 'Media Set', [MSET]) ), wbRArrayS('Enemy Sets', wbFormIDCk(YNAM, 'Media Set', [MSET]) ), wbRArrayS('Location Sets', wbFormIDCk(LNAM, 'Media Set', [MSET]) ), wbRArrayS('Battle Sets', wbFormIDCk(GNAM, 'Media Set', [MSET]) ), wbFormIDCk(RNAM, 'Conditional Faction', [FACT]), wbUnknown(FNAM) ]); wbRecord(MSET, 'Media Set', [ wbEDIDReq, wbFULL, wbInteger(NAM1, 'Type', itU32, wbEnum([ 'Battle Set', 'Location Set', 'Dungeon Set', 'Incidental Set' ], [ -1, 'No Set' ])), wbString(NAM2, 'Loop (B) / Battle (D) / Day Outer (L)'), wbString(NAM3, 'Explore (D) / Day Middle (L)'), wbString(NAM4, 'Suspense (D) / Day Inner (L)'), wbString(NAM5, 'Night Outer (L)'), wbString(NAM6, 'Night Middle (L)'), wbString(NAM7, 'Night Inner (L)'), wbFloat(NAM8, 'Loop dB (B) / Battle dB (D) / Day Outer dB (L)'), wbFloat(NAM9, 'Explore dB (D) / Day Middle dB (L)'), wbFloat(NAM0, 'Suspense dB (D) / Day Inner dB (L)'), wbFloat(ANAM, 'Night Outer dB (L)'), wbFloat(BNAM, 'Night Middle dB (L)'), wbFloat(CNAM, 'Night Inner dB (L)'), wbFloat(JNAM, 'Day Outer Boundary % (L)'), wbFloat(KNAM, 'Day Middle Boundary % (L)'), wbFloat(LNAM, 'Day Inner Boundary % (L)'), wbFloat(MNAM, 'Night Outer Boundary % (L)'), wbFloat(NNAM, 'Night Middle Boundary % (L)'), wbFloat(ONAM, 'Night Inner Boundary % (L)'), wbInteger(PNAM, 'Enable Flags', itU8, wbFlags([ {0x01} 'Day Outer', {0x02} 'Day Middle', {0x04} 'Day Inner', {0x08} 'Night Outer', {0x10} 'Night Middle', {0x20} 'Night Inner' ])), wbFloat(DNAM, 'Wait Time (B) / Minimum Time On (D,L) / Daytime Min (I)'), wbFloat(ENAM, 'Loop Fade Out (B) / Looping/Random Crossfade Overlap (D,L) / Nighttime Min (I)'), wbFloat(FNAM, 'Recovery Time (B) / Layer Crossfade Time (D,L) / Daytime Max (I)'), wbFloat(GNAM, 'Nighttime Max (I)'), wbFormIDCk(HNAM, 'Intro (B,D) / Daytime (I)', [SOUN]), wbFormIDCk(INAM, 'Outro (B,D) / Nighttime (I)', [SOUN]), wbUnknown(DATA) ]); wbRecord(AMEF, 'Ammo Effect', [ wbEDIDReq, wbFULL, wbStruct(DATA, 'Data', [ wbInteger('Type', itU32, wbEnum([ 'Damage Mod', 'DR Mod', 'DT Mod', 'Spread Mod', 'Weapon Condition Mod', 'Fatigue Mod' ])), wbInteger('Operation', itU32, wbEnum([ 'Add', 'Multiply', 'Subtract' ])), wbFloat('Value') ]) ]); wbRecord(CCRD, 'Caravan Card', [ wbEDIDReq, wbOBNDReq, wbFULL, wbMODL, wbICON, wbSCRI, wbYNAM, wbZNAM, wbRStruct('High Res Image', [ wbString(TX00, 'Face'), wbString(TX01, 'Back') ], []), wbRStruct('Card', [ wbInteger(INTV, 'Suit', itU32, wbEnum([ '', 'Hearts', 'Spades', 'Diamonds', 'Clubs', 'Joker' ])), wbInteger(INTV, 'Value', itU32, wbEnum([ '', 'Ace', '2', '3', '4', '5', '6', '7', '8', '9', '10', '', 'Jack', 'Queen', 'King', 'Joker' ])) ], []), wbInteger(DATA, 'Value', itU32) ]); wbRecord(CDCK, 'Caravan Deck', [ wbEDIDReq, wbFULL, wbRArrayS('Cards', wbFormIDCk(CARD, 'Card', [CCRD]) ), wbInteger(DATA, 'Count (broken)', itU32) ]); wbRecord(CHAL, 'Challenge', [ wbEDIDReq, wbFULL, wbICON, wbSCRI, wbDESC, wbStruct(DATA, 'Data', [ wbInteger('Type', itU32, wbEnum([ {00} 'Kill from a Form List', {01} 'Kill a specific FormID', {02} 'Kill any in a category', {03} 'Hit an Enemy', {04} 'Discover a Map Marker', {05} 'Use an Item', {06} 'Acquire an Item', {07} 'Use a Skill', {08} 'Do Damage', {09} 'Use an Item from a List', {10} 'Acquire an Item from a List', {11} 'Miscellaneous Stat', {12} 'Craft Using an Item', {13} 'Scripted Challenge' ])), wbInteger('Threshold', itU32), wbInteger('Flags', itU32, wbFlags([ 'Start Disabled', 'Recurring', 'Show Zero Progress' ])), wbInteger('Interval', itU32), wbByteArray('(depends on type)', 2), wbByteArray('(depends on type)', 2), wbByteArray('(depends on type)', 4) ]), wbFormID(SNAM, '(depends on type)'), wbFormID(XNAM, '(depends on type)') ]); wbRecord(CHIP, 'Casino Chip', [ wbEDIDReq, wbOBNDReq, wbFULL, wbMODL, wbICON, wbDEST, wbYNAM, wbZNAM ]); wbRecord(CMNY, 'Caravan Money', [ wbEDIDReq, wbOBNDReq, wbFULL, wbMODL, wbICON, wbYNAM, wbZNAM, wbInteger(DATA, 'Absolute Value', itU32) ]); wbRecord(CSNO, 'Casino', [ wbEDIDReq, wbFULL, wbStruct(DATA, 'Data', [ wbFloat('Decks % Before Shuffle'), wbFloat('BlackJack Payout Ratio'), wbArray('Slot Reel Stops', wbInteger('Reel', itU32),[ 'Symbol 1', 'Symbol 2', 'Symbol 3', 'Symbol 4', 'Symbol 5', 'Symbol 6', 'Symbol W' ]), wbInteger('Number of Decks', itU32), wbInteger('Max Winnings', itU32), wbFormIDCk('Currency', [CHIP]), wbFormIDCk('Casino Winnings Quest', [QUST]), wbInteger('Flags', itU32, wbFlags([ 'Dealer Stay on Soft 17' ])) ]), wbRStruct('Casino Chip Models', [ wbString(MODL, '$1 Chip'), wbString(MODL, '$5 Chip'), wbString(MODL, '$10 Chip'), wbString(MODL, '$25 Chip'), wbString(MODL, '$100 Chip'), wbString(MODL, '$500 Chip'), wbString(MODL, 'Roulette Chip') ], []), wbString(MODL, 'Slot Machine Model'), wbString(MOD2, 'Slot Machine Model (again?)'), wbString(MOD3, 'BlackJack Table Model'), wbString(MODT, 'BlackJack Table Model related'), wbString(MOD4, 'Roulette Table Model'), wbRStruct('Slot Reel Textures', [ wbString(ICON, 'Symbol 1'), wbString(ICON, 'Symbol 2'), wbString(ICON, 'Symbol 3'), wbString(ICON, 'Symbol 4'), wbString(ICON, 'Symbol 5'), wbString(ICON, 'Symbol 6'), wbString(ICON, 'Symbol W') ], []), wbRStruct('BlackJack Decks', [ wbString(ICO2, 'Deck 1'), wbString(ICO2, 'Deck 2'), wbString(ICO2, 'Deck 3'), wbString(ICO2, 'Deck 4') ], []) ]); wbRecord(DEHY, 'Dehydration Stage', [ wbEDIDReq, wbStruct(DATA, '', [ wbInteger('Trigger Threshold', itU32), wbFormIDCk('Actor Effect', [SPEL]) ], cpNormal, True) ]); wbRecord(HUNG, 'Hunger Stage', [ wbEDIDReq, wbStruct(DATA, '', [ wbInteger('Trigger Threshold', itU32), wbFormIDCk('Actor Effect', [SPEL]) ], cpNormal, True) ]); wbRecord(LSCT, 'Load Screen Type', [ wbEDIDReq, wbStruct(DATA, 'Data', [ wbInteger('Type', itU32, wbEnum([ 'None', 'XP Progress', 'Objective', 'Tip', 'Stats' ])), wbStruct('Data 1', [ wbInteger('X', itU32), wbInteger('Y', itU32), wbInteger('Width', itU32), wbInteger('Height', itU32), wbFloat('Orientation', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbInteger('Font', itU32, wbEnum([ '', '2', '3', '4', '5', '6', '7', '8' ])), wbStruct('Font Color', [ wbFloat('R'), wbFloat('G'), wbFloat('B') ]), wbInteger('Font', itU32, wbEnum([ '', 'Left', 'Center', '', 'Right' ])) ]), wbByteArray('Unknown', 20), wbStruct('Data 2', [ wbInteger('Font', itU32, wbEnum([ '', '2', '3', '4', '5', '6', '7', '8' ])), wbStruct('Font Color', [ wbFloat('R'), wbFloat('G'), wbFloat('B') ]), wbByteArray('', 4), wbInteger('Stats', itU32, wbEnum([ '', '2', '3', '4', '5', '6', '7', '8' ])) ]) ]) ]); wbRecord(RCCT, 'Recipe Category', [ wbEDIDReq, wbFULL, wbInteger(DATA, 'Flags', itU8, wbFlags([ 'Subcategory?', '', '', '', '', '', '', '' ])) ]); wbRecord(RCPE, 'Recipe', [ wbEDIDReq, wbFULL, wbCTDAs, wbStruct(DATA, 'Data', [ wbInteger('Skill', itS32, wbActorValueEnum), wbInteger('Level', itU32), wbFormIDCk('Category', [RCCT, NULL]), // Some of DeadMoney are NULL wbFormIDCk('Sub-Category', [RCCT]) ]), wbRStructs('Ingredients', 'Ingredient', [ wbFormIDCk(RCIL, 'Item', [ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, NOTE, IMOD, CMNY, CCRD, CHIP, LIGH], False, cpNormal, True), wbInteger(RCQY, 'Quantity', itU32, nil, cpNormal, True) ], []), wbRStructs('Outputs', 'Output', [ wbFormIDCk(RCOD, 'Item', [ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, NOTE, IMOD, CMNY, CCRD, CHIP, LIGH], False, cpNormal, True), wbInteger(RCQY, 'Quantity', itU32, nil, cpNormal, True) ], []) ]); wbRecord(REPU, 'Reputation', [ wbEDIDReq, wbFULL, wbICON, wbFloat(DATA, 'Value') ]); wbRecord(SLPD, 'Sleep Deprivation Stage', [ wbEDIDReq, wbStruct(DATA, '', [ wbInteger('Trigger Threshold', itU32), wbFormIDCk('Actor Effect', [SPEL]) ], cpNormal, True) ]); wbAddGroupOrder(GMST); wbAddGroupOrder(TXST); wbAddGroupOrder(MICN); wbAddGroupOrder(GLOB); wbAddGroupOrder(CLAS); wbAddGroupOrder(FACT); wbAddGroupOrder(HDPT); wbAddGroupOrder(HAIR); wbAddGroupOrder(EYES); wbAddGroupOrder(RACE); wbAddGroupOrder(SOUN); wbAddGroupOrder(ASPC); wbAddGroupOrder(MGEF); wbAddGroupOrder(SCPT); wbAddGroupOrder(LTEX); wbAddGroupOrder(ENCH); wbAddGroupOrder(SPEL); wbAddGroupOrder(ACTI); wbAddGroupOrder(TACT); wbAddGroupOrder(TERM); wbAddGroupOrder(ARMO); wbAddGroupOrder(BOOK); wbAddGroupOrder(CONT); wbAddGroupOrder(DOOR); wbAddGroupOrder(INGR); wbAddGroupOrder(LIGH); wbAddGroupOrder(MISC); wbAddGroupOrder(STAT); wbAddGroupOrder(SCOL); wbAddGroupOrder(MSTT); wbAddGroupOrder(PWAT); wbAddGroupOrder(GRAS); wbAddGroupOrder(TREE); wbAddGroupOrder(FURN); wbAddGroupOrder(WEAP); wbAddGroupOrder(AMMO); wbAddGroupOrder(NPC_); wbAddGroupOrder(CREA); wbAddGroupOrder(LVLC); wbAddGroupOrder(LVLN); wbAddGroupOrder(KEYM); wbAddGroupOrder(ALCH); wbAddGroupOrder(IDLM); wbAddGroupOrder(NOTE); wbAddGroupOrder(COBJ); wbAddGroupOrder(PROJ); wbAddGroupOrder(LVLI); wbAddGroupOrder(WTHR); wbAddGroupOrder(CLMT); wbAddGroupOrder(REGN); wbAddGroupOrder(NAVI); wbAddGroupOrder(DIAL); wbAddGroupOrder(QUST); wbAddGroupOrder(IDLE); wbAddGroupOrder(PACK); wbAddGroupOrder(CSTY); wbAddGroupOrder(LSCR); wbAddGroupOrder(ANIO); wbAddGroupOrder(WATR); wbAddGroupOrder(EFSH); wbAddGroupOrder(EXPL); wbAddGroupOrder(DEBR); wbAddGroupOrder(IMGS); wbAddGroupOrder(IMAD); wbAddGroupOrder(FLST); wbAddGroupOrder(PERK); wbAddGroupOrder(BPTD); wbAddGroupOrder(ADDN); wbAddGroupOrder(AVIF); wbAddGroupOrder(RADS); wbAddGroupOrder(CAMS); wbAddGroupOrder(CPTH); wbAddGroupOrder(VTYP); wbAddGroupOrder(IPCT); wbAddGroupOrder(IPDS); wbAddGroupOrder(ARMA); wbAddGroupOrder(ECZN); wbAddGroupOrder(MESG); wbAddGroupOrder(RGDL); wbAddGroupOrder(DOBJ); wbAddGroupOrder(LGTM); wbAddGroupOrder(MUSC); wbAddGroupOrder(IMOD); wbAddGroupOrder(REPU); wbAddGroupOrder(RCPE); wbAddGroupOrder(RCCT); wbAddGroupOrder(CHIP); wbAddGroupOrder(CSNO); wbAddGroupOrder(LSCT); wbAddGroupOrder(MSET); wbAddGroupOrder(ALOC); wbAddGroupOrder(CHAL); wbAddGroupOrder(AMEF); wbAddGroupOrder(CCRD); wbAddGroupOrder(CMNY); wbAddGroupOrder(CDCK); wbAddGroupOrder(DEHY); wbAddGroupOrder(HUNG); wbAddGroupOrder(SLPD); // Forced at the end. wbAddGroupOrder(CELL); wbAddGroupOrder(WRLD); end; procedure DefineFNV; begin DefineFNVa; DefineFNVb; DefineFNVc; DefineFNVd; DefineFNVe; DefineFNVf; end; end. ================================================ FILE: lib/xedit/wbDefinitionsFO3.pas ================================================ {******************************************************************************* The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. *******************************************************************************} unit wbDefinitionsFO3; {$I wbDefines.inc} interface uses wbInterface; var wbAggroRadiusFlags: IwbFlagsDef; wbPKDTFlags: IwbFlagsDef; wbRecordFlagsFlags: IwbFlagsDef; wbServiceFlags: IwbFlagsDef; wbTemplateFlags: IwbFlagsDef; wbAgressionEnum: IwbEnumDef; wbAlignmentEnum: IwbEnumDef; wbArchtypeEnum: IwbEnumDef; wbAssistanceEnum: IwbEnumDef; wbAttackAnimationEnum: IwbEnumDef; wbAxisEnum: IwbEnumDef; wbBlendModeEnum: IwbEnumDef; wbBlendOpEnum: IwbEnumDef; wbBodyLocationEnum: IwbEnumDef; wbBodyPartIndexEnum: IwbEnumDef; wbConfidenceEnum: IwbEnumDef; wbCreatureTypeEnum: IwbEnumDef; wbCrimeTypeEnum: IwbEnumDef; wbCriticalStageEnum: IwbEnumDef; wbEquipTypeEnum: IwbEnumDef; wbFormTypeEnum: IwbEnumDef; wbFunctionsEnum: IwbEnumDef; wbHeadPartIndexEnum: IwbEnumDef; wbImpactMaterialTypeEnum: IwbEnumDef; wbMenuModeEnum: IwbEnumDef; wbMiscStatEnum: IwbEnumDef; wbModEffectEnum: IwbEnumDef; wbMoodEnum: IwbEnumDef; wbMusicEnum: IwbEnumDef; wbObjectTypeEnum: IwbEnumDef; wbPKDTType: IwbEnumDef; wbPlayerActionEnum: IwbEnumDef; wbQuadrantEnum: IwbEnumDef; wbReloadAnimEnum: IwbEnumDef; wbSexEnum: IwbEnumDef; wbSkillEnum: IwbEnumDef; wbSoundLevelEnum: IwbEnumDef; wbSpecializationEnum: IwbEnumDef; wbVatsValueFunctionEnum: IwbEnumDef; wbWeaponAnimTypeEnum: IwbEnumDef; wbZTestFuncEnum: IwbEnumDef; procedure DefineFO3; implementation uses Types, Classes, SysUtils, Math, Variants, wbHelpers; const _00_IAD: TwbSignature = #$00'IAD'; _40_IAD: TwbSignature = #$40'IAD'; _01_IAD: TwbSignature = #$01'IAD'; _41_IAD: TwbSignature = #$41'IAD'; _02_IAD: TwbSignature = #$02'IAD'; _42_IAD: TwbSignature = #$42'IAD'; _03_IAD: TwbSignature = #$03'IAD'; _43_IAD: TwbSignature = #$43'IAD'; _04_IAD: TwbSignature = #$04'IAD'; _44_IAD: TwbSignature = #$44'IAD'; _05_IAD: TwbSignature = #$05'IAD'; _45_IAD: TwbSignature = #$45'IAD'; _06_IAD: TwbSignature = #$06'IAD'; _46_IAD: TwbSignature = #$46'IAD'; _07_IAD: TwbSignature = #$07'IAD'; _47_IAD: TwbSignature = #$47'IAD'; _08_IAD: TwbSignature = #$08'IAD'; _48_IAD: TwbSignature = #$48'IAD'; _09_IAD: TwbSignature = #$09'IAD'; _49_IAD: TwbSignature = #$49'IAD'; _0A_IAD: TwbSignature = #$0A'IAD'; _4A_IAD: TwbSignature = #$4A'IAD'; _0B_IAD: TwbSignature = #$0B'IAD'; _4B_IAD: TwbSignature = #$4B'IAD'; _0C_IAD: TwbSignature = #$0C'IAD'; _4C_IAD: TwbSignature = #$4C'IAD'; _0D_IAD: TwbSignature = #$0D'IAD'; _4D_IAD: TwbSignature = #$4D'IAD'; _0E_IAD: TwbSignature = #$0E'IAD'; _4E_IAD: TwbSignature = #$4E'IAD'; _0F_IAD: TwbSignature = #$0F'IAD'; _4F_IAD: TwbSignature = #$4F'IAD'; _10_IAD: TwbSignature = #$10'IAD'; _50_IAD: TwbSignature = #$50'IAD'; _11_IAD: TwbSignature = #$11'IAD'; _51_IAD: TwbSignature = #$51'IAD'; _12_IAD: TwbSignature = #$12'IAD'; _52_IAD: TwbSignature = #$52'IAD'; _13_IAD: TwbSignature = #$13'IAD'; _53_IAD: TwbSignature = #$53'IAD'; _14_IAD: TwbSignature = #$14'IAD'; _54_IAD: TwbSignature = #$54'IAD'; _0_IAD : TwbSignature = #0'IAD'; _1_IAD : TwbSignature = #1'IAD'; _2_IAD : TwbSignature = #2'IAD'; _3_IAD : TwbSignature = #3'IAD'; ACBS : TwbSignature = 'ACBS'; ACHR : TwbSignature = 'ACHR'; ACRE : TwbSignature = 'ACRE'; ACTI : TwbSignature = 'ACTI'; ADDN : TwbSignature = 'ADDN'; AIDT : TwbSignature = 'AIDT'; ALCH : TwbSignature = 'ALCH'; AMMO : TwbSignature = 'AMMO'; ANAM : TwbSignature = 'ANAM'; ANIO : TwbSignature = 'ANIO'; ARMA : TwbSignature = 'ARMA'; ARMO : TwbSignature = 'ARMO'; ASPC : TwbSignature = 'ASPC'; ATTR : TwbSignature = 'ATTR'; ATXT : TwbSignature = 'ATXT'; AVIF : TwbSignature = 'AVIF'; BIPL : TwbSignature = 'BIPL'; BMCT : TwbSignature = 'BMCT'; BMDT : TwbSignature = 'BMDT'; BNAM : TwbSignature = 'BNAM'; BOOK : TwbSignature = 'BOOK'; BPND : TwbSignature = 'BPND'; BPNI : TwbSignature = 'BPNI'; BPNN : TwbSignature = 'BPNN'; BPNT : TwbSignature = 'BPNT'; BPTD : TwbSignature = 'BPTD'; BPTN : TwbSignature = 'BPTN'; BTXT : TwbSignature = 'BTXT'; CAMS : TwbSignature = 'CAMS'; CELL : TwbSignature = 'CELL'; CLAS : TwbSignature = 'CLAS'; CLMT : TwbSignature = 'CLMT'; CNAM : TwbSignature = 'CNAM'; CNTO : TwbSignature = 'CNTO'; COBJ : TwbSignature = 'COBJ'; COED : TwbSignature = 'COED'; CONT : TwbSignature = 'CONT'; CPTH : TwbSignature = 'CPTH'; CRDT : TwbSignature = 'CRDT'; CREA : TwbSignature = 'CREA'; CSAD : TwbSignature = 'CSAD'; CSCR : TwbSignature = 'CSCR'; CSDC : TwbSignature = 'CSDC'; CSDI : TwbSignature = 'CSDI'; CSDT : TwbSignature = 'CSDT'; CSSD : TwbSignature = 'CSSD'; CSTD : TwbSignature = 'CSTD'; CSTY : TwbSignature = 'CSTY'; CTDA : TwbSignature = 'CTDA'; DATA : TwbSignature = 'DATA'; DEBR : TwbSignature = 'DEBR'; DELE : TwbSignature = 'DELE'; DESC : TwbSignature = 'DESC'; DEST : TwbSignature = 'DEST'; DIAL : TwbSignature = 'DIAL'; DMDL : TwbSignature = 'DMDL'; DMDT : TwbSignature = 'DMDT'; DNAM : TwbSignature = 'DNAM'; DOBJ : TwbSignature = 'DOBJ'; DODT : TwbSignature = 'DODT'; DOOR : TwbSignature = 'DOOR'; DSTD : TwbSignature = 'DSTD'; DSTF : TwbSignature = 'DSTF'; EAMT : TwbSignature = 'EAMT'; ECZN : TwbSignature = 'ECZN'; EDID : TwbSignature = 'EDID'; EFID : TwbSignature = 'EFID'; EFIT : TwbSignature = 'EFIT'; EFSD : TwbSignature = 'EFSD'; EFSH : TwbSignature = 'EFSH'; EITM : TwbSignature = 'EITM'; ENAM : TwbSignature = 'ENAM'; ENCH : TwbSignature = 'ENCH'; ENIT : TwbSignature = 'ENIT'; EPF2 : TwbSignature = 'EPF2'; EPF3 : TwbSignature = 'EPF3'; EPFD : TwbSignature = 'EPFD'; EPFT : TwbSignature = 'EPFT'; ESCE : TwbSignature = 'ESCE'; ETYP : TwbSignature = 'ETYP'; EXPL : TwbSignature = 'EXPL'; EYES : TwbSignature = 'EYES'; FACT : TwbSignature = 'FACT'; FGGA : TwbSignature = 'FGGA'; FGGS : TwbSignature = 'FGGS'; FGTS : TwbSignature = 'FGTS'; FLST : TwbSignature = 'FLST'; FLTV : TwbSignature = 'FLTV'; FNAM : TwbSignature = 'FNAM'; FULL : TwbSignature = 'FULL'; FURN : TwbSignature = 'FURN'; GLOB : TwbSignature = 'GLOB'; GMST : TwbSignature = 'GMST'; GNAM : TwbSignature = 'GNAM'; GRAS : TwbSignature = 'GRAS'; HAIR : TwbSignature = 'HAIR'; HCLR : TwbSignature = 'HCLR'; HDPT : TwbSignature = 'HDPT'; HEDR : TwbSignature = 'HEDR'; HNAM : TwbSignature = 'HNAM'; ICO2 : TwbSignature = 'ICO2'; ICON : TwbSignature = 'ICON'; IDLA : TwbSignature = 'IDLA'; IDLB : TwbSignature = 'IDLB'; IDLC : TwbSignature = 'IDLC'; IDLE : TwbSignature = 'IDLE'; IDLF : TwbSignature = 'IDLF'; IDLM : TwbSignature = 'IDLM'; IDLT : TwbSignature = 'IDLT'; IMAD : TwbSignature = 'IMAD'; IMGS : TwbSignature = 'IMGS'; INAM : TwbSignature = 'INAM'; INDX : TwbSignature = 'INDX'; INFO : TwbSignature = 'INFO'; INGR : TwbSignature = 'INGR'; IPCT : TwbSignature = 'IPCT'; IPDS : TwbSignature = 'IPDS'; ITXT : TwbSignature = 'ITXT'; JNAM : TwbSignature = 'JNAM'; KEYM : TwbSignature = 'KEYM'; KFFZ : TwbSignature = 'KFFZ'; KNAM : TwbSignature = 'KNAM'; LAND : TwbSignature = 'LAND'; LGTM : TwbSignature = 'LGTM'; LIGH : TwbSignature = 'LIGH'; LNAM : TwbSignature = 'LNAM'; LSCR : TwbSignature = 'LSCR'; LTEX : TwbSignature = 'LTEX'; LTMP : TwbSignature = 'LTMP'; LVLC : TwbSignature = 'LVLC'; LVLD : TwbSignature = 'LVLD'; LVLF : TwbSignature = 'LVLF'; LVLG : TwbSignature = 'LVLG'; LVLI : TwbSignature = 'LVLI'; LVLN : TwbSignature = 'LVLN'; LVLO : TwbSignature = 'LVLO'; MAST : TwbSignature = 'MAST'; MESG : TwbSignature = 'MESG'; MGEF : TwbSignature = 'MGEF'; MICN : TwbSignature = 'MICN'; MICO : TwbSignature = 'MICO'; MIC2 : TwbSignature = 'MIC2'; MISC : TwbSignature = 'MISC'; MNAM : TwbSignature = 'MNAM'; MO2B : TwbSignature = 'MO2B'; MO2S : TwbSignature = 'MO2S'; MO2T : TwbSignature = 'MO2T'; MO3B : TwbSignature = 'MO3B'; MO3S : TwbSignature = 'MO3S'; MO3T : TwbSignature = 'MO3T'; MO4B : TwbSignature = 'MO4B'; MO4S : TwbSignature = 'MO4S'; MO4T : TwbSignature = 'MO4T'; MOD2 : TwbSignature = 'MOD2'; MOD3 : TwbSignature = 'MOD3'; MOD4 : TwbSignature = 'MOD4'; MODB : TwbSignature = 'MODB'; MODD : TwbSignature = 'MODD'; MODL : TwbSignature = 'MODL'; MODS : TwbSignature = 'MODS'; MODT : TwbSignature = 'MODT'; MOSD : TwbSignature = 'MOSD'; MSTT : TwbSignature = 'MSTT'; MUSC : TwbSignature = 'MUSC'; IMPS : TwbSignature = 'IMPS'; IMPF : TwbSignature = 'IMPF'; NAM0 : TwbSignature = 'NAM0'; NAM1 : TwbSignature = 'NAM1'; NAM2 : TwbSignature = 'NAM2'; NAM3 : TwbSignature = 'NAM3'; NAM4 : TwbSignature = 'NAM4'; NAM5 : TwbSignature = 'NAM5'; NAM6 : TwbSignature = 'NAM6'; NAM7 : TwbSignature = 'NAM7'; NAM8 : TwbSignature = 'NAM8'; NAM9 : TwbSignature = 'NAM9'; NAME : TwbSignature = 'NAME'; NAVI : TwbSignature = 'NAVI'; NAVM : TwbSignature = 'NAVM'; NEXT : TwbSignature = 'NEXT'; NIFT : TwbSignature = 'NIFT'; NIFZ : TwbSignature = 'NIFZ'; NNAM : TwbSignature = 'NNAM'; NOTE : TwbSignature = 'NOTE'; NPC_ : TwbSignature = 'NPC_'; NULL : TwbSignature = 'NULL'; NVCA : TwbSignature = 'NVCA'; NVCI : TwbSignature = 'NVCI'; NVDP : TwbSignature = 'NVDP'; NVER : TwbSignature = 'NVER'; NVEX : TwbSignature = 'NVEX'; NVGD : TwbSignature = 'NVGD'; NVMI : TwbSignature = 'NVMI'; NVTR : TwbSignature = 'NVTR'; NVVX : TwbSignature = 'NVVX'; OBND : TwbSignature = 'OBND'; OFST : TwbSignature = 'OFST'; ONAM : TwbSignature = 'ONAM'; PACK : TwbSignature = 'PACK'; PBEA : TwbSignature = 'PBEA'; PERK : TwbSignature = 'PERK'; PFIG : TwbSignature = 'PFIG'; PFPC : TwbSignature = 'PFPC'; PGAG : TwbSignature = 'PGAG'; PGRE : TwbSignature = 'PGRE'; PMIS : TwbSignature = 'PMIS'; TRGT : TwbSignature = 'TRGT'; PGRI : TwbSignature = 'PGRI'; PGRL : TwbSignature = 'PGRL'; PGRP : TwbSignature = 'PGRP'; PGRR : TwbSignature = 'PGRR'; PKAM : TwbSignature = 'PKAM'; PKDD : TwbSignature = 'PKDD'; PKDT : TwbSignature = 'PKDT'; PKE2 : TwbSignature = 'PKE2'; PKED : TwbSignature = 'PKED'; PKFD : TwbSignature = 'PKFD'; PKID : TwbSignature = 'PKID'; PKPT : TwbSignature = 'PKPT'; PKW3 : TwbSignature = 'PKW3'; PLD2 : TwbSignature = 'PLD2'; PLDT : TwbSignature = 'PLDT'; PLYR : TwbSignature = 'PLYR'; PNAM : TwbSignature = 'PNAM'; POBA : TwbSignature = 'POBA'; POCA : TwbSignature = 'POCA'; POEA : TwbSignature = 'POEA'; PRKC : TwbSignature = 'PRKC'; PRKE : TwbSignature = 'PRKE'; PRKF : TwbSignature = 'PRKF'; PROJ : TwbSignature = 'PROJ'; PSDT : TwbSignature = 'PSDT'; PTD2 : TwbSignature = 'PTD2'; PTDT : TwbSignature = 'PTDT'; PUID : TwbSignature = 'PUID'; PWAT : TwbSignature = 'PWAT'; QNAM : TwbSignature = 'QNAM'; QOBJ : TwbSignature = 'QOBJ'; QSDT : TwbSignature = 'QSDT'; QSTA : TwbSignature = 'QSTA'; QSTI : TwbSignature = 'QSTI'; TPIC : TwbSignature = 'TPIC'; QSTR : TwbSignature = 'QSTR'; QUST : TwbSignature = 'QUST'; RACE : TwbSignature = 'RACE'; RADS : TwbSignature = 'RADS'; RAFB : TwbSignature = 'RAFB'; RAFD : TwbSignature = 'RAFD'; RAGA : TwbSignature = 'RAGA'; RAPS : TwbSignature = 'RAPS'; RCLR : TwbSignature = 'RCLR'; RDAT : TwbSignature = 'RDAT'; RDMD : TwbSignature = 'RDMD'; RDMO : TwbSignature = 'RDMO'; RDMP : TwbSignature = 'RDMP'; RDGS : TwbSignature = 'RDGS'; RDOT : TwbSignature = 'RDOT'; RDSD : TwbSignature = 'RDSD'; RDWT : TwbSignature = 'RDWT'; REFR : TwbSignature = 'REFR'; REGN : TwbSignature = 'REGN'; REPL : TwbSignature = 'REPL'; RGDL : TwbSignature = 'RGDL'; RNAM : TwbSignature = 'RNAM'; RPLD : TwbSignature = 'RPLD'; RPLI : TwbSignature = 'RPLI'; SCDA : TwbSignature = 'SCDA'; SCHR : TwbSignature = 'SCHR'; SCOL : TwbSignature = 'SCOL'; SCPT : TwbSignature = 'SCPT'; SCRI : TwbSignature = 'SCRI'; SCRN : TwbSignature = 'SCRN'; SCRO : TwbSignature = 'SCRO'; SCRV : TwbSignature = 'SCRV'; SCTX : TwbSignature = 'SCTX'; SCVR : TwbSignature = 'SCVR'; SLCP : TwbSignature = 'SLCP'; SLSD : TwbSignature = 'SLSD'; SNAM : TwbSignature = 'SNAM'; SNDD : TwbSignature = 'SNDD'; SNDX : TwbSignature = 'SNDX'; SOUL : TwbSignature = 'SOUL'; SOUN : TwbSignature = 'SOUN'; SPEL : TwbSignature = 'SPEL'; SPIT : TwbSignature = 'SPIT'; SPLO : TwbSignature = 'SPLO'; STAT : TwbSignature = 'STAT'; TACT : TwbSignature = 'TACT'; TCLF : TwbSignature = 'TCLF'; TCLT : TwbSignature = 'TCLT'; TERM : TwbSignature = 'TERM'; TES4 : TwbSignature = 'TES4'; TNAM : TwbSignature = 'TNAM'; TPLT : TwbSignature = 'TPLT'; TRDT : TwbSignature = 'TRDT'; TREE : TwbSignature = 'TREE'; TX00 : TwbSignature = 'TX00'; TX01 : TwbSignature = 'TX01'; TX02 : TwbSignature = 'TX02'; TX03 : TwbSignature = 'TX03'; TX04 : TwbSignature = 'TX04'; TX05 : TwbSignature = 'TX05'; TXST : TwbSignature = 'TXST'; UNAM : TwbSignature = 'UNAM'; VCLR : TwbSignature = 'VCLR'; VHGT : TwbSignature = 'VHGT'; VNAM : TwbSignature = 'VNAM'; VNML : TwbSignature = 'VNML'; VTCK : TwbSignature = 'VTCK'; VTEX : TwbSignature = 'VTEX'; VTXT : TwbSignature = 'VTXT'; VTYP : TwbSignature = 'VTYP'; WATR : TwbSignature = 'WATR'; WEAP : TwbSignature = 'WEAP'; WLST : TwbSignature = 'WLST'; WNAM : TwbSignature = 'WNAM'; WRLD : TwbSignature = 'WRLD'; WTHR : TwbSignature = 'WTHR'; XACT : TwbSignature = 'XACT'; XAMC : TwbSignature = 'XAMC'; XAMT : TwbSignature = 'XAMT'; XAPD : TwbSignature = 'XAPD'; XAPR : TwbSignature = 'XAPR'; XCAS : TwbSignature = 'XCAS'; XCCM : TwbSignature = 'XCCM'; XCET : TwbSignature = 'XCET'; XCHG : TwbSignature = 'XCHG'; XCIM : TwbSignature = 'XCIM'; XCLC : TwbSignature = 'XCLC'; XCLL : TwbSignature = 'XCLL'; XCLP : TwbSignature = 'XCLP'; XCLR : TwbSignature = 'XCLR'; XCLW : TwbSignature = 'XCLW'; XCMO : TwbSignature = 'XCMO'; XCMT : TwbSignature = 'XCMT'; XCNT : TwbSignature = 'XCNT'; XCWT : TwbSignature = 'XCWT'; XEMI : TwbSignature = 'XEMI'; XESP : TwbSignature = 'XESP'; XEZN : TwbSignature = 'XEZN'; XGLB : TwbSignature = 'XGLB'; XHLP : TwbSignature = 'XHLP'; XDCR : TwbSignature = 'XDCR'; XHLT : TwbSignature = 'XHLT'; XIBS : TwbSignature = 'XIBS'; XLCM : TwbSignature = 'XLCM'; XLKR : TwbSignature = 'XLKR'; XLOC : TwbSignature = 'XLOC'; XLOD : TwbSignature = 'XLOD'; XLRM : TwbSignature = 'XLRM'; XLTW : TwbSignature = 'XLTW'; XMBO : TwbSignature = 'XMBO'; XMBP : TwbSignature = 'XMBP'; XMBR : TwbSignature = 'XMBR'; XMRC : TwbSignature = 'XMRC'; XMRK : TwbSignature = 'XMRK'; XNAM : TwbSignature = 'XNAM'; XNDP : TwbSignature = 'XNDP'; XOCP : TwbSignature = 'XOCP'; XORD : TwbSignature = 'XORD'; XOWN : TwbSignature = 'XOWN'; XPOD : TwbSignature = 'XPOD'; XPTL : TwbSignature = 'XPTL'; XPPA : TwbSignature = 'XPPA'; XPRD : TwbSignature = 'XPRD'; XPRM : TwbSignature = 'XPRM'; XPWR : TwbSignature = 'XPWR'; XRAD : TwbSignature = 'XRAD'; XRDO : TwbSignature = 'XRDO'; XRDS : TwbSignature = 'XRDS'; XRGB : TwbSignature = 'XRGB'; XRGD : TwbSignature = 'XRGD'; XRMR : TwbSignature = 'XRMR'; XRNK : TwbSignature = 'XRNK'; XRTM : TwbSignature = 'XRTM'; XSCL : TwbSignature = 'XSCL'; XSED : TwbSignature = 'XSED'; XSRF : TwbSignature = 'XSRF'; XSRD : TwbSignature = 'XSRD'; XTEL : TwbSignature = 'XTEL'; XTRG : TwbSignature = 'XTRG'; XTRI : TwbSignature = 'XTRI'; XXXX : TwbSignature = 'XXXX'; YNAM : TwbSignature = 'YNAM'; ZNAM : TwbSignature = 'ZNAM'; var wbPKDTSpecificFlagsUnused : Boolean; wbEDID: IwbSubRecordDef; wbEDIDReq: IwbSubRecordDef; wbBMDT: IwbSubRecordDef; wbYNAM: IwbSubRecordDef; wbZNAM: IwbSubRecordDef; wbCOED: IwbSubRecordDef; wbXLCM: IwbSubRecordDef; wbEITM: IwbSubRecordDef; wbREPL: IwbSubRecordDef; wbBIPL: IwbSubRecordDef; wbOBND: IwbSubRecordDef; wbOBNDReq: IwbSubRecordDef; wbDEST: IwbSubRecordStructDef; wbDESTActor: IwbSubRecordStructDef; wbDODT: IwbSubRecordDef; wbXOWN: IwbSubRecordDef; wbXGLB: IwbSubRecordDef; wbXRGD: IwbSubRecordDef; wbXRGB: IwbSubRecordDef; wbSLSD: IwbSubRecordDef; wbSPLO: IwbSubRecordDef; wbSPLOs: IwbSubRecordArrayDef; wbCNTO: IwbSubRecordStructDef; wbCNTOs: IwbSubRecordArrayDef; wbAIDT: IwbSubRecordDef; wbCSDT: IwbSubRecordStructDef; wbCSDTs: IwbSubRecordArrayDef; wbFULL: IwbSubRecordDef; wbFULLActor: IwbSubRecordDef; wbFULLReq: IwbSubRecordDef; wbXNAM: IwbSubRecordDef; wbXNAMs: IwbSubRecordArrayDef; wbDESC: IwbSubRecordDef; wbDESCReq: IwbSubRecordDef; wbXSCL: IwbSubRecordDef; wbDATAPosRot : IwbSubRecordDef; wbPosRot : IwbStructDef; wbMODD: IwbSubRecordDef; wbMOSD: IwbSubRecordDef; wbMODL: IwbSubRecordStructDef; wbMODS: IwbSubRecordDef; wbMO2S: IwbSubRecordDef; wbMO3S: IwbSubRecordDef; wbMO4S: IwbSubRecordDef; wbMODLActor: IwbSubRecordStructDef; wbMODLReq: IwbSubRecordStructDef; wbCTDA: IwbSubRecordDef; wbSCHRReq: IwbSubRecordDef; wbCTDAs: IwbSubRecordArrayDef; wbCTDAsReq: IwbSubRecordArrayDef; wbSCROs: IwbSubRecordArrayDef; wbPGRP: IwbSubRecordDef; wbEmbeddedScript: IwbSubRecordStructDef; wbEmbeddedScriptPerk: IwbSubRecordStructDef; wbEmbeddedScriptReq: IwbSubRecordStructDef; wbSCRI: IwbSubRecordDef; wbSCRIActor: IwbSubRecordDef; wbFaceGen: IwbSubRecordStructDef; wbFaceGenNPC: IwbSubRecordStructDef; wbENAM: IwbSubRecordDef; wbFGGS: IwbSubRecordDef; wbXLOD: IwbSubRecordDef; wbXESP: IwbSubRecordDef; wbICON: IwbSubRecordStructDef; wbICONReq: IwbSubRecordStructDef; wbActorValue: IwbIntegerDef; wbETYP: IwbSubRecordDef; wbETYPReq: IwbSubRecordDef; wbEFID: IwbSubRecordDef; wbEFIT: IwbSubRecordDef; wbEffects: IwbSubRecordArrayDef; wbEffectsReq: IwbSubRecordArrayDef; wbBPNDStruct: IwbSubRecordDef; wbTimeInterpolator: IwbStructDef; wbColorInterpolator: IwbStructDef; function wbNVTREdgeToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Index : Integer; Flags : Cardinal; IsExternal : Boolean; Container : IwbContainerElementRef; begin Result := ''; IsExternal := False; if Supports(aElement, IwbContainerElementRef, Container) then begin Index := StrToIntDef(Copy(Container.Name, 11, 1), -1); if (Index >= 0) and (Index <= 2) then begin Flags := Container.ElementNativeValues['..\..\Flags']; IsExternal := Flags and (Cardinal(1) shl Index) <> 0; end; end; if IsExternal then begin case aType of ctToStr: begin Result := IntToStr(aInt); if Container.ElementExists['..\..\..\..\NVEX\Connection #' + IntToStr(aInt)] then Result := Result + ' (Triangle #' + Container.ElementValues['..\..\..\..\NVEX\Connection #' + IntToStr(aInt) + '\Triangle'] + ' in ' + Container.ElementValues['..\..\..\..\NVEX\Connection #' + IntToStr(aInt) + '\Navigation Mesh'] + ')' else Result := Result + ' '; end; ctToSortKey: if Container.ElementExists['..\..\..\..\NVEX\Connection #' + IntToStr(aInt)] then Result := Container.ElementSortKeys['..\..\..\..\NVEX\Connection #' + IntToStr(aInt) + '\Navigation Mesh', True] + '|' + Container.ElementSortKeys['..\..\..\..\NVEX\Connection #' + IntToStr(aInt) + '\Triangle', True]; ctCheck: if Container.ElementExists['..\..\..\..\NVEX\Connection #' + IntToStr(aInt)] then Result := '' else Result := 'NVEX\Connection #' + IntToStr(aInt) + ' is missing'; end end else case aType of ctToStr: Result := IntToStr(aInt); end; end; function wbNVTREdgeToInt(const aString: string; const aElement: IwbElement): Int64; begin Result := StrToInt64(aString); end; function wbEPFDActorValueToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var AsCardinal : Cardinal; AsFloat : Single; begin AsCardinal := aInt; AsFloat := PSingle(@AsCardinal)^; aInt := Round(AsFloat); case aType of ctToStr: Result := wbActorValueEnum.ToString(aInt, aElement); ctToSortKey: Result := wbActorValueEnum.ToSortKey(aInt, aElement); ctCheck: Result := wbActorValueEnum.Check(aInt, aElement); ctToEditValue: Result := wbActorValueEnum.ToEditValue(aInt, aElement); ctEditType: Result := 'ComboBox'; ctEditInfo: Result := wbActorValueEnum.EditInfo[aInt, aElement]; end; end; function wbEPFDActorValueToInt(const aString: string; const aElement: IwbElement): Int64; var AsCardinal : Cardinal; AsFloat : Single; begin AsFloat := wbActorValueEnum.FromEditValue(aString, aElement); PSingle(@AsCardinal)^ := AsFloat; Result := AsCardinal; end; function wbCTDAParam2VariableNameToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainerElementRef; //Container2 : IwbContainerElementRef; Param1 : IwbElement; MainRecord : IwbMainRecord; BaseRecord : IwbMainRecord; ScriptRef : IwbElement; Script : IwbMainRecord; Variables : TStringList; LocalVars : IwbContainerElementRef; LocalVar : IwbContainerElementRef; i, j : Integer; s : string; begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctToEditValue: Result := IntToStr(aInt); ctToSortKey: begin Result := IntToHex64(aInt, 8); Exit; end; ctCheck: Result := ''; ctEditType: Result := ''; ctEditInfo: Result := ''; end; if not Assigned(aElement) then Exit; Container := GetContainerRefFromUnionOrValue(aElement); if not Assigned(Container) then Exit; Param1 := Container.ElementByName['Parameter #1']; if not Assigned(Param1) then Exit; MainRecord := nil; if not Supports(Param1.LinksTo, IwbMainRecord, MainRecord) then Exit; { if Param1.NativeValue = 0 then if Supports(Container.Container, IwbContainerElementRef, Container) then for i := 0 to Pred(Container.ElementCount) do if Supports(Container.Elements[i], IwbContainerElementRef, Container2) then if SameText(Container2.ElementValues['Function'], 'GetIsID') then begin Param1 := Container2.ElementByName['Parameter #1']; if Supports(Param1.LinksTo, IwbMainRecord, MainRecord) then Break; end;} if not Assigned(MainRecord) then Exit; BaseRecord := MainRecord.BaseRecord; if Assigned(BaseRecord) then MainRecord := BaseRecord; ScriptRef := MainRecord.RecordBySignature['SCRI']; if not Assigned(ScriptRef) then begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end; Exit; end; if not Supports(ScriptRef.LinksTo, IwbMainRecord, Script) then begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end; Exit; end; Script := Script.HighestOverrideOrSelf[aElement._File.LoadOrder]; case aType of ctEditType: begin Result := 'ComboBox'; Exit; end; ctEditInfo: Variables := TStringList.Create; else Variables := nil; end; try if Supports(Script.ElementByName['Local Variables'], IwbContainerElementRef, LocalVars) then begin for i := 0 to Pred(LocalVars.ElementCount) do if Supports(LocalVars.Elements[i], IwbContainerElementRef, LocalVar) then begin j := LocalVar.ElementNativeValues['SLSD\Index']; s := LocalVar.ElementNativeValues['SCVR']; if Assigned(Variables) then Variables.AddObject(s, TObject(j)) else if j = aInt then begin case aType of ctToStr, ctToEditValue: Result := s; ctCheck: Result := ''; end; Exit; end; end; end; case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; ctEditInfo: begin Variables.Sort; Result := Variables.CommaText; end; end; finally FreeAndNil(Variables); end; end; function wbCTDAParam2VariableNameToInt(const aString: string; const aElement: IwbElement): Int64; var Container : IwbContainerElementRef; Param1 : IwbElement; MainRecord : IwbMainRecord; BaseRecord : IwbMainRecord; ScriptRef : IwbElement; Script : IwbMainRecord; LocalVars : IwbContainerElementRef; LocalVar : IwbContainerElementRef; i, j : Integer; s : string; begin Result := StrToInt64Def(aString, Low(Cardinal)); if Result <> Low(Cardinal) then Exit; if not Assigned(aElement) then raise Exception.Create('aElement not specified'); Container := GetContainerRefFromUnionOrValue(aElement); if not Assigned(Container) then raise Exception.Create('Container not assigned'); Param1 := Container.ElementByName['Parameter #1']; if not Assigned(Param1) then raise Exception.Create('Could not find "Parameter #1"'); if not Supports(Param1.LinksTo, IwbMainRecord, MainRecord) then raise Exception.Create('"Parameter #1" does not reference a valid main record'); BaseRecord := MainRecord.BaseRecord; if Assigned(BaseRecord) then MainRecord := BaseRecord; ScriptRef := MainRecord.RecordBySignature['SCRI']; if not Assigned(ScriptRef) then raise Exception.Create('"'+MainRecord.ShortName+'" does not contain a SCRI subrecord'); if not Supports(ScriptRef.LinksTo, IwbMainRecord, Script) then raise Exception.Create('"'+MainRecord.ShortName+'" does not have a valid script'); Script := Script.HighestOverrideOrSelf[aElement._File.LoadOrder]; if Supports(Script.ElementByName['Local Variables'], IwbContainerElementRef, LocalVars) then begin for i := 0 to Pred(LocalVars.ElementCount) do if Supports(LocalVars.Elements[i], IwbContainerElementRef, LocalVar) then begin j := LocalVar.ElementNativeValues['SLSD\Index']; s := LocalVar.ElementNativeValues['SCVR']; if SameText(s, Trim(aString)) then begin Result := j; Exit; end; end; end; raise Exception.Create('Variable "'+aString+'" was not found in "'+MainRecord.ShortName+'"'); end; function wbCTDAParam2QuestStageToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainerElementRef; Param1 : IwbElement; MainRecord : IwbMainRecord; EditInfos : TStringList; Stages : IwbContainerElementRef; Stage : IwbContainerElementRef; i, j : Integer; s, t : string; begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctToEditValue: Result := IntToStr(aInt); ctToSortKey: begin Result := IntToHex64(aInt, 8); Exit; end; ctCheck: Result := ''; ctEditType: Result := ''; ctEditInfo: Result := ''; end; if not Assigned(aElement) then Exit; Container := GetContainerRefFromUnionOrValue(aElement); if not Assigned(Container) then Exit; Param1 := Container.ElementByName['Parameter #1']; if not Assigned(Param1) then Exit; if not Supports(Param1.LinksTo, IwbMainRecord, MainRecord) then Exit; MainRecord := MainRecord.WinningOverride; if MainRecord.Signature <> QUST then begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end; Exit; end; case aType of ctEditType: begin Result := 'ComboBox'; Exit; end; ctEditInfo: EditInfos := TStringList.Create; else EditInfos := nil; end; try if Supports(MainRecord.ElementByName['Stages'], IwbContainerElementRef, Stages) then begin for i := 0 to Pred(Stages.ElementCount) do if Supports(Stages.Elements[i], IwbContainerElementRef, Stage) then begin j := Stage.ElementNativeValues['INDX']; s := Trim(Stage.ElementValues['Log Entries\Log Entry\CNAM']); t := IntToStr(j); while Length(t) < 3 do t := '0' + t; if s <> '' then t := t + ' ' + s; if Assigned(EditInfos) then EditInfos.AddObject(t, TObject(j)) else if j = aInt then begin case aType of ctToStr, ctToEditValue: Result := t; ctCheck: Result := ''; end; Exit; end; end; end; case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; ctEditInfo: begin EditInfos.Sort; Result := EditInfos.CommaText; end; end; finally FreeAndNil(EditInfos); end; end; function wbPerkDATAQuestStageToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainerElementRef; Param1 : IwbElement; MainRecord : IwbMainRecord; EditInfos : TStringList; Stages : IwbContainerElementRef; Stage : IwbContainerElementRef; i, j : Integer; s, t : string; begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctToEditValue: Result := IntToStr(aInt); ctToSortKey: begin Result := IntToHex64(aInt, 8); Exit; end; ctCheck: Result := ''; ctEditType: Result := ''; ctEditInfo: Result := ''; end; if not Assigned(aElement) then Exit; Container := GetContainerRefFromUnionOrValue(aElement); if not Assigned(Container) then Exit; Param1 := Container.ElementByName['Quest']; if not Assigned(Param1) then Exit; if not Supports(Param1.LinksTo, IwbMainRecord, MainRecord) then Exit; MainRecord := MainRecord.WinningOverride; if MainRecord.Signature <> QUST then begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end; Exit; end; case aType of ctEditType: begin Result := 'ComboBox'; Exit; end; ctEditInfo: EditInfos := TStringList.Create; else EditInfos := nil; end; try if Supports(MainRecord.ElementByName['Stages'], IwbContainerElementRef, Stages) then begin for i := 0 to Pred(Stages.ElementCount) do if Supports(Stages.Elements[i], IwbContainerElementRef, Stage) then begin j := Stage.ElementNativeValues['INDX']; s := Trim(Stage.ElementValues['Log Entries\Log Entry\CNAM']); t := IntToStr(j); while Length(t) < 3 do t := '0' + t; if s <> '' then t := t + ' ' + s; if Assigned(EditInfos) then EditInfos.AddObject(t, TObject(j)) else if j = aInt then begin case aType of ctToStr, ctToEditValue: Result := t; ctCheck: Result := ''; end; Exit; end; end; end; case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; ctEditInfo: begin EditInfos.Sort; Result := EditInfos.CommaText; end; end; finally FreeAndNil(EditInfos); end; end; function wbCTDAParam2QuestObjectiveToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainerElementRef; Param1 : IwbElement; MainRecord : IwbMainRecord; EditInfos : TStringList; Objectives : IwbContainerElementRef; Objective : IwbContainerElementRef; i, j : Integer; s, t : string; begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctToEditValue: Result := IntToStr(aInt); ctToSortKey: begin Result := IntToHex64(aInt, 8); Exit; end; ctCheck: Result := ''; ctEditType: Result := ''; ctEditInfo: Result := ''; end; if not Assigned(aElement) then Exit; Container := GetContainerRefFromUnionOrValue(aElement); if not Assigned(Container) then Exit; Param1 := Container.ElementByName['Parameter #1']; if not Assigned(Param1) then Exit; if not Supports(Param1.LinksTo, IwbMainRecord, MainRecord) then Exit; MainRecord := MainRecord.WinningOverride; if MainRecord.Signature <> QUST then begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end; Exit; end; case aType of ctEditType: begin Result := 'ComboBox'; Exit; end; ctEditInfo: EditInfos := TStringList.Create; else EditInfos := nil; end; try if Supports(MainRecord.ElementByName['Objectives'], IwbContainerElementRef, Objectives) then begin for i := 0 to Pred(Objectives.ElementCount) do if Supports(Objectives.Elements[i], IwbContainerElementRef, Objective) then begin j := Objective.ElementNativeValues['QOBJ']; s := Trim(Objective.ElementValues['NNAM']); t := IntToStr(j); while Length(t) < 3 do t := '0' + t; if s <> '' then t := t + ' ' + s; if Assigned(EditInfos) then EditInfos.AddObject(t, TObject(j)) else if j = aInt then begin case aType of ctToStr, ctToEditValue: Result := t; ctCheck: Result := ''; end; Exit; end; end; end; case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; ctEditInfo: begin EditInfos.Sort; Result := EditInfos.CommaText; end; end; finally FreeAndNil(EditInfos); end; end; function wbCTDAParam2QuestStageToInt(const aString: string; const aElement: IwbElement): Int64; var i : Integer; s : string; begin i := 1; s := Trim(aString); while (i <= Length(s)) and (s[i] in ['0'..'9']) do Inc(i); s := Copy(s, 1, Pred(i)); Result := StrToInt(s); end; function wbCTDAParam2QuestObjectiveToInt(const aString: string; const aElement: IwbElement): Int64; var i : Integer; s : string; begin i := 1; s := Trim(aString); while (i <= Length(s)) and (s[i] in ['0'..'9']) do Inc(i); s := Copy(s, 1, Pred(i)); Result := StrToInt(s); end; function wbClmtMoonsPhaseLength(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var PhaseLength : Byte; Masser : Boolean; Secunda : Boolean; begin Result := ''; if aType = ctToSortKey then begin Result := IntToHex64(aInt, 2); end else if aType = ctToStr then begin PhaseLength := aInt mod 64; Masser := (aInt and 64) <> 0; Secunda := (aInt and 128) <> 0; if Masser then if Secunda then Result := 'Masser, Secunda / ' else Result := 'Masser / ' else if Secunda then Result := 'Secunda / ' else Result := 'No Moon / '; Result := Result + IntToStr(PhaseLength); end; end; function wbClmtTime(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; begin if aType = ctToSortKey then Result := IntToHex64(aInt, 4) else if aType = ctToStr then Result := TimeToStr( EncodeTime(aInt div 6, (aInt mod 6) * 10, 0, 0) ) else Result := ''; end; function wbREFRNavmeshTriangleToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainerElementRef; Navmesh : IwbElement; MainRecord : IwbMainRecord; Triangles : IwbContainerElementRef; begin case aType of ctToStr: Result := IntToStr(aInt); ctToEditValue: Result := IntToStr(aInt); ctToSortKey: begin Result := IntToHex64(aInt, 8); Exit; end; ctCheck: Result := ''; ctEditType: Result := ''; ctEditInfo: Result := ''; end; if not Assigned(aElement) then Exit; Container := GetContainerRefFromUnionOrValue(aElement); if not Assigned(Container) then Exit; Navmesh := Container.Elements[0]; if not Assigned(Navmesh) then Exit; if not Supports(Navmesh.LinksTo, IwbMainRecord, MainRecord) then Exit; MainRecord := MainRecord.WinningOverride; if MainRecord.Signature <> NAVM then begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end; Exit; end; if not wbSimpleRecords and (aType = ctCheck) and Supports(MainRecord.ElementByPath['NVTR'], IwbContainerElementRef, Triangles) then if aInt >= Triangles.ElementCount then Result := ''; end; function wbStringToInt(const aString: string; const aElement: IwbElement): Int64; begin Result := StrToIntDef(aString, 0); end; var wbCtdaTypeFlags : IwbFlagsDef; function wbCtdaTypeToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var s: string; begin Result := ''; case aType of ctEditType: Result := 'CheckComboBox'; ctEditInfo: Result := 'Equal,Greater,Lesser,Or,"Use Global","Run on Target"'; ctToEditValue: begin Result := '000000'; case aInt and $F0 of $00 : Result[1] := '1'; $40 : Result[2] := '1'; $60 : begin Result[1] := '1'; Result[2] := '1'; end; $80 : Result[3] := '1'; $A0 : begin Result[1] := '1'; Result[3] := '1'; end; end; if (aInt and $01) <> 0 then Result[4] := '1'; if (aInt and $02) <> 0 then Result[6] := '1'; if (aInt and $04) <> 0 then Result[5] := '1'; end; ctToStr: begin case aInt and $F0 of $00 : Result := 'Equal to'; $20 : Result := 'Not equal to'; $40 : Result := 'Greater than'; $60 : Result := 'Greater than or equal to'; $80 : Result := 'Less than'; $A0 : Result := 'Less than or equal to'; else Result := '' end; if not Assigned(wbCtdaTypeFlags) then wbCtdaTypeFlags := wbFlags([ {0x01} 'Or', {0x02} 'Run on target', {0x04} 'Use global' ]); s := wbCtdaTypeFlags.ToString(aInt and $0F, aElement); if s <> '' then Result := Result + ' / ' + s; end; ctToSortKey: begin Result := IntToHex64(aInt, 2); Exit; end; ctCheck: begin case aInt and $F0 of $00, $20, $40, $60, $80, $A0 : Result := ''; else Result := '' end; if not Assigned(wbCtdaTypeFlags) then wbCtdaTypeFlags := wbFlags([ {0x01} 'Or', {0x02} 'Run on target', {0x04} 'Use global' ]); s := wbCtdaTypeFlags.Check(aInt and $0F, aElement); if s <> '' then Result := Result + ' / ' + s; end; end; end; function wbCtdaTypeToInt(const aString: string; const aElement: IwbElement): Int64; var s: string; begin s := aString + '000000'; // Result := 0; if s[1] = '1' then begin if s[2] = '1' then begin if s[3] = '1' then begin Result := $00; end else begin Result := $60; end; end else begin if s[3] = '1' then begin Result := $A0; end else begin Result := $00; end; end; end else begin if s[2] = '1' then begin if s[3] = '1' then begin Result := $20; end else begin Result := $40; end; end else begin if s[3] = '1' then begin Result := $80; end else begin Result := $20; end; end; end; if s[4] = '1' then Result := Result or $01; if s[6] = '1' then Result := Result or $02; if s[5] = '1' then Result := Result or $04; end; procedure wbHeadPartsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var Container : IwbContainerElementRef; begin if wbBeginInternalEdit then try if Supports(aElement, IwbContainerElementRef, Container) then if (Container.Elements[0].NativeValue = 1) and (Container.ElementCount > 2) then Container.RemoveElement(1); finally wbEndInternalEdit; end; end; procedure wbMESGDNAMAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var OldValue, NewValue : Integer; Container : IwbContainerElementRef; begin if VarSameValue(aOldValue, aNewValue) then Exit; if Supports(aElement.Container, IwbContainerElementRef, Container) then begin OldValue := Integer(aOldValue) and 1; NewValue := Integer(aNewValue) and 1; if NewValue = OldValue then Exit; if NewValue = 1 then Container.RemoveElement('TNAM') else Container.Add('TNAM', True); end; end; procedure wbGMSTEDIDAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var OldValue, NewValue : string; Container : IwbContainerElementRef; begin if VarSameValue(aOldValue, aNewValue) then Exit; if Supports(aElement.Container, IwbContainerElementRef, Container) then begin OldValue := aOldValue; NewValue := aNewValue; if (Length(OldValue) < 1) or (Length(OldValue) < 1) or (OldValue[1] <> NewValue[1]) then begin Container.RemoveElement('DATA'); Container.Add('DATA', True); end; end; end; procedure wbFLSTEDIDAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var OldValue, NewValue : string; OldOrdered, NewOrdered : Boolean; Container : IwbContainerElementRef; const OrderedList = 'OrderedList'; begin if VarSameValue(aOldValue, aNewValue) then Exit; if Supports(aElement.Container, IwbContainerElementRef, Container) then begin OldValue := aOldValue; NewValue := aNewValue; if Length(OldValue) > Length(OrderedList) then Delete(OldValue, 1, Length(OldValue)-Length(OrderedList)); if Length(NewValue) > Length(OrderedList) then Delete(NewValue, 1, Length(NewValue)-Length(OrderedList)); OldOrdered := SameText(OldValue, OrderedList); NewOrdered := SameText(NewValue, OrderedList); if OldOrdered <> NewOrdered then Container.RemoveElement('FormIDs'); end; end; procedure wbCtdaTypeAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var OldValue, NewValue: Integer; Container: IwbContainerElementRef; begin if VarSameValue(aOldValue, aNewValue) then Exit; if not Supports(aElement, IwbContainerElementRef, Container) then Exit; OldValue := aOldValue and $04; NewValue := aNewValue and $04; if OldValue <> NewValue then Container.ElementNativeValues['..\Comparison Value'] := 0; if aNewValue and $02 then begin Container.ElementNativeValues['..\Run On'] := 1; if Integer(Container.ElementNativeValues['..\Run On']) = 1 then aElement.NativeValue := Byte(aNewValue) and not $02; end; end; function wbMODTCallback(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Strings: TDynStrings; i: Integer; begin Result := ''; if wbLoaderDone and (aType in [ctToStr, ctToSortKey] ) then begin Strings := wbContainerHandler.ResolveHash(aInt); for i := Low(Strings) to High(Strings) do Result := Result + Strings[i] + ', '; SetLength(Result, Length(Result) -2 ); end; end; function wbIdleAnam(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; begin Result := ''; case aType of ctToStr: begin case aInt and not $C0 of 0: Result := 'Idle'; 1: Result := 'Movement'; 2: Result := 'Left Arm'; 3: Result := 'Left Hand'; 4: Result := 'Weapon'; 5: Result := 'Weapon Up'; 6: Result := 'Weapon Down'; 7: Result := 'Special Idle'; 20: Result := 'Whole Body'; 21: Result := 'Upper Body'; else Result := ''; end; if (aInt and $80) = 0 then Result := Result + ', Must return a file'; if (aInt and $40) = 1 then Result := Result + ', Unknown Flag'; end; ctToSortKey: begin Result := IntToHex64(aInt, 2); end; ctCheck: begin case aInt and not $C0 of 0..7, 20, 21: Result := ''; else Result := ''; end; end; end; end; function wbScaledInt4ToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; const PlusMinus : array[Boolean] of string = ('+', '-'); begin Result := ''; case aType of ctToStr, ctToEditValue: Result := FloatToStrF(aInt / 10000, ffFixed, 99, 4); ctToSortKey: begin Result := FloatToStrF(aInt / 10000, ffFixed, 99, 4); if Length(Result) < 22 then Result := StringOfChar('0', 22 - Length(Result)) + Result; Result := PlusMinus[aInt < 0] + Result; end; ctCheck: Result := ''; end; end; function wbScaledInt4ToInt(const aString: string; const aElement: IwbElement): Int64; var f: Extended; begin f := StrToFloat(aString); f := f * 10000; Result := Round(f); end; function wbHideFFFF(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; begin Result := ''; if aType = ctToSortKey then Result := IntToHex64(aInt, 4) else if aType = ctToStr then if aInt = $FFFF then Result := 'None' else Result := IntToStr(aInt); end; function wbAtxtPosition(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; begin Result := ''; if aType = ctToSortKey then Result := IntToHex64(aInt div 17, 2) + IntToHex64(aInt mod 17, 2) else if aType = ctCheck then begin if (aInt < 0) or (aInt > 288) then Result := '' else Result := ''; end else if aType = ctToStr then Result := IntToStr(aInt) + ' -> ' + IntToStr(aInt div 17) + ':' + IntToStr(aInt mod 17); end; function wbGLOBFNAM(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; begin Result := ''; case aType of ctToStr: begin case aInt of Ord('s'): Result := 'Short'; Ord('l'): Result := 'Long'; Ord('f'): Result := 'Float'; else Result := ''; end; end; ctToSortKey: Result := Chr(aInt); ctCheck: begin case aInt of Ord('s'), Ord('l'), Ord('f'): Result := ''; else Result := ''; end; end; end; end; function wbPlacedAddInfo(const aMainRecord: IwbMainRecord): string; var Rec: IwbRecord; Container: IwbContainer; s: string; Cell: IwbMainRecord; Position: TwbVector; Grid: TwbGridCell; begin Result := ''; Rec := aMainRecord.RecordBySignature['NAME']; if Assigned(Rec) then begin s := Trim(Rec.Value); if s <> '' then Result := 'places ' + s; end; Container := aMainRecord.Container; while Assigned(Container) and (Container.ElementType <> etGroupRecord) do Container := Container.Container; if Assigned(Container) then begin s := Trim(Container.Name); if s <> '' then begin if Result <> '' then Result := Result + ' '; Result := Result + 'in ' + s; // grid position of persistent reference in exterior persistent cell (interior cells are not persistent) if Supports(aMainRecord.Container, IwbGroupRecord, Container) then Cell := IwbGroupRecord(Container).ChildrenOf; if Assigned(Cell) and Cell.IsPersistent and (Cell.Signature = 'CELL') then if aMainRecord.GetPosition(Position) then begin Grid := wbPositionToGridCell(Position); Result := Result + ' at ' + IntToStr(Grid.x) + ',' + IntToStr(Grid.y); end; end; end; end; function wbINFOAddInfo(const aMainRecord: IwbMainRecord): string; var Container: IwbContainer; s: string; begin Result := Trim(aMainRecord.ElementValues['Responses\Response\NAM1']); if Result <> '' then Result := '''' + Result + ''''; Container := aMainRecord.Container; while Assigned(Container) and (Container.ElementType <> etGroupRecord) do Container := Container.Container; if Assigned(Container) then begin s := Trim(Container.Name); if s <> '' then begin if Result <> '' then Result := Result + ' '; Result := Result + 'in ' + s; end; end; s := Trim(aMainRecord.ElementValues['QSTI']); if s <> '' then begin if Result <> '' then Result := Result + ' '; Result := Result + 'for ' + s; end; end; function wbNAVMAddInfo(const aMainRecord: IwbMainRecord): string; var Rec : IwbRecord; Element : IwbElement; s : string; begin Result := ''; Rec := aMainRecord.RecordBySignature['DATA']; if Assigned(Rec) then begin Element := Rec.ElementByName['Cell']; if Assigned(Element) then Element := Element.LinksTo; if Assigned(Element) then s := Trim(Element.Name); if s <> '' then Result := 'for ' + s; end; end; function wbCellAddInfo(const aMainRecord: IwbMainRecord): string; var Rec: IwbRecord; Container: IwbContainer; GroupRecord : IwbGroupRecord; s: string; begin Result := ''; if not aMainRecord.IsPersistent then begin Rec := aMainRecord.RecordBySignature['XCLC']; if Assigned(Rec) then Result := 'at ' + Rec.Elements[0].Value + ',' + Rec.Elements[1].Value; end; Container := aMainRecord.Container; while Assigned(Container) and not (Supports(Container, IwbGroupRecord, GroupRecord) and (GroupRecord.GroupType = 1)) do Container := Container.Container; if Assigned(Container) then begin s := wbFormID.ToString(GroupRecord.GroupLabel, aMainRecord); if s <> '' then begin if Result <> '' then s := s + ' '; Result := 'in ' + s + Result; end; end; end; function wbWthrDataClassification(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; begin Result := ''; case aType of ctToStr: begin case aInt and not 192 of 0: Result := 'None'; 1: Result := 'Pleasant'; 2: Result := 'Cloudy'; 4: Result := 'Rainy'; 8: Result := 'Snow'; else Result := ''; end; end; ctToSortKey: begin Result := IntToHex64(aInt, 2) end; ctCheck: begin case aInt and not 192 of 0, 1, 2, 4, 8: Result := ''; else Result := ''; end; end; end; end; function wbNOTETNAMDecide(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var rDATA: IwbRecord; begin Result := 0; rDATA := aElement.Container.RecordBySignature[DATA]; if Assigned(rDATA) then if rDATA.NativeValue = 3 then //Voice Result := 1; end; function wbNOTESNAMDecide(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var rDATA: IwbRecord; begin Result := 0; rDATA := aElement.Container.RecordBySignature[DATA]; if Assigned(rDATA) then if rDATA.NativeValue = 3 then //Voice Result := 1; end; function wbIPDSDATACount(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; begin if Assigned(aBasePtr) and Assigned(aEndPtr) then Result := (Cardinal(aBasePtr) - Cardinal(aBasePtr)) div 4 else Result := 12; end; function wbNAVINAVMGetCount1(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var DataContainer : IwbDataContainer; begin Result := 0; if Supports(aElement, IwbDataContainer, DataContainer) then begin if DataContainer.ElementType = etArray then if not Supports(DataContainer.Container, IwbDataContainer, DataContainer) then Exit; Assert(DataContainer.Name = 'Data'); Result := PWord(Cardinal(DataContainer.DataBasePtr) + 3*3*4)^; end; end; function wbNAVINAVMGetCount2(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var DataContainer : IwbDataContainer; begin Result := 0; if Supports(aElement, IwbDataContainer, DataContainer) then begin if DataContainer.ElementType = etArray then if not Supports(DataContainer.Container, IwbDataContainer, DataContainer) then Exit; Assert(DataContainer.Name = 'Data'); Result := PWord(Cardinal(DataContainer.DataBasePtr) + 3*3*4 + 2)^; end; end; procedure wbCTDARunOnAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin if aOldValue <> aNewValue then if aNewValue <> 2 then aElement.Container.ElementNativeValues['Reference'] := 0; end; procedure wbPERKPRKETypeAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var Container : IwbContainerElementRef; // rDATA : IwbRecord; begin if aOldValue <> aNewValue then if Supports(aElement.Container, IwbContainerElementRef, Container) then begin if Supports(Container.Container, IwbContainerElementRef, Container) then begin Container.RemoveElement('DATA'); Container.Add('DATA', True); Container.RemoveElement('Perk Conditions'); Container.RemoveElement('Entry Point Function Parameters'); if aNewValue = 2 then begin Container.Add('EPFT', True); Container.ElementNativeValues['DATA\Entry Point\Function'] := 2; end; end; end; end; function wbMGEFFAssocItemDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; Archtype : Variant; DataContainer : IwbDataContainer; Element : IwbElement; const OffsetArchtype = 56; begin Result := 1; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; VarClear(ArchType); Element := Container.ElementByName['Archtype']; if Assigned(Element) then ArchType := Element.NativeValue else if Supports(Container, IwbDataContainer, DataContainer) and DataContainer.IsValidOffset(aBasePtr, aEndPtr, OffsetArchtype) then begin // we are part of a proper structure aBasePtr := Pointer(Cardinal(aBasePtr) + OffsetArchtype); ArchType := PCardinal(aBasePtr)^; end; if not VarIsEmpty(ArchType) then case Integer(ArchType) of 01: Result := 2;//Script 18: Result := 3;//Bound Item 19: Result := 4;//Summon Creature else Result := 0; end; end; procedure wbMGEFFAssocItemAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var Container : IwbContainer; Element : IwbElement; begin if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; if (aNewValue <> 0) then begin Element := Container.ElementByName['Archtype']; if Assigned(Element) and Element.NativeValue = 0 then Element.NativeValue := $FF; // Signals ArchType that it should not mess with us on the next change! end; end; procedure wbMGEFArchtypeAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var Container: IwbContainerElementRef; begin if VarSameValue(aOldValue, aNewValue) then Exit; if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if (aNewValue < $FF) and (aOldValue < $FF) then begin Container.ElementNativeValues['..\Assoc. Item'] := 0; case Integer(aNewValue) of 11: Container.ElementNativeValues['..\Actor Value'] := 48;//Invisibility 12: Container.ElementNativeValues['..\Actor Value'] := 49;//Chameleon 24: Container.ElementNativeValues['..\Actor Value'] := 47;//Paralysis else Container.ElementNativeValues['..\Actor Value'] := -1; end; end; end; procedure wbCounterEffectsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterByPathAfterSet('DATA - Data\Counter effect count', aElement); end; procedure wbMGEFAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterContainerByPathAfterSet('DATA - Data\Counter effect count', 'Counter Effects', aElement); end; function wbCTDAReferenceDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; if Integer(Container.ElementNativeValues['Run On']) = 2 then Result := 1; end; function wbNAVINVMIDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; case Integer(Container.ElementNativeValues['Type']) of $00: Result :=1; $20: Result :=2; $30: Result :=3; end; end; function wbIMGSSkinDimmerDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; SubRecord : IwbSubRecord; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; if Supports(Container, IwbSubRecord, SubRecord) then if SubRecord.SubRecordHeaderSize in [132, 148] then Result := 1; end; function wbCOEDOwnerDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; LinksTo : IwbElement; MainRecord : IwbMainRecord; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; LinksTo := Container.ElementByName['Owner'].LinksTo; if Supports(LinksTo, IwbMainRecord, MainRecord) then if MainRecord.Signature = 'NPC_' then Result := 1 else if MainRecord.Signature = 'FACT' then Result := 2; end; function wbCreaLevelDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container: IwbContainer; i: Int64; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; i := Container.ElementByName['Flags'].NativeValue; if i and $00000080 <> 0 then Result := 1; end; function wbGMSTUnionDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var rEDID: IwbRecord; s: string; begin Result := 1; rEDID := aElement.Container.RecordBySignature[EDID]; if Assigned(rEDID) then begin s := rEDID.Value; if Length(s) > 0 then case s[1] of 's': Result := 0; 'f': Result := 2; end; end; end; function wbFLSTLNAMIsSorted(const aContainer: IwbContainer): Boolean; var rEDID : IwbRecord; s : string; _File : IwbFile; MainRecord : IwbMainRecord; const OrderedList = 'OrderedList'; begin Result := wbSortFLST; {>>> Should not be sorted according to Arthmoor and JustinOther, left as sorted for compatibility <<<} rEDID := aContainer.RecordBySignature[EDID]; if Assigned(rEDID) then begin s := rEDID.Value; if Length(s) > Length(OrderedList) then Delete(s, 1, Length(s)-Length(OrderedList)); if SameText(s, OrderedList) then Result := False; end; if Result then begin MainRecord := aContainer.ContainingMainRecord; if not Assigned(MainRecord) then Exit; MainRecord := MainRecord.MasterOrSelf; if not Assigned(MainRecord) then Exit; _File := MainRecord._File; if not Assigned(_File) then Exit; if not SameText(_File.FileName, 'WeaponModKits.esp') then Exit; case (MainRecord.FormID and $FFFFFF) of $0130EB, $0130ED, $01522D, $01522E, $0158D5, $0158D6, $0158D7, $0158D8, $0158D9, $0158DA, $0158DC, $0158DD, $018E20: Result := False; end; end; end; function wbPerkDATADecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var rPRKE: IwbRecord; eType: IwbElement; begin Result := 0; rPRKE := aElement.Container.RecordBySignature[PRKE]; if Assigned(rPRKE) then begin eType := rPRKE.ElementByName['Type']; if Assigned(eType) then begin Result := eType.NativeValue; end; end; end; function wbEPFDDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container: IwbContainerElementRef; begin Result := 0; if not Assigned(aElement) then Exit; if not Supports(aElement.Container, IwbContainerElementRef, Container) then Exit; Result := Container.ElementNativeValues['EPFT']; if Result = 2 then if Integer(Container.ElementNativeValues['..\DATA\Entry Point\Function']) = 5 then Result := 5; end; type TCTDAFunctionParamType = ( ptNone, ptInteger, ptVariableName, //Integer ptSex, //Enum: Male, Female ptActorValue, //Enum: wbActorValue ptCrimeType, //?? Enum ptAxis, //?? Char ptQuestStage, //?? Integer ptMiscStat, //?? Enum ptAlignment, //?? Enum ptEquipType, //?? Enum ptFormType, //?? Enum ptCriticalStage, //?? Enum ptObjectReference, //REFR, ACHR, ACRE, PGRE ptInventoryObject, //ARMO, BOOK, MISC, WEAP, AMMO, KEYM, ALCH, NOTE, ARMA ptActor, //ACHR, ACRE ptVoiceType, //VTYP ptIdleForm, //IDLE ptFormList, //FLST ptNote, //NOTE ptQuest, //QUST ptFaction, //FACT ptWeapon, //WEAP ptCell, //CELL ptClass, //CLAS ptRace, //RACE ptActorBase, //NPC_, CREA ptGlobal, //GLOB ptWeather, //WTHR ptPackage, //PACK ptEncounterZone, //ECZN ptPerk, //PERK ptOwner, //FACT, NPC_ ptFurniture, //FURN ptMagicItem, //SPEL ptMagicEffect, //MGEF ptWorldspace, //WRLD ptVATSValueFunction, ptVATSValueParam, ptCreatureType, ptMenuMode, ptPlayerAction, ptBodyLocation, ptReferencableObject //TREE, SOUN, ACTI, DOOR, STAT, FURN, CONT, ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, LIGH, GRAS, ASPC, IDLM, ARMA, MSTT, NOTE, PWAT, SCOL, TACT, TERM ); PCTDAFunction = ^TCTDAFunction; TCTDAFunction = record Index: Integer; Name: string; ParamType1: TCTDAFunctionParamType; ParamType2: TCTDAFunctionParamType; end; const wbCTDAFunctions : array[0..243] of TCTDAFunction = ( (Index: 1; Name: 'GetDistance'; ParamType1: ptObjectReference), (Index: 5; Name: 'GetLocked'), (Index: 6; Name: 'GetPos'; ParamType1: ptAxis), (Index: 8; Name: 'GetAngle'; ParamType1: ptAxis), (Index: 10; Name: 'GetStartingPos'; ParamType1: ptAxis), (Index: 11; Name: 'GetStartingAngle'; ParamType1: ptAxis), (Index: 12; Name: 'GetSecondsPassed'), (Index: 14; Name: 'GetActorValue'; ParamType1: ptActorValue), (Index: 18; Name: 'GetCurrentTime'), (Index: 24; Name: 'GetScale'), (Index: 25; Name: 'IsMoving'), (Index: 26; Name: 'IsTurning'), (Index: 27; Name: 'GetLineOfSight'; ParamType1: ptObjectReference), (Index: 32; Name: 'GetInSameCell'; ParamType1: ptObjectReference), (Index: 35; Name: 'GetDisabled'), (Index: 36; Name: 'MenuMode'; ParamType1: ptMenuMode), (Index: 39; Name: 'GetDisease'), (Index: 40; Name: 'GetVampire'), (Index: 41; Name: 'GetClothingValue'), (Index: 42; Name: 'SameFaction'; ParamType1: ptActor), (Index: 43; Name: 'SameRace'; ParamType1: ptActor), (Index: 44; Name: 'SameSex'; ParamType1: ptActor), (Index: 45; Name: 'GetDetected'; ParamType1: ptActor), (Index: 46; Name: 'GetDead'), (Index: 47; Name: 'GetItemCount'; ParamType1: ptInventoryObject), (Index: 48; Name: 'GetGold'), (Index: 49; Name: 'GetSleeping'), (Index: 50; Name: 'GetTalkedToPC'), (Index: 53; Name: 'GetScriptVariable'; ParamType1: ptObjectReference; ParamType2: ptVariableName), (Index: 56; Name: 'GetQuestRunning'; ParamType1: ptQuest), (Index: 58; Name: 'GetStage'; ParamType1: ptQuest), (Index: 59; Name: 'GetStageDone'; ParamType1: ptQuest; ParamType2: ptQuestStage), (Index: 60; Name: 'GetFactionRankDifference'; ParamType1: ptFaction; ParamType2: ptActor), (Index: 61; Name: 'GetAlarmed'), (Index: 62; Name: 'IsRaining'), (Index: 63; Name: 'GetAttacked'), (Index: 64; Name: 'GetIsCreature'), (Index: 65; Name: 'GetLockLevel'), (Index: 66; Name: 'GetShouldAttack'; ParamType1: ptActor), (Index: 67; Name: 'GetInCell'; ParamType1: ptCell), (Index: 68; Name: 'GetIsClass'; ParamType1: ptClass), (Index: 69; Name: 'GetIsRace'; ParamType1: ptRace), (Index: 70; Name: 'GetIsSex'; ParamType1: ptSex), (Index: 71; Name: 'GetInFaction'; ParamType1: ptFaction), (Index: 72; Name: 'GetIsID'; ParamType1: ptReferencableObject), (Index: 73; Name: 'GetFactionRank'; ParamType1: ptFaction), (Index: 74; Name: 'GetGlobalValue'; ParamType1: ptGlobal), (Index: 75; Name: 'IsSnowing'), (Index: 76; Name: 'GetDisposition'; ParamType1: ptActor), (Index: 77; Name: 'GetRandomPercent'), (Index: 79; Name: 'GetQuestVariable'; ParamType1: ptQuest; ParamType2: ptVariableName), (Index: 80; Name: 'GetLevel'), (Index: 81; Name: 'GetArmorRating'), (Index: 84; Name: 'GetDeadCount'; ParamType1: ptActorBase), (Index: 91; Name: 'GetIsAlerted'), (Index: 98; Name: 'GetPlayerControlsDisabled'; ParamType1: ptInteger; ParamType2: ptInteger{; ParamType3: ptInteger; ParamType4: ptInteger; ParamType5: ptInteger; ParamType6: ptInteger; ParamType7: ptInteger}), (Index: 99; Name: 'GetHeadingAngle'; ParamType1: ptObjectReference), (Index: 101; Name: 'IsWeaponOut'), (Index: 102; Name: 'IsTorchOut'), (Index: 103; Name: 'IsShieldOut'), (Index: 106; Name: 'IsFacingUp'), (Index: 107; Name: 'GetKnockedState'), (Index: 108; Name: 'GetWeaponAnimType'), (Index: 109; Name: 'IsWeaponSkillType'; ParamType1: ptActorValue), (Index: 110; Name: 'GetCurrentAIPackage'), (Index: 111; Name: 'IsWaiting'), (Index: 112; Name: 'IsIdlePlaying'), (Index: 116; Name: 'GetMinorCrimeCount'), (Index: 117; Name: 'GetMajorCrimeCount'), (Index: 118; Name: 'GetActorAggroRadiusViolated'), (Index: 122; Name: 'GetCrime'; ParamType1: ptActor; ParamType2: ptCrimeType), (Index: 123; Name: 'IsGreetingPlayer'), (Index: 125; Name: 'IsGuard'), (Index: 127; Name: 'HasBeenEaten'), (Index: 128; Name: 'GetFatiguePercentage'), (Index: 129; Name: 'GetPCIsClass'; ParamType1: ptClass), (Index: 130; Name: 'GetPCIsRace'; ParamType1: ptRace), (Index: 131; Name: 'GetPCIsSex'; ParamType1: ptSex), (Index: 132; Name: 'GetPCInFaction'; ParamType1: ptFaction), (Index: 133; Name: 'SameFactionAsPC'), (Index: 134; Name: 'SameRaceAsPC'), (Index: 135; Name: 'SameSexAsPC'), (Index: 136; Name: 'GetIsReference'; ParamType1: ptObjectReference), (Index: 141; Name: 'IsTalking'), (Index: 142; Name: 'GetWalkSpeed'), (Index: 143; Name: 'GetCurrentAIProcedure'), (Index: 144; Name: 'GetTrespassWarningLevel'), (Index: 145; Name: 'IsTrespassing'), (Index: 146; Name: 'IsInMyOwnedCell'), (Index: 147; Name: 'GetWindSpeed'), (Index: 148; Name: 'GetCurrentWeatherPercent'), (Index: 149; Name: 'GetIsCurrentWeather'; ParamType1: ptWeather), (Index: 150; Name: 'IsContinuingPackagePCNear'), (Index: 153; Name: 'CanHaveFlames'), (Index: 154; Name: 'HasFlames'), (Index: 157; Name: 'GetOpenState'), (Index: 159; Name: 'GetSitting'), (Index: 160; Name: 'GetFurnitureMarkerID'), (Index: 161; Name: 'GetIsCurrentPackage'; ParamType1: ptPackage), (Index: 162; Name: 'IsCurrentFurnitureRef'; ParamType1: ptObjectReference), (Index: 163; Name: 'IsCurrentFurnitureObj'; ParamType1: ptFurniture), (Index: 170; Name: 'GetDayOfWeek'), (Index: 172; Name: 'GetTalkedToPCParam'; ParamType1: ptActor), (Index: 175; Name: 'IsPCSleeping'), (Index: 176; Name: 'IsPCAMurderer'), (Index: 180; Name: 'GetDetectionLevel'; ParamType1: ptActor), (Index: 182; Name: 'GetEquipped'; ParamType1: ptInventoryObject), (Index: 185; Name: 'IsSwimming'), (Index: 190; Name: 'GetAmountSoldStolen'), (Index: 192; Name: 'GetIgnoreCrime'), (Index: 193; Name: 'GetPCExpelled'; ParamType1: ptFaction), (Index: 195; Name: 'GetPCFactionMurder'; ParamType1: ptFaction), (Index: 197; Name: 'GetPCEnemyofFaction'; ParamType1: ptFaction), (Index: 199; Name: 'GetPCFactionAttack'; ParamType1: ptFaction), (Index: 203; Name: 'GetDestroyed'), (Index: 214; Name: 'HasMagicEffect'; ParamType1: ptMagicEffect), (Index: 215; Name: 'GetDefaultOpen'), (Index: 219; Name: 'GetAnimAction'), (Index: 223; Name: 'IsSpellTarget'; ParamType1: ptMagicItem), (Index: 224; Name: 'GetVATSMode'), (Index: 225; Name: 'GetPersuasionNumber'), (Index: 226; Name: 'GetSandman'), (Index: 227; Name: 'GetCannibal'), (Index: 228; Name: 'GetIsClassDefault'; ParamType1: ptClass), (Index: 229; Name: 'GetClassDefaultMatch'), (Index: 230; Name: 'GetInCellParam'; ParamType1: ptCell; ParamType2: ptObjectReference), (Index: 235; Name: 'GetVatsTargetHeight'), (Index: 237; Name: 'GetIsGhost'), (Index: 242; Name: 'GetUnconscious'), (Index: 244; Name: 'GetRestrained'), (Index: 246; Name: 'GetIsUsedItem'; ParamType1: ptReferencableObject), (Index: 247; Name: 'GetIsUsedItemType'; ParamType1: ptFormType), (Index: 254; Name: 'GetIsPlayableRace'), (Index: 255; Name: 'GetOffersServicesNow'), (Index: 258; Name: 'GetUsedItemLevel'), (Index: 259; Name: 'GetUsedItemActivate'), (Index: 264; Name: 'GetBarterGold'), (Index: 265; Name: 'IsTimePassing'), (Index: 266; Name: 'IsPleasant'), (Index: 267; Name: 'IsCloudy'), (Index: 274; Name: 'GetArmorRatingUpperBody'), (Index: 277; Name: 'GetBaseActorValue'; ParamType1: ptActorValue), (Index: 278; Name: 'IsOwner'; ParamType1: ptOwner), (Index: 280; Name: 'IsCellOwner'; ParamType1: ptCell; ParamType2: ptOwner), (Index: 282; Name: 'IsHorseStolen'), (Index: 285; Name: 'IsLeftUp'), (Index: 286; Name: 'IsSneaking'), (Index: 287; Name: 'IsRunning'), (Index: 288; Name: 'GetFriendHit'), (Index: 289; Name: 'IsInCombat'), (Index: 300; Name: 'IsInInterior'), (Index: 304; Name: 'IsWaterObject'), (Index: 306; Name: 'IsActorUsingATorch'), (Index: 309; Name: 'IsXBox'), (Index: 310; Name: 'GetInWorldspace'; ParamType1: ptWorldSpace), (Index: 312; Name: 'GetPCMiscStat'; ParamType1: ptMiscStat), (Index: 313; Name: 'IsActorEvil'), (Index: 314; Name: 'IsActorAVictim'), (Index: 315; Name: 'GetTotalPersuasionNumber'), (Index: 318; Name: 'GetIdleDoneOnce'), (Index: 320; Name: 'GetNoRumors'), (Index: 323; Name: 'WhichServiceMenu'), (Index: 327; Name: 'IsRidingHorse'), (Index: 332; Name: 'IsInDangerousWater'), (Index: 338; Name: 'GetIgnoreFriendlyHits'), (Index: 339; Name: 'IsPlayersLastRiddenHorse'), (Index: 353; Name: 'IsActor'), (Index: 354; Name: 'IsEssential'), (Index: 358; Name: 'IsPlayerMovingIntoNewSpace'), (Index: 361; Name: 'GetTimeDead'), (Index: 362; Name: 'GetPlayerHasLastRiddenHorse'), (Index: 365; Name: 'IsChild'), (Index: 367; Name: 'GetLastPlayerAction'), (Index: 368; Name: 'IsPlayerActionActive'; ParamType1: ptPlayerAction), (Index: 370; Name: 'IsTalkingActivatorActor'; ParamType1: ptActor), (Index: 372; Name: 'IsInList'; ParamType1: ptFormList), (Index: 382; Name: 'GetHasNote'; ParamType1: ptNote), (Index: 391; Name: 'GetHitLocation'), (Index: 392; Name: 'IsPC1stPerson'), (Index: 397; Name: 'GetCauseofDeath'), (Index: 398; Name: 'IsLimbGone'; ParamType1: ptBodyLocation), (Index: 399; Name: 'IsWeaponInList'; ParamType1: ptFormList), (Index: 403; Name: 'HasFriendDisposition'), (Index: 408; Name: 'GetVATSValue'; ParamType1: ptVATSValueFunction; ParamType2: ptVATSValueParam), (Index: 409; Name: 'IsKiller'; ParamType1: ptActor), (Index: 410; Name: 'IsKillerObject'; ParamType1: ptFormList), (Index: 411; Name: 'GetFactionCombatReaction'; ParamType1: ptFaction; ParamType2: ptFaction), (Index: 415; Name: 'Exists'; ParamType1: ptObjectReference), (Index: 416; Name: 'GetGroupMemberCount'), (Index: 417; Name: 'GetGroupTargetCount'), (Index: 427; Name: 'GetIsVoiceType'; ParamType1: ptVoiceType), (Index: 428; Name: 'GetPlantedExplosive'), (Index: 430; Name: 'IsActorTalkingThroughActivator'), (Index: 431; Name: 'GetHealthPercentage'), (Index: 433; Name: 'GetIsObjectType'; ParamType1: ptFormType), (Index: 435; Name: 'GetDialogueEmotion'), (Index: 436; Name: 'GetDialogueEmotionValue'), (Index: 438; Name: 'GetIsCreatureType'; ParamType1: ptCreatureType), (Index: 446; Name: 'GetInZone'; ParamType1: ptEncounterZone), (Index: 449; Name: 'HasPerk'; ParamType1: ptPerk), (Index: 450; Name: 'GetFactionRelation'; ParamType1: ptActor), (Index: 451; Name: 'IsLastIdlePlayed'; ParamType1: ptIdleForm), (Index: 454; Name: 'GetPlayerTeammate'), (Index: 455; Name: 'GetPlayerTeammateCount'), (Index: 459; Name: 'GetActorCrimePlayerEnemy'), (Index: 460; Name: 'GetActorFactionPlayerEnemy'), (Index: 464; Name: 'IsPlayerGrabbedRef'; ParamType1: ptObjectReference), (Index: 471; Name: 'GetDestructionStage'), (Index: 474; Name: 'GetIsAlignment'; ParamType1: ptAlignment), (Index: 478; Name: 'GetThreatRatio'; ParamType1: ptActor), (Index: 480; Name: 'GetIsUsedItemEquipType'; ParamType1: ptEquipType), (Index: 489; Name: 'GetConcussed'), (Index: 492; Name: 'GetMapMarkerVisible'), (Index: 495; Name: 'GetPermanentActorValue'; ParamType1: ptActorValue), (Index: 496; Name: 'GetKillingBlowLimb'), (Index: 500; Name: 'GetWeaponHealthPerc'), (Index: 503; Name: 'GetRadiationLevel'), (Index: 510; Name: 'GetLastHitCritical'), (Index: 515; Name: 'IsCombatTarget'; ParamType1: ptActor), (Index: 518; Name: 'GetVATSRightAreaFree'; ParamType1: ptObjectReference), (Index: 519; Name: 'GetVATSLeftAreaFree'; ParamType1: ptObjectReference), (Index: 520; Name: 'GetVATSBackAreaFree'; ParamType1: ptObjectReference), (Index: 521; Name: 'GetVATSFrontAreaFree'; ParamType1: ptObjectReference), (Index: 522; Name: 'GetIsLockBroken'), (Index: 523; Name: 'IsPS3'), (Index: 524; Name: 'IsWin32'), (Index: 525; Name: 'GetVATSRightTargetVisible'; ParamType1: ptObjectReference), (Index: 526; Name: 'GetVATSLeftTargetVisible'; ParamType1: ptObjectReference), (Index: 527; Name: 'GetVATSBackTargetVisible'; ParamType1: ptObjectReference), (Index: 528; Name: 'GetVATSFrontTargetVisible'; ParamType1: ptObjectReference), (Index: 531; Name: 'IsInCriticalStage'; ParamType1: ptCriticalStage), (Index: 533; Name: 'GetXPForNextLevel'), (Index: 546; Name: 'GetQuestCompleted'; ParamType1: ptQuest), (Index: 550; Name: 'IsGoreDisabled'), (Index: 555; Name: 'GetSpellUsageNum'; ParamType1: ptMagicItem), (Index: 557; Name: 'GetActorsInHigh'), (Index: 558; Name: 'HasLoaded3D'), // Added by FOSE: (Index: 1024; Name: 'GetFOSEVersion'; ), (Index: 1025; Name: 'GetFOSERevision'; ), (Index: 1028; Name: 'GetWeight'; ParamType1: ptInventoryObject; ), (Index: 1082; Name: 'IsKeyPressed'; ParamType1: ptInteger;), (Index: 1165; Name: 'GetWeaponHasScope'; ParamType1: ptInventoryObject; ), (Index: 1166; Name: 'IsControlPressed'; ParamType1: ptInteger; ), (Index: 1213; Name: 'GetFOSEBeta'; ) ); var wbCTDAFunctionEditInfo: string; function wbCTDAParamDescFromIndex(aIndex: Integer): PCTDAFunction; var L, H, I, C: Integer; begin Result := nil; L := Low(wbCTDAFunctions); H := High(wbCTDAFunctions); while L <= H do begin I := (L + H) shr 1; C := CmpW32(wbCTDAFunctions[I].Index, aIndex); if C < 0 then L := I + 1 else begin H := I - 1; if C = 0 then begin L := I; Result := @wbCTDAFunctions[L]; end; end; end; end; function wbCTDACompValueDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container: IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; if Integer(Container.ElementByName['Type'].NativeValue) and $04 <> 0 then Result := 1; end; function wbCTDAParam1Decider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Desc: PCTDAFunction; Container: IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; Desc := wbCTDAParamDescFromIndex(Container.ElementByName['Function'].NativeValue); if Assigned(Desc) then Result := Succ(Integer(Desc.ParamType1)); end; function wbCTDAParam2VATSValueParam(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; Result := Container.ElementByName['Parameter #1'].NativeValue; end; function wbCTDAParam2Decider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Desc: PCTDAFunction; Container: IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; Desc := wbCTDAParamDescFromIndex(Container.ElementByName['Function'].NativeValue); if Assigned(Desc) then Result := Succ(Integer(Desc.ParamType2)); end; function wbCTDAFunctionToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Desc : PCTDAFunction; i : Integer; begin Result := ''; case aType of ctToStr, ctToEditValue: begin Desc := wbCTDAParamDescFromIndex(aInt); if Assigned(Desc) then Result := Desc.Name else if aType = ctToEditValue then Result := IntToStr(aInt) else Result := ''; end; ctToSortKey: Result := IntToHex(aInt, 8); ctCheck: begin Desc := wbCTDAParamDescFromIndex(aInt); if Assigned(Desc) then Result := '' else Result := ''; end; ctEditType: Result := 'ComboBox'; ctEditInfo: begin Result := wbCTDAFunctionEditInfo; if Result = '' then begin with TStringList.Create do try for i := Low(wbCTDAFunctions) to High(wbCTDAFunctions) do Add(wbCTDAFunctions[i].Name); Sort; Result := CommaText; finally Free; end; wbCTDAFunctionEditInfo := Result; end; end; end; end; function wbCTDAFunctionToInt(const aString: string; const aElement: IwbElement): Int64; var i: Integer; begin for i := Low(wbCTDAFunctions) to High(wbCTDAFunctions) do with wbCTDAFunctions[i] do if SameText(Name, aString) then begin Result := Index; Exit; end; Result := StrToInt64(aString); end; type TPERKEntryPointConditionType = ( epcDefault, epcItem, epcWeapon, epcWeaponTarget, epcTarget, epcAttacker, epcAttackerAttackee, epcAttackerAttackerWeapon ); TPERKEntryPointFunctionType = ( epfFloat, epfLeveledItem, epfScript, epfUnknown ); TPERKEntryPointFunctionParamType = ( epfpNone, epfpFloat, epfpFloatFloat, epfpLeveledItem, epfpScript ); PPERKEntryPoint = ^TPERKEntryPoint; TPERKEntryPoint = record Name : string; Condition : TPERKEntryPointConditionType; FunctionType : TPERKEntryPointFunctionType; end; PPERKCondition = ^TPERKCondition; TPERKCondition = record Count : Integer; Caption1 : string; Caption2 : string; Caption3 : string; end; PPERKFunction = ^TPERKFunction; TPERKFunction = record Name : string; FunctionType : TPERKEntryPointFunctionType; ParamType : TPERKEntryPointFunctionParamType; end; const wbPERKCondition : array[TPERKEntryPointConditionType] of TPERKCondition = ( (Count: 1; Caption1: 'Perk Owner'), (Count: 2; Caption1: 'Perk Owner'; Caption2: 'Item'), (Count: 2; Caption1: 'Perk Owner'; Caption2: 'Weapon'), (Count: 3; Caption1: 'Perk Owner'; Caption2: 'Weapon'; Caption3: 'Target'), (Count: 2; Caption1: 'Perk Owner'; Caption2: 'Target'), (Count: 2; Caption1: 'Perk Owner'; Caption2: 'Attacker'), (Count: 3; Caption1: 'Perk Owner'; Caption2: 'Attacker'; Caption3: 'Attackee'), (Count: 3; Caption1: 'Perk Owner'; Caption2: 'Attacker'; Caption3: 'Attacker Weapon') ); wbPERKFunctions : array[0..9] of TPERKFunction = ( (Name: ''; FunctionType: epfUnknown; ParamType: epfpNone), (Name: 'Set Value'; FunctionType: epfFloat; ParamType: epfpFloat), (Name: 'Add Value'; FunctionType: epfFloat; ParamType: epfpFloat), (Name: 'Multiply Value'; FunctionType: epfFloat; ParamType: epfpFloat), (Name: 'Add Range To Value'; FunctionType: epfFloat; ParamType: epfpFloatFloat), (Name: 'Add Actor Value Mult'; FunctionType: epfFloat; ParamType: epfpFloatFloat), (Name: ''; FunctionType: epfUnknown; ParamType: epfpNone), (Name: ''; FunctionType: epfUnknown; ParamType: epfpNone), (Name: 'Add Leveled List'; FunctionType: epfLeveledItem; ParamType: epfpLeveledItem), (Name: 'Add Activate Choice'; FunctionType: epfScript; ParamType: epfpScript) ); wbPERKEntryPoints : array[0..36] of TPERKEntryPoint = ( (Name: 'Calculate Weapon Damage'; Condition: epcWeaponTarget), (Name: 'Calculate My Critical Hit Chance'; Condition: epcWeaponTarget), (Name: 'Calculate My Critical Hit Damage'; Condition: epcWeaponTarget), (Name: 'Calculate Weapon Attack AP Cost'; Condition: epcWeapon), (Name: 'Calculate Mine Explode Chance'; Condition: epcItem), (Name: 'Adjust Range Penalty'; Condition: epcWeapon), (Name: 'Adjust Limb Damage'; Condition: epcAttackerAttackerWeapon), (Name: 'Calculate Weapon Range'; Condition: epcWeapon), (Name: 'Calculate To Hit Chance'; Condition: epcWeaponTarget), (Name: 'Adjust Experience Points'), (Name: 'Adjust Gained Skill Points'), (Name: 'Adjust Book Skill Points'), (Name: 'Modify Recovered Health'), (Name: 'Calculate Inventory AP Cost'), (Name: 'Get Disposition'; Condition: epcTarget), (Name: 'Get Should Attack'; Condition: epcAttacker), (Name: 'Get Should Assist'; Condition: epcAttackerAttackee), (Name: 'Calculate Buy Price'; Condition: epcItem), (Name: 'Get Bad Karma'), (Name: 'Get Good Karma'), (Name: 'Ignore Locked Terminal'), (Name: 'Add Leveled List On Death'; Condition: epcTarget; FunctionType: epfLeveledItem), (Name: 'Get Max Carry Weight'), (Name: 'Modify Addiction Chance'), (Name: 'Modify Addiction Duration'), (Name: 'Modify Positive Chem Duration'), (Name: 'Adjust Drinking Radiation'), (Name: 'Activate'; Condition: epcTarget; FunctionType: epfScript), (Name: 'Mysterious Stranger'), (Name: 'Has Paralyzing Palm'), (Name: 'Hacking Science Bonus'), (Name: 'Ignore Running During Detection'), (Name: 'Ignore Broken Lock'), (Name: 'Has Concentrated Fire'), (Name: 'Calculate Gun Spread'; Condition: epcWeapon), (Name: 'Player Kill AP Reward'; Condition: epcWeaponTarget), (Name: 'Modify Enemy Critical Hit Chance'; Condition: epcWeaponTarget) ); wbPERKFunctionParams: array[TPERKEntryPointFunctionParamType] of string = ( 'None', 'Float', 'Float, Float', 'Leveled Item', 'Script' ); procedure wbPERKEntryPointAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var OldEntryPoint : PPERKEntryPoint; NewEntryPoint : PPERKEntryPoint; OldCondition : PPERKCondition; NewCondition : PPERKCondition; OldFunction : PPERKFunction; EntryPoint : IwbContainerElementRef; Effect : IwbContainerElementRef; PerkConditions : IwbContainerElementRef; PerkCondition : IwbContainerElementRef; Container : IwbContainerElementRef; i : Integer; begin if aOldValue <> aNewValue then begin OldEntryPoint := @wbPERKEntryPoints[Integer(aOldValue)]; NewEntryPoint := @wbPERKEntryPoints[Integer(aNewValue)]; OldCondition := @wbPERKCondition[OldEntryPoint.Condition]; NewCondition := @wbPERKCondition[NewEntryPoint.Condition]; if not Assigned(aElement) then Exit; if not Supports(aElement.Container, IwbContainerElementRef, EntryPoint) then Exit; i := EntryPoint.ElementNativeValues['Function']; if (i >= Low(wbPERKFunctions)) and (i <= High(wbPERKFunctions)) then OldFunction := @wbPERKFunctions[i] else OldFunction := nil; if not Assigned(OldFunction) or (OldFunction.FunctionType <> NewEntryPoint.FunctionType) then for i := Low(wbPERKFunctions) to High(wbPERKFunctions) do with wbPERKFunctions[i] do if FunctionType = NewEntryPoint.FunctionType then begin EntryPoint.ElementNativeValues['Function'] := i; Break; end; EntryPoint.ElementNativeValues['Perk Condition Tab Count'] := NewCondition.Count; if not Supports(EntryPoint.Container, IwbContainerElementRef, Container) then Exit; if not Supports(Container.Container, IwbContainerElementRef, Effect) then Exit; if not Supports(Effect.ElementByName['Perk Conditions'], IwbContainerElementRef, PerkConditions) then Exit; for i := Pred(PerkConditions.ElementCount) downto 0 do if Supports(PerkConditions.Elements[i], IwbContainerElementRef, PerkCondition) then if Integer(PerkCondition.ElementNativeValues['PRKC']) >= NewCondition.Count then PerkCondition.Remove else case Integer(PerkCondition.ElementNativeValues['PRKC']) of 2: if OldCondition.Caption2 <> NewCondition.Caption2 then PerkCondition.Remove; 3: if OldCondition.Caption3 <> NewCondition.Caption3 then PerkCondition.Remove; end; end; end; function wbPRKCToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainerElementRef; EntryPointVar : Variant; EntryPoint : Integer; begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctToEditValue: Result := IntToStr(aInt); ctToSortKey: begin Result := IntToHex64(aInt, 2); Exit; end; ctCheck: Result := ''; ctEditType: Result := ''; ctEditInfo: Result := ''; end; if not Supports(aElement, IwbContainerElementRef, Container) then Exit; EntryPointVar := Container.ElementNativeValues['..\..\..\DATA\Entry Point\Entry Point']; if VarIsNull(EntryPointVar) or VarIsClear(EntryPointVar) then Exit; EntryPoint := EntryPointVar; if (EntryPoint < Low(wbPERKEntryPoints)) or (EntryPoint > High(wbPERKEntryPoints)) then begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end; Exit; end; with wbPERKEntryPoints[EntryPoint] do begin with wbPERKCondition[Condition] do begin case aType of ctEditType: Result := 'ComboBox'; ctEditInfo: with TStringList.Create do try if Caption1 <> '' then Add(Caption1); if Caption2 <> '' then Add(Caption2); if Caption3 <> '' then Add(Caption3); Sort; Result := CommaText; finally Free; end; else if (aInt < 0) or (aInt >= Count) then case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end else case aType of ctToStr, ctToEditValue: case Integer(aInt) of 0: Result := Caption1; 1: Result := Caption2; 2: Result := Caption3; end; ctCheck: Result := ''; end; end; end; end; end; function wbPRKCToInt(const aString: string; const aElement: IwbElement): Int64; var Container : IwbContainerElementRef; EntryPointVar : Variant; EntryPoint : Integer; s : string; begin s := Trim(aString); Result := StrToInt64Def(s, Low(Integer)); if Result <> Low(Integer) then Exit; if s = '' then begin Result := 0; Exit; end; if not Supports(aElement, IwbContainerElementRef, Container) then raise Exception.Create('Could not resolve Entry Point'); EntryPointVar := Container.ElementNativeValues['..\..\..\DATA\Entry Point\Entry Point']; if VarIsNull(EntryPointVar) or VarIsClear(EntryPointVar) then raise Exception.Create('Could not resolve Entry Point'); EntryPoint := EntryPointVar; if (EntryPoint < Low(wbPERKEntryPoints)) or (EntryPoint > High(wbPERKEntryPoints)) then raise Exception.Create('Unknown Entry Point #'+IntToStr(EntryPoint)); with wbPERKEntryPoints[EntryPoint] do with wbPERKCondition[Condition] do if SameText(aString, Caption1) then Result := 0 else if SameText(aString, Caption2) then Result := 1 else if SameText(aString, Caption3) then Result := 2 else raise Exception.Create('"'+s+'" is not valid for this Entry Point'); end; function wbNeverShow(const aElement: IwbElement): Boolean; begin Result := wbHideNeverShow; end; function GetREGNType(aElement: IwbElement): Integer; var Container: IwbContainerElementRef; begin Result := -1; if not Assigned(aElement) then Exit; while aElement.Name <> 'Region Data Entry' do begin aElement := aElement.Container; if not Assigned(aElement) then Exit; end; if not Supports(aElement, IwbContainerElementRef, Container) then Exit; Result := Container.ElementNativeValues['RDAT\Type']; end; function wbREGNObjectsDontShow(const aElement: IwbElement): Boolean; begin Result := GetREGNType(aElement) <> 2; end; function wbREGNWeatherDontShow(const aElement: IwbElement): Boolean; begin Result := GetREGNType(aElement) <> 3; end; function wbREGNMapDontShow(const aElement: IwbElement): Boolean; begin Result := GetREGNType(aElement) <> 4; end; function wbREGNLandDontShow(const aElement: IwbElement): Boolean; begin Result := GetREGNType(aElement) <> 5; end; function wbREGNGrassDontShow(const aElement: IwbElement): Boolean; begin Result := GetREGNType(aElement) <> 6; end; function wbREGNSoundDontShow(const aElement: IwbElement): Boolean; begin Result := GetREGNType(aElement) <> 7; end; function wbMESGTNAMDontShow(const aElement: IwbElement): Boolean; var Container : IwbContainerElementRef; MainRecord : IwbMainRecord; begin Result := False; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Integer(Container.ElementNativeValues['DNAM']) and 1 <> 0 then Result := True; end; function wbEPFDDontShow(const aElement: IwbElement): Boolean; var Container: IwbContainerElementRef; begin Result := False; if aElement.Name <> 'Entry Point Function Parameters' then Exit; if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if not (Integer(Container.ElementNativeValues['EPFT']) in [1..3]) then Result := True; end; function wbTES4ONAMDontShow(const aElement: IwbElement): Boolean; var MainRecord : IwbMainRecord; begin Result := False; if not Assigned(aElement) then Exit; MainRecord := aElement.ContainingMainRecord; if not Assigned(MainRecord) then Exit; if not MainRecord.IsESM then Result := True; end; function wbEPF2DontShow(const aElement: IwbElement): Boolean; var Container: IwbContainerElementRef; begin Result := False; if aElement.Name <> 'Entry Point Function Parameters' then Exit; if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if not (Integer(Container.ElementNativeValues['EPFT']) in [4]) then Result := True; end; function wbPERKPRKCDontShow(const aElement: IwbElement): Boolean; var Container: IwbContainerElementRef; begin Result := False; if aElement.Name <> 'Effect' then Exit; if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Integer(Container.ElementNativeValues['PRKE\Type']) <> 2 then Result := True; end; function wbPerkDATAFunctionToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainerElementRef; EntryPointVar : Variant; EntryPoint : Integer; i : Integer; begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctToEditValue: Result := IntToStr(aInt); ctToSortKey: begin Result := IntToHex64(aInt, 2); Exit; end; ctCheck: Result := ''; ctEditType: Result := ''; ctEditInfo: Result := ''; end; if not Supports(aElement, IwbContainerElementRef, Container) then Exit; EntryPointVar := Container.ElementNativeValues['..\Entry Point']; if VarIsNull(EntryPointVar) or VarIsClear(EntryPointVar) then Exit; EntryPoint := EntryPointVar; if (EntryPoint < Low(wbPERKEntryPoints)) or (EntryPoint > High(wbPERKEntryPoints)) then begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end; Exit; end; with wbPERKEntryPoints[EntryPoint] do begin case aType of ctEditType: Result := 'ComboBox'; ctEditInfo: with TStringList.Create do try for i := Low(wbPERKFunctions) to High(wbPERKFunctions) do if wbPERKFunctions[i].FunctionType = FunctionType then if (wbPERKFunctions[i].Name <> '') then Add(wbPERKFunctions[i].Name); Sort; Result := CommaText; finally Free; end; else if (aInt < Low(wbPERKFunctions)) or (aInt > High(wbPERKFunctions)) then case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end else case aType of ctToStr, ctToEditValue: begin Result := wbPERKFunctions[Integer(aInt)].Name; if (aType = ctToStr) and (wbPERKFunctions[Integer(aInt)].FunctionType <> FunctionType) then Result := Result + ' '; end; ctCheck: if wbPERKFunctions[Integer(aInt)].FunctionType <> FunctionType then Result := '' else Result := ''; end; end; end; end; function wbPerkDATAFunctionToInt(const aString: string; const aElement: IwbElement): Int64; var Container : IwbContainerElementRef; EntryPointVar : Variant; EntryPoint : Integer; s : string; i : Integer; begin s := Trim(aString); Result := StrToInt64Def(s, Low(Integer)); if Result <> Low(Integer) then Exit; if s = '' then raise Exception.Create('"" is not a valid value for this field'); if not Supports(aElement, IwbContainerElementRef, Container) then raise Exception.Create('Could not resolve Entry Point'); EntryPointVar := Container.ElementNativeValues['..\Entry Point']; if VarIsNull(EntryPointVar) or VarIsClear(EntryPointVar) then raise Exception.Create('Could not resolve Entry Point'); EntryPoint := EntryPointVar; if (EntryPoint < Low(wbPERKEntryPoints)) or (EntryPoint > High(wbPERKEntryPoints)) then raise Exception.Create('Unknown Entry Point #'+IntToStr(EntryPoint)); with wbPERKEntryPoints[EntryPoint] do for i := Low(wbPERKFunctions) to High(wbPERKFunctions) do if wbPERKFunctions[i].FunctionType = FunctionType then if SameText(s, wbPERKFunctions[i].Name) then begin Result := i; Exit; end; raise Exception.Create('"'+s+'" is not valid for this Entry Point'); end; procedure wbPerkDATAFunctionAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var NewFunction : Integer; Container : IwbContainerElementRef; OldParamType: Integer; NewParamType: Integer; begin NewFunction := aNewValue; if (NewFunction < Low(wbPERKFunctions)) or (NewFunction > High(wbPERKFunctions)) then Exit; if not Supports(aElement, IwbContainerElementRef, Container) then Exit; OldParamType := Container.ElementNativeValues['..\..\..\Entry Point Function Parameters\EPFT']; NewParamType := Ord(wbPERKFunctions[NewFunction].ParamType); if (OldParamType = NewParamType) and not VarSameValue(aOldValue, aNewValue) and (NewFunction in [4,5]) then Container.ElementNativeValues['..\..\..\Entry Point Function Parameters\EPFT'] := 0; Container.ElementNativeValues['..\..\..\Entry Point Function Parameters\EPFT'] := NewParamType; end; function wbPerkEPFTToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainerElementRef; FunctionTypeVar : Variant; FunctionType : Integer; // i : Integer; begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctToEditValue: Result := IntToStr(aInt); ctToSortKey: begin Result := IntToHex64(aInt, 2); Exit; end; ctCheck: Result := ''; ctEditType: Result := ''; ctEditInfo: Result := ''; end; if not Supports(aElement, IwbContainerElementRef, Container) then Exit; FunctionTypeVar := Container.ElementNativeValues['..\..\DATA\Entry Point\Function']; if VarIsNull(FunctionTypeVar) or VarIsClear(FunctionTypeVar) then Exit; FunctionType := FunctionTypeVar; if (FunctionType < Low(wbPERKFunctions)) or (FunctionType > High(wbPERKFunctions)) then begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end; Exit; end; with wbPERKFunctions[FunctionType] do begin case aType of ctEditType: Result := 'ComboBox'; ctEditInfo: Result := '"' + wbPERKFunctionParams[ParamType] + '"'; else if (aInt < Ord(Low(wbPERKFunctionParams))) or (aInt > Ord(High(wbPERKFunctionParams))) then case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end else case aType of ctToStr, ctToEditValue: begin Result := wbPERKFunctionParams[TPERKEntryPointFunctionParamType(aInt)]; if (aType = ctToStr) and (TPERKEntryPointFunctionParamType(aInt) <> ParamType) then Result := Result + ' '; end; ctCheck: if TPERKEntryPointFunctionParamType(aInt) <> ParamType then Result := Result + ' ' else Result := ''; end; end; end; end; function wbPerkEPFTToInt(const aString: string; const aElement: IwbElement): Int64; var Container : IwbContainerElementRef; FunctionTypeVar : Variant; FunctionType : Integer; s : string; // i : Integer; j : TPERKEntryPointFunctionParamType; begin s := Trim(aString); Result := StrToInt64Def(s, Low(Integer)); if Result <> Low(Integer) then Exit; if s = '' then raise Exception.Create('"" is not a valid value for this field'); if not Supports(aElement, IwbContainerElementRef, Container) then raise Exception.Create('Could not resolve Function'); FunctionTypeVar := Container.ElementNativeValues['..\..\DATA\Entry Point\Function']; if VarIsNull(FunctionTypeVar) or VarIsClear(FunctionTypeVar) then raise Exception.Create('Could not resolve Function'); FunctionType := FunctionTypeVar; if (FunctionType < Low(wbPERKFunctions)) or (FunctionType > High(wbPERKFunctions)) then raise Exception.Create('Unknown Function #'+IntToStr(FunctionType)); with wbPERKFunctions[FunctionType] do begin for j := Low(wbPERKFunctionParams) to High(wbPERKFunctionParams) do if SameText(s, wbPERKFunctionParams[j]) then begin if j <> ParamType then raise Exception.Create('"'+s+'" is not a valid Parameter Type for Function "'+Name+'"'); Result := Ord(j); Exit; end; end; raise Exception.Create('"'+s+'" is not a valid Parameter Type'); end; procedure wbPerkEPFTAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var i: Integer; Container: IwbContainerElementRef; begin if VarSameValue(aOldValue, aNewValue) then Exit; i := aNewValue; if (i < Ord(Low(wbPERKFunctionParams))) or (i> Ord(High(wbPERKFunctionParams))) then Exit; if not Supports(aElement.Container, IwbContainerElementRef, Container) then Exit; Container.RemoveElement('EPFD'); Container.RemoveElement('EPF2'); Container.RemoveElement('EPF3'); Container.RemoveElement('Embedded Script'); case TPERKEntryPointFunctionParamType(i) of epfpFloat, epfpFloatFloat, epfpLeveledItem: Container.Add('EPFD', True); epfpScript: begin Container.Add('EPF2', True); Container.Add('EPF3', True); Container.Add('SCHR', True); end; end; end; procedure wbRemoveOFST(const aElement: IwbElement); var Container: IwbContainer; rOFST: IwbRecord; begin if not wbRemoveOffsetData then Exit; if Supports(aElement, IwbContainer, Container) then begin if wbBeginInternalEdit then try Container.RemoveElement(OFST); finally wbEndInternalEdit; end else begin rOFST := Container.RecordBySignature[OFST]; if Assigned(rOFST) then Container.RemoveElement(rOFST); end; end; end; function wbActorTemplateUseTraits(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; if not wbActorTemplateHide then Exit; Element := GetElementFromUnion(aElement); MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000001) <> 0; end; end; function wbActorTemplateUseStats(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; if not wbActorTemplateHide then Exit; Element := GetElementFromUnion(aElement); MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000002) <> 0; end; end; function wbActorAutoCalcDontShow(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; if not wbActorTemplateHide then Exit; Element := GetElementFromUnion(aElement); MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Flags']; Result := (i and $00000010) <> 0; end; end; function wbActorTemplateUseStatsAutoCalc(const aElement: IwbElement): Boolean; begin if not wbActorTemplateHide then Result := False else Result := wbActorTemplateUseStats(aElement) or wbActorAutoCalcDontShow(aElement); end; function wbActorTemplateUseFactions(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; if not wbActorTemplateHide then Exit; Element := GetElementFromUnion(aElement); MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000004) <> 0; end; end; function wbActorTemplateUseActorEffectList(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; if not wbActorTemplateHide then Exit; Element := GetElementFromUnion(aElement); MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000008) <> 0; end; end; function wbActorTemplateUseAIData(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; if not wbActorTemplateHide then Exit; Element := GetElementFromUnion(aElement); MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000010) <> 0; end; end; function wbActorTemplateUseAIPackages(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; if not wbActorTemplateHide then Exit; Element := GetElementFromUnion(aElement); MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000020) <> 0; end; end; function wbActorTemplateUseModelAnimation(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; if not wbActorTemplateHide then Exit; Element := GetElementFromUnion(aElement); MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000040) <> 0; end; end; function wbActorTemplateUseBaseData(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; if not wbActorTemplateHide then Exit; Element := GetElementFromUnion(aElement); MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000080) <> 0; end; end; function wbActorTemplateUseInventory(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; if not wbActorTemplateHide then Exit; Element := GetElementFromUnion(aElement); MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000100) <> 0; end; end; function wbActorTemplateUseScript(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; if not wbActorTemplateHide then Exit; Element := GetElementFromUnion(aElement); MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000200) <> 0; end; end; procedure wbCTDAAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; //Size : Cardinal; TypeFlags : Cardinal; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; TypeFlags := Container.ElementNativeValues['Type']; if (TypeFlags and $02) <> 0 then begin if Container.DataSize = 20 then Container.DataSize := 28; Container.ElementNativeValues['Type'] := TypeFlags and not $02; Container.ElementEditValues['Run On'] := 'Target'; end; finally wbEndInternalEdit; end; end; procedure wbMGEFAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; MainRecord : IwbMainRecord; OldActorValue : Integer; NewActorValue : Integer; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; OldActorValue := Container.ElementNativeValues['DATA - Data\Actor Value']; NewActorValue := OldActorValue; case Integer(Container.ElementNativeValues['DATA - Data\Archtype']) of 01, //Script 02, //Dispel 03, //Cure Disease 13, //Light 16, //Lock 17, //Open 18, //Bound Item 19, //Summon Creature 30, //Cure Paralysis 31, //Cure Addiction 32, //Cure Poison 33: //Concussion NewActorValue := -1; 11: //Invisibility NewActorValue := 48; //Invisibility 12: //Chameleon NewActorValue := 49; //Chameleon 24: //Paralysis NewActorValue := 47; //Paralysis end; if OldActorValue <> NewActorValue then Container.ElementNativeValues['DATA - Data\Actor Value'] := NewActorValue; finally wbEndInternalEdit; end; end; procedure wbPACKAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; MainRecord : IwbMainRecord; NewContainer : IwbContainerElementRef; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; case Integer(Container.ElementNativeValues['PKDT - General\Type']) of 0: begin {Find} Container.Add('PTDT'); end; 1: begin {Follow} Container.Add('PKFD'); end; 2: begin {Escort} end; 3: begin {Eat} Container.Add('PTDT'); Container.Add('PKED'); end; 4: begin {Sleep} if not Container.ElementExists['Locations'] then if Supports(Container.Add('Locations'), IwbContainerElementRef, NewContainer) then NewContainer.ElementEditValues['PLDT - Location 1\Type'] := 'Near editor location'; end; 5: begin {Wander} end; 6: begin {Travel} end; 7: begin {Accompany} end; 8: begin {Use Item At} end; 9: begin {Ambush} end; 10: begin {Flee Not Combat} end; 12: begin {Sandbox} end; 13: begin {Patrol} if not Container.ElementExists['Locations'] then if Supports(Container.Add('Locations'), IwbContainerElementRef, NewContainer) then NewContainer.ElementEditValues['PLDT - Location 1\Type'] := 'Near linked reference'; Container.Add('PKPT'); end; 14: begin {Guard} end; 15: begin {Dialogue} end; 16: begin {Use Weapon} end; end; finally wbEndInternalEdit; end; end; procedure wbNPCAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; MainRecord : IwbMainRecord; // BaseRecord : IwbMainRecord; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; if Container.ElementNativeValues['NAM5'] > 255 then Container.ElementNativeValues['NAM5'] := 255; finally wbEndInternalEdit; end; end; procedure wbREFRAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; MainRecord : IwbMainRecord; BaseRecord : IwbMainRecord; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; Container.RemoveElement('RCLR'); if Container.ElementExists['Ammo'] then begin BaseRecord := MainRecord.BaseRecord; if Assigned(BaseRecord) and (BaseRecord.Signature <> 'WEAP') then Container.RemoveElement('Ammo'); end; finally wbEndInternalEdit; end; end; procedure wbINFOAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; MainRecord : IwbMainRecord; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; if (Integer(Container.ElementNativeValues['DATA\Flags 1']) and $80) = 0 then Container.RemoveElement('DNAM'); Container.RemoveElement('SNDD'); if Container.ElementNativeValues['DATA\Type'] = 3 {Persuasion} then Container.ElementNativeValues['DATA\Type'] := 0 {Topic}; finally wbEndInternalEdit; end; end; procedure wbCELLAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; // Container2 : IwbContainerElementRef; MainRecord : IwbMainRecord; // i : Integer; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; if (not Container.ElementExists['XCLW']) and ((Integer(Container.ElementNativeValues['DATA']) and $02) <> 0) then begin Container.Add('XCLW', True); Container.ElementEditValues['XCLW'] := 'Default'; end; if (not Container.ElementExists['XNAM']) and ((Integer(Container.ElementNativeValues['DATA']) and $02) <> 0) then Container.Add('XNAM', True); // if Supports(Container.ElementBySignature[XCLR], IwbContainerElementRef, Container2) then begin // for i:= Pred(Container2.ElementCount) downto 0 do // if not Supports(Container2.Elements[i].LinksTo, IwbMainRecord, MainRecord) or (MainRecord.Signature <> 'REGN') then // Container2.RemoveElement(i); // if Container2.ElementCount < 1 then // Container2.Remove; // end; finally wbEndInternalEdit; end; end; procedure wbEmbeddedScriptAfterLoad(const aElement: IwbElement); var Container: IwbContainerElementRef; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if Container.ElementEditValues['SCHR\Type'] = 'Quest' then Container.ElementEditValues['SCHR\Type'] := 'Object'; finally wbEndInternalEdit; end; end; procedure wbSOUNAfterLoad(const aElement: IwbElement); var Container: IwbContainerElementRef; MainRecord : IwbMainRecord; OldCntr: IwbContainerElementRef; NewCntr: IwbContainerElementRef; NewCntr2: IwbContainerElementRef; i: Integer; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; if Container.ElementExists['SNDD'] then Exit; if not Supports(Container.RemoveElement('SNDX - Sound Data'), IwbContainerElementRef, OldCntr) then Exit; if not Supports(Container.Add('SNDD', True), IwbContainerElementRef, NewCntr) then Exit; for i := 0 to Pred(Min(OldCntr.ElementCount, NewCntr.ElementCount)) do NewCntr.Elements[i].Assign(Low(Integer), OldCntr.Elements[i], False); if not Supports(NewCntr.ElementByName['Attenuation Curve'], IwbContainerElementRef, NewCntr2) then Assert(False); Assert(NewCntr2.ElementCount = 5); if Supports(Container.RemoveElement('ANAM'), IwbContainerElementRef, OldCntr) then begin Assert(OldCntr.ElementCount = 5); for i := 0 to Pred(Min(OldCntr.ElementCount, NewCntr2.ElementCount)) do NewCntr2.Elements[i].Assign(Low(Integer), OldCntr.Elements[i], False); end else begin NewCntr2.Elements[0].NativeValue := 100; NewCntr2.Elements[1].NativeValue := 50; NewCntr2.Elements[2].NativeValue := 20; NewCntr2.Elements[3].NativeValue := 5; NewCntr2.Elements[4].NativeValue := 0; end; if not Supports(NewCntr.ElementByName['Reverb Attenuation Control'], IwbContainerElementRef, NewCntr2) then Assert(False); if Supports(Container.RemoveElement('GNAM'), IwbContainerElementRef, OldCntr) then NewCntr2.Assign(Low(Integer), OldCntr, False) else NewCntr2.NativeValue := 80; if not Supports(NewCntr.ElementByName['Priority'], IwbContainerElementRef, NewCntr2) then Assert(False); if Supports(Container.RemoveElement('HNAM'), IwbContainerElementRef, OldCntr) then NewCntr2.Assign(Low(Integer), OldCntr, False) else NewCntr2.NativeValue := 128; finally wbEndInternalEdit; end; end; procedure wbWATRAfterLoad(const aElement: IwbElement); var Container: IwbContainerElementRef; MainRecord : IwbMainRecord; // AnimationMultiplier : Extended; // AnimationAttackMultiplier : Extended; OldCntr: IwbContainerElementRef; NewCntr: IwbContainerElementRef; i: Integer; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; if Container.ElementExists['DNAM'] then Exit; if not Supports(Container.RemoveElement('DATA - Visual Data'), IwbContainerElementRef, OldCntr) then Exit; if not Supports(Container.Add('DNAM', True), IwbContainerElementRef, NewCntr) then Exit; for i := 0 to Pred(Min(OldCntr.ElementCount, NewCntr.ElementCount)) do if OldCntr.Elements[i].Name = 'Damage (Old Format)' then Container.ElementNativeValues['DATA - Damage'] := OldCntr.Elements[i].NativeValue else NewCntr.Elements[i].Assign(Low(Integer), OldCntr.Elements[i], False); NewCntr.ElementNativeValues['Noise Properties - Noise Layer One - Amplitude Scale'] := 1.0; NewCntr.ElementNativeValues['Noise Properties - Noise Layer Two - Amplitude Scale'] := 0.5; NewCntr.ElementNativeValues['Noise Properties - Noise Layer Three - Amplitude Scale'] := 0.25; finally wbEndInternalEdit; end; end; procedure wbWEAPAfterLoad(const aElement: IwbElement); var Container: IwbContainerElementRef; MainRecord : IwbMainRecord; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; if not Container.ElementExists['DNAM'] then Exit; if Container.ElementNativeValues['DNAM\Animation Multiplier'] = 0.0 then Container.ElementNativeValues['DNAM\Animation Multiplier'] := 1.0; if Container.ElementNativeValues['DNAM\Animation Attack Multiplier'] = 0.0 then Container.ElementNativeValues['DNAM\Animation Attack Multiplier'] := 1.0; finally wbEndInternalEdit; end; end; procedure wbMESGAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; MainRecord : IwbMainRecord; IsMessageBox : Boolean; HasTimeDelay : Boolean; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; IsMessageBox := (Integer(Container.ElementNativeValues['DNAM']) and 1) = 1; HasTimeDelay := Container.ElementExists['TNAM']; if IsMessageBox = HasTimeDelay then if IsMessageBox then Container.RemoveElement('TNAM') else begin if not Container.ElementExists['DNAM'] then Container.Add('DNAM', True); Container.ElementNativeValues['DNAM'] := Integer(Container.ElementNativeValues['DNAM']) or 1; end; finally wbEndInternalEdit; end; end; procedure wbEFSHAfterLoad(const aElement: IwbElement); var Container: IwbContainerElementRef; MainRecord : IwbMainRecord; FullParticleBirthRatio : Extended; PersistantParticleBirthRatio : Extended; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; if not Container.ElementExists['DATA'] then Exit; FullParticleBirthRatio := Container.ElementNativeValues['DATA\Particle Shader - Full Particle Birth Ratio']; PersistantParticleBirthRatio := Container.ElementNativeValues['DATA\Particle Shader - Persistant Particle Birth Ratio']; if ((FullParticleBirthRatio <> 0) and (FullParticleBirthRatio <= 1)) then begin FullParticleBirthRatio := FullParticleBirthRatio * 78.0; Container.ElementNativeValues['DATA\Particle Shader - Full Particle Birth Ratio'] := FullParticleBirthRatio; end; if ((PersistantParticleBirthRatio <> 0) and (PersistantParticleBirthRatio <= 1)) then begin PersistantParticleBirthRatio := PersistantParticleBirthRatio * 78.0; Container.ElementNativeValues['DATA\Particle Shader - Persistant Particle Birth Ratio'] := PersistantParticleBirthRatio; end; finally wbEndInternalEdit; end; end; procedure wbFACTAfterLoad(const aElement: IwbElement); var Container: IwbContainerElementRef; MainRecord : IwbMainRecord; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Container.ElementExists['CNAM'] then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; Container.RemoveElement('CNAM'); finally wbEndInternalEdit; end; end; procedure wbLIGHAfterLoad(const aElement: IwbElement); var Container: IwbContainerElementRef; MainRecord : IwbMainRecord; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; if not Container.ElementExists['FNAM'] then begin Container.Add('FNAM', True); Container.ElementNativeValues['FNAM'] := 1.0; end; if Container.ElementExists['DATA'] then begin if SameValue(Container.ElementNativeValues['DATA\Falloff Exponent'], 0.0) then Container.ElementNativeValues['DATA\Falloff Exponent'] := 1.0; if SameValue(Container.ElementNativeValues['DATA\FOV'], 0.0) then Container.ElementNativeValues['DATA\FOV'] := 90.0; end; finally wbEndInternalEdit; end; end; procedure wbEFITAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; Element : IwbElement; ActorValue: Variant; MainRecord: IwbMainRecord; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; MainRecord := Container.ContainingMainRecord; if not Assigned(MainRecord) or MainRecord.IsDeleted then Exit; Element := Container.ElementByPath['..\EFID']; if not Assigned(Element) then Exit; if not Supports(Element.LinksTo, IwbMainRecord, MainRecord) then Exit; if MainRecord.Signature <> 'MGEF' then Exit; ActorValue := MainRecord.ElementNativeValues['DATA - Data\Actor Value']; if VarIsNull(ActorValue) or VarIsClear(ActorValue) then Exit; if VarCompareValue(ActorValue, Container.ElementNativeValues['Actor Value']) <> vrEqual then Container.ElementNativeValues['Actor Value'] := ActorValue; finally wbEndInternalEdit; end; end; procedure wbRPLDAfterLoad(const aElement: IwbElement); var Container: IwbContainer; a, b: Single; NeedsFlip: Boolean; begin if wbBeginInternalEdit then try if Supports(aElement, IwbContainer, Container) then begin NeedsFlip := False; if Container.ElementCount > 1 then begin a := StrToFloat((Container.Elements[0] as IwbContainer).Elements[0].Value); b := StrToFloat((Container.Elements[Pred(Container.ElementCount)] as IwbContainer).Elements[0].Value); case CompareValue(a, b) of EqualsValue: begin a := StrToFloat((Container.Elements[0] as IwbContainer).Elements[1].Value); b := StrToFloat((Container.Elements[Pred(Container.ElementCount)] as IwbContainer).Elements[1].Value); NeedsFlip := CompareValue(a, b) = GreaterThanValue; end; GreaterThanValue: NeedsFlip := True; end; end; if NeedsFlip then Container.ReverseElements; end; finally wbEndInternalEdit; end; end; function wbPxDTLocationDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container: IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; Result := Container.ElementByName['Type'].NativeValue; end; function wbPKDTFalloutBehaviorFlagsDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; SubRecord : IwbSubRecord; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; if Supports(Container, IwbSubRecord, SubRecord) then if SubRecord.SubRecordHeaderSize = 8 then Result := 1; end; function wbPKDTSpecificFlagsDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; SubRecord : IwbSubRecord; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; if Supports(Container, IwbSubRecord, SubRecord) then if SubRecord.SubRecordHeaderSize = 8 then Exit; Result := Container.ElementByName['Type'].NativeValue + 1; end; procedure wbIDLAsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var Element : IwbElement; Container : IwbContainer; SelfAsContainer : IwbContainer; begin if wbBeginInternalEdit then try // if not wbCounterAfterSet('IDLC - Animation Count', aElement) then if Supports(aElement.Container, IwbContainer, Container) then begin Element := Container.ElementByPath['IDLC\Animation Count']; if Assigned(Element) and Supports(aElement, IwbContainer, SelfAsContainer) and (Element.GetNativeValue<>SelfAsContainer.GetElementCount) then Element.SetNativeValue(SelfAsContainer.GetElementCount); end; finally wbEndInternalEdit; end; end; procedure wbAnimationsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var Element : IwbElement; Elems : IwbElement; Container : IwbContainer; begin if wbBeginInternalEdit then try // if not wbCounterContainerAfterSet('IDLC - Animation Count', 'IDLA - Animations', aElement) then if Supports(aElement, IwbContainer, Container) then begin Element := Container.ElementByPath['IDLC\Animation Count']; Elems := Container.ElementByName['IDLA - Animations']; if Assigned(Element) and not Assigned(Elems) then if Element.GetNativeValue<>0 then Element.SetNativeValue(0); end; finally wbEndInternalEdit; end; end; function wbOffsetDataColsCounter(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Cardinal; var Container : IwbDataContainer; Element : IwbElement; fResult : Extended; begin Result := 0; if Supports(aElement.Container, IwbDataContainer, Container) and (Container.Name = 'OFST - Offset Data') and Supports(Container.Container, IwbDataContainer, Container) then begin Element := Container.ElementByPath['Object Bounds\NAM0 - Min\X']; if Assigned(Element) then begin fResult := Element.NativeValue; if fResult >= MaxInt then Result := 0 else Result := Trunc(fResult); Element := Container.ElementByPath['Object Bounds\NAM9 - Max\X']; if Assigned(Element) then begin fResult := Element.NativeValue; if fResult >= MaxInt then Result := 1 else Result := Trunc(fResult) - Result + 1; end; end; end; end; procedure DefineFO3a; begin wbRecordFlags := wbInteger('Record Flags', itU32, wbFlags([ {0x00000001}'ESM', {0x00000002}'', {0x00000004}'', // Plugin selected (Editor) {0x00000008}'', // Form cannot be saved (Runtime)/Plugin active (Editor) {0x00000010}'Form initialized (Runtime only)', // Plugin cannot be active or selected (Editor) {0x00000020}'Deleted', {0x00000040}'Border Region / Has Tree LOD / Constant / Hidden From Local Map', {0x00000080}'Turn Off Fire', {0x00000100}'Inaccessible', {0x00000200}'Casts shadows / On Local Map / Motion Blur', {0x00000400}'Quest item / Persistent reference', {0x00000800}'Initially disabled', {0x00001000}'Ignored', {0x00002000}'No Voice Filter', {0x00004000}'Cannot Save (Runtime only)', {0x00008000}'Visible when distant', {0x00010000}'Random Anim Start / High Priority LOD', {0x00020000}'Dangerous / Off limits (Interior cell) / Radio Station (Talking Activator)', {0x00040000}'Compressed', {0x00080000}'Can''t wait / Platform Specific Texture / Dead', {0x00100000}'Unknown 21', {0x00200000}'Load Started', // set when beginning to load the form from save {0x00400000}'Unknown 23', {0x00800000}'Unknown 24', {0x01000000}'Destructible (Runtime only)', {0x02000000}'Obstacle / No AI Acquire', {0x03000000}'NavMesh Generation - Filter', {0x08000000}'NavMesh Generation - Bounding Box', {0x10000000}'Non-Pipboy / Reflected by Auto Water', {0x20000000}'Child Can Use / Refracted by Auto Water', {0x40000000}'NavMesh Generation - Ground', {0x80000000}'Multibound' ])); (* wbInteger('Record Flags 2', itU32, wbFlags([ {0x00000001}'Unknown 1', {0x00000002}'Unknown 2', {0x00000004}'Unknown 3', {0x00000008}'Unknown 4', {0x00000010}'Unknown 5', {0x00000020}'Unknown 6', {0x00000040}'Unknown 7', {0x00000080}'Unknown 8', {0x00000100}'Unknown 9', {0x00000200}'Unknown 10', {0x00000400}'Unknown 11', {0x00000800}'Unknown 12', {0x00001000}'Unknown 13', {0x00002000}'Unknown 14', {0x00004000}'Unknown 15', {0x00008000}'Unknown 16', {0x00010000}'Unknown 17', {0x00020000}'Unknown 18', {0x00040000}'Unknown 19', {0x00080000}'Unknown 20', {0x00100000}'Unknown 21', {0x00200000}'Unknown 22', {0x00400000}'Unknown 23', {0x00800000}'Unknown 24', {0x01000000}'Unknown 25', {0x02000000}'Unknown 26', {0x03000000}'Unknown 27', {0x08000000}'Unknown 28', {0x10000000}'Unknown 29', {0x20000000}'Unknown 30', {0x40000000}'Unknown 31', {0x80000000}'Unknown 32' ])); (**) wbMainRecordHeader := wbStruct('Record Header', [ wbString('Signature', 4, cpCritical), wbInteger('Data Size', itU32, nil, cpIgnore), wbRecordFlags, wbFormID('FormID', cpFormID), wbByteArray('Version Control Info 1', 4, cpIgnore), wbInteger('Form Version', itU16, nil, cpIgnore), wbByteArray('Version Control Info 2', 2, cpIgnore) ]); wbSizeOfMainRecordStruct := 24; wbIgnoreRecords.Add(XXXX); wbXRGD := wbByteArray(XRGD, 'Ragdoll Data'); wbXRGB := wbByteArray(XRGB, 'Ragdoll Biped Data'); wbMusicEnum := wbEnum(['Default', 'Public', 'Dungeon']); wbSoundLevelEnum := wbEnum([ 'Loud', 'Normal', 'Silent' ]); wbWeaponAnimTypeEnum := wbEnum([ {00} 'Hand to Hand', {01} 'Melee (1 Hand)', {02} 'Melee (2 Hand)', {03} 'Pistol - Balistic (1 Hand)', {04} 'Pistol - Energy (1 Hand)', {05} 'Rifle - Balistic (2 Hand)', {06} 'Rifle - Automatic (2 Hand)', {07} 'Rifle - Energy (2 Hand)', {08} 'Handle (2 Hand)', {09} 'Launcher (2 Hand)', {10} 'Grenade Throw (1 Hand)', {11} 'Land Mine (1 Hand)', {12} 'Mine Drop (1 Hand)' ]); wbReloadAnimEnum := wbEnum([ 'ReloadA', 'ReloadB', 'ReloadC', 'ReloadD', 'ReloadE', 'ReloadF', 'ReloadG', 'ReloadH', 'ReloadI', 'ReloadJ', 'ReloadK' ],[255, 'None']); wbEDID := wbString(EDID, 'Editor ID', 0, cpNormal); // not cpBenign according to Arthmoor wbEDIDReq := wbString(EDID, 'Editor ID', 0, cpNormal, True); // not cpBenign according to Arthmoor wbFULL := wbString(FULL, 'Name', 0, cpTranslate); wbFULLActor := wbString(FULL, 'Name', 0, cpTranslate, False, wbActorTemplateUseBaseData); wbFULLReq := wbString(FULL, 'Name', 0, cpNormal, True); wbDESC := wbString(DESC, 'Description', 0, cpTranslate); wbDESCReq := wbString(DESC, 'Description', 0, cpTranslate, True); wbXSCL := wbFloat(XSCL, 'Scale'); wbOBND := wbStruct(OBND, 'Object Bounds', [ wbInteger('X1', itS16), wbInteger('Y1', itS16), wbInteger('Z1', itS16), wbInteger('X2', itS16), wbInteger('Y2', itS16), wbInteger('Z2', itS16) ]); wbOBNDReq := wbStruct(OBND, 'Object Bounds', [ wbInteger('X1', itS16), wbInteger('Y1', itS16), wbInteger('Z1', itS16), wbInteger('X2', itS16), wbInteger('Y2', itS16), wbInteger('Z2', itS16) ], cpNormal, True); wbREPL := wbFormIDCkNoReach(REPL, 'Repair List', [FLST]); wbEITM := wbFormIDCk(EITM, 'Object Effect', [ENCH, SPEL]); wbBIPL := wbFormIDCk(BIPL, 'Biped Model List', [FLST]); wbCOED := wbStructExSK(COED, [2], [0, 1], 'Extra Data', [ {00} wbFormIDCkNoReach('Owner', [NPC_, FACT, NULL]), {04} wbUnion('Global Variable / Required Rank', wbCOEDOwnerDecider, [ wbByteArray('Unused', 4, cpIgnore), wbFormIDCk('Global Variable', [GLOB, NULL]), wbInteger('Required Rank', itU32) ]), {08} wbFloat('Item Condition') ]); wbYNAM := wbFormIDCk(YNAM, 'Sound - Pick Up', [SOUN]); wbZNAM := wbFormIDCk(ZNAM, 'Sound - Drop', [SOUN]); wbPosRot := wbStruct('Position/Rotation', [ wbStruct('Position', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), wbStruct('Rotation', [ wbFloat('X', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Y', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Z', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize) ]) ]); wbDATAPosRot := wbStruct(DATA, 'Position/Rotation', [ wbStruct('Position', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), wbStruct('Rotation', [ wbFloat('X', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Y', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Z', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize) ]) ], cpNormal, True); wbMODS := wbArrayS(MODS, 'Alternate Textures', wbStructSK([0, 2], 'Alternate Texture', [ wbLenString('3D Name'), wbFormIDCk('New Texture', [TXST]), wbInteger('3D Index', itS32) ]), -1); wbMO2S := wbArrayS(MO2S, 'Alternate Textures', wbStructSK([0, 2], 'Alternate Texture', [ wbLenString('3D Name'), wbFormIDCk('New Texture', [TXST]), wbInteger('3D Index', itS32) ]), -1); wbMO3S := wbArrayS(MO3S, 'Alternate Textures', wbStructSK([0, 2], 'Alternate Texture', [ wbLenString('3D Name'), wbFormIDCk('New Texture', [TXST]), wbInteger('3D Index', itS32) ]), -1); wbMO4S := wbArrayS(MO4S, 'Alternate Textures', wbStructSK([0, 2], 'Alternate Texture', [ wbLenString('3D Name'), wbFormIDCk('New Texture', [TXST]), wbInteger('3D Index', itS32) ]), -1); wbMODD := wbInteger(MODD, 'FaceGen Model Flags', itU8, wbFlags([ 'Head', 'Torso', 'Right Hand', 'Left Hand' ])); wbMOSD := wbInteger(MOSD, 'FaceGen Model Flags', itU8, wbFlags([ 'Head', 'Torso', 'Right Hand', 'Left Hand' ])); wbMODL := wbRStructSK([0], 'Model', [ wbString(MODL, 'Model Filename', 0, cpNormal, True), wbByteArray(MODB, 'Unknown', 4, cpIgnore), wbByteArray(MODT, 'Texture Files Hashes', 0, cpIgnore), // wbArray(MODT, 'Texture Files Hashes', // wbByteArray('Unknown', 24, cpBenign), // wbArray('Hashes', wbInteger('Hash', itU64, wbMODTCallback), 3), // 0, nil, nil, cpBenign), wbMODS, wbMODD ], [], cpNormal, False, nil, True); wbMODLActor := wbRStructSK([0], 'Model', [ wbString(MODL, 'Model Filename', 0, cpNormal, True), wbByteArray(MODB, 'Unknown', 4, cpIgnore), wbByteArray(MODT, 'Texture Files Hashes', 0, cpIgnore), // wbArray(MODT, 'Texture Files Hashes', // wbByteArray('Unknown', 24, cpBenign), // wbArray('Hashes', wbInteger('Hash', itU64, wbMODTCallback), 3), // 0, nil, nil, cpBenign), wbMODS, wbMODD ], [], cpNormal, False, wbActorTemplateUseModelAnimation, True); wbMODLReq := wbRStructSK([0], 'Model', [ wbString(MODL, 'Model Filename', 0, cpNormal, True), wbByteArray(MODB, 'Unknown', 4, cpIgnore), wbByteArray(MODT, 'Texture Files Hashes', 0, cpIgnore), // wbArray(MODT, 'Texture Files', // wbByteArray('Unknown', 24, cpBenign), // wbArray('Hashes', wbInteger('Hash', itU64, wbMODTCallback), 3), // 0, nil, nil, cpBenign), wbMODS, wbMODD ], [], cpNormal, True, nil, True); wbDEST := wbRStruct('Destructable', [ wbStruct(DEST, 'Header', [ wbInteger('Health', itS32), wbInteger('Count', itU8), wbInteger('Flags', itU8, wbFlags([ 'VATS Targetable' ], True)), wbByteArray('Unused', 2) ]), wbRArray('Stages', wbRStruct('Stage', [ wbStruct(DSTD, 'Destruction Stage Data', [ wbInteger('Health %', itU8), wbInteger('Index', itU8), wbInteger('Damage Stage', itU8), wbInteger('Flags', itU8, wbFlags([ 'Cap Damage', 'Disable', 'Destroy' ])), wbInteger('Self Damage per Second', itS32), wbFormIDCk('Explosion', [EXPL, NULL]), wbFormIDCk('Debris', [DEBR, NULL]), wbInteger('Debris Count', itS32) ], cpNormal, True), wbRStructSK([0], 'Model', [ wbString(DMDL, 'Model Filename'), wbByteArray(DMDT, 'Texture Files Hashes', 0, cpIgnore) // wbArray(DMDT, 'Unknown', // wbByteArray('Unknown', 24, cpBenign), // 0, nil, nil, cpBenign) ], []), wbEmpty(DSTF, 'End Marker', cpNormal, True) ], []) ) ], []); wbDESTActor := wbRStruct('Destructable', [ wbStruct(DEST, 'Header', [ wbInteger('Health', itS32), wbInteger('Count', itU8), wbInteger('Flags', itU8, wbFlags([ 'VATS Targetable' ])), wbByteArray('Unused', 2) ]), wbRArray('Stages', wbRStruct('Stage', [ wbStruct(DSTD, 'Destruction Stage Data', [ wbInteger('Health %', itU8), wbInteger('Index', itU8), wbInteger('Damage Stage', itU8), wbInteger('Flags', itU8, wbFlags([ 'Cap Damage', 'Disable', 'Destroy' ])), wbInteger('Self Damage per Second', itS32), wbFormIDCk('Explosion', [EXPL, NULL]), wbFormIDCk('Debris', [DEBR, NULL]), wbInteger('Debris Count', itS32) ], cpNormal, True), wbRStructSK([0], 'Model', [ wbString(DMDL, 'Model Filename'), wbByteArray(DMDT, 'Texture Files Hashes', 0, cpIgnore) // wbArray(DMDT, 'Unknown', // wbByteArray('Unknown', 24, cpBenign), // 0, nil, nil, cpBenign) ], []), wbEmpty(DSTF, 'End Marker', cpNormal, True) ], []) ) ], [], cpNormal, False, wbActorTemplateUseModelAnimation); wbSCRI := wbFormIDCk(SCRI, 'Script', [SCPT]); wbSCRIActor := wbFormIDCk(SCRI, 'Script', [SCPT], False, cpNormal, False, wbActorTemplateUseScript); wbENAM := wbFormIDCk(ENAM, 'Object Effect', [ENCH]); wbXLOD := wbArray(XLOD, 'Distant LOD Data', wbFloat('Unknown'), 3); wbXESP := wbStruct(XESP, 'Enable Parent', [ wbFormIDCk('Reference', [PLYR, REFR, ACRE, ACHR, PGRE, PMIS, PBEA]), wbInteger('Flags', itU8, wbFlags([ 'Set Enable State to Opposite of Parent', 'Pop In' ])), wbByteArray('Unused', 3) ]); wbSCHRReq := wbStruct(SCHR, 'Basic Script Data', [ wbByteArray('Unused', 4), wbInteger('RefCount', itU32), wbInteger('CompiledSize', itU32), wbInteger('VariableCount', itU32), wbInteger('Type', itU16, wbEnum([ 'Object', 'Quest' ], [ $100, 'Effect' ])), wbInteger('Flags', itU16, wbFlags([ 'Enabled' ]), cpNormal, False, nil, nil, 1) ], cpNormal, True); wbSCROs := wbRArray('References', wbRUnion('', [ wbFormID(SCRO, 'Global Reference'), // wbFormIDCk(SCRO, 'Global Reference', // [ACTI, DOOR, STAT, FURN, CREA, SPEL, NPC_, CONT, ARMO, AMMO, MISC, WEAP, IMAD, // BOOK, KEYM, ALCH, LIGH, QUST, PLYR, PACK, LVLI, ECZN, EXPL, FLST, IDLM, PMIS, // FACT, ACHR, REFR, ACRE, GLOB, DIAL, CELL, SOUN, MGEF, WTHR, CLAS, EFSH, RACE, // LVLC, CSTY, WRLD, SCPT, IMGS, MESG, MSTT, MUSC, NOTE, PERK, PGRE, PROJ, LVLN, // WATR, ENCH, TREE, TERM, HAIR, EYES, ADDN, NULL]), wbInteger(SCRV, 'Local Variable', itU32) ], []) ); wbSLSD := wbStructSK(SLSD, [0], 'Local Variable Data', [ wbInteger('Index', itU32), wbByteArray('Unused', 12), wbInteger('Flags', itU8, wbFlags(['IsLongOrShort']), cpCritical), wbByteArray('Unused', 7) ]); wbEmbeddedScript := wbRStruct('Embedded Script', [ wbSCHRReq, wbByteArray(SCDA, 'Compiled Embedded Script', 0, cpNormal{, True}), wbStringScript(SCTX, 'Embedded Script Source', 0, cpNormal{, True}), wbRArrayS('Local Variables', wbRStructSK([0], 'Local Variable', [ wbSLSD, wbString(SCVR, 'Name', 0, cpCritical, True) ], [])), wbSCROs ], [], cpNormal, False, nil, False, wbEmbeddedScriptAfterLoad); wbEmbeddedScriptPerk := wbRStruct('Embedded Script', [ wbSCHRReq, wbByteArray(SCDA, 'Compiled Embedded Script', 0, cpNormal, True), wbStringScript(SCTX, 'Embedded Script Source', 0, cpNormal, True), wbRArrayS('Local Variables', wbRStructSK([0], 'Local Variable', [ wbSLSD, wbString(SCVR, 'Name', 0, cpCritical, True) ], [])), wbSCROs ], [], cpNormal, False, wbEPF2DontShow, False, wbEmbeddedScriptAfterLoad); wbEmbeddedScriptReq := wbRStruct('Embedded Script', [ wbSCHRReq, wbByteArray(SCDA, 'Compiled Embedded Script', 0, cpNormal{, True}), wbStringScript(SCTX, 'Embedded Script Source', 0, cpNormal{, True}), wbRArrayS('Local Variables', wbRStructSK([0], 'Local Variable', [ wbSLSD, wbString(SCVR, 'Name', 0, cpCritical, True) ], [])), wbSCROs ], [], cpNormal, True, nil, False, wbEmbeddedScriptAfterLoad); wbXLCM := wbInteger(XLCM, 'Level Modifier', itS32); wbRecord(ACHR, 'Placed NPC', [ wbEDID, wbFormIDCk(NAME, 'Base', [NPC_], False, cpNormal, True), wbFormIDCk(XEZN, 'Encounter Zone', [ECZN]), {--- Ragdoll ---} wbXRGD, wbXRGB, {--- Patrol Data ---} wbRStruct('Patrol Data', [ wbFloat(XPRD, 'Idle Time', cpNormal, True), wbEmpty(XPPA, 'Patrol Script Marker', cpNormal, True), wbFormIDCk(INAM, 'Idle', [IDLE, NULL], False, cpNormal, True), wbEmbeddedScriptReq, wbFormIDCk(TNAM, 'Topic', [DIAL, NULL], False, cpNormal, True) ], []), {--- Leveled Actor ----} wbXLCM, {--- Merchant Container ----} wbFormIDCk(XMRC, 'Merchant Container', [REFR], True), {--- Extra ---} wbInteger(XCNT, 'Count', itS32), wbFloat(XRDS, 'Radius'), wbFloat(XHLP, 'Health'), {--- Decals ---} wbRArrayS('Linked Decals', wbStructSK(XDCR, [0], 'Decal', [ wbFormIDCk('Reference', [REFR]), wbUnknown ]) ), {--- Linked Ref ---} wbFormIDCk(XLKR, 'Linked Reference', [REFR, ACRE, ACHR, PGRE, PMIS, PBEA, PLYR]), wbStruct(XCLP, 'Linked Reference Color', [ wbStruct('Link Start Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Link End Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]) ]), {--- Activate Parents ---} wbRStruct('Activate Parents', [ wbInteger(XAPD, 'Flags', itU8, wbFlags([ 'Parent Activate Only' ], True)), wbRArrayS('Activate Parent Refs', wbStructSK(XAPR, [0], 'Activate Parent Ref', [ wbFormIDCk('Reference', [REFR, ACRE, ACHR, PGRE, PMIS, PBEA, PLYR]), wbFloat('Delay') ]) ) ], []), {--- Enable Parent ---} wbXESP, {--- Emittance ---} wbFormIDCk(XEMI, 'Emittance', [LIGH, REGN]), {--- MultiBound ---} wbFormIDCk(XMBR, 'MultiBound Reference', [REFR]), {--- Flags ---} wbEmpty(XIBS, 'Ignored By Sandbox'), {--- 3D Data ---} wbXSCL, wbDATAPosRot ], True, wbPlacedAddInfo); wbXOWN := wbFormIDCkNoReach(XOWN, 'Owner', [FACT, ACHR, CREA, NPC_]); // Ghouls can own too aparently ! wbXGLB := wbFormIDCk(XGLB, 'Global variable', [GLOB]); wbRecord(ACRE, 'Placed Creature', [ wbEDID, wbFormIDCk(NAME, 'Base', [CREA], False, cpNormal, True), wbFormIDCk(XEZN, 'Encounter Zone', [ECZN]), wbXRGD, wbXRGB, {--- Patrol Data ---} wbRStruct('Patrol Data', [ wbFloat(XPRD, 'Idle Time', cpNormal, True), wbEmpty(XPPA, 'Patrol Script Marker', cpNormal, True), wbFormIDCk(INAM, 'Idle', [IDLE, NULL], False, cpNormal, True), wbEmbeddedScriptReq, wbFormIDCk(TNAM, 'Topic', [DIAL, NULL], False, cpNormal, True) ], []), {--- Leveled Actor ----} wbXLCM, {--- Ownership ---} wbRStruct('Ownership', [ wbXOWN, wbInteger(XRNK, 'Faction rank', itS32) ], [XCMT, XCMO]), {--- Merchant Container ----} wbFormIDCk(XMRC, 'Merchant Container', [REFR], True), {--- Extra ---} wbInteger(XCNT, 'Count', itS32), wbFloat(XRDS, 'Radius'), wbFloat(XHLP, 'Health'), {--- Decals ---} wbRArrayS('Linked Decals', wbStructSK(XDCR, [0], 'Decal', [ wbFormIDCk('Reference', [REFR, ACRE, ACHR, PGRE, PMIS, PBEA]), wbUnknown ]) ), {--- Linked Ref ---} wbFormIDCk(XLKR, 'Linked Reference', [REFR, ACRE, ACHR, PGRE, PMIS, PBEA, PLYR]), wbStruct(XCLP, 'Linked Reference Color', [ wbStruct('Link Start Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Link End Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]) ]), {--- Activate Parents ---} wbRStruct('Activate Parents', [ wbInteger(XAPD, 'Flags', itU8, wbFlags([ 'Parent Activate Only' ], True)), wbRArrayS('Activate Parent Refs', wbStructSK(XAPR, [0], 'Activate Parent Ref', [ wbFormIDCk('Reference', [REFR, ACRE, ACHR, PGRE, PMIS, PBEA, PLYR]), wbFloat('Delay') ]) ) ], []), {--- Enable Parent ---} wbXESP, {--- Emittance ---} wbFormIDCk(XEMI, 'Emittance', [LIGH, REGN]), {--- MultiBound ---} wbFormIDCk(XMBR, 'MultiBound Reference', [REFR]), {--- Flags ---} wbEmpty(XIBS, 'Ignored By Sandbox'), {--- 3D Data ---} wbXSCL, wbDATAPosRot ], True, wbPlacedAddInfo); wbRecord(ACTI, 'Activator', [ wbEDIDReq, wbOBNDReq, wbFULL, wbMODL, wbSCRI, wbDEST, wbFormIDCk(SNAM, 'Sound - Looping', [SOUN]), wbFormIDCk(VNAM, 'Sound - Activation', [SOUN]), wbFormIDCk(RNAM, 'Radio Station', [TACT]), wbFormIDCk(WNAM, 'Water Type', [WATR]) ]); wbICON := wbRStruct('Icon', [ wbString(ICON, 'Large Icon filename'), wbString(MICO, 'Small Icon filename') ], []); wbICONReq := wbRStruct('Icon', [ wbString(ICON, 'Large Icon filename'), wbString(MICO, 'Small Icon filename') ], [], cpNormal, True); wbVatsValueFunctionEnum := wbEnum([ 'Weapon Is', 'Weapon In List', 'Target Is', 'Target In List', 'Target Distance', 'Target Part', 'VATS Action', 'Is Success', 'Is Critical', 'Critical Effect Is', 'Critical Effect In List', 'Is Fatal', 'Explode Part', 'Dismember Part', 'Cripple Part', 'Weapon Type Is', 'Is Stranger', 'Is Paralyzing Palm' ]); wbActorValueEnum := wbEnum([ {00} 'Aggresion', {01} 'Confidence', {02} 'Energy', {03} 'Responsibility', {04} 'Mood', {05} 'Strength', {06} 'Perception', {07} 'Endurance', {08} 'Charisma', {09} 'Intelligence', {10} 'Agility', {11} 'Luck', {12} 'Action Points', {13} 'Carry Weight', {14} 'Critical Chance', {15} 'Heal Rate', {16} 'Health', {17} 'Melee Damage', {18} 'Damage Resistance', {19} 'Poison Resistance', {20} 'Rad Resistance', {21} 'Speed Multiplier', {22} 'Fatigue', {23} 'Karma', {24} 'XP', {25} 'Perception Condition', {26} 'Endurance Condition', {27} 'Left Attack Condition', {28} 'Right Attack Condition', {29} 'Left Mobility Condition', {30} 'Right Mobility Condition', {31} 'Brain Condition', {32} 'Barter', {33} 'Big Guns', {34} 'Energy Weapons', {35} 'Explosives', {36} 'Lockpick', {37} 'Medicine', {38} 'Melee Weapons', {39} 'Repair', {40} 'Science', {41} 'Small Guns', {42} 'Sneak', {43} 'Speech', {44} 'Throwing (unused)', {45} 'Unarmed', {46} 'Inventory Weight', {47} 'Paralysis', {48} 'Invisibility', {49} 'Chameleon', {50} 'Night Eye', {51} 'Detect Life Range', {52} 'Fire Resistance', {53} 'Water Breathing', {54} 'Rad Level', {55} 'Bloody Mess', {56} 'Unarmed Damage', {57} 'Assistance', {58} 'Electric Resistance', {59} 'Frost Resistance', {60} 'Energy Resistance', {61} 'EMP Resistance', {62} 'Variable01', {63} 'Variable02', {64} 'Variable03', {65} 'Variable04', {66} 'Variable05', {67} 'Variable06', {68} 'Variable07', {79} 'Variable08', {70} 'Variable09', {71} 'Variable10', {72} 'Ignore Negative Effects' ], [ -1, 'None' ]); wbSkillEnum := wbEnum([ 'Barter', 'Big Guns', 'Energy Weapons', 'Explosives', 'Lockpick', 'Medicine', 'Melee Weapons', 'Repair', 'Science', 'Small Guns', 'Sneak', 'Speech', 'Throwing (unused)', 'Unarmed' ], [ -1, 'None' ]); wbCrimeTypeEnum := wbEnum([ 'Steal', 'Pickpocket', 'Trespass', 'Attack', 'Murder' ], [ -1, 'None' ]); wbActorValue := wbInteger('Actor Value', itS32, wbActorValueEnum); wbEquipTypeEnum := wbEnum([ {00} 'Big Guns', {01} 'Energy Weapons', {02} 'Small Guns', {03} 'Melee Weapons', {04} 'Unarmed Weapon', {05} 'Thrown Weapons', {06} 'Mine', {07} 'Body Wear', {08} 'Head Wear', {09} 'Hand Wear', {10} 'Chems', {11} 'Stimpack', {12} 'Food', {13} 'Alcohol' ], [ -1, 'None' ]); wbETYP := wbInteger(ETYP, 'Equiptment Type', itS32, wbEquipTypeEnum); wbETYPReq := wbInteger(ETYP, 'Equiptment Type', itS32, wbEquipTypeEnum, cpNormal, True); wbFormTypeEnum := wbEnum([], [ $04, 'Texture Set', $05, 'Menu Icon', $06, 'Global', $07, 'Class', $08, 'Faction', $09, 'Head Part', $0A, 'Hair', $0B, 'Eyes', $0C, 'Race', $0D, 'Sound', $0E, 'Acoustic Space', $0F, 'Skill', $10, 'Base Effect', $11, 'Script', $12, 'Landscape Texture', $13, 'Object Effect', $14, 'Actor Effect', $15, 'Activator', $16, 'Talking Activator', $17, 'Terminal', $18, 'Armor', $19, 'Book', $1A, 'Clothing', $1B, 'Container', $1C, 'Door', $1D, 'Ingredient', $1E, 'Light', $1F, 'Misc', $20, 'Static', $21, 'Static Collection', $22, 'Movable Static', $23, 'Placeable Water', $24, 'Grass', $25, 'Tree', $26, 'Flora', $27, 'Furniture', $28, 'Weapon', $29, 'Ammo', $2A, 'NPC', $2B, 'Creature', $2C, 'Leveled Creature', $2D, 'Leveled NPC', $2E, 'Key', $2F, 'Ingestible', $30, 'Idle Marker', $31, 'Note', $32, 'Constructible Object', $33, 'Projectile', $34, 'Leveled Item', $35, 'Weather', $36, 'Climate', $37, 'Region', $39, 'Cell', $3A, 'Placed Object', $3B, 'Placed Character', $3C, 'Placed Creature', $3E, 'Placed Grenade', $41, 'Worldspace', $42, 'Landscape', $43, 'Navigation Mesh', $45, 'Dialog Topic', $46, 'Dialog Response', $47, 'Quest', $48, 'Idle Animation', $49, 'Package', $4A, 'Combat Style', $4B, 'Load Screen', $4C, 'Leveled Spell', $4D, 'Animated Object', $4E, 'Water', $4F, 'Effect Shader', $51, 'Explosion', $52, 'Debris', $53, 'Image Space', $54, 'Image Space Modifier', $55, 'FormID List', $56, 'Perk', $57, 'Body Part Data', $58, 'Addon Node', $59, 'Actor Value Info', $5A, 'Radiation Stage', $5B, 'Camera Shot', $5C, 'Camera Path', $5D, 'Voice Type', $5E, 'Impact Data', $5F, 'Impact DataSet', $60, 'Armor Addon', $61, 'Encounter Zone', $62, 'Message', $63, 'Ragdoll', $64, 'Default Object Manager', $65, 'Lighting Template', $66, 'Music Type' ]); wbMenuModeEnum := wbEnum([],[ 1, 'Type: Character Interface', 2, 'Type: Other', 3, 'Type: Console', 1001, 'Specific: Message', 1002, 'Specific: Inventory', 1003, 'Specific: Stats', 1004, 'Specific: HUDMainMenu', 1007, 'Specific: Loading', 1008, 'Specific: Container', 1009, 'Specific: Dialog', 1012, 'Specific: Sleep/Wait', 1013, 'Specific: Pause', 1014, 'Specific: LockPick', 1016, 'Specific: Quantity', 1027, 'Specific: Level Up', 1035, 'Specific: Pipboy Repair', 1036, 'Specific: Race / Sex', 1047, 'Specific: Credits', 1048, 'Specific: CharGen', 1051, 'Specific: TextEdit', 1053, 'Specific: Barter', 1054, 'Specific: Surgery', 1055, 'Specific: Hacking', 1056, 'Specific: VATS', 1057, 'Specific: Computers', 1058, 'Specific: Vendor Repair', 1059, 'Specific: Tutorial', 1060, 'Specific: You''re SPECIAL book' ]); end; procedure DefineFO3b; begin wbMiscStatEnum := wbEnum([ 'Quests Completed', 'Locations Discovered', 'People Killed', 'Creatures Killed', 'Locks Picked', 'Computers Hacked', 'Stimpaks Taken', 'Rad-X Taken', 'RadAway Taken', 'Chems Taken', 'Times Addicted', 'Mines Disarmed', 'Speech Successes', 'Pockets Picked', 'Pants Exploded', 'Books Read', 'Bobbleheads Found', 'Weapons Created', 'People Mezzed', 'Captives Rescued', 'Sandman Kills', 'Paralyzing Punches', 'Robots Disabled', 'Contracts Completed', 'Corpses Eaten', 'Mysterious Stranger Visits' ]); wbAlignmentEnum := wbEnum([ 'Good', 'Neutral', 'Evil', 'Very Good', 'Very Evil' ]); wbAxisEnum := wbEnum([], [ 88, 'X', 89, 'Y', 90, 'Z' ]); wbCriticalStageEnum := wbEnum([ 'None', 'Goo Start', 'Goo End', 'Disintegrate Start', 'Disintegrate End' ]); wbSexEnum := wbEnum(['Male','Female']); wbCreatureTypeEnum := wbEnum([ 'Animal', 'Mutated Animal', 'Mutated Insect', 'Abomination', 'Super Mutant', 'Feral Ghoul', 'Robot', 'Giant' ]); wbPlayerActionEnum := wbEnum([ '', 'Swinging Melee Weapon', 'Throwing Grenade', 'Fire Weapon', 'Lay Mine', 'Z Key Object', 'Jumping', 'Knocking over Objects', 'Stand on Table/Chair', 'Iron Sites', 'Destroying Object' ]); wbBodyLocationEnum := wbEnum([ 'Torso', 'Head 1', 'Head 2', 'Left Arm 1', 'Left Arm 2', 'Right Arm 1', 'Right Arm 2', 'Left Leg 1', 'Left Leg 2', 'Left Leg 3', 'Right Leg 1', 'Right Leg 2', 'Right Leg 3', 'Brain' ], [ -1, 'None' ]); wbEFID := wbFormIDCk(EFID, 'Base Effect', [MGEF]); wbEFIT := wbStructSK(EFIT, [3, 4], '', [ wbInteger('Magnitude', itU32), wbInteger('Area', itU32), wbInteger('Duration', itU32), wbInteger('Type', itU32, wbEnum(['Self', 'Touch', 'Target'])), wbActorValue ], cpNormal, True, nil, -1, wbEFITAfterLoad); wbCTDA := wbStruct(CTDA, 'Condition', [ wbInteger('Type', itU8, wbCtdaTypeToStr, wbCtdaTypeToInt, cpNormal, False, nil, wbCtdaTypeAfterSet), wbByteArray('Unused', 3), wbUnion('Comparison Value', wbCTDACompValueDecider, [ wbFloat('Comparison Value - Float'), wbFormIDCk('Comparison Value - Global', [GLOB]) ]), wbInteger('Function', itU32, wbCTDAFunctionToStr, wbCTDAFunctionToInt), // Limited to itu16 wbUnion('Parameter #1', wbCTDAParam1Decider, [ {00} wbByteArray('Unknown', 4), {01} wbByteArray('None', 4, cpIgnore), {02} wbInteger('Integer', itS32), {03} wbInteger('Variable Name (INVALID)', itS32), {04} wbInteger('Sex', itU32, wbSexEnum), {05} wbInteger('Actor Value', itS32, wbActorValueEnum), {06} wbInteger('Crime Type', itU32, wbCrimeTypeEnum), {07} wbInteger('Axis', itU32, wbAxisEnum), {08} wbInteger('Quest Stage (INVALID)', itS32), {09} wbInteger('Misc Stat', itU32, wbMiscStatEnum), {10} wbInteger('Alignment', itU32, wbAlignmentEnum), {11} wbInteger('Equip Type', itU32, wbEquipTypeEnum), {12} wbInteger('Form Type', itU32, wbFormTypeEnum), {13} wbInteger('Critical Stage', itU32, wbCriticalStageEnum), {14} wbFormIDCkNoReach('Object Reference', [PLYR, REFR, ACHR, ACRE, PGRE, PMIS, PBEA, TRGT], True), {16} wbFormIDCkNoReach('Inventory Object', [ARMO, BOOK, MISC, WEAP, AMMO, KEYM, ALCH, NOTE, FLST]), {17} wbFormIDCkNoReach('Actor', [PLYR, ACHR, ACRE, TRGT], True), {18} wbFormIDCkNoReach('Voice Type', [VTYP]), {19} wbFormIDCkNoReach('Idle', [IDLE]), {20} wbFormIDCkNoReach('Form List', [FLST]), {21} wbFormIDCkNoReach('Note', [NOTE]), {22} wbFormIDCkNoReach('Quest', [QUST]), {23} wbFormIDCkNoReach('Faction', [FACT]), {24} wbFormIDCkNoReach('Weapon', [WEAP]), {25} wbFormIDCkNoReach('Cell', [CELL]), {26} wbFormIDCkNoReach('Class', [CLAS]), {27} wbFormIDCkNoReach('Race', [RACE]), {28} wbFormIDCkNoReach('Actor Base', [NPC_, CREA, ACTI, TACT]), {29} wbFormIDCkNoReach('Global', [GLOB]), {30} wbFormIDCkNoReach('Weather', [WTHR]), {31} wbFormIDCkNoReach('Package', [PACK]), {32} wbFormIDCkNoReach('Encounter Zone', [ECZN]), {33} wbFormIDCkNoReach('Perk', [PERK]), {34} wbFormIDCkNoReach('Owner', [FACT, NPC_]), {35} wbFormIDCkNoReach('Furniture', [FURN, FLST]), {36} wbFormIDCkNoReach('Effect Item', [SPEL, ENCH, ALCH, INGR]), {37} wbFormIDCkNoReach('Base Effect', [MGEF]), {38} wbFormIDCkNoReach('Worldspace', [WRLD]), {39} wbInteger('VATS Value Function', itU32, wbVATSValueFunctionEnum), {40} wbInteger('VATS Value Param (INVALID)', itU32), {41} wbInteger('Creature Type', itU32, wbCreatureTypeEnum), {42} wbInteger('Menu Mode', itU32, wbMenuModeEnum), {43} wbInteger('Player Action', itU32, wbPlayerActionEnum), {44} wbInteger('Body Location', itS32, wbBodyLocationEnum), {45} wbFormIDCkNoReach('Referenceable Object', [CREA, NPC_, PROJ, TREE, SOUN, ACTI, DOOR, STAT, FURN, CONT, ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, LIGH, GRAS, ASPC, IDLM, ARMA, MSTT, NOTE, PWAT, SCOL, TACT, TERM, FLST, LVLC, LVLN], [CREA, NPC_, PROJ, TREE, SOUN, ACTI, DOOR, STAT, FURN, CONT, ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, LIGH, GRAS, ASPC, IDLM, ARMA, MSTT, NOTE, PWAT, SCOL, TACT, TERM, LVLC, LVLN]) ]), wbUnion('Parameter #2', wbCTDAParam2Decider, [ {00} wbByteArray('Unknown', 4), {01} wbByteArray('None', 4, cpIgnore), {02} wbInteger('Integer', itS32), {03} wbInteger('Variable Name', itS32, wbCTDAParam2VariableNameToStr, wbCTDAParam2VariableNameToInt), {04} wbInteger('Sex', itU32, wbSexEnum), {05} wbInteger('Actor Value', itS32, wbActorValueEnum), {06} wbInteger('Crime Type', itU32, wbCrimeTypeEnum), {07} wbInteger('Axis', itU32, wbAxisEnum), {08} wbInteger('Quest Stage', itS32, wbCTDAParam2QuestStageToStr, wbCTDAParam2QuestStageToInt), {09} wbInteger('Misc Stat', itU32, wbMiscStatEnum), {10} wbInteger('Alignment', itU32, wbAlignmentEnum), {11} wbInteger('Equip Type', itU32, wbEquipTypeEnum), {12} wbInteger('Form Type', itU32, wbFormTypeEnum), {13} wbInteger('Critical Stage', itU32, wbCriticalStageEnum), {14} wbFormIDCkNoReach('Object Reference', [PLYR, REFR, PMIS, PBEA, ACHR, ACRE, PGRE, TRGT], True), {16} wbFormIDCkNoReach('Inventory Object', [ARMO, BOOK, MISC, WEAP, AMMO, KEYM, ALCH, NOTE, FLST]), {17} wbFormIDCkNoReach('Actor', [PLYR, ACHR, ACRE, TRGT], True), {18} wbFormIDCkNoReach('Voice Type', [VTYP]), {19} wbFormIDCkNoReach('Idle', [IDLE]), {20} wbFormIDCkNoReach('Form List', [FLST]), {21} wbFormIDCkNoReach('Note', [NOTE]), {22} wbFormIDCkNoReach('Quest', [QUST]), {23} wbFormIDCkNoReach('Faction', [FACT]), {24} wbFormIDCkNoReach('Weapon', [WEAP]), {25} wbFormIDCkNoReach('Cell', [CELL]), {26} wbFormIDCkNoReach('Class', [CLAS]), {27} wbFormIDCkNoReach('Race', [RACE]), {28} wbFormIDCkNoReach('Actor Base', [NPC_, CREA, ACTI, TACT]), {29} wbFormIDCkNoReach('Global', [GLOB]), {30} wbFormIDCkNoReach('Weather', [WTHR]), {31} wbFormIDCkNoReach('Package', [PACK]), {32} wbFormIDCkNoReach('Encounter Zone', [ECZN]), {33} wbFormIDCkNoReach('Perk', [PERK]), {34} wbFormIDCkNoReach('Owner', [FACT, NPC_]), {35} wbFormIDCkNoReach('Furniture', [FURN, FLST]), {36} wbFormIDCkNoReach('Effect Item', [SPEL, ENCH, ALCH, INGR]), {37} wbFormIDCkNoReach('Base Effect', [MGEF]), {38} wbFormIDCkNoReach('Worldspace', [WRLD]), {39} wbInteger('VATS Value Function (INVALID)', itU32), {40} wbUnion('VATS Value Param', wbCTDAParam2VATSValueParam, [ wbFormIDCkNoReach('Weapon', [WEAP]), wbFormIDCkNoReach('Weapon List', [FLST], [WEAP]), wbFormIDCkNoReach('Target', [NPC_, CREA]), wbFormIDCkNoReach('Target List', [FLST], [NPC_, CREA]), wbByteArray('Unused', 4, cpIgnore), wbInteger('Target Part', itS32, wbActorValueEnum), wbInteger('VATS Action', itU32, wbEnum([ 'Unarmed Attack', 'One Hand Melee Attack', 'Two Hand Melee Attack', 'Fire Pistol', 'Fire Rifle', 'Fire Handle Weapon', 'Fire Launcher', 'Throw Grenade', 'Place Mine', 'Reload', 'Crouch', 'Stand', 'Switch Weapon', 'Toggle Weapon Drawn', 'Heal', 'Player Death' ])), wbByteArray('Unused', 4, cpIgnore), wbByteArray('Unused', 4, cpIgnore), wbFormIDCkNoReach('Critical Effect', [SPEL]), wbFormIDCkNoReach('Critical Effect List', [FLST], [SPEL]), wbByteArray('Unused', 4, cpIgnore), wbByteArray('Unused', 4, cpIgnore), wbByteArray('Unused', 4, cpIgnore), wbByteArray('Unused', 4, cpIgnore), wbInteger('Weapon Type', itU32, wbWeaponAnimTypeEnum), wbByteArray('Unused', 4, cpIgnore), wbByteArray('Unused', 4, cpIgnore) ]), {41} wbInteger('Creature Type', itU32, wbCreatureTypeEnum), {42} wbInteger('Menu Mode', itU32, wbMenuModeEnum), {43} wbInteger('Player Action', itU32, wbPlayerActionEnum), {44} wbInteger('Body Location', itS32, wbBodyLocationEnum), {45} wbFormIDCkNoReach('Referenceable Object', [CREA, NPC_, PROJ, TREE, SOUN, ACTI, DOOR, STAT, FURN, CONT, ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, LIGH, GRAS, ASPC, IDLM, ARMA, MSTT, NOTE, PWAT, SCOL, TACT, TERM, FLST, LVLC, LVLN], [CREA, NPC_, PROJ, TREE, SOUN, ACTI, DOOR, STAT, FURN, CONT, ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, LIGH, GRAS, ASPC, IDLM, ARMA, MSTT, NOTE, PWAT, SCOL, TACT, TERM, LVLC, LVLN]) ]), wbInteger('Run On', itU32, wbEnum([ 'Subject', 'Target', 'Reference', 'Combat Target', 'Linked Reference' ]), cpNormal, False, nil, wbCTDARunOnAfterSet), wbUnion('Reference', wbCTDAReferenceDecider, [ wbInteger('Unused', itU32, nil, cpIgnore), wbFormIDCkNoReach('Reference', [PLYR, ACHR, ACRE, REFR, PMIS, PBEA, PGRE], True) ]) ], cpNormal, False, nil, 6, wbCTDAAfterLoad); wbCTDAs := wbRArray('Conditions', wbCTDA); wbCTDAsReq := wbRArray('Conditions', wbCTDA, cpNormal, True); wbEffects := wbRStructs('Effects','Effect', [ wbEFID, wbEFIT, wbCTDAs ], []); wbEffectsReq := wbRStructs('Effects','Effect', [ wbEFID, wbEFIT, wbCTDAs ], [], cpNormal, True); wbRecord(ALCH, 'Ingestible', [ wbEDIDReq, wbOBNDReq, wbFULLReq, wbMODL, wbICON, wbSCRI, wbDEST, wbYNAM, wbZNAM, wbETYPReq, wbFloat(DATA, 'Weight', cpNormal, True), wbStruct(ENIT, 'Effect Data', [ wbInteger('Value', itS32), wbInteger('Flags?', itU8, wbFlags([ 'No Auto-Calc (Unused)', 'Food Item', 'Medicine' ])), wbByteArray('Unused', 3), wbFormIDCk('Withdrawal Effect', [SPEL, NULL]), wbFloat('Addiction Chance'), wbFormIDCk('Sound - Consume', [SOUN]) ], cpNormal, True), wbEffectsReq ]); wbRecord(AMMO, 'Ammunition', [ wbEDIDReq, wbOBNDReq, wbFULLReq, wbMODL, wbICON, wbDEST, wbYNAM, wbZNAM, wbStruct(DATA, 'Data', [ wbFloat('Speed'), wbInteger('Flags', itU8, wbFlags([ 'Ignores Normal Weapon Resistance', 'Non-Playable' ])), wbByteArray('Unused', 3), wbInteger('Value', itS32), wbInteger('Clip Rounds', itU8) ], cpNormal, True), wbString(ONAM, 'Short Name') ]); wbRecord(ANIO, 'Animated Object', [ wbEDIDReq, wbMODLReq, wbFormIDCk(DATA, 'Animation', [IDLE], False, cpNormal, True) ]); wbBMDT := wbStruct(BMDT, 'Biped Data', [ wbInteger('Biped Flags', itU32, wbFlags([ {0x00000001} 'Head', {0x00000002} 'Hair', {0x00000004} 'Upper Body', {0x00000008} 'Left Hand', {0x00000010} 'Right Hand', {0x00000020} 'Weapon', {0x00000040} 'PipBoy', {0x00000080} 'Backpack', {0x00000100} 'Necklace', {0x00000200} 'Headband', {0x00000400} 'Hat', {0x00000800} 'Eye Glasses', {0x00001000} 'Nose Ring', {0x00002000} 'Earrings', {0x00004000} 'Mask', {0x00008000} 'Choker', {0x00010000} 'Mouth Object', {0x00020000} 'Body AddOn 1', {0x00040000} 'Body AddOn 2', {0x00080000} 'Body AddOn 3' ])), wbInteger('General Flags', itU8, wbFlags([ {0x0001} '', {0x0002} '', {0x0004} '', {0x0008} '', {0x0010} '', {0x0020} 'Power Armor', {0x0040} 'Non-Playable', {0x0080} 'Heavy' ], True)), wbByteArray('Unused', 3) ], cpNormal, True); wbRecord(ARMO, 'Armor', [ wbEDIDReq, wbOBNDReq, wbFULL, wbSCRI, wbEITM, wbBMDT, wbRStruct('Male biped model', [ wbString(MODL, 'Model Filename', 0, cpNormal, True), wbByteArray(MODT, 'Texture Files Hashes', 0, cpIgnore), wbMODS, wbMODD ], [], cpNormal, False, nil, True), wbRStruct('Male world model', [ wbString(MOD2, 'Model Filename'), wbByteArray(MO2T, 'Texture Files Hashes', 0, cpIgnore), wbMO2S ], []), wbString(ICON, 'Male icon filename'), wbString(MICO, 'Male mico filename'), wbRStruct('Female biped model', [ wbString(MOD3, 'Model Filename', 0, cpNormal, True), wbByteArray(MO3T, 'Texture Files Hashes', 0, cpIgnore), wbMO3S, wbMOSD ], [], cpNormal, False, nil, True), wbRStruct('Female world model', [ wbString(MOD4, 'Model Filename'), wbByteArray(MO4T, 'Texture Files Hashes', 0, cpIgnore), wbMO4S ], []), wbString(ICO2, 'Female icon filename'), wbString(MIC2, 'Female mico filename'), wbString(BMCT, 'Ragdoll Constraint Template'), wbDEST, wbREPL, wbBIPL, wbETYPReq, wbYNAM, wbZNAM, wbStruct(DATA, 'Data', [ wbInteger('Value', itS32), wbInteger('Max Condition', itS32), wbFloat('Weight') ], cpNormal, True), wbStruct(DNAM, '', [ wbInteger('AR', itS16, wbDiv(100)), wbInteger('Flags', itU16, wbFlags([ 'Modulates Voice' ])) ], cpNormal, True) ]); wbRecord(ARMA, 'Armor Addon', [ wbEDIDReq, wbOBNDReq, wbFULL, wbBMDT, wbRStruct('Male biped model', [ wbString(MODL, 'Model Filename', 0, cpNormal, True), wbByteArray(MODT, 'Texture Files Hashes', 0, cpIgnore), wbMODS, wbMODD ], [], cpNormal, False, nil, True), wbRStruct('Male world model', [ wbString(MOD2, 'Model Filename'), wbByteArray(MO2T, 'Texture Files Hashes', 0, cpIgnore), wbMO2S ], []), wbString(ICON, 'Male icon filename'), wbString(MICO, 'Male mico filename'), wbRStruct('Female biped model', [ wbString(MOD3, 'Model Filename', 0, cpNormal, True), wbByteArray(MO3T, 'Texture Files Hashes', 0, cpIgnore), wbMO3S, wbMOSD ], [], cpNormal, False, nil, True), wbRStruct('Female world model', [ wbString(MOD4, 'Model Filename'), wbByteArray(MO4T, 'Texture Files Hashes', 0, cpIgnore), wbMO4S ], []), wbString(ICO2, 'Female icon filename'), wbString(MIC2, 'Female mico filename'), wbETYPReq, wbStruct(DATA, 'Data', [ wbInteger('Value', itS32), wbInteger('Max Condition', itS32), wbFloat('Weight') ], cpNormal, True), wbStruct(DNAM, '', [ wbInteger('AR', itS16, wbDiv(100)), wbInteger('Flags', itU16, wbFlags([ 'Modulates Voice' ])) ], cpNormal, True) ]); wbRecord(BOOK, 'Book', [ wbEDIDReq, wbOBNDReq, wbFULL, wbMODL, wbICON, wbSCRI, wbDESCReq, wbDEST, wbYNAM, wbZNAM, wbStruct(DATA, 'Data', [ wbInteger('Flags', itU8, wbFlags([ '', 'Can''t be Taken' ])), wbInteger('Skill', itS8, wbSkillEnum), wbInteger('Value', itS32), wbFloat('Weight') ], cpNormal, True) ]); wbSPLO := wbFormIDCk(SPLO, 'Actor Effect', [SPEL]); wbSPLOs := wbRArrayS('Actor Effects', wbSPLO, cpNormal, False, nil, nil, wbActorTemplateUseActorEffectList); wbRecord(CELL, 'Cell', [ wbEDID, wbFULL, wbInteger(DATA, 'Flags', itU8, wbFlags([ {0x01} 'Is Interior Cell', {0x02} 'Has water', {0x04} 'Invert Fast Travel behavior', {0x08} 'No LOD Water', {0x10} '', {0x20} 'Public place', {0x40} 'Hand changed', {0x80} 'Behave like exterior' ]), cpNormal, True), wbStruct(XCLC, 'Grid', [ wbInteger('X', itS32), wbInteger('Y', itS32), wbInteger('Force Hide Land', itU32, wbFlags([ 'Quad 1', 'Quad 2', 'Quad 3', 'Quad 4' ], True)) ], cpNormal, False, nil, 2), wbStruct(XCLL, 'Lighting', [ wbStruct('Ambient Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Directional Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Fog Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbFloat('Fog Near'), wbFloat('Fog Far'), wbInteger('Directional Rotation XY', itS32), wbInteger('Directional Rotation Z', itS32), wbFloat('Directional Fade'), wbFloat('Fog Clip Dist'), wbFloat('Fog Power') ], cpNormal, False, nil, 7), wbArray(IMPF, 'Footstep Materials', wbString('Unknown', 30), [ 'ConcSolid', 'ConcBroken', 'MetalSolid', 'MetalHollow', 'MetalSheet', 'Wood', 'Sand', 'Dirt', 'Grass', 'Water' ]), wbRStruct('Light Template', [ wbFormIDCk(LTMP, 'Template', [LGTM, NULL]), wbInteger(LNAM, 'Inherit', itU32, wbFlags([ {0x00000001}'Ambient Color', {0x00000002}'Directional Color', {0x00000004}'Fog Color', {0x00000008}'Fog Near', {0x00000010}'Fog Far', {0x00000020}'Directional Rotation', {0x00000040}'Directional Fade', {0x00000080}'Clip Distance', {0x00000100}'Fog Power' ]), cpNormal, True) ], [], cpNormal, True ), wbFloat(XCLW, 'Water Height'), wbString(XNAM, 'Water Noise Texture'), wbArrayS(XCLR, 'Regions', wbFormIDCk('Region', [REGN])), wbFormIDCk(XCIM, 'Image Space', [IMGS]), wbByteArray(XCET, 'Unknown', 1, cpIgnore), wbFormIDCk(XEZN, 'Encounter Zone', [ECZN]), wbFormIDCk(XCCM, 'Climate', [CLMT]), wbFormIDCk(XCWT, 'Water', [WATR]), wbRStruct('Ownership', [ wbXOWN, wbInteger(XRNK, 'Faction rank', itS32) ], [XCMT, XCMO]), wbFormIDCk(XCAS, 'Acoustic Space', [ASPC]), wbByteArray(XCMT, 'Unused', 1, cpIgnore), wbFormIDCk(XCMO, 'Music Type', [MUSC]) ], True, wbCellAddInfo, cpNormal, False, wbCELLAfterLoad); wbServiceFlags := wbFlags([ {0x00000001} 'Weapons', {0x00000002} 'Armor', {0x00000004} 'Alcohol', {0x00000008} 'Books', {0x00000010} 'Food', {0x00000020} 'Chems', {0x00000040} 'Stimpacks', {0x00000080} 'Lights?', {0x00000100} '', {0x00000200} '', {0x00000400} 'Miscellaneous', {0x00000800} '', {0x00001000} '', {0x00002000} 'Potions?', {0x00004000} 'Training', {0x00008000} '', {0x00010000} 'Recharge', {0x00020000} 'Repair' ]); wbSpecializationEnum := wbEnum(['Combat', 'Magic', 'Stealth']); wbRecord(CLAS, 'Class', [ wbEDIDReq, wbFULLReq, wbDESCReq, wbICON, wbStruct(DATA, '', [ wbArray('Tag Skills', wbInteger('Tag Skill', itS32, wbActorValueEnum), 4), wbInteger('Flags', itU32, wbFlags(['Playable', 'Guard'], True)), wbInteger('Buys/Sells and Services', itU32, wbServiceFlags), wbInteger('Teaches', itS8, wbSkillEnum), wbInteger('Maximum training level', itU8), wbByteArray('Unused', 2) ], cpNormal, True), wbArray(ATTR, 'Attributes', wbInteger('Attribute', itU8), [ 'Strength', 'Perception', 'Endurance', 'Charisma', 'Intelligence', 'Agility', 'Luck' ], cpNormal, True) ]); end; procedure DefineFO3c; begin wbRecord(CLMT, 'Climate', [ wbEDIDReq, wbArrayS(WLST, 'Weather Types', wbStructSK([0], 'Weather Type', [ wbFormIDCk('Weather', [WTHR, NULL]), wbInteger('Chance', itS32), wbFormIDCk('Global', [GLOB, NULL]) ])), wbString(FNAM, 'Sun Texture'), wbString(GNAM, 'Sun Glare Texture'), wbMODL, wbStruct(TNAM, 'Timing', [ wbStruct('Sunrise', [ wbInteger('Begin', itU8, wbClmtTime), wbInteger('End', itU8, wbClmtTime) ]), wbStruct('Sunset', [ wbInteger('Begin', itU8, wbClmtTime), wbInteger('End', itU8, wbClmtTime) ]), wbInteger('Volatility', itU8), wbInteger('Moons / Phase Length', itU8, wbClmtMoonsPhaseLength) ], cpNormal, True) ]); wbCNTO := wbRStructExSK([0], [1], 'Item', [ wbStructExSK(CNTO, [0], [1], 'Item', [ wbFormIDCk('Item', [ARMO, AMMO, MISC, WEAP, BOOK, LVLI, KEYM, ALCH, NOTE, MSTT{?}, STAT{?}]), wbInteger('Count', itS32) ]), wbCOED ], []); wbCNTOs := wbRArrayS('Items', wbCNTO); wbRecord(CONT, 'Container', [ wbEDIDReq, wbOBNDReq, wbFULL, wbMODL, wbSCRI, wbCNTOs, wbDEST, wbStruct(DATA, '', [ wbInteger('Flags', itU8, wbFlags(['', 'Respawns'])), wbFloat('Weight') ], cpNormal, True), wbFormIDCk(SNAM, 'Sound - Open', [SOUN]), wbFormIDCk(QNAM, 'Sound - Close', [SOUN]) ], True); wbCSDT := wbRStructSK([0], 'Sound Type', [ wbInteger(CSDT, 'Type', itU32,wbEnum([ {0x00} 'Left Foot', {0x01} 'Right Foot', {0x02} 'Left Back Foot', {0x03} 'Right Back Foot', {0x04} 'Idle', {0x05} 'Aware', {0x06} 'Attack', {0x07} 'Hit', {0x08} 'Death', {0x09} 'Weapon', {0x0A} 'Movement', {0x0B} 'Conscious' ])), wbRArrayS('Sounds', wbRStructSK([0], 'Sound', [ wbFormIDCk(CSDI, 'Sound', [SOUN], False, cpNormal, True), wbInteger(CSDC, 'Sound Chance', itU8, nil, cpNormal, True) ], []), cpNormal, True) ], []); wbCSDTs := wbRArrayS('Sound Types', wbCSDT, cpNormal, False, nil, nil, wbActorTemplateUseModelAnimation); wbAgressionEnum := wbEnum([ 'Unaggressive', 'Aggressive', 'Very Aggressive', 'Frenzied' ]); wbConfidenceEnum := wbEnum([ 'Cowardly', 'Cautious', 'Average', 'Brave', 'Foolhardy' ]); wbMoodEnum := wbEnum([ 'Neutral', 'Afraid', 'Annoyed', 'Cocky', 'Drugged', 'Pleasant', 'Angry', 'Sad' ]); wbAssistanceEnum := wbEnum([ 'Helps Nobody', 'Helps Allies', 'Helps Friends and Allies' ]); wbAggroRadiusFlags := wbFlags([ 'Aggro Radius Behavior' ]); wbAIDT := wbStruct(AIDT, 'AI Data', [ {00} wbInteger('Aggression', itU8, wbAgressionEnum), {01} wbInteger('Confidence', itU8, wbConfidenceEnum), {02} wbInteger('Energy Level', itU8), {03} wbInteger('Responsibility', itU8), {04} wbInteger('Mood', itU8, wbMoodEnum), wbByteArray('Unused', 3), {08} wbInteger('Buys/Sells and Services', itU32, wbServiceFlags), {0C} wbInteger('Teaches', itS8, wbSkillEnum), {0D} wbInteger('Maximum training level', itU8), {0E} wbInteger('Assistance', itS8, wbAssistanceEnum), {0F} wbInteger('Aggro Radius Behavior', itU8, wbAggroRadiusFlags), {10} wbInteger('Aggro Radius', itS32) ], cpNormal, True, wbActorTemplateUseAIData); wbAttackAnimationEnum := wbEnum([ ], [ 26, 'AttackLeft', 27, 'AttackLeftUp', 28, 'AttackLeftDown', 29, 'AttackLeftIS', 30, 'AttackLeftISUp', 31, 'AttackLeftISDown', 32, 'AttackRight', 33, 'AttackRightUp', 34, 'AttackRightDown', 35, 'AttackRightIS', 36, 'AttackRightISUp', 37, 'AttackRightISDown', 38, 'Attack3', 39, 'Attack3Up', 40, 'Attack3Down', 41, 'Attack3IS', 42, 'Attack3ISUp', 43, 'Attack3ISDown', 44, 'Attack4', 45, 'Attack4Up', 46, 'Attack4Down', 47, 'Attack4IS', 48, 'Attack4ISUp', 49, 'Attack4ISDown', 50, 'Attack5', 51, 'Attack5Up', 52, 'Attack5Down', 53, 'Attack5IS', 54, 'Attack5ISUp', 55, 'Attack5ISDown', 56, 'Attack6', 57, 'Attack6Up', 58, 'Attack6Down', 59, 'Attack6IS', 60, 'Attack6ISUp', 61, 'Attack6ISDown', 62, 'Attack7', 63, 'Attack7Up', 64, 'Attack7Down', 65, 'Attack7IS', 66, 'Attack7ISUp', 67, 'Attack7ISDown', 68, 'Attack8', 69, 'Attack8Up', 70, 'Attack8Down', 71, 'Attack8IS', 72, 'Attack8ISUp', 73, 'Attack8ISDown', 74, 'AttackLoop', 75, 'AttackLoopUp', 76, 'AttackLoopDown', 77, 'AttackLoopIS', 78, 'AttackLoopISUp', 79, 'AttackLoopISDown', 80, 'AttackSpin', 81, 'AttackSpinUp', 82, 'AttackSpinDown', 83, 'AttackSpinIS', 84, 'AttackSpinISUp', 85, 'AttackSpinISDown', 86, 'AttackSpin2', 87, 'AttackSpin2Up', 88, 'AttackSpin2Down', 89, 'AttackSpin2IS', 90, 'AttackSpin2ISUp', 91, 'AttackSpin2ISDown', 92, 'AttackPower', 93, 'AttackForwardPower', 94, 'AttackBackPower', 95, 'AttackLeftPower', 96, 'AttackRightPower', 97, 'PlaceMine', 98, 'PlaceMineUp', 99, 'PlaceMineDown', 100, 'PlaceMineIS', 101, 'PlaceMineISUp', 102, 'PlaceMineISDown', 103, 'PlaceMine2', 104, 'PlaceMine2Up', 105, 'PlaceMine2Down', 106, 'PlaceMine2IS', 107, 'PlaceMine2ISUp', 108, 'PlaceMine2ISDown', 109, 'AttackThrow', 110, 'AttackThrowUp', 111, 'AttackThrowDown', 112, 'AttackThrowIS', 113, 'AttackThrowISUp', 114, 'AttackThrowISDown', 115, 'AttackThrow2', 116, 'AttackThrow2Up', 117, 'AttackThrow2Down', 118, 'AttackThrow2IS', 119, 'AttackThrow2ISUp', 120, 'AttackThrow2ISDown', 121, 'AttackThrow3', 122, 'AttackThrow3Up', 123, 'AttackThrow3Down', 124, 'AttackThrow3IS', 125, 'AttackThrow3ISUp', 126, 'AttackThrow3ISDown', 127, 'AttackThrow4', 128, 'AttackThrow4Up', 129, 'AttackThrow4Down', 130, 'AttackThrow4IS', 131, 'AttackThrow4ISUp', 132, 'AttackThrow4ISDown', 133, 'AttackThrow5', 134, 'AttackThrow5Up', 135, 'AttackThrow5Down', 136, 'AttackThrow5IS', 137, 'AttackThrow5ISUp', 138, 'AttackThrow5ISDown', 167, 'PipBoy', 178, 'PipBoyChild', 255, ' ANY' ]); wbImpactMaterialTypeEnum := wbEnum([ 'Stone', 'Dirt', 'Grass', 'Glass', 'Metal', 'Wood', 'Organic', 'Cloth', 'Water', 'Hollow Metal', 'Organic Bug', 'Organic Glow' ]); wbTemplateFlags := wbFlags([ 'Use Traits', 'Use Stats', 'Use Factions', 'Use Actor Effect List', 'Use AI Data', 'Use AI Packages', 'Use Model/Animation', 'Use Base Data', 'Use Inventory', 'Use Script' ]); wbRecord(CREA, 'Creature', [ wbEDIDReq, wbOBNDReq, wbFULLActor, wbMODLActor, wbSPLOs, wbFormIDCk(EITM, 'Unarmed Attack Effect', [ENCH, SPEL], False, cpNormal, False, wbActorTemplateUseActorEffectList), wbInteger(EAMT, 'Unarmed Attack Animation', itU16, wbAttackAnimationEnum, cpNormal, True, False, wbActorTemplateUseActorEffectList), wbArrayS(NIFZ, 'Model List', wbStringLC('Model'), 0, cpNormal, False, nil, nil, wbActorTemplateUseModelAnimation), wbByteArray(NIFT, 'Texture Files Hashes', 0, cpIgnore, False, False, wbActorTemplateUseModelAnimation), wbStruct(ACBS, 'Configuration', [ {00} wbInteger('Flags', itU32, wbFlags([ {0x000001} 'Biped', {0x000002} 'Essential', {0x000004} 'Weapon & Shield?', {0x000008} 'Respawn', {0x000010} 'Swims', {0x000020} 'Flies', {0x000040} 'Walks', {0x000080} 'PC Level Mult', {0x000100} 'Unknown 8', {0x000200} 'No Low Level Processing', {0x000400} '', {0x000800} 'No Blood Spray', {0x001000} 'No Blood Decal', {0x002000} '', {0x004000} '', {0x008000} 'No Head', {0x010000} 'No Right Arm', {0x020000} 'No Left Arm', {0x040000} 'No Combat in Water', {0x080000} 'No Shadow', {0x100000} 'No VATS Melee', {0x00200000} 'Allow PC Dialogue', {0x00400000} 'Can''t Open Doors', {0x00800000} 'Immobile', {0x01000000} 'Tilt Front/Back', {0x02000000} 'Tilt Left/Right', {0x03000000} 'No Knockdowns', {0x08000000} 'Not Pushable', {0x10000000} 'Allow Pickpocket', {0x20000000} 'Is Ghost', {0x40000000} 'No Rotating To Head-track', {0x80000000} 'Invulnerable' ], [ {0x000001 Biped} wbActorTemplateUseModelAnimation, {0x000002 Essential} wbActorTemplateUseBaseData, {0x000004 Weapon & Shield} nil, {0x000008 Respawn} wbActorTemplateUseBaseData, {0x000010 Swims} wbActorTemplateUseModelAnimation, {0x000020 Flies} wbActorTemplateUseModelAnimation, {0x000040 Walks} wbActorTemplateUseModelAnimation, {0x000080 PC Level Mult} wbActorTemplateUseStats, {0x000100 Unknown 8} nil, {0x000200 No Low Level Processing} wbActorTemplateUseBaseData, {0x000400 } nil, {0x000800 No Blood Spray} wbActorTemplateUseModelAnimation, {0x001000 No Blood Decal} wbActorTemplateUseModelAnimation, {0x002000 } nil, {0x004000 } nil, {0x008000 No Head} wbActorTemplateUseModelAnimation, {0x010000 No Right Arm} wbActorTemplateUseModelAnimation, {0x020000 No Left Arm} wbActorTemplateUseModelAnimation, {0x040000 No Combat in Water} wbActorTemplateUseModelAnimation, {0x080000 No Shadow} wbActorTemplateUseModelAnimation, {0x100000 No VATS Melee} nil, {0x00200000 Allow PC Dialogue} wbActorTemplateUseBaseData, {0x00400000 Can''t Open Doors} wbActorTemplateUseBaseData, {0x00800000 Immobile} wbActorTemplateUseModelAnimation, {0x01000000 Tilt Front/Back} wbActorTemplateUseModelAnimation, {0x02000000 Tilt Left/Right} wbActorTemplateUseModelAnimation, {0x03000000 No Knockdowns} nil, {0x08000000 Not Pushable} wbActorTemplateUseModelAnimation, {0x10000000 Allow Pickpocket} wbActorTemplateUseBaseData, {0x20000000 Is Ghost} nil, {0x40000000 No Rotating To Head-track} wbActorTemplateUseModelAnimation, {0x80000000 Invulnerable} nil ])), {04} wbInteger('Fatigue', itU16, nil, cpNormal, False, wbActorTemplateUseStats), {06} wbInteger('Barter gold', itU16, nil, cpNormal, False, wbActorTemplateUseAIData), {08} wbUnion('Level', wbCreaLevelDecider, [ wbInteger('Level', itS16, nil, cpNormal, False, wbActorTemplateUseStats), wbInteger('Level Mult', itS16, wbDiv(1000), cpNormal, False, wbActorTemplateUseStats) ], cpNormal, False, wbActorTemplateUseStats), {10} wbInteger('Calc min', itU16, nil, cpNormal, False, wbActorTemplateUseStats), {12} wbInteger('Calc max', itU16, nil, cpNormal, False, wbActorTemplateUseStats), {14} wbInteger('Speed Multiplier', itU16, nil, cpNormal, False, wbActorTemplateUseStats), {16} wbFloat('Karma (Alignment)', cpNormal, False, 1, -1, wbActorTemplateUseTraits), {20} wbInteger('Disposition Base', itS16, nil, cpNormal, False, wbActorTemplateUseTraits), {22} wbInteger('Template Flags', itU16, wbTemplateFlags) ], cpNormal, True), wbRArrayS('Factions', wbStructSK(SNAM, [0], 'Faction', [ wbFormIDCk('Faction', [FACT]), wbInteger('Rank', itU8), wbByteArray('Unused', 3) ]), cpNormal, False, nil, nil, wbActorTemplateUseFactions), wbFormIDCk(INAM, 'Death item', [LVLI], False, cpNormal, False, wbActorTemplateUseTraits), wbFormIDCk(VTCK, 'Voice', [VTYP], False, cpNormal, False, wbActorTemplateUseTraits), wbFormIDCk(TPLT, 'Template', [CREA, LVLC]), wbDESTActor, wbSCRIActor, wbRArrayS('Items', wbCNTO, cpNormal, False, nil, nil, wbActorTemplateUseInventory), wbAIDT, wbRArray('Packages', wbFormIDCk(PKID, 'Package', [PACK]), cpNormal, False, nil, nil, wbActorTemplateUseAIPackages), wbArrayS(KFFZ, 'Animations', wbStringLC('Animation'), 0, cpNormal, False, nil, nil, wbActorTemplateUseModelAnimation), wbStruct(DATA, '', [ {00} wbInteger('Type', itU8, wbCreatureTypeEnum, cpNormal, False, wbActorTemplateUseTraits), {01} wbInteger('Combat Skill', itU8, nil, cpNormal, False, wbActorTemplateUseStats), {02} wbInteger('Magic Skill', itU8, nil, cpNormal, False, wbActorTemplateUseStats), {03} wbInteger('Stealth Skill', itU8, nil, cpNormal, False, wbActorTemplateUseStats), {04} wbInteger('Health', itS16, nil, cpNormal, False, wbActorTemplateUseStats), {06} wbByteArray('Unused', 2), {08} wbInteger('Damage', itS16, nil, cpNormal, False, wbActorTemplateUseStats), {10} wbArray('Attributes', wbInteger('Attribute', itU8), [ 'Strength', 'Perception', 'Endurance', 'Charisma', 'Intelligence', 'Agility', 'Luck' ], cpNormal, False, wbActorTemplateUseStats) ], cpNormal, True), wbInteger(RNAM, 'Attack reach', itU8, nil, cpNormal, True, False, wbActorTemplateUseTraits), wbFormIDCk(ZNAM, 'Combat Style', [CSTY], False, cpNormal, False, wbActorTemplateUseTraits), wbFormIDCk(PNAM, 'Body Part Data', [BPTD], False, cpNormal, True, wbActorTemplateUseModelAnimation), wbFloat(TNAM, 'Turning Speed', cpNormal, True, 1, -1, wbActorTemplateUseStats), wbFloat(BNAM, 'Base Scale', cpNormal, True, 1, -1, wbActorTemplateUseStats), wbFloat(WNAM, 'Foot Weight', cpNormal, True, 1, -1, wbActorTemplateUseStats), wbInteger(NAM4, 'Impact Material Type', itU32, wbImpactMaterialTypeEnum, cpNormal, True, False, wbActorTemplateUseModelAnimation), wbInteger(NAM5, 'Sound Level', itU32, wbSoundLevelEnum, cpNormal, True, False, wbActorTemplateUseModelAnimation), wbFormIDCk(CSCR, 'Inherits Sounds from', [CREA], False, cpNormal, False, wbActorTemplateUseModelAnimation), wbCSDTs, wbFormIDCk(CNAM, 'Impact Dataset', [IPDS], False, cpNormal, False, wbActorTemplateUseModelAnimation), wbFormIDCk(LNAM, 'Melee Weapon List', [FLST], False, cpNormal, False, wbActorTemplateUseTraits) ], True); end; procedure DefineFO3d; begin wbRecord(CSTY, 'Combat Style', [ wbEDIDReq, wbStruct(CSTD, 'Advanced - Standard', [ {000}wbInteger('Maneuver Decision - Dodge % Chance', itU8), {001}wbInteger('Maneuver Decision - Left/Right % Chance', itU8), {002}wbByteArray('Unused', 2), {004}wbFloat('Maneuver Decision - Dodge L/R Timer (min)'), {008}wbFloat('Maneuver Decision - Dodge L/R Timer (max)'), {012}wbFloat('Maneuver Decision - Dodge Forward Timer (min)'), {016}wbFloat('Maneuver Decision - Dodge Forward Timer (max)'), {020}wbFloat('Maneuver Decision - Dodge Back Timer Min'), {024}wbFloat('Maneuver Decision - Dodge Back Timer Max'), {028}wbFloat('Maneuver Decision - Idle Timer min'), {032}wbFloat('Maneuver Decision - Idle Timer max'), {036}wbInteger('Melee Decision - Block % Chance', itU8), {037}wbInteger('Melee Decision - Attack % Chance', itU8), {038}wbByteArray('Unused', 2), {040}wbFloat('Melee Decision - Recoil/Stagger Bonus to Attack'), {044}wbFloat('Melee Decision - Unconscious Bonus to Attack'), {048}wbFloat('Melee Decision - Hand-To-Hand Bonus to Attack'), {052}wbInteger('Melee Decision - Power Attacks - Power Attack % Chance', itU8), {053}wbByteArray('Unused', 3), {056}wbFloat('Melee Decision - Power Attacks - Recoil/Stagger Bonus to Power'), {060}wbFloat('Melee Decision - Power Attacks - Unconscious Bonus to Power Attack'), {064}wbInteger('Melee Decision - Power Attacks - Normal', itU8), {065}wbInteger('Melee Decision - Power Attacks - Forward', itU8), {066}wbInteger('Melee Decision - Power Attacks - Back', itU8), {067}wbInteger('Melee Decision - Power Attacks - Left', itU8), {068}wbInteger('Melee Decision - Power Attacks - Right', itU8), {069}wbByteArray('Unused', 3), {072}wbFloat('Melee Decision - Hold Timer (min)'), {076}wbFloat('Melee Decision - Hold Timer (max)'), {080}wbInteger('Flags', itU16, wbFlags([ 'Choose Attack using % Chance', 'Melee Alert OK', 'Flee Based on Personal Survival', '', 'Ignore Threats', 'Ignore Damaging Self', 'Ignore Damaging Group', 'Ignore Damaging Spectators', 'Cannot Use Stealthboy' ])), {082}wbByteArray('Unused', 2), {085}wbInteger('Maneuver Decision - Acrobatic Dodge % Chance', itU8), {085}wbInteger('Melee Decision - Power Attacks - Rushing Attack % Chance', itU8), {086}wbByteArray('Unused', 2), {088}wbFloat('Melee Decision - Power Attacks - Rushing Attack Distance Mult') ], cpNormal, True), wbStruct(CSAD, 'Advanced - Advanced', [ wbFloat('Dodge Fatigue Mod Mult'), wbFloat('Dodge Fatigue Mod Base'), wbFloat('Encumb. Speed Mod Base'), wbFloat('Encumb. Speed Mod Mult'), wbFloat('Dodge While Under Attack Mult'), wbFloat('Dodge Not Under Attack Mult'), wbFloat('Dodge Back While Under Attack Mult'), wbFloat('Dodge Back Not Under Attack Mult'), wbFloat('Dodge Forward While Attacking Mult'), wbFloat('Dodge Forward Not Attacking Mult'), wbFloat('Block Skill Modifier Mult'), wbFloat('Block Skill Modifier Base'), wbFloat('Block While Under Attack Mult'), wbFloat('Block Not Under Attack Mult'), wbFloat('Attack Skill Modifier Mult'), wbFloat('Attack Skill Modifier Base'), wbFloat('Attack While Under Attack Mult'), wbFloat('Attack Not Under Attack Mult'), wbFloat('Attack During Block Mult'), wbFloat('Power Att. Fatigue Mod Base'), wbFloat('Power Att. Fatigue Mod Mult') ], cpNormal, True), wbStruct(CSSD, 'Simple', [ {00} wbFloat('Cover Search Radius'), {04} wbFloat('Take Cover Chance'), {08} wbFloat('Wait Timer (min)'), {12} wbFloat('Wait Timer (max)'), {16} wbFloat('Wait to Fire Timer (min)'), {20} wbFloat('Wait to Fire Timer (max)'), {24} wbFloat('Fire Timer (min)'), {28} wbFloat('Fire Timer (max)'), {32} wbFloat('Ranged Weapon Range Mult (min)'), {36} wbByteArray('Unused', 4), {40} wbInteger('Weapon Restrictions', itU32, wbEnum([ 'None', 'Melee Only', 'Ranged Only' ])), {44} wbFloat('Ranged Weapon Range Mult (max)'), {48} wbFloat('Max Targeting FOV'), {52} wbFloat('Combat Radius'), {56} wbFloat('Semi-Auto Firing Delay Mult (min)'), {60} wbFloat('Semi-Auto Firing Delay Mult (max)') ], cpNormal, True) ]); wbRecord(DIAL, 'Dialog Topic', [ wbEDIDReq, wbRArrayS('Quests', wbFormIDCkNoReach(QSTI, 'Quest', [QUST], False, cpBenign)), wbRArrayS('Quests?', wbFormIDCkNoReach(QSTR, 'Quest?', [QUST], False, cpBenign)), wbFULL, wbFloat(PNAM, 'Priority', cpNormal, True, 1, -1, nil, nil, 50.0), wbStruct(DATA, '', [ wbInteger('Type', itU8, wbEnum([ {0} 'Topic', {1} 'Conversation', {2} 'Combat', {3} 'Persuasion', {4} 'Detection', {5} 'Service', {6} 'Miscellaneous', {7} 'Radio' ])), wbInteger('Flags', itU8, wbFlags([ 'Rumors', 'Top-level' ])) ], cpNormal, True, nil, 1) ], True); wbRecord(DOOR, 'Door', [ wbEDIDReq, wbOBNDReq, wbFULL, wbMODLReq, wbSCRI, wbDEST, wbFormIDCk(SNAM, 'Sound - Open', [SOUN]), wbFormIDCk(ANAM, 'Sound - Close', [SOUN]), wbFormIDCk(BNAM, 'Sound - Looping', [SOUN]), wbInteger(FNAM, 'Flags', itU8, wbFlags([ '', 'Automatic Door', 'Hidden', 'Minimal Use', 'Sliding Door' ]), cpNormal, True) ]); wbBlendModeEnum := wbEnum([ '', 'Zero', 'One', 'Source Color', 'Source Inverse Color', 'Source Alpha', 'Source Inverted Alpha', 'Dest Alpha', 'Dest Inverted Alpha', 'Dest Color', 'Dest Inverse Color', 'Source Alpha SAT' ]); wbBlendOpEnum := wbEnum([ '', 'Add', 'Subtract', 'Reverse Subtract', 'Minimum', 'Maximum' ]); wbZTestFuncEnum := wbEnum([ '', '', '', 'Equal To', 'Normal', 'Greater Than', '', 'Greater Than or Equal Than', 'Always Show' ]); wbRecord(EFSH, 'Effect Shader', [ wbEDID, wbString(ICON, 'Fill Texture'), wbString(ICO2, 'Particle Shader Texture'), wbString(NAM7, 'Holes Texture'), wbStruct(DATA, '', [ wbInteger('Flags', itU8, wbFlags([ {0} 'No Membrane Shader', {1} '', {2} '', {3} 'No Particle Shader', {4} 'Edge Effect - Inverse', {5} 'Membrane Shader - Affect Skin Only' ])), wbByteArray('Unused', 3), wbInteger('Membrane Shader - Source Blend Mode', itU32, wbBlendModeEnum), wbInteger('Membrane Shader - Blend Operation', itU32, wbBlendOpEnum), wbInteger('Membrane Shader - Z Test Function', itU32, wbZTestFuncEnum), wbStruct('Fill/Texture Effect - Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbFloat('Fill/Texture Effect - Alpha Fade In Time'), wbFloat('Fill/Texture Effect - Full Alpha Time'), wbFloat('Fill/Texture Effect - Alpha Fade Out Time'), wbFloat('Fill/Texture Effect - Presistent Alpha Ratio'), wbFloat('Fill/Texture Effect - Alpha Pulse Amplitude'), wbFloat('Fill/Texture Effect - Alpha Pulse Frequency'), wbFloat('Fill/Texture Effect - Texture Animation Speed (U)'), wbFloat('Fill/Texture Effect - Texture Animation Speed (V)'), wbFloat('Edge Effect - Fall Off'), wbStruct('Edge Effect - Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbFloat('Edge Effect - Alpha Fade In Time'), wbFloat('Edge Effect - Full Alpha Time'), wbFloat('Edge Effect - Alpha Fade Out Time'), wbFloat('Edge Effect - Persistent Alpha Ratio'), wbFloat('Edge Effect - Alpha Pulse Amplitude'), wbFloat('Edge Effect - Alpha Pusle Frequence'), wbFloat('Fill/Texture Effect - Full Alpha Ratio'), wbFloat('Edge Effect - Full Alpha Ratio'), wbInteger('Membrane Shader - Dest Blend Mode', itU32, wbBlendModeEnum), wbInteger('Particle Shader - Source Blend Mode', itU32, wbBlendModeEnum), wbInteger('Particle Shader - Blend Operation', itU32, wbBlendOpEnum), wbInteger('Particle Shader - Z Test Function', itU32, wbZTestFuncEnum), wbInteger('Particle Shader - Dest Blend Mode', itU32, wbBlendModeEnum), wbFloat('Particle Shader - Particle Birth Ramp Up Time'), wbFloat('Particle Shader - Full Particle Birth Time'), wbFloat('Particle Shader - Particle Birth Ramp Down Time'), wbFloat('Particle Shader - Full Particle Birth Ratio'), wbFloat('Particle Shader - Persistant Particle Birth Ratio'), wbFloat('Particle Shader - Particle Lifetime'), wbFloat('Particle Shader - Particle Lifetime +/-'), wbFloat('Particle Shader - Initial Speed Along Normal'), wbFloat('Particle Shader - Acceleration Along Normal'), wbFloat('Particle Shader - Initial Velocity #1'), wbFloat('Particle Shader - Initial Velocity #2'), wbFloat('Particle Shader - Initial Velocity #3'), wbFloat('Particle Shader - Acceleration #1'), wbFloat('Particle Shader - Acceleration #2'), wbFloat('Particle Shader - Acceleration #3'), wbFloat('Particle Shader - Scale Key 1'), wbFloat('Particle Shader - Scale Key 2'), wbFloat('Particle Shader - Scale Key 1 Time'), wbFloat('Particle Shader - Scale Key 2 Time'), wbStruct('Color Key 1 - Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Color Key 2 - Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Color Key 3 - Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbFloat('Color Key 1 - Color Alpha'), wbFloat('Color Key 2 - Color Alpha'), wbFloat('Color Key 3 - Color Alpha'), wbFloat('Color Key 1 - Color Key Time'), wbFloat('Color Key 2 - Color Key Time'), wbFloat('Color Key 3 - Color Key Time'), wbFloat('Particle Shader - Initial Speed Along Normal +/-'), wbFloat('Particle Shader - Initial Rotation (deg)'), wbFloat('Particle Shader - Initial Rotation (deg) +/-'), wbFloat('Particle Shader - Rotation Speed (deg/sec)'), wbFloat('Particle Shader - Rotation Speed (deg/sec) +/-'), wbFormIDCk('Addon Models', [DEBR, NULL]), wbFloat('Holes - Start Time'), wbFloat('Holes - End Time'), wbFloat('Holes - Start Val'), wbFloat('Holes - End Val'), wbFloat('Edge Width (alpha units)'), wbStruct('Edge Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbFloat('Explosion Wind Speed'), wbInteger('Texture Count U', itU32), wbInteger('Texture Count V', itU32), wbFloat('Addon Models - Fade In Time'), wbFloat('Addon Models - Fade Out Time'), wbFloat('Addon Models - Scale Start'), wbFloat('Addon Models - Scale End'), wbFloat('Addon Models - Scale In Time'), wbFloat('Addon Models - Scale Out Time') ], cpNormal, True, nil, 57) ], False, nil, cpNormal, False, wbEFSHAfterLoad); wbRecord(ENCH, 'Object Effect', [ wbEDIDReq, wbFULL, wbStruct(ENIT, 'Effect Data', [ wbInteger('Type', itU32, wbEnum([ {0} '', {1} '', {2} 'Weapon', {3} 'Apparel' ])), wbByteArray('Unused', 4), wbByteArray('Unused', 4), wbInteger('Flags', itU8, wbFlags([ 'No Auto-Calc', '', 'Hide Effect' ])), wbByteArray('Unused', 3) ], cpNormal, True), wbEffectsReq ]); wbRecord(EYES, 'Eyes', [ wbEDIDReq, wbFULLReq, wbString(ICON, 'Texture', 0{, cpNormal, True??}), wbInteger(DATA, 'Flags', itU8, wbFlags([ 'Playable', 'Not Male', 'Not Female' ]), cpNormal, True) ]); wbXNAM := wbStructSK(XNAM, [0], 'Relation', [ wbFormIDCkNoReach('Faction', [FACT, RACE]), wbInteger('Modifier', itS32), wbInteger('Group Combat Reaction', itU32, wbEnum([ 'Neutral', 'Enemy', 'Ally', 'Friend' ])) ]); wbXNAMs := wbRArrayS('Relations', wbXNAM); wbRecord(FACT, 'Faction', [ wbEDIDReq, wbFULL, wbXNAMs, wbStruct(DATA, '', [ wbInteger('Flags 1', itU8, wbFlags([ 'Hidden from PC', 'Evil', 'Special Combat' ])), wbInteger('Flags 2', itU8, wbFlags([ 'Track Crime', 'Allow Sell' ])), wbByteArray('Unused', 2) ], cpNormal, True, nil, 1), wbFloat(CNAM, 'Unused'), wbRStructsSK('Ranks', 'Rank', [0], [ wbInteger(RNAM, 'Rank#', itS32), wbString(MNAM, 'Male', 0, cpTranslate), wbString(FNAM, 'Female', 0, cpTranslate), wbString(INAM, 'Insignia (Unused)') ], []) ], False, nil, cpNormal, False, wbFACTAfterLoad); wbRecord(FURN, 'Furniture', [ wbEDIDReq, wbOBNDReq, wbFULL, wbMODLReq, wbSCRI, wbDEST, wbByteArray(MNAM, 'Marker Flags', 0, cpNormal, True) ]); wbRecord(GLOB, 'Global', [ wbEDIDReq, wbInteger(FNAM, 'Type', itU8, wbGLOBFNAM, nil, cpNormal, True), wbFloat(FLTV, 'Value', cpNormal, True) ]); wbRecord(GMST, 'Game Setting', [ wbString(EDID, 'Editor ID', 0, cpCritical, True, nil, wbGMSTEDIDAfterSet), wbUnion(DATA, 'Value', wbGMSTUnionDecider, [ wbString('', 0, cpTranslate), wbInteger('', itS32), wbFloat('') ], cpNormal, True) ]); wbDODT := wbStruct(DODT, 'Decal Data', [ wbFloat('Min Width'), wbFloat('Max Width'), wbFloat('Min Height'), wbFloat('Max Height'), wbFloat('Depth'), wbFloat('Shininess'), wbStruct('Parallax', [ wbFloat('Scale'), wbInteger('Passes', itU8) ]), wbInteger('Flags', itU8, wbFlags([ 'Parallax', 'Alpha - Blending', 'Alpha - Testing' ], True)), wbByteArray('Unused', 2), wbStruct('Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]) ]); wbRecord(TXST, 'Texture Set', [ wbEDIDReq, wbOBNDReq, wbRStruct('Textures (RGB/A)', [ wbString(TX00,'Base Image / Transparency'), wbString(TX01,'Normal Map / Specular'), wbString(TX02,'Environment Map Mask / ?'), wbString(TX03,'Glow Map / Unused'), wbString(TX04,'Parallax Map / Unused'), wbString(TX05,'Environment Map / Unused') ], []), wbDODT, wbInteger(DNAM, 'Flags', itU16, wbFlags([ 'No Specular Map' ]), cpNormal, True) ]); wbRecord(MICN, 'Menu Icon', [ wbEDIDReq, wbICONReq ]); wbRecord(HDPT, 'Head Part', [ wbEDIDReq, wbFULLReq, wbMODL, wbInteger(DATA, 'Flags', itU8, wbFlags([ 'Playable' ]), cpNormal, True), wbRArrayS('Extra Parts', wbFormIDCk(HNAM, 'Part', [HDPT]) ) ]); wbRecord(ASPC, 'Acoustic Space', [ wbEDIDReq, wbOBNDReq, wbFormIDCk(SNAM, 'Sound - Looping', [SOUN]), wbFormIDCk(RDAT, 'Use Sound from Region (Interiors Only)', [REGN]), wbInteger(ANAM, 'Environment Type', itU32, wbEnum([ 'None', 'Default', 'Generic', 'Padded Cell', 'Room', 'Bathroom', 'Livingroom', 'Stone Room', 'Auditorium', 'Concerthall', 'Cave', 'Arena', 'Hangar', 'Carpeted Hallway', 'Hallway', 'Stone Corridor', 'Alley', 'Forest', 'City', 'Mountains', 'Quarry', 'Plain', 'Parkinglot', 'Sewerpipe', 'Underwater', 'Small Room', 'Medium Room', 'Large Room', 'Medium Hall', 'Large Hall', 'Plate' ]), cpNormal, True) ]); wbRecord(TACT, 'Talking Activator', [ wbEDIDReq, wbOBNDReq, wbFULL, wbMODLReq, wbSCRI, wbDEST, wbFormIDCk(SNAM, 'Sound', [SOUN]), wbFormIDCk(VNAM, 'Voice Type', [VTYP]) ]); wbRecord(SCPT, 'Script', [ wbEDIDReq, wbSCHRReq, wbByteArray(SCDA, 'Compiled Script'), wbStringScript(SCTX, 'Script Source', 0, cpNormal{, True}), wbRArrayS('Local Variables', wbRStructSK([0], 'Local Variable', [ wbSLSD, wbString(SCVR, 'Name', 0, cpCritical, True) ], [])), wbSCROs ]); wbRecord(TERM, 'Terminal', [ wbEDIDReq, wbOBNDReq, wbFULL, wbMODL, wbSCRI, wbDEST, wbDESCReq, wbFormIDCk(SNAM, 'Sound - Looping', [SOUN]), wbFormIDCk(PNAM, 'Password Note', [NOTE]), wbStruct(DNAM, '', [ wbInteger('Base Hacking Difficulty', itU8, wbEnum([ 'Very Easy', 'Easy', 'Average', 'Hard', 'Very Hard', 'Requires Key' ])), wbInteger('Flags', itU8, wbFlags([ 'Leveled', 'Unlocked', 'Alternate Colors', 'Hide Welcome Text when displaying Image' ])), wbInteger('ServerType', itU8, wbEnum([ '-Server 1-', '-Server 2-', '-Server 3-', '-Server 4-', '-Server 5-', '-Server 6-', '-Server 7-', '-Server 8-', '-Server 9-', '-Server 10-' ])), wbByteArray('Unused', 1) ], cpNormal, True), wbRArray('Menu Items', wbRStruct('Menu Item', [ wbString(ITXT, 'Item Text'), wbString(RNAM, 'Result Text', 0, cpNormal, True), wbInteger(ANAM, 'Flags', itU8, wbFlags([ 'Add Note', 'Force Redraw' ]), cpNormal, True), wbFormIDCk(INAM, 'Display Note', [NOTE]), wbFormIDCk(TNAM, 'Sub Menu', [TERM]), wbEmbeddedScriptReq, wbCTDAs ], []) ) ]); wbRecord(SCOL, 'Static Collection', [ wbEDIDReq, wbOBNDReq, wbMODLReq, wbRStructsSK('Parts', 'Part', [0], [ wbFormIDCk(ONAM, 'Static', [STAT]), wbArrayS(DATA, 'Placements', wbStruct('Placement', [ wbStruct('Position', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), wbStruct('Rotation', [ wbFloat('X', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Y', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Z', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize) ]), wbFloat('Scale') ]), 0, cpNormal, True) ], [], cpNormal, True) ]); wbRecord(MSTT, 'Moveable Static', [ wbEDIDReq, wbOBNDReq, wbFULL, wbMODLReq, wbDEST, wbByteArray(DATA, 'Unknown', 1, cpNormal, True), wbFormIDCk(SNAM, 'Sound', [SOUN]) ]); wbRecord(PWAT, 'Placeable Water', [ wbEDIDReq, wbOBNDReq, wbMODLReq, wbStruct(DNAM, '', [ wbInteger('Flags', itU32, wbFlags([ {0x00000001}'Reflects', {0x00000002}'Reflects - Actors', {0x00000004}'Reflects - Land', {0x00000008}'Reflects - LOD Land', {0x00000010}'Reflects - LOD Buildings', {0x00000020}'Reflects - Trees', {0x00000040}'Reflects - Sky', {0x00000080}'Reflects - Dynamic Objects', {0x00000100}'Reflects - Dead Bodies', {0x00000200}'Refracts', {0x00000400}'Refracts - Actors', {0x00000800}'Refracts - Land', {0x00001000}'', {0x00002000}'', {0x00004000}'', {0x00008000}'', {0x00010000}'Refracts - Dynamic Objects', {0x00020000}'Refracts - Dead Bodies', {0x00040000}'Silhouette Reflections', {0x00080000}'', {0x00100000}'', {0x00200000}'', {0x00400000}'', {0x00800000}'', {0x01000000}'', {0x02000000}'', {0x03000000}'', {0x08000000}'', {0x10000000}'Depth', {0x20000000}'Object Texture Coordinates', {0x40000000}'', {0x80000000}'No Underwater Fog' ])), wbFormIDCk('Water', [WATR]) ], cpNormal, True) ]); wbRecord(IDLM, 'Idle Marker', [ wbEDIDReq, wbOBNDReq, wbInteger(IDLF, 'Flags', itU8, wbFlags([ 'Run in Sequence', '', 'Do Once' ]), cpNormal, True), wbStruct(IDLC, '', [ wbInteger('Animation Count', itU8), wbByteArray('Unused', 3) ], cpNormal, True, nil, 1), wbFloat(IDLT, 'Idle Timer Setting', cpNormal, True), wbArray(IDLA, 'Animations', wbFormIDCk('Animation', [IDLE, NULL]), 0, nil, wbIDLAsAfterSet, cpNormal, True) // NULL looks valid if IDLS\Animation Count is 0 ], False, nil, cpNormal, False, nil, wbAnimationsAfterSet); wbRecord(NOTE, 'Note', [ wbEDIDReq, wbOBNDReq, wbFULL, wbMODL, wbICON, wbYNAM, wbZNAM, wbInteger(DATA, 'Type', itU8, wbEnum([ 'Sound', 'Text', 'Image', 'Voice' ]), cpNormal, True), wbRArrayS('Quests', wbFormIDCkNoReach(ONAM, 'Quest', [QUST]) ), wbString(XNAM, 'Texture'), wbUnion(TNAM, 'Text / Topic', wbNOTETNAMDecide, [ wbString('Text'), wbFormIDCk('Topic', [DIAL]) ]), wbUnion(SNAM, 'Sound / NPC', wbNOTESNAMDecide, [ wbFormIDCk('Sound', [SOUN]), wbFormIDCk('NPC', [NPC_]) ]) ]); end; procedure DefineFO3e; begin wbRecord(PROJ, 'Projectile', [ wbEDIDReq, wbOBNDReq, wbFULL, wbMODLReq, wbDEST, wbStruct(DATA, 'Data', [ {00} wbInteger('Flags', itU16, wbFlags([ 'Hitscan', 'Explosion', 'Alt. Trigger', 'Muzzle Flash', '', 'Can Be Disabled', 'Can Be Picked Up', 'Supersonic', 'Pins Limbs', 'Pass Through Small Transparent' ])), {00} wbInteger('Type', itU16, wbEnum([ {00} '', {01} 'Missile', {02} 'Lobber', {03} '', {04} 'Beam', {05} '', {06} '', {07} '', {08} 'Flame' ])), {04} wbFloat('Gravity'), {08} wbFloat('Speed'), {12} wbFloat('Range'), {16} wbFormIDCk('Light', [LIGH, NULL]), {20} wbFormIDCk('Muzzle Flash - Light', [LIGH, NULL]), {24} wbFloat('Tracer Chance'), {28} wbFloat('Explosion - Alt. Trigger - Proximity'), {32} wbFloat('Explosion - Alt. Trigger - Timer'), {36} wbFormIDCk('Explosion', [EXPL, NULL]), {40} wbFormIDCk('Sound', [SOUN, NULL]), {44} wbFloat('Muzzle Flash - Duration'), {48} wbFloat('Fade Duration'), {52} wbFloat('Impact Force'), {56} wbFormIDCk('Sound - Countdown', [SOUN, NULL]), {60} wbFormIDCk('Sound - Disable', [SOUN, NULL]), {64} wbFormIDCk('Default Weapon Source', [WEAP, NULL]) ], cpNormal, True), wbRStructSK([0], 'Muzzle Flash Model', [ wbString(NAM1, 'Model Filename'), wbByteArray(NAM2, 'Texture Files Hashes', 0, cpIgnore) ], [], cpNormal, True), wbInteger(VNAM, 'Sound Level', itU32, wbSoundLevelEnum, cpNormal, True) ]); wbRecord(NAVI, 'Navigation Mesh Info Map', [ wbEDID, wbInteger(NVER, 'Version', itU32), wbRArray('Navigation Map Infos', wbStruct(NVMI, 'Navigation Map Info', [ wbByteArray('Unknown', 4), wbFormIDCk('Navigation Mesh', [NAVM]), wbFormIDCk('Location', [CELL, WRLD]), wbStruct('Grid', [ wbInteger('X', itS16), wbInteger('Y', itS16) ]), wbUnknown { wbUnion('Data', wbNAVINVMIDecider, [ wbStruct('Data', [ wbUnknown ]), wbStruct('Data', [ wbArray('Unknown', wbFloat('Unknown'), 3), wbByteArray('Unknown', 4) ]), wbStruct('Data', [ wbArray('Unknown', wbArray('Unknown', wbFloat('Unknown'), 3), 3), wbInteger('Count 1', itU16), wbInteger('Count 2', itU16), wbArray('Unknown', wbArray('Unknown', wbFloat('Unknown'), 3), [], wbNAVINAVMGetCount1), wbUnknown ]), wbStruct('Data', [ wbUnknown ]) ])} ]) ), wbRArray('Unknown', wbStruct(NVCI, 'Unknown', [ wbFormIDCk('Unknown', [NAVM]), wbArray('Unknown', wbFormIDCk('Unknown', [NAVM]), -1), wbArray('Unknown', wbFormIDCk('Unknown', [NAVM]), -1), wbArray('Doors', wbFormIDCk('Door', [REFR]), -1) ]) ) ]); if wbSimpleRecords then begin wbRecord(NAVM, 'Navigation Mesh', [ wbEDID, wbInteger(NVER, 'Version', itU32), wbStruct(DATA, '', [ wbFormIDCk('Cell', [CELL]), wbInteger('Vertex Count', itU32), wbInteger('Triangle Count', itU32), wbInteger('External Connections Count', itU32), wbInteger('NVCA Count', itU32), wbInteger('Doors Count', itU32) ]), wbByteArray(NVVX, 'Vertices'), wbByteArray(NVTR, 'Triangles'), wbByteArray(NVCA, 'Unknown'), wbArray(NVDP, 'Doors', wbStruct('Door', [ wbFormIDCk('Reference', [REFR]), wbInteger('Triangle', itU16), wbByteArray('Unused', 2) ])), wbByteArray(NVGD, 'Unknown'), wbArray(NVEX, 'External Connections', wbStruct('Connection', [ wbByteArray('Unknown', 4), wbFormIDCk('Navigation Mesh', [NAVM], False, cpNormal), wbInteger('Triangle', itU16, nil, cpNormal) ])) ], False, wbNAVMAddInfo); end else begin wbRecord(NAVM, 'Navigation Mesh', [ wbEDID, wbInteger(NVER, 'Version', itU32), wbStruct(DATA, '', [ wbFormIDCk('Cell', [CELL]), wbInteger('Vertex Count', itU32), wbInteger('Triangle Count', itU32), wbInteger('External Connections Count', itU32), wbInteger('NVCA Count', itU32), wbInteger('Doors Count', itU32) // as of version = 5 (earliest NavMesh version I saw (Fallout3 1.7) is already 11) ]), wbArray(NVVX, 'Vertices', wbStruct('Vertex', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ])), wbArray(NVTR, 'Triangles', wbStruct('Triangle', [ wbArray('Vertices', wbInteger('Vertex', itS16), 3), wbArray('Edges', wbInteger('Triangle', itS16, wbNVTREdgeToStr, wbNVTREdgeToInt), [ '0 <-> 1', '1 <-> 2', '2 <-> 0' ]), wbInteger('Flags', itU32, wbFlags([ 'Triangle #0 Is External', 'Triangle #1 Is External', 'Triangle #2 Is External', 'Unknown 4', 'Unknown 5', 'Unknown 6', 'Unknown 7', 'Unknown 8', 'Unknown 9', 'Unknown 10', 'Unknown 11', 'Unknown 12', 'Unknown 13', 'Unknown 14', 'Unknown 15', 'Unknown 16', 'Unknown 17', 'Unknown 18', 'Unknown 19', 'Unknown 20', 'Unknown 21', 'Unknown 22', 'Unknown 23', 'Unknown 24', 'Unknown 25', 'Unknown 26', 'Unknown 27', 'Unknown 28', 'Unknown 29', 'Unknown 30', 'Unknown 31', 'Unknown 32' ])) ])), wbArray(NVCA, 'Unknown', wbInteger('Unknown', itS16)), wbArray(NVDP, 'Doors', wbStruct('Door', [ wbFormIDCk('Reference', [REFR]), wbInteger('Triangle', itU16), wbByteArray('Unused', 2) ])), wbStruct(NVGD, 'Unknown', [ wbByteArray('Unknown', 4), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Unknown'), wbArray('Unknown', wbArray('Unknown', wbInteger('Unknown', itU16), -2)) ]), wbArray(NVEX, 'External Connections', wbStruct('Connection', [ wbByteArray('Unknown', 4), wbFormIDCk('Navigation Mesh', [NAVM], False, cpNormal), wbInteger('Triangle', itU16, nil, cpNormal) ])) ], False, wbNAVMAddInfo); end; wbRecord(PGRE, 'Placed Grenade', [ wbEDID, wbFormIDCk(NAME, 'Base', [PROJ], False, cpNormal, True), wbFormIDCk(XEZN, 'Encounter Zone', [ECZN]), wbXRGD, wbXRGB, {--- Patrol Data ---} wbRStruct('Patrol Data', [ wbFloat(XPRD, 'Idle Time', cpNormal, True), wbEmpty(XPPA, 'Patrol Script Marker', cpNormal, True), wbFormIDCk(INAM, 'Idle', [IDLE, NULL], False, cpNormal, True), wbEmbeddedScriptReq, wbFormIDCk(TNAM, 'Topic', [DIAL, NULL], False, cpNormal, True) ], []), {--- Ownership ---} wbRStruct('Ownership', [ wbXOWN, wbInteger(XRNK, 'Faction rank', itS32) ], [XCMT, XCMO]), {--- Extra ---} wbInteger(XCNT, 'Count', itS32), wbFloat(XRDS, 'Radius'), wbFloat(XHLP, 'Health'), {--- Reflected By / Refracted By ---} wbRArrayS('Reflected/Refracted By', wbStructSK(XPWR, [0], 'Water', [ wbFormIDCk('Reference', [REFR]), wbInteger('Type', itU32, wbFlags([ 'Reflection', 'Refraction' ])) ]) ), {--- Decals ---} wbRArrayS('Linked Decals', wbStructSK(XDCR, [0], 'Decal', [ wbFormIDCk('Reference', [REFR]), wbUnknown ]) ), {--- Linked Ref ---} wbFormIDCk(XLKR, 'Linked Reference', [REFR, ACRE, ACHR, PGRE, PMIS, PBEA, PLYR]), wbStruct(XCLP, 'Linked Reference Color', [ wbStruct('Link Start Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Link End Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]) ]), {--- Activate Parents ---} wbRStruct('Activate Parents', [ wbInteger(XAPD, 'Flags', itU8, wbFlags([ 'Parent Activate Only' ], True)), wbRArrayS('Activate Parent Refs', wbStructSK(XAPR, [0], 'Activate Parent Ref', [ wbFormIDCk('Reference', [REFR, ACRE, ACHR, PGRE, PMIS, PBEA, PLYR]), wbFloat('Delay') ]) ) ], []), {--- Enable Parent ---} wbXESP, {--- Emittance ---} wbFormIDCk(XEMI, 'Emittance', [LIGH, REGN]), {--- MultiBound ---} wbFormIDCk(XMBR, 'MultiBound Reference', [REFR]), {--- Flags ---} wbEmpty(XIBS, 'Ignored By Sandbox'), {--- 3D Data ---} wbXSCL, wbDATAPosRot ], True, wbPlacedAddInfo); wbRecord(PMIS, 'Placed Missile', [ wbEDID, wbFormIDCk(NAME, 'Base', [PROJ], False, cpNormal, True), wbFormIDCk(XEZN, 'Encounter Zone', [ECZN]), wbXRGD, wbXRGB, {--- Patrol Data ---} wbRStruct('Patrol Data', [ wbFloat(XPRD, 'Idle Time', cpNormal, True), wbEmpty(XPPA, 'Patrol Script Marker', cpNormal, True), wbFormIDCk(INAM, 'Idle', [IDLE, NULL], False, cpNormal, True), wbEmbeddedScriptReq, wbFormIDCk(TNAM, 'Topic', [DIAL, NULL], False, cpNormal, True) ], []), {--- Ownership ---} wbRStruct('Ownership', [ wbXOWN, wbInteger(XRNK, 'Faction rank', itS32) ], [XCMT, XCMO]), {--- Extra ---} wbInteger(XCNT, 'Count', itS32), wbFloat(XRDS, 'Radius'), wbFloat(XHLP, 'Health'), {--- Reflected By / Refracted By ---} wbRArrayS('Reflected/Refracted By', wbStructSK(XPWR, [0], 'Water', [ wbFormIDCk('Reference', [REFR]), wbInteger('Type', itU32, wbFlags([ 'Reflection', 'Refraction' ])) ]) ), {--- Decals ---} wbRArrayS('Linked Decals', wbStructSK(XDCR, [0], 'Decal', [ wbFormIDCk('Reference', [REFR]), wbUnknown ]) ), {--- Linked Ref ---} wbFormIDCk(XLKR, 'Linked Reference', [REFR, ACRE, ACHR, PGRE, PMIS, PBEA, PLYR]), wbStruct(XCLP, 'Linked Reference Color', [ wbStruct('Link Start Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Link End Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]) ]), {--- Activate Parents ---} wbRStruct('Activate Parents', [ wbInteger(XAPD, 'Flags', itU8, wbFlags([ 'Parent Activate Only' ], True)), wbRArrayS('Activate Parent Refs', wbStructSK(XAPR, [0], 'Activate Parent Ref', [ wbFormIDCk('Reference', [REFR, ACRE, ACHR, PGRE, PMIS, PBEA, PLYR]), wbFloat('Delay') ]) ) ], []), {--- Enable Parent ---} wbXESP, {--- Emittance ---} wbFormIDCk(XEMI, 'Emittance', [LIGH, REGN]), {--- MultiBound ---} wbFormIDCk(XMBR, 'MultiBound Reference', [REFR]), {--- Flags ---} wbEmpty(XIBS, 'Ignored By Sandbox'), {--- 3D Data ---} wbXSCL, wbDATAPosRot ], True, wbPlacedAddInfo); wbRecord(PBEA, 'Placed Beam', [ wbEDID, wbFormIDCk(NAME, 'Base', [PROJ], False, cpNormal, True), wbFormIDCk(XEZN, 'Encounter Zone', [ECZN]), wbXRGD, wbXRGB, {--- Patrol Data ---} wbRStruct('Patrol Data', [ wbFloat(XPRD, 'Idle Time', cpNormal, True), wbEmpty(XPPA, 'Patrol Script Marker', cpNormal, True), wbFormIDCk(INAM, 'Idle', [IDLE, NULL], False, cpNormal, True), wbEmbeddedScriptReq, wbFormIDCk(TNAM, 'Topic', [DIAL, NULL], False, cpNormal, True) ], []), {--- Ownership ---} wbRStruct('Ownership', [ wbXOWN, wbInteger(XRNK, 'Faction rank', itS32) ], [XCMT, XCMO]), {--- Extra ---} wbInteger(XCNT, 'Count', itS32), wbFloat(XRDS, 'Radius'), wbFloat(XHLP, 'Health'), {--- Reflected By / Refracted By ---} wbRArrayS('Reflected/Refracted By', wbStructSK(XPWR, [0], 'Water', [ wbFormIDCk('Reference', [REFR]), wbInteger('Type', itU32, wbFlags([ 'Reflection', 'Refraction' ])) ]) ), {--- Decals ---} wbRArrayS('Linked Decals', wbStructSK(XDCR, [0], 'Decal', [ wbFormIDCk('Reference', [REFR]), wbUnknown ]) ), {--- Linked Ref ---} wbFormIDCk(XLKR, 'Linked Reference', [REFR, ACRE, ACHR, PGRE, PMIS, PBEA, PLYR]), wbStruct(XCLP, 'Linked Reference Color', [ wbStruct('Link Start Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Link End Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]) ]), {--- Activate Parents ---} wbRStruct('Activate Parents', [ wbInteger(XAPD, 'Flags', itU8, wbFlags([ 'Parent Activate Only' ], True)), wbRArrayS('Activate Parent Refs', wbStructSK(XAPR, [0], 'Activate Parent Ref', [ wbFormIDCk('Reference', [REFR, ACRE, ACHR, PGRE, PMIS, PBEA, PLYR]), wbFloat('Delay') ]) ) ], []), {--- Enable Parent ---} wbXESP, {--- Emittance ---} wbFormIDCk(XEMI, 'Emittance', [LIGH, REGN]), {--- MultiBound ---} wbFormIDCk(XMBR, 'MultiBound Reference', [REFR]), {--- Flags ---} wbEmpty(XIBS, 'Ignored By Sandbox'), {--- 3D Data ---} wbXSCL, wbDATAPosRot ], True, wbPlacedAddInfo); wbRecord(EXPL, 'Explosion', [ wbEDIDReq, wbOBNDReq, wbFULL, wbMODL, wbEITM, wbFormIDCk(MNAM, 'Image Space Modifier', [IMAD]), wbStruct(DATA, 'Data', [ {00} wbFloat('Force'), {04} wbFloat('Damage'), {08} wbFloat('Radius'), {12} wbFormIDCk('Light', [LIGH, NULL]), {16} wbFormIDCk('Sound 1', [SOUN, NULL]), {20} wbInteger('Flags', itU32, wbFlags([ {0x00000001}'Unknown 1', {0x00000002}'Always Uses World Orientation', {0x00000004}'Knock Down - Always', {0x00000008}'Knock Down - By Formula', {0x00000010}'Ignore LOS Check', {0x00000020}'Push Explosion Source Ref Only', {0x00000040}'Ignore Image Space Swap' ])), {24} wbFloat('IS Radius'), {28} wbFormIDCk('Impact DataSet', [IPDS, NULL]), {32} wbFormIDCk('Sound 2', [SOUN, NULL]), wbStruct('Radiation', [ {36} wbFloat('Level'), {40} wbFloat('Dissipation Time'), {44} wbFloat('Radius') ]), {48} wbInteger('Sound Level', itU32, wbSoundLevelEnum, cpNormal, True) ], cpNormal, True), wbFormIDCk(INAM, 'Placed Impact Object', [TREE, SOUN, ACTI, DOOR, STAT, FURN, CONT, ARMO, AMMO, LVLN, LVLC, MISC, WEAP, BOOK, KEYM, ALCH, LIGH, GRAS, ASPC, IDLM, ARMA, MSTT, NOTE, PWAT, SCOL, TACT, TERM, TXST]) ]); wbRecord(DEBR, 'Debris', [ wbEDIDReq, wbRStructs('Models', 'Model', [ wbStruct(DATA, 'Data', [ wbInteger('Percentage', itU8), wbString('Model Filename'), wbInteger('Flags', itU8, wbFlags([ 'Has Collission Data' ])) ], cpNormal, True), wbByteArray(MODT, 'Texture Files Hashes', 0, cpIgnore) ], [], cpNormal, True) ]); wbRecord(IMGS, 'Image Space', [ wbEDIDReq, wbStruct(DNAM, '', [ wbStruct('HDR', [ {00} wbFloat('Eye Adapt Speed'), {04} wbFloat('Blur Radius'), {08} wbFloat('Blur Passes'), {12} wbFloat('Emissive Mult'), {16} wbFloat('Target LUM'), {20} wbFloat('Upper LUM Clamp'), {24} wbFloat('Bright Scale'), {28} wbFloat('Bright Clamp'), {32} wbFloat('LUM Ramp No Tex'), {36} wbFloat('LUM Ramp Min'), {40} wbFloat('LUM Ramp Max'), {44} wbFloat('Sunlight Dimmer'), {48} wbFloat('Grass Dimmer'), {52} wbFloat('Tree Dimmer'), {56} wbUnion('Skin Dimmer', wbIMGSSkinDimmerDecider, [ wbFloat('Skin Dimmer'), wbEmpty('Skin Dimmer', cpIgnore) ]) ], cpNormal, False, nil, 14), wbStruct('Bloom', [ {60} wbFloat('Blur Radius'), {64} wbFloat('Alpha Mult Interior'), {68} wbFloat('Alpha Mult Exterior') ]), wbStruct('Get Hit', [ {72} wbFloat('Blur Radius'), {76} wbFloat('Blur Damping Constant'), {80} wbFloat('Damping Constant') ]), wbStruct('Night Eye', [ wbStruct('Tint Color', [ {84} wbFloat('Red', cpNormal, False, 255, 0), {88} wbFloat('Green', cpNormal, False, 255, 0), {92} wbFloat('Blue', cpNormal, False, 255, 0) ]), {96} wbFloat('Brightness') ]), wbStruct('Cinematic', [ {100} wbFloat('Saturation'), wbStruct('Contrast', [ {104} wbFloat('Avg Lum Value'), {108} wbFloat('Value') ]), {112} wbFloat('Cinematic - Brightness - Value'), wbStruct('Tint', [ wbStruct('Color', [ {116} wbFloat('Red', cpNormal, False, 255, 0), {120} wbFloat('Green', cpNormal, False, 255, 0), {124} wbFloat('Blue', cpNormal, False, 255, 0) ]), {128} wbFloat('Value') ]) ]), wbByteArray('Unused', 4), wbByteArray('Unused', 4), wbByteArray('Unused', 4), wbByteArray('Unused', 4), wbInteger('Flags', itU8, wbFlags([ 'Saturation', 'Contrast', 'Tint', 'Brightness' ], True)), wbByteArray('Unused', 3) ], cpNormal, True, nil, 5) ]); wbTimeInterpolator := wbStruct('Data', [ wbFloat('Time'), wbFloat('Value') ]); wbColorInterpolator := wbStruct('Data', [ wbFloat('Time'), wbFloat('Red', cpNormal, False, 255, 0), wbFloat('Green', cpNormal, False, 255, 0), wbFloat('Blue', cpNormal, False, 255, 0), wbFloat('Alpha', cpNormal, False, 255, 0) ]); wbRecord(IMAD, 'Image Space Adapter', [ wbEDID, wbStruct(DNAM, 'Data Count', [ wbInteger('Flags', itU32, wbFlags(['Animatable'])), wbFloat('Duration'), wbStruct('HDR', [ wbInteger('Eye Adapt Speed Mult', itU32), wbInteger('Eye Adapt Speed Add', itU32), wbInteger('Bloom Blur Radius Mult', itU32), wbInteger('Bloom Blur Radius Add', itU32), wbInteger('Bloom Threshold Mult', itU32), wbInteger('Bloom Threshold Add', itU32), wbInteger('Bloom Scale Mult', itU32), wbInteger('Bloom Scale Add', itU32), wbInteger('Target Lum Min Mult', itU32), wbInteger('Target Lum Min Add', itU32), wbInteger('Target Lum Max Mult', itU32), wbInteger('Target Lum Max Add', itU32), wbInteger('Sunlight Scale Mult', itU32), wbInteger('Sunlight Scale Add', itU32), wbInteger('Sky Scale Mult', itU32), wbInteger('Sky Scale Add', itU32) ]), wbInteger('Unknown08 Mult', itU32), wbInteger('Unknown48 Add', itU32), wbInteger('Unknown09 Mult', itU32), wbInteger('Unknown49 Add', itU32), wbInteger('Unknown0A Mult', itU32), wbInteger('Unknown4A Add', itU32), wbInteger('Unknown0B Mult', itU32), wbInteger('Unknown4B Add', itU32), wbInteger('Unknown0C Mult', itU32), wbInteger('Unknown4C Add', itU32), wbInteger('Unknown0D Mult', itU32), wbInteger('Unknown4D Add', itU32), wbInteger('Unknown0E Mult', itU32), wbInteger('Unknown4E Add', itU32), wbInteger('Unknown0F Mult', itU32), wbInteger('Unknown4F Add', itU32), wbInteger('Unknown10 Mult', itU32), wbInteger('Unknown50 Add', itU32), wbStruct('Cinematic', [ wbInteger('Saturation Mult', itU32), wbInteger('Saturation Add', itU32), wbInteger('Brightness Mult', itU32), wbInteger('Brightness Add', itU32), wbInteger('Contrast Mult', itU32), wbInteger('Contrast Add', itU32) ]), wbInteger('Unknown14 Mult', itU32), wbInteger('Unknown54 Add', itU32), wbInteger('Tint Color', itU32), wbInteger('Blur Radius', itU32), wbInteger('Double Vision Strength', itU32), wbInteger('Radial Blur Strength', itU32), wbInteger('Radial Blur Ramp Up', itU32), wbInteger('Radial Blur Start', itU32), wbInteger('Radial Blur Flags', itU32, wbFlags(['Use Target'])), wbFloat('Radial Blur Center X'), wbFloat('Radial Blur Center Y'), wbInteger('DoF Strength', itU32), wbInteger('DoF Distance', itU32), wbInteger('DoF Range', itU32), wbInteger('DoF Flags', itU32, wbFlags(['Use Target'])), wbInteger('Radial Blur Ramp Down', itU32), wbInteger('Radial Blur Down Start', itU32), wbInteger('Fade Color', itU32), wbInteger('Motion Blur Strength', itU32) ], cpNormal, True, nil, 26), wbArray(BNAM, 'Blur Radius', wbTimeInterpolator), wbArray(VNAM, 'Double Vision Strength', wbTimeInterpolator), wbArray(TNAM, 'Tint Color', wbColorInterpolator), wbArray(NAM3, 'Fade Color', wbColorInterpolator), wbArray(RNAM, 'Radial Blur Strength', wbTimeInterpolator), wbArray(SNAM, 'Radial Blur Ramp Up', wbTimeInterpolator), wbArray(UNAM, 'Radial Blur Start', wbTimeInterpolator), wbArray(NAM1, 'Radial Blur Ramp Down', wbTimeInterpolator), wbArray(NAM2, 'Radial Blur Down Start', wbTimeInterpolator), wbArray(WNAM, 'DoF Strength', wbTimeInterpolator), wbArray(XNAM, 'DoF Distance', wbTimeInterpolator), wbArray(YNAM, 'DoF Range', wbTimeInterpolator), wbArray(NAM4, 'Motion Blur Strength', wbTimeInterpolator), wbRStruct('HDR', [ wbArray(_00_IAD, 'Eye Adapt Speed Mult', wbTimeInterpolator), wbArray(_40_IAD, 'Eye Adapt Speed Add', wbTimeInterpolator), wbArray(_01_IAD, 'Bloom Blur Radius Mult', wbTimeInterpolator), wbArray(_41_IAD, 'Bloom Blur Radius Add', wbTimeInterpolator), wbArray(_02_IAD, 'Bloom Threshold Mult', wbTimeInterpolator), wbArray(_42_IAD, 'Bloom Threshold Add', wbTimeInterpolator), wbArray(_03_IAD, 'Bloom Scale Mult', wbTimeInterpolator), wbArray(_43_IAD, 'Bloom Scale Add', wbTimeInterpolator), wbArray(_04_IAD, 'Target Lum Min Mult', wbTimeInterpolator), wbArray(_44_IAD, 'Target Lum Min Add', wbTimeInterpolator), wbArray(_05_IAD, 'Target Lum Max Mult', wbTimeInterpolator), wbArray(_45_IAD, 'Target Lum Max Add', wbTimeInterpolator), wbArray(_06_IAD, 'Sunlight Scale Mult', wbTimeInterpolator), wbArray(_46_IAD, 'Sunlight Scale Add', wbTimeInterpolator), wbArray(_07_IAD, 'Sky Scale Mult', wbTimeInterpolator), wbArray(_47_IAD, 'Sky Scale Add', wbTimeInterpolator) ], []), wbUnknown(_08_IAD), wbUnknown(_48_IAD), wbUnknown(_09_IAD), wbUnknown(_49_IAD), wbUnknown(_0A_IAD), wbUnknown(_4A_IAD), wbUnknown(_0B_IAD), wbUnknown(_4B_IAD), wbUnknown(_0C_IAD), wbUnknown(_4C_IAD), wbUnknown(_0D_IAD), wbUnknown(_4D_IAD), wbUnknown(_0E_IAD), wbUnknown(_4E_IAD), wbUnknown(_0F_IAD), wbUnknown(_4F_IAD), wbUnknown(_10_IAD), wbUnknown(_50_IAD), wbRStruct('Cinematic', [ wbArray(_11_IAD, 'Saturation Mult', wbTimeInterpolator), wbArray(_51_IAD, 'Saturation Add', wbTimeInterpolator), wbArray(_12_IAD, 'Brightness Mult', wbTimeInterpolator), wbArray(_52_IAD, 'Brightness Add', wbTimeInterpolator), wbArray(_13_IAD, 'Contrast Mult', wbTimeInterpolator), wbArray(_53_IAD, 'Contrast Add', wbTimeInterpolator) ], []), wbUnknown(_14_IAD), wbUnknown(_54_IAD) ]); wbRecord(FLST, 'FormID List', [ wbString(EDID, 'Editor ID', 0, cpBenign, True, nil, wbFLSTEDIDAfterSet), wbRArrayS('FormIDs', wbFormID(LNAM, 'FormID'), cpNormal, False, nil, nil, nil, wbFLSTLNAMIsSorted) ]); wbRecord(PERK, 'Perk', [ wbEDIDReq, wbFULL, wbDESCReq, wbICON, wbCTDAs, wbStruct(DATA, 'Data', [ wbInteger('Trait', itU8, wbEnum(['No', 'Yes'])), wbInteger('Min Level', itU8), wbInteger('Ranks', itU8), wbInteger('Playable', itU8, wbEnum(['No', 'Yes'])), wbInteger('Hidden', itU8, wbEnum(['No', 'Yes'])) ], cpNormal, True, nil, 4), wbRStructsSK('Effects', 'Effect', [0, 1], [ wbStructSK(PRKE, [1, 2, 0], 'Header', [ wbInteger('Type', itU8, wbEnum([ 'Quest + Stage', 'Ability', 'Entry Point' ]), cpNormal, False, nil, wbPERKPRKETypeAfterSet), wbInteger('Rank', itU8), wbInteger('Priority', itU8) ]), wbUnion(DATA, 'Effect Data', wbPerkDATADecider, [ wbStructSK([0, 1], 'Quest + Stage', [ wbFormIDCk('Quest', [QUST]), wbInteger('Quest Stage', itU8, wbPerkDATAQuestStageToStr, wbCTDAParam2QuestStageToInt), wbByteArray('Unused', 3) ]), wbFormIDCk('Ability', [SPEL]), wbStructSK([0, 1], 'Entry Point', [ wbInteger('Entry Point', itU8, wbEnum([ {00} 'Calculate Weapon Damage', {01} 'Calculate My Critical Hit Chance', {02} 'Calculate My Critical Hit Damage', {03} 'Calculate Weapon Attack AP Cost', {04} 'Calculate Mine Explode Chance', {05} 'Adjust Range Penalty', {06} 'Adjust Limb Damage', {07} 'Calculate Weapon Range', {08} 'Calculate To Hit Chance', {09} 'Adjust Experience Points', {10} 'Adjust Gained Skill Points', {11} 'Adjust Book Skill Points', {12} 'Modify Recovered Health', {13} 'Calculate Inventory AP Cost', {14} 'Get Disposition', {15} 'Get Should Attack', {16} 'Get Should Assist', {17} 'Calculate Buy Price', {18} 'Get Bad Karma', {19} 'Get Good Karma', {20} 'Ignore Locked Terminal', {21} 'Add Leveled List On Death', {22} 'Get Max Carry Weight', {23} 'Modify Addiction Chance', {24} 'Modify Addiction Duration', {25} 'Modify Positive Chem Duration', {26} 'Adjust Drinking Radiation', {27} 'Activate', {28} 'Mysterious Stranger', {29} 'Has Paralyzing Palm', {30} 'Hacking Science Bonus', {31} 'Ignore Running During Detection', {32} 'Ignore Broken Lock', {33} 'Has Concentrated Fire', {34} 'Calculate Gun Spread', {35} 'Player Kill AP Reward', {36} 'Modify Enemy Critical Hit Chance' ]), cpNormal, True, nil, wbPERKEntryPointAfterSet), wbInteger('Function', itU8, wbPerkDATAFunctionToStr, wbPerkDATAFunctionToInt, cpNormal, False, nil, wbPerkDATAFunctionAfterSet), wbInteger('Perk Condition Tab Count', itU8, nil, cpIgnore) ]) ], cpNormal, True), wbRStructsSK('Perk Conditions', 'Perk Condition', [0], [ wbInteger(PRKC, 'Run On', itS8, wbPRKCToStr, wbPRKCToInt), wbCTDAsReq ], [], cpNormal, False, nil, nil, wbPERKPRKCDontShow), wbRStruct('Entry Point Function Parameters', [ wbInteger(EPFT, 'Type', itU8, wbPerkEPFTToStr, wbPerkEPFTToInt, cpIgnore, False, nil, wbPerkEPFTAfterSet), wbUnion(EPFD, 'Data', wbEPFDDecider, [ wbByteArray('Unknown'), wbFloat('Float'), wbStruct('Float, Float', [ wbFloat('Float 1'), wbFloat('Float 2') ]), wbFormIDCk('Leveled Item', [LVLI]), wbEmpty('None (Script)'), wbStruct('Actor Value, Float', [ wbInteger('Actor Value', itU32, wbEPFDActorValueToStr, wbEPFDActorValueToInt), wbFloat('Float') ]) ], cpNormal, False, wbEPFDDontShow), wbString(EPF2, 'Button Label', 0, cpNormal, False, wbEPF2DontShow), wbInteger(EPF3, 'Script Flags', itU16, wbFlags([ 'Run Immediately' ]), cpNormal, False, False, wbEPF2DontShow), wbEmbeddedScriptPerk ], [], cpNormal, False, wbPERKPRKCDontShow), wbEmpty(PRKF, 'End Marker', cpIgnore, True) ], []) ]); wbBPNDStruct := wbStruct(BPND, '', [ {00} wbFloat('Damage Mult'), {04} wbInteger('Flags', itU8, wbFlags([ 'Severable', 'IK Data', 'IK Data - Biped Data', 'Explodable', 'IK Data - Is Head', 'IK Data - Headtracking', 'To Hit Chance - Absolute' ])), {05} wbInteger('Part Type', itU8, wbEnum([ 'Torso', 'Head 1', 'Head 2', 'Left Arm 1', 'Left Arm 2', 'Right Arm 1', 'Right Arm 2', 'Left Leg 1', 'Left Leg 2', 'Left Leg 3', 'Right Leg 1', 'Right Leg 2', 'Right Leg 3', 'Brain', 'Weapon' ])), {06} wbInteger('Health Percent', itU8), {07} wbInteger('Actor Value', itS8, wbActorValueEnum), {08} wbInteger('To Hit Chance', itU8), {09} wbInteger('Explodable - Explosion Chance %', itU8), {10} wbInteger('Explodable - Debris Count', itU16), {12} wbFormIDCk('Explodable - Debris', [DEBR, NULL]), {16} wbFormIDCk('Explodable - Explosion', [EXPL, NULL]), {20} wbFloat('Tracking Max Angle'), {24} wbFloat('Explodable - Debris Scale'), {28} wbInteger('Severable - Debris Count', itS32), {32} wbFormIDCk('Severable - Debris', [DEBR, NULL]), {36} wbFormIDCk('Severable - Explosion', [EXPL, NULL]), {40} wbFloat('Severable - Debris Scale'), wbStruct('Gore Effects Positioning', [ wbStruct('Translate', [ {44} wbFloat('X'), {48} wbFloat('Y'), {52} wbFloat('Z') ]), wbStruct('Rotation', [ {56} wbFloat('X', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), {60} wbFloat('Y', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), {64} wbFloat('Z', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize) ]) ]), {68} wbFormIDCk('Severable - Impact DataSet', [IPDS, NULL]), {72} wbFormIDCk('Explodable - Impact DataSet', [IPDS, NULL]), {28} wbInteger('Severable - Decal Count', itU8), {28} wbInteger('Explodable - Decal Count', itU8), {76} wbByteArray('Unused', 2), {80} wbFloat('Limb Replacement Scale') ], cpNormal, True); wbRecord(BPTD, 'Body Part Data', [ wbEDIDReq, wbMODLReq, wbRStructS('Body Parts', 'Body Part', [ wbString(BPTN, 'Part Name', 0, cpNormal, True), wbString(BPNN, 'Part Node', 0, cpNormal, True), wbString(BPNT, 'VATS Target', 0, cpNormal, True), wbString(BPNI, 'IK Data - Start Node', 0, cpNormal, True), wbBPNDStruct, wbString(NAM1, 'Limb Replacement Model', 0, cpNormal, True), wbString(NAM4, 'Gore Effects - Target Bone', 0, cpNormal, True), wbByteArray(NAM5, 'Texture Files Hashes', 0, cpIgnore) ], [], cpNormal, True), wbFormIDCk(RAGA, 'Ragdoll', [RGDL]) ]); wbRecord(ADDN, 'Addon Node', [ wbEDIDReq, wbOBNDReq, wbMODLReq, wbInteger(DATA, 'Node Index', itS32, nil, cpNormal, True), wbFormIDCk(SNAM, 'Sound', [SOUN]), wbStruct(DNAM, 'Data', [ wbInteger('Master Particle System Cap', itU16), wbByteArray('Unknown', 2) ], cpNormal, True) ]); wbRecord(AVIF, 'ActorValue Information', [ wbEDIDReq, wbFULL, wbDESCReq, wbICON, wbString(ANAM, 'Short Name') ]); wbRecord(RADS, 'Radiation Stage', [ wbEDIDReq, wbStruct(DATA, '', [ wbInteger('Trigger Threshold', itU32), wbFormIDCk('Actor Effect', [SPEL]) ], cpNormal, True) ]); wbRecord(CAMS, 'Camera Shot', [ wbEDIDReq, wbMODL, wbStruct(DATA, 'Data', [ {00} wbInteger('Action', itU32, wbEnum([ 'Shoot', 'Fly', 'Hit', 'Zoom' ])), {04} wbInteger('Location', itU32, wbEnum([ 'Attacker', 'Projectile', 'Target' ])), {08} wbInteger('Target', itU32, wbEnum([ 'Attacker', 'Projectile', 'Target' ])), {12} wbInteger('Flags', itU32, wbFlags([ 'Position Follows Location', 'Rotation Follows Target', 'Don''t Follow Bone', 'First Person Camera', 'No Tracer', 'Start At Time Zero' ])), wbStruct('Time Multipliers', [ {16} wbFloat('Player'), {20} wbFloat('Target'), {24} wbFloat('Global') ]), {28} wbFloat('Max Time'), {32} wbFloat('Min Time'), {36} wbFloat('Target % Between Actors') ], cpNormal, True, nil, 7), wbFormIDCk(MNAM, 'Image Space Modifier', [IMAD]) ]); wbRecord(CPTH, 'Camera Path', [ wbEDIDReq, wbCTDAs, wbArray(ANAM, 'Related Camera Paths', wbFormIDCk('Related Camera Path', [CPTH, NULL]), ['Parent', 'Previous Sibling'], cpNormal, True), wbInteger(DATA, 'Camera Zoom', itU8, wbEnum([ 'Default', 'Disable', 'Shot List' ]), cpNormal, True), wbRArray('Camera Shots', wbFormIDCk(SNAM, 'Camera Shot', [CAMS])) ]); wbRecord(VTYP, 'Voice Type', [ wbEDIDReq, wbInteger(DNAM, 'Flags', itU8, wbFlags([ 'Allow Default Dialog', 'Female' ]), cpNormal, True) ]); wbRecord(IPCT, 'Impact', [ wbEDIDReq, wbMODL, wbStruct(DATA, '', [ wbFloat('Effect - Duration'), wbInteger('Effect - Orientation', itU32, wbEnum([ 'Surface Normal', 'Projectile Vector', 'Projectile Reflection' ])), wbFloat('Angle Threshold'), wbFloat('Placement Radius'), wbInteger('Sound Level', itU32, wbSoundLevelEnum), wbInteger('Flags', itU32, wbFlags([ 'No Decal Data' ])) ], cpNormal, True), wbDODT, wbFormIDCk(DNAM, 'Texture Set', [TXST]), wbFormIDCk(SNAM, 'Sound 1', [SOUN]), wbFormIDCk(NAM1, 'Sound 2', [SOUN]) ]); wbRecord(IPDS, 'Impact DataSet', [ wbEDIDReq, wbStruct(DATA, 'Impacts', [ wbFormIDCk('Stone', [IPCT, NULL]), wbFormIDCk('Dirt', [IPCT, NULL]), wbFormIDCk('Grass', [IPCT, NULL]), wbFormIDCk('Glass', [IPCT, NULL]), wbFormIDCk('Metal', [IPCT, NULL]), wbFormIDCk('Wood', [IPCT, NULL]), wbFormIDCk('Organic', [IPCT, NULL]), wbFormIDCk('Cloth', [IPCT, NULL]), wbFormIDCk('Water', [IPCT, NULL]), wbFormIDCk('Hollow Metal', [IPCT, NULL]), wbFormIDCk('Organic Bug', [IPCT, NULL]), wbFormIDCk('Organic Glow', [IPCT, NULL]) ], cpNormal, True, nil, 9) ]); wbRecord(ECZN, 'Encounter Zone', [ wbEDIDReq, wbStruct(DATA, '', [ wbFormIDCkNoReach('Owner', [NPC_, FACT, NULL]), wbInteger('Rank', itS8), wbInteger('Minimum Level', itS8), wbInteger('Flags', itU8, wbFlags([ 'Never Resets', 'Match PC Below Minimum Level' ])), wbByteArray('Unused', 1) ], cpNormal, True) ]); wbRecord(MESG, 'Message', [ wbEDIDReq, wbDESCReq, wbFULL, wbFormIDCk(INAM, 'Icon', [MICN, NULL], False, cpNormal, True), wbByteArray(NAM0, 'Unused', 0, cpIgnore), wbByteArray(NAM1, 'Unused', 0, cpIgnore), wbByteArray(NAM2, 'Unused', 0, cpIgnore), wbByteArray(NAM3, 'Unused', 0, cpIgnore), wbByteArray(NAM4, 'Unused', 0, cpIgnore), wbByteArray(NAM5, 'Unused', 0, cpIgnore), wbByteArray(NAM6, 'Unused', 0, cpIgnore), wbByteArray(NAM7, 'Unused', 0, cpIgnore), wbByteArray(NAM8, 'Unused', 0, cpIgnore), wbByteArray(NAM9, 'Unused', 0, cpIgnore), wbInteger(DNAM, 'Flags', itU32, wbFlags([ 'Message Box', 'Auto Display' ]), cpNormal, True, False, nil, wbMESGDNAMAfterSet), wbInteger(TNAM, 'Display Time', itU32, nil, cpNormal, False, False, wbMESGTNAMDontShow), wbRStructs('Menu Buttons', 'Menu Button', [ wbString(ITXT, 'Button Text'), wbCTDAs ], []) ], False, nil, cpNormal, False, wbMESGAfterLoad); wbRecord(RGDL, 'Ragdoll', [ wbEDIDReq, wbInteger(NVER, 'Version', itU32, nil, cpNormal, True), wbStruct(DATA, 'General Data', [ wbInteger('Dynamic Bone Count', itU32), wbByteArray('Unused', 4), wbStruct('Enabled', [ wbInteger('Feedback', itU8, wbEnum(['No', 'Yes'])), wbInteger('Foot IK (broken, don''t use)', itU8, wbEnum(['No', 'Yes'])), wbInteger('Look IK (broken, don''t use)', itU8, wbEnum(['No', 'Yes'])), wbInteger('Grab IK (broken, don''t use)', itU8, wbEnum(['No', 'Yes'])), wbInteger('Pose Matching', itU8, wbEnum(['No', 'Yes'])) ]), wbByteArray('Unused', 1) ], cpNormal, True), wbFormIDCk(XNAM, 'Actor Base', [CREA, NPC_], False, cpNormal, True), wbFormIDCk(TNAM, 'Body Part Data', [BPTD], False, cpNormal, True), wbStruct(RAFD, 'Feedback Data', [ {00} wbFloat('Dynamic/Keyframe Blend Amount'), {04} wbFloat('Hierarchy Gain'), {08} wbFloat('Position Gain'), {12} wbFloat('Velocity Gain'), {16} wbFloat('Acceleration Gain'), {20} wbFloat('Snap Gain'), {24} wbFloat('Velocity Damping'), wbStruct('Snap Max Settings', [ {28} wbFloat('Linear Velocity'), {32} wbFloat('Angular Velocity'), {36} wbFloat('Linear Distance'), {40} wbFloat('Angular Distance') ]), wbStruct('Position Max Velocity', [ {44} wbFloat('Linear'), {48} wbFloat('Angular') ]), wbStruct('Position Max Velocity', [ {52} wbInteger('Projectile', itS32, wbDiv(1000)), {56} wbInteger('Melee', itS32, wbDiv(1000)) ]) ], cpNormal, False), wbArray(RAFB, 'Feedback Dynamic Bones', wbInteger('Bone', itU16), 0, nil, nil, cpNormal, False), wbStruct(RAPS, 'Pose Matching Data', [ {00} wbArray('Match Bones', wbInteger('Bone', itU16, wbHideFFFF), 3), {06} wbInteger('Flags', itU8, wbFlags([ 'Disable On Move' ])), {07} wbByteArray('Unused', 1), {08} wbFloat('Motors Strength'), {12} wbFloat('Pose Activation Delay Time'), {16} wbFloat('Match Error Allowance'), {20} wbFloat('Displacement To Disable') ], cpNormal, True), wbString(ANAM, 'Death Pose') ]); wbRecord(DOBJ, 'Default Object Manager', [ wbEDIDReq, wbArray(DATA, 'Default Objects', wbFormID('Default Object'), [ 'Stimpack', 'SuperStimpack', 'RadX', 'RadAway', 'Morphine', 'Perk Paralysis', 'Player Faction', 'Mysterious Stranger NPC', 'Mysterious Stranger Faction', 'Default Music', 'Battle Music', 'Death Music', 'Success Music', 'Level Up Music', 'Player Voice (Male)', 'Player Voice (Male Child)', 'Player Voice (Female)', 'Player Voice (Female Child)', 'Eat Package Default Food', 'Every Actor Ability', 'Drug Wears Off Image Space' ], cpNormal, True) ]); wbRecord(LGTM, 'Lighting Template', [ wbEDIDReq, wbStruct(DATA, 'Lighting', [ wbStruct('Ambient Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Directional Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Fog Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbFloat('Fog Near'), wbFloat('Fog Far'), wbInteger('Directional Rotation XY', itS32), wbInteger('Directional Rotation Z', itS32), wbFloat('Directional Fade'), wbFloat('Fog Clip Dist'), wbFloat('Fog Power') ], cpNormal, True) ]); wbRecord(MUSC, 'Music Type', [ wbEDIDReq, wbString(FNAM, 'Filename') ]); wbRecord(GRAS, 'Grass', [ wbEDIDReq, wbOBNDReq, wbMODLReq, wbStruct(DATA, '', [ wbInteger('Density', itU8), wbInteger('Min Slope', itU8), wbInteger('Max Slope', itU8), wbByteArray('Unused', 1), wbInteger('Unit from water amount', itU16), wbByteArray('Unused', 2), wbInteger('Unit from water type', itU32, wbEnum([ 'Above - At Least', 'Above - At Most', 'Below - At Least', 'Below - At Most', 'Either - At Least', 'Either - At Most', 'Either - At Most Above', 'Either - At Most Below' ])), wbFloat('Position Range'), wbFloat('Height Range'), wbFloat('Color Range'), wbFloat('Wave Period'), wbInteger('Flags', itU8, wbFlags([ 'Vertex Lighting', 'Uniform Scaling', 'Fit to Slope' ])), wbByteArray('Unused', 3) ], cpNormal, True) ]); wbRecord(HAIR, 'Hair', [ wbEDIDReq, wbFULLReq, wbMODLReq, wbString(ICON, 'Texture', 0, cpNormal, True), wbInteger(DATA, 'Flags', itU8, wbFlags([ 'Playable', 'Not Male', 'Not Female', 'Fixed' ]), cpNormal, True) ]); wbRecord(IDLE, 'Idle Animation', [ wbEDID, wbMODLReq, wbCTDAs, wbArray(ANAM, 'Related Idle Animations', wbFormIDCk('Related Idle Animation', [IDLE, NULL]), ['Parent', 'Previous Sibling'], cpNormal, True), wbStruct(DATA, '', [ wbInteger('Animation Group Section', itU8, wbIdleAnam), wbStruct('Looping', [ wbInteger('Min', itU8), wbInteger('Max', itU8) ]), wbByteArray('Unused', 1), wbInteger('Replay Delay', itS16), wbInteger('Flags', itU8, wbFlags([ 'No attacking' ])), wbByteArray('Unused', 1) ], cpNormal, True, nil, 4) ]); wbRecord(INFO, 'Dialog response', [ wbStruct(DATA, '', [ wbInteger('Type', itU8, wbEnum([ {0} 'Topic', {1} 'Conversation', {2} 'Combat', {3} 'Persuasion', {4} 'Detection', {5} 'Service', {6} 'Miscellaneous', {7} 'Radio' ])), wbInteger('Next Speaker', itU8, wbEnum([ {0} 'Target', {1} 'Self', {2} 'Either' ])), wbInteger('Flags 1', itU8, wbFlags([ {0x01} 'Goodbye', {0x02} 'Random', {0x04} 'Say Once', {0x08} 'Run Immediately', {0x10} 'Info Refusal', {0x20} 'Random End', {0x40} 'Run for Rumors', {0x80} 'Speech Challenge' ])), wbInteger('Flags 2', itU8, wbFlags([ {0x01} 'Say Once a Day', {0x02} 'Always Darken' ])) ], cpNormal, True, nil, 3), wbFormIDCkNoReach(QSTI, 'Quest', [QUST], False, cpNormal, True), wbFormIDCk(TPIC, 'Topic', [DIAL]), wbFormIDCkNoReach(PNAM, 'Previous INFO', [INFO, NULL]), wbRArray('Add Topics', wbFormIDCk(NAME, 'Topic', [DIAL])), wbRArray('Responses', wbRStruct('Response', [ wbStruct(TRDT, 'Response Data', [ wbInteger('Emotion Type', itU32, wbEnum([ {0} 'Neutral', {1} 'Anger', {2} 'Disgust', {3} 'Fear', {4} 'Sad', {5} 'Happy', {6} 'Surprise', {7} 'Pained' ])), wbInteger('Emotion Value', itS32), wbByteArray('Unused', 4), wbInteger('Response number', itU8), wbByteArray('Unused', 3), wbFormIDCk('Sound', [SOUN, NULL]), wbInteger('Flags', itU8, wbFlags([ 'Use Emotion Animation' ])), wbByteArray('Unused', 3) ], cpNormal, False, nil, 5), wbStringKC(NAM1, 'Response Text', 0, cpTranslate, True), wbString(NAM2, 'Script Notes', 0, cpTranslate, True), wbString(NAM3, 'Edits'), wbFormIDCk(SNAM, 'Speaker Animation', [IDLE]), wbFormIDCk(LNAM, 'Listener Animation', [IDLE]) ], []) ), wbCTDAs, wbRArray('Choices', wbFormIDCk(TCLT, 'Choice', [DIAL])), wbRArray('Link From', wbFormIDCk(TCLF, 'Topic', [DIAL])), wbRStruct('Script (Begin)', [ wbEmbeddedScriptReq ], [], cpNormal, True), wbRStruct('Script (End)', [ wbEmpty(NEXT, 'Marker'), wbEmbeddedScriptReq ], [], cpNormal, True), wbFormIDCk(SNDD, 'Unused', [SOUN]), wbString(RNAM, 'Prompt'), wbFormIDCk(ANAM, 'Speaker', [CREA, NPC_]), wbFormIDCk(KNAM, 'ActorValue/Perk', [AVIF, PERK]), wbInteger(DNAM, 'Speech Challenge', itU32, wbEnum([ '---', 'Very Easy', 'Easy', 'Average', 'Hard', 'Very Hard' ])) ], False, wbINFOAddInfo, cpNormal, False, wbINFOAfterLoad); wbRecord(INGR, 'Ingredient', [ wbEDIDReq, wbOBNDReq, wbFULL, wbMODL, wbICON, wbSCRI, wbETYPReq, wbFloat(DATA, 'Weight', cpNormal, True), wbStruct(ENIT, 'Effect Data', [ wbInteger('Value', itS32), wbInteger('Flags', itU8, wbFlags(['No auto-calculation', 'Food item'])), wbByteArray('Unused', 3) ], cpNormal, True), wbEffectsReq ]); wbRecord(KEYM, 'Key', [ wbEDIDReq, wbOBNDReq, wbFULLReq, wbMODL, wbICONReq, wbSCRI, wbDEST, wbYNAM, wbZNAM, wbStruct(DATA, '', [ wbInteger('Value', itS32), wbFloat('Weight') ], cpNormal, True) ]); wbQuadrantEnum := wbEnum([ {0} 'Bottom Left', {1} 'Bottom Right', {2} 'Top Left', {3} 'Top Right' ]); if wbSimpleRecords then begin wbRecord(LAND, 'Landscape', [ wbByteArray(DATA, 'Unknown'), wbByteArray(VNML, 'Vertex Normals'), wbByteArray(VHGT, 'Vertext Height Map'), wbByteArray(VCLR, 'Vertex Colours'), wbRArrayS('Layers', wbRUnion('Layer', [ wbRStructSK([0],'Base Layer', [ wbStructSK(BTXT, [1, 3], 'Base Layer Header', [ wbFormIDCk('Texture', [LTEX, NULL]), wbInteger('Quadrant', itU8, wbQuadrantEnum), wbByteArray('Unused', 1), wbInteger('Layer', itS16) ]) ], []), wbRStructSK([0],'Alpha Layer', [ wbStructSK(ATXT, [1, 3], 'Alpha Layer Header', [ wbFormIDCk('Texture', [LTEX, NULL]), wbInteger('Quadrant', itU8, wbQuadrantEnum), wbByteArray('Unused', 1), wbInteger('Layer', itS16) ]), wbByteArray(VTXT, 'Alpha Layer Data') ], []) ], [])), wbArray(VTEX, 'Textures', wbFormIDCk('Texture', [LTEX, NULL])) ]); end else begin wbRecord(LAND, 'Landscape', [ wbByteArray(DATA, 'Unknown'), wbArray(VNML, 'Vertex Normals', wbStruct('Row', [ wbArray('Columns', wbStruct('Column', [ wbInteger('X', itU8), wbInteger('Y', itU8), wbInteger('Z', itU8) ]), 33) ]), 33), wbStruct(VHGT, 'Vertext Height Map', [ wbFloat('Offset'), wbArray('Rows', wbStruct('Row', [ wbArray('Columns', wbInteger('Column', itU8), 33) ]), 33), wbByteArray('Unused', 3) ]), wbArray(VCLR, 'Vertex Colours', wbStruct('Row', [ wbArray('Columns', wbStruct('Column', [ wbInteger('X', itU8), wbInteger('Y', itU8), wbInteger('Z', itU8) ]), 33) ]), 33), wbRArrayS('Layers', wbRUnion('Layer', [ wbRStructSK([0],'Base Layer', [ wbStructSK(BTXT, [1, 3], 'Base Layer Header', [ wbFormIDCk('Texture', [LTEX, NULL]), wbInteger('Quadrant', itU8, wbQuadrantEnum), wbByteArray('Unused', 1), wbInteger('Layer', itS16) ]) ], []), wbRStructSK([0],'Alpha Layer', [ wbStructSK(ATXT, [1, 3], 'Alpha Layer Header', [ wbFormIDCk('Texture', [LTEX, NULL]), wbInteger('Quadrant', itU8, wbQuadrantEnum), wbByteArray('Unused', 1), wbInteger('Layer', itS16) ]), wbArrayS(VTXT, 'Alpha Layer Data', wbStructSK([0], 'Cell', [ wbInteger('Position', itU16, wbAtxtPosition), wbByteArray('Unused', 2), wbFloat('Opacity') ])) ], []) ], [])), wbArray(VTEX, 'Textures', wbFormIDCk('Texture', [LTEX, NULL])) ]); end; wbRecord(LIGH, 'Light', [ wbEDIDReq, wbOBNDReq, wbMODL, wbSCRI, wbDEST, wbFULL, wbICON, wbStruct(DATA, '', [ wbInteger('Time', itS32), wbInteger('Radius', itU32), wbStruct('Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbInteger('Unused', itU8) ]), wbInteger('Flags', itU32, wbFlags([ {0x00000001} 'Dynamic', {0x00000002} 'Can be Carried', {0x00000004} 'Negative', {0x00000008} 'Flicker', {0x00000010} 'Unused', {0x00000020} 'Off By Default', {0x00000040} 'Flicker Slow', {0x00000080} 'Pulse', {0x00000100} 'Pulse Slow', {0x00000200} 'Spot Light', {0x00000400} 'Spot Shadow' ])), wbFloat('Falloff Exponent'), wbFloat('FOV'), wbInteger('Value', itU32), wbFloat('Weight') ], cpNormal, True), wbFloat(FNAM, 'Fade value', cpNormal, True), wbFormIDCk(SNAM, 'Sound', [SOUN]) ], False, nil, cpNormal, False, wbLIGHAfterLoad); wbRecord(LSCR, 'Load Screen', [ wbEDIDReq, wbICONReq, wbDESCReq, wbRArrayS('Locations', wbStructSK(LNAM, [0, 1], 'Location', [ wbFormIDCkNoReach('Cell', [CELL, WRLD]), wbByteArray('Unused', 8) ])) ]); wbRecord(LTEX, 'Landscape Texture', [ wbEDIDReq, wbICON, wbFormIDCk(TNAM, 'Texture', [TXST], False, cpNormal, True), wbStruct(HNAM, 'Havok Data', [ wbInteger('Material Type', itU8, wbEnum([ {00} 'STONE', {01} 'CLOTH', {02} 'DIRT', {03} 'GLASS', {04} 'GRASS', {05} 'METAL', {06} 'ORGANIC', {07} 'SKIN', {08} 'WATER', {09} 'WOOD', {10} 'HEAVY STONE', {11} 'HEAVY METAL', {12} 'HEAVY WOOD', {13} 'CHAIN', {14} 'SNOW', {15} 'ELEVATOR', {16} 'HOLLOW METAL', {17} 'SHEET METAL', {18} 'SAND', {19} 'BRIKEN CONCRETE', {20} 'VEHILCE BODY', {21} 'VEHILCE PART SOLID', {22} 'VEHILCE PART HOLLOW', {23} 'BARREL', {24} 'BOTTLE', {25} 'SODA CAN', {26} 'PISTOL', {27} 'RIFLE', {28} 'SHOPPING CART', {29} 'LUNCHBOX', {30} 'BABY RATTLE', {31} 'RUBER BALL' ])), wbInteger('Friction', itU8), wbInteger('Restitution', itU8) ], cpNormal, True), wbInteger(SNAM, 'Texture Specular Exponent', itU8, nil, cpNormal, True), wbRArrayS('Grasses', wbFormIDCk(GNAM, 'Grass', [GRAS])) ]); wbRecord(LVLC, 'Leveled Creature', [ wbEDIDReq, wbOBNDReq, wbInteger(LVLD, 'Chance none', itU8, nil, cpNormal, True), wbInteger(LVLF, 'Flags', itU8, wbFlags([ {0x01} 'Calculate from all levels <= player''s level', {0x02} 'Calculate for each item in count' ]), cpNormal, True), wbRArrayS('Leveled List Entries', wbRStructExSK([0], [1], 'Leveled List Entry', [ wbStructExSK(LVLO , [0, 2], [3], 'Base Data', [ wbInteger('Level', itS16), wbByteArray('Unused', 2), wbFormIDCk('Reference', [CREA, LVLC]), wbInteger('Count', itS16), wbByteArray('Unused', 2) ]), wbCOED ], []), cpNormal, True), wbMODL ]); wbRecord(LVLN, 'Leveled NPC', [ wbEDIDReq, wbOBNDReq, wbInteger(LVLD, 'Chance none', itU8, nil, cpNormal, True), wbInteger(LVLF, 'Flags', itU8, wbFlags([ {0x01} 'Calculate from all levels <= player''s level', {0x02} 'Calculate for each item in count' ]), cpNormal, True), wbRArrayS('Leveled List Entries', wbRStructExSK([0], [1], 'Leveled List Entry', [ wbStructExSK(LVLO , [0, 2], [3], 'Base Data', [ wbInteger('Level', itS16), wbByteArray('Unused', 2), wbFormIDCk('Reference', [NPC_, LVLN]), wbInteger('Count', itS16), wbByteArray('Unused', 2) ]), wbCOED ], []), cpNormal, True), wbMODL ]); wbRecord(LVLI, 'Leveled Item', [ wbEDIDReq, wbOBNDReq, wbInteger(LVLD, 'Chance none', itU8, nil, cpNormal, True), wbInteger(LVLF, 'Flags', itU8, wbFlags([ {0x01} 'Calculate from all levels <= player''s level', {0x02} 'Calculate for each item in count', {0x04} 'Use All' ]), cpNormal, True), wbFormIDCk(LVLG, 'Global', [GLOB]), wbRArrayS('Leveled List Entries', wbRStructExSK([0], [1], 'Leveled List Entry', [ wbStructExSK(LVLO , [0, 2], [3], 'Base Data', [ wbInteger('Level', itS16), wbByteArray('Unused', 2), wbFormIDCk('Reference', [ARMO, AMMO, MISC, WEAP, BOOK, LVLI, KEYM, ALCH, NOTE]), wbInteger('Count', itS16), wbByteArray('Unused', 2) ]), wbCOED ], []) ) ]); wbArchtypeEnum := wbEnum([ {00} 'Value Modifier', {01} 'Script', {02} 'Dispel', {03} 'Cure Disease', {04} '', {05} '', {06} '', {07} '', {08} '', {09} '', {10} '', {11} 'Invisibility', {12} 'Chameleon', {13} 'Light', {14} '', {15} '', {16} 'Lock', {17} 'Open', {18} 'Bound Item', {19} 'Summon Creature', {20} '', {21} '', {22} '', {23} '', {24} 'Paralysis', {25} '', {26} '', {27} '', {28} '', {29} '', {30} 'Cure Paralysis', {31} 'Cure Addiction', {32} 'Cure Poison', {33} 'Concussion', {34} 'Value And Parts' ]); wbRecord(MGEF, 'Base Effect', [ wbEDIDReq, wbFULL, wbDESCReq, wbICON, wbMODL, wbStruct(DATA, 'Data', [ wbInteger('Flags', itU32, wbFlags([ {0x00000001} 'Hostile', {0x00000002} 'Recover', {0x00000004} 'Detrimental', {0x00000008} '', {0x00000010} 'Self', {0x00000020} 'Touch', {0x00000040} 'Target', {0x00000080} 'No Duration', {0x00000100} 'No Magnitude', {0x00000200} 'No Area', {0x00000400} 'FX Persist', {0x00000800} '', {0x00001000} 'Gory Visuals', {0x00002000} 'Display Name Only', {0x00004000} '', {0x00008000} 'Radio Broadcast ??', {0x00010000} '', {0x00020000} '', {0x00040000} '', {0x00080000} 'Use skill', {0x00100000} 'Use attribute', {0x00200000} '', {0x00400000} '', {0x00800000} '', {0x01000000} 'Painless', {0x02000000} 'Spray projectile type (or Fog if Bolt is specified as well)', {0x04000000} 'Bolt projectile type (or Fog if Spray is specified as well)', {0x08000000} 'No Hit Effect', {0x10000000} 'No Death Dispel', {0x20000000} '????' ])), {04} wbFloat('Base cost (Unused)'), {08} wbUnion('Assoc. Item', wbMGEFFAssocItemDecider, [ wbFormID('Unused', cpIgnore), wbFormID('Assoc. Item'), wbFormIDCk('Assoc. Script', [SCPT, NULL]), //Script wbFormIDCk('Assoc. Item', [WEAP, ARMO, NULL]), //Bound Item wbFormIDCk('Assoc. Creature', [CREA]) //Summon Creature ], cpNormal, false, nil, wbMGEFFAssocItemAfterSet), {12} wbInteger('Magic School (Unused)', itS32, wbEnum([ ], [ -1, 'None' ])), {16} wbInteger('Resistance Type', itS32, wbActorValueEnum), {20} wbInteger('Counter effect count', itU16), {22} wbByteArray('Unused', 2), {24} wbFormIDCk('Light', [LIGH, NULL]), {28} wbFloat('Projectile speed'), {32} wbFormIDCk('Effect Shader', [EFSH, NULL]), {36} wbFormIDCk('Object Display Shader', [EFSH, NULL]), {40} wbFormIDCk('Effect sound', [NULL, SOUN]), {44} wbFormIDCk('Bolt sound', [NULL, SOUN]), {48} wbFormIDCk('Hit sound', [NULL, SOUN]), {52} wbFormIDCk('Area sound', [NULL, SOUN]), {56} wbFloat('Constant Effect enchantment factor (Unused)'), {60} wbFloat('Constant Effect barter factor (Unused)'), {64} wbInteger('Archtype', itU32, wbArchtypeEnum, cpNormal, False, nil, wbMGEFArchtypeAfterSet), {68} wbActorValue ], cpNormal, True), wbRArrayS('Counter Effects', wbFormIDCk(ESCE, 'Effect', [MGEF]), cpNormal, False, nil, wbCounterEffectsAfterSet) ], False, nil, cpNormal, False, wbMGEFAfterLoad, wbMGEFAfterSet); wbRecord(MISC, 'Misc. Item', [ wbEDIDReq, wbOBNDReq, wbFULL, wbMODL, wbICON, wbSCRI, wbDEST, wbYNAM, wbZNAM, wbStruct(DATA, '', [ wbInteger('Value', itS32), wbFloat('Weight') ], cpNormal, True) ]); wbRecord(COBJ, 'Constructible Object', [ wbEDID, wbOBND, wbFULL, wbMODL, wbICON, wbSCRI, wbYNAM, wbZNAM, wbStruct(DATA, '', [ wbInteger('Value', itS32), wbFloat('Weight') ], cpNormal, True) ]); wbFaceGen := wbRStruct('FaceGen Data', [ wbByteArray(FGGS, 'FaceGen Geometry-Symmetric', 0, cpNormal, True), wbByteArray(FGGA, 'FaceGen Geometry-Asymmetric', 0, cpNormal, True), wbByteArray(FGTS, 'FaceGen Texture-Symmetric', 0, cpNormal, True) ], [], cpNormal, True); wbFaceGenNPC := wbRStruct('FaceGen Data', [ wbByteArray(FGGS, 'FaceGen Geometry-Symmetric', 0, cpNormal, True), wbByteArray(FGGA, 'FaceGen Geometry-Asymmetric', 0, cpNormal, True), wbByteArray(FGTS, 'FaceGen Texture-Symmetric', 0, cpNormal, True) ], [], cpNormal, True, wbActorTemplateUseModelAnimation); wbRecord(NPC_, 'Non-Player Character', [ wbEDIDReq, wbOBNDReq, wbFULLActor, wbMODLActor, wbStruct(ACBS, 'Configuration', [ {00} wbInteger('Flags', itU32, wbFlags([ {0x000001} 'Female', {0x000002} 'Essential', {0x000004} 'Is CharGen Face Preset', {0x000008} 'Respawn', {0x000010} 'Auto-calc stats', {0x000020} '', {0x000040} '', {0x000080} 'PC Level Mult', {0x000100} 'Use Template', {0x000200} 'No Low Level Processing', {0x000400} '', {0x000800} 'No Blood Spray', {0x001000} 'No Blood Decal', {0x002000} '', {0x004000} '', {0x008000} '', {0x010000} '', {0x020000} '', {0x040000} '', {0x080000} '', {0x100000} 'No VATS Melee', {0x00200000} '', {0x00400000} 'Can be all races', {0x00800000} '', {0x01000000} '', {0x02000000} '', {0x03000000} 'No Knockdowns', {0x08000000} 'Not Pushable', {0x10000000} '', {28} {0x20000000} '', {0x40000000} 'No Rotating To Head-track', {0x80000000} '' ], [ {0x000001 Female} wbActorTemplateUseTraits, {0x000002 Essential} wbActorTemplateUseBaseData, {0x000004 Is CharGen Face Preset} nil, {0x000008 Respawn} wbActorTemplateUseBaseData, {0x000010 Auto-calc stats} wbActorTemplateUseStats, {0x000020 } nil, {0x000040 } nil, {0x000080 PC Level Mult} wbActorTemplateUseStats, {0x000100 Use Template} nil, {0x000200 No Low Level Processing} wbActorTemplateUseBaseData, {0x000400 } nil, {0x000800 No Blood Spray} wbActorTemplateUseModelAnimation, {0x001000 No Blood Decal} wbActorTemplateUseModelAnimation, {0x002000 } nil, {0x004000 } nil, {0x008000 } nil, {0x010000 } nil, {0x020000 } nil, {0x040000 } nil, {0x080000 } nil, {0x100000 No VATS Melee} nil, {0x00200000 } nil, {0x00400000 Can be all races} nil, {0x00800000 } nil, {0x01000000 } nil, {0x02000000 } nil, {0x03000000 No Knockdowns} nil, {0x08000000 Not Pushable} wbActorTemplateUseModelAnimation, {0x10000000 } nil, {0x20000000 } nil, {0x40000000 No Rotating To Head-track} wbActorTemplateUseModelAnimation, {0x80000000 } nil ])), {04} wbInteger('Fatigue', itU16, nil, cpNormal, True, wbActorTemplateUseStats), {06} wbInteger('Barter gold', itU16, nil, cpNormal, False, wbActorTemplateUseAIData), {08} wbUnion('Level', wbCreaLevelDecider, [ wbInteger('Level', itS16, nil, cpNormal, True, wbActorTemplateUseStats), wbInteger('Level Mult', itS16, wbDiv(1000), cpNormal, True, wbActorTemplateUseStats) ], cpNormal, True, wbActorTemplateUseStats), {10} wbInteger('Calc min', itU16, nil, cpNormal, True, wbActorTemplateUseStats), {12} wbInteger('Calc max', itU16, nil, cpNormal, True, wbActorTemplateUseStats), {14} wbInteger('Speed Multiplier', itU16, nil, cpNormal, True, wbActorTemplateUseStats), {16} wbFloat('Karma (Alignment)', cpNormal, False, 1, -1, wbActorTemplateUseTraits), {20} wbInteger('Disposition Base', itS16, nil, cpNormal, False, wbActorTemplateUseTraits), {22} wbInteger('Template Flags', itU16, wbTemplateFlags) ], cpNormal, True), wbRArrayS('Factions', wbStructSK(SNAM, [0], 'Faction', [ wbFormIDCk('Faction', [FACT]), wbInteger('Rank', itU8), wbByteArray('Unused', 3) ]), cpNormal, False, nil, nil, wbActorTemplateUseFactions), wbFormIDCk(INAM, 'Death item', [LVLI], False, cpNormal, False, wbActorTemplateUseTraits), wbFormIDCk(VTCK, 'Voice', [VTYP], False, cpNormal, True, wbActorTemplateUseTraits), wbFormIDCk(TPLT, 'Template', [LVLN, NPC_]), wbFormIDCk(RNAM, 'Race', [RACE], False, cpNormal, True, wbActorTemplateUseTraits), wbSPLOs, wbFormIDCk(EITM, 'Unarmed Attack Effect', [ENCH, SPEL], False, cpNormal, False, wbActorTemplateUseActorEffectList), wbInteger(EAMT, 'Unarmed Attack Animation', itU16, wbAttackAnimationEnum, cpNormal, True, False, wbActorTemplateUseActorEffectList), wbDESTActor, wbSCRIActor, wbRArrayS('Items', wbCNTO, cpNormal, False, nil, nil, wbActorTemplateUseInventory), wbAIDT, wbRArray('Packages', wbFormIDCk(PKID, 'Package', [PACK]), cpNormal, False, nil, nil, wbActorTemplateUseAIPackages), wbArrayS(KFFZ, 'Animations', wbStringLC('Animation'), 0, cpNormal, False, nil, nil, wbActorTemplateUseModelAnimation), wbFormIDCk(CNAM, 'Class', [CLAS], False, cpNormal, True, wbActorTemplateUseTraits), wbStruct(DATA, '', [ {00} wbInteger('Base Health', itS32), {04} wbArray('Attributes', wbInteger('Attribute', itU8), [ 'Strength', 'Perception', 'Endurance', 'Charisma', 'Intelligence', 'Agility', 'Luck' ], cpNormal, False, wbActorAutoCalcDontShow), wbByteArray('Unused'{, 14 - only present in old record versions}) ], cpNormal, True, wbActorTemplateUseStats), wbStruct(DNAM, '', [ {00} wbArray('Skill Values', wbInteger('Skill', itU8), [ 'Barter', 'Big Guns', 'Energy Weapons', 'Explosives', 'Lockpick', 'Medicine', 'Melee Weapons', 'Repair', 'Science', 'Small Guns', 'Sneak', 'Speech', 'Throwing (unused)', 'Unarmed' ]), {14} wbArray('Skill Offsets', wbInteger('Skill', itU8), [ 'Barter', 'Big Guns', 'Energy Weapons', 'Explosives', 'Lockpick', 'Medicine', 'Melee Weapons', 'Repair', 'Science', 'Small Guns', 'Sneak', 'Speech', 'Throwing (unused)', 'Unarmed' ]) ], cpNormal, False, wbActorTemplateUseStatsAutoCalc), wbRArrayS('Head Parts', wbFormIDCk(PNAM, 'Head Part', [HDPT]), cpNormal, False, nil, nil, wbActorTemplateUseModelAnimation), wbFormIDCk(HNAM, 'Hair', [HAIR], False, cpNormal, False, wbActorTemplateUseModelAnimation), wbFloat(LNAM, 'Hair length', cpNormal, False, 1, -1, wbActorTemplateUseModelAnimation), wbFormIDCk(ENAM, 'Eyes', [EYES], False, cpNormal, False, wbActorTemplateUseModelAnimation), wbStruct(HCLR, 'Hair color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ], cpNormal, True, wbActorTemplateUseModelAnimation), wbFormIDCk(ZNAM, 'Combat Style', [CSTY], False, cpNormal, False, wbActorTemplateUseTraits), wbInteger(NAM4, 'Impact Material Type', itU32, wbImpactMaterialTypeEnum, cpNormal, True, False, wbActorTemplateUseModelAnimation), wbFaceGenNPC, wbInteger(NAM5, 'Unknown', itU16, nil, cpNormal, True, False, nil, nil, 255), wbFloat(NAM6, 'Height', cpNormal, True, 1, -1, wbActorTemplateUseTraits), wbFloat(NAM7, 'Weight', cpNormal, True, 1, -1, wbActorTemplateUseTraits) ], True, nil, cpNormal, False, wbNPCAfterLoad); wbPKDTFlags := wbFlags([ {0x00000001} 'Offers Services', {0x00000002} 'Must reach location', {0x00000004} 'Must complete', {0x00000008} 'Lock doors at package start', {0x00000010} 'Lock doors at package end', {0x00000020} 'Lock doors at location', {0x00000040} 'Unlock doors at package start', {0x00000080} 'Unlock doors at package end', {0x00000100} 'Unlock doors at location', {0x00000200} 'Continue if PC near', {0x00000400} 'Once per day', {0x00000800} '', {0x00001000} 'Skip fallout behavior', {0x00002000} 'Always run', {0x00004000} '', {0x00008000} '', {0x00010000} '', {0x00020000} 'Always sneak', {0x00040000} 'Allow swimming', {0x00080000} 'Allow falls', {0x00100000} 'Head-Tracking off', {0x00200000} 'Weapons unequipped', {0x00400000} 'Defensive combat', {0x00800000} 'Weapon Drawn', {0x01000000} 'No idle anims', {0x02000000} 'Pretend In Combat', {0x04000000} 'Continue During Combat', {0x08000000} 'No Combat Alert', {0x10000000} 'No Warn/Attack Behaviour', {0x20000000} '', {0x40000000} '', {0x80000000} '' ]); wbPKDTType := wbEnum([ {0} 'Find', {1} 'Follow', {2} 'Escort', {3} 'Eat', {4} 'Sleep', {5} 'Wander', {6} 'Travel', {7} 'Accompany', {8} 'Use Item At', {9} 'Ambush', {10} 'Flee Not Combat', {11} '', {12} 'Sandbox', {13} 'Patrol', {14} 'Guard', {15} 'Dialogue', {16} 'Use Weapon' ]); wbObjectTypeEnum := wbEnum([ ' NONE', 'Activators', 'Armor', 'Books', 'Clothing', 'Containers', 'Doors', 'Ingredients', 'Lights', 'Misc', 'Flora', 'Furniture', 'Weapons: Any', 'Ammo', 'NPCs', 'Creatures', 'Keys', 'Alchemy', 'Food', ' All: Combat Wearable', ' All: Wearable', 'Weapons: Ranged', 'Weapons: Melee', 'Weapons: NONE', 'Actor Effects: Any', 'Actor Effects: Range Target', 'Actor Effects: Range Touch', 'Actor Effects: Range Self', '', 'Actors: Any' ]); wbPKDTSpecificFlagsUnused := True; wbRecord(PACK, 'Package', [ wbEDIDReq, wbStruct(PKDT, 'General', [ wbInteger('General Flags', itU32, wbPKDTFlags), wbInteger('Type', itU8, wbPKDTType), wbByteArray('Unused', 1), wbInteger('Fallout Behavior Flags', itU16, wbFlags([ {0x00000001}'Hellos To Player', {0x00000002}'Random Conversations', {0x00000004}'Observe Combat Behavior', {0x00000008}'Unknown 4', {0x00000010}'Reaction To Player Actions', {0x00000020}'Friendly Fire Comments', {0x00000040}'Aggro Radius Behavior', {0x00000080}'Allow Idle Chatter', {0x00000100}'Avoid Radiation' ], True)), wbUnion('Type Specific Flags', wbPKDTSpecificFlagsDecider, [ wbEmpty('Type Specific Flags (missing)', cpIgnore, False, nil, True), wbInteger('Type Specific Flags - Find', itU16, wbFlags([ {0x00000001}'', {0x00000002}'', {0x00000004}'', {0x00000008}'', {0x00000010}'', {0x00000020}'', {0x00000040}'', {0x00000080}'', {0x00000100}'Find - Allow Buying', {0x00000200}'Find - Allow Killing', {0x00000400}'Find - Allow Stealing' ], wbPKDTSpecificFlagsUnused)), wbInteger('Type Specific Flags - Follow', itU16, wbFlags([], wbPKDTSpecificFlagsUnused)), wbInteger('Type Specific Flags - Escort', itU16, wbFlags([ {0x00000001}'', {0x00000002}'', {0x00000004}'', {0x00000008}'', {0x00000010}'', {0x00000020}'', {0x00000040}'', {0x00000080}'', {0x00000100}'Escort - Allow Buying', {0x00000200}'Escort - Allow Killing', {0x00000400}'Escort - Allow Stealing' ], wbPKDTSpecificFlagsUnused)), wbInteger('Type Specific Flags - Eat', itU16, wbFlags([ {0x00000001}'', {0x00000002}'', {0x00000004}'', {0x00000008}'', {0x00000010}'', {0x00000020}'', {0x00000040}'', {0x00000080}'', {0x00000100}'Eat - Allow Buying', {0x00000200}'Eat - Allow Killing', {0x00000400}'Eat - Allow Stealing' ], wbPKDTSpecificFlagsUnused)), wbInteger('Type Specific Flags - Sleep', itU16, wbFlags([], wbPKDTSpecificFlagsUnused)), wbInteger('Type Specific Flags - Wander', itU16, wbFlags([ {0x00000001}'Wander - No Eating', {0x00000002}'Wander - No Sleeping', {0x00000004}'Wander - No Conversation', {0x00000008}'Wander - No Idle Markers', {0x00000010}'Wander - No Furniture', {0x00000020}'Wander - No Wandering' ], wbPKDTSpecificFlagsUnused)), wbInteger('Type Specific Flags - Travel', itU16, wbFlags([], wbPKDTSpecificFlagsUnused)), wbInteger('Type Specific Flags - Accompany', itU16, wbFlags([], wbPKDTSpecificFlagsUnused)), wbInteger('Type Specific Flags - Use Item At', itU16, wbFlags([ {0x00000001}'', {0x00000002}'Use Item At - Sit Down', {0x00000004}'', {0x00000008}'', {0x00000010}'', {0x00000020}'', {0x00000040}'', {0x00000080}'', {0x00000100}'Use Item At - Allow Buying', {0x00000200}'Use Item At - Allow Killing', {0x00000400}'Use Item At - Allow Stealing' ], wbPKDTSpecificFlagsUnused)), wbInteger('Type Specific Flags - Ambush', itU16, wbFlags([ {0x00000001}'Ambush - Hide While Ambushing' ], wbPKDTSpecificFlagsUnused)), wbInteger('Type Specific Flags - Flee Not Combat', itU16, wbFlags([], wbPKDTSpecificFlagsUnused)), wbInteger('Type Specific Flags - ?', itU16, wbFlags([], wbPKDTSpecificFlagsUnused)), wbInteger('Type Specific Flags - Sandbox', itU16, wbFlags([ {0x00000001}'Sandbox - No Eating', {0x00000002}'Sandbox - No Sleeping', {0x00000004}'Sandbox - No Conversation', {0x00000008}'Sandbox - No Idle Markers', {0x00000010}'Sandbox - No Furniture', {0x00000020}'Sandbox - No Wandering' ], wbPKDTSpecificFlagsUnused)), wbInteger('Type Specific Flags - Patrol', itU16, wbFlags([], wbPKDTSpecificFlagsUnused)), wbInteger('Type Specific Flags - Guard', itU16, wbFlags([ {0x00000001}'', {0x00000002}'', {0x00000004}'Guard - Remain Near Reference to Guard' ], wbPKDTSpecificFlagsUnused)), wbInteger('Type Specific Flags - Dialogue', itU16, wbFlags([], wbPKDTSpecificFlagsUnused)), wbInteger('Type Specific Flags - Use Weapon', itU16, wbFlags([], wbPKDTSpecificFlagsUnused)) ]), wbByteArray('Unused', 2) ], cpNormal, True, nil, 2), wbRStruct('Locations', [ wbStruct(PLDT, 'Location 1', [ wbInteger('Type', itS32, wbEnum([ // Byte + filler {0} 'Near reference', {1} 'In cell', {2} 'Near current location', {3} 'Near editor location', {4} 'Object ID', {5} 'Object Type', {6} 'Near linked reference', {7} 'At package location' ])), wbUnion('Location', wbPxDTLocationDecider, [ wbFormIDCkNoReach('Reference', [REFR, PGRE, PMIS, PBEA, ACHR, ACRE, PLYR], True), wbFormIDCkNoReach('Cell', [CELL]), wbByteArray('Unused', 4, cpIgnore), wbByteArray('Unused', 4, cpIgnore), wbFormIDCkNoReach('Object ID', [ACTI, DOOR, STAT, FURN, CREA, SPEL, NPC_, CONT, ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, LIGH]), wbInteger('Object Type', itU32, wbObjectTypeEnum), wbByteArray('Unused', 4, cpIgnore), wbByteArray('Unused', 4, cpIgnore) ]), wbInteger('Radius', itS32) ]), wbStruct(PLD2, 'Location 2', [ wbInteger('Type', itS32, wbEnum([ {0} 'Near reference', {1} 'In cell', {2} 'Near current location', {3} 'Near editor location', {4} 'Object ID', {5} 'Object Type', {6} 'Near linked reference', {7} 'At package location' ])), wbUnion('Location', wbPxDTLocationDecider, [ wbFormIDCkNoReach('Reference', [REFR, PGRE, PMIS, PBEA, ACHR, ACRE, PLYR], True), wbFormIDCkNoReach('Cell', [CELL]), wbByteArray('Unused', 4, cpIgnore), wbByteArray('Unused', 4, cpIgnore), wbFormIDCkNoReach('Object ID', [ACTI, DOOR, STAT, FURN, CREA, SPEL, NPC_, CONT, ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, LIGH]), wbInteger('Object Type', itU32, wbObjectTypeEnum), wbByteArray('Unused', 4, cpIgnore), wbByteArray('Unused', 4, cpIgnore) ]), wbInteger('Radius', itS32) ]) ], []), wbStruct(PSDT, 'Schedule', [ wbInteger('Month', itS8), wbInteger('Day of week', itS8, wbEnum([ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Weekdays', 'Weekends', 'Monday, Wednesday, Friday', 'Tuesday, Thursday' ], [ -1, 'Any' ])), wbInteger('Date', itU8), wbInteger('Time', itS8), wbInteger('Duration', itS32) ], cpNormal, True), wbStruct(PTDT, 'Target 1', [ wbInteger('Type', itS32, wbEnum([ {0} 'Specific Reference', {1} 'Object ID', {2} 'Object Type', {3} 'Linked Reference' ]), cpNormal, False, nil, nil, 2), wbUnion('Target', wbPxDTLocationDecider, [ wbFormIDCkNoReach('Reference', [ACHR, ACRE, REFR, PGRE, PMIS, PBEA, PLYR], True), wbFormIDCkNoReach('Object ID', [ACTI, DOOR, STAT, FURN, CREA, SPEL, NPC_, LVLN, LVLC, CONT, ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, LIGH, FACT, FLST]), wbInteger('Object Type', itU32, wbObjectTypeEnum), wbByteArray('Unused', 4, cpIgnore) ]), wbInteger('Count / Distance', itS32), wbFloat('Unknown') ], cpNormal, False, nil, 3), wbCTDAs, wbRStruct('Idle Animations', [ wbInteger(IDLF, 'Flags', itU8, wbFlags([ 'Run in Sequence', '', 'Do Once' ]), cpNormal, True), wbStruct(IDLC, '', [ wbInteger( 'Animation Count', itU8), wbByteArray('Unused', 3) ], cpNormal, True, nil, 1), wbFloat(IDLT, 'Idle Timer Setting', cpNormal, True), wbArray(IDLA, 'Animations', wbFormIDCk('Animation', [IDLE]), 0, nil, wbIDLAsAfterSet, cpNormal, True), wbByteArray(IDLB, 'Unused', 4, cpIgnore) ], [], cpNormal, False, nil, False, nil {cannot be totally removed , wbAnimationsAfterSet}), wbFormIDCk(CNAM, 'Combat Style', [CSTY]), wbEmpty(PKED, 'Eat Marker'), wbInteger(PKE2, 'Escort Distance', itU32), wbFloat(PKFD, 'Follow - Start Location - Trigger Radius'), wbStruct(PKPT, 'Patrol Flags', [ wbInteger('Repeatable', itU8, wbEnum(['No', 'Yes']), cpNormal, False, nil, nil, 1), wbByteArray('Unused', 1) ], cpNormal, False, nil, 1), wbStruct(PKW3, 'Use Weapon Data', [ wbInteger('Flags', itU32, wbFlags([ 'Always Hit', '', '', '', '', '', '', '', 'Do No Damage', '', '', '', '', '', '', '', 'Crouch To Reload', '', '', '', '', '', '', '', 'Hold Fire When Blocked' ])), wbInteger('Fire Rate', itU8, wbEnum([ 'Auto Fire', 'Volley Fire' ])), wbInteger('Fire Count', itU8, wbEnum([ 'Number of Bursts', 'Repeat Fire' ])), wbInteger('Number of Bursts', itU16), wbStruct('Shoots Per Volleys', [ wbInteger('Min', itU16), wbInteger('Max', itU16) ]), wbStruct('Pause Between Volleys', [ wbFloat('Min'), wbFloat('Max') ]), wbByteArray('Unused', 4) ]), wbStruct(PTD2, 'Target 2', [ wbInteger('Type', itS32, wbEnum([ {0} 'Specific reference', {1} 'Object ID', {2} 'Object Type', {3} 'Linked Reference' ])), wbUnion('Target', wbPxDTLocationDecider, [ wbFormIDCkNoReach('Reference', [ACHR, ACRE, REFR, PGRE, PMIS, PBEA, PLYR], True), wbFormIDCkNoReach('Object ID', [ACTI, DOOR, STAT, FURN, CREA, SPEL, NPC_, LVLN, LVLC, CONT, ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, LIGH, FACT, FLST]), wbInteger('Object Type', itU32, wbObjectTypeEnum), wbByteArray('Unused', 4, cpIgnore) ]), wbInteger('Count / Distance', itS32), wbFloat('Unknown') ], cpNormal, False, nil, 3), wbEmpty(PUID, 'Use Item Marker'), wbEmpty(PKAM, 'Ambush Marker'), wbStruct(PKDD, 'Dialogue Data', [ wbFloat('FOV'), wbFormIDCk('Topic', [DIAL, NULL]), wbInteger('Flags', itU32, wbFlags([ 'No Headtracking', '', '', '', '', '', '', '', 'Don''t Control Target Movement' ])), wbByteArray('Unused', 4), wbInteger('Dialogue Type', itU32, wbEnum([ 'Conversation', 'Say To' ])), wbByteArray('Unknown', 4) ], cpNormal, False, nil, 3), wbStruct(PLD2, 'Location 2 (again??)', [ wbInteger('Type', itS32, wbEnum([ {0} 'Near reference', {1} 'In cell', {2} 'Near current location', {3} 'Near editor location', {4} 'Object ID', {5} 'Object Type', {6} 'Near linked reference', {7} 'At package location' ])), wbUnion('Location', wbPxDTLocationDecider, [ wbFormIDCkNoReach('Reference', [REFR, PGRE, PMIS, PBEA, ACHR, ACRE, PLYR], True), wbFormIDCkNoReach('Cell', [CELL]), wbByteArray('Unused', 4, cpIgnore), wbByteArray('Unused', 4, cpIgnore), wbFormIDCkNoReach('Object ID', [ACTI, DOOR, STAT, FURN, CREA, SPEL, NPC_, CONT, ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, LIGH]), wbInteger('Object Type', itU32, wbObjectTypeEnum), wbByteArray('Unused', 4, cpIgnore), wbByteArray('Unused', 4, cpIgnore) ]), wbInteger('Radius', itS32) ]), wbRStruct('OnBegin', [ wbEmpty(POBA, 'OnBegin Marker', cpNormal, True), wbFormIDCk(INAM, 'Idle', [IDLE, NULL], False, cpNormal, True), wbEmbeddedScriptReq, wbFormIDCk(TNAM, 'Topic', [DIAL, NULL], False, cpNormal, True) ], [], cpNormal, True), wbRStruct('OnEnd', [ wbEmpty(POEA, 'OnEnd Marker', cpNormal, True), wbFormIDCk(INAM, 'Idle', [IDLE, NULL], False, cpNormal, True), wbEmbeddedScriptReq, wbFormIDCk(TNAM, 'Topic', [DIAL, NULL], False, cpNormal, True) ], [], cpNormal, True), wbRStruct('OnChange', [ wbEmpty(POCA, 'OnChange Marker', cpNormal, True), wbFormIDCk(INAM, 'Idle', [IDLE, NULL], False, cpNormal, True), wbEmbeddedScriptReq, wbFormIDCk(TNAM, 'Topic', [DIAL, NULL], False, cpNormal, True) ], [], cpNormal, True) ], False, nil, cpNormal, False, wbPACKAfterLoad); wbRecord(QUST, 'Quest', [ wbEDIDReq, wbSCRI, wbFULL, wbICON, wbStruct(DATA, 'General', [ wbInteger('Flags', itU8, wbFlags([ {0x01} 'Start game enabled', {0x02} '', {0x04} 'Allow repeated conversation topics', {0x08} 'Allow repeated stages', {0x10} 'Unknown 4' ])), wbInteger('Priority', itU8), wbByteArray('Unused', 2), wbFloat('Quest Delay') ], cpNormal, True, nil, 3), wbCTDAs, wbRArrayS('Stages', wbRStructSK([0], 'Stage', [ wbInteger(INDX, 'Stage Index', itS16), wbRArray('Log Entries', wbRStruct('Log Entry', [ wbInteger(QSDT, 'Stage Flags', itU8, wbFlags([ {0x01} 'Complete Quest', {0x02} 'Fail Quest' ])), wbCTDAs, wbString(CNAM, 'Log Entry', 0, cpTranslate), wbEmbeddedScriptReq, wbFormIDCk(NAM0, 'Next Quest', [QUST]) ], [])) ], [])), wbRArray('Objectives', wbRStruct('Objective', [ wbInteger(QOBJ, 'Objective Index', itS32), wbString(NNAM, 'Description', 0, cpNormal, True), wbRArray('Targets', wbRStruct('Target', [ wbStruct(QSTA, 'Target', [ wbFormIDCkNoReach('Target', [REFR, PGRE, PMIS, PBEA, ACRE, ACHR], True), wbInteger('Flags', itU8, wbFlags([ {0x01} 'Compass Marker Ignores Locks' ])), wbByteArray('Unused', 3) ]), wbCTDAs ], [])) ], [])) ]); wbHeadPartIndexEnum := wbEnum([ 'Head', 'Ears', 'Mouth', 'Teeth Lower', 'Teeth Upper', 'Tongue', 'Left Eye', 'Right Eye' ]); wbBodyPartIndexEnum := wbEnum([ 'Upper Body', 'Left Hand', 'Right Hand', 'Upper Body Texture' ]); wbRecord(RACE, 'Race', [ wbEDIDReq, wbFULLReq, wbDESCReq, wbXNAMs, wbStruct(DATA, '', [ wbArrayS('Skill Boosts', wbStructSK([0], 'Skill Boost', [ wbInteger('Skill', itS8, wbActorValueEnum), wbInteger('Boost', itS8) ]), 7), wbByteArray('Unused', 2), wbFloat('Male Height'), wbFloat('Female Height'), wbFloat('Male Weight'), wbFloat('Female Weight'), wbInteger('Flags', itU32, wbFlags([ 'Playable', '', 'Child' ])) ], cpNormal, True), wbFormIDCk(ONAM, 'Older', [RACE]), wbFormIDCk(YNAM, 'Younger', [RACE]), wbEmpty(NAM2, 'Unknown Marker', cpNormal, True), wbArray(VTCK, 'Voices', wbFormIDCk('Voice', [VTYP]), ['Male', 'Female'], cpNormal, True), wbArray(DNAM, 'Default Hair Styles', wbFormIDCk('Default Hair Style', [HAIR, NULL]), ['Male', 'Female'], cpNormal, True), wbArray(CNAM, 'Default Hair Colors', wbInteger('Default Hair Color', itU8, wbEnum([ 'Bleached', 'Brown', 'Chocolate', 'Platinum', 'Cornsilk', 'Suede', 'Pecan', 'Auburn', 'Ginger', 'Honey', 'Gold', 'Rosewood', 'Black', 'Chestnut', 'Steel', 'Champagne' ])), ['Male', 'Female'], cpNormal, True), wbFloat(PNAM, 'FaceGen - Main clamp', cpNormal, True), wbFloat(UNAM, 'FaceGen - Face clamp', cpNormal, True), wbByteArray(ATTR, 'Unused', 0, cpNormal, True), wbRStruct('Head Data', [ wbEmpty(NAM0, 'Head Data Marker', cpNormal, True), wbRStruct('Male Head Data', [ wbEmpty(MNAM, 'Male Data Marker', cpNormal, True), wbRArrayS('Parts', wbRStructSK([0], 'Part', [ wbInteger(INDX, 'Index', itU32, wbHeadPartIndexEnum), wbMODLReq, wbICON ], [], cpNormal, False, nil, False, nil, wbHeadPartsAfterSet), cpNormal, True) ], [], cpNormal, True), wbRStruct('Female Head Data', [ wbEmpty(FNAM, 'Female Data Marker', cpNormal, True), wbRArrayS('Parts', wbRStructSK([0], 'Part', [ wbInteger(INDX, 'Index', itU32, wbHeadPartIndexEnum), wbMODLReq, wbICON ], [], cpNormal, False, nil, False, nil, wbHeadPartsAfterSet), cpNormal, True) ], [], cpNormal, True) ], [], cpNormal, True), wbRStruct('Body Data', [ wbEmpty(NAM1, 'Body Data Marker', cpNormal, True), wbRStruct('Male Body Data', [ wbEmpty(MNAM, 'Male Data Marker'), wbRArrayS('Parts', wbRStructSK([0], 'Part', [ wbInteger(INDX, 'Index', itU32, wbBodyPartIndexEnum), wbICON, wbMODLReq ], []), cpNormal, True) ], [], cpNormal, True), wbRStruct('Female Body Data', [ wbEmpty(FNAM, 'Female Data Marker', cpNormal, True), wbRArrayS('Parts', wbRStructSK([0], 'Part', [ wbInteger(INDX, 'Index', itU32, wbBodyPartIndexEnum), wbICON, wbMODLReq ], []), cpNormal, True) ], [], cpNormal, True) ], [], cpNormal, True), wbArrayS(HNAM, 'Hairs', wbFormIDCk('Hair', [HAIR]), 0, cpNormal, True), wbArrayS(ENAM, 'Eyes', wbFormIDCk('Eye', [EYES]), 0, cpNormal, True), wbRStruct('FaceGen Data', [ wbRStruct('Male FaceGen Data', [ wbEmpty(MNAM, 'Male Data Marker', cpNormal, True), wbFaceGen, wbUnknown(SNAM, cpNormal, True) ], [], cpNormal, True), wbRStruct('Female FaceGen Data', [ wbEmpty(FNAM, 'Female Data Marker', cpNormal, True), wbFaceGen, wbUnknown(SNAM, cpNormal, True) ], [], cpNormal, True) ], [], cpNormal, True) ]); wbRecord(REFR, 'Placed Object', [ wbEDID, { wbStruct(RCLR, 'Linked Reference Color (Old Format?)', [ wbStruct('Link Start Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Link End Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]) ], cpIgnore),} wbByteArray(RCLR, 'Unused', 0, cpIgnore), wbFormIDCk(NAME, 'Base', [TREE, SOUN, ACTI, DOOR, STAT, FURN, CONT, ARMO, AMMO, LVLN, LVLC, MISC, WEAP, BOOK, KEYM, ALCH, LIGH, GRAS, ASPC, IDLM, ARMA, MSTT, NOTE, PWAT, SCOL, TACT, TERM, TXST], False, cpNormal, True), wbFormIDCk(XEZN, 'Encounter Zone', [ECZN]), {--- ?? ---} wbXRGD, wbXRGB, {--- Primitive ---} wbStruct(XPRM, 'Primitive', [ wbStruct('Bounds', [ wbFloat('X', cpNormal, True, 2, 4), wbFloat('Y', cpNormal, True, 2, 4), wbFloat('Z', cpNormal, True, 2, 4) ]), wbStruct('Color', [ {84} wbFloat('Red', cpNormal, False, 255, 0), {88} wbFloat('Green', cpNormal, False, 255, 0), {92} wbFloat('Blue', cpNormal, False, 255, 0) ]), wbFloat('Unknown'), wbInteger('Type', itU32, wbEnum([ 'None', 'Box', 'Sphere', 'Portal Box' ])) ]), wbInteger(XTRI, 'Collision Layer', itU32, wbEnum([ 'Unidentified', 'Static', 'AnimStatic', 'Transparent', 'Clutter', 'Weapon', 'Projectile', 'Spell', 'Biped', 'Trees', 'Props', 'Water', 'Trigger', 'Terrain', 'Trap', 'Non Collidable', 'Cloud Trap', 'Ground', 'Portal', 'Debris Small', 'Debris Large', 'Acustic Space', 'Actor Zone', 'Projectile Zone', 'Gas Trap', 'Shell Casing', 'Transparent Small', 'Invisible Wall', 'Transparent Small Anim', 'Dead Bip', 'Char Controller', 'Avoid Box', 'Collision Box', 'Camera Sphere', 'Door Detection', 'Camera Pick', 'Item Pick', 'Line Of Sight', 'Path Pick', 'Custom Pick 1', 'Custom Pick 2', 'Spell Explosion', 'Dropping Pick' ])), wbEmpty(XMBP, 'MultiBound Primitive Marker'), {--- Bound Contents ---} {--- Bound Data ---} wbStruct(XMBO, 'Bound Half Extents', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), {--- Teleport ---} wbStruct(XTEL, 'Teleport Destination', [ wbFormIDCk('Door', [REFR], True), wbPosRot, wbInteger('Flags', itU32, wbFlags([ 'No Alarm' ])) ]), {--- Map Data ---} wbRStruct('Map Marker', [ wbEmpty(XMRK, 'Map Marker Data'), wbInteger(FNAM, 'Flags', itU8, wbFlags([ {0x01} 'Visible', {0x02} 'Can Travel To', {0x04} '"Show All" Hidden' ]), cpNormal, True), wbFULLReq, wbStruct(TNAM, '', [ wbInteger('Type', itU8, wbEnum([ 'None', 'City', 'Settlement', 'Encampment', 'Natural Landmark', 'Cave', 'Factory', 'Monument', 'Military', 'Office', 'Town Ruins', 'Urban Ruins', 'Sewer Ruins', 'Metro', 'Vault' ])), wbByteArray('Unused', 1) ], cpNormal, True) ], []), wbInteger(XSRF, 'Special Rendering Flags', itU32, wbFlags([ 'Unknown 0', 'Imposter', 'Use Full Shader in LOD' ])), wbByteArray(XSRD, 'Special Rendering Data', 4), {--- X Target Data ---} wbFormIDCk(XTRG, 'Target', [REFR, ACRE, ACHR, PGRE, PMIS, PBEA], True), {--- Leveled Actor ----} wbXLCM, {--- Patrol Data ---} wbRStruct('Patrol Data', [ wbFloat(XPRD, 'Idle Time', cpNormal, True), wbEmpty(XPPA, 'Patrol Script Marker', cpNormal, True), wbFormIDCk(INAM, 'Idle', [IDLE, NULL], False, cpNormal, True), wbEmbeddedScriptReq, wbFormIDCk(TNAM, 'Topic', [DIAL, NULL], False, cpNormal, True) ], []), {--- Radio ---} wbStruct(XRDO, 'Radio Data', [ wbFloat('Range Radius'), wbInteger('Broadcast Range Type', itU32, wbEnum([ 'Radius', 'Everywhere', 'Worldspace and Linked Interiors', 'Linked Interiors', 'Current Cell Only' ])), wbFloat('Static Percentage'), wbFormIDCkNoReach('Position Reference', [REFR, ACRE, ACHR, PGRE, PMIS, PBEA, NULL]) ]), {--- Ownership ---} wbRStruct('Ownership', [ wbXOWN, wbInteger(XRNK, 'Faction rank', itS32) ], [XCMT, XCMO]), {--- Lock ---} wbStruct(XLOC, 'Lock Data', [ wbInteger('Level', itU8), wbByteArray('Unused', 3), wbFormIDCkNoReach('Key', [KEYM, NULL]), wbInteger('Flags', itU8, wbFlags(['', '', 'Leveled Lock'])), wbByteArray('Unused', 3), wbByteArray('Unknown', 8) ], cpNormal, False, nil, 5), {--- Extra ---} wbInteger(XCNT, 'Count', itS32), wbFloat(XRDS, 'Radius'), wbFloat(XHLP, 'Health'), wbFloat(XRAD, 'Radiation'), wbFloat(XCHG, 'Charge'), wbRStruct('Ammo', [ wbFormIDCk(XAMT, 'Type', [AMMO], False, cpNormal, True), wbInteger(XAMC, 'Count', itS32, nil, cpNormal, True) ], []), {--- Reflected By / Refracted By ---} wbRArrayS('Reflected/Refracted By', wbStructSK(XPWR, [0], 'Water', [ wbFormIDCk('Reference', [REFR]), wbInteger('Type', itU32, wbFlags([ 'Reflection', 'Refraction' ])) ]) ), {--- Lit Water ---} wbRArrayS('Lit Water', wbFormIDCk(XLTW, 'Water', [REFR]) ), {--- Decals ---} wbRArrayS('Linked Decals', wbStructSK(XDCR, [0], 'Decal', [ wbFormIDCk('Reference', [REFR]), wbUnknown ]) ), {--- Linked Ref ---} wbFormIDCk(XLKR, 'Linked Reference', [REFR, ACRE, ACHR, PGRE, PMIS, PBEA, PLYR]), wbStruct(XCLP, 'Linked Reference Color', [ wbStruct('Link Start Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Link End Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]) ]), {--- Activate Parents ---} wbRStruct('Activate Parents', [ wbInteger(XAPD, 'Flags', itU8, wbFlags([ 'Parent Activate Only' ], True)), wbRArrayS('Activate Parent Refs', wbStructSK(XAPR, [0], 'Activate Parent Ref', [ wbFormIDCk('Reference', [REFR, ACRE, ACHR, PGRE, PMIS, PBEA, PLYR]), wbFloat('Delay') ]) ) ], []), {--- Enable Parent ---} wbXESP, {--- Emittance ---} wbFormIDCk(XEMI, 'Emittance', [LIGH, REGN]), {--- MultiBound ---} wbFormIDCk(XMBR, 'MultiBound Reference', [REFR]), {--- Flags ---} wbInteger(XACT, 'Action Flag', itU32, wbFlags([ 'Use Default', 'Activate', 'Open', 'Open by Default' ])), wbEmpty(ONAM, 'Open by Default'), wbEmpty(XIBS, 'Ignored By Sandbox'), {--- Generated Data ---} wbStruct(XNDP, 'Navigation Door Link', [ wbFormIDCk('Navigation Mesh', [NAVM]), wbInteger('Teleport Marker Triangle', itS16, wbREFRNavmeshTriangleToStr, wbStringToInt), wbByteArray('Unused', 2) ]), wbArray(XPOD, 'Portal Data', wbFormIDCk('Room', [REFR, NULL]), 2), wbStruct(XPTL, 'Portal Data', [ wbStruct('Size', [ wbFloat('Width', cpNormal, False, 2), wbFloat('Height', cpNormal, False, 2) ]), wbStruct('Position', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), wbStruct('Rotation (Quaternion?)', [ wbFloat('q1'), wbFloat('q2'), wbFloat('q3'), wbFloat('q4') ]) ]), wbInteger(XSED, 'SpeedTree Seed', itU8), wbRStruct('Room Data', [ wbStruct(XRMR, 'Header', [ wbInteger('Linked Rooms Count', itU16), wbByteArray('Unknown', 2) ]), wbRArrayS('Linked Rooms', wbFormIDCk(XLRM, 'Linked Room', [REFR]) ) ], []), wbStruct(XOCP, 'Occlusion Plane Data', [ wbStruct('Size', [ wbFloat('Width', cpNormal, False, 2), wbFloat('Height', cpNormal, False, 2) ]), wbStruct('Position', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), wbStruct('Rotation (Quaternion?)', [ wbFloat('q1'), wbFloat('q2'), wbFloat('q3'), wbFloat('q4') ]) ]), wbArray(XORD, 'Linked Occlusion Planes', wbFormIDCk('Plane', [REFR, NULL]), [ 'Right', 'Left', 'Bottom', 'Top' ]), wbXLOD, {--- 3D Data ---} wbXSCL, wbDATAPosRot ], True, wbPlacedAddInfo, cpNormal, False, wbREFRAfterLoad); wbRecord(REGN, 'Region', [ wbEDID, wbICON, wbStruct(RCLR, 'Map Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ], cpNormal, True), wbFormIDCkNoReach(WNAM, 'Worldspace', [WRLD]), wbRArray('Region Areas', wbRStruct('Region Area', [ wbInteger(RPLI, 'Edge Fall-off', itU32), wbArray(RPLD, 'Region Point List Data', wbStruct('Point', [ wbFloat('X'), wbFloat('Y') ]), 0, wbRPLDAfterLoad) ], [])), wbRArrayS('Region Data Entries', wbRStructSK([0], 'Region Data Entry', [ {always starts with an RDAT} wbStructSK(RDAT, [0], 'Data Header', [ wbInteger('Type', itU32, wbEnum([ {0}'', {1}'', {2}'Objects', {3}'Weather', {4}'Map', {5}'Land', {6}'Grass', {7}'Sound', {8}'', {9}'' ])), wbInteger('Flags', itU8, wbFlags([ 'Override' ])), wbInteger('Priority', itU8), wbByteArray('Unused') ], cpNormal, True), {followed by one of these: } {--- Objects ---} wbArray(RDOT, 'Objects', wbStruct('Object', [ wbFormIDCk('Object', [TREE, STAT, LTEX]), wbInteger('Parent Index', itU16, wbHideFFFF), wbByteArray('Unused', 2), wbFloat('Density'), wbInteger('Clustering', itU8), wbInteger('Min Slope', itU8), wbInteger('Max Slope', itU8), wbInteger('Flags', itU8, wbFlags([ {0}'Conform to slope', {1}'Paint Vertices', {2}'Size Variance +/-', {3}'X +/-', {4}'Y +/-', {5}'Z +/-', {6}'Tree', {7}'Huge Rock' ])), wbInteger('Radius wrt Parent', itU16), wbInteger('Radius', itU16), wbFloat('Min Height'), wbFloat('Max Height'), wbFloat('Sink'), wbFloat('Sink Variance'), wbFloat('Size Variance'), wbStruct('Angle Variance', [ wbInteger('X', itU16), wbInteger('Y', itU16), wbInteger('Z', itU16) ]), wbByteArray('Unused', 2), wbByteArray('Unknown', 4) ]), 0, nil, nil, cpNormal, False, wbREGNObjectsDontShow), {--- Map ---} wbString(RDMP, 'Map Name', 0, cpTranslate, False, wbREGNMapDontShow), {--- Grass ---} wbArrayS(RDGS, 'Grasses', wbStructSK([0], 'Grass', [ wbFormIDCk('Grass', [GRAS]), wbByteArray('Unknown',4) ]), 0, cpNormal, False, nil, nil, wbREGNGrassDontShow), {--- Sound ---} wbInteger(RDMD, 'Music Type', itU32, wbMusicEnum, cpIgnore, False, False, wbNeverShow), wbFormIDCk(RDMO, 'Music', [MUSC], False, cpNormal, False, wbREGNSoundDontShow), wbArrayS(RDSD, 'Sounds', wbStructSK([0], 'Sound', [ wbFormIDCk('Sound', [SOUN]), wbInteger('Flags', itU32, wbFlags([ 'Pleasant', 'Cloudy', 'Rainy', 'Snowy' ])), wbInteger('Chance', itU32, wbScaledInt4ToStr, wbScaledInt4ToInt) ]), 0, cpNormal, False, nil, nil, wbREGNSoundDontShow), {--- Weather ---} wbArrayS(RDWT, 'Weather Types', wbStructSK([0], 'Weather Type', [ wbFormIDCk('Weather', [WTHR]), wbInteger('Chance', itU32), wbFormIDCk('Global', [GLOB, NULL]) ]), 0, cpNormal, False, nil, nil, wbREGNWeatherDontShow) ], [])) ], True); wbRecord(SOUN, 'Sound', [ wbEDIDReq, wbOBNDReq, wbString(FNAM, 'Sound Filename'), wbRUnion('Sound Data', [ wbStruct(SNDD, 'Sound Data', [ wbInteger('Minimum Attentuation Distance', itU8, wbMul(5)), wbInteger('Maximum Attentuation Distance', itU8, wbMul(100)), wbInteger('Frequency Adjustment %', itS8), wbByteArray('Unused', 1), wbInteger('Flags', itU32, wbFlags([ {0x0001} 'Random Frequency Shift', {0x0002} 'Play At Random', {0x0004} 'Environment Ignored', {0x0008} 'Random Location', {0x0010} 'Loop', {0x0020} 'Menu Sound', {0x0040} '2D', {0x0080} '360 LFE', {0x0100} 'Dialogue Sound', {0x0200} 'Envelope Fast', {0x0400} 'Envelope Slow', {0x0800} '2D Radius', {0x1000} 'Mute When Submerged' ])), wbInteger('Static attentuation cdB', itS16), wbInteger('Stop time ', itU8), wbInteger('Start time ', itU8), wbArray('Attenuation Curve', wbInteger('Point', itS16), 5), wbInteger('Reverb Attenuation Control', itS16), wbInteger('Priority', itS32), wbByteArray('Unknown', 8) ], cpNormal, True), wbStruct(SNDX, 'Sound Data', [ wbInteger('Minimum attentuation distance', itU8, wbMul(5)), wbInteger('Maximum attentuation distance', itU8, wbMul(100)), wbInteger('Frequency adjustment %', itS8), wbByteArray('Unused', 1), wbInteger('Flags', itU32, wbFlags([ {0x0001} 'Random Frequency Shift', {0x0002} 'Play At Random', {0x0004} 'Environment Ignored', {0x0008} 'Random Location', {0x0010} 'Loop', {0x0020} 'Menu Sound', {0x0040} '2D', {0x0080} '360 LFE', {0x0100} 'Dialogue Sound', {0x0200} 'Envelope Fast', {0x0400} 'Envelope Slow', {0x0800} '2D Radius', {0x1000} 'Mute When Submerged' ])), wbInteger('Static attentuation cdB', itS16), wbInteger('Stop time ', itU8), wbInteger('Start time ', itU8) ], cpNormal, True) ], [], cpNormal, True), wbArray(ANAM, 'Attenuation Curve', wbInteger('Point', itS16), 5, nil, nil, cpNormal, False, wbNeverShow), wbInteger(GNAM, 'Reverb Attenuation Control', itS16, nil, cpNormal, False, False, wbNeverShow), wbInteger(HNAM, 'Priority', itS32, nil, cpNormal, False, False, wbNeverShow) ], False, nil, cpNormal, False, wbSOUNAfterLoad); wbRecord(SPEL, 'Actor Effect', [ wbEDIDReq, wbFULL, wbStruct(SPIT, '', [ wbInteger('Type', itU32, wbEnum([ {0} 'Actor Effect', {1} 'Disease', {2} 'Power', {3} 'Lesser Power', {4} 'Ability', {5} 'Poison', {6} '', {7} '', {8} '', {9} '', {10} 'Addiction' ])), wbInteger('Cost (Unused)', itU32), wbInteger('Level (Unused)', itU32, wbEnum([ {0} 'Unused' ])), wbInteger('Flags', itU8, wbFlags([ {0x00000001} 'No Auto-Calc', {0x00000002} 'Immune to Silence 1?', {0x00000004} 'PC Start Effect', {0x00000008} 'Immune to Silence 2?', {0x00000010} 'Area Effect Ignores LOS', {0x00000020} 'Script Effect Always Applies', {0x00000040} 'Disable Absorb/Reflect', {0x00000080} 'Force Touch Explode' ])), wbByteArray('Unused', 3) ], cpNormal, True), wbEffectsReq ]); wbRecord(STAT, 'Static', [ wbEDIDReq, wbOBNDReq, wbMODL ]); wbRecord(TES4, 'Main File Header', [ wbStruct(HEDR, 'Header', [ wbFloat('Version'), wbInteger('Number of Records', itU32), wbInteger('Next Object ID', itU32) ], cpNormal, True), wbByteArray(OFST, 'Unknown', 0, cpIgnore), wbByteArray(DELE, 'Unknown', 0, cpIgnore), wbString(CNAM, 'Author', 0, cpTranslate, True), wbString(SNAM, 'Description', 0, cpTranslate), wbRArray('Master Files', wbRStruct('Master File', [ wbString(MAST, 'Filename', 0, cpNormal, True), wbByteArray(DATA, 'Unused', 8, cpIgnore, True) ], [ONAM])), wbArray(ONAM, 'Overriden Forms', wbFormIDCk('Form', [REFR, ACHR, ACRE, PMIS, PBEA, PGRE, LAND, NAVM]), 0, nil, nil, cpNormal, False, wbTES4ONAMDontShow), wbByteArray(SCRN, 'Screenshot') ], True, nil, cpNormal, True, wbRemoveOFST); wbRecord(TREE, 'Tree', [ wbEDIDReq, wbOBNDReq, wbMODLReq, wbICONReq, wbArrayS(SNAM, 'SpeedTree Seeds', wbInteger('SpeedTree Seed', itU32), 0, cpNormal, True), wbStruct(CNAM, 'Tree Data', [ wbFloat('Leaf Curvature'), wbFloat('Minimum Leaf Angle'), wbFloat('Maximum Leaf Angle'), wbFloat('Branch Dimming Value'), wbFloat('Leaf Dimming Value'), wbInteger('Shadow Radius', itS32), wbFloat('Rock Speed'), wbFloat('Rustle Speed') ], cpNormal, True), wbStruct(BNAM, 'Billboard Dimensions', [ wbFloat('Width'), wbFloat('Height') ], cpNormal, True) ]); end; procedure DefineFO3f; begin wbRecord(WATR, 'Water', [ wbEDIDReq, wbFULL, wbString(NNAM, 'Noise Map', 0, cpNormal, True), wbInteger(ANAM, 'Opacity', itU8, nil, cpNormal, True), wbInteger(FNAM, 'Flags', itU8, wbFlags([ {0}'Causes Damage', {1}'Reflective' ]), cpNormal, True), wbString(MNAM, 'Material ID', 0, cpNormal, True), wbFormIDCk(SNAM, 'Sound', [SOUN]), wbFormIDCk(XNAM, 'Actor Effect', [SPEL]), wbInteger(DATA, 'Damage', itU16, nil, cpNormal, True, True), wbRUnion('Visual Data', [ wbStruct(DNAM, 'Visual Data', [ wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Water Properties - Sun Power'), wbFloat('Water Properties - Reflectivity Amount'), wbFloat('Water Properties - Fresnel Amount'), wbByteArray('Unused', 4), wbFloat('Fog Properties - Above Water - Fog Distance - Near Plane'), wbFloat('Fog Properties - Above Water - Fog Distance - Far Plane'), wbStruct('Shallow Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Deep Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Reflection Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbByteArray('Unused', 4), wbFloat('Rain Simulator - Force'), wbFloat('Rain Simulator - Velocity'), wbFloat('Rain Simulator - Falloff'), wbFloat('Rain Simulator - Dampner'), wbFloat('Displacement Simulator - Starting Size'), wbFloat('Displacement Simulator - Force'), wbFloat('Displacement Simulator - Velocity'), wbFloat('Displacement Simulator - Falloff'), wbFloat('Displacement Simulator - Dampner'), wbFloat('Rain Simulator - Starting Size'), wbFloat('Noise Properties - Normals - Noise Scale'), wbFloat('Noise Properties - Noise Layer One - Wind Direction'), wbFloat('Noise Properties - Noise Layer Two - Wind Direction'), wbFloat('Noise Properties - Noise Layer Three - Wind Direction'), wbFloat('Noise Properties - Noise Layer One - Wind Speed'), wbFloat('Noise Properties - Noise Layer Two - Wind Speed'), wbFloat('Noise Properties - Noise Layer Three - Wind Speed'), wbFloat('Noise Properties - Normals - Depth Falloff Start'), wbFloat('Noise Properties - Normals - Depth Falloff End'), wbFloat('Fog Properties - Above Water - Fog Amount'), wbFloat('Noise Properties - Normals - UV Scale'), wbFloat('Fog Properties - Under Water - Fog Amount'), wbFloat('Fog Properties - Under Water - Fog Distance - Near Plane'), wbFloat('Fog Properties - Under Water - Fog Distance - Far Plane'), wbFloat('Water Properties - Distortion Amount'), wbFloat('Water Properties - Shininess'), wbFloat('Water Properties - Reflection HDR Multiplier'), wbFloat('Water Properties - Light Radius'), wbFloat('Water Properties - Light Brightness'), wbFloat('Noise Properties - Noise Layer One - UV Scale'), wbFloat('Noise Properties - Noise Layer Two - UV Scale'), wbFloat('Noise Properties - Noise Layer Three - UV Scale'), wbFloat('Noise Properties - Noise Layer One - Amplitude Scale'), wbFloat('Noise Properties - Noise Layer Two - Amplitude Scale'), wbFloat('Noise Properties - Noise Layer Three - Amplitude Scale') ], cpNormal, True, nil, 46), wbStruct(DATA, 'Visual Data', [ wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Water Properties - Sun Power'), wbFloat('Water Properties - Reflectivity Amount'), wbFloat('Water Properties - Fresnel Amount'), wbByteArray('Unused', 4), wbFloat('Fog Properties - Above Water - Fog Distance - Near Plane'), wbFloat('Fog Properties - Above Water - Fog Distance - Far Plane'), wbStruct('Shallow Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Deep Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Reflection Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbByteArray('Unused', 4), wbFloat('Rain Simulator - Force'), wbFloat('Rain Simulator - Velocity'), wbFloat('Rain Simulator - Falloff'), wbFloat('Rain Simulator - Dampner'), wbFloat('Displacement Simulator - Starting Size'), wbFloat('Displacement Simulator - Force'), wbFloat('Displacement Simulator - Velocity'), wbFloat('Displacement Simulator - Falloff'), wbFloat('Displacement Simulator - Dampner'), wbFloat('Rain Simulator - Starting Size'), wbFloat('Noise Properties - Normals - Noise Scale'), wbFloat('Noise Properties - Noise Layer One - Wind Direction'), wbFloat('Noise Properties - Noise Layer Two - Wind Direction'), wbFloat('Noise Properties - Noise Layer Three - Wind Direction'), wbFloat('Noise Properties - Noise Layer One - Wind Speed'), wbFloat('Noise Properties - Noise Layer Two - Wind Speed'), wbFloat('Noise Properties - Noise Layer Three - Wind Speed'), wbFloat('Noise Properties - Normals - Depth Falloff Start'), wbFloat('Noise Properties - Normals - Depth Falloff End'), wbFloat('Fog Properties - Above Water - Fog Amount'), wbFloat('Noise Properties - Normals - UV Scale'), wbFloat('Fog Properties - Under Water - Fog Amount'), wbFloat('Fog Properties - Under Water - Fog Distance - Near Plane'), wbFloat('Fog Properties - Under Water - Fog Distance - Far Plane'), wbFloat('Water Properties - Distortion Amount'), wbFloat('Water Properties - Shininess'), wbFloat('Water Properties - Reflection HDR Multiplier'), wbFloat('Water Properties - Light Radius'), wbFloat('Water Properties - Light Brightness'), wbFloat('Noise Properties - Noise Layer One - UV Scale'), wbFloat('Noise Properties - Noise Layer Two - UV Scale'), wbFloat('Noise Properties - Noise Layer Three - UV Scale'), wbEmpty('Noise Properties - Noise Layer One - Amplitude Scale'), wbEmpty('Noise Properties - Noise Layer Two - Amplitude Scale'), wbEmpty('Noise Properties - Noise Layer Three - Amplitude Scale'), wbInteger('Damage (Old Format)', itU16) ], cpNormal, True) ], [], cpNormal, True), wbStruct(GNAM, 'Related Waters (Unused)', [ wbFormIDCk('Daytime', [WATR, NULL]), wbFormIDCk('Nighttime', [WATR, NULL]), wbFormIDCk('Underwater', [WATR, NULL]) ], cpNormal, True) ], False, nil, cpNormal, False, wbWATRAfterLoad); wbRecord(WEAP, 'Weapon', [ wbEDIDReq, wbOBNDReq, wbFULL, wbMODL, wbICON, wbSCRI, wbEITM, wbInteger(EAMT, 'Enchantment Charge Amount', itS16), wbFormIDCkNoReach(NAM0, 'Ammo', [AMMO, FLST]), wbDEST, wbREPL, wbETYPReq, wbBIPL, wbYNAM, wbZNAM, wbRStruct('Shell Casing Model', [ wbString(MOD2, 'Model Filename'), wbByteArray(MO2T, 'Texture Files Hashes', 0, cpIgnore), wbMO2S ], []), wbRStruct('Scope Model', [ wbString(MOD3, 'Model Filename'), wbByteArray(MO3T, 'Texture Files Hashes', 0, cpIgnore), wbMO3S ], []), wbFormIDCK(EFSD, 'Scope Effect', [EFSH]), wbRStruct('World Model', [ wbString(MOD4, 'Model Filename'), wbByteArray(MO4T, 'Texture Files Hashes', 0, cpIgnore), wbMO4S ], []), wbString(NNAM, 'Embedded Weapon Node'), wbFormIDCk(INAM, 'Impact DataSet', [IPDS]), wbFormIDCk(WNAM, '1st Person Model', [STAT]), wbFormIDCk(SNAM, 'Sound - Gun - Shoot 3D', [SOUN]), wbFormIDCk(XNAM, 'Sound - Gun - Shoot 2D', [SOUN]), wbFormIDCk(NAM7, 'Sound - Gun - Shoot 3D Looping', [SOUN]), wbFormIDCk(TNAM, 'Sound - Melee - Swing / Gun - No Ammo', [SOUN]), wbFormIDCk(NAM6, 'Sound - Block', [SOUN]), wbFormIDCk(UNAM, 'Sound - Idle', [SOUN]), wbFormIDCk(NAM9, 'Sound - Equip', [SOUN]), wbFormIDCk(NAM8, 'Sound - Unequip', [SOUN]), wbStruct(DATA, '', [ wbInteger('Value', itS32), wbInteger('Health', itS32), wbFloat('Weight'), wbInteger('Base Damage', itS16), wbInteger('Clip Size', itU8) ], cpNormal, True), wbStruct(DNAM, '', [ {00} wbInteger('Animation Type', itU32, wbWeaponAnimTypeEnum), {04} wbFloat('Animation Multiplier'), {08} wbFloat('Reach'), {12} wbInteger('Flags 1', itU8, wbFlags([ 'Ignores Normal Weapon Resistance', 'Is Automatic', 'Has Scope', 'Can''t Drop', 'Hide Backpack', 'Embedded Weapon', 'Don''t Use 1st Person IS Animations', 'Non-Playable' ])), {13} wbInteger('Grip Animation', itU8, wbEnum([ ], [ 171, 'HandGrip1', 172, 'HandGrip2', 173, 'HandGrip3', 255, 'DEFAULT' ])), {14} wbInteger('Ammo Use', itU8), {15} wbInteger('Reload Animation', itU8, wbReloadAnimEnum), {16} wbFloat('Min Spread'), {20} wbFloat('Spread'), {24} wbFloat('Unknown'), {28} wbFloat('Sight FOV'), {32} wbByteArray('Unused', 4), {36} wbFormIDCk('Projectile', [PROJ, NULL]), {40} wbInteger('Base VATS To-Hit Chance', itU8), {41} wbInteger('Attack Animation', itU8, wbEnum([ ], [ 26, 'AttackLeft', 32, 'AttackRight', 38, 'Attack3', 44, 'Attack4', 50, 'Attack5', 56, 'Attack6', 62, 'Attack7', 68, 'Attack8', 74, 'AttackLoop', 80, 'AttackSpin', 86, 'AttackSpin2', 97, 'PlaceMine', 103, 'PlaceMine2', 109, 'AttackThrow', 115, 'AttackThrow2', 121, 'AttackThrow3', 127, 'AttackThrow4', 133, 'AttackThrow5', 255, 'DEFAULT' ])), {42} wbInteger('Projectile Count', itU8), {43} wbInteger('Embedded Weapon - Actor Value', itU8, wbEnum([ {00} 'Perception', {01} 'Endurance', {02} 'Left Attack', {03} 'Right Attack', {04} 'Left Mobility', {05} 'Right Mobilty', {06} 'Brain' ])), {44} wbFloat('Min Range'), {48} wbFloat('Max Range'), {52} wbInteger('On Hit', itU32, wbEnum([ 'Normal formula behavior', 'Dismember Only', 'Explode Only', 'No Dismember/Explode' ])), {56} wbInteger('Flags 2', itU32, wbFlags([ {0x00000001}'Player Only', {0x00000002}'NPCs Use Ammo', {0x00000004}'No Jam After Reload', {0x00000008}'Override - Action Points', {0x00000010}'Minor Crime', {0x00000020}'Range - Fixed', {0x00000040}'Not Used In Normal Combat', {0x00000080}'Override - Damage to Weapon Mult', {0x00000100}'Don''t Use 3rd Person IS Animations', {0x00000200}'Short Burst', {0x00000400}'Rumble Alternate', {0x00000800}'Long Burst' ])), {60} wbFloat('Animation Attack Multiplier'), {64} wbFloat('Fire Rate'), {68} wbFloat('Override - Action Points'), {72} wbFloat('Rumble - Left Motor Strength'), {76} wbFloat('Rumble - Right Motor Strength'), {80} wbFloat('Rumble - Duration'), {84} wbFloat('Override - Damage to Weapon Mult'), {88} wbFloat('Attack Shots/Sec'), {92} wbFloat('Reload Time'), {96} wbFloat('Jam Time'), {100} wbFloat('Aim Arc'), {104} wbInteger('Skill', itS32, wbActorValueEnum), {108} wbInteger('Rumble - Pattern', itU32, wbEnum([ 'Constant', 'Square', 'Triangle', 'Sawtooth' ])), {112} wbFloat('Rumble - Wavelength'), {116} wbFloat('Limb Dmg Mult'), {120} wbInteger('Resist Type', itS32, wbActorValueEnum), {124} wbFloat('Sight Usage'), {128} wbFloat('Semi-Automatic Fire Delay Min'), {132} wbFloat('Semi-Automatic Fire Delay Max') ], cpNormal, True, nil, 36), wbStruct(CRDT, 'Critical Data', [ {00} wbInteger('Critical Damage', itU16), {09} wbByteArray('Unused', 2), {04} wbFloat('Crit % Mult'), {08} wbInteger('Flags', itU8, wbFlags([ 'On Death' ])), {09} wbByteArray('Unused', 3), {12} wbFormIDCk('Effect', [SPEL, NULL]) ], cpNormal, True), wbInteger(VNAM, 'Sound Level', itU32, wbSoundLevelEnum, cpNormal, True) ], False, nil, cpNormal, False, wbWEAPAfterLoad); if wbSimpleRecords then wbRecord(WRLD, 'Worldspace', [ wbEDIDReq, wbFULL, wbFormIDCk(XEZN, 'Encounter Zone', [ECZN]), wbRStruct('Parent', [ wbFormIDCk(WNAM, 'Worldspace', [WRLD]), wbStruct(PNAM, '', [ wbInteger('Flags', itU8, wbFlags([ {0x00000001}'Use Land Data', {0x00000002}'Use LOD Data', {0x00000004}'Use Map Data', {0x00000008}'Use Water Data', {0x00000010}'Use Climate Data', {0x00000020}'Use Image Space Data', {0x00000040}'', {0x00000080}'Needs Water Adjustment' ], True)), wbByteArray('Unknown', 1) ], cpNormal, True) ], []), wbFormIDCk(CNAM, 'Climate', [CLMT]), wbFormIDCk(NAM2, 'Water', [WATR]), wbFormIDCk(NAM3, 'LOD Water Type', [WATR]), wbFloat(NAM4, 'LOD Water Height'), wbStruct(DNAM, 'Land Data', [ wbFloat('Default Land Height'), wbFloat('Default Water Height') ]), wbICON, wbStruct(MNAM, 'Map Data', [ wbStruct('Usable Dimensions', [ wbInteger('X', itS32), wbInteger('Y', itS32) ]), wbStruct('Cell Coordinates', [ wbStruct('NW Cell', [ wbInteger('X', itS16), wbInteger('Y', itS16) ]), wbStruct('SE Cell', [ wbInteger('X', itS16), wbInteger('Y', itS16) ]) ]) ]), wbStruct(ONAM, 'World Map Offset Data', [ wbFloat('World Map Scale'), wbFloat('Cell X Offset'), wbFloat('Cell Y Offset') ], cpNormal, True), wbFormIDCk(INAM, 'Image Space', [IMGS]), wbInteger(DATA, 'Flags', itU8, wbFlags([ {0x01} 'Small World', {0x02} 'Can''t Fast Travel', {0x04} '', {0x08} '', {0x10} 'No LOD Water', {0x20} 'No LOD Noise', {0x40} 'Don''t Allow NPC Fall Damage', {0x80} 'Needs Water Adjustment' ]), cpNormal, True), wbRStruct('Object Bounds', [ wbStruct(NAM0, 'Min', [ wbFloat('X', cpNormal, False, 1/4096), wbFloat('Y', cpNormal, False, 1/4096) ], cpIgnore, True), wbStruct(NAM9, 'Max', [ wbFloat('X', cpNormal, False, 1/4096), wbFloat('Y', cpNormal, False, 1/4096) ], cpIgnore, True) ], []), wbFormIDCk(ZNAM, 'Music', [MUSC]), wbString(NNAM, 'Canopy Shadow', 0, cpNormal, True), wbString(XNAM, 'Water Noise Texture', 0, cpNormal, True), wbRArrayS('Swapped Impacts', wbStructExSK(IMPS, [0, 1], [2], 'Swapped Impact', [ wbInteger('Material Type', itU32, wbImpactMaterialTypeEnum), wbFormIDCkNoReach('Old', [IPCT]), wbFormIDCk('New', [IPCT, NULL]) ])), wbArray(IMPF, 'Footstep Materials', wbString('Unknown', 30), [ 'ConcSolid', 'ConcBroken', 'MetalSolid', 'MetalHollow', 'MetalSheet', 'Wood', 'Sand', 'Dirt', 'Grass', 'Water' ]), wbByteArray(OFST, 'Offset Data') ], False, nil, cpNormal, False, wbRemoveOFST) else wbRecord(WRLD, 'Worldspace', [ wbEDIDReq, wbFULL, wbFormIDCk(XEZN, 'Encounter Zone', [ECZN]), wbRStruct('Parent', [ wbFormIDCk(WNAM, 'Worldspace', [WRLD]), wbStruct(PNAM, '', [ wbInteger('Flags', itU8, wbFlags([ {0x00000001}'Use Land Data', {0x00000002}'Use LOD Data', {0x00000004}'Use Map Data', {0x00000008}'Use Water Data', {0x00000010}'Use Climate Data', {0x00000020}'Use Image Space Data', {0x00000040}'', {0x00000080}'Needs Water Adjustment' ], True)), wbByteArray('Unknown', 1) ], cpNormal, True) ], []), wbFormIDCk(CNAM, 'Climate', [CLMT]), wbFormIDCk(NAM2, 'Water', [WATR]), wbFormIDCk(NAM3, 'LOD Water Type', [WATR]), wbFloat(NAM4, 'LOD Water Height'), wbStruct(DNAM, 'Land Data', [ wbFloat('Default Land Height'), wbFloat('Default Water Height') ]), wbICON, wbStruct(MNAM, 'Map Data', [ wbStruct('Usable Dimensions', [ wbInteger('X', itS32), wbInteger('Y', itS32) ]), wbStruct('Cell Coordinates', [ wbStruct('NW Cell', [ wbInteger('X', itS16), wbInteger('Y', itS16) ]), wbStruct('SE Cell', [ wbInteger('X', itS16), wbInteger('Y', itS16) ]) ]) ]), wbStruct(ONAM, 'World Map Offset Data', [ wbFloat('World Map Scale'), wbFloat('Cell X Offset'), wbFloat('Cell Y Offset') ], cpNormal, True), wbFormIDCk(INAM, 'Image Space', [IMGS]), wbInteger(DATA, 'Flags', itU8, wbFlags([ {0x01} 'Small World', {0x02} 'Can''t Fast Travel', {0x04} '', {0x08} '', {0x10} 'No LOD Water', {0x20} 'No LOD Noise', {0x40} 'Don''t Allow NPC Fall Damage', {0x80} 'Needs Water Adjustment' ]), cpNormal, True), wbRStruct('Object Bounds', [ wbStruct(NAM0, 'Min', [ wbFloat('X', cpNormal, False, 1/4096), wbFloat('Y', cpNormal, False, 1/4096) ], cpIgnore, True), wbStruct(NAM9, 'Max', [ wbFloat('X', cpNormal, False, 1/4096), wbFloat('Y', cpNormal, False, 1/4096) ], cpIgnore, True) ], []), wbFormIDCk(ZNAM, 'Music', [MUSC]), wbString(NNAM, 'Canopy Shadow', 0, cpNormal, True), wbString(XNAM, 'Water Noise Texture', 0, cpNormal, True), wbRArrayS('Swapped Impacts', wbStructExSK(IMPS, [0, 1], [2], 'Swapped Impact', [ wbInteger('Material Type', itU32, wbImpactMaterialTypeEnum), wbFormIDCkNoReach('Old', [IPCT]), wbFormIDCk('New', [IPCT, NULL]) ])), wbArray(IMPF, 'Footstep Materials', wbString('Unknown', 30), [ 'ConcSolid', 'ConcBroken', 'MetalSolid', 'MetalHollow', 'MetalSheet', 'Wood', 'Sand', 'Dirt', 'Grass', 'Water' ]), wbArray(OFST, 'Offset Data', wbArray('Rows', wbInteger('Offset', itU32), wbOffsetDataColsCounter), 0) ], False, nil, cpNormal, False, wbRemoveOFST); wbRecord(WTHR, 'Weather', [ wbEDIDReq, wbFormIDCk(_0_IAD, 'Sunrise Image Space Modifier', [IMAD]), wbFormIDCk(_1_IAD, 'Day Image Space Modifier', [IMAD]), wbFormIDCk(_2_IAD, 'Sunset Image Space Modifier', [IMAD]), wbFormIDCk(_3_IAD, 'Night Image Space Modifier', [IMAD]), wbString(DNAM, 'Cloud Textures - Layer 0', 0, cpNormal, True), wbString(CNAM, 'Cloud Textures - Layer 1', 0, cpNormal, True), wbString(ANAM, 'Cloud Textures - Layer 2', 0, cpNormal, True), wbString(BNAM, 'Cloud Textures - Layer 3', 0, cpNormal, True), wbMODL, wbByteArray(LNAM, 'Unknown', 4, cpNormal, True), wbArray(ONAM, 'Cloud Speed', wbInteger('Layer', itU8{, wbDiv(2550)}), 4, nil, nil, cpNormal, True), wbArray(PNAM, 'Cloud Layer Colors', wbArray('Layer', wbStruct('Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), ['Sunrise', 'Day', 'Sunset', 'Night'] ), 4), wbArray(NAM0, 'Colors by Types/Times', wbArray('Type', wbStruct('Time', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), ['Sunrise', 'Day', 'Sunset', 'Night'] ), ['Sky-Upper','Fog','Unused','Ambient','Sunlight','Sun','Stars','Sky-Lower','Horizon','Unused'] , cpNormal, True), wbStruct(FNAM, 'Fog Distance', [ wbFloat('Day - Near'), wbFloat('Day - Far'), wbFloat('Night - Near'), wbFloat('Night - Far'), wbFloat('Day - Power'), wbFloat('Night - Fower') ], cpNormal, True), wbByteArray(INAM, 'Unused', 304, cpIgnore, True), wbStruct(DATA, '', [ wbInteger('Wind Speed', itU8), wbInteger('Cloud Speed (Lower)', itU8), wbInteger('Cloud Speed (Upper)', itU8), wbInteger('Trans Delta', itU8), wbInteger('Sun Glare', itU8), wbInteger('Sun Damage', itU8), wbInteger('Precipitation - Begin Fade In', itU8), wbInteger('Precipitation - End Fade Out', itU8), wbInteger('Thunder/Lightning - Begin Fade In', itU8), wbInteger('Thunder/Lightning - End Fade Out', itU8), wbInteger('Thunder/Lightning - Frequency', itU8), wbInteger('Weather Classification', itU8, wbWthrDataClassification), wbStruct('Lightning Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8) ]) ], cpNormal, True), wbRArray('Sounds', wbStruct(SNAM, 'Sound', [ wbFormIDCk('Sound', [SOUN]), wbInteger('Type', itU32, wbEnum([ {0}'Default', {1}'Precip', {2}'Wind', {3}'Thunder' ])) ])) ]); wbAddGroupOrder(GMST); wbAddGroupOrder(TXST); wbAddGroupOrder(MICN); wbAddGroupOrder(GLOB); wbAddGroupOrder(CLAS); wbAddGroupOrder(FACT); wbAddGroupOrder(HDPT); wbAddGroupOrder(HAIR); wbAddGroupOrder(EYES); wbAddGroupOrder(RACE); wbAddGroupOrder(SOUN); wbAddGroupOrder(ASPC); wbAddGroupOrder(MGEF); wbAddGroupOrder(SCPT); wbAddGroupOrder(LTEX); wbAddGroupOrder(ENCH); wbAddGroupOrder(SPEL); wbAddGroupOrder(ACTI); wbAddGroupOrder(TACT); wbAddGroupOrder(TERM); wbAddGroupOrder(ARMO); wbAddGroupOrder(BOOK); wbAddGroupOrder(CONT); wbAddGroupOrder(DOOR); wbAddGroupOrder(INGR); wbAddGroupOrder(LIGH); wbAddGroupOrder(MISC); wbAddGroupOrder(STAT); wbAddGroupOrder(SCOL); wbAddGroupOrder(MSTT); wbAddGroupOrder(PWAT); wbAddGroupOrder(GRAS); wbAddGroupOrder(TREE); wbAddGroupOrder(FURN); wbAddGroupOrder(WEAP); wbAddGroupOrder(AMMO); wbAddGroupOrder(NPC_); wbAddGroupOrder(CREA); wbAddGroupOrder(LVLC); wbAddGroupOrder(LVLN); wbAddGroupOrder(KEYM); wbAddGroupOrder(ALCH); wbAddGroupOrder(IDLM); wbAddGroupOrder(NOTE); wbAddGroupOrder(PROJ); wbAddGroupOrder(LVLI); wbAddGroupOrder(WTHR); wbAddGroupOrder(CLMT); wbAddGroupOrder(COBJ); wbAddGroupOrder(REGN); wbAddGroupOrder(NAVI); wbAddGroupOrder(CELL); wbAddGroupOrder(WRLD); wbAddGroupOrder(DIAL); wbAddGroupOrder(QUST); wbAddGroupOrder(IDLE); wbAddGroupOrder(PACK); wbAddGroupOrder(CSTY); wbAddGroupOrder(LSCR); wbAddGroupOrder(ANIO); wbAddGroupOrder(WATR); wbAddGroupOrder(EFSH); wbAddGroupOrder(EXPL); wbAddGroupOrder(DEBR); wbAddGroupOrder(IMGS); wbAddGroupOrder(IMAD); wbAddGroupOrder(FLST); wbAddGroupOrder(PERK); wbAddGroupOrder(BPTD); wbAddGroupOrder(ADDN); wbAddGroupOrder(AVIF); wbAddGroupOrder(RADS); wbAddGroupOrder(CAMS); wbAddGroupOrder(CPTH); wbAddGroupOrder(VTYP); wbAddGroupOrder(IPCT); wbAddGroupOrder(IPDS); wbAddGroupOrder(ARMA); wbAddGroupOrder(ECZN); wbAddGroupOrder(MESG); wbAddGroupOrder(RGDL); wbAddGroupOrder(DOBJ); wbAddGroupOrder(LGTM); wbAddGroupOrder(MUSC); end; procedure DefineFO3; begin DefineFO3a; DefineFO3b; DefineFO3c; DefineFO3d; DefineFO3e; DefineFO3f; end; end. ================================================ FILE: lib/xedit/wbDefinitionsFO4.pas ================================================ {******************************************************************************* The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. *******************************************************************************} unit wbDefinitionsFO4; {$I wbDefines.inc} interface uses wbInterface; var wbBipedObjectFlags: IwbFlagsDef; wbEquipType: IwbFlagsDef; wbFurnitureEntryTypeFlags: IwbFlagsDef; wbPKDTFlags: IwbFlagsDef; wbPKDTInterruptFlags: IwbFlagsDef; wbSMNodeFlags: IwbFlagsDef; wbActorPropertyEnum: IwbEnumDef; wbAdvanceActionEnum: IwbEnumDef; wbStaggerEnum: IwbEnumDef; wbAlignmentEnum: IwbEnumDef; wbArmorPropertyEnum: IwbEnumDef; wbAxisEnum: IwbEnumDef; wbBipedObjectEnum: IwbEnumDef; wbBlendModeEnum: IwbEnumDef; wbBlendOpEnum: IwbEnumDef; wbBodyPartIndexEnum: IwbEnumDef; wbCastEnum: IwbEnumDef; wbCastingSourceEnum: IwbEnumDef; wbCrimeTypeEnum: IwbEnumDef; wbCriticalStageEnum: IwbEnumDef; wbEmotionTypeEnum: IwbEnumDef; wbEntryPointsEnum: IwbEnumDef; wbEventFunctionEnum: IwbEnumDef; wbEventMemberEnum: IwbEnumDef; wbFormTypeEnum: IwbEnumDef; wbFurnitureAnimTypeEnum: IwbEnumDef; wbLocationEnum: IwbEnumDef; wbMiscStatEnum: IwbEnumDef; wbMusicEnum: IwbEnumDef; wbObjectModProperties: IwbArrayDef; wbObjectTypeEnum: IwbEnumDef; wbPropTypeEnum: IwbEnumDef; wbQuadrantEnum: IwbEnumDef; wbSexEnum: IwbEnumDef; wbSkillEnum: IwbEnumDef; wbSoulGemEnum: IwbEnumDef; wbSoundLevelEnum: IwbEnumDef; wbTargetEnum: IwbEnumDef; wbVatsValueFunctionEnum: IwbEnumDef; wbWardStateEnum: IwbEnumDef; wbWeaponAnimTypeEnum: IwbEnumDef; wbWeaponPropertyEnum: IwbEnumDef; wbZTestFuncEnum: IwbEnumDef; wbKeywordTypeEnum: IwbEnumDef; wbReverbClassEnum: IwbEnumDef; wbHitBehaviourEnum: IwbEnumDef; wbBoolEnum: IwbEnumDef; procedure DefineFO4; implementation uses Types, Classes, SysUtils, Math, Variants, wbHelpers; const _00_IAD: TwbSignature = #$00'IAD'; _01_IAD: TwbSignature = #$01'IAD'; _02_IAD: TwbSignature = #$02'IAD'; _03_IAD: TwbSignature = #$03'IAD'; _04_IAD: TwbSignature = #$04'IAD'; _05_IAD: TwbSignature = #$05'IAD'; _06_IAD: TwbSignature = #$06'IAD'; _07_IAD: TwbSignature = #$07'IAD'; _08_IAD: TwbSignature = #$08'IAD'; _09_IAD: TwbSignature = #$09'IAD'; _0A_IAD: TwbSignature = #$0A'IAD'; _0B_IAD: TwbSignature = #$0B'IAD'; _0C_IAD: TwbSignature = #$0C'IAD'; _0D_IAD: TwbSignature = #$0D'IAD'; _0E_IAD: TwbSignature = #$0E'IAD'; _0F_IAD: TwbSignature = #$0F'IAD'; _10_IAD: TwbSignature = #$10'IAD'; _11_IAD: TwbSignature = #$11'IAD'; _12_IAD: TwbSignature = #$12'IAD'; _13_IAD: TwbSignature = #$13'IAD'; _14_IAD: TwbSignature = #$14'IAD'; _40_IAD: TwbSignature = #$40'IAD'; _41_IAD: TwbSignature = #$41'IAD'; _42_IAD: TwbSignature = #$42'IAD'; _43_IAD: TwbSignature = #$43'IAD'; _44_IAD: TwbSignature = #$44'IAD'; _45_IAD: TwbSignature = #$45'IAD'; _46_IAD: TwbSignature = #$46'IAD'; _47_IAD: TwbSignature = #$47'IAD'; _48_IAD: TwbSignature = #$48'IAD'; _49_IAD: TwbSignature = #$49'IAD'; _4A_IAD: TwbSignature = #$4A'IAD'; _4B_IAD: TwbSignature = #$4B'IAD'; _4C_IAD: TwbSignature = #$4C'IAD'; _4D_IAD: TwbSignature = #$4D'IAD'; _4E_IAD: TwbSignature = #$4E'IAD'; _4F_IAD: TwbSignature = #$4F'IAD'; _50_IAD: TwbSignature = #$50'IAD'; _51_IAD: TwbSignature = #$51'IAD'; _52_IAD: TwbSignature = #$52'IAD'; _53_IAD: TwbSignature = #$53'IAD'; _54_IAD: TwbSignature = #$54'IAD'; {00TX} _00_0TX: TwbSignature = #$30'0TX'; {10TX} _10_0TX: TwbSignature = #$31'0TX'; {20TX} _20_0TX: TwbSignature = #$32'0TX'; {30TX} _30_0TX: TwbSignature = #$33'0TX'; {40TX} _40_0TX: TwbSignature = #$34'0TX'; {50TX} _50_0TX: TwbSignature = #$35'0TX'; {60TX} _60_0TX: TwbSignature = #$36'0TX'; {70TX} _70_0TX: TwbSignature = #$37'0TX'; {80TX} _80_0TX: TwbSignature = #$38'0TX'; {90TX} _90_0TX: TwbSignature = #$39'0TX'; {:0TX} _3A_0TX: TwbSignature = #$3A'0TX'; {;0TX} _3B_0TX: TwbSignature = #$3B'0TX'; {<0TX} _3C_0TX: TwbSignature = #$3C'0TX'; {=0TX} _3D_0TX: TwbSignature = #$3D'0TX'; {>0TX} _3E_0TX: TwbSignature = #$3E'0TX'; {?0TX} _3F_0TX: TwbSignature = #$3F'0TX'; {@0TX} _40h_0TX: TwbSignature = #$40'0TX'; {A0TX} A0TX: TwbSignature = 'A0TX'; {B0TX} B0TX: TwbSignature = 'B0TX'; {C0TX} C0TX: TwbSignature = 'C0TX'; {D0TX} D0TX: TwbSignature = 'D0TX'; {E0TX} E0TX: TwbSignature = 'E0TX'; {F0TX} F0TX: TwbSignature = 'F0TX'; {G0TX} G0TX: TwbSignature = 'G0TX'; {H0TX} H0TX: TwbSignature = 'H0TX'; {I0TX} I0TX: TwbSignature = 'I0TX'; {J0TX} J0TX: TwbSignature = 'J0TX'; {K0TX} K0TX: TwbSignature = 'K0TX'; {L0TX} L0TX: TwbSignature = 'L0TX'; AACT : TwbSignature = 'AACT'; ACBS : TwbSignature = 'ACBS'; ACEC : TwbSignature = 'ACEC'; { New To Dawnguard } ACEP : TwbSignature = 'ACEP'; { New To Dawnguard } ACHR : TwbSignature = 'ACHR'; ACID : TwbSignature = 'ACID'; { New To Dawnguard } ACPR : TwbSignature = 'ACPR'; { New To Skyrim } ACSR : TwbSignature = 'ACSR'; { New To Dawnguard } ACTI : TwbSignature = 'ACTI'; ACTV : TwbSignature = 'ACTV'; { New To Fallout 4 } ACUN : TwbSignature = 'ACUN'; { New To Dawnguard } ADDN : TwbSignature = 'ADDN'; AECH : TwbSignature = 'AECH'; { New To Fallout 4 } AHCF : TwbSignature = 'AHCF'; { New To Skyrim } AHCM : TwbSignature = 'AHCM'; { New To Skyrim } AIDT : TwbSignature = 'AIDT'; ALCA : TwbSignature = 'ALCA'; { New To Skyrim } ALCC : TwbSignature = 'ALCC'; { New To Fallout 4 } ALCH : TwbSignature = 'ALCH'; ALCL : TwbSignature = 'ALCL'; { New To Skyrim } ALCO : TwbSignature = 'ALCO'; { New To Skyrim } ALCS : TwbSignature = 'ALCS'; { New To Fallout 4 } ALDI : TwbSignature = 'ALDI'; { New To Fallout 4 } ALDN : TwbSignature = 'ALDN'; { New To Skyrim } ALEA : TwbSignature = 'ALEA'; { New To Skyrim } ALED : TwbSignature = 'ALED'; { New To Skyrim } ALEQ : TwbSignature = 'ALEQ'; { New To Skyrim } ALFA : TwbSignature = 'ALFA'; { New To Skyrim } ALFC : TwbSignature = 'ALFC'; { New To Skyrim } ALFD : TwbSignature = 'ALFD'; { New To Skyrim } ALFE : TwbSignature = 'ALFE'; { New To Skyrim } ALFI : TwbSignature = 'ALFI'; { New To Skyrim } ALFL : TwbSignature = 'ALFL'; { New To Skyrim } ALFR : TwbSignature = 'ALFR'; { New To Skyrim } ALFV : TwbSignature = 'ALFV'; { New To Fallout 4 } ALID : TwbSignature = 'ALID'; { New To Skyrim } ALLA : TwbSignature = 'ALLA'; { New To Fallout 4 } ALLS : TwbSignature = 'ALLS'; { New To Skyrim } ALMI : TwbSignature = 'ALMI'; { New To Fallout 4 } ALNA : TwbSignature = 'ALNA'; { New To Skyrim } ALNT : TwbSignature = 'ALNT'; { New To Skyrim } ALPC : TwbSignature = 'ALPC'; { New To Skyrim } ALRT : TwbSignature = 'ALRT'; { New To Skyrim } ALSP : TwbSignature = 'ALSP'; { New To Skyrim } ALST : TwbSignature = 'ALST'; { New To Skyrim } ALUA : TwbSignature = 'ALUA'; { New To Skyrim } AMDL : TwbSignature = 'AMDL'; { New To Fallout 4 } AMMO : TwbSignature = 'AMMO'; ANAM : TwbSignature = 'ANAM'; ANIO : TwbSignature = 'ANIO'; AOR2 : TwbSignature = 'AOR2'; { New To Fallout 4 } AORU : TwbSignature = 'AORU'; { New To Fallout 4 } APPR : TwbSignature = 'APPR'; { New To Fallout 4 } ARMA : TwbSignature = 'ARMA'; ARMO : TwbSignature = 'ARMO'; ARTO : TwbSignature = 'ARTO'; ASPC : TwbSignature = 'ASPC'; ASTP : TwbSignature = 'ASTP'; ATKD : TwbSignature = 'ATKD'; { New to Skyrim } ATKE : TwbSignature = 'ATKE'; { New to Skyrim } ATKR : TwbSignature = 'ATKR'; { New to Skyrim } ATKT : TwbSignature = 'ATKT'; { New To Fallout 4 } ATKS : TwbSignature = 'ATKS'; { New To Fallout 4 } ATKW : TwbSignature = 'ATKW'; { New To Fallout 4 } ATTN : TwbSignature = 'ATTN'; { New To Fallout 4 } ATTX : TwbSignature = 'ATTX'; { New To Fallout 4 } ATXT : TwbSignature = 'ATXT'; AVFL : TwbSignature = 'AVFL'; { New To Fallout 4 } AVIF : TwbSignature = 'AVIF'; AVSK : TwbSignature = 'AVSK'; { New to Skyrim } BAMT : TwbSignature = 'BAMT'; { New to Skyrim } BCLF : TwbSignature = 'BCLF'; { New to Fallout 4 } BIDS : TwbSignature = 'BIDS'; { New to Skyrim } BIPL : TwbSignature = 'BIPL'; BMCT : TwbSignature = 'BMCT'; BMMP : TwbSignature = 'BMMP'; { New to Fallout 4 } BNAM : TwbSignature = 'BNAM'; BNDS : TwbSignature = 'BNDS'; { New to Fallout 4 } BOD2 : TwbSignature = 'BOD2'; { New to Skyrim 1.6.91 CK} BODT : TwbSignature = 'BODT'; { New to Skyrim } BOOK : TwbSignature = 'BOOK'; BPND : TwbSignature = 'BPND'; BPNI : TwbSignature = 'BPNI'; BPNN : TwbSignature = 'BPNN'; BPNT : TwbSignature = 'BPNT'; BPTD : TwbSignature = 'BPTD'; BPTN : TwbSignature = 'BPTN'; BSIZ : TwbSignature = 'BSIZ'; { New to Fallout 4 } BSMB : TwbSignature = 'BSMB'; { New to Fallout 4 } BSMP : TwbSignature = 'BSMP'; { New to Fallout 4 } BSMS : TwbSignature = 'BSMS'; { New to Fallout 4 } BTXT : TwbSignature = 'BTXT'; CAMS : TwbSignature = 'CAMS'; CDIX : TwbSignature = 'CDIX'; { New to Fallout 4 } CELL : TwbSignature = 'CELL'; CIS1 : TwbSignature = 'CIS1'; { New to Skyrim } CIS2 : TwbSignature = 'CIS2'; { New to Skyrim } CITC : TwbSignature = 'CITC'; { New to Skyrim } CLAS : TwbSignature = 'CLAS'; CLFM : TwbSignature = 'CLFM'; CLMT : TwbSignature = 'CLMT'; CLSZ : TwbSignature = 'CLSZ'; { New to Fallout 4 } CMPO : TwbSignature = 'CMPO'; { New to Fallout 4 } CNAM : TwbSignature = 'CNAM'; CNTO : TwbSignature = 'CNTO'; COBJ : TwbSignature = 'COBJ'; COCT : TwbSignature = 'COCT'; { New to Skyrim 'Count'} COED : TwbSignature = 'COED'; COLL : TwbSignature = 'COLL'; CONT : TwbSignature = 'CONT'; CPTH : TwbSignature = 'CPTH'; CRDT : TwbSignature = 'CRDT'; CRGR : TwbSignature = 'CRGR'; { New to Skyrim } CRIF : TwbSignature = 'CRIF'; { New to Skyrim } CRIS : TwbSignature = 'CRIS'; { New to Fallout 4 } CRVA : TwbSignature = 'CRVA'; { New to Skyrim } CS2H : TwbSignature = 'CS2H'; { New To Fallout 4 } CS2D : TwbSignature = 'CS2D'; { New To Fallout 4 } CS2E : TwbSignature = 'CS2E'; { New To Fallout 4 } CS2F : TwbSignature = 'CS2F'; { New To Fallout 4 } CS2K : TwbSignature = 'CS2K'; { New To Fallout 4 } CSCR : TwbSignature = 'CSCR'; CSCV : TwbSignature = 'CSCV'; { New To Fallout 4 } CSDC : TwbSignature = 'CSDC'; CSDI : TwbSignature = 'CSDI'; CSDT : TwbSignature = 'CSDT'; CSFL : TwbSignature = 'CSFL'; { New to Skyrim } CSGD : TwbSignature = 'CSGD'; { New to Skyrim } CSLR : TwbSignature = 'CSLR'; { New to Skyrim } CSMD : TwbSignature = 'CSMD'; { New to Skyrim } CSME : TwbSignature = 'CSME'; { New to Skyrim } CSRA : TwbSignature = 'CSRA'; { New To Fallout 4 } CSTY : TwbSignature = 'CSTY'; CTDA : TwbSignature = 'CTDA'; CUSD : TwbSignature = 'CUSD'; { New to Fallout 4 } CVPA : TwbSignature = 'CVPA'; { New to Fallout 4 } DALC : TwbSignature = 'DALC'; { New to Skyrim } DAMA : TwbSignature = 'DAMA'; { New to Fallout 4 } DAMC : TwbSignature = 'DAMC'; { New to Fallout 4 } DATA : TwbSignature = 'DATA'; DEBR : TwbSignature = 'DEBR'; DELE : TwbSignature = 'DELE'; DEMO : TwbSignature = 'DEMO'; { New to Skyrim } DESC : TwbSignature = 'DESC'; DEST : TwbSignature = 'DEST'; DEVA : TwbSignature = 'DEVA'; { New to Skyrim } DFOB : TwbSignature = 'DFOB'; { New to Fallout 4 } DFTF : TwbSignature = 'DFTF'; { New To Skyrim } DFTM : TwbSignature = 'DFTM'; { New To Skyrim } DIAL : TwbSignature = 'DIAL'; DLBR : TwbSignature = 'DLBR'; DLVW : TwbSignature = 'DLVW'; DMAX : TwbSignature = 'DMAX'; { New to Skyrim } DMDC : TwbSignature = 'DMDC'; { New to Fallout 4 } DMDL : TwbSignature = 'DMDL'; DMDS : TwbSignature = 'DMDS'; { New to Skyrim } DMDT : TwbSignature = 'DMDT'; DMGT : TwbSignature = 'DMGT'; { New to Fallout 4 } DMIN : TwbSignature = 'DMIN'; { New to Skyrim } DNAM : TwbSignature = 'DNAM'; DOBJ : TwbSignature = 'DOBJ'; DODT : TwbSignature = 'DODT'; DOFT : TwbSignature = 'DOFT'; { New to Skyrim } DOOR : TwbSignature = 'DOOR'; DPLT : TwbSignature = 'DPLT'; { New to Skyrim } DSTA : TwbSignature = 'DSTA'; { New To Fallout 4 } DSTD : TwbSignature = 'DSTD'; DSTF : TwbSignature = 'DSTF'; DTGT : TwbSignature = 'DTGT'; { New To Fallout 4 } DTID : TwbSignature = 'DTID'; { New To Fallout 4 } DUAL : TwbSignature = 'DUAL'; EAMT : TwbSignature = 'EAMT'; ECOR : TwbSignature = 'ECOR'; { New to Skyrim } ECZN : TwbSignature = 'ECZN'; EDID : TwbSignature = 'EDID'; EFID : TwbSignature = 'EFID'; EFIT : TwbSignature = 'EFIT'; EFSH : TwbSignature = 'EFSH'; EITM : TwbSignature = 'EITM'; ENAM : TwbSignature = 'ENAM'; ENCH : TwbSignature = 'ENCH'; ENIT : TwbSignature = 'ENIT'; EPF2 : TwbSignature = 'EPF2'; EPF3 : TwbSignature = 'EPF3'; EPFB : TwbSignature = 'EPFB'; { New To Fallout 4 } EPFD : TwbSignature = 'EPFD'; EPFT : TwbSignature = 'EPFT'; EQUP : TwbSignature = 'EQUP'; ESCE : TwbSignature = 'ESCE'; ETYP : TwbSignature = 'ETYP'; EXPL : TwbSignature = 'EXPL'; EYES : TwbSignature = 'EYES'; FACT : TwbSignature = 'FACT'; FCHT : TwbSignature = 'FCHT'; { New to Skyrim } FCPL : TwbSignature = 'FCPL'; { New To Fallout 4 } FFFF : TwbSignature = 'FFFF'; FIMD : TwbSignature = 'FIMD'; { New To Fallout 4 } FLMV : TwbSignature = 'FLMV'; { New to Skyrim } FLOR : TwbSignature = 'FLOR'; FLST : TwbSignature = 'FLST'; FLTR : TwbSignature = 'FLTR'; { New to Skyrim } FLTV : TwbSignature = 'FLTV'; FMIN : TwbSignature = 'FMIN'; { New To Fallout 4 } FMRI : TwbSignature = 'FMRI'; { New To Fallout 4 } FMRN : TwbSignature = 'FMRN'; { New To Fallout 4 } FMRS : TwbSignature = 'FMRS'; { New To Fallout 4 } FNAM : TwbSignature = 'FNAM'; FNMK : TwbSignature = 'FNMK'; { New to Skyrim } FNPR : TwbSignature = 'FNPR'; { New to Skyrim } FPRT : TwbSignature = 'FPRT'; { New to Skyrim } FSTP : TwbSignature = 'FSTP'; FSTS : TwbSignature = 'FSTS'; FTSF : TwbSignature = 'FTSF'; { New to Skyrim } FTSM : TwbSignature = 'FTSM'; { New to Skyrim } FTST : TwbSignature = 'FTST'; { New to Skyrim } FTYP : TwbSignature = 'FTYP'; { New To Fallout 4 } FULL : TwbSignature = 'FULL'; FURN : TwbSignature = 'FURN'; FVPA : TwbSignature = 'FVPA'; { New To Fallout 4 } GDRY : TwbSignature = 'GDRY'; { New to Fallout 4 } GLOB : TwbSignature = 'GLOB'; GMST : TwbSignature = 'GMST'; GNAM : TwbSignature = 'GNAM'; GRAS : TwbSignature = 'GRAS'; GREE : TwbSignature = 'GREE'; { New to Fallout 4 } GWOR : TwbSignature = 'GWOR'; { New to Skyrim } HAZD : TwbSignature = 'HAZD'; HCLF : TwbSignature = 'HCLF'; { New to Skyrim } HDPT : TwbSignature = 'HDPT'; HEAD : TwbSignature = 'HEAD'; { New to Skyrim } HEDR : TwbSignature = 'HEDR'; HLTX : TwbSignature = 'HLTX'; { New to Fallout 4 } HNAM : TwbSignature = 'HNAM'; HTID : TwbSignature = 'HTID'; { New to Skyrim } ICO2 : TwbSignature = 'ICO2'; ICON : TwbSignature = 'ICON'; IDLA : TwbSignature = 'IDLA'; IDLB : TwbSignature = 'IDLB'; IDLC : TwbSignature = 'IDLC'; IDLE : TwbSignature = 'IDLE'; IDLF : TwbSignature = 'IDLF'; IDLM : TwbSignature = 'IDLM'; IDLT : TwbSignature = 'IDLT'; IMAD : TwbSignature = 'IMAD'; IMGS : TwbSignature = 'IMGS'; IMSP : TwbSignature = 'IMSP'; { New to Skyrim } INAM : TwbSignature = 'INAM'; INCC : TwbSignature = 'INCC'; { New to Skyrim } INDX : TwbSignature = 'INDX'; INFO : TwbSignature = 'INFO'; INGR : TwbSignature = 'INGR'; INNR : TwbSignature = 'INNR'; { New To Fallout 4 } INRD : TwbSignature = 'INRD'; { New To Fallout 4 } INTT : TwbSignature = 'INTT'; { New To Fallout 4 } INTV : TwbSignature = 'INTV'; IOVR : TwbSignature = 'IOVR'; { New To Fallout 4 } IPCT : TwbSignature = 'IPCT'; IPDS : TwbSignature = 'IPDS'; ISIZ : TwbSignature = 'ISIZ'; { New To Fallout 4 } ITID : TwbSignature = 'ITID'; { New To Fallout 4 } ITMC : TwbSignature = 'ITMC'; { New To Fallout 4 } ITME : TwbSignature = 'ITME'; { New To Fallout 4 } ITMS : TwbSignature = 'ITMS'; { New To Fallout 4 } ITXT : TwbSignature = 'ITXT'; JAIL : TwbSignature = 'JAIL'; { New To Skyrim } JNAM : TwbSignature = 'JNAM'; JOUT : TwbSignature = 'JOUT'; { New To Skyrim } KEYM : TwbSignature = 'KEYM'; KNAM : TwbSignature = 'KNAM'; KSIZ : TwbSignature = 'KSIZ'; KSSM : TwbSignature = 'KSSM'; { New To Fallout 4 } KWDA : TwbSignature = 'KWDA'; KYWD : TwbSignature = 'KYWD'; LAND : TwbSignature = 'LAND'; LAYR : TwbSignature = 'LAYR'; { New to Fallout 4 } LCEC : TwbSignature = 'LCEC'; { New to Skyrim } LCEP : TwbSignature = 'LCEP'; { New to Skyrim } LCID : TwbSignature = 'LCID'; { New to Skyrim } LCPR : TwbSignature = 'LCPR'; { New to Skyrim } LCRT : TwbSignature = 'LCRT'; LCSR : TwbSignature = 'LCSR'; { New to Skyrim } LCTN : TwbSignature = 'LCTN'; LCUN : TwbSignature = 'LCUN'; { New to Skyrim } LENS : TwbSignature = 'LENS'; { New to Fallout 4 } LFSD : TwbSignature = 'LFSD'; { New to Fallout 4 } LFSP : TwbSignature = 'LFSP'; { New to Fallout 4 } LGTM : TwbSignature = 'LGTM'; LIGH : TwbSignature = 'LIGH'; LLCT : TwbSignature = 'LLCT'; {New to Skyrim, part of LVLI 'Count'} LLKC : TwbSignature = 'LLKC'; { New to Fallout 4 } LNAM : TwbSignature = 'LNAM'; LSCR : TwbSignature = 'LSCR'; LSPR : TwbSignature = 'LSPR'; { New to Fallout 4 } LTEX : TwbSignature = 'LTEX'; LTMP : TwbSignature = 'LTMP'; LTPT : TwbSignature = 'LTPT'; { New to Fallout 4 } LTPC : TwbSignature = 'LTPC'; { New to Fallout 4 } LVLC : TwbSignature = 'LVLC'; LVLD : TwbSignature = 'LVLD'; LVLF : TwbSignature = 'LVLF'; LVLG : TwbSignature = 'LVLG'; LVLI : TwbSignature = 'LVLI'; LVLM : TwbSignature = 'LVLM'; { New to Fallout 4 } LVLN : TwbSignature = 'LVLN'; LVLO : TwbSignature = 'LVLO'; LVSG : TwbSignature = 'LVSG'; { New to Fallout 4 } LVSP : TwbSignature = 'LVSP'; MASE : TwbSignature = 'MASE'; { New To Fallout 4 } MAST : TwbSignature = 'MAST'; MATO : TwbSignature = 'MATO'; MATT : TwbSignature = 'MATT'; MCHT : TwbSignature = 'MCHT'; { New to Skyrim } MDOB : TwbSignature = 'MDOB'; MESG : TwbSignature = 'MESG'; MGEF : TwbSignature = 'MGEF'; MHDT : TwbSignature = 'MHDT'; { New to Skyrim } MIC2 : TwbSignature = 'MIC2'; MICN : TwbSignature = 'MICN'; { New to Fallout 4 } MICO : TwbSignature = 'MICO'; MISC : TwbSignature = 'MISC'; MLSI : TwbSignature = 'MLSI'; { New to Fallout 4 } MNAM : TwbSignature = 'MNAM'; MO2C : TwbSignature = 'MO2C'; { New to Fallout 4 } MO2F : TwbSignature = 'MO2F'; { New to Fallout 4 } MO2S : TwbSignature = 'MO2S'; MO2T : TwbSignature = 'MO2T'; MO3C : TwbSignature = 'MO3C'; { New to Fallout 4 } MO3F : TwbSignature = 'MO3F'; { New to Fallout 4 } MO3S : TwbSignature = 'MO3S'; MO3T : TwbSignature = 'MO3T'; MO4C : TwbSignature = 'MO4C'; { New to Fallout 4 } MO4F : TwbSignature = 'MO4F'; { New to Fallout 4 } MO4S : TwbSignature = 'MO4S'; MO4T : TwbSignature = 'MO4T'; MO5C : TwbSignature = 'MO5C'; { New to Fallout 4 } MO5F : TwbSignature = 'MO5F'; { New to Fallout 4 } MO5S : TwbSignature = 'MO5S'; { New to Skyrim } MO5T : TwbSignature = 'MO5T'; { New to Skyrim } MOD2 : TwbSignature = 'MOD2'; MOD3 : TwbSignature = 'MOD3'; MOD4 : TwbSignature = 'MOD4'; MOD5 : TwbSignature = 'MOD5'; { New to Skyrim } MODC : TwbSignature = 'MODC'; { New to Fallout 4 } MODF : TwbSignature = 'MODF'; { New to Fallout 4 } MODL : TwbSignature = 'MODL'; MODS : TwbSignature = 'MODS'; MODT : TwbSignature = 'MODT'; MODQ : TwbSignature = 'MODQ'; { New to Fallout 4 } MOVT : TwbSignature = 'MOVT'; MPAI : TwbSignature = 'MPAI'; { New To Skyrim } MPAV : TwbSignature = 'MPAV'; { New To Skyrim } MPCD : TwbSignature = 'MPCD'; { New to Fallout 4 } MPGN : TwbSignature = 'MPGN'; { New to Fallout 4 } MPGS : TwbSignature = 'MPGS'; { New to Fallout 4 } MPPC : TwbSignature = 'MPPC'; { New to Fallout 4 } MPPF : TwbSignature = 'MPPF'; { New to Fallout 4 } MPPI : TwbSignature = 'MPPI'; { New to Fallout 4 } MPPK : TwbSignature = 'MPPK'; { New to Fallout 4 } MPPM : TwbSignature = 'MPPM'; { New to Fallout 4 } MPPN : TwbSignature = 'MPPN'; { New to Fallout 4 } MPPT : TwbSignature = 'MPPT'; { New to Fallout 4 } MPRT : TwbSignature = 'MPRT'; { New to Skyrim } MRSV : TwbSignature = 'MRSV'; { New to Fallout 4 } MSDK : TwbSignature = 'MSDK'; { New to Fallout 4 } MSDV : TwbSignature = 'MSDV'; { New to Fallout 4 } MSID : TwbSignature = 'MSID'; { New to Fallout 4 } MSM0 : TwbSignature = 'MSM0'; { New to Fallout 4 } MSM1 : TwbSignature = 'MSM1'; { New to Fallout 4 } MSTT : TwbSignature = 'MSTT'; MSWP : TwbSignature = 'MSWP'; { New to Fallout 4 } MTNM : TwbSignature = 'MTNM'; { New to Skyrim } MTYP : TwbSignature = 'MTYP'; { New To Skyrim } MUSC : TwbSignature = 'MUSC'; MUST : TwbSignature = 'MUST'; MWGT : TwbSignature = 'MWGT'; { New to Fallout 4 } NAM0 : TwbSignature = 'NAM0'; NAM1 : TwbSignature = 'NAM1'; NAM2 : TwbSignature = 'NAM2'; NAM3 : TwbSignature = 'NAM3'; NAM4 : TwbSignature = 'NAM4'; NAM5 : TwbSignature = 'NAM5'; NAM6 : TwbSignature = 'NAM6'; NAM7 : TwbSignature = 'NAM7'; NAM8 : TwbSignature = 'NAM8'; NAM9 : TwbSignature = 'NAM9'; NAMA : TwbSignature = 'NAMA'; { New to Skyrim } NAME : TwbSignature = 'NAME'; NAVI : TwbSignature = 'NAVI'; NAVM : TwbSignature = 'NAVM'; NETO : TwbSignature = 'NETO'; { New to Fallout 4 } NEXT : TwbSignature = 'NEXT'; NNAM : TwbSignature = 'NNAM'; NNGT : TwbSignature = 'NNGT'; { New to Fallout 4 } NNGS : TwbSignature = 'NNGS'; { New to Fallout 4 } NNUS : TwbSignature = 'NNUS'; { New to Fallout 4 } NNUT : TwbSignature = 'NNUT'; { New to Fallout 4 } NOCM : TwbSignature = 'NOCM'; { New to Fallout 4 } NONE : TwbSignature = 'NONE'; { New to Fallout 4, used in OMOD Form Type } NOTE : TwbSignature = 'NOTE'; { New to Fallout 4 } NPC_ : TwbSignature = 'NPC_'; NPOS : TwbSignature = 'NPOS'; { New to Fallout 4 } NPOT : TwbSignature = 'NPOT'; { New to Fallout 4 } NQUS : TwbSignature = 'NQUS'; { New to Fallout 4 } NQUT : TwbSignature = 'NQUT'; { New to Fallout 4 } NTOP : TwbSignature = 'NTOP'; { New to Fallout 4 } NTRM : TwbSignature = 'NTRM'; { New to Fallout 4 } NULL : TwbSignature = 'NULL'; NVER : TwbSignature = 'NVER'; NVMI : TwbSignature = 'NVMI'; NVNM : TwbSignature = 'NVNM'; { New to Skyrim } NVPP : TwbSignature = 'NVPP'; { New to Skyrim } NVSI : TwbSignature = 'NVSI'; { New to Dawnguard } OBND : TwbSignature = 'OBND'; OBTE : TwbSignature = 'OBTE'; { New to Fallout 4 } OBTF : TwbSignature = 'OBTF'; { New to Fallout 4 } OBTS : TwbSignature = 'OBTS'; { New to Fallout 4 } OCOR : TwbSignature = 'OCOR'; { New to Skyrim } OFST : TwbSignature = 'OFST'; OMOD : TwbSignature = 'OMOD'; { New to Fallout 4 } ONAM : TwbSignature = 'ONAM'; OTFT : TwbSignature = 'OTFT'; OVIS : TwbSignature = 'OVIS'; { New to Fallout 4 } PACK : TwbSignature = 'PACK'; PARW : TwbSignature = 'PARW'; { New to Skyrim } PBAR : TwbSignature = 'PBAR'; { New to Skyrim } PBEA : TwbSignature = 'PBEA'; { New to Skyrim } PCMB : TwbSignature = 'PCMB'; { New to Fallout 4 } PCON : TwbSignature = 'PCON'; { New to Skyrim } PDTO : TwbSignature = 'PDTO'; { New to Skyrim } PERK : TwbSignature = 'PERK'; PFIG : TwbSignature = 'PFIG'; PFLA : TwbSignature = 'PFLA'; { New to Skyrim } PFO2 : TwbSignature = 'PFO2'; { New to Skyrim } PFOR : TwbSignature = 'PFOR'; { New to Skyrim } PFPC : TwbSignature = 'PFPC'; PFRN : TwbSignature = 'PFRN'; { New to Fallout 4 } PGRE : TwbSignature = 'PGRE'; PHTN : TwbSignature = 'PHTN'; { New to Skyrim } PHWT : TwbSignature = 'PHWT'; { New to Skyrim } PHZD : TwbSignature = 'PHZD'; PKC2 : TwbSignature = 'PKC2'; { New to Skyrim } PKCU : TwbSignature = 'PKCU'; { New to Skyrim } PKDT : TwbSignature = 'PKDT'; PKID : TwbSignature = 'PKID'; PKIN : TwbSignature = 'PKIN'; { New to Fallout 4 } PLCN : TwbSignature = 'PLCN'; { New to Skyrim } PLDT : TwbSignature = 'PLDT'; PLVD : TwbSignature = 'PLVD'; { New to Skyrim } PLYR : TwbSignature = 'PLYR'; PMIS : TwbSignature = 'PMIS'; PNAM : TwbSignature = 'PNAM'; POBA : TwbSignature = 'POBA'; POCA : TwbSignature = 'POCA'; POEA : TwbSignature = 'POEA'; PRCB : TwbSignature = 'PRCB'; { New to Skyrim } PRKC : TwbSignature = 'PRKC'; PRKE : TwbSignature = 'PRKE'; PRKF : TwbSignature = 'PRKF'; PRKR : TwbSignature = 'PRKR'; { New to Skyrim } PRKZ : TwbSignature = 'PRKZ'; { New to Skyrim } PROJ : TwbSignature = 'PROJ'; PRPS : TwbSignature = 'PRPS'; { New to Fallout 4 } PSDT : TwbSignature = 'PSDT'; PTDA : TwbSignature = 'PTDA'; { New to Skyrim } PTOP : TwbSignature = 'PTOP'; { New to Fallout 4 } PTRN : TwbSignature = 'PTRN'; { New to Fallout 4 } QNAM : TwbSignature = 'QNAM'; QOBJ : TwbSignature = 'QOBJ'; QSDT : TwbSignature = 'QSDT'; QSTA : TwbSignature = 'QSTA'; QSTI : TwbSignature = 'QSTI'; { New to Fallout 4 } QTGL : TwbSignature = 'QTGL'; { New To Skyrim } QTOP : TwbSignature = 'QTOP'; { New to Fallout 4 } QUAL : TwbSignature = 'QUAL'; { New To Skyrim } QUST : TwbSignature = 'QUST'; RACE : TwbSignature = 'RACE'; RADR : TwbSignature = 'RADR'; { New To Fallout 4 } RBPC : TwbSignature = 'RBPC'; { New To Fallout 4 } RCEC : TwbSignature = 'RCEC'; { New To Skyrim } RCLR : TwbSignature = 'RCLR'; RCPR : TwbSignature = 'RCPR'; { New to Dawnguard } RCSR : TwbSignature = 'RCSR'; { New To Skyrim } RCUN : TwbSignature = 'RCUN'; { New To Skyrim } RDAT : TwbSignature = 'RDAT'; RDGS : TwbSignature = 'RDGS'; RDMO : TwbSignature = 'RDMO'; RDMP : TwbSignature = 'RDMP'; RDOT : TwbSignature = 'RDOT'; RDSA : TwbSignature = 'RDSA'; { New to Skyrim } RDWT : TwbSignature = 'RDWT'; REFR : TwbSignature = 'REFR'; REGN : TwbSignature = 'REGN'; RELA : TwbSignature = 'RELA'; REPL : TwbSignature = 'REPL'; REPT : TwbSignature = 'REPT'; { New To Fallout 4 } REVB : TwbSignature = 'REVB'; RFCT : TwbSignature = 'RFCT'; RFGP : TwbSignature = 'RFGP'; { New to Fallout 4 } RGDL : TwbSignature = 'RGDL'; { Unused in Skyrim, but contained in Skyrim.esm } RLDM : TwbSignature = 'RLDM'; { New to Fallout 4 } RNAM : TwbSignature = 'RNAM'; RNMV : TwbSignature = 'RNMV'; { New to Skyrim } RPLD : TwbSignature = 'RPLD'; RPLI : TwbSignature = 'RPLI'; RPRF : TwbSignature = 'RPRF'; { New To Skyrim } RPRM : TwbSignature = 'RPRM'; { New To Skyrim } RVIS : TwbSignature = 'RVIS'; { New to Fallout 4 } SADD : TwbSignature = 'SADD'; { New To Fallout 4 } SAKD : TwbSignature = 'SAKD'; { New To Fallout 4 } SAPT : TwbSignature = 'SAPT'; { New To Fallout 4 } SCCO : TwbSignature = 'SCCO'; { New To Fallout 4 } SCDA : TwbSignature = 'SCDA'; SCEN : TwbSignature = 'SCEN'; SCHR : TwbSignature = 'SCHR'; SCOL : TwbSignature = 'SCOL'; { Unused in Skyrim, but contained in Skyrim.esm } SCPT : TwbSignature = 'SCPT'; { Unused in Skyrim, but contained in Skyrim.esm } SCQS : TwbSignature = 'SCQS'; { New To Fallout 4 } SCRL : TwbSignature = 'SCRL'; SCRN : TwbSignature = 'SCRN'; SCRO : TwbSignature = 'SCRO'; SCSN : TwbSignature = 'SCSN'; { New To Fallout 4 } SCTX : TwbSignature = 'SCTX'; SDSC : TwbSignature = 'SDSC'; { New to Skyrim } SGNM : TwbSignature = 'SGNM'; { New to Fallout 4 } SHOU : TwbSignature = 'SHOU'; SHRT : TwbSignature = 'SHRT'; { New to Skyrim } SKIL : TwbSignature = 'SKIL'; { New to Fallout 4 } SLCP : TwbSignature = 'SLCP'; SLGM : TwbSignature = 'SLGM'; SMBN : TwbSignature = 'SMBN'; SMEN : TwbSignature = 'SMEN'; SMQN : TwbSignature = 'SMQN'; SNAM : TwbSignature = 'SNAM'; SNCT : TwbSignature = 'SNCT'; SNDD : TwbSignature = 'SNDD'; SNDR : TwbSignature = 'SNDR'; SNMV : TwbSignature = 'SNMV'; { New to Skyrim } SOFT : TwbSignature = 'SOFT'; { New to Skyrim } SOPM : TwbSignature = 'SOPM'; SOUL : TwbSignature = 'SOUL'; SOUN : TwbSignature = 'SOUN'; SPCT : TwbSignature = 'SPCT'; { New to Skyrim } SPED : TwbSignature = 'SPED'; { New To Skyrim } SPEL : TwbSignature = 'SPEL'; SPGD : TwbSignature = 'SPGD'; SPIT : TwbSignature = 'SPIT'; SPLO : TwbSignature = 'SPLO'; SPMV : TwbSignature = 'SPMV'; { New To Skyrim } SPOR : TwbSignature = 'SPOR'; { New to Skyrim } SRAC : TwbSignature = 'SRAC'; { New to Fallout 4 } SRAF : TwbSignature = 'SRAF'; { New to Fallout 4 } SSPN : TwbSignature = 'SSPN'; { New to Fallout 4 } STAG : TwbSignature = 'STAG'; { New to Fallout 4 } STAT : TwbSignature = 'STAT'; STCP : TwbSignature = 'STCP'; { New to Fallout 4 } STKD : TwbSignature = 'STKD'; { New to Fallout 4 } STOL : TwbSignature = 'STOL'; { New to Skyrim } STOP : TwbSignature = 'STOP'; { New to Fallout 4 } STSC : TwbSignature = 'STSC'; { New to Fallout 4 } SWMV : TwbSignature = 'SWMV'; { New to Skyrim } TACT : TwbSignature = 'TACT'; TCLT : TwbSignature = 'TCLT'; TERM : TwbSignature = 'TERM'; { New to Fallout 4 } TES4 : TwbSignature = 'TES4'; TETI : TwbSignature = 'TETI'; { New to Fallout 4 } TEND : TwbSignature = 'TEND'; { New to Fallout 4 } TIAS : TwbSignature = 'TIAS'; { New to Skyrim } TIFC : TwbSignature = 'TIFC'; { New To Skyrim } TINC : TwbSignature = 'TINC'; { New to Skyrim } TIND : TwbSignature = 'TIND'; { New to Skyrim } TINI : TwbSignature = 'TINI'; { New to Skyrim } TINL : TwbSignature = 'TINL'; { New to Skyrim } TINP : TwbSignature = 'TINP'; { New to Skyrim } TINT : TwbSignature = 'TINT'; { New to Skyrim } TINV : TwbSignature = 'TINV'; { New to Skyrim } TIQS : TwbSignature = 'TIQS'; { New to Fallout 4 } TIRS : TwbSignature = 'TIRS'; { New to Skyrim } TLOD : TwbSignature = 'TLOD'; { New to Fallout 4 } TNAM : TwbSignature = 'TNAM'; TOFT : TwbSignature = 'TOFT'; { New to Fallout 4 } TPIC : TwbSignature = 'TPIC'; TPLT : TwbSignature = 'TPLT'; TPTA : TwbSignature = 'TPTA'; { New To Fallout 4 } TRDA : TwbSignature = 'TRDA'; { New To Fallout 4 } TRDT : TwbSignature = 'TRDT'; TREE : TwbSignature = 'TREE'; TRNS : TwbSignature = 'TRNS'; { New To Fallout 4 } TSCE : TwbSignature = 'TSCE'; { New To Fallout 4 } TTEB : TwbSignature = 'TTEB'; { New To Fallout 4 } TTEC : TwbSignature = 'TTEC'; { New To Fallout 4 } TTED : TwbSignature = 'TTED'; { New To Fallout 4 } TTEF : TwbSignature = 'TTEF'; { New To Fallout 4 } TTET : TwbSignature = 'TTET'; { New To Fallout 4 } TTGE : TwbSignature = 'TTGE'; { New To Fallout 4 } TTGP : TwbSignature = 'TTGP'; { New To Fallout 4 } TVDT : TwbSignature = 'TVDT'; { New To Skyrim } TWAT : TwbSignature = 'TWAT'; { New To Skyrim } TX00 : TwbSignature = 'TX00'; TX01 : TwbSignature = 'TX01'; TX02 : TwbSignature = 'TX02'; TX03 : TwbSignature = 'TX03'; TX04 : TwbSignature = 'TX04'; TX05 : TwbSignature = 'TX05'; TX06 : TwbSignature = 'TX06'; { New To Skyrim } TX07 : TwbSignature = 'TX07'; { New To Skyrim } TXST : TwbSignature = 'TXST'; UNAM : TwbSignature = 'UNAM'; UNES : TwbSignature = 'UNES'; { New To Skyrim } UNWP : TwbSignature = 'UNWP'; { New To Fallout 4 } VATS : TwbSignature = 'VATS'; VCLR : TwbSignature = 'VCLR'; VENC : TwbSignature = 'VENC'; { New To Skyrim } VEND : TwbSignature = 'VEND'; { New To Skyrim } VENV : TwbSignature = 'VENV'; { New To Skyrim } VHGT : TwbSignature = 'VHGT'; VISI : TwbSignature = 'VISI'; { New To Fallout 4 } VMAD : TwbSignature = 'VMAD'; VNAM : TwbSignature = 'VNAM'; VNML : TwbSignature = 'VNML'; VTCK : TwbSignature = 'VTCK'; VTEX : TwbSignature = 'VTEX'; VTXT : TwbSignature = 'VTXT'; VTYP : TwbSignature = 'VTYP'; WAIT : TwbSignature = 'WAIT'; { New To Skyrim } WAMD : TwbSignature = 'WAMD'; { New To Fallout 4 } WATR : TwbSignature = 'WATR'; WBDT : TwbSignature = 'WBDT'; { New to Skyrim } WCTR : TwbSignature = 'WCTR'; { New To Skyrim } WEAP : TwbSignature = 'WEAP'; WGDR : TwbSignature = 'WGDR'; { New To Fallout 4 } WKMV : TwbSignature = 'WKMV'; { New to Skyrim } WLEV : TwbSignature = 'WLEV'; { New To Fallout 4 } WLST : TwbSignature = 'WLST'; WMAP : TwbSignature = 'WMAP'; { New To Fallout 4 } WNAM : TwbSignature = 'WNAM'; WOOP : TwbSignature = 'WOOP'; WRLD : TwbSignature = 'WRLD'; WTHR : TwbSignature = 'WTHR'; WZMD : TwbSignature = 'WZMD'; { New To Fallout 4 } XACT : TwbSignature = 'XACT'; XALP : TwbSignature = 'XALP'; { New To Skyrim } XAMC : TwbSignature = 'XAMC'; { New To Fallout 4 } XAPD : TwbSignature = 'XAPD'; XAPR : TwbSignature = 'XAPR'; XASP : TwbSignature = 'XASP'; { New To Fallout 4 } XATP : TwbSignature = 'XATP'; { New To Fallout 4 } XATR : TwbSignature = 'XATR'; { New To Dawnguard } XBSD : TwbSignature = 'XBSD'; { New To Fallout 4 } XCAS : TwbSignature = 'XCAS'; XCCM : TwbSignature = 'XCCM'; XCHG : TwbSignature = 'XCHG'; XCIM : TwbSignature = 'XCIM'; XCLC : TwbSignature = 'XCLC'; XCLL : TwbSignature = 'XCLL'; XCLP : TwbSignature = 'XCLP'; XCLR : TwbSignature = 'XCLR'; XCLW : TwbSignature = 'XCLW'; XCMO : TwbSignature = 'XCMO'; XCNT : TwbSignature = 'XCNT'; XCRI : TwbSignature = 'XCRI'; { New To Fallout 4 } XCVL : TwbSignature = 'XCVL'; { New To Skyrim } XCVR : TwbSignature = 'XCVR'; { New To Fallout 4 } XCWT : TwbSignature = 'XCWT'; XCZA : TwbSignature = 'XCZA'; { New To Skyrim } XCZC : TwbSignature = 'XCZC'; { New To Skyrim } XCZR : TwbSignature = 'XCZR'; { New To Skyrim } XDCR : TwbSignature = 'XDCR'; XEMI : TwbSignature = 'XEMI'; XESP : TwbSignature = 'XESP'; XEZN : TwbSignature = 'XEZN'; XFVC : TwbSignature = 'XFVC'; { New To Skyrim } XGDR : TwbSignature = 'XGDR'; { New To Fallout 4 } XGLB : TwbSignature = 'XGLB'; XHLP : TwbSignature = 'XHLP'; XHLT : TwbSignature = 'XHLT'; { New To Fallout 4 } XHOR : TwbSignature = 'XHOR'; { New To Skyrim } XHTW : TwbSignature = 'XHTW'; { New To Skyrim } XIBS : TwbSignature = 'XIBS'; XILL : TwbSignature = 'XILL'; { New To Skyrim } XILW : TwbSignature = 'XILW'; { New To Fallout 4 } XIS2 : TwbSignature = 'XIS2'; { New To Skyrim } XLCM : TwbSignature = 'XLCM'; XLCN : TwbSignature = 'XLCN'; { New To Skyrim } XLIB : TwbSignature = 'XLIB'; { New To Skyrim } XLIG : TwbSignature = 'XLIG'; { New To Skyrim } XLKR : TwbSignature = 'XLKR'; XLKT : TwbSignature = 'XLKT'; { New To Fallout 4 } XLOC : TwbSignature = 'XLOC'; XLOD : TwbSignature = 'XLOD'; XLRL : TwbSignature = 'XLRL'; { New To Skyrim } XLRM : TwbSignature = 'XLRM'; XLRT : TwbSignature = 'XLRT'; { New To Skyrim } XLTW : TwbSignature = 'XLTW'; XLYR : TwbSignature = 'XLYR'; { New To Fallout 4 } XMBO : TwbSignature = 'XMBO'; XMBP : TwbSignature = 'XMBP'; XMBR : TwbSignature = 'XMBR'; XMRC : TwbSignature = 'XMRC'; XMRK : TwbSignature = 'XMRK'; XMSP : TwbSignature = 'XMSP'; { New To Fallout 4 } XNAM : TwbSignature = 'XNAM'; XNDP : TwbSignature = 'XNDP'; XOCP : TwbSignature = 'XOCP'; XORD : TwbSignature = 'XORD'; XOWN : TwbSignature = 'XOWN'; XPDD : TwbSignature = 'XPDD'; { New To Fallout 4 } XPLK : TwbSignature = 'XPLK'; { New To Fallout 4 } XPOD : TwbSignature = 'XPOD'; XPPA : TwbSignature = 'XPPA'; XPRD : TwbSignature = 'XPRD'; XPRI : TwbSignature = 'XPRI'; { New To Fallout 4 } XPRM : TwbSignature = 'XPRM'; XPTL : TwbSignature = 'XPTL'; XPWR : TwbSignature = 'XPWR'; XRDO : TwbSignature = 'XRDO'; { New To Fallout 4 } XRDS : TwbSignature = 'XRDS'; XRFG : TwbSignature = 'XRFG'; { New To Fallout 4 } XRGB : TwbSignature = 'XRGB'; XRGD : TwbSignature = 'XRGD'; XRMR : TwbSignature = 'XRMR'; XRNK : TwbSignature = 'XRNK'; XSCL : TwbSignature = 'XSCL'; XSPC : TwbSignature = 'XSPC'; { New To Skyrim } XTEL : TwbSignature = 'XTEL'; XTNM : TwbSignature = 'XTNM'; { New To Skyrim } XTRI : TwbSignature = 'XTRI'; XWCN : TwbSignature = 'XWCN'; { New To Skyrim } XWCS : TwbSignature = 'XWCS'; { New To Skyrim } XWCU : TwbSignature = 'XWCU'; { New To Skyrim } XWEM : TwbSignature = 'XWEM'; { New To Skyrim } XWPG : TwbSignature = 'XWPG'; { New To Fallout 4 } XWPN : TwbSignature = 'XWPN'; { New To Fallout 4 } XXXX : TwbSignature = 'XXXX'; YNAM : TwbSignature = 'YNAM'; ZNAM : TwbSignature = 'ZNAM'; ZOOM : TwbSignature = 'ZOOM'; { New To Fallout 4 } // signatures of reference records sigReferences : array [0..11] of TwbSignature = ( 'NULL', 'PLYR', 'ACHR', 'REFR', 'PGRE', 'PHZD', 'PMIS', 'PARW', 'PBAR', 'PBEA', 'PCON', 'PFLA' ); // signatures of referenceable records (placed by references or constructable) sigBaseObjects : array [0..43] of TwbSignature = ( 'NULL', 'ACTI', 'ADDN', 'ALCH', 'AMMO', 'ARMO', 'ARTO', 'ASPC', 'BNDS', 'BOOK', 'CMPO', 'COBJ', 'CONT', 'DEBR', 'DOOR', 'EXPL', 'FLST', 'FLOR', 'FURN', 'HAZD', 'IDLM', 'INGR', 'KEYM', 'LIGH', 'LVLI', 'LVLN', 'LVSP', 'MISC', 'MSTT', 'NOTE', 'NPC_', 'OMOD', 'PROJ', 'SCOL', 'SCRL', 'SOUN', 'SPEL', 'STAT', 'TACT', 'TERM', 'TREE', 'TXST', 'WATR', 'WEAP' ); var wbPKDTSpecificFlagsUnused : Boolean; wbEDID: IwbSubRecordDef; wbCOED: IwbSubRecordDef; wbXLCM: IwbSubRecordDef; wbEITM: IwbSubRecordDef; wbOBND: IwbSubRecordDef; wbOBNDReq: IwbSubRecordDef; wbDEST: IwbSubRecordStructDef; wbDESTActor: IwbSubRecordStructDef; wbDODT: IwbSubRecordDef; wbXRGD: IwbSubRecordDef; wbXRGB: IwbSubRecordDef; wbSPLO: IwbSubRecordDef; wbSPLOs: IwbSubRecordArrayDef; wbCNTO: IwbSubRecordStructDef; wbCNTOs: IwbSubRecordArrayDef; wbAIDT: IwbSubRecordDef; wbFULL: IwbSubRecordDef; wbFULLActor: IwbSubRecordDef; wbFULLReq: IwbSubRecordDef; wbDESC: IwbSubRecordDef; wbDESCReq: IwbSubRecordDef; wbXSCL: IwbSubRecordDef; wbDATAPosRot: IwbSubRecordDef; wbPosRot: IwbStructDef; wbMODC: IwbSubRecordDef; wbMODF: IwbSubRecordDef; wbMODL: IwbSubRecordStructDef; wbMODS: IwbSubRecordDef; wbMO2S: IwbSubRecordDef; wbMO3S: IwbSubRecordDef; wbMO4S: IwbSubRecordDef; wbMO2F: IwbSubRecordDef; wbMO3F: IwbSubRecordDef; wbMO4F: IwbSubRecordDef; wbMO5F: IwbSubRecordDef; wbMO2C: IwbSubRecordDef; wbMO3C: IwbSubRecordDef; wbMO4C: IwbSubRecordDef; wbMO5C: IwbSubRecordDef; wbMODLActor: IwbSubRecordStructDef; wbMODLReq: IwbSubRecordStructDef; wbCTDA: IwbSubRecordStructDef; wbCTDAs: IwbSubRecordArrayDef; wbCTDAsReq: IwbSubRecordArrayDef; wbCTDAsCount: IwbSubRecordArrayDef; wbCTDAsReqCount: IwbSubRecordArrayDef; wbXLOD: IwbSubRecordDef; wbXESP: IwbSubRecordDef; wbICON: IwbSubRecordDef; wbMICO: IwbSubRecordDef; wbActorValue: IwbIntegerDef; wbETYP: IwbSubRecordDef; wbETYPReq: IwbSubRecordDef; wbEFID: IwbSubRecordDef; wbEFIT: IwbSubRecordDef; wbEffectsReq: IwbSubRecordArrayDef; wbFirstPersonFlagsU32: IwbIntegerDef; wbBOD2: IwbSubRecordDef; wbScriptEntry: IwbStructDef; wbScriptFlags: IwbIntegerDef; wbScriptPropertyObject: IwbUnionDef; wbScriptPropertyStruct: IwbArrayDef; wbScriptProperties: IwbArrayDef; wbScriptFragments: IwbStructDef; wbScriptFragmentsQuest: IwbStructDef; wbScriptFragmentsInfo: IwbStructDef; wbScriptFragmentsPack: IwbStructDef; wbScriptFragmentsScen: IwbStructDef; wbPLDT: IwbSubRecordDef; wbPLVD: IwbSubRecordDef; wbTargetData: IwbStructDef; wbAttackData: IwbSubRecordStructDef; wbLLCT: IwbSubRecordDef; wbLVLD: IwbSubRecordDef; wbVMAD: IwbSubRecordDef; wbVMADFragmentedPERK: IwbSubRecordDef; wbVMADFragmentedPACK: IwbSubRecordDef; wbVMADFragmentedQUST: IwbSubRecordDef; wbVMADFragmentedSCEN: IwbSubRecordDef; wbVMADFragmentedINFO: IwbSubRecordDef; wbCOCT: IwbSubRecordDef; wbKSIZ: IwbSubRecordDef; wbKWDAs: IwbSubRecordDef; wbReqKWDAs: IwbSubRecordDef; wbKeywords: IwbSubRecordStructDef; wbCNAM: IwbSubRecordDef; wbCITC: IwbSubRecordDef; wbMGEFData: IwbSubRecordStructDef; wbMGEFType: IwbIntegerDef; wbMDOB: IwbSubRecordDef; wbSPIT: IwbSubRecordDef; wbDMDC: IwbSubRecordDef; wbDMDS: IwbSubRecordDef; wbMO5S: IwbSubRecordDef; wbSPCT: IwbSubRecordDef; wbMODT: IwbSubRecordDef; wbDMDT: IwbSubRecordDef; wbXOWN: IwbSubRecordDef; wbXRNK: IwbSubRecordDef; wbPhonemeTargets: IwbSubRecordDef; wbPHWT: IwbSubRecordStructDef; wbHeadPart: IwbSubRecordStructDef; wbQUSTAliasFlags: IwbSubRecordDef; wbPDTO: IwbSubRecordDef; wbPDTOs: IwbSubRecordArrayDef; wbUNAMs: IwbSubRecordArrayDef; wbNull: IwbValueDef; wbTimeInterpolator: IwbStructDef; wbColorInterpolator: IwbStructDef; wbYNAM: IwbSubRecordDef; wbZNAM: IwbSubRecordDef; wbSPED: IwbSubRecordDef; wbCUSD: IwbSubRecordDef; wbINRD: IwbSubRecordDef; wbPTRN: IwbSubRecordDef; wbNTRM: IwbSubRecordDef; wbPRPS: IwbSubRecordDef; wbFLTR: IwbSubRecordDef; wbAPPR: IwbSubRecordDef; wbObjectTemplate: IwbSubRecordStructDef; wbBSMPSequence: IwbSubRecordArrayDef; wbFTYP: IwbSubRecordDef; wbATTX: IwbSubRecordDef; wbMNAMFurnitureMarker: IwbSubRecordDef; wbSNAMMarkerParams: IwbSubRecordDef; wbOBTSReq: IwbSubRecordDef; //wbTintTemplateGroups: IwbSubrecordArrayDef; //wbMorphGroups: IwbSubrecordArrayDef; //wbRaceFRMI: IwbSubrecordArrayDef; wbRaceRBPC: IwbSubRecordDef; wbNVNM: IwbSubRecordDef; wbMaxHeightDataCELL: IwbSubRecordDef; wbMaxHeightDataWRLD: IwbSubRecordDef; wbOFST: IwbSubRecordDef; function Sig2Int(aSignature: TwbSignature): Cardinal; inline; begin Result := PCardinal(@aSignature)^; end; function wbEPFDActorValueToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var AsCardinal : Cardinal; AsFloat : Single; begin AsCardinal := aInt; AsFloat := PSingle(@AsCardinal)^; aInt := Round(AsFloat); case aType of ctToStr: Result := wbActorValueEnum.ToString(aInt, aElement); ctToSortKey: Result := wbActorValueEnum.ToSortKey(aInt, aElement); ctCheck: Result := wbActorValueEnum.Check(aInt, aElement); ctToEditValue: Result := wbActorValueEnum.ToEditValue(aInt, aElement); ctEditType: Result := 'ComboBox'; ctEditInfo: Result := wbActorValueEnum.EditInfo[aInt, aElement]; end; end; function wbEPFDActorValueToInt(const aString: string; const aElement: IwbElement): Int64; var AsCardinal : Cardinal; AsFloat : Single; begin AsFloat := wbActorValueEnum.FromEditValue(aString, aElement); PSingle(@AsCardinal)^ := AsFloat; Result := AsCardinal; end; function wbCTDAParam2QuestStageToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainerElementRef; Param1 : IwbElement; MainRecord : IwbMainRecord; EditInfos : TStringList; Stages : IwbContainerElementRef; Stage : IwbContainerElementRef; i, j : Integer; s, t : string; begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctToEditValue: Result := IntToStr(aInt); ctToSortKey: begin Result := IntToHex64(aInt, 8); Exit; end; ctCheck: Result := ''; ctEditType: Result := ''; ctEditInfo: Result := ''; end; if not Assigned(aElement) then Exit; Container := GetContainerRefFromUnionOrValue(aElement); if not Assigned(Container) then Exit; Param1 := Container.ElementByName['Parameter #1']; if not Assigned(Param1) then Exit; if not Supports(Param1.LinksTo, IwbMainRecord, MainRecord) then Exit; // get winning quest override except for partial forms if MainRecord.WinningOverride.Flags._Flags and $00004000 = 0 then MainRecord := MainRecord.WinningOverride else if MainRecord.Flags._Flags and $00004000 <> 0 then MainRecord := MainRecord.MasterOrSelf; if MainRecord.Signature <> QUST then begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end; Exit; end; case aType of ctEditType: begin Result := 'ComboBox'; Exit; end; ctEditInfo: EditInfos := TStringList.Create; else EditInfos := nil; end; try if Supports(MainRecord.ElementByName['Stages'], IwbContainerElementRef, Stages) then begin for i := 0 to Pred(Stages.ElementCount) do if Supports(Stages.Elements[i], IwbContainerElementRef, Stage) then begin j := Stage.ElementNativeValues['INDX\Stage Index']; s := Trim(Stage.ElementValues['Log Entries\Log Entry\CNAM']); t := IntToStr(j); while Length(t) < 3 do t := '0' + t; if s <> '' then t := t + ' ' + s; if Assigned(EditInfos) then EditInfos.AddObject(t, TObject(j)) else if j = aInt then begin case aType of ctToStr, ctToEditValue: Result := t; ctCheck: Result := ''; end; Exit; end; end; end; case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; ctEditInfo: begin EditInfos.Sort; Result := EditInfos.CommaText; end; end; finally FreeAndNil(EditInfos); end; end; function wbPerkDATAQuestStageToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainerElementRef; Param1 : IwbElement; MainRecord : IwbMainRecord; EditInfos : TStringList; Stages : IwbContainerElementRef; Stage : IwbContainerElementRef; i, j : Integer; s, t : string; begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctToEditValue: Result := IntToStr(aInt); ctToSortKey: begin Result := IntToHex64(aInt, 8); Exit; end; ctCheck: Result := ''; ctEditType: Result := ''; ctEditInfo: Result := ''; end; if not Assigned(aElement) then Exit; Container := GetContainerRefFromUnionOrValue(aElement); if not Assigned(Container) then Exit; Param1 := Container.ElementByName['Quest']; if not Assigned(Param1) then Exit; if not Supports(Param1.LinksTo, IwbMainRecord, MainRecord) then Exit; // get winning quest override except for partial forms if MainRecord.WinningOverride.Flags._Flags and $00004000 = 0 then MainRecord := MainRecord.WinningOverride else if MainRecord.Flags._Flags and $00004000 <> 0 then MainRecord := MainRecord.MasterOrSelf; if MainRecord.Signature <> QUST then begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end; Exit; end; case aType of ctEditType: begin Result := 'ComboBox'; Exit; end; ctEditInfo: EditInfos := TStringList.Create; else EditInfos := nil; end; try if Supports(MainRecord.ElementByName['Stages'], IwbContainerElementRef, Stages) then begin for i := 0 to Pred(Stages.ElementCount) do if Supports(Stages.Elements[i], IwbContainerElementRef, Stage) then begin j := Stage.ElementNativeValues['INDX\Stage Index']; s := Trim(Stage.ElementValues['Log Entries\Log Entry\CNAM']); t := IntToStr(j); while Length(t) < 3 do t := '0' + t; if s <> '' then t := t + ' ' + s; if Assigned(EditInfos) then EditInfos.AddObject(t, TObject(j)) else if j = aInt then begin case aType of ctToStr, ctToEditValue: Result := t; ctCheck: Result := ''; end; Exit; end; end; end; case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; ctEditInfo: begin EditInfos.Sort; Result := EditInfos.CommaText; end; end; finally FreeAndNil(EditInfos); end; end; function wbCTDAParam2QuestStageToInt(const aString: string; const aElement: IwbElement): Int64; var i : Integer; s : string; begin i := 1; s := Trim(aString); while (i <= Length(s)) and (s[i] in ['0'..'9']) do Inc(i); s := Copy(s, 1, Pred(i)); Result := StrToInt(s); end; function wbREFRNavmeshTriangleToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainerElementRef; Navmesh : IwbElement; MainRecord : IwbMainRecord; Triangles : IwbContainerElementRef; begin case aType of ctToStr: Result := IntToStr(aInt); ctToEditValue: Result := IntToStr(aInt); ctToSortKey: begin Result := IntToHex64(aInt, 8); Exit; end; ctCheck: Result := ''; ctEditType: Result := ''; ctEditInfo: Result := ''; end; if not Assigned(aElement) then Exit; Container := GetContainerRefFromUnionOrValue(aElement); if not Assigned(Container) then Exit; Navmesh := Container.Elements[0]; if not Assigned(Navmesh) then Exit; if not Supports(Navmesh.LinksTo, IwbMainRecord, MainRecord) then Exit; MainRecord := MainRecord.WinningOverride; if MainRecord.Signature <> NAVM then begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end; Exit; end; if Supports(MainRecord.ElementByPath['NVNM\Triangles'], IwbContainerElementRef, Triangles) and (aType = ctCheck) then if aInt >= Triangles.ElementCount then Result := ''; end; function wbStringToInt(const aString: string; const aElement: IwbElement): Int64; begin Result := StrToIntDef(aString, 0); end; { Alias to string conversion, requires quest reference or quest record specific to record that references alias } function wbAliasToStr(aInt: Int64; const aQuestRef: IwbElement; aType: TwbCallbackType): string; var MainRecord : IwbMainRecord; EditInfos : TStringList; Aliases : IwbContainerElementRef; Alias : IwbContainerElementRef; i, j : Integer; s, t : string; begin case aType of ctToStr: if aInt = -1 then Result := 'None' else if aInt = -2 then Result := 'Player' else Result := IntToStr(aInt) + ' '; ctToEditValue: if aInt = -1 then Result := 'None' else Result := IntToStr(aInt); ctToSortKey: begin Result := IntToHex64(aInt, 8); Exit; end; ctCheck: if (aInt = -1) or (aInt = -2) then Result := '' else Result := ''; ctEditType: Result := ''; ctEditInfo: Result := ''; end; if ((aInt = -1) or (aInt = -2)) and (aType <> ctEditType) and (aType <> ctEditInfo) then Exit; if not Assigned(aQuestRef) then Exit; // aQuestRef can be a QUST record or reference to QUST record if not Supports(aQuestRef, IwbMainRecord, MainRecord) then if not Supports(aQuestRef.LinksTo, IwbMainRecord, MainRecord) then Exit; // get winning quest override except for partial forms if MainRecord.WinningOverride.Flags._Flags and $00004000 = 0 then MainRecord := MainRecord.WinningOverride else if MainRecord.Flags._Flags and $00004000 <> 0 then MainRecord := MainRecord.MasterOrSelf; if MainRecord.Signature <> QUST then begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end; Exit; end; case aType of ctEditType: begin Result := 'ComboBox'; Exit; end; ctEditInfo: begin EditInfos := TStringList.Create; end; else EditInfos := nil; end; try if Supports(MainRecord.ElementByName['Aliases'], IwbContainerElementRef, Aliases) then begin for i := 0 to Pred(Aliases.ElementCount) do if Supports(Aliases.Elements[i], IwbContainerElementRef, Alias) then begin // skip alias collection if Assigned(Alias.ElementBySignature['ALCS']) then Continue; j := Alias.Elements[0].NativeValue; s := Alias.ElementEditValues['ALID']; t := IntToStr(j); while Length(t) < 3 do t := '0' + t; if s <> '' then t := t + ' ' + s; if Assigned(EditInfos) then EditInfos.Add(t) else if j = aInt then begin case aType of ctToStr, ctToEditValue: Result := t; ctCheck: Result := ''; end; Exit; end; end; end; case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; ctEditInfo: begin EditInfos.Add('None'); EditInfos.Sort; Result := EditInfos.CommaText; end; end; finally FreeAndNil(EditInfos); end; end; function wbStrToAlias(const aString: string; const aElement: IwbElement): Int64; var i : Integer; s : string; begin Result := -1; if aString = 'None' then Exit else if aString = 'Player' then begin Result := -2; Exit; end; i := 1; s := Trim(aString); while (i <= Length(s)) and (s[i] in ['-', '0'..'9']) do Inc(i); s := Copy(s, 1, Pred(i)); Result := StrToIntDef(s, -1); end; function wbScriptObjectAliasToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainerElementRef; begin if not wbResolveAlias then begin case aType of ctToStr, ctToEditValue: Result := IntToStr(aInt); ctToSortKey: Result := IntToHex64(aInt, 8); else Result := ''; end; Exit; end; if not Assigned(aElement) then Exit; Container := GetContainerRefFromUnionOrValue(aElement); if not Assigned(Container) then Exit; Result := wbAliasToStr(aInt, Container.ElementByName['FormID'], aType); end; function wbPackageLocationAliasToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainer; begin if not wbResolveAlias then begin case aType of ctToStr, ctToEditValue: Result := IntToStr(aInt); ctToSortKey: Result := IntToHex64(aInt, 8); else Result := ''; end; Exit; end; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; while Assigned(Container) and (Container.ElementType <> etMainRecord) do Container := Container.Container; if not Assigned(Container) then Exit; Result := wbAliasToStr(aInt, Container.ElementBySignature['QNAM'], aType); end; function wbQuestAliasToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainer; begin if not wbResolveAlias then begin case aType of ctToStr, ctToEditValue: Result := IntToStr(aInt); ctToSortKey: Result := IntToHex64(aInt, 8); else Result := ''; end; Exit; end; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; while Assigned(Container) and (Container.ElementType <> etMainRecord) do Container := Container.Container; if not Assigned(Container) then Exit; Result := wbAliasToStr(aInt, Container, aType); end; function wbQuestExternalAliasToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainer; begin if not wbResolveAlias then begin case aType of ctToStr, ctToEditValue: Result := IntToStr(aInt); ctToSortKey: Result := IntToHex64(aInt, 8); else Result := ''; end; Exit; end; if not Assigned(aElement) then Exit; Container := aElement.Container; if not Assigned(Container) then Exit; Result := wbAliasToStr(aInt, Container.ElementBySignature['ALEQ'] , aType); end; function wbConditionAliasToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainer; MainRecord : IwbMainRecord; GroupRecord : IwbGroupRecord; begin if not wbResolveAlias then begin case aType of ctToStr, ctToEditValue: Result := IntToStr(aInt); ctToSortKey: Result := IntToHex64(aInt, 8); else Result := ''; end; Exit; end; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; while Assigned(Container) and (Container.ElementType <> etMainRecord) do Container := Container.Container; if not Assigned(Container) then Exit; if not Supports(Container, IwbMainRecord, MainRecord) then Exit; if MainRecord.Signature = QUST then Result := wbAliasToStr(aInt, Container, aType) else if MainRecord.Signature = SCEN then Result := wbAliasToStr(aInt, Container.ElementBySignature['PNAM'], aType) else if MainRecord.Signature = PACK then Result := wbAliasToStr(aInt, Container.ElementBySignature['QNAM'], aType) else if MainRecord.Signature = INFO then begin // get DIAL for INFO if Supports(MainRecord.Container, IwbGroupRecord, GroupRecord) then if Supports(GroupRecord.ChildrenOf, IwbMainRecord, MainRecord) then Result := wbAliasToStr(aInt, MainRecord.ElementBySignature['QNAM'], aType); end else // this should never be called since aliases in conditions can be in the forms above only // but just in case case aType of ctToStr, ctToEditValue: Result := IntToStr(aInt); ctToSortKey: Result := IntToHex64(aInt, 8); else Result := ''; end; end; function wbClmtMoonsPhaseLength(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var PhaseLength : Byte; Masser : Boolean; Secunda : Boolean; begin Result := ''; if aType = ctToSortKey then begin Result := IntToHex64(aInt, 2); end else if aType = ctToStr then begin PhaseLength := aInt mod 64; Masser := (aInt and 64) <> 0; Secunda := (aInt and 128) <> 0; if Masser then if Secunda then Result := 'Masser, Secunda / ' else Result := 'Masser / ' else if Secunda then Result := 'Secunda / ' else Result := 'No Moon / '; Result := Result + IntToStr(PhaseLength); end; end; function wbClmtTime(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; begin if aType = ctToSortKey then Result := IntToHex64(aInt, 4) else if aType = ctToStr then Result := TimeToStr( EncodeTime(aInt div 6, (aInt mod 6) * 10, 0, 0) ) else Result := ''; end; var wbCtdaTypeFlags : IwbFlagsDef; function wbCtdaTypeToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var s: string; begin Result := ''; if not Assigned(wbCtdaTypeFlags) then wbCtdaTypeFlags := wbFlags([ {0x01} 'Or', {0x02} 'Use aliases', {0x04} 'Use global', {0x08} 'Use packdata', {0x10} 'Swap Subject and Target' ]); { Compare operator (upper 3 bits) LGE 000 0=Equal to 001 1=Not equal to 010 2=Greater than 011 3=Greater than or equal to 100 4=Less than 101 5=Less than or equal to Flags (lower 5 bits) 0x01=OR (default is to AND conditions together) 0x02=Parameters (use aliases) : Force function parameters to use quest alias data (exclusive with "use pack data") 0x04=Use global 0x08=Use Pack Data : Force function parameters to use pack data (exclusive with "use aliases") 0x10=Swap Subject and Target } case aType of ctEditType: Result := 'CheckComboBox'; ctEditInfo: Result := 'Equal,Greater,Lesser,Or,"Use Aliases","Use Global","Use Packdata","Swap Subject and Target"'; ctToEditValue: begin Result := '00000000'; case aInt and $E0 of $00 : Result[1] := '1'; $40 : Result[2] := '1'; $60 : begin Result[1] := '1'; Result[2] := '1'; end; $80 : Result[3] := '1'; $A0 : begin Result[1] := '1'; Result[3] := '1'; end; end; if (aInt and $01) <> 0 then // Or Result[4] := '1'; if (aInt and $02) <> 0 then // Use aliases Result[5] := '1'; if (aInt and $04) <> 0 then // Use global Result[6] := '1'; if (aInt and $08) <> 0 then // Use packdata Result[7] := '1'; if (aInt and $10) <> 0 then // Swap Subject and Target Result[8] := '1'; end; ctToStr: begin case aInt and $E0 of $00 : Result := 'Equal to'; $20 : Result := 'Not equal to'; $40 : Result := 'Greater than'; $60 : Result := 'Greater than or equal to'; $80 : Result := 'Less than'; $A0 : Result := 'Less than or equal to'; else Result := '' end; s := wbCtdaTypeFlags.ToString(aInt and $1F, aElement); if s <> '' then Result := Result + ' / ' + s; end; ctToSortKey: begin Result := IntToHex64(aInt, 2); Exit; end; ctCheck: begin case aInt and $E0 of $00, $20, $40, $60, $80, $A0 : Result := ''; else Result := '' end; s := wbCtdaTypeFlags.Check(aInt and $1F, aElement); if s <> '' then Result := Result + ' / ' + s; end; end; end; function wbCtdaTypeToInt(const aString: string; const aElement: IwbElement): Int64; var s: string; begin s := aString + '00000000'; if s[1] = '1' then begin if s[2] = '1' then begin if s[3] = '1' then begin Result := $00; end else begin Result := $60; end; end else begin if s[3] = '1' then begin Result := $A0; end else begin Result := $00; end; end; end else begin if s[2] = '1' then begin if s[3] = '1' then begin Result := $20; end else begin Result := $40; end; end else begin if s[3] = '1' then begin Result := $80; end else begin Result := $20; end; end; end; // Or if s[4] = '1' then Result := Result or $01; // Use aliases if s[5] = '1' then Result := Result or $02; // Use global if s[6] = '1' then Result := Result or $04; // Use packdata if s[7] = '1' then Result := Result or $08; // Swap Subject and Target if s[8] = '1' then Result := Result or $10; end; var wbEventFunctionAndMemberEditInfo: string; function wbEventFunctionAndMemberToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var EventFunction, EventMember: Integer; i, j: Integer; s1, s2: string; slMember: TStringList; begin Result := ''; EventFunction := aInt and $FFFF; EventMember := aInt shr 16; case aType of ctToStr, ctToEditValue: begin Result := wbEventFunctionEnum.ToEditValue(EventFunction, nil); Result := Result + ':' + wbEventMemberEnum.ToEditValue(EventMember, nil); end; ctToSortKey: Result := IntToHex(aInt, 8); ctCheck: begin s1 := wbEventFunctionEnum.Check(EventFunction, nil); if s1 <> '' then s1 := 'EventFunction' + s1; s2 := wbEventMemberEnum.Check(EventMember, nil); if s2 <> '' then s2 := 'EventMember' + s2; if (s1 <> '') or (s2 <> '') then Result := s1 + ':' + s2; end; ctEditType: Result := 'ComboBox'; ctEditInfo: begin Result := wbEventFunctionAndMemberEditInfo; if Result = '' then try slMember := TStringList.Create; slMember.CommaText := wbEventMemberEnum.EditInfo[0, nil]; with TStringList.Create do try for i := 0 to Pred(wbEventFunctionEnum.NameCount) do for j := 0 to Pred(slMember.Count) do Add(wbEventFunctionEnum.Names[i] + ':' + slMember[j]); Sort; Result := CommaText; finally Free; end; wbEventFunctionAndMemberEditInfo := Result; finally FreeAndNil(slMember); end end; end; end; function wbEventFunctionAndMemberToInt(const aString: string; const aElement: IwbElement): Int64; var EventFunction, EventMember, i: Integer; begin i := Pos(':', aString); if i > 0 then begin EventFunction := wbEventFunctionEnum.FromEditValue(Copy(aString, 1, i-1), nil); EventMember := wbEventMemberEnum.FromEditValue(Copy(aString, i+1, Length(aString)), nil); end else begin EventFunction := 0; EventMember := 0; end; Result := EventMember shl 16 + EventFunction; end; procedure wbMESGDNAMAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var OldValue, NewValue : Integer; Container : IwbContainerElementRef; begin if VarSameValue(aOldValue, aNewValue) then Exit; if Supports(aElement.Container, IwbContainerElementRef, Container) then begin OldValue := Integer(aOldValue) and 1; NewValue := Integer(aNewValue) and 1; if NewValue = OldValue then Exit; if NewValue = 1 then Container.RemoveElement('TNAM') else Container.Add('TNAM', True); end; end; procedure wbGMSTEDIDAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var OldValue, NewValue : string; Container : IwbContainerElementRef; begin if VarSameValue(aOldValue, aNewValue) then Exit; if Supports(aElement.Container, IwbContainerElementRef, Container) then begin OldValue := aOldValue; NewValue := aNewValue; if (Length(OldValue) < 1) or (Length(OldValue) < 1) or (OldValue[1] <> NewValue[1]) then begin Container.RemoveElement('DATA'); Container.Add('DATA', True); end; end; end; procedure wbFLSTEDIDAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var OldValue, NewValue : string; OldOrdered, NewOrdered : Boolean; Container : IwbContainerElementRef; const OrderedList = 'OrderedList'; begin if VarSameValue(aOldValue, aNewValue) then Exit; if Supports(aElement.Container, IwbContainerElementRef, Container) then begin OldValue := aOldValue; NewValue := aNewValue; if Length(OldValue) > Length(OrderedList) then Delete(OldValue, 1, Length(OldValue)-Length(OrderedList)); if Length(NewValue) > Length(OrderedList) then Delete(NewValue, 1, Length(NewValue)-Length(OrderedList)); OldOrdered := SameText(OldValue, OrderedList); NewOrdered := SameText(NewValue, OrderedList); if OldOrdered <> NewOrdered then Container.RemoveElement('FormIDs'); end; end; procedure wbCtdaTypeAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var OldValue, NewValue: Integer; Container: IwbContainerElementRef; begin if VarSameValue(aOldValue, aNewValue) then Exit; if not Supports(aElement, IwbContainerElementRef, Container) then Exit; // reset value if "use global" has changed OldValue := aOldValue and $04; NewValue := aNewValue and $04; if OldValue <> NewValue then Container.ElementNativeValues['..\Comparison Value'] := 0; {>>> "run on target", no such flag in Skyrim <<<} // if aNewValue and $02 then begin // Container.ElementNativeValues['..\Run On'] := 1; // if Integer(Container.ElementNativeValues['..\Run On']) = 1 then // aElement.NativeValue := Byte(aNewValue) and not $02; // end; end; procedure wbAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin Exit; end; function wbMODTCallback(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Strings: TDynStrings; i: Integer; begin Result := ''; if wbLoaderDone and (aType in [ctToStr, ctToSortKey] ) then begin Strings := wbContainerHandler.ResolveHash(aInt); for i := Low(Strings) to High(Strings) do Result := Result + Strings[i] + ', '; SetLength(Result, Length(Result) -2 ); end; end; {>>> Needs revision for Skyrim <<<} //function wbIdleAnam(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; //begin // Result := ''; // case aType of // ctToStr: begin // case aInt and not $C0 of // 0: Result := 'Idle'; // 1: Result := 'Movement'; // 2: Result := 'Left Arm'; // 3: Result := 'Left Hand'; // 4: Result := 'Weapon'; // 5: Result := 'Weapon Up'; // 6: Result := 'Weapon Down'; // 7: Result := 'Special Idle'; // 20: Result := 'Whole Body'; // 21: Result := 'Upper Body'; // else // Result := ''; // end; // // if (aInt and $80) = 0 then // Result := Result + ', Must return a file'; // if (aInt and $40) = 1 then // Result := Result + ', Unknown Flag'; // end; // ctToSortKey: begin // Result := IntToHex64(aInt, 2); // end; // ctCheck: begin // case aInt and not $C0 of // 0..7, 20, 21: Result := ''; // else // Result := ''; // end; // end; // end; //end; function wbScaledInt4ToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; const PlusMinus : array[Boolean] of string = ('+', '-'); begin Result := ''; case aType of ctToStr, ctToEditValue: Result := FloatToStrF(aInt / 10000, ffFixed, 99, 4); ctToSortKey: begin Result := FloatToStrF(aInt / 10000, ffFixed, 99, 4); if Length(Result) < 22 then Result := StringOfChar('0', 22 - Length(Result)) + Result; Result := PlusMinus[aInt < 0] + Result; end; ctCheck: Result := ''; end; end; function wbScaledInt4ToInt(const aString: string; const aElement: IwbElement): Int64; var f: Extended; begin f := StrToFloat(aString); f := f * 10000; Result := Round(f); end; function wbCloudSpeedToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; begin Result := ''; case aType of ctToStr, ctToEditValue: Result := FloatToStrF((aInt - 127)/127/10, ffFixed, 99, 4); ctCheck: Result := ''; end; end; function wbCloudSpeedToInt(const aString: string; const aElement: IwbElement): Int64; var f: Extended; begin f := StrToFloat(aString); f := f*10*127 + 127; Result := Min(Round(f), 254); end; function wbShortXYtoStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var x, y: SmallInt; begin y := aInt and $FFFF; x := aInt shr 16 and $FFFF; Result := ''; case aType of ctToStr, ctToEditValue: Result := Format('%d, %d', [x, y]); ctCheck: Result := ''; end; end; function wbStrToShortXY(const aString: string; const aElement: IwbElement): Int64; var x, y: SmallInt; Value: Cardinal; begin y := StrToIntDef(Copy(aString, 1, Pred(Pos(', ', aString))), 0); x := StrToIntDef(Copy(aString, Pos(', ', aString) + 2, Length(aString)), 0); PWord(@Value)^ := x; PWord(Cardinal(@Value) + SizeOf(SmallInt))^ := y; Result := Value; end; function wbHideFFFF(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; begin Result := ''; if aType = ctToSortKey then Result := IntToHex64(aInt, 4) else if aType = ctToStr then if aInt = $FFFF then Result := 'None' else Result := IntToStr(aInt); end; function wbAtxtPosition(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; begin Result := ''; if aType = ctToSortKey then Result := IntToHex64(aInt div 17, 2) + IntToHex64(aInt mod 17, 2) else if aType = ctCheck then begin if (aInt < 0) or (aInt > 288) then Result := '' else Result := ''; end else if aType = ctToStr then Result := IntToStr(aInt) + ' -> ' + IntToStr(aInt div 17) + ':' + IntToStr(aInt mod 17); end; function wbPlacedAddInfo(const aMainRecord: IwbMainRecord): string; var Rec: IwbRecord; Container: IwbContainer; s: string; Cell: IwbMainRecord; Position: TwbVector; Grid: TwbGridCell; begin Result := ''; Rec := aMainRecord.RecordBySignature['NAME']; if Assigned(Rec) then begin s := Trim(Rec.Value); if s <> '' then Result := 'places ' + s; end; Container := aMainRecord.Container; while Assigned(Container) and (Container.ElementType <> etGroupRecord) do Container := Container.Container; if Assigned(Container) then begin s := Trim(Container.Name); if s <> '' then begin if Result <> '' then Result := Result + ' '; Result := Result + 'in ' + s; // grid position of persistent reference in exterior persistent cell (interior cells are not persistent) if Supports(aMainRecord.Container, IwbGroupRecord, Container) then Cell := IwbGroupRecord(Container).ChildrenOf; if Assigned(Cell) and Cell.IsPersistent and (Cell.Signature = 'CELL') then if aMainRecord.GetPosition(Position) then begin Grid := wbPositionToGridCell(Position); Result := Result + ' at ' + IntToStr(Grid.x) + ',' + IntToStr(Grid.y); end; // in precombined mesh if aMainRecord.HasPrecombinedMesh then Result := Result + ' in ' + aMainRecord.PrecombinedMesh; end; end; end; function wbINFOAddInfo(const aMainRecord: IwbMainRecord): string; var Container: IwbContainer; s: string; begin Result := Trim(aMainRecord.ElementValues['Responses\Response\NAM1']); if Result <> '' then Result := '''' + Result + ''''; Container := aMainRecord.Container; while Assigned(Container) and (Container.ElementType <> etGroupRecord) do Container := Container.Container; if Assigned(Container) then begin s := Trim(Container.Name); if s <> '' then begin if Result <> '' then Result := Result + ' '; Result := Result + 'in ' + s; end; end; s := Trim(aMainRecord.ElementValues['QNAM']); if s <> '' then begin if Result <> '' then Result := Result + ' '; Result := Result + 'for ' + s; end; end; function wbNAVMAddInfo(const aMainRecord: IwbMainRecord): string; var Container: IwbContainer; s: string; begin Result := ''; Container := aMainRecord.Container; while Assigned(Container) and (Container.ElementType <> etGroupRecord) do Container := Container.Container; if Assigned(Container) then begin s := Trim(Container.Name); if s <> '' then begin if Result <> '' then Result := Result + ' '; Result := Result + 'in ' + s; end; end; end; //function wbNAVMAddInfo(const aMainRecord: IwbMainRecord): string; //var // Rec : IwbRecord; // Element : IwbElement; // s : string; //begin // Result := ''; // // Rec := aMainRecord.RecordBySignature['DATA']; // if Assigned(Rec) then begin // Element := Rec.ElementByName['Cell']; // if Assigned(Element) then // Element := Element.LinksTo; // if Assigned(Element) then // s := Trim(Element.Name); // if s <> '' then // Result := 'for ' + s; // end; //end; function wbCellAddInfo(const aMainRecord: IwbMainRecord): string; var Rec: IwbRecord; Container: IwbContainer; GroupRecord : IwbGroupRecord; s: string; begin Result := ''; if not aMainRecord.IsPersistent then begin Rec := aMainRecord.RecordBySignature['XCLC']; if Assigned(Rec) then Result := 'at ' + Rec.Elements[0].Value + ',' + Rec.Elements[1].Value; end; Container := aMainRecord.Container; while Assigned(Container) and not (Supports(Container, IwbGroupRecord, GroupRecord) and (GroupRecord.GroupType = 1)) do Container := Container.Container; if Assigned(Container) then begin s := wbFormID.ToString(GroupRecord.GroupLabel, aMainRecord); if s <> '' then begin if Result <> '' then s := s + ' '; Result := 'in ' + s + Result; end; end; end; procedure wbCTDARunOnAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin if aOldValue <> aNewValue then if aNewValue <> 2 then aElement.Container.ElementNativeValues['Reference'] := 0; end; {>>> Needs revision for Skyrim <<<} procedure wbPERKPRKETypeAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var Container : IwbContainerElementRef; // rDATA : IwbRecord; begin if aOldValue <> aNewValue then if Supports(aElement.Container, IwbContainerElementRef, Container) then begin if Supports(Container.Container, IwbContainerElementRef, Container) then begin Container.RemoveElement('DATA'); Container.Add('DATA', True); Container.RemoveElement('Perk Conditions'); Container.RemoveElement('Entry Point Function Parameters'); if aNewValue = 2 then begin Container.Add('EPFT', True); Container.ElementNativeValues['DATA\Entry Point\Function'] := 2; end; end; end; end; function wbNPCLevelDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container: IwbContainer; i: Int64; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; i := Container.ElementByName['Flags'].NativeValue; if i and $00000080 <> 0 then Result := 1; end; function wbMGEFAssocItemDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; Archtype : Variant; DataContainer : IwbDataContainer; Element : IwbElement; const OffsetArchtype = 56; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; VarClear(ArchType); Element := Container.ElementByName['Archetype']; if Assigned(Element) then ArchType := Element.NativeValue else if Supports(Container, IwbDataContainer, DataContainer) and DataContainer.IsValidOffset(aBasePtr, aEndPtr, OffsetArchtype) then begin // we are part a proper structure aBasePtr := Pointer(Cardinal(aBasePtr) + OffsetArchtype); ArchType := PCardinal(aBasePtr)^; end; if not VarIsEmpty(ArchType) then case Integer(ArchType) of 12: Result := 1; // Light 17: Result := 2; // Bound Item 18: Result := 3; // Summon Creature 25: Result := 4; // Guide 34: Result := 8; // Peak Mod 35: Result := 5; // Cloak 36: Result := 6; // Werewolf 39: Result := 7; // Enhance Weapon 40: Result := 4; // Spawn Hazard 46: Result := 6; // Vampire Lord end; end; procedure wbMGEFAssocItemAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var Container : IwbContainer; Element : IwbElement; begin if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; if (aNewValue <> 0) then begin Element := Container.ElementByName['Archetype']; if Assigned(Element) and (Element.NativeValue = 0) then Element.NativeValue := $FF; // Signals ArchType that it should not mess with us on the next change! // I assume this will alo protect Second AV Weight (The two actor values are after ArchType) end; end; procedure wbMGEFAV2WeightAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var Container : IwbContainer; Element : IwbElement; begin if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; if (aNewValue <> 0.0) then begin Element := Container.ElementByName['Archetype']; if Assigned(Element) and (Element.NativeValue = 0) then Element.NativeValue := $FF; // Signals ArchType that it should not mess with us on the next change! end; end; procedure wbMGEFArchtypeAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var Container: IwbContainerElementRef; begin if VarSameValue(aOldValue, aNewValue) then Exit; if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if (aNewValue < $FF) and (aOldValue < $FF) then begin Container.ElementNativeValues['..\Assoc. Item'] := 0; case Integer(aNewValue) of 06: Container.ElementNativeValues['..\Actor Value'] := 00;//Agression 07: Container.ElementNativeValues['..\Actor Value'] := 01;//Confidence 08: Container.ElementNativeValues['..\Actor Value'] := 00;//Agression 11: Container.ElementNativeValues['..\Actor Value'] := 54;//Invisibility 21: Container.ElementNativeValues['..\Actor Value'] := 53;//Paralysis 24: Container.ElementNativeValues['..\Actor Value'] := 01;//Confidence 38: Container.ElementNativeValues['..\Actor Value'] := 01;//Confidence 42: Container.ElementNativeValues['..\Actor Value'] := 01;//Confidence else Container.ElementNativeValues['..\Actor Value'] := -1; end; Container.ElementNativeValues['..\Second Actor Value'] := -1; Container.ElementNativeValues['..\Second AV Weight'] := 0.0; end; end; function wbCTDAReferenceDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; if Integer(Container.ElementNativeValues['Run On']) = 2 then Result := 1; end; function wbNAVIIslandDataDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; SubRecord : IwbMainRecord; Element : IwbElement; begin Result := 0; Container := aElement.Container; while Assigned(Container) and (Container.ElementType <> etSubRecord) do Container := Container.Container; if not Supports(Container, IwbSubRecord, SubRecord) then Exit; Element := SubRecord.ElementByName['Is Island']; if not Assigned(Element) then Exit; Result := Element.NativeValue; end; function wbNAVIParentDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; SubRecord : IwbMainRecord; Element : IwbElement; begin Result := 0; Container := aElement.Container; while Assigned(Container) and (Container.ElementType <> etsubRecord) do Container := Container.Container; if not Supports(Container, IwbSubRecord, SubRecord) then Exit; Element := SubRecord.ElementByName['Parent Worldspace']; if not Assigned(Element) then Exit; if (Element.NativeValue = 0) then Result := 1; end; function wbNVNMParentDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; Parent : IwbElement; i : integer; begin // Could be simplified by checking if Parent Worldspace is NULL, that's what the runtime does :) Result := 0; Container := aElement.Container; Parent := Container.ElementByName['Parent Worldspace']; if not Assigned(Parent) then Exit; i := Parent.NativeValue; // is interior cell? if i = 0 then Result := 1; end; function wbDoorTriangleDoorTriangleDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; Parent : IwbElement; i : int64; begin Result := 0; Container := aElement.Container; Parent := Container.ElementByName['DTUnknown']; if not Assigned(Parent) then Exit; i := Parent.NativeValue; // not sure if it would be an error in the file or if it really possible if i <> 0 then Result := 1; end; function wbSubrecordSizeDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var SubRecord : IwbSubRecord; begin Result := 0; if not Assigned(aElement) then Exit; if Supports(aElement, IwbSubRecord, SubRecord) then if SubRecord.DataSize > 0 then Result := 1; end; function wbCOEDOwnerDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; LinksTo : IwbElement; MainRecord : IwbMainRecord; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; LinksTo := Container.ElementByName['Owner'].LinksTo; if Supports(LinksTo, IwbMainRecord, MainRecord) then if MainRecord.Signature = 'NPC_' then Result := 1 else if MainRecord.Signature = 'FACT' then Result := 2; end; function wbGMSTUnionDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var rEDID: IwbRecord; s: string; begin Result := 1; rEDID := aElement.Container.RecordBySignature[EDID]; if Assigned(rEDID) then begin s := rEDID.Value; if Length(s) > 0 then case s[1] of 's': Result := 0; {String} {>>> Localization Strings <<<} 'i': Result := 1; {intS32} 'f': Result := 2; {Float} 'b': Result := 3; {Boolean} end; end; end; function wbFLSTLNAMIsSorted(const aContainer: IwbContainer): Boolean; var rEDID : IwbRecord; s : string; const OrderedList = 'OrderedList'; begin Result := False; {>>> Should not be sorted according to Arthmoor and JustinOther <<<} rEDID := aContainer.RecordBySignature[EDID]; if Assigned(rEDID) then begin s := rEDID.Value; if Length(s) > Length(OrderedList) then Delete(s, 1, Length(s)-Length(OrderedList)); if SameText(s, OrderedList) then Result := False; end; end; function wbPerkDATADecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var rPRKE: IwbRecord; eType: IwbElement; begin Result := 0; rPRKE := aElement.Container.RecordBySignature[PRKE]; if Assigned(rPRKE) then begin eType := rPRKE.ElementByName['Type']; if Assigned(eType) then begin Result := eType.NativeValue; end; end; end; function wbEPFDDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container: IwbContainerElementRef; begin Result := 0; if not Assigned(aElement) then Exit; if not Supports(aElement.Container, IwbContainerElementRef, Container) then Exit; Result := Container.ElementNativeValues['EPFT']; if Result = 2 then case Integer(Container.ElementNativeValues['..\DATA\Entry Point\Function']) of 5, 12, 13, 14: Result := 8; end; end; function wbSceneActionSoundDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container: IwbContainerElementRef; begin Result := 0; if not Assigned(aElement) then Exit; if not Supports(aElement.Container, IwbContainerElementRef, Container) then Exit; if Container.ElementNativeValues['ANAM'] <> 4 then Result := 1; end; function wbEFSHFormatDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var MainRecord: IwbMainRecord; begin Result := 0; if not Assigned(aElement) then Exit; if not Supports(aElement.Container, IwbMainRecord, MainRecord) then Exit; if MainRecord.Version < 102 then Result := 1; end; function wbDeciderFormVersion99(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; begin Result := wbFormVerDecider(aBasePtr, aEndPtr, aElement, 99); end; function wbAECHDataDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; rKNAM : IwbElement; s: string; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; Container := Container.Container; if not Assigned(Container) then Exit; rKNAM := Container.ElementBySignature['KNAM']; if not Assigned(rKNAM) then Exit; s := rKNAM.EditValue; if s = 'BSOverdrive' then Result := 0 else if s = 'BSStateVariableFilter' then Result := 1 else if s = 'BSDelayEffect' then Result := 2; end; function wbCLFMColorDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; rFNAM : IwbElement; i : Integer; begin Result := 0; // resolving to a float causes data loss when copying // since deciding field FNAM comes after a value CNAM Exit; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; Container := Container.Container; if not Assigned(Container) then Exit; rFNAM := Container.ElementBySignature['FNAM']; if not Assigned(rFNAM) then Exit; i := rFNAM.NativeValue; if i and 2 <> 0 then Result := 1; end; function wbCLFMColorToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainer; rFNAM : IwbElement; i : Integer; s : string; begin i := 0; Container := aElement.Container; if Assigned(Container) then begin rFNAM := Container.ElementBySignature['FNAM']; if Assigned(rFNAM) then i := rFNAM.NativeValue; end; if i and 2 <> 0 then s := FloatToStrF(PSingle(@aInt)^, ffFixed, 99, wbFloatDigits) else s := 'rgba(' + IntToStr(aInt and $FF) + ', ' + IntToStr(aInt shr 8 and $FF) + ', ' + IntToStr(aInt shr 16 and $FF) + ', ' + IntToStr(aInt shr 24 and $FF) + ')'; case aType of ctToStr: Result := s; ctToSortKey: Result := IntToHex(aInt, 8); ctToEditValue: Result := s; end; end; function wbCLFMColorToInt(const aString: string; const aElement: IwbElement): Int64; var s: string; value: Single; begin if SameText(Copy(aString, 1, 5), 'rgba(') then begin s := Copy(aString, 6, Pos(')', aString) - 6); with TStringList.Create do try Delimiter := ','; StrictDelimiter := True; DelimitedText := s; Result := 0; if Count = 4 then begin PByte(@Result)[0] := StrToIntDef(Strings[0], 0); PByte(@Result)[1] := StrToIntDef(Strings[1], 0); PByte(@Result)[2] := StrToIntDef(Strings[2], 0); PByte(@Result)[3] := StrToIntDef(Strings[3], 0); end; finally Free; end; end else begin try value := StrToFloat(aString) except value := 0.0 end; Result := PInteger(@value)^; end; end; function wbNOTEDataDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; rDNAM : IwbElement; i : Integer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; Container := Container.Container; if not Assigned(Container) then Exit; rDNAM := Container.ElementBySignature['DNAM']; if not Assigned(rDNAM) then Exit; i := rDNAM.NativeValue; case i of 0: Result := 1; 1: Result := 2; 3: Result := 3; end; end; function wbSNDRDataDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; rCNAM : IwbElement; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; Container := Container.Container; if not Assigned(Container) then Exit; rCNAM := Container.ElementBySignature['CNAM']; if not Assigned(rCNAM) then Exit; if rCNAM.EditValue = 'AutoWeapon' then Result := 1; end; {>>> For VMAD <<<} function wbScriptObjFormatDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var ObjFormat: Integer; Container: IwbContainer; begin Result := 0; Container := aElement.Container; while Assigned(Container) and (Container.ElementType <> etSubRecord) do Container := Container.Container; if not Assigned(Container) then Exit; ObjFormat := Container.ElementNativeValues['Object Format']; if ObjFormat = 1 then Result := 1; end; {>>> For VMAD <<<} function wbScriptPropertyDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; case Integer(Container.ElementNativeValues['Type']) of 1: Result := 1; 2: Result := 2; 3: Result := 3; 4: Result := 4; 5: Result := 5; 6: Result := 6; 7: Result := 7; 11: Result := 8; 12: Result := 9; 13: Result := 10; 14: Result := 11; 15: Result := 12; 17: Result := 13; end; end; function wbScriptPropertyStructMemberDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; case Integer(Container.ElementNativeValues['Type']) of 1: Result := 1; 2: Result := 2; 3: Result := 3; 4: Result := 4; 5: Result := 5; 11: Result := 6; 12: Result := 7; 13: Result := 8; 14: Result := 9; 15: Result := 10; end; end; procedure wbScriptPropertyTypeAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var Container : IwbContainerElementRef; begin if aOldValue <> aNewValue then if Supports(aElement.Container, IwbContainerElementRef, Container) then Container.ElementByName['Value'].SetToDefault; end; {>>> For VMAD <<<} function wbScriptFragmentsDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; MainRecord : IwbMainRecord; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; while Assigned(Container) and (Container.ElementType <> etMainRecord) do Container := Container.Container; if not Assigned(Container) then Exit; Supports(Container, IwbMainRecord, MainRecord); if MainRecord.Signature = PERK then Result := 1 else if MainRecord.Signature = TERM then Result := 1 else if MainRecord.Signature = INFO then Result := 2 else if MainRecord.Signature = PACK then Result := 3 else if MainRecord.Signature = QUST then Result := 4 else if MainRecord.Signature = SCEN then Result := 5; end; {>>> For VMAD <<<} function wbScriptFragmentsQuestCounter(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Cardinal; var Container : IwbContainer; begin Result := 0; if aElement.ElementType = etValue then Container := aElement.Container else Container := aElement as IwbContainer; if not Assigned(Container) then Exit; while Assigned(Container) and (Container.Name <> 'Script Fragments') do Container := Container.Container; if not Assigned(Container) then Exit; Result := Cardinal(Container.ElementNativeValues['fragmentCount']); end; {>>> For VMAD <<<} function wbScriptFragmentsInfoCounter(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Cardinal; var Container : IwbContainer; F : Integer; i : Integer; begin Result := 0; if aElement.ElementType = etValue then Container := aElement.Container else Container := aElement as IwbContainer; if not Assigned(Container) then Exit; while Assigned(Container) and (Container.Name <> 'Script Fragments') do Container := Container.Container; if not Assigned(Container) then Exit; F := Container.ElementByName['Flags'].NativeValue; for i := 0 to 2 do begin if (F and 1) = 1 then Inc(Result); F := F shr 1; end; for i := 3 to 7 do begin if (F and 1) = 1 then begin Inc(Result); if Assigned(wbProgressCallback) then wbProgressCallback('==='+aElement.Name+' ['+Container.Name+':'+Container.Path+'] = unknown info VMAD flag bit '+IntToStr(i)); end; F := F shr 1; end; end; {>>> For VMAD <<<} function wbScriptFragmentsSceneCounter(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Cardinal; var Container : IwbContainer; F : Integer; i : Integer; begin Result := 0; if aElement.ElementType = etValue then Container := aElement.Container else Container := aElement as IwbContainer; if not Assigned(Container) then Exit; while Assigned(Container) and (Container.Name <> 'Script Fragments') do Container := Container.Container; if not Assigned(Container) then Exit; F := Container.ElementByName['Flags'].NativeValue; for i := 0 to 2 do begin if (F and 1) = 1 then Inc(Result); F := F shr 1; end; for i := 3 to 7 do begin if (F and 1) = 1 then begin Inc(Result); if Assigned(wbProgressCallback) then wbProgressCallback('==='+aElement.Name+' ['+Container.Name+':'+Container.Path+'] = unknown scene VMAD flag bit '+IntToStr(i)); end; F := F shr 1; end; end; {>>> For VMAD <<<} function wbScriptFragmentsPackCounter(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Cardinal; var Container : IwbContainer; F : Integer; i : Integer; begin Result := 0; if aElement.ElementType = etValue then Container := aElement.Container else Container := aElement as IwbContainer; if not Assigned(Container) then Exit; while Assigned(Container) and (Container.Name <> 'Script Fragments') do Container := Container.Container; if not Assigned(Container) then Exit; F := Container.ElementByName['Flags'].NativeValue; for i := 0 to 7 do begin if (F and 1) = 1 then Inc(Result); F := F shr 1; end; end; {>>> For VMAD <<<} function wbScriptFragmentsEmptyScriptDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; if Container.ElementEditValues['scriptName'] = '' then Result := 1; end; function wbBOOKTeachesDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container: IwbContainer; i: Int64; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; i := Container.ElementByName['Flags'].NativeValue; if i and $01 <> 0 then Result := 1 else if i and $04 <> 0 then Result := 2 else if i and $10 <> 0 then Result := 3 else Result := 0; end; type TCTDAFunctionParamType = ( { 0} ptNone, { 1} ptInteger, { 2} ptFloat, { 3} ptActor, // ACHR { 4} ptActorBase, // NPC_ { 5} ptActorValue, // Enum: wbActorValue { 6} ptAdvanceAction, // ?? Enum { 7} ptAlias, // index into QUST quest aliases { 8} ptAlignment, // ?? Enum { 9} ptAssociationType, // ASTP {10} ptAxis, // ?? Char {11} ptCastingSource, // ?? Enum {12} ptCell, // CELL {13} ptClass, // CLAS {14} ptCrimeType, // ?? Enum {15} ptCriticalStage, // ?? Enum {16} ptEncounterZone, // ECZN {17} ptEquipType, // ?? Enum {18} ptEvent, // Struct {19} ptEventData, // LCTN, KYWD or FLST {20} ptFaction, // FACT {21} ptFormList, // FLST {22} ptFormType, // ?? Enum {23} ptFurniture, // FURN {24} ptFurnitureAnim, // enum {25} ptFurnitureEntry, // flags {26} ptGlobal, // GLOB {27} ptIdleForm, // IDLE {28} ptInventoryObject, // ARMO, BOOK, MISC, WEAP, AMMO, KEYM, ALCH, ARMA, LIGH, LVLI, COBJ {29} ptKeyword, // KYWD {30} ptLocation, // LCTN {31} ptMagicEffect, // MGEF {32} ptMagicItem, // SPEL {33} ptMiscStat, // ?? Enum {34} ptObjectReference, // REFR, ACHR {35} ptOwner, // FACT, NPC_ {36} ptPackage, // PACK {37} ptPackdata, // index into PACK package data inputs {38} ptPerk, // PERK {39} ptQuest, // QUST {40} ptQuestStage, // ?? Integer {41} ptRace, // RACE {42} ptReferencableObject, {43} ptRefType, // LCRT {44} ptRegion, // REGN {45} ptScene, // SCEN {46} ptSex, // Enum: Male, Female {47} ptShout, // SHOU {48} ptVariableName, // Integer {49} ptVATSValueFunction, // {50} ptVATSValueParam, {51} ptVoiceType, // VTYP {52} ptWardState, // enum {53} ptWeather, // WTHR {54} ptWorldspace, // WRLD {55} ptDamageType // DMGT ); PCTDAFunction = ^TCTDAFunction; TCTDAFunction = record Index: Integer; Name: string; ParamType1: TCTDAFunctionParamType; ParamType2: TCTDAFunctionParamType; ParamType3: TCTDAFunctionParamType; end; const wbCTDAFunctions : array[0..514] of TCTDAFunction = ( (Index: 0; Name: 'GetWantBlocking'), (Index: 1; Name: 'GetDistance'; ParamType1: ptObjectReference), (Index: 5; Name: 'GetLocked'), (Index: 6; Name: 'GetPos'; ParamType1: ptAxis), (Index: 8; Name: 'GetAngle'; ParamType1: ptAxis), (Index: 10; Name: 'GetStartingPos'; ParamType1: ptAxis), (Index: 11; Name: 'GetStartingAngle'; ParamType1: ptAxis), (Index: 12; Name: 'GetSecondsPassed'), (Index: 14; Name: 'GetValue'; ParamType1: ptActorValue), (Index: 18; Name: 'GetCurrentTime'), (Index: 24; Name: 'GetScale'), (Index: 25; Name: 'IsMoving'), (Index: 26; Name: 'IsTurning'), (Index: 27; Name: 'GetLineOfSight'; ParamType1: ptObjectReference), (Index: 31; Name: 'GetButtonPressed'), (Index: 32; Name: 'GetInSameCell'; ParamType1: ptObjectReference), (Index: 35; Name: 'GetDisabled'), (Index: 39; Name: 'GetDisease'), (Index: 41; Name: 'GetClothingValue'), (Index: 42; Name: 'SameFaction'; ParamType1: ptActor), (Index: 43; Name: 'SameRace'; ParamType1: ptActor), (Index: 44; Name: 'SameSex'; ParamType1: ptActor), (Index: 45; Name: 'GetDetected'; ParamType1: ptActor), (Index: 46; Name: 'GetDead'), (Index: 47; Name: 'GetItemCount'; ParamType1: ptReferencableObject), (Index: 48; Name: 'GetGold'), (Index: 49; Name: 'GetSleeping'), (Index: 50; Name: 'GetTalkedToPC'), (Index: 56; Name: 'GetQuestRunning'; ParamType1: ptQuest), (Index: 58; Name: 'GetStage'; ParamType1: ptQuest), (Index: 59; Name: 'GetStageDone'; ParamType1: ptQuest; ParamType2: ptQuestStage), (Index: 60; Name: 'GetFactionRankDifference'; ParamType1: ptFaction; ParamType2: ptActor), (Index: 61; Name: 'GetAlarmed'), (Index: 62; Name: 'IsRaining'), (Index: 63; Name: 'GetAttacked'), (Index: 64; Name: 'GetIsCreature'), (Index: 65; Name: 'GetLockLevel'), (Index: 66; Name: 'GetShouldAttack'; ParamType1: ptActor), (Index: 67; Name: 'GetInCell'; ParamType1: ptCell), (Index: 68; Name: 'GetIsClass'; ParamType1: ptClass), (Index: 69; Name: 'GetIsRace'; ParamType1: ptRace), (Index: 70; Name: 'GetIsSex'; ParamType1: ptSex), (Index: 71; Name: 'GetInFaction'; ParamType1: ptFaction), (Index: 72; Name: 'GetIsID'; ParamType1: ptReferencableObject), (Index: 73; Name: 'GetFactionRank'; ParamType1: ptFaction), (Index: 74; Name: 'GetGlobalValue'; ParamType1: ptGlobal), (Index: 75; Name: 'IsSnowing'), (Index: 77; Name: 'GetRandomPercent'), (Index: 79; Name: 'WouldBeStealing'; ParamType1: ptObjectReference), (Index: 80; Name: 'GetLevel'), (Index: 81; Name: 'IsRotating'), (Index: 83; Name: 'GetLeveledEncounterValue'; ParamType1: ptInteger), (Index: 84; Name: 'GetDeadCount'; ParamType1: ptActorBase), (Index: 91; Name: 'GetIsAlerted'), (Index: 99; Name: 'GetHeadingAngle'; ParamType1: ptObjectReference), (Index: 101; Name: 'IsWeaponMagicOut'), (Index: 102; Name: 'IsTorchOut'), (Index: 103; Name: 'IsShieldOut'), (Index: 105; Name: 'IsActionRef'; ParamType1: ptObjectReference), (Index: 106; Name: 'IsFacingUp'), (Index: 107; Name: 'GetKnockedState'), (Index: 108; Name: 'GetWeaponAnimType'), (Index: 109; Name: 'IsWeaponSkillType'; ParamType1: ptActorValue), (Index: 110; Name: 'GetCurrentAIPackage'), (Index: 111; Name: 'IsWaiting'), (Index: 112; Name: 'IsIdlePlaying'), (Index: 116; Name: 'IsIntimidatedbyPlayer'), (Index: 117; Name: 'IsPlayerInRegion'; ParamType1: ptRegion), (Index: 118; Name: 'GetActorAggroRadiusViolated'), (Index: 119; Name: 'GetCrimeKnown'; ParamType1: ptCrimeType; ParamType2: ptActor; ParamType3: ptActor), (Index: 122; Name: 'GetCrime'; ParamType1: ptActor; ParamType2: ptCrimeType), (Index: 123; Name: 'IsGreetingPlayer'), (Index: 125; Name: 'IsGuard'), (Index: 127; Name: 'HasBeenEaten'), (Index: 128; Name: 'GetStaminaPercentage'), (Index: 129; Name: 'HasBeenRead'), (Index: 130; Name: 'GetDying'), (Index: 131; Name: 'GetSceneActionPercent'; ParamType1: ptScene; ParamType2: ptInteger), (Index: 132; Name: 'WouldRefuseCommand'; ParamType1: ptObjectReference), (Index: 133; Name: 'SameFactionAsPC'), (Index: 134; Name: 'SameRaceAsPC'), (Index: 135; Name: 'SameSexAsPC'), (Index: 136; Name: 'GetIsReference'; ParamType1: ptObjectReference), (Index: 141; Name: 'IsTalking'), (Index: 142; Name: 'GetComponentCount'; ParamType1: ptReferencableObject), (Index: 143; Name: 'GetCurrentAIProcedure'), (Index: 144; Name: 'GetTrespassWarningLevel'), (Index: 145; Name: 'IsTrespassing'), (Index: 146; Name: 'IsInMyOwnedCell'), (Index: 147; Name: 'GetWindSpeed'), (Index: 148; Name: 'GetCurrentWeatherPercent'), (Index: 149; Name: 'GetIsCurrentWeather'; ParamType1: ptWeather), (Index: 150; Name: 'IsContinuingPackagePCNear'), (Index: 152; Name: 'GetIsCrimeFaction'; ParamType1: ptFaction), (Index: 153; Name: 'CanHaveFlames'), (Index: 154; Name: 'HasFlames'), (Index: 157; Name: 'GetOpenState'), (Index: 159; Name: 'GetSitting'), (Index: 160; Name: 'GetFurnitureMarkerID'), (Index: 161; Name: 'GetIsCurrentPackage'; ParamType1: ptPackage), (Index: 162; Name: 'IsCurrentFurnitureRef'; ParamType1: ptObjectReference), (Index: 163; Name: 'IsCurrentFurnitureObj'; ParamType1: ptFurniture), (Index: 167; Name: 'GetFactionReaction'; ParamType1: ptFaction; ParamType2: ptFaction), (Index: 170; Name: 'GetDayOfWeek'), (Index: 172; Name: 'GetTalkedToPCParam'; ParamType1: ptActor), (Index: 175; Name: 'IsPCSleeping'), (Index: 176; Name: 'IsPCAMurderer'), (Index: 180; Name: 'HasSameEditorLocationAsRef'; ParamType1: ptObjectReference; ParamType2: ptKeyword), (Index: 181; Name: 'HasSameEditorLocationAsRefAlias'; ParamType1: ptAlias; ParamType2: ptKeyword), (Index: 182; Name: 'GetEquipped'; ParamType1: ptReferencableObject), (Index: 185; Name: 'IsSwimming'), (Index: 186; Name: 'ScriptEffectElapsedSeconds'), (Index: 188; Name: 'GetPCSleepHours'), (Index: 190; Name: 'GetAmountSoldStolen'), (Index: 192; Name: 'GetIgnoreCrime'), (Index: 193; Name: 'GetPCExpelled'; ParamType1: ptFaction), (Index: 195; Name: 'GetPCFactionMurder'; ParamType1: ptFaction), (Index: 197; Name: 'GetPCEnemyofFaction'; ParamType1: ptFaction), (Index: 199; Name: 'GetPCFactionAttack'; ParamType1: ptFaction), (Index: 203; Name: 'GetDestroyed'), (Index: 205; Name: 'GetActionRef'), (Index: 206; Name: 'GetSelf'), (Index: 207; Name: 'GetContainer'), (Index: 208; Name: 'GetForceRun'), (Index: 210; Name: 'GetForceSneak'), (Index: 214; Name: 'HasMagicEffect'; ParamType1: ptMagicEffect), (Index: 215; Name: 'GetDefaultOpen'), (Index: 223; Name: 'IsSpellTarget'; ParamType1: ptMagicItem), (Index: 224; Name: 'GetVATSMode'), (Index: 225; Name: 'GetPersuasionNumber'), (Index: 226; Name: 'GetVampireFeed'), (Index: 227; Name: 'GetCannibal'), (Index: 228; Name: 'GetIsClassDefault'; ParamType1: ptClass), (Index: 229; Name: 'GetClassDefaultMatch'), (Index: 230; Name: 'GetInCellParam'; ParamType1: ptCell; ParamType2: ptObjectReference), (Index: 231; Name: 'GetPlayerDialogueInput'), (Index: 232; Name: 'GetCombatTarget'), (Index: 233; Name: 'GetPackageTarget'), (Index: 235; Name: 'GetVatsTargetHeight'), (Index: 237; Name: 'GetIsGhost'), (Index: 242; Name: 'GetUnconscious'), (Index: 244; Name: 'GetRestrained'), (Index: 246; Name: 'GetIsUsedItem'; ParamType1: ptReferencableObject), (Index: 247; Name: 'GetIsUsedItemType'; ParamType1: ptFormType), (Index: 248; Name: 'IsScenePlaying'; ParamType1: ptScene), (Index: 249; Name: 'IsInDialogueWithPlayer'), (Index: 250; Name: 'GetLocationCleared'; ParamType1: ptLocation), (Index: 254; Name: 'GetIsPlayableRace'), (Index: 255; Name: 'GetOffersServicesNow'), (Index: 256; Name: 'GetGameSetting'; ParamType1: ptNone), (Index: 258; Name: 'HasAssociationType'; ParamType1: ptActor; ParamType2: ptAssociationType), (Index: 259; Name: 'HasFamilyRelationship'; ParamType1: ptActor), (Index: 261; Name: 'HasParentRelationship'; ParamType1: ptActor), (Index: 262; Name: 'IsWarningAbout'; ParamType1: ptFormList), (Index: 263; Name: 'IsWeaponOut'), (Index: 264; Name: 'HasSpell'; ParamType1: ptMagicItem), (Index: 265; Name: 'IsTimePassing'), (Index: 266; Name: 'IsPleasant'), (Index: 267; Name: 'IsCloudy'), (Index: 274; Name: 'IsSmallBump'), (Index: 275; Name: 'GetParentRef'), (Index: 277; Name: 'GetBaseValue'; ParamType1: ptActorValue), (Index: 278; Name: 'IsOwner'; ParamType1: ptOwner), (Index: 280; Name: 'IsCellOwner'; ParamType1: ptCell; ParamType2: ptOwner), (Index: 282; Name: 'IsHorseStolen'), (Index: 285; Name: 'IsLeftUp'), (Index: 286; Name: 'IsSneaking'), (Index: 287; Name: 'IsRunning'), (Index: 288; Name: 'GetFriendHit'), (Index: 289; Name: 'IsInCombat'; ParamType1: ptInteger), (Index: 296; Name: 'IsAnimPlaying'; ParamType1: ptReferencableObject), (Index: 300; Name: 'IsInInterior'), (Index: 303; Name: 'IsActorsAIOff'), (Index: 304; Name: 'IsWaterObject'), (Index: 305; Name: 'GetPlayerAction'), (Index: 306; Name: 'IsActorUsingATorch'), (Index: 309; Name: 'IsXBox'), (Index: 310; Name: 'GetInWorldspace'; ParamType1: ptWorldspace), (Index: 312; Name: 'GetPCMiscStat'; ParamType1: ptMiscStat), (Index: 313; Name: 'GetPairedAnimation'), (Index: 314; Name: 'IsActorAVictim'), (Index: 315; Name: 'GetTotalPersuasionNumber'), (Index: 318; Name: 'GetIdleDoneOnce'), (Index: 320; Name: 'GetNoRumors'), (Index: 323; Name: 'GetCombatState'), (Index: 325; Name: 'GetWithinPackageLocation'; ParamType1: ptPackdata), (Index: 327; Name: 'IsRidingMount'), (Index: 329; Name: 'IsFleeing'), (Index: 332; Name: 'IsInDangerousWater'), (Index: 338; Name: 'GetIgnoreFriendlyHits'), (Index: 339; Name: 'IsPlayersLastRiddenMount'), (Index: 344; Name: 'ReleaseWeatherOverride'), (Index: 348; Name: 'SendTrespassAlarm'; ParamType1: ptActor), (Index: 353; Name: 'IsActor'), (Index: 354; Name: 'IsEssential'), (Index: 358; Name: 'IsPlayerMovingIntoNewSpace'), (Index: 359; Name: 'GetInCurrentLocation'; ParamType1: ptLocation), (Index: 360; Name: 'GetInCurrentLocationAlias'; ParamType1: ptAlias), (Index: 361; Name: 'GetTimeDead'), (Index: 362; Name: 'HasLinkedRef'; ParamType1: ptKeyword), (Index: 363; Name: 'GetLinkedRef'; ParamType1: ptKeyword), (Index: 365; Name: 'IsChild'), (Index: 366; Name: 'GetStolenItemValueNoCrime'; ParamType1: ptFaction), (Index: 367; Name: 'GetLastPlayerAction'), (Index: 368; Name: 'IsPlayerActionActive'; ParamType1: ptInteger), (Index: 370; Name: 'IsTalkingActivatorActor'; ParamType1: ptActor), (Index: 372; Name: 'IsInList'; ParamType1: ptFormList), (Index: 373; Name: 'GetStolenItemValue'; ParamType1: ptFaction), (Index: 375; Name: 'GetCrimeGoldViolent'; ParamType1: ptFaction), (Index: 376; Name: 'GetCrimeGoldNonviolent'; ParamType1: ptFaction), (Index: 378; Name: 'IsOwnedBy'; ParamType1: ptActor), (Index: 380; Name: 'GetCommandDistance'), (Index: 381; Name: 'GetCommandLocationDistance'), (Index: 387; Name: 'GetObjectiveFailed'; ParamType1: ptQuest; ParamType2: ptInteger), (Index: 390; Name: 'GetHitLocation'), (Index: 391; Name: 'IsPC1stPerson'), (Index: 396; Name: 'GetCauseofDeath'), (Index: 397; Name: 'IsLimbGone'; ParamType1: ptInteger), (Index: 398; Name: 'IsWeaponInList'; ParamType1: ptFormList), (Index: 402; Name: 'IsBribedbyPlayer'), (Index: 403; Name: 'GetRelationshipRank'; ParamType1: ptActor), (Index: 407; Name: 'GetVATSValue'; ParamType1: ptInteger; ParamType2: ptInteger), (Index: 408; Name: 'IsKiller'; ParamType1: ptActor), (Index: 409; Name: 'IsKillerObject'; ParamType1: ptFormList), (Index: 410; Name: 'GetFactionCombatReaction'; ParamType1: ptFaction; ParamType2: ptFaction), (Index: 414; Name: 'Exists'; ParamType1: ptObjectReference), (Index: 415; Name: 'GetGroupMemberCount'), (Index: 416; Name: 'GetGroupTargetCount'), (Index: 419; Name: 'GetObjectiveCompleted'; ParamType1: ptQuest; ParamType2: ptInteger), (Index: 420; Name: 'GetObjectiveDisplayed'; ParamType1: ptQuest; ParamType2: ptInteger), (Index: 425; Name: 'GetIsFormType'), (Index: 426; Name: 'GetIsVoiceType'; ParamType1: ptVoiceType), (Index: 427; Name: 'GetPlantedExplosive'), (Index: 429; Name: 'IsScenePackageRunning'), (Index: 430; Name: 'GetHealthPercentage'), (Index: 432; Name: 'GetIsObjectType'; ParamType1: ptFormType), (Index: 437; Name: 'GetIsCreatureType'; ParamType1: ptInteger), (Index: 438; Name: 'HasKey'; ParamType1: ptObjectReference), (Index: 439; Name: 'IsFurnitureEntryType'; ParamType1: ptReferencableObject), (Index: 444; Name: 'GetInCurrentLocationFormList'; ParamType1: ptFormList), (Index: 445; Name: 'GetInZone'; ParamType1: ptEncounterZone), (Index: 446; Name: 'GetVelocity'; ParamType1: ptAxis), (Index: 447; Name: 'GetGraphVariableFloat'), (Index: 448; Name: 'HasPerk'; ParamType1: ptPerk), (Index: 449; Name: 'GetFactionRelation'; ParamType1: ptActor), (Index: 450; Name: 'IsLastIdlePlayed'; ParamType1: ptIdleForm), (Index: 453; Name: 'GetPlayerTeammate'), (Index: 454; Name: 'GetPlayerTeammateCount'), (Index: 458; Name: 'GetActorCrimePlayerEnemy'), (Index: 459; Name: 'GetCrimeGold'; ParamType1: ptFaction), (Index: 462; Name: 'GetPlayerGrabbedRef'), (Index: 463; Name: 'IsPlayerGrabbedRef'; ParamType1: ptObjectReference), (Index: 465; Name: 'GetKeywordItemCount'; ParamType1: ptKeyword), (Index: 467; Name: 'GetBroadcastState'), (Index: 470; Name: 'GetDestructionStage'), (Index: 473; Name: 'GetIsAlignment'; ParamType1: ptAlignment), (Index: 476; Name: 'IsProtected'), (Index: 477; Name: 'GetThreatRatio'; ParamType1: ptActor), (Index: 479; Name: 'GetIsUsedItemEquipType'; ParamType1: ptEquipType), (Index: 480; Name: 'GetPlayerName'), (Index: 483; Name: 'GetPlayerActivated'), (Index: 485; Name: 'GetFullyEnabledActorsInHigh'), (Index: 487; Name: 'IsCarryable'), (Index: 488; Name: 'GetConcussed'), (Index: 489; Name: 'SetZoneRespawns'; ParamType1: ptEncounterZone; ParamType2: ptInteger), (Index: 490; Name: 'SetVATSTarget'; ParamType1: ptInteger), (Index: 491; Name: 'GetMapMarkerVisible'), (Index: 493; Name: 'PlayerKnows'; ParamType1: ptReferencableObject), (Index: 494; Name: 'GetPermanentValue'; ParamType1: ptActorValue), (Index: 495; Name: 'GetKillingBlowLimb'), (Index: 497; Name: 'CanPayCrimeGold'; ParamType1: ptFaction), (Index: 499; Name: 'GetDaysInJail'), (Index: 500; Name: 'EPAlchemyGetMakingPoison'), (Index: 501; Name: 'EPAlchemyEffectHasKeyword'; ParamType1: ptKeyword), (Index: 503; Name: 'GetAllowWorldInteractions'), (Index: 506; Name: 'DialogueGetAv'; ParamType1: ptActorValue), (Index: 507; Name: 'DialogueHasPerk'; ParamType1: ptPerk), (Index: 508; Name: 'GetLastHitCritical'), (Index: 510; Name: 'DialogueGetItemCount'; ParamType1: ptReferencableObject), (Index: 511; Name: 'LastCrippledCondition'; ParamType1: ptActorValue), (Index: 512; Name: 'HasSharedPowerGrid'; ParamType1: ptObjectReference), (Index: 513; Name: 'IsCombatTarget'; ParamType1: ptActor), (Index: 515; Name: 'GetVATSRightAreaFree'; ParamType1: ptObjectReference), (Index: 516; Name: 'GetVATSLeftAreaFree'; ParamType1: ptObjectReference), (Index: 517; Name: 'GetVATSBackAreaFree'; ParamType1: ptObjectReference), (Index: 518; Name: 'GetVATSFrontAreaFree'; ParamType1: ptObjectReference), (Index: 519; Name: 'GetIsLockBroken'), (Index: 520; Name: 'IsPS3'), (Index: 521; Name: 'IsWindowsPC'), (Index: 522; Name: 'GetVATSRightTargetVisible'; ParamType1: ptObjectReference), (Index: 523; Name: 'GetVATSLeftTargetVisible'; ParamType1: ptObjectReference), (Index: 524; Name: 'GetVATSBackTargetVisible'; ParamType1: ptObjectReference), (Index: 525; Name: 'GetVATSFrontTargetVisible'; ParamType1: ptObjectReference), (Index: 528; Name: 'IsInCriticalStage'; ParamType1: ptCriticalStage), (Index: 530; Name: 'GetXPForNextLevel'), (Index: 533; Name: 'GetInfamy'; ParamType1: ptFaction), (Index: 534; Name: 'GetInfamyViolent'; ParamType1: ptFaction), (Index: 535; Name: 'GetInfamyNonViolent'; ParamType1: ptFaction), (Index: 536; Name: 'GetTypeCommandPerforming'), (Index: 543; Name: 'GetQuestCompleted'; ParamType1: ptQuest), (Index: 544; Name: 'GetSpeechChallengeSuccessLevel'), (Index: 545; Name: 'PipBoyRadioOff'), (Index: 547; Name: 'IsGoreDisabled'), (Index: 550; Name: 'IsSceneActionComplete'; ParamType1: ptScene; ParamType2: ptInteger), (Index: 552; Name: 'GetSpellUsageNum'; ParamType1: ptMagicItem), (Index: 554; Name: 'GetActorsInHigh'), (Index: 555; Name: 'HasLoaded3D'), (Index: 559; Name: 'IsImageSpaceActive'; ParamType1: ptReferencableObject), (Index: 560; Name: 'HasKeyword'; ParamType1: ptKeyword), (Index: 561; Name: 'HasRefType'; ParamType1: ptRefType), (Index: 562; Name: 'LocationHasKeyword'; ParamType1: ptKeyword), (Index: 563; Name: 'LocationHasRefType'; ParamType1: ptRefType), (Index: 565; Name: 'GetIsEditorLocation'; ParamType1: ptLocation), (Index: 566; Name: 'GetIsAliasRef'; ParamType1: ptAlias), (Index: 567; Name: 'GetIsEditorLocationAlias'; ParamType1: ptAlias), (Index: 568; Name: 'IsSprinting'), (Index: 569; Name: 'IsBlocking'), (Index: 570; Name: 'HasEquippedSpell'; ParamType1: ptCastingSource), (Index: 571; Name: 'GetCurrentCastingType'; ParamType1: ptCastingSource), (Index: 572; Name: 'GetCurrentDeliveryType'; ParamType1: ptCastingSource), (Index: 574; Name: 'GetAttackState'), (Index: 575; Name: 'GetAliasedRef'; ParamType1: ptAlias), (Index: 576; Name: 'GetEventData'; ParamType1: ptEvent; ParamType2: ptEventData; ParamType3: ptNone), // fireundubh: Event Function, Event Member, Data (FO4) (Index: 577; Name: 'IsCloserToAThanB'; ParamType1: ptObjectReference; ParamType2: ptObjectReference), (Index: 578; Name: 'LevelMinusPCLevel'), (Index: 580; Name: 'IsBleedingOut'), (Index: 584; Name: 'GetRelativeAngle'; ParamType1: ptObjectReference; ParamType2: ptAxis), (Index: 589; Name: 'GetMovementDirection'), (Index: 590; Name: 'IsInScene'), (Index: 591; Name: 'GetRefTypeDeadCount'; ParamType1: ptLocation; ParamType2: ptRefType), (Index: 592; Name: 'GetRefTypeAliveCount'; ParamType1: ptLocation; ParamType2: ptRefType), (Index: 594; Name: 'GetIsFlying'), (Index: 595; Name: 'IsCurrentSpell'; ParamType1: ptMagicItem; ParamType2: ptCastingSource), (Index: 596; Name: 'SpellHasKeyword'; ParamType1: ptCastingSource; ParamType2: ptKeyword), (Index: 597; Name: 'GetEquippedItemType'; ParamType1: ptCastingSource), (Index: 598; Name: 'GetLocationAliasCleared'; ParamType1: ptAlias), (Index: 600; Name: 'GetLocationAliasRefTypeDeadCount'; ParamType1: ptAlias; ParamType2: ptRefType), (Index: 601; Name: 'GetLocationAliasRefTypeAliveCount'; ParamType1: ptAlias; ParamType2: ptRefType), (Index: 602; Name: 'IsWardState'; ParamType1: ptWardState), (Index: 603; Name: 'IsInSameCurrentLocationAsRef'; ParamType1: ptObjectReference; ParamType2: ptKeyword), (Index: 604; Name: 'IsInSameCurrentLocationAsRefAlias'; ParamType1: ptAlias; ParamType2: ptKeyword), (Index: 605; Name: 'LocationAliasIsLocation'; ParamType1: ptAlias; ParamType2: ptLocation), (Index: 606; Name: 'GetKeywordDataForLocation'; ParamType1: ptLocation; ParamType2: ptKeyword), (Index: 608; Name: 'GetKeywordDataForAlias'; ParamType1: ptAlias; ParamType2: ptKeyword), (Index: 610; Name: 'LocationAliasHasKeyword'; ParamType1: ptAlias; ParamType2: ptKeyword), (Index: 611; Name: 'IsNullPackageData'; ParamType1: ptPackdata), (Index: 612; Name: 'GetNumericPackageData'; ParamType1: ptPackdata), (Index: 613; Name: 'IsPlayerRadioOn'), (Index: 614; Name: 'GetPlayerRadioFrequency'), (Index: 615; Name: 'GetHighestRelationshipRank'), (Index: 616; Name: 'GetLowestRelationshipRank'), (Index: 617; Name: 'HasAssociationTypeAny'; ParamType1: ptAssociationType), (Index: 618; Name: 'HasFamilyRelationshipAny'), (Index: 619; Name: 'GetPathingTargetOffset'; ParamType1: ptAxis), (Index: 620; Name: 'GetPathingTargetAngleOffset'; ParamType1: ptAxis), (Index: 621; Name: 'GetPathingTargetSpeed'), (Index: 622; Name: 'GetPathingTargetSpeedAngle'; ParamType1: ptAxis), (Index: 623; Name: 'GetMovementSpeed'), (Index: 624; Name: 'GetInContainer'; ParamType1: ptObjectReference), (Index: 625; Name: 'IsLocationLoaded'; ParamType1: ptLocation), (Index: 626; Name: 'IsLocationAliasLoaded'; ParamType1: ptAlias), (Index: 627; Name: 'IsDualCasting'), (Index: 629; Name: 'GetVMQuestVariable'; ParamType1: ptQuest; ParamType2: ptNone), (Index: 630; Name: 'GetCombatAudioDetection'), (Index: 631; Name: 'GetCombatVisualDetection'), (Index: 632; Name: 'IsCasting'), (Index: 633; Name: 'GetFlyingState'), (Index: 635; Name: 'IsInFavorState'), (Index: 636; Name: 'HasTwoHandedWeaponEquipped'), (Index: 637; Name: 'IsFurnitureExitType'; ParamType1: ptReferencableObject), (Index: 638; Name: 'IsInFriendStatewithPlayer'), (Index: 639; Name: 'GetWithinDistance'; ParamType1: ptObjectReference; ParamType2: ptFloat), (Index: 640; Name: 'GetValuePercent'; ParamType1: ptActorValue), (Index: 641; Name: 'IsUnique'), (Index: 642; Name: 'GetLastBumpDirection'), (Index: 644; Name: 'GetInfoChallangeSuccess'), (Index: 645; Name: 'GetIsInjured'), (Index: 646; Name: 'GetIsCrashLandRequest'), (Index: 647; Name: 'GetIsHastyLandRequest'), (Index: 650; Name: 'IsLinkedTo'; ParamType1: ptObjectReference; ParamType2: ptKeyword), (Index: 651; Name: 'GetKeywordDataForCurrentLocation'; ParamType1: ptKeyword), (Index: 652; Name: 'GetInSharedCrimeFaction'; ParamType1: ptObjectReference), (Index: 653; Name: 'GetBribeAmount'), (Index: 654; Name: 'GetBribeSuccess'), (Index: 655; Name: 'GetIntimidateSuccess'), (Index: 656; Name: 'GetArrestedState'), (Index: 657; Name: 'GetArrestingActor'), (Index: 659; Name: 'HasVMScript'; ParamType1: ptNone), (Index: 660; Name: 'GetVMScriptVariable'; ParamType1: ptNone; ParamType2: ptNone), (Index: 661; Name: 'GetWorkshopResourceDamage'; ParamType1: ptActorValue), (Index: 664; Name: 'HasValidRumorTopic'; ParamType1: ptQuest), (Index: 672; Name: 'IsAttacking'), (Index: 673; Name: 'IsPowerAttacking'), (Index: 674; Name: 'IsLastHostileActor'), (Index: 675; Name: 'GetGraphVariableInt'; ParamType1: ptNone), (Index: 678; Name: 'ShouldAttackKill'; ParamType1: ptActor), (Index: 680; Name: 'GetActivationHeight'), (Index: 682; Name: 'WornHasKeyword'; ParamType1: ptKeyword), (Index: 683; Name: 'GetPathingCurrentSpeed'), (Index: 684; Name: 'GetPathingCurrentSpeedAngle'; ParamType1: ptAxis), (Index: 691; Name: 'GetWorkshopObjectCount'; ParamType1: ptReferencableObject), (Index: 693; Name: 'EPMagic_SpellHasKeyword'; ParamType1: ptKeyword), (Index: 694; Name: 'GetNoBleedoutRecovery'), (Index: 696; Name: 'EPMagic_SpellHasSkill'; ParamType1: ptActorValue), (Index: 697; Name: 'IsAttackType'; ParamType1: ptKeyword), (Index: 698; Name: 'IsAllowedToFly'), (Index: 699; Name: 'HasMagicEffectKeyword'; ParamType1: ptKeyword), (Index: 700; Name: 'IsCommandedActor'), (Index: 701; Name: 'IsStaggered'), (Index: 702; Name: 'IsRecoiling'), (Index: 703; Name: 'HasScopeWeaponEquipped'), (Index: 704; Name: 'IsPathing'), (Index: 705; Name: 'GetShouldHelp'; ParamType1: ptActor), (Index: 706; Name: 'HasBoundWeaponEquipped'; ParamType1: ptCastingSource), (Index: 707; Name: 'GetCombatTargetHasKeyword'; ParamType1: ptKeyword), (Index: 709; Name: 'GetCombatGroupMemberCount'), (Index: 710; Name: 'IsIgnoringCombat'), (Index: 711; Name: 'GetLightLevel'), (Index: 713; Name: 'SpellHasCastingPerk'; ParamType1: ptPerk), (Index: 714; Name: 'IsBeingRidden'), (Index: 715; Name: 'IsUndead'), (Index: 716; Name: 'GetRealHoursPassed'), (Index: 718; Name: 'IsUnlockedDoor'), (Index: 719; Name: 'IsHostileToActor'; ParamType1: ptActor), (Index: 720; Name: 'GetTargetHeight'; ParamType1: ptObjectReference), (Index: 721; Name: 'IsPoison'), (Index: 722; Name: 'WornApparelHasKeywordCount'; ParamType1: ptKeyword), (Index: 723; Name: 'GetItemHealthPercent'), (Index: 724; Name: 'EffectWasDualCast'), (Index: 725; Name: 'GetKnockStateEnum'), (Index: 726; Name: 'DoesNotExist'), (Index: 728; Name: 'GetPlayerWalkAwayFromDialogueScene'), (Index: 729; Name: 'GetActorStance'), (Index: 734; Name: 'CanProduceForWorkshop'), (Index: 735; Name: 'CanFlyHere'), (Index: 736; Name: 'EPIsDamageType'; ParamType1: ptDamageType), (Index: 738; Name: 'GetActorGunState'), (Index: 739; Name: 'GetVoiceLineLength'), (Index: 741; Name: 'ObjectTemplateItem_HasKeyword'; ParamType1: ptKeyword), (Index: 742; Name: 'ObjectTemplateItem_HasUniqueKeyword'; ParamType1: ptKeyword), (Index: 743; Name: 'ObjectTemplateItem_GetLevel'), (Index: 744; Name: 'MovementIdleMatches'; ParamType1: ptInteger; ParamType2: ptInteger), // TODO: determine correct param types (2) (Index: 745; Name: 'GetActionData'), (Index: 746; Name: 'GetActionDataShort'; ParamType1: ptInteger), (Index: 747; Name: 'GetActionDataByte'; ParamType1: ptInteger), (Index: 748; Name: 'GetActionDataFlag'; ParamType1: ptInteger), (Index: 749; Name: 'ModdedItemHasKeyword'; ParamType1: ptKeyword), (Index: 750; Name: 'GetAngryWithPlayer'), (Index: 751; Name: 'IsCameraUnderWater'), (Index: 753; Name: 'IsActorRefOwner'; ParamType1: ptActor), (Index: 754; Name: 'HasActorRefOwner'; ParamType1: ptActor), (Index: 756; Name: 'GetLoadedAmmoCount'), (Index: 757; Name: 'IsTimeSpanSunrise'), (Index: 758; Name: 'IsTimeSpanMorning'), (Index: 759; Name: 'IsTimeSpanAfternoon'), (Index: 760; Name: 'IsTimeSpanEvening'), (Index: 761; Name: 'IsTimeSpanSunset'), (Index: 762; Name: 'IsTimeSpanNight'), (Index: 763; Name: 'IsTimeSpanMidnight'), (Index: 764; Name: 'IsTimeSpanAnyDay'), (Index: 765; Name: 'IsTimeSpanAnyNight'), (Index: 766; Name: 'CurrentFurnitureHasKeyword'; ParamType1: ptKeyword), (Index: 767; Name: 'GetWeaponEquipIndex'), (Index: 769; Name: 'IsOverEncumbered'), (Index: 770; Name: 'IsPackageRequestingBlockedIdles'), (Index: 771; Name: 'GetActionDataInt'), (Index: 772; Name: 'GetVATSRightMinusLeftAreaFree'; ParamType1: ptObjectReference), (Index: 773; Name: 'GetInIronSights'; ParamType1: ptObjectReference), (Index: 774; Name: 'GetActorStaggerDirection'), (Index: 775; Name: 'GetActorStaggerMagnitude'), (Index: 776; Name: 'WornCoversBipedSlot'; ParamType1: ptInteger), (Index: 777; Name: 'GetInventoryValue'), (Index: 778; Name: 'IsPlayerInConversation'), (Index: 779; Name: 'IsInDialogueCamera'), (Index: 780; Name: 'IsMyDialogueTargetPlayer'), (Index: 781; Name: 'IsMyDialogueTargetActor'), (Index: 782; Name: 'GetMyDialogueTargetDistance'), (Index: 783; Name: 'IsSeatOccupied'; ParamType1: ptKeyword), (Index: 784; Name: 'IsPlayerRiding'), (Index: 785; Name: 'IsTryingEventCamera'), (Index: 786; Name: 'UseLeftSideCamera'), (Index: 787; Name: 'GetNoteType'), (Index: 788; Name: 'LocationHasPlayerOwnedWorkshop'), (Index: 789; Name: 'IsStartingAction'), (Index: 790; Name: 'IsMidAction'), (Index: 791; Name: 'IsWeaponChargeAttack'), (Index: 792; Name: 'IsInWorkshopMode'), (Index: 793; Name: 'IsWeaponChargingHoldAttack'), (Index: 794; Name: 'IsEncounterAbovePlayerLevel'), (Index: 795; Name: 'IsMeleeAttacking'), (Index: 796; Name: 'GetVATSQueuedTargetsUnique'), (Index: 797; Name: 'GetCurrentLocationCleared'), (Index: 798; Name: 'IsPowered'), (Index: 799; Name: 'GetTransmitterDistance'), (Index: 800; Name: 'GetCameraPlaybackTime'), (Index: 801; Name: 'IsInWater'), (Index: 802; Name: 'GetWithinActivateDistance'; ParamType1: ptObjectReference), (Index: 803; Name: 'IsUnderWater'), (Index: 804; Name: 'IsInSameSpace'; ParamType1: ptObjectReference), (Index: 805; Name: 'LocationAllowsReset'), (Index: 806; Name: 'GetVATSBackRightAreaFree'; ParamType1: ptObjectReference), (Index: 807; Name: 'GetVATSBackLeftAreaFree'; ParamType1: ptObjectReference), (Index: 808; Name: 'GetVATSBackRightTargetVisible'; ParamType1: ptObjectReference), (Index: 809; Name: 'GetVATSBackLeftTargetVisible'; ParamType1: ptObjectReference), (Index: 810; Name: 'GetVATSTargetLimbVisible'; ParamType1: ptObjectReference), (Index: 811; Name: 'IsPlayerListening'; ParamType1: ptFloat), (Index: 812; Name: 'GetPathingRequestedQuickTurn'), (Index: 813; Name: 'EPIsCalculatingBaseDamage'), (Index: 814; Name: 'GetReanimating'), (Index: 817; Name: 'IsInRobotWorkbench'), // F4SE (Index: 1024; Name: 'GetSKSEVersion'; ), (Index: 1025; Name: 'GetSKSEVersionMinor'; ), (Index: 1026; Name: 'GetSKSEVersionBeta'; ), (Index: 1027; Name: 'GetSKSERelease'; ), (Index: 1028; Name: 'ClearInvalidRegistrations'; ) ); var wbCTDAFunctionEditInfo: string; function wbCTDAParamDescFromIndex(aIndex: Integer): PCTDAFunction; var L, H, I, C: Integer; begin Result := nil; L := Low(wbCTDAFunctions); H := High(wbCTDAFunctions); while L <= H do begin I := (L + H) shr 1; C := CmpW32(wbCTDAFunctions[I].Index, aIndex); if C < 0 then L := I + 1 else begin H := I - 1; if C = 0 then begin L := I; Result := @wbCTDAFunctions[L]; end; end; end; end; function wbCTDACompValueDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container: IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; // "use global" flag if Integer(Container.ElementByName['Type'].NativeValue) and $04 <> 0 then Result := 1; end; function wbCTDAParam1Decider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Desc: PCTDAFunction; Container: IwbContainer; ParamFlag: Byte; ParamType: TCTDAFunctionParamType; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; Desc := wbCTDAParamDescFromIndex(Container.ElementByName['Function'].NativeValue); if Assigned(Desc) then begin ParamType := Desc.ParamType1; ParamFlag := Container.ElementByName['Type'].NativeValue; if ParamType in [ptObjectReference, ptActor, ptPackage] then begin if ParamFlag and $02 > 0 then begin // except for this func when Run On = Quest Alias, then alias is param3 and package is param1 // [INFO:00020D3C] if not ((Container.ElementByName['Run On'].NativeValue = 5) and (Desc.Name = 'GetIsCurrentPackage')) then ParamType := ptAlias {>>> 'use aliases' is set <<<} end else if ParamFlag and $08 > 0 then ParamType := ptPackdata; {>>> 'use packdata' is set <<<} end; Result := Succ(Integer(ParamType)); end; end; function wbCTDAParam2Decider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Desc: PCTDAFunction; Container: IwbContainer; ParamFlag: Byte; ParamType: TCTDAFunctionParamType; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; Desc := wbCTDAParamDescFromIndex(Container.ElementByName['Function'].NativeValue); if Assigned(Desc) then begin ParamType := Desc.ParamType2; ParamFlag := Container.ElementByName['Type'].NativeValue; if ParamType in [ptObjectReference, ptActor, ptPackage] then begin if ParamFlag and $02 > 0 then ParamType := ptAlias else {>>> 'use aliases' is set <<<} if ParamFlag and $08 > 0 then ParamType := ptPackdata; {>>> 'use packdata' is set <<<} end; Result := Succ(Integer(ParamType)); end; end; function wbCTDAParam2VATSValueParamDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; Result := Container.ElementByName['Parameter #1'].NativeValue; end; function wbCTDAFunctionToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Desc : PCTDAFunction; i : Integer; begin Result := ''; case aType of ctToStr, ctToEditValue: begin Desc := wbCTDAParamDescFromIndex(aInt); if Assigned(Desc) then Result := Desc.Name else if aType = ctToEditValue then Result := IntToStr(aInt) else Result := ''; end; ctToSortKey: Result := IntToHex(aInt, 8); ctCheck: begin Desc := wbCTDAParamDescFromIndex(aInt); if Assigned(Desc) then Result := '' else Result := ''; end; ctEditType: Result := 'ComboBox'; ctEditInfo: begin Result := wbCTDAFunctionEditInfo; if Result = '' then begin with TStringList.Create do try for i := Low(wbCTDAFunctions) to High(wbCTDAFunctions) do Add(wbCTDAFunctions[i].Name); Sort; Result := CommaText; finally Free; end; wbCTDAFunctionEditInfo := Result; end; end; end; end; function wbCTDAFunctionToInt(const aString: string; const aElement: IwbElement): Int64; var i: Integer; begin for i := Low(wbCTDAFunctions) to High(wbCTDAFunctions) do with wbCTDAFunctions[i] do if SameText(Name, aString) then begin Result := Index; Exit; end; Result := StrToInt64(aString); end; function wbNeverShow(const aElement: IwbElement): Boolean; begin Result := wbHideNeverShow; end; function GetREGNType(aElement: IwbElement): Integer; var Container: IwbContainerElementRef; begin Result := -1; if not Assigned(aElement) then Exit; while aElement.Name <> 'Region Data Entry' do begin aElement := aElement.Container; if not Assigned(aElement) then Exit; end; if not Supports(aElement, IwbContainerElementRef, Container) then Exit; Result := Container.ElementNativeValues['RDAT\Type']; end; function wbREGNObjectsDontShow(const aElement: IwbElement): Boolean; begin Result := GetREGNType(aElement) <> 2; end; function wbREGNWeatherDontShow(const aElement: IwbElement): Boolean; begin Result := GetREGNType(aElement) <> 3; end; function wbREGNMapDontShow(const aElement: IwbElement): Boolean; begin Result := GetREGNType(aElement) <> 4; end; function wbREGNLandDontShow(const aElement: IwbElement): Boolean; begin Result := GetREGNType(aElement) <> 5; end; function wbREGNGrassDontShow(const aElement: IwbElement): Boolean; begin Result := GetREGNType(aElement) <> 6; end; function wbREGNSoundDontShow(const aElement: IwbElement): Boolean; begin Result := GetREGNType(aElement) <> 7; end; function wbREGNImposterDontShow(const aElement: IwbElement): Boolean; begin Result := GetREGNType(aElement) <> 8; end; function wbMESGTNAMDontShow(const aElement: IwbElement): Boolean; var Container : IwbContainerElementRef; MainRecord : IwbMainRecord; begin Result := False; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Integer(Container.ElementNativeValues['DNAM']) and 1 <> 0 then Result := True; end; function wbEPFDDontShow(const aElement: IwbElement): Boolean; var Container: IwbContainerElementRef; begin Result := False; if aElement.Name <> 'Entry Point Function Parameters' then Exit; if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if not (Integer(Container.ElementNativeValues['EPFT']) in [1..3]) then Result := True; end; function wbTES4ONAMDontShow(const aElement: IwbElement): Boolean; var MainRecord : IwbMainRecord; begin Result := False; if not Assigned(aElement) then Exit; MainRecord := aElement.ContainingMainRecord; if not Assigned(MainRecord) then Exit; if not MainRecord.IsESM then Result := True; end; function wbEPF2DontShow(const aElement: IwbElement): Boolean; var Container: IwbContainerElementRef; begin Result := False; if aElement.Name <> 'Entry Point Function Parameters' then Exit; if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if not (Integer(Container.ElementNativeValues['EPFT']) in [4]) then Result := True; end; procedure wbRemoveOFST(const aElement: IwbElement); var Container: IwbContainer; rOFST: IwbRecord; begin if not wbRemoveOffsetData then Exit; if Supports(aElement, IwbContainer, Container) then begin if wbBeginInternalEdit then try Container.RemoveElement(OFST); finally wbEndInternalEdit; end else begin rOFST := Container.RecordBySignature[OFST]; if Assigned(rOFST) then Container.RemoveElement(rOFST); end; end; end; procedure wbWRLDAfterLoad(const aElement: IwbElement); function OutOfRange(aValue: Integer; aRange: Integer = 256): Boolean; begin Result := (aValue < -aRange) or (aValue > aRange); end; var MainRecord: IwbMainRecord; Container: IwbContainer; begin wbRemoveOFST(aElement); if wbBeginInternalEdit then try if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.ElementExists['Unused RNAM'] then MainRecord.RemoveElement('Unused RNAM'); //if MainRecord.ElementExists['World Default Level Data'] then // MainRecord.RemoveElement('World Default Level Data'); //if MainRecord.ElementExists['MHDT'] then // MainRecord.RemoveElement('MHDT'); if MainRecord.ElementExists['CLSZ'] then MainRecord.RemoveElement('CLSZ'); // large values in object bounds cause stutter and performance issues in game (reported by Arthmoor) // CK can occasionally set them wrong, so make a warning if Supports(MainRecord.ElementByName['Object Bounds'], IwbContainer, Container) then if OutOfRange(StrToIntDef(Container.ElementEditValues['NAM0\X'], 0)) or OutOfRange(StrToIntDef(Container.ElementEditValues['NAM0\Y'], 0)) or OutOfRange(StrToIntDef(Container.ElementEditValues['NAM9\X'], 0)) or OutOfRange(StrToIntDef(Container.ElementEditValues['NAM9\Y'], 0)) then wbProgressCallback(''); finally wbEndInternalEdit; end; end; procedure wbDOBJObjectsAfterLoad(const aElement: IwbElement); var ObjectsContainer : IwbContainerElementRef; i : Integer; ObjectContainer : IwbContainerElementRef; begin wbRemoveOFST(aElement); if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, ObjectsContainer) then Exit; for i := Pred(ObjectsContainer.ElementCount) downto 0 do if Supports(ObjectsContainer.Elements[i], IwbContainerElementRef, ObjectContainer) then if ObjectContainer.ElementNativeValues['Use'] = 0 then ObjectsContainer.RemoveElement(i, True); finally wbEndInternalEdit; end; end; function wbActorTemplateUseTraits(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; Element := aElement; MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000001) <> 0; end; end; function wbActorTemplateUseStats(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; Element := aElement; MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000002) <> 0; end; end; function wbActorAutoCalcDontShow(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; Element := aElement; MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Flags']; Result := (i and $00000010) <> 0; end; end; function wbActorTemplateUseStatsAutoCalc(const aElement: IwbElement): Boolean; begin Result := wbActorTemplateUseStats(aElement) or wbActorAutoCalcDontShow(aElement); end; function wbActorTemplateUseFactions(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; Element := aElement; MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000004) <> 0; end; end; function wbActorTemplateUseActorEffectList(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; Element := aElement; MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000008) <> 0; end; end; function wbActorTemplateUseAIData(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; Element := aElement; MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000010) <> 0; end; end; function wbActorTemplateUseAIPackages(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; Element := aElement; MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000020) <> 0; end; end; function wbActorTemplateUseModelAnimation(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; Element := aElement; MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000040) <> 0; end; end; function wbActorTemplateUseBaseData(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; Element := aElement; MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000080) <> 0; end; end; function wbActorTemplateUseInventory(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; Element := aElement; MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000100) <> 0; end; end; function wbActorTemplateUseScript(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; Element := aElement; MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000200) <> 0; end; end; function wbActorTemplatesUseTemplate0(const aElement: IwbElement): Boolean; var MainRecord : IwbMainRecord; begin MainRecord := aElement.ContainingMainRecord; if Assigned(MainRecord) then Result := (Cardinal(MainRecord.ElementNativeValues['ACBS\Use Template Actors']) shr 0 and 1) = 0 else Result := False; end; function wbActorTemplatesUseTemplate1(const aElement: IwbElement): Boolean; var MainRecord : IwbMainRecord; begin MainRecord := aElement.ContainingMainRecord; if Assigned(MainRecord) then Result := (Cardinal(MainRecord.ElementNativeValues['ACBS\Use Template Actors']) shr 1 and 1) = 0 else Result := False; end; function wbActorTemplatesUseTemplate2(const aElement: IwbElement): Boolean; var MainRecord : IwbMainRecord; begin MainRecord := aElement.ContainingMainRecord; if Assigned(MainRecord) then Result := (Cardinal(MainRecord.ElementNativeValues['ACBS\Use Template Actors']) shr 2 and 1) = 0 else Result := False; end; function wbActorTemplatesUseTemplate3(const aElement: IwbElement): Boolean; var MainRecord : IwbMainRecord; begin MainRecord := aElement.ContainingMainRecord; if Assigned(MainRecord) then Result := (Cardinal(MainRecord.ElementNativeValues['ACBS\Use Template Actors']) shr 3 and 1) = 0 else Result := False; end; function wbActorTemplatesUseTemplate4(const aElement: IwbElement): Boolean; var MainRecord : IwbMainRecord; begin MainRecord := aElement.ContainingMainRecord; if Assigned(MainRecord) then Result := (Cardinal(MainRecord.ElementNativeValues['ACBS\Use Template Actors']) shr 4 and 1) = 0 else Result := False; end; function wbActorTemplatesUseTemplate5(const aElement: IwbElement): Boolean; var MainRecord : IwbMainRecord; begin MainRecord := aElement.ContainingMainRecord; if Assigned(MainRecord) then Result := (Cardinal(MainRecord.ElementNativeValues['ACBS\Use Template Actors']) shr 5 and 1) = 0 else Result := False; end; function wbActorTemplatesUseTemplate6(const aElement: IwbElement): Boolean; var MainRecord : IwbMainRecord; begin MainRecord := aElement.ContainingMainRecord; if Assigned(MainRecord) then Result := (Cardinal(MainRecord.ElementNativeValues['ACBS\Use Template Actors']) shr 6 and 1) = 0 else Result := False; end; function wbActorTemplatesUseTemplate7(const aElement: IwbElement): Boolean; var MainRecord : IwbMainRecord; begin MainRecord := aElement.ContainingMainRecord; if Assigned(MainRecord) then Result := (Cardinal(MainRecord.ElementNativeValues['ACBS\Use Template Actors']) shr 7 and 1) = 0 else Result := False; end; function wbActorTemplatesUseTemplate8(const aElement: IwbElement): Boolean; var MainRecord : IwbMainRecord; begin MainRecord := aElement.ContainingMainRecord; if Assigned(MainRecord) then Result := (Cardinal(MainRecord.ElementNativeValues['ACBS\Use Template Actors']) shr 8 and 1) = 0 else Result := False; end; function wbActorTemplatesUseTemplate9(const aElement: IwbElement): Boolean; var MainRecord : IwbMainRecord; begin MainRecord := aElement.ContainingMainRecord; if Assigned(MainRecord) then Result := (Cardinal(MainRecord.ElementNativeValues['ACBS\Use Template Actors']) shr 9 and 1) = 0 else Result := False; end; function wbActorTemplatesUseTemplate10(const aElement: IwbElement): Boolean; var MainRecord : IwbMainRecord; begin MainRecord := aElement.ContainingMainRecord; if Assigned(MainRecord) then Result := (Cardinal(MainRecord.ElementNativeValues['ACBS\Use Template Actors']) shr 10 and 1) = 0 else Result := False; end; function wbActorTemplatesUseTemplate11(const aElement: IwbElement): Boolean; var MainRecord : IwbMainRecord; begin MainRecord := aElement.ContainingMainRecord; if Assigned(MainRecord) then Result := (Cardinal(MainRecord.ElementNativeValues['ACBS\Use Template Actors']) shr 11 and 1) = 0 else Result := False; end; function wbActorTemplatesUseTemplate12(const aElement: IwbElement): Boolean; var MainRecord : IwbMainRecord; begin MainRecord := aElement.ContainingMainRecord; if Assigned(MainRecord) then Result := (Cardinal(MainRecord.ElementNativeValues['ACBS\Use Template Actors']) shr 12 and 1) = 0 else Result := False; end; procedure wbRemoveEmptyKWDA(const aElement: IwbElement); var Container : IwbContainerElementRef; MainRecord : IwbMainRecord; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; if not Assigned(Container.ElementBySignature['KSIZ']) then if Assigned(Container.ElementBySignature['KWDA']) then Container.ElementBySignature['KWDA'].Remove; finally wbEndInternalEdit; end; end; procedure wbReplaceBODTwithBOD2(const aElement: IwbElement); var MainRecord : IwbMainRecord; ContainerBOD2 : IwbContainerElementRef; ContainerBODT : IwbContainerElementRef; begin Exit; {>>> Looks like causes problems with Dawnguard.esm <<<} if wbBeginInternalEdit then try if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if not Supports(MainRecord.ElementBySignature[BODT], IwbContainerElementRef, ContainerBODT) then Exit; if Supports(MainRecord.Add('BOD2', True), IwbContainerElementRef, ContainerBOD2) then begin ContainerBOD2.ElementNativeValues['First Person Flags'] := ContainerBODT.ElementNativeValues['First Person Flags']; ContainerBOD2.ElementNativeValues['Armor Type'] := ContainerBODT.ElementNativeValues['Armor Type']; MainRecord.RemoveElement(BODT); end; finally wbEndInternalEdit; end; end; procedure wbARMOAfterLoad(const aElement: IwbElement); begin wbRemoveEmptyKWDA(aElement); wbReplaceBODTwithBOD2(aElement); end; procedure wbARMAAfterLoad(const aElement: IwbElement); {var MainRecord : IwbMainRecord;} begin wbReplaceBODTwithBOD2(aElement); {if wbBeginInternalEdit then try if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.ElementNativeValues['DNAM\Weight slider - Male'] = 0 then MainRecord.ElementNativeValues['DNAM\Weight slider - Male'] := 2; if MainRecord.ElementNativeValues['DNAM\Weight slider - Female'] = 0 then MainRecord.ElementNativeValues['DNAM\Weight slider - Female'] := 2; finally wbEndInternalEdit; end;} end; procedure wbNPCAfterLoad(const aElement: IwbElement); begin wbRemoveEmptyKWDA(aElement); end; procedure wbREFRAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; MainRecord : IwbMainRecord; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; if Container.ElementExists['XLOC'] then begin if Container.ElementNativeValues['XLOC - Lock Data\Level'] = 0 then Container.ElementNativeValues['XLOC - Lock Data\Level'] := 1; end; Container.RemoveElement('XPTL'); finally wbEndInternalEdit; end; end; procedure wbWEAPAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; MainRecord : IwbMainRecord; Flags : Cardinal; begin wbRemoveEmptyKWDA(aElement); if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; // clear IronSights flags which are randomly assigned in CK if Container.ElementExists['DNAM'] then begin Flags := Container.ElementNativeValues['DNAM - Data\Flags']; Flags := Flags and ($FFFF xor $0040); Container.ElementNativeValues['DNAM - Data\Flags'] := Flags; Flags := Container.ElementNativeValues['DNAM - Data\Flags2']; Flags := Flags and ($FFFFFFFF xor $0100); Container.ElementNativeValues['DNAM - Data\Flags2'] := Flags; end; finally wbEndInternalEdit; end; end; procedure wbCELLXCLWGetConflictPriority(const aElement: IwbElement; var aCP: TwbConflictPriority); var Container : IwbContainerElementRef; MainRecord : IwbMainRecord; DataRec : IwbElement; Flags : Cardinal; begin if not Assigned(aElement) then Exit; if not Supports(aElement.Container, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(Container, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; DataRec := MainRecord.ElementBySignature[DATA]; if not Assigned(DataRec) then Exit; Flags := DataRec.NativeValue; {0x0001 Is Interior Cell} if (Flags and 1) = 1 then {Interior cells don't use water level in Skyrim at all} aCP := cpIgnore; end; procedure wbCELLDATAAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var Container : IwbContainer; begin if not Assigned(aElement) then Exit; Container := aElement.Container; while Assigned(Container) and not (Container.Def.DefType = dtRecord) do Container := Container.Container; if Assigned(Container) then Container.ResetConflict; end; procedure wbCELLAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; // Container2 : IwbContainerElementRef; MainRecord : IwbMainRecord; DataSubRec : IwbSubrecord; Flags : Byte; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; if Supports(Container.ElementBySignature['DATA'] , IwbSubRecord, DataSubRec) then begin // expand itU8 flags to itU16 if DataSubRec.SubRecordHeaderSize = 1 then begin Flags := PByte(DataSubRec.DataBasePtr)^; DataSubRec.SetToDefault; DataSubRec.NativeValue := Flags; end; // 'Default' water height for exterior cells if not set (so water height will be taken from WRLD by game) if (not Container.ElementExists['XCLW']) and ((Integer(DataSubRec.NativeValue) and $02) <> 0) then begin Container.Add('XCLW', True); Container.ElementEditValues['XCLW'] := 'Default'; end; end; // Min (-0 as in CK) water height is set to 0 when saving in CK if Container.ElementEditValues['XCLW'] = 'Min' then Container.ElementEditValues['XCLW'] := '0.0'; // if Supports(Container.ElementBySignature[XCLR], IwbContainerElementRef, Container2) then begin // for i := Pred(Container2.ElementCount) downto 0 do // if not Supports(Container2.Elements[i].LinksTo, IwbMainRecord, MainRecord) or (MainRecord.Signature <> 'REGN') then // Container2.RemoveElement(i); // if Container2.ElementCount < 1 then // Container2.Remove; // end; finally wbEndInternalEdit; end; end; procedure wbMESGAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; MainRecord : IwbMainRecord; IsMessageBox : Boolean; HasTimeDelay : Boolean; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; IsMessageBox := (Integer(Container.ElementNativeValues['DNAM']) and 1) = 1; HasTimeDelay := Container.ElementExists['TNAM']; if IsMessageBox = HasTimeDelay then if IsMessageBox then Container.RemoveElement('TNAM') else begin if not Container.ElementExists['DNAM'] then Container.Add('DNAM', True); Container.ElementNativeValues['DNAM'] := Integer(Container.ElementNativeValues['DNAM']) or 1; end; finally wbEndInternalEdit; end; end; procedure wbLIGHAfterLoad(const aElement: IwbElement); var Container: IwbContainerElementRef; MainRecord : IwbMainRecord; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; if not Container.ElementExists['FNAM'] then begin Container.Add('FNAM', True); Container.ElementNativeValues['FNAM'] := 1.0; end; if Container.ElementExists['DATA'] then begin if SameValue(Container.ElementNativeValues['DATA\Falloff Exponent'], 0.0) then Container.ElementNativeValues['DATA\Falloff Exponent'] := 1.0; if SameValue(Container.ElementNativeValues['DATA\FOV'], 0.0) then Container.ElementNativeValues['DATA\FOV'] := 90.0; end; finally wbEndInternalEdit; end; end; procedure wbEFITAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; Element : IwbElement; ActorValue: Variant; MainRecord: IwbMainRecord; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; MainRecord := Container.ContainingMainRecord; if not Assigned(MainRecord) or MainRecord.IsDeleted then Exit; Element := Container.ElementByPath['..\EFID']; if not Assigned(Element) then Exit; if not Supports(Element.LinksTo, IwbMainRecord, MainRecord) then Exit; if MainRecord.Signature <> 'MGEF' then Exit; ActorValue := MainRecord.ElementNativeValues['DATA - Data\Actor Value']; if VarIsNull(ActorValue) or VarIsClear(ActorValue) then Exit; if VarCompareValue(ActorValue, Container.ElementNativeValues['Actor Value']) <> vrEqual then Container.ElementNativeValues['Actor Value'] := ActorValue; finally wbEndInternalEdit; end; end; procedure wbRPLDAfterLoad(const aElement: IwbElement); var Container: IwbContainer; a, b: Single; NeedsFlip: Boolean; begin if wbBeginInternalEdit then try if Supports(aElement, IwbContainer, Container) then begin NeedsFlip := False; if Container.ElementCount > 1 then begin a := StrToFloat((Container.Elements[0] as IwbContainer).Elements[0].Value); b := StrToFloat((Container.Elements[Pred(Container.ElementCount)] as IwbContainer).Elements[0].Value); case CompareValue(a, b) of EqualsValue: begin a := StrToFloat((Container.Elements[0] as IwbContainer).Elements[1].Value); b := StrToFloat((Container.Elements[Pred(Container.ElementCount)] as IwbContainer).Elements[1].Value); NeedsFlip := CompareValue(a, b) = GreaterThanValue; end; GreaterThanValue: NeedsFlip := True; end; end; if NeedsFlip then Container.ReverseElements; end; finally wbEndInternalEdit; end; end; procedure wbLLEAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; Entries : IwbContainerElementRef; MainRecord : IwbMainRecord; i : integer; begin if wbBeginInternalEdit then try // zero entries' Chance None if Form Version < 69 if wbFormVerDecider(nil, nil, aElement, 69) = 1 then Exit; if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; if not Supports(MainRecord.ElementByName['Leveled List Entries'], IwbContainerElementRef, Entries) then Exit; for i := 0 to Pred(Entries.ElementCount) do begin if not Supports(Entries.Elements[i], IwbContainerElementRef, Container) then Exit; Container.ElementNativeValues['LVLO\Chance None'] := 0; end; finally wbEndInternalEdit; end; end; function wbPubPackCNAMDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var rANAM: IwbRecord; ctype: string; begin Result := 0; rANAM := aElement.Container.RecordBySignature[ANAM]; if Assigned(rANAM) then begin ctype := rANAM.NativeValue; if ctype = 'Bool' then Result := 1 else if ctype = 'Int' then Result := 2 else if ctype = 'Float' then Result := 3 else if ctype = 'ObjectList' then Result := 3; end; end; function wbTypeDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; Element : IwbElement; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; Element := Container.ElementByName['Type']; if Assigned(Element) then Result := Element.NativeValue else if wbMoreInfoForDecider then wbProgressCallback('"'+Container.Name+'" does not contain an element named Type'); end; procedure wbCNTOsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterAfterSet('COCT - Count', aElement); end; procedure wbContainerAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterContainerAfterSet('COCT - Count', 'Items', aElement); wbCounterContainerAfterSet('KSIZ - Keyword Count', 'KWDA - Keywords', aElement); end; procedure wbSPLOsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterAfterSet('SPCT - Count', aElement); end; procedure wbKWDAsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterAfterSet('KSIZ - Keyword Count', aElement); end; procedure wbNPCAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterContainerAfterSet('COCT - Count', 'Items', aElement); wbCounterContainerAfterSet('SPCT - Count', 'Actor Effects', aElement); wbCounterContainerAfterSet('LLCT - Count', 'Leveled List Entries', aElement); wbCounterContainerAfterSet('KSIZ - Keyword Count', 'KWDA - Keywords', aElement); wbCounterContainerAfterSet('PRKZ - Perk Count', 'Perks', aElement); end; procedure wbRaceAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterContainerAfterSet('SPCT - Count', 'Actor Effects', aElement); wbCounterContainerAfterSet('KSIZ - Keyword Count', 'KWDA - Keywords', aElement); end; procedure wbKeywordsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterContainerAfterSet('KSIZ - Keyword Count', 'KWDA - Keywords', aElement); end; procedure wbLVLOsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterAfterSet('LLCT - Count', aElement); end; procedure wbLLEAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterContainerAfterSet('LLCT - Count', 'Leveled List Entries', aElement); end; procedure wbPRKRsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterAfterSet('PRKZ - Perk Count', aElement); end; procedure wbSMQNQuestsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterAfterSet('QNAM - Quest Count', aElement); end; procedure wbCTDAsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterAfterSet('CITC - Condition Count', aElement); end; procedure wbConditionsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterContainerAfterSet('CITC - Condition Count', 'Conditions', aElement); end; procedure wbCounterEffectsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin // if it is really possible to have both counter effects and multiple data, this is going to be tricky. wbCounterByPathAfterSet('Magic Effect Data\DATA - Data\Counter effect count', aElement); end; procedure wbMGEFAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbKeywordsAfterSet(aElement, aOldValue, aNewValue); wbCounterContainerByPathAfterSet('Magic Effect Data\DATA - Data\Counter effect count', 'Counter Effects', aElement); end; procedure wbTERMDisplayItemsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterAfterSet('BSIZ - Count', aElement); end; procedure wbTERMMenuItemsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterAfterSet('ISIZ - Count', aElement); end; procedure wbSNDRRatesOfFireAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterAfterSet('ITMC - Count', aElement); end; procedure wbNPCActorSoundsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterAfterSet('CS2H - Count', aElement); end; procedure wbMorphPresetsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterAfterSet('MPPC - Count', aElement); end; procedure wbLENSAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterAfterSet('LFSP - Count', aElement); end; procedure wbIDLAsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var Element : IwbElement; Container : IwbContainer; SelfAsContainer : IwbContainer; begin if wbBeginInternalEdit then try if not wbCounterAfterSet('IDLC - Animation Count', aElement) then if Supports(aElement.Container, IwbContainer, Container) then begin Element := Container.ElementByPath['IDLC']; if Assigned(Element) and Supports(aElement, IwbContainer, SelfAsContainer) and (Element.GetNativeValue<>SelfAsContainer.GetElementCount) then Element.SetNativeValue(SelfAsContainer.GetElementCount); end; finally wbEndInternalEdit; end; end; procedure wbAnimationsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var Element : IwbElement; Elems : IwbElement; Container : IwbContainer; begin if wbBeginInternalEdit then try if not wbCounterContainerAfterSet('IDLC - Animation Count', 'IDLA - Animations', aElement) then if Supports(aElement, IwbContainer, Container) then begin Element := Container.ElementByPath['IDLC\Animation Count']; Elems := Container.ElementByName['IDLA - Animations']; if Assigned(Element) and not Assigned(Elems) then if Element.GetNativeValue<>0 then Element.SetNativeValue(0); end; finally wbEndInternalEdit; end; end; function wbOffsetDataColsCounter(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Cardinal; var Container : IwbDataContainer; Element : IwbElement; fResult : Extended; begin Result := 0; if Supports(aElement.Container, IwbDataContainer, Container) and (Container.Name = 'OFST - Offset Data') and Supports(Container.Container, IwbDataContainer, Container) then begin Element := Container.ElementByPath['Object Bounds\NAM0 - Min\X']; if Assigned(Element) then begin fResult := Element.NativeValue; if fResult >= MaxInt then Result := 0 else Result := Trunc(fResult); Element := Container.ElementByPath['Object Bounds\NAM9 - Max\X']; if Assigned(Element) then begin fResult := Element.NativeValue; if fResult >= MaxInt then Result := 1 else Result := Trunc(fResult) - Result + 1; end; end; end; end; procedure wbOMODpropertyAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterAfterSet('Property Count', aElement); end; procedure wbOMODincludeAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterAfterSet('Include Count', aElement); end; procedure wbOMODdataAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterContainerAfterSet('Property Count', 'Properties', aElement); wbCounterContainerAfterSet('Include Count', 'Includes', aElement); end; function wbOMODDataIncludeCounter(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Cardinal; var Container : IwbContainer; begin if Supports(aElement.Container, IwbContainer, Container) then Result := Container.ElementNativeValues['Include Count'] else Result := 0; end; function wbOMODDataPropertyCounter(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Cardinal; var Container : IwbContainer; begin if Supports(aElement.Container, IwbContainer, Container) then Result := Container.ElementNativeValues['Property Count'] else Result := 0; end; function GetObjectModPropertyEnum(const aElement: IwbElement): IwbEnumDef; var MainRecord: IwbMainRecord; rDATA: IwbContainer; Signature: TwbSignature; FormType: Cardinal; begin Result := nil; MainRecord := aElement.ContainingMainRecord; if not Assigned(MainRecord) then Exit; Signature := MainRecord.Signature; if Signature = OMOD then if Supports(MainRecord.ElementBySignature['DATA'], IwbContainer, rDATA) then begin FormType := rDATA.ElementNativeValues['Form Type']; Signature := PwbSignature(@FormType)^; end; if Signature = ARMO then Result := wbArmorPropertyEnum else if Signature = WEAP then Result := wbWeaponPropertyEnum else if Signature = NPC_ then Result := wbActorPropertyEnum; end; function wbObjectModPropertyToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var PropEnum: IwbEnumDef; begin Result := ''; PropEnum := GetObjectModPropertyEnum(aElement); if not Assigned(PropEnum) then case aType of ctToStr, ctToSortKey, ctToEditValue: Result := IntToStr(aInt); end else case aType of ctToStr: Result := PropEnum.ToString(aInt, aElement); ctToSortKey: Result := PropEnum.ToSortKey(aInt, aElement); ctCheck: Result := PropEnum.Check(aInt, aElement); ctToEditValue: Result := PropEnum.ToEditValue(aInt, aElement); ctEditType: Result := 'ComboBox'; ctEditInfo: Result := PropEnum.EditInfo[aInt, aElement]; end; end; function wbObjectModPropertyToInt(const aString: string; const aElement: IwbElement): Int64; var PropEnum: IwbEnumDef; begin PropEnum := GetObjectModPropertyEnum(aElement); if not Assigned(PropEnum) then Result := StrToIntDef(aString, 0) else Result := PropEnum.FromEditValue(aString, aElement); end; function wbOMODDataFunctionTypeDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; ValueType : Integer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; ValueType := Container.ElementNativeValues['Value Type']; case ValueType of 0: Result := 0; 1: Result := 0; 2: Result := 1; 4: Result := 3; 5: Result := 2; 6: Result := 3; end; end; function wbOMODDataPropertyValue1Decider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; ValueType : Integer; PropName : string; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; ValueType := Container.ElementNativeValues['Value Type']; PropName := Container.ElementEditValues['Property']; case ValueType of 0: Result := 1; 1: Result := 2; 2: Result := 3; 4, 6: Result := 4; 5: begin if PropName = 'SoundLevel' then Result := 6 else if PropName = 'StaggerValue' then Result := 7 else if PropName = 'HitBehaviour' then Result := 8 else Result := 5; end; end; end; function wbOMODDataPropertyValue2Decider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; ValueType : Integer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; ValueType := Container.ElementNativeValues['Value Type']; case ValueType of 0: Result := 1; 1: Result := 2; 2: Result := 3; 4: Result := 1; 6: Result := 2; end; end; procedure wbOBTSCombinationsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterAfterSet('OBTE - Count', aElement); end; procedure wbINNRAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterAfterSet('VNAM - Count', aElement); end; function wbCELLCombinedMeshesCounter(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Cardinal; var Container : IwbContainer; begin if Supports(aElement.Container, IwbContainer, Container) then Result := Container.ElementNativeValues['Meshes Count'] else Result := 0; end; procedure wbCELLCombinedMeshesAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterAfterSet('Meshes Count', aElement); end; function wbCELLCombinedRefsCounter(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Cardinal; var Container : IwbContainer; begin // the counter is double of entries (each member of struct is counted) if Supports(aElement.Container, IwbContainer, Container) then Result := Container.ElementNativeValues['References Count'] div 2 else Result := 0; end; procedure wbCELLCombinedRefsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var Element : IwbElement; Container : IwbContainer; SelfAsContainer : IwbContainer; begin // the counter is double of entries (each member of struct is counted) if wbBeginInternalEdit then try if Supports(aElement.Container, IwbContainer, Container) and Supports(aElement, IwbContainer, SelfAsContainer) then begin Element := Container.ElementByName['References Count']; if Assigned(Element) then try if (Element.GetNativeValue <> (SelfAsContainer.GetElementCount * 2)) then Element.SetNativeValue(SelfAsContainer.GetElementCount * 2); except end; end; finally wbEndInternalEdit; end; end; function wbCombinedMeshIDToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Cell: IwbMainRecord; begin Result := IntToHex(aInt, 8); Cell := aElement.ContainingMainRecord; if not Assigned(Cell) then Exit; case aType of ctToStr, ctToEditValue: begin Result := 'Precombined\' + IntToHex(Cell.FormID and $00FFFFFF, 8) + '_' + Result + '_OC.nif'; end; ctCheck: Result := ''; end; end; function wbCombinedMeshIDToInt(const aString: string; const aElement: IwbElement): Int64; var s: string; i: Integer; begin Result := 0; // hex number between first and second underscope i := Pos('_', aString); if i <> 0 then begin s := Copy(aString, i + 1, Length(aString) - i); i := Pos('_', s); if i <> 0 then begin s := Copy(s, 1, i - 1); if Length(s) = 8 then try Result := StrToInt64('$' + s); except end; end; end; end; function wbREFRRecordFlagsDecider(const aElement: IwbElement): Integer; var MainRecord : IwbMainRecord; NameRec : IwbElement; begin Result := 0; if not Assigned(aElement) then Exit; MainRecord := aElement.ContainingMainRecord; if not Assigned(MainRecord) then Exit; NameRec := MainRecord.ElementBySignature[NAME]; if not Assigned(NameRec) then Exit; if not Supports(NameRec.LinksTo, IwbMainRecord, MainRecord) then Exit; if (MainRecord.Signature = ACTI) or (MainRecord.Signature = STAT) or (MainRecord.Signature = SCOL) or (MainRecord.Signature = TREE) then Result := 1 else if (MainRecord.Signature = CONT) or (MainRecord.Signature = TERM) then Result := 2 else if MainRecord.Signature = DOOR then Result := 3 else if MainRecord.Signature = LIGH then Result := 4 else if MainRecord.Signature = MSTT then Result := 5 else if MainRecord.Signature = ADDN then Result := 6 else if (MainRecord.Signature = SCRL) or (MainRecord.Signature = AMMO) or (MainRecord.Signature = ARMO) or (MainRecord.Signature = BOOK) or (MainRecord.Signature = INGR) or (MainRecord.Signature = KEYM) or (MainRecord.Signature = MISC) or (MainRecord.Signature = FURN) or (MainRecord.Signature = WEAP) or (MainRecord.Signature = ALCH) then Result := 7; end; function wbByteColors(const aName: string = 'Color'): IwbStructDef; begin Result := wbStruct(aName, [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]); end; function wbFloatColors(const aName: string = 'Color'): IwbStructDef; begin Result := wbStruct(aName, [ wbFloat('Red', cpNormal, True, 255, 0), wbFloat('Green', cpNormal, True, 255, 0), wbFloat('Blue', cpNormal, True, 255, 0) ]); end; function wbWeatherColors(const aName: string): IwbStructDef; begin Result := wbStruct(aName, [ wbByteColors('Sunrise'), wbByteColors('Day'), wbByteColors('Sunset'), wbByteColors('Night'), wbByteColors('EarlySunrise'), wbByteColors('LateSunrise'), wbByteColors('EarlySunset'), wbByteColors('LateSunset') ], cpNormal, True, nil, 4); end; function wbAmbientColors(const aSignature: TwbSignature; const aName: string = 'Directional Ambient Lighting Colors'): IwbSubRecordDef; overload; begin Result := wbStruct(aSignature, aName, [ wbStruct('Directional', [ wbByteColors('X+'), wbByteColors('X-'), wbByteColors('Y+'), wbByteColors('Y-'), wbByteColors('Z+'), wbByteColors('Z-') ]), wbByteColors('Specular'), wbFloat('Scale') ]) end; function wbAmbientColors(const aName: string = 'Directional Ambient Lighting Colors'): IwbStructDef; overload; begin Result := wbStruct(aName, [ wbStruct('Directional', [ wbByteColors('X+'), wbByteColors('X-'), wbByteColors('Y+'), wbByteColors('Y-'), wbByteColors('Z+'), wbByteColors('Z-') ]), wbByteColors('Specular'), wbFloat('Scale', cpIgnore) ]); end; function wbIntToHexStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; begin case aType of ctToStr, ctToSortKey, ctToEditValue: Result := IntToHex(aInt, 8); else Result := ''; end; end; function wbStrToInt(const aString: string; const aElement: IwbElement): Int64; var s: string; i: integer; begin // ignore anything after space or : i := Pos(' ', aString); if i = 0 then i := Pos(':', aString); if i <> 0 then s := Copy(aString, 1, i - 1) else s := aString; try Result := StrToInt64(s) except Result := 0; end; end; function wbHexStrToInt(const aString: string; const aElement: IwbElement): Int64; var s: string; i: integer; begin // ignore anything after space or : i := Pos(' ', aString); if i = 0 then i := Pos(':', aString); if i <> 0 then s := Copy(aString, 1, i - 1) else s := aString; try Result := StrToInt64('$' + s) except Result := 0; end; end; type TFaceGenFeature = record RaceID : String; Female : Boolean; Entries : array of record Index: Cardinal; Name : String; end; end; PFaceGenFeature = ^TFaceGenFeature; var // cache of race specific face morphs FaceMorphs: array of TFaceGenFeature; // cache of race specific tint layers TintLayers: array of TFaceGenFeature; // cache of race specific morph groups/presets and values MorphValues: array of TFaceGenFeature; function wbMorphValueToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; function GetCached(const aRaceID: string; aFemale: boolean): PFaceGenFeature; var i: integer; begin Result := nil; if Length(MorphValues) <> 0 then for i := Low(MorphValues) to High(MorphValues) do if (MorphValues[i].Female = aFemale) and (MorphValues[i].RaceID = aRaceID) then begin Result := @MorphValues[i]; Break; end; end; var Actor, Race : IwbMainRecord; Element : IwbElement; Container, Entry : IwbContainerElementRef; Container2, Entry2: IwbContainerElementRef; Female, Female2 : Boolean; RaceID, EntryName : string; Cache : PFaceGenFeature; Index : Cardinal; i, j, k : integer; slList : TStringList; begin // defaults case aType of ctToStr, ctToEditValue: Result := IntToHex64(aInt, 8); ctToSortKey: begin Result := IntToHex64(aInt, 8); Exit; end; ctCheck: Result := ''; ctEditType: Result := ''; ctEditInfo: Result := ''; end; Actor := aElement.ContainingMainRecord; if not Assigned(Actor) then Exit; Female := Actor.ElementEditValues['ACBS\Flags\Female'] = '1'; Element := Actor.ElementBySignature['RNAM']; if not Assigned(Element) then Exit; Element := Element.LinksTo; if not Supports(Element, IwbMainRecord, Race) then Exit; Race := Race.WinningOverride; RaceID := Race.EditorID; Cache := GetCached(RaceID, Female); // cache not found, fill with data from RACE if not Assigned(Cache) then begin slList := TStringList.Create; for i := 0 to 1 do begin Female2 := i = 1; SetLength(MorphValues, Succ(Length(MorphValues))); Cache := @MorphValues[Pred(Length(MorphValues))]; Cache.RaceID := RaceID; Cache.Female := Female2; slList.Clear; if not Female2 then Element := Race.ElementByName['Male Morph Groups'] else Element := Race.ElementByName['Female Morph Groups']; // iterate over morph groups if Supports(Element, IwbContainerElementRef, Container) then for j := 0 to Pred(Container.ElementCount) do begin if not Supports(Container.Elements[j], IwbContainerElementRef, Entry) then Break; // group name EntryName := Entry.ElementEditValues['MPGN']; // iterate over morph group presets if not Supports(Entry.ElementByName['Morph Presets'], IwbContainerElementRef, Container2) then Continue; for k := 0 to Pred(Container2.ElementCount) do if Supports(Container2.Elements[k], IwbContainerElementRef, Entry2) then slList.AddObject( EntryName + ' - ' + Entry2.ElementEditValues['MPPN'], TObject(Cardinal(Entry2.ElementNativeValues['MPPI'])) ); end; // append morph values, same for both sexes if Supports(Race.ElementByName['Morph Values'], IwbContainerElementRef, Container) then for j := 0 to Pred(Container.ElementCount) do if Supports(Container.Elements[j], IwbContainerElementRef, Entry) then slList.AddObject( Entry.ElementEditValues['MSM0'] + '/' + Entry.ElementEditValues['MSM1'], TObject(Cardinal(Entry.ElementNativeValues['MSID'])) ); SetLength(Cache.Entries, slList.Count); for j := 0 to Pred(slList.Count) do begin Cache.Entries[j].Index := Cardinal(slList.Objects[j]); Cache.Entries[j].Name := slList[j]; end; end; slList.Free; Cache := GetCached(RaceID, Female); end; if not Assigned(Cache) then Exit; EntryName := ''; Index := Cardinal(aInt); if Length(Cache.Entries) <> 0 then for i := Low(Cache.Entries) to High(Cache.Entries) do if Cache.Entries[i].Index = Index then begin EntryName := Cache.Entries[i].Name; Break; end; case aType of ctToStr: begin if EntryName <> '' then Result := IntToHex64(aInt, 8) + ' ' + EntryName else Result := IntToHex64(aInt, 8) + ' '; end; ctCheck: begin if EntryName = '' then Result := '' else Result := ''; end; ctEditType: Result := 'ComboBox'; ctEditInfo: begin Result := ''; if Length(Cache.Entries) <> 0 then for i := Low(Cache.Entries) to High(Cache.Entries) do begin if Result <> '' then Result := Result + ','; Result := Result + '"' + IntToHex(Cache.Entries[i].Index, 8) + ' ' + Cache.Entries[i].Name + '"'; end; end; end; end; function wbFaceMorphToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; function GetCached(const aRaceID: string; aFemale: boolean): PFaceGenFeature; var i: integer; begin Result := nil; if Length(FaceMorphs) <> 0 then for i := Low(FaceMorphs) to High(FaceMorphs) do if (FaceMorphs[i].Female = aFemale) and (FaceMorphs[i].RaceID = aRaceID) then begin Result := @FaceMorphs[i]; Break; end; end; var Actor, Race : IwbMainRecord; Element : IwbElement; Container, Entry : IwbContainerElementRef; Female, Female2 : Boolean; RaceID, EntryName : string; Cache : PFaceGenFeature; Index : Cardinal; i, j : integer; begin // defaults case aType of ctToStr, ctToEditValue: Result := IntToHex64(aInt, 8); ctToSortKey: begin Result := IntToHex64(aInt, 8); Exit; end; ctCheck: Result := ''; ctEditType: Result := ''; ctEditInfo: Result := ''; end; Actor := aElement.ContainingMainRecord; if not Assigned(Actor) then Exit; Female := Actor.ElementEditValues['ACBS\Flags\Female'] = '1'; Element := Actor.ElementBySignature['RNAM']; if not Assigned(Element) then Exit; Element := Element.LinksTo; if not Supports(Element, IwbMainRecord, Race) then Exit; Race := Race.WinningOverride; RaceID := Race.EditorID; Cache := GetCached(RaceID, Female); // cache not found, fill with data from RACE if not Assigned(Cache) then begin for i := 0 to 1 do begin Female2 := i = 1; SetLength(FaceMorphs, Succ(Length(FaceMorphs))); Cache := @FaceMorphs[Pred(Length(FaceMorphs))]; Cache.RaceID := RaceID; Cache.Female := Female2; if not Female2 then Element := Race.ElementByName['Male Face Morphs'] else Element := Race.ElementByName['Female Face Morphs']; if not Supports(Element, IwbContainerElementRef, Container) then Continue; SetLength(Cache.Entries, Container.ElementCount); for j := 0 to Pred(Container.ElementCount) do begin if not Supports(Container.Elements[j], IwbContainerElementRef, Entry) then Break; Cache.Entries[j].Index := Entry.ElementNativeValues['FMRI']; Cache.Entries[j].Name := Entry.ElementEditValues['FMRN']; end; end; Cache := GetCached(RaceID, Female); end; if not Assigned(Cache) then Exit; EntryName := ''; Index := Cardinal(aInt); if Length(Cache.Entries) <> 0 then for i := Low(Cache.Entries) to High(Cache.Entries) do if Cache.Entries[i].Index = Index then begin EntryName := Cache.Entries[i].Name; Break; end; case aType of ctToStr: begin if EntryName <> '' then Result := IntToHex64(aInt, 8) + ' ' + EntryName else Result := IntToHex64(aInt, 8) + ' '; end; ctCheck: begin if EntryName = '' then Result := '' else Result := ''; end; ctEditType: Result := 'ComboBox'; ctEditInfo: begin Result := ''; if Length(Cache.Entries) <> 0 then for i := Low(Cache.Entries) to High(Cache.Entries) do begin if Result <> '' then Result := Result + ','; Result := Result + '"' + IntToHex(Cache.Entries[i].Index, 8) + ' ' + Cache.Entries[i].Name + '"'; end; end; end; end; function wbTintLayerToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; function GetCached(const aRaceID: string; aFemale: boolean): PFaceGenFeature; var i: integer; begin Result := nil; if Length(TintLayers) <> 0 then for i := Low(TintLayers) to High(TintLayers) do if (TintLayers[i].Female = aFemale) and (TintLayers[i].RaceID = aRaceID) then begin Result := @TintLayers[i]; Break; end; end; var Actor, Race : IwbMainRecord; Element : IwbElement; Container, Entry : IwbContainerElementRef; Container2, Entry2: IwbContainerElementRef; Female, Female2 : Boolean; RaceID, EntryName : string; Cache : PFaceGenFeature; Index : Cardinal; i, j, k : integer; slList : TStringList; begin // defaults case aType of ctToStr, ctToEditValue: Result := IntToStr(aInt); ctToSortKey: begin Result := IntToHex64(aInt, 8); Exit; end; ctCheck: Result := ''; ctEditType: Result := ''; ctEditInfo: Result := ''; end; Actor := aElement.ContainingMainRecord; if not Assigned(Actor) then Exit; Female := Actor.ElementEditValues['ACBS\Flags\Female'] = '1'; Element := Actor.ElementBySignature['RNAM']; if not Assigned(Element) then Exit; Element := Element.LinksTo; if not Supports(Element, IwbMainRecord, Race) then Exit; Race := Race.WinningOverride; RaceID := Race.EditorID; Cache := GetCached(RaceID, Female); // cache not found, fill with data from RACE if not Assigned(Cache) then begin slList := TStringList.Create; for i := 0 to 1 do begin Female2 := i = 1; SetLength(TintLayers, Succ(Length(TintLayers))); Cache := @TintLayers[Pred(Length(TintLayers))]; Cache.RaceID := RaceID; Cache.Female := Female2; if not Female2 then Element := Race.ElementByName['Male Tint Layers'] else Element := Race.ElementByName['Female Tint Layers']; if not Supports(Element, IwbContainerElementRef, Container) then Continue; slList.Clear; // iterate over tint groups for j := 0 to Pred(Container.ElementCount) do if Supports(Container.Elements[j], IwbContainerElementRef, Entry) then // iterate over tint group options if Supports(Entry.ElementByName['Options'], IwbContainerElementRef, Container2) then for k := 0 to Pred(Container2.ElementCount) do if Supports(Container2.Elements[k], IwbContainerElementRef, Entry2) then slList.AddObject( Entry.ElementEditValues['TTGP'] + ' - ' + Entry2.ElementEditValues['TTGP'], TObject(Cardinal(Entry2.ElementNativeValues['TETI\Index'])) ); SetLength(Cache.Entries, slList.Count); for j := 0 to Pred(slList.Count) do begin Cache.Entries[j].Index := Cardinal(slList.Objects[j]); Cache.Entries[j].Name := slList[j]; end; end; slList.Free; Cache := GetCached(RaceID, Female); end; if not Assigned(Cache) then Exit; EntryName := ''; Index := Cardinal(aInt); if Length(Cache.Entries) <> 0 then for i := Low(Cache.Entries) to High(Cache.Entries) do if Cache.Entries[i].Index = Index then begin EntryName := Cache.Entries[i].Name; Break; end; case aType of ctToStr: begin if EntryName <> '' then Result := IntToStr(aInt) + ' ' + EntryName else Result := IntToStr(aInt) + ' '; end; ctCheck: begin if EntryName = '' then Result := '' else Result := ''; end; ctEditType: Result := 'ComboBox'; ctEditInfo: begin Result := ''; if Length(Cache.Entries) <> 0 then for i := Low(Cache.Entries) to High(Cache.Entries) do begin if Result <> '' then Result := Result + ','; Result := Result + '"' + IntToStr(Cache.Entries[i].Index) + ' ' + Cache.Entries[i].Name + '"'; end; end; end; end; var wbRecordFlagsFlags : IwbFlagsDef; procedure DefineFO4a; begin wbNull := wbByteArray('Unused', -255); wbBoolEnum := wbEnum(['False', 'True']); wbLLCT := wbInteger(LLCT, 'Count', itU8, nil, cpBenign); wbCITC := wbInteger(CITC, 'Condition Count', itU32, nil, cpBenign); wbLVLD := wbInteger(LVLD, 'Chance None', itU8, nil, cpNormal, True); wbSPCT := wbInteger(SPCT, 'Count', itU32, nil, cpBenign); wbSPLO := wbFormIDCk(SPLO, 'Actor Effect', [SPEL, LVSP]); wbSPLOs := wbRArrayS('Actor Effects', wbSPLO, cpNormal, False, nil, wbSPLOsAfterSet, nil{wbActorTemplateUseActorEffectList}); wbKSIZ := wbInteger(KSIZ, 'Keyword Count', itU32, nil, cpBenign); wbKWDAs := wbArrayS(KWDA, 'Keywords', wbFormIDCk('Keyword', [KYWD, NULL]), 0, cpNormal, False, nil, wbKWDAsAfterSet); wbReqKWDAs := wbArrayS(KWDA, 'Keywords', wbFormIDCk('Keyword', [KYWD, NULL]), 0, cpNormal, True, nil, wbKWDAsAfterSet); wbKeywords := wbRStruct('Keywords', [ wbKSIZ, wbReqKWDAs ], []); //wbActorValue := wbInteger('Actor Value', itS32, wbActorValueEnum); wbActorValue := wbFormIDCkNoReach('Actor Value', [AVIF, NULL]); wbCOED := wbStructExSK(COED, [2], [0, 1], 'Extra Data', [ {00} wbFormIDCkNoReach('Owner', [NPC_, FACT, NULL]), {04} wbUnion('Global Variable / Required Rank', wbCOEDOwnerDecider, [ wbByteArray('Unused', 4, cpIgnore), wbFormIDCk('Global Variable', [GLOB, NULL]), wbInteger('Required Rank', itS32) ]), {08} wbFloat('Item Condition') ]); wbCNTO := wbRStructExSK([0], [1], 'Item', [ wbStructExSK(CNTO, [0], [1], 'Item', [ wbFormIDCk('Item', sigBaseObjects), wbInteger('Count', itS32) ]), wbCOED ], []); wbCOCT := wbInteger(COCT, 'Count', itU32, nil, cpBenign); wbCNTOs := wbRArrayS('Items', wbCNTO, cpNormal, False, nil, wbCNTOsAfterSet); {>>> When NAME is user defined these will be incorrect <<<} wbBipedObjectEnum := wbEnum([ '30 - Hair Top', '31 - Hair Long', '32 - FaceGen Head', '33 - BODY', '34 - L Hand', '35 - R Hand', '36 - [U] Torso', '37 - [U] L Arm', '38 - [U] R Arm', '39 - [U] L Leg', '40 - [U] R Leg', '41 - [A] Torso', '42 - [A] L Arm', '43 - [A] R Arm', '44 - [A] L Leg', '45 - [A] R Leg', '46 - Headband', '47 - Eyes', '48 - Beard', '49 - Mouth', '50 - Neck', '51 - Ring', '52 - Scalp', '53 - Decapitation', '54 - Unnamed', '55 - Unnamed', '56 - Unnamed', '57 - Unnamed', '58 - Unnamed', '59 - Shield', '60 - Pipboy', '61 - FX' ], [ -1, 'None' ]); wbBipedObjectFlags := wbFlags([ {0x00000001} '30 - Hair Top', {0x00000002} '31 - Hair Long', {0x00000004} '32 - FaceGen Head', {0x00000008} '33 - BODY', {0x00000010} '34 - L Hand', {0x00000020} '35 - R Hand', {0x00000040} '36 - [U] Torso', {0x00000080} '37 - [U] L Arm', {0x00000100} '38 - [U] R Arm', {0x00000200} '39 - [U] L Leg', {0x00000400} '40 - [U] R Leg', {0x00000800} '41 - [A] Torso', {0x00001000} '42 - [A] L Arm', {0x00002000} '43 - [A] R Arm', {0x00004000} '44 - [A] L Leg', {0x00008000} '45 - [A] R Leg', {0x00010000} '46 - Headband', {0x00020000} '47 - Eyes', {0x00040000} '48 - Beard', {0x00080000} '49 - Mouth', {0x00100000} '50 - Neck', {0x00200000} '51 - Ring', {0x00400000} '52 - Scalp', {0x00800000} '53 - Decapitation', {0x01000000} '54 - Unnamed', {0x02000000} '55 - Unnamed', {0x04000000} '56 - Unnamed', {0x08000000} '57 - Unnamed', {0x10000000} '58 - Unnamed', {0x20000000} '59 - Shield', {0x40000000} '60 - Pipboy', {0x80000000} '61 - FX' ], True); wbFirstPersonFlagsU32 := wbInteger('First Person Flags', itU32, wbBipedObjectFlags); wbBOD2 := wbStruct(BOD2, 'Biped Body Template', [ wbFirstPersonFlagsU32 ], cpNormal, False); wbMDOB := wbFormID(MDOB, 'Menu Display Object', cpNormal, False); wbCNAM := wbStruct(CNAM, 'Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unknown', 1) ]); wbDODT := wbStruct(DODT, 'Decal Data', [ wbFloat('Min Width'), wbFloat('Max Width'), wbFloat('Min Height'), wbFloat('Max Height'), wbFloat('Depth'), wbFloat('Shininess'), wbStruct('Parallax', [ wbFloat('Scale'), wbInteger('Passes', itU8) {>>> This can't be higher than 30 <<<} ]), wbInteger('Flags', itU8, wbFlags([ {0x01} 'POM Shadows', {0x02} 'Alpha - Blending', {0x04} 'Alpha - Testing', {0x08} 'No Subtextures' ], True)), wbInteger('Alpha Threshold?', itU16), wbByteColors('Color') ]); // wbRecordFlagsFlags := wbFlags([ // {>>> 0x00000000 ACTI: Collision Geometry (default) <<<} // {0x00000001}'ESM', // {0x00000002}'Unknown 2', // {>>> 0x00000004 ARMO: Not playable <<<} // {0x00000004}'NotPlayable', // {0x00000008}'Unknown 4', // {0x00000010}'Unknown 5', // {0x00000020}'Deleted', // {>>> 0x00000040 ACTI: Has Tree LOD <<<} // {>>> 0x00000040 REGN: Border Region <<<} // {>>> 0x00000040 STAT: Has Tree LOD <<<} // {>>> 0x00000040 REFR: Hidden From Local Map <<<} // {0x00000040}'Constant HiddenFromLocalMap BorderRegion HasTreeLOD', // {>>> 0x00000080 TES4: Localized <<<} // {>>> 0x00000080 PHZD: Turn Off Fire <<<} // {>>> 0x00000080 SHOU: Treat Spells as Powers <<<} // {>>> 0x00000080 STAT: Add-on LOD Object <<<} // {0x00000080}'Localized IsPerch AddOnLODObject TurnOffFire TreatSpellsAsPowers', // {>>> 0x00000100 ACTI: Must Update Anims <<<} // {>>> 0x00000100 REFR: Inaccessible <<<} // {>>> 0x00000100 REFR for LIGH: Doesn't light water <<<} // {0x00000100}'MustUpdateAnims Inaccessible DoesntLightWater', // {>>> 0x00000200 ACTI: Local Map - Turns Flag Off, therefore it is Hidden <<<} // {>>> 0x00000200 REFR: MotionBlurCastsShadows <<<} // {0x00000200}'HiddenFromLocalMap StartsDead MotionBlurCastsShadows', // {>>> 0x00000400 LSCR: Displays in Main Menu <<<} // {0x00000400}'PersistentReference QuestItem DisplaysInMainMenu', // {0x00000800}'InitiallyDisabled', // {0x00001000}'Ignored', // {0x00002000}'ActorChanged', // {0x00004000}'Unknown 15', // {>>> 0x00008000 STAT: Has Distant LOD <<<} // {0x00008000}'VWD', // {>>> 0x00010000 ACTI: Random Animation Start <<<} // {>>> 0x00010000 REFR light: Never fades <<<} // {0x00010000}'RandomAnimationStart NeverFades', // {>>> 0x00020000 ACTI: Dangerous <<<} // {>>> 0x00020000 REFR light: Doesn't light landscape <<<} // {>>> 0x00020000 SLGM: Can hold NPC's soul <<<} // {>>> 0x00020000 STAT: Use High-Detail LOD Texture <<<} // {0x00020000}'Dangerous OffLimits DoesntLightLandscape HighDetailLOD CanHoldNPC', // {0x00040000}'Compressed', // {>>> 0x00080000 STAT: Has Currents <<<} // {0x00080000}'CantWait HasCurrents', // {>>> 0x00100000 ACTI: Ignore Object Interaction <<<} // {0x00100000}'IgnoreObjectInteraction', // {0x00200000}'(Used in Memory Changed Form)', // {0x00400000}'Unknown 23', // {>>> 0x00800000 ACTI: Is Marker <<<} // {0x00800000}'IsMarker', // {0x01000000}'Unknown 25', // {>>> 0x02000000 ACTI: Obstacle <<<} // {>>> 0x02000000 REFR: No AI Acquire <<<} // {0x02000000}'Obstacle NoAIAcquire', // {>>> 0x04000000 ACTI: Filter <<<} // {0x04000000}'NavMeshFilter', // {>>> 0x08000000 ACTI: Bounding Box <<<} // {0x08000000}'NavMeshBoundingBox', // {>>> 0x10000000 STAT: Show in World Map <<<} // {0x10000000}'MustExitToTalk ShowInWorldMap', // {>>> 0x20000000 ACTI: Child Can Use <<<} // {>>> 0x20000000 REFR: Don't Havok Settle <<<} // {0x20000000}'ChildCanUse DontHavokSettle', // {>>> 0x40000000 ACTI: GROUND <<<} // {>>> 0x40000000 REFR: NoRespawn <<<} // {0x40000000}'NavMeshGround NoRespawn', // {>>> 0x80000000 REFR: MultiBound <<<} // {0x80000000}'MultiBound' // ], [18]); wbRecordFlagsFlags := wbFlags(wbRecordFlagsFlags, [ {0x00000001} { 0} 'Unknown 0', {0x00000002} { 1} 'Unknown 1', {0x00000004} { 2} 'Unknown 2', {0x00000008} { 3} 'Unknown 3', {0x00000010} { 4} 'Unknown 4', {0x00000020} { 4} 'Unknown 5', {0x00000040} { 6} 'Unknown 6', {0x00000080} { 7} 'Unknown 7', {0x00000100} { 8} 'Unknown 8', {0x00000200} { 9} 'Unknown 9', {0x00000400} {10} 'Unknown 10', {0x00000800} {11} 'Unknown 11', {0x00001000} {12} 'Unknown 12', {0x00002000} {13} 'Unknown 13', {0x00004000} {14} 'Unknown 14', {0x00008000} {15} 'Unknown 15', {0x00010000} {16} 'Unknown 16', {0x00020000} {17} 'Unknown 17', {0x00040000} {18} 'Unknown 18', {0x00080000} {19} 'Unknown 19', {0x00100000} {20} 'Unknown 20', {0x00200000} {21} 'Unknown 21', {0x00400000} {22} 'Unknown 22', {0x00800000} {23} 'Unknown 23', {0x01000000} {24} 'Unknown 24', {0x02000000} {25} 'Unknown 25', {0x04000000} {26} 'Unknown 26', {0x08000000} {27} 'Unknown 27', {0x10000000} {28} 'Unknown 28', {0x20000000} {29} 'Unknown 29', {0x40000000} {30} 'Unknown 30', {0x80000000} {31} 'Unknown 31' ]); wbRecordFlags := wbInteger('Record Flags', itU32, wbFlags(wbRecordFlagsFlags, wbFlagsList([]))); wbMainRecordHeader := wbStruct('Record Header', [ wbString('Signature', 4, cpCritical), wbInteger('Data Size', itU32, nil, cpIgnore), wbRecordFlags, wbFormID('FormID', cpFormID), wbByteArray('Version Control Info 1', 4, cpIgnore), wbInteger('Form Version', itU16, nil, cpIgnore), wbByteArray('Version Control Info 2', 2, cpIgnore) ]); wbSizeOfMainRecordStruct := 24; wbIgnoreRecords.Add(XXXX); wbXRGD := wbByteArray(XRGD, 'Ragdoll Data'); wbXRGB := wbByteArray(XRGB, 'Ragdoll Biped Data'); wbMusicEnum := wbEnum(['Default', 'Public', 'Dungeon']); wbSoundLevelEnum := wbEnum([ 'Loud', 'Normal', 'Silent', 'Very Loud', 'Quiet' ]); wbEntryPointsEnum := wbEnum([ { 0} 'Mod Breath Timer', { 1} 'Mod My Critical Hit Chance', { 2} 'Mod My Critical Hit Damage Mult', { 3} 'Mod Mine Explode Chance', { 4} 'Mod Incoming Limb Damage', { 5} 'Mod Book Actor Value Bonus', { 6} 'Mod Recovered Health', { 7} 'Set Should Attack', { 8} 'Mod Buy Prices', { 9} 'Add Leveled List On Death', {10} 'Set Max Carry Weight', {11} 'Mod Addiction Chance', {12} 'Mod Addiction Duration', {13} 'Mod Positive Chem Duration', {14} 'Activate', {15} 'Ignore Running During Detection', {16} 'Ignore Broken Lock', {17} 'Mod Enemy Critical Hit Chance', {18} 'Mod Sneak Attack Mult', {19} 'Mod Max Placeable Mines', {20} 'Mod Bow Zoom', {21} 'Mod Recover Arrow Chance', {22} 'Mod Exp', {23} 'Mod Telekinesis Distance', {24} 'Mod Telekinesis Damage Mult', {25} 'Mod Telekinesis Damage', {26} 'Mod Bashing Damage', {27} 'Mod Power Attack Action Points', {28} 'Mod Power Attack Damage', {29} 'Mod Spell Magnitude', {30} 'Mod Spell Duration', {31} 'Mod Secondary Value Weight', {32} 'Mod Armor Weight', {33} 'Mod Incoming Stagger', {34} 'Mod Target Stagger', {35} 'Mod Weapon Attack Damage', {36} 'Mod Incoming Weapon Damage', {37} 'Mod Target Damage Resistance', {38} 'Mod Spell Cost', {39} 'Mod Percent Blocked', {40} 'Mod Shield Deflect Arrow Chance', {41} 'Mod Incoming Spell Magnitude', {42} 'Mod Incoming Spell Duration', {43} 'Mod Player Intimidation', {44} 'Mod Ricochet Chance', {45} 'Mod Ricochet Damage', {46} 'Mod Bribe Amount', {47} 'Mod Detection Light', {48} 'Mod Detection Movement', {49} 'Mod Scrap Reward Mult', {50} 'Set Sweep Attack', {51} 'Apply Combat Hit Spell', {52} 'Apply Bashing Spell', {53} 'Apply Reanimate Spell', {54} 'Set Boolean Graph Variable', {55} 'Mod Spell Casting Sound Event', {56} 'Mod Pickpocket Chance', {57} 'Mod Detection Sneak Skill', {58} 'Mod Falling Damage', {59} 'Mod Lockpick Sweet Spot', {60} 'Mod Sell Prices', {61} 'Set Pickpocket Equipped Item', {62} 'Set Player Gate Lockpick', {63} 'Set Lockpick Starting Arc', {64} 'Set Progression Picking', {65} 'Set Lockpicks Unbreakable', {66} 'Mod Alchemy Effectiveness', {67} 'Apply Weapon Swing Spell', {68} 'Mod Commanded Actor Limit', {69} 'Apply Sneaking Spell', {70} 'Mod Player Magic Slowdown', {71} 'Mod Ward Magicka Absorption Pct', {72} 'Mod Initial Ingredient Effects Learned', {73} 'Purify Alchemy Ingredients', {74} 'Set Filter Activation', {75} 'Set Dual Cast', {76} 'Mod Outgoing Explosion Limb Damage', {77} 'Mod Enchantment Power', {78} 'Mod Soul Pct Captured to Weapon', {79} 'Mod VATS Attack Action Points', {80} 'Mod Reflect Damage Chance', {81} 'Set Activate Label', {82} 'Mod Kill Experience', {83} 'Mod Poison Dose Count', {84} 'Set Apply Placed Item', {85} 'Mod Armor Rating', {86} 'Mod lockpicking crime chance', {87} 'Mod ingredients harvested', {88} 'Mod Spell Range (Target Loc.)', {89} 'Mod Critical Charge Mult on Ricochet', {90} 'Mod lockpicking key reward chance', {91} 'Mod Auto Lockpicking Chance', {92} 'Mod Auto Hacking Chance', {93} 'Mod Typed Weapon Attack Damage', {94} 'Mod Typed Incoming Weapon Damage', {95} 'Mod Charisma Challenge Chance', {96} 'Mod Sprint AP Drain Rate', {97} 'Mod Drawn Weapon Weight Speed Effect', {98} 'Set Player Gate Hacking', {99} 'Mod Player Explosion Damage', {100} 'Mod Player Explosion Scale', {101} 'Set Rads To Health Mult', {102} 'Mod Actor Scope Stability', {103} 'Mod Actor Grenade Speed Mult', {104} 'Mod Explosion Force', {105} 'Mod VATS Penetration Min Visibility', {106} 'Mod Rads for Rad Health Max', {107} 'Mod VATS Player AP On Kill Chance', {108} 'Set VATS Fill Critical Bar On Hit', {109} 'Mod VATS Concentrated Fire Chance Bonus', {110} 'Mod VATS Critical Count', {111} 'Mod VATS Hold Em Steady Bonus', {112} 'Mod Typed Spell Magnitude', {113} 'Mod Typed Incoming Spell Magnitude', {114} 'Set VATS Gun-Fu Num Targets For Crits', {115} 'Mod Outgoing Limb Damage', {116} 'Mod Restore Action Cost Value', {117} 'Mod VATS Reload Action Points', {118} 'Mod Incoming Battery Damage', {119} 'Mod VATS Critical Charge', {120} 'Mod Exp Location', {121} 'Mod Exp Speech', {122} 'Mod VATS Head Shot Chance', {123} 'Mod VATS Hit Chance', {124} 'Mod Incoming Explosion Damage', {125} 'Mod Ammo Health Mult', {126} 'Mod Hacking Guesses', {127} 'Mod Terminal Lockout Time', {128} 'Set Undetectable', {129} 'Invest In Vendor', {130} 'Mod Outgoing Limb Bash Damage', {131} 'Set Run While Over Encumbered', {132} 'Get Component Radar Distance', {133} 'Show Grenade Trajectory', {134} 'Mod Cone-of-fire Mult', {135} 'Mod VATS Concentrated Fire Damage Mult', {136} 'Apply Bloody Mess Spell', {137} 'Mod VATS Critical Fill Chance On Bank', {138} 'Mod VATS Critical Fill Chance On Use', {139} 'Set VATS Critical Fill On AP Reward', {140} 'Set VATS Critical Fill On Stranger', {141} 'Mod Gun Range Mult', {142} 'Mod Scope Hold Breath AP Drain Mult', {143} 'Set Force Decapitate', {144} 'Mod VATS Shoot Explosive Damage Mult', {145} 'Mod Scrounger Fill Ammo Chance', {146} 'Set Can Explode Pants', {147} 'Set VATS Penetration Full Damage', {148} 'Mod VATS Gun-Fu 2nd Target Dmg Mult', {149} 'Mod VATS Gun-Fu 3rd Target Dmg Mult', {150} 'Mod VATS Gun-Fu 4th+ Target Dmg Mult', {151} 'Mod VATS Blitz Max Distance', {152} 'Set VATS Blitz Max Dmg Mult', {153} 'Mod VATS Blitz Dmg Bonus Dist', {154} 'Mod Bash Critical Chance', {155} 'VATS Apply Paralyzing Palm Spell', {156} 'Null Function' ]); wbEquipType := wbFlags([ {0x00000001} 'Hand To Hand Melee', {0x00000002} 'One Hand Sword', {0x00000004} 'One Hand Dagger', {0x00000008} 'One Hand Axe', {0x00000010} 'One Hand Mace', {0x00000020} 'Two Hand Sword', {0x00000040} 'Two Hand Axe', {0x00000080} 'Bow', {0x00000100} 'Staff', {0x00000200} 'Gun', {0x00000400} 'Grenade', {0x00000800} 'Mine', {0x00001000} 'Spell', {0x00002000} 'Shield', {0x00004000} 'Torch' ], True); wbEmotionTypeEnum := wbEnum([ {0} 'Neutral', {1} 'Anger', {2} 'Disgust', {3} 'Fear', {4} 'Sad', {5} 'Happy', {6} 'Surprise', {7} 'Puzzled' ]); wbFurnitureAnimTypeEnum := wbEnum([ {0} '', {1} 'Sit', {2} 'Lay', {3} '', {4} 'Lean' ]); wbFurnitureEntryTypeFlags := wbFlags([ {0x01} 'Front', {0x02} 'Behind', {0x04} 'Right', {0x08} 'Left', {0x10} 'Up' ]); wbWardStateEnum := wbEnum([ 'None', 'Absorb', 'Break' ]); wbEventFunctionEnum := wbEnum([ 'GetIsID', 'IsInList', 'GetValue', 'HasKeyword', 'GetItemValue' ]); // Event member names and availability are different depending on event type // Using generic names for the last 3 of them: Form, Value1, Value2 wbEventMemberEnum := wbEnum([], [ $0000, 'None', $314F, 'CreatedObject', $314C, '(Old)Location', $324C, '(New)Location', $314B, 'Keyword', $3146, 'Form', $3156, 'Value1', $3256, 'Value2' ]); wbWeaponAnimTypeEnum := wbEnum([ {0} 'HandToHandMelee', {1} 'OneHandSword', {2} 'OneHandDagger', {3} 'OneHandAxe', {4} 'OneHandMace', {5} 'TwoHandSword', {6} 'TwoHandAxe', {7} 'Bow', {8} 'Staff', {9} 'Crossbow' ]); wbReverbClassEnum := wbEnum([ 'Default', 'Class A', 'Class B', 'Class C', 'Class D', 'Class E' ]); wbHitBehaviourEnum := wbEnum([ 'Normal formula behaviour', 'Dismember only', 'Explode only', 'No dismember/explode' ]); wbEDID := wbString(EDID, 'Editor ID', 0, cpNormal); // not cpBenign according to Arthmoor wbFULL := wbLStringKC(FULL, 'Name', 0, cpTranslate); wbFULLActor := wbLStringKC(FULL, 'Name', 0, cpTranslate, False, nil{wbActorTemplateUseBaseData}); wbFULLReq := wbLStringKC(FULL, 'Name', 0, cpTranslate, True); wbDESC := wbLStringKC(DESC, 'Description', 0, cpTranslate); wbDESCReq := wbLStringKC(DESC, 'Description', 0, cpTranslate, True); wbXSCL := wbFloat(XSCL, 'Scale'); wbOBND := wbStruct(OBND, 'Object Bounds', [ wbInteger('X1', itS16), wbInteger('Y1', itS16), wbInteger('Z1', itS16), wbInteger('X2', itS16), wbInteger('Y2', itS16), wbInteger('Z2', itS16) ]); wbOBNDReq := wbStruct(OBND, 'Object Bounds', [ wbInteger('X1', itS16), wbInteger('Y1', itS16), wbInteger('Z1', itS16), wbInteger('X2', itS16), wbInteger('Y2', itS16), wbInteger('Z2', itS16) ], cpNormal, True); wbPropTypeEnum := wbEnum([ {00} 'None', {01} 'Object', {02} 'String', {03} 'Int32', {04} 'Float', {05} 'Bool', {06} 'Variable', {07} 'Struct', {08} '', {09} '', {10} '', {11} 'Array of Object', {12} 'Array of String', {13} 'Array of Int32', {14} 'Array of Float', {15} 'Array of Bool', {16} 'Array of Variable', {17} 'Array of Struct' ]); wbScriptFlags := wbInteger('Flags', itU8, wbEnum([ {0x00} 'Local', {0x01} 'Inherited', {0x02} 'Removed', {0x03} 'Inherited and Removed' ])); wbScriptPropertyObject := wbUnion('Object Union', wbScriptObjFormatDecider, [ wbStructSK([1], 'Object v2', [ wbInteger('Unused', itU16, nil, cpIgnore), wbInteger('Alias', itS16, wbScriptObjectAliasToStr, wbStrToAlias), wbFormID('FormID') ], [2, 1, 0]), wbStructSK([1], 'Object v1', [ wbFormID('FormID'), wbInteger('Alias', itS16, wbScriptObjectAliasToStr, wbStrToAlias), wbInteger('Unused', itU16, nil, cpIgnore) ]) ]); wbScriptPropertyStruct := wbArrayS('Struct', wbStructSK([0], 'Member', [ wbLenString('memberName', 2), wbInteger('Type', itU8, wbPropTypeEnum, cpNormal, False, nil, wbScriptPropertyTypeAfterSet), wbInteger('Flags', itU8, wbEnum([ {0x00} '', {0x01} 'Edited', {0x02} '', {0x03} 'Removed' ])), wbUnion('Value', wbScriptPropertyStructMemberDecider, [ {00} wbNull, {01} wbScriptPropertyObject, {02} wbLenString('String', 2), {03} wbInteger('Int32', itS32), {04} wbFloat('Float'), {05} wbInteger('Bool', itU8, wbBoolEnum), {11} wbArray('Array of Object', wbScriptPropertyObject, -1), {12} wbArray('Array of String', wbLenString('Element', 2), -1), {13} wbArray('Array of Int32', wbInteger('Element', itS32), -1), {14} wbArray('Array of Float', wbFloat('Element'), -1), {15} wbArray('Array of Bool', wbInteger('Element', itU8, wbBoolEnum), -1) ]) ]), -1, cpNormal, False); wbScriptProperties := wbArrayS('Properties', wbStructSK([0], 'Property', [ wbLenString('propertyName', 2), wbInteger('Type', itU8, wbPropTypeEnum, cpNormal, False, nil, wbScriptPropertyTypeAfterSet), wbInteger('Flags', itU8, wbEnum([ {0x00} '', {0x01} 'Edited', {0x02} '', {0x03} 'Removed' ])), wbUnion('Value', wbScriptPropertyDecider, [ {00} wbNull, {01} wbScriptPropertyObject, {02} wbLenString('String', 2), {03} wbInteger('Int32', itS32), {04} wbFloat('Float'), {05} wbInteger('Bool', itU8, wbBoolEnum), {06} wbScriptPropertyStruct, // Variable. No idea if possible or how to decode, leaving like that for the moment {07} wbScriptPropertyStruct, {11} wbArray('Array of Object', wbScriptPropertyObject, -1), {12} wbArray('Array of String', wbLenString('Element', 2), -1), {13} wbArray('Array of Int32', wbInteger('Element', itS32), -1), {14} wbArray('Array of Float', wbFloat('Element'), -1), {15} wbArray('Array of Bool', wbInteger('Element', itU8, wbBoolEnum), -1), {17} wbArray('Array of Struct', wbScriptPropertyStruct, -1) ]) ]), -2, cpNormal, False, nil, nil, nil, False); wbScriptEntry := wbStructSK([0], 'Script', [ wbLenString('scriptName', 2), wbScriptFlags, wbScriptProperties ]); wbScriptFragmentsInfo := wbStruct('Script Fragments', [ wbInteger('Unknown', itS8), wbInteger('Flags', itU8, wbFlags([ {1} 'OnBegin', {2} 'OnEnd' ])), wbScriptEntry, wbArray('Fragments', // Do NOT sort, ordered OnBegin, OnEnd wbStruct('Fragment', [ wbInteger('Unknown', itS8), wbLenString('scriptName', 2), wbLenString('fragmentName', 2) ]), [], wbScriptFragmentsInfoCounter) ]); wbScriptFragmentsPack := wbStruct('Script Fragments', [ wbInteger('Unknown', itS8), wbInteger('Flags', itU8, wbFlags([ {1} 'OnBegin', {2} 'OnEnd', {4} 'OnChange' ])), wbScriptEntry, wbArray('Fragments', // Do NOT sort, ordered OnBegin, OnEnd, OnChange wbStruct('Fragment', [ wbInteger('Unknown', itS8), wbLenString('scriptName', 2), wbLenString('fragmentName', 2) ]), [], wbScriptFragmentsPackCounter) ]); wbScriptFragmentsQuest := wbStruct('Script Fragments', [ wbInteger('Unknown', itS8), wbInteger('fragmentCount', itU16), wbLenString('scriptName', 2), // if scriptName = "" then no Flags and Properties wbUnion('Script', wbScriptFragmentsEmptyScriptDecider, [ wbStruct('Script Data', [ wbScriptFlags, wbScriptProperties ]), // Quest [000179EF] // Quest [000792CA] "Merchant Dialogue System" // Quest [00091FE1] // MQ101KelloggSequence "Kellogg Sequence in Vault 111" [QUST:000D3997] // DialogueGlowingSeaAtom "Children of the Atom Dialogue" [QUST:0012DB31] // BoSIdleHandlerQuest [QUST:00157460] wbNull ]), wbArrayS('Fragments', wbStructSK([0, 2], 'Fragment', [ wbInteger('Quest Stage', itU16), wbInteger('Unknown', itS16), wbInteger('Quest Stage Index', itS32), wbInteger('Unknown', itS8), wbLenString('scriptName', 2), wbLenString('fragmentName', 2) ]), wbScriptFragmentsQuestCounter) ]); wbScriptFragmentsScen := wbStruct('Script Fragments', [ wbInteger('Unknown', itS8), wbInteger('Flags', itU8, wbFlags([ {1} 'OnBegin', {2} 'OnEnd' ])), wbScriptEntry, wbArray('Fragments', // Do NOT sort, ordered OnBegin, OnEnd wbStruct('Fragment', [ wbInteger('Unknown', itS8), wbLenString('scriptName', 2), wbLenString('fragmentName', 2) ]), [], wbScriptFragmentsSceneCounter), wbArray('Phase Fragments', wbStructSK([0, 1], 'Phase Fragment', [ wbInteger('Phase Flag', itU8, wbFlags([ {1} 'OnStart', {2} 'OnCompletion' ])), wbInteger('Phase Index', itU8), wbInteger('Unknown', itS16), wbInteger('Unknown', itS8), wbInteger('Unknown', itS8), wbLenString('scriptName', 2), wbLenString('fragmentName', 2) ]), -2) ]); wbScriptFragments := wbStruct('Script Fragments', [ wbInteger('Unknown', itS8), wbScriptEntry, wbArrayS('Fragments', wbStructSK([0], 'Fragment', [ wbInteger('Fragment Index', itU16), wbInteger('Unknown', itS16), wbInteger('Unknown', itS8), wbLenString('scriptName', 2), wbLenString('fragmentName', 2) ]), -2) ]); {>>> http://www.uesp.net/wiki/Tes5Mod:Mod_File_Format/VMAD_Field <<<} wbVMAD := wbStruct(VMAD, 'Virtual Machine Adapter', [ wbInteger('Version', itS16, nil, cpIgnore), wbInteger('Object Format', itS16, nil, cpIgnore), wbArrayS('Scripts', wbScriptEntry, -2, cpNormal, False, nil, nil, nil, False) ]); wbVMADFragmentedPERK := wbStruct(VMAD, 'Virtual Machine Adapter', [ wbInteger('Version', itS16, nil, cpIgnore), wbInteger('Object Format', itS16, nil, cpIgnore), wbArrayS('Scripts', wbScriptEntry, -2, cpNormal, False, nil, nil, nil, False), wbScriptFragments ], cpNormal, False, nil, 3); wbVMADFragmentedPACK := wbStruct(VMAD, 'Virtual Machine Adapter', [ wbInteger('Version', itS16, nil, cpIgnore), wbInteger('Object Format', itS16, nil, cpIgnore), wbArrayS('Scripts', wbScriptEntry, -2, cpNormal, False, nil, nil, nil, False), wbScriptFragmentsPack ], cpNormal, False, nil, 3); wbVMADFragmentedQUST := wbStruct(VMAD, 'Virtual Machine Adapter', [ wbInteger('Version', itS16, nil, cpIgnore), wbInteger('Object Format', itS16, nil, cpIgnore), wbArrayS('Scripts', wbScriptEntry, -2, cpNormal, False, nil, nil, nil, False), wbScriptFragmentsQuest, wbArrayS('Aliases', wbStructSK([0], 'Alias', [ wbScriptPropertyObject, wbInteger('Version', itS16, nil, cpIgnore), wbInteger('Object Format', itS16, nil, cpIgnore), wbArrayS('Alias Scripts', wbScriptEntry, -2) ]), -2) ], cpNormal, False, nil, 3); wbVMADFragmentedSCEN := wbStruct(VMAD, 'Virtual Machine Adapter', [ wbInteger('Version', itS16, nil, cpIgnore), wbInteger('Object Format', itS16, nil, cpIgnore), wbArrayS('Scripts', wbScriptEntry, -2, cpNormal, False, nil, nil, nil, False), wbScriptFragmentsScen ], cpNormal, False, nil, 3); wbVMADFragmentedINFO := wbStruct(VMAD, 'Virtual Machine Adapter', [ wbInteger('Version', itS16, nil, cpIgnore), wbInteger('Object Format', itS16, nil, cpIgnore), wbArrayS('Scripts', wbScriptEntry, -2, cpNormal, False, nil, nil, nil, False), wbScriptFragmentsInfo ], cpNormal, False, nil, 3); wbAttackData := wbRStructSK([1], 'Attack', [ wbStruct(ATKD, 'Attack Data', [ wbFloat('Damage Mult'), wbFloat('Attack Chance'), wbFormIDCk('Attack Spell', [SPEL, NULL]), wbInteger('Attack Flags', itU32, wbFlags([ {0x00000001} 'Ignore Weapon', {0x00000002} 'Bash Attack', {0x00000004} 'Power Attack', {0x00000008} 'Charge Attack', {0x00000010} 'Rotating Attack', {0x00000020} 'Continuous Attack', {0x00000040} 'Unknown 6', {0x00000080} 'Unknown 7', {0x00000100} 'Unknown 8', {0x00000200} 'Unknown 9', {0x00000400} 'Unknown 10', {0x00000800} 'Unknown 11', {0x00001000} 'Unknown 12', {0x00002000} 'Unknown 13', {0x00004000} 'Unknown 14', {0x00008000} 'Unknown 15', {0x00010000} 'Unknown 16', {0x00020000} 'Unknown 17', {0x00040000} 'Unknown 18', {0x00080000} 'Unknown 19', {0x00100000} 'Unknown 20', {0x00200000} 'Unknown 21', {0x00400000} 'Unknown 22', {0x00800000} 'Unknown 23', {0x01000000} 'Unknown 24', {0x02000000} 'Unknown 25', {0x04000000} 'Unknown 26', {0x08000000} 'Unknown 27', {0x10000000} 'Unknown 28', {0x20000000} 'Unknown 29', {0x40000000} 'Unknown 30', {0x80000000} 'Override Data' ])), wbFloat('Attack Angle'), wbFloat('Strike Angle'), wbFloat('Stagger'), wbFloat('Knockdown'), wbFloat('Recovery Time'), wbFloat('Action Points Mult'), wbInteger('Stagger Offset', itS32) ]), wbString(ATKE, 'Attack Event'), wbFormIDCk(ATKW, 'Weapon Slot', [EQUP]), wbFormIDCk(ATKS, 'Required Slot', [EQUP]), wbString(ATKT, 'Description') ], []); wbLocationEnum := wbEnum([ {0} 'Near reference', // string dump: '%s' in '%s' radius %u {1} 'In cell', // string dump: In cell '%s' {2} 'Near package start location', // string dump: Near package start location, radius %u {3} 'Near editor location', // string dump: Near editor location, radius %u {4} 'Object ID', {5} 'Object Type', {6} 'Near linked reference', // string dump: Near linked reference, radius %u%s%s {7} 'At package location', // string dump: At package location, radius %u {8} 'Alias (reference)', // string dump: Alias: %s [item #%u], radius %u {9} 'Alias (location)', // string dump: Alias: %s, radius %u {10} 'Target', // string dump: {11} 'Target (location)', // string dump: Target: %s, radius %u {12} 'Near self', // Near Self, radius %u {13} 'Near Editor Location Cell', {14} 'Alias (ref collection)' ]); wbObjectTypeEnum := wbEnum([ { 0} ' NONE', { 1} 'Activators', { 2} 'Armor', { 3} 'Books', { 4} 'Containers', { 5} 'Doors', { 6} 'Ingredients', { 7} 'Lights', { 8} 'Miscellaneous', { 9} 'Flora', {10} 'Furniture', {11} 'Weapons: Any', {12} 'Ammo', {13} 'Keys', {14} 'Alchemy', {15} 'Food', {16} 'Clothing', {17} 'All: Wearable', {18} 'Weapons: NONE', {19} 'Weapons: Melee', {20} 'Weapons: Ranged', {21} 'Spells: Any', {22} 'Spells: Range Target', {23} 'Spells: Range Touch', {24} 'Spells: Range Self', {25} 'Actors: Any', {26} 'Furniture: Beds', {27} 'Furniture: Chairs', {28} 'Shouts', {29} 'Headtrack Markers' ]); wbPLDT := wbStruct(PLDT, 'Location', [ wbInteger('Type', itS32, wbLocationEnum), wbUnion('Location Value', wbTypeDecider, [ {0} wbFormIDCkNoReach('Reference', sigReferences), {1} wbFormIDCkNoReach('Cell', [NULL, CELL]), {2} wbByteArray('Near Package Start Location', 4, cpIgnore), {3} wbByteArray('Near Editor Location', 4, cpIgnore), {4} wbFormIDCkNoReach('Object ID', [NULL, ACTI, DOOR, STAT, MSTT, FURN, SPEL, NPC_, CONT, ARMO, AMMO, MISC, WEAP, OMOD, BOOK, NOTE, KEYM, ALCH, INGR, LIGH, FACT, FLST, IDLM, TXST, PROJ]), {5} wbInteger('Object Type', itU32, wbObjectTypeEnum), {6} wbFormIDCk('Keyword', [NULL, KYWD]), {7} wbByteArray('Unused', 4, cpIgnore), {8} wbInteger('Ref Alias', itS32, wbPackageLocationAliasToStr, wbStrToAlias), {9} wbInteger('Loc Alias', itS32, wbPackageLocationAliasToStr, wbStrToAlias), {10} wbInteger('Interrupt Data', itU32), {11} wbInteger('Packdata Target', itU32), {12} wbByteArray('Unknown', 4, cpIgnore), {13} wbByteArray('Unknown', 4), {14} wbInteger('Ref Collection Alias', itS32, wbPackageLocationAliasToStr, wbStrToAlias) ]), wbInteger('Radius', itS32), wbInteger('Collection Index', itU32) ], cpNormal, False, nil, 3); wbPLVD := wbStruct(PLVD, 'Location', [ wbInteger('Type', itS32, wbLocationEnum), wbUnion('Location Value', wbTypeDecider, [ {0} wbFormIDCkNoReach('Reference', sigReferences), {1} wbFormIDCkNoReach('Cell', [NULL, CELL]), {2} wbByteArray('Near Package Start Location', 4, cpIgnore), {3} wbByteArray('Near Editor Location', 4, cpIgnore), {4} wbFormIDCkNoReach('Object ID', [NULL, ACTI, DOOR, STAT, MSTT, FURN, SPEL, NPC_, CONT, ARMO, AMMO, MISC, WEAP, OMOD, BOOK, NOTE, KEYM, ALCH, INGR, LIGH, FACT, FLST, IDLM, TXST, PROJ]), {5} wbInteger('Object Type', itU32, wbObjectTypeEnum), {6} wbFormIDCk('Keyword', [NULL, KYWD]), {7} wbByteArray('Unused', 4, cpIgnore), {8} wbInteger('Ref Alias', itS32, wbPackageLocationAliasToStr, wbStrToAlias), {9} wbInteger('Loc Alias', itS32, wbPackageLocationAliasToStr, wbStrToAlias), {10} wbInteger('Interrupt Data', itU32), {11} wbInteger('Packdata Target', itU32), {12} wbByteArray('Unknown', 4, cpIgnore), {13} wbByteArray('Unknown', 4), {14} wbInteger('Ref Collection Alias', itS32, wbPackageLocationAliasToStr, wbStrToAlias) ]), wbInteger('Radius', itS32), wbInteger('Collection Index', itU32) ], cpNormal, False, nil, 3); wbTargetData := wbStruct('Target Data', [ wbInteger('Type', itS32, wbEnum([ {0} 'Specific Reference', {1} 'Object ID', {2} 'Object Type', {3} 'Linked Reference', {4} 'Ref Alias', {5} 'Interrupt Data', {6} 'Self', {7} 'Keyword', {8} 'Unknown 8' ]), cpNormal, False, nil, nil, 2), wbUnion('Target', wbTypeDecider, [ {0} wbFormIDCkNoReach('Reference', sigReferences, True), {1} wbFormIDCkNoReach('Object ID', [NULL, ACTI, DOOR, STAT, MSTT, FURN, SPEL, NPC_, CONT, ARMO, AMMO, MISC, WEAP, OMOD, BOOK, NOTE, KEYM, ALCH, INGR, LIGH, FACT, FLST, IDLM, TXST, PROJ]), {2} wbInteger('Object Type', itU32, wbObjectTypeEnum), {3} wbFormIDCk('Keyword', [KYWD, NULL]), {4} wbInteger('Alias', itS32, wbPackageLocationAliasToStr, wbStrToAlias), {5} wbInteger('Interrupt Data', itU32), {6} wbByteArray('Unknown', 4, cpIgnore), {7} wbFormIDCk('Keyword', [KYWD, NULL]), {8} wbByteArray('Unknown', 4, cpIgnore) ]), wbInteger('Count / Distance', itS32) ]); wbEITM := wbFormIDCk(EITM, 'Object Effect', [ENCH, SPEL]); wbPosRot := wbStruct('Position/Rotation', [ wbStruct('Position', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), wbStruct('Rotation', [ wbFloat('X', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Y', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Z', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize) ]) ]); wbDATAPosRot := wbStruct(DATA, 'Position/Rotation', [ wbStruct('Position', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), wbStruct('Rotation', [ wbFloat('X', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Y', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Z', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize) ]) ], cpNormal, True); wbMODS := wbFormIDCk(MODS, 'Material Swap', [MSWP]); wbMO2S := wbFormIDCk(MO2S, 'Material Swap', [MSWP]); wbMO3S := wbFormIDCk(MO3S, 'Material Swap', [MSWP]); wbMO4S := wbFormIDCk(MO4S, 'Material Swap', [MSWP]); wbMO5S := wbFormIDCk(MO5S, 'Material Swap', [MSWP]); wbMODF := wbUnknown(MODF); wbMO2F := wbUnknown(MO2F); wbMO3F := wbUnknown(MO3F); wbMO4F := wbUnknown(MO4F); wbMO5F := wbUnknown(MO5F); wbMODC := wbFloat(MODC, 'Color Remapping Index'); wbMO2C := wbFloat(MO2C, 'Color Remapping Index'); wbMO3C := wbFloat(MO3C, 'Color Remapping Index'); wbMO4C := wbFloat(MO4C, 'Color Remapping Index'); wbMO5C := wbFloat(MO5C, 'Color Remapping Index'); wbMODT := wbByteArray(MODT, 'Texture Files Hashes', 0, cpIgnore, false, false, wbNeverShow); wbDMDT := wbByteArray(DMDT, 'Texture Files Hashes', 0, cpIgnore, false, false, wbNeverShow); {wbMODT := wbStruct(MODT, 'Texture Files Hashes', [ wbInteger('Number of headers', itU32), wbInteger('Textures count', itU32), wbByteArray('Unused', 4), wbInteger('Unique textures count', itU32), wbInteger('Materials count', itU32), wbArray('Hashes', wbStruct('Hash', [ wbByteArray('Flags', 4), wbString('Type', 4), wbByteArray('Texture hash', 4) ])) ]);} wbMODL := wbRStructSK([0], 'Model', [ wbString(MODL, 'Model Filename', 0, cpNormal, True), wbMODT, wbMODS, wbMODC, wbMODF ], [], cpNormal, False, nil, True); wbMODLActor := wbRStructSK([0], 'Model', [ wbString(MODL, 'Model Filename', 0, cpNormal, True), wbMODT, wbMODS ], [], cpNormal, False, nil{wbActorTemplateUseModelAnimation}, True); wbMODLReq := wbRStructSK([0], 'Model', [ wbString(MODL, 'Model Filename', 0, cpNormal, True), wbMODT, wbMODS, wbMODC, wbMODF ], [], cpNormal, True, nil, True); wbDMDS := wbFormIDCk(DMDS, 'Material Swap', [MSWP]); wbDMDC := wbFloat(DMDC, 'Color Remapping Index'); wbDEST := wbRStruct('Destructible', [ wbStruct(DEST, 'Header', [ wbInteger('Health', itS32), wbInteger('DEST Count', itU8), wbInteger('Flags', itU8, wbFlags([ 'VATS Targetable', 'Large Actor Destroys' ])), wbByteArray('Unknown', 2) ]), wbArrayS(DAMC, 'Resistances', wbStructSK([0], 'Resistance', [ wbFormIDCk('Damage Type', [DMGT]), wbInteger('Value', itU32) ])), wbRArray('Stages', wbRStruct('Stage', [ wbStruct(DSTD, 'Destruction Stage Data', [ wbInteger('Health %', itU8), wbInteger('Index', itU8), wbInteger('Model Damage Stage', itU8), wbInteger('Flags', itU8, wbFlags([ 'Cap Damage', 'Disable', 'Destroy', 'Ignore External Dmg', 'Becomes Dynamic' ])), wbInteger('Self Damage per Second', itS32), wbFormIDCk('Explosion', [EXPL, NULL]), wbFormIDCk('Debris', [DEBR, NULL]), wbInteger('Debris Count', itS32) ], cpNormal, True), wbString(DSTA, 'Sequence Name'), wbRStructSK([0], 'Model', [ wbString(DMDL, 'Model Filename', 0, cpNormal, True), wbDMDT, wbDMDC, wbDMDS ], [], cpNormal, False, nil, True), wbEmpty(DSTF, 'End Marker', cpNormal, True) ], [], cpNormal, False, nil) ) ], [], cpNormal, False, nil); wbDESTActor := wbRStruct('Destructible', [ wbStruct(DEST, 'Header', [ wbInteger('Health', itS32), wbInteger('Count', itU8), wbInteger('VATS Targetable', itU8, wbBoolEnum), wbByteArray('Unknown', 2) ]), wbRArray('Stages', // Begin Stage Array wbRStruct('Stage', [ // Begin Stage RStruct wbStruct(DSTD, 'Destruction Stage Data', [ // Begin DSTD wbInteger('Health %', itU8), wbInteger('Index', itU8), wbInteger('Damage Stage', itU8), wbInteger('Flags', itU8, wbFlags([ 'Cap Damage', 'Disable', 'Destroy' ])), wbInteger('Self Damage per Second', itS32), wbFormIDCk('Explosion', [EXPL, NULL]), wbFormIDCk('Debris', [DEBR, NULL]), wbInteger('Debris Count', itS32) ], cpNormal, True), // End DSTD wbRStructSK([0], 'Model', [ // Begin DMDL wbString(DMDL, 'Model Filename') ], []), // End DMDL wbDMDT, wbDMDC, wbDMDS, wbEmpty(DSTF, 'End Marker', cpNormal, True) ], []) // Begin Stage RStruct ) // End Stage Array ], [], cpNormal, False, nil{wbActorTemplateUseModelAnimation}); wbXLOD := wbArray(XLOD, 'Distant LOD Data', wbFloat('Unknown'), 3); wbXESP := wbStruct(XESP, 'Enable Parent', [ wbFormIDCk('Reference', sigReferences), wbInteger('Flags', itU8, wbFlags([ 'Set Enable State to Opposite of Parent', 'Pop In' ])), wbByteArray('Unused', 3, cpIgnore) ]); wbPDTO := wbStruct(PDTO, 'Topic Data', [ wbInteger('Type', itU32, wbEnum([ 'Topic Ref', 'Topic Subtype' ])), wbUnion('Data', wbTypeDecider, [ wbFormIDCk('Topic', [DIAL, NULL]), wbString('Subtype', 4) ]) ]); wbPDTOs := wbRArray('Topic', wbPDTO, cpNormal, False, nil); wbXLCM := wbInteger(XLCM, 'Level Modifier', itS32, wbEnum([ 'Easy', 'Medium', 'Hard', 'Very Hard' ])); if wbSimpleRecords then begin wbMaxHeightDataCELL := wbByteArray(MHDT, 'Max Height Data', 0, cpNormal); wbMaxHeightDataWRLD := wbByteArray(MHDT, 'Max Height Data', 0, cpNormal); end else begin wbMaxHeightDataCELL := wbStruct(MHDT, 'Max Height Data', [ wbFloat('Offset'), wbArray('Rows', wbByteArray('Columns', 32) // way too verbose for no practical use //wbStruct('Row', [ wbArray('Columns', wbInteger('Column', itU8), 32) ]) , 32) ]); wbMaxHeightDataWRLD := wbStruct(MHDT, 'Max Height Data', [ wbStruct('Min', [ wbInteger('X', itS16), wbInteger('Y', itS16) ]), wbStruct('Max', [ wbInteger('X', itS16), wbInteger('Y', itS16) ]), wbByteArray('Cell Data', 0) // way too verbose for no practical use {wbArray('Cell Data', wbStruct('Quad Height', [ wbInteger('Bottom Left', itU8), wbInteger('Bottom Right', itU8), wbInteger('Top Left', itU8), wbInteger('Top Right', itU8) ]))} ]); end; if wbSimpleRecords then wbOFST := wbByteArray(OFST, 'Offset Data') else wbOFST := wbArray(OFST, 'Offset Data', wbArray('Rows', wbInteger('Offset', itU32), wbOffsetDataColsCounter), 0); wbXOWN := wbStruct(XOWN, 'Owner', [ wbFormIDCkNoReach('Owner', [FACT, ACHR, NPC_]), wbByteArray('Unknown', 4), wbInteger('Flags', itU8, wbFlags(['No Crime'])), wbByteArray('Unknown', 3) ]); wbXRNK := wbInteger(XRNK, 'Owner Faction Rank', itS32); if wbSimpleRecords then wbNVNM := wbStruct(NVNM, 'Navmesh Geometry', [ wbInteger('Version', itU32), wbByteArray('Magic', 4), wbFormIDCk('Parent Worldspace', [WRLD, NULL]), wbUnion('Parent', wbNVNMParentDecider, [ wbStruct('Coordinates', [ wbInteger('Grid Y', itS16), wbInteger('Grid X', itS16) ]), wbFormIDCk('Parent Cell', [CELL]) ]), wbByteArray('Vertices and Triangles') ]) else wbNVNM := wbStruct(NVNM, 'Navmesh Geometry', [ wbInteger('Version', itU32), // Changes how the struct is loaded, should be 15 in FO4 wbStruct('Pathing Cell', [ wbInteger('Magic', itU32), // This looks like a magic number (always $A5E9A03C), loaded with the parents wbFormIDCk('Parent Worldspace', [WRLD, NULL]), wbUnion('Parent', wbNVNMParentDecider, [ // same as TES5 cell if worldspace is null or Grid X Y wbStruct('Coordinates', [ wbInteger('Grid Y', itS16), wbInteger('Grid X', itS16) ]), wbFormIDCk('Parent Cell', [CELL]) ]) ]), wbArray('Vertices', wbStruct('Vertex', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), -1), wbArray('Triangles', wbStruct('Triangle', [ wbInteger('Vertex 0', itS16), wbInteger('Vertex 1', itS16), wbInteger('Vertex 2', itS16), wbInteger('Edge 0-1', itS16), wbInteger('Edge 1-2', itS16), wbInteger('Edge 2-0', itS16), wbFloat('Height'), // this and next if form ver > 57 wbInteger('Unknown', itU8, wbFlags([])), // flags wbInteger('Unknown', itU32) // encoding or flags ]) , -1), wbArray('Edge Links', wbStruct('Edge Link', [ wbInteger('Unknown', itU32), wbFormIDCk('Mesh', [NAVM]), // those last three are a structure wbInteger('Triangle', itS16), wbInteger('Unknown', itU8) // if form ver > 127 ]) , -1), wbArray('Door Triangles', wbStruct('Door Triangle', [ wbInteger('Triangle before door', itU16), // I would say itU16 wbInteger('DTUnknown', itU32), // used as a key to lookup in a map of PathingDoor wbUnion('Door', wbDoorTriangleDoorTriangleDecider, [wbNull, wbFormIDCk('Door', [REFR])]) ]) , -1), wbArray('Unknown 5', // if navmesh version gt 12 wbStruct('Unknown', [ wbInteger('Unknown', itU16), wbInteger('Unknown', itU16), wbInteger('Unknown', itU32 {, wbFlags([]) ? }) ]) , -1), wbArray('Unknown 6', wbStruct('Uknown', [ wbInteger('Unknown', itU16), wbInteger('Unknown', itU16) ]) , -1), wbArray('Unknown 7', // if navmesh version gt 11 wbStruct('Unknown', [ wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Unknown'), wbInteger('Unknown', itU16), wbInteger('Unknown', itU32) ]) , -1), wbStruct('Navmesh Grid', [ wbInteger('Navmesh Grid Size', itU32), // max 12 wbFloat('Max X Distance'), wbFloat('Max Y Distance'), wbFloat('Min X'), wbFloat('Min Y'), wbFloat('Min Z'), wbFloat('Max X'), wbFloat('Max Y'), wbFloat('Max Z'), wbArray('NavMesh Grid Arrays', wbArray('NavMeshGridCell', wbInteger('Triangle', itS16), -1)) // There are NavMeshGridSize^2 arrays to load ]) ]); end; procedure DefineFO4b; begin wbRecord(ACHR, 'Placed NPC', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000200} 9, 'Starts Dead', {0x00000400} 10, 'Persistent', {0x00000800} 11, 'Initially Disabled', {0x02000000} 25, 'No AI Acquire', {0x20000000} 29, 'Don''t Havok Settle' ], True, True)), [ wbEDID, wbVMAD, wbFormIDCk(NAME, 'Base', [NPC_], False, cpNormal, True), wbFormIDCk(XEZN, 'Encounter Zone', [ECZN]), {--- Ragdoll ---} wbXRGD, wbXRGB, {--- Patrol Data ---} wbRStruct('Patrol Data', [ wbFloat(XPRD, 'Idle Time', cpNormal, True), wbEmpty(XPPA, 'Patrol Script Marker', cpNormal, True), wbFormIDCk(INAM, 'Idle', [IDLE, NULL], False, cpNormal, True), wbPDTOs, wbFormIDCk(TNAM, 'Topic', [DIAL, NULL], False, cpNormal) ], []), {--- Leveled Actor ----} wbXLCM, {--- Extra ---} wbInteger(XCNT, 'Count', itS32), wbFloat(XRDS, 'Radius'), wbInteger(XHLT, 'Health %', itU32), wbRArrayS('Linked References', wbStructSK(XLKR, [0], 'Linked Reference', [ wbFormIDCk('Keyword/Ref', [KYWD, PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA, NULL]), wbFormIDCk('Ref', sigReferences) ], cpNormal, False, nil, 1)), {--- Activate Parents ---} wbRStruct('Activate Parents', [ wbInteger(XAPD, 'Flags', itU8, wbFlags([ 'Parent Activate Only' ], True)), wbRArrayS('Activate Parent Refs', wbStructSK(XAPR, [0], 'Activate Parent Ref', [ wbFormIDCk('Reference', sigReferences), wbFloat('Delay') ]) ) ], []), wbEmpty(XLKT, 'Linked Ref Transient'), wbFormIDCk(XRFG, 'Reference Group', [RFGP]), wbFormIDCk(XLYR, 'Layer', [LAYR]), wbFormIDCk(XMSP, 'Material Swap', [MSWP]), wbFormIDCk(XLCN, 'Persistent Location', [LCTN]), wbFormIDCk(XLRL, 'Location Reference', [LCRT, LCTN, NULL], False, cpBenignIfAdded), wbArray(XLRT, 'Location Ref Type', wbFormIDCk('Ref', [LCRT, NULL])), wbEmpty(XIS2, 'Ignored by Sandbox'), wbRArray('Spline Connection', wbStruct(XPLK, 'Link', [ wbFormIDCk('Ref', [REFR, ACHR]), wbUnknown // always 00 00 00 00 so far in DLCWorkshop03.esm ])), wbFloat(XHTW, 'Head-Tracking Weight'), wbFloat(XFVC, 'Favor Cost'), {--- Enable Parent ---} wbXESP, {--- Ownership ---} wbXOWN, wbXRNK, {--- Emittance ---} wbFormIDCk(XEMI, 'Emittance', [LIGH, REGN]), {--- MultiBound ---} wbFormIDCk(XMBR, 'MultiBound Reference', sigReferences), {--- Flags ---} wbEmpty(XIBS, 'Ignored By Sandbox'), {--- 3D Data ---} wbXSCL, wbDATAPosRot, wbString(MNAM, 'Comments') ], True, wbPlacedAddInfo); wbVatsValueFunctionEnum := wbEnum([ { 0} 'Weapon Is', { 1} 'Weapon In List', { 2} 'Target Is', { 3} 'Target In List', { 4} 'Target Distance', { 5} 'Target Part', { 6} 'VATS Action', { 7} 'Is Success', { 8} 'Is Critical', { 9} 'Critical Effect Is', {10} 'Critical Effect In List', {11} 'Is Fatal', {12} 'Explode Part', {13} 'Dismember Part', {14} 'Cripple Part', {15} 'Weapon Type Is', {16} 'Is Stranger', {17} 'Is Paralyzing Palm', {18} 'Projectile Type Is', {19} 'Delivery Type Is', {20} 'Casting Type Is' ]); wbActorValueEnum := wbEnum([ {00} 'Aggression', {01} 'Confidence', {02} 'Energy', {03} 'Morality', {04} 'Mood', {05} 'Assistance', {06} 'One-Handed', {07} 'Two-Handed', {08} 'Archery', {09} 'Block', {10} 'Smithing', {11} 'Heavy Armor', {12} 'Light Armor', {13} 'Pickpocket', {14} 'Lockpicking', {15} 'Sneak', {16} 'Alchemy', {17} 'Speech', {18} 'Alteration', {19} 'Conjuration', {20} 'Destruction', {21} 'Illusion', {22} 'Restoration', {23} 'Enchanting', {24} 'Health', {25} 'Magicka', {26} 'Stamina', {27} 'Heal Rate', {28} 'Magicka Rate', {29} 'Stamina Rate', {30} 'Speed Mult', {31} 'Inventory Weight', {32} 'Carry Weight', {33} 'Critical Chance', {34} 'Melee Damage', {35} 'Unarmed Damage', {36} 'Mass', {37} 'Voice Points', {38} 'Voice Rate', {39} 'Damage Resist', {40} 'Poison Resist', {41} 'Resist Fire', {42} 'Resist Shock', {43} 'Resist Frost', {44} 'Resist Magic', {45} 'Resist Disease', {46} 'Unknown 46', {47} 'Unknown 47', {48} 'Unknown 48', {49} 'Unknown 49', {50} 'Unknown 50', {51} 'Unknown 51', {52} 'Unknown 52', {53} 'Paralysis', {54} 'Invisibility', {55} 'Night Eye', {56} 'Detect Life Range', {57} 'Water Breathing', {58} 'Water Walking', {59} 'Unknown 59', {60} 'Fame', {61} 'Infamy', {62} 'Jumping Bonus', {63} 'Ward Power', {64} 'Right Item Charge', {65} 'Armor Perks', {66} 'Shield Perks', {67} 'Ward Deflection', {68} 'Variable01', {69} 'Variable02', {70} 'Variable03', {71} 'Variable04', {72} 'Variable05', {73} 'Variable06', {74} 'Variable07', {75} 'Variable08', {76} 'Variable09', {77} 'Variable10', {78} 'Bow Speed Bonus', {79} 'Favor Active', {80} 'Favors Per Day', {81} 'Favors Per Day Timer', {82} 'Left Item Charge', {83} 'Absorb Chance', {84} 'Blindness', {85} 'Weapon Speed Mult', {86} 'Shout Recovery Mult', {87} 'Bow Stagger Bonus', {88} 'Telekinesis', {89} 'Favor Points Bonus', {90} 'Last Bribed Intimidated', {91} 'Last Flattered', {92} 'Movement Noise Mult', {93} 'Bypass Vendor Stolen Check', {94} 'Bypass Vendor Keyword Check', {95} 'Waiting For Player', {96} 'One-Handed Modifier', {97} 'Two-Handed Modifier', {98} 'Marksman Modifier', {99} 'Block Modifier', {100} 'Smithing Modifier', {101} 'Heavy Armor Modifier', {102} 'Light Armor Modifier', {103} 'Pickpocket Modifier', {104} 'Lockpicking Modifier', {105} 'Sneaking Modifier', {106} 'Alchemy Modifier', {107} 'Speechcraft Modifier', {108} 'Alteration Modifier', {109} 'Conjuration Modifier', {110} 'Destruction Modifier', {111} 'Illusion Modifier', {112} 'Restoration Modifier', {113} 'Enchanting Modifier', {114} 'One-Handed Skill Advance', {115} 'Two-Handed Skill Advance', {116} 'Marksman Skill Advance', {117} 'Block Skill Advance', {118} 'Smithing Skill Advance', {119} 'Heavy Armor Skill Advance', {120} 'Light Armor Skill Advance', {121} 'Pickpocket Skill Advance', {122} 'Lockpicking Skill Advance', {123} 'Sneaking Skill Advance', {124} 'Alchemy Skill Advance', {125} 'Speechcraft Skill Advance', {126} 'Alteration Skill Advance', {127} 'Conjuration Skill Advance', {128} 'Destruction Skill Advance', {129} 'Illusion Skill Advance', {130} 'Restoration Skill Advance', {131} 'Enchanting Skill Advance', {132} 'Left Weapon Speed Multiply', {133} 'Dragon Souls', {134} 'Combat Health Regen Multiply', {135} 'One-Handed Power Modifier', {136} 'Two-Handed Power Modifier', {137} 'Marksman Power Modifier', {138} 'Block Power Modifier', {139} 'Smithing Power Modifier', {140} 'Heavy Armor Power Modifier', {141} 'Light Armor Power Modifier', {142} 'Pickpocket Power Modifier', {143} 'Lockpicking Power Modifier', {144} 'Sneaking Power Modifier', {145} 'Alchemy Power Modifier', {146} 'Speechcraft Power Modifier', {147} 'Alteration Power Modifier', {148} 'Conjuration Power Modifier', {149} 'Destruction Power Modifier', {150} 'Illusion Power Modifier', {151} 'Restoration Power Modifier', {152} 'Enchanting Power Modifier', {153} 'Dragon Rend', {154} 'Attack Damage Mult', {155} 'Heal Rate Mult', {156} 'Magicka Rate Mult', {157} 'Stamina Rate Mult', {158} 'Werewolf Perks', {159} 'Vampire Perks', {160} 'Grab Actor Offset', {161} 'Grabbed', {162} 'Unknown 162', {163} 'Reflect Damage' ], [ -1, 'None' ]); wbSkillEnum := wbEnum([ 'Unknown 1', 'Unknown 2', 'Unknown 3', 'Unknown 4', 'Unknown 5', 'Unknown 6', 'One Handed', 'Two Handed', 'Archery', 'Block', 'Smithing', 'Heavy Armor', 'Light Armor', 'Pickpocket', 'Lockpicking', 'Sneak', 'Alchemy', 'Speech', 'Alteration', 'Conjuration', 'Destruction', 'Illusion', 'Restoration', 'Enchanting' ], [ -1, 'None' ]); wbCastEnum := wbEnum([ {0} 'Constant Effect', {1} 'Fire and Forget', {2} 'Concentration', {3} 'Scroll' ]); wbTargetEnum := wbEnum([ {0} 'Self', {1} 'Touch', {2} 'Aimed', {3} 'Target Actor', {4} 'Target Location' ]); wbCastingSourceEnum := wbEnum([ 'Left', 'Right', 'Voice', 'Instant' ]); wbCrimeTypeEnum := wbEnum([ 'Steal', 'Pickpocket', 'Trespass', 'Attack', 'Murder', 'Escape Jail', 'Werewolf Transformation' ], [ -1, 'None' ]); wbKeywordTypeEnum := wbEnum([ {00} 'None', {01} 'Component Tech Level', {02} 'Attach Point', {03} 'Component Property', {04} 'Instantiation Filter', {05} 'Mod Association', {06} 'Sound', {07} 'Anim Archetype', {08} 'Function Call', {09} 'Recipe Filter', {10} 'Attraction Type', {11} 'Dialogue Subtype', {12} 'Quest Target', {13} 'Anim Flavor', {14} 'Anim Gender', {15} 'Anim Face', {16} 'Quest Group', {17} 'Anim Injured', {18} 'Dispel Effect' ]); wbETYP := wbFormIDCk(ETYP, 'Equipment Type', [EQUP, NULL]); wbETYPReq := wbFormIDCk(ETYP, 'Equipment Type', [EQUP, NULL], False, cpNormal, True); wbFormTypeEnum := wbEnum([], [ 0, 'Activator', 1, 'Armor', 2, 'Book', 3, 'Container', 4, 'Door', 5, 'Ingredient', 6, 'Light', 7, 'MiscItem', 8, 'Static', 9, 'Grass', 10, 'Tree', 12, 'Weapon', 13, 'Actor', 14, 'LeveledCharacter', 15, 'Spell', 16, 'Enchantment', 17, 'Potion', 18, 'LeveledItem', 19, 'Key', 20, 'Ammo', 21, 'Flora', 22, 'Furniture', 23, 'Sound Marker', 24, 'LandTexture', 25, 'CombatStyle', 26, 'LoadScreen', 27, 'LeveledSpell', 28, 'AnimObject', 29, 'WaterType', 30, 'IdleMarker', 31, 'EffectShader', 32, 'Projectile', 33, 'TalkingActivator', 34, 'Explosion', 35, 'TextureSet', 36, 'Debris', 37, 'MenuIcon', 38, 'FormList', 39, 'Perk', 40, 'BodyPartData', 41, 'AddOnNode', 42, 'MovableStatic', 43, 'CameraShot', 44, 'ImpactData', 45, 'ImpactDataSet', 46, 'Quest', 47, 'Package', 48, 'VoiceType', 49, 'Class', 50, 'Race', 51, 'Eyes', 52, 'HeadPart', 53, 'Faction', 54, 'Note', 55, 'Weather', 56, 'Climate', 57, 'ArmorAddon', 58, 'Global', 59, 'Imagespace', 60, 'Imagespace Modifier', 61, 'Encounter Zone', 62, 'Message', 63, 'Constructible Object', 64, 'Acoustic Space', 65, 'Ragdoll', 66, 'Script', 67, 'Magic Effect', 68, 'Music Type', 69, 'Static Collection', 70, 'Keyword', 71, 'Location', 72, 'Location Ref Type', 73, 'Footstep', 74, 'Footstep Set', 75, 'Material Type', 76, 'Actor Action', 77, 'Music Track', 78, 'Word of Power', 79, 'Shout', 80, 'Relationship', 81, 'Equip Slot', 82, 'Association Type', 83, 'Outfit', 84, 'Art Object', 85, 'Material Object', 87, 'Lighting Template', 88, 'Shader Particle Geometry', 89, 'Visual Effect', 90, 'Apparatus', 91, 'Movement Type', 92, 'Hazard', 93, 'SM Event Node', 94, 'Sound Descriptor', 95, 'Dual Cast Data', 96, 'Sound Category', 97, 'Soul Gem', 98, 'Sound Output Model', 99, 'Collision Layer', 100, 'Scroll', 101, 'ColorForm', 102, 'Reverb Parameters', 116, 'Terminal' ]); wbMiscStatEnum := wbEnum([], [ Int64($1EE71DBC), 'Animals Friended', Int64($FCDD5011), 'Animals Killed', Int64($366D84CF), 'Armor Improved', Int64($8E20D7C9), 'Assaults', Int64($B9B50725), 'Backstabs', Int64($EA01A954), 'Bobbleheads Collected', Int64($6932624D), 'Bright Ideas', Int64($7FF0CC3B), 'Brotherhood of Steel Quests Completed', Int64($FEA920AA), 'Buildings', Int64($1F84743B), 'Caps Found', Int64($9360004C), 'Chems Crafted', Int64($B2A78B7A), 'Chems Taken', Int64($53D9E9B5), 'Chests Looted', Int64($1E258BEE), 'Computers Hacked', Int64($3DE99B41), 'Cores Ejected', Int64($737EAA97), 'Corpses Eaten', Int64($40B11EFE), 'Creatures Killed', Int64($4C4B8DF3), 'Creatures Killed DLC03', Int64($22D5BA38), 'Critical Strikes', Int64($3C626A90), 'Days Passed', Int64($C5A52FD0), 'Days Survived', Int64($45FDBB1C), 'DLC01 Quests Completed', Int64($FA7CC7F9), 'DLC03 Locations Discovered', Int64($AA444695), 'Dungeons Cleared', Int64($F4E8FFD6), 'Fatman Deaths', Int64($66DAF3CF), 'Fits of Rage', Int64($554E59D5), 'Food', Int64($E1EB3490), 'Food Cooked', Int64($9311B22B), 'Food Eaten', Int64($F947D866), 'Four Leaf Clovers', Int64($7C586E7A), 'Fusion Cores Consumed', Int64($2826309E), 'Game Difficulty', Int64($A5EA7ABC), 'Grand Slams', Int64($F5A36770), 'Grim Reaper Sprints', Int64($52984AA4), 'Happiness', Int64($FA024018), 'Hours Slept', Int64($CAD2ECA1), 'Hours Waiting', Int64($8CC5DAB6), 'HSAtomicCommand', Int64($A2E4C1F2), 'HSAutomatron', Int64($20F9993D), 'HSGrognak', Int64($8D882844), 'HSJangles', Int64($910B02C0), 'HSPipfall', Int64($860E0723), 'HSRedMenace', Int64($3FFA8658), 'HSZetaInvaders', Int64($40CA9C83), 'Institute Quests Completed', Int64($7D2E57C0), 'Intimidations', Int64($FFE8010B), 'Investments Made', Int64($9AF17D9D), 'Items Crafted DLC03', Int64($CF48C0B9), 'Items Scrapped', Int64($82F190C2), 'Items Stolen', Int64($6D8671DD), 'Junk Collected', Int64($110B8D2F), 'Legendary Enemies Killed', Int64($8A24FDE2), 'Locations Discovered', Int64($5829CC2E), 'Locks Picked', Int64($7EA26C2D), 'Main Quests Completed', Int64($493B803C), 'Mines Disarmed', Int64($B1511B82), 'Minuteman Quests Completed', Int64($98EE55DC), 'Misc Objectives Completed', Int64($0F3315AC), 'Money Shots', Int64($5E457DAC), 'Most Caps Carried', Int64($D37C6909), 'Murders', Int64($B91253A4), 'Mysterious Strabger Visits', Int64($1DEEA18A), 'Nuka Cola Flavors Created', Int64($9CE72536), 'Nuka World Creatures Killed', Int64($EB0D60AC), 'Objects Built', Int64($73AD915B), 'Pants Exploded', Int64($53706A04), 'Paralyzing Punches', Int64($9E78CEB3), 'People', Int64($F22A8133), 'People Killed', Int64($D3F632FF), 'Plants Harvested', Int64($856FA4C1), 'PlayedFutureRetroHolotape', Int64($F2BAC234), 'Pockets Picked', Int64($AC69D9B9), 'Power', Int64($0D7B8B16), 'Quests Completed', Int64($0580BB9F), 'RadAway Taken', Int64($D2960073), 'Rad-X Taken', Int64($FDE20426), 'Railroad Quests Completed', Int64($3CBF7E59), 'Ricochets', Int64($01E1BC85), 'Robots Disabled', Int64($2CA4ECC0), 'Robots Improved', Int64($C8BC93BE), 'Robots Killed', Int64($98D5710C), 'Sandman Kills', Int64($B1AE4792), 'Side Quests Completed', Int64($ACE470D7), 'Skill Books Read', Int64($B556CC52), 'Sneak Attacks', Int64($32D1B38F), 'Speach Successes', Int64($5D6B18F1), 'Stimpacks Taken', Int64($C5321BC5), 'Supply Lines Created', Int64($3869002E), 'Survival Denied', Int64($F9DEC209), 'Survival Level-Ups', Int64($69AF5B9A), 'Synths Killed', Int64($0A872FA3), 'Times Addicted', Int64($7AEA9C2B), 'Trespasses', Int64($13752285), 'Turrets Killed', Int64($0B479511), 'Wasteland Whispers', Int64($FCD0CCC3), 'Water', Int64($61A5C5A9), 'Weapons Disarmed', Int64($1D3BA844), 'Weapons Improved', Int64($60A11697), 'Workshops Unlocked' ]); wbAdvanceActionEnum := wbEnum([ 'Normal Usage', 'Power Attack', 'Bash', 'Lockpick Success', 'Lockpick Broken' ]); wbAlignmentEnum := wbEnum([ 'Good', 'Neutral', 'Evil', 'Very Good', 'Very Evil' ]); wbAxisEnum := wbEnum([], [ 88, 'X', 89, 'Y', 90, 'Z' ]); wbCriticalStageEnum := wbEnum([ 'None', 'Goo Start', 'Goo End', 'Disintegrate Start', 'Disintegrate End' ]); wbStaggerEnum := wbEnum([ 'None', 'Small', 'Medium', 'Large', 'Extra Large' ]); wbSexEnum := wbEnum(['Male','Female']); wbEFID := wbFormIDCk(EFID, 'Base Effect', [MGEF]); wbEFIT := wbStructSK(EFIT, [3, 4], '', [ wbFloat('Magnitude', cpNormal, True), wbInteger('Area', itU32), wbInteger('Duration', itU32) ], cpNormal, True, nil, -1, wbEFITAfterLoad); wbCTDA := wbRStruct('Condition', [ wbStruct(CTDA, '', [ wbInteger('Type', itU8, wbCtdaTypeToStr, wbCtdaTypeToInt, cpNormal, False, nil, wbCtdaTypeAfterSet), wbByteArray('Unused', 3, cpIgnore, False, wbNeverShow), wbUnion('Comparison Value', wbCTDACompValueDecider, [ wbFloat('Comparison Value - Float'), wbFormIDCk('Comparison Value - Global', [GLOB]) ]), wbInteger('Function', itU16, wbCTDAFunctionToStr, wbCTDAFunctionToInt), wbByteArray('Unused', 2, cpIgnore, False, wbNeverShow), wbUnion('Parameter #1', wbCTDAParam1Decider, [ { unknown } wbByteArray('Unknown', 4), { 0 ptNone} wbByteArray('None', 4, cpIgnore), { 1 ptInteger} wbInteger('Integer', itS32), { 2 ptFloat} wbFloat('Float'), { 3 ptActor} wbFormIDCkNoReach('Actor', [NULL, PLYR, ACHR, REFR]), { 4 ptActorBase} wbFormIDCkNoReach('Actor Base', [NPC_]), { 5 ptActorValue} wbActorValue, { 6 ptAdvanceAction} wbInteger('Player Action', itU32, wbAdvanceActionEnum), { 7 ptAlias} wbInteger('Alias', itS32, wbConditionAliasToStr, wbStrToAlias), { 8 ptAlignment} wbInteger('Alignment', itU32, wbAlignmentEnum), { 9 ptAssociationType} wbFormIDCk('Association Type', [ASTP]), {10 ptAxis} wbInteger('Axis', itU32, wbAxisEnum), {11 ptCastingSource} wbInteger('Casting Type', itU32, wbCastingSourceEnum), {12 ptCell} wbFormIDCkNoReach('Cell', [CELL]), {13 ptClass} wbFormIDCkNoReach('Class', [CLAS]), {14 ptCrimeType} wbInteger('Crime Type', itU32, wbCrimeTypeEnum), {15 ptCriticalStage} wbInteger('Critical Stage', itU32, wbCriticalStageEnum), {16 ptEncounterZone} wbFormIDCkNoReach('Encounter Zone', [ECZN]), {17 ptEquipType} wbFormIDCkNoReach('Equip Type', [EQUP]), {18 ptEvent} wbInteger('Event', itU32, wbEventFunctionAndMemberToStr, wbEventFunctionAndMemberToInt), {19 ptEventData} wbFormID('Event Data'), {20 ptFaction} wbFormIDCkNoReach('Faction', [FACT]), {21 ptFormList} wbFormIDCkNoReach('Form List', [FLST]), {22 ptFormType} wbInteger('Form Type', itU32, wbFormTypeEnum), {23 ptFurniture} wbFormIDCkNoReach('Furniture', [FURN, FLST]), {24 ptFurnitureAnim} wbInteger('Furniture Anim', itU32, wbFurnitureAnimTypeEnum), {25 ptFurnitureEntry} wbInteger('Furniture Entry', itU32, wbEnum([], [$010000, 'Front', $020000, 'Behind', $040000, 'Right', $80000, 'Left', $100000, 'Up'])), {26 ptGlobal} wbFormIDCkNoReach('Global', [GLOB]), {27 ptIdleForm} wbFormIDCkNoReach('Idle', [IDLE]), {28 ptInventoryObject} wbFormIDCkNoReach('Inventory Object', sigBaseObjects), {29 ptKeyword} wbFormIDCkNoReach('Keyword', [KYWD, FLST, NULL]), {30 ptLocation} wbFormIDCkNoReach('Location', [LCTN]), {31 ptMagicEffect} wbFormIDCkNoReach('Base Effect', [MGEF]), {32 ptMagicItem} wbFormIDCkNoReach('Effect Item', [SPEL, ENCH, ALCH, INGR, SCRL]), {33 ptMiscStat} wbInteger('Misc Stat', itU32, wbMiscStatEnum), {34 ptObjectReference} wbFormIDCkNoReach('Object Reference', sigReferences), {35 ptOwner} wbFormIDCkNoReach('Owner', [NULL, FACT, NPC_]), {36 ptPackage} wbFormIDCkNoReach('Package', [PACK]), {37 ptPackdata} wbInteger('Packdata ID', itU32), {38 ptPerk} wbFormIDCkNoReach('Perk', [PERK]), {39 ptQuest} wbFormIDCkNoReach('Quest', [QUST]), {40 ptQuestStage} wbInteger('Quest Stage', itU32, wbCTDAParam2QuestStageToStr, wbCTDAParam2QuestStageToInt), {41 ptRace} wbFormIDCkNoReach('Race', [RACE]), {42 ptReferencableObject} wbFormIDCkNoReach('Referenceable Object', sigBaseObjects), {43 ptRefType} wbFormIDCkNoReach('Location Ref Type', [LCRT]), {44 ptRegion} wbFormIDCkNoReach('Region', [REGN]), {45 ptScene} wbFormIDCk('Scene', [NULL, SCEN]), {46 ptSex} wbInteger('Sex', itU32, wbSexEnum), {47 ptShout} wbFormIDCkNoReach('Shout', [SHOU]), {48 ptVariableName} wbByteArray('Variable Name (unused)', 4, cpIgnore), {49 ptVATSValueFunction} wbInteger('VATS Value Function', itU32, wbVATSValueFunctionEnum), {50 ptVATSValueParam} wbInteger('VATS Value Param (unused)', itU32), {51 ptVoiceType} wbFormIDCkNoReach('Voice Type', [VTYP, FLST]), {52 ptWardState} wbInteger('Ward State', itU32, wbWardStateEnum), {53 ptWeather} wbFormIDCkNoReach('Weather', [WTHR]), {54 ptWorldspace} wbFormIDCkNoReach('Worldspace', [WRLD, FLST]), {55 ptDamageType} wbFormIDCkNoReach('Damage Type', [DMGT, FLST]) ]), wbUnion('Parameter #2', wbCTDAParam2Decider, [ { unknown } wbByteArray('Unknown', 4), { 0 ptNone} wbByteArray('None', 4, cpIgnore), { 1 ptInteger} wbInteger('Integer', itS32), { 2 ptFloat} wbFloat('Float'), { 3 ptActor} wbFormIDCkNoReach('Actor', [NULL, PLYR, ACHR, REFR]), { 4 ptActorBase} wbFormIDCkNoReach('Actor Base', [NPC_]), { 5 ptActorValue} wbActorValue, { 6 ptAdvanceAction} wbInteger('Player Action', itU32, wbAdvanceActionEnum), { 7 ptAlias} wbInteger('Alias', itS32, wbConditionAliasToStr, wbStrToAlias), { 8 ptAlignment} wbInteger('Alignment', itU32, wbAlignmentEnum), { 9 ptAssociationType} wbFormIDCk('Association Type', [ASTP]), {10 ptAxis} wbInteger('Axis', itU32, wbAxisEnum), {11 ptCastingSource} wbInteger('Casting Type', itU32, wbCastingSourceEnum), {12 ptCell} wbFormIDCkNoReach('Cell', [CELL]), {13 ptClass} wbFormIDCkNoReach('Class', [CLAS]), {14 ptCrimeType} wbInteger('Crime Type', itU32, wbCrimeTypeEnum), {15 ptCriticalStage} wbInteger('Critical Stage', itU32, wbCriticalStageEnum), {16 ptEncounterZone} wbFormIDCkNoReach('Encounter Zone', [ECZN]), {17 ptEquipType} wbFormIDCkNoReach('Equip Type', [EQUP]), {18 ptEvent} wbInteger('Event', itU32, wbEventFunctionAndMemberToStr, wbEventFunctionAndMemberToInt), {19 ptEventData} wbFormID('Event Data'), {20 ptFaction} wbFormIDCkNoReach('Faction', [FACT]), {21 ptFormList} wbFormIDCkNoReach('Form List', [FLST]), {22 ptFormType} wbInteger('Form Type', itU32, wbFormTypeEnum), {23 ptFurniture} wbFormIDCkNoReach('Furniture', [FURN, FLST]), {24 ptFurnitureAnim} wbInteger('Furniture Anim', itU32, wbFurnitureAnimTypeEnum), {25 ptFurnitureEntry} wbInteger('Furniture Entry', itU32, wbEnum([], [$010000, 'Front', $020000, 'Behind', $040000, 'Right', $80000, 'Left', $100000, 'Up'])), {26 ptGlobal} wbFormIDCkNoReach('Global', [GLOB]), {27 ptIdleForm} wbFormIDCkNoReach('Idle', [IDLE]), {28 ptInventoryObject} wbFormIDCkNoReach('Inventory Object', sigBaseObjects), {29 ptKeyword} wbFormIDCkNoReach('Keyword', [KYWD, FLST, NULL]), {30 ptLocation} wbFormIDCkNoReach('Location', [LCTN]), {31 ptMagicEffect} wbFormIDCkNoReach('Base Effect', [MGEF]), {32 ptMagicItem} wbFormIDCkNoReach('Effect Item', [SPEL, ENCH, ALCH, INGR, SCRL]), {33 ptMiscStat} wbInteger('Misc Stat', itU32, wbMiscStatEnum), {34 ptObjectReference} wbFormIDCkNoReach('Object Reference', sigReferences), {35 ptOwner} wbFormIDCkNoReach('Owner', [NULL, FACT, NPC_]), {36 ptPackage} wbFormIDCkNoReach('Package', [PACK]), {37 ptPackdata} wbInteger('Packdata ID', itU32), {38 ptPerk} wbFormIDCkNoReach('Perk', [PERK]), {39 ptQuest} wbFormIDCkNoReach('Quest', [QUST]), {40 ptQuestStage} wbInteger('Quest Stage', itU32, wbCTDAParam2QuestStageToStr, wbCTDAParam2QuestStageToInt), {41 ptRace} wbFormIDCkNoReach('Race', [RACE]), {42 ptReferencableObject} wbFormIDCkNoReach('Referenceable Object', sigBaseObjects), {43 ptRefType} wbFormIDCkNoReach('Location Ref Type', [LCRT]), {44 ptRegion} wbFormIDCkNoReach('Region', [REGN]), {45 ptScene} wbFormIDCk('Scene', [NULL, SCEN]), {46 ptSex} wbInteger('Sex', itU32, wbSexEnum), {47 ptShout} wbFormIDCkNoReach('Shout', [SHOU]), {48 ptVariableName} wbByteArray('Variable Name (unused)', 4, cpIgnore), {49 ptVATSValueFunction} wbInteger('VATS Value Function', itU32, wbVATSValueFunctionEnum), {50 ptVATSValueParam} wbUnion('VATS Value Param', wbCTDAParam2VATSValueParamDecider, [ { 0} wbFormIDCkNoReach('Weapon', [WEAP]), { 1} wbFormIDCkNoReach('Weapon List', [FLST], [WEAP]), { 2} wbFormIDCkNoReach('Target', [NPC_]), { 3} wbFormIDCkNoReach('Target List', [FLST], [NPC_]), { 4} wbByteArray('Unknown', 4, cpIgnore), { 5} wbInteger('Target Part', itS32, wbActorValueEnum), { 6} wbInteger('VATS Action', itU32, wbEnum([ 'Unarmed Attack', 'One Hand Melee Attack', 'Two Hand Melee Attack', 'Magic Attack', 'Ranged Attack', 'Reload', 'Crouch', 'Stand', 'Switch Weapon', 'Toggle Weapon Drawn', 'Heal', 'Player Death' ])), { 7} wbByteArray('Unknown', 4, cpIgnore), { 8} wbByteArray('Unknown', 4, cpIgnore), { 9} wbFormIDCkNoReach('Critical Effect', [SPEL]), {10} wbFormIDCkNoReach('Critical Effect List', [FLST], [SPEL]), {11} wbByteArray('Unknown', 4, cpIgnore), {12} wbByteArray('Unknown', 4, cpIgnore), {13} wbByteArray('Unknown', 4, cpIgnore), {14} wbByteArray('Unknown', 4, cpIgnore), {15} wbInteger('Weapon Type', itU32, wbWeaponAnimTypeEnum), {16} wbByteArray('Unknown', 4, cpIgnore), {17} wbByteArray('Unknown', 4, cpIgnore), {18} wbInteger('Projectile Type', itU32, wbEnum([ 'Missile', 'Lobber', 'Beam', 'Flame', 'Cone', 'Barrier', 'Arrow' ])), {19} wbInteger('Delivery Type', itU32, wbTargetEnum), {20} wbInteger('Casting Type', itU32, wbCastEnum) ]), {51 ptVoiceType} wbFormIDCkNoReach('Voice Type', [VTYP, FLST]), {52 ptWardState} wbInteger('Ward State', itU32, wbWardStateEnum), {53 ptWeather} wbFormIDCkNoReach('Weather', [WTHR]), {54 ptWorldspace} wbFormIDCkNoReach('Worldspace', [WRLD, FLST]), {55 ptDamageType} wbFormIDCkNoReach('Damage Type', [DMGT, FLST]) ]), wbInteger('Run On', itU32, wbEnum([ { 0} 'Subject', { 1} 'Target', { 2} 'Reference', { 3} 'Combat Target', { 4} 'Linked Reference', { 5} 'Quest Alias', { 6} 'Package Data', { 7} 'Event Data', { 9} 'Command Target', {10} 'Event Camera Ref', {11} 'My Killer' ]), cpNormal, False, nil, wbCTDARunOnAfterSet), wbUnion('Reference', wbCTDAReferenceDecider, [ wbInteger('Unused', itU32, nil, cpIgnore), wbFormIDCkNoReach('Reference', sigReferences, False) ]), wbInteger('Parameter #3', itS32, nil, cpNormal, False, nil, nil, -1) ], cpNormal, False{, nil, 0, wbCTDAAfterLoad}), wbString(CIS1, 'Parameter #1'), wbString(CIS2, 'Parameter #2') ], [], cpNormal); wbCTDAs := wbRArray('Conditions', wbCTDA, cpNormal, False); wbCTDAsCount := wbRArray('Conditions', wbCTDA, cpNormal, False, nil, wbCTDAsAfterSet); wbCTDAsReq := wbRArray('Conditions', wbCTDA, cpNormal, True); wbCTDAsReqCount := wbRArray('Conditions', wbCTDA, cpNormal, True, nil, wbCTDAsAfterSet); wbICON := wbString(ICON, 'Inventory Image'); wbMICO := wbString(MICO, 'Message Icon'); wbPTRN := wbFormIDCk(PTRN, 'Preview Transform', [TRNS]); wbNTRM := wbFormIDCk(NTRM, 'Native Terminal', [TERM]); wbYNAM := wbFormIDCk(YNAM, 'Sound - Pick Up', [SNDR]); wbZNAM := wbFormIDCk(ZNAM, 'Sound - Put Down', [SNDR]); wbCUSD := wbFormIDCk(CUSD, 'Sound - Crafting', [SNDR]); wbINRD := wbFormIDCk(INRD, 'Instance Naming', [INNR]); wbPRPS := wbArrayS(PRPS, 'Properties', wbStructSK([0], 'Property', [ wbActorValue, wbFloat('Value') ])); wbFLTR := wbString(FLTR, 'Filter'); wbAPPR := wbArray(APPR, 'Attach Parent Slots', wbFormIDCk('Keyword', [KYWD])); wbFTYP := wbFormIDCk(FTYP, 'Forced Loc Ref Type', [LCRT]); wbATTX := wbLString(ATTX, 'Activate Text Override', 0, cpTranslate); wbMNAMFurnitureMarker := wbInteger(MNAM, 'Active Markers / Flags', itU32, wbFlags([ {0x00000001} 'Interaction Point 0', {0x00000002} 'Interaction Point 1', {0x00000004} 'Interaction Point 2', {0x00000008} 'Interaction Point 3', {0x00000010} 'Interaction Point 4', {0x00000020} 'Interaction Point 5', {0x00000040} 'Interaction Point 6', {0x00000080} 'Interaction Point 7', {0x00000100} 'Interaction Point 8', {0x00000200} 'Interaction Point 9', {0x00000400} 'Interaction Point 10', {0x00000800} 'Interaction Point 11', {0x00001000} 'Interaction Point 12', {0x00002000} 'Interaction Point 13', {0x00004000} 'Interaction Point 14', {0x00008000} 'Interaction Point 15', {0x00010000} 'Interaction Point 16', {0x00020000} 'Interaction Point 17', {0x00040000} 'Interaction Point 18', {0x00080000} 'Interaction Point 19', {0x00100000} 'Interaction Point 20', {0x00200000} 'Interaction Point 21', {0x00400000} 'Allow Awake Sound', {0x00800000} 'Enter With Weapon Drawn', {0x01000000} 'Play Anim When Full', {0x02000000} 'Disables Activation', {0x04000000} 'Is Perch', {0x08000000} 'Must Exit to Talk', {0x10000000} 'Use Static Avoid Node', {0x20000000} 'Unknown 29', {0x40000000} 'Has Model?', {0x80000000} 'Unknown 31' ])); wbSNAMMarkerParams := wbArray(SNAM, 'Marker Paramaters', wbStruct('Marker', [ wbFloat('Offset X'), wbFloat('Offset Y'), wbFloat('Offset Z'), wbFloat('Rotation Z', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFormIDCk('Keyword', [KYWD, NULL]), wbInteger('Entry Types', itU8, wbFlags([ 'Front', 'Rear', 'Right', 'Left', 'Other', 'Unused 5', 'Unused 6', 'Unused 7' ])), wbByteArray('Unknown', 3) ], cpNormal, False, nil, 4)); wbArmorPropertyEnum := wbEnum([ { 0} 'Enchantments', { 1} 'BashImpactDataSet', { 2} 'BlockMaterial', { 3} 'Keywords', { 4} 'Weight', { 5} 'Value', { 6} 'Rating', { 7} 'AddonIndex', { 8} 'BodyPart', { 9} 'DamageTypeValue', {10} 'ActorValues', {11} 'Health', {12} 'ColorRemappingIndex', {13} 'MaterialSwaps' ]); wbActorPropertyEnum := wbEnum([ { 0} 'Keywords', { 1} 'ForcedInventory', { 2} 'XPOffset', { 3} 'Enchantments', { 4} 'ColorRemappingIndex', { 5} 'MaterialSwaps' ]); wbWeaponPropertyEnum := wbEnum([ { 0} 'Speed', { 1} 'Reach', { 2} 'MinRange', { 3} 'MaxRange', { 4} 'AttackDelaySec', { 5} 'Unknown 5', { 6} 'OutOfRangeDamageMult', { 7} 'SecondaryDamage', { 8} 'CriticalChargeBonus', { 9} 'HitBehaviour', {10} 'Rank', {11} 'Unknown 11', {12} 'AmmoCapacity', {13} 'Unknown 13', {14} 'Unknown 14', {15} 'Type', {16} 'IsPlayerOnly', {17} 'NPCsUseAmmo', {18} 'HasChargingReload', {19} 'IsMinorCrime', {20} 'IsFixedRange', {21} 'HasEffectOnDeath', {22} 'HasAlternateRumble', {23} 'IsNonHostile', {24} 'IgnoreResist', {25} 'IsAutomatic', {26} 'CantDrop', {27} 'IsNonPlayable', {28} 'AttackDamage', {29} 'Value', {30} 'Weight', {31} 'Keywords', {32} 'AimModel', {33} 'AimModelMinConeDegrees', {34} 'AimModelMaxConeDegrees', {35} 'AimModelConeIncreasePerShot', {36} 'AimModelConeDecreasePerSec', {37} 'AimModelConeDecreaseDelayMs', {38} 'AimModelConeSneakMultiplier', {39} 'AimModelRecoilDiminishSpringForce', {40} 'AimModelRecoilDiminishSightsMult', {41} 'AimModelRecoilMaxDegPerShot', {42} 'AimModelRecoilMinDegPerShot', {43} 'AimModelRecoilHipMult', {44} 'AimModelRecoilShotsForRunaway', {45} 'AimModelRecoilArcDeg', {46} 'AimModelRecoilArcRotateDeg', {47} 'AimModelConeIronSightsMultiplier', {48} 'HasScope', {49} 'ZoomDataFOVMult', {50} 'FireSeconds', {51} 'NumProjectiles', {52} 'AttackSound', {53} 'AttackSound2D', {54} 'AttackLoop', {55} 'AttackFailSound', {56} 'IdleSound', {57} 'EquipSound', {58} 'UnEquipSound', {59} 'SoundLevel', {50} 'ImpactDataSet', {61} 'Ammo', {62} 'CritEffect', {63} 'BashImpactDataSet', {64} 'BlockMaterial', {65} 'Enchantments', {66} 'AimModelBaseStability', {67} 'ZoomData', {68} 'ZoomDataOverlay', {69} 'ZoomDataImageSpace', {70} 'ZoomDataCameraOffsetX', {71} 'ZoomDataCameraOffsetY', {72} 'ZoomDataCameraOffsetZ', {73} 'EquipSlot', {74} 'SoundLevelMult', {75} 'NPCAmmoList', {76} 'ReloadSpeed', {77} 'DamageTypeValues', {78} 'AccuracyBonus', {79} 'AttackActionPointCost', {80} 'OverrideProjectile', {81} 'HasBoltAction', {82} 'StaggerValue', {83} 'SightedTransitionSeconds', {84} 'FullPowerSeconds', {85} 'HoldInputToPower', {86} 'HasRepeatableSingleFire', {87} 'MinPowerPerShot', {88} 'ColorRemappingIndex', {89} 'MaterialSwaps', {90} 'CriticalDamageMult', {91} 'FastEquipSound', {92} 'DisableShells', {93} 'HasChargingAttack', {94} 'ActorValues' ]); wbObjectModProperties := wbArrayS('Properties', wbStructSK([4], 'Property', [ wbInteger('Value Type', itU8, wbEnum([ {0} 'Int', {1} 'Float', {2} 'Bool', {3} 'Unknown 3', {4} 'FormID,Int', {5} 'Enum', {6} 'FormID,Float' ])), wbByteArray('Unused', 3, cpIgnore), wbUnion('Function Type', wbOMODDataFunctionTypeDecider, [ { Float } wbInteger('Function Type', itU8, wbEnum(['SET', 'MUL+ADD', 'ADD'])), { Bool } wbInteger('Function Type', itU8, wbEnum(['SET', 'AND', 'OR'])), { Enum } wbInteger('Function Type', itU8, wbEnum(['SET'])), { FormID } wbInteger('Function Type', itU8, wbEnum(['SET', 'REM', 'ADD'])) ]), wbByteArray('Unused', 3, cpIgnore), wbInteger('Property', itU16, wbObjectModPropertyToStr, wbObjectModPropertyToInt), wbByteArray('Unused', 2, cpIgnore), wbUnion('Value 1', wbOMODDataPropertyValue1Decider, [ { 0} wbByteArray('Value 1 - Unknown', 4), { 1} wbInteger('Value 1 - Int', itU32), { 2} wbFloat('Value 1 - Float'), { 3} wbInteger('Value 1 - Bool', itU32, wbBoolEnum), { 4} wbFormID('Value 1 - FormID'), { 5} wbInteger('Value 1 - Enum', itU32), { 6} wbInteger('Sound Level', itU32, wbSoundLevelEnum), { 7} wbInteger('Stagger Value', itU32, wbStaggerEnum), { 8} wbInteger('Hit Behaviour', itU32, wbHitBehaviourEnum) ]), wbUnion('Value 2', wbOMODDataPropertyValue2Decider, [ wbByteArray('Unused', 4, cpIgnore), wbInteger('Value 2 - Int', itU32), wbFloat('Value 2 - Float'), wbInteger('Value 2 - Bool', itU32, wbBoolEnum) ]), wbFloat('Step') ]), wbOMODDataPropertyCounter, cpNormal, False, nil, wbOMODpropertyAfterSet); wbOBTSReq := wbStruct(OBTS, 'Object Mod Template Item', [ wbInteger('Include Count', itU32), // fixed name for wbOMOD* handlers wbInteger('Property Count', itU32), // fixed name for wbOMOD* handlers wbInteger('Level Min', itU8), wbByteArray('Unused', 1), wbInteger('Level Max', itU8), wbByteArray('Unused', 1), wbInteger('ID', itS16), wbInteger('Default', itU8, wbBoolEnum), wbArray('Keywords', wbFormIDCk('Keyword', [KYWD, NULL]), -4), wbInteger('Min Level For Ranks', itU8), wbInteger('Alt Levels Per Tier', itU8), wbArray('Includes', wbStruct('Include', [ wbFormIDCk('Mod', [OMOD]), wbInteger('Attach Point Index', itU8), wbInteger('Optional', itU8, wbBoolEnum), wbInteger('Don''t Use All', itU8, wbBoolEnum) ]), wbOMODDataIncludeCounter, cpNormal, False, nil, wbOMODincludeAfterSet), wbObjectModProperties ], cpNormal, True); wbObjectTemplate := wbRStruct('Object Template', [ wbInteger(OBTE, 'Count', itU32, nil, cpBenign), wbRArray('Combinations', wbRStruct('Combination', [ wbEmpty(OBTF, 'Editor Only'), wbFULL, wbOBTSReq ], [], cpNormal, False, nil, True), cpNormal, False, nil, wbOBTSCombinationsAfterSet), wbEmpty(STOP, 'Marker', cpNormal, True) ], []); wbBSMPSequence := wbRStructs('Bone Data', 'Data', [ wbInteger(BSMP, 'Gender', itU32, wbEnum(['Male', 'Female'])), // should not be sorted!!! wbRArray('Bones', wbRStruct('Bone', [ wbString(BSMB, 'Name'), wbArray(BSMS, 'Values', wbFloat('Value')), wbUnknown(BMMP) ], []) ) ], []); wbEffectsReq := wbRStructs('Effects', 'Effect', [ wbEFID, wbEFIT, wbCTDAs ], [], cpNormal, True); wbRecord(ACTI, 'Activator', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000002} 2, 'Never Fades', {0x00000004} 4, 'Non Occluder', {0x00000040} 6, 'Unknown 6', {0x00000080} 7, 'Heading Marker', {0x00000100} 8, 'Must Update Anims', {0x00000200} 9, 'Hidden From Local Map', {0x00000400} 10, 'Headtrack Marker', {0x00000800} 11, 'Used as Platform', {0x00001000} 13, 'Pack-In Use Only', {0x00008000} 15, 'Has Distant LOD', {0x00010000} 16, 'Random Anim Start', {0x00020000} 17, 'Dangerous', {0x00100000} 20, 'Ignore Object Interaction', {0x00800000} 23, 'Is Marker', {0x02000000} 25, 'Obstacle', {0x04000000} 26, 'NavMesh Generation - Filter', {0x08000000} 27, 'NavMesh Generation - Bounding Box', {0x20000000} 29, 'Child Can Use', {0x40000000} 30, 'NavMesh Generation - Ground' ])), [ wbEDID, wbVMAD, wbOBNDReq, wbPTRN, wbFormIDCk(STCP, 'Sound', [STAG]), wbFULL, wbMODL, wbDEST, wbKSIZ, wbKWDAs, wbPRPS, wbNTRM, wbFTYP, wbStruct(PNAM, 'Marker Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbInteger('Unused', itU8) ]), wbFormIDCk(SNAM, 'Sound - Looping', [SNDR]), wbFormIDCk(VNAM, 'Sound - Activation', [SNDR]), wbFormIDCk(WNAM, 'Water Type', [WATR]), wbATTX, wbInteger(FNAM, 'Flags', itU16, wbFlags([ 'No Displacement', 'Ignored by Sandbox', 'Unknown 2', 'Unknown 3', 'Is a Radio' ])), wbFormIDCk(KNAM, 'Interaction Keyword', [KYWD]), wbStruct(RADR, 'Radio Receiver', [ wbFormIDCk('Sound Model', [SOPM, NULL]), wbFloat('Frequency'), wbFloat('Volume'), wbInteger('Starts Active', itU8, wbBoolEnum), wbInteger('No Signal Static', itU8, wbBoolEnum) ], cpNormal, False, nil, 4), wbCITC, wbCTDAs, wbNVNM ], False, nil, cpNormal, False, nil, wbKeywordsAfterSet); wbRecord(TACT, 'Talking Activator', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000200} 9, 'Hidden From Local Map', {0x00010000} 16, 'Random Anim Start', {0x00020000} 17, 'Radio Station' ]), [17]), [ wbEDID, wbVMAD, wbOBNDReq, wbFULL, wbMODL, wbDEST, wbKSIZ, wbKWDAs, wbUnknown(PNAM, cpIgnore, True), wbFormIDCk(SNAM, 'Looping Sound', [SNDR]), wbUnknown(FNAM, cpIgnore, True), wbFormIDCk(VNAM, 'Voice Type', [VTYP]) ], False, nil, cpNormal, False, nil, wbKeywordsAfterSet); wbRecord(ALCH, 'Ingestible', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x20000000} 29, 'Medicine' ])), [ wbEDID, wbOBNDReq, wbPTRN, wbFULL, wbKSIZ, wbKWDAs, wbMODL, wbICON, wbMICO, wbYNAM, wbZNAM, wbETYP, wbCUSD, wbDEST, wbDESC, wbFloat(DATA, 'Weight', cpNormal, True), wbStruct(ENIT, 'Effect Data', [ wbInteger('Value', itS32), wbInteger('Flags', itU32, wbFlags([ {0x00000001} 'No Auto-Calc', {0x00000002} 'Food Item', {0x00000004} 'Unknown 3', {0x00000008} 'Unknown 4', {0x00000010} 'Unknown 5', {0x00000020} 'Unknown 6', {0x00000040} 'Unknown 7', {0x00000080} 'Unknown 8', {0x00000100} 'Unknown 9', {0x00000200} 'Unknown 10', {0x00000400} 'Unknown 11', {0x00000800} 'Unknown 12', {0x00001000} 'Unknown 13', {0x00002000} 'Unknown 14', {0x00004000} 'Unknown 15', {0x00008000} 'Unknown 16', {0x00010000} 'Medicine', {0x00020000} 'Poison' ])), wbFormID('Addiction'), wbFloat('Addiction Chance'), wbFormIDCk('Sound - Consume', [SNDR, NULL]) ], cpNormal, True), wbLString(DNAM, 'Addiction Name', 0, cpTranslate), wbEffectsReq ], False, nil, cpNormal, False, wbRemoveEmptyKWDA, wbKeywordsAfterSet); wbRecord(AMMO, 'Ammunition', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000004} 2, 'Non-Playable' ])), [ wbEDID, wbOBNDReq, wbPTRN, wbFULL, wbMODL, wbDEST, wbYNAM, wbZNAM, wbDESC, wbKSIZ, wbKWDAs, wbStruct(DATA, 'Data', [ wbInteger('Value', itU32), wbFloat('Weight') ], cpNormal, True, nil, 1), wbStruct(DNAM, '', [ wbFormIDCk('Projectile', [PROJ, NULL]), wbInteger('Flags', itU8, wbFlags([ {0x01} 'Ignores Normal Weapon Resistance', {0x02} 'Non-Playable', {0x04} 'Has Count Based 3D' ])), wbByteArray('Unused', 3), wbFloat('Damage'), wbInteger('Health', itU32) ], cpNormal, True), wbLStringKC(ONAM, 'Short Name', 0, cpTranslate), wbString(NAM1, 'Casing Model'), wbByteArray(NAM2, 'Texture Files Hashes', 0, cpIgnore, false, false, wbNeverShow) ], False, nil, cpNormal, False, wbRemoveEmptyKWDA, wbKeywordsAfterSet); wbRecord(ANIO, 'Animated Object', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000200} 9, 'Unknown 9' ]), [9]), [ wbEDID, wbMODL, wbString(BNAM, 'Unload Event') ]); wbRecord(ARMO, 'Armor', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000004} 2, 'Non-Playable', {0x00000040} 6, 'Shield', {0x00000400} 10, 'Unknown 10', {0x00008000} 15, 'Unknown 15' ])), [ wbEDID, wbVMAD, wbOBNDReq, wbPTRN, wbFULL, wbEITM, wbRStruct('Male world model', [ wbString(MOD2, 'Model Filename'), wbByteArray(MO2T, 'Texture Files Hashes', 0, cpIgnore, false, false, wbNeverShow), wbMO2S ], []), wbString(ICON, 'Male Inventory Image'), wbString(MICO, 'Male Message Icon'), wbRStruct('Female world model', [ wbString(MOD4, 'Model Filename'), wbByteArray(MO4T, 'Texture Files Hashes', 0, cpIgnore, false, false, wbNeverShow), wbMO4S ], []), wbString(ICO2, 'Female Inventory Image'), wbString(MIC2, 'Female Message Icon'), wbBOD2, wbDEST, wbYNAM, wbZNAM, wbETYP, wbFormIDCk(BIDS, 'Block Bash Impact Data Set', [IPDS, NULL]), wbFormIDCk(BAMT, 'Alternate Block Material', [MATT, NULL]), wbFormIDCk(RNAM, 'Race', [RACE]), wbKSIZ, wbKWDAs, wbDESC, wbINRD, wbRArray('Models', wbRStruct('Model', [ wbInteger(INDX, 'Addon Index', itU16), wbFormIDCk(MODL, 'Armor Addon', [ARMA]) ], []) ), wbStruct(DATA, '', [ wbInteger('Value', itS32), wbFloat('Weight'), wbInteger('Health', itU32) ], cpNormal, True), wbStruct(FNAM, '', [ wbInteger('Armor Rating', itU16), wbInteger('Base Addon Index', itU16), wbInteger('Stagger Rating', itU8, wbStaggerEnum), wbUnknown ]), wbArrayS(DAMA, 'Resistances', wbStructSK([0], 'Resistance', [ wbFormIDCk('Damage Type', [DMGT]), wbInteger('Value', itU32) ])), wbFormIDCk(TNAM, 'Template Armor', [ARMO]), wbAPPR, wbObjectTemplate ], False, nil, cpNormal, False, wbARMOAfterLoad, wbKeywordsAfterSet); wbRecord(ARMA, 'Armor Addon', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000040} 6, 'No Underarmor Scaling', {0x00000200} 9, 'Unknown 9', {0x40000000} 30, 'Hi-Res 1st Person Only' ])), [ wbEDID, wbBOD2, wbFormIDCk(RNAM, 'Race', [RACE]), wbStruct(DNAM, 'Data', [ wbInteger('Male Priority', itU8), wbInteger('Female Priority', itU8), // essentialy a number of world models for different weights (Enabled = 2 models _0.nif and _1.nif) wbInteger('Weight slider - Male', itU8, wbFlags([ {0x01} 'Unknown 0', {0x02} 'Enabled' ])), wbInteger('Weight slider - Female', itU8, wbFlags([ {0x01} 'Unknown 0', {0x02} 'Enabled' ])), wbByteArray('Unknown', 2), wbInteger('Detection Sound Value', itU8), wbByteArray('Unknown', 1), wbFloat('Weapon Adjust') ], cpNormal, True), wbRStruct('Male world model', [ wbString(MOD2, 'Model Filename'), wbByteArray(MO2T, 'Texture Files Hashes', 0, cpIgnore, false, false, wbNeverShow), wbMO2S, wbMO2C, wbMO2F ], [], cpNormal, False), wbRStruct('Female world model', [ wbString(MOD3, 'Model Filename'), wbByteArray(MO3T, 'Texture Files Hashes', 0, cpIgnore, false, false, wbNeverShow), wbMO3S, wbMO3C, wbMO3F ], []), wbRStruct('Male 1st Person', [ wbString(MOD4, 'Model Filename'), wbByteArray(MO4T, 'Texture Files Hashes', 0, cpIgnore, false, false, wbNeverShow), wbMO4S, wbMO4C, wbMO4F ], []), wbRStruct('Female 1st Person', [ wbString(MOD5, 'Model Filename'), wbByteArray(MO5T, 'Texture Files Hashes', 0, cpIgnore, false, false, wbNeverShow), wbMO5S, wbMO5C, wbMO5F ], []), wbFormIDCK(NAM0, 'Male Skin Texture', [TXST, NULL]), wbFormIDCK(NAM1, 'Female Skin Texture', [TXST, NULL]), wbFormIDCK(NAM2, 'Male Skin Texture Swap List', [FLST, NULL]), wbFormIDCK(NAM3, 'Female Skin Texture Swap List', [FLST, NULL]), wbRArrayS('Additional Races', wbFormIDCK(MODL, 'Race', [RACE, NULL])), wbFormIDCk(SNDD, 'Footstep Sound', [FSTS, NULL]), wbFormIDCk(ONAM, 'Art Object', [ARTO]), wbBSMPSequence ], False, nil, cpNormal, False, wbARMAAfterLoad); wbRecord(BOOK, 'Book', [ wbEDID, wbVMAD, wbOBNDReq, wbPTRN, wbFULL, wbMODL, wbICON, wbMICO, wbDESCreq, wbDEST, wbYNAM, wbZNAM, wbKSIZ, wbKWDAs, wbFormIDCk(FIMD, 'Featured Item Message', [MESG]), wbStruct(DATA, 'Data', [ wbInteger('Value', itU32), wbFloat('Weight') ], cpNormal, True), wbStruct(DNAM, '', [ wbInteger('Flags', itU8, wbFlags([ {0x01} 'Advance Actor Value', {0x02} 'Can''t be Taken', {0x04} 'Add Spell', {0x08} 'Unknown 3', {0x10} 'Add Perk' ])), wbUnion('Teaches', wbBOOKTeachesDecider, [ wbByteArray('Unused', 4), wbFormIDCk('Actor Value', [AVIF, NULL]), wbFormIDCk('Spell', [SPEL, NULL]), wbFormIDCk('Perk', [PERK, NULL]) ]), wbStruct('Text Offset' , [ wbInteger('X', itU32), wbInteger('Y', itU32) ]) ], cpNormal, True), wbLString(CNAM, 'Description', 0, cpTranslate), wbFormIDCk(INAM, 'Inventory Art', [STAT]) ], False, nil, cpNormal, False, nil, wbKeywordsAfterSet); end; procedure DefineFO4c; procedure ReferenceRecord(aSignature: TwbSignature; const aName: string); begin wbRecord(aSignature, aName, wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000080} 7, 'Turn Off Fire', {0x00000400} 10, 'Persistent', {0x00000800} 11, 'Initially Disabled', {0x10000000} 28, 'Reflected By Auto Water', {0x20000000} 29, 'Don''t Havok Settle', {0x40000000} 30, 'No Respawn' ], True, True)), [ wbEDID, wbVMAD, wbFormIDCk(NAME, 'Projectile', [PROJ, HAZD]), wbFormIDCk(XEZN, 'Encounter Zone', [ECZN]), wbFloat(XHTW, 'Head-Tracking Weight'), wbFloat(XFVC, 'Favor Cost'), wbRArrayS('Reflected/Refracted By', wbStructSK(XPWR, [0], 'Water', [ wbFormIDCk('Reference', [REFR]), wbInteger('Type', itU32, wbFlags([ 'Reflection', 'Refraction' ])) ], cpNormal, False, nil, 1) ), wbRArrayS('Linked References', wbStructSK(XLKR, [0], 'Linked Reference', [ wbFormIDCk('Keyword/Ref', [KYWD, PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA, NULL]), wbFormIDCk('Ref', sigReferences) ], cpNormal, False, nil, 1)), wbRStruct('Activate Parents', [ wbInteger(XAPD, 'Flags', itU8, wbFlags([ 'Parent Activate Only' ], True)), wbRArrayS('Activate Parent Refs', wbStructSK(XAPR, [0], 'Activate Parent Ref', [ wbFormIDCk('Reference', sigReferences), wbFloat('Delay') ]) ) ], []), wbFormIDCk(XASP, 'Unknown', [REFR]), wbUnknown(XATP), wbInteger(XAMC, 'Ammo Count', itU32), wbEmpty(XLKT, 'Linked Ref Transient'), wbFormIDCk(XLYR, 'Layer', [LAYR]), wbFormIDCk(XMSP, 'Material Swap', [MSWP]), wbFormIDCk(XRFG, 'Reference Group', [RFGP]), wbUnknown(XCVR), wbXESP, wbXOWN, wbXRNK, wbFormIDCk(XEMI, 'Emittance', [LIGH, REGN]), wbFormIDCk(XMBR, 'MultiBound Reference', [REFR]), wbEmpty(XIS2, 'Ignored by Sandbox'), wbArray(XLRT, 'Location Ref Type', wbFormIDCk('Ref', [LCRT, NULL])), wbFormIDCk(XLRL, 'Location Reference', [LCRT, LCTN, NULL], False, cpBenignIfAdded), wbXSCL, wbXLOD, wbDataPosRot, wbString(MNAM, 'Comments') ], True, wbPlacedAddInfo); end; begin {>>> Skrim has its own ref record for every projectile type PARW 'Arrow' PBEA 'Beam' PFLA 'Flame' PCON 'Cone' (voice) PBAR 'Barrier' PGRE 'Traps' PHZD 'Hazards' I guess all of them have the same structure <<<} ReferenceRecord(PARW, 'Placed Arrow'); ReferenceRecord(PBAR, 'Placed Barrier'); ReferenceRecord(PBEA, 'Placed Beam'); ReferenceRecord(PCON, 'Placed Cone/Voice'); ReferenceRecord(PFLA, 'Placed Flame'); ReferenceRecord(PGRE, 'Placed Projectile'); ReferenceRecord(PHZD, 'Placed Hazard'); ReferenceRecord(PMIS, 'Placed Missile'); wbRecord(CELL, 'Cell', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000400} 7, 'No Pre Vis', {0x00000400} 10, 'Persistent', {0x00020000} 17, 'Off Limits', {0x00040000} 18, 'Compressed', {0x00080000} 19, 'Can''t Wait' ]), [18]), [ wbEDID, wbFULL, wbInteger(DATA, 'Flags', itU16, wbFlags([ {0x0001} 'Is Interior Cell', {0x0002} 'Has Water', {0x0004} 'Can''t Travel From Here', {0x0008} 'No LOD Water', {0x0010} 'Unknown 5', {0x0020} 'Public Area', {0x0040} 'Hand Changed', {0x0080} 'Show Sky', {0x0100} 'Use Sky Lighting', {0x0200} 'Unknown 10', {0x0400} 'Unknown 11', {0x0800} 'Sunlight Shadows', {0x1000} 'Distant LOD only', {0x2000} 'Player Followers Can''t Travel Here', {0x4000} 'Unknown 15', {0x8000} 'Unknown 16' ]), cpNormal, True, False, nil, wbCELLDATAAfterSet), wbStruct(XCLC, 'Grid', [ wbInteger('X', itS32), wbInteger('Y', itS32), wbInteger('Force Hide Land', itU32, wbFlags([ 'Quad 1', 'Quad 2', 'Quad 3', 'Quad 4' ], True)) ], cpNormal, False, nil, 2), wbByteArray(VISI, 'PreVis Files Timestamp', 2), wbFormIDCk(RVIS, 'In PreVis File Of', [CELL]), wbByteArray(PCMB, 'PreCombined Files Timestamp', 2), wbStruct(XCLL, 'Lighting', [ wbByteColors('Ambient Color'), wbByteColors('Directional Color'), wbByteColors('Fog Color Near'), wbFloat('Fog Near'), wbFloat('Fog Far'), wbInteger('Directional Rotation XY', itS32), wbInteger('Directional Rotation Z', itS32), wbFloat('Directional Fade'), wbFloat('Fog Clip Distance'), wbFloat('Fog Power'), wbAmbientColors, wbByteColors('Fog Color Far'), wbFloat('Fog Max'), wbFloat('Light Fade Begin'), wbFloat('Light Fade End'), wbInteger('Inherits', itU32, wbFlags([ {0x00000001} 'Ambient Color', {0x00000002} 'Directional Color', {0x00000004} 'Fog Color', {0x00000008} 'Fog Near', {0x00000010} 'Fog Far', {0x00000020} 'Directional Rotation', {0x00000040} 'Directional Fade', {0x00000080} 'Clip Distance', {0x00000100} 'Fog Power', {0x00000200} 'Fog Max', {0x00000400} 'Light Fade Distances' ])), wbFloat('Near Height Mid'), wbFloat('Near Height Range'), wbByteColors('Fog Color High Near'), wbByteColors('Fog Color High Far'), wbFloat('High Density Scale'), wbFloat('Fog Near Scale'), wbFloat('Fog Far Scale'), wbFloat('Fog High Near Scale'), wbFloat('Fog High Far Scale'), wbFloat('Far Height Mid'), wbFloat('Far Height Range') ], cpNormal, False, nil, 11), wbInteger(CNAM, 'Precombined Object Level XY', itU8), wbInteger(ZNAM, 'Precombined Object Level Z', itU8), wbByteArray(TVDT, 'Unknown', 0, cpNormal), wbMaxHeightDataCELL, wbFormIDCk(LTMP, 'Lighting Template', [LGTM, NULL], False, cpNormal, True), {>>> XCLW sometimes has $FF7FFFFF and causes invalid floation point <<<} wbFloat(XCLW, 'Water Height', cpNormal, False, 1, -1, nil, nil, 0, wbCELLXCLWGetConflictPriority), wbArrayS(XCLR, 'Regions', wbFormIDCk('Region', [REGN])), wbFormIDCk(XLCN, 'Location', [LCTN]), wbByteArray(XWCN, 'Unknown', 0, cpIgnore), // leftover wbStruct(XWCU, 'Water Velocity', [ wbFloat('X Offset'), wbFloat('Y Offset'), wbFloat('Z Offset'), wbByteArray('Unknown', 4), wbFloat('X Angle'), wbFloat('Y Angle'), wbFloat('Z Angle'), wbByteArray('Unknown', 0) ]), wbFormIDCk(XCWT, 'Water', [WATR]), {--- Ownership ---} wbXOWN, wbXRNK, wbFormIDCk(XILL, 'Lock List', [FLST, NPC_]), wbStruct(XILW, 'Exterior LOD', [ wbFormIDCk('Worldspace', [WRLD]), wbFloat('Offset X'), wbFloat('Offset Y'), wbFloat('Offset Z') ]), wbString(XWEM, 'Water Environment Map'), wbFormIDCk(XCCM, 'Sky/Weather from Region', [REGN]), wbFormIDCk(XCAS, 'Acoustic Space', [ASPC]), wbFormIDCk(XEZN, 'Encounter Zone', [ECZN]), wbFormIDCk(XCMO, 'Music Type', [MUSC]), wbFormIDCk(XCIM, 'Image Space', [IMGS]), wbFormIDCk(XGDR, 'God Rays', [GDRY]), // those can be sorted I think, but makes copying records very slow since some cells have over 22000+ entries // DLC01Lair01 "The Mechanist's Lair" [CELL:010008A3] wbArrayS(XPRI, 'Physics References', wbFormIDCk('Reference', [REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA])), wbStruct(XCRI, 'Combined References', [ wbInteger('Meshes Count', itU32), wbInteger('References Count', itU32), wbArrayS('Meshes', wbInteger('Combined Mesh', itU32, wbCombinedMeshIDToStr, wbCombinedMeshIDToInt), wbCELLCombinedMeshesCounter, cpNormal, False, nil, wbCELLCombinedMeshesAfterSet), wbArrayS('References', wbStructSK([1, 0], 'Reference', [ wbFormIDCk('Reference', [REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA]), wbInteger('Combined Mesh', itU32, wbCombinedMeshIDToStr, wbCombinedMeshIDToInt) ]), wbCELLCombinedRefsCounter, cpNormal, False, nil, wbCELLCombinedRefsAfterSet) ]) ], True, wbCellAddInfo, cpNormal, False{, wbCELLAfterLoad}); wbRecord(CLAS, 'Class', [ wbEDID, wbFULLReq, wbDESCReq, wbICON, wbPRPS, wbStruct(DATA, 'Data', [ wbByteArray('Unknown', 4), wbFloat('Bleedout Default') ]) ]); wbRecord(CLMT, 'Climate', [ wbEDID, wbArrayS(WLST, 'Weather Types', wbStructSK([0], 'Weather Type', [ wbFormIDCk('Weather', [WTHR, NULL]), wbInteger('Chance', itS32), wbFormIDCk('Global', [GLOB, NULL]) ])), wbString(FNAM, 'Sun Texture'), wbString(GNAM, 'Sun Glare Texture'), wbMODL, wbStruct(TNAM, 'Timing', [ wbStruct('Sunrise', [ wbInteger('Begin', itU8, wbClmtTime), wbInteger('End', itU8, wbClmtTime) ]), wbStruct('Sunset', [ wbInteger('Begin', itU8, wbClmtTime), wbInteger('End', itU8, wbClmtTime) ]), wbInteger('Volatility', itU8), wbInteger('Moons / Phase Length', itU8, wbClmtMoonsPhaseLength) ], cpNormal, True) ]); wbRecord(SPGD, 'Shader Particle Geometry', [ wbEDID, wbStruct(DATA, 'Data', [ wbFloat('Gravity Velocity'), wbByteArray('Unknown', 4), wbFloat('Rotation Velocity'), wbByteArray('Unknown', 4), wbFloat('Particle Size X'), wbFloat('Center Offset Min'), wbFloat('Particle Size Y'), wbByteArray('Unknown', 4), wbFloat('Center Offset Min'), wbByteArray('Unknown', 4), wbFloat('Center Offset Max'), wbByteArray('Unknown', 4), wbFloat('Initial Rotation'), wbByteArray('Unknown', 4), wbInteger('# of Subtextures X', itU32), wbByteArray('Unknown', 4), wbInteger('# of Subtextures Y', itU32), wbByteArray('Unknown', 4), wbInteger('Type', itU32, wbEnum([ 'Rain', 'Snow' ])), wbByteArray('Unknown', 4), wbInteger('Box Size', itU32), wbByteArray('Unknown', 4), wbFloat('Particle Density'), wbUnknown ], cpNormal, True, nil, 10), wbString(MNAM, 'Particle Texture') ]); wbRecord(RFCT, 'Visual Effect', [ wbEDID, wbStruct(DATA, 'Effect Data', [ wbFormIDCK('Effect Art', [ARTO, NULL]), wbFormIDCK('Shader', [EFSH, NULL]), wbInteger('Flags', itU32, wbFlags([ {0x00000001} 'Rotate to Face Target', {0x00000002} 'Attach to Camera', {0x00000004} 'Inherit Rotation' ])) ], cpNormal, True) ]); wbRecord(CONT, 'Container', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00008000} 15, 'Has Distant LOD', {0x00010000} 16, 'Random Anim Start', {0x02000000} 25, 'Obstacle', {0x04000000} 26, 'NavMesh Generation - Filter', {0x08000000} 27, 'NavMesh Generation - Bounding Box', {0x40000000} 30, 'NavMesh Generation - Ground' ])), [ wbEDID, wbVMAD, wbOBNDReq, wbPTRN, wbFULL, wbMODL, wbCOCT, wbCNTOs, wbDEST, wbStruct(DATA, '', [ wbInteger('Flags', itU8, wbFlags([ {0x01} 'Allow Sounds When Animation', {0x02} 'Respawns', {0x04} 'Show Owner' ])), wbFloat('Weight') ], cpNormal, True), wbKSIZ, wbKWDAs, wbFTYP, wbPRPS, wbNTRM, wbFormIDCk(SNAM, 'Sound - Open', [SNDR]), wbFormIDCk(QNAM, 'Sound - Close', [SNDR]), wbFormIDCk(TNAM, 'Sound - Take All', [SNDR]), wbFormIDCk(ONAM, 'Filter List', [FLST]) ], True, nil, cpNormal, False, nil, wbContainerAfterSet); wbAIDT := wbStruct(AIDT, 'AI Data', [ {00} wbInteger('Aggression', itU8, wbEnum([ 'Unaggressive', 'Aggressive', 'Very Aggressive', 'Frenzied' ])), {01} wbInteger('Confidence', itU8, wbEnum([ 'Cowardly', 'Cautious', 'Average', 'Brave', 'Foolhardy' ])), {02} wbInteger('Energy Level', itU8), {03} wbInteger('Responsibility', itU8, wbEnum([ 'Any crime', 'Violence against enemies', 'Property crime only', 'No crime' ])), {04} wbInteger('Mood', itU8, wbEnum([ 'Neutral', 'Angry', 'Fear', 'Happy', 'Sad', 'Surprised', 'Puzzled', 'Disgusted' ])), wbInteger('Assistance', itU8, wbEnum([ 'Helps Nobody', 'Helps Allies', 'Helps Friends and Allies' ])), wbStruct('Aggro', [ wbInteger('Aggro Radius Behavior', itU8, wbBoolEnum), wbInteger('Unknown', itU8), wbInteger('Warn', itU32), wbInteger('Warn/Attack', itU32), wbInteger('Attack', itU32) ]), wbByteArray('Unknown', 4) ], cpNormal, True, nil{wbActorTemplateUseAIData}); wbRecord(CSTY, 'Combat Style', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00080000} 19, 'Allow Dual Wielding' ])), [ wbEDID, wbStruct(CSGD, 'General', [ wbFloat('Offensive Mult'), wbFloat('Defensive Mult'), wbFloat('Group Offensive Mult'), wbFloat('Equipment Score Mult - Melee'), wbFloat('Equipment Score Mult - Magic'), wbFloat('Equipment Score Mult - Ranged'), wbFloat('Equipment Score Mult - Shout'), wbFloat('Equipment Score Mult - Unarmed'), wbFloat('Equipment Score Mult - Staff'), wbFloat('Avoid Threat Chance'), wbFloat('Dodge Threat Chance'), wbFloat('Evade Threat Chance') ], cpNormal, True), wbUnknown(CSMD, cpIgnore), wbStruct(CSME, 'Melee', [ wbFloat('Attack Staggered Mult'), wbFloat('Power Attack Staggered Mult'), wbFloat('Power Attack Blocking Mult'), wbFloat('Bash Mult'), wbFloat('Bash Recoil Mult'), wbFloat('Bash Attack Mult'), wbFloat('Bash Power Attack Mult'), wbFloat('Special Attack Mult'), wbFloat('Block When Staggered Mult'), wbFloat('Attack When Staggered Mult') ], cpNormal, True, nil, 9), wbFloat(CSRA, 'Ranged Accuracy Mult', cpNormal, True), wbStruct(CSCR, 'Close Range', [ wbFloat('Dueling - Circle Mult'), wbFloat('Dueling - Fallback Mult'), wbFloat('Flanking - Flank Distance'), wbFloat('Flanking - Stalk Time'), wbFloat('Charging - Charge Distance'), wbFloat('Charging - Throw Probability'), wbFloat('Charging - Sprint Fast Probability'), wbFloat('Charging - Sideswipe Probability'), wbFloat('Charging - Disengane Probability'), wbInteger('Charging - Throw Max Targets', itU32), wbFloat('Flanking - Flank Variance') ], cpNormal, True), wbStruct(CSLR, 'Long Range', [ wbFloat('Strafe Mult'), wbFloat('Adjust Range Mult'), wbFloat('Crouch Mult'), wbFloat('Wait Mult'), wbFloat('Range Mult') ], cpNormal, True, nil, 3), wbFloat(CSCV, 'Cover Search Distance Mult', cpNormal, True), wbStruct(CSFL, 'Flight', [ wbFloat('Hover Chance'), wbFloat('Dive Bomb Chance'), wbFloat('Ground Attack Chance'), wbFloat('Hover Time'), wbFloat('Ground Attack Time'), wbFloat('Perch Attack Chance'), wbFloat('Perch Attack Time'), wbFloat('Flying Attack Chance') ], cpNormal, True), wbInteger(DATA, 'Flags', itU32, wbFlags([ {0x01} 'Dueling', {0x02} 'Flanking', {0x04} 'Allow Dual Wielding', {0x08} 'Charging', {0x10} 'Retarget Any Nearby Melee Target', {0x20} 'Unknown 5' ]), cpNormal, True) ]); end; procedure DefineFO4d; begin wbRecord(DIAL, 'Dialog Topic', [ wbEDID, wbFULL, wbFloat(PNAM, 'Priority', cpNormal, True, 1, -1, nil, nil, 50.0), wbFormIDCk(BNAM, 'Branch', [DLBR]), wbFormIDCk(QNAM, 'Quest', [QUST], False, cpNormal, False), wbFormIDCk(KNAM, 'Keyword', [KYWD]), wbStruct(DATA, 'Data', [ // this should not be named Flags since TwbFile.BuildReachable // expects Top-Level flag here from FNV wbInteger('Topic Flags', itU8, wbFlags([ 'Do All Before Repeating', 'Unknown 1', 'Unknown 2' ]), cpNormal, True), wbInteger('Category', itU8, wbEnum([ {0} 'Player', {1} 'Command', {2} 'Scene', {3} 'Combat', {4} 'Favor', {5} 'Detection', {6} 'Service', {7} 'Miscellaneous' ])), wbInteger('Subtype', itU16, wbEnum([ { 0} 'Custom', { 1} 'ForceGreet', { 2} 'Rumors', { 3} 'Custom', { 4} 'Call', { 5} 'Follow', { 6} 'Move', { 7} 'Attack', { 8} 'Inspect', { 9} 'Retrieve', {10} 'Stay', {11} 'Release', {12} 'ShowRelationships', {13} 'Reject', {14} 'Heal', {15} 'Assign', {16} 'Enter', {17} 'Custom', {18} 'Show', {19} 'Agree', {20} 'Refuse', {21} 'ExitFavorState', {22} 'MoralRefusal', {23} 'Trade', {24} 'PathingRefusal', {25} 'Attack', {26} 'PowerAttack', {27} 'Bash', {28} 'Hit', {29} 'Flee', {30} 'BleedOut', {31} 'AvoidThreat', {32} 'Death', {33} 'Block', {34} 'Taunt', {35} 'ThrowGrenade', {36} 'AllyKilled', {37} 'OrderFallback', {38} 'OrderMoveUp', {39} 'OrderFlank', {40} 'OrderTakeCover', {41} 'Retreat', {42} 'CoverMe', {43} 'SuppressiveFire', {44} 'CrippledLimb', {45} 'PairedAttack', {46} 'Steal', {47} 'Yield', {48} 'AcceptYield', {49} 'PickpocketCombat', {50} 'Assault', {51} 'Murder', {52} 'AssaultNC', {53} 'MurderNC', {54} 'PickpocketNC', {55} 'StealFromNC', {56} 'TrespassAgainstNC', {57} 'Trespass', {58} 'UNUSED01', {59} 'VoicePowerStartShort', {60} 'VoicePowerStartLong', {61} 'VoicePowerEndShort', {62} 'VoicePowerEndLong', {63} 'AlertIdle', {64} 'LostIdle', {65} 'NormalToAlert', {66} 'NormalToCombat', {67} 'NormalToLost', {68} 'AlertToNormal', {69} 'AlertToCombat', {70} 'CombatToNormal', {71} 'CombatToLost', {72} 'LostToNormal', {73} 'LostToCombat', {74} 'DetectFriendDie', {75} 'ServiceRefusal', {76} 'Repair', {77} 'Travel', {78} 'Training', {79} 'BarterExit', {80} 'RepairExit', {81} 'Recharge', {82} 'RechargeExit', {83} 'TrainingExit', {84} 'ObserveCombat', {85} 'NoticeCorpse', {86} 'TimeToGo', {87} 'Goodbye', {88} 'Hello', {89} 'SwingMeleeWeapon', {90} 'ShootBow', {91} 'ZKeyObject', {92} 'Jump', {93} 'KnockOverObject', {94} 'DestroyObject', {95} 'StandonFurniture', {96} 'LockedObject', {97} 'PickpocketTopic', {98} 'PursueIdleTopic', {99} 'SharedInfo', {100} 'SceneChoice', {101} 'PlayerCastProjectileSpell', {102} 'PlayerCastSelfSpell', {103} 'PlayerShout', {104} 'Idle', {105} 'EnterSprintBreath', {106} 'EnterBowZoomBreath', {107} 'ExitBowZoomBreath', {108} 'ActorCollidewithActor', {109} 'PlayerinIronSights', {110} 'OutofBreath', {111} 'CombatGrunt', {112} 'LeaveWaterBreath', {113} 'ImpatientPostitive', {114} 'ImpatientNegative', {115} 'ImpatientNeutral', {116} 'ImpatientQuestion', {117} 'WaitingForPlayerInput', {118} 'Greeting', {119} 'PlayerActivateDoor', {120} 'PlayerActivateTerminals', {121} 'PlayerActivateFurniture', {122} 'PlayerActivateActivators', {123} 'PlayerActivateContainer', {124} 'PlayerAquireFeaturedItem' ])) ]), wbString(SNAM, 'Subtype Name', 4), wbInteger(TIFC, 'Info Count', itU32, nil, cpBenign) ]); wbRecord(DOOR, 'Door', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000010} 4, 'Non Occluder', {0x00008000} 15, 'Has Distant LOD', {0x00010000} 16, 'Random Anim Start', {0x00800000} 23, 'Is Marker' ])), [ wbEDID, wbVMAD, wbOBNDReq, wbPTRN, wbFULL, wbMODL, wbDEST, wbKSIZ, wbKWDAs, wbNTRM, wbFormIDCk(SNAM, 'Sound - Open', [SNDR]), wbFormIDCk(ANAM, 'Sound - Close', [SNDR]), wbFormIDCk(BNAM, 'Sound - Loop', [SNDR]), wbInteger(FNAM, 'Flags', itU8, wbFlags([ '', 'Automatic', 'Hidden', 'Minimal Use', 'Sliding', 'Do Not Open in Combat Search', 'No "To" Text' ]), cpNormal, True), wbLStringKC(ONAM, 'Alternate Text - Open', 0, cpTranslate), wbLStringKC(CNAM, 'Alternate Text - Close', 0, cpTranslate) ]); wbBlendModeEnum := wbEnum([ '', 'Zero', 'One', 'Source Color', 'Source Inverse Color', 'Source Alpha', 'Source Inverted Alpha', 'Dest Alpha', 'Dest Inverted Alpha', 'Dest Color', 'Dest Inverse Color', 'Source Alpha SAT' ]); wbBlendOpEnum := wbEnum([ '', 'Add', 'Subtract', 'Reverse Subtract', 'Minimum', 'Maximum' ]); wbZTestFuncEnum := wbEnum([ '', '', '', 'Equal To', '', 'Greater Than', '', 'Greater Than or Equal To' ]); wbRecord(EFSH, 'Effect Shader', [ wbEDID, wbString(ICON, 'Fill Texture'), wbString(ICO2, 'Particle Shader Texture'), wbString(NAM7, 'Holes Texture'), wbString(NAM8, 'Membrane Palette Texture'), wbString(NAM9, 'Particle Palette Texture'), wbUnknown(DATA), // if form version < 62, ignored otherwise // format depends on Form Version (appear with form version 62, changed in form version 106), different for older records starting from the first field wbUnion(DNAM, '', wbEFSHFormatDecider, [ wbStruct('Data', [ wbInteger('Membrane Shader - Source Blend Mode', itU32, wbBlendModeEnum), wbInteger('Membrane Shader - Blend Operation', itU32, wbBlendOpEnum), wbInteger('Membrane Shader - Z Test Function', itU32, wbZTestFuncEnum), wbByteColors('Fill/Texture Effect - Color Key 1'), wbFloat('Fill/Texture Effect - Alpha Fade In Time'), wbFloat('Fill/Texture Effect - Full Alpha Time'), wbFloat('Fill/Texture Effect - Alpha Fade Out Time'), wbFloat('Fill/Texture Effect - Presistent Alpha Ratio'), wbFloat('Fill/Texture Effect - Alpha Pulse Amplitude'), wbFloat('Fill/Texture Effect - Alpha Pulse Frequency'), wbFloat('Fill/Texture Effect - Texture Animation Speed (U)'), wbFloat('Fill/Texture Effect - Texture Animation Speed (V)'), wbFloat('Edge Effect - Fall Off'), wbByteColors('Edge Effect - Color'), wbFloat('Edge Effect - Alpha Fade In Time'), wbFloat('Edge Effect - Full Alpha Time'), wbFloat('Edge Effect - Alpha Fade Out Time'), wbFloat('Edge Effect - Persistent Alpha Ratio'), wbFloat('Edge Effect - Alpha Pulse Amplitude'), wbFloat('Edge Effect - Alpha Pulse Frequency'), wbFloat('Fill/Texture Effect - Full Alpha Ratio'), wbFloat('Edge Effect - Full Alpha Ratio'), wbInteger('Membrane Shader - Dest Blend Mode', itU32, wbBlendModeEnum), wbFloat('Holes Animation - Start Time'), wbFloat('Holes Animation - End Time'), wbFloat('Holes Animation - Start Value'), wbFloat('Holes Animation - End Value'), wbFormIDCk('Ambient Sound', [SNDR, NULL]), wbByteColors('Fill/Texture Effect - Color Key 2'), wbByteColors('Fill/Texture Effect - Color Key 3'), wbInteger('Unknown', itU8), wbStruct('Fill/Texture Effect - Color Key Scale/Time', [ wbFloat('Color Key 1 - Scale'), wbFloat('Color Key 2 - Scale'), wbFloat('Color Key 3 - Scale'), wbFloat('Color Key 1 - Time'), wbFloat('Color Key 2 - Time'), wbFloat('Color Key 3 - Time') ]), wbInteger('Flags', itU32, wbFlags([ 'No Membrane Shader', 'Membrane Grayscale Color', 'Membrane Grayscale Alpha', 'No Particle Shader', 'Edge Effect - Inverse', 'Affect Skin Only', 'Texture Effect - Ignore Alpha', 'Texture Effect - Project UVs', 'Ignore Base Geometry Alpha', 'Texture Effect - Lighting', 'Texture Effect - No Weapons', 'Use Alpha Sorting', 'Prefer Dismembered Limbs', 'Unknown 13', 'Unknown 14', 'Particle Animated', 'Particle Grayscale Color', 'Particle Grayscale Alpha', 'Unknown 18', 'Unknown 19', 'Unknown 20', 'Unknown 21', 'Unknown 22', 'Unknown 23', 'Use Blood Geometry (Weapons Only)' ])), wbFloat('Fill/Texture Effect - Texture Scale (U)'), wbFloat('Fill/Texture Effect - Texture Scale (V)') ]), wbStruct('Data (old format)', [ wbByteArray('Unknown', 1), wbInteger('Membrane Shader - Source Blend Mode', itU32, wbBlendModeEnum), wbInteger('Membrane Shader - Blend Operation', itU32, wbBlendOpEnum), wbInteger('Membrane Shader - Z Test Function', itU32, wbZTestFuncEnum), wbByteColors('Fill/Texture Effect - Color Key 1'), wbFloat('Fill/Texture Effect - Alpha Fade In Time'), wbFloat('Fill/Texture Effect - Full Alpha Time'), wbFloat('Fill/Texture Effect - Alpha Fade Out Time'), wbFloat('Fill/Texture Effect - Presistent Alpha Ratio'), wbFloat('Fill/Texture Effect - Alpha Pulse Amplitude'), wbFloat('Fill/Texture Effect - Alpha Pulse Frequency'), wbFloat('Fill/Texture Effect - Texture Animation Speed (U)'), wbFloat('Fill/Texture Effect - Texture Animation Speed (V)'), wbFloat('Edge Effect - Fall Off'), wbByteColors('Edge Effect - Color'), wbFloat('Edge Effect - Alpha Fade In Time'), wbFloat('Edge Effect - Full Alpha Time'), wbFloat('Edge Effect - Alpha Fade Out Time'), wbFloat('Edge Effect - Persistent Alpha Ratio'), wbFloat('Edge Effect - Alpha Pulse Amplitude'), wbFloat('Edge Effect - Alpha Pulse Frequency'), wbFloat('Fill/Texture Effect - Full Alpha Ratio'), wbFloat('Edge Effect - Full Alpha Ratio'), wbInteger('Membrane Shader - Dest Blend Mode', itU32, wbBlendModeEnum), wbInteger('Particle Shader - Source Blend Mode', itU32, wbBlendModeEnum), wbInteger('Particle Shader - Blend Operation', itU32, wbBlendOpEnum), wbInteger('Particle Shader - Z Test Function', itU32, wbZTestFuncEnum), wbInteger('Particle Shader - Dest Blend Mode', itU32, wbBlendModeEnum), wbFloat('Particle Shader - Particle Birth Ramp Up Time'), wbFloat('Particle Shader - Full Particle Birth Time'), wbFloat('Particle Shader - Particle Birth Ramp Down Time'), wbFloat('Particle Shader - Full Particle Birth Ratio'), wbFloat('Particle Shader - Persistant Particle Count'), wbFloat('Particle Shader - Particle Lifetime'), wbFloat('Particle Shader - Particle Lifetime +/-'), wbFloat('Particle Shader - Initial Speed Along Normal'), wbFloat('Particle Shader - Acceleration Along Normal'), wbFloat('Particle Shader - Initial Velocity #1'), wbFloat('Particle Shader - Initial Velocity #2'), wbFloat('Particle Shader - Initial Velocity #3'), wbFloat('Particle Shader - Acceleration #1'), wbFloat('Particle Shader - Acceleration #2'), wbFloat('Particle Shader - Acceleration #3'), wbFloat('Particle Shader - Scale Key 1'), wbFloat('Particle Shader - Scale Key 2'), wbFloat('Particle Shader - Scale Key 1 Time'), wbFloat('Particle Shader - Scale Key 2 Time'), wbByteColors('Color Key 1 - Color'), wbByteColors('Color Key 2 - Color'), wbByteColors('Color Key 3 - Color'), wbFloat('Color Key 1 - Color Alpha'), wbFloat('Color Key 2 - Color Alpha'), wbFloat('Color Key 3 - Color Alpha'), wbFloat('Color Key 1 - Color Key Time'), wbFloat('Color Key 2 - Color Key Time'), wbFloat('Color Key 3 - Color Key Time'), wbFloat('Particle Shader - Initial Speed Along Normal +/-'), wbFloat('Particle Shader - Initial Rotation (deg)'), wbFloat('Particle Shader - Initial Rotation (deg) +/-'), wbFloat('Particle Shader - Rotation Speed (deg/sec)'), wbFloat('Particle Shader - Rotation Speed (deg/sec) +/-'), wbFormIDCk('Addon Models', [DEBR, NULL]), wbFloat('Holes - Start Time'), wbFloat('Holes - End Time'), wbFloat('Holes - Start Val'), wbFloat('Holes - End Val'), wbFloat('Edge Width (alpha units)'), wbByteColors('Edge Color'), wbFloat('Explosion Wind Speed'), wbInteger('Texture Count U', itU32), wbInteger('Texture Count V', itU32), wbFloat('Addon Models - Fade In Time'), wbFloat('Addon Models - Fade Out Time'), wbFloat('Addon Models - Scale Start'), wbFloat('Addon Models - Scale End'), wbFloat('Addon Models - Scale In Time'), wbFloat('Addon Models - Scale Out Time'), wbFormIDCk('Ambient Sound', [SNDR, NULL]), wbByteColors('Fill/Texture Effect - Color Key 2'), wbByteColors('Fill/Texture Effect - Color Key 3'), wbStruct('Fill/Texture Effect - Color Key Scale/Time', [ wbFloat('Color Key 1 - Scale'), wbFloat('Color Key 2 - Scale'), wbFloat('Color Key 3 - Scale'), wbFloat('Color Key 1 - Time'), wbFloat('Color Key 2 - Time'), wbFloat('Color Key 3 - Time') ]), wbFloat('Color Scale'), wbFloat('Birth Position Offset'), wbFloat('Birth Position Offset Range +/-'), wbStruct('Particle Shader Animated', [ wbInteger('Start Frame', itU32), wbInteger('Start Frame Variation', itU32), wbInteger('End Frame', itU32), wbInteger('Loop Start Frame', itU32), wbInteger('Loop Start Variation', itU32), wbInteger('Frame Count', itU32), wbInteger('Frame Count Variation', itU32) ]), wbInteger('Flags', itU32, wbFlags([ 'No Membrane Shader', 'Membrane Grayscale Color', 'Membrane Grayscale Alpha', 'No Particle Shader', 'Edge Effect Inverse', 'Affect Skin Only', 'Ignore Alpha', 'Project UVs', 'Ignore Base Geometry Alpha', 'Lighting', 'No Weapons', 'Unknown 11', 'Unknown 12', 'Unknown 13', 'Unknown 14', 'Particle Animated', 'Particle Grayscale Color', 'Particle Grayscale Alpha', 'Unknown 18', 'Unknown 19', 'Unknown 20', 'Unknown 21', 'Unknown 22', 'Unknown 23', 'Use Blood Geometry' ])), wbFloat('Fill/Texture Effect - Texture Scale (U)'), wbFloat('Fill/Texture Effect - Texture Scale (V)'), wbInteger('Scene Graph Emit Depth Limit (unused)', itU16) ]) ], cpNormal, True), wbMODL ]); wbRecord(ENCH, 'Object Effect', [ wbEDID, wbOBNDReq, wbFULL, wbStruct(ENIT, 'Effect Data', [ wbInteger('Enchantment Cost', itS32), wbInteger('Flags', itU32, wbFlags([ 'No Auto-Calc', '', 'Extend Duration On Recast' ])), wbInteger('Cast Type', itU32, wbCastEnum), wbInteger('Enchantment Amount', itS32), wbInteger('Target Type', itU32, wbTargetEnum), wbInteger('Enchant Type', itU32, wbEnum([], [ $06, 'Enchantment', $0C, 'Staff Enchantment' ])), wbFloat('Charge Time'), wbFormIDCk('Base Enchantment', [ENCH, NULL]), wbFormIDCk('Worn Restrictions', [FLST, NULL]) ], cpNormal, True, nil, 8), wbEffectsReq ]); {wbRecord(EYES, 'Eyes', [ wbEDID ]);} wbRecord(FACT, 'Faction', [ wbEDID, wbFULL, wbRArrayS('Relations', wbStructSK(XNAM, [0], 'Relation', [ wbFormIDCkNoReach('Faction', [FACT, RACE]), wbInteger('Modifier', itS32), wbInteger('Group Combat Reaction', itU32, wbEnum([ {0x00000001} 'Neutral', {0x00000002} 'Enemy', {0x00000004} 'Ally', {0x00000008} 'Friend' ])) ])), wbStruct(DATA, 'Flags', [ wbInteger('Flags', itU32, wbFlags([ {0x00000001} 'Hidden From NPC', {0x00000002} 'Special Combat', {0x00000004} 'Unknown 3', {0x00000008} 'Unknown 4', {0x00000010} 'Unknown 5', {0x00000020} 'Unknown 6', {0x00000040} 'Track Crime', {0x00000080} 'Ignore Crimes: Murder', {0x00000100} 'Ignore Crimes: Assault', {0x00000200} 'Ignore Crimes: Stealing', {0x00000400} 'Ignore Crimes: Trespass', {0x00000800} 'Do Not Report Crimes Against Members', {0x00001000} 'Crime Gold - Use Defaults', {0x00002000} 'Ignore Crimes: Pickpocket', {0x00004000} 'Vendor', {0x00008000} 'Can Be Owner', {0x00010000} 'Ignore Crimes: Werewolf (unused)' ])) ], cpNormal, True, nil, 1), wbFormIDCk(JAIL, 'Exterior Jail Marker', [REFR]), wbFormIDCk(WAIT, 'Follower Wait Marker', [REFR]), wbFormIDCk(STOL, 'Stolen Goods Container', [REFR]), wbFormIDCk(PLCN, 'Player Inventory Container', [REFR]), wbFormIDCk(CRGR, 'Shared Crime Faction List', [FLST]), wbFormIDCk(JOUT, 'Jail Outfit', [OTFT]), wbStruct(CRVA, 'Crime Values', [ wbInteger('Arrest', itU8, wbBoolEnum), wbInteger('Attack On Sight', itU8, wbBoolEnum), wbInteger('Murder', itU16), wbInteger('Assault', itU16), wbInteger('Trespass', itU16), wbInteger('Pickpocket', itU16), wbInteger('Unknown', itU16), wbFloat('Steal Multiplier'), wbInteger('Escape', itU16), wbInteger('Werewolf (unused)', itU16) ], cpNormal, False, nil, 7), wbRStructsSK('Ranks', 'Rank', [0], [ wbInteger(RNAM, 'Rank#', itU32), wbLString(MNAM, 'Male Title', 0, cpTranslate), wbLString(FNAM, 'Female Title', 0, cpTranslate), wbString(INAM, 'Insignia (unused)') ], []), wbFormIDCk(VEND, 'Vendor Buy/Sell List', [FLST]), wbFormIDCk(VENC, 'Merchant Container', [REFR]), wbStruct(VENV, 'Vendor Values', [ wbInteger('Start Hour', itU16), wbInteger('End Hour', itU16), wbInteger('Radius', itU16), wbByteArray('Unknown 1', 2), wbInteger('Buys Stolen Items', itU8, wbBoolEnum), wbInteger('Buy/Sell Everything Not In List?', itU8, wbBoolEnum), wbInteger('Buys NonStolen Items', itU8, wbBoolEnum), wbInteger('Unknown', itU8) ]), wbPLVD, wbCITC, wbCTDAsCount ], False, nil, cpNormal, False, nil {wbFACTAfterLoad}, wbConditionsAfterSet); wbRecord(FURN, 'Furniture', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000004} 2, 'Unknown 2', {0x00000010} 4, 'Unknown 4', {0x00000080} 7, 'Is Perch', {0x00002000} 13, 'Unknown 13', {0x00008000} 15, 'Has Distant LOD', {0x00010000} 16, 'Random Anim Start', {0x00800000} 23, 'Is Marker', {0x02000000} 25, 'Power Armor', {0x10000000} 28, 'Must Exit To Talk', {0x20000000} 29, 'Child Can Use' ])), [ wbEDID, wbVMAD, wbOBNDReq, wbPTRN, wbFULL, wbMODL, wbDEST, wbKSIZ, wbKWDAs, wbPRPS, wbNTRM, wbFTYP, wbUnknown(PNAM), wbFormIDCk(WNAM, 'Drinking Water Type', [WATR]), wbATTX, wbInteger(FNAM, 'Flags', itU16, wbFlags([ {0x0001} 'Unknown 0', {0x0002} 'Ignored By Sandbox' ])), wbCITC, wbCTDAsCount, wbCOCT, wbCNTOs, wbMNAMFurnitureMarker, wbStruct(WBDT, 'Workbench Data', [ wbInteger('Bench Type', itU8, wbEnum([ {0} 'None', {1} 'Create Object', // used only for MS11Workbench [FURN:00091FD5] {2} 'Weapons', // used for the Weapons (plural) workbench {3} 'Enchanting (unused)', // not used {4} 'Enchanting Experiment (unused)', // not used {5} 'Alchemy', // used for Chemistry and Cooking, so Alchemy is probably okay {6} 'Alchemy Experiment (unused)', // not used {7} 'Armor', // FO4 calls this the Armor workbench, no mention of Smithing {8} 'Power Armor', // used for Power Armor stations {9} 'Robot Mod' // used for Robot stations ])), wbInteger('Uses Skill', itS8, wbSkillEnum) ], cpNormal, True, nil, 1), wbFormIDCk(NAM1, 'Associated Form', [ARMO, WEAP, PERK, SPEL, HAZD]), wbRArray('Markers', wbRStruct('Marker', [ wbInteger(ENAM, 'Marker Index', itS32), wbStruct(NAM0, 'Disabled Entry Points', [ wbByteArray('Unknown', 2), wbInteger('Disabled Points', itU16, wbFurnitureEntryTypeFlags) ]) //wbFormIDCk(FNMK, 'Marker Keyword', [KYWD, NULL]) ], [])), wbRArray('Marker Entry Points', wbStruct(FNPR, 'Marker', [ wbInteger('Type', itU16, wbFurnitureAnimTypeEnum), wbInteger('Entry Points', itU16, wbFurnitureEntryTypeFlags) ])), wbString(XMRK, 'Marker Model'), wbSNAMMarkerParams, wbNVNM, wbAPPR, wbObjectTemplate ], False, nil, cpNormal, False, nil, wbKeywordsAfterSet); wbRecord(GLOB, 'Global', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000040} 6, 'Constant' ])), [ wbEDID, wbInteger(FNAM, 'Type', itU8, wbEnum([], [ 0, 'Unknown 0', Ord('s'), 'Short', Ord('l'), 'Long', Ord('f'), 'Float', Ord('b'), 'Boolean' ]), cpNormal, True), wbFloat(FLTV, 'Value', cpNormal, True) ]); wbRecord(GMST, 'Game Setting', [ wbString(EDID, 'Editor ID', 0, cpCritical, True, nil, wbGMSTEDIDAfterSet), wbUnion(DATA, 'Value', wbGMSTUnionDecider, [ wbLString('Name', 0, cpTranslate), wbInteger('Int', itS32), wbFloat('Float'), wbInteger('Bool', itU32, wbBoolEnum) ], cpNormal, True) ]); wbRecord(KYWD, 'Keyword', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00080000} {15} 15, 'Restricted' ])), [ wbEDID, wbCNAM, wbString(DNAM, 'Notes'), wbInteger(TNAM, 'Type', itU32, wbKeywordTypeEnum), wbFormIDCk(DATA, 'Attraction Rule', [AORU]), wbFULL, wbString(NNAM, 'Display Name') {Legacy record replaced with FULL} ]); end; procedure DefineFO4e; begin wbRecord(LCRT, 'Location Reference Type', [ wbEDID, wbCNAM, wbUnknown(TNAM) ]); wbRecord(AACT, 'Action', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00080000} {15} 15, 'Restricted' ])), [ wbEDID, wbCNAM, wbString(DNAM, 'Notes'), wbInteger(TNAM, 'Type', itU32, wbKeywordTypeEnum), wbFormIDCk(DATA, 'Attraction Rule', [AORU]), wbFULL ]); wbRecord(TXST, 'Texture Set', [ wbEDID, wbOBNDReq, wbRStruct('Textures (RGB/A)', [ wbString(TX00, 'Difuse'), wbString(TX01, 'Normal/Gloss'), wbString(TX03, 'Glow'), wbString(TX04, 'Height'), wbString(TX05, 'Environment'), wbString(TX02, 'Wrinkles'), {TX05 TX02 TX06 Yes this has to go here} wbString(TX06, 'Multilayer'), wbString(TX07, 'Smooth Spec') ], []), wbDODT, wbInteger(DNAM, 'Flags', itU16, wbFlags([ {0x0001} 'No Specular Map', {0x0002} 'Facegen Textures', {0x0004} 'Has Model Space Normal Map' ]), cpNormal, True), wbString(MNAM, 'Material') ]); wbRecord(HDPT, 'Head Part', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000004} 2, 'Non-Playable' ])), [ wbEDID, wbFULL, wbMODL, wbInteger(DATA, 'Flags', itU8, wbFlags([ {0x01} 'Playable', {0x02} 'Male', {0x04} 'Female', {0x10} 'Is Extra Part', {0x20} 'Use Solid Tint', {0x40} 'Uses Body Texture' ]), cpNormal, True), wbInteger(PNAM, 'Type', itU32, wbEnum([ 'Misc', 'Face', 'Eyes', 'Hair', 'Facial Hair', 'Scar', 'Eyebrows', 'Meatcaps', 'Teeth', 'Head Rear' ])), wbRArrayS('Extra Parts', wbFormIDCk(HNAM, 'Part', [HDPT]) ), wbRStructs('Parts', 'Part', [ wbInteger(NAM0, 'Part Type', itU32, wbEnum([ 'Race Morph', 'Tri', 'Chargen Morph' ])), wbString(NAM1, 'Filename', 0, cpTranslate, True) ], []), wbFormIDCk(TNAM, 'Texture Set', [TXST]), wbFormIDCk(CNAM, 'Color', [CLFM]), wbFormIDCk(RNAM, 'Valid Races', [FLST]), wbCTDAs ]); wbRecord(ASPC, 'Acoustic Space', [ wbEDID, wbOBNDReq, wbFormIDCk(SNAM, 'Looping Sound', [SNDR]), wbFormIDCk(RDAT, 'Use Sound from Region (Interiors Only)', [REGN]), wbFormIDCk(BNAM, 'Environment Type', [REVB]), wbInteger(XTRI, 'Is Interior', itU8, wbBoolEnum, cpNormal, True), wbInteger(WNAM, 'Weather Attenuation (dB)', itU16, wbDiv(100)) ]); wbRecord(MSTT, 'Moveable Static', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000100} 8, 'Must Update Anims', {0x00000200} 9, 'Hidden From Local Map', {0x00000800} 11, 'Used As Platform', {0x00002000} 13, 'Pack-In Use Only', {0x00008000} 15, 'Has Distant LOD', {0x00010000} 16, 'Random Anim Start', {0x00080000} 19, 'Has Currents', {0x02000000} 25, 'Obstacle', {0x04000000} 26, 'NavMesh Generation - Filter', {0x08000000} 27, 'NavMesh Generation - Bounding Box', {0x40000000} 30, 'NavMesh Generation - Ground' ])), [ wbEDID, wbVMAD, wbOBNDReq, wbPTRN, wbFULL, wbMODL, wbDEST, wbKSIZ, wbKWDAs, wbPRPS, wbInteger(DATA, 'On Local Map', itU8, wbBoolEnum, cpNormal, True), wbFormIDCk(SNAM, 'Looping Sound', [SNDR]) ]); end; procedure DefineFO4f; begin wbRecord(IDLM, 'Idle Marker', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x20000000} 29, 'Child Can Use' ])), [ wbEDID, wbOBNDReq, wbKSIZ, wbKWDAs, wbInteger(IDLF, 'Flags', itU8, wbFlags([ 'Run in Sequence', 'Unknown 1', 'Do Once', 'Unknown 3', 'Ignored by Sandbox' ]), cpNormal, False), wbInteger(IDLC, 'Animation Count', itU8, nil, cpBenign), wbFloat(IDLT, 'Idle Timer Setting', cpNormal, False), wbArray(IDLA, 'Animations', wbFormIDCk('Animation', [IDLE]), 0, nil, wbIDLAsAfterSet, cpNormal, False), wbFormIDCk(QNAM, 'Unknown', [KYWD]), wbMODL ], False, nil, cpNormal, False, nil, wbAnimationsAfterSet); wbRecord(PROJ, 'Projectile', [ wbEDID, wbOBNDReq, wbFULL, wbMODL, wbDEST, wbByteArray(DATA, 'Unused', 0, cpIgnore), wbStruct(DNAM, 'Data', [ wbInteger('Flags', itU16, wbFlags([ {0x00001} 'Hitscan', {0x00002} 'Explosion', {0x00004} 'Alt. Trigger', {0x00008} 'Muzzle Flash', {0x00010} 'Unknown 4', {0x00020} 'Can Be Disabled', {0x00040} 'Can Be Picked Up', {0x00080} 'Supersonic', {0x00100} 'Pins Limbs', {0x00200} 'Pass Through Small Transparent', {0x00400} 'Disable Combat Aim Correction', {0x00800} 'Penetrates Geometry', {0x01000} 'Continuous Update', {0x02000} 'Seeks Target' ])), wbInteger('Type', itU16, wbEnum([], [ $01, 'Missile', $02, 'Lobber', $04, 'Beam', $08, 'Flame', $10, 'Cone', $20, 'Barrier', $40, 'Arrow' ])), wbFloat('Gravity'), wbFloat('Speed'), wbFloat('Range'), wbFormIDCk('Light', [LIGH, NULL]), wbFormIDCk('Muzzle Flash - Light', [LIGH, NULL]), wbFloat('Explosion - Alt. Trigger - Proximity'), wbFloat('Explosion - Alt. Trigger - Timer'), wbFormIDCk('Explosion', [EXPL, NULL]), wbFormIDCk('Sound', [SNDR, NULL]), wbFloat('Muzzle Flash - Duration'), wbFloat('Fade Duration'), wbFloat('Impact Force'), wbFormIDCk('Sound - Countdown', [SNDR, NULL]), wbFormIDCk('Sound - Disable', [SNDR, NULL]), wbFormIDCk('Default Weapon Source', [WEAP, NULL]), wbFloat('Cone Spread'), wbFloat('Collision Radius'), wbFloat('Lifetime'), wbFloat('Relaunch Interval'), wbFormIDCk('Decal Data', [TXST, NULL]), wbFormIDCk('Collision Layer', [COLL, NULL]), wbInteger('Tracer Frequency', itU8), wbFormIDCk('VATS Projectile', [PROJ, NULL]) ]), wbRStructSK([0], 'Muzzle Flash Model', [ wbString(NAM1, 'Model Filename'), wbByteArray(NAM2, 'Texture Files Hashes', 0, cpIgnore, false, false, wbNeverShow) ], [], cpNormal, True), wbInteger(VNAM, 'Sound Level', itU32, wbSoundLevelEnum, cpNormal, True) ]); wbRecord(HAZD, 'Hazard', [ wbEDID, wbOBNDReq, wbFULL, wbMODL, wbFormIDCk(MNAM, 'Image Space Modifier', [IMAD, NULL]), wbStruct(DNAM, 'Data', [ wbInteger('Limit', itU32), wbFloat('Radius'), wbFloat('Lifetime'), wbFloat('Image Space Radius'), wbFloat('Target Interval'), wbInteger('Flags', itU32, wbFlags([ {0x01} 'Affects Player Only', {0x02} 'Inherit Duration from Spawn Spell', {0x04} 'Align to Impact Normal', {0x08} 'Inherit Radius from Spawn Spell', {0x10} 'Drop to Ground', {0x20} 'Taper Effectiveness by Proximity' ])), wbFormIDCk('Effect', [SPEL, ENCH, NULL]), wbFormIDCk('Light', [LIGH, NULL]), wbFormIDCk('Impact Data Set', [IPDS, NULL]), wbFormIDCk('Sound', [SNDR, NULL]), wbStruct('Taper Effectiveness', [ wbFloat('Full Effect Radius'), wbFloat('Taper Weight'), wbFloat('Taper Curse') ]) ]) ]); wbSoulGemEnum := wbEnum([ {0} 'None', {1} 'Petty', {2} 'Lesser', {3} 'Common', {4} 'Greater', {5} 'Grand' ]); {wbRecord(SLGM, 'Soul Gem', [ wbEDID ]);} if wbSimpleRecords then begin wbRecord(NAVI, 'Navigation Mesh Info Map', [ wbEDID, wbInteger(NVER, 'Version', itU32), wbRArray('Navigation Map Infos', wbStruct(NVMI, 'Navigation Map Info', [ wbFormIDCk('Navigation Mesh', [NAVM]), wbByteArray('Data', 20), wbArray('Merged To', wbFormIDCk('Mesh', [NAVM]), -1), wbArray('Preferred Merges', wbFormIDCk('Mesh', [NAVM]), -1), wbArray('Linked Doors', wbStruct('Door', [ wbByteArray('Unknown', 4), wbFormIDCk('Door Ref', [REFR]) ]), -1), wbInteger('Is Island', itU8, wbBoolEnum), wbUnion('Island', wbNAVIIslandDataDecider, [ wbNull, wbStruct('Island Data', [ wbByteArray('Unknown', 24), wbArray('Triangles', wbByteArray('Triangle', 6), -1), wbArray('Vertices', wbByteArray('Vertex', 12), -1) ]) ]), wbByteArray('Unknown', 4), wbFormIDCk('Parent Worldspace', [WRLD, NULL]), wbUnion('Parent', wbNAVIParentDecider, [ wbStruct('Coordinates', [ wbInteger('Grid Y', itS16), wbInteger('Grid X', itS16) ]), wbFormIDCk('Parent Cell', [CELL]) ]) ]) ), wbStruct(NVPP, 'Preferred Pathing', [ wbArray('NavMeshes', wbArray('Set', wbFormIDCk('', [NAVM]), -1), -1), wbArray('NavMesh Tree?', wbStruct('', [ wbFormIDCk('NavMesh', [NAVM]), wbInteger('Index/Node', itU32) ]), -1) ]), //wbArray(NVSI, 'Unknown', wbFormIDCk('Navigation Mesh', [NAVM])) wbUnknown(NVSI) ]); wbRecord(NAVM, 'Navigation Mesh', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00040000} 18, 'Compressed', {0x04000000} 26, 'AutoGen', {0x80000000} 31, 'Unknown 31' ]), [18]), [ wbEDID, wbNVNM, // wbStruct(NVNM, 'Geometry', [ // wbByteArray('Unknown', 8), // wbFormIDCk('Parent Worldspace', [WRLD, NULL]), // wbUnion('Parent', wbNVNMParentDecider, [ // wbStruct('Coordinates', [ // wbInteger('Grid Y', itS16), // wbInteger('Grid X', itS16) // ]), // wbFormIDCk('Parent Cell', [CELL]) // ]), // wbArray('Vertices', wbByteArray('Vertex', 12), -1), // wbArray('Triangles', wbByteArray('Triangle', 21), -1), // wbArray('Edge Links', // wbStruct('Edge Link', [ // wbByteArray('Unknown', 4), // wbFormIDCk('Mesh', [NAVM]), // wbInteger('Triangle', itS16), // wbInteger('Unknown', itU8) // ]) // , -1), // wbArray('Door Triangles', // wbStruct('Door Triangle', [ // wbInteger('Triangle before door', itS16), // wbByteArray('Unknown', 4), // wbFormIDCk('Door', [REFR]) // ]) // , -1), // wbUnknown // ]), wbUnknown(ONAM), wbUnknown(NNAM), wbUnknown(MNAM) ], False, wbNAVMAddInfo); end else begin wbRecord(NAVI, 'Navigation Mesh Info Map', [ wbEDID, wbInteger(NVER, 'Version', itU32), wbRArray('Navigation Map Infos', wbStruct(NVMI, 'Navigation Map Info', [ wbFormIDCk('Navigation Mesh', [NAVM]), wbByteArray('Unknown', 4), wbFloat('X'), wbFloat('Y'), wbFloat('Z'), wbInteger('Preferred Merges Flag', itU32), wbArray('Merged To', wbFormIDCk('Mesh', [NAVM]), -1), wbArray('Preferred Merges', wbFormIDCk('Mesh', [NAVM]), -1), wbArray('Linked Doors', wbStruct('Door', [ wbByteArray('Unknown', 4), wbFormIDCk('Door Ref', [REFR]) ]), -1), wbInteger('Is Island', itU8, wbBoolEnum), wbUnion('Island', wbNAVIIslandDataDecider, [ wbNull, wbStruct('Island Data', [ wbFloat('Min X'), wbFloat('Min Y'), wbFloat('Min Z'), wbFloat('Max X'), wbFloat('Max Y'), wbFloat('Max Z'), wbArray('Triangles', wbStruct('Triangle', [ wbArray('Vertices', wbInteger('Vertex', itS16), 3) ]) , -1), wbArray('Vertices', wbStruct('Vertex', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), -1) ]) ]), wbByteArray('Unknown', 4), wbFormIDCk('Parent Worldspace', [WRLD, NULL]), wbUnion('Parent', wbNAVIParentDecider, [ wbStruct('Coordinates', [ wbInteger('Grid Y', itS16), wbInteger('Grid X', itS16) ]), wbFormIDCk('Parent Cell', [CELL]) ]) ]) ), wbStruct(NVPP, 'Preferred Pathing', [ wbArray('NavMeshes', wbArray('Set', wbFormIDCk('', [NAVM]), -1), -1), wbArray('NavMesh Tree?', wbStruct('', [ wbFormIDCk('NavMesh', [NAVM]), wbInteger('Index/Node', itU32) ]), -1) ]), wbArray(NVSI, 'Unknown', wbFormIDCk('Navigation Mesh', [NAVM])) ]); wbRecord(NAVM, 'Navigation Mesh', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00040000} 18, 'Compressed', {0x04000000} 26, 'AutoGen' ]), [18]), [ wbEDID, wbNVNM, // wbStruct(NVNM, 'Geometry', [ // wbInteger('Unknown', itU32), // wbByteArray('Unknown', 4), // wbFormIDCk('Parent Worldspace', [WRLD, NULL]), // wbUnion('Parent', wbNVNMParentDecider, [ // wbStruct('Coordinates', [ // wbInteger('Grid Y', itS16), // wbInteger('Grid X', itS16) // ]), // wbFormIDCk('Parent Cell', [CELL]) // ]), // wbArray('Vertices', wbStruct('Vertex', [ // wbFloat('X'), // wbFloat('Y'), // wbFloat('Z') // ]), -1), // wbArray('Triangles', // wbStruct('Triangle', [ // wbInteger('Vertex 0', itS16), // wbInteger('Vertex 1', itS16), // wbInteger('Vertex 2', itS16), // wbInteger('Edge 0-1', itS16), // wbInteger('Edge 1-2', itS16), // wbInteger('Edge 2-0', itS16), // wbFloat('Height'), // wbByteArray('Unknown', 5) // ]) // , -1), // wbArray('Edge Links', // wbStruct('Edge Link', [ // wbByteArray('Unknown', 4), // wbFormIDCk('Mesh', [NAVM]), // wbInteger('Triangle', itS16), // wbInteger('Unknown', itU8) // ]) // , -1), // wbArray('Door Triangles', // wbStruct('Door Triangle', [ // wbInteger('Triangle before door', itS16), // wbByteArray('Unknown', 4), // wbFormIDCk('Door', [REFR]) // ]) // , -1), // wbUnknown // ]), wbFormID(ONAM), wbArray(NNAM, 'Unknown', wbInteger('Unknown', itU16)), wbUnion(MNAM, 'Unknown', wbSubrecordSizeDecider, [wbNull, wbStruct('Unknown', [ wbFormID('Unknown'), wbInteger('Unknown', itU16), wbInteger('Unused', itU16), wbUnknown ]) ]) ], False, wbNAVMAddInfo); end; end; procedure DefineFO4g; begin wbRecord(EXPL, 'Explosion', [ wbEDID, wbOBNDReq, wbFULL, wbMODL, wbEITM, wbFormIDCk(MNAM, 'Image Space Modifier', [IMAD]), wbStruct(DATA, 'Data', [ wbFormIDCk('Light', [LIGH, NULL]), wbFormIDCk('Sound 1', [SNDR, NULL]), wbFormIDCk('Sound 2', [SNDR, NULL]), wbFormIDCk('Impact Data Set', [IPDS, NULL]), wbFormID('Placed Object'), wbFormIDCk('Spawn Projectile', [PROJ, NULL]), wbFloat('Force'), wbFloat('Damage'), wbFloat('Inner Radius'), wbFloat('Outer Radius'), wbFloat('IS Radius'), wbUnion('Vertical Offset Mult', wbDeciderFormVersion99, [ wbByteArray('Unknown', 4), wbFloat('Vertical Offset Mult') ]), wbInteger('Flags', itU32, wbFlags([ {0x00000001} 'Unknown 0', {0x00000002} 'Always Uses World Orientation', {0x00000004} 'Knock Down - Always', {0x00000008} 'Knock Down - By Formula', {0x00000010} 'Ignore LOS Check', {0x00000020} 'Push Explosion Source Ref Only', {0x00000040} 'Ignore Image Space Swap', {0x00000080} 'Chain', {0x00000100} 'No Controller Vibration', {0x00000200} 'Placed Object Persists', {0x00000400} 'Skip Underwater Tests' ])), wbInteger('Sound Level', itU32, wbSoundLevelEnum), wbFloat('Placed Object AutoFade Delay'), wbInteger('Stagger', itU32, wbEnum([ 'None', 'Small', 'Medium', 'Large', 'Extra Large' ])), wbStruct('Spawn', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z'), wbFloat('Spread Degrees'), wbInteger('Count', itU32) ]) ], cpNormal, True, nil, 13) ]); wbRecord(DEBR, 'Debris', [ wbEDID, wbRStructs('Models', 'Model', [ wbStruct(DATA, 'Data', [ wbInteger('Percentage', itU8), wbString('Model Filename'), wbInteger('Flags', itU8, wbFlags([ 'Has Collision Data' ])) ], cpNormal, True), wbMODT ], [], cpNormal, True) ]); wbRecord(IMGS, 'Image Space', [ wbEDID, wbByteArray(ENAM, 'Unused', 0, cpIgnore), wbStruct(HNAM, 'HDR', [ wbFloat('Eye Adapt Speed'), wbFloat('Tonemap E'), wbFloat('Bloom Threshold'), wbFloat('Bloom Scale'), wbFloat('Auto Exposure Max'), wbFloat('Auto Exposure Min'), wbFloat('Sunlight Scale'), wbFloat('Sky Scale'), wbFloat('Middle Gray') ], cpNormal, True), wbStruct(CNAM, 'Cinematic', [ wbFloat('Saturation'), wbFloat('Brightness'), wbFloat('Contrast') ], cpNormal, True), wbStruct(TNAM, 'Tint', [ wbFloat('Amount'), wbFloatColors('Color') ], cpNormal, True), wbStruct(DNAM, 'Depth of Field', [ wbFloat('Strength'), wbFloat('Distance'), wbFloat('Range'), wbByteArray('Unused', 2, cpIgnore), wbInteger('Sky / Blur Radius', itU16, wbEnum([], [ 16384, 'Radius 0', 16672, 'Radius 1', 16784, 'Radius 2', 16848, 'Radius 3', 16904, 'Radius 4', 16936, 'Radius 5', 16968, 'Radius 6', 17000, 'Radius 7', 16576, 'No Sky, Radius 0', 16736, 'No Sky, Radius 1', 16816, 'No Sky, Radius 2', 16880, 'No Sky, Radius 3', 16920, 'No Sky, Radius 4', 16952, 'No Sky, Radius 5', 16984, 'No Sky, Radius 6', 17016, 'No Sky, Radius 7' ])), wbFloat('Vignette Radius'), wbFloat('Vignette Strength') ], cpNormal, True, nil, 5), wbString(TX00, 'LUT') ]); wbTimeInterpolator := wbStruct('Data', [ wbFloat('Time'), wbFloat('Value') ]); wbColorInterpolator := wbStruct('Data', [ wbFloat('Time'), wbFloat('Red', cpNormal, False, 255, 0), wbFloat('Green', cpNormal, False, 255, 0), wbFloat('Blue', cpNormal, False, 255, 0), wbFloat('Alpha', cpNormal, False, 255, 0) ]); wbRecord(IMAD, 'Image Space Adapter', [ wbEDID, wbStruct(DNAM, 'Data Count', [ wbInteger('Flags', itU32, wbFlags(['Animatable'])), wbFloat('Duration'), wbStruct('HDR', [ wbInteger('Eye Adapt Speed Mult', itU32), wbInteger('Eye Adapt Speed Add', itU32), wbInteger('Bloom Blur Radius Mult', itU32), wbInteger('Bloom Blur Radius Add', itU32), wbInteger('Bloom Threshold Mult', itU32), wbInteger('Bloom Threshold Add', itU32), wbInteger('Bloom Scale Mult', itU32), wbInteger('Bloom Scale Add', itU32), wbInteger('Target Lum Min Mult', itU32), wbInteger('Target Lum Min Add', itU32), wbInteger('Target Lum Max Mult', itU32), wbInteger('Target Lum Max Add', itU32), wbInteger('Sunlight Scale Mult', itU32), wbInteger('Sunlight Scale Add', itU32), wbInteger('Sky Scale Mult', itU32), wbInteger('Sky Scale Add', itU32) ]), wbInteger('Unknown08 Mult', itU32), wbInteger('Unknown48 Add', itU32), wbInteger('Unknown09 Mult', itU32), wbInteger('Unknown49 Add', itU32), wbInteger('Unknown0A Mult', itU32), wbInteger('Unknown4A Add', itU32), wbInteger('Unknown0B Mult', itU32), wbInteger('Unknown4B Add', itU32), wbInteger('Unknown0C Mult', itU32), wbInteger('Unknown4C Add', itU32), wbInteger('Unknown0D Mult', itU32), wbInteger('Unknown4D Add', itU32), wbInteger('Unknown0E Mult', itU32), wbInteger('Unknown4E Add', itU32), wbInteger('Unknown0F Mult', itU32), wbInteger('Unknown4F Add', itU32), wbInteger('Unknown10 Mult', itU32), wbInteger('Unknown50 Add', itU32), wbStruct('Cinematic', [ wbInteger('Saturation Mult', itU32), wbInteger('Saturation Add', itU32), wbInteger('Brightness Mult', itU32), wbInteger('Brightness Add', itU32), wbInteger('Contrast Mult', itU32), wbInteger('Contrast Add', itU32) ]), wbInteger('Unknown14 Mult', itU32), wbInteger('Unknown54 Add', itU32), wbInteger('Tint Color', itU32), wbInteger('Blur Radius', itU32), wbInteger('Double Vision Strength', itU32), wbInteger('Radial Blur Strength', itU32), wbInteger('Radial Blur Ramp Up', itU32), wbInteger('Radial Blur Start', itU32), wbInteger('Radial Blur Flags', itU32, wbFlags(['Use Target'])), wbFloat('Radial Blur Center X'), wbFloat('Radial Blur Center Y'), wbInteger('DoF Strength', itU32), wbInteger('DoF Distance', itU32), wbInteger('DoF Range', itU32), wbInteger('DoF Flags', itU32, wbFlags([ {0x00000001} 'Use Target', {0x00000002} 'Unknown 2', {0x00000004} 'Unknown 3', {0x00000008} 'Unknown 4', {0x00000010} 'Unknown 5', {0x00000020} 'Unknown 6', {0x00000040} 'Unknown 7', {0x00000080} 'Unknown 8', {0x00000100} 'Mode - Front', {0x00000200} 'Mode - Back', {0x00000400} 'No Sky', {0x00000800} 'Blur Radius Bit 2', {0x00001000} 'Blur Radius Bit 1', {0x00002000} 'Blur Radius Bit 0' ])), wbInteger('Radial Blur Ramp Down', itU32), wbInteger('Radial Blur Down Start', itU32), wbInteger('Fade Color', itU32), wbInteger('Motion Blur Strength', itU32), wbUnknown ]), wbArray(BNAM, 'Blur Radius', wbTimeInterpolator), wbArray(VNAM, 'Double Vision Strength', wbTimeInterpolator), wbArray(TNAM, 'Tint Color', wbColorInterpolator), wbArray(NAM3, 'Fade Color', wbColorInterpolator), wbRStruct('Radial Blur', [ wbArray(RNAM, 'Strength', wbTimeInterpolator), wbArray(SNAM, 'RampUp', wbTimeInterpolator), wbArray(UNAM, 'Start', wbTimeInterpolator), wbArray(NAM1, 'RampDown', wbTimeInterpolator), wbArray(NAM2, 'DownStart', wbTimeInterpolator) ], []), wbRStruct('Depth of Field', [ wbArray(WNAM, 'Strength', wbTimeInterpolator), wbArray(XNAM, 'Distance', wbTimeInterpolator), wbArray(YNAM, 'Range', wbTimeInterpolator), wbArray(NAM5, 'Vignette Radius', wbTimeInterpolator), wbArray(NAM6, 'Vignette Strength', wbTimeInterpolator) ], []), wbArray(NAM4, 'Motion Blur Strength', wbTimeInterpolator), wbRStruct('HDR', [ wbArray(_00_IAD, 'Eye Adapt Speed Mult', wbTimeInterpolator), wbArray(_40_IAD, 'Eye Adapt Speed Add', wbTimeInterpolator), wbArray(_01_IAD, 'Bloom Blur Radius Mult', wbTimeInterpolator), wbArray(_41_IAD, 'Bloom Blur Radius Add', wbTimeInterpolator), wbArray(_02_IAD, 'Bloom Threshold Mult', wbTimeInterpolator), wbArray(_42_IAD, 'Bloom Threshold Add', wbTimeInterpolator), wbArray(_03_IAD, 'Bloom Scale Mult', wbTimeInterpolator), wbArray(_43_IAD, 'Bloom Scale Add', wbTimeInterpolator), wbArray(_04_IAD, 'Target Lum Min Mult', wbTimeInterpolator), wbArray(_44_IAD, 'Target Lum Min Add', wbTimeInterpolator), wbArray(_05_IAD, 'Target Lum Max Mult', wbTimeInterpolator), wbArray(_45_IAD, 'Target Lum Max Add', wbTimeInterpolator), wbArray(_06_IAD, 'Sunlight Scale Mult', wbTimeInterpolator), wbArray(_46_IAD, 'Sunlight Scale Add', wbTimeInterpolator), wbArray(_07_IAD, 'Sky Scale Mult', wbTimeInterpolator), wbArray(_47_IAD, 'Sky Scale Add', wbTimeInterpolator) ], []), wbUnknown(_08_IAD), wbUnknown(_48_IAD), wbUnknown(_09_IAD), wbUnknown(_49_IAD), wbUnknown(_0A_IAD), wbUnknown(_4A_IAD), wbUnknown(_0B_IAD), wbUnknown(_4B_IAD), wbUnknown(_0C_IAD), wbUnknown(_4C_IAD), wbUnknown(_0D_IAD), wbUnknown(_4D_IAD), wbUnknown(_0E_IAD), wbUnknown(_4E_IAD), wbUnknown(_0F_IAD), wbUnknown(_4F_IAD), wbUnknown(_10_IAD), wbUnknown(_50_IAD), wbRStruct('Cinematic', [ wbArray(_11_IAD, 'Saturation Mult', wbTimeInterpolator), wbArray(_51_IAD, 'Saturation Add', wbTimeInterpolator), wbArray(_12_IAD, 'Brightness Mult', wbTimeInterpolator), wbArray(_52_IAD, 'Brightness Add', wbTimeInterpolator), wbArray(_13_IAD, 'Contrast Mult', wbTimeInterpolator), wbArray(_53_IAD, 'Contrast Add', wbTimeInterpolator) ], []), wbUnknown(_14_IAD), wbUnknown(_54_IAD) ]); wbRecord(FLST, 'FormID List', [ wbString(EDID, 'Editor ID', 0, cpBenign, True, nil, wbFLSTEDIDAfterSet), wbFULL, wbRArrayS('FormIDs', wbFormID(LNAM, 'FormID'), cpNormal, False, nil, nil, nil, wbFLSTLNAMIsSorted) ]); wbRecord(PERK, 'Perk', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000004} 2, 'Non-Playable' ])), [ wbEDID, wbVMADFragmentedPERK, wbFULL, wbDESCReq, wbString(ICON, 'Image'), wbCTDAs, wbStruct(DATA, 'Data', [ wbInteger('Trait', itU8, wbBoolEnum), wbInteger('Level', itU8), wbInteger('Num Ranks', itU8), wbInteger('Playable', itU8, wbBoolEnum), wbInteger('Hidden', itU8, wbBoolEnum) ], cpNormal, True), wbFormIDCk(SNAM, 'Sound', [SNDR]), wbFormIDCK(NNAM, 'Next Perk', [PERK, NULL]), wbString(FNAM, 'SWF'), wbRStructsSK('Effects', 'Effect', [0, 1], [ wbStructSK(PRKE, [1, 2, 0], 'Header', [ wbInteger('Type', itU8, wbEnum([ 'Quest + Stage', 'Ability', 'Entry Point' ]), cpNormal, False, nil, wbPERKPRKETypeAfterSet), wbInteger('Rank', itU8), wbInteger('Priority', itU8) ]), wbUnion(DATA, 'Effect Data', wbPerkDATADecider, [ wbStructSK([0, 1], 'Quest + Stage', [ wbFormIDCk('Quest', [QUST]), wbInteger('Quest Stage', itU16, wbPerkDATAQuestStageToStr, wbCTDAParam2QuestStageToInt), wbByteArray('Unused', 2) ]), wbFormIDCk('Ability', [SPEL]), wbStructSK([0, 1], 'Entry Point', [ wbInteger('Entry Point', itU8, wbEntryPointsEnum, cpNormal, True, nil{, wbPERKEntryPointAfterSet}), wbInteger('Function', itU8, wbEnum([ {0} 'Unknown 0', {1} 'Set Value', // EPFT=1 {2} 'Add Value', // EPFT=1 {3} 'Multiply Value', // EPFT=1 {4} 'Add Range To Value', // EPFT=2 {5} 'Add Actor Value Mult', // EPFT=2 {6} 'Absolute Value', // no params {7} 'Negative Absolute Value', // no params {8} 'Add Leveled List', // EPFT=3 {9} 'Add Activate Choice', // EPFT=4 {10} 'Select Spell', // EPFT=5 {11} 'Select Text', // EPFT=6 {12} 'Set to Actor Value Mult', // EPFT=2 {13} 'Multiply Actor Value Mult', // EPFT=2 {14} 'Multiply 1 + Actor Value Mult', // EPFT=2 {15} 'Set Text' // EPFT=7 ])), wbInteger('Perk Condition Tab Count', itU8, nil, cpIgnore) ]) ], cpNormal, True), wbRStructsSK('Perk Conditions', 'Perk Condition', [0], [ wbInteger(PRKC, 'Run On (Tab Index)', itS8{, wbPRKCToStr, wbPRKCToInt}), wbCTDAsReq ], [], cpNormal, False{, nil, nil, wbPERKPRKCDontShow}), wbRStruct('Function Parameters', [ wbInteger(EPFT, 'Type', itU8, wbEnum([ {0} 'None', {1} 'Float', {2} 'Float/AV,Float', {3} 'LVLI', {4} 'SPEL,lstring,flags', {5} 'SPEL', {6} 'string', {7} 'lstring', {8} 'AVIF' ])), // case(EPFT) of // 1: EPFD=float // 2: EPFD=float,float // 3: EPFD=LVLI // 4: EPFD=SPEL, EPF2=lstring, EPF3=int32 flags // 5: EPFD=SPEL // 6: EPFD=string // 7: EPFD=lstring wbInteger(EPFB, 'Perk Entry ID (unique)', itU16), wbLString(EPF2, 'Button Label', 0, cpTranslate), wbStruct(EPF3, 'Script Flags', [ wbInteger('Script Flags', itU8, wbFlags([ 'Run Immediately', 'Replace Default' ])), wbByteArray('Unknown', 1) ]), wbUnion(EPFD, 'Data', wbEPFDDecider, [ {0} wbByteArray('Unknown'), {1} wbFloat('Float'), {2} wbStruct('Float, Float', [ wbFloat('Float 1'), wbFloat('Float 2') ]), {3} wbFormIDCk('Leveled Item', [LVLI]), {4} wbFormIDCk('Spell', [SPEL]), {5} wbFormIDCk('Spell', [SPEL]), {6} wbString('Text', 0, cpTranslate), {7} wbLString('Text', 0, cpTranslate), {8} wbStruct('Actor Value, Float', [ wbActorValue, // wbInteger('Actor Value', itU32, wbEPFDActorValueToStr, wbEPFDActorValueToInt), wbFloat('Float') ]) ], cpNormal, False{, wbEPFDDontShow}) ], [], cpNormal, False{, wbPERKPRKCDontShow}), wbEmpty(PRKF, 'End Marker', cpIgnore, True) ], []) ]); wbRecord(BPTD, 'Body Part Data', [ wbEDID, wbMODL, wbRArrayS('Body Parts', wbRStructSK([1], 'Body Part', [ wbLString(BPTN, 'Part Name', 0, cpTranslate), // optional wbString(BPNN, 'Part Node', 0, cpNormal, True), wbString(BPNT, 'VATS Target', 0, cpNormal, True), wbStruct(BPND, '', [ wbFloat('Damage Mult'), wbFormIDCk('Explodable - Debris', [DEBR, NULL]), wbFormIDCk('Explodable - Explosion', [EXPL, NULL]), wbFloat('Explodable - Debris Scale'), wbFormIDCk('Severable - Debris', [DEBR, NULL]), wbFormIDCk('Severable - Explosion', [EXPL, NULL]), wbFloat('Severable - Debris Scale'), wbFloat('Cut - Min'), wbFloat('Cut - Max'), wbFloat('Cut - Radius'), wbFloat('Gore Effects - Local Rotate X', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Gore Effects - Local Rotate Y', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Cut - Tesselation'), wbFormIDCk('Severable - Impact DataSet', [IPDS, NULL]), wbFormIDCk('Explodable - Impact DataSet', [IPDS, NULL]), wbFloat('Explodable - Limb Replacement Scale'), wbInteger('Flags', itU8, wbFlags([ {0x01} 'Severable', {0x02} 'Hit Reaction', {0x04} 'Hit Reaction - Default', {0x08} 'Explodable', {0x10} 'Cut - Meat Cap Sever', {0x20} 'On Cripple', {0x40} 'Explodable - Absolute Chance', {0x80} 'Show Cripple Geometry' ])), wbInteger('Part Type', itU8, wbEnum([ { 0} 'Torso', { 1} 'Head1', { 2} 'Eye', { 3} 'LookAt', { 4} 'Fly Grab', { 5} 'Head2', { 6} 'LeftArm1', { 7} 'LeftArm2', { 8} 'RightArm1', { 9} 'RightArm2', {10} 'LeftLeg1', {11} 'LeftLeg2', {12} 'LeftLeg3', {13} 'RightLeg1', {14} 'RightLeg2', {15} 'RightLeg3', {16} 'Brain', {17} 'Weapon', {18} 'Root', {19} 'COM', {20} 'Pelvis', {21} 'Camera', {22} 'Offset Root', {23} 'Left Foot', {24} 'Right Foot', {25} 'Face Target Source' ])), wbInteger('Health Percent', itU8), wbFormIDCk('Actor Value', [AVIF, NULL]), wbInteger('To Hit Chance', itU8), wbInteger('Explodable - Explosion Chance %', itU8), wbInteger('Non-Lethal Dismemberment Chance', itU8), wbInteger('Severable - Debris Count', itU8), wbInteger('Explodable - Debris Count', itU8), wbInteger('Severable - Decal Count', itU8), wbInteger('Explodable - Decal Count', itU8), wbInteger('Geometry Segment Index', itU8), wbFormIDCk('On Cripple - Art Object', [ARTO, NULL]), wbFormIDCk('On Cripple - Debris', [DEBR, NULL]), wbFormIDCk('On Cripple - Explosion', [EXPL, NULL]), wbFormIDCk('On Cripple - Impact DataSet', [IPDS, NULL]), wbFloat('On Cripple - Debris Scale'), wbInteger('On Cripple - Debris Count', itU8), wbInteger('On Cripple - Decal Count', itU8) ], cpNormal, True), wbString(NAM1, 'Limb Replacement Model', 0, cpNormal, True), wbString(NAM4, 'Gore Effects - Target Bone', 0, cpNormal, True), wbByteArray(NAM5, 'Texture Files Hashes', 0, cpNormal), wbString(ENAM, 'Hit Reaction - Start'), wbString(FNAM, 'Hit Reaction - End'), wbFormIDCk(BNAM, 'Gore Effects - Dismember Blood Art', [ARTO]), wbFormIDCk(INAM, 'Gore Effects - Blood Impact Material Type', [MATT]), wbFormIDCk(JNAM, 'On Cripple - Blood Impact Material Type', [MATT]), wbFormIDCk(CNAM, 'Meat Cap TextureSet', [TXST]), wbFormIDCk(NAM2, 'Collar TextureSet', [TXST]), wbString(DNAM, 'Twist Variable Prefix') ], [], cpNormal, False, nil, True) ) ]); wbRecord(ADDN, 'Addon Node', [ wbEDID, wbOBNDReq, wbMODL, wbInteger(DATA, 'Node Index', itS32, nil, cpNormal, True), wbFormIDCk(SNAM, 'Sound', [SNDR]), wbFormIDCk(LNAM, 'Light', [LIGH]), wbStruct(DNAM, 'Data', [ wbInteger('Master Particle System Cap', itU16), wbInteger('Flags', itU16, wbEnum([ 'No Master Particle System', 'Master Particle System', 'Always Loaded', 'Master Particle System and Always Loaded' ])) ], cpNormal, True) ]); end; procedure DefineFO4h; begin wbRecord(AVIF, 'Actor Value Information', [ wbEDID, wbFULL, wbDESCReq, wbLString(ANAM, 'Abbreviation', 0, cpTranslate), wbFloat(NAM0, 'Default Value'), // Prior to form version 81, it was either 0.0, 1.0 or 100.0, so scale or multiplier ? wbInteger(AVFL, 'Flags', itU32, wbFlags([ // 32 bits Flags, it used to impact NAM0 loading (bits 10, 11, 12) (even though it loads later :) ) 'Unknown 1', 'Unknown 2', 'Unknown 3', 'Unknown 4', 'Unknown 5', 'Unknown 6', 'Unknown 7', 'Unknown 8', 'Unknown 9', 'Unknown 10', 'Unknown 11', 'Unknown 12', 'Unknown 13', 'Unknown 14', 'Unknown 15', 'Unknown 16', 'Unknown 17', 'Unknown 18', 'Unknown 19', 'Unknown 20', 'Minimum 1', 'Maximum 10', 'Maximum 100', 'Multiply By 100', 'Percentage', 'Unknown 26', 'Damage Is Positive', 'God Mode Immune', 'Unknown 29', 'Unknown 30', 'Unknown 31', 'Hardcoded' ])), wbInteger(NAM1, 'Type', itU32, wbEnum([ 'Derived Attribute', 'Special (Attribute)', 'Skill', 'AI Attribute', 'Resistance', 'Condition', 'Charge', 'Int Value', 'Variable', 'Resource' ])) ]); // S.P.E.C.I.A.L start at index 5, so FormID 0x2bc+5 to 0x2bc+11, RadResistIngestion at index 0x29 wbRecord(CAMS, 'Camera Shot', [ wbEDID, wbMODL, wbCTDAs, wbStruct(DATA, 'Data', [ wbInteger('Action', itU32, wbEnum([ {0} 'Shoot', {1} 'Fly', {2} 'Hit', {3} 'Zoom' ])), wbInteger('Location', itU32, wbEnum([ {0} 'Attacker', {1} 'Projectile', {2} 'Target', {3} 'Lead Actor' ])), wbInteger('Target', itU32, wbEnum([ {0} 'Attacker', {1} 'Projectile', {2} 'Target', {3} 'Lead Actor' ])), wbInteger('Flags', itU32, wbFlags([ {0x00000001} 'Position Follows Location', {0x00000002} 'Rotation Follows Target', {0x00000004} 'Don''t Follow Bone', {0x00000008} 'First Person Camera', {0x00000010} 'No Tracer', {0x00000020} 'Start At Time Zero', {0x00000040} 'Don''t Reset Location Spring', {0x00000080} 'Don''t Reset Target Spring' ])), wbStruct('Time Multipliers', [ wbFloat('Player'), wbFloat('Target'), wbFloat('Global') ]), wbFloat('Max Time'), wbFloat('Min Time'), wbFloat('Target % Between Actors'), wbFloat('Near Target Distance'), wbFloat('Location Spring'), wbFloat('Target Spring'), wbStruct('Rotation Offset', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]) ], cpNormal, True, nil, 9), wbFormIDCk(MNAM, 'Image Space Modifier', [IMAD]) ]); wbRecord(CPTH, 'Camera Path', [ wbEDID, wbCTDAs, wbArray(ANAM, 'Related Camera Paths', wbFormIDCk('Related Camera Path', [CPTH, NULL]), ['Parent', 'Previous Sibling'], cpNormal, True), wbInteger(DATA, 'Camera Zoom / Flags', itU8, wbFlags([ {0x01} 'Disable', {0x02} 'Shot List', {0x04} 'Dynamic Camera Times', {0x08} 'Unknown 3', {0x10} 'Unknown 4', {0x20} 'Unknown 5', {0x40} 'Randomize Paths', {0x80} 'Not Must Have Camera Shots' ]), cpNormal, True), wbRArray('Camera Shots', wbFormIDCk(SNAM, 'Camera Shot', [CAMS])) ]); wbRecord(VTYP, 'Voice Type', [ wbEDID, wbInteger(DNAM, 'Flags', itU8, wbFlags([ 'Allow Default Dialog', 'Female' ]), cpNormal, True) ]); wbRecord(MATT, 'Material Type', [ wbEDID, wbFormIDCk(PNAM, 'Material Parent', [MATT, NULL]), wbString(MNAM, 'Material Name'), wbStruct(CNAM, 'Havok Display Color', [ wbFloat('Red', cpNormal, True, 255, 0), wbFloat('Green', cpNormal, True, 255, 0), wbFloat('Blue', cpNormal, True, 255, 0) ]), wbFloat(BNAM, 'Buoyancy'), wbInteger(FNAM, 'Flags', itU32, wbFlags([ 'Stair Material', 'Arrows Stick', 'Can Tunnel' ], False)), wbFormIDCk(HNAM, 'Havok Impact Data Set', [IPDS]), wbString(ANAM, 'Breakable FX'), wbMODT ]); wbRecord(IPCT, 'Impact', [ wbEDID, wbMODL, wbStruct(DATA, '', [ wbFloat('Effect - Duration'), wbInteger('Effect - Orientation', itU32, wbEnum([ 'Surface Normal', 'Projectile Vector', 'Projectile Reflection' ])), wbFloat('Angle Threshold'), wbFloat('Placement Radius'), wbInteger('Sound Level', itU32, wbSoundLevelEnum), wbInteger('Flags', itU8, wbFlags([ {0x01} 'No Decal Data' ])), wbInteger('Impact Result', itU8, wbEnum([ {0} 'Default', {1} 'Destroy', {2} 'Bounce', {3} 'Impale', {4} 'Stick' ])), wbByteArray('Unknown', 2) ], cpNormal, True), wbDODT, wbFormIDCk(DNAM, 'Texture Set', [TXST]), wbFormIDCk(ENAM, 'Secondary Texture Set', [TXST]), wbFormIDCk(SNAM, 'Sound 1', [SNDR]), wbFormIDCk(NAM1, 'Sound 2', [SNDR]), wbFormIDCk(NAM3, 'Footstep Explosion', [EXPL]), wbFormIDCk(NAM2, 'Hazard', [HAZD]), wbFloat(FNAM, 'Footstep Particle Max Dist') ]); wbRecord(IPDS, 'Impact Data Set', [ wbEDID, wbRArrayS('Data', wbStructSK(PNAM, [0], '', [ wbFormIDCk('Material', [MATT]), wbFormIDCk('Impact', [IPCT]) ])) ]); wbRecord(ECZN, 'Encounter Zone', [ wbEDID, wbStruct(DATA, '', [ wbFormIDCkNoReach('Owner', [NPC_, FACT, NULL]), wbFormIDCk('Location', [LCTN, NULL]), wbInteger('Rank', itS8), wbInteger('Min Level', itS8), wbInteger('Flags', itU8, wbFlags([ 'Never Resets', 'Match PC Below Minimum Level', 'Disable Combat Boundary', 'Workshop' ])), wbInteger('Max Level', itS8) ], cpNormal, True) ]); wbRecord(LCTN, 'Location', [ wbEDID, wbArray(ACPR, 'Actor Cell Persistent Reference', wbStruct('', [ wbFormIDCk('Actor', sigReferences, False, cpBenign), wbFormIDCk('Location', [WRLD, CELL], False, cpBenign), wbInteger('Grid Y', itS16, nil, cpBenign), wbInteger('Grid X', itS16, nil, cpBenign) ])), wbArray(LCPR, 'Location Cell Persistent Reference', wbStruct('', [ wbFormIDCk('Actor', sigReferences, False, cpBenign), wbFormIDCk('Location', [WRLD, CELL], False, cpBenign), wbInteger('Grid Y', itS16, nil, cpBenign), wbInteger('Grid X', itS16, nil, cpBenign) ])), wbArray(RCPR, 'Reference Cell Persistent Reference', wbFormIDCk('Ref', [ACHR, REFR], False, cpBenign)), wbArray(ACUN, 'Actor Cell Unique', wbStruct('', [ wbFormIDCk('Actor', [NPC_], False, cpBenign), wbFormIDCk('Ref', [ACHR], False, cpBenign), wbFormIDCk('Location', [LCTN, NULL], False, cpBenign) ])), wbArray(LCUN, 'Location Cell Unique', wbStruct('', [ wbFormIDCk('Actor', [NPC_], False, cpBenign), wbFormIDCk('Ref', [ACHR], False, cpBenign), wbFormIDCk('Location', [LCTN, NULL], False, cpBenign) ])), wbArray(RCUN, 'Reference Cell Unique', wbFormIDCk('Actor', [NPC_], False, cpBenign)), wbArray(ACSR, 'Actor Cell Static Reference', wbStruct('', [ wbFormIDCk('Loc Ref Type', [LCRT], False, cpBenign), wbFormIDCk('Marker', sigReferences, False, cpBenign), wbFormIDCk('Location', [WRLD, CELL], False, cpBenign), wbInteger('Grid Y', itS16, nil, cpBenign), wbInteger('Grid X', itS16, nil, cpBenign) ])), wbArray(LCSR, 'Location Cell Static Reference', wbStruct('', [ wbFormIDCk('Loc Ref Type', [LCRT], False, cpBenign), wbFormIDCk('Marker', sigReferences, False, cpBenign), wbFormIDCk('Location', [WRLD, CELL], False, cpBenign), wbInteger('Grid Y', itS16, nil, cpBenign), wbInteger('Grid X', itS16, nil, cpBenign) ])), wbArray(RCSR, 'Reference Cell Static Reference', wbFormIDCk('Ref', [ACHR, REFR], False, cpBenign)), wbRArray('Actor Cell Encounter Cell', wbStruct(ACEC, 'Unknown', [ wbFormIDCk('Location', [WRLD, CELL], False, cpBenign), wbArray('Coordinates', wbStruct('', [ wbInteger('Grid Y', itS16, nil, cpBenign), wbInteger('Grid X', itS16, nil, cpBenign) ])) ]) ), wbRArray('Location Cell Encounter Cell', wbStruct(LCEC, 'Unknown', [ wbFormIDCk('Location', [WRLD, CELL], False, cpBenign), wbArray('Coordinates', wbStruct('', [ wbInteger('Grid Y', itS16, nil, cpBenign), wbInteger('Grid X', itS16, nil, cpBenign) ])) ]) ), wbRArray('Reference Cell Encounter Cell', wbStruct(RCEC, 'Unknown', [ wbFormIDCk('Location', [WRLD, CELL], False, cpBenign), wbArray('Coordinates', wbStruct('', [ wbInteger('Grid Y', itS16, nil, cpBenign), wbInteger('Grid X', itS16, nil, cpBenign) ])) ]) ), wbArray(ACID, 'Actor Cell Marker Reference', wbFormIDCk('Ref', sigReferences, False, cpBenign)), wbArray(LCID, 'Location Cell Marker Reference', wbFormIDCk('Ref', sigReferences, False, cpBenign)), wbArray(ACEP, 'Actor Cell Enable Point', wbStruct('', [ wbFormIDCk('Actor', sigReferences, False, cpBenign), wbFormIDCk('Ref', sigReferences, False, cpBenign), wbInteger('Grid Y', itS16, nil, cpBenign), wbInteger('Grid X', itS16, nil, cpBenign) ])), wbArray(LCEP, 'Location Cell Enable Point', wbStruct('', [ wbFormIDCk('Actor', sigReferences, False, cpBenign), wbFormIDCk('Ref', sigReferences, False, cpBenign), wbInteger('Grid Y', itS16, nil, cpBenign), wbInteger('Grid X', itS16, nil, cpBenign) ])), wbFULL, wbKSIZ, wbKWDAs, wbFormIDCk(PNAM, 'Parent Location', [LCTN, NULL]), wbFormIDCk(NAM1, 'Music', [MUSC, NULL]), wbFormIDCk(FNAM, 'Unreported Crime Faction', [FACT]), wbFormIDCk(MNAM, 'World Location Marker Ref', [REFR, ACHR]), wbFloat(RNAM, 'World Location Radius'), //wbFormIDCk(NAM0, 'Horse Marker Ref', [REFR]), wbFloat(ANAM, 'Unknown'), wbCNAM ], False, nil, cpNormal, False, nil, wbKeywordsAfterSet); end; {this is required to prevent XE6 compiler error} type TVarRecs = array of TVarRec; function CombineVarRecs(const a, b : array of const) : TVarRecs; begin SetLength(Result, Length(a) + Length(b)); if Length(a) > 0 then Move(a[0], Result[0], SizeOf(TVarRec) * Length(a)); if Length(b) > 0 then Move(b[0], Result[Length(a)], SizeOf(TVarRec) * Length(b)); end; function MakeVarRecs(const a : array of const) : TVarRecs; begin SetLength(Result, Length(a)); if Length(a) > 0 then Move(a[0], Result[0], SizeOf(TVarRec) * Length(a)); end; procedure DefineFO4i; var a, b, c : TVarRecs; begin wbRecord(MESG, 'Message', [ wbEDID, wbDESCReq, wbFULL, wbFormIDCk(INAM, 'Icon (unused)', [NULL], False, cpIgnore, True), // leftover wbFormIDCk(QNAM, 'Owner Quest', [QUST]), wbInteger(DNAM, 'Flags', itU32, wbFlags([ 'Message Box', 'Delay Initial Display' ]), cpNormal, True, False, nil, wbMESGDNAMAfterSet), wbInteger(TNAM, 'Display Time', itU32, nil, cpNormal, False, False, wbMESGTNAMDontShow), wbString(SNAM, 'SWF'), wbLString(NNAM, 'Short Title', 0, cpTranslate), wbRStructs('Menu Buttons', 'Menu Button', [ wbLString(ITXT, 'Button Text', 0, cpTranslate), wbCTDAs ], []) ], False, nil, cpNormal, False, wbMESGAfterLoad); a := MakeVarRecs([ 0, 'None', Sig2Int('AAAC'), 'Action Activate', Sig2Int('AAB1'), 'Action Bleedout Start', Sig2Int('AAB2'), 'Action Bleedout Stop', Sig2Int('AABA'), 'Action Block Anticipate', Sig2Int('AABH'), 'Action Block Hit', Sig2Int('AABI'), 'Action Bumped Into', Sig2Int('AADA'), 'Action Dual Attack', Sig2Int('AADE'), 'Action Death', Sig2Int('AADL'), 'Action Dual Release', Sig2Int('AADR'), 'Action Draw', Sig2Int('AADW'), 'Action Death Wait', Sig2Int('AAF1'), 'Action Fly Start', Sig2Int('AAF2'), 'Action Fly Stop', Sig2Int('AAFA'), 'Action Fall', Sig2Int('AAFQ'), 'Action Force Equip', Sig2Int('AAGU'), 'Action Get Up', Sig2Int('AAH1'), 'Action Hover Start', Sig2Int('AAH2'), 'Action Hover Stop', Sig2Int('AAID'), 'Action Idle', Sig2Int('AAIS'), 'Action Idle Stop', Sig2Int('AAJP'), 'Action Jump', Sig2Int('AALA'), 'Action Left Attack', Sig2Int('AALD'), 'Action Left Ready', Sig2Int('AALI'), 'Action Left Interrupt', Sig2Int('AALK'), 'Action Look', Sig2Int('AALM'), 'Action Large Movement Delta', Sig2Int('AALN'), 'Action Land', Sig2Int('AALR'), 'Action Left Release', Sig2Int('AALS'), 'Action Left Sync Attack', Sig2Int('AAMT'), 'Action Mantle', Sig2Int('AAOE'), 'Action AoE Attack', Sig2Int('AAPA'), 'Action Right Power Attack', Sig2Int('AAPE'), 'Action Path End', Sig2Int('AAPS'), 'Action Path Start', Sig2Int('AAR2'), 'Action Large Recoil', Sig2Int('AARA'), 'Action Right Attack', Sig2Int('AARC'), 'Action Recoil', Sig2Int('AARD'), 'Action Right Ready', Sig2Int('AARI'), 'Action Right Interrupt', Sig2Int('AARR'), 'Action Right Release', Sig2Int('AARS'), 'Action Right Sync Attack', Sig2Int('AAS1'), 'Action Stagger Start', Sig2Int('AASC'), 'Action Shield Change', Sig2Int('AASH'), 'Action Sheath', Sig2Int('AASN'), 'Action Sneak', Sig2Int('AASP'), 'Action Sprint Stop', Sig2Int('AASS'), 'Action Summoned Start', Sig2Int('AAST'), 'Action Sprint Start', Sig2Int('AASW'), 'Action Swim State Change', Sig2Int('AAVC'), 'Action Voice', Sig2Int('AAVD'), 'Action Voice Ready', Sig2Int('AAVI'), 'Action Voice Interrupt', Sig2Int('AAVR'), 'Action Voice Release', Sig2Int('AAWH'), 'Action Ward Hit', Sig2Int('ABLA'), 'Action Begin Looping Activate', Sig2Int('ABOL'), 'Action Bolt Charge', Sig2Int('ABSE'), 'Art Object Absorb Effect', Sig2Int('ACHI'), 'Action Hide', Sig2Int('ACSS'), 'Action Cover Sprint Start', Sig2Int('ACTN'), 'Action Tunnel', Sig2Int('ACWR'), 'Action Cower', Sig2Int('ADGE'), 'Action Dodge', Sig2Int('ADPA'), 'Action Dual Power Attack', Sig2Int('AECL'), 'Action Enter Cover', Sig2Int('AELA'), 'Action End Looping Activate', Sig2Int('AENC'), 'Action Enter Combat', Sig2Int('AENI'), 'Action Dialogue Enter', Sig2Int('AEVD'), 'Action Evade', Sig2Int('AEXC'), 'Action Exit Cover', Sig2Int('AEXI'), 'Action Dialogue Exit', Sig2Int('AEXT'), 'Action Exit Combat', Sig2Int('AFCH'), 'Action Fire Charge', Sig2Int('AFCO'), 'Action Fire Charge Hold', Sig2Int('AFEM'), 'Action Fire Empty', Sig2Int('AFIA'), 'Action Fire Auto', Sig2Int('AFIS'), 'Action Fire Single', Sig2Int('AFLT'), 'Action Flip-Throw', Sig2Int('AFNP'), 'Keyword Activator Furniture No Player', Sig2Int('AGAL'), 'Action Gun Alert', Sig2Int('AGCS'), 'Action Gun Charge Start', Sig2Int('AGDN'), 'Action Gun Down', Sig2Int('AGRX'), 'Action Gun Relaxed', Sig2Int('AGRY'), 'Action Gun Ready', Sig2Int('AIDW'), 'Action Idle Warn', Sig2Int('AIEN'), 'Action Interaction Enter', Sig2Int('AIEQ'), 'Action Interaction Exit Quick', Sig2Int('AIEX'), 'Action Interaction Exit', Sig2Int('AILN'), 'Action Dialogue Listen Negative', Sig2Int('AILp'), 'Action Dialogue Listen Positive', Sig2Int('AILQ'), 'Action Dialogue Listen Question', Sig2Int('AINT'), 'Action Intimidate', Sig2Int('AIVC'), 'Verlet Cape', Sig2Int('AIXA'), 'Action Interaction Exit Alternate', Sig2Int('AKDN'), 'Action Knockdown', Sig2Int('ALIC'), 'Action Limb Critical', Sig2Int('ALIK'), 'Alcohol Item keyword', Sig2Int('ALPA'), 'Action Left Power Attack', Sig2Int('ALTI'), 'Action Dialogue Listen', Sig2Int('AMBK'), 'Action Move Backward', Sig2Int('AMEL'), 'Action Melee', Sig2Int('AMFD'), 'Action Move Forward', Sig2Int('AMLT'), 'Action Move Left', Sig2Int('AMRT'), 'Action Move Right', Sig2Int('AMSP'), 'Action Move Stop', Sig2Int('AMST'), 'Action Move Start', Sig2Int('ANML'), 'Keyword Animal', Sig2Int('ANSC'), 'Action NonSupport Contact', Sig2Int('AODA'), 'Keyword Armor Material Daedric', Sig2Int('AODB'), 'Keyword Armor Material Dragonbone', Sig2Int('AODP'), 'Keyword Armor Material Dragonplate', Sig2Int('AODS'), 'Keyword Armor Material Dragonscale', Sig2Int('AODW'), 'Keyword Armor Material Dwarven', Sig2Int('AOEB'), 'Keyword Armor Material Ebony', Sig2Int('AOEL'), 'Keyword Armor Material Elven', Sig2Int('AOES'), 'Keyword Armor Material ElvenSplinted', Sig2Int('AOFE'), 'Keyword Armor Material Iron', Sig2Int('AOFL'), 'Keyword Armor Material FullLeather', Sig2Int('AOGL'), 'Keyword Armor Material Glass', Sig2Int('AOHI'), 'Keyword Armor Material Hide', Sig2Int('AOIB'), 'Keyword Armor Material IronBanded', Sig2Int('AOIH'), 'Keyword Armor Material ImperialHeavy', Sig2Int('AOIM'), 'Keyword Armor Material Imperial', Sig2Int('AOIR'), 'Keyword Armor Material ImperialReinforced', Sig2Int('AOOR'), 'Keyword Armor Material Orcish', Sig2Int('AOSC'), 'Keyword Armor Material Scaled', Sig2Int('AOSD'), 'Keyword Armor Material Studded', Sig2Int('AOSK'), 'Keyword Armor Material Stormcloak', Sig2Int('AOSP'), 'Keyword Armor Material SteelPlate', Sig2Int('AOST'), 'Keyword Armor Material Steel', Sig2Int('APIC'), 'Action Pipboy Close', Sig2Int('APID'), 'Action Pipboy Data', Sig2Int('APII'), 'Action Pipboy Inventory', Sig2Int('APIM'), 'Action Pipboy Map', Sig2Int('APIN'), 'Action Pipboy Inspect', Sig2Int('APIP'), 'Action Pipboy', Sig2Int('APIS'), 'Action Pipboy Stats', Sig2Int('APIT'), 'Action Pipboy Tab', Sig2Int('APIZ'), 'Action Pipboy Zoom', Sig2Int('APLH'), 'Action Pipboy Load Holotape', Sig2Int('APLN'), 'Action Dialogue Listen Neutral', Sig2Int('APNC'), 'Action Panic', Sig2Int('APPS'), 'Action Pipboy Select', Sig2Int('APR0'), 'Action Pipboy Radio Off', Sig2Int('APR1'), 'Action Pipboy Radio On', Sig2Int('APSH'), 'Allow Player Shout', Sig2Int('APTP'), 'Action Pipboy Tab Previous', Sig2Int('AREL'), 'Action Reload', Sig2Int('ARGI'), 'Action Ragdoll Instant', Sig2Int('ARTL'), 'Armor Material List', Sig2Int('ASFL'), 'Action Shuffle', Sig2Int('ASID'), 'Action Idle Stop Instant', Sig2Int('ASIR'), 'Action Sighted Release', Sig2Int('ASIT'), 'Action Sighted', Sig2Int('ATHR'), 'Action Throw', Sig2Int('ATKI'), 'Action Dialogue Talking', Sig2Int('ATLE'), 'Action Turn Left', Sig2Int('ATRI'), 'Action Turn Right', Sig2Int('ATSP'), 'Action Turn Stop', Sig2Int('AVVP'), 'Vampire Available Perks', Sig2Int('AVWP'), 'Unused', Sig2Int('AWWS'), 'Action Waterwalk Start', Sig2Int('AWWW'), 'Bunny Faction', Sig2Int('BAPO'), 'Base Potion', Sig2Int('BAPS'), 'Base Poison', Sig2Int('BEEP'), 'Keyword Robot', Sig2Int('BENA'), 'Base Armor Enchantment', Sig2Int('BENW'), 'Base Weapon Enchantment', Sig2Int('BTMS'), 'Battle Music', Sig2Int('CACA'), 'Commanded Actor Ability', Sig2Int('CHIK'), 'Chem Item keyword', Sig2Int('CLIK'), 'Clothes Item keyword', Sig2Int('CMPX'), 'Complex Scene Object', Sig2Int('CNMK'), 'Keyword nullptr Mod', Sig2Int('COEX'), 'Keyword Conditional Explosion', Sig2Int('COOK'), 'Keyword Cooking Pot', Sig2Int('CSTY'), 'Combat Style', Sig2Int('CWNE'), 'Keyword Civil War Neutral', Sig2Int('CWOK'), 'Keyword Civil War Owner', Sig2Int('DAED'), 'Keyword Daedra', Sig2Int('DBHF'), 'Dark Brotherhood Faction', Sig2Int('DCMS'), 'Dungeon Cleared Music', Sig2Int('DCZM'), 'Dragon Crash Zone Marker', Sig2Int('DDSC'), 'Dialogue Voice Category', Sig2Int('DEIS'), 'Drug Wears Off Image Space', Sig2Int('DFTS'), 'Footstep Set', Sig2Int('DGFL'), 'DialogueFollower Quest', Sig2Int('DIEN'), 'Keyword Disallow Enchanting', Sig2Int('DLMT'), 'Landscape Material', Sig2Int('DLZM'), 'Dragon Land Zone Marker', Sig2Int('DMFL'), 'Default Movement Type: Fly', Sig2Int('DMSN'), 'Default Movement Type: Sneak', Sig2Int('DMSW'), 'Default Movement Type: Swim', Sig2Int('DMWL'), 'Default Movement Type: Default', Sig2Int('DOP2'), 'Dialogue Output Model 3D', Sig2Int('DOP3'), 'Dialogue Output Model 2D', Sig2Int('DRAK'), 'Keyword Dragon', Sig2Int('DTMS'), 'Death Music', Sig2Int('EACA'), 'Every Actor Ability', Sig2Int('EPDF'), 'Eat Package Default Food', Sig2Int('FFFP'), 'Keyword Furniture Forces 1st Person', Sig2Int('FFTP'), 'Keyword Furniture Forces 3rd Person', Sig2Int('FOIK'), 'Food Item Keyword', Sig2Int('FORG'), 'Keyword Forge', Sig2Int('FTEL'), 'Male Face Texture Set: Eyes', Sig2Int('FTGF'), 'Fighters'' Guild Faction', Sig2Int('FTHD'), 'Male Face Texture Set: Head', Sig2Int('FTHF'), 'Female Face Texture Set: Head', Sig2Int('FTMF'), 'Female Face Texture Set: Mouth', Sig2Int('FTML'), 'Favor travel marker location', Sig2Int('FTMO'), 'Male Face Texture Set: Mouth', Sig2Int('FTNP'), 'Furniture Test NPC', Sig2Int('FTRF'), 'Female Face Texture Set: Eyes' ]); b := MakeVarRecs([ Sig2Int('GCK1'), 'Keyword Generic Craftable Keyword 01', Sig2Int('GCK2'), 'Keyword Generic Craftable Keyword 02', Sig2Int('GCK3'), 'Keyword Generic Craftable Keyword 03', Sig2Int('GCK4'), 'Keyword Generic Craftable Keyword 04', Sig2Int('GCK5'), 'Keyword Generic Craftable Keyword 05', Sig2Int('GCK6'), 'Keyword Generic Craftable Keyword 06', Sig2Int('GCK7'), 'Keyword Generic Craftable Keyword 07', Sig2Int('GCK8'), 'Keyword Generic Craftable Keyword 08', Sig2Int('GCK9'), 'Keyword Generic Craftable Keyword 09', Sig2Int('GCKX'), 'Keyword Generic Craftable Keyword 10', Sig2Int('GFAC'), 'Guard Faction', Sig2Int('GLIK'), 'Gloves Item Keyword', Sig2Int('GOLD'), 'Gold', Sig2Int('GRIK'), 'Grenade Item Keyword', Sig2Int('HBAL'), 'Help Basic Alchemy', Sig2Int('HBBR'), 'Help Barter', Sig2Int('HBCO'), 'Help Basic Cooking', Sig2Int('HBEC'), 'Help Basic Enchanting', Sig2Int('HBFG'), 'Help Basic Forging', Sig2Int('HBFS'), 'Help Favorites', Sig2Int('HBFT'), 'Help Teamate Favor', Sig2Int('HBHJ'), 'Help Jail', Sig2Int('HBJL'), 'Help Journal', Sig2Int('HBLH'), 'Help Low Health', Sig2Int('HBLK'), 'Help Basic Lockpicking PC', Sig2Int('HBLM'), 'Help Low Magicka', Sig2Int('HBLS'), 'Help Low Stamina', Sig2Int('HBLU'), 'Help Leveling up', Sig2Int('HBLX'), 'Help Basic Lockpicking Console', Sig2Int('HBML'), 'Help Basic Smelting', Sig2Int('HBMM'), 'Help Map Menu', Sig2Int('HBOC'), 'Help Basic Object Creation', Sig2Int('HBSA'), 'Help Basic Smithing Armor', Sig2Int('HBSK'), 'Help Skills Menu', Sig2Int('HBSM'), 'Help Basic Smithing Weapon', Sig2Int('HBTA'), 'Help Basic Tanning', Sig2Int('HBWC'), 'Help Weapon Charge', Sig2Int('HCLL'), 'FormList Hair Color List', Sig2Int('HEIK'), 'Helmet Item Keyword', Sig2Int('HFSD'), 'Heartbeat Sound Fast', Sig2Int('HMPC'), 'Help Manual PC', Sig2Int('HMXB'), 'Help Manual XBox', Sig2Int('HRSK'), 'Keyword Horse', Sig2Int('HSSD'), 'Heartbeat Sound Slow', Sig2Int('HVFS'), 'Harvest Failed Sound', Sig2Int('HVSS'), 'Harvest Sound', Sig2Int('HWIK'), 'Heavy Weapon Item keyword', Sig2Int('IMDI'), 'Dialogue Imagespace', Sig2Int('IMID'), 'ImageSpaceModifier for inventory menu.', Sig2Int('IMLH'), 'Imagespace: Low Health', Sig2Int('IMPP'), 'ImageSpaceModifier for Pipboy menu in Power armor.', Sig2Int('IOPM'), 'Interface Output Model', Sig2Int('JRLF'), 'Jarl Faction', Sig2Int('JWLR'), 'Keyword Jewelry', Sig2Int('KHFL'), 'Kinect Help FormList', Sig2Int('KTRW'), 'Teammate Ready Weapon', Sig2Int('KWBR'), 'Color Form', Sig2Int('KWCU'), 'Keyword Cuirass', Sig2Int('KWDM'), 'Keyword DummyObject', Sig2Int('KWDO'), 'Keyword ClearableLocation', Sig2Int('KWGE'), 'Keyword UseGeometryEmitter', Sig2Int('KWMS'), 'Keyword MustStop', Sig2Int('LGH1'), 'Default Light 1', Sig2Int('LGH2'), 'Default Light 2', Sig2Int('LGH3'), 'Default Light 3', Sig2Int('LGH4'), 'Default Light 4', Sig2Int('LGHP'), 'Pipboy Light', Sig2Int('LKHO'), 'Keyword Hold Location', Sig2Int('LKPK'), 'Lockpick', Sig2Int('LMHP'), 'Local Map Hide Plane', Sig2Int('LRRD'), 'LocRefType Resource Destructible', Sig2Int('LRSO'), 'LocRefType Civil War Soldier', Sig2Int('LSIS'), 'Imagespace: Load screen', Sig2Int('MBIK'), 'Med Bag Item Keyword', Sig2Int('MDSC'), 'Music Sound Category', Sig2Int('MFSN'), 'Magic Fail Sound', Sig2Int('MGGF'), 'Mages'' Guild Faction', Sig2Int('MIIK'), 'Mine Item Keyword', Sig2Int('MMCL'), 'Main Menu Cell', Sig2Int('MMSD'), 'Map Menu Looping Sound', Sig2Int('MNTK'), 'Keyword Mount', Sig2Int('MTSC'), 'Master Sound Category', Sig2Int('MVBL'), 'Keyword Movable', Sig2Int('NASD'), 'No-Activation Sound', Sig2Int('NDSC'), 'Non-Dialogue Voice Category', Sig2Int('NMRD'), 'Road Marker', Sig2Int('NPCK'), 'Keyword NPC', Sig2Int('NRNT'), 'Keyword Nirnroot', Sig2Int('P3OM'), 'Player''s Output Model 3rd Person', Sig2Int('PDLC'), 'Pause During Loading Menu Category', Sig2Int('PDMC'), 'Pause During Menu Category Fade', Sig2Int('PDSA'), 'Putdown Sound Armor', Sig2Int('PDSB'), 'Putdown Sound Book', Sig2Int('PDSG'), 'Putdown Sound Generic', Sig2Int('PDSI'), 'Putdown Sound Ingredient', Sig2Int('PDSW'), 'Putdown Sound Weapon', Sig2Int('PFAC'), 'Player Faction', Sig2Int('PIMC'), 'Pause During Menu Category Immediate', Sig2Int('PIVV'), 'Player Is Vampire Variable', Sig2Int('PIWV'), 'UNUSED01', Sig2Int('PLOC'), 'PersistAll Location', Sig2Int('PLST'), 'Default Pack List', Sig2Int('POEQ'), 'Potion Equip', Sig2Int('POPM'), 'Player''s Output Model 1st Person', Sig2Int('PTEM'), 'Package Template', Sig2Int('PTFR'), 'PotentialFollower Faction', Sig2Int('PTNP'), 'Pathing Test NPC', Sig2Int('PUSA'), 'Pickup Sound Armor', Sig2Int('PUSB'), 'Pickup Sound Book', Sig2Int('PUSG'), 'Pickup Sound Generic', Sig2Int('PUSI'), 'Pickup Sound Ingredient', Sig2Int('PUSW'), 'Pickup Sound Weapon', Sig2Int('PVFA'), 'Player Voice Female', Sig2Int('PVFC'), 'Player Voice Female Child', Sig2Int('PVMA'), 'Player Voice Male', Sig2Int('PVMC'), 'Player Voice Male Child', Sig2Int('PWFD'), 'Wait-For-Dialogue Package', Sig2Int('QMEA'), 'Quest Marker Enemy Above', Sig2Int('QMEB'), 'Quest Marker Enemy Below', Sig2Int('QMEN'), 'Quest Marker Enemy', Sig2Int('QMFO'), 'Quest Marker Follower', Sig2Int('QMLO'), 'Quest Marker Location', Sig2Int('RIVR'), 'Vampire Race', Sig2Int('RIVS'), 'Vampire Spells', Sig2Int('RIWR'), 'UNUSED02', Sig2Int('RKIK'), 'Repair Kit Item Keyword', Sig2Int('RUSG'), 'Keyword Reusable SoulGem', Sig2Int('RVBT'), 'Reverb Type', Sig2Int('SALT'), 'Sitting Angle Limit', Sig2Int('SAT1'), 'Keyword Scale Actor To 1.0', Sig2Int('SCSD'), 'Soul Captured Sound', Sig2Int('SFDC'), 'SFX To Fade In Dialogue Category', Sig2Int('SFSN'), 'Shout Fail Sound', Sig2Int('SKLK'), 'Skeleton Key', Sig2Int('SLDM'), 'Snow LOD Material', Sig2Int('SLHD'), 'Snow LOD Material HD', Sig2Int('SMLT'), 'Keyword Smelter', Sig2Int('SMSC'), 'Stats Mute Category', Sig2Int('SPFK'), 'Keyword Special Furniture', Sig2Int('SSSC'), 'Stats Music', Sig2Int('TANN'), 'Keyword Tanning Rack', Sig2Int('TKAM'), 'Keyword Type Ammo', Sig2Int('TKAR'), 'Keyword Type Armor', Sig2Int('TKBK'), 'Keyword Type Book', Sig2Int('TKGS'), 'Telekinesis Grab Sound', Sig2Int('TKIG'), 'Keyword Type Ingredient', Sig2Int('TKKY'), 'Keyword Type Key', Sig2Int('TKMS'), 'Keyword Type Misc', Sig2Int('TKPT'), 'Keyword Type Potion', Sig2Int('TKSG'), 'Keyword Type SoulGem', Sig2Int('TKTS'), 'Telekinesis Throw Sound', Sig2Int('TKWP'), 'Keyword Type Weapon', Sig2Int('TVGF'), 'Thieves'' Guild Faction', Sig2Int('UNDK'), 'Keyword Undead', Sig2Int('URVT'), 'Underwater Reverb Type', Sig2Int('UWLS'), 'Underwater Loop Sound', Sig2Int('VAMP'), 'Keyword Vampire', Sig2Int('VLOC'), 'Virtual Location', Sig2Int('VOEQ'), 'Voice Equip', Sig2Int('WASN'), 'Ward Absorb Sound', Sig2Int('WBSN'), 'Ward Break Sound', Sig2Int('WDSN'), 'Ward Deflect Sound', Sig2Int('WEML'), 'Weapon Material List', Sig2Int('WMDA'), 'Keyword Weapon Material Daedric', Sig2Int('WMDH'), 'Keyword Weapon Material DraugrHoned', Sig2Int('WMDR'), 'Keyword Weapon Material Draugr', Sig2Int('WMDW'), 'Keyword Weapon Material Dwarven', Sig2Int('WMEB'), 'Keyword Weapon Material Ebony', Sig2Int('WMEL'), 'Keyword Weapon Material Elven', Sig2Int('WMFA'), 'Keyword Weapon Material Falmer', Sig2Int('WMFH'), 'Keyword Weapon Material FalmerHoned', Sig2Int('WMGL'), 'Keyword Weapon Material Glass', Sig2Int('WMIK'), 'Workshop Misc Item Keyword', Sig2Int('WMIM'), 'Keyword Weapon Material Imperial', Sig2Int('WMIR'), 'Keyword Weapon Material Iron', Sig2Int('WMOR'), 'Keyword Weapon Material Orcish', Sig2Int('WMST'), 'Keyword Weapon Material Steel', Sig2Int('WMWE'), 'World Map Weather', Sig2Int('WMWO'), 'Keyword Weapon Material Wood', Sig2Int('WPOK'), 'Workshop Player Ownership', Sig2Int('WTBA'), 'Keyword WeaponTypeBoundArrow', Sig2Int('WWSP'), 'UNUSED03' ]); c := CombineVarRecs(a, b); wbRecord(DOBJ, 'Default Object Manager', [ wbEDID, wbArrayS(DNAM, 'Objects', wbStructSK([0], 'Object', [ wbInteger('Use', itU32, wbEnum([], c), cpNormalIgnoreEmpty), wbFormID('Object ID', cpNormalIgnoreEmpty) ]), 0, cpNormalIgnoreEmpty, True, wbDOBJObjectsAfterLoad ) ]); wbRecord(LGTM, 'Lighting Template', [ wbEDID, wbStruct(DATA, 'Lighting', [ wbByteColors('Ambient Color'), wbByteColors('Directional Color'), wbByteColors('Fog Color Near'), wbFloat('Fog Near'), wbFloat('Fog Far'), wbInteger('Directional Rotation XY', itS32), wbInteger('Directional Rotation Z', itS32), wbFloat('Directional Fade'), wbFloat('Fog Clip Distance'), wbFloat('Fog Power'), wbByteArray('Unused', 32, cpIgnore), wbByteColors('Fog Color Far'), wbFloat('Fog Max'), wbFloat('Light Fade Begin'), wbFloat('Light Fade End'), wbByteArray('Unused', 4, cpIgnore), wbFloat('Near Height Mid'), wbFloat('Near Height Range'), wbByteColors('Fog Color High Near'), wbByteColors('Fog Color High Far'), wbFloat('High Density Scale'), wbFloat('Fog Near Scale'), wbFloat('Fog Far Scale'), wbFloat('Fog High Near Scale'), wbFloat('Fog High Far Scale'), wbFloat('Far Height Mid'), wbFloat('Far Height Range') ], cpNormal, True, nil, 15), wbAmbientColors(DALC), wbFormIDCk(WGDR, 'God Rays', [GDRY]) ]); wbRecord(MUSC, 'Music Type', [ wbEDID, wbInteger(FNAM, 'Flags', itU32, wbFlags([ {0x01} 'Plays One Selection', {0x02} 'Abrupt Transition', {0x04} 'Cycle Tracks', {0x08} 'Maintain Track Order', {0x10} 'Unknown 5', {0x20} 'Ducks Current Track', {0x40} 'Doesn''t Queue' ]), cpNormal, True), wbStruct(PNAM, 'Data', [ wbInteger('Priority', itU16), wbInteger('Ducking (dB)', itU16, wbDiv(100)) ]), wbFloat(WNAM, 'Fade Duration'), wbArray(TNAM, 'Music Tracks', wbFormIDCk('Track', [MUST, NULL])) ]); wbRecord(FSTP, 'Footstep', [ wbEDID, wbFormIDCk(DATA, 'Impact Data Set', [IPDS, NULL], False, cpNormal, True), wbString(ANAM, 'Tag', 0, cpNormal, True) ]); wbRecord(FSTS, 'Footstep Set', [ wbEDID, wbStruct(XCNT, 'Count', [ wbInteger('Walking', itU32), wbInteger('Running', itU32), wbInteger('Sprinting', itU32), wbInteger('Sneaking', itU32), wbInteger('Swimming', itU32) ], cpNormal, True), wbArray(DATA, 'Footstep Sets', wbFormIDCk('Footstep', [FSTP]), 0, nil, nil, cpNormal, True) ]); wbSMNodeFlags := wbFlags([ 'Random', 'Warn if no child quest started' ]); wbRecord(SMBN, 'Story Manager Branch Node', [ wbEDID, wbFormIDCk(PNAM, 'Parent ', [SMQN, SMBN, SMEN, NULL]), wbFormIDCk(SNAM, 'Child ', [SMQN, SMBN, SMEN, NULL], False, cpBenign), wbCITC, wbCTDAsCount, wbInteger(DNAM, 'Flags', itU32, wbSMNodeFlags), wbUnknown(XNAM) ], False, nil, cpNormal, False, nil, wbConditionsAfterSet); wbRecord(SMQN, 'Story Manager Quest Node', [ wbEDID, wbFormIDCk(PNAM, 'Parent ', [SMQN, SMBN, SMEN, NULL]), wbFormIDCk(SNAM, 'Child ', [SMQN, SMBN, SMEN, NULL], False, cpBenign), wbCITC, wbCTDAsCount, wbStruct(DNAM, 'Flags', [ wbInteger('Node Flags', itU16, wbSMNodeFlags), wbInteger('Quest Flags', itU16, wbFlags([ 'Do all before repeating', 'Shares event', 'Num quests to run' ])) ]), wbInteger(XNAM, 'Max concurrent quests', itU32), wbInteger(MNAM, 'Num quests to run', itU32), wbFloat(HNAM, 'Hours until reset'), wbInteger(QNAM, 'Quest Count', itU32, nil, cpBenign), wbRArray('Quests', wbRStructSK([0], 'Quest', [ wbFormIDCk(NNAM, 'Quest', [QUST]), wbUnknown(FNAM), wbFloat(RNAM, 'Hours until reset', cpNormal, False, 1/24) ], []), cpNormal, False, nil, wbSMQNQuestsAfterSet) ], False, nil, cpNormal, False, nil, wbConditionsAfterSet); wbRecord(SMEN, 'Story Manager Event Node', [ wbEDID, wbFormIDCk(PNAM, 'Parent ', [SMQN, SMBN, SMEN, NULL]), wbFormIDCk(SNAM, 'Child ', [SMQN, SMBN, SMEN, NULL]), wbCITC, wbCTDAsCount, wbInteger(DNAM, 'Flags', itU32, wbSMNodeFlags), wbUnknown(XNAM), wbString(ENAM, 'Type', 4) ], False, nil, cpNormal, False, nil, wbConditionsAfterSet); end; procedure DefineFO4j; begin wbRecord(DLBR, 'Dialog Branch', [ wbEDID, wbFormIDCk(QNAM, 'Quest', [QUST], False, cpNormal, True), wbInteger(TNAM, 'Unknown', itU32), wbInteger(DNAM, 'Flags', itU32, wbFlags([ {0x01} 'Top-Level', {0x02} 'Blocking', {0x04} 'Exclusive' ])), wbFormIDCk(SNAM, 'Starting Topic', [DIAL], False, cpNormal, True) ]); wbRecord(MUST, 'Music Track', [ wbEDID, wbInteger(CNAM, 'Track Type', itU32, wbEnum([], [ Int64($23F678C3), 'Palette', Int64($6ED7E048), 'Single Track', Int64($A1A9C4D5), 'Silent Track' ]), cpNormal, True), wbFloat(FLTV, 'Duration'), wbFloat(DNAM, 'Fade-Out'), wbString(ANAM, 'Track Filename'), wbString(BNAM, 'Finale Filename'), wbStruct(LNAM, 'Loop Data', [ wbFloat('Loop Begins'), wbFloat('Loop Ends'), wbInteger('Loop Count', itU32) ]), wbArray(FNAM, 'Cue Points', wbFloat('Point')), wbCITC, wbCTDAsCount, wbArray(SNAM, 'Tracks', wbFormIDCk('Track', [MUST, NULL])) ], False, nil, cpNormal, False, nil, wbConditionsAfterSet); wbRecord(DLVW, 'Dialog View', [ wbEDID, wbFormIDCk(QNAM, 'Quest', [QUST], False, cpNormal, True), wbRArray('Branches', wbFormIDCk(BNAM, 'Branch', [DLBR])), wbRArray('Unknown TNAM', wbRStruct('Unknown', [ wbUnknown(TNAM) ], [])), wbUnknown(ENAM), wbUnknown(DNAM) ]); {wbRecord(WOOP, 'Word of Power', [ wbEDID ]);} {wbRecord(SHOU, 'Shout', [ wbEDID ]);} wbRecord(EQUP, 'Equip Type', [ wbEDID, wbArray(PNAM, 'Slot Parents', wbFormIDCk('Parent', [EQUP])), wbInteger(DATA, 'Flags', itU32, wbFlags([ 'Use All Parents', 'Parents Optional', 'Item Slot' ])), wbFormIDCk(ANAM, 'Condition Actor Value', [AVIF, NULL, FFFF]) ]); wbRecord(RELA, 'Relationship', [ wbEDID, wbStruct(DATA, 'Data', [ wbFormIDCk('Parent', [NPC_, NULL]), wbFormIDCk('Child', [NPC_, NULL]), wbInteger('Rank', itU8, wbEnum([ 'Lover', 'Ally', 'Confidant', 'Friend', 'Acquaitance', 'Rival', 'Foe', 'Enemy', 'Archnemesis' ])), wbByteArray('Unknown', 2), wbInteger('Flags', itU8, wbFlags([ {0x01} 'Unknown 1', {0x02} 'Unknown 2', {0x04} 'Unknown 3', {0x08} 'Unknown 4', {0x10} 'Unknown 5', {0x20} 'Unknown 6', {0x40} 'Unknown 7', {0x80} 'Secret' ])), wbFormIDCk('Association Type', [ASTP, NULL]) ]) ]); wbRecord(SCEN, 'Scene', [ wbEDID, wbVMADFragmentedSCEN, wbInteger(FNAM, 'Flags', itU32, wbFlags([ {0x00000001} 'Begin on Quest Start', {0x00000002} 'Stop on Quest End', {0x00000004} 'Unknown 2', {0x00000008} 'Repeat Conditions While True', {0x00000010} 'Interruptible', {0x00000020} 'Unknown 5', {0x00000040} 'Prevent Player Exit Dialogue', {0x00000080} 'Unknown 7', {0x00000100} 'Unknown 8', {0x00000200} 'Unknown 9', {0x00000400} 'Unknown 10', {0x00000800} 'Disable Dialogue Camera', {0x00001000} 'No Follower Idle Chatter' ])), wbRArray('Phases', wbRStruct('Phase', [ wbEmpty(HNAM, 'Marker Phase Start'), wbString(NAM0, 'Name'), wbRStruct('Start Conditions', [wbCTDAs], []), wbEmpty(NEXT, 'Marker Start Conditions'), wbRStruct('Completion Conditions', [wbCTDAs], []), wbEmpty(NEXT, 'Marker Completion Conditions'), wbInteger(WNAM, 'Editor Width', itU32), wbInteger(FNAM, 'Flags', itU16, wbFlags([ {0x0001} 'Start - WalkAway Phase', {0x0002} 'Don''t Run End Scripts on Scene Jump', {0x0004} 'Start - Inherit In Templated Scenes' ])), wbStruct(SCQS, 'Set Parent Quest Stage', [ wbInteger('On Start', itS16), wbInteger('On Completion', itS16) ]), wbEmpty(HNAM, 'Marker Phase End') ], []) ), wbRArray('Actors', wbRStruct('Actor', [ wbInteger(ALID, 'Alias ID', itS32), wbInteger(LNAM, 'Flags', itU32, wbFlags([ 'No Player Activation', 'Optional', 'Run Only Scene Packages', 'No Command State' ])), wbInteger(DNAM, 'Behaviour Flags', itU32, wbFlags([ 'Death Pause', 'Death End', 'Combat Pause', 'Combat End', 'Dialogue Pause', 'Dialogue End', 'OBS_COM Pause', 'OBS_COM End' ])) ], [])), wbRArray('Actions', wbRStruct('Action', [ wbInteger(ANAM, 'Type', itU16, wbEnum([ {0} 'Dialogue', {1} 'Package', {2} 'Timer', {3} 'Player Dialogue', {4} 'Start Scene', {5} 'NPC Response Dialogue', {6} 'Radio' ])), wbString(NAM0, 'Name'), wbInteger(ALID, 'Alias ID', itS32), wbInteger(INAM, 'Index', itU32), wbInteger(FNAM, 'Flags', itU32, wbFlags([ {0x00000001} 'Unknown 0', {0x00000002} 'Unknown 1', {0x00000004} 'Unknown 2', {0x00000008} 'Unknown 3', {0x00000010} 'Unknown 4', {0x00000020} 'Unknown 5', {0x00000040} 'Unknown 6', {0x00000080} 'Player Positive Use Dialogue Subtype / Hold Into Next Scene', {0x00000100} 'Player Negative Use Dialogue Subtype', {0x00000200} 'Player Neutral Use Dialogue Subtype', {0x00000400} 'Use Dialogue Subtype', {0x00000800} 'Player Question Use Dialogue Subtype', {0x00001000} 'Keep/Clear Target on Action End', {0x00002000} 'Unknown 13', {0x00004000} 'Unknown 14', {0x00008000} 'Face Target', {0x00010000} 'Looping', {0x00020000} 'Headtrack Player', {0x00040000} 'Unknown 18', {0x00080000} 'Ignore For Completion', {0x00100000} 'Unknown 20', {0x00200000} 'Camera Speaker Target', {0x00400000} 'Complete Face Target', {0x00800000} 'Unknown 23', {0x01000000} 'Unknown 24', {0x02000000} 'Unknown 25', {0x04000000} 'Unknown 26', {0x08000000} 'NPC Positive Use Dialogue Subtype', {0x10000000} 'NPC Negative Use Dialogue Subtype', {0x20000000} 'NPC Neutral Use Dialogue Subtype', {0x40000000} 'NPC Question Use Dialogue Subtype' ])), wbInteger(SNAM, 'Start Phase', itU32), wbInteger(ENAM, 'End Phase', itU32), wbFloat(SNAM, 'Timer - Max Seconds'), wbInteger(SCQS, 'Set Parent Quest Stage', itS16), wbFloat(TNAM, 'Timer - Min Seconds'), wbUnknown(STSC), wbRStructs('Start Scenes', 'Start Scene', [ wbFormIDCk(LCEP, 'Scene', [SCEN]), wbInteger(INTT, 'Phase Index', itU16), wbString(SSPN, 'Start Phase for Scene'), wbCITC, wbCTDAs ], []), wbFormIDCk(PTOP, 'Player Positive Response', [DIAL]), wbFormIDCk(NTOP, 'Player Negative Response', [DIAL]), wbFormIDCk(NETO, 'Player Neutral Response', [DIAL]), wbFormIDCk(QTOP, 'Player Question Response', [DIAL]), wbFormIDCk(VENC, 'Player Positive Dialogue Subtype', [KYWD]), wbFormIDCk(PLVD, 'Player Negative Dialogue Subtype', [KYWD]), wbFormIDCk(JOUT, 'Player Neutral Dialogue Subtype', [KYWD]), wbFormIDCk(DALC, 'Player Question Dialogue Subtype', [KYWD]), wbArray(DTID, 'NPC Headtracking', wbInteger('Actor ID', itS32)), wbFormIDCk(NPOT, 'NPC Positive Response', [DIAL]), wbFormIDCk(NNGT, 'NPC Negative Response', [DIAL]), wbFormIDCk(NNUT, 'NPC Neutral Response', [DIAL]), wbFormIDCk(NQUT, 'NPC Question Response', [DIAL]), wbFormIDCk(NPOS, 'NPC Positive Dialogue Subtype', [KYWD]), wbFormIDCk(NNGS, 'NPC Negative Dialogue Subtype', [KYWD]), wbFormIDCk(NNUS, 'NPC Neutral Dialogue Subtype', [KYWD]), wbFormIDCk(NQUS, 'NPC Question Dialogue Subtype', [KYWD]), wbInteger(DTGT, 'Dialogue Target Actor', itS32), wbRArray('Packages', wbFormIDCk(PNAM, 'Package', [PACK])), wbFormIDCk(DATA, 'Topic', [DIAL, NULL]), wbUnion(HTID, '', wbSceneActionSoundDecider, [ wbEmpty('End Scene Say Greeting'), wbFormIDCk('Play Sound', [SNDR, NULL]) ]), wbFloat(DMAX, 'Looping - Max'), wbFloat(DMIN, 'Looping - Min'), wbStruct(CRIS, 'Camera', [ wbFloat('FOV On Player Camera'), wbFloat('Rate Of Camera Change') ]), wbInteger(DEMO, 'Emotion Type', itU32, wbEmotionTypeEnum), wbInteger(DEVA, 'Emotion Value', itU32), wbArray(HTID, 'Player Headtracking', wbInteger('Actor ID', itS32)), wbFormIDCk(VENC, 'Dialogue Subtype', [KYWD]), wbFormIDCk(PNAM, 'AnimArchType', [KYWD]), wbFormIDCk(ONAM, 'Audio Output Override', [SOPM]), wbEmpty(ANAM, 'End Marker') ], [])), wbFormIDCk(PNAM, 'Quest', [QUST]), wbInteger(INAM, 'Last Action Index', itU32), wbUnknown(VNAM), wbFloat(CNAM, 'Camera Distance Override'), wbFloat(ACTV, 'Dialogue Distance Override'), wbFloat(CRIS, 'FOV Override'), wbKSIZ, wbKWDAs, wbCTDAs, wbStruct(SCQS, 'Set Parent Quest Stage', [ wbInteger('On Begin', itS16), wbInteger('On End', itS16) ]), wbString(NNAM, 'Notes'), wbFormIDCk(TNAM, 'Template Scene', [SCEN]), wbInteger(XNAM, 'Index', itU32) ]); wbRecord(ASTP, 'Association Type', [ wbEDID, wbString(MPRT, 'Male Parent Title'), wbString(FPRT, 'Female Parent Title'), wbString(MCHT, 'Male Child Title'), wbString(FCHT, 'Female Child Title'), wbInteger(DATA, 'Flags', itU32, wbFlags([ 'Family Association' ])) ]); end; procedure DefineFO4k; begin wbSPED := wbStruct(SPED, 'Movement Data', [ wbFloat('Unknown'), wbFloat('Walk - Left'), wbFloat('Run - Left'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Walk - Right'), wbFloat('Run - Right'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Walk - Forward'), wbFloat('Run - Forward'), wbFloat('Sprint - Forward'), wbFloat('Unknown'), wbFloat('Walk - Back'), wbFloat('Run - Back'), wbFloat('Unknown'), wbFloat('Standing - Pitch', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Walk - Pitch', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Run - Pitch', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Sprint - Pitch', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Unknown'{, cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize}), wbFloat('Unknown'{, cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize}), wbFloat('Unknown'{, cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize}), wbFloat('Unknown'{, cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize}), wbFloat('Standing - Yaw', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Walk - Yaw', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Run - Yaw', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Sprint - Yaw', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize) ], cpNormal, True, nil, 10); wbRecord(OTFT, 'Outfit', [ wbEDID, wbArrayS(INAM, 'Items', wbFormIDCk('Item', [ARMO, LVLI])) ]); wbRecord(ARTO, 'Art Object', [ wbEDID, wbOBNDReq, wbPTRN, wbKSIZ, wbKWDAs, wbMODL, wbInteger(DNAM, 'Art Type', itU32, wbEnum([ 'Magic Casting', 'Magic Hit Effect', 'Enchantment Effect' ])) ]); wbRecord(MATO, 'Material Object', [ wbEDID, wbMODL, wbRArray('Property Data', wbByteArray(DNAM, 'Data', 0, cpIgnore, False, False, wbNeverShow) ), wbStruct(DATA, 'Directional Material Data', [ wbFloat('Falloff Scale'), wbFloat('Falloff Bias'), wbFloat('Noise UV Scale'), wbFloat('Material UV Scale'), wbStruct('Projection Vector', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), wbFloat('Normal Dampener'), wbFloatColors('Single Pass Color'), wbInteger('Flags', itU32, wbFlags(['Single Pass'])) ], cpNormal, True, nil, 5) ]); wbRecord(MOVT, 'Movement Type', [ wbEDID, wbString(MNAM, 'Name'), wbSPED, wbStruct(INAM, 'Anim Change Thresholds (unused)', [ wbFloat('Directional', cpNormal, True, 180/Pi), wbFloat('Movement Speed'), wbFloat('Rotation Speed', cpNormal, True, 180/Pi) ]), wbFloat(JNAM, 'Float Height'), wbFloat(LNAM, 'Flight - Angle Gain') ]); wbRecord(SNDR, 'Sound Descriptor', [ wbEDID, wbString(NNAM, 'Notes'), wbInteger(CNAM, 'Descriptor Type', itU32, wbEnum([], [ Int64($1EEF540A), 'Standard', Int64($54651A43), 'Compound', Int64($ED157AE3), 'AutoWeapon' ])), wbFormIDCk(GNAM, 'Category', [SNCT]), wbFormIDCk(SNAM, 'Alternate Sound For', [SNDR]), wbRArray('Sounds', wbRStruct('Sound Files', [ wbString(ANAM, 'File Name') ], []) ), wbFormIDCk(ONAM, 'Output Model', [SOPM]), wbCTDAs, wbStruct(LNAM, 'Values', [ wbByteArray('Unknown', 1), wbInteger('Looping', itU8, wbEnum([], [ $00, 'None', $08, 'Loop', $10, 'Envelope Fast', $20, 'Envelope Slow' ])), wbInteger('Sidechain', itU8), wbInteger('Rumble Send Value = (Small / 7) + ((Big / 7) * 16)', itU8) ]), wbUnion(BNAM, 'Data', wbSNDRDataDecider, [ wbStruct('Values', [ wbInteger('% Frequency Shift', itS8), wbInteger('% Frequency Variance', itS8), wbInteger('Priority', itU8), wbInteger('db Variance', itU8), wbInteger('Static Attenuation (db)', itU16, wbDiv(100)) ]), wbFormIDCk('Base Descriptor', [SNDR]) ]), wbRArray('Descriptors', wbFormIDCk(DNAM, 'Descriptor', [SNDR])), wbInteger(ITMC, 'Count', itU32, nil, cpBenign), wbRArrayS('Rates of Fire', wbRStructSK([1], 'Sound', [ wbEmpty(ITMS, 'Marker Start'), wbInteger(INTV, 'RoF (RPM)', itU32), wbString(FNAM, 'File'), wbEmpty(ITME, 'Marker End') ], []), cpNormal, False, nil, wbSNDRRatesOfFireAfterSet ) ]); wbRecord(DUAL, 'Dual Cast Data', [ wbEDID ]); wbRecord(SNCT, 'Sound Category', [ wbEDID, wbFULL, wbInteger(FNAM, 'Flags', itU32, wbFlags([ {0x0000001} 'Mute When Submerged', {0x0000002} 'Should Appear on Menu', {0x0000004} 'Immune to Time Speedup', {0x0000008} 'Pause During Menus (Immed)', {0x0000010} 'Pause During Menus (Fade)', {0x0000020} 'Exclude from Player OPM Override', {0x0000040} 'Pause During Start Menu' ]), cpNormal, True), wbFormIDCk(PNAM, 'Parent Category', [SNCT]), wbFormIDCk(ONAM, 'Menu Slider Category', [SNCT]), wbInteger(VNAM, 'Static Volume Multiplier', itU16, wbDiv(65535)), wbInteger(UNAM, 'Default Menu Value', itU16, wbDiv(65535)), wbFloat(MNAM, 'Min Frequency Multiplier'), wbFloat(CNAM, 'Sidechain Target Multiplier') ]); wbRecord(SOPM, 'Sound Output Model', [ wbEDID, wbStruct(NAM1, 'Data', [ wbInteger('Flags', itU8, wbFlags([ {0x01} 'Attenuates With Distance', {0x02} 'Allows Rumble', {0x04} 'Applies Doppler', {0x08} 'Applies Distance Delay', {0x10} 'Player Output Model', {0x20} 'Try Play on Controller', {0x40} 'Causes Ducking', {0x80} 'Avoids Ducking' ])), wbByteArray('Unknown', 2), wbInteger('Reverb Send %', itU8) ]), wbInteger(MNAM, 'Type', itU32, wbEnum([ 'Uses HRTF', 'Defined Speaker Output' ])), wbInteger(VNAM, 'Static Attenuation', itS16, wbDiv(100)), wbStruct(ONAM, 'Output Values', [ wbArray('Channels', wbStruct('', [ wbInteger('FL', itU8), wbInteger('FR', itU8), wbInteger('C', itU8), wbInteger('LFE', itU8), wbInteger('RL', itU8), wbInteger('RR', itU8), wbInteger('SL', itU8), wbInteger('SR', itU8) ]), [ 'Channel 0', 'Channel 1', 'Channel 2? (unused)' ]) ]), wbStruct(ATTN, 'Attenuation Values', [ wbFloat('Fade In Distance - Start'), wbFloat('Fade In Distance - End'), wbFloat('Fade Out Distance - Start'), wbFloat('Fade Out Distance - End'), wbStruct('Fade In Curve', [ wbInteger('Value 1', itU8), wbInteger('Value 2', itU8), wbInteger('Value 3', itU8), wbInteger('Value 4', itU8) ]), wbStruct('Fade Out Curve', [ wbInteger('Value 1', itU8), wbInteger('Value 2', itU8), wbInteger('Value 3', itU8), wbInteger('Value 4', itU8) ]) ]), wbFormIDCk(ENAM, 'Effect Chain', [AECH]) ]); wbRecord(COLL, 'Collision Layer', [ wbEDID, wbDESCReq, wbInteger(BNAM, 'Index', itU32, nil, cpNormal, True), wbStruct(FNAM, 'Debug Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbInteger('Unused', itU8) ], cpNormal, True), wbInteger(GNAM, 'Flags', itU32, wbFlags([ {0x00000001} 'Trigger Volume', {0x00000002} 'Sensor', {0x00000004} 'Navmesh Obstacle' ]), cpNormal, True), wbString(MNAM, 'Name', 0, cpNormal, True), wbInteger(INTV, 'Interactables Count', itU32, nil, cpNormal, True), wbArrayS(CNAM, 'Collides With', wbFormIDCk('Forms', [COLL]), 0, cpNormal, False) ]); wbRecord(CLFM, 'Color', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000004} 2, 'Non-Playable' ])), [ wbEDID, wbFULL, // union decider doesn't work during copying since decision data FNAM is located after it // workaround using integer formatters wbInteger(CNAM, 'Color/Index', itU32, wbCLFMColorToStr, wbCLFMColorToInt), {wbUnion(CNAM, 'Value', wbCLFMColorDecider, [ wbByteColors('Color'), wbFloat('Remapping Index') ]),} wbInteger(FNAM, 'Flags', itU32, wbFlags([ 'Playable', 'Remapping Index', 'Extended LUT' ]), cpNormal, True), wbCTDAs ]); end; procedure DefineFO4l; begin wbRecord(REVB, 'Reverb Parameters', [ wbEDID, wbStruct(DATA, 'Data', [ wbInteger('Decay Time (ms)', itU16), wbInteger('HF Reference (Hz)', itU16), wbInteger('Room Filter', itS8), wbInteger('Room HF Filter', itS8), wbInteger('Reflections', itS8), wbInteger('Reverb Amp', itS8), wbInteger('Decay HF Ratio', itU8, wbDiv(100)), wbInteger('Reflect Delay (ms), scaled', itU8), wbInteger('Reverb Delay (ms)', itU8), wbInteger('Diffusion %', itU8), wbInteger('Density %', itU8), wbInteger('Unknown', itU8) ], cpNormal, True), wbInteger(ANAM, 'Reverb Class', itU32, wbReverbClassEnum, cpNormal, True) ]); wbRecord(GRAS, 'Grass', [ wbEDID, wbOBNDReq, wbMODL, wbStruct(DATA, '', [ wbInteger('Density', itU8), wbInteger('Min Slope', itU8), wbInteger('Max Slope', itU8), wbByteArray('Unknown', 1), wbInteger('Units From Water', itU16), wbByteArray('Unknown', 2), wbInteger('Units From Water Type', itU32, wbEnum([ 'Above - At Least', 'Above - At Most', 'Below - At Least', 'Below - At Most', 'Either - At Least', 'Either - At Most', 'Either - At Most Above', 'Either - At Most Below' ])), wbFloat('Position Range'), wbFloat('Height Range'), wbFloat('Color Range'), wbFloat('Wave Period'), wbInteger('Flags', itU8, wbFlags([ 'Vertex Lighting', 'Uniform Scaling', 'Fit to Slope' ])), wbByteArray('Unknown', 3) ], cpNormal, True) ]); wbRecord(IDLE, 'Idle Animation', [ wbEDID, wbCTDAs, wbString(DNAM, 'Behavior Graph'), wbString(ENAM, 'Animation Event'), wbArray(ANAM, 'Related Idle Animations', wbFormIDCk('Related Idle Animation', [AACT, IDLE, NULL]), ['Parent', 'Previous Sibling'], cpNormal, True), wbStruct(DATA, '', [ wbStruct('Looping seconds (both 255 forever)', [ wbInteger('Min', itU8), wbInteger('Max', itU8) ]), wbInteger('Flags', itU8, wbFlags([ {0x01} 'Parent', {0x02} 'Sequence', {0x04} 'No Attacking', {0x04} 'Blocking' ], True)), wbInteger('Animation Group Section', itU8{, wbIdleAnam}), wbInteger('Replay Delay', itU16) ], cpNormal, True), wbString(GNAM, 'Animation File') ]); wbRecord(INFO, 'Dialog response', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000040} 6, 'Unknown 6', {0x00000080} 7, 'Exclude From Export', {0x00002000} 13, 'Actor Changed' ])), [ wbEDID, wbVMADFragmentedINFO, wbStruct(ENAM, 'Response flags', [ wbInteger('Flags', itU16, wbFlags([ {0x0001} 'Start Scene on End', {0x0002} 'Random', {0x0004} 'Say Once', {0x0008} 'Requires Player Activation', {0x0010} 'Unknown 4', {0x0020} 'Random End', {0x0040} 'End Running Scene', {0x0080} 'ForceGreet Hello', {0x0100} 'Player Address', {0x0200} 'Unknown 9', {0x0400} 'Can Move While Greeting', {0x0800} 'No LIP File', {0x1000} 'Requires post-processing', {0x2000} 'Audio Output Override', {0x4000} 'Has Capture', {0x8000} 'Unknown 16' ])), wbInteger('Reset Hours', itU16, wbDiv(2730)) ]), wbFormIDCk(TPIC, 'Topic', [DIAL]), wbFormIDCkNoReach(PNAM, 'Previous INFO', [INFO, NULL], False, cpBenign), wbFormIDCk(DNAM, 'Shared INFO', [INFO]), wbFormIDCk(GNAM, 'Unknown', [INFO]), wbString(IOVR, 'Override Filename'), wbRArray('Responses', wbRStruct('Response', [ wbStruct(TRDA, 'Response Data', [ wbFormIDCk('Emotion', [KYWD, FFFF]), wbInteger('Response number', itU8), wbByteArray('Unused', 3), wbByteArray('Unknown', 2), wbInteger('Interrupt Percentage', itU16), wbInteger('Camera Target Alias', itS32), wbInteger('Camera Location Alias', itS32) ]), wbLStringKC(NAM1, 'Response Text', 0, cpTranslate, True), wbString(NAM2, 'Script Notes', 0, cpNormal, True), wbString(NAM3, 'Edits', 0, cpNormal, True), wbString(NAM4, 'Alternate LIP Text', 0, cpNormal, True), wbFormIDCk(SNAM, 'Idle Animations: Speaker', [IDLE]), wbFormIDCk(LNAM, 'Idle Animations: Listener', [IDLE]), wbInteger(TNAM, 'Interrupt Percentage', itU16), wbByteArray(NAM9, 'Text Hash'), wbFormIDCk(SRAF, 'Camera Path', [CPTH]), wbEmpty(WZMD, 'Stop on Scene End') ], [])), wbCTDAs, wbLString(RNAM, 'Prompt', 0, cpTranslate), wbFormIDCk(ANAM, 'Speaker', [NPC_]), wbFormIDCk(TSCE, 'Start Scene', [SCEN]), wbInteger(ALFA, 'Forced Alias', itS32), wbUnknown(INTV), wbFormIDCk(ONAM, 'Audio Output Override', [SOPM]), wbInteger(GREE, 'Greet Distance', itU32), wbStruct(TIQS, 'Set Parent Quest Stage', [ wbInteger('On Begin', itS16), wbInteger('On End', itS16) ]), wbString(NAM0, 'Start Scene Phase'), wbInteger(INCC, 'Challenge', itU32, wbEnum([ {0} 'None', {1} 'Easy', {2} 'Medium', {3} 'Hard', {4} 'Always Succeeds', {5} 'Easy Repeatable', {6} 'Medium Repeatable', {7} 'Hard Repeatable' ])), wbFormIDCk(MODQ, 'Reset Global', [GLOB]), wbInteger(INAM, 'Subtitle Priority', itU32, wbEnum([ 'Low', 'Normal', 'Unknown 2', 'Force' ])) ], False, wbINFOAddInfo, cpNormal, False, nil{wbINFOAfterLoad}); wbRecord(INGR, 'Ingredient', [ wbEDID, wbVMAD, wbOBNDReq, wbFULL, wbKSIZ, wbKWDAs, wbMODL, wbICON, wbMICO, wbDEST, wbETYP, wbYNAM, wbZNAM, wbStruct(DATA, '', [ wbInteger('Value', itS32), wbFloat('Weight') ], cpNormal, True), wbStruct(ENIT, 'Effect Data', [ wbInteger('Ingredient Value', itS32), wbInteger('Flags', itU32, wbFlags([ {0x00000001} 'No auto-calculation', {0x00000002} 'Food item', {0x00000004} 'Unknown 3', {0x00000008} 'Unknown 4', {0x00000010} 'Unknown 5', {0x00000020} 'Unknown 6', {0x00000040} 'Unknown 7', {0x00000080} 'Unknown 8', {0x00000100} 'References Persist' ])) ], cpNormal, True), wbEffectsReq ], False, nil, cpNormal, False, nil, wbKeywordsAfterSet); wbRecord(KEYM, 'Key', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000800} 11, 'Calc Value From Components', {0x00002000} 13, 'Pack-In Use Only' ])), [ wbEDID, wbVMAD, wbOBNDReq, wbPTRN, wbFULLReq, wbMODL, wbICON, wbMICO, wbDEST, wbYNAM, wbZNAM, wbKSIZ, wbKWDAs, wbStruct(DATA, '', [ wbInteger('Value', itS32), wbFloat('Weight') ], cpNormal, True) ], False, nil, cpNormal, False, nil, wbKeywordsAfterSet); wbQuadrantEnum := wbEnum([ {0} 'Bottom Left', {1} 'Bottom Right', {2} 'Top Left', {3} 'Top Right' ]); if wbSimpleRecords then begin wbRecord(LAND, 'Landscape', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00040000} 18, 'Compressed' ]), [18]), [ wbByteArray(DATA, 'Unknown'), wbByteArray(VNML, 'Vertex Normals'), wbByteArray(VHGT, 'Vertext Height Map'), wbByteArray(VCLR, 'Vertex Colours'), wbRArrayS('Layers', wbRUnion('Layer', [ wbRStructSK([0],'Base Layer', [ wbStructSK(BTXT, [1, 3], 'Base Layer Header', [ wbFormIDCk('Texture', [LTEX, NULL]), wbInteger('Quadrant', itU8, wbQuadrantEnum), wbByteArray('Unknown', 1), wbInteger('Layer', itS16) ]) ], []), wbRStructSK([0],'Alpha Layer', [ wbStructSK(ATXT, [1, 3], 'Alpha Layer Header', [ wbFormIDCk('Texture', [LTEX, NULL]), wbInteger('Quadrant', itU8, wbQuadrantEnum), wbByteArray('Unknown', 1), wbInteger('Layer', itS16) ]), wbByteArray(VTXT, 'Alpha Layer Data') ], []) ], [])), wbArray(VTEX, 'Textures', wbFormIDCk('Texture', [LTEX, NULL])), wbRArray('Unknown', wbUnknown(MPCD)) ]); end else begin wbRecord(LAND, 'Landscape', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00040000} 18, 'Compressed' ]), [18]), [ wbByteArray(DATA, 'Unknown'), wbArray(VNML, 'Vertex Normals', wbStruct('Row', [ wbArray('Columns', wbStruct('Column', [ wbInteger('X', itU8), wbInteger('Y', itU8), wbInteger('Z', itU8) ]), 33) ]), 33), wbStruct(VHGT, 'Vertext Height Map', [ wbFloat('Offset'), wbArray('Rows', wbStruct('Row', [ wbArray('Columns', wbInteger('Column', itU8), 33) ]), 33), wbByteArray('Unknown', 3) ]), wbArray(VCLR, 'Vertex Colours', wbStruct('Row', [ wbArray('Columns', wbStruct('Column', [ wbInteger('X', itU8), wbInteger('Y', itU8), wbInteger('Z', itU8) ]), 33) ]), 33), wbRArrayS('Layers', wbRUnion('Layer', [ wbRStructSK([0],'Base Layer', [ wbStructSK(BTXT, [1, 3], 'Base Layer Header', [ wbFormIDCk('Texture', [LTEX, NULL]), wbInteger('Quadrant', itU8, wbQuadrantEnum), wbByteArray('Unknown', 1), wbInteger('Layer', itS16) ]) ], []), wbRStructSK([0],'Alpha Layer', [ wbStructSK(ATXT, [1, 3], 'Alpha Layer Header', [ wbFormIDCk('Texture', [LTEX, NULL]), wbInteger('Quadrant', itU8, wbQuadrantEnum), wbByteArray('Unknown', 1), wbInteger('Layer', itS16) ]), wbArrayS(VTXT, 'Alpha Layer Data', wbStructSK([0], 'Cell', [ wbInteger('Position', itU16, wbAtxtPosition), wbByteArray('Unknown', 2), wbFloat('Opacity') ])) ], []) ], [])), wbArray(VTEX, 'Textures', wbFormIDCk('Texture', [LTEX, NULL])), wbRArray('Unknown', wbUnknown(MPCD)) ]); end; wbRecord(LIGH, 'Light', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00010000} 16, 'Random Anim Start', {0x00020000} 17, 'Unknown 17', {0x00020000} 25, 'Obstacle', {0x00020000} 28, 'Portal-strict' ])), [ wbEDID, wbVMAD, wbOBNDReq, wbPTRN, wbMODL, wbKSIZ, wbKWDAs, wbDEST, wbPRPS, wbFULL, wbICON, wbMICO, wbStruct(DATA, '', [ wbInteger('Time', itS32), wbInteger('Radius', itU32), wbByteColors('Color'), // Omnidirectional is the default type wbInteger('Flags', itU32, wbFlags([ {0x00000001} 'Unknown 0', {0x00000002} 'Can be Carried', {0x00000004} 'Unknown 2', {0x00000008} 'Flicker', {0x00000010} 'Unknown 4', {0x00000020} 'Off By Default', {0x00000040} 'Unknown 6', {0x00000080} 'Pulse', {0x00000100} 'Unknown 8', {0x00000200} 'Unknown 9', {0x00000400} 'Shadow Spotlight', {0x00000800} 'Shadow Hemisphere', {0x00001000} 'Shadow OmniDirectional', {0x00002000} 'Unknown 13', {0x00004000} 'NonShadow Spotlight', {0x00008000} 'Non Specular', {0x00010000} 'Attenuation Only', {0x00020000} 'NonShadow Box', {0x00040000} 'Ignore Roughness', {0x00080000} 'No Rim Lighting', {0x00100000} 'Ambient Only', {0x00200000} 'Unknown 21' // only in [001C7F0C] ])), wbFloat('Falloff Exponent'), wbFloat('FOV'), wbFloat('Near Clip'), wbStruct('Flicker Effect', [ wbFloat('Period'), wbFloat('Intensity Amplitude'), wbFloat('Movement Amplitude') ]), wbFloat('Constant'), wbFloat('Scalar'), wbFloat('Exponent'), wbFloat('God Rays - Near Clip'), wbInteger('Value', itU32), wbFloat('Weight') ], cpNormal, True, nil, 10), wbFloat(FNAM, 'Fade value', cpNormal, True), wbString(NAM0, 'Gobo'), wbFormIDCk(LNAM, 'Lens', [LENS]), wbFormIDCk(WGDR, 'God Rays', [GDRY]), wbFormIDCk(SNAM, 'Sound', [SNDR]) ], False, nil, cpNormal, False, wbLIGHAfterLoad); end; procedure DefineFO4m; begin wbRecord(LSCR, 'Load Screen', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000400} 10, 'Displays In Main Menu', {0x00008000} 15, 'No Rotation' ])), [ wbEDID, wbDESCReq, wbCTDAs, wbFormIDCk(NNAM, 'Loading Screen NIF', [STAT, SCOL, NULL], False, cpNormal, True), wbFormIDCk(TNAM, 'Transform', [TRNS]), wbStruct(ONAM, 'Rotation', [ wbInteger('Min', itS16), wbInteger('Max', itS16) ]), wbStruct(ZNAM, 'Zoom', [ wbFloat('Min'), wbFloat('Max') ]), wbString(MOD2, 'Camera Path', 0, cpNormal, False) ]); wbRecord(LTEX, 'Landscape Texture', [ wbEDID, wbFormIDCk(TNAM, 'Texture Set', [TXST], False, cpNormal, False), wbFormIDCk(MNAM, 'Material Type', [MATT, NULL], False, cpNormal, True), wbStruct(HNAM, 'Havok Data', [ wbInteger('Friction', itU8), wbInteger('Restitution', itU8) ], cpNormal, True), wbInteger(SNAM, 'Texture Specular Exponent', itU8, nil, cpNormal, True), wbRArray('Grasses', wbFormIDCk(GNAM, 'Grass', [GRAS])) ]); wbRecord(LVLN, 'Leveled NPC', [ wbEDID, wbOBNDReq, wbLVLD, wbInteger(LVLM, 'Max Count', itU8), { Always 00 } {Unavailable} wbInteger(LVLF, 'Flags', itU8, wbFlags([ {0x01} 'Calculate from all levels <= player''s level', {0x02} 'Calculate for each item in count', {0x04} 'Calculate All' {Still picks just one} ]), cpNormal, True), wbFormIDCk(LVLG, 'Use Global', [GLOB]), wbLLCT, wbRArrayS('Leveled List Entries', wbRStructExSK([0], [1], 'Leveled List Entry', [ wbStructExSK(LVLO , [0, 2], [3], 'Base Data', [ wbInteger('Level', itU16), wbByteArray('Unused', 2, cpIgnore, false, wbNeverShow), wbFormIDCk('Reference', [NPC_, LVLN]), wbInteger('Count', itS16), wbInteger('Chance None', itU8), wbByteArray('Unused', 1, cpIgnore, false, wbNeverShow) ]), wbCOED ], []), cpNormal, False, nil, wbLVLOsAfterSet), wbArrayS(LLKC, 'Filter Keyword Chances', wbStructSK([0], 'Filter', [ wbFormIDCk('Keyword', [KYWD]), wbInteger('Chance', itU32) ]) ), wbMODL ], False, nil, cpNormal, False, wbLLEAfterLoad, wbLLEAfterSet); wbRecord(LVLI, 'Leveled Item', [ wbEDID, wbOBNDReq, wbLVLD, wbInteger(LVLM, 'Max Count', itU8), { Always 00 } wbInteger(LVLF, 'Flags', itU8, wbFlags([ {0x01} 'Calculate from all levels <= player''s level', {0x02} 'Calculate for each item in count', {0x04} 'Use All' ]), cpNormal, True), wbFormIDCk(LVLG, 'Use Global', [GLOB]), wbLLCT, wbRArrayS('Leveled List Entries', wbRStructExSK([0], [1], 'Leveled List Entry', [ wbStructExSK(LVLO , [0, 2], [3], 'Base Data', [ wbInteger('Level', itU16), wbByteArray('Unused', 2, cpIgnore, false, wbNeverShow), wbFormIDCk('Reference', sigBaseObjects), wbInteger('Count', itU16), wbInteger('Chance None', itU8), wbByteArray('Unused', 1, cpIgnore, false, wbNeverShow) ]), wbCOED ], []), cpNormal, False, nil, wbLVLOsAfterSet ), wbArrayS(LLKC, 'Filter Keyword Chances', wbStructSK([0], 'Filter', [ wbFormIDCk('Keyword', [KYWD]), wbInteger('Chance', itU32) ]) ), wbFormIDCk(LVSG, 'Epic Loot Chance', [GLOB]), wbLStringKC(ONAM, 'Override Name', 0, cpTranslate) ], False, nil, cpNormal, False, wbLLEAfterLoad, wbLLEAfterSet); wbRecord(LVSP, 'Leveled Spell', [ wbEDID ]); wbMGEFType := wbInteger('Archetype', itU32, wbEnum([ {00} 'Value Modifier', {01} 'Script', {02} 'Dispel', {03} 'Cure Disease', {04} 'Absorb', {05} 'Dual Value Modifier', {06} 'Calm', {07} 'Demoralize', {08} 'Frenzy', {09} 'Disarm', {10} 'Command Summoned', {11} 'Invisibility', {12} 'Light', {13} 'Darkness', {14} 'Nighteye', {15} 'Lock', {16} 'Open', {17} 'Bound Weapon', {18} 'Summon Creature', {19} 'Detect Life', {20} 'Telekinesis', {21} 'Paralysis', {22} 'Reanimate', {23} 'Soul Trap', {24} 'Turn Undead', {25} 'Guide', {26} 'Unknown 26', {27} 'Cure Paralysis', {28} 'Cure Addiction', {29} 'Cure Poison', {30} 'Concussion', {31} 'Stimpack', {32} 'Accumulate Magnitude', {33} 'Stagger', {34} 'Peak Value Modifier', {35} 'Cloak', {36} 'Unknown 36', {37} 'Slow Time', {38} 'Rally', {39} 'Enhance Weapon', {40} 'Spawn Hazard', {41} 'Etherealize', {42} 'Banish', {43} 'Spawn Scripted Ref', {44} 'Disguise', {45} 'Damage', {46} 'Immunity', {47} 'Permanent Reanimate', {48} 'Jetpack', {49} 'Chameleon' ]), cpNormal, False, nil, wbMGEFArchtypeAfterSet); wbMGEFData := wbRStruct('Magic Effect Data', [ wbStruct(DATA, 'Data', [ wbInteger('Flags', itU32, wbFlags([ {0x00000001} 'Hostile', {0x00000002} 'Recover', {0x00000004} 'Detrimental', {0x00000008} 'Snap to Navmesh', {0x00000010} 'No Hit Event', {0x00000020} 'Unknown 6', {0x00000040} 'Unknown 7', {0x00000080} 'Unknown 8', {0x00000100} 'Dispel with Keywords', {0x00000200} 'No Duration', {0x00000400} 'No Magnitude', {0x00000800} 'No Area', {0x00001000} 'FX Persist', {0x00002000} 'Unknown 14', {0x00004000} 'Gory Visuals', {0x00008000} 'Hide in UI', {0x00010000} 'Unknown 17', {0x00020000} 'No Recast', {0x00040000} 'Unknown 19', {0x00080000} 'Unknown 20', {0x00100000} 'Unknown 21', {0x00200000} 'Power Affects Magnitude', {0x00400000} 'Power Affects Duration', {0x00800000} 'Unknown 24', {0x01000000} 'Unknown 25', {0x02000000} 'Unknown 26', {0x04000000} 'Painless', {0x08000000} 'No Hit Effect', {0x10000000} 'No Death Dispel', {0x20000000} 'Unknown 30', {0x40000000} 'Unknown 31', {0x80000000} 'Unknown 32' ])), wbFloat('Base Cost'), wbUnion('Assoc. Item', wbMGEFAssocItemDecider, [ wbFormID('Unused', cpIgnore), wbFormIDCk('Assoc. Item', [LIGH, NULL]), wbFormIDCk('Assoc. Item', [WEAP, ARMO, NULL]), wbFormIDCk('Assoc. Item', [NPC_, NULL]), wbFormIDCk('Assoc. Item', [HAZD, NULL]), wbFormIDCk('Assoc. Item', [SPEL, NULL]), wbFormIDCk('Assoc. Item', [RACE, NULL]), wbFormIDCk('Assoc. Item', [ENCH, NULL]), wbFormIDCk('Assoc. Item', [KYWD, NULL]) ], cpNormal, False, nil, wbMGEFAssocItemAfterSet), wbByteArray('Magic Skill (unused)', 4), wbFormIDCk('Resist Value', [AVIF, NULL]), wbInteger('Counter Effect count', itU16), wbByteArray('Unused', 2), wbFormIDCk('Casting Light', [LIGH, NULL]), wbFloat('Taper Weight'), wbFormIDCk('Hit Shader', [EFSH, NULL]), wbFormIDCk('Enchant Shader', [EFSH, NULL]), wbInteger('Minimum Skill Level', itU32), wbStruct('Spellmaking', [ wbInteger('Area', itU32), wbFloat('Casting Time') ]), wbFloat('Taper Curve'), wbFloat('Taper Duration'), wbFloat('Second AV Weight', cpNormal, False, nil, wbMGEFAV2WeightAfterSet), wbMGEFType, wbActorValue, wbFormIDCk('Projectile', [PROJ, NULL]), wbFormIDCk('Explosion', [EXPL, NULL]), wbInteger('Casting Type', itU32, wbCastEnum), wbInteger('Delivery', itU32, wbTargetEnum), wbActorValue, //wbInteger('Second Actor Value', itS32, wbActorValueEnum), wbFormIDCk('Casting Art', [ARTO, NULL]), wbFormIDCk('Hit Effect Art', [ARTO, NULL]), wbFormIDCk('Impact Data', [IPDS, NULL]), wbFloat('Skill Usage Multiplier'), wbStruct('Dual Casting', [ wbFormIDCk('Art', [DUAL, NULL]), wbFloat('Scale') ]), wbFormIDCk('Enchant Art', [ARTO, NULL]), wbByteArray('Unknown', 4), wbByteArray('Unknown', 4), wbFormIDCk('Equip Ability', [SPEL, NULL]), wbFormIDCk('Image Space Modifier', [IMAD, NULL]), wbFormIDCk('Perk to Apply', [PERK, NULL]), wbInteger('Casting Sound Level', itU32, wbSoundLevelEnum), wbStruct('Script Effect AI', [ wbFloat('Score'), wbFloat('Delay Time') ]) ], cpNormal, True) ], []); wbRecord(MGEF, 'Magic Effect', [ wbEDID, wbVMAD, wbFULL, wbMDOB, wbKSIZ, wbKWDAs, wbMGEFData, wbRArrayS('Counter Effects', wbFormIDCk(ESCE, 'Effect', [MGEF]), cpNormal, False, nil, wbCounterEffectsAfterSet), wbArray(SNDD, 'Sounds', wbStruct('', [ wbInteger('Type', itU32, wbEnum([ 'Sheathe/Draw', 'Charge', 'Ready', 'Release', 'Concentration Cast Loop', 'On Hit' ])), wbFormIDCk('Sound', [SNDR]) ])), wbLStringKC(DNAM, 'Magic Item Description', 0, cpTranslate), wbCTDAs ], False, nil, cpNormal, False, nil {wbMGEFAfterLoad}, wbMGEFAfterSet); wbRecord(MISC, 'Misc. Item', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000004} 11, 'Calc From Components', {0x00000004} 13, 'Pack-In Use Only' ])), [ wbEDID, wbVMAD, wbOBNDReq, wbPTRN, wbFULL, wbMODL, wbICON, wbMICO, wbDEST, wbYNAM, wbZNAM, wbKSIZ, wbKWDAs, wbFormID(FIMD, 'Featured Item Message'), wbStruct(DATA, 'Data', [ wbInteger('Value', itS32), wbFloat('Weight') ], cpNormal, True), // the amount of components is the same as size of CDIX, so should not be sorted probably wbStructs(CVPA, 'Components', 'Component', [ wbFormIDCk('Component', sigBaseObjects), // CK allows only CMPO wbInteger('Count', itU32) ]), wbArray(CDIX, 'Component Display Indices', wbInteger('Display Index', itU8)) ], False, nil, cpNormal, False, wbRemoveEmptyKWDA, wbKeywordsAfterSet); wbRecord(COBJ, 'Constructible Object', [ wbEDID, wbYNAM, wbZNAM, wbArrayS(FVPA, 'Components', wbStructSK([0], 'Component', [ wbFormIDCk('Component', sigBaseObjects), wbInteger('Count', itU32) ]) ), wbDESC, wbCTDAs, wbFormIDCk(CNAM, 'Created Object', sigBaseObjects), wbFormIDCk(BNAM, 'Workbench Keyword', [KYWD]), wbByteArray(NAM1, 'Unused', 0, cpIgnore, False, False, wbNeverShow), // co_PA_FusionCore01 wbByteArray(NAM2, 'Unused', 0, cpIgnore, False, False, wbNeverShow), // co_PA_FusionCore01 wbByteArray(NAM3, 'Unused', 0, cpIgnore, False, False, wbNeverShow), // co_PA_FusionCore01 wbFormIDCk(ANAM, 'Menu Art Object', [ARTO]), wbArrayS(FNAM, 'Category', wbFormIDCk('Keyword', [KYWD])), wbStruct(INTV, 'Data', [ wbInteger('Created Object Count', itU16), wbInteger('Priority', itU16) ], cpNormal, False, nil, 1) ]); wbRecord(NPC_, 'Non-Player Character (Actor)', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000400} 10, 'Unknown 10', {0x00040000} 18, 'Compressed', {0x00080000} 19, 'Unknown 19', {0x20000000} 29, 'Bleedout Override' ]), [18]), [ wbEDID, wbVMAD, wbOBNDReq, wbPTRN, wbFormIDCk(STCP, 'Unknown', [STAG]), wbStruct(ACBS, 'Configuration', [ wbInteger('Flags', itU32, wbFlags([ {0x00000001} 'Female', {0x00000002} 'Essential', {0x00000004} 'Is CharGen Face Preset', {0x00000008} 'Respawn', {0x00000010} 'Auto-calc stats', {0x00000020} 'Unique', {0x00000040} 'Doesn''t affect stealth meter', {0x00000080} 'PC Level Mult', {0x00000100} 'Unknown 8', {0x00000200} 'Calc For Each Template', {0x00000400} 'Unknown 10', {0x00000800} 'Protected', {0x00001000} 'Unknown 12', {0x00002000} 'Unknown 13', {0x00004000} 'Summonable', {0x00008000} 'Unknown 15', {0x00010000} 'Doesn''t bleed', {0x00020000} 'Unknown 17', {0x00040000} 'Bleedout Override', {0x00080000} 'Opposite Gender Anims', {0x00100000} 'Simple Actor', {0x00200000} 'Unknown 21', {0x00400000} 'Unknown 22', {0x00800000} 'No Activation/Hellos', {0x01000000} 'Diffuse Alpha Test', {0x02000000} 'Unknown 25', {0x04000000} 'Unknown 26', {0x08000000} 'Unknown 27', {0x10000000} 'Unknown 28', {0x20000000} 'Is Ghost', {0x40000000} 'Unknown 30', {0x80000000} 'Invulnerable' ])), wbInteger('XP Value Offset', itS16, nil, cpNormal, True, nil{wbActorTemplateUseStats}), wbUnion('Level', wbNPCLevelDecider, [ wbInteger('Level', itS16, nil, cpNormal, True, nil{wbActorTemplateUseStats}), wbInteger('Level Mult', itS16, wbDiv(1000), cpNormal, True, nil{wbActorTemplateUseStats}) ], cpNormal, True, nil{wbActorTemplateUseStats}), wbInteger('Calc min level', itU16, nil, cpNormal, True, nil{wbActorTemplateUseStats}), wbInteger('Calc max level', itU16, nil, cpNormal, True, nil{wbActorTemplateUseStats}), wbInteger('Disposition Base', itS16), wbInteger('Use Template Actors', itU16, wbFlags([ {0x0001} 'Traits', {0x0002} 'Stats', {0x0004} 'Factions', {0x0008} 'Spell List', {0x0010} 'AI Data', {0x0020} 'AI Packages', {0x0040} 'Model/Animation', {0x0080} 'Base Data', {0x0100} 'Inventory', {0x0200} 'Script', {0x0400} 'Def Pack List', {0x0800} 'Attack Data', {0x1000} 'Keywords' ])), wbInteger('Bleedout Override', itU16), wbByteArray('Unknown', 2) ], cpNormal, True), wbRArrayS('Factions', wbStructSK(SNAM, [0], 'Faction', [ wbFormIDCk('Faction', [FACT]), wbInteger('Rank', itS8) ]), cpNormal, False, nil, nil, nil{wbActorTemplateUseFactions} ), wbFormIDCk(INAM, 'Death item', [LVLI], False, cpNormal, False, nil{wbActorTemplateUseTraits}), wbFormIDCk(VTCK, 'Voice', [VTYP], False, cpNormal, False, nil{wbActorTemplateUseTraits}), wbFormIDCk(TPLT, 'Default Template', [LVLN, NPC_]), wbFormIDCk(LTPT, 'Legendary Template', [LVLN, NPC_]), wbFormIDCk(LTPC, 'Legendary Chance', [GLOB]), wbStruct(TPTA, 'Template Actors', [ wbFormIDCk('Traits', [LVLN, NPC_, NULL], False, cpNormal, False, wbActorTemplatesUseTemplate0), wbFormIDCk('Stats', [LVLN, NPC_, NULL], False, cpNormal, False, wbActorTemplatesUseTemplate1), wbFormIDCk('Factions', [LVLN, NPC_, NULL], False, cpNormal, False, wbActorTemplatesUseTemplate2), wbFormIDCk('Spell List', [LVLN, NPC_, NULL], False, cpNormal, False, wbActorTemplatesUseTemplate3), wbFormIDCk('AI Data', [LVLN, NPC_, NULL], False, cpNormal, False, wbActorTemplatesUseTemplate4), wbFormIDCk('AI Packages', [LVLN, NPC_, NULL], False, cpNormal, False, wbActorTemplatesUseTemplate5), wbFormIDCk('Model/Animation', [LVLN, NPC_, NULL], False, cpNormal, False, wbActorTemplatesUseTemplate6), wbFormIDCk('Base Data', [LVLN, NPC_, NULL], False, cpNormal, False, wbActorTemplatesUseTemplate7), wbFormIDCk('Inventory', [LVLN, NPC_, NULL], False, cpNormal, False, wbActorTemplatesUseTemplate8), wbFormIDCk('Script', [LVLN, NPC_, NULL], False, cpNormal, False, wbActorTemplatesUseTemplate9), wbFormIDCk('Def Pack List', [LVLN, NPC_, NULL], False, cpNormal, False, wbActorTemplatesUseTemplate10), wbFormIDCk('Attack Data', [LVLN, NPC_, NULL], False, cpNormal, False, wbActorTemplatesUseTemplate11), wbFormIDCk('Keywords', [LVLN, NPC_, NULL], False, cpNormal, False, wbActorTemplatesUseTemplate12) ]), wbFormIDCk(RNAM, 'Race', [RACE], False, cpNormal, True, nil{wbActorTemplateUseTraits}), wbSPCT, wbSPLOs, wbDEST, wbFormIDCk(WNAM, 'Skin', [ARMO], False, cpNormal, False), wbFormIDCk(ANAM, 'Far away model', [ARMO], False, cpNormal, False, nil{wbActorTemplateUseTraits}), wbFormIDCk(ATKR, 'Attack Race', [RACE], False, cpNormal, False), wbRArrayS('Attacks', wbAttackData), wbFormIDCk(SPOR, 'Spectator Override Package List', [FLST]), wbFormIDCk(OCOR, 'Observe Dead Body Override Package List', [FLST]), wbFormIDCk(GWOR, 'Guard Warn Override Package List', [FLST]), wbFormIDCk(ECOR, 'Combat Override Package List', [FLST]), wbFormIDCk(FCPL, 'Follower Command Package List', [FLST]), wbFormIDCk(RCLR, 'Follower Elevator Package List', [FLST]), wbInteger(PRKZ, 'Perk Count', itU32, nil, cpBenign), wbRArrayS('Perks', wbStructSK(PRKR, [0], 'Perk', [ wbFormIDCk('Perk', [PERK]), wbInteger('Rank', itU8) ]), cpNormal, False, nil, wbPRKRsAfterSet ), wbPRPS, wbFTYP, wbNTRM, wbCOCT, wbCNTOs, wbAIDT, wbRArray('Packages', wbFormIDCk(PKID, 'Package', [PACK]), cpNormal, False, nil{wbActorTemplateUseAIPackages}), wbKSIZ, wbKWDAs, wbAPPR, wbObjectTemplate, wbFormIDCk(CNAM, 'Class', [CLAS], False, cpNormal, True), wbFULL, wbLString(SHRT, 'Short Name', 0, cpTranslate), wbByteArray(DATA, 'Marker'), wbStruct(DNAM, '', [ wbInteger('Unknown', itU16), wbInteger('Unknown', itU16), wbInteger('Far Away Model Distance', itU16), wbInteger('Geared Up Weapons', itU16) ]), wbRArrayS('Head Parts', wbFormIDCk(PNAM, 'Head Part', [HDPT]), cpNormal, False, nil, nil, nil{wbActorTemplateUseModelAnimation}), wbFormIDCk(HCLF, 'Hair Color', [CLFM], False, cpNormal, False), wbFormIDCk(BCLF, 'Facial Hair Color', [CLFM], False, cpNormal, False), wbFormIDCk(ZNAM, 'Combat Style', [CSTY], False, cpNormal, False), wbFormIDCk(GNAM, 'Gift Filter', [FLST], False, cpNormal, False), wbUnknown(NAM5, cpNormal, True), wbFloat(NAM6, 'Height Min', cpNormal, True), wbFloat(NAM7, 'Unused', cpNormal, True), wbFloat(NAM4, 'Height Max'), wbStruct(MWGT, 'Weight', [ wbFloat('Thin'), wbFloat('Muscular'), wbFloat('Fat') ]), wbInteger(NAM8, 'Sound Level', itU32, wbSoundLevelEnum, cpNormal, True), wbRStruct('Actor Sounds', [ wbInteger(CS2H, 'Count', itU32, nil, cpBenign, True), wbRArrayS('Sounds', wbRStructSK([0], 'Sound', [ wbFormIDCk(CS2K, 'Keyword', [KYWD]), wbFormIDCk(CS2D, 'Sound', [SNDR], False, cpNormal, True) ], [], cpNormal, False, nil, True), cpNormal, False, nil, wbNPCActorSoundsAfterSet ), wbEmpty(CS2E, 'End Marker', cpNormal, True), wbByteArray(CS2F, 'Finalize', 1, cpNormal, True) ], []), wbFormIDCk(CSCR, 'Inherits Sounds From', [NPC_], False, cpNormal, False), wbFormIDCk(PFRN, 'Power Armor Stand', [FURN]), wbFormIDCk(DOFT, 'Default Outfit', [OTFT], False, cpNormal, False), wbFormIDCk(SOFT, 'Sleeping Outfit', [OTFT], False, cpNormal, False), wbFormIDCk(DPLT, 'Default Package List', [FLST], False, cpNormal, False), wbFormIDCk(CRIF, 'Crime Faction', [FACT], False, cpNormal, False), wbFormIDCk(FTST, 'Head Texture', [TXST], False, cpNormal, False), wbStruct(QNAM, 'Texture lighting', [ wbFloat('Red', cpNormal, True, 255, 0), wbFloat('Green', cpNormal, True, 255, 0), wbFloat('Blue', cpNormal, True, 255, 0), wbFloat('Alpha') ]), wbArray(MSDK, 'Morph Keys', wbInteger('Key', itU32, wbMorphValueToStr, wbHexStrToInt)), wbArray(MSDV, 'Morph Values', wbFloat('Value')), wbRArrayS('Face Tinting Layers', wbRStructSK([0], 'Layer', [ wbStructSK(TETI, [1], 'Index', [ wbInteger('Data Type', itU16, wbEnum(['', 'Value/Color', 'Value'])), wbInteger('Index', itU16, wbTintLayerToStr, wbStrToInt) ]), //wbByteArray(TEND, 'Data') wbStruct(TEND, 'Data', [ wbInteger('Value', itU8, wbDiv(100)), wbByteColors('Color'), wbInteger('Template Color Index', itS16) ], cpNormal, True, nil, 1) ], []) ), wbStruct(MRSV, 'Body Morph Region Values', [ wbFloat('Head'), wbFloat('Upper Torso'), wbFloat('Arms'), wbFloat('Lower Torso'), wbFloat('Legs') ]), // reported to cause issues when sorted wbRArrayS('Face Morphs', wbRStructSK([0], 'Face Morph', [ wbInteger(FMRI, 'Index', itU32, wbFaceMorphToStr, wbHexStrToInt), //wbArray(FMRS, 'Unknown', wbFloat('Unknown')) wbStruct(FMRS, 'Values', [ wbFloat('Position - X'), wbFloat('Position - Y'), wbFloat('Position - Z'), wbFloat('Rotation - X'), wbFloat('Rotation - Y'), wbFloat('Rotation - Z'), wbFloat('Scale'), wbByteArray('Unknown') ]) ], []) ), wbFloat(FMIN, 'Facial Morph Intensity'), wbATTX ], False, nil, cpNormal, False, wbNPCAfterLoad, wbNPCAfterSet); wbPKDTSpecificFlagsUnused := False; wbPKDTFlags := wbFlags([ {0x00000001} 'Offers Services', {0x00000002} 'Unknown 2', {0x00000004} 'Must complete', {0x00000008} 'Maintain Speed at Goal', {0x00000010} 'Treat As Player Follower', {0x00000020} 'Unknown 6', {0x00000040} 'Unlock doors at package start', {0x00000080} 'Unlock doors at package end', {0x00000100} 'Request Block Idles', {0x00000200} 'Continue if PC Near', {0x00000400} 'Once per day', {0x00000800} 'Unknown 12', {0x00001000} 'Skip Load Into Furniture', {0x00002000} 'Preferred Speed', {0x00004000} 'Unknown 15', {0x00008000} 'Unknown 16', {0x00010000} 'Unknown 17', {0x00020000} 'Always Sneak', {0x00040000} 'Allow Swimming', {0x00080000} 'Unknown 20', {0x00100000} 'Ignore Combat', {0x00200000} 'Weapons Unequipped', {0x00400000} 'Unknown 23', {0x00800000} 'Weapon Drawn', {0x01000000} 'Unknown 25', {0x02000000} 'Unknown 26', {0x04000000} 'Unknown 27', {0x08000000} 'No Combat Alert', {0x10000000} 'Unknown 29', {0x20000000} 'Wear Sleep Outfit', {0x40000000} 'Unknown 31', {0x80000000} 'Unknown 32' ], [29]); wbPKDTInterruptFlags := wbFlags([ {0x0001} 'Hellos to player', {0x0002} 'Random conversations', {0x0004} 'Observe combat behavior', {0x0008} 'Greet corpse behavior', {0x0010} 'Reaction to player actions', {0x0020} 'Friendly fire comments', {0x0040} 'Aggro Radius Behavior', {0x0080} 'Allow Idle Chatter', {0x0100} 'Unknown 9', {0x0200} 'World Interactions', {0x0400} 'Off For Important Scene', {0x0800} 'Unknown 12', {0x1000} 'Unknown 13', {0x2000} 'Unknown 14', {0x4000} 'Unknown 15', {0x8000} 'Unknown 16' ]); end; procedure DefineFO4n; function wbTintTemplateGroups(const aName: string): IwbSubRecordArrayDef; begin Result := wbRStructs(aName, 'Group', [ wbLString(TTGP, 'Group Name', 0, cpTranslate), wbRStructs('Options', 'Option', [ wbStruct(TETI, 'Index', [ wbByteArray('Unknown', 2), wbInteger('Index', itU16) ]), wbLString(TTGP, 'Name', 0, cpTranslate), wbUnknown(TTEF), wbCTDAs, wbRArray('Textures', wbString(TTET, 'Texture')), wbUnknown(TTEB), wbArray(TTEC, 'Template Colors', wbStruct('Template Color', [ wbFormIDCk('Color', [CLFM]), wbFloat('Alpha'), wbInteger('Template Index', itU16), wbByteArray('Unknown', 4) ])), wbFloat(TTED, 'Unknown') ], []), wbByteArray(TTGE, 'Group End', 4) ], []); end; function wbMorphGroups(const aName: string): IwbSubRecordArrayDef; begin Result := wbRArray(aName, wbRStruct('Morph Group', [ wbString(MPGN, 'Name'), wbInteger(MPPC, 'Count', itU32, nil, cpBenign), wbRArray('Morph Presets', wbRStruct('Morph Preset', [ wbInteger(MPPI, 'Index', itU32, wbIntToHexStr, wbHexStrToInt), wbLString(MPPN, 'Name', 0, cpTranslate), wbString(MPPM, 'Unknown'), wbFormIDCk(MPPT, 'Texture', [TXST]), wbUnknown(MPPF) ], []), cpNormal, False, nil, wbMorphPresetsAfterSet ), wbUnknown(MPPK), wbUnknown(MPGS) ], []) ); end; function wbFaceMorphs(const aName: string): IwbSubRecordArrayDef; begin Result := wbRArray(aName, wbRStruct('Face Morph', [ wbInteger(FMRI, 'Index', itU32, wbIntToHexStr, wbHexStrToInt), wbLString(FMRN, 'Name') ], []) ); end; begin wbUNAMs := wbRArray('Data Inputs', wbRStruct('Data Input', [ wbInteger(UNAM, 'Index', itS8), wbString(BNAM, 'Name'), wbInteger(PNAM, 'Flags', itU32, wbFlags([ 'Public' ])) ], [])); wbRecord(PACK, 'Package', [ wbEDID, wbVMADFragmentedPACK, wbStruct(PKDT, 'Pack Data', [ wbInteger('General Flags', itU32, wbPKDTFlags), wbInteger('Type', itU8, wbEnum ([], [ 18, 'Package', 19, 'Package Template' ])), wbInteger('Interrupt Override', itU8, wbEnum([ {0} 'None', {1} 'Spectator', {2} 'ObserveDead', {3} 'GuardWarn', {4} 'Combat', {5} 'Command Travel', {6} 'Command Activate', {7} 'Leave Workstation' ])), wbInteger('Preferred Speed', itU8, wbEnum([ 'Walk', 'Jog', 'Run', 'Fast Walk' ])), wbByteArray('Unknown', 1), wbInteger('Interrupt Flags', itU16, wbPKDTInterruptFlags), wbByteArray('Unknown', 2) ], cpNormal, True), wbStruct(PSDT, 'Schedule', [ wbInteger('Month', itS8), wbInteger('Day of week', itS8, wbEnum([ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Weekdays', 'Weekends', 'Monday, Wednesday, Friday', 'Tuesday, Thursday' ], [ -1, 'Any' ])), wbInteger('Date', itU8), wbInteger('Hour', itS8), wbInteger('Minute', itS8), wbByteArray('Unused', 3, cpIgnore), wbInteger('Duration (minutes)', itS32) ], cpNormal, True), wbCTDAs, wbRStruct('Idle Animations', [ wbInteger(IDLF, 'Flags', itU8, wbEnum([], [ 0, 'Unknown', 8, 'Random', 9, 'Run in Sequence', 12, 'Random, Do Once', 13, 'Run in Sequence, Do Once' ]), cpNormal, True), wbInteger(IDLC, 'Animation Count', itU8, nil, cpBenign), wbFloat(IDLT, 'Idle Timer Setting', cpNormal, True), wbArray(IDLA, 'Animations', wbFormIDCk('Animation', [IDLE]), 0, nil, wbIDLAsAfterSet, cpNormal, True), wbByteArray(IDLB, 'Unknown', 4, cpIgnore) ], [], cpNormal, False, nil, False, nil {cannot be totally removed , wbAnimationsAfterSet}), wbFormIDCk(CNAM, 'Combat Style', [CSTY]), wbFormIDCk(QNAM, 'Owner Quest', [QUST]), wbStruct(PKCU, 'Counter', [ wbInteger('Data Input Count', itU32), wbFormIDCk('Package Template', [PACK, NULL]), wbInteger('Version Counter (autoincremented)', itU32) ], cpNormal, True), wbRStruct('Package Data', [ wbRArray('Data Input Values', wbRStruct('Value', [ wbString(ANAM, 'Type'), wbUnion(CNAM, 'Value', wbPubPackCNAMDecider, [ {0} wbByteArray('Unknown'), {1} wbInteger('Bool', itU8, wbBoolEnum), {2} wbInteger('Integer', itU32), {3} wbFloat('Float') ]), wbUnknown(BNAM), wbPDTOs, wbPLDT, wbStruct(PTDA, 'Target', [wbTargetData]), wbUnknown(TPIC) ], [], cpNormal, False)), wbUNAMs ], []), wbByteArray(XNAM, 'Marker'), wbRStruct('Procedure Tree', [ wbRArray('Branches', wbRStruct('Branch', [ wbString(ANAM, 'Branch Type'), wbCITC, wbCTDAsCount, wbStruct(PRCB, 'Root', [ wbInteger('Branch Count', itU32), wbInteger('Flags', itU32, wbFlags([ 'Repeat when Complete', 'Unknown 1' ])) ]), wbString(PNAM, 'Procedure Type'), wbInteger(FNAM, 'Flags', itU32, wbFlags(['Success Completes Package'])), wbRArray('Data Input Indexes', wbInteger(PKC2, 'Index', itU8)), {>>> PFO2 should be single, there is only 1 PACK [00095F46] in Skyrim.esm with 2xPFO2 <<<} wbRArray('Flags Override', wbStruct(PFO2, 'Data', [ wbInteger('Set General Flags', itU32, wbPKDTFlags), wbInteger('Clear General Flags', itU32, wbPKDTFlags), wbInteger('Set Interrupt Flags', itU16, wbPKDTInterruptFlags), wbInteger('Clear Interrupt Flags', itU16, wbPKDTInterruptFlags), wbInteger('Preferred Speed Override', itU8, wbEnum([ 'Walk', 'Jog', 'Run', 'Fast Walk' ])), wbByteArray('Unknown', 3) ]) ), wbRArray('Unknown', wbUnknown(PFOR), cpIgnore) ], [], cpNormal, False, nil, False, nil, wbConditionsAfterSet)) ], []), wbUNAMs, wbRStruct('OnBegin', [ wbEmpty(POBA, 'OnBegin Marker', cpNormal, True), wbFormIDCk(INAM, 'Idle', [IDLE, NULL], False, cpNormal, True), wbPDTOs ], []), wbRStruct('OnEnd', [ wbEmpty(POEA, 'OnEnd Marker', cpNormal, True), wbFormIDCk(INAM, 'Idle', [IDLE, NULL], False, cpNormal, True), wbPDTOs ], []), wbRStruct('OnChange', [ wbEmpty(POCA, 'OnChange Marker', cpNormal, True), wbFormIDCk(INAM, 'Idle', [IDLE, NULL], False, cpNormal, True), wbPDTOs ], []) ], False, nil, cpNormal, False, nil {wbPACKAfterLoad}); wbQUSTAliasFlags := wbInteger(FNAM, 'Flags', itU32, wbFlags([ {0x00000001} 'Reserves Location/Reference', {0x00000002} 'Optional', {0x00000004} 'Quest Object', {0x00000008} 'Allow Reuse in Quest', {0x00000010} 'Allow Dead', {0x00000020} 'Matching Ref - In Loaded Area', {0x00000040} 'Essential', {0x00000080} 'Allow Disabled', {0x00000100} 'Stores Text', {0x00000200} 'Allow Reserved', {0x00000400} 'Protected', {0x00000800} 'Forced by Aliases', {0x00001000} 'Allow Destroyed', {0x00002000} 'Matching Ref - Closest', {0x00004000} 'Uses Stored Text', {0x00008000} 'Initially Disabled', {0x00010000} 'Allow Cleared', {0x00020000} 'Clear Names When Removed', {0x00040000} 'Matching Ref - Actors Only', {0x00080000} 'Create Ref - Temp', {0x00100000} 'External Alias - Linked', {0x00200000} 'No Pickpocket', {0x00400000} 'Can Apply Data To Non-Aliased Refs', {0x00800000} 'Is Companion', {0x01000000} 'Optional All Scenes' ])); wbRecord(QUST, 'Quest', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00004000} 14, 'Partial Form' // Allows the Record to inherit some subrecords from its master ])), [ wbEDID, wbVMADFragmentedQUST, wbFULL, wbStruct(DNAM, 'General', [ wbInteger('Flags', itU16, wbFlags([ {0x0001} 'Start Game Enabled', {0x0002} 'Unknown 2', {0x0004} 'Add Idle Topic To Hello', {0x0008} 'Allow repeated stages', {0x0010} 'Unknown 5', {0x0020} 'Unknown 6', {0x0040} 'Unknown 7', {0x0080} 'Unknown 8', {0x0100} 'Run Once', {0x0200} 'Exclude from dialogue export', {0x0400} 'Warn on alias fill failure', {0x0800} 'Unknown 12', {0x1000} 'Unknown 13' ])), wbInteger('Priority', itU8), wbInteger('Form Version', itU8, nil, cpIgnore), wbByteArray('Unknown', 4), wbInteger('Type', itU32, wbEnum([ {0} 'None', {1} 'Main Quest', {2} 'Brotherhood of Steel', {3} 'Institute', {4} 'Minutemen', {5} 'Railroad', {6} 'Miscellaneous', {7} 'Side Quests', {8} 'DLC01', {9} 'DLC02', {10} 'DLC03', {11} 'DLC04', {12} 'DLC05', {13} 'DLC06', {14} 'DLC07' ])) ]), wbString(ENAM, 'Event', 4), wbFormIDCk(LNAM, 'Location', [LCTN]), wbFormIDCk(XNAM, 'Quest Completion XP', [GLOB]), wbRArray('Text Display Globals', wbFormIDCk(QTGL, 'Global', [GLOB])), wbFLTR, wbRStruct('Quest Dialogue Conditions', [wbCTDAs], [], cpNormal, False), wbEmpty(NEXT, 'Marker'), wbCTDAs, {>>> Unknown, doesn't show up in CK <<<} wbRArrayS('Stages', wbRStructSK([0], 'Stage', [ wbStructSK(INDX, [0], 'Stage Index', [ wbInteger('Stage Index', itU16), wbInteger('Flags', itU8, wbFlags([ {0x01} 'Unknown 1', {0x02} 'Run On Start', {0x04} 'Run On Stop', {0x08} 'Keep Instance Data From Here On' ])), wbInteger('Unknown', itU8) ]), wbRArray('Log Entries', wbRStruct('Log Entry', [ wbInteger(QSDT, 'Stage Flags', itU8, wbFlags([ {0x01} 'Complete Quest', {0x02} 'Fail Quest' ])), wbCTDAs, wbString(NAM2, 'Note'), wbLString(CNAM, 'Log Entry', 0, cpTranslate), wbFormIDCk(NAM0, 'Next Quest', [QUST]) ], [])) ], [])), wbRArray('Objectives', wbRStruct('Objective', [ wbInteger(QOBJ, 'Objective Index', itU16), wbInteger(FNAM, 'Flags', itU32, wbFlags([ {0x01} 'ORed With Previous', {0x02} 'No Stats Tracking' ])), wbLString(NNAM, 'Display Text', 0, cpTranslate, True), wbRArray('Targets', wbRStruct('Target', [ wbStruct(QSTA, 'Target', [ wbInteger('Alias', itS32, wbQuestAliasToStr, wbStrToAlias), wbInteger('Flags', itU32, wbFlags([ {0x01} 'Compass Marker Ignores Locks', {0x02} 'Hostile', {0x04} 'Use Straight Line Pathing' ])), wbFormIDCk('Keyword', [KYWD, NULL]) ]), wbCTDAs ], [])) ], [])), wbByteArray(ANAM, 'Aliases Marker', 4), wbRArray('Aliases', wbRUnion('Alias', [ // Reference Alias wbRStruct('Alias', [ wbInteger(ALST, 'Reference Alias ID', itU32), wbString(ALID, 'Alias Name'), wbQUSTAliasFlags, wbInteger(ALFI, 'Force Into Alias When Filled', itS32, wbQuestAliasToStr, wbStrToAlias), //wbFormIDCk(ALFL, 'Specific Location', [LCTN]), wbFormID(ALFR, 'Forced Reference'), wbFormIDCk(ALUA, 'Unique Actor', [NPC_]), wbRStruct('Location Alias Reference', [ wbInteger(ALFA, 'Alias', itS32, wbQuestAliasToStr, wbStrToAlias), wbFormIDCk(KNAM, 'Keyword', [KYWD]), wbFormIDCk(ALRT, 'Ref Type', [LCRT]) ], []), wbRStruct('External Alias Reference', [ wbFormIDCk(ALEQ, 'Quest', [QUST]), wbInteger(ALEA, 'Alias', itS32, wbQuestExternalAliasToStr, wbStrToAlias) ], []), wbRStruct('Create Reference to Object', [ wbFormID(ALCO, 'Object'), wbStruct(ALCA, 'Alias', [ wbInteger('Alias', itS16, wbQuestAliasToStr, wbStrToAlias), wbInteger('Create', itU16, wbEnum([] ,[ $0000, 'At', $8000, 'In' ])) ]), wbInteger(ALCL, 'Level', itU32, wbEnum([ 'Easy', 'Medium', 'Hard', 'Very Hard', 'None' ])) ], []), wbRStruct('Find Matching Reference Near Alias', [ wbInteger(ALNA, 'Alias', itS32, wbQuestAliasToStr, wbStrToAlias), wbInteger(ALNT, 'Type', itU32, wbEnum([ 'Linked From', 'Linked Ref' ])) ], []), wbRStruct('Find Matching Reference From Event', [ wbString(ALFE, 'From Event', 4), wbByteArray(ALFD, 'Event Data') ], []), wbInteger(ALCC, 'Closest To Alias', itS32, wbQuestAliasToStr, wbStrToAlias), wbCTDAs, wbKSIZ, wbKWDAs, wbCOCT, wbCNTOs, wbFormIDCk(SPOR, 'Spectator override package list', [FLST], False, cpNormal, False), wbFormIDCk(OCOR, 'Observe dead body override package list', [FLST], False, cpNormal, False), wbFormIDCk(GWOR, 'Guard warn override package list', [FLST], False, cpNormal, False), wbFormIDCk(ECOR, 'Combat override package list', [FLST], False, cpNormal, False), wbArray(ALLA, 'Linked Aliases', wbStruct('Linked Alias', [ wbFormIDCk('Keyword', [KYWD, NULL]), wbInteger('Alias', itS32, wbQuestAliasToStr, wbStrToAlias) ])), wbFormIDCk(ALDN, 'Display Name', [MESG]), wbFormIDCk(ALFV, 'Forced Voice', [VTYP]), wbFormIDCk(ALDI, 'Death Item', [LVLI]), wbRArrayS('Alias Spells', wbFormIDCk(ALSP, 'Spell', [SPEL])), wbRArrayS('Alias Factions', wbFormIDCk(ALFC, 'Faction', [FACT])), wbRArray('Alias Package Data', wbFormIDCk(ALPC, 'Package', [PACK])), wbFormIDCk(VTCK, 'Voice Types', [NPC_, FACT, FLST, VTYP, NULL]), wbEmpty(ALED, 'Alias End', cpNormal, True) ], [], cpNormal, False, nil, False, nil, wbContainerAfterSet), // Location Alias wbRStruct('Alias', [ wbInteger(ALLS, 'Location Alias ID', itU32), wbString(ALID, 'Alias Name'), wbQUSTAliasFlags, wbInteger(ALFI, 'Force Into Alias When Filled', itS32, wbQuestAliasToStr, wbStrToAlias), wbFormIDCk(ALFL, 'Specific Location', [LCTN]), wbRStruct('Reference Alias Location', [ wbInteger(ALFA, 'Alias', itS32, wbQuestAliasToStr, wbStrToAlias), wbFormIDCk(KNAM, 'Keyword', [KYWD]) ], []), wbRStruct('External Alias Location', [ wbFormIDCk(ALEQ, 'Quest', [QUST]), wbInteger(ALEA, 'Alias', itS32, wbQuestExternalAliasToStr, wbStrToAlias) ], []), wbRStruct('Find Matching Location From Event', [ wbString(ALFE, 'From Event', 4), wbByteArray(ALFD, 'Event Data') ], []), wbCTDAs, wbInteger(ALCC, 'Closest To Alias', itS32, wbQuestAliasToStr, wbStrToAlias), wbEmpty(ALED, 'Alias End', cpNormal, True) ], []), // Ref Collection Alias wbRStruct('Alias', [ wbInteger(ALCS, 'Collection Alias ID', itU32), wbInteger(ALMI, 'Max Initial Fill Count', itU8) ], []) ], []) ), wbString(NNAM, 'Description', 0, cpTranslate, False), wbFormIDCk(GNAM, 'Quest Group', [KYWD]), wbString(SNAM, 'SWF File') ]); wbBodyPartIndexEnum := wbEnum([ 'Body Texture' ]); wbPhonemeTargets := wbStruct(PHWT, 'Phoneme Target Weight', [ wbFloat('Aah / LipBigAah'), wbFloat('BigAah / LipDST'), wbFloat('BMP / LipEee'), wbFloat('ChJsh / LipFV'), wbFloat('DST / LipK'), wbFloat('Eee / LipL'), wbFloat('Eh / LipR'), wbFloat('FV / LipTh'), wbFloat('I'), wbFloat('K'), wbFloat('N'), wbFloat('Oh'), wbFloat('OohQ'), wbFloat('R'), wbFloat('TH'), wbFloat('W'), wbUnknown ], cpNormal, False, nil, 1); // only a single value in HandyRace wbPHWT := wbRStruct('FaceFX Phonemes', [ wbRStruct('IY', [wbPhonemeTargets], []), wbRStruct('IH', [wbPhonemeTargets], []), wbRStruct('EH', [wbPhonemeTargets], []), wbRStruct('EY', [wbPhonemeTargets], []), wbRStruct('AE', [wbPhonemeTargets], []), wbRStruct('AA', [wbPhonemeTargets], []), wbRStruct('AW', [wbPhonemeTargets], []), wbRStruct('AY', [wbPhonemeTargets], []), wbRStruct('AH', [wbPhonemeTargets], []), wbRStruct('AO', [wbPhonemeTargets], []), wbRStruct('OY', [wbPhonemeTargets], []), wbRStruct('OW', [wbPhonemeTargets], []), wbRStruct('UH', [wbPhonemeTargets], []), wbRStruct('UW', [wbPhonemeTargets], []), wbRStruct('ER', [wbPhonemeTargets], []), wbRStruct('AX', [wbPhonemeTargets], []), wbRStruct('S', [wbPhonemeTargets], []), wbRStruct('SH', [wbPhonemeTargets], []), wbRStruct('Z', [wbPhonemeTargets], []), wbRStruct('ZH', [wbPhonemeTargets], []), wbRStruct('F', [wbPhonemeTargets], []), wbRStruct('TH', [wbPhonemeTargets], []), wbRStruct('V', [wbPhonemeTargets], []), wbRStruct('DH', [wbPhonemeTargets], []), wbRStruct('M', [wbPhonemeTargets], []), wbRStruct('N', [wbPhonemeTargets], []), wbRStruct('NG', [wbPhonemeTargets], []), wbRStruct('L', [wbPhonemeTargets], []), wbRStruct('R', [wbPhonemeTargets], []), wbRStruct('W', [wbPhonemeTargets], []), wbRStruct('Y', [wbPhonemeTargets], []), wbRStruct('HH', [wbPhonemeTargets], []), wbRStruct('B', [wbPhonemeTargets], []), wbRStruct('D', [wbPhonemeTargets], []), wbRStruct('JH', [wbPhonemeTargets], []), wbRStruct('G', [wbPhonemeTargets], []), wbRStruct('P', [wbPhonemeTargets], []), wbRStruct('T', [wbPhonemeTargets], []), wbRStruct('K', [wbPhonemeTargets], []), wbRStruct('CH', [wbPhonemeTargets], []), wbRStruct('SIL', [wbPhonemeTargets], []), wbRStruct('SHOTSIL', [wbPhonemeTargets], []), wbRStruct('FLAP', [wbPhonemeTargets], []) ], []); wbHeadPart := wbRStructSK([0], 'Head Part', [ wbInteger(INDX, 'Head Part Number', itU32), wbFormIDCk(HEAD, 'Head', [HDPT, NULL]) ], []); wbRaceRBPC := wbArray(RBPC, 'Biped Object Conditions', wbUnion('Slot 30+', wbFormVer78Decider, [ wbInteger('Slot 30+', itU32), wbFormIDCk('Slot 30+', [AVIF, NULL]) ]) ); // since version 78: array of pair of AVIF FormID, before array of AVIF index. Similar to DamageType (and MGEF also somehow). {wbUnion(RBPC, 'Biped Object Conditions', wbFormVer78Decider, [ wbArray('Biped Object Conditions', wbInteger('Condition AV', itU32)), wbArray('Biped Object Conditions', wbStruct('Condition AV', [ wbFormIDck('AVIF 1', [AVIF, NULL]), wbFormIDck('AVIF 2', [AVIF, NULL]) ])) ]);} wbRecord(RACE, 'Race', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00080000} 19, 'Unknown 19' ])), [ wbEDID, wbFormIDCk(STCP, 'Sound', [STAG]), wbFULL, wbDESCReq, wbSPCT, wbSPLOs, wbFormIDCk(WNAM, 'Skin', [ARMO, NULL]), wbBOD2, wbKSIZ, wbKWDAs, wbPRPS, wbAPPR, wbStruct(DATA, 'Data', [ wbFloat('Male Height'), wbFloat('Female Height'), wbStruct('Male Default Weight', [ wbFloat('Thin'), wbFloat('Muscular'), wbFloat('Fat') ]), wbStruct('Female Default Weight', [ wbFloat('Thin'), wbFloat('Muscular'), wbFloat('Fat') ]), wbInteger('Flags', itU32, wbFlags([ {0x00000001} 'Playable', {0x00000002} 'FaceGen Head', {0x00000004} 'Child', {0x00000008} 'Tilt Front/Back', {0x00000010} 'Tilt Left/Right', {0x00000020} 'No Shadow', {0x00000040} 'Swims', {0x00000080} 'Flies', {0x00000100} 'Walks', {0x00000200} 'Immobile', {0x00000400} 'Not Pushable', {0x00000800} 'No Combat In Water', {0x00001000} 'No Rotating to Head-Track', {0x00002000} 'Don''t Show Blood Spray', {0x00004000} 'Don''t Show Blood Decal', {0x00008000} 'Uses Head Track Anims', {0x00010000} 'Spells Align w/Magic Node', {0x00020000} 'Use World Raycasts For FootIK', {0x00040000} 'Allow Ragdoll Collision', {0x00080000} 'Regen HP In Combat', {0x00100000} 'Can''t Open Doors', {0x00200000} 'Allow PC Dialogue', {0x00400000} 'No Knockdowns', {0x00800000} 'Allow Pickpocket', {0x01000000} 'Always Use Proxy Controller', {0x02000000} 'Don''t Show Weapon Blood', {0x04000000} 'Overlay Head Part List', {>>>Only one can be active<<<} {0x08000000} 'Override Head Part List', {>>>Only one can be active<<<} {0x10000000} 'Can Pickup Items', {0x20000000} 'Allow Multiple Membrane Shaders', {0x40000000} 'Can Dual Wield', {0x80000000} 'Avoids Roads' ])), wbFloat('Acceleration Rate'), wbFloat('Deceleration Rate'), wbInteger('Size', itU32, wbEnum([ 'Small', 'Medium', 'Large', 'Extra Large' ])), wbByteArray('Unknown', 8), wbFloat('Injured Health Pct'), wbInteger('Shield Biped Object', itS32, wbBipedObjectEnum), wbInteger('Beard Biped Object', itS32, wbBipedObjectEnum), wbInteger('Body Biped Object', itS32, wbBipedObjectEnum), wbFloat('Aim Angle Tolerance'), wbFloat('Flight Radius'), wbFloat('Angular Acceleration Rate'), wbFloat('Angular Tolerance'), wbInteger('Flags 2', itU32, wbFlags([ {0x00000001} 'Use Advanced Avoidance', {0x00000002} 'Non-Hostile', {0x00000004} 'Floats', {0x00000008} 'Unknown 3', {0x00000010} 'Unknown 4', {0x00000020} 'Head Axis Bit 0', {0x00000040} 'Head Axis Bit 1', {0x00000080} 'Can Melee When Knocked Down', {0x00000100} 'Use Idle Chatter During Combat', {0x00000200} 'Ungendered', {0x00000400} 'Can Move When Knocked Down', {0x00000800} 'Use Large Actor Pathing', {0x00001000} 'Use Subsegmented Damage', {0x00002000} 'Flight - Defer Kill', {0x00004000} 'Unknown 14', {0x00008000} 'Flight - Allow Procedural Crash Land', {0x00010000} 'Disable Weapon Culling', {0x00020000} 'Use Optimal Speeds', {0x00040000} 'Has Facial Rig', {0x00080000} 'Can Use Crippled Limbs', {0x00100000} 'Use Quadruped Controller', {0x00200000} 'Low Priority Pushable', {0x00400000} 'Cannot Use Playable Items' ])), wbByteArray('Unknown', 36), wbInteger('Pipboy Biped Object', itS32, wbBipedObjectEnum), wbInteger('XP Value', itS16), wbFloat('Severable - Debris Scale'), wbInteger('Severable - Debris Count', itU8), wbInteger('Severable - Decal Count', itU8), wbFloat('Explodable - Debris Scale'), wbInteger('Explodable - Debris Count', itU8), wbInteger('Explodable - Decal Count', itU8), wbFormIDCk('Severable - Explosion', [EXPL, NULL]), wbFormIDCk('Severable - Debris', [DEBR, NULL]), wbFormIDCk('Severable - Impact DataSet', [IPDS, NULL]), wbFormIDCk('Explodable - Explosion', [EXPL, NULL]), wbFormIDCk('Explodable - Debris', [DEBR, NULL]), wbFormIDCk('Explodable - Impact DataSet', [IPDS, NULL]), wbFloat('OnCripple - Debris Scale'), wbInteger('OnCripple - Debris Count', itU8), wbInteger('OnCripple - Decal Count', itU8), wbFormIDCk('OnCripple - Explosion', [EXPL, NULL]), wbFormIDCk('OnCripple - Debris', [DEBR, NULL]), wbFormIDCk('OnCripple - Impact DataSet', [IPDS, NULL]), wbFormIDCk('Explodable - Subsegment Explosion', [EXPL, NULL]), wbFloat('Orientation Limits - Pitch'), wbFloat('Orientation Limits - Roll') ], cpNormal, True), wbEmpty(MNAM, 'Male Marker'), wbString(ANAM, 'Male Skeletal Model'), wbMODT, wbEmpty(FNAM, 'Female Marker'), wbString(ANAM, 'Female Skeletal Model'), wbMODT, wbEmpty(NAM2, 'Marker NAM2 #1'), wbRArrayS('Movement Type Names', wbString(MTNM, 'Name')), wbArray(VTCK, 'Voices', wbFormIDCk('Voice', [VTYP]), ['Male', 'Female'], cpNormal, True), //wbArray(DNAM, 'Decapitate Armors', wbFormIDCk('Decapitate Armor', [NULL, ARMO]), ['Male', 'Female'], cpNormal, False), wbArray(HCLF, 'Default Hair Colors', wbFormIDCk('Default Hair Color', [NULL, CLFM]), ['Male', 'Female'], cpNormal, False), wbInteger(TINL, 'Total Number of Tints in List', itU16, nil, nil, cpNormal, False), {>>> Needs Count Updated <<<} wbFloat(PNAM, 'FaceGen - Main clamp', cpNormal, True), wbFloat(UNAM, 'FaceGen - Face clamp', cpNormal, True), wbFormIDCk(ATKR, 'Attack Race', [RACE], False, cpNormal, False), wbRArrayS('Attacks', wbAttackData), wbRStruct('Body Data', [ wbEmpty(NAM1, 'Body Data Marker', cpNormal, True), wbRStruct('Male Body Data', [ wbEmpty(MNAM, 'Male Data Marker'), wbRArrayS('Parts', wbRStructSK([0], 'Part', [ wbInteger(INDX, 'Index', itU32, wbBodyPartIndexEnum), wbMODL ], []), cpNormal, True) ], [], cpNormal, True), wbRStruct('Female Body Data', [ wbEmpty(FNAM, 'Female Data Marker', cpNormal, True), wbRArrayS('Parts', wbRStructSK([0], 'Part', [ wbInteger(INDX, 'Index', itU32, wbBodyPartIndexEnum), wbMODL ], []), cpNormal, True) ], [], cpNormal, True) ], [], cpNormal, True), wbFormIDCk(GNAM, 'Body Part Data', [BPTD]), wbEmpty(NAM2, 'Marker NAM2 #2', cpNormal), wbEmpty(NAM3, 'Marker NAM3 #3', cpNormal, True), wbRStruct('Male Behavior Graph', [ wbEmpty(MNAM, 'Male Data Marker'), wbMODL ], [], cpNormal, True), wbRStruct('Female Behavior Graph', [ wbEmpty(FNAM, 'Female Data Marker', cpNormal, True), wbMODL ], [], cpNormal, True), wbFormIDCk(NAM4, 'Impact Material Type', [MATT]), wbFormIDCk(NAM5, 'Impact Data Set', [IPDS]), wbFormIDCk(NAM7, 'Dismember Blood Art', [ARTO]), wbFormIDCk(CNAM, 'Meat Cap TextureSet', [TXST]), wbFormIDCk(NAM2, 'Collar TextureSet', [TXST]), wbFormIDCk(ONAM, 'Sound - Open Corpse', [SNDR]), wbFormIDCk(LNAM, 'Sound - Close Corpse', [SNDR]), wbRArray('Biped Object Names', wbString(NAME, 'Name')), wbRaceRBPC, wbRArrayS('Movement Data Overrides', wbRStructSK([0], 'Override', [ wbFormIDCk(MTYP, 'Movement Type', [MOVT]), wbSPED ], [])), wbInteger(VNAM, 'Equipment Flags', itU32, wbEquipType), wbRArray('Equip Slots', wbRStruct('Equip Slot', [ wbFormIDCk(QNAM, 'Equip Slot', [EQUP]), wbString(ZNAM, 'Node') ], []) ), wbFormIDCk(UNWP, 'Unarmed Weapon', [WEAP]), wbRArray('Phoneme Target Names', wbString(PHTN, 'Name')), wbPHWT, wbFormIDCk(WKMV, 'Base Movement Defaults - Default', [MOVT]), wbFormIDCk(SWMV, 'Base Movement Defaults - Swim', [MOVT]), wbFormIDCk(FLMV, 'Base Movement Defaults - Fly', [MOVT]), wbFormIDCk(SNMV, 'Base Movement Defaults - Sneak', [MOVT]), // Male head wbEmpty(NAM0, 'Head Data Marker'), wbEmpty(MNAM, 'Male Data Marker'), wbStruct(NNAM, 'Male Neck Fat Adjustments Scale', [ wbByteArray('Unknown', 4), wbFloat('X'), wbFloat('Y') ]), wbRArrayS('Male Head Parts', wbHeadPart), wbRArray('Male Race Presets', wbFormIDCk(RPRM, 'Preset NPC', [NPC_, NULL])), wbRArray('Male Hair Colors', wbFormIDCk(AHCM, 'Hair Color', [CLFM, NULL])), wbRArrayS('Male Face Details', wbFormIDCk(FTSM, 'Texture Set', [TXST, NULL])), wbFormIDCk(DFTM, 'Male Default Face Texture', [TXST]), wbTintTemplateGroups('Male Tint Layers'), wbMorphGroups('Male Morph Groups'), wbFaceMorphs('Male Face Morphs'), wbString(WMAP, 'Male Wrinkle Map Path'), // Female head wbEmpty(NAM0, 'Head Data Marker'), wbEmpty(FNAM, 'Female Data Marker'), wbStruct(NNAM, 'Female Neck Fat Adjustments Scale', [ wbByteArray('Unknown', 4), wbFloat('X'), wbFloat('Y') ]), wbRArrayS('Female Head Parts', wbHeadPart), wbRArray('Female Race Presets', wbFormIDCk(RPRF, 'Preset NPC', [NPC_, NULL])), wbRArray('Female Hair Colors', wbFormIDCk(AHCF, 'Hair Color', [CLFM, NULL])), wbRArrayS('Female Face Details', wbFormIDCk(FTSF, 'Texture Set', [TXST, NULL])), wbFormIDCk(DFTF, 'Female Default Face Texture', [TXST]), wbTintTemplateGroups('Female Tint Layers'), wbMorphGroups('Female Morph Groups'), wbFaceMorphs('Female Face Morphs'), wbString(WMAP, 'Female Wrinkle Map Path'), wbFormIDCk(NAM8, 'Morph Race', [RACE]), wbFormIDCk(RNAM, 'Armor Race', [RACE]), wbFormIDCk(SRAC, 'Subgraph Template Race', [RACE]), wbFormIDCk(SADD, 'Subgraph Additive Race', [RACE]), wbRArray('Subgraph Data', wbRStruct('Data', [ wbString(SGNM, 'Behaviour Graph'), wbRArray('Actor Keywords', wbFormIDCk(SAKD, 'Keyword', [KYWD])), wbRArray('Target Keywords', wbFormIDCk(STKD, 'Keyword', [KYWD])), wbRArray('Animation Paths', wbString(SAPT, 'Path'), cpNormal, True), // Values greater than $10000 sets a bool. Reading this "closes" the current record. wbStruct(SRAF, 'Flags', [ wbInteger('Role', itU16, wbEnum([ {0} 'MT', {1} 'Weapon', {2} 'Furniture', {3} 'Idle', {4} 'Pipboy' ])), wbInteger('Perspective', itU16, wbEnum([ '3rd', '1st' ])) ], cpNormal, True) ], [], cpNormal, False, nil, True) ), wbFloat(PTOP, 'Idle Chatter Time Min'), wbFloat(NTOP, 'Idle Chatter Time Max'), wbRArray('Morph Values', wbRStruct('Value', [ wbInteger(MSID, 'Index', itU32, wbIntToHexStr, wbHexStrToInt), wbString(MSM0, 'Min Name'), wbString(MSM1, 'Max Name') ], []) ), wbUnknown(MLSI), wbString(HNAM, 'Hair Color Lookup Texture'), wbString(HLTX, 'Hair Color Extended Lookup Texture'), wbFormIDCk(QSTI, 'Dialogue Quest', [QUST]), wbBSMPSequence ], False, nil, cpNormal, False, nil, wbRACEAfterSet); wbRecord(REFR, 'Placed Object', wbFormaterUnion(wbREFRRecordFlagsDecider, [ wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000010} 4, 'Ground Piece', {0x00000100} 8, 'LOD Respects Enable State', {0x00000400} 10, 'Persistent', {0x00000800} 11, 'Initially Disabled', {0x00010000} 16, 'Is Full LOD', {0x04000000} 26, 'Filter (Collision Geometry)', {0x08000000} 27, 'Bounding Box (Collision Geometry)', {0x10000000} 28, 'Reflected By Auto Water', {0x40000000} 30, 'Ground', {0x80000000} 31, 'Multibound' ], True, True)), {ACTI STAT SCOL TREE} wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000010} 4, 'Ground Piece', {0x00000100} 8, 'LOD Respects Enable State', {0x00000200} 9, 'Hidden From Local Map', {0x00000400} 10, 'Persistent', {0x00000800} 11, 'Initially Disabled', {0x00008000} 15, 'Visible when distant', {0x00010000} 16, 'Is Full LOD', {0x04000000} 26, 'Filter (Collision Geometry)', {0x08000000} 27, 'Bounding Box (Collision Geometry)', {0x10000000} 28, 'Reflected By Auto Water', {0x20000000} 29, 'Don''t Havok Settle', {0x40000000} 30, 'No Respawn', {0x80000000} 31, 'Multibound' ], True, True)), {CONT TERM} wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000010} 4, 'Ground Piece', {0x00000400} 10, 'Persistent', {0x00000800} 11, 'Initially Disabled', {0x00010000} 16, 'Is Full LOD', {0x02000000} 25, 'No AI Acquire', {0x04000000} 26, 'Filter (Collision Geometry)', {0x08000000} 27, 'Bounding Box (Collision Geometry)', {0x20000000} 29, 'Don''t Havok Settle', {0x40000000} 30, 'Ground', {0x80000000} 31, 'Multibound' ], True, True)), {DOOR} wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000004} 2, 'Minimal Use Door', {0x00000040} 6, 'Hidden From Local Map', {0x00000100} 8, 'Inaccessible', {0x00000400} 10, 'Persistent', {0x00000800} 11, 'Initially Disabled', {0x00010000} 16, 'Is Full LOD', {0x04000000} 26, 'Filter (Collision Geometry)', {0x08000000} 27, 'Bounding Box (Collision Geometry)', {0x20000000} 29, 'Don''t Havok Settle', {0x40000000} 30, 'No Respawn', {0x80000000} 31, 'Multibound' ], True, True)), {LIGH} wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000100} 8, 'Doesn''t Light Water', {0x00000200} 9, 'Casts Shadows', {0x00000400} 10, 'Persistent', {0x00000800} 11, 'Initially Disabled', {0x00010000} 16, 'Never Fades', {0x00020000} 17, 'Doesn''t Light Landscape', {0x02000000} 25, 'No AI Acquire', {0x10000000} 28, 'Reflected By Auto Water', {0x20000000} 29, 'Don''t Havok Settle', {0x40000000} 30, 'No Respawn', {0x80000000} 31, 'Multibound' ], True, True)), {MSTT} wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000010} 4, 'Ground Piece', {0x00000200} 9, 'Motion Blur', {0x00000400} 10, 'Persistent', {0x00000800} 11, 'Initially Disabled', {0x00010000} 16, 'Is Full LOD', {0x04000000} 26, 'Filter (Collision Geometry)', {0x08000000} 27, 'Bounding Box (Collision Geometry)', {0x10000000} 28, 'Reflected By Auto Water', {0x20000000} 29, 'Don''t Havok Settle', {0x40000000} 30, 'No Respawn', {0x80000000} 31, 'Multibound' ], True, True)), {ADDN} wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000400} 10, 'Persistent', {0x00000800} 11, 'Initially Disabled', {0x00010000} 16, 'Is Full LOD', {0x10000000} 28, 'Reflected By Auto Water', {0x20000000} 29, 'Don''t Havok Settle', {0x40000000} 30, 'No Respawn', {0x80000000} 31, 'Multibound' ], True, True)), {ALCH BOOK SCRL AMMO ARMO INGR KEYM MISC FURN WEAP} wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000010} 4, 'Ground Piece', {0x00000400} 10, 'Persistent', {0x00000800} 11, 'Initially Disabled', {0x00010000} 16, 'Is Full LOD', {0x02000000} 25, 'No AI Acquire', {0x10000000} 28, 'Reflected By Auto Water', {0x20000000} 29, 'Don''t Havok Settle', {0x40000000} 30, 'No Respawn', {0x80000000} 31, 'Multibound' ], True, True)) ]), [ wbEDID, wbVMAD, wbFormIDCk(NAME, 'Base', sigBaseObjects, False, cpNormal, True), {--- Bound Contents ---} {--- Bound Data ---} wbStruct(XMBO, 'Bound Half Extents', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), {--- Primitive ---} wbStruct(XPRM, 'Primitive', [ wbStruct('Bounds', [ wbFloat('X', cpNormal, True, 2, 4), wbFloat('Y', cpNormal, True, 2, 4), wbFloat('Z', cpNormal, True, 2, 4) ]), wbFloatColors('Color'), wbFloat('Unknown'), wbInteger('Type', itU32, wbEnum([ 'None', 'Box', 'Sphere', 'Plane', 'Line', 'Ellipsoid' ])) ]), wbArray(XPOD, 'Portal Data', wbStruct('References', [ wbFormIDCk('Origin', [REFR, NULL]), wbFormIDCk('Destination', [REFR, NULL]) ])), wbUnknown(XORD), wbStruct(XOCP, 'Occlusion Plane Data', [ wbStruct('Size', [ wbFloat('Width', cpNormal, False, 2), wbFloat('Height', cpNormal, False, 2) ]), wbStruct('Position', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), wbStruct('Rotation (Quaternion?)', [ wbFloat('q1'), wbFloat('q2'), wbFloat('q3'), wbFloat('q4') ]) ]), wbRStruct('Bound Data', [ wbStruct(XRMR, 'Header', [ wbInteger('Linked Rooms Count', itU8), wbInteger('Flags', itU8, wbFlags([ 'Unknown 1', 'Unknown 2', 'Unknown 3', 'Unknown 4', 'Unknown 5', 'Unknown 6', 'Has Image Space', 'Has Lighting Template' ])), wbByteArray('Unknown', 2) ]), wbFormIDCk(LNAM, 'Lighting Template', [LGTM]), wbFormIDCk(INAM, 'Image Space', [IMGS]), wbRArrayS('Linked Rooms', wbFormIDCk(XLRM, 'Linked Room', [REFR]) ) ], []), wbEmpty(XMBP, 'MultiBound Primitive Marker', cpIgnore), {--- Ragdoll ---} wbXRGD, wbXRGB, wbFloat(XRDS, 'Radius'), wbXSCL, {--- Emittance ---} wbFormIDCk(XEMI, 'Emittance', [LIGH, REGN]), wbStruct(XLIG, 'Light Data', [ wbFloat('FOV 90+/-'), wbFloat('Fade 1.0+/-'), wbFloat('End Distance Cap'), wbFloat('Shadow Depth Bias'), wbFloat('Near Clip'), wbFloat('Volumetric Intensity') ], cpNormal, False, nil, 4), wbStruct(XALP, 'Alpha', [ wbInteger('Cutoff', itU8), wbInteger('Base', itU8) ]), {--- Teleport ---} wbStruct(XTEL, 'Teleport Destination', [ wbFormIDCk('Door', [REFR], True), wbPosRot, wbInteger('Flags', itU32, wbFlags([ 'No Alarm', 'No Load Screen', 'Relative Position' ])), wbFormIDCk('Transition Interior', [CELL, NULL]) ]), wbFormIDCk(XTNM, 'Teleport Loc Name', [MESG]), {--- MultiBound ---} wbFormIDCk(XMBR, 'MultiBound Reference', [REFR]), {--- Placed Water ---} wbUnknown(XWCN), wbStruct(XWCU, 'Water Velocity', [ wbFloat('X Offset'), wbFloat('Y Offset'), wbFloat('Z Offset'), wbByteArray('Unknown', 4), wbFloat('X Angle'), wbFloat('Y Angle'), wbFloat('Z Angle'), wbByteArray('Unknown', 0) ]), wbFormIDCk(XASP, 'Acoustic Restriction', [REFR]), wbEmpty(XATP, 'Activation Point'), wbInteger(XAMC, 'Ammo Count', itU32), wbEmpty(XLKT, 'Linked Ref Transient'), wbFormIDCk(XLYR, 'Layer', [LAYR]), wbFormIDCk(XMSP, 'Material Swap', [MSWP]), wbFormIDCk(XRFG, 'Reference Group', [RFGP]), wbStruct(XRDO, 'Radio', [ wbFloat('Frequency'), wbFloat('Min Weak Distance'), wbFloat('Max Weak Distance'), wbInteger('Flags', itU32, wbFlags(['Ignores Distance Checks'])) ]), wbStruct(XBSD, 'Spline', [ wbFloat('Slack'), wbFloat('Thickness'), wbFloat('Unknown'), // not shown in editor wbFloat('Unknown'), // not shown in editor wbFloat('Unknown'), // not shown in editor wbInteger('Wind - Detached End', itU8, wbBoolEnum), wbByteArray('Unused', 0) // junk data? ], cpNormal, False, nil, 5), wbStruct(XPDD, 'Projected Decal', [ wbFloat('Width Scale'), wbFloat('Height Scale') // "Uses Box Primitive" checkbox does the following: // 1. "Rounds" above floats (probably due to floating point precision) [DIRTY EDITS?] // 2. "Rounds" DATA\Position floats (probably due to floating point precision) [DIRTY EDITS?] // 3. Creates an XPRM subrecord (this is the "Primitive" tab in the editor) // 4. Fills out Primitive data: // 4a. Primitive type: Box // 4b. Collision layer: XTRI subrecord = 15 // 4c. Bounds (XYZ): 256.0, 215.0, 256.0 // 4d. Color (RGB): 0, 128, 128 // 4e. Unknown: 0.4 ]), wbFormIDCk(XSPC, 'Spawn Container', [REFR]), {--- Activate Parents ---} wbRStruct('Activate Parents', [ wbInteger(XAPD, 'Flags', itU8, wbFlags([ 'Parent Activate Only' ], True)), wbRArrayS('Activate Parent Refs', wbStructSK(XAPR, [0], 'Activate Parent Ref', [ wbFormIDCk('Reference', sigReferences), wbFloat('Delay') ]) ) ], []), wbFormIDCk(XLIB, 'Leveled Item Base Object', [LVLI]), wbXLCM, wbFormIDCk(XLCN, 'Persistent Location', [LCTN]), {>>> COLL form Index value <<<} wbInteger(XTRI, 'Collision Layer', itU32), {--- Lock ---} wbStruct(XLOC, 'Lock Data', [ wbInteger('Level', itU8, wbEnum([], [ 0, 'None', 1, 'Novice 1', 25, 'Novice 25', 50, 'Advanced', 75, 'Expert', 100, 'Master', 253, 'Requires Terminal', 251, 'Barred', 252, 'Chained', 254, 'Inaccessible', 255, 'Requires Key' ])), wbByteArray('Unused', 3, cpIgnore), wbFormIDCkNoReach('Key', [KEYM, NULL]), wbInteger('Flags', itU8, wbFlags(['', '', 'Leveled Lock'])), wbByteArray('Unused', 3, cpIgnore), wbUnknown ], cpNormal, False, nil, 4), wbFormIDCk(XEZN, 'Encounter Zone', [ECZN]), {--- Generated Data ---} wbStruct(XNDP, 'Navigation Door Link', [ wbFormIDCk('Navigation Mesh', [NAVM]), wbInteger('Teleport Marker Triangle', itS16, wbREFRNavmeshTriangleToStr, wbStringToInt), wbByteArray('Unused', 2, cpIgnore) ]), wbFormIDCk(XLRL, 'Location Reference', [LCRT, LCTN, NULL], False, cpBenignIfAdded), wbArray(XLRT, 'Location Ref Type', wbFormIDCk('Ref', [LCRT, NULL])), wbEmpty(XIS2, 'Ignored by Sandbox'), {--- Ownership ---} wbXOWN, wbXRNK, wbInteger(XCNT, 'Item Count', itS32), wbInteger(XHLT, 'Health %', itU32), wbXESP, wbRArray('Linked References', wbStruct(XLKR, 'Linked Reference', [ wbFormIDCk('Keyword/Ref', [KYWD, PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA, NULL]), wbFormIDCk('Ref', sigReferences) ], cpNormal, False, nil, 1)), wbRArray('Patrol', wbRStruct('Data', [ wbFloat(XPRD, 'Idle Time', cpNormal, True), wbEmpty(XPPA, 'Patrol Script Marker', cpNormal, True), wbFormIDCk(INAM, 'Idle', [IDLE, NULL], False, cpNormal, True), wbPDTOs ], [])), {--- Flags ---} wbInteger(XACT, 'Action Flag', itU32, wbFlags([ 'Use Default', 'Activate', 'Open', 'Open by Default' ])), wbFloat(XHTW, 'Head-Tracking Weight'), wbFloat(XFVC, 'Favor Cost'), wbEmpty(ONAM, 'Open by Default'), {--- Map Data ---} wbRStruct('Map Marker', [ wbEmpty(XMRK, 'Map Marker Data'), wbInteger(FNAM, 'Map Flags', itU8, wbFlags([ {0x01} 'Visible', {0x02} 'Can Travel To', {0x04} '"Show All" Hidden', {0x08} 'Use Location Name' ]), cpNormal, True), wbFULLReq, wbStruct(TNAM, '', [ wbInteger('Type', itU8, wbEnum([], [ {Vv = Verified Vanilla} {No new map markers for Automatron or Workshop} 0, 'Cave', {Vv} 1, 'City', {Vv} 2, 'Diamond City', {Vv} 3, 'Encampment', {Vv} 4, 'Factory / Industrial Site', {Vv} 5, 'Gov''t Building / Monument', {Vv} 6, 'Metro Station', {Vv} 7, 'Military Base', {Vv} 8, 'Natural Landmark', {Vv} 9, 'Office / Civic Building', {Vv} 10, 'Ruins - Town', {Vv} 11, 'Ruins - Urban', {Vv} 12, 'Sanctuary', {Vv} 13, 'Settlement', {Vv} 14, 'Sewer / Utility Tunnels', {Vv} 15, 'Vault', {Vv} 16, 'Airfield', {Vv} 17, 'Bunker Hill', {Vv} 18, 'Camper', {Vv} 19, 'Car', {Vv} 20, 'Church', {Vv} 21, 'Country Club', {Vv} 22, 'Custom House', {Vv} 23, 'Drive-In', {Vv} 24, 'Elevated Highway', {Vv} 25, 'Faneuil Hall', {Vv} 26, 'Farm', {Vv} 27, 'Filling Station', {Vv} 28, 'Forested', {Vv} 29, 'Goodneighbor', {Vv} 30, 'Graveyard', {Vv} 31, 'Hospital', {Vv} 32, 'Industrial Dome', {Vv} 33, 'Industrial Stacks', {Vv} 34, 'Institute', {Vv} 35, 'Irish Pride', {Vv} 36, 'Junkyard', {Vv} 37, 'Observatory', {Vv} 38, 'Pier', {Vv} 39, 'Pond / Lake', {Vv} 40, 'Quarry', {Vv} 41, 'Radioactive Area', {Vv} 42, 'Radio Tower', {Vv} 43, 'Salem', {Vv} 44, 'School', {Vv} 45, 'Shipwreck', {Vv} 46, 'Submarine', {Vv} 47, 'Swan Pond', {Vv} 48, 'Synth Head', {Vv} 49, 'Town', {Vv} 50, 'Brotherhood of Steel', {Vv} 51, 'Brownstone Townhouse', {Vv} 52, 'Bunker', {Vv} 53, 'Castle', {Vv} 54, 'Skyscraper', {Vv} 55, 'Libertalia', {Vv} 56, 'Low-Rise Building', {Vv} 57, 'Minutemen', {Vv} 58, 'Police Station', {Vv} 59, 'Prydwen', {Vv} 60, 'Railroad - Faction', {Vv} 61, 'Railroad', {Vv} 62, 'Satellite', {Vv} 63, 'Sentinel', {Vv} 64, 'USS Constitution', {Vv} 65, 'Mechanist LairRaider settlementVassal settlementPotential Vassal settlement', {Vv} 66, 'Custom 66', 67, 'Custom 67', 68, 'Custom 68', 69, 'Custom 69', 70, 'Custom 70', 71, 'Custom 71', 72, 'Custom 72', 73, 'Custom 73', 74, 'Custom 74', 75, 'Custom 75', 76, 'Custom 76', 77, 'Custom 77', 78, 'Custom 78', 79, 'Custom 79', 80, 'Custom 80', 81, 'Custom 81', 82, 'Custom 82', 83, 'Custom 83', 84, 'Custom 84', 85, 'Custom 85', 86, 'Custom 86', 87, 'Custom 87', 88, 'Custom 88', 89, 'Custom 89', 90, 'Custom 90', 91, 'Custom 91', 92, 'Custom 92', 93, 'Custom 93', 94, 'Custom 94', 95, 'Custom 95', 96, 'Custom 96', 97, 'Custom 97', 98, 'Custom 98', 99, 'Custom 99' ])), wbByteArray('Unused', 1) ], cpNormal, True) ], []), {--- Attach reference ---} wbFormIDCk(XATR, 'Attach Ref', [REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA]), wbRArray('Spline Connection', wbStruct(XPLK, 'Link', [ wbFormIDCk('Ref', [REFR, ACHR]), wbUnknown // always 00 00 00 00 so far in DLCWorkshop03.esm ])), wbRStruct('Power Grid', [ wbInteger(XWPG, 'Count', itU32), wbRArray('Connections', wbStruct(XWPN, 'Connection', [ wbFormIDCk('Node 1', [REFR, ACHR, NULL]), wbFormIDCk('Node 2', [REFR, ACHR, NULL]), wbFormIDCk('Line', [REFR, NULL]) // BNDS ref ])) ], []), wbUnknown(XCVR), wbUnknown(XCVL), wbFormIDCk(XCZR, 'Unknown', sigReferences), wbUnknown(XCZA), wbFormIDCk(XCZC, 'Unknown', [CELL, NULL]), wbXLOD, // not seen in FO4 vanilla files wbDataPosRot, wbString(MNAM, 'Comments') ], True, wbPlacedAddInfo, cpNormal, False, wbREFRAfterLoad); wbRecord(REGN, 'Region', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000040} 6, 'Border Region' ])), [ wbEDID, wbStruct(RCLR, 'Map Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unknown', 1) ], cpNormal, True), wbFormIDCkNoReach(WNAM, 'Worldspace', [WRLD]), wbRArray('Region Areas', wbRStruct('Region Area', [ wbInteger(RPLI, 'Edge Fall-off', itU32), wbArray(RPLD, 'Region Point List Data', wbStruct('Point', [ wbFloat('X'), wbFloat('Y') ]), 0, wbRPLDAfterLoad), wbUnknown(ANAM) ], [])), wbRArrayS('Region Data Entries', wbRStructSK([0], 'Region Data Entry', [ {always starts with an RDAT} wbStructSK(RDAT, [0], 'Data Header', [ wbInteger('Type', itU32, wbEnum([ {0} 'Unknown 0', {1} 'Unknown 1', {2} 'Objects', {3} 'Weather', {4} 'Map', {5} 'Land', {6} 'Grass', {7} 'Sound', {8} 'Imposter', {9} 'Unknown 10', {10}'Unknown 11', {11}'Unknown 12', {12}'Unknown 13', {13}'Unknown 14', {14}'Unknown 15', {15}'Unknown 16' ])), wbInteger('Flags', itU8, wbFlags([ 'Override' ])), wbInteger('Priority', itU8), wbByteArray('Unknown') ], cpNormal, True), {--- Icon ---} wbICON, {--- Sound ---} wbFormIDCk(RDMO, 'Music', [MUSC], False, cpNormal, False, wbREGNSoundDontShow), wbArrayS(RDSA, 'Sounds', wbStructSK([0], 'Sound', [ wbFormIDCk('Sound', [SNDR, NULL]), wbInteger('Flags', itU32, wbFlags([ {0x00000001} 'Pleasant', {0x00000002} 'Cloudy', {0x00000004} 'Rainy', {0x00000008} 'Snowy' ])), wbFloat('Chance') ]), 0, cpNormal, False, nil, nil, wbREGNSoundDontShow), {--- Map ---} wbLString(RDMP, 'Map Name', 0, cpTranslate, False, wbREGNMapDontShow), {followed by one of these: } {--- Objects ---} wbArray(RDOT, 'Objects', wbStruct('Object', [ wbFormIDCk('Object', [TREE, FLOR, STAT, LTEX, MSTT]), wbInteger('Parent Index', itU16, wbHideFFFF), wbByteArray('Unknown', 2), wbFloat('Density'), wbInteger('Clustering', itU8), wbInteger('Min Slope', itU8), wbInteger('Max Slope', itU8), wbInteger('Flags', itU8, wbFlags([ {0}'Conform to slope', {1}'Paint Vertices', {2}'Size Variance +/-', {3}'X +/-', {4}'Y +/-', {5}'Z +/-', {6}'Tree', {7}'Huge Rock' ])), wbInteger('Radius wrt Parent', itU16), wbInteger('Radius', itU16), wbFloat('Min Height'), wbFloat('Max Height'), wbFloat('Sink'), wbFloat('Sink Variance'), wbFloat('Size Variance'), wbStruct('Angle Variance', [ wbInteger('X', itU16), wbInteger('Y', itU16), wbInteger('Z', itU16) ]), wbByteArray('Unknown', 2), wbByteArray('Unknown', 4) ]), 0, nil, nil, cpNormal, False, wbREGNObjectsDontShow), {--- Grass ---} wbArrayS(RDGS, 'Grasses', wbStructSK([0], 'Grass', [ wbFormIDCk('Grass', [GRAS]), wbByteArray('Unknown',4) ]), 0, cpNormal, False, nil, nil, wbREGNGrassDontShow), {--- Weather ---} wbArrayS(RDWT, 'Weather Types', wbStructSK([0], 'Weather Type', [ wbFormIDCk('Weather', [WTHR]), wbInteger('Chance', itU32), wbFormIDCk('Global', [GLOB, NULL]) ]), 0, cpNormal, False, nil, nil, wbREGNWeatherDontShow), wbFloat(RLDM, 'LOD Display Distance Multiplier'), wbFloat(ANAM, 'Occlusion Accuracy Dist') ], [])) ], True); wbRecord(SOUN, 'Sound Marker', [ wbEDID, wbOBNDReq, wbFormIDCk(SDSC, 'Sound Descriptor', [SNDR, NULL]), wbStruct(REPT, 'Repeat', [ wbFloat('Min Time'), wbFloat('Max Time'), wbInteger('Stackable', itU8, wbBoolEnum) ], cpNormal, False, nil, 2) ]); wbSPIT := wbStruct(SPIT, 'Data', [ wbInteger('Base Cost', itU32), wbInteger('Flags', itU32, wbFlags([ {0x00000001} 'Manual Cost Calc', {0x00000002} 'Unknown 2', {0x00000004} 'Unknown 3', {0x00000008} 'Unknown 4', {0x00000010} 'Unknown 5', {0x00000020} 'Unknown 6', {0x00000040} 'Unknown 7', {0x00000080} 'Unknown 8', {0x00000100} 'Unknown 9', {0x00000200} 'Unknown 10', {0x00000400} 'Unknown 11', {0x00000800} 'Unknown 12', {0x00001000} 'Unknown 13', {0x00002000} 'Unknown 14', {0x00004000} 'Unknown 15', {0x00008000} 'Unknown 16', {0x00010000} 'Unknown 17', {0x00020000} 'PC Start Spell', {0x00040000} 'Instant Cast', {0x00080000} 'Area Effect Ignores LOS', {0x00100000} 'Ignore Resistance', {0x00200000} 'No Absorb/Reflect', {0x00400000} 'Unknown 23', {0x00800000} 'No Dual Cast Modification', {0x01000000} 'Unknown 25', {0x02000000} 'Unknown 26', {0x04000000} 'Unknown 27', {0x08000000} 'Unknown 28', {0x10000000} 'Unknown 29', {0x20000000} 'Unknown 30', {0x40000000} 'Unknown 31', {0x80000000} 'Unknown 32' ])), wbInteger('Type', itU32, wbEnum([ {0} 'Spell', {1} 'Disease', {2} 'Power', {3} 'Lesser Power', {4} 'Ability', {5} 'Poison', {6} 'Unknown 6', {7} 'Unknown 7', {8} 'Unknown 8', {9} 'Unknown 9', {10} 'Addiction', {11} 'Voice' ])), wbFloat('Charge Time'), wbInteger('Cast Type', itU32, wbCastEnum), wbInteger('Target Type', itU32, wbTargetEnum), wbFloat('Cast Duration'), wbFloat('Range'), wbFormIDCk('Casting Perk', [NULL, PERK]) ], cpNormal, True); wbRecord(SPEL, 'Spell', [ wbEDID, wbOBNDReq, wbFULL, wbKSIZ, wbKWDAs, wbETYP, wbDESCReq, wbSPIT, wbEffectsReq ], False, nil, cpNormal, False, nil, wbKeywordsAfterSet); {wbRecord(SCRL, 'Scroll', [ wbEDID ]);} wbRecord(STAT, 'Static', wbFlags(wbRecordFlagsFlags, [ {0x00000001} { 0} '', {0x00000002} { 1} '', {0x00000004} { 2} 'Heading Marker', {0x00000008} { 3} '', {0x00000010} { 4} 'Non Occluder', {0x00000020} { 5} 'Deleted', {0x00000040} { 6} 'Has Tree LOD', // Used in Fallout 4 ? {0x00000080} { 7} 'Add-On LOD Object', {0x00000100} { 8} '', {0x00000200} { 9} 'Hidden From Local Map', {0x00000400} {10} 'Headtrack Marker', {0x00000800} {11} 'Used as Platform', {0x00001000} {12} '', {0x00002000} {13} 'Pack-In Use Only', {0x00004000} {14} '', {0x00008000} {15} 'Has Distant LOD', {0x00010000} {16} '', {0x00020000} {17} 'Uses HD LOD Texture', {0x00040000} {18} '', {0x00080000} {19} 'Has Currents', {0x00100000} {20} '', {0x00200000} {21} '', {0x00400000} {22} '', {0x00800000} {23} 'Is Marker', {0x01000000} {24} '', {0x02000000} {25} 'Obstacle', {0x04000000} {26} 'NavMesh Generation - Filter', {0x08000000} {27} 'NavMesh Generation - Bounding Box', {0x10000000} {28} 'Show In World Map (Sky Cell Only)', {0x20000000} {29} '', {0x40000000} {30} 'NavMesh Generation - Ground', {0x80000000} {31} '' ]), [ wbEDID, wbVMAD, wbOBNDReq, wbPTRN, wbFTYP, wbMODL, wbPRPS, wbFULL, wbStruct(DNAM, 'Direction Material', [ wbFloat('Max Angle (30-120)'), wbFormIDCk('Material', [MATO, NULL]), wbFloat('Leaf Amplitude'), wbFloat('Leaf Frequency') ], cpNormal, True, nil, 2), wbNVNM, wbArray(MNAM, 'Distant LOD', wbStruct('LOD', [ {>>> Contains null-terminated mesh filename followed by random data up to 260 bytes <<<} wbString(True, 'Mesh', 260) //wbByteArray('Mesh', 260, cpIgnore) ]), [ 'Level 0', 'Level 1', 'Level 2', 'Level 3' ], cpNormal, False ) ], True); // unordered, NVNM can be before or after MNAM wbRecord(TES4, 'Main File Header', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000001} 0, 'ESM', {0x00000080} 7, 'Localized' ], False), True), [ wbStruct(HEDR, 'Header', [ wbFloat('Version'), wbInteger('Number of Records', itU32), wbInteger('Next Object ID', itU32) ], cpNormal, True), wbByteArray(OFST, 'Unknown', 0, cpIgnore), // If possible then ignored by the runtime. Neither from the CK wbByteArray(DELE, 'Unknown', 0, cpIgnore), // If possible then ignored by the runtime. Neither from the CK wbString(CNAM, 'Author', 0, cpTranslate, True), wbString(SNAM, 'Description', 0, cpTranslate), wbRArray('Master Files', wbRStruct('Master File', [ wbString(MAST, 'Filename', 0, cpNormal, True), // wbInteger(DATA, 'Filesize', itU64, nil, nil, cpIgnore, True) // Should be set by CK but usually null wbByteArray(DATA, 'Unknown', 8, cpIgnore, True) ], [ONAM])), wbArray(ONAM, 'Overridden Forms', // Valid in CK wbFormIDCk('Form', [ACHR, LAND, NAVM, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA, DLBR, DIAL, INFO, SCEN]), 0, nil, nil, cpNormal, False{, wbTES4ONAMDontShow}), wbByteArray(SCRN, 'Screenshot'), // If possible then ignored by the runtime. Neither from the CK wbRArray('Transient Types (CK only)', wbStruct(TNAM, 'Transient Type', [ wbInteger('FormType', itU32), // seen TESTopic 78 (array of DIAL) and BGSScene 126 (array of SCEN) wbArray('Unknown', wbFormID('Unknown')) ])), // Ignored by the runtime wbInteger(INTV, 'Unknown', itU32), // Ignored by the runtime, 4 bytes loaded in CK wbInteger(INCC, 'Unknown', itU32) // Size of some array of 12 bytes elements ], True, nil, cpNormal, True, wbRemoveOFST); end; procedure DefineFO4o; begin wbRecord(TREE, 'Tree', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00008000} 15, 'Has Distant LOD' ])), [ wbEDID, wbVMAD, wbOBNDReq, wbMODL, wbFormIDCK(PFIG, 'Ingredient', sigBaseObjects), wbFormIDCK(SNAM, 'Harvest Sound', [SNDR, NULL]), wbStruct(PFPC, 'Ingredient Production', [ wbInteger('Spring', itU8), wbInteger('Summer', itU8), wbInteger('Fall', itU8), wbInteger('Winter', itU8) ]), wbFULL, wbStruct(CNAM, 'Tree Data', [ wbFloat('Trunk Flexibility'), wbFloat('Branch Flexibility'), //wbByteArray('Unknown', 32), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Leaf Amplitude'), wbFloat('Leaf Frequency') ], cpNormal, True) ]); wbRecord(FLOR, 'Flora', [ wbEDID, wbVMAD, wbOBNDReq, wbPTRN, wbFULLReq, wbMODL, wbDEST, wbKSIZ, wbKWDAs, wbPRPS, wbUnknown(PNAM), wbATTX, wbLString(RNAM, 'Activate Text Override', 0, cpTranslate), wbUnknown(FNAM), wbFormIDCk(PFIG, 'Ingredient', sigBaseObjects), wbFormIDCK(SNAM, 'Harvest Sound', [SNDR]), wbStruct(PFPC, 'Ingredient Production', [ wbInteger('Spring', itU8), wbInteger('Summer ', itU8), wbInteger('Fall', itU8), wbInteger('Winter', itU8) ], cpNormal, True) ], False, nil, cpNormal, False, nil, wbKeywordsAfterSet); wbRecord(WATR, 'Water', [ wbEDID, wbFULL, wbInteger(ANAM, 'Opacity (unused)', itU8), wbInteger(FNAM, 'Flags', itU8, wbFlags([ {0x01} 'Dangerous', {0x02} 'Unknown 1', {0x04} 'Directional Sound' ]), cpNormal, True), wbFormIDCk(TNAM, 'Material (unused)', [MATT]), wbFormIDCk(SNAM, 'Open Sound', [SNDR, NULL]), wbFormIDCk(XNAM, 'Consume Spell', [SPEL]), wbFormIDCk(YNAM, 'Contact Spell', [SPEL]), wbFormIDCk(INAM, 'Image Space', [IMGS]), wbByteArray(DATA, 'Unused', 0), wbStruct(DNAM, 'Visual Data', [ wbStruct('Fog Properties', [ wbFloat('Depth Amount'), wbByteColors('Shallow Color'), wbByteColors('Deep Color'), wbFloat('Color Shallow Range'), wbFloat('Color Deep Range'), wbFloat('Shallow Alpha'), wbFloat('Deep Alpha'), wbFloat('Alpha Shallow Range'), wbFloat('Alpha Deep Range'), wbByteColors('Underwater Color'), wbFloat('Underwater Fog Amount'), wbFloat('Underwater Near Fog'), wbFloat('Underwater Far Fog') ]), wbStruct('Physical Properties', [ wbFloat('Normal Magnitude'), wbFloat('Shallow Normal Falloff'), wbFloat('Deep Normal Falloff'), wbFloat('Reflectivity Amount'), wbFloat('Fresnel Amount'), wbFloat('Surface Effect Falloff'), wbStruct('Displacement Simulator', [ wbFloat('Force'), wbFloat('Velocity'), wbFloat('Falloff'), wbFloat('Dampener'), wbFloat('Starting Size') ]), wbByteColors('Reflection Color') ]), wbStruct('Specular Properties', [ wbFloat('Sun Specular Power'), wbFloat('Sun Specular Magnitude'), wbFloat('Sun Sparkle Power'), wbFloat('Sun Sparkle Magnitude'), wbFloat('Interior Specular Radius'), wbFloat('Interior Specular Brightness'), wbFloat('Interior Specular Power') ]), wbStruct('Noise Properties', [ wbFloat('Layer 1 - Wind Direction'), wbFloat('Layer 2 - Wind Direction'), wbFloat('Layer 3 - Wind Direction'), wbFloat('Layer 1 - Wind Speed'), wbFloat('Layer 2 - Wind Speed'), wbFloat('Layer 3 - Wind Speed'), wbFloat('Layer 1 - Amplitude Scale'), wbFloat('Layer 2 - Amplitude Scale'), wbFloat('Layer 3 - Amplitude Scale'), wbFloat('Layer 1 - UV Scale'), wbFloat('Layer 2 - UV Scale'), wbFloat('Layer 3 - UV Scale'), wbFloat('Layer 1 - Noise Falloff'), wbFloat('Layer 2 - Noise Falloff'), wbFloat('Layer 3 - Noise Falloff') ]), wbStruct('Silt Properties', [ wbFloat('Silt Amount'), wbByteColors('Light Color'), wbByteColors('Dark Color') ]), wbInteger('Screen Space Reflections', itU8, wbBoolEnum) ], cpNormal, True, nil, 4), wbByteArray(GNAM, 'Unused', 0), wbStruct(NAM0, 'Linear Velocity', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ], cpNormal, False), wbStruct(NAM1, 'Angular Velocity', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ], cpNormal, False), wbString(NAM2, 'Layer 1 Noise Texture'), wbString(NAM3, 'Layer 2 Noise Texture'), wbString(NAM4, 'Layer 3 Noise Texture') ]); wbRecord(WEAP, 'Weapon', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000004} 2, 'Non-Playable', {0x20000000} 30, 'High-Res 1st Person Only' ])), [ wbEDID, wbVMAD, wbOBNDReq, wbPTRN, wbFULL, wbMODL, wbICON, wbMICO, wbEITM, wbInteger(EAMT, 'Enchantment Amount', itU16), wbDEST, wbETYP, wbFormIDCk(BIDS, 'Block Bash Impact Data Set', [IPDS, NULL]), wbFormIDCk(BAMT, 'Alternate Block Material', [MATT, NULL]), wbYNAM, wbZNAM, wbKSIZ, wbKWDAs, wbDESC, wbFormIDCk(INRD, 'Instance Naming', [INNR]), wbAPPR, wbObjectTemplate, wbFormIDCk(NNAM, 'Embedded Weapon Mod', [OMOD]), wbRStruct('1st Person Model', [ wbString(MOD4, 'Model Filename'), wbByteArray(MO4T, 'Texture Files Hashes', 0, cpIgnore, false, false, wbNeverShow), wbMO4S, wbMO4C, wbMO4F ], []), wbStruct(DNAM, 'Data', [ wbFormIDCk('Ammo', [AMMO, NULL]), wbFloat('Speed'), wbFloat('Reload Speed'), wbFloat('Reach'), wbFloat('Min Range'), wbFloat('Max Range'), wbFloat('Attack Delay'), wbByteArray('Unknown', 4), wbFloat('Damage - OutOfRange Mult'), wbInteger('On Hit', itU32, wbHitBehaviourEnum), wbFormIDCk('Skill', [AVIF, NULL]), wbFormIDCk('Resist', [AVIF, NULL]), wbInteger('Flags', itU32, wbFlags([ {0x00000001} 'Player Only', {0x00000002} 'NPCs Use Ammo', {0x00000004} 'No Jam After Reload', {0x00000008} 'Charging Reload', {0x00000010} 'Minor Crime', {0x00000020} 'Fixed Range', {0x00000040} 'Not Used In Normal Combat', {0x00000080} 'Unknown 8', {0x00000100} 'Crit Effect - on Death', {0x00000200} 'Charging Attack', {0x00000400} 'Unknown 11', {0x00000800} 'Hold Input To Power', {0x00001000} 'Non Hostile', {0x00002000} 'Bound Weapon', {0x00004000} 'Ignores Normal Weapon Resistance', {0x00008000} 'Automatic', {0x00010000} 'Repeatable Single Fire', {0x00020000} 'Can''t Drop', {0x00040000} 'Hide Backpack', {0x00080000} 'Embedded Weapon', {0x00100000} 'Not Playable', {0x00200000} 'Has Scope', {0x00400000} 'Bolt Action', {0x00800000} 'Secondary Weapon', {0x01000000} 'Disable Shells', {0x02000000} 'Unknown 26', {0x04000000} 'Unknown 27', {0x08000000} 'Unknown 28', {0x10000000} 'Unknown 29', {0x20000000} 'Unknown 30', {0x40000000} 'Unknown 31', {0x80000000} 'Unknown 32' ])), wbInteger('Capacity', itU16), wbInteger('Animation Type', itU8, wbEnum([ 'HandToHandMelee', 'OneHandSword', 'OneHandDagger', 'OneHandAxe', 'OneHandMace', 'TwoHandSword', 'TwoHandAxe', 'Bow', 'Staff', 'Gun', 'Grenade', 'Mine' ])), wbFloat('Damage - Secondary'), wbFloat('Weight'), wbInteger('Value', itU32), wbInteger('Damage - Base', itU16), wbInteger('Sound Level', itU32, wbSoundLevelEnum), wbFormIDCk('Sound - Attack', [SNDR, NULL]), wbFormIDCk('Sound - Attack 2D', [SNDR, NULL]), wbFormIDCk('Sound - Attack Loop', [SNDR, NULL]), wbFormIDCk('Sound - Attack Fail', [SNDR, NULL]), wbFormIDCk('Sound - Idle', [SNDR, NULL]), wbFormIDCk('Sound - Equip Sound', [SNDR, NULL]), wbFormIDCk('Sound - UnEquip Sound', [SNDR, NULL]), wbFormIDCk('Sound - Fast Equip Sound', [SNDR, NULL]), wbInteger('Accuracy Bonus', itU8), wbFloat('Animation Attack Seconds'), wbByteArray('Unknown', 2), wbFloat('Action Point Cost'), wbFloat('Full Power Seconds'), wbFloat('Min Power Per Shot'), wbInteger('Stagger', itU32, wbStaggerEnum), wbByteArray('Unknown', 4) ]), wbStruct(FNAM, '', [ wbFloat('Animation Fire Seconds'), wbFloat('Rumble - Left Motor Strength'), wbFloat('Rumble - Right Motor Strength'), wbFloat('Rumble - Duration'), wbFloat('Animation Reload Seconds'), wbByteArray('Unknown', 4), wbFloat('Sighted Transition Seconds'), wbInteger('# Projectiles', itU8), wbFormIDCk('Override Projectile', [PROJ, NULL]), wbInteger('Pattern', itU32, wbEnum([ 'Constant', 'Square', 'Triangle', 'Sawtooth' ])), wbInteger('Rumble - Peroid (ms)', itU32) ]), wbStruct(CRDT, 'Critical Data', [ wbFloat('Crit Damage Mult'), wbFloat('Crit Charge Bonus'), wbFormIDCk('Crit Effect', [SPEL, NULL]) ]), wbFormIDCk(INAM, 'Impact Data Set', [IPDS]), wbFormIDCk(LNAM, 'NPC Add Ammo List', [LVLI]), wbFormIDCk(WAMD, 'Aim Model', [AMDL]), wbFormIDCk(WZMD, 'Zoom', [ZOOM]), wbFormIDCk(CNAM, 'Template', [WEAP]), wbStructs(DAMA, 'Damage Types', 'Damage Type', [ wbFormIDCk('Type', [DMGT]), wbInteger('Amount', itU32) ]), wbFLTR, wbInteger(MASE, 'Melee Speed', itU32, wbEnum([ 'Very Slow', 'Slow', 'Medium', 'Fast', 'Very Fast' ])) ], False, nil, cpNormal, False, nil{wbWEAPAfterLoad}, wbKeywordsAfterSet); wbRecord(WRLD, 'Worldspace', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00080000} 19, 'Can''t Wait' ])), [ wbEDID, wbRArray('Unused RNAM', wbUnknown(RNAM), cpIgnore, False{, wbNeverShow}), wbMaxHeightDataWRLD, wbFULL, wbStruct(WCTR, 'Fixed Dimensions Center Cell', [ wbInteger('X', itS16), wbInteger('Y', itS16) ]), wbFormIDCk(LTMP, 'Interior Lighting', [LGTM]), wbFormIDCk(XEZN, 'Encounter Zone', [ECZN, NULL]), wbFormIDCk(XLCN, 'Location', [LCTN, NULL]), wbRStruct('Parent', [ wbFormIDCk(WNAM, 'Worldspace', [WRLD]), wbStruct(PNAM, '', [ wbInteger('Flags', itU8, wbFlags([ {0x0001} 'Use Land Data', {0x0002} 'Use LOD Data', {0x0004} 'Don''t Use Map Data', {0x0008} 'Use Water Data', {0x0010} 'Use Climate Data', {0x0020} 'Use Image Space Data (unused)', {0x0040} 'Use Sky Cell' ], [5])), wbByteArray('Unknown', 1) ], cpNormal, True) ], []), wbFormIDCk(CNAM, 'Climate', [CLMT]), wbFormIDCk(NAM2, 'Water', [WATR]), wbFormIDCk(NAM3, 'LOD Water Type', [WATR]), wbFloat(NAM4, 'LOD Water Height'), wbStruct(DNAM, 'Land Data', [ wbFloat('Default Land Height'), wbFloat('Default Water Height') ]), wbString(ICON, 'Map Image'), wbRStruct('Cloud Model', [wbMODL], []), wbStruct(MNAM, 'Map Data', [ wbStruct('Usable Dimensions', [ wbInteger('X', itS32), wbInteger('Y', itS32) ]), wbStruct('Cell Coordinates', [ wbStruct('NW Cell', [ wbInteger('X', itS16), wbInteger('Y', itS16) ]), wbStruct('SE Cell', [ wbInteger('X', itS16), wbInteger('Y', itS16) ]) ]) ]), wbStruct(ONAM, 'World Map Offset Data', [ wbFloat('World Map Scale'), wbFloat('Cell X Offset'), wbFloat('Cell Y Offset'), wbFloat('Cell Z Offset') ], cpNormal, True), wbFloat(NAMA, 'Distant LOD Multiplier'), wbInteger(DATA, 'Flags', itU8, wbFlags([ {0x01} 'Small World', {0x02} 'Can''t Fast Travel', {0x04} 'Unknown 3', {0x08} 'No LOD Water', {0x10} 'No Landscape', {0x20} 'No Sky', {0x40} 'Fixed Dimensions', {0x80} 'No Grass' ]), cpNormal, True), {>>> Object Bounds doesn't show up in CK <<<} wbRStruct('Object Bounds', [ wbStruct(NAM0, 'Min', [ wbFloat('X', cpNormal, False, 1/4096), wbFloat('Y', cpNormal, False, 1/4096) ], cpIgnore, True), wbStruct(NAM9, 'Max', [ wbFloat('X', cpNormal, False, 1/4096), wbFloat('Y', cpNormal, False, 1/4096) ], cpIgnore, True) ], []), wbFormIDCk(ZNAM, 'Music', [MUSC]), wbString(NNAM, 'Canopy Shadow (unused)', 0, cpIgnore), wbString(XWEM, 'Water Environment Map'), wbString(TNAM, 'HD LOD Diffuse Texture'), wbString(UNAM, 'HD LOD Normal Texture'), wbRStruct('World Default Level Data', [ wbStruct(WLEV, 'Dimension', [ wbStruct('NW Cell', [ wbInteger('X', itS8), wbInteger('Y', itS8) ]), wbStruct('Size', [ wbInteger('Width', itU8), wbInteger('Height', itU8) ]) ]), wbByteArray(WLEV, 'Data') ], []), wbOFST, wbUnknown(CLSZ) ], False, nil, cpNormal, False, wbWRLDAfterLoad); wbRecord(WTHR, 'Weather', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000200} 9, 'Unknown 9' ])), [ wbEDID, wbString(_00_0TX, 'Cloud Texture Layer #0'), wbString(_10_0TX, 'Cloud Texture Layer #1'), wbString(_20_0TX, 'Cloud Texture Layer #2'), wbString(_30_0TX, 'Cloud Texture Layer #3'), wbString(_40_0TX, 'Cloud Texture Layer #4'), wbString(_50_0TX, 'Cloud Texture Layer #5'), wbString(_60_0TX, 'Cloud Texture Layer #6'), wbString(_70_0TX, 'Cloud Texture Layer #7'), wbString(_80_0TX, 'Cloud Texture Layer #8'), wbString(_90_0TX, 'Cloud Texture Layer #9'), wbString(_3A_0TX, 'Cloud Texture Layer #10'), wbString(_3B_0TX, 'Cloud Texture Layer #11'), wbString(_3C_0TX, 'Cloud Texture Layer #12'), wbString(_3D_0TX, 'Cloud Texture Layer #13'), wbString(_3E_0TX, 'Cloud Texture Layer #14'), wbString(_3F_0TX, 'Cloud Texture Layer #15'), wbString(_40h_0TX, 'Cloud Texture Layer #16'), wbString(A0TX, 'Cloud Texture Layer #17'), wbString(B0TX, 'Cloud Texture Layer #18'), wbString(C0TX, 'Cloud Texture Layer #19'), wbString(D0TX, 'Cloud Texture Layer #20'), wbString(E0TX, 'Cloud Texture Layer #21'), wbString(F0TX, 'Cloud Texture Layer #22'), wbString(G0TX, 'Cloud Texture Layer #23'), wbString(H0TX, 'Cloud Texture Layer #24'), wbString(I0TX, 'Cloud Texture Layer #25'), wbString(J0TX, 'Cloud Texture Layer #26'), wbString(K0TX, 'Cloud Texture Layer #27'), wbString(L0TX, 'Cloud Texture Layer #28'), wbUnknown(LNAM), wbFormIDCK(MNAM, 'Precipitation Type', [SPGD, NULL]), wbFormIDCK(NNAM, 'Visual Effect', [RFCT, NULL], False, cpNormal, True), wbByteArray(ONAM, 'Unused', 0, cpIgnore), wbRStruct('Cloud Speed', [ wbArray(RNAM, 'Y Speed', wbInteger('Layer', itU8, wbCloudSpeedToStr, wbCloudSpeedToInt)), wbArray(QNAM, 'X Speed', wbInteger('Layer', itU8, wbCloudSpeedToStr, wbCloudSpeedToInt)) ], []), wbArray(PNAM, 'Cloud Colors', wbWeatherColors('Layer')), wbArray(JNAM, 'Cloud Alphas', wbStruct('Layer', [ wbFloat('Sunrise'), wbFloat('Day'), wbFloat('Sunset'), wbFloat('Night'), wbFloat('EarlySunrise'), wbFloat('LateSunrise'), wbFloat('EarlySunset'), wbFloat('LateSunset') ])), wbStruct(NAM0, 'Weather Colors', [ wbWeatherColors('Sky-Upper'), wbWeatherColors('Fog Near'), wbWeatherColors('Unknown'), wbWeatherColors('Ambient'), wbWeatherColors('Sunlight'), wbWeatherColors('Sun'), wbWeatherColors('Stars'), wbWeatherColors('Sky-Lower'), wbWeatherColors('Horizon'), wbWeatherColors('Effect Lighting'), wbWeatherColors('Cloud LOD Diffuse'), wbWeatherColors('Cloud LOD Ambient'), wbWeatherColors('Fog Far'), wbWeatherColors('Sky Statics'), wbWeatherColors('Water Multiplier'), wbWeatherColors('Sun Glare'), wbWeatherColors('Moon Glare'), wbWeatherColors('Fog Near High'), wbWeatherColors('Fog Far High') ], cpNormal, True, nil, 8), wbArray(NAM4, 'Unknown', wbFloat('Unknown')), wbStruct(FNAM, 'Fog Distance', [ wbFloat('Day - Near'), wbFloat('Day - Far'), wbFloat('Night - Near'), wbFloat('Night - Far'), wbFloat('Day - Power'), wbFloat('Night - Power'), wbFloat('Day - Max'), wbFloat('Night - Max'), wbFloat('Day - Near Height Mid'), wbFloat('Day - Near Height Range'), wbFloat('Night - Near Height Mid'), wbFloat('Night - Near Height Range'), wbFloat('Day - High Density Scale'), wbFloat('Night - High Density Scale'), wbFloat('Day - Far Height Mid'), wbFloat('Day - Far Height Range'), wbFloat('Night - Far Height Mid'), wbFloat('Night - Far Height Range') ], cpNormal, True, nil, 8), wbStruct(DATA, 'Data', [ wbInteger('Wind Speed', itU8), // scaled 0..1 wbByteArray('Unknown', 2), wbInteger('Trans Delta', itU8), // scaled 0..0,25 wbInteger('Sun Glare', itU8), // scaled 0..1 wbInteger('Sun Damage', itU8), // scaled 0..1 wbInteger('Precipitation - Begin Fade In', itU8), // scaled 0..1 wbInteger('Precipitation - End Fade Out', itU8), // scaled 0..1 wbInteger('Thunder/Lightning - Begin Fade In', itU8), wbInteger('Thunder/Lightning - End Fade Out', itU8), wbInteger('Thunder/Lightning - Frequency', itU8), wbInteger('Flags', itU8, wbFlags([ {0x01} 'Weather - Pleasant', {0x02} 'Weather - Cloudy', {0x04} 'Weather - Rainy', {0x08} 'Weather - Snow', {0x10} 'Sky Statics - Always Visible', {0x20} 'Sky Statics - Follows Sun Position', {0x40} 'Rain Occlusion', {0x80} 'HUD Rain Effects' ])), wbStruct('Lightning Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8) ]), wbInteger('Visual Effect - Begin', itU8), // scaled 0..1 wbInteger('Visual Effect - End', itU8), // scaled 0..1 wbInteger('Wind Direction', itU8), // scaled 0..360 wbInteger('Wind Direction Range', itU8), // scaled 0..180 wbInteger('Unknown', itU8) ], cpNormal, True, nil, 16), wbInteger(NAM1, 'Disabled Cloud Layers', itU32, wbFlags(['0','1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21','22','23','24','25','26','27','28','29','30','31'])), wbRArray('Sounds', wbStruct(SNAM, 'Sound', [ wbFormIDCK('Sound', [SNDR, NULL]), wbInteger('Type', itU32, wbEnum([ {0x01} 'Default', {0x02} 'Precipitation', {0x04} 'Wind', {0x08} 'Thunder' ])) ]) ), wbRArrayS('Sky Statics', wbFormIDCk(TNAM, 'Static', [STAT, NULL])), wbStruct(IMSP, 'Image Spaces', [ wbFormIDCK('Sunrise', [IMGS, NULL]), wbFormIDCK('Day', [IMGS, NULL]), wbFormIDCK('Sunset', [IMGS, NULL]), wbFormIDCK('Night', [IMGS, NULL]), wbFormIDCK('EarlySunrise', [IMGS, NULL]), wbFormIDCK('LateSunrise', [IMGS, NULL]), wbFormIDCK('EarlySunset', [IMGS, NULL]), wbFormIDCK('LateSunset', [IMGS, NULL]) ], cpNormal, True, nil, 4), wbStruct(WGDR, 'God Rays', [ wbFormIDCK('Sunrise', [GDRY, NULL]), wbFormIDCK('Day', [GDRY, NULL]), wbFormIDCK('Sunset', [GDRY, NULL]), wbFormIDCK('Night', [GDRY, NULL]), wbFormIDCK('EarlySunrise', [GDRY, NULL]), wbFormIDCK('LateSunrise', [GDRY, NULL]), wbFormIDCK('EarlySunset', [GDRY, NULL]), wbFormIDCK('LateSunset', [GDRY, NULL]) ]), wbRStruct('Directional Ambient Lighting Colors', [ wbAmbientColors(DALC, 'Sunrise'), wbAmbientColors(DALC, 'Day'), wbAmbientColors(DALC, 'Sunset'), wbAmbientColors(DALC, 'Night'), wbAmbientColors(DALC, 'EarlySunrise'), wbAmbientColors(DALC, 'LateSunrise'), wbAmbientColors(DALC, 'EarlySunset'), wbAmbientColors(DALC, 'LateSunset') ], [], cpNormal, True), wbRStruct('Aurora', [wbMODL], []), wbFormIDCk(GNAM, 'Sun Glare Lens Flare', [LENS]), wbStruct(UNAM, 'Magic', [ wbFormIDCk('On Lightning Strike - Spell', [SPEL, NULL]), wbFloat('On Lightning Strike - Threshold'), wbFormIDCk('On Weather Activate - Spell', [SPEL, NULL]), wbFloat('On Weather Activate - Threshold'), wbByteArray('Unknown', 4), // SPEL FormID for another context but unresolved in Fallout4.esm, legacy data wbFloat('Unknown') ], cpNormal, False, nil, 3), wbFloat(VNAM, 'Volatility Mult'), wbFloat(WNAM, 'Visibility Mult') ]); end; procedure DefineFO4p; begin {wbRecord(SCPT, 'SCPT', [ wbEDID ]);} end; {>>> Start of new Fallout 4 Records <<<} procedure DefineFO4q; begin wbRecord(AECH, 'Audio Effect Chain', [ wbEDID, wbRArray('Effects', wbRStruct('Effect', [ wbInteger(KNAM, 'Type', itU32, wbEnum([], [ Int64($864804BE), 'BSOverdrive', Int64($EF575F7F), 'BSStateVariableFilter', Int64($18837B4F), 'BSDelayEffect' ]), cpNormal, False, False, nil, nil, Int64($864804BE)), wbStruct(DNAM, 'Data', [ wbInteger('Enabled', itU32, wbBoolEnum), wbUnion('Value 1', wbAECHDataDecider, [ wbFloat('Input Gain'), // exponentially(?) normalized from 0..10 to -80..20 wbFloat('Center Freq'), wbFloat('Feedback %') ]), wbUnion('Value 2', wbAECHDataDecider, [ wbFloat('Output Gain'), // exponentially(?) normalized from 0..10 to -80..20 wbFloat('Q Value'), wbFloat('Wet Mix %') ]), wbUnion('Value 3', wbAECHDataDecider, [ wbFloat('Upper Threshold'), // exponentially(?) normalized from 0..1 to -74..0 wbInteger('Filter Mode', itU32, wbEnum([ 'High Pass', 'Low Pass', 'Band Pass', 'Notch' ])), wbInteger('Delay MS', itU32) ]), wbUnion('Value 4', wbAECHDataDecider, [ wbFloat('Lower Threshold'), // exponentially(?) normalized from 0..1 to -80..0 wbByteArray('Unused', 0), wbByteArray('Unused', 0) ]) ]) ], []) ) ]); wbRecord(AMDL, 'Aim Model', [ wbEDID, wbStruct(DNAM, 'Data', [ wbFloat('Cone of Fire - Min Angle'), wbFloat('Cone of Fire - Max Angle'), wbFloat('Cone of Fire - Increase Per Shot'), wbFloat('Cone of Fire - Decrease Per Sec'), wbInteger('Cone of Fire - Decrease Delay MS', itU32), wbFloat('Cone of Fire - Sneak Mult'), wbFloat('Recoil - Diminish Spring Force'), wbFloat('Recoil - Diminish Sights Mult'), wbFloat('Recoil - Max Per Shot'), wbFloat('Recoil - Min Per Shot'), wbFloat('Recoil - Hip Mult'), wbInteger('Runaway - Recoil Shots', itU32), wbFloat('Recoil - Arc'), wbFloat('Recoil - Arc Rotate'), wbFloat('Cone of Fire - Iron Sights Mult'), wbFloat('Stability - Base Stability') ]) ]); wbRecord(AORU, 'Attraction Rule', [ wbEDID, wbStruct(AOR2, 'Data', [ wbFloat('Radius'), wbFloat('Min Delay'), wbFloat('Max Delay'), wbInteger('Requires Line of Sight', itU8, wbBoolEnum), wbInteger('Combat Target', itU8, wbBoolEnum), wbByteArray('Unused', 2) ], cpNormal, True) ]); wbRecord(BNDS, 'Bendable Spline', [ wbEDID, wbOBND, wbStruct(DNAM, 'Data', [ wbFloat('Default Number of Tiles'), wbInteger('Default Number of Slices', itU16), wbInteger('Default Number of Tiles - Relative to Length', itU16, wbBoolEnum), wbFloatColors('Default Color'), wbFloat('Wind Settings - Sensibility'), wbFloat('Wind Settings - Flexibility') ]), wbFormIDCk(TNAM, 'Texture', [TXST]) ]); wbRecord(CMPO, 'Component', [ wbEDID, wbOBND, wbFULL, wbCUSD, wbInteger(DATA, 'Auto Calc Value', itU32), wbFormIDCk(MNAM, 'Scrap Item', [MISC]), wbFormIDCk(GNAM, 'Mod Scrap Scalar', [GLOB]) ]); wbRecord(DFOB, 'Default Object', [ wbEDID, wbFormID(DATA, 'Object') ]); wbRecord(DMGT, 'Damage Type', [ wbEDID, // Before form version 78, it was an array of AVIF index, since then array of AVIF formID, coupled with a SPEL formID wbUnion(DNAM, 'Data', wbFormVer78Decider, [ wbArray('Damage Types', wbInteger('Actor Value Index', itU32)), wbArray('Damage Types', wbStruct('Damage Type', [ wbFormIDck('Actor Value', [AVIF, NULL]), wbFormIDck('Spell', [SPEL, NULL]) ])) ]) ]); wbRecord(GDRY, 'God Rays', [ wbEDID, wbStruct(DATA, 'Data', [ wbFloatColors('Back Color'), wbFloatColors('Fwd Color'), wbFloat('Intensity'), wbFloat('Air Color - Scale'), wbFloat('Back Color - Scale'), wbFloat('Fwd Color - Scale'), wbFloat('Back Phase'), wbFloatColors('Air Color'), wbFloat('Fwd Phase') ]) ]); end; procedure DefineFO4r; begin wbRecord(INNR, 'Instance Naming Rules', [ wbEDID, wbInteger(UNAM, 'Target', itU32, wbEnum([], [ 0, 'None', $1D, 'Armor', $2D, 'Actor', $2A, 'Furniture', $2B, 'Weapon' ])), wbRArray('Naming Rules', wbRStruct('Ruleset', [ wbInteger(VNAM, 'Count', itU32), // should not be sorted wbRArray('Names', wbRStruct('Name', [ wbLString(WNAM, 'Text', 0, cpTranslate), wbKSIZ, wbKWDAs, wbStruct(XNAM, 'Property', [ wbFloat('Value'), wbInteger('Target', itU8, wbEnum([ { 0} 'Enchantments', { 1} 'BashImpactDataSet', { 2} 'BlockMaterial', { 3} 'Keywords', { 4} 'Weight', { 5} 'Value', { 6} 'Rating', { 7} 'AddonIndex', { 8} 'BodyPart', { 9} 'DamageTypeValues', {10} 'ActorValues', {11} 'Health', {12} 'ColorRemappingIndex', {13} 'MaterialSwaps' ])), wbInteger('Op', itU8, wbEnum([ {0} '>=', {1} '>', {2} '<=', {3} '<', {4} '=' ])) ]), wbInteger(YNAM, 'Index', itU16) ], []), cpNormal, False, nil, wbINNRAfterSet ) ], []) ) ]); wbRecord(KSSM, 'Sound Keyword Mapping', [ wbEDID, wbFormIDCk(DNAM, 'Primary Descriptor', [SNDR]), wbFormIDCk(ENAM, 'Exterior Tail', [SNDR]), wbFormIDCk(VNAM, 'VATS Descriptor', [SNDR]), wbFloat(TNAM, 'VATS Threshold'), wbRArray('Keywords', wbFormIDCk(KNAM, 'Keyword', [KYWD])), wbRArrayS('Sounds', wbStructSK(RNAM, [0], 'Sound', [ wbInteger('Reverb Class', itU32, wbReverbClassEnum), wbFormIDCk('Descriptor', [SNDR]) ])) ]); wbRecord(LAYR, 'Layer', [ wbEDID, wbFormIDCk(PNAM, 'Parent', [LAYR]) ]); wbRecord(LENS, 'Lens Flare', [ wbEDID, wbFloat(CNAM, 'Color Influence'), wbFloat(DNAM, 'Fade Distance Radius Scale'), wbInteger(LFSP, 'Count', itU32, nil, cpBenign), wbRArrayS('Lens Flare Sprites', wbRStructSK([0], 'Flare', [ wbString(DNAM, 'Lens Flare Sprite ID'), wbString(FNAM, 'Texture'), wbStruct(LFSD, 'Lens Flare Data', [ wbFloatColors('Tint'), wbFloat('Width'), wbFloat('Height'), wbFloat('Position'), wbFloat('Angular Fade'), wbFloat('Opacity'), wbInteger('Flags', itU32, wbFlags([ {0x01} 'Rotates', {0x02} 'Shrinks When Occluded' ])) ]) ], []), cpNormal, False, nil, wbLENSAfterSet ) ]); {wbRecord(LSPR, 'LSPR', [ wbEDID ]); wbRecord(MICN, 'MICN', [ wbEDID ]);} wbRecord(MSWP, 'Material Swap', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00010000} 16, 'Custom Swap' ])), [ wbEDID, wbString(FNAM, 'Tree Folder'), {First FNAM} wbRArrayS('Material Substitutions', wbRStructSK([0], 'Substitution', [ wbString(BNAM, 'Original Material'), wbString(SNAM, 'Replacement Material'), wbString(FNAM, 'Tree Folder (obsolete)'), {Unused, will be moved up to First FNAM} wbFloat(CNAM, 'Color Remapping Index') ], []) ) ]); wbRecord(NOCM, 'Navigation Mesh Obstacle Manager', [ wbRArray('Unknown', wbRStruct('Unknown', [ wbInteger(INDX, 'Index', itU32), wbRArray('Unknown', wbUnknown(DATA)), wbUnknown(INTV), wbString(NAM1, 'Model') ], []) ) ]); end; procedure DefineFO4s; begin wbRecord(NOTE, 'Note', [ wbEDID, wbVMAD, wbOBND, wbPTRN, wbFULL, wbMODL, wbICON, wbYNAM, wbZNAM, wbInteger(DNAM, 'Type', itU8, wbEnum([ 'Sound', 'Voice', 'Program', 'Terminal' ]), cpNormal, True), wbStruct(DATA, '', [ // was DNAM before form version 65. Now holds value and weight wbInteger('Value', itU32), wbFloat('Weight') ]), wbUnion(SNAM, 'Data', wbNOTEDataDecider, [ wbByteArray('Unused', 4), wbFormIDCk('Sound', [SNDR]), wbFormIDCk('Scene', [SCEN]), wbFormIDCk('Terminal', [TERM]) ]), wbString(PNAM, 'Program File') ]); wbRecord(OMOD, 'Object Modification', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000008} 4, 'Legendary Mod', {0x00000040} 7, 'Mod Collection' ])), [ wbEDID, wbFULL, wbDESC, wbMODL, wbStruct(DATA, 'Data', [ wbInteger('Include Count', itU32), wbInteger('Property Count', itU32), wbByteArray('Unused', 2, cpIgnore), wbInteger('Form Type', itU32, wbEnum([], [ Sig2Int(ARMO), 'Armor', Sig2Int(NPC_), 'Non-player character', Sig2Int(WEAP), 'Weapon', Sig2Int(NONE), 'None' ])), wbByteArray('Unused', 2, cpIgnore), wbFormIDCk('Attach Point', [KYWD, NULL]), wbArray('Attach Parent Slots', wbFormIDCk('Keyword', [KYWD, NULL]), -1), // no way to change these in CK, legacy data leftover? wbArray('Items', wbStruct('Item', [ wbByteArray('Value 1', 4), wbByteArray('Value 2', 4) ]), -1), // should not be sorted wbArray('Includes', wbStruct('Include', [ wbFormIDCk('Mod', [OMOD]), wbInteger('Minimum Level', itU8), wbInteger('Optional', itU8, wbBoolEnum), wbInteger('Don''t Use All', itU8, wbBoolEnum) ]), wbOMODDataIncludeCounter, cpNormal, False, nil, wbOMODincludeAfterSet), wbObjectModProperties ], cpNormal, False, nil, -1, nil, wbOMODdataAfterSet), wbArray(MNAM, 'Target OMOD Keywords', wbFormIDCk('Keyword', [KYWD])), wbArray(FNAM, 'Filter Keywords', wbFormIDCk('Keyword', [KYWD])), wbFormIDCk(LNAM, 'Loose Mod', sigBaseObjects), wbInteger(NAM1, 'Priority', itU8), wbFLTR ]); wbRecord(OVIS, 'Object Visibility Manager', [ wbRArray('Unknown', wbRStruct('Unknown', [ wbFormIDCk(INDX, 'Object', [STAT]), wbStruct(DATA, 'Object Bounds', [ wbFloat('X1'), wbFloat('Y1'), wbFloat('Z1'), wbFloat('X2'), wbFloat('Y2'), wbFloat('Z2') ]) ], []) ) ]); wbRecord(PKIN, 'Pack-In', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000200} 9, 'Prefab' ])), [ wbEDID, wbOBND, wbFLTR, wbFormIDCk(CNAM, 'Cell', [CELL]), wbInteger(VNAM, 'Version', itU32) ]); wbRecord(RFGP, 'Reference Group', [ wbEDID, wbString(NNAM, 'Name'), wbFormIDCk(RNAM, 'Reference', sigReferences), wbUnknown(PNAM) ]); {wbRecord(RGDL, 'RGDL', [ wbEDID ]);} wbRecord(SCCO, 'Scene Collection', [ wbEDID, wbFormIDCk(QNAM, 'Quest', [QUST]), wbRArray('Scenes', wbRStruct('Scene', [ wbFormIDCk(SNAM, 'Scene', [SCEN]), wbStruct(XNAM, 'Unknown', [ wbInteger('Unknown', itS32), wbInteger('Unknown', itS32) ]) ], []) ), wbUnknown(VNAM, cpNormal, True), wbRArray('Unknown', wbStruct(XNAM, 'Unknown', [ wbInteger('Unknown', itS32), wbInteger('Unknown', itS32) ])), wbUnknown(VNAM, cpNormal, True) ]); wbRecord(SCOL, 'Static Collection', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000004} 4, 'Non Occluder', {0x00000200} 9, 'Hidden From Local Map', {0x00000400} 10, 'Unknown 10', {0x00000800} 11, 'Used as Platform', {0x00008000} 15, 'Has Distant LOD', {0x02000000} 25, 'Obstacle', {0x04000000} 26, 'NavMesh Generation - Filter', {0x08000000} 27, 'NavMesh Generation - Bounding Box', {0x40000000} 30, 'NavMesh Generation - Ground' ])), [ wbEDID, wbOBNDReq, wbPTRN, wbMODL, wbFULL, wbFLTR, wbRStructsSK('Parts', 'Part', [0], [ wbFormIDCk(ONAM, 'Static', [ACTI, ALCH, AMMO, BOOK, CONT, DOOR, FURN, MISC, MSTT, STAT, TERM, WEAP]), wbArrayS(DATA, 'Placements', wbStruct('Placement', [ wbStruct('Position', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), wbStruct('Rotation', [ wbFloat('X', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Y', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Z', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize) ]), wbFloat('Scale') ]), 0, cpNormal, True) ], [], cpNormal, True) ]); wbRecord(SCSN, 'Audio Category Snapshot', [ wbEDID, wbInteger(PNAM, 'Priority', itU16), wbRArray('Category Multipliers', wbStruct(CNAM, 'Category Multiplier', [ wbFormIDCk('Categoty', [SNCT]), wbFloat('Multiplier') ])) ]); end; procedure DefineFO4t; begin {wbRecord(SKIL, 'SKIL', [ wbEDID ]);} wbRecord(STAG, 'Animation Sound Tag Set', [ wbEDID, wbRArray('Sounds', wbStruct(TNAM, 'Sound', [ wbFormIDCk('Sound', [SNDR, NULL]), wbString('Action') ])) ]); wbRecord(TERM, 'Terminal', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000004} 4, 'Unknown 4', {0x00002000} 13, 'Unknown 13', {0x00008000} 15, 'Has Distant LOD', {0x00010000} 16, 'Random Anim Start' ])), [ wbEDID, wbVMADFragmentedPERK, // same fragments format as in PERK wbOBNDReq, wbPTRN, wbLString(NAM0, 'Header Text'), wbLString(WNAM, 'Welcome Text'), wbFULL, wbMODL, wbKSIZ, wbKWDAs, wbPRPS, wbUnknown(PNAM), wbFormIDCk(SNAM, 'Looping Sound', [SNDR]), wbUnknown(FNAM), wbCOCT, wbCNTOs, wbMNAMFurnitureMarker, wbByteArray(WBDT, 'Workbench Data (unused)', 0), wbString(XMRK, 'Marker Model'), wbSNAMMarkerParams, wbInteger(BSIZ, 'Count', itU32, nil, cpBenign), wbRArray('Body Text', wbRStruct('Item', [ wbLString(BTXT, 'Text', 0, cpTranslate), wbCTDAs ], []), cpNormal, False, nil, wbTERMDisplayItemsAfterSet ), wbInteger(ISIZ, 'Count', itU32, nil, cpBenign), wbRArray('Menu Items', wbRStruct('Menu Item', [ wbLString(ITXT, 'Item Text', 0, cpTranslate), wbLString(RNAM, 'Response Text', 0, cpTranslate), wbInteger(ANAM, 'Type', itU8, wbEnum([ {0} 'Unknown 0', {1} 'Unknown 1', {2} 'Unknown 2', {3} 'Unknown 3', {4} 'Submenu - Terminal', {5} 'Submenu - Return to Top Level', {6} 'Submenu - Force Redraw', {7} 'Unknown 7', {8} 'Display Text' ]), cpNormal, True), wbInteger(ITID, 'Item ID', itU16), wbLString(UNAM, 'Display Text', 0, cpTranslate), wbString(VNAM, 'Show Image'), wbFormIDCk(TNAM, 'Submenu', [TERM]), wbCTDAs ], []), cpNormal, False, nil, wbTERMMenuItemsAfterSet ) ]); {wbRecord(TLOD, 'TLOD', [ wbEDID ]); wbRecord(TOFT, 'TOFT', [ wbEDID ]);} wbRecord(TRNS, 'Transform', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00008000} 16, 'Around Origin' ])), [ wbEDID, wbStruct(DATA, 'Data', [ wbPosRot, wbFloat('Scale'), wbFloat('Zoom Min'), wbFloat('Zoom Max') ], cpNormal, True, nil, 2) ]); wbRecord(ZOOM, 'Zoom', [ wbEDID, wbStruct(GNAM, 'Data', [ wbFloat('FOV Mult'), wbInteger('Overlay', itU32, wbEnum([ { 0} 'Default', { 1} 'Fine', { 2} 'Duplex', { 3} 'German', { 4} 'Dot', { 5} 'Mil-Dot', { 6} 'Circle', { 7} 'Old Rangefind', { 8} 'Modern Rangefind', { 9} 'SVD', {10} 'Hand Painted', {11} 'Binoculars', {12} 'Cross', {13} 'Double Zero', {14} 'Rangefinder 1', {15} 'Rangefinder 2', {16} 'Rectangle' ])), wbFormIDCk('Imagespace Modifier', [IMAD, NULL]), wbStruct('Camera Offset', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]) ]) ]); end; procedure DefineFO4u; begin wbAddGroupOrder(GMST); wbAddGroupOrder(KYWD); wbAddGroupOrder(LCRT); wbAddGroupOrder(AACT); wbAddGroupOrder(TRNS); wbAddGroupOrder(CMPO); wbAddGroupOrder(TXST); //wbAddGroupOrder(MICN); wbAddGroupOrder(GLOB); wbAddGroupOrder(DMGT); wbAddGroupOrder(CLAS); wbAddGroupOrder(FACT); wbAddGroupOrder(HDPT); //wbAddGroupOrder(EYES); wbAddGroupOrder(RACE); wbAddGroupOrder(SOUN); wbAddGroupOrder(ASPC); //wbAddGroupOrder(SKIL); wbAddGroupOrder(MGEF); //wbAddGroupOrder(SCPT);{>>> Unused in Skyrim, but contained in Skyrim.esm <<<} wbAddGroupOrder(LTEX); wbAddGroupOrder(ENCH); wbAddGroupOrder(SPEL); //wbAddGroupOrder(SCRL); wbAddGroupOrder(ACTI); wbAddGroupOrder(TACT); wbAddGroupOrder(ARMO); wbAddGroupOrder(BOOK); wbAddGroupOrder(CONT); wbAddGroupOrder(DOOR); wbAddGroupOrder(INGR); wbAddGroupOrder(LIGH); wbAddGroupOrder(MISC); wbAddGroupOrder(STAT); wbAddGroupOrder(SCOL); wbAddGroupOrder(MSTT); wbAddGroupOrder(GRAS); wbAddGroupOrder(TREE); wbAddGroupOrder(FLOR); wbAddGroupOrder(FURN); wbAddGroupOrder(WEAP); wbAddGroupOrder(AMMO); wbAddGroupOrder(NPC_); wbAddGroupOrder(LVLN); wbAddGroupOrder(KEYM); wbAddGroupOrder(ALCH); wbAddGroupOrder(IDLM); wbAddGroupOrder(NOTE); wbAddGroupOrder(PROJ); wbAddGroupOrder(HAZD); wbAddGroupOrder(BNDS); //wbAddGroupOrder(SLGM); wbAddGroupOrder(TERM); wbAddGroupOrder(LVLI); wbAddGroupOrder(WTHR); wbAddGroupOrder(CLMT); wbAddGroupOrder(SPGD); wbAddGroupOrder(RFCT); wbAddGroupOrder(REGN); wbAddGroupOrder(NAVI); wbAddGroupOrder(CELL); //wbAddGroupOrder(REFR); //wbAddGroupOrder(ACHR); //wbAddGroupOrder(PMIS); //wbAddGroupOrder(PARW); //wbAddGroupOrder(PGRE); //wbAddGroupOrder(PBEA); //wbAddGroupOrder(PFLA); //wbAddGroupOrder(PCON); //wbAddGroupOrder(PBAR); //wbAddGroupOrder(PHZD); wbAddGroupOrder(WRLD); //wbAddGroupOrder(LAND); //wbAddGroupOrder(NAVM); //wbAddGroupOrder(TLOD); //wbAddGroupOrder(DIAL); //wbAddGroupOrder(INFO); wbAddGroupOrder(QUST); wbAddGroupOrder(IDLE); wbAddGroupOrder(PACK); wbAddGroupOrder(CSTY); wbAddGroupOrder(LSCR); wbAddGroupOrder(LVSP); wbAddGroupOrder(ANIO); wbAddGroupOrder(WATR); wbAddGroupOrder(EFSH); //wbAddGroupOrder(TOFT); wbAddGroupOrder(EXPL); wbAddGroupOrder(DEBR); wbAddGroupOrder(IMGS); wbAddGroupOrder(IMAD); wbAddGroupOrder(FLST); wbAddGroupOrder(PERK); wbAddGroupOrder(BPTD); wbAddGroupOrder(ADDN); wbAddGroupOrder(AVIF); wbAddGroupOrder(CAMS); wbAddGroupOrder(CPTH); wbAddGroupOrder(VTYP); wbAddGroupOrder(MATT); wbAddGroupOrder(IPCT); wbAddGroupOrder(IPDS); wbAddGroupOrder(ARMA); wbAddGroupOrder(ECZN); wbAddGroupOrder(LCTN); wbAddGroupOrder(MESG); //wbAddGroupOrder(RGDL);{>>> Unused in Skyrim, but contained in Skyrim.esm <<<} wbAddGroupOrder(DOBJ); wbAddGroupOrder(DFOB); wbAddGroupOrder(LGTM); wbAddGroupOrder(MUSC); wbAddGroupOrder(FSTP); wbAddGroupOrder(FSTS); wbAddGroupOrder(SMBN); wbAddGroupOrder(SMQN); wbAddGroupOrder(SMEN); wbAddGroupOrder(DLBR); wbAddGroupOrder(MUST); wbAddGroupOrder(DLVW); //wbAddGroupOrder(WOOP); //wbAddGroupOrder(SHOU); wbAddGroupOrder(EQUP); wbAddGroupOrder(RELA); wbAddGroupOrder(SCEN); wbAddGroupOrder(ASTP); wbAddGroupOrder(OTFT); wbAddGroupOrder(ARTO); wbAddGroupOrder(MATO); wbAddGroupOrder(MOVT); wbAddGroupOrder(SNDR); wbAddGroupOrder(DUAL); // doesn't exist but can be created in CK wbAddGroupOrder(SNCT); wbAddGroupOrder(SOPM); wbAddGroupOrder(COLL); wbAddGroupOrder(CLFM); wbAddGroupOrder(REVB); wbAddGroupOrder(PKIN); wbAddGroupOrder(RFGP); wbAddGroupOrder(AMDL); wbAddGroupOrder(LAYR); wbAddGroupOrder(COBJ); wbAddGroupOrder(OMOD); wbAddGroupOrder(MSWP); wbAddGroupOrder(ZOOM); wbAddGroupOrder(INNR); wbAddGroupOrder(KSSM); wbAddGroupOrder(AECH); wbAddGroupOrder(SCCO); wbAddGroupOrder(AORU); wbAddGroupOrder(SCSN); wbAddGroupOrder(STAG); wbAddGroupOrder(NOCM); wbAddGroupOrder(LENS); //wbAddGroupOrder(LSPR); wbAddGroupOrder(GDRY); wbAddGroupOrder(OVIS); end; procedure DefineFO4; begin DefineFO4a; DefineFO4b; DefineFO4c; DefineFO4d; DefineFO4e; DefineFO4f; DefineFO4g; DefineFO4h; DefineFO4i; DefineFO4j; DefineFO4k; DefineFO4l; DefineFO4m; DefineFO4n; DefineFO4o; DefineFO4p; DefineFO4q; DefineFO4r; DefineFO4s; DefineFO4t; DefineFO4u; SetLength(wbOfficialDLC, 6); wbOfficialDLC[0] := 'DLCRobot.esm'; wbOfficialDLC[1] := 'DLCWorkshop01.esm'; wbOfficialDLC[2] := 'DLCCoast.esm'; wbOfficialDLC[3] := 'DLCWorkshop02.esm'; wbOfficialDLC[4] := 'DLCWorkshop03.esm'; wbOfficialDLC[5] := 'DLCNukaWorld.esm'; end; initialization end. ================================================ FILE: lib/xedit/wbDefinitionsTES3.pas ================================================ {******************************************************************************* The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. *******************************************************************************} //------------------------------------------------------------------------------ // Placeholder for future expansion //------------------------------------------------------------------------------ unit wbDefinitionsTES3; interface uses wbInterface; var wbPKDTFlags: IwbFlagsDef; wbServiceFlags: IwbFlagsDef; wbAxisEnum: IwbEnumDef; wbBlendModeEnum: IwbEnumDef; wbBlendOpEnum: IwbEnumDef; wbCrimeTypeEnum: IwbEnumDef; wbFormTypeEnum: IwbEnumDef; wbFunctionsEnum: IwbEnumDef; wbMagicSchoolEnum: IwbEnumDef; wbMusicEnum: IwbEnumDef; wbOBMEResolutionInfo: IwbEnumDef; wbPKDTType: IwbEnumDef; wbQuadrantEnum: IwbEnumDef; wbSexEnum: IwbEnumDef; wbSkillEnum: IwbEnumDef; wbSoulGemEnum: IwbEnumDef; wbSpecializationEnum: IwbEnumDef; wbZTestFuncEnum: IwbEnumDef; procedure DefineTES3; implementation uses Types, Classes, SysUtils, Math, Variants; const ACBS : TwbSignature = 'ACBS'; ACHR : TwbSignature = 'ACHR'; ACRE : TwbSignature = 'ACRE'; TRGT : TwbSignature = 'TRGT'; ACTI : TwbSignature = 'ACTI'; AIDT : TwbSignature = 'AIDT'; ALCH : TwbSignature = 'ALCH'; AMMO : TwbSignature = 'AMMO'; ANAM : TwbSignature = 'ANAM'; ANIO : TwbSignature = 'ANIO'; APPA : TwbSignature = 'APPA'; ARMO : TwbSignature = 'ARMO'; ATTR : TwbSignature = 'ATTR'; ATXT : TwbSignature = 'ATXT'; BMDT : TwbSignature = 'BMDT'; BNAM : TwbSignature = 'BNAM'; BOOK : TwbSignature = 'BOOK'; BSGN : TwbSignature = 'BSGN'; BTXT : TwbSignature = 'BTXT'; CELL : TwbSignature = 'CELL'; CLAS : TwbSignature = 'CLAS'; CLMT : TwbSignature = 'CLMT'; CLOT : TwbSignature = 'CLOT'; CNAM : TwbSignature = 'CNAM'; CNTO : TwbSignature = 'CNTO'; CONT : TwbSignature = 'CONT'; CREA : TwbSignature = 'CREA'; CSAD : TwbSignature = 'CSAD'; CSCR : TwbSignature = 'CSCR'; CSDC : TwbSignature = 'CSDC'; CSDI : TwbSignature = 'CSDI'; CSDT : TwbSignature = 'CSDT'; CSTD : TwbSignature = 'CSTD'; CSTY : TwbSignature = 'CSTY'; CTDA : TwbSignature = 'CTDA'; CTDT : TwbSignature = 'CTDT'; DATA : TwbSignature = 'DATA'; DATX : TwbSignature = 'DATX'; DELE : TwbSignature = 'DELE'; DESC : TwbSignature = 'DESC'; DIAL : TwbSignature = 'DIAL'; DNAM : TwbSignature = 'DNAM'; DOOR : TwbSignature = 'DOOR'; EDID : TwbSignature = 'EDID'; EDDX : TwbSignature = 'EDDX'; EFID : TwbSignature = 'EFID'; EFIT : TwbSignature = 'EFIT'; ACVA : TwbSignature = 'ACVA'; EFII : TwbSignature = 'EFII'; EFXX : TwbSignature = 'EFXX'; EFIX : TwbSignature = 'EFIX'; EFME : TwbSignature = 'EFME'; EFSH : TwbSignature = 'EFSH'; ENAM : TwbSignature = 'ENAM'; ENCH : TwbSignature = 'ENCH'; ENIT : TwbSignature = 'ENIT'; ESCE : TwbSignature = 'ESCE'; EYES : TwbSignature = 'EYES'; FACT : TwbSignature = 'FACT'; FGGA : TwbSignature = 'FGGA'; FGGS : TwbSignature = 'FGGS'; FGTS : TwbSignature = 'FGTS'; FLOR : TwbSignature = 'FLOR'; FLTV : TwbSignature = 'FLTV'; FNAM : TwbSignature = 'FNAM'; FULL : TwbSignature = 'FULL'; FURN : TwbSignature = 'FURN'; GLOB : TwbSignature = 'GLOB'; GMST : TwbSignature = 'GMST'; GNAM : TwbSignature = 'GNAM'; GRAS : TwbSignature = 'GRAS'; HAIR : TwbSignature = 'HAIR'; HCLR : TwbSignature = 'HCLR'; HEDR : TwbSignature = 'HEDR'; HNAM : TwbSignature = 'HNAM'; ICO2 : TwbSignature = 'ICO2'; ICON : TwbSignature = 'ICON'; IDLE : TwbSignature = 'IDLE'; NULL : TwbSignature = 'NULL'; INAM : TwbSignature = 'INAM'; INDX : TwbSignature = 'INDX'; INFO : TwbSignature = 'INFO'; INGR : TwbSignature = 'INGR'; JNAM : TwbSignature = 'JNAM'; KEYM : TwbSignature = 'KEYM'; KFFZ : TwbSignature = 'KFFZ'; LAND : TwbSignature = 'LAND'; LIGH : TwbSignature = 'LIGH'; LNAM : TwbSignature = 'LNAM'; LSCR : TwbSignature = 'LSCR'; LTEX : TwbSignature = 'LTEX'; LVLC : TwbSignature = 'LVLC'; LVLD : TwbSignature = 'LVLD'; LVLF : TwbSignature = 'LVLF'; LVLI : TwbSignature = 'LVLI'; LVLO : TwbSignature = 'LVLO'; LVSP : TwbSignature = 'LVSP'; MAST : TwbSignature = 'MAST'; MGEF : TwbSignature = 'MGEF'; MISC : TwbSignature = 'MISC'; MNAM : TwbSignature = 'MNAM'; MO2B : TwbSignature = 'MO2B'; MO2T : TwbSignature = 'MO2T'; MO3B : TwbSignature = 'MO3B'; MO3T : TwbSignature = 'MO3T'; MO4B : TwbSignature = 'MO4B'; MO4T : TwbSignature = 'MO4T'; MOD2 : TwbSignature = 'MOD2'; MOD3 : TwbSignature = 'MOD3'; MOD4 : TwbSignature = 'MOD4'; MODB : TwbSignature = 'MODB'; MODL : TwbSignature = 'MODL'; MODT : TwbSignature = 'MODT'; NAM0 : TwbSignature = 'NAM0'; NAM1 : TwbSignature = 'NAM1'; NAM2 : TwbSignature = 'NAM2'; NAM9 : TwbSignature = 'NAM9'; NAME : TwbSignature = 'NAME'; NIFT : TwbSignature = 'NIFT'; NIFZ : TwbSignature = 'NIFZ'; NPC_ : TwbSignature = 'NPC_'; OFST : TwbSignature = 'OFST'; OBME : TwbSignature = 'OBME'; ONAM : TwbSignature = 'ONAM'; PACK : TwbSignature = 'PACK'; PFIG : TwbSignature = 'PFIG'; PFPC : TwbSignature = 'PFPC'; PGAG : TwbSignature = 'PGAG'; PGRD : TwbSignature = 'PGRD'; PGRI : TwbSignature = 'PGRI'; PGRL : TwbSignature = 'PGRL'; PGRP : TwbSignature = 'PGRP'; PGRR : TwbSignature = 'PGRR'; PKDT : TwbSignature = 'PKDT'; PKID : TwbSignature = 'PKID'; PLDT : TwbSignature = 'PLDT'; PNAM : TwbSignature = 'PNAM'; PSDT : TwbSignature = 'PSDT'; PTDT : TwbSignature = 'PTDT'; QNAM : TwbSignature = 'QNAM'; QSDT : TwbSignature = 'QSDT'; QSTA : TwbSignature = 'QSTA'; QSTI : TwbSignature = 'QSTI'; QSTR : TwbSignature = 'QSTR'; TPIC : TwbSignature = 'TPIC'; QUST : TwbSignature = 'QUST'; RACE : TwbSignature = 'RACE'; RCLR : TwbSignature = 'RCLR'; RDAT : TwbSignature = 'RDAT'; RDGS : TwbSignature = 'RDGS'; RDMD : TwbSignature = 'RDMD'; RDMP : TwbSignature = 'RDMP'; RDOT : TwbSignature = 'RDOT'; RDSD : TwbSignature = 'RDSD'; RDWT : TwbSignature = 'RDWT'; REFR : TwbSignature = 'REFR'; PLYR : TwbSignature = 'PLYR'; REGN : TwbSignature = 'REGN'; RNAM : TwbSignature = 'RNAM'; ROAD : TwbSignature = 'ROAD'; RPLD : TwbSignature = 'RPLD'; RPLI : TwbSignature = 'RPLI'; SBSP : TwbSignature = 'SBSP'; SCDA : TwbSignature = 'SCDA'; SCHD : TwbSignature = 'SCHD'; SCHR : TwbSignature = 'SCHR'; SCIT : TwbSignature = 'SCIT'; SCPT : TwbSignature = 'SCPT'; SCRI : TwbSignature = 'SCRI'; SCRO : TwbSignature = 'SCRO'; SCRV : TwbSignature = 'SCRV'; SCTX : TwbSignature = 'SCTX'; SCVR : TwbSignature = 'SCVR'; SGST : TwbSignature = 'SGST'; SKIL : TwbSignature = 'SKIL'; SLCP : TwbSignature = 'SLCP'; SLGM : TwbSignature = 'SLGM'; SLSD : TwbSignature = 'SLSD'; SNAM : TwbSignature = 'SNAM'; SNDD : TwbSignature = 'SNDD'; SNDX : TwbSignature = 'SNDX'; SOUL : TwbSignature = 'SOUL'; SOUN : TwbSignature = 'SOUN'; SPEL : TwbSignature = 'SPEL'; SPIT : TwbSignature = 'SPIT'; SPLO : TwbSignature = 'SPLO'; STAT : TwbSignature = 'STAT'; TCLF : TwbSignature = 'TCLF'; TCLT : TwbSignature = 'TCLT'; TES3 : TwbSignature = 'TES3'; TNAM : TwbSignature = 'TNAM'; TRDT : TwbSignature = 'TRDT'; TREE : TwbSignature = 'TREE'; UNAM : TwbSignature = 'UNAM'; VCLR : TwbSignature = 'VCLR'; VHGT : TwbSignature = 'VHGT'; VNAM : TwbSignature = 'VNAM'; VNML : TwbSignature = 'VNML'; VTEX : TwbSignature = 'VTEX'; VTXT : TwbSignature = 'VTXT'; WATR : TwbSignature = 'WATR'; WEAP : TwbSignature = 'WEAP'; WLST : TwbSignature = 'WLST'; WNAM : TwbSignature = 'WNAM'; WRLD : TwbSignature = 'WRLD'; WTHR : TwbSignature = 'WTHR'; XACT : TwbSignature = 'XACT'; XCCM : TwbSignature = 'XCCM'; XCHG : TwbSignature = 'XCHG'; XCLC : TwbSignature = 'XCLC'; XCLL : TwbSignature = 'XCLL'; XCLR : TwbSignature = 'XCLR'; XCLW : TwbSignature = 'XCLW'; XCMT : TwbSignature = 'XCMT'; XCNT : TwbSignature = 'XCNT'; XCWT : TwbSignature = 'XCWT'; XESP : TwbSignature = 'XESP'; XGLB : TwbSignature = 'XGLB'; XHLT : TwbSignature = 'XHLT'; XHRS : TwbSignature = 'XHRS'; XLCM : TwbSignature = 'XLCM'; XLOC : TwbSignature = 'XLOC'; XLOD : TwbSignature = 'XLOD'; XMRC : TwbSignature = 'XMRC'; XMRK : TwbSignature = 'XMRK'; XNAM : TwbSignature = 'XNAM'; XOWN : TwbSignature = 'XOWN'; XPCI : TwbSignature = 'XPCI'; XRGD : TwbSignature = 'XRGD'; XRNK : TwbSignature = 'XRNK'; XRTM : TwbSignature = 'XRTM'; XSCL : TwbSignature = 'XSCL'; XSED : TwbSignature = 'XSED'; XSOL : TwbSignature = 'XSOL'; XTEL : TwbSignature = 'XTEL'; XTRG : TwbSignature = 'XTRG'; XXXX : TwbSignature = 'XXXX'; ZNAM : TwbSignature = 'ZNAM'; var wbEDID: IwbSubRecordDef; wbXOWN: IwbSubRecordDef; wbXGLB: IwbSubRecordDef; wbXRGD: IwbSubRecordDef; wbSLSD: IwbSubRecordDef; wbBodyDataIndex: IwbSubRecordDef; wbSPLO: IwbSubRecordDef; wbSPLOs: IwbSubRecordArrayDef; wbCNTO: IwbSubRecordDef; wbCNTOs: IwbSubRecordArrayDef; wbCSDT: IwbSubRecordStructDef; wbCSDTs: IwbSubRecordArrayDef; wbFULL: IwbSubRecordDef; wbFULLReq: IwbSubRecordDef; wbXNAM: IwbSubRecordDef; wbXNAMs: IwbSubRecordArrayDef; wbDESC: IwbSubRecordDef; wbXSCL: IwbSubRecordDef; wbDATAPosRot : IwbSubRecordDef; wbPosRot : IwbStructDef; wbMODL: IwbSubRecordStructDef; wbCTDA: IwbSubRecordUnionDef; wbSCHR: IwbSubRecordUnionDef; wbCTDAs: IwbSubRecordArrayDef; wbSCROs: IwbSubRecordArrayDef; wbPGRP: IwbSubRecordDef; wbResultScript: IwbSubRecordStructDef; // wbResultScriptOld: IwbSubRecordStructDef; wbSCRI: IwbSubRecordDef; wbFaceGen: IwbSubRecordStructDef; wbENAM: IwbSubRecordDef; wbFGGS: IwbSubRecordDef; wbXLOD: IwbSubRecordDef; wbXESP: IwbSubRecordDef; wbICON: IwbSubRecordDef; wbEFID: IwbSubRecordDef; wbEFIDOBME: IwbSubRecordDef; wbEFIT: IwbSubRecordDef; wbEFITOBME: IwbSubRecordDef; wbEFIX: IwbSubRecordDef; wbSCIT: IwbSubRecordStructDef; wbSCITOBME: IwbSubRecordStructDef; wbEffects: IwbSubRecordUnionDef; function wbClmtMoonsPhaseLength(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var PhaseLength : Byte; Masser : Boolean; Secunda : Boolean; begin Result := ''; if aType = ctToSortKey then begin Result := IntToHex64(aInt, 2); end else if aType = ctToStr then begin PhaseLength := aInt mod 64; Masser := (aInt and 64) <> 0; Secunda := (aInt and 128) <> 0; if Masser then if Secunda then Result := 'Masser, Secunda / ' else Result := 'Masser / ' else if Secunda then Result := 'Secunda / ' else Result := 'No Moon / '; Result := Result + IntToStr(PhaseLength); end; end; function wbClmtTime(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; begin Result := ''; if aType = ctToSortKey then Result := IntToHex64(aInt, 4) else if aType = ctToStr then Result := TimeToStr( EncodeTime(aInt div 6, (aInt mod 6) * 10, 0, 0) ); end; var wbCtdaTypeFlags : IwbFlagsDef; function wbCtdaType(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var s: string; begin Result := ''; case aType of ctToStr: begin case aInt and $F0 of $00 : Result := 'Equal to'; $20 : Result := 'Not equal to'; $40 : Result := 'Greater than'; $60 : Result := 'Greater than or equal to'; $80 : Result := 'Less than'; $A0 : Result := 'Less than or equal to'; else Result := '' end; if not Assigned(wbCtdaTypeFlags) then wbCtdaTypeFlags := wbFlags([ {0x01} 'Or', {0x02} 'Run on target', {0x04} 'Use global' ]); s := wbCtdaTypeFlags.ToString(aInt and $0F, aElement); if s <> '' then Result := Result + ' / ' + s; end; ctToSortKey: begin Result := IntToHex64(aInt, 2); Exit; end; ctCheck: begin case aInt and $F0 of $00, $20, $40, $60, $80, $A0 : Result := ''; else Result := '' end; if not Assigned(wbCtdaTypeFlags) then wbCtdaTypeFlags := wbFlags([ {0x01} 'Or', {0x02} 'Run on target', {0x04} 'Use global' ]); s := wbCtdaTypeFlags.Check(aInt and $0F, aElement); if s <> '' then Result := Result + ' / ' + s; end; end; end; function wbIdleAnam(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; begin Result := ''; case aType of ctToStr: begin case aInt and not $80 of 0: Result := 'Lower Body'; 1: Result := 'Left Arm'; 2: Result := 'Left Hand'; 3: Result := 'Right Arm'; 4: Result := 'Special Idle'; 5: Result := 'Whole Body'; 6: Result := 'Upper Body'; else Result := ''; end; if (aInt and $80) = 0 then Result := Result + ', Must return a file'; end; ctToSortKey: begin Result := IntToHex64(aInt, 2); end; ctCheck: begin case aInt and not $80 of 0..6: Result := ''; else Result := ''; end; end; end; end; function wbScaledInt4ToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; const PlusMinus : array[Boolean] of string = ('+', '-'); begin Result := ''; case aType of ctToStr, ctToEditValue: Result := FloatToStrF(aInt / 10000, ffFixed, 99, 4); ctToSortKey: begin Result := FloatToStrF(aInt / 10000, ffFixed, 99, 4); if Length(Result) < 22 then Result := StringOfChar('0', 22 - Length(Result)) + Result; Result := PlusMinus[aInt < 0] + Result; end; ctCheck: Result := ''; end; end; function wbScaledInt4ToInt(const aString: string; const aElement: IwbElement): Int64; var f: Extended; begin f := StrToFloat(aString); f := f * 10000; Result := Round(f); end; function wbHideFFFF(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; begin Result := ''; if aType = ctToSortKey then Result := IntToHex64(aInt, 4) else if aType = ctToStr then if aInt = $FFFF then Result := 'None' else Result := IntToStr(aInt); end; function wbAtxtPosition(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; begin Result := ''; if aType = ctToSortKey then Result := IntToHex64(aInt div 17, 2) + IntToHex64(aInt mod 17, 2) else if aType = ctCheck then begin if (aInt < 0) or (aInt > 288) then Result := '' else Result := ''; end else if aType = ctToStr then Result := IntToStr(aInt) + ' -> ' + IntToStr(aInt div 17) + ':' + IntToStr(aInt mod 17); end; function wbWthrDataClassification(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; begin Result := ''; case aType of ctToStr: begin case aInt and not 192 of 0: Result := 'None'; 1: Result := 'Pleasant'; 2: Result := 'Cloudy'; 3: Result := 'Rainy'; 4: Result := 'Snow'; else Result := ''; end; end; ctToSortKey: begin Result := IntToHex64(aInt, 2) end; ctCheck: begin case aInt and not 192 of 0..4: Result := ''; else Result := ''; end; end; end; end; function wbGLOBFNAM(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; begin Result := ''; case aType of ctToStr: begin case aInt of Ord('s'): Result := 'Short'; Ord('l'): Result := 'Long'; Ord('f'): Result := 'Float'; else Result := ''; end; end; ctToSortKey: Result := Chr(aInt); ctCheck: begin case aInt of Ord('s'), Ord('l'), Ord('f'): Result := ''; else Result := ''; end; end; end; end; function wbPlacedAddInfo(const aMainRecord: IwbMainRecord): string; var Rec: IwbRecord; Container: IwbContainer; s: string; begin Result := ''; Rec := aMainRecord.RecordBySignature['NAME']; if Assigned(Rec) then begin s := Trim(Rec.Value); if s <> '' then Result := 'places ' + s; end; Container := aMainRecord.Container; while Assigned(Container) and (Container.ElementType <> etGroupRecord) do Container := Container.Container; if Assigned(Container) then begin s := Trim(Container.Name); if s <> '' then begin if Result <> '' then Result := Result + ' '; Result := Result + 'in ' + s; end; end; end; function wbCellAddInfo(const aMainRecord: IwbMainRecord): string; var Rec: IwbRecord; Container: IwbContainer; GroupRecord : IwbGroupRecord; s: string; begin Result := ''; Rec := aMainRecord.RecordBySignature['XCLC']; if Assigned(Rec) then Result := 'at ' + Rec.Elements[0].Value + ',' + Rec.Elements[1].Value; Container := aMainRecord.Container; while Assigned(Container) and not (Supports(Container, IwbGroupRecord, GroupRecord) and (GroupRecord.GroupType = 1)) do Container := Container.Container; if Assigned(Container) then begin s := wbFormID.ToString(GroupRecord.GroupLabel, aMainRecord); if s <> '' then begin if Result <> '' then s := s + ' '; Result := 'in ' + s + Result; end; end; end; function wbGMSTUnionDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var rEDID: IwbRecord; s: string; begin Result := 1; rEDID := aElement.Container.RecordBySignature[EDID]; if Assigned(rEDID) then begin s := rEDID.Value; if Length(s) > 0 then case s[1] of 's': Result := 0; 'f': Result := 2; end; end; end; function wbMISCActorValueDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var MainRecord : IwbMainRecord; begin Result := 0; if not Assigned(aElement) then Exit; MainRecord := aElement.ContainingMainRecord; if not Assigned(MainRecord) then Exit; if (MainRecord.Flags._Flags and $000000C0) = $000000C0 then Result := 1; end; function wbXLOCFillerDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container: IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; if Container.DataSize = 16 then Result := 1; end; function wbPACKPKDTDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container: IwbContainer; begin Result := 1; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; if Container.DataSize = 4 then Result := 0; end; function wbREFRXSEDDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container: IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; if Container.DataSize = 4 then Result := 1; end; type TCTDAFunctionParamType = ( ptNone, ptInteger, ptVariableName, //Integer ptSex, //Enum: Male, Female ptActorValue, //Enum: wbActorValue ptCrimeType, //?? Enum ptAxis, //?? Char ptFormType, //?? Enum ptQuestStage, ptObjectReference, //REFR, ACHR, ACRE, PGRE ptInventoryObject, //ARMO, BOOK, MISC, WEAP, AMMO, KEYM, ALCH, NOTE, ARMA ptActor, //ACHR, ACRE ptQuest, //QUST ptFaction, //FACT ptCell, //CELL ptClass, //CLAS ptRace, //RACE ptActorBase, //NPC_, CREA ptGlobal, //GLOB ptWeather, //WTHR ptPackage, //PACK ptOwnerOpt, //FACT, NPC_ ptBirthsign, //BSGN ptFurniture, //FURN ptMagicItem, //SPEL ptMagicEffect, //MGEF ptWorldspace, //WRLD ptReferencableObject ); PCTDAFunction = ^TCTDAFunction; TCTDAFunction = record Index: Integer; Name: string; ParamType1: TCTDAFunctionParamType; ParamType2: TCTDAFunctionParamType; end; const wbCTDAFunctions : array[0..168] of TCTDAFunction = ( (Index: 1; Name: 'GetDistance'; ParamType1: ptObjectReference), (Index: 5; Name: 'GetLocked'), (Index: 6; Name: 'GetPos'; ParamType1: ptAxis), (Index: 8; Name: 'GetAngle'; ParamType1: ptAxis), (Index: 10; Name: 'GetStartingPos'; ParamType1: ptAxis), (Index: 11; Name: 'GetStartingAngle'; ParamType1: ptAxis), (Index: 12; Name: 'GetSecondsPassed'), (Index: 14; Name: 'GetActorValue'; ParamType1: ptActorValue), (Index: 18; Name: 'GetCurrentTime'), (Index: 24; Name: 'GetScale'), (Index: 27; Name: 'GetLineOfSight'; ParamType1: ptObjectReference), (Index: 32; Name: 'GetInSameCell'; ParamType1: ptObjectReference), (Index: 35; Name: 'GetDisabled'), (Index: 36; Name: 'MenuMode'; ParamType1: ptInteger), (Index: 39; Name: 'GetDisease'), (Index: 40; Name: 'GetVampire'), (Index: 41; Name: 'GetClothingValue'), (Index: 42; Name: 'SameFaction'; ParamType1: ptActor), (Index: 43; Name: 'SameRace'; ParamType1: ptActor), (Index: 44; Name: 'SameSex'; ParamType1: ptActor), (Index: 45; Name: 'GetDetected'; ParamType1: ptActor), (Index: 46; Name: 'GetDead'), (Index: 47; Name: 'GetItemCount'; ParamType1: ptInventoryObject), (Index: 48; Name: 'GetGold'), (Index: 49; Name: 'GetSleeping'), (Index: 50; Name: 'GetTalkedToPC'), (Index: 53; Name: 'GetScriptVariable'; ParamType1: ptObjectReference; ParamType2: ptVariableName), (Index: 56; Name: 'GetQuestRunning'; ParamType1: ptQuest), (Index: 58; Name: 'GetStage'; ParamType1: ptQuest), (Index: 59; Name: 'GetStageDone'; ParamType1: ptQuest; ParamType2: ptQuestStage), (Index: 60; Name: 'GetFactionRankDifference'; ParamType1: ptFaction; ParamType2: ptActor), (Index: 61; Name: 'GetAlarmed'), (Index: 62; Name: 'IsRaining'), (Index: 63; Name: 'GetAttacked'), (Index: 64; Name: 'GetIsCreature'), (Index: 65; Name: 'GetLockLevel'), (Index: 66; Name: 'GetShouldAttack'; ParamType1: ptActor), (Index: 67; Name: 'GetInCell'; ParamType1: ptCell), (Index: 68; Name: 'GetIsClass'; ParamType1: ptClass), (Index: 69; Name: 'GetIsRace'; ParamType1: ptRace), (Index: 70; Name: 'GetIsSex'; ParamType1: ptSex), (Index: 71; Name: 'GetInFaction'; ParamType1: ptFaction), (Index: 72; Name: 'GetIsID'; ParamType1: ptReferencableObject), (Index: 73; Name: 'GetFactionRank'; ParamType1: ptFaction), (Index: 74; Name: 'GetGlobalValue'; ParamType1: ptGlobal), (Index: 75; Name: 'IsSnowing'), (Index: 76; Name: 'GetDisposition'; ParamType1: ptActor), (Index: 77; Name: 'GetRandomPercent'), (Index: 79; Name: 'GetQuestVariable'; ParamType1: ptQuest; ParamType2: ptVariableName), (Index: 80; Name: 'GetLevel'), (Index: 81; Name: 'GetArmorRating'), (Index: 84; Name: 'GetDeadCount'; ParamType1: ptActorBase), (Index: 91; Name: 'GetIsAlerted'), (Index: 98; Name: 'GetPlayerControlsDisabled'), (Index: 99; Name: 'GetHeadingAngle'; ParamType1: ptObjectReference), (Index: 101; Name: 'IsWeaponOut'), (Index: 102; Name: 'IsTorchOut'), (Index: 103; Name: 'IsShieldOut'), (Index: 104; Name: 'IsYielding'), (Index: 106; Name: 'IsFacingUp'), (Index: 107; Name: 'GetKnockedState'), (Index: 108; Name: 'GetWeaponAnimType'), (Index: 109; Name: 'GetWeaponSkillType'), (Index: 110; Name: 'GetCurrentAIPackage'), (Index: 111; Name: 'IsWaiting'), (Index: 112; Name: 'IsIdlePlaying'), (Index: 116; Name: 'GetCrimeGold'), (Index: 122; Name: 'GetCrime'; ParamType1: ptActor; ParamType2: ptCrimeType), (Index: 125; Name: 'IsGuard'), (Index: 127; Name: 'CanPayCrimeGold'), (Index: 128; Name: 'GetFatiguePercentage'), (Index: 129; Name: 'GetPCIsClass'; ParamType1: ptClass), (Index: 130; Name: 'GetPCIsRace'; ParamType1: ptRace), (Index: 131; Name: 'GetPCIsSex'; ParamType1: ptSex), (Index: 132; Name: 'GetPCInFaction'; ParamType1: ptFaction), (Index: 133; Name: 'SameFactionAsPC'), (Index: 134; Name: 'SameRaceAsPC'), (Index: 135; Name: 'SameSexAsPC'), (Index: 136; Name: 'GetIsReference'; ParamType1: ptObjectReference), (Index: 141; Name: 'IsTalking'), (Index: 142; Name: 'GetWalkSpeed'), (Index: 143; Name: 'GetCurrentAIProcedure'), (Index: 144; Name: 'GetTrespassWarningLevel'), (Index: 145; Name: 'IsTrespassing'), (Index: 146; Name: 'IsInMyOwnedCell'), (Index: 147; Name: 'GetWindSpeed'), (Index: 148; Name: 'GetCurrentWeatherPercent'), (Index: 149; Name: 'GetIsCurrentWeather'; ParamType1: ptWeather), (Index: 150; Name: 'IsContinuingPackagePCNear'), (Index: 153; Name: 'CanHaveFlames'), (Index: 154; Name: 'HasFlames'), (Index: 157; Name: 'GetOpenState'), (Index: 159; Name: 'GetSitting'), (Index: 160; Name: 'GetFurnitureMarkerID'), (Index: 161; Name: 'GetIsCurrentPackage'; ParamType1: ptPackage), (Index: 162; Name: 'IsCurrentFurnitureRef'; ParamType1: ptObjectReference), (Index: 163; Name: 'IsCurrentFurnitureObj'; ParamType1: ptFurniture), (Index: 170; Name: 'GetDayOfWeek'), (Index: 171; Name: 'IsPlayerInJail'), (Index: 172; Name: 'GetTalkedToPCParam'; ParamType1: ptActor), (Index: 175; Name: 'IsPCSleeping'), (Index: 176; Name: 'IsPCAMurderer'), (Index: 180; Name: 'GetDetectionLevel'; ParamType1: ptActor), (Index: 182; Name: 'GetEquipped'; ParamType1: ptInventoryObject), (Index: 185; Name: 'IsSwimming'), (Index: 190; Name: 'GetAmountSoldStolen'), (Index: 193; Name: 'GetPCExpelled'; ParamType1: ptFaction), (Index: 195; Name: 'GetPCFactionMurder'; ParamType1: ptFaction), (Index: 197; Name: 'GetPCFactionSteal'; ParamType1: ptFaction), (Index: 199; Name: 'GetPCFactionAttack'; ParamType1: ptFaction), (Index: 201; Name: 'GetPCFactionSubmitAuthority'; ParamType1: ptFaction), (Index: 203; Name: 'GetDestroyed'), (Index: 214; Name: 'HasMagicEffect'; ParamType1: ptMagicEffect), (Index: 215; Name: 'GetDoorDefaultOpen'), (Index: 223; Name: 'IsSpellTarget'; ParamType1: ptMagicItem), (Index: 224; Name: 'GetIsPlayerBirthsign'; ParamType1: ptBirthsign), (Index: 225; Name: 'GetPersuasionNumber'), (Index: 227; Name: 'HasVampireFed'), (Index: 228; Name: 'GetIsClassDefault'; ParamType1: ptClass), (Index: 229; Name: 'GetClassDefaultMatch'), (Index: 230; Name: 'GetInCellParam'; ParamType1: ptCell; ParamType2: ptObjectReference), (Index: 237; Name: 'GetIsGhost'), (Index: 242; Name: 'GetUnconscious'), (Index: 244; Name: 'GetRestrained'), (Index: 246; Name: 'GetIsUsedItem'; ParamType1: ptReferencableObject), (Index: 247; Name: 'GetIsUsedItemType'; ParamType1: ptFormType), (Index: 249; Name: 'GetPCFame'), (Index: 251; Name: 'GetPCInfamy'), (Index: 254; Name: 'GetIsPlayableRace'), (Index: 255; Name: 'GetOffersServicesNow'), (Index: 258; Name: 'GetUsedItemLevel'), (Index: 259; Name: 'GetUsedItemActivate'), (Index: 264; Name: 'GetBarterGold'), (Index: 265; Name: 'IsTimePassing'), (Index: 266; Name: 'IsPleasant'), (Index: 267; Name: 'IsCloudy'), (Index: 274; Name: 'GetArmorRatingUpperBody'), (Index: 277; Name: 'GetBaseActorValue'; ParamType1: ptActorValue), (Index: 278; Name: 'IsOwner'; ParamType1: ptOwnerOpt), (Index: 280; Name: 'IsCellOwner'; ParamType1: ptCell; ParamType2: ptOwnerOpt), (Index: 282; Name: 'IsHorseStolen'), (Index: 285; Name: 'IsLeftUp'), (Index: 286; Name: 'IsSneaking'), (Index: 287; Name: 'IsRunning'), (Index: 288; Name: 'GetFriendHit'; ParamType1: ptActor), (Index: 289; Name: 'IsInCombat'), (Index: 300; Name: 'IsInInterior'), (Index: 305; Name: 'GetInvestmentGold'), (Index: 306; Name: 'IsActorUsingATorch'), (Index: 309; Name: 'IsXBox'), (Index: 310; Name: 'GetInWorldspace'; ParamType1: ptWorldSpace), (Index: 312; Name: 'GetPCMiscStat'; ParamType1: ptInteger), (Index: 313; Name: 'IsActorEvil'), (Index: 314; Name: 'IsActorAVictim'), (Index: 315; Name: 'GetTotalPersuasionNumber'), (Index: 318; Name: 'GetIdleDoneOnce'), (Index: 320; Name: 'GetNoRumors'), (Index: 323; Name: 'WhichServiceMenu'), (Index: 327; Name: 'IsRidingHorse'), (Index: 329; Name: 'IsTurnArrest'), (Index: 332; Name: 'IsInDangerousWater'), (Index: 338; Name: 'GetIgnoreFriendlyHits'), (Index: 339; Name: 'IsPlayersLastRiddenHorse'), (Index: 353; Name: 'IsActor'), (Index: 354; Name: 'IsEssential'), (Index: 358; Name: 'IsPlayerMovingIntoNewSpace'), (Index: 361; Name: 'GetTimeDead'), (Index: 362; Name: 'GetPlayerHasLastRiddenHorse'), (Index: 365; Name: 'GetPlayerInSEWorld') ); var wbCTDAFunctionEditInfo : string; function wbCTDAParamDescFromIndex(aIndex: Integer): PCTDAFunction; var L, H, I, C: Integer; begin Result := nil; L := Low(wbCTDAFunctions); H := High(wbCTDAFunctions); while L <= H do begin I := (L + H) shr 1; C := CmpW32(wbCTDAFunctions[I].Index, aIndex); if C < 0 then L := I + 1 else begin H := I - 1; if C = 0 then begin L := I; Result := @wbCTDAFunctions[L]; end; end; end; end; function wbCTDACompValueDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container: IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; if Integer(Container.ElementByName['Type'].NativeValue) and $04 <> 0 then Result := 1; end; function wbEFITOBMEParamDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var ParamInfo: Variant; Container: IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; ParamInfo := Container.ElementNativeValues['..\EFME\EFIT Param Info']; if VarIsNull(ParamInfo) or VarIsEmpty(ParamInfo) then else Result := ParamInfo; end; function wbEFIXParamDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var ParamInfo: Variant; Container: IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; ParamInfo := Container.ElementNativeValues['..\EFME\EFIX Param Info']; if VarIsNull(ParamInfo) or VarIsEmpty(ParamInfo) then else Result := ParamInfo; end; function wbCTDAParam1Decider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Desc: PCTDAFunction; Container: IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; Desc := wbCTDAParamDescFromIndex(Container.ElementByName['Function'].NativeValue); if Assigned(Desc) then Result := Succ(Integer(Desc.ParamType1)); end; function wbCTDAParam2Decider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Desc: PCTDAFunction; Container: IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; Desc := wbCTDAParamDescFromIndex(Container.ElementByName['Function'].NativeValue); if Assigned(Desc) then Result := Succ(Integer(Desc.ParamType2)); end; { function wbCTDAFunction(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Desc: PCTDAFunction; begin Result := ''; case aType of ctToStr: begin Desc := wbCTDAParamDescFromIndex(aInt); if Assigned(Desc) then Result := Desc.Name else Result := ''; end; ctToSortKey: Result := IntToHex(aInt, 8); ctCheck: begin Desc := wbCTDAParamDescFromIndex(aInt); if Assigned(Desc) then Result := '' else Result := ''; end; end; end; } function wbCTDAFunctionToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Desc : PCTDAFunction; i : Integer; begin Result := ''; case aType of ctToStr, ctToEditValue: begin Desc := wbCTDAParamDescFromIndex(aInt); if Assigned(Desc) then Result := Desc.Name else if aType = ctToEditValue then Result := IntToStr(aInt) else Result := ''; end; ctToSortKey: Result := IntToHex(aInt, 8); ctCheck: begin Desc := wbCTDAParamDescFromIndex(aInt); if Assigned(Desc) then Result := '' else Result := ''; end; ctEditType: Result := 'ComboBox'; ctEditInfo: begin Result := wbCTDAFunctionEditInfo; if Result = '' then begin with TStringList.Create do try for i := Low(wbCTDAFunctions) to High(wbCTDAFunctions) do Add(wbCTDAFunctions[i].Name); Sort; Result := CommaText; finally Free; end; wbCTDAFunctionEditInfo := Result; end; end; end; end; function wbCTDAFunctionToInt(const aString: string; const aElement: IwbElement): Int64; var i: Integer; begin for i := Low(wbCTDAFunctions) to High(wbCTDAFunctions) do with wbCTDAFunctions[i] do if SameText(Name, aString) then begin Result := Index; Exit; end; Result := StrToInt64(aString); end; function wbCTDAParam2VariableNameToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainerElementRef; Param1 : IwbElement; MainRecord : IwbMainRecord; BaseRecord : IwbMainRecord; ScriptRef : IwbElement; Script : IwbMainRecord; Variables : TStringList; LocalVars : IwbContainerElementRef; LocalVar : IwbContainerElementRef; i, j : Integer; s : string; begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctToEditValue: Result := IntToStr(aInt); ctToSortKey: begin Result := IntToHex64(aInt, 8); Exit; end; ctCheck: Result := ''; ctEditType: Result := ''; ctEditInfo: Result := ''; end; if not Assigned(aElement) then Exit; Container := GetContainerRefFromUnionOrValue(aElement); if not Assigned(Container) then Exit; Param1 := Container.ElementByName['Parameter #1']; if not Assigned(Param1) then Exit; MainRecord := nil; if not Supports(Param1.LinksTo, IwbMainRecord, MainRecord) then Exit; { if Param1.NativeValue = 0 then if Supports(Container.Container, IwbContainerElementRef, Container) then for i := 0 to Pred(Container.ElementCount) do if Supports(Container.Elements[i], IwbContainerElementRef, Container2) then if SameText(Container2.ElementValues['Function'], 'GetIsID') then begin Param1 := Container2.ElementByName['Parameter #1']; if Supports(Param1.LinksTo, IwbMainRecord, MainRecord) then Break; end;} if not Assigned(MainRecord) then Exit; BaseRecord := MainRecord.BaseRecord; if Assigned(BaseRecord) then MainRecord := BaseRecord; ScriptRef := MainRecord.RecordBySignature['SCRI']; if not Assigned(ScriptRef) then begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end; Exit; end; if not Supports(ScriptRef.LinksTo, IwbMainRecord, Script) then begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end; Exit; end; case aType of ctEditType: begin Result := 'ComboBox'; Exit; end; ctEditInfo: Variables := TStringList.Create; else Variables := nil; end; try if Supports(Script.ElementByName['Local Variables'], IwbContainerElementRef, LocalVars) then begin for i := 0 to Pred(LocalVars.ElementCount) do if Supports(LocalVars.Elements[i], IwbContainerElementRef, LocalVar) then begin j := LocalVar.ElementNativeValues['SLSD\Index']; s := LocalVar.ElementNativeValues['SCVR']; if Assigned(Variables) then Variables.AddObject(s, TObject(j)) else if j = aInt then begin case aType of ctToStr, ctToEditValue: Result := s; ctCheck: Result := ''; end; Exit; end; end; end; case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; ctEditInfo: begin Variables.Sort; Result := Variables.CommaText; end; end; finally FreeAndNil(Variables); end; end; function wbCTDAParam2VariableNameToInt(const aString: string; const aElement: IwbElement): Int64; var Container : IwbContainerElementRef; Param1 : IwbElement; MainRecord : IwbMainRecord; BaseRecord : IwbMainRecord; ScriptRef : IwbElement; Script : IwbMainRecord; LocalVars : IwbContainerElementRef; LocalVar : IwbContainerElementRef; i, j : Integer; s : string; begin Result := StrToInt64Def(aString, Low(Cardinal)); if Result <> Low(Cardinal) then Exit; if not Assigned(aElement) then raise Exception.Create('aElement not specified'); Container := GetContainerRefFromUnionOrValue(aElement); if not Assigned(Container) then raise Exception.Create('Container not assigned'); Param1 := Container.ElementByName['Parameter #1']; if not Assigned(Param1) then raise Exception.Create('Could not find "Parameter #1"'); if not Supports(Param1.LinksTo, IwbMainRecord, MainRecord) then raise Exception.Create('"Parameter #1" does not reference a valid main record'); BaseRecord := MainRecord.BaseRecord; if Assigned(BaseRecord) then MainRecord := BaseRecord; ScriptRef := MainRecord.RecordBySignature['SCRI']; if not Assigned(ScriptRef) then raise Exception.Create('"'+MainRecord.ShortName+'" does not contain a SCRI subrecord'); if not Supports(ScriptRef.LinksTo, IwbMainRecord, Script) then raise Exception.Create('"'+MainRecord.ShortName+'" does not have a valid script'); if Supports(Script.ElementByName['Local Variables'], IwbContainerElementRef, LocalVars) then begin for i := 0 to Pred(LocalVars.ElementCount) do if Supports(LocalVars.Elements[i], IwbContainerElementRef, LocalVar) then begin j := LocalVar.ElementNativeValues['SLSD\Index']; s := LocalVar.ElementNativeValues['SCVR']; if SameText(s, Trim(aString)) then begin Result := j; Exit; end; end; end; raise Exception.Create('Variable "'+aString+'" was not found in "'+MainRecord.ShortName+'"'); end; function wbCTDAParam2QuestStageToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainerElementRef; Param1 : IwbElement; MainRecord : IwbMainRecord; EditInfos : TStringList; Stages : IwbContainerElementRef; Stage : IwbContainerElementRef; i, j : Integer; s, t : string; begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctToEditValue: Result := IntToStr(aInt); ctToSortKey: begin Result := IntToHex64(aInt, 8); Exit; end; ctCheck: Result := ''; ctEditType: Result := ''; ctEditInfo: Result := ''; end; if not Assigned(aElement) then Exit; Container := GetContainerRefFromUnionOrValue(aElement); if not Assigned(Container) then Exit; Param1 := Container.ElementByName['Parameter #1']; if not Assigned(Param1) then Exit; if not Supports(Param1.LinksTo, IwbMainRecord, MainRecord) then Exit; if MainRecord.Signature <> QUST then begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end; Exit; end; case aType of ctEditType: begin Result := 'ComboBox'; Exit; end; ctEditInfo: EditInfos := TStringList.Create; else EditInfos := nil; end; try if Supports(MainRecord.ElementByName['Stages'], IwbContainerElementRef, Stages) then begin for i := 0 to Pred(Stages.ElementCount) do if Supports(Stages.Elements[i], IwbContainerElementRef, Stage) then begin j := Stage.ElementNativeValues['INDX']; s := Trim(Stage.ElementValues['Log Entries\Log Entry\CNAM']); t := IntToStr(j); while Length(t) < 3 do t := '0' + t; if s <> '' then t := t + ' ' + s; if Assigned(EditInfos) then EditInfos.AddObject(t, TObject(j)) else if j = aInt then begin case aType of ctToStr, ctToEditValue: Result := t; ctCheck: Result := ''; end; Exit; end; end; end; case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; ctEditInfo: begin EditInfos.Sort; Result := EditInfos.CommaText; end; end; finally FreeAndNil(EditInfos); end; end; function wbCTDAParam2QuestStageToInt(const aString: string; const aElement: IwbElement): Int64; var i : Integer; s : string; begin i := 1; s := Trim(aString); while (i <= Length(s)) and (s[i] in ['0'..'9']) do Inc(i); s := Copy(s, 1, Pred(i)); Result := StrToInt(s); end; procedure wbRemoveOFST(const aElement: IwbElement); var Container: IwbContainer; rOFST: IwbRecord; begin if Supports(aElement, IwbContainer, Container) then begin rOFST := Container.RecordBySignature[OFST]; if Assigned(rOFST) then Container.RemoveElement(rOFST); end; end; procedure wbCELLAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; Container2 : IwbContainerElementRef; MainRecord : IwbMainRecord; i : Integer; IsInterior : Boolean; GroupRecord : IwbGroupRecord; Removed : Boolean; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; if not Container.ElementExists['DATA'] then Exit; IsInterior := (Container.ElementNativeValues['DATA'] and 1) <> 0; if IsInterior then Container.Add('XCLL') else begin Container.Add('XCLC'); if (Container.ElementNativeValues['DATA'] and 2) = 0 then if Supports(MainRecord.Container, IwbGroupRecord, GroupRecord) then if GroupRecord.GroupType = 1 then Container.ElementNativeValues['DATA'] := Container.ElementNativeValues['DATA'] or 2; end; Removed := False; if Supports(Container.ElementBySignature[XCLR], IwbContainerElementRef, Container2) then begin for i:= Pred(Container2.ElementCount) downto 0 do if not Supports(Container2.Elements[i].LinksTo, IwbMainRecord, MainRecord) or (MainRecord.Signature <> 'REGN') then begin if not Removed then begin Removed := True; Container2.MarkModifiedRecursive; end; Container2.RemoveElement(i); end; if Container2.ElementCount < 1 then Container2.Remove; end; finally wbEndInternalEdit; end; end; procedure wbMGEFAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; MainRecord : IwbMainRecord; _File : IwbFile; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; _File := MainRecord._File; if not Assigned(_File) then Exit; if not SameText(_File.FileName, 'Oblivion.esm') then Exit; if SameText(MainRecord.EditorID, 'RSFI') or SameText(MainRecord.EditorID, 'RSFR') or SameText(MainRecord.EditorID, 'RSPA') or SameText(MainRecord.EditorID, 'RSSH') then begin Container.ElementNativeValues['DATA - Data\Flags'] := Cardinal(Container.ElementNativeValues['DATA - Data\Flags']) or $8; end; if SameText(MainRecord.EditorID, 'REAN') then begin Container.ElementNativeValues['DATA - Data\Flags'] := Cardinal(Container.ElementNativeValues['DATA - Data\Flags']) and not $20000; end; finally wbEndInternalEdit; end; end; procedure wbEFITAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; Element : IwbElement; ActorValue: Variant; MainRecord: IwbMainRecord; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; Element := Container.ElementByName['Magic effect name']; if not Assigned(Element) then Exit; if not Supports(Element.LinksTo, IwbMainRecord, MainRecord) then Exit; if MainRecord.Signature <> 'MGEF' then Exit; if (MainRecord.ElementNativeValues['DATA - Data\Flags'] and $01000000) = 0 then Exit; ActorValue := MainRecord.ElementNativeValues['DATA - Data\Assoc. Item']; if VarIsNull(ActorValue) or VarIsClear(ActorValue) then Exit; if VarCompareValue(ActorValue, Container.ElementNativeValues['Actor Value']) <> vrEqual then Container.ElementNativeValues['Actor Value'] := ActorValue; finally wbEndInternalEdit; end; end; procedure wbREFRAfterLoad(const aElement: IwbElement); var Container: IwbContainerElementRef; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; Container.RemoveElement('XPCI'); finally wbEndInternalEdit; end; end; procedure wbLIGHAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; MainRecord : IwbMainRecord; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; if Container.ElementExists['DATA'] then begin if SameValue(Container.ElementNativeValues['DATA\Falloff Exponent'], 0.0) then Container.ElementNativeValues['DATA\Falloff Exponent'] := 1.0; if SameValue(Container.ElementNativeValues['DATA\FOV'], 0.0) then Container.ElementNativeValues['DATA\FOV'] := 90.0; end; finally wbEndInternalEdit; end; end; procedure wbLVLAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; MainRecord : IwbMainRecord; Chance : Integer; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; Container.RemoveElement('DATA'); Chance := Container.ElementNativeValues['LVLD']; if (Chance and $80) <> 0 then begin Chance := Chance and not $80; Container.ElementNativeValues['LVLD'] := Chance; Container.ElementNativeValues['LVLF'] := Container.ElementNativeValues['LVLF'] or $01; end; finally wbEndInternalEdit; end; end; procedure wbRPLDAfterLoad(const aElement: IwbElement); var Container : IwbContainer; a, b : Single; NeedsFlip : Boolean; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainer, Container) then Exit; NeedsFlip := False; if Container.ElementCount > 1 then begin a := (Container.Elements[0] as IwbContainer).Elements[0].NativeValue; b := (Container.Elements[Pred(Container.ElementCount)] as IwbContainer).Elements[0].NativeValue; case CompareValue(a, b) of EqualsValue: begin a := (Container.Elements[0] as IwbContainer).Elements[1].NativeValue; b := (Container.Elements[Pred(Container.ElementCount)] as IwbContainer).Elements[1].NativeValue; NeedsFlip := CompareValue(a, b) = GreaterThanValue; end; GreaterThanValue: NeedsFlip := True; end; end; if NeedsFlip then Container.ReverseElements; finally wbEndInternalEdit; end; end; procedure wbPGRDAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; MainRecord : IwbMainRecord; Points : IwbContainerElementRef; Connections : IwbContainerElementRef; i, j : Integer; Point : IwbContainerElementRef; Connection : IwbContainerElementRef; Removed : Boolean; FirstRemoved: Boolean; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; if not Supports(Container.ElementBySignature['PGRP'], IwbContainerElementRef, Points) then Exit; if not Container.ElementExists['PGAG'] then Container.Add('PGAG').DataSize := (Points.ElementCount + 7) div 8; MainRecord.IsCompressed := True; if not Supports(Container.ElementBySignature['PGRR'], IwbContainerElementRef, Connections) then Exit; if Points.ElementCount < Connections.ElementCount then Exit; FirstRemoved := False; for i := Pred(Connections.ElementCount) downto 0 do begin Connection := Connections.Elements[i] as IwbContainerElementRef; Removed := False; j := Connection.ElementCount; while j > 0 do begin Dec(j); if Connection.Elements[j].NativeValue = 65535 then begin if not FirstRemoved then begin FirstRemoved := True; Connections.MarkModifiedRecursive; end; Connection.Elements[j].Remove; Removed := True; end else Break; end; if Removed then begin Point := Points.Elements[i] as IwbContainerElementRef; Point.ElementNativeValues['Connections'] := Connection.ElementCount; end; end; finally wbEndInternalEdit; end; end; procedure wbPGRRPointAfterLoad(const aElement: IwbElement); var Connections : IwbContainerElementRef; i : Integer; // Index : Integer; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Connections) then Exit; for i := Pred(Connections.ElementCount) downto 0 do if Connections.Elements[i].NativeValue = 65535 then begin Connections.RemoveElement(i); end; { if Removed then begin Index := aElement.Container.ElementCount; (aElement.ContainingMainRecord.RecordBySignature['PGRP'].Elements[Index] as IwbContainer).Elements[3].NativeValue := Connections.ElementCount; end;} finally wbEndInternalEdit; end; end; procedure wbPGRIPointerAfterLoad(const aElement: IwbElement); var Connections : IwbContainerElementRef; i, j : Integer; s : string; Keys : TStringList; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Connections) then Exit; Keys := TStringList.Create; try Keys.Sorted := True; Keys.Duplicates := dupError; for i := Pred(Connections.ElementCount) downto 0 do begin s := Connections.Elements[i].SortKey[True]; if Keys.Find(s, j) then Connections.RemoveElement(i, True) else Keys.Add(s); end; finally Keys.Free; end; finally wbEndInternalEdit; end; end; { function wbPGRPConnectionsCallback(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Point : IwbContainerElementRef; s : string; i : Integer; PGRP : IwbContainerElementRef; PGRD : IwbMainRecord; PGRR : IwbContainerElementRef; Cons : IwbContainerElementRef; begin Result := ''; if aType = ctCheck then Exit; if wbFixupPGRD and (aInt > 0) and Assigned(aElement) and (aElement.ElementStates * [esModified] = []) then begin Point := aElement.Container as IwbContainerElementRef; if Assigned(Point) then begin s := Trim(Point.Name); i := Pos('#', s); if i > 0 then begin i := StrToIntDef(Copy(s, i+1, High(Integer)), -1); if i >= 0 then begin PGRP := Point.Container as IwbContainerElementRef; if Assigned(PGRP) then begin if Supports(PGRP.Container, IwbMainRecord, PGRD) then begin if (csInitDone in PGRD.ContainerStates) and (PGRD.Signature = 'PGRD') then begin PGRR := PGRD.RecordBySignature['PGRR'] as IwbContainerElementRef; if Assigned(PGRR) and (PGRR.ElementCount > 0) and (csInitDone in PGRR.ContainerStates) then begin if (i < PGRR.ElementCount) then begin if Supports(PGRR.Elements[i], IwbContainer, Cons) then begin aInt := Cons.ElementCount; end; end; end; PGRR := nil; end; end; end; end; end; end; end; if aType = ctToSortKey then Result := IntToHex64(aInt, 2) else if aType = ctToStr then Result := IntToStr(aInt); end; } function wbPxDTLocationDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container: IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; Result := Container.ElementByName['Type'].NativeValue; end; function wbCalcPGRRSize(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Cardinal; var Index: Integer; begin Index := aElement.Container.ElementCount; Result := ((aElement.Container.Container as IwbMainRecord).RecordBySignature['PGRP'].Elements[Pred(Index)] as IwbContainer).Elements[3].NativeValue; end; function wbMGEFFAssocItemDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var s: string; Container: IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; s := Container.ElementByName['Flags'].SortKey[False]; if s[17] = '1' then Result := 1 else if s[18] = '1' then Result := 2 else if s[19] = '1' then Result := 3 else if s[25] = '1' then Result := 4; end; function wbEDDXDontShow(const aElement: IwbElement): Boolean; var MainRecord : IwbMainRecord; begin Result := True; if Supports(aElement.Container, IwbMainRecord, MainRecord) then Result := not Assigned(MainRecord.ElementBySignature[OBME]); end; function wbOBMEDontShow(const aElement: IwbElement): Boolean; var _File: IwbFile; begin if not Assigned(aElement) then begin Result := True; Exit; end; Result := False; _File := aElement._File; if Assigned(_File) and SameText(_File.FileName, 'Oblivion.esm') then Result := True; end; procedure DefineTES3; begin wbHeaderSignature := 'TES3'; wbRecordFlags := wbInteger('Record Flags', itU32, wbFlags([ {0x00000001}'ESM', {0x00000002}'', {0x00000004}'', {0x00000008}'', {0x00000010}'', {0x00000020}'Deleted', {0x00000040}'Border Region / Actor Value', {0x00000080}'Turn Off Fire / Actor Value', {0x00000100}'', {0x00000200}'Casts shadows', {0x00000400}'Quest item / Persistent reference / Show in Menu', {0x00000800}'Initially disabled', {0x00001000}'Ignored', {0x00002000}'', {0x00004000}'', {0x00008000}'Visible when distant', {0x00010000}'', {0x00020000}'Dangerous / Off limits (Interior cell)', {0x00040000}'Compressed ', {0x00080000}'Can''t wait' ])); wbMainRecordHeader := wbStruct('Record Header', [ wbString('Signature', 4, cpCritical), wbInteger('Data Size', itU32, nil, cpIgnore), wbRecordFlags, wbFormID('FormID', cpFormID), wbByteArray('Unknown', 4, cpIgnore) ]); wbSizeOfMainRecordStruct := 20; wbIgnoreRecords.Add(XXXX); wbXRGD := wbByteArray(XRGD, 'Ragdoll Data'); wbMusicEnum := wbEnum(['Default', 'Public', 'Dungeon']); wbEDID := wbString(EDID, 'Editor ID', 0, cpBenign); wbFULL := wbString(FULL, 'Name', 0, cpTranslate); wbFULLReq := wbString(FULL, 'Name', 0, cpNormal, True); wbDESC := wbString(DESC, 'Description', 0, cpTranslate); wbXSCL := wbFloat(XSCL, 'Scale'); wbPosRot := wbStruct('Position/Rotation', [ wbStruct('Position', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), wbStruct('Rotation', [ wbFloat('X', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Y', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Z', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize) ]) ]); wbDATAPosRot := wbStruct(DATA, 'Position/Rotation', [ wbStruct('Position', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), wbStruct('Rotation', [ wbFloat('X', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Y', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Z', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize) ]) ], cpNormal, True); wbMODL := wbRStructSK([0], 'Model', [ wbString(MODL, 'Model Filename'), wbFloat(MODB, 'Bound Radius', cpBenign), wbByteArray(MODT, 'Texture Files Hashes', 0, cpIgnore) // wbArray(MODT, 'Unknown', // wbByteArray('Unknown', 24, cpBenign), // 0, nil, cpBenign) ], []); wbSCRI := wbFormIDCk(SCRI, 'Script', [SCPT]); wbENAM := wbFormIDCk(ENAM, 'Enchantment', [ENCH]); wbXLOD := wbArray(XLOD, 'Distant LOD Data', wbFloat('Unknown'), 3); wbXESP := wbStruct(XESP, 'Enable Parent', [ wbFormIDCk('Reference', [PLYR, REFR, ACRE, ACHR]), wbInteger('Flags', itU8, wbFlags([ 'Set Enable State to Opposite of Parent' ])), wbByteArray('Unused', 3) ]); wbRecord(ACHR, 'Placed NPC', [ wbEDID, wbFormIDCk(NAME, 'Base', [NPC_], False, cpNormal, True), wbRStruct('Unused', [ wbFormIDCk(XPCI, 'Unused', [CELL]), wbString(FULL, 'Unused') ], []), wbXLOD, wbXESP, wbFormIDCk(XMRC, 'Merchant container', [REFR], True), wbFormIDCk(XHRS, 'Horse', [ACRE], True), wbXRGD, wbXSCL, wbDATAPosRot ], True, wbPlacedAddInfo, cpNormal, False, wbREFRAfterLoad); wbXOWN := wbFormIDCk(XOWN, 'Owner', [FACT, NPC_]); wbXGLB := wbFormIDCk(XGLB, 'Global variable', [GLOB]); wbRecord(ACRE, 'Placed Creature', [ wbEDID, wbFormIDCk(NAME, 'Base', [CREA], False, cpNormal, True), wbRStruct('Ownership', [ wbXOWN, wbInteger(XRNK, 'Faction rank', itS32), wbXGLB ], []), wbXESP, wbXRGD, wbXSCL, wbDATAPosRot ], True, wbPlacedAddInfo); wbRecord(ACTI, 'Activator', [ wbEDID, wbFULL, wbMODL, wbSCRI, wbFormIDCk(SNAM, 'Sound', [SOUN]) ]); wbICON := wbString(ICON, 'Icon filename'); wbActorValueEnum := wbEnum([ 'Strength', 'Intelligence', 'Willpower', 'Agility', 'Speed', 'Endurance', 'Personality', 'Luck', 'Health', 'Magicka', 'Fatigue', 'Encumbrance', 'Armorer', 'Athletics', 'Blade', 'Block', 'Blunt', 'Hand To Hand', 'Heavy Armor', 'Alchemy', 'Alteration', 'Conjuration', 'Destruction', 'Illusion', 'Mysticism', 'Restoration', 'Acrobatics', 'Light Armor', 'Marksman', 'Mercantile', 'Security', 'Sneak', 'Speechcraft', {33} 'Aggression', {34} 'Confidence', {35} 'Energy', {36} 'Responsibility', {37} 'Bounty', {38} 'Fame', {39} 'Infamy', {40} 'Magicka Multiplier', {41} 'Night Eye Bonus', {42} 'Attack Bonus', {43} 'Defend Bonus', {44} 'Casting Penalty', {45} 'Blindness', {46} 'Chameleon', {47} 'Invisibility', {48} 'Paralysis', {49} 'Silence', {50} 'Confusion', {51} 'Detect Item Range', {52} 'Spell Absorb Chance', {53} 'Spell Reflect Chance', {54} 'Swim Speed Multiplier', {55} 'Water Breathing', {56} 'Water Walking', {57} 'Stunted Magicka', {58} 'Detect Life Range', {59} 'Reflect Damage', {60} 'Telekinesis', {61} 'Resist Fire', {62} 'Resist Frost', {63} 'Resist Disease', {64} 'Resist Magic', {65} 'Resist Normal Weapons', {66} 'Resist Paralysis', {67} 'Resist Poison', {68} 'Resist Shock', {69} 'Vampirism', {70} 'Darkness', {71} 'Resist Water Damage' ], [ -1, 'None' ]); wbSkillEnum := wbEnum([ 'Armorer', 'Athletics', 'Blade', 'Block', 'Blunt', 'Hand To Hand', 'Heavy Armor', 'Alchemy', 'Alteration', 'Conjuration', 'Destruction', 'Illusion', 'Mysticism', 'Restoration', 'Acrobatics', 'Light Armor', 'Marksman', 'Mercantile', 'Security', 'Sneak', 'Speechcraft' ], [ -1, 'None' ]); wbEFID := wbInteger(EFID, 'Magic effect name', itU32, wbChar4, cpNormal, True); wbEFIDOBME := wbStringMgefCode(EFID, 'Magic Effect Code', 4, cpNormal, True); wbEFIT := wbStructSK(EFIT, [4, 5], '', [ wbInteger('Magic effect name', itU32, wbChar4), wbInteger('Magnitude', itU32), wbInteger('Area', itU32), wbInteger('Duration', itU32), wbInteger('Type', itU32, wbEnum(['Self', 'Touch', 'Target'])), wbInteger('Actor Value', itS32, wbActorValueEnum) ], cpNormal, True, nil, -1, wbEFITAfterLoad); wbEFITOBME := wbStructSK(EFIT, [4, 5], '', [ wbStringMgefCode('Magic Effect Code', 4), wbInteger('Magnitude', itU32), wbInteger('Area', itU32), wbInteger('Duration', itU32), wbInteger('Type', itU32, wbEnum(['Self', 'Touch', 'Target'])), wbUnion('Param #1', wbEFITOBMEParamDecider, [ wbByteArray('Param #1 - Unknown Type', 4), wbFormID('Param #1 - FormID'), wbStringMgefCode('Param #1 - Magic Effect Code', 4), wbFormIDCk('Param #1 - Actor Value', [ACVA]) ]) ], cpNormal, True, nil, -1{, wbEFITAfterLoad}); wbEFIX := wbStructSK(EFIX, [3], '', [ wbInteger('Override Mask', itU32, wbFlags([])), wbInteger('Flags', itU32, wbFlags([])), wbFloat('Base Cost'), wbUnion('Param #2', wbEFIXParamDecider, [ wbByteArray('Param #2 - Unknown Type', 4), wbFormID('Param #2 - FormID'), wbStringMgefCode('Param #2 - Magic Effect Code', 4), wbFormIDCk('Param #2 - Actor Value', [ACVA]) ]) ], cpNormal, True, nil, -1, wbEFITAfterLoad); wbMagicSchoolEnum := wbEnum([ 'Alteration', 'Conjuration', 'Destruction', 'Illusion', 'Mysticism', 'Restoration' ]); wbSCIT := wbRStructSK([0], 'Script effect', [ wbStructSK(SCIT, [0], 'Script effect data', [ wbFormIDCk('Script effect', [NULL, SCPT]), wbInteger('Magic school', itU32, wbMagicSchoolEnum), wbInteger('Visual effect name', itU32, wbChar4), wbInteger('Flags', itU8, wbFlags(['Hostile'])), wbByteArray('Unused', 3) ], cpNormal, True, nil, 1), wbFULLReq ], []); wbSCITOBME := wbRStructSK([0], 'Script effect', [ wbStructSK(SCIT, [0], 'Script effect data', [ wbFormIDCk('Script effect', [NULL, SCPT]), wbInteger('Magic school', itU32, wbMagicSchoolEnum), wbStringMgefCode('Visual Effect Code', 4), wbInteger('Flags', itU8, wbFlags(['Hostile'])), wbByteArray('Unused', 3) ], cpNormal, True, nil, 1), wbFULLReq ], []); wbOBMEResolutionInfo := wbEnum(['None', 'FormID', 'Magic Effect Code', 'Actor Value']); wbEffects := wbRUnion('Effects', [ wbRStruct('Effects', [ wbRStructs('Effects','Effect', [ wbEFID, wbEFIT, wbSCIT ], []) ], []), wbRStruct('Effects', [ wbRStructs('Effects','Effect', [ wbStruct(EFME, 'Oblivion Magic Extender', [ wbInteger('Record Version', itU8), wbStruct('OBME Version', [ wbInteger('Beta', itU8), wbInteger('Minor', itU8), wbInteger('Major', itU8) ]), wbInteger('EFIT Param Info', itU8, wbOBMEResolutionInfo), wbInteger('EFIX Param Info', itU8, wbOBMEResolutionInfo), wbByteArray('Unused', $0A) ]), wbEFIDOBME, wbEFITOBME, wbSCITOBME, wbString(EFII, 'Icon'), wbEFIX ], []), wbEmpty(EFXX, 'Effects End Marker', cpNormal, True), wbFULLReq ], []) ], []); wbRecord(ALCH, 'Potion', [ wbEDID, wbStruct(OBME, 'Oblivion Magic Extender', [ wbInteger('Record Version', itU8), wbStruct('OBME Version', [ wbInteger('Beta', itU8), wbInteger('Minor', itU8), wbInteger('Major', itU8) ]), wbByteArray('Unused', $1C) ], cpNormal, False, wbOBMEDontShow), wbFULL, wbMODL, wbICON, wbSCRI, wbFloat(DATA, 'Weight', cpNormal, True), wbStruct(ENIT, '', [ wbInteger('Value', itS32), wbInteger('Flags', itU8, wbFlags(['No auto-calculation', 'Food item'])), wbByteArray('Unused', 3) ], cpNormal, True), wbEffects ]); wbRecord(AMMO, 'Ammunition', [ wbEDID, wbFULL, wbMODL, wbICON, wbFormIDCk(ENAM, 'Enchantment', [ENCH]), wbInteger(ANAM, 'Enchantment Points', itU16), wbStruct(DATA, '', [ wbFloat('Speed'), wbInteger('Flags', itU8, wbFlags(['Ignores Normal Weapon Resistance'])), wbByteArray('Unused', 3), wbInteger('Value', itU32), wbFloat('Weight'), wbInteger('Damage', itU16) ], cpNormal, True) ]); wbRecord(ANIO, 'Animated Object', [ wbEDID, wbMODL, wbFormIDCk(DATA, 'IDLE animation', [IDLE], False, cpNormal, True) ]); wbRecord(APPA, 'Alchemical Apparatus', [ wbEDID, wbFULL, wbMODL, wbICON, wbSCRI, wbStruct(DATA, '', [ wbInteger('Type', itU8, wbEnum(['Mortar and Pestle', 'Alembic', 'Calcinator', 'Retort'])), wbInteger('Value', itU32), wbFloat('Weight'), wbFloat('Quality') ], cpNormal, True) ]); wbRecord(ARMO, 'Armor', [ wbEDID, wbFULL, wbSCRI, wbENAM, wbInteger(ANAM, 'Enchantment Points', itU16), wbStruct(BMDT, '', [ wbInteger('Biped Flags', itU16, wbFlags([ {0x00000001} 'Head', {0x00000002} 'Hair', {0x00000004} 'Upper Body', {0x00000008} 'Lower Body', {0x00000010} 'Hand', {0x00000020} 'Foot', {0x00000040} 'Right Ring', {0x00000080} 'Left Ring', {0x00000100} 'Amulet', {0x00000200} 'Weapon', {0x00000400} 'Back Weapon', {0x00000800} 'Side Weapon', {0x00001000} 'Quiver', {0x00002000} 'Shield', {0x00004000} 'Torch', {0x00008000} 'Tail' ])), wbInteger('General Flags', itU8, wbFlags([ {0x0001} 'Hide Rings', {0x0002} 'Hide Amulets', {0x0004} '', {0x0008} '', {0x0010} '', {0x0020} '', {0x0040} 'Non-Playable', {0x0080} 'Heavy armor' ])), wbByteArray('Unused', 1) ], cpNormal, True), wbRStruct('Male biped model', [ wbString(MODL, 'Model Filename'), wbFloat(MODB, 'Bound Radius', cpBenign), wbByteArray(MODT, 'Texture Files Hashes', 0, cpIgnore) ], []), wbRStruct('Male world model', [ wbString(MOD2, 'Model Filename'), wbFloat(MO2B, 'Bound Radius', cpBenign), wbByteArray(MO2T, 'Texture Files Hashes', 0, cpIgnore) ], []), wbString(ICON, 'Male icon filename'), wbRStruct('Female biped model', [ wbString(MOD3, 'Model Filename'), wbFloat(MO3B, 'Bound Radius', cpBenign), wbByteArray(MO3T, 'Texture Files Hashes', 0, cpIgnore) ], []), wbRStruct('Female world model', [ wbString(MOD4, 'Model Filename'), wbFloat(MO4B, 'Bound Radius', cpBenign), wbByteArray(MO4T, 'Texture Files Hashes', 0, cpIgnore) ], []), wbString(ICO2, 'Female icon filename'), wbStruct(DATA, '', [ wbInteger('Armor', itU16, wbDiv(100)), wbInteger('Value', itU32), wbInteger('Health', itU32), wbFloat('Weight') ], cpNormal, True) ]); wbRecord(BOOK, 'Book', [ wbEDID, wbFULL, wbMODL, wbICON, wbSCRI, wbENAM, wbInteger(ANAM, 'Enchantment Points', itU16), wbDESC, wbStruct(DATA, '', [ wbInteger('Flags', itU8, wbFlags(['Scroll', 'Can''t be taken'])), wbInteger('Teaches', itS8, wbSkillEnum), wbInteger('Value', itU32), wbFloat('Weight') ], cpNormal, True) ], True); wbSPLO := wbFormIDCk(SPLO, 'Spell', [SPEL, LVSP]); wbSPLOs := wbRArrayS('Spells', wbSPLO); wbRecord(BSGN, 'Birthsign', [ wbEDID, wbFULL, wbICON, wbDESC, wbSPLOs ]); wbRecord(CELL, 'Cell', [ wbEDID, wbFULL, wbInteger(DATA, 'Flags', itU8, wbFlags([ {0x01} 'Is Interior Cell', {0x02} 'Has water', {0x04} 'Invert Fast Travel behavior', {0x08} 'Force hide land (exterior cell) / Oblivion interior (interior cell)', {0x10} '', {0x20} 'Public place', {0x40} 'Hand changed', {0x80} 'Behave like exterior' ]), cpNormal, True), wbStruct(XCLC, 'Grid', [ wbInteger('X', itS32), wbInteger('Y', itS32) ]), wbStruct(XCLL, 'Lighting', [ wbStruct('Ambient Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Directional Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Fog Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbFloat('Fog Near'), wbFloat('Fog Far'), wbInteger('Directional Rotation XY', itS32), wbInteger('Directional Rotation Z', itS32), wbFloat('Directional Fade', cpNormal, False, 1, -1, nil, nil, 1.0), wbFloat('Fog Clip Dist') ]), wbArrayS(XCLR, 'Regions', wbFormIDCk('Region', [REGN])), wbInteger(XCMT, 'Music', itU8, wbMusicEnum), wbFloat(XCLW, 'Water Height', cpBenign), wbFormIDCk(XCCM, 'Climate', [CLMT]), wbFormIDCk(XCWT, 'Water', [WATR]), wbRStruct('Ownership', [ wbXOWN, wbInteger(XRNK, 'Faction rank', itS32), wbXGLB ], [XCLW, XCMT]) ], True, wbCellAddInfo, cpNormal, False, wbCELLAfterLoad); wbServiceFlags := wbFlags([ {0x00000001} 'Weapons', {0x00000002} 'Armor', {0x00000004} 'Clothing', {0x00000008} 'Books', {0x00000010} 'Ingredients', {0x00000020} '', {0x00000040} '', {0x00000080} 'Lights', {0x00000100} 'Apparatus', {0x00000200} '', {0x00000400} 'Miscellaneous', {0x00000800} 'Spells', {0x00001000} 'Magic Items', {0x00002000} 'Potions', {0x00004000} 'Training', {0x00008000} '', {0x00010000} 'Recharge', {0x00020000} 'Repair' ]); wbSpecializationEnum := wbEnum(['Combat', 'Magic', 'Stealth']); wbRecord(CLAS, 'Class', [ wbEDID, wbFULL, wbDESC, wbICON, wbStruct(DATA, '', [ wbArrayS('Primary Attributes', wbInteger('Primary Attribute', itS32, wbActorValueEnum), 2), wbInteger('Specialization', itU32, wbSpecializationEnum), wbArrayS('Major Skills', wbInteger('Major Skill', itS32, wbActorValueEnum), 7), wbInteger('Flags', itU32, wbFlags(['Playable', 'Guard'])), wbInteger('Buys/Sells and Services', itU32, wbServiceFlags), wbInteger('Teaches', itS8, wbSkillEnum), wbInteger('Maximum training level', itU8), wbInteger('Unused', itU16) ], cpNormal, True, nil, 5) ]); wbRecord(CLMT, 'Climate', [ wbEDID, wbArrayS(WLST, 'Weather Types', wbStructSK([0], 'Weather Type', [ wbFormIDCk('Weather', [WTHR]), wbInteger('Chance', itS32) ])), wbString(FNAM, 'Sun Texture'), wbString(GNAM, 'Sun Glare Texture'), wbMODL, wbStruct(TNAM, 'Timing', [ wbStruct('Sunrise', [ wbInteger('Begin', itU8, wbClmtTime), wbInteger('End', itU8, wbClmtTime) ]), wbStruct('Sunset', [ wbInteger('Begin', itU8, wbClmtTime), wbInteger('End', itU8, wbClmtTime) ]), wbInteger('Volatility', itU8), wbInteger('Moons / Phase Length', itU8, wbClmtMoonsPhaseLength) ], cpNormal, True) ]); wbRecord(CLOT, 'Clothing', [ wbEDID, wbFULL, wbSCRI, wbENAM, wbInteger(ANAM, 'Enchantment Points', itU16), wbStruct(BMDT, '', [ wbInteger('Biped Flags', itU16, wbFlags([ {0x00000001} 'Head', {0x00000002} 'Hair', {0x00000004} 'Upper Body', {0x00000008} 'Lower Body', {0x00000010} 'Hand', {0x00000020} 'Foot', {0x00000040} 'Right Ring', {0x00000080} 'Left Ring', {0x00000100} 'Amulet', {0x00000200} 'Weapon', {0x00000400} 'Back Weapon', {0x00000800} 'Side Weapon', {0x00001000} 'Quiver', {0x00002000} 'Shield', {0x00004000} 'Torch', {0x00008000} 'Tail' ])), wbInteger('General Flags', itU8, wbFlags([ {0x0001} 'Hide Rings', {0x0002} 'Hide Amulets', {0x0004} '', {0x0008} '', {0x0010} '', {0x0020} '', {0x0040} 'Non-Playable', {0x0080} '' {Heavy armor} ])), wbByteArray('Unused', 1) ], cpNormal, True), wbRStruct('Male biped model', [ wbString(MODL, 'Model Filename'), wbFloat(MODB, 'Bound Radius', cpBenign), wbByteArray(MODT, 'Texture Files Hashes', 0, cpIgnore) ], []), wbRStruct('Male world model', [ wbString(MOD2, 'Model Filename'), wbFloat(MO2B, 'Bound Radius', cpBenign), wbByteArray(MO2T, 'Texture Files Hashes', 0, cpIgnore) ], []), wbString(ICON, 'Male icon filename'), wbRStruct('Female biped model', [ wbString(MOD3, 'Model Filename'), wbFloat(MO3B, 'Bound Radius', cpBenign), wbByteArray(MO3T, 'Texture Files Hashes', 0, cpIgnore) ], []), wbRStruct('Female world model', [ wbString(MOD4, 'Model Filename'), wbFloat(MO4B, 'Bound Radius', cpBenign), wbByteArray(MO4T, 'Texture Files Hashes', 0, cpIgnore) ], []), wbString(ICO2, 'Female icon filename'), wbStruct(DATA, '', [ wbInteger('Value', itU32), wbFloat('Weight') ], cpNormal, True) ]); wbCNTO := wbStructSK(CNTO, [0], 'Item', [ wbFormIDCk('Item', [ARMO, AMMO, MISC, WEAP, INGR, SLGM, SGST, BOOK, LVLI, KEYM, CLOT, ALCH, APPA, LIGH]), wbInteger('Count', itS32) ]); wbCNTOs := wbRArrayS('Items', wbCNTO); wbRecord(CONT, 'Container', [ wbEDID, wbFULL, wbMODL, wbSCRI, wbCNTOs, wbStruct(DATA, '', [ wbInteger('Flags', itU8, wbFlags(['', 'Respawns'])), wbFloat('Weight') ], cpNormal, True), wbFormIDCk(SNAM, 'Open sound', [SOUN]), wbFormIDCk(QNAM, 'Close sound', [SOUN]) ]); wbCSDT := wbRStructSK([0], 'Sound Type', [ wbInteger(CSDT, 'Type', itU32,wbEnum([ {0x00} 'Left Foot', {0x01} 'Right Foot', {0x02} 'Left Back Foot', {0x03} 'Right Back Foot', {0x04} 'Idle', {0x05} 'Aware', {0x06} 'Attack', {0x07} 'Hit', {0x08} 'Death', {0x09} 'Weapon' ])), wbRArrayS('Sounds', wbRStructSK([0], 'Sound', [ wbFormIDCk(CSDI, 'Sound', [SOUN], False, cpNormal, True), wbInteger(CSDC, 'Sound Chance', itU8, nil, cpNormal, True) ], []), cpNormal, True) ], []); wbCSDTs := wbRArrayS('Sound Types', wbCSDT); wbSoulGemEnum := wbEnum([ {0} 'None', {1} 'Petty', {2} 'Lesser', {3} 'Common', {4} 'Greater', {5} 'Grand' ]); wbRecord(CREA, 'Creature', [ wbEDID, wbFULL, wbMODL, wbCNTOs, wbSPLOs, wbArrayS(NIFZ, 'Models', wbStringLC('Model')), wbByteArray(NIFT, 'Texture Files Hashes', 0, cpIgnore), wbStruct(ACBS, 'Configuration', [ wbInteger('Flags', itU32, wbFlags([ {0x000001} 'Biped', {0x000002} 'Essential', {0x000004} 'Weapon & Shield', {0x000008} 'Respawn', {0x000010} 'Swims', {0x000020} 'Flies', {0x000040} 'Walks', {0x000080} 'PC Level Offset', {0x000100} 'Unused', //?? {0x000200} 'No Low Level Processing', {0x000400} 'Unused', //?? {0x000800} 'No Blood Spray', {0x001000} 'No Blood Decal', {0x002000} '', {0x004000} '', {0x008000} 'No Head', {0x010000} 'No Right Arm', {0x020000} 'No Left Arm', {0x040000} 'No Combat in Water', {0x080000} 'No Shadow', {0x100000} 'No Corpse Check' ])), wbInteger('Base spell points', itU16), wbInteger('Fatigue', itU16), wbInteger('Barter gold', itU16), wbInteger('Level (offset)', itS16), wbInteger('Calc min', itU16), wbInteger('Calc max', itU16) ], cpNormal, True), wbRArrayS('Factions', wbStructSK(SNAM, [0], 'Faction', [ wbFormIDCk('Faction', [FACT]), wbInteger('Rank', itU8), wbByteArray('Unused', 3) ]) ), wbFormIDCk(INAM, 'Death item', [LVLI]), wbSCRI, wbStruct(AIDT, 'AI Data', [ wbInteger('Aggression', itU8), wbInteger('Confidence', itU8), wbInteger('Energy Level', itU8), wbInteger('Responsibility', itU8), wbInteger('Buys/Sells and Services', itU32, wbServiceFlags), wbInteger('Teaches', itS8, wbSkillEnum), wbInteger('Maximum training level', itU8), wbByteArray('Unused', 2) ], cpNormal, True), wbRArray('AI Packages', wbFormIDCk(PKID, 'AI Package', [PACK])), wbArrayS(KFFZ, 'Animations', wbStringLC('Animation')), wbStruct(DATA, 'Creature Data', [ wbInteger('Type', itU8, wbEnum([ 'Creature', 'Daedra', 'Undead', 'Humanoid', 'Horse', 'Giant' ])), wbInteger('Combat Skill', itU8), wbInteger('Magic Skill', itU8), wbInteger('Stealth Skill', itU8), wbInteger('Soul', itU8, wbSoulGemEnum), wbByteArray('Unused', 1), wbInteger('Health', itU16), wbByteArray('Unused', 2), wbInteger('Attack Damage', itU16), wbInteger('Strength', itU8), wbInteger('Intelligence', itU8), wbInteger('Willpower', itU8), wbInteger('Agility', itU8), wbInteger('Speed', itU8), wbInteger('Endurance', itU8), wbInteger('Personality', itU8), wbInteger('Luck', itU8) ], cpNormal, True), wbInteger(RNAM, 'Attack reach', itU8, nil, cpNormal, True), wbFormIDCk(ZNAM, 'Combat Style', [CSTY]), wbFloat(TNAM, 'Turning Speed', cpNormal, True), wbFloat(BNAM, 'Base Scale', cpNormal, True), wbFloat(WNAM, 'Foot Weight', cpNormal, True), wbString(NAM0, 'Blood Spray'), wbString(NAM1, 'Blood Decal'), wbFormIDCk(CSCR, 'Inherits Sounds from', [CREA]), wbCSDTs ], True); wbRecord(CSTY, 'Combat Style', [ wbEDID, wbStruct(CSTD, 'Standard', [ {000}wbInteger('Dodge % Chance', itU8), {001}wbInteger('Left/Right % Chance', itU8), {002}wbByteArray('Unused', 2), {004}wbFloat('Dodge L/R Timer (min)'), {008}wbFloat('Dodge L/R Timer (max)'), {012}wbFloat('Dodge Forward Timer (min)'), {016}wbFloat('Dodge Forward Timer (max)'), {020}wbFloat('Dodge Back Timer Min'), {024}wbFloat('Dodge Back Timer Max'), {028}wbFloat('Idle Timer min'), {032}wbFloat('Idle Timer max'), {036}wbInteger('Block % Chance', itU8), {037}wbInteger('Attack % Chance', itU8), {038}wbByteArray('Unused', 2), {040}wbFloat('Recoil/Stagger Bonus to Attack'), {044}wbFloat('Unconscious Bonus to Attack'), {048}wbFloat('Hand-To-Hand Bonus to Attack'), {052}wbInteger('Power Attack % Chance', itU8), {053}wbByteArray('Unused', 3), {056}wbFloat('Recoil/Stagger Bonus to Power'), {060}wbFloat('Unconscious Bonus to Power Attack'), {064}wbInteger('Power Attack - Normal', itU8), {065}wbInteger('Power Attack - Forward', itU8), {066}wbInteger('Power Attack - Back', itU8), {067}wbInteger('Power Attack - Left', itU8), {068}wbInteger('Power Attack - Right', itU8), {069}wbByteArray('Unused', 3), {072}wbFloat('Hold Timer (min)'), {076}wbFloat('Hold Timer (max)'), {080}wbInteger('Flags 1', itU8, wbFlags([ 'Advanced', 'Choose Attack using % Chance', 'Ignore Allies in Area', 'Will Yield', 'Rejects Yields', 'Fleeing Disabled', 'Prefers Ranged', 'Melee Alert OK' ])), {081}wbInteger('Acrobatic Dodge % Chance', itU8), {082}wbByteArray('Unused', 2), {084}wbFloat('Range Mult (Optimal)'), {088}wbFloat('Range Mult (Max)'), {092}wbFloat('Switch Distance (Melee)'), {096}wbFloat('Switch Distance (Ranged)'), {100}wbFloat('Buff standoff Distance'), {104}wbFloat('Ranged standoff Distance'), {108}wbFloat('Group standoff Distance'), {112}wbInteger('Rushing Attack % Chance', itU8), {113}wbByteArray('Unused', 3), {116}wbFloat('Rushing Attack Distance Mult'), {120}wbInteger('Flags 2', itU32, wbFlags([ 'Do Not Acquire' ])) ], cpNormal, True, nil, 31), wbStruct(CSAD, 'Advanced', [ wbFloat('Dodge Fatigue Mod Mult'), wbFloat('Dodge Fatigue Mod Base'), wbFloat('Encumb. Speed Mod Base'), wbFloat('Encumb. Speed Mod Mult'), wbFloat('Dodge While Under Attack Mult'), wbFloat('Dodge Not Under Attack Mult'), wbFloat('Dodge Back While Under Attack Mult'), wbFloat('Dodge Back Not Under Attack Mult'), wbFloat('Dodge Forward While Attacking Mult'), wbFloat('Dodge Forward Not Attacking Mult'), wbFloat('Block Skill Modifier Mult'), wbFloat('Block Skill Modifier Base'), wbFloat('Block While Under Attack Mult'), wbFloat('Block Not Under Attack Mult'), wbFloat('Attack Skill Modifier Mult'), wbFloat('Attack Skill Modifier Base'), wbFloat('Attack While Under Attack Mult'), wbFloat('Attack Not Under Attack Mult'), wbFloat('Attack During Block Mult'), wbFloat('Power Att. Fatigue Mod Base'), wbFloat('Power Att. Fatigue Mod Mult') ]) ]); wbRecord(DIAL, 'Dialog Topic', [ wbEDID, wbRArrayS('Quests', wbFormIDCk(QSTI, 'Quest', [QUST], False, cpBenign)), wbRArrayS('Quests?', wbFormIDCk(QSTR, 'Quest?', [QUST], False, cpBenign)), wbFULL, wbInteger(DATA, 'Type', itU8, wbEnum([ {0} 'Topic', {1} 'Conversation', {2} 'Combat', {3} 'Persuasion', {4} 'Detection', {5} 'Service', {6} 'Miscellaneous' ]), cpNormal, True) ], True); wbRecord(DOOR, 'Door', [ wbEDID, wbFULL, wbMODL, wbSCRI, wbFormIDCk(SNAM, 'Open sound', [SOUN]), wbFormIDCk(ANAM, 'Close sound', [SOUN]), wbFormIDCk(BNAM, 'Loop sound', [SOUN]), wbInteger(FNAM, 'Flags', itU8, wbFlags([ {0x01} 'Oblivion gate', {0x02} 'Automatic door', {0x04} 'Hidden', {0x08} 'Minimal use' ]), cpNormal, True), wbRArrayS('Random teleport destinations', wbFormIDCk(TNAM, 'Destination', [CELL, WRLD])) ]); wbBlendModeEnum := wbEnum([ '', 'Zero', 'One', 'Source Color', 'Source Inverse Color', 'Source Alpha', 'Source Inverted Alpha', 'Dest Alpha', 'Dest Inverted Alpha', 'Dest Color', 'Dest Inverse Color', 'Source Alpha SAT' ]); wbBlendOpEnum := wbEnum([ '', 'Add', 'Subtract', 'Reverse Subtract', 'Minimum', 'Maximum' ]); wbZTestFuncEnum := wbEnum([ '', '', '', 'Equal To', 'Normal', 'Greater Than', '', 'Greater Than or Equal Than', 'Always Show' ]); wbRecord(EFSH, 'Effect Shader', [ wbEDID, wbString(ICON, 'Fill Texture'), wbString(ICO2, 'Particle Shader Texture'), wbStruct(DATA, '', [ wbInteger('Flags', itU8, wbFlags([ {0} 'No Membrane Shader', {1} '', {2} '', {3} 'No Particle Shader', {4} 'Edge Effect - Inverse', {5} 'Membrane Shader - Affect Skin Only' ])), wbByteArray('Unused', 3), wbInteger('Membrane Shader - Source Blend Mode', itU32, wbBlendModeEnum), wbInteger('Membrane Shader - Blend Operation', itU32, wbBlendOpEnum), wbInteger('Membrane Shader - Z Test Function', itU32, wbZTestFuncEnum), wbStruct('Fill/Texture Effect - Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbFloat('Fill/Texture Effect - Alpha Fade In Time'), wbFloat('Fill/Texture Effect - Full Alpha Time'), wbFloat('Fill/Texture Effect - Alpha Fade Out Time'), wbFloat('Fill/Texture Effect - Presistent Alpha Ratio'), wbFloat('Fill/Texture Effect - Alpha Pulse Amplitude'), wbFloat('Fill/Texture Effect - Alpha Pulse Frequency'), wbFloat('Fill/Texture Effect - Texture Animation Speed (U)'), wbFloat('Fill/Texture Effect - Texture Animation Speed (V)'), wbFloat('Edge Effect - Fall Off'), wbStruct('Edge Effect - Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbFloat('Edge Effect - Alpha Fade In Time'), wbFloat('Edge Effect - Full Alpha Time'), wbFloat('Edge Effect - Alpha Fade Out Time'), wbFloat('Edge Effect - Persistent Alpha Ratio'), wbFloat('Edge Effect - Alpha Pulse Amplitude'), wbFloat('Edge Effect - Alpha Pusle Frequence'), wbFloat('Fill/Texture Effect - Full Alpha Ratio'), wbFloat('Edge Effect - Full Alpha Ratio'), wbInteger('Membrane Shader - Dest Blend Mode', itU32, wbBlendModeEnum), wbInteger('Particle Shader - Source Blend Mode', itU32, wbBlendModeEnum), wbInteger('Particle Shader - Blend Operation', itU32, wbBlendOpEnum), wbInteger('Particle Shader - Z Test Function', itU32, wbZTestFuncEnum), wbInteger('Particle Shader - Dest Blend Mode', itU32, wbBlendModeEnum), wbFloat('Particle Shader - Particle Birth Ramp Up Time'), wbFloat('Particle Shader - Full Particle Birth Time'), wbFloat('Particle Shader - Particle Birth Ramp Down Time'), wbFloat('Particle Shader - Full Particle Birth Ratio'), wbFloat('Particle Shader - Persistant Particle Birth Ratio'), wbFloat('Particle Shader - Particle Lifetime'), wbFloat('Particle Shader - Particle Lifetime +/-'), wbFloat('Particle Shader - Initial Speed Along Normal'), wbFloat('Particle Shader - Acceleration Along Normal'), wbFloat('Particle Shader - Initial Velocity #1'), wbFloat('Particle Shader - Initial Velocity #2'), wbFloat('Particle Shader - Initial Velocity #3'), wbFloat('Particle Shader - Acceleration #1'), wbFloat('Particle Shader - Acceleration #2'), wbFloat('Particle Shader - Acceleration #3'), wbFloat('Particle Shader - Scale Key 1'), wbFloat('Particle Shader - Scale Key 2'), wbFloat('Particle Shader - Scale Key 1 Time'), wbFloat('Particle Shader - Scale Key 2 Time'), wbStruct('Color Key 1 - Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Color Key 2 - Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Color Key 3 - Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbFloat('Color Key 1 - Color Alpha'), wbFloat('Color Key 2 - Color Alpha'), wbFloat('Color Key 3 - Color Alpha'), wbFloat('Color Key 1 - Color Key Time'), wbFloat('Color Key 2 - Color Key Time'), wbFloat('Color Key 3 - Color Key Time') ], cpNormal, True, nil, 25) ]); wbRecord(ENCH, 'Enchantment', [ wbEDID, wbStruct(OBME, 'Oblivion Magic Extender', [ wbInteger('Record Version', itU8), wbStruct('OBME Version', [ wbInteger('Beta', itU8), wbInteger('Minor', itU8), wbInteger('Major', itU8) ]), wbByteArray('Unused', $1C) ], cpNormal, False, wbOBMEDontShow), wbFULL, wbStruct(ENIT, '', [ wbInteger('Type', itU32, wbEnum([ {0} 'Scroll', {1} 'Staff', {2} 'Weapon', {3} 'Apparel' ])), wbInteger('Charge Amount', itU32), wbInteger('Enchant Cost', itU32), wbInteger('Flags', itU8, wbFlags(['Manual Enchant Cost (Autocalc Off)'])), wbByteArray('Unused', 3) ], cpNormal, True), wbEffects ]); wbRecord(EYES, 'Eyes', [ wbEDID, wbFULL, wbString(ICON, 'Texture', 0, cpNormal, True), wbInteger(DATA, 'Flags', itU8, wbFlags(['Playable']), cpNormal, True) ]); wbXNAM := wbStructSK(XNAM, [0], 'Relation', [ wbFormIDCk('Faction', [FACT, RACE]), wbInteger('Modifier', itS32) ]); wbXNAMs := wbRArrayS('Relations', wbXNAM); wbRecord(FACT, 'Faction', [ wbEDID, wbFULL, wbXNAMs, wbInteger(DATA, 'Flags', itU8, wbFlags(['Hidden from Player', 'Evil', 'Special Combat']), cpNormal, True), wbFloat(CNAM, 'Crime Gold Multiplier', cpNormal, True, 1, -1, nil, nil, 1.0), wbRStructsSK('Ranks', 'Rank', [0], [ wbInteger(RNAM, 'Rank#', itS32), wbString(MNAM, 'Male', 0, cpTranslate), wbString(FNAM, 'Female', 0, cpTranslate), wbString(INAM, 'Insignia') ], []) ]); wbRecord(FLOR, 'Flora', [ wbEDID, wbFULL, wbMODL, wbSCRI, wbFormIDCk(PFIG, 'Ingredient', [INGR]), wbStruct(PFPC, 'Seasonal ingredient production', [ wbInteger('Spring', itU8), wbInteger('Summer ', itU8), wbInteger('Fall', itU8), wbInteger('Winter', itU8) ], cpNormal, True) ]); wbRecord(FURN, 'Furniture', [ wbEDID, wbFULL, wbMODL, wbSCRI, wbByteArray(MNAM, 'Marker Flags', 0, cpNormal, True) ]); wbRecord(GLOB, 'Global', [ wbEDID, wbInteger(FNAM, 'Type', itU8, wbGLOBFNAM, nil, cpNormal, True), wbFloat(FLTV, 'Value', cpNormal, True) ]); wbRecord(GMST, 'Game Setting', [ wbEDID, wbUnion(DATA, 'Value', wbGMSTUnionDecider, [ wbString('', 0, cpTranslate), wbInteger('', itS32), wbFloat('') ], cpNormal, True) ]); wbRecord(GRAS, 'Grass', [ wbEDID, wbMODL, wbStruct(DATA, '', [ wbInteger('Density', itU8), wbInteger('Min Slope', itU8), wbInteger('Max Slope', itU8), wbByteArray('Unused', 1), wbInteger('Unit from water amount', itU16), wbByteArray('Unused', 2), wbInteger('Unit from water type', itU32, wbEnum([ 'Above - At Least', 'Above - At Most', 'Below - At Least', 'Below - At Most', 'Either - At Least', 'Either - At Most', 'Either - At Most Above', 'Either - At Most Below' ])), wbFloat('Position Range'), wbFloat('Height Range'), wbFloat('Color Range'), wbFloat('Wave Period'), wbInteger('Flags', itU8, wbFlags([ 'Vertex Lighting', 'Uniform Scaling', 'Fit to Slope' ])), wbByteArray('Unused', 3) ], cpNormal, True) ]); wbRecord(HAIR, 'Hair', [ wbEDID, wbFULL, wbMODL, wbString(ICON, 'Texture', 0, cpNormal, True), wbInteger(DATA, 'Flags', itU8, wbFlags([ 'Playable', 'Not Male', 'Not Female', 'Fixed' ]), cpNormal, True) ]); wbCrimeTypeEnum := wbEnum([ 'Steal', 'Pickpocket', 'Trespass', 'Attack', 'Murder', 'Steal Horse' ], [ -1, 'None' ]); wbFormTypeEnum := wbEnum([], [ $03, 'Game Setting', $04, 'Global', $05, 'Class', $06, 'Faction', $07, 'Hair', $08, 'Eyes', $09, 'Race', $0A, 'Sound', $0B, 'Skill', $0C, 'Magic Effect', $0D, 'Script', $0E, 'Land Texture', $0F, 'Enchantment', $10, 'Spell', $11, 'BirthSign', $12, 'Activator', $13, 'Apparatus', $14, 'Armor', $15, 'Book', $16, 'Clothing', $17, 'Container', $18, 'Door', $19, 'Ingredient', $1A, 'Light', $1B, 'Misc', $1C, 'Static', $1D, 'Grass', $1E, 'Tree', $1F, 'Flora', $20, 'Furniture', $21, 'Weapon', $22, 'Ammi', $23, 'NPC', $24, 'Creature', $25, 'Leveled Creature', $26, 'Soul Gem', $27, 'Key', $28, 'Alchemy', $29, 'SubSpace', $2A, 'Sigil Stone', $2B, 'Leveled Item', $2D, 'Weather', $2E, 'Climate', $2F, 'Region', $30, 'Cell', $31, 'Placed Object', $32, 'Placed NPC', $33, 'Placed Creature', $34, 'Path Grid', $35, 'Worldspace', $36, 'Landscape', $38, 'Road', $39, 'Dialog Topic', $3A, 'Dialog Response', $3B, 'Quest', $3C, 'Idle Animation', $3D, 'Package', $3E, 'Combat Style', $3F, 'Load Screen', $40, 'Leveled Spell', $41, 'Animated Object', $42, 'Water', $43, 'Effect Shader' ]); wbSexEnum := wbEnum(['Male','Female']); wbAxisEnum := wbEnum([], [ 88, 'X', 89, 'Y', 90, 'Z' ]); wbCTDA := wbRUnion('Condition', [ wbStruct(CTDA, 'Condition', [ wbInteger('Type', itU8, wbCtdaType), wbByteArray('Unused', 3), wbUnion('Comparison Value', wbCTDACompValueDecider, [ wbFloat('Comparison Value - Float'), wbFormIDCk('Comparison Value - Global', [GLOB]) ]), wbInteger('Function', itU32, wbCTDAFunctionToStr, wbCTDAFunctionToInt), wbUnion('Parameter #1', wbCTDAParam1Decider, [ {00} wbByteArray('Unknown', 4), {01} wbByteArray('None', 4, cpIgnore), {02} wbInteger('Integer', itS32), {03} wbInteger('Variable Name (INVALID)', itS32), {04} wbInteger('Sex', itU32, wbSexEnum), {05} wbFormIDCk('Actor Value', [ACVA]), // {05} wbInteger('Actor Value', itS32, wbActorValueEnum), {06} wbInteger('Crime Type', itU32, wbCrimeTypeEnum), {07} wbInteger('Axis', itU32, wbAxisEnum), {08} wbInteger('Form Type', itU32, wbFormTypeEnum), {09} wbInteger('Quest Stage (INVALID)', itS32), {10} wbFormIDCk('Object Reference', [PLYR, REFR, ACHR, ACRE, TRGT]), {12} wbFormIDCk('Inventory Object', [ARMO, AMMO, MISC, WEAP, INGR, SLGM, SGST, BOOK, KEYM, CLOT, ALCH, APPA, LIGH]), {13} wbFormIDCk('Actor', [PLYR, ACHR, ACRE, TRGT]), {14} wbFormIDCk('Quest', [QUST]), {15} wbFormIDCk('Faction', [FACT]), {16} wbFormIDCk('Cell', [CELL]), {17} wbFormIDCk('Class', [CLAS]), {18} wbFormIDCk('Race', [RACE]), {19} wbFormIDCk('Actor Base', [NPC_, CREA, ACTI]), {20} wbFormIDCk('Global', [GLOB]), {21} wbFormIDCk('Weather', [WTHR]), {22} wbFormIDCk('Package', [PACK]), {23} wbFormIDCk('Owner', [FACT, NPC_]), {24} wbFormIDCk('Birthsign', [BSGN]), {25} wbFormIDCk('Furniture', [FURN]), {26} wbFormIDCk('Magic Item', [SPEL]), {27} wbFormIDCk('Magic Effect', [MGEF]), {28} wbFormIDCk('Worldspace', [WRLD]), {29} wbFormIDCk('Referenceable Object', [CREA, NPC_, TREE, SBSP, LVLC, SOUN, ACTI, DOOR, FLOR, STAT, FURN, CONT, ARMO, AMMO, MISC, WEAP, INGR, SLGM, SGST, BOOK, KEYM, CLOT, ALCH, APPA, LIGH, GRAS]) ]), wbUnion('Parameter #2', wbCTDAParam2Decider, [ {00} wbByteArray('Unknown', 4), {01} wbByteArray('None', 4, cpIgnore), {02} wbInteger('Integer', itS32), {03} wbInteger('Variable Name', itS32, wbCTDAParam2VariableNameToStr, wbCTDAParam2VariableNameToInt), {04} wbInteger('Sex', itU32, wbSexEnum), {05} wbFormIDCk('Actor Value', [ACVA]), // {05} wbInteger('Actor Value', itS32, wbActorValueEnum), {06} wbInteger('Crime Type', itU32, wbCrimeTypeEnum), {07} wbInteger('Axis', itU32, wbAxisEnum), {08} wbInteger('Form Type', itU32, wbFormTypeEnum), {09} wbInteger('Quest Stage', itS32, wbCTDAParam2QuestStageToStr, wbCTDAParam2QuestStageToInt), {10} wbFormIDCk('Object Reference', [PLYR, REFR, ACHR, ACRE, TRGT]), {12} wbFormIDCk('Inventory Object', [ARMO, AMMO, MISC, WEAP, INGR, SLGM, SGST, BOOK, KEYM, CLOT, ALCH, APPA, LIGH]), {13} wbFormIDCk('Actor', [PLYR, ACHR, ACRE, TRGT]), {14} wbFormIDCk('Quest', [QUST]), {15} wbFormIDCk('Faction', [FACT]), {16} wbFormIDCk('Cell', [CELL]), {17} wbFormIDCk('Class', [CLAS]), {18} wbFormIDCk('Race', [RACE]), {19} wbFormIDCk('Actor Base', [NPC_, CREA, ACTI]), {20} wbFormIDCk('Global', [GLOB]), {21} wbFormIDCk('Weather', [WTHR]), {22} wbFormIDCk('Package', [PACK]), {23} wbFormIDCk('Owner', [FACT, NPC_]), {24} wbFormIDCk('Birthsign', [BSGN]), {25} wbFormIDCk('Furniture', [FURN]), {26} wbFormIDCk('Magic Item', [SPEL]), {27} wbFormIDCk('Magic Effect', [MGEF]), {28} wbFormIDCk('Worldspace', [WRLD]), {29} wbFormIDCk('Referenceable Object', [CREA, NPC_, TREE, SBSP, LVLC, SOUN, ACTI, DOOR, FLOR, STAT, FURN, CONT, ARMO, AMMO, MISC, WEAP, INGR, SLGM, SGST, BOOK, KEYM, CLOT, ALCH, APPA, LIGH, GRAS]) ]), wbInteger('Unused', itU32, nil, cpIgnore) ], cpNormal, False, nil, 6), wbStruct(CTDT, 'Condition (old format)', [ wbInteger('Type', itU8, wbCtdaType), wbByteArray('Unused', 3), wbUnion('Comparison Value', wbCTDACompValueDecider, [ wbFloat('Comparison Value - Float'), wbFormIDCk('Comparison Value - Global', [GLOB]) ]), wbInteger('Function', itU32, wbCTDAFunctionToStr, wbCTDAFunctionToInt), wbUnion('Parameter #1', wbCTDAParam1Decider, [ {00} wbByteArray('Unknown', 4), {01} wbByteArray('None', 4, cpIgnore), {02} wbInteger('Integer', itS32), {03} wbInteger('Variable Name (INVALID)', itS32), {04} wbInteger('Sex', itU32, wbSexEnum), {05} wbFormIDCk('Actor Value', [ACVA]), // {05} wbInteger('Actor Value', itS32, wbActorValueEnum), {06} wbInteger('Crime Type', itU32, wbCrimeTypeEnum), {07} wbInteger('Axis', itU32, wbAxisEnum), {08} wbInteger('Form Type', itU32, wbFormTypeEnum), {09} wbInteger('Quest Stage (INVALID)', itS32), {10} wbFormIDCk('Object Reference', [PLYR, REFR, ACHR, ACRE, TRGT]), {12} wbFormIDCk('Inventory Object', [ARMO, AMMO, MISC, WEAP, INGR, SLGM, SGST, BOOK, KEYM, CLOT, ALCH, APPA, LIGH]), {13} wbFormIDCk('Actor', [PLYR, ACHR, ACRE, TRGT]), {14} wbFormIDCk('Quest', [QUST]), {15} wbFormIDCk('Faction', [FACT]), {16} wbFormIDCk('Cell', [CELL]), {17} wbFormIDCk('Class', [CLAS]), {18} wbFormIDCk('Race', [RACE]), {19} wbFormIDCk('Actor Base', [NPC_, CREA, ACTI]), {20} wbFormIDCk('Global', [GLOB]), {21} wbFormIDCk('Weather', [WTHR]), {22} wbFormIDCk('Package', [PACK]), {23} wbFormIDCk('Owner', [FACT, NPC_]), {24} wbFormIDCk('Birthsign', [BSGN]), {25} wbFormIDCk('Furniture', [FURN]), {26} wbFormIDCk('Magic Item', [SPEL]), {27} wbFormIDCk('Magic Effect', [MGEF]), {28} wbFormIDCk('Worldspace', [WRLD]), {29} wbFormIDCk('Referenceable Object', [CREA, NPC_, TREE, SBSP, LVLC, SOUN, ACTI, DOOR, FLOR, STAT, FURN, CONT, ARMO, AMMO, MISC, WEAP, INGR, SLGM, SGST, BOOK, KEYM, CLOT, ALCH, APPA, LIGH, GRAS]) ]), wbUnion('Parameter #2', wbCTDAParam2Decider, [ {00} wbByteArray('Unknown', 4), {01} wbByteArray('None', 4, cpIgnore), {02} wbInteger('Integer', itS32), {03} wbInteger('Variable Name', itS32, wbCTDAParam2VariableNameToStr, wbCTDAParam2VariableNameToInt), {04} wbInteger('Sex', itU32, wbSexEnum), {05} wbFormIDCk('Actor Value', [ACVA]), // {05} wbInteger('Actor Value', itS32, wbActorValueEnum), {06} wbInteger('Crime Type', itU32, wbCrimeTypeEnum), {07} wbInteger('Axis', itU32, wbAxisEnum), {08} wbInteger('Form Type', itU32, wbFormTypeEnum), {09} wbInteger('Quest Stage', itS32, wbCTDAParam2QuestStageToStr, wbCTDAParam2QuestStageToInt), {10} wbFormIDCk('Object Reference', [PLYR, REFR, ACHR, ACRE, TRGT]), {12} wbFormIDCk('Inventory Object', [ARMO, AMMO, MISC, WEAP, INGR, SLGM, SGST, BOOK, KEYM, CLOT, ALCH, APPA, LIGH]), {13} wbFormIDCk('Actor', [PLYR, ACHR, ACRE, TRGT]), {14} wbFormIDCk('Quest', [QUST]), {15} wbFormIDCk('Faction', [FACT]), {16} wbFormIDCk('Cell', [CELL]), {17} wbFormIDCk('Class', [CLAS]), {18} wbFormIDCk('Race', [RACE]), {19} wbFormIDCk('Actor Base', [NPC_, CREA, ACTI]), {20} wbFormIDCk('Global', [GLOB]), {21} wbFormIDCk('Weather', [WTHR]), {22} wbFormIDCk('Package', [PACK]), {23} wbFormIDCk('Owner', [FACT, NPC_]), {24} wbFormIDCk('Birthsign', [BSGN]), {25} wbFormIDCk('Furniture', [FURN]), {26} wbFormIDCk('Magic Item', [SPEL]), {27} wbFormIDCk('Magic Effect', [MGEF]), {28} wbFormIDCk('Worldspace', [WRLD]), {29} wbFormIDCk('Referenceable Object', [CREA, NPC_, TREE, SBSP, LVLC, SOUN, ACTI, DOOR, FLOR, STAT, FURN, CONT, ARMO, AMMO, MISC, WEAP, INGR, SLGM, SGST, BOOK, KEYM, CLOT, ALCH, APPA, LIGH, GRAS]) ]), wbEmpty('Unused', cpIgnore) ]) ], []); wbCTDAs := wbRArray('Conditions', wbCTDA); wbSCHR := wbRUnion('Basic Script Data', [ wbStruct(SCHR, 'Basic Script Data', [ wbByteArray('Unused', 4), wbInteger('RefCount', itU32), wbInteger('CompiledSize', itU32), wbInteger('VariableCount', itU32), wbInteger('Type', itU32, wbEnum([ 'Object', 'Quest' ], [ $100, 'Magic Effect' ])) ]), wbStruct(SCHD, 'Basic Script Data', [ wbByteArray('Unused', 4), wbInteger('RefCount', itU32), wbInteger('CompiledSize', itU32), wbInteger('VariableCount', itU32), wbInteger('Type', itU32, wbEnum([ 'Object', 'Quest' ], [ $100, 'Magic Effect' ])) ]) ], []); wbSCROs := wbRArray('References', wbRUnion('', [ wbFormIDCk(SCRO, 'Global Reference', [ACTI, DOOR, FLOR, STAT, FURN, CREA, SPEL, NPC_, CONT, ARMO, AMMO, MISC, WEAP, INGR, SLGM, SGST, BOOK, KEYM, CLOT, ALCH, APPA, LIGH, QUST, PLYR, PACK, LVLI, FACT, ACHR, REFR, ACRE, GLOB, DIAL, CELL, SOUN, MGEF, WTHR, CLAS, EFSH, RACE, LVLC, CSTY, WRLD, SCPT, BSGN, TREE, NULL]), wbInteger(SCRV, 'Local Variable', itU32) ], []) ); wbResultScript := wbRStruct('Result Script', [ wbSCHR, wbByteArray(SCDA, 'Compiled result script'), wbStringScript(SCTX, 'Result script source'), wbSCROs ], []); { wbResultScriptOld := wbRStruct('Result Script (Old Format?)', [ wbByteArray(SCHD, 'Unknown (Script Header?)'), wbByteArray(SCDA, 'Compiled result script'), wbStringScript(SCTX, 'Result script source'), wbSCROs ], []); } wbRecord(IDLE, 'Idle Animation', [ wbEDID, wbMODL, wbCTDAs, wbInteger(ANAM, 'Animation Group Section', itU8, wbIdleAnam, nil, cpNormal, True), wbArray(DATA, 'Related Idle Animations', wbFormIDCk('Related Idle Animation', [IDLE, NULL]), ['Parent', 'Previous Sibling'], cpNormal, True) ]); wbRecord(INFO, 'Dialog response', [ wbStruct(DATA, '', [ wbInteger('Type', itU8, wbEnum([ {0} 'Topic', {1} 'Conversation', {2} 'Combat', {3} 'Persuasion', {4} 'Detection', {5} 'Service', {6} 'Miscellaneous' ])), wbInteger('Flags', itU8, wbFlags([ {0x0001} 'Goodbye', {0x0002} 'Random', {0x0004} 'Say Once', {0x0008} '', {0x0010} 'Info Refusal', {0x0020} 'Random End', {0x0040} 'Run for Rumors' ])), wbByteArray('Unused', 1) ], cpNormal, True), wbFormIDCk(QSTI, 'Quest', [QUST], False, cpNormal, True), wbFormIDCk(TPIC, 'Topic', [DIAL]), wbFormIDCk(PNAM, 'Previous INFO', [INFO, NULL]), wbRArray('Add topics', wbFormIDCk(NAME, 'Topic', [DIAL])), wbRArray('Responses', wbRStruct('Response', [ wbStruct(TRDT, 'Response Data', [ wbInteger('Emotion Type', itU32, wbEnum([ {0} 'Neutral', {1} 'Anger', {2} 'Disgust', {3} 'Fear', {4} 'Sad', {5} 'Happy', {6} 'Surprise' ])), wbInteger('Emotion Value', itS32), wbByteArray('Unused', 4), wbInteger('Response number', itU8), wbByteArray('Unused', 3) ]), wbString(NAM1, 'Response Text', 0, cpTranslate), wbString(NAM2, 'Actor notes', 0, cpTranslate) ], []) ), wbCTDAs, wbRArray('Choices', wbFormIDCk(TCLT, 'Choice', [DIAL])), wbRArray('Link From', wbFormIDCk(TCLF, 'Topic', [DIAL])), wbResultScript ]); wbRecord(INGR, 'Ingredient', [ wbEDID, wbStruct(OBME, 'Oblivion Magic Extender', [ wbInteger('Record Version', itU8), wbStruct('OBME Version', [ wbInteger('Beta', itU8), wbInteger('Minor', itU8), wbInteger('Major', itU8) ]), wbByteArray('Unused', $1C) ], cpNormal, False, wbOBMEDontShow), wbFULL, wbMODL, wbICON, wbSCRI, wbFloat(DATA, 'Weight', cpNormal, True), wbStruct(ENIT, '', [ wbInteger('Value', itS32), wbInteger('Flags', itU8, wbFlags(['No auto-calculation', 'Food item'])), wbByteArray('Unused', 3) ], cpNormal, True), wbEffects ]); wbRecord(KEYM, 'Key', [ wbEDID, wbFULL, wbMODL, wbICON, wbSCRI, wbStruct(DATA, '', [ wbInteger('Value', itS32), wbFloat('Weight') ], cpNormal, True) ]); wbQuadrantEnum := wbEnum([ {0} 'Bottom Left', {1} 'Bottom Right', {2} 'Top Left', {3} 'Top Right' ]); if wbSimpleRecords then begin wbRecord(LAND, 'Landscape', [ wbByteArray(DATA, 'Unknown'), wbByteArray(VNML, 'Vertex Normals'), wbByteArray(VHGT, 'Vertext Height Map'), wbByteArray(VCLR, 'Vertex Colours'), wbRArrayS('Layers', wbRUnion('Layer', [ wbRStructSK([0],'Base Layer', [ wbStructSK(BTXT, [1, 3], 'Base Layer Header', [ wbFormIDCk('Texture', [LTEX, NULL]), wbInteger('Quadrant', itU8, wbQuadrantEnum), wbByteArray('Unused', 1), wbInteger('Layer', itS16) ]) ], []), wbRStructSK([0],'Alpha Layer', [ wbStructSK(ATXT, [1, 3], 'Alpha Layer Header', [ wbFormIDCk('Texture', [LTEX, NULL]), wbInteger('Quadrant', itU8, wbQuadrantEnum), wbByteArray('Unused', 1), wbInteger('Layer', itS16) ]), wbByteArray(VTXT, 'Alpha Layer Data') ], []) ], [])), wbArray(VTEX, 'Textures', wbFormIDCk('Texture', [LTEX, NULL])) ]); end else begin wbRecord(LAND, 'Landscape', [ wbByteArray(DATA, 'Unknown'), // wbStruct(DATA, '', [ // wbInteger('Flags', itU8, wbFlags([])), // wbByteArray('Unknown') // ]), wbArray(VNML, 'Vertex Normals', wbStruct('Row', [ wbArray('Columns', wbStruct('Column', [ wbInteger('X', itU8), wbInteger('Y', itU8), wbInteger('Z', itU8) ]), 33) ]), 33), wbStruct(VHGT, 'Vertext Height Map', [ wbFloat('Offset'), wbArray('Rows', wbStruct('Row', [ wbArray('Columns', wbInteger('Column', itU8), 33) ]), 33), wbByteArray('Unused', 3) ]), wbArray(VCLR, 'Vertex Colours', wbStruct('Row', [ wbArray('Columns', wbStruct('Column', [ wbInteger('X', itU8), wbInteger('Y', itU8), wbInteger('Z', itU8) ]), 33) ]), 33), wbRArrayS('Layers', wbRUnion('Layer', [ wbRStructSK([0],'Base Layer', [ wbStructSK(BTXT, [1, 3], 'Base Layer Header', [ wbFormIDCk('Texture', [LTEX, NULL]), wbInteger('Quadrant', itU8, wbQuadrantEnum), wbByteArray('Unused', 1), wbInteger('Layer', itS16) ]) ], []), wbRStructSK([0],'Alpha Layer', [ wbStructSK(ATXT, [1, 3], 'Alpha Layer Header', [ wbFormIDCk('Texture', [LTEX, NULL]), wbInteger('Quadrant', itU8, wbQuadrantEnum), wbByteArray('Unused', 1), wbInteger('Layer', itS16) ]), wbArrayS(VTXT, 'Alpha Layer Data', wbStructSK([0], 'Cell', [ wbInteger('Position', itU16, wbAtxtPosition), wbByteArray('Unused', 2), wbFloat('Opacity') ])) ], []) ], [])), wbArray(VTEX, 'Textures', wbFormIDCk('Texture', [LTEX, NULL])) ]); end; wbRecord(LIGH, 'Light', [ wbEDID, wbMODL, wbSCRI, wbFULL, wbICON, wbStruct(DATA, '', [ wbInteger('Time', itS32), wbInteger('Radius', itU32), wbStruct('Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbInteger('Unused', itU8) ]), wbInteger('Flags', itU32, wbFlags([ {0x00000001} 'Dynamic', {0x00000002} 'Can be Carried', {0x00000004} 'Negative', {0x00000008} 'Flicker', {0x00000010} 'Unused', {0x00000020} 'Off By Default', {0x00000040} 'Flicker Slow', {0x00000080} 'Pulse', {0x00000100} 'Pulse Slow', {0x00000200} 'Spot Light', {0x00000400} 'Spot Shadow' ])), wbFloat('Falloff Exponent'), wbFloat('FOV'), wbInteger('Value', itU32), wbFloat('Weight') ], cpNormal, True, nil, 6), wbFloat(FNAM, 'Fade value', cpNormal, True, 1, -1, nil, nil, 1.0), wbFormIDCk(SNAM, 'Sound', [SOUN]) ], False, nil, cpNormal, False, wbLIGHAfterLoad); wbRecord(LSCR, 'Load Screen', [ wbEDID, wbICON, wbDESC, wbRArrayS('Locations', wbStructSK(LNAM, [0, 1], 'Location', [ wbFormIDCk('Direct', [CELL, WRLD, NULL]), wbStructSK([0, 1], 'Indirect', [ wbFormIDCk('World', [NULL, WRLD]), wbStructSK([0,1], 'Grid', [ wbInteger('Y', itS16), wbInteger('X', itS16) ]) ]) ])) ]); wbRecord(LTEX, 'Landscape Texture', [ wbEDID, wbICON, wbStruct(HNAM, 'Havok Data', [ wbInteger('Material Type', itU8, wbEnum([ {00} 'STONE', {01} 'CLOTH', {02} 'DIRT', {03} 'GLASS', {04} 'GRASS', {05} 'METAL', {06} 'ORGANIC', {07} 'SKIN', {08} 'WATER', {09} 'WOOD', {10} 'HEAVY STONE', {11} 'HEAVY METAL', {12} 'HEAVY WOOD', {13} 'CHAIN', {14} 'SNOW' ]), cpNormal, True, nil, nil, 2), wbInteger('Friction', itU8, nil, cpNormal, True, nil, nil, 30), wbInteger('Restitution', itU8, nil, cpNormal, True, nil, nil, 30) ], cpNormal, True), wbInteger(SNAM, 'Texture Specular Exponent', itU8, nil, cpNormal, True, False, nil, nil, 30), wbRArrayS('Grasses', wbFormIDCk(GNAM, 'Grass', [GRAS])) ]); wbRecord(LVLC, 'Leveled Creature', [ wbEDID, wbInteger(LVLD, 'Chance none', itU8, nil, cpNormal, True), wbInteger(LVLF, 'Flags', itU8, wbFlags([ {0x01} 'Calculate from all levels <= player''s level', {0x02} 'Calculate for each item in count' ]), cpNormal, True), wbRArrayS('Leveled List Entries', wbStructExSK(LVLO , [0, 2], [3], 'Leveled List Entry', [ wbInteger('Level', itS16), wbByteArray('Unused', 2), wbFormIDCk('Reference', [NPC_, CREA, LVLC]), wbInteger('Count', itS16), wbByteArray('Unused', 2) ], cpNormal, False, nil, 3), cpNormal, True), wbSCRI, wbFormIDCk(TNAM, 'Creature template', [NPC_, CREA]) ], True, nil, cpNormal, False, wbLVLAfterLoad); wbRecord(LVLI, 'Leveled Item', [ wbEDID, wbInteger(LVLD, 'Chance none', itU8, nil, cpNormal, True), wbInteger(LVLF, 'Flags', itU8, wbFlags([ {0x01} 'Calculate from all levels <= player''s level', {0x02} 'Calculate for each item in count' ]), cpNormal, True), wbRArrayS('Leveled List Entries', wbStructExSK(LVLO , [0, 2], [3], 'Leveled List Entry', [ wbInteger('Level', itS16), wbByteArray('Unused', 2), wbFormIDCk('Reference', [ARMO, AMMO, MISC, WEAP, INGR, SLGM, SGST, BOOK, LVLI, KEYM, CLOT, ALCH, APPA, LIGH]), wbInteger('Count', itS16), wbByteArray('Unused', 2) ], cpNormal, False, nil, 3), cpNormal, True), wbByteArray(DATA, 'Unused', 1) ], False, nil, cpNormal, False, wbLVLAfterLoad); wbRecord(LVSP, 'Leveled Spell', [ wbEDID, wbInteger(LVLD, 'Chance none', itU8, nil, cpNormal, True), wbInteger(LVLF, 'Flags', itU8, wbFlags([ {0x01} 'Calculate from all levels <= player''s level', {0x02} 'Calculate for each item in count', {0x04} 'Use all spells' ]), cpNormal, True), wbRArrayS('Leveled List Entries', wbStructExSK(LVLO , [0, 2], [3], 'Leveled List Entry', [ wbInteger('Level', itS16), wbByteArray('Unused', 2), wbFormIDCk('Reference', [SPEL, LVSP]), wbInteger('Count', itS16), wbByteArray('Unused', 2) ], cpNormal, False, nil, 3), cpNormal, True) ], False, nil, cpNormal, False, wbLVLAfterLoad); wbRecord(MGEF, 'Magic Effect', [ wbStringMgefCode(EDID, 'Magic Effect Code'), wbStruct(OBME, 'Oblivion Magic Extender', [ wbInteger('Record Version', itU8), wbStruct('OBME Version', [ wbInteger('Beta', itU8), wbInteger('Minor', itU8), wbInteger('Major', itU8) ]), wbInteger('Param A Info', itU8, wbOBMEResolutionInfo), wbInteger('Param B Info', itU8, wbOBMEResolutionInfo), wbByteArray('Unused', 2), wbString('Handler', 4), wbInteger('Flag Overrides', itU32, wbFlags([ { 0} '', { 1} '', { 2} 'ParamFlagA', { 3} 'Beneficial', { 4} '', { 5} '', { 6} '', { 7} '', { 8} '', { 9} '', {10} '', {11} '', {12} '', {13} '', {14} '', {15} '', {16} 'ParamFlagB', {17} 'Magnitude Is Range', {18} 'Atomic Resistance', {19} 'ParamFlagC', {20} 'ParamFlagD', {21} '', {22} '', {23} '', {24} '', {25} '', {26} '', {27} '', {28} '', {29} '', {30} 'Hidden' ])), wbByteArray('ParamB', 4), wbByteArray('Unused', $1C) ], cpNormal, False, wbOBMEDontShow), wbString(EDDX, 'EditorID', 0, cpNormal, False, wbEDDXDontShow), wbFULL, wbDESC, wbICON, wbMODL, wbStruct(DATA, 'Data', [ wbInteger('Flags', itU32, wbFlags([ {0x00000001} 'Hostile', {0x00000002} 'Recover', {0x00000004} 'Detrimental', {0x00000008} 'Magnitude %', {0x00000010} 'Self', {0x00000020} 'Touch', {0x00000040} 'Target', {0x00000080} 'No duration', {0x00000100} 'No magnitude', {0x00000200} 'No area', {0x00000400} 'FX persist', {0x00000800} 'Spellmaking', {0x00001000} 'Enchanting', {0x00002000} 'No Ingredient', {0x00004000} '', {0x00008000} '', {0x00010000} 'Use weapon', {0x00020000} 'Use armor', {0x00040000} 'Use creature', {0x00080000} 'Use skill', {0x00100000} 'Use attribute', {0x00200000} '', {0x00400000} '', {0x00800000} '', {0x01000000} 'Use actor value', {0x02000000} 'Spray projectile type (or Fog if Bolt is specified as well)', {0x04000000} 'Bolt projectile type', {0x08000000} 'No hit effect' ])), wbFloat('Base cost'), wbUnion('Assoc. Item', wbMGEFFAssocItemDecider, [ wbFormIDCk('Unused', [NULL]), wbFormIDCk('Assoc. Weapon', [WEAP]), wbFormIDCk('Assoc. Armor', [ARMO, NULL{?}]), wbFormIDCk('Assoc. Creature', [CREA, LVLC, NPC_]), wbInteger('Assoc. Actor Value', itS32, wbActorValueEnum) ]), wbInteger('Magic School', itS32, wbMagicSchoolEnum), wbInteger('Resist value', itS32, wbActorValueEnum), wbInteger('Counter Effect Count', itU16), //!!! must be updated automatically when ESCE length changes! wbByteArray('Unused', 2), wbFormIDCk('Light', [LIGH, NULL]), wbFloat('Projectile speed'), wbFormIDCk('Effect Shader', [EFSH, NULL]), wbFormIDCk('Enchant effect', [EFSH, NULL]), wbFormIDCk('Casting sound', [NULL, SOUN]), wbFormIDCk('Bolt sound', [NULL, SOUN]), wbFormIDCk('Hit sound', [NULL, SOUN]), wbFormIDCk('Area sound', [NULL, SOUN]), wbFloat('Constant Effect enchantment factor'), wbFloat('Constant Effect barter factor') ], cpNormal, True, nil, 10), wbArrayS(ESCE, 'Counter Effects', wbStringMgefCode('Counter Effect Code', 4){wbInteger('Counter Effect', itU32, wbChar4)}) ], False, nil, cpNormal, False, wbMGEFAfterLoad); wbRecord(MISC, 'Misc. Item', [ wbEDID, wbFULL, wbMODL, wbICON, wbSCRI, wbStruct(DATA, '', [ wbUnion('', wbMISCActorValueDecider, [ wbInteger('Value', itS32), wbFormIDCk('Actor Value', [ACVA]) ]), wbUnion('', wbMISCActorValueDecider, [ wbFloat('Weight'), wbInteger('Group', itU32, wbEnum([], [ $40E00000, ' [NONE]', $40400000, 'AI', $00000000, 'Attribute', $40C00000, 'Combat', $40A00000, 'Misc', $40000000, 'Skill', $40800000, 'Social', $3F800000, 'Stat' ])) ]) ], cpNormal, True) ]); wbFaceGen := wbRStruct('FaceGen Data', [ wbByteArray(FGGS, 'FaceGen Geometry-Symmetric', 0, cpNormal, True), wbByteArray(FGGA, 'FaceGen Geometry-Asymmetric', 0, cpNormal, True), wbByteArray(FGTS, 'FaceGen Texture-Symmetric', 0, cpNormal, True) ], [], cpNormal, True); wbRecord(NPC_, 'Non-Player Character', [ wbEDID, wbFULL, wbMODL, wbStruct(ACBS, 'Configuration', [ wbInteger('Flags', itU32, wbFlags([ {0x000001} 'Female', {0x000002} 'Essential', {0x000004} '', {0x000008} 'Respawn', {0x000010} 'Auto-calc stats', {0x000020} '', {0x000040} '', {0x000080} 'PC Level Offset', {0x000100} '', {0x000200} 'No Low Level Processing', {0x000400} '', {0x000800} '', {0x001000} '', {0x002000} 'No Rumors', {0x004000} 'Summonable', {0x008000} 'No Persuasion', {0x010000} '', {0x020000} '', {0x040000} '', {0x080000} '', {0x100000} 'Can Corpse Check' ])), wbInteger('Base spell points', itU16), wbInteger('Fatigue', itU16), wbInteger('Barter gold', itU16), wbInteger('Level (offset)', itS16), wbInteger('Calc min', itU16), wbInteger('Calc max', itU16) ], cpNormal, True), wbRArrayS('Factions', wbStructSK(SNAM, [0], 'Faction', [ wbFormIDCk('Faction', [FACT]), wbInteger('Rank', itU8), wbByteArray('Unused', 3) ]) ), wbFormIDCk(INAM, 'Death item', [LVLI]), wbFormIDCk(RNAM, 'Race', [RACE], False, cpNormal, True), wbCNTOs, wbSPLOs, wbSCRI, wbStruct(AIDT, 'AI Data', [ wbInteger('Aggression', itU8), wbInteger('Confidence', itU8), wbInteger('Energy Level', itU8), wbInteger('Responsibility', itU8), wbInteger('Buys/Sells and Services', itU32, wbServiceFlags), wbInteger('Teaches', itS8, wbSkillEnum), wbInteger('Maximum training level', itU8), wbByteArray('Unused', 2) ], cpNormal, True), wbRArray('AI Packages', wbFormIDCk(PKID, 'AI Package', [PACK])), wbArrayS(KFFZ, 'Animations', wbString('Animation')), wbFormIDCk(CNAM, 'Class', [CLAS], False, cpNormal, True), wbStruct(DATA, 'Stats', [ wbInteger('Armorer', itU8), wbInteger('Athletics', itU8), wbInteger('Blade', itU8), wbInteger('Block', itU8), wbInteger('Blunt', itU8), wbInteger('Hand to Hand', itU8), wbInteger('Heavy Armor', itU8), wbInteger('Alchemy', itU8), wbInteger('Alteration', itU8), wbInteger('Conjuration', itU8), wbInteger('Destruction', itU8), wbInteger('Illusion', itU8), wbInteger('Mysticism', itU8), wbInteger('Restoration', itU8), wbInteger('Acrobatics', itU8), wbInteger('Light Armor', itU8), wbInteger('Marksman', itU8), wbInteger('Mercantile', itU8), wbInteger('Security', itU8), wbInteger('Sneak', itU8), wbInteger('Speechcraft', itU8), wbInteger('Health', itU16), wbByteArray('Unused', 2), wbInteger('Strength', itU8), wbInteger('Intelligence', itU8), wbInteger('Willpower', itU8), wbInteger('Agility', itU8), wbInteger('Speed', itU8), wbInteger('Endurance', itU8), wbInteger('Personality', itU8), wbInteger('Luck', itU8) ], cpNormal, True), wbFormIDCk(HNAM, 'Hair', [HAIR]), wbFloat(LNAM, 'Hair length'), wbArray(ENAM, 'Eyes', wbFormIDCk('Eyes', [EYES])), wbStruct(HCLR, 'Hair color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ], cpNormal, True), wbFormIDCk(ZNAM, 'Combat Style', [CSTY]), wbFaceGen, wbByteArray(FNAM, 'Unknown', 0, cpBenign) ], True); wbPKDTFlags := wbFlags([ {0x00000001} 'Offers services', {0x00000002} 'Must reach location', {0x00000004} 'Must complete', {0x00000008} 'Lock doors at package start', {0x00000010} 'Lock doors at package end', {0x00000020} 'Lock doors at location', {0x00000040} 'Unlock doors at package start', {0x00000080} 'Unlock doors at package end', {0x00000100} 'Unlock doors at location', {0x00000200} 'Continue if PC near', {0x00000400} 'Once per day', {0x00000800} 'Unused', {0x00001000} 'Skip fallout behavior', {0x00002000} 'Always run', {0x00004000} '', {0x00008000} '', {0x00010000} '', {0x00020000} 'Always sneak', {0x00040000} 'Allow swimming', {0x00080000} 'Allow falls', {0x00100000} 'Armor unequipped', {0x00200000} 'Weapons unequipped', {0x00400000} 'Defensive combat', {0x00800000} 'Use horse', {0x01000000} 'No idle anims', {0x02000000} '', {0x04000000} '', {0x08000000} '', {0x10000000} '', {0x20000000} '', {0x40000000} '', {0x80000000} '' ]); wbPKDTType := wbEnum([ {0} 'Find', {1} 'Follow', {2} 'Escort', {3} 'Eat', {4} 'Sleep', {5} 'Wander', {6} 'Travel', {7} 'Accompany', {8} 'Use item at', {9} 'Ambush', {10} 'Flee not combat', {11} 'Cast magic' ]); wbRecord(PACK, 'AI Package', [ wbEDID, wbUnion(PKDT, 'General', wbPACKPKDTDecider, [ wbStruct('General', [ wbInteger('Flags', itU16, wbPKDTFlags), wbInteger('Type', itU8, wbPKDTType), wbByteArray('Unused', 1) ]), wbStruct('General', [ wbInteger('Flags', itU32, wbPKDTFlags), wbInteger('Type', itU8, wbPKDTType), wbByteArray('Unused', 3) ]) ]), wbStruct(PLDT, 'Location', [ wbInteger('Type', itS32, wbEnum([ {0} 'Near reference', {1} 'In cell', {2} 'Near current location', {3} 'Near editor location', {4} 'Object ID', {5} 'Object type' ])), wbUnion('Location', wbPxDTLocationDecider, [ wbFormIDCk('Reference', [REFR, ACHR, ACRE, PLYR], True), wbFormIDCk('Cell', [CELL]), wbFormIDCk('Unused', [NULL]), wbFormIDCk('Unused', [NULL]), wbFormIDCk('Object ID', [ACTI, DOOR, FLOR, STAT, FURN, CREA, SPEL, NPC_, CONT, ARMO, AMMO, MISC, WEAP, INGR, SLGM, SGST, BOOK, KEYM, CLOT, ALCH, APPA, LIGH]), wbInteger('Object type', itU32) ]), wbInteger('Radius', itS32) ]), wbStruct(PSDT, 'Schedule', [ wbInteger('Month', itS8), wbInteger('Day of week', itS8, wbEnum([ 'Sundas', 'Morndas', 'Tirdas', 'Middas', 'Turdas', 'Fredas', 'Loredas', 'Morndas to Fredas', 'Loredas, Sundas', 'Morndas, Middas, Fredas', 'Tirdas, Turdas' ], [ -1, 'Any' ])), wbInteger('Date', itU8), wbInteger('Time', itS8), wbInteger('Duration', itS32) ]), wbStruct(PTDT, 'Target', [ wbInteger('Type', itS32, wbEnum([ {0} 'Specific reference', {1} 'Object ID', {2} 'Object type' ])), wbUnion('Target', wbPxDTLocationDecider, [ wbFormIDCk('Reference', [ACHR, ACRE, REFR, PLYR], True), wbFormIDCk('Object ID', [ACTI, DOOR, FLOR, STAT, FURN, CREA, SPEL, NPC_, CONT, ARMO, AMMO, MISC, WEAP, INGR, SLGM, SGST, BOOK, KEYM, CLOT, ALCH, APPA, LIGH]), wbInteger('Object type', itU32) ]), wbInteger('Count', itS32) ]), wbCTDAs ]); wbPGRP := wbArray(PGRP, 'Points', wbStruct('Point', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z (Even = Red/Orange, Odd = Blue)'), wbInteger('Connections', itU8{, wbPGRPConnectionsCallback}), wbByteArray('Unused', 3) ]), 0, nil, nil, cpNormal, True); {The Connection Count in the PGRP record specifies how many entries in this array belong to each point. If the first 4 points in the PGRP array have Connection Counts 2, 5, 2, 4 then the first 2 entries are the connections of point 0, then next 5 are the connections of point 1, the next 2 of point 2, the next 4 of point 3 and so on..., this can currently not be represented declaratively } wbRecord(PGRD, 'Path Grid', [ wbInteger(DATA, 'Point Count', itU16, nil, cpNormal, True), wbPGRP, wbByteArray(PGAG, 'Unknown'), wbArray(PGRR, 'Point-to-Point Connections', wbArrayS('Point', wbInteger('Point', itU16), wbCalcPGRRSize{, cpNormal, False, wbPGRRPointAfterLoad}) ), wbArrayS(PGRI, 'Inter-Cell Connections', wbStructSK([0,2,3,4], 'Inter-Cell Connection', [ wbInteger('Point', itU16), wbByteArray('Unused', 2), wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), 0, cpNormal, False, wbPGRIPointerAfterLoad), wbRArrayS('Point-to-Reference Mappings', wbStructSK(PGRL, [0], 'Point-to-Reference Mapping', [ wbFormIDCk('Reference', [REFR]), wbArrayS('Points', wbInteger('Point', itU32)) ]) ) ], False, nil, cpNormal, False, wbPGRDAfterLoad); wbRecord(QUST, 'Quest', [ wbEDID, wbSCRI, wbFULL, wbICON, wbStruct(DATA, 'General', [ wbInteger('Flags', itU8, wbFlags([ {0x01} 'Start game enabled', {0x02} '', {0x04} 'Allow repeated conversation topics', {0x08} 'Allow repeated stages' ])), wbInteger('Priority', itU8) ], cpNormal, True), wbCTDAs, wbRArrayS('Stages', wbRStructSK([0], 'Stage', [ wbInteger(INDX, 'Stage index', itS16), wbRArray('Log Entries', wbRStruct('Log Entry', [ wbInteger(QSDT, 'Stage Flags', itU8, wbFlags([ {0x01} 'Complete quest' ])), wbCTDAs, wbString(CNAM, 'Log Entry', 0, cpTranslate), wbResultScript ], [])) ], [])), wbRArray('Targets', wbRStruct('Target', [ wbStruct(QSTA, 'Target', [ wbFormIDCk('Target', [REFR, ACRE, ACHR], True), wbInteger('Flags', itU8, wbFlags([ {0x01} 'Compass marker ignores locks' ])), wbByteArray('Unused', 3) ]), wbCTDAs ], [])) ]); wbBodyDataIndex := wbInteger(INDX, 'Index', itU32, wbEnum([ 'Upper Body', 'Lower Body', 'Hand', 'Foot', 'Tail' ])); wbRecord(RACE, 'Race', [ wbEDID, wbFULL, wbDESC, wbSPLOs, wbXNAMs, wbStruct(DATA, '', [ wbArrayS('Skill Boosts', wbStructSK([0], 'Skill Boost', [ wbInteger('Skill', itS8, wbActorValueEnum), wbInteger('Boost', itS8) ]), 7), wbByteArray('Unused', 2), wbFloat('Male Height'), wbFloat('Female Height'), wbFloat('Male Weight'), wbFloat('Female Weight'), wbInteger('Flags', itU32, wbFlags([ 'Playable' ])) ], cpNormal, True), wbStruct(VNAM, 'Voice', [ wbFormIDCk('Male', [RACE, NULL]), wbFormIDCk('Female', [RACE, NULL]) ]), wbStruct(DNAM, 'Default Hair', [ wbFormIDCk('Male', [HAIR]), wbFormIDCk('Female', [HAIR]) ]), wbInteger(CNAM, 'Default Hair Color', itU8, nil, cpNormal, True), wbFloat(PNAM, 'FaceGen - Main clamp', cpNormal, True), wbFloat(UNAM, 'FaceGen - Face clamp', cpNormal, True), wbStruct(ATTR, 'Base Attributes', [ wbStruct('Male', [ wbInteger('Strength', itU8), wbInteger('Intelligence', itU8), wbInteger('Willpower', itU8), wbInteger('Agility', itU8), wbInteger('Speed', itU8), wbInteger('Endurance', itU8), wbInteger('Personality', itU8), wbInteger('Luck', itU8) ]), wbStruct('Female', [ wbInteger('Strength', itU8), wbInteger('Intelligence', itU8), wbInteger('Willpower', itU8), wbInteger('Agility', itU8), wbInteger('Speed', itU8), wbInteger('Endurance', itU8), wbInteger('Personality', itU8), wbInteger('Luck', itU8) ]) ]), wbRStruct('Face Data', [ wbEmpty(NAM0, 'Face Data Marker'), wbRArrayS('Parts', wbRStructSK([0], 'Part', [ wbInteger(INDX, 'Index', itU32, wbEnum([ 'Head', 'Ear (Male)', 'Ear (Female)', 'Mouth', 'Teeth (Lower)', 'Teeth (Upper)', 'Tongue', 'Eye (Left)', 'Eye (Right)' ])), wbMODL, wbICON ], [])) ], [], cpNormal, True), wbEmpty(NAM1, 'Body Data Marker', cpNormal, True), wbRStruct('Male Body Data', [ wbEmpty(MNAM, 'Male Body Data Marker'), wbMODL, wbRArrayS('Parts', wbRStructSK([0], 'Part', [ wbBodyDataIndex, wbICON ], [])) ], [], cpNormal, True), wbRStruct('Female Body Data', [ wbEmpty(FNAM, 'Female Body Data Marker'), wbMODL, wbRArrayS('Parts', wbRStructSK([0], 'Part', [ wbBodyDataIndex, wbICON ], [])) ], [], cpNormal, True), wbArrayS(HNAM, 'Hairs', wbFormIDCk('Hair', [HAIR]), 0, cpNormal, True), wbArrayS(ENAM, 'Eyes', wbFormIDCk('Eye', [EYES]), 0, cpNormal, True), wbFaceGen, wbByteArray(SNAM, 'Unknown', 2, cpNormal, True) ], True); wbRecord(REFR, 'Placed Object', [ wbEDID, wbFormIDCk(NAME, 'Base', [TREE, SBSP, LVLC, SOUN, ACTI, DOOR, FLOR, STAT, FURN, CONT, ARMO, AMMO, MISC, WEAP, INGR, SLGM, SGST, BOOK, KEYM, CLOT, ALCH, APPA, LIGH, GRAS], False, cpNormal, True), wbStruct(XTEL, 'Teleport Destination', [ wbFormIDCk('Door', [REFR], True), wbPosRot ]), wbStruct(XLOC, 'Lock information', [ wbInteger('Lock Level', itU8), wbByteArray('Unused', 3), wbFormIDCk('Key', [KEYM, NULL]), wbUnion('Unused', wbXLOCFillerDecider, [ wbEmpty('Unused'), wbByteArray('Unused', 4) ]), wbInteger('Flags', itU8, wbFlags(['', '', 'Leveled Lock'])), wbByteArray('Unused', 3) ]), wbRStruct('Ownership', [ wbXOWN, wbInteger(XRNK, 'Faction rank', itS32), wbXGLB ], [XLOC]), wbXESP, wbFormIDCk(XTRG, 'Target', [REFR, ACHR, ACRE], True), wbUnion(XSED, '', wbREFRXSEDDecider, [ wbInteger('SpeedTree Seed', itU8), wbInteger('SpeedTree Seed (old format)', itU8{itU32 CS just cuts it off...}) ]), wbXLOD, wbFloat(XCHG, 'Charge'), wbInteger(XHLT, 'Health', itS32), wbRStruct('Unused', [ wbFormIDCk(XPCI, 'Unused', [CELL]), wbString(FULL, 'Unused') ], []), wbInteger(XLCM, 'Level Modifier', itS32), wbFormIDCk(XRTM, 'Unknown', [REFR]), wbInteger(XACT, 'Action Flag', itU32, wbFlags([ 'Use Default', 'Activate', 'Open', 'Open by Default' ])), wbInteger(XCNT, 'Count', itS32), wbRStruct('Map Marker', [ wbEmpty(XMRK, 'Map Marker Start Marker'), wbInteger(FNAM, 'Map Flags', itU8, wbFlags([ {0x01} 'Visible', {0x02} 'Can Travel To' ]), cpNormal, True), wbFULLReq, wbStruct(TNAM, '', [ wbInteger('Type', itU8, wbEnum([ {0x00} 'None?', {0x01} 'Camp', {0x02} 'Cave', {0x03} 'City', {0x04} 'Elven Ruin', {0x05} 'Fort Ruin', {0x06} 'Mine', {0x07} 'Landmark', {0x08} 'Tavern', {0x09} 'Settlement', {0x0A} 'Daedric Shrine', {0x0B} 'Oblivion Gate', {0x0C} 'Unknown? (door icon)' ])), wbByteArray('Unused', 1) ], cpNormal, True) ], []), wbEmpty(ONAM, 'Open by Default'), wbXSCL, wbInteger(XSOL, 'Contained Soul', itU8, wbSoulGemEnum), wbDATAPosRot ], True, wbPlacedAddInfo, cpNormal, False, wbREFRAfterLoad); wbRecord(REGN, 'Region', [ wbEDID, wbICON, wbStruct(RCLR, 'Map Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ], cpNormal, True), wbFormIDCk(WNAM, 'Worldspace', [WRLD]), wbRArray('Region Areas', wbRStruct('Region Area', [ wbInteger(RPLI, 'Edge Fall-off', itU32), wbArray(RPLD, 'Region Point List Data', wbStruct('Point', [ wbFloat('X'), wbFloat('Y') ]), 0, wbRPLDAfterLoad) ], []), cpNormal, True), wbRArrayS('Region Data Entries', wbRStructSK([0], 'Region Data Entry', [ {always starts with an RDAT} wbStructSK(RDAT, [0], 'Data Header', [ wbInteger('Type', itU32, wbEnum([ {0}'', {1}'', {2}'Objects', {3}'Weather', {4}'Map', {5}'', {6}'Grass', {7}'Sound', {8}'', {9}'' ])), wbInteger('Flags', itU8, wbFlags([ 'Override' ])), wbInteger('Priority', itU8), wbByteArray('Unused', 2) ], cpNormal, True, nil, 3), {followed by one of these: } {--- Objects ---} wbArray(RDOT, 'Objects', wbStruct('Object', [ wbFormIDCk('Object', [TREE, FLOR, STAT, LTEX]), wbInteger('Parent Index', itU16, wbHideFFFF), wbByteArray('Unused', 2), wbFloat('Density'), wbInteger('Clustering', itU8), wbInteger('Min Slope', itU8), wbInteger('Max Slope', itU8), wbInteger('Flags', itU8, wbFlags([ {0}'Conform to slope', {1}'Paint Vertices', {2}'Size Variance +/-', {3}'X +/-', {4}'Y +/-', {5}'Z +/-', {6}'Tree', {7}'Huge Rock' ])), wbInteger('Radius wrt Parent', itU16), wbInteger('Radius', itU16), wbByteArray('Unknown', 4), wbFloat('Max Height'), wbFloat('Sink'), wbFloat('Sink Variance'), wbFloat('Size Variance'), wbStruct('Angle Variance', [ wbInteger('X', itU16), wbInteger('Y', itU16), wbInteger('Z', itU16) ]), wbByteArray('Unused', 2), wbByteArray('Unknown', 4) ])), {--- Map ---} wbString(RDMP, 'Map Name', 0, cpTranslate), {--- Grass ---} wbArrayS(RDGS, 'Grasses', wbStructSK([0], 'Grass', [ wbFormIDCk('Grass', [GRAS]), wbByteArray('Unused', 4) ])), {--- Sound ---} wbInteger(RDMD, 'Music Type', itU32, wbMusicEnum), wbArrayS(RDSD, 'Sounds', wbStructSK([0], 'Sound', [ wbFormIDCk('Sound', [SOUN]), wbInteger('Flags', itU32, wbFlags([ 'Pleasant', 'Cloudy', 'Rainy', 'Snowy' ])), wbInteger('Chance', itU32, wbScaledInt4ToStr, wbScaledInt4ToInt) ])), {--- Weather ---} wbArrayS(RDWT, 'Weather Types', wbStructSK([0], 'Weather Type', [ wbFormIDCk('Weather', [WTHR]), wbInteger('Chance', itU32) ])) ], [])) ], True); wbRecord(ROAD, 'Road', [ wbPGRP, wbArray(PGRR, 'Point-to-Point Connections (complex structure can''t be represented, see source)', {The Connection Count in the PGRP record specifies how many entries in this array belong to each point. If the first 4 points in the PGRP array have Connection Counts 2, 5, 2, 4 then the first 2 entries are the connections of point 0, then next 5 are the connections of point 1, the next 2 of point 2, the next 4 of point 3 and so on..., this can currently not be represented declaratively } wbStruct('Point', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), 0, nil, nil, cpNormal, True) ]); wbRecord(SBSP, 'Subspace', [ wbEDID, wbStruct(DNAM, '', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ], cpNormal, True) ]); wbSLSD := wbStructSK(SLSD, [0], 'Local Variable Data', [ wbInteger('Index', itU32), wbByteArray('Unused', 12), wbInteger('Flags', itU8, wbFlags(['IsLongOrShort']), cpCritical), wbByteArray('Unused') ]); wbRecord(SCPT, 'Script', [ wbEDID, wbByteArray(SCHD, 'Unknown (Script Header?)'), wbSCHR, wbByteArray(SCDA, 'Compiled Script'), wbStringScript(SCTX, 'Script Source', 0, cpNormal, True), wbRArrayS('Local Variables', wbRStructSK([0], 'Local Variable', [ wbSLSD, wbString(SCVR, 'Name', 0, cpCritical) ], [])), wbSCROs ]); wbRecord(SGST, 'Sigil Stone', [ wbEDID, wbStruct(OBME, 'Oblivion Magic Extender', [ wbInteger('Record Version', itU8), wbStruct('OBME Version', [ wbInteger('Beta', itU8), wbInteger('Minor', itU8), wbInteger('Major', itU8) ]), wbByteArray('Unused', $1C) ], cpNormal, False, wbOBMEDontShow), wbFULL, wbMODL, wbICON, wbSCRI, wbEffects, wbStruct(DATA, '', [ wbInteger('Uses ', itU8), wbInteger('Value', itU32), wbFloat('Weight') ], cpNormal, True) ]); wbRecord(SKIL, 'Skill', [ wbEDID, wbInteger(INDX, 'Skill', itS32, wbActorValueEnum, cpNormal, True), wbDESC, wbICON, wbStruct(DATA, 'Skill Data', [ wbInteger('Action', itS32, wbActorValueEnum), wbInteger('Attribute', itS32, wbActorValueEnum), wbInteger('Specialization', itU32, wbSpecializationEnum), wbArray('Use Values', wbFloat('Use Value'), 2) ], cpNormal, True), wbString(ANAM, 'Apprentice Text', 0, cpTranslate, True), wbString(JNAM, 'Journeyman Text', 0, cpTranslate, True), wbString(ENAM, 'Expert Text', 0, cpTranslate, True), wbString(MNAM, 'Master Text', 0, cpTranslate, True) ]); wbRecord(SLGM, 'Soul Gem', [ wbEDID, wbFULL, wbMODL, wbICON, wbSCRI, wbStruct(DATA, '', [ wbInteger('Value', itU32), wbFloat('Weight') ], cpNormal, True), wbInteger(SOUL, 'Contained Soul', itU8, wbSoulGemEnum, cpNormal, True), wbInteger(SLCP, 'Maximum Capacity', itU8, wbSoulGemEnum, cpNormal, True) ]); wbRecord(SOUN, 'Sound', [ wbEDID, wbString(FNAM, 'Sound Filename'), wbRUnion('Sound Data', [ wbStruct(SNDX, 'Sound Data', [ wbInteger('Minimum attentuation distance', itU8, wbMul(5)), wbInteger('Maximum attentuation distance', itU8, wbMul(100)), wbInteger('Frequency adjustment %', itS8), wbByteArray('Unused', 1), wbInteger('Flags', itU16, wbFlags([ {0x0001} 'Random Frequency Shift', {0x0002} 'Play At Random', {0x0004} 'Environment Ignored', {0x0008} 'Random Location', {0x0010} 'Loop', {0x0020} 'Menu Sound', {0x0040} '2D', {0x0080} '360 LFE' ])), wbByteArray('Unused', 2), wbInteger('Static attentuation cdB', itS16), wbInteger('Stop time ', itU8), wbInteger('Start time ', itU8) ], cpNormal, True), wbStruct(SNDD, 'Sound Data', [ wbInteger('Minimum attentuation distance', itU8, wbMul(5)), wbInteger('Maximum attentuation distance', itU8, wbMul(100)), wbInteger('Frequency adjustment %', itS8), wbByteArray('Unused', 1), wbInteger('Flags', itU16, wbFlags([ {0x0001} 'Random Frequency Shift', {0x0002} 'Play At Random', {0x0004} 'Environment Ignored', {0x0008} 'Random Location', {0x0010} 'Loop', {0x0020} 'Menu Sound', {0x0040} '2D', {0x0080} '360 LFE' ])), wbByteArray('Unused', 2), wbEmpty('Unused'), wbEmpty('Unused'), wbEmpty('Unused') ], cpNormal, True) ], [], cpNormal, True) ]); wbRecord(SPEL, 'Spell', [ wbEDID, wbStruct(OBME, 'Oblivion Magic Extender', [ wbInteger('Record Version', itU8), wbStruct('OBME Version', [ wbInteger('Beta', itU8), wbInteger('Minor', itU8), wbInteger('Major', itU8) ]), wbByteArray('Unused', $1C) ], cpNormal, False, wbOBMEDontShow), wbFULL, wbStruct(SPIT, '', [ wbInteger('Type', itU32, wbEnum([ {0} 'Spell', {1} 'Disease', {2} 'Power', {3} 'Lesser Power', {4} 'Ability', {5} 'Poison' ])), wbInteger('Cost', itU32), wbInteger('Level', itU32, wbEnum([ {0} 'Novice', {1} 'Apprentice', {2} 'Journeyman', {3} 'Expert', {4} 'Master' ])), wbInteger('Flags', itU8, wbFlags([ {0x00000001} 'Manual Spell Cost', {0x00000002} 'Immune to Silence 1', {0x00000004} 'Player Start Spell', {0x00000008} 'Immune to Silence 2', {0x00000010} 'Area Effect Ignores LOS', {0x00000020} 'Script Effect Always Applies', {0x00000040} 'Disallow Spell Absorb/Reflect', {0x00000080} 'Touch Spell Explodes w/ no Target' ])), wbByteArray('Unused', 3) ], cpNormal, True), wbEffects ]); wbRecord(STAT, 'Static', [ wbEDID, wbMODL ]); wbRecord(TES3, 'Main File Header', [ wbStruct(HEDR, 'Header', [ wbFloat('Version'), wbInteger('Number of Records', itU32), wbInteger('Next Object ID', itU32) ], cpNormal, True), wbByteArray(OFST, 'Unknown', 0, cpIgnore), wbByteArray(DELE, 'Unknown', 0, cpIgnore), wbString(CNAM, 'Author', 0, cpTranslate, True), wbString(SNAM, 'Description', 0, cpTranslate), wbRArray('Master Files', wbRStruct('Master File', [ wbString(MAST, 'Filename', 0, cpNormal, True), wbByteArray(DATA, 'Unused', 8, cpIgnore, True) ], [])) ], False, nil, cpNormal, True, wbRemoveOFST); wbRecord(TREE, 'Tree', [ wbEDID, wbMODL, wbICON, wbArrayS(SNAM, 'SpeedTree Seeds', wbInteger('SpeedTree Seed', itU32)), wbStruct(CNAM, 'Tree Data', [ wbFloat('Leaf Curvature'), wbFloat('Minimum Leaf Angle'), wbFloat('Maximum Leaf Angle'), wbFloat('Branch Dimming Value'), wbFloat('Leaf Dimming Value'), wbInteger('Shadow Radius', itS32), wbFloat('Rock Speed'), wbFloat('Rustle Speed') ], cpNormal, True), wbStruct(BNAM, 'Billboard Dimensions', [ wbFloat('Width'), wbFloat('Height') ], cpNormal, True) ]); wbRecord(WATR, 'Water', [ wbEDID, wbString(TNAM, 'Texture', 0, cpNormal, True), wbInteger(ANAM, 'Opacity', itU8, nil, cpNormal, True), wbInteger(FNAM, 'Flags', itU8, wbFlags([ {0}'Causes Damage', {1}'Reflective' ]), cpNormal, True), wbString(MNAM, 'Material ID'), wbFormIDCk(SNAM, 'Sound', [SOUN]), wbStruct(DATA, '', [ wbFloat('Wind Velocity'), wbFloat('Wind Direction'), wbFloat('Wave Amplitude'), wbFloat('Wave Frequency'), wbFloat('Sun Power'), wbFloat('Reflectivity Amount'), wbFloat('Fresnel Amount'), wbFloat('Scroll X Speed'), wbFloat('Scroll Y Speed'), wbFloat('Fog Distance - Near Plane'), wbFloat('Fog Distance - Far Plane'), wbStruct('Shallow Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Deep Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Reflection Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbInteger('Texture Blend', itU8), wbByteArray('Unused', 3), wbFloat('Rain Simulator - Force'), wbFloat('Rain Simulator - Velocity'), wbFloat('Rain Simulator - Falloff'), wbFloat('Rain Simulator - Dampner'), wbFloat('Rain Simulator - Starting Size'), wbFloat('Displacement Simulator - Force'), wbFloat('Displacement Simulator - Velocity'), wbFloat('Displacement Simulator - Falloff'), wbFloat('Displacement Simulator - Dampner'), wbFloat('Displacement Simulator - Starting Size'), wbInteger('Damage', itU16) ], cpNormal, True, nil, 0), wbStruct(GNAM, 'Related Waters', [ wbFormIDCk('Daytime', [WATR, NULL]), wbFormIDCk('Nighttime', [WATR, NULL]), wbFormIDCk('Underwater', [WATR, NULL]) ], cpNormal, True) ]); wbRecord(WEAP, 'Weapon', [ wbEDID, wbFULL, wbMODL, wbICON, wbSCRI, wbENAM, wbInteger(ANAM, 'Enchantment Points', itU16), wbStruct(DATA, '', [ wbInteger('Type', itU32, wbEnum([ {0} 'Blade One Hand', {1} 'Blade Two Hand', {2} 'Blunt One Hand', {3} 'Blunt Two Hand', {4} 'Staff', {5} 'Bow' ])), wbFloat('Speed'), wbFloat('Reach'), wbInteger('Flags', itU32, wbFlags(['Ignores Normal Weapon Resistance'])), wbInteger('Value', itU32), wbInteger('Health', itU32), wbFloat('Weight'), wbInteger('Damage', itU16) ], cpNormal, True) ]); wbRecord(WRLD, 'Worldspace', [ wbEDID, wbFULL, wbFormIDCk(WNAM, 'Parent Worldspace', [WRLD]), wbFormIDCk(CNAM, 'Climate', [CLMT]), wbFormIDCk(NAM2, 'Water', [WATR]), wbICON, wbStruct(MNAM, 'Map Data', [ wbStruct('Uable Dimensions', [ wbInteger('X', itS32), wbInteger('Y', itS32) ]), wbStruct('Cell Coordinates', [ wbStruct('NW Cell', [ wbInteger('X', itS16), wbInteger('Y', itS16) ]), wbStruct('SE Cell', [ wbInteger('X', itS16), wbInteger('Y', itS16) ]) ]) ]), wbInteger(DATA, 'Flags', itU8, wbFlags([ {0x01} 'Small world', {0x02} 'Can''t fast travel', {0x04} 'Oblivion worldspace', {0x08} '', {0x10} 'No LOD water' ]), cpNormal, True), wbArray(NAM0, 'Unknown', wbFloat(''), 0, nil, nil, cpNormal, True), wbArray(NAM9, 'Unknown', wbFloat(''), 0, nil, nil, cpNormal, True), wbInteger(SNAM, 'Music', itU32, wbMusicEnum), wbByteArray(OFST, 'Unknown') ], False, nil, cpNormal, False, wbRemoveOFST); wbRecord(WTHR, 'Weather', [ wbEDID, wbString(CNAM, 'Texture Lower Layer'), wbString(DNAM, 'Texture Upper Layer'), wbMODL, wbArray(NAM0, 'Colors by Types/Times', wbArray('Type', wbStruct('Time', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), ['Sunrise', 'Day', 'Sunset', 'Night'] ), ['Sky-Upper','Fog','Clouds-Lower','Ambient','Sunlight','Sun','Stars','Sky-Lower','Horizon','Clouds-Upper'] , cpNormal, True), wbStruct(FNAM, 'Fog Distance', [ wbFloat('Day Near'), wbFloat('Day Far'), wbFloat('Night Near'), wbFloat('Night Far') ], cpNormal, True), wbStruct(HNAM, 'HDR Data', [ wbFloat('Eye Adapt Speed'), wbFloat('Blur Radius'), wbFloat('Blur Passes'), wbFloat('Emissive Mult'), wbFloat('Target LUM'), wbFloat('Upper LUM Clamp'), wbFloat('Bright Scale'), wbFloat('Bright Clamp'), wbFloat('LUM Ramp No Tex'), wbFloat('LUM Ramp Min'), wbFloat('LUM Ramp Max'), wbFloat('Sunlight Dimmer'), wbFloat('Grass Dimmer'), wbFloat('Tree Dimmer') ], cpNormal, True), wbStruct(DATA, '', [ wbInteger('Wind Speed', itU8), wbInteger('Cloud Speed (Lower)', itU8), wbInteger('Cloud Speed (Upper)', itU8), wbInteger('Trans Delta', itU8), wbInteger('Sun Glare', itU8), wbInteger('Sun Damage', itU8), wbInteger('Precipitation - Begin Fade In', itU8), wbInteger('Precipitation - End Fade Out', itU8), wbInteger('Thunder/Lightning - Begin Fade In', itU8), wbInteger('Thunder/Lightning - End Fade Out', itU8), wbInteger('Thunder/Lightning - Frequency', itU8), wbInteger('Weather Classification', itU8, wbWthrDataClassification), wbStruct('Lightning Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8) ]) ], cpNormal, True), wbRArray('Sounds', wbStruct(SNAM, 'Sound', [ wbFormIDCk('Sound', [SOUN]), wbInteger('Type', itU32, wbEnum([ {0}'Default', {1}'Precip', {2}'Wind', {3}'Thunder' ])) ])) ]); wbAddGroupOrder(GMST); wbAddGroupOrder(GLOB); wbAddGroupOrder(CLAS); wbAddGroupOrder(FACT); wbAddGroupOrder(HAIR); wbAddGroupOrder(EYES); wbAddGroupOrder(RACE); wbAddGroupOrder(SOUN); wbAddGroupOrder(SKIL); wbAddGroupOrder(MGEF); wbAddGroupOrder(SCPT); wbAddGroupOrder(LTEX); wbAddGroupOrder(ENCH); wbAddGroupOrder(SPEL); wbAddGroupOrder(BSGN); wbAddGroupOrder(ACTI); wbAddGroupOrder(APPA); wbAddGroupOrder(ARMO); wbAddGroupOrder(BOOK); wbAddGroupOrder(CLOT); wbAddGroupOrder(CONT); wbAddGroupOrder(DOOR); wbAddGroupOrder(INGR); wbAddGroupOrder(LIGH); wbAddGroupOrder(MISC); wbAddGroupOrder(STAT); wbAddGroupOrder(GRAS); wbAddGroupOrder(TREE); wbAddGroupOrder(FLOR); wbAddGroupOrder(FURN); wbAddGroupOrder(WEAP); wbAddGroupOrder(AMMO); wbAddGroupOrder(NPC_); wbAddGroupOrder(CREA); wbAddGroupOrder(LVLC); wbAddGroupOrder(SLGM); wbAddGroupOrder(KEYM); wbAddGroupOrder(ALCH); wbAddGroupOrder(SBSP); wbAddGroupOrder(SGST); wbAddGroupOrder(LVLI); wbAddGroupOrder(WTHR); wbAddGroupOrder(CLMT); wbAddGroupOrder(REGN); wbAddGroupOrder(CELL); wbAddGroupOrder(WRLD); wbAddGroupOrder(DIAL); wbAddGroupOrder(QUST); wbAddGroupOrder(IDLE); wbAddGroupOrder(PACK); wbAddGroupOrder(CSTY); wbAddGroupOrder(LSCR); wbAddGroupOrder(LVSP); wbAddGroupOrder(ANIO); wbAddGroupOrder(WATR); wbAddGroupOrder(EFSH); end; initialization end. ================================================ FILE: lib/xedit/wbDefinitionsTES4.pas ================================================ {******************************************************************************* The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. *******************************************************************************} unit wbDefinitionsTES4; {$I wbDefines.inc} interface uses wbInterface; var wbPKDTFlags: IwbFlagsDef; wbServiceFlags: IwbFlagsDef; wbAxisEnum: IwbEnumDef; wbBlendModeEnum: IwbEnumDef; wbBlendOpEnum: IwbEnumDef; wbCrimeTypeEnum: IwbEnumDef; wbFormTypeEnum: IwbEnumDef; wbFunctionsEnum: IwbEnumDef; wbMagicSchoolEnum: IwbEnumDef; wbMusicEnum: IwbEnumDef; wbOBMEResolutionInfo: IwbEnumDef; wbPKDTType: IwbEnumDef; wbQuadrantEnum: IwbEnumDef; wbSexEnum: IwbEnumDef; wbSkillEnum: IwbEnumDef; wbSoulGemEnum: IwbEnumDef; wbSpecializationEnum: IwbEnumDef; wbZTestFuncEnum: IwbEnumDef; procedure DefineTES4; implementation uses Types, Classes, SysUtils, Math, Variants, wbHelpers; const ACBS : TwbSignature = 'ACBS'; ACHR : TwbSignature = 'ACHR'; ACRE : TwbSignature = 'ACRE'; TRGT : TwbSignature = 'TRGT'; ACTI : TwbSignature = 'ACTI'; AIDT : TwbSignature = 'AIDT'; ALCH : TwbSignature = 'ALCH'; AMMO : TwbSignature = 'AMMO'; ANAM : TwbSignature = 'ANAM'; ANIO : TwbSignature = 'ANIO'; APPA : TwbSignature = 'APPA'; ARMO : TwbSignature = 'ARMO'; ATTR : TwbSignature = 'ATTR'; ATXT : TwbSignature = 'ATXT'; BMDT : TwbSignature = 'BMDT'; BNAM : TwbSignature = 'BNAM'; BOOK : TwbSignature = 'BOOK'; BSGN : TwbSignature = 'BSGN'; BTXT : TwbSignature = 'BTXT'; CELL : TwbSignature = 'CELL'; CLAS : TwbSignature = 'CLAS'; CLMT : TwbSignature = 'CLMT'; CLOT : TwbSignature = 'CLOT'; CNAM : TwbSignature = 'CNAM'; CNTO : TwbSignature = 'CNTO'; CONT : TwbSignature = 'CONT'; CREA : TwbSignature = 'CREA'; CSAD : TwbSignature = 'CSAD'; CSCR : TwbSignature = 'CSCR'; CSDC : TwbSignature = 'CSDC'; CSDI : TwbSignature = 'CSDI'; CSDT : TwbSignature = 'CSDT'; CSTD : TwbSignature = 'CSTD'; CSTY : TwbSignature = 'CSTY'; CTDA : TwbSignature = 'CTDA'; CTDT : TwbSignature = 'CTDT'; DATA : TwbSignature = 'DATA'; DATX : TwbSignature = 'DATX'; DELE : TwbSignature = 'DELE'; DESC : TwbSignature = 'DESC'; DIAL : TwbSignature = 'DIAL'; DNAM : TwbSignature = 'DNAM'; DOOR : TwbSignature = 'DOOR'; EDID : TwbSignature = 'EDID'; EDDX : TwbSignature = 'EDDX'; EFID : TwbSignature = 'EFID'; EFIT : TwbSignature = 'EFIT'; ACVA : TwbSignature = 'ACVA'; EFII : TwbSignature = 'EFII'; EFXX : TwbSignature = 'EFXX'; EFIX : TwbSignature = 'EFIX'; EFME : TwbSignature = 'EFME'; EFSH : TwbSignature = 'EFSH'; ENAM : TwbSignature = 'ENAM'; ENCH : TwbSignature = 'ENCH'; ENIT : TwbSignature = 'ENIT'; ESCE : TwbSignature = 'ESCE'; EYES : TwbSignature = 'EYES'; FACT : TwbSignature = 'FACT'; FGGA : TwbSignature = 'FGGA'; FGGS : TwbSignature = 'FGGS'; FGTS : TwbSignature = 'FGTS'; FLOR : TwbSignature = 'FLOR'; FLTV : TwbSignature = 'FLTV'; FNAM : TwbSignature = 'FNAM'; FULL : TwbSignature = 'FULL'; FURN : TwbSignature = 'FURN'; GLOB : TwbSignature = 'GLOB'; GMST : TwbSignature = 'GMST'; GNAM : TwbSignature = 'GNAM'; GRAS : TwbSignature = 'GRAS'; HAIR : TwbSignature = 'HAIR'; HCLR : TwbSignature = 'HCLR'; HEDR : TwbSignature = 'HEDR'; HNAM : TwbSignature = 'HNAM'; ICO2 : TwbSignature = 'ICO2'; ICON : TwbSignature = 'ICON'; IDLE : TwbSignature = 'IDLE'; NULL : TwbSignature = 'NULL'; INAM : TwbSignature = 'INAM'; INDX : TwbSignature = 'INDX'; INFO : TwbSignature = 'INFO'; INGR : TwbSignature = 'INGR'; JNAM : TwbSignature = 'JNAM'; KEYM : TwbSignature = 'KEYM'; KFFZ : TwbSignature = 'KFFZ'; LAND : TwbSignature = 'LAND'; LIGH : TwbSignature = 'LIGH'; LNAM : TwbSignature = 'LNAM'; LSCR : TwbSignature = 'LSCR'; LTEX : TwbSignature = 'LTEX'; LVLC : TwbSignature = 'LVLC'; LVLD : TwbSignature = 'LVLD'; LVLF : TwbSignature = 'LVLF'; LVLI : TwbSignature = 'LVLI'; LVLO : TwbSignature = 'LVLO'; LVSP : TwbSignature = 'LVSP'; MAST : TwbSignature = 'MAST'; MGEF : TwbSignature = 'MGEF'; MISC : TwbSignature = 'MISC'; MNAM : TwbSignature = 'MNAM'; MO2B : TwbSignature = 'MO2B'; MO2T : TwbSignature = 'MO2T'; MO3B : TwbSignature = 'MO3B'; MO3T : TwbSignature = 'MO3T'; MO4B : TwbSignature = 'MO4B'; MO4T : TwbSignature = 'MO4T'; MOD2 : TwbSignature = 'MOD2'; MOD3 : TwbSignature = 'MOD3'; MOD4 : TwbSignature = 'MOD4'; MODB : TwbSignature = 'MODB'; MODL : TwbSignature = 'MODL'; MODT : TwbSignature = 'MODT'; NAM0 : TwbSignature = 'NAM0'; NAM1 : TwbSignature = 'NAM1'; NAM2 : TwbSignature = 'NAM2'; NAM9 : TwbSignature = 'NAM9'; NAME : TwbSignature = 'NAME'; NIFT : TwbSignature = 'NIFT'; NIFZ : TwbSignature = 'NIFZ'; NPC_ : TwbSignature = 'NPC_'; OFST : TwbSignature = 'OFST'; OBME : TwbSignature = 'OBME'; ONAM : TwbSignature = 'ONAM'; PACK : TwbSignature = 'PACK'; PFIG : TwbSignature = 'PFIG'; PFPC : TwbSignature = 'PFPC'; PGAG : TwbSignature = 'PGAG'; PGRD : TwbSignature = 'PGRD'; PGRI : TwbSignature = 'PGRI'; PGRL : TwbSignature = 'PGRL'; PGRP : TwbSignature = 'PGRP'; PGRR : TwbSignature = 'PGRR'; PKDT : TwbSignature = 'PKDT'; PKID : TwbSignature = 'PKID'; PLDT : TwbSignature = 'PLDT'; PNAM : TwbSignature = 'PNAM'; PSDT : TwbSignature = 'PSDT'; PTDT : TwbSignature = 'PTDT'; QNAM : TwbSignature = 'QNAM'; QSDT : TwbSignature = 'QSDT'; QSTA : TwbSignature = 'QSTA'; QSTI : TwbSignature = 'QSTI'; QSTR : TwbSignature = 'QSTR'; TPIC : TwbSignature = 'TPIC'; QUST : TwbSignature = 'QUST'; RACE : TwbSignature = 'RACE'; RCLR : TwbSignature = 'RCLR'; RDAT : TwbSignature = 'RDAT'; RDGS : TwbSignature = 'RDGS'; RDMD : TwbSignature = 'RDMD'; RDMP : TwbSignature = 'RDMP'; RDOT : TwbSignature = 'RDOT'; RDSD : TwbSignature = 'RDSD'; RDWT : TwbSignature = 'RDWT'; REFR : TwbSignature = 'REFR'; PLYR : TwbSignature = 'PLYR'; REGN : TwbSignature = 'REGN'; RNAM : TwbSignature = 'RNAM'; ROAD : TwbSignature = 'ROAD'; RPLD : TwbSignature = 'RPLD'; RPLI : TwbSignature = 'RPLI'; SBSP : TwbSignature = 'SBSP'; SCDA : TwbSignature = 'SCDA'; SCHD : TwbSignature = 'SCHD'; SCHR : TwbSignature = 'SCHR'; SCIT : TwbSignature = 'SCIT'; SCPT : TwbSignature = 'SCPT'; SCRI : TwbSignature = 'SCRI'; SCRO : TwbSignature = 'SCRO'; SCRV : TwbSignature = 'SCRV'; SCTX : TwbSignature = 'SCTX'; SCVR : TwbSignature = 'SCVR'; SGST : TwbSignature = 'SGST'; SKIL : TwbSignature = 'SKIL'; SLCP : TwbSignature = 'SLCP'; SLGM : TwbSignature = 'SLGM'; SLSD : TwbSignature = 'SLSD'; SNAM : TwbSignature = 'SNAM'; SNDD : TwbSignature = 'SNDD'; SNDX : TwbSignature = 'SNDX'; SOUL : TwbSignature = 'SOUL'; SOUN : TwbSignature = 'SOUN'; SPEL : TwbSignature = 'SPEL'; SPIT : TwbSignature = 'SPIT'; SPLO : TwbSignature = 'SPLO'; STAT : TwbSignature = 'STAT'; TCLF : TwbSignature = 'TCLF'; TCLT : TwbSignature = 'TCLT'; TES4 : TwbSignature = 'TES4'; TNAM : TwbSignature = 'TNAM'; TRDT : TwbSignature = 'TRDT'; TREE : TwbSignature = 'TREE'; UNAM : TwbSignature = 'UNAM'; VCLR : TwbSignature = 'VCLR'; VHGT : TwbSignature = 'VHGT'; VNAM : TwbSignature = 'VNAM'; VNML : TwbSignature = 'VNML'; VTEX : TwbSignature = 'VTEX'; VTXT : TwbSignature = 'VTXT'; WATR : TwbSignature = 'WATR'; WEAP : TwbSignature = 'WEAP'; WLST : TwbSignature = 'WLST'; WNAM : TwbSignature = 'WNAM'; WRLD : TwbSignature = 'WRLD'; WTHR : TwbSignature = 'WTHR'; XACT : TwbSignature = 'XACT'; XCCM : TwbSignature = 'XCCM'; XCHG : TwbSignature = 'XCHG'; XCLC : TwbSignature = 'XCLC'; XCLL : TwbSignature = 'XCLL'; XCLR : TwbSignature = 'XCLR'; XCLW : TwbSignature = 'XCLW'; XCMT : TwbSignature = 'XCMT'; XCNT : TwbSignature = 'XCNT'; XCWT : TwbSignature = 'XCWT'; XESP : TwbSignature = 'XESP'; XGLB : TwbSignature = 'XGLB'; XHLT : TwbSignature = 'XHLT'; XHRS : TwbSignature = 'XHRS'; XLCM : TwbSignature = 'XLCM'; XLOC : TwbSignature = 'XLOC'; XLOD : TwbSignature = 'XLOD'; XMRC : TwbSignature = 'XMRC'; XMRK : TwbSignature = 'XMRK'; XNAM : TwbSignature = 'XNAM'; XOWN : TwbSignature = 'XOWN'; XPCI : TwbSignature = 'XPCI'; XRGD : TwbSignature = 'XRGD'; XRNK : TwbSignature = 'XRNK'; XRTM : TwbSignature = 'XRTM'; XSCL : TwbSignature = 'XSCL'; XSED : TwbSignature = 'XSED'; XSOL : TwbSignature = 'XSOL'; XTEL : TwbSignature = 'XTEL'; XTRG : TwbSignature = 'XTRG'; XXXX : TwbSignature = 'XXXX'; ZNAM : TwbSignature = 'ZNAM'; var wbEDID: IwbSubRecordDef; wbXOWN: IwbSubRecordDef; wbXGLB: IwbSubRecordDef; wbXRGD: IwbSubRecordDef; wbSLSD: IwbSubRecordDef; wbBodyDataIndex: IwbSubRecordDef; wbSPLO: IwbSubRecordDef; wbSPLOs: IwbSubRecordArrayDef; wbCNTO: IwbSubRecordDef; wbCNTOs: IwbSubRecordArrayDef; wbCSDT: IwbSubRecordStructDef; wbCSDTs: IwbSubRecordArrayDef; wbFULL: IwbSubRecordDef; wbFULLReq: IwbSubRecordDef; wbXNAM: IwbSubRecordDef; wbXNAMs: IwbSubRecordArrayDef; wbDESC: IwbSubRecordDef; wbXSCL: IwbSubRecordDef; wbDATAPosRot : IwbSubRecordDef; wbPosRot : IwbStructDef; wbMODL: IwbSubRecordStructDef; wbCTDA: IwbSubRecordUnionDef; wbSCHR: IwbSubRecordUnionDef; wbCTDAs: IwbSubRecordArrayDef; wbSCROs: IwbSubRecordArrayDef; wbPGRP: IwbSubRecordDef; wbResultScript: IwbSubRecordStructDef; // wbResultScriptOld: IwbSubRecordStructDef; wbSCRI: IwbSubRecordDef; wbFaceGen: IwbSubRecordStructDef; wbENAM: IwbSubRecordDef; wbFGGS: IwbSubRecordDef; wbXLOD: IwbSubRecordDef; wbXESP: IwbSubRecordDef; wbICON: IwbSubRecordDef; wbEFID: IwbSubRecordDef; wbEFIDOBME: IwbSubRecordDef; wbEFIT: IwbSubRecordDef; wbEFITOBME: IwbSubRecordDef; wbEFIX: IwbSubRecordDef; wbSCIT: IwbSubRecordStructDef; wbSCITOBME: IwbSubRecordStructDef; // wbEffects: IwbSubRecordUnionDef; wbEffects: IwbSubRecordArrayDef; function wbClmtMoonsPhaseLength(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var PhaseLength : Byte; Masser : Boolean; Secunda : Boolean; begin Result := ''; if aType = ctToSortKey then begin Result := IntToHex64(aInt, 2); end else if aType = ctToStr then begin PhaseLength := aInt mod 64; Masser := (aInt and 64) <> 0; Secunda := (aInt and 128) <> 0; if Masser then if Secunda then Result := 'Masser, Secunda / ' else Result := 'Masser / ' else if Secunda then Result := 'Secunda / ' else Result := 'No Moon / '; Result := Result + IntToStr(PhaseLength); end; end; function wbClmtTime(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; begin Result := ''; if aType = ctToSortKey then Result := IntToHex64(aInt, 4) else if aType = ctToStr then Result := TimeToStr( EncodeTime(aInt div 6, (aInt mod 6) * 10, 0, 0) ); end; var wbCtdaTypeFlags : IwbFlagsDef; function wbCtdaType(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var s: string; begin Result := ''; case aType of ctToStr: begin case aInt and $F0 of $00 : Result := 'Equal to'; $20 : Result := 'Not equal to'; $40 : Result := 'Greater than'; $60 : Result := 'Greater than or equal to'; $80 : Result := 'Less than'; $A0 : Result := 'Less than or equal to'; else Result := '' end; if not Assigned(wbCtdaTypeFlags) then wbCtdaTypeFlags := wbFlags([ {0x01} 'Or', {0x02} 'Run on target', {0x04} 'Use global' ]); s := wbCtdaTypeFlags.ToString(aInt and $0F, aElement); if s <> '' then Result := Result + ' / ' + s; end; ctToSortKey: begin Result := IntToHex64(aInt, 2); Exit; end; ctCheck: begin case aInt and $F0 of $00, $20, $40, $60, $80, $A0 : Result := ''; else Result := '' end; if not Assigned(wbCtdaTypeFlags) then wbCtdaTypeFlags := wbFlags([ {0x01} 'Or', {0x02} 'Run on target', {0x04} 'Use global' ]); s := wbCtdaTypeFlags.Check(aInt and $0F, aElement); if s <> '' then Result := Result + ' / ' + s; end; end; end; function wbIdleAnam(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; begin Result := ''; case aType of ctToStr: begin case aInt and not $80 of 0: Result := 'Lower Body'; 1: Result := 'Left Arm'; 2: Result := 'Left Hand'; 3: Result := 'Right Arm'; 4: Result := 'Special Idle'; 5: Result := 'Whole Body'; 6: Result := 'Upper Body'; else Result := ''; end; if (aInt and $80) = 0 then Result := Result + ', Must return a file'; end; ctToSortKey: begin Result := IntToHex64(aInt, 2); end; ctCheck: begin case aInt and not $80 of 0..6: Result := ''; else Result := ''; end; end; end; end; function wbScaledInt4ToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; const PlusMinus : array[Boolean] of string = ('+', '-'); begin Result := ''; case aType of ctToStr, ctToEditValue: Result := FloatToStrF(aInt / 10000, ffFixed, 99, 4); ctToSortKey: begin Result := FloatToStrF(aInt / 10000, ffFixed, 99, 4); if Length(Result) < 22 then Result := StringOfChar('0', 22 - Length(Result)) + Result; Result := PlusMinus[aInt < 0] + Result; end; ctCheck: Result := ''; end; end; function wbScaledInt4ToInt(const aString: string; const aElement: IwbElement): Int64; var f: Extended; begin f := StrToFloat(aString); f := f * 10000; Result := Round(f); end; function wbHideFFFF(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; begin Result := ''; if aType = ctToSortKey then Result := IntToHex64(aInt, 4) else if aType = ctToStr then if aInt = $FFFF then Result := 'None' else Result := IntToStr(aInt); end; function wbAtxtPosition(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; begin Result := ''; if aType = ctToSortKey then Result := IntToHex64(aInt div 17, 2) + IntToHex64(aInt mod 17, 2) else if aType = ctCheck then begin if (aInt < 0) or (aInt > 288) then Result := '' else Result := ''; end else if aType = ctToStr then Result := IntToStr(aInt) + ' -> ' + IntToStr(aInt div 17) + ':' + IntToStr(aInt mod 17); end; function wbWthrDataClassification(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; begin Result := ''; case aType of ctToStr: begin case aInt and not 192 of 0: Result := 'None'; 1: Result := 'Pleasant'; 2: Result := 'Cloudy'; 3: Result := 'Unknown 3'; 4: Result := 'Rainy'; 8: Result := 'Snow'; else Result := ''; end; end; ctToSortKey: begin Result := IntToHex64(aInt, 2) end; ctCheck: begin case aInt and not 192 of 0..4, 8: Result := ''; else Result := ''; end; end; end; end; function wbGLOBFNAM(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; begin Result := ''; case aType of ctToStr: begin case aInt of Ord('s'): Result := 'Short'; Ord('l'): Result := 'Long'; Ord('f'): Result := 'Float'; else Result := ''; end; end; ctToSortKey: Result := Chr(aInt); ctCheck: begin case aInt of Ord('s'), Ord('l'), Ord('f'): Result := ''; else Result := ''; end; end; end; end; function wbPlacedAddInfo(const aMainRecord: IwbMainRecord): string; var Rec: IwbRecord; Container: IwbContainer; s: string; Cell: IwbMainRecord; Position: TwbVector; Grid: TwbGridCell; begin Result := ''; Rec := aMainRecord.RecordBySignature['NAME']; if Assigned(Rec) then begin s := Trim(Rec.Value); if s <> '' then Result := 'places ' + s; end; Container := aMainRecord.Container; while Assigned(Container) and (Container.ElementType <> etGroupRecord) do Container := Container.Container; if Assigned(Container) then begin s := Trim(Container.Name); if s <> '' then begin if Result <> '' then Result := Result + ' '; Result := Result + 'in ' + s; // grid position of persistent reference in exterior persistent cell (interior cells are not persistent) if Supports(aMainRecord.Container, IwbGroupRecord, Container) then Cell := IwbGroupRecord(Container).ChildrenOf; if Assigned(Cell) and Cell.IsPersistent and (Cell.Signature = 'CELL') then if aMainRecord.GetPosition(Position) then begin Grid := wbPositionToGridCell(Position); Result := Result + ' at ' + IntToStr(Grid.x) + ',' + IntToStr(Grid.y); end; end; end; end; function wbCellAddInfo(const aMainRecord: IwbMainRecord): string; var Rec: IwbRecord; Container: IwbContainer; GroupRecord : IwbGroupRecord; s: string; begin Result := ''; if not aMainRecord.IsPersistent then begin Rec := aMainRecord.RecordBySignature['XCLC']; if Assigned(Rec) then Result := 'at ' + Rec.Elements[0].Value + ',' + Rec.Elements[1].Value; end; Container := aMainRecord.Container; while Assigned(Container) and not (Supports(Container, IwbGroupRecord, GroupRecord) and (GroupRecord.GroupType = 1)) do Container := Container.Container; if Assigned(Container) then begin s := wbFormID.ToString(GroupRecord.GroupLabel, aMainRecord); if s <> '' then begin if Result <> '' then s := s + ' '; Result := 'in ' + s + Result; end; end; end; function wbGMSTUnionDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var rEDID: IwbRecord; s: string; begin Result := 1; rEDID := aElement.Container.RecordBySignature[EDID]; if Assigned(rEDID) then begin s := rEDID.Value; if Length(s) > 0 then case s[1] of 's': Result := 0; 'f': Result := 2; end; end; end; function wbMISCActorValueDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var MainRecord : IwbMainRecord; begin Result := 0; if not Assigned(aElement) then Exit; MainRecord := aElement.ContainingMainRecord; if not Assigned(MainRecord) then Exit; if (MainRecord.Flags._Flags and $000000C0) = $000000C0 then Result := 1; end; function wbXLOCFillerDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; SubRecord : IwbSubRecord; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; if Supports(Container, IwbSubRecord, SubRecord) then if SubRecord.SubRecordHeaderSize = 16 then Result := 1; end; function wbPACKPKDTDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; SubRecord : IwbSubRecord; begin Result := 1; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; if Supports(Container, IwbSubRecord, SubRecord) then if SubRecord.SubRecordHeaderSize = 4 then Result := 0; end; function wbREFRXSEDDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; SubRecord : IwbSubRecord; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; if Supports(Container, IwbSubRecord, SubRecord) then if SubRecord.SubRecordHeaderSize = 4 then Result := 1; end; type TCTDAFunctionParamType = ( ptNone, ptInteger, ptVariableName, //Integer ptSex, //Enum: Male, Female ptActorValue, //Enum: wbActorValue ptCrimeType, //?? Enum ptAxis, //?? Char ptFormType, //?? Enum ptQuestStage, ptObjectReference, //REFR, ACHR, ACRE, PGRE ptInventoryObject, //ARMO, BOOK, MISC, WEAP, AMMO, KEYM, ALCH, NOTE, ARMA ptActor, //ACHR, ACRE ptQuest, //QUST ptFaction, //FACT ptCell, //CELL ptClass, //CLAS ptRace, //RACE ptActorBase, //NPC_, CREA ptGlobal, //GLOB ptWeather, //WTHR ptPackage, //PACK ptOwnerOpt, //FACT, NPC_ ptBirthsign, //BSGN ptFurniture, //FURN ptMagicItem, //SPEL ptMagicEffect, //MGEF ptWorldspace, //WRLD ptReferencableObject ); PCTDAFunction = ^TCTDAFunction; TCTDAFunction = record Index: Integer; Name: string; ParamType1: TCTDAFunctionParamType; ParamType2: TCTDAFunctionParamType; end; const wbCTDAFunctions : array[0..191] of TCTDAFunction = ( (Index: 1; Name: 'GetDistance'; ParamType1: ptObjectReference), (Index: 5; Name: 'GetLocked'), (Index: 6; Name: 'GetPos'; ParamType1: ptAxis), (Index: 8; Name: 'GetAngle'; ParamType1: ptAxis), (Index: 10; Name: 'GetStartingPos'; ParamType1: ptAxis), (Index: 11; Name: 'GetStartingAngle'; ParamType1: ptAxis), (Index: 12; Name: 'GetSecondsPassed'), (Index: 14; Name: 'GetActorValue'; ParamType1: ptActorValue), (Index: 18; Name: 'GetCurrentTime'), (Index: 24; Name: 'GetScale'), (Index: 27; Name: 'GetLineOfSight'; ParamType1: ptObjectReference), (Index: 32; Name: 'GetInSameCell'; ParamType1: ptObjectReference), (Index: 35; Name: 'GetDisabled'), (Index: 36; Name: 'MenuMode'; ParamType1: ptInteger), (Index: 39; Name: 'GetDisease'), (Index: 40; Name: 'GetVampire'), (Index: 41; Name: 'GetClothingValue'), (Index: 42; Name: 'SameFaction'; ParamType1: ptActor), (Index: 43; Name: 'SameRace'; ParamType1: ptActor), (Index: 44; Name: 'SameSex'; ParamType1: ptActor), (Index: 45; Name: 'GetDetected'; ParamType1: ptActor), (Index: 46; Name: 'GetDead'), (Index: 47; Name: 'GetItemCount'; ParamType1: ptInventoryObject), (Index: 48; Name: 'GetGold'), (Index: 49; Name: 'GetSleeping'), (Index: 50; Name: 'GetTalkedToPC'), (Index: 53; Name: 'GetScriptVariable'; ParamType1: ptObjectReference; ParamType2: ptVariableName), (Index: 56; Name: 'GetQuestRunning'; ParamType1: ptQuest), (Index: 58; Name: 'GetStage'; ParamType1: ptQuest), (Index: 59; Name: 'GetStageDone'; ParamType1: ptQuest; ParamType2: ptQuestStage), (Index: 60; Name: 'GetFactionRankDifference'; ParamType1: ptFaction; ParamType2: ptActor), (Index: 61; Name: 'GetAlarmed'), (Index: 62; Name: 'IsRaining'), (Index: 63; Name: 'GetAttacked'), (Index: 64; Name: 'GetIsCreature'), (Index: 65; Name: 'GetLockLevel'), (Index: 66; Name: 'GetShouldAttack'; ParamType1: ptActor), (Index: 67; Name: 'GetInCell'; ParamType1: ptCell), (Index: 68; Name: 'GetIsClass'; ParamType1: ptClass), (Index: 69; Name: 'GetIsRace'; ParamType1: ptRace), (Index: 70; Name: 'GetIsSex'; ParamType1: ptSex), (Index: 71; Name: 'GetInFaction'; ParamType1: ptFaction), (Index: 72; Name: 'GetIsID'; ParamType1: ptReferencableObject), (Index: 73; Name: 'GetFactionRank'; ParamType1: ptFaction), (Index: 74; Name: 'GetGlobalValue'; ParamType1: ptGlobal), (Index: 75; Name: 'IsSnowing'), (Index: 76; Name: 'GetDisposition'; ParamType1: ptActor), (Index: 77; Name: 'GetRandomPercent'), (Index: 79; Name: 'GetQuestVariable'; ParamType1: ptQuest; ParamType2: ptVariableName), (Index: 80; Name: 'GetLevel'), (Index: 81; Name: 'GetArmorRating'), (Index: 84; Name: 'GetDeadCount'; ParamType1: ptActorBase), (Index: 91; Name: 'GetIsAlerted'), (Index: 98; Name: 'GetPlayerControlsDisabled'), (Index: 99; Name: 'GetHeadingAngle'; ParamType1: ptObjectReference), (Index: 101; Name: 'IsWeaponOut'), (Index: 102; Name: 'IsTorchOut'), (Index: 103; Name: 'IsShieldOut'), (Index: 104; Name: 'IsYielding'), (Index: 106; Name: 'IsFacingUp'), (Index: 107; Name: 'GetKnockedState'), (Index: 108; Name: 'GetWeaponAnimType'), (Index: 109; Name: 'GetWeaponSkillType'), (Index: 110; Name: 'GetCurrentAIPackage'), (Index: 111; Name: 'IsWaiting'), (Index: 112; Name: 'IsIdlePlaying'), (Index: 116; Name: 'GetCrimeGold'), (Index: 122; Name: 'GetCrime'; ParamType1: ptActor; ParamType2: ptCrimeType), (Index: 125; Name: 'IsGuard'), (Index: 127; Name: 'CanPayCrimeGold'), (Index: 128; Name: 'GetFatiguePercentage'), (Index: 129; Name: 'GetPCIsClass'; ParamType1: ptClass), (Index: 130; Name: 'GetPCIsRace'; ParamType1: ptRace), (Index: 131; Name: 'GetPCIsSex'; ParamType1: ptSex), (Index: 132; Name: 'GetPCInFaction'; ParamType1: ptFaction), (Index: 133; Name: 'SameFactionAsPC'), (Index: 134; Name: 'SameRaceAsPC'), (Index: 135; Name: 'SameSexAsPC'), (Index: 136; Name: 'GetIsReference'; ParamType1: ptObjectReference), (Index: 141; Name: 'IsTalking'), (Index: 142; Name: 'GetWalkSpeed'), (Index: 143; Name: 'GetCurrentAIProcedure'), (Index: 144; Name: 'GetTrespassWarningLevel'), (Index: 145; Name: 'IsTrespassing'), (Index: 146; Name: 'IsInMyOwnedCell'), (Index: 147; Name: 'GetWindSpeed'), (Index: 148; Name: 'GetCurrentWeatherPercent'), (Index: 149; Name: 'GetIsCurrentWeather'; ParamType1: ptWeather), (Index: 150; Name: 'IsContinuingPackagePCNear'), (Index: 153; Name: 'CanHaveFlames'), (Index: 154; Name: 'HasFlames'), (Index: 157; Name: 'GetOpenState'), (Index: 159; Name: 'GetSitting'), (Index: 160; Name: 'GetFurnitureMarkerID'), (Index: 161; Name: 'GetIsCurrentPackage'; ParamType1: ptPackage), (Index: 162; Name: 'IsCurrentFurnitureRef'; ParamType1: ptObjectReference), (Index: 163; Name: 'IsCurrentFurnitureObj'; ParamType1: ptFurniture), (Index: 170; Name: 'GetDayOfWeek'), (Index: 171; Name: 'IsPlayerInJail'), (Index: 172; Name: 'GetTalkedToPCParam'; ParamType1: ptActor), (Index: 175; Name: 'IsPCSleeping'), (Index: 176; Name: 'IsPCAMurderer'), (Index: 180; Name: 'GetDetectionLevel'; ParamType1: ptActor), (Index: 182; Name: 'GetEquipped'; ParamType1: ptInventoryObject), (Index: 185; Name: 'IsSwimming'), (Index: 190; Name: 'GetAmountSoldStolen'), (Index: 193; Name: 'GetPCExpelled'; ParamType1: ptFaction), (Index: 195; Name: 'GetPCFactionMurder'; ParamType1: ptFaction), (Index: 197; Name: 'GetPCFactionSteal'; ParamType1: ptFaction), (Index: 199; Name: 'GetPCFactionAttack'; ParamType1: ptFaction), (Index: 201; Name: 'GetPCFactionSubmitAuthority'; ParamType1: ptFaction), (Index: 203; Name: 'GetDestroyed'), (Index: 214; Name: 'HasMagicEffect'; ParamType1: ptMagicEffect), (Index: 215; Name: 'GetDoorDefaultOpen'), (Index: 223; Name: 'IsSpellTarget'; ParamType1: ptMagicItem), (Index: 224; Name: 'GetIsPlayerBirthsign'; ParamType1: ptBirthsign), (Index: 225; Name: 'GetPersuasionNumber'), (Index: 227; Name: 'HasVampireFed'), (Index: 228; Name: 'GetIsClassDefault'; ParamType1: ptClass), (Index: 229; Name: 'GetClassDefaultMatch'), (Index: 230; Name: 'GetInCellParam'; ParamType1: ptCell; ParamType2: ptObjectReference), (Index: 237; Name: 'GetIsGhost'), (Index: 242; Name: 'GetUnconscious'), (Index: 244; Name: 'GetRestrained'), (Index: 246; Name: 'GetIsUsedItem'; ParamType1: ptReferencableObject), (Index: 247; Name: 'GetIsUsedItemType'; ParamType1: ptFormType), (Index: 249; Name: 'GetPCFame'), (Index: 251; Name: 'GetPCInfamy'), (Index: 254; Name: 'GetIsPlayableRace'), (Index: 255; Name: 'GetOffersServicesNow'), (Index: 258; Name: 'GetUsedItemLevel'), (Index: 259; Name: 'GetUsedItemActivate'), (Index: 264; Name: 'GetBarterGold'), (Index: 265; Name: 'IsTimePassing'), (Index: 266; Name: 'IsPleasant'), (Index: 267; Name: 'IsCloudy'), (Index: 274; Name: 'GetArmorRatingUpperBody'), (Index: 277; Name: 'GetBaseActorValue'; ParamType1: ptActorValue), (Index: 278; Name: 'IsOwner'; ParamType1: ptOwnerOpt), (Index: 280; Name: 'IsCellOwner'; ParamType1: ptCell; ParamType2: ptOwnerOpt), (Index: 282; Name: 'IsHorseStolen'), (Index: 285; Name: 'IsLeftUp'), (Index: 286; Name: 'IsSneaking'), (Index: 287; Name: 'IsRunning'), (Index: 288; Name: 'GetFriendHit'; ParamType1: ptActor), (Index: 289; Name: 'IsInCombat'), (Index: 300; Name: 'IsInInterior'), (Index: 305; Name: 'GetInvestmentGold'), (Index: 306; Name: 'IsActorUsingATorch'), (Index: 309; Name: 'IsXBox'), (Index: 310; Name: 'GetInWorldspace'; ParamType1: ptWorldSpace), (Index: 312; Name: 'GetPCMiscStat'; ParamType1: ptInteger), (Index: 313; Name: 'IsActorEvil'), (Index: 314; Name: 'IsActorAVictim'), (Index: 315; Name: 'GetTotalPersuasionNumber'), (Index: 318; Name: 'GetIdleDoneOnce'), (Index: 320; Name: 'GetNoRumors'), (Index: 323; Name: 'WhichServiceMenu'), (Index: 327; Name: 'IsRidingHorse'), (Index: 329; Name: 'IsTurnArrest'), (Index: 332; Name: 'IsInDangerousWater'), (Index: 338; Name: 'GetIgnoreFriendlyHits'), (Index: 339; Name: 'IsPlayersLastRiddenHorse'), (Index: 353; Name: 'IsActor'), (Index: 354; Name: 'IsEssential'), (Index: 358; Name: 'IsPlayerMovingIntoNewSpace'), (Index: 361; Name: 'GetTimeDead'), (Index: 362; Name: 'GetPlayerHasLastRiddenHorse'), (Index: 365; Name: 'GetPlayerInSEWorld'), // Added by OBSE: (Index: 1107; Name: 'IsAmmo,'; ParamType1: ptInteger), (Index: 1884; Name: 'GetPCTrainingSessionsUsed'; ParamType1: ptPackage), (Index: 2213; Name: 'GetPackageOffersServices'; ParamType1: ptPackage), (Index: 2214; Name: 'GetPackageMustReachLocation'; ParamType1: ptPackage), (Index: 2215; Name: 'GetPackageMustComplete'; ParamType1: ptPackage), (Index: 2216; Name: 'GetPackageLockDoorsAtStart'; ParamType1: ptPackage), (Index: 2217; Name: 'GetPackageLockDoorsAtEnd'; ParamType1: ptPackage), (Index: 2218; Name: 'GetPackageLockDoorsAtLocation'; ParamType1: ptPackage), (Index: 2219; Name: 'GetPackageUnlockDoorsAtStart'; ParamType1: ptPackage), (Index: 2220; Name: 'GetPackageUnlockDoorsAtEnd'; ParamType1: ptPackage), (Index: 2221; Name: 'GetPackageUnlockDoorsAtLocation'; ParamType1: ptPackage), (Index: 2222; Name: 'GetPackageContinueIfPCNear'; ParamType1: ptPackage), (Index: 2223; Name: 'GetPackageOncePerDay'; ParamType1: ptPackage), (Index: 2224; Name: 'GetPackageSkipFalloutBehavior'; ParamType1: ptPackage), (Index: 2225; Name: 'GetPackageAlwaysRun'; ParamType1: ptPackage), (Index: 2226; Name: 'GetPackageAlwaysSneak'; ParamType1: ptPackage), (Index: 2227; Name: 'GetPackageAllowSwimming'; ParamType1: ptPackage), (Index: 2228; Name: 'GetPackageAllowFalls'; ParamType1: ptPackage), (Index: 2229; Name: 'GetPackageArmorUnequipped'; ParamType1: ptPackage), (Index: 2230; Name: 'GetPackageWeaponsUnequipped'; ParamType1: ptPackage), (Index: 2231; Name: 'GetPackageDefensiveCombat'; ParamType1: ptPackage), (Index: 2232; Name: 'GetPackageUseHorse'; ParamType1: ptPackage), (Index: 2233; Name: 'GetPackageNoIdleAnims'; ParamType1: ptPackage) ); var wbCTDAFunctionEditInfo : string; function wbCTDAParamDescFromIndex(aIndex: Integer): PCTDAFunction; var L, H, I, C: Integer; begin Result := nil; L := Low(wbCTDAFunctions); H := High(wbCTDAFunctions); while L <= H do begin I := (L + H) shr 1; C := CmpW32(wbCTDAFunctions[I].Index, aIndex); if C < 0 then L := I + 1 else begin H := I - 1; if C = 0 then begin L := I; Result := @wbCTDAFunctions[L]; end; end; end; end; function wbCTDACompValueDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container: IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; if Integer(Container.ElementByName['Type'].NativeValue) and $04 <> 0 then Result := 1; end; function wbEFITOBMEParamDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var ParamInfo: Variant; Container: IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; ParamInfo := Container.ElementNativeValues['..\EFME\EFIT Param Info']; if VarIsNull(ParamInfo) or VarIsEmpty(ParamInfo) then else Result := ParamInfo; end; function wbEFIXParamDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var ParamInfo: Variant; Container: IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; ParamInfo := Container.ElementNativeValues['..\EFME\EFIX Param Info']; if VarIsNull(ParamInfo) or VarIsEmpty(ParamInfo) then else Result := ParamInfo; end; function wbCTDAParam1Decider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Desc: PCTDAFunction; Container: IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; Desc := wbCTDAParamDescFromIndex(Container.ElementByName['Function'].NativeValue); if Assigned(Desc) then Result := Succ(Integer(Desc.ParamType1)); end; function wbCTDAParam2Decider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Desc: PCTDAFunction; Container: IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; Desc := wbCTDAParamDescFromIndex(Container.ElementByName['Function'].NativeValue); if Assigned(Desc) then Result := Succ(Integer(Desc.ParamType2)); end; { function wbCTDAFunction(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Desc: PCTDAFunction; begin Result := ''; case aType of ctToStr: begin Desc := wbCTDAParamDescFromIndex(aInt); if Assigned(Desc) then Result := Desc.Name else Result := ''; end; ctToSortKey: Result := IntToHex(aInt, 8); ctCheck: begin Desc := wbCTDAParamDescFromIndex(aInt); if Assigned(Desc) then Result := '' else Result := ''; end; end; end; } function wbCTDAFunctionToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Desc : PCTDAFunction; i : Integer; begin Result := ''; case aType of ctToStr, ctToEditValue: begin Desc := wbCTDAParamDescFromIndex(aInt); if Assigned(Desc) then Result := Desc.Name else if aType = ctToEditValue then Result := IntToStr(aInt) else Result := ''; end; ctToSortKey: Result := IntToHex(aInt, 8); ctCheck: begin Desc := wbCTDAParamDescFromIndex(aInt); if Assigned(Desc) then Result := '' else Result := ''; end; ctEditType: Result := 'ComboBox'; ctEditInfo: begin Result := wbCTDAFunctionEditInfo; if Result = '' then begin with TStringList.Create do try for i := Low(wbCTDAFunctions) to High(wbCTDAFunctions) do Add(wbCTDAFunctions[i].Name); Sort; Result := CommaText; finally Free; end; wbCTDAFunctionEditInfo := Result; end; end; end; end; function wbCTDAFunctionToInt(const aString: string; const aElement: IwbElement): Int64; var i: Integer; begin for i := Low(wbCTDAFunctions) to High(wbCTDAFunctions) do with wbCTDAFunctions[i] do if SameText(Name, aString) then begin Result := Index; Exit; end; Result := StrToInt64(aString); end; function wbCTDAParam2VariableNameToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainerElementRef; Param1 : IwbElement; MainRecord : IwbMainRecord; BaseRecord : IwbMainRecord; ScriptRef : IwbElement; Script : IwbMainRecord; Variables : TStringList; LocalVars : IwbContainerElementRef; LocalVar : IwbContainerElementRef; i, j : Integer; s : string; begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctToEditValue: Result := IntToStr(aInt); ctToSortKey: begin Result := IntToHex64(aInt, 8); Exit; end; ctCheck: Result := ''; ctEditType: Result := ''; ctEditInfo: Result := ''; end; if not Assigned(aElement) then Exit; Container := GetContainerRefFromUnionOrValue(aElement); if not Assigned(Container) then Exit; Param1 := Container.ElementByName['Parameter #1']; if not Assigned(Param1) then Exit; MainRecord := nil; if not Supports(Param1.LinksTo, IwbMainRecord, MainRecord) then Exit; { if Param1.NativeValue = 0 then if Supports(Container.Container, IwbContainerElementRef, Container) then for i := 0 to Pred(Container.ElementCount) do if Supports(Container.Elements[i], IwbContainerElementRef, Container2) then if SameText(Container2.ElementValues['Function'], 'GetIsID') then begin Param1 := Container2.ElementByName['Parameter #1']; if Supports(Param1.LinksTo, IwbMainRecord, MainRecord) then Break; end;} if not Assigned(MainRecord) then Exit; BaseRecord := MainRecord.BaseRecord; if Assigned(BaseRecord) then MainRecord := BaseRecord; ScriptRef := MainRecord.RecordBySignature['SCRI']; if not Assigned(ScriptRef) then begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end; Exit; end; if not Supports(ScriptRef.LinksTo, IwbMainRecord, Script) then begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end; Exit; end; case aType of ctEditType: begin Result := 'ComboBox'; Exit; end; ctEditInfo: Variables := TStringList.Create; else Variables := nil; end; try if Supports(Script.ElementByName['Local Variables'], IwbContainerElementRef, LocalVars) then begin for i := 0 to Pred(LocalVars.ElementCount) do if Supports(LocalVars.Elements[i], IwbContainerElementRef, LocalVar) then begin j := LocalVar.ElementNativeValues['SLSD\Index']; s := LocalVar.ElementNativeValues['SCVR']; if Assigned(Variables) then Variables.AddObject(s, TObject(j)) else if j = aInt then begin case aType of ctToStr, ctToEditValue: Result := s; ctCheck: Result := ''; end; Exit; end; end; end; case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; ctEditInfo: begin Variables.Sort; Result := Variables.CommaText; end; end; finally FreeAndNil(Variables); end; end; function wbCTDAParam2VariableNameToInt(const aString: string; const aElement: IwbElement): Int64; var Container : IwbContainerElementRef; Param1 : IwbElement; MainRecord : IwbMainRecord; BaseRecord : IwbMainRecord; ScriptRef : IwbElement; Script : IwbMainRecord; LocalVars : IwbContainerElementRef; LocalVar : IwbContainerElementRef; i, j : Integer; s : string; begin Result := StrToInt64Def(aString, Low(Cardinal)); if Result <> Low(Cardinal) then Exit; if not Assigned(aElement) then raise Exception.Create('aElement not specified'); Container := GetContainerRefFromUnionOrValue(aElement); if not Assigned(Container) then raise Exception.Create('Container not assigned'); Param1 := Container.ElementByName['Parameter #1']; if not Assigned(Param1) then raise Exception.Create('Could not find "Parameter #1"'); if not Supports(Param1.LinksTo, IwbMainRecord, MainRecord) then raise Exception.Create('"Parameter #1" does not reference a valid main record'); BaseRecord := MainRecord.BaseRecord; if Assigned(BaseRecord) then MainRecord := BaseRecord; ScriptRef := MainRecord.RecordBySignature['SCRI']; if not Assigned(ScriptRef) then raise Exception.Create('"'+MainRecord.ShortName+'" does not contain a SCRI subrecord'); if not Supports(ScriptRef.LinksTo, IwbMainRecord, Script) then raise Exception.Create('"'+MainRecord.ShortName+'" does not have a valid script'); if Supports(Script.ElementByName['Local Variables'], IwbContainerElementRef, LocalVars) then begin for i := 0 to Pred(LocalVars.ElementCount) do if Supports(LocalVars.Elements[i], IwbContainerElementRef, LocalVar) then begin j := LocalVar.ElementNativeValues['SLSD\Index']; s := LocalVar.ElementNativeValues['SCVR']; if SameText(s, Trim(aString)) then begin Result := j; Exit; end; end; end; raise Exception.Create('Variable "'+aString+'" was not found in "'+MainRecord.ShortName+'"'); end; function wbCTDAParam2QuestStageToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainerElementRef; Param1 : IwbElement; MainRecord : IwbMainRecord; EditInfos : TStringList; Stages : IwbContainerElementRef; Stage : IwbContainerElementRef; i, j : Integer; s, t : string; begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctToEditValue: Result := IntToStr(aInt); ctToSortKey: begin Result := IntToHex64(aInt, 8); Exit; end; ctCheck: Result := ''; ctEditType: Result := ''; ctEditInfo: Result := ''; end; if not Assigned(aElement) then Exit; Container := GetContainerRefFromUnionOrValue(aElement); if not Assigned(Container) then Exit; Param1 := Container.ElementByName['Parameter #1']; if not Assigned(Param1) then Exit; if not Supports(Param1.LinksTo, IwbMainRecord, MainRecord) then Exit; MainRecord := MainRecord.WinningOverride; if MainRecord.Signature <> QUST then begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end; Exit; end; case aType of ctEditType: begin Result := 'ComboBox'; Exit; end; ctEditInfo: EditInfos := TStringList.Create; else EditInfos := nil; end; try if Supports(MainRecord.ElementByName['Stages'], IwbContainerElementRef, Stages) then begin for i := 0 to Pred(Stages.ElementCount) do if Supports(Stages.Elements[i], IwbContainerElementRef, Stage) then begin j := Stage.ElementNativeValues['INDX']; s := Trim(Stage.ElementValues['Log Entries\Log Entry\CNAM']); t := IntToStr(j); while Length(t) < 3 do t := '0' + t; if s <> '' then t := t + ' ' + s; if Assigned(EditInfos) then EditInfos.AddObject(t, TObject(j)) else if j = aInt then begin case aType of ctToStr, ctToEditValue: Result := t; ctCheck: Result := ''; end; Exit; end; end; end; case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; ctEditInfo: begin EditInfos.Sort; Result := EditInfos.CommaText; end; end; finally FreeAndNil(EditInfos); end; end; function wbCTDAParam2QuestStageToInt(const aString: string; const aElement: IwbElement): Int64; var i : Integer; s : string; begin i := 1; s := Trim(aString); while (i <= Length(s)) and (s[i] in ['0'..'9']) do Inc(i); s := Copy(s, 1, Pred(i)); Result := StrToInt(s); end; procedure wbRemoveOFST(const aElement: IwbElement); var Container: IwbContainer; rOFST: IwbRecord; begin if not wbRemoveOffsetData then Exit; if Supports(aElement, IwbContainer, Container) then begin rOFST := Container.RecordBySignature[OFST]; if Assigned(rOFST) then Container.RemoveElement(rOFST); end; end; procedure wbCELLAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; // Container2 : IwbContainerElementRef; MainRecord : IwbMainRecord; // i : Integer; IsInterior : Boolean; GroupRecord : IwbGroupRecord; // Removed : Boolean; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; if not Container.ElementExists['DATA'] then Exit; IsInterior := (Container.ElementNativeValues['DATA'] and 1) <> 0; if IsInterior then Container.Add('XCLL') else begin Container.Add('XCLC'); if (Container.ElementNativeValues['DATA'] and 2) = 0 then if Supports(MainRecord.Container, IwbGroupRecord, GroupRecord) then if GroupRecord.GroupType = 1 then Container.ElementNativeValues['DATA'] := Container.ElementNativeValues['DATA'] or 2; end; // Removed := False; // if Supports(Container.ElementBySignature[XCLR], IwbContainerElementRef, Container2) then begin // for i:= Pred(Container2.ElementCount) downto 0 do // if not Supports(Container2.Elements[i].LinksTo, IwbMainRecord, MainRecord) or (MainRecord.Signature <> 'REGN') then begin // if not Removed then begin // Removed := True; // Container2.MarkModifiedRecursive; // end; // Container2.RemoveElement(i); // end; // if Container2.ElementCount < 1 then // Container2.Remove; // end; finally wbEndInternalEdit; end; end; procedure wbMGEFAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; MainRecord : IwbMainRecord; _File : IwbFile; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; _File := MainRecord._File; if not Assigned(_File) then Exit; if not SameText(_File.FileName, 'Oblivion.esm') then Exit; if SameText(MainRecord.EditorID, 'RSFI') or SameText(MainRecord.EditorID, 'RSFR') or SameText(MainRecord.EditorID, 'RSPA') or SameText(MainRecord.EditorID, 'RSSH') then begin Container.ElementNativeValues['DATA - Data\Flags'] := Cardinal(Container.ElementNativeValues['DATA - Data\Flags']) or $8; end; if SameText(MainRecord.EditorID, 'REAN') then begin Container.ElementNativeValues['DATA - Data\Flags'] := Cardinal(Container.ElementNativeValues['DATA - Data\Flags']) and not $20000; end; finally wbEndInternalEdit; end; end; procedure wbCounterEffectsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterByPathAfterSet('DATA - Data\Counter effect count', aElement); end; procedure wbMGEFAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterContainerByPathAfterSet('DATA - Data\Counter effect count', 'ESCE - Counter Effects', aElement); end; procedure wbEFITAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; Element : IwbElement; ActorValue: Variant; MainRecord: IwbMainRecord; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; Element := Container.ElementByName['Magic effect name']; if not Assigned(Element) then Exit; if not Supports(Element.LinksTo, IwbMainRecord, MainRecord) then Exit; if MainRecord.Signature <> 'MGEF' then Exit; if (MainRecord.ElementNativeValues['DATA - Data\Flags'] and $01000000) = 0 then Exit; ActorValue := MainRecord.ElementNativeValues['DATA - Data\Assoc. Item']; if VarIsNull(ActorValue) or VarIsClear(ActorValue) then Exit; if VarCompareValue(ActorValue, Container.ElementNativeValues['Actor Value']) <> vrEqual then Container.ElementNativeValues['Actor Value'] := ActorValue; finally wbEndInternalEdit; end; end; procedure wbREFRAfterLoad(const aElement: IwbElement); var Container: IwbContainerElementRef; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; Container.RemoveElement('XPCI'); finally wbEndInternalEdit; end; end; procedure wbLIGHAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; MainRecord : IwbMainRecord; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; if Container.ElementExists['DATA'] then begin if SameValue(Container.ElementNativeValues['DATA\Falloff Exponent'], 0.0) then Container.ElementNativeValues['DATA\Falloff Exponent'] := 1.0; if SameValue(Container.ElementNativeValues['DATA\FOV'], 0.0) then Container.ElementNativeValues['DATA\FOV'] := 90.0; end; finally wbEndInternalEdit; end; end; procedure wbLVLAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; MainRecord : IwbMainRecord; Chance : Integer; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; Container.RemoveElement('DATA'); Chance := Container.ElementNativeValues['LVLD']; if (Chance and $80) <> 0 then begin Chance := Chance and not $80; Container.ElementNativeValues['LVLD'] := Chance; Container.ElementNativeValues['LVLF'] := Container.ElementNativeValues['LVLF'] or $01; end; finally wbEndInternalEdit; end; end; procedure wbRPLDAfterLoad(const aElement: IwbElement); var Container : IwbContainer; a, b : Single; NeedsFlip : Boolean; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainer, Container) then Exit; NeedsFlip := False; if Container.ElementCount > 1 then begin a := (Container.Elements[0] as IwbContainer).Elements[0].NativeValue; b := (Container.Elements[Pred(Container.ElementCount)] as IwbContainer).Elements[0].NativeValue; case CompareValue(a, b) of EqualsValue: begin a := (Container.Elements[0] as IwbContainer).Elements[1].NativeValue; b := (Container.Elements[Pred(Container.ElementCount)] as IwbContainer).Elements[1].NativeValue; NeedsFlip := CompareValue(a, b) = GreaterThanValue; end; GreaterThanValue: NeedsFlip := True; end; end; if NeedsFlip then Container.ReverseElements; finally wbEndInternalEdit; end; end; procedure wbPGRDAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; MainRecord : IwbMainRecord; Points : IwbContainerElementRef; Connections : IwbContainerElementRef; i, j : Integer; Point : IwbContainerElementRef; Connection : IwbContainerElementRef; Removed : Boolean; FirstRemoved: Boolean; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; if not Supports(Container.ElementBySignature['PGRP'], IwbContainerElementRef, Points) then Exit; if not Container.ElementExists['PGAG'] then Container.Add('PGAG').DataSize := (Points.ElementCount + 7) div 8; MainRecord.IsCompressed := True; if not Supports(Container.ElementBySignature['PGRR'], IwbContainerElementRef, Connections) then Exit; if Points.ElementCount < Connections.ElementCount then Exit; FirstRemoved := False; for i := Pred(Connections.ElementCount) downto 0 do begin Connection := Connections.Elements[i] as IwbContainerElementRef; Removed := False; j := Connection.ElementCount; while j > 0 do begin Dec(j); if Connection.Elements[j].NativeValue = 65535 then begin if not FirstRemoved then begin FirstRemoved := True; Connections.MarkModifiedRecursive; end; Connection.Elements[j].Remove; Removed := True; end else Break; end; if Removed then begin Point := Points.Elements[i] as IwbContainerElementRef; Point.ElementNativeValues['Connections'] := Connection.ElementCount; end; end; finally wbEndInternalEdit; end; end; procedure wbPGRRPointAfterLoad(const aElement: IwbElement); var Connections : IwbContainerElementRef; i : Integer; // Index : Integer; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Connections) then Exit; for i := Pred(Connections.ElementCount) downto 0 do if Connections.Elements[i].NativeValue = 65535 then begin Connections.RemoveElement(i); end; { if Removed then begin Index := aElement.Container.ElementCount; (aElement.ContainingMainRecord.RecordBySignature['PGRP'].Elements[Index] as IwbContainer).Elements[3].NativeValue := Connections.ElementCount; end;} finally wbEndInternalEdit; end; end; procedure wbPGRIPointerAfterLoad(const aElement: IwbElement); var Connections : IwbContainerElementRef; i, j : Integer; s : string; Keys : TStringList; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Connections) then Exit; Keys := TStringList.Create; try Keys.Sorted := True; Keys.Duplicates := dupError; for i := Pred(Connections.ElementCount) downto 0 do begin s := Connections.Elements[i].SortKey[True]; if Keys.Find(s, j) then Connections.RemoveElement(i, True) else Keys.Add(s); end; finally Keys.Free; end; finally wbEndInternalEdit; end; end; { function wbPGRPConnectionsCallback(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Point : IwbContainerElementRef; s : string; i : Integer; PGRP : IwbContainerElementRef; PGRD : IwbMainRecord; PGRR : IwbContainerElementRef; Cons : IwbContainerElementRef; begin Result := ''; if aType = ctCheck then Exit; if wbFixupPGRD and (aInt > 0) and Assigned(aElement) and (aElement.ElementStates * [esModified] = []) then begin Point := aElement.Container as IwbContainerElementRef; if Assigned(Point) then begin s := Trim(Point.Name); i := Pos('#', s); if i > 0 then begin i := StrToIntDef(Copy(s, i+1, High(Integer)), -1); if i >= 0 then begin PGRP := Point.Container as IwbContainerElementRef; if Assigned(PGRP) then begin if Supports(PGRP.Container, IwbMainRecord, PGRD) then begin if (csInitDone in PGRD.ContainerStates) and (PGRD.Signature = 'PGRD') then begin PGRR := PGRD.RecordBySignature['PGRR'] as IwbContainerElementRef; if Assigned(PGRR) and (PGRR.ElementCount > 0) and (csInitDone in PGRR.ContainerStates) then begin if (i < PGRR.ElementCount) then begin if Supports(PGRR.Elements[i], IwbContainer, Cons) then begin aInt := Cons.ElementCount; end; end; end; PGRR := nil; end; end; end; end; end; end; end; if aType = ctToSortKey then Result := IntToHex64(aInt, 2) else if aType = ctToStr then Result := IntToStr(aInt); end; } function wbPxDTLocationDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container: IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; Result := Container.ElementByName['Type'].NativeValue; end; function wbCalcPGRRSize(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Cardinal; var Index: Integer; function ExtractCountFromLabel(const aElement: IwbElement; aCount: Integer): Integer; var i: Integer; begin i := Pos('#', aElement.Name); if i = 0 then Result := aCount else try Result := StrToInt(Trim(Copy(aElement.Name, i+1, Length(aElement.Name))))+1; except Result := aCount; end; end; begin Index := ExtractCountFromLabel(aElement, aElement.Container.ElementCount); Result := ((aElement.Container.Container as IwbMainRecord).RecordBySignature['PGRP'].Elements[Pred(Index)] as IwbContainer).Elements[3].NativeValue; end; function wbMGEFFAssocItemDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var s: string; Container: IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; s := Container.ElementByName['Flags'].SortKey[False]; if s[17] = '1' then Result := 1 else if s[18] = '1' then Result := 2 else if s[19] = '1' then Result := 3 else if s[25] = '1' then Result := 4; end; function wbEDDXDontShow(const aElement: IwbElement): Boolean; var MainRecord : IwbMainRecord; begin Result := True; if Supports(aElement.Container, IwbMainRecord, MainRecord) then Result := not Assigned(MainRecord.ElementBySignature[OBME]); end; function wbOBMEDontShow(const aElement: IwbElement): Boolean; var _File: IwbFile; begin if not Assigned(aElement) then begin Result := True; Exit; end; Result := False; _File := aElement._File; if Assigned(_File) and SameText(_File.FileName, 'Oblivion.esm') then Result := True; end; function wbOffsetDataColsCounter(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Cardinal; var Container : IwbDataContainer; Element : IwbElement; fResult : Extended; begin Result := 0; if Supports(aElement.Container, IwbDataContainer, Container) and (Container.Name = 'OFST - Offset Data') and Supports(Container.Container, IwbDataContainer, Container) then begin Element := Container.ElementByPath['Object Bounds\NAM0 - Min\X']; if Assigned(Element) then begin fResult := Element.NativeValue; if fResult >= MaxInt then Result := 0 else Result := Trunc(fResult); Element := Container.ElementByPath['Object Bounds\NAM9 - Max\X']; if Assigned(Element) then begin fResult := Element.NativeValue; if fResult >= MaxInt then Result := 1 else Result := Trunc(fResult) - Result + 1; end; end; end; end; procedure DefineTES4; begin wbRecordFlags := wbInteger('Record Flags', itU32, wbFlags([ {0x00000001}'ESM', {0x00000002}'', {0x00000004}'', {0x00000008}'', {0x00000010}'', {0x00000020}'Deleted', {0x00000040}'Border Region / Actor Value', {0x00000080}'Turn Off Fire / Actor Value', {0x00000100}'', {0x00000200}'Casts shadows', {0x00000400}'Quest item / Persistent reference / Show in Menu', {0x00000800}'Initially disabled', {0x00001000}'Ignored', {0x00002000}'', {0x00004000}'', {0x00008000}'Visible when distant', {0x00010000}'', {0x00020000}'Dangerous / Off limits (Interior cell)', {0x00040000}'Compressed ', {0x00080000}'Can''t wait' ])); wbMainRecordHeader := wbStruct('Record Header', [ wbString('Signature', 4, cpCritical), wbInteger('Data Size', itU32, nil, cpIgnore), wbRecordFlags, wbFormID('FormID', cpFormID), wbByteArray('Unknown', 4, cpIgnore) ]); wbSizeOfMainRecordStruct := 20; wbIgnoreRecords.Add(XXXX); wbXRGD := wbByteArray(XRGD, 'Ragdoll Data'); wbMusicEnum := wbEnum(['Default', 'Public', 'Dungeon']); wbEDID := wbString(EDID, 'Editor ID', 0, cpNormal); // not cpBenign according to Arthmoor wbFULL := wbStringKC(FULL, 'Name', 0, cpTranslate); wbFULLReq := wbStringKC(FULL, 'Name', 0, cpNormal, True); wbDESC := wbStringKC(DESC, 'Description', 0, cpTranslate); wbXSCL := wbFloat(XSCL, 'Scale'); wbPosRot := wbStruct('Position/Rotation', [ wbStruct('Position', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), wbStruct('Rotation', [ wbFloat('X', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Y', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Z', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize) ]) ]); wbDATAPosRot := wbStruct(DATA, 'Position/Rotation', [ wbStruct('Position', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), wbStruct('Rotation', [ wbFloat('X', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Y', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Z', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize) ]) ], cpNormal, True); wbMODL := wbRStructSK([0], 'Model', [ wbString(MODL, 'Model Filename'), wbFloat(MODB, 'Bound Radius', cpBenign), wbByteArray(MODT, 'Texture Files Hashes', 0, cpIgnore) // wbArray(MODT, 'Unknown', // wbByteArray('Unknown', 24, cpBenign), // 0, nil, cpBenign) ], []); wbSCRI := wbFormIDCk(SCRI, 'Script', [SCPT]); wbENAM := wbFormIDCk(ENAM, 'Enchantment', [ENCH]); wbXLOD := wbArray(XLOD, 'Distant LOD Data', wbFloat('Unknown'), 3); wbXESP := wbStruct(XESP, 'Enable Parent', [ wbFormIDCk('Reference', [PLYR, REFR, ACRE, ACHR]), wbInteger('Flags', itU8, wbFlags([ 'Set Enable State to Opposite of Parent' ])), wbByteArray('Unused', 3) ]); wbRecord(ACHR, 'Placed NPC', [ wbEDID, wbFormIDCk(NAME, 'Base', [NPC_], False, cpNormal, True), wbRStruct('Unused', [ wbFormIDCk(XPCI, 'Unused', [CELL]), wbString(FULL, 'Unused') ], []), wbXLOD, wbXESP, wbFormIDCk(XMRC, 'Merchant container', [REFR], True), wbFormIDCk(XHRS, 'Horse', [ACRE], True), wbXRGD, wbXSCL, wbDATAPosRot ], True, wbPlacedAddInfo, cpNormal, False, wbREFRAfterLoad); wbXOWN := wbFormIDCk(XOWN, 'Owner', [FACT, NPC_]); wbXGLB := wbFormIDCk(XGLB, 'Global variable', [GLOB]); wbRecord(ACRE, 'Placed Creature', [ wbEDID, wbFormIDCk(NAME, 'Base', [CREA], False, cpNormal, True), wbRStruct('Ownership', [ wbXOWN, wbInteger(XRNK, 'Faction rank', itS32), wbXGLB ], []), wbXESP, wbXRGD, wbXSCL, wbDATAPosRot ], True, wbPlacedAddInfo); wbRecord(ACTI, 'Activator', [ wbEDID, wbFULL, wbMODL, wbSCRI, wbFormIDCk(SNAM, 'Sound', [SOUN]) ]); wbICON := wbString(ICON, 'Icon filename'); wbActorValueEnum := wbEnum([ 'Strength', 'Intelligence', 'Willpower', 'Agility', 'Speed', 'Endurance', 'Personality', 'Luck', 'Health', 'Magicka', 'Fatigue', 'Encumbrance', 'Armorer', 'Athletics', 'Blade', 'Block', 'Blunt', 'Hand To Hand', 'Heavy Armor', 'Alchemy', 'Alteration', 'Conjuration', 'Destruction', 'Illusion', 'Mysticism', 'Restoration', 'Acrobatics', 'Light Armor', 'Marksman', 'Mercantile', 'Security', 'Sneak', 'Speechcraft', {33} 'Aggression', {34} 'Confidence', {35} 'Energy', {36} 'Responsibility', {37} 'Bounty', {38} 'Fame', {39} 'Infamy', {40} 'Magicka Multiplier', {41} 'Night Eye Bonus', {42} 'Attack Bonus', {43} 'Defend Bonus', {44} 'Casting Penalty', {45} 'Blindness', {46} 'Chameleon', {47} 'Invisibility', {48} 'Paralysis', {49} 'Silence', {50} 'Confusion', {51} 'Detect Item Range', {52} 'Spell Absorb Chance', {53} 'Spell Reflect Chance', {54} 'Swim Speed Multiplier', {55} 'Water Breathing', {56} 'Water Walking', {57} 'Stunted Magicka', {58} 'Detect Life Range', {59} 'Reflect Damage', {60} 'Telekinesis', {61} 'Resist Fire', {62} 'Resist Frost', {63} 'Resist Disease', {64} 'Resist Magic', {65} 'Resist Normal Weapons', {66} 'Resist Paralysis', {67} 'Resist Poison', {68} 'Resist Shock', {69} 'Vampirism', {70} 'Darkness', {71} 'Resist Water Damage' ], [ -1, 'None' ]); wbSkillEnum := wbEnum([ 'Armorer', 'Athletics', 'Blade', 'Block', 'Blunt', 'Hand To Hand', 'Heavy Armor', 'Alchemy', 'Alteration', 'Conjuration', 'Destruction', 'Illusion', 'Mysticism', 'Restoration', 'Acrobatics', 'Light Armor', 'Marksman', 'Mercantile', 'Security', 'Sneak', 'Speechcraft' ], [ -1, 'None' ]); wbEFID := wbInteger(EFID, 'Magic effect name', itU32, wbChar4, cpNormal, True); wbEFIDOBME := wbStringMgefCode(EFID, 'Magic Effect Code', 4, cpNormal, True); wbEFIT := wbStructSK(EFIT, [4, 5], '', [ wbInteger('Magic effect name', itU32, wbChar4), wbInteger('Magnitude', itU32), wbInteger('Area', itU32), wbInteger('Duration', itU32), wbInteger('Type', itU32, wbEnum(['Self', 'Touch', 'Target'])), wbInteger('Actor Value', itS32, wbActorValueEnum) ], cpNormal, True, nil, -1, wbEFITAfterLoad); wbEFITOBME := wbStructSK(EFIT, [4, 5], '', [ wbStringMgefCode('Magic Effect Code', 4), wbInteger('Magnitude', itU32), wbInteger('Area', itU32), wbInteger('Duration', itU32), wbInteger('Type', itU32, wbEnum(['Self', 'Touch', 'Target'])), wbUnion('Param #1', wbEFITOBMEParamDecider, [ wbByteArray('Param #1 - Unknown Type', 4), wbFormID('Param #1 - FormID'), wbStringMgefCode('Param #1 - Magic Effect Code', 4), wbFormIDCk('Param #1 - Actor Value', [ACVA]) ]) ], cpNormal, True, nil, -1{, wbEFITAfterLoad}); wbEFIX := wbStructSK(EFIX, [3], '', [ wbInteger('Override Mask', itU32, wbFlags([])), wbInteger('Flags', itU32, wbFlags([])), wbFloat('Base Cost'), wbUnion('Param #2', wbEFIXParamDecider, [ wbByteArray('Param #2 - Unknown Type', 4), wbFormID('Param #2 - FormID'), wbStringMgefCode('Param #2 - Magic Effect Code', 4), wbFormIDCk('Param #2 - Actor Value', [ACVA]) ]) ], cpNormal, True, nil, -1, wbEFITAfterLoad); wbMagicSchoolEnum := wbEnum([ 'Alteration', 'Conjuration', 'Destruction', 'Illusion', 'Mysticism', 'Restoration' ]); wbSCIT := wbRStructSK([0], 'Script effect', [ wbStructSK(SCIT, [0], 'Script effect data', [ wbFormIDCk('Script effect', [NULL, SCPT]), wbInteger('Magic school', itU32, wbMagicSchoolEnum), wbInteger('Visual effect name', itU32, wbChar4), wbInteger('Flags', itU8, wbFlags(['Hostile'])), wbByteArray('Unused', 3) ], cpNormal, True, nil, 1), wbFULLReq ], []); wbSCITOBME := wbRStructSK([0], 'Script effect', [ wbStructSK(SCIT, [0], 'Script effect data', [ wbFormIDCk('Script effect', [NULL, SCPT]), wbInteger('Magic school', itU32, wbMagicSchoolEnum), wbStringMgefCode('Visual Effect Code', 4), wbInteger('Flags', itU8, wbFlags(['Hostile'])), wbByteArray('Unused', 3) ], cpNormal, True, nil, 1), wbFULLReq ], []); wbOBMEResolutionInfo := wbEnum(['None', 'FormID', 'Magic Effect Code', 'Actor Value']); wbEffects := wbRArray('Effects', wbRUnion('Effects', [ wbRStruct('Effect', [ wbEFID, wbEFIT, wbSCIT ], []), wbRStruct('Effects', [ wbRStructs('Effects','Effect', [ wbStruct(EFME, 'Oblivion Magic Extender', [ wbInteger('Record Version', itU8), wbStruct('OBME Version', [ wbInteger('Beta', itU8), wbInteger('Minor', itU8), wbInteger('Major', itU8) ]), wbInteger('EFIT Param Info', itU8, wbOBMEResolutionInfo), wbInteger('EFIX Param Info', itU8, wbOBMEResolutionInfo), wbByteArray('Unused', $0A) ]), wbEFIDOBME, wbEFITOBME, wbSCITOBME, wbString(EFII, 'Icon'), wbEFIX ], []), wbEmpty(EFXX, 'Effects End Marker', cpNormal, True), wbFULLReq ], []) ], []) ); // wbEffects := // wbRUnion('Effects', [ // wbRStruct('Effects', [ // wbRStructs('Effects','Effect', [ // wbEFID, // wbEFIT, // wbSCIT // ], []) // ], []), // wbRStruct('Effects', [ // wbRStructs('Effects','Effect', [ // wbStruct(EFME, 'Oblivion Magic Extender', [ // wbInteger('Record Version', itU8), // wbStruct('OBME Version', [ // wbInteger('Beta', itU8), // wbInteger('Minor', itU8), // wbInteger('Major', itU8) // ]), // wbInteger('EFIT Param Info', itU8, wbOBMEResolutionInfo), // wbInteger('EFIX Param Info', itU8, wbOBMEResolutionInfo), // wbByteArray('Unused', $0A) // ]), // wbEFIDOBME, // wbEFITOBME, // wbSCITOBME, // wbString(EFII, 'Icon'), // wbEFIX // ], []), // wbEmpty(EFXX, 'Effects End Marker', cpNormal, True), // wbFULLReq // ], []) // ], []); wbRecord(ALCH, 'Potion', [ wbEDID, wbStruct(OBME, 'Oblivion Magic Extender', [ wbInteger('Record Version', itU8), wbStruct('OBME Version', [ wbInteger('Beta', itU8), wbInteger('Minor', itU8), wbInteger('Major', itU8) ]), wbByteArray('Unused', $1C) ], cpNormal, False, wbOBMEDontShow), wbFULL, wbMODL, wbICON, wbSCRI, wbFloat(DATA, 'Weight', cpNormal, True), wbStruct(ENIT, '', [ wbInteger('Value', itS32), wbInteger('Flags', itU8, wbFlags(['No auto-calculation', 'Food item'])), wbByteArray('Unused', 3) ], cpNormal, True), wbEffects ]); wbRecord(AMMO, 'Ammunition', [ wbEDID, wbFULL, wbMODL, wbICON, wbFormIDCk(ENAM, 'Enchantment', [ENCH]), wbInteger(ANAM, 'Enchantment Points', itU16), wbStruct(DATA, '', [ wbFloat('Speed'), wbInteger('Flags', itU8, wbFlags(['Ignores Normal Weapon Resistance'])), wbByteArray('Unused', 3), wbInteger('Value', itU32), wbFloat('Weight'), wbInteger('Damage', itU16) ], cpNormal, True) ]); wbRecord(ANIO, 'Animated Object', [ wbEDID, wbMODL, wbFormIDCk(DATA, 'IDLE animation', [IDLE], False, cpNormal, True) ]); wbRecord(APPA, 'Alchemical Apparatus', [ wbEDID, wbFULL, wbMODL, wbICON, wbSCRI, wbStruct(DATA, '', [ wbInteger('Type', itU8, wbEnum(['Mortar and Pestle', 'Alembic', 'Calcinator', 'Retort'])), wbInteger('Value', itU32), wbFloat('Weight'), wbFloat('Quality') ], cpNormal, True) ]); wbRecord(ARMO, 'Armor', [ wbEDID, wbFULL, wbSCRI, wbENAM, wbInteger(ANAM, 'Enchantment Points', itU16), wbStruct(BMDT, '', [ wbInteger('Biped Flags', itU16, wbFlags([ {0x00000001} 'Head', {0x00000002} 'Hair', {0x00000004} 'Upper Body', {0x00000008} 'Lower Body', {0x00000010} 'Hand', {0x00000020} 'Foot', {0x00000040} 'Right Ring', {0x00000080} 'Left Ring', {0x00000100} 'Amulet', {0x00000200} 'Weapon', {0x00000400} 'Back Weapon', {0x00000800} 'Side Weapon', {0x00001000} 'Quiver', {0x00002000} 'Shield', {0x00004000} 'Torch', {0x00008000} 'Tail' ])), wbInteger('General Flags', itU8, wbFlags([ {0x0001} 'Hide Rings', {0x0002} 'Hide Amulets', {0x0004} '', {0x0008} '', {0x0010} '', {0x0020} '', {0x0040} 'Non-Playable', {0x0080} 'Heavy armor' ])), wbByteArray('Unused', 1) ], cpNormal, True), wbRStruct('Male biped model', [ wbString(MODL, 'Model Filename'), wbFloat(MODB, 'Bound Radius', cpBenign), wbByteArray(MODT, 'Texture Files Hashes', 0, cpIgnore) ], []), wbRStruct('Male world model', [ wbString(MOD2, 'Model Filename'), wbFloat(MO2B, 'Bound Radius', cpBenign), wbByteArray(MO2T, 'Texture Files Hashes', 0, cpIgnore) ], []), wbString(ICON, 'Male icon filename'), wbRStruct('Female biped model', [ wbString(MOD3, 'Model Filename'), wbFloat(MO3B, 'Bound Radius', cpBenign), wbByteArray(MO3T, 'Texture Files Hashes', 0, cpIgnore) ], []), wbRStruct('Female world model', [ wbString(MOD4, 'Model Filename'), wbFloat(MO4B, 'Bound Radius', cpBenign), wbByteArray(MO4T, 'Texture Files Hashes', 0, cpIgnore) ], []), wbString(ICO2, 'Female icon filename'), wbStruct(DATA, '', [ wbInteger('Armor', itU16, wbDiv(100)), wbInteger('Value', itU32), wbInteger('Health', itU32), wbFloat('Weight') ], cpNormal, True) ]); wbRecord(BOOK, 'Book', [ wbEDID, wbFULL, wbMODL, wbICON, wbSCRI, wbENAM, wbInteger(ANAM, 'Enchantment Points', itU16), wbDESC, wbStruct(DATA, '', [ wbInteger('Flags', itU8, wbFlags(['Scroll', 'Can''t be taken'])), wbInteger('Teaches', itS8, wbSkillEnum), wbInteger('Value', itU32), wbFloat('Weight') ], cpNormal, True) ], True); wbSPLO := wbFormIDCk(SPLO, 'Spell', [SPEL, LVSP]); wbSPLOs := wbRArrayS('Spells', wbSPLO); wbRecord(BSGN, 'Birthsign', [ wbEDID, wbFULL, wbICON, wbDESC, wbSPLOs ]); wbRecord(CELL, 'Cell', [ wbEDID, wbFULL, wbInteger(DATA, 'Flags', itU8, wbFlags([ {0x01} 'Is Interior Cell', {0x02} 'Has water', {0x04} 'Invert Fast Travel behavior', {0x08} 'Force hide land (exterior cell) / Oblivion interior (interior cell)', {0x10} '', {0x20} 'Public place', {0x40} 'Hand changed', {0x80} 'Behave like exterior' ]), cpNormal, True), wbStruct(XCLC, 'Grid', [ wbInteger('X', itS32), wbInteger('Y', itS32) ]), wbStruct(XCLL, 'Lighting', [ wbStruct('Ambient Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Directional Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Fog Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbFloat('Fog Near'), wbFloat('Fog Far'), wbInteger('Directional Rotation XY', itS32), wbInteger('Directional Rotation Z', itS32), wbFloat('Directional Fade', cpNormal, False, 1, -1, nil, nil, 1.0), wbFloat('Fog Clip Dist') ]), wbArrayS(XCLR, 'Regions', wbFormIDCk('Region', [REGN])), wbInteger(XCMT, 'Music', itU8, wbMusicEnum), wbFloat(XCLW, 'Water Height', cpBenign), wbFormIDCk(XCCM, 'Climate', [CLMT]), wbFormIDCk(XCWT, 'Water', [WATR]), wbRStruct('Ownership', [ wbXOWN, wbInteger(XRNK, 'Faction rank', itS32), wbXGLB ], [XCLW, XCMT, XCCM]) ], True, wbCellAddInfo, cpNormal, False, wbCELLAfterLoad); wbServiceFlags := wbFlags([ {0x00000001} 'Weapons', {0x00000002} 'Armor', {0x00000004} 'Clothing', {0x00000008} 'Books', {0x00000010} 'Ingredients', {0x00000020} '', {0x00000040} '', {0x00000080} 'Lights', {0x00000100} 'Apparatus', {0x00000200} '', {0x00000400} 'Miscellaneous', {0x00000800} 'Spells', {0x00001000} 'Magic Items', {0x00002000} 'Potions', {0x00004000} 'Training', {0x00008000} '', {0x00010000} 'Recharge', {0x00020000} 'Repair' ]); wbSpecializationEnum := wbEnum(['Combat', 'Magic', 'Stealth']); wbRecord(CLAS, 'Class', [ wbEDID, wbFULL, wbDESC, wbICON, wbStruct(DATA, '', [ wbArrayS('Primary Attributes', wbInteger('Primary Attribute', itS32, wbActorValueEnum), 2), wbInteger('Specialization', itU32, wbSpecializationEnum), wbArrayS('Major Skills', wbInteger('Major Skill', itS32, wbActorValueEnum), 7), wbInteger('Flags', itU32, wbFlags(['Playable', 'Guard'])), wbInteger('Buys/Sells and Services', itU32, wbServiceFlags), wbInteger('Teaches', itS8, wbSkillEnum), wbInteger('Maximum training level', itU8), wbInteger('Unused', itU16) ], cpNormal, True, nil, 5) ]); wbRecord(CLMT, 'Climate', [ wbEDID, wbArrayS(WLST, 'Weather Types', wbStructSK([0], 'Weather Type', [ wbFormIDCk('Weather', [WTHR]), wbInteger('Chance', itS32) ])), wbString(FNAM, 'Sun Texture'), wbString(GNAM, 'Sun Glare Texture'), wbMODL, wbStruct(TNAM, 'Timing', [ wbStruct('Sunrise', [ wbInteger('Begin', itU8, wbClmtTime), wbInteger('End', itU8, wbClmtTime) ]), wbStruct('Sunset', [ wbInteger('Begin', itU8, wbClmtTime), wbInteger('End', itU8, wbClmtTime) ]), wbInteger('Volatility', itU8), wbInteger('Moons / Phase Length', itU8, wbClmtMoonsPhaseLength) ], cpNormal, True) ]); wbRecord(CLOT, 'Clothing', [ wbEDID, wbFULL, wbSCRI, wbENAM, wbInteger(ANAM, 'Enchantment Points', itU16), wbStruct(BMDT, '', [ wbInteger('Biped Flags', itU16, wbFlags([ {0x00000001} 'Head', {0x00000002} 'Hair', {0x00000004} 'Upper Body', {0x00000008} 'Lower Body', {0x00000010} 'Hand', {0x00000020} 'Foot', {0x00000040} 'Right Ring', {0x00000080} 'Left Ring', {0x00000100} 'Amulet', {0x00000200} 'Weapon', {0x00000400} 'Back Weapon', {0x00000800} 'Side Weapon', {0x00001000} 'Quiver', {0x00002000} 'Shield', {0x00004000} 'Torch', {0x00008000} 'Tail' ])), wbInteger('General Flags', itU8, wbFlags([ {0x0001} 'Hide Rings', {0x0002} 'Hide Amulets', {0x0004} '', {0x0008} '', {0x0010} '', {0x0020} '', {0x0040} 'Non-Playable', {0x0080} '' {Heavy armor} ])), wbByteArray('Unused', 1) ], cpNormal, True), wbRStruct('Male biped model', [ wbString(MODL, 'Model Filename'), wbFloat(MODB, 'Bound Radius', cpBenign), wbByteArray(MODT, 'Texture Files Hashes', 0, cpIgnore) ], []), wbRStruct('Male world model', [ wbString(MOD2, 'Model Filename'), wbFloat(MO2B, 'Bound Radius', cpBenign), wbByteArray(MO2T, 'Texture Files Hashes', 0, cpIgnore) ], []), wbString(ICON, 'Male icon filename'), wbRStruct('Female biped model', [ wbString(MOD3, 'Model Filename'), wbFloat(MO3B, 'Bound Radius', cpBenign), wbByteArray(MO3T, 'Texture Files Hashes', 0, cpIgnore) ], []), wbRStruct('Female world model', [ wbString(MOD4, 'Model Filename'), wbFloat(MO4B, 'Bound Radius', cpBenign), wbByteArray(MO4T, 'Texture Files Hashes', 0, cpIgnore) ], []), wbString(ICO2, 'Female icon filename'), wbStruct(DATA, '', [ wbInteger('Value', itU32), wbFloat('Weight') ], cpNormal, True) ]); wbCNTO := wbStructSK(CNTO, [0], 'Item', [ wbFormIDCk('Item', [ARMO, AMMO, MISC, WEAP, INGR, SLGM, SGST, BOOK, LVLI, KEYM, CLOT, ALCH, APPA, LIGH]), wbInteger('Count', itS32) ]); wbCNTOs := wbRArrayS('Items', wbCNTO); wbRecord(CONT, 'Container', [ wbEDID, wbFULL, wbMODL, wbSCRI, wbCNTOs, wbStruct(DATA, '', [ wbInteger('Flags', itU8, wbFlags(['', 'Respawns'])), wbFloat('Weight') ], cpNormal, True), wbFormIDCk(SNAM, 'Open sound', [SOUN]), wbFormIDCk(QNAM, 'Close sound', [SOUN]) ]); wbCSDT := wbRStructSK([0], 'Sound Type', [ wbInteger(CSDT, 'Type', itU32,wbEnum([ {0x00} 'Left Foot', {0x01} 'Right Foot', {0x02} 'Left Back Foot', {0x03} 'Right Back Foot', {0x04} 'Idle', {0x05} 'Aware', {0x06} 'Attack', {0x07} 'Hit', {0x08} 'Death', {0x09} 'Weapon' ])), wbRArrayS('Sounds', wbRStructSK([0], 'Sound', [ wbFormIDCk(CSDI, 'Sound', [SOUN, NULL], False, cpNormal, True), wbInteger(CSDC, 'Sound Chance', itU8, nil, cpNormal, True) ], []), cpNormal, True) ], []); wbCSDTs := wbRArrayS('Sound Types', wbCSDT); wbSoulGemEnum := wbEnum([ {0} 'None', {1} 'Petty', {2} 'Lesser', {3} 'Common', {4} 'Greater', {5} 'Grand' ]); wbRecord(CREA, 'Creature', [ wbEDID, wbFULL, wbMODL, wbCNTOs, wbSPLOs, wbArrayS(NIFZ, 'Models', wbStringLC('Model')), wbByteArray(NIFT, 'Texture Files Hashes', 0, cpIgnore), wbStruct(ACBS, 'Configuration', [ wbInteger('Flags', itU32, wbFlags([ {0x000001} 'Biped', {0x000002} 'Essential', {0x000004} 'Weapon & Shield', {0x000008} 'Respawn', {0x000010} 'Swims', {0x000020} 'Flies', {0x000040} 'Walks', {0x000080} 'PC Level Offset', {0x000100} 'Unused', //?? {0x000200} 'No Low Level Processing', {0x000400} 'Unused', //?? {0x000800} 'No Blood Spray', {0x001000} 'No Blood Decal', {0x002000} '', {0x004000} '', {0x008000} 'No Head', {0x010000} 'No Right Arm', {0x020000} 'No Left Arm', {0x040000} 'No Combat in Water', {0x080000} 'No Shadow', {0x100000} 'No Corpse Check' ])), wbInteger('Base spell points', itU16), wbInteger('Fatigue', itU16), wbInteger('Barter gold', itU16), wbInteger('Level (offset)', itS16), wbInteger('Calc min', itU16), wbInteger('Calc max', itU16) ], cpNormal, True), wbRArrayS('Factions', wbStructSK(SNAM, [0], 'Faction', [ wbFormIDCk('Faction', [FACT]), wbInteger('Rank', itU8), wbByteArray('Unused', 3) ]) ), wbFormIDCk(INAM, 'Death item', [LVLI]), wbSCRI, wbStruct(AIDT, 'AI Data', [ wbInteger('Aggression', itU8), wbInteger('Confidence', itU8), wbInteger('Energy Level', itU8), wbInteger('Responsibility', itU8), wbInteger('Buys/Sells and Services', itU32, wbServiceFlags), wbInteger('Teaches', itS8, wbSkillEnum), wbInteger('Maximum training level', itU8), wbByteArray('Unused', 2) ], cpNormal, True), wbRArray('AI Packages', wbFormIDCk(PKID, 'AI Package', [PACK])), wbArrayS(KFFZ, 'Animations', wbStringLC('Animation')), wbStruct(DATA, 'Creature Data', [ wbInteger('Type', itU8, wbEnum([ 'Creature', 'Daedra', 'Undead', 'Humanoid', 'Horse', 'Giant' ])), wbInteger('Combat Skill', itU8), wbInteger('Magic Skill', itU8), wbInteger('Stealth Skill', itU8), wbInteger('Soul', itU8, wbSoulGemEnum), wbByteArray('Unused', 1), wbInteger('Health', itU16), wbByteArray('Unused', 2), wbInteger('Attack Damage', itU16), wbInteger('Strength', itU8), wbInteger('Intelligence', itU8), wbInteger('Willpower', itU8), wbInteger('Agility', itU8), wbInteger('Speed', itU8), wbInteger('Endurance', itU8), wbInteger('Personality', itU8), wbInteger('Luck', itU8) ], cpNormal, True), wbInteger(RNAM, 'Attack reach', itU8, nil, cpNormal, True), wbFormIDCk(ZNAM, 'Combat Style', [CSTY]), wbFloat(TNAM, 'Turning Speed', cpNormal, True), wbFloat(BNAM, 'Base Scale', cpNormal, True), wbFloat(WNAM, 'Foot Weight', cpNormal, True), wbString(NAM0, 'Blood Spray'), wbString(NAM1, 'Blood Decal'), wbFormIDCk(CSCR, 'Inherits Sounds from', [CREA]), wbCSDTs ], True); wbRecord(CSTY, 'Combat Style', [ wbEDID, wbStruct(CSTD, 'Standard', [ {000}wbInteger('Dodge % Chance', itU8), {001}wbInteger('Left/Right % Chance', itU8), {002}wbByteArray('Unused', 2), {004}wbFloat('Dodge L/R Timer (min)'), {008}wbFloat('Dodge L/R Timer (max)'), {012}wbFloat('Dodge Forward Timer (min)'), {016}wbFloat('Dodge Forward Timer (max)'), {020}wbFloat('Dodge Back Timer Min'), {024}wbFloat('Dodge Back Timer Max'), {028}wbFloat('Idle Timer min'), {032}wbFloat('Idle Timer max'), {036}wbInteger('Block % Chance', itU8), {037}wbInteger('Attack % Chance', itU8), {038}wbByteArray('Unused', 2), {040}wbFloat('Recoil/Stagger Bonus to Attack'), {044}wbFloat('Unconscious Bonus to Attack'), {048}wbFloat('Hand-To-Hand Bonus to Attack'), {052}wbInteger('Power Attack % Chance', itU8), {053}wbByteArray('Unused', 3), {056}wbFloat('Recoil/Stagger Bonus to Power'), {060}wbFloat('Unconscious Bonus to Power Attack'), {064}wbInteger('Power Attack - Normal', itU8), {065}wbInteger('Power Attack - Forward', itU8), {066}wbInteger('Power Attack - Back', itU8), {067}wbInteger('Power Attack - Left', itU8), {068}wbInteger('Power Attack - Right', itU8), {069}wbByteArray('Unused', 3), {072}wbFloat('Hold Timer (min)'), {076}wbFloat('Hold Timer (max)'), {080}wbInteger('Flags 1', itU8, wbFlags([ 'Advanced', 'Choose Attack using % Chance', 'Ignore Allies in Area', 'Will Yield', 'Rejects Yields', 'Fleeing Disabled', 'Prefers Ranged', 'Melee Alert OK' ])), {081}wbInteger('Acrobatic Dodge % Chance', itU8), {082}wbByteArray('Unused', 2), {084}wbFloat('Range Mult (Optimal)'), {088}wbFloat('Range Mult (Max)'), {092}wbFloat('Switch Distance (Melee)'), {096}wbFloat('Switch Distance (Ranged)'), {100}wbFloat('Buff standoff Distance'), {104}wbFloat('Ranged standoff Distance'), {108}wbFloat('Group standoff Distance'), {112}wbInteger('Rushing Attack % Chance', itU8), {113}wbByteArray('Unused', 3), {116}wbFloat('Rushing Attack Distance Mult'), {120}wbInteger('Flags 2', itU32, wbFlags([ 'Do Not Acquire' ])) ], cpNormal, True, nil, 31), wbStruct(CSAD, 'Advanced', [ wbFloat('Dodge Fatigue Mod Mult'), wbFloat('Dodge Fatigue Mod Base'), wbFloat('Encumb. Speed Mod Base'), wbFloat('Encumb. Speed Mod Mult'), wbFloat('Dodge While Under Attack Mult'), wbFloat('Dodge Not Under Attack Mult'), wbFloat('Dodge Back While Under Attack Mult'), wbFloat('Dodge Back Not Under Attack Mult'), wbFloat('Dodge Forward While Attacking Mult'), wbFloat('Dodge Forward Not Attacking Mult'), wbFloat('Block Skill Modifier Mult'), wbFloat('Block Skill Modifier Base'), wbFloat('Block While Under Attack Mult'), wbFloat('Block Not Under Attack Mult'), wbFloat('Attack Skill Modifier Mult'), wbFloat('Attack Skill Modifier Base'), wbFloat('Attack While Under Attack Mult'), wbFloat('Attack Not Under Attack Mult'), wbFloat('Attack During Block Mult'), wbFloat('Power Att. Fatigue Mod Base'), wbFloat('Power Att. Fatigue Mod Mult') ]) ]); wbRecord(DIAL, 'Dialog Topic', [ wbEDID, wbRArrayS('Quests', wbFormIDCk(QSTI, 'Quest', [QUST], False, cpBenign)), wbRArrayS('Quests?', wbFormIDCk(QSTR, 'Quest?', [QUST], False, cpBenign)), wbFULL, wbInteger(DATA, 'Type', itU8, wbEnum([ {0} 'Topic', {1} 'Conversation', {2} 'Combat', {3} 'Persuasion', {4} 'Detection', {5} 'Service', {6} 'Miscellaneous' ]), cpNormal, True) ], True); wbRecord(DOOR, 'Door', [ wbEDID, wbFULL, wbMODL, wbSCRI, wbFormIDCk(SNAM, 'Open sound', [SOUN]), wbFormIDCk(ANAM, 'Close sound', [SOUN]), wbFormIDCk(BNAM, 'Loop sound', [SOUN]), wbInteger(FNAM, 'Flags', itU8, wbFlags([ {0x01} 'Oblivion gate', {0x02} 'Automatic door', {0x04} 'Hidden', {0x08} 'Minimal use' ]), cpNormal, True), wbRArrayS('Random teleport destinations', wbFormIDCk(TNAM, 'Destination', [CELL, WRLD])) ]); wbBlendModeEnum := wbEnum([ '', 'Zero', 'One', 'Source Color', 'Source Inverse Color', 'Source Alpha', 'Source Inverted Alpha', 'Dest Alpha', 'Dest Inverted Alpha', 'Dest Color', 'Dest Inverse Color', 'Source Alpha SAT' ]); wbBlendOpEnum := wbEnum([ '', 'Add', 'Subtract', 'Reverse Subtract', 'Minimum', 'Maximum' ]); wbZTestFuncEnum := wbEnum([ '', '', '', 'Equal To', 'Normal', 'Greater Than', '', 'Greater Than or Equal Than', 'Always Show' ]); wbRecord(EFSH, 'Effect Shader', [ wbEDID, wbString(ICON, 'Fill Texture'), wbString(ICO2, 'Particle Shader Texture'), wbStruct(DATA, '', [ wbInteger('Flags', itU8, wbFlags([ {0} 'No Membrane Shader', {1} '', {2} '', {3} 'No Particle Shader', {4} 'Edge Effect - Inverse', {5} 'Membrane Shader - Affect Skin Only' ])), wbByteArray('Unused', 3), wbInteger('Membrane Shader - Source Blend Mode', itU32, wbBlendModeEnum), wbInteger('Membrane Shader - Blend Operation', itU32, wbBlendOpEnum), wbInteger('Membrane Shader - Z Test Function', itU32, wbZTestFuncEnum), wbStruct('Fill/Texture Effect - Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbFloat('Fill/Texture Effect - Alpha Fade In Time'), wbFloat('Fill/Texture Effect - Full Alpha Time'), wbFloat('Fill/Texture Effect - Alpha Fade Out Time'), wbFloat('Fill/Texture Effect - Presistent Alpha Ratio'), wbFloat('Fill/Texture Effect - Alpha Pulse Amplitude'), wbFloat('Fill/Texture Effect - Alpha Pulse Frequency'), wbFloat('Fill/Texture Effect - Texture Animation Speed (U)'), wbFloat('Fill/Texture Effect - Texture Animation Speed (V)'), wbFloat('Edge Effect - Fall Off'), wbStruct('Edge Effect - Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbFloat('Edge Effect - Alpha Fade In Time'), wbFloat('Edge Effect - Full Alpha Time'), wbFloat('Edge Effect - Alpha Fade Out Time'), wbFloat('Edge Effect - Persistent Alpha Ratio'), wbFloat('Edge Effect - Alpha Pulse Amplitude'), wbFloat('Edge Effect - Alpha Pusle Frequence'), wbFloat('Fill/Texture Effect - Full Alpha Ratio'), wbFloat('Edge Effect - Full Alpha Ratio'), wbInteger('Membrane Shader - Dest Blend Mode', itU32, wbBlendModeEnum), wbInteger('Particle Shader - Source Blend Mode', itU32, wbBlendModeEnum), wbInteger('Particle Shader - Blend Operation', itU32, wbBlendOpEnum), wbInteger('Particle Shader - Z Test Function', itU32, wbZTestFuncEnum), wbInteger('Particle Shader - Dest Blend Mode', itU32, wbBlendModeEnum), wbFloat('Particle Shader - Particle Birth Ramp Up Time'), wbFloat('Particle Shader - Full Particle Birth Time'), wbFloat('Particle Shader - Particle Birth Ramp Down Time'), wbFloat('Particle Shader - Full Particle Birth Ratio'), wbFloat('Particle Shader - Persistant Particle Birth Ratio'), wbFloat('Particle Shader - Particle Lifetime'), wbFloat('Particle Shader - Particle Lifetime +/-'), wbFloat('Particle Shader - Initial Speed Along Normal'), wbFloat('Particle Shader - Acceleration Along Normal'), wbFloat('Particle Shader - Initial Velocity #1'), wbFloat('Particle Shader - Initial Velocity #2'), wbFloat('Particle Shader - Initial Velocity #3'), wbFloat('Particle Shader - Acceleration #1'), wbFloat('Particle Shader - Acceleration #2'), wbFloat('Particle Shader - Acceleration #3'), wbFloat('Particle Shader - Scale Key 1'), wbFloat('Particle Shader - Scale Key 2'), wbFloat('Particle Shader - Scale Key 1 Time'), wbFloat('Particle Shader - Scale Key 2 Time'), wbStruct('Color Key 1 - Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Color Key 2 - Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Color Key 3 - Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbFloat('Color Key 1 - Color Alpha'), wbFloat('Color Key 2 - Color Alpha'), wbFloat('Color Key 3 - Color Alpha'), wbFloat('Color Key 1 - Color Key Time'), wbFloat('Color Key 2 - Color Key Time'), wbFloat('Color Key 3 - Color Key Time') ], cpNormal, True, nil, 25) ]); wbRecord(ENCH, 'Enchantment', [ wbEDID, wbStruct(OBME, 'Oblivion Magic Extender', [ wbInteger('Record Version', itU8), wbStruct('OBME Version', [ wbInteger('Beta', itU8), wbInteger('Minor', itU8), wbInteger('Major', itU8) ]), wbByteArray('Unused', $1C) ], cpNormal, False, wbOBMEDontShow), wbFULL, wbStruct(ENIT, '', [ wbInteger('Type', itU32, wbEnum([ {0} 'Scroll', {1} 'Staff', {2} 'Weapon', {3} 'Apparel' ])), wbInteger('Charge Amount', itU32), wbInteger('Enchant Cost', itU32), wbInteger('Flags', itU8, wbFlags(['Manual Enchant Cost (Autocalc Off)'])), wbByteArray('Unused', 3) ], cpNormal, True), wbEffects ]); wbRecord(EYES, 'Eyes', [ wbEDID, wbFULL, wbString(ICON, 'Texture', 0, cpNormal, True), wbInteger(DATA, 'Flags', itU8, wbFlags(['Playable']), cpNormal, True) ]); wbXNAM := wbStructSK(XNAM, [0], 'Relation', [ wbFormIDCk('Faction', [FACT, RACE]), wbInteger('Modifier', itS32) ]); wbXNAMs := wbRArrayS('Relations', wbXNAM); wbRecord(FACT, 'Faction', [ wbEDID, wbFULL, wbXNAMs, wbInteger(DATA, 'Flags', itU8, wbFlags(['Hidden from Player', 'Evil', 'Special Combat']), cpNormal, True), wbFloat(CNAM, 'Crime Gold Multiplier', cpNormal, True, 1, -1, nil, nil, 1.0), wbRStructsSK('Ranks', 'Rank', [0], [ wbInteger(RNAM, 'Rank#', itS32), wbString(MNAM, 'Male', 0, cpTranslate), wbString(FNAM, 'Female', 0, cpTranslate), wbString(INAM, 'Insignia') ], []) ]); wbRecord(FLOR, 'Flora', [ wbEDID, wbFULL, wbMODL, wbSCRI, wbFormIDCk(PFIG, 'Ingredient', [INGR]), wbStruct(PFPC, 'Seasonal ingredient production', [ wbInteger('Spring', itU8), wbInteger('Summer ', itU8), wbInteger('Fall', itU8), wbInteger('Winter', itU8) ], cpNormal, True) ]); wbRecord(FURN, 'Furniture', [ wbEDID, wbFULL, wbMODL, wbSCRI, wbByteArray(MNAM, 'Marker Flags', 0, cpNormal, True) ]); wbRecord(GLOB, 'Global', [ wbEDID, wbInteger(FNAM, 'Type', itU8, wbGLOBFNAM, nil, cpNormal, True), wbFloat(FLTV, 'Value', cpNormal, True) ]); wbRecord(GMST, 'Game Setting', [ wbEDID, wbUnion(DATA, 'Value', wbGMSTUnionDecider, [ wbString('', 0, cpTranslate), wbInteger('', itS32), wbFloat('') ], cpNormal, True) ]); wbRecord(GRAS, 'Grass', [ wbEDID, wbMODL, wbStruct(DATA, '', [ wbInteger('Density', itU8), wbInteger('Min Slope', itU8), wbInteger('Max Slope', itU8), wbByteArray('Unused', 1), wbInteger('Unit from water amount', itU16), wbByteArray('Unused', 2), wbInteger('Unit from water type', itU32, wbEnum([ 'Above - At Least', 'Above - At Most', 'Below - At Least', 'Below - At Most', 'Either - At Least', 'Either - At Most', 'Either - At Most Above', 'Either - At Most Below' ])), wbFloat('Position Range'), wbFloat('Height Range'), wbFloat('Color Range'), wbFloat('Wave Period'), wbInteger('Flags', itU8, wbFlags([ 'Vertex Lighting', 'Uniform Scaling', 'Fit to Slope' ])), wbByteArray('Unused', 3) ], cpNormal, True) ]); wbRecord(HAIR, 'Hair', [ wbEDID, wbFULL, wbMODL, wbString(ICON, 'Texture', 0, cpNormal, True), wbInteger(DATA, 'Flags', itU8, wbFlags([ 'Playable', 'Not Male', 'Not Female', 'Fixed' ]), cpNormal, True) ]); wbCrimeTypeEnum := wbEnum([ 'Steal', 'Pickpocket', 'Trespass', 'Attack', 'Murder', 'Steal Horse' ], [ -1, 'None' ]); wbFormTypeEnum := wbEnum([], [ $03, 'Game Setting', $04, 'Global', $05, 'Class', $06, 'Faction', $07, 'Hair', $08, 'Eyes', $09, 'Race', $0A, 'Sound', $0B, 'Skill', $0C, 'Magic Effect', $0D, 'Script', $0E, 'Land Texture', $0F, 'Enchantment', $10, 'Spell', $11, 'BirthSign', $12, 'Activator', $13, 'Apparatus', $14, 'Armor', $15, 'Book', $16, 'Clothing', $17, 'Container', $18, 'Door', $19, 'Ingredient', $1A, 'Light', $1B, 'Misc', $1C, 'Static', $1D, 'Grass', $1E, 'Tree', $1F, 'Flora', $20, 'Furniture', $21, 'Weapon', $22, 'Ammi', $23, 'NPC', $24, 'Creature', $25, 'Leveled Creature', $26, 'Soul Gem', $27, 'Key', $28, 'Alchemy', $29, 'SubSpace', $2A, 'Sigil Stone', $2B, 'Leveled Item', $2D, 'Weather', $2E, 'Climate', $2F, 'Region', $30, 'Cell', $31, 'Placed Object', $32, 'Placed NPC', $33, 'Placed Creature', $34, 'Path Grid', $35, 'Worldspace', $36, 'Landscape', $38, 'Road', $39, 'Dialog Topic', $3A, 'Dialog Response', $3B, 'Quest', $3C, 'Idle Animation', $3D, 'Package', $3E, 'Combat Style', $3F, 'Load Screen', $40, 'Leveled Spell', $41, 'Animated Object', $42, 'Water', $43, 'Effect Shader' ]); wbSexEnum := wbEnum(['Male','Female']); wbAxisEnum := wbEnum([], [ 88, 'X', 89, 'Y', 90, 'Z' ]); wbCTDA := wbRUnion('Condition', [ wbStruct(CTDA, 'Condition', [ wbInteger('Type', itU8, wbCtdaType), wbByteArray('Unused', 3), wbUnion('Comparison Value', wbCTDACompValueDecider, [ wbFloat('Comparison Value - Float'), wbFormIDCk('Comparison Value - Global', [GLOB]) ]), wbInteger('Function', itU32, wbCTDAFunctionToStr, wbCTDAFunctionToInt), wbUnion('Parameter #1', wbCTDAParam1Decider, [ {00} wbByteArray('Unknown', 4), {01} wbByteArray('None', 4, cpIgnore), {02} wbInteger('Integer', itS32), {03} wbInteger('Variable Name (INVALID)', itS32), {04} wbInteger('Sex', itU32, wbSexEnum), {05} wbFormIDCk('Actor Value', [ACVA]), // {05} wbInteger('Actor Value', itS32, wbActorValueEnum), {06} wbInteger('Crime Type', itU32, wbCrimeTypeEnum), {07} wbInteger('Axis', itU32, wbAxisEnum), {08} wbInteger('Form Type', itU32, wbFormTypeEnum), {09} wbInteger('Quest Stage (INVALID)', itS32), {10} wbFormIDCk('Object Reference', [PLYR, REFR, ACHR, ACRE, TRGT]), {12} wbFormIDCk('Inventory Object', [ARMO, AMMO, MISC, WEAP, INGR, SLGM, SGST, BOOK, KEYM, CLOT, ALCH, APPA, LIGH]), {13} wbFormIDCk('Actor', [PLYR, ACHR, ACRE, TRGT]), {14} wbFormIDCk('Quest', [QUST]), {15} wbFormIDCk('Faction', [FACT]), {16} wbFormIDCk('Cell', [CELL]), {17} wbFormIDCk('Class', [CLAS]), {18} wbFormIDCk('Race', [RACE]), {19} wbFormIDCk('Actor Base', [NPC_, CREA, ACTI]), {20} wbFormIDCk('Global', [GLOB]), {21} wbFormIDCk('Weather', [WTHR]), {22} wbFormIDCk('Package', [PACK]), {23} wbFormIDCk('Owner', [FACT, NPC_]), {24} wbFormIDCk('Birthsign', [BSGN]), {25} wbFormIDCk('Furniture', [FURN]), {26} wbFormIDCk('Magic Item', [SPEL]), {27} wbFormIDCk('Magic Effect', [MGEF]), {28} wbFormIDCk('Worldspace', [WRLD]), {29} wbFormIDCk('Referenceable Object', [CREA, NPC_, TREE, SBSP, LVLC, SOUN, ACTI, DOOR, FLOR, STAT, FURN, CONT, ARMO, AMMO, MISC, WEAP, INGR, SLGM, SGST, BOOK, KEYM, CLOT, ALCH, APPA, LIGH, GRAS]) ]), wbUnion('Parameter #2', wbCTDAParam2Decider, [ {00} wbByteArray('Unknown', 4), {01} wbByteArray('None', 4, cpIgnore), {02} wbInteger('Integer', itS32), {03} wbInteger('Variable Name', itS32, wbCTDAParam2VariableNameToStr, wbCTDAParam2VariableNameToInt), {04} wbInteger('Sex', itU32, wbSexEnum), {05} wbFormIDCk('Actor Value', [ACVA]), // {05} wbInteger('Actor Value', itS32, wbActorValueEnum), {06} wbInteger('Crime Type', itU32, wbCrimeTypeEnum), {07} wbInteger('Axis', itU32, wbAxisEnum), {08} wbInteger('Form Type', itU32, wbFormTypeEnum), {09} wbInteger('Quest Stage', itS32, wbCTDAParam2QuestStageToStr, wbCTDAParam2QuestStageToInt), {10} wbFormIDCk('Object Reference', [PLYR, REFR, ACHR, ACRE, TRGT]), {12} wbFormIDCk('Inventory Object', [ARMO, AMMO, MISC, WEAP, INGR, SLGM, SGST, BOOK, KEYM, CLOT, ALCH, APPA, LIGH]), {13} wbFormIDCk('Actor', [PLYR, ACHR, ACRE, TRGT]), {14} wbFormIDCk('Quest', [QUST]), {15} wbFormIDCk('Faction', [FACT]), {16} wbFormIDCk('Cell', [CELL]), {17} wbFormIDCk('Class', [CLAS]), {18} wbFormIDCk('Race', [RACE]), {19} wbFormIDCk('Actor Base', [NPC_, CREA, ACTI]), {20} wbFormIDCk('Global', [GLOB]), {21} wbFormIDCk('Weather', [WTHR]), {22} wbFormIDCk('Package', [PACK]), {23} wbFormIDCk('Owner', [FACT, NPC_]), {24} wbFormIDCk('Birthsign', [BSGN]), {25} wbFormIDCk('Furniture', [FURN]), {26} wbFormIDCk('Magic Item', [SPEL]), {27} wbFormIDCk('Magic Effect', [MGEF]), {28} wbFormIDCk('Worldspace', [WRLD]), {29} wbFormIDCk('Referenceable Object', [CREA, NPC_, TREE, SBSP, LVLC, SOUN, ACTI, DOOR, FLOR, STAT, FURN, CONT, ARMO, AMMO, MISC, WEAP, INGR, SLGM, SGST, BOOK, KEYM, CLOT, ALCH, APPA, LIGH, GRAS]) ]), wbInteger('Unused', itU32, nil, cpIgnore) ], cpNormal, False, nil, 6), wbStruct(CTDT, 'Condition (old format)', [ wbInteger('Type', itU8, wbCtdaType), wbByteArray('Unused', 3), wbUnion('Comparison Value', wbCTDACompValueDecider, [ wbFloat('Comparison Value - Float'), wbFormIDCk('Comparison Value - Global', [GLOB]) ]), wbInteger('Function', itU32, wbCTDAFunctionToStr, wbCTDAFunctionToInt), wbUnion('Parameter #1', wbCTDAParam1Decider, [ {00} wbByteArray('Unknown', 4), {01} wbByteArray('None', 4, cpIgnore), {02} wbInteger('Integer', itS32), {03} wbInteger('Variable Name (INVALID)', itS32), {04} wbInteger('Sex', itU32, wbSexEnum), {05} wbFormIDCk('Actor Value', [ACVA]), // {05} wbInteger('Actor Value', itS32, wbActorValueEnum), {06} wbInteger('Crime Type', itU32, wbCrimeTypeEnum), {07} wbInteger('Axis', itU32, wbAxisEnum), {08} wbInteger('Form Type', itU32, wbFormTypeEnum), {09} wbInteger('Quest Stage (INVALID)', itS32), {10} wbFormIDCk('Object Reference', [PLYR, REFR, ACHR, ACRE, TRGT]), {12} wbFormIDCk('Inventory Object', [ARMO, AMMO, MISC, WEAP, INGR, SLGM, SGST, BOOK, KEYM, CLOT, ALCH, APPA, LIGH]), {13} wbFormIDCk('Actor', [PLYR, ACHR, ACRE, TRGT]), {14} wbFormIDCk('Quest', [QUST]), {15} wbFormIDCk('Faction', [FACT]), {16} wbFormIDCk('Cell', [CELL]), {17} wbFormIDCk('Class', [CLAS]), {18} wbFormIDCk('Race', [RACE]), {19} wbFormIDCk('Actor Base', [NPC_, CREA, ACTI]), {20} wbFormIDCk('Global', [GLOB]), {21} wbFormIDCk('Weather', [WTHR]), {22} wbFormIDCk('Package', [PACK]), {23} wbFormIDCk('Owner', [FACT, NPC_]), {24} wbFormIDCk('Birthsign', [BSGN]), {25} wbFormIDCk('Furniture', [FURN]), {26} wbFormIDCk('Magic Item', [SPEL]), {27} wbFormIDCk('Magic Effect', [MGEF]), {28} wbFormIDCk('Worldspace', [WRLD]), {29} wbFormIDCk('Referenceable Object', [CREA, NPC_, TREE, SBSP, LVLC, SOUN, ACTI, DOOR, FLOR, STAT, FURN, CONT, ARMO, AMMO, MISC, WEAP, INGR, SLGM, SGST, BOOK, KEYM, CLOT, ALCH, APPA, LIGH, GRAS]) ]), wbUnion('Parameter #2', wbCTDAParam2Decider, [ {00} wbByteArray('Unknown', 4), {01} wbByteArray('None', 4, cpIgnore), {02} wbInteger('Integer', itS32), {03} wbInteger('Variable Name', itS32, wbCTDAParam2VariableNameToStr, wbCTDAParam2VariableNameToInt), {04} wbInteger('Sex', itU32, wbSexEnum), {05} wbFormIDCk('Actor Value', [ACVA]), // {05} wbInteger('Actor Value', itS32, wbActorValueEnum), {06} wbInteger('Crime Type', itU32, wbCrimeTypeEnum), {07} wbInteger('Axis', itU32, wbAxisEnum), {08} wbInteger('Form Type', itU32, wbFormTypeEnum), {09} wbInteger('Quest Stage', itS32, wbCTDAParam2QuestStageToStr, wbCTDAParam2QuestStageToInt), {10} wbFormIDCk('Object Reference', [PLYR, REFR, ACHR, ACRE, TRGT]), {12} wbFormIDCk('Inventory Object', [ARMO, AMMO, MISC, WEAP, INGR, SLGM, SGST, BOOK, KEYM, CLOT, ALCH, APPA, LIGH]), {13} wbFormIDCk('Actor', [PLYR, ACHR, ACRE, TRGT]), {14} wbFormIDCk('Quest', [QUST]), {15} wbFormIDCk('Faction', [FACT]), {16} wbFormIDCk('Cell', [CELL]), {17} wbFormIDCk('Class', [CLAS]), {18} wbFormIDCk('Race', [RACE]), {19} wbFormIDCk('Actor Base', [NPC_, CREA, ACTI]), {20} wbFormIDCk('Global', [GLOB]), {21} wbFormIDCk('Weather', [WTHR]), {22} wbFormIDCk('Package', [PACK]), {23} wbFormIDCk('Owner', [FACT, NPC_]), {24} wbFormIDCk('Birthsign', [BSGN]), {25} wbFormIDCk('Furniture', [FURN]), {26} wbFormIDCk('Magic Item', [SPEL]), {27} wbFormIDCk('Magic Effect', [MGEF]), {28} wbFormIDCk('Worldspace', [WRLD]), {29} wbFormIDCk('Referenceable Object', [CREA, NPC_, TREE, SBSP, LVLC, SOUN, ACTI, DOOR, FLOR, STAT, FURN, CONT, ARMO, AMMO, MISC, WEAP, INGR, SLGM, SGST, BOOK, KEYM, CLOT, ALCH, APPA, LIGH, GRAS]) ]), wbEmpty('Unused', cpIgnore) ]) ], []); wbCTDAs := wbRArray('Conditions', wbCTDA); wbSCHR := wbRUnion('Basic Script Data', [ wbStruct(SCHR, 'Basic Script Data', [ wbByteArray('Unused', 4), wbInteger('RefCount', itU32), wbInteger('CompiledSize', itU32), wbInteger('VariableCount', itU32), wbInteger('Type', itU32, wbEnum([ 'Object', 'Quest' ], [ $100, 'Magic Effect' ])) ]), wbStruct(SCHD, 'Basic Script Data', [ wbByteArray('Unused', 4), wbInteger('RefCount', itU32), wbInteger('CompiledSize', itU32), wbInteger('VariableCount', itU32), wbInteger('Type', itU32, wbEnum([ 'Object', 'Quest' ], [ $100, 'Magic Effect' ])), wbByteArray('Unknown') ]) ], []); wbSCROs := wbRArray('References', wbRUnion('', [ wbFormID(SCRO, 'Global Reference'), // wbFormIDCk(SCRO, 'Global Reference', // [ACTI, DOOR, FLOR, STAT, FURN, CREA, SPEL, NPC_, CONT, ARMO, AMMO, MISC, WEAP, // INGR, SLGM, SGST, BOOK, KEYM, CLOT, ALCH, APPA, LIGH, QUST, PLYR, PACK, LVLI, // FACT, ACHR, REFR, ACRE, GLOB, DIAL, CELL, SOUN, MGEF, WTHR, CLAS, EFSH, RACE, // LVLC, CSTY, WATR, WRLD, SCPT, BSGN, TREE, ENCH, NULL]), wbInteger(SCRV, 'Local Variable', itU32) ], []) ); wbResultScript := wbRStruct('Result Script', [ wbSCHR, wbByteArray(SCDA, 'Compiled result script'), wbStringScript(SCTX, 'Result script source'), wbSCROs ], []); { wbResultScriptOld := wbRStruct('Result Script (Old Format?)', [ wbByteArray(SCHD, 'Unknown (Script Header?)'), wbByteArray(SCDA, 'Compiled result script'), wbStringScript(SCTX, 'Result script source'), wbSCROs ], []); } wbRecord(IDLE, 'Idle Animation', [ wbEDID, wbMODL, wbCTDAs, wbInteger(ANAM, 'Animation Group Section', itU8, wbIdleAnam, nil, cpNormal, True), wbArray(DATA, 'Related Idle Animations', wbFormIDCk('Related Idle Animation', [IDLE, NULL]), ['Parent', 'Previous Sibling'], cpNormal, True) ]); wbRecord(INFO, 'Dialog response', [ wbStruct(DATA, '', [ wbInteger('Type', itU8, wbEnum([], [ 0, 'Topic', 1, 'Conversation', 2, 'Combat', 3, 'Persuasion', 4, 'Detection', 5, 'Service', 6, 'Miscellaneous' ])), wbInteger('Next Speaker', itU8, wbEnum([ {0} 'Target', {1} 'Self', {2} 'Either' ])), wbInteger('Flags', itU8, wbFlags([ {0x0001} 'Goodbye', {0x0002} 'Random', {0x0004} 'Say Once', {0x0008} 'Run Immediately', {0x0010} 'Info Refusal', {0x0020} 'Random End', {0x0040} 'Run for Rumors' ])) ], cpNormal, True), wbFormIDCk(QSTI, 'Quest', [QUST], False, cpNormal, True), wbFormIDCk(TPIC, 'Topic', [DIAL]), wbFormIDCk(PNAM, 'Previous INFO', [INFO, NULL]), wbRArray('Add topics', wbFormIDCk(NAME, 'Topic', [DIAL])), wbRArray('Responses', wbRStruct('Response', [ wbStruct(TRDT, 'Response Data', [ wbInteger('Emotion Type', itU32, wbEnum([ {0} 'Neutral', {1} 'Anger', {2} 'Disgust', {3} 'Fear', {4} 'Sad', {5} 'Happy', {6} 'Surprise' ])), wbInteger('Emotion Value', itS32), wbByteArray('Unused', 4), wbInteger('Response number', itU8), wbByteArray('Unused', 3) ]), wbStringKC(NAM1, 'Response Text', 0, cpTranslate), wbString(NAM2, 'Actor notes', 0, cpTranslate) ], []) ), wbCTDAs, wbRArray('Choices', wbFormIDCk(TCLT, 'Choice', [DIAL])), wbRArray('Link From', wbFormIDCk(TCLF, 'Topic', [DIAL])), wbResultScript ]); wbRecord(INGR, 'Ingredient', [ wbEDID, wbStruct(OBME, 'Oblivion Magic Extender', [ wbInteger('Record Version', itU8), wbStruct('OBME Version', [ wbInteger('Beta', itU8), wbInteger('Minor', itU8), wbInteger('Major', itU8) ]), wbByteArray('Unused', $1C) ], cpNormal, False, wbOBMEDontShow), wbFULL, wbMODL, wbICON, wbSCRI, wbFloat(DATA, 'Weight', cpNormal, True), wbStruct(ENIT, '', [ wbInteger('Value', itS32), wbInteger('Flags', itU8, wbFlags(['No auto-calculation', 'Food item'])), wbByteArray('Unused', 3) ], cpNormal, True), wbEffects ]); wbRecord(KEYM, 'Key', [ wbEDID, wbFULL, wbMODL, wbICON, wbSCRI, wbStruct(DATA, '', [ wbInteger('Value', itS32), wbFloat('Weight') ], cpNormal, True) ]); wbQuadrantEnum := wbEnum([ {0} 'Bottom Left', {1} 'Bottom Right', {2} 'Top Left', {3} 'Top Right' ]); if wbSimpleRecords then begin wbRecord(LAND, 'Landscape', [ wbByteArray(DATA, 'Unknown'), wbByteArray(VNML, 'Vertex Normals'), wbByteArray(VHGT, 'Vertext Height Map'), wbByteArray(VCLR, 'Vertex Colours'), wbRArrayS('Layers', wbRUnion('Layer', [ wbRStructSK([0],'Base Layer', [ wbStructSK(BTXT, [1, 3], 'Base Layer Header', [ wbFormIDCk('Texture', [LTEX, NULL]), wbInteger('Quadrant', itU8, wbQuadrantEnum), wbByteArray('Unused', 1), wbInteger('Layer', itS16) ]) ], []), wbRStructSK([0],'Alpha Layer', [ wbStructSK(ATXT, [1, 3], 'Alpha Layer Header', [ wbFormIDCk('Texture', [LTEX, NULL]), wbInteger('Quadrant', itU8, wbQuadrantEnum), wbByteArray('Unused', 1), wbInteger('Layer', itS16) ]), wbByteArray(VTXT, 'Alpha Layer Data') ], []) ], [])), wbArray(VTEX, 'Textures', wbFormIDCk('Texture', [LTEX, NULL])) ]); end else begin wbRecord(LAND, 'Landscape', [ wbByteArray(DATA, 'Unknown'), // wbStruct(DATA, '', [ // wbInteger('Flags', itU8, wbFlags([])), // wbByteArray('Unknown') // ]), wbArray(VNML, 'Vertex Normals', wbStruct('Row', [ wbArray('Columns', wbStruct('Column', [ wbInteger('X', itU8), wbInteger('Y', itU8), wbInteger('Z', itU8) ]), 33) ]), 33), wbStruct(VHGT, 'Vertext Height Map', [ wbFloat('Offset'), wbArray('Rows', wbStruct('Row', [ wbArray('Columns', wbInteger('Column', itU8), 33) ]), 33), wbByteArray('Unused', 3) ]), wbArray(VCLR, 'Vertex Colours', wbStruct('Row', [ wbArray('Columns', wbStruct('Column', [ wbInteger('X', itU8), wbInteger('Y', itU8), wbInteger('Z', itU8) ]), 33) ]), 33), wbRArrayS('Layers', wbRUnion('Layer', [ wbRStructSK([0],'Base Layer', [ wbStructSK(BTXT, [1, 3], 'Base Layer Header', [ wbFormIDCk('Texture', [LTEX, NULL]), wbInteger('Quadrant', itU8, wbQuadrantEnum), wbByteArray('Unused', 1), wbInteger('Layer', itS16) ]) ], []), wbRStructSK([0],'Alpha Layer', [ wbStructSK(ATXT, [1, 3], 'Alpha Layer Header', [ wbFormIDCk('Texture', [LTEX, NULL]), wbInteger('Quadrant', itU8, wbQuadrantEnum), wbByteArray('Unused', 1), wbInteger('Layer', itS16) ]), wbArrayS(VTXT, 'Alpha Layer Data', wbStructSK([0], 'Cell', [ wbInteger('Position', itU16, wbAtxtPosition), wbByteArray('Unused', 2), wbFloat('Opacity') ])) ], []) ], [])), wbArray(VTEX, 'Textures', wbFormIDCk('Texture', [LTEX, NULL])) ]); end; wbRecord(LIGH, 'Light', [ wbEDID, wbMODL, wbSCRI, wbFULL, wbICON, wbStruct(DATA, '', [ wbInteger('Time', itS32), wbInteger('Radius', itU32), wbStruct('Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbInteger('Unused', itU8) ]), wbInteger('Flags', itU32, wbFlags([ {0x00000001} 'Dynamic', {0x00000002} 'Can be Carried', {0x00000004} 'Negative', {0x00000008} 'Flicker', {0x00000010} 'Unused', {0x00000020} 'Off By Default', {0x00000040} 'Flicker Slow', {0x00000080} 'Pulse', {0x00000100} 'Pulse Slow', {0x00000200} 'Spot Light', {0x00000400} 'Spot Shadow' ])), wbFloat('Falloff Exponent'), wbFloat('FOV'), wbInteger('Value', itU32), wbFloat('Weight') ], cpNormal, True, nil, 6), wbFloat(FNAM, 'Fade value', cpNormal, True, 1, -1, nil, nil, 1.0), wbFormIDCk(SNAM, 'Sound', [SOUN]) ], False, nil, cpNormal, False, wbLIGHAfterLoad); wbRecord(LSCR, 'Load Screen', [ wbEDID, wbICON, wbDESC, wbRArrayS('Locations', wbStructSK(LNAM, [0, 1], 'Location', [ wbFormIDCk('Direct', [CELL, WRLD, NULL]), wbStructSK([0, 1], 'Indirect', [ wbFormIDCk('World', [NULL, WRLD]), wbStructSK([0,1], 'Grid', [ wbInteger('Y', itS16), wbInteger('X', itS16) ]) ]) ])) ]); wbRecord(LTEX, 'Landscape Texture', [ wbEDID, wbICON, wbStruct(HNAM, 'Havok Data', [ wbInteger('Material Type', itU8, wbEnum([ {00} 'STONE', {01} 'CLOTH', {02} 'DIRT', {03} 'GLASS', {04} 'GRASS', {05} 'METAL', {06} 'ORGANIC', {07} 'SKIN', {08} 'WATER', {09} 'WOOD', {10} 'HEAVY STONE', {11} 'HEAVY METAL', {12} 'HEAVY WOOD', {13} 'CHAIN', {14} 'SNOW' ]), cpNormal, True, nil, nil, 2), wbInteger('Friction', itU8, nil, cpNormal, True, nil, nil, 30), wbInteger('Restitution', itU8, nil, cpNormal, True, nil, nil, 30) ], cpNormal, True), wbInteger(SNAM, 'Texture Specular Exponent', itU8, nil, cpNormal, True, False, nil, nil, 30), wbRArrayS('Grasses', wbFormIDCk(GNAM, 'Grass', [GRAS])) ]); wbRecord(LVLC, 'Leveled Creature', [ wbEDID, wbInteger(LVLD, 'Chance none', itU8, nil, cpNormal, True), wbInteger(LVLF, 'Flags', itU8, wbFlags([ {0x01} 'Calculate from all levels <= player''s level', {0x02} 'Calculate for each item in count' ]), cpNormal, True), wbRArrayS('Leveled List Entries', wbStructExSK(LVLO , [0, 2], [3], 'Leveled List Entry', [ wbInteger('Level', itS16), wbByteArray('Unused', 2), wbFormIDCk('Reference', [NPC_, CREA, LVLC]), wbInteger('Count', itS16), wbByteArray('Unused', 2) ], cpNormal, False, nil, 3), cpNormal, True), wbSCRI, wbFormIDCk(TNAM, 'Creature template', [NPC_, CREA]) ], True, nil, cpNormal, False, wbLVLAfterLoad); wbRecord(LVLI, 'Leveled Item', [ wbEDID, wbInteger(LVLD, 'Chance none', itU8, nil, cpNormal, True), wbInteger(LVLF, 'Flags', itU8, wbFlags([ {0x01} 'Calculate from all levels <= player''s level', {0x02} 'Calculate for each item in count' ]), cpNormal, True), wbRArrayS('Leveled List Entries', wbStructExSK(LVLO , [0, 2], [3], 'Leveled List Entry', [ wbInteger('Level', itS16), wbByteArray('Unused', 2), wbFormIDCk('Reference', [ARMO, AMMO, MISC, WEAP, INGR, SLGM, SGST, BOOK, LVLI, KEYM, CLOT, ALCH, APPA, LIGH]), wbInteger('Count', itS16), wbByteArray('Unused', 2) ], cpNormal, False, nil, 3), cpNormal, True), wbByteArray(DATA, 'Unused', 1) ], False, nil, cpNormal, False, wbLVLAfterLoad); wbRecord(LVSP, 'Leveled Spell', [ wbEDID, wbInteger(LVLD, 'Chance none', itU8, nil, cpNormal, True), wbInteger(LVLF, 'Flags', itU8, wbFlags([ {0x01} 'Calculate from all levels <= player''s level', {0x02} 'Calculate for each item in count', {0x04} 'Use all spells' ]), cpNormal, True), wbRArrayS('Leveled List Entries', wbStructExSK(LVLO , [0, 2], [3], 'Leveled List Entry', [ wbInteger('Level', itS16), wbByteArray('Unused', 2), wbFormIDCk('Reference', [SPEL, LVSP]), wbInteger('Count', itS16), wbByteArray('Unused', 2) ], cpNormal, False, nil, 3), cpNormal, True) ], False, nil, cpNormal, False, wbLVLAfterLoad); wbRecord(MGEF, 'Magic Effect', [ wbStringMgefCode(EDID, 'Magic Effect Code'), wbStruct(OBME, 'Oblivion Magic Extender', [ wbInteger('Record Version', itU8), wbStruct('OBME Version', [ wbInteger('Beta', itU8), wbInteger('Minor', itU8), wbInteger('Major', itU8) ]), wbInteger('Param A Info', itU8, wbOBMEResolutionInfo), wbInteger('Param B Info', itU8, wbOBMEResolutionInfo), wbByteArray('Unused', 2), wbString('Handler', 4), wbInteger('Flag Overrides', itU32, wbFlags([ { 0} '', { 1} '', { 2} 'ParamFlagA', { 3} 'Beneficial', { 4} '', { 5} '', { 6} '', { 7} '', { 8} '', { 9} '', {10} '', {11} '', {12} '', {13} '', {14} '', {15} '', {16} 'ParamFlagB', {17} 'Magnitude Is Range', {18} 'Atomic Resistance', {19} 'ParamFlagC', {20} 'ParamFlagD', {21} '', {22} '', {23} '', {24} '', {25} '', {26} '', {27} '', {28} '', {29} '', {30} 'Hidden' ])), wbByteArray('ParamB', 4), wbByteArray('Unused', $1C) ], cpNormal, False, wbOBMEDontShow), wbString(EDDX, 'EditorID', 0, cpNormal, False, wbEDDXDontShow), wbFULL, wbDESC, wbICON, wbMODL, wbStruct(DATA, 'Data', [ wbInteger('Flags', itU32, wbFlags([ {0x00000001} 'Hostile', {0x00000002} 'Recover', {0x00000004} 'Detrimental', {0x00000008} 'Magnitude %', {0x00000010} 'Self', {0x00000020} 'Touch', {0x00000040} 'Target', {0x00000080} 'No duration', {0x00000100} 'No magnitude', {0x00000200} 'No area', {0x00000400} 'FX persist', {0x00000800} 'Spellmaking', {0x00001000} 'Enchanting', {0x00002000} 'No Ingredient', {0x00004000} 'Unknown 14', {0x00008000} 'Unknown 15', {0x00010000} 'Use weapon', {0x00020000} 'Use armor', {0x00040000} 'Use creature', {0x00080000} 'Use skill', {0x00100000} 'Use attribute', {0x00200000} 'Unknown 21', {0x00400000} 'Unknown 22', {0x00800000} 'Unknown 23', {0x01000000} 'Use actor value', {0x02000000} 'Spray projectile type (or Fog if Bolt is specified as well)', {0x04000000} 'Bolt projectile type', {0x08000000} 'No hit effect', {0x10000000} 'Unknown 28', {0x20000000} 'Unknown 29', {0x40000000} 'Unknown 30', {0x80000000} 'Unknown 31' ])), wbFloat('Base cost'), wbUnion('Assoc. Item', wbMGEFFAssocItemDecider, [ wbFormIDCk('Unused', [NULL]), wbFormIDCk('Assoc. Weapon', [WEAP]), wbFormIDCk('Assoc. Armor', [ARMO, NULL{?}]), wbFormIDCk('Assoc. Creature', [CREA, LVLC, NPC_]), wbInteger('Assoc. Actor Value', itS32, wbActorValueEnum) ]), wbInteger('Magic School', itS32, wbMagicSchoolEnum), wbInteger('Resist value', itS32, wbActorValueEnum), wbInteger('Counter Effect Count', itU16), //!!! must be updated automatically when ESCE length changes! wbByteArray('Unused', 2), wbFormIDCk('Light', [LIGH, NULL]), wbFloat('Projectile speed'), wbFormIDCk('Effect Shader', [EFSH, NULL]), wbFormIDCk('Enchant effect', [EFSH, NULL]), wbFormIDCk('Casting sound', [NULL, SOUN]), wbFormIDCk('Bolt sound', [NULL, SOUN]), wbFormIDCk('Hit sound', [NULL, SOUN]), wbFormIDCk('Area sound', [NULL, SOUN]), wbFloat('Constant Effect enchantment factor'), wbFloat('Constant Effect barter factor') ], cpNormal, True, nil, 10), wbArrayS(ESCE, 'Counter Effects', wbStringMgefCode('Counter Effect Code', 4), 0, cpNormal, False, nil, wbCounterEffectsAfterSet) ], False, nil, cpNormal, False, wbMGEFAfterLoad, wbMGEFAfterSet); wbRecord(MISC, 'Misc. Item', [ wbEDID, wbFULL, wbMODL, wbICON, wbSCRI, wbStruct(DATA, '', [ wbUnion('', wbMISCActorValueDecider, [ wbInteger('Value', itS32), wbFormIDCk('Actor Value', [ACVA]) ]), wbUnion('', wbMISCActorValueDecider, [ wbFloat('Weight'), wbInteger('Group', itU32, wbEnum([], [ $40E00000, ' [NONE]', $40400000, 'AI', $00000000, 'Attribute', $40C00000, 'Combat', $40A00000, 'Misc', $40000000, 'Skill', $40800000, 'Social', $3F800000, 'Stat' ])) ]) ], cpNormal, True) ]); wbFaceGen := wbRStruct('FaceGen Data', [ wbByteArray(FGGS, 'FaceGen Geometry-Symmetric', 0, cpNormal, True), wbByteArray(FGGA, 'FaceGen Geometry-Asymmetric', 0, cpNormal, True), wbByteArray(FGTS, 'FaceGen Texture-Symmetric', 0, cpNormal, True) ], [], cpNormal, True); wbRecord(NPC_, 'Non-Player Character', [ wbEDID, wbFULL, wbMODL, wbStruct(ACBS, 'Configuration', [ wbInteger('Flags', itU32, wbFlags([ {0x000001} 'Female', {0x000002} 'Essential', {0x000004} '', {0x000008} 'Respawn', {0x000010} 'Auto-calc stats', {0x000020} '', {0x000040} '', {0x000080} 'PC Level Offset', {0x000100} '', {0x000200} 'No Low Level Processing', {0x000400} '', {0x000800} '', {0x001000} '', {0x002000} 'No Rumors', {0x004000} 'Summonable', {0x008000} 'No Persuasion', {0x010000} '', {0x020000} '', {0x040000} '', {0x080000} '', {0x100000} 'Can Corpse Check' ])), wbInteger('Base spell points', itU16), wbInteger('Fatigue', itU16), wbInteger('Barter gold', itU16), wbInteger('Level (offset)', itS16), wbInteger('Calc min', itU16), wbInteger('Calc max', itU16) ], cpNormal, True), wbRArrayS('Factions', wbStructSK(SNAM, [0], 'Faction', [ wbFormIDCk('Faction', [FACT]), wbInteger('Rank', itU8), wbByteArray('Unused', 3) ]) ), wbFormIDCk(INAM, 'Death item', [LVLI]), wbFormIDCk(RNAM, 'Race', [RACE], False, cpNormal, True), wbCNTOs, wbSPLOs, wbSCRI, wbStruct(AIDT, 'AI Data', [ wbInteger('Aggression', itU8), wbInteger('Confidence', itU8), wbInteger('Energy Level', itU8), wbInteger('Responsibility', itU8), wbInteger('Buys/Sells and Services', itU32, wbServiceFlags), wbInteger('Teaches', itS8, wbSkillEnum), wbInteger('Maximum training level', itU8), wbByteArray('Unused', 2) ], cpNormal, True), wbRArray('AI Packages', wbFormIDCk(PKID, 'AI Package', [PACK])), wbArrayS(KFFZ, 'Animations', wbString('Animation')), wbFormIDCk(CNAM, 'Class', [CLAS], False, cpNormal, True), wbStruct(DATA, 'Stats', [ wbInteger('Armorer', itU8), wbInteger('Athletics', itU8), wbInteger('Blade', itU8), wbInteger('Block', itU8), wbInteger('Blunt', itU8), wbInteger('Hand to Hand', itU8), wbInteger('Heavy Armor', itU8), wbInteger('Alchemy', itU8), wbInteger('Alteration', itU8), wbInteger('Conjuration', itU8), wbInteger('Destruction', itU8), wbInteger('Illusion', itU8), wbInteger('Mysticism', itU8), wbInteger('Restoration', itU8), wbInteger('Acrobatics', itU8), wbInteger('Light Armor', itU8), wbInteger('Marksman', itU8), wbInteger('Mercantile', itU8), wbInteger('Security', itU8), wbInteger('Sneak', itU8), wbInteger('Speechcraft', itU8), wbInteger('Health', itU16), wbByteArray('Unused', 2), wbInteger('Strength', itU8), wbInteger('Intelligence', itU8), wbInteger('Willpower', itU8), wbInteger('Agility', itU8), wbInteger('Speed', itU8), wbInteger('Endurance', itU8), wbInteger('Personality', itU8), wbInteger('Luck', itU8) ], cpNormal, True), wbFormIDCk(HNAM, 'Hair', [HAIR]), wbFloat(LNAM, 'Hair length'), wbArray(ENAM, 'Eyes', wbFormIDCk('Eyes', [EYES])), wbStruct(HCLR, 'Hair color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ], cpNormal, True), wbFormIDCk(ZNAM, 'Combat Style', [CSTY]), wbFaceGen, wbByteArray(FNAM, 'Unknown', 0, cpBenign) ], True); wbPKDTFlags := wbFlags([ {0x00000001} 'Offers services', {0x00000002} 'Must reach location', {0x00000004} 'Must complete', {0x00000008} 'Lock doors at package start', {0x00000010} 'Lock doors at package end', {0x00000020} 'Lock doors at location', {0x00000040} 'Unlock doors at package start', {0x00000080} 'Unlock doors at package end', {0x00000100} 'Unlock doors at location', {0x00000200} 'Continue if PC near', {0x00000400} 'Once per day', {0x00000800} 'Unused', {0x00001000} 'Skip fallout behavior', {0x00002000} 'Always run', {0x00004000} '', {0x00008000} '', {0x00010000} '', {0x00020000} 'Always sneak', {0x00040000} 'Allow swimming', {0x00080000} 'Allow falls', {0x00100000} 'Armor unequipped', {0x00200000} 'Weapons unequipped', {0x00400000} 'Defensive combat', {0x00800000} 'Use horse', {0x01000000} 'No idle anims', {0x02000000} '', {0x04000000} '', {0x08000000} '', {0x10000000} '', {0x20000000} '', {0x40000000} '', {0x80000000} '' ]); wbPKDTType := wbEnum([ {0} 'Find', {1} 'Follow', {2} 'Escort', {3} 'Eat', {4} 'Sleep', {5} 'Wander', {6} 'Travel', {7} 'Accompany', {8} 'Use item at', {9} 'Ambush', {10} 'Flee not combat', {11} 'Cast magic' ]); wbRecord(PACK, 'AI Package', [ wbEDID, wbUnion(PKDT, 'General', wbPACKPKDTDecider, [ wbStruct('General', [ wbInteger('Flags', itU16, wbPKDTFlags), wbInteger('Type', itU8, wbPKDTType), wbByteArray('Unused', 1) ]), wbStruct('General', [ wbInteger('Flags', itU32, wbPKDTFlags), wbInteger('Type', itU8, wbPKDTType), wbByteArray('Unused', 3) ]) ]), wbStruct(PLDT, 'Location', [ wbInteger('Type', itS32, wbEnum([ {0} 'Near reference', {1} 'In cell', {2} 'Near current location', {3} 'Near editor location', {4} 'Object ID', {5} 'Object type' ])), wbUnion('Location', wbPxDTLocationDecider, [ wbFormIDCk('Reference', [REFR, ACHR, ACRE, PLYR], True), wbFormIDCk('Cell', [CELL]), wbFormIDCk('Unused', [NULL]), wbFormIDCk('Unused', [NULL]), wbFormIDCk('Object ID', [ACTI, DOOR, FLOR, STAT, FURN, CREA, SPEL, NPC_, CONT, ARMO, AMMO, MISC, WEAP, INGR, SLGM, SGST, BOOK, KEYM, CLOT, ALCH, APPA, LIGH]), wbInteger('Object type', itU32) ]), wbInteger('Radius', itS32) ]), wbStruct(PSDT, 'Schedule', [ wbInteger('Month', itS8), wbInteger('Day of week', itS8, wbEnum([ 'Sundas', 'Morndas', 'Tirdas', 'Middas', 'Turdas', 'Fredas', 'Loredas', 'Morndas to Fredas', 'Loredas, Sundas', 'Morndas, Middas, Fredas', 'Tirdas, Turdas' ], [ -1, 'Any' ])), wbInteger('Date', itU8), wbInteger('Time', itS8), wbInteger('Duration', itS32) ]), wbStruct(PTDT, 'Target', [ wbInteger('Type', itS32, wbEnum([ {0} 'Specific reference', {1} 'Object ID', {2} 'Object type' ])), wbUnion('Target', wbPxDTLocationDecider, [ wbFormIDCk('Reference', [ACHR, ACRE, REFR, PLYR], True), wbFormIDCk('Object ID', [ACTI, DOOR, FLOR, STAT, FURN, CREA, SPEL, NPC_, CONT, ARMO, AMMO, MISC, WEAP, INGR, SLGM, SGST, BOOK, KEYM, CLOT, ALCH, APPA, LIGH]), wbInteger('Object type', itU32) ]), wbInteger('Count', itS32) ]), wbCTDAs ]); wbPGRP := wbArray(PGRP, 'Points', wbStruct('Point', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z (Even = Red/Orange, Odd = Blue)'), wbInteger('Connections', itU8{, wbPGRPConnectionsCallback}), wbByteArray('Unused', 3) ]), 0, nil, nil, cpNormal, True); {The Connection Count in the PGRP record specifies how many entries in this array belong to each point. If the first 4 points in the PGRP array have Connection Counts 2, 5, 2, 4 then the first 2 entries are the connections of point 0, then next 5 are the connections of point 1, the next 2 of point 2, the next 4 of point 3 and so on..., this can currently not be represented declaratively } wbRecord(PGRD, 'Path Grid', [ wbInteger(DATA, 'Point Count', itU16, nil, cpNormal, True), wbPGRP, wbByteArray(PGAG, 'Unknown'), wbArray(PGRR, 'Point-to-Point Connections', wbArrayS('Point', wbInteger('Point', itS16), wbCalcPGRRSize{, cpNormal, False, wbPGRRPointAfterLoad}) ), wbArrayS(PGRI, 'Inter-Cell Connections', wbStructSK([0,2,3,4], 'Inter-Cell Connection', [ wbInteger('Point', itU16), wbByteArray('Unused', 2), wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), 0, cpNormal, False, wbPGRIPointerAfterLoad), wbRArrayS('Point-to-Reference Mappings', wbStructSK(PGRL, [0], 'Point-to-Reference Mapping', [ wbFormIDCk('Reference', [REFR]), wbArrayS('Points', wbInteger('Point', itU32)) ]) ) ], False, nil, cpNormal, False, wbPGRDAfterLoad); wbRecord(QUST, 'Quest', [ wbEDID, wbSCRI, wbFULL, wbICON, wbStruct(DATA, 'General', [ wbInteger('Flags', itU8, wbFlags([ {0x01} 'Start game enabled', {0x02} '', {0x04} 'Allow repeated conversation topics', {0x08} 'Allow repeated stages' ])), wbInteger('Priority', itU8) ], cpNormal, True), wbCTDAs, wbRArrayS('Stages', wbRStructSK([0], 'Stage', [ wbInteger(INDX, 'Stage index', itS16), wbRArray('Log Entries', wbRStruct('Log Entry', [ wbInteger(QSDT, 'Stage Flags', itU8, wbFlags([ {0x01} 'Complete quest' ])), wbCTDAs, wbString(CNAM, 'Log Entry', 0, cpTranslate), wbResultScript ], [])) ], [])), wbRArray('Targets', wbRStruct('Target', [ wbStruct(QSTA, 'Target', [ wbFormIDCk('Target', [REFR, ACRE, ACHR], True), wbInteger('Flags', itU8, wbFlags([ {0x01} 'Compass marker ignores locks' ])), wbByteArray('Unused', 3) ]), wbCTDAs ], [])) ]); wbBodyDataIndex := wbInteger(INDX, 'Index', itU32, wbEnum([ 'Upper Body', 'Lower Body', 'Hand', 'Foot', 'Tail' ])); wbRecord(RACE, 'Race', [ wbEDID, wbFULL, wbDESC, wbSPLOs, wbXNAMs, wbStruct(DATA, '', [ wbArrayS('Skill Boosts', wbStructSK([0], 'Skill Boost', [ wbInteger('Skill', itS8, wbActorValueEnum), wbInteger('Boost', itS8) ]), 7), wbByteArray('Unused', 2), wbFloat('Male Height'), wbFloat('Female Height'), wbFloat('Male Weight'), wbFloat('Female Weight'), wbInteger('Flags', itU32, wbFlags([ 'Playable' ])) ], cpNormal, True), wbStruct(VNAM, 'Voice', [ wbFormIDCk('Male', [RACE, NULL]), wbFormIDCk('Female', [RACE, NULL]) ]), wbStruct(DNAM, 'Default Hair', [ wbFormIDCk('Male', [HAIR]), wbFormIDCk('Female', [HAIR]) ]), wbInteger(CNAM, 'Default Hair Color', itU8, nil, cpNormal, True), wbFloat(PNAM, 'FaceGen - Main clamp', cpNormal, True), wbFloat(UNAM, 'FaceGen - Face clamp', cpNormal, True), wbStruct(ATTR, 'Base Attributes', [ wbStruct('Male', [ wbInteger('Strength', itU8), wbInteger('Intelligence', itU8), wbInteger('Willpower', itU8), wbInteger('Agility', itU8), wbInteger('Speed', itU8), wbInteger('Endurance', itU8), wbInteger('Personality', itU8), wbInteger('Luck', itU8) ]), wbStruct('Female', [ wbInteger('Strength', itU8), wbInteger('Intelligence', itU8), wbInteger('Willpower', itU8), wbInteger('Agility', itU8), wbInteger('Speed', itU8), wbInteger('Endurance', itU8), wbInteger('Personality', itU8), wbInteger('Luck', itU8) ]) ]), wbRStruct('Face Data', [ wbEmpty(NAM0, 'Face Data Marker'), wbRArrayS('Parts', wbRStructSK([0], 'Part', [ wbInteger(INDX, 'Index', itU32, wbEnum([ 'Head', 'Ear (Male)', 'Ear (Female)', 'Mouth', 'Teeth (Lower)', 'Teeth (Upper)', 'Tongue', 'Eye (Left)', 'Eye (Right)' ])), wbMODL, wbICON ], [])) ], [], cpNormal, True), wbEmpty(NAM1, 'Body Data Marker', cpNormal, True), wbRStruct('Male Body Data', [ wbEmpty(MNAM, 'Male Body Data Marker'), wbMODL, wbRArrayS('Parts', wbRStructSK([0], 'Part', [ wbBodyDataIndex, wbICON ], [])) ], [], cpNormal, True), wbRStruct('Female Body Data', [ wbEmpty(FNAM, 'Female Body Data Marker'), wbMODL, wbRArrayS('Parts', wbRStructSK([0], 'Part', [ wbBodyDataIndex, wbICON ], [])) ], [], cpNormal, True), wbArrayS(HNAM, 'Hairs', wbFormIDCk('Hair', [HAIR]), 0, cpNormal, True), wbArrayS(ENAM, 'Eyes', wbFormIDCk('Eye', [EYES]), 0, cpNormal, True), wbFaceGen, wbByteArray(SNAM, 'Unknown', 2, cpNormal, True) ], True); wbRecord(REFR, 'Placed Object', [ wbEDID, wbFormIDCk(NAME, 'Base', [TREE, SBSP, LVLC, SOUN, ACTI, DOOR, FLOR, STAT, FURN, CONT, ARMO, AMMO, MISC, WEAP, INGR, SLGM, SGST, BOOK, KEYM, CLOT, ALCH, APPA, LIGH, GRAS], False, cpNormal, True), wbStruct(XTEL, 'Teleport Destination', [ wbFormIDCk('Door', [REFR], True), wbPosRot ]), wbStruct(XLOC, 'Lock information', [ wbInteger('Lock Level', itU8), wbByteArray('Unused', 3), wbFormIDCk('Key', [KEYM, NULL]), wbUnion('Unused', wbXLOCFillerDecider, [ wbEmpty('Unused'), wbByteArray('Unused', 4) ]), wbInteger('Flags', itU8, wbFlags(['', '', 'Leveled Lock'])), wbByteArray('Unused', 3) ]), wbRStruct('Ownership', [ wbXOWN, wbInteger(XRNK, 'Faction rank', itS32), wbXGLB ], [XLOC]), wbXESP, wbFormIDCk(XTRG, 'Target', [REFR, ACHR, ACRE], True), wbStruct(XSED, 'SpeedTree', [ wbInteger('Seed', itU8), wbUnion('Unused', wbREFRXSEDDecider, [ wbEmpty('Unused', cpIgnore), wbByteArray('Unused', 3, cpIgnore) ]) ]), wbXLOD, wbFloat(XCHG, 'Charge'), wbInteger(XHLT, 'Health', itS32), wbRStruct('Unused', [ wbFormIDCk(XPCI, 'Unused', [CELL]), wbString(FULL, 'Unused') ], []), wbInteger(XLCM, 'Level Modifier', itS32), wbFormIDCk(XRTM, 'Unknown', [REFR]), wbInteger(XACT, 'Action Flag', itU32, wbFlags([ 'Use Default', 'Activate', 'Open', 'Open by Default' ])), wbInteger(XCNT, 'Count', itS32), wbRStruct('Map Marker', [ wbEmpty(XMRK, 'Map Marker Data'), wbInteger(FNAM, 'Map Flags', itU8, wbFlags([ {0x01} 'Visible', {0x02} 'Can Travel To' ]), cpNormal, True), wbFULLReq, wbStruct(TNAM, '', [ wbInteger('Type', itU8, wbEnum([ {0x00} 'None', {0x01} 'Camp', {0x02} 'Cave', {0x03} 'City', {0x04} 'Elven Ruin', {0x05} 'Fort Ruin', {0x06} 'Mine', {0x07} 'Landmark', {0x08} 'Tavern', {0x09} 'Settlement', {0x0A} 'Daedric Shrine', {0x0B} 'Oblivion Gate', {0x0C} 'Unknown? (door icon)' ])), wbByteArray('Unused', 1) ], cpNormal, True) ], []), wbEmpty(ONAM, 'Open by Default'), wbXRGD, wbXSCL, wbInteger(XSOL, 'Contained Soul', itU8, wbSoulGemEnum), wbDATAPosRot ], True, wbPlacedAddInfo, cpNormal, False, wbREFRAfterLoad); wbRecord(REGN, 'Region', [ wbEDID, wbICON, wbStruct(RCLR, 'Map Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ], cpNormal, True), wbFormIDCk(WNAM, 'Worldspace', [WRLD]), wbRArray('Region Areas', wbRStruct('Region Area', [ wbInteger(RPLI, 'Edge Fall-off', itU32), wbArray(RPLD, 'Region Point List Data', wbStruct('Point', [ wbFloat('X'), wbFloat('Y') ]), 0, wbRPLDAfterLoad) ], []), cpNormal, True), wbRArrayS('Region Data Entries', wbRStructSK([0], 'Region Data Entry', [ {always starts with an RDAT} wbStructSK(RDAT, [0], 'Data Header', [ wbInteger('Type', itU32, wbEnum([ {0}'', {1}'', {2}'Objects', {3}'Weather', {4}'Map', {5}'Unknown 5', {6}'Grass', {7}'Sound', {8}'', {9}'' ])), wbInteger('Flags', itU8, wbFlags([ 'Override' ])), wbInteger('Priority', itU8), wbByteArray('Unused', 2) ], cpNormal, True, nil, 3), {followed by one of these: } {--- Objects ---} wbArray(RDOT, 'Objects', wbStruct('Object', [ wbFormIDCk('Object', [TREE, FLOR, STAT, LTEX]), wbInteger('Parent Index', itU16, wbHideFFFF), wbByteArray('Unused', 2), wbFloat('Density'), wbInteger('Clustering', itU8), wbInteger('Min Slope', itU8), wbInteger('Max Slope', itU8), wbInteger('Flags', itU8, wbFlags([ {0}'Conform to slope', {1}'Paint Vertices', {2}'Size Variance +/-', {3}'X +/-', {4}'Y +/-', {5}'Z +/-', {6}'Tree', {7}'Huge Rock' ])), wbInteger('Radius wrt Parent', itU16), wbInteger('Radius', itU16), wbFloat('Min Height'), wbFloat('Max Height'), wbFloat('Sink'), wbFloat('Sink Variance'), wbFloat('Size Variance'), wbStruct('Angle Variance', [ wbInteger('X', itU16), wbInteger('Y', itU16), wbInteger('Z', itU16) ]), wbByteArray('Unused', 2), wbByteArray('Unknown', 4) ])), {--- Map ---} wbString(RDMP, 'Map Name', 0, cpTranslate), {--- Grass ---} wbArrayS(RDGS, 'Grasses', wbStructSK([0], 'Grass', [ wbFormIDCk('Grass', [GRAS]), wbByteArray('Unused', 4) ])), {--- Sound ---} wbInteger(RDMD, 'Music Type', itU32, wbMusicEnum), wbArrayS(RDSD, 'Sounds', wbStructSK([0], 'Sound', [ wbFormIDCk('Sound', [SOUN]), wbInteger('Flags', itU32, wbFlags([ 'Pleasant', 'Cloudy', 'Rainy', 'Snowy' ])), wbInteger('Chance', itU32, wbScaledInt4ToStr, wbScaledInt4ToInt) ])), {--- Weather ---} wbArrayS(RDWT, 'Weather Types', wbStructSK([0], 'Weather Type', [ wbFormIDCk('Weather', [WTHR]), wbInteger('Chance', itU32) ])) ], [])) ], True); wbRecord(ROAD, 'Road', [ wbPGRP, wbArray(PGRR, 'Point-to-Point Connections (complex structure can''t be represented, see source)', {The Connection Count in the PGRP record specifies how many entries in this array belong to each point. If the first 4 points in the PGRP array have Connection Counts 2, 5, 2, 4 then the first 2 entries are the connections of point 0, then next 5 are the connections of point 1, the next 2 of point 2, the next 4 of point 3 and so on..., this can currently not be represented declaratively } wbStruct('Point', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), 0, nil, nil, cpNormal, True) ]); wbRecord(SBSP, 'Subspace', [ wbEDID, wbStruct(DNAM, '', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ], cpNormal, True) ]); wbSLSD := wbStructSK(SLSD, [0], 'Local Variable Data', [ wbInteger('Index', itU32), wbByteArray('Unused', 12), wbInteger('Flags', itU8, wbFlags(['IsLongOrShort']), cpCritical), wbByteArray('Unused') ]); wbRecord(SCPT, 'Script', [ wbEDID, wbByteArray(SCHD, 'Unknown (Script Header?)'), wbSCHR, wbByteArray(SCDA, 'Compiled Script'), wbStringScript(SCTX, 'Script Source', 0, cpNormal, True), wbRArrayS('Local Variables', wbRStructSK([0], 'Local Variable', [ wbSLSD, wbString(SCVR, 'Name', 0, cpCritical) ], [])), wbSCROs ]); wbRecord(SGST, 'Sigil Stone', [ wbEDID, wbStruct(OBME, 'Oblivion Magic Extender', [ wbInteger('Record Version', itU8), wbStruct('OBME Version', [ wbInteger('Beta', itU8), wbInteger('Minor', itU8), wbInteger('Major', itU8) ]), wbByteArray('Unused', $1C) ], cpNormal, False, wbOBMEDontShow), wbFULL, wbMODL, wbICON, wbSCRI, wbEffects, wbStruct(DATA, '', [ wbInteger('Uses ', itU8), wbInteger('Value', itU32), wbFloat('Weight') ], cpNormal, True) ]); wbRecord(SKIL, 'Skill', [ wbEDID, wbInteger(INDX, 'Skill', itS32, wbActorValueEnum, cpNormal, True), wbDESC, wbICON, wbStruct(DATA, 'Skill Data', [ wbInteger('Action', itS32, wbActorValueEnum), wbInteger('Attribute', itS32, wbActorValueEnum), wbInteger('Specialization', itU32, wbSpecializationEnum), wbArray('Use Values', wbFloat('Use Value'), 2) ], cpNormal, True), wbString(ANAM, 'Apprentice Text', 0, cpTranslate, True), wbString(JNAM, 'Journeyman Text', 0, cpTranslate, True), wbString(ENAM, 'Expert Text', 0, cpTranslate, True), wbString(MNAM, 'Master Text', 0, cpTranslate, True) ]); wbRecord(SLGM, 'Soul Gem', [ wbEDID, wbFULL, wbMODL, wbICON, wbSCRI, wbStruct(DATA, '', [ wbInteger('Value', itU32), wbFloat('Weight') ], cpNormal, True), wbInteger(SOUL, 'Contained Soul', itU8, wbSoulGemEnum, cpNormal, True), wbInteger(SLCP, 'Maximum Capacity', itU8, wbSoulGemEnum, cpNormal, True) ]); wbRecord(SOUN, 'Sound', [ wbEDID, wbString(FNAM, 'Sound Filename'), wbRUnion('Sound Data', [ wbStruct(SNDX, 'Sound Data', [ wbInteger('Minimum attenuation distance', itU8, wbMul(5)), wbInteger('Maximum attenuation distance', itU8, wbMul(100)), wbInteger('Frequency adjustment %', itS8), wbByteArray('Unused', 1), wbInteger('Flags', itU16, wbFlags([ {0x0001} 'Random Frequency Shift', {0x0002} 'Play At Random', {0x0004} 'Environment Ignored', {0x0008} 'Random Location', {0x0010} 'Loop', {0x0020} 'Menu Sound', {0x0040} '2D', {0x0080} '360 LFE' ])), wbByteArray('Unused', 2), wbInteger('Static Attenuation (db)', itU16, wbDiv(100)), wbInteger('Stop time', itU8), wbInteger('Start time', itU8) ], cpNormal, True), wbStruct(SNDD, 'Sound Data', [ wbInteger('Minimum attenuation distance', itU8, wbMul(5)), wbInteger('Maximum attenuation distance', itU8, wbMul(100)), wbInteger('Frequency adjustment %', itS8), wbByteArray('Unused', 1), wbInteger('Flags', itU16, wbFlags([ {0x0001} 'Random Frequency Shift', {0x0002} 'Play At Random', {0x0004} 'Environment Ignored', {0x0008} 'Random Location', {0x0010} 'Loop', {0x0020} 'Menu Sound', {0x0040} '2D', {0x0080} '360 LFE' ])), wbByteArray('Unused', 2), wbEmpty('Unused'), wbEmpty('Unused'), wbEmpty('Unused') ], cpNormal, True) ], [], cpNormal, True) ]); wbRecord(SPEL, 'Spell', [ wbEDID, wbStruct(OBME, 'Oblivion Magic Extender', [ wbInteger('Record Version', itU8), wbStruct('OBME Version', [ wbInteger('Beta', itU8), wbInteger('Minor', itU8), wbInteger('Major', itU8) ]), wbByteArray('Unused', $1C) ], cpNormal, False, wbOBMEDontShow), wbFULL, wbStruct(SPIT, '', [ wbInteger('Type', itU32, wbEnum([ {0} 'Spell', {1} 'Disease', {2} 'Power', {3} 'Lesser Power', {4} 'Ability', {5} 'Poison' ])), wbInteger('Cost', itU32), wbInteger('Level', itU32, wbEnum([ {0} 'Novice', {1} 'Apprentice', {2} 'Journeyman', {3} 'Expert', {4} 'Master' ])), wbInteger('Flags', itU8, wbFlags([ {0x00000001} 'Manual Spell Cost', {0x00000002} 'Immune to Silence 1', {0x00000004} 'Player Start Spell', {0x00000008} 'Immune to Silence 2', {0x00000010} 'Area Effect Ignores LOS', {0x00000020} 'Script Effect Always Applies', {0x00000040} 'Disallow Spell Absorb/Reflect', {0x00000080} 'Touch Spell Explodes w/ no Target' ])), wbByteArray('Unused', 3) ], cpNormal, True), wbEffects ]); wbRecord(STAT, 'Static', [ wbEDID, wbMODL ]); wbRecord(TES4, 'Main File Header', [ wbStruct(HEDR, 'Header', [ wbFloat('Version'), wbInteger('Number of Records', itU32), wbInteger('Next Object ID', itU32) ], cpNormal, True), wbByteArray(OFST, 'Unknown', 0, cpIgnore), wbByteArray(DELE, 'Unknown', 0, cpIgnore), wbString(CNAM, 'Author', 0, cpTranslate, True), wbString(SNAM, 'Description', 0, cpTranslate), wbRArray('Master Files', wbRStruct('Master File', [ wbString(MAST, 'Filename', 0, cpNormal, True), wbByteArray(DATA, 'Unused', 8, cpIgnore, True) ], [])) ], False, nil, cpNormal, True, wbRemoveOFST); wbRecord(TREE, 'Tree', [ wbEDID, wbMODL, wbICON, wbArrayS(SNAM, 'SpeedTree Seeds', wbInteger('SpeedTree Seed', itU32)), wbStruct(CNAM, 'Tree Data', [ wbFloat('Leaf Curvature'), wbFloat('Minimum Leaf Angle'), wbFloat('Maximum Leaf Angle'), wbFloat('Branch Dimming Value'), wbFloat('Leaf Dimming Value'), wbInteger('Shadow Radius', itS32), wbFloat('Rock Speed'), wbFloat('Rustle Speed') ], cpNormal, True), wbStruct(BNAM, 'Billboard Dimensions', [ wbFloat('Width'), wbFloat('Height') ], cpNormal, True) ]); wbRecord(WATR, 'Water', [ wbEDID, wbString(TNAM, 'Texture', 0, cpNormal, True), wbInteger(ANAM, 'Opacity', itU8, nil, cpNormal, True), wbInteger(FNAM, 'Flags', itU8, wbFlags([ {0}'Causes Damage', {1}'Reflective' ]), cpNormal, True), wbString(MNAM, 'Material ID'{>>>}, 0, cpNormal, True{<<<}), wbFormIDCk(SNAM, 'Sound', [SOUN]), wbStruct(DATA, '', [ wbFloat('Wind Velocity'), wbFloat('Wind Direction'), wbFloat('Wave Amplitude'), wbFloat('Wave Frequency'), wbFloat('Sun Power'), wbFloat('Reflectivity Amount'), wbFloat('Fresnel Amount'), wbFloat('Scroll X Speed'), wbFloat('Scroll Y Speed'), wbFloat('Fog Distance - Near Plane'), wbFloat('Fog Distance - Far Plane'), wbStruct('Shallow Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Deep Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbStruct('Reflection Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), wbInteger('Texture Blend', itU8), wbByteArray('Unused', 3), wbFloat('Rain Simulator - Force'), wbFloat('Rain Simulator - Velocity'), wbFloat('Rain Simulator - Falloff'), wbFloat('Rain Simulator - Dampner'), wbFloat('Rain Simulator - Starting Size'), wbFloat('Displacement Simulator - Force'), wbFloat('Displacement Simulator - Velocity'), wbFloat('Displacement Simulator - Falloff'), wbFloat('Displacement Simulator - Dampner'), wbFloat('Displacement Simulator - Starting Size'), wbInteger('Damage', itU16) ], cpNormal, True, nil, 0), wbStruct(GNAM, 'Related Waters', [ wbFormIDCk('Daytime', [WATR, NULL]), wbFormIDCk('Nighttime', [WATR, NULL]), wbFormIDCk('Underwater', [WATR, NULL]) ], cpNormal{>>>, True<<<}) ]); wbRecord(WEAP, 'Weapon', [ wbEDID, wbFULL, wbMODL, wbICON, wbSCRI, wbENAM, wbInteger(ANAM, 'Enchantment Points', itU16), wbStruct(DATA, '', [ wbInteger('Type', itU32, wbEnum([ {0} 'Blade One Hand', {1} 'Blade Two Hand', {2} 'Blunt One Hand', {3} 'Blunt Two Hand', {4} 'Staff', {5} 'Bow' ])), wbFloat('Speed'), wbFloat('Reach'), wbInteger('Flags', itU32, wbFlags(['Ignores Normal Weapon Resistance'])), wbInteger('Value', itU32), wbInteger('Health', itU32), wbFloat('Weight'), wbInteger('Damage', itU16) ], cpNormal, True) ]); if wbSimpleRecords then wbRecord(WRLD, 'Worldspace', [ wbEDID, wbFULL, wbRStruct('Parent', [ wbFormIDCk(WNAM, 'Worldspace', [WRLD]) ], []), wbFormIDCk(CNAM, 'Climate', [CLMT]), wbFormIDCk(NAM2, 'Water', [WATR]), wbICON, wbStruct(MNAM, 'Map Data', [ wbStruct('Usable Dimensions', [ wbInteger('X', itS32), wbInteger('Y', itS32) ]), wbStruct('Cell Coordinates', [ wbStruct('NW Cell', [ wbInteger('X', itS16), wbInteger('Y', itS16) ]), wbStruct('SE Cell', [ wbInteger('X', itS16), wbInteger('Y', itS16) ]) ]) ]), wbInteger(DATA, 'Flags', itU8, wbFlags([ {0x01} 'Small world', {0x02} 'Can''t fast travel', {0x04} 'Oblivion worldspace', {0x08} '', {0x10} 'No LOD water' ]), cpNormal, True), //wbArray(NAM0, 'Unknown', wbFloat(''), 0, nil, nil, cpNormal, True), //wbArray(NAM9, 'Unknown', wbFloat(''), 0, nil, nil, cpNormal, True), wbRStruct('Object Bounds', [ wbStruct(NAM0, 'Min', [ wbFloat('X', cpNormal, False, 1/4096), wbFloat('Y', cpNormal, False, 1/4096) ], cpIgnore, True), wbStruct(NAM9, 'Max', [ wbFloat('X', cpNormal, False, 1/4096), wbFloat('Y', cpNormal, False, 1/4096) ], cpIgnore, True) ], []), wbInteger(SNAM, 'Music', itU32, wbMusicEnum), wbByteArray(OFST, 'Offset Data') ], False, nil, cpNormal, False, wbRemoveOFST) else wbRecord(WRLD, 'Worldspace', [ wbEDID, wbFULL, wbRStruct('Parent', [ wbFormIDCk(WNAM, 'Worldspace', [WRLD]) ], []), wbFormIDCk(CNAM, 'Climate', [CLMT]), wbFormIDCk(NAM2, 'Water', [WATR]), wbICON, wbStruct(MNAM, 'Map Data', [ wbStruct('Usable Dimensions', [ wbInteger('X', itS32), wbInteger('Y', itS32) ]), wbStruct('Cell Coordinates', [ wbStruct('NW Cell', [ wbInteger('X', itS16), wbInteger('Y', itS16) ]), wbStruct('SE Cell', [ wbInteger('X', itS16), wbInteger('Y', itS16) ]) ]) ]), wbInteger(DATA, 'Flags', itU8, wbFlags([ {0x01} 'Small world', {0x02} 'Can''t fast travel', {0x04} 'Oblivion worldspace', {0x08} '', {0x10} 'No LOD water' ]), cpNormal, True), //wbArray(NAM0, 'Unknown', wbFloat(''), 0, nil, nil, cpNormal, True), //wbArray(NAM9, 'Unknown', wbFloat(''), 0, nil, nil, cpNormal, True), wbRStruct('Object Bounds', [ wbStruct(NAM0, 'Min', [ wbFloat('X', cpNormal, False, 1/4096), wbFloat('Y', cpNormal, False, 1/4096) ], cpIgnore, True), wbStruct(NAM9, 'Max', [ wbFloat('X', cpNormal, False, 1/4096), wbFloat('Y', cpNormal, False, 1/4096) ], cpIgnore, True) ], []), wbInteger(SNAM, 'Music', itU32, wbMusicEnum), wbArray(OFST, 'Offset Data', wbArray('Rows', wbInteger('Offset', itU32), wbOffsetDataColsCounter), 0) ], False, nil, cpNormal, False, wbRemoveOFST); wbRecord(WTHR, 'Weather', [ wbEDID, wbString(CNAM, 'Texture Lower Layer'), wbString(DNAM, 'Texture Upper Layer'), wbMODL, wbArray(NAM0, 'Colors by Types/Times', wbArray('Type', wbStruct('Time', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]), ['Sunrise', 'Day', 'Sunset', 'Night'] ), ['Sky-Upper','Fog','Clouds-Lower','Ambient','Sunlight','Sun','Stars','Sky-Lower','Horizon','Clouds-Upper'] , cpNormal, True), wbStruct(FNAM, 'Fog Distance', [ wbFloat('Day Near'), wbFloat('Day Far'), wbFloat('Night Near'), wbFloat('Night Far') ], cpNormal, True), wbStruct(HNAM, 'HDR Data', [ wbFloat('Eye Adapt Speed'), wbFloat('Blur Radius'), wbFloat('Blur Passes'), wbFloat('Emissive Mult'), wbFloat('Target LUM'), wbFloat('Upper LUM Clamp'), wbFloat('Bright Scale'), wbFloat('Bright Clamp'), wbFloat('LUM Ramp No Tex'), wbFloat('LUM Ramp Min'), wbFloat('LUM Ramp Max'), wbFloat('Sunlight Dimmer'), wbFloat('Grass Dimmer'), wbFloat('Tree Dimmer') ], cpNormal, True), wbStruct(DATA, '', [ wbInteger('Wind Speed', itU8), wbInteger('Cloud Speed (Lower)', itU8), wbInteger('Cloud Speed (Upper)', itU8), wbInteger('Trans Delta', itU8), wbInteger('Sun Glare', itU8), wbInteger('Sun Damage', itU8), wbInteger('Precipitation - Begin Fade In', itU8), wbInteger('Precipitation - End Fade Out', itU8), wbInteger('Thunder/Lightning - Begin Fade In', itU8), wbInteger('Thunder/Lightning - End Fade Out', itU8), wbInteger('Thunder/Lightning - Frequency', itU8), wbInteger('Weather Classification', itU8, wbWthrDataClassification), wbStruct('Lightning Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8) ]) ], cpNormal, True), wbRArray('Sounds', wbStruct(SNAM, 'Sound', [ wbFormIDCk('Sound', [SOUN]), wbInteger('Type', itU32, wbEnum([ {0}'Default', {1}'Precip', {2}'Wind', {3}'Thunder' ])) ])) ]); wbAddGroupOrder(GMST); wbAddGroupOrder(GLOB); wbAddGroupOrder(CLAS); wbAddGroupOrder(FACT); wbAddGroupOrder(HAIR); wbAddGroupOrder(EYES); wbAddGroupOrder(RACE); wbAddGroupOrder(SOUN); wbAddGroupOrder(SKIL); wbAddGroupOrder(MGEF); wbAddGroupOrder(SCPT); wbAddGroupOrder(LTEX); wbAddGroupOrder(ENCH); wbAddGroupOrder(SPEL); wbAddGroupOrder(BSGN); wbAddGroupOrder(ACTI); wbAddGroupOrder(APPA); wbAddGroupOrder(ARMO); wbAddGroupOrder(BOOK); wbAddGroupOrder(CLOT); wbAddGroupOrder(CONT); wbAddGroupOrder(DOOR); wbAddGroupOrder(INGR); wbAddGroupOrder(LIGH); wbAddGroupOrder(MISC); wbAddGroupOrder(STAT); wbAddGroupOrder(GRAS); wbAddGroupOrder(TREE); wbAddGroupOrder(FLOR); wbAddGroupOrder(FURN); wbAddGroupOrder(WEAP); wbAddGroupOrder(AMMO); wbAddGroupOrder(NPC_); wbAddGroupOrder(CREA); wbAddGroupOrder(LVLC); wbAddGroupOrder(SLGM); wbAddGroupOrder(KEYM); wbAddGroupOrder(ALCH); wbAddGroupOrder(SBSP); wbAddGroupOrder(SGST); wbAddGroupOrder(LVLI); wbAddGroupOrder(WTHR); wbAddGroupOrder(CLMT); wbAddGroupOrder(REGN); wbAddGroupOrder(CELL); wbAddGroupOrder(WRLD); wbAddGroupOrder(DIAL); wbAddGroupOrder(QUST); wbAddGroupOrder(IDLE); wbAddGroupOrder(PACK); wbAddGroupOrder(CSTY); wbAddGroupOrder(LSCR); wbAddGroupOrder(LVSP); wbAddGroupOrder(ANIO); wbAddGroupOrder(WATR); wbAddGroupOrder(EFSH); end; initialization end. ================================================ FILE: lib/xedit/wbDefinitionsTES5.pas ================================================ {******************************************************************************* The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. *******************************************************************************} unit wbDefinitionsTES5; {$I wbDefines.inc} interface uses wbInterface; var wbBipedObjectFlags: IwbFlagsDef; wbEquipType: IwbFlagsDef; wbFurnitureEntryTypeFlags: IwbFlagsDef; wbPKDTFlags: IwbFlagsDef; wbPKDTInterruptFlags: IwbFlagsDef; wbSMNodeFlags: IwbFlagsDef; wbAdvanceActionEnum: IwbEnumDef; wbAlignmentEnum: IwbEnumDef; wbArmorTypeEnum: IwbEnumDef; wbAttackAnimationEnum: IwbEnumDef; wbAxisEnum: IwbEnumDef; wbBipedObjectEnum: IwbEnumDef; wbBlendModeEnum: IwbEnumDef; wbBlendOpEnum: IwbEnumDef; wbBodyPartIndexEnum: IwbEnumDef; wbCastEnum: IwbEnumDef; wbCastingSourceEnum: IwbEnumDef; wbCrimeTypeEnum: IwbEnumDef; wbCriticalStageEnum: IwbEnumDef; wbEmotionTypeEnum: IwbEnumDef; wbEntryPointsEnum: IwbEnumDef; wbEventFunctionEnum: IwbEnumDef; wbEventMemberEnum: IwbEnumDef; wbFormTypeEnum: IwbEnumDef; wbFunctionsEnum: IwbEnumDef; wbFurnitureAnimTypeEnum: IwbEnumDef; wbLocationEnum: IwbEnumDef; wbMiscStatEnum: IwbEnumDef; wbMusicEnum: IwbEnumDef; wbObjectTypeEnum: IwbEnumDef; wbPropTypeEnum: IwbEnumDef; wbQuadrantEnum: IwbEnumDef; wbSexEnum: IwbEnumDef; wbSkillEnum: IwbEnumDef; wbSoulGemEnum: IwbEnumDef; wbSoundLevelEnum: IwbEnumDef; wbTargetEnum: IwbEnumDef; wbTintMaskTypeEnum: IwbEnumDef; wbVatsValueFunctionEnum: IwbEnumDef; wbWardStateEnum: IwbEnumDef; wbWeaponAnimTypeEnum: IwbEnumDef; wbZTestFuncEnum: IwbEnumDef; procedure DefineTES5; implementation uses Types, Classes, SysUtils, Math, Variants, wbHelpers; const _00_IAD: TwbSignature = #$00'IAD'; _01_IAD: TwbSignature = #$01'IAD'; _02_IAD: TwbSignature = #$02'IAD'; _03_IAD: TwbSignature = #$03'IAD'; _04_IAD: TwbSignature = #$04'IAD'; _05_IAD: TwbSignature = #$05'IAD'; _06_IAD: TwbSignature = #$06'IAD'; _07_IAD: TwbSignature = #$07'IAD'; _08_IAD: TwbSignature = #$08'IAD'; _09_IAD: TwbSignature = #$09'IAD'; _0A_IAD: TwbSignature = #$0A'IAD'; _0B_IAD: TwbSignature = #$0B'IAD'; _0C_IAD: TwbSignature = #$0C'IAD'; _0D_IAD: TwbSignature = #$0D'IAD'; _0E_IAD: TwbSignature = #$0E'IAD'; _0F_IAD: TwbSignature = #$0F'IAD'; _10_IAD: TwbSignature = #$10'IAD'; _11_IAD: TwbSignature = #$11'IAD'; _12_IAD: TwbSignature = #$12'IAD'; _13_IAD: TwbSignature = #$13'IAD'; _14_IAD: TwbSignature = #$14'IAD'; _40_IAD: TwbSignature = #$40'IAD'; _41_IAD: TwbSignature = #$41'IAD'; _42_IAD: TwbSignature = #$42'IAD'; _43_IAD: TwbSignature = #$43'IAD'; _44_IAD: TwbSignature = #$44'IAD'; _45_IAD: TwbSignature = #$45'IAD'; _46_IAD: TwbSignature = #$46'IAD'; _47_IAD: TwbSignature = #$47'IAD'; _48_IAD: TwbSignature = #$48'IAD'; _49_IAD: TwbSignature = #$49'IAD'; _4A_IAD: TwbSignature = #$4A'IAD'; _4B_IAD: TwbSignature = #$4B'IAD'; _4C_IAD: TwbSignature = #$4C'IAD'; _4D_IAD: TwbSignature = #$4D'IAD'; _4E_IAD: TwbSignature = #$4E'IAD'; _4F_IAD: TwbSignature = #$4F'IAD'; _50_IAD: TwbSignature = #$50'IAD'; _51_IAD: TwbSignature = #$51'IAD'; _52_IAD: TwbSignature = #$52'IAD'; _53_IAD: TwbSignature = #$53'IAD'; _54_IAD: TwbSignature = #$54'IAD'; {00TX} _00_0TX: TwbSignature = #$30'0TX'; {10TX} _10_0TX: TwbSignature = #$31'0TX'; {20TX} _20_0TX: TwbSignature = #$32'0TX'; {30TX} _30_0TX: TwbSignature = #$33'0TX'; {40TX} _40_0TX: TwbSignature = #$34'0TX'; {50TX} _50_0TX: TwbSignature = #$35'0TX'; {60TX} _60_0TX: TwbSignature = #$36'0TX'; {70TX} _70_0TX: TwbSignature = #$37'0TX'; {80TX} _80_0TX: TwbSignature = #$38'0TX'; {90TX} _90_0TX: TwbSignature = #$39'0TX'; {:0TX} _3A_0TX: TwbSignature = #$3A'0TX'; {;0TX} _3B_0TX: TwbSignature = #$3B'0TX'; {<0TX} _3C_0TX: TwbSignature = #$3C'0TX'; {=0TX} _3D_0TX: TwbSignature = #$3D'0TX'; {>0TX} _3E_0TX: TwbSignature = #$3E'0TX'; {?0TX} _3F_0TX: TwbSignature = #$3F'0TX'; {@0TX} _40h_0TX: TwbSignature = #$40'0TX'; {A0TX} A0TX: TwbSignature = 'A0TX'; {B0TX} B0TX: TwbSignature = 'B0TX'; {C0TX} C0TX: TwbSignature = 'C0TX'; {D0TX} D0TX: TwbSignature = 'D0TX'; {E0TX} E0TX: TwbSignature = 'E0TX'; {F0TX} F0TX: TwbSignature = 'F0TX'; {G0TX} G0TX: TwbSignature = 'G0TX'; {H0TX} H0TX: TwbSignature = 'H0TX'; {I0TX} I0TX: TwbSignature = 'I0TX'; {J0TX} J0TX: TwbSignature = 'J0TX'; {K0TX} K0TX: TwbSignature = 'K0TX'; {L0TX} L0TX: TwbSignature = 'L0TX'; AACT : TwbSignature = 'AACT'; ACBS : TwbSignature = 'ACBS'; ACEC : TwbSignature = 'ACEC'; { New To Dawnguard } ACEP : TwbSignature = 'ACEP'; { New To Dawnguard } ACHR : TwbSignature = 'ACHR'; ACID : TwbSignature = 'ACID'; { New To Dawnguard } ACPR : TwbSignature = 'ACPR'; { New To Skyrim } ACSR : TwbSignature = 'ACSR'; { New To Dawnguard } ACTI : TwbSignature = 'ACTI'; ACUN : TwbSignature = 'ACUN'; { New To Dawnguard } ADDN : TwbSignature = 'ADDN'; AHCF : TwbSignature = 'AHCF'; { New To Skyrim } AHCM : TwbSignature = 'AHCM'; { New To Skyrim } AIDT : TwbSignature = 'AIDT'; ALCA : TwbSignature = 'ALCA'; { New To Skyrim } ALCH : TwbSignature = 'ALCH'; ALCL : TwbSignature = 'ALCL'; { New To Skyrim } ALCO : TwbSignature = 'ALCO'; { New To Skyrim } ALDN : TwbSignature = 'ALDN'; { New To Skyrim } ALEA : TwbSignature = 'ALEA'; { New To Skyrim } ALED : TwbSignature = 'ALED'; { New To Skyrim } ALEQ : TwbSignature = 'ALEQ'; { New To Skyrim } ALFA : TwbSignature = 'ALFA'; { New To Skyrim } ALFC : TwbSignature = 'ALFC'; { New To Skyrim } ALFD : TwbSignature = 'ALFD'; { New To Skyrim } ALFE : TwbSignature = 'ALFE'; { New To Skyrim } ALFI : TwbSignature = 'ALFI'; { New To Skyrim } ALFL : TwbSignature = 'ALFL'; { New To Skyrim } ALFR : TwbSignature = 'ALFR'; { New To Skyrim } ALID : TwbSignature = 'ALID'; { New To Skyrim } ALLS : TwbSignature = 'ALLS'; { New To Skyrim } ALNA : TwbSignature = 'ALNA'; { New To Skyrim } ALNT : TwbSignature = 'ALNT'; { New To Skyrim } ALPC : TwbSignature = 'ALPC'; { New To Skyrim } ALRT : TwbSignature = 'ALRT'; { New To Skyrim } ALSP : TwbSignature = 'ALSP'; { New To Skyrim } ALST : TwbSignature = 'ALST'; { New To Skyrim } ALUA : TwbSignature = 'ALUA'; { New To Skyrim } AMMO : TwbSignature = 'AMMO'; ANAM : TwbSignature = 'ANAM'; ANIO : TwbSignature = 'ANIO'; APPA : TwbSignature = 'APPA'; ARMA : TwbSignature = 'ARMA'; ARMO : TwbSignature = 'ARMO'; ARTO : TwbSignature = 'ARTO'; ASPC : TwbSignature = 'ASPC'; ASTP : TwbSignature = 'ASTP'; ATKD : TwbSignature = 'ATKD'; { New to Skyrim } ATKE : TwbSignature = 'ATKE'; { New to Skyrim } ATKR : TwbSignature = 'ATKR'; { New to Skyrim } ATXT : TwbSignature = 'ATXT'; AVIF : TwbSignature = 'AVIF'; AVSK : TwbSignature = 'AVSK'; { New to Skyrim } BAMT : TwbSignature = 'BAMT'; { New to Skyrim } BIDS : TwbSignature = 'BIDS'; { New to Skyrim } BIPL : TwbSignature = 'BIPL'; BMCT : TwbSignature = 'BMCT'; BNAM : TwbSignature = 'BNAM'; BOD2 : TwbSignature = 'BOD2'; { New to Skyrim 1.6.91 CK} BODT : TwbSignature = 'BODT'; { New to Skyrim } BOOK : TwbSignature = 'BOOK'; BPND : TwbSignature = 'BPND'; BPNI : TwbSignature = 'BPNI'; BPNN : TwbSignature = 'BPNN'; BPNT : TwbSignature = 'BPNT'; BPTD : TwbSignature = 'BPTD'; BPTN : TwbSignature = 'BPTN'; BTXT : TwbSignature = 'BTXT'; CAMS : TwbSignature = 'CAMS'; CELL : TwbSignature = 'CELL'; CIS1 : TwbSignature = 'CIS1'; { New to Skyrim } CIS2 : TwbSignature = 'CIS2'; { New to Skyrim } CITC : TwbSignature = 'CITC'; { New to Skyrim } CLAS : TwbSignature = 'CLAS'; CLDC : TwbSignature = 'CLDC'; { New to Skyrim, but unused } CLFM : TwbSignature = 'CLFM'; CLMT : TwbSignature = 'CLMT'; CNAM : TwbSignature = 'CNAM'; CNTO : TwbSignature = 'CNTO'; COBJ : TwbSignature = 'COBJ'; COCT : TwbSignature = 'COCT'; { New to Skyrim 'Count'} COED : TwbSignature = 'COED'; COLL : TwbSignature = 'COLL'; CONT : TwbSignature = 'CONT'; CPTH : TwbSignature = 'CPTH'; CRDT : TwbSignature = 'CRDT'; CRGR : TwbSignature = 'CRGR'; { New to Skyrim } CRIF : TwbSignature = 'CRIF'; { New to Skyrim } CRVA : TwbSignature = 'CRVA'; { New to Skyrim } CSCR : TwbSignature = 'CSCR'; CSDC : TwbSignature = 'CSDC'; CSDI : TwbSignature = 'CSDI'; CSDT : TwbSignature = 'CSDT'; CSFL : TwbSignature = 'CSFL'; { New to Skyrim } CSGD : TwbSignature = 'CSGD'; { New to Skyrim } CSLR : TwbSignature = 'CSLR'; { New to Skyrim } CSMD : TwbSignature = 'CSMD'; { New to Skyrim } CSME : TwbSignature = 'CSME'; { New to Skyrim } CSTY : TwbSignature = 'CSTY'; CTDA : TwbSignature = 'CTDA'; DALC : TwbSignature = 'DALC'; { New to Skyrim } DATA : TwbSignature = 'DATA'; DEBR : TwbSignature = 'DEBR'; DELE : TwbSignature = 'DELE'; DEMO : TwbSignature = 'DEMO'; { New to Skyrim } DESC : TwbSignature = 'DESC'; DEST : TwbSignature = 'DEST'; DEVA : TwbSignature = 'DEVA'; { New to Skyrim } DFTF : TwbSignature = 'DFTF'; { New To Skyrim } DFTM : TwbSignature = 'DFTM'; { New To Skyrim } DIAL : TwbSignature = 'DIAL'; DLBR : TwbSignature = 'DLBR'; DLVW : TwbSignature = 'DLVW'; DMAX : TwbSignature = 'DMAX'; { New to Skyrim } DMDL : TwbSignature = 'DMDL'; DMDS : TwbSignature = 'DMDS'; { New to Skyrim } DMDT : TwbSignature = 'DMDT'; DMIN : TwbSignature = 'DMIN'; { New to Skyrim } DNAM : TwbSignature = 'DNAM'; DOBJ : TwbSignature = 'DOBJ'; DODT : TwbSignature = 'DODT'; DOFT : TwbSignature = 'DOFT'; { New to Skyrim } DOOR : TwbSignature = 'DOOR'; DPLT : TwbSignature = 'DPLT'; { New to Skyrim } DSTD : TwbSignature = 'DSTD'; DSTF : TwbSignature = 'DSTF'; DUAL : TwbSignature = 'DUAL'; EAMT : TwbSignature = 'EAMT'; ECOR : TwbSignature = 'ECOR'; { New to Skyrim } ECZN : TwbSignature = 'ECZN'; EDID : TwbSignature = 'EDID'; EFID : TwbSignature = 'EFID'; EFIT : TwbSignature = 'EFIT'; EFSH : TwbSignature = 'EFSH'; EITM : TwbSignature = 'EITM'; ENAM : TwbSignature = 'ENAM'; ENCH : TwbSignature = 'ENCH'; ENIT : TwbSignature = 'ENIT'; EPF2 : TwbSignature = 'EPF2'; EPF3 : TwbSignature = 'EPF3'; EPFD : TwbSignature = 'EPFD'; EPFT : TwbSignature = 'EPFT'; EQUP : TwbSignature = 'EQUP'; ESCE : TwbSignature = 'ESCE'; ETYP : TwbSignature = 'ETYP'; EXPL : TwbSignature = 'EXPL'; EYES : TwbSignature = 'EYES'; FACT : TwbSignature = 'FACT'; FCHT : TwbSignature = 'FCHT'; { New to Skyrim } FLMV : TwbSignature = 'FLMV'; { New to Skyrim } FLOR : TwbSignature = 'FLOR'; FLST : TwbSignature = 'FLST'; FLTR : TwbSignature = 'FLTR'; { New to Skyrim } FLTV : TwbSignature = 'FLTV'; FNAM : TwbSignature = 'FNAM'; FNMK : TwbSignature = 'FNMK'; { New to Skyrim } FNPR : TwbSignature = 'FNPR'; { New to Skyrim } FPRT : TwbSignature = 'FPRT'; { New to Skyrim } FSTP : TwbSignature = 'FSTP'; FSTS : TwbSignature = 'FSTS'; FTSF : TwbSignature = 'FTSF'; { New to Skyrim } FTSM : TwbSignature = 'FTSM'; { New to Skyrim } FTST : TwbSignature = 'FTST'; { New to Skyrim } FULL : TwbSignature = 'FULL'; FURN : TwbSignature = 'FURN'; GLOB : TwbSignature = 'GLOB'; GMST : TwbSignature = 'GMST'; GNAM : TwbSignature = 'GNAM'; GRAS : TwbSignature = 'GRAS'; GWOR : TwbSignature = 'GWOR'; { New to Skyrim } HAIR : TwbSignature = 'HAIR'; { Unused in Skyrim, but contained in Skyrim.esm } HAZD : TwbSignature = 'HAZD'; HCLF : TwbSignature = 'HCLF'; { New to Skyrim } HDPT : TwbSignature = 'HDPT'; HEAD : TwbSignature = 'HEAD'; { New to Skyrim } HEDR : TwbSignature = 'HEDR'; HNAM : TwbSignature = 'HNAM'; HTID : TwbSignature = 'HTID'; { New to Skyrim } ICO2 : TwbSignature = 'ICO2'; ICON : TwbSignature = 'ICON'; IDLA : TwbSignature = 'IDLA'; IDLB : TwbSignature = 'IDLB'; IDLC : TwbSignature = 'IDLC'; IDLE : TwbSignature = 'IDLE'; IDLF : TwbSignature = 'IDLF'; IDLM : TwbSignature = 'IDLM'; IDLT : TwbSignature = 'IDLT'; IMAD : TwbSignature = 'IMAD'; IMGS : TwbSignature = 'IMGS'; IMSP : TwbSignature = 'IMSP'; { New to Skyrim } INAM : TwbSignature = 'INAM'; INCC : TwbSignature = 'INCC'; { New to Skyrim } INDX : TwbSignature = 'INDX'; INFO : TwbSignature = 'INFO'; INGR : TwbSignature = 'INGR'; INTV : TwbSignature = 'INTV'; IPCT : TwbSignature = 'IPCT'; IPDS : TwbSignature = 'IPDS'; ITXT : TwbSignature = 'ITXT'; JAIL : TwbSignature = 'JAIL'; { New To Skyrim } JNAM : TwbSignature = 'JNAM'; JOUT : TwbSignature = 'JOUT'; { New To Skyrim } KEYM : TwbSignature = 'KEYM'; KNAM : TwbSignature = 'KNAM'; KSIZ : TwbSignature = 'KSIZ'; KWDA : TwbSignature = 'KWDA'; KYWD : TwbSignature = 'KYWD'; LAND : TwbSignature = 'LAND'; LCEC : TwbSignature = 'LCEC'; { New to Skyrim } LCEP : TwbSignature = 'LCEP'; { New to Skyrim } LCID : TwbSignature = 'LCID'; { New to Skyrim } LCPR : TwbSignature = 'LCPR'; { New to Skyrim } LCRT : TwbSignature = 'LCRT'; LCSR : TwbSignature = 'LCSR'; { New to Skyrim } LCTN : TwbSignature = 'LCTN'; LCUN : TwbSignature = 'LCUN'; { New to Skyrim } LENS : TwbSignature = 'LENS'; { New to SSE } LFSD : TwbSignature = 'LFSD'; { New to SSE } LFSP : TwbSignature = 'LFSP'; { New to SSE } LGTM : TwbSignature = 'LGTM'; LIGH : TwbSignature = 'LIGH'; LLCT : TwbSignature = 'LLCT'; {New to Skyrim, part of LVLI 'Count'} LNAM : TwbSignature = 'LNAM'; LSCR : TwbSignature = 'LSCR'; LTEX : TwbSignature = 'LTEX'; LTMP : TwbSignature = 'LTMP'; LVLC : TwbSignature = 'LVLC'; LVLD : TwbSignature = 'LVLD'; LVLF : TwbSignature = 'LVLF'; LVLG : TwbSignature = 'LVLG'; LVLI : TwbSignature = 'LVLI'; LVLN : TwbSignature = 'LVLN'; LVLO : TwbSignature = 'LVLO'; LVSP : TwbSignature = 'LVSP'; MAST : TwbSignature = 'MAST'; MATO : TwbSignature = 'MATO'; MATT : TwbSignature = 'MATT'; MCHT : TwbSignature = 'MCHT'; { New to Skyrim } MDOB : TwbSignature = 'MDOB'; MESG : TwbSignature = 'MESG'; MGEF : TwbSignature = 'MGEF'; MHDT : TwbSignature = 'MHDT'; { New to Skyrim } MIC2 : TwbSignature = 'MIC2'; MICO : TwbSignature = 'MICO'; MISC : TwbSignature = 'MISC'; MNAM : TwbSignature = 'MNAM'; MO2S : TwbSignature = 'MO2S'; MO2T : TwbSignature = 'MO2T'; MO3S : TwbSignature = 'MO3S'; MO3T : TwbSignature = 'MO3T'; MO4S : TwbSignature = 'MO4S'; MO4T : TwbSignature = 'MO4T'; MO5S : TwbSignature = 'MO5S'; { New to Skyrim } MO5T : TwbSignature = 'MO5T'; { New to Skyrim } MOD2 : TwbSignature = 'MOD2'; MOD3 : TwbSignature = 'MOD3'; MOD4 : TwbSignature = 'MOD4'; MOD5 : TwbSignature = 'MOD5'; { New to Skyrim } MODD : TwbSignature = 'MODD'; MODL : TwbSignature = 'MODL'; MODS : TwbSignature = 'MODS'; MODT : TwbSignature = 'MODT'; MOVT : TwbSignature = 'MOVT'; MPAI : TwbSignature = 'MPAI'; { New To Skyrim } MPAV : TwbSignature = 'MPAV'; { New To Skyrim } MPRT : TwbSignature = 'MPRT'; { New to Skyrim } MSTT : TwbSignature = 'MSTT'; MTNM : TwbSignature = 'MTNM'; { New to Skyrim } MTYP : TwbSignature = 'MTYP'; { New To Skyrim } MUSC : TwbSignature = 'MUSC'; MUST : TwbSignature = 'MUST'; NAM0 : TwbSignature = 'NAM0'; NAM1 : TwbSignature = 'NAM1'; NAM2 : TwbSignature = 'NAM2'; NAM3 : TwbSignature = 'NAM3'; NAM4 : TwbSignature = 'NAM4'; NAM5 : TwbSignature = 'NAM5'; NAM6 : TwbSignature = 'NAM6'; NAM7 : TwbSignature = 'NAM7'; NAM8 : TwbSignature = 'NAM8'; NAM9 : TwbSignature = 'NAM9'; NAMA : TwbSignature = 'NAMA'; { New to Skyrim } NAME : TwbSignature = 'NAME'; NAVI : TwbSignature = 'NAVI'; NAVM : TwbSignature = 'NAVM'; NEXT : TwbSignature = 'NEXT'; NNAM : TwbSignature = 'NNAM'; NPC_ : TwbSignature = 'NPC_'; NULL : TwbSignature = 'NULL'; NVER : TwbSignature = 'NVER'; NVMI : TwbSignature = 'NVMI'; NVNM : TwbSignature = 'NVNM'; { New to Skyrim } NVPP : TwbSignature = 'NVPP'; { New to Skyrim } NVSI : TwbSignature = 'NVSI'; { New to Dawnguard } OBND : TwbSignature = 'OBND'; OCOR : TwbSignature = 'OCOR'; { New to Skyrim } OFST : TwbSignature = 'OFST'; ONAM : TwbSignature = 'ONAM'; OTFT : TwbSignature = 'OTFT'; PACK : TwbSignature = 'PACK'; PARW : TwbSignature = 'PARW'; { New to Skyrim } PBAR : TwbSignature = 'PBAR'; { New to Skyrim } PBEA : TwbSignature = 'PBEA'; { New to Skyrim } PCON : TwbSignature = 'PCON'; { New to Skyrim } PDTO : TwbSignature = 'PDTO'; { New to Skyrim } PERK : TwbSignature = 'PERK'; PFIG : TwbSignature = 'PFIG'; PFLA : TwbSignature = 'PFLA'; { New to Skyrim } PFO2 : TwbSignature = 'PFO2'; { New to Skyrim } PFOR : TwbSignature = 'PFOR'; { New to Skyrim } PFPC : TwbSignature = 'PFPC'; PGRE : TwbSignature = 'PGRE'; PHTN : TwbSignature = 'PHTN'; { New to Skyrim } PHWT : TwbSignature = 'PHWT'; { New to Skyrim } PHZD : TwbSignature = 'PHZD'; PKC2 : TwbSignature = 'PKC2'; { New to Skyrim } PKCU : TwbSignature = 'PKCU'; { New to Skyrim } PKDT : TwbSignature = 'PKDT'; PKID : TwbSignature = 'PKID'; PLCN : TwbSignature = 'PLCN'; { New to Skyrim } PLDT : TwbSignature = 'PLDT'; PLVD : TwbSignature = 'PLVD'; { New to Skyrim } PLYR : TwbSignature = 'PLYR'; PMIS : TwbSignature = 'PMIS'; PNAM : TwbSignature = 'PNAM'; POBA : TwbSignature = 'POBA'; POCA : TwbSignature = 'POCA'; POEA : TwbSignature = 'POEA'; PRCB : TwbSignature = 'PRCB'; { New to Skyrim } PRKC : TwbSignature = 'PRKC'; PRKE : TwbSignature = 'PRKE'; PRKF : TwbSignature = 'PRKF'; PRKR : TwbSignature = 'PRKR'; { New to Skyrim } PRKZ : TwbSignature = 'PRKZ'; { New to Skyrim } PROJ : TwbSignature = 'PROJ'; PSDT : TwbSignature = 'PSDT'; PTDA : TwbSignature = 'PTDA'; { New to Skyrim } PWAT : TwbSignature = 'PWAT'; { Unused in Skyrim, but contained in Skyrim.esm } QNAM : TwbSignature = 'QNAM'; QOBJ : TwbSignature = 'QOBJ'; QSDT : TwbSignature = 'QSDT'; QSTA : TwbSignature = 'QSTA'; QTGL : TwbSignature = 'QTGL'; { New To Skyrim } QUAL : TwbSignature = 'QUAL'; { New To Skyrim } QUST : TwbSignature = 'QUST'; RACE : TwbSignature = 'RACE'; RCEC : TwbSignature = 'RCEC'; { New To Skyrim } RCLR : TwbSignature = 'RCLR'; RCPR : TwbSignature = 'RCPR'; { New to Dawnguard } RCSR : TwbSignature = 'RCSR'; { New To Skyrim } RCUN : TwbSignature = 'RCUN'; { New To Skyrim } RDAT : TwbSignature = 'RDAT'; RDGS : TwbSignature = 'RDGS'; RDMO : TwbSignature = 'RDMO'; RDMP : TwbSignature = 'RDMP'; RDOT : TwbSignature = 'RDOT'; RDSA : TwbSignature = 'RDSA'; { New to Skyrim } RDWT : TwbSignature = 'RDWT'; REFR : TwbSignature = 'REFR'; REGN : TwbSignature = 'REGN'; RELA : TwbSignature = 'RELA'; REPL : TwbSignature = 'REPL'; RGDL : TwbSignature = 'RGDL';{ Unused in Skyrim, but contained in Skyrim.esm } REVB : TwbSignature = 'REVB'; RFCT : TwbSignature = 'RFCT'; RNAM : TwbSignature = 'RNAM'; RNMV : TwbSignature = 'RNMV'; { New to Skyrim } RPLD : TwbSignature = 'RPLD'; RPLI : TwbSignature = 'RPLI'; RPRF : TwbSignature = 'RPRF'; { New To Skyrim } RPRM : TwbSignature = 'RPRM'; { New To Skyrim } SCDA : TwbSignature = 'SCDA'; SCEN : TwbSignature = 'SCEN'; SCHR : TwbSignature = 'SCHR'; SCOL : TwbSignature = 'SCOL'; { Unused in Skyrim, but contained in Skyrim.esm } SCPT : TwbSignature = 'SCPT'; { Unused in Skyrim, but contained in Skyrim.esm } SCRL : TwbSignature = 'SCRL'; SCRN : TwbSignature = 'SCRN'; SCRO : TwbSignature = 'SCRO'; SCTX : TwbSignature = 'SCTX'; SDSC : TwbSignature = 'SDSC'; { New to Skyrim } SHOU : TwbSignature = 'SHOU'; SHRT : TwbSignature = 'SHRT'; { New to Skyrim } SLCP : TwbSignature = 'SLCP'; SLGM : TwbSignature = 'SLGM'; SMBN : TwbSignature = 'SMBN'; SMEN : TwbSignature = 'SMEN'; SMQN : TwbSignature = 'SMQN'; SNAM : TwbSignature = 'SNAM'; SNCT : TwbSignature = 'SNCT'; SNDD : TwbSignature = 'SNDD'; SNDR : TwbSignature = 'SNDR'; SNMV : TwbSignature = 'SNMV'; { New to Skyrim } SOFT : TwbSignature = 'SOFT'; { New to Skyrim } SOPM : TwbSignature = 'SOPM'; SOUL : TwbSignature = 'SOUL'; SOUN : TwbSignature = 'SOUN'; SPCT : TwbSignature = 'SPCT'; { New to Skyrim } SPED : TwbSignature = 'SPED'; { New To Skyrim } SPEL : TwbSignature = 'SPEL'; SPGD : TwbSignature = 'SPGD'; SPIT : TwbSignature = 'SPIT'; SPLO : TwbSignature = 'SPLO'; SPMV : TwbSignature = 'SPMV'; { New To Skyrim } SPOR : TwbSignature = 'SPOR'; { New to Skyrim } STAT : TwbSignature = 'STAT'; STOL : TwbSignature = 'STOL'; { New to Skyrim } SWMV : TwbSignature = 'SWMV'; { New to Skyrim } TACT : TwbSignature = 'TACT'; TCLT : TwbSignature = 'TCLT'; TES4 : TwbSignature = 'TES4'; TIAS : TwbSignature = 'TIAS'; { New to Skyrim } TIFC : TwbSignature = 'TIFC'; { New To Skyrim } TINC : TwbSignature = 'TINC'; { New to Skyrim } TIND : TwbSignature = 'TIND'; { New to Skyrim } TINI : TwbSignature = 'TINI'; { New to Skyrim } TINL : TwbSignature = 'TINL'; { New to Skyrim } TINP : TwbSignature = 'TINP'; { New to Skyrim } TINT : TwbSignature = 'TINT'; { New to Skyrim } TINV : TwbSignature = 'TINV'; { New to Skyrim } TIRS : TwbSignature = 'TIRS'; { New to Skyrim } TNAM : TwbSignature = 'TNAM'; TPIC : TwbSignature = 'TPIC'; TPLT : TwbSignature = 'TPLT'; TRDT : TwbSignature = 'TRDT'; TREE : TwbSignature = 'TREE'; TVDT : TwbSignature = 'TVDT'; { New To Skyrim } TWAT : TwbSignature = 'TWAT'; { New To Skyrim } TX00 : TwbSignature = 'TX00'; TX01 : TwbSignature = 'TX01'; TX02 : TwbSignature = 'TX02'; TX03 : TwbSignature = 'TX03'; TX04 : TwbSignature = 'TX04'; TX05 : TwbSignature = 'TX05'; TX06 : TwbSignature = 'TX06'; { New To Skyrim } TX07 : TwbSignature = 'TX07'; { New To Skyrim } TXST : TwbSignature = 'TXST'; UNAM : TwbSignature = 'UNAM'; UNES : TwbSignature = 'UNES'; { New To Skyrim } VATS : TwbSignature = 'VATS'; VCLR : TwbSignature = 'VCLR'; VENC : TwbSignature = 'VENC'; { New To Skyrim } VEND : TwbSignature = 'VEND'; { New To Skyrim } VENV : TwbSignature = 'VENV'; { New To Skyrim } VHGT : TwbSignature = 'VHGT'; VMAD : TwbSignature = 'VMAD'; VNAM : TwbSignature = 'VNAM'; VNML : TwbSignature = 'VNML'; VOLI : TwbSignature = 'VOLI'; { New To SSE } VTCK : TwbSignature = 'VTCK'; VTEX : TwbSignature = 'VTEX'; VTXT : TwbSignature = 'VTXT'; VTYP : TwbSignature = 'VTYP'; WAIT : TwbSignature = 'WAIT'; { New To Skyrim } WATR : TwbSignature = 'WATR'; WBDT : TwbSignature = 'WBDT'; { New to Skyrim } WCTR : TwbSignature = 'WCTR'; { New To Skyrim } WEAP : TwbSignature = 'WEAP'; WKMV : TwbSignature = 'WKMV'; { New to Skyrim } WLST : TwbSignature = 'WLST'; WNAM : TwbSignature = 'WNAM'; WOOP : TwbSignature = 'WOOP'; WRLD : TwbSignature = 'WRLD'; WTHR : TwbSignature = 'WTHR'; XACT : TwbSignature = 'XACT'; XALP : TwbSignature = 'XALP'; { New To Skyrim } XAPD : TwbSignature = 'XAPD'; XAPR : TwbSignature = 'XAPR'; XATR : TwbSignature = 'XATR'; { New To Dawnguard } XCAS : TwbSignature = 'XCAS'; XCCM : TwbSignature = 'XCCM'; XCHG : TwbSignature = 'XCHG'; XCIM : TwbSignature = 'XCIM'; XCLC : TwbSignature = 'XCLC'; XCLL : TwbSignature = 'XCLL'; XCLP : TwbSignature = 'XCLP'; XCLR : TwbSignature = 'XCLR'; XCLW : TwbSignature = 'XCLW'; XCMO : TwbSignature = 'XCMO'; XCNT : TwbSignature = 'XCNT'; XCVL : TwbSignature = 'XCVL'; { New To Skyrim } XCWT : TwbSignature = 'XCWT'; XCZA : TwbSignature = 'XCZA'; { New To Skyrim } XCZC : TwbSignature = 'XCZC'; { New To Skyrim } XCZR : TwbSignature = 'XCZR'; { New To Skyrim } XDCR : TwbSignature = 'XDCR'; XEMI : TwbSignature = 'XEMI'; XESP : TwbSignature = 'XESP'; XEZN : TwbSignature = 'XEZN'; XFVC : TwbSignature = 'XFVC'; { New To Skyrim } XGLB : TwbSignature = 'XGLB'; XHLP : TwbSignature = 'XHLP'; XHOR : TwbSignature = 'XHOR'; { New To Skyrim } XHTW : TwbSignature = 'XHTW'; { New To Skyrim } XIBS : TwbSignature = 'XIBS'; XILL : TwbSignature = 'XILL'; { New To Skyrim } XIS2 : TwbSignature = 'XIS2'; { New To Skyrim } XLCM : TwbSignature = 'XLCM'; XLCN : TwbSignature = 'XLCN'; { New To Skyrim } XLIB : TwbSignature = 'XLIB'; { New To Skyrim } XLIG : TwbSignature = 'XLIG'; { New To Skyrim } XLKR : TwbSignature = 'XLKR'; XLOC : TwbSignature = 'XLOC'; XLOD : TwbSignature = 'XLOD'; XLRL : TwbSignature = 'XLRL'; { New To Skyrim } XLRM : TwbSignature = 'XLRM'; XLRT : TwbSignature = 'XLRT'; { New To Skyrim } XLTW : TwbSignature = 'XLTW'; XMBO : TwbSignature = 'XMBO'; XMBP : TwbSignature = 'XMBP'; XMBR : TwbSignature = 'XMBR'; XMRC : TwbSignature = 'XMRC'; XMRK : TwbSignature = 'XMRK'; XNAM : TwbSignature = 'XNAM'; XNDP : TwbSignature = 'XNDP'; XOCP : TwbSignature = 'XOCP'; XORD : TwbSignature = 'XORD'; XOWN : TwbSignature = 'XOWN'; XPOD : TwbSignature = 'XPOD'; XPPA : TwbSignature = 'XPPA'; XPRD : TwbSignature = 'XPRD'; XPRM : TwbSignature = 'XPRM'; XPTL : TwbSignature = 'XPTL'; XPWR : TwbSignature = 'XPWR'; XRDS : TwbSignature = 'XRDS'; XRGB : TwbSignature = 'XRGB'; XRGD : TwbSignature = 'XRGD'; XRMR : TwbSignature = 'XRMR'; XRNK : TwbSignature = 'XRNK'; XSCL : TwbSignature = 'XSCL'; XSPC : TwbSignature = 'XSPC'; { New To Skyrim } XTEL : TwbSignature = 'XTEL'; XTNM : TwbSignature = 'XTNM'; { New To Skyrim } XTRI : TwbSignature = 'XTRI'; XWEM : TwbSignature = 'XWEM'; { New To Skyrim } XWCN : TwbSignature = 'XWCN'; { New To Skyrim } XWCS : TwbSignature = 'XWCS'; { New To Skyrim } XWCU : TwbSignature = 'XWCU'; { New To Skyrim } XXXX : TwbSignature = 'XXXX'; YNAM : TwbSignature = 'YNAM'; ZNAM : TwbSignature = 'ZNAM'; var wbPKDTSpecificFlagsUnused : Boolean; wbEDID: IwbSubRecordDef; wbCOED: IwbSubRecordDef; wbXLCM: IwbSubRecordDef; wbEITM: IwbSubRecordDef; wbOBND: IwbSubRecordDef; wbOBNDReq: IwbSubRecordDef; wbDEST: IwbSubRecordStructDef; wbDESTActor: IwbSubRecordStructDef; wbDODT: IwbSubRecordDef; wbXGLB: IwbSubRecordDef; wbXRGD: IwbSubRecordDef; wbXRGB: IwbSubRecordDef; wbSPLO: IwbSubRecordDef; wbSPLOs: IwbSubRecordArrayDef; wbCNTO: IwbSubRecordStructDef; wbCNTOs: IwbSubRecordArrayDef; wbAIDT: IwbSubRecordDef; wbCSDT: IwbSubRecordStructDef; wbCSDTs: IwbSubRecordArrayDef; wbFULL: IwbSubRecordDef; wbFULLActor: IwbSubRecordDef; wbFULLReq: IwbSubRecordDef; wbDESC: IwbSubRecordDef; wbDESCReq: IwbSubRecordDef; wbXSCL: IwbSubRecordDef; wbDATAPosRot: IwbSubRecordDef; wbPosRot: IwbStructDef; wbMODD: IwbSubRecordDef; wbMODL: IwbSubRecordStructDef; wbMODS: IwbSubRecordDef; wbMO2S: IwbSubRecordDef; wbMO3S: IwbSubRecordDef; wbMO4S: IwbSubRecordDef; wbMODLActor: IwbSubRecordStructDef; wbMODLReq: IwbSubRecordStructDef; wbCTDA: IwbSubRecordStructDef; wbCTDAs: IwbSubRecordArrayDef; wbCTDAsReq: IwbSubRecordArrayDef; wbCTDAsCount: IwbSubRecordArrayDef; wbCTDAsReqCount: IwbSubRecordArrayDef; wbXLOD: IwbSubRecordDef; wbXESP: IwbSubRecordDef; wbICON: IwbSubRecordStructDef; wbICONReq: IwbSubRecordStructDef; wbICO2: IwbSubRecordStructDef; wbActorValue: IwbIntegerDef; wbETYP: IwbSubRecordDef; wbETYPReq: IwbSubRecordDef; wbEFID: IwbSubRecordDef; wbEFIT: IwbSubRecordDef; wbEffectsReq: IwbSubRecordArrayDef; wbFirstPersonFlagsU32: IwbIntegerDef; wbBODT: IwbSubRecordDef; wbBOD2: IwbSubRecordDef; wbBODTBOD2: IwbSubRecordUnionDef; wbScriptEntry: IwbStructDef; wbScriptFlags: IwbIntegerDef; wbScriptPropertyObject: IwbUnionDef; wbScriptProperties: IwbArrayDef; wbScriptFragments: IwbStructDef; wbScriptFragmentsQuest: IwbStructDef; wbScriptFragmentsInfo: IwbStructDef; wbScriptFragmentsPack: IwbStructDef; wbScriptFragmentsScen: IwbStructDef; wbPLDT: IwbSubRecordDef; wbPLVD: IwbSubRecordDef; wbTargetData: IwbStructDef; wbAttackData: IwbSubRecordStructDef; wbLLCT: IwbSubRecordDef; wbLVLD: IwbSubRecordDef; wbVMAD: IwbSubRecordDef; wbVMADFragmentedPERK: IwbSubRecordDef; wbVMADFragmentedPACK: IwbSubRecordDef; wbVMADFragmentedQUST: IwbSubRecordDef; wbVMADFragmentedSCEN: IwbSubRecordDef; wbVMADFragmentedINFO: IwbSubRecordDef; wbCOCT: IwbSubRecordDef; wbKSIZ: IwbSubRecordDef; wbKWDAs: IwbSubRecordDef; wbReqKWDAs: IwbSubRecordDef; wbKeywords: IwbSubRecordStructDef; wbCNAM: IwbSubRecordDef; wbCNAMReq: IwbSubRecordDef; wbCITC: IwbSubRecordDef; wbMGEFData: IwbSubRecordStructDef; wbMGEFType: IwbIntegerDef; wbMDOB: IwbSubRecordDef; wbSPIT: IwbSubRecordDef; wbDMDSs: IwbSubRecordDef; wbMO5S: IwbSubRecordDef; wbSPCT: IwbSubRecordDef; wbTints: IwbSubRecordArrayDef; wbMODT: IwbSubRecordDef; wbDMDT: IwbSubRecordDef; wbOwnership: IwbSubRecordStructDef; wbRACE_DATAFlags01: IwbIntegerDef; wbPhonemeTargets: IwbSubRecordDef; wbNoseMorphFlags: IwbIntegerDef; wbBrowMorphFlags: IwbIntegerDef; wbEyesMorphFlags01: IwbIntegerDef; wbEyesMorphFlags02: IwbIntegerDef; wbLipMorphFlags: IwbIntegerDef; wbPHWT: IwbSubRecordStructDef; wbMorphs: IwbSubRecordStructDef; wbHeadPart: IwbSubRecordStructDef; wbQUSTAliasFlags: IwbSubRecordDef; wbPDTO: IwbSubRecordDef; wbPDTOs: IwbSubRecordArrayDef; wbUNAMs: IwbSubRecordArrayDef; wbNull: IwbValueDef; wbTimeInterpolator: IwbStructDef; wbColorInterpolator: IwbStructDef; wbYNAM: IwbSubRecordDef; wbZNAM: IwbSubRecordDef; wbMaxHeightDataCELL: IwbSubRecordDef; wbMaxHeightDataWRLD: IwbSubRecordDef; wbTVDT: IwbSubRecordDef; wbOFST: IwbSubRecordDef; wbNVNM: IwbSubRecordDef; wbNAVIslandData: IwbStructDef; function IsSSE: Boolean; inline; overload; begin Result := wbGameMode = gmSSE; end; function IsSSE(const aDef1, aDef2: String): String; inline; overload; begin if IsSSE then Result := aDef1 else Result := aDef2; end; function IsSSE(const aDef1, aDef2: IwbSubRecordDef): IwbSubRecordDef; inline; overload; begin if IsSSE then Result := aDef1 else Result := aDef2; end; function Sig2Int(aSignature: TwbSignature): Cardinal; inline; begin Result := PCardinal(@aSignature)^; end; function wbEPFDActorValueToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var AsCardinal : Cardinal; AsFloat : Single; begin AsCardinal := aInt; AsFloat := PSingle(@AsCardinal)^; aInt := Round(AsFloat); case aType of ctToStr: Result := wbActorValueEnum.ToString(aInt, aElement); ctToSortKey: Result := wbActorValueEnum.ToSortKey(aInt, aElement); ctCheck: Result := wbActorValueEnum.Check(aInt, aElement); ctToEditValue: Result := wbActorValueEnum.ToEditValue(aInt, aElement); ctEditType: Result := 'ComboBox'; ctEditInfo: Result := wbActorValueEnum.EditInfo[aInt, aElement]; end; end; function wbEPFDActorValueToInt(const aString: string; const aElement: IwbElement): Int64; var AsCardinal : Cardinal; AsFloat : Single; begin AsFloat := wbActorValueEnum.FromEditValue(aString, aElement); PSingle(@AsCardinal)^ := AsFloat; Result := AsCardinal; end; function wbCTDAParam2QuestStageToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainerElementRef; Param1 : IwbElement; MainRecord : IwbMainRecord; EditInfos : TStringList; Stages : IwbContainerElementRef; Stage : IwbContainerElementRef; i, j : Integer; s, t : string; begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctToEditValue: Result := IntToStr(aInt); ctToSortKey: begin Result := IntToHex64(aInt, 8); Exit; end; ctCheck: Result := ''; ctEditType: Result := ''; ctEditInfo: Result := ''; end; if not Assigned(aElement) then Exit; Container := GetContainerRefFromUnionOrValue(aElement); if not Assigned(Container) then Exit; Param1 := Container.ElementByName['Parameter #1']; if not Assigned(Param1) then Exit; if not Supports(Param1.LinksTo, IwbMainRecord, MainRecord) then Exit; MainRecord := MainRecord.WinningOverride; if MainRecord.Signature <> QUST then begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end; Exit; end; case aType of ctEditType: begin Result := 'ComboBox'; Exit; end; ctEditInfo: EditInfos := TStringList.Create; else EditInfos := nil; end; try if Supports(MainRecord.ElementByName['Stages'], IwbContainerElementRef, Stages) then begin for i := 0 to Pred(Stages.ElementCount) do if Supports(Stages.Elements[i], IwbContainerElementRef, Stage) then begin j := Stage.ElementNativeValues['INDX\Stage Index']; s := Trim(Stage.ElementValues['Log Entries\Log Entry\CNAM']); t := IntToStr(j); while Length(t) < 3 do t := '0' + t; if s <> '' then t := t + ' ' + s; if Assigned(EditInfos) then EditInfos.AddObject(t, TObject(j)) else if j = aInt then begin case aType of ctToStr, ctToEditValue: Result := t; ctCheck: Result := ''; end; Exit; end; end; end; case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; ctEditInfo: begin EditInfos.Sort; Result := EditInfos.CommaText; end; end; finally FreeAndNil(EditInfos); end; end; function wbPerkDATAQuestStageToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainerElementRef; Param1 : IwbElement; MainRecord : IwbMainRecord; EditInfos : TStringList; Stages : IwbContainerElementRef; Stage : IwbContainerElementRef; i, j : Integer; s, t : string; begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctToEditValue: Result := IntToStr(aInt); ctToSortKey: begin Result := IntToHex64(aInt, 8); Exit; end; ctCheck: Result := ''; ctEditType: Result := ''; ctEditInfo: Result := ''; end; if not Assigned(aElement) then Exit; Container := GetContainerRefFromUnionOrValue(aElement); if not Assigned(Container) then Exit; Param1 := Container.ElementByName['Quest']; if not Assigned(Param1) then Exit; if not Supports(Param1.LinksTo, IwbMainRecord, MainRecord) then Exit; MainRecord := MainRecord.WinningOverride; if MainRecord.Signature <> QUST then begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end; Exit; end; case aType of ctEditType: begin Result := 'ComboBox'; Exit; end; ctEditInfo: EditInfos := TStringList.Create; else EditInfos := nil; end; try if Supports(MainRecord.ElementByName['Stages'], IwbContainerElementRef, Stages) then begin for i := 0 to Pred(Stages.ElementCount) do if Supports(Stages.Elements[i], IwbContainerElementRef, Stage) then begin j := Stage.ElementNativeValues['INDX\Stage Index']; s := Trim(Stage.ElementValues['Log Entries\Log Entry\CNAM']); t := IntToStr(j); while Length(t) < 3 do t := '0' + t; if s <> '' then t := t + ' ' + s; if Assigned(EditInfos) then EditInfos.AddObject(t, TObject(j)) else if j = aInt then begin case aType of ctToStr, ctToEditValue: Result := t; ctCheck: Result := ''; end; Exit; end; end; end; case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; ctEditInfo: begin EditInfos.Sort; Result := EditInfos.CommaText; end; end; finally FreeAndNil(EditInfos); end; end; function wbCTDAParam2QuestStageToInt(const aString: string; const aElement: IwbElement): Int64; var i : Integer; s : string; begin i := 1; s := Trim(aString); while (i <= Length(s)) and (s[i] in ['0'..'9']) do Inc(i); s := Copy(s, 1, Pred(i)); Result := StrToInt(s); end; function wbREFRNavmeshTriangleToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainerElementRef; Navmesh : IwbElement; MainRecord : IwbMainRecord; Triangles : IwbContainerElementRef; begin case aType of ctToStr: Result := IntToStr(aInt); ctToEditValue: Result := IntToStr(aInt); ctToSortKey: begin Result := IntToHex64(aInt, 8); Exit; end; ctCheck: Result := ''; ctEditType: Result := ''; ctEditInfo: Result := ''; end; if not Assigned(aElement) then Exit; Container := GetContainerRefFromUnionOrValue(aElement); if not Assigned(Container) then Exit; Navmesh := Container.Elements[0]; if not Assigned(Navmesh) then Exit; if not Supports(Navmesh.LinksTo, IwbMainRecord, MainRecord) then Exit; MainRecord := MainRecord.WinningOverride; if MainRecord.Signature <> NAVM then begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end; Exit; end; if Supports(MainRecord.ElementByPath['NVNM\Triangles'], IwbContainerElementRef, Triangles) and (aType = ctCheck) then if aInt >= Triangles.ElementCount then Result := ''; end; function wbStringToInt(const aString: string; const aElement: IwbElement): Int64; begin Result := StrToIntDef(aString, 0); end; { Alias to string conversion, requires quest reference or quest record specific to record that references alias } function wbAliasToStr(aInt: Int64; const aQuestRef: IwbElement; aType: TwbCallbackType): string; var MainRecord : IwbMainRecord; EditInfos : TStringList; Aliases : IwbContainerElementRef; Alias : IwbContainerElementRef; i, j : Integer; s, t : string; begin case aType of ctToStr: if aInt = -1 then Result := 'None' else Result := IntToStr(aInt) + ' '; ctToEditValue: if aInt = -1 then Result := 'None' else Result := IntToStr(aInt); ctToSortKey: begin Result := IntToHex64(aInt, 8); Exit; end; ctCheck: if aInt = -1 then Result := '' else Result := ''; ctEditType: Result := ''; ctEditInfo: Result := ''; end; if (aInt = -1) and (aType <> ctEditType) and (aType <> ctEditInfo) then Exit; if not Assigned(aQuestRef) then Exit; // aQuestRef can be a QUST record or reference to QUST record if not Supports(aQuestRef, IwbMainRecord, MainRecord) then if not Supports(aQuestRef.LinksTo, IwbMainRecord, MainRecord) then Exit; MainRecord := MainRecord.WinningOverride; if MainRecord.Signature <> QUST then begin case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; end; Exit; end; case aType of ctEditType: begin Result := 'ComboBox'; Exit; end; ctEditInfo: EditInfos := TStringList.Create; else EditInfos := nil; end; try if Supports(MainRecord.ElementByName['Aliases'], IwbContainerElementRef, Aliases) then begin for i := 0 to Pred(Aliases.ElementCount) do if Supports(Aliases.Elements[i], IwbContainerElementRef, Alias) then begin j := Alias.Elements[0].NativeValue; s := Alias.ElementEditValues['ALID']; t := IntToStr(j); while Length(t) < 3 do t := '0' + t; if s <> '' then t := t + ' ' + s; if Assigned(EditInfos) then EditInfos.Add(t) else if j = aInt then begin case aType of ctToStr, ctToEditValue: Result := t; ctCheck: Result := ''; end; Exit; end; end; end; case aType of ctToStr: Result := IntToStr(aInt) + ' '; ctCheck: Result := ''; ctEditInfo: begin EditInfos.Add('None'); EditInfos.Sort; Result := EditInfos.CommaText; end; end; finally FreeAndNil(EditInfos); end; end; function wbStrToAlias(const aString: string; const aElement: IwbElement): Int64; var i : Integer; s : string; begin Result := -1; if aString = 'None' then Exit; i := 1; s := Trim(aString); while (i <= Length(s)) and (s[i] in ['-', '0'..'9']) do Inc(i); s := Copy(s, 1, Pred(i)); Result := StrToIntDef(s, -1); end; function wbScriptObjectAliasToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainerElementRef; begin if not wbResolveAlias then begin case aType of ctToStr, ctToEditValue: Result := IntToStr(aInt); ctToSortKey: Result := IntToHex64(aInt, 8); else Result := ''; end; Exit; end; if not Assigned(aElement) then Exit; Container := GetContainerRefFromUnionOrValue(aElement); if not Assigned(Container) then Exit; Result := wbAliasToStr(aInt, Container.ElementByName['FormID'], aType); end; function wbPackageLocationAliasToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainer; begin if not wbResolveAlias then begin case aType of ctToStr, ctToEditValue: Result := IntToStr(aInt); ctToSortKey: Result := IntToHex64(aInt, 8); else Result := ''; end; Exit; end; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; while Assigned(Container) and (Container.ElementType <> etMainRecord) do Container := Container.Container; if not Assigned(Container) then Exit; Result := wbAliasToStr(aInt, Container.ElementBySignature['QNAM'], aType); end; function wbQuestAliasToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainer; begin if not wbResolveAlias then begin case aType of ctToStr, ctToEditValue: Result := IntToStr(aInt); ctToSortKey: Result := IntToHex64(aInt, 8); else Result := ''; end; Exit; end; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; while Assigned(Container) and (Container.ElementType <> etMainRecord) do Container := Container.Container; if not Assigned(Container) then Exit; Result := wbAliasToStr(aInt, Container, aType); end; function wbQuestExternalAliasToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainer; begin if not wbResolveAlias then begin case aType of ctToStr, ctToEditValue: Result := IntToStr(aInt); ctToSortKey: Result := IntToHex64(aInt, 8); else Result := ''; end; Exit; end; if not Assigned(aElement) then Exit; Container := aElement.Container; if not Assigned(Container) then Exit; Result := wbAliasToStr(aInt, Container.ElementBySignature['ALEQ'] , aType); end; function wbConditionAliasToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Container : IwbContainer; MainRecord : IwbMainRecord; GroupRecord : IwbGroupRecord; begin if not wbResolveAlias then begin case aType of ctToStr, ctToEditValue: Result := IntToStr(aInt); ctToSortKey: Result := IntToHex64(aInt, 8); else Result := ''; end; Exit; end; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; while Assigned(Container) and (Container.ElementType <> etMainRecord) do Container := Container.Container; if not Assigned(Container) then Exit; if not Supports(Container, IwbMainRecord, MainRecord) then Exit; if MainRecord.Signature = QUST then Result := wbAliasToStr(aInt, Container, aType) else if MainRecord.Signature = SCEN then Result := wbAliasToStr(aInt, Container.ElementBySignature['PNAM'], aType) else if MainRecord.Signature = PACK then Result := wbAliasToStr(aInt, Container.ElementBySignature['QNAM'], aType) else if MainRecord.Signature = INFO then begin // get DIAL for INFO if Supports(MainRecord.Container, IwbGroupRecord, GroupRecord) then if Supports(GroupRecord.ChildrenOf, IwbMainRecord, MainRecord) then Result := wbAliasToStr(aInt, MainRecord.ElementBySignature['QNAM'], aType); end else // this should never be called since aliases in conditions can be in the forms above only // but just in case case aType of ctToStr, ctToEditValue: Result := IntToStr(aInt); ctToSortKey: Result := IntToHex64(aInt, 8); else Result := ''; end; end; function wbClmtMoonsPhaseLength(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var PhaseLength : Byte; Masser : Boolean; Secunda : Boolean; begin Result := ''; if aType = ctToSortKey then begin Result := IntToHex64(aInt, 2); end else if aType = ctToStr then begin PhaseLength := aInt mod 64; Masser := (aInt and 64) <> 0; Secunda := (aInt and 128) <> 0; if Masser then if Secunda then Result := 'Masser, Secunda / ' else Result := 'Masser / ' else if Secunda then Result := 'Secunda / ' else Result := 'No Moon / '; Result := Result + IntToStr(PhaseLength); end; end; function wbClmtTime(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; begin if aType = ctToSortKey then Result := IntToHex64(aInt, 4) else if aType = ctToStr then try Result := TimeToStr( EncodeTime(aInt div 6, (aInt mod 6) * 10, 0, 0) ) except Result := IntToStr(aInt) end else Result := ''; end; var wbCtdaTypeFlags : IwbFlagsDef; function wbCtdaTypeToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var s: string; begin Result := ''; if not Assigned(wbCtdaTypeFlags) then wbCtdaTypeFlags := wbFlags([ {0x01} 'Or', {0x02} 'Use aliases', {0x04} 'Use global', {0x08} 'Use packdata', {0x10} 'Swap Subject and Target' ]); { Compare operator (upper 3 bits) LGE 000 0=Equal to 001 1=Not equal to 010 2=Greater than 011 3=Greater than or equal to 100 4=Less than 101 5=Less than or equal to Flags (lower 5 bits) 0x01=OR (default is to AND conditions together) 0x02=Parameters (use aliases) : Force function parameters to use quest alias data (exclusive with "use pack data") 0x04=Use global 0x08=Use Pack Data : Force function parameters to use pack data (exclusive with "use aliases") 0x10=Swap Subject and Target } case aType of ctEditType: Result := 'CheckComboBox'; ctEditInfo: Result := 'Equal,Greater,Lesser,Or,"Use Aliases","Use Global","Use Packdata","Swap Subject and Target"'; ctToEditValue: begin Result := '00000000'; case aInt and $E0 of $00 : Result[1] := '1'; $40 : Result[2] := '1'; $60 : begin Result[1] := '1'; Result[2] := '1'; end; $80 : Result[3] := '1'; $A0 : begin Result[1] := '1'; Result[3] := '1'; end; end; if (aInt and $01) <> 0 then // Or Result[4] := '1'; if (aInt and $02) <> 0 then // Use aliases Result[5] := '1'; if (aInt and $04) <> 0 then // Use global Result[6] := '1'; if (aInt and $08) <> 0 then // Use packdata Result[7] := '1'; if (aInt and $10) <> 0 then // Swap Subject and Target Result[8] := '1'; end; ctToStr: begin case aInt and $E0 of $00 : Result := 'Equal to'; $20 : Result := 'Not equal to'; $40 : Result := 'Greater than'; $60 : Result := 'Greater than or equal to'; $80 : Result := 'Less than'; $A0 : Result := 'Less than or equal to'; else Result := '' end; s := wbCtdaTypeFlags.ToString(aInt and $1F, aElement); if s <> '' then Result := Result + ' / ' + s; end; ctToSortKey: begin Result := IntToHex64(aInt, 2); Exit; end; ctCheck: begin case aInt and $E0 of $00, $20, $40, $60, $80, $A0 : Result := ''; else Result := '' end; s := wbCtdaTypeFlags.Check(aInt and $1F, aElement); if s <> '' then Result := Result + ' / ' + s; end; end; end; function wbCtdaTypeToInt(const aString: string; const aElement: IwbElement): Int64; var s: string; begin s := aString + '00000000'; if s[1] = '1' then begin if s[2] = '1' then begin if s[3] = '1' then begin Result := $00; end else begin Result := $60; end; end else begin if s[3] = '1' then begin Result := $A0; end else begin Result := $00; end; end; end else begin if s[2] = '1' then begin if s[3] = '1' then begin Result := $20; end else begin Result := $40; end; end else begin if s[3] = '1' then begin Result := $80; end else begin Result := $20; end; end; end; // Or if s[4] = '1' then Result := Result or $01; // Use aliases if s[5] = '1' then Result := Result or $02; // Use global if s[6] = '1' then Result := Result or $04; // Use packdata if s[7] = '1' then Result := Result or $08; // Swap Subject and Target if s[8] = '1' then Result := Result or $10; end; var wbEventFunctionAndMemberEditInfo: string; function wbEventFunctionAndMemberToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var EventFunction, EventMember: Integer; i, j: Integer; s1, s2: string; slMember: TStringList; begin Result := ''; EventFunction := aInt and $FFFF; EventMember := aInt shr 16; case aType of ctToStr, ctToEditValue: begin Result := wbEventFunctionEnum.ToEditValue(EventFunction, nil); Result := Result + ':' + wbEventMemberEnum.ToEditValue(EventMember, nil); end; ctToSortKey: Result := IntToHex(aInt, 8); ctCheck: begin s1 := wbEventFunctionEnum.Check(EventFunction, nil); if s1 <> '' then s1 := 'EventFunction' + s1; s2 := wbEventMemberEnum.Check(EventMember, nil); if s2 <> '' then s2 := 'EventMember' + s2; if (s1 <> '') or (s2 <> '') then Result := s1 + ':' + s2; end; ctEditType: Result := 'ComboBox'; ctEditInfo: begin Result := wbEventFunctionAndMemberEditInfo; if Result = '' then try slMember := TStringList.Create; slMember.CommaText := wbEventMemberEnum.EditInfo[0, nil]; with TStringList.Create do try for i := 0 to Pred(wbEventFunctionEnum.NameCount) do for j := 0 to Pred(slMember.Count) do Add(wbEventFunctionEnum.Names[i] + ':' + slMember[j]); Sort; Result := CommaText; finally Free; end; wbEventFunctionAndMemberEditInfo := Result; finally FreeAndNil(slMember); end end; end; end; function wbEventFunctionAndMemberToInt(const aString: string; const aElement: IwbElement): Int64; var EventFunction, EventMember, i: Integer; begin i := Pos(':', aString); if i > 0 then begin EventFunction := wbEventFunctionEnum.FromEditValue(Copy(aString, 1, i-1), nil); EventMember := wbEventMemberEnum.FromEditValue(Copy(aString, i+1, Length(aString)), nil); end else begin EventFunction := 0; EventMember := 0; end; Result := EventMember shl 16 + EventFunction; end; procedure wbMESGDNAMAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var OldValue, NewValue : Integer; Container : IwbContainerElementRef; begin if VarSameValue(aOldValue, aNewValue) then Exit; if Supports(aElement.Container, IwbContainerElementRef, Container) then begin OldValue := Integer(aOldValue) and 1; NewValue := Integer(aNewValue) and 1; if NewValue = OldValue then Exit; if NewValue = 1 then Container.RemoveElement('TNAM') else Container.Add('TNAM', True); end; end; procedure wbGMSTEDIDAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var OldValue, NewValue : string; Container : IwbContainerElementRef; begin if VarSameValue(aOldValue, aNewValue) then Exit; if Supports(aElement.Container, IwbContainerElementRef, Container) then begin OldValue := aOldValue; NewValue := aNewValue; if (Length(OldValue) < 1) or (Length(OldValue) < 1) or (OldValue[1] <> NewValue[1]) then begin Container.RemoveElement('DATA'); Container.Add('DATA', True); end; end; end; procedure wbFLSTEDIDAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var OldValue, NewValue : string; OldOrdered, NewOrdered : Boolean; Container : IwbContainerElementRef; const OrderedList = 'OrderedList'; begin if VarSameValue(aOldValue, aNewValue) then Exit; if Supports(aElement.Container, IwbContainerElementRef, Container) then begin OldValue := aOldValue; NewValue := aNewValue; if Length(OldValue) > Length(OrderedList) then Delete(OldValue, 1, Length(OldValue)-Length(OrderedList)); if Length(NewValue) > Length(OrderedList) then Delete(NewValue, 1, Length(NewValue)-Length(OrderedList)); OldOrdered := SameText(OldValue, OrderedList); NewOrdered := SameText(NewValue, OrderedList); if OldOrdered <> NewOrdered then Container.RemoveElement('FormIDs'); end; end; procedure wbCtdaTypeAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var OldValue, NewValue: Integer; Container: IwbContainerElementRef; begin if VarSameValue(aOldValue, aNewValue) then Exit; if not Supports(aElement, IwbContainerElementRef, Container) then Exit; // reset value if "use global" has changed OldValue := aOldValue and $04; NewValue := aNewValue and $04; if OldValue <> NewValue then Container.ElementNativeValues['..\Comparison Value'] := 0; {>>> "run on target", no such flag in Skyrim <<<} // if aNewValue and $02 then begin // Container.ElementNativeValues['..\Run On'] := 1; // if Integer(Container.ElementNativeValues['..\Run On']) = 1 then // aElement.NativeValue := Byte(aNewValue) and not $02; // end; end; procedure wbAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin Exit; end; function wbMODTCallback(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Strings: TDynStrings; i: Integer; begin Result := ''; if wbLoaderDone and (aType in [ctToStr, ctToSortKey] ) then begin Strings := wbContainerHandler.ResolveHash(aInt); for i := Low(Strings) to High(Strings) do Result := Result + Strings[i] + ', '; SetLength(Result, Length(Result) -2 ); end; end; {>>> Needs revision for Skyrim <<<} //function wbIdleAnam(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; //begin // Result := ''; // case aType of // ctToStr: begin // case aInt and not $C0 of // 0: Result := 'Idle'; // 1: Result := 'Movement'; // 2: Result := 'Left Arm'; // 3: Result := 'Left Hand'; // 4: Result := 'Weapon'; // 5: Result := 'Weapon Up'; // 6: Result := 'Weapon Down'; // 7: Result := 'Special Idle'; // 20: Result := 'Whole Body'; // 21: Result := 'Upper Body'; // else // Result := ''; // end; // // if (aInt and $80) = 0 then // Result := Result + ', Must return a file'; // if (aInt and $40) = 1 then // Result := Result + ', Unknown Flag'; // end; // ctToSortKey: begin // Result := IntToHex64(aInt, 2); // end; // ctCheck: begin // case aInt and not $C0 of // 0..7, 20, 21: Result := ''; // else // Result := ''; // end; // end; // end; //end; function wbScaledInt4ToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; const PlusMinus : array[Boolean] of string = ('+', '-'); begin Result := ''; case aType of ctToStr, ctToEditValue: Result := FloatToStrF(aInt / 10000, ffFixed, 99, 4); ctToSortKey: begin Result := FloatToStrF(aInt / 10000, ffFixed, 99, 4); if Length(Result) < 22 then Result := StringOfChar('0', 22 - Length(Result)) + Result; Result := PlusMinus[aInt < 0] + Result; end; ctCheck: Result := ''; end; end; function wbScaledInt4ToInt(const aString: string; const aElement: IwbElement): Int64; var f: Extended; begin f := StrToFloat(aString); f := f * 10000; Result := Round(f); end; function wbCloudSpeedToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; begin Result := ''; case aType of ctToStr, ctToEditValue: Result := FloatToStrF((aInt - 127)/127/10, ffFixed, 99, 4); ctCheck: Result := ''; end; end; function wbCloudSpeedToInt(const aString: string; const aElement: IwbElement): Int64; var f: Extended; begin f := StrToFloat(aString); f := f*10*127 + 127; Result := Min(Round(f), 254); end; function wbShortXYtoStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var x, y: SmallInt; begin y := aInt and $FFFF; x := aInt shr 16 and $FFFF; Result := ''; case aType of ctToStr, ctToEditValue: Result := Format('%d, %d', [x, y]); ctCheck: Result := ''; end; end; function wbStrToShortXY(const aString: string; const aElement: IwbElement): Int64; var x, y: SmallInt; Value: Cardinal; begin y := StrToIntDef(Copy(aString, 1, Pred(Pos(', ', aString))), 0); x := StrToIntDef(Copy(aString, Pos(', ', aString) + 2, Length(aString)), 0); PWord(@Value)^ := x; PWord(Cardinal(@Value) + SizeOf(SmallInt))^ := y; Result := Value; end; function wbHideFFFF(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; begin Result := ''; if aType = ctToSortKey then Result := IntToHex64(aInt, 4) else if aType = ctToStr then if aInt = $FFFF then Result := 'None' else Result := IntToStr(aInt); end; function wbAtxtPosition(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; begin Result := ''; if aType = ctToSortKey then Result := IntToHex64(aInt div 17, 2) + IntToHex64(aInt mod 17, 2) else if aType = ctCheck then begin if (aInt < 0) or (aInt > 288) then Result := '' else Result := ''; end else if aType = ctToStr then Result := IntToStr(aInt) + ' -> ' + IntToStr(aInt div 17) + ':' + IntToStr(aInt mod 17); end; function wbGLOBFNAM(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; begin Result := ''; case aType of ctToStr: begin case aInt of Ord('s'): Result := 'Short'; Ord('l'): Result := 'Long'; Ord('f'): Result := 'Float'; Ord('b'): Result := 'Boolean'; else Result := ''; end; end; ctToSortKey: Result := Chr(aInt); ctCheck: begin case aInt of Ord('s'), Ord('l'), Ord('f'), Ord('b'): Result := ''; else Result := ''; end; end; end; end; function wbPlacedAddInfo(const aMainRecord: IwbMainRecord): string; var Rec: IwbRecord; Container: IwbContainer; s: string; Cell: IwbMainRecord; Position: TwbVector; Grid: TwbGridCell; begin Result := ''; Rec := aMainRecord.RecordBySignature['NAME']; if Assigned(Rec) then begin s := Trim(Rec.Value); if s <> '' then Result := 'places ' + s; end; Container := aMainRecord.Container; while Assigned(Container) and (Container.ElementType <> etGroupRecord) do Container := Container.Container; if Assigned(Container) then begin s := Trim(Container.Name); if s <> '' then begin if Result <> '' then Result := Result + ' '; Result := Result + 'in ' + s; // grid position of persistent reference in exterior persistent cell (interior cells are not persistent) if Supports(aMainRecord.Container, IwbGroupRecord, Container) then Cell := IwbGroupRecord(Container).ChildrenOf; if Assigned(Cell) and Cell.IsPersistent and (Cell.Signature = 'CELL') then if aMainRecord.GetPosition(Position) then begin Grid := wbPositionToGridCell(Position); Result := Result + ' at ' + IntToStr(Grid.x) + ',' + IntToStr(Grid.y); end; end; end; end; function wbINFOAddInfo(const aMainRecord: IwbMainRecord): string; var Container: IwbContainer; s: string; begin Result := Trim(aMainRecord.ElementValues['Responses\Response\NAM1']); if Result <> '' then Result := '''' + Result + ''''; Container := aMainRecord.Container; while Assigned(Container) and (Container.ElementType <> etGroupRecord) do Container := Container.Container; if Assigned(Container) then begin s := Trim(Container.Name); if s <> '' then begin if Result <> '' then Result := Result + ' '; Result := Result + 'in ' + s; end; end; s := Trim(aMainRecord.ElementValues['QNAM']); if s <> '' then begin if Result <> '' then Result := Result + ' '; Result := Result + 'for ' + s; end; end; function wbNAVMAddInfo(const aMainRecord: IwbMainRecord): string; var Container: IwbContainer; s: string; begin Result := ''; Container := aMainRecord.Container; while Assigned(Container) and (Container.ElementType <> etGroupRecord) do Container := Container.Container; if Assigned(Container) then begin s := Trim(Container.Name); if s <> '' then begin if Result <> '' then Result := Result + ' '; Result := Result + 'in ' + s; end; end; end; function wbCellAddInfo(const aMainRecord: IwbMainRecord): string; var Rec: IwbRecord; Container: IwbContainer; GroupRecord : IwbGroupRecord; s: string; begin Result := ''; if not aMainRecord.IsPersistent then begin Rec := aMainRecord.RecordBySignature['XCLC']; if Assigned(Rec) then Result := 'at ' + Rec.Elements[0].Value + ',' + Rec.Elements[1].Value; end; Container := aMainRecord.Container; while Assigned(Container) and not (Supports(Container, IwbGroupRecord, GroupRecord) and (GroupRecord.GroupType = 1)) do Container := Container.Container; if Assigned(Container) then begin s := wbFormID.ToString(GroupRecord.GroupLabel, aMainRecord); if s <> '' then begin if Result <> '' then s := s + ' '; Result := 'in ' + s + Result; end; end; end; procedure wbCTDARunOnAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin if aOldValue <> aNewValue then if aNewValue <> 2 then aElement.Container.ElementNativeValues['Reference'] := 0; end; {>>> Needs revision for Skyrim <<<} procedure wbPERKPRKETypeAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var Container : IwbContainerElementRef; // rDATA : IwbRecord; begin if aOldValue <> aNewValue then if Supports(aElement.Container, IwbContainerElementRef, Container) then begin if Supports(Container.Container, IwbContainerElementRef, Container) then begin Container.RemoveElement('DATA'); Container.Add('DATA', True); Container.RemoveElement('Perk Conditions'); Container.RemoveElement('Entry Point Function Parameters'); if aNewValue = 2 then begin Container.Add('EPFT', True); Container.ElementNativeValues['DATA\Entry Point\Function'] := 2; end; end; end; end; function wbNPCLevelDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container: IwbContainer; i: Int64; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; i := Container.ElementByName['Flags'].NativeValue; if i and $00000080 <> 0 then Result := 1; end; function wbMGEFAssocItemDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; Archtype : Variant; DataContainer : IwbDataContainer; Element : IwbElement; const OffsetArchtype = 56; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; VarClear(ArchType); Element := Container.ElementByName['Archtype']; if Assigned(Element) then ArchType := Element.NativeValue else if Supports(Container, IwbDataContainer, DataContainer) and DataContainer.IsValidOffset(aBasePtr, aEndPtr, OffsetArchtype) then begin // we are part a proper structure aBasePtr := Pointer(Cardinal(aBasePtr) + OffsetArchtype); ArchType := PCardinal(aBasePtr)^; end; if not VarIsEmpty(ArchType) then case Integer(ArchType) of 12: Result := 1; // Light 17: Result := 2; // Bound Item 18: Result := 3; // Summon Creature 25: Result := 4; // Guide 34: Result := 8; // Peak Mod 35: Result := 5; // Cloak 36: Result := 6; // Werewolf 39: Result := 7; // Enhance Weapon 40: Result := 4; // Spawn Hazard 46: Result := 6; // Vampire Lord end; end; procedure wbMGEFAssocItemAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var Container : IwbContainer; Element : IwbElement; begin if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; if (aNewValue <> 0) then begin Element := Container.ElementByName['Archtype']; if Assigned(Element) and (Element.NativeValue = 0) then Element.NativeValue := $FF; // Signals ArchType that it should not mess with us on the next change! // I assume this will alo protect Second AV Weight (The two actor values are after ArchType) end; end; procedure wbMGEFAV2WeightAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var Container : IwbContainer; Element : IwbElement; begin if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; if (aNewValue <> 0.0) then begin Element := Container.ElementByName['Archtype']; if Assigned(Element) and (Element.NativeValue = 0) then Element.NativeValue := $FF; // Signals ArchType that it should not mess with us on the next change! end; end; procedure wbMGEFArchtypeAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var Container: IwbContainerElementRef; begin if VarSameValue(aOldValue, aNewValue) then Exit; if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if (aNewValue < $FF) and (aOldValue < $FF) then begin Container.ElementNativeValues['..\Assoc. Item'] := 0; case Integer(aNewValue) of 06: Container.ElementNativeValues['..\Actor Value'] := 00;//Agression 07: Container.ElementNativeValues['..\Actor Value'] := 01;//Confidence 08: Container.ElementNativeValues['..\Actor Value'] := 00;//Agression 11: Container.ElementNativeValues['..\Actor Value'] := 54;//Invisibility 21: Container.ElementNativeValues['..\Actor Value'] := 53;//Paralysis 24: Container.ElementNativeValues['..\Actor Value'] := 01;//Confidence 38: Container.ElementNativeValues['..\Actor Value'] := 01;//Confidence 42: Container.ElementNativeValues['..\Actor Value'] := 01;//Confidence else Container.ElementNativeValues['..\Actor Value'] := -1; end; Container.ElementNativeValues['..\Second Actor Value'] := -1; Container.ElementNativeValues['..\Second AV Weight'] := 0.0; end; end; function wbCTDAReferenceDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; if Integer(Container.ElementNativeValues['Run On']) = 2 then Result := 1; end; function wbNAVIIslandDataDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; SubRecord : IwbMainRecord; Element : IwbElement; begin Result := 0; Container := aElement.Container; while Assigned(Container) and (Container.ElementType <> etsubRecord) do Container := Container.Container; if not Supports(Container, IwbSubRecord, SubRecord) then Exit; Element := SubRecord.ElementByName['Is Island']; if not Assigned(Element) then Exit; Result := Element.NativeValue; end; function wbNAVIParentDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; SubRecord : IwbMainRecord; Element : IwbElement; begin Result := 0; Container := aElement.Container; while Assigned(Container) and (Container.ElementType <> etsubRecord) do Container := Container.Container; if not Supports(Container, IwbSubRecord, SubRecord) then Exit; Element := SubRecord.ElementByName['Parent Worldspace']; if not Assigned(Element) then Exit; if (Element.NativeValue = 0) then Result := 1; end; function wbNVNMParentDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; Current : IwbContainer; Parent : IwbContainer; GroupRecord : IwbGroupRecord; MainRecord : IwbMainRecord; rData : IwbRecord; i : integer; begin Result := 0; Container := aElement.Container; while Assigned(Container) and (Container.ElementType <> etGroupRecord) do Container := Container.Container; if not Supports(Container, IwbGroupRecord, GroupRecord) then Exit; MainRecord := GroupRecord.ChildrenOf; // This does NOT work while adding master! if not Assigned(MainRecord) then begin // we expect: // plugin \ CELL group \ Block \ Sub Block \ CELL // \ CELL Children group \ Permanent children group // \ Temporary children group = GroupRecord = Container if Assigned(Container) and (Container.ElementType = etGroupRecord) then Container := Container.Container; if Assigned(Container) and (Container.ElementType = etGroupRecord) then Parent := Container.Container; i := 0; while (i < Parent.ElementCount) and Supports(Parent.Elements[i], IwbContainer, Current) and (Current <> Container) do Inc(i); if (i = 0) or (i = Parent.ElementCount) or not Supports(Parent.Elements[i-1], IwbMainRecord,MainRecord) then begin wbProgressCallback('Parent of a NVNM is not a MainRecord'); // Assert(Assigned(MainRecord)); // Better an exception than to destroy the plugin. Exit; end; end; if (MainRecord.Signature<>CELL) then begin wbProgressCallback('Parent of a NVNM is not identified as a CELL'); Assert(MainRecord.Signature=CELL); // Better an exception than to destroy the plugin. Exit; end; rDATA := MainRecord.RecordBySignature['DATA']; if not Assigned(rData) then Exit; i := rData.NativeValue; // is interior cell? if i and 1 <> 0 then Result := 1; end; function wbCOEDOwnerDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; LinksTo : IwbElement; MainRecord : IwbMainRecord; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; LinksTo := Container.ElementByName['Owner'].LinksTo; if Supports(LinksTo, IwbMainRecord, MainRecord) then if MainRecord.Signature = 'NPC_' then Result := 1 else if MainRecord.Signature = 'FACT' then Result := 2; end; function wbGMSTUnionDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var rEDID: IwbRecord; s: string; begin Result := 1; rEDID := aElement.Container.RecordBySignature[EDID]; if Assigned(rEDID) then begin s := rEDID.Value; if Length(s) > 0 then case s[1] of 's': Result := 0; {String} {>>> Localization Strings <<<} 'i': Result := 1; {intS32} 'f': Result := 2; {Float} 'b': Result := 3; {Boolean} end; end; end; function wbFLSTLNAMIsSorted(const aContainer: IwbContainer): Boolean; var rEDID : IwbRecord; s : string; const OrderedList = 'OrderedList'; begin Result := False; {>>> Should not be sorted according to Arthmoor and JustinOther <<<} rEDID := aContainer.RecordBySignature[EDID]; if Assigned(rEDID) then begin s := rEDID.Value; if Length(s) > Length(OrderedList) then Delete(s, 1, Length(s)-Length(OrderedList)); if SameText(s, OrderedList) then Result := False; end; end; function wbPerkDATADecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var rPRKE: IwbRecord; eType: IwbElement; begin Result := 0; rPRKE := aElement.Container.RecordBySignature[PRKE]; if Assigned(rPRKE) then begin eType := rPRKE.ElementByName['Type']; if Assigned(eType) then begin Result := eType.NativeValue; end; end; end; function wbEPFDDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container: IwbContainerElementRef; begin Result := 0; if not Assigned(aElement) then Exit; if not Supports(aElement.Container, IwbContainerElementRef, Container) then Exit; Result := Container.ElementNativeValues['EPFT']; if Result = 2 then case Integer(Container.ElementNativeValues['..\DATA\Entry Point\Function']) of 5, 12, 13, 14: Result := 8; end; end; function wbSPGDFormatDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var MainRecord: IwbMainRecord; begin Result := 0; if not Assigned(aElement) then Exit; if not Supports(aElement.Container, IwbMainRecord, MainRecord) then Exit; if MainRecord.Version < 44 then Result := 1; end; {>>> For VMAD <<<} function wbScriptObjFormatDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var ObjFormat: Integer; Container: IwbContainer; begin Result := 0; Container := aElement.Container; while Assigned(Container) and (Container.ElementType <> etSubRecord) do Container := Container.Container; if not Assigned(Container) then Exit; ObjFormat := Container.ElementNativeValues['Object Format']; if ObjFormat = 1 then Result := 1; end; {>>> For VMAD <<<} function wbScriptPropertyDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; case Integer(Container.ElementNativeValues['Type']) of 1: Result := 1; 2: Result := 2; 3: Result := 3; 4: Result := 4; 5: Result := 5; 11: Result := 6; 12: Result := 7; 13: Result := 8; 14: Result := 9; 15: Result := 10; end; end; procedure wbScriptPropertyTypeAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var Container : IwbContainerElementRef; begin if aOldValue <> aNewValue then if Supports(aElement.Container, IwbContainerElementRef, Container) then Container.ElementByName['Value'].SetToDefault; end; {>>> For VMAD <<<} function wbScriptFragmentExistsDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; MainRecord : IwbMainRecord; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; while Assigned(Container) and (Container.ElementType <> etMainRecord) do Container := Container.Container; if not Assigned(Container) then Exit; Supports(Container, IwbMainRecord, MainRecord); if MainRecord.Signature = INFO then Result := 1 else if MainRecord.Signature = PACK then Result := 2 else if MainRecord.Signature = PERK then Result := 3 else if MainRecord.Signature = QUST then Result := 4 else if MainRecord.Signature = SCEN then Result := 5; end; {>>> For VMAD <<<} function wbScriptFragmentsQuestCounter(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Cardinal; var Container : IwbContainer; begin Result := 0; if aElement.ElementType = etValue then Container := aElement.Container else Container := aElement as IwbContainer; if not Assigned(Container) then Exit; while Assigned(Container) and (Container.Name <> 'Script Fragments') do Container := Container.Container; if not Assigned(Container) then Exit; Result := Integer(Container.ElementNativeValues['fragmentCount']); end; {>>> For VMAD <<<} function wbScriptFragmentsInfoCounter(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Cardinal; var Container : IwbContainer; F : Integer; i : Integer; begin Result := 0; if aElement.ElementType = etValue then Container := aElement.Container else Container := aElement as IwbContainer; if not Assigned(Container) then Exit; while Assigned(Container) and (Container.Name <> 'Script Fragments') do Container := Container.Container; if not Assigned(Container) then Exit; F := Container.ElementByName['Flags'].NativeValue; for i := 0 to 2 do begin if (F and 1) = 1 then Inc(Result); F := F shr 1; end; for i := 3 to 7 do begin if (F and 1) = 1 then begin Inc(Result); if Assigned(wbProgressCallback) then wbProgressCallback('==='+aElement.Name+' ['+Container.Name+':'+Container.Path+'] = unknown info VMAD flag bit '+IntToStr(i)); end; F := F shr 1; end; end; {>>> For VMAD <<<} function wbScriptFragmentsSceneCounter(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Cardinal; var Container : IwbContainer; F : Integer; i : Integer; begin Result := 0; if aElement.ElementType = etValue then Container := aElement.Container else Container := aElement as IwbContainer; if not Assigned(Container) then Exit; while Assigned(Container) and (Container.Name <> 'Script Fragments') do Container := Container.Container; if not Assigned(Container) then Exit; F := Container.ElementByName['Flags'].NativeValue; for i := 0 to 2 do begin if (F and 1) = 1 then Inc(Result); F := F shr 1; end; for i := 3 to 7 do begin if (F and 1) = 1 then begin Inc(Result); if Assigned(wbProgressCallback) then wbProgressCallback('==='+aElement.Name+' ['+Container.Name+':'+Container.Path+'] = unknown scene VMAD flag bit '+IntToStr(i)); end; F := F shr 1; end; end; {>>> For VMAD <<<} function wbScriptFragmentsPackCounter(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Cardinal; var Container : IwbContainer; F : Integer; i : Integer; begin Result := 0; if aElement.ElementType = etValue then Container := aElement.Container else Container := aElement as IwbContainer; if not Assigned(Container) then Exit; while Assigned(Container) and (Container.Name <> 'Script Fragments') do Container := Container.Container; if not Assigned(Container) then Exit; F := Container.ElementByName['Flags'].NativeValue; for i := 0 to 7 do begin if (F and 1) = 1 then Inc(Result); F := F shr 1; end; end; function wbBOOKTeachesDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container: IwbContainer; i: Int64; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; i := Container.ElementByName['Flags'].NativeValue; if i and $00000004 <> 0 then Result := 1; end; type TCTDAFunctionParamType = ( ptNone, ptInteger, ptFloat, ptVariableName, //Integer ptSex, //Enum: Male, Female ptActorValue, //Enum: wbActorValue ptCrimeType, //?? Enum ptAxis, //?? Char ptQuestStage, //?? Integer ptMiscStat, //?? Enum ptAlignment, //?? Enum ptEquipType, //?? Enum ptFormType, //?? Enum ptCriticalStage, //?? Enum ptObjectReference, //REFR, ACHR ptInventoryObject, //ARMO, BOOK, MISC, WEAP, AMMO, KEYM, ALCH, ARMA, LIGH, LVLI, COBJ ptActor, //ACHR ptVoiceType, //VTYP ptIdleForm, //IDLE ptFormList, //FLST ptQuest, //QUST ptFaction, //FACT ptCell, //CELL ptClass, //CLAS ptRace, //RACE ptActorBase, //NPC_ ptGlobal, //GLOB ptWeather, //WTHR ptPackage, //PACK ptEncounterZone, //ECZN ptPerk, //PERK ptOwner, //FACT, NPC_ ptFurniture, //FURN ptMagicItem, //SPEL ptMagicEffect, //MGEF ptWorldspace, //WRLD ptVATSValueFunction, ptVATSValueParam, ptReferencableObject, ptRegion, //REGN ptKeyword, //KYWD ptAdvanceAction, // ?? Enum ptCastingSource, // ?? Enum ptShout, //SHOU ptLocation, //LCTN ptRefType, //LCRT ptAlias, // index into QUST quest aliases ptPackdata, // index into PACK package data inputs ptAssociationType, // ASTP ptFurnitureAnim, // enum ptFurnitureEntry, // flags ptScene, // SCEN ptWardState, // enum ptEvent, // Struct ptEventData // LCTN, KYWD or FLST ); PCTDAFunction = ^TCTDAFunction; TCTDAFunction = record Index: Integer; Name: string; ParamType1: TCTDAFunctionParamType; ParamType2: TCTDAFunctionParamType; ParamType3: TCTDAFunctionParamType; end; const {>> N means New, V means verified that the name has not changed <<<} wbCTDAFunctions : array[0..399] of TCTDAFunction = ( {N} (Index: 0; Name: 'GetWantBlocking'), {V} (Index: 1; Name: 'GetDistance'; ParamType1: ptObjectReference), {V} (Index: 5; Name: 'GetLocked'), {V} (Index: 6; Name: 'GetPos'; ParamType1: ptAxis), {V} (Index: 8; Name: 'GetAngle'; ParamType1: ptAxis), {V} (Index: 10; Name: 'GetStartingPos'; ParamType1: ptAxis), {V} (Index: 11; Name: 'GetStartingAngle'; ParamType1: ptAxis), {V} (Index: 12; Name: 'GetSecondsPassed'), {V} (Index: 14; Name: 'GetActorValue'; ParamType1: ptActorValue), {V} (Index: 18; Name: 'GetCurrentTime'), {V} (Index: 24; Name: 'GetScale'), {V} (Index: 25; Name: 'IsMoving'), {V} (Index: 26; Name: 'IsTurning'), {V} (Index: 27; Name: 'GetLineOfSight'; ParamType1: ptObjectReference), {V} (Index: 32; Name: 'GetInSameCell'; ParamType1: ptObjectReference), {V} (Index: 35; Name: 'GetDisabled'), {V} (Index: 36; Name: 'MenuMode'; ParamType1: ptInteger), // was ptMenuMode {V} (Index: 39; Name: 'GetDisease'), {V} (Index: 41; Name: 'GetClothingValue'), {V} (Index: 42; Name: 'SameFaction'; ParamType1: ptActor), {V} (Index: 43; Name: 'SameRace'; ParamType1: ptActor), {V} (Index: 44; Name: 'SameSex'; ParamType1: ptActor), {V} (Index: 45; Name: 'GetDetected'; ParamType1: ptActor), {V} (Index: 46; Name: 'GetDead'), {V} (Index: 47; Name: 'GetItemCount'; ParamType1: ptInventoryObject), {V} (Index: 48; Name: 'GetGold'), {V} (Index: 49; Name: 'GetSleeping'), {V} (Index: 50; Name: 'GetTalkedToPC'), {V} (Index: 53; Name: 'GetScriptVariable'; ParamType1: ptObjectReference; ParamType2: ptVariableName), {V} (Index: 56; Name: 'GetQuestRunning'; ParamType1: ptQuest), {V} (Index: 58; Name: 'GetStage'; ParamType1: ptQuest), {V} (Index: 59; Name: 'GetStageDone'; ParamType1: ptQuest; ParamType2: ptQuestStage), {V} (Index: 60; Name: 'GetFactionRankDifference'; ParamType1: ptFaction; ParamType2: ptActor), {V} (Index: 61; Name: 'GetAlarmed'), {V} (Index: 62; Name: 'IsRaining'), {V} (Index: 63; Name: 'GetAttacked'), {V} (Index: 64; Name: 'GetIsCreature'), {V} (Index: 65; Name: 'GetLockLevel'), {V} (Index: 66; Name: 'GetShouldAttack'; ParamType1: ptActor), {V} (Index: 67; Name: 'GetInCell'; ParamType1: ptCell), {V} (Index: 68; Name: 'GetIsClass'; ParamType1: ptClass), {V} (Index: 69; Name: 'GetIsRace'; ParamType1: ptRace), {V} (Index: 70; Name: 'GetIsSex'; ParamType1: ptSex), {V} (Index: 71; Name: 'GetInFaction'; ParamType1: ptFaction), {V} (Index: 72; Name: 'GetIsID'; ParamType1: ptReferencableObject), {V} (Index: 73; Name: 'GetFactionRank'; ParamType1: ptFaction), {V} (Index: 74; Name: 'GetGlobalValue'; ParamType1: ptGlobal), {V} (Index: 75; Name: 'IsSnowing'), {V} (Index: 77; Name: 'GetRandomPercent'), {V} (Index: 79; Name: 'GetQuestVariable'; ParamType1: ptQuest; ParamType2: ptVariableName), {V} (Index: 80; Name: 'GetLevel'), {N} (Index: 81; Name: 'IsRotating'), {V} (Index: 84; Name: 'GetDeadCount'; ParamType1: ptActorBase), {V} (Index: 91; Name: 'GetIsAlerted'), {V} (Index: 98; Name: 'GetPlayerControlsDisabled'; ParamType1: ptInteger; ParamType2: ptInteger), {V} (Index: 99; Name: 'GetHeadingAngle'; ParamType1: ptObjectReference), {N} (Index: 101; Name: 'IsWeaponMagicOut'), {V} (Index: 102; Name: 'IsTorchOut'), {V} (Index: 103; Name: 'IsShieldOut'), {V} (Index: 106; Name: 'IsFacingUp'), {V} (Index: 107; Name: 'GetKnockedState'), {V} (Index: 108; Name: 'GetWeaponAnimType'), {V} (Index: 109; Name: 'IsWeaponSkillType'; ParamType1: ptActorValue), {V} (Index: 110; Name: 'GetCurrentAIPackage'), {V} (Index: 111; Name: 'IsWaiting'), {V} (Index: 112; Name: 'IsIdlePlaying'), {N} (Index: 116; Name: 'IsIntimidatebyPlayer'), {N} (Index: 117; Name: 'IsPlayerInRegion'; ParamType1: ptRegion), {V} (Index: 118; Name: 'GetActorAggroRadiusViolated'), {V} (Index: 122; Name: 'GetCrime'; ParamType1: ptActor; ParamType2: ptCrimeType), {V} (Index: 123; Name: 'IsGreetingPlayer'), {V} (Index: 125; Name: 'IsGuard'), {V} (Index: 127; Name: 'HasBeenEaten'), {V} (Index: 128; Name: 'GetStaminaPercentage'), {V} (Index: 129; Name: 'GetPCIsClass'; ParamType1: ptClass), {V} (Index: 130; Name: 'GetPCIsRace'; ParamType1: ptRace), {V} (Index: 131; Name: 'GetPCIsSex'; ParamType1: ptSex), {V} (Index: 132; Name: 'GetPCInFaction'; ParamType1: ptFaction), {V} (Index: 133; Name: 'SameFactionAsPC'), {V} (Index: 134; Name: 'SameRaceAsPC'), {V} (Index: 135; Name: 'SameSexAsPC'), {V} (Index: 136; Name: 'GetIsReference'; ParamType1: ptObjectReference), {V} (Index: 141; Name: 'IsTalking'), {V} (Index: 142; Name: 'GetWalkSpeed'), {V} (Index: 143; Name: 'GetCurrentAIProcedure'), {V} (Index: 144; Name: 'GetTrespassWarningLevel'), {V} (Index: 145; Name: 'IsTrespassing'), {V} (Index: 146; Name: 'IsInMyOwnedCell'), {V} (Index: 147; Name: 'GetWindSpeed'), {V} (Index: 148; Name: 'GetCurrentWeatherPercent'), {V} (Index: 149; Name: 'GetIsCurrentWeather'; ParamType1: ptWeather), {V} (Index: 150; Name: 'IsContinuingPackagePCNear'), {N} (Index: 152; Name: 'GetIsCrimeFaction'; ParamType1: ptFaction), {V} (Index: 153; Name: 'CanHaveFlames'), {V} (Index: 154; Name: 'HasFlames'), {V} (Index: 157; Name: 'GetOpenState'), {V} (Index: 159; Name: 'GetSitting'), {V} (Index: 161; Name: 'GetIsCurrentPackage'; ParamType1: ptPackage), {V} (Index: 162; Name: 'IsCurrentFurnitureRef'; ParamType1: ptObjectReference), {V} (Index: 163; Name: 'IsCurrentFurnitureObj'; ParamType1: ptFurniture), {V} (Index: 170; Name: 'GetDayOfWeek'), {V} (Index: 172; Name: 'GetTalkedToPCParam'; ParamType1: ptActor), {V} (Index: 175; Name: 'IsPCSleeping'), {V} (Index: 176; Name: 'IsPCAMurderer'), {N} (Index: 180; Name: 'HasSameEditorLocAsRef'; ParamType1: ptObjectReference; ParamType2: ptKeyword), {N} (Index: 181; Name: 'HasSameEditorLocAsRefAlias'; ParamType1: ptAlias; ParamType2: ptKeyword), {V} (Index: 182; Name: 'GetEquipped'; ParamType1: ptInventoryObject), {V} (Index: 185; Name: 'IsSwimming'), {V} (Index: 190; Name: 'GetAmountSoldStolen'), {V} (Index: 192; Name: 'GetIgnoreCrime'), {V} (Index: 193; Name: 'GetPCExpelled'; ParamType1: ptFaction), {V} (Index: 195; Name: 'GetPCFactionMurder'; ParamType1: ptFaction), {V} (Index: 197; Name: 'GetPCEnemyofFaction'; ParamType1: ptFaction), {V} (Index: 199; Name: 'GetPCFactionAttack'; ParamType1: ptFaction), {V} (Index: 203; Name: 'GetDestroyed'), {V} (Index: 214; Name: 'HasMagicEffect'; ParamType1: ptMagicEffect), {V} (Index: 215; Name: 'GetDefaultOpen'), {V} (Index: 219; Name: 'GetAnimAction'), {V} (Index: 223; Name: 'IsSpellTarget'; ParamType1: ptMagicItem), {V} (Index: 224; Name: 'GetVATSMode'), {V} (Index: 225; Name: 'GetPersuasionNumber'), {V} (Index: 226; Name: 'GetVampireFeed'), {V} (Index: 227; Name: 'GetCannibal'), {V} (Index: 228; Name: 'GetIsClassDefault'; ParamType1: ptClass), {V} (Index: 229; Name: 'GetClassDefaultMatch'), {V} (Index: 230; Name: 'GetInCellParam'; ParamType1: ptCell; ParamType2: ptObjectReference), {V} (Index: 235; Name: 'GetVatsTargetHeight'), {V} (Index: 237; Name: 'GetIsGhost'), {V} (Index: 242; Name: 'GetUnconscious'), {V} (Index: 244; Name: 'GetRestrained'), {V} (Index: 246; Name: 'GetIsUsedItem'; ParamType1: ptReferencableObject), {V} (Index: 247; Name: 'GetIsUsedItemType'; ParamType1: ptFormType), {N} (Index: 248; Name: 'IsScenePlaying'; ParamType1: ptScene), {N} (Index: 249; Name: 'IsInDialogueWithPlayer'), {N} (Index: 250; Name: 'GetLocationCleared'; ParamType1: ptLocation), {V} (Index: 254; Name: 'GetIsPlayableRace'), {V} (Index: 255; Name: 'GetOffersServicesNow'), {N} (Index: 258; Name: 'HasAssociationType'; ParamType1: ptActor; ParamType2: ptAssociationType), {N} (Index: 259; Name: 'HasFamilyRelationship'; ParamType1: ptActor), {N} (Index: 261; Name: 'HasParentRelationship'; ParamType1: ptActor), {N} (Index: 262; Name: 'IsWarningAbout'; ParamType1: ptFormList), {V} (Index: 263; Name: 'IsWeaponOut'), {N} (Index: 264; Name: 'HasSpell'; ParamType1: ptMagicItem), {V} (Index: 265; Name: 'IsTimePassing'), {V} (Index: 266; Name: 'IsPleasant'), {V} (Index: 267; Name: 'IsCloudy'), {N} (Index: 274; Name: 'IsSmallBump'), {V} (Index: 277; Name: 'GetBaseActorValue'; ParamType1: ptActorValue), {V} (Index: 278; Name: 'IsOwner'; ParamType1: ptOwner), {V} (Index: 280; Name: 'IsCellOwner'; ParamType1: ptCell; ParamType2: ptOwner), {V} (Index: 282; Name: 'IsHorseStolen'), {V} (Index: 285; Name: 'IsLeftUp'), {V} (Index: 286; Name: 'IsSneaking'), {V} (Index: 287; Name: 'IsRunning'), {V} (Index: 288; Name: 'GetFriendHit'), {V} (Index: 289; Name: 'IsInCombat'; ParamType1: ptInteger), {V} (Index: 300; Name: 'IsInInterior'), {V} (Index: 304; Name: 'IsWaterObject'), {N} (Index: 305; Name: 'GetPlayerAction'), {V} (Index: 306; Name: 'IsActorUsingATorch'), {V} (Index: 309; Name: 'IsXBox'), {V} (Index: 310; Name: 'GetInWorldspace'; ParamType1: ptWorldSpace), {V} (Index: 312; Name: 'GetPCMiscStat'; ParamType1: ptMiscStat), {N} (Index: 313; Name: 'GetPairedAnimation'), {V} (Index: 314; Name: 'IsActorAVictim'), {V} (Index: 315; Name: 'GetTotalPersuasionNumber'), {V} (Index: 318; Name: 'GetIdleDoneOnce'), {V} (Index: 320; Name: 'GetNoRumors'), {N} (Index: 323; Name: 'GetCombatState'), {N} (Index: 325; Name: 'GetWithinPackageLocation'; ParamType1: ptPackdata), {V} (Index: 327; Name: 'IsRidingMount'), {N} (Index: 329; Name: 'IsFleeing'), {V} (Index: 332; Name: 'IsInDangerousWater'), {V} (Index: 338; Name: 'GetIgnoreFriendlyHits'), {V} (Index: 339; Name: 'IsPlayersLastRiddenMount'), {V} (Index: 353; Name: 'IsActor'), {V} (Index: 354; Name: 'IsEssential'), {V} (Index: 358; Name: 'IsPlayerMovingIntoNewSpace'), {N} (Index: 359; Name: 'GetInCurrentLoc'; ParamType1: ptLocation), {N} (Index: 360; Name: 'GetInCurrentLocAlias'; ParamType1: ptAlias), {V} (Index: 361; Name: 'GetTimeDead'), {N} (Index: 362; Name: 'HasLinkedRef'; ParamType1: ptKeyword), {V} (Index: 365; Name: 'IsChild'), {N} (Index: 366; Name: 'GetStolenItemValueNoCrime'; ParamType1: ptFaction), {V} (Index: 367; Name: 'GetLastPlayerAction'), {V} (Index: 368; Name: 'IsPlayerActionActive'; ParamType1: ptInteger), // was ptPlayerAction {V} (Index: 370; Name: 'IsTalkingActivatorActor'; ParamType1: ptActor), {V} (Index: 372; Name: 'IsInList'; ParamType1: ptFormList), {N} (Index: 373; Name: 'GetStolenItemValue'; ParamType1: ptFaction), {N} (Index: 375; Name: 'GetCrimeGoldViolent'), {N} (Index: 376; Name: 'GetCrimeGoldNonviolent'), {N} (Index: 378; Name: 'HasShout'; ParamType1: ptShout), {V} (Index: 381; Name: 'GetHasNote'; ParamType1: ptInteger), // was ptNote {V} (Index: 390; Name: 'GetHitLocation'), {V} (Index: 391; Name: 'IsPC1stPerson'), {V} (Index: 396; Name: 'GetCauseofDeath'), {V} (Index: 397; Name: 'IsLimbGone'; ParamType1: ptInteger), // was ptBodyLocation {V} (Index: 398; Name: 'IsWeaponInList'; ParamType1: ptFormList), {N} (Index: 402; Name: 'IsBribedbyPlayer'), {V} (Index: 403; Name: 'GetRelationshipRank'; ParamType1: ptObjectReference), {V} (Index: 407; Name: 'GetVATSValue'; ParamType1: ptVATSValueFunction; ParamType2: ptVATSValueParam), {V} (Index: 408; Name: 'IsKiller'; ParamType1: ptActor), {V} (Index: 409; Name: 'IsKillerObject'; ParamType1: ptFormList), {V} (Index: 410; Name: 'GetFactionCombatReaction'; ParamType1: ptFaction; ParamType2: ptFaction), {V} (Index: 414; Name: 'Exists'; ParamType1: ptObjectReference), {V} (Index: 415; Name: 'GetGroupMemberCount'), {V} (Index: 416; Name: 'GetGroupTargetCount'), {V} (Index: 426; Name: 'GetIsVoiceType'; ParamType1: ptVoiceType), {V} (Index: 427; Name: 'GetPlantedExplosive'), {N} (Index: 429; Name: 'IsScenePackageRunning'), {V} (Index: 430; Name: 'GetHealthPercentage'), {V} (Index: 432; Name: 'GetIsObjectType'; ParamType1: ptFormType), {V} (Index: 434; Name: 'GetDialogueEmotion'), {V} (Index: 435; Name: 'GetDialogueEmotionValue'), {V} (Index: 437; Name: 'GetIsCreatureType'; ParamType1: ptInteger), {N} (Index: 444; Name: 'GetInCurrentLocFormList'; ParamType1: ptFormList), {V} (Index: 445; Name: 'GetInZone'; ParamType1: ptEncounterZone), {N} (Index: 446; Name: 'GetVelocity'; ParamType1: ptAxis), {N} (Index: 447; Name: 'GetGraphVariableFloat'; ParamType1: ptVariableName), {V} (Index: 448; Name: 'HasPerk'; ParamType1: ptPerk; ParamType2: ptInteger{Alt?}), {V} (Index: 449; Name: 'GetFactionRelation'; ParamType1: ptActor), {V} (Index: 450; Name: 'IsLastIdlePlayed'; ParamType1: ptIdleForm), {V} (Index: 453; Name: 'GetPlayerTeammate'), {V} (Index: 454; Name: 'GetPlayerTeammateCount'), {V} (Index: 458; Name: 'GetActorCrimePlayerEnemy'), {V} (Index: 459; Name: 'GetCrimeGold'), {V} (Index: 463; Name: 'IsPlayerGrabbedRef'; ParamType1: ptObjectReference), {N} (Index: 465; Name: 'GetKeywordItemCount'; ParamType1: ptKeyword), {V} (Index: 470; Name: 'GetDestructionStage'), {V} (Index: 473; Name: 'GetIsAlignment'; ParamType1: ptAlignment), {N} (Index: 476; Name: 'IsProtected'), {V} (Index: 477; Name: 'GetThreatRatio'; ParamType1: ptActor), {V} (Index: 479; Name: 'GetIsUsedItemEquipType'; ParamType1: ptEquipType), {N} (Index: 487; Name: 'IsCarryable'), {V} (Index: 488; Name: 'GetConcussed'), {V} (Index: 491; Name: 'GetMapMarkerVisible'), {N} (Index: 493; Name: 'PlayerKnows'; ParamType1: ptMagicEffect), {V} (Index: 494; Name: 'GetPermanentActorValue'; ParamType1: ptActorValue), {V} (Index: 495; Name: 'GetKillingBlowLimb'), {N} (Index: 497; Name: 'CanPayCrimeGold'), {N} (Index: 499; Name: 'GetDaysInJail'), {N} (Index: 500; Name: 'EPAlchemyGetMakingPoison'), {N} (Index: 501; Name: 'EPAlchemyEffectHasKeyword'; ParamType1: ptKeyword), {N} (Index: 503; Name: 'GetAllowWorldInteractions'), {V} (Index: 508; Name: 'GetLastHitCritical'), {N} (Index: 513; Name: 'IsCombatTarget'; ParamType1: ptActor), {V} (Index: 515; Name: 'GetVATSRightAreaFree'; ParamType1: ptObjectReference), {V} (Index: 516; Name: 'GetVATSLeftAreaFree'; ParamType1: ptObjectReference), {V} (Index: 517; Name: 'GetVATSBackAreaFree'; ParamType1: ptObjectReference), {V} (Index: 518; Name: 'GetVATSFrontAreaFree'; ParamType1: ptObjectReference), {N} (Index: 519; Name: 'GetLockIsBroken'), {N} (Index: 520; Name: 'IsPS3'), {N} (Index: 521; Name: 'IsWin32'), {V} (Index: 522; Name: 'GetVATSRightTargetVisible'; ParamType1: ptObjectReference), {V} (Index: 523; Name: 'GetVATSLeftTargetVisible'; ParamType1: ptObjectReference), {V} (Index: 524; Name: 'GetVATSBackTargetVisible'; ParamType1: ptObjectReference), {V} (Index: 525; Name: 'GetVATSFrontTargetVisible'; ParamType1: ptObjectReference), {V} (Index: 528; Name: 'IsInCriticalStage'; ParamType1: ptCriticalStage), {N} (Index: 530; Name: 'GetXPForNextLevel'), {N} (Index: 533; Name: 'GetInfamy'), {N} (Index: 534; Name: 'GetInfamyViolent'), {N} (Index: 535; Name: 'GetInfamyNonViolent'), {V} (Index: 543; Name: 'GetQuestCompleted'; ParamType1: ptQuest), {V} (Index: 547; Name: 'IsGoreDisabled'), {N} (Index: 550; Name: 'IsSceneActionComplete'; ParamType1: ptScene; ParamType2: ptInteger), {V} (Index: 552; Name: 'GetSpellUsageNum'; ParamType1: ptMagicItem), {N} (Index: 554; Name: 'GetActorsInHigh'), {V} (Index: 555; Name: 'HasLoaded3D'), {N} (Index: 560; Name: 'HasKeyword'; ParamType1: ptKeyword), {N} (Index: 561; Name: 'HasRefType'; ParamType1: ptRefType), {N} (Index: 562; Name: 'LocationHasKeyword'; ParamType1: ptKeyword), {N} (Index: 563; Name: 'LocationHasRefType'; ParamType1: ptRefType), {N} (Index: 565; Name: 'GetIsEditorLocation'; ParamType1: ptLocation), {N} (Index: 566; Name: 'GetIsAliasRef'; ParamType1: ptAlias), {N} (Index: 567; Name: 'GetIsEditorLocAlias'; ParamType1: ptAlias), {N} (Index: 568; Name: 'IsSprinting'), {N} (Index: 569; Name: 'IsBlocking'), {N} (Index: 570; Name: 'HasEquippedSpell'; ParamType1: ptCastingSource), {N} (Index: 571; Name: 'GetCurrentCastingType'; ParamType1: ptCastingSource), {N} (Index: 572; Name: 'GetCurrentDeliveryType'; ParamType1: ptCastingSource), {N} (Index: 574; Name: 'GetAttackState'), {N} (Index: 576; Name: 'GetEventData'; ParamType1: ptEvent; ParamType2: ptEventData; ParamType3: ptNone), {N} (Index: 577; Name: 'IsCloserToAThanB'; ParamType1: ptObjectReference; ParamType2: ptObjectReference), {N} (Index: 579; Name: 'GetEquippedShout'; ParamType1: ptShout), {N} (Index: 580; Name: 'IsBleedingOut'), {N} (Index: 584; Name: 'GetRelativeAngle'; ParamType1: ptObjectReference; ParamType2: ptAxis), {N} (Index: 589; Name: 'GetMovementDirection'), {N} (Index: 590; Name: 'IsInScene'), {N} (Index: 591; Name: 'GetRefTypeDeadCount'; ParamType1: ptLocation; ParamType2: ptRefType), {N} (Index: 592; Name: 'GetRefTypeAliveCount'; ParamType1: ptLocation; ParamType2: ptRefType), {N} (Index: 594; Name: 'GetIsFlying'), {N} (Index: 595; Name: 'IsCurrentSpell'; ParamType1: ptMagicItem; ParamType2: ptCastingSource), {N} (Index: 596; Name: 'SpellHasKeyword'; ParamType1: ptCastingSource; ParamType2: ptKeyword), {N} (Index: 597; Name: 'GetEquippedItemType'; ParamType1: ptCastingSource), {N} (Index: 598; Name: 'GetLocationAliasCleared'; ParamType1: ptAlias), {N} (Index: 600; Name: 'GetLocAliasRefTypeDeadCount'; ParamType1: ptAlias; ParamType2: ptRefType), {N} (Index: 601; Name: 'GetLocAliasRefTypeAliveCount'; ParamType1: ptAlias; ParamType2: ptRefType), {N} (Index: 602; Name: 'IsWardState'; ParamType1: ptWardState), {N} (Index: 603; Name: 'IsInSameCurrentLocAsRef'; ParamType1: ptObjectReference; ParamType2: ptKeyword), {N} (Index: 604; Name: 'IsInSameCurrentLocAsRefAlias'; ParamType1: ptAlias; ParamType2: ptKeyword), {N} (Index: 605; Name: 'LocAliasIsLocation'; ParamType1: ptAlias; ParamType2: ptLocation), {N} (Index: 606; Name: 'GetKeywordDataForLocation'; ParamType1: ptLocation; ParamType2: ptKeyword), {N} (Index: 608; Name: 'GetKeywordDataForAlias'; ParamType1: ptAlias; ParamType2: ptKeyword), {N} (Index: 610; Name: 'LocAliasHasKeyword'; ParamType1: ptAlias; ParamType2: ptKeyword), {N} (Index: 611; Name: 'IsNullPackageData'; ParamType1: ptPackdata), {N} (Index: 612; Name: 'GetNumericPackageData'; ParamType1: ptInteger), {N} (Index: 613; Name: 'IsFurnitureAnimType'; ParamType1: ptFurnitureAnim), {N} (Index: 614; Name: 'IsFurnitureEntryType'; ParamType1: ptFurnitureEntry), {N} (Index: 615; Name: 'GetHighestRelationshipRank'), {N} (Index: 616; Name: 'GetLowestRelationshipRank'), {N} (Index: 617; Name: 'HasAssociationTypeAny'; ParamType1: ptAssociationType), {N} (Index: 618; Name: 'HasFamilyRelationshipAny'), {N} (Index: 619; Name: 'GetPathingTargetOffset'; ParamType1: ptAxis), {N} (Index: 620; Name: 'GetPathingTargetAngleOffset'; ParamType1: ptAxis), {N} (Index: 621; Name: 'GetPathingTargetSpeed'), {N} (Index: 622; Name: 'GetPathingTargetSpeedAngle'; ParamType1: ptAxis), {N} (Index: 623; Name: 'GetMovementSpeed'), {N} (Index: 624; Name: 'GetInContainer'; ParamType1: ptObjectReference), {N} (Index: 625; Name: 'IsLocationLoaded'; ParamType1: ptLocation), {N} (Index: 626; Name: 'IsLocAliasLoaded'; ParamType1: ptAlias), {N} (Index: 627; Name: 'IsDualCasting'), {N} (Index: 629; Name: 'GetVMQuestVariable'; ParamType1: ptQuest; ParamType2: ptVariableName), {N} (Index: 630; Name: 'GetVMScriptVariable'; ParamType1: ptObjectReference; ParamType2: ptVariableName), {N} (Index: 631; Name: 'IsEnteringInteractionQuick'), {N} (Index: 632; Name: 'IsCasting'), {N} (Index: 633; Name: 'GetFlyingState'), {N} (Index: 635; Name: 'IsInFavorState'), {N} (Index: 636; Name: 'HasTwoHandedWeaponEquipped'), {N} (Index: 637; Name: 'IsExitingInstant'), {N} (Index: 638; Name: 'IsInFriendStateWithPlayer'), {N} (Index: 639; Name: 'GetWithinDistance'; ParamType1: ptObjectReference; ParamType2: ptFloat), {N} (Index: 640; Name: 'GetActorValuePercent'; ParamType1: ptActorValue), {N} (Index: 641; Name: 'IsUnique'), {N} (Index: 642; Name: 'GetLastBumpDirection'), {N} (Index: 644; Name: 'IsInFurnitureState'; ParamType1: ptFurnitureAnim), {N} (Index: 645; Name: 'GetIsInjured'), {N} (Index: 646; Name: 'GetIsCrashLandRequest'), {N} (Index: 647; Name: 'GetIsHastyLandRequest'), {N} (Index: 650; Name: 'IsLinkedTo'; ParamType1: ptObjectReference; ParamType2: ptKeyword), {N} (Index: 651; Name: 'GetKeywordDataForCurrentLocation'; ParamType1: ptKeyword), {N} (Index: 652; Name: 'GetInSharedCrimeFaction'; ParamType1: ptObjectReference), {N} (Index: 654; Name: 'GetBribeSuccess'), {N} (Index: 655; Name: 'GetIntimidateSuccess'), {N} (Index: 656; Name: 'GetArrestedState'), {N} (Index: 657; Name: 'GetArrestingActor'), {N} (Index: 659; Name: 'EPTemperingItemIsEnchanted'), {N} (Index: 660; Name: 'EPTemperingItemHasKeyword'; ParamType1: ptKeyword), {N} (Index: 664; Name: 'GetReplacedItemType'; ParamType1: ptCastingSource), {N} (Index: 672; Name: 'IsAttacking'), {N} (Index: 673; Name: 'IsPowerAttacking'), {N} (Index: 674; Name: 'IsLastHostileActor'), {N} (Index: 675; Name: 'GetGraphVariableInt'; ParamType1: ptVariableName), {N} (Index: 676; Name: 'GetCurrentShoutVariation'), {N} (Index: 678; Name: 'ShouldAttackKill'; ParamType1: ptActor), {N} (Index: 680; Name: 'GetActivatorHeight'), {N} (Index: 681; Name: 'EPMagic_IsAdvanceSkill'; ParamType1: ptActorValue), {N} (Index: 682; Name: 'WornHasKeyword'; ParamType1: ptKeyword), {N} (Index: 683; Name: 'GetPathingCurrentSpeed'), {N} (Index: 684; Name: 'GetPathingCurrentSpeedAngle'; ParamType1: ptAxis), {N} (Index: 691; Name: 'EPModSkillUsage_AdvanceObjectHasKeyword'; ParamType1: ptKeyword), {N} (Index: 692; Name: 'EPModSkillUsage_IsAdvanceAction'; ParamType1: ptAdvanceAction), {N} (Index: 693; Name: 'EPMagic_SpellHasKeyword'; ParamType1: ptKeyword), {N} (Index: 694; Name: 'GetNoBleedoutRecovery'), {N} (Index: 696; Name: 'EPMagic_SpellHasSkill'; ParamType1: ptActorValue), {N} (Index: 697; Name: 'IsAttackType'; ParamType1: ptKeyword), {N} (Index: 698; Name: 'IsAllowedToFly'), {N} (Index: 699; Name: 'HasMagicEffectKeyword'; ParamType1: ptKeyword), {N} (Index: 700; Name: 'IsCommandedActor'), {N} (Index: 701; Name: 'IsStaggered'), {N} (Index: 702; Name: 'IsRecoiling'), {N} (Index: 703; Name: 'IsExitingInteractionQuick'), {N} (Index: 704; Name: 'IsPathing'), {N} (Index: 705; Name: 'GetShouldHelp'; ParamType1: ptActor), {N} (Index: 706; Name: 'HasBoundWeaponEquipped'; ParamType1: ptCastingSource), {N} (Index: 707; Name: 'GetCombatTargetHasKeyword'; ParamType1: ptKeyword), {N} (Index: 709; Name: 'GetCombatGroupMemberCount'), {N} (Index: 710; Name: 'IsIgnoringCombat'), {N} (Index: 711; Name: 'GetLightLevel'), {N} (Index: 713; Name: 'SpellHasCastingPerk'; ParamType1: ptPerk), {N} (Index: 714; Name: 'IsBeingRidden'), {N} (Index: 715; Name: 'IsUndead'), {N} (Index: 716; Name: 'GetRealHoursPassed'), {N} (Index: 718; Name: 'IsUnlockedDoor'), {N} (Index: 719; Name: 'IsHostileToActor'; ParamType1: ptActor), {N} (Index: 720; Name: 'GetTargetHeight'; ParamType1: ptObjectReference), {N} (Index: 721; Name: 'IsPoison'), {N} (Index: 722; Name: 'WornApparelHasKeywordCount'; ParamType1: ptKeyword), {N} (Index: 723; Name: 'GetItemHealthPercent'), {N} (Index: 724; Name: 'EffectWasDualCast'), {N} (Index: 725; Name: 'GetKnockedStateEnum'), {N} (Index: 726; Name: 'DoesNotExist'), {N} (Index: 730; Name: 'IsOnFlyingMount'), {N} (Index: 731; Name: 'CanFlyHere'), {N} (Index: 732; Name: 'IsFlyingMountPatrolQueud'), {N} (Index: 733; Name: 'IsFlyingMountFastTravelling'), // Added by SKSE (Index: 1024; Name: 'GetSKSEVersion'; ), (Index: 1025; Name: 'GetSKSEVersionMinor'; ), (Index: 1026; Name: 'GetSKSEVersionBeta'; ), (Index: 1027; Name: 'GetSKSERelease'; ), (Index: 1028; Name: 'ClearInvalidRegistrations'; ) ); var wbCTDAFunctionEditInfo: string; function wbCTDAParamDescFromIndex(aIndex: Integer): PCTDAFunction; var L, H, I, C: Integer; begin Result := nil; L := Low(wbCTDAFunctions); H := High(wbCTDAFunctions); while L <= H do begin I := (L + H) shr 1; C := CmpW32(wbCTDAFunctions[I].Index, aIndex); if C < 0 then L := I + 1 else begin H := I - 1; if C = 0 then begin L := I; Result := @wbCTDAFunctions[L]; end; end; end; end; function wbCTDACompValueDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container: IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; // "use global" flag if Integer(Container.ElementByName['Type'].NativeValue) and $04 <> 0 then Result := 1; end; function wbCTDAParam1Decider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Desc: PCTDAFunction; Container: IwbContainer; ParamFlag: Byte; ParamType: TCTDAFunctionParamType; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; Desc := wbCTDAParamDescFromIndex(Container.ElementByName['Function'].NativeValue); if Assigned(Desc) then begin ParamType := Desc.ParamType1; ParamFlag := Container.ElementByName['Type'].NativeValue; if ParamType in [ptObjectReference, ptActor, ptPackage] then begin if ParamFlag and $02 > 0 then ParamType := ptAlias else {>>> 'use aliases' is set <<<} if ParamFlag and $08 > 0 then ParamType := ptPackdata; {>>> 'use packdata' is set <<<} end; Result := Succ(Integer(ParamType)); end; end; function wbCTDAParam2Decider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Desc: PCTDAFunction; Container: IwbContainer; ParamFlag: Byte; ParamType: TCTDAFunctionParamType; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; Desc := wbCTDAParamDescFromIndex(Container.ElementByName['Function'].NativeValue); if Assigned(Desc) then begin ParamType := Desc.ParamType2; ParamFlag := Container.ElementByName['Type'].NativeValue; if ParamType in [ptObjectReference, ptActor, ptPackage] then begin if ParamFlag and $02 > 0 then ParamType := ptAlias else {>>> 'use aliases' is set <<<} if ParamFlag and $08 > 0 then ParamType := ptPackdata; {>>> 'use packdata' is set <<<} end; Result := Succ(Integer(ParamType)); end; end; function wbCTDAParam2VATSValueParamDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; Result := Container.ElementByName['Parameter #1'].NativeValue; end; function wbCTDAFunctionToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; var Desc : PCTDAFunction; i : Integer; begin Result := ''; case aType of ctToStr, ctToEditValue: begin Desc := wbCTDAParamDescFromIndex(aInt); if Assigned(Desc) then Result := Desc.Name else if aType = ctToEditValue then Result := IntToStr(aInt) else Result := ''; end; ctToSortKey: Result := IntToHex(aInt, 8); ctCheck: begin Desc := wbCTDAParamDescFromIndex(aInt); if Assigned(Desc) then Result := '' else Result := ''; end; ctEditType: Result := 'ComboBox'; ctEditInfo: begin Result := wbCTDAFunctionEditInfo; if Result = '' then begin with TStringList.Create do try for i := Low(wbCTDAFunctions) to High(wbCTDAFunctions) do Add(wbCTDAFunctions[i].Name); Sort; Result := CommaText; finally Free; end; wbCTDAFunctionEditInfo := Result; end; end; end; end; function wbCTDAFunctionToInt(const aString: string; const aElement: IwbElement): Int64; var i: Integer; begin for i := Low(wbCTDAFunctions) to High(wbCTDAFunctions) do with wbCTDAFunctions[i] do if SameText(Name, aString) then begin Result := Index; Exit; end; Result := StrToInt64(aString); end; function wbNeverShow(const aElement: IwbElement): Boolean; begin Result := wbHideNeverShow; end; function GetREGNType(aElement: IwbElement): Integer; var Container: IwbContainerElementRef; begin Result := -1; if not Assigned(aElement) then Exit; while aElement.Name <> 'Region Data Entry' do begin aElement := aElement.Container; if not Assigned(aElement) then Exit; end; if not Supports(aElement, IwbContainerElementRef, Container) then Exit; Result := Container.ElementNativeValues['RDAT\Type']; end; function wbREGNObjectsDontShow(const aElement: IwbElement): Boolean; begin Result := GetREGNType(aElement) <> 2; end; function wbREGNWeatherDontShow(const aElement: IwbElement): Boolean; begin Result := GetREGNType(aElement) <> 3; end; function wbREGNMapDontShow(const aElement: IwbElement): Boolean; begin Result := GetREGNType(aElement) <> 4; end; function wbREGNLandDontShow(const aElement: IwbElement): Boolean; begin Result := GetREGNType(aElement) <> 5; end; function wbREGNGrassDontShow(const aElement: IwbElement): Boolean; begin Result := GetREGNType(aElement) <> 6; end; function wbREGNSoundDontShow(const aElement: IwbElement): Boolean; begin Result := GetREGNType(aElement) <> 7; end; function wbREGNImposterDontShow(const aElement: IwbElement): Boolean; begin Result := GetREGNType(aElement) <> 8; end; function wbMESGTNAMDontShow(const aElement: IwbElement): Boolean; var Container : IwbContainerElementRef; MainRecord : IwbMainRecord; begin Result := False; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Integer(Container.ElementNativeValues['DNAM']) and 1 <> 0 then Result := True; end; function wbEPFDDontShow(const aElement: IwbElement): Boolean; var Container: IwbContainerElementRef; begin Result := False; if aElement.Name <> 'Entry Point Function Parameters' then Exit; if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if not (Integer(Container.ElementNativeValues['EPFT']) in [1..3]) then Result := True; end; function wbTES4ONAMDontShow(const aElement: IwbElement): Boolean; var MainRecord : IwbMainRecord; begin Result := False; if not Assigned(aElement) then Exit; MainRecord := aElement.ContainingMainRecord; if not Assigned(MainRecord) then Exit; if not MainRecord.IsESM then Result := True; end; function wbEPF2DontShow(const aElement: IwbElement): Boolean; var Container: IwbContainerElementRef; begin Result := False; if aElement.Name <> 'Entry Point Function Parameters' then Exit; if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if not (Integer(Container.ElementNativeValues['EPFT']) in [4]) then Result := True; end; procedure wbRemoveOFST(const aElement: IwbElement); var Container: IwbContainer; rOFST: IwbRecord; begin if not wbRemoveOffsetData then Exit; if Supports(aElement, IwbContainer, Container) then begin if wbBeginInternalEdit then try Container.RemoveElement(OFST); finally wbEndInternalEdit; end else begin rOFST := Container.RecordBySignature[OFST]; if Assigned(rOFST) then Container.RemoveElement(rOFST); end; end; end; procedure wbWRLDAfterLoad(const aElement: IwbElement); function OutOfRange(aValue: Integer; aRange: Integer = 256): Boolean; begin Result := (aValue < -aRange) or (aValue > aRange); end; var MainRecord: IwbMainRecord; Container: IwbContainer; begin wbRemoveOFST(aElement); if wbBeginInternalEdit then try if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; // not used in Skyrim if MainRecord.ElementExists['Unused RNAM'] then MainRecord.RemoveElement('Unused RNAM'); // used in SSE but remove from the game master to speed up worldspace browsing since it is huge // and the game master is never saved anyway if IsSSE and (MainRecord._File.LoadOrder = 0) then MainRecord.RemoveElement('Large References'); // large values in object bounds cause stutter and performance issues in game (reported by Arthmoor) // CK can occasionally set them wrong, so make a warning if Supports(MainRecord.ElementByName['Object Bounds'], IwbContainer, Container) then if OutOfRange(StrToIntDef(Container.ElementEditValues['NAM0\X'], 0)) or OutOfRange(StrToIntDef(Container.ElementEditValues['NAM0\Y'], 0)) or OutOfRange(StrToIntDef(Container.ElementEditValues['NAM9\X'], 0)) or OutOfRange(StrToIntDef(Container.ElementEditValues['NAM9\Y'], 0)) then wbProgressCallback(''); finally wbEndInternalEdit; end; end; procedure wbDOBJObjectsAfterLoad(const aElement: IwbElement); var ObjectsContainer : IwbContainerElementRef; i : Integer; ObjectContainer : IwbContainerElementRef; begin wbRemoveOFST(aElement); if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, ObjectsContainer) then Exit; for i := Pred(ObjectsContainer.ElementCount) downto 0 do if Supports(ObjectsContainer.Elements[i], IwbContainerElementRef, ObjectContainer) then if ObjectContainer.ElementNativeValues['Use'] = 0 then ObjectsContainer.RemoveElement(i, True); finally wbEndInternalEdit; end; end; function wbActorTemplateUseTraits(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; Element := aElement; MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000001) <> 0; end; end; function wbActorTemplateUseStats(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; Element := aElement; MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000002) <> 0; end; end; function wbActorAutoCalcDontShow(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; Element := aElement; MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Flags']; Result := (i and $00000010) <> 0; end; end; function wbActorTemplateUseStatsAutoCalc(const aElement: IwbElement): Boolean; begin Result := wbActorTemplateUseStats(aElement) or wbActorAutoCalcDontShow(aElement); end; function wbActorTemplateUseFactions(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; Element := aElement; MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000004) <> 0; end; end; function wbActorTemplateUseActorEffectList(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; Element := aElement; MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000008) <> 0; end; end; function wbActorTemplateUseAIData(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; Element := aElement; MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000010) <> 0; end; end; function wbActorTemplateUseAIPackages(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; Element := aElement; MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000020) <> 0; end; end; function wbActorTemplateUseModelAnimation(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; Element := aElement; MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000040) <> 0; end; end; function wbActorTemplateUseBaseData(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; Element := aElement; MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000080) <> 0; end; end; function wbActorTemplateUseInventory(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; Element := aElement; MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000100) <> 0; end; end; function wbActorTemplateUseScript(const aElement: IwbElement): Boolean; var Element : IwbElement; MainRecord : IwbMainRecord; i : Int64; begin Result := False; Element := aElement; MainRecord := nil; while Assigned(Element) and not Supports(Element, IwbMainRecord, MainRecord) do Element := Element.Container; if Assigned(MainRecord) then begin i := MainRecord.ElementNativeValues['ACBS\Template Flags']; Result := (i and $00000200) <> 0; end; end; procedure wbRemoveEmptyKWDA(const aElement: IwbElement); var Container : IwbContainerElementRef; MainRecord : IwbMainRecord; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; if not Assigned(Container.ElementBySignature['KSIZ']) then if Assigned(Container.ElementBySignature['KWDA']) then Container.ElementBySignature['KWDA'].Remove; finally wbEndInternalEdit; end; end; procedure wbReplaceBODTwithBOD2(const aElement: IwbElement); var MainRecord : IwbMainRecord; ContainerBOD2 : IwbContainerElementRef; ContainerBODT : IwbContainerElementRef; begin Exit; {>>> Looks like causes problems with Dawnguard.esm <<<} if wbBeginInternalEdit then try if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if not Supports(MainRecord.ElementBySignature[BODT], IwbContainerElementRef, ContainerBODT) then Exit; if Supports(MainRecord.Add('BOD2', True), IwbContainerElementRef, ContainerBOD2) then begin ContainerBOD2.ElementNativeValues['First Person Flags'] := ContainerBODT.ElementNativeValues['First Person Flags']; ContainerBOD2.ElementNativeValues['Armor Type'] := ContainerBODT.ElementNativeValues['Armor Type']; MainRecord.RemoveElement(BODT); end; finally wbEndInternalEdit; end; end; procedure wbARMOAfterLoad(const aElement: IwbElement); begin wbRemoveEmptyKWDA(aElement); wbReplaceBODTwithBOD2(aElement); end; procedure wbARMAAfterLoad(const aElement: IwbElement); {var MainRecord : IwbMainRecord;} begin wbReplaceBODTwithBOD2(aElement); {if wbBeginInternalEdit then try if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.ElementNativeValues['DNAM\Weight slider - Male'] = 0 then MainRecord.ElementNativeValues['DNAM\Weight slider - Male'] := 2; if MainRecord.ElementNativeValues['DNAM\Weight slider - Female'] = 0 then MainRecord.ElementNativeValues['DNAM\Weight slider - Female'] := 2; finally wbEndInternalEdit; end;} end; procedure wbNPCAfterLoad(const aElement: IwbElement); begin wbRemoveEmptyKWDA(aElement); end; procedure wbREFRAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; MainRecord : IwbMainRecord; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; if Container.ElementExists['XLOC'] then begin if Container.ElementNativeValues['XLOC - Lock Data\Level'] = 0 then Container.ElementNativeValues['XLOC - Lock Data\Level'] := 1; end; Container.RemoveElement('XPTL'); finally wbEndInternalEdit; end; end; procedure wbRACEAfterLoad(const aElement: IwbElement); begin wbReplaceBODTwithBOD2(aElement); end; procedure wbWEAPAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; MainRecord : IwbMainRecord; Flags : Cardinal; begin wbRemoveEmptyKWDA(aElement); if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; // clear IronSights flags which are randomly assigned in CK if Container.ElementExists['DNAM'] then begin Flags := Container.ElementNativeValues['DNAM - Data\Flags']; Flags := Flags and ($FFFF xor $0040); Container.ElementNativeValues['DNAM - Data\Flags'] := Flags; Flags := Container.ElementNativeValues['DNAM - Data\Flags2']; Flags := Flags and ($FFFFFFFF xor $0100); Container.ElementNativeValues['DNAM - Data\Flags2'] := Flags; end; finally wbEndInternalEdit; end; end; procedure wbCELLXCLWGetConflictPriority(const aElement: IwbElement; var aCP: TwbConflictPriority); var Container : IwbContainerElementRef; MainRecord : IwbMainRecord; DataRec : IwbElement; Flags : Cardinal; begin if not Assigned(aElement) then Exit; if not Supports(aElement.Container, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(Container, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; DataRec := MainRecord.ElementBySignature[DATA]; if not Assigned(DataRec) then Exit; Flags := DataRec.NativeValue; {0x0001 Is Interior Cell} if (Flags and 1) = 1 then {Interior cells don't use water level in Skyrim at all} aCP := cpIgnore; end; procedure wbCELLDATAAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var Container : IwbContainer; begin if not Assigned(aElement) then Exit; Container := aElement.Container; while Assigned(Container) and not (Container.Def.DefType = dtRecord) do Container := Container.Container; if Assigned(Container) then Container.ResetConflict; end; procedure wbCELLAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; // Container2 : IwbContainerElementRef; MainRecord : IwbMainRecord; DataSubRec : IwbSubrecord; Flags8 : Byte; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; if Supports(Container.ElementBySignature['DATA'] , IwbSubRecord, DataSubRec) then begin // expand legacy itU8 flags to itU16 if DataSubRec.SubRecordHeaderSize = 1 then begin Flags8 := PByte(DataSubRec.DataBasePtr)^; DataSubRec.SetToDefault; DataSubRec.NativeValue := Flags8; end; // 'Default' water height for exterior cells if not set (so water height will be taken from WRLD by game) if (not Container.ElementExists['XCLW']) and ((Integer(DataSubRec.NativeValue) and $02) <> 0) then begin Container.Add('XCLW', True); Container.ElementEditValues['XCLW'] := 'Default'; end; end; // Min (-0 as in CK) water height is set to 0 when saving in CK if Container.ElementEditValues['XCLW'] = 'Min' then Container.ElementEditValues['XCLW'] := '0.0'; // if Supports(Container.ElementBySignature[XCLR], IwbContainerElementRef, Container2) then begin // for i := Pred(Container2.ElementCount) downto 0 do // if not Supports(Container2.Elements[i].LinksTo, IwbMainRecord, MainRecord) or (MainRecord.Signature <> 'REGN') then // Container2.RemoveElement(i); // if Container2.ElementCount < 1 then // Container2.Remove; // end; finally wbEndInternalEdit; end; end; procedure wbMESGAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; MainRecord : IwbMainRecord; IsMessageBox : Boolean; HasTimeDelay : Boolean; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; IsMessageBox := (Integer(Container.ElementNativeValues['DNAM']) and 1) = 1; HasTimeDelay := Container.ElementExists['TNAM']; if IsMessageBox = HasTimeDelay then if IsMessageBox then Container.RemoveElement('TNAM') else begin if not Container.ElementExists['DNAM'] then Container.Add('DNAM', True); Container.ElementNativeValues['DNAM'] := Integer(Container.ElementNativeValues['DNAM']) or 1; end; finally wbEndInternalEdit; end; end; {>>> Updated, but not called for Skyrim Why is it required to fix particle counts? Because 1 pass = 79 particles? >>>} //procedure wbEFSHAfterLoad(const aElement: IwbElement); //var // Container: IwbContainerElementRef; // MainRecord : IwbMainRecord; // FullParticleBirthRatio : Extended; // PersistantParticleCount : Extended; //begin // if wbBeginInternalEdit then try // if not Supports(aElement, IwbContainerElementRef, Container) then // Exit; // // if Container.ElementCount < 1 then // Exit; // // if not Supports(aElement, IwbMainRecord, MainRecord) then // Exit; // // if MainRecord.IsDeleted then // Exit; // // if not Container.ElementExists['DATA'] then // Exit; // // FullParticleBirthRatio := Container.ElementNativeValues['DATA\Particle Shader - Full Particle Birth Ratio']; // PersistantParticleCount := Container.ElementNativeValues['DATA\Particle Shader - Persistant Particle Count']; // // if ((FullParticleBirthRatio <> 0) and (FullParticleBirthRatio <= 1)) then begin // FullParticleBirthRatio := FullParticleBirthRatio * 78.0; // Container.ElementNativeValues['DATA\Particle Shader - Full Particle Birth Ratio'] := FullParticleBirthRatio; // end; // // if ((PersistantParticleCount <> 0) and (PersistantParticleCount <= 1)) then begin // PersistantParticleCount := PersistantParticleCount * 78.0; // Container.ElementNativeValues['DATA\Particle Shader - Persistant Particle Count'] := PersistantParticleCount; // end; // // finally // wbEndInternalEdit; // end; //end; procedure wbLIGHAfterLoad(const aElement: IwbElement); var Container: IwbContainerElementRef; MainRecord : IwbMainRecord; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; if not Supports(aElement, IwbMainRecord, MainRecord) then Exit; if MainRecord.IsDeleted then Exit; if not Container.ElementExists['FNAM'] then begin Container.Add('FNAM', True); Container.ElementNativeValues['FNAM'] := 1.0; end; if Container.ElementExists['DATA'] then begin if SameValue(Container.ElementNativeValues['DATA\Falloff Exponent'], 0.0) then Container.ElementNativeValues['DATA\Falloff Exponent'] := 1.0; if SameValue(Container.ElementNativeValues['DATA\FOV'], 0.0) then Container.ElementNativeValues['DATA\FOV'] := 90.0; end; finally wbEndInternalEdit; end; end; procedure wbEFITAfterLoad(const aElement: IwbElement); var Container : IwbContainerElementRef; Element : IwbElement; ActorValue: Variant; MainRecord: IwbMainRecord; begin if wbBeginInternalEdit then try if not Supports(aElement, IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; MainRecord := Container.ContainingMainRecord; if not Assigned(MainRecord) or MainRecord.IsDeleted then Exit; Element := Container.ElementByPath['..\EFID']; if not Assigned(Element) then Exit; if not Supports(Element.LinksTo, IwbMainRecord, MainRecord) then Exit; if MainRecord.Signature <> 'MGEF' then Exit; ActorValue := MainRecord.ElementNativeValues['DATA - Data\Actor Value']; if VarIsNull(ActorValue) or VarIsClear(ActorValue) then Exit; if VarCompareValue(ActorValue, Container.ElementNativeValues['Actor Value']) <> vrEqual then Container.ElementNativeValues['Actor Value'] := ActorValue; finally wbEndInternalEdit; end; end; procedure wbRPLDAfterLoad(const aElement: IwbElement); var Container: IwbContainer; a, b: Single; NeedsFlip: Boolean; begin if wbBeginInternalEdit then try if Supports(aElement, IwbContainer, Container) then begin NeedsFlip := False; if Container.ElementCount > 1 then begin a := StrToFloat((Container.Elements[0] as IwbContainer).Elements[0].Value); b := StrToFloat((Container.Elements[Pred(Container.ElementCount)] as IwbContainer).Elements[0].Value); case CompareValue(a, b) of EqualsValue: begin a := StrToFloat((Container.Elements[0] as IwbContainer).Elements[1].Value); b := StrToFloat((Container.Elements[Pred(Container.ElementCount)] as IwbContainer).Elements[1].Value); NeedsFlip := CompareValue(a, b) = GreaterThanValue; end; GreaterThanValue: NeedsFlip := True; end; end; if NeedsFlip then Container.ReverseElements; end; finally wbEndInternalEdit; end; end; function wbPubPackCNAMDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var rANAM: IwbRecord; ctype: string; begin Result := 0; rANAM := aElement.Container.RecordBySignature[ANAM]; if Assigned(rANAM) then begin ctype := rANAM.NativeValue; if ctype = 'Bool' then Result := 1 else if ctype = 'Int' then Result := 2 else if ctype = 'Float' then Result := 3 else if ctype = 'ObjectList' then Result := 3; end; end; function wbTypeDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; var Container : IwbContainer; Element : IwbElement; begin Result := 0; if not Assigned(aElement) then Exit; Container := GetContainerFromUnion(aElement); if not Assigned(Container) then Exit; Element := Container.ElementByName['Type']; if Assigned(Element) then Result := Element.NativeValue else if wbMoreInfoForDecider then wbProgressCallback('"'+Container.Name+'" does not contain an element named Type'); end; procedure wbCNTOsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterAfterSet('COCT - Count', aElement); end; procedure wbContainerAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterContainerAfterSet('COCT - Count', 'Items', aElement); wbCounterContainerAfterSet('KSIZ - Keyword Count', 'KWDA - Keywords', aElement); end; procedure wbSPLOsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterAfterSet('SPCT - Count', aElement); end; procedure wbKWDAsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterAfterSet('KSIZ - Keyword Count', aElement); end; procedure wbNPCAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterContainerAfterSet('COCT - Count', 'Items', aElement); wbCounterContainerAfterSet('SPCT - Count', 'Actor Effects', aElement); wbCounterContainerAfterSet('LLCT - Count', 'Leveled List Entries', aElement); wbCounterContainerAfterSet('KSIZ - Keyword Count', 'KWDA - Keywords', aElement); wbCounterContainerAfterSet('PRKZ - Perk Count', 'Perks', aElement); end; procedure wbRaceAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterContainerAfterSet('SPCT - Count', 'Actor Effects', aElement); wbCounterContainerAfterSet('KSIZ - Keyword Count', 'KWDA - Keywords', aElement); end; procedure wbKeywordsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterContainerAfterSet('KSIZ - Keyword Count', 'KWDA - Keywords', aElement); end; procedure wbLVLOsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterAfterSet('LLCT - Count', aElement); end; procedure wbLLEAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterContainerAfterSet('LLCT - Count', 'Leveled List Entries', aElement); end; procedure wbPRKRsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterAfterSet('PRKZ - Perk Count', aElement); end; procedure wbSMQNQuestsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterAfterSet('QNAM - Quest Count', aElement); end; procedure wbCTDAsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterAfterSet('CITC - Condition Count', aElement); end; procedure wbConditionsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterContainerAfterSet('CITC - Condition Count', 'Conditions', aElement); end; procedure wbCounterEffectsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin // if it is really possible to have both counter effects and multiple data, this is going to be tricky. wbCounterByPathAfterSet('Magic Effect Data\DATA - Data\Counter effect count', aElement); end; procedure wbMGEFAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbKeywordsAfterSet(aElement, aOldValue, aNewValue); wbCounterContainerByPathAfterSet('Magic Effect Data\DATA - Data\Counter effect count', 'Counter Effects', aElement); end; procedure wbLENSAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin wbCounterAfterSet('LFSP - Count', aElement); end; procedure wbIDLAsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var Element : IwbElement; Container : IwbContainer; SelfAsContainer : IwbContainer; begin if wbBeginInternalEdit then try if not wbCounterAfterSet('IDLC - Animation Count', aElement) then if Supports(aElement.Container, IwbContainer, Container) then begin Element := Container.ElementByPath['IDLC\Animation Count']; if Assigned(Element) and Supports(aElement, IwbContainer, SelfAsContainer) and (Element.GetNativeValue<>SelfAsContainer.GetElementCount) then Element.SetNativeValue(SelfAsContainer.GetElementCount); end; finally wbEndInternalEdit; end; end; procedure wbAnimationsAfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); var Element : IwbElement; Elems : IwbElement; Container : IwbContainer; begin if wbBeginInternalEdit then try if not wbCounterContainerAfterSet('IDLC - Animation Count', 'IDLA - Animations', aElement) then if Supports(aElement, IwbContainer, Container) then begin Element := Container.ElementByPath['IDLC\Animation Count']; Elems := Container.ElementByName['IDLA - Animations']; if Assigned(Element) and not Assigned(Elems) then if Element.GetNativeValue<>0 then Element.SetNativeValue(0); end; finally wbEndInternalEdit; end; end; function wbOffsetDataColsCounter(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Cardinal; var Container : IwbDataContainer; Element : IwbElement; fResult : Extended; begin Result := 0; if Supports(aElement.Container, IwbDataContainer, Container) and (Container.Name = 'OFST - Offset Data') and Supports(Container.Container, IwbDataContainer, Container) then begin Element := Container.ElementByPath['Object Bounds\NAM0 - Min\X']; if Assigned(Element) then begin fResult := Element.NativeValue; if fResult >= MaxInt then Result := 0 else Result := Trunc(fResult); Element := Container.ElementByPath['Object Bounds\NAM9 - Max\X']; if Assigned(Element) then begin fResult := Element.NativeValue; if fResult >= MaxInt then Result := 1 else Result := Trunc(fResult) - Result + 1; end; end; end; end; function wbREFRRecordFlagsDecider(const aElement: IwbElement): Integer; var MainRecord : IwbMainRecord; NameRec : IwbElement; begin Result := 0; if not Assigned(aElement) then Exit; MainRecord := aElement.ContainingMainRecord; if not Assigned(MainRecord) then Exit; NameRec := MainRecord.ElementBySignature[NAME]; if not Assigned(NameRec) then Exit; if not Supports(NameRec.LinksTo, IwbMainRecord, MainRecord) then Exit; if (MainRecord.Signature = ACTI) or (MainRecord.Signature = STAT) or (MainRecord.Signature = TREE) then Result := 1 else if MainRecord.Signature = CONT then Result := 2 else if MainRecord.Signature = DOOR then Result := 3 else if MainRecord.Signature = LIGH then Result := 4 else if MainRecord.Signature = MSTT then Result := 5 else if MainRecord.Signature = ADDN then Result := 6 else if (MainRecord.Signature = SCRL) or (MainRecord.Signature = AMMO) or (MainRecord.Signature = ARMO) or (MainRecord.Signature = BOOK) or (MainRecord.Signature = INGR) or (MainRecord.Signature = KEYM) or (MainRecord.Signature = MISC) or (MainRecord.Signature = SLGM) or (MainRecord.Signature = WEAP) or (MainRecord.Signature = ALCH) then Result := 7; end; function wbByteColors(const aName: string = 'Color'): IwbStructDef; begin Result := wbStruct(aName, [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unused', 1) ]); end; function wbFloatColors(const aName: string = 'Color'): IwbStructDef; begin Result := wbStruct(aName, [ wbFloat('Red', cpNormal, True, 255, 0), wbFloat('Green', cpNormal, True, 255, 0), wbFloat('Blue', cpNormal, True, 255, 0) ]); end; function wbWeatherColors(const aName: string): IwbStructDef; begin Result := wbStruct(aName, [ wbByteColors('Sunrise'), wbByteColors('Day'), wbByteColors('Sunset'), wbByteColors('Night') ], cpNormal, True); end; function wbAmbientColors(const aSignature: TwbSignature; const aName: string = 'Directional Ambient Lighting Colors'): IwbSubRecordDef; overload; begin Result := wbStruct(aSignature, aName, [ wbStruct('Directional', [ wbByteColors('X+'), wbByteColors('X-'), wbByteColors('Y+'), wbByteColors('Y-'), wbByteColors('Z+'), wbByteColors('Z-') ]), wbByteColors('Specular'), wbFloat('Scale') ], cpNormal, False, nil, 1) end; function wbAmbientColors(const aName: string = 'Directional Ambient Lighting Colors'): IwbStructDef; overload; begin Result := wbStruct(aName, [ wbStruct('Directional', [ wbByteColors('X+'), wbByteColors('X-'), wbByteColors('Y+'), wbByteColors('Y-'), wbByteColors('Z+'), wbByteColors('Z-') ]), wbByteColors('Specular'), wbFloat('Scale', cpIgnore) ], cpNormal, False, nil, 1); end; function wbStrToInt(const aString: string; const aElement: IwbElement): Int64; var s: string; i: integer; begin // ignore anything after space or : i := Pos(' ', aString); if i = 0 then i := Pos(':', aString); if i <> 0 then s := Copy(aString, 1, i - 1) else s := aString; try Result := StrToInt64(s) except Result := 0; end; end; type TFaceGenFeature = record RaceID : String; Female : Boolean; Entries : array of record Index: Cardinal; Name : String; end; end; PFaceGenFeature = ^TFaceGenFeature; var // cache of race specific tint layers TintLayers: array of TFaceGenFeature; function wbTintLayerToStr(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; function GetCached(const aRaceID: string; aFemale: boolean): PFaceGenFeature; var i: integer; begin Result := nil; if Length(TintLayers) <> 0 then for i := Low(TintLayers) to High(TintLayers) do if (TintLayers[i].Female = aFemale) and (TintLayers[i].RaceID = aRaceID) then begin Result := @TintLayers[i]; Break; end; end; var Actor, Race : IwbMainRecord; Element : IwbElement; Container, Entry : IwbContainerElementRef; Female, Female2 : Boolean; RaceID, EntryName : string; s : string; Cache : PFaceGenFeature; Index : Cardinal; i, j : integer; begin // defaults case aType of ctToStr, ctToEditValue: Result := IntToStr(aInt); ctToSortKey: begin Result := IntToHex64(aInt, 8); Exit; end; ctCheck: Result := ''; ctEditType: Result := ''; ctEditInfo: Result := ''; end; Actor := aElement.ContainingMainRecord; if not Assigned(Actor) then Exit; Female := Actor.ElementEditValues['ACBS\Flags\Female'] = '1'; Element := Actor.ElementBySignature['RNAM']; if not Assigned(Element) then Exit; Element := Element.LinksTo; if not Supports(Element, IwbMainRecord, Race) then Exit; Race := Race.WinningOverride; RaceID := Race.EditorID; Cache := GetCached(RaceID, Female); // cache not found, fill with data from RACE if not Assigned(Cache) then begin for i := 0 to 1 do begin Female2 := i = 1; SetLength(TintLayers, Succ(Length(TintLayers))); Cache := @TintLayers[Pred(Length(TintLayers))]; Cache.RaceID := RaceID; Cache.Female := Female2; if not Female2 then Element := Race.ElementByPath['Head Data\Male Head Data\Tint Masks'] else Element := Race.ElementByPath['Head Data\Female Head Data\Tint Masks']; if not Supports(Element, IwbContainerElementRef, Container) then Continue; SetLength(Cache.Entries, Container.ElementCount); for j := 0 to Pred(Container.ElementCount) do begin if not Supports(Container.Elements[j], IwbContainerElementRef, Entry) then Break; Cache.Entries[j].Index := Entry.ElementNativeValues['Tint Layer\Texture\TINI']; s := Entry.ElementEditValues['Tint Layer\Texture\TINP']; // add texture name if s <> '' then s := '[' + s + '] '; s := s + ChangeFileExt(ExtractFileName(Entry.ElementEditValues['Tint Layer\Texture\TINT']), ''); Cache.Entries[j].Name := s; end; end; Cache := GetCached(RaceID, Female); end; if not Assigned(Cache) then Exit; EntryName := ''; Index := Cardinal(aInt); if Length(Cache.Entries) <> 0 then for i := Low(Cache.Entries) to High(Cache.Entries) do if Cache.Entries[i].Index = Index then begin EntryName := Cache.Entries[i].Name; Break; end; case aType of ctToStr: begin if EntryName <> '' then Result := IntToStr(aInt) + ' ' + EntryName else Result := IntToStr(aInt) + ' '; end; ctCheck: begin if EntryName = '' then Result := '' else Result := ''; end; ctEditType: Result := 'ComboBox'; ctEditInfo: begin Result := ''; if Length(Cache.Entries) <> 0 then for i := Low(Cache.Entries) to High(Cache.Entries) do begin if Result <> '' then Result := Result + ','; Result := Result + '"' + IntToStr(Cache.Entries[i].Index) + ' ' + Cache.Entries[i].Name + '"'; end; end; end; end; var wbRecordFlagsFlags : IwbFlagsDef; procedure DefineTES5a; begin wbNull := wbByteArray('Unused', -255); wbLLCT := wbInteger(LLCT, 'Count', itU8, nil, cpBenign); wbCITC := wbInteger(CITC, 'Condition Count', itU32, nil, cpBenign); wbLVLD := wbInteger(LVLD, 'Chance None', itU8, nil, cpNormal, True); wbSPCT := wbInteger(SPCT, 'Count', itU32, nil, cpBenign); wbSPLO := wbFormIDCk(SPLO, 'Actor Effect', [SPEL, SHOU, LVSP]); wbSPLOs := wbRArrayS('Actor Effects', wbSPLO, cpNormal, False, nil, wbSPLOsAfterSet, nil{wbActorTemplateUseActorEffectList}); wbKSIZ := wbInteger(KSIZ, 'Keyword Count', itU32, nil, cpBenign); wbKWDAs := wbArrayS(KWDA, 'Keywords', wbFormIDCk('Keyword', [KYWD, NULL]), 0, cpNormal, False, nil, wbKWDAsAfterSet); wbReqKWDAs := wbArrayS(KWDA, 'Keywords', wbFormIDCk('Keyword', [KYWD, NULL]), 0, cpNormal, True, nil, wbKWDAsAfterSet); wbKeywords := wbRStruct('Keywords', [ wbKSIZ, wbReqKWDAs ], []); wbCOED := wbStructExSK(COED, [2], [0, 1], 'Extra Data', [ {00} wbFormIDCkNoReach('Owner', [NPC_, FACT, NULL]), {04} wbUnion('Global Variable / Required Rank', wbCOEDOwnerDecider, [ wbByteArray('Unused', 4, cpIgnore), wbFormIDCk('Global Variable', [GLOB, NULL]), wbInteger('Required Rank', itS32) ]), {08} wbFloat('Item Condition') ]); wbCNTO := wbRStructExSK([0], [1], 'Item', [ wbStructExSK(CNTO, [0], [1], 'Item', [ wbFormIDCk('Item', [ARMO, AMMO, APPA, MISC, WEAP, BOOK, LVLI, KEYM, ALCH, INGR, LIGH, SLGM, SCRL]), wbInteger('Count', itS32) ]), wbCOED ], []); wbCOCT := wbInteger(COCT, 'Count', itU32, nil, cpBenign); wbCNTOs := wbRArrayS('Items', wbCNTO, cpNormal, False, nil, wbCNTOsAfterSet); wbArmorTypeEnum := wbEnum([ 'Light Armor', 'Heavy Armor', 'Clothing' ]); {>>> When NAME is user defined these will be incorrect <<<} wbBipedObjectEnum := wbEnum([ '30 - Head', '31 - Hair', '32 - Body', '33 - Hands', '34 - Forearms', '35 - Amulet', '36 - Ring', '37 - Feet', '38 - Calves', '39 - Shield', '40 - Tail', '41 - LongHair', '42 - Circlet', '43 - Ears', '44 - Unnamed', '45 - Unnamed', '46 - Unnamed', '47 - Unnamed', '48 - Unnamed', '49 - Unnamed', '50 - DecapitateHead', '51 - Decapitate', '52 - Unnamed', '53 - Unnamed', '54 - Unnamed', '55 - Unnamed', '56 - Unnamed', '57 - Unnamed', '58 - Unnamed', '59 - Unnamed', '60 - Unnamed', '61 - FX01' ], [ -1, 'None' ]); wbBipedObjectFlags := wbFlags([ {0x00000001} '30 - Head', {0x00000002} '31 - Hair', {0x00000004} '32 - Body', {0x00000008} '33 - Hands', {0x00000010} '34 - Forearms', {0x00000020} '35 - Amulet', {0x00000040} '36 - Ring', {0x00000080} '37 - Feet', {0x00000100} '38 - Calves', {0x00000200} '39 - Shield', {0x00000400} '40 - Tail', {0x00000800} '41 - LongHair', {0x00001000} '42 - Circlet', {0x00002000} '43 - Ears', {0x00004000} '44 - Unnamed', {0x00008000} '45 - Unnamed', {0x00010000} '46 - Unnamed', {0x00020000} '47 - Unnamed', {0x00040000} '48 - Unnamed', {0x00080000} '49 - Unnamed', {0x00100000} '50 - DecapitateHead', {0x00200000} '51 - Decapitate', {0x00400000} '52 - Unnamed', {0x00800000} '53 - Unnamed', {0x01000000} '54 - Unnamed', {0x02000000} '55 - Unnamed', {0x04000000} '56 - Unnamed', {0x08000000} '57 - Unnamed', {0x10000000} '58 - Unnamed', {0x20000000} '59 - Unnamed', {0x40000000} '60 - Unnamed', {0x80000000} '61 - FX01' ], True); wbFirstPersonFlagsU32 := wbInteger('First Person Flags', itU32, wbBipedObjectFlags); wbBODT := wbStruct(BODT, 'Body Template', [ wbFirstPersonFlagsU32, wbInteger('General Flags', itU8, wbFlags([ {0x00000001}'(ARMA)Modulates Voice', {>>> From ARMA <<<} {0x00000002}'Unknown 2', {0x00000004}'Unknown 3', {0x00000008}'Unknown 4', {0x00000010}'(ARMO)Non-Playable', {>>> From ARMO <<<} {0x00000020}'Unknown 6', {0x00000040}'Unknown 7', {0x00000080}'Unknown 8' ], True)), wbByteArray('Unused', 3, cpIgnore), wbInteger('Armor Type', itU32, wbArmorTypeEnum) ], cpNormal, False, nil, 3); wbBOD2 := wbStruct(BOD2, 'Biped Body Template', [ wbFirstPersonFlagsU32, wbInteger('Armor Type', itU32, wbArmorTypeEnum) ], cpNormal, False); wbBODTBOD2 := wbRUnion('Biped Body Template', [ wbStruct(BOD2, 'Biped Body Template', [ wbFirstPersonFlagsU32, wbInteger('General Flags', it0, wbFlags([ {0x00000001}'(ARMA)Modulates Voice', {>>> From ARMA <<<} {0x00000002}'Unknown 2', {0x00000004}'Unknown 3', {0x00000008}'Unknown 4', {0x00000010}'(ARMO)Non-Playable', {>>> From ARMO <<<} {0x00000020}'Unknown 6', {0x00000040}'Unknown 7', {0x00000080}'Unknown 8' ], True)), wbEmpty('Unused'), wbInteger('Armor Type', itU32, wbArmorTypeEnum) ], cpNormal, False), wbStruct(BODT, 'Body Template', [ wbFirstPersonFlagsU32, wbInteger('General Flags', itU8, wbFlags([ {0x00000001}'(ARMA)Modulates Voice', {>>> From ARMA <<<} {0x00000002}'Unknown 2', {0x00000004}'Unknown 3', {0x00000008}'Unknown 4', {0x00000010}'(ARMO)Non-Playable', {>>> From ARMO <<<} {0x00000020}'Unknown 6', {0x00000040}'Unknown 7', {0x00000080}'Unknown 8' ], True)), wbByteArray('Unused', 3, cpIgnore), wbInteger('Armor Type', itU32, wbArmorTypeEnum) ], cpNormal, False, nil, 3) ], []); wbMDOB := wbFormID(MDOB, 'Menu Display Object', cpNormal, False); wbCNAM := wbStruct(CNAM, 'Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unknown', 1) ]); wbCNAMReq := wbStruct(CNAM, 'Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unknown', 1) ], cpNormal, True); wbDODT := wbStruct(DODT, 'Decal Data', [ wbFloat('Min Width'), wbFloat('Max Width'), wbFloat('Min Height'), wbFloat('Max Height'), wbFloat('Depth'), wbFloat('Shininess'), wbStruct('Parallax', [ wbFloat('Scale'), wbInteger('Passes', itU8) {>>> This can't be higher than 30 <<<} ]), wbInteger('Flags', itU8, wbFlags([ {0x01}'Parallax', {0x02}'Alpha - Blending', {0x04}'Alpha - Testing', {0x08}'No Subtextures' ], True)), wbByteArray('Unknown', 2), wbByteColors('Color') ]); // wbRecordFlagsFlags := wbFlags([ // {>>> 0x00000000 ACTI: Collision Geometry (default) <<<} // {0x00000001}'ESM', // {0x00000002}'Unknown 2', // {>>> 0x00000004 ARMO: Not playable <<<} // {0x00000004}'NotPlayable', // {0x00000008}'Unknown 4', // {0x00000010}'Unknown 5', // {0x00000020}'Deleted', // {>>> 0x00000040 ACTI: Has Tree LOD <<<} // {>>> 0x00000040 REGN: Border Region <<<} // {>>> 0x00000040 STAT: Has Tree LOD <<<} // {>>> 0x00000040 REFR: Hidden From Local Map <<<} // {0x00000040}'Constant HiddenFromLocalMap BorderRegion HasTreeLOD', // {>>> 0x00000080 TES4: Localized <<<} // {>>> 0x00000080 PHZD: Turn Off Fire <<<} // {>>> 0x00000080 SHOU: Treat Spells as Powers <<<} // {>>> 0x00000080 STAT: Add-on LOD Object <<<} // {0x00000080}'Localized IsPerch AddOnLODObject TurnOffFire TreatSpellsAsPowers', // {>>> 0x00000100 ACTI: Must Update Anims <<<} // {>>> 0x00000100 REFR: Inaccessible <<<} // {>>> 0x00000100 REFR for LIGH: Doesn't light water <<<} // {0x00000100}'MustUpdateAnims Inaccessible DoesntLightWater', // {>>> 0x00000200 ACTI: Local Map - Turns Flag Off, therefore it is Hidden <<<} // {>>> 0x00000200 REFR: MotionBlurCastsShadows <<<} // {0x00000200}'HiddenFromLocalMap StartsDead MotionBlurCastsShadows', // {>>> 0x00000400 LSCR: Displays in Main Menu <<<} // {0x00000400}'PersistentReference QuestItem DisplaysInMainMenu', // {0x00000800}'InitiallyDisabled', // {0x00001000}'Ignored', // {0x00002000}'ActorChanged', // {0x00004000}'Unknown 15', // {>>> 0x00008000 STAT: Has Distant LOD <<<} // {0x00008000}'VWD', // {>>> 0x00010000 ACTI: Random Animation Start <<<} // {>>> 0x00010000 REFR light: Never fades <<<} // {0x00010000}'RandomAnimationStart NeverFades', // {>>> 0x00020000 ACTI: Dangerous <<<} // {>>> 0x00020000 REFR light: Doesn't light landscape <<<} // {>>> 0x00020000 SLGM: Can hold NPC's soul <<<} // {>>> 0x00020000 STAT: Use High-Detail LOD Texture <<<} // {0x00020000}'Dangerous OffLimits DoesntLightLandscape HighDetailLOD CanHoldNPC', // {0x00040000}'Compressed', // {>>> 0x00080000 STAT: Has Currents <<<} // {0x00080000}'CantWait HasCurrents', // {>>> 0x00100000 ACTI: Ignore Object Interaction <<<} // {0x00100000}'IgnoreObjectInteraction', // {0x00200000}'(Used in Memory Changed Form)', // {0x00400000}'Unknown 23', // {>>> 0x00800000 ACTI: Is Marker <<<} // {0x00800000}'IsMarker', // {0x01000000}'Unknown 25', // {>>> 0x02000000 ACTI: Obstacle <<<} // {>>> 0x02000000 REFR: No AI Acquire <<<} // {0x02000000}'Obstacle NoAIAcquire', // {>>> 0x04000000 ACTI: Filter <<<} // {0x04000000}'NavMeshFilter', // {>>> 0x08000000 ACTI: Bounding Box <<<} // {0x08000000}'NavMeshBoundingBox', // {>>> 0x10000000 STAT: Show in World Map <<<} // {0x10000000}'MustExitToTalk ShowInWorldMap', // {>>> 0x20000000 ACTI: Child Can Use <<<} // {>>> 0x20000000 REFR: Don't Havok Settle <<<} // {0x20000000}'ChildCanUse DontHavokSettle', // {>>> 0x40000000 ACTI: GROUND <<<} // {>>> 0x40000000 REFR: NoRespawn <<<} // {0x40000000}'NavMeshGround NoRespawn', // {>>> 0x80000000 REFR: MultiBound <<<} // {0x80000000}'MultiBound' // ], [18]); wbRecordFlagsFlags := wbFlags(wbRecordFlagsFlags, [ {0x00000001} { 0} 'Unknown 0', {0x00000002} { 1} 'Unknown 1', {0x00000004} { 2} 'Unknown 2', {0x00000008} { 3} 'Unknown 3', {0x00000010} { 4} 'Unknown 4', {0x00000020} { 4} 'Unknown 5', {0x00000040} { 6} 'Unknown 6', {0x00000080} { 7} 'Unknown 7', {0x00000100} { 8} 'Unknown 8', {0x00000200} { 9} 'Unknown 9', {0x00000400} {10} 'Unknown 10', {0x00000800} {11} 'Unknown 11', {0x00001000} {12} 'Unknown 12', {0x00002000} {13} 'Unknown 13', {0x00004000} {14} 'Unknown 14', {0x00008000} {15} 'Unknown 15', {0x00010000} {16} 'Unknown 16', {0x00020000} {17} 'Unknown 17', {0x00040000} {18} 'Unknown 18', {0x00080000} {19} 'Unknown 19', {0x00100000} {20} 'Unknown 20', {0x00200000} {21} 'Unknown 21', {0x00400000} {22} 'Unknown 22', {0x00800000} {23} 'Unknown 23', {0x01000000} {24} 'Unknown 24', {0x02000000} {25} 'Unknown 25', {0x04000000} {26} 'Unknown 26', {0x08000000} {27} 'Unknown 27', {0x10000000} {28} 'Unknown 28', {0x20000000} {29} 'Unknown 29', {0x40000000} {30} 'Unknown 30', {0x80000000} {31} 'Unknown 31' ]); wbRecordFlags := wbInteger('Record Flags', itU32, wbFlags(wbRecordFlagsFlags, wbFlagsList([]))); wbMainRecordHeader := wbStruct('Record Header', [ wbString('Signature', 4, cpCritical), wbInteger('Data Size', itU32, nil, cpIgnore), wbRecordFlags, wbFormID('FormID', cpFormID), wbByteArray('Version Control Info 1', 4, cpIgnore), wbInteger('Form Version', itU16, nil, cpIgnore), wbByteArray('Version Control Info 2', 2, cpIgnore) ]); wbSizeOfMainRecordStruct := 24; wbIgnoreRecords.Add(XXXX); wbXRGD := wbByteArray(XRGD, 'Ragdoll Data'); wbXRGB := wbByteArray(XRGB, 'Ragdoll Biped Data'); wbMusicEnum := wbEnum(['Default', 'Public', 'Dungeon']); wbSoundLevelEnum := wbEnum([ 'Loud', 'Normal', 'Silent', 'Very Loud' ]); wbEntryPointsEnum := wbEnum([ { 0} 'Calculate Weapon Damage', { 1} 'Calculate My Critical Hit Chance', { 2} 'Calculate My Critical Hit Damage', { 3} 'Calculate Mine Explode Chance', { 4} 'Adjust Limb Damage', { 5} 'Adjust Book Skill Points', { 6} 'Mod Recovered Health', { 7} 'Get Should Attack', { 8} 'Mod Buy Prices', { 9} 'Add Leveled List On Death', {10} 'Get Max Carry Weight', {11} 'Mod Addiction Chance', {12} 'Mod Addiction Duration', {13} 'Mod Positive Chem Duration', {14} 'Activate', {15} 'Ignore Running During Detection', {16} 'Ignore Broken Lock', {17} 'Mod Enemy Critical Hit Chance', {18} 'Mod Sneak Attack Mult', {19} 'Mod Max Placeable Mines', {20} 'Mod Bow Zoom', {21} 'Mod Recover Arrow Chance', {22} 'Mod Skill Use', {23} 'Mod Telekinesis Distance', {24} 'Mod Telekinesis Damage Mult', {25} 'Mod Telekinesis Damage', {26} 'Mod Bashing Damage', {27} 'Mod Power Attack Stamina', {28} 'Mod Power Attack Damage', {29} 'Mod Spell Magnitude', {30} 'Mod Spell Duration', {31} 'Mod Secondary Value Weight', {32} 'Mod Armor Weight', {33} 'Mod Incoming Stagger', {34} 'Mod Target Stagger', {35} 'Mod Attack Damage', {36} 'Mod Incoming Damage', {37} 'Mod Target Damage Resistance', {38} 'Mod Spell Cost', {39} 'Mod Percent Blocked', {40} 'Mod Shield Deflect Arrow Chance', {41} 'Mod Incoming Spell Magnitude', {42} 'Mod Incoming Spell Duration', {43} 'Mod Player Intimidation', {44} 'Mod Player Reputation', {45} 'Mod Favor Points', {46} 'Mod Bribe Amount', {47} 'Mod Detection Light', {48} 'Mod Detection Movement', {49} 'Mod Soul Gem Recharge', {50} 'Set Sweep Attack', {51} 'Apply Combat Hit Spell', {52} 'Apply Bashing Spell', {53} 'Apply Reanimate Spell', {54} 'Set Boolean Graph Variable', {55} 'Mod Spell Casting Sound Event', {56} 'Mod Pickpocket Chance', {57} 'Mod Detection Sneak Skill', {58} 'Mod Falling Damage', {59} 'Mod Lockpick Sweet Spot', {60} 'Mod Sell Prices', {61} 'Can Pickpocket Equipped Item', {62} 'Mod Lockpick Level Allowed', {63} 'Set Lockpick Starting Arc', {64} 'Set Progression Picking', {65} 'Make Lockpicks Unbreakable', {66} 'Mod Alchemy Effectiveness', {67} 'Apply Weapon Swing Spell', {68} 'Mod Commanded Actor Limit', {69} 'Apply Sneaking Spell', {70} 'Mod Player Magic Slowdown', {71} 'Mod Ward Magicka Absorption Pct', {72} 'Mod Initial Ingredient Effects Learned', {73} 'Purify Alchemy Ingredients', {74} 'Filter Activation', {75} 'Can Dual Cast Spell', {76} 'Mod Tempering Health', {77} 'Mod Enchantment Power', {78} 'Mod Soul Pct Captured to Weapon', {79} 'Mod Soul Gem Enchanting', {80} 'Mod # Applied Enchantments Allowed', {81} 'Set Activate Label', {82} 'Mod Shout OK', {83} 'Mod Poison Dose Count', {84} 'Should Apply Placed Item', {85} 'Mod Armor Rating', {86} 'Mod Lockpicking Crime Chance', {87} 'Mod Ingredients Harvested', {88} 'Mod Spell Range (Target Loc.)', {89} 'Mod Potions Created', {90} 'Mod Lockpicking Key Reward Chance', {91} 'Allow Mount Actor' ]); wbLocationEnum := wbEnum([ {0} 'Near reference', {1} 'In cell', {2} 'Near package start location', {3} 'Near editor location', {4} 'Object ID', {5} 'Object Type', {6} 'Near linked reference', {7} 'At package location', {8} 'Alias (reference)', {9} 'Alias (location)', {10} 'Unknown 10', {11} 'Unknown 11', {12} 'Near self' ]); wbEquipType := wbFlags([ {0x00000001}'Hand To Hand Melee', {0x00000002}'One Hand Sword', {0x00000004}'One Hand Dagger', {0x00000008}'One Hand Axe', {0x00000010}'One Hand Mace', {0x00000020}'Two Hand Sword', {0x00000040}'Two Hand Axe', {0x00000080}'Bow', {0x00000100}'Staff', {0x00000200}'Spell', {0x00000400}'Shield', {0x00000800}'Torch', {0x00001000}'Crossbow' ], True); wbEmotionTypeEnum := wbEnum([ {0} 'Neutral', {1} 'Anger', {2} 'Disgust', {3} 'Fear', {4} 'Sad', {5} 'Happy', {6} 'Surprise', {7} 'Puzzled' ]); wbFurnitureAnimTypeEnum := wbEnum([ {0} '', {1} 'Sit', {2} 'Lay', {3} '', {4} 'Lean' ]); wbFurnitureEntryTypeFlags := wbFlags([ {0x01} 'Front', {0x02} 'Behind', {0x04} 'Right', {0x08} 'Left', {0x10} 'Up' ]); wbWardStateEnum := wbEnum([ 'None', 'Absorb', 'Break' ]); wbEventFunctionEnum := wbEnum([ 'GetIsID', 'IsInList', 'GetValue', 'HasKeyword', 'GetItemValue' ]); // Event member names and availability are different depending on event type // Using generic names for the last 3 of them: Form, Value1, Value2 wbEventMemberEnum := wbEnum([], [ $0000, 'None', $314F, 'CreatedObject', $314C, '(Old)Location', $324C, '(New)Location', $314B, 'Keyword', $3146, 'Form', $3156, 'Value1', $3256, 'Value2' ]); wbWeaponAnimTypeEnum := wbEnum([ {0} 'HandToHandMelee', {1} 'OneHandSword', {2} 'OneHandDagger', {3} 'OneHandAxe', {4} 'OneHandMace', {5} 'TwoHandSword', {6} 'TwoHandAxe', {7} 'Bow', {8} 'Staff', {9} 'Crossbow' ]); wbEDID := wbString(EDID, 'Editor ID', 0, cpNormal); // not cpBenign according to Arthmoor wbFULL := wbLStringKC(FULL, 'Name', 0, cpTranslate); wbFULLActor := wbLStringKC(FULL, 'Name', 0, cpTranslate, False, nil{wbActorTemplateUseBaseData}); wbFULLReq := wbLStringKC(FULL, 'Name', 0, cpTranslate, True); wbDESC := wbLStringKC(DESC, 'Description', 0, cpTranslate); wbDESCReq := wbLStringKC(DESC, 'Description', 0, cpTranslate, True); wbXSCL := wbFloat(XSCL, 'Scale'); wbOBND := wbStruct(OBND, 'Object Bounds', [ wbInteger('X1', itS16), wbInteger('Y1', itS16), wbInteger('Z1', itS16), wbInteger('X2', itS16), wbInteger('Y2', itS16), wbInteger('Z2', itS16) ]); wbOBNDReq := wbStruct(OBND, 'Object Bounds', [ wbInteger('X1', itS16), wbInteger('Y1', itS16), wbInteger('Z1', itS16), wbInteger('X2', itS16), wbInteger('Y2', itS16), wbInteger('Z2', itS16) ], cpNormal, True); wbPropTypeEnum := wbEnum([ {00} 'None', {01} 'Object', {02} 'String', {03} 'Int32', {04} 'Float', {05} 'Bool', {06} '', {07} '', {08} '', {09} '', {10} '', {11} 'Array of Object', {12} 'Array of String', {13} 'Array of Int32', {14} 'Array of Float', {15} 'Array of Bool' ]); wbScriptFlags := wbInteger('Flags', itU8, wbEnum([ {0x00} 'Local', {0x01} 'Inherited', {0x02} 'Removed', {0x03} 'Inherited and Removed' ])); wbScriptPropertyObject := wbUnion('Object Union', wbScriptObjFormatDecider, [ wbStructSK([1], 'Object v2', [ wbInteger('Unused', itU16, nil, cpIgnore), wbInteger('Alias', itS16, wbScriptObjectAliasToStr, wbStrToAlias), wbFormID('FormID') ], [2, 1, 0]), wbStructSK([1], 'Object v1', [ wbFormID('FormID'), wbInteger('Alias', itS16, wbScriptObjectAliasToStr, wbStrToAlias), wbInteger('Unused', itU16, nil, cpIgnore) ]) ]); wbScriptProperties := wbArrayS('Properties', wbStructSK([0], 'Property', [ wbLenString('propertyName', 2), wbInteger('Type', itU8, wbPropTypeEnum, cpNormal, False, nil, wbScriptPropertyTypeAfterSet), wbInteger('Flags', itU8, wbEnum([ {0x00} '', {0x01} 'Edited', {0x02} '', {0x03} 'Removed' ])), wbUnion('Value', wbScriptPropertyDecider, [ {00} wbNull, {01} wbScriptPropertyObject, {02} wbLenString('String', 2), {03} wbInteger('Int32', itS32), {04} wbFloat('Float'), {05} wbInteger('Bool', itU8, wbEnum(['False', 'True'])), {11} wbArray('Array of Object', wbScriptPropertyObject, -1), {12} wbArray('Array of String', wbLenString('Element', 2), -1), {13} wbArray('Array of Int32', wbInteger('Element', itS32), -1), {14} wbArray('Array of Float', wbFloat('Element'), -1), {15} wbArray('Array of Bool', wbInteger('Element', itU8, wbEnum(['False', 'True'])), -1) ]) ]), -2, cpNormal, False, nil, nil, nil, False); wbScriptEntry := wbStructSK([0], 'Script', [ wbLenString('scriptName', 2), wbScriptFlags, wbScriptProperties ]); wbScriptFragmentsInfo := wbStruct('Script Fragments', [ wbInteger('Unknown', itS8), wbInteger('Flags', itU8, wbFlags([ {1} 'OnBegin', {2} 'OnEnd' ])), wbLenString('fileName', 2), wbArray('Fragments', // Do NOT sort, ordered OnBegin, OnEnd wbStruct('Fragment', [ wbInteger('Unknown', itS8), wbLenString('scriptName', 2), wbLenString('fragmentName', 2) ]), [], wbScriptFragmentsInfoCounter) ]); wbScriptFragmentsPack := wbStruct('Script Fragments', [ wbInteger('Unknown', itS8), wbInteger('Flags', itU8, wbFlags([ {1} 'OnBegin', {2} 'OnEnd', {4} 'OnChange' ])), wbLenString('fileName', 2), wbArray('Fragments', // Do NOT sort, ordered OnBegin, OnEnd, OnChange wbStruct('Fragment', [ wbInteger('Unknown', itS8), wbLenString('scriptName', 2), wbLenString('fragmentName', 2) ]), [], wbScriptFragmentsPackCounter) ]); wbScriptFragmentsQuest := wbStruct('Script Fragments', [ wbInteger('Unknown', itS8), wbInteger('fragmentCount', itU16), wbLenString('fileName', 2), wbArrayS('Fragments', wbStructSK([0, 2], 'Fragment', [ wbInteger('Quest Stage', itU16), wbInteger('Unknown', itS16), wbInteger('Quest Stage Index', itS32), wbInteger('Unknown', itS8), wbLenString('scriptName', 2), wbLenString('fragmentName', 2) ]), wbScriptFragmentsQuestCounter) ]); wbScriptFragmentsScen := wbStruct('Script Fragments', [ wbInteger('Unknown', itS8), wbInteger('Flags', itU8, wbFlags([ {1} 'OnBegin', {2} 'OnEnd' ])), wbLenString('fileName', 2), wbArray('Fragments', // Do NOT sort, ordered OnBegin, OnEnd wbStruct('Fragment', [ wbInteger('Unknown', itS8), wbLenString('scriptName', 2), wbLenString('fragmentName', 2) ]), [], wbScriptFragmentsSceneCounter), wbArray('Phase Fragments', wbStructSK([0, 1], 'Phase Fragment', [ wbInteger('Phase Flag', itU8, wbFlags([ {1} 'OnStart', {2} 'OnCompletion' ])), wbInteger('Phase Index', itU8), wbInteger('Unknown', itS16), wbInteger('Unknown', itS8), wbInteger('Unknown', itS8), wbLenString('scriptName', 2), wbLenString('fragmentName', 2) ]), -2) ]); wbScriptFragments := wbStruct('Script Fragments', [ wbInteger('Unknown', itS8), wbLenString('fileName', 2), wbArrayS('Fragments', wbStructSK([0], 'Fragment', [ wbInteger('Fragment Index', itU16), wbInteger('Unknown', itS16), wbInteger('Unknown', itS8), wbLenString('scriptName', 2), wbLenString('fragmentName', 2) ]), -2) ]); {>>> http://www.uesp.net/wiki/Tes5Mod:Mod_File_Format/VMAD_Field <<<} wbVMAD := wbStruct(VMAD, 'Virtual Machine Adapter', [ wbInteger('Version', itS16, nil, cpIgnore), wbInteger('Object Format', itS16, nil, cpIgnore), wbArrayS('Scripts', wbScriptEntry, -2, cpNormal, False, nil, nil, nil, False) ]); wbVMADFragmentedPERK := wbStruct(VMAD, 'Virtual Machine Adapter', [ wbInteger('Version', itS16, nil, cpIgnore), wbInteger('Object Format', itS16, nil, cpIgnore), wbArrayS('Scripts', wbScriptEntry, -2, cpNormal, False, nil, nil, nil, False), wbScriptFragments ], cpNormal, False, nil, 3); wbVMADFragmentedPACK := wbStruct(VMAD, 'Virtual Machine Adapter', [ wbInteger('Version', itS16, nil, cpIgnore), wbInteger('Object Format', itS16, nil, cpIgnore), wbArrayS('Scripts', wbScriptEntry, -2, cpNormal, False, nil, nil, nil, False), wbScriptFragmentsPack ], cpNormal, False, nil, 3); wbVMADFragmentedQUST := wbStruct(VMAD, 'Virtual Machine Adapter', [ wbInteger('Version', itS16, nil, cpIgnore), wbInteger('Object Format', itS16, nil, cpIgnore), wbArrayS('Scripts', wbScriptEntry, -2, cpNormal, False, nil, nil, nil, False), wbScriptFragmentsQuest, wbArrayS('Aliases', wbStructSK([0], 'Alias', [ wbScriptPropertyObject, wbInteger('Version', itS16, nil, cpIgnore), wbInteger('Object Format', itS16, nil, cpIgnore), wbArrayS('Alias Scripts', wbScriptEntry, -2) ]), -2) ], cpNormal, False, nil, 3); wbVMADFragmentedSCEN := wbStruct(VMAD, 'Virtual Machine Adapter', [ wbInteger('Version', itS16, nil, cpIgnore), wbInteger('Object Format', itS16, nil, cpIgnore), wbArrayS('Scripts', wbScriptEntry, -2, cpNormal, False, nil, nil, nil, False), wbScriptFragmentsScen ], cpNormal, False, nil, 3); wbVMADFragmentedINFO := wbStruct(VMAD, 'Virtual Machine Adapter', [ wbInteger('Version', itS16, nil, cpIgnore), wbInteger('Object Format', itS16, nil, cpIgnore), wbArrayS('Scripts', wbScriptEntry, -2, cpNormal, False, nil, nil, nil, False), wbScriptFragmentsInfo ], cpNormal, False, nil, 3); wbAttackData := wbRStructSK([1], 'Attack', [ wbStruct(ATKD, 'Attack Data', [ wbFloat('Damage Mult'), wbFloat('Attack Chance'), wbFormIDCk('Attack Spell', [SPEL, SHOU, NULL]), wbInteger('Attack Flags', itU32, wbFlags([ {0x00000001} 'Ignore Weapon', {0x00000002} 'Bash Attack', {0x00000004} 'Power Attack', {0x00000008} 'Left Attack', {0x00000010} 'Rotating Attack', {0x00000020} 'Unknown 5', {0x00000040} 'Unknown 6', {0x00000080} 'Unknown 7', {0x00000100} 'Unknown 8', {0x00000200} 'Unknown 9', {0x00000400} 'Unknown 10', {0x00000800} 'Unknown 11', {0x00001000} 'Unknown 12', {0x00002000} 'Unknown 13', {0x00004000} 'Unknown 14', {0x00008000} 'Unknown 15', {0x00010000} 'Unknown 16', {0x00020000} 'Unknown 17', {0x00040000} 'Unknown 18', {0x00080000} 'Unknown 19', {0x00100000} 'Unknown 20', {0x00200000} 'Unknown 21', {0x00400000} 'Unknown 22', {0x00800000} 'Unknown 23', {0x01000000} 'Unknown 24', {0x02000000} 'Unknown 25', {0x04000000} 'Unknown 26', {0x08000000} 'Unknown 27', {0x10000000} 'Unknown 28', {0x20000000} 'Unknown 29', {0x40000000} 'Unknown 30', {0x80000000} 'Override Data' ])), wbFloat('Attack Angle'), wbFloat('Strike Angle'), wbFloat('Stagger'), wbFormIDCk('Attack Type', [KYWD, NULL]), wbFloat('Knockdown'), wbFloat('Recovery Time'), wbFloat('Stamina Mult') ]), wbString(ATKE, 'Attack Event') ], []); wbPLDT := wbStruct(PLDT, 'Location', [ wbInteger('Type', itS32, wbLocationEnum), wbUnion('Location Value', wbTypeDecider, [ {0} wbFormIDCkNoReach('Reference', [NULL, DOOR, PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA]), {1} wbFormIDCkNoReach('Cell', [NULL, CELL]), {2} wbByteArray('Near Package Start Location', 4, cpIgnore), {3} wbByteArray('Near Editor Location', 4, cpIgnore), {4} wbFormIDCkNoReach('Object ID', [NULL, ACTI, DOOR, STAT, MSTT, FURN, SPEL, SCRL, NPC_, CONT, ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, LIGH, FACT, FLST, IDLM, SHOU]), {5} wbInteger('Object Type', itU32, wbObjectTypeEnum), {6} wbFormIDCk('Keyword', [NULL, KYWD]), {7} wbByteArray('Unused', 4, cpIgnore), {8} wbInteger('Alias', itS32, wbPackageLocationAliasToStr, wbStrToAlias), {9} wbInteger('Reference', itS32, wbPackageLocationAliasToStr, wbStrToAlias), {10} wbByteArray('Unknown', 4, cpIgnore), {11} wbByteArray('Unknown', 4, cpIgnore), {12} wbByteArray('Unknown', 4, cpIgnore) ]), wbInteger('Radius', itS32) ]); wbPLVD := wbStruct(PLVD, 'Location', [ wbInteger('Type', itS32, wbLocationEnum), wbUnion('Location Value', wbTypeDecider, [ {0} wbFormIDCkNoReach('Reference', [NULL, DOOR, PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA]), {1} wbFormIDCkNoReach('Cell', [NULL, CELL]), {2} wbByteArray('Near Package Start Location', 4, cpIgnore), {3} wbByteArray('Near Editor Location', 4, cpIgnore), {4} wbFormIDCkNoReach('Object ID', [NULL, ACTI, DOOR, STAT, MSTT, FURN, SPEL, SCRL, NPC_, CONT, ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, INGR, LIGH, FACT, FLST, IDLM, SHOU]), {5} wbInteger('Object Type', itU32, wbObjectTypeEnum), {6} wbFormIDCk('Keyword', [NULL, KYWD]), {7} wbByteArray('Unused', 4, cpIgnore), {8} wbInteger('Alias', itS32, wbPackageLocationAliasToStr, wbStrToAlias), {9} wbInteger('Reference', itS32, wbPackageLocationAliasToStr, wbStrToAlias), {10} wbByteArray('Unknown', 4, cpIgnore), {11} wbByteArray('Unknown', 4, cpIgnore), {12} wbByteArray('Unknown', 4, cpIgnore) ]), wbInteger('Radius', itS32) ]); wbTargetData := wbStruct('Target Data', [ wbInteger('Type', itS32, wbEnum([ {0} 'Specific Reference', {1} 'Object ID', {2} 'Object Type', {3} 'Linked Reference', {4} 'Ref Alias', {5} 'Unknown 5', {6} 'Self' ]), cpNormal, False, nil, nil, 2), wbUnion('Target', wbTypeDecider, [ {0} wbFormIDCkNoReach('Reference', [NULL, PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA], True), {1} wbFormIDCkNoReach('Object ID', [NULL, ACTI, DOOR, STAT, MSTT, FURN, SPEL, SCRL, NPC_, CONT, ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, INGR, LIGH, FACT, FLST, IDLM, SHOU, SOUN, TXST, PROJ]), {2} wbInteger('Object Type', itU32, wbObjectTypeEnum), {3} wbFormID('Reference'), {4} wbInteger('Alias', itS32, wbPackageLocationAliasToStr, wbStrToAlias), {5} wbByteArray('Unknown', 4, cpIgnore), {6} wbByteArray('Unknown', 4, cpIgnore) ]), wbInteger('Count / Distance', itS32) ]); wbEITM := wbFormIDCk(EITM, 'Object Effect', [ENCH, SPEL]); wbPosRot := wbStruct('Position/Rotation', [ wbStruct('Position', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), wbStruct('Rotation', [ wbFloat('X', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Y', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Z', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize) ]) ]); wbDATAPosRot := wbStruct(DATA, 'Position/Rotation', [ wbStruct('Position', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), wbStruct('Rotation', [ wbFloat('X', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Y', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Z', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize) ]) ], cpNormal, True); wbMO2S := wbArrayS(MO2S, 'Alternate Textures', wbStructSK([0, 2], 'Alternate Texture', [ wbLenString('3D Name'), wbFormIDCk('New Texture', [TXST]), wbInteger('3D Index', itS32) ]), -1); wbMO3S := wbArrayS(MO3S, 'Alternate Textures', wbStructSK([0, 2], 'Alternate Texture', [ wbLenString('3D Name'), wbFormIDCk('New Texture', [TXST]), wbInteger('3D Index', itS32) ]), -1); wbMO4S := wbArrayS(MO4S, 'Alternate Textures', wbStructSK([0, 2], 'Alternate Texture', [ wbLenString('3D Name'), wbFormIDCk('New Texture', [TXST]), wbInteger('3D Index', itS32) ]), -1); wbMO5S := wbArrayS(MO5S, 'Alternate Textures', wbStructSK([0, 2], 'Alternate Texture', [ wbLenString('3D Name'), wbFormIDCk('New Texture', [TXST]), wbInteger('3D Index', itS32) ]), -1); wbMODS := wbArrayS(MODS, 'Alternate Textures', wbStructSK([0, 2], 'Alternate Texture', [ wbLenString('3D Name'), wbFormIDCk('New Texture', [TXST]), wbInteger('3D Index', itS32) ]), -1); wbMODD := wbInteger(MODD, 'FaceGen Model Flags', itU8, wbFlags([ 'Head', 'Torso', 'Right Hand', 'Left Hand' ])); wbMODT := wbByteArray(MODT, 'Texture Files Hashes', 0, cpIgnore, false, false, wbNeverShow); wbDMDT := wbByteArray(DMDT, 'Texture Files Hashes', 0, cpIgnore, false, false, wbNeverShow); wbMODL := wbRStructSK([0], 'Model', [ wbString(MODL, 'Model Filename', 0, cpNormal, True), wbMODT, wbMODS ], [], cpNormal, False, nil, True); wbMODLActor := wbRStructSK([0], 'Model', [ wbString(MODL, 'Model Filename', 0, cpNormal, True), wbMODT, wbMODS ], [], cpNormal, False, nil{wbActorTemplateUseModelAnimation}, True); wbMODLReq := wbRStructSK([0], 'Model', [ wbString(MODL, 'Model Filename', 0, cpNormal, True), wbMODT, wbMODS ], [], cpNormal, True, nil, True); wbDMDSs := wbArrayS(DMDS, 'Alternate Textures', wbStructSK([0, 2], 'Alternate Texture', [ wbLenString('3D Name'), wbFormIDCk('New Texture', [TXST]), wbInteger('3D Index', itS32) ]), -1); wbDEST := wbRStruct('Destructable', [ wbStruct(DEST, 'Header', [ wbInteger('Health', itS32), wbInteger('DEST Count', itU8), wbInteger('VATS Targetable', itU8, wbEnum(['False', 'True'])), wbByteArray('Unknown', 2) ]), wbRArray('Stages', wbRStruct('Stage', [ wbStruct(DSTD, 'Destruction Stage Data', [ wbInteger('Health %', itU8), wbInteger('Index', itU8), wbInteger('Model Damage Stage', itU8), wbInteger('Flags', itU8, wbFlags([ 'Cap Damage', 'Disable', 'Destroy', 'Ignore External Dmg' ])), wbInteger('Self Damage per Second', itS32), wbFormIDCk('Explosion', [EXPL, NULL]), wbFormIDCk('Debris', [DEBR, NULL]), wbInteger('Debris Count', itS32) ], cpNormal, True), wbRStructSK([0], 'Model', [ wbString(DMDL, 'Model Filename'), wbDMDT, wbDMDSs ], [], cpNormal, False, nil), wbEmpty(DSTF, 'End Marker', cpNormal, True) ], [], cpNormal, False, nil) ) ], [], cpNormal, False, nil); wbDESTActor := wbRStruct('Destructable', [ wbStruct(DEST, 'Header', [ wbInteger('Health', itS32), wbInteger('Count', itU8), wbInteger('VATS Targetable', itU8, wbEnum(['False', 'True'])), wbByteArray('Unknown', 2) ]), wbRArray('Stages', // Begin Stage Array wbRStruct('Stage', [ // Begin Stage RStruct wbStruct(DSTD, 'Destruction Stage Data', [ // Begin DSTD wbInteger('Health %', itU8), wbInteger('Index', itU8), wbInteger('Damage Stage', itU8), wbInteger('Flags', itU8, wbFlags([ 'Cap Damage', 'Disable', 'Destroy' ])), wbInteger('Self Damage per Second', itS32), wbFormIDCk('Explosion', [EXPL, NULL]), wbFormIDCk('Debris', [DEBR, NULL]), wbInteger('Debris Count', itS32) ], cpNormal, True), // End DSTD wbRStructSK([0], 'Model', [ // Begin DMDL wbString(DMDL, 'Model Filename') ], []), // End DMDL wbDMDT, wbDMDSs, wbEmpty(DSTF, 'End Marker', cpNormal, True) ], []) // Begin Stage RStruct ) // End Stage Array ], [], cpNormal, False, nil{wbActorTemplateUseModelAnimation}); wbXLOD := wbArray(XLOD, 'Distant LOD Data', wbFloat('Unknown'), 3); wbXESP := wbStruct(XESP, 'Enable Parent', [ wbFormIDCk('Reference', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA]), wbInteger('Flags', itU8, wbFlags([ 'Set Enable State to Opposite of Parent', 'Pop In' ])), wbByteArray('Unused', 3, cpIgnore) ]); wbPDTO := wbStruct(PDTO, 'Topic Data', [ wbInteger('Type', itU32, wbEnum([ 'Topic Ref', 'Topic Subtype' ])), wbUnion('Data', wbTypeDecider, [ wbFormIDCk('Topic', [DIAL, NULL]), wbString('Subtype', 4) ]) ]); wbPDTOs := wbRArray('Topic', wbPDTO, cpNormal, False, nil); wbXLCM := wbInteger(XLCM, 'Level Modifier', itS32, wbEnum([ 'Easy', 'Medium', 'Hard', 'Very Hard' ])); wbTVDT := wbByteArray(TVDT, 'Occlusion Data', 0, cpNormal); // wbTVDT := wbArray(TVDT, 'Occlusion Data', wbInteger('Unknown', itS32)), if wbSimpleRecords then begin wbMaxHeightDataCELL := wbByteArray(MHDT, 'Max Height Data', 0, cpNormal); wbMaxHeightDataWRLD := wbByteArray(MHDT, 'Max Height Data', 0, cpNormal); end else begin wbMaxHeightDataCELL := wbStruct(MHDT, 'Max Height Data', [ wbFloat('Offset'), wbArray('Rows', wbByteArray('Columns', 32) // way too verbose for no practical use //wbStruct('Row', [ wbArray('Columns', wbInteger('Column', itU8), 32) ]) , 32) ]); wbMaxHeightDataWRLD := wbStruct(MHDT, 'Max Height Data', [ wbStruct('Min', [ wbInteger('X', itS16), wbInteger('Y', itS16) ]), wbStruct('Max', [ wbInteger('X', itS16), wbInteger('Y', itS16) ]), wbByteArray('Cell Data', 0) // way too verbose for no practical use {wbArray('Cell Data', wbStruct('Quad Height', [ wbInteger('Bottom Left', itU8), wbInteger('Bottom Right', itU8), wbInteger('Top Left', itU8), wbInteger('Top Right', itU8) ]))} ]); end; if wbSimpleRecords then wbOFST := wbByteArray(OFST, 'Offset Data') else wbOFST := wbArray(OFST, 'Offset Data', wbArray('Rows', wbInteger('Offset', itU32), wbOffsetDataColsCounter), 0); wbOwnership := wbRStruct('Ownership', [ wbFormIDCkNoReach(XOWN, 'Owner', [FACT, ACHR, NPC_]), wbInteger(XRNK, 'Faction rank', itS32) ], [XRGD]); wbXGLB := wbFormIDCk(XGLB, 'Global variable', [GLOB]); end; procedure DefineTES5b; begin wbRecord(ACHR, 'Placed NPC', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000200} 9, 'Starts Dead', {0x00000400} 10, 'Persistent', {0x00000800} 11, 'Initially Disabled', {0x02000000} 25, 'No AI Acquire', {0x20000000} 29, 'Don''t Havok Settle' ], True, True)), [ wbEDID, wbVMAD, wbFormIDCk(NAME, 'Base', [NPC_], False, cpNormal, True), wbFormIDCk(XEZN, 'Encounter Zone', [ECZN]), {--- Ragdoll ---} wbXRGD, wbXRGB, {--- Patrol Data ---} wbRStruct('Patrol Data', [ wbFloat(XPRD, 'Idle Time', cpNormal, True), wbEmpty(XPPA, 'Patrol Script Marker', cpNormal, True), wbFormIDCk(INAM, 'Idle', [IDLE, NULL], False, cpNormal, True), {>>> BEGIN leftover from earlier CK versions <<<} wbRStruct('Unused', [ wbUnknown(SCHR), wbUnknown(SCDA), wbUnknown(SCTX), wbUnknown(QNAM), wbUnknown(SCRO) ], [], cpIgnore, false, wbNeverShow), {>>> END leftover from earlier CK versions <<<} wbPDTOs, wbFormIDCk(TNAM, 'Topic', [DIAL, NULL], False, cpNormal) ], []), {--- Leveled Actor ----} wbXLCM, {--- Merchant Container ----} wbFormIDCk(XMRC, 'Merchant Container', [REFR], True), {--- Extra ---} wbInteger(XCNT, 'Count', itS32), wbFloat(XRDS, 'Radius'), wbFloat(XHLP, 'Health'), wbRArrayS('Linked References', wbStructSK(XLKR, [0], 'Linked Reference', [ wbFormIDCk('Keyword/Ref', [KYWD, PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA, NULL]), wbFormIDCk('Ref', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA]) ], cpNormal, False, nil, 1)), {--- Activate Parents ---} wbRStruct('Activate Parents', [ wbInteger(XAPD, 'Flags', itU8, wbFlags([ 'Parent Activate Only' ], True)), wbRArrayS('Activate Parent Refs', wbStructSK(XAPR, [0], 'Activate Parent Ref', [ wbFormIDCk('Reference', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA]), wbFloat('Delay') ]) ) ], []), {--- Linked Ref ---} wbStruct(XCLP, 'Linked Reference Color', [ wbByteColors('Link Start Color'), wbByteColors('Link End Color') ]), wbFormIDCk(XLCN, 'Persistent Location', [LCTN]), wbFormIDCk(XLRL, 'Location Reference', [LCRT, LCTN, NULL], False, cpBenignIfAdded), wbEmpty(XIS2, 'Ignored by Sandbox'), wbArray(XLRT, 'Location Ref Type', wbFormIDCk('Ref', [LCRT, NULL])), wbFormIDCk(XHOR, 'Horse', [ACHR]), wbFloat(XHTW, 'Head-Tracking Weight'), wbFloat(XFVC, 'Favor Cost'), {--- Enable Parent ---} wbXESP, {--- Ownership ---} wbOwnership, {--- Emittance ---} wbFormIDCk(XEMI, 'Emittance', [LIGH, REGN]), {--- MultiBound ---} wbFormIDCk(XMBR, 'MultiBound Reference', [REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA]), {--- Flags ---} wbEmpty(XIBS, 'Ignored By Sandbox'), {--- 3D Data ---} wbXSCL, wbDATAPosRot ], True, wbPlacedAddInfo); wbRecord(ACTI, 'Activator', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000040} 6, 'Has Tree LOD', {0x00000100} 8, 'Must Update Anims', {0x00000200} 9, 'Hidden From Local Map', {0x00008000} 15, 'Has Distant LOD', {0x00010000} 16, 'Random Anim Start', {0x00020000} 17, 'Dangerous', {0x00100000} 20, 'Ignore Object Interaction', {0x00800000} 23, 'Is Marker', {0x02000000} 25, 'Obstacle', {0x04000000} 26, 'NavMesh Generation - Filter', {0x08000000} 27, 'NavMesh Generation - Bounding Box', {0x20000000} 29, 'Child Can Use', {0x40000000} 30, 'NavMesh Generation - Ground' ])), [ wbEDID, wbVMAD, wbOBNDReq, wbFULL, wbMODL, wbDEST, wbKSIZ, wbKWDAs, wbStruct(PNAM, 'Marker Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbInteger('Unused', itU8) ]), wbFormIDCk(SNAM, 'Sound - Looping', [SNDR]), wbFormIDCk(VNAM, 'Sound - Activation', [SNDR]), wbFormIDCk(WNAM, 'Water Type', [WATR]), wbLString(RNAM, 'Activate Text Override', 0, cpTranslate), wbInteger(FNAM, 'Flags', itU16, wbFlags([ 'No Displacement', 'Ignored by Sandbox' ])), wbFormIDCk(KNAM, 'Interaction Keyword', [KYWD]) ], False, nil, cpNormal, False, nil, wbKeywordsAfterSet); wbRecord(TACT, 'Talking Activator', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000200} 9, 'Hidden From Local Map', {0x00010000} 16, 'Random Anim Start', {0x00020000} 17, 'Radio Station' ]), [17]), [ wbEDID, wbVMAD, wbOBNDReq, wbFULL, wbMODL, wbDEST, wbKSIZ, wbKWDAs, wbUnknown(PNAM, cpIgnore, True), wbFormIDCk(SNAM, 'Looping Sound', [SNDR]), wbUnknown(FNAM, cpIgnore, True), wbFormIDCk(VNAM, 'Voice Type', [VTYP]) ], False, nil, cpNormal, False, nil, wbKeywordsAfterSet); wbICON := wbRStruct('Icon', [ wbString(ICON, 'Large Icon filename', 0, cpNormal, True), wbString(MICO, 'Small Icon filename') ], [], cpNormal, False, nil, True); wbICONReq := wbRStruct('Icon', [ wbString(ICON, 'Large Icon filename', 0, cpNormal, True), wbString(MICO, 'Small Icon filename') ], [], cpNormal, True, nil, True); wbICO2 := wbRStruct('Icon 2 (female)', [ wbString(ICO2, 'Large Icon filename', 0, cpNormal, True), wbString(MIC2, 'Small Icon filename') ], [], cpNormal, False, nil, True); wbVatsValueFunctionEnum := wbEnum([ { 0} 'Weapon Is', { 1} 'Weapon In List', { 2} 'Target Is', { 3} 'Target In List', { 4} 'Target Distance', { 5} 'Target Part', { 6} 'VATS Action', { 7} 'Is Success', { 8} 'Is Critical', { 9} 'Critical Effect Is', {10} 'Critical Effect In List', {11} 'Is Fatal', {12} 'Explode Part', {13} 'Dismember Part', {14} 'Cripple Part', {15} 'Weapon Type Is', {16} 'Is Stranger', {17} 'Is Paralyzing Palm', {18} 'Projectile Type Is', {19} 'Delivery Type Is', {20} 'Casting Type Is' ]); wbActorValueEnum := wbEnum([ {00} 'Aggresion', {01} 'Confidence', {02} 'Energy', {03} 'Morality', {04} 'Mood', {05} 'Assistance', {06} 'One-Handed', {07} 'Two-Handed', {08} 'Archery', {09} 'Block', {10} 'Smithing', {11} 'Heavy Armor', {12} 'Light Armor', {13} 'Pickpocket', {14} 'Lockpicking', {15} 'Sneak', {16} 'Alchemy', {17} 'Speech', {18} 'Alteration', {19} 'Conjuration', {20} 'Destruction', {21} 'Illusion', {22} 'Restoration', {23} 'Enchanting', {24} 'Health', {25} 'Magicka', {26} 'Stamina', {27} 'Heal Rate', {28} 'Magicka Rate', {29} 'Stamina Rate', {30} 'Speed Mult', {31} 'Inventory Weight', {32} 'Carry Weight', {33} 'Critical Chance', {34} 'Melee Damage', {35} 'Unarmed Damage', {36} 'Mass', {37} 'Voice Points', {38} 'Voice Rate', {39} 'Damage Resist', {40} 'Poison Resist', {41} 'Resist Fire', {42} 'Resist Shock', {43} 'Resist Frost', {44} 'Resist Magic', {45} 'Resist Disease', {46} 'Unknown 46', {47} 'Unknown 47', {48} 'Unknown 48', {49} 'Unknown 49', {50} 'Unknown 50', {51} 'Unknown 51', {52} 'Unknown 52', {53} 'Paralysis', {54} 'Invisibility', {55} 'Night Eye', {56} 'Detect Life Range', {57} 'Water Breathing', {58} 'Water Walking', {59} 'Unknown 59', {60} 'Fame', {61} 'Infamy', {62} 'Jumping Bonus', {63} 'Ward Power', {64} 'Right Item Charge', {65} 'Armor Perks', {66} 'Shield Perks', {67} 'Ward Deflection', {68} 'Variable01', {69} 'Variable02', {70} 'Variable03', {71} 'Variable04', {72} 'Variable05', {73} 'Variable06', {74} 'Variable07', {75} 'Variable08', {76} 'Variable09', {77} 'Variable10', {78} 'Bow Speed Bonus', {79} 'Favor Active', {80} 'Favors Per Day', {81} 'Favors Per Day Timer', {82} 'Left Item Charge', {83} 'Absorb Chance', {84} 'Blindness', {85} 'Weapon Speed Mult', {86} 'Shout Recovery Mult', {87} 'Bow Stagger Bonus', {88} 'Telekinesis', {89} 'Favor Points Bonus', {90} 'Last Bribed Intimidated', {91} 'Last Flattered', {92} 'Movement Noise Mult', {93} 'Bypass Vendor Stolen Check', {94} 'Bypass Vendor Keyword Check', {95} 'Waiting For Player', {96} 'One-Handed Modifier', {97} 'Two-Handed Modifier', {98} 'Marksman Modifier', {99} 'Block Modifier', {100} 'Smithing Modifier', {101} 'Heavy Armor Modifier', {102} 'Light Armor Modifier', {103} 'Pickpocket Modifier', {104} 'Lockpicking Modifier', {105} 'Sneaking Modifier', {106} 'Alchemy Modifier', {107} 'Speechcraft Modifier', {108} 'Alteration Modifier', {109} 'Conjuration Modifier', {110} 'Destruction Modifier', {111} 'Illusion Modifier', {112} 'Restoration Modifier', {113} 'Enchanting Modifier', {114} 'One-Handed Skill Advance', {115} 'Two-Handed Skill Advance', {116} 'Marksman Skill Advance', {117} 'Block Skill Advance', {118} 'Smithing Skill Advance', {119} 'Heavy Armor Skill Advance', {120} 'Light Armor Skill Advance', {121} 'Pickpocket Skill Advance', {122} 'Lockpicking Skill Advance', {123} 'Sneaking Skill Advance', {124} 'Alchemy Skill Advance', {125} 'Speechcraft Skill Advance', {126} 'Alteration Skill Advance', {127} 'Conjuration Skill Advance', {128} 'Destruction Skill Advance', {129} 'Illusion Skill Advance', {130} 'Restoration Skill Advance', {131} 'Enchanting Skill Advance', {132} 'Left Weapon Speed Multiply', {133} 'Dragon Souls', {134} 'Combat Health Regen Multiply', {135} 'One-Handed Power Modifier', {136} 'Two-Handed Power Modifier', {137} 'Marksman Power Modifier', {138} 'Block Power Modifier', {139} 'Smithing Power Modifier', {140} 'Heavy Armor Power Modifier', {141} 'Light Armor Power Modifier', {142} 'Pickpocket Power Modifier', {143} 'Lockpicking Power Modifier', {144} 'Sneaking Power Modifier', {145} 'Alchemy Power Modifier', {146} 'Speechcraft Power Modifier', {147} 'Alteration Power Modifier', {148} 'Conjuration Power Modifier', {149} 'Destruction Power Modifier', {150} 'Illusion Power Modifier', {151} 'Restoration Power Modifier', {152} 'Enchanting Power Modifier', {153} 'Dragon Rend', {154} 'Attack Damage Mult', {155} 'Heal Rate Mult', {156} 'Magicka Rate Mult', {157} 'Stamina Rate Mult', {158} 'Werewolf Perks', {159} 'Vampire Perks', {160} 'Grab Actor Offset', {161} 'Grabbed', {162} 'Unknown 162', {163} 'Reflect Damage' ], [ -1, 'None' ]); wbSkillEnum := wbEnum([ 'Unknown 1', 'Unknown 2', 'Unknown 3', 'Unknown 4', 'Unknown 5', 'Unknown 6', 'One Handed', 'Two Handed', 'Archery', 'Block', 'Smithing', 'Heavy Armor', 'Light Armor', 'Pickpocket', 'Lockpicking', 'Sneak', 'Alchemy', 'Speech', 'Alteration', 'Conjuration', 'Destruction', 'Illusion', 'Restoration', 'Enchanting' ], [ -1, 'None' ]); wbCastEnum := wbEnum([ {0} 'Constant Effect', {1} 'Fire and Forget', {2} 'Concentration', {3} 'Scroll' ]); wbTargetEnum := wbEnum([ {0} 'Self', {1} 'Touch', {2} 'Aimed', {3} 'Target Actor', {4} 'Target Location' ]); wbCastingSourceEnum := wbEnum([ 'Left', 'Right', 'Voice', 'Instant' ]); wbCrimeTypeEnum := wbEnum([ 'Steal', 'Pickpocket', 'Trespass', 'Attack', 'Murder', 'Escape Jail', 'Werewolf Transformation' ], [ -1, 'None' ]); wbActorValue := wbInteger('Actor Value', itS32, wbActorValueEnum); wbETYP := wbFormIDCk(ETYP, 'Equipment Type', [EQUP, NULL]); wbETYPReq := wbFormIDCk(ETYP, 'Equipment Type', [EQUP, NULL], False, cpNormal, True); wbFormTypeEnum := wbEnum([], [ 0, 'Activator', 1, 'Armor', 2, 'Book', 3, 'Container', 4, 'Door', 5, 'Ingredient', 6, 'Light', 7, 'MiscItem', 8, 'Static', 9, 'Grass', 10, 'Tree', 12, 'Weapon', 13, 'Actor', 14, 'LeveledCharacter', 15, 'Spell', 16, 'Enchantment', 17, 'Potion', 18, 'LeveledItem', 19, 'Key', 20, 'Ammo', 21, 'Flora', 22, 'Furniture', 23, 'Sound Marker', 24, 'LandTexture', 25, 'CombatStyle', 26, 'LoadScreen', 27, 'LeveledSpell', 28, 'AnimObject', 29, 'WaterType', 30, 'IdleMarker', 31, 'EffectShader', 32, 'Projectile', 33, 'TalkingActivator', 34, 'Explosion', 35, 'TextureSet', 36, 'Debris', 37, 'MenuIcon', 38, 'FormList', 39, 'Perk', 40, 'BodyPartData', 41, 'AddOnNode', 42, 'MovableStatic', 43, 'CameraShot', 44, 'ImpactData', 45, 'ImpactDataSet', 46, 'Quest', 47, 'Package', 48, 'VoiceType', 49, 'Class', 50, 'Race', 51, 'Eyes', 52, 'HeadPart', 53, 'Faction', 54, 'Note', 55, 'Weather', 56, 'Climate', 57, 'ArmorAddon', 58, 'Global', 59, 'Imagespace', 60, 'Imagespace Modifier', 61, 'Encounter Zone', 62, 'Message', 63, 'Constructible Object', 64, 'Acoustic Space', 65, 'Ragdoll', 66, 'Script', 67, 'Magic Effect', 68, 'Music Type', 69, 'Static Collection', 70, 'Keyword', 71, 'Location', 72, 'Location Ref Type', 73, 'Footstep', 74, 'Footstep Set', 75, 'Material Type', 76, 'Actor Action', 77, 'Music Track', 78, 'Word of Power', 79, 'Shout', 80, 'Relationship', 81, 'Equip Slot', 82, 'Association Type', 83, 'Outfit', 84, 'Art Object', 85, 'Material Object', 87, 'Lighting Template', 88, 'Shader Particle Geometry', 89, 'Visual Effect', 90, 'Apparatus', 91, 'Movement Type', 92, 'Hazard', 93, 'SM Event Node', 94, 'Sound Descriptor', 95, 'Dual Cast Data', 96, 'Sound Category', 97, 'Soul Gem', 98, 'Sound Output Model', 99, 'Collision Layer', 100, 'Scroll', 101, 'ColorForm', 102, 'Reverb Parameters' ]); wbMiscStatEnum := wbEnum([], [ Int64($FCDD5011), 'Animals Killed', Int64($366D84CF), 'Armor Improved', Int64($023497E6), 'Armor Made', Int64($8E20D7C9), 'Assaults', Int64($579FFA75), 'Automations Killed', Int64($B9B50725), 'Backstabs', Int64($ED6A0EF2), 'Barters', Int64($CCB952CE), 'Books Read', Int64($317E8B4C), 'Brawls Won', Int64($1D79006B), 'Bribes', Int64($3602DE8F), 'Bunnies Slaughtered', Int64($53D9E9B5), 'Chests Looted', Int64($683C1980), 'Civil War Quests Completed', Int64($66CCC50A), 'College of Winterhold Quests Completed', Int64($40B11EFE), 'Creatures Killed', Int64($22D5BA38), 'Critical Strikes', Int64($A930980F), 'Daedra Killed', Int64($3558374B), 'Daedric Quests Completed', Int64($37A76425), 'Dawnguard Quests Completed', Int64($2BDAC36F), 'Days as a Vampire', Int64($6E684590), 'Days as a Werewolf', Int64($B6F118DB), 'Days Jailed', Int64($3C626A90), 'Days Passed', Int64($8556AD88), 'Diseases Contracted', Int64($46D6FBBC), 'Dragon Souls Collected', Int64($AA444695), 'Dungeons Cleared', Int64($1A37F336), 'Eastmarch Bounty', Int64($5AC3A8ED), 'Falkreath Bounty', Int64($87B12ECC), 'Favorite School', Int64($518BBC4E), 'Favorite Shout', Int64($41DD77A6), 'Favorite Spell', Int64($171C5391), 'Favorite Weapon', Int64($4F041AA2), 'Fines Paid', Int64($9311B22B), 'Food Eaten', Int64($57C089F7), 'Gold Found', Int64($D20EDA4F), 'Haafingar Bounty', Int64($516C486D), 'Hjaalmarch Bounty', Int64($B0A1E32E), 'Horses Owned', Int64($EBAE35E8), 'Horses Stolen', Int64($FA024018), 'Hours Slept', Int64($CAD2ECA1), 'Hours Waiting', Int64($527DF857), 'Houses Owned', Int64($47B4A015), 'Ingredients Eaten', Int64($CE842356), 'Ingredients Harvested', Int64($7D2E57C0), 'Intimidations', Int64($C21702B5), 'Items Pickpocketed', Int64($82F190C2), 'Items Stolen', Int64($6627464B), 'Jail Escapes', Int64($3520E710), 'Largest Bounty', Int64($8A24FDE2), 'Locations Discovered', Int64($5829CC2E), 'Locks Picked', Int64($88089979), 'Magic Items Made', Int64($7EA26C2D), 'Main Quests Completed', Int64($7187A208), 'Mauls', Int64($98EE55DC), 'Misc Objectives Completed', Int64($FA06230B), 'Most Gold Carried', Int64($D37C6909), 'Murders', Int64($22C2CBD0), 'Necks Bitten', Int64($BEEBCC87), 'Nirnroots Found', Int64($56CCFC54), 'NumVampirePerks', Int64($76A1A5C0), 'NumWerewolfPerks', Int64($F22A8133), 'People Killed', Int64($47A78467), 'Persuasions', Int64($F2BAC234), 'Pockets Picked', Int64($17C64668), 'Poisons Mixed', Int64($7D8F2EA6), 'Poisons Used', Int64($4228DE85), 'Potions Mixed', Int64($9631EC11), 'Potions Used', Int64($DE6C73FE), 'Questlines Completed', Int64($0D7B8B16), 'Quests Completed', Int64($BB39399E), 'Shouts Learned', Int64($731B5333), 'Shouts Mastered', Int64($F921D8BA), 'Shouts Unlocked', Int64($B1AE4792), 'Side Quests Completed', Int64($ACE470D7), 'Skill Books Read', Int64($F33130CE), 'Skill Increases', Int64($B556CC52), 'Sneak Attacks', Int64($A74CBE83), 'Soul Gems Used', Int64($C2C9E233), 'Souls Trapped', Int64($5EC89F1A), 'Spells Learned', Int64($B251A346), 'Standing Stones Found', Int64($05D45702), 'Stores Invested In', Int64($D0FE7031), 'The Companions Quests Completed', Int64($52BA68CB), 'The Dark Brotherhood Quests Completed', Int64($3E267D77), 'The Pale Bounty', Int64($69B48177), 'The Reach Bounty', Int64($50A23F69), 'The Rift Bounty', Int64($62B2E95D), 'Thieves'' Guild Quests Completed', Int64($944CEA93), 'Times Jailed', Int64($50AAB633), 'Times Shouted', Int64($99BB86D8), 'Total Lifetime Bounty', Int64($4C252391), 'Training Sessions', Int64($7AEA9C2B), 'Trespasses', Int64($A67626F4), 'Tribal Orcs Bounty', Int64($41D4BC0F), 'Undead Killed', Int64($F39260A1), 'Vampirism Cures', Int64($61A5C5A9), 'Weapons Disarmed', Int64($1D3BA844), 'Weapons Improved', Int64($25F1EA25), 'Weapons Made', Int64($38A2DD66), 'Werewolf Transformations', Int64($4231FA4F), 'Whiterun Bounty', Int64($92565767), 'Wings Plucked', Int64($C7FC518D), 'Winterhold Bounty', Int64($949FA7BC), 'Words of Power Learned', Int64($2C6E3FC0), 'Words of Power Unlocked' ]); wbAdvanceActionEnum := wbEnum([ 'Normal Usage', 'Power Attack', 'Bash', 'Lockpick Success', 'Lockpick Broken' ]); wbAlignmentEnum := wbEnum([ 'Good', 'Neutral', 'Evil', 'Very Good', 'Very Evil' ]); wbAxisEnum := wbEnum([], [ 88, 'X', 89, 'Y', 90, 'Z' ]); wbCriticalStageEnum := wbEnum([ 'None', 'Goo Start', 'Goo End', 'Disintegrate Start', 'Disintegrate End' ]); wbSexEnum := wbEnum(['Male','Female']); wbEFID := wbFormIDCk(EFID, 'Base Effect', [MGEF]); wbEFIT := wbStructSK(EFIT, [3, 4], '', [ wbFloat('Magnitude', cpNormal, True), wbInteger('Area', itU32), wbInteger('Duration', itU32) ], cpNormal, True, nil, -1, wbEFITAfterLoad); wbCTDA := wbRStruct('Condition', [ wbStruct(CTDA, '', [ wbInteger('Type', itU8, wbCtdaTypeToStr, wbCtdaTypeToInt, cpNormal, False, nil, wbCtdaTypeAfterSet), wbByteArray('Unused', 3, cpIgnore, False, wbNeverShow), wbUnion('Comparison Value', wbCTDACompValueDecider, [ wbFloat('Comparison Value - Float'), wbFormIDCk('Comparison Value - Global', [GLOB]) ]), wbInteger('Function', itU16, wbCTDAFunctionToStr, wbCTDAFunctionToInt), wbByteArray('Unused', 2, cpIgnore, False, wbNeverShow), wbUnion('Parameter #1', wbCTDAParam1Decider, [ wbByteArray('Unknown', 4), wbByteArray('None', 4, cpIgnore), wbInteger('Integer', itS32), wbFloat('Float'), wbByteArray('Variable Name (unused)', 4, cpIgnore), wbInteger('Sex', itU32, wbSexEnum), wbInteger('Actor Value', itS32, wbActorValueEnum), wbInteger('Crime Type', itU32, wbCrimeTypeEnum), wbInteger('Axis', itU32, wbAxisEnum), wbInteger('Quest Stage (unused)', itS32), wbInteger('Misc Stat', itU32, wbMiscStatEnum), wbInteger('Alignment', itU32, wbAlignmentEnum), wbFormIDCkNoReach('Equip Type', [EQUP]), wbInteger('Form Type', itU32, wbFormTypeEnum), wbInteger('Critical Stage', itU32, wbCriticalStageEnum), wbFormIDCkNoReach('Object Reference', [NULL, PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA]), wbFormIDCkNoReach('Inventory Object', [ARMO, BOOK, MISC, WEAP, AMMO, KEYM, ALCH, SCRL, SLGM, INGR, FLST, LIGH, LVLI, COBJ]), wbFormIDCkNoReach('Actor', [NULL, PLYR, ACHR, REFR]), wbFormIDCkNoReach('Voice Type', [VTYP, FLST]), wbFormIDCkNoReach('Idle', [IDLE]), wbFormIDCkNoReach('Form List', [FLST]), wbFormIDCkNoReach('Quest', [QUST]), wbFormIDCkNoReach('Faction', [FACT]), wbFormIDCkNoReach('Cell', [CELL]), wbFormIDCkNoReach('Class', [CLAS]), wbFormIDCkNoReach('Race', [RACE]), wbFormIDCkNoReach('Actor Base', [NPC_]), wbFormIDCkNoReach('Global', [GLOB]), wbFormIDCkNoReach('Weather', [WTHR]), wbFormIDCkNoReach('Package', [PACK]), wbFormIDCkNoReach('Encounter Zone', [ECZN]), wbFormIDCkNoReach('Perk', [PERK]), wbFormIDCkNoReach('Owner', [NULL, FACT, NPC_]), wbFormIDCkNoReach('Furniture', [FURN, FLST]), wbFormIDCkNoReach('Effect Item', [SPEL, ENCH, ALCH, INGR, SCRL]), wbFormIDCkNoReach('Base Effect', [MGEF]), wbFormIDCkNoReach('Worldspace', [WRLD, FLST]), wbInteger('VATS Value Function', itU32, wbVATSValueFunctionEnum), wbInteger('VATS Value Param (INVALID)', itU32), wbFormIDCkNoReach('Referenceable Object', [NULL, NPC_, PROJ, TREE, SOUN, ACTI, DOOR, STAT, FURN, CONT, ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, LIGH, GRAS, ASPC, IDLM, ARMA, MSTT, TACT, FLST, LVLI, LVSP, SPEL, SCRL, SHOU, SLGM, ENCH], [NPC_, PROJ, TREE, SOUN, ACTI, DOOR, STAT, FURN, CONT, ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, LIGH, GRAS, ASPC, IDLM, ARMA, MSTT, TACT, LVLI, LVSP, SPEL, SCRL, SHOU, SLGM, ENCH]), wbFormIDCkNoReach('Region', [REGN]), wbFormIDCkNoReach('Keyword', [KYWD, NULL]), wbInteger('Player Action', itU32, wbAdvanceActionEnum), wbInteger('Casting Type', itU32, wbCastingSourceEnum), wbFormIDCkNoReach('Shout', [SHOU]), wbFormIDCkNoReach('Location', [LCTN]), wbFormIDCkNoReach('Location Ref Type', [LCRT]), wbInteger('Alias', itS32, wbConditionAliasToStr, wbStrToAlias), wbInteger('Packdata ID', itU32), wbFormIDCk('Association Type', [ASTP]), wbInteger('Furniture Anim', itU32, wbFurnitureAnimTypeEnum), wbInteger('Furniture Entry', itU32, wbEnum([], [$010000, 'Front', $020000, 'Behind', $040000, 'Right', $80000, 'Left', $100000, 'Up'])), wbFormIDCk('Scene', [NULL, SCEN]), wbInteger('Ward State', itU32, wbWardStateEnum), wbInteger('Event', itU32, wbEventFunctionAndMemberToStr, wbEventFunctionAndMemberToInt), wbFormID('Event Data') ]), wbUnion('Parameter #2', wbCTDAParam2Decider, [ wbByteArray('Unknown', 4), wbByteArray('None', 4, cpIgnore), wbInteger('Integer', itS32), wbFloat('Float'), wbByteArray('Variable Name (unused)', 4, cpIgnore), wbInteger('Sex', itU32, wbSexEnum), wbInteger('Actor Value', itS32, wbActorValueEnum), wbInteger('Crime Type', itU32, wbCrimeTypeEnum), wbInteger('Axis', itU32, wbAxisEnum), wbInteger('Quest Stage', itS32, wbCTDAParam2QuestStageToStr, wbCTDAParam2QuestStageToInt), wbInteger('Misc Stat', itU32, wbMiscStatEnum), wbInteger('Alignment', itU32, wbAlignmentEnum), wbFormIDCkNoReach('Equip Type', [EQUP]), wbInteger('Form Type', itU32, wbFormTypeEnum), wbInteger('Critical Stage', itU32, wbCriticalStageEnum), wbFormIDCkNoReach('Object Reference', [NULL, PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA]), wbFormIDCkNoReach('Inventory Object', [ARMO, BOOK, MISC, WEAP, AMMO, KEYM, ALCH, SCRL, SLGM, INGR, FLST, LIGH, LVLI, COBJ]), wbFormIDCkNoReach('Actor', [NULL, PLYR, ACHR, REFR]), wbFormIDCkNoReach('Voice Type', [VTYP, FLST]), wbFormIDCkNoReach('Idle', [IDLE]), wbFormIDCkNoReach('Form List', [FLST]), wbFormIDCkNoReach('Quest', [QUST]), wbFormIDCkNoReach('Faction', [FACT]), wbFormIDCkNoReach('Cell', [CELL]), wbFormIDCkNoReach('Class', [CLAS]), wbFormIDCkNoReach('Race', [RACE]), wbFormIDCkNoReach('Actor Base', [NPC_]), wbFormIDCkNoReach('Global', [GLOB]), wbFormIDCkNoReach('Weather', [WTHR]), wbFormIDCkNoReach('Package', [PACK]), wbFormIDCkNoReach('Encounter Zone', [ECZN]), wbFormIDCkNoReach('Perk', [PERK]), wbFormIDCkNoReach('Owner', [NULL, FACT, NPC_]), wbFormIDCkNoReach('Furniture', [FURN, FLST]), wbFormIDCkNoReach('Effect Item', [SPEL, ENCH, ALCH, INGR, SCRL]), wbFormIDCkNoReach('Base Effect', [MGEF]), wbFormIDCkNoReach('Worldspace', [WRLD, FLST]), wbInteger('VATS Value Function', itU32, wbVATSValueFunctionEnum), wbUnion('VATS Value Param', wbCTDAParam2VATSValueParamDecider, [ { 0} wbFormIDCkNoReach('Weapon', [WEAP]), { 1} wbFormIDCkNoReach('Weapon List', [FLST], [WEAP]), { 2} wbFormIDCkNoReach('Target', [NPC_]), { 3} wbFormIDCkNoReach('Target List', [FLST], [NPC_]), { 4} wbByteArray('Unknown', 4, cpIgnore), { 5} wbInteger('Target Part', itS32, wbActorValueEnum), { 6} wbInteger('VATS Action', itU32, wbEnum([ 'Unarmed Attack', 'One Hand Melee Attack', 'Two Hand Melee Attack', 'Magic Attack', 'Ranged Attack', 'Reload', 'Crouch', 'Stand', 'Switch Weapon', 'Toggle Weapon Drawn', 'Heal', 'Player Death' ])), { 7} wbByteArray('Unknown', 4, cpIgnore), { 8} wbByteArray('Unknown', 4, cpIgnore), { 9} wbFormIDCkNoReach('Critical Effect', [SPEL]), {10} wbFormIDCkNoReach('Critical Effect List', [FLST], [SPEL]), {11} wbByteArray('Unknown', 4, cpIgnore), {12} wbByteArray('Unknown', 4, cpIgnore), {13} wbByteArray('Unknown', 4, cpIgnore), {14} wbByteArray('Unknown', 4, cpIgnore), {15} wbInteger('Weapon Type', itU32, wbWeaponAnimTypeEnum), {16} wbByteArray('Unknown', 4, cpIgnore), {17} wbByteArray('Unknown', 4, cpIgnore), {18} wbInteger('Projectile Type', itU32, wbEnum([ 'Missile', 'Lobber', 'Beam', 'Flame', 'Cone', 'Barrier', 'Arrow' ])), {19} wbInteger('Delivery Type', itU32, wbTargetEnum), {20} wbInteger('Casting Type', itU32, wbCastEnum) ]), wbFormIDCkNoReach('Referenceable Object', [NULL, NPC_, PROJ, TREE, SOUN, ACTI, DOOR, STAT, FURN, CONT, ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, LIGH, GRAS, ASPC, IDLM, ARMA, MSTT, TACT, FLST, LVLI, LVSP, SPEL, SCRL, SHOU, SLGM, ENCH], [NPC_, PROJ, TREE, SOUN, ACTI, DOOR, STAT, FURN, CONT, ARMO, AMMO, MISC, WEAP, BOOK, KEYM, ALCH, LIGH, GRAS, ASPC, IDLM, ARMA, MSTT, TACT, LVLI, LVSP, SPEL, SCRL, SHOU, SLGM, ENCH]), wbFormIDCkNoReach('Region', [REGN]), wbFormIDCkNoReach('Keyword', [KYWD, NULL]), wbInteger('Player Action', itU32, wbAdvanceActionEnum), wbInteger('Casting Type', itU32, wbCastingSourceEnum), wbFormIDCkNoReach('Shout', [SHOU]), wbFormIDCkNoReach('Location', [LCTN]), wbFormIDCkNoReach('Location Ref Type', [LCRT]), wbInteger('Alias', itS32, wbConditionAliasToStr, wbStrToAlias), wbInteger('Packdata ID', itU32), wbFormIDCk('Association Type', [ASTP]), wbInteger('Furniture Anim', itU32, wbFurnitureAnimTypeEnum), wbInteger('Furniture Entry', itU32, wbEnum([], [$010000, 'Front', $020000, 'Behind', $040000, 'Right', $80000, 'Left', $100000, 'Up'])), wbFormIDCk('Scene', [NULL, SCEN]), wbInteger('Ward State', itU32, wbWardStateEnum), wbInteger('Event', itU32, wbEventFunctionAndMemberToStr, wbEventFunctionAndMemberToInt), wbFormID('Event Data') ]), wbInteger('Run On', itU32, wbEnum([ {0} 'Subject', {1} 'Target', {2} 'Reference', {3} 'Combat Target', {4} 'Linked Reference', {5} 'Quest Alias', {6} 'Package Data', {7} 'Event Data' ]), cpNormal, False, nil, wbCTDARunOnAfterSet), wbUnion('Reference', wbCTDAReferenceDecider, [ wbInteger('Unused', itU32, nil, cpIgnore), wbFormIDCkNoReach('Reference', [NULL, PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA], False) ]), wbInteger('Parameter #3', itS32, nil, cpNormal, False, nil, nil, -1) ], cpNormal, False{, nil, 0, wbCTDAAfterLoad}), wbString(CIS1, 'Parameter #1'), wbString(CIS2, 'Parameter #2') ], [], cpNormal); wbCTDAs := wbRArray('Conditions', wbCTDA, cpNormal, False); wbCTDAsCount := wbRArray('Conditions', wbCTDA, cpNormal, False, nil, wbCTDAsAfterSet); wbCTDAsReq := wbRArray('Conditions', wbCTDA, cpNormal, True); wbCTDAsReqCount := wbRArray('Conditions', wbCTDA, cpNormal, True, nil, wbCTDAsAfterSet); wbYNAM := wbFormIDCk(YNAM, 'Sound - Pick Up', [SNDR]); wbZNAM := wbFormIDCk(ZNAM, 'Sound - Put Down', [SNDR]); wbEffectsReq := wbRStructs('Effects', 'Effect', [ wbEFID, wbEFIT, wbCTDAs ], [], cpNormal, True); wbRecord(ALCH, 'Ingestible', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x20000000} 29, 'Medicine' ])), [ wbEDID, wbOBNDReq, wbFULL, wbKSIZ, wbKWDAs, wbDESC, wbMODL, wbDEST, wbICON, wbYNAM, wbZNAM, wbETYP, wbFloat(DATA, 'Weight', cpNormal, True), wbStruct(ENIT, 'Effect Data', [ wbInteger('Value', itS32), wbInteger('Flags', itU32, wbFlags([ {0x00000001} 'No Auto-Calc', {0x00000002} 'Food Item', {0x00000004} 'Unknown 3', {0x00000008} 'Unknown 4', {0x00000010} 'Unknown 5', {0x00000020} 'Unknown 6', {0x00000040} 'Unknown 7', {0x00000080} 'Unknown 8', {0x00000100} 'Unknown 9', {0x00000200} 'Unknown 10', {0x00000400} 'Unknown 11', {0x00000800} 'Unknown 12', {0x00001000} 'Unknown 13', {0x00002000} 'Unknown 14', {0x00004000} 'Unknown 15', {0x00008000} 'Unknown 16', {0x00010000} 'Medicine', {0x00020000} 'Poison' ])), wbFormID('Addiction'), wbFloat('Addiction Chance'), wbFormIDCk('Sound - Consume', [SNDR, NULL]) ], cpNormal, True), wbEffectsReq ], False, nil, cpNormal, False, wbRemoveEmptyKWDA, wbKeywordsAfterSet); wbRecord(AMMO, 'Ammunition', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000004} 2, 'Non-Playable' ])), [ wbEDID, wbOBNDReq, wbFULL, wbMODL, wbICON, wbDEST, wbYNAM, wbZNAM, wbDESC, wbKSIZ, wbKWDAs, wbStruct(DATA, 'Data', [ wbFormIDCk('Projectile', [PROJ, NULL]), wbInteger('Flags', itU32, wbFlags([ 'Ignores Normal Weapon Resistance', 'Non-Playable', 'Non-Bolt' ])), wbFloat('Damage'), wbInteger('Value', itU32) ], cpNormal, True), wbString(ONAM, 'Short Name') ], False, nil, cpNormal, False, wbRemoveEmptyKWDA, wbKeywordsAfterSet); wbRecord(ANIO, 'Animated Object', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000200} 9, 'Unknown 9' // always present in updated records, not in Skyrim.esm ]), [9]), [ wbEDID, wbMODL, wbString(BNAM, 'Unload Event') ]); wbRecord(ARMO, 'Armor', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000004} 2, 'Non-Playable', {0x00000040} 6, 'Shield', {0x00000400} 10, 'Unknown 10', {0x00008000} 15, 'Unknown 15' ])), [ wbEDID, wbVMAD, wbOBNDReq, wbFULL, wbEITM, wbInteger(EAMT, 'Enchantment Amount', itU16), wbRStruct('Male world model', [ wbString(MOD2, 'Model Filename'), wbByteArray(MO2T, 'Texture Files Hashes', 0, cpIgnore, false, false, wbNeverShow), wbMO2S ], []), wbICON, wbRStruct('Female world model', [ wbString(MOD4, 'Model Filename'), wbByteArray(MO4T, 'Texture Files Hashes', 0, cpIgnore, false, false, wbNeverShow), wbMO4S ], []), wbICO2, wbBODTBOD2, wbDEST, wbYNAM, wbZNAM, wbString(BMCT, 'Ragdoll Constraint Template'), wbETYP, wbFormIDCk(BIDS, 'Bash Impact Data Set', [IPDS]), wbFormIDCk(BAMT, 'Alternate Block Material', [MATT]), wbFormIDCk(RNAM, 'Race', [RACE]), wbKSIZ, wbKWDAs, wbDESC, wbRArray('Armature', wbFormIDCK(MODL, 'Model Filename', [ARMA, NULL])), wbStruct(DATA, 'Data', [ wbInteger('Value', itS32), wbFloat('Weight') ], cpNormal, True), wbInteger(DNAM, 'Armor Rating', itS32, wbDiv(100), cpNormal, True), wbFormIDCk(TNAM, 'Template Armor', [ARMO]) ], False, nil, cpNormal, False, wbARMOAfterLoad, wbKeywordsAfterSet); wbRecord(ARMA, 'Armor Addon', [ wbEDID, wbBODTBOD2, wbFormIDCk(RNAM, 'Race', [RACE]), wbStruct(DNAM, 'Data', [ wbInteger('Male Priority', itU8), wbInteger('Female Priority', itU8), // essentialy a number of world models for different weights (Enabled = 2 models _0.nif and _1.nif) wbInteger('Weight slider - Male', itU8, wbFlags([ {0x01} 'Unknown 0', {0x02} 'Enabled' ])), wbInteger('Weight slider - Female', itU8, wbFlags([ {0x01} 'Unknown 0', {0x02} 'Enabled' ])), wbByteArray('Unknown', 2), wbInteger('Detection Sound Value', itU8), wbByteArray('Unknown', 1), wbFloat('Weapon Adjust') ], cpNormal, True), wbRStruct('Male world model', [ wbString(MOD2, 'Model Filename'), wbByteArray(MO2T, 'Texture Files Hashes', 0, cpIgnore, false, false, wbNeverShow), wbMO2S ], [], cpNormal, False), wbRStruct('Female world model', [ wbString(MOD3, 'Model Filename'), wbByteArray(MO3T, 'Texture Files Hashes', 0, cpIgnore, false, false, wbNeverShow), wbMO3S ], []), wbRStruct('Male 1st Person', [ wbString(MOD4, 'Model Filename'), wbByteArray(MO4T, 'Texture Files Hashes', 0, cpIgnore, false, false, wbNeverShow), wbMO4S ], []), wbRStruct('Female 1st Person', [ wbString(MOD5, 'Model Filename'), wbByteArray(MO5T, 'Texture Files Hashes', 0, cpIgnore, false, false, wbNeverShow), wbMO5S ], []), wbFormIDCK(NAM0, 'Male Skin Texture', [TXST, NULL]), wbFormIDCK(NAM1, 'Female Skin texture', [TXST, NULL]), wbFormIDCK(NAM2, 'Male Skin Texture Swap List', [FLST, NULL]), wbFormIDCK(NAM3, 'Female Skin Texture Swap List', [FLST, NULL]), wbRArrayS('Additional Races', wbFormIDCK(MODL, 'Race', [RACE, NULL])), wbFormIDCk(SNDD, 'Footstep Sound', [FSTS, NULL]), wbFormIDCk(ONAM, 'Art Object', [ARTO]) ], False, nil, cpNormal, False, wbARMAAfterLoad); wbRecord(BOOK, 'Book', [ wbEDID, wbVMAD, wbOBNDReq, wbFULL, wbMODL, wbICON, wbLStringKC(DESC, 'Book Text', 0, cpTranslate, True), wbDEST, wbYNAM, wbZNAM, wbKSIZ, wbKWDAs, wbStruct(DATA, 'Data', [ wbInteger('Flags', itU8, wbFlags([ {0x01} 'Teaches Skill', {0x02} 'Can''t be Taken', {0x04} 'Teaches Spell', {0x08} 'Unknown 4', {0x10} 'Unknown 5', {0x20} 'Unknown 6', {0x40} 'Unknown 7', {0x80} 'Unknown 8' ])), wbInteger('Type', itU8, wbEnum([], [ 0, 'Book/Tome', 255, 'Note/Scroll' ])), wbByteArray('Unused', 2), wbUnion('Teaches', wbBOOKTeachesDecider, [ wbInteger('Skill', itS32, wbSkillEnum), wbFormIDCk('Spell', [SPEL, NULL]) ]), wbInteger('Value', itU32), wbFloat('Weight') ], cpNormal, True), wbFormIDCk(INAM, 'Inventory Art', [STAT]), wbLString(CNAM, 'Description', 0, cpTranslate) ], False, nil, cpNormal, False, nil, wbKeywordsAfterSet); end; procedure DefineTES5c; procedure ReferenceRecord(aSignature: TwbSignature; const aName: string); begin wbRecord(aSignature, aName, wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000080} 7, 'Turn Off Fire', {0x00000400} 10, 'Persistent', {0x00000800} 11, 'Initially Disabled', {0x10000000} 28, 'Reflected By Auto Water', {0x20000000} 29, 'Don''t Havok Settle', {0x40000000} 30, 'No Respawn' ], True, True)), [ wbEDID, wbVMAD, wbFormIDCk(NAME, 'Projectile', [PROJ, HAZD]), wbFormIDCk(XEZN, 'Encounter Zone', [ECZN]), wbOwnership, wbFloat(XHTW, 'Head-Tracking Weight'), wbFloat(XFVC, 'Favor Cost'), wbRArrayS('Reflected/Refracted By', wbStructSK(XPWR, [0], 'Water', [ wbFormIDCk('Reference', [REFR]), wbInteger('Type', itU32, wbFlags([ 'Reflection', 'Refraction' ])) ], cpNormal, False, nil, 1) ), wbRArrayS('Linked References', wbStructSK(XLKR, [0], 'Linked Reference', [ wbFormIDCk('Keyword/Ref', [KYWD, PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA, NULL]), wbFormIDCk('Ref', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA]) ], cpNormal, False, nil, 1)), wbRStruct('Activate Parents', [ wbInteger(XAPD, 'Flags', itU8, wbFlags([ 'Parent Activate Only' ], True)), wbRArrayS('Activate Parent Refs', wbStructSK(XAPR, [0], 'Activate Parent Ref', [ wbFormIDCk('Reference', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA]), wbFloat('Delay') ]) ) ], []), wbXESP, wbFormIDCk(XEMI, 'Emittance', [LIGH, REGN]), wbFormIDCk(XMBR, 'MultiBound Reference', [REFR]), wbEmpty(XIS2, 'Ignored by Sandbox'), wbArray(XLRT, 'Location Ref Type', wbFormIDCk('Ref', [LCRT, NULL])), wbFormIDCk(XLRL, 'Location Reference', [LCRT, LCTN, NULL], False, cpBenignIfAdded), wbXLOD, wbXSCL, wbDataPosRot ], True, wbPlacedAddInfo); end; begin {>>> Skrim has its own ref record for every projectile type PARW 'Arrow' PBEA 'Beam' PFLA 'Flame' PCON 'Cone' (voice) PBAR 'Barrier' PGRE 'Traps' PHZD 'Hazards' I guess all of them have the same structure <<<} ReferenceRecord(PARW, 'Placed Arrow'); ReferenceRecord(PBAR, 'Placed Barrier'); ReferenceRecord(PBEA, 'Placed Beam'); ReferenceRecord(PCON, 'Placed Cone/Voice'); ReferenceRecord(PFLA, 'Placed Flame'); ReferenceRecord(PGRE, 'Placed Projectile'); ReferenceRecord(PHZD, 'Placed Hazard'); ReferenceRecord(PMIS, 'Placed Missile'); wbRecord(CELL, 'Cell', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000400} 10, 'Persistent', {0x00020000} 17, 'Off Limits', {0x00040000} 18, 'Compressed', {0x00080000} 19, 'Can''t Wait' ]), [18]), [ wbEDID, wbFULL, {>>> Flags can be itU8, but CELL\DATA has a critical role in various wbImplementation.pas routines and replacing it with wbUnion generates error when setting for example persistent flag in REFR. So let it always be an integer <<<} wbInteger(DATA, 'Flags', itU16, wbFlags([ {0x0001} 'Is Interior Cell', {0x0002} 'Has Water', {0x0004} 'Can''t Travel From Here', {0x0008} 'No LOD Water', {0x0010} 'Unknown 5', {0x0020} 'Public Area', {0x0040} 'Hand Changed', {0x0080} 'Show Sky', {0x0100} 'Use Sky Lighting' ]), cpNormal, True, False, nil, wbCELLDATAAfterSet), wbStruct(XCLC, 'Grid', [ wbInteger('X', itS32), wbInteger('Y', itS32), wbInteger('Force Hide Land', itU32, wbFlags([ 'Quad 1', 'Quad 2', 'Quad 3', 'Quad 4' ], True)) ], cpNormal, False, nil, 2), wbStruct(XCLL, 'Lighting', [ wbByteColors('Ambient Color'), wbByteColors('Directional Color'), wbByteColors('Fog Color Near'), wbFloat('Fog Near'), wbFloat('Fog Far'), wbInteger('Directional Rotation XY', itS32), wbInteger('Directional Rotation Z', itS32), wbFloat('Directional Fade'), wbFloat('Fog Clip Distance'), wbFloat('Fog Power'), wbAmbientColors('Ambient Colors'), wbByteColors('Fog Color Far'), wbFloat('Fog Max'), wbFloat('Light Fade Begin'), wbFloat('Light Fade End'), wbInteger('Inherits', itU32, wbFlags([ {0x00000001}'Ambient Color', {0x00000002}'Directional Color', {0x00000004}'Fog Color', {0x00000008}'Fog Near', {0x00000010}'Fog Far', {0x00000020}'Directional Rotation', {0x00000040}'Directional Fade', {0x00000080}'Clip Distance', {0x00000100}'Fog Power', {0x00000200}'Fog Max', {0x00000400}'Light Fade Distances' ])) ], cpNormal, False, nil, 11), wbTVDT, wbMaxHeightDataCELL, wbFormIDCk(LTMP, 'Lighting Template', [LGTM, NULL], False, cpNormal, True), wbByteArray(LNAM, 'Unknown', 0, cpIgnore), // leftover flags, they are now in XCLC {>>> XCLW sometimes has $FF7FFFFF and causes invalid floation point <<<} wbFloat(XCLW, 'Water Height', cpNormal, False, 1, -1, nil, nil, 0, wbCELLXCLWGetConflictPriority), //wbByteArray(XCLW, 'Water Height', 4), wbString(XNAM, 'Water Noise Texture'), wbArrayS(XCLR, 'Regions', wbFormIDCk('Region', [REGN])), wbFormIDCk(XLCN, 'Location', [LCTN]), wbByteArray(XWCN, 'Unknown', 0, cpIgnore), // leftover wbByteArray(XWCS, 'Unknown', 0, cpIgnore), // leftover wbStruct(XWCU, 'Water Velocity', [ wbFloat('X Offset'), wbFloat('Y Offset'), wbFloat('Z Offset'), wbByteArray('Unknown', 4), wbFloat('X Angle'), wbFloat('Y Angle'), wbFloat('Z Angle'), wbByteArray('Unknown', 0) ]), wbFormIDCk(XCWT, 'Water', [WATR]), wbOwnership, wbFormIDCk(XILL, 'Lock List', [FLST, NPC_]), wbString(XWEM, 'Water Environment Map'), wbFormIDCk(XCCM, 'Sky/Weather from Region', [REGN]), wbFormIDCk(XCAS, 'Acoustic Space', [ASPC]), wbFormIDCk(XEZN, 'Encounter Zone', [ECZN]), wbFormIDCk(XCMO, 'Music Type', [MUSC]), wbFormIDCk(XCIM, 'Image Space', [IMGS]) ], True, wbCellAddInfo, cpNormal, False, wbCELLAfterLoad); wbRecord(CLAS, 'Class', [ wbEDID, wbFULLReq, wbDESCReq, wbICON, wbStruct(DATA, '', [ wbByteArray('Unknown', 4), wbInteger('Teaches', itS8, wbEnum([ 'One Handed', 'Two Handed', 'Archery', 'Block', 'Smithing', 'Heavy Armor', 'Light Armor', 'Pickpocket', 'Lockpicking', 'Sneak', 'Alchemy', 'Speech', 'Alteration', 'Conjuration', 'Destruction', 'Illusion', 'Restoration', 'Enchanting' ])), wbInteger('Maximum training level', itU8), wbArray('Skill Weights', wbInteger('Weight', itU8), [ 'One Handed', 'Two Handed', 'Archery', 'Block', 'Smithing', 'Heavy Armor', 'Light Armor', 'Pickpocket', 'Lockpicking', 'Sneak', 'Alchemy', 'Speech', 'Alteration', 'Conjuration', 'Destruction', 'Illusion', 'Restoration', 'Enchanting' ]), wbFloat('Bleedout Default'), wbInteger('Voice Points', itU32), wbArray('Attribute Weights', wbInteger('Weight', itU8), [ 'Health', 'Magicka', 'Stamina', 'Unknown' ]) ], cpNormal, True) ]); wbRecord(CLMT, 'Climate', [ wbEDID, wbArrayS(WLST, 'Weather Types', wbStructSK([0], 'Weather Type', [ wbFormIDCk('Weather', [WTHR, NULL]), wbInteger('Chance', itS32), wbFormIDCk('Global', [GLOB, NULL]) ])), wbString(FNAM, 'Sun Texture'), wbString(GNAM, 'Sun Glare Texture'), wbMODL, wbStruct(TNAM, 'Timing', [ wbStruct('Sunrise', [ wbInteger('Begin', itU8, wbClmtTime), wbInteger('End', itU8, wbClmtTime) ]), wbStruct('Sunset', [ wbInteger('Begin', itU8, wbClmtTime), wbInteger('End', itU8, wbClmtTime) ]), wbInteger('Volatility', itU8), wbInteger('Moons / Phase Length', itU8, wbClmtMoonsPhaseLength) ], cpNormal, True) ]); wbRecord(SPGD, 'Shader Particle Geometry', [ wbEDID, // FO4 SPGD format for Form Version 44 wbUnion(DATA, '', wbSPGDFormatDecider, [ wbStruct('Data', [ wbFloat('Gravity Velocity'), wbByteArray('Unknown', 4), wbFloat('Rotation Velocity'), wbByteArray('Unknown', 4), wbFloat('Particle Size X'), wbFloat('Center Offset Min'), wbFloat('Particle Size Y'), wbByteArray('Unknown', 4), wbFloat('Center Offset Min'), wbByteArray('Unknown', 4), wbFloat('Center Offset Max'), wbByteArray('Unknown', 4), wbFloat('Initial Rotation'), wbByteArray('Unknown', 4), wbInteger('# of Subtextures X', itU32), wbByteArray('Unknown', 4), wbInteger('# of Subtextures Y', itU32), wbByteArray('Unknown', 4), wbInteger('Type', itU32, wbEnum([ 'Rain', 'Snow' ])), wbByteArray('Unknown', 4), wbInteger('Box Size', itU32), wbByteArray('Unknown', 4), wbFloat('Particle Density'), wbByteArray('Unknown', 4) ], cpNormal, True), wbStruct('Data', [ wbFloat('Gravity Velocity'), wbFloat('Rotation Velocity'), wbFloat('Particle Size X'), wbFloat('Particle Size Y'), wbFloat('Center Offset Min'), wbFloat('Center Offset Max'), wbFloat('Initial Rotation Range'), wbInteger('# of Subtextures X', itU32), wbInteger('# of Subtextures Y', itU32), wbInteger('Type', itU32, wbEnum([ 'Rain', 'Snow' ])), wbInteger('Box Size', itU32), wbFloat('Particle Density') ], cpNormal, True, nil, 10) ]), wbString(ICON, 'Particle Texture') ]); wbRecord(RFCT, 'Visual Effect', [ wbEDID, wbStruct(DATA, 'Effect Data', [ wbFormIDCK('Effect Art', [ARTO, NULL]), wbFormIDCK('Shader', [EFSH, NULL]), wbInteger('Flags', itU32, wbFlags([ {0x00000001}'Rotate to Face Target', {0x00000002}'Attach to Camera', {0x00000004}'Inherit Rotation' ])) ], cpNormal, True) ]); wbRecord(CONT, 'Container', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00008000} 15, 'Has Distant LOD', {0x00010000} 16, 'Random Anim Start', {0x02000000} 25, 'Obstacle', {0x04000000} 26, 'NavMesh Generation - Filter', {0x08000000} 27, 'NavMesh Generation - Bounding Box', {0x40000000} 30, 'NavMesh Generation - Ground' ])), [ wbEDID, wbVMAD, wbOBNDReq, wbFULL, wbMODL, wbCOCT, wbCNTOs, wbDEST, wbStruct(DATA, '', [ wbInteger('Flags', itU8, wbFlags([ {0x01} 'Allow Sounds When Animation', {0x02} 'Respawns', {0x04} 'Show Owner' ])), wbFloat('Weight') ], cpNormal, True), wbFormIDCk(SNAM, 'Sound - Open', [SNDR]), wbFormIDCk(QNAM, 'Sound - Close', [SNDR]) ], True, nil, cpNormal, False, nil, wbContainerAfterSet); wbCSDT := wbRStructSK([0], 'Sound Type', [ wbInteger(CSDT, 'Type', itU32,wbEnum([ {00} 'Left Foot', {01} 'Right Foot', {02} 'Left Back Foot', {03} 'Right Back Foot', {04} 'Idle', {05} 'Aware', {06} 'Attack', {07} 'Hit', {08} 'Death', {09} 'Weapon', {10} 'Movement Loop', {11} 'Conscious Loop', {12} 'Auxiliary 1', {13} 'Auxiliary 2', {14} 'Auxiliary 3', {15} 'Auxiliary 4', {16} 'Auxiliary 5', {17} 'Auxiliary 6', {18} 'Auxiliary 7', {19} 'Auxiliary 8', {19} 'Auxiliary 8', {20} 'Jump', {21} 'PlayRandom/Loop' ])), wbRArrayS('Sounds', wbRStructSK([0], 'Sound', [ wbFormIDCk(CSDI, 'Sound', [SNDR, NULL], False, cpNormal, True), wbInteger(CSDC, 'Sound Chance', itU8, nil, cpNormal, True) ], []), cpNormal, True) ], []); wbCSDTs := wbRArrayS('Sound Types', wbCSDT, cpNormal, False, nil, nil, nil{wbActorTemplateUseModelAnimation}); wbAIDT := wbStruct(AIDT, 'AI Data', [ {00} wbInteger('Aggression', itU8, wbEnum([ 'Unaggressive', 'Aggressive', 'Very Aggressive', 'Frenzied' ])), {01} wbInteger('Confidence', itU8, wbEnum([ 'Cowardly', 'Cautious', 'Average', 'Brave', 'Foolhardy' ])), {02} wbInteger('Energy Level', itU8), {03} wbInteger('Responsibility', itU8, wbEnum([ 'Any crime', 'Violence against enemies', 'Property crime only', 'No crime' ])), {04} wbInteger('Mood', itU8, wbEnum([ 'Neutral', 'Angry', 'Fear', 'Happy', 'Sad', 'Surprised', 'Puzzled', 'Disgusted' ])), wbInteger('Assistance', itU8, wbEnum([ 'Helps Nobody', 'Helps Allies', 'Helps Friends and Allies' ])), wbStruct('Aggro', [ wbInteger('Aggro Radius Behavior', itU8, wbEnum(['False', 'True'])), wbInteger('Unknown', itU8), wbInteger('Warn', itU32), wbInteger('Warn/Attack', itU32), wbInteger('Attack', itU32) ]) ], cpNormal, True, nil{wbActorTemplateUseAIData}); wbAttackAnimationEnum := wbEnum([], [ 26, 'AttackLeft', 32, 'AttackRight', 38, 'Attack3', 44, 'Attack4', 50, 'Attack5', 56, 'Attack6', 62, 'Attack7', 68, 'Attack8', 74, 'AttackLoop', 80, 'AttackSpin', 86, 'AttackSpin2', 97, 'PlaceMine', 103, 'PlaceMine2', 109, 'AttackThrow', 115, 'AttackThrow2', 121, 'AttackThrow3', 127, 'AttackThrow4', 133, 'AttackThrow5', 255, ' DEFAULT' ]); wbRecord(CSTY, 'Combat Style', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00080000} 19, 'Allow Dual Wielding' ])), [ wbEDID, wbStruct(CSGD, 'General', [ wbFloat('Offensive Mult'), wbFloat('Defensive Mult'), wbFloat('Group Offensive Mult'), // keep as separate floats, some elements can be omitted wbFloat('Equipment Score Mult - Melee'), wbFloat('Equipment Score Mult - Magic'), wbFloat('Equipment Score Mult - Ranged'), wbFloat('Equipment Score Mult - Shout'), wbFloat('Equipment Score Mult - Unarmed'), wbFloat('Equipment Score Mult - Staff'), wbFloat('Avoid Threat Chance') ], cpNormal, True, nil, 0), wbUnknown(CSMD, cpIgnore), wbStruct(CSME, 'Melee', [ wbFloat('Attack Staggered Mult'), wbFloat('Power Attack Staggered Mult'), wbFloat('Power Attack Blocking Mult'), wbFloat('Bash Mult'), wbFloat('Bash Recoil Mult'), wbFloat('Bash Attack Mult'), wbFloat('Bash Power Attack Mult'), wbFloat('Special Attack Mult') ], cpNormal, False, nil, 0), wbStruct(CSCR, 'Close Range', [ wbFloat('Circle Mult'), wbFloat('Fallback Mult'), wbFloat('Flank Distance'), wbFloat('Stalk Time') ], cpNormal, False, nil, 0), wbStruct(CSLR, 'Long Range', [ wbFloat('Strafe Mult') ], cpNormal, False), wbStruct(CSFL, 'Flight', [ wbFloat('Hover Chance'), wbFloat('Dive Bomb Chance'), wbFloat('Ground Attack Chance'), wbFloat('Hover Time'), wbFloat('Ground Attack Time'), wbFloat('Perch Attack Chance'), wbFloat('Perch Attack Time'), wbFloat('Flying Attack Chance') ], cpNormal, False, nil, 0), wbInteger(DATA, 'Flags', itU32, wbFlags([ {0x01} 'Dueling', {0x02} 'Flanking', {0x04} 'Allow Dual Wielding' ]), cpNormal, False) ]); end; procedure DefineTES5d; begin wbRecord(DIAL, 'Dialog Topic', [ wbEDID, wbFULL, wbFloat(PNAM, 'Priority', cpNormal, True, 1, -1, nil, nil, 50.0), wbFormIDCk(BNAM, 'Branch', [DLBR, NULL]), wbFormIDCk(QNAM, 'Quest', [QUST, NULL], False, cpNormal, False), wbStruct(DATA, 'Data', [ // this should not be named Flags since TwbFile.BuildReachable // expects Top-Level flag here from FNV wbInteger('Topic Flags', itU8, wbFlags([ 'Do All Before Repeating' ]), cpNormal, True), wbInteger('Category', itU8, wbEnum([ {0} 'Topic', {1} 'Favor', // only in DA14 quest topics {2} 'Scene', {3} 'Combat', {4} 'Favors', {5} 'Detection', {6} 'Service', {7} 'Miscellaneous' ])), wbInteger('Subtype', itU16, wbEnum([], [ 0, 'Custom', 1, 'ForceGreet', 2, 'Rumors', 3, 'Custom?', 4, 'Intimidate', 5, 'Flatter', 6, 'Bribe', 7, 'Ask Gift', 8, 'Gift', 9, 'Ask Favor', 10, 'Favor', 11, 'Show Relationships', 12, 'Folow', 13, 'Reject', 14, 'Scene', 15, 'Show', 16, 'Agree', 17, 'Refuse', 18, 'ExitFavorState', 19, 'MoralRefusal', 20, 'FlyingMountLand', 21, 'FlyingMountCancelLand', 22, 'FlyingMountAcceptTarget', 23, 'FlyingMountRejectTarget', 24, 'FlyingMountNoTarget', 25, 'FlyingMountDestinationReached', 26, 'Attack', 27, 'PowerAttack', 28, 'Bash', 29, 'Hit', 30, 'Flee', 31, 'Bleedout', 32, 'AvoidThreat', 33, 'Death', 34, 'GroupStrategy', 35, 'Block', 36, 'Taunt', 37, 'AllyKilled', 38, 'Steal', 39, 'Yield', 40, 'AcceptYield', 41, 'PickpocketCombat', 42, 'Assault', 43, 'Murder', 44, 'AssaultNC', 45, 'MurderNC', 46, 'PickpocketNC', 47, 'StealFromNC', 48, 'TrespassAgainstNC', 49, 'Trespass', 50, 'WereTransformCrime', 51, 'VoicePowerStartShort', 52, 'VoicePowerStartLong', 53, 'VoicePowerEndShort', 54, 'VoicePowerEndLong', 55, 'AlertIdle', 56, 'LostIdle', 57, 'NormalToAlert', 58, 'AlertToCombat', 59, 'NormalToCombat', 60, 'AlertToNormal', 61, 'CombatToNormal', 62, 'CombatToLost', 63, 'LostToNormal', 64, 'LostToCombat', 65, 'DetectFriendDie', 66, 'ServiceRefusal', 67, 'Repair', 68, 'Travel', 69, 'Training', 70, 'BarterExit', 71, 'RepairExit', 72, 'Recharge', 73, 'RechargeExit', 74, 'TrainingExit', 75, 'ObserveCombat', 76, 'NoticeCorpse', 77, 'TimeToGo', 78, 'GoodBye', 79, 'Hello', 80, 'SwingMeleeWeapon', 81, 'ShootBow', 82, 'ZKeyObject', 83, 'Jump', 84, 'KnockOverObject', 85, 'DestroyObject', 86, 'StandonFurniture', 87, 'LockedObject', 88, 'PickpocketTopic', 89, 'PursueIdleTopic', 90, 'SharedInfo', 91, 'PlayerCastProjectileSpell', 92, 'PlayerCastSelfSpell', 93, 'PlayerShout', 94, 'Idle', 95, 'EnterSprintBreath', 96, 'EnterBowZoomBreath', 97, 'ExitBowZoomBreath', 98, 'ActorCollidewithActor', 99, 'PlayerinIronSights', 100, 'OutofBreath', 101, 'CombatGrunt', 102, 'LeaveWaterBreath' ])) ]), wbString(SNAM, 'Subtype Name', 4), wbInteger(TIFC, 'Info Count', itU32, nil, cpBenign) ]); wbRecord(DOOR, 'Door', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00008000} 15, 'Has Distant LOD', {0x00010000} 16, 'Random Anim Start', {0x00800000} 23, 'Is Marker' ])), [ wbEDID, wbVMAD, wbOBNDReq, wbFULL, wbMODL, wbDEST, wbFormIDCk(SNAM, 'Sound - Open', [SNDR]), wbFormIDCk(ANAM, 'Sound - Close', [SNDR]), wbFormIDCk(BNAM, 'Sound - Loop', [SNDR]), wbInteger(FNAM, 'Flags', itU8, wbFlags([ '', 'Automatic', 'Hidden', 'Minimal Use', 'Sliding', 'Do Not Open in Combat Search' ]), cpNormal, True) ]); wbBlendModeEnum := wbEnum([ '', 'Zero', 'One', 'Source Color', 'Source Inverse Color', 'Source Alpha', 'Source Inverted Alpha', 'Dest Alpha', 'Dest Inverted Alpha', 'Dest Color', 'Dest Inverse Color', 'Source Alpha SAT' ]); wbBlendOpEnum := wbEnum([ '', 'Add', 'Subtract', 'Reverse Subtract', 'Minimum', 'Maximum' ]); wbZTestFuncEnum := wbEnum([ '', '', '', 'Equal To', 'Normal', 'Greater Than', '', 'Greater Than or Equal To', 'Always Show' ]); wbRecord(EFSH, 'Effect Shader', [ wbEDID, wbString(ICON, 'Fill Texture'), wbString(ICO2, 'Particle Shader Texture'), wbString(NAM7, 'Holes Texture'), wbString(NAM8, 'Membrane Palette Texture'), wbString(NAM9, 'Particle Palette Texture'), wbStruct(DATA, '', [ wbByteArray('Unknown', 4), wbInteger('Membrane Shader - Source Blend Mode', itU32, wbBlendModeEnum), wbInteger('Membrane Shader - Blend Operation', itU32, wbBlendOpEnum), wbInteger('Membrane Shader - Z Test Function', itU32, wbZTestFuncEnum), wbByteColors('Fill/Texture Effect - Color Key 1'), wbFloat('Fill/Texture Effect - Alpha Fade In Time'), wbFloat('Fill/Texture Effect - Full Alpha Time'), wbFloat('Fill/Texture Effect - Alpha Fade Out Time'), wbFloat('Fill/Texture Effect - Presistent Alpha Ratio'), wbFloat('Fill/Texture Effect - Alpha Pulse Amplitude'), wbFloat('Fill/Texture Effect - Alpha Pulse Frequency'), wbFloat('Fill/Texture Effect - Texture Animation Speed (U)'), wbFloat('Fill/Texture Effect - Texture Animation Speed (V)'), wbFloat('Edge Effect - Fall Off'), wbByteColors('Edge Effect - Color'), wbFloat('Edge Effect - Alpha Fade In Time'), wbFloat('Edge Effect - Full Alpha Time'), wbFloat('Edge Effect - Alpha Fade Out Time'), wbFloat('Edge Effect - Persistent Alpha Ratio'), wbFloat('Edge Effect - Alpha Pulse Amplitude'), wbFloat('Edge Effect - Alpha Pulse Frequency'), wbFloat('Fill/Texture Effect - Full Alpha Ratio'), wbFloat('Edge Effect - Full Alpha Ratio'), wbInteger('Membrane Shader - Dest Blend Mode', itU32, wbBlendModeEnum), wbInteger('Particle Shader - Source Blend Mode', itU32, wbBlendModeEnum), wbInteger('Particle Shader - Blend Operation', itU32, wbBlendOpEnum), wbInteger('Particle Shader - Z Test Function', itU32, wbZTestFuncEnum), wbInteger('Particle Shader - Dest Blend Mode', itU32, wbBlendModeEnum), wbFloat('Particle Shader - Particle Birth Ramp Up Time'), wbFloat('Particle Shader - Full Particle Birth Time'), wbFloat('Particle Shader - Particle Birth Ramp Down Time'), wbFloat('Particle Shader - Full Particle Birth Ratio'), wbFloat('Particle Shader - Persistant Particle Count'), wbFloat('Particle Shader - Particle Lifetime'), wbFloat('Particle Shader - Particle Lifetime +/-'), wbFloat('Particle Shader - Initial Speed Along Normal'), wbFloat('Particle Shader - Acceleration Along Normal'), wbFloat('Particle Shader - Initial Velocity #1'), wbFloat('Particle Shader - Initial Velocity #2'), wbFloat('Particle Shader - Initial Velocity #3'), wbFloat('Particle Shader - Acceleration #1'), wbFloat('Particle Shader - Acceleration #2'), wbFloat('Particle Shader - Acceleration #3'), wbFloat('Particle Shader - Scale Key 1'), wbFloat('Particle Shader - Scale Key 2'), wbFloat('Particle Shader - Scale Key 1 Time'), wbFloat('Particle Shader - Scale Key 2 Time'), wbByteColors('Color Key 1 - Color'), wbByteColors('Color Key 2 - Color'), wbByteColors('Color Key 3 - Color'), wbFloat('Color Key 1 - Color Alpha'), wbFloat('Color Key 2 - Color Alpha'), wbFloat('Color Key 3 - Color Alpha'), wbFloat('Color Key 1 - Color Key Time'), wbFloat('Color Key 2 - Color Key Time'), wbFloat('Color Key 3 - Color Key Time'), wbFloat('Particle Shader - Initial Speed Along Normal +/-'), wbFloat('Particle Shader - Initial Rotation (deg)'), wbFloat('Particle Shader - Initial Rotation (deg) +/-'), wbFloat('Particle Shader - Rotation Speed (deg/sec)'), wbFloat('Particle Shader - Rotation Speed (deg/sec) +/-'), wbFormIDCk('Addon Models', [DEBR, NULL]), wbFloat('Holes - Start Time'), wbFloat('Holes - End Time'), wbFloat('Holes - Start Val'), wbFloat('Holes - End Val'), wbFloat('Edge Width (alpha units)'), wbByteColors('Edge Color'), wbFloat('Explosion Wind Speed'), wbInteger('Texture Count U', itU32), wbInteger('Texture Count V', itU32), wbFloat('Addon Models - Fade In Time'), wbFloat('Addon Models - Fade Out Time'), wbFloat('Addon Models - Scale Start'), wbFloat('Addon Models - Scale End'), wbFloat('Addon Models - Scale In Time'), wbFloat('Addon Models - Scale Out Time'), wbFormIDCk('Ambient Sound', [SNDR, SOUN, NULL]), wbByteColors('Fill/Texture Effect - Color Key 2'), wbByteColors('Fill/Texture Effect - Color Key 3'), wbStruct('Fill/Texture Effect - Color Key Scale/Time', [ wbFloat('Color Key 1 - Scale'), wbFloat('Color Key 2 - Scale'), wbFloat('Color Key 3 - Scale'), wbFloat('Color Key 1 - Time'), wbFloat('Color Key 2 - Time'), wbFloat('Color Key 3 - Time') ]), wbFloat('Color Scale'), wbFloat('Birth Position Offset'), wbFloat('Birth Position Offset Range +/-'), wbStruct('Particle Shader Animated', [ wbInteger('Start Frame', itU32), wbInteger('Start Frame Variation', itU32), wbInteger('End Frame', itU32), wbInteger('Loop Start Frame', itU32), wbInteger('Loop Start Variation', itU32), wbInteger('Frame Count', itU32), wbInteger('Frame Count Variation', itU32) ]), wbInteger('Flags', itU32, wbFlags([ 'No Membrane Shader', 'Membrane Grayscale Color', 'Membrane Grayscale Alpha', 'No Particle Shader', 'Edge Effect Inverse', 'Affect Skin Only', 'Ignore Alpha', 'Project UVs', 'Ignore Base Geometry Alpha', 'Lighting', 'No Weapons', 'Unknown 11', 'Unknown 12', 'Unknown 13', 'Unknown 14', 'Particle Animated', 'Particle Grayscale Color', 'Particle Grayscale Alpha', 'Unknown 18', 'Unknown 19', 'Unknown 20', 'Unknown 21', 'Unknown 22', 'Unknown 23', 'Use Blood Geometry' ])), wbFloat('Fill/Texture Effect - Texture Scale (U)'), wbFloat('Fill/Texture Effect - Texture Scale (V)'), wbInteger('Scene Graph Emit Depth Limit (unused)', itU32) ], cpNormal, True, nil, 0) ], False, nil, cpNormal, False, nil {wbEFSHAfterLoad}); wbRecord(ENCH, 'Object Effect', [ wbEDID, wbOBNDReq, wbFULL, wbStruct(ENIT, 'Effect Data', [ wbInteger('Enchantment Cost', itS32), wbInteger('Flags', itU32, wbFlags([ 'No Auto-Calc', '', 'Extend Duration On Recast' ])), wbInteger('Cast Type', itU32, wbCastEnum), wbInteger('Enchantment Amount', itS32), wbInteger('Target Type', itU32, wbTargetEnum), wbInteger('Enchant Type', itU32, wbEnum([], [ $06, 'Enchantment', $0C, 'Staff Enchantment' ])), wbFloat('Charge Time'), wbFormIDCk('Base Enchantment', [ENCH, NULL]), wbFormIDCk('Worn Restrictions', [FLST, NULL]) ], cpNormal, True, nil, 8), wbEffectsReq ]); wbRecord(EYES, 'Eyes', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000004} 2, 'Non-Playable' ])), [ wbEDID, wbFULLReq, wbString(ICON, 'Texture', 0, cpNormal, True), wbInteger(DATA, 'Flags', itU8, wbFlags([ {0x01}'Playable', {0x02}'Not Male', {0x04}'Not Female', {0x08}'Unknown 4', {0x10}'Unknown 5', {0x20}'Unknown 6', {0x40}'Unknown 7', {0x80}'Unknown 8' ]), cpNormal, True) ]); wbRecord(FACT, 'Faction', [ wbEDID, wbFULL, wbRArrayS('Relations', wbStructSK(XNAM, [0], 'Relation', [ wbFormIDCkNoReach('Faction', [FACT, RACE]), wbInteger('Modifier', itS32), wbInteger('Group Combat Reaction', itU32, wbEnum([ {0x00000001}'Neutral', {0x00000002}'Enemy', {0x00000004}'Ally', {0x00000008}'Friend' ])) ])), wbStruct(DATA, 'Flags', [ wbInteger('Flags', itU32, wbFlags([ {0x00000001}'Hidden From NPC', {0x00000002}'Special Combat', {0x00000004}'Unknown 3', {0x00000008}'Unknown 4', {0x00000010}'Unknown 5', {0x00000020}'Unknown 6', {0x00000040}'Track Crime', {0x00000080}'Ignore Crimes: Murder', {0x00000100}'Ignore Crimes: Assault', {0x00000200}'Ignore Crimes: Stealing', {0x00000400}'Ignore Crimes: Trespass', {0x00000800}'Do Not Report Crimes Against Members', {0x00001000}'Crime Gold - Use Defaults', {0x00002000}'Ignore Crimes: Pickpocket', {0x00004000}'Vendor', {0x00008000}'Can Be Owner', {0x00010000}'Ignore Crimes: Werewolf', {0x00020000}'Unknown 18', {0x00040000}'Unknown 19', {0x00080000}'Unknown 20', {0x00100000}'Unknown 21', {0x00200000}'Unknown 22', {0x00400000}'Unknown 23', {0x00800000}'Unknown 24', {0x01000000}'Unknown 25', {0x02000000}'Unknown 26', {0x04000000}'Unknown 27', {0x08000000}'Unknown 28', {0x10000000}'Unknown 29', {0x20000000}'Unknown 30', {0x40000000}'Unknown 31', {0x80000000}'Unknown 32' ])) ], cpNormal, True, nil, 1), wbFormIDCk(JAIL, 'Exterior Jail Marker', [REFR]), wbFormIDCk(WAIT, 'Follower Wait Marker', [REFR]), wbFormIDCk(STOL, 'Stolen Goods Container', [REFR]), wbFormIDCk(PLCN, 'Player Inventory Container', [REFR]), wbFormIDCk(CRGR, 'Shared Crime Faction List', [FLST]), wbFormIDCk(JOUT, 'Jail Outfit', [OTFT]), wbStruct(CRVA, 'Crime Values', [ {01} wbInteger('Arrest', itU8, wbEnum(['False', 'True'])), {02} wbInteger('Attack On Sight', itU8, wbEnum(['False', 'True'])), {02} wbInteger('Murder', itU16), {02} wbInteger('Assault', itU16), {02} wbInteger('Trespass', itU16), {02} wbInteger('Pickpocket', itU16), {02} wbInteger('Unknown', itU16), {02} wbFloat('Steal Multiplier'), {02} wbInteger('Escape', itU16), {02} wbInteger('Werewolf', itU16) ], cpNormal, False, nil, 7), wbRStructsSK('Ranks', 'Rank', [0], [ wbInteger(RNAM, 'Rank#', itU32), wbLString(MNAM, 'Male Title', 0, cpTranslate), wbLString(FNAM, 'Female Title', 0, cpTranslate), wbString(INAM, 'Insignia Unused') ], []), wbFormIDCk(VEND, 'Vendor Buy/Sell List', [FLST]), wbFormIDCk(VENC, 'Merchant Container', [REFR]), wbStruct(VENV, 'Vendor Values', [ {01} wbInteger('Start Hour', itU16), {02} wbInteger('End Hour', itU16), {02} wbInteger('Radius', itU16), {02} wbByteArray('Unknown 1', 2), wbInteger('Only Buys Stolen Items', itU8, wbEnum(['False', 'True'])), wbInteger('Not/Sell Buy', itU8, wbEnum(['False', 'True'])), {02} wbByteArray('Unknown 2', 2) ]), wbPLVD, wbCITC, wbCTDAsCount ], False, nil, cpNormal, False, nil {wbFACTAfterLoad}, wbConditionsAfterSet); wbRecord(FURN, 'Furniture', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000080} 7, 'Is Perch', {0x00008000} 15, 'Has Distant LOD', {0x00010000} 16, 'Random Anim Start', {0x00800000} 23, 'Is Marker', {0x10000000} 28, 'Must Exit To Talk', {0x20000000} 29, 'Child Can Use' ])), [ wbEDID, wbVMAD, wbOBNDReq, wbFULL, wbMODL, wbDEST, wbKSIZ, wbKWDAs, wbUnknown(PNAM), wbInteger(FNAM, 'Flags', itU16, wbFlags([ {0x0001} 'Unknown 0', {0x0002} 'Ignored By Sandbox' ])), wbFormIDCk(KNAM, 'Interaction Keyword', [KYWD, NULL]), wbInteger(MNAM, 'Active Markers / Flags', itU32, wbFlags([ {0x00000001} 'Sit 0', {0x00000002} 'Sit 1', {0x00000004} 'Sit 2', {0x00000008} 'Sit 3', {0x00000010} 'Sit 4', {0x00000020} 'Sit 5', {0x00000040} 'Sit 6', {0x00000080} 'Sit 7', {0x00000100} 'Sit 8', {0x00000200} 'Sit 9', {0x00000400} 'Sit 10', {0x00000800} 'Sit 11', {0x00001000} 'Sit 12', {0x00002000} 'Sit 13', {0x00004000} 'Sit 14', {0x00008000} 'Sit 15', {0x00010000} 'Sit 16', {0x00020000} 'Sit 17', {0x00040000} 'Sit 18', {0x00080000} 'Sit 19', {0x00100000} 'Sit 20', {0x00200000} 'Sit 21', {0x00400000} 'Sit 22', {0x00800000} 'Sit 23', {0x01000000} 'Unknown 25', {0x02000000} 'Disables Activation', {0x04000000} 'Is Perch', {0x08000000} 'Must Exit to Talk', {0x10000000} 'Unknown 29', {0x20000000} 'Unknown 30', {0x40000000} 'Unknown 31', {0x80000000} 'Unknown 32' ])), wbStruct(WBDT, 'Workbench Data', [ wbInteger('Bench Type', itU8, wbEnum([ {0} 'None', {1} 'Create object', {2} 'Smithing Weapon', {3} 'Enchanting', {4} 'Enchanting Experiment', {5} 'Alchemy', {6} 'Alchemy Experiment', {7} 'Smithing Armor' ])), wbInteger('Uses Skill', itS8, wbSkillEnum) ]), wbFormIDCk(NAM1, 'Associated Spell', [SPEL]), wbRArray('Markers', wbRStruct('Marker', [ wbInteger(ENAM, 'Marker Index', itU32), wbStruct(NAM0, 'Disabled Entry Points', [ wbByteArray('Unknown', 2), wbInteger('Disabled Points', itU16, wbFurnitureEntryTypeFlags) ]), wbFormIDCk(FNMK, 'Marker Keyword', [KYWD, NULL]) ], [])), wbRArray('Marker Entry Points', wbStruct(FNPR, 'Marker', [ wbInteger('Type', itU16, wbFurnitureAnimTypeEnum), wbInteger('Entry Points', itU16, wbFurnitureEntryTypeFlags) ])), wbString(XMRK, 'Model Filename') ], False, nil, cpNormal, False, nil, wbKeywordsAfterSet); //---------------------------------------------------------------------------- // For expansion to use wbGLOBUnionDecider to display Short, Long, Float // correctly without making a signed float by default //---------------------------------------------------------------------------- wbRecord(GLOB, 'Global', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000040} 6, 'Constant' ])), [ wbEDID, wbInteger(FNAM, 'Type', itU8, wbGLOBFNAM, nil, cpNormal, True), wbFloat(FLTV, 'Value', cpNormal, True) ]); wbRecord(GMST, 'Game Setting', [ wbString(EDID, 'Editor ID', 0, cpCritical, True, nil, wbGMSTEDIDAfterSet), wbUnion(DATA, 'Value', wbGMSTUnionDecider, [ wbLString('Name', 0, cpTranslate), wbInteger('Int', itS32), wbFloat('Float'), wbInteger('Bool', itU32, wbEnum(['False', 'True'])) ], cpNormal, True) ]); wbRecord(KYWD, 'Keyword', [ wbEDID, wbCNAM ]); end; procedure DefineTES5e; begin wbRecord(LCRT, 'Location Reference Type', [ wbEDID, wbCNAM ]); wbRecord(AACT, 'Action', [ wbEDID, wbCNAM ]); wbRecord(TXST, 'Texture Set', [ wbEDID, wbOBNDReq, wbRStruct('Textures (RGB/A)', [ wbString(TX00,'Difuse'), wbString(TX01,'Normal/Gloss'), wbString(TX02,'Environment Mask/Subsurface Tint'), wbString(TX03,'Glow/Detail Map'), wbString(TX04,'Height'), wbString(TX05,'Environment'), wbString(TX06,'Multilayer'), wbString(TX07,'Backlight Mask/Specular') ], []), wbDODT, wbInteger(DNAM, 'Flags', itU16, wbFlags([ {0x0001}'No Specular Map', {0x0002}'Facegen Textures', {0x0004}'Has Model Space Normal Map' ]), cpNormal, False) ]); wbRecord(HDPT, 'Head Part', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000004} 2, 'Non-Playable' ])), [ wbEDID, wbFULL, wbMODL, wbInteger(DATA, 'Flags', itU8, wbFlags([ {0x01} 'Playable', {0x02} 'Male', {0x04} 'Female', {0x10} 'Is Extra Part', {0x20} 'Use Solid Tint' ]), cpNormal, True), wbInteger(PNAM, 'Type', itU32, wbEnum([ 'Misc', 'Face', 'Eyes', 'Hair', 'Facial Hair', 'Scar', 'Eyebrows' ])), wbRArrayS('Extra Parts', wbFormIDCk(HNAM, 'Part', [HDPT]) ), wbRStructs('Parts', 'Part', [ wbInteger(NAM0, 'Part Type', itU32, wbEnum([ 'Race Morph', 'Tri', 'Chargen Morph' ])), wbString(NAM1, 'Filename', 0, cpTranslate, True) ], []), wbFormIDCk(TNAM, 'Texture Set', [TXST, NULL]), wbFormIDCk(CNAM, 'Color', [CLFM, NULL]), wbFormIDCk(RNAM, 'Valid Races', [FLST, NULL]) ]); wbRecord(ASPC, 'Acoustic Space', [ wbEDID, wbOBNDReq, wbFormIDCk(SNAM, 'Ambient Sound', [SNDR]), wbFormIDCk(RDAT, 'Use Sound from Region (Interiors Only)', [REGN]), wbFormIDCk(BNAM, 'Environment Type (reverb)', [REVB]) ]); wbRecord(MSTT, 'Moveable Static', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000100} 8, 'Must Update Anims', {0x00000200} 9, 'Hidden From Local Map', {0x00008000} 15, 'Has Distant LOD', {0x00010000} 16, 'Random Anim Start', {0x00080000} 19, 'Has Currents', {0x02000000} 25, 'Obstacle', {0x04000000} 26, 'NavMesh Generation - Filter', {0x08000000} 27, 'NavMesh Generation - Bounding Box', {0x40000000} 30, 'NavMesh Generation - Ground' ])), [ wbEDID, wbOBNDReq, wbFULL, wbMODL, wbDEST, wbInteger(DATA, 'Flags', itU8, wbFlags([ 'On Local Map', 'Unknown 1', 'Unknown 2' ]), cpNormal, True), wbFormIDCk(SNAM, 'Looping Sound', [SNDR]) ]); end; procedure DefineTES5f; begin wbRecord(IDLM, 'Idle Marker', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x20000000} 29, 'Child Can Use' ])), [ wbEDID, wbOBNDReq, wbInteger(IDLF, 'Flags', itU8, wbFlags([ 'Run in Sequence', 'Unknown 1', 'Do Once', 'Unknown 3', 'Ignored by Sandbox' ]), cpNormal, False), wbInteger(IDLC, 'Animation Count', itU8, nil, cpBenign), wbFloat(IDLT, 'Idle Timer Setting', cpNormal, False), wbArray(IDLA, 'Animations', wbFormIDCk('Animation', [IDLE]), 0, nil, wbIDLAsAfterSet, cpNormal, False), wbMODL ], False, nil, cpNormal, False, nil, wbAnimationsAfterSet); wbRecord(PROJ, 'Projectile', [ wbEDID, wbOBNDReq, wbFULL, wbMODL, wbDEST, wbStruct(DATA, 'Data', [ {00} wbInteger('Flags', itU16, wbFlags([ 'Hitscan', 'Explosion', 'Alt. Trigger', 'Muzzle Flash', '', 'Can Be Disabled', 'Can Be Picked Up', 'Supersonic', 'Pins Limbs', 'Pass Through Small Transparent', 'Disable Combat Aim Correction', 'Rotation' ])), {02} wbInteger('Type', itU16, wbEnum([], [ $01, 'Missile', $02, 'Lobber', $04, 'Beam', $08, 'Flame', $10, 'Cone', $20, 'Barrier', $40, 'Arrow' ])), {04} wbFloat('Gravity'), {08} wbFloat('Speed'), {12} wbFloat('Range'), {16} wbFormIDCk('Light', [LIGH, NULL]), {20} wbFormIDCk('Muzzle Flash - Light', [LIGH, NULL]), {24} wbFloat('Tracer Chance'), {28} wbFloat('Explosion - Alt. Trigger - Proximity'), {32} wbFloat('Explosion - Alt. Trigger - Timer'), {36} wbFormIDCk('Explosion', [EXPL, NULL]), {40} wbFormIDCk('Sound', [SNDR, NULL]), {44} wbFloat('Muzzle Flash - Duration'), {48} wbFloat('Fade Duration'), {52} wbFloat('Impact Force'), {56} wbFormIDCk('Sound - Countdown', [SNDR, NULL]), {60} wbFormIDCk('Sound - Disable', [SNDR, NULL]), {64} wbFormIDCk('Default Weapon Source', [WEAP, NULL]), {68} wbFloat('Cone Spread'), {72} wbFloat('Collision Radius'), {76} wbFloat('Lifetime'), {80} wbFloat('Relaunch Interval'), wbFormIDCk('Decal Data', [TXST, NULL]), wbFormIDCk('Collision Layer', [COLL, NULL]) ], cpNormal, True, nil, 22), wbRStructSK([0], 'Muzzle Flash Model', [ wbString(NAM1, 'Model Filename'), wbByteArray(NAM2, 'Texture Files Hashes', 0, cpIgnore, false, false, wbNeverShow) ], [], cpNormal, True), wbInteger(VNAM, 'Sound Level', itU32, wbSoundLevelEnum, cpNormal, True) ]); wbRecord(HAZD, 'Hazard', [ wbEDID, wbOBNDReq, wbFULL, wbMODL, wbFormIDCk(MNAM, 'Image Space Modifier', [IMAD, NULL]), wbStruct(DATA, 'Data', [ wbInteger('Limit', itU32), wbFloat('Radius'), wbFloat('Lifetime'), wbFloat('Image Space Radius'), wbFloat('Target Interval'), wbInteger('Flags', itU32, wbFlags([ {0x01} 'Affects Player Only', {0x02} 'Inherit Duration from Spawn Spell', {0x04} 'Align to Impact Normal', {0x08} 'Inherit Radius from Spawn Spell', {0x10} 'Drop to Ground' ])), wbFormIDCk('Spell', [SPEL, NULL]), wbFormIDCk('Light', [LIGH, NULL]), wbFormIDCk('Impact Data Set', [IPDS, NULL]), wbFormIDCk('Sound', [SNDR, NULL]) ]) ]); wbSoulGemEnum := wbEnum([ {0} 'None', {1} 'Petty', {2} 'Lesser', {3} 'Common', {4} 'Greater', {5} 'Grand' ]); wbRecord(SLGM, 'Soul Gem', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00020000} 17, 'Can Hold NPC Soul' ])), [ wbEDID, wbOBND, wbFULL, wbMODL, wbICON, wbDEST, wbYNAM, wbZNAM, wbKSIZ, wbKWDAs, wbStruct(DATA, '', [ wbInteger('Value', itU32), wbFloat('Weight') ], cpNormal, True), wbInteger(SOUL, 'Contained Soul', itU8, wbSoulGemEnum, cpNormal, True), wbInteger(SLCP, 'Maximum Capacity', itU8, wbSoulGemEnum, cpNormal, True), wbFormIDCk(NAM0, 'Linked To', [SLGM]) ], False, nil, cpNormal, False, nil, wbKeywordsAfterSet); if wbSimpleRecords then wbNVNM := wbStruct(NVNM, 'Geometry', [ wbByteArray('Unknown', 8), wbFormIDCk('Parent Worldspace', [WRLD, NULL]), wbUnion('Parent', wbNVNMParentDecider, [ wbStruct('Coordinates', [ wbInteger('Grid Y', itS16), wbInteger('Grid X', itS16) ]), wbFormIDCk('Parent Cell', [CELL]) ]), wbArray('Vertices', wbByteArray('Vertex', 12), -1), wbArray('Triangles', wbByteArray('Triangle', 16), -1), wbArray('External Connections', wbStruct('Connection', [ wbByteArray('Unknown', 4), wbFormIDCk('Mesh', [NAVM]), wbInteger('Triangle', itS16) ]) , -1), wbArray('Door Triangles', wbStruct('Door Triangle', [ wbInteger('Triangle before door', itS16), wbByteArray('Unknown', 4), wbFormIDCk('Door', [REFR]) ]) , -1), wbUnknown ]) else wbNVNM := wbStruct(NVNM, 'Geometry', [ wbInteger('Unknown', itU32), wbByteArray('Unknown', 4), wbFormIDCk('Parent Worldspace', [WRLD, NULL]), wbUnion('Parent', wbNVNMParentDecider, [ wbStruct('Coordinates', [ wbInteger('Grid Y', itS16), wbInteger('Grid X', itS16) ]), wbFormIDCk('Parent Cell', [CELL]) ]), wbArray('Vertices', wbStruct('Vertex', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), -1), wbArray('Triangles', wbStruct('Triangle', [ wbInteger('Vertex 0', itS16), wbInteger('Vertex 1', itS16), wbInteger('Vertex 2', itS16), wbInteger('Edge 0-1', itS16), wbInteger('Edge 1-2', itS16), wbInteger('Edge 2-0', itS16), wbInteger('Flags', itU16, wbFlags([ 'Edge 0-1 link', 'Edge 1-2 link', 'Edge 2-0 link', 'Unknown 4', 'Unknown 5', 'Unknown 6', 'Preferred', 'Unknown 8', 'Unknown 9', 'Water', 'Door', 'Found', 'Unknown 13', 'Unknown 14', 'Unknown 15', 'Unknown 16' ])), wbInteger('Cover Flags', itU16, wbFlags([ 'Edge 0-1 wall', 'Edge 0-1 ledge cover', 'Unknown 3', 'Unknown 4', 'Edge 0-1 left', 'Edge 0-1 right', 'Edge 1-2 wall', 'Edge 1-2 ledge cover', 'Unknown 9', 'Unknown 10', 'Edge 1-2 left', 'Edge 1-2 right', 'Unknown 13', 'Unknown 14', 'Unknown 15', 'Unknown 16' ])) //wbInteger('Cover Edge #1 Flags', itU8), //wbInteger('Cover Edge #2 Flags', itU8) ]) , -1), wbArray('Edge Links', wbStruct('Edge Link', [ wbByteArray('Unknown', 4), wbFormIDCk('Mesh', [NAVM]), wbInteger('Triangle', itS16) ]) , -1), wbArray('Door Triangles', wbStruct('Door Triangle', [ wbInteger('Triangle before door', itS16), wbByteArray('Unknown', 4), wbFormIDCk('Door', [REFR]) ]) , -1), wbArray('Cover Triangles', wbInteger('Triangle', itS16), -1), wbInteger('NavMeshGrid Divisor', itU32), wbFloat('Max X Distance'), wbFloat('Max Y Distance'), wbFloat('Min X'), wbFloat('Min Y'), wbFloat('Min Z'), wbFloat('Max X'), wbFloat('Max Y'), wbFloat('Max Z'), wbArray('NavMeshGrid', wbArray('NavMeshGridCell', wbInteger('Triangle', itS16), -1)) ]); wbRecord(NAVM, 'Navigation Mesh', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00040000} 18, 'Compressed', {0x04000000} 26, 'AutoGen', {0x80000000} 31, 'NavmeshGenCell' ]), [18]), [ wbEDID, wbNVNM, wbUnknown(ONAM), wbUnknown(PNAM), wbUnknown(NNAM) ], False, wbNAVMAddInfo); if wbSimpleRecords then wbNAVIslandData := wbStruct('Island Data', [ wbByteArray('Unknown', 24), wbArray('Triangles', wbByteArray('Triangle', 6), -1), wbArray('Vertices', wbByteArray('Vertex', 12), -1) ]) else wbNAVIslandData := wbStruct('Island Data', [ wbFloat('Min X'), wbFloat('Min Y'), wbFloat('Min Z'), wbFloat('Max X'), wbFloat('Max Y'), wbFloat('Max Z'), wbArray('Triangles', wbStruct('Triangle', [ wbArray('Vertices', wbInteger('Vertex', itS16), 3) ]) , -1), wbArray('Vertices', wbStruct('Vertex', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), -1) ]); wbRecord(NAVI, 'Navigation Mesh Info Map', [ wbEDID, wbInteger(NVER, 'Version', itU32), wbRArray('Navigation Map Infos', wbStruct(NVMI, 'Navigation Map Info', [ wbFormIDCk('Navigation Mesh', [NAVM]), wbByteArray('Unknown', 4), wbFloat('X'), wbFloat('Y'), wbFloat('Z'), wbInteger('Preferred Merges Flag', itU32), wbArray('Merged To', wbFormIDCk('Mesh', [NAVM]), -1), wbArray('Preferred Merges', wbFormIDCk('Mesh', [NAVM]), -1), wbArray('Linked Doors', wbStruct('Door', [ wbByteArray('Unknown', 4), wbFormIDCk('Door Ref', [REFR]) ]), -1), wbInteger('Is Island', itU8, wbEnum(['False', 'True'])), wbUnion('Island', wbNAVIIslandDataDecider, [ wbNull, wbNAVIslandData ]), wbByteArray('Unknown', 4), wbFormIDCk('Parent Worldspace', [WRLD, NULL]), wbUnion('Parent', wbNAVIParentDecider, [ wbStruct('Coordinates', [ wbInteger('Grid Y', itS16), wbInteger('Grid X', itS16) ]), wbFormIDCk('Parent Cell', [CELL]) ]) ]) ), wbStruct(NVPP, 'Preferred Pathing', [ wbArray('NavMeshes', wbArray('Set', wbFormIDCk('', [NAVM]), -1), -1), wbArray('NavMesh Tree?', wbStruct('', [ wbFormIDCk('NavMesh', [NAVM]), wbInteger('Index/Node', itU32) ]), -1) ]), wbArray(NVSI, 'Unknown', wbFormIDCk('Navigation Mesh', [NAVM])) ]); end; procedure DefineTES5g; begin wbRecord(EXPL, 'Explosion', [ wbEDID, wbVMAD, wbOBNDReq, wbFULL, wbMODL, wbEITM, wbFormIDCk(MNAM, 'Image Space Modifier', [IMAD]), wbStruct(DATA, 'Data', [ // Contradicted by FireStormExplosion02 [EXPL:000877F9] wbFormIDCk('Light', [LIGH, NULL]), wbFormIDCk('Sound 1', [SNDR, NULL]), wbFormIDCk('Sound 2', [SNDR, NULL]), wbFormIDCk('Impact Data Set', [IPDS, NULL]), wbFormID('Placed Object'), wbFormIDCk('Spawn Projectile', [PROJ, NULL]), wbFloat('Force'), wbFloat('Damage'), wbFloat('Radius'), wbFloat('IS Radius'), wbFloat('Vertical Offset Mult'), wbInteger('Flags', itU32, wbFlags([ 'Unknown 0', 'Always Uses World Orientation', 'Knock Down - Always', 'Knock Down - By Formula', 'Ignore LOS Check', 'Push Explosion Source Ref Only', 'Ignore Image Space Swap', 'Chain', 'No Controller Vibration' ])), wbInteger('Sound Level', itU32, wbSoundLevelEnum, cpNormal, True) ], cpNormal, True, nil, 10) ]); wbRecord(DEBR, 'Debris', [ wbEDID, wbRStructs('Models', 'Model', [ wbStruct(DATA, 'Data', [ wbInteger('Percentage', itU8), wbString('Model Filename'), wbInteger('Flags', itU8, wbFlags([ 'Has Collision Data' ])) ], cpNormal, True), wbMODT ], [], cpNormal, True) ]); wbRecord(IMGS, 'Image Space', [ wbEDID, wbUnknown(ENAM, cpIgnore), wbStruct(HNAM, 'HDR', [ wbFloat('Eye Adapt Speed'), wbFloat('Bloom Blur Radius'), wbFloat('Bloom Threshold'), wbFloat('Bloom Scale'), wbFloat('Receive Bloom Threshold'), wbFloat('White'), wbFloat('Sunlight Scale'), wbFloat('Sky Scale'), wbFloat('Eye Adapt Strength') ]), wbStruct(CNAM, 'Cinematic', [ wbFloat('Saturation'), wbFloat('Brightness'), wbFloat('Contrast') ]), wbStruct(TNAM, 'Tint', [ wbFloat('Amount'), wbFloatColors('Color') ]), wbStruct(DNAM, 'Depth of Field', [ wbFloat('Strength'), wbFloat('Distance'), wbFloat('Range'), wbByteArray('Unknown', 2), wbInteger('Sky / Blur Radius', itU16, wbEnum([], [ 16384, 'Radius 0', 16672, 'Radius 1', 16784, 'Radius 2', 16848, 'Radius 3', 16904, 'Radius 4', 16936, 'Radius 5', 16968, 'Radius 6', 17000, 'Radius 7', 16576, 'No Sky, Radius 0', 16736, 'No Sky, Radius 1', 16816, 'No Sky, Radius 2', 16880, 'No Sky, Radius 3', 16920, 'No Sky, Radius 4', 16952, 'No Sky, Radius 5', 16984, 'No Sky, Radius 6', 17016, 'No Sky, Radius 7' ])) ], cpNormal, False, nil, 3) ]); wbTimeInterpolator := wbStruct('Data', [ wbFloat('Time'), wbFloat('Value') ]); wbColorInterpolator := wbStruct('Data', [ wbFloat('Time'), wbFloat('Red', cpNormal, False, 255, 0), wbFloat('Green', cpNormal, False, 255, 0), wbFloat('Blue', cpNormal, False, 255, 0), wbFloat('Alpha', cpNormal, False, 255, 0) ]); wbRecord(IMAD, 'Image Space Adapter', [ wbEDID, wbStruct(DNAM, 'Data Count', [ wbInteger('Flags', itU32, wbFlags(['Animatable'])), wbFloat('Duration'), wbStruct('HDR', [ wbInteger('Eye Adapt Speed Mult', itU32), wbInteger('Eye Adapt Speed Add', itU32), wbInteger('Bloom Blur Radius Mult', itU32), wbInteger('Bloom Blur Radius Add', itU32), wbInteger('Bloom Threshold Mult', itU32), wbInteger('Bloom Threshold Add', itU32), wbInteger('Bloom Scale Mult', itU32), wbInteger('Bloom Scale Add', itU32), wbInteger('Target Lum Min Mult', itU32), wbInteger('Target Lum Min Add', itU32), wbInteger('Target Lum Max Mult', itU32), wbInteger('Target Lum Max Add', itU32), wbInteger('Sunlight Scale Mult', itU32), wbInteger('Sunlight Scale Add', itU32), wbInteger('Sky Scale Mult', itU32), wbInteger('Sky Scale Add', itU32) ]), wbInteger('Unknown08 Mult', itU32), wbInteger('Unknown48 Add', itU32), wbInteger('Unknown09 Mult', itU32), wbInteger('Unknown49 Add', itU32), wbInteger('Unknown0A Mult', itU32), wbInteger('Unknown4A Add', itU32), wbInteger('Unknown0B Mult', itU32), wbInteger('Unknown4B Add', itU32), wbInteger('Unknown0C Mult', itU32), wbInteger('Unknown4C Add', itU32), wbInteger('Unknown0D Mult', itU32), wbInteger('Unknown4D Add', itU32), wbInteger('Unknown0E Mult', itU32), wbInteger('Unknown4E Add', itU32), wbInteger('Unknown0F Mult', itU32), wbInteger('Unknown4F Add', itU32), wbInteger('Unknown10 Mult', itU32), wbInteger('Unknown50 Add', itU32), wbStruct('Cinematic', [ wbInteger('Saturation Mult', itU32), wbInteger('Saturation Add', itU32), wbInteger('Brightness Mult', itU32), wbInteger('Brightness Add', itU32), wbInteger('Contrast Mult', itU32), wbInteger('Contrast Add', itU32) ]), wbInteger('Unknown14 Mult', itU32), wbInteger('Unknown54 Add', itU32), wbInteger('Tint Color', itU32), wbInteger('Blur Radius', itU32), wbInteger('Double Vision Strength', itU32), wbInteger('Radial Blur Strength', itU32), wbInteger('Radial Blur Ramp Up', itU32), wbInteger('Radial Blur Start', itU32), wbInteger('Radial Blur Flags', itU32, wbFlags(['Use Target'])), wbFloat('Radial Blur Center X'), wbFloat('Radial Blur Center Y'), wbInteger('DoF Strength', itU32), wbInteger('DoF Distance', itU32), wbInteger('DoF Range', itU32), wbInteger('DoF Flags', itU32, wbFlags([ {0x00000001} 'Use Target', {0x00000002} 'Unknown 2', {0x00000004} 'Unknown 3', {0x00000008} 'Unknown 4', {0x00000010} 'Unknown 5', {0x00000020} 'Unknown 6', {0x00000040} 'Unknown 7', {0x00000080} 'Unknown 8', {0x00000100} 'Mode - Front', {0x00000200} 'Mode - Back', {0x00000400} 'No Sky', {0x00000800} 'Blur Radius Bit 2', {0x00001000} 'Blur Radius Bit 1', {0x00002000} 'Blur Radius Bit 0' ])), wbInteger('Radial Blur Ramp Down', itU32), wbInteger('Radial Blur Down Start', itU32), wbInteger('Fade Color', itU32), wbInteger('Motion Blur Strength', itU32) ]), wbArray(BNAM, 'Blur Radius', wbTimeInterpolator), wbArray(VNAM, 'Double Vision Strength', wbTimeInterpolator), wbArray(TNAM, 'Tint Color', wbColorInterpolator), wbArray(NAM3, 'Fade Color', wbColorInterpolator), wbArray(RNAM, 'Radial Blur Strength', wbTimeInterpolator), wbArray(SNAM, 'Radial Blur Ramp Up', wbTimeInterpolator), wbArray(UNAM, 'Radial Blur Start', wbTimeInterpolator), wbArray(NAM1, 'Radial Blur Ramp Down', wbTimeInterpolator), wbArray(NAM2, 'Radial Blur Down Start', wbTimeInterpolator), wbArray(WNAM, 'DoF Strength', wbTimeInterpolator), wbArray(XNAM, 'DoF Distance', wbTimeInterpolator), wbArray(YNAM, 'DoF Range', wbTimeInterpolator), wbArray(NAM4, 'Motion Blur Strength', wbTimeInterpolator), wbRStruct('HDR', [ wbArray(_00_IAD, 'Eye Adapt Speed Mult', wbTimeInterpolator), wbArray(_40_IAD, 'Eye Adapt Speed Add', wbTimeInterpolator), wbArray(_01_IAD, 'Bloom Blur Radius Mult', wbTimeInterpolator), wbArray(_41_IAD, 'Bloom Blur Radius Add', wbTimeInterpolator), wbArray(_02_IAD, 'Bloom Threshold Mult', wbTimeInterpolator), wbArray(_42_IAD, 'Bloom Threshold Add', wbTimeInterpolator), wbArray(_03_IAD, 'Bloom Scale Mult', wbTimeInterpolator), wbArray(_43_IAD, 'Bloom Scale Add', wbTimeInterpolator), wbArray(_04_IAD, 'Target Lum Min Mult', wbTimeInterpolator), wbArray(_44_IAD, 'Target Lum Min Add', wbTimeInterpolator), wbArray(_05_IAD, 'Target Lum Max Mult', wbTimeInterpolator), wbArray(_45_IAD, 'Target Lum Max Add', wbTimeInterpolator), wbArray(_06_IAD, 'Sunlight Scale Mult', wbTimeInterpolator), wbArray(_46_IAD, 'Sunlight Scale Add', wbTimeInterpolator), wbArray(_07_IAD, 'Sky Scale Mult', wbTimeInterpolator), wbArray(_47_IAD, 'Sky Scale Add', wbTimeInterpolator) ], []), wbUnknown(_08_IAD), wbUnknown(_48_IAD), wbUnknown(_09_IAD), wbUnknown(_49_IAD), wbUnknown(_0A_IAD), wbUnknown(_4A_IAD), wbUnknown(_0B_IAD), wbUnknown(_4B_IAD), wbUnknown(_0C_IAD), wbUnknown(_4C_IAD), wbUnknown(_0D_IAD), wbUnknown(_4D_IAD), wbUnknown(_0E_IAD), wbUnknown(_4E_IAD), wbUnknown(_0F_IAD), wbUnknown(_4F_IAD), wbUnknown(_10_IAD), wbUnknown(_50_IAD), wbRStruct('Cinematic', [ wbArray(_11_IAD, 'Saturation Mult', wbTimeInterpolator), wbArray(_51_IAD, 'Saturation Add', wbTimeInterpolator), wbArray(_12_IAD, 'Brightness Mult', wbTimeInterpolator), wbArray(_52_IAD, 'Brightness Add', wbTimeInterpolator), wbArray(_13_IAD, 'Contrast Mult', wbTimeInterpolator), wbArray(_53_IAD, 'Contrast Add', wbTimeInterpolator) ], []), wbUnknown(_14_IAD), wbUnknown(_54_IAD) ]); wbRecord(FLST, 'FormID List', [ wbString(EDID, 'Editor ID', 0, cpBenign, True, nil, wbFLSTEDIDAfterSet), wbRArrayS('FormIDs', wbFormID(LNAM, 'FormID'), cpNormal, False, nil, nil, nil, wbFLSTLNAMIsSorted) ]); wbRecord(PERK, 'Perk', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000004} 2, 'Non-Playable' ])), [ wbEDID, wbVMADFragmentedPERK, wbFULL, wbDESCReq, wbICON, wbCTDAs, wbStruct(DATA, 'Data', [ wbInteger('Trait', itU8, wbEnum(['False', 'True'])), wbInteger('Level', itU8), wbInteger('Num Ranks', itU8), wbInteger('Playable', itU8, wbEnum(['False', 'True'])), wbInteger('Hidden', itU8, wbEnum(['False', 'True'])) ], cpNormal, True), wbFormIDCK(NNAM, 'Next Perk', [PERK, NULL]), wbRStructsSK('Effects', 'Effect', [0, 1], [ wbStructSK(PRKE, [1, 2, 0], 'Header', [ wbInteger('Type', itU8, wbEnum([ 'Quest + Stage', 'Ability', 'Entry Point' ]), cpNormal, False, nil, wbPERKPRKETypeAfterSet), wbInteger('Rank', itU8), wbInteger('Priority', itU8) ]), wbUnion(DATA, 'Effect Data', wbPerkDATADecider, [ wbStructSK([0, 1], 'Quest + Stage', [ wbFormIDCk('Quest', [QUST]), wbInteger('Quest Stage', itU8, wbPerkDATAQuestStageToStr, wbCTDAParam2QuestStageToInt), wbByteArray('Unused', 3) ]), wbFormIDCk('Ability', [SPEL]), wbStructSK([0, 1], 'Entry Point', [ wbInteger('Entry Point', itU8, wbEntryPointsEnum, cpNormal, True, nil{, wbPERKEntryPointAfterSet}), wbInteger('Function', itU8, wbEnum([ {0} 'Unknown 0', {1} 'Set Value', // EPFT=1 {2} 'Add Value', // EPFT=1 {3} 'Multiply Value', // EPFT=1 {4} 'Add Range To Value', // EPFT=2 {5} 'Add Actor Value Mult', // EPFT=2 {6} 'Absolute Value', // no params {7} 'Negative Absolute Value', // no params {8} 'Add Leveled List', // EPFT=3 {9} 'Add Activate Choice', // EPFT=4 {10} 'Select Spell', // EPFT=5 {11} 'Select Text', // EPFT=6 {12} 'Set to Actor Value Mult', // EPFT=2 {13} 'Multiply Actor Value Mult', // EPFT=2 {14} 'Multiply 1 + Actor Value Mult', // EPFT=2 {15} 'Set Text' // EPFT=7 ])), wbInteger('Perk Condition Tab Count', itU8, nil, cpIgnore) ]) ], cpNormal, True), wbRStructsSK('Perk Conditions', 'Perk Condition', [0], [ wbInteger(PRKC, 'Run On (Tab Index)', itS8{, wbPRKCToStr, wbPRKCToInt}), wbCTDAsReq ], [], cpNormal, False{, nil, nil, wbPERKPRKCDontShow}), wbRStruct('Function Parameters', [ wbInteger(EPFT, 'Type', itU8, wbEnum([ {0} 'None', {1} 'Float', {2} 'Float/AV,Float', {3} 'LVLI', {4} 'SPEL,lstring,flags', {5} 'SPEL', {6} 'string', {7} 'lstring' ])), // case(EPFT) of // 1: EPFD=float // 2: EPFD=float,float // 3: EPFD=LVLI // 4: EPFD=SPEL, EPF2=lstring, EPF3=int32 flags // 5: EPFD=SPEL // 6: EPFD=string // 7: EPFD=lstring wbLString(EPF2, 'Button Label', 0, cpTranslate), wbStruct(EPF3, 'Script Flags', [ wbInteger('Script Flags', itU8, wbFlags([ 'Run Immediately', 'Replace Default' ])), wbByteArray('Unknown', 3) ]), wbUnion(EPFD, 'Data', wbEPFDDecider, [ {0} wbByteArray('Unknown'), {1} wbFloat('Float'), {2} wbStruct('Float, Float', [ wbFloat('Float 1'), wbFloat('Float 2') ]), {3} wbFormIDCk('Leveled Item', [LVLI]), {4} wbFormIDCk('Spell', [SPEL]), {5} wbFormIDCk('Spell', [SPEL]), {6} wbString('Text', 0, cpTranslate), {7} wbLString('Text', 0, cpTranslate), {8} wbStruct('Actor Value, Float', [ wbInteger('Actor Value', itU32, wbEPFDActorValueToStr, wbEPFDActorValueToInt), wbFloat('Float') ]) ], cpNormal, False{, wbEPFDDontShow}) ], [], cpNormal, False{, wbPERKPRKCDontShow}), wbEmpty(PRKF, 'End Marker', cpIgnore, True) ], []) ]); wbRecord(BPTD, 'Body Part Data', [ wbEDID, wbMODL, wbRStructsSK('Body Parts', 'Body Part', [2], [ wbLString(BPTN, 'Part Name', 0, cpTranslate, True), wbString(PNAM, 'Pose Matching', 0, cpNormal, False), wbString(BPNN, 'Part Node', 0, cpNormal, True), wbString(BPNT, 'VATS Target', 0, cpNormal, True), wbString(BPNI, 'IK Data - Start Node', 0, cpNormal, True), wbStruct(BPND, '', [ {00} wbFloat('Damage Mult'), {04} wbInteger('Flags', itU8, wbFlags([ 'Severable', 'IK Data', 'IK Data - Biped Data', 'Explodable', 'IK Data - Is Head', 'IK Data - Headtracking', 'To Hit Chance - Absolute' ])), {05} wbInteger('Part Type', itU8, wbEnum([ 'Torso', 'Head', 'Eye', 'LookAt', 'Fly Grab', 'Saddle' ])), {06} wbInteger('Health Percent', itU8), {07} wbInteger('Actor Value', itS8, wbActorValueEnum), {08} wbInteger('To Hit Chance', itU8), {09} wbInteger('Explodable - Explosion Chance %', itU8), {10} wbInteger('Explodable - Debris Count', itU16), {12} wbFormIDCk('Explodable - Debris', [DEBR, NULL]), {16} wbFormIDCk('Explodable - Explosion', [EXPL, NULL]), {20} wbFloat('Tracking Max Angle'), {24} wbFloat('Explodable - Debris Scale'), {28} wbInteger('Severable - Debris Count', itS32), {32} wbFormIDCk('Severable - Debris', [DEBR, NULL]), {36} wbFormIDCk('Severable - Explosion', [EXPL, NULL]), {40} wbFloat('Severable - Debris Scale'), wbStruct('Gore Effects Positioning', [ wbStruct('Translate', [ {44} wbFloat('X'), {48} wbFloat('Y'), {52} wbFloat('Z') ]), wbStruct('Rotation', [ {56} wbFloat('X', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), {60} wbFloat('Y', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), {64} wbFloat('Z', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize) ]) ]), {68} wbFormIDCk('Severable - Impact DataSet', [IPDS, NULL]), {72} wbFormIDCk('Explodable - Impact DataSet', [IPDS, NULL]), {28} wbInteger('Severable - Decal Count', itU8), {28} wbInteger('Explodable - Decal Count', itU8), {76} wbByteArray('Unknown', 2), {80} wbFloat('Limb Replacement Scale') ], cpNormal, True), wbString(NAM1, 'Limb Replacement Model', 0, cpNormal, True), wbString(NAM4, 'Gore Effects - Target Bone', 0, cpNormal, True), wbByteArray(NAM5, 'Texture Files Hashes', 0, cpNormal) ], [], cpNormal, True) ]); wbRecord(ADDN, 'Addon Node', [ wbEDID, wbOBNDReq, wbMODL, wbInteger(DATA, 'Node Index', itS32, nil, cpNormal, True), wbFormIDCk(SNAM, 'Sound', [SNDR, NULL]), wbStruct(DNAM, 'Data', [ wbInteger('Master Particle System Cap', itU16), wbInteger('Flags', itU16, wbEnum([], [ {>>> Value Must be 1 or 3 <<<} 1, 'Unknown 1', // {0x0001}'Unknown 0', : The Check-Box is Unchecked in the CK 3, 'Always Loaded' // {0x0002}'Always Loaded' : The Check-Box is Unchecked in the CK ])) ], cpNormal, True) ]); end; procedure DefineTES5h; begin wbRecord(AVIF, 'Actor Value Information', [ wbEDID, wbFULL, wbDESCReq, wbString(ANAM, 'Abbreviation'), wbUnknown(CNAM), wbStruct(AVSK, 'Skill', [ wbFloat('Skill Use Mult'), wbFloat('Skill Offset Mult'), wbFloat('Skill Improve Mult'), wbFloat('Skill Improve Offset') ]), wbRArray('Perk Tree', wbRStruct('Node', [ wbFormIDCk(PNAM, 'Perk', [PERK, NULL]), wbUnknown(FNAM), wbInteger(XNAM, 'Perk-Grid X', itU32), wbInteger(YNAM, 'Perk-Grid Y', itU32), wbFloat(HNAM, 'Horizontal Position'), wbFloat(VNAM, 'Vertical Position'), wbFormIDCk(SNAM, 'Associated Skill', [AVIF, NULL]), wbRArray('Connections', wbInteger(CNAM, 'Line to Index', itU32)), wbInteger(INAM, 'Index', itU32) ], []) ) ]); wbRecord(CAMS, 'Camera Shot', [ wbEDID, wbMODL, wbStruct(DATA, 'Data', [ {00} wbInteger('Action', itU32, wbEnum([ 'Shoot', 'Fly', 'Hit', 'Zoom' ])), {04} wbInteger('Location', itU32, wbEnum([ 'Attacker', 'Projectile', 'Target', 'Lead Actor' ])), {08} wbInteger('Target', itU32, wbEnum([ 'Attacker', 'Projectile', 'Target', 'Lead Actor' ])), {12} wbInteger('Flags', itU32, wbFlags([ 'Position Follows Location', 'Rotation Follows Target', 'Don''t Follow Bone', 'First Person Camera', 'No Tracer', 'Start At Time Zero' ])), wbStruct('Time Multipliers', [ {16} wbFloat('Player'), {20} wbFloat('Target'), {24} wbFloat('Global') ]), {28} wbFloat('Max Time'), {32} wbFloat('Min Time'), {36} wbFloat('Target % Between Actors'), {40} wbFloat('Near Target Distance') ], cpNormal, True, nil, 8), wbFormIDCk(MNAM, 'Image Space Modifier', [IMAD]) ]); wbRecord(CPTH, 'Camera Path', [ wbEDID, wbCTDAs, wbArray(ANAM, 'Related Camera Paths', wbFormIDCk('Related Camera Path', [CPTH, NULL]), ['Parent', 'Previous Sibling'], cpNormal, True), wbInteger(DATA, 'Camera Zoom', itU8, wbEnum([], [ 0, 'Default, Must Have Camera Shots', 1, 'Disable, Must Have Camera Shots', 2, 'Shot List, Must Have Camera Shots', 128, 'Default', 129, 'Disable', 130, 'Shot List' ]), cpNormal, True), wbRArray('Camera Shots', wbFormIDCk(SNAM, 'Camera Shot', [CAMS])) ]); wbRecord(VTYP, 'Voice Type', [ wbEDID, wbInteger(DNAM, 'Flags', itU8, wbFlags([ 'Allow Default Dialog', 'Female' ]), cpNormal, True) ]); wbRecord(MATT, 'Material Type', [ wbEDID, wbFormIDCk(PNAM, 'Material Parent', [MATT, NULL]), wbString(MNAM, 'Material Name'), wbStruct(CNAM, 'Havok Display Color', [ wbFloat('Red', cpNormal, True, 255, 0), wbFloat('Green', cpNormal, True, 255, 0), wbFloat('Blue', cpNormal, True, 255, 0) ]), wbFloat(BNAM, 'Buoyancy'), wbInteger(FNAM, 'Flags', itU32, wbFlags([ 'Stair Material', 'Arrows Stick' ], False)), wbFormIDCk(HNAM, 'Havok Impact Data Set', [IPDS, NULL]) ]); wbRecord(IPCT, 'Impact', [ wbEDID, wbMODL, wbStruct(DATA, '', [ wbFloat('Effect - Duration'), wbInteger('Effect - Orientation', itU32, wbEnum([ 'Surface Normal', 'Projectile Vector', 'Projectile Reflection' ])), wbFloat('Angle Threshold'), wbFloat('Placement Radius'), wbInteger('Sound Level', itU32, wbSoundLevelEnum), wbInteger('Flags', itU8, wbFlags([ {0x01} 'No Decal Data' ])), wbInteger('Impact Result', itU8, wbEnum([ {0} 'Default', {1} 'Destroy', {2} 'Bounce', {3} 'Impale', {4} 'Stick' ])), wbByteArray('Unknown', 2) ], cpNormal, True, nil, 4), wbDODT, wbFormIDCk(DNAM, 'Texture Set', [TXST]), wbFormIDCk(ENAM, 'Secondary Texture Set', [TXST]), wbFormIDCk(SNAM, 'Sound 1', [SNDR, SOUN, NULL]), wbFormIDCk(NAM1, 'Sound 2', [SNDR, SOUN, NULL]), wbFormIDCk(NAM2, 'Hazard', [HAZD, NULL]) ]); wbRecord(IPDS, 'Impact Data Set', [ wbEDID, wbRArrayS('Data', wbStructSK(PNAM, [0], '', [ wbFormIDCk('Material', [MATT]), wbFormIDCk('Impact', [IPCT]) ])) ]); wbRecord(ECZN, 'Encounter Zone', [ wbEDID, wbStruct(DATA, '', [ wbFormIDCkNoReach('Owner', [NPC_, FACT, NULL]), wbFormIDCk('Location', [LCTN, NULL]), wbInteger('Rank', itS8), wbInteger('Min Level', itS8), wbInteger('Flags', itU8, wbFlags([ 'Never Resets', 'Match PC Below Minimum Level', 'Disable Combat Boundary' ])), wbInteger('Max Level', itS8) ], cpNormal, True, nil, 2) ]); wbRecord(LCTN, 'Location', [ wbEDID, wbArray(ACPR, 'Actor Cell Persistent Reference', wbStruct('', [ wbFormIDCk('Actor', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA], False, cpBenign), wbFormIDCk('Location', [WRLD, CELL], False, cpBenign), wbInteger('Grid Y', itS16, nil, cpBenign), wbInteger('Grid X', itS16, nil, cpBenign) ])), wbArray(LCPR, 'Location Cell Persistent Reference', wbStruct('', [ wbFormIDCk('Actor', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA], False, cpBenign), wbFormIDCk('Location', [WRLD, CELL], False, cpBenign), wbInteger('Grid Y', itS16, nil, cpBenign), wbInteger('Grid X', itS16, nil, cpBenign) ])), {>>> From Danwguard.esm, Does not follow similar previous patterns <<<} wbArray(RCPR, 'Reference Cell Persistent Reference', wbFormIDCk('Ref', [ACHR, REFR], False, cpBenign)), wbArray(ACUN, 'Actor Cell Unique', wbStruct('', [ wbFormIDCk('Actor', [NPC_], False, cpBenign), wbFormIDCk('Ref', [ACHR], False, cpBenign), wbFormIDCk('Location', [LCTN, NULL], False, cpBenign) ])), wbArray(LCUN, 'Location Cell Unique', wbStruct('', [ wbFormIDCk('Actor', [NPC_], False, cpBenign), wbFormIDCk('Ref', [ACHR], False, cpBenign), wbFormIDCk('Location', [LCTN, NULL], False, cpBenign) ])), {>>> in Unofficial Skyrim patch <<<} wbArray(RCUN, 'Reference Cell Unique', wbFormIDCk('Actor', [NPC_], False, cpBenign)), wbArray(ACSR, 'Actor Cell Static Reference', wbStruct('', [ wbFormIDCk('Loc Ref Type', [LCRT], False, cpBenign), wbFormIDCk('Marker', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA], False, cpBenign), wbFormIDCk('Location', [WRLD, CELL], False, cpBenign), wbInteger('Grid Y', itS16, nil, cpBenign), wbInteger('Grid X', itS16, nil, cpBenign) ])), wbArray(LCSR, 'Location Cell Static Reference', wbStruct('', [ wbFormIDCk('Loc Ref Type', [LCRT], False, cpBenign), wbFormIDCk('Marker', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA], False, cpBenign), wbFormIDCk('Location', [WRLD, CELL], False, cpBenign), wbInteger('Grid Y', itS16, nil, cpBenign), wbInteger('Grid X', itS16, nil, cpBenign) ])), {>>> Seen in Open Cities <<<} wbArray(RCSR, 'Reference Cell Static Reference', wbFormIDCk('Ref', [ACHR, REFR], False, cpBenign)), wbRArray('Actor Cell Encounter Cell', wbStruct(ACEC, 'Unknown', [ wbFormIDCk('Location', [WRLD, CELL], False, cpBenign), wbArray('Coordinates', wbStruct('', [ wbInteger('Grid Y', itS16, nil, cpBenign), wbInteger('Grid X', itS16, nil, cpBenign) ])) ]) ), wbRArray('Location Cell Encounter Cell', wbStruct(LCEC, 'Unknown', [ wbFormIDCk('Location', [WRLD, CELL], False, cpBenign), wbArray('Coordinates', wbStruct('', [ wbInteger('Grid Y', itS16, nil, cpBenign), wbInteger('Grid X', itS16, nil, cpBenign) ])) ]) ), {>>> Seen in Open Cities <<<} wbRArray('Reference Cell Encounter Cell', wbStruct(RCEC, 'Unknown', [ wbFormIDCk('Location', [WRLD, CELL], False, cpBenign), wbArray('Coordinates', wbStruct('', [ wbInteger('Grid Y', itS16, nil, cpBenign), wbInteger('Grid X', itS16, nil, cpBenign) ])) ]) ), wbArray(ACID, 'Actor Cell Marker Reference', wbFormIDCk('Ref', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA], False, cpBenign)), wbArray(LCID, 'Location Cell Marker Reference', wbFormIDCk('Ref', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA], False, cpBenign)), wbArray(ACEP, 'Actor Cell Enable Point', wbStruct('', [ wbFormIDCk('Actor', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA], False, cpBenign), wbFormIDCk('Ref', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA], False, cpBenign), wbInteger('Grid Y', itS16, nil, cpBenign), wbInteger('Grid X', itS16, nil, cpBenign) ])), wbArray(LCEP, 'Location Cell Enable Point', wbStruct('', [ wbFormIDCk('Actor', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA], False, cpBenign), wbFormIDCk('Ref', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA], False, cpBenign), wbInteger('Grid Y', itS16, nil, cpBenign), wbInteger('Grid X', itS16, nil, cpBenign) ])), wbFULL, wbKSIZ, wbKWDAs, wbFormIDCk(PNAM, 'Parent Location', [LCTN, NULL]), wbFormIDCk(NAM1, 'Music', [MUSC, NULL]), wbFormIDCk(FNAM, 'Unreported Crime Faction', [FACT]), wbFormIDCk(MNAM, 'World Location Marker Ref', [REFR, ACHR]), wbFloat(RNAM, 'World Location Radius'), wbFormIDCk(NAM0, 'Horse Marker Ref', [REFR]), wbCNAM ], False, nil, cpNormal, False, nil, wbKeywordsAfterSet); end; {this is required to prevent XE6 compiler error} type TVarRecs = array of TVarRec; function CombineVarRecs(const a, b : array of const) : TVarRecs; begin SetLength(Result, Length(a) + Length(b)); if Length(a) > 0 then Move(a[0], Result[0], SizeOf(TVarRec) * Length(a)); if Length(b) > 0 then Move(b[0], Result[Length(a)], SizeOf(TVarRec) * Length(b)); end; function MakeVarRecs(const a : array of const) : TVarRecs; begin SetLength(Result, Length(a)); if Length(a) > 0 then Move(a[0], Result[0], SizeOf(TVarRec) * Length(a)); end; procedure DefineTES5i; var a, b, c : TVarRecs; begin wbRecord(MESG, 'Message', [ wbEDID, wbDESCReq, wbFULL, wbFormIDCk(INAM, 'Icon (unused)', [NULL], False, cpIgnore, True), // leftover wbFormIDCk(QNAM, 'Owner Quest', [QUST]), wbInteger(DNAM, 'Flags', itU32, wbFlags([ 'Message Box', 'Auto Display' ]), cpNormal, True, False, nil, wbMESGDNAMAfterSet), wbInteger(TNAM, 'Display Time', itU32, nil, cpNormal, False, False, wbMESGTNAMDontShow), wbRStructs('Menu Buttons', 'Menu Button', [ wbLString(ITXT, 'Button Text', 0, cpTranslate), wbCTDAs ], []) ], False, nil, cpNormal, False, wbMESGAfterLoad); a := MakeVarRecs([ 0, 'None', Sig2Int('RADA'), 'RADA (Unused)', Sig2Int('MORP'), 'MORP (Unused)', Sig2Int('PPAR'), 'PPAR (Unused)', Sig2Int('MYSN'), 'MYSN (Unused)', Sig2Int('MYSF'), 'MYSF (Unused)', Sig2Int('WWSP'), 'Werewolf Spell', Sig2Int('SALT'), 'Sitting Angle Limit', Sig2Int('APSH'), 'Allow Player Shout', Sig2Int('GOLD'), 'Gold', Sig2Int('LKPK'), 'Lockpick', Sig2Int('SKLK'), 'SkeletonKey', Sig2Int('PFAC'), 'Player Faction', Sig2Int('GFAC'), 'Guard Faction', Sig2Int('DFMS'), 'Default Music', Sig2Int('BTMS'), 'Battle Music', Sig2Int('DTMS'), 'Death Music', Sig2Int('SCMS'), 'Success Music', Sig2Int('LUMS'), 'Level Up Music', Sig2Int('DCMS'), 'Dungeon Cleared Music', Sig2Int('PVMA'), 'Player Voice (Male)', Sig2Int('PVMC'), 'Player Voice (Male Child)', Sig2Int('PVFA'), 'Player Voice (Female)', Sig2Int('PVFC'), 'Player Voice (Female Child)', Sig2Int('EPDF'), 'Eat Package Default Food', Sig2Int('LHEQ'), 'LeftHand Equip', Sig2Int('RHEQ'), 'RightHand Equip', Sig2Int('EHEQ'), 'EitherHand Equip', Sig2Int('VOEQ'), 'Voice Equip', Sig2Int('POEQ'), 'Potion Equip', Sig2Int('EACA'), 'Every Actor Ability', Sig2Int('CACA'), 'Commanded Actor Ability', Sig2Int('DEIS'), 'Drug Wears Off Image Space', Sig2Int('DFTS'), 'Footstep Set', Sig2Int('DLMT'), 'Landscape Material', Sig2Int('DLZM'), 'Dragon Land Zone Marker', Sig2Int('DCZM'), 'Dragon Crash Zone Marker', Sig2Int('CSTY'), 'Combat Style', Sig2Int('PLST'), 'Default Pack List', Sig2Int('PWFD'), 'Wait-For-Dialogue Package', Sig2Int('LRTB'), 'LocRefType Boss', Sig2Int('VLOC'), 'Virtual Location', Sig2Int('PLOC'), 'PersistAll Location', Sig2Int('INVP'), 'Inventory Player', Sig2Int('PTNP'), 'Pathing Test NPC', Sig2Int('FPCS'), 'Favor Cost Small', Sig2Int('FPCM'), 'Favor Cost Medium', Sig2Int('FPCL'), 'Favor Cost Large', Sig2Int('FGPD'), 'Favor Gifts Per Day', Sig2Int('AASW'), 'Action Swim State Change', Sig2Int('AALK'), 'Action Look', Sig2Int('AALA'), 'Action LeftAttack', Sig2Int('AALD'), 'Action LeftReady', Sig2Int('AALR'), 'Action LeftRelease', Sig2Int('AALI'), 'Action LeftInterrupt', Sig2Int('AARA'), 'Action RightAttack', Sig2Int('AARD'), 'Action RightReady', Sig2Int('AARR'), 'Action RightRelease', Sig2Int('AARI'), 'Action RightInterrupt', Sig2Int('AADA'), 'Action DualAttack', Sig2Int('AADL'), 'Action DualRelease', Sig2Int('AAAC'), 'Action Activate', Sig2Int('AAJP'), 'Action Jump', Sig2Int('AAFA'), 'Action Fall', Sig2Int('AALN'), 'Action Land', Sig2Int('AASN'), 'Action Sneak', Sig2Int('AAVC'), 'Action Voice', Sig2Int('AAVD'), 'Action VoiceReady', Sig2Int('AAVR'), 'Action VoiceRelease', Sig2Int('AAVI'), 'Action VoiceInterrupt', Sig2Int('AAID'), 'Action Idle', Sig2Int('AAST'), 'Action Sprint Start', Sig2Int('AASP'), 'Action Sprint Stop', Sig2Int('AADR'), 'Action Draw', Sig2Int('AASH'), 'Action Sheath', Sig2Int('ALPA'), 'Action Left Power Attack', Sig2Int('AAPA'), 'Action Right Power Attack', Sig2Int('ADPA'), 'Action Dual Power Attack', Sig2Int('AAS1'), 'Action Stagger Start', Sig2Int('AABH'), 'Action Block Hit', Sig2Int('AABA'), 'Action Block Anticipate', Sig2Int('AARC'), 'Action Recoil', Sig2Int('AAR2'), 'Action Large Recoil', Sig2Int('AAB1'), 'Action Bleedout Start', Sig2Int('AAB2'), 'Action Bleedout Stop', Sig2Int('AAIS'), 'Action Idle Stop', Sig2Int('AAWH'), 'Action Ward Hit', Sig2Int('AAFQ'), 'Action Force Equip', Sig2Int('AASC'), 'Action Shield Change', Sig2Int('AAPS'), 'Action Path Start', Sig2Int('AAPE'), 'Action Path End', Sig2Int('AALM'), 'Action Large Movement Delta', Sig2Int('AAF1'), 'Action Fly Start', Sig2Int('AAF2'), 'Action Fly Stop', Sig2Int('AAH1'), 'Action Hover Start', Sig2Int('AAH2'), 'Action Hover Stop', Sig2Int('AABI'), 'Action Bumped Into', Sig2Int('AASS'), 'Action Summoned Start', Sig2Int('ATKI'), 'Action Talking Idle', Sig2Int('ALTI'), 'Action Listen Idle', Sig2Int('AADE'), 'Action Death', Sig2Int('AADW'), 'Action Death Wait', Sig2Int('AIDW'), 'Action Idle Warn', Sig2Int('AMST'), 'Action Move Start', Sig2Int('AMSP'), 'Action Move Stop', Sig2Int('ATRI'), 'Action Turn Right', Sig2Int('ATLE'), 'Action Turn Left', Sig2Int('ATSP'), 'Action Turn Stop', Sig2Int('AMFD'), 'Action Move Forward', Sig2Int('AMBK'), 'Action Move Backward', Sig2Int('AMLT'), 'Action Move Left', Sig2Int('AMRT'), 'Action Move Right', Sig2Int('ARAG'), 'Action Reset Animation Graph', Sig2Int('AKDN'), 'Action Knockdown', Sig2Int('AAGU'), 'Action Get Up', Sig2Int('ASID'), 'Action Idle Stop Instant', Sig2Int('ARGI'), 'Action Ragdoll Instant', Sig2Int('AWWS'), 'Action Waterwalk Start', Sig2Int('AREL'), 'Action Reload', Sig2Int('PUSG'), 'Pickup Sound Generic', Sig2Int('PDSG'), 'Putdown Sound Generic', Sig2Int('PUSW'), 'Pickup Sound Weapon', Sig2Int('PDSW'), 'Putdown Sound Weapon', Sig2Int('PUSA'), 'Pickup Sound Armor', Sig2Int('PDSA'), 'Putdown Sound Armor', Sig2Int('PUSB'), 'Pickup Sound Book', Sig2Int('PDSB'), 'Putdown Sound Book', Sig2Int('PUSI'), 'Pickup Sound Ingredient', Sig2Int('PDSI'), 'Putdown Sound Ingredient', Sig2Int('HVSS'), 'Harvest Sound', Sig2Int('HVFS'), 'Harvest Failed Sound', Sig2Int('WBSN'), 'Ward Break Sound', Sig2Int('WASN'), 'Ward Absorb Sound', Sig2Int('WDSN'), 'Ward Deflect Sound', Sig2Int('MFSN'), 'Magic Fail Sound', Sig2Int('SFSN'), 'Shout Fail Sound', Sig2Int('HFSD'), 'Heartbeat Sound Fast', Sig2Int('HSSD'), 'Heartbeat Sound Slow', Sig2Int('IMLH'), 'Imagespace: Low Health', Sig2Int('SCSD'), 'Soul Captured Sound', Sig2Int('NASD'), 'No-Activation Sound', Sig2Int('MMSD'), 'Map Menu Looping Sound', Sig2Int('DDSC'), 'Dialogue Voice Category', Sig2Int('NDSC'), 'Non-Dialogue Voice Category', Sig2Int('SFDC'), 'SFX To Fade In Dialogue Category', Sig2Int('PDMC'), 'Pause During Menu Category (Fade)', Sig2Int('PIMC'), 'Pause During Menu Category (Immediate)', Sig2Int('PDLC'), 'Pause During Loading Menu Category', Sig2Int('MDSC'), 'Music Sound Category', Sig2Int('SMSC'), 'Stats Mute Category', Sig2Int('SSSC'), 'Stats Music', Sig2Int('MTSC'), 'Master Sound Category', Sig2Int('TSSC'), 'Time Sensitive Sound Category', Sig2Int('DOP2'), 'Dialogue Output Model (3D)', Sig2Int('DOP3'), 'Dialogue Output Model (2D)', Sig2Int('POPM'), 'Player''s Output Model (1st Person)', Sig2Int('P3OM'), 'Player''s Output Model (3rd Person)', Sig2Int('IOPM'), 'Interface Output Model', Sig2Int('RVBT'), 'Reverb Type', Sig2Int('UWLS'), 'Underwater Loop Sound', Sig2Int('URVT'), 'Underwater Reverb Type', Sig2Int('HRSK'), 'Keyword - Horse', Sig2Int('UNDK'), 'Keyword - Undead', Sig2Int('NPCK'), 'Keyword - NPC', Sig2Int('KWBR'), 'Keyword - BeastRace', Sig2Int('KWDM'), 'Keyword - DummyObject', Sig2Int('KWGE'), 'Keyword - UseGeometryEmitter', Sig2Int('KWMS'), 'Keyword - MustStop', Sig2Int('KWUA'), 'Keyword - UpdateDuringArchery', Sig2Int('KWOT'), 'Keyword - Skip Outfit Items', Sig2Int('FTHD'), 'Male Face Texture Set: Head', Sig2Int('FTMO'), 'Male Face Texture Set: Mouth', Sig2Int('FTEL'), 'Male Face Texture Set: Eyes', Sig2Int('FTHF'), 'Female Face Texture Set: Head', Sig2Int('FTMF'), 'Female Face Texture Set: Mouth', Sig2Int('FTRF'), 'Female Face Texture Set: Eyes', Sig2Int('IMID'), 'ImageSpaceModifier for inventory menu.', Sig2Int('PTEM'), 'Package template', Sig2Int('MMCL'), 'Main Menu Cell', Sig2Int('DMWL'), 'Default MovementType: Walk', Sig2Int('DMRN'), 'Default MovementType: Run', Sig2Int('DMSW'), 'Default MovementType: Swim', Sig2Int('DMFL'), 'Default MovementType: Fly', Sig2Int('DMSN'), 'Default MovementType: Sneak', Sig2Int('DMSP'), 'Default MovementType: Sprint', Sig2Int('SPFK'), 'Keyword - Special Furniture', Sig2Int('FFFP'), 'Keyword - Furniture Forces 1st Person', Sig2Int('FFTP'), 'Keyword - Furniture Forces 3rd Person', Sig2Int('AFNP'), 'Keyword - Activator Furniture No Player', Sig2Int('TKGS'), 'Telekinesis Grab Sound', Sig2Int('TKTS'), 'Telekinesis Throw Sound', Sig2Int('WMWE'), 'World Map Weather', Sig2Int('HMPC'), 'Help Manual PC', Sig2Int('HMXB'), 'Help Manual XBox', Sig2Int('TKAM'), 'Keyword - Type Ammo', Sig2Int('TKAR'), 'Keyword - Type Armor', Sig2Int('TKBK'), 'Keyword - Type Book', Sig2Int('TKIG'), 'Keyword - Type Ingredient', Sig2Int('TKKY'), 'Keyword - Type Key', Sig2Int('TKMS'), 'Keyword - Type Misc', Sig2Int('TKSG'), 'Keyword - Type SoulGem', Sig2Int('TKWP'), 'Keyword - Type Weapon', Sig2Int('TKPT'), 'Keyword - Type Potion', Sig2Int('BENW'), 'Base Weapon Enchantment', Sig2Int('BENA'), 'Base Armor Enchantment', Sig2Int('BAPO'), 'Base Potion', Sig2Int('BAPS'), 'Base Poison', Sig2Int('DRAK'), 'Keyword - Dragon', Sig2Int('MVBL'), 'Keyword - Movable', Sig2Int('ABSE'), 'Art Object - Absorb Effect', Sig2Int('WEML'), 'Weapon Material List', Sig2Int('ARTL'), 'Armor Material List', Sig2Int('DIEN'), 'Keyword - Disallow Enchanting', Sig2Int('FTML'), 'Favor travel marker location', Sig2Int('LKHO'), 'Keyword - Hold Location', Sig2Int('CWOK'), 'Keyword - Civil War Owner', Sig2Int('CWNE'), 'Keyword - Civil War Neutral', Sig2Int('LRSO'), 'LocRefType - Civil War Soldier', Sig2Int('KWDO'), 'Keyword - ClearableLocation', Sig2Int('LRRD'), 'LocRefType - Resource Destructible', Sig2Int('HCLL'), 'FormList - Hair Color List', Sig2Int('CMPX'), 'Complex Scene Object', Sig2Int('RUSG'), 'Keyword - Reusable SoulGem', Sig2Int('ANML'), 'Keyword - Animal', Sig2Int('DAED'), 'Keyword - Daedra' ]); b := MakeVarRecs([ Sig2Int('BEEP'), 'Keyword - Robot', Sig2Int('NRNT'), 'Keyword - Nirnroot', Sig2Int('FTGF'), 'Fighters'' Guild Faction', Sig2Int('MGGF'), 'Mages'' Guild Faction', Sig2Int('TVGF'), 'Thieves'' Guild Faction', Sig2Int('DBHF'), 'Dark Brotherhood Faction', Sig2Int('JRLF'), 'Jarl Faction', Sig2Int('AWWW'), 'Bunny Faction', Sig2Int('PIVV'), 'Player Is Vampire Variable', Sig2Int('PIWV'), 'Player Is Werewolf Variable', Sig2Int('NMRD'), 'Road Marker', Sig2Int('SAT1'), 'Keyword: Scale Actor To 1.0', Sig2Int('VAMP'), 'Keyword: Vampire', Sig2Int('FORG'), 'Keyword: Forge', Sig2Int('COOK'), 'Keyword: Cooking Pot', Sig2Int('SMLT'), 'Keyword: Smelter', Sig2Int('TANN'), 'Keyword: Tanning Rack', Sig2Int('HBLK'), 'Help - Basic Lockpicking (PC)', Sig2Int('HBLX'), 'Help - Basic Lockpicking (Console)', Sig2Int('HBFG'), 'Help - Basic Forging', Sig2Int('HBCO'), 'Help - Basic Cooking', Sig2Int('HBML'), 'Help - Basic Smelting', Sig2Int('HBTA'), 'Help - Basic Tanning', Sig2Int('HBOC'), 'Help - Basic Object Creation', Sig2Int('HBEC'), 'Help - Basic Enchanting', Sig2Int('HBSM'), 'Help - Basic Smithing Weapon', Sig2Int('HBSA'), 'Help - Basic Smithing Armor', Sig2Int('HBAL'), 'Help - Basic Alchemy', Sig2Int('HBBR'), 'Help - Barter', Sig2Int('HBLU'), 'Help - Leveling up', Sig2Int('HBSK'), 'Help - Skills Menu', Sig2Int('HBMM'), 'Help - Map Menu', Sig2Int('HBJL'), 'Help - Journal', Sig2Int('HBLH'), 'Help - Low Health', Sig2Int('HBLM'), 'Help - Low Magicka', Sig2Int('HBLS'), 'Help - Low Stamina', Sig2Int('HBHJ'), 'Help - Jail', Sig2Int('HBFT'), 'Help - Teamate Favor', Sig2Int('HBWC'), 'Help - Weapon Charge', Sig2Int('HBFS'), 'Help - Favorites', Sig2Int('KHFL'), 'Kinect Help FormList', Sig2Int('HBFM'), 'Help - Flying Mount', Sig2Int('HBTL'), 'Help - Target Lock', Sig2Int('HBAT'), 'Help - Attack Target', Sig2Int('MHFL'), 'Help - Mods', Sig2Int('LSIS'), 'Imagespace: Load screen', Sig2Int('WMDA'), 'Keyword - Weapon Material Daedric', Sig2Int('WMDR'), 'Keyword - Weapon Material Draugr', Sig2Int('WMDH'), 'Keyword - Weapon Material DraugrHoned', Sig2Int('WMDW'), 'Keyword - Weapon Material Dwarven', Sig2Int('WMEB'), 'Keyword - Weapon Material Ebony', Sig2Int('WMEL'), 'Keyword - Weapon Material Elven', Sig2Int('WMFA'), 'Keyword - Weapon Material Falmer', Sig2Int('WMFH'), 'Keyword - Weapon Material FalmerHoned', Sig2Int('WMGL'), 'Keyword - Weapon Material Glass', Sig2Int('WMIM'), 'Keyword - Weapon Material Imperial', Sig2Int('WMIR'), 'Keyword - Weapon Material Iron', Sig2Int('WMOR'), 'Keyword - Weapon Material Orcish', Sig2Int('WMST'), 'Keyword - Weapon Material Steel', Sig2Int('WMWO'), 'Keyword - Weapon Material Wood', Sig2Int('WTBA'), 'Keyword - WeaponTypeBoundArrow', Sig2Int('AODA'), 'Keyword - Armor Material Daedric', Sig2Int('AODP'), 'Keyword - Armor Material Dragonplate', Sig2Int('AODS'), 'Keyword - Armor Material Dragonscale', Sig2Int('AODB'), 'Keyword - Armor Material Dragonbone', Sig2Int('AODW'), 'Keyword - Armor Material Dwarven', Sig2Int('AOEB'), 'Keyword - Armor Material Ebony', Sig2Int('AOEL'), 'Keyword - Armor Material Elven', Sig2Int('AOES'), 'Keyword - Armor Material ElvenSplinted', Sig2Int('AOFL'), 'Keyword - Armor Material FullLeather', Sig2Int('AOGL'), 'Keyword - Armor Material Glass', Sig2Int('AOHI'), 'Keyword - Armor Material Hide', Sig2Int('AOIM'), 'Keyword - Armor Material Imperial', Sig2Int('AOIH'), 'Keyword - Armor Material ImperialHeavy', Sig2Int('AOIR'), 'Keyword - Armor Material ImperialReinforced', Sig2Int('AOFE'), 'Keyword - Armor Material Iron', Sig2Int('AOIB'), 'Keyword - Armor Material IronBanded', Sig2Int('AOOR'), 'Keyword - Armor Material Orcish', Sig2Int('AOSC'), 'Keyword - Armor Material Scaled', Sig2Int('AOST'), 'Keyword - Armor Material Steel', Sig2Int('AOSP'), 'Keyword - Armor Material SteelPlate', Sig2Int('AOSK'), 'Keyword - Armor Material Stormcloak', Sig2Int('AOSD'), 'Keyword - Armor Material Studded', Sig2Int('GCK1'), 'Keyword - Generic Craftable Keyword 01', Sig2Int('GCK2'), 'Keyword - Generic Craftable Keyword 02', Sig2Int('GCK3'), 'Keyword - Generic Craftable Keyword 03', Sig2Int('GCK4'), 'Keyword - Generic Craftable Keyword 04', Sig2Int('GCK5'), 'Keyword - Generic Craftable Keyword 05', Sig2Int('GCK6'), 'Keyword - Generic Craftable Keyword 06', Sig2Int('GCK7'), 'Keyword - Generic Craftable Keyword 07', Sig2Int('GCK8'), 'Keyword - Generic Craftable Keyword 08', Sig2Int('GCK9'), 'Keyword - Generic Craftable Keyword 09', Sig2Int('GCKX'), 'Keyword - Generic Craftable Keyword 10', Sig2Int('JWLR'), 'Keyword - Jewelry', Sig2Int('KWCU'), 'Keyword - Cuirass', Sig2Int('MNTK'), 'Keyword - Mount', Sig2Int('LMHP'), 'Local Map Hide Plane', Sig2Int('SLDM'), 'Snow LOD Material', Sig2Int('SLHD'), 'Snow LOD Material (HD)', Sig2Int('ALDM'), 'Ash LOD Material', Sig2Int('ALHD'), 'Ash LOD Material (HD)', Sig2Int('DGFL'), 'DialogueFollower Quest', Sig2Int('PTFR'), 'PotentialFollower Faction', Sig2Int('AVWP'), 'Werewolf Available Perks', Sig2Int('AVVP'), 'Vampire Available Perks', Sig2Int('RIWR'), 'Werewolf Race', Sig2Int('RIVR'), 'Vampire Race', Sig2Int('RIVS'), 'Vampire Spells', Sig2Int('DMXL'), 'Dragon Mount No Land List', Sig2Int('PCMD'), 'Player Can Mount Dragon Here List', Sig2Int('FMYS'), 'Flying Mount - Allowed Spells', Sig2Int('FMNS'), 'Flying Mount - Disallowed Spells', Sig2Int('MNT2'), 'Keyword - Mount', Sig2Int('AIVC'), 'Verlet Cape', Sig2Int('FTNP'), 'Furniture Test NPC', Sig2Int('COEX'), 'Keyword - Conditional Explosion', Sig2Int('VFNC'), 'Vampire Feed No Crime Faction', Sig2Int('KWSP'), 'Skyrim - Worldspace', Sig2Int('ALBM'), 'Keyword - Armor Material Light Bonemold', Sig2Int('ALCH'), 'Keyword - Armor Material Light Chitin', Sig2Int('ALNC'), 'Keyword - Armor Material Light Nordic', Sig2Int('ALSM'), 'Keyword - Armor Material Light Stalhrim', Sig2Int('FMFF'), 'Flying Mount - Fly Fast Worldspaces', Sig2Int('AHBM'), 'Keyword - Armor Material Heavy Bonemold', Sig2Int('AHCH'), 'Keyword - Armor Material Heavy Chitin', Sig2Int('AHNC'), 'Keyword - Armor Material Heavy Nordic', Sig2Int('AHSM'), 'Keyword - Armor Material Heavy Stalhrim', Sig2Int('WPNC'), 'Keyword - Weapon Material Nordic', Sig2Int('WPSM'), 'Keyword - Weapon Material Stalhrim' ]); c := CombineVarRecs(a, b); wbRecord(DOBJ, 'Default Object Manager', [ wbEDID, wbArrayS(DNAM, 'Objects', wbStructSK([0], 'Object', [ wbInteger('Use', itU32, wbEnum([], c), cpNormalIgnoreEmpty), wbFormID('Object ID', cpNormalIgnoreEmpty) ]), 0, cpNormalIgnoreEmpty, True, wbDOBJObjectsAfterLoad ) ]); wbRecord(LGTM, 'Lighting Template', [ wbEDID, wbStruct(DATA, 'Lighting', [ wbByteColors('Ambient Color'), wbByteColors('Directional Color'), wbByteColors('Fog Color Near'), wbFloat('Fog Near'), wbFloat('Fog Far'), wbInteger('Directional Rotation XY', itS32), wbInteger('Directional Rotation Z', itS32), wbFloat('Directional Fade'), wbFloat('Fog Clip Dist'), wbFloat('Fog Power'), wbAmbientColors('Ambient Colors'), // WindhelmLightingTemplate [LGTM:0007BA87] only find 24 ! wbByteColors('Fog Color Far'), wbFloat('Fog Max'), wbStruct('Light Fade Distances', [ wbFloat('Start'), wbFloat('End') ]), wbByteArray('Unknown', 4) ], cpNormal, True, nil, 11), wbAmbientColors(DALC) ]); wbRecord(MUSC, 'Music Type', [ wbEDID, wbInteger(FNAM, 'Flags', itU32, wbFlags([ {0x01} 'Plays One Selection', {0x02} 'Abrupt Transition', {0x04} 'Cycle Tracks', {0x08} 'Maintain Track Order', {0x10} 'Unknown 4', {0x20} 'Ducks Current Track', {0x40} IsSSE('Doesn''t Queue', 'Unknown 6') ]), cpNormal, True), wbStruct(PNAM, 'Data', [ wbInteger('Priority', itU16), wbInteger('Ducking (dB)', itU16, wbDiv(100)) ]), wbFloat(WNAM, 'Fade Duration'), wbArray(TNAM, 'Music Tracks', wbFormIDCk('Track', [MUST, NULL])) ]); wbRecord(FSTP, 'Footstep', [ wbEDID, wbFormIDCk(DATA, 'Impact Data Set', [IPDS, NULL], False, cpNormal, True), wbString(ANAM, 'Tag', 0, cpNormal, True) ]); wbRecord(FSTS, 'Footstep Set', [ wbEDID, wbStruct(XCNT, 'Count', [ wbInteger('Walk Forward Sets', itU32), wbInteger('Run Forward Sets', itU32), wbInteger('Walk Forward Alternate Sets', itU32), wbInteger('Run Forward Alternate Sets', itU32), wbInteger('Walk Forward Alternate 2 Sets', itU32) ], cpNormal, True), wbArray(DATA, 'Footstep Sets', wbFormIDCk('Footstep', [FSTP]), 0, nil, nil, cpNormal, True) ]); wbSMNodeFlags := wbFlags([ 'Random', 'Warn if no child quest started' ]); wbRecord(SMBN, 'Story Manager Branch Node', [ wbEDID, wbFormIDCk(PNAM, 'Parent ', [SMQN, SMBN, SMEN, NULL]), wbFormIDCk(SNAM, 'Child ', [SMQN, SMBN, SMEN, NULL]), wbCITC, wbCTDAsCount, wbInteger(DNAM, 'Flags', itU32, wbSMNodeFlags), wbUnknown(XNAM) ], False, nil, cpNormal, False, nil, wbConditionsAfterSet); wbRecord(SMQN, 'Story Manager Quest Node', [ wbEDID, wbFormIDCk(PNAM, 'Parent ', [SMQN, SMBN, SMEN, NULL]), wbFormIDCk(SNAM, 'Child ', [SMQN, SMBN, SMEN, NULL]), wbCITC, wbCTDAsCount, wbStruct(DNAM, 'Flags', [ wbInteger('Node Flags', itU16, wbSMNodeFlags), wbInteger('Quest Flags', itU16, wbFlags([ 'Do all before repeating', 'Shares event', 'Num quests to run' ])) ]), wbInteger(XNAM, 'Max concurrent quests', itU32), wbInteger(MNAM, 'Num quests to run', itU32), wbInteger(QNAM, 'Quest Count', itU32, nil, cpBenign), wbRArray('Quests', wbRStructSK([0], 'Quest', [ wbFormIDCk(NNAM, 'Quest', [QUST]), wbUnknown(FNAM), wbFloat(RNAM, 'Hours until reset', cpNormal, False, 1/24) ], []), cpNormal, False, nil, wbSMQNQuestsAfterSet) ], False, nil, cpNormal, False, nil, wbConditionsAfterSet); wbRecord(SMEN, 'Story Manager Event Node', [ wbEDID, wbFormIDCk(PNAM, 'Parent ', [SMQN, SMBN, SMEN, NULL]), wbFormIDCk(SNAM, 'Child ', [SMQN, SMBN, SMEN, NULL]), wbCITC, wbCTDAsCount, wbInteger(DNAM, 'Flags', itU32, wbSMNodeFlags), wbUnknown(XNAM), wbString(ENAM, 'Type', 4) ], False, nil, cpNormal, False, nil, wbConditionsAfterSet); end; procedure DefineTES5j; begin wbRecord(DLBR, 'Dialog Branch', [ wbEDID, wbFormIDCk(QNAM, 'Quest', [QUST], False, cpNormal, True), wbInteger(TNAM, 'Unknown', itU32), wbInteger(DNAM, 'Flags', itU32, wbFlags([ {0x01} 'Top-Level', {0x02} 'Blocking', {0x04} 'Exclusive' ])), wbFormIDCk(SNAM, 'Starting Topic', [DIAL], False, cpNormal, True) ]); wbRecord(MUST, 'Music Track', [ wbEDID, wbInteger(CNAM, 'Track Type', itU32, wbEnum([], [ Int64($23F678C3), 'Palette', Int64($6ED7E048), 'Single Track', Int64($A1A9C4D5), 'Silent Track' ]), cpNormal, True), wbFloat(FLTV, 'Duration'), wbFloat(DNAM, 'Fade-Out'), wbString(ANAM, 'Track Filename'), wbString(BNAM, 'Finale Filename'), wbArray(FNAM, 'Cue Points', wbFloat('Point')), wbStruct(LNAM, 'Loop Data', [ wbFloat('Loop Begins'), wbFloat('Loop Ends'), wbInteger('Loop Count', itU32) ]), wbCITC, wbCTDAsCount, wbArray(SNAM, 'Tracks', wbFormIDCk('Track', [MUST, NULL])) ], False, nil, cpNormal, False, nil, wbConditionsAfterSet); wbRecord(DLVW, 'Dialog View', [ wbEDID, wbFormIDCk(QNAM, 'Quest', [QUST], False, cpNormal, True), wbRArray('Branches', wbFormIDCk(BNAM, 'Branch', [DLBR])), wbRArray('Unknown TNAM', wbRStruct('Unknown', [ wbUnknown(TNAM) ], [])), wbUnknown(ENAM), wbUnknown(DNAM) ]); wbRecord(WOOP, 'Word of Power', [ wbEDID, wbFULL, wbLString(TNAM, 'Translation', 0, cpTranslate, True) ]); wbRecord(SHOU, 'Shout', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000080} 7, 'Treat spells as powers' ])), [ wbEDID, wbFULL, wbMDOB, wbDESC, {>>> Don't sort <<<} wbRArray('Words of Power', wbStruct(SNAM, '', [ wbFormIDCk('Word', [WOOP, NULL]), wbFormIDCk('Spell', [SPEL, NULL]), wbFloat('Recovery Time') ]) ) ]); wbRecord(EQUP, 'Equip Type', [ wbEDID, wbArray(PNAM, 'Slot Parents', wbFormID('Can Be Equipped'), 0, nil, nil, cpNormal, False), wbInteger(DATA, 'Use All Parents', itU32, wbEnum(['False', 'True'])) ]); wbRecord(RELA, 'Relationship', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000040} 6, 'Secret' ])), [ wbEDID, wbStruct(DATA, 'Data', [ wbFormIDCk('Parent', [NPC_, NULL]), wbFormIDCk('Child', [NPC_, NULL]), wbInteger('Rank', itU16, wbEnum([ 'Lover', 'Ally', 'Confidant', 'Friend', 'Acquaitance', 'Rival', 'Foe', 'Enemy', 'Archnemesis' ])), wbByteArray('Unknown', 1), wbInteger('Flags', itU8, wbFlags([ {0x01} 'Unknown 1', {0x02} 'Unknown 2', {0x04} 'Unknown 3', {0x08} 'Unknown 4', {0x10} 'Unknown 5', {0x20} 'Unknown 6', {0x40} 'Unknown 7', {0x80} 'Secret' ])), wbFormIDCk('Association Type', [ASTP, NULL]) ]) ]); wbRecord(SCEN, 'Scene', [ wbEDID, wbVMADFragmentedSCEN, wbInteger(FNAM, 'Flags', itU32, wbFlags([ 'Begin on Quest Start', 'Stop on Quest End', 'Unknown 3', 'Repeat Conditions While True', 'Interruptible' ])), wbRArray('Phases', wbRStruct('Phase', [ wbEmpty(HNAM, 'Marker Phase Start'), wbString(NAM0, 'Name'), // CTDA before or after next //wbEmpty(NEXT, 'Marker'), wbRStruct('Start Conditions', [wbCTDAs], []), wbEmpty(NEXT, 'Marker'), wbRStruct('Completion Conditions', [wbCTDAs], []), {>>> BEGIN leftover from earlier CK versions <<<} wbRStruct('Unused', [ wbUnknown(SCHR), wbUnknown(SCDA), wbUnknown(SCTX), wbUnknown(QNAM), wbUnknown(SCRO) ], [], cpIgnore, false, wbNeverShow), wbEmpty(NEXT, 'Marker'), wbRStruct('Unused', [ wbUnknown(SCHR), wbUnknown(SCDA), wbUnknown(SCTX), wbUnknown(QNAM), wbUnknown(SCRO) ], [], cpIgnore, false, wbNeverShow), {>>> END leftover from earlier CK versions begin <<<} wbInteger(WNAM, 'Editor Width', itU32), wbEmpty(HNAM, 'Marker Phase End') ], []) ), wbRArray('Actors', wbRStruct('Actor', [ wbInteger(ALID, 'Actor ID', itU32), wbInteger(LNAM, 'Flags', itU32, wbFlags([ 'No Player Activation', 'Optional' ])), wbInteger(DNAM, 'Behaviour Flags', itU32, wbFlags([ 'Death Pause (unsused)', 'Death End', 'Combat Pause', 'Combat End', 'Dialogue Pause', 'Dialogue End', 'OBS_COM Pause', 'OBS_COM End' ])) ], [])), wbRArray('Actions', wbRStruct('Action', [ wbInteger(ANAM, 'Type', itU16, wbEnum([ 'Dialogue', 'Package', 'Timer' ])), wbString(NAM0, 'Name'), wbInteger(ALID, 'Actor ID', itS32), wbUnknown(LNAM), wbInteger(INAM, 'Index', itU32), wbInteger(FNAM, 'Flags', itU32, wbFlags([ {0x00000001} 'Unknown 1', {0x00000002} 'Unknown 2', {0x00000004} 'Unknown 3', {0x00000008} 'Unknown 4', {0x00000010} 'Unknown 5', {0x00000020} 'Unknown 6', {0x00000040} 'Unknown 7', {0x00000080} 'Unknown 8', {0x00000100} 'Unknown 9', {0x00000200} 'Unknown 10', {0x00000400} 'Unknown 11', {0x00000800} 'Unknown 12', {0x00001000} 'Unknown 13', {0x00002000} 'Unknown 14', {0x00004000} 'Unknown 15', {0x00008000} 'Face Target', {0x00010000} 'Looping', {0x00020000} 'Headtrack Player' ])), wbInteger(SNAM, 'Start Phase', itU32), wbInteger(ENAM, 'End Phase', itU32), wbFloat(SNAM, 'Timer Seconds'), wbRArray('Packages', wbFormIDCk(PNAM, 'Package', [PACK])), wbFormIDCk(DATA, 'Topic', [DIAL, NULL]), wbInteger(HTID, 'Headtrack Actor ID', itS32), wbFloat(DMAX, 'Looping - Max'), wbFloat(DMIN, 'Looping - Min'), wbInteger(DEMO, 'Emotion Type', itU32, wbEmotionTypeEnum), wbInteger(DEVA, 'Emotion Value', itU32), {>>> BEGIN leftover from earlier CK versions <<<} wbRStruct('Unused', [ wbUnknown(SCHR), wbUnknown(SCDA), wbUnknown(SCTX), wbUnknown(QNAM), wbUnknown(SCRO) ], [], cpIgnore, false, wbNeverShow), {>>> END leftover from earlier CK versions <<<} wbEmpty(ANAM, 'End Marker') ], [])), {>>> BEGIN leftover from earlier CK versions <<<} wbRStruct('Unused', [ wbUnknown(SCHR), wbUnknown(SCDA), wbUnknown(SCTX), wbUnknown(QNAM), wbUnknown(SCRO) ], [], cpIgnore, false, wbNeverShow), wbEmpty(NEXT, 'Marker'), wbRStruct('Unused', [ wbUnknown(SCHR), wbUnknown(SCDA), wbUnknown(SCTX), wbUnknown(QNAM), wbUnknown(SCRO) ], [], cpIgnore, false, wbNeverShow), {>>> END leftover from earlier CK versions <<<} wbFormIDCk(PNAM, 'Quest', [QUST]), wbInteger(INAM, 'Last Action Index', itU32), wbUnknown(VNAM), wbCTDAs ]); wbRecord(ASTP, 'Association Type', [ wbEDID, wbString(MPRT, 'Male Parent Title'), wbString(FPRT, 'Female Parent Title'), wbString(MCHT, 'Male Child Title'), wbString(FCHT, 'Female Child Title'), wbInteger(DATA, 'Flags', itU32, wbFlags([ 'Family Association' ])) ]); end; procedure DefineTES5k; begin wbRecord(OTFT, 'Outfit', [ wbEDID, wbArrayS(INAM, 'Items', wbFormIDCk('Item', [ARMO, LVLI])) ]); wbRecord(ARTO, 'Art Object', [ wbEDID, wbOBNDReq, wbMODL, wbInteger(DNAM, 'Art Type', itU32, wbEnum([ 'Magic Casting', 'Magic Hit Effect', 'Enchantment Effect' ])) ]); wbRecord(MATO, 'Material Object', [ wbEDID, wbMODL, wbRArray('Property Data', wbByteArray(DNAM, 'Data', 0, cpIgnore, False, False, wbNeverShow) ), IsSSE( wbStruct(DATA, 'Directional Material Data', [ wbFloat('Falloff Scale'), wbFloat('Falloff Bias'), wbFloat('Noise UV Scale'), wbFloat('Material UV Scale'), wbStruct('Projection Vector', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), wbFloat('Normal Dampener'), wbFloatColors('Single Pass Color'), wbInteger('Flags', itU32, wbFlags(['Single Pass'])), // SSE wbInteger('Flags', itU8, wbFlags([ {0x01} 'Snow' ])), wbByteArray('Unused', 3, cpIgnore) ], cpNormal, True, nil, 5), wbStruct(DATA, 'Directional Material Data', [ wbFloat('Falloff Scale'), wbFloat('Falloff Bias'), wbFloat('Noise UV Scale'), wbFloat('Material UV Scale'), wbStruct('Projection Vector', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), wbFloat('Normal Dampener'), wbFloatColors('Single Pass Color'), wbInteger('Flags', itU32, wbFlags(['Single Pass'])) ], cpNormal, True, nil, 5) ) ]); wbRecord(MOVT, 'Movement Type', [ wbEDID, wbString(MNAM, 'Name'), wbStruct(SPED, 'Default Data', [ wbFloat('Left Walk'), wbFloat('Left Run'), wbFloat('Right Walk'), wbFloat('Right Run'), wbFloat('Forward Walk'), wbFloat('Forward Run'), wbFloat('Back Walk'), wbFloat('Back Run'), wbFloat('Rotate in Place Walk', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Rotate in Place Run', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize), wbFloat('Rotate while Moving Run', cpNormal, True, wbRotationFactor, wbRotationScale, nil, RadiansNormalize) ], cpNormal, True, nil, 10), wbStruct(INAM, 'Anim Change Thresholds', [ wbFloat('Directional', cpNormal, True, 180/Pi), wbFloat('Movement Speed'), wbFloat('Rotation Speed', cpNormal, True, 180/Pi) ]) ]); wbRecord(SNDR, 'Sound Descriptor', [ wbEDID, wbUnknown(CNAM), wbFormID(GNAM, 'Category'), wbFormIDCk(SNAM, 'Alternate Sound For', [SNDR, NULL]), wbRArray('Sounds', wbRStruct('Sound Files', [ wbString(ANAM, 'File Name') ],[]) ), wbFormIDCk(ONAM, 'Output Model', [SOPM, NULL]), wbLString(FNAM, 'String', 0, cpIgnore), wbCTDAs, wbStruct(LNAM, 'Values', [ wbByteArray('Unknown', 1), wbInteger('Looping', itU8, wbEnum([], [ $00 , 'None', $08 , 'Loop', $10 , 'Envelope Fast', $20 , 'Envelope Slow' ])), wbByteArray('Unknown', 1), wbInteger('Rumble Send Value = (Small / 7) + ((Big / 7) * 16)', itU8) ]), wbStruct(BNAM, 'Values', [ wbInteger('% Frequency Shift', itS8), wbInteger('% Frequency Variance', itS8), wbInteger('Priority', itU8), wbInteger('db Variance', itU8), wbInteger('Static Attenuation (db)', itU16, wbDiv(100)) ]) ]); wbRecord(DUAL, 'Dual Cast Data', [ wbEDID, wbOBNDReq, wbStruct(DATA, 'Data', [ wbFormIDCk('Projectile', [PROJ, NULL]), wbFormIDCk('Explosion', [EXPL, NULL]), wbFormIDCk('Effect Shader', [EFSH, NULL]), wbFormIDCk('Hit Effect Art', [ARTO, NULL]), wbFormIDCk('Impact Data Set', [IPDS, NULL]), wbInteger('Inherit Scale', itU32, wbFlags([ 'Hit Effect Art', 'Projectile', 'Explosion' ])) ], cpNormal, True) ]); wbRecord(SNCT, 'Sound Category', [ wbEDID, wbFULL, wbInteger(FNAM, 'Flags', itU32, wbFlags([ 'Mute When Submerged', 'Should Appear on Menu' ]), cpNormal, True), wbFormIDCk(PNAM, 'Parent', [SNCT]), wbInteger(VNAM, 'Static Volume Multiplier', itU16, wbDiv(65535)), wbInteger(UNAM, 'Default Menu Value', itU16, wbDiv(65535)) ]); wbRecord(SOPM, 'Sound Output Model', [ wbEDID, wbStruct(NAM1, 'Data', [ wbInteger('Flags', itU8, wbFlags([ 'Attenuates With Distance', 'Allows Rumble' ])), wbByteArray('Unknown', 2), wbInteger('Reverb Send %', itU8) ]), wbUnknown(FNAM), // leftover, unused wbInteger(MNAM, 'Type', itU32, wbEnum([ 'Uses HRTF', 'Defined Speaker Output' ])), wbUnknown(CNAM), // leftover, unused wbUnknown(SNAM), // leftover, unused wbStruct(ONAM, 'Output Values', [ wbArray('Channels', wbStruct('', [ wbInteger('L', itU8), wbInteger('R', itU8), wbInteger('C', itU8), wbInteger('LFE', itU8), wbInteger('RL', itU8), wbInteger('RR', itU8), wbInteger('BL', itU8), wbInteger('BR', itU8) ]), [ 'Channel 0', 'Channel 1', 'Channel 2? (unused)' ]) ]), wbStruct(ANAM, 'Attenuation Values', [ wbByteArray('Unknown', 4), wbFloat('Min Distance'), wbFloat('Max Distance'), wbArray('Curve', wbInteger('Value', itU8), 5), wbByteArray('Unknown') ]) ]); wbRecord(COLL, 'Collision Layer', [ wbEDID, wbDESCReq, wbInteger(BNAM, 'Index', itU32, nil, cpNormal, True), wbStruct(FNAM, 'Debug Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbInteger('Unused', itU8) ], cpNormal, True), wbInteger(GNAM, 'Flags', itU32, wbFlags([ {0x00000001} 'Trigger Volume', {0x00000002} 'Sensor', {0x00000004} 'Navmesh Obstacle' ]), cpNormal, True), wbString(MNAM, 'Name', 0, cpNormal, True), wbInteger(INTV, 'Interactables Count', itU32, nil, cpNormal, True), wbArrayS(CNAM, 'Collides With', wbFormIDCk('Forms', [COLL]), 0, cpNormal, False) ]); wbRecord(CLFM, 'Color', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000004} 2, 'Non-Playable' ])), [ wbEDID, wbFULL, wbCNAMReq, wbInteger(FNAM, 'Playable', itU32, wbEnum(['False', 'True']), cpNormal, True) ]); end; procedure DefineTES5l; begin wbRecord(REVB, 'Reverb Parameters', [ wbEDID, wbStruct(DATA, 'Data', [ wbInteger('Decay Time (ms)', itU16), wbInteger('HF Reference (Hz)', itU16), wbInteger('Room Filter', itS8), wbInteger('Room HF Filter', itS8), wbInteger('Reflections', itS8), wbInteger('Reverb Amp', itS8), wbInteger('Decay HF Ratio', itU8, wbDiv(100)), wbInteger('Reflect Delay (ms), scaled', itU8), wbInteger('Reverb Delay (ms)', itU8), wbInteger('Diffusion %', itU8), wbInteger('Density %', itU8), wbInteger('Unknown', itU8) ], cpNormal, True) ]); wbRecord(GRAS, 'Grass', [ wbEDID, wbOBNDReq, wbMODL, wbStruct(DATA, '', [ wbInteger('Density', itU8), wbInteger('Min Slope', itU8), wbInteger('Max Slope', itU8), wbByteArray('Unknown', 1), wbInteger('Units From Water', itU16), wbByteArray('Unknown', 2), wbInteger('Units From Water Type', itU32, wbEnum([ 'Above - At Least', 'Above - At Most', 'Below - At Least', 'Below - At Most', 'Either - At Least', 'Either - At Most', 'Either - At Most Above', 'Either - At Most Below' ])), wbFloat('Position Range'), wbFloat('Height Range'), wbFloat('Color Range'), wbFloat('Wave Period'), wbInteger('Flags', itU8, wbFlags([ 'Vertex Lighting', 'Uniform Scaling', 'Fit to Slope' ])), wbByteArray('Unknown', 3) ], cpNormal, True) ]); wbRecord(IDLE, 'Idle Animation', [ wbEDID, wbCTDAs, wbString(DNAM, 'Filename'), wbString(ENAM, 'Animation Event'), wbArray(ANAM, 'Related Idle Animations', wbFormIDCk('Related Idle Animation', [AACT, IDLE, NULL]), ['Parent', 'Previous Sibling'], cpNormal, True), wbStruct(DATA, 'Data (unused)', [ wbStruct('Looping seconds (both 255 forever)', [ wbInteger('Min', itU8), wbInteger('Max', itU8) ]), wbInteger('Flags', itU8, wbFlags([ {0x01} 'Parent', {0x02} 'Sequence', {0x04} 'No Attacking', {0x04} 'Blocking' ], True)), wbInteger('Animation Group Section', itU8{, wbIdleAnam}), wbInteger('Replay Delay', itU16) ], cpIgnore, True) ]); wbRecord(INFO, 'Dialog response', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00002000} 13, 'Actor Changed' ])), [ wbEDID, wbVMADFragmentedINFO, wbUnknown(DATA), wbStruct(ENAM, 'Response flags', [ wbInteger('Flags', itU16, wbFlags([ {0x0001} 'Goodbye', {0x0002} 'Random', {0x0004} 'Say once', {0x0008} 'Unknown 4', {0x0010} 'Unknown 5', {0x0020} 'Random end', {0x0040} 'Invisible continue', {0x0080} 'Walk Away', {0x0100} 'Walk Away Invisible in Menu', {0x0200} 'Force subtitle', {0x0400} 'Can move while greeting', {0x0800} 'No LIP File', {0x1000} 'Requires post-processing', {0x2000} 'Audio Output Override', {0x4000} 'Spends favor points', {0x8000} 'Unknown 16' ])), wbInteger('Reset Hours', itU16, wbDiv(2730)) ]), wbFormIDCk(TPIC, 'Topic', [DIAL]), wbFormIDCkNoReach(PNAM, 'Previous INFO', [INFO, NULL], False, cpBenign), wbInteger(CNAM, 'Favor Level', itU8, wbEnum([ 'None', 'Small', 'Medium', 'Large' ])), wbRArray('Link To', wbFormIDCk(TCLT, 'Response', [DIAL, INFO, NULL])), wbFormID(DNAM, 'Response Data'), wbRArray('Responses', wbRStruct('Response', [ wbStruct(TRDT, 'Response Data', [ wbInteger('Emotion Type', itU32, wbEmotionTypeEnum), wbInteger('Emotion Value', itU32), wbByteArray('Unused', 4), wbInteger('Response number', itU8), wbByteArray('Unused', 3), wbFormIDCk('Sound', [SNDR, NULL]), wbInteger('Flags', itU8, wbFlags([ 'Use Emotion Animation' ])), wbByteArray('Unused', 3) ]), wbLStringKC(NAM1, 'Response Text', 0, cpTranslate), wbString(NAM2, 'Script Notes'), wbString(NAM3, 'Edits'), wbFormIDCk(SNAM, 'Idle Animations: Speaker', [IDLE]), wbFormIDCk(LNAM, 'Idle Animations: Listener', [IDLE]) ], [])), wbCTDAs, {>>> BEGIN leftover from earlier CK versions <<<} wbRArray('Unknown', wbRStruct('Unknown', [ wbUnknown(SCHR), wbFormID(QNAM, 'Unknown'), wbEmpty(NEXT, 'Marker') ], []), cpIgnore, false, nil, nil, wbNeverShow ), {>>> END leftover from earlier CK versions <<<} wbLString(RNAM, 'Prompt', 0, cpTranslate), wbFormIDCk(ANAM, 'Speaker', [NPC_]), wbFormIDCk(TWAT, 'Walk Away Topic', [DIAL]), wbFormIDCk(ONAM, 'Audio Output Override', [SOPM]) ], False, wbINFOAddInfo, cpNormal, False, nil{wbINFOAfterLoad}); wbRecord(INGR, 'Ingredient', [ wbEDID, wbVMAD, wbOBNDReq, wbFULL, wbKSIZ, wbKWDAs, wbMODL, wbICON, wbDEST, wbETYP, wbYNAM, wbZNAM, wbStruct(DATA, '', [ wbInteger('Value', itS32), wbFloat('Weight') ], cpNormal, True), wbStruct(ENIT, 'Effect Data', [ wbInteger('Ingredient Value', itS32), wbInteger('Flags', itU32, wbFlags([ {0x00000001} 'No auto-calculation', {0x00000002} 'Food item', {0x00000004} 'Unknown 3', {0x00000008} 'Unknown 4', {0x00000010} 'Unknown 5', {0x00000020} 'Unknown 6', {0x00000040} 'Unknown 7', {0x00000080} 'Unknown 8', {0x00000100} 'References Persist' ])) ], cpNormal, True), wbEffectsReq ], False, nil, cpNormal, False, nil, wbKeywordsAfterSet); wbRecord(KEYM, 'Key', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000004} 2, 'Non-Playable' ])), [ wbEDID, wbVMAD, wbOBNDReq, wbFULLReq, wbMODL, wbICON, wbDEST, wbYNAM, wbZNAM, wbKSIZ, wbKWDAs, wbStruct(DATA, '', [ wbInteger('Value', itS32), wbFloat('Weight') ], cpNormal, True) ], False, nil, cpNormal, False, nil, wbKeywordsAfterSet); wbQuadrantEnum := wbEnum([ {0} 'Bottom Left', {1} 'Bottom Right', {2} 'Top Left', {3} 'Top Right' ]); if wbSimpleRecords then begin wbRecord(LAND, 'Landscape', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00040000} 18, 'Compressed' ]), [18]), [ wbByteArray(DATA, 'Unknown'), wbByteArray(VNML, 'Vertex Normals'), wbByteArray(VHGT, 'Vertext Height Map'), wbByteArray(VCLR, 'Vertex Colours'), wbRArrayS('Layers', wbRUnion('Layer', [ wbRStructSK([0],'Base Layer', [ wbStructSK(BTXT, [1, 3], 'Base Layer Header', [ wbFormIDCk('Texture', [LTEX, NULL]), wbInteger('Quadrant', itU8, wbQuadrantEnum), wbByteArray('Unknown', 1), wbInteger('Layer', itS16) ]) ], []), wbRStructSK([0],'Alpha Layer', [ wbStructSK(ATXT, [1, 3], 'Alpha Layer Header', [ wbFormIDCk('Texture', [LTEX, NULL]), wbInteger('Quadrant', itU8, wbQuadrantEnum), wbByteArray('Unknown', 1), wbInteger('Layer', itS16) ]), wbByteArray(VTXT, 'Alpha Layer Data') ], []) ], [])), wbArray(VTEX, 'Textures', wbFormIDCk('Texture', [LTEX, NULL])) ]); end else begin wbRecord(LAND, 'Landscape', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00040000} 18, 'Compressed' ]), [18]), [ wbByteArray(DATA, 'Unknown'), wbArray(VNML, 'Vertex Normals', wbStruct('Row', [ wbArray('Columns', wbStruct('Column', [ wbInteger('X', itU8), wbInteger('Y', itU8), wbInteger('Z', itU8) ]), 33) ]), 33), wbStruct(VHGT, 'Vertext Height Map', [ wbFloat('Offset'), wbArray('Rows', wbStruct('Row', [ wbArray('Columns', wbInteger('Column', itU8), 33) ]), 33), wbByteArray('Unknown', 3) ]), wbArray(VCLR, 'Vertex Colours', wbStruct('Row', [ wbArray('Columns', wbStruct('Column', [ wbInteger('X', itU8), wbInteger('Y', itU8), wbInteger('Z', itU8) ]), 33) ]), 33), wbRArrayS('Layers', wbRUnion('Layer', [ wbRStructSK([0],'Base Layer', [ wbStructSK(BTXT, [1, 3], 'Base Layer Header', [ wbFormIDCk('Texture', [LTEX, NULL]), wbInteger('Quadrant', itU8, wbQuadrantEnum), wbByteArray('Unknown', 1), wbInteger('Layer', itS16) ]) ], []), wbRStructSK([0],'Alpha Layer', [ wbStructSK(ATXT, [1, 3], 'Alpha Layer Header', [ wbFormIDCk('Texture', [LTEX, NULL]), wbInteger('Quadrant', itU8, wbQuadrantEnum), wbByteArray('Unknown', 1), wbInteger('Layer', itS16) ]), wbArrayS(VTXT, 'Alpha Layer Data', wbStructSK([0], 'Cell', [ wbInteger('Position', itU16, wbAtxtPosition), wbByteArray('Unknown', 2), wbFloat('Opacity') ])) ], []) ], [])), wbArray(VTEX, 'Textures', wbFormIDCk('Texture', [LTEX, NULL])) ]); end; wbRecord(LIGH, 'Light', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00010000} 16, 'Random Anim Start', {0x00020000} 17, 'Portal-strict', {0x02000000} 25, 'Obstacle' ])), [ wbEDID, wbVMAD, wbOBNDReq, wbMODL, wbDEST, wbFULL, wbICON, wbStruct(DATA, '', [ wbInteger('Time', itS32), wbInteger('Radius', itU32), wbByteColors, wbInteger('Flags', itU32, wbFlags([ {0x00000001} 'Dynamic', {0x00000002} 'Can be Carried', {0x00000004} 'Negative', {0x00000008} 'Flicker', {0x00000010} 'Unknown', {0x00000020} 'Off By Default', {0x00000040} 'Flicker Slow', {0x00000080} 'Pulse', {0x00000100} 'Pulse Slow', {0x00000200} 'Spot Light', {0x00000400} 'Shadow Spotlight', {0x00000800} 'Shadow Hemisphere', {0x00001000} 'Shadow Omnidirectional', {0x00002000} 'Portal-strict' ])), wbFloat('Falloff Exponent'), wbFloat('FOV'), wbFloat('Near Clip'), wbStruct('Flicker Effect', [ wbFloat('Period', cpNormal, False, 0.01), wbFloat('Intensity Amplitude'), wbFloat('Movement Amplitude') ]), wbInteger('Value', itU32), wbFloat('Weight') ], cpNormal, True), wbFloat(FNAM, 'Fade value', cpNormal, True), wbFormIDCk(SNAM, 'Sound', [SNDR]) ], False, nil, cpNormal, False, wbLIGHAfterLoad); end; procedure DefineTES5m; begin wbRecord(LSCR, 'Load Screen', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000400} 10, 'Displays In Main Menu' ])), [ wbEDID, wbICON, wbDESCReq, wbCTDAs, wbFormIDCk(NNAM, 'Loading Screen NIF', [STAT, NULL], False, cpNormal, True), wbFloat(SNAM, 'Initial Scale'), wbStruct(RNAM, 'Initial Rotation', [ wbInteger('X', itS16), wbInteger('Y', itS16), wbInteger('Z', itS16) ]), wbStruct(ONAM, 'Rotation Offset Constraints', [ wbInteger('Min', itS16), wbInteger('Max', itS16) ]), wbStruct(XNAM, 'Initial Translation Offset', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), wbString(MOD2, 'Camera Path', 0, cpNormal, False) ]); wbRecord(LTEX, 'Landscape Texture', [ wbEDID, wbFormIDCk(TNAM, 'Texture Set', [TXST], False, cpNormal, False), wbFormIDCk(MNAM, 'Material Type', [MATT, NULL], False, cpNormal, True), wbStruct(HNAM, 'Havok Data', [ wbInteger('Friction', itU8), wbInteger('Restitution', itU8) ], cpNormal, True), wbInteger(SNAM, 'Texture Specular Exponent', itU8, nil, cpNormal, True), wbRArrayS('Grasses', wbFormIDCk(GNAM, 'Grass', [GRAS])), // SSE wbInteger(INAM, IsSSE('Flags', 'Unused'), itU32, wbFlags([ {0x01} 'Is Snow' ])) ]); wbRecord(LVLN, 'Leveled NPC', [ wbEDID, wbOBNDReq, wbLVLD, wbInteger(LVLF, 'Flags', itU8, wbFlags([ {0x01} 'Calculate from all levels <= player''s level', {0x02} 'Calculate for each item in count' ]), cpNormal, True), wbFormIDCk(LVLG, 'Global', [GLOB]), wbLLCT, wbRArrayS('Leveled List Entries', wbRStructExSK([0], [1], 'Leveled List Entry', [ wbStructExSK(LVLO , [0, 2], [3], 'Base Data', [ wbInteger('Level', itS16), wbByteArray('Unknown', 2, cpIgnore, false, wbNeverShow), wbFormIDCk('Reference', [NPC_, LVLN]), wbInteger('Count', itS16), wbByteArray('Unknown', 2, cpIgnore, false, wbNeverShow) ]), wbCOED ], []), cpNormal, False, nil, wbLVLOsAfterSet), wbMODL ], False, nil, cpNormal, False, nil, wbLLEAfterSet); wbRecord(LVLI, 'Leveled Item', [ wbEDID, wbOBNDReq, wbLVLD, wbInteger(LVLF, 'Flags', itU8, wbFlags([ {0x01} 'Calculate from all levels <= player''s level', {0x02} 'Calculate for each item in count', {0x04} 'Use All', {0x08} 'Special Loot' ]), cpNormal, True), wbFormIDCk(LVLG, 'Global', [GLOB]), wbLLCT, wbRArrayS('Leveled List Entries', wbRStructExSK([0], [1], 'Leveled List Entry', [ wbStructExSK(LVLO , [0, 2], [3], 'Base Data', [ wbInteger('Level', itU16), wbByteArray('Unknown', 2, cpIgnore, false, wbNeverShow), wbFormIDCk('Reference', [ARMO, AMMO, APPA, MISC, WEAP, BOOK, LVLI, KEYM, ALCH, LIGH, INGR, SLGM, SCRL]), wbInteger('Count', itU16), wbByteArray('Unknown', 2, cpIgnore, false, wbNeverShow) ]), wbCOED ], []), cpNormal, False, nil, wbLVLOsAfterSet ) ], False, nil, cpNormal, False, nil, wbLLEAfterSet); wbRecord(LVSP, 'Leveled Spell', [ wbEDID, wbOBNDReq, wbLVLD, wbInteger(LVLF, 'Flags', itU8, wbFlags([ {0x01} 'Calculate from all levels <= player''s level', {0x02} 'Calculate for each item in count', {0x04} 'Use All Spells' ]), cpNormal, True), wbLLCT, wbRArrayS('Leveled List Entries', wbRStructSK([0], 'Leveled List Entry', [ wbStructExSK(LVLO , [0, 2], [3], 'Base Data', [ wbInteger('Level', itU16), wbByteArray('Unknown', 2, cpIgnore, false, wbNeverShow), wbFormIDCk('Reference', [SPEL, LVSP]), wbInteger('Count', itU16), wbByteArray('Unknown', 2, cpIgnore, false, wbNeverShow) ]) ], []), cpNormal, False, nil, wbLVLOsAfterSet ) ], False, nil, cpNormal, False, nil, wbLLEAfterSet); wbMGEFType := wbInteger('Archtype', itU32, wbEnum([ {00} 'Value Modifier', {01} 'Script', {02} 'Dispel', {03} 'Cure Disease', {04} 'Absorb', {05} 'Dual Value Modifier', {06} 'Calm', {07} 'Demoralize', {08} 'Frenzy', {09} 'Disarm', {10} 'Command Summoned', {11} 'Invisibility', {12} 'Light', {13} 'Unknown 13', {14} 'Unknown 14', {15} 'Lock', {16} 'Open', {17} 'Bound Weapon', {18} 'Summon Creature', {19} 'Detect Life', {20} 'Telekinesis', {21} 'Paralysis', {22} 'Reanimate', {23} 'Soul Trap', {24} 'Turn Undead', {25} 'Guide', {26} 'Werewolf Feed', {27} 'Cure Paralysis', {28} 'Cure Addiction', {29} 'Cure Poison', {30} 'Concussion', {31} 'Value and Parts', {32} 'Accumulate Magnitude', {33} 'Stagger', {34} 'Peak Value Modifier', {35} 'Cloak', {36} 'Werewolf', {37} 'Slow Time', {38} 'Rally', {39} 'Enhance Weapon', {40} 'Spawn Hazard', {41} 'Etherealize', {42} 'Banish', {43} 'Spawn Scripted Ref', {44} 'Disguise', {45} 'Grab Actor', {46} 'Vampire Lord' ]), cpNormal, False, nil, wbMGEFArchtypeAfterSet); wbMGEFData := wbRStruct('Magic Effect Data', [ wbStruct(DATA, 'Data', [ wbInteger('Flags', itU32, wbFlags([ {0x00000001} 'Hostile', {0x00000002} 'Recover', {0x00000004} 'Detrimental', {0x00000008} 'Snap to Navmesh', {0x00000010} 'No Hit Event', {0x00000020} 'Unknown 6', {0x00000040} 'Unknown 7', {0x00000080} 'Unknown 8', {0x00000100} 'Dispel with Keywords', {0x00000200} 'No Duration', {0x00000400} 'No Magnitude', {0x00000800} 'No Area', {0x00001000} 'FX Persist', {0x00002000} 'Unknown 14', {0x00004000} 'Gory Visuals', {0x00008000} 'Hide in UI', {0x00010000} 'Unknown 17', {0x00020000} 'No Recast', {0x00040000} 'Unknown 19', {0x00080000} 'Unknown 20', {0x00100000} 'Unknown 21', {0x00200000} 'Power Affects Magnitude', {0x00400000} 'Power Affects Duration', {0x00800000} 'Unknown 24', {0x01000000} 'Unknown 25', {0x02000000} 'Unknown 26', {0x04000000} 'Painless', {0x08000000} 'No Hit Effect', {0x10000000} 'No Death Dispel', {0x20000000} 'Unknown 30', {0x40000000} 'Unknown 31', {0x80000000} 'Unknown 32' ])), wbFloat('Base Cost'), wbUnion('Assoc. Item', wbMGEFAssocItemDecider, [ wbFormID('Unused', cpIgnore), wbFormIDCk('Assoc. Item', [LIGH, NULL]), wbFormIDCk('Assoc. Item', [WEAP, ARMO, NULL]), wbFormIDCk('Assoc. Item', [NPC_, NULL]), wbFormIDCk('Assoc. Item', [HAZD, NULL]), wbFormIDCk('Assoc. Item', [SPEL, NULL]), wbFormIDCk('Assoc. Item', [RACE, NULL]), wbFormIDCk('Assoc. Item', [ENCH, NULL]), wbFormIDCk('Assoc. Item', [KYWD, NULL]) ], cpNormal, False, nil, wbMGEFAssocItemAfterSet), wbInteger('Magic Skill', itS32, wbActorValueEnum), wbInteger('Resist Value', itS32, wbActorValueEnum), wbInteger('Counter Effect count', itU16), wbByteArray('Unused', 2), wbFormIDCk('Casting Light', [LIGH, NULL]), wbFloat('Taper Weight'), wbFormIDCk('Hit Shader', [EFSH, NULL]), wbFormIDCk('Enchant Shader', [EFSH, NULL]), wbInteger('Minimum Skill Level', itU32), wbStruct('Spellmaking', [ wbInteger('Area', itU32), wbFloat('Casting Time') ]), wbFloat('Taper Curve'), wbFloat('Taper Duration'), wbFloat('Second AV Weight', cpNormal, False, nil, wbMGEFAV2WeightAfterSet), wbMGEFType, wbActorValue, wbFormIDCk('Projectile', [PROJ, NULL]), wbFormIDCk('Explosion', [EXPL, NULL]), wbInteger('Casting Type', itU32, wbCastEnum), wbInteger('Delivery', itU32, wbTargetEnum), wbInteger('Second Actor Value', itS32, wbActorValueEnum), wbFormIDCk('Casting Art', [ARTO, NULL]), wbFormIDCk('Hit Effect Art', [ARTO, NULL]), wbFormIDCk('Impact Data', [IPDS, NULL]), wbFloat('Skill Usage Multiplier'), wbStruct('Dual Casting', [ wbFormIDCk('Art', [DUAL, NULL]), wbFloat('Scale') ]), wbFormIDCk('Enchant Art', [ARTO, NULL]), wbByteArray('Unknown', 4), wbByteArray('Unknown', 4), wbFormIDCk('Equip Ability', [SPEL, NULL]), wbFormIDCk('Image Space Modifier', [IMAD, NULL]), wbFormIDCk('Perk to Apply', [PERK, NULL]), wbInteger('Casting Sound Level', itU32, wbSoundLevelEnum), wbStruct('Script Effect AI', [ wbFloat('Score'), wbFloat('Delay Time') ]) ], cpNormal, True) ], []); wbRecord(MGEF, 'Magic Effect', [ wbEDID, wbVMAD, wbFULL, wbMDOB, wbKSIZ, wbKWDAs, wbMGEFData, wbRArrayS('Counter Effects', wbFormIDCk(ESCE, 'Effect', [MGEF]), cpNormal, False, nil, wbCounterEffectsAfterSet), wbArray(SNDD, 'Sounds', wbStruct('', [ wbInteger('Type', itU32, wbEnum([ 'Sheathe/Draw', 'Charge', 'Ready', 'Release', 'Concentration Cast Loop', 'On Hit' ])), wbFormIDCk('Sound', [SNDR]) ])), wbLStringKC(DNAM, 'Magic Item Description', 0, cpTranslate), wbCTDAs ], False, nil, cpNormal, False, nil {wbMGEFAfterLoad}, wbMGEFAfterSet); wbRecord(MISC, 'Misc. Item', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000004} 2, 'Non-Playable' ])), [ wbEDID, wbVMAD, wbOBNDReq, wbFULL, wbMODL, wbICON, wbDEST, wbYNAM, wbZNAM, wbKSIZ, wbKWDAs, wbStruct(DATA, 'Data', [ wbInteger('Value', itS32), wbFloat('Weight') ], cpNormal, True) ], False, nil, cpNormal, False, wbRemoveEmptyKWDA, wbKeywordsAfterSet); wbRecord(APPA, 'Alchemical Apparatus', [ wbEDID, wbVMAD, wbOBNDReq, wbFULL, wbMODL, wbICON, wbDEST, wbYNAM, wbZNAM, wbInteger(QUAL, 'Quality', itS32, wbEnum([], [ 0, 'Novice', 1, 'Apprentice', 2, 'Journeyman', 3, 'Expert', 4, 'Master' ])), wbDESC, wbStruct(DATA, 'Data', [ wbInteger('Value', itU32), wbFloat('Weight') ]) ]); wbRecord(COBJ, 'Constructible Object', [ wbEDID, wbCOCT, wbCNTOs, wbCTDAs, wbFormID(CNAM, 'Created Object'), wbFormIDCk(BNAM, 'Workbench Keyword', [KYWD]), wbInteger(NAM1, 'Created Object Count', itU16) ], False, nil, cpNormal, False, nil, wbContainerAfterSet); wbRecord(NPC_, 'Non-Player Character (Actor)', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000400} 10, 'Unknown 10', {0x00040000} 18, 'Compressed', {0x00080000} 19, 'Unknown 19', {0x20000000} 29, 'Bleedout Override' ]), [18]), [ wbEDID, wbVMAD, wbOBNDReq, wbStruct(ACBS, 'Configuration', [ wbInteger('Flags', itU32, wbFlags([ {0x00000001} 'Female', {0x00000002} 'Essential', {0x00000004} 'Is CharGen Face Preset', {0x00000008} 'Respawn', {0x00000010} 'Auto-calc stats', {0x00000020} 'Unique', {0x00000040} 'Doesn''t affect stealth meter', {0x00000080} 'PC Level Mult', {0x00000100} 'Use Template?', {0x00000200} 'Unknown 9', {0x00000400} 'Unknown 10', {0x00000800} 'Protected', {0x00001000} 'Unknown 12', {0x00002000} 'Unknown 13', {0x00004000} 'Summonable', {0x00008000} 'Unknown 15', {0x00010000} 'Doesn''t bleed', {0x00020000} 'Unknown 17', {0x00040000} 'Bleedout Override', {0x00080000} 'Opposite Gender Anims', {0x00100000} 'Simple Actor', {0x00200000} 'looped script?', {0x00400000} 'Unknown 22', {0x00800000} 'Unknown 23', {0x01000000} 'Unknown 24', {0x02000000} 'Unknown 25', {0x04000000} 'Unknown 26', {0x08000000} 'Unknown 27', {0x10000000} 'looped audio?', {0x20000000} 'Is Ghost', {0x40000000} 'Unknown 30', {0x80000000} 'Invulnerable' ])), wbInteger('Magicka Offset', itS16, nil, cpNormal, True, nil{wbActorTemplateUseStats}), wbInteger('Stamina Offset', itS16, nil, cpNormal, False, nil{wbActorTemplateUseAIData}), wbUnion('Level', wbNPCLevelDecider, [ wbInteger('Level', itS16, nil, cpNormal, True, nil{wbActorTemplateUseStats}), wbInteger('Level Mult', itS16, wbDiv(1000), cpNormal, True, nil{wbActorTemplateUseStats}) ], cpNormal, True, nil{wbActorTemplateUseStats}), wbInteger('Calc min level', itU16, nil, cpNormal, True, nil{wbActorTemplateUseStats}), wbInteger('Calc max level', itU16, nil, cpNormal, True, nil{wbActorTemplateUseStats}), wbInteger('Speed Multiplier', itU16, nil, cpNormal, True, nil{wbActorTemplateUseStats}), wbInteger('Disposition Base (unused)', itS16, nil, cpIgnore, True, nil{wbActorTemplateUseTraits}), wbInteger('Template Flags', itU16, wbFlags([ {0x0001} 'Use Traits', {0x0002} 'Use Stats', {0x0004} 'Use Factions', {0x0008} 'Use Spell List', {0x0010} 'Use AI Data', {0x0020} 'Use AI Packages', {0x0040} 'Use Model/Animation?', {0x0080} 'Use Base Data', {0x0100} 'Use Inventory', {0x0200} 'Use Script', {0x0400} 'Use Def Pack List', {0x0800} 'Use Attack Data', {0x1000} 'Use Keywords' ])), wbInteger('Health Offset', itS16, nil, cpNormal, True, nil{wbActorTemplateUseStats}), wbInteger('Bleedout Override', itU16, nil, cpNormal, True, nil{wbActorTemplateUseStats}) ], cpNormal, True), wbRArrayS('Factions', wbStructSK(SNAM, [0], 'Faction', [ wbFormIDCk('Faction', [FACT]), wbInteger('Rank', itS8), wbByteArray('Unused', 3, cpIgnore) ]), cpNormal, False, nil, nil, nil{wbActorTemplateUseFactions} ), wbFormIDCk(INAM, 'Death item', [LVLI], False, cpNormal, False, nil{wbActorTemplateUseTraits}), wbFormIDCk(VTCK, 'Voice', [VTYP], False, cpNormal, False, nil{wbActorTemplateUseTraits}), wbFormIDCk(TPLT, 'Template', [LVLN, NPC_]), wbFormIDCk(RNAM, 'Race', [RACE], False, cpNormal, True, nil{wbActorTemplateUseTraits}), wbSPCT, wbSPLOs, wbDEST, wbFormIDCk(WNAM, 'Worn Armor', [ARMO], False, cpNormal, False), wbFormIDCk(ANAM, 'Far away model', [ARMO], False, cpNormal, False, nil{wbActorTemplateUseTraits}), wbFormIDCk(ATKR, 'Attack Race', [RACE], False, cpNormal, False), wbRArrayS('Attacks', wbAttackData), wbFormIDCk(SPOR, 'Spectator override package list', [FLST], False, cpNormal, False), wbFormIDCk(OCOR, 'Observe dead body override package list', [FLST], False, cpNormal, False), wbFormIDCk(GWOR, 'Guard warn override package list', [FLST], False, cpNormal, False), wbFormIDCk(ECOR, 'Combat override package list', [FLST], False, cpNormal, False), wbInteger(PRKZ, 'Perk Count', itU32, nil, cpBenign), wbRArrayS('Perks', wbStructSK(PRKR, [0], 'Perk', [ wbFormIDCk('Perk', [PERK]), wbInteger('Rank', itU8), wbByteArray('Unused', 3, cpIgnore) ]), cpNormal, False, nil, wbPRKRsAfterSet ), wbCOCT, wbCNTOs, wbAIDT, wbRArray('Packages', wbFormIDCk(PKID, 'Package', [PACK]), cpNormal, False, nil{wbActorTemplateUseAIPackages}), wbKSIZ, wbKWDAs, wbFormIDCk(CNAM, 'Class', [CLAS], False, cpNormal, True), wbFULL, wbLString(SHRT, 'Short Name', 0, cpTranslate), wbByteArray(DATA, 'Marker'), wbStruct(DNAM, 'Player Skills', [ wbArray('Skill Values', wbInteger('Skill', itU8), [ 'OneHanded', 'TwoHanded', 'Marksman', 'Block', 'Smithing', 'HeavyArmor', 'LightArmor', 'Pickpocket', 'Lockpicking', 'Sneak', 'Alchemy', 'Speechcraft', 'Alteration', 'Conjuration', 'Destruction', 'Illusion', 'Restoration', 'Enchanting' ]), wbArray('Skill Offsets', wbInteger('Skill', itU8), [ 'OneHanded', 'TwoHanded', 'Marksman', 'Block', 'Smithing', 'HeavyArmor', 'LightArmor', 'Pickpocket', 'Lockpicking', 'Sneak', 'Alchemy', 'Speechcraft', 'Alteration', 'Conjuration', 'Destruction', 'Illusion', 'Restoration', 'Enchanting' ]), //wbByteArray('Unknown', 4), wbInteger('Health', itU16), wbInteger('Magicka', itU16), wbInteger('Stamina', itU16), wbByteArray('Unused', 2, cpIgnore), wbFloat('Far away model distance'), wbInteger('Geared up weapons', itU8), wbByteArray('Unused', 3, cpIgnore) ], cpNormal, False, nil{wbActorTemplateUseStatsAutoCalc}), wbRArrayS('Head Parts', wbFormIDCk(PNAM, 'Head Part', [HDPT]), cpNormal, False, nil, nil, nil{wbActorTemplateUseModelAnimation}), wbFormIDCk(HCLF, 'Hair Color', [CLFM], False, cpNormal, False), wbFormIDCk(ZNAM, 'Combat Style', [CSTY], False, cpNormal, False), wbFormIDCk(GNAM, 'Gift Filter', [FLST], False, cpNormal, False), wbUnknown(NAM5, cpNormal, True), wbFloat(NAM6, 'Height', cpNormal, True), wbFloat(NAM7, 'Weight', cpNormal, True), wbInteger(NAM8, 'Sound Level', itU32, wbSoundLevelEnum, cpNormal, True), wbCSDTs, // When CSCR exists CSDT, CSDI, CSDC are not present wbFormIDCk(CSCR, 'Inherits Sounds From', [NPC_], False, cpNormal, False), wbFormIDCk(DOFT, 'Default outfit', [OTFT], False, cpNormal, False), wbFormIDCk(SOFT, 'Sleeping outfit', [OTFT], False, cpNormal, False), wbFormIDCk(DPLT, 'Default Package List', [FLST], False, cpNormal, False), wbFormIDCk(CRIF, 'Crime faction', [FACT], False, cpNormal, False), wbFormIDCk(FTST, 'Head texture', [TXST], False, cpNormal, False), wbStruct(QNAM, 'Texture lighting', [ wbFloat('Red', cpNormal, True, 255, 0), wbFloat('Green', cpNormal, True, 255, 0), wbFloat('Blue', cpNormal, True, 255, 0) ]), wbStruct(NAM9, 'Face morph', [ wbFloat('Nose Long/Short'), wbFloat('Nose Up/Down'), wbFloat('Jaw Up/Down'), wbFloat('Jaw Narrow/Wide'), wbFloat('Jaw Farward/Back'), wbFloat('Cheeks Up/Down'), wbFloat('Cheeks Farward/Back'), wbFloat('Eyes Up/Down'), wbFloat('Eyes In/Out'), wbFloat('Brows Up/Down'), wbFloat('Brows In/Out'), wbFloat('Brows Farward/Back'), wbFloat('Lips Up/Down'), wbFloat('Lips In/Out'), wbFloat('Chin Narrow/Wide'), wbFloat('Chin Up/Down'), wbFloat('Chin Underbite/Overbite'), wbFloat('Eyes Farward/Back'), wbFloat('Unknown') ], cpNormal, False), wbStruct(NAMA, 'Face parts', [ wbInteger('Nose', itU32), wbInteger('Unknown', itS32), wbInteger('Eyes', itU32), wbInteger('Mouth', itU32) ]), wbRArrayS('Tint Layers', wbRStructSK([0], 'Layer', [ wbInteger(TINI, 'Tint Index', itU16, wbTintLayerToStr, wbStrToInt), wbStruct(TINC, 'Tint Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbInteger('Alpha', itU8) ]), wbInteger(TINV, 'Interpolation Value', itU32, wbDiv(100)), wbInteger(TIAS, 'Preset', itS16) ], [])) ], False, nil, cpNormal, False, wbNPCAfterLoad, wbNPCAfterSet); wbObjectTypeEnum := wbEnum([ ' NONE', 'Activators', 'Armor', 'Books', 'Clothing', 'Containers', 'Doors', 'Ingredients', 'Lights', 'Misc', 'Flora', 'Furniture', 'Weapons: Any', 'Ammo', 'NPCs', 'Creatures', 'Keys', 'Alchemy', 'Food', ' All: Combat Wearable', ' All: Wearable', 'Weapons: Ranged', 'Weapons: Melee', 'Weapons: NONE', 'Actor Effects: Any', 'Actor Effects: Range Target', 'Actor Effects: Range Touch', 'Actor Effects: Range Self', 'Actors: Any' ]); wbPKDTSpecificFlagsUnused := False; wbPKDTFlags := wbFlags([ {0x00000001} 'Offers Services', {0x00000002} 'Unknown 2', {0x00000004} 'Must complete', {0x00000008} 'Maintain Speed at Goal', {0x00000010} 'Unknown 5', {0x00000020} 'Unknown 6', {0x00000040} 'Unlock doors at package start', {0x00000080} 'Unlock doors at package end', {0x00000100} 'Unknown 9', {0x00000200} 'Continue if PC Near', {0x00000400} 'Once per day', {0x00000800} 'Unknown 12', {0x00001000} 'Unknown 13', {0x00002000} 'Preferred Speed', {0x00004000} 'Unknown 15', {0x00008000} 'Unknown 16', {0x00010000} 'Unknown 17', {0x00020000} 'Always Sneak', {0x00040000} 'Allow Swimming', {0x00080000} 'Unknown 20', {0x00100000} 'Ignore Combat', {0x00200000} 'Weapons Unequipped', {0x00400000} 'Unknown 23', {0x00800000} 'Weapon Drawn', {0x01000000} 'Unknown 25', {0x02000000} 'Unknown 26', {0x04000000} 'Unknown 27', {0x08000000} 'No Combat Alert', {0x10000000} 'Unknown 29', {0x20000000} 'Wear Sleep Outfit (unused)', {0x40000000} 'Unknown 31', {0x80000000} 'Unknown 32' ], [29]); wbPKDTInterruptFlags := wbFlags([ {0x0001}'Hellos to player', {0x0002}'Random conversations', {0x0004}'Observe combat behavior', {0x0008}'Greet corpse behavior', {0x0010}'Reaction to player actions', {0x0020}'Friendly fire comments', {0x0040}'Aggro Radius Behavior', {0x0080}'Allow Idle Chatter', {0x0100}'Unknown 9', {0x0200}'World Interactions', {0x0400}'Unknown 11', {0x0800}'Unknown 12', {0x1000}'Unknown 13', {0x2000}'Unknown 14', {0x4000}'Unknown 15', {0x8000}'Unknown 16' ]); end; procedure DefineTES5n; begin wbUNAMs:= wbRArray('Data Inputs', wbRStruct('Data Input', [ wbInteger(UNAM, 'Index', itS8), wbString(BNAM, 'Name'), wbInteger(PNAM, 'Flags', itU32, wbFlags([ 'Public' ])) ], [])); wbRecord(PACK, 'Package', [ wbEDID, wbVMADFragmentedPACK, wbStruct(PKDT, 'Pack Data', [ wbInteger('General Flags', itU32, wbPKDTFlags), wbInteger('Type', itU8, wbEnum ([], [ 18, 'Package', 19, 'Package Template' ])), wbInteger('Interrupt Override', itU8, wbEnum([ 'None', 'Spectator', 'ObserveDead', 'GuardWarn', 'Combat' ])), wbInteger('Preferred Speed', itU8, wbEnum([ 'Walk', 'Jog', 'Run', 'Fast Walk' ])), wbByteArray('Unknown', 1), wbInteger('Interrupt Flags', itU16, wbPKDTInterruptFlags), wbByteArray('Unknown', 2) ], cpNormal, True), wbStruct(PSDT, 'Schedule', [ wbInteger('Month', itS8), wbInteger('Day of week', itS8, wbEnum([ 'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Weekdays', 'Weekends', 'Monday, Wednesday, Friday', 'Tuesday, Thursday' ], [ -1, 'Any' ])), wbInteger('Date', itU8), wbInteger('Hour', itS8), wbInteger('Minute', itS8), wbByteArray('Unused', 3, cpIgnore), wbInteger('Duration (minutes)', itS32) ], cpNormal, True), wbCTDAs, wbRStruct('Idle Animations', [ wbInteger(IDLF, 'Flags', itU8, wbEnum([], [ 0, 'Unknown', 8, 'Random', 9, 'Run in Sequence', 12, 'Random, Do Once', 13, 'Run in Sequence, Do Once' ]), cpNormal, True), wbStruct(IDLC, '', [ wbInteger('Animation Count', itU8, nil, cpBenign), wbByteArray('Unknown', 3) ], cpNormal, True, nil, 1), wbFloat(IDLT, 'Idle Timer Setting', cpNormal, True), wbArray(IDLA, 'Animations', wbFormIDCk('Animation', [IDLE]), 0, nil, wbIDLAsAfterSet, cpNormal, True), wbByteArray(IDLB, 'Unknown', 4, cpIgnore) ], [], cpNormal, False, nil, False, nil {cannot be totally removed , wbAnimationsAfterSet}), wbFormIDCk(CNAM, 'Combat Style', [CSTY]), wbFormIDCk(QNAM, 'Owner Quest', [QUST]), wbStruct(PKCU, 'Counter', [ wbInteger('Data Input Count', itU32), wbFormIDCk('Package Template', [PACK, NULL]), wbInteger('Version Counter (autoincremented)', itU32) ], cpNormal, True), wbRStruct('Package Data', [ wbRArray('Data Input Values', wbRStruct('Value', [ wbString(ANAM, 'Type'), wbUnion(CNAM, 'Value', wbPubPackCNAMDecider, [ {0} wbByteArray('Unknown'), {1} wbInteger('Bool', itU8, wbEnum(['False', 'True'])), {2} wbInteger('Integer', itU32), {3} wbFloat('Float') ]), wbUnknown(BNAM), wbPDTOs, wbPLDT, wbStruct(PTDA, 'Target', [wbTargetData]), wbUnknown(TPIC) ], [], cpNormal, False)), wbUNAMs ], []), wbByteArray(XNAM, 'Marker'), wbRStruct('Procedure Tree', [ wbRArray('Branches', wbRStruct('Branch', [ wbString(ANAM, 'Branch Type'), wbCITC, wbCTDAsCount, wbStruct(PRCB, 'Root', [ wbInteger('Branch Count', itU32), wbInteger('Flags', itU32, wbFlags([ 'Repeat when Complete', 'Unknown 1' ])) ]), wbString(PNAM, 'Procedure Type'), wbInteger(FNAM, 'Flags', itU32, wbFlags(['Success Completes Package'])), wbRArray('Data Input Indexes', wbInteger(PKC2, 'Index', itU8)), {>>> PFO2 should be single, there is only 1 PACK [00095F46] in Skyrim.esm with 2xPFO2 <<<} wbRArray('Flags Override', wbStruct(PFO2, 'Data', [ wbInteger('Set General Flags', itU32, wbPKDTFlags), wbInteger('Clear General Flags', itU32, wbPKDTFlags), wbInteger('Set Interrupt Flags', itU16, wbPKDTInterruptFlags), wbInteger('Clear Interrupt Flags', itU16, wbPKDTInterruptFlags), wbInteger('Preferred Speed Override', itU8, wbEnum([ 'Walk', 'Jog', 'Run', 'Fast Walk' ])), wbByteArray('Unknown', 3) ]) ), wbRArray('Unknown', wbUnknown(PFOR), cpIgnore) ], [], cpNormal, False, nil, False, nil, wbConditionsAfterSet)) ], []), wbUNAMs, wbRStruct('OnBegin', [ wbEmpty(POBA, 'OnBegin Marker', cpNormal, True), wbFormIDCk(INAM, 'Idle', [IDLE, NULL], False, cpNormal, True), {>>> BEGIN leftover from earlier CK versions <<<} wbByteArray(SCHR, 'Unused', 0, cpIgnore, false, false, wbNeverShow), wbByteArray(SCTX, 'Unused', 0, cpIgnore, false, false, wbNeverShow), wbByteArray(QNAM, 'Unused', 0, cpIgnore, false, false, wbNeverShow), wbByteArray(TNAM, 'Unused', 0, cpIgnore, false, false, wbNeverShow), {>>> END leftover from earlier CK versions <<<} wbPDTOs ], []), wbRStruct('OnEnd', [ wbEmpty(POEA, 'OnEnd Marker', cpNormal, True), wbFormIDCk(INAM, 'Idle', [IDLE, NULL], False, cpNormal, True), {>>> BEGIN leftover from earlier CK versions <<<} wbByteArray(SCHR, 'Unused', 0, cpIgnore, false, false, wbNeverShow), wbByteArray(SCTX, 'Unused', 0, cpIgnore, false, false, wbNeverShow), wbByteArray(QNAM, 'Unused', 0, cpIgnore, false, false, wbNeverShow), wbByteArray(TNAM, 'Unused', 0, cpIgnore, false, false, wbNeverShow), {>>> END leftover from earlier CK versions <<<} wbPDTOs ], []), wbRStruct('OnChange', [ wbEmpty(POCA, 'OnChange Marker', cpNormal, True), wbFormIDCk(INAM, 'Idle', [IDLE, NULL], False, cpNormal, True), {>>> BEGIN leftover from earlier CK versions <<<} wbByteArray(SCHR, 'Unused', 0, cpIgnore, false, false, wbNeverShow), wbByteArray(SCDA, 'Unused', 0, cpIgnore, false, false, wbNeverShow), wbByteArray(SCTX, 'Unused', 0, cpIgnore, false, false, wbNeverShow), wbByteArray(QNAM, 'Unused', 0, cpIgnore, false, false, wbNeverShow), wbByteArray(TNAM, 'Unused', 0, cpIgnore, false, false, wbNeverShow), {>>> END leftover from earlier CK versions <<<} wbPDTOs ], []) ], False, nil, cpNormal, False, nil {wbPACKAfterLoad}); wbQUSTAliasFlags := wbStruct(FNAM, 'Alias Flags', [ wbInteger('Flags', itU16, wbFlags([ {0x0001}'Reserves Location/Reference', {0x0002}'Optional', {0x0004}'Quest Object', {0x0008}'Allow Reuse in Quest', {0x0010}'Allow Dead', {0x0020}'Matching Ref - In Loaded Area', {0x0040}'Essential', {0x0080}'Allow Disabled', {0x0100}'Stores Text', {0x0200}'Allow Reserved', {0x0400}'Protected', {0x0800}'Forced by Aliases?', {0x1000}'Allow Destroyed', {0x2000}'Matching Ref - Closest', {0x4000}'Uses Stored Text', {0x8000}'Initially Disabled' ])), wbInteger('Additional Flags', itU16, wbFlags([ {0x0001}'Allow Cleared', {0x0002}'Clear Names When Removed' ])) ], cpNormal, False, nil, 1); wbRecord(QUST, 'Quest', [ wbEDID, wbVMADFragmentedQUST, wbFULL, wbStruct(DNAM, 'General', [ wbInteger('Flags', itU16, wbFlags([ {0x0001} 'Start Game Enabled', {0x0002} 'Unknown 2', {0x0004} 'Unknown 3', {0x0008} 'Allow repeated stages', {0x0010} 'Unknown 5', {0x0020} 'Unknown 6', {0x0040} 'Unknown 7', {0x0080} 'Unknown 8', {0x0100} 'Run Once', {0x0200} 'Exclude from dialogue export', {0x0400} 'Warn on alias fill failure', {0x0800} 'Unknown 12', {0x1000} 'Unknown 13' ])), wbInteger('Priority', itU8), wbInteger('Form Version', itU8, nil, cpIgnore), wbByteArray('Unknown', 4), wbInteger('Type', itU32, wbEnum([ {0} 'None', {1} 'Main Quest', {2} 'Mages'' Guild', {3} 'Thieves'' Guild', {4} 'Dark Brotherhood', {5} 'Companion Quests', {6} 'Miscellaneous', {7} 'Daedric', {8} 'Side Quest', {9} 'Civil War', {10} 'DLC01 - Vampire', {11} 'DLC02 - Dragonborn' ])) ]), wbString(ENAM, 'Event', 4), wbRArray('Text Display Globals', wbFormIDCk(QTGL, 'Global', [GLOB])), wbString(FLTR, 'Object Window Filter', 0, cpTranslate), wbRStruct('Quest Dialogue Conditions', [wbCTDAs], [], cpNormal, False), wbEmpty(NEXT, 'Marker'), wbCTDAs, {>>> Unknown, doesn't show up in CK <<<} wbRArrayS('Stages', wbRStructSK([0], 'Stage', [ wbStructSK(INDX, [0], 'Stage Index', [ wbInteger('Stage Index', itU16), wbInteger('Flags', itU8, wbFlags([ {0x01} 'Unknown 1', {0x02} 'Start Up Stage', {0x04} 'Shut Down Stage', {0x08} 'Keep Instance Data From Here On' ])), wbInteger('Unknown', itU8) ]), wbRArray('Log Entries', wbRStruct('Log Entry', [ wbInteger(QSDT, 'Stage Flags', itU8, wbFlags([ {0x01} 'Complete Quest', {0x02} 'Fail Quest' ])), wbCTDAs, wbLString(CNAM, 'Log Entry', 0, cpTranslate), wbFormIDCk(NAM0, 'Next Quest', [QUST]), {>>> BEGIN leftover from earlier CK versions <<<} wbByteArray(SCHR, 'Unused', 0, cpIgnore, false, false, wbNeverShow), wbByteArray(SCTX, 'Unused', 0, cpIgnore, false, false, wbNeverShow), wbByteArray(QNAM, 'Unused', 0, cpIgnore, false, false, wbNeverShow) {>>> END leftover from earlier CK versions <<<} ], [])) ], [])), wbRArray('Objectives', wbRStruct('Objective', [ wbInteger(QOBJ, 'Objective Index', itU16), wbInteger(FNAM, 'Flags', itU32, wbFlags(['ORed With Previous'])), wbLString(NNAM, 'Display Text', 0, cpTranslate, True), wbRArray('Targets', wbRStruct('Target', [ wbStruct(QSTA, 'Target', [ wbInteger('Alias', itS32, wbQuestAliasToStr, wbStrToAlias), wbInteger('Flags', itU8, wbFlags([ {0x01} 'Compass Marker Ignores Locks' ])), wbByteArray('Unused', 3) ]), wbCTDAs ], [])) ], [])), wbByteArray(ANAM, 'Aliases Marker', 4), wbRArray('Aliases', wbRUnion('Alias', [ // Reference Alias wbRStruct('Alias', [ wbInteger(ALST, 'Reference Alias ID', itU32), wbString(ALID, 'Alias Name'), wbQUSTAliasFlags, wbInteger(ALFI, 'Force Into Alias When Filled', itS32, wbQuestAliasToStr, wbStrToAlias), wbFormIDCk(ALFL, 'Specific Location', [LCTN]), wbFormID(ALFR, 'Forced Reference'), wbFormIDCk(ALUA, 'Unique Actor', [NPC_]), wbRStruct('Location Alias Reference', [ wbInteger(ALFA, 'Alias', itS32, wbQuestAliasToStr, wbStrToAlias), wbFormIDCk(KNAM, 'Keyword', [KYWD]), wbFormIDCk(ALRT, 'Ref Type', [LCRT]) ], []), wbRStruct('External Alias Reference', [ wbFormIDCk(ALEQ, 'Quest', [QUST]), wbInteger(ALEA, 'Alias', itS32, wbQuestExternalAliasToStr, wbStrToAlias) ], []), wbRStruct('Create Reference to Object', [ wbFormID(ALCO, 'Object'), wbStruct(ALCA, 'Alias', [ wbInteger('Alias', itS16, wbQuestAliasToStr, wbStrToAlias), wbInteger('Create', itU16, wbEnum([] ,[ $0000, 'At', $8000, 'In' ])) ]), wbInteger(ALCL, 'Level', itU32, wbEnum([ 'Easy', 'Medium', 'Hard', 'Very Hard', 'None' ])) ], []), wbRStruct('Find Matching Reference Near Alias', [ wbInteger(ALNA, 'Alias', itS32, wbQuestAliasToStr, wbStrToAlias), wbInteger(ALNT, 'Type', itU32, wbEnum([ 'Linked Ref Child' ])) ], []), wbRStruct('Find Matching Reference From Event', [ wbString(ALFE, 'From Event', 4), wbByteArray(ALFD, 'Event Data') ], []), wbCTDAs, wbKSIZ, wbKWDAs, wbCOCT, wbCNTOs, wbFormIDCk(SPOR, 'Spectator override package list', [FLST], False, cpNormal, False), wbFormIDCk(OCOR, 'Observe dead body override package list', [FLST], False, cpNormal, False), wbFormIDCk(GWOR, 'Guard warn override package list', [FLST], False, cpNormal, False), wbFormIDCk(ECOR, 'Combat override package list', [FLST], False, cpNormal, False), wbFormIDCk(ALDN, 'Display Name', [MESG]), wbRArray('Alias Spells', wbFormIDCk(ALSP, 'Spell', [SPEL])), wbRArray('Alias Factions', wbFormIDCk(ALFC, 'Faction', [FACT])), wbRArray('Alias Package Data', wbFormIDCk(ALPC, 'Package', [PACK])), wbFormIDCk(VTCK, 'Voice Types', [NPC_, FLST, NULL]), wbEmpty(ALED, 'Alias End', cpNormal, True) ], [], cpNormal, False, nil, False, nil, wbContainerAfterSet), // Location Alias wbRStruct('Alias', [ wbInteger(ALLS, 'Location Alias ID', itU32), wbString(ALID, 'Alias Name'), wbQUSTAliasFlags, wbInteger(ALFI, 'Force Into Alias When Filled', itS32, wbQuestAliasToStr, wbStrToAlias), wbFormIDCk(ALFL, 'Specific Location', [LCTN]), wbFormID(ALFR, 'Forced Reference'), wbFormIDCk(ALUA, 'Unique Actor', [NPC_]), wbRStruct('Location Alias Reference', [ wbInteger(ALFA, 'Alias', itS32, wbQuestAliasToStr, wbStrToAlias), wbFormIDCk(KNAM, 'Keyword', [KYWD]), wbFormIDCk(ALRT, 'Ref Type', [LCRT]) ], []), wbRStruct('External Alias Reference', [ wbFormIDCk(ALEQ, 'Quest', [QUST]), wbInteger(ALEA, 'Alias', itS32, wbQuestExternalAliasToStr, wbStrToAlias) ], []), wbRStruct('Create Reference to Object', [ wbFormID(ALCO, 'Object'), wbStruct(ALCA, 'Alias', [ wbInteger('Alias', itS16, wbQuestAliasToStr, wbStrToAlias), wbInteger('Create', itU16, wbEnum([] ,[ $0000, 'At', $8000, 'In' ])) ]), wbInteger(ALCL, 'Level', itU32, wbEnum([ 'Easy', 'Medium', 'Hard', 'Very Hard', 'None' ])) ], []), wbRStruct('Find Matching Reference Near Alias', [ wbInteger(ALNA, 'Alias', itS32, wbQuestAliasToStr, wbStrToAlias), wbInteger(ALNT, 'Type', itU32, wbEnum([ 'Linked Ref Child' ])) ], []), wbRStruct('Find Matching Reference From Event', [ wbString(ALFE, 'From Event', 4), wbByteArray(ALFD, 'Event Data') ], []), wbCTDAs, wbKSIZ, wbKWDAs, wbCOCT, wbCNTOs, wbFormIDCk(SPOR, 'Spectator override package list', [FLST], False, cpNormal, False), wbFormIDCk(OCOR, 'Observe dead body override package list', [FLST], False, cpNormal, False), wbFormIDCk(GWOR, 'Guard warn override package list', [FLST], False, cpNormal, False), wbFormIDCk(ECOR, 'Combat override package list', [FLST], False, cpNormal, False), wbFormIDCk(ALDN, 'Display Name', [MESG]), wbRArray('Alias Spells', wbFormIDCk(ALSP, 'Spell', [SPEL])), wbRArray('Alias Factions', wbFormIDCk(ALFC, 'Faction', [FACT])), wbRArray('Alias Package Data', wbFormIDCk(ALPC, 'Package', [PACK])), wbFormIDCk(VTCK, 'Voice Types', [NPC_, FLST, NULL]), wbEmpty(ALED, 'Alias End', cpNormal, True) ], [], cpNormal, False, nil, False, nil, wbContainerAfterSet) ], []) ), wbString(NNAM, 'Description', 0, cpNormal, False), wbRArray('Targets', wbRStruct('Target', [ wbStruct(QSTA, 'Target', [ wbFormIDCkNoReach('Target', [ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA], True), wbInteger('Flags', itU8, wbFlags([ {0x01} 'Compass Marker Ignores Locks' ])), wbByteArray('Unknown', 3) ]), wbCTDAs ], [])) ]); wbBodyPartIndexEnum := wbEnum([ 'Body Texture' ]); wbNoseMorphFlags := wbInteger('Nose Morph Flags', itU32, wbFlags([ {0x00000001}'NoseType0', {0x00000002}'NoseType1', {0x00000004}'NoseType2', {0x00000008}'NoseType3', {0x00000010}'NoseType4', {0x00000020}'NoseType5', {0x00000040}'NoseType6', {0x00000080}'NoseType7', {0x00000100}'NoseType8', {0x00000200}'NoseType9', {0x00000400}'NoseType10', {0x00000800}'NoseType11', {0x00001000}'NoseType12', {0x00002000}'NoseType13', {0x00004000}'NoseType14', {0x00008000}'NoseType15', {0x00010000}'NoseType16', {0x00020000}'NoseType17', {0x00040000}'NoseType18', {0x00080000}'NoseType19', {0x00100000}'NoseType20', {0x00200000}'NoseType21', {0x00400000}'NoseType22', {0x00800000}'NoseType23', {0x01000000}'NoseType24', {0x02000000}'NoseType25', {0x04000000}'NoseType26', {0x08000000}'NoseType27', {0x10000000}'NoseType28', {0x20000000}'NoseType29', {0x40000000}'NoseType30', {0x80000000}'NoseType31' ])); wbBrowMorphFlags := wbInteger('Brow Morph Flags', itU32, wbFlags([ {0x00000001}'BrowType0', {0x00000002}'BrowType1', {0x00000004}'BrowType2', {0x00000008}'BrowType3', {0x00000010}'BrowType4', {0x00000020}'BrowType5', {0x00000040}'BrowType6', {0x00000080}'BrowType7', {0x00000100}'BrowType8', {0x00000200}'BrowType9', {0x00000400}'BrowType10', {0x00000800}'BrowType11', {0x00001000}'BrowType12', {0x00002000}'BrowType13', {0x00004000}'BrowType14', {0x00008000}'BrowType15', {0x00010000}'BrowType16', {0x00020000}'BrowType17', {0x00040000}'BrowType18', {0x00080000}'BrowType19', {0x00100000}'BrowType20' ], True)); wbEyesMorphFlags01 := wbInteger('Eye Morph Flags 1', itU32, wbFlags([ {0x00000001}'EyesType0', {0x00000002}'EyesType1', {0x00000004}'EyesType2', {0x00000008}'EyesType3', {0x00000010}'EyesType4', {0x00000020}'EyesType5', {0x00000040}'EyesType6', {0x00000080}'EyesType7', {0x00000100}'EyesType8', {0x00000200}'EyesType9', {0x00000400}'EyesType10', {0x00000800}'EyesType11', {0x00001000}'EyesType12', {0x00002000}'EyesType13', {0x00004000}'EyesType14', {0x00008000}'EyesType15', {0x00010000}'EyesType16', {0x00020000}'EyesType17', {0x00040000}'EyesType18', {0x00080000}'EyesType19', {0x00100000}'EyesType20', {0x00200000}'EyesType21', {0x00400000}'EyesType22', {0x00800000}'EyesType23', {0x01000000}'EyesType24', {0x02000000}'EyesType25', {0x04000000}'EyesType26', {0x08000000}'EyesType27', {0x10000000}'EyesType28', {0x20000000}'EyesType29', {0x40000000}'EyesType30', {0x80000000}'EyesType31' ])); wbEyesMorphFlags02 := wbInteger('Eye Morph Flags 2', itU8, wbFlags([ {0x00000001}'EyesType32', {0x00000002}'EyesType33', {0x00000004}'EyesType34', {0x00000008}'EyesType35', {0x00000010}'EyesType36', {0x00000020}'EyesType37', {0x00000040}'EyesType38' ], True)); wbLipMorphFlags := wbInteger('Lip Morph Flags', itU32, wbFlags([ {0x00000001}'LipType0', {0x00000002}'LipType1', {0x00000004}'LipType2', {0x00000008}'LipType3', {0x00000010}'LipType4', {0x00000020}'LipType5', {0x00000040}'LipType6', {0x00000080}'LipType7', {0x00000100}'LipType8', {0x00000200}'LipType9', {0x00000400}'LipType10', {0x00000800}'LipType11', {0x00001000}'LipType12', {0x00002000}'LipType13', {0x00004000}'LipType14', {0x00008000}'LipType15', {0x00010000}'LipType16', {0x00020000}'LipType17', {0x00040000}'LipType18', {0x00080000}'LipType19', {0x00100000}'LipType20', {0x00200000}'LipType21', {0x00400000}'LipType22', {0x00800000}'LipType23', {0x01000000}'LipType24', {0x02000000}'LipType25', {0x04000000}'LipType26', {0x08000000}'LipType27', {0x10000000}'LipType28', {0x20000000}'LipType29', {0x40000000}'LipType30', {0x80000000}'LipType31' ])); wbTintMaskTypeEnum := wbEnum([ 'None', 'Lip Color', 'Cheek Color', 'Eyeliner', 'EyeSocket Upper', 'EyeSocket Lower', 'Skin Tone', 'Paint', 'Laugh Lines', 'Cheek Color Lower', 'Nose', 'Chin', 'Neck', 'Forehead', 'Dirt', 'Unknown 16' ]); wbTints := wbRArray('Tint Masks', wbRStruct('Tint Assets', [ wbRArray('Tint Layer', wbRStruct('Texture', [ wbInteger(TINI, 'Index', itU16), wbString(TINT, 'File Name'), {>>> When set to None TINP does not exist Needs routine to add when changing the Mask Type <<<} wbInteger(TINP, 'Mask Type', itU16, wbTintMaskTypeEnum), wbFormIDCk(TIND, 'Preset Default', [CLFM, NULL]) ], [])), wbRArray('Presets', wbRStruct('Preset', [ wbFormIDCk(TINC, 'Color', [CLFM, NULL]), wbFloat(TINV, 'Default Value'), wbInteger(TIRS, 'Index', itU16) ], [])) ], [])); wbRACE_DATAFlags01 := wbInteger('Flags', itU32, wbFlags([ {0x00000001}'Playable', {0x00000002}'FaceGen Head', {0x00000004}'Child', {0x00000008}'Tilt Front/Back', {0x00000010}'Tilt Left/Right', {0x00000020}'No Shadow', {0x00000040}'Swims', {0x00000080}'Flies', {0x00000100}'Walks', {0x00000200}'Immobile', {0x00000400}'Not Pushable', {0x00000800}'No Combat In Water', {0x00001000}'No Rotating to Head-Track', {0x00002000}'Don''t Show Blood Spray', {0x00004000}'Don''t Show Blood Decal', {0x00008000}'Uses Head Track Anims', {0x00010000}'Spells Align w/Magic Node', {0x00020000}'Use World Raycasts For FootIK', {0x00040000}'Allow Ragdoll Collision', {0x00080000}'Regen HP In Combat', {0x00100000}'Can''t Open Doors', {0x00200000}'Allow PC Dialogue', {0x00400000}'No Knockdowns', {0x00800000}'Allow Pickpocket', {0x01000000}'Always Use Proxy Controller', {0x02000000}'Don''t Show Weapon Blood', {0x04000000}'Overlay Head Part List', {>>>Only one can be active<<<} {0x08000000}'Override Head Part List', {>>>Only one can be active<<<} {0x10000000}'Can Pickup Items', {0x20000000}'Allow Multiple Membrane Shaders', {0x40000000}'Can Dual Wield', {0x80000000}'Avoids Roads' ])); wbPhonemeTargets := wbStruct(PHWT, 'Phoneme Target Weight', [ wbFloat('Aah / LipBigAah'), wbFloat('BigAah / LipDST'), wbFloat('BMP / LipEee'), wbFloat('ChJsh / LipFV'), wbFloat('DST / LipK'), wbFloat('Eee / LipL'), wbFloat('Eh / LipR'), wbFloat('FV / LipTh'), wbFloat('I'), wbFloat('K'), wbFloat('N'), wbFloat('Oh'), wbFloat('OohQ'), wbFloat('R'), wbFloat('TH'), wbFloat('W') ], cpNormal, False, nil, 8); wbPHWT := wbRStruct('FaceFX Phonemes', [ wbRStruct('IY', [wbPhonemeTargets], []), wbRStruct('IH', [wbPhonemeTargets], []), wbRStruct('EH', [wbPhonemeTargets], []), wbRStruct('EY', [wbPhonemeTargets], []), wbRStruct('AE', [wbPhonemeTargets], []), wbRStruct('AA', [wbPhonemeTargets], []), wbRStruct('AW', [wbPhonemeTargets], []), wbRStruct('AY', [wbPhonemeTargets], []), wbRStruct('AH', [wbPhonemeTargets], []), wbRStruct('AO', [wbPhonemeTargets], []), wbRStruct('OY', [wbPhonemeTargets], []), wbRStruct('OW', [wbPhonemeTargets], []), wbRStruct('UH', [wbPhonemeTargets], []), wbRStruct('UW', [wbPhonemeTargets], []), wbRStruct('ER', [wbPhonemeTargets], []), wbRStruct('AX', [wbPhonemeTargets], []), wbRStruct('S', [wbPhonemeTargets], []), wbRStruct('SH', [wbPhonemeTargets], []), wbRStruct('Z', [wbPhonemeTargets], []), wbRStruct('ZH', [wbPhonemeTargets], []), wbRStruct('F', [wbPhonemeTargets], []), wbRStruct('TH', [wbPhonemeTargets], []), wbRStruct('V', [wbPhonemeTargets], []), wbRStruct('DH', [wbPhonemeTargets], []), wbRStruct('M', [wbPhonemeTargets], []), wbRStruct('N', [wbPhonemeTargets], []), wbRStruct('NG', [wbPhonemeTargets], []), wbRStruct('L', [wbPhonemeTargets], []), wbRStruct('R', [wbPhonemeTargets], []), wbRStruct('W', [wbPhonemeTargets], []), wbRStruct('Y', [wbPhonemeTargets], []), wbRStruct('HH', [wbPhonemeTargets], []), wbRStruct('B', [wbPhonemeTargets], []), wbRStruct('D', [wbPhonemeTargets], []), wbRStruct('JH', [wbPhonemeTargets], []), wbRStruct('G', [wbPhonemeTargets], []), wbRStruct('P', [wbPhonemeTargets], []), wbRStruct('T', [wbPhonemeTargets], []), wbRStruct('K', [wbPhonemeTargets], []), wbRStruct('CH', [wbPhonemeTargets], []), wbRStruct('SIL', [wbPhonemeTargets], []), wbRStruct('SHOTSIL', [wbPhonemeTargets], []), wbRStruct('FLAP', [wbPhonemeTargets], []) ], []); wbMorphs := wbRStruct('Available Morphs', [ wbByteArray(MPAI, 'Unknown', 0), wbStruct(MPAV, 'Nose Variants', [ wbNoseMorphFlags, wbByteArray('Unknown', 4), wbByteArray('Unknown', 4), wbByteArray('Unknown', 4), wbByteArray('Unknown', 4), wbByteArray('Unknown', 4), wbByteArray('Unknown', 4), wbByteArray('Unknown', 4) ]), wbByteArray(MPAI, 'Unknown', 0), wbStruct(MPAV, 'Brow Variants', [ wbBrowMorphFlags, wbByteArray('Unknown', 4), wbByteArray('Unknown', 4), wbByteArray('Unknown', 4), wbByteArray('Unknown', 4), wbByteArray('Unknown', 4), wbByteArray('Unknown', 4), wbByteArray('Unknown', 4) ]), wbByteArray(MPAI, 'Unknown', 0), wbStruct(MPAV, 'Eye Variants', [ wbEyesMorphFlags01, wbEyesMorphFlags02, wbByteArray('Unknown', 3), wbByteArray('Unknown', 4), wbByteArray('Unknown', 4), wbByteArray('Unknown', 4), wbByteArray('Unknown', 4), wbByteArray('Unknown', 4), wbByteArray('Unknown', 4) ]), wbByteArray(MPAI, 'Unknown', 0), wbStruct(MPAV, 'Lip Variants', [ wbLipMorphFlags, wbByteArray('Unknown', 4), wbByteArray('Unknown', 4), wbByteArray('Unknown', 4), wbByteArray('Unknown', 4), wbByteArray('Unknown', 4), wbByteArray('Unknown', 4), wbByteArray('Unknown', 4) ]) ], []); wbHeadPart := wbRStructSK([0],'Head Part', [ wbInteger(INDX, 'Head Part Number', itU32), wbFormIDCk(HEAD, 'Head', [HDPT, NULL]) ], []); wbRecord(RACE, 'Race', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00080000} 19, 'Critter?' ])), [ wbEDID, wbFULL, wbDESCReq, wbSPCT, wbSPLOs, wbFormIDCk(WNAM, 'Skin', [ARMO, NULL]), // wbBODT, // wbBOD2, wbBODTBOD2, wbKSIZ, wbKWDAs, wbStruct(DATA, '', [ wbArrayS('Skill Boosts', wbStructSK([0], 'Skill Boost', [ wbInteger('Skill', itS8, wbActorValueEnum), wbInteger('Boost', itS8) ]), 7), wbByteArray('Unknown', 2), wbFloat('Male Height'), wbFloat('Female Height'), wbFloat('Male Weight'), wbFloat('Female Weight'), wbRACE_DATAFlags01, wbFloat('Starting Health'), wbFloat('Starting Magicka'), wbFloat('Starting Stamina'), wbFloat('Base Carry Weight'), wbFloat('Base Mass'), wbFloat('Acceleration rate'), wbFloat('Deceleration rate'), wbInteger('Size', itU32, wbEnum([ 'Small', 'Medium', 'Large', 'Extra Large' ])), wbInteger('Head Biped Object', itS32, wbBipedObjectEnum), wbInteger('Hair Biped Object', itS32, wbBipedObjectEnum), wbFloat('Injured Health Pct'), wbInteger('Shield Biped Object', itS32, wbBipedObjectEnum), wbFloat('Health Regen'), wbFloat('Magicka Regen'), wbFloat('Stamina Regen'), wbFloat('Unarmed Damage'), wbFloat('Unarmed Reach'), wbInteger('Body Biped Object', itS32, wbBipedObjectEnum), wbFloat('Aim Angle Tolerance'), wbFloat('Flight Radius'), wbFloat('Angular Acceleration Rate'), wbFloat('Angular Tolerance'), wbInteger('Flags 2', itU32, wbFlags([ {0x00000001} 'Use Advanced Avoidance', {0x00000002} 'Non-Hostile', {0x00000004} 'Unknown 2', {0x00000008} 'Unknown 3', {0x00000010} 'Allow Mounted Combat' ])), wbStruct('Mount Data', [ wbFloat('Offset X', cpNormal, False, 1, -1, nil, nil, -63.479000), wbFloat('Offset Y'), wbFloat('Unknown'), wbFloat('Unknown', cpNormal, False, 1, -1, nil, nil, -50.0), wbFloat('Unknown'), wbFloat('Unknown', cpNormal, False, 1, -1, nil, nil, 65.0), wbFloat('Unknown'), wbFloat('Unknown', cpNormal, False, 1, -1, nil, nil, -300.0), wbFloat('Unknown') ]) //wbByteArray('Unknown', 4*7) ], cpNormal, True, nil, 29), wbEmpty(MNAM, 'Male Marker'), wbString(ANAM, 'Male Skeletal Model'), wbMODT, wbEmpty(FNAM, 'Female Marker'), wbString(ANAM, 'Female Skeletal Model'), wbMODT, wbEmpty(NAM2, 'Marker NAM2 #1'), wbRArrayS('Movement Type Names', wbString(MTNM, 'Name')), wbArray(VTCK, 'Voices', wbFormIDCk('Voice', [VTYP]), ['Male', 'Female'], cpNormal, True), wbArray(DNAM, 'Decapitate Armors', wbFormIDCk('Decapitate Armor', [NULL, ARMO]), ['Male', 'Female'], cpNormal, False), wbArray(HCLF, 'Default Hair Colors', wbFormIDCk('Default Hair Color', [NULL, CLFM]), ['Male', 'Female'], cpNormal, False), wbInteger(TINL, 'Total Number of Tints in List', itU16, nil, nil, cpNormal, False), {>>> Needs Count Updated <<<} wbFloat(PNAM, 'FaceGen - Main clamp', cpNormal, True), wbFloat(UNAM, 'FaceGen - Face clamp', cpNormal, True), wbFormIDCk(ATKR, 'Attack Race', [RACE], False, cpNormal, False), wbRArrayS('Attacks', wbAttackData), wbRStruct('Body Data', [ wbEmpty(NAM1, 'Body Data Marker', cpNormal, True), wbRStruct('Male Body Data', [ wbEmpty(MNAM, 'Male Data Marker'), wbRArrayS('Parts', wbRStructSK([0], 'Part', [ wbInteger(INDX, 'Index', itU32, wbBodyPartIndexEnum), wbMODL ], []), cpNormal, True) ], [], cpNormal, True), wbRStruct('Female Body Data', [ wbEmpty(FNAM, 'Female Data Marker', cpNormal, True), wbRArrayS('Parts', wbRStructSK([0], 'Part', [ wbInteger(INDX, 'Index', itU32, wbBodyPartIndexEnum), wbMODL ], []), cpNormal, True) ], [], cpNormal, True) ], [], cpNormal, True), wbArrayS(HNAM, 'Hairs', wbFormIDCk('Hair', [HDPT, NULL]), 0, cpNormal), wbArrayS(ENAM, 'Eyes', wbFormIDCk('Eye', [EYES, NULL]), 0, cpNormal), wbFormIDCk(GNAM, 'Body Part Data', [BPTD, NULL]), wbEmpty(NAM2, 'Marker NAM2 #2', cpNormal), wbEmpty(NAM3, 'Marker NAM3 #3', cpNormal, True), wbRStruct('Male Behavior Graph', [ wbEmpty(MNAM, 'Male Data Marker'), wbMODL ], [], cpNormal, True), wbRStruct('Female Behavior Graph', [ wbEmpty(FNAM, 'Female Data Marker', cpNormal, True), wbMODL ], [], cpNormal, True), wbFormIDCk(NAM4, 'Material Type', [MATT, NULL]), wbFormIDCk(NAM5, 'Impact Data Set', [IPDS, NULL]), wbFormIDCk(NAM7, 'Decapitation FX', [ARTO, NULL]), wbFormIDCk(ONAM, 'Open Loot Sound', [SNDR, NULL]), wbFormIDCk(LNAM, 'Close Loot Sound', [SNDR, NULL]), {>>> When NAME is user defined wbBipedObjectEnum will be incorrect <<<} wbRArray('Biped Object Names', wbString(NAME, 'Name')), wbRArrayS('Movement Types', wbRStructSK([0], 'Movement Types', [ wbFormIDCk(MTYP, 'Movement Type', [MOVT, NULL]), wbStruct(SPED, 'Override Values', [ wbFloat('Left - Walk'), wbFloat('Left - Run'), wbFloat('Right - Walk'), wbFloat('Right - Run'), wbFloat('Forward - Walk'), wbFloat('Forward - Run'), wbFloat('Back - Walk'), wbFloat('Back - Run'), wbFloat('Rotate - Walk'), wbFloat('Rotate - Walk'), wbFloat('Unknown') ]) ], [])), wbInteger(VNAM, 'Equipment Flags', itU32, wbEquipType), wbRArrayS('Equip Slots', wbFormIDCk(QNAM, 'Equip Slot', [EQUP, NULL])), wbFormIDCk(UNES, 'Unarmed Equip Slot', [EQUP, NULL]), wbRArray('Phoneme Target Names', wbString(PHTN, 'Name')), wbPHWT, wbFormIDCk(WKMV, 'Base Movement Default - Walk', [MOVT, NULL]), wbFormIDCk(RNMV, 'Base Movement Default - Run', [MOVT, NULL]), wbFormIDCk(SWMV, 'Base Movement Default - Swim', [MOVT, NULL]), wbFormIDCk(FLMV, 'Base Movement Default - Fly', [MOVT, NULL]), wbFormIDCk(SNMV, 'Base Movement Default - Sneak', [MOVT, NULL]), wbFormIDCk(SPMV, 'Base Movement Default - Sprint', [MOVT, NULL]), // Start Head Data wbRStruct('Head Data', [ wbEmpty(NAM0, 'Head Data Marker', cpNormal, True), wbRStruct('Male Head Data', [ wbEmpty(MNAM, 'Male Data Marker', cpNormal, True), wbRArrayS('Head Parts', wbHeadPart), wbMorphs, wbRArrayS('Race Presets Male', wbFormIDCk(RPRM, 'Preset NPC', [NPC_, NULL])), wbRArrayS('Available Hair Colors Male', wbFormIDCk(AHCM, 'Hair Color', [CLFM, NULL])), wbRArrayS('Face Details Texture Set List Male', wbFormIDCk(FTSM, 'Texture Set', [TXST, NULL])), wbFormIDCk(DFTM, 'Default Face Texture Male', [TXST, NULL]), wbTints, wbMODL ], [], cpNormal, True), wbRStruct('Female Head Data', [ wbEmpty(NAM0, 'Head Data Marker', cpNormal, True), wbEmpty(FNAM, 'Female Data Marker', cpNormal, True), wbRArrayS('Head Parts', wbHeadPart), wbMorphs, wbRArrayS('Race Presets Female', wbFormIDCk(RPRF, 'Preset NPC', [NPC_, NULL])), wbRArrayS('Available Hair Colors Female', wbFormIDCk(AHCF, 'Hair Color', [CLFM, NULL])), wbRArrayS('Face Details Texture Set List Female', wbFormIDCk(FTSF, 'Texture Set', [TXST, NULL])), wbFormIDCk(DFTF, 'Default Face Texture Female', [TXST, NULL]), wbTints, wbMODL ], [], cpNormal, True) ], [], cpNormal, False), // End Head Data wbFormIDCk(NAM8, 'Morph race', [RACE, NULL]), wbFormIDCk(RNAM, 'Armor race', [RACE, NULL]) ], False, nil, cpNormal, False, wbRACEAfterLoad, wbRACEAfterSet); wbRecord(REFR, 'Placed Object', wbFormaterUnion(wbREFRRecordFlagsDecider, [ wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000400} 10, 'Persistent', {0x00000800} 11, 'Initially Disabled', {0x00010000} 16, 'Is Full LOD', {0x04000000} 26, 'Filter (Collision Geometry)', {0x08000000} 27, 'Bounding Box (Collision Geometry)', {0x10000000} 28, 'Reflected By Auto Water', {0x40000000} 30, 'Ground', {0x80000000} 31, 'Multibound' ], True, True)), {ACTI STAT TREE} wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000200} 9, 'Hidden From Local Map', {0x00000400} 10, 'Persistent', {0x00000800} 11, 'Initially Disabled', {0x00008000} 15, 'Visible when distant', {0x00010000} 16, 'Is Full LOD', {0x04000000} 26, 'Filter (Collision Geometry)', {0x08000000} 27, 'Bounding Box (Collision Geometry)', {0x10000000} 28, 'Reflected By Auto Water', {0x20000000} 29, 'Don''t Havok Settle', {0x40000000} 30, 'No Respawn', {0x80000000} 31, 'Multibound' ], True, True)), {CONT} wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000400} 10, 'Persistent', {0x00000800} 11, 'Initially Disabled', {0x00010000} 16, 'Is Full LOD', {0x02000000} 25, 'No AI Acquire', {0x04000000} 26, 'Filter (Collision Geometry)', {0x08000000} 27, 'Bounding Box (Collision Geometry)', {0x10000000} 28, 'Reflected By Auto Water', {0x20000000} 29, 'Don''t Havok Settle', {0x40000000} 30, 'Ground', {0x80000000} 31, 'Multibound' ], True, True)), {DOOR} wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000040} 6, 'Hidden From Local Map', {0x00000100} 8, 'Inaccessible', {0x00000400} 10, 'Persistent', {0x00000800} 11, 'Initially Disabled', {0x00010000} 16, 'Is Full LOD', {0x04000000} 26, 'Filter (Collision Geometry)', {0x08000000} 27, 'Bounding Box (Collision Geometry)', {0x10000000} 28, 'Reflected By Auto Water', {0x20000000} 29, 'Don''t Havok Settle', {0x40000000} 30, 'No Respawn', {0x80000000} 31, 'Multibound' ], True, True)), {LIGH} wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000100} 8, 'Doesn''t Light Water', {0x00000200} 9, 'Casts Shadows', {0x00000400} 10, 'Persistent', {0x00000800} 11, 'Initially Disabled', {0x00010000} 16, 'Never Fades', {0x00020000} 17, 'Doesn''t Light Landscape', {0x02000000} 25, 'No AI Acquire', {0x10000000} 28, 'Reflected By Auto Water', {0x20000000} 29, 'Don''t Havok Settle', {0x40000000} 30, 'No Respawn', {0x80000000} 31, 'Multibound' ], True, True)), {MSTT} wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000200} 9, 'Motion Blur', {0x00000400} 10, 'Persistent', {0x00000800} 11, 'Initially Disabled', {0x00010000} 16, 'Is Full LOD', {0x04000000} 26, 'Filter (Collision Geometry)', {0x08000000} 27, 'Bounding Box (Collision Geometry)', {0x10000000} 28, 'Reflected By Auto Water', {0x20000000} 29, 'Don''t Havok Settle', {0x40000000} 30, 'No Respawn', {0x80000000} 31, 'Multibound' ], True, True)), {ADDN} wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000400} 10, 'Persistent', {0x00000800} 11, 'Initially Disabled', {0x00010000} 16, 'Is Full LOD', {0x10000000} 28, 'Reflected By Auto Water', {0x20000000} 29, 'Don''t Havok Settle', {0x40000000} 30, 'No Respawn', {0x80000000} 31, 'Multibound' ], True, True)), {ALCH SCRL AMMO ARMO INGR KEYM MISC SLGM WEAP} wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000400} 10, 'Persistent', {0x00000800} 11, 'Initially Disabled', {0x00010000} 16, 'Is Full LOD', {0x02000000} 25, 'No AI Acquire', {0x10000000} 28, 'Reflected By Auto Water', {0x20000000} 29, 'Don''t Havok Settle', {0x40000000} 30, 'No Respawn', {0x80000000} 31, 'Multibound' ], True, True)) ]), [ wbEDID, wbVMAD, wbFormIDCk(NAME, 'Base', [ TREE, SNDR, ACTI, DOOR, STAT, FURN, CONT, ARMO, AMMO, LVLN, LVLC, MISC, WEAP, BOOK, KEYM, ALCH, LIGH, GRAS, ASPC, IDLM, ARMA, INGR, MSTT, TACT, TXST, FLOR, SLGM, SCRL, SOUN, APPA, SPEL, ARTO, ADDN ], False, cpNormal, True), {--- Bound Contents ---} {--- Bound Data ---} wbStruct(XMBO, 'Bound Half Extents', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), {--- Primitive ---} wbStruct(XPRM, 'Primitive', [ wbStruct('Bounds', [ wbFloat('X', cpNormal, True, 2, 4), wbFloat('Y', cpNormal, True, 2, 4), wbFloat('Z', cpNormal, True, 2, 4) ]), wbStruct('Color', [ {84} wbFloat('Red', cpNormal, False, 255, 0), {88} wbFloat('Green', cpNormal, False, 255, 0), {92} wbFloat('Blue', cpNormal, False, 255, 0) ]), wbFloat('Unknown'), wbInteger('Type', itU32, wbEnum([ 'None', 'Box', 'Sphere', 'Portal Box', 'Unknown 4' ])) ]), wbUnknown(XORD), wbStruct(XOCP, 'Occlusion Plane Data', [ wbStruct('Size', [ wbFloat('Width', cpNormal, False, 2), wbFloat('Height', cpNormal, False, 2) ]), wbStruct('Position', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), wbStruct('Rotation (Quaternion?)', [ wbFloat('q1'), wbFloat('q2'), wbFloat('q3'), wbFloat('q4') ]) ]), wbArray(XPOD, 'Portal Data', wbStruct('References', [ wbFormIDCk('Origin', [REFR, NULL]), wbFormIDCk('Destination', [REFR, NULL]) ])), wbStruct(XPTL, 'Room Portal (unused)', [ wbStruct('Size', [ wbFloat('Width', cpNormal, False, 2), wbFloat('Height', cpNormal, False, 2) ]), wbStruct('Position', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ]), wbStruct('Rotation (Quaternion?)', [ wbFloat('q1'), wbFloat('q2'), wbFloat('q3'), wbFloat('q4') ]) ], cpIgnore), // removed by CK wbRStruct('Bound Data', [ wbStruct(XRMR, 'Header', [ wbInteger('Linked Rooms Count', itU8), wbInteger('Flags', itU8, wbFlags([ 'Unknown 1', 'Unknown 2', 'Unknown 3', 'Unknown 4', 'Unknown 5', 'Unknown 6', 'Has Image Space', 'Has Lighting Template' ])), wbByteArray('Unknown', 2) ]), wbFormIDCk(LNAM, 'Lighting Template', [LGTM]), wbFormIDCk(INAM, 'Image Space', [IMGS]), wbRArrayS('Linked Rooms', wbFormIDCk(XLRM, 'Linked Room', [REFR]) ) ], []), wbEmpty(XMBP, 'MultiBound Primitive Marker', cpIgnore), wbXRGD, wbXRGB, wbFloat(XRDS, 'Radius'), {--- Reflected By / Refracted By ---} wbRArrayS('Reflected/Refracted By', wbStructSK(XPWR, [0], 'Water', [ wbFormIDCk('Reference', [REFR]), wbInteger('Type', itU32, wbFlags([ 'Reflection', 'Refraction' ])) ], cpNormal, False, nil, 1) ), {--- Lit Water ---} wbRArrayS('Lit Water', wbFormIDCk(XLTW, 'Water', [REFR]) ), {--- Emittance ---} wbFormIDCk(XEMI, 'Emittance', [LIGH, REGN]), wbStruct(XLIG, 'Light Data', [ wbFloat('FOV 90+/-'), wbFloat('Fade 1.35+/-'), wbByteArray('Unknown', 4), wbFloat('Shadow Depth Bias'), wbByteArray('Unknown', 4) // optional ], cpNormal, False, nil, 4), wbStruct(XALP, 'Alpha', [ wbInteger('Cutoff', itU8), wbInteger('Base', itU8) ]), {--- Teleport ---} wbStruct(XTEL, 'Teleport Destination', [ wbFormIDCk('Door', [REFR], True), wbPosRot, wbInteger('Flags', itU32, wbFlags([ 'No Alarm' ])) ]), wbFormIDCk(XTNM, 'Teleport Message Box', [MESG]), {--- MultiBound ---} wbFormIDCk(XMBR, 'MultiBound Reference', [REFR]), wbByteArray(XWCN, 'Unknown', 0, cpIgnore), // leftover wbByteArray(XWCS, 'Unknown', 0, cpIgnore), // leftover wbStruct(XWCU, 'Water Velocity', [ wbFloat('X Offset'), wbFloat('Y Offset'), wbFloat('Z Offset'), wbByteArray('Unknown', 4), wbFloat('X Angle'), wbFloat('Y Angle'), wbFloat('Z Angle'), wbByteArray('Unknown', 0) ]), wbStruct(XCVL, 'Unknown', [ wbByteArray('Unknown', 4), wbFloat('X Angle'), wbByteArray('Unknown', 4) ]), wbFormIDCk(XCZR, 'Unknown', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA, NULL]), wbUnknown(XCZA), wbFormIDCk(XCZC, 'Unknown', [CELL, NULL]), wbXSCL, wbFormIDCk(XSPC, 'Spawn Container', [REFR]), {--- Activate Parents ---} wbRStruct('Activate Parents', [ wbInteger(XAPD, 'Flags', itU8, wbFlags([ 'Parent Activate Only' ], True)), wbRArrayS('Activate Parent Refs', wbStructSK(XAPR, [0], 'Activate Parent Ref', [ wbFormIDCk('Reference', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA]), wbFloat('Delay') ]) ) ], []), wbFormIDCk(XLIB, 'Leveled Item Base Object', [LVLI]), wbXLCM, wbFormIDCk(XLCN, 'Persistent Location', [LCTN]), {>>> COLL form Index value <<<} wbInteger(XTRI, 'Collision Layer', itU32), {--- Lock ---} {>>Lock Tab for REFR when 'Locked' is Unchecked this record is not present <<<} wbStruct(XLOC, 'Lock Data', [ wbInteger('Level', itU8, wbEnum([], [ 1, 'Novice', 25, 'Apprentice', 50, 'Adept', 75, 'Expert', 100, 'Master', 255, 'Requires Key' ])), wbByteArray('Unused', 3, cpIgnore), wbFormIDCkNoReach('Key', [KEYM, NULL]), wbInteger('Flags', itU8, wbFlags(['', '', 'Leveled Lock'])), wbByteArray('Unused', 3, cpIgnore), wbByteArray('Unused', 8, cpIgnore) ], cpNormal, False, nil, 4), wbFormIDCk(XEZN, 'Encounter Zone', [ECZN]), {--- Generated Data ---} wbStruct(XNDP, 'Navigation Door Link', [ wbFormIDCk('Navigation Mesh', [NAVM]), wbInteger('Teleport Marker Triangle', itS16, wbREFRNavmeshTriangleToStr, wbStringToInt), wbByteArray('Unused', 2, cpIgnore) ]), wbArray(XLRT, 'Location Ref Type', wbFormIDCk('Ref', [LCRT, NULL])), wbEmpty(XIS2, 'Ignored by Sandbox'), {--- Ownership ---} wbOwnership, wbInteger(XCNT, 'Item Count', itS32), wbFloat(XCHG, 'Charge'), wbFormIDCk(XLRL, 'Location Reference', [LCRT, LCTN, NULL], False, cpBenignIfAdded), wbXESP, wbRArray('Linked References', wbStruct(XLKR, 'Linked Reference', [ wbFormIDCk('Keyword/Ref', [KYWD, PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA, NULL]), wbFormIDCk('Ref', [PLYR, ACHR, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA]) ], cpNormal, False, nil, 1)), wbRArray('Patrol', wbRStruct('Data', [ wbFloat(XPRD, 'Idle Time', cpNormal, True), wbEmpty(XPPA, 'Patrol Script Marker', cpNormal, True), wbFormIDCk(INAM, 'Idle', [IDLE, NULL], False, cpNormal, True), wbByteArray(SCHR, 'Unused', 0, cpIgnore, false, false, wbNeverShow), wbByteArray(SCTX, 'Unused', 0, cpIgnore, false, false, wbNeverShow), wbPDTOs ], [])), {--- Flags ---} wbInteger(XACT, 'Action Flag', itU32, wbFlags([ 'Use Default', 'Activate', 'Open', 'Open by Default' ])), wbFloat(XHTW, 'Head-Tracking Weight'), wbFloat(XFVC, 'Favor Cost'), wbEmpty(ONAM, 'Open by Default'), {--- Map Data ---} wbRStruct('Map Marker', [ wbEmpty(XMRK, 'Map Marker Data'), wbInteger(FNAM, 'Map Flags', itU8, wbFlags([ {0x01} 'Visible', {0x02} 'Can Travel To', {0x04} '"Show All" Hidden' ]), cpNormal, True), wbFULLReq, wbStruct(TNAM, '', [ wbInteger('Type', itU8, wbEnum([], [ 0, 'None', 1, 'City', 2, 'Town', 3, 'Settlement', 4, 'Cave', 5, 'Camp', 6, 'Fort', 7, 'Nordic Ruins', 8, 'Dwemer Ruin', 9, 'Shipwreck', 10, 'Grove', 11, 'Landmark', 12, 'Dragon Lair', 13, 'Farm', 14, 'Wood Mill', 15, 'Mine', 16, 'Imperial Camp', 17, 'Stormcloak Camp', 18, 'Doomstone', 19, 'Wheat Mill', 20, 'Smelter', 21, 'Stable', 22, 'Imperial Tower', 23, 'Clearing', 24, 'Pass', 25, 'Altar', 26, 'Rock', 27, 'Lighthouse', 28, 'Orc Stronghold', 29, 'Giant Camp', 30, 'Shack', 31, 'Nordic Tower', 32, 'Nordic Dwelling', 33, 'Docks', 34, 'Shrine', 35, 'Riften Castle', 36, 'Riften Capitol', 37, 'Windhelm Castle', 38, 'Windhelm Capitol', 39, 'Whiterun Castle', 40, 'Whiterun Capitol', 41, 'Solitude Castle', 42, 'Solitude Capitol', 43, 'Markarth Castle', 44, 'Markarth Capitol', 45, 'Winterhold Castle', 46, 'Winterhold Capitol', 47, 'Morthal Castle', 48, 'Morthal Capitol', 49, 'Falkreath Castle', 50, 'Falkreath Capitol', 51, 'Dawnstar Castle', 52, 'Dawnstar Capitol', 53, 'DLC02 - Temple of Miraak', 54, 'DLC02 - Raven Rock', 55, 'DLC02 - Beast Stone', 56, 'DLC02 - Tel Mithryn', 57, 'DLC02 - To Skyrim', 58, 'DLC02 - To Solstheim', 59, 'Custom 59', 60, 'Custom 60', 61, 'Custom 61', 62, 'Custom 62', 63, 'Custom 63', 64, 'Custom 64', 65, 'Custom 65', 66, 'Custom 66', 67, 'Custom 67', 68, 'Custom 68', 69, 'Custom 69', 70, 'Custom 70', 71, 'Custom 71', 72, 'Custom 72', 73, 'Custom 73', 74, 'Custom 74', 75, 'Custom 75', 76, 'Custom 76', 77, 'Custom 77', 78, 'Custom 78', 79, 'Custom 79', 80, 'Custom 80', 81, 'Custom 81', 82, 'Custom 82', 83, 'Custom 83', 84, 'Custom 84', 85, 'Custom 85', 86, 'Custom 86', 87, 'Custom 87', 88, 'Custom 88', 89, 'Custom 89', 90, 'Custom 90', 91, 'Custom 91', 92, 'Custom 92', 93, 'Custom 93', 94, 'Custom 94', 95, 'Custom 95', 96, 'Custom 96', 97, 'Custom 97', 98, 'Custom 98', 99, 'Custom 99' ])), wbByteArray('Unused', 1) ], cpNormal, True) ], []), {--- Attach reference ---} wbFormIDCk(XATR, 'Attach Ref', [REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA]), wbXLOD, wbDataPosRot ], True, wbPlacedAddInfo, cpNormal, False, wbREFRAfterLoad); wbRecord(REGN, 'Region', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000040} 6, 'Border Region' ])), [ wbEDID, wbStruct(RCLR, 'Map Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8), wbByteArray('Unknown', 1) ], cpNormal, True), {>>> Skyrim.esm has some incorrect FormIDs here, probably leftover <<<} wbFormIDCkNoReach(WNAM, 'Worldspace', [WRLD]), wbRArray('Region Areas', wbRStruct('Region Area', [ wbInteger(RPLI, 'Edge Fall-off', itU32), wbArray(RPLD, 'Region Point List Data', wbStruct('Point', [ wbFloat('X'), wbFloat('Y') ]), 0, wbRPLDAfterLoad) ], [])), wbRArrayS('Region Data Entries', wbRStructSK([0], 'Region Data Entry', [ {always starts with an RDAT} wbStructSK(RDAT, [0], 'Data Header', [ wbInteger('Type', itU32, wbEnum([ {0} 'Unknown 0', {1} 'Unknown 1', {2} 'Objects', {3} 'Weather', {4} 'Map', {5} 'Land', {6} 'Grass', {7} 'Sound', {8} 'Imposter', {9} 'Unknown 10', {10}'Unknown 11', {11}'Unknown 12', {12}'Unknown 13', {13}'Unknown 14', {14}'Unknown 15', {15}'Unknown 16' ])), wbInteger('Flags', itU8, wbFlags([ 'Override' ])), wbInteger('Priority', itU8), wbByteArray('Unknown') ], cpNormal, True), {--- Icon ---} wbICON, {--- Sound ---} wbFormIDCk(RDMO, 'Music', [MUSC], False, cpNormal, False, wbREGNSoundDontShow), wbArrayS(RDSA, 'Sounds', wbStructSK([0], 'Sound', [ wbFormIDCk('Sound', [SNDR, NULL]), wbInteger('Flags', itU32, wbFlags([ {0x00000001}'Pleasant', {0x00000002}'Cloudy', {0x00000004}'Rainy', {0x00000008}'Snowy' ])), wbFloat('Chance') ]), 0, cpNormal, False, nil, nil, wbREGNSoundDontShow), {--- Map ---} wbLString(RDMP, 'Map Name', 0, cpTranslate, False, wbREGNMapDontShow), {followed by one of these: } {--- Objects ---} wbArray(RDOT, 'Objects', wbStruct('Object', [ wbFormIDCk('Object', [TREE, FLOR, STAT, LTEX, MSTT]), wbInteger('Parent Index', itU16, wbHideFFFF), wbByteArray('Unknown', 2), wbFloat('Density'), wbInteger('Clustering', itU8), wbInteger('Min Slope', itU8), wbInteger('Max Slope', itU8), wbInteger('Flags', itU8, wbFlags([ {0}'Conform to slope', {1}'Paint Vertices', {2}'Size Variance +/-', {3}'X +/-', {4}'Y +/-', {5}'Z +/-', {6}'Tree', {7}'Huge Rock' ])), wbInteger('Radius wrt Parent', itU16), wbInteger('Radius', itU16), wbFloat('Min Height'), wbFloat('Max Height'), wbFloat('Sink'), wbFloat('Sink Variance'), wbFloat('Size Variance'), wbStruct('Angle Variance', [ wbInteger('X', itU16), wbInteger('Y', itU16), wbInteger('Z', itU16) ]), wbByteArray('Unknown', 2), wbByteArray('Unknown', 4) ]), 0, nil, nil, cpNormal, False, wbREGNObjectsDontShow), {--- Grass ---} wbArrayS(RDGS, 'Grasses', wbStructSK([0], 'Grass', [ wbFormIDCk('Grass', [GRAS]), wbByteArray('Unknown',4) ]), 0, cpNormal, False, nil, nil, wbREGNGrassDontShow), {--- Weather ---} wbArrayS(RDWT, 'Weather Types', wbStructSK([0], 'Weather Type', [ wbFormIDCk('Weather', [WTHR]), wbInteger('Chance', itU32), wbFormIDCk('Global', [GLOB, NULL]) ]), 0, cpNormal, False, nil, nil, wbREGNWeatherDontShow) ], [])) ], True); wbRecord(SOUN, 'Sound Marker', [ wbEDID, wbOBNDReq, wbUnknown(FNAM, cpIgnore), // leftover, unused wbUnknown(SNDD, cpIgnore), // leftover, unused wbFormIDCk(SDSC, 'Sound Descriptor', [SNDR, NULL]) ]); wbSPIT := wbStruct(SPIT, 'Data', [ wbInteger('Base Cost', itU32), wbInteger('Flags', itU32, wbFlags([ {0x00000001} 'Manual Cost Calc', {0x00000002} 'Unknown 2', {0x00000004} 'Unknown 3', {0x00000008} 'Unknown 4', {0x00000010} 'Unknown 5', {0x00000020} 'Unknown 6', {0x00000040} 'Unknown 7', {0x00000080} 'Unknown 8', {0x00000100} 'Unknown 9', {0x00000200} 'Unknown 10', {0x00000400} 'Unknown 11', {0x00000800} 'Unknown 12', {0x00001000} 'Unknown 13', {0x00002000} 'Unknown 14', {0x00004000} 'Unknown 15', {0x00008000} 'Unknown 16', {0x00010000} 'Unknown 17', {0x00020000} 'PC Start Spell', {0x00040000} 'Unknown 19', {0x00080000} 'Area Effect Ignores LOS', {0x00100000} 'Ignore Resistance', {0x00200000} 'No Absorb/Reflect', {0x00400000} 'Unknown 23', {0x00800000} 'No Dual Cast Modification', {0x01000000} 'Unknown 25', {0x02000000} 'Unknown 26', {0x04000000} 'Unknown 27', {0x08000000} 'Unknown 28', {0x10000000} 'Unknown 29', {0x20000000} 'Unknown 30', {0x40000000} 'Unknown 31', {0x80000000} 'Unknown 32' ])), wbInteger('Type', itU32, wbEnum([ {0} 'Spell', {1} 'Disease', {2} 'Power', {3} 'Lesser Power', {4} 'Ability', {5} 'Poison', {6} 'Unknown 6', {7} 'Unknown 7', {8} 'Unknown 8', {9} 'Unknown 9', {10} 'Addiction', {11} 'Voice' ])), wbFloat('Charge Time'), wbInteger('Cast Type', itU32, wbCastEnum), wbInteger('Target Type', itU32, wbTargetEnum), wbFloat('Cast Duration'), wbFloat('Range'), wbFormIDCk('Half-cost Perk', [NULL, PERK]) ], cpNormal, True); wbRecord(SPEL, 'Spell', [ wbEDID, wbOBNDReq, wbFULL, wbKSIZ, wbKWDAs, wbMDOB, wbETYP, wbDESCReq, wbSPIT, wbEffectsReq ], False, nil, cpNormal, False, nil, wbKeywordsAfterSet); wbRecord(SCRL, 'Scroll', [ wbEDID, wbOBNDReq, wbFULL, wbKSIZ, wbKWDAs, wbMDOB, wbETYP, wbDESC, wbMODL, wbDEST, wbYNAM, wbZNAM, wbStruct(DATA, 'Item', [ wbInteger('Value', itU32), wbFloat('Weight') ], cpNormal, True), wbSPIT, wbEffectsReq ], False, nil, cpNormal, False, nil, wbKeywordsAfterSet); wbRecord(STAT, 'Static', wbFlags(wbRecordFlagsFlags, [ {0x00000001} { 0} '', {0x00000002} { 1} '', {0x00000004} { 2} 'Never Fades', {0x00000008} { 3} '', {0x00000010} { 4} '', {0x00000020} { 5} 'Deleted', {0x00000040} { 6} 'Has Tree LOD', {0x00000080} { 7} 'Add-On LOD Object', {0x00000100} { 8} '', {0x00000200} { 9} 'Hidden From Local Map', {0x00000400} {10} '', {0x00000800} {11} 'Unknown 11', // present in Skyrim.esm but can't be set {0x00001000} {12} '', {0x00002000} {13} '', {0x00004000} {14} '', {0x00008000} {15} 'Has Distant LOD', {0x00010000} {16} 'Unknown 16', // present in Skyrim.esm but can't be set {0x00020000} {17} 'Uses HD LOD Texture', {0x00040000} {18} '', {0x00080000} {19} 'Has Currents', {0x00100000} {20} '', {0x00200000} {21} '', {0x00400000} {22} '', {0x00800000} {23} 'Is Marker', {0x01000000} {24} '', {0x02000000} {25} 'Obstacle', {0x04000000} {26} 'NavMesh Generation - Filter', {0x08000000} {27} 'NavMesh Generation - Bounding Box', {0x10000000} {28} 'Show In World Map', {0x20000000} {29} '', {0x40000000} {30} 'NavMesh Generation - Ground', {0x80000000} {31} '' ], [11, 16]), [ wbEDID, wbOBNDReq, wbMODL, IsSSE( wbStruct(DNAM, 'Direction Material', [ wbFloat('Max Angle (30-120)'), wbFormIDCk('Material', [MATO, NULL]), // SSE wbInteger('Flags', itU8, wbFlags([ {0x01} 'Considered Snow' ])), wbByteArray('Unused', 3, cpIgnore) ], cpNormal, True, nil, 2), wbStruct(DNAM, 'Direction Material', [ wbFloat('Max Angle (30-120)'), wbFormIDCk('Material', [MATO, NULL]) ], cpNormal, True) ), wbArray(MNAM, 'Distant LOD', wbStruct('LOD', [ {>>> Contains null-terminated mesh filename followed by random data up to 260 bytes <<<} wbString(True, 'Mesh', 260) //wbByteArray('Mesh', 260, cpIgnore) ]), [ 'Level 0', 'Level 1', 'Level 2', 'Level 3' ], cpNormal, False ) ]); wbRecord(TES4, 'Main File Header', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000001} 0, 'ESM', {0x00000080} 7, 'Localized' ], False), True), [ wbStruct(HEDR, 'Header', [ wbFloat('Version'), wbInteger('Number of Records', itU32), wbInteger('Next Object ID', itU32) ], cpNormal, True), wbByteArray(OFST, 'Unknown', 0, cpIgnore), wbByteArray(DELE, 'Unknown', 0, cpIgnore), wbString(CNAM, 'Author', 0, cpTranslate, True), wbString(SNAM, 'Description', 0, cpTranslate), wbRArray('Master Files', wbRStruct('Master File', [ wbString(MAST, 'Filename', 0, cpNormal, True), wbByteArray(DATA, 'Unknown', 8, cpIgnore, True) ], [ONAM])), wbArray(ONAM, 'Overridden Forms', wbFormIDCk('Form', [ACHR, LAND, NAVM, REFR, PGRE, PHZD, PMIS, PARW, PBAR, PBEA, PCON, PFLA]), 0, nil, nil, cpNormal, False{, wbTES4ONAMDontShow}), wbByteArray(SCRN, 'Screenshot'), wbUnknown(INTV), wbUnknown(INCC) ], True, nil, cpNormal, True, wbRemoveOFST); end; procedure DefineTES5o; begin wbRecord(TREE, 'Tree', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00008000} 15, 'Has Distant LOD' ])), [ wbEDID, wbVMAD, wbOBNDReq, wbMODL, wbFormIDCK(PFIG, 'Ingredient', [INGR, ALCH, MISC, LVLI, NULL]), wbFormIDCK(SNAM, 'Harvest Sound', [SNDR, NULL]), wbStruct(PFPC, 'Ingredient Production', [ wbInteger('Spring', itU8), wbInteger('Summer', itU8), wbInteger('Fall', itU8), wbInteger('Winter', itU8) ]), wbFULL, wbStruct(CNAM, 'Tree Data', [ wbFloat('Trunk Flexibility'), wbFloat('Branch Flexibility'), //wbByteArray('Unknown', 32), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Leaf Amplitude'), wbFloat('Leaf Frequency') ], cpNormal, True) ]); wbRecord(FLOR, 'Flora', [ wbEDID, wbVMAD, wbOBNDReq, wbFULLReq, wbMODL, wbDEST, wbKSIZ, wbKWDAs, wbUnknown(PNAM), wbLString(RNAM, 'Activate Text Override', 0, cpTranslate), wbUnknown(FNAM), wbFormIDCk(PFIG, 'Ingredient', [INGR, ALCH, LVLI, MISC, NULL]), wbFormIDCK(SNAM, 'Sound', [SNDR, NULL]), wbStruct(PFPC, 'Seasonal ingredient production', [ wbInteger('Spring', itU8), wbInteger('Summer ', itU8), wbInteger('Fall', itU8), wbInteger('Winter', itU8) ], cpNormal, True) ], False, nil, cpNormal, False, nil, wbKeywordsAfterSet); wbRecord(WATR, 'Water', [ wbEDID, wbFULL, wbRArray('Unused', wbString(NNAM, 'Noise Map', 0, cpIgnore, False)), // leftover wbInteger(ANAM, 'Opacity', itU8, nil, cpNormal, True), wbInteger(FNAM, 'Flags', itU8, wbFlags([ {0x01} 'Causes Damage', {0x02} 'Unknown 1', {0x04} 'Unknown 2', {0x08} IsSSE('Enable Flowmap', 'Unknown 3'), {0x10} IsSSE('Blend Normals', 'Unknown 4'), {0x20} 'Unknown 5', {0x40} 'Unknown 6', {0x80} 'Unknown 7' ]), cpNormal, True), wbByteArray(MNAM, 'Unused', 0, cpIgnore, False), // leftover wbFormIDCk(TNAM, 'Material', [MATT]), wbFormIDCk(SNAM, 'Open Sound', [SNDR, NULL]), wbFormIDCk(XNAM, 'Spell', [SPEL]), wbFormIDCk(INAM, 'Image Space', [IMGS]), wbInteger(DATA, 'Damage Per Second', itU16, nil, cpNormal, True, True), IsSSE( wbStruct(DNAM, 'Visual Data', [ wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Specular Properties - Sun Specular Power'), wbFloat('Water Properties - Reflectivity Amount'), wbFloat('Water Properties - Fresnel Amount'), wbByteArray('Unknown', 4), wbFloat('Fog Properties - Above Water - Fog Distance - Near Plane'), wbFloat('Fog Properties - Above Water - Fog Distance - Far Plane'), wbByteColors('Shallow Color'), wbByteColors('Deep Color'), wbByteColors('Reflection Color'), wbByteArray('Unknown', 4), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Displacement Simulator - Starting Size'), wbFloat('Displacement Simulator - Force'), wbFloat('Displacement Simulator - Velocity'), wbFloat('Displacement Simulator - Falloff'), wbFloat('Displacement Simulator - Dampner'), wbFloat('Unknown'), wbFloat('Noise Properties - Noise Falloff'), wbFloat('Noise Properties - Layer One - Wind Direction'), wbFloat('Noise Properties - Layer Two - Wind Direction'), wbFloat('Noise Properties - Layer Three - Wind Direction'), wbFloat('Noise Properties - Layer One - Wind Speed'), wbFloat('Noise Properties - Layer Two - Wind Speed'), wbFloat('Noise Properties - Layer Three - Wind Speed'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Fog Properties - Above Water - Fog Amount'), wbFloat('Unknown'), wbFloat('Fog Properties - Under Water - Fog Amount'), wbFloat('Fog Properties - Under Water - Fog Distance - Near Plane'), wbFloat('Fog Properties - Under Water - Fog Distance - Far Plane'), wbFloat('Water Properties - Refraction Magnitude'), wbFloat('Specular Properties - Specular Power'), wbFloat('Unknown'), wbFloat('Specular Properties - Specular Radius'), wbFloat('Specular Properties - Specular Brightness'), wbFloat('Noise Properties - Layer One - UV Scale'), wbFloat('Noise Properties - Layer Two - UV Scale'), wbFloat('Noise Properties - Layer Three - UV Scale'), wbFloat('Noise Properties - Layer One - Amplitude Scale'), wbFloat('Noise Properties - Layer Two - Amplitude Scale'), wbFloat('Noise Properties - Layer Three - Amplitude Scale'), wbFloat('Water Properties - Reflection Magnitude'), wbFloat('Specular Properties - Sun Sparkle Magnitude'), wbFloat('Specular Properties - Sun Specular Magnitude'), wbFloat('Depth Properties - Reflections'), wbFloat('Depth Properties - Refraction'), wbFloat('Depth Properties - Normals'), wbFloat('Depth Properties - Specular Lighting'), wbFloat('Specular Properties - Sun Sparkle Power'), // SSE wbFloat('Noise Properties - Flowmap Scale') ], cpNormal, True, nil, 57), wbStruct(DNAM, 'Visual Data', [ wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Specular Properties - Sun Specular Power'), wbFloat('Water Properties - Reflectivity Amount'), wbFloat('Water Properties - Fresnel Amount'), wbByteArray('Unknown', 4), wbFloat('Fog Properties - Above Water - Fog Distance - Near Plane'), wbFloat('Fog Properties - Above Water - Fog Distance - Far Plane'), wbByteColors('Shallow Color'), wbByteColors('Deep Color'), wbByteColors('Reflection Color'), wbByteArray('Unknown', 4), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Displacement Simulator - Starting Size'), wbFloat('Displacement Simulator - Force'), wbFloat('Displacement Simulator - Velocity'), wbFloat('Displacement Simulator - Falloff'), wbFloat('Displacement Simulator - Dampner'), wbFloat('Unknown'), wbFloat('Noise Properties - Noise Falloff'), wbFloat('Noise Properties - Layer One - Wind Direction'), wbFloat('Noise Properties - Layer Two - Wind Direction'), wbFloat('Noise Properties - Layer Three - Wind Direction'), wbFloat('Noise Properties - Layer One - Wind Speed'), wbFloat('Noise Properties - Layer Two - Wind Speed'), wbFloat('Noise Properties - Layer Three - Wind Speed'), wbFloat('Unknown'), wbFloat('Unknown'), wbFloat('Fog Properties - Above Water - Fog Amount'), wbFloat('Unknown'), wbFloat('Fog Properties - Under Water - Fog Amount'), wbFloat('Fog Properties - Under Water - Fog Distance - Near Plane'), wbFloat('Fog Properties - Under Water - Fog Distance - Far Plane'), wbFloat('Water Properties - Refraction Magnitude'), wbFloat('Specular Properties - Specular Power'), wbFloat('Unknown'), wbFloat('Specular Properties - Specular Radius'), wbFloat('Specular Properties - Specular Brightness'), wbFloat('Noise Properties - Layer One - UV Scale'), wbFloat('Noise Properties - Layer Two - UV Scale'), wbFloat('Noise Properties - Layer Three - UV Scale'), wbFloat('Noise Properties - Layer One - Amplitude Scale'), wbFloat('Noise Properties - Layer Two - Amplitude Scale'), wbFloat('Noise Properties - Layer Three - Amplitude Scale'), wbFloat('Water Properties - Reflection Magnitude'), wbFloat('Specular Properties - Sun Sparkle Magnitude'), wbFloat('Specular Properties - Sun Specular Magnitude'), wbFloat('Depth Properties - Reflections'), wbFloat('Depth Properties - Refraction'), wbFloat('Depth Properties - Normals'), wbFloat('Depth Properties - Specular Lighting'), wbFloat('Specular Properties - Sun Sparkle Power') ]) ), wbByteArray(GNAM, 'Unused', 0, cpNormal, True), // leftover wbStruct(NAM0, 'Linear Velocity', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ], cpNormal, False), wbStruct(NAM1, 'Angular Velocity', [ wbFloat('X'), wbFloat('Y'), wbFloat('Z') ], cpNormal, False), wbString(NAM2, 'Noise Layer One - Noise Texture', 0, cpNormal, False), wbString(NAM3, 'Noise Layer Two - Noise Texture', 0, cpNormal, False), wbString(NAM4, 'Noise Layer Three - Noise Texture', 0, cpNormal, False), // SSE wbString(NAM5, 'Flow Normals - Noise Texture', 0, cpNormal, False) ], False, nil, cpNormal, False); wbRecord(WEAP, 'Weapon', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00000004} 2, 'Non-Playable' ])), [ wbEDID, wbVMAD, wbOBNDReq, wbFULL, wbMODL, wbICON, wbEITM, wbInteger(EAMT, 'Enchantment Amount', itU16), wbDEST, wbETYP, wbFormIDCk(BIDS, 'Block Bash Impact Data Set', [IPDS, NULL]), wbFormIDCk(BAMT, 'Alternate Block Material', [MATT, NULL]), wbYNAM, wbZNAM, wbKSIZ, wbKWDAs, wbDESC, wbRStruct('Has Scope', [ wbString(MOD3, 'Model Filename'), wbByteArray(MO3T, 'Texture Files Hashes', 0, cpIgnore, false, false, wbNeverShow), wbMO3S ], []), wbByteArray(NNAM, 'Unused', 0, cpIgnore, False), // leftover wbFormIDCk(INAM, 'Impact Data Set', [IPDS, NULL]), wbFormIDCk(WNAM, '1st Person Model Object', [STAT, NULL]), wbFormIDCk(SNAM, 'Attack Sound', [SNDR]), wbFormIDCk(XNAM, 'Attack Sound 2D', [SNDR]), wbFormIDCk(NAM7, 'Attack Loop Sound', [SNDR]), wbFormIDCk(TNAM, 'Attack Fail Sound', [SNDR]), wbFormIDCk(UNAM, 'Idle Sound', [SNDR]), wbFormIDCk(NAM9, 'Equip Sound', [SNDR]), wbFormIDCk(NAM8, 'Unequip Sound', [SNDR]), wbStruct(DATA, 'Game Data', [ wbInteger('Value', itU32), wbFloat('Weight'), wbInteger('Damage', itU16) ]), wbStruct(DNAM, 'Data', [ wbInteger('Animation Type', itU8, wbWeaponAnimTypeEnum), wbByteArray('Unused', 3, cpIgnore), wbFloat('Speed'), wbFloat('Reach'), wbInteger('Flags', itU16, wbFlags([ {0x0001}'Ignores Normal Weapon Resistance', {0x0002}'Automatic (unused)', {0x0004}'Has Scope (unused)', {0x0008}'Can''t Drop', {0x0010}'Hide Backpack (unused)', {0x0020}'Embedded Weapon (unused)', {0x0040}'Don''t Use 1st Person IS Anim (unused)', {0x0080}'Non-playable' ], [1, 2, 4, 5, 6])), wbByteArray('Unused', 2, cpIgnore), wbFloat('Sight FOV'), wbByteArray('Unknown', 4), wbInteger('Base VATS To-Hit Chance', itU8), wbInteger('Attack Animation', itU8, wbAttackAnimationEnum), wbInteger('# Projectiles', itU8), wbInteger('Embedded Weapon AV (unused)', itU8), wbFloat('Range Min'), wbFloat('Range Max'), wbInteger('On Hit', itU32, wbEnum([ 'No formula behaviour', 'Dismember only', 'Explode only', 'No dismember/explode' ])), wbInteger('Flags2', itU32, wbFlags([ {0x00000001} 'Player Only', {0x00000002} 'NPCs Use Ammo', {0x00000004} 'No Jam After Reload (unused)', {0x00000008} 'Unknown 4', {0x00000010} 'Minor Crime', {0x00000020} 'Range Fixed', {0x00000040} 'Not Used in Normal Combat', {0x00000080} 'Unknown 8', {0x00000100} 'Don''t Use 3rd Person IS Anim (unused)', {0x00000200} 'Burst Shot', {0x00000400} 'Rumble - Alternate', {0x00000800} 'Long Bursts', {0x00001000} 'Non-hostile', {0x00002000} 'Bound Weapon' ], [2, 8])), wbFloat('Animation Attack Mult'), wbFloat('Unknown'), wbFloat('Rumble - Left Motor Strength'), wbFloat('Rumble - Right Motor Strength'), wbFloat('Rumble - Duration'), wbByteArray('Unknown', 12), wbInteger('Skill', itS32, wbSkillEnum), wbByteArray('Unknown', 8), wbInteger('Resist', itS32, wbActorValueEnum), wbByteArray('Unknown', 4), wbFloat('Stagger') ]), IsSSE( wbStruct(CRDT, 'Critical Data', [ wbInteger('Damage', itU16), wbByteArray('Unknown', 2), wbFloat('% Mult'), wbInteger('Flags', itU8, wbFlags([ 'On Death' ])), // SSE wbByteArray('Unused', 3, cpIgnore), wbByteArray('Unknown', 4), wbFormIDCk('Effect', [SPEL, NULL]), wbByteArray('Unknown', 4) ]), wbStruct(CRDT, 'Critical Data', [ wbInteger('Damage', itU16), wbByteArray('Unknown', 2), wbFloat('% Mult'), wbInteger('Flags', itU8, wbFlags([ 'On Death' ])), wbByteArray('Unused', 3, cpIgnore), wbFormIDCk('Effect', [SPEL, NULL]) ]) ), wbInteger(VNAM, 'Detection Sound Level', itU32, wbSoundlevelEnum), wbFormIDCk(CNAM, 'Template', [WEAP]) ], False, nil, cpNormal, False, wbWEAPAfterLoad, wbKeywordsAfterSet); wbRecord(WRLD, 'Worldspace', wbFlags(wbRecordFlagsFlags, wbFlagsList([ {0x00080000} 19, 'Can''t Wait' ])), [ wbEDID, wbRArray(IsSSE('Large References', 'Unused RNAM'), wbStruct(RNAM, 'Grid', [ wbInteger('Y', itS16, nil, cpIgnore), wbInteger('X', itS16, nil, cpIgnore), wbArray('References', wbStruct('Reference', [ wbFormIDCk('Ref', [REFR], False, cpIgnore), wbInteger('Y', itS16, nil, cpIgnore), wbInteger('X', itS16, nil, cpIgnore) ]), -1) ]), cpIgnore, False, nil, nil, wbNeverShow ), wbMaxHeightDataWRLD, wbFULL, wbStruct(WCTR, 'Fixed Dimensions Center Cell', [ wbInteger('X', itS16), wbInteger('Y', itS16) ]), wbFormIDCk(LTMP, 'Interior Lighting', [LGTM]), wbFormIDCk(XEZN, 'Encounter Zone', [ECZN, NULL]), wbFormIDCk(XLCN, 'Location', [LCTN, NULL]), wbRStruct('Parent', [ wbFormIDCk(WNAM, 'Worldspace', [WRLD]), wbStruct(PNAM, '', [ wbInteger('Flags', itU8, wbFlags([ {0x0001}'Use Land Data', {0x0002}'Use LOD Data', {0x0004}'Don''t Use Map Data', {0x0008}'Use Water Data', {0x0010}'Use Climate Data', {0x0020}'Use Image Space Data (unused)', {0x0040}'Use Sky Cell' ], [5])), wbByteArray('Unknown', 1) ], cpNormal, True) ], []), wbFormIDCk(CNAM, 'Climate', [CLMT]), wbFormIDCk(NAM2, 'Water', [WATR]), wbFormIDCk(NAM3, 'LOD Water Type', [WATR]), wbFloat(NAM4, 'LOD Water Height'), wbStruct(DNAM, 'Land Data', [ wbFloat('Default Land Height'), wbFloat('Default Water Height') ]), wbString(ICON, 'Map Image'), wbRStruct('Cloud Model', [wbMODL], []), wbStruct(MNAM, 'Map Data', [ wbStruct('Usable Dimensions', [ wbInteger('X', itS32), wbInteger('Y', itS32) ]), wbStruct('Cell Coordinates', [ wbStruct('NW Cell', [ wbInteger('X', itS16), wbInteger('Y', itS16) ]), wbStruct('SE Cell', [ wbInteger('X', itS16), wbInteger('Y', itS16) ]) ]), wbStruct('Camera Data', [ wbFloat('Min Height'), wbFloat('Max Height'), wbFloat('Initial Pitch') ]) ], cpNormal, False, nil, 2), wbStruct(ONAM, 'World Map Offset Data', [ wbFloat('World Map Scale'), wbFloat('Cell X Offset'), wbFloat('Cell Y Offset'), wbFloat('Cell Z Offset') ], cpNormal, True), wbFloat(NAMA, 'Distant LOD Multiplier'), wbInteger(DATA, 'Flags', itU8, wbFlags([ {0x01} 'Small World', {0x02} 'Can''t Fast Travel', {0x04} 'Unknown 3', {0x08} 'No LOD Water', {0x10} 'No Landscape', {0x20} 'No Sky', {0x40} 'Fixed Dimensions', {0x80} 'No Grass' ]), cpNormal, True), {>>> Object Bounds doesn't show up in CK <<<} wbRStruct('Object Bounds', [ wbStruct(NAM0, 'Min', [ wbFloat('X', cpNormal, False, 1/4096), wbFloat('Y', cpNormal, False, 1/4096) ], cpIgnore, True), wbStruct(NAM9, 'Max', [ wbFloat('X', cpNormal, False, 1/4096), wbFloat('Y', cpNormal, False, 1/4096) ], cpIgnore, True) ], []), wbFormIDCk(ZNAM, 'Music', [MUSC]), wbString(NNAM, 'Canopy Shadow (unused)', 0, cpIgnore), wbString(XNAM, 'Water Noise Texture'), wbString(TNAM, 'HD LOD Diffuse Texture'), wbString(UNAM, 'HD LOD Normal Texture'), wbString(XWEM, 'Water Environment Map (unused)', 0, cpIgnore), wbOFST ], False, nil, cpNormal, False, wbWRLDAfterLoad); wbRecord(WTHR, 'Weather', [ wbEDID, wbString(_00_0TX, 'Cloud Texture Layer #0'), wbString(_10_0TX, 'Cloud Texture Layer #1'), wbString(_20_0TX, 'Cloud Texture Layer #2'), wbString(_30_0TX, 'Cloud Texture Layer #3'), wbString(_40_0TX, 'Cloud Texture Layer #4'), wbString(_50_0TX, 'Cloud Texture Layer #5'), wbString(_60_0TX, 'Cloud Texture Layer #6'), wbString(_70_0TX, 'Cloud Texture Layer #7'), wbString(_80_0TX, 'Cloud Texture Layer #8'), wbString(_90_0TX, 'Cloud Texture Layer #9'), wbString(_3A_0TX, 'Cloud Texture Layer #10'), wbString(_3B_0TX, 'Cloud Texture Layer #11'), wbString(_3C_0TX, 'Cloud Texture Layer #12'), wbString(_3D_0TX, 'Cloud Texture Layer #13'), wbString(_3E_0TX, 'Cloud Texture Layer #14'), wbString(_3F_0TX, 'Cloud Texture Layer #15'), wbString(_40h_0TX, 'Cloud Texture Layer #16'), wbString(A0TX, 'Cloud Texture Layer #17'), wbString(B0TX, 'Cloud Texture Layer #18'), wbString(C0TX, 'Cloud Texture Layer #19'), wbString(D0TX, 'Cloud Texture Layer #20'), wbString(E0TX, 'Cloud Texture Layer #21'), wbString(F0TX, 'Cloud Texture Layer #22'), wbString(G0TX, 'Cloud Texture Layer #23'), wbString(H0TX, 'Cloud Texture Layer #24'), wbString(I0TX, 'Cloud Texture Layer #25'), wbString(J0TX, 'Cloud Texture Layer #26'), wbString(K0TX, 'Cloud Texture Layer #27'), wbString(L0TX, 'Cloud Texture Layer #28'), wbByteArray(DNAM, 'Unused', 0, cpIgnore), wbByteArray(CNAM, 'Unused', 0, cpIgnore), wbByteArray(ANAM, 'Unused', 0, cpIgnore), wbByteArray(BNAM, 'Unused', 0, cpIgnore), wbUnknown(LNAM), wbFormIDCK(MNAM, 'Precipitation Type', [SPGD, NULL]), wbFormIDCK(NNAM, 'Visual Effect', [RFCT, NULL], False, cpNormal, True), wbByteArray(ONAM, 'Unused', 0, cpIgnore), wbRStruct('Cloud Speed', [ wbArray(RNAM, 'Y Speed', wbInteger('Layer', itU8, wbCloudSpeedToStr, wbCloudSpeedToInt)), wbArray(QNAM, 'X Speed', wbInteger('Layer', itU8, wbCloudSpeedToStr, wbCloudSpeedToInt)) ], []), wbArray(PNAM, 'Cloud Colors', wbWeatherColors('Layer')), wbArray(JNAM, 'Cloud Alphas', wbStruct('Layer', [ wbFloat('Sunrise'), wbFloat('Day'), wbFloat('Sunset'), wbFloat('Night') ])), {>>> not as an array since last entries are omitted in skyrim.esm <<<} wbStruct(NAM0, 'Weather Colors', [ wbWeatherColors('Sky-Upper'), wbWeatherColors('Fog Near'), wbWeatherColors('Unknown'), wbWeatherColors('Ambient'), wbWeatherColors('Sunlight'), wbWeatherColors('Sun'), wbWeatherColors('Stars'), wbWeatherColors('Sky-Lower'), wbWeatherColors('Horizon'), wbWeatherColors('Effect Lighting'), wbWeatherColors('Cloud LOD Diffuse'), wbWeatherColors('Cloud LOD Ambient'), wbWeatherColors('Fog Far'), wbWeatherColors('Sky Statics'), wbWeatherColors('Water Multiplier'), wbWeatherColors('Sun Glare'), wbWeatherColors('Moon Glare') ], cpNormal, True, nil, 13), wbStruct(FNAM, 'Fog Distance', [ wbFloat('Day - Near'), wbFloat('Day - Far'), wbFloat('Night - Near'), wbFloat('Night - Far'), wbFloat('Day - Power'), wbFloat('Night - Power'), wbFloat('Day - Max'), wbFloat('Night - Max') ], cpNormal, True), wbStruct(DATA, 'Data', [ wbInteger('Wind Speed', itU8), // scaled 0..1 wbByteArray('Unknown', 2), wbInteger('Trans Delta', itU8), // scaled 0..0,25 wbInteger('Sun Glare', itU8), // scaled 0..1 wbInteger('Sun Damage', itU8), // scaled 0..1 wbInteger('Precipitation - Begin Fade In', itU8), // scaled 0..1 wbInteger('Precipitation - End Fade Out', itU8), // scaled 0..1 wbInteger('Thunder/Lightning - Begin Fade In', itU8), wbInteger('Thunder/Lightning - End Fade Out', itU8), wbInteger('Thunder/Lightning - Frequency', itU8), wbInteger('Flags', itU8, wbFlags([ {0x01} 'Weather - Pleasant', {0x02} 'Weather - Cloudy', {0x04} 'Weather - Rainy', {0x08} 'Weather - Snow', {0x10} 'Sky Statics - Always Visible', {0x20} 'Sky Statics - Follows Sun Position' ])), wbStruct('Lightning Color', [ wbInteger('Red', itU8), wbInteger('Green', itU8), wbInteger('Blue', itU8) ]), wbInteger('Visual Effect - Begin', itU8), // scaled 0..1 wbInteger('Visual Effect - End', itU8), // scaled 0..1 wbInteger('Wind Direction', itU8), // scaled 0..360 wbInteger('Wind Direction Range', itU8) // scaled 0..180 ], cpNormal, True), wbInteger(NAM1, 'Disabled Cloud Layers', itU32, wbFlags(['0','1','2','3','4','5','6','7','8','9','10','11','12','13','14','15','16','17','18','19','20','21','22','23','24','25','26','27','28','29','30','31'])), wbRArray('Sounds', wbStruct(SNAM, 'Sound', [ wbFormIDCK('Sound', [SNDR, SOUN, NULL]), wbInteger('Type', itU32, wbEnum([ {0x01} 'Default', {0x02} 'Precipitation', {0x04} 'Wind', {0x08} 'Thunder' ])) ]) ), wbRArrayS('Sky Statics', wbFormIDCk(TNAM, 'Static', [STAT, NULL])), wbStruct(IMSP, 'Image Spaces', [ wbFormIDCK('Sunrise', [IMGS, NULL]), wbFormIDCK('Day', [IMGS, NULL]), wbFormIDCK('Sunset', [IMGS, NULL]), wbFormIDCK('Night', [IMGS, NULL]) ]), // SSE wbStruct(HNAM, 'Volumetric Lighting', [ wbFormIDCK('Sunrise', [VOLI, NULL]), wbFormIDCK('Day', [VOLI, NULL]), wbFormIDCK('Sunset', [VOLI, NULL]), wbFormIDCK('Night', [VOLI, NULL]) ]), wbRStruct('Directional Ambient Lighting Colors', [ wbAmbientColors(DALC, 'Sunrise'), wbAmbientColors(DALC, 'Day'), wbAmbientColors(DALC, 'Sunset'), wbAmbientColors(DALC, 'Night') ], [], cpNormal, True), wbByteArray(NAM2, 'Unused', 0, cpIgnore), wbByteArray(NAM3, 'Unused', 0, cpIgnore), wbRStruct('Aurora', [wbMODL], []), wbFormIDCk(GNAM, 'Sun Glare Lens Flare', [LENS]) ]); if IsSSE then begin wbRecord(VOLI, 'Volumetric Lighting', [ wbEDID, wbFloat(CNAM, 'Intensity'), wbFloat(DNAM, 'Custom Color - Contribution'), wbFloat(ENAM, 'Red', cpNormal, False, 255, 0), wbFloat(FNAM, 'Green', cpNormal, False, 255, 0), wbFloat(GNAM, 'Blue', cpNormal, False, 255, 0), wbFloat(HNAM, 'Density - Contribution'), wbFloat(INAM, 'Density - Size'), wbFloat(JNAM, 'Density - Wind Speed'), wbFloat(KNAM, 'Density - Falling Speed'), wbFloat(LNAM, 'Phase Function - Contribution'), wbFloat(MNAM, 'Phase Function - Scattering'), wbFloat(NNAM, 'Sampling Repartition - Range Factor') { max 1.0 } ]); wbRecord(LENS, 'Lens Flare', [ wbEDID, wbFloat(CNAM, 'Color Influence'), wbFloat(DNAM, 'Fade Distance Radius Scale'), wbInteger(LFSP, 'Count', itU32, nil, cpBenign), wbRArray('Lens Flare Sprites', wbRStruct('Flare', [ wbString(DNAM, 'Lens Flare Sprite ID'), wbString(FNAM, 'Texture'), wbStruct(LFSD, 'Lens Flare Data', [ wbFloatColors('Tint'), wbFloat('Width'), wbFloat('Height'), wbFloat('Position'), wbFloat('Angular Fade'), wbFloat('Opacity'), wbInteger('Flags', itU32, wbFlags([ {0x01} 'Rotates', {0x02} 'Shrinks When Occluded' ])) ]) ], []), cpNormal, False, nil, wbLENSAfterSet ) ]); end; end; {>>> Unused records, they have empty GRUP in skyrim.esm <<<} procedure DefineTES5p; begin wbRecord(CLDC, 'CLDC', [ wbEDID ]); wbRecord(HAIR, 'HAIR', [ wbEDID ]); wbRecord(PWAT, 'PWAT', [ wbEDID ]); wbRecord(RGDL, 'RGDL', [ wbEDID ]); wbRecord(SCOL, 'SCOL', [ wbEDID ]); wbRecord(SCPT, 'SCPT', [ wbEDID ]); end; procedure DefineTES5q; begin wbAddGroupOrder(GMST); wbAddGroupOrder(KYWD); wbAddGroupOrder(LCRT); wbAddGroupOrder(AACT); wbAddGroupOrder(TXST); wbAddGroupOrder(GLOB); wbAddGroupOrder(CLAS); wbAddGroupOrder(FACT); wbAddGroupOrder(HDPT); wbAddGroupOrder(HAIR);{>>> Unused in Skyrim, but contained in Skyrim.esm <<<} wbAddGroupOrder(EYES); wbAddGroupOrder(RACE); wbAddGroupOrder(SOUN); wbAddGroupOrder(ASPC); wbAddGroupOrder(MGEF); wbAddGroupOrder(SCPT);{>>> Unused in Skyrim, but contained in Skyrim.esm <<<} wbAddGroupOrder(LTEX); wbAddGroupOrder(ENCH); wbAddGroupOrder(SPEL); wbAddGroupOrder(SCRL); wbAddGroupOrder(ACTI); wbAddGroupOrder(TACT); wbAddGroupOrder(ARMO); wbAddGroupOrder(BOOK); wbAddGroupOrder(CONT); wbAddGroupOrder(DOOR); wbAddGroupOrder(INGR); wbAddGroupOrder(LIGH); wbAddGroupOrder(MISC); wbAddGroupOrder(APPA); wbAddGroupOrder(STAT); wbAddGroupOrder(SCOL);{>>> Unused in Skyrim, but contained in Skyrim.esm <<<} wbAddGroupOrder(MSTT); wbAddGroupOrder(PWAT);{>>> Unused in Skyrim, but contained in Skyrim.esm <<<} wbAddGroupOrder(GRAS); wbAddGroupOrder(TREE); wbAddGroupOrder(CLDC);{>>> Unused in Skyrim, but contained in Skyrim.esm <<<} wbAddGroupOrder(FLOR); wbAddGroupOrder(FURN); wbAddGroupOrder(WEAP); wbAddGroupOrder(AMMO); wbAddGroupOrder(NPC_); wbAddGroupOrder(LVLN); wbAddGroupOrder(KEYM); wbAddGroupOrder(ALCH); wbAddGroupOrder(IDLM); wbAddGroupOrder(COBJ); wbAddGroupOrder(PROJ); wbAddGroupOrder(HAZD); wbAddGroupOrder(SLGM); wbAddGroupOrder(LVLI); wbAddGroupOrder(WTHR); wbAddGroupOrder(CLMT); wbAddGroupOrder(SPGD); wbAddGroupOrder(RFCT); wbAddGroupOrder(REGN); wbAddGroupOrder(NAVI); wbAddGroupOrder(CELL); wbAddGroupOrder(WRLD); wbAddGroupOrder(DIAL); wbAddGroupOrder(QUST); wbAddGroupOrder(IDLE); wbAddGroupOrder(PACK); wbAddGroupOrder(CSTY); wbAddGroupOrder(LSCR); wbAddGroupOrder(LVSP); wbAddGroupOrder(ANIO); wbAddGroupOrder(WATR); wbAddGroupOrder(EFSH); wbAddGroupOrder(EXPL); wbAddGroupOrder(DEBR); wbAddGroupOrder(IMGS); wbAddGroupOrder(IMAD); wbAddGroupOrder(FLST); wbAddGroupOrder(PERK); wbAddGroupOrder(BPTD); wbAddGroupOrder(ADDN); wbAddGroupOrder(AVIF); wbAddGroupOrder(CAMS); wbAddGroupOrder(CPTH); wbAddGroupOrder(VTYP); wbAddGroupOrder(MATT); wbAddGroupOrder(IPCT); wbAddGroupOrder(IPDS); wbAddGroupOrder(ARMA); wbAddGroupOrder(ECZN); wbAddGroupOrder(LCTN); wbAddGroupOrder(MESG); wbAddGroupOrder(RGDL);{>>> Unused in Skyrim, but contained in Skyrim.esm <<<} wbAddGroupOrder(DOBJ); wbAddGroupOrder(LGTM); wbAddGroupOrder(MUSC); wbAddGroupOrder(FSTP); wbAddGroupOrder(FSTS); wbAddGroupOrder(SMBN); wbAddGroupOrder(SMQN); wbAddGroupOrder(SMEN); wbAddGroupOrder(DLBR); wbAddGroupOrder(MUST); wbAddGroupOrder(DLVW); wbAddGroupOrder(WOOP); wbAddGroupOrder(SHOU); wbAddGroupOrder(EQUP); wbAddGroupOrder(RELA); wbAddGroupOrder(SCEN); wbAddGroupOrder(ASTP); wbAddGroupOrder(OTFT); wbAddGroupOrder(ARTO); wbAddGroupOrder(MATO); if IsSSE then wbAddGroupOrder(VOLI); {New to SSE} wbAddGroupOrder(MOVT); wbAddGroupOrder(SNDR); wbAddGroupOrder(DUAL); wbAddGroupOrder(SNCT); wbAddGroupOrder(SOPM); wbAddGroupOrder(COLL); wbAddGroupOrder(CLFM); wbAddGroupOrder(REVB); if IsSSE then wbAddGroupOrder(LENS); {New to SSE} end; procedure DefineTES5; begin DefineTES5a; DefineTES5b; DefineTES5c; DefineTES5d; DefineTES5e; DefineTES5f; DefineTES5g; DefineTES5h; DefineTES5i; DefineTES5j; DefineTES5k; DefineTES5l; DefineTES5m; DefineTES5n; DefineTES5o; DefineTES5p; DefineTES5q; if IsSSE then begin SetLength(wbOfficialDLC, 3); wbOfficialDLC[0] := 'Dawnguard.esm'; wbOfficialDLC[1] := 'HearthFires.esm'; wbOfficialDLC[2] := 'Dragonborn.esm'; end; end; initialization end. ================================================ FILE: lib/xedit/wbHelpers.pas ================================================ {******************************************************************************* The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. *******************************************************************************} unit wbHelpers; {$I wbDefines.inc} interface uses Classes, Windows, SysUtils, Graphics, ShellAPI, ShlObj, IniFiles, Registry, wbInterface, Imaging, ImagingTypes; Const CRCSeed = $ffffffff; {$IFDEF WIN64} CRC32tab : Array[0..255] of DWord = ( $00000000, $77073096, $ee0e612c, $990951ba, $076dc419, $706af48f, $e963a535, $9e6495a3, $0edb8832, $79dcb8a4, $e0d5e91e, $97d2d988, $09b64c2b, $7eb17cbd, $e7b82d07, $90bf1d91, $1db71064, $6ab020f2, $f3b97148, $84be41de, $1adad47d, $6ddde4eb, $f4d4b551, $83d385c7, $136c9856, $646ba8c0, $fd62f97a, $8a65c9ec, $14015c4f, $63066cd9, $fa0f3d63, $8d080df5, $3b6e20c8, $4c69105e, $d56041e4, $a2677172, $3c03e4d1, $4b04d447, $d20d85fd, $a50ab56b, $35b5a8fa, $42b2986c, $dbbbc9d6, $acbcf940, $32d86ce3, $45df5c75, $dcd60dcf, $abd13d59, $26d930ac, $51de003a, $c8d75180, $bfd06116, $21b4f4b5, $56b3c423, $cfba9599, $b8bda50f, $2802b89e, $5f058808, $c60cd9b2, $b10be924, $2f6f7c87, $58684c11, $c1611dab, $b6662d3d, $76dc4190, $01db7106, $98d220bc, $efd5102a, $71b18589, $06b6b51f, $9fbfe4a5, $e8b8d433, $7807c9a2, $0f00f934, $9609a88e, $e10e9818, $7f6a0dbb, $086d3d2d, $91646c97, $e6635c01, $6b6b51f4, $1c6c6162, $856530d8, $f262004e, $6c0695ed, $1b01a57b, $8208f4c1, $f50fc457, $65b0d9c6, $12b7e950, $8bbeb8ea, $fcb9887c, $62dd1ddf, $15da2d49, $8cd37cf3, $fbd44c65, $4db26158, $3ab551ce, $a3bc0074, $d4bb30e2, $4adfa541, $3dd895d7, $a4d1c46d, $d3d6f4fb, $4369e96a, $346ed9fc, $ad678846, $da60b8d0, $44042d73, $33031de5, $aa0a4c5f, $dd0d7cc9, $5005713c, $270241aa, $be0b1010, $c90c2086, $5768b525, $206f85b3, $b966d409, $ce61e49f, $5edef90e, $29d9c998, $b0d09822, $c7d7a8b4, $59b33d17, $2eb40d81, $b7bd5c3b, $c0ba6cad, $edb88320, $9abfb3b6, $03b6e20c, $74b1d29a, $ead54739, $9dd277af, $04db2615, $73dc1683, $e3630b12, $94643b84, $0d6d6a3e, $7a6a5aa8, $e40ecf0b, $9309ff9d, $0a00ae27, $7d079eb1, $f00f9344, $8708a3d2, $1e01f268, $6906c2fe, $f762575d, $806567cb, $196c3671, $6e6b06e7, $fed41b76, $89d32be0, $10da7a5a, $67dd4acc, $f9b9df6f, $8ebeeff9, $17b7be43, $60b08ed5, $d6d6a3e8, $a1d1937e, $38d8c2c4, $4fdff252, $d1bb67f1, $a6bc5767, $3fb506dd, $48b2364b, $d80d2bda, $af0a1b4c, $36034af6, $41047a60, $df60efc3, $a867df55, $316e8eef, $4669be79, $cb61b38c, $bc66831a, $256fd2a0, $5268e236, $cc0c7795, $bb0b4703, $220216b9, $5505262f, $c5ba3bbe, $b2bd0b28, $2bb45a92, $5cb36a04, $c2d7ffa7, $b5d0cf31, $2cd99e8b, $5bdeae1d, $9b64c2b0, $ec63f226, $756aa39c, $026d930a, $9c0906a9, $eb0e363f, $72076785, $05005713, $95bf4a82, $e2b87a14, $7bb12bae, $0cb61b38, $92d28e9b, $e5d5be0d, $7cdcefb7, $0bdbdf21, $86d3d2d4, $f1d4e242, $68ddb3f8, $1fda836e, $81be16cd, $f6b9265b, $6fb077e1, $18b74777, $88085ae6, $ff0f6a70, $66063bca, $11010b5c, $8f659eff, $f862ae69, $616bffd3, $166ccf45, $a00ae278, $d70dd2ee, $4e048354, $3903b3c2, $a7672661, $d06016f7, $4969474d, $3e6e77db, $aed16a4a, $d9d65adc, $40df0b66, $37d83bf0, $a9bcae53, $debb9ec5, $47b2cf7f, $30b5ffe9, $bdbdf21c, $cabac28a, $53b39330, $24b4a3a6, $bad03605, $cdd70693, $54de5729, $23d967bf, $b3667a2e, $c4614ab8, $5d681b02, $2a6f2b94, $b40bbe37, $c30c8ea1, $5a05df1b, $2d02ef8d ); {$ENDIF} function wbDistance(const a, b: TwbVector): Single; overload function wbDistance(const a, b: IwbMainRecord): Single; overload; function wbStringToSignatures(aSignatures: string): TwbSignatures; function wbGetSiblingREFRsWithin(const aMainRecord: IwbMainRecord; aDistance: Single): TDynMainRecords; function wbGetSiblingRecords(const aElement: IwbElement; aSignatures: TwbSignatures; aOverrides: Boolean): TDynMainRecords; function FindMatchText(Strings: TStrings; const Str: string): Integer; function IsFileESM(const aFileName: string): Boolean; function IsFileESP(const aFileName: string): Boolean; function IsFileESL(const aFileName: string): Boolean; procedure DeleteDirectory(const DirName: string); function FullPathToFilename(aString: string): string; procedure wbFlipBitmap(aBitmap: TBitmap; MirrorType: Integer); // MirrorType: 1 - horizontal, 2 - vertical, 0 - both function wbAlphaBlend(DestDC, X, Y, Width, Height, SrcDC, SrcX, SrcY, SrcWidth, SrcHeight, Alpha: integer): Boolean; procedure SaveFont(aIni: TMemIniFile; aSection, aName: string; aFont: TFont); procedure LoadFont(aIni: TMemIniFile; aSection, aName: string; aFont: TFont); function wbDDSDataToBitmap(aData: TBytes; Bitmap: TBitmap): Boolean; function wbDDSStreamToBitmap(aStream: TStream; Bitmap: TBitmap): Boolean; function wbCRC32Data(aData: TBytes): Cardinal; function wbCRC32File(aFileName: string): Cardinal; function wbDecodeCRCList(const aList: string): TDynCardinalArray; function wbSHA1Data(aData: TBytes): string; function wbSHA1File(aFileName: string): string; function wbMD5Data(aData: TBytes): string; function wbMD5File(aFileName: string): string; function wbIsAssociatedWithExtension(aExt: string): Boolean; function wbAssociateWithExtension(aExt, aName, aDescr: string): Boolean; type PnxLeveledListCheckCircularStack = ^TnxLeveledListCheckCircularStack; TnxLeveledListCheckCircularStack = record rllcLast : PnxLeveledListCheckCircularStack; rllcMainRecord : IwbMainRecord; end; procedure wbLeveledListCheckCircular(const aMainRecord: IwbMainRecord; aStack: PnxLeveledListCheckCircularStack); type TnxFastStringList = class(TStringList) protected function CompareStrings(const S1, S2: string): Integer; override; public constructor CreateSorted(aDups : TDuplicates = dupError); procedure Clear(aFreeObjects: Boolean = False); reintroduce; end; TnxFastStringListCS = class(TnxFastStringList) public procedure AfterConstruction; override; end; TnxFastStringListIC = class(TnxFastStringList) end; function wbExtractNameFromPath(aPathName: String): String; function wbCounterAfterSet(aCounterName: String; const aElement: IwbElement): Boolean; function wbCounterByPathAfterSet(aCounterName: String; const aElement: IwbElement): Boolean; function wbCounterContainerAfterSet(aCounterName: String; anArrayName: String; const aElement: IwbElement; DeleteOnEmpty: Boolean = True): Boolean; function wbCounterContainerByPathAfterSet(aCounterName: String; anArrayName: String; const aElement: IwbElement): Boolean; function wbFormVerDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement; aMinimum: Integer): Integer; function wbFormVer78Decider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; // BSA helper function MakeDataFileName(FileName, DataPath: String): String; function FindBSAs(IniName, DataPath: String; var bsaNames: TStringList; var bsaMissing: TStringList): Integer; function HasBSAs(ModName, DataPath: String; Exact, modini: Boolean; var bsaNames: TStringList; var bsaMissing: TStringList): Integer; implementation uses wbSort; procedure wbLeveledListCheckCircular(const aMainRecord: IwbMainRecord; aStack: PnxLeveledListCheckCircularStack); var Stack : TnxLeveledListCheckCircularStack; s : string; CER : IwbContainerElementRef; LLE : IwbContainerElementRef; i : Integer; LVLO : IwbContainerElementRef; Reference : IwbContainerElementRef; MainRecord : IwbMainRecord; begin Stack.rllcLast := aStack; Stack.rllcMainRecord := aMainRecord; while Assigned(aStack) do begin if aStack.rllcMainRecord.LoadOrderFormID = aMainRecord.LoadOrderFormID then begin s := aMainRecord.Name; aStack := Stack.rllcLast; while Assigned(aStack) do begin s := ' -> ' + s; s := aStack.rllcMainRecord.Name + s; if aStack.rllcMainRecord.LoadOrderFormID = aMainRecord.LoadOrderFormID then Break; aStack := aStack.rllcLast; end; s := 'Circular Leveled List found: ' + s; raise Exception.Create(s); end; aStack := aStack.rllcLast; end; if aMainRecord.IsTagged then Exit; aMainRecord.Tag; if Supports(aMainRecord, IwbContainerElementRef, CER) then begin if Supports(CER.ElementByName['Leveled List Entries'], IwbContainerElementRef, LLE) then begin for i := 0 to Pred(LLE.ElementCount) do if Supports(LLE.Elements[i], IwbContainerElementRef, LVLO) then begin if Supports(LVLO.ElementByName['Reference'], IwbContainerElementRef, Reference) then begin if Supports(Reference.LinksTo, IwbMainRecord, MainRecord) then begin if (MainRecord.Signature = aMainRecord.Signature) then begin MainRecord := MainRecord.WinningOverride; wbLeveledListCheckCircular(MainRecord, @Stack); end; end; end; end; end; end; end; function Vec3Subtract(out vOut: TwbVector; const v1, v2: TwbVector): TwbVector; begin with vOut do begin x:= v1.x - v2.x; y:= v1.y - v2.y; z:= v1.z - v2.z; end; Result := vOut; end; function Vec3Length(const v: TwbVector): Single; begin with v do Result:= Sqrt(x*x + y*y + z*z); end; function wbDistance(const a, b: TwbVector): Single; var t: TwbVector; begin Result := Vec3Length(Vec3Subtract(t,a,b)); end; function wbDistance(const a, b: IwbMainRecord): Single; overload; var PosA, PosB: TwbVector; begin if not a.GetPosition(PosA) then raise Exception.Create('GetPosition failed'); if not b.GetPosition(PosB) then raise Exception.Create('GetPosition failed'); Result := wbDistance(PosA, PosB); end; function wbStringToSignatures(aSignatures: string): TwbSignatures; var i: integer; s: AnsiString; begin with TStringList.Create do try if Pos(',', aSignatures) <> 0 then Delimiter := ',' else Delimiter := ' '; StrictDelimiter := True; DelimitedText := aSignatures; for i := 0 to Pred(Count) do begin s := AnsiString(Strings[i]); if Length(s) >= SizeOf(TwbSignature) then begin SetLength(Result, Succ(Length(Result))); System.Move(s[1], Result[Pred(Length(Result))][0], SizeOf(TwbSignature)); end; end; finally Free; end; end; function wbGetSiblingREFRsWithin(const aMainRecord: IwbMainRecord; aDistance: Single): TDynMainRecords; var Count : Integer; Position : TwbVector; MaxLoadOrder: Integer; procedure FindREFRs(const aElement: IwbElement); var MainRecord : IwbMainRecord; Container : IwbContainerElementRef; i : Integer; Temp : TwbVector; begin if Supports(aElement, IwbMainRecord, MainRecord) then begin if not (aMainRecord.LoadOrderFormID = MainRecord.LoadOrderFormID) and MainRecord.GetPosition(Temp) and (wbDistance(Temp,Position) <= aDistance) then begin if High(Result) < Count then SetLength(Result, Length(Result) * 2); Result[Count] := MainRecord.HighestOverrideOrSelf[MaxLoadOrder]; Inc(Count); end; end else if Supports(aElement, IwbContainerElementRef, Container) then for i := 0 to Pred(Container.ElementCount) do FindREFRs(Container.Elements[i]); end; var GroupRecord : IwbGroupRecord; CellMaster : IwbMainRecord; i, j : Integer; begin Result := nil; if not aMainRecord.GetPosition(Position) then Exit; if not Supports(aMainRecord.Container, IwbGroupRecord, GroupRecord) then Exit; if not (GroupRecord.GroupType in [8..10]) then Exit; CellMaster := GroupRecord.ChildrenOf; if not Assigned(CellMaster) then Exit; CellMaster := CellMaster.MasterOrSelf; MaxLoadOrder := aMainRecord._File.LoadOrder; Count := 0; SetLength(Result, 1024); FindREFRs(CellMaster.ChildGroup); for i := 0 to Pred(CellMaster.OverrideCount) do if CellMaster.Overrides[i]._File.LoadOrder <= aMainRecord._File.LoadOrder then FindREFRs(CellMaster.Overrides[i]) else Break; SetLength(Result, Count); if Length(Result) > 1 then begin wbMergeSort(@Result[0], Length(Result), CompareElementsFormIDAndLoadOrder); j := 0; for i := Succ(Low(Result)) to High(Result) do begin if (Result[j].LoadOrderFormID <> Result[i].LoadOrderFormID) and not (Result[j].IsDeleted) then Inc(j); if j <> i then Result[j] := Result[i]; end; SetLength(Result, Succ(j)); end; end; function wbGetSiblingRecords(const aElement: IwbElement; aSignatures: TwbSignatures; aOverrides: Boolean): TDynMainRecords; procedure FindRecords(const aElement: IwbElement; var aSignatures: TwbSignatures; var Records: TDynMainRecords; var Count: Integer); var MainRecord : IwbMainRecord; Container : IwbContainerElementRef; i : Integer; begin if Supports(aElement, IwbMainRecord, MainRecord) then begin for i := Low(aSignatures) to High(aSignatures) do if MainRecord.Signature = aSignatures[i] then begin if High(Records) < Count then SetLength(Records, Length(Records) * 2); Records[Count] := MainRecord; Inc(Count); Break; end; end else if Supports(aElement, IwbContainerElementRef, Container) then for i := 0 to Pred(Container.ElementCount) do FindRecords(Container.Elements[i], aSignatures, Records, Count); end; var MainRecord, Master : IwbMainRecord; i, j, Count : Integer; begin Count := 0; SetLength(Result, 4096); if Supports(aElement, IwbMainRecord, MainRecord) then begin FindRecords(MainRecord.ChildGroup, aSignatures, Result, Count); // include overrides from plugins loaded later for that record if aOverrides then begin Master := MainRecord.MasterOrSelf; for i := 0 to Pred(Master.OverrideCount) do if Master.Overrides[i]._File.LoadOrder > MainRecord._File.LoadOrder then FindRecords(Master.Overrides[i].ChildGroup, aSignatures, Result, Count); end; end else // if Group or File object is passed, no overrides FindRecords(aElement, aSignatures, Result, Count); SetLength(Result, Count); // removing duplicates (overridden records) if aOverrides and (Length(Result) > 1) then begin wbMergeSort(@Result[0], Length(Result), CompareElementsFormIDAndLoadOrder); j := 0; for i := Succ(Low(Result)) to High(Result) do begin if Result[j].LoadOrderFormID <> Result[i].LoadOrderFormID then Inc(j); if j <> i then Result[j] := Result[i]; end; SetLength(Result, Succ(j)); end; end; function FindMatchText(Strings: TStrings; const Str: string): Integer; begin for Result := 0 to Strings.Count-1 do if SameText(Strings[Result], Str) then Exit; Result := -1; end; function IsFileESM(const aFileName: string): Boolean; const ghostesm = '.esm.ghost'; begin Result := SameText(ExtractFileExt(aFileName), '.esm') or SameText(Copy(aFileName, Length(aFileName) - Length(ghostesm) + 1, Length(ghostesm)), ghostesm) end; function IsFileESP(const aFileName: string): Boolean; const ghostesp = '.esp.ghost'; begin Result := SameText(ExtractFileExt(aFileName), '.esp') or SameText(Copy(aFileName, Length(aFileName) - Length(ghostesp) + 1, Length(ghostesp)), ghostesp) end; function IsFileESL(const aFileName: string): Boolean; const ghostesp = '.esl.ghost'; begin Result := SameText(ExtractFileExt(aFileName), '.esl') or SameText(Copy(aFileName, Length(aFileName) - Length(ghostesp) + 1, Length(ghostesp)), ghostesp) end; procedure DeleteDirectory(const DirName: string); var FileOp: TSHFileOpStruct; begin FillChar(FileOp, SizeOf(FileOp), 0); FileOp.wFunc := FO_DELETE; FileOp.pFrom := PChar(DirName+#0);//double zero-terminated FileOp.fFlags := FOF_SILENT or FOF_NOERRORUI or FOF_NOCONFIRMATION; SHFileOperation(FileOp); end; function FullPathToFilename(aString: string): string; var i: Integer; s: string; begin s := aString; for i := Length(s) downto 1 do if Copy(s, i, 3) = ' \ ' then begin Delete(s, i, 1); Delete(s, i+1, 1); end else if Copy(s, i, 2) = ' \' then begin Delete(s, i, 1); end else if s[i] = '"' then s[i] := '''' else if s[i] = ':' then s[i] := '-' else if s[i] = '/' then s[i] := ' '; while (Length(s)>0) and (s[Length(s)]=' ') do Delete(s, Length(s), 1); Result := s; end; procedure wbFlipBitmap(aBitmap: TBitmap; MirrorType: Integer); var MemBmp: TBitmap; Dest: TRect; begin if not Assigned(aBitmap) then Exit; MemBmp := TBitmap.Create; try MemBmp.Assign(aBitmap); case MirrorType of 1: begin Dest.Left := MemBmp.Width; Dest.Top := 0; Dest.Right := -MemBmp.Width; Dest.Bottom := MemBmp.Height end; 2: begin Dest.Left := 0; Dest.Top := MemBmp.Height; Dest.Right := MemBmp.Width; Dest.Bottom := -MemBmp.Height end; 0: begin Dest.Left := MemBmp.Width; Dest.Top := MemBmp.Height; Dest.Right := -MemBmp.Width; Dest.Bottom := -MemBmp.Height end; end; StretchBlt(MemBmp.Canvas.Handle, Dest.Left, Dest.Top, Dest.Right, Dest.Bottom, MemBmp.Canvas.Handle, 0, 0, MemBmp.Width, MemBmp.Height, SRCCOPY); aBitmap.Assign(MemBmp); finally FreeAndNil(MemBmp); end; end; function wbAlphaBlend(DestDC, X, Y, Width, Height, SrcDC, SrcX, SrcY, SrcWidth, SrcHeight, Alpha: integer): Boolean; var BlendFunc: TBlendFunction; begin BlendFunc.BlendOp := AC_SRC_OVER; BlendFunc.BlendFlags := 0; BlendFunc.SourceConstantAlpha := Alpha; if Alpha = 255 then BlendFunc.AlphaFormat := AC_SRC_ALPHA else BlendFunc.AlphaFormat := 0; Result := Windows.AlphaBlend(DestDC, X, Y, Width, Height, SrcDC, SrcX, SrcY, SrcWidth, SrcHeight, BlendFunc); end; procedure SaveFont(aIni: TMemIniFile; aSection, aName: string; aFont: TFont); begin aIni.WriteString(aSection, aName + 'Name', aFont.Name); aIni.WriteInteger(aSection, aName + 'CharSet', aFont.CharSet); aIni.WriteInteger(aSection, aName + 'Color', aFont.Color); aIni.WriteInteger(aSection, aName + 'Size', aFont.Size); aIni.WriteInteger(aSection, aName + 'Style', Byte(aFont.Style)); end; procedure LoadFont(aIni: TMemIniFile; aSection, aName: string; aFont: TFont); begin aFont.Name := aIni.ReadString(aSection, aName + 'Name', aFont.Name); aFont.CharSet := TFontCharSet(aIni.ReadInteger(aSection, aName + 'CharSet', aFont.CharSet)); aFont.Color := TColor(aIni.ReadInteger(aSection, aName + 'Color', aFont.Color)); aFont.Size := aIni.ReadInteger(aSection, aName + 'Size', aFont.Size); aFont.Style := TFontStyles(Byte(aIni.ReadInteger(aSection, aName + 'Style', Byte(aFont.Style)))); end; var crctbl: array[0..7] of array[0..255] of cardinal; procedure CRCInit; var c: cardinal; i, j: integer; begin; for i:=0 to 255 do begin; c:=i; for j:=1 to 8 do if odd(c) then c:=(c shr 1) xor $EDB88320 else c:=(c shr 1); crctbl[0][i]:=c; end; for i:=0 to 255 do begin; c:=crctbl[0][i]; for j:=1 to 7 do begin; c:=(c shr 8) xor crctbl[0][byte(c)]; crctbl[j][i]:=c; end; end; end; {$IFDEF WIN64} function crc32_update(inbuffer: pointer; buffersize, crc: DWord): DWord; // crc-32. Processes 4 bytes at a time. type PDWord = ^DWord; PByte = ^Byte; var currptr: pointer; i: byte; begin currptr := inbuffer; Result := crc; while buffersize > 4 do begin Result := Result xor PDWord(currptr)^; inc(PByte(currptr), 4); Result := (Result shr 8) xor Crc32Tab[Byte(Result)]; Result := (Result shr 8) xor Crc32Tab[Byte(Result)]; Result := (Result shr 8) xor CRC32Tab[Byte(Result)]; Result := (Result shr 8) xor crc32Tab[Byte(Result)]; dec(buffersize, 4); end; for i := 1 to buffersize do begin Result := CRC32tab[Byte(Result xor DWord(PByte(currptr)^))] xor (Result shr 8); inc(PByte(currptr), 1); end; end; {$ENDIF} Function CRCend( crc : DWord ): DWord; begin CRCend := (crc xor CRCSeed); end; function ShaCrcRefresh(OldCRC: cardinal; BufPtr: pointer; BufLen: integer): cardinal; // Fast CRC32 calculator // (c) Aleksandr Sharahov 2009 // Free for any use {$IFDEF WIN64} begin Result := crc32_update(BufPtr, BufLen, OldCRC); {$ENDIF WIN64} {$IFDEF WIN32} asm test edx, edx jz @ret neg ecx jz @ret push ebx @head: test dl, 3 jz @bodyinit movzx ebx, byte [edx] inc edx xor bl, al shr eax, 8 xor eax, [ebx*4 + crctbl] inc ecx jnz @head pop ebx @ret: ret @bodyinit: sub edx, ecx add ecx, 8 jg @bodydone push esi push edi mov edi, edx mov edx, eax @bodyloop: mov ebx, [edi + ecx - 4] xor edx, [edi + ecx - 8] movzx esi, bl mov eax, [esi*4 + crctbl + 1024*3] movzx esi, bh xor eax, [esi*4 + crctbl + 1024*2] shr ebx, 16 movzx esi, bl xor eax, [esi*4 + crctbl + 1024*1] movzx esi, bh xor eax, [esi*4 + crctbl + 1024*0] movzx esi, dl xor eax, [esi*4 + crctbl + 1024*7] movzx esi, dh xor eax, [esi*4 + crctbl + 1024*6] shr edx, 16 movzx esi, dl xor eax, [esi*4 + crctbl + 1024*5] movzx esi, dh xor eax, [esi*4 + crctbl + 1024*4] add ecx, 8 jg @done mov ebx, [edi + ecx - 4] xor eax, [edi + ecx - 8] movzx esi, bl mov edx, [esi*4 + crctbl + 1024*3] movzx esi, bh xor edx, [esi*4 + crctbl + 1024*2] shr ebx, 16 movzx esi, bl xor edx, [esi*4 + crctbl + 1024*1] movzx esi, bh xor edx, [esi*4 + crctbl + 1024*0] movzx esi, al xor edx, [esi*4 + crctbl + 1024*7] movzx esi, ah xor edx, [esi*4 + crctbl + 1024*6] shr eax, 16 movzx esi, al xor edx, [esi*4 + crctbl + 1024*5] movzx esi, ah xor edx, [esi*4 + crctbl + 1024*4] add ecx, 8 jle @bodyloop mov eax, edx @done: mov edx, edi pop edi pop esi @bodydone: sub ecx, 8 jl @tail pop ebx ret @tail: movzx ebx, byte [edx + ecx]; xor bl,al; shr eax,8; xor eax, [ebx*4 + crctbl]; inc ecx; jnz @tail; pop ebx ret {$ENDIF WIN32} end; function wbCRC32Data(aData: TBytes): Cardinal; begin Result := not ShaCrcRefresh($FFFFFFFF, @aData[0], Length(aData)); end; function wbCRC32File(aFileName: string): Cardinal; var Data: TBytes; begin Result := 0; if FileExists(aFileName) then with TFileStream.Create(aFileName, fmOpenRead + fmShareDenyNone) do try SetLength(Data, Size); ReadBuffer(Data[0], Length(Data)); Result := wbCRC32Data(Data); finally Free; end; end; function wbDecodeCRCList(const aList: string): TDynCardinalArray; var i: Integer; s: string; j: Int64; begin Result := nil; try with TStringList.Create do try CommaText := aList; for i := 0 to Pred(Count) do begin s := Trim(Strings[i]); if Length(s) <> 8 then Abort; j := StrToInt64('$'+s); if (j < Low(Cardinal)) or (j > High(Cardinal)) then Abort; SetLength(Result, Succ(Length(Result))); Result[High(Result)] := j; end; finally Free; end; except SetLength(Result, 1); Result[0] := $FFFFFFFF; end; end; function CryptAcquireContext(var phProv: DWORD; pszContainer, pszProvider: LPCSTR; dwProvType, dwFlags: DWORD): BOOL; stdcall; external advapi32 name 'CryptAcquireContextA'; function CryptCreateHash(hProv,Algid,hKey,dwFlags: DWORD; var phHash: DWORD): BOOL; stdcall; external advapi32; function CryptHashData(hHash: DWORD; pbData: PBYTE; dwDataLen, dwFlags: DWORD): BOOL; stdcall; external advapi32; function CryptGetHashParam(hHash, dwParam: DWORD; pbData: PBYTE; var pdwDataLen: DWORD; dwFlags: DWORD): BOOL; stdcall; external advapi32; function CryptDestroyHash(hHash: DWORD): BOOL; stdcall; external advapi32; function CryptReleaseContext(hProv: DWORD; dwFlags: DWORD): BOOL; stdcall; external advapi32; function CryptoAPIGetHash(Data: Pointer; nSize: Cardinal; HashType: Cardinal): TBytes; const HP_HASHVAL = $0002; {hash value} PROV_RSA_FULL = 1; CRYPT_VERIFYCONTEXT = $F0000000; var hProv, hHash: Cardinal; begin if CryptAcquireContext(hProv, nil, nil, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) then try if CryptCreateHash(hProv, HashType, 0, 0, hHash) then try if CryptHashData(hHash, Data, nSize, 0) then begin if CryptGetHashParam(hHash, HP_HASHVAL, nil, nSize, 0) then begin SetLength(Result, nSize); if not CryptGetHashParam(hHash, HP_HASHVAL, @Result[0], nSize, 0) then SetLength(Result, 0); end; end; finally CryptDestroyHash(hHash); end; finally CryptReleaseContext(hProv, 0); end; end; const ALG_CRC32 = $0001; ALG_MD2 = $8001; ALG_MD4 = $8002; ALG_MD5 = $8003; ALG_SHA = $8004; function wbCryptoApiHashData(aData: TBytes; aALG: Cardinal): string; function BytesToHexStr(aBytes: TBytes): string; var i: Cardinal; bt: Byte; const Hex = '0123456789abcdef'; begin Result:= ''; for i:= Low(aBytes) to High(aBytes) do begin bt := aBytes[i]; Result:= Result + Hex[bt shr $4 + 1] + Hex[bt and $0f + 1] end; end; begin Result := BytesToHexStr(CryptoAPIGetHash(@aData[0], Length(aData), aALG)); end; function wbSHA1Data(aData: TBytes): string; begin Result := wbCryptoApiHashData(aData, ALG_SHA); end; function wbSHA1File(aFileName: string): string; var Data: TBytes; begin Result := ''; if FileExists(aFileName) then with TFileStream.Create(aFileName, fmOpenRead + fmShareDenyNone) do try SetLength(Data, Size); ReadBuffer(Data[0], Length(Data)); Result := wbSHA1Data(Data); finally Free; end; end; function wbMD5Data(aData: TBytes): string; begin Result := wbCryptoApiHashData(aData, ALG_MD5); end; function wbMD5File(aFileName: string): string; var Data: TBytes; begin Result := ''; if FileExists(aFileName) then with TFileStream.Create(aFileName, fmOpenRead + fmShareDenyNone) do try SetLength(Data, Size); ReadBuffer(Data[0], Length(Data)); Result := wbMD5Data(Data); finally Free; end; end; { TnxFastStringList } procedure TnxFastStringList.Clear(aFreeObjects: Boolean); var i: Integer; begin if aFreeObjects then for i := 0 to Pred(Count) do Objects[i].Free; inherited Clear; end; function TnxFastStringList.CompareStrings(const S1, S2: string): Integer; begin {x$IFDEF DCC6OrLater} if CaseSensitive then Result := CompareStr(S1, S2) else {x$ENDIF} Result := CompareText(S1, S2); end; constructor TnxFastStringList.CreateSorted(aDups: TDuplicates); begin Create; Duplicates := aDups; Sorted := True; end; { TnxFastStringListCS } procedure TnxFastStringListCS.AfterConstruction; begin inherited; {x$IFDEF DCC6OrLater} CaseSensitive := True; {x$ENDIF} end; function wbExtractNameFromPath(aPathName: String): String; begin Result := aPathName; while Pos('\', Result)>0 do Delete(Result, 1, Pos('\', Result)) end; function wbCounterAfterSet(aCounterName: String; const aElement: IwbElement): Boolean; var Element : IwbElement; Container : IwbContainer; SelfAsContainer : IwbContainer; begin Result := False; if wbBeginInternalEdit then try if (Length(aCounterName)>=4) and Supports(aElement.Container, IwbContainer, Container) and Supports(aElement, IwbContainer, SelfAsContainer) then begin Element := Container.ElementByName[aCounterName]; if not Assigned(Element) then // Signatures not listed in mrDef cannot be added Element := Container.Add(Copy(aCounterName, 1, 4)); if Assigned(Element) and (SameText(Element.Name, aCounterName)) then try if (Element.GetNativeValue<>SelfAsContainer.GetElementCount) then Element.SetNativeValue(SelfAsContainer.GetElementCount); Result := True; except // No exception if the value cannot be set, expected non value end; end; finally wbEndInternalEdit; end; end; function wbCounterByPathAfterSet(aCounterName: String; const aElement: IwbElement): Boolean; var Element : IwbElement; Container : IwbContainer; SelfAsContainer : IwbContainer; begin Result := False; if wbBeginInternalEdit then try if (Length(aCounterName)>=4) and Supports(aElement.Container, IwbContainer, Container) and Supports(aElement, IwbContainer, SelfAsContainer) then begin Element := Container.ElementByPath[aCounterName]; // if not Assigned(Element) then // Signatures not listed in mrDef cannot be added // Element := Container.Add(Copy(aCounterName, 1, 4)); if Assigned(Element) and (SameText(Element.Name, wbExtractNameFromPath(aCounterName))) then try if (Element.GetNativeValue<>SelfAsContainer.GetElementCount) then Element.SetNativeValue(SelfAsContainer.GetElementCount); Result := True; except // No exception if the value cannot be set, expected non value end; end; finally wbEndInternalEdit; end; end; function wbCounterContainerAfterSet(aCounterName: String; anArrayName: String; const aElement: IwbElement; DeleteOnEmpty: Boolean = True): Boolean; var Element : IwbElement; Elems : IwbElement; Container : IwbContainer; begin Result := False; // You may need to check alterative counter name if wbBeginInternalEdit then try if Supports(aElement, IwbContainer, Container) then begin Element := Container.ElementByName[aCounterName]; Elems := Container.ElementByName[anArrayName]; if Assigned(Element) then begin if not Assigned(Elems) then if DeleteOnEmpty then Container.RemoveElement(aCounterName) else if Element.GetNativeValue <> 0 then Element.SetNativeValue(0); Result := True; // Counter member exists end; end; finally wbEndInternalEdit; end; end; function wbCounterContainerByPathAfterSet(aCounterName: String; anArrayName: String; const aElement: IwbElement): Boolean; var Element : IwbElement; Elems : IwbElement; Container : IwbContainer; begin Result := False; // You may need to check alterative counter name if wbBeginInternalEdit then try if Supports(aElement, IwbContainer, Container) then begin Element := Container.ElementByPath[aCounterName]; Elems := Container.ElementByName[anArrayName]; if Assigned(Element) then begin if not Assigned(Elems) then if Element.GetNativeValue <> 0 then Element.SetNativeValue(0); Result := True; // Counter member exists end; end; finally wbEndInternalEdit; end; end; // BSA helper function MakeDataFileName(FileName, DataPath: String): String; begin // MO uses 3 chars aliases if Length(FileName) < 3 then Result := '' else if not ((FileName[1] = '\') or (FileName[2] = ':')) then Result := DataPath + FileName else Result := FileName; end; function FindBSAs(IniName, DataPath: String; var bsaNames: TStringList; var bsaMissing: TStringList): Integer; var i: Integer; j: Integer; s: String; t: String; begin Result := 0; j := 0; if Assigned(bsaNames) then j := bsaNames.Count; if Assigned(bsaMissing) then j := j + bsaMissing.Count; if Assigned(bsaNames) then // TIniFile uses GetPrivateProfileString() to read data, it is virtualized by MO // TMemIniFile reads from string list directly, not supported by MO with TIniFile.Create(iniName) do try with TStringList.Create do try if wbGameMode in [gmTES4, gmFO3, gmFNV] then Text := StringReplace(ReadString('Archive', 'sArchiveList', ''), ',' ,#10, [rfReplaceAll]) else if wbGameMode in [ gmTES5, gmSSE ] then Text := StringReplace( ReadString('Archive', 'sResourceArchiveList', '') + ',' + ReadString('Archive', 'sResourceArchiveList2', ''), ',', #10, [rfReplaceAll] ) else if wbGameMode = gmFO4 then Text := StringReplace( ReadString('Archive', 'sResourceIndexFileList', '') + ',' + ReadString('Archive', 'sResourceStartUpArchiveList', '') + ',' + ReadString('Archive', 'sResourceArchiveList', '') + ',' + ReadString('Archive', 'sResourceArchiveList2', ''), ',', #10, [rfReplaceAll] ); for i := 0 to Pred(Count) do begin s := Trim(Strings[i]); t := MakeDataFileName(s, DataPath); if (Length(t)>0) then if FileExists(t) then begin if wbContainerHandler.ContainerExists(t) then Continue; bsaNames.Add(s); end else if Assigned(bsaMissing) then bsaMissing.Add(s); end; Result := bsaNames.Count + bsaMissing.Count - j; // How many were added finally Free; end; finally Free; end; end; function HasBSAs(ModName, DataPath: String; Exact, modini: Boolean; var bsaNames: TStringList; var bsaMissing: TStringList): Integer; var j: Integer; t: String; F: TSearchRec; begin Result := 0; j := 0; if Assigned(bsaNames) then j := bsaNames.Count; if Assigned(bsaMissing) then j := j + bsaMissing.Count; // All games prior to Skyrim load BSA files with partial matching, Skyrim requires exact name match and // can use a private ini to specify the bsa to use. if not exact then ModName := ModName + '*'; if FindFirst(DataPath + ModName + wbArchiveExtension, faAnyFile, F) = 0 then try repeat if wbContainerHandler.ContainerExists(DataPath + F.Name) then Continue; t := MakeDataFileName(F.Name, DataPath); if (Length(t)>0) and FileExists(t) then begin if not wbContainerHandler.ContainerExists(t) then if Assigned(bsaNames) then bsaNames.Add(F.Name); end else if Assigned(bsaMissing) then bsaMissing.Add(F.Name); until FindNext(F) <> 0; Result := bsaNames.Count + bsaMissing.Count - j; finally FindClose(F); end; if modIni then Result := Result + FindBSAs(DataPath+ChangeFileExt(ModName, '.ini'), DataPath, bsaNames, bsaMissing); end; function wbDDSDataToBitmap(aData: TBytes; Bitmap: TBitmap): Boolean; var img: TImageData; ms: TMemoryStream; begin Result := False; if not LoadImageFromMemory(@aData[0], Length(aData), img) then Exit; ms := TMemoryStream.Create; try if SaveImageToStream('BMP', ms, img) then begin ms.Position := 0; Bitmap.LoadFromStream(ms); Result := True; end; finally FreeImage(img); ms.Free; end; end; function wbDDSStreamToBitmap(aStream: TStream; Bitmap: TBitmap): Boolean; var img: TImageData; ms: TMemoryStream; begin Result := False; if not LoadImageFromStream(aStream, img) then Exit; ms := TMemoryStream.Create; try if SaveImageToStream('BMP', ms, img) then begin ms.Position := 0; Bitmap.LoadFromStream(ms); Result := True; end; finally FreeImage(img); ms.Free; end; end; function wbIsAssociatedWithExtension(aExt: string): Boolean; var Name: string; begin Result := False; with TRegistry.Create do try RootKey := HKEY_CURRENT_USER; if OpenKey('\Software\Classes\' + LowerCase(aExt), False) then begin Name := ReadString(''); if OpenKey('\Software\Classes\' + Name + '\DefaultIcon', False) then if SameText(ReadString(''), ParamStr(0)) then Result := True; end; finally Free; end; end; function wbAssociateWithExtension(aExt, aName, aDescr: string): Boolean; begin Result := False; if aExt = '' then Exit else aExt := LowerCase(aExt); if aExt[1] <> '.' then aExt := '.' + aExt; with TRegistry.Create do try RootKey := HKEY_CURRENT_USER; if OpenKey('\Software\Classes\' + aExt, True) then WriteString('', aName) else raise Exception.Create('Not enough rights to modify the registry'); if OpenKey('\Software\Classes\' + aName, True) then WriteString('', aDescr); if OpenKey('\Software\Classes\' + aName + '\DefaultIcon', True) then WriteString('', ParamStr(0)); if OpenKey('\Software\Classes\' + aName + '\shell\open\command', True) then WriteString('', ParamStr(0) + ' "%1"'); Result := True; finally Free; end; SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, nil, nil); end; function wbFormVerDecider(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement; aMinimum: Integer): Integer; var FormVer : Integer; MainRecord : IwbMainRecord; Element : IwbElement; begin Result := 1; if not Assigned(aElement) then Exit; MainRecord := aElement.GetContainingMainRecord; if not Assigned(MainRecord) then Exit; Element := MainRecord.ElementByPath['Record Header\Form Version']; if Assigned(Element) then begin FormVer := Element.NativeValue; if FormVer 0) and not Assigned(wbKeepAliveRoot) then wbKeepAliveRoot := wbCreateKeepAliveRoot; end; function wbEndKeepAlive: Integer; begin Result := Pred(wbKeepAliveCount); wbKeepAliveCount := Result; if Result = 0 then wbKeepAliveRoot := nil; end; const TheEmptyPlugin = 'SavesEmptyPlugin.esp'; type TwbMainRecordEntryHeader = record mrehGeneration : Cardinal; mrehHead : Pointer; mrehTail : Pointer; mrehCount : Cardinal; mrehInUse : Boolean; procedure BeginUse; procedure EndUse; end; var mreHeader: TwbMainRecordEntryHeader; function wbCopyElementToFile(const aSource: IwbElement; aFile: IwbFile; aAsNew, aDeepCopy: Boolean; const aPrefixRemove, aPrefix, aSuffix: string): IwbElement; var MainRecord : IwbMainRecord; Container : IwbContainer; Target : IwbElement; begin Inc(wbCopyIsRunning); try if (wbCurrentTick>0) and (wbCurrentTick+500 UpCase(t[i]) then Exit; Result := True; end; type IwbElementInternal = interface(IwbElement) ['{556DF03C-2723-46FC-99C6-F50BB5E66F86}'] procedure SetContainer(const aContainer: IwbContainer); procedure SetSortOrder(aIndex: Integer); procedure SetMemoryOrder(aIndex: Integer); function GetMemoryOrder: Integer; procedure SetModified(aValue: Boolean); procedure SetInternalModified(aValue: Boolean); function GetCountedRecordCount: Cardinal; procedure PrepareSave; procedure MasterCountUpdated(aOld, aNew: Byte); procedure MasterIndicesUpdated(const aOld, aNew: TBytes); procedure FindUsedMasters(aMasters: PwbUsedMasters); procedure InvalidateStorage; function Reached: Boolean; function BeginDecide: Boolean; procedure EndDecide; property Modified: Boolean read GetModified write SetModified; property MemoryOrder: Integer read GetMemoryOrder write SetMemoryOrder; property InternalModified: Boolean write SetInternalModified; end; TwbElement = class(TInterfacedObject, IInterface, IwbElement, IwbElementInternal) protected eContainer : Pointer{IwbContainer}; //weak reference eSortOrder : Integer; eMemoryOrder : Integer; eStates : TwbElementStates; eSortKey : string; eExtendedSortKey : string; eExternalRefs : Integer; eContainerRef : IwbContainerElementRef; eUpdateCount : Integer; {---IInterface---} function _AddRef: Integer; virtual; stdcall; function _Release: Integer; virtual; stdcall; {---IwbElementInternal---} function InternalAddRef: Integer; stdcall; function InternalRelease: Integer; stdcall; function IwbElementInternal._AddRef = InternalAddRef; function IwbElementInternal._Release = InternalRelease; function GetCountedRecordCount: Cardinal; virtual; procedure PrepareSave; virtual; procedure MasterCountUpdated(aOld, aNew: Byte); virtual; procedure MasterIndicesUpdated(const aOld, aNew: TBytes); virtual; procedure FindUsedMasters(aMasters: PwbUsedMasters); virtual; procedure InvalidateStorage; virtual; procedure InvalidateParentStorage; virtual; function Reached: Boolean; virtual; function LinksToParent: Boolean; virtual; procedure SetMemoryOrder(aIndex: Integer); function GetMemoryOrder: Integer; function BeginDecide: Boolean; procedure EndDecide; procedure NotifyChanged(aContainer: Pointer); procedure NotifyChangedInternal(aContainer: Pointer); virtual; procedure ReportRequiredMasters(aStrings: TStrings; aAsNew: Boolean; Recursive: Boolean = True; Initial: Boolean = false); virtual; function GetElementID: Cardinal; function GetElementStates: TwbElementStates; procedure SetElementState(aState: TwbElementState; Clear: Boolean = false); function Equals(const aElement: IwbElement): Boolean; reintroduce; procedure Hide; procedure Show; function GetIsHidden: Boolean; function HasErrors: Boolean; virtual; function GetValue: string; virtual; function GetCheck: string; virtual; function GetSortKey(aExtended: Boolean): string; virtual; function GetSortKeyInternal(aExtended: Boolean): string; virtual; function GetSortPriority: Integer; virtual; function GetName: string; virtual; function GetBaseName: string; virtual; function GetDisplayName: string; virtual; function GetShortName: string; virtual; function GetPath: string; virtual; function GetFullPath: string; virtual; function GetPathName: string; virtual; function GetSkipped: Boolean; virtual; function GetDef: IwbNamedDef; virtual; function GetValueDef: IwbValueDef; virtual; function GetResolvedValueDef: IwbValueDef; virtual; function GetElementType: TwbElementType; virtual; procedure DoReset(aForce: Boolean); virtual; function GetContainer: IwbContainer; function GetContainingMainRecord: IwbMainRecord; virtual; function GetFile: IwbFile; virtual; function GetReferenceFile: IwbFile; virtual; function GetSortOrder: Integer; procedure BuildRef; virtual; procedure AddReferencedFromID(aFormID: Cardinal); virtual; function CompareExchangeFormID(aOldFormID: Cardinal; aNewFormID: Cardinal): Boolean; virtual; function GetIsEditable: Boolean; virtual; function GetIsRemoveable: Boolean; virtual; function GetEditValue: string; virtual; procedure SetEditValue(const aValue: string); virtual; function GetNativeValue: Variant; virtual; procedure SetNativeValue(const aValue: Variant); virtual; procedure RequestStorageChange(var aBasePtr, aEndPtr: Pointer; aNewSize: Cardinal); virtual; function GetConflictPriority: TwbConflictPriority; virtual; function GetConflictPriorityCanChange: Boolean; virtual; function GetModified: Boolean; procedure MarkModifiedRecursive; virtual; function GetIsInjected: Boolean; virtual; function GetReferencesInjected: Boolean; virtual; function GetInjectionSourceFiles: TDynFiles; virtual; function GetIsNotReachable: Boolean; virtual; procedure SetModified(aValue: Boolean); virtual; procedure SetInternalModified(aValue: Boolean); virtual; function GetDataSize: Integer; virtual; procedure SetDataSize(aSize: Integer); virtual; procedure MergeStorage(var aBasePtr: Pointer; aEndPtr: Pointer); procedure MergeStorageInternal(var aBasePtr: Pointer; aEndPtr: Pointer); virtual; procedure InformStorage(var aBasePtr: Pointer; aEndPtr: Pointer); virtual; procedure Remove; virtual; function CanContainFormIDs: Boolean; virtual; function AddIfMissing(const aElement: IwbElement; aAsNew, aDeepCopy : Boolean; const aPrefixRemove, aPrefix, aSuffix: string): IwbElement; function AddIfMissingInternal(const aElement: IwbElement; aAsNew, aDeepCopy : Boolean; const aPrefixRemove, aPrefix, aSuffix: string): IwbElement; virtual; procedure ResetConflict; virtual; procedure ResetReachable; virtual; function RemoveInjected(aCanRemove: Boolean): Boolean; virtual; function GetEditType: TwbEditType; virtual; function GetEditInfo: string; virtual; function GetDontShow: Boolean; virtual; procedure SetToDefault; procedure SetToDefaultInternal; virtual; function CanAssign(aIndex: Integer; const aElement: IwbElement; aCheckDontShow: Boolean): Boolean; function CanAssignInternal(aIndex: Integer; const aElement: IwbElement; aCheckDontShow: Boolean): Boolean; virtual; function Assign(aIndex: Integer; const aElement: IwbElement; aOnlySK: Boolean): IwbElement; function AssignInternal(aIndex: Integer; const aElement: IwbElement; aOnlySK: Boolean): IwbElement; virtual; procedure WriteToStream(aStream: TStream; aResetModified: Boolean); procedure WriteToStreamInternal(aStream: TStream; aResetModified: Boolean); virtual; function GetLinksTo: IwbElement; virtual; function GetNoReach: Boolean; procedure SetContainer(const aContainer: IwbContainer); virtual; procedure SetSortOrder(aIndex: Integer); procedure DoAfterSet(const aOldValue, aNewValue: Variant); virtual; procedure MoveUp; procedure MoveDown; function CanMoveUp: Boolean; function CanMoveDown: Boolean; procedure NextMember; procedure PreviousMember; function CanChangeMember: Boolean; procedure Tag; procedure ResetTags; virtual; function IsTagged: Boolean; function CopyInto(const aFile: IwbFile; aAsNew, aDeepCopy: Boolean; const aPrefixRemove, aPrefix, aSuffix: string): IwbElement; function BeginUpdate: Integer; function EndUpdate: Integer; procedure UpdatedEnded; virtual; constructor Create(const aContainer: IwbContainer); procedure BeforeDestruction; override; procedure AfterConstruction; override; class function NewInstance: TObject; override; procedure FreeInstance; override; function GetTreeHead: Boolean; // Is the element expected to be a "header record" in the tree navigator function GetTreeBranch: Boolean; // Is the element expected to show in the tree navigator end; TDynElementInternals = array of IwbElementInternal; IwbContainerInternal = interface(IwbContainer) ['{8D9AC0D3-3961-4320-A036-EB4771B081CD}'] function ReleaseElements: TDynElementInternals; procedure ElementChanged(const aElement: IwbElement; aContainer: Pointer); procedure SortBySortOrder; procedure CreatedEmpty; procedure MoveElementUp(const aElement: IwbElement); procedure MoveElementDown(const aElement: IwbElement); function CanMoveElementUp(const aElement: IwbElement): Boolean; function CanMoveElementDown(const aElement: IwbElement): Boolean; procedure NextElementMember(const aElement: IwbElement); procedure PreviousElementMember(const aElement: IwbElement); function CanChangeElementMember(const aElement: IwbElement): Boolean; end; TwbContainer = class(TwbElement, IwbContainerElementRef, IwbContainer, IwbContainerInternal) protected cntElements : TDynElementInternals; cntElementsMap : TDynCardinalArray; cntElementRefs : Integer; cntStates : TwbContainerStates; cntKeepAliveNext : IwbContainerElementRef; function _AddRef: Integer; override; stdcall; function _Release: Integer; override; stdcall; {---IwbContainerElementRef---} function ElementAddRef: Integer; stdcall; function ElementRelease: Integer; stdcall; function IwbContainerElementRef._AddRef = ElementAddRef; function IwbContainerElementRef._Release = ElementRelease; function GetCountedRecordCount: Cardinal; override; procedure PrepareSave; override; procedure MasterCountUpdated(aOld, aNew: Byte); override; procedure MasterIndicesUpdated(const aOld, aNew: TBytes); override; procedure FindUsedMasters(aMasters: PwbUsedMasters); override; procedure SortBySortOrder; virtual; procedure CreatedEmpty; function Reached: Boolean; override; function RemoveInjected(aCanRemove: Boolean): Boolean; override; procedure ReportRequiredMasters(aStrings: TStrings; aAsNew: Boolean; Recursive: Boolean = True; Initial: Boolean = false); override; procedure ResetConflict; override; procedure ResetReachable; override; procedure DoReset(aForce: Boolean); override; procedure DoInit; virtual; function HasErrors: Boolean; override; function GetSortKeyInternal(aExtended: Boolean): string; override; function GetDataSize: Integer; override; procedure MergeStorageInternal(var aBasePtr: Pointer; aEndPtr: Pointer); override; procedure InformStorage(var aBasePtr: Pointer; aEndPtr: Pointer); override; procedure BuildRef; override; procedure MarkModifiedRecursive; override; function CanAssignInternal(aIndex: Integer; const aElement: IwbElement; aCheckDontShow: Boolean): Boolean; override; function AssignInternal(aIndex: Integer; const aElement: IwbElement; aOnlySK: Boolean): IwbElement; override; function GetIsInSK(aIndex: Integer): Boolean; virtual; procedure SetToDefaultInternal; override; procedure WriteToStreamInternal(aStream: TStream; aResetModified: Boolean); override; function GetElement(aIndex: Integer): IwbElement; function GetElementCount: Integer; function GetElementByName(const aName: string): IwbElement; function GetRecordBySignature(const aSignature: TwbSignature): IwbRecord; function GetElementByMemoryOrder(aSortOrder: Integer): IwbElement; function GetElementBySignature(const aSignature: TwbSignature): IwbElement; function GetElementBySortOrder(aSortOrder: Integer): IwbElement; function GetAdditionalElementCount: Integer; virtual; procedure ReverseElements; function GetContainerStates: TwbContainerStates; function GetElementByPath(const aPath: string): IwbElement; function GetElementValue(const aName: string): string; function GetElementExists(const aName: string): Boolean; function GetElementEditValue(const aName: string): string; procedure SetElementEditValue(const aName, aValue: string); function GetElementNativeValue(const aName: string): Variant; procedure SetElementNativeValue(const aName: string; const aValue: Variant); function GetElementLinksTo(const aName: string): IwbElement; function GetElementSortKey(const aName: string; aExtended: Boolean): string; function ResolveElementName(aName: string; out aRemainingName: string; aCanCreate: Boolean = False): IwbElement; virtual; procedure AddElement(const aElement: IwbElement); virtual; procedure InsertElement(aPosition: Integer; const aElement: IwbElement); function RemoveElement(aPos: Integer; aMarkModified: Boolean = False): IwbElement; overload; virtual; function RemoveElement(const aElement: IwbElement; aMarkModified: Boolean = False): IwbElement; overload; virtual; function RemoveElement(const aName: string): IwbElement; overload; function LastElement: IwbElement; function CanElementReset: Boolean; virtual; function GetAddList: TDynStrings; virtual; function Add(const aName: string; aSilent: Boolean): IwbElement; virtual; function IsElementRemoveable(const aElement: IwbElement): Boolean; virtual; function IsElementEditable(const aElement: IwbElement): Boolean; virtual; function IndexOf(const aElement: IwbElement): Integer; virtual; function ReleaseElements: TDynElementInternals; procedure ElementChanged(const aElement: IwbElement; aContainer: Pointer); virtual; procedure NotifyChangedInternal(aContainer: Pointer); override; function CompareExchangeFormID(aOldFormID: Cardinal; aNewFormID: Cardinal): Boolean; override; procedure Init; virtual; procedure Reset; virtual; procedure Bar; function ReleaseKeepAlive: IwbContainerElementRef; procedure MoveElementUp(const aElement: IwbElement); procedure MoveElementDown(const aElement: IwbElement); function CanMoveElementUp(const aElement: IwbElement): Boolean; function CanMoveElementDown(const aElement: IwbElement): Boolean; function CanMoveElement: Boolean; virtual; procedure NextElementMember(const aElement: IwbElement); procedure PreviousElementMember(const aElement: IwbElement); function CanChangeElementMember(const aElement: IwbElement): Boolean; function FindBySortKey(const aSortKey: string; aExtended: Boolean; out aIndex: Integer): Boolean; procedure AfterConstruction; override; procedure BeforeDestruction; override; class function NewInstance: TObject; override; destructor Destroy; override; procedure FreeInstance; override; procedure ResetTags; override; end; IwbFileInternal = interface(IwbFile) ['{E1334034-06D0-4299-BFE0-E0DE97C128E2}'] procedure AddMainRecord(const aRecord: IwbMainRecord); procedure RemoveMainRecord(const aRecord: IwbMainRecord); procedure InjectMainRecord(const aRecord: IwbMainRecord); procedure RemoveInjectedMainRecord(const aRecord: IwbMainRecord); procedure ForceClosed; procedure GetMasters(aMasters: TStrings); end; TwbFile = class(TwbContainer, IwbFile, IwbFileInternal) protected flFileName : string; flLoadOrder : Integer; flCompareTo : string; flStates : TwbFileStates; flUnsavedSince : TDateTime; flFileHandle : THandle; flMapHandle : THandle; flView : Pointer; flEndPtr : Pointer; flMasters : array of IwbFile; flRecords : array of IwbMainRecord; flRecordsCount : Integer; {only used during loading} flRecordsByEditorID : array of IwbMainRecord; flRecordsByEditorIDCount : Integer; {only used during loading} flLoadFinished : Boolean; flFormIDsSorted : Boolean; flInjectedRecords : array of IwbMainRecord; procedure flOpenFile; virtual; procedure flCloseFile; virtual; procedure flProgress(const aStatus: string); function Reached: Boolean; override; function GetElementType: TwbElementType; override; function GetFile: IwbFile; override; function GetReferenceFile: IwbFile; override; function GetName: string; override; function GetBaseName: string; override; procedure PrepareSave; override; procedure SetModified(aValue: Boolean); override; procedure BuildRef; override; function FindFormID(aFormID: Cardinal; var Index: Integer): Boolean; function FindInjectedID(aFormID: Cardinal; var Index: Integer): Boolean; function FindEditorID(const aEditorID: string; var Index: Integer): Boolean; function GetMasterRecordByFormID(aFormID: Cardinal; aAllowInjected: Boolean): IwbMainRecord; function GetAddList: TDynStrings; override; function Add(const aName: string; aSilent: Boolean): IwbElement; override; function IsElementRemoveable(const aElement: IwbElement): Boolean; override; function IsElementEditable(const aElement: IwbElement): Boolean; override; function GetIsEditable: Boolean; override; function GetIsRemoveable: Boolean; override; procedure WriteToStreamInternal(aStream: TStream; aResetModified: Boolean); override; function AddIfMissingInternal(const aElement: IwbElement; aAsNew, aDeepCopy : Boolean; const aPrefixRemove, aPrefix, aSuffix: string): IwbElement; override; function NewFormID: Cardinal; {---IwbFile---} function GetFileName: string; function GetUnsavedSince: TDateTime; function HasMaster(const aFileName: string): Boolean; function GetMaster(aIndex: Integer): IwbFile; function GetMasterCount: Integer; function GetRecordByFormID(aFormID: Cardinal; aAllowInjected: Boolean): IwbMainRecord; function GetRecordByEditorID(const aEditorID: string): IwbMainRecord; function GetGroupBySignature(const aSignature: TwbSignature): IwbGroupRecord; function HasGroup(const aSignature: TwbSignature): Boolean; function GetFileStates: TwbFileStates; function GetRecord(aIndex: Integer): IwbMainRecord; function GetRecordCount: Integer; function GetHeader: IwbMainRecord; function GetLoadOrder: Integer; procedure ForceLoadOrder(aValue: Integer); procedure SetLoadOrder(aValue: Integer); function LoadOrderFormIDtoFileFormID(aFormID: Cardinal): Cardinal; function FileFormIDtoLoadOrderFormID(aFormID: Cardinal): Cardinal; function LoadOrderFileIDtoFileFileID(aFileID: Byte): Byte; function FileFileIDtoLoadOrderFileID(aFileID: Byte): Byte; procedure AddMasters(aMasters: TStrings); procedure AddMasterIfMissing(const aMaster: string); procedure SortMasters; procedure CleanMasters; procedure BuildReachable; function GetIsESM: Boolean; procedure SetIsESM(Value: Boolean); function GetIsLocalized: Boolean; procedure SetIsLocalized(Value: Boolean); function GetNextObjectID: Cardinal; procedure SetNextObjectID(aObjectID: Cardinal); function GetIsNotPlugin: Boolean; function GetHasNoFormID: Boolean; procedure SetHasNoFormID(Value: Boolean); {---IwbFileInternal---} procedure AddMainRecord(const aRecord: IwbMainRecord); procedure RemoveMainRecord(const aRecord: IwbMainRecord); procedure InjectMainRecord(const aRecord: IwbMainRecord); procedure RemoveInjectedMainRecord(const aRecord: IwbMainRecord); procedure ForceClosed; procedure GetMasters(aMasters: TStrings); virtual; procedure Scan; virtual; procedure SortRecords; procedure SortRecordsByEditorID; procedure AddMaster(const aFileName: string; isTemporary: Boolean = False); overload; procedure AddMaster(const aFile: IwbFile); overload; constructor Create(const aFileName: string; aLoadOrder: Integer; aCompareTo: string; aOnlyHeader: Boolean; IsTemporary: Boolean = False); constructor CreateNew(const aFileName: string; aLoadOrder: Integer); public destructor Destroy; override; end; TwbFileSource = class(TwbFile) protected procedure Scan; override; constructor CreateNew(const aFileName: string; aLoadOrder: Integer); procedure GetMasters(aMasters: TStrings); override; end; TwbDataContainerFlag = ( dcfDontCompare, dcfDontMerge, dcfDontSave, dcfStorageInvalid ); TwbDataContainerFlags = set of TwbDataContainerFlag; IwbDataContainerInternal = interface(IwbDataContainer) ['{E13AE2AD-20CB-4429-86C2-0DEC3ECEE38B}'] procedure UpdateStorageFromElements; end; TwbDataContainer = class(TwbContainer, IwbDataContainer, IwbDataContainerInternal) protected dcBasePtr : Pointer; dcEndPtr : Pointer; dcDataBasePtr : Pointer; dcDataEndPtr : Pointer; dcDataStorage : TBytes; dcFlags : TwbDataContainerFlags; constructor Create(const aContainer : IwbContainer; var aBasePtr : Pointer; aEndPtr : Pointer; const aPrevMainRecord : IwbMainRecord); virtual; procedure InitDataPtr; virtual; abstract; function GetDataPrefixSize: Integer; virtual; function GetResolvedValueDef: IwbValueDef; override; procedure InvalidateStorage; override; procedure SetContainer(const aContainer: IwbContainer); override; procedure SetModified(aValue: Boolean); override; procedure RequestStorageChange(var aBasePtr, aEndPtr: Pointer; aNewSize: Cardinal); override; procedure WriteToStreamInternal(aStream: TStream; aResetModified: Boolean); override; procedure MergeStorageInternal(var aBasePtr: Pointer; aEndPtr: Pointer); override; procedure InformStorage(var aBasePtr: Pointer; aEndPtr: Pointer); override; function DoCheckSizeAfterWrite: Boolean; virtual; procedure SetToDefaultInternal; override; function IsFlags: Boolean; virtual; function GetEditType: TwbEditType; override; function GetEditInfo: string; override; function GetConflictPriority: TwbConflictPriority; override; {---IwbDataContainer---} function GetDataBasePtr: Pointer; function GetDataEndPtr: Pointer; function GetDataSize: Integer; override; procedure SetDataSize(aSize: Integer); override; function GetDontCompare: Boolean; function GetDontSave: Boolean; function IsValidOffset(aBasePtr, aEndPtr: Pointer; anOffset: Integer): Boolean; function IsLocalOffset(anOffset: Integer): Boolean; {--- IwbDataContainerInternal ---} procedure UpdateStorageFromElements; virtual; end; TwbRecordClass = class of TwbRecord; TwbRecord = class(TwbDataContainer, IwbRecord, IwbHasSignature) protected recSkipped : Boolean; protected constructor Create(const aContainer : IwbContainer; var aBasePtr : Pointer; aEndPtr : Pointer; const aPrevMainRecord : IwbMainRecord); overload; override; function GetSignature: TwbSignature; procedure ScanData; virtual; abstract; procedure InformPrevMainRecord(const aPrevMainRecord : IwbMainRecord); virtual; procedure SortBySortOrder; override; public class function CreateForPtr(var aPtr : Pointer; aEndPtr : Pointer; const aContainer : IwbContainer; const aPrevMainRecord : IwbMainRecord) : IwbRecord; function GetName: string; override; function GetSkipped: Boolean; override; end; PwbMainRecordStruct = ^TwbMainRecordStruct; TwbMainRecordStruct = packed record mrsSignature : TwbSignature; mrsDataSize : Cardinal; mrsFlags : TwbMainRecordStructFlags; mrsFormID : Cardinal; mrsVCS1 : Cardinal; mrsVersion : Word; mrsVCS2 : Word; end; IwbMainRecordInternal = interface(IwbMainRecord) ['{405C85E0-2261-4078-B99C-199007D31544}'] procedure AddOverride(const aMainRecord: IwbMainRecord); procedure RemoveOverride(const aMainRecord: IwbMainRecord); procedure SetMaster(const aMaster: IwbMainRecord); procedure YouAreTheMaster(const aOverrides, aReferencedBy: TDynMainRecords); overload; procedure YouAreTheMaster(const aOldMaster: IwbMainRecord; const aOverrides, aReferencedBy: TDynMainRecords); overload; procedure YouGotAMaster(const aMaster: IwbMainRecord); procedure SetChildGroup(const aGroup: IwbGroupRecord); procedure RemoveChildGroup(const aGroup: IwbGroupRecord); procedure SetReferencesInjected(aValue: Boolean); procedure ClearForRelease; procedure MakeHeaderWriteable; function mrStruct: PwbMainRecordStruct; end; IwbMainRecordEntry = interface(IwbMainRecordInternal) ['{0C89F580-C95A-4A6C-85EA-BD5E411788A4}'] procedure RemoveEntry; procedure RemoveEntryInternal; procedure InsertEntryAfter(const aEntry: IwbMainRecordEntry); procedure InsertEntryHead; procedure InsertEntryTail; function GetPrevEntry: IwbMainRecordEntry; procedure SetPrevEntry(const aEntry: IwbMainRecordEntry); function GetNextEntry: IwbMainRecordEntry; procedure SetNextEntry(const aEntry: IwbMainRecordEntry); function GetIsInList: Boolean; property PrevEntry: IwbMainRecordEntry read GetPrevEntry write SetPrevEntry; property NextEntry: IwbMainRecordEntry read GetNextEntry write SetNextEntry; property IsInList: Boolean read GetIsInList; end; TwbMainRecordState = ( mrsBuildingRef, mrsReferencedByUnsorted, mrsIsInjected, mrsIsInjectedChecked, mrsReferencesInjected, mrsReferencesInjectedChecked, mrsSearchedChildGroup, mrsHasVWDMeshChecked, mrsHasVWDMesh, mrsHasPrecombinedMeshChecked, mrsHasPrecombinedMesh, mrsBaseRecordChecked, mrsQuickInit, mrsQuickInitDone, mrsHasMeshChecked, mrsHasMesh, mrsNoUpdateRefs, mrBasePtrAllocated ); TwbMainRecordStates = set of TwbMainRecordState; IwbContainedIn = interface ['{002F064A-81B8-40EB-AA09-E5F7AE061D9E}'] procedure ContainerChanged; end; TwbMainRecord = class(TwbRecord, IwbMainRecord, IwbMainRecordInternal, IwbMainRecordEntry, IwbContainedIn) protected mrDef : IwbRecordDef; mrLoadOrderFormID : Cardinal; mrFixedFormID : Cardinal; mrMaster : Pointer{IwbMainRecord}; mrOverrides : TDynMainRecords; mrOverridesSorted : Boolean; mrEditorID : string; mrFullName : string; mrStates : TwbMainRecordStates; mrBaseRecordID : Cardinal; mrPrecombinedCellID: Cardinal; mrPrecombinedID : Cardinal; mrConflictAll : TConflictAll; mrConflictThis : TConflictThis; mrDataStorage : TBytes; mrGroup : IwbGroupRecord; mrReferencedBy : TDynMainRecords; mrReferences : TDynCardinalArray; mrTmpRefFormIDs : TDynCardinalArray; mrTmpRefFormIDHigh : Integer; mreGeneration : Integer; mrePrev : Pointer; mreNext : Pointer; function mrStruct: PwbMainRecordStruct; inline; procedure ElementChanged(const aElement: IwbElement; aContainer: Pointer); override; function RemoveElement(aPos: Integer; aMarkModified: Boolean = False): IwbElement; overload; override; function ResolveElementName(aName: string; out aRemainingName: string; aCanCreate: Boolean = False): IwbElement; override; function GetIsInjected: Boolean; override; function GetReferencesInjected: Boolean; override; function GetInjectionSourceFiles: TDynFiles; override; function RemoveInjected(aCanRemove: Boolean): Boolean; override; function GetIsNotReachable: Boolean; override; function GetCountedRecordCount: Cardinal; override; procedure InitDataPtr; override; procedure DecompressIfNeeded; procedure ScanData; override; procedure WriteToStreamInternal(aStream: TStream; aResetModified: Boolean); override; procedure MergeStorageInternal(var aBasePtr: Pointer; aEndPtr: Pointer); override; procedure InformStorage(var aBasePtr: Pointer; aEndPtr: Pointer); override; function CanContainFormIDs: Boolean; override; function CompareExchangeFormID(aOldFormID: Cardinal; aNewFormID: Cardinal): Boolean; override; function CanElementReset: Boolean; override; procedure Remove; override; procedure PrepareSave; override; procedure MasterCountUpdated(aOld, aNew: Byte); override; procedure MasterIndicesUpdated(const aOld, aNew: TBytes); override; procedure FindUsedMasters(aMasters: PwbUsedMasters); override; function GetReferenceFile: IwbFile; override; procedure ReportRequiredMasters(aStrings: TStrings; aAsNew: Boolean; Recursive: Boolean = True; Initial: Boolean = false); override; function LinksToParent: Boolean; override; function Reached: Boolean; override; function GetContainingMainRecord: IwbMainRecord; override; procedure DoBuildRef(aRemove: Boolean); procedure BuildRef; override; procedure AddReferencedFromID(aFormID: Cardinal); override; procedure ResetConflict; override; procedure ResetReachable; override; procedure Init; override; procedure Reset; override; function GetPath: string; override; function GetValue: string; override; function GetSortKeyInternal(aExtended: Boolean): string; override; function GetSortPriority: Integer; override; function GetAdditionalElementCount: Integer; override; function GetIsEditable: Boolean; override; function GetEditValue: string; override; procedure SetEditValue(const aValue: string); override; function GetNativeValue: Variant; override; procedure SetNativeValue(const aValue: Variant); override; function IsElementRemoveable(const aElement: IwbElement): Boolean; override; procedure SetContainer(const aContainer: IwbContainer); override; function FindReferencedBy(const aMainRecord: IwbMainRecord; var Index: Integer): Boolean; function CanAssignInternal(aIndex: Integer; const aElement: IwbElement; aCheckDontShow: Boolean): Boolean; override; function AssignInternal(aIndex: Integer; const aElement: IwbElement; aOnlySK: Boolean): IwbElement; override; function AddIfMissingInternal(const aElement: IwbElement; aAsNew, aDeepCopy : Boolean; const aPrefixRemove, aPrefix, aSuffix: string): IwbElement; override; procedure CollapseStorage; function GetAddList: TDynStrings; override; function Add(const aName: string; aSilent: Boolean): IwbElement; override; function CheckChildOfCell: Boolean; procedure UpdateCellChildGroup; procedure UpdateInteriorCellGroup; procedure MarkModifiedRecursive; override; {---IwbMainRecord---} function GetDef: IwbNamedDef; override; function GetElementType: TwbElementType; override; function GetFormID: Cardinal; function GetFixedFormID: Cardinal; function GetLoadOrderFormID: Cardinal; procedure SetLoadOrderFormID(aFormID: Cardinal); function GetEditorID: string; function GetCanHaveEditorID: Boolean; procedure SetEditorID(const aValue: string); function GetFullName: string; function GetDisplayNameKey: string; function GetMaster: IwbMainRecord; function GetIsMaster: Boolean; function GetMasterOrSelf: IwbMainRecord; function GetOverride(aIndex: Integer): IwbMainRecord; function GetOverrideCount: Integer; procedure AddReferencedBy(aMainRecord: IwbMainRecord); procedure RemoveReferencedBy(aMainRecord: IwbMainRecord); procedure SortReferencedBy; function GetReferencedBy(aIndex: Integer): IwbMainRecord; function GetReferencedByCount: Integer; function GetCheck: string; override; function GetIsWinningOverride: Boolean; function GetWinningOverride: IwbMainRecord; function GetHighestOverrideOrSelf(aMaxLoadOrder: Integer): IwbMainRecord; function GetFlags: TwbMainRecordStructFlags; function GetFlagsPtr: PwbMainRecordStructFlags; function GetChildGroup: IwbGroupRecord; function EnsureChildGroup: IwbGroupRecord; function GetBaseRecord: IwbMainRecord; function GetBaseRecordID: Cardinal; procedure MakeHeaderWriteable; function GetConflictAll: TConflictAll; procedure SetConflictAll(aValue: TConflictAll); function GetConflictThis: TConflictThis; procedure SetConflictThis(aValue: TConflictThis); function GetIsESM: Boolean; procedure SetIsESM(aValue: Boolean); function GetIsLocalized: Boolean; procedure SetIsLocalized(aValue: Boolean); function GetIsPersistent: Boolean; procedure SetIsPersistent(aValue: Boolean); function GetIsDeleted: Boolean; procedure SetIsDeleted(aValue: Boolean); function GetIsCompressed: Boolean; procedure SetIsCompressed(aValue: Boolean); function GetIsVisibleWhenDistant: Boolean; procedure SetIsVisibleWhenDistant(aValue: Boolean); function GetHasVisibleWhenDistantMesh: Boolean; function GetHasMesh: Boolean; function GetHasPrecombinedMesh: Boolean; function GetPrecombinedMesh: string; function GetIsInitiallyDisabled: Boolean; procedure SetIsInitiallyDisabled(aValue: Boolean); procedure UpdateRefs; function GetPosition(out aPosition: TwbVector): Boolean; function SetPosition(const aPosition: TwbVector): Boolean; function GetRotation(out aRotation: TwbVector): Boolean; function GetScale(out aScale: Single): Boolean; function GetGridCell(out aGridCell: TwbGridCell): Boolean; function GetFormVersion: Cardinal; {>>> Form Version access <<<} procedure SetFormVersion(aFormVersion: Cardinal); {>>> Form Version access <<<} procedure ChangeFormSignature(aSignature: TwbSignature); procedure ClampFormID(aIndex: Cardinal); procedure Delete; procedure DeleteInto(const aFile: IwbFile); function MasterRecordsFromMasterFilesAndSelf: TDynMainRecords; {---IwbMainRecordInternal---} procedure AddOverride(const aMainRecord: IwbMainRecord); procedure RemoveOverride(const aMainRecord: IwbMainRecord); procedure SetMaster(const aMaster: IwbMainRecord); procedure YouAreTheMaster(const aOverrides, aReferencedBy: TDynMainRecords); overload; procedure YouAreTheMaster(const aOldMaster: IwbMainRecord; const aOverrides, aReferencedBy: TDynMainRecords); overload; procedure YouGotAMaster(const aMaster: IwbMainRecord); procedure SetChildGroup(const aGroup: IwbGroupRecord); procedure RemoveChildGroup(const aGroup: IwbGroupRecord); procedure SetReferencesInjected(aValue: Boolean); procedure ClearForRelease; {---IwbMainRecordEntry---} procedure RemoveEntry; procedure RemoveEntryInternal; procedure InsertEntryAfter(const aEntry: IwbMainRecordEntry); procedure InsertEntryHead; procedure InsertEntryTail; function GetPrevEntry: IwbMainRecordEntry; procedure SetPrevEntry(const aEntry: IwbMainRecordEntry); function GetNextEntry: IwbMainRecordEntry; procedure SetNextEntry(const aEntry: IwbMainRecordEntry); function GetIsInList: Boolean; {--- IwbContainedIn ---} procedure ContainerChanged; public constructor Create(const aContainer : IwbContainer; var aBasePtr : Pointer; aEndPtr : Pointer; const aPrevMainRecord : IwbMainRecord); override; constructor Create(const aContainer : IwbContainer; const aSignature : TwbSignature; aFormID : Cardinal); overload; destructor Destroy; override; function GetName: string; override; function GetShortName: string; override; function GetDisplayName: string; override; end; PwbSubRecordHeaderStruct = ^TwbSubRecordHeaderStruct; TwbSubRecordHeaderStruct = packed record srsSignature : TwbSignature; srsDataSize : Word; end; IwbSubRecordInternal = interface(IwbSubRecord) ['{AB66BAE8-2618-4B85-80CE-A108C3B80808}'] procedure SetDef(const aDef: IwbSubRecordDef); end; TwbSubRecordState = ( srsIsArray, srsIsFlags, srsIsUnion, srsSorted, srsSortInvalid ); TwbSubRecordStates = set of TwbSubRecordState; TwbSubRecord = class(TwbRecord, IwbSubRecord, IwbSubRecordInternal, IwbSortableContainer) protected {private} srDef : IwbSubRecordDef; srValueDef : IwbValueDef; srStates : TwbSubRecordStates; srArraySizePrefix : Integer; protected constructor Create(const aContainer : IwbContainer; const aSubRecordDef: IwbSubRecordDef); overload; destructor Destroy; override; procedure SetDef(const aDef: IwbSubRecordDef); function srStruct: PwbSubRecordHeaderStruct; inline; procedure InitDataPtr; override; procedure ScanData; override; procedure DoInit; override; procedure Init; override; procedure Reset; override; function GetDataPrefixSize: Integer; override; procedure CheckCount; function GetName: string; override; function GetDisplayName: string; override; function IsFlags: Boolean; override; function GetValue: string; override; function GetCheck: string; override; function GetSortKeyInternal(aExtended: Boolean): string; override; function GetIsEditable: Boolean; override; function GetValueDef: IwbValueDef; override; function GetEditValue: string; override; procedure SetEditValue(const aValue: string); override; function GetNativeValue: Variant; override; procedure SetNativeValue(const aValue: Variant); override; procedure BuildRef; override; function CompareExchangeFormID(aOldFormID: Cardinal; aNewFormID: Cardinal): Boolean; override; procedure MasterCountUpdated(aOld, aNew: Byte); override; procedure MasterIndicesUpdated(const aOld, aNew: TBytes); override; procedure FindUsedMasters(aMasters: PwbUsedMasters); override; procedure MergeStorageInternal(var aBasePtr: Pointer; aEndPtr: Pointer); override; procedure InformStorage(var aBasePtr: Pointer; aEndPtr: Pointer); override; function IsElementRemoveable(const aElement: IwbElement): Boolean; override; procedure SetModified(aValue: Boolean); override; function CanContainFormIDs: Boolean; override; function CanElementReset: Boolean; override; function GetLinksTo: IwbElement; override; procedure ElementChanged(const aElement: IwbElement; aContainer: Pointer); override; procedure PrepareSave; override; function RemoveInjected(aCanRemove: Boolean): Boolean; override; procedure SetToDefaultInternal; override; procedure WriteToStreamInternal(aStream: TStream; aResetModified: Boolean); override; function CanAssignInternal(aIndex: Integer; const aElement: IwbElement; aCheckDontShow: Boolean): Boolean; override; function AssignInternal(aIndex: Integer; const aElement: IwbElement; aOnlySK: Boolean): IwbElement; override; function AddIfMissingInternal(const aElement: IwbElement; aAsNew, aDeepCopy : Boolean; const aPrefixRemove, aPrefix, aSuffix: string): IwbElement; override; function GetIsInSK(aIndex: Integer): Boolean; override; function DoCheckSizeAfterWrite: Boolean; override; function GetDef: IwbNamedDef; override; function GetElementType: TwbElementType; override; function GetDataSize: Integer; override; function CanMoveElement: Boolean; override; procedure CheckTerminator; {--- IwbSubRecord ---} function GetSubRecordHeaderSize: Integer; {--- IwbSortableContainer ---} function GetSorted: Boolean; end; TwbValueBase = class(TwbDataContainer) protected vbValueDef : IwbValueDef; vbNameSuffix : string; protected procedure InitDataPtr; override; function GetDef: IwbNamedDef; override; function GetValueDef: IwbValueDef; override; function GetName: string; override; function GetBaseName: string; override; function GetDisplayName: string; override; function GetCheck: string; override; function GetValue: string; override; function GetSortKeyInternal(aExtended: Boolean): string; override; function GetIsEditable: Boolean; override; function CanElementReset: Boolean; override; function GetEditValue: string; override; procedure SetEditValue(const aValue: string); override; function GetNativeValue: Variant; override; procedure SetNativeValue(const aValue: Variant); override; procedure BuildRef; override; function CanContainFormIDs: Boolean; override; function GetLinksTo: IwbElement; override; function GetDataSize: Integer; override; function DoCheckSizeAfterWrite: Boolean; override; procedure SetToDefaultInternal; override; function GetIsInSK(aIndex: Integer): Boolean; override; public constructor Create(const aContainer : IwbContainer; var aBasePtr : Pointer; aEndPtr : Pointer; const aValueDef : IwbValueDef; const aNameSuffix : string; aDontCompare: Boolean = False); reintroduce; overload; constructor Create(const aContainer : IwbContainer; const aValueDef : IwbValueDef; const aSource : IwbElement; const aOnlySK : Boolean; const aNameSuffix : string); reintroduce; overload; end; TwbArray = class(TwbValueBase, IwbSortableContainer) protected {private} arrSorted : Boolean; arrSortInvalid : Boolean; arrSizePrefix : Integer; protected procedure DoInit; override; procedure Init; override; procedure Reset; override; function GetElementType: TwbElementType; override; function IsElementRemoveable(const aElement: IwbElement): Boolean; override; procedure SetModified(aValue: Boolean); override; procedure ElementChanged(const aElement: IwbElement; aContainer: Pointer); override; function CanAssignInternal(aIndex: Integer; const aElement: IwbElement; aCheckDontShow: Boolean): Boolean; override; function AssignInternal(aIndex: Integer; const aElement: IwbElement; aOnlySK: Boolean): IwbElement; override; function AddIfMissingInternal(const aElement: IwbElement; aAsNew, aDeepCopy : Boolean; const aPrefixRemove, aPrefix, aSuffix: string): IwbElement; override; procedure PrepareSave; override; procedure CheckTerminator; function GetDataPrefixSize: Integer; override; procedure CheckCount; function CanMoveElement: Boolean; override; {--- IwbSortableContainer ---} function GetSorted: Boolean; end; TwbStruct = class(TwbValueBase) protected szCompressedSize : Integer; szUncompressedSize : Cardinal; szCompressedType : TwbStructCompression; procedure Init; override; procedure Reset; override; function GetElementType: TwbElementType; override; procedure DecompressIfNeeded; function GetIsCompressed: TwbStructCompression; property IsCompressed: TwbStructCompression read GetIsCompressed; end; TwbFileHeader = class(TwbStruct, IwbFileHeader) protected function GetFileMagic: TwbFileMagic; end; TwbChapter = class(TwbStruct, IwbChapter) protected cChapterSkipped : Boolean; protected function GetSkipped: Boolean; override; function GetElementType: TwbElementType; override; function GetChapterType: Integer; function GetChapterTypeName: String; function GetChapterName: String; public constructor Create(const aContainer : IwbContainer; const aValueDef : IwbValueDef; const aSource : IwbElement; const aOnlySK : Boolean; const aNameSuffix : string); reintroduce; overload; end; TwbUnion = class(TwbValueBase) protected function CompareExchangeFormID(aOldFormID: Cardinal; aNewFormID: Cardinal): Boolean; override; procedure Init; override; procedure Reset; override; function GetElementType: TwbElementType; override; procedure MasterCountUpdated(aOld, aNew: Byte); override; procedure MasterIndicesUpdated(const aOld, aNew: TBytes); override; procedure FindUsedMasters(aMasters: PwbUsedMasters); override; end; TwbRecordHeaderStruct = class(TwbStruct) protected function CanContainFormIDs: Boolean; override; procedure BuildRef; override; function CompareExchangeFormID(aOldFormID: Cardinal; aNewFormID: Cardinal): Boolean; override; function IsElementEditable(const aElement: IwbElement): Boolean; override; function GetIsEditable: Boolean; override; procedure ElementChanged(const aElement: IwbElement; aContainer: Pointer); override; function AddIfMissingInternal(const aElement: IwbElement; aAsNew, aDeepCopy : Boolean; const aPrefixRemove, aPrefix, aSuffix: string): IwbElement; override; end; TwbValue = class(TwbValueBase, IwbSortableContainer) protected {private} vIsFlags : Boolean; protected function GetValue: string; override; function CompareExchangeFormID(aOldFormID: Cardinal; aNewFormID: Cardinal): Boolean; override; procedure MasterCountUpdated(aOld, aNew: Byte); override; procedure MasterIndicesUpdated(const aOld, aNew: TBytes); override; procedure FindUsedMasters(aMasters: PwbUsedMasters); override; function AddIfMissingInternal(const aElement: IwbElement; aAsNew, aDeepCopy : Boolean; const aPrefixRemove, aPrefix, aSuffix: string): IwbElement; override; function IsFlags: Boolean; override; procedure Init; override; procedure Reset; override; function GetElementType: TwbElementType; override; procedure SetEditValue(const aValue: string); override; procedure SetNativeValue(const aValue: Variant); override; {--- IwbSortableContainer ---} function GetSorted: Boolean; end; TwbContainedInElement = class(TwbValue, IwbContainedIn) protected {private} cieLockCount: Integer; protected procedure InvalidateParentStorage; override; function CanContainFormIDs: Boolean; override; procedure BuildRef; override; function CompareExchangeFormID(aOldFormID: Cardinal; aNewFormID: Cardinal): Boolean; override; function IsElementEditable(const aElement: IwbElement): Boolean; override; procedure ElementChanged(const aElement: IwbElement; aContainer: Pointer); override; procedure SetModified(aValue: Boolean); override; procedure DoAfterSet(const aOldValue, aNewValue: Variant); override; {--- IwbContainedIn ---} procedure ContainerChanged; public constructor Create(const aMainRecord: IwbMainRecord); end; IwbStringListTerminator = interface ['{0D8ED4AA-1AFE-4283-87D7-2B66C5496227}'] end; TwbStringListTerminator = class(TwbElement, IwbStringListTerminator) function GetName: string; override; function GetElementType: TwbElementType; override; function GetConflictPriority: TwbConflictPriority; override; function GetSortKeyInternal(aExtended: Boolean): string; override; procedure SetEditValue(const aValue: string); override; procedure SetNativeValue(const aValue: Variant); override; function GetDataSize: Integer; override; procedure WriteToStreamInternal(aStream: TStream; aResetModified: Boolean); override; procedure MergeStorageInternal(var aBasePtr: Pointer; aEndPtr: Pointer); override; procedure InformStorage(var aBasePtr: Pointer; aEndPtr: Pointer); override; function CanAssignInternal(aIndex: Integer; const aElement: IwbElement; aCheckDontShow: Boolean): Boolean; override; function AssignInternal(aIndex: Integer; const aElement: IwbElement; aOnlySK: Boolean): IwbElement; override; end; IwbFlag = interface(IwbElement) ['{EED55516-C6D5-4ADD-B147-36B115E7449D}'] function GetFlagsDef: IwbFlagsDef; function GetFlagIndex: Integer; property FlagsDef: IwbFlagsDef read GetFlagsDef; property FlagIndex: Integer read GetFlagIndex; end; TwbFlag = class(TwbElement, IwbFlag) protected {private} fBasePtr : Pointer; fEndPtr : Pointer; fIntegerDef : IwbIntegerDef; fFlagsDef : IwbFlagsDef; fLastDefID : Cardinal; fIndex : Integer; protected constructor Create(const aContainer : IwbContainer; aBasePtr : Pointer; aEndPtr : Pointer; const aIntegerDef : IwbIntegerDef; const aFlagsDef : IwbFlagsDef; aIndex : Integer); function GetName: string; override; function GetDef: IwbNamedDef; override; function GetValueDef: IwbValueDef; override; function GetValue: string; override; function GetSortKey(aExtended: Boolean): string; override; function GetSortKeyInternal(aExtended: Boolean): string; override; function GetConflictPriority: TwbConflictPriority; override; function GetDontShow: Boolean; override; procedure InformStorage(var aBasePtr: Pointer; aEndPtr: Pointer); override; function GetDataSize: Integer; override; procedure InvalidateParentStorage; override; function GetIsEditable: Boolean; override; function GetIsRemoveable: Boolean; override; procedure Remove; override; function GetEditValue: string; override; procedure SetEditValue(const aValue: string); override; function GetNativeValue: Variant; override; procedure SetNativeValue(const aValue: Variant); override; function GetElementType: TwbElementType; override; {--- IwbFlag ---} function GetFlagsDef: IwbFlagsDef; function GetFlagIndex: Integer; end; PwbGroupRecordStruct = ^TwbGroupRecordStruct; TwbGroupRecordStruct = packed record grsSignature : TwbSignature; grsGroupSize : Cardinal; grsLabel : Cardinal; grsGroupType : Integer; grsStamp : Cardinal; grsUnknown : Cardinal; end; IwbGroupRecordInternal = interface(IwbGroupRecord) ['{0BDDCF46-DFF6-4771-8FBB-0BC78828999B}'] procedure Sort; procedure SetModified(aValue: Boolean); end; TwbGroupState = ( gsSorted, gsSorting, gsSortPostponed ); TwbGroupStates = set of TwbGroupState; TwbGroupRecord = class(TwbRecord, IwbGroupRecord, IwbGroupRecordInternal) protected {private} grStates: TwbGroupStates; protected constructor Create(const aContainer : IwbContainer; const aSignature : TwbSignature); overload; constructor Create(const aContainer : IwbContainer; aType : Integer; const aMainRecord : IwbMainRecord); overload; constructor Create(const aContainer : IwbContainer; aType : Integer; aLabel : Cardinal); overload; destructor Destroy; override; function grStruct: PwbGroupRecordStruct; inline; function GetCountedRecordCount: Cardinal; override; procedure InitDataPtr; override; procedure ScanData; override; procedure InformPrevMainRecord(const aPrevMainRecord : IwbMainRecord); override; function GetName: string; override; function GetShortName: string; override; function GetElementType: TwbElementType; override; function GetSortKeyInternal(aExtended: Boolean): string; override; function IsElementRemoveable(const aElement: IwbElement): Boolean; override; procedure Remove; override; procedure NotifyChangedInternal(aContainer: Pointer); override; function GetAddList: TDynStrings; override; function Add(const aName: string; aSilent: Boolean): IwbElement; override; procedure Sort; procedure UpdatedEnded; override; procedure SetModified(aValue: Boolean); override; procedure PrepareSave; override; procedure WriteToStreamInternal(aStream: TStream; aResetModified: Boolean); override; procedure MasterCountUpdated(aOld, aNew: Byte); override; procedure MasterIndicesUpdated(const aOld, aNew: TBytes); override; procedure FindUsedMasters(aMasters: PwbUsedMasters); override; function AddIfMissingInternal(const aElement: IwbElement; aAsNew, aDeepCopy : Boolean; const aPrefixRemove, aPrefix, aSuffix: string): IwbElement; override; procedure MakeHeaderWriteable; procedure BuildRef; override; function LinksToParent: Boolean; override; function Reached: Boolean; override; function FindChildGroup(aType: Integer; aMainRecord: IwbMainRecord): IwbGroupRecord; function GetMainRecordByEditorID(const aEditorID: string): IwbMainRecord; function GetMainRecordByFormID(const aFormID: Cardinal): IwbMainRecord; function GetGroupType: Integer; function GetGroupLabel: Cardinal; procedure SetGroupLabel(aLabel: Cardinal); function GetChildrenOf: IwbMainRecord; procedure AddElement(const aElement: IwbElement); override; end; IwbSubRecordArrayInternal = interface(IwbSubRecordArray) ['{4400F93F-9D13-43CA-B43D-727725EC73C8}'] procedure DoProcess(const aContainer : IwbContainer; aPos : Integer); end; TwbSubRecordArray = class(TwbContainer, IwbSubRecordArray, IwbSubRecordArrayInternal, IwbSortableContainer, IwbHasSignature) protected {private} arcDef : IwbSubRecordArrayDef; arcSorted : Boolean; arcSortInvalid : Boolean; protected constructor Create(const aOwner : IwbContainer; const aContainer : IwbContainer; aPos : Integer; const aDef : IwbSubRecordArrayDef); procedure DoProcess(const aContainer : IwbContainer; aPos : Integer); procedure DoInit; override; function GetName: string; override; function GetDef: IwbNamedDef; override; function GetElementType: TwbElementType; override; function IsElementRemoveable(const aElement: IwbElement): Boolean; override; procedure SetModified(aValue: Boolean); override; function CanContainFormIDs: Boolean; override; function CanElementReset: Boolean; override; procedure ElementChanged(const aElement: IwbElement; aContainer: Pointer); override; function CanAssignInternal(aIndex: Integer; const aElement: IwbElement; aCheckDontShow: Boolean): Boolean; override; function AssignInternal(aIndex: Integer; const aElement: IwbElement; aOnlySK: Boolean): IwbElement; override; function AddIfMissingInternal(const aElement: IwbElement; aAsNew, aDeepCopy : Boolean; const aPrefixRemove, aPrefix, aSuffix: string): IwbElement; override; function CanMoveElement: Boolean; override; {---IwbSortableContainer---} function GetSorted: Boolean; {--- IwbHasSignature ---} function GetSignature: TwbSignature; end; TwbSubRecordStruct = class(TwbContainer, IwbHasSignature) protected {private} srcDef: IwbRecordDef; protected constructor Create(const aOwner : IwbContainer; const aContainer : IwbContainer; aPos : Integer; const aDef : IwbSubRecordStructDef); procedure AddRequiredElements; function Add(const aName: string; aSilent: Boolean): IwbElement; override; function GetSortKeyInternal(aExtended: Boolean): string; override; function GetName: string; override; function GetDef: IwbNamedDef; override; function GetElementType: TwbElementType; override; function IsElementRemoveable(const aElement: IwbElement): Boolean; override; function CanContainFormIDs: Boolean; override; function CanElementReset: Boolean; override; function RemoveInjected(aCanRemove: Boolean): Boolean; override; function CanAssignInternal(aIndex: Integer; const aElement: IwbElement; aCheckDontShow: Boolean): Boolean; override; function AssignInternal(aIndex: Integer; const aElement: IwbElement; aOnlySK: Boolean): IwbElement; override; function AddIfMissingInternal(const aElement: IwbElement; aAsNew, aDeepCopy : Boolean; const aPrefixRemove, aPrefix, aSuffix: string): IwbElement; override; function GetIsInSK(aIndex: Integer): Boolean; override; {--- IwbHasSignature ---} function GetSignature: TwbSignature; end; const NONE : TwbSignature = #0#0#0#0; function CompareFormIDs(Item1, Item2: Pointer): Integer; asm {$IFDEF WIN32} xor ecx, ecx cmp eax, edx ja @@GT je @@EQ @@LT: dec ecx dec ecx @@GT: inc ecx @@EQ: mov eax, ecx {$ENDIF WIN32} {$IFDEF WIN64} xor rax, rax cmp rcx, rdx ja @@GT je @@EQ @@LT: dec rax dec rax @@GT: inc rax @@EQ: {$ENDIF WIN64} end; function CompareSubRecords(Item1, Item2: Pointer): Integer; var SortOrder1: Integer; SortOrder2: Integer; begin if Item1 = Item2 then begin Result := 0; Exit; end; SortOrder1 := IwbElement(Item1).SortOrder; SortOrder2 := IwbElement(Item2).SortOrder; Result := CmpI32(SortOrder1, SortOrder2); if Result = 0 then begin Result := CmpW32(Ord(IwbElement(Item1).ElementType), Ord(IwbElement(Item2).ElementType)); if Result = 0 then begin if IwbElement(Item1).ElementType = etSubRecord then Result := CmpW32( Cardinal((IwbElement(Item1) as IwbSubRecord).DataBasePtr), Cardinal((IwbElement(Item2) as IwbSubRecord).DataBasePtr) ); end; end; end; function CompareSortKeys(Item1, Item2: Pointer): Integer; var SortKey1 : string; SortKey2 : string; // Container1 : IwbContainer; // Container2 : IwbContainer; begin if Item1 = Item2 then begin Result := 0; Exit; end; SortKey1 := IwbElement(Item1).SortKey[True]; SortKey2 := IwbElement(Item2).SortKey[True]; Result := CompareStr(SortKey1, SortKey2); if Result = 0 then begin SortKey1 := IwbElement(Item1).Value; SortKey2 := IwbElement(Item1).Value; Result := CompareStr(SortKey1, SortKey2); if Result = 0 then begin Result := CmpW32(Ord(IwbElement(Item1).ElementType), Ord(IwbElement(Item2).ElementType)); if Result = 0 then begin if IwbElement(Item1).ElementType = etSubRecord then Result := CmpW32( Cardinal((IwbElement(Item1) as IwbSubRecord).DataBasePtr), Cardinal((IwbElement(Item2) as IwbSubRecord).DataBasePtr) ){ else try if Supports(IwbElement(Item1), IwbContainer, Container1) and Supports(IwbElement(Item2), IwbContainer, Container2) then Result := CmpW32( Cardinal((Container1 as TwbContainer).cntElements), // Arbitrary value that should not change during the sort Cardinal((Container2 as TwbContainer).cntElements) ); except // If an Element supporting IwbContainer could NOT be a TwbContainer end}; end; end; end; end; function CompareSortOrder(Item1, Item2: Pointer): Integer; var SortOrder1: Integer; SortOrder2: Integer; begin if Item1 = Item2 then begin Result := 0; Exit; end; SortOrder1 := IwbElement(Item1).SortOrder; SortOrder2 := IwbElement(Item2).SortOrder; Result := CmpI32(SortOrder1, SortOrder2); end; function CompareLoadOrder(Item1, Item2: Pointer): Integer; var LoadOrder1: Integer; LoadOrder2: Integer; begin if Item1 = Item2 then begin Result := 0; Exit; end; LoadOrder1 := IwbFile(Item1).LoadOrder; LoadOrder2 := IwbFile(Item2).LoadOrder; Result := CmpI32(LoadOrder1, LoadOrder2); if Result = 0 then Result := CmpW32(IwbFile(Item1).ElementID, IwbFile(Item2).ElementID); end; { TwbFile } procedure TwbFile.AddMaster(const aFileName: string; IsTemporary: Boolean); var _File : IwbFile; s : string; t : string; i : Integer; begin if not wbRequireLoadorder and IsTemporary then begin for i := 0 to Pred(GetMasterCount) do if SameText(ExtractFileName(aFileName), GetMaster(i).FileName) then Exit; end; s := ExtractFilePath(aFileName); t := ExtractFileName(aFileName); if s = '' then s := ExtractFilePath(flFileName); if s <> '' then s := IncludeTrailingPathDelimiter(s); flProgress('Adding master "' + t + '"'); _File := wbFile(s + t, -1, '', IsTemporary, False); if not (wbToolMode in [tmDump, tmExport]) and (wbRequireLoadOrder and (_File.LoadOrder < 0)) then raise Exception.Create('"' + GetFileName + '" requires master "' + aFileName + '" to be loaded before it.') else AddMaster(_File); end; function TwbFile.Add(const aName: string; aSilent: Boolean): IwbElement; var Signature : TwbSignature; Dummy : Integer; begin if not IsElementEditable(nil) then raise Exception.Create('File "'+GetFileName+'" is not editable'); Result := nil; if Length(aName) < 4 then Exit; Signature := StrToSignature(aName); Result := GetGroupBySignature(Signature); if Assigned(Result) then Exit; if not wbGroupOrder.Find(Signature, Dummy) then Exit; if GroupToSkip.Find(Signature, Dummy) then Exit; if RecordToSkip.Find(Signature, Dummy) then Exit; Result := TwbGroupRecord.Create(Self, Signature); if Length(cntElements) > 1 then wbMergeSort(@cntElements[1], High(cntElements), CompareSortOrder); end; function TwbFile.AddIfMissingInternal(const aElement: IwbElement; aAsNew, aDeepCopy : Boolean; const aPrefixRemove, aPrefix, aSuffix: string): IwbElement; var GroupRecord : IwbGroupRecord; Dummy : Integer; Signature : TwbSignature; SelfRef : IwbContainerElementRef; i : Integer; begin if not IsElementEditable(nil) then raise Exception.Create('File "'+GetFileName+'" is not editable'); SelfRef := Self as IwbContainerElementRef; if not Supports(aElement, IwbGroupRecord, GroupRecord) then raise Exception.Create('Only group records can be added to files'); if GroupRecord.GroupType <> 0 then raise Exception.Create('Only top level group records can be added to files'); Signature := TwbSignature(GroupRecord.GroupLabel); if not wbGroupOrder.Find(Signature, Dummy) then raise Exception.Create(Signature + 'is not a valid group label'); Result := GetGroupBySignature(Signature); if not Assigned(Result) then begin Result := TwbGroupRecord.Create(Self, Signature); if Length(cntElements) > 1 then wbMergeSort(@cntElements[1], High(cntElements), CompareSortOrder); end; if aDeepCopy then for i := 0 to Pred(GroupRecord.ElementCount) do Result.AddIfMissing(GroupRecord.Elements[i], aAsNew, True, aPrefixRemove, aPrefix, aSuffix); end; procedure TwbFile.AddMainRecord(const aRecord: IwbMainRecord); const MGEF : TwbSignature = 'MGEF'; GMST : TwbSignature = 'GMST'; var FormID : Cardinal; s : string; i : Integer; Master : IwbMainRecord; FileID : Byte; Signature : TwbSignature; begin if not Assigned(aRecord) then Exit; FormID := aRecord.FormID; if FormID <> 0 then begin if flFormIDsSorted then begin if Length(flRecords) > 0 then begin if FindFormID(FormID, i) then raise Exception.Create('Duplicate FormID ['+IntToHex64(FormID, 8)+'] in file ' + GetName); end else i := 0; SetLength(flRecords, Succ(Length(flRecords))); if i < High(flRecords) then begin Move(flRecords[i], flRecords[Succ(i)], SizeOf(Pointer) * (High(flRecords) - i)); Pointer(flRecords[i]) := nil; end; flRecords[i] := aRecord; end else begin if flRecordsCount >= Length(flRecords) then SetLength(flRecords, Succ(flRecordsCount)); flRecords[flRecordsCount] := aRecord; Inc(flRecordsCount); end; FileID := FormID shr 24; if FileID >= Cardinal(GetMasterCount) then begin {new record...} end else try Master := GetMasterRecordByFormID(FormID, True); if Assigned(Master) then (Master as IwbMainRecordInternal).AddOverride(aRecord) else (GetMaster(FileID) as IwbFileInternal).InjectMainRecord(aRecord); except on E: Exception do if Assigned(wbProgressCallback) then wbProgressCallback('Error: <'+e.Message+'> while trying to determine master record for ' + aRecord.Name); end; end; if flFormIDsSorted then Exit; Signature := aRecord.Signature; if (Cardinal(Signature) = Cardinal(MGEF)) or (Cardinal(Signature) = Cardinal(GMST)) or wbTrackAllEditorID then begin s := aRecord.EditorID; if s <> '' then begin if flRecordsByEditorIDCount >= Length(flRecordsByEditorID) then SetLength(flRecordsByEditorID, Succ(flRecordsByEditorIDCount)); flRecordsByEditorID[flRecordsByEditorIDCount] := aRecord; Inc(flRecordsByEditorIDCount); end; end; end; procedure TwbFile.AddMaster(const aFile: IwbFile); begin SetLength(flMasters, Succ(Length(flMasters))); flMasters[High(flMasters)] := aFile; end; procedure TwbFile.AddMasterIfMissing(const aMaster: string); var i : Integer; Masters : TStringList; begin for i := 0 to Pred(GetMasterCount) do if SameText(aMaster, GetMaster(i).FileName) then Exit; Masters := TStringList.Create; try Masters.Add(aMaster); AddMasters(Masters); SortMasters; finally Masters.Free; end; end; procedure TwbFile.AddMasters(aMasters: TStrings); var OldMasterCount : Integer; Header : IwbContainerElementRef; MasterFiles : IwbContainerElementRef; IsNew : Boolean; rec : IwbRecord; i, j : Integer; begin OldMasterCount := GetMasterCount; if not IsElementEditable(nil) then raise Exception.Create('File "'+GetFileName+'" is not editable'); if GetIsNotPlugin then Exit; if (GetElementCount < 1) or not Supports(GetElement(0), IwbContainerElementRef, Header) then raise Exception.CreateFmt('Unexpected error reading file "%s"', [flFileName]); IsNew := False; MasterFiles := Header.ElementByName['Master Files'] as IwbContainerElementRef; if not Assigned(MasterFiles) then begin Header.Assign(5, nil, False); MasterFiles := Header.ElementByName['Master Files'] as IwbContainerElementRef; Assert(Assigned(MasterFiles)); IsNew := True; end; for i := 0 to Pred(aMasters.Count) do begin if IsNew then begin Assert(MasterFiles.ElementCount = 1); Rec := (MasterFiles[0] as IwbContainer).RecordBySignature['MAST']; IsNew := False; end else begin j := MasterFiles.ElementCount; MasterFiles.Assign(High(Integer), nil, False); Assert(MasterFiles.ElementCount = Succ(j)); Rec := (MasterFiles[j] as IwbContainer).RecordBySignature['MAST']; end; Assert(Assigned(Rec)); Assert(Rec.EditValue = ''); Rec.EditValue := aMasters[i]; AddMaster(aMasters[i]); end; MasterCountUpdated(OldMasterCount, GetMasterCount); SortRecords; end; procedure TwbFile.BuildReachable; var Group : IwbGroupRecord; i : Integer; Rec : IwbMainRecord; Cnt : IwbContainerElementRef; Cnt2 : IwbContainerElementRef; Flg : IwbElement; s : string; begin Assert(Length(cntElements) > 0); cntElements[0].Reached; for i := Low(flRecords) to High(flRecords) do if flRecords[i].LoadOrderFormID > $800 then break else if flRecords[i].IsWinningOverride then (flRecords[i] as IwbElementInternal).Reached; Group := GetGroupBySignature('GMST'); if Assigned(Group) then for i := 0 to Pred(Group.ElementCount) do (Group.Elements[i] as IwbElementInternal).Reached; Group := GetGroupBySignature('ANIO'); if Assigned(Group) then for i := 0 to Pred(Group.ElementCount) do (Group.Elements[i] as IwbElementInternal).Reached; Group := GetGroupBySignature('IDLE'); if Assigned(Group) then for i := 0 to Pred(Group.ElementCount) do (Group.Elements[i] as IwbElementInternal).Reached; Group := GetGroupBySignature('LSCR'); if Assigned(Group) then for i := 0 to Pred(Group.ElementCount) do (Group.Elements[i] as IwbElementInternal).Reached; if wbGameMode = gmTES4 then begin Group := GetGroupBySignature('SKIL'); if Assigned(Group) then for i := 0 to Pred(Group.ElementCount) do (Group.Elements[i] as IwbElementInternal).Reached; Group := GetGroupBySignature('BSGN'); if Assigned(Group) then for i := 0 to Pred(Group.ElementCount) do (Group.Elements[i] as IwbElementInternal).Reached; Group := GetGroupBySignature('CLAS'); if Assigned(Group) then for i := 0 to Pred(Group.ElementCount) do if Supports(Group.Elements[i], IwbMainRecord, Rec) then begin if Rec.IsWinningOverride then begin Cnt := Rec as IwbContainerElementRef; if Supports(Cnt.RecordBySignature['DATA'], IwbContainerElementRef, Cnt) then begin Flg := Cnt.ElementByName['Flags']; if Assigned(Flg) then begin s := Flg.EditValue; if (Length(s) > 0) and (s[1]='1') then (Rec as IwbElementInternal).Reached; end; end; end; end; end else begin Group := GetGroupBySignature('AVIF'); if Assigned(Group) then for i := 0 to Pred(Group.ElementCount) do (Group.Elements[i] as IwbElementInternal).Reached; Group := GetGroupBySignature('ADDN'); if Assigned(Group) then for i := 0 to Pred(Group.ElementCount) do (Group.Elements[i] as IwbElementInternal).Reached; Group := GetGroupBySignature('CAMS'); if Assigned(Group) then for i := 0 to Pred(Group.ElementCount) do (Group.Elements[i] as IwbElementInternal).Reached; Group := GetGroupBySignature('CPTH'); if Assigned(Group) then for i := 0 to Pred(Group.ElementCount) do (Group.Elements[i] as IwbElementInternal).Reached; Group := GetGroupBySignature('NAVI'); if Assigned(Group) then for i := 0 to Pred(Group.ElementCount) do (Group.Elements[i] as IwbElementInternal).Reached; Group := GetGroupBySignature('RADS'); if Assigned(Group) then for i := 0 to Pred(Group.ElementCount) do (Group.Elements[i] as IwbElementInternal).Reached; Group := GetGroupBySignature('PERK'); if Assigned(Group) then for i := 0 to Pred(Group.ElementCount) do if Supports(Group.Elements[i], IwbMainRecord, Rec) then begin if Rec.IsWinningOverride then begin Cnt := Rec as IwbContainerElementRef; if Supports(Cnt.RecordBySignature['DATA'], IwbContainerElementRef, Cnt) then begin Flg := Cnt.ElementByName['Playable']; if Assigned(Flg) then begin if Flg.NativeValue <> 0 then (Rec as IwbElementInternal).Reached; end; end; end; end; Group := GetGroupBySignature('HDPT'); if Assigned(Group) then for i := 0 to Pred(Group.ElementCount) do if Supports(Group.Elements[i], IwbMainRecord, Rec) then begin if Rec.IsWinningOverride then begin Cnt := Rec as IwbContainerElementRef; if Supports(Cnt.RecordBySignature['DATA'], IwbContainerElementRef, Cnt) then begin if (Integer(Cnt.NativeValue) and 1) <> 0 then (Rec as IwbElementInternal).Reached; end; end; end; Group := GetGroupBySignature('DIAL'); if Assigned(Group) then for i := 0 to Pred(Group.ElementCount) do if Supports(Group.Elements[i], IwbMainRecord, Rec) then begin if Rec.IsWinningOverride then begin Cnt := Rec as IwbContainerElementRef; if Supports(Cnt.RecordBySignature['DATA'], IwbContainerElementRef, Cnt2) then begin Flg := Cnt2.ElementByName['Flags']; if Assigned(Flg) then begin s := Flg.SortKey[False]; if (Length(s)>1) and (s[2] = '1') then (Rec as IwbElementInternal).Reached; end; end; end; end; Group := GetGroupBySignature('NPC_'); if Assigned(Group) then for i := 0 to Pred(Group.ElementCount) do if Supports(Group.Elements[i], IwbMainRecord, Rec) then begin if Rec.IsWinningOverride then begin Cnt := Rec as IwbContainerElementRef; if Supports(Cnt.RecordBySignature['ACBS'], IwbContainerElementRef, Cnt) then begin Flg := Cnt.ElementByName['Flags']; if Assigned(Flg) then begin s := Flg.EditValue; if (Length(s) > 2) and (s[3]='1') then (Rec as IwbElementInternal).Reached; end; end; end; end; end; Group := GetGroupBySignature('RACE'); if Assigned(Group) then for i := 0 to Pred(Group.ElementCount) do if Supports(Group.Elements[i], IwbMainRecord, Rec) then begin if Rec.IsWinningOverride then begin Cnt := Rec as IwbContainerElementRef; if Supports(Cnt.RecordBySignature['DATA'], IwbContainerElementRef, Cnt) then begin Flg := Cnt.ElementByName['Flags']; if Assigned(Flg) then begin s := Flg.EditValue; if (Length(s) > 0) and (s[1]='1') then (Rec as IwbElementInternal).Reached; end; end; end; end; Group := GetGroupBySignature('QUST'); if Assigned(Group) then for i := 0 to Pred(Group.ElementCount) do if Supports(Group.Elements[i], IwbMainRecord, Rec) then begin if Rec.IsWinningOverride then begin Cnt := Rec as IwbContainerElementRef; if Supports(Cnt.RecordBySignature['DATA'], IwbContainerElementRef, Cnt) then begin Flg := Cnt.Elements[0]; if Assigned(Flg) then begin s := Flg.EditValue; if (Length(s) > 0) and (s[1]='1') then (Rec as IwbElementInternal).Reached; end; end; end; end; end; procedure TwbFile.BuildRef; begin inherited; end; procedure TwbFile.CleanMasters; var i, j, k : Integer; Old,New : TBytes; Header : IwbContainerElementRef; MasterFiles : IwbContainerElementRef; Rec : IwbRecord; UsedMasters : TwbUsedMasters; begin if not IsElementEditable(nil) then raise Exception.Create('File "'+GetFileName+'" is not editable'); if (GetElementCount < 1) or not Supports(GetElement(0), IwbContainerElementRef, Header) then raise Exception.CreateFmt('Unexpected error reading file "%s"', [flFileName]); if Length(flMasters) >= 1 then begin MasterFiles := Header.ElementByName['Master Files'] as IwbContainerElementRef; Assert(Assigned(MasterFiles)); Assert(MasterFiles.ElementCount = Length(flMasters)); for i := Low(flMasters) to High(flMasters) do begin Rec := (MasterFiles[i] as IwbContainer).RecordBySignature['MAST']; Assert(Assigned(Rec)); Assert(SameText(Rec.Value, flMasters[i].FileName)); MasterFiles[i].SortOrder := i; end; FillChar(UsedMasters, SizeOf(UsedMasters), 0); FindUsedMasters(@UsedMasters); Old := nil; New := nil; j := 0; for i := Low(flMasters) to High(flMasters) do if UsedMasters[i] then begin if i <> j then begin flMasters[j] := flMasters[i]; MasterFiles[i].SortOrder := j; SetLength(Old, Succ(Length(Old))); Old[High(Old)] := i; SetLength(New, Succ(Length(New))); New[High(New)] := j; end; Inc(j); end else MasterFiles[i].SortOrder := $100; k := Length(flMasters); if j <> k then begin SetLength(flMasters, j); (MasterFiles as IwbContainerInternal).SortBySortOrder; for i := Pred(MasterFiles.ElementCount) downto 0 do if MasterFiles[i].SortOrder = $100 then MasterFiles.RemoveElement(i); Assert(Length(flMasters) = MasterFiles.ElementCount); for i := Low(flMasters) to High(flMasters) do begin Rec := (MasterFiles[i] as IwbContainer).RecordBySignature['MAST']; Assert(Assigned(Rec)); Assert(SameText(Rec.Value, flMasters[i].FileName)); end; if Length(Old) > 0 then MasterIndicesUpdated(Old, New); MasterCountUpdated(k, j); SortRecords; end; end; end; constructor TwbFile.Create(const aFileName: string; aLoadOrder: Integer; aCompareTo: string; aOnlyHeader: Boolean; IsTemporary: Boolean = False); begin if IsTemporary then Include(flStates, fsIsTemporary); if aCompareTo <> '' then begin Include(flStates, fsIsCompareLoad); if SameText(ExtractFileName(aFileName), wbGameName + wbHardcodedDat) then Include(flStates, fsIsHardcoded); end else if SameText(ExtractFileName(aFileName), wbGameName + '.esm') then Include(flStates, fsIsGameMaster); if aOnlyHeader then Include(flStates, fsOnlyHeader); flCompareTo := aCompareTo; flLoadOrder := aLoadOrder; flFileName := aFileName; flOpenFile; Scan; end; constructor TwbFile.CreateNew(const aFileName: string; aLoadOrder: Integer); var Header : IwbMainRecord; begin Include(flStates, fsIsNew); flLoadOrder := aLoadOrder; flFileName := aFileName; Header := TwbMainRecord.Create(Self, wbHeaderSignature, 0); if wbGameMode = gmFNV then Header.RecordBySignature['HEDR'].Elements[0].EditValue := '1.34' else if wbGameMode = gmFO3 then Header.RecordBySignature['HEDR'].Elements[0].EditValue := '0.94' else if wbGameMode = gmTES3 then Header.RecordBySignature['HEDR'].Elements[0].EditValue := '1.30' else if wbGameMode = gmTES4 then Header.RecordBySignature['HEDR'].Elements[0].EditValue := '1.0' else if wbGameMode = gmTES5 then Header.RecordBySignature['HEDR'].Elements[0].EditValue := '1.7' else if wbGameMode = gmSSE then Header.RecordBySignature['HEDR'].Elements[0].EditValue := '1.7' else if wbGameMode = gmFO4 then Header.RecordBySignature['HEDR'].Elements[0].EditValue := '0.95'; Header.RecordBySignature['HEDR'].Elements[2].EditValue := '2048'; flLoadFinished := True; end; destructor TwbFile.Destroy; begin flCloseFile; inherited; end; function TwbFile.FileFileIDtoLoadOrderFileID(aFileID: Byte): Byte; var NewFileID : Integer; begin if aFileID >= GetMasterCount then NewFileID := GetLoadOrder else NewFileID := flMasters[aFileID].LoadOrder; if NewFileID < 0 then raise Exception.Create('File FormID ['+IntToHex64(aFileID, 2)+'] can not be mapped to load order FormID for file "'+GetFileName+'"'); Result := NewFileID; end; function TwbFile.FileFormIDtoLoadOrderFormID(aFormID: Cardinal): Cardinal; var FileID : Integer; NewFileID : Integer; begin if aFormID = 0 then begin Result := 0; Exit; end; FileID := aFormID shr 24; if FileID >= GetMasterCount then NewFileID := GetLoadOrder else NewFileID := flMasters[FileID].LoadOrder; if NewFileID < 0 then raise Exception.Create('File FormID ['+IntToHex64(aFormID, 8)+'] can not be mapped to load order FormID for file "'+GetFileName+'"'); Result := (aFormID and $00FFFFFF) or (Cardinal(NewFileID) shl 24); end; function TwbFile.FindEditorID(const aEditorID: string; var Index: Integer): Boolean; var L, H, I, C: Integer; begin Result := False; if not flLoadFinished then Exit; L := Low(flRecordsByEditorID); H := High(flRecordsByEditorID); while L <= H do begin I := (L + H) shr 1; C := CompareText(flRecordsByEditorID[I].EditorID, aEditorID); if C < 0 then L := I + 1 else begin H := I - 1; if C = 0 then begin Result := True; L := I; end; end; end; Index := L; end; function TwbFile.FindFormID(aFormID: Cardinal; var Index: Integer): Boolean; var L, H, I, C: Integer; begin Result := False; if not flFormIDsSorted then begin Exit; for i := 0 to Pred(flRecordsCount) do if flRecords[I].FixedFormID = aFormID then begin Index := i; Result := True; Exit; end; Exit; end; if (aFormID shr 24) > Cardinal(GetMasterCount) then aFormID := (aFormID and $00FFFFFF) or (Cardinal(GetMasterCount) shl 24); L := Low(flRecords); H := High(flRecords); while L <= H do begin I := (L + H) shr 1; C := CmpW32(flRecords[I].FixedFormID, aFormID); if C < 0 then L := I + 1 else begin H := I - 1; if C = 0 then begin Result := True; L := I; end; end; end; Index := L; end; function TwbFile.FindInjectedID(aFormID: Cardinal; var Index: Integer): Boolean; var L, H, I, C: Integer; begin Result := False; aFormID := aFormID and $00FFFFFF; L := Low(flInjectedRecords); H := High(flInjectedRecords); while L <= H do begin I := (L + H) shr 1; C := CmpW32(flInjectedRecords[I].FormID and $00FFFFFF, aFormID); if C < 0 then L := I + 1 else begin H := I - 1; if C = 0 then begin Result := True; L := I; end; end; end; Index := L; end; procedure TwbFile.flCloseFile; begin if Assigned(flView) then begin UnmapViewOfFile(flView); flView := nil; end; if (flMapHandle <> INVALID_HANDLE_VALUE) and (flMapHandle <> 0) then begin CloseHandle(flMapHandle); flMapHandle := INVALID_HANDLE_VALUE; end; if (flFileHandle <> INVALID_HANDLE_VALUE) and (flFileHandle <> 0) then begin CloseHandle(flFileHandle); flFileHandle := INVALID_HANDLE_VALUE; end; if fsIsTemporary in flStates then try DeleteFile(Self.flFileName); except wbProgressCallback('Could not delete temporary file '+flFileName); end; end; procedure TwbFile.flOpenFile; const FileAccessMode: array[Boolean] of Cardinal = (GENERIC_READ, GENERIC_READ or GENERIC_WRITE); FileShareMode: array[Boolean] of Cardinal = (FILE_SHARE_READ, 0); PageProtection: array[Boolean] of Cardinal = (PAGE_READONLY, PAGE_READWRITE); ViewAccessMode: array[Boolean] of Cardinal = (FILE_MAP_READ, FILE_MAP_READ or FILE_MAP_WRITE); begin flProgress('Loading file'); flFileHandle := CreateFile( PChar(flFileName), FileAccessMode[False], FileShareMode[False], nil, OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS, 0 ); if (flFileHandle = INVALID_HANDLE_VALUE) or (flFileHandle = 0) then RaiseLastOSError; flMapHandle := CreateFileMapping( flFileHandle, nil, PageProtection[False], 0, 0, nil ); if (flMapHandle = INVALID_HANDLE_VALUE) or (flMapHandle = 0) then RaiseLastOSError; flView := MapViewOfFileEx( flMapHandle, ViewAccessMode[False], 0, 0, 0, nil ); if not Assigned(flView) then RaiseLastOSError; flEndPtr := Pointer( Cardinal(flView) + GetFileSize(flFileHandle, nil) ); flProgress('File loaded'); end; procedure TwbFile.flProgress(const aStatus: string); begin if Assigned(wbProgressCallback) then wbProgressCallback('['+GetFileName+'] ' + aStatus); end; procedure TwbFile.ForceClosed; var i: Integer; begin for i := High(flRecords) downto Low(flRecords) do (flRecords[i] as IwbMainRecordInternal).ClearForRelease; for i := High(flInjectedRecords) downto Low(flInjectedRecords) do (flInjectedRecords[i] as IwbMainRecordInternal).ClearForRelease; flMasters := nil; flRecords := nil; flRecordsByEditorID := nil; flInjectedRecords := nil; ReleaseElements; flCloseFile; end; procedure TwbFile.ForceLoadOrder(aValue: Integer); begin flLoadOrder := aValue; end; function TwbFile.GetAddList: TDynStrings; var i, j : Integer; GroupRecord : IwbGroupRecord; RecordDef : PwbRecordDef; begin Result := nil; if not IsElementEditable(nil) then Exit; with TStringList.Create do try Sorted := True; Duplicates := dupIgnore; AddStrings(wbGroupOrder); for i := 0 to Pred(GroupToSkip.Count) do if Find(GroupToSkip[i], j) then Delete(j); for i := 0 to Pred(RecordToSkip.Count) do if Find(RecordToSkip[i], j) then Delete(j); for i := Succ(Low(cntElements)) to High(cntElements) do if Supports(cntElements[i], IwbGroupRecord, GroupRecord) then if GroupRecord.GroupType = 0 then if Find(TwbSignature(GroupRecord.GroupLabel), j) then Delete(j); Sorted := False; for i := Pred(Count) downto 0 do if wbFindRecordDef(AnsiString(Strings[i]), RecordDef) then Strings[i] := Strings[i] + ' - ' + RecordDef.Name else Delete(i); SetLength(Result, Count); for i := 0 to Pred(Count) do Result[i] := Strings[i]; finally Free; end; end; function TwbFile.GetBaseName: string; begin Result := GetFileName; if fsIsHardcoded in flStates then Result := wbGameName + '.exe'; end; function TwbFile.GetElementType: TwbElementType; begin Result := etFile; end; function TwbFile.GetFile: IwbFile; begin Result := Self; end; function TwbFile.GetFileName: string; begin Result := ExtractFileName(flFileName); end; function TwbFile.GetFileStates: TwbFileStates; begin Result := flStates; end; function TwbFile.GetGroupBySignature(const aSignature: TwbSignature): IwbGroupRecord; var SelfRef: IwbContainerElementRef; i: Integer; begin SelfRef := Self; DoInit; for i := Low(cntElements) to High(cntElements) do if Supports(cntElements[i], IwbGroupRecord, Result) and (Result.GroupType = 0) and (TwbSignature(Result.GroupLabel) = aSignature) then Exit; Result := nil; end; function TwbFile.GetHasNoFormID: Boolean; begin Result := GetIsNotPlugin or (fsHasNoFormID in flStates); end; function TwbFile.GetHeader: IwbMainRecord; var SelfRef : IwbContainerElementRef; begin SelfRef := Self; DoInit; if (Length(cntElements) > 0) and (Supports(cntElements[0], IwbMainRecord, Result)) and (Result.Signature = wbHeaderSignature) then begin {Result already set} end else Result := nil; end; function TwbFile.GetIsEditable: Boolean; begin Result := wbIsInternalEdit or ( wbEditAllowed and not (fsIsGameMaster in flStates) and not (fsIsHardcoded in flStates) and not (fsIsCompareLoad in flStates) ); end; function TwbFile.GetIsESM: Boolean; var Header : IwbMainRecord; begin if GetIsNotPlugin then begin Result := False; Exit; end; if (GetElementCount < 1) or not Supports(GetElement(0), IwbMainRecord, Header) then raise Exception.CreateFmt('Unexpected error reading file "%s"', [flFileName]); Result := Header.IsESM; end; function TwbFile.GetIsLocalized: Boolean; var Header : IwbMainRecord; begin if GetIsNotPlugin then begin Result := False; Exit; end; if (GetElementCount < 1) or not Supports(GetElement(0), IwbMainRecord, Header) then raise Exception.CreateFmt('Unexpected error reading file "%s"', [flFileName]); Result := Header.IsLocalized; end; function TwbFile.GetNextObjectID: Cardinal; var Header : IwbContainerElementRef; begin if (GetElementCount > 0) and Supports(GetElement(0), IwbContainerElementRef, Header) then Result := Cardinal(Header.ElementNativeValues['HEDR\Next Object ID']) else Result := 0; end; procedure TwbFile.SetNextObjectID(aObjectID: Cardinal); var Header : IwbMainRecord; begin if (GetElementCount > 0) and Supports(GetElement(0), IwbContainerElementRef, Header) then Header.ElementNativeValues['HEDR\Next Object ID'] := aObjectID; end; function TwbFile.GetIsNotPlugin: Boolean; begin Result := not wbIsPlugin(flFileName); end; function TwbFile.GetIsRemoveable: Boolean; begin Result := False; end; function TwbFile.GetLoadOrder: Integer; begin Result := flLoadOrder; end; function TwbFile.GetMaster(aIndex: Integer): IwbFile; begin Result := flMasters[aIndex]; end; function TwbFile.GetMasterCount: Integer; begin Result := Length(flMasters); end; function TwbFile.GetMasterRecordByFormID(aFormID: Cardinal; aAllowInjected: Boolean): IwbMainRecord; var FileID : Byte; Master : IwbFile; begin FileID := aFormID shr 24; if FileID >= Cardinal(GetMasterCount) then begin Result := nil; end else begin Master := flMasters[FileID]; Result := Master.RecordByFormID[(aFormID and $00FFFFFF) or (Cardinal(Master.MasterCount) shl 24), aAllowInjected]; end; end; procedure TwbFile.GetMasters(aMasters: TStrings); var Header : IwbMainRecord; MasterFiles : IwbContainerElementRef; Rec : IwbRecord; i : Integer; begin if (GetElementCount <> 1) or not Supports(GetElement(0), IwbMainRecord, Header) then raise Exception.CreateFmt('Unexpected error reading file "%s"', [flFileName]); if Header.Signature <> wbHeaderSignature then raise Exception.CreateFmt('Expected header signature '+wbHeaderSignature+', found %s in file "%s"', [String(Header.Signature), flFileName]); MasterFiles := Header.ElementByName['Master Files'] as IwbContainerElementRef; if Assigned(MasterFiles) then for i := 0 to Pred(MasterFiles.ElementCount) do begin Rec := (MasterFiles[i] as IwbContainer).RecordBySignature['MAST']; if not Assigned(Rec) then raise Exception.CreateFmt('Unexpected error reading master list for file "%s"', [flFileName]); aMasters.Add(Rec.Value); end; end; function TwbFile.GetName: string; begin Result := GetFileName; if fsIsHardcoded in flStates then Result := wbGameName + '.exe'; if flLoadOrder >= 0 then Result := '['+IntToHex64(flLoadOrder, 2)+'] ' + Result; end; function TwbFile.GetRecord(aIndex: Integer): IwbMainRecord; begin Result := flRecords[aIndex]; end; function TwbFile.GetRecordByEditorID(const aEditorID: string): IwbMainRecord; var i: Integer; begin Result := nil; if FindEditorID(aEditorID, i) then Result := flRecordsByEditorID[i] else for i := Pred(GetMasterCount) downto 0 do begin Result := GetMaster(i).RecordByEditorID[aEditorID]; if Assigned(Result) then Exit; end; end; function TwbFile.GetRecordByFormID(aFormID: Cardinal; aAllowInjected: Boolean): IwbMainRecord; var i: Integer; begin if FindFormID(aFormID, i) then begin Result := flRecords[i]; Exit; end else if aAllowInjected and ((aFormID shr 24) >= Cardinal(GetMasterCount)) and FindInjectedID(aFormID, i) then begin Result := flInjectedRecords[i]; Exit; end; Result := GetMasterRecordByFormID(aFormID, aAllowInjected); end; function TwbFile.GetRecordCount: Integer; begin Result := Length(flRecords); end; function TwbFile.GetReferenceFile: IwbFile; begin Result := Self; end; function TwbFile.GetUnsavedSince: TDateTime; begin Result := flUnsavedSince; end; function TwbFile.HasGroup(const aSignature: TwbSignature): Boolean; begin Result := GetGroupBySignature(aSignature) <> nil; end; function TwbFile.HasMaster(const aFileName: string): Boolean; var i: Integer; begin Result := False; for i := 0 to Pred(GetMasterCount) do begin Result := SameText(GetMaster(i).FileName, aFileName); if Result then Exit; end; end; procedure TwbFile.InjectMainRecord(const aRecord: IwbMainRecord); var i: Integer; begin if Length(flInjectedRecords) > 0 then begin if FindInjectedID(aRecord.FormID, i) then begin if [fsIsHardcoded, fsIsCompareLoad] * flInjectedRecords[i]._File.FileStates = [] then begin if Assigned(wbProgressCallback) then wbProgressCallback(''); end; (flInjectedRecords[i] as IwbMainRecordInternal).AddOverride(aRecord); Exit; end end else i := 0; if [fsIsHardcoded, fsIsCompareLoad] * aRecord._File.FileStates = [] then begin if Assigned(wbProgressCallback) then wbProgressCallback(''); end; SetLength(flInjectedRecords, Succ(Length(flInjectedRecords))); if i < High(flInjectedRecords) then begin Move(flInjectedRecords[i], flInjectedRecords[Succ(i)], SizeOf(Pointer) * (High(flInjectedRecords) - i)); Pointer(flInjectedRecords[i]) := nil; end; flInjectedRecords[i] := aRecord; end; function TwbFile.IsElementEditable(const aElement: IwbElement): Boolean; begin Result := wbIsInternalEdit or GetIsEditable; end; function TwbFile.IsElementRemoveable(const aElement: IwbElement): Boolean; begin Result := False; if not IsElementEditable(aElement) then Exit; if Assigned(aElement) then case aElement.ElementType of etMainRecord: Result := (aElement as IwbMainRecord).Signature <> wbHeaderSignature; {can't remove the file header} etGroupRecord: Result := True; else Assert(False); end; end; function TwbFile.LoadOrderFileIDtoFileFileID(aFileID: Byte): Byte; var NewFileID : Integer; i : Integer; begin NewFileID := -1; if aFileID = GetLoadOrder then NewFileID := GetMasterCount else for i := 0 to Pred(GetMasterCount) do if flMasters[i].LoadOrder = aFileID then begin NewFileID := i; Break; end; if NewFileID < 0 then raise Exception.Create('Load order FileID ['+IntToHex64(aFileID, 2)+'] can not be mapped to file FileID for file "'+GetFileName+'"'); Result := NewFileID; end; function TwbFile.LoadOrderFormIDtoFileFormID(aFormID: Cardinal): Cardinal; var FileID : Integer; NewFileID : Integer; i : Integer; begin if aFormID = 0 then begin Result := 0; Exit; end; FileID := aFormID shr 24; NewFileID := -1; if FileID = GetLoadOrder then NewFileID := GetMasterCount else for i := 0 to Pred(GetMasterCount) do if flMasters[i].LoadOrder = FileID then begin NewFileID := i; Break; end; if NewFileID < 0 then raise Exception.Create('Load order FormID ['+IntToHex64(aFormID, 8)+'] can not be mapped to file FormID for file "'+GetFileName+'"'); Result := (aFormID and $00FFFFFF) or (Cardinal(NewFileID) shl 24); end; function TwbFile.NewFormID: Cardinal; var SelfRef : IwbContainerElementRef; FileHeader : IwbMainRecord; HEDR : IwbRecord; begin SelfRef := Self as IwbContainerElementRef; DoInit; if Length(cntElements) < 1 then raise Exception.Create('File '+GetFileName+' has no file header'); if cntElements[0].ElementType <> etMainRecord then raise Exception.Create('File '+GetFileName+' has invalid record '+cntElements[0].Name+' as file header.'); FileHeader := cntElements[0] as IwbMainRecord; if FileHeader.Signature <> wbHeaderSignature then raise Exception.Create('File '+GetFileName+' has invalid record '+cntElements[0].Name+' with invalid signature as file header.'); HEDR := FileHeader.RecordBySignature['HEDR']; if not Assigned(HEDR) then raise Exception.Create('File '+GetFileName+' has a file header with missing HEDR subrecord'); Result := StrToInt64Def(HEDR.Elements[2].EditValue, 2048); Result := Result and $00FFFFFF; if (Result = 0) or (Result = $00FFFFFF) then Result := StrToInt64Def(HEDR.Elements[1].EditValue, 2048); if Result < 2048 then Result := 2048; Result := (Result and $00FFFFFF) or (Cardinal(GetMasterCount) shl 24); while GetRecordByFormID(Result, True) <> nil do begin Inc(Result); if Cardinal(Result shr 24) <> Cardinal(Length(flMasters)) then Result := Cardinal(2048) or (Cardinal(GetMasterCount) shl 24); end; HEDR.Elements[2].EditValue := IntToStr(Succ(Result) and $00FFFFFF); end; procedure TwbFile.PrepareSave; var SelfRef : IwbContainerElementRef; i, j, k : Integer; GroupRecord : IwbGroupRecord; Groups : array of Boolean; RecordCount : Cardinal; FileHeader: IwbMainRecord; HEDR: IwbRecord; MasterFiles : IwbContainerElementRef; MasterFile : IwbContainerElementRef; ONAMs: IwbContainerElementRef; NewONAM: IwbElement; Current: IwbMainRecord; FormID: Cardinal; FileID: Cardinal; Signature : TwbSignature; Master : IwbMainRecord; begin SelfRef := Self as IwbContainerElementRef; DoInit; if Length(cntElements) < 1 then raise Exception.Create('File '+GetFileName+' has no file header'); if not GetIsNotPlugin then begin if cntElements[0].ElementType <> etMainRecord then raise Exception.Create('File '+GetFileName+' has invalid record '+cntElements[0].Name+' as file header.'); FileHeader := cntElements[0] as IwbMainRecord; if FileHeader.Signature <> wbHeaderSignature then raise Exception.Create('File '+GetFileName+' has invalid record '+cntElements[0].Name+' with invalid signature as file header.'); HEDR := FileHeader.RecordBySignature['HEDR']; if not Assigned(HEDR) then raise Exception.Create('File '+GetFileName+' has a file header with missing HEDR subrecord'); inherited; SetLength(Groups, wbGroupOrder.Count); for i := Succ(Low(cntElements)) to High(cntElements) do begin if not Supports(cntElements[i], IwbGroupRecord, GroupRecord) then raise Exception.Create('File '+GetFileName+' contains invalid top level record: '+ cntElements[i].Name); if GroupRecord.GroupType <> 0 then raise Exception.Create('File '+GetFileName+' contains invalid top level group type '+IntToStr(GroupRecord.GroupType)+' for group: '+ cntElements[i].Name); if GroupRecord.SortOrder < 0 then raise Exception.Create('File '+GetFileName+' contains top level group without known sort order: '+ cntElements[i].Name); if GroupRecord.SortOrder > High(Groups) then raise Exception.Create('File '+GetFileName+' contains top level group with invalid sort order: '+ cntElements[i].Name); if Groups[GroupRecord.SortOrder] then raise Exception.Create('File '+GetFileName+' contains duplicated top level group: '+ cntElements[i].Name); Groups[GroupRecord.SortOrder] := True; end; if Length(cntElements) > 1 then wbMergeSort(@cntElements[1], High(cntElements), CompareSortOrder); RecordCount := GetCountedRecordCount; if RecordCount < 1 then raise Exception.Create('File '+GetFileName+' has an invalid record count'); HEDR.Elements[1].EditValue := IntToStr(Pred(RecordCount)); j := 0; ONAMs := nil; if wbGameMode in [gmFO3, gmFNV, gmTES5, gmSSE, gmFO4] then begin Include(TwbMainRecord(FileHeader).mrStates, mrsNoUpdateRefs); while FileHeader.RemoveElement('ONAM') <> nil do ; if Supports(FileHeader.ElementByName['Master Files'], IwbContainerElementRef, MasterFiles) then for i := 0 to Pred(MasterFiles.ElementCount) do begin if Supports(MasterFiles.Elements[i], IwbContainerElementRef, MasterFile) then begin // Fallout 4 CK creates ONAMs in ESP too if FileHeader.IsESM or (wbGameMode = gmFO4) then while j <= High(flRecords) do begin Current := flRecords[j]; FormID := Current.FixedFormID; FileID := FormID shr 24; if FileID > i then Break; Assert(FileID = i); Inc(j); Signature := Current.Signature; if (Signature = 'NAVM') or (Signature = 'LAND') or (Signature = 'REFR') or (Signature = 'PGRE') or (Signature = 'PMIS') or (Signature = 'ACHR') or (Signature = 'ACRE') or (Signature = 'PARW') or {>>> Skyrim <<<} (Signature = 'PBEA') or {>>> Skyrim <<<} (Signature = 'PFLA') or {>>> Skyrim <<<} (Signature = 'PCON') or {>>> Skyrim <<<} (Signature = 'PBAR') or {>>> Skyrim <<<} (Signature = 'PHZD') or {>>> Skyrim <<<} // Fallout 4 (and later games?) ((wbGameMode >= gmFO4) and ( (Signature = 'SCEN') or (Signature = 'DLBR') or (Signature = 'DIAL') or (Signature = 'INFO') )) then begin if (not wbMasterUpdateFilterONAM) or Current.IsWinningOverride then begin // ONAMs are for overridden temporary refs only if Current.IsPersistent then Continue; if not Assigned(ONAMs) then begin if not Supports(FileHeader.Add('ONAM', True), IwbContainerElementRef, ONAMs) then Assert(False); Assert(ONAMs.ElementCount = 1); NewONAM := ONAMs.Elements[0]; end else NewONAM := ONAMs.Assign(High(Integer), nil, True); NewONAM.NativeValue := FormID; if wbMasterUpdateFixPersistence and not Current.IsPersistent and not Current.IsMaster then begin Master := Current.Master; if Assigned(Master) then begin if Master.IsPersistent then begin flProgress('Setting Persistent: ' + Current.Name); Current.IsPersistent := True; end else for k := 0 to Pred(Master.OverrideCount) do if Current.Equals(Master.Overrides[k]) then Break else if Master.Overrides[k].IsPersistent then begin flProgress('Setting Persistent: ' + Current.Name); Current.IsPersistent := True; Break; end; end; end; end; end; end; end; if j > High(flRecords) then Break; end; Exclude(TwbMainRecord(FileHeader).mrStates, mrsNoUpdateRefs); FileHeader.UpdateRefs; end; if wbClampFormID then begin if Supports(FileHeader.ElementByName['Master Files'], IwbContainerElementRef, MasterFiles) then k := MasterFiles.ElementCount else k := 0; for i := Low(flRecords) to High(flRecords) do flRecords[i].ClampFormID(k); end; end else inherited; end; function TwbFile.Reached: Boolean; begin Result := False; end; procedure TwbFile.RemoveInjectedMainRecord(const aRecord: IwbMainRecord); var i: Integer; begin if (Length(flInjectedRecords) > 0) and FindInjectedID(aRecord.FormID, i) then begin Assert( (aRecord as IwbElement) = (flInjectedRecords[i] as IwbElement) ); flInjectedRecords[i] := nil; if i < High(flInjectedRecords) then begin Move(flInjectedRecords[Succ(i)], flInjectedRecords[i], SizeOf(Pointer) * (High(flInjectedRecords) - i)); Pointer(flInjectedRecords[High(flInjectedRecords)]) := nil; end; SetLength(flInjectedRecords, Pred(Length(flInjectedRecords))); end; end; procedure TwbFile.RemoveMainRecord(const aRecord: IwbMainRecord); var i : Integer; Master : IwbMainRecord; FileID : Byte; begin if not Assigned(aRecord) then Exit; if aRecord.FormID <> 0 then begin Assert(flLoadFinished); if (Length(flRecords) < 1) or not FindFormID(aRecord.FormID, i) then raise Exception.Create('Can''t remove FormID ['+IntToHex64(aRecord.FormID, 8)+'] from file '+GetName+': FormID not registered'); flRecords[i] := nil; if i < High(flRecords) then begin Move(flRecords[Succ(i)], flRecords[i], SizeOf(Pointer) * (High(flRecords) - i)); Pointer(flRecords[High(flRecords)]) := nil; end; SetLength(flRecords, Pred(Length(flRecords))); FileID := aRecord.FormID shr 24; if FileID >= Cardinal(GetMasterCount) then begin {record for this file} end else try Master := GetMasterRecordByFormID(aRecord.FormID, True); if Assigned(Master) and ((Master as IwbElement) <> (aRecord as IwbElement)) then (Master as IwbMainRecordInternal).RemoveOverride(aRecord) else (GetMaster(FileID) as IwbFileInternal).RemoveInjectedMainRecord(aRecord); except on E: Exception do if Assigned(wbProgressCallback) then wbProgressCallback('Error: <'+e.Message+'> while trying to determine master record for ' + aRecord.Name); end; end; end; procedure TwbFile.Scan; var CurrentPtr : Pointer; Header : IwbMainRecord; HEDR : IwbRecord; MasterFiles : IwbContainerElementRef; Rec : IwbRecord; i, j : Integer; SelfRef : IwbContainerElementRef; Groups : array of IwbGroupRecord; GroupRecord : IwbGroupRecord; IsInternal : Boolean; begin SelfRef := Self as IwbContainerElementRef; flProgress('Start processing'); CurrentPtr := flView; TwbRecord.CreateForPtr(CurrentPtr, flEndPtr, Self, nil); if (GetElementCount <> 1) or not Supports(GetElement(0), IwbMainRecord, Header) then raise Exception.CreateFmt('Unexpected error reading file "%s"', [flFileName]); if Header.Signature <> wbHeaderSignature then raise Exception.CreateFmt('Expected header signature TES4, found %s in file "%s"', [String(Header.Signature), flFileName]); if fsOnlyHeader in flStates then Exit; MasterFiles := Header.ElementByName['Master Files'] as IwbContainerElementRef; if Assigned(MasterFiles) then for i := 0 to Pred(MasterFiles.ElementCount) do begin Rec := (MasterFiles[i] as IwbContainer).RecordBySignature['MAST']; if not Assigned(Rec) then raise Exception.CreateFmt('Unexpected error reading master list for file "%s"', [flFileName]); AddMaster(Rec.Value); end; if flCompareTo <> '' then AddMaster(flCompareTo); flRecordsCount := 0; HEDR := Header.RecordBySignature['HEDR']; if Assigned(HEDR) then begin SetLength(flRecords, StrToInt(HEDR.Elements[1].Value)); end; flProgress('Header processed. Expecting ' + IntToStr(Length(flRecords)) + ' records'); while Cardinal(CurrentPtr) < Cardinal(flEndPtr) do begin Rec := TwbRecord.CreateForPtr(CurrentPtr, flEndPtr, Self, nil); flProgress(Rec.Name + ' processed'); end; if flRecordsCount < Length(flRecords) then SetLength(flRecords, flRecordsCount); flProgress('Building FormID index'); if flRecordsCount < Length(flRecords) then SetLength(flRecords, flRecordsCount); SortRecords; flProgress('FormID index built'); flProgress('Building EditorID index'); if flRecordsByEditorIDCount < Length(flRecordsByEditorID) then SetLength(flRecordsByEditorID, flRecordsByEditorIDCount); SortRecordsByEditorID; flProgress('EditorID index built'); if wbGameMode in [gmFNV, gmTES5, gmSSE, gmFO4] then begin IsInternal := not GetIsEditable and wbBeginInternalEdit(True); try SetLength(Groups, wbGroupOrder.Count); for i := High(cntElements) downto Succ(Low(cntElements)) do begin if not Supports(cntElements[i], IwbGroupRecord, GroupRecord) then begin flProgress('Error: File contains invalid top level record: '+ cntElements[i].Name); Continue; end; if GroupRecord.GroupType <> 0 then begin flProgress('Error: File contains invalid top level group type '+IntToStr(GroupRecord.GroupType)+' for group: '+ cntElements[i].Name); Continue; end; if GroupRecord.SortOrder < 0 then begin flProgress('Error: File contains top level group without known sort order: '+ cntElements[i].Name); Continue; end; if GroupRecord.SortOrder > High(Groups) then begin flProgress('Error: File contains top level group with invalid sort order: '+ cntElements[i].Name); Continue; end; if Assigned(Groups[GroupRecord.SortOrder]) then begin flProgress('Warning: File contains duplicated top level group: ' + cntElements[i].Name); if wbBeginInternalEdit(True) then try if Groups[GroupRecord.SortOrder].ElementCount = 0 then begin Groups[GroupRecord.SortOrder].Remove; Groups[GroupRecord.SortOrder] := nil; Groups[GroupRecord.SortOrder] := GroupRecord; end else begin j := 0; while GroupRecord.ElementCount > 0 do begin Groups[GroupRecord.SortOrder].AddElement(GroupRecord.RemoveElement(0, True)); Inc(j); end; (Groups[GroupRecord.SortOrder] as IwbGroupRecordInternal).Sort; (Groups[GroupRecord.SortOrder] as IwbGroupRecordInternal).SetModified(True); flProgress('Merged ' + IntToStr(j) + ' record from duplicated group: ' + cntElements[i].Name); GroupRecord.Remove; end; finally wbEndInternalEdit; end; Continue; end; Groups[GroupRecord.SortOrder] := GroupRecord; end; finally if IsInternal then wbEndInternalEdit; end; end; flProgress('Processing completed'); flLoadFinished := True; end; procedure TwbFile.SetHasNoFormID(Value: Boolean); begin if Value or GetIsNotPlugin then Include(flStates, fsHasNoFormID) else Exclude(flStates, fsHasNoFormID); end; procedure TwbFile.SetIsESM(Value: Boolean); var Header : IwbMainRecord; begin if GetIsNotPlugin then begin Exit; end; if (GetElementCount < 1) or not Supports(GetElement(0), IwbMainRecord, Header) then raise Exception.CreateFmt('Unexpected error reading file "%s"', [flFileName]); if Value <> Header.IsESM then begin if not IsElementEditable(nil) then raise Exception.Create('File "'+GetFileName+'" is not editable'); Header.IsESM := Value; end; end; procedure TwbFile.SetIsLocalized(Value: Boolean); var Header : IwbMainRecord; begin if GetIsNotPlugin then begin Exit; end; if (GetElementCount < 1) or not Supports(GetElement(0), IwbMainRecord, Header) then raise Exception.CreateFmt('Unexpected error reading file "%s"', [flFileName]); if Value <> Header.IsLocalized then begin if not IsElementEditable(nil) then raise Exception.Create('File "'+GetFileName+'" is not editable'); Header.IsLocalized := Value; end; end; procedure TwbFile.SetLoadOrder(aValue: Integer); begin flLoadOrder := aValue; end; procedure TwbFile.SetModified(aValue: Boolean); begin if not (esUnsaved in eStates) and not wbIsInternalEdit then flUnsavedSince := Now; inherited; end; function CompareRecords(Item1, Item2: Pointer): Integer; var FormID1 : Cardinal; FormID2 : Cardinal; begin FormID1 := IwbMainRecord(Item1).FixedFormID; FormID2 := IwbMainRecord(Item2).FixedFormID; if FormID1 < FormID2 then Result := -1 else if FormID1 = FormID2 then Result := 0 else Result := 1; end; function CompareOverrides(Item1, Item2: Pointer): Integer; var LoadOrder1 : Cardinal; LoadOrder2 : Cardinal; begin LoadOrder1 := IwbMainRecord(Item1)._File.LoadOrder; LoadOrder2 := IwbMainRecord(Item2)._File.LoadOrder; if LoadOrder1 < LoadOrder2 then Result := -1 else if LoadOrder1 = LoadOrder2 then Result := 0 else Result := 1; end; function CompareRecordsByEditorID(Item1, Item2: Pointer): Integer; begin Result := CompareText(IwbMainRecord(Item1).EditorID, IwbMainRecord(Item2).EditorID); end; procedure TwbFile.SortMasters; var OldList : TStringList; i, j : Integer; Old,New : TBytes; Header : IwbContainerElementRef; MasterFiles : IwbContainerElementRef; Rec : IwbRecord; begin if not IsElementEditable(nil) then raise Exception.Create('File "'+GetFileName+'" is not editable'); if GetIsNotPlugin then Exit; if (GetElementCount < 1) or not Supports(GetElement(0), IwbContainerElementRef, Header) then raise Exception.CreateFmt('Unexpected error reading file "%s"', [flFileName]); if Length(flMasters) > 1 then begin MasterFiles := Header.ElementByName['Master Files'] as IwbContainerElementRef; Assert(Assigned(MasterFiles)); Assert(MasterFiles.ElementCount = Length(flMasters)); OldList := TStringList.Create; OldList.Sorted := True; OldList.Duplicates := dupError; try for i := Low(flMasters) to High(flMasters) do begin Rec := (MasterFiles[i] as IwbContainer).RecordBySignature['MAST']; Assert(Assigned(Rec)); Assert(SameText(Rec.Value, flMasters[i].FileName)); OldList.AddObject(flMasters[i].FileName, Pointer(i)); MasterFiles[i].SortOrder := i; end; wbMergeSort(@flMasters[0], Length(flMasters), CompareLoadOrder); Old := nil; New := nil; for i := Low(flMasters) to High(flMasters) do begin j := Integer(OldList.Objects[OldList.IndexOf(flMasters[i].FileName)]); if i <> j then begin MasterFiles[j].SortOrder := i; SetLength(Old, Succ(Length(Old))); Old[High(Old)] := j; SetLength(New, Succ(Length(New))); New[High(New)] := i; end; end; if Length(Old) > 0 then begin (MasterFiles as IwbContainerInternal).SortBySortOrder; MasterIndicesUpdated(Old, New); end; finally OldList.Free; end; SortRecords; end; end; type TwbRecordSortEntry = record rseFormID : Cardinal; rseMainRecord : Pointer; end; TwbRecordSortEntries = array of TwbRecordSortEntry; PwbRecordSortEntry = ^TwbRecordSortEntry; TwbRecordSortEntryPtrs = array of PwbRecordSortEntry; function CompareSortEntryPtrs(Item1{eax}, Item2{edx}: Pointer): Integer; asm {$IFDEF WIN32} mov ecx, [eax + TwbRecordSortEntry.rseFormID] mov edx, [edx + TwbRecordSortEntry.rseFormID] xor eax, eax cmp ecx, edx mov ecx, -1 cmovb eax, ecx seta al {$ENDIF WIN32} {$IFDEF WIN64} mov rcx, [rcx + TwbRecordSortEntry.rseFormID] mov rdx, [rdx + TwbRecordSortEntry.rseFormID] xor rax, rax cmp rcx, rdx mov rcx, -1 cmovb rax, rcx seta al {$ENDIF WIN64} end; procedure TwbFile.SortRecords; var SortEntries : TwbRecordSortEntries; SortEntryPtrs : TwbRecordSortEntryPtrs; i : Integer; begin i := Length(flRecords); if i > 0 then begin SetLength(SortEntries, i); SetLength(SortEntryPtrs, i); for i := Low(flRecords) to High(flRecords) do begin SortEntries[i].rseFormID := flRecords[i].FixedFormID; SortEntries[i].rseMainRecord := Pointer(flRecords[i]); SortEntryPtrs[i] := @SortEntries[i]; end; wbMergeSort(@SortEntryPtrs[0], Length(SortEntryPtrs), CompareSortEntryPtrs); for i := Low(flRecords) to High(flRecords) do Pointer(flRecords[i]) := SortEntryPtrs[i].rseMainRecord; end; flFormIDsSorted := True; end; procedure TwbFile.SortRecordsByEditorID; begin if Length(flRecordsByEditorID) > 0 then wbMergeSort(@flRecordsByEditorID[0], Length(flRecordsByEditorID), CompareRecordsByEditorID); end; procedure TwbFile.WriteToStreamInternal(aStream: TStream; aResetModified: Boolean); var SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; PrepareSave; inherited WriteToStreamInternal(aStream, aResetModified); Exclude(eStates, esUnsaved); if aResetModified then begin Exclude(eStates, esModified); Exclude(eStates, esInternalModified); end; end; type TwbUnionFlags = ( ufNone, ufArray, ufSortedArray, ufFlags ); function ArrayDoInit(const aValueDef: IwbValueDef; const aContainer: IwbContainer; var aBasePtr: Pointer; aEndPtr: Pointer; out SizePrefix: Integer): Boolean; forward; procedure StructDoInit(const aValueDef: IwbValueDef; const aContainer: IwbContainer; var aBasePtr: Pointer; aEndPtr: Pointer); forward; function UnionDoInit(const aValueDef: IwbValueDef; const aContainer: IwbContainer; var aBasePtr: Pointer; aEndPtr: Pointer): TwbUnionFlags; forward; function ValueDoInit(const aValueDef: IwbValueDef; const aContainer: IwbContainer; var aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Boolean; forward; { TwbContainer } function TwbContainer.Add(const aName: string; aSilent: Boolean): IwbElement; begin Result := nil; end; procedure TwbContainer.AddElement(const aElement: IwbElement); begin if not Assigned(aElement) then Exit; SetLength(cntElements, Succ(Length(cntElements))); cntElements[High(cntElements)] := aElement as IwbElementInternal; cntElements[High(cntElements)].SetContainer(Self); NotifyChanged(eContainer); end; function TwbContainer.IndexOf(const aElement: IwbElement): Integer; var i: Integer; begin Result := -1; if Assigned(aElement) then for i := Low(cntElements) to High(cntElements) do if aElement.Equals(cntElements[i]) then begin Result := i; Exit; end; end; procedure TwbContainer.InformStorage(var aBasePtr: Pointer; aEndPtr: Pointer); var i: Integer; j: Integer; k: Integer; l: Integer; m: Integer; n: Integer; SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; DoInit; m := Low(Integer); for l := Low(cntElements) to High(cntElements) do if cntElements[l].MemoryOrder > m then m := cntElements[l].MemoryOrder; for l := Low(cntElements) to High(cntElements) do if cntElements[l].MemoryOrder = Low(Integer) then begin cntElements[l].MemoryOrder := m + 1; Inc(m); end; m := Low(Integer); k := Low(Integer); for i := Low(cntElements) to High(cntElements) do begin n := k; j := High(Integer); for l := Low(cntElements) to High(cntElements) do begin if (m= Low(cntElements)); Assert(k <> n); m := cntElements[k].MemoryOrder; cntElements[k].InformStorage(aBasePtr, aEndPtr); end; end; procedure TwbContainer.InsertElement(aPosition: Integer; const aElement: IwbElement); begin if not Assigned(aElement) then Exit; SetLength(cntElements, Succ(Length(cntElements))); if aPosition < Low(cntElements) then aPosition := Low(cntElements) else if aPosition > High(cntElements) then aPosition := High(cntElements); if aPosition < High(cntElements) then begin Move(cntElements[aPosition], cntElements[Succ(aPosition)], (High(cntElements) - aPosition) * SizeOf(Pointer)); Pointer(cntElements[aPosition]) := nil; end; cntElements[aPosition] := aElement as IwbElementInternal; cntElements[aPosition].SetContainer(Self); NotifyChanged(eContainer); end; function TwbContainer.IsElementEditable(const aElement: IwbElement): Boolean; begin if Assigned(eContainer) then Result := IwbContainer(eContainer).IsElementEditable(Self) else Result := True; end; function TwbContainer.IsElementRemoveable(const aElement: IwbElement): Boolean; begin Result := False; end; function LockedInc(var Target: Integer): Integer; register; asm {$IFDEF WIN32} mov ecx, eax mov eax, 1 lock xadd [ecx], eax inc eax {$ENDIF WIN32} {$IFDEF WIN64} mov rax, 1 lock xadd [rcx], rax inc rax {$ENDIF WIN64} end; function LockedDec(var Target: Integer): Integer; register; asm {$IFDEF WIN32} mov ecx, eax mov eax, -1 lock xadd [ecx], eax dec eax {$ENDIF WIN32} {$IFDEF WIN64} mov rax, -1 lock xadd [rcx], rax dec rax {$ENDIF WIN64} end; procedure TwbContainer.AfterConstruction; begin inherited; {$IFDEF WIN64} LockedDec(cntElementRefs); {$ENDIF WIN64} {$IFDEF WIN32} asm mov eax, [Self] lock dec dword ptr [eax + cntElementRefs] end; {$ENDIF WIN32} end; function TwbContainer.AssignInternal(aIndex: Integer; const aElement: IwbElement; aOnlySK: Boolean): IwbElement; var Container : IwbContainer; uContainer : IwbContainerElementRef; sElement : IwbElement; BasePtr : Pointer; i, j : Integer; SelfRef : IwbContainerElementRef; ValueDef : IwbValueDef; UnionDef : IwbUnionDef; HasMap : Boolean; StructDef : IwbStructDef; OurSize : Integer; begin Result := nil; if not wbEditAllowed then raise Exception.Create(GetName + ' can not be assigned.'); SelfRef := Self as IwbContainerElementRef; if Assigned(eContainer) then if not IwbContainer(eContainer).IsElementEditable(Self) then Exit; DoInit; if inherited CanAssignInternal(aIndex, aElement, False) then Result := inherited AssignInternal(aIndex, aElement, aOnlySK); if (aIndex = Low(Integer)) and (Length(cntElements) > 0) then begin if Supports(aElement, IwbContainer, Container) and (Container.ElementCount = GetElementCount) then begin ValueDef := GetValueDef; if (ValueDef = aElement.ValueDef) or ( Assigned(ValueDef) and ( ValueDef.Equals(aElement.ValueDef) or ValueDef.CanAssign(Self, aIndex, aElement.ValueDef) ) ) then begin HasMap := Length(cntElementsMap) > 0; if HasMap then begin Assert(Length(cntElements) = Length(cntElementsMap)); //if the elements haven't got their space allocated yet, we need //to make sure they are first written to in the "on disk" order //before copying in the mapped order below SetToDefault; end; for i := Low(cntElements) to High(cntElements) do begin if HasMap then j := cntElementsMap[i] else j := i; // if we have a union, we cannot progress until the union has been resolved and its cntElements is populated sElement := Container.Elements[i]; if (sElement.ElementType = etUnion) and Supports(cntElements[j], IwbContainerElementRef, uContainer) and Supports(uContainer.GetValueDef, IwbUnionDef, UnionDef) then begin if (uContainer.ElementCount = 1) then begin // At this point it is usually the default choice set by default uContainer.RemoveElement(0); end; if (uContainer.ElementCount = 0) then begin BasePtr := nil; UnionDoInit(UnionDef, uContainer as IwbContainer, BasePtr, nil); end; end; if (not aOnlySK or GetIsInSK(cntElements[j].SortOrder)) then begin if cntElements[j].CanAssign(Low(Integer), sElement, False) then cntElements[j].Assign(Low(Integer), sElement, aOnlySK) else if Supports(sElement.ValueDef, IwbEmptyDef) then begin // this might be a case the source begin a struct // with "OptionalFromElement" empty elements at the end If Supports(Container.ResolvedValueDef, IwbStructDef, StructDef) then if StructDef.OptionalFromElement >= 0 then if StructDef.OptionalFromElement <= j then begin //yes it is Assert(not HasMap); //this would be really tricky to handle with mapped elements... Assert(Self is TwbDataContainer); //if the source is a struct and is assignable to us, this should be guaranteed OurSize := 0; for j := Low(cntElements) to Pred(i) do Inc(OurSize, cntElements[j].DataSize); if GetDataSize > OurSize then with TwbDataContainer(Self) do begin UpdateStorageFromElements; Assert(Length(dcDataStorage) >= OurSize); Assert(not (dcfStorageInvalid in dcFlags)); Reset; SetLength(dcDataStorage, OurSize); if OurSize > 0 then begin dcDataBasePtr := @dcDataStorage[Low(dcDataStorage)]; dcDataEndPtr := Pointer( Cardinal(dcDataBasePtr) + OurSize ); end else begin dcDataBasePtr := @EmptyPtr; dcDataEndPtr := @EmptyPtr; end; Init; end; Exit; end; end; end; end; end; end; end; end; procedure TwbContainer.Bar; begin end; procedure TwbContainer.BeforeDestruction; begin Assert(cntElementRefs = 0); inherited BeforeDestruction; {$IFDEF WIN64} LockedInc(cntElementRefs); {$ENDIF WIN64} {$IFDEF WIN32} asm mov eax, [Self] lock inc dword ptr [eax + cntElementRefs] end; {$ENDIF WIN32} end; procedure TwbContainer.BuildRef; var i: Integer; SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; DoInit; Include(cntStates, csRefsBuild); for i := Low(cntElements) to High(cntElements) do if cntElements[i].CanContainFormIDs then cntElements[i].BuildRef; end; function TwbContainer.CanAssignInternal(aIndex: Integer; const aElement: IwbElement; aCheckDontShow: Boolean): Boolean; var Container : IwbContainer; i : Integer; SelfRef : IwbContainerElementRef; ValueDef : IwbValueDef; begin Result := False; if not wbEditAllowed then Exit; if not Assigned(aElement) then Exit; if Assigned(eContainer) then if not IwbContainer(eContainer).IsElementEditable(Self) then Exit; SelfRef := Self as IwbContainerElementRef; Result := inherited CanAssignInternal(aIndex, aElement, aCheckDontShow); DoInit; if not Result and (aIndex = Low(Integer)) and (Length(cntElements) > 0) then begin if Supports(aElement, IwbContainer, Container) and (Container.ElementCount = GetElementCount) then begin ValueDef := GetValueDef; Result := (ValueDef = aElement.ValueDef) or ( Assigned(ValueDef) and ( ValueDef.Equals(aElement.ValueDef) or ValueDef.CanAssign(Self, aIndex, aElement.ValueDef) ) ); end; if Result then for i := Low(cntElements) to High(cntElements) do begin Result := (cntElements[i].ConflictPriority = cpIgnore) or (Container.Elements[i].ConflictPriority = cpIgnore) or cntElements[i].CanAssign(Low(Integer), Container.Elements[i], aCheckDontShow); if not Result then Exit; end; end; end; function TwbContainer.CanChangeElementMember(const aElement: IwbElement): Boolean; var SubRecordArrayDef : IwbSubRecordArrayDef; begin Result := Supports(GetDef, IwbSubRecordArrayDef, SubRecordArrayDef) and Supports(SubRecordArrayDef.Element, IwbSubRecordUnionDef) and IsElementEditable(Self); end; function TwbContainer.CanMoveElement: Boolean; begin Result := False; end; function TwbContainer.CanMoveElementDown(const aElement: IwbElement): Boolean; var i: Integer; begin Result := False; if Assigned(eContainer) and not IwbContainer(eContainer).IsElementEditable(Self) then Exit; if not CanMoveElement then Exit; if Length(cntElements) < 2 then Exit; if cntElements[High(cntElements)].Equals(aElement) then Exit; Result := True; for i := 0 to Pred(High(cntElements)) do if cntElements[i].Equals(aElement) then Exit; Result := False; end; function TwbContainer.CanMoveElementUp(const aElement: IwbElement): Boolean; var i: Integer; begin Result := False; if Assigned(eContainer) and not IwbContainer(eContainer).IsElementEditable(Self) then Exit; if not CanMoveElement then Exit; if Length(cntElements) < 2 then Exit; if cntElements[0].Equals(aElement) then Exit; Result := True; for i := 1 to High(cntElements) do if cntElements[i].Equals(aElement) then Exit; Result := False; end; function TwbContainer.CanElementReset: Boolean; begin if Assigned(eContainer) then Result := IwbContainer(eContainer).CanElementReset else Result := True; end; function TwbContainer.CompareExchangeFormID(aOldFormID, aNewFormID: Cardinal): Boolean; var i: Integer; SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; DoInit; Result := False; for i := Low(cntElements) to High(cntElements) do if cntElements[i].CanContainFormIDs then Result := cntElements[i].CompareExchangeFormID(aOldFormID, aNewFormID) or Result; end; procedure TwbContainer.CreatedEmpty; begin Include(cntStates, csAsCreatedEmpty); end; procedure TwbContainer.Init; begin { can be overriden } end; destructor TwbContainer.Destroy; begin ReleaseElements; inherited; end; procedure TwbContainer.DoInit; var i : Integer; ValueDef : IwbValueDef; KAC : PwbKeepAliveContext; begin if esDestroying in eStates then Exit; if csInit in cntStates then Exit; if [csInitializing, csReseting] * cntStates <> [] then Exit; Include(cntStates, csInitializing); try cntElementsMap := nil; Include(cntStates, csInit); Include(cntStates, csInitOnce); Init; Include(cntStates, csInitDone); for i := Low(cntElements) to High(cntElements) do cntElements[i].MemoryOrder := i; ValueDef := GetValueDef; if Assigned(ValueDef) then cntElementsMap := ValueDef.GetElementMap; if not wbSpeedOverMemory then if not (GetElementType in [etMainRecord, etGroupRecord]) then if not Assigned(cntKeepAliveNext) and (Length(cntElements) > 0) then begin KAC := wbKeepAliveContext; if Assigned(KAC) then begin cntKeepAliveNext := KAC.kacHead; KAC.kacHead := Self as IwbContainerElementRef; end; end; finally Exclude(cntStates, csInitializing); end; end; procedure TwbContainer.DoReset(aForce: Boolean); begin if not aForce then begin if Length(cntElements) = 0 then Exit; if not (csInit in cntStates) then Exit; if esModified in eStates then Exit; if cntElementRefs > 0 then Exit; if not CanElementReset then Exit; end; if [csInitializing, csReseting] * cntStates <> [] then Exit; {$IFDEF WIN64} LockedInc(cntElementRefs); {$ENDIF WIN64} {$IFDEF WIN32} asm mov eax, [Self] lock inc dword ptr [eax + cntElementRefs] end; {$ENDIF WIN32} try Include(cntStates, csReseting); Exclude(cntStates, csInitDone); Reset; cntElementsMap := nil; finally Exclude(cntStates, csReseting); {$IFDEF WIN64} LockedDec(cntElementRefs); {$ENDIF WIN64} {$IFDEF WIN32} asm mov eax, [Self] lock dec dword ptr [eax + cntElementRefs] end; {$ENDIF WIN32} Exclude(cntStates, csInit); end; end; {$D-} function TwbContainer.ElementAddRef: Integer; begin {$IFDEF WIN64} LockedInc(cntElementRefs); {$ENDIF WIN64} {$IFDEF WIN32} asm mov eax, [Self] lock inc dword ptr [eax + cntElementRefs] end; {$ENDIF WIN32} Result := inherited _AddRef; end; {$D+} procedure TwbContainer.ElementChanged(const aElement: IwbElement; aContainer: Pointer); begin NotifyChanged(aContainer); end; {$D-} function TwbContainer.ElementRelease: Integer; label Skip; begin {$IFDEF WIN64} if LockedDec(cntElementRefs) = 0 then {$ENDIF WIN64} {$IFDEF WIN32} asm mov eax, -1 mov ecx, [Self] lock xadd dword ptr [ecx + cntElementRefs], eax cmp eax, 1 jne Skip end; {$ENDIF WIN32} DoReset(False); Skip: Result := inherited _Release; end; {$D+} function TwbContainer.FindBySortKey(const aSortKey: string; aExtended: Boolean; out aIndex: Integer): Boolean; var L, H, I, C: Integer; begin Result := False; L := Low(cntElements); H := High(cntElements); while L <= H do begin I := (L + H) shr 1; C := CompareStr(cntElements[I].SortKey[aExtended], aSortKey); if C < 0 then L := I + 1 else begin H := I - 1; if C = 0 then begin Result := True; L := I; end; end; end; aIndex := L; end; procedure TwbContainer.FindUsedMasters(aMasters: PwbUsedMasters); var i : Integer; SelfRef : IwbContainerElementRef; begin inherited; SelfRef := Self as IwbContainerElementRef; DoInit; for i := Low(cntElements) to High(cntElements) do if cntElements[i].CanContainFormIDs then cntElements[i].FindUsedMasters(aMasters); end; procedure TwbContainer.FreeInstance; begin Assert(cntElementRefs = 1); inherited; end; function TwbContainer.GetAdditionalElementCount: Integer; begin Result := 0; end; function TwbContainer.GetAddList: TDynStrings; begin Result := nil; end; function TwbContainer.GetContainerStates: TwbContainerStates; begin Result := cntStates; end; function TwbContainer.GetDataSize: Integer; var i : Integer; SelfRef : IwbContainerElementRef; DataContainer : IwbDataContainer; begin SelfRef := Self as IwbContainerElementRef; Result := 0; DoInit; for i := Low(cntElements) to High(cntElements) do begin if Supports(cntElements[i], IwbDataContainer, DataContainer) and DataContainer.DontSave then Continue; Inc(Result, cntElements[i].DataSize); end; end; function TwbContainer.GetElement(aIndex: Integer): IwbElement; var SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; DoInit; if not Assigned(cntElements) or (aIndex>=Length(cntElements)) then begin // Using the wrong contained array at the time if wbMoreInfoForIndex and (DebugHook <> 0) and Assigned(wbProgressCallback) then wbProgressCallback('Debugger: ['+ IwbElement(Self).Path +'] Index ' + IntToStr(aIndex) + ' greater than max '+ IntToStr(Length(cntElements)-1)); Result := nil end else begin if Length(cntElementsMap) = Length(cntElements) then aIndex := cntElementsMap[aIndex]; Result := IInterface(cntElements[aIndex]) as IwbElement; end; end; function TwbContainer.GetElementByName(const aName: string): IwbElement; var i: integer; SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; DoInit; Result := nil; for i := Low(cntElements) to High(cntElements) do if SameText(cntElements[i].Name, aName) then begin Result := IInterface(cntElements[i]) as IwbElement; Exit; end; for i := Low(cntElements) to High(cntElements) do if SameText(cntElements[i].DisplayName, aName) then begin Result := IInterface(cntElements[i]) as IwbElement; Exit; end; end; function TwbContainer.GetElementByPath(const aPath: string): IwbElement; var SelfRef : IwbContainerElementRef; Element : IwbElement; Path : string; Container : IwbContainerElementRef; begin Result := nil; SelfRef := Self as IwbContainerElementRef; DoInit; Element := ResolveElementName(aPath, Path); if not Assigned(Element) then Exit; if Path = '' then Result := Element else if Supports(Element, IwbContainerElementRef, Container) then Result := Container.ElementByPath[Path]; end; function TwbContainer.GetElementByMemoryOrder(aSortOrder: Integer): IwbElement; var i: integer; SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; DoInit; Dec(aSortOrder, GetAdditionalElementCount); Result := nil; for i := Low(cntElements) to High(cntElements) do if cntElements[i].MemoryOrder = aSortOrder then begin Result := IInterface(cntElements[i]) as IwbElement; Exit; end; end; function TwbContainer.GetElementBySignature(const aSignature: TwbSignature): IwbElement; var i: integer; HasSignature: IwbHasSignature; SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; DoInit; Result := nil; for i := Low(cntElements) to High(cntElements) do if Supports(cntElements[i], IwbHasSignature, HasSignature) then if HasSignature.Signature = aSignature then begin Result := HasSignature; Exit; end; end; function TwbContainer.GetElementBySortOrder(aSortOrder: Integer): IwbElement; var i: integer; SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; DoInit; Dec(aSortOrder, GetAdditionalElementCount); Result := nil; for i := Low(cntElements) to High(cntElements) do if cntElements[i].SortOrder = aSortOrder then begin Result := IInterface(cntElements[i]) as IwbElement; Exit; end; end; function TwbContainer.GetElementCount: Integer; var SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; DoInit; Result := Length(cntElements); end; function TwbContainer.GetElementEditValue(const aName: string): string; var SelfRef : IwbContainerElementRef; Element : IwbElement; Name : string; Container : IwbContainerElementRef; begin Result := ''; SelfRef := Self as IwbContainerElementRef; DoInit; Element := ResolveElementName(aName, Name); if not Assigned(Element) then Exit; if Name = '' then Result := Element.EditValue else if Supports(Element, IwbContainerElementRef, Container) then Result := Container.ElementEditValues[Name]; end; function TwbContainer.GetElementExists(const aName: string): Boolean; var SelfRef : IwbContainerElementRef; Element : IwbElement; Name : string; Container : IwbContainerElementRef; begin Result := False; SelfRef := Self as IwbContainerElementRef; DoInit; Element := ResolveElementName(aName, Name); if not Assigned(Element) then Exit; if Name = '' then Result := True else if Supports(Element, IwbContainerElementRef, Container) then Result := Container.ElementExists[Name]; end; function TwbContainer.GetElementLinksTo(const aName: string): IwbElement; var SelfRef : IwbContainerElementRef; Element : IwbElement; Name : string; Container : IwbContainerElementRef; begin Result := nil; SelfRef := Self as IwbContainerElementRef; DoInit; Element := ResolveElementName(aName, Name); if not Assigned(Element) then Exit; if Name = '' then Result := Element.LinksTo else if Supports(Element, IwbContainerElementRef, Container) then Result := Container.ElementLinksTo[Name]; end; function TwbContainer.GetElementNativeValue(const aName: string): Variant; var SelfRef : IwbContainerElementRef; Element : IwbElement; Name : string; Container : IwbContainerElementRef; begin VarClear(Result); SelfRef := Self as IwbContainerElementRef; DoInit; Element := ResolveElementName(aName, Name); if not Assigned(Element) then Exit; if Name = '' then Result := Element.NativeValue else if Supports(Element, IwbContainerElementRef, Container) then Result := Container.ElementNativeValues[Name]; end; function TwbContainer.GetElementSortKey(const aName: string; aExtended: Boolean): string; var SelfRef : IwbContainerElementRef; Element : IwbElement; Name : string; Container : IwbContainerElementRef; begin Result := ''; SelfRef := Self as IwbContainerElementRef; DoInit; Element := ResolveElementName(aName, Name); if not Assigned(Element) then Exit; if Name = '' then Result := Element.SortKey[aExtended] else if Supports(Element, IwbContainerElementRef, Container) then Result := Container.ElementSortKeys[Name, aExtended]; end; function TwbContainer.GetElementValue(const aName: string): string; var SelfRef : IwbContainerElementRef; Element : IwbElement; Name : string; Container : IwbContainerElementRef; begin Result := ''; SelfRef := Self as IwbContainerElementRef; DoInit; Element := ResolveElementName(aName, Name); if not Assigned(Element) then Exit; if Name = '' then Result := Element.Value else if Supports(Element, IwbContainerElementRef, Container) then Result := Container.ElementValues[Name]; end; function TwbContainer.GetIsInSK(aIndex: Integer): Boolean; begin Result := False; end; function TwbContainer.GetRecordBySignature(const aSignature: TwbSignature): IwbRecord; var i: integer; lRecord: IwbRecord; SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; DoInit; Result := nil; for i := Low(cntElements) to High(cntElements) do if Supports(cntElements[i], IwbRecord, lRecord) then if lRecord.Signature = aSignature then begin Result := lRecord; Exit; end; end; function TwbContainer.GetCountedRecordCount: Cardinal; var i: Integer; SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; Result := 0; DoInit; for i := Low(cntElements) to High(cntElements) do Inc(Result, cntElements[i].GetCountedRecordCount); end; function TwbContainer.GetSortKeyInternal(aExtended: Boolean): string; var i: Integer; SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; DoInit; Result := ''; for i := Low(cntElements) to High(cntElements) do begin Result := Result + cntElements[i].SortKey[aExtended]; if i < High(cntElements) then Result := Result + '|'; end; end; function TwbContainer.HasErrors: Boolean; var SelfRef : IwbContainerElementRef; i : Integer; begin SelfRef := Self as IwbContainerElementRef; DoInit; Result := inherited HasErrors; if Result then Exit; for i := Low(cntElements) to High(cntElements) do begin Result := cntElements[i].HasErrors; if Result then Exit; end; end; function TwbContainer.LastElement: IwbElement; var SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; DoInit; if Length(cntElements) > 0 then Result := IInterface(cntElements[High(cntElements)]) as IwbElement else Result := nil; end; procedure TwbContainer.MarkModifiedRecursive; var i: Integer; SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; DoInit; for i := Low(cntElements) to High(cntElements) do cntElements[i].MarkModifiedRecursive; inherited; end; procedure TwbContainer.MasterCountUpdated(aOld, aNew: Byte); var i: Integer; SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; DoInit; for i := Low(cntElements) to High(cntElements) do if cntElements[i].CanContainFormIDs then cntElements[i].MasterCountUpdated(aOld, aNew); end; procedure TwbContainer.MasterIndicesUpdated(const aOld, aNew: TBytes); var i : Integer; SelfRef : IwbContainerElementRef; begin inherited; SelfRef := Self as IwbContainerElementRef; DoInit; for i := Low(cntElements) to High(cntElements) do if cntElements[i].CanContainFormIDs then cntElements[i].MasterIndicesUpdated(aOld, aNew); end; procedure TwbContainer.MergeStorageInternal(var aBasePtr: Pointer; aEndPtr: Pointer); var i: Integer; j: Integer; k: Integer; l: Integer; m: Integer; n: Integer; SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; DoInit; If GetElementType in SortedElementTypes then begin m := Low(Integer); for l := Low(cntElements) to High(cntElements) do if (cntElements[l].MemoryOrder > m) and not Supports(cntElements[l], IwbStringListTerminator) then m := cntElements[l].MemoryOrder; for l := Low(cntElements) to High(cntElements) do if cntElements[l].MemoryOrder = Low(Integer) then begin cntElements[l].MemoryOrder := m + 1; Inc(m); end; for l := Low(cntElements) to High(cntElements) do if Supports(cntElements[l], IwbStringListTerminator) then cntElements[l].MemoryOrder := m+1; m := Low(Integer); k := Low(Integer); for i := Low(cntElements) to High(cntElements) do begin n := k; j := High(Integer); for l := Low(cntElements) to High(cntElements) do begin if (m= Low(cntElements)); if k = n then Assert(k <> n); m := cntElements[k].MemoryOrder; cntElements[k].MergeStorage(aBasePtr, aEndPtr); end; end else for l := Low(cntElements) to High(cntElements) do cntElements[l].MergeStorage(aBasePtr, aEndPtr); end; procedure TwbContainer.MoveElementDown(const aElement: IwbElement); var i: Integer; begin if Assigned(eContainer) and not IwbContainer(eContainer).IsElementEditable(Self) then Exit; if not CanMoveElement then Exit; if Length(cntElements) < 2 then Exit; if cntElements[High(cntElements)].Equals(aElement) then Exit; for i := 0 to Pred(High(cntElements)) do if cntElements[i].Equals(aElement) then begin SetModified(True); InvalidateStorage; cntElements[i] := cntElements[Succ(i)]; cntElements[Succ(i)] := aElement as IwbElementInternal; Exit; end; end; procedure TwbContainer.MoveElementUp(const aElement: IwbElement); var i: Integer; begin if Assigned(eContainer) and not IwbContainer(eContainer).IsElementEditable(Self) then Exit; if not CanMoveElement then Exit; if Length(cntElements) < 2 then Exit; if cntElements[0].Equals(aElement) then Exit; for i := 1 to High(cntElements) do if cntElements[i].Equals(aElement) then begin SetModified(True); InvalidateStorage; cntElements[i] := cntElements[Pred(i)]; cntElements[Pred(i)] := aElement as IwbElementInternal; Exit; end; end; class function TwbContainer.NewInstance: TObject; begin Result := inherited NewInstance; TwbContainer(Result).cntElementRefs := 1; end; procedure TwbContainer.NextElementMember(const aElement: IwbElement); var ElementIndex : Integer; ElementDef : IwbRecordMemberDef; Element : IwbElement; Container : IwbContainer; SubRecordArrayDef : IwbSubRecordArrayDef; SubRecordUnionDef : IwbSubRecordUnionDef; RecordDef : IwbRecordDef; i : Integer; begin if Assigned(eContainer) and not IwbContainer(eContainer).IsElementEditable(Self) then Exit; if not CanChangeElementMember(aElement) then Exit; if not Supports(GetDef, IwbSubRecordArrayDef, SubRecordArrayDef) or not Supports(SubRecordArrayDef.Element, IwbSubRecordUnionDef, SubRecordUnionDef) then Exit; if not Supports(SubRecordArrayDef.Element, IwbRecordDef, RecordDef) then Exit; if Supports(aElement.Container, IwbContainer, Container) then begin for i := 0 to Pred(RecordDef.MemberCount) do if RecordDef.Members[i].Equals(aElement.Def) then break; if i < RecordDef.MemberCount then begin RemoveElement(aElement); ElementIndex := (i + 1) mod RecordDef.MemberCount; ElementDef := RecordDef.Members[ElementIndex]; case ElementDef.DefType of dtSubRecord: Element := TwbSubRecord.Create(Self, ElementDef as IwbSubRecordDef); dtSubRecordArray: Element := TwbSubRecordArray.Create(Self, nil, Low(Integer), ElementDef as IwbSubRecordArrayDef); dtSubRecordStruct: Element := TwbSubRecordStruct.Create(Self, nil, Low(Integer), ElementDef as IwbSubRecordStructDef); else Assert(False); end; if Assigned(Element) and Assigned(aElement) then try Element.Assign(Low(Integer), nil, False); if csAsCreatedEmpty in cntStates then Exclude(cntStates, csAsCreatedEmpty); except Element.Container.RemoveElement(Element); raise; end; end; end; end; procedure TwbContainer.NotifyChangedInternal(aContainer: Pointer); begin if [csInitializing, csReseting] * cntStates <> [] then Exit; if csAsCreatedEmpty in cntStates then Exclude(cntStates, csAsCreatedEmpty); inherited; if esModified in eStates then DoAfterSet(varEmpty, varEmpty); end; procedure TwbContainer.PrepareSave; var i: Integer; SelfRef : IwbContainerElementRef; begin if wbDelayLoadRecords then if not (esModified in eStates) then Exit; SelfRef := Self as IwbContainerElementRef; DoInit; for i := High(cntElements) downto Low(cntElements) do cntElements[i].PrepareSave; end; procedure TwbContainer.PreviousElementMember(const aElement: IwbElement); var ElementIndex : Integer; ElementDef : IwbRecordMemberDef; Element : IwbElement; Container : IwbContainer; SubRecordArrayDef : IwbSubRecordArrayDef; SubRecordUnionDef : IwbSubRecordUnionDef; RecordDef : IwbRecordDef; i : Integer; begin if Assigned(eContainer) and not IwbContainer(eContainer).IsElementEditable(Self) then Exit; if not CanChangeElementMember(aElement) then Exit; if not Supports(GetDef, IwbSubRecordArrayDef, SubRecordArrayDef) or not Supports(SubRecordArrayDef.Element, IwbSubRecordUnionDef, SubRecordUnionDef) then Exit; if not Supports(SubRecordArrayDef.Element, IwbRecordDef, RecordDef) then Exit; if Supports(aElement.Container, IwbContainer, Container) then begin for i := 0 to Pred(RecordDef.MemberCount) do if RecordDef.Members[i].Equals(aElement.Def) then break; if i < RecordDef.MemberCount then begin RemoveElement(aElement); ElementIndex := (i - 1) mod RecordDef.MemberCount; ElementDef := RecordDef.Members[ElementIndex]; case ElementDef.DefType of dtSubRecord: Element := TwbSubRecord.Create(Self, ElementDef as IwbSubRecordDef); dtSubRecordArray: Element := TwbSubRecordArray.Create(Self, nil, Low(Integer), ElementDef as IwbSubRecordArrayDef); dtSubRecordStruct: Element := TwbSubRecordStruct.Create(Self, nil, Low(Integer), ElementDef as IwbSubRecordStructDef); else Assert(False); end; if Assigned(Element) and Assigned(aElement) then try Element.Assign(Low(Integer), nil, False); if csAsCreatedEmpty in cntStates then Exclude(cntStates, csAsCreatedEmpty); except Element.Container.RemoveElement(Element); raise; end; end; end; end; function TwbContainer.Reached: Boolean; var i : Integer; SelfRef : IwbContainerElementRef; begin Result := False; if GetDontShow then Exit; SelfRef := Self as IwbContainerElementRef; DoInit; Result := inherited Reached; if not Result then Exit; for i := Low(cntElements) to High(cntElements) do if cntElements[i].CanContainFormIDs then cntElements[i].Reached; end; function TwbContainer.ReleaseElements: TDynElementInternals; var i: Integer; SelfRef : IwbContainerElementRef; begin if not (esDestroying in eStates) then SelfRef := Self as IwbContainerElementRef; Result := cntElements; cntElements := nil; for i := Low(Result) to High(Result) do Result[i].SetContainer(nil); Exclude(cntStates, csAsCreatedEmpty); end; function TwbContainer.ReleaseKeepAlive: IwbContainerElementRef; begin Result := cntKeepAliveNext; cntKeepAliveNext := nil; end; function TwbContainer.RemoveElement(const aElement: IwbElement; aMarkModified: Boolean = False): IwbElement; var i: Integer; SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; Result := aElement; if not Assigned(aElement) then Exit; if Length(cntElements) > 0 then begin if cntElements[High(cntElements)].Equals(aElement) then begin Result := RemoveElement(High(cntElements), aMarkModified); Exit; end; for i := Low(cntElements) to Pred(High(cntElements)) do if cntElements[i].Equals(aElement) then begin Result := RemoveElement(i, aMarkModified); Exit; end; end; Result := nil; Exit; end; function TwbContainer.RemoveElement(const aName: string): IwbElement; var SelfRef : IwbContainerElementRef; Name : string; Container : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; DoInit; Result := ResolveElementName(aName, Name); if not Assigned(Result) then Exit; if Name = '' then Result.Remove else if Supports(Result, IwbContainerElementRef, Container) then Result := Container.RemoveElement(Name) else Result := nil; end; function TwbContainer.RemoveInjected(aCanRemove: Boolean): Boolean; var i : Integer; SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; DoInit; Result := GetReferencesInjected; if not Result then for i := High(cntElements) downto Low(cntElements) do if cntElements[i].CanContainFormIDs then begin Result := cntElements[i].RemoveInjected(True) or Result; if Result and aCanRemove then Break; end; if Result and aCanRemove and GetIsRemoveable then begin Result := False; Remove; end; end; procedure TwbContainer.ReportRequiredMasters(aStrings: TStrings; aAsNew: Boolean; Recursive: Boolean = True; Initial: Boolean = false); var i: Integer; SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; DoInit; inherited; if Recursive or (Initial and not Supports(Self, IwbGroupRecord)) then for i := Low(cntElements) to High(cntElements) do if cntElements[i].CanContainFormIDs then cntElements[i].ReportRequiredMasters(aStrings, aAsNew, Recursive); end; function TwbContainer.RemoveElement(aPos: Integer; aMarkModified: Boolean = False): IwbElement; var SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; Result := nil; if aPos < Low(cntElements) then Exit else if aPos > High(cntElements) then Exit; if aMarkModified then begin SetModified(True); InvalidateStorage; end; Result := IInterface(cntElements[aPos]) as IwbElement; cntElements[aPos].SetContainer(nil); cntElements[aPos] := nil; if aPos < High(cntElements) then begin Move(cntElements[Succ(aPos)], cntElements[aPos], (High(cntElements) - aPos) * SizeOf(Pointer)); Pointer(cntElements[High(cntElements)]) := nil; end; SetLength(cntElements, Pred(Length(cntElements))); NotifyChanged(eContainer); end; procedure TwbContainer.Reset; begin { can be overriden } end; procedure TwbContainer.ResetConflict; var i : Integer; SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; // DoInit; elements that don't exist yet don't have anything to reset... inherited; for i := Low(cntElements) to High(cntElements) do cntElements[i].ResetConflict; end; procedure TwbContainer.ResetReachable; var i : Integer; SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; // DoInit; elements that don't exist yet don't have anything to reset... inherited; for i := Low(cntElements) to High(cntElements) do cntElements[i].ResetReachable; end; procedure TwbContainer.ResetTags; var i: Integer; begin inherited; for i := Low(cntElements) to High(cntElements) do cntElements[i].ResetTags; end; function TwbContainer.ResolveElementName(aName: string; out aRemainingName: string; aCanCreate: Boolean = False): IwbElement; var i : Integer; begin aRemainingName := ''; i := Pos('\', aName); if i > 0 then begin aRemainingName := Copy(aName, Succ(i), High(Integer)); Delete(aName, i, High(Integer)); end; if aName = '..' then Result := GetContainer else if (Length(aName) > 0) and (aName[1] = '[') and (aName[Length(aName)] = ']') then begin i := StrToIntDef(Copy(aName, 2, Length(aName) - 2), 0); Result := GetElement(i); end else Result := GetElementByName(aName); if not Assigned(Result) and (Length(aName) = 4) then Result := GetElementBySignature(StrToSignature(aName)); end; procedure TwbContainer.ReverseElements; var Temp: TDynElementInternals; i: Integer; SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; SetLength(Temp, Length(cntElements)); for i := Low(cntElements) to High(cntElements) do Temp[High(cntElements)-i] := cntElements[i]; cntElements := Temp; end; procedure TwbContainer.SetElementEditValue(const aName, aValue: string); var SelfRef : IwbContainerElementRef; Element : IwbElement; Name : string; Container : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; DoInit; Element := ResolveElementName(aName, Name, True); if not Assigned(Element) then Exit; if Name = '' then Element.EditValue := aValue else if Supports(Element, IwbContainerElementRef, Container) then Container.ElementEditValues[Name] := aValue; end; procedure TwbContainer.SetElementNativeValue(const aName: string; const aValue: Variant); var SelfRef : IwbContainerElementRef; Element : IwbElement; Name : string; Container : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; DoInit; Element := ResolveElementName(aName, Name, True); if not Assigned(Element) then Exit; if Name = '' then Element.NativeValue := aValue else if Supports(Element, IwbContainerElementRef, Container) then Container.ElementNativeValues[Name] := aValue; end; procedure TwbContainer.SetToDefaultInternal; var i : Integer; SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; DoInit; inherited; for i := Low(cntElements) to High(cntElements) do cntElements[i].SetToDefault; end; procedure TwbContainer.SortBySortOrder; var i, j: Integer; begin SetModified(True); i := GetAdditionalElementCount; j := Length(cntElements) - i; if j > 1 then begin wbMergeSort(@cntElements[i], j, CompareSortOrder); InvalidateStorage; end; end; procedure TwbContainer.WriteToStreamInternal(aStream: TStream; aResetModified: Boolean); var i: Integer; SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; DoInit; inherited; for i := Low(cntElements) to High(cntElements) do cntElements[i].WriteToStream(aStream, aResetModified); Exclude(eStates, esUnsaved); if aResetModified then begin Exclude(eStates, esModified); Exclude(eStates, esInternalModified); end; end; {$D-} function TwbContainer._AddRef: Integer; begin if wbSpeedOverMemory then Result := ElementAddRef else Result := inherited _AddRef; end; function TwbContainer._Release: Integer; begin if wbSpeedOverMemory then Result := ElementRelease else begin Result := inherited _Release; if (Result > 0) and (cntElementRefs = 0) and (csInit in cntStates) then DoReset(False); end; end; {$D+} //------------------------------------------------------------------------------ // TwbRecord //------------------------------------------------------------------------------ constructor TwbRecord.Create(const aContainer : IwbContainer; var aBasePtr : Pointer; aEndPtr : Pointer; const aPrevMainRecord : IwbMainRecord); var Dummy: Integer; begin inherited Create(aContainer, aBasePtr, aEndPtr, aPrevMainRecord); recSkipped := recSkipped or RecordToSkip.Find(GetSignature, Dummy); InformPrevMainRecord(aPrevMainRecord); ScanData; end; class function TwbRecord.CreateForPtr(var aPtr : Pointer; aEndPtr : Pointer; const aContainer : IwbContainer; const aPrevMainRecord : IwbMainRecord) : IwbRecord; begin if aContainer.ElementType = etMainRecord then Result := TwbSubRecord.Create(aContainer, aPtr, aEndPtr, aPrevMainRecord) else if PwbSignature(aPtr)^ = 'GRUP' then Result := TwbGroupRecord.Create(aContainer, aPtr, aEndPtr, aPrevMainRecord) else Result := TwbMainRecord.Create(aContainer, aPtr, aEndPtr, aPrevMainRecord); end; function TwbRecord.GetName: string; var Sig : TwbSignature; i : Integer; begin Sig := GetSignature; for i := Low(Sig) to High(Sig) do if Ord(Sig[i]) < 32 then Sig[i] := AnsiChar( Ord('a') + Ord(Sig[i]) ); Result := Sig; end; function TwbRecord.GetSkipped: Boolean; begin Result := recSkipped; end; procedure TwbRecord.InformPrevMainRecord(const aPrevMainRecord: IwbMainRecord); begin {can be overriden} end; procedure TwbRecord.SortBySortOrder; begin SetModified(True); if Length(cntElements) > 1 then begin wbMergeSort(@cntElements[1], High(cntElements), CompareSortOrder); InvalidateStorage; end; end; function TwbRecord.GetSignature: TwbSignature; begin if Assigned(dcBasePtr) then Result := PwbSignature(dcBasePtr)^ else Result := NONE; end; { TwbMainRecord } function TwbMainRecord.Add(const aName: string; aSilent: Boolean): IwbElement; var s : string; SelfRef : IwbContainerElementRef; i : Integer; Group : IwbGroupRecord; begin Result := nil; if not wbIsInternalEdit then if not wbEditAllowed or not GetIsEditable then raise Exception.Create(GetName + ' can not be edited'); if GetIsDeleted then Exit; s := Copy(aName, 1, 4); if (GetSignature = 'CELL') and ( SameText(s, 'NAVM') or SameText(s, 'PGRD') or SameText(s, 'LAND') or SameText(s, 'REFR') or SameText(s, 'PGRE') or SameText(s, 'PMIS') or SameText(s, 'ACRE') or SameText(s, 'ACHR') or SameText(s, 'PARW') or {>>> Skyrim <<<} SameText(s, 'PBEA') or {>>> Skyrim <<<} SameText(s, 'PFLA') or {>>> Skyrim <<<} SameText(s, 'PCON') or {>>> Skyrim <<<} SameText(s, 'PBAR') or {>>> Skyrim <<<} SameText(s, 'PHZD') {>>> Skyrim <<<} ) then begin Group := GetChildGroup; if not Assigned(Group) then begin Group := TwbGroupRecord.Create(GetContainer, 6, Self); mrGroup := Group; end; SelfRef := Group as IwbContainerElementRef; Group := nil; for i := 0 to Pred(SelfRef.ElementCount) do if Supports(SelfRef.Elements[i], IwbGroupRecord, Group) then if (Group.GroupType = 9) and (Group.GroupLabel = Self.GetFormID) then Break else Group := nil; if not Assigned(Group) then Group := TwbGroupRecord.Create(SelfRef as IwbContainer, 9, Self); Result := Group.Add(aName, aSilent); Exit; end else if (GetSignature = 'DIAL') and ( SameText(s, 'INFO') ) then begin Group := GetChildGroup; if not Assigned(Group) then begin Group := TwbGroupRecord.Create(GetContainer, 7, Self); mrGroup := Group; end; Result := Group.Add(aName, aSilent); Exit; end else if (GetSignature = 'WRLD') and ( SameText(s, 'ROAD') or SameText(s, 'CELL') ) then begin Group := GetChildGroup; if not Assigned(Group) then begin Group := TwbGroupRecord.Create(GetContainer, 1, Self); mrGroup := Group; end; Result := Group.Add(aName, aSilent); Exit; end else if wbVWDAsQuestChildren and (GetSignature = 'QUST') and ( SameText(s, 'DLBR') or SameText(s, 'DIAL') or SameText(s, 'SCEN') ) then begin Group := GetChildGroup; if not Assigned(Group) then begin Group := TwbGroupRecord.Create(GetContainer, 10, Self); mrGroup := Group; end; Result := Group.Add(aName, aSilent); Exit; end; if Assigned(mrDef) then begin SelfRef := Self as IwbContainerElementRef; DoInit; for i := 0 to Pred(mrDef.MemberCount) do if SameText(mrDef.Members[i].Name, aName) or SameText(mrDef.Members[i].DefaultSignature, aName) then begin Result := GetElementBySortOrder(i + GetAdditionalElementCount); if not Assigned(Result) then begin Assign(i, nil, False); Result := GetElementBySortOrder(i + GetAdditionalElementCount); Assert(Assigned(Result)); if wbSortSubRecords and (Length(cntElements) > 1) then wbMergeSort(@cntElements[0], Length(cntElements), CompareSubRecords); end; Exit; end; end; end; function TwbMainRecord.AddIfMissingInternal(const aElement: IwbElement; aAsNew, aDeepCopy: Boolean; const aPrefixRemove, aPrefix, aSuffix: string): IwbElement; var SelfRef : IwbContainerElementRef; begin if not wbEditAllowed then raise Exception.Create(GetName + ' can not be assigned.'); if GetIsDeleted then Exit; if Assigned(mrDef) then begin SelfRef := Self as IwbContainerElementRef; DoInit; Assert(Assigned(aElement.Def)); if aElement.SortOrder < 0 then begin Result := GetElementBySortOrder(aElement.SortOrder + GetAdditionalElementCount); Assert(Assigned(Result)); Assert(Assigned(Result.Def)); Assert(aElement.Def.Equals(Result.Def)); end else begin Assert(aElement.SortOrder >= 0); Assert(aElement.SortOrder < mrDef.MemberCount); if not aElement.Def.Equals(mrDef.Members[aElement.SortOrder]) then Assert(Self.CanAssign(aElement.SortOrder, aElement, True)); Result := GetElementBySortOrder(aElement.SortOrder + GetAdditionalElementCount); end; if not Assigned(Result) then begin Assign(aElement.SortOrder, aElement, not aDeepCopy); Result := GetElementBySortOrder(aElement.SortOrder + GetAdditionalElementCount); Assert(Assigned(Result)); if wbSortSubRecords and (Length(cntElements) > 1) then wbMergeSort(@cntElements[0], Length(cntElements), CompareSubRecords); end else Result.Assign(Low(Integer), aElement, not aDeepCopy); end; end; procedure TwbMainRecord.AddOverride(const aMainRecord: IwbMainRecord); begin if aMainRecord.Signature <> GetSignature then if Assigned(wbProgressCallback) then wbProgressCallback(Format('Warning: Record %s in file %s is being overridden by record %s in file %s.', [ '['+ GetSignature + ':' + IntToHex64(GetFormID, 8)+ ']', GetFile.FileName, '['+ aMainRecord.Signature + ':' + IntToHex64(aMainRecord.FormID, 8)+ ']', aMainRecord._File.FileName ])); SetLength(mrOverrides, Succ(Length(mrOverrides))); mrOverrides[High(mrOverrides)] := aMainRecord; (aMainRecord as IwbMainRecordInternal).SetMaster(Self); mrOverridesSorted := False; end; procedure TwbMainRecord.AddReferencedBy(aMainRecord : IwbMainRecord); begin SetLength(mrReferencedBy, Succ(Length(mrReferencedBy))); mrReferencedBy[High(mrReferencedBy)] := aMainRecord; Include(mrStates, mrsReferencedByUnsorted); end; procedure TwbMainRecord.AddReferencedFromID(aFormID: Cardinal); begin Assert(mrsBuildingRef in mrStates); if aFormID = 0 then Exit; Inc(mrTmpRefFormIDHigh); if High(mrTmpRefFormIDs) < mrTmpRefFormIDHigh then if mrTmpRefFormIDHigh = 0 then SetLength(mrTmpRefFormIDs, 64) else SetLength(mrTmpRefFormIDs, mrTmpRefFormIDHigh * 2); mrTmpRefFormIDs[mrTmpRefFormIDHigh] := aFormID; end; function TwbMainRecord.AssignInternal(aIndex: Integer; const aElement: IwbElement; aOnlySK: Boolean): IwbElement; var MainRecord : IwbMainRecord; Member : IwbRecordMemberDef; Container : IwbContainerElementRef; Element : IwbElement; i : Integer; SelfRef : IwbContainerElementRef; BasePtr : Pointer; IsAdd : Boolean; IsAddChild : Boolean; GroupRecord : IwbGroupRecord; DataContainer : IwbDataContainer; NeedUpdate : Boolean; begin Result := nil; if not wbEditAllowed then raise Exception.Create(GetName + ' can not be assigned.'); if GetIsDeleted then Exit; if Assigned(mrDef) then begin wbBeginKeepAlive; try SelfRef := Self as IwbContainerElementRef; DoInit; if aIndex = Low(Integer) then begin NeedUpdate := CheckChildOfCell; SetModified(True); InvalidateStorage; ReleaseElements; if Assigned(aElement) then begin Container := aElement as IwbContainerElementRef; if Supports(aElement, IwbMainRecord, MainRecord) then begin MakeHeaderWriteable; with TwbMainRecord(MainRecord.ElementID) do begin Self.mrStruct.mrsFlags := mrStruct.mrsFlags; Self.mrStruct.mrsVCS1 := DefaultVCS1; if wbGameMode in [gmFO3, gmFNV, gmTES5, gmSSE, gmFO4] then begin Self.mrStruct.mrsVersion := mrStruct.mrsVersion; Self.mrStruct.mrsVCS2 := DefaultVCS2; //mrStruct.mrsVCS2; end; end; end; end; if Supports(Self.GetContainer, IwbGroupRecord, GroupRecord) then if wbCreateContainedIn and (GroupRecord.GroupType in [1, 4..10]) then with TwbContainedInElement.Create(Self) do begin _AddRef; _Release; end; GroupRecord := nil; BasePtr := dcBasePtr; with TwbRecordHeaderStruct.Create(Self, BasePtr, Pointer( Cardinal(BasePtr) + wbSizeOfMainRecordStruct), mrDef.RecordHeaderStruct, '') do begin Include(dcFlags, dcfDontSave); SetSortOrder(-1); SetMemoryOrder(Low(Integer)); _AddRef; _Release; end; if Assigned(aElement) then begin for i := 0 to Pred(Container.ElementCount) do begin Element := Container.Elements[i]; Assign(Element.SortOrder, Element, aOnlySK); end; end else begin for i := 0 to Pred(mrDef.MemberCount) do if mrDef.Members[i].Required then Assign(i, nil, False); end; if NeedUpdate then UpdateCellChildGroup; CollapseStorage; end else begin if (aIndex >= 0) and (aIndex < mrDef.MemberCount) then begin Member := mrDef.Members[aIndex]; IsAdd := not Assigned(aElement) or Member.CanAssign(Self, Low(Integer), aElement.Def); IsAddChild := not IsAdd and Assigned(aElement) and Member.CanAssign(Self, High(Integer), aElement.Def); if IsAdd or IsAddChild then begin Element := GetElementBySortOrder(aIndex + GetAdditionalElementCount); if Assigned(Element) then begin if IsAdd and Assigned(aElement) then Element.Assign(Low(Integer), aElement, aOnlySK) else if IsAddChild then Element.Assign(High(Integer), aElement, aOnlySK); end else begin if Member.DefType = dtSubRecordUnion then begin if Assigned(aElement) then begin Supports(aElement, IwbDataContainer, DataContainer); Member := (Member as IwbRecordDef).GetMemberFor((aElement as IwbHasSignature).Signature, DataContainer); end else Member := (Member as IwbRecordDef).Members[0]; Assert(Assigned(Member)); end; case Member.DefType of dtSubRecord: Element := TwbSubRecord.Create(Self, Member as IwbSubRecordDef); dtSubRecordArray: Element := TwbSubRecordArray.Create(Self, nil, Low(Integer), Member as IwbSubRecordArrayDef); dtSubRecordStruct: Element := TwbSubRecordStruct.Create(Self, nil, Low(Integer), Member as IwbSubRecordStructDef); else Assert(False); end; if Assigned(Element) then try Element.SortOrder := aIndex; Element.MemoryOrder := aIndex; if IsAdd and Assigned(aElement) then Element.Assign(Low(Integer), aElement, aOnlySK) else if IsAddChild then Element.Assign(High(Integer), aElement, aOnlySK); except Element.Container.RemoveElement(Element); raise; end; end; Result := Element; end; end else if (aIndex = -2) then begin Element := GetElementBySortOrder(aIndex + GetAdditionalElementCount); if Assigned(Element) then Element.Assign(Low(Integer), aElement, False); Result := Element; end; end; finally wbEndKeepAlive; end; if wbSortSubRecords and (Length(cntElements) > 1) then wbMergeSort(@cntElements[0], Length(cntElements), CompareSubRecords); end else Result := inherited AssignInternal(aIndex, aElement, aOnlySK); end; procedure TwbMainRecord.BuildRef; procedure UseKAC; var KAR: IwbKeepAliveRoot; begin KAR := wbCreateKeepAliveRoot; DoBuildRef(False); end; begin if wbSpeedOverMemory then DoBuildRef(False) else UseKAC; if Assigned(wbProgressCallback) then wbProgressCallback(''); end; procedure TwbMainRecord.DoBuildRef(aRemove: Boolean); var _File : IwbFile; Files : array of IwbFile; FilesCount : Integer; SelfIntf : IwbMainRecord; procedure ProcessRef(aFormID: Cardinal; aAdd: Boolean); var FileID : Integer; MainRecord : IwbMainRecord; begin if not Assigned(_File) then begin _File := GetFile; FilesCount := _File.MasterCount; SetLength(Files, Succ(FilesCount)); Files[FilesCount] := _File; SelfIntf := Self as IwbMainRecord; end; FileID := aFormID shr 24; if FileID > FilesCount then FileID := FilesCount; if not Assigned(Files[FileID]) then Files[FileID] := _File.Masters[FileID]; aFormID := (aFormID and $00FFFFFF) or (Cardinal(Files[FileID].MasterCount) shl 24); MainRecord := Files[FileID].RecordByFormID[aFormID, True]; if Assigned(MainRecord) then if aAdd then MainRecord.AddReferencedBy(SelfIntf) else MainRecord.RemoveReferencedBy(SelfIntf); end; var NewReferences : TDynCardinalArray; LastFormID : Cardinal; i, j : Integer; NewCount : integer; Cmp : Integer; SelfRef : IwbContainerElementRef; begin if mrsBuildingRef in mrStates then Exit; SelfRef := Self as IwbContainerElementRef; Assert(not (mrsBuildingRef in mrStates)); Include(mrStates, mrsBuildingRef); try mrTmpRefFormIDHigh := -1; mrTmpRefFormIDs := nil; if not aRemove then inherited BuildRef; NewCount := 0; SetLength(NewReferences, Succ(mrTmpRefFormIDHigh)); if mrTmpRefFormIDHigh >= 0 then begin wbMergeSort(@mrTmpRefFormIDs[0], Succ(mrTmpRefFormIDHigh), CompareFormIDs); LastFormID := 0; for i := 0 to mrTmpRefFormIDHigh do if mrTmpRefFormIDs[i] <> LastFormID then begin LastFormID := mrTmpRefFormIDs[i]; NewReferences[NewCount] := LastFormID; Inc(NewCount); end; end; SetLength(NewReferences, NewCount); i := 0; j := 0; while (i < NewCount) and (j < Length(mrReferences)) do begin Cmp := CmpW32(NewReferences[i], mrReferences[j]); if Cmp = 0 then begin Inc(i); Inc(j); end else if Cmp < 0 then begin ProcessRef(NewReferences[i], True); Inc(i); end else begin ProcessRef(mrReferences[j], False); Inc(j); end; end; while i < NewCount do begin ProcessRef(NewReferences[i], True); Inc(i); end; while j < Length(mrReferences) do begin ProcessRef(mrReferences[j], False); Inc(j); end; mrReferences := NewReferences; finally Exclude(mrStates, mrsBuildingRef); mrTmpRefFormIDs := nil; end; end; procedure TwbMainRecord.ElementChanged(const aElement: IwbElement; aContainer: Pointer); const EDID = $44494445; FULL = $4C4C5546; NAME = $454D414E; var SubRecord: IwbSubRecord; begin if Supports(aElement, IwbSubRecord, SubRecord) then case Cardinal(SubRecord.Signature) of EDID: mrEditorID := SubRecord.Value; FULL: mrFullName := SubRecord.Value; NAME: Exclude(mrStates, mrsBaseRecordChecked); end; inherited; if not (mrsNoUpdateRefs in mrStates) then UpdateRefs; end; function TwbMainRecord.EnsureChildGroup: IwbGroupRecord; const WRLD = $444C5257; CELL = $4C4C4543; DIAL = $4C414944; var SearchForGroup : Integer; ContainingGroup : IwbGroupRecord; begin Result := GetChildGroup; if not Assigned(Result) then begin case Cardinal(GetSignature) of WRLD: SearchForGroup := 1; CELL: SearchForGroup := 6; DIAL: SearchForGroup := 7; else if wbVWDAsQuestChildren and (GetSignature = 'QUST') then SearchForGroup := 10 else SearchForGroup := 0; end; if (SearchForGroup > 0) and Supports(GetContainer, IwbGroupRecord, ContainingGroup) then begin mrGroup := ContainingGroup.FindChildGroup(SearchForGroup, Self); if not Assigned(mrGroup) and ContainingGroup.IsElementEditable(nil) then begin mrGroup := TwbGroupRecord.Create(ContainingGroup, SearchForGroup, Self); Result := mrGroup; end; end; end; Assert(Assigned(Result)); end; function TwbMainRecord.CanAssignInternal(aIndex: Integer; const aElement: IwbElement; aCheckDontShow: Boolean): Boolean; begin Result := False; if not wbEditAllowed then Exit; if GetIsDeleted then Exit; if Assigned(eContainer) then if not IwbContainer(eContainer).IsElementEditable(Self) then Exit; if aCheckDontShow then if GetDontShow then Exit; if not Assigned(aElement) then begin Result := (aIndex >= 0) and (aIndex < mrDef.MemberCount) and (GetElementBySortOrder(aIndex + GetAdditionalElementCount) = nil); if Result and aCheckDontShow then Result := not mrDef.Members[aIndex].DontShow[Self]; Exit; end; if Assigned(mrDef) then begin if aIndex = Low(Integer) then Result := mrDef.Equals(aElement.Def) else begin Result := (aIndex >= 0) and (aIndex < mrDef.MemberCount) and ( mrDef.Members[aIndex].CanAssign(Self, Low(Integer), aElement.Def) or mrDef.Members[aIndex].CanAssign(Self, High(Integer), aElement.Def) ); if Result and aCheckDontShow then Result := not mrDef.Members[aIndex].DontShow[Self]; end; end else Result := False; end; function TwbMainRecord.CanContainFormIDs: Boolean; begin Result := True; {There is a FormID in the header} end; function TwbMainRecord.CanElementReset: Boolean; begin Result := cntElementRefs < 1; end; function TwbMainRecord.CheckChildOfCell: Boolean; var Sig : TwbSignature; Group1 : IwbGroupRecord; Group2 : IwbGroupRecord; begin Sig := GetSignature; Result := (Sig = 'REFR') or (Sig = 'PMIS') or (Sig = 'PGRE') or (Sig = 'ACRE') or (Sig = 'ACHR') or (Sig = 'PARW') or {>>> Skyrim <<<} (Sig = 'PBEA') or {>>> Skyrim <<<} (Sig = 'PFLA') or {>>> Skyrim <<<} (Sig = 'PCON') or {>>> Skyrim <<<} (Sig = 'PBAR') or {>>> Skyrim <<<} (Sig = 'PHZD'); {>>> Skyrim <<<} if not Result then Exit; if not Supports(GetContainer, IwbGroupRecord, Group1) then raise Exception.Create(GetName + ' is not contained in a group.'); if not (Group1.GroupType in [8, 9, 10]) then raise Exception.Create(GetName + ' is not contained in a group of type "Cell Persistent Childen", "Cell Temporary Children" or "Cell Visible Distant Children"'); if not Supports(Group1.Container, IwbGroupRecord, Group2) then raise Exception.Create(Group1.GetName + ' is not contained in a group.'); if not (Group2.GroupType in [6]) then raise Exception.Create(Group1.GetName + ' is not contained in a group of type "Cell Children"'); end; procedure TwbMainRecord.ClearForRelease; begin mrMaster := nil; mrOverrides := nil; mrReferencedBy := nil; mrGroup := nil; ReleaseElements; end; procedure TwbMainRecord.CollapseStorage; var Stream : TMemoryStream; begin if (esModified in eStates) then begin PrepareSave; Stream := TMemoryStream.Create; try WriteToStream(Stream, True); DoReset(True); ReleaseElements; if mrBasePtrAllocated in mrStates then FreeMem(dcBasePtr); GetMem(dcBasePtr, Stream.Size); Include(mrStates, mrBasePtrAllocated); Move(Stream.Memory^, dcBasePtr^, Stream.Size); dcEndPtr := Pointer( Cardinal(dcBasePtr) + Stream.Size); Exclude(dcFlags, dcfStorageInvalid); mrDataStorage := nil; dcDataStorage := nil; dcDataBasePtr := nil; dcDataEndPtr := nil; InitDataPtr; SetModified(True); InvalidateParentStorage; finally Stream.Free; end; end; end; function TwbMainRecord.CompareExchangeFormID(aOldFormID, aNewFormID: Cardinal): Boolean; var SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; mrBaseRecordID := 0; Exclude(mrStates, mrsBaseRecordChecked); Result := inherited CompareExchangeFormID(aOldFormID, aNewFormID); if {Result and} (csRefsBuild in cntStates) then // if you changed to an already existing FormID BuildRef; end; procedure TwbMainRecord.ContainerChanged; var ContainedIn: IwbContainedIn; begin if csInit in cntStates then if Supports(GetElementBySortOrder(-2 + GetAdditionalElementCount), IwbContainedIn, ContainedIn) then ContainedIn.ContainerChanged; end; constructor TwbMainRecord.Create(const aContainer: IwbContainer; const aSignature: TwbSignature; aFormID: Cardinal); var BasePtr : PwbMainRecordStruct; i : Integer; SelfRef : IwbContainerElementRef; Group : IwbGroupRecordInternal; Group2 : IwbGroupRecordInternal; ContainerRef : IwbContainerElementRef; s : string; Block : Cardinal; SubBlock : Cardinal; lContainer : IwbContainer; IsInterior : Boolean; begin IsInterior := False; lContainer := aContainer; New(BasePtr); Include(mrStates, mrBasePtrAllocated); BasePtr.mrsSignature := aSignature; BasePtr.mrsDataSize := 0; BasePtr.mrsFlags._Flags := 0; BasePtr.mrsFormID := aFormID; BasePtr.mrsVCS1 := DefaultVCS1; case wbGameMode of gmFO4 : BasePtr.mrsVersion := 131; gmTES5: BasePtr.mrsVersion := 43; gmSSE : BasePtr.mrsVersion := 44; gmFNV : BasePtr.mrsVersion := 15; gmFO3 : BasePtr.mrsVersion := 15; else BasePtr.mrsVersion := 15; end; BasePtr.mrsVCS2 := DefaultVCS2; Group := nil; if Supports(lContainer, IwbGroupRecordInternal, Group) then if Group.GroupType = 8 then BasePtr.mrsFlags.SetPersistent(True) else if (Group.GroupType = 10) and not (wbVWDAsQuestChildren and Supports(Group.Container, IwbGroupRecord, Group2) and (TwbSignature(Group2.GroupLabel) = 'QUST')) then BasePtr.mrsFlags.SetVisibleWhenDistant(True); if Assigned(Group) then if aSignature = 'CELL' then begin if Group.GroupType = 3 then Supports(Group.Container, IwbGroupRecordInternal, Group); if Assigned(Group) then begin if Group.GroupType = 2 then Supports(Group.Container, IwbGroupRecordInternal, Group); if Assigned(Group) then begin if (Group.GroupType = 0) and (TwbSignature(Group.GroupLabel) = 'CELL') then begin s := '00' + IntToStr(aFormID and $00FFFFFF); Block := StrToInt(s[Length(s)]); SubBlock := StrToInt(s[Pred(Length(s))]); ContainerRef := Group as IwbContainerElementRef; Group := nil; for i := 0 to Pred(ContainerRef.ElementCount) do if Supports(ContainerRef.Elements[i], IwbGroupRecord, Group) then if (Group.GroupType = 2) and (Group.GroupLabel = Block) then Break else Group := nil; if not Assigned(Group) then Group := TwbGroupRecord.Create(ContainerRef as IwbContainer, 2, Block); ContainerRef := Group as IwbContainerElementRef; Group := nil; for i := 0 to Pred(ContainerRef.ElementCount) do if Supports(ContainerRef.Elements[i], IwbGroupRecord, Group) then if (Group.GroupType = 3) and (Group.GroupLabel = SubBlock) then Break else Group := nil; if not Assigned(Group) then Group := TwbGroupRecord.Create(ContainerRef as IwbContainer, 3, SubBlock); lContainer := Group as IwbContainer; IsInterior := True; end; end; end; end; Create(lContainer, Pointer(BasePtr), nil, nil); Assert(Assigned(mrDef)); SelfRef := Self as IwbContainerElementRef; DoInit; SetModified(True); InvalidateStorage; for i := 0 to Pred(mrDef.MemberCount) do if mrDef.Members[i].Required then Assign(i, nil, False); if Supports(lContainer, IwbGroupRecordInternal, Group) then Group.Sort; if IsInterior then if Supports(GetRecordBySignature('DATA'), IwbContainerElementRef, ContainerRef) then ContainerRef.EditValue := '1'; end; constructor TwbMainRecord.Create(const aContainer: IwbContainer; var aBasePtr: Pointer; aEndPtr: Pointer; const aPrevMainRecord : IwbMainRecord); var _File: IwbFileInternal; begin inherited; try _File := GetFile as IwbFileInternal; if Assigned(_File) then _File.AddMainRecord(Self); except if Assigned(aContainer) then aContainer.RemoveElement(Self); raise; end; end; procedure TwbMainRecord.DecompressIfNeeded; var UncompressedLength: Cardinal; begin InitDataPtr; // reset... if mrStruct.mrsFlags.IsCompressed then try UncompressedLength := PCardinal(dcDataBasePtr)^; if UncompressedLength > 0 then begin SetLength(mrDataStorage, UncompressedLength ); DecompressToUserBuf( Pointer( Cardinal(dcDataBasePtr) + SizeOf(Cardinal) ), mrStruct.mrsDataSize - SizeOf(Cardinal), @mrDataStorage[0], UncompressedLength ); dcDataBasePtr := @mrDataStorage[0]; dcDataEndPtr := Pointer( Cardinal(dcDataBasePtr) + UncompressedLength ); end else begin mrDataStorage := nil; dcDataBasePtr := @EmptyPtr; dcDataEndPtr := @EmptyPtr; end; except dcDataBasePtr := nil; dcDataEndPtr := nil; end; end; procedure TwbMainRecord.Delete; var SelfRef : IwbContainerElementRef; BasePtr : Pointer; GroupRecord : IwbGroupRecord; begin SelfRef := Self; DoInit; SetModified(True); InvalidateStorage; ReleaseElements; MakeHeaderWriteable; GetFlagsPtr.SetDeleted(True); if Supports(Self.GetContainer, IwbGroupRecord, GroupRecord) then if wbCreateContainedIn and (GroupRecord.GroupType in [1, 4..10]) then with TwbContainedInElement.Create(Self) do begin _AddRef; _Release; end; GroupRecord := nil; BasePtr := dcBasePtr; with TwbRecordHeaderStruct.Create(Self, BasePtr, Pointer( Cardinal(BasePtr) + wbSizeOfMainRecordStruct), mrDef.RecordHeaderStruct, '') do begin Include(dcFlags, dcfDontSave); SetSortOrder(-1); SetMemoryOrder(Low(Integer)); _AddRef; _Release; end; end; procedure TwbMainRecord.DeleteInto(const aFile: IwbFile); var MainRecord: IwbMainRecord; begin if Supports(CopyInto(aFile, False, False, '', '', ''), IwbMainRecord, MainRecord) then MainRecord.Delete; end; destructor TwbMainRecord.Destroy; begin if mrBasePtrAllocated in mrStates then FreeMem(dcBasePtr); inherited; end; procedure TwbMainRecord.Init; var FoundError : Boolean; CurrentPtr : Pointer; CurrentDefPos : Integer; CurrentRecPos : Integer; Element : IwbElement; CurrentRec : IwbSubRecord; CurrentDef : IwbRecordMemberDef; SubRecordArray : IwbSubRecordArrayInternal; Dummy : Integer; LastElementForMember : array of IwbElement; GroupRecord : IwbGroupRecord; GroupRecordInternal : IwbGroupRecordInternal; {$IFDEF DBGSUBREC} // MainRecord : IwbMainRecord; s: string; {$ENDIF} RequiredRecords : set of byte; PresentRecords : set of byte; i : Integer; begin RequiredRecords := []; PresentRecords := []; inherited; if recSkipped then Exit; if Length(cntElements) > 0 then Exit; DecompressIfNeeded; FoundError := False; if not (mrsQuickInit in mrStates) then begin if Supports(Self.GetContainer, IwbGroupRecord, GroupRecord) then if wbCreateContainedIn and (GroupRecord.GroupType in [1, 4..10]) then with TwbContainedInElement.Create(Self) do begin _AddRef; _Release; end; GroupRecord := nil; CurrentPtr := dcBasePtr; with TwbRecordHeaderStruct.Create(Self, CurrentPtr, Pointer( Cardinal(CurrentPtr) + wbSizeOfMainRecordStruct), mrDef.RecordHeaderStruct, '') do begin Include(dcFlags, dcfDontSave); SetSortOrder(-1); SetMemoryOrder(Low(Integer)); _AddRef; _Release; end; end; {$IFDEF DBGSUBREC} s := ''; {$ENDIF} CurrentPtr := GetDataBasePtr; while Cardinal(CurrentPtr) < Cardinal(dcDataEndPtr) do begin Element := TwbRecord.CreateForPtr(CurrentPtr, dcDataEndPtr, Self, nil); {$IFDEF DBGSUBREC} if Supports(Element, IwbSubRecord, CurrentRec) then s := s + CurrentRec.Signature + ' '; {$ENDIF} end; Element := nil; if not Assigned(mrDef) then Exit; SetLength(LastElementForMember, mrDef.MemberCount); if not Assigned(cntElements) then Exit; CurrentDefPos := 0; CurrentRecPos := 0; while (CurrentRecPos < Length(cntElements)) do begin if cntElements[CurrentRecPos].ElementType <> etSubRecord then begin Inc(CurrentRecPos); Continue; end; CurrentRec := cntElements[CurrentRecPos] as IwbSubRecord; if wbIgnoreRecords.Find(CurrentRec.Signature, Dummy) then begin Inc(CurrentRecPos); Continue; end; if mrDef.AllowUnordered then begin CurrentDefPos := mrDef.GetMemberIndexFor(CurrentRec.Signature, CurrentRec); if CurrentDefPos < 0 then begin if Assigned(wbProgressCallback) then wbProgressCallback('Error: record '+ String(GetSignature) + ' contains unexpected (or out of order) subrecord ' + String(CurrentRec.Signature) + ' ' + IntToHex(Int64(Cardinal(CurrentRec.Signature)), 8) ); FoundError := True; Inc(CurrentRecPos); Continue; end; CurrentDef := mrDef.Members[CurrentDefPos]; end else begin if not mrDef.ContainsMemberFor(CurrentRec.Signature, CurrentRec) then begin if Assigned(wbProgressCallback) then wbProgressCallback('Error: record '+ String(GetSignature) + ' contains unexpected (or out of order) subrecord ' + String(CurrentRec.Signature) + ' ' + IntToHex(Int64(Cardinal(CurrentRec.Signature)), 8) ); FoundError := True; Inc(CurrentRecPos); Continue; end; if (CurrentDefPos < mrDef.MemberCount) and not FoundError then begin CurrentDef := mrDef.Members[CurrentDefPos]; if not CurrentDef.CanHandle(CurrentRec.Signature, CurrentRec) then begin Inc(CurrentDefPos); Continue; end; end else begin if Assigned(wbProgressCallback) then wbProgressCallback('Error: record '+ String(GetSignature) + ' contains unexpected (or out of order) subrecord ' + String(CurrentRec.Signature) ); FoundError := True; CurrentDefPos := mrDef.GetMemberIndexFor(CurrentRec.Signature, CurrentRec); if CurrentDefPos < 0 then begin Inc(CurrentRecPos); Continue; end; CurrentDef := mrDef.Members[CurrentDefPos]; end; end; if CurrentDefPos > mrDef.QuickInitLimit then begin Include(mrStates, mrsQuickInitDone); if mrsQuickInit in mrStates then Exit; end; if CurrentDef.DefType = dtSubRecordUnion then begin CurrentDef := (CurrentDef as IwbRecordDef).GetMemberFor(CurrentRec.Signature, CurrentRec); Assert(Assigned(CurrentDef)); end; case CurrentDef.DefType of dtSubRecord : begin (CurrentRec as IwbSubRecordInternal).SetDef(CurrentDef as IwbSubRecordDef); if CurrentRec.Signature = 'EDID' then mrEditorID := CurrentRec.Value else if CurrentRec.Signature = 'FULL' then mrFullName := CurrentRec.Value else if (CurrentRec.Signature = 'NAME') and ( (mrDef.DefaultSignature = 'REFR') or (mrDef.DefaultSignature = 'PGRE') or (mrDef.DefaultSignature = 'PMIS') or (mrDef.DefaultSignature = 'ACHR') or (mrDef.DefaultSignature = 'ACRE') or (mrDef.DefaultSignature = 'PARW') or {>>> Skyrim <<<} (mrDef.DefaultSignature = 'PBEA') or {>>> Skyrim <<<} (mrDef.DefaultSignature = 'PFLA') or {>>> Skyrim <<<} (mrDef.DefaultSignature = 'PCON') or {>>> Skyrim <<<} (mrDef.DefaultSignature = 'PBAR') or {>>> Skyrim <<<} (mrDef.DefaultSignature = 'PHZD') {>>> Skyrim <<<} ) then begin mrBaseRecordID := CurrentRec.NativeValue; Include(mrStates, mrsBaseRecordChecked); end; end; dtSubRecordArray : begin if Supports(LastElementForMember[CurrentDefPos], IwbSubRecordArrayInternal, SubRecordArray) then begin SubRecordArray.DoProcess(Self, CurrentRecPos); Continue; end else InsertElement(CurrentRecPos, TwbSubRecordArray.Create(nil, Self, CurrentRecPos, CurrentDef as IwbSubRecordArrayDef)); end; dtSubRecordStruct : InsertElement(CurrentRecPos, TwbSubRecordStruct.Create(nil, Self, CurrentRecPos, CurrentDef as IwbSubRecordStructDef)); else raise Exception.CreateFmt('Unexpected def type for SubRecord %s in %s', [String(CurrentRec.Signature), String(GetSignature)]); end; (cntElements[CurrentRecPos] as IwbElementInternal).SetSortOrder(CurrentDefPos); (cntElements[CurrentRecPos] as IwbElementInternal).SetMemoryOrder(CurrentDefPos); Include(PresentRecords, CurrentDefPos); LastElementForMember[CurrentDefPos] := cntElements[CurrentRecPos]; Inc(CurrentRecPos); Inc(CurrentDefPos); end; while CurrentRecPos < Length(cntElements) do begin if cntElements[CurrentRecPos].ElementType <> etSubRecord then begin Inc(CurrentRecPos); Continue; end; CurrentRec := cntElements[CurrentRecPos] as IwbSubRecord; if wbIgnoreRecords.Find(CurrentRec.Signature, Dummy) then begin Inc(CurrentRecPos); Continue; end; if Assigned(wbProgressCallback) then wbProgressCallback('Error: record '+ String(GetSignature) + ' contains unexpected (or out of order) subrecord ' + String(CurrentRec.Signature) ); FoundError := True; Inc(CurrentRecPos); end; // if GetSignature = 'DIAL' then // FoundError := True; if FoundError then if Assigned(wbProgressCallback) then begin wbProgressCallback('Errors were found in: ' + GetName); {$IFDEF DBGSUBREC} wbProgressCallback('Contained subrecords: ' + s); {$ENDIF} end; if wbSortSubRecords and (mrDef.AllowUnordered or (esModified in eStates)) and (Length(cntElements) > 1) then wbMergeSort(@cntElements[0], Length(cntElements), CompareSubRecords); mrDef.AfterLoad(Self); if not mrStruct.mrsFlags.IsDeleted then begin for i := 0 to Pred(mrDef.MemberCount) do if mrDef.Members[i].Required then Include(RequiredRecords, i); RequiredRecords := RequiredRecords - PresentRecords; if RequiredRecords <> [] then begin if wbBeginInternalEdit then try for i := 0 to Pred(mrDef.MemberCount) do if i in RequiredRecords then begin if wbMoreInfoForRequired then wbProgressCallback(' ['+IntToHex64(mrFixedFormID, 8)+'] Adding missing record: ' + mrDef.Members[i].GetName); Assign(i, nil, False); end; finally wbEndInternalEdit; end; end; end; if wbReportMode {and mrDef.AllowUnordered} then begin s := GetSignature + ' -> ' + s; CurrentRecPos := SubRecordOrderList.Add(s); SubRecordOrderList.Objects[CurrentRecPos] := Pointer(Succ(Integer(SubRecordOrderList.Objects[CurrentRecPos]))); end; { if GetSignature = 'SCPT' then begin // s := (GetRecordBySignature('DATA') as IwbContainer).Elements[0].EditValue + s; CurrentRecPos := SubRecordOrderList.Add(s); SubRecordOrderList.Objects[CurrentRecPos] := Pointer(Succ(Integer(SubRecordOrderList.Objects[CurrentRecPos]))); end; } Include(cntStates, csInitOnce); if not GetIsDeleted and (GetSignature = 'INFO') and not Assigned(GetRecordBySignature('PNAM')) and wbAllowInternalEdit then if Supports(IwbContainer(eContainer), IwbGroupRecordInternal, GroupRecordInternal) then GroupRecordInternal.Sort; end; function TwbMainRecord.FindReferencedBy(const aMainRecord: IwbMainRecord; var Index: Integer): Boolean; var L, H, I, C: Integer; begin Result := False; L := Low(mrReferencedBy); H := High(mrReferencedBy); while L <= H do begin I := (L + H) shr 1; C := CmpW32(mrReferencedBy[I].LoadOrderFormID , aMainRecord.LoadOrderFormID); if C = 0 then C := CmpW32(mrReferencedBy[I]._File.LoadOrder, aMainRecord._File.LoadOrder); if C < 0 then L := I + 1 else begin H := I - 1; if C = 0 then begin Result := True; L := I; end; end; end; Index := L; end; procedure TwbMainRecord.FindUsedMasters(aMasters: PwbUsedMasters); var FileID : Integer; i : Integer; SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; DoInit; if mrStruct.mrsFormID <> 0 then begin FileID := mrStruct.mrsFormID shr 24; aMasters[FileID] := True; end; if csRefsBuild in cntStates then begin for i := High(mrReferences) downto Low(mrReferences) do begin FileID := mrReferences[i] shr 24; aMasters[FileID] := True; end; end else inherited; end; function TwbMainRecord.GetAdditionalElementCount: Integer; var GroupRecord: IwbGroupRecord; begin Result := 1; if wbCreateContainedIn and Supports(Self.GetContainer, IwbGroupRecord, GroupRecord) then if GroupRecord.GroupType in [1, 4..10] then Inc(Result); end; function TwbMainRecord.GetAddList: TDynStrings; var i, j : Integer; RecordDef : PwbRecordDef; begin Result := nil; if GetIsDeleted then Exit; if GetSignature = 'DIAL' then begin SetLength(Result, 1); Result[0] := 'INFO'; end else if GetSignature = 'CELL' then begin SetLength(Result, 11); Result[0] := 'ACHR'; Result[1] := 'ACRE'; Result[2] := 'REFR'; Result[3] := 'PGRE'; Result[4] := 'PMIS'; Result[5] := 'PARW'; {>>> Skyrim <<<} Result[6] := 'PBEA'; {>>> Skyrim <<<} Result[7] := 'PFLA'; {>>> Skyrim <<<} Result[8] := 'PCON'; {>>> Skyrim <<<} Result[9] := 'PBAR'; {>>> Skyrim <<<} Result[10] := 'PHZD'; {>>> Skyrim <<<} end else if GetSignature = 'WRLD' then begin end else if wbVWDAsQuestChildren and (GetSignature = 'QUST') then begin SetLength(Result, 3); Result[0] := 'DIAL'; Result[1] := 'DLBR'; Result[2] := 'SCEN'; end; j := 0; for i := Low(Result) to High(Result) do if wbFindRecordDef(AnsiString(Result[i]), RecordDef) then begin Result[j] := Result[i] + ' - ' + RecordDef.Name; Inc(j); end; SetLength(Result, j); end; function TwbMainRecord.GetBaseRecord: IwbMainRecord; var SelfRef: IwbContainerElementRef; NameRec: IwbContainerElementRef; begin Result := nil; if not ((mrsQuickInitDone in mrStates) or (csInitOnce in cntStates)) then begin SelfRef := Self as IwbContainerElementRef; Assert(not (csInit in cntStates)); Include(mrStates, mrsQuickInit); Include(cntStates, csInit); try try Init; finally DoReset(True); end; finally Exclude(cntStates, csInit); Exclude(mrStates, mrsQuickInit); end; end; if not (mrsBaseRecordChecked in mrStates) then begin SelfRef := Self as IwbContainerElementRef; mrBaseRecordID := 0; Include(mrStates, mrsBaseRecordChecked); if Supports(GetRecordBySignature('NAME'), IwbContainerElementRef, NameRec) then if Supports(NameRec.LinksTo, IwbMainRecord, Result) then begin mrBaseRecordID := NameRec.NativeValue; end; Exit; end; if mrBaseRecordID <> 0 then with GetFile do Result := RecordByFormID[mrBaseRecordID, True]; end; function TwbMainRecord.GetBaseRecordID: Cardinal; begin if not (mrsBaseRecordChecked in mrStates) then GetBaseRecord; Result := GetFile.FileFormIDtoLoadOrderFormID(mrBaseRecordID); end; function TwbMainRecord.GetCanHaveEditorID: Boolean; begin Result := Assigned(mrDef) and mrDef.ContainsEditorID; end; function TwbMainRecord.GetCheck: string; var i, j: Integer; RequiredCount: Integer; Element: IwbElement; Def: IwbNamedDef; FoundIt: Boolean; SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; Result := ''; if not Assigned(mrDef) then Exit; if recSkipped then Exit; if mrStruct.mrsFlags.IsDeleted then begin Result := ''; for i := GetAdditionalElementCount to Pred(GetElementCount) do begin Element := cntElements[i]; Def := Element.Def; if Assigned(Def) then Result := Result + Def.Name + ', '; end; SetLength(Result, Length(Result) - 2); if Result <> '' then Result := 'Record marked as deleted but contains: ' + Result; Exit; end; RequiredCount := 0; for i := 0 to Pred(mrDef.MemberCount) do if mrDef.Members[i].Required then Inc(RequiredCount); for i := 0 to Pred(GetElementCount) do begin Element := cntElements[i]; Def := Element.Def; if Assigned(Def) then begin if Def.Required then Dec(RequiredCount); end; end; if RequiredCount > 0 then begin Result := 'Missing required members: '; for i := 0 to Pred(mrDef.MemberCount) do if mrDef.Members[i].Required then begin Def := mrDef.Members[i]; FoundIt := False; for j := 0 to High(cntElements) do begin Element := cntElements[j]; if Def.Equals(Element.Def) then begin FoundIt := True; Break; end; end; if not FoundIt then Result := Result + Def.Name + ', '; end; SetLength(Result, Length(Result) - 2); end; end; function TwbMainRecord.GetChildGroup: IwbGroupRecord; var SearchForGroup: Integer; ContainingGroup: IwbGroupRecord; begin Result := mrGroup; if not Assigned(Result) and not (mrsSearchedChildGroup in mrStates) then begin try Include(mrStates, mrsSearchedChildGroup); SearchForGroup := 0; if GetSignature = 'WRLD' then SearchForGroup := 1 else if GetSignature = 'CELL' then SearchForGroup := 6 else if GetSignature = 'DIAL' then SearchForGroup := 7 else if wbVWDAsQuestChildren and (GetSignature = 'QUST') then SearchForGroup := 10; if (SearchForGroup > 0) and Supports(GetContainer, IwbGroupRecord, ContainingGroup) then mrGroup := ContainingGroup.FindChildGroup(SearchForGroup, Self); Result := mrGroup; finally Exclude(mrStates, mrsSearchedChildGroup); end; end; end; function TwbMainRecord.GetConflictAll: TConflictAll; begin Result := mrConflictAll; end; function TwbMainRecord.GetConflictThis: TConflictThis; begin Result := mrConflictThis; end; function TwbMainRecord.GetContainingMainRecord: IwbMainRecord; begin Result := Self; end; function TwbMainRecord.GetDef: IwbNamedDef; begin Result := mrDef; end; function StrRight(const s: String; Len: Integer): string; begin Result := s; while Length(Result)>> Skyrim <<<} (GetSignature = 'PBEA') or {>>> Skyrim <<<} (GetSignature = 'PFLA') or {>>> Skyrim <<<} (GetSignature = 'PCON') or {>>> Skyrim <<<} (GetSignature = 'PBAR') or {>>> Skyrim <<<} (GetSignature = 'PHZD') {>>> Skyrim <<<} then begin if Supports(GetElementByName('Map Marker'), IwbContainerElementRef, MapMarker) then Rec := MapMarker.RecordBySignature['FULL'] else Rec := GetRecordBySignature('NAME'); if Assigned(Rec) then Result := Trim(Rec.Value) end else if (GetSignature = 'CELL') then begin if Supports(GetContainer, IwbGroupRecord, GroupRecord) and (GroupRecord.GroupType = 1) then Result := '' else if Supports(GetRecordBySignature('XCLC'), IwbContainerElementRef, GridCoords) and (GridCoords.ElementCount >= 2) then Result := '<' + StrRight(GridCoords.Elements[0].Value,3) + ', ' + StrRight(GridCoords.Elements[1].Value,3) + '>'; end else if (GetSignature = 'INFO') then begin Result := GetElementValue('Responses\Response\NAM1'); end; end; function TwbMainRecord.GetDisplayNameKey: string; var Rec : IwbRecord; GridCoords : IwbContainerElementRef; GroupRecord : IwbGroupRecord; MapMarker : IwbContainerElementRef; begin Result := GetFullName; if Result = '' then if (GetSignature = 'REFR') or (GetSignature = 'PGRE') or (GetSignature = 'PMIS') or (GetSignature = 'ACHR') or (GetSignature = 'ACRE') or (GetSignature = 'PARW') or {>>> Skyrim <<<} (GetSignature = 'PBEA') or {>>> Skyrim <<<} (GetSignature = 'PFLA') or {>>> Skyrim <<<} (GetSignature = 'PCON') or {>>> Skyrim <<<} (GetSignature = 'PBAR') or {>>> Skyrim <<<} (GetSignature = 'PHZD') {>>> Skyrim <<<} then begin if Supports(GetElementByName('Map Marker'), IwbContainerElementRef, MapMarker) then Rec := MapMarker.RecordBySignature['FULL'] else Rec := GetRecordBySignature('NAME'); if Assigned(Rec) then Result := Trim(Rec.Value) end else if (GetSignature = 'CELL') then begin if Supports(GetContainer, IwbGroupRecord, GroupRecord) and (GroupRecord.GroupType = 1) then Result := ' ' else if Supports(GetRecordBySignature('XCLC'), IwbContainerElementRef, GridCoords) and (GridCoords.ElementCount >= 2) then Result := GridCoords.Elements[0].SortKey[True] + '|' + GridCoords.Elements[1].SortKey[True]; end; end; function TwbMainRecord.GetEditorID: string; var SelfRef: IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; if not ((mrsQuickInitDone in mrStates) or (csInitOnce in cntStates)) then begin if csInit in cntStates then begin Result := ''; Exit; end; Include(mrStates, mrsQuickInit); Include(cntStates, csInit); try try Init; finally DoReset(True); end; finally Exclude(cntStates, csInit); Exclude(mrStates, mrsQuickInit); end; end; Result := mrEditorID; end; function TwbMainRecord.GetEditValue: string; begin if wbDisplayLoadOrderFormID then Result := IntToHex64(GetLoadOrderFormID, 8) else Result := IntToHex64(GetFormID, 8); end; function TwbMainRecord.GetElementType: TwbElementType; begin Result := etMainRecord; end; function TwbMainRecord.GetFixedFormID: Cardinal; function MovedHereForSpeed: Cardinal; var MasterCount: Cardinal; _File: IwbFile; begin Result := PwbMainRecordStruct(dcBasePtr).mrsFormID; _File := GetFile; if Assigned(_File) then begin MasterCount := _File.MasterCount; if Result shr 24 > MasterCount then begin Result := (Result and $00FFFFFF) or (MasterCount shl 24); end; end; mrFixedFormID := Result; end; begin Result := mrFixedFormID; if Result = 0 then Result := MovedHereForSpeed; end; function TwbMainRecord.GetFlags: TwbMainRecordStructFlags; begin Result := mrStruct.mrsFlags; end; function TwbMainRecord.GetFlagsPtr: PwbMainRecordStructFlags; begin Result := @mrStruct.mrsFlags; end; function TwbMainRecord.GetFormID: Cardinal; begin Result := mrStruct.mrsFormID; end; function TwbMainRecord.GetFullName: string; var SelfRef: IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; if not ((mrsQuickInitDone in mrStates) or (csInitOnce in cntStates)) then begin Include(mrStates, mrsQuickInit); if csInit in cntStates then begin Result := ''; Exit; end; Include(cntStates, csInit); try try Init; finally DoReset(True); end; finally Exclude(cntStates, csInit); Exclude(mrStates, mrsQuickInit); end; end; Result := mrFullName; end; function TwbMainRecord.GetFormVersion: Cardinal; begin Result := mrStruct.mrsVersion; end; procedure TwbMainRecord.SetFormVersion(aFormVersion: Cardinal); begin MakeHeaderWriteable; mrStruct.mrsVersion := aFormVersion; end; procedure TwbMainRecord.ChangeFormSignature(aSignature: TwbSignature); begin MakeHeaderWriteable; mrStruct.mrsSignature := aSignature; end; procedure TwbMainRecord.ClampFormID(aIndex: Cardinal); begin if mrStruct.mrsFormID shr 24 > aIndex then begin MakeHeaderWriteable; mrStruct.mrsFormID := (mrStruct.mrsFormID and $00FFFFFF) or (aIndex shl 24); if Assigned(mrGroup) then mrGroup.GroupLabel := mrStruct.mrsFormID; end; end; function TwbMainRecord.GetGridCell(out aGridCell: TwbGridCell): Boolean; var Signature : TwbSignature; SelfRef : IwbContainerElementRef; XCLCRec : IwbContainerElementRef; begin Result := False; Signature := GetSignature; if (Signature <> 'CELL') then Exit; SelfRef := Self; DoInit; if not Supports(GetRecordBySignature('XCLC'), IwbContainerElementRef, XCLCRec) then Exit; if XCLCRec.ElementCount < 2 then Exit; with aGridCell, XCLCRec do begin X := StrToIntDef(Elements[0].Value, -10000); Y := StrToIntDef(Elements[1].Value, -10000); Result := (x <> -10000) and (y <> -10000); end; end; function TwbMainRecord.GetHasMesh: Boolean; var SelfRef : IwbContainerElementRef; ModelCnt : IwbContainerElementRef; MODL : IwbContainerElementRef; s : String; begin if not (mrsHasMeshChecked in mrStates) and Assigned(wbContainerHandler) then begin Include(mrStates, mrsHasMeshChecked); if GetSignature = 'TREE' then begin Include(mrStates, mrsHasMesh); end else begin SelfRef := Self as IwbContainerElementRef; if Supports(GetElementByName('Model'), IwbContainerElementRef, ModelCnt) then if Supports(ModelCnt.RecordBySignature['MODL'], IwbContainerElementRef, MODL) then begin s := Trim(StringReplace(MODL.Value, '/', '\', [rfReplaceAll])); if s <> '' then begin s := 'meshes\'+ s;// if Length(wbContainerHandler.OpenResource(s)) > 0 then Include(mrStates, mrsHasMesh); end; end; end; end; Result := mrsHasMesh in mrStates; end; function TwbMainRecord.GetHasPrecombinedMesh: Boolean; begin if not (mrsHasPrecombinedMeshChecked in mrStates) then Self.GetPrecombinedMesh; Result := mrsHasPrecombinedMesh in mrStates; end; type TwbPrecombinedInfo = record Ref, ID: Cardinal; end; var PrecombinedCacheFileName: string; PrecombinedCacheCellFormID: Cardinal; PrecombinedCache: array of TwbPrecombinedInfo; function TwbMainRecord.GetPrecombinedMesh: string; var Signature : TwbSignature; SelfRef : IwbContainerElementRef; Group : IwbGroupRecord; Cell : IwbMainRecord; CombinedRefs, CombinedRef: IwbContainerElementRef; cnt, i : Cardinal; s: string; begin Result := ''; if not (mrsHasPrecombinedMeshChecked in mrStates) then begin // we need file for cache checking if not Assigned(IwbElement(Self)._File) then Exit; Include(mrStates, mrsHasPrecombinedMeshChecked); Self.mrPrecombinedCellID := 0; Self.mrPrecombinedID := 0; if wbGameMode <> gmFO4 then Exit; Signature := Self.GetSignature; if (Signature <> 'REFR') and (Signature <> 'PGRE') and (Signature <> 'PMIS') and (Signature <> 'PARW') and (Signature <> 'PBEA') and (Signature <> 'PFLA') and (Signature <> 'PCON') and (Signature <> 'PBAR') and (Signature <> 'PHZD') then Exit; SelfRef := Self as IwbContainerElementRef; // markers can't be precombined if Cardinal(SelfRef.ElementNativeValues['NAME']) < $800 then Exit; if Supports(SelfRef.Container, IwbGroupRecord, Group) then Cell := Group.ChildrenOf; if not Assigned(Cell) then Exit; s := IwbElement(Self)._File.Name; i := Cell.FormID; // store cell's precombined index in cache if (i <> PrecombinedCacheCellFormID) or (s <> PrecombinedCacheFileName) then begin PrecombinedCacheCellFormID := i; PrecombinedCacheFileName := s; SetLength(PrecombinedCache, 0); if Supports(Cell.ElementByPath['XCRI\References'], IwbContainerElementRef, CombinedRefs) then begin cnt := CombinedRefs.ElementCount; SetLength(PrecombinedCache, cnt); for i := 0 to Pred(cnt) do if Supports(CombinedRefs[i], IwbContainerElementRef, CombinedRef) and (CombinedRef.ElementCount = 2) then begin PrecombinedCache[i].Ref := CombinedRef.Elements[0].NativeValue; PrecombinedCache[i].ID := CombinedRef.Elements[1].NativeValue; end; end; end; // search for ref in precombined index cache if Length(PrecombinedCache) > 0 then for i := Low(PrecombinedCache) to High(PrecombinedCache) do if PrecombinedCache[i].Ref = Self.GetFormID then begin Self.mrPrecombinedCellID := Cell.FormID and $00FFFFFF; Self.mrPrecombinedID := PrecombinedCache[i].ID; Include(mrStates, mrsHasPrecombinedMesh); Break; end; end; if mrsHasPrecombinedMesh in mrStates then Result := 'Precombined\' + IntToHex(Self.mrPrecombinedCellID, 8) + '_' + IntToHex(Self.mrPrecombinedID, 8) + '_OC.nif'; end; function TwbMainRecord.GetHasVisibleWhenDistantMesh: Boolean; var SelfRef : IwbContainerElementRef; ModelCnt : IwbContainerElementRef; MODL : IwbContainerElementRef; s : String; begin if not (mrsHasVWDMeshChecked in mrStates) and Assigned(wbContainerHandler) then begin Include(mrStates, mrsHasVWDMeshChecked); if GetSignature = 'TREE' then begin SelfRef := Self as IwbContainerElementRef; if Supports(GetElementByName('Model'), IwbContainerElementRef, ModelCnt) then if Supports(ModelCnt.RecordBySignature['MODL'], IwbContainerElementRef, MODL) then begin s := Trim(StringReplace(MODL.Value, '/', '\', [rfReplaceAll])); if s <> '' then begin s := 'textures\trees\billboards'+ChangeFileExt(s, '.dds'); if Length(wbContainerHandler.OpenResource(s)) > 0 then Include(mrStates, mrsHasVWDMesh); end; end; end else begin SelfRef := Self as IwbContainerElementRef; if Supports(GetElementByName('Model'), IwbContainerElementRef, ModelCnt) then if Supports(ModelCnt.RecordBySignature['MODL'], IwbContainerElementRef, MODL) then begin s := Trim(StringReplace(MODL.Value, '/', '\', [rfReplaceAll])); if s <> '' then begin s := 'meshes\'+ChangeFileExt(s, '_far.nif'); if Length(wbContainerHandler.OpenResource(s)) > 0 then Include(mrStates, mrsHasVWDMesh); end; end; end; end; Result := mrsHasVWDMesh in mrStates; end; function TwbMainRecord.GetHighestOverrideOrSelf(aMaxLoadOrder: Integer): IwbMainRecord; var Master : IwbMainRecord; i : Integer; begin Result := Self; Master := GetMasterOrSelf; for i := Pred(Master.OverrideCount) downto 0 do if Master.Overrides[i]._File.LoadOrder <= aMaxLoadOrder then begin Result := Master.Overrides[i]; Exit; end; end; function TwbMainRecord.GetInjectionSourceFiles: TDynFiles; var i, j, k : Integer; Rec : IwbMainRecord; _File : IwbFile; LastID : Cardinal; begin SetLength(Result, Length(mrReferences)); if Length(Result) > 0 then begin _File := GetFile; j := 0; for i := Low(mrReferences) to High(mrReferences) do begin Rec := _File.RecordByFormID[mrReferences[i], True]; if Assigned(Rec) then if not _File.Equals(Rec._File) then begin Rec := Rec.MasterOrSelf; if Rec.IsInjected then begin Result[j] := Rec._File; Inc(j); end; end; end; if j > 1 then begin wbMergeSort(@Result[0], j, CompareLoadOrder); k := 1; LastID := Result[0].ElementID; for i := 1 to Pred(j) do if Result[i].ElementID <> LastID then begin LastID := Result[i].ElementID; if k <> i then Result[k] := Result[i]; Inc(k); end; SetLength(Result, k); end else SetLength(Result, j); end; end; function TwbMainRecord.GetIsCompressed: Boolean; begin Result := GetFlags.IsCompressed; end; function TwbMainRecord.GetIsDeleted: Boolean; begin Result := GetFlags.IsDeleted; end; function TwbMainRecord.GetIsEditable: Boolean; begin Result := wbIsInternalEdit; if Result then Exit; if Assigned(eContainer) and not IwbContainer(eContainer).IsElementEditable(Self) then Exit; Result := True; end; function TwbMainRecord.GetIsESM: Boolean; begin Result := GetFlags.IsESM; end; function TwbMainRecord.GetIsLocalized: Boolean; begin Result := GetFlags.IsLocalized; end; function TwbMainRecord.GetIsInitiallyDisabled: Boolean; begin Result := GetFlags.IsInitiallyDisabled; end; function TwbMainRecord.GetIsInjected: Boolean; begin if not (mrsIsInjectedChecked in mrStates) then begin if not Assigned(mrMaster) and (mrStruct.mrsFormID <> 0) and( (mrStruct.mrsFormID shr 24) < Cardinal(GetFile.MasterCount) ) and not (fsIsHardcoded in GetFile.FileStates) then Include(mrStates, mrsIsInjected) else Exclude(mrStates, mrsIsInjected); Include(mrStates, mrsIsInjectedChecked); end; Result := mrsIsInjected in mrStates; end; function TwbMainRecord.GetIsInList: Boolean; begin with mreHeader do Result := mrehInUse and (mrehGeneration = mreGeneration); end; function TwbMainRecord.GetIsMaster: Boolean; begin Result := not Assigned(mrMaster); end; function TwbMainRecord.GetIsNotReachable: Boolean; var i: Integer; begin if Assigned(mrMaster) then Result := IwbMainRecord(mrMaster).IsNotReachable else begin Result := inherited GetIsNotReachable; if Result then for i := Low(mrOverrides) to High(mrOverrides) do if not (esNotReachable in mrOverrides[i].ElementStates) then begin Result := False; Exit; end; end; end; function TwbMainRecord.GetIsPersistent: Boolean; begin Result := GetFlags.IsPersistent; end; function TwbMainRecord.GetIsVisibleWhenDistant: Boolean; begin Result := GetFlags.IsVisibleWhenDistant; end; function TwbMainRecord.GetIsWinningOverride: Boolean; var Master: IwbMainRecord; begin if Assigned(mrMaster) then begin Master := IwbMainRecord(mrMaster); Assert(Master.OverrideCount > 0); Result := Equals(Master.Overrides[Pred(Master.OverrideCount)]); end else Result := Length(mrOverrides) < 1; end; function TwbMainRecord.GetLoadOrderFormID: Cardinal; var _File : IwbFile; _Master : IwbFile; FileID : Cardinal; begin Result := mrLoadOrderFormID; if Result = 0 then begin Result := mrStruct.mrsFormID; if Result = 0 then Exit; _File := GetFile; Assert(Assigned(_File)); FileID := Result shr 24; if FileID >= Cardinal(_File.MasterCount) then _Master := _File else _Master := _File.Masters[FileID]; if _Master.LoadOrder < 0 then raise Exception.CreateFmt('FormID [%s] in file %s refers to master file %s which has not been assigned a global load order', [ IntToHex64(Result, 8), _File.FileName, _Master.FileName ]); FileID := _Master.LoadOrder; Result := (Result and $00FFFFFF) or (FileID shl 24); mrLoadOrderFormID := Result; end; end; function TwbMainRecord.GetMaster: IwbMainRecord; begin Result := IwbMainRecord(mrMaster); end; function TwbMainRecord.GetMasterOrSelf: IwbMainRecord; begin Result := GetMaster; if not Assigned(Result) then Result := Self; end; function TwbMainRecord.GetShortName: string; var // Rec: IwbRecord; s : string; begin if wbDisplayShorterNames then begin Result := ''; s := GetEditorID; if s <> '' then Result := Result + {'<' +} s {+'>'}; s := GetFullName; if s <> '' then begin if Result <> '' then Result := Result + ' '; Result := Result + '"' + s +'"'; end; if Result <> '' then Result := Result + ' '; if wbDisplayLoadOrderFormID then Result := Result + '[' + GetSignature + ':' + IntToHex64(GetLoadOrderFormID, 8) + ']' else Result := Result + '[' + GetSignature + ':' + IntToHex64(mrStruct.mrsFormID, 8) + ']'; end else begin Result := inherited GetName; if Assigned(mrDef) then Result := Result + ' - ' + mrDef.GetName; if wbDisplayLoadOrderFormID then Result := Result + ' [' + IntToHex64(GetLoadOrderFormID, 8) + ']' else Result := Result + ' [' + IntToHex64(mrStruct.mrsFormID, 8) + ']'; s := GetEditorID; if s <> '' then Result := Result + ' <' + s +'>'; s := GetFullName; if s <> '' then Result := Result + ' "' + s +'"'; end; end; function TwbMainRecord.GetName: string; var s : string; begin Result := GetShortName; if Assigned(mrDef) then begin s := Trim(mrDef.AdditionalInfoFor(Self)); if s <> '' then Result := Result + ' (' + s + ')'; end; end; function TwbMainRecord.GetNativeValue: Variant; begin if wbDisplayLoadOrderFormID then Result := GetLoadOrderFormID else Result := GetFormID; end; function TwbMainRecord.GetNextEntry: IwbMainRecordEntry; begin Assert(mreHeader.mrehInUse); if mreGeneration = mreHeader.mrehGeneration then Result := IwbMainRecordEntry(mreNext) else Result := nil; end; function TwbMainRecord.GetOverride(aIndex: Integer): IwbMainRecord; begin if not mrOverridesSorted then begin wbMergeSort(@mrOverrides[0], Length(mrOverrides), CompareOverrides); mrOverridesSorted := True; end; Result := mrOverrides[aIndex]; end; function TwbMainRecord.GetOverrideCount: Integer; begin Result := Length(mrOverrides); end; function TwbMainRecord.GetPosition(out aPosition: TwbVector): Boolean; var Signature : TwbSignature; SelfRef : IwbContainerElementRef; DataRec : IwbContainerElementRef; begin Result := False; try Signature := GetSignature; if (Signature <> 'REFR') and (Signature <> 'ACRE') and (Signature <> 'ACHR') and (Signature <> 'PGRE') and (Signature <> 'PMIS') and (Signature <> 'PARW') and {>>> Skyrim <<<} (Signature <> 'PBEA') and {>>> Skyrim <<<} (Signature <> 'PFLA') and {>>> Skyrim <<<} (Signature <> 'PCON') and {>>> Skyrim <<<} (Signature <> 'PBAR') and {>>> Skyrim <<<} (Signature <> 'PHZD') {>>> Skyrim <<<} then Exit; SelfRef := Self; DoInit; if not Supports(GetRecordBySignature('DATA'), IwbContainerElementRef, DataRec) then Exit; if DataRec.ElementCount <> 2 then Exit; with aPosition, (DataRec.Elements[0] as IwbContainerElementRef) do begin if ElementCount <> 3 then Exit; X := Elements[0].NativeValue; Y := Elements[1].NativeValue; Z := Elements[2].NativeValue; end; except on E: Exception do begin if Assigned(wbProgressCallback) then wbProgressCallback('Error getting position for "' + GetName + '": ' + E.Message); Result := False; Exit; end; end; Result := True; end; function TwbMainRecord.GetPrevEntry: IwbMainRecordEntry; begin Assert(mreHeader.mrehInUse); if mreGeneration = mreHeader.mrehGeneration then Result := IwbMainRecordEntry(mrePrev) else Result := nil; end; function TwbMainRecord.GetPath: string; begin Result := mrStruct.mrsSignature; end; function TwbMainRecord.GetCountedRecordCount: Cardinal; begin Result := 1; end; function TwbMainRecord.GetReferencedBy(aIndex: Integer): IwbMainRecord; begin if mrsReferencedByUnsorted in mrStates then SortReferencedBy; Result := mrReferencedBy[aIndex]; end; function TwbMainRecord.GetReferencedByCount: Integer; begin Result := Length(mrReferencedBy); end; function TwbMainRecord.GetReferenceFile: IwbFile; var FileID: Integer; begin Result := GetFile; FileID := mrStruct.mrsFormID shr 24; if FileID < Result.MasterCount then Result := Result.Masters[FileID]; end; function TwbMainRecord.GetReferencesInjected: Boolean; var i, j : Integer; _File : IwbFile; RecFile : IwbFile; Rec : IwbMainRecord; Found : Boolean; begin if not (mrsReferencesInjectedChecked in mrStates) and (csRefsBuild in cntStates) then begin Include(mrStates, mrsReferencesInjectedChecked); Exclude(mrStates, mrsReferencesInjected); if Length(mrReferences) > 0 then begin _File := GetFile; for i := Low(mrReferences) to High(mrReferences) do begin Rec := _File.RecordByFormID[mrReferences[i], True]; if Assigned(Rec) then begin RecFile := Rec._File; if not _File.Equals(RecFile) then begin Rec := Rec.MasterOrSelf; if Rec.IsInjected then begin Found := False; for j := 0 to Pred(_File.MasterCount) do if _File.Masters[j].Equals(RecFile) then begin Found := True; Break; end; if not Found then begin Include(mrStates, mrsReferencesInjected); Break; end; end; end; end; end; end; end; Result := mrsReferencesInjected in mrStates; end; function TwbMainRecord.GetRotation(out aRotation: TwbVector): Boolean; var Signature : TwbSignature; SelfRef : IwbContainerElementRef; DataRec : IwbContainerElementRef; begin Result := False; Signature := GetSignature; if (Signature <> 'REFR') and (Signature <> 'ACRE') and (Signature <> 'ACHR') and (Signature <> 'PGRE') and (Signature <> 'PMIS') and (Signature <> 'PARW') and {>>> Skyrim <<<} (Signature <> 'PBEA') and {>>> Skyrim <<<} (Signature <> 'PFLA') and {>>> Skyrim <<<} (Signature <> 'PCON') and {>>> Skyrim <<<} (Signature <> 'PBAR') and {>>> Skyrim <<<} (Signature <> 'PHZD') {>>> Skyrim <<<} then Exit; SelfRef := Self; DoInit; if not Supports(GetRecordBySignature('DATA'), IwbContainerElementRef, DataRec) then Exit; if DataRec.ElementCount <> 2 then Exit; with aRotation, (DataRec.Elements[1] as IwbContainerElementRef) do begin if ElementCount <> 3 then Exit; X := StrToFloatDef(Elements[0].Value, 0); Y := StrToFloatDef(Elements[1].Value, 0); Z := StrToFloatDef(Elements[2].Value, 0); end; Result := True; end; function TwbMainRecord.GetScale(out aScale: Single): Boolean; var Signature : TwbSignature; SelfRef : IwbContainerElementRef; XSclRec : IwbContainerElementRef; begin Result := False; aScale := 1; Signature := GetSignature; if (Signature <> 'REFR') and (Signature <> 'ACRE') and (Signature <> 'ACHR') and (Signature <> 'PGRE') and (Signature <> 'PMIS') and (Signature <> 'PARW') and {>>> Skyrim <<<} (Signature <> 'PBEA') and {>>> Skyrim <<<} (Signature <> 'PFLA') and {>>> Skyrim <<<} (Signature <> 'PCON') and {>>> Skyrim <<<} (Signature <> 'PBAR') and {>>> Skyrim <<<} (Signature <> 'PHZD') {>>> Skyrim <<<} then Exit; SelfRef := Self; DoInit; if not Supports(GetRecordBySignature('XSCL'), IwbContainerElementRef, XSclRec) then Exit; aScale := StrToFloatDef(XSclRec.Value, 0); Result := True; end; function TwbMainRecord.GetSortKeyInternal(aExtended: Boolean): string; begin Result := IntToHex64(mrStruct.mrsFormID, 8); end; function TwbMainRecord.GetSortPriority: Integer; begin if (GetSignature = 'ROAD') or (GetSignature = 'LAND') then Result := -2 else if (GetSignature = 'CELL') or (GetSignature = 'PGRD') or (GetSignature = 'NAVM') then Result := -1 else Result := 0; end; function TwbMainRecord.GetValue: string; var Def: IwbDef; begin if wbReportMode then begin Def := GetValueDef; if Assigned(Def) then Def.Used; Def := GetDef; if Assigned(Def) then Def.Used; end; Result := ''; end; function TwbMainRecord.GetWinningOverride: IwbMainRecord; begin if Assigned(mrMaster) then Result := IwbMainRecord(mrMaster).WinningOverride else if Length(mrOverrides) > 0 then Result := mrOverrides[High(mrOverrides)] else Result := Self; end; procedure TwbMainRecord.InformStorage(var aBasePtr: Pointer; aEndPtr: Pointer); begin Assert(False); end; procedure TwbMainRecord.InitDataPtr; var RecordDef : PwbRecordDef; begin if Assigned(dcEndPtr) then begin dcDataBasePtr := Pointer( Cardinal( dcBasePtr ) + wbSizeOfMainRecordStruct ); dcDataEndPtr := Pointer( Cardinal( dcDataBasePtr ) + mrStruct.mrsDataSize ); dcEndPtr := dcDataEndPtr; end; if not Assigned(mrDef) then begin if wbFindRecordDef(PwbSignature(dcBasePtr)^, RecordDef) then mrDef := RecordDef^ else begin if Assigned(wbProgressCallback) then wbProgressCallback('Error: unknown record type '+ String(PwbSignature(dcBasePtr)^)); end; end; end; procedure TwbMainRecord.InsertEntryAfter(const aEntry: IwbMainRecordEntry); var Entry: IwbMainRecordEntry; begin Assert(Assigned(aEntry)); RemoveEntry; Assert(mreGeneration = -1); with mreHeader do begin Assert(mrehInUse); mreGeneration := mrehGeneration; Entry := Self; mrePrev := Pointer(aEntry); mreNext := Pointer(aEntry.NextEntry); aEntry.NextEntry := Entry; if Assigned(mreNext) then begin Assert( aEntry.Equals(IwbMainRecordEntry(mreNext).PrevEntry) ); IwbMainRecordEntry(mreNext).PrevEntry := Entry; end else begin Assert( aEntry.Equals(IwbMainRecordEntry(mrehTail)) ); mrehTail := Pointer(Entry); end; Inc(mrehCount); end; end; procedure TwbMainRecord.InsertEntryHead; var Entry: IwbMainRecordEntry; begin RemoveEntry; Assert(mreGeneration = -1); with mreHeader do begin Assert(mrehInUse); mreGeneration := mrehGeneration; mrePrev := nil; mreNext := mrehHead; Entry := Self; mrehHead := Pointer(Entry); if Assigned(mreNext) then begin Assert(not Assigned(IwbMainRecordEntry(mreNext).PrevEntry)); IwbMainRecordEntry(mreNext).PrevEntry := Entry end else begin Assert(not Assigned(mrehTail)); mrehTail := Pointer(Entry); end; Inc(mrehCount); end; end; procedure TwbMainRecord.InsertEntryTail; var Entry: IwbMainRecordEntry; begin RemoveEntry; Assert(mreGeneration = -1); with mreHeader do begin Assert(mrehInUse); mreGeneration := mrehGeneration; mreNext := nil; mrePrev := mrehTail; Entry := Self; mrehTail := Pointer(Entry); if Assigned(mrePrev) then begin Assert(not Assigned(IwbMainRecordEntry(mrePrev).NextEntry)); IwbMainRecordEntry(mrePrev).NextEntry := Entry end else begin Assert(not Assigned(mrehHead)); mrehHead := Pointer(Entry); end; Inc(mrehCount); end; end; function TwbMainRecord.IsElementRemoveable(const aElement: IwbElement): Boolean; begin Result := IsElementEditable(aElement) and not aElement.Def.Required; end; function TwbMainRecord.LinksToParent: Boolean; var Signature : TwbSignature; DATA : IwbRecord; SelfPtr : IwbContainerElementRef; s : string; begin Signature := GetSignature; if (Signature = 'CELL') then begin Result := True; SelfPtr := Self as IwbContainerElementRef; DATA := GetRecordBySignature('DATA'); if Assigned(DATA) then begin s := DATA.EditValue; if (Length(s)>0) and (s[1]='1') then Result := False; end; end else Result := (Signature = 'INFO') or (Signature = 'REFR') or (Signature = 'PGRE') or (Signature = 'PMIS') or (Signature = 'ACHR') or (Signature = 'ACRE') or (Signature = 'PGRD') or (Signature = 'PARW') or {>>> Skyrim <<<} (Signature = 'PBEA') or {>>> Skyrim <<<} (Signature = 'PFLA') or {>>> Skyrim <<<} (Signature = 'PCON') or {>>> Skyrim <<<} (Signature = 'PBAR') or {>>> Skyrim <<<} (Signature = 'PHZD') or {>>> Skyrim <<<} (Signature = 'NAVM') or (Signature = 'ROAD') or (Signature = 'LAND') or (wbVWDAsQuestChildren and ((Signature = 'DLBR') or (Signature = 'DIAL') or (Signature = 'SCEN'))); end; procedure TwbMainRecord.MakeHeaderWriteable; var p : PwbMainRecordStruct; BasePtr : Pointer; SelfPtr : IwbContainerElementRef; RecordHeader : IwbElement; begin SelfPtr := Self as IwbContainerElementRef; DoInit; SetModified(True); InvalidateParentStorage; if Assigned(dcEndPtr) then begin New(p); Include(mrStates, mrBasePtrAllocated); p^ := mrStruct^; dcBasePtr := p; dcEndPtr := nil; RecordHeader := GetElementBySortOrder( (-1) + GetAdditionalElementCount ); if Assigned(RecordHeader) then begin BasePtr := p; RecordHeader.InformStorage(BasePtr, Pointer( Cardinal(BasePtr) + wbSizeOfMainRecordStruct ) ); end; end; end; procedure TwbMainRecord.MarkModifiedRecursive; var SelfRef : IwbContainerElementRef; Group : IwbGroupRecord; begin SelfRef := Self as IwbContainerElementRef; DoInit; inherited; Group := GetChildGroup; if Assigned(Group) then Group.MarkModifiedRecursive; end; procedure TwbMainRecord.MasterCountUpdated(aOld, aNew: Byte); var FileID : Integer; i : Integer; FoundOne : Boolean; SelfRef : IwbContainerElementRef; // EditorID : IwbElement; begin mrBaseRecordID := 0; Exclude(mrStates, mrsBaseRecordChecked); SelfRef := Self as IwbContainerElementRef; DoInit; if mrStruct.mrsFormID <> 0 then begin //Assert(aNew > aOld); FileID := mrStruct.mrsFormID shr 24; if FileID >= aOld then begin FileID := aNew; MakeHeaderWriteable; mrStruct.mrsFormID := (mrStruct.mrsFormID and $00FFFFFF) or (Cardinal(FileID) shl 24); mrFixedFormID := 0; mrLoadOrderFormID := 0; Exclude(mrStates, mrsIsInjectedChecked); end; end; if csRefsBuild in cntStates then begin FoundOne := False; for i := High(mrReferences) downto Low(mrReferences) do begin FileID := mrReferences[i] shr 24; if FileID < aOld then Break; FoundOne := True; FileID := aNew; mrReferences[i] := (mrReferences[i] and $00FFFFFF) or (Cardinal(FileID) shl 24); end; if FoundOne then inherited; end else inherited; end; procedure TwbMainRecord.MasterIndicesUpdated(const aOld, aNew: TBytes); var OldFormID: Cardinal; NewFormID: Cardinal; i : Integer; FoundOne : Boolean; SelfRef : IwbContainerElementRef; begin mrBaseRecordID := 0; Exclude(mrStates, mrsBaseRecordChecked); SelfRef := Self as IwbContainerElementRef; DoInit; if mrStruct.mrsFormID <> 0 then begin OldFormID := mrStruct.mrsFormID; NewFormID := FixupFormID(OldFormID, aOld, aNew); if OldFormID <> NewFormID then begin MakeHeaderWriteable; mrStruct.mrsFormID := NewFormID; mrFixedFormID := 0; mrLoadOrderFormID := 0; Exclude(mrStates, mrsIsInjectedChecked); end; end; if csRefsBuild in cntStates then begin FoundOne := False; for i := Low(mrReferences) to High(mrReferences) do begin OldFormID := mrReferences[i]; NewFormID := FixupFormID(OldFormID, aOld, aNew); if OldFormID <> NewFormID then begin FoundOne := True; mrReferences[i] := NewFormID; end; end; if FoundOne then begin wbMergeSort(@mrReferences[0], Length(mrReferences), CompareFormIDs ); inherited; end; end else inherited; end; function TwbMainRecord.MasterRecordsFromMasterFilesAndSelf: TDynMainRecords; var Res : TDynMainRecords; _File : IwbFile; Master : IwbMainRecord; i, j : Integer; function AddRecord(const aRecord: IwbMainRecord): Boolean; var k : Integer; RecFile : IwbFile; begin Result := Equals(aRecord); if not Result then begin RecFile := aRecord._File; Result := _File.Equals(RecFile); if not Result then for k := 0 to Pred(_File.MasterCount) do begin Result := _File.Masters[k].Equals(RecFile); if Result then Break; end; if Result then Result := False else Exit; end; Res[i] := aRecord; Inc(i); end; begin Result := nil; Res := nil; if Assigned(mrMaster) then begin _File := GetFile; if Assigned(_File) then begin Master := IwbMainRecord(mrMaster); SetLength(Res, Succ(Master.OverrideCount)); i := 0; if not AddRecord(Master) then for j := 0 to Pred(Master.OverrideCount) do if AddRecord(Master.Overrides[j]) then break; SetLength(Res, i); if i> 0 then begin Result := Res; Exit; end; end; end; SetLength(Res, 1); Res[0] := Self; Result := Res; end; procedure TwbMainRecord.MergeStorageInternal(var aBasePtr: Pointer; aEndPtr: Pointer); begin Assert(False); end; function TwbMainRecord.mrStruct: PwbMainRecordStruct; begin Result := PwbMainRecordStruct(dcBasePtr); end; procedure TwbMainRecord.PrepareSave; var _File : IwbFile; GroupRecord : IwbGroupRecord; begin if GetSignature = wbHeaderSignature then begin if not Supports(GetContainer, IwbFile, _File) then raise Exception.Create('File Header record '+GetName+' must be contained directly in the file.'); if GetFormID <> 0 then raise Exception.Create('File Header record '+GetName+' can not have a FormID.'); end else begin if GetFormID = 0 then raise Exception.Create('Record '+GetName+' must have a FormID.'); if not Supports(GetContainer, IwbGroupRecord, GroupRecord) then raise Exception.Create('Record '+GetName+' is not contained in a group.'); case GroupRecord.GroupType of 0: begin {top level} if TwbSignature(GroupRecord.GroupLabel) <> GetSignature then raise Exception.Create('Record ' + GetName + ' can not be contained in ' + GroupRecord.Name); end; 1: begin {World Children} if (GetSignature <> 'CELL') and (GetSignature <> 'ROAD') then raise Exception.Create('Record ' + GetName + ' can not be contained in ' + GroupRecord.Name); end; 2, 4, 6: begin {interior and exterior block and cell children} raise Exception.Create('Record ' + GetName + ' can not be contained in ' + GroupRecord.Name); end; 3, 5: begin {interior and exterior sub-block} if (GetSignature <> 'CELL') then raise Exception.Create('Record ' + GetName + ' can not be contained in ' + GroupRecord.Name); end; 7: begin {topic children} if (GetSignature <> 'INFO') then raise Exception.Create('Record ' + GetName + ' can not be contained in ' + GroupRecord.Name); end; 8, 10: begin {Persistent and Visible when Distant/Quest Children} if (GetSignature <> 'REFR') and (GetSignature <> 'ACHR') and (GetSignature <> 'ACRE') and (GetSignature <> 'PGRE') and (GetSignature <> 'PMIS') and (GetSignature <> 'PARW') and {>>> Skyrim <<<} (GetSignature <> 'PBEA') and {>>> Skyrim <<<} (GetSignature <> 'PFLA') and {>>> Skyrim <<<} (GetSignature <> 'PCON') and {>>> Skyrim <<<} (GetSignature <> 'PBAR') and {>>> Skyrim <<<} (GetSignature <> 'PHZD') {>>> Skyrim <<<} then if not (wbVWDAsQuestChildren and ((GetSignature = 'DLBR') or (GetSignature = 'DIAL') or (GetSignature = 'SCEN'))) then raise Exception.Create('Record ' + GetName + ' can not be contained in ' + GroupRecord.Name); case GroupRecord.GroupType of 8:begin if not mrStruct.mrsFlags.IsPersistent then raise Exception.Create('Record ' + GetName + ' needs to have it''s Persistent flag set to be contained in ' + GroupRecord.Name); end; 10: if not wbVWDAsQuestChildren then begin if not mrStruct.mrsFlags.IsVisibleWhenDistant then raise Exception.Create('Record ' + GetName + ' needs to have it''s Visible when Distant flag set to be contained in ' + GroupRecord.Name); if mrStruct.mrsFlags.IsPersistent then raise Exception.Create('Record ' + GetName + ' can not have it''s Persistent flag set to be contained in ' + GroupRecord.Name); end; end; end; 9: begin {Temporary} if (GetSignature <> 'REFR') and (GetSignature <> 'ACHR') and (GetSignature <> 'ACRE') and (GetSignature <> 'LAND') and (GetSignature <> 'PGRD') and (GetSignature <> 'NAVM') and (GetSignature <> 'PGRE') and (GetSignature <> 'PMIS') and (GetSignature <> 'PARW') and {>>> Skyrim <<<} (GetSignature <> 'PBEA') and {>>> Skyrim <<<} (GetSignature <> 'PFLA') and {>>> Skyrim <<<} (GetSignature <> 'PCON') and {>>> Skyrim <<<} (GetSignature <> 'PBAR') and {>>> Skyrim <<<} (GetSignature <> 'PHZD') {>>> Skyrim <<<} then raise Exception.Create('Record ' + GetName + ' can not be contained in ' + GroupRecord.Name); if mrStruct.mrsFlags.IsPersistent then raise Exception.Create('Record ' + GetName + ' can not have it''s Persistent flag set to be contained in ' + GroupRecord.Name); if mrStruct.mrsFlags.IsVisibleWhenDistant and not wbVWDInTemporary then raise Exception.Create('Record ' + GetName + ' can not have it''s Visible when Distant flag set to be contained in ' + GroupRecord.Name); end; end; end; if GetIsDeleted and (GetDataSize > 0) then begin GetDataSize; Delete; end; //not needed for now inherited; end; function TwbMainRecord.Reached: Boolean; var Signature : TwbSignature; i : Integer; IsComplex : Boolean; { _File : IwbFile; Rec : IwbMainRecord; } SelfRef : IwbContainerElementRef; begin if esReachable in eStates then Exit(False); SelfRef := Self as IwbContainerElementRef; DoInit; Signature := GetSignature; IsComplex := (Signature = 'DIAL') or (Signature = 'WRLD') or (Signature = 'CELL'); if GetIsWinningOverride or IsComplex then begin {if csRefsBuild in cntStates then begin Result := esNotReachable in eStates; Exclude(eStates, esNotReachable); if Result and (Length(mrReferences) > 0) then begin _File := GetFile; for i := Low(mrReferences) to High(mrReferences) do begin Rec := _File.RecordByFormID[mrReferences[i], True]; if Assigned(Rec) then (Rec as IwbElementInternal).Reached; end; end; if LinksToParent then begin if Assigned(eContainer) then (IwbContainer(eContainer) as IwbElementInternal).Reached; Exit; end; end else} Result := inherited Reached; if Result then begin if not Assigned(eContainer) then Exit; if LinksToParent then Exit; if not IsComplex then Exit; if Assigned(mrMaster) then (IwbMainRecord(mrMaster) as IwbElementInternal).Reached else for i := 0 to Pred(GetOverrideCount) do (GetOverride(i) as IwbElementInternal).Reached; if Assigned(mrGroup) then (mrGroup as IwbElementInternal).Reached; end; end else Result := (GetWinningOverride as IwbElementInternal).Reached; end; procedure TwbMainRecord.Remove; var _File: IwbFileInternal; begin DoBuildRef(True); _File := GetFile as IwbFileInternal; if Assigned(_File) then _File.RemoveMainRecord(Self); if Assigned(mrMaster) then (IwbMainRecord(mrMaster) as IwbMainRecordInternal).RemoveOverride(Self) else if Length(mrOverrides) > 0 then (mrOverrides[0] as IwbMainRecordInternal).YouAreTheMaster(mrOverrides, mrReferencedBy); mrMaster := nil; mrOverrides := nil; mrReferencedBy := nil; mrFixedFormID := 0; mrLoadOrderFormID := 0; Exclude(mrStates, mrsIsInjectedChecked); mrConflictAll := caUnknown; mrConflictThis := ctUnknown; inherited; end; procedure TwbMainRecord.RemoveChildGroup(const aGroup: IwbGroupRecord); begin if Assigned(mrGroup) and mrGroup.Equals(aGroup) then begin mrGroup := nil; Exclude(mrStates, mrsSearchedChildGroup); end; end; function TwbMainRecord.RemoveElement(aPos: Integer; aMarkModified: Boolean = False): IwbElement; begin Result := inherited RemoveElement(aPos, aMarkModified); if Assigned(Result) and (Result.ElementType = etSubRecord) then with (Result as IwbSubRecord) do begin if Signature = 'EDID' then mrEditorID := '' else if Signature = 'FULL' then begin if (mrFullName <> '') and (Value = mrFullName) then mrFullName := ''; end else if Signature = 'NAME' then Exclude(mrStates, mrsBaseRecordChecked); end; end; procedure TwbMainRecord.RemoveEntry; var Entry : IwbMainRecordEntry; i : Integer; begin if Supports(IInterface(mrMaster), IwbMainRecordEntry, Entry) then Entry.RemoveEntry else begin RemoveEntryInternal; for i := Low(mrOverrides) to High(mrOverrides) do if Supports(mrOverrides[i], IwbMainRecordEntry, Entry) then Entry.RemoveEntryInternal; end; end; procedure TwbMainRecord.RemoveEntryInternal; begin with mreHeader do begin Assert(mrehInUse); if mreGeneration = mrehGeneration then begin if Assigned(mrePrev) then IwbMainRecordEntry(mrePrev).NextEntry := IwbMainRecordEntry(mreNext) else begin Assert(Equals(IwbMainRecordEntry(mrehHead))); mrehHead := mreNext; end; if Assigned(mreNext) then IwbMainRecordEntry(mreNext).PrevEntry := IwbMainRecordEntry(mrePrev) else begin Assert(Equals(IwbMainRecordEntry(mrehTail))); mrehTail := mrePrev; end; Dec(mrehCount); end; mrePrev := nil; mreNext := nil; mreGeneration := -1; end; end; function TwbMainRecord.RemoveInjected(aCanRemove: Boolean): Boolean; var i : Integer; SelfRef : IwbContainerElementRef; Element : IwbElement; begin SelfRef := Self as IwbContainerElementRef; DoInit; Result := False; if GetReferencesInjected then begin if GetSignature = 'SCPT' then begin Element := GetElementByName('References'); if Assigned(Element) then Element.Remove; Element := GetRecordBySignature('SCDA'); if Assigned(Element) then Element.EditValue := '1D 00 00 00'; Element := GetRecordBySignature('SCHR'); if Assigned(Element) then with (Element as IwbContainerElementRef) do begin ElementByName['RefCount'].EditValue := '0'; ElementByName['CompiledSize'].EditValue := '4'; end; Element := GetRecordBySignature('SCTX'); if Assigned(Element) then with TStringList.Create do try Text := Element.EditValue; for i := 0 to Pred(Count) do if StartsWith(Trim(Strings[i]), 'begin') then begin while i <= Count do Delete(Pred(Count)); Break; end; Element.EditValue := Text; finally Free; end; end else begin for i := High(cntElements) downto Low(cntElements) do if cntElements[i].CanContainFormIDs then begin Result := cntElements[i].RemoveInjected(True) or Result; if Result and aCanRemove then Break; end; end; end; Exclude(mrStates, mrsReferencesInjectedChecked); if Result and aCanRemove and GetIsRemoveable then begin Result := False; Remove; end; end; procedure TwbMainRecord.RemoveOverride(const aMainRecord: IwbMainRecord); var i,j: Integer; begin j := 0; for i := Low(mrOverrides) to High(mrOverrides) do begin if (mrOverrides[i] as IwbElement) <> (aMainRecord as IwbElement) then begin if i <> j then mrOverrides[j] := mrOverrides[i]; Inc(j); end; end; SetLength(mrOverrides, j); end; procedure TwbMainRecord.RemoveReferencedBy(aMainRecord: IwbMainRecord); var i: Integer; begin if mrsReferencedByUnsorted in mrStates then SortReferencedBy; if FindReferencedBy(aMainRecord, i) then begin mrReferencedBy[i] := nil; if i < High(mrReferencedBy) then begin Move(mrReferencedBy[Succ(i)], mrReferencedBy[i], SizeOf(Pointer) * (High(mrReferencedBy) - i)); Pointer(mrReferencedBy[High(mrReferencedBy)]) := nil; end; SetLength(mrReferencedBy, Pred(Length(mrReferencedBy))); end; end; procedure TwbMainRecord.ReportRequiredMasters(aStrings: TStrings; aAsNew: Boolean; Recursive: Boolean = True; Initial: Boolean = false); var _File: IwbFile; begin if not aAsNew then begin _File := GetReferenceFile; aStrings.AddObject(_File.FileName, Pointer(_File)); end; inherited; end; procedure TwbMainRecord.Reset; begin ReleaseElements; mrDataStorage := nil; InitDataPtr; inherited; end; procedure TwbMainRecord.ResetConflict; var i: Integer; begin inherited; if Assigned(mrMaster) then IwbElement(mrMaster).ResetConflict else begin mrConflictAll := caUnknown; mrConflictThis := ctUnknown; for i := Low(mrOverrides) to High(mrOverrides) do with mrOverrides[i] do begin ConflictAll := caUnknown; ConflictThis := ctUnknown; end; end; end; procedure TwbMainRecord.ResetReachable; begin Include(eStates, esNotReachable); Exclude(eStates, esReachable); end; function TwbMainRecord.ResolveElementName(aName: string; out aRemainingName: string; aCanCreate: Boolean): IwbElement; var i: Integer; begin Result := inherited ResolveElementName(aName, aRemainingName, aCanCreate); if not Assigned(Result) and aCanCreate and Assigned(mrDef) and (Length(aName) = 4) then begin i := mrDef.GetMemberIndexFor(StrToSignature(aName), nil); if i < 0 then Exit; Assign(i, nil, False); Result := GetElementBySignature(StrToSignature(aName)); end; end; procedure TwbMainRecord.ScanData; var SelfRef : IwbContainerElementRef; begin if not wbDelayLoadRecords then begin SelfRef := Self as IwbContainerElementRef; DoInit; end; end; procedure TwbMainRecord.SetChildGroup(const aGroup: IwbGroupRecord); begin if Pointer(mrGroup) = Pointer(aGroup) then Exit; if Assigned(aGroup) then begin if not (not Assigned(mrGroup) or (mrGroup.Equals(aGroup))) then begin if not (not Assigned(mrGroup) or (mrGroup.Equals(aGroup))) then Assert(not Assigned(mrGroup) or (mrGroup.Equals(aGroup)), 'Found additional ' + mrGroup.Name + ' for ' + Self.GetName); end; if Assigned(eContainer) then IwbContainer(eContainer).Equals(aGroup.Container); end else Assert(Assigned(mrGroup)); mrGroup := aGroup; end; procedure TwbMainRecord.SetConflictAll(aValue: TConflictAll); begin mrConflictAll := aValue; end; procedure TwbMainRecord.SetConflictThis(aValue: TConflictThis); begin mrConflictThis := aValue; end; procedure TwbMainRecord.SetContainer(const aContainer: IwbContainer); var ContainedIn: IwbContainedIn; begin inherited; if csInit in cntStates then if Supports(GetElementBySortOrder(-2 + GetAdditionalElementCount), IwbContainedIn, ContainedIn) then ContainedIn.ContainerChanged; end; procedure TwbMainRecord.SetEditorID(const aValue: string); var SelfRef : IwbContainerElementRef; Rec : IwbRecord; i : Integer; begin if not Assigned(mrDef) then Exit; if aValue = GetEditorID then Exit; SelfRef := Self as IwbContainerElementRef; DoInit; Rec := GetRecordBySignature('EDID'); if not Assigned(Rec) then begin i := mrDef.GetMemberIndexFor('EDID', nil); if i < 0 then Exit; Assign(i, nil, False); Rec := GetRecordBySignature('EDID'); Assert(Assigned(Rec)); end; if aValue = '' then Rec.Remove else Rec.EditValue := aValue; Assert(mrEditorID = aValue); end; procedure TwbMainRecord.SetEditValue(const aValue: string); begin if not wbEditAllowed then raise Exception.Create(GetName + ' can not be edited.'); if wbDisplayLoadOrderFormID then begin SetLoadOrderFormID(StrToInt64('$'+aValue)); NotifyChanged(eContainer); end else raise Exception.Create('FormID can only be edited if wbDisplayLoadOrderFormID is active'); end; procedure TwbMainRecord.SetIsCompressed(aValue: Boolean); begin if aValue <> GetIsCompressed then begin MakeHeaderWriteable; GetFlagsPtr.SetCompressed(aValue); end; end; procedure TwbMainRecord.SetIsDeleted(aValue: Boolean); var SelfRef : IwbContainerElementRef; i, j : Integer; BasePtr : Pointer; GroupRecord : IwbGroupRecord; Master : IwbMainRecord; MainRecord : IwbMainRecord; SelfIndex : Integer; _File : IwbFile; begin if aValue <> GetIsDeleted then begin if aValue then Delete else begin SelfRef := Self; DoInit; SetModified(True); InvalidateStorage; ReleaseElements; MakeHeaderWriteable; GetFlagsPtr.SetDeleted(False); if Supports(Self.GetContainer, IwbGroupRecord, GroupRecord) then if wbCreateContainedIn and (GroupRecord.GroupType in [1, 4..10]) then with TwbContainedInElement.Create(Self) do begin _AddRef; _Release; end; GroupRecord := nil; BasePtr := dcBasePtr; with TwbRecordHeaderStruct.Create(Self, BasePtr, Pointer( Cardinal(BasePtr) + wbSizeOfMainRecordStruct), mrDef.RecordHeaderStruct, '') do begin Include(dcFlags, dcfDontSave); SetSortOrder(-1); SetMemoryOrder(Low(Integer)); _AddRef; _Release; end; for i := 0 to Pred(mrDef.MemberCount) do if mrDef.Members[i].Required then Assign(i, nil, False); Master := GetMaster; if not Assigned(Master) then Exit; _File := GetFile; SelfIndex := -1; for i := 0 to Pred(Master.OverrideCount) do if Equals(Master.Overrides[i]) then begin SelfIndex := i; Break; end; for i := Pred(SelfIndex) downto 0 do begin MainRecord := Master.Overrides[i]; if not MainRecord.IsDeleted then begin for j := Pred(_File.MasterCount) downto 0 do if MainRecord._File.Equals(_File.Masters[j]) then begin Self.Assign(Low(Integer), MainRecord, False); Exit; end; end; end; if not Master.IsDeleted then Self.Assign(Low(Integer), Master, False); end; end; end; procedure TwbMainRecord.SetIsESM(aValue: Boolean); begin if aValue <> GetIsESM then begin MakeHeaderWriteable; GetFlagsPtr.SetESM(aValue); end; end; procedure TwbMainRecord.SetIsLocalized(aValue: Boolean); begin if aValue <> GetIsLocalized then begin MakeHeaderWriteable; GetFlagsPtr.SetLocalized(aValue); end; end; procedure TwbMainRecord.SetIsInitiallyDisabled(aValue: Boolean); begin if aValue <> GetIsInitiallyDisabled then begin MakeHeaderWriteable; GetFlagsPtr.SetInitiallyDisabled(aValue); end; end; procedure TwbMainRecord.SetIsPersistent(aValue: Boolean); var NeedUpdate: Boolean; begin if aValue <> GetIsPersistent then begin NeedUpdate := CheckChildOfCell; MakeHeaderWriteable; GetFlagsPtr.SetPersistent(aValue); if NeedUpdate then UpdateCellChildGroup; end; end; procedure TwbMainRecord.SetIsVisibleWhenDistant(aValue: Boolean); var NeedUpdate: Boolean; begin if aValue <> GetIsVisibleWhenDistant then begin NeedUpdate := CheckChildOfCell; MakeHeaderWriteable; GetFlagsPtr.SetVisibleWhenDistant(aValue); if NeedUpdate then UpdateCellChildGroup; end; end; procedure TwbMainRecord.SetLoadOrderFormID(aFormID: Cardinal); var _File: IwbFileInternal; FileID: Integer; NewFileID: Integer; i : Integer; Master: IwbMainRecord; begin if GetLoadOrderFormID = aFormID then Exit; _File := GetFile as IwbFileInternal; FileID := aFormID shr 24; NewFileID := -1; if FileID = _File.LoadOrder then NewFileID := _File.MasterCount else begin for i := 0 to Pred(_File.MasterCount) do if _File.Masters[i].LoadOrder = FileID then begin NewFileID := i; Break; end; end; if NewFileID < 0 then raise Exception.Create('FormID ['+IntToHex64(aFormID, 8)+'] belongs to a file that is not available as master to records in ' + _File.Name); aFormID := (aFormID and $00FFFFFF) or (Cardinal(NewFileID) shl 24); if (GetFormID and $00FFFFFF) = (aFormID and $00FFFFFF) then if ((GetFormID shr 24) >= Cardinal(_File.MasterCount)) and ((aFormID shr 24) >= Cardinal(_File.MasterCount)) then begin // we can do this relatively quietly and quickly... if Assigned(mrGroup) then Assert(mrGroup.GroupLabel = mrStruct.mrsFormID); MakeHeaderWriteable; mrStruct.mrsFormID := aFormID; if Assigned(mrGroup) then mrGroup.GroupLabel := aFormID; UpdateInteriorCellGroup; Exit; end; Master := _File.RecordByFormID[aFormID, False]; if Assigned(Master) and ((Master._File as IwbFileInternal) = _File) then raise Exception.Create('FormID ['+IntToHex64(aFormID, 8)+'] is already present in file ' + _File.Name); _File.RemoveMainRecord(Self); if Assigned(mrMaster) then (IwbMainRecord(mrMaster) as IwbMainRecordInternal).RemoveOverride(Self) else if Length(mrOverrides) > 0 then (mrOverrides[0] as IwbMainRecordInternal).YouAreTheMaster(mrOverrides, mrReferencedBy); mrMaster := nil; mrOverrides := nil; mrReferencedBy := nil; mrFixedFormID := 0; mrLoadOrderFormID := 0; Exclude(mrStates, mrsIsInjectedChecked); mrConflictAll := caUnknown; mrConflictThis := ctUnknown; if Assigned(mrGroup) then Assert(mrGroup.GroupLabel = mrStruct.mrsFormID); MakeHeaderWriteable; mrStruct.mrsFormID := aFormID; if Assigned(mrGroup) then mrGroup.GroupLabel := aFormID; UpdateInteriorCellGroup; _File.AddMainRecord(Self); end; procedure TwbMainRecord.SetMaster(const aMaster: IwbMainRecord); begin mrMaster := Pointer(aMaster); if Assigned(mrMaster) then begin Include(mrStates, mrsIsInjectedChecked); Exclude(mrStates, mrsIsInjected); end else Exclude(mrStates, mrsIsInjectedChecked); end; procedure TwbMainRecord.SetNativeValue(const aValue: Variant); begin if not wbEditAllowed then raise Exception.Create(GetName + ' can not be edited.'); if wbDisplayLoadOrderFormID then begin SetLoadOrderFormID(aValue); NotifyChanged(eContainer); end else raise Exception.Create('FormID can only be edited if wbDisplayLoadOrderFormID is active'); end; procedure TwbMainRecord.SetNextEntry(const aEntry: IwbMainRecordEntry); begin Assert(mreHeader.mrehInUse); Assert(mreGeneration = mreHeader.mrehGeneration); mreNext := Pointer(aEntry); end; function TwbMainRecord.SetPosition(const aPosition: TwbVector): Boolean; var Signature : TwbSignature; SelfRef : IwbContainerElementRef; DataRec : IwbContainerElementRef; begin Result := False; Signature := GetSignature; if (Signature <> 'REFR') and (Signature <> 'ACRE') and (Signature <> 'ACHR') and (Signature <> 'PGRE') and (Signature <> 'PMIS') and (Signature <> 'PARW') and {>>> Skyrim <<<} (Signature <> 'PBEA') and {>>> Skyrim <<<} (Signature <> 'PFLA') and {>>> Skyrim <<<} (Signature <> 'PCON') and {>>> Skyrim <<<} (Signature <> 'PBAR') and {>>> Skyrim <<<} (Signature <> 'PHZD') {>>> Skyrim <<<} then Exit; SelfRef := Self; DoInit; if not Supports(GetRecordBySignature('DATA'), IwbContainerElementRef, DataRec) then Exit; if DataRec.ElementCount <> 2 then Exit; with aPosition, (DataRec.Elements[0] as IwbContainerElementRef) do begin if ElementCount <> 3 then Exit; Elements[0].NativeValue := X; Elements[1].NativeValue := Y; Elements[2].NativeValue := Z; end; Result := True; end; procedure TwbMainRecord.SetPrevEntry(const aEntry: IwbMainRecordEntry); begin Assert(mreHeader.mrehInUse); Assert(mreGeneration = mreHeader.mrehGeneration); mrePrev := Pointer(aEntry); end; procedure TwbMainRecord.SetReferencesInjected(aValue: Boolean); begin if aValue then begin Include(mrStates, mrsReferencesInjectedChecked); Include(mrStates, mrsReferencesInjected); end else begin Exclude(mrStates, mrsReferencesInjectedChecked); Exclude(mrStates, mrsReferencesInjected); end; end; function CompareReferencedByFile(Item1, Item2: Pointer): Integer; begin Result := CmpW32(IwbMainRecord(Item1)._File.LoadOrder, IwbMainRecord(Item2)._File.LoadOrder); end; function CompareReferencedBy(Item1, Item2: Pointer): Integer; begin Result := CmpW32(IwbMainRecord(Item1).LoadOrderFormID , IwbMainRecord(Item2).LoadOrderFormID); if Result = 0 then Result := CompareReferencedByFile(Item1, Item2); end; procedure TwbMainRecord.SortReferencedBy; begin Exclude(mrStates, mrsReferencedByUnsorted); if Length(mrReferencedBy) > 1 then wbMergeSort(@mrReferencedBy[0], Length(mrReferencedBy), CompareReferencedBy); end; procedure TwbMainRecord.UpdateCellChildGroup; var OldTypeGroup : IwbGroupRecord; OldChildGroup : IwbGroupRecord; OldCellOwnerGroup : IwbGroupRecord; NewTypeGroup : IwbGroupRecord; TempGroup : IwbGroupRecord; TempGroup2 : IwbGroupRecord; NewChildGroup : IwbGroupRecord; NewCellOwnerGroup : IwbGroupRecord; CorrectGroupType : Integer; i : Integer; OldCell : IwbMainRecord; NewCell : IwbMainRecord; Worldspace : IwbMainRecord; IsExterior : Boolean; SelfRef : IwbElement; Position : TwbVector; GridCell : TwbGridCell; SubBlock : TwbGridCell; Block : TwbGridCell; TempGridCell : TwbGridCell; SubBlockLabel : Cardinal; BlockLabel : Cardinal; begin SelfRef := Self as IwbElement; if not Supports(GetContainer, IwbGroupRecord, OldTypeGroup) then raise Exception.Create(GetName + ' is not contained in a group.'); if not (OldTypeGroup.GroupType in [8, 9, 10]) then raise Exception.Create(GetName + ' is not contained in a group of type "Cell Persistent Childen", "Cell Temporary Children" or "Cell Visible Distant Children"'); if not Supports(OldTypeGroup.Container, IwbGroupRecord, OldChildGroup) then raise Exception.Create(OldTypeGroup.GetName + ' is not contained in a group'); if not (OldChildGroup.GroupType in [6]) then raise Exception.Create(OldTypeGroup.GetName + ' is not contained in a group of type "Cell Children"'); if GetIsPersistent then CorrectGroupType := 8 else if GetIsVisibleWhenDistant and not wbVWDInTemporary then CorrectGroupType := 10 else CorrectGroupType := 9; if OldTypeGroup.GroupType = CorrectGroupType then Exit; OldCell := OldChildGroup.ChildrenOf; if not Assigned(OldCell) then raise Exception.Create(OldChildGroup.GetName + ' can not find its CELL record'); if not OldCell.ElementExists['DATA'] then raise Exception.Create(OldCell.GetName + ' is missing its DATA subrecord'); i := OldCell.GetElementNativeValue('DATA'); IsExterior := (i and 1) = 0; if IsExterior then begin if not Supports(OldCell.Container, IwbGroupRecord, OldCellOwnerGroup) then raise Exception.Create(OldCell.GetName + ' is not contained in a group'); if not (OldCellOwnerGroup.GroupType in [1, 5]) then raise Exception.Create(OldCell.GetName + ' is not contained in a group of type "World Childen" or "Exterior Cell Sub-Block"'); if (CorrectGroupType = 8) then begin if OldCellOwnerGroup.GroupType <> 1 then begin if not Supports(OldCellOwnerGroup.Container, IwbGroupRecord, TempGroup) then raise Exception.Create(OldCellOwnerGroup.GetName + ' is not contained in a group'); if not (TempGroup.GroupType in [4]) then raise Exception.Create(OldCellOwnerGroup.GetName + ' is not contained in a group of type "Exterior Cell Block"'); if not Supports(TempGroup.Container, IwbGroupRecord, NewCellOwnerGroup) then raise Exception.Create(TempGroup.GetName + ' is not contained in a group'); if not (NewCellOwnerGroup.GroupType in [1]) then raise Exception.Create(TempGroup.GetName + ' is not contained in a group of type "World Childen"'); NewCell := nil; for i := 0 to Pred(NewCellOwnerGroup.ElementCount) do if Supports(NewCellOwnerGroup.Elements[i], IwbMainRecord, NewCell) then if NewCell.Signature <> 'CELL' then NewCell := nil else Break; if not Assigned(NewCell) then begin Worldspace := NewCellOwnerGroup.ChildrenOf; if not Assigned(Worldspace) then raise Exception.Create(NewCellOwnerGroup.GetName + ' can not find its WRLD record'); Worldspace := Worldspace.MasterOrSelf; TempGroup := Worldspace.ChildGroup; if not Assigned(TempGroup) then raise Exception.Create(Worldspace.GetName + ' can not find its child group'); for i := 0 to Pred(TempGroup.ElementCount) do if Supports(TempGroup.Elements[i], IwbMainRecord, NewCell) then if NewCell.Signature <> 'CELL' then NewCell := nil else Break; if Assigned(NewCell) then NewCell := wbCopyElementToFile(NewCell, GetFile, False, True, '', '', '') as IwbMainRecord; end; if not Assigned(NewCell) then raise Exception.Create('Could not determine CELL for persistent exterior references'); NewChildGroup := NewCell.EnsureChildGroup; end else NewChildGroup := OldChildGroup; end else begin if OldCellOwnerGroup.GroupType <> 5 then begin if not GetPosition(Position) then raise Exception.Create('Could not determine position of ' + GetName); GridCell := wbPositionToGridCell(Position); SubBlock := wbSubBlockFromGridCell(GridCell); Block := wbBlockFromSubBlock(SubBlock); SubBlockLabel := wbGridCellToGroupLabel(SubBlock); BlockLabel := wbGridCellToGroupLabel(Block); NewCell := nil; TempGroup := nil; for i := 0 to Pred(OldCellOwnerGroup.ElementCount) do if Supports(OldCellOwnerGroup.Elements[i], IwbGroupRecord, TempGroup) then if (TempGroup.GroupType = 4) and (TempGroup.GroupLabel = BlockLabel) then Break else TempGroup := nil; if Assigned(TempGroup) then begin NewCellOwnerGroup := nil; for i := 0 to Pred(TempGroup.ElementCount) do if Supports(TempGroup.Elements[i], IwbGroupRecord, NewCellOwnerGroup) then if (NewCellOwnerGroup.GroupType = 5) and (NewCellOwnerGroup.GroupLabel = SubBlockLabel) then Break else NewCellOwnerGroup := nil; if Assigned(NewCellOwnerGroup) then for i := 0 to Pred(NewCellOwnerGroup.ElementCount) do if Supports(NewCellOwnerGroup.Elements[i], IwbMainRecord, NewCell) then if NewCell.GetGridCell(TempGridCell) and (GridCell.x = TempGridCell.x) and (GridCell.y = TempGridCell.y) then Break else NewCell := nil; end; if not Assigned(NewCell) then begin Worldspace := OldCellOwnerGroup.ChildrenOf; if not Assigned(Worldspace) then raise Exception.Create(OldCellOwnerGroup.GetName + ' can not find its WRLD record'); Worldspace := Worldspace.MasterOrSelf; TempGroup2 := Worldspace.ChildGroup; if not Assigned(TempGroup2) then raise Exception.Create(Worldspace.GetName + ' can not find its child group'); TempGroup := nil; for i := 0 to Pred(TempGroup2.ElementCount) do if Supports(TempGroup2.Elements[i], IwbGroupRecord, TempGroup) then if (TempGroup.GroupType = 4) and (TempGroup.GroupLabel = BlockLabel) then Break else TempGroup := nil; if Assigned(TempGroup) then begin NewCellOwnerGroup := nil; for i := 0 to Pred(TempGroup.ElementCount) do if Supports(TempGroup.Elements[i], IwbGroupRecord, NewCellOwnerGroup) then if (NewCellOwnerGroup.GroupType = 5) and (NewCellOwnerGroup.GroupLabel = SubBlockLabel) then Break else NewCellOwnerGroup := nil; if Assigned(NewCellOwnerGroup) then for i := 0 to Pred(NewCellOwnerGroup.ElementCount) do if Supports(NewCellOwnerGroup.Elements[i], IwbMainRecord, NewCell) then if NewCell.GetGridCell(TempGridCell) and (GridCell.x = TempGridCell.x) and (GridCell.y = TempGridCell.y) then Break else NewCell := nil; end; if Assigned(NewCell) then NewCell := wbCopyElementToFile(NewCell, GetFile, False, True, '', '', '') as IwbMainRecord; end; if not Assigned(NewCell) then raise Exception.Create('Could not determine CELL for persistent exterior references'); NewChildGroup := NewCell.EnsureChildGroup; end else NewChildGroup := OldChildGroup; end; end else NewChildGroup := OldChildGroup; if not Assigned(NewChildGroup) then raise Exception.Create('Could not determine new CELL child group'); NewTypeGroup := nil; for i := 0 to Pred(NewChildGroup.ElementCount) do if Supports(NewChildGroup.Elements[i], IwbGroupRecord, NewTypeGroup) then if NewTypeGroup.GroupType = CorrectGroupType then Break else NewTypeGroup := nil; if not Assigned(NewTypeGroup) then NewTypeGroup := TwbGroupRecord.Create(NewChildGroup, CorrectGroupType, NewChildGroup.ChildrenOf); OldTypeGroup.RemoveElement(SelfRef); if OldTypeGroup.ElementCount = 0 then OldTypeGroup.Remove else (OldTypeGroup as IwbGroupRecordInternal).SetModified(True); NewTypeGroup.AddElement(SelfRef); (NewTypeGroup as IwbGroupRecordInternal).SetModified(True); (NewTypeGroup as IwbGroupRecordInternal).Sort; if OldChildGroup.ElementCount = 0 then OldChildGroup.Remove else (OldChildGroup as IwbGroupRecordInternal).SetModified(True); end; procedure TwbMainRecord.UpdateInteriorCellGroup; var Container : IwbContainer; SubBlockGroup : IwbGroupRecord; BlockGroup : IwbGroupRecord; TopGroup : IwbGroupRecord; NewSubBlockGroup : IwbGroupRecord; NewBlockGroup : IwbGroupRecord; ChildGroup : IwbGroupRecord; i: Integer; s : string; Block : Integer; SubBlock : Integer; SelfRef : IwbElement; begin SelfRef := Self as IwbElement; if GetSignature <> 'CELL' then Exit; if not GetElementExists('DATA') then Exit; i := GetElementNativeValue('DATA'); if (i and 1) <> 1 then Exit; Container := GetContainer; if not Supports(Container, IwbGroupRecord, SubBlockGroup) then raise Exception.Create(GetName + ' is not contained in a group.'); if not (SubBlockGroup.GroupType in [3]) then begin if (SubBlockGroup.GroupType in [0]) and (TwbSignature(SubBlockGroup.GroupLabel) = 'CELL') then begin TopGroup := SubBlockGroup; SubBlockGroup := nil; end else raise Exception.Create(GetName + ' is not contained in a group of type "Interior Cell Sub-Block"'); end else begin if not Supports(SubBlockGroup.Container, IwbGroupRecord, BlockGroup) then raise Exception.Create(SubBlockGroup.GetName + ' is not contained in a group.'); if not (BlockGroup.GroupType in [2]) then raise Exception.Create(GetName + ' is not contained in a group of type "Interior Cell Block"'); if not Supports(BlockGroup.Container, IwbGroupRecord, TopGroup) then raise Exception.Create(TopGroup.GetName + ' is not contained in a group.'); if not (TopGroup.GroupType in [0]) or (TwbSignature(TopGroup.GroupLabel) <> 'CELL') then raise Exception.Create(GetName + ' is not contained in a group of type "Top CELL"'); end; s := '00' + IntToStr(mrStruct.mrsFormID and Cardinal($00FFFFFF)); i := Length(s); if i > 2 then System.Delete(s, 1, i - 2); Block := StrToInt(s[2]); SubBlock := StrToInt(s[1]); NewBlockGroup := BlockGroup; NewSubBlockGroup := SubBlockGroup; if not Assigned(NewBlockGroup) or (NewBlockGroup.GroupLabel <> Block) then begin NewBlockGroup := nil; NewSubBlockGroup := nil; for i := 0 to Pred(TopGroup.ElementCount) do if Supports(TopGroup.Elements[i], IwbGroupRecord, NewBlockGroup) then if NewBlockGroup.GroupLabel = Block then Break else NewBlockGroup := nil; if not Assigned(NewBlockGroup) then begin NewBlockGroup := TwbGroupRecord.Create(TopGroup, 2, Block); (TopGroup as IwbGroupRecordInternal).SetModified(True); (TopGroup as IwbGroupRecordInternal).Sort; end; end; if not Assigned(NewSubBlockGroup) or (NewSubBlockGroup.GroupLabel <> SubBlock) then begin NewSubBlockGroup := nil; for i := 0 to Pred(NewBlockGroup.ElementCount) do if Supports(NewBlockGroup.Elements[i], IwbGroupRecord, NewSubBlockGroup) then if NewSubBlockGroup.GroupLabel = SubBlock then Break else NewSubBlockGroup := nil; if not Assigned(NewSubBlockGroup) then begin NewSubBlockGroup := TwbGroupRecord.Create(NewBlockGroup, 3, SubBlock); (NewBlockGroup as IwbGroupRecordInternal).SetModified(True); (NewBlockGroup as IwbGroupRecordInternal).Sort; end; end; if not Container.Equals(NewSubBlockGroup) then begin ChildGroup := mrGroup; Container.RemoveElement(SelfRef); if Assigned(ChildGroup) then Container.RemoveElement(ChildGroup); NewSubBlockGroup.AddElement(SelfRef); if Assigned(ChildGroup) then NewSubBlockGroup.AddElement(ChildGroup); (NewSubBlockGroup as IwbGroupRecordInternal).SetModified(True); (NewSubBlockGroup as IwbGroupRecordInternal).Sort; if Assigned(SubBlockGroup) then begin if SubBlockGroup.ElementCount = 0 then begin SubBlockGroup.Remove; if Assigned(BlockGroup) then begin if BlockGroup.ElementCount = 0 then begin BlockGroup.Remove; (TopGroup as IwbGroupRecordInternal).SetModified(True); end else (BlockGroup as IwbGroupRecordInternal).SetModified(True); end; end else (SubBlockGroup as IwbGroupRecordInternal).SetModified(True); end; end; end; procedure TwbMainRecord.UpdateRefs; begin if (csRefsBuild in cntStates) then BuildRef; end; procedure TwbMainRecord.WriteToStreamInternal(aStream: TStream; aResetModified: Boolean); var CurrentPosition : Int64; NewPosition : Int64; DataSize : Cardinal; MemoryStream : TMemoryStream; mrs : TwbMainRecordStruct; var SelfRef : IwbContainerElementRef; begin if (esModified in eStates) or wbTestWrite then begin SelfRef := Self as IwbContainerElementRef; DoInit; CurrentPosition := aStream.Position; mrs := mrStruct^; // mrs.mrsFlags2 := 0; aStream.WriteBuffer(mrs, wbSizeOfMainRecordStruct ); if wbForceNewHeader then aStream.WriteBuffer(wbNewHeaderAddon, SizeOf(wbNewHeaderAddon) ); if mrStruct.mrsFlags.IsCompressed then begin MemoryStream := TMemoryStream.Create; try inherited WriteToStreamInternal(MemoryStream, aResetModified); DataSize := MemoryStream.Size; aStream.WriteBuffer(DataSize, SizeOf(DataSize)); MemoryStream.Position := 0; ZCompressStream(MemoryStream, aStream); finally FreeAndNil(MemoryStream); end; end else inherited; NewPosition := aStream.Position; if wbForceNewHeader then DataSize := (NewPosition - CurrentPosition) - wbSizeOfMainRecordStruct - SizeOf(wbNewHeaderAddon) else DataSize := (NewPosition - CurrentPosition) - wbSizeOfMainRecordStruct; aStream.Position := CurrentPosition + 4; aStream.WriteBuffer(DataSize, SizeOf(DataSize)); aStream.Position := NewPosition; end else begin CurrentPosition := aStream.Position; aStream.WriteBuffer(dcBasePtr^, Cardinal(dcEndPtr) - Cardinal(dcBasePtr) ); if CurrentPosition + wbSizeOfMainRecordStruct + mrStruct.mrsDataSize <> aStream.Position then Assert(CurrentPosition + wbSizeOfMainRecordStruct + mrStruct.mrsDataSize <> aStream.Position); end; Exclude(eStates, esUnsaved); if aResetModified then begin Exclude(eStates, esModified); Exclude(eStates, esInternalModified); end; end; procedure TwbMainRecord.YouAreTheMaster(const aOverrides, aReferencedBy: TDynMainRecords); var i: Integer; FileID: Integer; _File: IwbFile; begin Assert(Length(aOverrides) > 0); Assert(Equals(aOverrides[0])); Assert(Assigned(mrMaster)); Assert(Length(mrOverrides) = 0); Assert(Length(mrReferencedBy) = 0); mrMaster := nil; mrOverrides := Copy(aOverrides, 1, High(Integer)); for i := Low(mrOverrides) to High(mrOverrides) do (mrOverrides[i] as IwbMainRecordInternal).SetMaster(Self); mrOverridesSorted := False; mrReferencedBy := aReferencedBy; for i := Low(mrReferencedBy) to High(mrReferencedBy) do (mrReferencedBy[i] as IwbMainRecordInternal).SetReferencesInjected(True); FileID := GetFormID shr 24; _File := GetFile; Assert(FileID < _File.MasterCount); (_File.Masters[FileID] as IwbFileInternal).InjectMainRecord(Self); Include(mrStates, mrsIsInjectedChecked); Include(mrStates, mrsIsInjected); end; procedure TwbMainRecord.YouAreTheMaster(const aOldMaster: IwbMainRecord; const aOverrides, aReferencedBy: TDynMainRecords); var i : Integer; begin Assert(not Assigned(mrMaster)); Assert(Length(mrOverrides) = 0); Assert(Length(mrReferencedBy) = 0); SetLength(mrOverrides, Succ(Length(aOverrides))); mrOverrides[0] := aOldMaster; for i := Low(aOverrides) to High(aOverrides) do mrOverrides[Succ(i)] := aOverrides[i]; for i := Low(mrOverrides) to High(mrOverrides) do (mrOverrides[i] as IwbMainRecordInternal).SetMaster(Self); mrOverridesSorted := False; mrReferencedBy := aReferencedBy; for i := Low(mrReferencedBy) to High(mrReferencedBy) do (mrReferencedBy[i] as IwbMainRecordInternal).SetReferencesInjected(False); Exclude(mrStates, mrsIsInjectedChecked); end; procedure TwbMainRecord.YouGotAMaster(const aMaster: IwbMainRecord); begin Assert(Assigned(aMaster)); Assert(not Assigned(mrMaster)); (aMaster as IwbMainRecordInternal).YouAreTheMaster(Self as IwbMainRecord, mrOverrides, mrReferencedBy); Assert(aMaster.Equals(IwbElement(mrMaster))); mrOverrides := nil; mrReferencedBy := nil; (aMaster._File as IwbFileInternal).RemoveInjectedMainRecord(Self); Include(mrStates, mrsIsInjectedChecked); Exclude(mrStates, mrsIsInjected); end; { TwbSubRecord } function TwbSubRecord.AddIfMissingInternal(const aElement: IwbElement; aAsNew, aDeepCopy: Boolean; const aPrefixRemove, aPrefix, aSuffix: string): IwbElement; var SelfRef : IwbContainerElementRef; i : Integer; s : string; ArrayDef : IwbArrayDef; StructDef : IwbStructDef; IntegerDef : IwbIntegerDef; FlagsDef : IwbFlagsDef; begin if not wbEditAllowed then raise Exception.Create(GetName + ' can not be modified.'); SelfRef := Self as IwbContainerElementRef; DoInit; if Assigned(srValueDef) then begin case srValueDef.DefType of dtRecord, dtSubRecord, dtSubRecordArray, dtSubRecordStruct: Assert(False); dtArray: begin ArrayDef := srValueDef as IwbArrayDef; if srsSorted in srStates then begin Assert(not (srsSortInvalid in srStates)); if FindBySortKey(aElement.SortKey[False], False, i) then begin Result := cntElements[i]; if aDeepCopy then Result.Assign(Low(Integer), aElement, False); Exit; end; end; if srsSorted in srStates then s := '' else s := '#' + IntToStr(Length(cntElements)); if not Supports(aElement, IwbStringListTerminator) then if (csAsCreatedEmpty in cntStates) then begin SetModified(True); Assert(Length(cntElements)=1); Result := cntElements[0]; Exclude(cntStates, csAsCreatedEmpty); try Result.Assign(Low(Integer), aElement, not aDeepCopy); except Result := nil; raise; end; end else case ArrayDef.Element.DefType of dtArray: Result := TwbArray.Create(Self, ArrayDef.Element, aElement, not aDeepCopy, s); dtStruct: Result := TwbStruct.Create(Self, ArrayDef.Element, aElement, not aDeepCopy, s); dtStructChapter: Result := TwbChapter.Create(Self, ArrayDef.Element, aElement, not aDeepCopy, s); dtUnion: Result := TwbUnion.Create(Self, ArrayDef.Element, aElement, not aDeepCopy, s); else Result := TwbValue.Create(Self, ArrayDef.Element, aElement, not aDeepCopy, s); end; CheckCount; CheckTerminator; end; dtStruct, dtStructChapter: begin StructDef := srValueDef as IwbStructDef; Assert(aElement.SortOrder >= 0); Assert(aElement.SortOrder < StructDef.MemberCount ); Assert(Assigned(aElement.ValueDef)); Result := GetElementBySortOrder(aElement.SortOrder); Assert(Assigned(Result)); Assert(StructDef.Members[aElement.SortOrder].CanAssign(Result, Low(Integer), aElement.ValueDef)); if not aDeepCopy then if Supports(Result.ValueDef, IwbIntegerDef, IntegerDef) then if Supports(IntegerDef.Formater[Result], IwbFlagsDef, FlagsDef) then Exit(Result); Result.Assign(Low(Integer), aElement, not aDeepCopy); end; dtUnion: begin inherited AddIfMissingInternal(aElement, aAsNew, aDeepCopy, aPrefixRemove, aPrefix, aSuffix); end; else inherited AddIfMissingInternal(aElement, aAsNew, aDeepCopy, aPrefixRemove, aPrefix, aSuffix); end; end else inherited AddIfMissingInternal(aElement, aAsNew, aDeepCopy, aPrefixRemove, aPrefix, aSuffix); end; function TwbSubRecord.AssignInternal(aIndex: Integer; const aElement: IwbElement; aOnlySK: Boolean): IwbElement; var Element : IwbElement; ArrayDef : IwbArrayDef; Container : IwbContainer; s : string; i : Integer; SelfRef : IwbContainerElementRef; p, q : Pointer; begin Result := nil; if not wbEditAllowed then raise Exception.Create(GetName + ' can not be assigned.'); SelfRef := Self as IwbContainerElementRef; DoInit; if Assigned(srValueDef) then begin case srValueDef.DefType of dtRecord, dtSubRecord, dtSubRecordArray, dtSubRecordStruct: Assert(False); dtArray: begin ArrayDef := srValueDef as IwbArrayDef; if (aIndex = Low(Integer)) and ArrayDef.CanAssign(Self, aIndex, aElement.ValueDef) then begin if aOnlySK then Exit; Container := aElement as IwbContainer; if ArrayDef.IsVariableSize then begin Assert(ArrayDef.ElementCount <= 0); SetModified(True); InvalidateStorage; ReleaseElements; dcDataStorage := nil; dcDataBasePtr := @EmptyPtr; dcDataEndPtr := @EmptyPtr; Exclude(dcFlags, dcfStorageInvalid); if ArrayDef.ElementCount < 0 then RequestStorageChange(p, q, 4); for i := 0 to Pred(Container.ElementCount) do Assign(i, Container.Elements[i], aOnlySK); end else begin Assert(Container.ElementCount = ArrayDef.ElementCount); Assert(GetElementCount = ArrayDef.ElementCount); for i := 0 to Pred(Container.ElementCount) do cntElements[i].Assign(Low(Integer), Container.Elements[i], aOnlySK); end; end else begin if (aIndex >= 0) and (ArrayDef.ElementCount <= 0) and ((aIndex = High(Integer)) or ArrayDef.Element.CanAssign(Self, Low(Integer), aElement.ValueDef)) then begin {add one entry} if srsSorted in srStates then s := '' else s := '#' + IntToStr(Length(cntElements)); if (csAsCreatedEmpty in cntStates) then begin SetModified(True); Assert(Length(cntElements)=1); Result := cntElements[0]; Exclude(cntStates, csAsCreatedEmpty); try Result.Assign(Low(Integer), aElement, aOnlySK); except Result := nil; raise; end; end else begin Element := nil; if not Supports(aElement, IwbStringListTerminator) then case ArrayDef.Element.DefType of dtArray: Element := TwbArray.Create(Self, ArrayDef.Element, aElement, aOnlySK, s); dtStruct: Element := TwbStruct.Create(Self, ArrayDef.Element, aElement, aOnlySK, s); dtStructChapter: Element := TwbChapter.Create(Self, ArrayDef.Element, aElement, aOnlySK, s); dtUnion: Element := TwbUnion.Create(Self, ArrayDef.Element, aElement, aOnlySK, s); else Element := TwbValue.Create(Self, ArrayDef.Element, aElement, aOnlySK, s); end; Result := Element; end; end; end; CheckCount; CheckTerminator; end; else Result := inherited AssignInternal(aIndex, aElement, aOnlySK); end; end else if inherited CanAssignInternal(aIndex, aElement, False) then Result := inherited AssignInternal(aIndex, aElement, aOnlySK); end; procedure TwbSubRecord.BuildRef; var SelfRef: IwbElement; begin SelfRef := Self as IwbContainerElementRef; if Assigned(srDef) then begin DoInit; if Assigned(srValueDef) then srValueDef.BuildRef(GetDataBasePtr, dcDataEndPtr, Self); end; inherited; end; function TwbSubRecord.CanAssignInternal(aIndex: Integer; const aElement: IwbElement; aCheckDontShow: Boolean): Boolean; var ArrayDef: IwbArrayDef; begin Result := False; if not wbEditAllowed then Exit; if Assigned(eContainer) then if not IwbContainer(eContainer).IsElementEditable(Self) then Exit; if aCheckDontShow and GetDontShow then Exit; if srsIsArray in srStates then begin ArrayDef := srValueDef as IwbArrayDef; if not Assigned(aElement) then begin if aIndex = High(Integer) then Result := ArrayDef.ElementCount <= 0; Exit; end; Result := ArrayDef.CanAssign(Self, aIndex, aElement.ValueDef) or ( (ArrayDef.ElementCount <= 0) and ArrayDef.Element.CanAssign(Self, Low(Integer), aElement.ValueDef) ); end else begin if not Assigned(aElement) then Exit; Result := inherited CanAssignInternal(aIndex, aElement, aCheckDontShow); if not Result and Assigned(srDef) then Result := srDef.CanAssign(Self, aIndex, aElement.Def); end; end; function TwbSubRecord.CanContainFormIDs: Boolean; begin Result := Assigned(srDef) and srDef.CanContainFormIDs; end; function TwbSubRecord.CanMoveElement: Boolean; begin Result := srStates * [srsIsArray, srsSorted] = [srsIsArray]; end; function TwbSubRecord.CanElementReset: Boolean; begin // Result := inherited CanElementReset; Result := cntElementRefs < 1; end; procedure TwbSubRecord.CheckCount; var Count : Cardinal; i : Integer; UpdateCount : Integer; begin if not (srArraySizePrefix in [1, 2, 4]) then Exit; if Assigned(dcDataBasePtr) then case srArraySizePrefix of 1: Count := PByte(dcDataBasePtr)^; 2: Count := PWord(dcDataBasePtr)^; 4: Count := PCardinal(dcDataBasePtr)^; else Count := 0; end else Count := 0; if Count <> Length(cntElements) then begin UpdateCount := eUpdateCount; for i := 1 to UpdateCount do EndUpdate; case srArraySizePrefix of 1: PByte(GetDataBasePtr)^ := Length(cntElements); 2: PWord(GetDataBasePtr)^ := Length(cntElements); 4: PCardinal(GetDataBasePtr)^ := Length(cntElements); end; for i := 1 to UpdateCount do BeginUpdate; end; end; procedure TwbSubRecord.CheckTerminator; var i : Integer; ArrayDef : IwbArrayDef; StringDef : IwbStringDef; begin if not Supports(srValueDef, IwbArrayDef, ArrayDef) then Exit; if not ArrayDef.IsVariableSize then Exit; if ArrayDef.Element.DefType <> dtString then Exit; if (not Supports(ArrayDef.Element, IwbStringDef, StringDef)) or (StringDef.GetStringSize>0) then Exit; for i := Low(cntElements) to High(cntElements) do if Supports(cntElements[i], IwbStringListTerminator) then Exit; SetModified(True); InvalidateStorage; TwbStringListTerminator.Create(Self); if srsSorted in srStates then Include(srStates, srsSortInvalid); end; function Resolve(const aValueDef: IwbValueDef; aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): IwbValueDef; var Internal : IwbElementInternal; UnionDef : IwbUnionDef; CanDecide : Boolean; begin Result := aValueDef; Supports(aElement, IwbElementInternal, Internal); CanDecide := False; try while Supports(Result, IwbUnionDef, UnionDef) do begin CanDecide := CanDecide or (Assigned(Internal) and Internal.BeginDecide); if CanDecide then Result := UnionDef.Decide(aBasePtr,aEndPtr,aElement) else break; end; finally if CanDecide then Internal.EndDecide; end; end; function TwbSubRecord.CompareExchangeFormID(aOldFormID, aNewFormID: Cardinal): Boolean; var SelfRef : IwbContainerElementRef; ResolvedDef : IwbValueDef; begin SelfRef := Self as IwbContainerElementRef; Result := False; if not Assigned(srDef) then Exit; DoInit; Result := inherited CompareExchangeFormID(aOldFormID, aNewFormID); ResolvedDef := Resolve(srValueDef, GetDataBasePtr, dcDataEndPtr, Self); if Assigned(ResolvedDef) then Result := ResolvedDef.CompareExchangeFormID(GetDataBasePtr, dcDataEndPtr, Self, aOldFormID, aNewFormID) or Result; end; constructor TwbSubRecord.Create(const aContainer: IwbContainer; const aSubRecordDef: IwbSubRecordDef); var BasePtr : Pointer; EndPtr : Pointer; SaveAsCreatedEmpty : Boolean; begin cntStates := []; srDef := aSubRecordDef; BasePtr := nil; Create(aContainer, BasePtr, nil, nil); DoInit; SaveAsCreatedEmpty := (csAsCreatedEmpty in cntStates); BasePtr := nil; EndPtr := nil; RequestStorageChange(BasePtr, EndPtr, GetDataSize); SetToDefault; if SaveAsCreatedEmpty then Include(cntStates, csAsCreatedEmpty); end; destructor TwbSubRecord.Destroy; begin if not Assigned(dcEndPtr) and Assigned(dcBasePtr) then FreeMem(dcBasePtr, SizeOf(TwbSubRecordHeaderStruct) ); inherited; end; function TwbSubRecord.DoCheckSizeAfterWrite: Boolean; begin Result := True; end; procedure TwbSubRecord.DoInit; begin inherited; if srStates * [srsSorted, srsSortInvalid] = [srsSorted, srsSortInvalid] then begin if Length(cntElements) > 1 then wbMergeSort(@cntElements[0], Length(cntElements), CompareSortKeys); Exclude(srStates, srsSortInvalid); end; end; procedure TwbSubRecord.ElementChanged(const aElement: IwbElement; aContainer: Pointer); begin if srsSorted in srStates then Include(srStates, srsSortInvalid); inherited; end; procedure TwbSubRecord.FindUsedMasters(aMasters: PwbUsedMasters); var SelfRef : IwbContainerElementRef; ResolvedDef : IwbValueDef; begin SelfRef := Self as IwbContainerElementRef; if not Assigned(srDef) then Exit; DoInit; inherited FindUsedMasters(aMasters); ResolvedDef := Resolve(srValueDef, GetDataBasePtr, dcDataEndPtr, Self); if Assigned(ResolvedDef) then ResolvedDef.FindUsedMasters(GetDataBasePtr, dcDataEndPtr, Self, aMasters); end; //var // y: Integer; procedure TwbSubRecord.Init; var ValueDef : IwbValueDef; BasePtr : Pointer; Element : IwbElement; HasUnusedData : Boolean; begin inherited; if GetSkipped then Exit; if not Assigned(srDef) then Exit; BasePtr := GetDataBasePtr; ValueDef := Resolve(srDef.Value, BasePtr, dcDataEndPtr, Self); srArraySizePrefix := 0; if Assigned(ValueDef) then if ValueDef.Name = '' then begin srValueDef := ValueDef; case ValueDef.DefType of dtArray: begin Include(srStates, srsIsArray); if ArrayDoInit(ValueDef, Self, BasePtr, dcDataEndPtr, srArraySizePrefix) then Include(srStates, srsSorted); end; dtStruct, dtStructChapter: StructDoInit(ValueDef, Self, BasePtr, dcDataEndPtr); dtUnion: begin Include(srStates, srsIsUnion); case UnionDoInit(ValueDef, Self, BasePtr, dcDataEndPtr) of ufArray: Include(srStates, srsIsArray); ufSortedArray: begin Include(srStates, srsIsArray); Include(srStates, srsSorted); end; ufFlags: begin Include(srStates, srsIsFlags); Include(srStates, srsSorted); end; end; end; else if ValueDoInit(ValueDef, Self, BasePtr, dcDataEndPtr, Self) then begin Include(srStates, srsIsFlags); Include(srStates, srsSorted); end; end; // flags are already created in the right sort order if srStates * [srsSorted, srsIsFlags] = [srsSorted] then Include(srStates, srsSortInvalid); end else case ValueDef.DefType of dtArray: Element := TwbArray.Create(Self, BasePtr, dcDataEndPtr, ValueDef, ''); dtStruct: Element := TwbStruct.Create(Self, BasePtr, dcDataEndPtr, ValueDef, ''); dtStructChapter: Element := TwbChapter.Create(Self, BasePtr, dcDataEndPtr, ValueDef, ''); dtUnion: Element := TwbUnion.Create(Self, BasePtr, dcDataEndPtr, ValueDef, ''); else Element := TwbValue.Create(Self, BasePtr, dcDataEndPtr, ValueDef, ''); end; if Assigned(dcDataEndPtr) and Assigned(BasePtr) and (BasePtr <> dcDataEndPtr) then begin HasUnusedData := not SameText(ValueDef.Name, 'Unused'); if HasUnusedData and (ValueDef.DefType = dtString) then begin HasUnusedData := False; while Cardinal(BasePtr) < Cardinal(dcDataEndPtr) do begin if PAnsiChar(BasePtr)^ <> #0 then begin HasUnusedData := True; Break; end; Inc(PByte(BasePtr)); end; end; if HasUnusedData then begin if wbReportMode then srDef.HasUnusedData; {$IFDEF DBGSUBREC} if Assigned(wbProgressCallback) then wbProgressCallback(''); {$ENDIF} end; end; srDef.AfterLoad(Self); end; function TwbSubRecord.GetCheck: string; var SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; Result := ''; if not Assigned(srDef) then Exit; DoInit; if Assigned(srValueDef) then Result := srValueDef.Check(GetDataBasePtr, dcDataEndPtr, Self); end; function TwbSubRecord.GetDataPrefixSize: Integer; begin Result := srArraySizePrefix; end; function TwbSubRecord.GetDataSize: Integer; var SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; DoInit; if not Assigned(dcDataBasePtr) and Assigned(srValueDef) and not (dcfStorageInvalid in dcFlags) then begin Result := srValueDef.DefaultSize[nil, nil, Self]; Assert(Result <> Cardinal(High(Integer))); end else Result := inherited GetDataSize; end; function TwbSubRecord.GetDef: IwbNamedDef; begin Result := srDef; end; function TwbSubRecord.GetDisplayName: string; var s : string; SelfRef : IwbContainerElementRef; ValueDef : IwbValueDef; begin SelfRef := Self as IwbContainerElementRef; Result := inherited GetName; ValueDef := Resolve(srValueDef, GetDataBasePtr, GetDataEndPtr, Self); if Assigned(ValueDef) then begin s := ValueDef.Name; if s <> '' then begin Result := Result + ' - ' + s; Exit; end; end; if not Assigned(srDef) then Exit; Result := Result + ' - ' + srDef.GetName; end; function TwbSubRecord.GetEditValue: string; var SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; Result := ''; if not Assigned(srDef) then Exit; DoInit; if Assigned(srValueDef) then Result := srValueDef.EditValue[GetDataBasePtr, dcDataEndPtr, Self] else Result := ''; end; function TwbSubRecord.GetElementType: TwbElementType; begin Result := etSubRecord; end; function TwbSubRecord.GetIsEditable: Boolean; var SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; Result := wbIsInternalEdit; if Result then Exit; if Assigned(eContainer) and not IwbContainer(eContainer).IsElementEditable(SelfRef) then Exit; if not Assigned(srDef) then Exit; DoInit; Result := Assigned(srValueDef) and srValueDef.IsEditable[GetDataBasePtr, dcDataEndPtr, Self]; end; function TwbSubRecord.GetIsInSK(aIndex: Integer): Boolean; var SelfRef : IwbContainerElementRef; HasSortKey : IwbHasSortKeyDef; begin Result := False; SelfRef := Self as IwbContainerElementRef; DoInit; if not Supports(srValueDef, IwbHasSortKeyDef, HasSortKey) then Exit; Result := HasSortKey.IsInSK(aIndex); end; function TwbSubRecord.GetLinksTo: IwbElement; var SelfRef: IwbContainerElementRef; begin Result := nil; SelfRef := Self as IwbContainerElementRef; DoInit; if not Assigned(srValueDef) then Exit; Result := srValueDef.LinksTo[dcDataBasePtr, dcDataEndPtr, Self]; end; function TwbSubRecord.GetName: string; begin Result := inherited GetName; if not Assigned(srDef) then Exit; Result := Result + ' - ' + srDef.GetName; end; function TwbSubRecord.GetNativeValue: Variant; var SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; Result := ''; if not Assigned(srDef) then Exit; DoInit; if Assigned(srValueDef) then Result := srValueDef.NativeValue[GetDataBasePtr, dcDataEndPtr, Self] else Result := Null; end; function TwbSubRecord.GetSorted: Boolean; var EmptyDef : IwbEmptyDef; SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; if not Assigned(srValueDef) then DoInit; Result := (srsSorted in srStates) or (Supports(Resolve(srValueDef, GetDataBasePtr, GetDataEndPtr, Self), IwbEmptyDef, EmptyDef) and EmptyDef.Sorted); end; function TwbSubRecord.GetSortKeyInternal(aExtended: Boolean): string; var SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; Result := GetSignature; if not Assigned(srDef) then Exit; DoInit; if Assigned(srValueDef) then Result := srValueDef.ToSortKey(GetDataBasePtr, dcDataEndPtr, Self, aExtended) else Result := inherited GetSortKeyInternal(aExtended); end; function TwbSubRecord.GetSubRecordHeaderSize: Integer; begin if Assigned(dcBasePtr) then Result := srStruct.srsDataSize else Result := 0; end; function TwbSubRecord.GetValue: string; var // i : Integer; // j : Int64; SelfRef : IwbContainerElementRef; var Def: IwbDef; begin if wbReportMode then begin Def := GetValueDef; if Assigned(Def) then Def.Used; Def := GetDef; if Assigned(Def) then Def.Used; end; SelfRef := Self as IwbContainerElementRef; Result := ''; if not Assigned(srDef) then Exit; DoInit; if Assigned(srValueDef) then Result := srValueDef.ToString(GetDataBasePtr, dcDataEndPtr, Self); end; function TwbSubRecord.GetValueDef: IwbValueDef; var SelfRef : IwbContainerElementRef; begin if not Assigned(srValueDef) or ((srsIsUnion in srStates) and not (csInit in cntStates)) then begin SelfRef := Self as IwbContainerElementRef; DoInit; end; Result := srValueDef; end; procedure TwbSubRecord.InformStorage(var aBasePtr: Pointer; aEndPtr: Pointer); var SizeNeeded : Cardinal; SizeAvailable : Cardinal; BasePtr : Pointer; begin Assert(Assigned(dcBasePtr)); Assert(Assigned(dcEndPtr)); SizeNeeded := SizeOf(TwbSubRecordHeaderStruct); SizeAvailable := Cardinal( aEndPtr ) - Cardinal( aBasePtr ); Assert( SizeAvailable >= SizeNeeded ); BasePtr := aBasePtr; Inc(PByte(aBasePtr), SizeNeeded ); inherited; Assert(srStruct.srsDataSize = Cardinal( dcDataEndPtr ) - Cardinal( dcDataBasePtr )); dcBasePtr := BasePtr; dcEndPtr := dcDataEndPtr; end; procedure TwbSubRecord.InitDataPtr; var lDataSize : Cardinal; LastRecord : IwbElement; Container : IwbContainer; begin if Assigned(dcBasePtr) then begin dcDataBasePtr := Pointer( Cardinal( dcBasePtr ) + SizeOf(TwbSubRecordHeaderStruct) ); lDataSize := srStruct.srsDataSize; if lDataSize = 0 then begin Container := GetContainer; if Assigned(Container) and (Container.ElementCount >= 2) then begin LastRecord := Container.Elements[Container.ElementCount - 2]; if Assigned(LastRecord) and (LastRecord.ElementType = etSubRecord) then with LastRecord as IwbSubRecord do if Signature = 'XXXX' then begin lDataSize := PCardinal(DataBasePtr)^; Container.RemoveElement(Container.ElementCount - 2); end; end; end; dcDataEndPtr := Pointer( Cardinal( dcDataBasePtr ) + lDataSize ); dcEndPtr := dcDataEndPtr; end else begin GetMem(dcBasePtr, SizeOf(TwbSubRecordHeaderStruct) ); if Assigned(srDef) then srStruct.srsSignature := srDef.DefaultSignature else srStruct.srsSignature := NONE; end; end; function TwbSubRecord.IsElementRemoveable(const aElement: IwbElement): Boolean; begin Result := IsElementEditable(aElement) and (srsIsArray in srStates) and Assigned(srValueDef) and ((srValueDef as IwbArrayDef).ElementCount <= 0) and (Length(cntElements)>1); end; function TwbSubRecord.IsFlags: Boolean; begin Result := srsIsFlags in srStates; end; procedure TwbSubRecord.MasterCountUpdated(aOld, aNew: Byte); var SelfRef : IwbContainerElementRef; ResolvedDef : IwbValueDef; begin SelfRef := Self as IwbContainerElementRef; if not Assigned(srDef) then Exit; DoInit; inherited MasterCountUpdated(aOld, aNew); ResolvedDef := Resolve(srValueDef, GetDataBasePtr, dcDataEndPtr, Self); if Assigned(ResolvedDef) then ResolvedDef.MasterCountUpdated(GetDataBasePtr, dcDataEndPtr, Self, aOld, aNew); end; procedure TwbSubRecord.MasterIndicesUpdated(const aOld, aNew: TBytes); var SelfRef : IwbContainerElementRef; ResolvedDef : IwbValueDef; begin SelfRef := Self as IwbContainerElementRef; if not Assigned(srDef) then Exit; DoInit; inherited MasterIndicesUpdated(aOld, aNew); ResolvedDef := Resolve(srValueDef, GetDataBasePtr, dcDataEndPtr, Self); if Assigned(ResolvedDef) then ResolvedDef.MasterIndicesUpdated(GetDataBasePtr, dcDataEndPtr, Self, aOld, aNew); end; procedure TwbSubRecord.MergeStorageInternal(var aBasePtr: Pointer; aEndPtr: Pointer); var SizeNeeded : Cardinal; SizeAvailable : Cardinal; BasePtr : Pointer; begin Assert(Assigned(dcBasePtr)); SizeNeeded := SizeOf(TwbSubRecordHeaderStruct); SizeAvailable := Cardinal( aEndPtr ) - Cardinal( aBasePtr ); Assert( SizeAvailable >= SizeNeeded ); BasePtr := aBasePtr; Move(dcBasePtr^, aBasePtr^, SizeNeeded); Inc(PByte(aBasePtr), SizeNeeded ); inherited; if not Assigned(dcEndPtr) then FreeMem(dcBasePtr, SizeNeeded); dcBasePtr := BasePtr; dcEndPtr := dcDataEndPtr; srStruct.srsDataSize := Cardinal( dcDataEndPtr ) - Cardinal( dcDataBasePtr ); end; procedure TwbSubRecord.PrepareSave; begin if wbDelayLoadRecords then if not (esModified in eStates) then Exit; CheckCount; CheckTerminator; inherited; UpdateStorageFromElements; end; function TwbSubRecord.RemoveInjected(aCanRemove: Boolean): Boolean; var i : Integer; SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; DoInit; Result := False; if {(GetSignature = 'PTDT') or} (GetSignature = 'PLDT') then begin Assert(GetElementCount = 3); Result := GetElement(1).ReferencesInjected; if Result then begin GetElement(0).EditValue := '2'; GetElement(1).EditValue := '00000000'; Result := False; end; end else begin for i := High(cntElements) downto Low(cntElements) do if cntElements[i].CanContainFormIDs then begin Result := cntElements[i].RemoveInjected(True) or Result; if Result and aCanRemove then Break; end; end; if Result and aCanRemove and GetIsRemoveable then begin Result := False; Remove; end; end; procedure TwbSubRecord.Reset; begin ReleaseElements; srValueDef := nil; srStates := srStates - [srsIsArray, srsIsFlags, srsSorted, srsSortInvalid]; inherited; end; procedure TwbSubRecord.ScanData; begin { nothing } end; procedure TwbSubRecord.SetDef(const aDef: IwbSubRecordDef); begin srDef := aDef; DoReset(True); end; procedure TwbSubRecord.SetEditValue(const aValue: string); var SelfRef : IwbContainerElementRef; OldValue, NewValue: Variant; begin if not wbEditAllowed then raise Exception.Create(GetName + ' can not be edited.'); SelfRef := Self as IwbContainerElementRef; if not Assigned(srDef) then if aValue <> '' then raise Exception.Create(GetName + ' can not be edited') else Exit; DoInit; if GetEditValue <> aValue then begin if Assigned(srValueDef) then begin OldValue := GetNativeValue; srValueDef.EditValue[GetDataBasePtr, dcDataEndPtr, Self] := aValue; NewValue := GetNativeValue; DoAfterSet(OldValue, NewValue); end else raise Exception.Create(GetName + ' can not be edited'); if (srsIsFlags in srStates) and (csInit in cntStates) then begin Reset; Init; end; NotifyChanged(eContainer); end; end; procedure TwbSubRecord.SetModified(aValue: Boolean); begin inherited; if aValue and (srsSorted in srStates) then Include(srStates, srsSortInvalid); end; procedure TwbSubRecord.SetNativeValue(const aValue: Variant); var OldValue, NewValue: Variant; SelfRef : IwbContainerElementRef; begin if not wbEditAllowed then raise Exception.Create(GetName + ' can not be edited.'); SelfRef := Self as IwbContainerElementRef; if not Assigned(srDef) then raise Exception.Create(GetName + ' can not be edited'); DoInit; if Assigned(srValueDef) then begin OldValue := GetNativeValue; srValueDef.NativeValue[GetDataBasePtr, dcDataEndPtr, Self] := aValue; NewValue := GetNativeValue; DoAfterSet(OldValue, NewValue); end else raise Exception.Create(GetName + ' can not be edited'); if (srsIsFlags in srStates) and (csInit in cntStates) then begin Reset; Init; end; NotifyChanged(eContainer); end; procedure TwbSubRecord.SetToDefaultInternal; var SelfRef: IwbContainerElementRef; BasePtr, EndPtr: Pointer; begin SelfRef := Self as IwbContainerElementRef; if csInit in cntStates then DoReset(True); BasePtr := nil; EndPtr := nil; dcDataBasePtr := nil; dcDataEndPtr := nil; dcDataStorage := nil; DoInit; if Assigned(srValueDef) then RequestStorageChange(BasePtr, EndPtr, srValueDef.DefaultSize[nil, nil, Self]); inherited; end; function TwbSubRecord.srStruct: PwbSubRecordHeaderStruct; begin Result := PwbSubRecordHeaderStruct(dcBasePtr); end; procedure TwbSubRecord.WriteToStreamInternal(aStream: TStream; aResetModified: Boolean); var CurrentPosition : Int64; NewPosition : Int64; BigDataSize : Cardinal; SubHeader : TwbSubRecordHeaderStruct; SelfRef : IwbContainerElementRef; begin if (esModified in eStates) or wbTestWrite or (srStruct.srsDataSize = 0) then begin SelfRef := Self as IwbContainerElementRef; DoInit; BigDataSize := GetDataSize; if BigDataSize > High(Word) then begin SubHeader.srsSignature := 'XXXX'; SubHeader.srsDataSize := SizeOf(Cardinal); aStream.WriteBuffer(SubHeader, SizeOf(TwbSubRecordHeaderStruct) ); aStream.WriteBuffer(BigDataSize, SizeOf(BigDataSize) ); SubHeader.srsSignature := srStruct.srsSignature; SubHeader.srsDataSize := 0; end else begin SubHeader.srsSignature := srStruct.srsSignature; SubHeader.srsDataSize := BigDataSize; end; aStream.WriteBuffer(SubHeader, SizeOf(TwbSubRecordHeaderStruct) ); CurrentPosition := aStream.Position; inherited; NewPosition := aStream.Position; if BigDataSize <> NewPosition - CurrentPosition then Assert(BigDataSize = NewPosition - CurrentPosition ); end else begin aStream.WriteBuffer(dcBasePtr^, SizeOf(TwbSubRecordHeaderStruct) ); CurrentPosition := aStream.Position; inherited; if CurrentPosition + srStruct.srsDataSize <> aStream.Position then Assert(CurrentPosition + srStruct.srsDataSize = aStream.Position); end; Exclude(eStates, esUnsaved); if aResetModified then begin Exclude(eStates, esModified); Exclude(eStates, esInternalModified); end; end; { TwbGroupRecord } function TwbGroupRecord.Add(const aName: string; aSilent: Boolean): IwbElement; var Signature : TwbSignature; FormID : Cardinal; _File : IwbFile; MainRecord: IwbMainRecord; IsInjected: Boolean; Group : IwbGroupRecord; i : Integer; SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; Result := nil; if Length(aName) < 4 then Exit; Signature := StrToSignature(aName); case grStruct.grsGroupType of 0: if Signature <> TwbSignature(grStruct.grsLabel) then Exit; 1: if (Signature <> 'ROAD') and (Signature <> 'CELL') then Exit; 7: if (Signature <> 'INFO') then Exit; 6: begin Group := nil; for i := 0 to GetElementCount do if Supports(GetElement(i), IwbGroupRecord, Group) then if (Group.GroupType = 9) and (Group.GroupLabel = GetGroupLabel) then Break else Group := nil; if not Assigned(Group) then Group := TwbGroupRecord.Create(Self, 9, GetGroupLabel); Result := Group.Add(aName, aSilent); Exit; end; 8: if (Signature <> 'REFR') and (Signature <> 'ACRE') and (Signature <> 'PGRE') and (Signature <> 'PMIS') and (Signature <> 'PARW') and {>>> Skyrim <<<} (Signature <> 'PBEA') and {>>> Skyrim <<<} (Signature <> 'PFLA') and {>>> Skyrim <<<} (Signature <> 'PCON') and {>>> Skyrim <<<} (Signature <> 'PBAR') and {>>> Skyrim <<<} (Signature <> 'PHZD') and {>>> Skyrim <<<} (Signature <> 'ACHR') then Exit; 9: if (Signature <> 'LAND') and (Signature <> 'PGRD') and (Signature <> 'NAVM') and (Signature <> 'REFR') and (Signature <> 'PGRE') and (Signature <> 'PMIS') and (Signature <> 'PARW') and {>>> Skyrim <<<} (Signature <> 'PBEA') and {>>> Skyrim <<<} (Signature <> 'PFLA') and {>>> Skyrim <<<} (Signature <> 'PCON') and {>>> Skyrim <<<} (Signature <> 'PBAR') and {>>> Skyrim <<<} (Signature <> 'PHZD') and {>>> Skyrim <<<} (Signature <> 'ACRE') and (Signature <> 'ACHR') then Exit; 10: if (not wbVWDAsQuestChildren and (Signature <> 'REFR')) or (wbVWDAsQuestChildren and not ((Signature = 'REFR') or (Signature = 'DLBR') or (Signature = 'DIAL') or (Signature = 'SCEN'))) then Exit; else Exit; end; _File := GetFile; if not Assigned(_File) then Exit; if aSilent then FormID := _File.NewFormID else FormID := _File.LoadOrderFormIDtoFileFormID(wbGetFormID(Self)); if FormID = 0 then Exit; IsInjected := False; MainRecord := _File.RecordByFormID[FormID, True]; if Assigned(MainRecord) then begin if _File.Equals(MainRecord._File) then raise Exception.Create('FormID ['+IntToHex64(FormID, 8)+'] is already defined in file "'+_File.Name+'"'); IsInjected := (FormID shr 24) = Cardinal(_File.MasterCount); if MainRecord.Signature <> Signature then raise Exception.Create('Existing record '+MainRecord.Name+' has different signature'); end; Result := TwbMainRecord.Create(Self, Signature, FormID); if IsInjected then (MainRecord as IwbMainRecordInternal).YouGotAMaster(Result as IwbMainRecord); if csRefsBuild in _File.ContainerStates then Result.BuildRef; end; function RemovePrefix(const s, aPrefix: string): string; begin if SameText(Copy(s, 1, Length(aPrefix)), aPrefix) then Result := Copy(s, Succ(Length(aPrefix)), High(Integer)) else Result := s; end; procedure TwbGroupRecord.AddElement(const aElement: IwbElement); var DialGroup : IwbGroupRecord; Container : IwbContainer; DialRec : IwbMainRecord; i : Integer; begin if esUnsaved in aElement.ElementStates then // Let's not penalised too much loading time. if ((TwbSignature(grStruct.grsLabel) = 'DIAL') or wbVWDAsQuestChildren) then // Issue 86: https://code.google.com/p/skyrim-plugin-decoding-project/issues/detail?id=86 if Supports(aElement, IwbGroupRecord, DialGroup) then // The DIAL GRUP must immediatly follow corresponding DIAL MainRecord. if DialGroup.GroupType = 7 then // Let's hope nobody messes up the groupType if Supports(Self, IwbContainer, Container) then if Container.ElementCount > 0 then for i := 0 to Pred(Container.ElementCount) - 1 do // If we are reading the plugins and at the end don't bother moving data around. if Supports(Container.Elements[i], IwbMainRecord, DialRec) then if DialRec.Signature = 'DIAL' then if DialRec.FormID = DialGroup.GroupLabel then begin InsertElement(i+1, aElement); Exit; end; inherited; end; function TwbGroupRecord.AddIfMissingInternal(const aElement: IwbElement; aAsNew, aDeepCopy : Boolean; const aPrefixRemove, aPrefix, aSuffix: string): IwbElement; var MainRecord : IwbMainRecord; MainRecord2 : IwbMainRecord; FormID : Cardinal; i : Integer; SelfRef : IwbContainerElementRef; s : string; GroupRecord : IwbGroupRecord; GroupRecord2 : IwbGroupRecord; begin Result := nil; SelfRef := Self as IwbContainerElementRef; case grStruct.grsGroupType of 0: begin if TwbSignature(grStruct.grsLabel) = 'DIAL' then begin if Supports(aElement, IwbGroupRecord, GroupRecord) then begin if GroupRecord.GroupType <> 7 then raise Exception.Create('Can''t add '+GroupRecord.Name+' to top level group with signature ' + TwbSignature(grStruct.grsLabel)); MainRecord := GroupRecord.ChildrenOf; if not Assigned(MainRecord) then raise Exception.Create('Can''t find record for '+ GroupRecord.Name); MainRecord := MainRecord.HighestOverrideOrSelf[GetFile.LoadOrder]; MainRecord := AddIfMissingInternal(MainRecord, aAsNew, True, aPrefixRemove, aPrefix, aSuffix) as IwbMainRecord; Assert(Assigned(MainRecord)); Result := MainRecord.ChildGroup; if not Assigned(Result) then Result := TwbGroupRecord.Create(Self, 7, MainRecord); GroupRecord2 := Result as IwbGroupRecord; if aDeepCopy then for i := 0 to Pred(GroupRecord.ElementCount) do GroupRecord2.AddIfMissing(GroupRecord.Elements[i], aAsNew, aDeepCopy, aPrefixRemove, aPrefix, aSuffix); Exit; end; end else if TwbSignature(grStruct.grsLabel) = 'CELL' then begin if Supports(aElement, IwbGroupRecord, GroupRecord) then begin if GroupRecord.GroupType <> 2 then raise Exception.Create('Can''t add '+GroupRecord.Name+' to top level group with signature ' + TwbSignature(grStruct.grsLabel)); if GroupRecord.GroupLabel > 9 then raise Exception.Create('Can''t add '+GroupRecord.Name+' to top level group with signature ' + TwbSignature(grStruct.grsLabel)); for i := 0 to Pred(GetElementCount) do if Supports(GetElement(i), IwbGroupRecord, GroupRecord2) then begin if (GroupRecord2.GroupType = 2) and (GroupRecord2.GroupLabel = GroupRecord.GroupLabel) then begin Result := GroupRecord2; break; end; end; if not Assigned(Result) then Result := TwbGroupRecord.Create(Self, 2, GroupRecord.GroupLabel); GroupRecord2 := Result as IwbGroupRecord; if aDeepCopy then for i := 0 to Pred(GroupRecord.ElementCount) do GroupRecord2.AddIfMissing(GroupRecord.Elements[i], aAsNew, aDeepCopy, aPrefixRemove, aPrefix, aSuffix); Exit; end; end else if TwbSignature(grStruct.grsLabel) = 'WRLD' then begin if Supports(aElement, IwbGroupRecord, GroupRecord) then begin if GroupRecord.GroupType <> 1 then raise Exception.Create('Can''t add '+GroupRecord.Name+' to top level group with signature ' + TwbSignature(grStruct.grsLabel)); MainRecord := GroupRecord.ChildrenOf; if not Assigned(MainRecord) then raise Exception.Create('Can''t find record for '+ GroupRecord.Name); MainRecord := MainRecord.HighestOverrideOrSelf[GetFile.LoadOrder]; MainRecord := AddIfMissingInternal(MainRecord, aAsNew, True, aPrefixRemove, aPrefix, aSuffix) as IwbMainRecord; Assert(Assigned(MainRecord)); Result := MainRecord.ChildGroup; if not Assigned(Result) then Result := TwbGroupRecord.Create(Self, 1, MainRecord); GroupRecord2 := Result as IwbGroupRecord; if aDeepCopy then for i := 0 to Pred(GroupRecord.ElementCount) do GroupRecord2.AddIfMissing(GroupRecord.Elements[i], aAsNew, aDeepCopy, aPrefixRemove, aPrefix, aSuffix); Exit; end; end else if wbVWDAsQuestChildren and (TwbSignature(grStruct.grsLabel) = 'QUST') then begin if Supports(aElement, IwbGroupRecord, GroupRecord) then begin if GroupRecord.GroupType <> 10 then raise Exception.Create('Can''t add '+GroupRecord.Name+' to top level group with signature ' + TwbSignature(grStruct.grsLabel)); MainRecord := GroupRecord.ChildrenOf; if not Assigned(MainRecord) then raise Exception.Create('Can''t find record for '+ GroupRecord.Name); MainRecord := MainRecord.HighestOverrideOrSelf[GetFile.LoadOrder]; MainRecord := AddIfMissingInternal(MainRecord, aAsNew, True, aPrefixRemove, aPrefix, aSuffix) as IwbMainRecord; Assert(Assigned(MainRecord)); Result := MainRecord.ChildGroup; if not Assigned(Result) then Result := TwbGroupRecord.Create(Self, 10, MainRecord); GroupRecord2 := Result as IwbGroupRecord; if aDeepCopy then for i := 0 to Pred(GroupRecord.ElementCount) do GroupRecord2.AddIfMissing(GroupRecord.Elements[i], aAsNew, aDeepCopy, aPrefixRemove, aPrefix, aSuffix); Exit; end; end; if not Supports(aElement, IwbMainRecord, MainRecord) then raise Exception.Create('Only main records can be added to top level groups'); if MainRecord.Signature <> TwbSignature(grStruct.grsLabel) then raise Exception.Create('Can''t add main record with signature '+MainRecord.Signature+' to top level group with signature ' + TwbSignature(grStruct.grsLabel)); if aAsNew then FormID := GetFile.NewFormID else begin FormID := GetFile.LoadOrderFormIDtoFileFormID(MainRecord.LoadOrderFormID); for i := Low(cntElements) to High(cntElements) do if Supports(cntElements[i], IwbMainRecord, MainRecord2) then if MainRecord2.FixedFormID = FormID then begin Result := MainRecord2; exit; end; end; Result := TwbMainRecord.Create(Self, MainRecord.Signature, FormID); if aDeepCopy then begin Result.Assign(Low(Integer), aElement, False); if (aPrefix <> '') or (aSuffix <> '') then with Result as IwbMainRecord do begin s := EditorID; s := RemovePrefix(s, aPrefixRemove); if s <> '' then EditorID := aPrefix + s + aSuffix; end; end; if not aAsNew and MainRecord.IsMaster and (Result._File.LoadOrder <= MainRecord._File.LoadOrder) then if Supports(Result, IwbMainRecord, MainRecord2) then (MainRecord as IwbMainRecordInternal).YouGotAMaster(MainRecord2); if Assigned(Result) and (csRefsBuild in Result._File.ContainerStates) then Result.BuildRef; end; 1: begin if Supports(aElement, IwbGroupRecord, GroupRecord) then begin if GroupRecord.GroupType = 4 then begin for i := 0 to Pred(GetElementCount) do if Supports(GetElement(i), IwbGroupRecord, GroupRecord2) then begin if (GroupRecord2.GroupType = GroupRecord.GroupType) and (GroupRecord2.GroupLabel = GroupRecord.GroupLabel) then begin Result := GroupRecord2; break; end; end; if not Assigned(Result) then Result := TwbGroupRecord.Create(Self, 4, GroupRecord.GroupLabel); GroupRecord2 := Result as IwbGroupRecord; if aDeepCopy then for i := 0 to Pred(GroupRecord.ElementCount) do GroupRecord2.AddIfMissing(GroupRecord.Elements[i], aAsNew, aDeepCopy, aPrefixRemove, aPrefix, aSuffix); Exit; end; if GroupRecord.GroupType <> 6 then raise Exception.Create('Can''t add '+GroupRecord.Name+' to top level group with signature ' + TwbSignature(grStruct.grsLabel)); MainRecord := GroupRecord.ChildrenOf; if not Assigned(MainRecord) then raise Exception.Create('Can''t find record for '+ GroupRecord.Name); MainRecord := MainRecord.HighestOverrideOrSelf[GetFile.LoadOrder]; MainRecord := AddIfMissingInternal(MainRecord, aAsNew, True, aPrefixRemove, aPrefix, aSuffix) as IwbMainRecord; Assert(Assigned(MainRecord)); Result := MainRecord.ChildGroup; if not Assigned(Result) then Result := TwbGroupRecord.Create(Self, 6, MainRecord); GroupRecord2 := Result as IwbGroupRecord; if aDeepCopy then for i := 0 to Pred(GroupRecord.ElementCount) do GroupRecord2.AddIfMissing(GroupRecord.Elements[i], aAsNew, aDeepCopy, aPrefixRemove, aPrefix, aSuffix); Exit; end; if not Supports(aElement, IwbMainRecord, MainRecord) then raise Exception.Create('Only main records can be added to ' + GetName); if (MainRecord.Signature <> 'CELL') and (MainRecord.Signature <> 'ROAD') then raise Exception.Create('Can''t add main record with signature '+MainRecord.Signature+' to ' + GetName); if aAsNew then raise Exception.Create('Can''t copy record '+MainRecord.Name+' as new record.') else begin FormID := GetFile.LoadOrderFormIDtoFileFormID(MainRecord.LoadOrderFormID); for i := Low(cntElements) to High(cntElements) do if Supports(cntElements[i], IwbMainRecord, MainRecord2) then if MainRecord2.FixedFormID = FormID then begin Result := MainRecord2; exit; end; end; Result := TwbMainRecord.Create(Self, MainRecord.Signature, FormID); if aDeepCopy then begin Result.Assign(Low(Integer), aElement, False); if (aPrefix <> '') or (aSuffix <> '') then with Result as IwbMainRecord do begin s := EditorID; s := RemovePrefix(s, aPrefixRemove); if s <> '' then EditorID := aPrefix + s + aSuffix; end; end; if not aAsNew and MainRecord.IsMaster and (Result._File.LoadOrder <= MainRecord._File.LoadOrder) then if Supports(Result, IwbMainRecord, MainRecord2) then (MainRecord as IwbMainRecordInternal).YouGotAMaster(MainRecord2); if Assigned(Result) and (csRefsBuild in Result._File.ContainerStates) then Result.BuildRef; end; 2, 4: begin if Supports(aElement, IwbGroupRecord, GroupRecord) then begin if GroupRecord.GroupType <> grStruct.grsGroupType + 1 then raise Exception.Create('Can''t add '+GroupRecord.Name+' to ' + GetName); for i := 0 to Pred(GetElementCount) do if Supports(GetElement(i), IwbGroupRecord, GroupRecord2) then begin if (GroupRecord2.GroupType = GroupRecord.GroupType) and (GroupRecord2.GroupLabel = GroupRecord.GroupLabel) then begin Result := GroupRecord2; break; end; end; if not Assigned(Result) then Result := TwbGroupRecord.Create(Self, GroupRecord.GroupType, GroupRecord.GroupLabel); GroupRecord2 := Result as IwbGroupRecord; if aDeepCopy then for i := 0 to Pred(GroupRecord.ElementCount) do GroupRecord2.AddIfMissing(GroupRecord.Elements[i], aAsNew, aDeepCopy, aPrefixRemove, aPrefix, aSuffix); Exit; end; raise Exception.Create('Can''t add ' + aElement.Name + ' to ' + GetName); end; 3, 5: begin if Supports(aElement, IwbGroupRecord, GroupRecord) then begin if GroupRecord.GroupType <> 6 then raise Exception.Create('Can''t add '+GroupRecord.Name+' to top level group with signature ' + TwbSignature(grStruct.grsLabel)); MainRecord := GroupRecord.ChildrenOf; if not Assigned(MainRecord) then raise Exception.Create('Can''t find record for '+ GroupRecord.Name); MainRecord := MainRecord.HighestOverrideOrSelf[GetFile.LoadOrder]; MainRecord := AddIfMissingInternal(MainRecord, aAsNew, True, aPrefixRemove, aPrefix, aSuffix) as IwbMainRecord; Assert(Assigned(MainRecord)); Result := MainRecord.ChildGroup; if not Assigned(Result) then Result := TwbGroupRecord.Create(Self, 6, MainRecord); GroupRecord2 := Result as IwbGroupRecord; if aDeepCopy then for i := 0 to Pred(GroupRecord.ElementCount) do GroupRecord2.AddIfMissing(GroupRecord.Elements[i], aAsNew, aDeepCopy, aPrefixRemove, aPrefix, aSuffix); Exit; end; if not Supports(aElement, IwbMainRecord, MainRecord) then raise Exception.Create('Only main records can be added to ' + GetName); if MainRecord.Signature <> 'CELL' then raise Exception.Create('Can''t add main record with signature '+MainRecord.Signature+' to ' + GetName); if aAsNew then raise Exception.Create('Can''t copy record '+MainRecord.Name+' as new record.') else begin FormID := GetFile.LoadOrderFormIDtoFileFormID(MainRecord.LoadOrderFormID); for i := Low(cntElements) to High(cntElements) do if Supports(cntElements[i], IwbMainRecord, MainRecord2) then if MainRecord2.FixedFormID = FormID then begin Result := MainRecord2; exit; end; end; Result := TwbMainRecord.Create(Self, MainRecord.Signature, FormID); if aDeepCopy then begin Result.Assign(Low(Integer), aElement, False); if (aPrefix <> '') or (aSuffix <> '') then with Result as IwbMainRecord do begin s := EditorID; s := RemovePrefix(s, aPrefixRemove); if s <> '' then EditorID := aPrefix + s + aSuffix; end; end; if not aAsNew and MainRecord.IsMaster and (Result._File.LoadOrder <= MainRecord._File.LoadOrder) then if Supports(Result, IwbMainRecord, MainRecord2) then (MainRecord as IwbMainRecordInternal).YouGotAMaster(MainRecord2); if Assigned(Result) and (csRefsBuild in Result._File.ContainerStates) then Result.BuildRef; end; 6: begin if Supports(aElement, IwbGroupRecord, GroupRecord) then begin if not (GroupRecord.GroupType in [8, 9, 10]) then raise Exception.Create('Can''t add '+GroupRecord.Name+' to ' + GetName); for i := 0 to Pred(GetElementCount) do if Supports(GetElement(i), IwbGroupRecord, GroupRecord2) then begin if GroupRecord2.GroupType = GroupRecord.GroupType then begin Result := GroupRecord2; break; end; end; if not Assigned(Result) then Result := TwbGroupRecord.Create(Self, GroupRecord.GroupType, Self.GetChildrenOf); GroupRecord2 := Result as IwbGroupRecord; if aDeepCopy then for i := 0 to Pred(GroupRecord.ElementCount) do GroupRecord2.AddIfMissing(GroupRecord.Elements[i], aAsNew, aDeepCopy, aPrefixRemove, aPrefix, aSuffix); Exit; end; raise Exception.Create('Can''t add ' + aElement.Name + ' to ' + GetName); end; 7: begin if not Supports(aElement, IwbMainRecord, MainRecord) then raise Exception.Create('Only main records can be added to ' + GetName); if MainRecord.Signature <> 'INFO' then raise Exception.Create('Can''t add main record with signature '+MainRecord.Signature+' to ' + GetName); if aAsNew then FormID := GetFile.NewFormID else begin FormID := GetFile.LoadOrderFormIDtoFileFormID(MainRecord.LoadOrderFormID); for i := Low(cntElements) to High(cntElements) do if Supports(cntElements[i], IwbMainRecord, MainRecord2) then if MainRecord2.FixedFormID = FormID then begin Result := MainRecord2; exit; end; end; Result := TwbMainRecord.Create(Self, MainRecord.Signature, FormID); if aDeepCopy then begin Result.Assign(Low(Integer), aElement, False); if (aPrefix <> '') or (aSuffix <> '') then with Result as IwbMainRecord do begin s := EditorID; s := RemovePrefix(s, aPrefixRemove); if s <> '' then EditorID := aPrefix + s + aSuffix; end; end; if not aAsNew and MainRecord.IsMaster and (Result._File.LoadOrder <= MainRecord._File.LoadOrder) then if Supports(Result, IwbMainRecord, MainRecord2) then (MainRecord as IwbMainRecordInternal).YouGotAMaster(MainRecord2); if Assigned(Result) and (csRefsBuild in Result._File.ContainerStates) then Result.BuildRef; end; 8, 9, 10: begin if wbVWDAsQuestChildren and Supports(aElement, IwbGroupRecord, GroupRecord) then begin if GroupRecord.GroupType <> 7 then raise Exception.Create('Can''t add '+GroupRecord.Name+' to top level group with signature ' + TwbSignature(grStruct.grsLabel)); MainRecord := GroupRecord.ChildrenOf; if not Assigned(MainRecord) then raise Exception.Create('Can''t find record for '+ GroupRecord.Name); MainRecord := MainRecord.HighestOverrideOrSelf[GetFile.LoadOrder]; MainRecord := AddIfMissingInternal(MainRecord, aAsNew, True, aPrefixRemove, aPrefix, aSuffix) as IwbMainRecord; Assert(Assigned(MainRecord)); Result := MainRecord.ChildGroup; if not Assigned(Result) then Result := TwbGroupRecord.Create(Self, 7, MainRecord); GroupRecord2 := Result as IwbGroupRecord; if aDeepCopy then for i := 0 to Pred(GroupRecord.ElementCount) do GroupRecord2.AddIfMissing(GroupRecord.Elements[i], aAsNew, aDeepCopy, aPrefixRemove, aPrefix, aSuffix); Exit; end; if not Supports(aElement, IwbMainRecord, MainRecord) then raise Exception.Create('Only main records can be added to ' + GetName); if (MainRecord.Signature <> 'REFR') and (MainRecord.Signature <> 'ACHR') and (MainRecord.Signature <> 'ACRE') and (MainRecord.Signature <> 'PGRE') and (MainRecord.Signature <> 'PMIS') and (MainRecord.Signature <> 'PARW') and {>>> Skyrim <<<} (MainRecord.Signature <> 'PBEA') and {>>> Skyrim <<<} (MainRecord.Signature <> 'PFLA') and {>>> Skyrim <<<} (MainRecord.Signature <> 'PCON') and {>>> Skyrim <<<} (MainRecord.Signature <> 'PBAR') and {>>> Skyrim <<<} (MainRecord.Signature <> 'PHZD') {>>> Skyrim <<<} then // check any non reference record if not ( // DIAL, DLBR and SCEN can be added to child group 10 (quest children) (wbVWDAsQuestChildren and (grStruct.grsGroupType = 10) and ((MainRecord.Signature = 'DLBR') or (MainRecord.Signature = 'DIAL') or (MainRecord.Signature = 'SCEN'))) or // PGRD, LAND and NAVM can be added to child group 9 (temporary) (grStruct.grsGroupType = 9) and ((MainRecord.Signature = 'PGRD') or (MainRecord.Signature = 'LAND') or (MainRecord.Signature = 'NAVM')) ) then raise Exception.Create('Can''t add main record with signature '+MainRecord.Signature+' to ' + GetName); if aAsNew then FormID := GetFile.NewFormID else begin FormID := GetFile.LoadOrderFormIDtoFileFormID(MainRecord.LoadOrderFormID); for i := Low(cntElements) to High(cntElements) do if Supports(cntElements[i], IwbMainRecord, MainRecord2) then if MainRecord2.FixedFormID = FormID then begin Result := MainRecord2; exit; end; end; Result := TwbMainRecord.Create(Self, MainRecord.Signature, FormID); if aDeepCopy then begin Result.Assign(Low(Integer), aElement, False); if (aPrefix <> '') or (aSuffix <> '') then with Result as IwbMainRecord do begin s := EditorID; s := RemovePrefix(s, aPrefixRemove); if s <> '' then EditorID := aPrefix + s + aSuffix; end; end; if not aAsNew and MainRecord.IsMaster and (Result._File.LoadOrder <= MainRecord._File.LoadOrder) then if Supports(Result, IwbMainRecord, MainRecord2) then (MainRecord as IwbMainRecordInternal).YouGotAMaster(MainRecord2); if Assigned(Result) and (csRefsBuild in Result._File.ContainerStates) then Result.BuildRef; end; else raise Exception.Create(ClassName + '.AddIfMissingInternal is not implemented for GroupType ' + IntToStr(grStruct.grsGroupType)); end; end; procedure TwbGroupRecord.BuildRef; var Rec: IwbMainRecord; begin inherited; if GetGroupType in [1, 6, 7] then begin Rec := (GetFile as IwbFileInternal).RecordByFormID[GetGroupLabel, False]; if Assigned(Rec) then begin if Rec._File.Equals(GetFile) then (Rec as IwbMainRecordInternal).SetChildGroup(Self) else begin if Assigned(wbProgressCallback) then wbProgressCallback(' 0 then begin FileID := grStruct.grsLabel shr 24; aMasters[FileID] := True; end; end; end; function TwbGroupRecord.GetAddList: TDynStrings; var i, j : Integer; RecordDef : PwbRecordDef; begin Result := nil; case grStruct.grsGroupType of 0: begin SetLength(Result, 1); Result[0] := TwbSignature(grStruct.grsLabel); end; 7: begin SetLength(Result, 1); Result[0] := 'INFO'; end; 8: begin SetLength(Result, 11); Result[0] := 'ACHR'; Result[1] := 'ACRE'; Result[2] := 'REFR'; Result[3] := 'PGRE'; Result[4] := 'PMIS'; Result[5] := 'PARW'; {>>> Skyrim <<<} Result[6] := 'PBEA'; {>>> Skyrim <<<} Result[7] := 'PFLA'; {>>> Skyrim <<<} Result[8] := 'PCON'; {>>> Skyrim <<<} Result[9] := 'PBAR'; {>>> Skyrim <<<} Result[10] := 'PHZD'; {>>> Skyrim <<<} end; 6, 9: begin SetLength(Result, 11); Result[0] := 'ACHR'; Result[1] := 'ACRE'; Result[2] := 'REFR'; Result[3] := 'PGRE'; Result[4] := 'PMIS'; Result[5] := 'PARW'; {>>> Skyrim <<<} Result[6] := 'PBEA'; {>>> Skyrim <<<} Result[7] := 'PFLA'; {>>> Skyrim <<<} Result[8] := 'PCON'; {>>> Skyrim <<<} Result[9] := 'PBAR'; {>>> Skyrim <<<} Result[10] := 'PHZD'; {>>> Skyrim <<<} end; 10: if wbVWDAsQuestChildren then begin SetLength(Result, 3); Result[0] := 'DIAL'; Result[1] := 'DLBR'; Result[2] := 'SCEN'; end else begin SetLength(Result, 1); Result[0] := 'REFR'; end; end; j := 0; for i := Low(Result) to High(Result) do if wbFindRecordDef(AnsiString(Result[i]), RecordDef) then begin Result[j] := Result[i] + ' - ' + RecordDef.Name; Inc(j); end; SetLength(Result, j); end; function TwbGroupRecord.GetChildrenOf: IwbMainRecord; begin Result := nil; if grStruct.grsGroupType in [1, 6..10] then Result := GetFile.RecordByFormID[grStruct.grsLabel, True]; end; function TwbGroupRecord.GetElementType: TwbElementType; begin Result := etGroupRecord; end; function TwbGroupRecord.GetGroupLabel: Cardinal; begin Result := grStruct.grsLabel; end; function TwbGroupRecord.GetGroupType: Integer; begin Result := grStruct.grsGroupType; end; function TwbGroupRecord.GetMainRecordByEditorID(const aEditorID: string): IwbMainRecord; var SelfRef : IwbContainerElementRef; i : Integer; begin Result := nil; SelfRef := Self; DoInit; for i := Low(cntElements) to High(cntElements) do if Supports(cntElements[i], IwbMainRecord, Result) then if SameText(Result.EditorID, aEditorID) then Exit; Result := nil; end; function TwbGroupRecord.GetMainRecordByFormID(const aFormID: Cardinal): IwbMainRecord; var SelfRef : IwbContainerElementRef; i : Integer; begin Result := nil; SelfRef := Self; DoInit; for i := Low(cntElements) to High(cntElements) do if Supports(cntElements[i], IwbMainRecord, Result) then if Result.FormID = aFormID then Exit; Result := nil; end; function TwbGroupRecord.GetName: string; begin Result := inherited GetName; case grStruct.grsGroupType of 0: begin Result := Result + ' Top "' + PwbSignature(@grStruct.grsLabel)^ + '"'; Exit; end; 1: Result := Result + ' World Children of '; 2: begin Result := Result + ' Interior Cell Block ' + IntToStr(grStruct.grsLabel); Exit; end; 3: begin Result := Result + ' Interior Cell Sub-Block ' + IntToStr(grStruct.grsLabel); Exit; end; 4: begin Result := Result + ' Exterior Cell Block ' + IntToStr(LongRecSmall(grStruct.grsLabel).Lo) + ', ' + IntToStr(LongRecSmall(grStruct.grsLabel).Hi); Exit; end; 5: begin Result := Result + ' Exterior Cell Sub-Block ' + IntToStr(LongRecSmall(grStruct.grsLabel).Lo) + ', ' + IntToStr(LongRecSmall(grStruct.grsLabel).Hi); Exit; end; 6: Result := Result + ' Cell Children of '; 7: Result := Result + ' Topic Children of '; 8: Result := Result + ' Cell Persistent Children of '; 9: Result := Result + ' Cell Temporary Children of '; 10: if wbVWDAsQuestChildren then Result := Result + ' Quest Children of ' else Result := Result + ' Cell Visible Distant Children of '; else Result := Result + ' Unknown type: ' + IntToStr(grStruct.grsGroupType); Exit; end; // if wbDisplayLoadOrderFormID then // Result := Result + wbFormID.ToString(GetChildrenOf.FixedFormID, Self) // else Result := Result + wbFormID.ToString(grStruct.grsLabel, Self); end; function TwbGroupRecord.GetCountedRecordCount: Cardinal; begin Result := Succ(inherited GetCountedRecordCount); end; function TwbGroupRecord.GetShortName: string; var RecordDef : PwbRecordDef; begin case grStruct.grsGroupType of 0: begin Result := PwbSignature(@grStruct.grsLabel)^; if wbFindRecordDef(AnsiString(Result), RecordDef) then Result := RecordDef.GetName; end; 1: Result := 'World Children'; 2: Result := 'Block ' + IntToStr(grStruct.grsLabel); 3: Result := 'Sub-Block ' + IntToStr(grStruct.grsLabel); 4: Result := 'Block ' + IntToStr(LongRecSmall(grStruct.grsLabel).Hi) + ', ' + IntToStr(LongRecSmall(grStruct.grsLabel).Lo); 5: Result := 'Sub-Block ' + IntToStr(LongRecSmall(grStruct.grsLabel).Hi) + ', ' + IntToStr(LongRecSmall(grStruct.grsLabel).Lo); 6: Result := 'Children of ' + IntToHex(grStruct.grsLabel, 8); 7: Result := 'Children of ' + IntToHex(grStruct.grsLabel, 8); 8: Result := 'Persistent'; 9: Result := 'Temporary'; 10: if wbVWDAsQuestChildren then Result := 'Children of ' + IntToHex(grStruct.grsLabel, 8) else Result := 'Visible when Distant'; else Result := Result + ' Unknown type: ' + IntToStr(grStruct.grsGroupType); end; end; function TwbGroupRecord.GetSortKeyInternal(aExtended: Boolean): string; begin Result := IntToHex64(GetGroupType, 2); case grStruct.grsGroupType of 0: Result := Result + PwbSignature(@grStruct.grsLabel)^; 4: Result := Result + IntToHex64(LongRecSmall(grStruct.grsLabel).Hi + Low(SmallInt), 5) + IntToHex64(LongRecSmall(grStruct.grsLabel).Lo + Low(SmallInt), 5); 5: Result := Result + IntToHex64(LongRecSmall(grStruct.grsLabel).Hi + Low(SmallInt), 5) + IntToHex64(LongRecSmall(grStruct.grsLabel).Lo + Low(SmallInt), 5); else Result := Result + IntToHex64(grStruct.grsLabel, 8); end; end; function TwbGroupRecord.grStruct: PwbGroupRecordStruct; begin Result := PwbGroupRecordStruct(dcBasePtr); end; procedure TwbGroupRecord.InformPrevMainRecord(const aPrevMainRecord: IwbMainRecord); begin inherited; if (grStruct.grsGroupType in [1, 6, 7]) and Assigned(aPrevMainRecord) and (aPrevMainRecord.FormID = grStruct.grsLabel) then (aPrevMainRecord as IwbMainRecordInternal).SetChildGroup(Self); end; procedure TwbGroupRecord.InitDataPtr; var Dummy: Integer; begin if Assigned(dcEndPtr) then begin dcDataBasePtr := Pointer( Cardinal( dcBasePtr ) + wbSizeOfMainRecordStruct ); dcDataEndPtr := Pointer( Cardinal( dcBasePtr ) + grStruct.grsGroupSize ); dcEndPtr := dcDataEndPtr; if not recSkipped then if grStruct.grsGroupType = 0 then recSkipped := GroupToSkip.Find(PwbSignature(@grStruct.grsLabel)^, Dummy); end; end; function TwbGroupRecord.IsElementRemoveable(const aElement: IwbElement): Boolean; begin Result := IsElementEditable(aElement); end; function TwbGroupRecord.LinksToParent: Boolean; begin Result := GetGroupType in [4, 5, 8..10]; end; procedure TwbGroupRecord.MakeHeaderWriteable; var p : PwbGroupRecordStruct; SelfPtr : IwbContainerElementRef; begin SelfPtr := Self as IwbContainerElementRef; DoInit; SetModified(True); InvalidateParentStorage; if Assigned(dcEndPtr) then begin New(p); p^ := grStruct^; dcBasePtr := p; dcEndPtr := nil; end; end; procedure TwbGroupRecord.MasterCountUpdated(aOld, aNew: Byte); var FileID: Integer; begin if grStruct.grsGroupType in [1, 6..10] then begin if grStruct.grsLabel <> 0 then begin FileID := grStruct.grsLabel shr 24; if FileID >= aOld then begin FileID := aNew; MakeHeaderWriteable; grStruct.grsLabel := (grStruct.grsLabel and $00FFFFFF) or (Cardinal(FileID) shl 24); end; end; end; inherited; end; procedure TwbGroupRecord.MasterIndicesUpdated(const aOld, aNew: TBytes); var OldFormID: Cardinal; NewFormID: Cardinal; begin inherited; if grStruct.grsGroupType in [1, 6..10] then begin if grStruct.grsLabel <> 0 then begin OldFormID := grStruct.grsLabel; NewFormID := FixupFormID(OldFormID, aOld, aNew); if OldFormID <> NewFormID then begin MakeHeaderWriteable; grStruct.grsLabel := NewFormID; end; end; end; end; procedure TwbGroupRecord.NotifyChangedInternal(aContainer: Pointer); begin if gsSorting in grStates then Exit; inherited; // Let's try to sort only when the group membership change and not when one of its member change. if Assigned(aContainer) and (IwbContainerInternal(aContainer).ElementID = GetElementID) then Exclude(grStates, gsSorted); end; procedure TwbGroupRecord.PrepareSave; begin if esModified in eStates then Sort; inherited; if Length(cntElements) = 0 then Remove else if esModified in eStates then begin Exclude(grStates, gsSorted); Sort; end; end; function TwbGroupRecord.Reached: Boolean; var Rec : IwbMainRecord; SelfRef : IwbContainerElementRef; begin if esReachable in eStates then Exit(False); SelfRef := Self as IwbContainerElementRef; DoInit; if GetGroupType in [0, 2, 3] then begin Result := False; Exit; end; Result := inherited Reached; if Result and (GetGroupType in [1, 6..10]) then begin Rec := (GetFile as IwbFileInternal).RecordByFormID[GetGroupLabel, False]; if Assigned(Rec) then (Rec as IwbElementInternal).Reached; end; end; procedure TwbGroupRecord.Remove; var i : Integer; SelfRef : IwbContainerElementRef; MainRecord : IwbMainRecord; begin SelfRef := Self as IwbContainerElementRef; for i := High(cntElements) downto Low(cntElements) do cntElements[i].Remove; MainRecord := GetChildrenOf; if Assigned(MainRecord) and MainRecord._File.Equals(GetFile) then (MainRecord as IwbMainRecordInternal).RemoveChildGroup(Self); inherited Remove; end; procedure TwbGroupRecord.ScanData; var CurrentPtr : Pointer; Rec : IwbRecord; MainRecord : IwbMainRecord; PrevMainRecord : IwbMainRecord; begin case grStruct.grsGroupType of 0: begin SetSortOrder(wbGetGroupOrder(PwbSignature(@grStruct.grsLabel)^)); SetMemoryOrder(wbGetGroupOrder(PwbSignature(@grStruct.grsLabel)^)); end; end; if recSkipped then Exit; CurrentPtr := GetDataBasePtr; PrevMainRecord := nil; while Cardinal(CurrentPtr) < Cardinal(dcDataEndPtr) do begin Rec := TwbRecord.CreateForPtr(CurrentPtr, dcDataEndPtr, Self, PrevMainRecord); if Supports(Rec, IwbMainRecord, MainRecord) then PrevMainRecord := MainRecord; Rec := nil; MainRecord := nil; end; PrevMainRecord := nil; end; procedure TwbGroupRecord.SetGroupLabel(aLabel: Cardinal); var OldLabel : Cardinal; i : Integer; GroupRecord : IwbGroupRecord; SelfPtr : IwbContainerElementRef; ContainedIn : IwbContainedIn; begin SelfPtr := Self as IwbContainerElementRef; OldLabel := grStruct.grsLabel; if aLabel = OldLabel then Exit; case grStruct.grsGroupType of 1: ;//Result := Result + ' World Children of '; 6: ;//Result := Result + ' Cell Children of '; 7: ;//Result := Result + ' Topic Children of '; 8: ;//Result := Result + ' Cell Persistent Children of '; 9: ;//Result := Result + ' Cell Temporary Children of '; 10: ;//Result := Result + ' Cell Visible Distant Children of '; else raise Exception.Create('Can not set Label of ' + GetName); end; MakeHeaderWriteable; grStruct.grsLabel := aLabel; // if grStruct.grsGroupType <> 6 then // Exit; for i := 0 to Pred(GetElementCount) do if Supports(GetElement(i), IwbGroupRecord, GroupRecord) then begin if GroupRecord.GroupType in [8..10] then if GroupRecord.GroupLabel = OldLabel then GroupRecord.GroupLabel := aLabel; end else if Supports(GetElement(i), IwbContainedIn, ContainedIn) then ContainedIn.ContainerChanged; end; procedure TwbGroupRecord.SetModified(aValue: Boolean); begin inherited; InvalidateStorage; end; function FindSortElement(const aElement: IwbElement): IwbElement; var GroupRecord : IwbGroupRecord; begin if Supports(aElement, IwbGroupRecord, GroupRecord) then begin Result := GroupRecord.ChildrenOf; if Assigned(Result) then Exit; end; Result := aElement; end; function CompareGroupContents(Item1, Item2: Pointer): Integer; var Element1 : IwbElement; Element2 : IwbElement; SortElement1 : IwbElement; SortElement2 : IwbElement; GroupRecord1 : IwbGroupRecord; GroupRecord2 : IwbGroupRecord; MainRecord1 : IwbMainRecord; MainRecord2 : IwbMainRecord; begin Element1 := IwbElement(Item1); Element2 := IwbElement(Item2); if Element1 = Element2 then begin Result := 0; Exit; end; if Assigned(Element1) <> Assigned(Element2) then begin if Assigned(Element1) then Result := -1 else Result := 1; Exit; end else if not Assigned(Element1) then begin Result := 0; Exit; end; {"ChildrenOf" groups always sort like their owner} SortElement1 := FindSortElement(Element1); SortElement2 := FindSortElement(Element2); if Assigned(SortElement1) <> Assigned(SortElement2) then begin if Assigned(SortElement1) then Result := -1 else Result := 1; Exit; end else if not Assigned(SortElement1) then begin Result := 0; Exit; end; Result := CmpI32(Ord(SortElement1.ElementType), Ord(SortElement2.ElementType)); if Result = 0 then case SortElement1.ElementType of etFile: begin Assert(False); Exit; end; etGroupRecord: begin Assert(SortElement2.ElementType = etGroupRecord); GroupRecord1 := SortElement1 as IwbGroupRecord; GroupRecord2 := SortElement2 as IwbGroupRecord; Assert(GroupRecord1.GroupType = GroupRecord2.GroupType); case GroupRecord1.GroupType of 0: Result := CompareText( TwbSignature(GroupRecord1.GroupLabel), TwbSignature(GroupRecord2.GroupLabel)); 2, 3: Result := CmpI32( Integer(GroupRecord1.GroupLabel), Integer(GroupRecord2.GroupLabel)); 4, 5: begin Result := CmpI32( LongRecSmall(GroupRecord1.GroupLabel).Hi, LongRecSmall(GroupRecord2.GroupLabel).Hi); if Result = 0 then Result := CmpI32( LongRecSmall(GroupRecord1.GroupLabel).Lo, LongRecSmall(GroupRecord2.GroupLabel).Lo); end; else Assert(False); end; end; etMainRecord: begin Assert(SortElement2.ElementType = etMainRecord); MainRecord1 := SortElement1 as IwbMainRecord; MainRecord2 := SortElement2 as IwbMainRecord; Result := 0; if Result = 0 then begin Result := CmpI32(MainRecord1.SortPriority, MainRecord2.SortPriority); if Result = 0 then begin if wbDisplayLoadOrderFormID then Result := CmpW32(MainRecord1.LoadOrderFormID, MainRecord2.LoadOrderFormID) else Result := CmpW32(MainRecord1.FixedFormID, MainRecord2.FixedFormID); if Result = 0 then Result := CmpW32(MainRecord1.ElementID, MainRecord2.ElementID); end; end; end else Assert(False); end; if Result = 0 then if Element1 <> SortElement1 then begin if Element2 <> SortElement2 then begin {both are groups of the same element } GroupRecord1 := Element1 as IwbGroupRecord; GroupRecord2 := Element2 as IwbGroupRecord; Result := CmpI32(GroupRecord1.GroupType, GroupRecord2.GroupType); if Result = 0 then Result := CmpW32(GroupRecord1.GroupLabel, GroupRecord2.GroupLabel); end else begin {element1 is a group of element2} Result := 1; end; end else begin if Element2 <> SortElement2 then begin {element2 is a group of element1} Result := -1; end else begin {really seems to be the same} end; end; end; var ElementRefs : array of IwbContainerElementRef; ElementRefsCount : Integer; procedure TwbGroupRecord.Sort; procedure DoInserRecord(const InsertRecord: IwbMainRecordEntry); var TargetRecord: IwbMainRecordEntry; begin SetLength(ElementRefs, Succ(Length(ElementRefs))); if not Supports(InsertRecord, IwbContainerElementRef, ElementRefs[High(ElementRefs)]) then Assert(False); if Supports(InsertRecord.ElementLinksTo['PNAM'], IwbMainRecordEntry, TargetRecord) then begin SetLength(ElementRefs, Succ(Length(ElementRefs))); if not Supports(TargetRecord, IwbContainerElementRef, ElementRefs[High(ElementRefs)]) then Assert(False); if not TargetRecord.IsInList then DoInserRecord(TargetRecord); InsertRecord.InsertEntryAfter(TargetRecord); end else if InsertRecord.ElementExists['PNAM'] then InsertRecord.InsertEntryHead else InsertRecord.InsertEntryTail; end; var ChildrenOf : IwbMainRecord; MainRecords : TDynMainRecords; Groups : TDynGroupRecords; Group : IwbContainerElementRef; g : IwbGroupRecord; i, j, k : Integer; InsertRecord: IwbMainRecordEntry; TargetRecord: IwbMainRecordEntry; PrevRecord : IwbMainRecordEntry; InfoQuest : Int64; InfoQuest2 : Int64; Inserted : Boolean; NewElements : TDynElementInternals; begin if grStates * [gsSorted, gsSorting] <> [] then Exit; if eUpdateCount > 0 then begin Include(grStates, gsSortPostponed); Exit; end; Include(grStates, gsSorting); try ChildrenOf := GetChildrenOf; // there is no PNAM in Fallout 4, looks like INFOs are no longer linked lists if (wbGameMode <> gmFO4) and Assigned(ChildrenOf) and (ChildrenOf.Signature = 'DIAL') then begin {>>> Sorting DIAL group doesn't always work, and Skyrim.esm has a plenty of unsorted DIALs <<<} {>>> Also disabled for FNV, https://code.google.com/p/skyrim-plugin-decoding-project/issues/detail?id=59 <<<} if not wbSortGroupRecord then Exit; if not wbDisplayLoadOrderFormID then Exit; Inc(ElementRefsCount); try MainRecords := ChildrenOf.MasterRecordsFromMasterFilesAndSelf; SetLength(Groups, Length(MainRecords)); i := 0; for j := Low(MainRecords) to High(MainRecords) do begin Groups[i] := MainRecords[j].ChildGroup; if Assigned(Groups[i]) and (Groups[i].ElementCount > 0) then Inc(i); end; SetLength(Groups, i); for i := Low(Groups) to High(Groups) do if not Equals(Groups[i]) then (Groups[i] as IwbGroupRecordInternal).Sort; mreHeader.BeginUse; try for i := Low(Groups) to High(Groups) do if Supports(Groups[i], IwbContainerElementRef, Group) then for j := 0 to Pred(Group.ElementCount) do if Supports(Group.Elements[j], IwbMainRecordEntry, InsertRecord) then DoInserRecord(InsertRecord); TargetRecord := IwbMainRecordEntry(mreHeader.mrehTail); while Assigned(TargetRecord) do begin PrevRecord := TargetRecord.PrevEntry; if not Equals(TargetRecord.Container) then TargetRecord.RemoveEntry else if not TargetRecord.IsDeleted then if wbBeginInternalEdit then try if not TargetRecord.ElementExists['PNAM'] then begin {>>> No QSTI in Skyrim, using DIAL\QNAM <<<} if wbGameMode in [ gmTES5, gmSSE ] then begin Supports(TargetRecord.Container, IwbGroupRecord, g); InfoQuest := g.ChildrenOf.ElementNativeValues['QNAM']; end else InfoQuest := TargetRecord.ElementNativeValues['QSTI']; InsertRecord := PrevRecord; Inserted := False; while Assigned(InsertRecord) do begin if wbGameMode in [ gmTES5, gmSSE ] then begin Supports(InsertRecord.Container, IwbGroupRecord, g); InfoQuest2 := g.ChildrenOf.ElementNativeValues['QNAM']; end else InfoQuest2 := InsertRecord.ElementNativeValues['QSTI']; if (not InsertRecord.IsDeleted) and (InfoQuest = InfoQuest2) then begin try Inserted := True; TargetRecord.Add('PNAM').NativeValue := InsertRecord.LoadOrderFormID; except TargetRecord.RemoveElement('PNAM'); end; Break; end; InsertRecord := InsertRecord.PrevEntry; end; if not Inserted then TargetRecord.Add('PNAM'); end; finally wbEndInternalEdit; end; TargetRecord := PrevRecord; end; Assert(mreHeader.mrehCount = Length(cntElements)); SetLength(NewElements, Length(cntElements)); k := High(NewElements); TargetRecord := IwbMainRecordEntry(mreHeader.mrehTail); while Assigned(TargetRecord) do begin Assert(k >= Low(NewElements)); if not Supports(TargetRecord, IwbElementInternal, NewElements[k]) then Assert(False); TargetRecord := TargetRecord.PrevEntry; Dec(k); end; Assert(k = -1); cntElements := NewElements; Include(grStates, gsSorted); finally mreHeader.EndUse; end; finally Dec(ElementRefsCount); if ElementRefsCount = 0 then ElementRefs := nil; end; Exit; end; if Length(cntElements) > 1 then wbMergeSort(@cntElements[0], Length(cntElements), CompareGroupContents); Include(grStates, gsSorted); finally Exclude(grStates, gsSorting); end; end; procedure TwbGroupRecord.UpdatedEnded; begin if gsSortPostponed in grStates then begin Exclude(grStates, gsSortPostponed); Sort; end; inherited; end; procedure TwbGroupRecord.WriteToStreamInternal(aStream: TStream; aResetModified: Boolean); var CurrentPosition : Int64; NewPosition : Int64; DataSize : Cardinal; grs : TwbGroupRecordStruct; begin CurrentPosition := aStream.Position; grs := grStruct^; aStream.WriteBuffer(grs, wbSizeOfMainRecordStruct ); if wbForceNewHeader then aStream.WriteBuffer(wbNewHeaderAddon, SizeOf(wbNewHeaderAddon) ); inherited; if (esModified in eStates) or wbTestWrite then begin NewPosition := aStream.Position; DataSize := (NewPosition - CurrentPosition); aStream.Position := CurrentPosition + 4; aStream.WriteBuffer(DataSize, SizeOf(DataSize)); aStream.Position := NewPosition; end else if wbForceNewHeader then Assert(CurrentPosition + grStruct.grsGroupSize + SizeOf(wbNewHeaderAddon) = aStream.Position) else Assert(CurrentPosition + grStruct.grsGroupSize = aStream.Position); Exclude(eStates, esUnsaved); if aResetModified then begin Exclude(eStates, esModified); Exclude(eStates, esInternalModified); end; end; { TwbElement } function TwbElement.AddIfMissing(const aElement: IwbElement; aAsNew, aDeepCopy : Boolean; const aPrefixRemove, aPrefix, aSuffix: string): IwbElement; {$IFDEF USE_CODESITE} var Log: Boolean; Group : IwbGroupRecord; {$ENDIF} begin if (wbCurrentTick>0) and (wbCurrentTick+5000) and (wbCurrentTick+500 0 then Assert(FRefCount = 0); Include(eStates, esDestroying); inherited BeforeDestruction; {$IFDEF WIN64} LockedInc(eExternalRefs); LockedInc(FRefCount); {$ENDIF WIN64} {$IFDEF WIN32} asm mov eax, [Self] lock inc dword ptr [eax + eExternalRefs] lock inc dword ptr [eax + FRefCount] end; {$ENDIF WIN64} end; function TwbElement.BeginDecide: Boolean; begin Result := not (esDeciding in eStates); if Result then Include(eStates, esDeciding); end; function TwbElement.BeginUpdate: Integer; begin Result := Succ(eUpdateCount); eUpdateCount := Result; end; procedure TwbElement.BuildRef; begin {nothing} end; function TwbElement.CanAssign(aIndex: Integer; const aElement: IwbElement; aCheckDontShow: Boolean): Boolean; {$IFDEF USE_CODESITE} var Log: Boolean; {$ENDIF} begin {$IFDEF USE_CODESITE} Log := (laElementCanAssign in wbLoggingAreas) and wbCodeSiteLoggingEnabled; if Log then begin CodeSite.EnterMethod(Self, 'CanAssign'); CodeSite.Send('Self.Name', Self.GetName); CodeSite.Send('Self.Path', Self.GetPath); CodeSite.Send('Self.Value', Self.GetValue); CodeSite.Send('aIndex', aIndex); if Assigned(aElement) then begin CodeSite.Send('aElement.Name', aElement.Name); CodeSite.Send('aElement.Path', aElement.Path); CodeSite.Send('aElement.Value', aElement.Value); end else CodeSite.Send('aElement', 'nil'); CodeSite.Send('aCheckDontShow', aCheckDontShow); end; Result := False; try {$ENDIF} Result := CanAssignInternal(aIndex, aElement, aCheckDontShow); {$IFDEF USE_CODESITE} finally if Log then begin CodeSite.Send('Result', Result); CodeSite.ExitMethod(Self, 'CanAssign'); end; end; {$ENDIF} end; function TwbElement.CanAssignInternal(aIndex: Integer; const aElement: IwbElement; aCheckDontShow: Boolean): Boolean; var TargetValueDef: IwbValueDef; SourceValueDef: IwbValueDef; begin Result := wbIsInternalEdit; if Result then Exit; if not wbEditAllowed then Exit; if not GetIsEditable then Exit; if not Assigned(aElement) then Exit; TargetValueDef := GetValueDef; if TargetValueDef = nil then Exit; SourceValueDef := aElement.ValueDef; if SourceValueDef = nil then Exit; Result := TargetValueDef.CanAssign(Self, aIndex, SourceValueDef); if Result and aCheckDontShow and GetDontShow then Result := False; end; function TwbElement.CanChangeMember: Boolean; begin Result := Assigned(eContainer) and IwbContainerInternal(eContainer).CanChangeElementMember(Self); end; function TwbElement.CanContainFormIDs: Boolean; begin Result := True; end; function TwbElement.CanMoveDown: Boolean; begin Result := Assigned(eContainer) and IwbContainerInternal(eContainer).CanMoveElementDown(Self); end; function TwbElement.CanMoveUp: Boolean; begin Result := Assigned(eContainer) and IwbContainerInternal(eContainer).CanMoveElementUp(Self); end; function TwbElement.CompareExchangeFormID(aOldFormID, aNewFormID: Cardinal): Boolean; begin Result := False; end; function CompareLoadOrderSL(List: TStringList; Index1, Index2: Integer): Integer; begin if Index1 = Index2 then begin Result := 0; Exit; end; Result := CmpI32( IwbFile(Pointer(List.Objects[Index1])).LoadOrder, IwbFile(Pointer(List.Objects[Index2])).LoadOrder); end; procedure AddRequiredMasters(aMasters: TStrings; const aTargetFile: IwbFile); var sl : TStringList; i, j : Integer; begin sl := TStringList.Create; try sl.Sorted := True; sl.Duplicates := dupIgnore; sl.AddStrings(aMasters); for i := 0 to Pred(aTargetFile.MasterCount) do if sl.Find(aTargetFile.Masters[i].FileName, j) then sl.Delete(j); if sl.Find(aTargetFile.FileName, j) then sl.Delete(j); if sl.Count > 0 then begin for i := 0 to Pred(sl.Count) do if IwbFile(Pointer(sl.Objects[i])).LoadOrder >= aTargetFile.LoadOrder then raise Exception.Create('The required master "' + sl[i] + '" can not be added to "' + aTargetFile.FileName + '" as it has a higher load order'); sl.Sorted := False; sl.CustomSort(CompareLoadOrderSL); aTargetFile.AddMasters(sl); end; finally sl.Free; end; end; function TwbElement.CopyInto(const aFile: IwbFile; aAsNew, aDeepCopy: Boolean; const aPrefixRemove, aPrefix, aSuffix: string): IwbElement; var sl : TStringList; MainRecord : IwbMainRecord; GroupRecord : IwbGroupRecord; begin sl := TStringList.Create; try sl.Sorted := True; sl.Duplicates := dupIgnore; ReportRequiredMasters(sl, aAsNew); AddRequiredMasters(sl, aFile); if aDeepCopy and Supports(Self, IwbMainRecord, MainRecord) and Assigned(MainRecord.ChildGroup) then begin Result := wbCopyElementToFile(MainRecord.ChildGroup, aFile, aAsNew, True, aPrefixRemove, aPrefix, aSuffix); if Supports(Result, IwbGroupRecord, GroupRecord) then Result := GroupRecord.ChildrenOf else Result := nil; end else Result := wbCopyElementToFile(Self, aFile, aAsNew, True, aPrefixRemove, aPrefix, aSuffix); finally sl.Free; end; end; constructor TwbElement.Create(const aContainer: IwbContainer); begin eSortOrder := High(Integer); eMemoryOrder := Low(Integer); inherited Create; if Assigned(aContainer) then aContainer.AddElement(Self); end; procedure TwbElement.DoAfterSet(const aOldValue, aNewValue: Variant); var NamedDef: IwbNamedDef; begin NamedDef := GetValueDef; if Assigned(NamedDef) then NamedDef.AfterSet(Self, aOldValue, aNewValue); if Supports(GetDef, IwbNamedDef, NamedDef) then NamedDef.AfterSet(Self, aOldValue, aNewValue); end; procedure TwbElement.DoReset(aForce: Boolean); begin {nothing} end; procedure TwbElement.EndDecide; begin Exclude(eStates, esDeciding); end; function TwbElement.EndUpdate: Integer; begin Result := Pred(eUpdateCount); eUpdateCount := Result; if Result = 0 then UpdatedEnded; end; function TwbElement.Equals(const aElement: IwbElement): Boolean; begin Result := Assigned(aElement) and (aElement.ElementID = GetElementID); end; procedure TwbElement.FindUsedMasters(aMasters: PwbUsedMasters); begin {can be overriden} end; procedure TwbElement.FreeInstance; begin if (FRefCount and $7FFFFFFF) <> 1 then Assert(FRefCount = 1); Assert(eExternalRefs = 1); inherited; end; function TwbElement.GetBaseName: string; begin Result := GetName; end; function TwbElement.GetCheck: string; begin Result := ''; end; function TwbElement.GetConflictPriority: TwbConflictPriority; var Def : IwbDef; MainRecord : IwbMainRecord; begin Result := cpNormal; Def := GetValueDef; if not Assigned(Def) then Def := GetDef; if Assigned(Def) then Result := Def.ConflictPriority[Self]; if wbTranslationMode then begin if Result <> cpTranslate then Result := cpIgnore else Result := cpNormal; end else begin if Result = cpTranslate then Result := cpNormal; end; if Result = cpFormID then begin Result := cpCritical; MainRecord := GetContainingMainRecord; if Assigned(MainRecord) and (MainRecord.Signature = 'GMST') then Result := cpBenign; end; end; function TwbElement.GetConflictPriorityCanChange: Boolean; var Def : IwbDef; begin Result := False; Def := GetValueDef; if not Assigned(Def) then Def := GetDef; if Assigned(Def) then Result := Def.ConflictPriorityCanChange; end; function TwbElement.GetContainer: IwbContainer; begin Result := IwbContainer(eContainer); end; function TwbElement.GetContainingMainRecord: IwbMainRecord; begin if Assigned(eContainer) then Result := IwbContainer(eContainer).ContainingMainRecord else Result := nil; end; function TwbElement.GetDataSize: Integer; begin Result := 0; end; function TwbElement.GetDef: IwbNamedDef; begin Result := nil; end; function TwbElement.GetDisplayName: string; begin Result := GetName; end; function TwbElement.GetDontShow: Boolean; var Def: IwbDef; begin Result := False; Def := GetValueDef; if Assigned(Def) then Result := Def.DontShow[Self]; if not Result then begin Def := GetDef; if Assigned(Def) then Result := Def.DontShow[Self]; end; end; function TwbElement.GetEditInfo: string; begin Result := ''; end; function TwbElement.GetEditType: TwbEditType; begin Result := etDefault; end; function TwbElement.GetEditValue: string; begin Result := ''; end; function TwbElement.GetElementID: Cardinal; begin Result := Cardinal(Self); end; function TwbElement.GetElementStates: TwbElementStates; begin Result := eStates; end; function TwbElement.GetElementType: TwbElementType; begin Assert(False, 'This method is abstract'); Result := TwbElementType(-1); end; function TwbElement.GetFile: IwbFile; begin if Assigned(eContainer) then Result := IwbContainerInternal(eContainer)._File else Result := nil; end; function TwbElement.GetFullPath: string; begin if Assigned(eContainer) then Result := IwbElement(eContainer).FullPath else Result := ''; Result := Result + ' \ '; if Assigned(eContainer) then Result := Result + '['+IntToStr(IwbContainer(eContainer).IndexOf(Self))+'] '; Result := Result + GetName; end; function TwbElement.GetPathName: string; begin if Assigned(eContainer) then Result := IwbElement(eContainer).PathName else Result := ''; Result := Result + '\'; if Assigned(eContainer) then Result := Result + '['+IntToStr(IwbContainer(eContainer).IndexOf(Self))+'] '; Result := Result + GetShortName; end; function TwbElement.GetInjectionSourceFiles: TDynFiles; var Element : IwbElement; MainRecord : IwbMainRecord; begin Result := nil; Element := GetLinksTo; if Supports(Element, IwbMainRecord, MainRecord) and not GetFile.Equals(MainRecord._File) and MainRecord.MasterOrSelf.IsInjected then begin SetLength(Result, 1); Result[0] := MainRecord.MasterOrSelf._File; end; end; function TwbElement.GetIsEditable: Boolean; begin Result := wbIsInternalEdit; end; function TwbElement.GetIsHidden: Boolean; begin if [esHidden, esParentHiddenChecked] * eStates = [] then begin Include(eStates, esParentHiddenChecked); if Assigned(eContainer) and IwbContainer(eContainer).IsHidden then Include(eStates, esParentHidden) else Exclude(eStates, esParentHidden); end; Result := eStates * [esHidden, esParentHidden] <> []; end; function TwbElement.GetIsInjected: Boolean; begin Result := False; end; function TwbElement.GetIsNotReachable: Boolean; begin Result := esNotReachable in eStates; end; function TwbElement.GetIsRemoveable: Boolean; begin Result := not Assigned(eContainer) or IwbContainer(eContainer).IsElementRemoveable(Self); end; function TwbElement.GetLinksTo: IwbElement; begin Result := nil; end; function TwbElement.GetMemoryOrder: Integer; begin Result := eMemoryOrder; end; function TwbElement.GetModified: Boolean; begin if wbShowInternalEdit then Result := [esModified] * eStates = [esModified] else Result := [esModified, esInternalModified] * eStates = [esModified]; end; function TwbElement.GetName: string; var Def: IwbDef; begin if wbReportMode then begin Def := GetValueDef; if Assigned(Def) then Def.Used; Def := GetDef; if Assigned(Def) then Def.Used; end; Result := ''; end; function TwbElement.GetNativeValue: Variant; begin Result := Null; end; function TwbElement.GetNoReach: Boolean; var Def : IwbDef; begin Def := GetValueDef; if not Assigned(Def) then Def := GetDef; if Assigned(Def) then Result := Def.NoReach else Result := False; end; function TwbElement.GetPath: string; begin if Assigned(eContainer) then Result := IwbElement(eContainer).Path else Result := ''; Result := Result + ' \ ' + GetName; end; function TwbElement.GetCountedRecordCount: Cardinal; begin Result := 0; end; function TwbElement.GetReferenceFile: IwbFile; var Container: IwbContainer; begin Container := GetContainer; if Assigned(Container) then Result := Container.ReferenceFile else Result := nil; end; function TwbElement.GetReferencesInjected: Boolean; var Element : IwbElement; _File : IwbFile; ElementFile : IwbFile; i : Integer; begin Element := GetLinksTo; Result := Assigned(Element) and Element.IsInjected; if Result then begin _File := GetFile; ElementFile := Element._File; Result := not _File.Equals(ElementFile); if Result then begin for i := 0 to Pred(_File.MasterCount) do if _File.Masters[i].Equals(ElementFile) then begin Result := False; Exit; end; end; end; end; function TwbElement.GetResolvedValueDef: IwbValueDef; begin Result := GetValueDef; end; function TwbElement.GetShortName: string; var Def: IwbDef; begin if wbReportMode then begin Def := GetDef; if Assigned(Def) then Def.Used; end; Result := GetName; end; function TwbElement.GetSkipped: Boolean; begin Result := False; end; function TwbElement.GetSortKey(aExtended: Boolean): string; begin if aExtended then begin if not (esExtendedSortKeyValid in eStates) then begin if not (esSorting in eStates) then begin Include(eStates, esSorting); eExtendedSortKey := GetSortKeyInternal(aExtended); Exclude(eStates, esSorting); end else eExtendedSortKey := GetSortKeyInternal(aExtended); Include(eStates, esExtendedSortKeyValid); end; Result := eExtendedSortKey; end else begin if not (esSortKeyValid in eStates) then begin if not (esSorting in eStates) then begin Include(eStates, esSorting); eSortKey := GetSortKeyInternal(aExtended); Exclude(eStates, esSorting); end else eSortKey := GetSortKeyInternal(aExtended); Include(eStates, esSortKeyValid); end; Result := eSortKey; end; end; function TwbElement.GetSortKeyInternal(aExtended: Boolean): string; begin Result := ''; end; function TwbElement.GetSortOrder: Integer; begin Result := eSortOrder; end; function TwbElement.GetSortPriority: Integer; begin Result := 0; end; function TwbElement.GetTreeBranch: Boolean; var NamedDef: IwbNamedDef; begin if Supports(GetDef, IwbNamedDef, NamedDef) then Result := NamedDef.TreeBranch else Result := False; end; function TwbElement.GetTreeHead: Boolean; var NamedDef: IwbNamedDef; begin if Supports(GetDef, IwbNamedDef, NamedDef) then Result := NamedDef.TreeHead else Result := False; end; function TwbElement.GetValue: string; var Def: IwbDef; begin if wbReportMode then begin Def := GetValueDef; if Assigned(Def) then Def.Used; Def := GetDef; if Assigned(Def) then Def.Used; end; Result := ''; end; function TwbElement.GetValueDef: IwbValueDef; begin Result := nil; end; function TwbElement.HasErrors: Boolean; begin Result := Trim(GetCheck) <> ''; end; procedure TwbElement.Hide; begin if not (esHidden in eStates) then begin Include(eStates, esHidden); ResetConflict; end; end; procedure TwbElement.InformStorage(var aBasePtr: Pointer; aEndPtr: Pointer); begin {can be overriden} end; {$D-} function TwbElement.InternalAddRef: Integer; begin Result := inherited _AddRef; end; function TwbElement.InternalRelease: Integer; begin Result := inherited _Release; end; {$D+} procedure TwbElement.InvalidateParentStorage; begin if Assigned(eContainer) then (IwbContainer(eContainer) as IwbElementInternal).InvalidateStorage; end; procedure TwbElement.InvalidateStorage; begin InvalidateParentStorage; end; function TwbElement.IsTagged: Boolean; begin Result := esTagged in eStates; end; function TwbElement.LinksToParent: Boolean; begin Result := False; end; procedure TwbElement.MarkModifiedRecursive; begin if not Assigned(eContainer) or IwbContainer(eContainer).IsElementEditable(Self) then begin SetModified(True); InvalidateParentStorage; end; end; procedure TwbElement.MasterCountUpdated(aOld, aNew: Byte); begin {can be overriden} end; procedure TwbElement.MasterIndicesUpdated(const aOld, aNew: TBytes); begin Assert( Length(aOld) = Length(aNew) ); end; procedure TwbElement.MergeStorage(var aBasePtr: Pointer; aEndPtr: Pointer); {$IFDEF USE_CODESITE} var Log: Boolean; {$ENDIF} begin {$IFDEF USE_CODESITE} Log := (laElementMergeStorage in wbLoggingAreas) and wbCodeSiteLoggingEnabled; if Log then begin CodeSite.EnterMethod(Self, 'MergeStorage'); CodeSite.Send('Self.Name', Self.GetName); CodeSite.Send('Self.Path', Self.GetPath); CodeSite.Send('Self.Value', Self.GetValue); if StartsWith(Self.GetValue, ' 0 then Include(eStates, esChangeNotified) else NotifyChangedInternal(aContainer); end; procedure TwbElement.NotifyChangedInternal(aContainer: Pointer); begin if Assigned(eContainer) then IwbContainerInternal(eContainer).ElementChanged(Self, aContainer); end; procedure TwbElement.PrepareSave; begin {can be overriden} end; procedure TwbElement.PreviousMember; begin if not CanChangeMember then Exit; IwbContainerInternal(eContainer).PreviousElementMember(Self); end; function TwbElement.Reached: Boolean; var MainRecord : IwbMainRecord; begin Result := not (esReachable in eStates); if GetDontShow then Exit; Exclude(eStates, esNotReachable); Include(eStates, esReachable); If Result then begin if not GetNoReach then if Supports(GetLinksTo, IwbMainRecord, MainRecord) then begin MainRecord := MainRecord.WinningOverride; (MainRecord as IwbElementInternal).Reached; end; if LinksToParent and Assigned(eContainer) then (IwbContainer(eContainer) as IwbElementInternal).Reached; end; end; procedure TwbElement.Remove; begin if Assigned(eContainer) then begin SetModified(True); InvalidateParentStorage; IwbContainer(eContainer).RemoveElement(Self as IwbElement); end; end; function TwbElement.RemoveInjected(aCanRemove: Boolean): Boolean; begin Result := GetReferencesInjected; if Result and GetIsRemoveable then begin Result := False; Remove; end; end; procedure TwbElement.ReportRequiredMasters(aStrings: TStrings; aAsNew: Boolean; Recursive: Boolean = True; Initial: Boolean = false); var Element : IwbElement; ReferenceFile : IwbFile; begin Element := GetLinksTo; if Assigned(Element) then begin ReferenceFile := Element.ReferenceFile; if Assigned(ReferenceFile) then begin aStrings.AddObject(ReferenceFile.FileName, Pointer(ReferenceFile)); end; end; end; procedure TwbElement.RequestStorageChange(var aBasePtr, aEndPtr: Pointer; aNewSize: Cardinal); begin raise Exception.Create(GetName + ' is not editable'); end; procedure TwbElement.ResetConflict; begin Exclude(eStates, esParentHiddenChecked); Exclude(eStates, esParentHidden); end; procedure TwbElement.ResetReachable; begin Include(eStates, esNotReachable); Exclude(eStates, esReachable); end; procedure TwbElement.ResetTags; begin Exclude(eStates, esTagged); end; procedure TwbElement.SetContainer(const aContainer: IwbContainer); begin if Assigned(aContainer) then begin Assert(not Assigned(eContainer)); if esNotReachable in aContainer.ElementStates then Include(eStates, esNotReachable); end else Assert(Assigned(eContainer)); if Assigned(aContainer) then eContainer := Pointer(aContainer as IwbContainerInternal) else eContainer := nil; if not Assigned(eContainer) then eContainerRef := nil else if eExternalRefs > 0 then eContainerRef := aContainer as IwbContainerElementRef; end; procedure TwbElement.SetDataSize(aSize: Integer); begin Assert(False, 'Can''t SetDataSize on ' + ClassName); end; procedure TwbElement.SetEditValue(const aValue: string); begin raise Exception.Create(GetName + ' can not be edited.'); end; procedure TwbElement.SetElementState(aState: TwbElementState; Clear: Boolean); begin if Clear then Exclude(eStates, aState) else Include(eStates, aState); end; procedure TwbElement.SetInternalModified(aValue: Boolean); begin wbBeginInternalEdit(True); try SetModified(aValue); finally wbEndInternalEdit; end; end; procedure TwbElement.SetMemoryOrder(aIndex: Integer); begin eMemoryOrder := aIndex; end; procedure TwbElement.SetModified(aValue: Boolean); begin if aValue then begin if wbIsInternalEdit then begin if not (esModified in eStates) then Include(eStates, esInternalModified); end else begin Exclude(eStates, esInternalModified); Include(eStates, esUnsaved); end; Include(eStates, esModified); Exclude(eStates, esSortKeyValid); Exclude(eStates, esExtendedSortKeyValid); eSortKey := ''; eExtendedSortKey := ''; // if wbIsInternalEdit and (Self is TwbMainRecord) then // Exit; if eUpdateCount > 0 then Include(eStates, esModifiedUpdated) else if Assigned(eContainer) then (IwbContainer(eContainer) as IwbElementInternal).Modified := True; end; end; procedure TwbElement.SetNativeValue(const aValue: Variant); begin raise Exception.Create(GetName + ' can not be edited.'); end; procedure TwbElement.SetSortOrder(aIndex: Integer); begin eSortOrder := aIndex; end; procedure TwbElement.SetToDefault; {$IFDEF USE_CODESITE} var Log: Boolean; {$ENDIF} begin {$IFDEF USE_CODESITE} Log := (laElementSetToDefault in wbLoggingAreas) and wbCodeSiteLoggingEnabled; if Log then begin CodeSite.EnterMethod(Self, 'SetToDefault'); CodeSite.Send('Self.Name', Self.GetName); CodeSite.Send('Self.Path', Self.GetPath); CodeSite.Send('Self.DataSize', Self.GetDataSize); CodeSite.Send('Self.Value', Self.GetValue); end; {$ENDIF} BeginUpdate; try SetToDefaultInternal; finally EndUpdate; {$IFDEF USE_CODESITE} if Log then begin CodeSite.Send('Self.Value', Self.GetValue); CodeSite.Send('Self.DataSize', Self.GetDataSize); CodeSite.ExitMethod(Self, 'SetToDefault'); end; {$ENDIF} end; end; procedure TwbElement.SetToDefaultInternal; begin { can be overriden } end; procedure TwbElement.Show; begin if esHidden in eStates then begin Exclude(eStates, esHidden); ResetConflict; end; end; procedure TwbElement.Tag; begin Include(eStates, esTagged); end; procedure TwbElement.UpdatedEnded; begin if esChangeNotified in eStates then begin Exclude(eStates, esChangeNotified); NotifyChanged(eContainer); end; if esModifiedUpdated in eStates then begin Exclude(eStates, esModifiedUpdated); if Assigned(eContainer) and (esModified in eStates) then (IwbContainer(eContainer) as IwbElementInternal).Modified := True; end; end; procedure TwbElement.WriteToStream(aStream: TStream; aResetModified: Boolean); {$IFDEF USE_CODESITE} var Log: Boolean; {$ENDIF} begin {$IFDEF USE_CODESITE} Log := (laElementWriteToStream in wbLoggingAreas) and wbCodeSiteLoggingEnabled; if Log then begin CodeSite.EnterMethod(Self, 'WriteToStream'); CodeSite.Send('Self.Name', Self.GetName); CodeSite.Send('Self.Path', Self.GetPath); CodeSite.Send('Self.Value', Self.GetValue); CodeSite.Send('aStream.Position', aStream.Position); CodeSite.Send('aResetModified', aResetModified); end; try {$ENDIF} WriteToStreamInternal(aStream, aResetModified); {$IFDEF USE_CODESITE} finally if Log then begin CodeSite.Send('aStream.Position', aStream.Position); CodeSite.Send('Self.Value', Self.GetValue); CodeSite.ExitMethod(Self, 'WriteToStream'); end; end; {$ENDIF} end; procedure TwbElement.WriteToStreamInternal(aStream: TStream; aResetModified: Boolean); begin Exclude(eStates, esUnsaved); if aResetModified then begin Exclude(eStates, esModified); Exclude(eStates, esInternalModified); end; end; {$D-} function TwbElement._AddRef: Integer; label Skip; begin Assert(not (esDestroying in eStates)); {$IFDEF WIN64} if LockedInc(eExternalRefs) = 1 then {$ENDIF WIN64} {$IFDEF WIN32} asm mov eax, 1 mov ecx, [Self] lock xadd dword ptr [ecx + eExternalRefs], eax cmp eax, 0 jne Skip end; {$ENDIF WIN32} eContainerRef := IInterface(eContainer) as IwbContainerElementRef; Skip: Result := inherited _AddRef; end; function TwbElement._Release: Integer; label Skip; begin {$IFDEF WIN64} if LockedDec(eExternalRefs) = 0 then {$ENDIF WIN64} {$IFDEF WIN32} asm mov eax, -1 mov ecx, [Self] lock xadd dword ptr [ecx + eExternalRefs], eax cmp eax, 1 jne Skip end; {$ENDIF WIN32} eContainerRef := nil; Skip: Result := inherited _Release; end; {$D+} { TwbSubRecordArray } function TwbSubRecordArray.AddIfMissingInternal(const aElement: IwbElement; aAsNew, aDeepCopy: Boolean; const aPrefixRemove, aPrefix, aSuffix: string): IwbElement; var SelfRef : IwbContainerElementRef; i : Integer; begin if not wbEditAllowed then raise Exception.Create(GetName + ' can not be assigned.'); SelfRef := Self as IwbContainerElementRef; DoInit; Assert(Assigned(aElement.Def)); Assert(arcDef.Element.Equals(aElement.Def)); if arcSorted and not aAsNew then begin Assert(not arcSortInvalid); if FindBySortKey(aElement.SortKey[False], False,i) then begin Result := cntElements[i]; if aDeepCopy then Result.Assign(Low(Integer), aElement, False); Exit; end; end; if (csAsCreatedEmpty in cntStates) then begin SetModified(True); Assert(Length(cntElements)=1); Result := cntElements[0]; Exclude(cntStates, csAsCreatedEmpty); end else case arcDef.Element.DefType of dtSubRecord: Result := TwbSubRecord.Create(Self, arcDef.Element as IwbSubRecordDef); dtSubRecordArray: Result := TwbSubRecordArray.Create(Self, nil, Low(Integer), arcDef.Element as IwbSubRecordArrayDef); dtSubRecordStruct: Result := TwbSubRecordStruct.Create(Self, nil, Low(Integer), arcDef.Element as IwbSubRecordStructDef); else Assert(False); end; try Result.Assign(Low(Integer), aElement, not aDeepCopy); except Result.Container.RemoveElement(Result); Result := nil; raise; end; end; function TwbSubRecordArray.AssignInternal(aIndex: Integer; const aElement: IwbElement; aOnlySK: Boolean): IwbElement; var Element : IwbElement; Container : IwbContainer; i : Integer; SelfRef : IwbContainerElementRef; ElementDef : IwbRecordMemberDef; DataContainer : IwbDataContainer; begin Result := nil; if not wbEditAllowed then raise Exception.Create(GetName + ' can not be assigned.'); SelfRef := Self as IwbContainerElementRef; DoInit; if (aIndex = Low(Integer)) and arcDef.CanAssign(Self, aIndex, aElement.Def) then begin if aOnlySK then Exit; Container := aElement as IwbContainer; SetModified(True); InvalidateStorage; ReleaseElements; for i := 0 to Pred(Container.ElementCount) do Assign(i, Container.Elements[i], aOnlySK); end else if (aIndex >= 0) and (not Assigned(aElement) or arcDef.Element.CanAssign(Self, Low(Integer), aElement.Def)) or ((aIndex = Low(Integer)) and arcDef.Element.CanAssign(Self, aIndex, aElement.Def)) then begin Element := nil; if (csAsCreatedEmpty in cntStates) and Assigned(aElement) then begin SetModified(True); Assert(Length(cntElements)=1); Element := cntElements[0]; Exclude(cntStates, csAsCreatedEmpty); end else begin ElementDef := arcDef.Element; if ElementDef.DefType = dtSubRecordUnion then begin if Assigned(aElement) then begin Supports(aElement, IwbDataContainer, DataContainer); ElementDef := (ElementDef as IwbRecordDef).GetMemberFor((aElement as IwbHasSignature).Signature, DataContainer) end else ElementDef := (ElementDef as IwbRecordDef).Members[0]; Assert(Assigned(ElementDef)); end; case ElementDef.DefType of dtSubRecord: Element := TwbSubRecord.Create(Self, ElementDef as IwbSubRecordDef); dtSubRecordArray: Element := TwbSubRecordArray.Create(Self, nil, Low(Integer), ElementDef as IwbSubRecordArrayDef); dtSubRecordStruct: Element := TwbSubRecordStruct.Create(Self, nil, Low(Integer), ElementDef as IwbSubRecordStructDef); else Assert(False); end; end; if Assigned(Element) and Assigned(aElement) then try Element.Assign(Low(Integer), aElement, aOnlySK); if csAsCreatedEmpty in cntStates then Exclude(cntStates, csAsCreatedEmpty); except Element.Container.RemoveElement(Element); raise; end; Result := Element; end; arcSorted := False; if wbSortSubRecords and arcDef.Sorted[IwbContainer(eContainer)] then begin if Length(cntElements) > 1 then wbMergeSort(@cntElements[0], Length(cntElements), CompareSortKeys); arcSorted := True; end; end; function TwbSubRecordArray.CanAssignInternal(aIndex: Integer; const aElement: IwbElement; aCheckDontShow: Boolean): Boolean; begin Result := False; if not wbEditAllowed then Exit; if Assigned(eContainer) then if not IwbContainer(eContainer).IsElementEditable(Self) then Exit; if aCheckDontShow and GetDontShow then Exit; if not Assigned(aElement) then begin Result := aIndex >= 0; Exit; end; Result := arcDef.CanAssign(Self, aIndex, aElement.Def); if not Result then begin Result := arcDef.Element.CanAssign(Self, Low(Integer), aElement.Def); if Result then if aCheckDontShow and arcDef.Element.DontShow[aElement] then Result := False; end; end; function TwbSubRecordArray.CanContainFormIDs: Boolean; begin Result := arcDef.CanContainFormIDs; end; function TwbSubRecordArray.CanMoveElement: Boolean; begin Result := not arcSorted; end; function TwbSubRecordArray.CanElementReset: Boolean; begin // Result := inherited CanElementReset; Result := cntElementRefs < 1; end; constructor TwbSubRecordArray.Create(const aOwner : IwbContainer; const aContainer : IwbContainer; aPos : Integer; const aDef : IwbSubRecordArrayDef); begin arcDef := aDef; eContainer := Pointer(aOwner); try if aPos <> Low(Integer) then begin DoProcess(aContainer, aPos) end else begin Assign(High(Integer), nil, False); Include(cntStates, csAsCreatedEmpty); end; finally eContainer := nil; end; inherited Create(aOwner); if aPos = Low(Integer) then begin SetModified(True); InvalidateStorage; end; end; procedure TwbSubRecordArray.DoInit; begin inherited; if arcSorted and arcSortInvalid then begin if Length(cntElements) > 1 then wbMergeSort(@cntElements[0], Length(cntElements), CompareSortKeys); arcSortInvalid := False; end; end; procedure TwbSubRecordArray.DoProcess(const aContainer : IwbContainer; aPos : Integer); var SubRecord : IwbSubRecordInternal; ElementDef : IwbRecordMemberDef; Element : IwbElement; SelfRef : IwbContainerElementRef; begin SelfRef := Self; while (aPos < aContainer.ElementCount) and (aContainer[aPos].ElementType = etSubRecord) do begin SubRecord := aContainer[aPos] as IwbSubRecordInternal; ElementDef := arcDef.Element; if ElementDef.DefType = dtSubRecordUnion then begin ElementDef := (ElementDef as IwbRecordDef).GetMemberFor(SubRecord.Signature, SubRecord); if not Assigned(ElementDef) then Break; end; if not ElementDef.CanHandle(SubRecord.Signature, SubRecord) then Break; case ElementDef.DefType of dtSubRecord: begin aContainer.RemoveElement(aPos); SubRecord.SetDef(ElementDef as IwbSubRecordDef); AddElement(SubRecord); end; dtSubRecordArray: begin Element := TwbSubRecordArray.Create(Self, aContainer, aPos, ElementDef as IwbSubRecordArrayDef); end; dtSubRecordStruct: Element := TwbSubRecordStruct.Create(Self, aContainer, aPos, ElementDef as IwbSubRecordStructDef); else raise Exception.CreateFmt('Unexpected def type for SubRecord %s in array', [String(SubRecord.Signature)]); end; end; arcSorted := False; if wbSortSubRecords and arcDef.Sorted[aContainer] then begin arcSorted := True; arcSortInvalid := True; end; end; procedure TwbSubRecordArray.ElementChanged(const aElement: IwbElement; aContainer: Pointer); begin inherited; if arcSorted then arcSortInvalid := True; end; function TwbSubRecordArray.GetDef: IwbNamedDef; begin Result := arcDef; end; function TwbSubRecordArray.GetElementType: TwbElementType; begin Result := etSubRecordArray; end; function TwbSubRecordArray.GetName: string; begin Result := arcDef.GetName; end; function TwbSubRecordArray.GetSignature: TwbSignature; var i : Integer; lRecord : IwbRecord; SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; if GetElementCount > 0 then begin Assert(not arcSortInvalid); Result := NONE; for i := 0 to Pred(GetElementCount) do if Supports(GetElement(i), IwbRecord, lRecord) then begin Result := lRecord.Signature; Exit; end; end; end; function TwbSubRecordArray.GetSorted: Boolean; begin Result := arcSorted; end; function TwbSubRecordArray.IsElementRemoveable(const aElement: IwbElement): Boolean; begin Result := IsElementEditable(aElement) and (Length(cntElements) > 1); end; procedure TwbSubRecordArray.SetModified(aValue: Boolean); begin inherited; if aValue and arcSorted then arcSortInvalid := True; end; { TwbSubRecordStruct } function TwbSubRecordStruct.Add(const aName: string; aSilent: Boolean): IwbElement; var Signature : TwbSignature; Index : Integer; begin Result := nil; if not IsElementEditable(nil) then raise Exception.Create('"' + GetName + '" is not editable'); Result := nil; if Length(aName) < 4 then Exit; Signature := StrToSignature(aName); Result := GetElementBySignature(Signature); if Assigned(Result) then Exit; Index := srcDef.GetMemberIndexFor(Signature, nil); if Index >= 0 then Assign(Index, nil, False); Result := GetElementBySignature(Signature); Assert(Assigned(Result)); end; function TwbSubRecordStruct.AddIfMissingInternal(const aElement: IwbElement; aAsNew, aDeepCopy: Boolean; const aPrefixRemove, aPrefix, aSuffix: string): IwbElement; var SelfRef : IwbContainerElementRef; begin if not wbEditAllowed then raise Exception.Create(GetName + ' can not be assigned.'); SelfRef := Self as IwbContainerElementRef; DoInit; Assert(aElement.SortOrder >= 0); Assert(aElement.SortOrder < srcDef.MemberCount); Assert(Assigned(aElement.Def)); Assert(aElement.Def.Equals(srcDef.Members[aElement.SortOrder])); Result := GetElementBySortOrder(aElement.SortOrder + GetAdditionalElementCount); if not Assigned(Result) then begin Assign(aElement.SortOrder, aElement, not aDeepCopy); Result := GetElementBySortOrder(aElement.SortOrder + GetAdditionalElementCount); Assert(Assigned(Result)); if wbSortSubRecords and (Length(cntElements) > 1) then wbMergeSort(@cntElements[0], Length(cntElements), CompareSubRecords); end else Result.Assign(Low(Integer), aElement, not aDeepCopy); end; procedure TwbSubRecordStruct.AddRequiredElements; var CurrentDefPos : Integer; CurrentDef : IwbRecordMemberDef; Element : IwbElementInternal; begin for CurrentDefPos := 0 to Pred(srcDef.MemberCount) do begin CurrentDef := srcDef.Members[CurrentDefPos]; if ((CurrentDefPos = 0) and not srcDef.AllowUnordered) or CurrentDef.Required then begin if CurrentDef.DefType = dtSubRecordUnion then begin CurrentDef := (CurrentDef as IwbRecordDef).Members[0]; Assert(Assigned(CurrentDef)); end; case CurrentDef.DefType of dtSubRecord : Element := TwbSubRecord.Create(Self, CurrentDef as IwbSubRecordDef); dtSubRecordArray : Element := TwbSubRecordArray.Create(Self, nil, Low(Integer), CurrentDef as IwbSubRecordArrayDef); dtSubRecordStruct : Element := TwbSubRecordStruct.Create(Self, nil, Low(Integer), CurrentDef as IwbSubRecordStructDef); else Assert(False); end; Element.SetSortOrder(CurrentDefPos); Element.SetMemoryOrder(CurrentDefPos); end; end; end; function TwbSubRecordStruct.AssignInternal(aIndex: Integer; const aElement: IwbElement; aOnlySK: Boolean): IwbElement; var Member : IwbRecordMemberDef; Container : IwbContainer; Element : IwbElement; i : Integer; begin Result := nil; if not wbEditAllowed then raise Exception.Create(GetName + ' can not be assigned.'); if aIndex = Low(Integer) then begin Container := aElement as IwbContainer; SetModified(True); InvalidateStorage; ReleaseElements; AddRequiredElements; if Assigned(Container) then for i := 0 to Pred(Container.ElementCount) do begin Element := Container.Elements[i]; if not aOnlySK or GetIsInSK(Element.SortOrder) then Assign(Element.SortOrder, Element, aOnlySK); end; end else begin if (aIndex >= 0) and (aIndex < srcDef.MemberCount) then begin Member := srcDef.Members[aIndex]; if not Assigned(aElement) or Member.CanAssign(Self, Low(Integer), aElement.Def) then begin Element := GetElementBySortOrder(aIndex + GetAdditionalElementCount); if Assigned(Element) then begin if Assigned(aElement) then Element.Assign(Low(Integer), aElement, aOnlySK) end else begin case Member.DefType of dtSubRecord: Element := TwbSubRecord.Create(Self, Member as IwbSubRecordDef); dtSubRecordArray: Element := TwbSubRecordArray.Create(Self, nil, Low(Integer), Member as IwbSubRecordArrayDef); dtSubRecordStruct: Element := TwbSubRecordStruct.Create(Self, nil, Low(Integer), Member as IwbSubRecordStructDef); else Assert(False); end; if Assigned(Element) then try Element.SortOrder := aIndex; if Assigned(aElement) then Element.Assign(Low(Integer), aElement, aOnlySK); except Element.Container.RemoveElement(Element); raise; end; end; Result := Element; end; end; end; if wbSortSubRecords and (Length(cntElements) > 1) then wbMergeSort(@cntElements[0], Length(cntElements), CompareSubRecords); end; function TwbSubRecordStruct.CanAssignInternal(aIndex: Integer; const aElement: IwbElement; aCheckDontShow: Boolean): Boolean; begin Result := False; if not wbEditAllowed then Exit; if Assigned(eContainer) then if not IwbContainer(eContainer).IsElementEditable(Self) then Exit; if aCheckDontShow and GetDontShow then Exit; if not Assigned(aElement) then begin Result := (aIndex >= 0) and (aIndex < srcDef.MemberCount) and (GetElementBySortOrder(aIndex + GetAdditionalElementCount) = nil); if Result and aCheckDontShow then if srcDef.Members[aIndex].DontShow[Self] then Result := False; Exit; end; if Assigned(srcDef) then begin if aIndex = Low(Integer) then Result := srcDef.Equals(aElement.Def) else begin Result := (aIndex >= 0) and (aIndex < srcDef.MemberCount) and srcDef.Members[aIndex].CanAssign(Self, Low(Integer), aElement.Def); if Result and aCheckDontShow then if srcDef.Members[aIndex].DontShow[Self] then Result := False; end; end else Result := False; end; function TwbSubRecordStruct.CanContainFormIDs: Boolean; begin Result := srcDef.CanContainFormIDs; end; function TwbSubRecordStruct.CanElementReset: Boolean; begin // Result := inherited CanElementReset; Result := cntElementRefs < 1; end; constructor TwbSubRecordStruct.Create(const aOwner : IwbContainer; const aContainer : IwbContainer; aPos : Integer; const aDef : IwbSubRecordStructDef); var CurrentDefPos : Integer; CurrentRec : IwbSubRecordInternal; CurrentDef : IwbRecordMemberDef; Element : IwbElementInternal; begin srcDef := aDef as IwbRecordDef; if aPos = Low(Integer) then begin AddRequiredElements; end else begin CurrentDefPos := 0; while (aPos < aContainer.ElementCount) and (CurrentDefPos < srcDef.MemberCount) do begin if aContainer[aPos].ElementType <> etSubRecord then Break; CurrentRec := aContainer[aPos] as IwbSubRecordInternal; if not srcDef.ContainsMemberFor(CurrentRec.Signature, CurrentRec) then begin if srcDef.SkipSignature[CurrentRec.Signature] then begin Inc(aPos); Continue; end; Break; end; if srcDef.AllowUnordered then begin CurrentDefPos := srcDef.GetMemberIndexFor(CurrentRec.Signature, CurrentRec); if CurrentDefPos < 0 then begin if Assigned(wbProgressCallback) then wbProgressCallback('Error: record '+ String(GetSignature) + ' contains unexpected (or out of order) subrecord ' + String(CurrentRec.Signature) + ' ' + IntToHex(Int64(Cardinal(CurrentRec.Signature)), 8) ); //FoundError := True; Inc(aPos); Continue; end; CurrentDef := srcDef.Members[CurrentDefPos]; end; CurrentDef := srcDef.Members[CurrentDefPos]; if not CurrentDef.CanHandle(CurrentRec.Signature, CurrentRec) then begin Inc(CurrentDefPos); Continue; end; if CurrentDef.DefType = dtSubRecordUnion then begin CurrentDef := (CurrentDef as IwbRecordDef).GetMemberFor(CurrentRec.Signature, CurrentRec); Assert(Assigned(CurrentDef)); end; case CurrentDef.DefType of dtSubRecord : begin aContainer.RemoveElement(aPos); CurrentRec.SetDef(CurrentDef as IwbSubRecordDef); AddElement(CurrentRec); Element := CurrentRec as IwbElementInternal; end; dtSubRecordArray : Element := TwbSubRecordArray.Create(Self, aContainer, aPos, CurrentDef as IwbSubRecordArrayDef); dtSubRecordStruct : Element := TwbSubRecordStruct.Create(Self, aContainer, aPos, CurrentDef as IwbSubRecordStructDef); else raise Exception.CreateFmt('Unexpected def type for SubRecord %s', [String(CurrentRec.Signature)]); end; Element.SetSortOrder(CurrentDefPos); Element.SetMemoryOrder(CurrentDefPos); Inc(CurrentDefPos); end; end; srcDef.AfterLoad(Self); inherited Create(aOwner); if aPos = Low(Integer) then begin SetModified(True); InvalidateStorage; end; end; function TwbSubRecordStruct.GetDef: IwbNamedDef; begin Result := srcDef; end; function TwbSubRecordStruct.GetElementType: TwbElementType; begin Result := etSubRecordStruct; end; function TwbSubRecordStruct.GetIsInSK(aIndex: Integer): Boolean; var SelfRef : IwbContainerElementRef; HasSortKey : IwbHasSortKeyDef; begin Result := False; SelfRef := Self as IwbContainerElementRef; DoInit; if not Supports(srcDef, IwbHasSortKeyDef, HasSortKey) then Exit; Result := HasSortKey.IsInSK(aIndex); end; function TwbSubRecordStruct.GetName: string; begin Result := srcDef.GetName; end; function TwbSubRecordStruct.GetSignature: TwbSignature; var i : Integer; lRecord : IwbRecord; SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; Result := NONE; for i := 0 to Pred(GetElementCount) do if Supports(GetElement(i), IwbRecord, lRecord) then begin Result := lRecord.Signature; Exit; end; end; function TwbSubRecordStruct.GetSortKeyInternal(aExtended: Boolean): string; var HasSortKey : IwbHasSortKeyDef; SortMember : Integer; Element : IwbElement; i : Integer; SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; Result := ''; if Supports(srcDef, IwbHasSortKeyDef, HasSortKey) then begin DoInit; if HasSortKey.SortKeyCount[False] > 0 then for i := 0 to Pred(HasSortKey.SortKeyCount[aExtended]) do begin SortMember := HasSortKey.SortKeys[i, aExtended]; Element := GetElementBySortOrder(SortMember + GetAdditionalElementCount); if Assigned(Element) then Result := Result + Element.SortKey[aExtended]; if i < Pred(HasSortKey.SortKeyCount[aExtended]) then Result := Result + '|'; end; end; end; function TwbSubRecordStruct.IsElementRemoveable(const aElement: IwbElement): Boolean; begin Result := IsElementEditable(aElement) and (Length(cntElements) > 1) and (srcDef.AllowUnordered or not cntElements[0].Equals(aElement)); if Result and Assigned(aElement.Def) then Result := not aElement.Def.Required; end; function TwbSubRecordStruct.RemoveInjected(aCanRemove: Boolean): Boolean; var Element : IwbElement; Container : IwbContainerElementRef; SelfRef : IwbContainerElementRef; i : Integer; begin if SameText(GetName, 'Result Script') then begin Result := False; SelfRef := Self as IwbContainerElementRef; DoInit; if Supports(GetElementByName('References'), IwbContainerElementRef, Container) then for i := 0 to Pred(Container.ElementCount) do begin Result := Container.Elements[i].ReferencesInjected; if Result then Break; end; if Result then begin Result := False; Container.Remove; Element := GetRecordBySignature('SCHD'); if Assigned(Element) then Element.Remove; Element := GetRecordBySignature('SCDA'); if Assigned(Element) then Element.Remove; Element := GetRecordBySignature('SCTX'); if Assigned(Element) then Element.Remove; if Supports(GetRecordBySignature('SCHR'), IwbContainerElementRef, Container) then begin Container.ElementByName['RefCount'].EditValue := '0'; Container.ElementByName['CompiledSize'].EditValue := '0'; Container.ElementByName['VariableCount'].EditValue := '0'; end; end; end else Result := inherited RemoveInjected(aCanRemove); end; function ArrayDoInit(const aValueDef: IwbValueDef; const aContainer: IwbContainer; var aBasePtr: Pointer; aEndPtr: Pointer; out SizePrefix: Integer): Boolean; var Element : IwbElement; ArrayDef : IwbArrayDef; ValueDef : IwbValueDef; i : Integer; t : string; VarSize : Boolean; ArrSize : Integer; begin ArrayDef := aValueDef as IwbArrayDef; Result := wbSortSubRecords and ArrayDef.Sorted; if not ArrayDef.CanAddTo then aContainer.SetElementState(esNotSuitableToAddTo); SizePrefix := ArrayDef.PrefixSize[aBasePtr]; i := 0; ValueDef := ArrayDef.Element; VarSize := ArrayDef.IsVariableSize; ArrSize := ArrayDef.ElementCount; if ArrSize < 0 then begin ArrSize := ArrayDef.PrefixCount[aBasePtr]; end else if (ArrSize < 1) and Assigned(ArrayDef.CountCallback) then ArrSize := ArrayDef.CountCallback(aBasePtr, aEndPtr, aContainer) else if VarSize then ArrSize := High(Integer); if Assigned(aBasePtr) then Inc(PByte(aBasePtr), SizePrefix); if ArrSize > 0 then while not VarSize or ((Cardinal(aBasePtr) < Cardinal(aEndPtr)) or (not Assigned(aBasePtr))) do begin if Result then t := '' else begin t := ArrayDef.ElementLabel[i]; if t <> '' then t := ' (' + t + ')'; t := '#' + IntToStr(i) + t; end; case ValueDef.DefType of dtArray: Element := TwbArray.Create(aContainer, aBasePtr, aEndPtr, ValueDef, t); dtStruct: Element := TwbStruct.Create(aContainer, aBasePtr, aEndPtr, ValueDef, t); dtStructChapter: Element := TwbChapter.Create(aContainer, aBasePtr, aEndPtr, ValueDef, t); dtUnion: Element := TwbUnion.Create(aContainer, aBasePtr, aEndPtr, ValueDef, t); dtString: begin if Assigned(aBasePtr) and (PAnsiChar(aBasePtr)^ = #0) and (ValueDef.IsVariableSize) then begin Inc(PByte(aBasePtr)); Break; end; Element := TwbValue.Create(aContainer, aBasePtr, aEndPtr, ValueDef, t); end; else Element := TwbValue.Create(aContainer, aBasePtr, aEndPtr, ValueDef, t); end; Inc(i); if VarSize and not Assigned(aBasePtr) then begin (aContainer as IwbContainerInternal).CreatedEmpty; Break; end; Dec(ArrSize); if ArrSize = 0 then Break { else if not (not VarSize or ((Cardinal(aBasePtr) < Cardinal(aEndPtr)) or (not Assigned(aBasePtr)))) then wbProgressCallback('Error: not enough data for array. Elements remaining are '+IntToStr(ArrSize)) Silently fails = called at an invalid time }; end; if (ValueDef.DefType = dtString) and (ValueDef.IsVariableSize) then Element := TwbStringListTerminator.Create(aContainer); ArrayDef.AfterLoad(aContainer); end; { TwbArray } procedure TwbArray.Init; var BasePtr: Pointer; begin inherited; if GetSkipped then Exit; BasePtr := GetDataBasePtr; arrSorted := ArrayDoInit(vbValueDef, Self, BasePtr, dcDataEndPtr, arrSizePrefix); arrSortInvalid := arrSorted; end; function TwbArray.AddIfMissingInternal(const aElement: IwbElement; aAsNew, aDeepCopy: Boolean; const aPrefixRemove, aPrefix, aSuffix: string): IwbElement; var SelfRef : IwbContainerElementRef; i : Integer; s : string; ArrayDef : IwbArrayDef; begin if not wbEditAllowed then raise Exception.Create(GetName + ' can not be modified.'); SelfRef := Self as IwbContainerElementRef; DoInit; ArrayDef := vbValueDef as IwbArrayDef; if arrSorted then begin Assert(not arrSortInvalid); if FindBySortKey(aElement.SortKey[False], False, i) then begin Result := cntElements[i]; if aDeepCopy then Result.Assign(Low(Integer), aElement, False); Exit; end; end; if arrSorted then s := '' else s := '#' + IntToStr(Length(cntElements)); if not Supports(aElement, IwbStringListTerminator) then case ArrayDef.Element.DefType of dtArray: Result := TwbArray.Create(Self, ArrayDef.Element, aElement, not aDeepCopy, s); dtStruct: Result := TwbStruct.Create(Self, ArrayDef.Element, aElement, not aDeepCopy, s); dtStructChapter: Result := TwbChapter.Create(Self, ArrayDef.Element, aElement, not aDeepCopy, s); dtUnion: Result := TwbUnion.Create(Self, ArrayDef.Element, aElement, not aDeepCopy, s); else Result := TwbValue.Create(Self, ArrayDef.Element, aElement, not aDeepCopy, s); end; CheckCount; CheckTerminator; end; function TwbArray.AssignInternal(aIndex: Integer; const aElement: IwbElement; aOnlySK: Boolean): IwbElement; var Element : IwbElement; sElement : IwbElement; dElement : IwbElement; ArrayDef : IwbArrayDef; Container : IwbContainer; DataContainer : IwbDataContainer; s : string; i : Integer; SelfRef : IwbContainerElementRef; p, q : Pointer; begin Result := nil; if not wbEditAllowed then raise Exception.Create(GetName + ' can not be assigned.'); SelfRef := Self as IwbContainerElementRef; DoInit; ArrayDef := vbValueDef as IwbArrayDef; if (aIndex = Low(Integer)) and ArrayDef.CanAssign(Self, aIndex, aElement.ValueDef) then begin if aOnlySK then Exit; Container := aElement as IwbContainer; if ArrayDef.IsVariableSize then begin Assert(ArrayDef.ElementCount <= 0); SetModified(True); InvalidateStorage; ReleaseElements; dcDataStorage := nil; dcDataBasePtr := @EmptyPtr; dcDataEndPtr := @EmptyPtr; Exclude(dcFlags, dcfStorageInvalid); if ArrayDef.ElementCount < 0 then if aElement.DataSize > 0 then begin RequestStorageChange(p, q, aElement.DataSize); if Supports(aElement, IwbDataContainer, DataContainer) then begin q := DataContainer.DataBasePtr; Move(q^, p^, aElement.DataSize); end; end else RequestStorageChange(p, q, ArrayDef.PrefixSize[nil]); NotifyChanged(eContainer); for i := 0 to Pred(Container.ElementCount) do Assign(i, Container.Elements[i], aOnlySK); end else begin Assert(Container.ElementCount = ArrayDef.ElementCount); Assert(GetElementCount = ArrayDef.ElementCount); for i := 0 to Pred(Container.ElementCount) do begin sElement := Container.Elements[i]; dElement := GetElementByMemoryOrder(i); dElement.Assign(Low(Integer), sElement, aOnlySK); end; end; end else begin if (aIndex >= 0) and (ArrayDef.ElementCount <= 0) and ((aIndex = High(Integer)) or ArrayDef.Element.CanAssign(Self, Low(Integer), aElement.ValueDef)) then begin {add one entry} if arrSorted then s := '' else s := '#' + IntToStr(Length(cntElements)); Element := nil; if not Supports(aElement, IwbStringListTerminator) then case ArrayDef.Element.DefType of dtArray: Element := TwbArray.Create(Self, ArrayDef.Element, aElement, aOnlySK, s); dtStruct: Element := TwbStruct.Create(Self, ArrayDef.Element, aElement, aOnlySK, s); dtStructChapter: Element := TwbChapter.Create(Self, ArrayDef.Element, aElement, aOnlySK, s); dtUnion: Element := TwbUnion.Create(Self, ArrayDef.Element, aElement, aOnlySK, s); else Element := TwbValue.Create(Self, ArrayDef.Element, aElement, aOnlySK, s); end; Result := Element; end; end; CheckCount; CheckTerminator; end; function TwbArray.CanAssignInternal(aIndex: Integer; const aElement: IwbElement; aCheckDontShow: Boolean): Boolean; var ArrayDef: IwbArrayDef; begin Result := False; if not wbEditAllowed then Exit; if Assigned(eContainer) then if not IwbContainer(eContainer).IsElementEditable(Self) then Exit; if aCheckDontShow and GetDontShow then Exit; ArrayDef := vbValueDef as IwbArrayDef; if not Assigned(aElement) then begin if aIndex = High(Integer) then Result := ArrayDef.ElementCount <= 0; Exit; end; Result := ArrayDef.CanAssign(Self, aIndex, aElement.ValueDef) or ( (ArrayDef.ElementCount <= 0) and ArrayDef.Element.CanAssign(Self, Low(Integer), aElement.ValueDef) ); end; function TwbArray.CanMoveElement: Boolean; begin Result := not arrSorted; end; procedure TwbArray.CheckCount; var Count : Cardinal; i : Integer; UpdateCount : Integer; ArrayDef : IwbArrayDef; begin if arrSizePrefix = 0 then Exit; ArrayDef := vbValueDef as IwbArrayDef; Count := arrayDef.PrefixCount[dcDataBasePtr]; DoInit; if Count <> Length(cntElements) then begin UpdateCount := eUpdateCount; for i := 1 to UpdateCount do EndUpdate; // Stops optimisation ArrayDef.SetPrefixCount(dcDataBasePtr, Length(cntElements)); for i := 1 to UpdateCount do BeginUpdate; // Restore optimisation end; end; procedure TwbArray.CheckTerminator; var i : Integer; ArrayDef : IwbArrayDef; begin ArrayDef := vbValueDef as IwbArrayDef; if not ArrayDef.IsVariableSize then Exit; if ArrayDef.Element.DefType <> dtString then Exit; for i := Low(cntElements) to High(cntElements) do if Supports(cntElements[i], IwbStringListTerminator) then Exit; SetModified(True); InvalidateStorage; TwbStringListTerminator.Create(Self); if arrSorted then arrSortInvalid := True; end; procedure TwbArray.DoInit; var i : Integer; Sorting : Boolean; begin inherited; if arrSorted and arrSortInvalid then if (Length(cntElements) > 1) then begin Sorting := False; for i := 0 to Length(cntElements)-1 do if (esSorting in (cntElements[i] as IwbElementInternal).ElementStates) then begin Sorting := TRue; Break; end; if not Sorting then begin wbMergeSort(@cntElements[0], Length(cntElements), CompareSortKeys); arrSortInvalid := False; end; end; end; procedure TwbArray.ElementChanged(const aElement: IwbElement; aContainer: Pointer); begin inherited; if arrSorted then arrSortInvalid := True; end; function TwbArray.GetDataPrefixSize: Integer; begin Result := arrSizePrefix; end; function TwbArray.GetElementType: TwbElementType; begin Result := etArray; end; function TwbArray.GetSorted: Boolean; begin Result := arrSorted; end; function TwbArray.IsElementRemoveable(const aElement: IwbElement): Boolean; begin Result := IsElementEditable(aElement) and ((vbValueDef as IwbArrayDef).ElementCount <= 0) { and (Length(cntElements)>1)}; end; procedure TwbArray.PrepareSave; begin CheckCount; CheckTerminator; inherited; end; procedure TwbArray.Reset; begin ReleaseElements; arrSorted := False; arrSortInvalid := False; inherited; end; procedure TwbArray.SetModified(aValue: Boolean); begin inherited; if aValue and arrSorted then arrSortInvalid := True; end; { TwbStruct } procedure StructDoInit(const aValueDef: IwbValueDef; const aContainer: IwbContainer; var aBasePtr: Pointer; aEndPtr: Pointer); var StructDef : IwbStructDef; i : Integer; ValueDef : IwbValueDef; Element : IwbElementInternal; IntegerDef : IwbIntegerDef; OptionalFromElement : Integer; Size : Integer; over : Boolean; begin StructDef := aValueDef as IwbStructDef; OptionalFromElement := StructDef.OptionalFromElement; if OptionalFromElement < 0 then OptionalFromElement := High(Integer); for i := 0 to Pred(StructDef.MemberCount) do begin ValueDef := StructDef.Members[i]; if Assigned(aBasePtr) and (i >= OptionalFromElement) then begin over := (Cardinal(aBasePtr) >= Cardinal(aEndPtr)); if not over then begin Size := ValueDef.Size[aBasePtr, aEndPtr, aContainer]; over := (Size Cardinal(aEndPtr)); end; if over then begin aEndPtr := aBasePtr; ValueDef := Resolve(ValueDef, aBasePtr, aEndPtr, aContainer); if Supports(ValueDef, IwbIntegerDef, IntegerDef) and Supports(IntegerDef.Formater[aContainer], IwbFlagsDef) then ValueDef := wbEmpty(ValueDef.Name, cpIgnore, False, nil, True) else ValueDef := wbEmpty(ValueDef.Name, cpIgnore); end; end; case ValueDef.DefType of dtArray: Element := TwbArray.Create(aContainer, aBasePtr, aEndPtr, ValueDef, ''); dtStruct: Element := TwbStruct.Create(aContainer, aBasePtr, aEndPtr, ValueDef, ''); dtStructChapter: Element := TwbChapter.Create(aContainer, aBasePtr, aEndPtr, ValueDef, ''); dtUnion: Element := TwbUnion.Create(aContainer, aBasePtr, aEndPtr, ValueDef, ''); else Element := TwbValue.Create(aContainer, aBasePtr, aEndPtr, ValueDef, ''); end; {if wbHideUnused and not wbEditAllowed and (Element.GetName = 'Unused') then begin with aContainer do begin Assert((LastElement as IwbElementInternal) = Element); RemoveElement(Pred(ElementCount)); end; end else} begin Element.SetSortOrder(i); Element.SetMemoryOrder(i); end; end; StructDef.AfterLoad(aContainer); end; procedure TwbStruct.Init; var BasePtr: Pointer; begin inherited; if GetSkipped then Exit; DecompressIfNeeded; BasePtr := GetDataBasePtr; StructDoInit(vbValueDef, Self, BasePtr, dcDataEndPtr); end; function TwbStruct.GetElementType: TwbElementType; begin Result := etStruct; end; procedure TwbStruct.Reset; begin ReleaseElements; inherited; end; procedure TwbStruct.DecompressIfNeeded; var sc : TwbStructCompression; begin sc := IsCompressed; if sc <> scNone then try InitDataPtr; // reset... SetLength(dcDataStorage, szUncompressedSize ); case sc of scNone: Assert(False); // Getting there would be very funny :) scZComp: DecompressToUserBuf( Pointer(Cardinal(dcDataBasePtr)), GetDataSize, @dcDataStorage[0], PCardinal(dcDataBasePtr)^ ); scLZComp: LZ4_decompress_safe(Pointer(Cardinal(dcDataBasePtr)), @dcDataStorage[0], GetDataSize, szUncompressedSize); else Assert(False); // Something hasn't been updated yet. end; dcDataEndPtr := Pointer( Cardinal(@dcDataStorage[0]) + szUncompressedSize ); dcDataBasePtr := @dcDataStorage[0]; except dcDataBasePtr := nil; dcDataEndPtr := nil; end; end; function TwbStruct.GetIsCompressed: TwbStructCompression; var szDef : IwbStructZDef; lzDef : IwbStructLZDef; begin if (szCompressedSize = 0) then if Supports(vbValueDef, IwbStructZDef, szDef) then begin szUncompressedSize := szDef.GetSizing(GetDataBasePtr, GetDataEndPtr, Self, szCompressedSize); if szUncompressedSize <> 0 then szCompressedType := scZComp; end else if Supports(vbValueDef, IwbStructLZDef, lzDef) then begin szUncompressedSize := lzDef.GetSizing(GetDataBasePtr, GetDataEndPtr, Self, szCompressedSize); if szUncompressedSize <> 0 then szCompressedType := scLZComp; end else szCompressedSize := -1; Result := szCompressedType; end; { TwbUnion } function UnionDoInit(const aValueDef: IwbValueDef; const aContainer: IwbContainer; var aBasePtr: Pointer; aEndPtr: Pointer): TwbUnionFlags; var UnionDef : IwbUnionDef; ValueDef : IwbValueDef; ArrayDef : IwbArrayDef; Element : IwbElementInternal; begin Result := ufNone; UnionDef := aValueDef as IwbUnionDef; ValueDef := UnionDef.Decide(aBasePtr, aEndPtr, aContainer); if Assigned(ValueDef) then // I had one case. Most likely due to an error in wbXXXXDefinitions case ValueDef.DefType of dtArray: begin if wbSortSubRecords and Supports(ValueDef, IwbArrayDef, ArrayDef) and ArrayDef.Sorted then Result := ufSortedArray else Result := ufArray; Element := TwbArray.Create(aContainer, aBasePtr, aEndPtr, ValueDef, ''); end; dtStruct: Element := TwbStruct.Create(aContainer, aBasePtr, aEndPtr, ValueDef, ''); dtStructChapter: Element := TwbChapter.Create(aContainer, aBasePtr, aEndPtr, ValueDef, ''); dtUnion: Element := TwbUnion.Create(aContainer, aBasePtr, aEndPtr, ValueDef, ''); else Element := nil; // >>> so that simple union behave as they did <<< TwbValue.Create(aContainer, aBasePtr, aEndPtr, ValueDef, ''); if ValueDoInit(aValueDef, aContainer, aBasePtr, aEndPtr, aContainer) then Result := ufFlags; end; if Assigned(Element) then begin Element.SetSortOrder(0); Element.SetMemoryOrder(0); end; UnionDef.AfterLoad(aContainer); end; function TwbUnion.CompareExchangeFormID(aOldFormID, aNewFormID: Cardinal): Boolean; var SelfRef : IwbContainerElementRef; ResolvedDef : IwbValueDef; begin SelfRef := Self as IwbContainerElementRef; DoInit; Result := inherited CompareExchangeFormID(aOldFormID, aNewFormID); ResolvedDef := Resolve(vbValueDef, GetDataBasePtr, dcDataEndPtr, Self); if Assigned(ResolvedDef) then Result := ResolvedDef.CompareExchangeFormID(GetDataBasePtr, dcDataEndPtr, Self, aOldFormID, aNewFormID) or Result; end; function TwbUnion.GetElementType: TwbElementType; begin Result := etUnion; end; procedure TwbUnion.Init; var BasePtr: Pointer; begin inherited; if GetSkipped then Exit; BasePtr := GetDataBasePtr; UnionDoInit(vbValueDef, Self, BasePtr, dcDataEndPtr); end; procedure TwbUnion.MasterCountUpdated(aOld, aNew: Byte); var SelfRef : IwbContainerElementRef; ResolvedDef : IwbValueDef; begin SelfRef := Self as IwbContainerElementRef; DoInit; inherited MasterCountUpdated(aOld, aNew); ResolvedDef := Resolve(vbValueDef, GetDataBasePtr, dcDataEndPtr, Self); if Assigned(ResolvedDef) then ResolvedDef.MasterCountUpdated(GetDataBasePtr, dcDataEndPtr, Self, aOld, aNew); end; procedure TwbUnion.MasterIndicesUpdated(const aOld, aNew: TBytes); var SelfRef : IwbContainerElementRef; ResolvedDef : IwbValueDef; begin SelfRef := Self as IwbContainerElementRef; DoInit; inherited MasterIndicesUpdated(aOld, aNew); ResolvedDef := Resolve(vbValueDef, GetDataBasePtr, dcDataEndPtr, Self); if Assigned(ResolvedDef) then ResolvedDef.MasterIndicesUpdated(GetDataBasePtr, dcDataEndPtr, Self, aOld, aNew); end; procedure TwbUnion.FindUsedMasters(aMasters: PwbUsedMasters); var SelfRef : IwbContainerElementRef; ResolvedDef : IwbValueDef; begin SelfRef := Self as IwbContainerElementRef; DoInit; inherited FindUsedMasters(aMasters); ResolvedDef := Resolve(vbValueDef, GetDataBasePtr, dcDataEndPtr, Self); if Assigned(ResolvedDef) then ResolvedDef.FindUsedMasters(GetDataBasePtr, dcDataEndPtr, Self, aMasters); end; procedure TwbUnion.Reset; begin ReleaseElements; inherited; end; { TwbValue } function TwbValue.AddIfMissingInternal(const aElement : IwbElement; aAsNew : Boolean; aDeepCopy : Boolean; const aPrefixRemove : string; const aPrefix : string; const aSuffix : string) : IwbElement; var Flag : IwbFlag; IntegerDef : IwbIntegerDef; FlagsDef : IwbFlagsDef; s : string; begin if vIsFlags and Supports(aElement, IwbFlag, Flag) then if Supports(vbValueDef, IwbIntegerDef, IntegerDef) then if Supports(IntegerDef.Formater[Self], IwbFlagsDef, FlagsDef) then if FlagsDef.CanAssign(Self, Low(Integer), Flag.FlagsDef) then begin s := GetEditValue; s := s + StringOfChar('0', 64 - Length(s)); if (Flag.FlagIndex >= 0) and (Flag.FlagIndex < Length(s)) then begin s[Succ(Flag.FlagIndex)] := '1'; SetEditValue(s); Exit(GetElementBySortOrder(Flag.FlagIndex)); end; end; Result := inherited AddIfMissingInternal(aElement, aAsNew, aDeepCopy, aPrefixRemove, aPrefix, aSuffix) end; function TwbValue.CompareExchangeFormID(aOldFormID, aNewFormID: Cardinal): Boolean; var SelfRef : IwbContainerElementRef; ResolvedDef : IwbValueDef; begin SelfRef := Self as IwbContainerElementRef; DoInit; Result := inherited CompareExchangeFormID(aOldFormID, aNewFormID); ResolvedDef := Resolve(vbValueDef, GetDataBasePtr, dcDataEndPtr, Self); if Assigned(ResolvedDef) then Result := ResolvedDef.CompareExchangeFormID(GetDataBasePtr, dcDataEndPtr, Self, aOldFormID, aNewFormID) or Result; end; function ValueDoInit(const aValueDef: IwbValueDef; const aContainer: IwbContainer; var aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Boolean; var IntegerDef : IwbIntegerDef; FlagsDef : IwbFlagsDef; i : Cardinal; j : Cardinal; t : string; BasePtr : Pointer; Element : IwbElement; ValueDef : IwbValueDef; begin Result := False; ValueDef := Resolve(aValueDef, aBasePtr, aEndPtr, aElement); if Assigned(ValueDef) then begin if wbFlagsAsArray then if Supports(ValueDef, IwbIntegerDef, IntegerDef) then if Supports(IntegerDef.Formater[aElement], IwbFlagsDef, FlagsDef) then begin if Assigned(aBasePtr) and (FlagsDef.FlagCount > 0) then begin j := IntegerDef.ToInt(aBasePtr, aEndPtr, aContainer); if j <> 0 then for i := 0 to Pred(FlagsDef.FlagCount) do if (j and (Cardinal(1) shl i)) <> 0 then begin t := FlagsDef.Flags[i]; if (t <> '') and (not wbHideUnused or not SameText(t,'Unused')) then Element := TwbFlag.Create(aContainer, aBasePtr, aEndPtr, IntegerDef, FlagsDef, i); j := j and not (Cardinal(1) shl i); if j = 0 then Break; end; end; Result := True; end; ValueDef.AfterLoad(aContainer); end; if wbMoreInfoForUnknown then begin if Assigned(ValueDef) then t := ValueDef.Name else t := ''; if t = '' then t := aContainer.Def.Name; if SameText(t, 'Unknown') and (not Assigned(aBasePtr) or (aBasePtr <> aEndPtr)) then for i := 0 to 3 do begin BasePtr := Pointer( Cardinal(aBasePtr) + i ); Element := TwbArray.Create(aContainer, BasePtr, aEndPtr, wbArray('Offset '+IntToStr(i)+' AsU8', wbInteger('AsU8', itU8)), '', True); BasePtr := Pointer( Cardinal(aBasePtr) + i ); Element := TwbArray.Create(aContainer, BasePtr, aEndPtr, wbArray('Offset '+IntToStr(i)+' AsS8', wbInteger('AsS8', itS8)), '', True); BasePtr := Pointer( Cardinal(aBasePtr) + i ); Element := TwbArray.Create(aContainer, BasePtr, aEndPtr, wbArray('Offset '+IntToStr(i)+' AsU16', wbInteger('AsU16', itU16)), '', True); BasePtr := Pointer( Cardinal(aBasePtr) + i ); Element := TwbArray.Create(aContainer, BasePtr, aEndPtr, wbArray('Offset '+IntToStr(i)+' AsS16', wbInteger('AsS16', itS16)), '', True); BasePtr := Pointer( Cardinal(aBasePtr) + i ); Element := TwbArray.Create(aContainer, BasePtr, aEndPtr, wbArray('Offset '+IntToStr(i)+' AsU32', wbInteger('AsU32', itU32)), '', True); BasePtr := Pointer( Cardinal(aBasePtr) + i ); Element := TwbArray.Create(aContainer, BasePtr, aEndPtr, wbArray('Offset '+IntToStr(i)+' AsS32', wbInteger('AsS32', itS32)), '', True); BasePtr := Pointer( Cardinal(aBasePtr) + i ); Element := TwbArray.Create(aContainer, BasePtr, aEndPtr, wbArray('Offset '+IntToStr(i)+' AsS64', wbInteger('AsS64', itS64)), '', True); BasePtr := Pointer( Cardinal(aBasePtr) + i ); Element := TwbArray.Create(aContainer, BasePtr, aEndPtr, wbArray('Offset '+IntToStr(i)+' AsFormID', wbInteger('AsFormID', itU32, wbFormID)), '', True); BasePtr := Pointer( Cardinal(aBasePtr) + i ); Element := TwbArray.Create(aContainer, BasePtr, aEndPtr, wbArray('Offset '+IntToStr(i)+' AsChar4', wbInteger('AsChar4', itU32, wbChar4)), '', True); BasePtr := Pointer( Cardinal(aBasePtr) + i ); Element := TwbArray.Create(aContainer, BasePtr, aEndPtr, wbArray('Offset '+IntToStr(i)+' AsFloat', wbFloat('AsFloat')), '', True); BasePtr := Pointer( Cardinal(aBasePtr) + i ); Element := TwbArray.Create(aContainer, BasePtr, aEndPtr, wbArray('Offset '+IntToStr(i)+' AsString', wbString('AsString')), '', True); if wbToolSource in [tsSaves] then begin BasePtr := Pointer( Cardinal(aBasePtr) + i ); Element := TwbArray.Create(aContainer, BasePtr, aEndPtr, wbArray('Offset '+IntToStr(i)+' AsRefID', wbRefID('RefID')), '', True); BasePtr := Pointer( Cardinal(aBasePtr) + i ); Element := TwbArray.Create(aContainer, BasePtr, aEndPtr, wbArray('Offset '+IntToStr(i)+' AsU6to30', wbInteger('AsU6to30', itU6to30)), '', True); end; end; end; if assigned(ValueDef) then i := ValueDef.Size[aBasePtr, aEndPtr, aContainer] else i := High(Integer); if i = Cardinal(High(Integer)) then aBasePtr := aEndPtr else if Assigned(aBasePtr) then Inc(PByte(aBasePtr), i); end; procedure TwbValue.Init; var BasePtr: Pointer; begin inherited; BasePtr := GetDataBasePtr; vIsFlags := ValueDoInit(vbValueDef, Self, BasePtr, dcDataEndPtr, Self); // flags should already have been created in the right order, no need to sort them // if vIsFlags then // if Length(cntElements) > 1 then // wbMergeSort(@cntElements[0], Length(cntElements), CompareSortKeys); end; function TwbValue.IsFlags: Boolean; begin Result := vIsFlags; end; procedure TwbValue.MasterCountUpdated(aOld, aNew: Byte); var SelfRef : IwbContainerElementRef; ResolvedDef : IwbValueDef; begin SelfRef := Self as IwbContainerElementRef; DoInit; inherited MasterCountUpdated(aOld, aNew); ResolvedDef := Resolve(vbValueDef, GetDataBasePtr, dcDataEndPtr, Self); if Assigned(ResolvedDef) then ResolvedDef.MasterCountUpdated(GetDataBasePtr, dcDataEndPtr, Self, aOld, aNew); end; procedure TwbValue.MasterIndicesUpdated(const aOld, aNew: TBytes); var SelfRef : IwbContainerElementRef; ResolvedDef : IwbValueDef; begin SelfRef := Self as IwbContainerElementRef; DoInit; inherited MasterIndicesUpdated(aOld, aNew); ResolvedDef := Resolve(vbValueDef, GetDataBasePtr, dcDataEndPtr, Self); if Assigned(ResolvedDef) then ResolvedDef.MasterIndicesUpdated(GetDataBasePtr, dcDataEndPtr, Self, aOld, aNew); end; procedure TwbValue.FindUsedMasters(aMasters: PwbUsedMasters); var SelfRef : IwbContainerElementRef; ResolvedDef : IwbValueDef; begin SelfRef := Self as IwbContainerElementRef; DoInit; inherited FindUsedMasters(aMasters); ResolvedDef := Resolve(vbValueDef, GetDataBasePtr, dcDataEndPtr, Self); if Assigned(ResolvedDef) then ResolvedDef.FindUsedMasters(GetDataBasePtr, dcDataEndPtr, Self, aMasters); end; function TwbValue.GetElementType: TwbElementType; begin Result := etValue; end; function TwbValue.GetSorted: Boolean; var EmptyDef: IwbEmptyDef; begin Result := vIsFlags or (Supports(Resolve(vbValueDef, GetDataBasePtr, GetDataEndPtr, Self), IwbEmptyDef, EmptyDef) and EmptyDef.Sorted); end; function TwbValue.GetValue: string; //var // i : Integer; // j : Int64; var Def: IwbDef; begin if wbReportMode then begin Def := GetValueDef; if Assigned(Def) then Def.Used; Def := GetDef; if Assigned(Def) then Def.Used; end; { if vIsFlags then begin Result := ''; with (vbValueDef as IwbIntegerDef), (Formater as IwbFlagsDef) do begin j := ToInt(GetDataBasePtr, dcDataEndPtr, Self); for i := 0 to 63 do if (j and (Int64(1) shl i)) <> 0 then if (i >= FlagCount) or (Flags[i] = '') then Result := Result + ', '; end; SetLength(Result, Length(Result) - 2); end else} Result := inherited GetValue; end; procedure TwbValue.Reset; begin vIsFlags := False; ReleaseElements; inherited; end; procedure TwbValue.SetEditValue(const aValue: string); var OldValue, NewValue: Variant; begin if not wbEditAllowed then raise Exception.Create(GetName + ' can not be edited.'); if (not Assigned(dcDataBasePtr) or not Assigned(dcDataEndPtr)) or (aValue <> GetEditValue) then begin OldValue := GetNativeValue; vbValueDef.EditValue[GetDataBasePtr, dcDataEndPtr, Self] := aValue; if vIsFlags and (csInit in cntStates) then begin Reset; Init; end; NewValue := GetNativeValue; DoAfterSet(OldValue, NewValue); NotifyChanged(eContainer); if vIsFlags and (csInit in cntStates) then begin if vbValueDef.EditValue[GetDataBasePtr, dcDataEndPtr, Self] <> aValue then begin Reset; Init; end; end; end; end; procedure TwbValue.SetNativeValue(const aValue: Variant); var OldValue, NewValue: Variant; begin if not wbEditAllowed then raise Exception.Create(GetName + ' can not be edited.'); OldValue := GetNativeValue; vbValueDef.NativeValue[GetDataBasePtr, dcDataEndPtr, Self] := aValue; if vIsFlags and (csInit in cntStates) then begin Reset; Init; end; NewValue := GetNativeValue; DoAfterSet(OldValue, NewValue); NotifyChanged(eContainer); if vIsFlags and (csInit in cntStates) then begin Reset; Init; end; end; var Files : array of IwbFile; FilesMap: TStringList; procedure wbFileForceClosed; var i: Integer; begin for i := Low(Files) to High(Files) do (Files[i] as IwbFileInternal).ForceClosed; Files := nil; FilesMap.Clear; end; function wbExpandFileName(const aFileName: string): string; begin if ExtractFilePath(aFileName) = '' then Result := wbDataPath + ExtractFileName(aFileName) else Result := aFileName; end; function wbFile(const aFileName: string; aLoadOrder: Integer = -1; aCompareTo: string = ''; IsTemporary: Boolean = False; aOnlyHeader: Boolean = False): IwbFile; var FileName: string; i: Integer; begin FileName := wbExpandFileName(aFileName); {if ExtractFilePath(aFileName) = '' then FileName := ExpandFileName('.\'+aFileName) else FileName := ExpandFileName(aFileName);} if FilesMap.Find(FileName, i) then Result := IwbFile(Pointer(FilesMap.Objects[i])) else begin if not wbIsPlugin(FileName) then Result := TwbFileSource.Create(FileName, aLoadOrder, aCompareTo, aOnlyHeader, IsTemporary) else Result := TwbFile.Create(FileName, aLoadOrder, aCompareTo, aOnlyHeader, IsTemporary); SetLength(Files, Succ(Length(Files))); Files[High(Files)] := Result; FilesMap.AddObject(FileName, Pointer(Result)); end; end; procedure wbMastersForFile(const aFileName: string; aMasters: TStrings); var FileName : string; i : Integer; _File : IwbFileInternal; begin FileName := wbExpandFileName(aFileName); {if ExtractFilePath(aFileName) = '' then FileName := ExpandFileName('.\'+aFileName) else FileName := ExpandFileName(aFileName);} try if FilesMap.Find(FileName, i) then _File := IwbFile(Pointer(FilesMap.Objects[i])) as IwbFileInternal else if not wbIsPlugin(FileName) then _File := TwbFileSource.Create(FileName, -1, '', True) else _File := TwbFile.Create(FileName, -1, '', True); _File.GetMasters(aMasters); except // File neither found nor replaced, ignore if in xDump if not (wbToolMode in [tmDump, tmExport]) then Raise; end; end; function wbNewFile(const aFileName: string; aLoadOrder: Integer): IwbFile; var FileName: string; i: Integer; begin FileName := wbExpandFileName(aFileName); {if ExtractFilePath(aFileName) = '' then FileName := ExpandFileName('.\'+aFileName) else FileName := ExpandFileName(aFileName);} if FilesMap.Find(FileName, i) then raise Exception.Create(FileName + ' exists already') else begin Result := TwbFile.CreateNew(FileName, aLoadOrder); SetLength(Files, Succ(Length(Files))); Files[High(Files)] := Result; FilesMap.AddObject(FileName, Pointer(Result)); end; end; function wbFindWinningMainRecordByEditorID(const aSignature: TwbSignature; const aEditorID: string): IwbMainRecord; var i : Integer; Group : IwbGroupRecord; begin Result := nil; for i := High(Files) downto Low(Files) do if Supports(Files[i].GroupBySignature[aSignature], IwbGroupRecord, Group) then begin Result := Group.MainRecordByEditorID[aEditorID]; if Assigned(Result) then begin Result := Result.WinningOverride; Exit; end; end; end; function wbFormListToArray(const aFormList: IwbMainRecord; const aSignatures: string): TDynMainRecords; var Container : IwbContainerElementRef; Signatures : TStringList; i, j : Integer; MainRecord : IwbMainRecord; begin Result := nil; if not Assigned(aFormList) or (aFormList.Signature <> 'FLST') then Exit; if not Supports(aFormList.ElementByName['wbFormListToArray FormIDs'], IwbContainerElementRef, Container) then Exit; if Container.ElementCount < 1 then Exit; Signatures := TStringList.Create; try Signatures.CommaText := aSignatures; Signatures.Sorted := True; for i := 0 to Pred(Container.ElementCount) do begin if Supports(Container.Elements[i].LinksTo, IwbMainRecord, MainRecord) then if Signatures.Find(MainRecord.Signature, j) then begin SetLength(Result, Succ(Length(Result))); Result[High(Result)] := MainRecord; end; end; finally Signatures.Free; end; end; { TwbFlag } constructor TwbFlag.Create(const aContainer : IwbContainer; aBasePtr : Pointer; aEndPtr : Pointer; const aIntegerDef : IwbIntegerDef; const aFlagsDef : IwbFlagsDef; aIndex : Integer); begin fBasePtr := aBasePtr; fEndPtr := aEndPtr; fIntegerDef := aIntegerDef; if not fIntegerDef.FormaterCanChange then fFlagsDef := aFlagsDef; fIndex := aIndex; inherited Create(aContainer); SetSortOrder(aIndex); SetMemoryOrder(aIndex); end; function TwbFlag.GetConflictPriority: TwbConflictPriority; var MainRecord: IwbMainRecord; begin if wbTranslationMode then Result := cpIgnore else if GetFlagsDef.FlagIgnoreConflict[fIndex] then Result := cpIgnore else if Assigned(fIntegerDef) then Result := fIntegerDef.ConflictPriority[Self] else Result := cpNormal; if Result = cpFormID then begin Result := cpCritical; MainRecord := GetContainingMainRecord; if Assigned(MainRecord) and (MainRecord.Signature = 'GMST') then Result := cpBenign; end; end; function TwbFlag.GetDataSize: Integer; begin Result := 0; end; function TwbFlag.GetDef: IwbNamedDef; begin Result := GetFlagsDef.FlagDef[fIndex]; end; function TwbFlag.GetDontShow: Boolean; begin Result := GetFlagsDef.FlagDontShow[Self, fIndex]; end; function TwbFlag.GetEditValue: string; var s: string; begin s := GetContainer.EditValue; if Length(s) >= Succ(fIndex) then Result := s[Succ(fIndex)] else Result := '0'; end; function TwbFlag.GetElementType: TwbElementType; begin Result := etFlag; end; function TwbFlag.GetFlagIndex: Integer; begin Result := fIndex; end; function TwbFlag.GetFlagsDef: IwbFlagsDef; begin if Assigned(fFlagsDef) then Result := fFlagsDef else Result := fIntegerDef.Formater[IwbContainer(eContainer)] as IwbFlagsDef; end; function TwbFlag.GetIsEditable: Boolean; begin Result := wbIsInternalEdit or GetContainer.IsEditable; end; function TwbFlag.GetIsRemoveable: Boolean; begin Result := wbIsInternalEdit or GetContainer.IsEditable; end; function TwbFlag.GetName: string; begin Result := GetFlagsDef.Flags[fIndex]; end; function TwbFlag.GetNativeValue: Variant; var s: string; begin s := GetContainer.EditValue; if Length(s) >= Succ(fIndex) then Result := s[Succ(fIndex)] = '1' else Result := False; end; function TwbFlag.GetSortKey(aExtended: Boolean): string; procedure CheckFlagsChanged; var FlagsDef : IwbFlagsDef; begin FlagsDef := GetFlagsDef.Root as IwbFlagsDef; if FlagsDef.DefID <> fLastDefID then begin Exclude(eStates, esExtendedSortKeyValid); Exclude(eStates, esSortKeyValid); end; end; begin if not Assigned(fFlagsDef) then CheckFlagsChanged; Result := inherited GetSortKey(aExtended); end; function TwbFlag.GetSortKeyInternal(aExtended: Boolean): string; var s : string; FlagsDef : IwbFlagsDef; BaseFlagsDef : IwbFlagsDef; begin FlagsDef := GetFlagsDef.Root as IwbFlagsDef; BaseFlagsDef := FlagsDef.BaseFlagsDef; s := IntToHex64(BaseFlagsDef.DefID, 8); Result := s + IntToHex64(fIndex, 2); if not FlagsDef.Equals(BaseFlagsDef) then begin s := FlagsDef.Flags[fIndex]; if not SameText(s, BaseFlagsDef.Flags[fIndex]) then Result := Result + s; end; fLastDefID := FlagsDef.DefID; end; function TwbFlag.GetValue: string; //var // i: Int64; var Def: IwbDef; begin if wbReportMode then begin Def := GetValueDef; if Assigned(Def) then Def.Used; Def := GetDef; if Assigned(Def) then Def.Used; end; Result := GetFlagsDef.Flags[fIndex]; { i := fIntegerDef.ToInt(fBasePtr, fEndPtr, Self); if (i and (Int64(1) shl fIndex)) <> 0 then Result := GetName else Result := ''; } end; function TwbFlag.GetValueDef: IwbValueDef; begin Result := GetFlagsDef.FlagDef[fIndex]; end; procedure TwbFlag.InformStorage(var aBasePtr: Pointer; aEndPtr: Pointer); var Size: Cardinal; begin fBasePtr := aBasePtr; Size := fIntegerDef.Size[aBasePtr, aEndPtr, GetContainer]; fEndPtr := Pointer( Cardinal(fBasePtr) + Size ); if Cardinal(fEndPtr) > Cardinal(aEndPtr) then fEndPtr := aEndPtr; end; procedure TwbFlag.InvalidateParentStorage; begin {not inherited} end; procedure TwbFlag.Remove; begin SetEditValue('0'); end; procedure TwbFlag.SetEditValue(const aValue: string); var s: string; c: Char; begin if not wbEditAllowed then raise Exception.Create(GetName + ' can not be edited.'); if aValue = '1' then c := '1' else c := '0'; s := GetContainer.EditValue; if Length(s) >= Succ(fIndex) then s[Succ(fIndex)] := c else s := s + StringOfChar('0', fIndex - Length(s) ) + c; GetContainer.EditValue := s; end; procedure TwbFlag.SetNativeValue(const aValue: Variant); var s: string; c: Char; begin if not wbEditAllowed then raise Exception.Create(GetName + ' can not be edited.'); if aValue = True then c := '1' else c := '0'; s := GetContainer.EditValue; if Length(s) >= Succ(fIndex) then s[Succ(fIndex)] := c else s := s + StringOfChar('0', fIndex - Length(s) ) + c; GetContainer.EditValue := s; end; { TwbDataContainer } constructor TwbDataContainer.Create(const aContainer: IwbContainer; var aBasePtr: Pointer; aEndPtr: Pointer; const aPrevMainRecord : IwbMainRecord); begin dcBasePtr := aBasePtr; dcEndPtr := aEndPtr; dcDataBasePtr := aBasePtr; dcDataEndPtr := aEndPtr; inherited Create(aContainer); try InitDataPtr; aBasePtr := dcEndPtr; except if Assigned(aContainer) then aContainer.RemoveElement(Self); raise; end; end; function TwbDataContainer.DoCheckSizeAfterWrite: Boolean; begin Result := False; end; function TwbDataContainer.GetConflictPriority: TwbConflictPriority; var Def : IwbDef; ValueDef : IwbValueDef; MainRecord : IwbMainRecord; begin Result := cpNormal; Def := GetValueDef; if not Assigned(Def) then Def := GetDef; if Supports(Def, IwbValueDef, ValueDef) then Def := Resolve(ValueDef, GetDataBasePtr, GetDataEndPtr, Self); if Assigned(Def) then Result := Def.ConflictPriority[Self]; if wbTranslationMode then begin if Result <> cpTranslate then Result := cpIgnore else Result := cpNormal; end else begin if Result = cpTranslate then Result := cpNormal; end; if Result = cpFormID then begin Result := cpCritical; MainRecord := GetContainingMainRecord; if Assigned(MainRecord) and (MainRecord.Signature = 'GMST') then Result := cpBenign; end; end; function TwbDataContainer.GetDataBasePtr: Pointer; begin if (dcfStorageInvalid in dcFlags) then UpdateStorageFromElements; Result := dcDataBasePtr; end; function TwbDataContainer.GetDataEndPtr: Pointer; begin if (dcfStorageInvalid in dcFlags) then UpdateStorageFromElements; Result := dcDataEndPtr; end; function TwbDataContainer.GetDataSize: Integer; begin if (dcfStorageInvalid in dcFlags) or not Assigned(dcDataBasePtr) or not Assigned(dcDataEndPtr) then Result := inherited GetDataSize + GetDataPrefixSize else Result := Cardinal( dcDataEndPtr ) - Cardinal( dcDataBasePtr ); end; function TwbDataContainer.GetDontCompare: Boolean; begin Result := (dcfDontCompare in dcFlags); end; function TwbDataContainer.GetDontSave: Boolean; begin Result := (dcfDontSave in dcFlags); end; function TwbDataContainer.GetEditInfo: string; var ValueDef: IwbValueDef; begin Result := ''; if Supports(GetValueDef, IwbValueDef, ValueDef) then Result := ValueDef.EditInfo[GetDataBasePtr, dcDataEndPtr, Self]; end; function TwbDataContainer.GetEditType: TwbEditType; var ValueDef: IwbValueDef; begin Result := etDefault; if Supports(GetValueDef, IwbValueDef, ValueDef) then Result := ValueDef.EditType[GetDataBasePtr, dcDataEndPtr, Self]; end; function TwbDataContainer.GetResolvedValueDef: IwbValueDef; begin Result := Resolve(GetValueDef, GetDataBasePtr, dcDataEndPtr, Self); end; function TwbDataContainer.GetDataPrefixSize: Integer; begin Result := 0; end; procedure TwbDataContainer.InformStorage(var aBasePtr: Pointer; aEndPtr: Pointer); var SizeNeeded : Cardinal; SizeAvailable : Cardinal; BasePtr : Pointer; begin if [dcfDontMerge, dcfDontCompare] * dcFlags <> [] then Exit; if Length(dcDataStorage) <> 0 then Assert(Length(dcDataStorage) = 0); SizeNeeded := GetDataSize; if SizeNeeded > 0 then begin SizeAvailable := Cardinal( aEndPtr ) - Cardinal( aBasePtr ); if (SizeAvailable < SizeNeeded) then Assert( SizeAvailable >= SizeNeeded ); BasePtr := aBasePtr; Inc(PByte(aBasePtr), GetDataPrefixSize); inherited; if BasePtr = aBasePtr then begin if not (dcfDontMerge in dcFlags) then Inc(PByte(aBasePtr), SizeNeeded); end else if Cardinal(aBasePtr) - Cardinal(BasePtr) > SizeNeeded then // we overwrote something Assert( Cardinal(aBasePtr) - Cardinal(BasePtr) = SizeNeeded) else // Adjust size of data not initialized yet aBasePtr := PByte(BasePtr) + SizeNeeded; dcDataBasePtr := BasePtr; dcDataEndPtr := aBasePtr; end; end; procedure TwbDataContainer.InvalidateStorage; begin Include(dcFlags, dcfStorageInvalid); inherited; end; function TwbDataContainer.IsFlags: Boolean; begin Result := False; end; function TwbDataContainer.IsValidOffset(aBasePtr, aEndPtr: Pointer; anOffset: Integer): Boolean; begin Result := False; if Cardinal(aBasePtr) >= Cardinal(dcBasePtr) then if Cardinal(aBasePtr) < Cardinal(dcEndPtr) then if Cardinal(aEndPtr) > Cardinal(dcBasePtr) then if Cardinal(aEndPtr) <= Cardinal(dcEndPtr) then if Cardinal(aBasePtr)+anOffset < Cardinal(dcEndPtr) then Result := True; end; function TwbDataContainer.IsLocalOffset(anOffset: Integer): Boolean; begin if Cardinal(dcDataBasePtr)+anOffset < Cardinal(dcDataEndPtr) then Result := True else Result := False; end; procedure TwbDataContainer.MergeStorageInternal(var aBasePtr: Pointer; aEndPtr: Pointer); var SizeNeeded : Cardinal; SizeAvailable : Cardinal; BasePtr : Pointer; PrefixSize : Integer; begin if [dcfDontMerge, dcfDontCompare] * dcFlags <> [] then Exit; if (dcfStorageInvalid in dcFlags) then begin BasePtr := aBasePtr; PrefixSize := GetDataPrefixSize; if (PrefixSize > 0) then begin Move(dcDataBasePtr^, aBasePtr^, PrefixSize); Inc(PByte(aBasePtr), PrefixSize); end; inherited; dcDataBasePtr := BasePtr; dcDataEndPtr := aBasePtr; end else begin SizeNeeded := Cardinal( dcDataEndPtr ) - Cardinal( dcDataBasePtr ); if SizeNeeded > 0 then begin SizeAvailable := Cardinal( aEndPtr ) - Cardinal( aBasePtr ); if SizeAvailable < SizeNeeded then Assert( SizeAvailable >= SizeNeeded ); Move(dcDataBasePtr^, aBasePtr^, SizeNeeded); dcDataBasePtr := aBasePtr; Inc(PByte(aBasePtr), SizeNeeded); dcDataEndPtr := aBasePtr; BasePtr := dcDataBasePtr; Inc(PByte(BasePtr), GetDataPrefixSize); inherited InformStorage(BasePtr, dcDataEndPtr); end else begin dcDataBasePtr := nil; dcDataEndPtr := nil; end; dcDataStorage := nil; end; end; procedure TwbDataContainer.RequestStorageChange(var aBasePtr, aEndPtr: Pointer; aNewSize: Cardinal); var BasePtr : Pointer; OldSize : Cardinal; NeedsCopy : Boolean; begin if (dcfStorageInvalid in dcFlags) then UpdateStorageFromElements; SetModified(True); InvalidateParentStorage; if aNewSize = 0 then begin dcDataStorage := nil; dcDataBasePtr := @EmptyPtr; dcDataEndPtr := @EmptyPtr; end else if Cardinal(Length(dcDataStorage)) <> aNewSize then begin OldSize := Cardinal( dcDataEndPtr ) - Cardinal( dcDataBasePtr ); NeedsCopy := (Length(dcDataStorage) = 0) and (OldSize > 0); SetLength(dcDataStorage, aNewSize); if NeedsCopy then Move(dcDataBasePtr^, dcDataStorage[0], Min(OldSize, aNewSize)); dcDataBasePtr := @dcDataStorage[0]; dcDataEndPtr := Pointer( Cardinal(dcDataBasePtr) + aNewSize ); BasePtr := dcDataBasePtr; Inc(PByte(BasePtr), GetDataPrefixSize); inherited InformStorage(BasePtr, dcDataEndPtr); end; Exclude(dcFlags, dcfStorageInvalid); aBasePtr := dcDataBasePtr; aEndPtr := dcDataEndPtr; end; procedure TwbDataContainer.SetContainer(const aContainer: IwbContainer); var DataContainer: IwbDataContainer; begin if not (dcfDontCompare in dcFlags) then if Supports(aContainer, IwbDataContainer, DataContainer) and DataContainer.DontCompare then Include(dcFlags, dcfDontCompare); inherited; end; procedure TwbDataContainer.SetDataSize(aSize: Integer); var BasePtr, EndPtr: Pointer; begin if aSize = GetDataSize then Exit; BasePtr := nil; EndPtr := nil; RequestStorageChange(BasePtr, EndPtr, aSize); if csInit in cntStates then begin Reset; Init; end; end; procedure TwbDataContainer.SetModified(aValue: Boolean); begin inherited SetModified(aValue); end; procedure TwbDataContainer.SetToDefaultInternal; var SelfRef : IwbContainerElementRef; ValueDef : IwbValueDef; OldValue, NewValue : Variant; begin SelfRef := Self as IwbContainerElementRef; DoInit; ValueDef := GetValueDef; if Assigned(ValueDef) then begin OldValue := GetNativeValue; if ValueDef.SetToDefault(GetDataBasePtr, GetDataEndPtr, Self) then begin NewValue := GetNativeValue; DoAfterSet(OldValue, NewValue); NotifyChanged(eContainer); if IsFlags and (csInit in cntStates) then begin Reset; Init; end; end; end; inherited; end; procedure TwbDataContainer.UpdateStorageFromElements; var PrefixSize : Integer; NewStorage : TBytes; BasePtr : Pointer; EndPtr : Pointer; SelfRef : IwbContainerElementRef; i : Integer; DataContainerInternal : IwbDataContainerInternal; begin if not (dcfStorageInvalid in dcFlags) then Exit; SelfRef := Self as IwbContainerElementRef; for i := Low(cntElements) to High(cntElements) do if Supports(cntElements[i], IwbDataContainerInternal, DataContainerInternal) then DataContainerInternal.UpdateStorageFromElements; SetLength(NewStorage, inherited GetDataSize + GetDataPrefixSize); if Length(NewStorage) > 0 then begin BasePtr := @NewStorage[0]; EndPtr := Pointer( Cardinal(BasePtr) + Cardinal(Length(NewStorage)) ); PrefixSize := GetDataPrefixSize; if (PrefixSize > 0) then Move(dcDataBasePtr^, BasePtr^, PrefixSize); Inc(PByte(BasePtr), PrefixSize); inherited MergeStorageInternal(BasePtr, EndPtr); dcDataStorage := NewStorage; dcDataBasePtr := @NewStorage[0]; dcDataEndPtr := Pointer( Cardinal(dcDataBasePtr) + Cardinal(Length(dcDataStorage)) ); Assert(dcDataEndPtr = EndPtr); end else begin dcDataStorage := nil; dcDataBasePtr := nil; dcDataEndPtr := nil; end; Exclude(dcFlags, dcfStorageInvalid); end; procedure TwbDataContainer.WriteToStreamInternal(aStream: TStream; aResetModified: Boolean); var OldPosition : Int64; Size : Cardinal; ExpectedSize : Cardinal; begin if [dcfDontSave, dcfDontCompare] * dcFlags <> [] then Exit; OldPosition := aStream.Position; ExpectedSize := GetDataSize; if (esModified in eStates) or wbTestWrite then begin if not (dcfStorageInvalid in dcFlags) and Assigned(dcDataEndPtr) and Assigned(dcDataBasePtr) then Size := Cardinal( dcDataEndPtr ) - Cardinal( dcDataBasePtr ) else Size := 0; if Size > 0 then begin if Size <> ExpectedSize then Assert(Size = ExpectedSize); aStream.WriteBuffer(dcDataBasePtr^, Size); end else begin inherited WriteToStreamInternal(aStream, aResetModified); if aStream.Position = OldPosition then begin Size := GetDataSize; if Size > 0 then aStream.WriteBuffer(GetDataBasePtr^, Size); end; end; end else begin Size := ExpectedSize; if Size > 0 then aStream.WriteBuffer(GetDataBasePtr^, Size); end; if (aStream.Position - OldPosition) <> ExpectedSize then if DoCheckSizeAfterWrite then Assert(not DoCheckSizeAfterWrite); Exclude(eStates, esUnsaved); if aResetModified then begin Exclude(eStates, esModified); Exclude(eStates, esInternalModified); end; end; { TwbValueBase } procedure TwbValueBase.BuildRef; var SelfRef: IwbElement; begin SelfRef := Self as IwbContainerElementRef; inherited; vbValueDef.BuildRef(GetDataBasePtr, dcDataEndPtr, Self); end; constructor TwbValueBase.Create(const aContainer : IwbContainer; var aBasePtr : Pointer; aEndPtr : Pointer; const aValueDef : IwbValueDef; const aNameSuffix : string; aDontCompare: Boolean); begin if aDontCompare then Include(dcFlags, dcfDontCompare); vbValueDef := aValueDef; vbNameSuffix := aNameSuffix; inherited Create(aContainer, aBasePtr, aEndPtr, nil); end; function TwbValueBase.CanContainFormIDs: Boolean; begin Result := vbValueDef.CanContainFormIDs; end; function TwbValueBase.CanElementReset: Boolean; begin // Result := inherited CanElementReset; Result := eExternalRefs < 1; end; constructor TwbValueBase.Create(const aContainer : IwbContainer; const aValueDef : IwbValueDef; const aSource : IwbElement; const aOnlySK : Boolean; const aNameSuffix : string); var BasePtr : Pointer; EndPtr : Pointer; begin BasePtr := nil; Create(aContainer, BasePtr, nil, aValueDef, aNameSuffix); if Assigned(aSource) then try RequestStorageChange(BasePtr, EndPtr, GetDataSize); SetToDefault; Assign(Low(Integer), aSource, aOnlySK); SetModified(True); except if Assigned(aContainer) then aContainer.RemoveElement(Self); raise; end else begin BasePtr := nil; EndPtr := nil; SetModified(True); RequestStorageChange(BasePtr, EndPtr, GetDataSize); SetToDefault; end; end; function TwbValueBase.DoCheckSizeAfterWrite: Boolean; begin Result := True; end; function TwbValueBase.GetBaseName: string; begin Result := vbValueDef.Name; end; function TwbValueBase.GetCheck: string; var SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; DoInit; Result := vbValueDef.Check(GetDataBasePtr, dcDataEndPtr, Self); end; function TwbValueBase.GetDataSize: Integer; begin if not Assigned(dcDataBasePtr) and not (dcfStorageInvalid in dcFlags) then Result := vbValueDef.DefaultSize[nil, nil, Self] else Result := inherited GetDataSize; end; function TwbValueBase.GetDef: IwbNamedDef; begin Result := vbValueDef; end; function TwbValueBase.GetDisplayName: string; var Resolved: IwbValueDef; Container: IwbDataContainer; begin Resolved := Resolve(vbValueDef, GetDataBasePtr, GetDataEndPtr, Self); if (not Assigned(Resolved)) or (Resolved <> vbValueDef) and (Resolved.DefType in dtNonValues) then Result := vbValueDef.Name else Result := Resolved.Name; if Assigned(Resolved) then begin if (Resolved.DefType in dtNonValues) and (wbDumpOffset=1) then // simply display starting offset. Result := Result + ' {' + IntToHex64(Cardinal(GetDataBasePtr)-wbBaseOffset, 8) + '}'; // something for Dump: Displaying the size in {} and the array count in [] // Triggers a lot of pre calculations if (Resolved.DefType in dtNonValues) and (wbDumpOffset>2) then Result := Result + ' {' + IntToHex64(Cardinal(GetDataEndPtr)-wbBaseOffset, 8) + '-' + IntToHex64(Cardinal(GetDataBasePtr)-wbBaseOffset, 8) + ' = ' +IntToStr(Resolved.Size[GetDataBasePtr, GetDataEndPtr, Self]) + '}'; if (Resolved.DefType = dtArray) and (wbDumpOffset>1) and Supports(Self, IwbDataContainer, Container) then Result := Result + ' [' + IntToStr(Container.GetElementCount) + ']'; end; if vbNameSuffix <> '' then Result := Result + ' ' + vbNameSuffix; end; function TwbValueBase.GetEditValue: string; var SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; DoInit; Result := vbValueDef.EditValue[GetDataBasePtr, dcDataEndPtr, Self] end; function TwbValueBase.GetIsEditable: Boolean; var SelfRef : IwbContainerElementRef; begin Result := wbIsInternalEdit; if Result then Exit; SelfRef := Self as IwbContainerElementRef; if Assigned(eContainer) and not IwbContainer(eContainer).IsElementEditable(SelfRef) then Exit; DoInit; Result := vbValueDef.IsEditable[GetDataBasePtr, dcDataEndPtr, Self]; end; function TwbValueBase.GetIsInSK(aIndex: Integer): Boolean; var SelfRef : IwbContainerElementRef; HasSortKey : IwbHasSortKeyDef; begin Result := False; SelfRef := Self as IwbContainerElementRef; DoInit; if not Supports(vbValueDef, IwbHasSortKeyDef, HasSortKey) then Exit; Result := HasSortKey.IsInSK(aIndex); end; function TwbValueBase.GetLinksTo: IwbElement; var SelfRef: IwbContainerElementRef; begin Result := nil; SelfRef := Self as IwbContainerElementRef; DoInit; if not Assigned(vbValueDef) then Exit; Result := vbValueDef.LinksTo[dcDataBasePtr, dcDataEndPtr, Self]; end; function TwbValueBase.GetName: string; begin Result := vbValueDef.Name; if vbNameSuffix <> '' then Result := Result + ' ' + vbNameSuffix; end; function TwbValueBase.GetNativeValue: Variant; var SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; DoInit; Result := vbValueDef.NativeValue[GetDataBasePtr, dcDataEndPtr, Self] end; function TwbValueBase.GetSortKeyInternal(aExtended: Boolean): string; var SelfRef : IwbContainerElementRef; begin SelfRef := Self as IwbContainerElementRef; if (dcfDontCompare in dcFlags) then Result := '' else begin DoInit; Result := vbValueDef.ToSortKey(GetDataBasePtr, dcDataEndPtr, Self, aExtended); end; end; function TwbValueBase.GetValue: string; var SelfRef : IwbContainerElementRef; var Def: IwbDef; begin if wbReportMode then begin Def := GetValueDef; if Assigned(Def) then Def.Used; Def := GetDef; if Assigned(Def) then Def.Used; end; SelfRef := Self as IwbContainerElementRef; DoInit; Result := vbValueDef.ToString(GetDataBasePtr, dcDataEndPtr, Self); end; function TwbValueBase.GetValueDef: IwbValueDef; //var // SelfRef: IwbContainerElementRef; begin // SelfRef := Self as IwbContainerElementRef; // DoInit; Result := vbValueDef; end; procedure TwbValueBase.InitDataPtr; var Size : Integer; begin if (GetDataBasePtr <> nil) and (Cardinal(dcDataEndPtr)>=Cardinal(dcDataBasePtr)) then begin Size := vbValueDef.Size[dcDataBasePtr, dcDataEndPtr, Self]; if Size < High(Integer) then begin dcDataEndPtr := Pointer( Cardinal(dcDataBasePtr) + Cardinal(Size) ); if Cardinal(dcDataEndPtr) > Cardinal(dcEndPtr) then dcDataEndPtr := dcEndPtr else dcEndPtr := dcDataEndPtr; end; end; end; procedure TwbValueBase.SetEditValue(const aValue: string); var OldValue, NewValue: Variant; begin if not wbEditAllowed then raise Exception.Create(GetName + ' can not be edited.'); if aValue <> GetEditValue then begin OldValue := GetNativeValue; vbValueDef.EditValue[GetDataBasePtr, dcDataEndPtr, Self] := aValue; NewValue := GetNativeValue; DoAfterSet(OldValue, NewValue); NotifyChanged(eContainer); end; end; procedure TwbValueBase.SetNativeValue(const aValue: Variant); var OldValue, NewValue: Variant; begin if not wbEditAllowed then raise Exception.Create(GetName + ' can not be edited.'); OldValue := GetNativeValue; vbValueDef.NativeValue[GetDataBasePtr, dcDataEndPtr, Self] := aValue; NewValue := GetNativeValue; DoAfterSet(OldValue, NewValue); NotifyChanged(eContainer); end; procedure TwbValueBase.SetToDefaultInternal; var SelfRef: IwbContainerElementRef; BasePtr, EndPtr: Pointer; begin SelfRef := Self as IwbContainerElementRef; if csInit in cntStates then DoReset(True); BasePtr := nil; EndPtr := nil; dcDataBasePtr := nil; dcDataEndPtr := nil; dcDataStorage := nil; DoInit; RequestStorageChange(BasePtr, EndPtr, vbValueDef.DefaultSize[nil, nil, Self]); inherited; end; { TwbRecordHeaderStruct } function TwbRecordHeaderStruct.AddIfMissingInternal(const aElement : IwbElement; aAsNew : Boolean; aDeepCopy : Boolean; const aPrefixRemove : string; const aPrefix : string; const aSuffix : string) : IwbElement; var StructDef : IwbStructDef; SelfRef : IwbContainerElementRef; begin Result := nil; if not wbEditAllowed then raise Exception.Create(GetName + ' can not be assigned.'); SelfRef := Self as IwbContainerElementRef; DoInit; if not Supports(GetDef, IwbStructDef, StructDef) then Exit; Assert(aElement.SortOrder >= 0); Assert(aElement.SortOrder < StructDef.MemberCount); Assert(Assigned(aElement.Def)); Assert(aElement.Def.Equals(StructDef.Members[aElement.SortOrder])); Result := GetElementBySortOrder(aElement.SortOrder + GetAdditionalElementCount); Assert(Assigned(Result)); Result.Assign(Low(Integer), aElement, not aDeepCopy); end; procedure TwbRecordHeaderStruct.BuildRef; begin end; function TwbRecordHeaderStruct.CanContainFormIDs: Boolean; begin Result := False; end; function TwbRecordHeaderStruct.CompareExchangeFormID(aOldFormID, aNewFormID: Cardinal): Boolean; begin Result := False; end; procedure TwbRecordHeaderStruct.ElementChanged(const aElement: IwbElement; aContainer: Pointer); var MainRecordInternal : IwbMainRecordInternal; DataContainer : IwbDataContainer; Flags : TwbMainRecordStructFlags; p : Pointer; ToggleDeleted : Boolean; TogglePersistent : Boolean; ToggleVisibleWhenDistant : Boolean; begin ToggleDeleted := False; TogglePersistent := False; ToggleVisibleWhenDistant := False; if Supports(IInterface(eContainer) , IwbMainRecordInternal, MainRecordInternal) then begin if SameText(aElement.Def.Name, 'Record Flags') then begin if Supports(aElement, IwbDataContainer, DataContainer) then begin Flags._Flags := PCardinal(DataContainer.DataBasePtr)^; UpdateStorageFromElements; dcDataStorage := nil; Exclude(dcFlags, dcfStorageInvalid); MainRecordInternal.MakeHeaderWriteable; if Flags.IsESM then if MainRecordInternal.Signature <> wbHeaderSignature then Flags.SetESM(False); if Flags.IsDeleted <> MainRecordInternal.mrStruct.mrsFlags.IsDeleted then begin Flags.SetDeleted(MainRecordInternal.mrStruct.mrsFlags.IsDeleted); ToggleDeleted := True; end; if Flags.IsPersistent <> MainRecordInternal.mrStruct.mrsFlags.IsPersistent then begin Flags.SetPersistent(MainRecordInternal.mrStruct.mrsFlags.IsPersistent); TogglePersistent := True; end; if Flags.IsVisibleWhenDistant <> MainRecordInternal.mrStruct.mrsFlags.IsVisibleWhenDistant then begin Flags.SetVisibleWhenDistant(MainRecordInternal.mrStruct.mrsFlags.IsVisibleWhenDistant); ToggleVisibleWhenDistant := True; end; MainRecordInternal.mrStruct.mrsFlags := Flags; end; end; p := MainRecordInternal.mrStruct; InformStorage(p, Pointer(Cardinal(p) + wbSizeOfMainRecordStruct )); with MainRecordInternal do begin if ToggleDeleted then IsDeleted := not IsDeleted; if not IsDeleted then begin if TogglePersistent then IsPersistent := not IsPersistent; if ToggleVisibleWhenDistant then IsVisibleWhenDistant := not IsVisibleWhenDistant; end; end; end; inherited; end; function TwbRecordHeaderStruct.GetIsEditable: Boolean; begin Result := wbIsInternalEdit; end; function TwbRecordHeaderStruct.IsElementEditable(const aElement: IwbElement): Boolean; begin Result := Assigned(aElement) and Assigned(aElement.ValueDef) and SameText(aElement.ValueDef.Name, 'Record Flags'); if Result and Assigned(eContainer) then Result := IwbContainer(eContainer).IsElementEditable(Self); end; { TwbStringListTerminator } function TwbStringListTerminator.AssignInternal(aIndex: Integer; const aElement: IwbElement; aOnlySK: Boolean): IwbElement; begin Result := nil; end; function TwbStringListTerminator.CanAssignInternal(aIndex: Integer; const aElement: IwbElement; aCheckDontShow: Boolean): Boolean; begin Result := False; if Assigned(eContainer) then if not IwbContainer(eContainer).IsElementEditable(Self) then Exit; Result := Supports(aElement, IwbStringListTerminator); end; function TwbStringListTerminator.GetConflictPriority: TwbConflictPriority; begin Result := cpIgnore; end; function TwbStringListTerminator.GetDataSize: Integer; begin Result := 1; end; function TwbStringListTerminator.GetElementType: TwbElementType; begin Result := etStringListTerminator; end; function TwbStringListTerminator.GetName: string; begin Result := 'Terminator'; end; function TwbStringListTerminator.GetSortKeyInternal(aExtended: Boolean): string; begin Result := #255; end; procedure TwbStringListTerminator.InformStorage(var aBasePtr: Pointer; aEndPtr: Pointer); begin Assert( Cardinal(aBasePtr) < Cardinal(aEndPtr)); Inc(PByte(aBasePtr)); end; procedure TwbStringListTerminator.MergeStorageInternal(var aBasePtr: Pointer; aEndPtr: Pointer); begin Assert( Cardinal(aBasePtr) < Cardinal(aEndPtr)); PAnsiChar(aBasePtr)^ := #0; Inc(PByte(aBasePtr)); end; procedure TwbStringListTerminator.SetEditValue(const aValue: string); begin end; procedure TwbStringListTerminator.SetNativeValue(const aValue: Variant); begin end; procedure TwbStringListTerminator.WriteToStreamInternal(aStream: TStream; aResetModified: Boolean); const NullChar : AnsiChar = #0; begin aStream.Write(NullChar, 1); Exclude(eStates, esUnsaved); if aResetModified then begin Exclude(eStates, esModified); Exclude(eStates, esInternalModified); end; end; procedure WriteSubRecordOrderList; var i: Integer; begin if not wbReportMode then Exit; SubRecordOrderList.Sorted := False; for i := 0 to Pred(SubRecordOrderList.Count) do SubRecordOrderList[i] := SubRecordOrderList[i] + ' (' + IntToStr(Integer(SubRecordOrderList.Objects[i]) )+ ')'; SubRecordOrderList.SaveToFile('SubRecordOrderList.txt'); end; var wbContainedInDef : array[0..10] of IwbIntegerDef; { TwbContainedInElement } procedure TwbContainedInElement.BuildRef; begin end; function TwbContainedInElement.CanContainFormIDs: Boolean; begin Result := False; end; function TwbContainedInElement.CompareExchangeFormID(aOldFormID, aNewFormID: Cardinal): Boolean; begin Result := False; end; procedure TwbContainedInElement.ContainerChanged; var MainRecord : IwbMainRecord; GroupRecord : IwbGroupRecord; Grp : TwbGroupTypes; begin if cieLockCount > 0 then Exit; if not Supports(GetContainer, IwbMainRecord, MainRecord) then Exit; if not Supports(MainRecord.Container, IwbGroupRecord, GroupRecord) then Exit; if GroupRecord.GroupType = 5 then if not Supports(GroupRecord.Container, IwbGroupRecord, GroupRecord) then Exit; if GroupRecord.GroupType = 4 then if not Supports(GroupRecord.Container, IwbGroupRecord, GroupRecord) then Exit; if wbVWDAsQuestChildren then Grp := [8..9] else Grp := [8..10]; if GroupRecord.GroupType in Grp then if not Supports(GroupRecord.Container, IwbGroupRecord, GroupRecord) then Exit; if wbVWDAsQuestChildren then Grp := [1, 6, 7, 10] else Grp := [1, 6, 7]; if not (GroupRecord.GroupType in Grp) then Exit; PCardinal(GetDataBasePtr)^ := GroupRecord.GroupLabel; Exclude(eStates, esSortKeyValid); Exclude(eStates, esExtendedSortKeyValid); eSortKey := ''; eExtendedSortKey := ''; end; constructor TwbContainedInElement.Create(const aMainRecord: IwbMainRecord); var BasePtr : Pointer; EndPtr : Pointer; GroupRecord : IwbGroupRecord; Grp : TwbGroupTypes; begin // MainRecord must be in a group if not Supports(aMainRecord.Container, IwbGroupRecord, GroupRecord) then Assert(False); // if that group is Exterior Sub-Block, then it must be in a group too, get it if GroupRecord.GroupType = 5 then if not Supports(GroupRecord.Container, IwbGroupRecord, GroupRecord) then Assert(False); // if that group is Exterior Block, then it must be in a group too, get it if GroupRecord.GroupType = 4 then if not Supports(GroupRecord.Container, IwbGroupRecord, GroupRecord) then Assert(False); // if group is persistent, temporary or vwd cell children, it should be in a group too // if vwd is treated as quest children, then exclude it from check if wbVWDAsQuestChildren then Grp := [8..9] else Grp := [8..10]; if GroupRecord.GroupType in Grp then if not Supports(GroupRecord.Container, IwbGroupRecord, GroupRecord) then Assert(False); // the final list of parent groups, mainrecords in those will have ContainedIn element if wbVWDAsQuestChildren then Grp := [1, 6, 7, 10] else Grp := [1, 6, 7]; Assert(GroupRecord.GroupType in Grp); Include(dcFlags, dcfDontMerge); Include(dcFlags, dcfDontSave); BasePtr := nil; EndPtr := nil; inherited Create(aMainRecord, BasePtr, EndPtr, wbContainedInDef[GroupRecord.GroupType], '', False); SetSortOrder(-2); BasePtr := nil; EndPtr := nil; RequestStorageChange(BasePtr, EndPtr, GetDataSize); Assert(Assigned(BasePtr)); PCardinal(BasePtr)^ := GroupRecord.GroupLabel; end; procedure TwbContainedInElement.DoAfterSet(const aOldValue, aNewValue: Variant); var OldFormID : Cardinal; NewFormID : Cardinal; _File : IwbFile; MainRecord : IwbMainRecord; NewOwner : IwbMainRecord; GroupRecord : IwbGroupRecord; OldGroup : IwbGroupRecord; Group1 : IwbGroupRecord; Group2 : IwbGroupRecord; Group3 : IwbGroupRecord; CorrectGroup : Integer; i : Integer; begin Inc(cieLockCount); try inherited; if aOldValue <> aNewValue then begin OldFormID := aOldValue; NewFormID := aNewValue; _File := GetFile; MainRecord := GetContainer as IwbMainRecord; OldGroup := MainRecord.Container as IwbGroupRecord; NewOwner := _File.RecordByFormID[NewFormID, False]; if not Assigned(NewOwner) then begin if Assigned(dcDataBasePtr) then PCardinal(dcDataBasePtr)^ := OldFormID; Exit; end; if not _File.Equals(NewOwner._File) then NewOwner := wbCopyElementToFile(NewOwner, _File, False, True, '', '', '') as IwbMainRecord; GroupRecord := NewOwner.EnsureChildGroup; case GroupRecord.GroupType of 1: begin Assert(OldGroup.GroupType in [1, 5]); Group1 := OldGroup; Group2 := nil; Group3 := nil; if OldGroup.GroupType = 5 then begin if not Supports(Group1.Container, IwbGroupRecord, Group2) then Assert(False); Assert(Group2.GroupType = 4); Group3 := nil; for i := 0 to Pred(GroupRecord.ElementCount) do if Supports(GroupRecord.Elements[i], IwbGroupRecord, Group3) then if (Group3.GroupType = 4) and (Group3.GroupLabel = Group2.GroupLabel) then Break else Group3 := nil; if not Assigned(Group3) then Group3 := TwbGroupRecord.Create(GroupRecord, 4, Group2.GroupLabel); GroupRecord := Group3; Group3 := nil; for i := 0 to Pred(GroupRecord.ElementCount) do if Supports(GroupRecord.Elements[i], IwbGroupRecord, Group3) then if (Group3.GroupType = 5) and (Group3.GroupLabel = Group1.GroupLabel) then Break else Group3 := nil; if not Assigned(Group3) then Group3 := TwbGroupRecord.Create(GroupRecord, 5, Group1.GroupLabel); GroupRecord := Group3; if not Supports(Group2.Container, IwbGroupRecord, Group3) then Assert(False); Assert(Group3.GroupType = 1); end; Group1.RemoveElement(MainRecord); if Group1.ElementCount = 0 then begin (Group1 as IwbGroupRecordInternal).SetModified(True); Group1.Remove; if Assigned(Group2) then if Group2.ElementCount = 0 then begin (Group2 as IwbGroupRecordInternal).SetModified(True); Group2.Remove; if Assigned(Group3) then if Group3.ElementCount = 0 then begin (Group3 as IwbGroupRecordInternal).SetModified(True); Group3.Remove; end else (Group3 as IwbGroupRecordInternal).SetModified(True); end else (Group2 as IwbGroupRecordInternal).SetModified(True); end else (Group1 as IwbGroupRecordInternal).SetModified(True); GroupRecord.AddElement(MainRecord); (GroupRecord as IwbGroupRecordInternal).SetModified(True); (GroupRecord as IwbGroupRecordInternal).Sort; end; 6: begin if MainRecord.IsPersistent then CorrectGroup := 8 else if MainRecord.IsVisibleWhenDistant and not wbVWDInTemporary then CorrectGroup := 10 else CorrectGroup := 9; Group3 := nil; for i := 0 to Pred(GroupRecord.ElementCount) do if Supports(GroupRecord.Elements[i], IwbGroupRecord, Group3) then if Group3.GroupType = CorrectGroup then Break else Group3 := nil; if not Assigned(Group3) then Group3 := TwbGroupRecord.Create(GroupRecord, CorrectGroup, GroupRecord.ChildrenOf); OldGroup.RemoveElement(MainRecord); if OldGroup.ElementCount = 0 then OldGroup.Remove else (OldGroup as IwbGroupRecordInternal).SetModified(True); Group3.AddElement(MainRecord); (Group3 as IwbGroupRecordInternal).SetModified(True); (Group3 as IwbGroupRecordInternal).Sort; end; 7: begin OldGroup.RemoveElement(MainRecord); if OldGroup.ElementCount = 0 then OldGroup.Remove else (OldGroup as IwbGroupRecordInternal).SetModified(True); GroupRecord.AddElement(MainRecord); (GroupRecord as IwbGroupRecordInternal).SetModified(True); (GroupRecord as IwbGroupRecordInternal).Sort; end; else Assert(False); end; end; finally Dec(cieLockCount); end; ContainerChanged; end; procedure TwbContainedInElement.ElementChanged(const aElement: IwbElement; aContainer: Pointer); begin end; procedure TwbContainedInElement.InvalidateParentStorage; begin end; function TwbContainedInElement.IsElementEditable(const aElement: IwbElement): Boolean; begin Result := False; end; procedure TwbContainedInElement.SetModified(aValue: Boolean); begin if not aValue then inherited else begin Exclude(eStates, esSortKeyValid); Exclude(eStates, esExtendedSortKeyValid); eSortKey := ''; end; end; { TwbMainRecordEntryHeader } procedure TwbMainRecordEntryHeader.BeginUse; begin Assert(not mrehInUse); mrehInUse := True; Inc(mrehGeneration); mrehHead := nil; mrehTail := nil; mrehCount := 0; end; procedure TwbMainRecordEntryHeader.EndUse; begin Assert(mrehInUse); mrehInUse := False; Inc(mrehGeneration); mrehHead := nil; mrehTail := nil; mrehCount := 0; end; const WRLD : TwbSignature = 'WRLD'; CELL : TwbSignature = 'CELL'; DIAL : TwbSignature = 'DIAL'; QUST : TwbSignature = 'QUST'; { TwbFileSource } constructor TwbFileSource.CreateNew(const aFileName: string; aLoadOrder: Integer); begin Include(flStates, fsIsNew); flLoadOrder := aLoadOrder; flFileName := aFileName; end; procedure TwbFileSource.GetMasters(aMasters: TStrings); var Header : IwbFileHeader; MasterFiles : IwbContainerElementRef; fPath : String; i : Integer; modOffset : Cardinal; modPtr : Pointer; mods : TwbArray; begin if (GetElementCount <> 1) or not Supports(GetElement(0), IwbFileHeader, Header) then raise Exception.CreateFmt('Unexpected error reading file "%s"', [flFileName]); if Header.FileMagic <> wbFileMagic then raise Exception.CreateFmt('Expected File Magic %s, found %s in file "%s"', [wbFileMagic, String(Header.FileMagic), flFileName]); if Pos('Absolute:', wbFilePlugins)=1 then begin modOffset := Cardinal(flView)+StrToInt(Copy(wbFilePlugins, 10, Length(wbFilePlugins))); modPtr := Pointer(modOffset); mods := TwbArray.Create(nil, modPtr, flEndPtr, wbArray('Modules', wbLenString('PluginName', 2), -4), '', False); Supports(mods, IwbContainerElementRef, MasterFiles); end else MasterFiles := Header.ElementByName[wbFilePlugins] as IwbContainerElementRef; if Assigned(MasterFiles) then for i := 0 to Pred(MasterFiles.ElementCount) do begin fPath := wbDataPath + MasterFiles[i].Value; if FileExists(fPath) then aMasters.Add(MasterFiles[i].Value) end; end; function CreateTemporaryCopy(FileName, CompareFile: String): String; var s : String; i : Integer; begin if not SameText(ExtractFilePath(CompareFile), wbDataPath) then begin s := wbDataPath + ExtractFileName(CompareFile); if FileExists(s) then // Finds a unique name for i := 0 to 255 do begin s := wbDataPath + ExtractFileName(CompareFile) + IntToHex(i, 3); if not FileExists(s) then Break; end; if FileExists(s) then begin wbProgressCallback('Could not copy '+FileName+' into '+wbDataPath); Exit; end; CompareFile := s; CopyFile(PChar(FileName), PChar(CompareFile), false); end; Result := CompareFile; end; function SelectTemporaryCopy(FileName, CompareFile: String): String; var s : String; i : Integer; begin if not SameText(ExtractFilePath(CompareFile), wbDataPath) then begin for i := 0 to 255 do begin s := wbDataPath + ExtractFileName(CompareFile) + IntToHex(i, 3); if FileExists(s) then Break; end; if not FileExists(s) then s := wbDataPath + CompareFile + IntToHex(0, 3); CompareFile := s; if not FileExists(CompareFile) then CopyFile(PChar(FileName), PChar(CompareFile), false); end; Result := CompareFile; end; procedure TwbFileSource.Scan; var CurrentPtr : Pointer; Header : IwbFileHeader; MasterFiles : IwbContainerElementRef; i : Integer; ExtractInfo : TByteSet; Element : IwbElement; Container : IwbContainer; SelfRef : IwbContainerElementRef; fPath : String; modOffset : Cardinal; modPtr : Pointer; mods : TwbArray; begin SelfRef := Self as IwbContainerElementRef; flProgress('Start processing'); wbBaseOffset := Cardinal(flView); CurrentPtr := flView; TwbFileHeader.Create(Self, CurrentPtr, flEndPtr, wbFileHeader, '', False); if (GetElementCount <> 1) or not Supports(GetElement(0), IwbFileHeader, Header) then raise Exception.CreateFmt('Unexpected error reading file "%s"', [flFileName]); if Header.FileMagic <> wbFileMagic then raise Exception.CreateFmt('Expected header Magic %s, found %s in file "%s"', [wbFileMagic, String(Header.FileMagic), flFileName]); if fsOnlyHeader in flStates then Exit; if Pos('Absolute:', wbFilePlugins)=1 then begin modOffset := Cardinal(flView)+StrToInt(Copy(wbFilePlugins, 10, Length(wbFilePlugins))); modPtr := Pointer(modOffset); mods := TwbArray.Create(nil, modPtr, flEndPtr, wbArray('Modules', wbLenString('PluginName', 2), -4), '', False); Supports(mods, IwbContainerElementRef, MasterFiles); end else MasterFiles := Header.ElementByName[wbFilePlugins] as IwbContainerElementRef; if Assigned(MasterFiles) then for i := 0 to Pred(MasterFiles.ElementCount) do begin fPath := wbDataPath + MasterFiles[i].Value; if FileExists(fPath) then AddMaster(fPath) else if wbUseFalsePlugins then begin fPath := wbDataPath + wbAppName + TheEmptyPlugin; // place holder to keep save indexes if not FileExists(fPath) then fPath := ExtractFilePath(wbProgramPath) + wbAppName + TheEmptyPlugin; // place holder to keep save indexes if FileExists(fPath) then AddMaster(SelectTemporaryCopy(fPath, MasterFiles[i].Value), True); end; end; if flCompareTo <> '' then AddMaster(flCompareTo); if Assigned(wbExtractInfo) then ExtractInfo := wbExtractInfo^ else ExtractInfo := []; for i := 0 to Pred(wbFileChapters.MemberCount) do begin case wbFileChapters.Members[i].DefType of dtArray: Element := TwbArray.Create(Self, currentPtr, flEndPtr, wbFileChapters.Members[i], ''); dtStruct: Element := TwbStruct.Create(Self, currentPtr, flEndPtr, wbFileChapters.Members[i], ''); dtStructChapter: Element := TwbChapter.Create(Self, currentPtr, flEndPtr, wbFileChapters.Members[i], ''); dtUnion: Element := TwbUnion.Create(Self, currentPtr, flEndPtr, wbFileChapters.Members[i], ''); else Element := TwbValue.Create(Self, currentPtr, flEndPtr, wbFileChapters.Members[i], ''); end; if (i in ExtractInfo) and Supports(Element, IwbContainer, Container) then with Element as TwbContainer do DoInit; end; for i := 0 to Pred(GetElementCount) do GetElement(i).SortOrder := i; flProgress('Processing completed'); flLoadFinished := True; end; { TwbFileHeader } function TwbFileHeader.GetFileMagic: TwbFileMagic; var Element : IwbElement; Container : IwbContainer; begin Result := ''; if not Supports(Self, IwbContainer, Container) or (Container.ElementCount < 1) then Exit; Element := Container.Elements[0]; if Assigned(Element) then Result := Element.NativeValue; end; { TwbChapter } constructor TwbChapter.Create(const aContainer : IwbContainer; const aValueDef : IwbValueDef; const aSource : IwbElement; const aOnlySK : Boolean; const aNameSuffix : string); var Dummy : Integer; begin if Assigned(aValueDef) then Assert(Supports(aValueDef, IwbStructCDef)); inherited; cChapterSkipped := cChapterSkipped or ChaptersToSkip.Find(aValueDef.Name, Dummy); end; function TwbChapter.GetChapterName: String; var Struct : IwbStructCDef; begin if Assigned(vbValueDef) and Supports(vbValueDef, IwbStructCDef, Struct) then Result := Struct.GetChapterName(dcBasePtr, dcEndPtr, Self) else Result := Struct.GetChapterTypeName(dcBasePtr, dcEndPtr, Self); end; function TwbChapter.GetChapterType: Integer; var Struct : IwbStructCDef; begin Result := -1; if Assigned(vbValueDef) and Supports(vbValueDef, IwbStructCDef, Struct) then Result := Struct.GetChapterType(dcBasePtr, dcEndPtr, Self); end; function TwbChapter.GetChapterTypeName: String; var Struct : IwbStructCDef; begin if Assigned(vbValueDef) and Supports(vbValueDef, IwbStructCDef, Struct) then Result := Struct.GetChapterTypeName(dcBasePtr, dcEndPtr, Self) else Result := IntToStr(Struct.GetChapterType(dcBasePtr, dcEndPtr, Self)); end; function TwbChapter.GetElementType: TwbElementType; begin Result := etStructChapter; end; function TwbChapter.GetSkipped: Boolean; begin Result := cChapterSkipped; end; { TwbKeepAliveRoot } constructor TwbKeepAliveRoot.Create; begin inherited; Setup; end; destructor TwbKeepAliveRoot.Destroy; begin inherited; Teardown; end; procedure TwbKeepAliveRoot.Done; begin Teardown; end; procedure TwbKeepAliveRoot.Setup; begin New(karKAC); karKAC.kacFinished := False; karKAC.kacPrev := wbKeepAliveContext; karKAC.kacHead := TwbContainer.Create(nil); wbKeepAliveContext := karKAC; end; procedure TwbKeepAliveRoot.Teardown; var KAC : PwbKeepAliveContext; begin if Assigned(karKAC) then begin karKAC.kacFinished := True; karKAC := nil; end; KAC := wbKeepAliveContext; while Assigned(KAC) and KAC.kacFinished do begin wbKeepAliveContext := KAC.kacPrev; while Assigned(KAC.kacHead) do KAC.kacHead := KAC.kacHead.ReleaseKeepAlive; Dispose(KAC); KAC := wbKeepAliveContext; end; end; initialization wbContainedInDef[1] := wbFormIDCk('Worldspace', [WRLD], False, cpNormal, True); wbContainedInDef[6] := wbFormIDCk('Cell', [CELL], False, cpNormal, True); wbContainedInDef[7] := wbFormIDCk('Topic', [DIAL], False, cpNormal, True); wbContainedInDef[10] := wbFormIDCk('Quest', [QUST], False, cpNormal, True); SubRecordOrderList := TwbFastStringList.Create; SubRecordOrderList.Sorted := True; SubRecordOrderList.Duplicates := dupIgnore; RecordToSkip := TwbFastStringList.Create; RecordToSkip.Sorted := True; RecordToSkip.Duplicates := dupIgnore; GroupToSkip := TwbFastStringList.Create; GroupToSkip.Sorted := True; GroupToSkip.Duplicates := dupIgnore; ChaptersToSkip := TwbFastStringList.Create; ChaptersToSkip.Sorted := True; ChaptersToSkip.Duplicates := dupIgnore; FilesMap := TwbFastStringList.Create; FilesMap.Sorted := True; FilesMap.Duplicates := dupError; finalization WriteSubRecordOrderList; FreeAndNil(SubRecordOrderList); FreeAndNil(RecordToSkip); FreeAndNil(GroupToSkip); FreeAndNil(ChaptersToSkip); FreeAndNil(FilesMap); wbContainedInDef[1] := nil; wbContainedInDef[6] := nil; wbContainedInDef[7] := nil; wbContainedInDef[10] := nil; end. ================================================ FILE: lib/xedit/wbInit.pas ================================================ {******************************************************************************* The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. *******************************************************************************} unit wbInit; {$I wbDefines.inc} interface uses Classes; var wbApplicationTitle : string; wbScriptsPath : string; wbScriptToRun : string; wbBackupPath : string; wbTempPath : string; wbSavePath : string; wbMyGamesTheGamePath : string; wbPluginsFileName : String; wbSettingsFileName : string; wbModGroupFileName : string; wbPluginToUse : string; // Passed a specific plugin as parameter wbLogFile : string; // Optional log file for this session wbMyProfileName : string; wbMasterUpdateDone : Boolean; wbDontSave : Boolean; wbDontBackup : Boolean = False; wbRemoveTempPath : Boolean = True; wbQuickShowConflicts : Boolean; wbQuickClean : Boolean; wbParamIndex : integer = 1; // First unused parameter wbPluginsToUse : TStringList; function wbFindNextValidCmdLineFileName(var startingIndex : integer; out aValue : string; defaultPath : string = '') : Boolean; function wbFindNextValidCmdLinePlugin(var startingIndex : integer; out aValue : string; defaultPath : string) : Boolean; function wbFindCmdLineParam(const aSwitch : string; out aValue : string): Boolean; overload; function wbLoadMOHookFile: Boolean; procedure SwitchToCoSave; implementation uses SysUtils, Windows, Registry, ShellApi, Dialogs, ShlObj, IOUtils, IniFiles, wbHelpers, wbInterface, wbImplementation, wbDefinitionsFNV, wbDefinitionsFNVSaves, wbDefinitionsFO3, wbDefinitionsFO3Saves, wbDefinitionsFO4, wbDefinitionsFO4Saves, wbDefinitionsTES3, wbDefinitionsTES4, wbDefinitionsTES4Saves, wbDefinitionsTES5, wbDefinitionsTES5Saves; function wbFindCmdLineParam(const aSwitch : string; const aChars : TSysCharSet; aIgnoreCase : Boolean; out aValue : string) : Boolean; overload; var i : Integer; s : string; begin Result := False; aValue := ''; for i := 1 to ParamCount do begin s := ParamStr(i); if (aChars = []) or (s[1] in aChars) then if aIgnoreCase then begin if AnsiCompareText(Copy(s, 2, Length(aSwitch)), aSwitch) = 0 then begin if (length(s)>(length(aSwitch)+2)) and (s[Length(aSwitch) + 2] = ':') then begin aValue := Copy(s, Length(aSwitch) + 3, MaxInt); Result := True; end; Exit; end; end else if AnsiCompareStr(Copy(s, 2, Length(aSwitch)), aSwitch) = 0 then begin if s[Length(aSwitch) + 2] = ':' then begin aValue := Copy(s, Length(aSwitch) + 3, MaxInt); Result := True; end; Exit; end; end; end; function wbFindCmdLineParam(var startingIndex : integer; const aChars : TSysCharSet; out aValue : string) : Boolean; overload; var i : integer; s : string; begin Result := False; aValue := ''; for i := startingIndex to ParamCount do begin s := ParamStr(i); if (aChars = []) or (s[1] in aChars) then // skipped Inc(startingIndex) else begin aValue := ParamStr(i); startingIndex := i+1; Result := True; break; end end; end; function wbFindCmdLineParam(const aSwitch : string; out aValue : string) : Boolean; overload; begin Result := wbFindCmdLineParam(aSwitch, SwitchChars, True, aValue); end; function wbFindCmdLineParam(var startingIndex : integer; out aValue : string) : Boolean; overload; begin Result := wbFindCmdLineParam(startingIndex, SwitchChars, aValue); end; function wbCheckForValidExtension(aFilePath : string; const anExtension : string): Boolean; overload; begin Result := UpperCase(ExtractFileExt(aFilePath)) = UpperCase(anExtension); end; function wbCheckForPluginExtension(aFilePath : string): Boolean; begin Result := wbCheckForValidExtension(aFilePath, '.esp') or wbCheckForValidExtension(aFilePath, '.esm'); end; function wbCheckForValidExtension(aFilePath : string): Boolean; overload; begin Result := wbCheckForPluginExtension(aFilePath) or wbCheckForValidExtension(aFilePath, '.fos') or wbCheckForValidExtension(aFilePath, '.ess'); end; function wbFindNextValidCmdLineFileName(var startingIndex : integer; out aValue : string; defaultPath : string = '') : Boolean; begin Result := wbFindCmdLineParam(startingIndex, SwitchChars, aValue); if Result and not FileExists(aValue) then if (defaultPath<>'') then if FileExists(defaultPath+'\'+aValue) then aValue := ExpandFileName(defaultPath+'\'+aValue) else Result := False else Result := False; end; function wbFindNextValidCmdLinePlugin(var startingIndex : integer; out aValue : string; defaultPath : string) : Boolean; begin repeat Result := wbFindNextValidCmdLineFileName(startingIndex, aValue, defaultPath); until not Result or wbCheckForPluginExtension(aValue); if Result then if (AnsiCompareText(ExtractFilePath(ExpandFileName(aValue)), ExpandFileName(defaultPath)) = 0) then begin aValue := ExtractFileName(aValue); if not Assigned(wbPluginsToUse) then wbPluginsToUse := TStringList.Create; wbPluginsToUse.Add(aValue); end else Result := False; end; // several ini settings should be read before record definitions // they may affect definitions like wbSimpleRecords // and should be overridden by command line parameters procedure ReadSettings; var Settings: TMemIniFile; begin try Settings := TMemIniFile.Create(wbSettingsFileName); try wbLoadBSAs := Settings.ReadBool('Options', 'LoadBSAs', wbLoadBSAs); wbSimpleRecords := Settings.ReadBool('Options', 'SimpleRecords', wbSimpleRecords); wbShowFlagEnumValue := Settings.ReadBool('Options', 'ShowFlagEnumValue', wbShowFlagEnumValue); wbTrackAllEditorID := Settings.ReadBool('Options', 'TrackAllEditorID', wbTrackAllEditorID); finally Settings.Free; end; finally end; end; function GetCSIDLShellFolder(CSIDLFolder: integer): string; begin SetLength(Result, MAX_PATH); SHGetSpecialFolderPath(0, PChar(Result), CSIDLFolder, True); SetLength(Result, StrLen(PChar(Result))); if (Result <> '') then Result := IncludeTrailingBackslash(Result); end; function CheckAppPath: string; const //gmFNV, gmFO3, gmTES3, gmTES4, gmTES5, gmSSE, gmFO4 ExeName : array[TwbGameMode] of string = ('FalloutNV.exe', 'Fallout3.exe', 'Morrowind.exe', 'Oblivion.exe', 'TESV.exe', 'SkyrimSE.exe', 'Fallout4.exe'); var s: string; begin Result := ''; s := ExtractFilePath(ParamStr(0)); while Length(s) > 3 do begin if FileExists(s + ExeName[wbGameMode]) and DirectoryExists(s + 'Data') then begin Result := s; Exit; end; s := ExtractFilePath(ExcludeTrailingPathDelimiter(s)); end; end; {===SafeLoadLibrary============================================================} {$IFDEF CPUX86} function TestAndClearFPUExceptions(AExceptionMask: Word): Boolean; asm PUSH ECX MOV CX, AX FSTSW AX TEST AX, CX JNE @@bad XOR EAX, EAX INC EAX JMP @@exit @@bad: XOR EAX, EAX @@exit: POP ECX FCLEX RET end; {------------------------------------------------------------------------------} function SafeLoadLibrary(const Filename: string; ErrorMode: UINT): HMODULE; var OldMode: UINT; FPUControlWord: Word; begin OldMode := SetErrorMode(ErrorMode); try FPUControlWord := Get8087CW(); Result := LoadLibrary(PChar(Filename)); TestAndClearFPUExceptions(0); Set8087CW(FPUControlWord); finally SetErrorMode(OldMode); end; end; {==============================================================================} {$ENDIF CPUX86} function wbLoadMOHookFile: Boolean; var HookDll : HMODULE; Init : function(logLevel: Integer; profileName: LPCWSTR): BOOL; cdecl; begin if not wbShouldLoadMOHookFile then Exit(True); Result := False; if not FileExists(wbMOHookFile) then Exit; HookDll := SafeLoadLibrary(wbMOHookFile, SEM_NOOPENFILEERRORBOX); if HookDll <> 0 then begin Pointer(@Init) := GetProcAddress(HookDll, 'Init'); if Assigned(Pointer(@Init)) then Result := Init(0, PWideChar(UnicodeString(wbMOProfile))); end; end; procedure DoInitPath(const ParamIndex: Integer); const sBethRegKey = '\SOFTWARE\Bethesda Softworks\'; sBethRegKey64 = '\SOFTWARE\Wow6432Node\Bethesda Softworks\'; var s : String; IniFile : TIniFile; begin wbModGroupFileName := wbProgramPath + wbAppName + wbToolName + '.modgroups'; if not wbFindCmdLineParam('S', wbScriptsPath) then wbScriptsPath := wbProgramPath + 'Edit Scripts\'; if not wbFindCmdLineParam('T', wbTempPath) then wbTempPath := IncludeTrailingPathDelimiter(TPath.GetTempPath + wbAppName + 'Edit') else wbRemoveTempPath := not DirectoryExists(wbTempPath); if not wbFindCmdLineParam('D', wbDataPath) then begin wbDataPath := CheckAppPath; if wbDataPath = '' then with TRegistry.Create do try RootKey := HKEY_LOCAL_MACHINE; if not OpenKeyReadOnly(sBethRegKey + wbGameName2 + '\') then if not OpenKeyReadOnly(sBethRegKey64 + wbGameName2 + '\') then begin s := 'Fatal: Could not open registry key: ' + sBethRegKey + wbGameName + '\'; // if wbGameMode = gmTES5 then // All game exists on steam now ShowMessage(s+#13+#10+'This can happen after Steam updates, run game''s launcher to restore registry settings'); wbDontSave := True; Exit; end; wbDataPath := ReadString('Installed Path'); if wbDataPath = '' then begin s := 'Fatal: Could not determine '+wbGameName2+' installation path, no "Installed Path" registry key'; // if wbGameMode = gmTES5 then ShowMessage(s+#13+#10+'This can happen after Steam updates, run game''s launcher to restore registry settings'); wbDontSave := True; end; finally Free; end; if wbDataPath <>'' then wbDataPath := IncludeTrailingPathDelimiter(wbDataPath) + 'Data\'; end else wbDataPath := IncludeTrailingPathDelimiter(wbDataPath); wbOutputPath := wbDataPath; if wbFindCmdLineParam('O', s) and (Length(s) > 0) then if s[1] = '.' then //assume relative path wbOutputPath := IncludeTrailingPathDelimiter(wbOutputPath + s) else //assume absolute path wbOutputPath := IncludeTrailingPathDelimiter(s); wbMOHookFile := wbDataPath + '..\Mod Organizer\hook.dll'; if not wbFindCmdLineParam('I', wbTheGameIniFileName) then begin wbMyProfileName := GetCSIDLShellFolder(CSIDL_PERSONAL); if wbMyProfileName = '' then begin ShowMessage('Fatal: Could not determine my documents folder'); Exit; end; wbMyGamesTheGamePath := wbMyProfileName + 'My Games\'+ wbGameName2 +'\'; if wbGameMode in [gmFO3, gmFNV] then wbTheGameIniFileName := wbMyGamesTheGamePath + 'Fallout.ini' else if wbGameMode = gmFO4 then wbTheGameIniFileName := wbMyGamesTheGamePath + 'Fallout4.ini' else wbTheGameIniFileName := wbMyGamesTheGamePath + wbGameName + '.ini'; end; if not wbFindCmdLineParam('G', wbSavePath) then begin if wbMyGamesTheGamePath = '' then wbMyGamesTheGamePath := ExtractFilePath(wbTheGameIniFileName); s := 'Saves\'; if FileExists(wbTheGameIniFileName) then begin IniFile := TIniFile.Create(wbTheGameIniFileName); try s := IniFile.ReadString('General', 'SLocalSavePath', s); finally FreeAndNil(IniFile); end; end; wbSavePath := wbMyGamesTheGamePath + s; end; wbSavePath := IncludeTrailingPathDelimiter(wbSavePath); wbParamIndex := ParamIndex; if not wbFindCmdLineParam('P', wbPluginsFileName) then if not (wbFindNextValidCmdLineFileName(wbParamIndex, wbPluginsFileName) and SameText(ExtractFileExt(wbPluginsFileName), '.txt')) or wbCheckForValidExtension(wbPluginsFileName) then begin wbParamIndex := ParamIndex; wbPluginsFileName := GetCSIDLShellFolder(CSIDL_LOCAL_APPDATA); if wbPluginsFileName = '' then begin ShowMessage('Fatal: Could not determine the local application data folder'); Exit; end; wbPluginsFileName := wbPluginsFileName + wbGameName2 + '\Plugins.txt'; end; // settings in the ini file next to app, or in the same folder with plugins.txt wbSettingsFileName := wbProgramPath + wbAppName + wbToolName + '.ini'; if not FileExists(wbSettingsFileName) then wbSettingsFileName := ChangeFileExt(wbPluginsFileName, '.'+LowerCase(wbAppName)+'viewsettings'); wbBackupPath := ''; if not (wbDontSave or wbFindCmdLineParam('B', wbBackupPath)) then begin wbBackupPath := wbDataPath + wbAppName + 'Edit Backups\'; if not DirectoryExists(wbBackupPath) then if not ForceDirectories(wbBackupPath) then wbBackupPath := wbDataPath; end; wbFindCmdLineParam('R', wbLogFile); end; var wbForcedModes: string; AppGameMode, AppToolMode, AppSourceMode: string; procedure DetectAppMode; const SourceModes : array [1..2] of string = ('plugins', 'saves'); GameModes: array [1..6] of string = ('tes4', 'tes5', 'sse', 'fo3', 'fnv', 'fo4'); ToolModes: array [1..12] of string = ( 'edit', 'view', 'lodgen', 'script', 'translate', 'setesm', 'clearesm', 'sortandclean', 'sortandcleanmasters', 'checkforerrors', 'checkforitm', 'checkfordr'); var s, p: string; begin // Detecting game mode // check command line params first for mode overrides // they should take precendence over application name detection // AppSourceMode := SourceModes[1]; for s in SourceModes do if FindCmdLineSwitch(s) or wbFindCmdLineParam(s, p) or (Pos(s, wbForcedModes) <> 0) then begin AppSourceMode := s; Break; end; // if no overrrides, then check by executable name if AppSourceMode = '' then for s in SourceModes do if (Pos(s, LowerCase(ExtractFileName(ParamStr(0)))) <> 0) or (Pos(s, wbForcedModes) <> 0) then begin AppSourceMode := s; Break; end; // if still nothing, then default value if AppSourceMode = '' then AppSourceMode := 'plugins'; for s in GameModes do if FindCmdLineSwitch(s) or wbFindCmdLineParam(s, p) or (Pos(s, wbForcedModes) <> 0) then begin AppGameMode := s; Break; end; // if no overrrides, then check by executable name if AppGameMode = '' then for s in GameModes do if (Pos(s, LowerCase(ExtractFileName(ParamStr(0)))) <> 0) or (Pos(s, wbForcedModes) <> 0) then begin AppGameMode := s; Break; end; // if still nothing, then default value if AppGameMode = '' then AppGameMode := 'fo4'; // the same for tool mode for s in ToolModes do if FindCmdLineSwitch(s) or wbFindCmdLineParam(s, p) or (Pos(s, wbForcedModes) <> 0) then begin AppToolMode := s; Break; end; if AppToolMode = '' then for s in ToolModes do if (Pos(s, LowerCase(ExtractFileName(ParamStr(0)))) <> 0) or (Pos(s, wbForcedModes) <> 0) then begin AppToolMode := s; Break; end; if AppToolMode = '' then AppToolMode := 'edit'; end; function isMode(aMode: String): Boolean; begin aMode := LowerCase(aMode); Result := (AppGameMode = aMode) or (AppToolMode = aMode) or (AppSourceMode = aMode); end; // Force app modes function CheckForcedMode: Boolean; var s: string; i: integer; begin Result := False; // there is a game specific script provided to execute // go into 'script' tool mode and detect game mode by script's extension i := 1; if wbFindCmdLineParam('script', s) or wbFindNextValidCmdLineFileName(i, s) then begin if not FileExists(s) then Exit; wbScriptToRun := s; s := ExtractFileExt(s); i := Pos(UpperCase('pas'), UpperCase(s)); if (i > 0) and (i = Length(s) - 2) then begin wbForcedModes := Copy(s, 2, Length(s) - 4) + ',script'; Result := True; end; end; end; procedure wbDoInit; var s: string; begin wbReportMode := False; wbEditAllowed := True; wbDontSave := False; CheckForcedMode; DetectAppMode; if isMode('Saves') then begin wbToolSource := tsSaves; wbSourceName := 'Saves'; wbUseFalsePlugins := True; end else begin // defaults to plugin wbToolSource := tsPlugins; wbSourceName := 'Plugins'; end; if isMode('View') then begin wbToolMode := tmView; wbToolName := 'View'; wbEditAllowed := False; wbDontSave := True; end else if isMode('MasterUpdate') then begin wbToolMode := tmMasterUpdate; wbToolName := 'MasterUpdate'; end else if isMode('MasterRestore') then begin wbToolMode := tmMasterRestore; wbToolName := 'MasterRestore'; end else if isMode('LODGen') then begin wbToolMode := tmLODgen; wbToolName := 'LODGen'; wbEditAllowed := False; wbDontSave := True; end else if isMode('Script') then begin wbToolMode := tmScript; wbToolName := 'Script'; end else if isMode('Translate') then begin wbToolMode := tmTranslate; wbToolName := 'Trans'; end else if isMode('setESM') then begin wbToolMode := tmESMify; wbToolName := 'SettingESMflag'; end else if isMode('clearESM') then begin wbToolMode := tmESPify; wbToolName := 'ClearingESMflag'; end else if isMode('SortAndClean') then begin wbToolMode := tmSortAndCleanMasters; wbToolName := 'SortAndCleanMasters'; end else if isMode('CheckForErrors') then begin wbToolMode := tmCheckForErrors; wbToolName := 'CheckForErrors'; end else if isMode('CheckForITM') then begin wbToolMode := tmCheckForITM; wbToolName := 'CheckForITM'; end else if isMode('CheckForDR') then begin wbToolMode := tmCheckForDR; wbToolName := 'CheckForDR'; end else if isMode('Edit') then begin wbToolMode := tmEdit; wbToolName := 'Edit'; end else begin ShowMessage('Application name must contain Edit, View, LODGen, MasterUpdate, MasterRestore, setESM, clearESM, sortAndCleanMasters, CheckForITM, CheckForDR or CheckForErrors to select mode.'); Exit; end; if isMode('FNV') then begin wbGameMode := gmFNV; wbAppName := 'FNV'; wbGameName := 'FalloutNV'; if not (wbToolMode in wbAlwaysMode) and not (wbToolMode in [tmMasterUpdate, tmMasterRestore]) then begin ShowMessage('Application '+wbGameName+' does not currently support '+wbToolName); Exit; end; if not (wbToolSource in [tsPlugins, tsSaves]) then begin ShowMessage('Application '+wbGameName+' does not currently support '+wbSourceName); Exit; end; end else if isMode('FO3') then begin wbGameMode := gmFO3; wbAppName := 'FO3'; wbGameName := 'Fallout3'; if not (wbToolMode in wbAlwaysMode) and not (wbToolMode in [tmMasterUpdate, tmMasterRestore]) then begin ShowMessage('Application '+wbGameName+' does not currently support '+wbToolName); Exit; end; if not (wbToolSource in [tsPlugins]) then begin ShowMessage('Application '+wbGameName+' does not currently support '+wbSourceName); Exit; end; end else if isMode('TES3') then begin wbGameMode := gmTES3; wbAppName := 'TES3'; wbGameName := 'Morrowind'; if not (wbToolMode in []) then begin ShowMessage('Application '+wbGameName+' does not currently support '+wbToolName); Exit; end; if not (wbToolSource in []) then begin ShowMessage('Application '+wbGameName+' does not currently support '+wbSourceName); Exit; end; end else if isMode('TES4') then begin wbGameMode := gmTES4; wbAppName := 'TES4'; wbGameName := 'Oblivion'; if not (wbToolMode in wbAlwaysMode) and not (wbToolMode in []) then begin ShowMessage('Application '+wbGameName+' does not currently support '+wbToolName); Exit; end; if not (wbToolSource in [tsPlugins]) then begin ShowMessage('Application '+wbGameName+' does not currently support '+wbSourceName); Exit; end; end else if isMode('TES5') then begin wbGameMode := gmTES5; wbAppName := 'TES5'; wbGameName := 'Skyrim'; if not (wbToolMode in wbAlwaysMode) and not (wbToolMode in [tmTranslate]) then begin ShowMessage('Application '+wbGameName+' does not currently support '+wbToolName); Exit; end; if not (wbToolSource in [tsPlugins, tsSaves]) then begin ShowMessage('Application '+wbGameName+' does not currently support '+wbSourceName); Exit; end; end else if isMode('SSE') then begin wbGameMode := gmSSE; wbAppName := 'SSE'; wbGameName := 'Skyrim'; wbGameName2 := 'Skyrim Special Edition'; if not (wbToolMode in wbAlwaysMode) and not (wbToolMode in [tmTranslate]) then begin ShowMessage('Application '+wbGameName+' does not currently support '+wbToolName); Exit; end; if not (wbToolSource in [tsPlugins, tsSaves]) then begin ShowMessage('Application '+wbGameName+' does not currently support '+wbSourceName); Exit; end; end else if isMode('FO4') then begin wbGameMode := gmFO4; wbAppName := 'FO4'; wbGameName := 'Fallout4'; wbArchiveExtension := '.ba2'; if not (wbToolMode in wbAlwaysMode) and not (wbToolMode in [tmTranslate]) then begin ShowMessage('Application '+wbGameName+' does not currently support '+wbToolName); Exit; end; if not (wbToolSource in [tsPlugins, tsSaves]) then begin ShowMessage('Application '+wbGameName+' does not currently support '+wbSourceName); Exit; end; end else begin ShowMessage('Application name must contain FNV, FO3, FO4, SSE, TES4 or TES5 to select game.'); Exit; end; if (wbToolSource = tsSaves) and (wbToolMode = tmEdit) then begin ShowMessage('Application '+wbGameName+' does not currently support '+wbSourceName+' in '+wbToolName+' mode.'); Exit; end; if wbGameName2 = '' then wbGameName2 := wbGameName; DoInitPath(wbParamIndex); if wbGameMode = gmFNV then begin wbVWDInTemporary := True; wbLoadBSAs := False; ReadSettings; end else if wbGameMode = gmFO3 then begin wbVWDInTemporary := True; wbLoadBSAs := False; ReadSettings; end else if wbGameMode = gmTES3 then begin wbLoadBSAs := False; wbAllowInternalEdit := false; ReadSettings; end else if wbGameMode = gmTES4 then begin wbLoadBSAs := True; wbAllowInternalEdit := false; ReadSettings; end else if wbGameMode = gmTES5 then begin wbVWDInTemporary := True; wbLoadBSAs := True; // localization won't work otherwise wbHideIgnored := False; // to show Form Version ReadSettings; end else if wbGameMode = gmSSE then begin wbVWDInTemporary := True; wbLoadBSAs := True; // localization won't work otherwise wbHideIgnored := False; // to show Form Version ReadSettings; end else if wbGameMode = gmFO4 then begin wbVWDInTemporary := True; wbVWDAsQuestChildren := True; wbLoadBSAs := True; // localization won't work otherwise wbHideIgnored := False; // to show Form Version ReadSettings; //wbCreateContainedIn := False; end else begin Exit; end; case wbGameMode of gmFNV: case wbToolSource of tsSaves: DefineFNVSaves; tsPlugins: DefineFNV; end; gmFO3: case wbToolSource of tsSaves: DefineFO3Saves; tsPlugins: DefineFO3; end; gmFO4: case wbToolSource of tsSaves: DefineFO4Saves; tsPlugins: DefineFO4; end; gmTES3: case wbToolSource of tsPlugins: DefineTES3; end; gmTES4: case wbToolSource of tsSaves: DefineTES4Saves; tsPlugins: DefineTES4; end; gmTES5: case wbToolSource of tsSaves: DefineTES5Saves; tsPlugins: DefineTES5; end; gmSSE: case wbToolSource of tsSaves: DefineTES5Saves; tsPlugins: DefineTES5; end else ShowMessage('Application name must contain FNV, FO3, FO4, SSE, TES4 or TES5 to select game.'); Exit; end; case wbGameMode of gmTES5, gmSSE: wbLanguage := 'English'; gmFO4: wbLanguage := 'En'; end; if wbFindCmdLineParam('l', s) then wbLanguage := s; if wbFindCmdLineParam('cp', s) then begin if SameText(s, 'utf-8') then wbStringEncoding := seUTF8; end; if FindCmdLineSwitch('speed') then wbSpeedOverMemory := True; if FindCmdLineSwitch('memory') then wbSpeedOverMemory := False; if FindCmdLineSwitch('report') then wbReportMode := (DebugHook <> 0); if FindCmdLineSwitch('MoreInfoForIndex') then wbMoreInfoForIndex := true; if FindCmdLineSwitch('fixup') then wbAllowInternalEdit := True else if FindCmdLineSwitch('nofixup') then wbAllowInternalEdit := False; if FindCmdLineSwitch('skipbsa') then wbLoadBSAs := False else if FindCmdLineSwitch('forcebsa') then wbLoadBSAs := True; if FindCmdLineSwitch('skipInternalEditing') then wbAllowInternalEdit := False else if FindCmdLineSwitch('forceInternalEditing') then wbAllowInternalEdit := True; if FindCmdLineSwitch('showfixup') then wbShowInternalEdit := True else if FindCmdLineSwitch('hidefixup') then wbShowInternalEdit := False; if FindCmdLineSwitch('quickshowconflicts') then wbQuickShowConflicts := True; if FindCmdLineSwitch('IKnowWhatImDoing') then wbIKnowWhatImDoing := True; if FindCmdLineSwitch('quickclean') and (wbToolSource in [tsPlugins]) then wbQuickClean := wbIKnowWhatImDoing; if FindCmdLineSwitch('TrackAllEditorID') then wbTrackAllEditorID := True; if wbToolMode in wbPluginModes then // look for the file name if not wbFindNextValidCmdLinePlugin(wbParamIndex, wbPluginToUse, wbDataPath) then begin ShowMessage(wbToolName+' mode requires a valid plugin name!'); Exit; end; if wbToolMode = tmLODgen then begin wbIKnowWhatImDoing := True; wbAllowInternalEdit := False; wbShowInternalEdit := False; wbLoadBSAs := True; wbBuildRefs := False; end else if wbToolMode = tmScript then begin wbIKnowWhatImDoing := True; wbLoadBSAs := True; wbBuildRefs := True; end else if wbToolMode in [tmMasterUpdate, tmESMify] then begin wbIKnowWhatImDoing := True; wbAllowInternalEdit := False; wbShowInternalEdit := False; wbLoadBSAs := False; wbBuildRefs := False; wbMasterUpdateFilterONAM := wbToolMode in [tmESMify]; if FindCmdLineSwitch('filteronam') then wbMasterUpdateFilterONAM := True else if FindCmdLineSwitch('noFilteronam') then wbMasterUpdateFilterONAM := True; if FindCmdLineSwitch('FixPersistence') then wbMasterUpdateFixPersistence := True else if FindCmdLineSwitch('NoFixPersistence') then wbMasterUpdateFixPersistence := False; end else if wbToolMode in [tmMasterRestore, tmESPify, tmCheckForDR, tmCheckForITM, tmCheckForErrors] then begin wbIKnowWhatImDoing := True; wbAllowInternalEdit := False; wbShowInternalEdit := False; wbLoadBSAs := False; wbBuildRefs := False; end else if wbToolMode = tmTranslate then begin wbTranslationMode := True; end; wbApplicationTitle := wbAppName + wbToolName + ' ' + VersionString; {$IFDEF LiteVersion} wbApplicationTitle := wbApplicationTitle + ' Lite'; {$ENDIF} {$IFDEF WIN64} wbApplicationTitle := wbApplicationTitle + ' x64'; {$ENDIF WIN64} if FindCmdLineSwitch('fixuppgrd') then wbFixupPGRD := True; wbShouldLoadMOHookFile := wbFindCmdLineParam('moprofile', wbMOProfile); if (wbToolMode = tmEdit) and not wbIsAssociatedWithExtension('.' + wbAppName + 'pas') then try wbAssociateWithExtension('.' + wbAppName + 'pas', wbAppName + 'Script', wbAppName + wbToolName + ' script'); except end; end; procedure SwitchToCoSave; begin case wbGameMode of gmFNV: SwitchToFNVCoSave; gmFO3: SwitchToFO3CoSave; gmTES4: SwitchToTES4CoSave; gmTES5: SwitchToTES5CoSave; gmSSE: SwitchToTES5CoSave; end; end; initialization wbDoInit; end. ================================================ FILE: lib/xedit/wbInterface.pas ================================================ {****************************************************************************** The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. *******************************************************************************} unit wbInterface; {$I wbDefines.inc} interface uses Classes, SysUtils, Graphics; const VersionString = '3.2'; clOrange = $004080FF; wbFloatDigits = 6; wbHardcodedDat = '.Hardcoded.keep.this.with.the.exe.and.otherwise.ignore.it.I.really.mean.it.dat'; type TwbProgressCallback = procedure(const aStatus: string); TwbPointerArray = array [0..Pred(High(Integer) div SizeOf(Pointer))] of Pointer; PwbPointerArray = ^TwbPointerArray; {General array of pointer} threadvar wbProgressCallback : TwbProgressCallback; wbCurrentTick : Integer; wbCurrentAction : string; wbStartTime : TDateTime; wbShowStartTime : Integer; var wbDisplayLoadOrderFormID : Boolean = False; wbSimpleRecords : Boolean = True; wbFixupPGRD : Boolean = False; wbIKnowWhatImDoing : Boolean = False; wbHideUnused : Boolean = True; wbHideIgnored : Boolean = True; wbHideNeverShow : Boolean = True; wbShowFormVersion : Boolean = False; wbShowFlagEnumValue : Boolean = False; wbShowGroupRecordCount : Boolean = False; wbDisplayShorterNames : Boolean = False; wbSortSubRecords : Boolean = False; wbSortFLST : Boolean = True; wbSortGroupRecord : Boolean = False; wbRemoveOffsetData : Boolean = True; wbEditAllowed : Boolean = False; wbFlagsAsArray : Boolean = False; wbDelayLoadRecords : Boolean = True; wbMoreInfoForUnknown : Boolean = False; wbMoreInfoForIndex : Boolean = False; wbTranslationMode : Boolean = False; wbTestWrite : Boolean = False; wbForceNewHeader : Boolean = False; // add wbNewHeaderAddon value to the headers of mainrecords and GRUP records wbNewHeaderAddon : Cardinal = 40; // 4 additional bytes, 40 - new form version field wbRequireLoadOrder : Boolean = False; wbCreateContainedIn : Boolean = True; wbVWDInTemporary : Boolean = False; wbVWDAsQuestChildren : Boolean = False; wbResolveAlias : Boolean = True; wbActorTemplateHide : Boolean = True; wbClampFormID : Boolean = True; wbAllowErrors : Boolean = True; wbDoNotBuildRefsFor : TStringList; wbCopyIsRunning : Integer = 0; wbUDRSetXESP : Boolean = True; wbUDRSetScale : Boolean = False; wbUDRSetScaleValue : Single = 0.0; wbUDRSetZ : Boolean = True; wbUDRSetZValue : Single = -30000; wbUDRSetMSTT : Boolean = True; wbUDRSetMSTTValue : Int64 = $0000001B; { AshPile01 } wbMasterUpdateFilterONAM : Boolean = False; wbMasterUpdateFixPersistence : Boolean = True; wbAllowInternalEdit : Boolean = True; wbShowInternalEdit : Boolean = False; wbReportMode : Boolean = False; wbReportUnused : Boolean = False; wbReportRequired : Boolean = True; wbReportUnusedData : Boolean = True; wbReportUnknownFormIDs : Boolean = True; wbReportUnknownFloats : Boolean = True; wbReportUnknownStrings : Boolean = True; wbReportEmpty : Boolean = True; wbReportSometimesEmpty : Boolean = True; wbReportFormIDs : Boolean = True; wbReportNotFoundButAllowedFormIDs : Boolean = True; wbReportUnknownFlags : Boolean = True; wbReportUnknownEnums : Boolean = True; wbReportFormIDNotAllowedReferences : Boolean = True; wbReportUnknown : Boolean = True; wbMoreInfoForRequired : Boolean = False; wbMoreInfoForDecider : Boolean = False; wbTrackAllEditorID : Boolean = False; wbShowTip : Boolean = True; wbCheckExpectedBytes : Boolean = True; wbRotationFactor : Extended = 180/Pi; wbRotationScale : Integer = 4; wbDumpOffset : Integer = 0; // 1= starting offset, 2 = Count, 3 = Offsets, size and count wbBaseOffset : Cardinal = 0; wbProgramPath : string; wbDataPath : string; wbOutputPath : string; wbTheGameIniFileName : string; wbShouldLoadMOHookFile : Boolean; wbMOProfile : string; wbMOHookFile : string; wbSpeedOverMemory : Boolean = False; {$IFDEF USE_CODESITE} type TwbLoggingArea = ( laAddIfMissing, laElementAssign, laElementCanAssign, laElementSetToDefault, laElementWriteToStream, laElementMergeStorage, laDummy ); TwbLoggingAreas = set of TwbLoggingArea; var wbLoggingAreas : TwbLoggingAreas = [ laAddIfMissing, laElementAssign, laElementCanAssign, laElementSetToDefault, //laElementWriteToStream, //laElementMergeStorage, laDummy ]; function wbCodeSiteLoggingEnabled: Boolean; function wbBeginCodeSiteLogging: Integer; function wbEndCodeSiteLogging: Integer; {$ENDIF} type TConflictAll = ( caUnknown, caOnlyOne, caNoConflict, caConflictBenign, caOverride, caConflict, caConflictCritical ); TByteSet = set of Byte; TConflictAllSet = set of TConflictAll; TConflictAllColors = array[TConflictAll] of TColor; TConflictThis = ( ctUnknown, ctIgnored, ctNotDefined, ctIdenticalToMaster, ctOnlyOne, ctHiddenByModGroup, ctMaster, ctConflictBenign, ctOverride, ctIdenticalToMasterWinsConflict, ctConflictWins, ctConflictLoses ); TConflictThisSet = set of TConflictThis; TConflictThisColors = array[TConflictThis] of TColor; var wbColorConflictAll: TConflictAllColors = ( clDefault, // caUnknown clDefault, // caOnlyOne clLime, // caNoConflict clYellow, // caConflictBenign clYellow, // caOverride clRed, // caConflict clFuchsia // caConflictCritical ); wbColorConflictThis: TConflictThisColors = ( clWindowText, // ctUnknown clWindowText, // ctIgnored clMedGray, // ctNotDefined clDkGray, // ctIdenticalToMaster clWindowText, // ctOnlyOne clLtGray, // ctHiddenByModGroup clPurple, // ctMaster clWindowText, // ctConflictBenign clGreen, // ctOverride clOlive, // ctIdenticalToMasterWinsConflict clOrange, // ctConflictWins clRed // ctConflictLoses ); type TwbConflictPriority = ( cpIgnore, cpBenignIfAdded, cpBenign, cpTranslate, cpNormal, cpNormalIgnoreEmpty, cpCritical, cpFormID ); LongRecSmall = packed record Lo, Hi: Smallint; end; PwbSignature = ^TwbSignature; TwbSignature = array[0..3] of AnsiChar; TwbSignatures = array of TwbSignature; TwbFileMagic = string; TwbIntType = ( it0, itU8, itS8, itU16, itS16, itU32, itS32, itU64, itS64, itU24, itU6to30 ); TwbDefType = ( dtRecord, dtSubRecord, dtSubRecordArray, dtSubRecordStruct, dtSubRecordUnion, dtString, dtLString, dtLenString, dtByteArray, dtInteger, dtIntegerFormater, dtIntegerFormaterUnion, dtFlag, dtFloat, dtArray, dtStruct, dtUnion, dtEmpty, dtStructChapter ); TwbGroupTypes = set of Byte; TwbStringEncoding = (seCP1252, seUTF8); var dtNonValues : set of TwbDefType = [ dtRecord, dtSubRecord, dtSubRecordArray, dtSubRecordStruct, dtSubRecordUnion, dtArray, dtStruct, dtUnion, dtStructChapter ]; wbStringEncoding: TwbStringEncoding = seCP1252; type IwbDef = interface; TwbDefs = array of IwbDef; TwbDefPath = array of record Def : IwbDef; Index : Integer; end; IwbElement = interface; IwbDef = interface ['{C7739FBD-3B58-48A2-9DD0-8057D3496892}'] function GetDefType: TwbDefType; function GetDefTypeName: string; function CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; function Assign(const aTarget: IwbElement; aIndex: Integer; const aSource: IwbElement; aOnlySK: Boolean): IwbElement; function GetDefID: Cardinal; function Equals(const aDef: IwbDef): Boolean; function GetConflictPriority(const aElement: IwbElement): TwbConflictPriority; function GetConflictPriorityCanChange: Boolean; function GetRequired: Boolean; function CanContainFormIDs: Boolean; function GetDontShow(const aElement: IwbElement): Boolean; function GetHasDontShow: Boolean; function GetRoot: IwbDef; function GetNoReach: Boolean; function GetParent: IwbDef; procedure Report(const aParents: TwbDefPath); procedure Used(const aElement: IwbElement = nil; const s: string = ''); procedure PossiblyRequired; procedure NotRequired; function IsNotRequired: Boolean; property DefType: TwbDefType read GetDefType; property DefTypeName: string read GetDefTypeName; property DefID: Cardinal read GetDefID; property ConflictPriority[const aElement: IwbElement]: TwbConflictPriority read GetConflictPriority; property ConflictPriorityCanChange: Boolean read GetConflictPriorityCanChange; property Required: Boolean read GetRequired; property DontShow[const aElement: IwbElement]: Boolean read GetDontShow; property HasDontShow: Boolean read GetHasDontShow; property Root: IwbDef read GetRoot; property NoReach: Boolean read GetNoReach; property Parent: IwbDef read GetParent; end; TwbElementType = ( etFile, etMainRecord, etGroupRecord, etSubRecord, etSubRecordStruct, etSubRecordArray, etSubRecordUnion, etArray, etStruct, etValue, etFlag, etStringListTerminator, etUnion, etStructChapter ); TwbElementTypes = set of TwbElementType; IwbContainer = interface; IwbFile = interface; IwbNamedDef = interface; IwbValueDef = interface; IwbMainRecord = interface; TwbElementState = ( esModified, esInternalModified, esUnsaved, esSortKeyValid, esExtendedSortKeyValid, esHidden, esParentHidden, esParentHiddenChecked, esNotReachable, esReachable, esTagged, esDeciding, esNotSuitableToAddTo, esDummy, {Used in wbScriptAdapter as a default value} esConstructionComplete, esDestroying, esChangeNotified, esModifiedUpdated, esSorting ); TwbElementStates = set of TwbElementState; TwbEditType = ( etDefault, etComboBox, etCheckComboBox ); TDynFiles = array of IwbFile; IwbElement = interface ['{F4B4637D-C794-415F-B5C7-587EAA4095B3}'] function GetElementID: Cardinal; function GetElementStates: TwbElementStates; procedure SetElementState(aState: TwbElementState; Clear: Boolean = false); function Equals(const aElement: IwbElement): Boolean; function GetValue: string; function GetCheck: string; function GetSortKey(aExtended: Boolean): string; function GetSortPriority: Integer; function GetName: string; function GetBaseName: string; function GetDisplayName: string; function GetShortName: string; function GetPath: string; function GetFullPath: string; function GetPathName: string; function GetSkipped: Boolean; function GetDef: IwbNamedDef; function GetValueDef: IwbValueDef; function GetResolvedValueDef: IwbValueDef; function GetElementType: TwbElementType; function GetContainer: IwbContainer; function GetContainingMainRecord: IwbMainRecord; function GetFile: IwbFile; function GetReferenceFile: IwbFile; function GetSortOrder: Integer; procedure SetSortOrder(aSortOrder: Integer); function GetMemoryOrder: Integer; procedure SetMemoryOrder(aSortOrder: Integer); procedure BuildRef; function CompareExchangeFormID(aOldFormID: Cardinal; aNewFormID: Cardinal): Boolean; function GetEditValue: string; procedure SetEditValue(const aValue: string); function GetNativeValue: Variant; procedure SetNativeValue(const aValue: Variant); function GetIsEditable: Boolean; function GetIsRemoveable: Boolean; procedure RequestStorageChange(var aBasePtr, aEndPtr: Pointer; aNewSize: Cardinal); function GetConflictPriority: TwbConflictPriority; function GetConflictPriorityCanChange: Boolean; function GetModified: Boolean; procedure MarkModifiedRecursive; function GetIsInjected: Boolean; function GetReferencesInjected: Boolean; function GetInjectionSourceFiles: TDynFiles; function GetIsNotReachable: Boolean; function GetDataSize: Integer; procedure SetDataSize(aSize: Integer); procedure MergeStorage(var aBasePtr: Pointer; aEndPtr: Pointer); procedure InformStorage(var aBasePtr: Pointer; aEndPtr: Pointer); procedure AddReferencedFromID(aFormID: Cardinal); function CanContainFormIDs: Boolean; function GetLinksTo: IwbElement; function GetNoReach: Boolean; procedure ReportRequiredMasters(aStrings: TStrings; aAsNew: Boolean; recursive: Boolean = True; initial: Boolean = false); function AddIfMissing(const aElement: IwbElement; aAsNew, aDeepCopy : Boolean; const aPrefixRemove, aPrefix, aSuffix: string): IwbElement; procedure ResetConflict; procedure ResetReachable; function RemoveInjected(aCanRemove: Boolean): Boolean; function GetEditType: TwbEditType; function GetEditInfo: string; function GetDontShow: Boolean; procedure SetToDefault; procedure NotifyChanged(aContainer: Pointer); function CanAssign(aIndex: Integer; const aElement: IwbElement; aCheckDontShow: Boolean): Boolean; function Assign(aIndex: Integer; const aElement: IwbElement; aOnlySK: Boolean): IwbElement; procedure Remove; function HasErrors: Boolean; procedure Hide; procedure Show; function GetIsHidden: Boolean; procedure MoveUp; procedure MoveDown; function CanMoveUp: Boolean; function CanMoveDown: Boolean; procedure NextMember; procedure PreviousMember; function CanChangeMember: Boolean; procedure Tag; procedure ResetTags; function IsTagged: Boolean; property IsHidden: Boolean read GetIsHidden; procedure WriteToStream(aStream: TStream; aResetModified: Boolean); function CopyInto(const aFile: IwbFile; AsNew, DeepCopy: Boolean; const aPrefixRemove, aPrefix, aSuffix: string): IwbElement; function GetTreeHead: Boolean; // Is the element expected to be a "header record" in the tree navigator function GetTreeBranch: Boolean; // Is the element expected to show in the tree navigator property ElementID: Cardinal read GetElementID; property ElementStates: TwbElementStates read GetElementStates; property Container: IwbContainer read GetContainer; property ContainingMainRecord: IwbMainRecord read GetContainingMainRecord; property _File: IwbFile read GetFile; property ReferenceFile: IwbFile read GetReferenceFile; property InjectionSourceFiles: TDynFiles read GetInjectionSourceFiles; property ElementType: TwbElementType read GetElementType; property Name: string read GetName; property BaseName: string read GetBaseName; property DisplayName: string read GetDisplayName; property ShortName: string read GetShortName; property Path: string read GetPath; property FullPath: string read GetFullPath; property PathName: string read GetPathName; property Skipped: Boolean read GetSkipped; property Value: string read GetValue; property SortKey[aExtended: Boolean]: string read GetSortKey; property Check: string read GetCheck; property Modified: Boolean read GetModified; property IsInjected: Boolean read GetIsInjected; property IsNotReachable: Boolean read GetIsNotReachable; property ReferencesInjected: Boolean read GetReferencesInjected; property IsEditable: Boolean read GetIsEditable; property EditValue: string read GetEditValue write SetEditValue; property NativeValue: Variant read GetNativeValue write SetNativeValue; property IsRemoveable: Boolean read GetIsRemoveable; property Def: IwbNamedDef read GetDef; property ValueDef: IwbValueDef read GetValueDef; property ResolvedValueDef: IwbValueDef read GetResolvedValueDef; property MemoryOrder: Integer read GetMemoryOrder write SetMemoryOrder; property SortPriority: Integer read GetSortPriority; property SortOrder: Integer read GetSortOrder write SetSortOrder; property ConflictPriority: TwbConflictPriority read GetConflictPriority; property ConflictPriorityCanChange: Boolean read GetConflictPriorityCanChange; property DataSize: Integer read GetDataSize write SetDataSize; property LinksTo: IwbElement read GetLinksTo; property NoReach: Boolean read GetNoReach; property EditType: TwbEditType read GetEditType; property EditInfo: string read GetEditInfo; property DontShow: Boolean read GetDontShow; property TreeHead: Boolean read GetTreeHead; property TreeBranch: Boolean read GetTreeBranch; end; IwbRecord = interface; TwbContainerState = ( csInit, csInitOnce, csInitDone, csInitializing, csReseting, csRefsBuild, csAsCreatedEmpty ); TwbContainerStates = set of TwbContainerState; TDynStrings = array of string; IwbContainerBase = interface(IwbElement) ['{1484D26A-0F67-41FA-9044-8772E68CBA56}'] function GetElement(aIndex: Integer): IwbElement; function GetElementCount: Integer; function GetElementByName(const aName: string): IwbElement; function GetRecordBySignature(const aSignature: TwbSignature): IwbRecord; function GetElementByMemoryOrder(aSortOrder: Integer): IwbElement; function GetElementBySignature(const aSignature: TwbSignature): IwbElement; function GetElementBySortOrder(aSortOrder: Integer): IwbElement; function GetAdditionalElementCount: Integer; function GetContainerStates: TwbContainerStates; function GetElementByPath(const aPath: string): IwbElement; function GetElementValue(const aName: string): string; function GetElementExists(const aName: string): Boolean; function GetElementEditValue(const aName: string): string; procedure SetElementEditValue(const aName, aValue: string); function GetElementNativeValue(const aName: string): Variant; procedure SetElementNativeValue(const aName: string; const aValue: Variant); function GetElementLinksTo(const aName: string): IwbElement; function GetElementSortKey(const aName: string; aExtended: Boolean): string; procedure AddElement(const aElement: IwbElement); procedure InsertElement(aPos: Integer; const aElement: IwbElement); function RemoveElement(aPos: Integer; aMarkModified: Boolean = False): IwbElement; overload; function RemoveElement(const aElement: IwbElement; aMarkModified: Boolean = False): IwbElement; overload; function RemoveElement(const aName: string): IwbElement; overload; procedure ReverseElements; function LastElement: IwbElement; function IsElementRemoveable(const aElement: IwbElement): Boolean; function IsElementEditable(const aElement: IwbElement): Boolean; function IndexOf(const aElement: IwbElement): Integer; function CanElementReset: Boolean; function GetAddList: TDynStrings; function Add(const aName: string; aSilent: Boolean = True): IwbElement; property Elements[aIndex: Integer]: IwbElement read GetElement; default; property ElementCount: Integer read GetElementCount; property AdditionalElementCount: Integer read GetAdditionalElementCount; property ElementByPath[const aPath: string]: IwbElement read GetElementByPath; property ElementValues[const aName: string]: string read GetElementValue; property ElementEditValues[const aName: string]: string read GetElementEditValue write SetElementEditValue; property ElementNativeValues[const aName: string]: Variant read GetElementNativeValue write SetElementNativeValue; property ElementLinksTo[const aName: string]: IwbElement read GetElementLinksTo; property ElementExists[const aName: string]: Boolean read GetElementExists; property ElementSortKeys[const aName: string; aExtended: Boolean]: string read GetElementSortKey; property ContainerStates: TwbContainerStates read GetContainerStates; property ElementByName[const aName: string]: IwbElement read GetElementByName; property RecordBySignature[const aSignature: TwbSignature]: IwbRecord read GetRecordBySignature; property ElementByMemoryOrder[aSortOrder: Integer]: IwbElement read GetElementByMemoryOrder; property ElementBySignature[const aSignature: TwbSignature]: IwbElement read GetElementBySignature; property ElementBySortOrder[aSortOrder: Integer]: IwbElement read GetElementBySortOrder; end; IwbContainer = interface(IwbContainerBase) ['{4C4FCDD0-C885-458A-B8F2-EA3EFF8B5EEE}'] procedure Bar; end; IwbContainerElementRef= interface(IwbContainerBase) ['{4066BCCF-01AA-4638-9C3D-3475CD8D5749}'] function ReleaseKeepAlive: IwbContainerElementRef; end; IwbKeepAliveRoot = interface(IInterface) ['{D1D2C080-CE73-428F-B88F-BF9503CB8619}'] procedure Done; end; IwbSortableContainer = interface(IwbContainer) ['{A8A65D99-507C-4D2D-86EF-57BC99E09964}'] function GetSorted: Boolean; property Sorted: Boolean read GetSorted; end; IwbGroupRecord = interface; TwbFileState = ( fsIsNew, fsIsCompareLoad, fsOnlyHeader, fsIsHardcoded, fsIsGameMaster, fsIsTemporary, fsHasNoFormID ); TwbFileStates = set of TwbFileState; TwbPluginExtensions = TDynStrings; IwbFile = interface(IwbContainer) ['{38AA15A6-F652-45C7-B875-9CB502E5DA92}'] function GetFileName: string; function GetUnsavedSince: TDateTime; function GetMaster(aIndex: Integer): IwbFile; function GetMasterCount: Integer; function GetRecordByFormID(aFormID: Cardinal; aAllowInjected: Boolean): IwbMainRecord; function GetRecordByEditorID(const aEditorID: string): IwbMainRecord; function GetLoadOrder: Integer; procedure ForceLoadOrder(aValue: Integer); function GetGroupBySignature(const aSignature: TwbSignature): IwbGroupRecord; function HasGroup(const aSignature: TwbSignature): Boolean; function GetFileStates: TwbFileStates; procedure BuildReachable; function LoadOrderFormIDtoFileFormID(aFormID: Cardinal): Cardinal; function FileFormIDtoLoadOrderFormID(aFormID: Cardinal): Cardinal; function LoadOrderFileIDtoFileFileID(aFileID: Byte): Byte; function FileFileIDtoLoadOrderFileID(aFileID: Byte): Byte; function NewFormID: Cardinal; procedure AddMasters(aMasters: TStrings); procedure AddMasterIfMissing(const aMaster: string); procedure SortMasters; procedure CleanMasters; function GetRecord(aIndex: Integer): IwbMainRecord; function GetRecordCount: Integer; function GetHeader: IwbMainRecord; function GetIsESM: Boolean; procedure SetIsESM(Value: Boolean); function GetIsLocalized: Boolean; procedure SetIsLocalized(Value: Boolean); function GetNextObjectID: Cardinal; procedure SetNextObjectID(aObjectID: Cardinal); function GetIsNotPlugin: Boolean; function GetHasNoFormID: Boolean; procedure SetHasNoFormID(Value: Boolean); property FileName: string read GetFileName; property UnsavedSince: TDateTime read GetUnsavedSince; function HasMaster(const aFileName: string): Boolean; property Masters[aIndex: Integer]: IwbFile read GetMaster; property MasterCount: Integer read GetMasterCount; property RecordByFormID[aFormID: Cardinal; aAllowInjected: Boolean]: IwbMainRecord read GetRecordByFormID; property RecordByEditorID[const aEditorID: string]: IwbMainRecord read GetRecordByEditorID; property GroupBySignature[const aSignature: TwbSignature]: IwbGroupRecord read GetGroupBySignature; property Records[aIndex: Integer]: IwbMainRecord read GetRecord; property RecordCount: Integer read GetRecordCount; property Header: IwbMainRecord read GetHeader; property LoadOrder: Integer read GetLoadOrder; property FileStates: TwbFileStates read GetFileStates; property IsESM: Boolean read GetIsESM write SetIsESM; property IsLocalized: Boolean read GetIsLocalized write SetIsLocalized; property NextObjectID: Cardinal read GetNextObjectID write SetNextObjectID; property IsNotPlugin: Boolean // Save or other file to display. read GetIsNotPlugin; property HasNoFormID: Boolean // Like Morrowind for example. Also true for save/coSave. read GetHasNoFormID write SetHasNoFormID; end; IwbDataContainer = interface(IwbContainer) ['{6E547F7C-87E4-4917-8F43-4D3CEE5AFE8C}'] function GetDataBasePtr: Pointer; function GetDataEndPtr: Pointer; function GetDataSize: Integer; function GetDontCompare: Boolean; function GetDontSave: Boolean; function IsValidOffset(aBasePtr, aEndPtr: Pointer; anOffset: Integer): Boolean; function IsLocalOffset(anOffset: Integer): Boolean; property DataBasePtr: Pointer read GetDataBasePtr; property DataEndPtr: Pointer read GetDataEndPtr; property DataSize: Integer read GetDataSize; property DontCompare: Boolean read GetDontCompare; property DontSave: Boolean read GetDontSave; end; TDynDataContainers = array of IwbDataContainer; IwbRecord = interface(IwbDataContainer) ['{4FC53881-25E2-421D-8AF6-F589979767E6}'] function GetSignature: TwbSignature; property Signature: TwbSignature read GetSignature; end; IwbHasSignature = interface(IwbElement) ['{DF563D7C-A441-4864-B47A-49F3A96508F7}'] function GetSignature: TwbSignature; property Signature: TwbSignature read GetSignature; end; PwbMainRecordStructFlags = ^TwbMainRecordStructFlags; TwbMainRecordStructFlags = packed record _Flags: Cardinal; function IsESM: Boolean; inline; function IsDeleted: Boolean; inline; function IsLocalized: Boolean; inline; function CastsShadows: Boolean; inline; function IsPersistent: Boolean; inline; function IsInitiallyDisabled: Boolean; inline; function IsIgnored: Boolean; inline; function IsVisibleWhenDistant: Boolean; inline; function IsDangerous: Boolean; inline; function IsCompressed: Boolean; inline; function CantWait: Boolean; inline; function HasLODtree: Boolean; inline; procedure SetESM(aValue: Boolean); procedure SetDeleted(aValue: Boolean); procedure SetLocalized(aValue: Boolean); procedure SetPersistent(aValue: Boolean); procedure SetCompressed(aValue: Boolean); procedure SetInitiallyDisabled(aValue: Boolean); procedure SetVisibleWhenDistant(aValue: Boolean); end; PwbMainRecordStructFlags3 = ^TwbMainRecordStructFlags3; TwbMainRecordStructFlags3 = packed record _Flags: Cardinal; end; TwbVector = packed record x: Single; y: Single; z: Single; end; TwbGridCell = record x, y: Integer; end; TDynMainRecords = array of IwbMainRecord; IwbMainRecord = interface(IwbRecord) ['{F06FD5E2-621D-4422-BA00-CB3CA72B3691}'] function GetFormID: Cardinal; function GetFixedFormID: Cardinal; function GetLoadOrderFormID: Cardinal; procedure SetLoadOrderFormID(aFormID: Cardinal); function GetEditorID: string; function GetCanHaveEditorID: Boolean; procedure SetEditorID(const aValue: string); function GetFullName: string; function GetDisplayNameKey: string; function GetMaster: IwbMainRecord; function GetIsMaster: Boolean; function GetMasterOrSelf: IwbMainRecord; function GetOverride(aIndex: Integer): IwbMainRecord; function GetOverrideCount: Integer; procedure AddReferencedBy(aMainRecord: IwbMainRecord); procedure RemoveReferencedBy(aMainRecord: IwbMainRecord); function GetReferencedBy(aIndex: Integer): IwbMainRecord; function GetReferencedByCount: Integer; function GetIsWinningOverride: Boolean; function GetWinningOverride: IwbMainRecord; function GetHighestOverrideOrSelf(aMaxLoadOrder: Integer): IwbMainRecord; function GetFlags: TwbMainRecordStructFlags; function GetChildGroup: IwbGroupRecord; function EnsureChildGroup: IwbGroupRecord; function GetBaseRecord: IwbMainRecord; function GetBaseRecordID: Cardinal; function GetConflictAll: TConflictAll; procedure SetConflictAll(aValue: TConflictAll); function GetConflictThis: TConflictThis; procedure SetConflictThis(aValue: TConflictThis); function GetIsESM: Boolean; procedure SetIsESM(aValue: Boolean); function GetIsPersistent: Boolean; procedure SetIsPersistent(aValue: Boolean); function GetIsDeleted: Boolean; procedure SetIsDeleted(aValue: Boolean); function GetIsLocalized: Boolean; procedure SetIsLocalized(aValue: Boolean); function GetIsCompressed: Boolean; procedure SetIsCompressed(aValue: Boolean); function GetIsVisibleWhenDistant: Boolean; procedure SetIsVisibleWhenDistant(aValue: Boolean); function GetHasVisibleWhenDistantMesh: Boolean; function GetHasMesh: Boolean; function GetHasPrecombinedMesh: Boolean; function GetPrecombinedMesh: string; function GetIsInitiallyDisabled: Boolean; procedure SetIsInitiallyDisabled(aValue: Boolean); procedure UpdateRefs; function GetPosition(out aPosition: TwbVector): Boolean; function SetPosition(const aPosition: TwbVector): Boolean; function GetRotation(out aRotation: TwbVector): Boolean; function GetScale(out aScale: Single): Boolean; function GetGridCell(out aGridCell: TwbGridCell): Boolean; procedure Delete; procedure DeleteInto(const aFile: IwbFile); function MasterRecordsFromMasterFilesAndSelf: TDynMainRecords; function GetFormVersion: Cardinal; procedure SetFormVersion(aFormVersion: Cardinal); procedure ChangeFormSignature(aSignature: TwbSignature); procedure ClampFormID(aIndex: Cardinal); property Version: Cardinal read GetFormVersion write SetFormVersion; property BaseRecord: IwbMainRecord read GetBaseRecord; property BaseRecordID: Cardinal read GetBaseRecordID; property FormID: Cardinal read GetFormID; property FixedFormID: Cardinal read GetFixedFormID; property LoadOrderFormID: Cardinal read GetLoadOrderFormID write SetLoadOrderFormID; property EditorID: string read GetEditorID write SetEditorID; property CanHaveEditorID: Boolean read GetCanHaveEditorID; property FullName: string read GetFullName; property DisplayNameKey: string read GetDisplayNameKey; property Flags: TwbMainRecordStructFlags read GetFlags; property Master: IwbMainRecord read GetMaster; property MasterOrSelf: IwbMainRecord read GetMasterOrSelf; property IsMaster: Boolean read GetIsMaster; property ChildGroup: IwbGroupRecord read GetChildGroup; property Overrides[aIndex: Integer]: IwbMainRecord read GetOverride; property OverrideCount: Integer read GetOverrideCount; property IsWinningOverride: Boolean read GetIsWinningOverride; property WinningOverride: IwbMainRecord read GetWinningOverride; property HighestOverrideOrSelf[aMaxLoadOrder: Integer]: IwbMainRecord read GetHighestOverrideOrSelf; property ReferencedBy[aIndex: Integer]: IwbMainRecord read GetReferencedBy; property ReferencedByCount: Integer read GetReferencedByCount; property IsESM: Boolean read GetIsESM write SetIsESM; property IsPersistent: Boolean read GetIsPersistent write SetIsPersistent; property IsDeleted: Boolean read GetIsDeleted write SetIsDeleted; property IsCompressed: Boolean read GetIsCompressed write SetIsCompressed; property IsLocalized: Boolean read GetIsLocalized write SetIslocalized; property IsVisibleWhenDistant: Boolean read GetIsVisibleWhenDistant write SetIsVisibleWhenDistant; property HasVisibleWhenDistantMesh: Boolean read GetHasVisibleWhenDistantMesh; property HasMesh: Boolean read GetHasMesh; property HasPrecombinedMesh: Boolean read GetHasPrecombinedMesh; property PrecombinedMesh: string read GetPrecombinedMesh; property IsInitiallyDisabled: Boolean read GetIsInitiallyDisabled write SetIsInitiallyDisabled; property ConflictAll: TConflictAll read GetConflictAll write SetConflictAll; property ConflictThis: TConflictThis read GetConflictThis write SetConflictThis; end; IwbFileHeader = interface(IwbDataContainer) ['{E309EEE2-C20E-4506-BF46-B63F903706C9}'] function GetFileMagic: TwbFileMagic; property FileMagic: TwbFileMagic read GetFileMagic; end; IwbChapter = interface ['{3E575648-EF6F-4e9f-956F-D2E184B670E4}'] function GetChapterType: Integer; function GetChapterTypeName: String; function GetChapterName: String; property ChapterType: Integer read GetChapterType; property ChapterTypeName: String read GetChapterTypeName; property ChapterName: String read GetChapterName; end; TDynElements = array of IwbElement; {$IFDEF WIN32} TDynCardinalArray = array of Cardinal; {$ENDIF WIN32} {$IFDEF WIN64} TDynCardinalArray = array of UInt64; {$ENDIF WIN32} IwbSubRecord = interface(IwbRecord) ['{CDE36A3D-64F6-4B8E-980E-FBAB8D9FCAF7}'] function GetSubRecordHeaderSize: Integer; property SubRecordHeaderSize: Integer read GetSubRecordHeaderSize; end; TDynGroupRecords = array of IwbGroupRecord; IwbGroupRecord = interface(IwbRecord) ['{BFF16E47-4E66-4EAD-9BEF-364728AE0A6B}'] function GetGroupType: Integer; function GetGroupLabel: Cardinal; procedure SetGroupLabel(aLabel: Cardinal); function GetChildrenOf: IwbMainRecord; function FindChildGroup(aType: Integer; aMainRecord: IwbMainRecord): IwbGroupRecord; function GetMainRecordByEditorID(const aEditorID: string): IwbMainRecord; function GetMainRecordByFormID(const aFormID: Cardinal): IwbMainRecord; procedure AddElement(const aElement: IwbElement); property GroupType: Integer read GetGroupType; property GroupLabel: Cardinal read GetGroupLabel write SetGroupLabel; property ChildrenOf: IwbMainRecord read GetChildrenOf; property MainRecordByEditorID[const aEditorID: string]: IwbMainRecord read GetMainRecordByEditorID; property MainRecordByFormID[const aFormID: Cardinal]: IwbMainRecord read GetMainRecordByFormID; end; IwbSubRecordArray = interface ['{26937F7A-5F31-4D65-932F-038BD0FA9FEF}'] end; IwbSubRecordStruct = interface ['{E8C496D3-D396-4685-87EC-82E1FD2588B8}'] end; IwbSubRecordUnion = interface ['{11959F58-B396-4449-9D9D-5DF1251C3E76}'] end; TwbCallbackType = ( ctToStr, ctToSortKey, ctCheck, ctToEditValue, ctEditType, ctEditInfo ); TwbAfterLoadCallback = procedure(const aElement: IwbElement); TwbAfterSetCallback = procedure(const aElement: IwbElement; const aOldValue, aNewValue: Variant); TwbDontShowCallback = function(const aElement: IwbElement): Boolean; TwbFloatNormalizer = function(const aElement: IwbElement; aFloat: Extended): Extended; TwbGetConflictPriority = procedure(const aElement: IwbElement; var aConflictPriority: TwbConflictPriority); TwbIntToStrCallback = function(aInt: Int64; const aElement: IwbElement; aType: TwbCallbackType): string; TwbStrToIntCallback = function(const aString: string; const aElement: IwbElement): Int64; TwbAddInfoCallback = function(const aMainRecord: IwbMainRecord): string; TwbUnionDecider = function(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; TwbIntegerDefFormaterUnionDecider = function(const aElement: IwbElement): Integer; TwbIsSortedCallback = function(const aContainer: IwbContainer): Boolean; TwbCountCallback = function(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Cardinal; TwbSizeCallback = function(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement;var CompressedSize: Integer): Cardinal; TwbGetChapterTypeCallback = function(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; TwbGetChapterTypeNameCallback = function(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): String; TwbGetChapterNameCallback = function(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): String; IwbNamedDef = interface(IwbDef) ['{F8FEDE89-C089-42C5-B587-49A7D87055F0}'] function GetName: string; function GetPath: string; procedure AfterLoad(const aElement: IwbElement); procedure AfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); function GetTreeHead: Boolean; // Is the element expected to be a "header record" in the tree navigator procedure SetTreeHead(aValue: Boolean); // Make the element a "header record" in the tree navigator; function GetTreeBranch: Boolean; // Is the element included in a "leaf" expected to be displayed in the view pane procedure SetTreeBranch(aValue: Boolean); // Make the element included in a "leaf" visible in the tree navigator; property Name: string read GetName; property Path: string read GetPath; property TreeHead: Boolean read GetTreeHead write SetTreeHead; property TreeBranch: Boolean read GetTreeBranch write SetTreeBranch; end; IwbSignatureDef = interface(IwbNamedDef) ['{EF20E1A2-8719-4934-AC36-C91DC72C3F70}'] function GetDefaultSignature: TwbSignature; function GetSignatures(const aIndex: Integer): TwbSignature; function GetSignatureCount: Integer; function CanHandle(aSignature : TwbSignature; const aDataContainer : IwbDataContainer) : Boolean; property DefaultSignature: TwbSignature read GetDefaultSignature; property Signatures[const aIndex: Integer]: TwbSignature read GetSignatures; property SignatureCount: Integer read GetSignatureCount; end; IwbRecordMemberDef = interface; IwbStructDef = interface; PwbRecordDef = ^IwbRecordDef; IwbRecordDef = interface(IwbSignatureDef) ['{89FE380F-7A0B-493C-AA9E-08957A4C167B}'] function ContainsMemberFor(aSignature : TwbSignature; const aDataContainer : IwbDataContainer) : Boolean; function GetMemberFor(aSignature : TwbSignature; const aDataContainer : IwbDataContainer) : IwbRecordMemberDef; function GetMemberIndexFor(aSignature : TwbSignature; const aDataContainer : IwbDataContainer) : Integer; function AllowUnordered: Boolean; function AdditionalInfoFor(const aMainRecord: IwbMainRecord): string; function GetMember(aIndex: Integer): IwbRecordMemberDef; function GetMemberCount: Integer; function GetSkipSignature(const aSignature: TwbSignature): Boolean; function GetQuickInitLimit: Integer; function GetContainsEditorID: Boolean; function GetRecordHeaderStruct: IwbStructDef; property Members[aIndex: Integer]: IwbRecordMemberDef read GetMember; property MemberCount: Integer read GetMemberCount; property SkipSignature[const aSignature: TwbSignature]: Boolean read GetSkipSignature; property QuickInitLimit: Integer read GetQuickInitLimit; property ContainsEditorID: Boolean read GetContainsEditorID; property RecordHeaderStruct: IwbStructDef read GetRecordHeaderStruct; end; IwbHasSortKeyDef = interface(IwbRecordDef) ['{877FEF58-72B1-4735-9E08-166B5F4043F3}'] function GetSortKey(aIndex: Integer; aExtended: Boolean): Integer; function GetSortKeyCount(aExtended: Boolean): Integer; function IsInSK(aIndex: Integer): Boolean; property SortKeys[aIndex: Integer; aExtended: Boolean]: Integer read GetSortKey; property SortKeyCount[aExtended: Boolean]: Integer read GetSortKeyCount; end; IwbRecordMemberDef = interface(IwbSignatureDef) ['{259F3F08-F4ED-439D-8C1A-48137C84E52A}'] end; TwbUsedMasters = array[Byte] of Boolean; PwbUsedMasters = ^TwbUsedMasters; IwbValueDef = interface(IwbNamedDef) ['{BBF684A6-0EE5-4EF6-83DD-D323A0D2919A}'] function ToString(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; function ToSortKey(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aExtended: Boolean): string; function Check(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; function GetSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; function GetDefaultSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; function GetLinksTo(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): IwbElement; procedure BuildRef(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement); function GetIsVariableSize: Boolean; function GetCanBeZeroSize: Boolean; function ToEditValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; procedure FromEditValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: string); function ToNativeValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Variant; procedure FromNativeValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: Variant); function GetIsEditable(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Boolean; function GetEditType(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): TwbEditType; function GetEditInfo(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; function SetToDefault(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Boolean; procedure MasterCountUpdated(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aOld, aNew: Byte); procedure MasterIndicesUpdated(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aOld, aNew: TBytes); procedure FindUsedMasters(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aMasters: PwbUsedMasters); function CompareExchangeFormID(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aOldFormID: Cardinal; aNewFormID: Cardinal): Boolean; function GetElementMap: TDynCardinalArray; property Size[aBasePtr, aEndPtr: Pointer; const aElement: IwbElement]: Integer read GetSize; property DefaultSize[aBasePtr, aEndPtr: Pointer; const aElement: IwbElement]: Integer read GetDefaultSize; property IsVariableSize: Boolean read GetIsVariableSize; property CanBeZeroSize: Boolean read GetCanBeZeroSize; property IsEditable[aBasePtr, aEndPtr: Pointer; const aElement: IwbElement]: Boolean read GetIsEditable; property EditValue[aBasePtr, aEndPtr: Pointer; const aElement: IwbElement]: string read ToEditValue write FromEditValue; property NativeValue[aBasePtr, aEndPtr: Pointer; const aElement: IwbElement]: Variant read ToNativeValue write FromNativeValue; property LinksTo[aBasePtr, aEndPtr: Pointer; const aElement: IwbElement]: IwbElement read GetLinksTo; property EditType[aBasePtr, aEndPtr: Pointer; const aElement: IwbElement]: TwbEditType read GetEditType; property EditInfo[aBasePtr, aEndPtr: Pointer; const aElement: IwbElement]: string read GetEditInfo; end; IwbSubRecordDef = interface(IwbRecordMemberDef) ['{D848E426-8768-45F4-B192-4DEFBE34D40A}'] function GetValue: IwbValueDef; procedure HasUnusedData; property Value: IwbValueDef read GetValue; end; IwbSubRecordArrayDef = interface(IwbRecordMemberDef) ['{67943BAC-B558-4112-8DBC-C94A44E0B1D1}'] function GetElement: IwbRecordMemberDef; function GetSorted(const aContainer: IwbContainer): Boolean; property Element: IwbRecordMemberDef read GetElement; property Sorted[const aContainer: IwbContainer]: Boolean read GetSorted; end; IwbSubRecordStructDef = interface(IwbRecordMemberDef) ['{B5441812-5229-488B-AEA6-C182CEBED441}'] end; IwbSubRecordUnionDef = interface(IwbRecordMemberDef) ['{BC66ABFF-3108-4C64-B416-674A2A8F297D}'] end; IwbUnionDef = interface(IwbValueDef) ['{04D6B7BA-B457-4E43-9910-592395FEA0D6}'] function Decide(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): IwbValueDef; function GetMember(aIndex: Integer): IwbValueDef; function GetMemberCount: Integer; property Members[aIndex: Integer]: IwbValueDef read GetMember; property MemberCount: Integer read GetMemberCount; end; IwbStringDef = interface(IwbValueDef) ['{37B02D28-EDB4-41C6-B933-9F56C013A88A}'] function GetStringSize: Integer; property StringSize: Integer read GetStringSize; end; IwbLenStringDef = interface(IwbValueDef) ['{1AD7FAE2-DAA7-4651-B78D-10E138EDF48B}'] end; IwbByteArrayDef = interface(IwbValueDef) ['{3069E1AC-4307-421B-93E4-797E18075EF9}'] end; IwbEmptyDef = interface(IwbValueDef) ['{0A858744-947B-4B6E-9972-D8BF5398C87C}'] function GetSorted: Boolean; property Sorted: Boolean read GetSorted; end; IwbIntegerDefFormater = interface; IwbIntegerDef = interface(IwbValueDef) ['{00A270B0-ACFC-444C-A7E8-A577BD40704E}'] function ToInt(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Int64; procedure FromInt(aValue: Int64; aBasePtr, aEndPtr: Pointer; const aElement: IwbElement); function GetFormater(const aElement: IwbElement): IwbIntegerDefFormater; function GetFormaterCanChange: Boolean; function GetIntType: TwbIntType; function GetExpectedLength(aValue: Int64 = 0): Integer; property Formater[const aElement: IwbElement]: IwbIntegerDefFormater read GetFormater; property FormaterCanChange: Boolean read GetFormaterCanChange; property IntType: TwbIntType read GetIntType; property ExpectedLength[aValue: Int64 = 0]: Integer read GetExpectedLength; end; IwbInternalIntegerDef = interface(IwbIntegerDef) ['{16A15EF7-6295-4817-BA94-CDD7E8C1CF8B}'] procedure ReplaceFormater(const aFormater: IwbIntegerDefFormater); end; IwbFloatDef = interface(IwbValueDef) ['{29F116C6-0208-4D55-ACA7-2A9BB17BF80B}'] end; IwbArrayDef = interface(IwbValueDef) ['{BD195F99-4AC3-4BD0-9193-267332E97D79}'] function GetElement: IwbValueDef; function GetCount: Integer; function GetElementLabel(aIndex: Integer): string; function GetSorted: Boolean; function GetCanAddTo: Boolean; function GetCountCallBack: TwbCountCallback; function GetPrefixSize(aBasePtr: Pointer): Integer; function GetPrefixLength(aBasePtr: Pointer): Integer; function GetPrefixCount(aBasePtr: Pointer): Cardinal; procedure SetPrefixCount(aBasePtr: Pointer; aCount: Cardinal); property Element: IwbValueDef read GetElement; property ElementCount: Integer read GetCount; property ElementLabel[aIndex: Integer]: string read GetElementLabel; property Sorted: Boolean read GetSorted; property CountCallBack: TwbCountCallback read GetCountCallback; property CanAddTo: Boolean read GetCanAddTo; property PrefixSize[aBasePtr: Pointer]: Integer // how many bytes of storage for the prefix read GetPrefixSize; property PrefixLength[aBasePtr: Pointer]: Integer // Integer size of the prefix read GetPrefixLength; property PrefixCount[aBasePtr: Pointer]: Cardinal // Value stored in the prefix read GetPrefixCount write SetPrefixCount; end; IwbStructDef = interface(IwbValueDef) ['{9B20A03C-BC3F-433A-9781-E46BD5C660A9}'] function GetMemberCount: Integer; function GetMember(aIndex: Integer): IwbValueDef; function GetMemberByName(const aName: string): IwbValueDef; function GetOptionalFromElement: Integer; property MemberCount: Integer read GetMemberCount; property Members[aIndex: Integer]: IwbValueDef read GetMember; property MembersByName[const aName: string]: IwbValueDef read GetMemberByName; property OptionalFromElement: Integer read GetOptionalFromElement; end; IwbStructCDef = interface(IwbStructDef) ['{B72FD1AD-018D-47D3-91E7-5028C5E0E759}'] function GetSizing(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement;var CompressedSize: Integer): Cardinal; function GetChapterType(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; function GetChapterTypeName(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): String; function GetChapterName(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): String; end; TwbStructCompression = ( scNone, scZComp, scLZComp ); IwbStructZDef = interface(IwbStructCDef) // Compressible structure !!! NOT SAFE FOR EDIT AT THE MOMEMNT !!! ['{8ED8E461-E4BB-494E-8A3B-B352A245B9A0}'] end; IwbStructLZDef = interface(IwbStructZDef) // Compressible structure using LZ4 !!! NOT SAFE FOR EDIT AT THE MOMEMNT !!! ['{A5AB100F-83CA-4B53-B3CD-2BF926210900}'] end; IwbIntegerDefFormater = interface(IwbDef) ['{56A6EB7B-3A90-4F09-8E80-D7399569DFCC}'] function ToString(aInt: Int64; const aElement: IwbElement): string; function ToSortKey(aInt: Int64; const aElement: IwbElement): string; function Check(aInt: Int64; const aElement: IwbElement): string; procedure BuildRef(aInt: Int64; const aElement: IwbElement); function GetEditType(aInt: Int64; const aElement: IwbElement): TwbEditType; function GetEditInfo(aInt: Int64; const aElement: IwbElement): string; function ToEditValue(aInt: Int64; const aElement: IwbElement): string; function FromEditValue(const aValue: string; const aElement: IwbElement): Int64; function GetIsEditable(aInt: Int64; const aElement: IwbElement): Boolean; function GetLinksTo(aInt: Int64; const aElement: IwbElement): IwbElement; function CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; function MasterCountUpdated(aInt: Int64; aOld, aNew: Byte; const aElement: IwbElement): Int64; function MasterIndicesUpdated(aInt: Int64; const aOld, aNew: TBytes; const aElement: IwbElement): Int64; procedure FindUsedMasters(aInt: Int64; aMasters: PwbUsedMasters; const aElement: IwbElement); function CompareExchangeFormID(var aInt: Int64; aOldFormID: Cardinal; aNewFormID: Cardinal; const aElement: IwbElement): Boolean; function GetRequiresKey: Boolean; property IsEditable[aInt: Int64; const aElement: IwbElement]: Boolean read GetIsEditable; property LinksTo[aInt: Int64; const aElement: IwbElement]: IwbElement read GetLinksTo; property EditType[aInt: Int64; const aElement: IwbElement]: TwbEditType read GetEditType; property EditInfo[aInt: Int64; const aElement: IwbElement]: string read GetEditInfo; property RequiresKey: Boolean read GetRequiresKey; end; IwbIntegerDefFormaterUnion = interface(IwbIntegerDefFormater) ['{C04B1181-A570-41AE-A31E-7977B722EE0A}'] function Decide(const aElement: IwbElement): IwbIntegerDefFormater; function GetMember(aIndex: Integer): IwbIntegerDefFormater; function GetMemberCount: Integer; property Members[aIndex: Integer]: IwbIntegerDefFormater read GetMember; property MemberCount: Integer read GetMemberCount; end; IwbDumpIntegerDefFormater = interface(IwbIntegerDefFormater) ['{9767F3EF-0E6F-45FB-AC9F-31A9B4312760}'] end; IwbFormID = interface(IwbIntegerDefFormater) ['{71C4A255-B983-488C-9837-0A720132348A}'] function GetMainRecord(aInt: Int64; const aElement: IwbElement): IwbMainRecord; end; IwbRefID = interface(IwbFormID) ['{F6EEAFDD-5AD7-4DB3-BF45-5D5DB53465D4}'] end; IwbFormIDChecked = interface(IwbFormID) ['{DC7CBC9F-07EC-430B-94EE-ECE1867A2660}'] function GetSignature(aIndex: Integer): TwbSignature; function GetSignatureCount: Integer; property Signatures[aIndex: Integer]: TwbSignature read GetSignature; property SignatureCount: Integer read GetSignatureCount; end; IwbChar4 = interface(IwbIntegerDefFormater) ['{CF657B3A-E7A6-48FE-AC68-8DF15962A531}'] end; IwbStr4 = interface(IwbIntegerDefFormater) // 4 bytes strings stored as itU32 ['{2DC5200E-C1F1-47e7-A927-3D110D59F55A}'] end; // The interface handles swaping the character in readable order IwbFlagsDef = interface; IwbFlagDef = interface(IwbValueDef) ['{CCD4FBC4-D1CA-4B91-9E2F-6EE6118D5D07}'] function GetFlagsDef: IwbFlagsDef; function GetFlagIndex: Integer; property FlagsDef: IwbFlagsDef read GetFlagsDef; property FlagIndex: Integer read GetFlagIndex; end; IwbFlagsDef = interface(IwbIntegerDefFormater) ['{EF564466-A671-453A-88CF-42A0AA32D849}'] function GetBaseFlagsDef: IwbFlagsDef; function GetFlag(aIndex: Integer): string; function GetFlagCount: Integer; function GetFlagIgnoreConflict(aIndex: Integer): Boolean; function GetFlagDontShow(const aElement: IwbElement; aIndex: Integer): Boolean; function GetFlagHasDontShow(aIndex: Integer): Boolean; procedure FlagGetCP(const aElement: IwbElement; aIndex: Integer; var aCP: TwbConflictPriority); function GetFlagHasGetCP(aIndex: Integer): Boolean; function GetFlagDef(aIndex : Integer): IwbFlagDef; property BaseFlagsDef: IwbFlagsDef read GetBaseFlagsDef; property Flags[aIndex: Integer] : string read GetFlag; property FlagCount: Integer read GetFlagCount; property FlagIgnoreConflict[aIndex: Integer] : Boolean read GetFlagIgnoreConflict; property FlagDontShow[const aElement: IwbElement; aIndex: Integer]: Boolean read GetFlagDontShow; property FlagHasDontShow[aIndex: Integer]: Boolean read GetFlagHasDontShow; property FlagHasGetCP[aIndex: Integer]: Boolean read GetFlagHasGetCP; property FlagDef[aIndex: Integer]: IwbFlagDef read GetFlagDef; end; IwbEnumDef = interface(IwbIntegerDefFormater) ['{A3AFE02E-F72D-4E0E-BC56-219F7EE2B564}'] function GetName(aIndex: Integer): string; function GetNameCount: Integer; property Names[aIndex: Integer]: string read GetName; property NameCount: Integer read GetNameCount; end; IwbKey2Data6EnumDef = interface(IwbEnumDef) ['{A74C58CC-6280-4143-B72B-4AD4F68A9957}'] end; IwbData6Key2EnumDef = interface(IwbEnumDef) ['{AC7F99C9-9DF1-43BB-9052-6AD4B69E706F}'] end; IwbCallbackDef = interface(IwbIntegerDefFormater) ['{BF6A0830-F981-4E0A-B4F2-2A09D575CD19}'] function GetCallback: TwbIntToStrCallback; property Callback: TwbIntToStrCallback read GetCallback; end; IwbResourceContainer = interface; IwbResource = interface(IInterface) ['{B626E8BF-D2E3-40D1-8F3A-E6001D76B97B}'] function GetContainer: IwbResourceContainer; function GetData: TBytes; property Container: IwbResourceContainer read GetContainer; end; IwbResourceContainer = interface(IInterface) ['{023EA9C4-19B5-4587-B298-559EEF8F224E}'] function GetName: String; function OpenResource(const aFileName: string): IwbResource; function ResourceExists(const aFileName: string): Boolean; procedure ResourceList(const aList: TStrings; const aFolder: string = ''); procedure ResolveHash(const aHash: Int64; var Results: TDynStrings); property Name: string read GetName; end; IwbFolder = interface(IwbResourceContainer) ['{E71981ED-3C0C-4334-8476-116AEB0EEA1E}'] function GetPathName: string; property PathName: string read GetPathName; end; IwbBSAFile = interface(IwbResourceContainer) ['{DC987017-9F5C-42D2-BAD2-E1A622E99081}'] function GetFileName: string; property FileName: string read GetFileName; end; IwbBA2File = interface(IwbResourceContainer) ['{D05EAAEC-8A23-4CDD-83E4-7593AC846CE3}'] function GetFileName: string; property FileName: string read GetFileName; end; TDynResources = array of IwbResource; IwbContainerHandler = interface(IInterface) ['{0CC80043-EADC-4C7D-8677-8719735582C7}'] procedure AddFolder(const aPath: string); procedure AddBSA(const aFileName: string); procedure AddBA2(const aFileName: string); function OpenResource(const aFileName: string): TDynResources; function OpenResourceData(const aContainerName, aFileName: string): TBytes; function ResolveHash(const aHash: Int64): TDynStrings; function ContainerExists(aContainerName: string): Boolean; procedure ContainerList(const aList: TStrings); procedure ContainerResourceList(const aContainerName: string; const aList: TStrings; const aFolder: string = ''); function ResourceExists(const aFileName: string): Boolean; function ResourceCount(const aFileName: string; aContainers: TStrings = nil): Integer; procedure ResourceCopy(const aContainerName, aFileName, aPathOut: string); end; var SortedElementTypes : set of TwbElementType = [ etFile, etMainRecord, etGroupRecord, etSubRecord, etSubRecordArray, etArray ]; wbPluginExtensions : TwbPluginExtensions; function wbRecord(const aSignature : TwbSignature; const aName : string; const aMembers : array of IwbRecordMemberDef; aAllowUnordered : Boolean = False; aAddInfoCallback: TwbAddInfoCallback = nil; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil) : IwbRecordDef; overload; function wbRecord(const aSignature : TwbSignature; const aName : string; const aRecordFlags : IwbIntegerDefFormater; const aMembers : array of IwbRecordMemberDef; aAllowUnordered : Boolean = False; aAddInfoCallback: TwbAddInfoCallback = nil; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil) : IwbRecordDef; overload; function wbSubRecord(const aSignature : TwbSignature; const aName : string; const aValue : IwbValueDef; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aSizeMatch : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbSubRecord(const aSignatures : array of TwbSignature; const aName : string; const aValue : IwbValueDef; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aSizeMatch : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbString(const aSignature : TwbSignature; const aName : string = 'Unknown'; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbString(const aName : string = 'Unknown'; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbStringDef; overload; function wbStringForward(const aSignature : TwbSignature; // When the editor can leave chars after the ending #0 const aName : string = 'Unknown'; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbString( aForward : Boolean = False; const aName : string = 'Unknown'; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbStringDef; overload; function wbStringT(const aSignature : TwbSignature; const aName : string = 'Unknown'; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbStringT(const aName : string = 'Unknown'; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbStringDef; overload; function wbStringScript(const aSignature : TwbSignature; const aName : string; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbStringScript(const aName : string; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbStringDef; overload; function wbStringLC(const aSignature : TwbSignature; const aName : string; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbStringLC(const aName : string; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbStringDef; overload; function wbStringKC(const aSignature : TwbSignature; const aName : string; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbStringKC(const aName : string; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbStringDef; overload; function wbLString(const aSignature : TwbSignature; const aName : string; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbLString(const aName : string; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbStringDef; overload; function wbLStringKC(const aSignature : TwbSignature; const aName : string; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbLStringKC(const aName : string; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbStringDef; overload; function wbStringMgefCode(const aSignature : TwbSignature; const aName : string; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbStringMgefCode(const aName : string; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbStringDef; overload; function wbLenString(const aSignature : TwbSignature; const aName : string; aPrefix : Integer = 4; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbLenString(const aName : string; aPrefix : Integer = 4; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbLenStringDef; overload; function wbLenStringT(const aSignature : TwbSignature; const aName : string; aPrefix : Integer = 4; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbLenStringT(const aName : string; aPrefix : Integer = 4; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbLenStringDef; overload; function wbUnion(const aSignature : TwbSignature; const aName : string; aDecider : TwbUnionDecider; const aMembers : array of IwbValueDef; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbUnion(const aName : string; aDecider : TwbUnionDecider; const aMembers : array of IwbValueDef; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbUnionDef; overload; function wbByteArray(const aSignature : TwbSignature; const aName : string = 'Unknown'; aSize : Int64 = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aSizeMatch : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbByteArray(const aName : string = 'Unknown'; aSize : Int64 = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbByteArrayDef; overload; function wbByteArrayT(const aName : string = 'Unknown'; aSize : Int64 = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbByteArrayDef; overload; function wbByteArray(const aName : string; aCountCallback : TwbCountCallback; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbByteArrayDef; overload; function wbUnknown(const aSignature : TwbSignature; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbUnknown(aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbByteArrayDef; overload; function wbInteger(const aSignature : TwbSignature; const aName : string; const aIntType : TwbIntType; const aFormater : IwbIntegerDefFormater = nil; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aMatchSize : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aDefault : Int64 = 0; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbInteger(const aName : string; const aIntType : TwbIntType; const aFormater : IwbIntegerDefFormater = nil; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aDefault : Int64 = 0; aGetCP : TwbGetConflictPriority = nil) : IwbIntegerDef; overload; function wbInteger(const aSignature : TwbSignature; const aName : string; const aIntType : TwbIntType; const aToStr : TwbIntToStrCallback; const aToInt : TwbStrToIntCallback = nil; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aDefault : Int64 = 0; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbInteger(const aName : string; const aIntType : TwbIntType; const aToStr : TwbIntToStrCallback; const aToInt : TwbStrToIntCallback = nil; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aDefault : Int64 = 0; aGetCP : TwbGetConflictPriority = nil) : IwbIntegerDef; overload; function wbIntegerT(const aSignature : TwbSignature; const aName : string; const aIntType : TwbIntType; const aFormater : IwbIntegerDefFormater = nil; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aMatchSize : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aDefault : Int64 = 0; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbIntegerT(const aName : string; const aIntType : TwbIntType; const aFormater : IwbIntegerDefFormater = nil; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aDefault : Int64= 0; aGetCP : TwbGetConflictPriority = nil) : IwbIntegerDef; overload; function wbIntegerT(const aSignature : TwbSignature; const aName : string; const aIntType : TwbIntType; const aToStr : TwbIntToStrCallback; const aToInt : TwbStrToIntCallback = nil; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aDefault : Int64 = 0; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbIntegerT(const aName : string; const aIntType : TwbIntType; const aToStr : TwbIntToStrCallback; const aToInt : TwbStrToIntCallback = nil; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aDefault : Int64 = 0; aGetCP : TwbGetConflictPriority = nil) : IwbIntegerDef; overload; function wbFloat(const aSignature : TwbSignature; const aName : string = 'Unknown'; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aScale : Extended = 1.0; aDigits : Integer = -1; aDontShow : TwbDontShowCallback = nil; aNormalizer : TwbFloatNormalizer = nil; aDefault : Extended = 0.0; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbFloat(const aName : string = 'Unknown'; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aScale : Extended = 1.0; aDigits : Integer = -1; aDontShow : TwbDontShowCallback = nil; aNormalizer : TwbFloatNormalizer = nil; aDefault : Extended = 0.0; aGetCP : TwbGetConflictPriority = nil) : IwbFloatDef; overload; function wbFloat(const aName : string; aPriority : TwbConflictPriority; aRequired : Boolean; aDontShow : TwbDontShowCallback; aAfterSet : TwbAfterSetCallback = nil; aNormalizer : TwbFloatNormalizer = nil; aDefault : Extended = 0.0; aGetCP : TwbGetConflictPriority = nil) : IwbFloatDef; overload; function wbDouble(const aSignature : TwbSignature; const aName : string = 'Unknown'; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aScale : Extended = 1.0; aDigits : Integer = -1; aDontShow : TwbDontShowCallback = nil; aNormalizer : TwbFloatNormalizer = nil; aDefault : Extended = 0.0; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbDouble(const aName : string = 'Unknown'; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aScale : Extended = 1.0; aDigits : Integer = -1; aDontShow : TwbDontShowCallback = nil; aNormalizer : TwbFloatNormalizer = nil; aDefault : Extended = 0.0; aGetCP : TwbGetConflictPriority = nil) : IwbFloatDef; overload; function wbDouble(const aName : string; aPriority : TwbConflictPriority; aRequired : Boolean; aDontShow : TwbDontShowCallback; aAfterSet : TwbAfterSetCallback = nil; aNormalizer : TwbFloatNormalizer = nil; aDefault : Extended = 0.0; aGetCP : TwbGetConflictPriority = nil) : IwbFloatDef; overload; function wbFloatT(const aSignature : TwbSignature; const aName : string = 'Unknown'; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aScale : Extended = 1.0; aDigits : Integer = -1; aDontShow : TwbDontShowCallback = nil; aNormalizer : TwbFloatNormalizer = nil; aDefault : Extended = 0.0; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbFloatT(const aName : string = 'Unknown'; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aScale : Extended = 1.0; aDigits : Integer = -1; aDontShow : TwbDontShowCallback = nil; aNormalizer : TwbFloatNormalizer = nil; aDefault : Extended = 0.0; aGetCP : TwbGetConflictPriority = nil) : IwbFloatDef; overload; function wbFloatT(const aName : string; aPriority : TwbConflictPriority; aRequired : Boolean; aDontShow : TwbDontShowCallback; aAfterSet : TwbAfterSetCallback = nil; aNormalizer : TwbFloatNormalizer = nil; aDefault : Extended = 0.0; aGetCP : TwbGetConflictPriority = nil) : IwbFloatDef; overload; function wbDoubleT(const aSignature : TwbSignature; const aName : string = 'Unknown'; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aScale : Extended = 1.0; aDigits : Integer = -1; aDontShow : TwbDontShowCallback = nil; aNormalizer : TwbFloatNormalizer = nil; aDefault : Extended = 0.0; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbDoubleT(const aName : string = 'Unknown'; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aScale : Extended = 1.0; aDigits : Integer = -1; aDontShow : TwbDontShowCallback = nil; aNormalizer : TwbFloatNormalizer = nil; aDefault : Extended = 0.0; aGetCP : TwbGetConflictPriority = nil) : IwbFloatDef; overload; function wbDoubleT(const aName : string; aPriority : TwbConflictPriority; aRequired : Boolean; aDontShow : TwbDontShowCallback; aAfterSet : TwbAfterSetCallback = nil; aNormalizer : TwbFloatNormalizer = nil; aDefault : Extended = 0.0; aGetCP : TwbGetConflictPriority = nil) : IwbFloatDef; overload; {--- wbArray - list of identical elements -------------------------------------} function wbArray(const aSignature : TwbSignature; const aName : string; const aElement : IwbValueDef; aCount : Integer = 0; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbArray(const aName : string; const aElement : IwbValueDef; aCount : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; function wbArray(const aName : string; const aElement : IwbValueDef; aCount : Integer; aAfterLoad : TwbAfterLoadCallback; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; function wbArray(const aSignature : TwbSignature; const aName : string; const aElement : IwbValueDef; const aLabels : array of string; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbArray(const aSignature : TwbSignature; const aName : string; const aElement : IwbValueDef; const aLabels : array of string; aCountCallback : TwbCountCallback; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbArray(const aName : string; const aElement : IwbValueDef; const aLabels : array of string; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; function wbArray(const aName : string; const aElement : IwbValueDef; const aLabels : array of string; aCountCallback : TwbCountCallback; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; function wbArray(const aName : string; const aElement : IwbValueDef; aCountCallback : TwbCountCallback; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; function wbArrayPT(const aSignature : TwbSignature; // case where the prefix is terminated. const aName : string; const aElement : IwbValueDef; aCount : Integer = 0; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbArrayPT(const aName : string; const aElement : IwbValueDef; aCount : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; function wbArrayPT(const aName : string; const aElement : IwbValueDef; aCount : Integer; aAfterLoad : TwbAfterLoadCallback; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; function wbArrayT(const aName : string; // case where members are not terminated, but the array itself yes const aElement : IwbValueDef; aCount : Integer; const aLabels : array of string; aAfterLoad : TwbAfterLoadCallback; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; function wbArrayPT(const aSignature : TwbSignature; const aName : string; const aElement : IwbValueDef; const aLabels : array of string; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbArrayPT(const aSignature : TwbSignature; const aName : string; const aElement : IwbValueDef; const aLabels : array of string; aCountCallback : TwbCountCallback; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbArrayPT(const aName : string; const aElement : IwbValueDef; const aLabels : array of string; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; function wbArrayPT(const aName : string; const aElement : IwbValueDef; const aLabels : array of string; aCountCallback : TwbCountCallback; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; function wbArrayT(const aName : string; // case where members are not terminated, but the array itself yes const aElement : IwbValueDef; const aLabels : array of string; aCountCallback : TwbCountCallback; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; function wbArrayPT(const aName : string; const aElement : IwbValueDef; aCountCallback : TwbCountCallback; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; function wbRArray(const aName : string; const aElement : IwbRecordMemberDef; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordArrayDef; overload; function wbArrayS(const aSignature : TwbSignature; const aName : string; const aElement : IwbValueDef; aCount : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbArrayS(const aName : string; const aElement : IwbValueDef; aCount : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aDontShow : TwbDontShowCallback = nil; aCanAddTo : Boolean = True; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; function wbArrayS(const aName : string; const aElement : IwbValueDef; aCount : Integer; aAfterLoad : TwbAfterLoadCallback; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aAfterSet : TwbAfterSetCallback = nil; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; function wbArrayS(const aName : string; const aElement : IwbValueDef; aCountCallback : TwbCountCallback; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; function wbArray(const aName : string; const aElement : IwbValueDef; aCountCallback : TwbCountCallback; aPriority : TwbConflictPriority; aRequired : Boolean; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; function wbArrayS(const aSignature : TwbSignature; const aName : string; const aElement : IwbValueDef; const aLabels : array of string; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbArrayS(const aName : string; const aElement : IwbValueDef; const aLabels : array of string; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; function wbRArrayS(const aName : string; const aElement : IwbRecordMemberDef; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aDontShow : TwbDontShowCallback = nil; aIsSorted : TwbIsSortedCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordArrayDef; overload; {--- wbStruct - ordered list of members ----------------------------------------} function wbStructSK(const aSortKey : array of Integer; const aName : string; const aMembers : array of IwbValueDef; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aOptionalFromElement : Integer = -1; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbStructDef; overload; function wbStructSK(const aSortKey : array of Integer; const aName : string; const aMembers : array of IwbValueDef; {$IFDEF WIN32} const aElementMap : array of Cardinal; {$ENDIF WIN32} {$IFDEF WIN64} const aElementMap : array of UInt64; {$ENDIF WIN64} aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aOptionalFromElement : Integer = -1; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbStructDef; overload; function wbStructSK(const aSignature : TwbSignature; const aSortKey : array of Integer; const aName : string; const aMembers : array of IwbValueDef; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aOptionalFromElement : Integer = -1; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbMultiStructSK(const aSignatures : array of TwbSignature; const aSortKey : array of Integer; const aName : string; const aMembers : array of IwbValueDef; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aOptionalFromElement : Integer = -1; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; function wbStructExSK(const aSortKey : array of Integer; const aExSortKey : array of Integer; const aName : string; const aMembers : array of IwbValueDef; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aOptionalFromElement : Integer = -1; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbStructDef; overload; function wbStructExSK(const aSignature : TwbSignature; const aSortKey : array of Integer; const aExSortKey : array of Integer; const aName : string; const aMembers : array of IwbValueDef; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aOptionalFromElement : Integer = -1; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbStruct(const aSignature : TwbSignature; const aName : string; const aMembers : array of IwbValueDef; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aOptionalFromElement : Integer = -1; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbStruct(const aName : string; const aMembers : array of IwbValueDef; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aOptionalFromElement : Integer = -1; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbStructDef; overload; function wbStructC(const aName : string; aSizing : TwbSizeCallback; aGetChapterType : TwbGetChapterTypeCallback; aGetChapterTypeName : TwbGetChapterTypeNameCallback; aGetChapterName : TwbGetChapterNameCallback; const aMembers : array of IwbValueDef; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aOptionalFromElement : Integer = -1; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbStructDef; overload; function wbStructZ(const aName : string; aSizing : TwbSizeCallback; aGetChapterType : TwbGetChapterTypeCallback; aGetChapterTypeName : TwbGetChapterTypeNameCallback; aGetChapterName : TwbGetChapterNameCallback; const aMembers : array of IwbValueDef; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aOptionalFromElement : Integer = -1; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbStructDef; overload; function wbStructLZ(const aName : string; aSizing : TwbSizeCallback; aGetChapterType : TwbGetChapterTypeCallback; aGetChapterTypeName : TwbGetChapterTypeNameCallback; aGetChapterName : TwbGetChapterNameCallback; const aMembers : array of IwbValueDef; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aOptionalFromElement : Integer = -1; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbStructDef; overload; function wbRStruct(const aName : string; const aMembers : array of IwbRecordMemberDef; const aSkipSigs : array of TwbSignature; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAllowUnordered : Boolean = False; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordStructDef; overload; function wbRStructSK(const aSortKey : array of Integer; const aName : string; const aMembers : array of IwbRecordMemberDef; const aSkipSigs : array of TwbSignature; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAllowUnordered : Boolean = False; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordStructDef; overload; function wbRStructExSK(const aSortKey : array of Integer; const aExSortKey : array of Integer; const aName : string; const aMembers : array of IwbRecordMemberDef; const aSkipSigs : array of TwbSignature; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAllowUnordered : Boolean = False; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordStructDef; overload; function wbRUnion(const aName : string; const aMembers : array of IwbRecordMemberDef; const aSkipSigs : array of TwbSignature; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordUnionDef; {--- wbStructS - array of struct ----------------------------------------------} function wbStructS(const aSignature : TwbSignature; const aName : string; const aElementName : string; const aMembers : array of IwbValueDef; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbStructS(const aName : string; const aElementName : string; const aMembers : array of IwbValueDef; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; function wbRStructS(const aName : string; const aElementName : string; const aMembers : array of IwbRecordMemberDef; const aSkipSigs : array of TwbSignature; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordArrayDef; overload; function wbRStructsSK(const aName : string; const aElementName : string; const aSortKey : array of Integer; const aMembers : array of IwbRecordMemberDef; const aSkipSigs : array of TwbSignature; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordArrayDef; overload; function wbEmpty(const aSignature : TwbSignature; const aName : string; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbEmpty(const aName : string; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aSorted : Boolean = False; aGetCP : TwbGetConflictPriority = nil) : IwbValueDef; overload; function wbRefID: IwbRefID; overload; function wbRefID(const aName : string; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbIntegerDef; overload; function wbRefIDT(const aName : string; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbIntegerDef; overload; function wbDumpInteger : IwbIntegerDefFormater; overload; function wbKey2Data6Enum(const aNames : array of string) : IwbKey2Data6EnumDef; overload; function wbData6Key2Enum(const aNames : array of string) : IwbData6Key2EnumDef; overload; function wbFormID: IwbFormID; overload; function wbFormID(const aValidRefs : array of TwbSignature; aPersistent: Boolean) : IwbFormID; overload; function wbFormIDNoReach(const aValidRefs : array of TwbSignature; aPersistent : Boolean) : IwbFormID; overload; function wbFormID(const aValidRefs : array of TwbSignature; const aValidFlstRefs : array of TwbSignature; aPersistent : Boolean) : IwbFormID; overload; function wbFormIDNoReach(const aValidRefs : array of TwbSignature; const aValidFlstRefs : array of TwbSignature; aPersistent : Boolean) : IwbFormID; overload; function wbFormID(const aSignature : TwbSignature; const aName : string = 'Unknown'; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbFormID(const aName : string; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil) : IwbIntegerDef; overload; function wbFormIDT(const aName : string; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbIntegerDef; overload; function wbFormIDCk(const aSignature : TwbSignature; const aName : string; const aValidRefs : array of TwbSignature; aPersistent: Boolean = False; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbFormIDCkNoReach(const aSignature : TwbSignature; const aName : string; const aValidRefs : array of TwbSignature; aPersistent: Boolean = False; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbFormIDCk(const aName : string; const aValidRefs : array of TwbSignature; aPersistent: Boolean = False; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil) : IwbIntegerDef; overload; function wbFormIDCkNoReach(const aName : string; const aValidRefs : array of TwbSignature; aPersistent: Boolean = False; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbIntegerDef; overload; function wbFormIDCk(const aSignature : TwbSignature; const aName : string; const aValidRefs : array of TwbSignature; const aValidFlstRefs : array of TwbSignature; aPersistent : Boolean = False; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; function wbFormIDCk(const aName : string; const aValidRefs : array of TwbSignature; const aValidFlstRefs : array of TwbSignature; aPersistent : Boolean = False; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbIntegerDef; overload; function wbFormIDCkNoReach(const aName : string; const aValidRefs : array of TwbSignature; const aValidFlstRefs : array of TwbSignature; aPersistent : Boolean = False; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbIntegerDef; overload; function wbChar4: IwbChar4; function wbStr4: IwbStr4; function wbFlags(const aNames : array of string; aUnknownIsUnused : Boolean = False) : IwbFlagsDef; overload; function wbFlags(const aNames : array of string; const aFlagsToIgnore : array of integer) : IwbFlagsDef; overload; function wbFlags(const aNames : array of string; const aDontShows : array of TwbDontShowCallback; aUnknownIsUnused : Boolean = False) : IwbFlagsDef; overload; function wbFlags(const aBaseFlagsDef : IwbFlagsDef; const aNames : array of string; aUnknownIsUnused : Boolean = False) : IwbFlagsDef; overload; function wbFlags(const aBaseFlagsDef : IwbFlagsDef; const aNames : array of string; const aFlagsToIgnore : array of integer) : IwbFlagsDef; overload; function wbFlags(const aBaseFlagsDef : IwbFlagsDef; const aNames : array of string; const aDontShows : array of TwbDontShowCallback; aUnknownIsUnused : Boolean = False) : IwbFlagsDef; overload; function wbEnum(const aNames : array of string) : IwbEnumDef; overload; function wbEnum(const aNames : array of string; const aSparseNames : array of const) : IwbEnumDef; overload; function wbDiv(aValue : Integer) : IwbIntegerDefFormater; function wbMul(aValue : Integer) : IwbIntegerDefFormater; function wbCallback(const aToStr : TwbIntToStrCallback; const aToInt : TwbStrToIntCallback) : IwbIntegerDefFormater; function wbFormaterUnion(aDecider : TwbIntegerDefFormaterUnionDecider; aMembers : array of IwbIntegerDefFormater) : IwbIntegerDefFormaterUnion; function wbIsPlugin(aFileName: string): Boolean; function wbStr4ToString(aInt: Int64): string; type PwbRecordDefEntry = ^TwbRecordDefEntry; TwbRecordDefEntry = record rdeSignature : TwbSignature; rdeHash : Integer; rdeDef : IwbRecordDef; rdeNext : Integer; end; TwbRecordDefEntries = array of TwbRecordDefEntry; const RecordDefHashMapSize = 1546; var wbRecordDefs : TwbRecordDefEntries; wbRecordDefHashMap : array[0..Pred(RecordDefHashMapSize)] of Integer; wbIgnoreRecords : TStringList; wbGroupOrder : TStringList; wbLoadBSAs : Boolean{} = True{}; wbLoadAllBSAs : Boolean{} = False{}; wbArchiveExtension : string = '.bsa'; wbBuildRefs : Boolean{} = True{}; wbContainerHandler : IwbContainerHandler; wbLoaderDone : Boolean; wbLoaderError : Boolean; procedure wbAddGroupOrder(const aSignature: TwbSignature); function wbGetGroupOrder(const aSignature: TwbSignature): Integer; function IntToHex64(Value: Int64; Digits: Integer): string; inline; function CmpB8(a, b: Byte): Integer; function CmpI32(a, b : Integer) : Integer; function CmpW32(a, b: Cardinal): Integer; function CmpI64(const a, b : Int64) : Integer; function CompareElementsFormIDAndLoadOrder(Item1, Item2: Pointer): Integer; function ConflictAllToColor(aConflictAll: TConflictAll): TColor; function ConflictThisToColor(aConflictThis: TConflictThis): TColor; var wbGetFormIDCallback : function(const aElement: IwbElement): Cardinal; function wbFlagsList(aFlags: array of const; aDeleted : Boolean = True; aUnknowns: Boolean = False): TDynStrings; function wbGetFormID(const aElement: IwbElement): Cardinal; function wbPositionToGridCell(const aPosition: TwbVector): TwbGridCell; function wbSubBlockFromGridCell(const aGridCell: TwbGridCell): TwbGridCell; function wbBlockFromSubBlock(const aSubBlock: TwbGridCell): TwbGridCell; function wbGridCellToGroupLabel(const aGridCell: TwbGridCell): Cardinal; function wbIsInGridCell(const aPosition: TwbVector; const aGridCell: TwbGridCell): Boolean; var wbRecordFlags : IwbIntegerDef; wbMainRecordHeader : IwbStructDef; wbSizeOfMainRecordStruct : Integer; type TwbGameMode = (gmFNV, gmFO3, gmTES3, gmTES4, gmTES5, gmSSE, gmFO4); TwbToolMode = (tmView, tmEdit, tmDump, tmExport, tmMasterUpdate, tmMasterRestore, tmLODgen, tmScript, tmTranslate, tmESMify, tmESPify, tmSortAndCleanMasters, tmCheckForErrors, tmCheckForITM, tmCheckForDR); TwbToolSource = (tsPlugins, tsSaves); TwbSetOfMode = set of TwbToolMode; var wbGameMode : TwbGameMode; wbToolMode : TwbToolMode; wbToolSource : TwbToolSource; wbAppName : string; wbGameName : string; wbGameName2 : string; // game title name wbToolName : string; wbSourceName : String; wbLanguage : string; wbAutoModes : TwbSetOfMode = [ tmMasterUpdate, tmMasterRestore, tmLODgen, // Tool modes that run without user interaction until final status tmESMify, tmESPify, tmSortAndCleanMasters, tmCheckForErrors, tmCheckForITM, tmCheckForDR ]; wbPluginModes : TwbSetOfMode = [ tmESMify, tmESPify, tmSortAndCleanMasters, tmCheckForErrors, tmCheckForITM, tmCheckForDR ]; // Auto modes that require a specific plugin to be provided. wbAlwaysMode : TwbSetOfMode = [ tmView, tmEdit, tmESMify, tmESPify, tmSortAndCleanMasters, tmLODgen, tmScript, tmCheckForITM, tmCheckForDR, tmCheckForErrors ]; // Modes available to all decoded games function wbDefToName(const aDef: IwbDef): string; function wbDefsToPath(const aDefs: TwbDefPath): string; procedure ReportDefs; type IwbProgress = interface ['{054006B0-096D-43CD-A92A-3095B525C854}'] procedure UpdateStatus(aPosition: Integer; const aStatus: string); end; IwbWaitForm = interface ['{185C220C-3135-4A8A-8E0E-8001759F3C85}'] function GetIsCanceled: Boolean; function CreateProgress(const aCaption : string; const aStatus : string; aMax : Integer) : IwbProgress; property IsCanceled: Boolean read GetIsCanceled; end; TwbCreateWaitForm = function(const aCaption : string; const aMessage : string; aCanCancel : Boolean; aShowDelay : Integer = 0; aUpdateDelay : Integer = 0) : IwbWaitForm; function NullCreateWaitForm(const aCaption : string; const aMessage : string; aCanCancel : Boolean; aShowDelay : Integer = 0; aUpdateDelay : Integer = 0) : IwbWaitForm; var wbCreateWaitForm : TwbCreateWaitForm = NullCreateWaitForm; type TwbFastStringList = class(TStringList) protected function CompareStrings(const S1, S2: string): Integer; override; public constructor CreateSorted(aDups : TDuplicates = dupError); procedure Clear(aFreeObjects: Boolean = False); reintroduce; end; TwbFastStringListCS = class(TwbFastStringList) public procedure AfterConstruction; override; end; TwbFastStringListIC = class(TwbFastStringList) end; function RadiansNormalize(const aElement: IwbElement; aFloat: Extended): Extended; function wbBeginInternalEdit(aForce: Boolean = False): Boolean; procedure wbEndInternalEdit; function wbIsInternalEdit: Boolean; function StrToSignature(const s: string): TwbSignature; function wbStringToAnsi(const aString: string; const aElement: IwbElement): AnsiString; function wbAnsiToString(const aString: AnsiString; const aElement: IwbElement): string; function FixupFormID(aFormID: Cardinal; const aOld, aNew: TBytes): Cardinal; threadvar _InternalEditCount: Integer; _BlockInternalEdit: Boolean; var wbActorValueEnum: IwbEnumDef; function GetContainerFromUnion(const aElement: IwbElement): IwbContainer; function GetContainerRefFromUnionOrValue(const aElement: IwbElement): IwbContainerElementRef; function GetElementFromUnion(const aElement: IwbElement): IwbElement; var wbHeaderSignature : TwbSignature = 'TES4'; wbFileMagic : TwbFileMagic; wbFilePlugins : String = 'Master Files'; wbUseFalsePlugins : Boolean = False; wbFileHeader : IwbStructDef; wbFileChapters : IwbStructDef; wbBytesToSkip : Cardinal = 0; wbBytesToDump : Cardinal = $FFFFFFFF; wbBytesToGroup : Cardinal = 4; wbExtractInfo : ^TByteSet; wbTerminator : Byte = Ord('|'); wbPlayerRefID : Cardinal = $14; wbChangedFormOffset : Integer = 10000; wbOfficialDLC : array of string; type {$IFDEF WIN32} TwbRefIDArray = array of Cardinal; {$ENDIF WIN32} {$IFDEF WIN64} TwbRefIDArray = array of UInt64; {$ENDIF WIN64} function wbReadInteger24(aBasePtr: pointer): Int64; procedure InitializeRefIDArray(anArray: TwbRefIDArray); function wbFindRecordDef(const aSignature : TwbSignature; out aRecordDef : PwbRecordDef) : Boolean; overload; function wbFindRecordDef(const aSignature : AnsiString; out aRecordDef : PwbRecordDef) : Boolean; overload; function _wbRecordDefMap: TStringList; implementation uses Windows, Variants, Math, AnsiStrings, TypInfo, wbSort, wbLocalization; function StrToSignature(const s: string): TwbSignature; var t: AnsiString; begin t := AnsiString(s); if Length(t) >= 4 then Result := PwbSignature(@t[1])^ else raise Exception.Create('"'+t+'" is not a valid signature'); end; function IsTranslatable(const aElement: IwbElement): Boolean; var Def: IwbDef; begin Result := False; if Assigned(aElement) then begin Def := aElement.ValueDef; if not Assigned(Def) then Def := aElement.Def; if Assigned(Def) then Result := Def.ConflictPriority[aElement] = cpTranslate; end; end; function wbStringToAnsi(const aString: String; const aElement: IwbElement): AnsiString; var Translatable: Boolean; begin if Assigned(aElement) then Translatable := IsTranslatable(aElement) else Translatable := True; if Translatable and (wbStringEncoding = seUTF8) then Result := UTF8Encode(aString) else Result := AnsiString(aString); end; function wbAnsiToString(const aString: AnsiString; const aElement: IwbElement): string; var Translatable: Boolean; begin if Assigned(aElement) then Translatable := IsTranslatable(aElement) else Translatable := True; if Translatable and (wbStringEncoding = seUTF8) then Result := UTF8Decode(aString) else Result := string(aString); end; function wbBeginInternalEdit(aForce: Boolean): Boolean; begin Result := wbEditAllowed and (wbAllowInternalEdit or aForce) and not _BlockInternalEdit; if Result then Inc(_InternalEditCount); end; procedure wbEndInternalEdit; begin Dec(_InternalEditCount); end; function wbIsInternalEdit: Boolean; begin Result := _InternalEditCount > 0; end; var OnePi : Single = 3.1415927;//(2!) 653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067; TwoPi : Extended; function RoundToEx(const AValue: Extended; const ADigit: TRoundToRange): Extended; var LFactor: Extended; begin LFactor := IntPower(10, ADigit); Result := Round(AValue / LFactor) * LFactor; end; function DoSingleSameValue(const A, B: Single): Boolean; const SingleResolution : Single = 0.000000499999999999999999999; begin Result := Abs(A - B) <= Max(Min(Abs(A), Abs(B)) * SingleResolution, SingleResolution) end; function SingleSameValue(const A, B: Extended): Boolean; var sA, sB: Single; begin sA := A; sB := B; Result := DoSingleSameValue(sA, sB); end; function RadiansNormalize(const aElement: IwbElement; aFloat: Extended): Extended; begin // Result := RoundToEx(aFloat, -6); Result := aFloat; if Abs(Result/TwoPi) > 100.0 then Result := Result - Sign(Result)*TwoPi*Trunc(Abs(Result/TwoPi) - 100.0); while Result < 0.0 do Result := Result + TwoPi; while Result > TwoPi do Result := Result - TwoPi; if SingleSameValue(Result, 0.0) or (Result < 0.0) then Result := 0.0; if SingleSameValue(Result, TwoPi) or (Result > TwoPi) then Result := 0.0; // Result := RoundToEx(Result, -6); end; type TwbNullWaitForm = class(TInterfacedObject, IwbWaitForm) protected {--- IwbWaitForm ---} function GetIsCanceled: Boolean; function CreateProgress(const aCaption : string; const aStatus : string; aMax : Integer) : IwbProgress; end; TwbNullProgress = class(TInterfacedObject, IwbProgress) protected {--- IwbProgress ---} procedure UpdateStatus(aPosition: Integer; const aStatus: string); end; { TwbNullWaitForm } function TwbNullWaitForm.CreateProgress(const aCaption, aStatus: string; aMax: Integer): IwbProgress; begin Result := TwbNullProgress.Create; end; function TwbNullWaitForm.GetIsCanceled: Boolean; begin Result := False; end; { TwbNullProgress } procedure TwbNullProgress.UpdateStatus(aPosition: Integer; const aStatus: string); begin end; function NullCreateWaitForm(const aCaption : string; const aMessage : string; aCanCancel : Boolean; aShowDelay : Integer = 0; aUpdateDelay : Integer = 0) : IwbWaitForm; begin Result := TwbNullWaitForm.Create; end; procedure ReportDefs; var i: Integer; begin for i:= Low(wbRecordDefs) to High(wbRecordDefs) do wbRecordDefs[i].rdeDef.Report(nil); end; function wbDefToName(const aDef: IwbDef): string; var SignatureDef : IwbSignatureDef; Signature : TwbSignature; NamedDef : IwbNamedDef; i : Integer; begin if Supports(aDef, IwbSignatureDef, SignatureDef) then begin Signature := SignatureDef.DefaultSignature; if Signature[0]=#0 then Result := '$(00)'+Signature[1]+Signature[2]+Signature[3] + ' - ' + SignatureDef.Name else Result := Signature + ' - ' + SignatureDef.Name; end else if Supports(aDef, IwbNamedDef, NamedDef) then begin Result := NamedDef.Name; end else if Assigned(aDef) then begin Result := '<'+GetEnumName(TypeInfo(TwbDefType), Ord(aDef.DefType))+'>'; end else Result := ''; for i := Length(Result) downto 1 do if Result[i]<' ' then begin Insert('$('+IntToHex(Ord(Result[i]), 2)+')', Result, i); Delete(Result, i + 5, 1); end; end; function wbDefsToPath(const aDefs: TwbDefPath): string; var i: Integer; begin Result := ''; for i := Low(aDefs) to High(aDefs) do begin Result := Result + wbDefToName(aDefs[i].Def) + ' \ '; if aDefs[i].Index >= 0 then Result := Result + '['+IntToStr(aDefs[i].Index)+'] '; end; end; function wbIsInGridCell(const aPosition: TwbVector; const aGridCell: TwbGridCell): Boolean; var GridCell : TwbGridCell; begin GridCell := wbPositionToGridCell(aPosition); Result := (GridCell.x = aGridCell.x) and (GridCell.y = aGridCell.y); end; function wbPositionToGridCell(const aPosition: TwbVector): TwbGridCell; begin Result.x := Trunc(aPosition.x / 4096); if aPosition.x < 0 then Dec(Result.x); Result.y := Trunc(aPosition.y / 4096); if aPosition.y < 0 then Dec(Result.y); end; function wbSubBlockFromGridCell(const aGridCell: TwbGridCell): TwbGridCell; begin Result.x := aGridCell.x div 8; if (aGridCell.x < 0) and ((aGridCell.x mod 8) <> 0) then Dec(Result.x); Result.y := aGridCell.y div 8; if (aGridCell.y < 0) and ((aGridCell.y mod 8) <> 0) then Dec(Result.y); end; function wbBlockFromSubBlock(const aSubBlock: TwbGridCell): TwbGridCell; begin Result.x := aSubBlock.x div 4; if (aSubBlock.x < 0) and ((aSubBlock.x mod 4) <> 0) then Dec(Result.x); Result.y := aSubBlock.y div 4; if (aSubBlock.y < 0) and ((aSubBlock.y mod 4) <> 0) then Dec(Result.y); end; function wbGridCellToGroupLabel(const aGridCell: TwbGridCell): Cardinal; var x, y: Smallint; xx,yy: Word; begin x := aGridCell.x; y := aGridCell.y; xx := PWord(@x)^; yy := PWord(@y)^; Result := Cardinal(yy) or (Cardinal(xx) shl 16); end; function wbGetFormID(const aElement: IwbElement): Cardinal; begin if Assigned(wbGetFormIDCallback) then Result := wbGetFormIDCallback(aElement) else Result := 0; end; function ConflictAllToColor(aConflictAll: TConflictAll): TColor; begin Result := wbColorConflictAll[aConflictAll]; end; function ConflictThisToColor(aConflictThis: TConflictThis): TColor; begin Result := wbColorConflictThis[aConflictThis]; end; procedure wbAddGroupOrder(const aSignature: TwbSignature); begin if not Assigned(wbGroupOrder) then wbGroupOrder := TwbFastStringListCS.CreateSorted; wbGroupOrder.AddObject(aSignature, Pointer(wbGroupOrder.Count)); end; function wbGetGroupOrder(const aSignature: TwbSignature): Integer; begin if Assigned(wbGroupOrder) then begin Result := wbGroupOrder.IndexOf(aSignature); if Result >= 0 then Result := Integer(wbGroupOrder.Objects[Result]); end else Result := -1; end; function CompareElementsFormIDAndLoadOrder(Item1, Item2: Pointer): Integer; var MainRecord1, MainRecord2: IwbMainRecord; begin if Item1 = Item2 then begin Result := 0; Exit; end; MainRecord1 := IwbElement(Item1) as IwbMainRecord; MainRecord2 := IwbElement(Item2) as IwbMainRecord; Result := CmpW32( MainRecord1.LoadOrderFormID, MainRecord2.LoadOrderFormID); if Result = 0 then Result := CmpI32( MainRecord1._File.LoadOrder, MainRecord2._File.LoadOrder); end; function wbFlagsList(aFlags: array of const; aDeleted : Boolean = True; aUnknowns: Boolean = False): TDynStrings; var e: IwbEnumDef; i: integer; s: string; begin e := wbEnum([], aFlags); SetLength(Result, 32); for i := 0 to 31 do if i = 12 then Result[i] := 'Ignored' else if aDeleted and (i = 5) then Result[i] := 'Deleted' else begin s := e.ToString(i, nil); if Pos('<', s) <> 1 then Result[i] := s else if aUnknowns then Result[i] := 'Unknown ' + IntToStr(i); end end; type TwbDef = class; IwbDefInternal = interface(IwbDef) ['{8EBA62A9-AF6B-4377-B52C-A1CEBF5B3ED6}'] function SetParent(const aParent: TwbDef; aForceDuplicate: Boolean): IwbDef; end; TwbDefClass = class of TwbDef; TwbDef = class(TInterfacedObject, IwbDef, IwbDefInternal) private defSource : IwbDef; defParent : TwbDef; defPriority : TwbConflictPriority; defGetCP : TwbGetConflictPriority; defRequired : Boolean; defUsed : Boolean; defReported : Boolean; defPossiblyRequired : Boolean; defNotRequired : Boolean; IsUnknown : Boolean; IsUnknownChecked : Boolean; UnknownValues : TStringList; protected constructor Clone(const aSource: TwbDef); virtual; constructor Create(aPriority: TwbConflictPriority; aRequired: Boolean; aGetCP: TwbGetConflictPriority); {---IwbDef---} function GetDefType: TwbDefType; virtual; abstract; function GetDefTypeName: string; virtual; abstract; function CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; virtual; function Assign(const aTarget: IwbElement; aIndex: Integer; const aSource: IwbElement; aOnlySK: Boolean): IwbElement; virtual; function GetDefID: Cardinal; function Equals(const aDef: IwbDef): Boolean; reintroduce; virtual; function GetConflictPriority(const aElement: IwbElement): TwbConflictPriority; virtual; function GetConflictPriorityCanChange: Boolean; virtual; function GetRequired: Boolean; function CanContainFormIDs: Boolean; virtual; function GetDontShow(const aElement: IwbElement): Boolean; virtual; function GetHasDontShow: Boolean; virtual; function GetRoot: IwbDef; function GetParent: IwbDef; procedure Report(const aParents: TwbDefPath); virtual; procedure Used(const aElement: IwbElement; const s: string); procedure PossiblyRequired; procedure NotRequired; function IsNotRequired: Boolean; function GetNoReach: Boolean; virtual; {--- IwbDefInternal ---} function SetParent(const aParent: TwbDef; aForceDuplicate: Boolean): IwbDef; virtual; procedure ParentSet; virtual; function Duplicate: TwbDef; end; TwbNamedDef = class(TwbDef, IwbNamedDef) private noName : string; noAfterLoad : TwbAfterLoadCallback; noAfterSet : TwbAfterSetCallback; noDontShow : TwbDontShowCallback; noTerminator : Boolean; noUnused : Boolean; noTreeHead : Boolean; noTreeBranch : Boolean; protected constructor Clone(const aSource: TwbDef); override; constructor Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aName : string; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aDontShow : TwbDontShowCallback; aGetCP : TwbGetConflictPriority; aTerminator : Boolean); {--- IwbDef ---} function GetDontShow(const aElement: IwbElement): Boolean; override; function GetHasDontShow: Boolean; override; {--- IwbDefInternal ---} procedure ParentSet; override; {---IwbNamedDef---} function GetName: string; function GetPath: string; procedure AfterLoad(const aElement: IwbElement); virtual; procedure AfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); function GetTreeHead: Boolean; // Is the element expected to be a "header record" in the tree navigator procedure SetTreeHead(aValue: Boolean); // Make the element a "header record" in the tree navigator; function GetTreeBranch: Boolean; // Is the element included in a "leaf" expected to be displayed in the view pane procedure SetTreeBranch(aValue: Boolean); // Make the element included in a "leaf" visible in the tree navigator; end; TwbSignatureDef = class(TwbNamedDef, IwbSignatureDef) private soSignatures : TwbSignatures; protected constructor Clone(const aSource: TwbDef); override; constructor Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aSignature : TwbSignature; const aName : string; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aDontShow : TwbDontShowCallback; aGetCP : TwbGetConflictPriority); overload; constructor Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aSignatures : array of TwbSignature; const aName : string; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aDontShow : TwbDontShowCallback; aGetCP : TwbGetConflictPriority); overload; {---IwbSignatureDef---} function GetDefaultSignature: TwbSignature; function GetSignatures(const aIndex: Integer): TwbSignature; function GetSignatureCount: Integer; function CanHandle(aSignature : TwbSignature; const aDataContainer : IwbDataContainer) : Boolean; virtual; end; TwbRecordDef = class(TwbSignatureDef, IwbRecordDef) private recRecordFlags : IwbIntegerDefFormater; recRecordHeaderStruct : IwbStructDef; recMembers : array of IwbRecordMemberDef; recSignatures : TStringList; recAllowUnordered : Boolean; recAddInfoCallback : TwbAddInfoCallback; recCanContainFormIDs : Boolean; recQuickInitLimit : Integer; recContainsEditorID : Boolean; protected constructor Clone(const aSource: TwbDef); override; constructor Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aSignature : TwbSignature; const aName : string; const aRecordFlags : IwbIntegerDefFormater; const aMembers : array of IwbRecordMemberDef; aAllowUnordered : Boolean; aAddInfoCallback : TwbAddInfoCallback; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback); destructor Destroy; override; {---IwbDef---} function GetDefType: TwbDefType; override; function GetDefTypeName: string; override; procedure Report(const aParents: TwbDefPath); override; {---IwbRecordDef---} function ContainsMemberFor(aSignature : TwbSignature; const aDataContainer : IwbDataContainer) : Boolean; function GetMemberFor(aSignature : TwbSignature; const aDataContainer : IwbDataContainer) : IwbRecordMemberDef; function GetMemberIndexFor(aSignature : TwbSignature; const aDataContainer : IwbDataContainer) : Integer; function AllowUnordered: Boolean; function AdditionalInfoFor(const aMainRecord: IwbMainRecord): string; function GetMember(aIndex: Integer): IwbRecordMemberDef; function GetMemberCount: Integer; function CanContainFormIDs: Boolean; override; function GetSkipSignature(const aSignature: TwbSignature): Boolean; virtual; function GetQuickInitLimit: Integer; function GetContainsEditorID: Boolean; function GetRecordHeaderStruct: IwbStructDef; procedure AfterLoad(const aElement: IwbElement); override; end; TwbSubRecordDef = class(TwbSignatureDef, IwbRecordMemberDef, IwbSubRecordDef) private srValue : IwbValueDef; srSizeMatch : Boolean; srHasUnusedData: Boolean; protected constructor Clone(const aSource: TwbDef); override; constructor Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aSignature : TwbSignature; const aName : string; const aValue : IwbValueDef; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aSizeMatch : Boolean; aDontShow : TwbDontShowCallback; aGetCP : TwbGetConflictPriority); overload; constructor Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aSignatures : array of TwbSignature; const aName : string; const aValue : IwbValueDef; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aSizeMatch : Boolean; aDontShow : TwbDontShowCallback; aGetCP : TwbGetConflictPriority); overload; {---IwbDef---} function GetDefType: TwbDefType; override; function GetDefTypeName: string; override; function CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; override; procedure Report(const aParents: TwbDefPath); override; {---IwbSubRecordDef---} function GetValue: IwbValueDef; function CanContainFormIDs: Boolean; override; procedure HasUnusedData; function CanHandle(aSignature : TwbSignature; const aDataContainer : IwbDataContainer) : Boolean; override; end; TwbSubRecordArrayDef = class(TwbNamedDef, IwbRecordMemberDef, IwbSubRecordArrayDef) private sraElement : IwbRecordMemberDef; sraSorted : Boolean; sraIsSorted : TwbIsSortedCallback; public constructor Clone(const aSource: TwbDef); override; constructor Create(aPriority : TwbConflictPriority; aRequired: Boolean; const aName : string; const aElement : IwbRecordMemberDef; aSorted : Boolean; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aDontShow : TwbDontShowCallback; aIsSorted : TwbIsSortedCallback; aGetCP : TwbGetConflictPriority); {---IwbDef---} function GetDefType: TwbDefType; override; function GetDefTypeName: string; override; function CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; override; function CanContainFormIDs: Boolean; override; procedure Report(const aParents: TwbDefPath); override; {---IwbNamedDef---} procedure AfterLoad(const aElement: IwbElement); override; {---IwbSignatureDef---} function GetDefaultSignature: TwbSignature; function GetSignatures(const aIndex: Integer): TwbSignature; function GetSignatureCount: Integer; function CanHandle(aSignature : TwbSignature; const aDataContainer : IwbDataContainer) : Boolean; virtual; {---IwbSubRecordArrayDef---} function GetElement: IwbRecordMemberDef; function GetSorted(const aContainer: IwbContainer): Boolean; end; TwbSubRecordStructDef = class(TwbNamedDef, IwbRecordMemberDef, IwbSubRecordStructDef, IwbRecordDef) private srsMembers : array of IwbRecordMemberDef; srsSignatures : TStringList; srsSkipSignatures : TStringList; srsCanContainFormIDs : Boolean; srsAllowUnordered : Boolean; public constructor Clone(const aSource: TwbDef); override; constructor Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aName : string; const aMembers : array of IwbRecordMemberDef; const aSkipSigs : array of TwbSignature; aDontShow : TwbDontShowCallback; aAllowUnordered : Boolean; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aGetCP : TwbGetConflictPriority); destructor Destroy; override; {---IwbDef---} function GetDefType: TwbDefType; override; function GetDefTypeName: string; override; function CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; override; function CanContainFormIDs: Boolean; override; procedure Report(const aParents: TwbDefPath); override; {---IwbNamedDef---} procedure AfterLoad(const aElement: IwbElement); override; {---IwbSignatureDef---} function GetDefaultSignature: TwbSignature; function GetSignatures(const aIndex: Integer): TwbSignature; function GetSignatureCount: Integer; function CanHandle(aSignature : TwbSignature; const aDataContainer : IwbDataContainer) : Boolean; virtual; {---IwbRecordDef---} function ContainsMemberFor(aSignature : TwbSignature; const aDataContainer : IwbDataContainer) : Boolean; function GetMemberFor(aSignature : TwbSignature; const aDataContainer : IwbDataContainer) : IwbRecordMemberDef; function GetMemberIndexFor(aSignature : TwbSignature; const aDataContainer : IwbDataContainer) : Integer; function AllowUnordered: Boolean; function AdditionalInfoFor(const aMainRecord: IwbMainRecord): string; function GetMember(aIndex: Integer): IwbRecordMemberDef; function GetMemberCount: Integer; function GetSkipSignature(const aSignature: TwbSignature): Boolean; virtual; function GetQuickInitLimit: Integer; virtual; function GetContainsEditorID: Boolean; function GetRecordHeaderStruct: IwbStructDef; end; TwbSubRecordUnionDef = class(TwbNamedDef, IwbRecordMemberDef, IwbSubRecordUnionDef, IwbRecordDef) private sruMembers : array of IwbRecordMemberDef; sruSignatures : TStringList; sruSkipSignatures : TStringList; sruCanContainFormIDs : Boolean; public constructor Clone(const aSource: TwbDef); override; constructor Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aName : string; const aMembers : array of IwbRecordMemberDef; const aSkipSigs : array of TwbSignature; aDontShow : TwbDontShowCallback; aGetCP : TwbGetConflictPriority); destructor Destroy; override; {---IwbDef---} function GetDefType: TwbDefType; override; function GetDefTypeName: string; override; function CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; override; function CanContainFormIDs: Boolean; override; procedure Report(const aParents: TwbDefPath); override; {---IwbSignatureDef---} function GetDefaultSignature: TwbSignature; function GetSignatures(const aIndex: Integer): TwbSignature; function GetSignatureCount: Integer; function CanHandle(aSignature : TwbSignature; const aDataContainer : IwbDataContainer) : Boolean; virtual; {---IwbRecordDef---} function ContainsMemberFor(aSignature : TwbSignature; const aDataContainer : IwbDataContainer) : Boolean; function GetMemberFor(aSignature : TwbSignature; const aDataContainer : IwbDataContainer) : IwbRecordMemberDef; function GetMemberIndexFor(aSignature : TwbSignature; const aDataContainer : IwbDataContainer) : Integer; function AllowUnordered: Boolean; function AdditionalInfoFor(const aMainRecord: IwbMainRecord): string; function GetMember(aIndex: Integer): IwbRecordMemberDef; function GetMemberCount: Integer; function GetSkipSignature(const aSignature: TwbSignature): Boolean; virtual; function GetQuickInitLimit: Integer; virtual; function GetContainsEditorID: Boolean; function GetRecordHeaderStruct: IwbStructDef; end; TwbSubRecordStructSKDef = class(TwbSubRecordStructDef, IwbHasSortKeyDef) private srsSortKey : array of Integer; srsExSortKey : array of Integer; srsMemberInSK : array of Boolean; public constructor Clone(const aSource: TwbDef); override; constructor Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aName : string; const aMembers : array of IwbRecordMemberDef; const aSkipSigs : array of TwbSignature; const aSortKey : array of Integer; const aExSortKey : array of Integer; aDontShow : TwbDontShowCallback; aAllowUnordered : Boolean; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aGetCP : TwbGetConflictPriority); {---IwbHasSortKeyDef---} function GetSortKey(aIndex: Integer; aExtended: Boolean): Integer; function GetSortKeyCount(aExtended: Boolean): Integer; function IsInSK(aIndex: Integer): Boolean; end; TwbValueDefState = ( vdsIsVariableSize, vdsIsVariableSizeChecked ); TwbValueDefStates = set of TwbValueDefState; TwbValueDef = class(TwbNamedDef, IwbValueDef) protected vdStates: TwbValueDefStates; {---IwbValueDef---} function ToString(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; reintroduce; virtual; abstract; function ToSortKey(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aExtended: Boolean): string; virtual; function Check(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; virtual; function GetSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; virtual; abstract; function GetDefaultSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; virtual; abstract; function GetLinksTo(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): IwbElement; virtual; procedure BuildRef(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement); virtual; function GetIsVariableSize: Boolean; function GetIsVariableSizeInternal: Boolean; virtual; function GetCanBeZeroSize: Boolean; virtual; function ToEditValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; virtual; procedure FromEditValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: string); virtual; function ToNativeValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Variant; virtual; procedure FromNativeValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: Variant); virtual; function GetIsEditable(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Boolean; virtual; function GetEditType(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): TwbEditType; virtual; function GetEditInfo(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; virtual; function SetToDefault(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Boolean; virtual; function GetElementMap: TDynCardinalArray; virtual; procedure MasterCountUpdated(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aOld, aNew: Byte); virtual; procedure MasterIndicesUpdated(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aOld, aNew: TBytes); virtual; procedure FindUsedMasters(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aMasters: PwbUsedMasters); virtual; function CompareExchangeFormID(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aOldFormID: Cardinal; aNewFormID: Cardinal): Boolean; virtual; end; TwbUnionDef = class(TwbValueDef, IwbUnionDef) protected {private} udDecider: TwbUnionDecider; udMembers: array of IwbValueDef; ubCanContainFormIDs: Boolean; protected constructor Clone(const aSource: TwbDef); override; constructor Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aName : string; aDecider : TwbUnionDecider; const aMembers : array of IwbValueDef; aDontShow : TwbDontShowCallback; aAfterSet : TwbAfterSetCallback; aGetCP : TwbGetConflictPriority); {---IwbDef---} function GetDefType: TwbDefType; override; function GetDefTypeName: string; override; function CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; override; function CanContainFormIDs: Boolean; override; procedure Report(const aParents: TwbDefPath); override; {---IwbValueDef---} function ToString(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; override; function ToSortKey(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aExtended: Boolean): string; override; function Check(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; override; function GetSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; override; function GetDefaultSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; override; function GetLinksTo(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): IwbElement; override; procedure BuildRef(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement); override; function GetIsVariableSizeInternal: Boolean; override; function ToEditValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; override; procedure FromEditValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: string); override; function ToNativeValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Variant; override; procedure FromNativeValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: Variant); override; function GetIsEditable(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Boolean; override; function GetEditType(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): TwbEditType; override; function GetEditInfo(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; override; function SetToDefault(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Boolean; override; {---IwbUnionDef---} function Decide(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): IwbValueDef; function GetMember(aIndex: Integer): IwbValueDef; function GetMemberCount: Integer; end; TwbStringTransformType = ( ttToString, ttToSortKey, ttToEditValue, ttFromEditValue, ttToNativeValue, ttFromNativeValue ); TwbStringDef = class(TwbValueDef, IwbStringDef) protected sdSize: Integer; sdForward: boolean; protected constructor Clone(const aSource: TwbDef); override; constructor Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aName : string; aSize : Integer; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aDontShow : TwbDontShowCallback; aGetCP : TwbGetConflictPriority; aTerminator : Boolean; aForward : boolean = false); virtual; function ToStringNative(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): AnsiString; virtual; function ToStringTransform(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aTransformType: TwbStringTransformType): string; procedure FromStringNative(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: AnsiString); virtual; procedure FromStringTransform(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: string; aTransformType: TwbStringTransformType); function TransformString(const s: AnsiString; aTransformType: TwbStringTransformType; const aElement: IwbElement): AnsiString; virtual; {---IwbDef---} function GetDefType: TwbDefType; override; function GetDefTypeName: string; override; function CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; override; function CanContainFormIDs: Boolean; override; {---IwbValueDef---} function ToString(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; override; function ToSortKey(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aExtended: Boolean): string; override; function GetSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; override; function GetDefaultSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; override; function GetIsVariableSizeInternal: Boolean; override; function ToEditValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; override; procedure FromEditValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: string); override; function ToNativeValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Variant; override; procedure FromNativeValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: Variant); override; function GetIsEditable(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Boolean; override; function SetToDefault(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Boolean; override; {---IwbStringDef---} function GetStringSize: Integer; end; TwbStringScriptDef = class(TwbStringDef) protected function TransformString(const s: AnsiString; aTransformType: TwbStringTransformType; const aElement: IwbElement): AnsiString; override; end; TwbStringLCDef = class(TwbStringDef) protected function TransformString(const s: AnsiString; aTransformType: TwbStringTransformType; const aElement: IwbElement): AnsiString; override; end; TwbStringKCDef = class(TwbStringDef) // Keep Case protected function ToSortKey(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aExtended: Boolean): string; override; end; TwbStringMgefCodeDef = class(TwbStringDef) protected function TransformString(const s: AnsiString; aTransformType: TwbStringTransformType; const aElement: IwbElement): AnsiString; override; {---IwbDef---} function CanContainFormIDs: Boolean; override; {---IwbValueDef---} function GetLinksTo(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): IwbElement; override; procedure BuildRef(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement); override; procedure MasterCountUpdated(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aOld, aNew: Byte); override; procedure MasterIndicesUpdated(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aOld, aNew: TBytes); override; procedure FindUsedMasters(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aMasters: PwbUsedMasters); override; function SetToDefault(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Boolean; override; end; TwbLStringDef = class(TwbStringDef) protected function GetDefType: TwbDefType; override; function GetDefTypeName: string; override; function ToStringNative(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): AnsiString; override; procedure FromStringNative(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: AnsiString); override; function GetSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; override; function GetDefaultSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; override; end; TwbLStringKCDef = class(TwbLStringDef) protected function ToSortKey(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aExtended: Boolean): string; override; end; TwbLenStringDef = class(TwbValueDef, IwbLenStringDef) protected Prefix: Integer; constructor Clone(const aSource: TwbDef); override; constructor Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aName : string; aPrefix : integer; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aDontShow : TwbDontShowCallback; aGetCP : TwbGetConflictPriority; aTerminator : Boolean); {---IwbDef---} function GetDefType: TwbDefType; override; function GetDefTypeName: string; override; function CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; override; function CanContainFormIDs: Boolean; override; {---IwbValueDef---} function ToString(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; override; function Check(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; override; function GetSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; override; function GetDefaultSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; override; function GetIsVariableSizeInternal: Boolean; override; function ToEditValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; override; procedure FromEditValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: string); override; function ToNativeValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Variant; override; procedure FromNativeValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: Variant); override; function GetIsEditable(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Boolean; override; function SetToDefault(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Boolean; override; function GetPrefixLen: Integer; function GetPrefixOffset: Integer; function GetPrefixValue(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; procedure SetPrefixValue(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement; aValue: Cardinal); end; TwbByteArrayDef = class(TwbValueDef, IwbByteArrayDef) protected {private} badSize : Int64; FoundFormIDAtOffSet : array of Integer; NotFoundFormIDAtOffSet : array of Integer; SignaturesAtOffSet : array of TStringList; FormIDsAtOffSetFoundIn : array of TStringList; FoundFloatAtOffSet : array of Integer; NotFoundFloatAtOffSet : array of Integer; FloatsAtOffSet : array of TStringList; FoundString : Integer; NotFoundString : Integer; Strings : TStringList; //------------------------------------------------------------------------------ // Added LString Routine //------------------------------------------------------------------------------ FoundLString : Integer; NotFoundLString : Integer; IsEmpty : Integer; IsNotEmpty : Integer; badCountCallback : TwbCountCallBack; protected constructor Clone(const aSource: TwbDef); override; constructor Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aName : string; aSize : Int64; aDontShow : TwbDontShowCallback; aCountCallback : TwbCountCallback; aGetCP : TwbGetConflictPriority; aTerminator : Boolean); {---IwbDef---} function GetDefType: TwbDefType; override; function GetDefTypeName: string; override; function CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; override; function CanContainFormIDs: Boolean; override; procedure Report(const aParents: TwbDefPath); override; {---IwbValueDef---} function ToString(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; override; function GetSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; override; function GetDefaultSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; override; function GetIsVariableSizeInternal: Boolean; override; function ToEditValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; override; procedure FromEditValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: string); override; function ToNativeValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Variant; override; procedure FromNativeValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: Variant); override; function GetIsEditable(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Boolean; override; function SetToDefault(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Boolean; override; end; TwbEmptyDef = class(TwbValueDef, IwbEmptyDef) protected {private} edSorted: Boolean; protected constructor Clone(const aSource: TwbDef); override; constructor Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aName : string; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aDontShow : TwbDontShowCallback; aSorted : Boolean; aGetCP : TwbGetConflictPriority); {---IwbDef---} function GetDefType: TwbDefType; override; function GetDefTypeName: string; override; function CanContainFormIDs: Boolean; override; {---IwbValueDef---} function ToString(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; override; function ToSortKey(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aExtended: Boolean): string; override; function GetSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; override; function GetDefaultSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; override; function GetCanBeZeroSize: Boolean; override; procedure FromEditValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: string); override; function GetIsEditable(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Boolean; override; {--- IwbEmptyDef ---} function GetSorted: Boolean; end; TwbIntegerDef = class(TwbValueDef, IwbIntegerDef, IwbInternalIntegerDef) private inType : TwbIntType; inFormater : IwbIntegerDefFormater; inDefault : Int64; protected constructor Clone(const aSource: TwbDef); override; constructor Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aName : string; const aIntType : TwbIntType; const aFormater : IwbIntegerDefFormater; aDontShow : TwbDontShowCallback; aAfterSet : TwbAfterSetCallback; aDefault : Int64; aGetCP : TwbGetConflictPriority; aTerminator : Boolean); {---IwbDef---} function GetDefType: TwbDefType; override; function GetDefTypeName: string; override; function CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; override; function Assign(const aTarget: IwbElement; aIndex: Integer; const aSource: IwbElement; aOnlySK: Boolean): IwbElement; override; function CanContainFormIDs: Boolean; override; procedure Report(const aParents: TwbDefPath); override; function GetNoReach: Boolean; override; {---IwbValueDef---} function ToString(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; override; function ToSortKey(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aExtended: Boolean): string; override; function Check(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; override; function GetSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; override; function GetDefaultSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; override; function GetLinksTo(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): IwbElement; override; procedure BuildRef(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement); override; function ToEditValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; override; procedure FromEditValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: string); override; function ToNativeValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Variant; override; procedure FromNativeValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: Variant); override; function GetIsEditable(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Boolean; override; function GetEditType(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): TwbEditType; override; function GetEditInfo(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; override; function SetToDefault(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Boolean; override; procedure MasterCountUpdated(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aOld, aNew: Byte); override; procedure MasterIndicesUpdated(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aOld, aNew: TBytes); override; procedure FindUsedMasters(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aMasters: PwbUsedMasters); override; function CompareExchangeFormID(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aOldFormID: Cardinal; aNewFormID: Cardinal): Boolean; override; {---IwbIntegerDef---} function ToInt(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Int64; procedure FromInt(aValue: Int64; aBasePtr, aEndPtr: Pointer; const aElement: IwbElement); function GetFormater(const aElement: IwbElement): IwbIntegerDefFormater; function GetFormaterCanChange: Boolean; function GetIntType: TwbIntType; function GetExpectedLength(aValue: Int64 = 0): Integer; {---IwbInternalIntegerDef---} procedure ReplaceFormater(const aFormater: IwbIntegerDefFormater); end; TwbFloatDef = class(TwbValueDef, IwbFloatDef) private fdDefault : Extended; fdScale : Extended; fdDigits : Integer; fdNormalizer : TwbFloatNormalizer; fdDouble : Boolean; protected constructor Clone(const aSource: TwbDef); override; {---IwbDef---} function GetDefType: TwbDefType; override; function GetDefTypeName: string; override; function CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; override; function CanContainFormIDs: Boolean; override; {---IwbValueDef---} function ToString(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; override; function ToSortKey(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aExtended: Boolean): string; override; function GetSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; override; function GetDefaultSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; override; function ToEditValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; override; procedure FromEditValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: string); override; function ToNativeValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Variant; override; procedure FromNativeValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: Variant); override; function GetIsEditable(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Boolean; override; function SetToDefault(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Boolean; override; function ToValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Extended; public constructor Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aName : string; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aScale : Extended; aDigits : Integer; aDontShow : TwbDontShowCallback; aNormalizer : TwbFloatNormalizer; aDefault : Extended; aGetCP : TwbGetConflictPriority; aDouble : Boolean; aTerminator : Boolean); end; TwbArrayDef = class(TwbValueDef, IwbArrayDef) private arCount : Integer; arCountCallback : TwbCountCallback; arElement : IwbValueDef; arLabels : array of string; arSorted : Boolean; arCanAddTo : Boolean; arTerminated : Boolean; protected constructor Clone(const aSource: TwbDef); override; constructor Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aName : string; const aElement : IwbValueDef; aCount : Integer; const aLabels : array of string; aSorted : Boolean; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aDontShow : TwbDontShowCallback; aGetCP : TwbGetConflictPriority; aCanAddTo : Boolean; aTerminator : Boolean; aTerminated : Boolean); overload; constructor Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aName : string; const aElement : IwbValueDef; aCountCallback : TwbCountCallback; const aLabels : array of string; aSorted : Boolean; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aDontShow : TwbDontShowCallback; aGetCP : TwbGetConflictPriority; aCanAddTo : Boolean; aTerminator : Boolean; aTerminated : Boolean); overload; {---IwbDef---} function GetDefType: TwbDefType; override; function GetDefTypeName: string; override; function CanContainFormIDs: Boolean; override; procedure Report(const aParents: TwbDefPath); override; {---IwbValueDef---} function GetSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; override; function GetDefaultSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; override; function ToString(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; override; function GetIsVariableSizeInternal: Boolean; override; function GetCanBeZeroSize: Boolean; override; function CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; override; {---IwbArrayDef---} function GetElement: IwbValueDef; function GetCount: Integer; function GetElementLabel(aIndex: Integer): string; function GetSorted: Boolean; function GetCanAddTo: Boolean; function GetCountCallBack: TwbCountCallback; function GetPrefixSize(aBasePtr: Pointer): Integer; function GetPrefixLength(aBasePtr: Pointer): Integer; function GetPrefixCount(aBasePtr: Pointer): Cardinal; procedure SetPrefixCount(aBasePtr: Pointer; aValue: Cardinal); end; TwbStructDef = class(TwbValueDef, IwbStructDef) private stMembers : array of IwbValueDef; stSortKey : array of Integer; stExSortKey : array of Integer; stElementMap : TDynCardinalArray; stCanContainFormIDs : Boolean; stOptionalFromElement : Integer; protected constructor Clone(const aSource: TwbDef); override; constructor Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aName : string; const aMembers : array of IwbValueDef; const aSortKey : array of Integer; const aExSortKey : array of Integer; {$IFDEF WIN32} const aElementMap : array of Cardinal; {$ENDIF WIN32} {$IFDEF WIN64} const aElementMap : array of UInt64; {$ENDIF WIN64} aOptionalFromElement : Integer; aDontShow : TwbDontShowCallback; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aGetCP : TwbGetConflictPriority); {---IwbDef---} function GetDefType: TwbDefType; override; function GetDefTypeName: string; override; function CanContainFormIDs: Boolean; override; procedure Report(const aParents: TwbDefPath); override; {---IwbValueDef---} function GetSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; override; function GetDefaultSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; override; function ToString(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; override; function ToSortKey(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aExtended: Boolean): string; override; function GetIsVariableSizeInternal: Boolean; override; function CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; override; function GetElementMap: TDynCardinalArray; override; {---IwbStructDef---} function GetMemberCount: Integer; function GetMember(aIndex: Integer): IwbValueDef; function GetMemberByName(const aName: string): IwbValueDef; function GetOptionalFromElement: Integer; end; TwbStructCDef = class(TwbStructDef, IwbStructCDef) private scSizeCallback : TwbSizeCallback; scGetChapterType : TwbGetChapterTypeCallback; scGetChapterTypeName : TwbGetChapterTypeNameCallback; scGetChapterName : TwbGetChapterNameCallback; protected constructor Clone(const aSource: TwbDef); override; constructor Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aName : string; const aMembers : array of IwbValueDef; const aSortKey : array of Integer; const aExSortKey : array of Integer; aOptionalFromElement : Integer; aDontShow : TwbDontShowCallback; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aSizeCallBack : TwbSizeCallback; aGetChapterType : TwbGetChapterTypeCallback; aGetChapterTypeName : TwbGetChapterTypeNameCallback; aGetChapterName : TwbGetChapterNameCallback; aGetCP : TwbGetConflictPriority); function GetDefType: TwbDefType; override; function GetDefTypeName: string; override; public function GetSizing(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement;var CompressedSize: Integer): Cardinal; virtual; function GetChapterType(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; virtual; function GetChapterTypeName(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): String; virtual; function GetChapterName(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): String; virtual; end; TwbStructZDef = class(TwbStructCDef, IwbStructZDef) end; TwbStructLZDef = class(TwbStructCDef, IwbStructLZDef) end; TwbIntegerDefFormater = class(TwbDef, IwbIntegerDefFormater) protected constructor Clone(const aSource: TwbDef); override; {---IwbDef---} function GetDefType: TwbDefType; override; function GetDefTypeName: string; override; {---IwbIntegerDefFormater---} function ToString(aInt: Int64; const aElement: IwbElement): string; reintroduce; virtual; abstract; function ToSortKey(aInt: Int64; const aElement: IwbElement): string; virtual; abstract; function Check(aInt: Int64; const aElement: IwbElement): string; virtual; procedure BuildRef(aInt: Int64; const aElement: IwbElement); virtual; function GetEditType(aInt: Int64; const aElement: IwbElement): TwbEditType; virtual; function GetEditInfo(aInt: Int64; const aElement: IwbElement): string; virtual; function ToEditValue(aInt: Int64; const aElement: IwbElement): string; virtual; function FromEditValue(const aValue: string; const aElement: IwbElement): Int64; virtual; function GetIsEditable(aInt: Int64; const aElement: IwbElement): Boolean; virtual; function GetLinksTo(aInt: Int64; const aElement: IwbElement): IwbElement; virtual; function CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; override; function MasterCountUpdated(aInt: Int64; aOld, aNew: Byte; const aElement: IwbElement): Int64; virtual; function MasterIndicesUpdated(aInt: Int64; const aOld, aNew: TBytes; const aElement: IwbElement): Int64; virtual; procedure FindUsedMasters(aInt: Int64; aMasters: PwbUsedMasters; const aElement: IwbElement); virtual; function CompareExchangeFormID(var aInt: Int64; aOldFormID: Cardinal; aNewFormID: Cardinal; const aElement: IwbElement): Boolean; virtual; function GetRequiresKey: Boolean; virtual; end; TwbIntegerDefFormaterUnion = class(TwbIntegerDefFormater, IwbIntegerDefFormaterUnion) private idfuDecider: TwbIntegerDefFormaterUnionDecider; idfuMembers: array of IwbIntegerDefFormater; protected constructor Clone(const aSource: TwbDef); override; constructor Create(aPriority : TwbConflictPriority; aRequired : Boolean; aGetCP : TwbGetConflictPriority; aDecider : TwbIntegerDefFormaterUnionDecider; const aMembers : array of IwbIntegerDefFormater); {---IwbDef---} function GetDefType: TwbDefType; override; function CanContainFormIDs: Boolean; override; procedure Report(const aParents: TwbDefPath); override; function GetNoReach: Boolean; override; {---IwbIntegerDefFormater---} function ToString(aInt: Int64; const aElement: IwbElement): string; override; function ToSortKey(aInt: Int64; const aElement: IwbElement): string; override; function Check(aInt: Int64; const aElement: IwbElement): string; override; procedure BuildRef(aInt: Int64; const aElement: IwbElement); override; function GetEditType(aInt: Int64; const aElement: IwbElement): TwbEditType; override; function GetEditInfo(aInt: Int64; const aElement: IwbElement): string; override; function ToEditValue(aInt: Int64; const aElement: IwbElement): string; override; function FromEditValue(const aValue: string; const aElement: IwbElement): Int64; override; function GetIsEditable(aInt: Int64; const aElement: IwbElement): Boolean; override; function GetLinksTo(aInt: Int64; const aElement: IwbElement): IwbElement; override; function CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; override; function MasterCountUpdated(aInt: Int64; aOld, aNew: Byte; const aElement: IwbElement): Int64; override; function MasterIndicesUpdated(aInt: Int64; const aOld, aNew: TBytes; const aElement: IwbElement): Int64; override; procedure FindUsedMasters(aInt: Int64; aMasters: PwbUsedMasters; const aElement: IwbElement); override; function CompareExchangeFormID(var aInt: Int64; aOldFormID: Cardinal; aNewFormID: Cardinal; const aElement: IwbElement): Boolean; override; {---IwbIntegerDefFormaterUnion---} function Decide(const aElement: IwbElement): IwbIntegerDefFormater; function GetMember(aIndex: Integer): IwbIntegerDefFormater; function GetMemberCount: Integer; property Members[aIndex: Integer]: IwbIntegerDefFormater read GetMember; property MemberCount: Integer read GetMemberCount; end; TwbDumpIntegerDefFormater = class(TwbIntegerDefFormater, IwbDumpIntegerDefFormater) protected function ToString(aInt: Int64; const aElement: IwbElement): string; override; function ToSortKey(aInt: Int64; const aElement: IwbElement): string; override; end; TwbFormID = class(TwbIntegerDefFormater, IwbFormID) protected FoundSignatures: TStringList; FoundNotAllowedReferences: TStringList; NotResolved: TStringList; constructor Clone(const aSource: TwbDef); override; function IsValid(const aSignature: TwbSignature): Boolean; virtual; function IsValidFlst(const aSignature: TwbSignature): Boolean; virtual; function CheckFlst(const aMainRecord: IwbMainRecord): Boolean; virtual; function IsValidMainRecord(const aMainRecord: IwbMainRecord): Boolean; virtual; function FindRecordForAVCode(aInt: Int64; const aElement: IwbElement): IwbMainRecord; {---IwbDef---} procedure Report(const aParents: TwbDefPath); override; {---IwbIntegerDefFormater---} function Check(aInt: Int64; const aElement: IwbElement): string; override; function ToString(aInt: Int64; const aElement: IwbElement): string; override; function ToSortKey(aInt: Int64; const aElement: IwbElement): string; override; procedure BuildRef(aInt: Int64; const aElement: IwbElement); override; function GetEditType(aInt: Int64; const aElement: IwbElement): TwbEditType; override; function GetEditInfo(aInt: Int64; const aElement: IwbElement): string; override; function ToEditValue(aInt: Int64; const aElement: IwbElement): string; override; function FromEditValue(const aValue: string; const aElement: IwbElement): Int64; override; function GetIsEditable(aInt: Int64; const aElement: IwbElement): Boolean; override; function GetLinksTo(aInt: Int64; const aElement: IwbElement): IwbElement; override; function CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; override; function CanContainFormIDs: Boolean; override; function MasterCountUpdated(aInt: Int64; aOld, aNew: Byte; const aElement: IwbElement): Int64; override; function MasterIndicesUpdated(aInt: Int64; const aOld, aNew: TBytes; const aElement: IwbElement): Int64; override; procedure FindUsedMasters(aInt: Int64; aMasters: PwbUsedMasters; const aElement: IwbElement); override; function CompareExchangeFormID(var aInt: Int64; aOldFormID: Cardinal; aNewFormID: Cardinal; const aElement: IwbElement): Boolean; override; {---IwbFormID---} function GetMainRecord(aInt: Int64; const aElement: IwbElement): IwbMainRecord; virtual; end; TwbRefID = class(TwbFormID, IwbRefID) protected {---IwbIntegerDefFormater---} function ToString(aInt: Int64; const aElement: IwbElement): string; override; procedure BuildRef(aInt: Int64; const aElement: IwbElement); override; end; TwbFormIDChecked = class(TwbFormID, IwbFormIDChecked) protected {private} fidcValidRefsArr : array of TwbSignature; fidcValidRefs : TStringList; fidcValidFlstRefsArr : array of TwbSignature; fidcValidFlstRefs : TStringList; fidcPersistent : Boolean; fidcNoReach : Boolean; protected constructor Clone(const aSource: TwbDef); override; constructor Create(const aValidRefs : array of TwbSignature; const aValidFlstRefs : array of TwbSignature; aPersistent : Boolean; aNoReach : Boolean = False); destructor Destroy; override; function IsValid(const aSignature: TwbSignature): Boolean; override; function IsValidFlst(const aSignature: TwbSignature): Boolean; override; function CheckFlst(const aMainRecord: IwbMainRecord): Boolean; override; function IsValidMainRecord(const aMainRecord: IwbMainRecord): Boolean; override; {---IwbDef---} procedure Report(const aParents: TwbDefPath); override; function GetNoReach: Boolean; override; {---IwbIntegerDefFormater---} function Check(aInt: Int64; const aElement: IwbElement): string; override; function FromEditValue(const aValue: string; const aElement: IwbElement): Int64; override; function CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; override; {---IwbFormIDChecked---} function GetSignature(aIndex: Integer): TwbSignature; function GetSignatureCount: Integer; end; TwbChar4 = class(TwbIntegerDefFormater, IwbChar4) protected constructor Clone(const aSource: TwbDef); override; {---IwbIntegerDefFormater---} function ToString(aInt: Int64; const aElement: IwbElement): string; override; function ToSortKey(aInt: Int64; const aElement: IwbElement): string; override; procedure BuildRef(aInt: Int64; const aElement: IwbElement); override; function CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; override; function GetLinksTo(aInt: Int64; const aElement: IwbElement): IwbElement; override; function ToEditValue(aInt: Int64; const aElement: IwbElement): string; override; function FromEditValue(const aValue: string; const aElement: IwbElement): Int64; override; function GetIsEditable(aInt: Int64; const aElement: IwbElement): Boolean; override; function CanContainFormIDs: Boolean; override; end; TwbStr4 = class(TwbIntegerDefFormater, IwbStr4) protected constructor Clone(const aSource: TwbDef); override; {---IwbIntegerDefFormater---} function ToString(aInt: Int64; const aElement: IwbElement): string; override; function ToSortKey(aInt: Int64; const aElement: IwbElement): string; override; function CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; override; function ToEditValue(aInt: Int64; const aElement: IwbElement): string; override; function FromEditValue(const aValue: string; const aElement: IwbElement): Int64; override; function GetIsEditable(aInt: Int64; const aElement: IwbElement): Boolean; override; function CanContainFormIDs: Boolean; override; end; TwbFlagsDef = class(TwbIntegerDefFormater, IwbFlagsDef) private flgBaseFlagsDef : IwbFlagsDef; flgNames : array of string; flgDontShows : array of TwbDontShowCallback; flgHasDontShows : Boolean; flgUnusedMask : Int64; flgIgnoreMask : Int64; flgUnknownIsUnused : Boolean; flgGetCPs : array of TwbGetConflictPriority; flgHasGetCPs : Boolean; flgFlagDefs : array of IwbFlagDef; UnknownFlags : array[0..63] of Integer; HasUnknownFlags : Boolean; protected constructor Clone(const aSource: TwbDef); override; constructor Create(const aBaseFlagsDef : IwbFlagsDef; const aNames : array of string; const aDontShows : array of TwbDontShowCallback; aUnknownIsUnused : Boolean; aIgnoreMask : Int64; const aGetCPs : array of TwbGetConflictPriority); {---IwbDef---} procedure Report(const aParents: TwbDefPath); override; function GetDefTypeName: string; override; {---IwbIntegerDefFormater---} function Check(aInt: Int64; const aElement: IwbElement): string; override; function ToString(aInt: Int64; const aElement: IwbElement): string; override; function ToSortKey(aInt: Int64; const aElement: IwbElement): string; override; function CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; override; function Assign(const aTarget: IwbElement; aIndex: Integer; const aSource: IwbElement; aOnlySK: Boolean): IwbElement; override; function CanContainFormIDs: Boolean; override; function GetEditType(aInt: Int64; const aElement: IwbElement): TwbEditType; override; function GetEditInfo(aInt: Int64; const aElement: IwbElement): string; override; function ToEditValue(aInt: Int64; const aElement: IwbElement): string; override; function FromEditValue(const aValue: string; const aElement: IwbElement): Int64; override; function GetIsEditable(aInt: Int64; const aElement: IwbElement): Boolean; override; function GetRequiresKey: Boolean; override; {---IwbFlagsDef---} function GetBaseFlagsDef: IwbFlagsDef; function GetFlag(aIndex: Integer): string; function GetFlagCount: Integer; function GetFlagIgnoreConflict(aIndex: Integer): Boolean; function GetFlagDontShow(const aElement: IwbElement; aIndex: Integer): Boolean; function GetFlagHasDontShow(aIndex: Integer): Boolean; procedure FlagGetCP(const aElement: IwbElement; aIndex: Integer; var aCP: TwbConflictPriority); function GetFlagHasGetCP(aIndex: Integer): Boolean; function GetFlagDef(aIndex : Integer): IwbFlagDef; end; TwbFlagDef = class(TwbValueDef, IwbFlagDef) private fdFlagIndex : Integer; protected constructor Clone(const aSource: TwbDef); override; constructor Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aName : string; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aDontShow : TwbDontShowCallback; aGetCP : TwbGetConflictPriority; aTerminator : Boolean; aFlagIndex : Integer); {---IwbDef---} function GetDefType: TwbDefType; override; function GetDefTypeName: string; override; function CanContainFormIDs: Boolean; override; function GetHasDontShow: Boolean; override; function GetDontShow(const aElement: IwbElement): Boolean; override; function GetConflictPriority(const aElement: IwbElement): TwbConflictPriority; override; function GetConflictPriorityCanChange: Boolean; override; function GetCanBeZeroSize: Boolean; override; {---IwbValueDef---} function ToString(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; override; function GetSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; override; function GetDefaultSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; override; {---IwbFlagDef---} function GetFlagsDef: IwbFlagsDef; function GetFlagIndex: Integer; end; PwbSparseName = ^TwbSparseName; TwbSparseName = record snIndex : Int64; snName : string; end; TwbEnumDef = class(TwbIntegerDefFormater, IwbEnumDef) private enNames : array of string; enSparseNames : array of TwbSparseName; enSparseNamesMap : array of PwbSparseName; enEditInfo : string; UnknownEnums: TStringList; protected constructor Clone(const aSource: TwbDef); override; constructor Create(const aNames : array of string; const aSparseNames : array of const); function FindSparseName(aSearchIndex: Int64; var Index: Integer): Boolean; function CanContainFormIDs: Boolean; override; {---IwbDef---} procedure Report(const aParents: TwbDefPath); override; function GetDefTypeName: string; override; {---IwbIntegerDefFormater---} function Check(aInt: Int64; const aElement: IwbElement): string; override; function ToString(aInt: Int64; const aElement: IwbElement): string; override; function ToSortKey(aInt: Int64; const aElement: IwbElement): string; override; function CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; override; function GetEditType(aInt: Int64; const aElement: IwbElement): TwbEditType; override; function GetEditInfo(aInt: Int64; const aElement: IwbElement): string; override; function ToEditValue(aInt: Int64; const aElement: IwbElement): string; override; function FromEditValue(const aValue: string; const aElement: IwbElement): Int64; override; function GetIsEditable(aInt: Int64; const aElement: IwbElement): Boolean; override; {---IwbEnumDef---} function GetName(aIndex: Integer): string; function GetNameCount: Integer; end; TwbKey2Data6EnumDef = class(TwbEnumDef, IwbKey2Data6EnumDef) protected {---IwbIntegerDefFormater---} function ToString(aInt: Int64; const aElement: IwbElement): string; override; function ToSortKey(aInt: Int64; const aElement: IwbElement): string; override; end; TwbData6Key2EnumDef = class(TwbEnumDef, IwbData6Key2EnumDef) protected {---IwbIntegerDefFormater---} function ToString(aInt: Int64; const aElement: IwbElement): string; override; function ToSortKey(aInt: Int64; const aElement: IwbElement): string; override; end; TwbDivDef = class(TwbIntegerDefFormater) private ddValue: Integer; protected constructor Clone(const aSource: TwbDef); override; constructor Create(aValue: Integer); function CanContainFormIDs: Boolean; override; {---IwbIntegerDefFormater---} function ToString(aInt: Int64; const aElement: IwbElement): string; override; function ToSortKey(aInt: Int64; const aElement: IwbElement): string; override; function CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; override; function ToEditValue(aInt: Int64; const aElement: IwbElement): string; override; function FromEditValue(const aValue: string; const aElement: IwbElement): Int64; override; function GetIsEditable(aInt: Int64; const aElement: IwbElement): Boolean; override; end; TwbMulDef = class(TwbIntegerDefFormater) private mdValue: Integer; protected constructor Clone(const aSource: TwbDef); override; constructor Create(aValue: Integer); function CanContainFormIDs: Boolean; override; {---IwbIntegerDefFormater---} function ToString(aInt: Int64; const aElement: IwbElement): string; override; function ToSortKey(aInt: Int64; const aElement: IwbElement): string; override; function CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; override; function ToEditValue(aInt: Int64; const aElement: IwbElement): string; override; function FromEditValue(const aValue: string; const aElement: IwbElement): Int64; override; function GetIsEditable(aInt: Int64; const aElement: IwbElement): Boolean; override; end; TwbCallbackDef = class(TwbIntegerDefFormater, IwbCallbackDef) private cdToStr: TwbIntToStrCallback; cdToInt: TwbStrToIntCallback; protected constructor Clone(const aSource: TwbDef); override; constructor Create(const aToStr : TwbIntToStrCallback; const aToInt : TwbStrToIntCallback); function CanContainFormIDs: Boolean; override; {---IwbIntegerDefFormater---} function Check(aInt: Int64; const aElement: IwbElement): string; override; function ToString(aInt: Int64; const aElement: IwbElement): string; override; function ToSortKey(aInt: Int64; const aElement: IwbElement): string; override; function CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; override; function GetEditType(aInt: Int64; const aElement: IwbElement): TwbEditType; override; function GetEditInfo(aInt: Int64; const aElement: IwbElement): string; override; function ToEditValue(aInt: Int64; const aElement: IwbElement): string; override; function FromEditValue(const aValue: string; const aElement: IwbElement): Int64; override; function GetIsEditable(aInt: Int64; const aElement: IwbElement): Boolean; override; {---IwbCallbackDef---} function GetCallback: TwbIntToStrCallback; end; function wbRecord(const aSignature : TwbSignature; const aName : string; const aMembers : array of IwbRecordMemberDef; aAllowUnordered : Boolean = False; aAddInfoCallback : TwbAddInfoCallback = nil; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil) : IwbRecordDef; begin Result := wbRecord(aSignature, aName, nil, aMembers, aAllowUnordered, aAddInfoCallback, aPriority, aRequired, aAfterLoad, aAfterSet); end; function wbRecord(const aSignature : TwbSignature; const aName : string; const aRecordFlags : IwbIntegerDefFormater; const aMembers : array of IwbRecordMemberDef; aAllowUnordered : Boolean = False; aAddInfoCallback : TwbAddInfoCallback = nil; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil) : IwbRecordDef; var Hash : Integer; Index : Integer; RDE : PwbRecordDefEntry; NewIndex : Integer; begin Hash := Cardinal(aSignature) mod RecordDefHashMapSize; Index := Pred(wbRecordDefHashMap[Hash]); if Index >= 0 then begin RDE := @wbRecordDefs[Index]; while Assigned(RDE) do begin if Cardinal(RDE.rdeSignature) = Cardinal(aSignature) then raise Exception.CreateFmt('Duplicated record definition for signature %s', [String(aSignature)]); if RDE.rdeNext >= 0 then RDE := @wbRecordDefs[RDE.rdeNext] else RDE := nil; end; end; Result := TwbRecordDef.Create(aPriority, aRequired, aSignature, aName, aRecordFlags, aMembers, aAllowUnordered, aAddInfoCallback, aAfterLoad, aAfterSet); NewIndex := Length(wbRecordDefs); SetLength(wbRecordDefs, Succ(NewIndex)); with wbRecordDefs[NewIndex] do begin rdeDef := Result; rdeSignature := aSignature; rdeHash := Hash; rdeNext := Index; end; wbRecordDefHashMap[Hash] := Succ(NewIndex); end; function wbSubRecord(const aSignature : TwbSignature; const aName : string; const aValue : IwbValueDef; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aSizeMatch : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; begin Result := TwbSubRecordDef.Create(aPriority, aRequired, aSignature, aName, aValue, aAfterLoad, aAfterSet, aSizeMatch, aDontShow, aGetCP); end; function wbSubRecord(const aSignatures : array of TwbSignature; const aName : string; const aValue : IwbValueDef; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet: TwbAfterSetCallback = nil; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aSizeMatch : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; begin Result := TwbSubRecordDef.Create(aPriority, aRequired, aSignatures, aName, aValue, aAfterLoad, aAfterSet, aSizeMatch, aDontShow, aGetCP); end; function wbString(const aSignature : TwbSignature; const aName : string = 'Unknown'; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; begin Result := wbSubRecord(aSignature, aName, wbString('', aSize, aPriority), nil, aAfterSet, aPriority, aRequired, False, aDontShow, aGetCP); end; function wbString(const aName : string = 'Unknown'; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbStringDef; overload; begin Result := TwbStringDef.Create(aPriority, aRequired, aName, aSize, nil, aAfterSet, aDontShow, aGetCP, False); end; function wbStringForward(const aSignature : TwbSignature; // When the editor can leave chars after the ending #0 const aName : string = 'Unknown'; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; begin Result := wbSubRecord(aSignature, aName, wbString(True, '', aSize, aPriority, aRequired, aDontShow, aAfterSet), nil, aAfterSet, aPriority, aRequired, False, aDontShow); end; function wbString( aForward : Boolean = False; const aName : string = 'Unknown'; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbStringDef; overload; begin Result := TwbStringDef.Create(aPriority, aRequired, aName, aSize, nil, aAfterSet, aDontShow, aGetCP, False, aForward); end; function wbStringT(const aSignature : TwbSignature; const aName : string = 'Unknown'; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; begin Result := wbSubRecord(aSignature, aName, wbStringT('', aSize, aPriority, aRequired, aDontShow, aAfterSet, aGetCP), nil, aAfterSet, aPriority, aRequired, False, aDontShow, aGetCP); end; function wbStringT(const aName : string = 'Unknown'; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbStringDef; overload; begin Result := TwbStringDef.Create(aPriority, aRequired, aName, aSize, nil, aAfterSet, aDontShow, aGetCP, True); end; function wbStringScript(const aSignature : TwbSignature; const aName : string; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; begin Result := wbSubRecord(aSignature, aName, wbStringScript('', aSize, aPriority), nil, aAfterSet, aPriority, aRequired, False, aDontShow, aGetCP); end; function wbStringScript(const aName : string; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbStringDef; overload; begin Result := TwbStringScriptDef.Create(aPriority, aRequired, aName, aSize, nil, aAfterSet, aDontShow, aGetCP, False); end; function wbStringLC(const aSignature : TwbSignature; const aName : string; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; begin Result := wbSubRecord(aSignature, aName, wbStringLC('', aSize, aPriority), nil, aAfterSet, aPriority, aRequired, False, aDontShow, aGetCP); end; function wbStringLC(const aName : string; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbStringDef; overload; begin Result := TwbStringLCDef.Create(aPriority, aRequired, aName, aSize, nil, aAfterSet, aDontShow, aGetCP, False); end; function wbStringKC(const aSignature : TwbSignature; const aName : string; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; begin Result := wbSubRecord(aSignature, aName, wbStringKC('', aSize, aPriority), nil, aAfterSet, aPriority, aRequired, False, aDontShow, aGetCP); end; function wbStringKC(const aName : string; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbStringDef; overload; begin Result := TwbStringKCDef.Create(aPriority, aRequired, aName, aSize, nil, aAfterSet, aDontShow, aGetCP, False); end; function wbLString(const aSignature : TwbSignature; const aName : string; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; begin Result := wbSubRecord(aSignature, aName, wbLString('', aSize, aPriority), nil, aAfterSet, aPriority, aRequired, False, aDontShow, aGetCP); end; function wbLString(const aName : string; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbStringDef; overload; begin Result := TwbLStringDef.Create(aPriority, aRequired, aName, aSize, nil, aAfterSet, aDontShow, aGetCP, False); end; function wbLStringKC(const aSignature : TwbSignature; const aName : string; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; begin Result := wbSubRecord(aSignature, aName, wbLStringKC('', aSize, aPriority), nil, aAfterSet, aPriority, aRequired, False, aDontShow, aGetCP); end; function wbLStringKC(const aName : string; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbStringDef; overload; begin Result := TwbLStringKCDef.Create(aPriority, aRequired, aName, aSize, nil, aAfterSet, aDontShow, aGetCP, False); end; function wbStringMgefCode(const aSignature : TwbSignature; const aName : string; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; begin Result := wbSubRecord(aSignature, aName, wbStringMgefCode('', aSize, aPriority), nil, aAfterSet, aPriority, aRequired, False, aDontShow, aGetCP); end; function wbStringMgefCode(const aName : string; aSize : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbStringDef; overload; begin Result := TwbStringMgefCodeDef.Create(aPriority, aRequired, aName, aSize, nil, aAfterSet, aDontShow, aGetCP, False); end; function wbLenString(const aSignature : TwbSignature; const aName : string; aPrefix : Integer = 4; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; begin Result := wbSubRecord(aSignature, aName, wbLenString('', aPrefix, aPriority), nil, nil, aPriority, aRequired, False, aDontShow, aGetCP); end; function wbLenString(const aName : string; aPrefix : Integer = 4; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbLenStringDef; overload; begin Result := TwbLenStringDef.Create(aPriority, aRequired, aName, aPrefix, nil, nil, aDontShow, aGetCP, False); end; function wbLenStringT(const aSignature : TwbSignature; const aName : string; aPrefix : Integer = 4; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; begin Result := wbSubRecord(aSignature, aName, wbLenStringT('', aPrefix, aPriority), nil, nil, aPriority, aRequired, False, aDontShow, aGetCP); end; function wbLenStringT(const aName : string; aPrefix : Integer = 4; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbLenStringDef; overload; begin Result := TwbLenStringDef.Create(aPriority, aRequired, aName, aPrefix, nil, nil, aDontShow, aGetCP, True); end; function wbUnion(const aSignature : TwbSignature; const aName : string; aDecider : TwbUnionDecider; const aMembers : array of IwbValueDef; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; begin Result := wbSubRecord(aSignature, aName, wbUnion('', aDecider, aMembers, aPriority), nil, nil, aPriority, aRequired, False, aDontShow, aGetCP); end; function wbUnion(const aName : string; aDecider : TwbUnionDecider; const aMembers : array of IwbValueDef; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbUnionDef; overload; begin Result := TwbUnionDef.Create(aPriority, aRequired, aName, aDecider, aMembers, aDontShow, aAfterSet, aGetCP); end; function wbByteArray(const aSignature : TwbSignature; const aName : string = 'Unknown'; aSize : Int64 = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aSizeMatch : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; begin Result := wbSubRecord(aSignature, aName, wbByteArray('', aSize, aPriority), nil, nil, aPriority, aRequired, aSizeMatch, aDontShow, aGetCP); end; function wbByteArray(const aName : string = 'Unknown'; aSize : Int64 = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbByteArrayDef; overload; begin Result := TwbByteArrayDef.Create(aPriority, aRequired, aName, aSize, aDontShow, nil, aGetCP, False); end; function wbByteArrayT(const aName : string = 'Unknown'; aSize : Int64 = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbByteArrayDef; overload; begin Result := TwbByteArrayDef.Create(aPriority, aRequired, aName, aSize, aDontShow, nil, aGetCP, True); end; function wbByteArray(const aName : string; aCountCallback : TwbCountCallback; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbByteArrayDef; overload; begin Result := TwbByteArrayDef.Create(aPriority, aRequired, aName, 0, aDontShow, aCountCallback, aGetCP, False); end; function wbUnknown(const aSignature : TwbSignature; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; begin Result := wbByteArray(aSignature, 'Unknown', 0, aPriority, aRequired, False, aDontShow, aGetCP); end; function wbUnknown(aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbByteArrayDef; begin Result := wbByteArray('Unknown', 0, aPriority, aRequired, aDontShow, aGetCP); end; function wbInteger(const aSignature : TwbSignature; const aName : string; const aIntType : TwbIntType; const aFormater : IwbIntegerDefFormater = nil; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aMatchSize : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aDefault : Int64 = 0; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; begin Result := wbSubRecord(aSignature, aName, wbInteger('', aIntType, aFormater, aPriority, False, nil, nil, aDefault), nil, aAfterSet, aPriority, aRequired, aMatchSize, aDontShow, aGetCP); end; function wbIntegerT(const aSignature : TwbSignature; const aName : string; const aIntType : TwbIntType; const aFormater : IwbIntegerDefFormater = nil; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aMatchSize : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aDefault : Int64 = 0; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; begin Result := wbSubRecord(aSignature, aName, wbIntegerT('', aIntType, aFormater, aPriority, False, nil, nil, aDefault), nil, aAfterSet, aPriority, aRequired, aMatchSize, aDontShow, aGetCP); end; function wbInteger(const aName : string; const aIntType : TwbIntType; const aFormater : IwbIntegerDefFormater = nil; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aDefault : Int64 = 0; aGetCP : TwbGetConflictPriority = nil) : IwbIntegerDef; overload; begin Result := TwbIntegerDef.Create(aPriority, aRequired, aName, aIntType, aFormater, aDontShow, aAfterSet, aDefault, aGetCP, False); end; function wbIntegerT(const aName : string; const aIntType : TwbIntType; const aFormater : IwbIntegerDefFormater = nil; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aDefault : Int64 = 0; aGetCP : TwbGetConflictPriority = nil) : IwbIntegerDef; overload; begin Result := TwbIntegerDef.Create(aPriority, aRequired, aName, aIntType, aFormater, aDontShow, aAfterSet, aDefault, aGetCP, True); end; function wbInteger(const aSignature : TwbSignature; const aName : string; const aIntType : TwbIntType; const aToStr : TwbIntToStrCallback; const aToInt : TwbStrToIntCallback = nil; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aDefault : Int64 = 0; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; var Callback: IwbIntegerDefFormater; begin if Assigned(aToStr) then Callback := wbCallback(aToStr, aToInt); Result := wbInteger(aSignature, aName, aIntType, Callback, aPriority, aRequired, False, aDontShow, aAfterSet, aDefault); end; function wbIntegerT(const aSignature : TwbSignature; const aName : string; const aIntType : TwbIntType; const aToStr : TwbIntToStrCallback; const aToInt : TwbStrToIntCallback = nil; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aDefault : Int64 = 0; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; var Callback: IwbIntegerDefFormater; begin if Assigned(aToStr) then Callback := wbCallback(aToStr, aToInt); Result := wbIntegerT(aSignature, aName, aIntType, Callback, aPriority, aRequired, False, aDontShow, aAfterSet, aDefault, aGetCP); end; function wbInteger(const aName : string; const aIntType : TwbIntType; const aToStr : TwbIntToStrCallback; const aToInt : TwbStrToIntCallback = nil; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aDefault : Int64 = 0; aGetCP : TwbGetConflictPriority = nil) : IwbIntegerDef; overload; var Callback: IwbIntegerDefFormater; begin if Assigned(aToStr) then Callback := wbCallback(aToStr, aToInt); Result := wbInteger(aName, aIntType, Callback, aPriority, aRequired, aDontShow, aAfterSet, aDefault); end; function wbIntegerT(const aName : string; const aIntType : TwbIntType; const aToStr : TwbIntToStrCallback; const aToInt : TwbStrToIntCallback = nil; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aDefault : Int64 = 0; aGetCP : TwbGetConflictPriority = nil) : IwbIntegerDef; overload; var Callback: IwbIntegerDefFormater; begin if Assigned(aToStr) then Callback := wbCallback(aToStr, aToInt); Result := wbIntegerT(aName, aIntType, Callback, aPriority, aRequired, aDontShow, aAfterSet, aDefault, aGetCP); end; function wbFloat(const aSignature : TwbSignature; const aName : string = 'Unknown'; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aScale : Extended = 1.0; aDigits : Integer = -1; aDontShow : TwbDontShowCallback = nil; aNormalizer : TwbFloatNormalizer = nil; aDefault : Extended = 0.0; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; begin Result := wbSubRecord(aSignature, aName, wbFloat('', aPriority, False, aScale, aDigits, nil, aNormalizer, aDefault, aGetCP), nil, nil, aPriority, aRequired, False, aDontShow, aGetCP); end; function wbDouble(const aSignature : TwbSignature; const aName : string = 'Unknown'; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aScale : Extended = 1.0; aDigits : Integer = -1; aDontShow : TwbDontShowCallback = nil; aNormalizer : TwbFloatNormalizer = nil; aDefault : Extended = 0.0; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; begin Result := wbSubRecord(aSignature, aName, wbDouble('', aPriority, False, aScale, aDigits, nil, aNormalizer, aDefault), nil, nil, aPriority, aRequired, False, aDontShow, aGetCP); end; function wbFloat(const aName : string = 'Unknown'; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aScale : Extended = 1.0; aDigits : Integer = -1; aDontShow : TwbDontShowCallback = nil; aNormalizer : TwbFloatNormalizer = nil; aDefault : Extended = 0.0; aGetCP : TwbGetConflictPriority = nil) : IwbFloatDef; overload; begin Result := TwbFloatDef.Create(aPriority, aRequired, aName, nil, nil, aScale, aDigits, aDontShow, aNormalizer, aDefault, aGetCP, False, False); end; function wbDouble(const aName : string = 'Unknown'; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aScale : Extended = 1.0; aDigits : Integer = -1; aDontShow : TwbDontShowCallback = nil; aNormalizer : TwbFloatNormalizer = nil; aDefault : Extended = 0.0; aGetCP : TwbGetConflictPriority = nil) : IwbFloatDef; overload; begin Result := TwbFloatDef.Create(aPriority, aRequired, aName, nil, nil, aScale, aDigits, aDontShow, aNormalizer, aDefault, aGetCP, True, False); end; function wbFloat(const aName : string; aPriority : TwbConflictPriority; aRequired : Boolean; aDontShow : TwbDontShowCallback; aAfterSet : TwbAfterSetCallback = nil; aNormalizer : TwbFloatNormalizer = nil; aDefault : Extended = 0.0; aGetCP : TwbGetConflictPriority = nil) : IwbFloatDef; overload; begin Result := TwbFloatDef.Create(aPriority, aRequired, aName, nil, aAfterSet, 1.0, -1, aDontShow, aNormalizer, aDefault, aGetCP, False, False); end; function wbDouble(const aName : string; aPriority : TwbConflictPriority; aRequired : Boolean; aDontShow : TwbDontShowCallback; aAfterSet : TwbAfterSetCallback = nil; aNormalizer : TwbFloatNormalizer = nil; aDefault : Extended = 0.0; aGetCP : TwbGetConflictPriority = nil) : IwbFloatDef; overload; begin Result := TwbFloatDef.Create(aPriority, aRequired, aName, nil, aAfterSet, 1.0, -1, aDontShow, aNormalizer, aDefault, aGetCP, True, False); end; function wbFloatT(const aSignature : TwbSignature; const aName : string = 'Unknown'; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aScale : Extended = 1.0; aDigits : Integer = -1; aDontShow : TwbDontShowCallback = nil; aNormalizer : TwbFloatNormalizer = nil; aDefault : Extended = 0.0; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; begin Result := wbSubRecord(aSignature, aName, wbFloatT('', aPriority, False, aScale, aDigits, nil, aNormalizer, aDefault), nil, nil, aPriority, aRequired, False, aDontShow, aGetCP); end; function wbDoubleT(const aSignature : TwbSignature; const aName : string = 'Unknown'; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aScale : Extended = 1.0; aDigits : Integer = -1; aDontShow : TwbDontShowCallback = nil; aNormalizer : TwbFloatNormalizer = nil; aDefault : Extended = 0.0; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; begin Result := wbSubRecord(aSignature, aName, wbDoubleT('', aPriority, False, aScale, aDigits, nil, aNormalizer, aDefault), nil, nil, aPriority, aRequired, False, aDontShow, aGetCP); end; function wbFloatT(const aName : string = 'Unknown'; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aScale : Extended = 1.0; aDigits : Integer = -1; aDontShow : TwbDontShowCallback = nil; aNormalizer : TwbFloatNormalizer = nil; aDefault : Extended = 0.0; aGetCP : TwbGetConflictPriority = nil) : IwbFloatDef; overload; begin Result := TwbFloatDef.Create(aPriority, aRequired, aName, nil, nil, aScale, aDigits, aDontShow, aNormalizer, aDefault, aGetCP, False, True); end; function wbDoubleT(const aName : string = 'Unknown'; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aScale : Extended = 1.0; aDigits : Integer = -1; aDontShow : TwbDontShowCallback = nil; aNormalizer : TwbFloatNormalizer = nil; aDefault : Extended = 0.0; aGetCP : TwbGetConflictPriority = nil) : IwbFloatDef; overload; begin Result := TwbFloatDef.Create(aPriority, aRequired, aName, nil, nil, aScale, aDigits, aDontShow, aNormalizer, aDefault, aGetCP, True, True); end; function wbFloatT(const aName : string; aPriority : TwbConflictPriority; aRequired : Boolean; aDontShow : TwbDontShowCallback; aAfterSet : TwbAfterSetCallback = nil; aNormalizer : TwbFloatNormalizer = nil; aDefault : Extended = 0.0; aGetCP : TwbGetConflictPriority = nil) : IwbFloatDef; overload; begin Result := TwbFloatDef.Create(aPriority, aRequired, aName, nil, aAfterSet, 1.0, -1, aDontShow, aNormalizer, aDefault, aGetCP, False, True); end; function wbDoubleT(const aName : string; aPriority : TwbConflictPriority; aRequired : Boolean; aDontShow : TwbDontShowCallback; aAfterSet : TwbAfterSetCallback = nil; aNormalizer : TwbFloatNormalizer = nil; aDefault : Extended = 0.0; aGetCP : TwbGetConflictPriority = nil) : IwbFloatDef; overload; begin Result := TwbFloatDef.Create(aPriority, aRequired, aName, nil, aAfterSet, 1.0, -1, aDontShow, aNormalizer, aDefault, aGetCP, True, True); end; {--- wbArray - list of identical elements -------------------------------------} function wbArray(const aSignature : TwbSignature; const aName : string; const aElement : IwbValueDef; aCount : Integer = 0; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; begin Result := wbSubRecord(aSignature, aName, wbArray('', aElement, aCount, aPriority), aAfterLoad, aAfterSet, aPriority, aRequired, False, aDontShow, aGetCP); end; function wbArray(const aName : string; const aElement : IwbValueDef; aCount : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; begin Result := TwbArrayDef.Create(aPriority, aRequired, aName, aElement, aCount, [], False, nil, nil, aDontShow, aGetCP, True, False, False); end; function wbArray(const aName : string; const aElement : IwbValueDef; aCount : Integer; aAfterLoad : TwbAfterLoadCallback; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; begin Result := TwbArrayDef.Create(aPriority, aRequired, aName, aElement, aCount, [], False, aAfterLoad, nil, aDontShow, aGetCP, True, False, False); end; function wbArrayPT(const aSignature : TwbSignature; const aName : string; const aElement : IwbValueDef; aCount : Integer = 0; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; begin Result := wbSubRecord(aSignature, aName, wbArrayPT('', aElement, aCount, aPriority), aAfterLoad, aAfterSet, aPriority, aRequired, False, aDontShow, aGetCP); end; function wbArrayPT(const aName : string; const aElement : IwbValueDef; aCount : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; begin Result := TwbArrayDef.Create(aPriority, aRequired, aName, aElement, aCount, [], False, nil, nil, aDontShow, aGetCP, True, True, False); end; function wbArrayPT(const aName : string; const aElement : IwbValueDef; aCount : Integer; aAfterLoad : TwbAfterLoadCallback; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; begin Result := TwbArrayDef.Create(aPriority, aRequired, aName, aElement, aCount, [], False, aAfterLoad, nil, aDontShow, aGetCP, True, True, False); end; function wbArrayT(const aName : string; const aElement : IwbValueDef; aCount : Integer; const aLabels : array of string; aAfterLoad : TwbAfterLoadCallback; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; begin Result := TwbArrayDef.Create(aPriority, aRequired, aName, aElement, aCount, aLabels, False, aAfterLoad, nil, aDontShow, aGetCP, True, True, True); end; function wbRArray(const aName : string; const aElement : IwbRecordMemberDef; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordArrayDef; overload; begin Result := TwbSubRecordArrayDef.Create(aPriority, aRequired, aName, aElement, False, aAfterLoad, aAfterSet, aDontShow, nil, aGetCP); end; function wbArray(const aSignature : TwbSignature; const aName : string; const aElement : IwbValueDef; const aLabels : array of string; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; begin Result := wbSubRecord(aSignature, aName, wbArray('', aElement, aLabels, aPriority), nil, nil, aPriority, aRequired, False, aDontShow, aGetCP); end; function wbArray(const aSignature : TwbSignature; const aName : string; const aElement : IwbValueDef; const aLabels : array of string; aCountCallback : TwbCountCallback; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; begin Result := wbSubRecord(aSignature, aName, wbArray('', aElement, aLabels, aCountCallback, aPriority), nil, nil, aPriority, aRequired, False, aDontShow, aGetCP); end; function wbArray(const aName : string; const aElement : IwbValueDef; const aLabels : array of string; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; begin Result := TwbArrayDef.Create(aPriority, aRequired, aName, aElement, Length(aLabels), aLabels, False, nil, nil, aDontShow, aGetCP, True, False, False); end; function wbArray(const aName : string; const aElement : IwbValueDef; const aLabels : array of string; aCountCallback : TwbCountCallback; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; begin Result := TwbArrayDef.Create(aPriority, aRequired, aName, aElement, aCountCallback, aLabels, False, nil, nil, aDontShow, aGetCP, True, False, False); end; function wbArray(const aName : string; const aElement : IwbValueDef; aCountCallback : TwbCountCallback; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; begin Result := TwbArrayDef.Create(aPriority, aRequired, aName, aElement, aCountCallback, [], False, nil, nil, aDontShow, aGetCP, True, False, False); end; function wbArrayPT(const aSignature : TwbSignature; const aName : string; const aElement : IwbValueDef; const aLabels : array of string; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; begin Result := wbSubRecord(aSignature, aName, wbArrayPT('', aElement, aLabels, aPriority), nil, nil, aPriority, aRequired, False, aDontShow, aGetCP); end; function wbArrayPT(const aSignature : TwbSignature; const aName : string; const aElement : IwbValueDef; const aLabels : array of string; aCountCallback : TwbCountCallback; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; begin Result := wbSubRecord(aSignature, aName, wbArrayPT('', aElement, aLabels, aCountCallback, aPriority), nil, nil, aPriority, aRequired, False, aDontShow, aGetCP); end; function wbArrayPT(const aName : string; const aElement : IwbValueDef; const aLabels : array of string; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; begin Result := TwbArrayDef.Create(aPriority, aRequired, aName, aElement, Length(aLabels), aLabels, False, nil, nil, aDontShow, aGetCP, True, True, False); end; function wbArrayPT(const aName : string; const aElement : IwbValueDef; const aLabels : array of string; aCountCallback : TwbCountCallback; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; begin Result := TwbArrayDef.Create(aPriority, aRequired, aName, aElement, aCountCallback, aLabels, False, nil, nil, aDontShow, aGetCP, True, True, False); end; function wbArrayT(const aName : string; const aElement : IwbValueDef; const aLabels : array of string; aCountCallback : TwbCountCallback; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; begin Result := TwbArrayDef.Create(aPriority, aRequired, aName, aElement, aCountCallback, aLabels, False, nil, nil, aDontShow, aGetCP, True, True, True); end; function wbArrayPT(const aName : string; const aElement : IwbValueDef; aCountCallback : TwbCountCallback; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; begin Result := TwbArrayDef.Create(aPriority, aRequired, aName, aElement, aCountCallback, [], False, nil, nil, aDontShow, aGetCP, True, True, False); end; {--- wbArrayS - list of identical elements - gets sorted ----------------------} function wbArrayS(const aSignature : TwbSignature; const aName : string; const aElement : IwbValueDef; aCount : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; begin Result := wbSubRecord(aSignature, aName, wbArrayS('', aElement, aCount, aPriority, False, aAfterLoad, aAfterSet), nil, nil, aPriority, aRequired, False, aDontShow, aGetCP); end; function wbArrayS(const aName : string; const aElement : IwbValueDef; aCount : Integer = 0; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aDontShow : TwbDontShowCallback = nil; aCanAddTo : Boolean = True; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; begin Result := TwbArrayDef.Create(aPriority, aRequired, aName, aElement, aCount, [], True, aAfterLoad, aAfterSet, aDontShow, aGetCP, aCanAddTo, False, False); end; function wbArrayS(const aName : string; const aElement : IwbValueDef; aCount : Integer; aAfterLoad : TwbAfterLoadCallback; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aAfterSet : TwbAfterSetCallback = nil; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; begin Result := TwbArrayDef.Create(aPriority, aRequired, aName, aElement, aCount, [], True, aAfterLoad, aAfterSet, aDontShow, aGetCP, True, False, False); end; function wbArrayS(const aName : string; const aElement : IwbValueDef; aCountCallback : TwbCountCallback; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; begin Result := TwbArrayDef.Create(aPriority, aRequired, aName, aElement, aCountCallback, [], True, aAfterLoad, aAfterSet, aDontShow, aGetCP, True, False, False); end; function wbArray(const aName : string; const aElement : IwbValueDef; aCountCallback : TwbCountCallback; aPriority : TwbConflictPriority; aRequired : Boolean; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; begin Result := TwbArrayDef.Create(aPriority, aRequired, aName, aElement, aCountCallback, [], False, aAfterLoad, aAfterSet, aDontShow, aGetCP, True, False, False); end; function wbRArrayS(const aName : string; const aElement : IwbRecordMemberDef; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aDontShow : TwbDontShowCallback = nil; aIsSorted : TwbIsSortedCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordArrayDef; overload; begin Result := TwbSubRecordArrayDef.Create(aPriority, aRequired, aName, aElement, True, aAfterLoad, aAfterSet, aDontShow, aIsSorted, aGetCP); end; function wbArrayS(const aSignature : TwbSignature; const aName : string; const aElement : IwbValueDef; const aLabels : array of string; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; begin Result := wbSubRecord(aSignature, aName, wbArrayS('', aElement, aLabels, aPriority, False, aAfterLoad), nil, nil, aPriority, aRequired, False, aDontShow, aGetCP); end; function wbArrayS(const aName : string; const aElement : IwbValueDef; const aLabels : array of string; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; begin Result := TwbArrayDef.Create(aPriority, aRequired, aName, aElement, Length(aLabels), aLabels, True, aAfterLoad, aAfterSet, aDontShow, aGetCP, True, False, False); end; {--- wbStruct - ordered list of members ----------------------------------------} function wbStructSK(const aSignature : TwbSignature; const aSortKey : array of Integer; const aName : string; const aMembers : array of IwbValueDef; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aOptionalFromElement : Integer = -1; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; begin Result := wbSubRecord(aSignature, aName, wbStructSK(aSortKey, '', aMembers, aPriority, False, nil, aOptionalFromElement), aAfterLoad, aAfterSet, aPriority, aRequired, False, aDontShow, aGetCP); end; function wbMultiStructSK(const aSignatures : array of TwbSignature; const aSortKey : array of Integer; const aName : string; const aMembers : array of IwbValueDef; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aOptionalFromElement : Integer = -1; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; begin Result := wbSubRecord(aSignatures, aName, wbStructSK(aSortKey, '', aMembers, aPriority, False, nil, aOptionalFromElement), aAfterLoad, aAfterSet, aPriority, aRequired, False, aDontShow, aGetCP); end; function wbStructSK(const aSortKey : array of Integer; const aName : string; const aMembers : array of IwbValueDef; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aOptionalFromElement : Integer = -1; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbStructDef; overload; begin Result := TwbStructDef.Create(aPriority, aRequired, aName, aMembers, aSortKey, [], [], aOptionalFromElement, aDontShow, aAfterLoad, aAfterSet, aGetCP); end; function wbStructSK(const aSortKey : array of Integer; const aName : string; const aMembers : array of IwbValueDef; {$IFDEF WIN32} const aElementMap : array of Cardinal; {$ENDIF WIN32} {$IFDEF WIN64} const aElementMap : array of UInt64; {$ENDIF WIN64} aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aOptionalFromElement : Integer = -1; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbStructDef; overload; begin Result := TwbStructDef.Create(aPriority, aRequired, aName, aMembers, aSortKey, [], aElementMap, aOptionalFromElement, aDontShow, aAfterLoad, aAfterSet, aGetCP); end; function wbStructExSK(const aSignature : TwbSignature; const aSortKey : array of Integer; const aExSortKey : array of Integer; const aName : string; const aMembers : array of IwbValueDef; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aOptionalFromElement : Integer = -1; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; begin Result := wbSubRecord(aSignature, aName, wbStructExSK(aSortKey, aExSortKey, '', aMembers, aPriority, False, nil, aOptionalFromElement), aAfterLoad, aAfterSet, aPriority, aRequired, False, aDontShow, aGetCP); end; function wbStructExSK(const aSortKey : array of Integer; const aExSortKey : array of Integer; const aName : string; const aMembers : array of IwbValueDef; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aOptionalFromElement : Integer = -1; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbStructDef; overload; begin Result := TwbStructDef.Create(aPriority, aRequired, aName, aMembers, aSortKey, aExSortKey, [], aOptionalFromElement, aDontShow, aAfterLoad, aAfterSet, aGetCP); end; function wbStruct(const aSignature : TwbSignature; const aName : string; const aMembers : array of IwbValueDef; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aOptionalFromElement : Integer = -1; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; begin Result := wbSubRecord(aSignature, aName, wbStruct('', aMembers, aPriority, False, nil, aOptionalFromElement), aAfterLoad, aAfterSet, aPriority, aRequired, False, aDontShow, aGetCP); end; function wbStruct(const aName : string; const aMembers : array of IwbValueDef; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aOptionalFromElement : Integer = -1; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbStructDef; overload; begin Result := TwbStructDef.Create(aPriority, aRequired, aName, aMembers, [], [], [], aOptionalFromElement, aDontShow, aAfterLoad, aAfterSet, aGetCP); end; function wbStructC(const aName : string; aSizing : TwbSizeCallback; aGetChapterType : TwbGetChapterTypeCallback; aGetChapterTypeName : TwbGetChapterTypeNameCallback; aGetChapterName : TwbGetChapterNameCallback; const aMembers : array of IwbValueDef; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aOptionalFromElement : Integer = -1; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbStructDef; overload; begin Result := TwbStructCDef.Create(aPriority, aRequired, aName, aMembers, [], [], aOptionalFromElement, aDontShow, aAfterLoad, aAfterSet, aSizing, aGetChapterType, aGetChapterTypeName, aGetChapterName, aGetCP); end; function wbStructZ(const aName : string; aSizing : TwbSizeCallback; aGetChapterType : TwbGetChapterTypeCallback; aGetChapterTypeName : TwbGetChapterTypeNameCallback; aGetChapterName : TwbGetChapterNameCallback; const aMembers : array of IwbValueDef; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aOptionalFromElement : Integer = -1; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbStructDef; overload; begin Result := TwbStructZDef.Create(aPriority, aRequired, aName, aMembers, [], [], aOptionalFromElement, aDontShow, aAfterLoad, aAfterSet, aSizing, aGetChapterType, aGetChapterTypeName, agetChapterName, aGetCP); end; function wbStructLZ(const aName : string; aSizing : TwbSizeCallback; aGetChapterType : TwbGetChapterTypeCallback; aGetChapterTypeName : TwbGetChapterTypeNameCallback; aGetChapterName : TwbGetChapterNameCallback; const aMembers : array of IwbValueDef; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aOptionalFromElement : Integer = -1; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbStructDef; overload; begin Result := TwbStructLZDef.Create(aPriority, aRequired, aName, aMembers, [], [], aOptionalFromElement, aDontShow, aAfterLoad, aAfterSet, aSizing, aGetChapterType, aGetChapterTypeName, agetChapterName, aGetCP); end; function wbRStruct(const aName : string; const aMembers : array of IwbRecordMemberDef; const aSkipSigs : array of TwbSignature; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAllowUnordered : Boolean = False; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordStructDef; overload; begin Result := TwbSubRecordStructDef.Create(aPriority, aRequired, aName, aMembers, aSkipSigs, aDontShow, aAllowUnordered, aAfterLoad, aAfterSet, aGetCP); end; function wbRStructSK(const aSortKey : array of Integer; const aName : string; const aMembers : array of IwbRecordMemberDef; const aSkipSigs : array of TwbSignature; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAllowUnordered : Boolean = False; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordStructDef; overload; begin Result := TwbSubRecordStructSKDef.Create(aPriority, aRequired, aName, aMembers, aSkipSigs, aSortKey, [], aDontShow, aAllowUnordered, aAfterLoad, aAfterSet, aGetCP); end; function wbRStructExSK(const aSortKey : array of Integer; const aExSortKey : array of Integer; const aName : string; const aMembers : array of IwbRecordMemberDef; const aSkipSigs : array of TwbSignature; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAllowUnordered : Boolean = False; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordStructDef; overload; begin Result := TwbSubRecordStructSKDef.Create(aPriority, aRequired, aName, aMembers, aSkipSigs, aSortKey, aExSortKey, aDontShow, aAllowUnordered, aAfterLoad, aAfterSet, aGetCP); end; function wbRUnion(const aName : string; const aMembers : array of IwbRecordMemberDef; const aSkipSigs : array of TwbSignature; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordUnionDef; overload; begin Result := TwbSubRecordUnionDef.Create(aPriority, aRequired, aName, aMembers, aSkipSigs, aDontShow, aGetCP); end; {--- wbStructS - array of struct ----------------------------------------------} function wbStructS(const aSignature : TwbSignature; const aName : string; const aElementName : string; const aMembers : array of IwbValueDef; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; begin Result := wbArray(aSignature, aName, wbStruct(aElementName, aMembers, aPriority), 0, nil, nil, aPriority, aRequired, aDontShow, aGetCP); end; function wbStructS(const aName : string; const aElementName : string; const aMembers : array of IwbValueDef; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbArrayDef; overload; begin Result := wbArray(aName, wbStruct(aElementName, aMembers, aPriority), 0, aPriority, aRequired, aDontShow, aGetCP); end; function wbRStructS(const aName : string; const aElementName : string; const aMembers : array of IwbRecordMemberDef; const aSkipSigs : array of TwbSignature; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordArrayDef; overload; begin Result := wbRArray(aName, wbRStruct(aElementName, aMembers, aSkipSigs ,aPriority), aPriority, aRequired, nil, nil, aDontShow, aGetCP); end; function wbRStructsSK(const aName : string; const aElementName : string; const aSortKey : array of Integer; const aMembers : array of IwbRecordMemberDef; const aSkipSigs : array of TwbSignature; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aAfterLoad : TwbAfterLoadCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordArrayDef; overload; begin Result := wbRArrayS(aName, wbRStructSK(aSortKey, aElementName, aMembers, aSkipSigs, aPriority), aPriority, aRequired, aAfterLoad, aAfterSet, aDontShow, nil, aGetCP); end; function wbEmpty(const aSignature : TwbSignature; const aName : string; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; begin Result := wbSubRecord(aSignature, aName, wbEmpty('', aPriority, aRequired), nil, nil, aPriority, aRequired, False, aDontShow, aGetCP); end; function wbEmpty(const aName : string; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aSorted : Boolean = False; aGetCP : TwbGetConflictPriority = nil) : IwbValueDef; begin Result := TwbEmptyDef.Create(aPriority, aRequired, aName, nil, nil, aDontShow, aSorted, aGetCP); end; function wbDumpInteger : IwbIntegerDefFormater; begin Result := TwbDumpIntegerDefFormater.Create(cpNormal, False, nil); end; function wbKey2Data6Enum(const aNames : array of string) : IwbKey2Data6EnumDef; begin Result := TwbKey2Data6EnumDef.Create(aNames, []); end; function wbData6Key2Enum(const aNames : array of string) : IwbData6Key2EnumDef; begin Result := TwbData6Key2EnumDef.Create(aNames, []); end; var _RefID: IwbRefID; function wbRefID: IwbRefID; begin if wbReportMode then Result := TwbRefID.Create(cpNormal, False, nil) else begin if not Assigned(_RefID) then _RefID := TwbRefID.Create(cpNormal, False, nil); Result := _RefID; end; end; function wbRefID(const aName : string; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbIntegerDef; overload; begin Result := wbInteger(aName, itU24, wbRefID, aPriority, aRequired, aDontShow, aAfterSet, 0, aGetCP); end; function wbRefIDT(const aName : string; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbIntegerDef; overload; begin Result := wbIntegerT(aName, itU24, wbRefID, aPriority, aRequired, aDontShow, aAfterSet, 0, aGetCP); end; var _FormID: IwbFormID; function wbFormID: IwbFormID; begin if wbReportMode then Result := TwbFormID.Create(cpNormal, False, nil) else begin if not Assigned(_FormID) then _FormID := TwbFormID.Create(cpNormal, False, nil); Result := _FormID; end; end; function wbFormID(const aValidRefs : array of TwbSignature; aPersistent: Boolean) : IwbFormID; begin Result := TwbFormIDChecked.Create(aValidRefs, [], aPersistent); end; function wbFormID(const aValidRefs : array of TwbSignature; const aValidFlstRefs : array of TwbSignature; aPersistent : Boolean) : IwbFormID; begin Result := TwbFormIDChecked.Create(aValidRefs, aValidFlstRefs, aPersistent); end; function wbFormIDNoReach(const aValidRefs : array of TwbSignature; aPersistent: Boolean) : IwbFormID; begin Result := TwbFormIDChecked.Create(aValidRefs, [], aPersistent, True); end; function wbFormIDNoReach(const aValidRefs : array of TwbSignature; const aValidFlstRefs : array of TwbSignature; aPersistent : Boolean) : IwbFormID; begin Result := TwbFormIDChecked.Create(aValidRefs, aValidFlstRefs, aPersistent, True); end; function wbChar4: IwbChar4; begin Result := TwbChar4.Create(cpNormal, False, nil); end; function wbStr4: IwbStr4; begin Result := TwbStr4.Create(cpNormal, False, nil); end; function wbFormID(const aSignature : TwbSignature; const aName : string = 'Unknown'; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; begin Result := wbInteger( aSignature, aName, itU32, wbFormID, aPriority, aRequired, False, aDontShow, nil, 0, aGetCP); end; function wbFormID(const aName : string; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil) : IwbIntegerDef; overload; begin Result := wbInteger(aName, itU32, wbFormID, aPriority, aRequired, aDontShow, aAfterSet); end; function wbFormIDT(const aName : string; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbIntegerDef; overload; begin Result := wbIntegerT(aName, itU32, wbFormID, aPriority, aRequired, aDontShow, aAfterSet, 0, aGetCP); end; function wbFormIDCk(const aSignature : TwbSignature; const aName : string; const aValidRefs : array of TwbSignature; aPersistent: Boolean = False; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; begin Result := wbInteger(aSignature, aName, itU32, wbFormID(aValidRefs, aPersistent), aPriority, aRequired, False, aDontShow, nil, 0, aGetCP); end; function wbFormIDCkNoReach(const aSignature : TwbSignature; const aName : string; const aValidRefs : array of TwbSignature; aPersistent: Boolean = False; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; begin Result := wbInteger(aSignature, aName, itU32, wbFormIDNoReach(aValidRefs, aPersistent), aPriority, aRequired, False, aDontShow, nil, 0, aGetCP); end; function wbFormIDCk(const aName : string; const aValidRefs : array of TwbSignature; aPersistent: Boolean = False; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aAfterSet : TwbAfterSetCallback = nil) : IwbIntegerDef; overload; begin Result := wbInteger(aName, itU32, wbFormID(aValidRefs, aPersistent), aPriority, aRequired, aDontShow, aAfterSet); end; function wbFormIDCkNoReach(const aName : string; const aValidRefs : array of TwbSignature; aPersistent: Boolean = False; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbIntegerDef; overload; begin Result := wbInteger(aName, itU32, wbFormIDNoReach(aValidRefs, aPersistent), aPriority, aRequired, aDontShow, nil, 0, aGetCP); end; function wbFormIDCk(const aSignature : TwbSignature; const aName : string; const aValidRefs : array of TwbSignature; const aValidFlstRefs : array of TwbSignature; aPersistent : Boolean = False; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbSubRecordDef; overload; begin Result := wbInteger(aSignature, aName, itU32, wbFormID(aValidRefs, aValidFlstRefs, aPersistent), aPriority, aRequired, False, aDontShow, nil, 0, aGetCP); end; function wbFormIDCk(const aName : string; const aValidRefs : array of TwbSignature; const aValidFlstRefs : array of TwbSignature; aPersistent : Boolean = False; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbIntegerDef; overload; begin Result := wbInteger(aName, itU32, wbFormID(aValidRefs, aValidFlstRefs, aPersistent), aPriority, aRequired, aDontShow, nil, 0, aGetCP); end; function wbFormIDCkNoReach(const aName : string; const aValidRefs : array of TwbSignature; const aValidFlstRefs : array of TwbSignature; aPersistent : Boolean = False; aPriority : TwbConflictPriority = cpNormal; aRequired : Boolean = False; aDontShow : TwbDontShowCallback = nil; aGetCP : TwbGetConflictPriority = nil) : IwbIntegerDef; overload; begin Result := wbInteger(aName, itU32, wbFormIDNoReach(aValidRefs, aValidFlstRefs, aPersistent), aPriority, aRequired, aDontShow, nil, 0, aGetCP); end; function wbFlags(const aNames : array of string; aUnknownIsUnused : Boolean = False) : IwbFlagsDef; begin Result := wbFlags(nil, aNames, aUnknownIsUnused); end; function wbFlags(const aNames : array of string; const aFlagsToIgnore : array of integer) : IwbFlagsDef; overload; begin Result := wbFlags(nil, aNames, aFlagsToIgnore); end; function wbFlags(const aNames : array of string; const aDontShows : array of TwbDontShowCallback; aUnknownIsUnused : Boolean = False) : IwbFlagsDef; overload; begin Result := wbFlags(nil, aNames, aDontShows, aUnknownIsUnused); end; function wbFlags(const aBaseFlagsDef : IwbFlagsDef; const aNames : array of string; aUnknownIsUnused : Boolean = False) : IwbFlagsDef; begin Result := TwbFlagsDef.Create(aBaseFlagsDef, aNames, [], aUnknownIsUnused, 0, []); end; function wbFlags(const aBaseFlagsDef : IwbFlagsDef; const aNames : array of string; const aFlagsToIgnore : array of integer) : IwbFlagsDef; overload; var IgnoreMask : Int64; i : Integer; Index : Int64; begin IgnoreMask := 0; for i := Low(aFlagsToIgnore) to High(aFlagsToIgnore) do begin Index := aFlagsToIgnore[i]; if (Index >= 0) and (Index <= High(aNames)) then IgnoreMask := IgnoreMask or (1 shl Index); end; Result := TwbFlagsDef.Create(aBaseFlagsDef, aNames, [], False, IgnoreMask, []); end; function wbFlags(const aBaseFlagsDef : IwbFlagsDef; const aNames : array of string; const aDontShows : array of TwbDontShowCallback; aUnknownIsUnused : Boolean = False) : IwbFlagsDef; overload; begin Result := TwbFlagsDef.Create(aBaseFlagsDef, aNames, aDontShows, aUnknownIsUnused, 0, []); end; function wbEnum(const aNames : array of string) : IwbEnumDef; begin Result := TwbEnumDef.Create(aNames, []); end; function wbEnum(const aNames : array of string; const aSparseNames : array of const) : IwbEnumDef; overload; begin Result := TwbEnumDef.Create(aNames, aSparseNames); end; function wbDiv(aValue : Integer) : IwbIntegerDefFormater; begin Result := TwbDivDef.Create(aValue); end; function wbMul(aValue : Integer) : IwbIntegerDefFormater; begin Result := TwbMulDef.Create(aValue); end; function wbCallback(const aToStr : TwbIntToStrCallback; const aToInt : TwbStrToIntCallback) : IwbIntegerDefFormater; begin Result := TwbCallbackDef.Create(aToStr, aToInt); end; function wbFormaterUnion(aDecider : TwbIntegerDefFormaterUnionDecider; aMembers : array of IwbIntegerDefFormater) : IwbIntegerDefFormaterUnion; begin Result := TwbIntegerDefFormaterUnion.Create(cpNormal, False, nil, aDecider, aMembers); end; { TwbDef } function TwbDef.Assign(const aTarget : IwbElement; aIndex : Integer; const aSource : IwbElement; aOnlySK : Boolean) : IwbElement; begin Result := nil; aTarget.SetEditValue(aSource.EditValue); end; function TwbDef.CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; begin Result := False; end; function TwbDef.CanContainFormIDs: Boolean; begin Result := True; end; constructor TwbDef.Clone(const aSource: TwbDef); begin with aSource do Self.Create(defPriority, defRequired, defGetCP).defSource := aSource; end; constructor TwbDef.Create(aPriority: TwbConflictPriority; aRequired: Boolean; aGetCP: TwbGetConflictPriority); begin defPriority := aPriority; defRequired := aRequired; defGetCP := aGetCP; inherited Create; end; function TwbDef.Duplicate: TwbDef; begin Result := TwbDefClass(ClassType).Clone(Self); end; function TwbDef.Equals(const aDef: IwbDef): Boolean; begin Result := Assigned(aDef) and (aDef.DefID = GetDefID); end; function TwbDef.GetConflictPriority(const aElement: IwbElement): TwbConflictPriority; begin Result := defPriority; if Assigned(defGetCP) then defGetCP(aElement, Result); end; function TwbDef.GetConflictPriorityCanChange: Boolean; begin Result := Assigned(defGetCP); end; function TwbDef.GetDefID: Cardinal; begin Result := Cardinal(Self); end; function TwbDef.GetDontShow(const aElement: IwbElement): Boolean; begin Result := False; end; function TwbDef.GetHasDontShow: Boolean; begin Result := False; end; function TwbDef.GetNoReach: Boolean; begin Result := False; end; function TwbDef.GetParent: IwbDef; begin Result := defParent; end; function TwbDef.GetRequired: Boolean; begin Result := defRequired; end; function TwbDef.GetRoot: IwbDef; begin Result := defSource; if not Assigned(Result) then Result := Self else Result := Result.GetRoot; end; function TwbDef.IsNotRequired: Boolean; begin Result := defNotRequired; end; procedure TwbDef.NotRequired; begin defNotRequired := True; end; procedure TwbDef.ParentSet; begin {can be overriden} end; procedure TwbDef.PossiblyRequired; begin defPossiblyRequired := True; end; procedure TwbDef.Report(const aParents: TwbDefPath); var i, j : Integer; sl : TStringList; begin if defReported then Exit; if wbReportUnused then if not defUsed then WriteLn('Unused: ', wbDefsToPath(aParents), wbDefToName(Self)); if wbReportRequired and defPossiblyRequired then if defNotRequired = defRequired then if defNotRequired then WriteLn('Not Required: ', wbDefsToPath(aParents), wbDefToName(Self)) else WriteLn('Required: ', wbDefsToPath(aParents), wbDefToName(Self)); if wbReportUnknown then if Assigned(UnknownValues) then begin WriteLn('Unknown Field: ', wbDefsToPath(aParents), wbDefToName(Self), ' (', UnknownValues.Count ,')'); for i := 0 to Pred(UnknownValues.Count) do begin sl := UnknownValues.Objects[i] as TStringList; WriteLn(' ', UnknownValues[i], ' (', sl.Count ,')'); for j := 0 to Pred(sl.Count) do WriteLn(' ', sl[j]); end; end else if IsUnknown then WriteLn('Unknown Field: ', wbDefsToPath(aParents), wbDefToName(Self)); defReported := True; end; function TwbDef.SetParent(const aParent: TwbDef; aForceDuplicate: Boolean): IwbDef; begin Assert(Assigned(aParent)); if Assigned(defParent) or aForceDuplicate then Result := Duplicate.SetParent(aParent, False) else begin Result := Self; defParent := aParent; ParentSet; end; end; procedure TwbDef.Used(const aElement: IwbElement; const s: string); var i: Integer; NamedDef: IwbNamedDef; begin if not wbReportMode then Exit; defUsed := True; if not IsUnknown then if not IsUnknownChecked then begin IsUnknownChecked := True; if Supports(defParent, IwbNamedDef, NamedDef) then if Pos('unknown', LowerCase(NamedDef.Name)) > 0 then IsUnknown := True; end; if wbReportUnknown then if IsUnknown and Assigned(aElement) and (s <> '') then begin if not Assigned(UnknownValues) then UnknownValues := TwbFastStringListCS.CreateSorted; if UnknownValues.Count < 20 then begin if not UnknownValues.Find(s, i) then i := UnknownValues.AddObject(s, TwbFastStringListCS.CreateSorted(dupIgnore)); with UnknownValues.Objects[i] as TStringList do if Count < 20 then Add(aElement.FullPath); end; end; end; { TwbNamedDef } procedure TwbNamedDef.AfterLoad(const aElement: IwbElement); begin Used(nil, ''); if Assigned(noAfterLoad) then noAfterLoad(aElement); end; procedure TwbNamedDef.AfterSet(const aElement: IwbElement; const aOldValue, aNewValue: Variant); begin if Assigned(noAfterSet) then noAfterSet(aElement, aOldValue, aNewValue); end; constructor TwbNamedDef.Clone(const aSource: TwbDef); begin with (aSource as TwbNamedDef) do begin Self.Create(defPriority, defRequired, noName, noAfterLoad, noAfterSet, noDontShow, defGetCP, noTerminator).defSource := aSource; Self.noTreeHead := GetTreeHead; Self.notreeBranch := GetTreeBranch; end end; constructor TwbNamedDef.Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aName : string; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aDontShow : TwbDontShowCallback; aGetCP : TwbGetConflictPriority; aTerminator : Boolean); begin noName := aName; noDontShow := aDontShow; noAfterLoad := aAfterLoad; noAfterSet := aAfterSet; noTerminator := aTerminator; noTreeHead := False; noTreeBranch := False; if aName = 'Unused' then begin noUnused := True; if aPriority = cpNormal then aPriority := cpIgnore; end; inherited Create(aPriority, aRequired, aGetCP); if Pos('unknown', LowerCase(aName)) > 0 then IsUnknown := True; end; function TwbNamedDef.GetDontShow(const aElement: IwbElement): Boolean; begin if Assigned(noDontShow) then Result := noDontShow(aElement) else Result := wbHideUnused and noUnused; end; function TwbNamedDef.GetHasDontShow: Boolean; begin Result := Assigned(noDontShow) or (wbHideUnused and noUnused); end; function TwbNamedDef.GetName: string; begin Result := noName; end; function TwbNamedDef.GetPath: string; var Parent: IwbDef; NamedDef: IwbNamedDef; begin Result := GetName; Parent := defParent; while Assigned(Parent) do begin if Supports(Parent, IwbNamedDef, NamedDef) then Result := NamedDef.Name + ' \ ' + Result else Result := Parent.DefTypeName + ' \ ' + Result; Parent := Parent.Parent; end; end; function TwbNamedDef.GetTreeBranch: Boolean; begin Result := noTreeBranch; end; function TwbNamedDef.GetTreeHead: Boolean; begin Result := noTreeHead; end; procedure TwbNamedDef.ParentSet; var Parent: IwbNamedDef; begin inherited; if not (IsUnknown or noUnused) and (noName = '') and Supports(defParent, IwbNamedDef, Parent) then begin IsUnknown := IsUnknown or (Pos('unknown', LowerCase(Parent.Name)) > 0); noUnused := noUnused or (Parent.Name = 'Unused'); end; end; procedure TwbNamedDef.SetTreeBranch(aValue: Boolean); begin noTreeBranch := avalue; end; procedure TwbNamedDef.SetTreeHead(aValue: Boolean); begin noTreeHead := aValue; end; { TwbSignatureDef } function TwbSignatureDef.CanHandle(aSignature : TwbSignature; const aDataContainer : IwbDataContainer) : Boolean; begin Result := aSignature = GetDefaultSignature; end; constructor TwbSignatureDef.Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aSignature : TwbSignature; const aName : string; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aDontShow : TwbDontShowCallback; aGetCP : TwbGetConflictPriority); begin SetLength(soSignatures, 1); soSignatures[0] := aSignature; inherited Create(aPriority, aRequired, aName, aAfterLoad, aAfterSet, aDontShow, aGetCP, False); end; constructor TwbSignatureDef.Clone(const aSource: TwbDef); begin with (aSource as TwbSignatureDef) do Self.Create(defPriority, defRequired, soSignatures, noName, noAfterLoad, noAfterSet, noDontShow, defGetCP).defSource := aSource; end; constructor TwbSignatureDef.Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aSignatures : array of TwbSignature; const aName : string; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aDontShow : TwbDontShowCallback; aGetCP : TwbGetConflictPriority); var i: Integer; begin Assert(Length(aSignatures) >= 1); SetLength(soSignatures, Length(aSignatures)); for i := Low(soSignatures) to High(soSignatures) do soSignatures[i] := aSignatures[i]; inherited Create(aPriority, aRequired, aName, aAfterLoad, aAfterSet, aDontShow, aGetCP, False); end; function TwbSignatureDef.GetDefaultSignature: TwbSignature; begin Result := soSignatures[0]; end; function TwbSignatureDef.GetSignatureCount: Integer; begin Result := Length(soSignatures); end; function TwbSignatureDef.GetSignatures(const aIndex: Integer): TwbSignature; begin Result := soSignatures[aIndex]; end; { TwbRecordDef } function TwbRecordDef.AdditionalInfoFor(const aMainRecord: IwbMainRecord): string; begin if (wbCopyIsRunning = 0) and Assigned(recAddInfoCallback) then Result := recAddInfoCallback(aMainRecord) else Result := ''; end; procedure TwbRecordDef.AfterLoad(const aElement: IwbElement); var Found : Boolean; Container : IwbContainerElementRef; Element : IwbElement; i, j : Integer; begin inherited; if wbReportMode and wbReportRequired and Supports(aElement, IwbContainerElementRef, Container) then begin for i := Low(recMembers) to High(recMembers) do if not recMembers[i].IsNotRequired then begin Found := False; for j := 0 to Pred(Container.ElementCount) do begin Element := Container.Elements[j]; if recMembers[i].Equals(Element.Def) or recMembers[i].Equals(Element.ValueDef) then begin Found := True; Break; end; end; recMembers[i].PossiblyRequired; if not Found then recMembers[i].NotRequired; end; end; end; function TwbRecordDef.AllowUnordered: Boolean; begin Result := recAllowUnordered; end; function TwbRecordDef.CanContainFormIDs: Boolean; begin Result := recCanContainFormIDs; end; constructor TwbRecordDef.Clone(const aSource: TwbDef); begin with aSource as TwbRecordDef do Self.Create(defPriority, defRequired, GetDefaultSignature, noName, recRecordFlags, recMembers, recAllowUnordered, recAddInfoCallback, noAfterLoad, noAfterSet).defSource := aSource; end; function TwbRecordDef.ContainsMemberFor(aSignature : TwbSignature; const aDataContainer : IwbDataContainer) : Boolean; var Dummy: Integer; begin Result := recSignatures.Find(aSignature, Dummy); end; constructor TwbRecordDef.Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aSignature : TwbSignature; const aName : string; const aRecordFlags : IwbIntegerDefFormater; const aMembers : array of IwbRecordMemberDef; aAllowUnordered : Boolean; aAddInfoCallback : TwbAddInfoCallback; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback); var i, j : Integer; Sig : TwbSignature; begin recRecordFlags := aRecordFlags; recQuickInitLimit := -1; recAllowUnordered := aAllowUnordered; recAddInfoCallback := aAddInfoCallback; if Assigned(recRecordFlags) and Assigned(wbRecordFlags) and Assigned(wbMainRecordHeader) then begin recRecordHeaderStruct := (wbMainRecordHeader as IwbDefInternal).SetParent(Self, True) as IwbStructDef; (recRecordHeaderStruct.MembersByName[wbRecordFlags.Name] as IwbInternalIntegerDef).ReplaceFormater(recRecordFlags); end; recSignatures := TwbFastStringListCS.CreateSorted(dupAccept); if aAllowUnordered then recSignatures.Duplicates := dupError; SetLength(recMembers, Length(aMembers)); for i := Low(recMembers) to High(recMembers) do begin recMembers[i] := (aMembers[i] as IwbDefInternal).SetParent(Self, False) as IwbRecordMemberDef; recCanContainFormIDs := recCanContainFormIDs or aMembers[i].CanContainFormIDs; for j := 0 to Pred(aMembers[i].SignatureCount) do begin Sig := aMembers[i].Signatures[j]; if (Sig = 'EDID') or (Sig = 'FULL') or ( (Sig = 'NAME') and ( (aSignature = 'REFR') or (aSignature = 'ACHR') or (aSignature = 'ACRE') or (aSignature = 'PGRE') or (aSignature = 'PMIS') or (aSignature = 'PARW') or {>>> Skyrim <<<} (aSignature = 'PBEA') or {>>> Skyrim <<<} (aSignature = 'PFLA') or {>>> Skyrim <<<} (aSignature = 'PCON') or {>>> Skyrim <<<} (aSignature = 'PBAR') or {>>> Skyrim <<<} (aSignature = 'PHZD') {>>> Skyrim <<<} ) ) then begin recQuickInitLimit := i; if Sig = 'EDID' then recContainsEditorID := True; end; try recSignatures.AddObject(Sig, Pointer(i) ); except on E: Exception do raise Exception.Create('Duplicate definition ' + Sig + ' in allow unordered record ' + aSignature); end; end; end; inherited Create(aPriority, aRequired, aSignature, aName, aAfterLoad, aAfterSet, nil, nil); end; function TwbRecordDef.GetMember(aIndex: Integer): IwbRecordMemberDef; begin Result := recMembers[aIndex]; end; function TwbRecordDef.GetMemberCount: Integer; begin Result := Length(recMembers); end; function TwbRecordDef.GetMemberFor(aSignature : TwbSignature; const aDataContainer : IwbDataContainer) : IwbRecordMemberDef; var i: Integer; begin if recSignatures.Find(aSignature, i) then Result := recMembers[Integer(recSignatures.Objects[i])] else Result := nil; end; function TwbRecordDef.GetMemberIndexFor(aSignature : TwbSignature; const aDataContainer : IwbDataContainer) : Integer; var i: Integer; begin if recSignatures.Find(aSignature, i) then Result := Integer(recSignatures.Objects[i]) else Result := -1; end; function TwbRecordDef.GetQuickInitLimit: Integer; begin Result := recQuickInitLimit; end; function TwbRecordDef.GetRecordHeaderStruct: IwbStructDef; begin if Assigned(recRecordHeaderStruct) then Result := recRecordHeaderStruct else Result := wbMainRecordHeader; end; function TwbRecordDef.GetSkipSignature(const aSignature: TwbSignature): Boolean; begin Result := False; end; procedure TwbRecordDef.Report(const aParents: TwbDefPath); var Parents : TwbDefPath; i : Integer; begin if defReported then Exit; inherited; Parents := aParents; SetLength(Parents, Succ(Length(Parents))); Parents[High(Parents)].Def := Self; for i := Low(recMembers) to High(recMembers) do if Assigned(recMembers[i]) then begin Parents[High(Parents)].Index := i; recMembers[i].Report(Parents); end; defReported := True; end; destructor TwbRecordDef.Destroy; begin inherited; FreeAndNil(recSignatures); end; function TwbRecordDef.GetContainsEditorID: Boolean; begin Result := recContainsEditorID; end; function TwbRecordDef.GetDefType: TwbDefType; begin Result := dtRecord; end; function TwbRecordDef.GetDefTypeName: string; begin Result := 'Record'; end; { TwbSubRecordDef } function TwbSubRecordDef.CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; var SubRecordDef : IwbSubRecordDef; begin if Supports(aDef, IwbSubRecordDef, SubRecordDef) then Result := Equals(aDef) or Assigned(srValue) and srValue.CanAssign(aElement, aIndex, SubRecordDef.Value) else Result := Assigned(srValue) and srValue.CanAssign(aElement, aIndex, aDef); end; function TwbSubRecordDef.CanContainFormIDs: Boolean; begin Result := srValue.CanContainFormIDs; end; function TwbSubRecordDef.CanHandle(aSignature : TwbSignature; const aDataContainer : IwbDataContainer) : Boolean; begin Result := inherited CanHandle(aSignature, aDataContainer); if Result and srSizeMatch and Assigned(aDataContainer) and Assigned(srValue) then Result := aDataContainer.DataSize = srValue.DefaultSize[nil, nil, nil]; end; constructor TwbSubRecordDef.Clone(const aSource: TwbDef); begin with aSource as TwbSubRecordDef do Self.Create(defPriority, defRequired, soSignatures, noName, srValue, noAfterLoad, noAfterSet, srSizeMatch, noDontShow, defGetCP).defSource := aSource; end; constructor TwbSubRecordDef.Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aSignature : TwbSignature; const aName : string; const aValue : IwbValueDef; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aSizeMatch : Boolean; aDontShow : TwbDontShowCallback; aGetCP : TwbGetConflictPriority); begin srSizeMatch := aSizeMatch; if Assigned(aValue) then srValue := (aValue as IwbDefInternal).SetParent(Self, False) as IwbValueDef; inherited Create(aPriority, aRequired, aSignature, aName, aAfterLoad, aAfterSet, aDontShow, aGetCP); end; constructor TwbSubRecordDef.Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aSignatures : array of TwbSignature; const aName : string; const aValue : IwbValueDef; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aSizeMatch : Boolean; aDontShow : TwbDontShowCallback; aGetCP : TwbGetConflictPriority); begin srSizeMatch := aSizeMatch; if Assigned(aValue) then srValue := (aValue as IwbDefInternal).SetParent(Self, False) as IwbValueDef; inherited Create(aPriority, aRequired, aSignatures, aName, aAfterLoad, aAfterSet, aDontShow, aGetCP); end; function TwbSubRecordDef.GetDefType: TwbDefType; begin Result := dtSubRecord; end; function TwbSubRecordDef.GetDefTypeName: string; begin Result := 'SubRecord of '+GetValue.GetDefTypeName; end; function TwbSubRecordDef.GetValue: IwbValueDef; begin Result := srValue; end; procedure TwbSubRecordDef.HasUnusedData; begin srHasUnusedData := True; end; procedure TwbSubRecordDef.Report(const aParents: TwbDefPath); var Parents : TwbDefPath; begin if defReported then Exit; inherited; if Assigned(srValue) then begin Parents := aParents; SetLength(Parents, Succ(Length(Parents))); Parents[High(Parents)].Def := Self; Parents[High(Parents)].Index := -1; srValue.Report(Parents); end; if wbReportUnusedData then if srHasUnusedData then WriteLn('Has Unused Data: ', wbDefsToPath(aParents), wbDefToName(Self)); defReported := True; end; { TwbSubRecordArrayDef } procedure TwbSubRecordArrayDef.AfterLoad(const aElement: IwbElement); var Container: IwbContainerElementRef; begin inherited; if wbReportMode and wbReportRequired and Supports(aElement, IwbContainerElementRef, Container) then begin sraElement.PossiblyRequired; if Container.ElementCount < 1 then sraElement.NotRequired; end; end; function TwbSubRecordArrayDef.CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; var SubRecordArrayDef : IwbSubRecordArrayDef; begin if aIndex = Low(Integer) then Result := Supports(aDef, IwbSubRecordArrayDef, SubRecordArrayDef) and GetElement.CanAssign(aElement, aIndex, SubRecordArrayDef.Element) else if aIndex = High(Integer) then Result := GetElement.CanAssign(aElement, Low(Integer), aDef) else Result := False; end; function TwbSubRecordArrayDef.CanContainFormIDs: Boolean; begin Result := sraElement.CanContainFormIDs; end; function TwbSubRecordArrayDef.CanHandle(aSignature : TwbSignature; const aDataContainer : IwbDataContainer) : Boolean; begin Result := sraElement.CanHandle(aSignature, aDataContainer); end; constructor TwbSubRecordArrayDef.Clone(const aSource: TwbDef); begin with aSource as TwbSubRecordArrayDef do Self.Create(defPriority, defRequired, noName, sraElement, sraSorted, noAfterLoad, noAfterSet, noDontShow, sraIsSorted, defGetCP).defSource := aSource; end; constructor TwbSubRecordArrayDef.Create(aPriority : TwbConflictPriority; aRequired: Boolean; const aName : string; const aElement : IwbRecordMemberDef; aSorted : Boolean; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aDontShow : TwbDontShowCallback; aIsSorted : TwbIsSortedCallback; aGetCP : TwbGetConflictPriority); begin if Assigned(aElement) then sraElement := (aElement as IwbDefInternal).SetParent(Self, False) as IwbRecordMemberDef; sraSorted := aSorted; sraIsSorted := aIsSorted; inherited Create(aPriority, aRequired, aName, aAfterLoad, aAfterSet, aDontShow, aGetCP, False); end; function TwbSubRecordArrayDef.GetElement: IwbRecordMemberDef; begin Result := sraElement; end; function TwbSubRecordArrayDef.GetDefaultSignature: TwbSignature; begin Result := sraElement.GetDefaultSignature; end; function TwbSubRecordArrayDef.GetSignatureCount: Integer; begin Result := sraElement.GetSignatureCount; end; function TwbSubRecordArrayDef.GetSignatures(const aIndex: Integer): TwbSignature; begin Result := sraElement.GetSignatures(aIndex); end; function TwbSubRecordArrayDef.GetSorted(const aContainer: IwbContainer): Boolean; begin if Assigned(sraIsSorted) then Result := sraIsSorted(aContainer) else Result := sraSorted; end; procedure TwbSubRecordArrayDef.Report(const aParents: TwbDefPath); var Parents : TwbDefPath; begin if defReported then Exit; inherited; if Assigned(sraElement) then begin Parents := aParents; SetLength(Parents, Succ(Length(Parents))); Parents[High(Parents)].Def := Self; Parents[High(Parents)].Index := -1; sraElement.Report(Parents); end; defReported := True; end; function TwbSubRecordArrayDef.GetDefType: TwbDefType; begin Result := dtSubRecordArray; end; function TwbSubRecordArrayDef.GetDefTypeName: string; begin Result := 'SubRecordArray of '+GetElement.GetDefTypeName; end; { TwbSubRecordStructDef } function TwbSubRecordStructDef.AdditionalInfoFor(const aMainRecord: IwbMainRecord): string; begin Result := ''; end; procedure TwbSubRecordStructDef.AfterLoad(const aElement: IwbElement); var Found : Boolean; Container : IwbContainerElementRef; Element : IwbElement; i, j : Integer; begin inherited; if wbReportMode and wbReportRequired and Supports(aElement, IwbContainerElementRef, Container) then begin for i := 1 to High(srsMembers) do if not srsMembers[i].IsNotRequired then begin Found := False; for j := 0 to Pred(Container.ElementCount) do begin Element := Container.Elements[j]; if srsMembers[i].Equals(Element.Def) or srsMembers[i].Equals(Element.ValueDef) then begin Found := True; Break; end; end; srsMembers[i].PossiblyRequired; if not Found then srsMembers[i].NotRequired; end; end; end; function TwbSubRecordStructDef.AllowUnordered: Boolean; begin Result := srsAllowUnordered; end; function TwbSubRecordStructDef.CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; var SubRecordStructDef : IwbSubRecordStructDef; RecordDef : IwbRecordDef; i : Integer; begin if Supports(aDef, IwbSubRecordStructDef, SubRecordStructDef) then begin Result := Equals(aDef); if not Result and Supports(aDef, IwbRecordDef, RecordDef) and (GetMemberCount = RecordDef.MemberCount)then begin Result := True; for i := 0 to Pred(GetMemberCount) do if not srsMembers[i].CanAssign(aElement, aIndex, RecordDef.Members[i]) then begin Result := False; Break; end; end; end else Result := False; end; function TwbSubRecordStructDef.CanContainFormIDs: Boolean; begin Result := srsCanContainFormIDs; end; function TwbSubRecordStructDef.CanHandle(aSignature : TwbSignature; const aDataContainer : IwbDataContainer) : Boolean; begin if srsAllowUnordered then Result := ContainsMemberFor(aSignature, aDataContainer) else Result := srsMembers[0].CanHandle(aSignature, aDataContainer); end; constructor TwbSubRecordStructDef.Clone(const aSource: TwbDef); var SkipSigs : array of TwbSignature; i : Integer; begin with aSource as TwbSubRecordStructDef do begin if Assigned(srsSkipSignatures) then begin SetLength(SkipSigs, srsSkipSignatures.Count); for i := 0 to Pred(srsSkipSignatures.Count) do SkipSigs[i] := StrToSignature(srsSkipSignatures[i]); end; Self.Create(defPriority, defRequired, noName, srsMembers, SkipSigs, noDontShow, srsAllowUnordered, noAfterLoad, noAfterSet, defGetCP).defSource := aSource; end; end; function TwbSubRecordStructDef.ContainsMemberFor(aSignature : TwbSignature; const aDataContainer : IwbDataContainer) : Boolean; var Dummy: Integer; begin Result := srsSignatures.Find(aSignature, Dummy); end; constructor TwbSubRecordStructDef.Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aName : string; const aMembers : array of IwbRecordMemberDef; const aSkipSigs : array of TwbSignature; aDontShow : TwbDontShowCallback; aAllowUnordered : Boolean; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aGetCP : TwbGetConflictPriority); var i,j: Integer; FoundRequired : Boolean; begin srsAllowUnordered := aAllowUnordered; srsSignatures := TwbFastStringListCS.CreateSorted(dupIgnore); FoundRequired := False; SetLength(srsMembers, Length(aMembers)); for i := Low(srsMembers) to High(srsMembers) do begin srsMembers[i] := (aMembers[i] as IwbDefInternal).SetParent(Self, False) as IwbRecordMemberDef; srsCanContainFormIDs := srsCanContainFormIDs or aMembers[i].CanContainFormIDs; FoundRequired := FoundRequired or srsMembers[i].Required; for j := 0 to Pred(aMembers[i].SignatureCount) do srsSignatures.AddObject(aMembers[i].Signatures[j], Pointer(i) ); end; if Length(aSkipSigs) > 0 then begin srsSkipSignatures := TwbFastStringListCS.CreateSorted(dupIgnore); for i := Low(aSkipSigs) to High(aSkipSigs) do srsSkipSignatures.Add(aSkipSigs[i]); end; inherited Create(aPriority, aRequired, aName, aAfterLoad, aAfterSet, aDontShow, aGetCP, False); if srsAllowUnordered and not FoundRequired then raise Exception.Create(GetPath + ' must contain at least one required element'); end; destructor TwbSubRecordStructDef.Destroy; begin inherited; FreeAndNil(srsSignatures); FreeAndNil(srsSkipSignatures); end; function TwbSubRecordStructDef.GetDefType: TwbDefType; begin Result := dtSubRecordStruct; end; function TwbSubRecordStructDef.GetDefTypeName: string; begin Result := 'SubRecordStruct'; end; function TwbSubRecordStructDef.GetMember(aIndex: Integer): IwbRecordMemberDef; begin Result := srsMembers[aIndex]; end; function TwbSubRecordStructDef.GetMemberCount: Integer; begin Result := Length(srsMembers); end; function TwbSubRecordStructDef.GetMemberFor(aSignature : TwbSignature; const aDataContainer : IwbDataContainer) : IwbRecordMemberDef; var i: Integer; begin if srsSignatures.Find(aSignature, i) then Result := srsMembers[Integer(srsSignatures.Objects[i])] else Result := nil; end; function TwbSubRecordStructDef.GetMemberIndexFor(aSignature : TwbSignature; const aDataContainer : IwbDataContainer) : Integer; var i: Integer; begin if srsSignatures.Find(aSignature, i) then Result := Integer(srsSignatures.Objects[i]) else Result := -1; end; function TwbSubRecordStructDef.GetQuickInitLimit: Integer; begin Result := -1; end; function TwbSubRecordStructDef.GetRecordHeaderStruct: IwbStructDef; begin Result := wbMainRecordHeader; end; function TwbSubRecordStructDef.GetContainsEditorID: Boolean; begin Result := False; end; function TwbSubRecordStructDef.GetDefaultSignature: TwbSignature; begin Result := srsMembers[0].GetDefaultSignature; end; function TwbSubRecordStructDef.GetSignatureCount: Integer; begin if srsAllowUnordered then Result := srsSignatures.Count else Result := srsMembers[0].GetSignatureCount; end; function TwbSubRecordStructDef.GetSignatures(const aIndex: Integer): TwbSignature; begin if srsAllowUnordered then Result := StrToSignature(srsSignatures[aIndex]) else Result := srsMembers[0].GetSignatures(aIndex); end; function TwbSubRecordStructDef.GetSkipSignature(const aSignature: TwbSignature): Boolean; var Dummy: Integer; begin Result := Assigned(srsSkipSignatures) and srsSkipSignatures.Find(aSignature, Dummy); end; procedure TwbSubRecordStructDef.Report(const aParents: TwbDefPath); var Parents : TwbDefPath; i : Integer; begin if defReported then Exit; inherited; Parents := aParents; SetLength(Parents, Succ(Length(Parents))); Parents[High(Parents)].Def := Self; for i := Low(srsMembers) to High(srsMembers) do if Assigned(srsMembers[i]) then begin Parents[High(Parents)].Index := i; srsMembers[i].Report(Parents); end; defReported := True; end; { TwbSubRecordUnionDef } function TwbSubRecordUnionDef.AdditionalInfoFor(const aMainRecord: IwbMainRecord): string; begin Result := ''; end; function TwbSubRecordUnionDef.AllowUnordered: Boolean; begin Result := True; end; function TwbSubRecordUnionDef.CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; var SubRecordUnionDef : IwbSubRecordUnionDef; RecordDef : IwbRecordDef; i : Integer; begin for i := Low(sruMembers) to High(sruMembers) do begin Result := sruMembers[i].CanAssign(aElement, aIndex, aDef); if Result = True then Exit; end; if Supports(aDef, IwbSubRecordUnionDef, SubRecordUnionDef) then begin Result := Equals(aDef); if not Result and Supports(aDef, IwbRecordDef, RecordDef) and (GetMemberCount = RecordDef.MemberCount)then begin Result := True; for i := 0 to Pred(GetMemberCount) do if not sruMembers[i].CanAssign(aElement, aIndex, RecordDef.Members[i]) then begin Result := False; Break; end; end; end else Result := False; end; function TwbSubRecordUnionDef.CanContainFormIDs: Boolean; begin Result := sruCanContainFormIDs; end; function TwbSubRecordUnionDef.CanHandle(aSignature : TwbSignature; const aDataContainer : IwbDataContainer) : Boolean; var i: Integer; begin Result := False; for i := Low(sruMembers) to High(sruMembers) do begin Result := sruMembers[i].CanHandle(aSignature, aDataContainer); if Result then Exit; end; end; constructor TwbSubRecordUnionDef.Clone(const aSource: TwbDef); var SkipSigs : array of TwbSignature; i : Integer; begin with aSource as TwbSubRecordUnionDef do begin if Assigned(sruSkipSignatures) then begin SetLength(SkipSigs, sruSkipSignatures.Count); for i := 0 to Pred(sruSkipSignatures.Count) do SkipSigs[i] := StrToSignature(sruSkipSignatures[i]); end; Self.Create(defPriority, defRequired, noName, sruMembers, SkipSigs, noDontShow, defGetCP).defSource := aSource; end; end; function TwbSubRecordUnionDef.ContainsMemberFor(aSignature : TwbSignature; const aDataContainer : IwbDataContainer) : Boolean; begin Result := CanHandle(aSignature, aDataContainer); end; constructor TwbSubRecordUnionDef.Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aName : string; const aMembers : array of IwbRecordMemberDef; const aSkipSigs : array of TwbSignature; aDontShow : TwbDontShowCallback; aGetCP : TwbGetConflictPriority); var i,j: Integer; begin sruSignatures := TwbFastStringListCS.CreateSorted(dupIgnore); SetLength(sruMembers, Length(aMembers)); for i := Low(sruMembers) to High(sruMembers) do begin sruMembers[i] := (aMembers[i] as IwbDefInternal).SetParent(Self, False) as IwbRecordMemberDef; sruCanContainFormIDs := sruCanContainFormIDs or aMembers[i].CanContainFormIDs; for j := 0 to Pred(aMembers[i].SignatureCount) do sruSignatures.AddObject(aMembers[i].Signatures[j], Pointer(i)); end; if Length(aSkipSigs) > 0 then begin sruSkipSignatures := TwbFastStringListCS.CreateSorted(dupIgnore); for i := Low(aSkipSigs) to High(aSkipSigs) do sruSkipSignatures.Add(aSkipSigs[i]); end; inherited Create(aPriority, aRequired, aName, nil, nil, aDontShow, aGetCP, False); end; destructor TwbSubRecordUnionDef.Destroy; begin inherited; FreeAndNil(sruSignatures); end; function TwbSubRecordUnionDef.GetContainsEditorID: Boolean; begin Result := False; end; function TwbSubRecordUnionDef.GetDefaultSignature: TwbSignature; begin Result := sruMembers[0].GetDefaultSignature; end; function TwbSubRecordUnionDef.GetDefType: TwbDefType; begin Result := dtSubRecordUnion; end; function TwbSubRecordUnionDef.GetDefTypeName: string; begin Result := 'SubRecordUnion'; end; function TwbSubRecordUnionDef.GetMember(aIndex: Integer): IwbRecordMemberDef; begin Result := sruMembers[aIndex]; end; function TwbSubRecordUnionDef.GetMemberCount: Integer; begin Result := Length(sruMembers); end; function TwbSubRecordUnionDef.GetMemberFor(aSignature : TwbSignature; const aDataContainer : IwbDataContainer) : IwbRecordMemberDef; var i: Integer; begin Result := nil; for i := Low(sruMembers) to High(sruMembers) do begin if sruMembers[i].CanHandle(aSignature, aDataContainer) then begin Result := sruMembers[i]; Exit; end; end; end; function TwbSubRecordUnionDef.GetMemberIndexFor(aSignature : TwbSignature; const aDataContainer : IwbDataContainer) : Integer; var i: Integer; begin Result := -1; for i := Low(sruMembers) to High(sruMembers) do begin if sruMembers[i].CanHandle(aSignature, aDataContainer) then begin Result := i; Exit; end; end; end; function TwbSubRecordUnionDef.GetQuickInitLimit: Integer; begin Result := -1; end; function TwbSubRecordUnionDef.GetRecordHeaderStruct: IwbStructDef; begin Result := wbMainRecordHeader; end; function TwbSubRecordUnionDef.GetSignatureCount: Integer; var i: Integer; begin Result := 0; for i := Low(sruMembers) to High(sruMembers) do Inc(Result, sruMembers[i].GetSignatureCount); end; function TwbSubRecordUnionDef.GetSignatures(const aIndex: Integer): TwbSignature; var i, j, k: Integer; begin j := aIndex; for i := Low(sruMembers) to High(sruMembers) do begin k := sruMembers[i].GetSignatureCount; if k > 0 then begin if j >= k then Dec(j, k) else begin Result := sruMembers[i].GetSignatures(Pred(k)); Exit; end; end; end; raise Exception.Create('Invalid index'); end; function TwbSubRecordUnionDef.GetSkipSignature(const aSignature: TwbSignature): Boolean; var Dummy: Integer; begin Result := Assigned(sruSkipSignatures) and sruSkipSignatures.Find(aSignature, Dummy); end; procedure TwbSubRecordUnionDef.Report(const aParents: TwbDefPath); var Parents : TwbDefPath; i : Integer; begin if defReported then Exit; inherited; Parents := aParents; SetLength(Parents, Succ(Length(Parents))); Parents[High(Parents)].Def := Self; for i := Low(sruMembers) to High(sruMembers) do if Assigned(sruMembers[i]) then begin Parents[High(Parents)].Index := i; sruMembers[i].Report(Parents); end; defReported := True; end; function wbReadInteger24(aBasePtr: pointer): Int64; var Buffer : array[0..3] of Byte; begin Result := 0; Buffer[3] := 0; Buffer[2] := PByte(aBasePtr)^; aBasePtr := Pointer(Cardinal(aBasePtr)+1); Buffer[1] := PByte(aBasePtr)^; aBasePtr := Pointer(Cardinal(aBasePtr)+1); Buffer[0] := PByte(aBasePtr)^; Move(Buffer, Result, SizeOf(Result)); end; procedure WriteInteger24(aBasePtr: pointer; aValue: Int64); var Buffer : array[0..3] of Byte; begin Move(aValue, Buffer, SizeOf(aValue)); PByte(aBasePtr)^ := Buffer[2]; aBasePtr := Pointer(Cardinal(aBasePtr)+1); PByte(aBasePtr)^ := Buffer[1]; aBasePtr := Pointer(Cardinal(aBasePtr)+1); PByte(aBasePtr)^ := Buffer[0]; end; function ReadIntegerCounterSize(aBasePtr: pointer): Int64; var Key : Byte; begin if Assigned(aBasePtr) then begin Key := $3 and PByte(aBasePtr)^; // The counter length is coded into the 2 least significant bits case key of 0: Result := 1; 1: Result := 2; 2: Result := 4; else Result := 1; end end else Result := 1; // Minimum size end; function ReadIntegerCounter(aBasePtr: pointer): Int64; var Key : Byte; begin Result := 0; if Assigned(aBasePtr) then begin Key := $3 and PByte(aBasePtr)^; // The counter length is coded into the 2 least significant bits case key of 0: Move(PByte(aBasePtr)^, Result, 1); // The 6 remaining bits are the count. 1: Move(PWord(aBasePtr)^, Result, 2); // 6 + 8 bits of count 2: Move(PCardinal(aBasePtr)^, Result, 4); // 6 + 24 bits of count 3: ; // Not supposed to exist : zeroed out by the engine end; Result := Result shr 2; end; end; procedure WriteIntegerCounter(aBasePtr: pointer; aValue: Int64); var Buffer : array[0..3] of Byte; begin if Assigned(aBasePtr) then begin Move(aValue, Buffer, SizeOf(aValue)); if Buffer[3] > 0 then begin // 4 bytes counter Buffer[3] := (Buffer[3] shl 2 ) or 3; PByte(aBasePtr)^ := Buffer[3]; aBasePtr := Pointer(Cardinal(aBasePtr)+1); PByte(aBasePtr)^ := Buffer[2]; aBasePtr := Pointer(Cardinal(aBasePtr)+1); PByte(aBasePtr)^ := Buffer[1]; aBasePtr := Pointer(Cardinal(aBasePtr)+1); PByte(aBasePtr)^ := Buffer[0]; end else if Buffer[2] > 0 then begin Buffer[2] := (Buffer[3] shl 2 ) or 2; PByte(aBasePtr)^ := Buffer[2]; aBasePtr := Pointer(Cardinal(aBasePtr)+1); PByte(aBasePtr)^ := Buffer[1]; aBasePtr := Pointer(Cardinal(aBasePtr)+1); PByte(aBasePtr)^ := Buffer[0]; end else if Buffer[1] > 0 then begin Buffer[1] := (Buffer[1] shl 2 ) or 1; PByte(aBasePtr)^ := Buffer[1]; aBasePtr := Pointer(Cardinal(aBasePtr)+1); PByte(aBasePtr)^ := Buffer[0]; end else begin Buffer[0] := (Buffer[0] shl 2 ) or 0; PByte(aBasePtr)^ := Buffer[0]; end; end; end; { TwbIntegerDef } function TwbIntegerDef.Assign(const aTarget : IwbElement; aIndex : Integer; const aSource : IwbElement; aOnlySK : Boolean) : IwbElement; begin if Assigned(inFormater) then Result := inFormater.Assign(aTarget, aIndex, aSource, aOnlySK) else Result := inherited Assign(aTarget, aIndex, aSource, aOnlySK) end; procedure TwbIntegerDef.BuildRef(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement); var Value : Int64; begin if Assigned(inFormater) then if (Cardinal(aEndPtr) - Cardinal(aBasePtr)) >= GetExpectedLength then begin case inType of itU8: Value := PByte(aBasePtr)^; itS8: Value := PShortInt(aBasePtr)^; itU16: Value := PWord(aBasePtr)^; itS16: Value := PSmallInt(aBasePtr)^; itU24: Value := wbReadInteger24(aBasePtr); itU32: Value := PCardinal(aBasePtr)^; itS32: Value := PLongInt(aBasePtr)^; itU64: Value := PUInt64(aBasePtr)^; //no U64 in delphi... itS64: Value := PInt64(aBasePtr)^; itU6to30: Value := ReadIntegerCounter(aBasePtr); else {it0:} Value := 0; end; inFormater.BuildRef(Value, aElement); end; end; function TwbIntegerDef.CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; var IntegerDef : IwbIntegerDef; begin Result := Supports(aDef, IwbIntegerDef, IntegerDef); if Result then begin if Assigned(inFormater) then Result := inFormater.CanAssign(aElement, aIndex, IntegerDef.Formater[aElement]) else if Assigned(IntegerDef.Formater[aElement]) then Result := IntegerDef.Formater[aElement].CanAssign(aElement, aIndex, GetFormater(aElement)); end else if Assigned(inFormater) then Result := inFormater.CanAssign(aElement, aIndex, aDef); end; function TwbIntegerDef.CanContainFormIDs: Boolean; begin Result := Assigned(inFormater) and (inFormater.CanContainFormIDs); end; function TwbIntegerDef.Check(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; var Len : Cardinal; Value : Int64; begin Result := ''; Len := Cardinal(aEndPtr) - Cardinal(aBasePtr); if Len < GetExpectedLength then begin if wbCheckExpectedBytes then Result := Format('Expected %d bytes of data, found %d', [GetExpectedLength , Len]) end else begin case inType of itU8: Value := PByte(aBasePtr)^; itS8: Value := PShortInt(aBasePtr)^; itU16: Value := PWord(aBasePtr)^; itS16: Value := PSmallInt(aBasePtr)^; itU24: Value := wbReadInteger24(aBasePtr); itU32: Value := PCardinal(aBasePtr)^; itS32: Value := PLongInt(aBasePtr)^; itU64: Value := PUInt64(aBasePtr)^; //no U64 in delphi... itS64: Value := PInt64(aBasePtr)^; itU6to30: Value := ReadIntegerCounter(aBasePtr); else {itU0:} Value := 0; end; if Assigned(inFormater) then Result := inFormater.Check(Value, aElement) else Result := ''; end; end; constructor TwbIntegerDef.Clone(const aSource: TwbDef); begin with aSource as TwbIntegerDef do Self.Create(defPriority, defRequired, noName, inType, inFormater, noDontShow, noAfterSet, inDefault, defGetCP, noTerminator).defSource := aSource; end; function TwbIntegerDef.CompareExchangeFormID(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aOldFormID, aNewFormID: Cardinal): Boolean; var i: Int64; begin if Assigned(inFormater) then begin i := ToInt(aBasePtr, aEndPtr, aElement); Result := inFormater.CompareExchangeFormID(i, aOldFormID, aNewFormID, aElement); if Result then FromInt(i, aBasePtr, aEndPtr, aElement); end else Result := inherited CompareExchangeFormID(aBasePtr, aEndPtr, aElement, aOldFormID, aNewFormID); end; constructor TwbIntegerDef.Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aName : string; const aIntType : TwbIntType; const aFormater : IwbIntegerDefFormater; aDontShow : TwbDontShowCallback; aAfterSet : TwbAfterSetCallback; aDefault : Int64; aGetCP : TwbGetConflictPriority; aTerminator : Boolean); begin inDefault := aDefault; inType := aIntType; if Assigned(aFormater) then inFormater := (aFormater as IwbDefInternal).SetParent(Self, False) as IwbIntegerDefFormater; inherited Create(aPriority, aRequired, aName, nil, aAfterSet, aDontShow, aGetCP, aTerminator); end; procedure TwbIntegerDef.FindUsedMasters(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aMasters: PwbUsedMasters); begin if Assigned(inFormater) then inFormater.FindUsedMasters(ToInt(aBasePtr, aEndPtr, aElement), aMasters, aElement) else inherited FindUsedMasters(aBasePtr, aEndPtr, aElement, aMasters); end; procedure TwbIntegerDef.FromEditValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: string); var i: Int64; begin if aValue = '' then i := 0 else if Assigned(inFormater) then i := inFormater.FromEditValue(aValue, aElement) else i := StrToInt64(aValue); FromInt(i, aBasePtr, aEndPtr, aElement); end; procedure TwbIntegerDef.FromInt(aValue: Int64; aBasePtr, aEndPtr: Pointer; const aElement: IwbElement); begin aElement.RequestStorageChange(aBasePtr, aEndPtr, GetExpectedLength(aValue)); case inType of itU8: PByte(aBasePtr)^ := aValue; itS8: PShortInt(aBasePtr)^ := aValue; itU16: PWord(aBasePtr)^ := aValue; itS16: PSmallInt(aBasePtr)^ := aValue; itU24: WriteInteger24(aBasePtr, aValue); itU32: PCardinal(aBasePtr)^ := aValue; itS32: PLongInt(aBasePtr)^ := aValue; itU64: PUInt64(aBasePtr)^ := aValue; itS64: PInt64(aBasePtr)^ := aValue; itU6to30: WriteIntegerCounter(aBasePtr, aValue); else {it0: } end; end; procedure TwbIntegerDef.FromNativeValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: Variant); begin aElement.RequestStorageChange(aBasePtr, aEndPtr, GetExpectedLength(aValue)); case inType of itS8: PShortInt(aBasePtr)^ := aValue; itU16: PWord(aBasePtr)^ := aValue; itS16: PSmallInt(aBasePtr)^ := aValue; itU24: WriteInteger24(aBasePtr, aValue); itU32: PCardinal(aBasePtr)^ := aValue; itS32: PLongInt(aBasePtr)^ := aValue; itU64: PUInt64(aBasePtr)^ := aValue; itS64: PInt64(aBasePtr)^ := aValue; itU6to30: WriteIntegerCounter(aBasePtr, aValue); else PByte(aBasePtr)^ := aValue; end; end; function TwbIntegerDef.GetDefType: TwbDefType; begin Result := dtInteger; end; function TwbIntegerDef.GetDefTypeName: string; begin if Assigned(inFormater) then Result := inFormater.GetDefTypeName else case inType of itS8: Result := 'Signed Byte'; itU16: Result := 'Unsigned Word'; itS16: Result := 'Signed Word'; itU24: Result := 'RefID'; itU32: Result := 'Unsigned DWord'; itS32: Result := 'Signed DWord'; itU64: Result := 'Unsigned QWord'; itS64: Result := 'Signed QWord'; itU6to30: Result := 'Counter'; else Result := 'Unsigned Byte'; end; end; function TwbIntegerDef.GetEditInfo(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; begin if Assigned(inFormater) then Result := inFormater.EditInfo[ToInt(aBasePtr, aEndPtr, aElement), aElement] else Result := inherited GetEditInfo(aBasePtr, aEndPtr, aElement); end; function TwbIntegerDef.GetEditType(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): TwbEditType; begin if Assigned(inFormater) then Result := inFormater.EditType[ToInt(aBasePtr, aEndPtr, aElement), aElement] else Result := inherited GetEditType(aBasePtr, aEndPtr, aElement); end; function TwbIntegerDef.GetExpectedLength(aValue: Int64 = 0): Integer; const ExpectedLen : array[TwbIntType] of Cardinal = ( 0, 1, 1, 2, 2, 4, 4, 8, 8, 3, 1 ); begin if inType = it0 then Result := 0 else begin Result := ExpectedLen[inType]+Ord(noTerminator); if (inType=itU6to30) and (aValue<>0) then case (aValue and 3) of 0 : Result := 1 + Ord(noTerminator); 1 : Result := 2 + Ord(noTerminator); 2 : Result := 4 + Ord(noTerminator); end; end; end; function TwbIntegerDef.GetFormater(const aElement: IwbElement): IwbIntegerDefFormater; var Union: IwbIntegerDefFormaterUnion; begin Result := inFormater; while Supports(Result, IwbIntegerDefFormaterUnion, Union) do Result := Union.Decide(aElement); end; function TwbIntegerDef.GetFormaterCanChange: Boolean; begin Result := Supports(inFormater, IwbIntegerDefFormaterUnion); end; function TwbIntegerDef.GetIntType: TwbIntType; begin Result := inType; end; function TwbIntegerDef.GetIsEditable(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Boolean; begin Result := wbIsInternalEdit or (not Assigned(inFormater) or inFormater.IsEditable[ToInt(aBasePtr, aEndPtr, aElement), aElement]); end; function TwbIntegerDef.GetLinksTo(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): IwbElement; var Value : Int64; begin Result := nil; if Assigned(inFormater) then if (Cardinal(aEndPtr) - Cardinal(aBasePtr)) >= GetExpectedLength then begin case inType of itU8: Value := PByte(aBasePtr)^; itS8: Value := PShortInt(aBasePtr)^; itU16: Value := PWord(aBasePtr)^; itS16: Value := PSmallInt(aBasePtr)^; itU24: Value := wbReadInteger24(aBasePtr); itU32: Value := PCardinal(aBasePtr)^; itS32: Value := PLongInt(aBasePtr)^; itU64: Value := PUInt64(aBasePtr)^; //no U64 in delphi... itS64: Value := PInt64(aBasePtr)^; itU6to30: Value := ReadIntegerCounter(aBasePtr); else {it0:} Value := 0; end; Result := inFormater.LinksTo[Value, aElement]; end; end; function TwbIntegerDef.GetNoReach: Boolean; begin Result := Assigned(inFormater) and inFormater.NoReach; end; function TwbIntegerDef.GetSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; begin if inType = it0 then Result := 0 else if Assigned(aBasePtr) and Assigned(aEndPtr) and (Cardinal(aBasePtr) NewValue then FromInt(NewValue, aBasePtr, aEndPtr, aElement) end else inherited MasterCountUpdated(aBasePtr, aEndPtr, aElement, aOld, aNew); end; procedure TwbIntegerDef.MasterIndicesUpdated(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aOld, aNew: TBytes); var OldValue : Int64; NewValue : Int64; begin if Assigned(inFormater) then begin OldValue := ToInt(aBasePtr, aEndPtr, aElement); NewValue := inFormater.MasterIndicesUpdated(OldValue, aOld, aNew, aElement); if OldValue <> NewValue then FromInt(NewValue, aBasePtr, aEndPtr, aElement) end else inherited MasterIndicesUpdated(aBasePtr, aEndPtr, aElement, aOld, aNew); end; procedure TwbIntegerDef.ReplaceFormater(const aFormater: IwbIntegerDefFormater); begin defSource := nil; if Assigned(aFormater) then inFormater := (aFormater as IwbDefInternal).SetParent(Self, True) as IwbIntegerDefFormater else inFormater := nil end; procedure TwbIntegerDef.Report(const aParents: TwbDefPath); var Parents : TwbDefPath; begin if defReported then Exit; inherited; if Assigned(inFormater) then begin Parents := aParents; SetLength(Parents, Succ(Length(Parents))); Parents[High(Parents)].Def := Self; Parents[High(Parents)].Index := -1; inFormater.Report(aParents); end; defReported := True; end; function TwbIntegerDef.SetToDefault(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Boolean; begin Result := not Assigned(aBasePtr) or (ToInt(aBasePtr, aEndPtr, aElement) <> inDefault); if Result then FromInt(inDefault, aBasePtr, aEndPtr, aElement); end; function IntToHex64(Value: Int64; Digits: Integer): string; begin Result := IntToHex(Value, Digits); end; function TwbIntegerDef.ToEditValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; var Len : Cardinal; Value : Int64; const PlusMinus : array[Boolean] of string = ('+', '-'); begin Len := Cardinal(aEndPtr) - Cardinal(aBasePtr); if (Len < GetExpectedLength) or (inType = it0) then Result := '' else begin case inType of itU8: Value := PByte(aBasePtr)^; itS8: Value := PShortInt(aBasePtr)^; itU16: Value := PWord(aBasePtr)^; itS16: Value := PSmallInt(aBasePtr)^; itU24: Value := wbReadInteger24(aBasePtr); itU32: Value := PCardinal(aBasePtr)^; itS32: Value := PLongInt(aBasePtr)^; itU64: Value := PUInt64(aBasePtr)^; //no U64 in delphi... itS64: Value := PInt64(aBasePtr)^; itU6to30: Value := ReadIntegerCounter(aBasePtr); else {it0:} Value := 0; end; Result := ''; if Assigned(inFormater) then Result := inFormater.ToEditValue(Value, aElement); if Result = '' then Result := IntToStr(Value); end; end; function TwbIntegerDef.ToInt(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Int64; var Len : Cardinal; begin Len := Cardinal(aEndPtr) - Cardinal(aBasePtr); if Len < GetExpectedLength then Result := 0 else case inType of itU8: Result := PByte(aBasePtr)^; itS8: Result := PShortInt(aBasePtr)^; itU16: Result := PWord(aBasePtr)^; itS16: Result := PSmallInt(aBasePtr)^; itU24: Result := wbReadInteger24(aBasePtr); itU32: Result := PCardinal(aBasePtr)^; itS32: Result := PLongInt(aBasePtr)^; itU64: Result := PUInt64(aBasePtr)^; //no U64 in delphi... itS64: Result := PInt64(aBasePtr)^; itU6to30: Result := ReadIntegerCounter(aBasePtr); else {it0:} Result := 0; end; end; function TwbIntegerDef.ToNativeValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Variant; begin if (Cardinal(aEndPtr) - Cardinal(aBasePtr)) < GetExpectedLength then VarClear(Result) else case inType of itU8: Result := PByte(aBasePtr)^; itS8: Result := PShortInt(aBasePtr)^; itU16: Result := PWord(aBasePtr)^; itS16: Result := PSmallInt(aBasePtr)^; itU24: Result := wbReadInteger24(aBasePtr); itU32: Result := PCardinal(aBasePtr)^; itS32: Result := PLongInt(aBasePtr)^; itU64: Result := PUInt64(aBasePtr)^; //no U64 in delphi... itS64: Result := PInt64(aBasePtr)^; itU6to30: Result := ReadIntegerCounter(aBasePtr); else {it0:} Result := 0; end; end; function TwbIntegerDef.ToSortKey(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aExtended: Boolean): string; var Len : Cardinal; Value : Int64; const PlusMinus : array[Boolean] of string = ('+', '-'); begin Len := Cardinal(aEndPtr) - Cardinal(aBasePtr); if Len < GetExpectedLength then if Assigned(inFormater) and inFormater.RequiresKey then Result := inFormater.ToSortKey(0, aElement) else Result := '' else begin case inType of itU8: Value := PByte(aBasePtr)^; itS8: Value := PShortInt(aBasePtr)^; itU16: Value := PWord(aBasePtr)^; itS16: Value := PSmallInt(aBasePtr)^; itU24: Value := wbReadInteger24(aBasePtr); itU32: Value := PCardinal(aBasePtr)^; itS32: Value := PLongInt(aBasePtr)^; itU64: Value := PUInt64(aBasePtr)^; //no U64 in delphi... itS64: Value := PInt64(aBasePtr)^; itU6to30: Value := ReadIntegerCounter(aBasePtr); else {it0:} Value := 0; end; Result := ''; if Assigned(inFormater) then Result := inFormater.ToSortKey(Value, aElement); if Result = '' then begin case inType of itS8: Value := Value + Abs(Int64(Low(ShortInt))); itS16: Value := Value + Abs(Int64(Low(SmallInt))); itS32: Value := Value + Abs(Int64(Low(LongInt))); itS64: Value := Value + Abs(Int64(Low(Int64))); end; Result := Result + IntToHex64(Value, Succ(GetExpectedLength(Value) * 2)); end; end; end; function TwbIntegerDef.ToString(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; var Len : Cardinal; Value : Int64; begin Result := ''; if inType = it0 then Exit; Len := Cardinal(aEndPtr) - Cardinal(aBasePtr); if Len < GetExpectedLength then begin if wbCheckExpectedBytes then Result := Format('', [GetExpectedLength, Len]) end else begin case inType of itU8: Value := PByte(aBasePtr)^; itS8: Value := PShortInt(aBasePtr)^; itU16: Value := PWord(aBasePtr)^; itS16: Value := PSmallInt(aBasePtr)^; itU24: Value := wbReadInteger24(aBasePtr); itU32: Value := PCardinal(aBasePtr)^; itS32: Value := PLongInt(aBasePtr)^; itU64: Value := PUInt64(aBasePtr)^; //no U64 in delphi... itS64: Value := PInt64(aBasePtr)^; itU6to30: Value := ReadIntegerCounter(aBasePtr); else {it0:} Value := 0; end; if Assigned(inFormater) then Result := inFormater.ToString(Value, aElement) else Result := IntToStr(Value); if (Len > GetExpectedLength) and not (inType in [itU6to30]) then begin if wbCheckExpectedBytes then Result := Result + Format(' ', [GetExpectedLength , Len]) end; end; Used(aElement, Result); end; { TwbArrayDef } constructor TwbArrayDef.Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aName : string; const aElement : IwbValueDef; aCount : Integer; const aLabels : array of string; aSorted : Boolean; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aDontShow : TwbDontShowCallback; aGetCP : TwbGetConflictPriority; aCanAddTo : Boolean; aTerminator : Boolean; aTerminated : Boolean); var i: Integer; begin Assert((not aSorted) or (Length(aLabels) < 1)); SetLength(arLabels, Length(aLabels)); for i := Low(arLabels) to High(arLabels) do arLabels[i] := aLabels[i]; arCount := aCount; if Assigned(aElement) then arElement := (aElement as IwbDefInternal).SetParent(Self, False) as IwbValueDef; arSorted := aSorted; arCanAddTo := aCanAddTo; arTerminated := aTerminated; inherited Create(aPriority, aRequired, aName, aAfterLoad, aAfterSet, aDontShow, aGetCP, aTerminator); end; function TwbArrayDef.CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; var ArrayDef: IwbArrayDef; begin Result := (aIndex = Low(Integer)) and Supports(aDef, IwbArrayDef, ArrayDef) and ( ( arCount <= 0 ) or (arCount = ArrayDef.ElementCount) ) and arElement.CanAssign(aElement, aIndex, ArrayDef.Element); end; function TwbArrayDef.CanContainFormIDs: Boolean; begin Result := arElement.CanContainFormIDs; end; constructor TwbArrayDef.Clone(const aSource: TwbDef); begin with aSource as TwbArrayDef do if Assigned(arCountCallback) then Self.Create(defPriority, defRequired, noName, arElement, arCountCallback, arLabels, arSorted, noAfterLoad, noAfterSet, noDontShow, defGetCP, arCanAddTo, noTerminator, arTerminated).defSource := aSource else Self.Create(defPriority, defRequired, noName, arElement, arCount, arLabels, arSorted, noAfterLoad, noAfterSet, noDontShow, defGetCP, arCanAddTo, noTerminator, arTerminated).defSource := aSource; end; constructor TwbArrayDef.Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aName : string; const aElement : IwbValueDef; aCountCallback : TwbCountCallback; const aLabels : array of string; aSorted : Boolean; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aDontShow : TwbDontShowCallback; aGetCP : TwbGetConflictPriority; aCanAddTo : Boolean; aTerminator : Boolean; aTerminated : Boolean); begin arCountCallback := aCountCallback; Create(aPriority, aRequired, aName, aElement, 0, aLabels, aSorted, aAfterLoad, aAfterSet, aDontShow, aGetCP, aCanAddTo, aTerminator, aTerminated); end; function TwbArrayDef.GetCanAddTo: Boolean; begin Result := arCanAddTo; end; function TwbArrayDef.GetCanBeZeroSize: Boolean; begin Result := True; end; function TwbArrayDef.GetCount: Integer; begin Result := arCount; end; function TwbArrayDef.GetCountCallBack: TwbCountCallback; begin Result := arCountCallBack; end; function TwbArrayDef.GetDefType: TwbDefType; begin Result := dtArray; end; function TwbArrayDef.GetDefTypeName: string; var Prefix: Integer; begin if arCount < 0 then begin if arCount < -1 then if arCount < -2 then Prefix := 1 else Prefix := 2 else Prefix := 4; if noTerminator then Result := 'Separated Array with '+IntToStr(Prefix)+' Bytes Counter of ' else Result := 'Array with '+IntToStr(Prefix)+' Bytes Counter of '; end else begin if (arCount < 1) and Assigned(arCountCallback) then if noTerminator then Result := 'Separated Variable Count Array' else Result := 'Variable Count Array' else if arCount > 0 then if noTerminator then Result := 'Separated Array of '+IntToStr(arCount)+' ' else Result := 'Array of '+IntToStr(arCount)+' ' else if noTerminator then Result := 'Separated Array of ' else Result := 'Array of '; end; Result := Result + GetElement.GetDefTypeName; end; function TwbArrayDef.GetElement: IwbValueDef; begin Result := arElement; end; function TwbArrayDef.GetElementLabel(aIndex: Integer): string; begin if (aIndex >= Low(arLabels)) and (aIndex <= High(arLabels)) then Result := arLabels[aIndex] else Result := ''; end; function TwbArrayDef.GetIsVariableSizeInternal: Boolean; begin Result := (arCount <= 0) or arElement.IsVariableSize; end; function TwbArrayDef.GetPrefixCount(aBasePtr: Pointer): Cardinal; var Count : int64; begin Result := 0; if arCount = -255 then Result := 0 else if arCount = -254 then Result := ReadIntegerCounter(aBasePtr) else if arCount = -253 then begin // Matrix of count * count Count := ReadIntegerCounter(aBasePtr); Result := Count * Count; end else if arCount = -241 then begin // Matrix of cardinal * cardinal Count := PCardinal(aBasePtr)^; Result := Count * Count; end else if Assigned(aBasePtr) then case GetPrefixlength(aBasePtr) of 1: Result := PByte(aBasePtr)^; 2: Result := PWord(aBasePtr)^; 4: Result := PCardinal(aBasePtr)^; end; end; function TwbArrayDef.GetPrefixLength(aBasePtr: Pointer): Integer; begin Result := 0; if arCount < 0 then if arCount = -1 then Result := 4 else if arCount = -2 then Result := 2 else if arCount = -4 then Result := 1 else if arCount = -241 then Result := 4 else if arCount = -253 then Result := ReadIntegerCounterSize(aBasePtr) else if arCount = -254 then Result := ReadIntegerCounterSize(aBasePtr); end; function TwbArrayDef.GetPrefixSize(aBasePtr: Pointer): Integer; begin Result := GetPrefixLength(aBasePtr); if (Result>0) and noTerminator then Inc(Result); end; function TwbArrayDef.GetSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; var Prefix : Integer; Count : Integer; Index : Integer; // Used instead of count for easier debugging output. Size : Integer; BasePtr : Pointer; CheckedContainer : Boolean; ArrayContainer : IwbContainerElementRef; Element : IwbElement; DataContainer : IwbDataContainer; KnownSize : Boolean; // aName : String; function CheckContainer: IwbContainerElementRef; begin if Assigned(aElement) and (aElement.ValueDef.DefID = GetDefID) then Supports(aElement, IwbContainerElementRef, ArrayContainer); Result := ArrayContainer; CheckedContainer := True; end; function Container: IwbContainerElementRef; begin if CheckedContainer then Result := ArrayContainer else Result := CheckContainer; end; begin Result := 0; CheckedContainer := False; ArrayContainer := nil; if Assigned(aBasePtr) and Assigned(aEndPtr) and (Cardinal(aEndPtr) '+IntToHex64(Cardinal(aEndPtr), 8)+' for '+noName); Exit; end; Prefix := GetPrefixSize(aBasePtr); BasePtr := aBasePtr; Count := arCount; if Count < 0 then begin Count := GetPrefixCount(aBasePtr); Result := Prefix; end else begin if (Count < 1) and Assigned(arCountCallback) and not (Container=nil) then Count := arCountCallback(BasePtr, aEndPtr, ArrayContainer); if not Assigned(BasePtr) and (Count < 1) and not Assigned(arCountCallback) then // EXPERIMENT: Probably should not be done Count := 1; if (Count < 1) and not Assigned(arCountCallback) then begin Result := High(Integer); Exit; end; end; if Assigned(BasePtr) then Inc(PByte(BasePtr), Prefix); if Count > 0 then if arElement.IsVariableSize then begin if Container = nil then begin // Make sure it won't be used if unassigned, and still delay FindOurself until it is effectivly required if not Assigned(BasePtr) then Result := arElement.DefaultSize[nil, nil, aElement] else Result := High(Integer); Exit; end; if ArrayContainer.ElementCount = Count then begin KnownSize := True; for Index := 0 to Pred(Count) do begin Element := ArrayContainer.Elements[Index]; if Supports(Element, IwbDataContainer, DataContainer) then begin Size := Cardinal(DataContainer.DataEndPtr)-Cardinal(DataContainer.DataBasePtr); Inc(Result, Size); end else begin KnownSize := False; Break; end; end; end else KnownSize := False; Index := 0; if not KnownSize then while (Count > Index) and (Cardinal(BasePtr) < Cardinal(aEndPtr)) do begin Element := ArrayContainer.Elements[Index]; if not Assigned(Element) then begin if wbMoreInfoForIndex and (DebugHook <> 0) and Assigned(wbProgressCallback) then wbProgressCallback('Debug: ['+ ArrayContainer.Path +'] Index ' + IntToStr(Index) + ' of ' + IntToStr(Count) + ' greater than max '+ IntToStr(ArrayContainer.ElementCount-1)); Element := aElement; // If it is too soon, revert to previous way of doing things end; Size := arElement.Size[BasePtr, aEndPtr, Element]; if Size = High(Integer) then begin Result := High(Integer); Exit; end; Inc(Result, Size); if Assigned(aBasePtr) and Assigned(aEndPtr) and (Cardinal(aEndPtr)aBasePtr) then // wbProgressCallback('Found an array with a negative size! (2) '+IntToHex64(Cardinal(aBasePtr)+Result, 8)+ // ' > '+IntToHex64(Cardinal(aEndPtr), 8)+' for '+noName); Result := Cardinal(aEndPtr)-Cardinal(aBasePtr)+Result; Exit; end; if Assigned(BasePtr) then Inc(PByte(BasePtr), Size); Inc(Index); end; end else begin if (Container <> nil) and (ArrayContainer.ElementCount > 0) then Element := ArrayContainer.Elements[0] else Element := aElement; Size := arElement.Size[BasePtr, aEndPtr, Element]; if Size = High(Integer) then begin Result := High(Integer); Exit; end; Result := (Count * Size) + Prefix; if Assigned(aBasePtr) and Assigned(aEndPtr) and (Cardinal(aEndPtr)aBasePtr) then // wbProgressCallback('Found a static array with a negative size! (3) '+IntToHex64(Cardinal(aBasePtr)+Result, 8)+ // ' > '+IntToHex64(Cardinal(aEndPtr), 8)+' for '+noName); Result := Cardinal(aEndPtr)-Cardinal(aBasePtr); Exit; end; end; Inc(Result, Ord(arTerminated)); end; function TwbArrayDef.GetDefaultSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; begin if ((arCount = 0) and not Assigned(arCountCallback)) then Result := 0 else Result := GetSize(aBasePtr, aEndPtr, aElement); end; function TwbArrayDef.GetSorted: Boolean; begin if wbCopyIsRunning = 0 then Result := arSorted else Result := False; end; procedure TwbArrayDef.Report(const aParents: TwbDefPath); var Parents : TwbDefPath; begin if defReported then Exit; inherited; if Assigned(arElement) then begin Parents := aParents; SetLength(Parents, Succ(Length(Parents))); Parents[High(Parents)].Def := Self; Parents[High(Parents)].Index := -1; arElement.Report(aParents); end; defReported := True; end; procedure TwbArrayDef.SetPrefixCount(aBasePtr: Pointer; aValue: Cardinal); begin if arCount = -255 then else if arCount = -254 then WriteIntegerCounter(aBasePtr, aValue) else if Assigned(aBasePtr) then case GetPrefixlength(aBasePtr) of 1: PByte(aBasePtr)^ := aValue; 2: PWord(aBasePtr)^ := aValue; 4: PCardinal(aBasePtr)^ := aValue; end; end; function TwbArrayDef.ToString(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; begin Result := ''; Used(aElement, Result); end; { TwbStructDef } function TwbStructDef.CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; var StructDef : IwbStructDef; i : Integer; begin Result := (aIndex = Low(Integer)) and Supports(aDef, IwbStructDef, StructDef) and ( GetMemberCount = StructDef.MemberCount); if Result and not Equals(aDef) then for i := 0 to Pred(GetMemberCount) do if not stMembers[i].CanAssign(aElement, Low(Integer), StructDef.Members[i]) then begin Result := False; Exit; end; end; function TwbStructDef.CanContainFormIDs: Boolean; begin Result := stCanContainFormIDs; end; constructor TwbStructDef.Clone(const aSource: TwbDef); begin with aSource as TwbStructDef do Self.Create(defPriority, defRequired, noName, stMembers, stSortKey, stExSortKey, stElementMap, stOptionalFromElement, noDontShow, noAfterLoad, noAfterSet, defGetCP).defSource := aSource; end; constructor TwbStructDef.Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aName : string; const aMembers : array of IwbValueDef; const aSortKey : array of Integer; const aExSortKey : array of Integer; {$IFDEF WIN32} const aElementMap : array of Cardinal; {$ENDIF WIN32} {$IFDEF WIN64} const aElementMap : array of UInt64; {$ENDIF WIN64} aOptionalFromElement : Integer; aDontShow : TwbDontShowCallback; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aGetCP : TwbGetConflictPriority); var i: Integer; begin stOptionalFromElement := aOptionalFromElement; SetLength(stMembers, Length(aMembers)); for i := Low(stMembers) to High(stMembers) do begin stMembers[i] := (aMembers[i] as IwbDefInternal).SetParent(Self, False) as IwbValueDef; stCanContainFormIDs := stCanContainFormIDs or aMembers[i].CanContainFormIDs; end; SetLength(stSortKey, Length(aSortKey)); for i := Low(stSortKey) to High(stSortKey) do stSortKey[i] := aSortKey[i]; SetLength(stExSortKey, Length(aExSortKey)); for i := Low(stExSortKey) to High(stExSortKey) do stExSortKey[i] := aExSortKey[i]; SetLength(stElementMap, Length(aElementMap)); for i := Low(stElementMap) to High(stElementMap) do stElementMap[i] := aElementMap[i]; if Length(stElementMap) > 0 then begin Assert(Length(stElementMap) = Length(stMembers)); // should really check that the element map only contains valid values // and that there are no optional elements... end; inherited Create(aPriority, aRequired, aName, aAfterLoad, aAfterSet, aDontShow, aGetCP, False); end; function TwbStructDef.GetDefType: TwbDefType; begin Result := dtStruct; end; function TwbStructDef.GetDefTypeName: string; begin Result := 'Structure'; end; function TwbStructDef.GetElementMap: TDynCardinalArray; begin Result := stElementMap; end; function TwbStructDef.GetMember(aIndex: Integer): IwbValueDef; begin Result := stMembers[aIndex]; end; function TwbStructDef.GetMemberByName(const aName: string): IwbValueDef; var i: Integer; begin for i := Low(stMembers) to High(stMembers) do if SameText(stMembers[i].Name, aName) then Exit(stMembers[i]); Result := nil; end; function TwbStructDef.GetMemberCount: Integer; begin Result := Length(stMembers); end; function TwbStructDef.GetOptionalFromElement: Integer; begin Result := stOptionalFromElement; end; function TwbStructDef.GetSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; var i : Integer; Size : Integer; scDef : IwbStructCDef; BasePtr : Pointer; Container : IwbContainerElementRef; Element : IwbElement; begin Result := 0; if Supports(Self, IwbStructCDef, scDef) then begin scDef.GetSizing(aBasePtr, aEndPtr, aElement, Size); if Size>0 then begin Inc(Result, Size); Exit; end; end; if (Cardinal(aBasePtr) > Cardinal(aEndPtr)) then begin // if aBasePtr >= aEndPtr then no allocation (or error) // wbProgressCallback('Found a struct with a negative size! (1) '+IntToHex64(Cardinal(aBasePtr), 8)+ // ' > '+IntToHex64(Cardinal(aEndPtr), 8)+' for '+ noName); end else if (not Assigned(aBasePtr) or (Cardinal(aBasePtr) = Cardinal(aEndPtr))) and (GetIsVariableSizeInternal) then begin Result := 0; // assuming we would have called GetDefaultSize otherwise... GetDefaultSize(aBasePtr, aEndPtr, aElement); end else begin BasePtr := aBasePtr; if GetIsVariableSize and Supports(aElement, IwbContainerElementRef, Container) and Equals(Container.ValueDef) and (Container.ElementCount > 0) then begin for i := 0 to Pred(Container.ElementCount) do begin Element := Container.Elements[i]; Size := Element.ValueDef.Size[BasePtr, aEndPtr, Element]; if Size = High(Integer) then begin Result := High(Integer); Break; end; Inc(Result, Size); if Assigned(aBasePtr) and Assigned(aEndPtr) and (Cardinal(aEndPtr)aBasePtr) then // wbProgressCallback('Found a struct with a negative size! (2) '+IntToHex64(Cardinal(aBasePtr)+Size, 8)+ // ' < '+IntToHex64(Cardinal(aEndPtr), 8)+' for '+noName); Result := Cardinal(aEndPtr)-Cardinal(aBasePtr); Break; end; if Assigned(BasePtr) then Inc(PByte(BasePtr), Size); end; end else for i := Low(stMembers) to High(stMembers) do begin Size := stMembers[i].Size[BasePtr, aEndPtr, aElement]; if Size = High(Integer) then begin Result := High(Integer); Break; end; Inc(Result, Size); if Assigned(aBasePtr) and Assigned(aEndPtr) and (Cardinal(aEndPtr)aBasePtr) then // wbProgressCallback('Found a struct with a negative size! (2) '+IntToHex64(Cardinal(aBasePtr)+Result, 8)+ // ' > '+IntToHex64(Cardinal(aEndPtr), 8)+' for '+noName); Result := Cardinal(aEndPtr)-Cardinal(aBasePtr); Break; end; if Assigned(BasePtr) then Inc(PByte(BasePtr), Size); end; end; end; function TwbStructDef.GetDefaultSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; var i : Integer; Size : Integer; begin Result := 0; for i := Low(stMembers) to High(stMembers) do begin Size := stMembers[i].DefaultSize[aBasePtr, aEndPtr, aElement]; if Size = High(Integer) then begin Result := High(Integer); Break; end; if Assigned(aBasePtr) then Inc(PByte(aBasePtr), Size); Inc(Result, Size); end; end; function TwbStructDef.GetIsVariableSizeInternal: Boolean; var i : Integer; begin Result := False; for i := Low(stMembers) to High(stMembers) do if stMembers[i].IsVariableSize then begin Result := True; Break; end; end; procedure TwbStructDef.Report(const aParents: TwbDefPath); var Parents : TwbDefPath; i : Integer; begin if defReported then Exit; inherited; Parents := aParents; SetLength(Parents, Succ(Length(Parents))); Parents[High(Parents)].Def := Self; for i := Low(stMembers) to High(stMembers) do if Assigned(stMembers[i]) then begin Parents[High(Parents)].Index := i; stMembers[i].Report(Parents); end; defReported := True; end; function TwbStructDef.ToSortKey(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aExtended: Boolean): string; var i, j : Integer; SortMember : Integer; BasePtr : Pointer; EndPtr : Pointer; begin Result := ''; if (Length(stSortKey) > 0) or (aExtended and (Length(stExSortKey) > 0)) then begin for i := Low(stSortKey) to High(stSortKey) do begin SortMember := stSortKey[i]; if SortMember <= High(stMembers) then begin BasePtr := aBasePtr; for j := Low(stMembers) to Pred(SortMember) do begin Inc(PByte(BasePtr), stMembers[j].Size[BasePtr, aEndPtr, aElement]); if Cardinal(BasePtr) > Cardinal(aEndPtr) then BasePtr := aEndPtr; end; EndPtr := Pointer( Cardinal(BasePtr) + Cardinal(stMembers[SortMember].Size[BasePtr, aEndPtr, aElement]) ); if Cardinal(BasePtr) > Cardinal(aEndPtr) then BasePtr := aEndPtr; if Cardinal(EndPtr) > Cardinal(aEndPtr) then EndPtr := aEndPtr; Result := Result + stMembers[SortMember].ToSortKey(BasePtr, EndPtr, aElement, aExtended); end; if i < High(stSortKey) then Result := Result + '|'; end; if aExtended then begin if (Length(stSortKey) > 0) and (Length(stExSortKey) > 0) then Result := Result + '|'; for i := Low(stExSortKey) to High(stExSortKey) do begin SortMember := stExSortKey[i]; if SortMember <= High(stMembers) then begin BasePtr := aBasePtr; for j := Low(stMembers) to Pred(SortMember) do begin Inc(PByte(BasePtr), stMembers[j].Size[BasePtr, aEndPtr, aElement]); if Cardinal(BasePtr) > Cardinal(aEndPtr) then BasePtr := aEndPtr; end; EndPtr := Pointer( Cardinal(BasePtr) + Cardinal(stMembers[SortMember].Size[BasePtr, aEndPtr, aElement]) ); if Cardinal(BasePtr) > Cardinal(aEndPtr) then BasePtr := aEndPtr; if Cardinal(EndPtr) > Cardinal(aEndPtr) then EndPtr := aEndPtr; Result := Result + stMembers[SortMember].ToSortKey(BasePtr, EndPtr, aElement, aExtended); end; if i < High(stExSortKey) then Result := Result + '|'; end; end; end else begin BasePtr := aBasePtr; for j := Low(stMembers) to High(stMembers) do begin EndPtr := Pointer( Cardinal(BasePtr) + Cardinal(stMembers[j].Size[BasePtr, aEndPtr, aElement]) ); if Cardinal(BasePtr) > Cardinal(aEndPtr) then BasePtr := aEndPtr; if Cardinal(EndPtr) > Cardinal(aEndPtr) then EndPtr := aEndPtr; Result := Result + stMembers[j].ToSortKey(BasePtr, EndPtr, aElement, aExtended); BasePtr := EndPtr; if j < High(stMembers) then Result := Result + '|'; end; end; end; function TwbStructDef.ToString(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; begin Result := ''; Used(aElement, Result); end; { TwbFlagsDef } function TwbFlagsDef.Assign(const aTarget : IwbElement; aIndex : Integer; const aSource : IwbElement; aOnlySK : Boolean) : IwbElement; var FlagDef : IwbFlagDef; i : Int64; begin if Supports(aSource.ValueDef, IwbFlagDef, FlagDef) then begin i := aTarget.NativeValue; i := i or (1 shl FlagDef.FlagIndex); aTarget.NativeValue := i; end else Result := inherited Assign(aTarget, aIndex, aSource, aOnlySK); end; function TwbFlagsDef.CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; var FlagsDef : IwbFlagsDef; FlagDef : IwbFlagDef; i : Integer; begin if Supports(aDef, IwbFlagsDef, FlagsDef) then begin Result := FlagsDef.FlagCount = GetFlagCount; if Result and not GetRoot.Equals(FlagsDef.Root) then for i := 0 to Pred(GetFlagCount) do if not SameStr(FlagsDef.Flags[i], GetFlag(i)) then begin Result := False; Exit; end; end else if Supports(aDef, IwbFlagDef, FlagDef) then begin FlagsDef := FlagDef.FlagsDef; Result := GetBaseFlagsDef.Equals(FlagsDef.BaseFlagsDef); if Result then begin i := FlagDef.FlagIndex; Result := SameStr(FlagsDef.Flags[i], GetFlag(i)); end; end else Result := false; end; function TwbFlagsDef.CanContainFormIDs: Boolean; begin Result := False; end; function TwbFlagsDef.Check(aInt: Int64; const aElement: IwbElement): string; var i: Integer; s: string; begin Result := ''; if not flgUnknownIsUnused then begin for i := 0 to 63 do if (aInt and (Int64(1) shl i)) <> 0 then begin s := ''; if i <= High(flgNames) then s := flgNames[i]; if s = '' then begin s := ''; Result := Result + s + ', '; end; end; SetLength(Result, Length(Result)-2); end; end; constructor TwbFlagsDef.Clone(const aSource: TwbDef); begin with aSource as TwbFlagsDef do Self.Create(flgBaseFlagsDef, flgNames, flgDontShows, flgUnknownIsUnused, flgIgnoreMask, flgGetCPs).defSource := aSource; end; constructor TwbFlagsDef.Create(const aBaseFlagsDef : IwbFlagsDef; const aNames : array of string; const aDontShows : array of TwbDontShowCallback; aUnknownIsUnused : Boolean; aIgnoreMask : Int64; const aGetCPs : array of TwbGetConflictPriority); var i: Integer; begin if Assigned(aBaseFlagsDef) then flgBaseFlagsDef := aBaseFlagsDef.Root as IwbFlagsDef; flgIgnoreMask := aIgnoreMask; flgUnknownIsUnused := aUnknownIsUnused; flgUnusedMask := 0; if flgUnknownIsUnused then flgUnusedMask := not flgUnusedMask; SetLength(flgNames, Length(aNames)); for i := Low(flgNames) to High(flgNames) do begin flgNames[i] := aNames[i]; if SameText(flgNames[i], 'Unused') then flgUnusedMask := flgUnusedMask or (Int64(1) shl i) else if flgUnknownIsUnused and (flgNames[i] <> '') then flgUnusedMask := flgUnusedMask and not (Int64(1) shl i); end; SetLength(flgFlagDefs, Length(flgNames)); SetLength(flgDontShows, Length(aDontShows)); for i := Low(flgDontShows) to High(flgDontShows) do begin flgDontShows[i] := aDontShows[i]; flgHasDontShows := flgHasDontShows or Assigned(flgDontShows[i]); end; SetLength(flgGetCPs, Length(aGetCPs)); for i := Low(flgGetCPs) to High(flgGetCPs) do begin flgGetCPs[i] := aGetCPs[i]; flgHasGetCPs := flgHasGetCPs or Assigned(flgGetCPs[i]); end; inherited Create(cpNormal, False, nil); end; function TwbFlagsDef.FromEditValue(const aValue: string; const aElement: IwbElement): Int64; var i: Integer; begin Result := 0; for i := 1 to Length(aValue) do case aValue[i] of '0': {do nothing}; '1': Result := Result or (Int64(1) shl Pred(i)); else raise Exception.Create('"'+aValue[i]+'" is not a valid character for a flag'); end; Result := Result and not flgUnusedMask; end; function TwbFlagsDef.GetBaseFlagsDef: IwbFlagsDef; begin if Assigned(flgBaseFlagsDef) then Result := flgBaseFlagsDef else Result := GetRoot as IwbFlagsDef; end; function TwbFlagsDef.GetDefTypeName: string; var i: Integer; begin if Length(flgNames)=0 then inherited else begin Result := '('+flgNames[Low(flgNames)]; for i := 1 to High(flgNames) do Result := Result+','+flgNames[i]; Result := Result+')' end; end; function TwbFlagsDef.GetEditInfo(aInt: Int64; const aElement: IwbElement): string; var FlagCount : Integer; IntegerDef : IwbIntegerDef; i : Integer; s : string; begin FlagCount := 64; if Assigned(aElement) and (Supports(aElement.Def, IwbIntegerDef, IntegerDef) or Supports(aElement.ValueDef, IwbIntegerDef, IntegerDef)) then case IntegerDef.IntType of it0: FlagCount := 0; itU8, itS8: FlagCount := 8; itU16, itS16: FlagCount := 16; itU32, itS32: FlagCount := 32; end; with TStringList.Create do try for i := 0 to Pred(FlagCount) do begin s := ''; if i <= High(flgNames) then s := flgNames[i]; if s = '' then if flgUnknownIsUnused then s := 'Unused' else s := ''; if GetFlagDontShow(aElement, i) then s := '(' + s + ')'; if wbShowFlagEnumValue then s := s + ' (0x' + IntToHex(Int64(1) shl i, 8) + ')'; Add(s); end; Result := CommaText; finally Free; end; end; function TwbFlagsDef.GetEditType(aInt: Int64; const aElement: IwbElement): TwbEditType; begin Result := etCheckComboBox; end; function TwbFlagsDef.GetFlag(aIndex: Integer): string; begin Result := flgNames[aIndex]; if wbShowFlagEnumValue then Result := Result + ' (0x' + IntToHex(Int64(1) shl aIndex, 8) + ')'; end; function TwbFlagsDef.GetFlagCount: Integer; begin Result := Length(flgNames); end; function TwbFlagsDef.GetFlagDef(aIndex: Integer): IwbFlagDef; var FlagDef: IwbFlagDef; begin Result := flgFlagDefs[aIndex]; if not Assigned(Result) then begin FlagDef := TwbFlagDef.Create(defPriority, False, flgNames[aIndex], nil, nil, nil, nil, False, aIndex).SetParent(Self, False) as IwbFlagDef; {this really should be done threadsafe with a locked compare exchange} flgFlagDefs[aIndex] := FlagDef; Result := flgFlagDefs[aIndex]; end; end; function TwbFlagsDef.GetFlagDontShow(const aElement: IwbElement; aIndex: Integer): Boolean; begin Result := False; if flgHasDontShows and (aIndex <= High(flgDontShows)) and Assigned(flgDontShows[aIndex]) then Result := flgDontShows[aIndex](aElement); end; procedure TwbFlagsDef.FlagGetCP(const aElement : IwbElement; aIndex : Integer; var aCP : TwbConflictPriority); begin if flgHasGetCPs and (aIndex <= High(flgGetCPs)) and Assigned(flgGetCPs[aIndex]) then flgGetCPs[aIndex](aElement, aCP); end; function TwbFlagsDef.GetFlagHasDontShow(aIndex: Integer): Boolean; begin Result := flgHasDontShows and (aIndex <= High(flgDontShows)) and Assigned(flgDontShows[aIndex]); end; function TwbFlagsDef.GetFlagHasGetCP(aIndex: Integer): Boolean; begin Result := flgHasGetCPs and (aIndex <= High(flgGetCPs)) and Assigned(flgGetCPs[aIndex]); end; function TwbFlagsDef.GetFlagIgnoreConflict(aIndex: Integer): Boolean; begin Result := (flgIgnoreMask and (Int64(1) shl Int64(aIndex))) <> 0; end; function TwbFlagsDef.GetIsEditable(aInt: Int64; const aElement: IwbElement): Boolean; begin Result := True; end; procedure TwbFlagsDef.Report(const aParents: TwbDefPath); var i: Integer; begin if defReported then Exit; inherited; if wbReportMode and wbReportUnknownFlags and HasUnknownFlags then begin WriteLn('Unknown Flags in: ', wbDefsToPath(aParents), wbDefToName(Self)); for i := 0 to 63 do if UnknownFlags[i] > 0 then WriteLn(' ', i,' (',UnknownFlags[i],')'); end; defReported := True; end; function TwbFlagsDef.GetRequiresKey: Boolean; begin Result := True; end; function TwbFlagsDef.ToEditValue(aInt: Int64; const aElement: IwbElement): string; var i: Integer; begin aInt := aInt and not flgUnusedMask; Result := StringOfChar('0', 64); for i := 0 to 63 do if (aInt and (Int64(1) shl i)) <> 0 then begin Result[Succ(i)] := '1'; aInt := aInt and not (Int64(1) shl i); if aInt = 0 then begin SetLength(Result, Succ(i)); Exit; end; end; end; function TwbFlagsDef.ToSortKey(aInt: Int64; const aElement: IwbElement): string; var i: Integer; begin aInt := aInt and not flgUnusedMask; Result := StringOfChar('0', 64); for i := 0 to 63 do if (aInt and (Int64(1) shl i)) <> 0 then if not GetFlagDontShow(aElement, i) then Result[Succ(i)] := '1'; end; function TwbFlagsDef.ToString(aInt: Int64; const aElement: IwbElement): string; var i: Integer; s: string; begin Result := ''; aInt := aInt and not flgUnusedMask; for i := 0 to 63 do if (aInt and (Int64(1) shl i)) <> 0 then begin s := ''; if i <= High(flgNames) then s := flgNames[i]; if s = '' then begin s := ''; if wbReportMode and wbReportUnknownFlags then begin Inc(UnknownFlags[i]); HasUnknownFlags := True; end; end; if wbShowFlagEnumValue then s := s + ' (0x' + IntToHex(Int64(1) shl i, 8) + ')'; if not GetFlagDontShow(aElement, i) then Result := Result + s + ', '; end; SetLength(Result, Length(Result)-2); Used(aElement, Result); end; { TwbEnumDef } function TwbEnumDef.CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; var EnumDef: IwbEnumDef; i: Integer; begin Result := Supports(aDef, IwbEnumDef, EnumDef) and (EnumDef.NameCount = GetNameCount); if Result and not Equals(EnumDef) then for i := 0 to Pred(GetNameCount) do if not SameStr(EnumDef.Names[i], GetName(i)) then begin Result := False; Exit; end; end; function TwbEnumDef.CanContainFormIDs: Boolean; begin Result := False; end; function TwbEnumDef.Check(aInt: Int64; const aElement: IwbElement): string; var i: Integer; begin Result := ''; if (aInt >= Low(enNames)) and (aInt <= High(enNames)) then Result := enNames[aInt]; if Result = '' then if FindSparseName(aInt, i) then Result := enSparseNamesMap[i].snName; if Result = '' then Result := '' else Result := ''; end; function CompareSparseName(Item1, Item2: Pointer): Integer; var Index1, Index2: Int64; begin Index1 := PwbSparseName(Item1).snIndex; Index2 := PwbSparseName(Item2).snIndex; if Index1 < Index2 then Result := -1 else if Index1 = Index2 then Result := 0 else Result := 1; end; constructor TwbEnumDef.Clone(const aSource: TwbDef); var i: Integer; begin with aSource as TwbEnumDef do begin inherited Create(defPriority, defRequired, defGetCP).defSource := aSource; Self.enNames := Copy(enNames, 0, Length(enNames)); Self.enSparseNames := Copy(enSparseNames, 0, Length(enSparseNames)); Self.enEditInfo := enEditInfo; end; SetLength(enSparseNamesMap, Length(enSparseNames)); for i := Low(enSparseNames) to High(enSparseNames) do enSparseNamesMap[i] := @enSparseNames[i]; if Length(enSparseNames) > 0 then wbMergeSort(@enSparseNamesMap[0], Length(enSparseNames), CompareSparseName); end; constructor TwbEnumDef.Create(const aNames: array of string; const aSparseNames : array of const); var i : Integer; EditInfo : TStringList; begin EditInfo := TwbFastStringListIC.Create; try SetLength(enNames, Length(aNames)); for i := Low(enNames) to High(enNames) do begin enNames[i] := aNames[i]; if aNames[i] <> '' then if wbShowFlagEnumValue then EditInfo.Add(aNames[i] + ' (' + IntToStr(i) + ')') else EditInfo.Add(aNames[i]); end; Assert(Length(aSparseNames) mod 2 = 0); SetLength(enSparseNames, Length(aSparseNames) div 2); for i := Low(enSparseNames) to High(enSparseNames) do begin Assert(aSparseNames[ i * 2 ].VType in [vtInteger, vtInt64]); Assert(aSparseNames[Succ(i * 2)].VType in [vtAnsiString, vtChar, vtUnicodeString, vtWideChar]); with enSparseNames[i] do begin if aSparseNames[i * 2].VType = vtInteger then snIndex := aSparseNames[i * 2 ].VInteger else snIndex := aSparseNames[i * 2 ].VInt64^; if aSparseNames[Succ(i * 2)].VType = vtAnsiString then snName := AnsiString(aSparseNames[Succ(i * 2)].VAnsiString) else if aSparseNames[Succ(i * 2)].VType = vtChar then snName := aSparseNames[Succ(i * 2)].VChar else if aSparseNames[Succ(i * 2)].VType = vtUnicodeString then snName := UnicodeString(aSparseNames[Succ(i * 2)].VUnicodeString) else if aSparseNames[Succ(i * 2)].VType = vtWideChar then snName := aSparseNames[Succ(i * 2)].VWideChar; if snName <> '' then if wbShowFlagEnumValue then EditInfo.Add(snName + ' (' + IntToStr(snIndex) + ')') else EditInfo.Add(snName); end; end; EditInfo.Sort; enEditInfo := EditInfo.CommaText; finally FreeAndNil(EditInfo); end; SetLength(enSparseNamesMap, Length(enSparseNames)); for i := Low(enSparseNames) to High(enSparseNames) do enSparseNamesMap[i] := @enSparseNames[i]; if Length(enSparseNames) > 0 then wbMergeSort(@enSparseNamesMap[0], Length(enSparseNames), CompareSparseName); inherited Create(cpNormal, False, nil); end; function CmpB8(a, b: Byte): Integer; asm {$IFDEF WIN32} xor ecx, ecx cmp al, dl ja @@GT je @@EQ @@LT: dec ecx dec ecx @@GT: inc ecx @@EQ: mov eax, ecx {$ENDIF WIN32} {$IFDEF WIN64} xor eax, eax cmp ecx, edx ja @@GT je @@EQ @@LT: dec eax dec eax @@GT: inc eax @@EQ: {$ENDIF WIN64} end; function CmpI32(a, b : Integer) : Integer; asm {$IFDEF WIN32} xor ecx, ecx cmp eax, edx jg @@GT je @@EQ @@LT: dec ecx dec ecx @@GT: inc ecx @@EQ: mov eax, ecx {$ENDIF WIN32} {$IFDEF WIN64} xor eax, eax cmp ecx, edx jg @@GT je @@EQ @@LT: dec eax dec eax @@GT: inc eax @@EQ: {$ENDIF WIN64} end; function CmpW32(a, b: Cardinal): Integer; asm {$IFDEF WIN32} xor ecx, ecx cmp eax, edx ja @@GT je @@EQ @@LT: dec ecx dec ecx @@GT: inc ecx @@EQ: mov eax, ecx {$ENDIF WIN32} {$IFDEF WIN64} xor eax, eax cmp ecx, edx ja @@GT je @@EQ @@LT: dec eax dec eax @@GT: inc eax @@EQ: {$ENDIF WIN64} end; function CmpI64(const a, b : Int64) : Integer; //begin // if a = b then // Result := nxEqual // else if a < b then // Result := nxSmallerThan // else // Result := nxGreaterThan; //end; asm {$IFDEF WIN32} xor eax, eax mov edx, [ebp+20] cmp edx, [ebp+12] jg @@GT jl @@LT mov edx, [ebp+16] cmp edx, [ebp+8] ja @@GT je @@EQ @@LT: dec eax dec eax @@GT: inc eax @@EQ: {$ENDIF WIN32} {$IFDEF WIN64} xor rax, rax cmp rcx, rdx jg @@GT je @@EQ @@LT: dec rax dec rax @@GT: inc rax @@EQ: {$ENDIF WIN64} end; function TwbEnumDef.FindSparseName(aSearchIndex: Int64; var Index: Integer): Boolean; var L, H, I, C: Integer; begin Result := False; L := Low(enSparseNamesMap); H := High(enSparseNamesMap); while L <= H do begin I := (L + H) shr 1; C := CmpI64(enSparseNamesMap[I].snIndex, aSearchIndex); if C < 0 then L := I + 1 else begin H := I - 1; if C = 0 then begin Result := True; L := I; end; end; end; Index := L; end; function TwbEnumDef.FromEditValue(const aValue: string; const aElement: IwbElement): Int64; var i, j: Integer; Value: string; begin if aValue = '' then Result := 0 else begin Value := aValue; if wbShowFlagEnumValue and (Value[Length(Value)] = ')') then begin // remove an integer value of enum from enum string value i := LastDelimiter('(', Value); if (i > 0) and TryStrToInt(Copy(Value, Succ(i), Length(Value) - Succ(i)), j) then Delete(Value, Pred(i), Length(Value)); end; for i := Low(enNames) to High(enNames) do if SameStr(enNames[i], Value) then begin Result := i; Exit; end; for i := Low(enSparseNames) to High(enSparseNames) do with enSparseNames[i] do if SameStr(snName, Value) then begin Result := snIndex; Exit; end; Result := StrToInt64(Value); end; end; function TwbEnumDef.GetDefTypeName: string; var i: Integer; begin if Length(enNames)=0 then inherited else begin Result := '('+enNames[Low(enNames)]; for i := 1 to High(enNames) do Result := Result+','+enNames[i]; Result := Result+')' end; end; function TwbEnumDef.GetEditInfo(aInt: Int64; const aElement: IwbElement): string; begin Result := enEditInfo; end; function TwbEnumDef.GetEditType(aInt: Int64; const aElement: IwbElement): TwbEditType; begin Result := etComboBox; end; function TwbEnumDef.GetIsEditable(aInt: Int64; const aElement: IwbElement): Boolean; begin Result := True; end; function TwbEnumDef.GetName(aIndex: Integer): string; begin Result := enNames[aIndex]; end; function TwbEnumDef.GetNameCount: Integer; begin Result := Length(enNames); end; procedure TwbEnumDef.Report(const aParents: TwbDefPath); var i, j: Integer; sl: TStringList; begin if defReported then Exit; inherited; if wbReportMode and wbReportUnknownEnums and Assigned(UnknownEnums) then begin WriteLn('Unknown Enums in: ', wbDefsToPath(aParents), wbDefToName(Self)); for i := 0 to Pred(UnknownEnums.Count) do begin sl := UnknownEnums.Objects[i] as TStringList; WriteLn(' ', UnknownEnums[i], ' (',sl.Count,')' ); for j := 0 to Pred(sl.Count) do WriteLn(' ', sl[j], ' (',Integer(sl.Objects[j]),')' ); end; end; defReported := True; end; function TwbEnumDef.ToEditValue(aInt: Int64; const aElement: IwbElement): string; var i: Integer; begin Result := ''; if (aInt >= Low(enNames)) and (aInt <= High(enNames)) then begin Result := enNames[aInt]; if wbShowFlagEnumValue then Result := Result + ' (' + IntToStr(aInt) + ')'; end; if Result = '' then if FindSparseName(aInt, i) then begin Result := enSparseNamesMap[i].snName; if wbShowFlagEnumValue then Result := Result + ' (' + IntToStr(enSparseNamesMap[i].snIndex) + ')'; end; if Result = '' then begin Result := IntToStr(aInt); if wbShowFlagEnumValue then Result := Result + ' (' + IntToStr(aInt) + ')'; end; end; function TwbEnumDef.ToSortKey(aInt: Int64; const aElement: IwbElement): string; begin Result := ''; {handled by IntegerDef} end; function TwbEnumDef.ToString(aInt: Int64; const aElement: IwbElement): string; var s: string; i: Integer; begin Result := ''; if (aInt >= Low(enNames)) and (aInt <= High(enNames)) then begin Result := enNames[aInt]; if wbShowFlagEnumValue and (Result <> '') then Result := Result + ' (' + IntToStr(aInt) + ')'; end; if Result = '' then begin if FindSparseName(aInt, i) then begin Result := enSparseNamesMap[i].snName; if wbShowFlagEnumValue then Result := Result + ' (' + IntToStr(enSparseNamesMap[i].snIndex) + ')'; end else begin Result := ''; if wbReportMode and wbReportUnknownEnums then begin if not Assigned(UnknownEnums) then UnknownEnums := TwbFastStringListIC.CreateSorted; if not UnknownEnums.Find(Result, i) then i := UnknownEnums.AddObject(Result, TwbFastStringListIC.CreateSorted); with UnknownEnums.Objects[i] as TStringList do begin if Count < 10 then begin s := aElement.FullPath; if not Find(s, i) then i := Add(s); Objects[i] := TObject(Succ(Integer(Objects[i]))); end; end; end; end; end; Used(aElement, Result); end; { TwbStringDef } function TwbStringDef.CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; var StringDef: IwbStringDef; begin Result := Supports(aDef, IwbStringDef, StringDef) and ((sdSize = 0) or (StringDef.StringSize = 0) or (sdSize <= StringDef.StringSize)); end; function TwbStringDef.CanContainFormIDs: Boolean; begin Result := False; end; constructor TwbStringDef.Clone(const aSource: TwbDef); begin with aSource as TwbStringDef do Self.Create(defPriority, defRequired, noName, sdSize, noAfterLoad, noAfterSet, noDontShow, defGetCP, noTerminator).defSource := aSource; end; constructor TwbStringDef.Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aName : string; aSize : Integer; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aDontShow : TwbDontShowCallback; aGetCP : TwbGetConflictPriority; aTerminator : Boolean; aForward : boolean); begin sdSize := aSize; sdForward := aForward; inherited Create(aPriority, aRequired, aName, aAfterLoad, aAfterSet, aDontShow, aGetCP, aTerminator); end; procedure TwbStringDef.FromEditValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: string); begin FromStringTransform(aBasePtr, aEndPtr, aElement, aValue, ttFromEditValue); end; procedure TwbStringDef.FromNativeValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: Variant); begin FromStringTransform(aBasePtr, aEndPtr, aElement, aValue, ttFromNativeValue); end; procedure TwbStringDef.FromStringNative(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: AnsiString); var NewSize : Integer; begin if sdSize > 0 then NewSize := sdSize else NewSize := Succ(Length(aValue)); aElement.RequestStorageChange(aBasePtr, aEndPtr, NewSize + Ord(noTerminator)); if sdSize > 0 then begin FillChar(aBasePtr^, sdSize, 0); NewSize := Length(aValue); if NewSize > 0 then Move(aValue[1], aBasePtr^, NewSize); end else begin if NewSize > 1 then Move(aValue[1], aBasePtr^, Length(aValue)); PAnsiChar(aBasePtr)[Pred(NewSize)] := #0; end; if noTerminator then PAnsiChar(aBasePtr)[NewSize] := AnsiChar(wbTerminator); end; procedure TwbStringDef.FromStringTransform(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: string; aTransformType: TwbStringTransformType); begin FromStringNative(aBasePtr, aEndPtr, aElement, TransformString(wbStringToAnsi(aValue, aElement), aTransformType, aElement)); end; function TwbStringDef.GetDefType: TwbDefType; begin Result := dtString; end; function TwbStringDef.GetDefTypeName: string; begin Result := 'Terminated String'; end; function TwbStringDef.GetIsEditable(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Boolean; begin Result := True; end; function TwbStringDef.GetIsVariableSizeInternal: Boolean; begin Result := sdSize = 0; end; function TwbStringDef.GetStringSize: Integer; begin Result := sdSize; end; function TwbStringDef.SetToDefault(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Boolean; begin Result := not Assigned(aBasePtr) or (ToString(aBasePtr, aEndPtr, aElement) <> ''); if Result then FromEditValue(aBasePtr, aEndPtr, aElement, ''); end; function TwbStringDef.GetSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; begin if sdSize > 0 then Result := sdSize + Ord(noTerminator) else begin if aBasePtr = nil then Result := 1 + Ord(noTerminator) else begin Result := Ord(noTerminator); while Cardinal(aBasePtr) < Cardinal(aEndPtr) do begin Inc(Result); if PAnsiChar(aBasePtr)^ = #0 then Exit; Inc(PByte(aBasePtr)); end; end; end; end; function TwbStringDef.GetDefaultSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; begin if sdSize > 0 then Result := sdSize + Ord(noTerminator) else Result := 1 + Ord(noTerminator); end; function TwbStringDef.ToEditValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; begin Result := ToStringTransform(aBasePtr, aEndPtr, aElement, ttToEditValue); end; function TwbStringDef.ToNativeValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Variant; begin Result := ToStringTransform(aBasePtr, aEndPtr, aElement, ttToNativeValue); end; function TwbStringDef.ToSortKey(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aExtended: Boolean): string; begin Result := UpperCase(ToStringTransform(aBasePtr, aEndPtr, aElement, ttToSortKey)); end; function TwbStringDef.ToString(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; begin Result := ToStringTransform(aBasePtr, aEndPtr, aElement, ttToString); end; function TwbStringDef.ToStringNative(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): AnsiString; var aLen, Len : Cardinal; begin Len := Cardinal(aEndPtr) - Cardinal(aBasePtr); if sdSize > 0 then begin if Len > Cardinal(sdSize) then Len := sdSize; end; if sdForward then begin aLen := 0; while aLen < Len do begin if PAnsiChar(aBasePtr)[aLen] = #0 then Break; Inc(aLen); end; Len := aLen; //if aLen < Len then // Len := Succ(aLen); end else while (Len > 0) and (PAnsiChar(aBasePtr)[Pred(Len)] = #0) do Dec(Len); SetLength(Result, Len); if Len > 0 then Move(aBasePtr^, Result[1], Len); Used(aElement, Result); end; function TwbStringDef.ToStringTransform(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aTransformType: TwbStringTransformType): string; begin Result := wbAnsiToString(TransformString(ToStringNative(aBasePtr, aEndPtr, aElement), aTransformType, aElement), aElement); end; function TwbStringDef.TransformString(const s: AnsiString; aTransformType: TwbStringTransformType; const aElement: IwbElement): AnsiString; begin Result := s; end; { TwbFloatDef } const SingleNaN : Single = 0.0/0.0; DoubleNaN : Double = 0.0/0.0; SingleInf : Single = 1.0/0.0; DoubleInf : Double = 1.0/0.0; function TwbFloatDef.CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; var FloatDef: IwbFloatDef; begin Result := Supports(aDef, IwbFloatDef, FloatDef); end; function TwbFloatDef.CanContainFormIDs: Boolean; begin Result := False; end; constructor TwbFloatDef.Clone(const aSource: TwbDef); begin with aSource as TwbFloatDef do Self.Create(defPriority, defRequired, noName, noAfterLoad, noAfterSet, fdScale, fdDigits, noDontShow, fdNormalizer, fdDefault, defGetCP, fdDouble, noTerminator).defSource := aSource; end; constructor TwbFloatDef.Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aName : string; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aScale : Extended; aDigits : Integer; aDontShow : TwbDontShowCallback; aNormalizer : TwbFloatNormalizer; aDefault : Extended; aGetCP : TwbGetConflictPriority; aDouble : Boolean; aTerminator : Boolean); begin fdDefault := aDefault; fdScale := aScale; fdDigits := aDigits; fdNormalizer := aNormalizer; fdDouble := aDouble; if fdDigits < 0 then fdDigits := wbFloatDigits; inherited Create(aPriority, aRequired, aName, aAfterLoad, aAfterSet, aDontShow, aGetCP, aTerminator); end; procedure TwbFloatDef.FromEditValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: string); var Value: Extended; begin aElement.RequestStorageChange(aBasePtr, aEndPtr, 4); if aValue = '' then begin if fdDouble then PDouble(aBasePtr)^ := 0.0 else PSingle(aBasePtr)^ := 0.0; end else if SameText(aValue, 'NaN') then begin if fdDouble then PDouble(aBasePtr)^ := DoubleNaN else PSingle(aBasePtr)^ := SingleNaN; end else if SameText(aValue, 'Inf') then begin if fdDouble then PDouble(aBasePtr)^ := DoubleInf else PSingle(aBasePtr)^ := SingleInf; end else if SameText(aValue, 'Default') or SameText(aValue, 'Max') then begin if fdDouble then PInt64(aBasePtr)^ := $7FEFFFFFFFFFFFFF else PCardinal(aBasePtr)^ := $7F7FFFFF; end else if SameText(aValue, 'Min') then begin if fdDouble then PInt64(aBasePtr)^ := -$10000000000001 // $FFEFFFFFFFFFFFFF else PCardinal(aBasePtr)^ := $FF7FFFFF; end else begin Value := RoundToEx(StrToFloat(aValue), -fdDigits); Value := Value / fdScale; if Assigned(fdNormalizer) then Value := fdNormalizer(aElement, Value); if fdDouble then PDouble(aBasePtr)^ := Value else PSingle(aBasePtr)^ := Value; end; end; procedure TwbFloatDef.FromNativeValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: Variant); var Clear : Boolean; Value : Extended; Size : Integer; begin Clear := VarIsClear(aValue); if not Clear then Value := aValue else Value := 0; if fdDouble then Size := SizeOf(Double)+Ord(noTerminator) else Size := SizeOf(Single)+Ord(noTerminator); aElement.RequestStorageChange(aBasePtr, aEndPtr, Size); if Assigned(aBasePtr) then begin if Clear then begin if fdDouble then PDouble(aBasePtr)^ := DoubleNaN else PSingle(aBasePtr)^ := SingleNaN; end else if fdDouble and (SameValue(Value, MaxDouble) or (Value > MaxDouble)) then PInt64(aBasePtr)^ := $7FEFFFFFFFFFFFFF else if fdDouble and (SameValue(Value, -MaxDouble) or (Value < -MaxDouble)) then PInt64(aBasePtr)^ := -$10000000000001 // $FFEFFFFFFFFFFFFF else if not fdDouble and (SameValue(Value, MaxSingle) or (Value > MaxSingle)) then PCardinal(aBasePtr)^ := $7F7FFFFF else if not fdDouble and (SameValue(Value, -MaxSingle) or (Value < -MaxSingle)) then PCardinal(aBasePtr)^ := $FF7FFFFF else begin Value := RoundToEx(Value, -fdDigits); Value := Value / fdScale; if Assigned(fdNormalizer) then Value := fdNormalizer(aElement, Value); if fdDouble then PDouble(aBasePtr)^ := Value else PSingle(aBasePtr)^ := Value; end; if noTerminator then PByte(aBasePtr)[SizeOf(Single)] := wbTerminator; end; end; function TwbFloatDef.GetDefType: TwbDefType; begin Result := dtFloat; end; function TwbFloatDef.GetDefTypeName: string; begin Result := 'Float'; end; function TwbFloatDef.GetIsEditable(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Boolean; begin Result := True; end; function TwbFloatDef.GetSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; begin if Assigned(aBasePtr) and Assigned(aEndPtr) and (Cardinal(aBasePtr) >= Cardinal(aEndPtr)) then Result := Ord(noTerminator) else Result := GetDefaultSize(aBasePtr, aEndPtr, aElement) end; function TwbFloatDef.GetDefaultSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; begin if fdDouble then Result := SizeOf(Double) + Ord(noTerminator) else Result := SizeOf(Single) + Ord(noTerminator); end; function TwbFloatDef.SetToDefault(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Boolean; var Value: Extended; begin Value := ToNativeValue(aBasePtr, aEndPtr, aElement); if fdDouble then Result := not Assigned(aBasePtr) or not SameValue(Value, fdDefault) else Result := not Assigned(aBasePtr) or not SingleSameValue(Value, fdDefault); if Result then FromNativeValue(aBasePtr, aEndPtr, aElement, fdDefault); end; function TwbFloatDef.ToValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Extended; var Len : Cardinal; Value : Extended; begin Len := Cardinal(aEndPtr) - Cardinal(aBasePtr); if Len < GetDefaultSize(aBasePtr, aEndPtr, aElement) then Result := NaN else if fdDouble then try if PInt64(aBasePtr)^ = $7FEFFFFFFFFFFFFF then Result := maxDouble else if PInt64(aBasePtr)^ = $FFEFFFFFFFFFFFFF then Result := -maxDouble else begin Value := PDouble(aBasePtr)^; if IsInfinite(Value) or IsNan(Value) then Result := Value else begin try if Value <> 0.0 then if SameValue(Value, 0.0) then Value := 0.0; except Value := 0.0; end; if Assigned(fdNormalizer) then Value := fdNormalizer(aElement, Value); Value := Value * fdScale; Result := RoundToEx(Value, -fdDigits); end; end; except Result := NaN; end else try if PCardinal(aBasePtr)^ = $7F7FFFFF then Result := maxSingle else if PCardinal(aBasePtr)^ = $FF7FFFFF then Result := -maxSingle else begin Value := PSingle(aBasePtr)^; if IsInfinite(Value) or IsNan(Value) then Result := Value else begin try if Value <> 0.0 then if SingleSameValue(Value, 0.0) then Value := 0.0; except Value := 0.0; end; if Assigned(fdNormalizer) then Value := fdNormalizer(aElement, Value); Value := Value * fdScale; Result := RoundToEx(Value, -fdDigits); end; end; except Result := NaN; end; end; function TwbFloatDef.ToEditValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; var Value : Extended; begin Value := ToValue(aBasePtr, aEndPtr, aElement); if IsNaN(Value) then Result := 'NaN' else if IsInfinite(Value) then Result := 'Inf' else if (Value = maxDouble) or (Value = maxSingle) then Result := 'Default' // 'Max' ?? else if (Value = -maxDouble) or (Value = -maxSingle) then Result := 'Min' else Result := FloatToStrF(Value, ffFixed, 99, fdDigits); end; function TwbFloatDef.ToNativeValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Variant; var Value: Extended; begin Value := ToValue(aBasePtr, aEndPtr, aElement); if IsNaN(Value) then VarClear(Result) else if Value = maxDouble then Result := maxDouble else if Value = maxSingle then Result := maxSingle else Result := Value; end; function TwbFloatDef.ToSortKey(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aExtended: Boolean): string; var Value : Extended; g : Extended; const PlusMinus : array[Boolean] of string = ('+', '-'); begin Value := ToValue(aBasePtr, aEndPtr, aElement); if IsNaN(Value) then Result := StringOfChar(' ', 23) else if (Value = maxDouble) or (Value = maxSingle) then Result := '+' + StringOfChar('9', 22) else begin g := Abs(Value); Result := FloatToStrF(g, ffFixed, 99, fdDigits); if Length(Result) < 22 then Result := StringOfChar('0', 22 - Length(Result)) + Result; Result := PlusMinus[(Value < 0) and not IsZero(Value, 0.0000009999999999)] + Result; end; end; function TwbFloatDef.ToString(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; var Len : Cardinal; Value : Extended; begin Result := ''; Len := Cardinal(aEndPtr) - Cardinal(aBasePtr); if Len < GetDefaultSize(aBasePtr, aEndPtr, aElement) then begin if wbCheckExpectedBytes then Result := Format('', [GetDefaultSize(aBasePtr, aEndPtr, aElement), Len]) end else begin Value := ToValue(aBasePtr, aEndPtr, aElement); if IsNan(Value) then Result := 'NaN' else if IsInfinite(Value) then Result := 'Inf' else if (Value=maxDouble) or (Value=maxSingle) then Result := 'Default' // 'Max' ?? else if (Value=-maxDouble) or (Value=-maxSingle) then Result := 'Min' else Result := FloatToStrF(Value, ffFixed, 99, fdDigits); if Len > GetDefaultSize(aBasePtr, aEndPtr, aElement) then if wbCheckExpectedBytes then Result := Format(' ', [GetDefaultSize(aBasePtr, aEndPtr, aElement), Len]); end; Used(aElement, Result); end; { TwbChar4 } procedure TwbChar4.BuildRef(aInt: Int64; const aElement: IwbElement); var U32: Cardinal; _File: IwbFile; Rec: IwbMainRecord; begin U32 := aInt; _File := aElement._File; if Assigned(_File) then begin Rec := _File.RecordByEditorID[PwbSignature(@U32)^]; if Assigned(Rec) then aElement.AddReferencedFromID(Rec.LoadOrderFormID); // should always be 00, these are only defined in Oblivion.esm end; end; function TwbChar4.CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; begin Result := Supports(aDef, IwbChar4); end; function TwbChar4.CanContainFormIDs: Boolean; begin Result := True; end; constructor TwbChar4.Clone(const aSource: TwbDef); begin with aSource as TwbChar4 do Self.Create(defPriority, defRequired, defGetCP).defSource := aSource; end; function TwbChar4.FromEditValue(const aValue: string; const aElement: IwbElement): Int64; const Empty : TwbSignature = ' '; var s : AnsiString; begin if aValue = '' then Result := Cardinal(Empty) else begin s := AnsiString(aValue); if Length(s) <> 4 then raise Exception.Create('The value must be exactly 4 characters'); Result := PCardinal(@s[1])^; end; end; function TwbChar4.GetIsEditable(aInt: Int64; const aElement: IwbElement): Boolean; begin Result := True; end; function TwbChar4.GetLinksTo(aInt: Int64; const aElement: IwbElement): IwbElement; var U32: Cardinal; _File: IwbFile; begin Result := nil; U32 := aInt; _File := aElement._File; if Assigned(_File) then Result := _File.RecordByEditorID[PwbSignature(@U32)^]; end; function TwbChar4.ToEditValue(aInt: Int64; const aElement: IwbElement): string; begin Result := ToSortKey(aInt, aElement); end; function TwbChar4.ToSortKey(aInt: Int64; const aElement: IwbElement): string; var U32: Cardinal; begin U32 := aInt; Result := PwbSignature(@U32)^; end; function TwbChar4.ToString(aInt: Int64; const aElement: IwbElement): string; var U32: Cardinal; _File: IwbFile; Rec: IwbRecord; begin U32 := aInt; Result := PwbSignature(@U32)^; _File := aElement._File; if Assigned(_File) then begin Rec := _File.RecordByEditorID[Result]; if Assigned(Rec) then begin Result := Rec.Name; Used(aElement, Result); Exit; end; end; if U32 <> 0 then Result := Result + ' '; Used(aElement, Result); end; { TwbStr4 } function TwbStr4.CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; begin Result := Supports(aDef, IwbStr4); end; function TwbStr4.CanContainFormIDs: Boolean; begin Result := False; end; constructor TwbStr4.Clone(const aSource: TwbDef); begin with aSource as TwbStr4 do Self.Create(defPriority, defRequired, defGetCP).defSource := aSource; end; function TwbStr4.FromEditValue(const aValue: string; const aElement: IwbElement): Int64; const Empty : TwbSignature = ' '; var s : AnsiString; Temp : AnsiString; i : Integer; begin if aValue = '' then Result := Cardinal(Empty) else begin s := AnsiString(aValue); if Length(s) <> 4 then raise Exception.Create('The value must be exactly 4 characters'); Temp := s; for i := 1 to 4 do s[i] := Temp[5-i]; Result := PCardinal(@s[1])^; end; end; function TwbStr4.GetIsEditable(aInt: Int64; const aElement: IwbElement): Boolean; begin Result := True; end; function TwbStr4.ToEditValue(aInt: Int64; const aElement: IwbElement): string; begin Result := ToSortKey(aInt, aElement); end; function TwbStr4.ToSortKey(aInt: Int64; const aElement: IwbElement): string; begin Result := wbStr4ToString(aInt); end; function TwbStr4.ToString(aInt: Int64; const aElement: IwbElement): string; begin Result := ToSortKey(aInt, aElement); Used(aElement, Result); end; { TwbFormID } procedure TwbFormID.BuildRef(aInt: Int64; const aElement: IwbElement); begin if ((aInt < $800) or (aInt = $FFFFFFFF)) and IsValid('ACVA') then Exit; if (aInt <> 0) and (aInt <> $14) then aElement.AddReferencedFromID(aInt); end; function TwbFormID.CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; begin Result := Supports(aDef, IwbFormID); end; function TwbFormID.CanContainFormIDs: Boolean; begin Result := True; end; function TwbFormID.Check(aInt: Int64; const aElement: IwbElement): string; var _File: IwbFile; MainRecord: IwbMainRecord; begin Result := ''; if Assigned(aElement) then begin _File := aElement._File; if Assigned(_File) then begin try MainRecord := _File.RecordByFormID[aInt, True]; if Assigned(MainRecord) then Exit; except on E: Exception do begin Result := E.Message; Exit; end; end; end; end; if aInt > $800 then Result := '['+IntToHex64(aInt,8)+'] < Error: Could not be resolved >'; end; function TwbFormID.CheckFlst(const aMainRecord: IwbMainRecord): Boolean; begin Result := True; end; constructor TwbFormID.Clone(const aSource: TwbDef); begin with aSource as TwbFormID do Self.Create(defPriority, defRequired, defGetCP).defSource := aSource; end; function TwbFormID.CompareExchangeFormID(var aInt: Int64; aOldFormID: Cardinal; aNewFormID: Cardinal; const aElement: IwbElement): Boolean; var _File : IwbFile; FormID : Cardinal; FileID : Integer; NewFileID : Integer; i : Integer; begin Result := False; if {(aInt < $800) or} (aInt = $FFFFFFFF) and IsValid('ACVA') then // Allows source to be reserverd as this does NOT change the record itself Exit; if Assigned(aElement) then begin _File := aElement._File; if Assigned(_File) then begin FormID := aInt; FileID := FormID shr 24; if FileID >= _File.MasterCount then FileID := _File.LoadOrder else FileID := _File.Masters[FileID].LoadOrder; if FileID < 0 then raise Exception.Create('Could not determine load order FormID for old value'); FormID := (FormID and $00FFFFFF) or (Cardinal(FileID) shl 24); if FormID = aOldFormID then begin FileID := aNewFormID shr 24; NewFileID := -1; if FileID = _File.LoadOrder then NewFileID := _File.MasterCount else for i := 0 to Pred(_File.MasterCount) do if _File.Masters[i].LoadOrder = FileID then begin NewFileID := i; break; end; if NewFileID < 0 then raise Exception.Create('FormID ['+IntToHex64(aNewFormID, 8)+'] references a master which is not available in file ' + _File.Name); FormID := (aNewFormID and $00FFFFFF) or (Cardinal(NewFileID) shl 24); if aInt <> FormID then begin aInt := FormID; Result := True; end; end; end; end; end; function TwbFormID.FindRecordForAVCode(aInt: Int64; const aElement: IwbElement): IwbMainRecord; var CheckedFiles : TList; MaxLoadOrder : Integer; function CheckFile(aFile: IwbFile): IwbMainRecord; var Group : IwbContainerElementRef; i : Integer; AV : Variant; begin if CheckedFiles.IndexOf(Pointer(aFile)) >= 0 then Exit(nil); CheckedFiles.Add(Pointer(aFile)); if Supports(aFile.GroupBySignature['MISC'], IwbContainerElementRef, Group) then begin for i := 0 to Pred(Group.ElementCount) do if Supports(Group.Elements[i], IwbMainRecord, Result) then begin Result := Result.HighestOverrideOrSelf[MaxLoadOrder]; if (Result.Flags._Flags and $000000C0) = $000000C0 then begin AV := Result.ElementNativeValues['DATA\Actor Value']; if not (VarIsNull(AV) or VarIsEmpty(AV)) then begin if AV = aInt then Exit; end; end; end; end; Result := nil; for i := Pred(aFile.MasterCount) downto 0 do begin Result := CheckFile(aFile.Masters[i]); if Assigned(Result) then Exit; end; end; var _File : IwbFile; begin Result := nil; if not Assigned(aElement) then Exit; _File := aElement._File; if not Assigned(_File) then Exit; if aInt < $800 then begin CheckedFiles := TList.Create; try MaxLoadOrder := _File.LoadOrder; Result := CheckFile(_File); finally CheckedFiles.Free; end; end else try Result := _File.RecordByFormID[aInt, True]; except end; end; procedure TwbFormID.FindUsedMasters(aInt: Int64; aMasters: PwbUsedMasters; const aElement: IwbElement); var OldValue : Cardinal; FileID : Integer; begin if (aInt < $800) or (aInt = $FFFFFFFF) and IsValid('ACVA') then Exit; OldValue := aInt; if OldValue <> 0 then begin FileID := OldValue shr 24; aMasters[FileID] := True; end; end; function TwbFormID.FromEditValue(const aValue: string; const aElement: IwbElement): Int64; var _File : IwbFile; FormID : Cardinal; FileID : Integer; NewFileID : Integer; i : Integer; s, t : string; begin s := ''; t := aValue; i := Pos('[', t); while i > 0 do begin Delete(t, 1, i); i := Pos(']', t); if i > 0 then begin s := Copy(t, 1, Pred(i)); Delete(t, 1, i); if (Length(s) = 13) and (s[5] = ':') then Delete(s, 1, 5); end; try StrToInt64('$' + s); if Length(s) = 8 then i := 0 else i := Pos('[', t); except i := Pos('[', t); end; end; if Length(s) = 8 then Result := StrToInt64('$' + s) else begin if IsValid('ACVA') and SameText(Trim(aValue), 'None') then begin Result := $FF; Exit; end else Result := StrToInt64('$' + aValue); end; if not wbDisplayLoadOrderFormID then Exit; if Result < $800 then Exit; if Result = $FFFFFFFF then Exit; if Assigned(aElement) then begin _File := aElement._File; if Assigned(_File) then begin FormID := Result; FileID := FormID shr 24; NewFileID := -1; if FileID = _File.LoadOrder then NewFileID := _File.MasterCount else for i := 0 to Pred(_File.MasterCount) do if _File.Masters[i].LoadOrder = FileID then begin NewFileID := i; break; end; if NewFileID < 0 then raise Exception.Create('FormID ['+IntToHex64(FormID, 8)+'] references a master which is not available in file ' + _File.Name); FormID := (FormID and $00FFFFFF) or (Cardinal(NewFileID) shl 24); Result := FormID; end; end; end; function TwbFormID.GetEditInfo(aInt: Int64; const aElement: IwbElement): string; var ACVAIsValid : Boolean; Strings : TStringList; CheckAll : Boolean; Wait : IwbWaitForm; FilesProg : IwbProgress; procedure Process(const aFile: IwbFile); var i, j : Integer; s : string; MainRecord : IwbMainRecord; GroupRecord : IwbGroupRecord; GroupsProg : IwbProgress; RecordsProg : IwbProgress; begin if CheckAll then begin for i := 0 to Pred(aFile.RecordCount) do begin MainRecord := aFile.Records[i]; if IsValid(MainRecord.Signature) and IsValidMainRecord(MainRecord) then begin if MainRecord.CanHaveEditorID and (MainRecord.EditorID = '') then Continue; s := Trim(MainRecord.Name); if s <> '' then begin if s[1] = '<' then Delete(s, 1, 1); if CheckFlst(MainRecord) then Strings.Add(s); if not Assigned(RecordsProg) then RecordsProg := Wait.CreateProgress('Records', s, Pred(aFile.RecordCount) ) else RecordsProg.UpdateStatus(i, s); end; end; if Wait.IsCanceled then Exit; end; end else for i := 0 to Pred(aFile.ElementCount) do begin if not Assigned(GroupsProg) then GroupsProg := Wait.CreateProgress('Groups', aFile.Elements[i].Name, Pred(aFile.ElementCount) ) else GroupsProg.UpdateStatus(i, aFile.Elements[i].Name); if Supports(aFile.Elements[i], IwbGroupRecord, GroupRecord) then if GroupRecord.GroupType = 0 then if IsValid(TwbSignature(GroupRecord.GroupLabel)) then for j := 0 to Pred(GroupRecord.ElementCount) do begin if Supports(GroupRecord.Elements[j], IwbMainRecord, MainRecord) then begin if IsValid(MainRecord.Signature) and IsValidMainRecord(MainRecord) then begin if MainRecord.CanHaveEditorID and (MainRecord.EditorID = '') then Continue; s := Trim(MainRecord.Name); if s <> '' then begin if s[1] = '<' then Delete(s, 1, 1); if CheckFlst(MainRecord) then Strings.Add(s); if not Assigned(RecordsProg) then RecordsProg := Wait.CreateProgress('Records', s, Pred(GroupRecord.ElementCount) ) else RecordsProg.UpdateStatus(j, s); end; end; end; if Wait.IsCanceled then Exit; end; if Wait.IsCanceled then Exit; end; end; var _File : IwbFile; i : Integer; s : string; begin Result := ''; if not wbDisplayLoadOrderFormID then Exit; ACVAIsValid := IsValid('ACVA'); if Assigned(aElement) then begin _File := aElement._File; if Assigned(_File) then begin Strings := TwbFastStringListIC.Create; try CheckAll := IsValid('CELL') or IsValid('LAND') or IsValid('ROAD') or IsValid('REFR') or IsValid('ACHR') or IsValid('ACRE') or IsValid('PGRE') or IsValid('PGRD') or IsValid('PARW') or {>>> Skyrim <<<} IsValid('PBAR') or {>>> Skyrim <<<} IsValid('PBEA') or {>>> Skyrim <<<} IsValid('PFLA') or {>>> Skyrim <<<} IsValid('PCON') or {>>> Skyrim <<<} IsValid('PHZD') or {>>> Skyrim <<<} IsValid('NAVM') or IsValid('INFO'); Wait := wbCreateWaitForm('Building DropDownList', 'The DropDown list is being built. Please Wait...', True, 2000, 500); FilesProg := Wait.CreateProgress('Files', _File.Name, _File.MasterCount); Process(_File); for i := Pred(_File.MasterCount) downto 0 do if not Wait.IsCanceled then begin FilesProg.UpdateStatus( _File.MasterCount - i, _File.Masters[i].Name ); Process(_File.Masters[i]); end; Wait := nil; FilesProg := nil; if ACVAIsValid then begin for i := 0 to Pred(wbActorValueEnum.NameCount) do Strings.Add(wbActorValueEnum.Names[i] + ' [ACVA:' + IntToHex64(i, 8) + ']'); Strings.Add(' None [ACVA:000000FF]'); Strings.Add(' Invalid [ACVA:00000048]'); end else begin if IsValid('NULL') then Strings.Add('NULL - Null Reference [00000000]'); if IsValid('FFFF') then Strings.Add('FFFF - None Reference [FFFFFFFF]'); if IsValid('TRGT') then Strings.Add('TARGET - Target Reference [00000000]'); if IsValid('PLYR') then Strings.Add('Player [00000014]'); end; Strings.Sort; s := ''; for i := Pred(Strings.Count) downto 0 do if Strings[i] <> s then s := Strings[i] else Strings.Delete(i); Result := Strings.CommaText; finally FreeAndNil(Strings); end; end; end; end; function TwbFormID.GetEditType(aInt: Int64; const aElement: IwbElement): TwbEditType; begin Result := etComboBox; end; function TwbFormID.GetIsEditable(aInt: Int64; const aElement: IwbElement): Boolean; begin Result := True; end; function TwbFormID.GetLinksTo(aInt: Int64; const aElement: IwbElement): IwbElement; var _File : IwbFile; begin Result := nil; if aInt = 0 then Exit; if aInt = $14 then Exit; if (aInt = $FFFFFFFF) and IsValid('FFFF') then Exit; if (aInt < $800) and IsValid('ACVA') then Exit; if Assigned(aElement) then begin _File := aElement._File; if Assigned(_File) then try Result := _File.RecordByFormID[aInt, True]; except end; end; end; function TwbFormID.GetMainRecord(aInt: Int64; const aElement: IwbElement): IwbMainRecord; var _File: IwbFile; begin Result := nil; if Assigned(aElement) then begin _File := aElement._File; if Assigned(_File) then Result := _File.RecordByFormID[aInt, True]; end; end; function TwbFormID.IsValid(const aSignature: TwbSignature): Boolean; begin Result := aSignature <> 'ACVA'; end; function TwbFormID.IsValidFlst(const aSignature: TwbSignature): Boolean; begin Result := True; end; function TwbFormID.IsValidMainRecord(const aMainRecord: IwbMainRecord): Boolean; begin Result := True; end; function TwbFormID.MasterCountUpdated(aInt: Int64; aOld, aNew: Byte; const aElement: IwbElement): Int64; var OldValue : Cardinal; NewValue : Cardinal; FileID : Cardinal; begin OldValue := aInt; NewValue := OldValue; if (aInt < $800) or (aInt = $FFFFFFFF) and (IsValid('ACVA') or IsValid('FFFF')) then begin Result := NewValue; Exit; end; if OldValue <> 0 then begin FileID := OldValue shr 24; if FileID >= aOld then begin FileID := aNew; NewValue := (OldValue and $00FFFFFF) or (FileID shl 24); end; end; Result := NewValue; end; function FixupFormID(aFormID: Cardinal; const aOld, aNew: TBytes): Cardinal; var FileID : Integer; i : Integer; begin Result := aFormID; if (Result = 0) or (Result = $14) or (Result = $FFFFFFFF) then Exit; FileID := aFormID shr 24; for i := Low(aOld) to High(aOld) do if aOld[i] = FileID then begin Result := (aFormID and $00FFFFFF) or (Cardinal(aNew[i]) shl 24); Exit; end; end; function TwbFormID.MasterIndicesUpdated(aInt: Int64; const aOld, aNew: TBytes; const aElement: IwbElement): Int64; var OldValue : Cardinal; NewValue : Cardinal; begin OldValue := aInt; NewValue := OldValue; if (aInt < $800) or (aInt = $FFFFFFFF) and (IsValid('ACVA') or IsValid('FFFF')) then begin Result := NewValue; Exit; end; if OldValue <> 0 then NewValue := FixupFormID(OldValue, aOld, aNew); Result := NewValue; end; procedure TwbFormID.Report(const aParents: TwbDefPath); var i: Integer; begin if defReported then Exit; inherited; if wbReportMode then if wbReportFormIDs then begin if Assigned(FoundSignatures) then if ClassType = TwbFormID then begin WriteLn('Unchecked FormID Formater: ', wbDefsToPath(aParents), wbDefToName(Self)); WriteLn(' ', FoundSignatures.CommaText); for i := 0 to Pred(FoundSignatures.Count) do WriteLn(' ', FoundSignatures.Strings[i], ' (', Integer(FoundSignatures.Objects[i]),')'); end; if Assigned(NotResolved) then begin WriteLn('FormID contains unresolvable values: ', wbDefsToPath(aParents), wbDefToName(Self)); for i := 0 to Pred(NotResolved.Count) do WriteLn(' ', NotResolved.Strings[i], ' (', Integer(NotResolved.Objects[i]),')'); end; if Assigned(FoundNotAllowedReferences) then begin WriteLn('FormID contains not allowed references: ', wbDefsToPath(aParents), wbDefToName(Self)); for i := 0 to Pred(FoundNotAllowedReferences.Count) do WriteLn(' ', FoundNotAllowedReferences.Strings[i], ' (', Integer(FoundNotAllowedReferences.Objects[i]),')'); end; end; defReported := True; end; function TwbFormID.ToEditValue(aInt: Int64; const aElement: IwbElement): string; begin if wbDisplayLoadOrderFormID then begin Result := ToString(aInt, aElement);//ToSortKey(aInt, aElement) if (Length(Result) > 0) and (Result[1] = '<') then Delete(Result, 1, 1); end else Result := IntToHex64(aInt, 8); end; function TwbFormID.ToSortKey(aInt: Int64; const aElement: IwbElement): string; var MainRecord: IwbMainRecord; begin if (aInt < $800) or (aInt = $FFFFFFFF) then begin Result := IntToHex64(aInt, 8); Exit; end; MainRecord := GetMainRecord(aInt, aElement); if Assigned(MainRecord) then begin try Result := IntToHex64(MainRecord.LoadOrderFormID, 8); Exit; except on E: Exception do begin Result := IntToHex64(aInt, 8); Exit; end; end; end; Result := IntToHex64(aInt, 8); end; function TwbFormID.ToString(aInt: Int64; const aElement: IwbElement): string; var _File : IwbFile; i : Integer; s : string; MainRecord : IwbMainRecord; begin if ((aInt < $800) or (aInt = $FFFFFFFF)) and IsValid('ACVA') then begin if (aInt = -1) or (aInt = $FF) or (aInt = $FFFFFFFF) then Result := ' None [ACVA:000000FF]' else if aInt = $48 then Result := ' Invalid [ACVA:00000048]' else begin MainRecord := FindRecordForAVCode(aInt, aElement); if Assigned(MainRecord) then Result := MainRecord.FullName else Result := wbActorValueEnum.ToString(aInt, aElement); Result := Result + ' [ACVA:' + IntToHex64(aInt,8) + ']'; end; Exit; end; if aInt = 0 then begin if IsValid('TRGT') and not IsValid('NULL') then begin Result := 'TARGET - Target Reference ['+IntToHex64(aInt,8)+']'; if wbReportMode then if wbReportFormIDs then begin if not Assigned(FoundSignatures) then FoundSignatures := TwbFastStringListCS.CreateSorted; if not FoundSignatures.Find('TRGT', i) then i := FoundSignatures.Add('TRGT'); FoundSignatures.Objects[i] := TObject(Succ(Integer(FoundSignatures.Objects[i]))); end; end else begin Result := 'NULL - Null Reference ['+IntToHex64(aInt,8)+']'; if wbReportMode then if wbReportFormIDs then begin if not Assigned(FoundSignatures) then FoundSignatures := TwbFastStringListCS.CreateSorted; if not FoundSignatures.Find('NULL', i) then i := FoundSignatures.Add('NULL'); FoundSignatures.Objects[i] := TObject(Succ(Integer(FoundSignatures.Objects[i]))); end; end; Used(aElement, Result); Exit; end else if aInt = $FFFFFFFF then begin Result := 'FFFF - None Reference ['+IntToHex64(aInt,8)+']'; if wbReportMode then if wbReportFormIDs then begin if not Assigned(FoundSignatures) then FoundSignatures := TwbFastStringListCS.CreateSorted; if not FoundSignatures.Find('FFFF', i) then i := FoundSignatures.Add('FFFF'); FoundSignatures.Objects[i] := TObject(Succ(Integer(FoundSignatures.Objects[i]))); end; Used(aElement, Result); Exit; end else if aInt = $14 then begin if wbReportMode then if wbReportFormIDs then begin if not Assigned(FoundSignatures) then FoundSignatures := TwbFastStringListCS.CreateSorted; if not FoundSignatures.Find('PLYR', i) then i := FoundSignatures.Add('PLYR'); FoundSignatures.Objects[i] := TObject(Succ(Integer(FoundSignatures.Objects[i]))); end; Result := 'Player ['+IntToHex64(aInt,8)+']'; Used(aElement, Result); Exit; end; if Assigned(aElement) then begin _File := aElement._File; if Assigned(_File) then begin try MainRecord := _File.RecordByFormID[aInt, True]; if Assigned(MainRecord) then begin Result := MainRecord.Name; if wbReportMode then if wbReportFormIDs then begin if not Assigned(FoundSignatures) then FoundSignatures := TwbFastStringListCS.CreateSorted; if not FoundSignatures.Find(MainRecord.Signature, i) then i := FoundSignatures.Add(MainRecord.Signature); FoundSignatures.Objects[i] := TObject(Succ(Integer(FoundSignatures.Objects[i]))); end; if wbReportFormIDNotAllowedReferences and (ClassType = TwbFormIDChecked) then with TwbFormIDChecked(Self) do begin if fidcValidRefs.IndexOf(MainRecord.Signature) < 0 then begin if not Assigned(FoundNotAllowedReferences) then FoundNotAllowedReferences := TwbFastStringListCS.CreateSorted; if not FoundNotAllowedReferences.Find(MainRecord.Name, i) then i := FoundNotAllowedReferences.Add(MainRecord.Name); FoundNotAllowedReferences.Objects[i] := TObject(Succ(Integer(FoundNotAllowedReferences.Objects[i]))); end; end; Used(aElement, Result); Exit; end; except on E: Exception do begin Result := '['+IntToHex64(aInt,8)+'] '; if wbReportMode then if wbReportFormIDs then begin if not Assigned(FoundSignatures) then FoundSignatures := TwbFastStringListCS.CreateSorted; if not FoundSignatures.Find('Error', i) then i := FoundSignatures.Add('Error'); FoundSignatures.Objects[i] := TObject(Succ(Integer(FoundSignatures.Objects[i]))); end; Used(aElement, Result); Exit; end; end; end; end; if aInt < $800 then begin s := IntToHex64(aInt,8); Result := '['+s+'] '; if wbReportMode then if wbReportFormIDs then begin if not Assigned(FoundSignatures) then FoundSignatures := TwbFastStringListCS.CreateSorted; if not FoundSignatures.Find('Hardcoded', i) then i := FoundSignatures.Add('Hardcoded'); FoundSignatures.Objects[i] := TObject(Succ(Integer(FoundSignatures.Objects[i]))); if not Assigned(NotResolved) then NotResolved := TwbFastStringListCS.CreateSorted; if NotResolved.Count < 50 then begin if not NotResolved.Find(s, i) then i := NotResolved.Add(s); NotResolved.Objects[i] := TObject(Succ(Integer(NotResolved.Objects[i]))); end; end; end else begin s := IntToHex64(aInt,8); Result := '['+s+'] < Error: Could not be resolved >'; if wbReportMode then if wbReportFormIDs then begin if not Assigned(FoundSignatures) then FoundSignatures := TwbFastStringListCS.CreateSorted; if not FoundSignatures.Find('NotResolved', i) then i := FoundSignatures.Add('NotResolved'); FoundSignatures.Objects[i] := TObject(Succ(Integer(FoundSignatures.Objects[i]))); if not Assigned(NotResolved) then NotResolved := TwbFastStringListCS.CreateSorted; if NotResolved.Count < 50 then begin if not NotResolved.Find(s, i) then i := NotResolved.Add(s); NotResolved.Objects[i] := TObject(Succ(Integer(NotResolved.Objects[i]))); end; end; end; Used(aElement, Result); end; { TwbByteArrayDef } function TwbByteArrayDef.CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; var ByteArrayDef: IwbByteArrayDef; begin Result := Supports(aDef, IwbByteArrayDef, ByteArrayDef); if Result and (badSize > 0) then begin Result := ByteArrayDef.IsVariableSize or (ByteArrayDef.DefaultSize[nil, nil, nil] <= Integer(badSize)); end; end; function TwbByteArrayDef.CanContainFormIDs: Boolean; begin Result := False; end; constructor TwbByteArrayDef.Clone(const aSource: TwbDef); begin with aSource as TwbByteArrayDef do Self.Create(defPriority, defRequired, noName, badSize, noDontShow, badCountCallBack, defGetCP, noTerminator).defSource := aSource; end; constructor TwbByteArrayDef.Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aName : string; aSize : Int64; aDontShow : TwbDontShowCallback; aCountCallback : TwbCountCallback; aGetCP : TwbGetConflictPriority; aTerminator : Boolean); begin badSize := aSize; badCountCallback := aCountCallback; inherited Create(aPriority, aRequired, aName, nil, nil, aDontShow, aGetCP, aTerminator); end; procedure TwbByteArrayDef.FromEditValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: string); var Bytes : array of Byte; i, j : Integer; Prefix : Integer; begin SetLength(Bytes, Length(aValue) div 2); i := 1; j := 0; while i <= Length(aValue) do begin case aValue[i] of ' ', ',', ';': {allowed whitespace} Inc(i); '0'..'9', 'a'..'f', 'A'..'F': begin if i = Length(aValue) then raise Exception.Create('Unexpected end of value. Single digit in hexadecimal pair'); if aValue[Succ(i)] in ['0'..'9', 'a'..'f', 'A'..'F'] then begin Bytes[j] := StrToInt('$'+Copy(aValue,i, 2)); Inc(j); Inc(i, 2); end else raise Exception.Create('"'+aValue[Succ(i)]+'" at position '+IntToStr(Succ(i))+' is not a valid character for ' + GetName); end; else raise Exception.Create('"'+aValue[i]+'" at position '+IntToStr(i)+' is not a valid character for ' + GetName); end; end; SetLength(Bytes, j); case badSize of -1 : Prefix := SizeOf(Cardinal); -2 : Prefix := SizeOf(Word); -4 : Prefix := SizeOf(Byte); else Prefix := 0; end; if (badSize > 0) then SetLength(Bytes, badSize); aElement.RequestStorageChange(aBasePtr, aEndPtr, Length(Bytes)+Prefix); if Length(Bytes) > 0 then Move(Bytes[0], Pointer(Cardinal(aBasePtr)+Prefix)^, Length(Bytes)); end; procedure TwbByteArrayDef.FromNativeValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: Variant); var Bytes : TBytes; Prefix : Integer; begin Bytes := aValue; case badSize of -1 : Prefix := SizeOf(Cardinal); -2 : Prefix := SizeOf(Word); -4 : Prefix := SizeOf(Byte); else Prefix := 0; end; if (badSize > 0) then SetLength(Bytes, badSize); aElement.RequestStorageChange(aBasePtr, aEndPtr, Length(Bytes)+Prefix); if Length(Bytes) > 0 then Move(Bytes[0], Pointer(Cardinal(aBasePtr)+Prefix)^, Length(Bytes)); end; function TwbByteArrayDef.GetDefType: TwbDefType; begin Result := dtByteArray; end; function TwbByteArrayDef.GetDefTypeName: string; begin if badSize > 0 then Result := IntToStr(badSize)+' Bytes Array' else if Assigned(badCountCallback) then Result := 'Variable Size Byte Array' else case badSize of -1 : Result := 'Variable Size Byte Array with four bytes length'; -2 : Result := 'Variable Size Byte Array with two bytes length'; -4 : Result := 'Variable Size Byte Array with one byte length'; -255 : Result := 'Null'; 0 : Result := 'Filler for remaining data'; end end; function TwbByteArrayDef.GetIsEditable(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Boolean; begin Result := True; end; function TwbByteArrayDef.GetIsVariableSizeInternal: Boolean; begin Result := badSize <= 0; end; function TwbByteArrayDef.GetSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; begin if Assigned(aBasePtr) and Assigned(aEndPtr) and (Cardinal(aBasePtr) >= Cardinal(aEndPtr)) then Result := 0 else if Assigned(badCountCallback) then Result := badCountCallback(aBasePtr, aEndPtr, aElement) else begin Result := badSize; if Assigned(aBasePtr) then case Result of -1 : Result := PCardinal(aBasePtr)^+SizeOf(Cardinal); -2 : Result := PWord(aBasePtr)^+SizeOf(Word); -4 : Result := PByte(aBasePtr)^+SizeOf(Byte); -255 : Result := 0; // Explicitly null for wbNull (displays better in unions) 0 : Result := High(Integer); end else if Result < 0 then Result := 0; end; if Result>0 then Inc(Result, Ord(noTerminator)); end; function TwbByteArrayDef.GetDefaultSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; begin if badSize>=0 then Result := badSize else case badSize of -1 : Result := SizeOf(Cardinal); -2 : Result := SizeOf(Word); -4 : Result := SizeOf(Byte); -255 : Result := 0; // Explicitly null for wbNull (displays better in unions) else Result := 0; end; if Result>0 then Inc(Result, Ord(noTerminator)); end; procedure TwbByteArrayDef.Report(const aParents: TwbDefPath); var FoundOne: Boolean; {i,} j, k, l : Integer; s: string; sl: TStringList; BA: TwbByteArrayDef; begin if defReported then Exit; inherited; BA := Self; s := wbDefsToPath(aParents) + wbDefToName(Self); if (Pos('Hashes', s) < 1) and (Pos('SCDA', s) < 1) and (Pos('SCTX', s) < 1) and (Pos('MODT', s) < 1) and (Pos('MO2T', s) < 1) and (Pos('MO3T', s) < 1) and (Pos('MO4T', s) < 1) and (Pos('DMDT', s) < 1) and (Pos('NIFT', s) < 1) and (Pos('XRGD', s) < 1) and (Pos('XCLP', s) < 1) and (Pos('RCLR', s) < 1) then begin if wbReportUnknownFormIDs then begin FoundOne := False; with BA do begin for j := Low(FoundFormIDAtOffSet) to High(FoundFormIDAtOffSet) do if (FoundFormIDAtOffSet[j] > 2) and (NotFoundFormIDAtOffSet[j] = 0) then begin if not FoundOne then begin FoundOne := True; WriteLn('Found FormIDs: ', s); end; with SignaturesAtOffSet[j] do begin WriteLn(' Offset ', j, ': ', Count, ' (', FoundFormIDAtOffSet[j],')'); for k := 0 to Pred(Count) do begin sl := Objects[k] as TStringList; WriteLn(' ', Strings[k], ' (', sl.Count,')'); with sl do for l := 0 to Pred(Count) do WriteLn(' ', Strings[l],' (',Integer(Objects[l]),') '); end; if Assigned(FormIDsAtOffSetFoundIn[j]) then with FormIDsAtOffSetFoundIn[j] do for k := 0 to Pred(Count) do WriteLn(' ', Strings[k]); end; end; end; end; if wbReportUnknownFloats then begin FoundOne := False; with BA do begin for j := Low(FoundFloatAtOffSet) to High(FoundFloatAtOffSet) do if (FoundFloatAtOffSet[j] > 2) and (NotFoundFloatAtOffSet[j] = 0) then begin if not FoundOne then begin FoundOne := True; WriteLn('Found Floats: ', s); end; with FloatsAtOffSet[j] do begin WriteLn(' Offset ', j, ': ', Count, ' (', FoundFloatAtOffSet[j],')'); for k := 0 to Pred(Count) do WriteLn(' ', Strings[k], ' (', Integer(Objects[k]),')'); end; end; end; end; end; if wbReportUnknownStrings then if (FoundString > 0) and (NotFoundString < 1) then begin WriteLn('Found Strings: ', s, ': ',Strings.Count,' (', FoundString, ')'); with Strings do for k := 0 to Pred(Count) do WriteLn(' ', Strings[k], ' (', Integer(Objects[k]),')'); end; if wbReportEmpty then if IsEmpty > 0 then if IsNotEmpty > 0 then begin if wbReportSometimesEmpty then WriteLn('Sometimes Empty: ', s, ': ', IsEmpty, ' (Empty) vs. ', IsNotEmpty, ' (not Empty)') end else WriteLn('Always Empty: ', s, ': ', IsEmpty, ' (Empty) vs. ', IsNotEmpty, ' (not Empty)'); defReported := True; end; function TwbByteArrayDef.SetToDefault(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Boolean; var Size : Integer; Default : String; begin Size := GetSize(aBasePtr, aEndPtr, aElement); if (Size > 0) and (Size < High(Integer)) then begin Default := '00'; while Length(Default)<(Size*3-1) do Default := Default + ' 00'; end else Default := ''; Result := not Assigned(aBasePtr) or (ToString(aBasePtr, aEndPtr, aElement) <> Default); if Result then FromEditValue(aBasePtr, aEndPtr, aElement, Default); end; function TwbByteArrayDef.ToEditValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; begin Result := ToString(aBasePtr, aEndPtr, aElement); end; function TwbByteArrayDef.ToNativeValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Variant; var Bytes: TBytes; begin case badSize of -1 : aBasePtr := Pointer(Cardinal(aBasePtr)+SizeOf(Cardinal)); -2 : aBasePtr := Pointer(Cardinal(aBasePtr)+SizeOf(Word)); -4 : aBasePtr := Pointer(Cardinal(aBasePtr)+SizeOf(Byte)); end; SetLength(Bytes, Cardinal(aEndPtr) - Cardinal(aBasePtr)); if Length(Bytes) > 0 then Move(aBasePtr^, Bytes[0], Length(Bytes)); Result := Bytes; end; function CountBits(aCardinal: Cardinal): Integer; var i: Integer; begin Result := 0; for I := 0 to 31 do if (aCardinal shr i) and 1 = 1 then Inc(Result); end; function TwbByteArrayDef.ToString(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; var p: PByte; {} _File: IwbFile; MainRecord: IwbMainRecord; OffSet: Integer; aInt: Cardinal; // Path : string; s: string; i: Integer; f, f2: Single; begin Result := ''; case badSize of -1 : aBasePtr := Pointer(Cardinal(aBasePtr)+SizeOf(Cardinal)); -2 : aBasePtr := Pointer(Cardinal(aBasePtr)+SizeOf(Word)); -4 : aBasePtr := Pointer(Cardinal(aBasePtr)+SizeOf(Byte)); end; p := aBasePtr; while Cardinal(p) < Cardinal(aEndPtr) do begin Result := Result + IntToHex64(p^, 2) + ' '; Inc(p); end; SetLength(Result, Length(Result) - 1); if wbReportMode then begin if Assigned(aElement) and (Self.noName <> 'Unused') then begin _File := aElement._File; if wbReportUnknownFormIDs then begin p := aBasePtr; OffSet := 0; while (Cardinal(p)+3) < Cardinal(aEndPtr) do begin aInt := PCardinal(p)^; if (aInt <> $0) and (aInt <> $14) and ((Length(NotFoundFormIDAtOffSet) < Succ(OffSet)) or (NotFoundFormIDAtOffSet[Offset] < 1)) then begin MainRecord := nil; try MainRecord := _File.RecordByFormID[aInt, True]; except on E: Exception do begin MainRecord := nil; end; end; if Length(FoundFormIDAtOffSet) < Succ(Offset) then SetLength(FoundFormIDAtOffSet, Succ(Offset)); if Length(NotFoundFormIDAtOffSet) < Succ(Offset) then SetLength(NotFoundFormIDAtOffSet, Succ(Offset)); if Length(SignaturesAtOffSet) < Succ(Offset) then SetLength(SignaturesAtOffSet, Succ(Offset)); if Length(FormIDsAtOffSetFoundIn) < Succ(Offset) then SetLength(FormIDsAtOffSetFoundIn, Succ(Offset)); if Assigned(MainRecord) then begin if (aInt > $14) and (CountBits(aInt) > 4) then begin Inc(FoundFormIDAtOffSet[Offset]); if not Assigned(SignaturesAtOffSet[Offset]) then SignaturesAtOffSet[Offset] := TwbFastStringListCS.CreateSorted; s := MainRecord.Signature; if not SignaturesAtOffSet[Offset].Find(s, i) then i := SignaturesAtOffSet[Offset].AddObject(s, TwbFastStringListCS.CreateSorted); s := MainRecord.Name; with TStringList(SignaturesAtOffSet[Offset].Objects[i]) do if Find(s, i) then Objects[i] := TObject(Succ(Integer(Objects[i]))) else if Count < 10 then AddObject(s, TObject(1)); if not Assigned(FormIDsAtOffSetFoundIn[Offset]) then FormIDsAtOffSetFoundIn[Offset] := TwbFastStringListCS.CreateSorted(dupIgnore); if FormIDsAtOffSetFoundIn[Offset].Count < 50 then FormIDsAtOffSetFoundIn[Offset].Add(aElement.FullPath); end; end else Inc(NotFoundFormIDAtOffSet[Offset]); end; Inc(p,4); Inc(OffSet,4); end; end; if wbReportUnknownFloats then begin p := aBasePtr; OffSet := 0; while (Cardinal(p)+3) < Cardinal(aEndPtr) do begin aInt := PCardinal(p)^; f := PSingle(p)^; if (aInt <> $0) and ((Length(NotFoundFloatAtOffSet) < Succ(OffSet)) or (NotFoundFloatAtOffSet[Offset] < 1)) then begin if Length(FoundFloatAtOffSet) < Succ(Offset) then SetLength(FoundFloatAtOffSet, Succ(Offset)); if Length(NotFoundFloatAtOffSet) < Succ(Offset) then SetLength(NotFoundFloatAtOffSet, Succ(Offset)); if Length(FloatsAtOffSet) < Succ(Offset) then SetLength(FloatsAtOffSet, Succ(Offset)); try f2 := RoundToEx(f, -3); {>>> Floating Point Violation <<<} if (f2 <> 0) and (Abs(f-f2) < 0.0002) then begin if (f2 > -1000000) and (f2 < 1000000) then begin Inc(FoundFloatAtOffSet[Offset]); if not Assigned(FloatsAtOffSet[Offset]) then FloatsAtOffSet[Offset] := TwbFastStringListCS.CreateSorted; s := FloatToStr(RoundToEx(f,-7)); with FloatsAtOffSet[Offset] do if Count < 15 then begin if not Find(s, i) then i := AddObject(s, TObject(0)); Objects[i] := TObject(Succ(Integer(Objects[i]))); end; end; end else Inc(NotFoundFloatAtOffSet[Offset]); except Inc(NotFoundFloatAtOffSet[Offset]); end; end; Inc(p,4); Inc(OffSet,4); end; end; if wbReportUnknownStrings then begin if (badSize < 1) and (NotFoundString < 1) then begin p := aBasePtr; while (Cardinal(p)) < Cardinal(aEndPtr) do begin if p^ < 32 then if (Succ(Cardinal(p)) = Cardinal(aEndPtr)) and (p^ = 0) then begin s := PAnsiChar(aBasePtr); if Length(s) > 4 then begin Inc(FoundString); if not Assigned(Strings) then Strings := TwbFastStringListCS.CreateSorted; with Strings do if Count < 15 then begin if not Find(s, i) then i := AddObject(s, TObject(0)); Objects[i] := TObject(Succ(Integer(Objects[i]))); end; end; end else begin Inc(NotFoundString); Break; end; Inc(p); end; end; end; if wbReportEmpty then begin if (Cardinal(aBasePtr)) < Cardinal(aEndPtr) then Inc(IsNotEmpty) else Inc(IsEmpty); end; end; end; Used(aElement, Result); end; { TwbDivDef } function TwbDivDef.CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; begin Result := True; end; function TwbDivDef.CanContainFormIDs: Boolean; begin Result := False; end; constructor TwbDivDef.Clone(const aSource: TwbDef); begin with aSource as TwbDivDef do Self.Create(ddValue).defSource := aSource; end; constructor TwbDivDef.Create(aValue: Integer); begin ddValue := aValue; inherited Create(cpNormal, False, nil); end; function TwbDivDef.FromEditValue(const aValue: string; const aElement: IwbElement): Int64; begin Result := Round(StrToFloat(aValue) * ddValue); end; function TwbDivDef.GetIsEditable(aInt: Int64; const aElement: IwbElement): Boolean; begin Result := True; end; function TwbDivDef.ToEditValue(aInt: Int64; const aElement: IwbElement): string; begin Result := FloatToStrF(aInt / ddValue, ffFixed, 99, wbFloatDigits); end; function TwbDivDef.ToSortKey(aInt: Int64; const aElement: IwbElement): string; const PlusMinus : array[Boolean] of string = ('+', '-'); begin Result := PlusMinus[aInt < 0] + IntToHex64(Abs(aInt), 16); end; function TwbDivDef.ToString(aInt: Int64; const aElement: IwbElement): string; begin Result := FloatToStrF(aInt / ddValue, ffFixed, 99, wbFloatDigits); Used(aElement, Result); end; { TwbMulDef } function TwbMulDef.CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; begin Result := True; end; function TwbMulDef.CanContainFormIDs: Boolean; begin Result := False; end; constructor TwbMulDef.Clone(const aSource: TwbDef); begin with aSource as TwbMulDef do Self.Create(mdValue).defSource := aSource; end; constructor TwbMulDef.Create(aValue: Integer); begin mdValue := aValue; inherited Create(cpNormal, False, nil); end; function TwbMulDef.FromEditValue(const aValue: string; const aElement: IwbElement): Int64; begin Result := StrToInt64(aValue) div mdValue; end; function TwbMulDef.GetIsEditable(aInt: Int64; const aElement: IwbElement): Boolean; begin Result := True; end; function TwbMulDef.ToEditValue(aInt: Int64; const aElement: IwbElement): string; begin Result := IntToStr(aInt * mdValue); end; function TwbMulDef.ToSortKey(aInt: Int64; const aElement: IwbElement): string; begin Result := ''; {handled by integer def} end; function TwbMulDef.ToString(aInt: Int64; const aElement: IwbElement): string; begin Result := IntToStr(aInt * mdValue); Used(aElement, Result); end; { TwbCallbackDef } function TwbCallbackDef.CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; var CallbackDef: IwbCallbackDef; begin Result := Supports(aDef, IwbCallbackDef, CallbackDef) and (@CallbackDef.Callback = @cdToStr); end; function TwbCallbackDef.CanContainFormIDs: Boolean; begin Result := False; end; function TwbCallbackDef.Check(aInt: Int64; const aElement: IwbElement): string; begin Result := cdToStr(aInt, aElement, ctCheck); end; constructor TwbCallbackDef.Clone(const aSource: TwbDef); begin with aSource as TwbCallbackDef do Self.Create(cdToStr, cdToInt).defSource := aSource; end; constructor TwbCallbackDef.Create(const aToStr : TwbIntToStrCallback; const aToInt : TwbStrToIntCallback); begin cdToStr := aToStr; cdToInt := aToInt; inherited Create(cpNormal, False, nil); end; function TwbCallbackDef.FromEditValue(const aValue: string; const aElement: IwbElement): Int64; begin if Assigned(cdToInt) then Result := cdToInt(aValue, aElement) else Result := StrToInt64(aValue) end; function TwbCallbackDef.GetCallback: TwbIntToStrCallback; begin Result := cdToStr; end; function TwbCallbackDef.GetEditInfo(aInt: Int64; const aElement: IwbElement): string; begin Result := cdToStr(aInt, aElement, ctEditInfo); end; function TwbCallbackDef.GetEditType(aInt: Int64; const aElement: IwbElement): TwbEditType; var s: string; begin Result := etDefault; s := cdToStr(aInt, aElement, ctEditType); if SameText(s, 'ComboBox') then Result := etComboBox else if SameText(s, 'CheckComboBox') then Result := etCheckComboBox; end; function TwbCallbackDef.GetIsEditable(aInt: Int64; const aElement: IwbElement): Boolean; begin Result := True; end; function TwbCallbackDef.ToEditValue(aInt: Int64; const aElement: IwbElement): string; begin Result := cdToStr(aInt, aElement, ctToEditValue); if Result = '' then Result := IntToStr(aInt); end; function TwbCallbackDef.ToSortKey(aInt: Int64; const aElement: IwbElement): string; begin Result := cdToStr(aInt, aElement, ctToSortKey); end; function TwbCallbackDef.ToString(aInt: Int64; const aElement: IwbElement): string; begin Result := cdToStr(aInt, aElement, ctToStr); Used(aElement, Result); end; { TwbValueDef } procedure TwbValueDef.BuildRef; begin {nothing} end; function TwbValueDef.Check(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; begin Result := ''; end; function TwbValueDef.CompareExchangeFormID(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aOldFormID, aNewFormID: Cardinal): Boolean; begin {can be overriden} Result := False; end; procedure TwbValueDef.FindUsedMasters(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aMasters: PwbUsedMasters); begin {can be overriden} end; procedure TwbValueDef.FromEditValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: string); begin raise Exception.Create(GetName + ' is not editable.'); end; procedure TwbValueDef.FromNativeValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: Variant); begin raise Exception.Create(GetName + ' is not editable.'); end; function TwbValueDef.GetCanBeZeroSize: Boolean; begin Result := False; end; function TwbValueDef.GetEditInfo(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; begin Result := ''; end; function TwbValueDef.GetEditType(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): TwbEditType; begin Result := etDefault; end; function TwbValueDef.GetElementMap: TDynCardinalArray; begin Result := nil; end; function TwbValueDef.GetIsEditable(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Boolean; begin Result := wbIsInternalEdit; end; function TwbValueDef.GetIsVariableSize: Boolean; begin if not (vdsIsVariableSizeChecked in vdStates) then begin if GetIsVariableSizeInternal then Include(vdStates, vdsIsVariableSize) else Exclude(vdStates, vdsIsVariableSize); Include(vdStates, vdsIsVariableSizeChecked) end; Result := vdsIsVariableSize in vdStates; end; function TwbValueDef.GetIsVariableSizeInternal: Boolean; begin Result := False; end; function TwbValueDef.GetLinksTo(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): IwbElement; begin Result := nil; end; procedure TwbValueDef.MasterCountUpdated(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aOld, aNew: Byte); begin {can be overriden} end; procedure TwbValueDef.MasterIndicesUpdated(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aOld, aNew: TBytes); begin {can be overriden} end; function TwbValueDef.SetToDefault(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Boolean; begin Result := False; {can be overriden} end; function TwbValueDef.ToEditValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; begin Result := ''; end; function TwbValueDef.ToNativeValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Variant; begin VarClear(Result); end; function TwbValueDef.ToSortKey(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aExtended: Boolean): string; begin Result := UpperCase(ToString(aBasePtr, aEndPtr, aElement)); end; { TwbSubRecordStructSKDef } constructor TwbSubRecordStructSKDef.Clone(const aSource: TwbDef); var SkipSigs : array of TwbSignature; i : Integer; begin with aSource as TwbSubRecordStructSKDef do begin if Assigned(srsSkipSignatures) then begin SetLength(SkipSigs, srsSkipSignatures.Count); for i := 0 to Pred(srsSkipSignatures.Count) do SkipSigs[i] := StrToSignature(srsSkipSignatures[i]); end; Self.Create(defPriority, defRequired, noName, srsMembers, SkipSigs, srsSortKey, srsExSortKey, noDontShow, srsAllowUnordered, noAfterLoad, noAfterSet, defGetCP).defSource := aSource; end; end; constructor TwbSubRecordStructSKDef.Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aName : string; const aMembers : array of IwbRecordMemberDef; const aSkipSigs : array of TwbSignature; const aSortKey : array of Integer; const aExSortKey : array of Integer; aDontShow : TwbDontShowCallback; aAllowUnordered : Boolean; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aGetCP : TwbGetConflictPriority); var i: Integer; begin SetLength(srsMemberInSK, Length(aMembers)); SetLength(srsSortKey, Length(aSortKey)); for i := Low(srsSortKey) to High(srsSortKey) do begin Assert( not srsMemberInSK[aSortKey[i]] ); srsMemberInSK[aSortKey[i]] := True; srsSortKey[i] := aSortKey[i]; end; SetLength(srsExSortKey, Length(aExSortKey)); for i := Low(srsExSortKey) to High(srsExSortKey) do srsExSortKey[i] := aExSortKey[i]; inherited Create(aPriority, aRequired, aName, aMembers, aSkipSigs, aDontShow, aAllowUnordered, aAfterLoad, aAfterSet, aGetCP); end; function TwbSubRecordStructSKDef.GetSortKey(aIndex: Integer; aExtended: Boolean): Integer; begin if aIndex <= High(srsSortKey) then Result := srsSortKey[aIndex] else Result := srsExSortKey[aIndex-Length(srsSortKey)]; end; function TwbSubRecordStructSKDef.GetSortKeyCount(aExtended: Boolean): Integer; begin Result := Length(srsSortKey); if aExtended then Inc(Result, Length(srsExSortKey)); end; function TwbSubRecordStructSKDef.IsInSK(aIndex: Integer): Boolean; begin Result := (aIndex >= Low(srsMemberInSK)) and (aIndex <= High(srsMemberInSK)) and srsMemberInSK[aIndex]; end; { TwbFormIDChecked } function TwbFormIDChecked.CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; var FormIDChecked : IwbFormIDChecked; i : Integer; Dummy : Integer; begin if Supports(aDef, IwbFormIDChecked, FormIDChecked) then begin Result := False; for i := 0 to Pred(FormIDChecked.SignatureCount) do if (FormIDChecked.Signatures[i] <> 'NULL') and (FormIDChecked.Signatures[i] <> 'TRGT') then if fidcValidRefs.Find(FormIDChecked.Signatures[i], Dummy) then begin Result := True; Exit; end; end else Result := inherited CanAssign(aElement, aIndex, aDef); end; function TwbFormIDChecked.Check(aInt: Int64; const aElement: IwbElement): string; var _File: IwbFile; MainRecord: IwbMainRecord; Found: TwbSignature; begin Result := ''; {>>> No ACVA errors <<<} if IsValid('ACVA') then Exit; if aInt = 0 then begin if IsValid('TRGT') and not IsValid('NULL') then begin Found := 'TRGT'; if fidcValidRefs.IndexOf(Found) < 0 then Result := 'Found a TRGT reference, expected: ' + fidcValidRefs.CommaText; end else begin Found := 'NULL'; if fidcValidRefs.IndexOf(Found) < 0 then Result := 'Found a NULL reference, expected: ' + fidcValidRefs.CommaText; end; Exit; end else if aInt = $FFFFFFFF then begin Found := 'FFFF'; if fidcValidRefs.IndexOf(Found) < 0 then Result := 'Found a None (FFFFFFFF) reference, expected: ' + fidcValidRefs.CommaText; Exit; end else if aInt = $14 then begin Found := 'PLYR'; if fidcValidRefs.IndexOf(Found) < 0 then Result := 'Found a PLYR reference, expected: ' + fidcValidRefs.CommaText; Exit; end; if Assigned(aElement) then begin _File := aElement._File; if Assigned(_File) then begin try MainRecord := _File.RecordByFormID[aInt, True]; if Assigned(MainRecord) then begin Found := MainRecord.Signature; if fidcValidRefs.IndexOf(Found) < 0 then Result := 'Found a '+Found+' reference, expected: ' + fidcValidRefs.CommaText else begin if fidcPersistent then if not MainRecord.WinningOverride.Flags.IsPersistent then begin Result := 'Target is not persistent'; Exit; end; if not CheckFlst(MainRecord) then Result := 'Referenced FLST contains invalid entry'; end; Exit; end; except on E: Exception do begin Result := E.Message; Exit; end; end; end; end; if aInt > $800 then Result := '['+IntToHex64(aInt,8)+'] < Error: Could not be resolved >'; end; function TwbFormIDChecked.CheckFlst(const aMainRecord: IwbMainRecord): Boolean; var Container : IwbContainerElementRef; i, j : Integer; MainRecord : IwbMainRecord; begin Result := True; if fidcValidFlstRefs.Count < 1 then Exit; if aMainRecord.Signature <> 'FLST' then Exit; if Supports(aMainRecord.ElementByName['FormIDs'], IwbContainerElementRef, Container) then for i := 0 to Pred(Container.ElementCount) do if Supports(Container.Elements[i].LinksTo, IwbMainRecord, MainRecord) then if not fidcValidFlstRefs.Find(MainRecord.Signature, j) then begin Result := False; Exit; end; end; constructor TwbFormIDChecked.Clone(const aSource: TwbDef); begin with aSource as TwbFormIDChecked do Self.Create(fidcValidRefsArr, fidcValidFlstRefsArr, fidcPersistent, fidcNoReach).defSource := aSource; end; constructor TwbFormIDChecked.Create(const aValidRefs : array of TwbSignature; const aValidFlstRefs : array of TwbSignature; aPersistent : Boolean; aNoReach : Boolean); var i: Integer; begin fidcPersistent := aPersistent; fidcNoReach := aNoReach; fidcValidRefs := TwbFastStringListCS.CreateSorted; SetLength(fidcValidRefsArr, Length(aValidRefs)); for i := Low(aValidRefs) to High(aValidRefs) do begin fidcValidRefsArr[i] := aValidRefs[i]; fidcValidRefs.Add(aValidRefs[i]); end; fidcValidFlstRefs := TwbFastStringListCS.CreateSorted; SetLength(fidcValidFlstRefsArr, Length(aValidFlstRefs)); for i := Low(aValidFlstRefs) to High(aValidFlstRefs) do begin fidcValidFlstRefsArr[i] := aValidFlstRefs[i]; fidcValidFlstRefs.Add(aValidFlstRefs[i]); end; inherited Create(cpNormal, False, nil); end; destructor TwbFormIDChecked.Destroy; begin FreeAndNil(fidcValidRefs); FreeAndNil(fidcValidFlstRefs); inherited; end; function TwbFormIDChecked.FromEditValue(const aValue: string; const aElement: IwbElement): Int64; var Error: string; begin Result := inherited FromEditValue(aValue, aElement); if not wbAllowErrors then begin Error := Check(Result, aElement); if Error <> '' then raise Exception.Create(Error); end; end; function TwbFormIDChecked.GetNoReach: Boolean; begin Result := fidcNoReach; end; function TwbFormIDChecked.GetSignature(aIndex: Integer): TwbSignature; begin Result := StrToSignature(fidcValidRefs[aIndex]); end; function TwbFormIDChecked.GetSignatureCount: Integer; begin Result := fidcValidRefs.Count; end; function TwbFormIDChecked.IsValid(const aSignature: TwbSignature): Boolean; begin Result := fidcValidRefs.IndexOf(aSignature) >= 0; end; function TwbFormIDChecked.IsValidFlst(const aSignature: TwbSignature): Boolean; begin Result := (fidcValidFlstRefs.Count = 0) or (fidcValidFlstRefs.IndexOf(aSignature) >= 0); end; function TwbFormIDChecked.IsValidMainRecord(const aMainRecord: IwbMainRecord): Boolean; begin Result := not fidcPersistent or aMainRecord.IsPersistent; end; procedure TwbFormIDChecked.Report(const aParents: TwbDefPath); var i, j : Integer; s : string; Sigs : TStringList; begin if defReported then Exit; inherited; if wbReportMode then if wbReportFormIDs and Assigned(FoundSignatures) and (FoundSignatures.Count > 0) then begin s := ''; Sigs := TwbFastStringListCS.CreateSorted; try Sigs.AddStrings(FoundSignatures); for i := 0 to Pred(fidcValidRefs.Count) do if Sigs.Find(fidcValidRefs[i], j) then Sigs.Delete(j) else s := s + fidcValidRefs[i] + ','; SetLength(s, Pred(Length(s))); if not wbReportNotFoundButAllowedFormIDs then s := ''; if (s <> '') or (Sigs.Count > 0) then begin WriteLn('Differences in Checked FormID Formater: ', wbDefsToPath(aParents), wbDefToName(Self)); if s <> '' then WriteLn(' Not found but allowed: ', s); if Sigs.Count > 0 then begin WriteLn(' Found but not allowed: ', Sigs.CommaText); for i := 0 to Pred(Sigs.Count) do WriteLn(' ', Sigs.Strings[i], ' (', Integer(Sigs.Objects[i]),')'); end; end; finally Sigs.Free; end; end; defReported := True; end; { TwbIntegerDefFormater } procedure TwbIntegerDefFormater.BuildRef(aInt: Int64; const aElement: IwbElement); begin { nothing } end; function TwbIntegerDefFormater.CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; begin Result := False; end; function TwbIntegerDefFormater.Check(aInt: Int64; const aElement: IwbElement): string; begin Result := ''; end; constructor TwbIntegerDefFormater.Clone(const aSource: TwbDef); begin with aSource as TwbIntegerDefFormater do Self.Create(defPriority, defRequired, defGetCP).defSource := aSource; end; function TwbIntegerDefFormater.CompareExchangeFormID(var aInt: Int64; aOldFormID, aNewFormID: Cardinal; const aElement: IwbElement): Boolean; begin Result := False; // ? Should be overriden end; procedure TwbIntegerDefFormater.FindUsedMasters(aInt: Int64; aMasters: PwbUsedMasters; const aElement: IwbElement); begin {can be overriden} end; function TwbIntegerDefFormater.FromEditValue(const aValue: string; const aElement: IwbElement): Int64; begin raise Exception.Create(Classname + ' does not support editing'); end; function TwbIntegerDefFormater.GetDefType: TwbDefType; begin Result := dtIntegerFormater; end; function TwbIntegerDefFormater.GetDefTypeName: string; begin Result := ClassName; end; function TwbIntegerDefFormater.GetEditInfo(aInt: Int64; const aElement: IwbElement): string; begin Result := ''; end; function TwbIntegerDefFormater.GetEditType(aInt: Int64; const aElement: IwbElement): TwbEditType; begin Result := etDefault; end; function TwbIntegerDefFormater.GetIsEditable(aInt: Int64; const aElement: IwbElement): Boolean; begin Result := wbIsInternalEdit; end; function TwbIntegerDefFormater.GetLinksTo(aInt: Int64; const aElement: IwbElement): IwbElement; begin Result := nil; end; function TwbIntegerDefFormater.GetRequiresKey: Boolean; begin Result := False; end; function TwbIntegerDefFormater.MasterCountUpdated(aInt: Int64; aOld, aNew: Byte; const aElement: IwbElement): Int64; begin Result := aInt; end; function TwbIntegerDefFormater.MasterIndicesUpdated(aInt: Int64; const aOld, aNew: TBytes; const aElement: IwbElement): Int64; begin Result := aInt; end; function TwbIntegerDefFormater.ToEditValue(aInt: Int64; const aElement: IwbElement): string; begin Result := ''; end; { TwbUnionDef } procedure TwbUnionDef.BuildRef(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement); var ValueDef : IwbValueDef; begin inherited; ValueDef := Decide(aBasePtr, aEndPtr, aElement); if Assigned(ValueDef) then ValueDef.BuildRef(aBasePtr, aEndPtr, aElement); end; function TwbUnionDef.CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef): Boolean; var UnionDef : IwbUnionDef; i : Integer; begin if Supports(aDef, IwbUnionDef, UnionDef) then begin Result := Equals(aDef); if not Result then for i := 0 to Pred(UnionDef.MemberCount) do begin Result := CanAssign(aElement, aIndex, UnionDef.Members[i]); if Result then Exit; end; end else begin Result := False; for i := 0 to Pred(GetMemberCount) do begin Result := udMembers[i].CanAssign(aElement, aIndex, aDef); if Result then Exit; end; end; end; function TwbUnionDef.CanContainFormIDs: Boolean; begin Result := ubCanContainFormIDs; end; function TwbUnionDef.Check(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; begin Result := Decide(aBasePtr, aEndPtr, aElement).Check(aBasePtr, aEndPtr, aElement); end; constructor TwbUnionDef.Clone(const aSource: TwbDef); begin with aSource as TwbUnionDef do Self.Create(defPriority, defRequired, noName, udDecider, udMembers, noDontShow, noAfterSet, defGetCP).defSource := aSource; end; constructor TwbUnionDef.Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aName : string; aDecider : TwbUnionDecider; const aMembers : array of IwbValueDef; aDontShow : TwbDontShowCallback; aAfterSet : TwbAfterSetCallback; aGetCP : TwbGetConflictPriority); var i: Integer; begin inherited Create(aPriority, aRequired, aName, nil, aAfterSet, aDontShow, aGetCP, False); udDecider := aDecider; SetLength(udMembers, Length(aMembers)); for I := Low(udMembers) to High(udMembers) do begin udMembers[i] := (aMembers[i] as IwbDefInternal).SetParent(Self, False) as IwbValueDef; ubCanContainFormIDs := ubCanContainFormIDs or aMembers[i].CanContainFormIDs; end; end; function TwbUnionDef.Decide(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): IwbValueDef; var aMemberIndex : Integer; begin aMemberIndex := udDecider(aBasePtr, aEndPtr, aElement); if (aMemberIndex>=0) and (aMemberIndex j then begin j := -1; break; end; Result := j = -1; end; end; function TwbUnionDef.GetLinksTo(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): IwbElement; var ValueDef: IwbValueDef; begin ValueDef := Decide(aBasePtr, aEndPtr, aElement); if Assigned(ValueDef) then Result := ValueDef.LinksTo[aBasePtr, aEndPtr, aElement] else Result := nil; end; function TwbUnionDef.GetMember(aIndex: Integer): IwbValueDef; begin Result := udMembers[aIndex]; end; function TwbUnionDef.GetMemberCount: Integer; begin Result := Length(udMembers); end; function TwbUnionDef.GetSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; var i : Integer; Size : Integer; aMember : IwbValueDef; Container : IwbContainerElementRef; Element : IwbElement; begin // if Assigned(aBasePtr) and Assigned(aEndPtr) and (Cardinal(aEndPtr) '+IntToHex64(Cardinal(aEndPtr), 8)+' for '+noName); // end; if GetIsVariableSize then aMember := Decide(aBasePtr, aEndPtr, aElement) else aMember := nil;; if not Assigned(aMember) then begin if Length(udMembers)>0 then Result := udMembers[0].Size[aBasePtr, aEndPtr, aElement] else Result := Low(Integer); if (Result > 0) and GetIsVariableSize then for i := 1 to High(udMembers) do if Result <> High(Integer) then begin Size := udMembers[i].Size[aBasePtr, aEndPtr, aElement]; if Size = 0 then begin // No valid value can be found Result := 0; Break; end else if Result < Size then Result := Size; end else break; end else begin if GetIsVariableSize and Supports(aElement, IwbContainerElementRef, Container) and Equals(Container.ValueDef) and (Container.ElementCount = 1) then begin Element := Container.Elements[0]; if not aMember.Equals(Element.ValueDef) then Element := nil; end; if not Assigned(Element) then Element := aElement; Result := aMember.Size[aBasePtr, aEndPtr, Element]; if Result = High(Integer) then Exit; if Assigned(aBasePtr) and Assigned(aEndPtr) and (Cardinal(aEndPtr)aBasePtr) then // wbProgressCallback('Found a union with a negative size! (2) '+IntToHex64(Cardinal(aBasePtr)+Result, 8)+ // ' > '+IntToHex64(Cardinal(aEndPtr), 8)+' for '+noName); Result := Cardinal(aEndPtr)-Cardinal(aBasePtr); end; end; end; function TwbUnionDef.GetDefaultSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; var aMember : IwbValueDef; begin aMember := Decide(aBasePtr, aEndPtr, aElement); if Assigned(aMember) then Result := aMember.DefaultSize[aBasePtr, aEndPtr, aElement] else Result := 0; end; procedure TwbUnionDef.Report(const aParents: TwbDefPath); var Parents : TwbDefPath; i : Integer; begin if defReported then Exit; inherited; Parents := aParents; SetLength(Parents, Succ(Length(Parents))); Parents[High(Parents)].Def := Self; for i := Low(udMembers) to High(udMembers) do if Assigned(udMembers[i]) then begin Parents[High(Parents)].Index := i; udMembers[i].Report(Parents); end; defReported := True; end; function TwbUnionDef.SetToDefault(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Boolean; var ValueDef: IwbValueDef; begin ValueDef := Decide(aBasePtr, aEndPtr, aElement); if Assigned(ValueDef) then Result := ValueDef.SetToDefault(aBasePtr, aEndPtr, aElement) else Result := False; end; function TwbUnionDef.ToEditValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; var ValueDef: IwbValueDef; begin ValueDef := Decide(aBasePtr, aEndPtr, aElement); if Assigned(ValueDef) then Result := ValueDef.EditValue[aBasePtr, aEndPtr, aElement] else Result := ''; end; function TwbUnionDef.ToNativeValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Variant; var ValueDef: IwbValueDef; begin ValueDef := Decide(aBasePtr, aEndPtr, aElement); if Assigned(ValueDef) then Result := ValueDef.NativeValue[aBasePtr, aEndPtr, aElement] else Result := ''; end; function TwbUnionDef.ToSortKey(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aExtended: Boolean): string; var ValueDef: IwbValueDef; begin ValueDef := Decide(aBasePtr, aEndPtr, aElement); if Assigned(ValueDef) then Result := ValueDef.ToSortKey(aBasePtr, aEndPtr, aElement, aExtended) else Result := ''; end; function TwbUnionDef.ToString(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; var ValueDef: IwbValueDef; begin ValueDef := Decide(aBasePtr, aEndPtr, aElement); if Assigned(ValueDef) then Result := ValueDef.ToString(aBasePtr, aEndPtr, aElement) else Result := ''; Used(aElement, Result); end; { TwbEmptyDef } function TwbEmptyDef.CanContainFormIDs: Boolean; begin Result := False; end; constructor TwbEmptyDef.Clone(const aSource: TwbDef); begin with aSource as TwbEmptyDef do Self.Create(defPriority, defRequired, noName, noAfterLoad, noAfterSet, noDontShow, edSorted, defGetCP).defSource := aSource; end; constructor TwbEmptyDef.Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aName : string; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aDontShow : TwbDontShowCallback; aSorted : Boolean; aGetCP : TwbGetConflictPriority); begin edSorted := aSorted; inherited Create(aPriority, aRequired, aName, aAfterLoad, aAfterSet, aDontShow, aGetCP, False); end; procedure TwbEmptyDef.FromEditValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: string); begin end; function TwbEmptyDef.GetCanBeZeroSize: Boolean; begin Result := True; end; function TwbEmptyDef.GetDefType: TwbDefType; begin Result := dtEmpty; end; function TwbEmptyDef.GetDefTypeName: string; begin Result := 'Place holder for optional elements'; end; function TwbEmptyDef.GetIsEditable(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Boolean; begin Result := True; end; function TwbEmptyDef.GetSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; begin Result := 0; end; function TwbEmptyDef.GetDefaultSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; begin Result := 0; end; function TwbEmptyDef.GetSorted: Boolean; begin Result := edSorted; end; function TwbEmptyDef.ToSortKey(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aExtended: Boolean): string; //var // NamedDef: IwbNamedDef; begin // Result := GetName; // if (Result = '') and Supports(defParent, IwbNamedDef, NamedDef) then // Result := NamedDef.Name; // if Result = '' then Result := ''; // Result := ''; end; function TwbEmptyDef.ToString(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; //var // NamedDef: IwbNamedDef; begin // Result := GetName; // if (Result = '') and Supports(defParent, IwbNamedDef, NamedDef) then // Result := NamedDef.Name; Result := ''; Used(aElement, Result); end; { TwbMainRecordStructFlags } function TwbMainRecordStructFlags.CantWait: Boolean; begin Result := (_Flags and $00080000) <> 0; end; function TwbMainRecordStructFlags.CastsShadows: Boolean; begin Result := (_Flags and $00000200) <> 0; end; function TwbMainRecordStructFlags.HasLODtree: Boolean; begin Result := (_Flags and $00000040) <> 0; end; function TwbMainRecordStructFlags.IsCompressed: Boolean; begin Result := (_Flags and $00040000) <> 0; end; function TwbMainRecordStructFlags.IsDangerous: Boolean; begin Result := (_Flags and $00020000) <> 0; end; function TwbMainRecordStructFlags.IsDeleted: Boolean; begin Result := (_Flags and $00000020) <> 0; end; function TwbMainRecordStructFlags.IsLocalized: Boolean; begin Result := (_Flags and $00000080) <> 0; end; function TwbMainRecordStructFlags.IsESM: Boolean; begin Result := (_Flags and $00000001) <> 0; end; function TwbMainRecordStructFlags.IsIgnored: Boolean; begin Result := (_Flags and $00001000) <> 0; end; function TwbMainRecordStructFlags.IsInitiallyDisabled: Boolean; begin Result := (_Flags and $00000800) <> 0; end; function TwbMainRecordStructFlags.IsPersistent: Boolean; begin Result := (_Flags and $00000400) <> 0; end; function TwbMainRecordStructFlags.IsVisibleWhenDistant: Boolean; begin Result := (_Flags and $00008000) <> 0; end; procedure TwbMainRecordStructFlags.SetCompressed(aValue: Boolean); begin if aValue then _Flags := _Flags or $00040000 else _Flags := _Flags and not $00040000; end; procedure TwbMainRecordStructFlags.SetDeleted(aValue: Boolean); begin if aValue then _Flags := _Flags or $00000020 else _Flags := _Flags and not $00000020; end; procedure TwbMainRecordStructFlags.SetESM(aValue: Boolean); begin if aValue then _Flags := _Flags or $00000001 else _Flags := _Flags and not $00000001; end; procedure TwbMainRecordStructFlags.SetLocalized(aValue: Boolean); begin if aValue then _Flags := _Flags or $00000080 else _Flags := _Flags and not $00000080 end; procedure TwbMainRecordStructFlags.SetInitiallyDisabled(aValue: Boolean); begin if aValue then _Flags := _Flags or $00000800 else _Flags := _Flags and not $00000800; end; procedure TwbMainRecordStructFlags.SetPersistent(aValue: Boolean); begin if aValue then _Flags := _Flags or $00000400 else _Flags := _Flags and not $00000400; end; procedure TwbMainRecordStructFlags.SetVisibleWhenDistant(aValue: Boolean); begin if aValue then _Flags := _Flags or $00008000 else _Flags := _Flags and not $00008000; end; { TwbLenStringDef } function TwbLenStringDef.CanAssign(const aElement: IwbElement; aIndex: Integer; const aDef: IwbDef) : Boolean; begin Result := aDef.DefType in [dtString, dtLString, dtLenString]; end; function TwbLenStringDef.CanContainFormIDs: Boolean; begin Result := False; end; function TwbLenStringDef.Check(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; var Size : Cardinal; Len : Cardinal; begin Result := ''; Len := Cardinal(aEndPtr) - Cardinal(aBasePtr); if Len < GetPrefixOffset then begin if wbCheckExpectedBytes then Result := Format('Expected at least %d bytes of data, found %d', [Abs(Prefix) , Len]); Exit; end; Size := GetPrefixValue(aBasePtr, aEndPtr, aElement) + GetPrefixOffset; if Len < Size then begin if wbCheckExpectedBytes then Result := Format('Expected %d bytes of data, found %d', [Size , Len]); end; end; constructor TwbLenStringDef.Clone(const aSource: TwbDef); begin with aSource as TwbLenStringDef do Self.Create(defPriority, defRequired, noName, Prefix, noAfterLoad, noAfterSet, noDontShow, defGetCP, noTerminator).defSource := aSource; end; constructor TwbLenStringDef.Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aName : string; aPrefix : Integer; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aDontShow : TwbDontShowCallback; aGetCP : TwbGetConflictPriority; aTerminator : Boolean); begin Prefix := aPrefix; if not (Abs(Prefix) in [1, 2, 3, 4, 5]) then Prefix := 4; inherited Create(aPriority, aRequired, aName, aAfterLoad, aAfterSet, aDontShow, aGetCP, aTerminator); end; procedure TwbLenStringDef.FromEditValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: string); var Len : Cardinal; NewSize : Cardinal; p : Pointer; s : AnsiString; begin s := AnsiString(aValue); Len := Length(s); NewSize := Len + GetPrefixOffset; aElement.RequestStorageChange(aBasePtr, aEndPtr, NewSize + Ord(noTerminator)); SetPrefixValue(aBasePtr, aEndPtr, aElement, Len); p := Pointer(Cardinal(aBasePtr) + GetPrefixOffset); if Len > 0 then Move(s[1], p^, Len); if noTerminator then begin Inc(PByte(p), Len+1); PByte(p)^ := wbTerminator; end; end; procedure TwbLenStringDef.FromNativeValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: Variant); begin FromEditValue(aBasePtr, aEndPtr, aElement, aValue); end; function TwbLenStringDef.GetDefType: TwbDefType; begin Result := dtLenString; end; function TwbLenStringDef.GetDefTypeName: string; begin if Prefix > 0 then Result := 'String with length of '+IntToStr(Prefix)+' bytes' else Result := 'Separated String with length of '+IntToStr(GetPrefixLen)+' bytes' end; function TwbLenStringDef.GetIsEditable(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Boolean; begin Result := True; end; function TwbLenStringDef.GetIsVariableSizeInternal: Boolean; begin Result := True; end; function TwbLenStringDef.GetPrefixLen: Integer; begin case Prefix of 1, -2: Result := 1; 2, -3: Result := 2; 4, -5: Result := 4; else Result := 0; end; end; function TwbLenStringDef.GetPrefixOffset: Integer; begin Result := Abs(Prefix); end; function TwbLenStringDef.GetPrefixValue(aBasePtr: Pointer; aEndPtr: Pointer; const aElement: IwbElement): Integer; begin case Prefix of 1, -2: Result := PByte(aBasePtr)^; 2, -3: Result := PWord(aBasePtr)^; 4, -5: Result := PCardinal(aBasePtr)^; else Result := 0; end; end; function TwbLenStringDef.GetSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; var Len : Integer; begin if Assigned(aBasePtr) and Assigned(aEndPtr) then if (Cardinal(aBasePtr) >= Cardinal(aEndPtr)) then Result := 0 else begin Result := Cardinal(aEndPtr) - Cardinal(aBasePtr); Len := GetPrefixValue(aBasePtr, aEndPtr, aElement); if Len>0 then Len := Len+GetPrefixOffset+Ord(noTerminator) else Len := GetPrefixOffset; if Len>Result then Exit; if Len < Result then Result := Len; end else Result := GetPrefixOffset; end; function TwbLenStringDef.GetDefaultSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; begin Result := GetPrefixOffset+Ord(noTerminator); end; procedure TwbLenStringDef.SetPrefixValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aValue: Cardinal); begin case Prefix of 1, -2: PByte(aBasePtr)^ := aValue; 2, -3: PWord(aBasePtr)^ := aValue; 4, -5: PCardinal(aBasePtr)^ := aValue; end; end; function TwbLenStringDef.SetToDefault(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Boolean; begin Result := not Assigned(aBasePtr) or (ToString(aBasePtr, aEndPtr, aElement) <> ''); if Result then FromEditValue(aBasePtr, aEndPtr, aElement, ''); end; function TwbLenStringDef.ToEditValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; begin Result := ToString(aBasePtr, aEndPtr, aElement); end; function TwbLenStringDef.ToNativeValue(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Variant; begin Result := ToString(aBasePtr, aEndPtr, aElement); end; function TwbLenStringDef.ToString(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; var Size : Cardinal; Len : Cardinal; s : AnsiString; begin s := ''; Len := Cardinal(aEndPtr) - Cardinal(aBasePtr); if Len Size then Len := Size; SetLength(s, Len); if Len > 0 then Move(aBasePtr^, s[1], Len); Result := wbAnsiToString(s, aElement); Used(aElement, Result); end; { TwbFastStringList } procedure TwbFastStringList.Clear(aFreeObjects: Boolean); var i: Integer; begin if aFreeObjects then for i := 0 to Pred(Count) do Objects[i].Free; inherited Clear; end; function TwbFastStringList.CompareStrings(const S1, S2: string): Integer; begin if CaseSensitive then Result := CompareStr(S1, S2) else Result := CompareText(S1, S2); end; constructor TwbFastStringList.CreateSorted(aDups: TDuplicates); begin Create; Duplicates := aDups; Sorted := True; end; { TwbFastStringListCS } procedure TwbFastStringListCS.AfterConstruction; begin inherited; CaseSensitive := True; end; { TwbStringLCDef } function TwbStringLCDef.TransformString(const s: AnsiString; aTransformType: TwbStringTransformType; const aElement: IwbElement): AnsiString; begin Result := LowerCase(s); end; { TwbLString } function TwbLStringDef.GetDefType: TwbDefType; begin Result := dtLString; end; function TwbLStringDef.GetDefTypeName: string; begin Result := 'Localized String'; end; procedure TwbLStringDef.FromStringNative(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aValue: AnsiString); var ID: Cardinal; begin if Copy(aValue, 1, Length(sStringID)) = sStringID then begin aElement.RequestStorageChange(aBasePtr, aEndPtr, SizeOf(Cardinal)); PCardinal(aBasePtr)^ := StrToInt64Def('$' + Copy(aValue, Succ(Length(sStringID)), Length(aValue)), 0); Exit; end; if aElement._File.IsLocalized then if wbLocalizationHandler.NoTranslate then // assign a string when delocalizing and NoTranslate is true inherited FromStringNative(aBasePtr, aEndPtr, aElement, aValue) else begin // set localized string's value ID := wbLocalizationHandler.SetValue(PCardinal(aBasePtr)^, aElement, aValue); aElement.RequestStorageChange(aBasePtr, aEndPtr, SizeOf(Cardinal)); PCardinal(aBasePtr)^ := ID; //raise Exception.Create('Can not assign to a localized string') end else inherited FromStringNative(aBasePtr, aEndPtr, aElement, aValue); end; function TwbLStringDef.GetSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; begin if Assigned(aBasePtr) and Assigned(aEndPtr) and (Cardinal(aBasePtr) >= Cardinal(aEndPtr)) then Result := 0 else if Assigned(aBasePtr) and Assigned(aEndPtr) and Assigned(aElement._File) and aElement._File.IsLocalized then Result := Min(4, Cardinal(aEndPtr) - Cardinal(aBasePtr)) else Result := inherited GetSize(aBasePtr, aEndPtr, aElement); end; function TwbLStringDef.GetDefaultSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; begin if Assigned(aElement._File) and aElement._File.IsLocalized then Result := 4 else Result := inherited GetDefaultSize(aBasePtr, aEndPtr, aElement); end; function TwbLStringDef.ToStringNative(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): AnsiString; begin if Assigned(aElement._File) and aElement._File.IsLocalized then begin if (Cardinal(aEndPtr) - Cardinal(aBasePtr)) <> 4 then Result := '< Error: lstring ID should be Int32 value >' else Result := wbStringToAnsi(wbLocalizationHandler.GetValue(PCardinal(aBasePtr)^, aElement), aElement) end else Result := inherited ToStringNative(aBasePtr, aEndPtr, aElement); end; { TwbStringScriptDef } function TwbStringScriptDef.TransformString(const s: AnsiString; aTransformType: TwbStringTransformType; const aElement: IwbElement): AnsiString; var i: Integer; begin if aTransformType = ttToSortKey then begin with TStringList.Create do try Text := s; for i := Pred(Count) downto 0 do begin Strings[i] := Trim(Strings[i]); if Strings[i] = '' then Delete(i); end; Result := AnsiString(Text); finally Free; end; end else Result := s; end; { TwbStringMgefCodeDef } procedure TwbStringMgefCodeDef.BuildRef(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement); var _File : IwbFile; Rec : IwbMainRecord; begin _File := aElement._File; if Assigned(_File) then begin Rec := _File.RecordByEditorID[ToStringTransform(aBasePtr, aEndPtr, aElement, ttToSortKey)]; if Assigned(Rec) then aElement.AddReferencedFromID(Rec.LoadOrderFormID); end; end; function TwbStringMgefCodeDef.CanContainFormIDs: Boolean; begin Result := True; end; procedure TwbStringMgefCodeDef.FindUsedMasters(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aMasters: PwbUsedMasters); var s : AnsiString; MgefCode : PCardinal; begin s := ToStringNative(aBasePtr, aEndPtr, aElement); if Length(s) <> 4 then Exit; MgefCode := PCardinal(@s[1]); if (MgefCode^ and $80000000) <> 0 then { yes, it's a dynamic code } aMasters[(MgefCode^ and $000000FF)] := True; end; function TwbStringMgefCodeDef.GetLinksTo(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): IwbElement; var _File : IwbFile; begin Result := nil; _File := aElement._File; if Assigned(_File) then Result := _File.RecordByEditorID[ToStringTransform(aBasePtr, aEndPtr, aElement, ttToSortKey)]; end; procedure TwbStringMgefCodeDef.MasterCountUpdated(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aOld, aNew: Byte); var s : AnsiString; MgefCode : PCardinal; begin s := ToStringNative(aBasePtr, aEndPtr, aElement); if Length(s) <> 4 then Exit; MgefCode := PCardinal(@s[1]); if (MgefCode^ and $80000000) <> 0 then { yes, it's a dynamic code } if (MgefCode^ and $000000FF) >= aOld then begin { yes, it refers to this file } MgefCode^ := (MgefCode^ and $FFFFFF00) or aNew; FromStringNative(aBasePtr, aEndPtr, aElement, s); aElement.NotifyChanged(Pointer(aElement.Container)); end; end; procedure TwbStringMgefCodeDef.MasterIndicesUpdated(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; const aOld, aNew: TBytes); var s : AnsiString; MgefCode : PCardinal; i : Integer; begin s := ToStringNative(aBasePtr, aEndPtr, aElement); if Length(s) <> 4 then Exit; MgefCode := PCardinal(@s[1]); Assert(Length(aOld) = Length(aNew)); if (MgefCode^ and $80000000) <> 0 then { yes, it's a dynamic code } for i := Low(aOld) to High(aOld) do if (MgefCode^ and $000000FF) = aOld[i] then begin { yes, it refers to this file } MgefCode^ := (MgefCode^ and $FFFFFF00) or aNew[i]; FromStringNative(aBasePtr, aEndPtr, aElement, s); aElement.NotifyChanged(Pointer(aElement.Container)); Exit; end; end; function TwbStringMgefCodeDef.SetToDefault(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Boolean; begin Result := not Assigned(aBasePtr) or (ToString(aBasePtr, aEndPtr, aElement) <> '____'); if Result then FromEditValue(aBasePtr, aEndPtr, aElement, '____'); end; function TwbStringMgefCodeDef.TransformString(const s: AnsiString; aTransformType: TwbStringTransformType; const aElement: IwbElement): AnsiString; var IsAlpha : Boolean; i, j : Integer; MgefCode : Cardinal; _File : IwbFile; FileID : Byte; t : AnsiString; begin case aTransformType of ttToString, ttToSortKey, ttToEditValue, ttToNativeValue: begin Result := s; if Length(s) = 4 then begin IsAlpha := True; for i := 1 to 4 do if not(s[i] in ['a'..'z', 'A'..'Z', '0'..'9', '_']) then begin IsAlpha := False; break; end; if not IsAlpha then begin MgefCode := PCardinal(@s[1])^; if (MgefCode and $80000000) <> 0 then begin if Assigned(aElement) then begin _File := aElement._File; if Assigned(_File) then begin FileID := MgefCode and $000000FF; if FileID >= _File.MasterCount then Result := AnsiString(_File.Name) else Result := AnsiString(_File.Masters[FileID].Name); Result := Result + ':' + AnsiString(IntToStr((MgefCode and not $800000FF) shr 8)); Exit; end; end; end; Result := AnsiString(IntToHex64(MgefCode, 8)); if aTransformType = ttToString then Result := Result + ' '; end; end else if aTransformType = ttToString then Result := Result + AnsiString(' '); end; ttFromEditValue, ttFromNativeValue: begin Result := Trim(s); if S = '' then Exit; i := Pos(':', Result); if i > 0 then begin t := Copy(Result, 1, Pred(i)); FileID := $FF; if Assigned(aElement) then begin _File := aElement._File; if Assigned(_File) then begin if SameText(t, _File.FileName) then FileID := _File.MasterCount else if SameText(t, _File.Name) then FileID := _File.MasterCount else begin for j := 0 to Pred(_File.MasterCount) do if SameText(t, _File.Masters[j].Name) then begin FileID := j; break; end; if FileID = $FF then for j := 0 to Pred(_File.MasterCount) do if SameText(t, _File.Masters[j].FileName) then begin FileID := j; break; end; end; end; end; if FileID = $FF then begin if i > 1 then FileID := StrToInt('$' + t); if Assigned(aElement) then begin _File := aElement._File; if Assigned(_File) then if FileID = $FF then FileID := _File.MasterCount else FileID := _File.LoadOrderFileIDtoFileFileID(FileID); end; end; t := Copy(Result, Succ(i), High(Integer)); MgefCode := StrToInt(t); if MgefCode > $7FFFFF then raise Exception.Create('"'+t+'" exceeds the maximum value for a dynamic magic effect code'); MgefCode := (MgefCode shl 8) or $80000000; MgefCode := MgefCode or FileID; end else if Length(Result) = 8 then begin MgefCode := StrToInt('$' + Result); if (MgefCode and $80000000) <> 0 then raise Exception.Create('"'+Result+'" is not a valid magic effect code'); end else if Length(s) = 4 then begin IsAlpha := True; for i := 1 to 4 do if not(s[i] in ['a'..'z', 'A'..'Z', '0'..'9', '_']) then begin IsAlpha := False; break; end; if not IsAlpha then raise Exception.Create('"'+Result+'" is not a valid magic effect code'); MgefCode := PCardinal(@Result[1])^; end else raise Exception.Create('"'+Result+'" is not a valid magic effect code'); SetLength(Result, 4); PCardinal(@Result[1])^ := MgefCode; end; end; end; function GetContainerFromUnion(const aElement: IwbElement): IwbContainer; begin // Should change the name to GetContainerFromUnionOrValue :) if (aElement.ElementType = etUnion) or (aElement.ElementType = etValue) then begin Result := aElement.Container; while Result.ElementType = etUnion do Result := Result.Container end else Result := aElement as IwbContainer; end; function GetContainerRefFromUnionOrValue(const aElement: IwbElement): IwbContainerElementRef; begin if (aElement.ElementType = etUnion) or (aElement.ElementType = etValue) then begin Supports(aElement.Container, IwbContainerElementRef, Result); while Result.ElementType = etUnion do Supports(Result.Container, IwbContainerElementRef, Result); end else Supports(aElement, IwbContainerElementRef, Result); end; function GetElementFromUnion(const aElement: IwbElement): IwbElement; begin if (aElement.ElementType = etUnion) then begin Result := aElement.Container; while Result.ElementType = etUnion do Result := Result.Container; end else Result := aElement; end; { TwbStringKCDef } function TwbStringKCDef.ToSortKey(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aExtended: Boolean): string; begin Result := ToStringTransform(aBasePtr, aEndPtr, aElement, ttToSortKey); end; { TwbLStringKCDef } function TwbLStringKCDef.ToSortKey(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; aExtended: Boolean): string; begin Result := ToStringTransform(aBasePtr, aEndPtr, aElement, ttToSortKey); end; { TwbRefID } var wbRefIDArray : TwbRefIDArray = nil; procedure InitializeRefIDArray(anArray: TwbRefIDArray); begin wbRefIDArray := anArray; end; procedure TwbRefID.BuildRef(aInt: Int64; const aElement: IwbElement); var key : Integer; val : Integer; begin // First two bits are the key: key := aInt shr 22; val := aInt and $003FFFFF; case key of 0: if (val > 0) and (val < Length(wbRefIDArray)) then inherited BuildRef(wbRefIDArray[val - 1], aElement); 1: inherited BuildRef(val, aElement); // '['+IntToHex64(val, 8)+'] Skyrim.esm FormID'; end; end; function TwbRefID.ToString(aInt: Int64; const aElement: IwbElement): string; var key : Integer; val : Integer; begin // First two bits are the key: key := aInt shr 22; val := aInt and $003FFFFF; case key of 0: if val = 0 then Result := '[00000000] NULL' else if val < Length(wbRefIDArray) then begin val := wbRefIDArray[val - 1]; Result := inherited ToString(val, aElement); Result := Copy(Result, 1, Pos('[', Result)) + IntToHex64(val, 8) + Copy(Result, Pos(']', Result), Length(Result)); end else Result := '['+IntToHex64(val-1, 8)+'] Index in FormID Array'; 1: Result := inherited ToString(val, aElement); 2: Result := '[FF'+IntToHex64(val, 6)+'] Created FormID'; else Result := '['+IntToHex64(aInt, 8)+'] '; end; Result := IntToStr(aInt)+' '+Result; Used(aElement, Result); end; { TwbDumpIntegerDefFormater } function TwbDumpIntegerDefFormater.ToSortKey(aInt: Int64; const aElement: IwbElement): string; begin Result := IntToHex64(aInt, 8); end; function TwbDumpIntegerDefFormater.ToString(aInt: Int64; const aElement: IwbElement): string; begin Result := IntToStr(aInt) + ' [' + IntToHex64(aInt, 8) + '] ['+IntToStr(aInt and $03)+':'+IntToStr(aInt shr 2)+']'; end; { TwbStructCDef } constructor TwbStructCDef.Clone(const aSource: TwbDef); begin with aSource as TwbStructCDef do Self.Create(defPriority, defRequired, noName, stMembers, stSortKey, stExSortKey, stOptionalFromElement, noDontShow, noAfterLoad, noAfterSet, scSizeCallback, scGetChapterType, scGetChapterTypeName, scGetChapterName, defGetCP).defSource := aSource; end; constructor TwbStructCDef.Create(aPriority: TwbConflictPriority; aRequired : Boolean; const aName : string; const aMembers : array of IwbValueDef; const aSortKey, aExSortKey : array of Integer; aOptionalFromElement : Integer; aDontShow : TwbDontShowCallback; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aSizeCallBack : TwbSizeCallback; aGetChapterType : TwbGetChapterTypeCallback; aGetChapterTypeName : TwbGetChapterTypeNameCallback; aGetChapterName : TwbGetChapterNameCallback; aGetCP : TwbGetConflictPriority); begin scSizeCallback := aSizeCallback; scGetChapterType := aGetChapterType; scGetChapterTypeName := aGetChapterTypeName; scGetChapterName := aGetChapterName; inherited Create(aPriority, aRequired, aName, aMembers, aSortKey, aExSortKey, [], aOptionalFromElement, aDontShow, aAfterLoad, aAfterSet, aGetCP); noTreeBranch := False; end; function TwbStructCDef.GetDefType: TwbDefType; begin Result := dtStructChapter; end; function TwbStructCDef.GetDefTypeName: string; begin Result := 'Chapter'; end; function TwbStructCDef.GetSizing(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement; var CompressedSize: Integer): Cardinal; begin if Assigned(scSizeCallback) then Result := scSizeCallback(aBasePtr, aEndPtr, aElement, CompressedSize) else begin CompressedSize := -1; Result := 0; end; end; function TwbStructCDef.GetChapterName(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): String; begin if Assigned(scGetChapterName) then Result := scGetChapterName(aBasePtr, aEndPtr, aElement) else if Assigned(scGetChapterTypeName) then Result := scGetChapterTypeName(aBasePtr, aEndPtr, aElement) else Result := GetName; end; function TwbStructCDef.GetChapterType(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; begin if Assigned(scGetChapterType) then Result := scGetChapterType(aBasePtr, aEndPtr, aElement) else Result := -1; end; function TwbStructCDef.GetChapterTypeName(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): String; begin if Assigned(scGetChapterTypeName) then Result := scGetChapterTypeName(aBasePtr, aEndPtr, aElement) else Result := IntToStr(GetChapterType(aBasePtr, aEndPtr, aElement)); end; { TwbKey2Data6EnumDef } function TwbKey2Data6EnumDef.ToSortKey(aInt: Int64; const aElement: IwbElement): string; begin Result := IntToHex64(aInt, 2); end; function TwbKey2Data6EnumDef.ToString(aInt: Int64; const aElement: IwbElement): string; var key : Integer; val : Integer; begin key := aInt shr 6; val := aInt and $3f; if val>=Length(enNames) then Result := 'Bad enum index: ' + IntToStr(val) + ' [' + IntToHex64(val, 2) + ']' else Result := enNames[val]; case key of 0: Result := Result + ' Small size'; 1: Result := Result + ' Medium size'; 2: Result := Result + ' Large size'; end; end; { TwbData6Key2EnumDef } function TwbData6Key2EnumDef.ToSortKey(aInt: Int64; const aElement: IwbElement): string; begin Result := IntToHex64(aInt, 2); end; function TwbData6Key2EnumDef.ToString(aInt: Int64; const aElement: IwbElement): string; var key : Integer; begin if aInt < Power(2, 6) then key := 0 else if aInt < Power(2, 14) then key := 1 else if aInt < Power(2, 22) then key := 2 else key := 3; Result := IntToStr(aInt); case key of 0: Result := Result + ' Small size'; 1: Result := Result + ' Medium size'; 2: Result := Result + ' Large size'; 3: Result := '0' + ' Null size'; end; end; { TwbIntegerDefFormaterUnion } procedure TwbIntegerDefFormaterUnion.BuildRef(aInt : Int64; const aElement : IwbElement); var IntegerDef: IwbIntegerDefFormater; begin IntegerDef := Decide(aElement); if Assigned(IntegerDef) then IntegerDef.BuildRef(aInt, aElement); end; function TwbIntegerDefFormaterUnion.CanAssign(const aElement : IwbElement; aIndex : Integer; const aDef : IwbDef) : Boolean; var IntegerDef: IwbIntegerDefFormater; begin IntegerDef := Decide(aElement); if Assigned(IntegerDef) then Result := IntegerDef.CanAssign(aElement, aIndex, aDef) else Result := False; end; function TwbIntegerDefFormaterUnion.CanContainFormIDs: Boolean; var i: Integer; begin for i := Low(idfuMembers) to High(idfuMembers) do if idfuMembers[i].CanContainFormIDs then Exit(True); Result := False; end; function TwbIntegerDefFormaterUnion.Check(aInt : Int64; const aElement : IwbElement) : string; begin Result := Decide(aElement).Check(aInt, aElement); end; constructor TwbIntegerDefFormaterUnion.Clone(const aSource: TwbDef); begin with aSource as TwbIntegerDefFormaterUnion do Self.Create(defPriority, defRequired, defGetCP, idfuDecider, idfuMembers).defSource := aSource; end; function TwbIntegerDefFormaterUnion.CompareExchangeFormID(var aInt : Int64; aOldFormID : Cardinal; aNewFormID : Cardinal; const aElement : IwbElement) : Boolean; var IntegerDef: IwbIntegerDefFormater; begin IntegerDef := Decide(aElement); if Assigned(IntegerDef) then Result := IntegerDef.CompareExchangeFormID(aInt, aOldFormID, aNewFormID, aElement) else Result := False; end; constructor TwbIntegerDefFormaterUnion.Create(aPriority : TwbConflictPriority; aRequired : Boolean; aGetCP : TwbGetConflictPriority; aDecider : TwbIntegerDefFormaterUnionDecider; const aMembers : array of IwbIntegerDefFormater); var i: Integer; begin inherited Create(aPriority, aRequired, aGetCP); idfuDecider := aDecider; SetLength(idfuMembers, Length(aMembers)); for i := Low(aMembers) to High(aMembers) do idfuMembers[i] := (aMembers[i] as IwbDefInternal).SetParent(Self, False) as IwbIntegerDefFormater; end; function TwbIntegerDefFormaterUnion.Decide(const aElement : IwbElement) : IwbIntegerDefFormater; var i: Integer; begin i := idfuDecider(aElement); if (i>=0) and (i=0) and (aIndex= 0 then begin RDE := @wbRecordDefs[Index]; while Assigned(RDE) do begin if Cardinal(RDE.rdeSignature) = Cardinal(aSignature) then begin aRecordDef := @RDE.rdeDef; Exit(True); end; if RDE.rdeNext >= 0 then RDE := @wbRecordDefs[RDE.rdeNext] else RDE := nil; end; end; aRecordDef := nil; Result := False; end; function wbFindRecordDef(const aSignature : AnsiString; out aRecordDef : PwbRecordDef) : Boolean; begin Result := (Length(aSignature) = 4) and wbFindRecordDef(PwbSignature(@aSignature[1])^, aRecordDef); end; var wbRecordDefMap: TStringList; function _wbRecordDefMap: TStringList; var i: Integer; begin if not Assigned(wbRecordDefMap) then begin wbRecordDefMap := TwbFastStringList.Create; for i := Low(wbRecordDefs) to High(wbRecordDefs) do with wbRecordDefs[i] do wbRecordDefMap.AddObject(rdeSignature, Pointer(rdeDef)); wbRecordDefMap.Sorted := True; end; Result := wbRecordDefMap; end; {$IFDEF USE_CODESITE} threadvar wbCodeSiteLoggingCount: Integer; function wbCodeSiteLoggingEnabled: Boolean; begin Result := wbCodeSiteLoggingCount > 0; end; function wbBeginCodeSiteLogging: Integer; begin Result := Succ(wbCodeSiteLoggingCount); wbCodeSiteLoggingCount := Result; end; function wbEndCodeSiteLogging: Integer; begin Result := Pred(wbCodeSiteLoggingCount); wbCodeSiteLoggingCount := Result; end; {$ENDIF} { TwbFlagDef } function TwbFlagDef.CanContainFormIDs: Boolean; begin Result := False; end; constructor TwbFlagDef.Clone(const aSource: TwbDef); begin with (aSource as TwbFlagDef) do Self.Create(defPriority, defRequired, noName, noAfterLoad, noAfterSet, noDontShow, defGetCP, noTerminator, fdFlagIndex).defSource := aSource; end; constructor TwbFlagDef.Create(aPriority : TwbConflictPriority; aRequired : Boolean; const aName : string; aAfterLoad : TwbAfterLoadCallback; aAfterSet : TwbAfterSetCallback; aDontShow : TwbDontShowCallback; aGetCP : TwbGetConflictPriority; aTerminator : Boolean; aFlagIndex : Integer); begin fdFlagIndex := aFlagIndex; inherited Create(aPriority, aRequired, aName, aAfterLoad, aAfterSet, aDontShow, aGetCP, aTerminator); end; function TwbFlagDef.GetCanBeZeroSize: Boolean; begin Result := True; end; function TwbFlagDef.GetConflictPriority(const aElement: IwbElement): TwbConflictPriority; begin with GetFlagsDef do begin if FlagIgnoreConflict[GetFlagIndex] then Result := cpIgnore else Result := cpNormal; FlagGetCP(aElement, GetFlagIndex, Result); end; end; function TwbFlagDef.GetConflictPriorityCanChange: Boolean; begin Result := GetFlagsDef.FlagHasGetCP[GetFlagIndex]; end; function TwbFlagDef.GetDefaultSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; begin Result := 0; end; function TwbFlagDef.GetDefType: TwbDefType; begin Result := dtFlag; end; function TwbFlagDef.GetDefTypeName: string; begin Result := 'FlagDef'; end; function TwbFlagDef.GetDontShow(const aElement: IwbElement): Boolean; begin Result := GetFlagsDef.FlagDontShow[aElement, GetFlagIndex]; end; function TwbFlagDef.GetFlagIndex: Integer; begin Result := fdFlagIndex; end; function TwbFlagDef.GetFlagsDef: IwbFlagsDef; begin Result := defParent as IwbFlagsDef; end; function TwbFlagDef.GetHasDontShow: Boolean; begin Result := GetFlagsDef.FlagHasDontShow[GetFlagIndex]; end; function TwbFlagDef.GetSize(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): Integer; begin Result := 0; end; function TwbFlagDef.ToString(aBasePtr, aEndPtr: Pointer; const aElement: IwbElement): string; begin Assert(False); Result := ''; end; function wbIsPlugin(aFileName: string): Boolean; var i: Integer; begin Result := Pos(UpperCase(wbHardcodedDat), UpperCase(aFileName))<>0; if not Result then for i := 0 to Pred(Length(wbPluginExtensions)) do if Pos(UpperCase(wbPluginExtensions[i]), UpperCase(ExtractFileExt(aFileName)))=1 then begin Result := True; Exit; end; end; function wbStr4ToString(aInt: Int64): string; var U32 : Cardinal; Temp : String; i : Integer; begin if aInt=0 then Result := ' ' else begin U32 := aInt; Result := PwbSignature(@U32)^; if Length(Result)=4 then begin Temp := Result; for i := 1 to 4 do Result[i] := Temp[5-i]; end else begin Result := ' '; // wbProgressCallback('Found a str4 that does not have 4 characters! (1) '+IntToHex64(aInt, 8)); end; end; end; initialization TwoPi := 2 * OnePi; if (DebugHook = 0) then wbReportMode := False; wbIgnoreRecords := TStringList.Create; wbIgnoreRecords.Sorted := True; wbIgnoreRecords.Duplicates := dupIgnore; wbDoNotBuildRefsFor := TStringList.Create; wbDoNotBuildRefsFor.Sorted := True; wbDoNotBuildRefsFor.Duplicates := dupIgnore; wbProgramPath := IncludeTrailingPathDelimiter(ExtractFilePath(ParamStr(0))); SetLength(wbPluginExtensions, 3); wbPluginExtensions[0] := '.ESP'; wbPluginExtensions[1] := '.ESM'; wbPluginExtensions[2] := '.GHOST'; finalization FreeAndNil(wbIgnoreRecords); FreeAndNil(wbDoNotBuildRefsFor); FreeAndNil(wbGroupOrder); FreeAndNil(wbRecordDefMap); wbRecordDefs := nil; wbContainerHandler := nil; end. ================================================ FILE: lib/xedit/wbLocalization.pas ================================================ {******************************************************************************* The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. *******************************************************************************} unit wbLocalization; {$I wbDefines.inc} interface uses Classes, SysUtils, StrUtils, Math, wbInterface, wbBSA; const sStringID = 'STRINGID:'; type TwbLStringType = ( lsDLString, lsILString, lsString ); TwbLocalizationFile = class private fName : string; fFileName : string; fFileType : TwbLStringType; fStrings : TStrings; fModified : boolean; fNextID : Cardinal; procedure Init; function FileStringType(aFileName: string): TwbLStringType; function ReadZString(aStream: TMemoryStream): AnsiString; function ReadLenZString(aStream: TMemoryStream): AnsiString; procedure WriteZString(aStream: TMemoryStream; aString: AnsiString); procedure WriteLenZString(aStream: TMemoryStream; aString: AnsiString); procedure ReadDirectory(aStream: TMemoryStream); protected function Get(Index: Cardinal): string; procedure Put(Index: Cardinal; const S: string); public property Strings[Index: Cardinal]: string read Get write Put; default; property Items: TStrings read fStrings; property Name: string read fName; property FileName: string read fFileName; property Modified: boolean read fModified write fModified; property NextID: Cardinal read fNextID; constructor Create(const aFileName: string); overload; constructor Create(const aFileName: string; aData: TBytes); overload; destructor Destroy; override; function Count: Integer; function IndexToID(Index: Integer): Cardinal; function IDExists(ID: Cardinal): boolean; function AddString(ID: Integer; const S: string): boolean; procedure WriteToStream(const aStream: TStream); procedure ExportToFile(const aFileName: string); end; TwbLocalizationHandler = class private lFiles : TStrings; fReuseDup : boolean; protected function Get(Index: Integer): TwbLocalizationFile; function GetStringsPath: string; public NoTranslate: boolean; property _Files[Index: Integer]: TwbLocalizationFile read Get; default; property StringsPath: string read GetStringsPath; property ReuseDup: Boolean read fReuseDup write fReuseDup; constructor Create; destructor Destroy; override; procedure Clear; function Count: Integer; function LocalizedValueDecider(aElement: IwbElement): TwbLStringType; function AvailableLanguages: TStringList; function AvailableLocalizationFiles: TStringList; procedure LoadForFile(aFileName: string); function AddLocalization(const aFileName: string): TwbLocalizationFile; overload; function AddLocalization(const aFileName: string; aData: TBytes): TwbLocalizationFile; overload; function GetValue(ID: Cardinal; aElement: IwbElement): string; function SetValue(ID: Cardinal; aElement: IwbElement; aValue: string): Cardinal; function AddValue(aValue: string; aElement: IwbElement): Cardinal; function GetLocalizationFileNameByElement(aElement: IwbElement): string; function GetLocalizationFileNameByType(aPluginFile: string; ls: TwbLStringType): string; procedure GetStringsFromFile(aFileName: string; const aList: TStrings); end; const wbLocalizationExtension: array [TwbLStringType] of string = ( '.DLSTRINGS', '.ILSTRINGS', '.STRINGS' ); var wbLocalizationHandler: TwbLocalizationHandler; implementation uses WideStrUtils; constructor TwbLocalizationFile.Create(const aFileName: string); var fs: TFileStream; fStream: TMemoryStream; Buffer: PByte; begin fFileName := aFileName; Init; // cache file in mem fStream := TMemoryStream.Create; try fs := TFileStream.Create(aFileName, fmOpenRead or fmShareDenyNone); GetMem(Buffer, fs.Size); try fs.ReadBuffer(Buffer^, fs.Size); fStream.WriteBuffer(Buffer^, fs.Size); fStream.Position := 0; ReadDirectory(fStream); finally if Assigned(Buffer) then FreeMem(Buffer); end; finally FreeAndNil(fs); FreeAndNil(fStream); end; end; constructor TwbLocalizationFile.Create(const aFileName: string; aData: TBytes); var fStream: TMemoryStream; begin fFileName := aFileName; Init; fStream := TMemoryStream.Create; try fStream.WriteBuffer(aData[0], length(aData)); fStream.Position := 0; ReadDirectory(fStream); finally FreeAndNil(fStream); end; end; destructor TwbLocalizationFile.Destroy; begin FreeAndNil(fStrings); inherited; end; procedure TwbLocalizationFile.Init; begin fModified := false; fName := ExtractFileName(fFileName); fFileType := FileStringType(fFileName); fStrings := TwbFastStringList.Create; fNextID := 1; end; function TwbLocalizationFile.FileStringType(aFileName: string): TwbLStringType; var ext: string; i: TwbLStringType; begin Result := lsString; ext := ExtractFileExt(aFileName); for i := Low(TwbLStringType) to High(TwbLStringType) do if SameText(ext, wbLocalizationExtension[i]) then Result := i; end; function TwbLocalizationFile.ReadZString(aStream: TMemoryStream): AnsiString; var Position : Integer; begin Position := aStream.Position; Result := PAnsiChar(@PByte(aStream.Memory)[Position]); aStream.Position := aStream.Position + Succ(Length(Result)); end; function TwbLocalizationFile.ReadLenZString(aStream: TMemoryStream): AnsiString; var Len: Cardinal; begin aStream.ReadBuffer(Len, 4); Dec(Len); // trailing null SetLength(Result, Len); if Len > 0 then aStream.ReadBuffer(Result[1], Len); end; procedure TwbLocalizationFile.WriteZString(aStream: TMemoryStream; aString: AnsiString); const z: Byte = 0; begin aStream.WriteBuffer(aString[1], Length(aString)); aStream.WriteBuffer(z, SizeOf(z)); end; procedure TwbLocalizationFile.WriteLenZString(aStream: TMemoryStream; aString: AnsiString); const z: Byte = 0; var l: Cardinal; begin l := Length(aString) + SizeOf(z); aStream.WriteBuffer(l, SizeOf(Cardinal)); aStream.WriteBuffer(aString[1], Length(aString)); aStream.WriteBuffer(z, SizeOf(z)); end; procedure TwbLocalizationFile.ReadDirectory(aStream: TMemoryStream); var i: integer; scount, id, offset: Cardinal; oldPos: int64; s: AnsiString; begin if aStream.Size < 8 then Exit; aStream.Read(scount, 4); // number of strings aStream.Position := aStream.Position + 4; // skip dataSize if scount > 0 then for i := 0 to scount - 1 do begin aStream.Read(id, 4); // string ID aStream.Read(offset, 4); // offset of string relative to data (header + dirsize) oldPos := aStream.Position; aStream.Position := 8 + scount*8 + offset; // header + dirsize + offset if fFileType = lsString then s := ReadZString(aStream) else s := ReadLenZString(aStream); fStrings.AddObject(wbAnsiToString(s, nil), pointer(id)); if Succ(id) > fNextID then fNextID := Succ(id); aStream.Position := oldPos; end; end; procedure TwbLocalizationFile.WriteToStream(const aStream: TStream); var dir, data: TMemoryStream; i: integer; c: Cardinal; begin dir := TMemoryStream.Create; data := TMemoryStream.Create; c := fStrings.Count; dir.WriteBuffer(c, SizeOf(c)); // number of strings dir.WriteBuffer(c, SizeOf(c)); // dataSize, will overwrite later try for i := 0 to Pred(fStrings.Count) do begin c := Cardinal(fStrings.Objects[i]); dir.WriteBuffer(c, SizeOf(c)); // ID c := data.Position; dir.WriteBuffer(c, SizeOf(c)); // relative position if fFileType = lsString then WriteZString(data, wbStringToAnsi(fStrings[i], nil)) else WriteLenZString(data, wbStringToAnsi(fStrings[i], nil)); end; c := data.Size; dir.Position := 4; dir.WriteBuffer(c, SizeOf(c)); // dataSize aStream.CopyFrom(dir, 0); aStream.CopyFrom(data, 0); finally FreeAndNil(dir); FreeAndNil(data); end; end; function TwbLocalizationFile.Count: Integer; begin Result := fStrings.Count; end; function TwbLocalizationFile.IndexToID(Index: Integer): Cardinal; begin if Index < Count then Result := Cardinal(fStrings.Objects[Index]) else Result := 0; end; function TwbLocalizationFile.IDExists(ID: Cardinal): boolean; begin Result := fStrings.IndexOfObject(Pointer(ID)) <> -1; end; function TwbLocalizationFile.Get(Index: Cardinal): string; var idx: integer; begin Result := ''; idx := fStrings.IndexOfObject(Pointer(Index)); if idx <> -1 then Result := fStrings[idx] else Result := ''; end; procedure TwbLocalizationFile.Put(Index: Cardinal; const S: string); var idx: integer; begin idx := fStrings.IndexOfObject(Pointer(Index)); if idx <> -1 then if fStrings[idx] <> S then begin fStrings[idx] := S; fModified := true; end; end; function TwbLocalizationFile.AddString(ID: Integer; const S: string): boolean; begin Result := false; if ID < NextID then Exit; fStrings.AddObject(S, Pointer(ID)); fNextID := Succ(ID); fModified := true; Result := true; end; procedure TwbLocalizationFile.ExportToFile(const aFileName: string); var i: integer; sl: TStringList; begin sl := TStringList.Create; try for i := 0 to Pred(fStrings.Count) do begin sl.Add('[' + IntToHex(Integer(fStrings.Objects[i]), 8) + ']'); sl.Add(fStrings[i]); end; sl.SaveToFile(aFileName); finally FreeAndNil(sl); end; end; constructor TwbLocalizationHandler.Create; begin lFiles := TwbFastStringListCS.CreateSorted; fReuseDup := false; NoTranslate := false; end; destructor TwbLocalizationHandler.Destroy; begin Clear; FreeAndNil(lFiles); end; function TwbLocalizationHandler.Count: Integer; begin Result := lFiles.Count; end; procedure TwbLocalizationHandler.Clear; var i: integer; begin for i := 0 to Pred(Count) do _Files[i].Destroy; lFiles.Clear; end; function TwbLocalizationHandler.Get(Index: Integer): TwbLocalizationFile; begin if Index < Count then Result := TwbLocalizationFile(lFiles.Objects[Index]) else Result := nil; end; function TwbLocalizationHandler.AddLocalization(const aFileName: string): TwbLocalizationFile; begin Result := TwbLocalizationFile.Create(aFileName); lFiles.AddObject(ExtractFileName(aFileName), Result); end; function TwbLocalizationHandler.AddLocalization(const aFileName: string; aData: TBytes): TwbLocalizationFile; begin Result := TwbLocalizationFile.Create(aFileName, aData); lFiles.AddObject(ExtractFileName(aFileName), Result); end; function TwbLocalizationHandler.LocalizedValueDecider(aElement: IwbElement): TwbLStringType; var sigElement, sigRecord: TwbSignature; aRecord: IwbSubRecord; begin if Supports(aElement, IwbSubRecord, aRecord) then sigElement := aRecord.Signature else sigElement := ''; sigRecord := aElement.ContainingMainRecord.Signature; if (sigRecord <> 'LSCR') and (sigElement = 'DESC') then Result := lsDLString else // DESC always from dlstrings except LSCR if (sigRecord = 'QUST') and (sigElement = 'CNAM') then Result := lsDLString else // quest log entry if (sigRecord = 'BOOK') and (sigElement = 'CNAM') then Result := lsDLString else // Book CNAM description if (sigRecord = 'INFO') and (sigElement <> 'RNAM') then Result := lsILString else // dialog, RNAM are lsString, others lsILString Result := lsString; // others end; function TwbLocalizationHandler.GetStringsPath: string; begin Result := wbDataPath + 'Strings\'; end; function TwbLocalizationHandler.AvailableLanguages: TStringList; var F: TSearchRec; p: integer; s: string; begin Result := TStringList.Create; if FindFirst(StringsPath + '*.*STRINGS', faAnyFile, F) = 0 then try repeat s := LowerCase(ChangeFileExt(F.Name, '')); p := LastDelimiter('_', s); if p > 0 then begin s := Copy(s, p + 1, length(s)); if s = '' then Continue; s := AnsiUpperCase(s[1]) + Copy(s, 2, Length(s)); if Result.IndexOf(s) = -1 then Result.Add(s); end; until FindNext(F) <> 0; finally FindClose(F); end; end; function TwbLocalizationHandler.AvailableLocalizationFiles: TStringList; var F: TSearchRec; begin Result := TStringList.Create; if FindFirst(StringsPath + '*.*STRINGS', faAnyFile, F) = 0 then try repeat Result.Add(F.Name); until FindNext(F) <> 0; finally FindClose(F); end; end; procedure TwbLocalizationHandler.LoadForFile(aFileName: string); var ls: TwbLStringType; s: string; res: TDynResources; begin if not Assigned(wbContainerHandler) then Exit; for ls := Low(TwbLStringType) to High(TwbLStringType) do begin s := wbLocalizationHandler.GetLocalizationFileNameByType(aFileName, ls); if lFiles.IndexOf(ExtractFileName(s)) = -1 then begin res := wbContainerHandler.OpenResource(s); if length(res) > 0 then begin //wbProgressCallback('[' + s + '] Loading Localization.'); wbLocalizationHandler.AddLocalization(wbDataPath + s, res[High(res)].GetData); end; end; end; end; function TwbLocalizationHandler.GetLocalizationFileNameByType(aPluginFile: string; ls: TwbLStringType): string; begin Result := Format('%s_%s%s', [ ChangeFileExt(aPluginFile, ''), wbLanguage, wbLocalizationExtension[ls] ]); // relative path to Data folder Result := 'Strings\' + Result; end; function TwbLocalizationHandler.GetLocalizationFileNameByElement(aElement: IwbElement): string; begin Result := ''; if not Assigned(aElement) then Exit; Result := GetLocalizationFileNameByType(aElement._File.FileName, LocalizedValueDecider(aElement)); end; // create a new lstring from aValue for aElement function TwbLocalizationHandler.AddValue(aValue: string; aElement: IwbElement): Cardinal; var ls: TwbLStringType; FileName: string; wblf: array [TwbLStringType] of TwbLocalizationFile; idx: integer; data: TBytes; ID: Cardinal; begin Result := 0; if not Assigned(aElement) then Exit; if aValue = '' then Exit; // create localization files if absent try ID := 1; for ls := Low(TwbLStringType) to High(TwbLStringType) do begin FileName := GetLocalizationFileNameByType(aElement._File.FileName, ls); idx := lFiles.IndexOf(ExtractFileName(FileName)); if idx = -1 then begin wblf[ls] := AddLocalization(wbDataPath + FileName, data); wblf[ls].Modified := true; end else wblf[ls] := _Files[idx]; if wblf[ls].NextID > ID then ID := wblf[ls].NextID; end; ls := LocalizedValueDecider(aElement); // detect a duplicate string if ReuseDup then begin idx := wblf[ls].fStrings.IndexOf(aValue); if idx <> -1 then ID := Cardinal(wblf[ls].fStrings.Objects[idx]) else wblf[ls].AddString(ID, aValue); end else wblf[ls].AddString(ID, aValue); Result := ID; finally end; end; function TwbLocalizationHandler.SetValue(ID: Cardinal; aElement: IwbElement; aValue: string): Cardinal; var idx: integer; FileName: string; begin Result := ID; if not Assigned(aElement) then Exit; FileName := GetLocalizationFileNameByElement(aElement); idx := lFiles.IndexOf(ExtractFileName(FileName)); if (idx = -1) or (ID = 0) then begin // new string Result := AddValue(aValue, aElement); Exit; end; if not _Files[idx].IDExists(ID) then // string doesn't exist, create new Result := AddValue(aValue, aElement) else // modify existing _Files[idx][ID] := aValue; end; function TwbLocalizationHandler.GetValue(ID: Cardinal; aElement: IwbElement): string; var lFileName: string; idx: integer; begin Result := ''; if NoTranslate then begin Result := IntToHex(ID, 8); Exit; end; if ID = 0 then Exit; lFileName := ExtractFileName(GetLocalizationFileNameByElement(aElement)); if lFileName = '' then Exit; idx := lFiles.IndexOf(lFileName); // load strings files if absent if idx = - 1 then LoadForFile(aElement._File.FileName); // get file again idx := lFiles.IndexOf(lFileName); if idx = - 1 then begin Result := ''; Exit; end; Result := _Files[idx][ID]; end; procedure TwbLocalizationHandler.GetStringsFromFile(aFileName: string; const aList: TStrings); var i: integer; begin if not Assigned(aList) then Exit; for i := 0 to Pred(lFiles.Count) do if SameText(lFiles[i], aFileName) then begin aList.Assign(_Files[i].fStrings); Break; end; end; initialization wbLocalizationHandler := TwbLocalizationHandler.Create; finalization FreeAndNil(wbLocalizationHandler); end. ================================================ FILE: lib/xedit/wbSort.pas ================================================ {******************************************************************************* The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. *******************************************************************************} unit wbSort; {$I wbDefines.inc} interface uses Classes, wbInterface; procedure wbMergeSort(aList: Pointer; aCount: Integer; aCompare: TListSortCompare); implementation type TwbMove = procedure(const Source; var Dest; Count : Integer); var wbMove : TwbMove = nil; const // x64 - use InsertionSort instead MergeSort for small arrays MIN_SIZE = 32; {$IFDEF WIN32} function wbMergeSortInternal(_A, _B: PwbPointerArray; _Count : Integer; _Compare: TListSortCompare): PwbPointerArray; register; const SizeOfPointer = SizeOf(Pointer); SizeOf2Pointer = 2 * SizeOf(Pointer); EspOffset = $38; A = EspOffset - SizeOfPointer * 1; B = EspOffset - SizeOfPointer * 2; Compare = EspOffset+$08; //sometimes ebp Temp = EspOffset - SizeOfPointer * 3; Count = EspOffset - SizeOfPointer * 4; SegmentSize = EspOffset - SizeOfPointer * 5; Temp2 = EspOffset - SizeOfPointer * 6; pRightEnd = EspOffset - SizeOfPointer * 7; pLeftEnd = EspOffset - SizeOfPointer * 8; pListEnd = EspOffset - SizeOfPointer * 9; pNextLeft = EspOffset - SizeOfPointer * 10; SavedCompares = EspOffset - SizeOfPointer * 11; asm { begin } sub esp, EspOffset mov [esp + 00], edi mov [esp + 08], esi mov [esp + 04], ebx mov [esp+Count], ecx mov [esp+B], edx mov [esp+A], eax {======== first run =========================================================} xor ebp, ebp { pBuffer := @b; } mov edi, [esp+B] { pLeft := @a; } mov esi, [esp+A] { pListEnd := @a[Pred(Count)]; } mov ebx, [esp+Count] dec ebx lea ebx, [esi+ebx*SizeOfPointer] mov dword ptr [esp+Temp], 0 jmp @@FirstRun_CompareLoop nop nop nop nop nop nop nop @@FirstRun_CompareLoop: { if Compare(pLeft^, pRight^) <= 0 then begin } mov eax, [esi] mov edx, [esi + SizeOfPointer] call [esp+Compare] test eax, eax jg @@FirstRun_MergeFromRight jl @@FirstRun_MergeFromLeft add dword ptr [esp+Temp], 1 jmp @@FirstRun_MergeFromLeft nop nop nop nop nop nop nop nop nop nop @@FirstRun_MergeFromLeft: { pBuffer^ := pLeft^; } mov eax, [esi] mov [edi], eax { pBuffer+1^ := pLeft+1^; } mov eax, [esi + SizeOfPointer] mov [edi + SizeOfPointer], eax { Inc(pBuffer, 2); } add edi, SizeOf2Pointer { Inc(pLeft, 2); } add esi, SizeOf2Pointer { until pLeft+1 >= pListEnd } cmp esi, ebx jb @@FirstRun_CompareLoop ja @@FirstRun_NoRemaining jmp @@FirstRun_CopyRemaining nop nop nop nop nop nop nop nop @@FirstRun_MergeFromRight: lea ebp, [ebp +1] { pBuffer+1^ := pLeft^; } mov eax, [esi] mov [edi + SizeOfPointer], eax { pBuffer^ := pLeft+1^; } mov eax, [esi + SizeOfPointer] mov [edi], eax { Inc(pBuffer, 2); } add edi, SizeOf2Pointer { Inc(pLeft, 2); } add esi, SizeOf2Pointer { until pLeft+1 >= pListEnd } cmp esi, ebx jb @@FirstRun_CompareLoop ja @@FirstRun_NoRemaining @@FirstRun_CopyRemaining: { pBuffer^ := pLeft^; } mov eax, [esi] mov [edi], eax nop nop nop @@FirstRun_NoRemaining: mov edx, ebp mov ebp, [esp+Compare] { if never merged from left... } test edx, edx jz @@ShortCutFwd_Entry { if always merged from right... } mov eax, [esp+Count] shr eax, 1 add edx, [esp+Temp] cmp edx, eax je @@ShortCutBwd_Entry { T := A; } mov eax, [esp+A] { A := B; } mov edx, [esp+B] mov [esp+A], edx { B := T; } mov [esp+B], eax jmp @@SmallRuns_Entry {======== shortcut forward run ==============================================} nop nop nop @@ShortCutFwd_Entry: { pLeft := @a; } mov esi, [esp+A] { pListEnd := @a[Pred(Count)]; - still valid} { skip first element } add esi, SizeOfPointer cmp esi, ebx jae @@Exit nop @@ShortCutFwd_CompareLoop: { if Compare(pLeft^, pRight^) <= 0 then begin } mov eax, [esi] mov edx, [esi + SizeOfPointer] call ebp test eax, eax { if any element didn't fit, do a full merge } jg @@SmallRuns_Entry { Inc(pLeft, 2); } add esi, SizeOf2Pointer { until pLeft+1 >= pListEnd } cmp esi, ebx jb @@ShortCutFwd_CompareLoop jmp @@Exit {======== shortcut forward run ==============================================} nop nop nop nop nop @@ShortCutBwd_Entry: mov esi, [esp+A] mov ebx, [esp + Count] cmp ebx, 2 je @@ShortCutBwd_ExchangeLoop_Entry sub ebx, 3 or ebx, 1 lea ebx, [esi + ebx * 4] cmp esi, ebx jae @@Exit nop nop @@ShortCutBwd_CompareLoop: { if Compare(pLeft^, pRight^) <= 0 then begin } mov eax, [ebx] mov edx, [ebx + SizeOfPointer] call ebp test eax, eax { if any element didn't fit, do a full merge } jl @@ShortCutBwd_Error { Inc(pLeft, 2); } sub ebx, SizeOf2Pointer { until pLeft+1 >= pListEnd } cmp esi, ebx jb @@ShortCutBwd_CompareLoop @@ShortCutBwd_ExchangeLoop_Entry: mov esi, [esp+A] mov ebx, [esp + Count] sub ebx, 1 lea ebx, [esi + ebx * 4] @@ShortCutBwd_ExchangeLoop: mov eax, [esi] mov edx, [ebx] mov [ebx], eax mov [esi], edx add esi, SizeOfPointer sub ebx, SizeOfPointer cmp esi, ebx jb @@ShortCutBwd_ExchangeLoop jmp @@Exit nop nop nop nop nop nop nop nop nop @@ShortCutBwd_Error: { T := A; } mov eax, [esp+A] { A := B; } mov edx, [esp+B] mov [esp+A], edx { B := T; } mov [esp+B], eax jmp @@SmallRuns_Entry {======== small runs ====================================================} nop nop nop nop nop nop nop nop nop nop nop nop nop nop @@SmallRuns_Entry: { SegmentSize := 2; } mov eax, 2 mov dword ptr [esp+SegmentSize], eax nop nop nop nop nop nop nop @@SmallRuns_OuterLoop_Entry: mov ebp, [esp + Compare] @@SmallRuns_OuterLoop: // requires SegmentSize in eax { pBuffer := @b; } mov edi, [esp+B] { pLeft := @a; } mov esi, [esp+A] { pRight := @a[SegmentSize]; } lea ebx, [esi+eax*SizeOfPointer] { pLeftEnd := pRight; } mov [esp+pLeftEnd], ebx { pListEnd := @a[Count]; } mov edx, [esp+Count] lea edx, [esi+ edx*SizeOfPointer] mov [esp+pListEnd], edx { pRightEnd := @a[SegmentSize + SegmentSize]; } lea eax, [ebx+eax*SizeOfPointer] mov [esp+pRightEnd], eax jmp @@SmallRuns_InnerLoopEntry //requires pRightEnd in eax and pListEnd in edx nop nop nop nop nop nop nop nop nop @@SmallRuns_InnerLoopSetRightEnd: { pRightEnd := pListEnd; } mov [esp+pRightEnd], edx @@SmallRuns_InnerLoop: @@SmallRuns_CompareLoop: { if Compare(pLeft^, pRight^) <= 0 then begin } mov edx, [ebx] mov eax, [esi] call ebp test eax, eax jg @@SmallRuns_MergeFromRight @@SmallRuns_MergeFromLeft: { pBuffer^ := pLeft^; } mov eax, [esi] mov [edi], eax { Inc(pBuffer); } add edi, SizeOfPointer { Inc(pLeft); } add esi, SizeOfPointer { if Cardinal(pLeft) >= Cardinal(pLeftEnd) then begin } cmp esi, [esp+pLeftEnd] jb @@SmallRuns_CompareLoop nop nop @@SmallRuns_CopyRemainingFromRight_Entry: mov edx, [esp+pRightEnd] //used in CopyRemainingFromRight @@SmallRuns_CopyRemainingFromRight: { pBuffer^ := pRight^; } mov eax, [ebx] mov [edi], eax { Inc(pBuffer); } add edi, SizeOfPointer { Inc(pRight); } add ebx, SizeOfPointer { while Cardinal(pRight) < Cardinal(pRightEnd) do begin } cmp ebx, edx jb @@SmallRuns_CopyRemainingFromRight { Break; } jmp @@SmallRuns_BreakOutOfCompareLoop @@SmallRuns_MergeBoth: { pBuffer^ := pRight^; } mov eax, [esi] mov [edi], eax mov eax, [ebx] mov [edi + SizeOfPointer], eax { Inc(pBuffer); } add edi, SizeOf2Pointer { Inc(pRight); } add ebx, SizeOfPointer add esi, SizeOfPointer cmp esi, [esp+pLeftEnd] jae @@SmallRuns_LeftDone cmp ebx, [esp+pRightEnd] jb @@SmallRuns_CompareLoop jmp @@SmallRuns_CopyRemainingFromLeft_Entry @@SmallRuns_LeftDone: cmp ebx, [esp+pRightEnd] jb @@SmallRuns_CopyRemainingFromRight_Entry jmp @@SmallRuns_BreakOutOfCompareLoop @@SmallRuns_MergeFromRight: { pBuffer^ := pRight^; } mov eax, [ebx] mov [edi], eax { Inc(pBuffer); } add edi, SizeOfPointer { Inc(pRight); } add ebx, SizeOfPointer { if Cardinal(pRight) >= Cardinal(pRightEnd) then begin } cmp ebx, [esp+pRightEnd] jb @@SmallRuns_CompareLoop @@SmallRuns_CopyRemainingFromLeft_Entry: mov edx, [esp+pLeftEnd] // used in CopyRemainingFromLeft @@SmallRuns_CopyRemainingFromLeft: { pBuffer^ := pLeft^; } mov eax, [esi] mov [edi], eax { Inc(pBuffer); } add edi, SizeOfPointer { Inc(pLeft); } add esi, SizeOfPointer { while Cardinal(pLeft) < Cardinal(pLeftEnd) do begin } cmp esi, edx jb @@SmallRuns_CopyRemainingFromLeft @@SmallRuns_BreakOutOfCompareLoop: { Inc(pLeft, SegmentSize); } mov eax, [esp+SegmentSize] shl eax, 02h add esi, eax { Inc(pRight, SegmentSize); } add ebx, eax { pLeftEnd := pRight; } mov [esp+pLeftEnd], ebx { Inc(pRightEnd, SegmentSize + SegmentSize); } lea eax, [ebx + eax] mov [esp+pRightEnd], eax mov edx, [esp+pListEnd] @@SmallRuns_InnerLoopEntry: //requires pRightEnd in eax and pListEnd in edx { while Cardinal(pRightEnd) <= Cardinal(pListEnd) do begin } cmp eax, edx jbe @@SmallRuns_InnerLoop { if Cardinal(pLeft) < Cardinal(pListEnd) then begin } cmp edx, esi jbe @@SmallRuns_NoRemaining { if Cardinal(pRight) < Cardinal(pListEnd) then begin } cmp edx, ebx ja @@SmallRuns_InnerLoopSetRightEnd @@SmallRuns_CopyRemaining: { pBuffer^ := pLeft^; } mov eax, [esi] mov [edi], eax { Inc(pBuffer); } add edi, SizeOfPointer { Inc(pLeft); } add esi, SizeOfPointer { while Cardinal(pLeft) < Cardinal(pListEnd) do begin } cmp esi, edx jb @@SmallRuns_CopyRemaining @@SmallRuns_NoRemaining: { T := A; } mov eax, [esp+A] { A := B; } mov edx, [esp+B] mov [esp+A], edx { B := T; } mov [esp+B], eax { SegmentSize := SegmentSize shl 1; } mov eax, [esp+SegmentSize] shl eax, 1 mov [esp+SegmentSize], eax { while SegmentSize < Count do begin } cmp eax, [esp+Count] jge @@Exit cmp eax, 128 jne @@SmallRuns_OuterLoop // requires SegmentSize in eax {======== large runs ====================================================} @@LargeRuns_OuterLoop: // requires SegmentSize in eax { pBuffer := @b; } mov edi, [esp+B] { pLeft := @a; } mov esi, [esp+A] { pRight := @a[SegmentSize]; } lea ebx, [esi+eax*SizeOfPointer] { pLeftEnd := pRight; } mov [esp+pLeftEnd], ebx { pListEnd := @a[Count]; } mov edx, [esp+Count] lea edx, [esi+ edx*SizeOfPointer] mov [esp+pListEnd], edx { pRightEnd := @a[SegmentSize + SegmentSize]; } lea eax, [ebx+eax*SizeOfPointer] mov [esp+pRightEnd], eax mov [esp+pNextLeft], eax mov [esp+SavedCompares], 0 jmp @@LargeRuns_InnerLoopEntry //requires pRightEnd in eax and pListEnd in edx nop nop nop @@LargeRuns_InnerLoopSetRightEnd: { pRightEnd := pListEnd; } mov [esp+pRightEnd], edx mov [esp+pNextLeft], edx @@LargeRuns_InnerLoop: { Compare(pLeft^, pRight^) } mov edx, [ebx] mov eax, [esi] call [esp+Compare] test eax, eax { if equal -> perfect overlap, copy both, no need to waste a comparison... } je @@LargeRuns_CopyBoth mov edx, [esp+pLeftEnd] jl @@LargeRuns_MoveFromLeft // requires LeftEnd in edx @@LargeRuns_SwitchLeftAndRight: { if greater -> right one is smaller } { move it over to the buffer, no need to waste a comparison} mov ecx, [ebx] mov [edi], ecx add ebx, SizeOfPointer add edi, SizeOfPointer { switch left and right } xchg ebx, esi mov eax, [esp+pRightEnd] mov [esp+pLeftEnd], eax mov [esp+pRightEnd], edx { if we reached the end, copy the rest } cmp esi, eax jae @@LargeRuns_CopyRemainingFromRight_Entry mov edx, eax jmp @@LargeRuns_CompareLeftEndAndRight nop nop nop nop nop nop nop nop nop nop nop nop nop nop @@LargeRuns_MoveFromLeft: // requires LeftEnd in edx { if lesser -> left one is smaller} { move it over to the buffer, no need to waste a comparison} mov ecx, [esi] mov [edi], ecx add esi, SizeOfPointer add edi, SizeOfPointer { if we reached the end, copy the rest } cmp esi, edx{LeftEnd} jae @@LargeRuns_CopyRemainingFromRight_Entry @@LargeRuns_CompareLeftEndAndRight: // requires LeftEnd in edx sub edx, SizeOfPointer mov eax, [edx] mov edx, [ebx] call [esp+Compare] test eax, eax jg @@LargeRuns_BinarySearchLeft_Entry { LeftEnd <= Right, no need to continue merging, just copy and get out of here } { first copy just left } mov eax, esi mov edx, edi mov ecx, [esp+pLeftEnd] sub ecx, eax add edi, ecx add [esp+SavedCompares], ecx call [wbMove] { then copy just right } mov eax, ebx mov edx, edi mov ecx, [esp+pRightEnd] sub ecx, eax add edi, ecx add [esp+SavedCompares], ecx call [wbMove] { we are done here } jmp @@LargeRuns_BreakOutOfCompareLoop nop nop nop nop nop nop @@LargeRuns_CopyBoth: mov eax, [ebx] mov [edi], eax mov eax, [esi] mov [edi + SizeOfPointer], eax add ebx, SizeOfPointer add esi, SizeOfPointer add edi, SizeOf2Pointer cmp esi, [esp+pLeftEnd] jae @@LargeRuns_CopyRemainingFromRight_Entry cmp ebx, [esp+pRightEnd] jae @@LargeRuns_CopyRemainingFromLeft_Entry jmp @@LargeRuns_InnerLoop nop nop nop nop nop @@LargeRuns_BinarySearchLeft_Entry: { save our old Left } mov [esp+Temp], esi { save our old Buffer } mov [esp+Temp2], edi mov edi, [esp+pLeftEnd] sub edi, SizeOfPointer { we start with esi = Low and edi = High} nop @@LargeRuns_BinarySearchLeft_Loop: { calculate the middle into ebp } mov ebp, edi sub ebp, esi shr ebp, 3 lea ebp, [esi + ebp *4]; { compare middle with Right} mov eax, [ebp] mov edx, [ebx] sub [esp+SavedCompares], 4 call [esp+Compare] test eax, eax jg @@LargeRuns_BinarySearchLeft_Greater @@LargeRuns_BinarySearchLeft_LesserOrEqual: { move the lower bound } lea esi, [ebp + SizeOfPointer] cmp esi, edi jbe @@LargeRuns_BinarySearchLeft_Loop jmp @@LargeRuns_BinarySearchLeft_Exit @@LargeRuns_BinarySearchLeft_Greater: { mov the higher bound } lea edi, [ebp - SizeOfPointer] cmp esi, edi jbe @@LargeRuns_BinarySearchLeft_Loop jmp @@LargeRuns_BinarySearchLeft_Exit nop nop nop nop nop nop nop @@LargeRuns_BinarySearchLeft_Exit: { edi is pointing to the last entry that's <= Right } { get our old left } mov esi, [esp+Temp] mov edx, edi { restore Buffer} mov edi, [esp+Temp2] jmp @@LargeRuns_BinarySearchLeft_CopyLeadingLeft_Entry nop nop nop nop @@LargeRuns_BinarySearchLeft_CopyLeadingLeft_Loop: { pBuffer^ := pLeft^; } mov eax, [esi] mov [edi], eax { Inc(pBuffer); } add edi, SizeOfPointer { Inc(pLeft); } add esi, SizeOfPointer add [esp+SavedCompares], 4 { while Cardinal(pLeft) <= FoundItem do begin } @@LargeRuns_BinarySearchLeft_CopyLeadingLeft_Entry: cmp esi, edx jbe @@LargeRuns_BinarySearchLeft_CopyLeadingLeft_Loop { we've copied all entries from Left that where <= Right } { are we done with Left? } cmp esi, [esp+pLeftEnd] jae @@LargeRuns_CopyRemainingFromRight_Entry { pBuffer^ := pRight^; } mov eax, [ebx] mov [edi], eax { Inc(pBuffer); } add edi, SizeOfPointer { Inc(pRight); } add ebx, SizeOfPointer { are we done with Right? } cmp ebx, [esp+pRightEnd] jae @@LargeRuns_CopyRemainingFromLeft_Entry { now we can start with the normal compare loop} mov ebp, [esp+Compare] jmp @@LargeRuns_CompareLoop nop nop nop nop nop nop @@LargeRuns_CompareLoop: { if Compare(pLeft^, pRight^) <= 0 then begin } mov edx, [ebx] mov eax, [esi] call ebp test eax, eax jg @@LargeRuns_MergeFromRight @@LargeRuns_MergeFromLeft: { pBuffer^ := pLeft^; } mov eax, [esi] mov [edi], eax { Inc(pBuffer); } add edi, SizeOfPointer { Inc(pLeft); } add esi, SizeOfPointer { if Cardinal(pLeft) >= Cardinal(pLeftEnd) then begin } cmp esi, [esp+pLeftEnd] jb @@LargeRuns_CompareLoop nop nop @@LargeRuns_CopyRemainingFromRight_Entry: mov edx, [esp+pRightEnd] //used in CopyRemainingFromRight @@LargeRuns_CopyRemainingFromRight: { pBuffer^ := pRight^; } mov eax, [ebx] mov [edi], eax { Inc(pBuffer); } add edi, SizeOfPointer { Inc(pRight); } add ebx, SizeOfPointer { while Cardinal(pRight) < Cardinal(pRightEnd) do begin } cmp ebx, edx jb @@LargeRuns_CopyRemainingFromRight { Break; } jmp @@LargeRuns_BreakOutOfCompareLoop @@LargeRuns_MergeFromRight: { pBuffer^ := pRight^; } mov eax, [ebx] mov [edi], eax { Inc(pBuffer); } add edi, SizeOfPointer { Inc(pRight); } add ebx, SizeOfPointer { if Cardinal(pRight) >= Cardinal(pRightEnd) then begin } cmp ebx, [esp+pRightEnd] jb @@LargeRuns_CompareLoop @@LargeRuns_CopyRemainingFromLeft_Entry: mov edx, [esp+pLeftEnd] // used in CopyRemainingFromLeft @@LargeRuns_CopyRemainingFromLeft: { pBuffer^ := pLeft^; } mov eax, [esi] mov [edi], eax { Inc(pBuffer); } add edi, SizeOfPointer { Inc(pLeft); } add esi, SizeOfPointer { while Cardinal(pLeft) < Cardinal(pLeftEnd) do begin } cmp esi, edx jb @@LargeRuns_CopyRemainingFromLeft @@LargeRuns_BreakOutOfCompareLoop: { Inc(pLeft, SegmentSize); } mov eax, [esp+SegmentSize] shl eax, 02h mov esi, [esp+pNextLeft] { Inc(pRight, SegmentSize); } lea ebx, [esi + eax] { pLeftEnd := pRight; } mov [esp+pLeftEnd], ebx { Inc(pRightEnd, SegmentSize + SegmentSize); } lea eax, [ebx + eax] mov [esp+pRightEnd], eax mov [esp+pNextLeft], eax mov edx, [esp+pListEnd] @@LargeRuns_InnerLoopEntry: //requires pRightEnd in eax and pListEnd in edx { while Cardinal(pRightEnd) <= Cardinal(pListEnd) do begin } cmp eax, edx jbe @@LargeRuns_InnerLoop { if Cardinal(pLeft) < Cardinal(pListEnd) then begin } cmp edx, esi jbe @@LargeRuns_NoRemaining { if Cardinal(pRight) < Cardinal(pListEnd) then begin } cmp edx, ebx ja @@LargeRuns_InnerLoopSetRightEnd @@LargeRuns_CopyRemaining: { pBuffer^ := pLeft^; } mov eax, [esi] mov [edi], eax { Inc(pBuffer); } add edi, SizeOfPointer { Inc(pLeft); } add esi, SizeOfPointer { while Cardinal(pLeft) < Cardinal(pListEnd) do begin } cmp esi, edx jb @@LargeRuns_CopyRemaining @@LargeRuns_NoRemaining: { T := A; } mov eax, [esp+A] { A := B; } mov edx, [esp+B] mov [esp+A], edx { B := T; } mov [esp+B], eax { SegmentSize := SegmentSize shl 1; } mov eax, [esp+SegmentSize] shl eax, 1 mov [esp+SegmentSize], eax { while SegmentSize < Count do begin } mov edx, [esp+Count] cmp eax, edx jge @@Exit cmp [esp+SavedCompares], edx jl @@SmallRuns_OuterLoop_Entry jmp @@LargeRuns_OuterLoop // requires SegmentSize in eax @@Exit: { Result := A; } mov eax, [esp+A] { end; } mov edi, [esp + 00] mov esi, [esp + 08] mov ebx, [esp + 04] add esp, EspOffset end; procedure wbMergeSort(aList: Pointer; aCount: Integer; aCompare: TListSortCompare); procedure UseStackBufferLarge; var Buffer: array[0..Pred(4 * 1024)] of Pointer; begin if wbMergeSortInternal(aList, @Buffer[0], aCount, aCompare) <> aList then Move(Buffer, aList^, aCount * SizeOf(Pointer) ); end; procedure UseStackBufferSmall; var Buffer: array[0..Pred(1024)] of Pointer; begin if wbMergeSortInternal(aList, @Buffer[0], aCount, aCompare) <> aList then Move(Buffer, aList^, aCount * SizeOf(Pointer) ); end; var Buffer: Pointer; begin if (aCount < 2) or (not Assigned(aList)) then Exit; if aCount > 4 * 1024 then begin GetMem(Buffer, aCount * SizeOf(Pointer)); if wbMergeSortInternal(aList, Buffer, aCount, aCompare) <> aList then Move(Buffer^, aList^, aCount * SizeOf(Pointer)); FreeMem(Buffer); end else if aCount > 1024 then UseStackBufferLarge else UseStackBufferSmall; end; {$ENDIF WIN32} {$IFDEF WIN64} procedure InsertionSort(aList: PwbPointerArray; left, right: integer; aCompare: TListSortCompare); var i: Integer; j: integer; temp: Pointer; begin for i := Succ(left) to right do begin j := i; temp := aList[j]; while (j > left) AND (aCompare(temp, aList[Pred(j)]) < 0) do begin aList[j] := aList[Pred(j)]; dec(j); end; aList[j] := temp; end; end; procedure MergeSort(ptrList: PwbPointerArray; left: Integer; right: Integer; aCompare: TListSortCompare; Buffer: PwbPointerArray); var i, j, k, mid, aCount: Integer; begin mid := (left + right) div 2; if (left < mid) then begin if (mid - left) <= MIN_SIZE then begin InsertionSort(ptrList, left, mid, aCompare) end else begin MergeSort(ptrList, left, mid, aCompare, Buffer); end; end; if (succ(mid) < right) then begin if (right - succ(mid)) <= MIN_SIZE then begin InsertionSort(ptrList, succ(mid), right, aCompare); end else begin MergeSort(ptrList, succ(mid), right, aCompare, Buffer); end; end; if aCompare(ptrList[mid], ptrList[Succ(mid)]) < 0 then exit; aCount := succ(mid - left); Move(ptrList[left], Buffer[0], aCount * SizeOf(Pointer)); i := 0; j := succ(mid); k := left; while (i < aCount) and (j <= right) do begin if (aCompare(Buffer[i], ptrList[j]) <= 0) then begin ptrList[k] := Buffer[i]; inc(i); end else begin ptrList[k] := ptrList[j]; inc(j); end; inc(k); end; if (i < aCount) then begin Move(Buffer[i], ptrList[k], (aCount - i) * SizeOf(Pointer)); end; end; procedure wbMergeSort(aList: Pointer; aCount: Integer; aCompare: TListSortCompare); var Buffer: Pointer; begin if (aCount < 2) or (not Assigned(aList)) then Exit; if aCount <= MIN_SIZE then begin InsertionSort(aList, 0, Pred(aCount), aCompare); end else begin GetMem(Buffer, aCount * SizeOf(Pointer)); MergeSort(aList, 0, Pred(aCount), aCompare, Buffer); FreeMem(Buffer, aCount * SizeOf(Pointer)); end; end; {$ENDIF WIN64} initialization wbMove := @Move; finalization end. ================================================ FILE: lib/xedit/wbStreams.pas ================================================ {******************************************************************************* The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. *******************************************************************************} unit wbStreams; {$I wbDefines.inc} interface uses SysUtils, Math, Classes, Windows, wbInterface; type TwbBaseCachedFileStreamClass = class of TwbBaseCachedFileStream; TwbBaseCachedFileStream = class(TStream) private function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall; function _AddRef: Integer; stdcall; function _Release: Integer; stdcall; protected FHandle: THandle; FOwnsHandle: Boolean; FCache: PByte; FCacheSize: Integer; FPosition: Int64;//the current position in the file (relative to the beginning of the file) FCacheStart: Int64;//the postion in the file of the start of the cache (relative to the beginning of the file) FCacheEnd: Int64;//the postion in the file of the end of the cache (relative to the beginning of the file) FFileName: string; FLastError: DWORD; procedure HandleError(const Msg: string); procedure RaiseSystemError(const Msg: string; LastError: DWORD); overload; procedure RaiseSystemError(const Msg: string); overload; procedure RaiseSystemErrorFmt(const Msg: string; const Args: array of const); function CreateHandle(FlagsAndAttributes: DWORD): THandle; virtual; abstract; function GetFileSize: Int64; virtual; procedure SetSize(NewSize: Longint); override; procedure SetSize(const NewSize: Int64); override; function FileRead(var Buffer; Count: Longword): Integer; function FileWrite(const Buffer; Count: Longword): Integer; function FileSeek(const Offset: Int64; Origin: TSeekOrigin): Int64; public constructor Create(const FileName: string); overload; constructor Create(const FileName: string; CacheSize: Integer); overload; constructor Create(const FileName: string; CacheSize: Integer; Handle: THandle); overload; virtual; destructor Destroy; override; property CacheSize: Integer read FCacheSize; function Read(var Buffer; Count: Longint): Longint; override; function Write(const Buffer; Count: Longint): Longint; override; function Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; override; function ReadSignature: TwbSignature; inline; function ReadByte: Byte; inline; function ReadWord: Word; inline; function ReadCardinal: Cardinal; inline; function ReadInt64: Int64; inline; function ReadStringLen(Term: Boolean = True): string; inline; function ReadStringLen16: string; inline; function ReadStringTerm: string; inline; procedure WriteCardinal(aCardinal: Cardinal); inline; procedure WriteSmallInt(aSmallInt: SmallInt); inline; end; IDisableStreamReadCache = interface ['{0B6D0004-88D1-42D5-BC0F-447911C0FC21}'] procedure DisableStreamReadCache; procedure EnableStreamReadCache; end; TwbReadOnlyCachedFileStream = class(TwbBaseCachedFileStream, IDisableStreamReadCache) (* This class works by filling the cache each time a call to Read is made and FPosition is outside the existing cache. By filling the cache we mean reading from the file into the temporary cache. Calls to Read when FPosition is in the existing cache are then dealt with by filling the buffer with bytes from the cache. *) private FUseAlignedCache: Boolean; FViewStart: Int64; FViewLength: Int64; FDisableStreamReadCacheRefCount: Integer; procedure DisableStreamReadCache; procedure EnableStreamReadCache; procedure FlushCache; protected function CreateHandle(FlagsAndAttributes: DWORD): THandle; override; function GetFileSize: Int64; override; public constructor Create(const FileName: string; CacheSize: Integer; Handle: THandle); overload; override; property UseAlignedCache: Boolean read FUseAlignedCache write FUseAlignedCache; function Read(var Buffer; Count: Longint): Longint; override; procedure SetViewWindow(const ViewStart, ViewLength: Int64); end; TwbWriteCachedFileStream = class(TwbBaseCachedFileStream, IDisableStreamReadCache) (* This class works by caching calls to Write. By this we mean temporarily storing the bytes to be written in the cache. As each call to Write is processed the cache grows. The cache is written to file when: 1. A call to Write is made when the cache is full. 2. A call to Write is made and FPosition is outside the cache (this must be as a result of a call to Seek). 3. The class is destroyed. Note that data can be read from these streams but the reading is not cached and in fact a read operation will flush the cache before attempting to read the data. *) private FFileSize: Int64; FReadStream: TwbReadOnlyCachedFileStream; FReadStreamCacheSize: Integer; FReadStreamUseAlignedCache: Boolean; procedure DisableStreamReadCache; procedure EnableStreamReadCache; procedure CreateReadStream; procedure FlushCache; protected function CreateHandle(FlagsAndAttributes: DWORD): THandle; override; function GetFileSize: Int64; override; public constructor Create(const FileName: string; CacheSize, ReadStreamCacheSize: Integer; ReadStreamUseAlignedCache: Boolean); overload; destructor Destroy; override; function Read(var Buffer; Count: Longint): Longint; override; function Write(const Buffer; Count: Longint): Longint; override; end; { TwbFileStream = class(TFileStream) function Duplicate: TwbFileStream; end; } implementation function GetFileSizeEx(hFile: THandle; var FileSize: Int64): BOOL; stdcall; external kernel32; function SetFilePointerEx(hFile: THandle; DistanceToMove: Int64; lpNewFilePointer: PInt64; dwMoveMethod: DWORD): BOOL; stdcall; external kernel32; { TwbBaseCachedFileStream } constructor TwbBaseCachedFileStream.Create(const FileName: string); begin Create(FileName, 0); end; constructor TwbBaseCachedFileStream.Create(const FileName: string; CacheSize: Integer); begin Create(FileName, CacheSize, 0); end; constructor TwbBaseCachedFileStream.Create(const FileName: string; CacheSize: Integer; Handle: THandle); const DefaultCacheSize = 16*1024; //16kb - this was chosen empirically - don't make it too large otherwise the progress report is 'jerky' begin inherited Create; FFileName := FileName; FOwnsHandle := Handle=0; if FOwnsHandle then begin FHandle := CreateHandle(FILE_ATTRIBUTE_NORMAL); end else begin FHandle := Handle; end; FCacheSize := CacheSize; if FCacheSize<=0 then begin FCacheSize := DefaultCacheSize; end; GetMem(FCache, FCacheSize); end; destructor TwbBaseCachedFileStream.Destroy; begin FreeMem(FCache); if FOwnsHandle and (FHandle<>0) then begin CloseHandle(FHandle); end; inherited; end; function TwbBaseCachedFileStream.QueryInterface(const IID: TGUID; out Obj): HResult; begin if GetInterface(IID, Obj) then begin Result := S_OK; end else begin Result := E_NOINTERFACE; end; end; function TwbBaseCachedFileStream._AddRef: Integer; begin Result := -1; end; function TwbBaseCachedFileStream._Release: Integer; begin Result := -1; end; procedure TwbBaseCachedFileStream.HandleError(const Msg: string); begin if FLastError<>0 then begin RaiseSystemError(Msg, FLastError); end; end; procedure TwbBaseCachedFileStream.RaiseSystemError(const Msg: string; LastError: DWORD); begin raise EStreamError.Create(Trim(Msg+' ')+SysErrorMessage(LastError)); end; procedure TwbBaseCachedFileStream.RaiseSystemError(const Msg: string); begin RaiseSystemError(Msg, GetLastError); end; procedure TwbBaseCachedFileStream.RaiseSystemErrorFmt(const Msg: string; const Args: array of const); begin RaiseSystemError(Format(Msg, Args)); end; function TwbBaseCachedFileStream.GetFileSize: Int64; begin if not GetFileSizeEx(FHandle, Result) then begin RaiseSystemErrorFmt('GetFileSizeEx failed for %s.', [FFileName]); end; end; procedure TwbBaseCachedFileStream.SetSize(NewSize: Longint); begin SetSize(Int64(NewSize)); end; procedure TwbBaseCachedFileStream.SetSize(const NewSize: Int64); begin Seek(NewSize, soBeginning); if not Windows.SetEndOfFile(FHandle) then begin RaiseSystemErrorFmt('SetEndOfFile for %s.', [FFileName]); end; end; function TwbBaseCachedFileStream.FileRead(var Buffer; Count: Longword): Integer; begin if Windows.ReadFile(FHandle, Buffer, Count, LongWord(Result), nil) then begin FLastError := 0; end else begin FLastError := GetLastError; Result := -1; end; end; function TwbBaseCachedFileStream.FileWrite(const Buffer; Count: Longword): Integer; begin if Windows.WriteFile(FHandle, Buffer, Count, LongWord(Result), nil) then begin FLastError := 0; end else begin FLastError := GetLastError; Result := -1; end; end; function TwbBaseCachedFileStream.FileSeek(const Offset: Int64; Origin: TSeekOrigin): Int64; begin if not SetFilePointerEx(FHandle, Offset, @Result, ord(Origin)) then begin RaiseSystemErrorFmt('SetFilePointerEx failed for %s.', [FFileName]); end; end; function TwbBaseCachedFileStream.Read(var Buffer; Count: Integer): Longint; begin raise EAssertionFailed.Create('Cannot read from this stream'); end; function TwbBaseCachedFileStream.ReadCardinal: Cardinal; begin ReadBuffer(Result, SizeOf(Result)); end; function TwbBaseCachedFileStream.ReadInt64: Int64; begin ReadBuffer(Result, SizeOf(Result)); end; function TwbBaseCachedFileStream.ReadSignature: TwbSignature; begin ReadBuffer(Result, SizeOf(Result)); end; function TwbBaseCachedFileStream.ReadByte: Byte; begin ReadBuffer(Result, SizeOf(Result)); end; function TwbBaseCachedFileStream.ReadWord: Word; begin ReadBuffer(Result, SizeOf(Result)); end; function TwbBaseCachedFileStream.ReadStringLen(Term: Boolean = True): string; var Len : Byte; s : AnsiString; begin ReadBuffer(Len, 1); SetLength(s, Len); if Len > 0 then begin ReadBuffer(s[1], Len); if Term then SetLength(s, Pred(Length(s))); end; Result := s; end; function TwbBaseCachedFileStream.ReadStringLen16: string; var Len : Word; s : AnsiString; begin ReadBuffer(Len, 2); SetLength(s, Len); if Len > 0 then ReadBuffer(s[1], Len); Result := s; end; function TwbBaseCachedFileStream.ReadStringTerm: string; var i: Integer; s: AnsiString; begin if (FCacheEnd - FPosition >= 256) and (FCacheStart >= FPosition) then begin s := PAnsiChar(@FCache[FPosition - FCacheStart]); Inc(FPosition, Succ(Length(s))); end else begin SetLength(s, 256); i := 0; repeat Inc(i); ReadBuffer(s[i], 1); until s[i] = #0; SetLength(s, Pred(i)); end; Result := s; end; function TwbBaseCachedFileStream.Write(const Buffer; Count: Integer): Longint; begin raise EAssertionFailed.Create('Cannot write to this stream'); end; procedure TwbBaseCachedFileStream.WriteCardinal(aCardinal: Cardinal); begin WriteBuffer(aCardinal, SizeOf(aCardinal)); end; procedure TwbBaseCachedFileStream.WriteSmallInt(aSmallInt: SmallInt); begin WriteBuffer(aSmallInt, SizeOf(aSmallInt)); end; function TwbBaseCachedFileStream.Seek(const Offset: Int64; Origin: TSeekOrigin): Int64; //Set FPosition to the value specified - if this has implications for the //cache then overriden Write and Read methods must deal with those. begin case Origin of soBeginning: FPosition := Offset; soEnd: FPosition := GetFileSize+Offset; soCurrent: inc(FPosition, Offset); end; Result := FPosition; end; { TwbReadOnlyCachedFileStream } constructor TwbReadOnlyCachedFileStream.Create(const FileName: string; CacheSize: Integer; Handle: THandle); begin inherited; SetViewWindow(0, inherited GetFileSize); end; function TwbReadOnlyCachedFileStream.CreateHandle(FlagsAndAttributes: DWORD): THandle; begin Result := Windows.CreateFile( PChar(FFileName), GENERIC_READ, FILE_SHARE_READ, nil, OPEN_EXISTING, FlagsAndAttributes, 0 ); if Result=INVALID_HANDLE_VALUE then begin RaiseSystemErrorFmt('Cannot open %s.', [FFileName]); end; end; procedure TwbReadOnlyCachedFileStream.DisableStreamReadCache; begin inc(FDisableStreamReadCacheRefCount); end; procedure TwbReadOnlyCachedFileStream.EnableStreamReadCache; begin dec(FDisableStreamReadCacheRefCount); end; procedure TwbReadOnlyCachedFileStream.FlushCache; begin FCacheStart := 0; FCacheEnd := 0; end; function TwbReadOnlyCachedFileStream.GetFileSize: Int64; begin Result := FViewLength; end; procedure TwbReadOnlyCachedFileStream.SetViewWindow(const ViewStart, ViewLength: Int64); begin if ViewStart<0 then begin raise EAssertionFailed.Create('Invalid view window'); end; if (ViewStart+ViewLength)>inherited GetFileSize then begin raise EAssertionFailed.Create('Invalid view window'); end; FViewStart := ViewStart; FViewLength := ViewLength; FPosition := 0; FCacheStart := 0; FCacheEnd := 0; end; function TwbReadOnlyCachedFileStream.Read(var Buffer; Count: Longint): Longint; var NumOfBytesToCopy, NumOfBytesLeft, NumOfBytesRead: Longint; CachePtr, BufferPtr: PByte; begin if (FDisableStreamReadCacheRefCount>0) or (Count > FCacheSize) then begin FileSeek(FPosition+FViewStart, soBeginning); Result := FileRead(Buffer, Count); if Result=-1 then begin Result := 0;//contract is to return number of bytes that were read end; inc(FPosition, Result); end else begin Result := 0; NumOfBytesLeft := Count; BufferPtr := @Buffer; while NumOfBytesLeft>0 do begin if (FPosition=FCacheEnd) then begin //the current position is not available in the cache so we need to re-fill the cache FCacheStart := FPosition; if UseAlignedCache then begin FCacheStart := FCacheStart - (FCacheStart mod CacheSize); end; FileSeek(FCacheStart+FViewStart, soBeginning); NumOfBytesRead := FileRead(FCache^, CacheSize); if NumOfBytesRead=-1 then begin exit; end; Assert(NumOfBytesRead>=0); FCacheEnd := FCacheStart+NumOfBytesRead; if NumOfBytesRead=0 then begin FLastError := ERROR_HANDLE_EOF;//must be at the end of the file break; end; end; //read from cache to Buffer NumOfBytesToCopy := Min(FCacheEnd-FPosition, NumOfBytesLeft); CachePtr := FCache; inc(CachePtr, FPosition-FCacheStart); Move(CachePtr^, BufferPtr^, NumOfBytesToCopy); inc(Result, NumOfBytesToCopy); inc(FPosition, NumOfBytesToCopy); inc(BufferPtr, NumOfBytesToCopy); dec(NumOfBytesLeft, NumOfBytesToCopy); end; end; end; { TwbWriteCachedFileStream } constructor TwbWriteCachedFileStream.Create(const FileName: string; CacheSize, ReadStreamCacheSize: Integer; ReadStreamUseAlignedCache: Boolean); begin inherited Create(FileName, CacheSize); FReadStreamCacheSize := ReadStreamCacheSize; FReadStreamUseAlignedCache := ReadStreamUseAlignedCache; end; destructor TwbWriteCachedFileStream.Destroy; begin FlushCache;//make sure that the final calls to Write get recorded in the file FreeAndNil(FReadStream); inherited; end; function TwbWriteCachedFileStream.CreateHandle(FlagsAndAttributes: DWORD): THandle; begin Result := Windows.CreateFile( PChar(FFileName), GENERIC_READ or GENERIC_WRITE, 0, nil, CREATE_ALWAYS, FlagsAndAttributes, 0 ); if Result=INVALID_HANDLE_VALUE then begin RaiseSystemErrorFmt('Cannot create %s.', [FFileName]); end; end; procedure TwbWriteCachedFileStream.DisableStreamReadCache; begin CreateReadStream; FReadStream.DisableStreamReadCache; end; procedure TwbWriteCachedFileStream.EnableStreamReadCache; begin Assert(Assigned(FReadStream)); FReadStream.EnableStreamReadCache; end; function TwbWriteCachedFileStream.GetFileSize: Int64; begin Result := FFileSize; end; procedure TwbWriteCachedFileStream.CreateReadStream; begin if not Assigned(FReadStream) then begin FReadStream := TwbReadOnlyCachedFileStream.Create(FFileName, FReadStreamCacheSize, FHandle); FReadStream.UseAlignedCache := FReadStreamUseAlignedCache; end; end; procedure TwbWriteCachedFileStream.FlushCache; var NumOfBytesToWrite: Longint; begin if Assigned(FCache) then begin NumOfBytesToWrite := FCacheEnd-FCacheStart; if NumOfBytesToWrite>0 then begin FileSeek(FCacheStart, soBeginning); if FileWrite(FCache^, NumOfBytesToWrite)<>NumOfBytesToWrite then begin RaiseSystemErrorFmt('FileWrite failed for %s.', [FFileName]); end; if Assigned(FReadStream) then begin FReadStream.FlushCache; end; end; FCacheStart := FPosition; FCacheEnd := FPosition; end; end; function TwbWriteCachedFileStream.Read(var Buffer; Count: Integer): Longint; begin FlushCache; CreateReadStream; Assert(FReadStream.FViewStart=0); if FReadStream.FViewLength<>FFileSize then begin FReadStream.SetViewWindow(0, FFileSize); end; FReadStream.Position := FPosition; Result := FReadStream.Read(Buffer, Count); inc(FPosition, Result); end; function TwbWriteCachedFileStream.Write(const Buffer; Count: Longint): Longint; var NumOfBytesToCopy, NumOfBytesLeft: Longint; CachePtr, BufferPtr: PByte; begin Result := 0; NumOfBytesLeft := Count; BufferPtr := @Buffer; while NumOfBytesLeft>0 do begin if ((FPositionFCacheEnd))//the current position is outside the cache or (FPosition-FCacheStart=FCacheSize)//the cache is full then begin FlushCache; Assert(FCacheStart=FPosition); end; //write from Buffer to the cache NumOfBytesToCopy := Min(FCacheSize-(FPosition-FCacheStart), NumOfBytesLeft); CachePtr := FCache; inc(CachePtr, FPosition-FCacheStart); Move(BufferPtr^, CachePtr^, NumOfBytesToCopy); inc(Result, NumOfBytesToCopy); inc(FPosition, NumOfBytesToCopy); FCacheEnd := Max(FCacheEnd, FPosition); inc(BufferPtr, NumOfBytesToCopy); dec(NumOfBytesLeft, NumOfBytesToCopy); end; FFileSize := Max(FFileSize, FPosition); end; initialization finalization end. ================================================ FILE: lib/xedit/zlib/ZLibEx.inc ================================================ {************************************************************************************************* * ZLibEx.inc * * copyright (c) 2006-2013 base2 technologies * * * * version information for delphi/c++ builder * * * * revision history * * 2013.05.23 updated for delphi xe3 (2013) * * 2012.05.01 updated for delphi xe2 (2012) * * 2010.09.18 updated for delphi xe (2011) * * 2010.01.27 updated for delphi 2010 * * 2009.04.11 updated to use CONDITIONALEXPRESSIONS and CompilerVersion * * 2009.01.28 updated for delphi 2009 * * 2007.10.01 updated for delphi 2007 * * 2005.11.29 created * * * * acknowledgments * * iztok kacin * * 2009.04.11 CONDITIONALEXPRESSIONS and CompilerVersion changes * *************************************************************************************************} {$ifndef CONDITIONALEXPRESSIONS} {** delphi ************************************************************************************} {$ifdef VER80} // delphi 1 {$define Delphi} {$define Version1} {$endif} {$ifdef VER90} // delphi 2 {$define Delphi} {$define Version2} {$endif} {$ifdef VER100} // delphi 3 {$define Delphi} {$define Version3} {$endif} {$ifdef VER120} // delphi 4 {$define Delphi} {$define Version4} {$endif} {** c++ builder *******************************************************************************} {$ifdef VER93} // c++ builder 1 {$define CBuilder} {$define Version1} {$endif} {$ifdef VER110} // c++ builder 3 {$define CBuilder} {$define Version3} {$endif} {$ifdef VER125} // c++ builder 4 {$define CBuilder} {$define Version4} {$endif} {** delphi/c++ builder (common) ***************************************************************} {$ifdef VER130} // delphi/c++ builder 5 {$ifdef BCB} {$define CBuilder} {$ELSE} {$define Delphi} {$endif} {$define Version5} {$define Version5Plus} {$endif} {$ELSE} {$ifdef BCB} {$define CBuilder} {$ELSE} {$define Delphi} {$endif} {$define Version5Plus} {$if CompilerVersion >= 14.0} // delphi 6 {$ifdef VER140} {$define Version6} {$endif} {$define Version6Plus} {$ifend} {$if CompilerVersion >= 15.0} // delphi 7 {$ifdef VER150} {$define Version7} {$endif} {$define Version7Plus} {$ifend} {$if CompilerVersion >= 16.0} // delphi 8 (.net) {$ifdef VER160} {$define Version8} {$endif} {$define Version8Plus} {$ifend} {$if CompilerVersion >= 17.0} // delphi 2005 {$ifdef VER170} {$define Version2005} {$endif} {$define Version2005Plus} {$ifend} {$if CompilerVersion >= 18.0} // bds 2006 {$ifdef VER180} {$define Version2006} {$endif} {$define Version2006Plus} {$ifend} {$if CompilerVersion >= 18.5} // bds 2007 {$ifdef VER185} {$define Version2007} {$endif} {$define Version2007Plus} {$ifend} {$if CompilerVersion >= 20.0} // bds 2009 {$ifdef VER200} {$define Version2009} {$endif} {$define Version2009Plus} {$ifend} {$if CompilerVersion >= 21.0} // bds 2010 {$ifdef VER210} {$define Version2010} {$endif} {$define Version2010Plus} {$ifend} {$if CompilerVersion >= 22.0} // bds xe (2011) {$ifdef VER220} {$define Version2011} {$endif} {$define Version2011Plus} {$ifend} {$if CompilerVersion >= 23.0} // bds xe2 (2012) {$ifdef VER230} {$define Version2012} {$endif} {$define Version2012Plus} {$ifend} {$if CompilerVersion >= 24.0} // bds xe3 (2013) {$ifdef VER240} {$define Version2013} {$endif} {$define Version2013Plus} {$ifend} {$endif} ================================================ FILE: lib/xedit/zlib/ZLibExApi.pas ================================================ {************************************************************************************************* * ZLibExApi.pas * * * * copyright (c) 2000-2013 base2 technologies * * copyright (c) 1995-2002 Borland Software Corporation * * * * revision history * * 2013.05.23 updated to zlib version 1.2.8 * * 2012.05.21 updated for win64 (delphi xe2) * * moved win32 obj files to win32 subfolder * * changed win32 obj options to exclude the underscore * * 2012.05.07 updated to zlib version 1.2.7 * * 2012.03.05 udpated to zlib version 1.2.6 * * 2010.04.20 updated to zlib version 1.2.5 * * 2010.04.15 updated to zlib version 1.2.4 * * 2005.07.25 updated to zlib version 1.2.3 * * 2005.01.11 updated to zlib version 1.2.2 * * 2004.01.06 updated to zlib version 1.2.1 * * 2002.03.15 updated to zlib version 1.1.4 * * * * acknowledgments * * burak kalayci * * 2002.03.15 informing me about the zlib 1.1.4 update * * 2004.01.06 informing me about the zlib 1.2.1 update * * * * vicente sanchez-alarcos * * 2005.01.11 informing me about the zlib 1.2.2 update * * * * mathijs van veluw * * 2005.07.25 informing me about the zlib 1.2.3 update * * * * tommi prami * * 2012.03.05 informing me about the zlib 1.2.6 update * * * * marian pascalau * * 2012.05.21 providing the win64 obj files and your win64 modifications * * * * roman ganz * * 2013.05.23 informing me about the zlib 1.2.8 update * *************************************************************************************************} unit ZLibExApi; interface {$I ZLibEx.inc} const {** version ids *******************************************************************************} ZLIB_VERSION: PAnsiChar = '1.2.8'; ZLIB_VERNUM = $1280; ZLIB_VER_MAJOR = 1; ZLIB_VER_MINOR = 2; ZLIB_VER_REVISION = 8; ZLIB_VER_SUBREVISION = 0; {** compression methods ***********************************************************************} Z_DEFLATED = 8; {** information flags *************************************************************************} Z_INFO_FLAG_SIZE = $1; Z_INFO_FLAG_CRC = $2; Z_INFO_FLAG_ADLER = $4; Z_INFO_NONE = 0; Z_INFO_DEFAULT = Z_INFO_FLAG_SIZE or Z_INFO_FLAG_CRC; {** flush constants ***************************************************************************} Z_NO_FLUSH = 0; Z_PARTIAL_FLUSH = 1; Z_SYNC_FLUSH = 2; Z_FULL_FLUSH = 3; Z_FINISH = 4; Z_BLOCK = 5; Z_TREES = 6; {** return codes ******************************************************************************} Z_OK = 0; Z_STREAM_END = 1; Z_NEED_DICT = 2; Z_ERRNO = (-1); Z_STREAM_ERROR = (-2); Z_DATA_ERROR = (-3); Z_MEM_ERROR = (-4); Z_BUF_ERROR = (-5); Z_VERSION_ERROR = (-6); {** compression levels ************************************************************************} Z_NO_COMPRESSION = 0; Z_BEST_SPEED = 1; Z_BEST_COMPRESSION = 9; Z_DEFAULT_COMPRESSION = (-1); {** compression strategies ********************************************************************} Z_FILTERED = 1; Z_HUFFMAN_ONLY = 2; Z_RLE = 3; Z_FIXED = 4; Z_DEFAULT_STRATEGY = 0; {** data types ********************************************************************************} Z_BINARY = 0; Z_TEXT = 1; Z_ASCII = Z_TEXT; Z_UNKNOWN = 2; {** return code messages **********************************************************************} z_errmsg: Array [0..9] of String = ( 'Need dictionary', // Z_NEED_DICT (2) 'Stream end', // Z_STREAM_END (1) 'OK', // Z_OK (0) 'File error', // Z_ERRNO (-1) 'Stream error', // Z_STREAM_ERROR (-2) 'Data error', // Z_DATA_ERROR (-3) 'Insufficient memory', // Z_MEM_ERROR (-4) 'Buffer error', // Z_BUF_ERROR (-5) 'Incompatible version', // Z_VERSION_ERROR (-6) '' ); type TZAlloc = function (opaque: Pointer; items, size: Integer): Pointer; cdecl; TZFree = procedure (opaque, block: Pointer); cdecl; {** TZStreamRec *******************************************************************************} TZStreamRec = packed record next_in : PByte; // next input byte avail_in : Cardinal; // number of bytes available at next_in total_in : Longword; // total nb of input bytes read so far next_out : PByte; // next output byte should be put here avail_out: Cardinal; // remaining free space at next_out total_out: Longword; // total nb of bytes output so far msg : PAnsiChar; // last error message, NULL if no error state : Pointer; // not visible by applications zalloc : TZAlloc; // used to allocate the internal state zfree : TZFree; // used to free the internal state opaque : Pointer; // private data object passed to zalloc and zfree data_type: Integer; // best guess about the data type: ascii or binary adler : Longword; // adler32 value of the uncompressed data reserved : Longword; // reserved for future use end; {** macros **************************************************************************************} function deflateInit(var strm: TZStreamRec; level: Integer): Integer; {$ifdef Version2005Plus} inline; {$endif} function deflateInit2(var strm: TZStreamRec; level, method, windowBits, memLevel, strategy: Integer): Integer; {$ifdef Version2005Plus} inline; {$endif} function inflateInit(var strm: TZStreamRec): Integer; {$ifdef Version2005Plus} inline; {$endif} function inflateInit2(var strm: TZStreamRec; windowBits: Integer): Integer; {$ifdef Version2005Plus} inline; {$endif} {** external routines ***************************************************************************} function deflateInit_(var strm: TZStreamRec; level: Integer; version: PAnsiChar; recsize: Integer): Integer; function deflateInit2_(var strm: TZStreamRec; level, method, windowBits, memLevel, strategy: Integer; version: PAnsiChar; recsize: Integer): Integer; function deflate(var strm: TZStreamRec; flush: Integer): Integer; function deflateEnd(var strm: TZStreamRec): Integer; function deflateReset(var strm: TZStreamRec): Integer; function inflateInit_(var strm: TZStreamRec; version: PAnsiChar; recsize: Integer): Integer; function inflateInit2_(var strm: TZStreamRec; windowBits: Integer; version: PAnsiChar; recsize: Integer): Integer; function inflate(var strm: TZStreamRec; flush: Integer): Integer; function inflateEnd(var strm: TZStreamRec): Integer; function inflateReset(var strm: TZStreamRec): Integer; function adler32(adler: Longint; const buf; len: Integer): Longint; function crc32(crc: Longint; const buf; len: Integer): Longint; implementation {************************************************************************************************* * link zlib code * * * * bcc32 flags * * -c -O2 -Ve -X -pr -a8 -b -d -k- -vi -tWM -u- * * * * note: do not reorder the following -- doing so will result in external * * functions being undefined * *************************************************************************************************} {$ifdef WIN64} {$L win64\deflate.obj} {$L win64\inflate.obj} {$L win64\inftrees.obj} {$L win64\infback.obj} {$L win64\inffast.obj} {$L win64\trees.obj} {$L win64\compress.obj} {$L win64\adler32.obj} {$L win64\crc32.obj} {$else} {$L win32\deflate.obj} {$L win32\inflate.obj} {$L win32\inftrees.obj} {$L win32\infback.obj} {$L win32\inffast.obj} {$L win32\trees.obj} {$L win32\compress.obj} {$L win32\adler32.obj} {$L win32\crc32.obj} {$endif} {** macros **************************************************************************************} function deflateInit(var strm: TZStreamRec; level: Integer): Integer; begin result := deflateInit_(strm, level, ZLIB_VERSION, SizeOf(TZStreamRec)); end; function deflateInit2(var strm: TZStreamRec; level, method, windowBits, memLevel, strategy: Integer): Integer; begin result := deflateInit2_(strm, level, method, windowBits, memLevel, strategy, ZLIB_VERSION, SizeOf(TZStreamRec)); end; function inflateInit(var strm: TZStreamRec): Integer; begin result := inflateInit_(strm, ZLIB_VERSION, SizeOf(TZStreamRec)); end; function inflateInit2(var strm: TZStreamRec; windowBits: Integer): Integer; begin result := inflateInit2_(strm, windowBits, ZLIB_VERSION, SizeOf(TZStreamRec)); end; {** external routines ***************************************************************************} function deflateInit_(var strm: TZStreamRec; level: Integer; version: PAnsiChar; recsize: Integer): Integer; external; function deflateInit2_(var strm: TZStreamRec; level, method, windowBits, memLevel, strategy: Integer; version: PAnsiChar; recsize: Integer): Integer; external; function deflate(var strm: TZStreamRec; flush: Integer): Integer; external; function deflateEnd(var strm: TZStreamRec): Integer; external; function deflateReset(var strm: TZStreamRec): Integer; external; function inflateInit_(var strm: TZStreamRec; version: PAnsiChar; recsize: Integer): Integer; external; function inflateInit2_(var strm: TZStreamRec; windowBits: Integer; version: PAnsiChar; recsize: Integer): Integer; external; function inflate(var strm: TZStreamRec; flush: Integer): Integer; external; function inflateEnd(var strm: TZStreamRec): Integer; external; function inflateReset(var strm: TZStreamRec): Integer; external; function adler32(adler: Longint; const buf; len: Integer): Longint; external; function crc32(crc: Longint; const buf; len: Integer): Longint; external; {** zlib function implementations ***************************************************************} function zcalloc(opaque: Pointer; items, size: Integer): Pointer; begin GetMem(result,items * size); end; procedure zcfree(opaque, block: Pointer); begin FreeMem(block); end; {** c function implementations ******************************************************************} function memset(p: Pointer; b: Byte; count: Integer): Pointer; cdecl; begin FillChar(p^, count, b); result := p; end; procedure memcpy(dest, source: Pointer; count: Integer); cdecl; begin Move(source^, dest^, count); end; {$ifndef WIN64} procedure _llmod; asm jmp System.@_llmod; end; {$endif} end. ================================================ FILE: lib/xedit/zlib/zlibex.pas ================================================ {************************************************************************************************* * ZLibEx.pas * * * * copyright (c) 2000-2013 base2 technologies * * copyright (c) 1995-2002 Borland Software Corporation * * * * revision history * * 2012.05.21 updated for win64 (delphi xe2) * * added NativeInt type for delphi 2007- * * added NativeUInt type for delphi 2007- * * 2011.07.21 fixed routines to validate size before calling Move * * 2010.07.01 hide overloaded Z*String* routines for delphi 5 * * 2010.05.02 added ZDelfateEx and ZInflateEx * * 2010.04.20 added TZ*Buffer classes * * 2010.04.15 moved core zlib routines to separate unit (ZLibExApi.pas) * * added ZDeflate* and ZInflate* * * 2010.04.14 fixed ZInternalCompress loops * * fixed ZInternalDecompress loops * * updated ZInternalCompressStream loops * * updated ZInternalDecompressStream loops * * 2010.01.27 updated for delphi 2010 * * 2009.04.14 added overloaded string routines for AnsiString and UnicodeString * * 2009.01.28 updated for delphi 2009 String (UnicodeString) * * 2008.05.15 added TStreamPos type for Stream.Position variants * * added TCustomZStream.Stream* methods * * 2007.08.17 modified TZCompressionStream.Write to use Write instead of WriteBuffer * * 2007.03.15 moved gzip routines to separate unit (ZLibExGZ.pas) * * 2006.10.07 fixed EZLibError constructor for c++ builder compatibility * * 2006.03.28 moved Z_DEFLATED to interface section * * added custom compression levels zcLevel1 thru zcLevel9 * * 2006.03.27 added ZCompressStreamWeb * * 2006.03.24 added ZAdler32 and ZCrc32 * * 2005.11.29 changed FStreamPos to Int64 for delphi 6+ * * 2005.03.04 modified ZInternalCompressStream loops * * modified ZInternalDecompressStream loops * * 2005.02.07 fixed ZInternalCompressStream loop conditions * * fixed ZInternalDecompressStream loop conditions * * 2005.01.11 added ZCompressStrWeb * * 2003.04.14 added ZCompress2 and ZDecompress2 * * added ZCompressStr2 and ZDecompressStr2 * * added ZCompressStream2 and ZDecompressStream2 * * added overloaded T*Stream constructors to support InflateInit2 * * and DeflateInit2 * * fixed ZDecompressStream to use ZDecompressCheck instead of ZCompressCheck * * 2001.11.27 enhanced TZDecompressionStream.Read to adjust source stream position upon end * * of compression data * * fixed endless loop in TZDecompressionStream.Read when destination count was * * greater than uncompressed data * * 2001.10.26 renamed unit to integrate "nicely" with delphi 6 * * 2000.11.24 added soFromEnd condition to TZDecompressionStream.Seek * * added ZCompressStream and ZDecompressStream * * 2000.06.13 optimized, fixed, rewrote, and enhanced the zlib.pas unit included on the * * delphi cd (zlib version 1.1.3) * * * * acknowledgments * * erik turner * * 2001.10.26 Z*Stream routines * * * * david bennion * * 2001.11.27 finding the nasty little endless loop quirk with the * * TZDecompressionStream.Read method * * * * luigi sandon * * 2005.02.07 pointing out the missing loop condition (Z_STREAM_END) in * * ZInternalCompressStream and ZInternalDecompressStream * * * * ferry van genderen * * 2005.03.04 assisting me fine tune and beta test ZInternalCompressStream and * * ZInternalDecompressStream * * * * j. rathlev * * 2005.11.28 pointing out the FStreamPos and TStream.Position type inconsistency * * * * anders johansen * * 2006.10.07 pointing out the ELibError constructor incompatibility with c++ builder * * * * marcin szafranski * * 2009.01.28 beta testing the delphi 2009 changes * * * * iztok kacin * * 2009.04.14 assisting me design and further improve support for delphi 2009 * * * * oleg matrozov * * 2010.04.14 pointing out the missing loop condition (avail_in > 0) in ZInternalCompress * * and ZInternalDecompress * * 2010.04.20 prototyping and assisting with the TZ*Buffer classes * * * * edward koo * * 2010.07.01 pointing out the delphi 5 incompatibility with the overloaded Z*String* * * routines * * * * egron elbra * * 2011.07.20 pointing out the range exception when moving empty strings * * * * marian pascalau * * 2012.05.21 providing their win64 modifications * * * * donations * * 2011.05.06 farshad mohajeri * * 2012.06.07 marat safin * * 2012.12.14 moacir schmidt * * 2013.05.23 roman ganz * *************************************************************************************************} unit ZLibEx; interface {$I ZLibEx.inc} uses SysUtils, Classes, ZLibExApi; type {$ifndef UNICODE} RawByteString = AnsiString; UnicodeString = WideString; UnicodeChar = WideChar; {$else ifdef Version2010Plus} UnicodeChar = WideChar; {$endif} {$ifndef Version2009Plus} NativeInt = Integer; NativeUInt = Cardinal; {$endif} TStreamPos = {$ifdef Version6Plus} Int64 {$else} Longint {$endif}; TZCompressionLevel = ( zcNone, zcFastest, zcDefault, zcMax, zcLevel1, zcLevel2, zcLevel3, zcLevel4, zcLevel5, zcLevel6, zcLevel7, zcLevel8, zcLevel9 ); TZStrategy = ( zsDefault, zsFiltered, zsHuffman, zsRLE, zsFixed ); TZError = ( zeError, zeStreamError, zeDataError, zeMemoryError, zeBufferError, zeVersionError ); TZFlush = ( zfNoFlush, zfPartialFlush, zfSyncFlush, zfFullFlush, zfFinish, zfBlock, zfTrees ); const ZLevels: Array [TZCompressionLevel] of Integer = ( Z_NO_COMPRESSION, // zcNone Z_BEST_SPEED, // zcFastest Z_DEFAULT_COMPRESSION, // zcDefault Z_BEST_COMPRESSION, // zcMax 1, // zcLevel1 2, // zcLevel2 3, // zcLevel3 4, // zcLevel4 5, // zcLevel5 6, // zcLevel6 7, // zcLevel7 8, // zcLevel8 9 // zcLevel9 ); ZStrategies: Array [TZStrategy] of Integer = ( Z_DEFAULT_STRATEGY, // zsDefault Z_FILTERED, // zsFiltered Z_HUFFMAN_ONLY, // zsHuffman Z_RLE, // zsRLE Z_FIXED // zsFixed ); ZErrors: Array [TZError] of Integer = ( Z_ERRNO, // zeError Z_STREAM_ERROR, // zeStreamError Z_DATA_ERROR, // zeDataError Z_MEM_ERROR, // zeMemoryError Z_BUF_ERROR, // zeBufferError Z_VERSION_ERROR // zeVersionError ); ZFlushes: Array [TZFlush] of Integer = ( Z_NO_FLUSH, // zfNoFlush Z_PARTIAL_FLUSH, // zfPartialFlush Z_SYNC_FLUSH, // zfSyncFlush Z_FULL_FLUSH, // zfFullFlush Z_FINISH, // zfFinish Z_BLOCK, // zfBlock Z_TREES // zfTrees ); type {** TZ*Function *******************************************************************************} TZReadFunction = function (param: Pointer; var buffer; size: Integer): Integer; TZWriteFunction = function (param: Pointer; const buffer; size: Integer): Integer; {** TZInformation *****************************************************************************} TZInformation = packed record CompressedFlags : Longint; CompressedSize : TStreamPos; CompressedCrc : Longint; CompressedAdler : Longint; UncompressedFlags: Longint; UncompressedSize : TStreamPos; UncompressedCrc : Longint; UncompressedAdler: Longint; end; {** TCustomZStream ****************************************************************************} TCustomZStream = class(TStream) private FStream : TStream; FStreamPos : TStreamPos; FOnProgress: TNotifyEvent; FZStream : TZStreamRec; FBuffer : Array [Word] of Byte; function GetStreamPosition: TStreamPos; procedure SetStreamPosition(value: TStreamPos); protected constructor Create(stream: TStream); function StreamRead(var buffer; count: Longint): Longint; function StreamWrite(const buffer; count: Longint): Longint; function StreamSeek(offset: Longint; origin: Word): Longint; procedure StreamReadBuffer(var buffer; count: Longint); procedure StreamWriteBuffer(const buffer; count: Longint); procedure DoProgress; dynamic; property StreamPosition: TStreamPos read GetStreamPosition write SetStreamPosition; property OnProgress: TNotifyEvent read FOnProgress write FOnProgress; end; {** TZCompressionStream ***********************************************************************} TZCompressionStream = class(TCustomZStream) private function GetCompressionRate: Single; public constructor Create(dest: TStream; compressionLevel: TZCompressionLevel = zcDefault); overload; constructor Create(dest: TStream; compressionLevel: TZCompressionLevel; windowBits, memLevel: Integer; strategy: TZStrategy); overload; destructor Destroy; override; function Read(var buffer; count: Longint): Longint; override; function Write(const buffer; count: Longint): Longint; override; function Seek(offset: Longint; origin: Word): Longint; override; property CompressionRate: Single read GetCompressionRate; property OnProgress; end; {** TZDecompressionStream *********************************************************************} TZDecompressionStream = class(TCustomZStream) public constructor Create(source: TStream); overload; constructor Create(source: TStream; windowBits: Integer); overload; destructor Destroy; override; function Read(var buffer; count: Longint): Longint; override; function Write(const buffer; count: Longint): Longint; override; function Seek(offset: Longint; origin: Word): Longint; override; property OnProgress; end; {** TZCustomBuffer ****************************************************************************} TZCustomBuffer = class(TObject) private FBuffer : Pointer; FBufferCapacity: Integer; FBufferSize : Integer; protected FZStream: TZStreamRec; procedure BufferWrite(const buffer: Pointer; size: Integer); procedure BufferRead(var buffer: Pointer; size: Integer); procedure BufferCapacity(capacity: Integer); property BufferSize: Integer read FBufferSize; public constructor Create; destructor Destroy; override; procedure Clear; virtual; procedure Flush(flush: TZFlush); virtual; function Write(const buffer: Pointer; size: Integer): Integer; overload; virtual; abstract; function Write(const s: AnsiString): Integer; overload; function Read(var buffer: Pointer; size: Integer): Integer; overload; function Read(var s: AnsiString): Integer; overload; end; {** TZCompressionBuffer ***********************************************************************} TZCompressionBuffer = class(TZCustomBuffer) public constructor Create(level: TZCompressionLevel = zcDefault); overload; constructor Create(level: TZCompressionLevel; windowBits, memLevel: Integer; strategy: TZStrategy); overload; destructor Destroy; override; procedure Clear; override; procedure Flush(flush: TZFlush); override; function Write(const buffer: Pointer; size: Integer): Integer; override; end; {** TZDecompressionBuffer *********************************************************************} TZDecompressionBuffer = class(TZCustomBuffer) public constructor Create; overload; constructor Create(windowBits: Integer); overload; destructor Destroy; override; procedure Clear; override; function Write(const buffer: Pointer; size: Integer): Integer; override; end; {** zlib deflate routines ***********************************************************************} function ZDeflateInit(var stream: TZStreamRec; level: TZCompressionLevel): Integer; {$ifdef Version2005Plus} inline; {$endif} function ZDeflateInit2(var stream: TZStreamRec; level: TZCompressionLevel; windowBits, memLevel: Integer; strategy: TZStrategy): Integer; {$ifdef Version2005Plus} inline; {$endif} function ZDeflate(var stream: TZStreamRec; flush: TZFlush): Integer; {$ifdef Version2005Plus} inline; {$endif} function ZDeflateEnd(var stream: TZStreamRec): Integer; {$ifdef Version2005Plus} inline; {$endif} function ZDeflateReset(var stream: TZStreamRec): Integer; {$ifdef Version2005Plus} inline; {$endif} {** zlib inflate routines ***********************************************************************} function ZInflateInit(var stream: TZStreamRec): Integer; {$ifdef Version2005Plus} inline; {$endif} function ZInflateInit2(var stream: TZStreamRec; windowBits: Integer): Integer; {$ifdef Version2005Plus} inline; {$endif} function ZInflate(var stream: TZStreamRec; flush: TZFlush): Integer; {$ifdef Version2005Plus} inline; {$endif} function ZInflateEnd(var stream: TZStreamRec): Integer; {$ifdef Version2005Plus} inline; {$endif} function ZInflateReset(var stream: TZStreamRec): Integer; {$ifdef Version2005Plus} inline; {$endif} {** zlib checksum routines **********************************************************************} function ZAdler32(adler: Longint; const buffer; size: Integer): Longint; {$ifdef Version2005Plus} inline; {$endif} function ZCrc32(crc: Longint; const buffer; size: Integer): Longint; {$ifdef Version2005Plus} inline; {$endif} {** zlib custom routines ************************************************************************} procedure ZDeflateEx(var stream: TZStreamRec; param: Pointer; read: TZReadFunction; write: TZWriteFunction; flush: TZFlush); procedure ZInflateEx(var stream: TZStreamRec; param: Pointer; read: TZReadFunction; write: TZWriteFunction; flush: TZFlush); {************************************************************************************************* * ZCompress * * * * pre-conditions * * inBuffer = pointer to uncompressed data * * inSize = size of inBuffer (bytes) * * outBuffer = pointer (unallocated) * * level = compression level * * * * post-conditions * * outBuffer = pointer to compressed data (allocated) * * outSize = size of outBuffer (bytes) * *************************************************************************************************} procedure ZCompress(const inBuffer: Pointer; inSize: Integer; out outBuffer: Pointer; out outSize: Integer; level: TZCompressionLevel = zcDefault); {************************************************************************************************* * ZCompress2 * * * * pre-conditions * * inBuffer = pointer to uncompressed data * * inSize = size of inBuffer (bytes) * * outBuffer = pointer (unallocated) * * level = compression level * * method = compression method * * windowBits = window bits * * memLevel = memory level * * strategy = compression strategy * * * * post-conditions * * outBuffer = pointer to compressed data (allocated) * * outSize = size of outBuffer (bytes) * *************************************************************************************************} procedure ZCompress2(const inBuffer: Pointer; inSize: Integer; out outBuffer: Pointer; out outSize: Integer; level: TZCompressionLevel; windowBits, memLevel: Integer; strategy: TZStrategy); {************************************************************************************************* * ZDecompress * * * * pre-conditions * * inBuffer = pointer to compressed data * * inSize = size of inBuffer (bytes) * * outBuffer = pointer (unallocated) * * outEstimate = estimated size of uncompressed data (bytes) * * * * post-conditions * * outBuffer = pointer to decompressed data (allocated) * * outSize = size of outBuffer (bytes) * *************************************************************************************************} procedure ZDecompress(const inBuffer: Pointer; inSize: Integer; out outBuffer: Pointer; out outSize: Integer; outEstimate: Integer = 0); {************************************************************************************************* * ZDecompress2 * * * * pre-conditions * * inBuffer = pointer to compressed data * * inSize = size of inBuffer (bytes) * * outBuffer = pointer (unallocated) * * windowBits = window bits * * outEstimate = estimated size of uncompressed data (bytes) * * * * post-conditions * * outBuffer = pointer to decompressed data (allocated) * * outSize = size of outBuffer (bytes) * *************************************************************************************************} procedure ZDecompress2(const inBuffer: Pointer; inSize: Integer; out outBuffer: Pointer; out outSize: Integer; windowBits: Integer; outEstimate: Integer = 0); {** string routines *****************************************************************************} {************************************************************************************************* * ZCompressStr * * * * pre-conditions * * s = uncompressed data string * * level = compression level * * * * return * * compressed data string * *************************************************************************************************} function ZCompressStr(const s: AnsiString; level: TZCompressionLevel = zcDefault): RawByteString; procedure ZCompressString(var result: RawByteString; const s: AnsiString; level: TZCompressionLevel = zcDefault); overload; {$ifdef Version6Plus} procedure ZCompressString(var result: RawByteString; const s: UnicodeString; level: TZCompressionLevel = zcDefault); overload; {$endif} {************************************************************************************************* * ZCompressStrEx * * * * pre-conditions * * s = uncompressed data string * * level = compression level * * * * return * * compressed data string with 4 byte (integer) header indicating * * original uncompressed data length * *************************************************************************************************} function ZCompressStrEx(const s: AnsiString; level: TZCompressionLevel = zcDefault): RawByteString; procedure ZCompressStringEx(var result: RawByteString; const s: AnsiString; level: TZCompressionLevel = zcDefault); overload; {$ifdef Version6Plus} procedure ZCompressStringEx(var result: RawByteString; const s: UnicodeString; level: TZCompressionLevel = zcDefault); overload; {$endif} {************************************************************************************************* * ZCompressStr2 * * * * pre-conditions * * s = uncompressed data string * * level = compression level * * windowBits = window bits * * memLevel = memory level * * strategy = compression strategy * * * * return * * compressed data string * *************************************************************************************************} function ZCompressStr2(const s: AnsiString; level: TZCompressionLevel; windowBits, memLevel: Integer; strategy: TZStrategy): RawByteString; procedure ZCompressString2(var result: RawByteString; const s: AnsiString; level: TZCompressionLevel; windowBits, memLevel: Integer; strategy: TZStrategy); overload; {$ifdef Version6Plus} procedure ZCompressString2(var result: RawByteString; const s: UnicodeString; level: TZCompressionLevel; windowBits, memLevel: Integer; strategy: TZStrategy); overload; {$endif} {************************************************************************************************* * ZCompressStrWeb * * * * pre-conditions * * s = uncompressed data string * * * * return * * compressed data string * *************************************************************************************************} function ZCompressStrWeb(const s: AnsiString): RawByteString; procedure ZCompressStringWeb(var result: RawByteString; const s: AnsiString); overload; {$ifdef Version6Plus} procedure ZCompressStringWeb(var result: RawByteString; const s: UnicodeString); overload; {$endif} {************************************************************************************************* * ZDecompressStr * * * * pre-conditions * * s = compressed data string * * * * return * * uncompressed data string * *************************************************************************************************} function ZDecompressStr(const s: RawByteString): AnsiString; procedure ZDecompressString(var result: AnsiString; const s: RawByteString); overload; {$ifdef Version6Plus} procedure ZDecompressString(var result: UnicodeString; const s: RawByteString); overload; {$endif} {************************************************************************************************* * ZDecompressStrEx * * * * pre-conditions * * s = compressed data string with 4 byte (integer) header indicating * * original uncompressed data length * * * * return * * uncompressed data string * *************************************************************************************************} function ZDecompressStrEx(const s: RawByteString): AnsiString; procedure ZDecompressStringEx(var result: AnsiString; const s: RawByteString); overload; {$ifdef Version6Plus} procedure ZDecompressStringEx(var result: UnicodeString; const s: RawByteString); overload; {$endif} {************************************************************************************************* * ZDecompressStr2 * * * * pre-conditions * * s = compressed data string * * windowBits = window bits * * * * return * * uncompressed data string * *************************************************************************************************} function ZDecompressStr2(const s: RawByteString; windowBits: Integer): AnsiString; procedure ZDecompressString2(var result: AnsiString; const s: RawByteString; windowBits: Integer); overload; {$ifdef Version6Plus} procedure ZDecompressString2(var result: UnicodeString; const s: RawByteString; windowBits: Integer); overload; {$endif} {** stream routines *****************************************************************************} procedure ZCompressStream(inStream, outStream: TStream; level: TZCompressionLevel = zcDefault); procedure ZCompressStream2(inStream, outStream: TStream; level: TZCompressionLevel; windowBits, memLevel: Integer; strategy: TZStrategy); procedure ZCompressStreamWeb(inStream, outStream: TStream); procedure ZDecompressStream(inStream, outStream: TStream); procedure ZDecompressStream2(inStream, outStream: TStream; windowBits: Integer); {************************************************************************************************} type EZLibErrorClass = class of EZlibError; EZLibError = class(Exception) private FErrorCode: Integer; public constructor Create(code: Integer; const dummy: String = ''); overload; constructor Create(error: TZError; const dummy: String = ''); overload; property ErrorCode: Integer read FErrorCode write FErrorCode; end; EZCompressionError = class(EZLibError); EZDecompressionError = class(EZLibError); { DecompressToUserBuf decompresses data, buffer to buffer, in one call. In: InBuf = ptr to compressed data InBytes = number of bytes in InBuf Out: OutBuf = ptr to user-allocated buffer to contain decompressed data BufSize = number of bytes in OutBuf } procedure DecompressToUserBuf(const InBuf: Pointer; InBytes: Integer; const OutBuf: Pointer; BufSize: Integer); implementation function DCheck(code: Integer): Integer; begin Result := code; if code < 0 then raise EZDecompressionError.Create(64673); //!! end; const SZInvalid = 'Invalid ZStream operation!'; {************************************************************************************************} function ZCompressCheck(code: Integer): Integer; begin result := code; if code < 0 then begin raise EZCompressionError.Create(code); end; end; function ZDecompressCheck(code: Integer; raiseBufferError: Boolean = True): Integer; begin Result := code; if code < 0 then begin if (code <> Z_BUF_ERROR) or raiseBufferError then begin raise EZDecompressionError.Create(code); end; end; end; {** zlib deflate routines ***********************************************************************} function ZDeflateInit(var stream: TZStreamRec; level: TZCompressionLevel): Integer; begin result := deflateInit_(stream, ZLevels[level], ZLIB_VERSION, SizeOf(TZStreamRec)); end; function ZDeflateInit2(var stream: TZStreamRec; level: TZCompressionLevel; windowBits, memLevel: Integer; strategy: TZStrategy): Integer; begin result := deflateInit2_(stream, ZLevels[level], Z_DEFLATED, windowBits, memLevel, ZStrategies[strategy], ZLIB_VERSION, SizeOf(TZStreamRec)); end; function ZDeflate(var stream: TZStreamRec; flush: TZFlush): Integer; begin result := deflate(stream, ZFlushes[flush]); end; function ZDeflateEnd(var stream: TZStreamRec): Integer; begin result := deflateEnd(stream); end; function ZDeflateReset(var stream: TZStreamRec): Integer; begin result := deflateReset(stream); end; {** zlib inflate routines ***********************************************************************} function ZInflateInit(var stream: TZStreamRec): Integer; begin result := inflateInit_(stream, ZLIB_VERSION, SizeOf(TZStreamRec)); end; function ZInflateInit2(var stream: TZStreamRec; windowBits: Integer): Integer; begin result := inflateInit2_(stream, windowBits, ZLIB_VERSION, SizeOf(TZStreamRec)); end; function ZInflate(var stream: TZStreamRec; flush: TZFlush): Integer; begin result := inflate(stream, ZFlushes[flush]); end; function ZInflateEnd(var stream: TZStreamRec): Integer; begin result := inflateEnd(stream); end; function ZInflateReset(var stream: TZStreamRec): Integer; begin result := inflateReset(stream); end; {** zlib checksum routines **********************************************************************} function ZAdler32(adler: Longint; const buffer; size: Integer): Longint; begin result := adler32(adler,buffer,size); end; function ZCrc32(crc: Longint; const buffer; size: Integer): Longint; begin result := crc32(crc,buffer,size); end; {** zlib extended routines **********************************************************************} procedure ZDeflateEx(var stream: TZStreamRec; param: Pointer; read: TZReadFunction; write: TZWriteFunction; flush: TZFlush); const bufferSize = 8192; var zresult : Integer; readBuffer : Array [0..bufferSize - 1] of Byte; writeBuffer: Array [0..bufferSize - 1] of Byte; writeSize : Integer; flushEx : TZFlush; begin if Assigned(read) then begin stream.avail_in := read(param, readBuffer, bufferSize); end else stream.avail_in := 0; repeat stream.next_in := @readBuffer; repeat stream.avail_out := bufferSize; stream.next_out := @writeBuffer; flushEx := flush; if (flushEx = zfFinish) and (stream.avail_in = bufferSize) then begin flushEx := zfNoFlush; end; zresult := ZCompressCheck(ZDeflate(stream, flushEx)); writeSize := bufferSize - stream.avail_out; write(param, writeBuffer, writeSize); until stream.avail_out > 0; //assert: stream.avail_in = 0 if (zresult <> Z_STREAM_END) and Assigned(read) then begin stream.avail_in := read(param, readBuffer, bufferSize); end; until (stream.avail_in = 0) and (flush = flushEx); end; procedure ZInflateEx(var stream: TZStreamRec; param: Pointer; read: TZReadFunction; write: TZWriteFunction; flush: TZFlush); const bufferSize = 8192; var zresult : Integer; readBuffer : Array [0..bufferSize - 1] of Byte; writeBuffer: Array [0..bufferSize - 1] of Byte; writeSize : Integer; begin if Assigned(read) then begin stream.avail_in := read(param, readBuffer, bufferSize); end else stream.avail_in := 0; zresult := Z_OK; while (zresult <> Z_STREAM_END) and (stream.avail_in > 0) do begin stream.next_in := @readBuffer; repeat stream.avail_out := bufferSize; stream.next_out := @writeBuffer; zresult := ZDecompressCheck(ZInflate(stream, flush), False); writeSize := bufferSize - stream.avail_out; write(param, writeBuffer, writeSize); until stream.avail_out > 0; if (zresult <> Z_STREAM_END) and Assigned(read) then begin stream.avail_in := read(param, readBuffer, bufferSize); end; end; end; {** private buffer routines *********************************************************************} type PZBufferParam = ^TZBufferParam; TZBufferParam = packed record InBuffer : Pointer; InPosition : Integer; InSize : Integer; OutBuffer : Pointer; OutPosition: Integer; OutSize : Integer; end; function ZBufferRead(p: Pointer; var buffer; size: Integer): Integer; var param: PZBufferParam; begin param := PZBufferParam(p); result := param^.InSize - param^.InPosition; if result > size then result := size; Move(Pointer(Integer(param^.InBuffer) + param^.InPosition)^, buffer, result); Inc(param^.InPosition, result); end; function ZBufferWrite(p: Pointer; const buffer; size: Integer): Integer; var param: PZBufferParam; begin param := PZBufferParam(p); if param^.OutPosition + size > param^.OutSize then begin param^.OutSize := param^.OutPosition + size; ReallocMem(Pointer(param^.OutBuffer), param^.OutSize); end; Move(buffer, Pointer(Integer(param^.OutBuffer) + param^.OutPosition)^, size); Inc(param^.OutPosition, size); result := size; end; procedure ZInternalCompressEx(var zstream: TZStreamRec; const inBuffer: Pointer; inSize: Integer; out outBuffer: Pointer; out outSize: Integer); var param: TZBufferParam; begin FillChar(param, SizeOf(TZBufferParam), 0); outBuffer := Nil; outSize := 0; param.InBuffer := inBuffer; param.InSize := inSize; try ZDeflateEx(zstream, @param, @ZBufferRead, @ZBufferWrite, zfFinish); ZCompressCheck(ZDeflateEnd(zstream)); outBuffer := param.OutBuffer; outSize := param.OutSize; except FreeMem(param.OutBuffer); raise; end; end; procedure ZInternalDecompressEx(zstream: TZStreamRec; const inBuffer: Pointer; inSize: Integer; out outBuffer: Pointer; out outSize: Integer; outEstimate: Integer); var param: TZBufferParam; begin FillChar(param, SizeOf(TZBufferParam), 0); outBuffer := Nil; outSize := 0; param.InBuffer := inBuffer; param.InSize := inSize; if outEstimate > 0 then begin GetMem(param.OutBuffer, outEstimate); param.OutSize := outEstimate; end; try ZInflateEx(zstream, @param, @ZBufferRead, @ZBufferWrite, zfNoFlush); ZDecompressCheck(ZInflateEnd(zstream)); outBuffer := param.OutBuffer; outSize := param.OutSize; except FreeMem(param.OutBuffer); raise; end; end; procedure ZInternalCompress(var zstream: TZStreamRec; const inBuffer: Pointer; inSize: Integer; out outBuffer: Pointer; out outSize: Integer); const delta = 256; var zresult: Integer; begin outSize := ((inSize + (inSize div 10) + 12) + 255) and not 255; outBuffer := Nil; try try zstream.next_in := inBuffer; zstream.avail_in := inSize; repeat ReallocMem(outBuffer, outSize); zstream.next_out := PByte(NativeUInt(outBuffer) + zstream.total_out); zstream.avail_out := NativeUInt(outSize) - zstream.total_out; zresult := ZCompressCheck(ZDeflate(zstream, zfNoFlush)); Inc(outSize, delta); until (zresult = Z_STREAM_END) or (zstream.avail_in = 0); while zresult <> Z_STREAM_END do begin ReallocMem(outBuffer, outSize); zstream.next_out := PByte(NativeUInt(outBuffer) + zstream.total_out); zstream.avail_out := NativeUInt(outSize) - zstream.total_out; zresult := ZCompressCheck(ZDeflate(zstream, zfFinish)); Inc(outSize, delta); end; finally ZCompressCheck(ZDeflateEnd(zstream)); end; ReallocMem(outBuffer, zstream.total_out); outSize := zstream.total_out; except FreeMem(outBuffer); raise; end; end; procedure ZInternalDecompress(zstream: TZStreamRec; const inBuffer: Pointer; inSize: Integer; out outBuffer: Pointer; out outSize: Integer; outEstimate: Integer); var zresult: Integer; delta : Integer; begin delta := (inSize + 255) and not 255; if outEstimate = 0 then outSize := delta else outSize := outEstimate; outBuffer := Nil; try try zresult := Z_OK; zstream.avail_in := inSize; zstream.next_in := inBuffer; while (zresult <> Z_STREAM_END) and (zstream.avail_in > 0) do begin repeat ReallocMem(outBuffer, outSize); zstream.next_out := PByte(NativeUInt(outBuffer) + zstream.total_out); zstream.avail_out := NativeUInt(outSize) - zstream.total_out; zresult := ZDecompressCheck(ZInflate(zstream, zfNoFlush), False); Inc(outSize, delta); until (zresult = Z_STREAM_END) or (zstream.avail_out > 0); end; finally ZDecompressCheck(ZInflateEnd(zstream)); end; ReallocMem(outBuffer, zstream.total_out); outSize := zstream.total_out; except if Assigned(outBuffer) then FreeMem(outBuffer); raise; end; end; {** buffer routines *****************************************************************************} procedure ZCompress(const inBuffer: Pointer; inSize: Integer; out outBuffer: Pointer; out outSize: Integer; level: TZCompressionLevel); var zstream: TZStreamRec; begin FillChar(zstream, SizeOf(TZStreamRec), 0); ZCompressCheck(ZDeflateInit(zstream, level)); ZInternalCompress(zstream, inBuffer, inSize, outBuffer, outSize); end; procedure ZCompress2(const inBuffer: Pointer; inSize: Integer; out outBuffer: Pointer; out outSize: Integer; level: TZCompressionLevel; windowBits, memLevel: Integer; strategy: TZStrategy); var zstream: TZStreamRec; begin FillChar(zstream, SizeOf(TZStreamRec), 0); ZCompressCheck(ZDeflateInit2(zstream, level, windowBits, memLevel, strategy)); ZInternalCompress(zstream, inBuffer, inSize, outBuffer, outSize); end; procedure ZDecompress(const inBuffer: Pointer; inSize: Integer; out outBuffer: Pointer; out outSize: Integer; outEstimate: Integer); var zstream: TZStreamRec; begin FillChar(zstream, SizeOf(TZStreamRec), 0); ZDecompressCheck(ZInflateInit(zstream)); ZInternalDecompress(zstream, inBuffer, inSize, outBuffer, outSize, outEstimate); end; procedure ZDecompress2(const inBuffer: Pointer; inSize: Integer; out outBuffer: Pointer; out outSize: Integer; windowBits: Integer; outEstimate: Integer); var zstream: TZStreamRec; begin FillChar(zstream, SizeOf(TZStreamRec), 0); ZDecompressCheck(ZInflateInit2(zstream, windowBits)); ZInternalDecompress(zstream, inBuffer, inSize, outBuffer, outSize, outEstimate); end; {** string routines *****************************************************************************} function ZCompressStr(const s: AnsiString; level: TZCompressionLevel): RawByteString; begin ZCompressString(result, s, level); end; procedure ZCompressString(var result: RawByteString; const s: AnsiString; level: TZCompressionLevel); var buffer: Pointer; size : Integer; begin ZCompress(Pointer(s), Length(s), buffer, size, level); SetLength(result, size); if size > 0 then begin Move(buffer^, result[1], size); end; FreeMem(buffer); end; {$ifdef Version6Plus} procedure ZCompressString(var result: RawByteString; const s: UnicodeString; level: TZCompressionLevel); var buffer: Pointer; size : Integer; begin ZCompress(Pointer(s), Length(s) * SizeOf(UnicodeChar), buffer, size, level); SetLength(result, size); if size > 0 then begin Move(buffer^, result[1], size); end; FreeMem(buffer); end; {$endif} function ZCompressStrEx(const s: AnsiString; level: TZCompressionLevel): RawByteString; begin ZCompressStringEx(result, s, level); end; procedure ZCompressStringEx(var result: RawByteString; const s: AnsiString; level: TZCompressionLevel); var buffer: Pointer; size : Integer; begin ZCompress(Pointer(s), Length(s), buffer, size, level); SetLength(result, size + SizeOf(Integer)); if size > 0 then begin Move(buffer^, result[1 + SizeOf(Integer)], size); end; size := Length(s); Move(size, result[1], SizeOf(Integer)); FreeMem(buffer); end; {$ifdef Version6Plus} procedure ZCompressStringEx(var result: RawByteString; const s: UnicodeString; level: TZCompressionLevel); var buffer: Pointer; size : Integer; begin ZCompress(Pointer(s), Length(s) * SizeOf(UnicodeChar), buffer, size, level); SetLength(result, size + SizeOf(Integer)); if size > 0 then begin Move(buffer^, result[1 + SizeOf(Integer)], size); end; size := Length(s) * SizeOf(UnicodeChar); Move(size, result[1], SizeOf(Integer)); FreeMem(buffer); end; {$endif} function ZCompressStr2(const s: AnsiString; level: TZCompressionLevel; windowBits, memLevel: Integer; strategy: TZStrategy): RawByteString; begin ZCompressString2(result, s, level, windowBits, memLevel, strategy); end; procedure ZCompressString2(var result: RawByteString; const s: AnsiString; level: TZCompressionLevel; windowBits, memLevel: Integer; strategy: TZStrategy); var buffer: Pointer; size : Integer; begin ZCompress2(Pointer(s), Length(s), buffer, size, level, windowBits, memLevel, strategy); SetLength(result, size); if size > 0 then begin Move(buffer^, result[1], size); end; FreeMem(buffer); end; {$ifdef Version6Plus} procedure ZCompressString2(var result: RawByteString; const s: UnicodeString; level: TZCompressionLevel; windowBits, memLevel: Integer; strategy: TZStrategy); var buffer: Pointer; size : Integer; begin ZCompress2(Pointer(s), Length(s) * SizeOf(UnicodeChar), buffer, size, level, windowBits, memLevel, strategy); SetLength(result, size); if size > 0 then begin Move(buffer^, result[1], size); end; FreeMem(buffer); end; {$endif} function ZCompressStrWeb(const s: AnsiString): RawByteString; begin ZCompressStringWeb(result, s); end; procedure ZCompressStringWeb(var result: RawByteString; const s: AnsiString); begin ZCompressString2(result, s, zcFastest, -15, 9, zsDefault); end; {$ifdef Version6Plus} procedure ZCompressStringWeb(var result: RawBytestring; const s: UnicodeString); begin ZCompressString2(result, s, zcFastest, -15, 9, zsDefault); end; {$endif} function ZDecompressStr(const s: RawByteString): AnsiString; begin ZDecompressString(result, s); end; procedure ZDecompressString(var result: AnsiString; const s: RawByteString); var buffer: Pointer; size : Integer; begin ZDecompress(Pointer(s), Length(s), buffer, size); SetLength(result, size); if size > 0 then begin Move(buffer^, result[1], size); end; FreeMem(buffer); end; {$ifdef Version6Plus} procedure ZDecompressString(var result: UnicodeString; const s: RawByteString); var buffer: Pointer; size : Integer; begin ZDecompress(Pointer(s), Length(s), buffer, size); SetLength(result, size div SizeOf(UnicodeChar)); if size > 0 then begin Move(buffer^, result[1], size); end; FreeMem(buffer); end; {$endif} function ZDecompressStrEx(const s: RawByteString): AnsiString; begin ZDecompressStringEx(result, s); end; procedure ZDecompressStringEx(var result: AnsiString; const s: RawByteString); var buffer : Pointer; size : Integer; data : AnsiString; dataSize: Integer; begin Move(s[1], size, SizeOf(Integer)); dataSize := Length(s) - SizeOf(Integer); SetLength(data, dataSize); if dataSize > 0 then begin Move(s[1 + SizeOf(Integer)], data[1], dataSize); ZDecompress(Pointer(data), dataSize, buffer, size, size); SetLength(result, size); if size > 0 then begin Move(buffer^, result[1], size); end; FreeMem(buffer); end else begin SetLength(result, 0); end; end; {$ifdef Version6Plus} procedure ZDecompressStringEx(var result: UnicodeString; const s: RawByteString); var buffer : Pointer; size : Integer; data : AnsiString; dataSize: Integer; begin Move(s[1], size, SizeOf(Integer)); dataSize := Length(s) - SizeOf(Integer); if dataSize > 0 then begin SetLength(data, dataSize); Move(s[1 + SizeOf(Integer)], data[1], dataSize); ZDecompress(Pointer(data), dataSize, buffer, size, size); SetLength(result, size div SizeOf(UnicodeChar)); if size > 0 then begin Move(buffer^, result[1], size); end; FreeMem(buffer); end else begin SetLength(result, 0); end; end; {$endif} function ZDecompressStr2(const s: RawByteString; windowBits: Integer): AnsiString; begin ZDecompressString2(result, s, windowBits); end; procedure ZDecompressString2(var result: AnsiString; const s: RawByteString; windowBits: Integer); var buffer: Pointer; size : Integer; begin ZDecompress2(Pointer(s), Length(s), buffer, size, windowBits); SetLength(result, size); if size > 0 then begin Move(buffer^, result[1], size); end; FreeMem(buffer); end; {$ifdef Version6Plus} procedure ZDecompressString2(var result: UnicodeString; const s: RawByteString; windowBits: Integer); var buffer: Pointer; size : Integer; begin ZDecompress2(Pointer(s), Length(s), buffer, size, windowBits); SetLength(result, size div SizeOf(UnicodeChar)); if size > 0 then begin Move(buffer^, result[1], size); end; FreeMem(buffer); end; {$endif} {** private stream routines *********************************************************************} type PZStreamParam = ^TZStreamParam; TZStreamParam = packed record InStream : TStream; OutStream : TStream; end; function ZStreamRead(p: Pointer; var buffer; size: Integer): Integer; var param: PZStreamParam; begin param := PZStreamParam(p); result := param^.InStream.Read(buffer, size); end; function ZStreamWrite(p: Pointer; const buffer; size: Integer): Integer; var param: PZStreamParam; begin param := PZStreamParam(p); result := param^.OutStream.Write(buffer, size); end; procedure ZInternalCompressStreamEx(zstream: TZStreamRec; inStream, outStream: TStream); var param: TZStreamParam; begin FillChar(param, SizeOf(TZStreamParam), 0); param.InStream := inStream; param.OutStream := outStream; ZDeflateEx(zstream, @param, @ZBufferRead, @ZBufferWrite, zfFinish); ZCompressCheck(ZDeflateEnd(zstream)); end; procedure ZInternalDecompressStreamEx(zstream: TZStreamRec; inStream, outStream: TStream); var param: TZStreamParam; begin FillChar(param, SizeOf(TZStreamParam), 0); param.InStream := inStream; param.OutStream := outStream; ZInflateEx(zstream, @param, @ZBufferRead, @ZBufferWrite, zfNoFlush); ZDecompressCheck(ZInflateEnd(zstream)); end; procedure ZInternalCompressStream(zstream: TZStreamRec; inStream, outStream: TStream); const bufferSize = 32768; var zresult : Integer; inBuffer : Array [0..bufferSize - 1] of Byte; outBuffer: Array [0..bufferSize - 1] of Byte; outSize : Integer; begin zresult := Z_STREAM_END; zstream.avail_in := inStream.Read(inBuffer, bufferSize); while zstream.avail_in > 0 do begin zstream.next_in := @inBuffer; repeat zstream.next_out := @outBuffer; zstream.avail_out := bufferSize; zresult := ZCompressCheck(ZDeflate(zstream, zfNoFlush)); outSize := bufferSize - zstream.avail_out; outStream.Write(outBuffer, outSize); until (zresult = Z_STREAM_END) or (zstream.avail_in = 0); zstream.avail_in := inStream.Read(inBuffer, bufferSize); end; while zresult <> Z_STREAM_END do begin zstream.next_out := @outBuffer; zstream.avail_out := bufferSize; zresult := ZCompressCheck(ZDeflate(zstream, zfFinish)); outSize := bufferSize - zstream.avail_out; outStream.Write(outBuffer, outSize); end; ZCompressCheck(ZDeflateEnd(zstream)); end; procedure ZInternalDecompressStream(zstream: TZStreamRec; inStream, outStream: TStream); const bufferSize = 32768; var zresult : Integer; inBuffer : Array [0..bufferSize-1] of Byte; outBuffer: Array [0..bufferSize-1] of Byte; outSize : Integer; begin try zresult := Z_OK; zstream.avail_in := inStream.Read(inBuffer, bufferSize); while (zresult <> Z_STREAM_END) and (zstream.avail_in > 0) do begin zstream.next_in := @inBuffer; repeat zstream.next_out := @outBuffer; zstream.avail_out := bufferSize; zresult := ZDecompressCheck(ZInflate(zstream, zfNoFlush), False); outSize := bufferSize - zstream.avail_out; outStream.Write(outBuffer, outSize); until (zresult = Z_STREAM_END) or (zstream.avail_out > 0); if zstream.avail_in > 0 then begin inStream.Position := inStream.Position - zstream.avail_in; end; if zresult <> Z_STREAM_END then begin zstream.avail_in := inStream.Read(inBuffer, bufferSize); end; end; finally ZDecompressCheck(ZInflateEnd(zstream)); end; end; {** stream routines *****************************************************************************} {procedure ZCompressStream(inStream, outStream: TStream; level: TZCompressionLevel); var zstream: TZStreamRec; begin FillChar(zstream, SizeOf(TZStreamRec), 0); ZCompressCheck(ZDeflateInit(zstream, level)); ZInternalCompressStream(zstream, inStream, outStream); end;} procedure ZCompressStream(inStream, outStream: TStream; level: TZCompressionLevel); const bufferSize = 32768; var zstream: TZStreamRec; zresult: Integer; inBuffer: array[0..bufferSize - 1] of Char; outBuffer: array[0..bufferSize - 1] of Char; inSize: Integer; outSize: Integer; begin FillChar(zstream, SizeOf(TZStreamRec), 0); ZCompressCheck(DeflateInit(zstream, ZLevels[level])); inSize := inStream.Read(inBuffer, bufferSize); while inSize > 0 do begin zstream.next_in := @inBuffer[0]; zstream.avail_in := inSize; repeat zstream.next_out := @outBuffer[0]; zstream.avail_out := bufferSize; ZCompressCheck(deflate(zstream, Z_NO_FLUSH)); // outSize := zstream.next_out - outBuffer; outSize := bufferSize - zstream.avail_out; outStream.Write(outBuffer, outSize); until (zstream.avail_in = 0) and (zstream.avail_out > 0); inSize := inStream.Read(inBuffer, bufferSize); end; repeat zstream.next_out := @outBuffer[0]; zstream.avail_out := bufferSize; zresult := ZCompressCheck(deflate(zstream, Z_FINISH)); // outSize := zstream.next_out - outBuffer; outSize := bufferSize - zstream.avail_out; outStream.Write(outBuffer, outSize); until (zresult = Z_STREAM_END) and (zstream.avail_out > 0); ZCompressCheck(deflateEnd(zstream)); end; procedure ZCompressStream2(inStream, outStream: TStream; level: TZCompressionLevel; windowBits, memLevel: Integer; strategy: TZStrategy); var zstream: TZStreamRec; begin FillChar(zstream, SizeOf(TZStreamRec), 0); ZCompressCheck(ZDeflateInit2(zstream, level, windowBits, memLevel, strategy)); ZInternalCompressStream(zstream,inStream,outStream); end; procedure ZCompressStreamWeb(inStream, outStream: TStream); begin ZCompressStream2(inStream, outStream, zcFastest, -15, 9, zsDefault); end; procedure ZDecompressStream(inStream, outStream: TStream); var zstream: TZStreamRec; begin FillChar(zstream, SizeOf(TZStreamRec), 0); ZDecompressCheck(ZInflateInit(zstream)); ZInternalDecompressStream(zstream, inStream, outStream); end; procedure ZDecompressStream2(inStream, outStream: TStream; windowBits: Integer); var zstream: TZStreamRec; begin FillChar(zstream, SizeOf(TZStreamRec), 0); ZDecompressCheck(ZInflateInit2(zstream, windowBits)); ZInternalDecompressStream(zstream, inStream, outStream); end; {** TCustomZStream ******************************************************************************} constructor TCustomZStream.Create(stream: TStream); begin inherited Create; FStream := stream; FStreamPos := stream.Position; end; function TCustomZStream.StreamRead(var buffer; count: Longint): Longint; begin if FStream.Position <> FStreamPos then FStream.Position := FStreamPos; result := FStream.Read(buffer,count); FStreamPos := FStreamPos + result; end; function TCustomZStream.StreamWrite(const buffer; count: Longint): Longint; begin if FStream.Position <> FStreamPos then FStream.Position := FStreamPos; result := FStream.Write(buffer,count); FStreamPos := FStreamPos + result; end; function TCustomZStream.StreamSeek(offset: Longint; origin: Word): Longint; begin if FStream.Position <> FStreamPos then FStream.Position := FStreamPos; result := FStream.Seek(offset,origin); FStreamPos := FStream.Position; end; procedure TCustomZStream.StreamReadBuffer(var buffer; count: Longint); begin if FStream.Position <> FStreamPos then FStream.Position := FStreamPos; FStream.ReadBuffer(buffer,count); FStreamPos := FStreamPos + count; end; procedure TCustomZStream.StreamWriteBuffer(const buffer; count: Longint); begin if FStream.Position <> FStreamPos then FStream.Position := FStreamPos; FStream.WriteBuffer(buffer,count); FStreamPos := FStreamPos + count; end; procedure TCustomZStream.DoProgress; begin if Assigned(FOnProgress) then FOnProgress(Self); end; function TCustomZStream.GetStreamPosition: TStreamPos; begin result := FStream.Position; end; procedure TCustomZStream.SetStreamPosition(value: TStreamPos); begin FStream.Position := value; FStreamPos := FStream.Position; end; {** TZCompressionStream *************************************************************************} constructor TZCompressionStream.Create(dest: TStream; compressionLevel: TZCompressionLevel); begin inherited Create(dest); FZStream.next_out := @FBuffer; FZStream.avail_out := SizeOf(FBuffer); ZCompressCheck(ZDeflateInit(FZStream, compressionLevel)); end; constructor TZCompressionStream.Create(dest: TStream; compressionLevel: TZCompressionLevel; windowBits, memLevel: Integer; strategy: TZStrategy); begin inherited Create(dest); FZStream.next_out := @FBuffer; FZStream.avail_out := SizeOf(FBuffer); ZCompressCheck(ZDeflateInit2(FZStream, compressionLevel, windowBits, memLevel, strategy)); end; destructor TZCompressionStream.Destroy; begin FZStream.next_in := Nil; FZStream.avail_in := 0; try while ZCompressCheck(ZDeflate(FZStream, zfFinish)) <> Z_STREAM_END do begin StreamWriteBuffer(FBuffer, SizeOf(FBuffer) - FZStream.avail_out); FZStream.next_out := @FBuffer; FZStream.avail_out := SizeOf(FBuffer); end; if FZStream.avail_out < SizeOf(FBuffer) then begin StreamWriteBuffer(FBuffer, SizeOf(FBuffer) - FZStream.avail_out); end; finally ZDeflateEnd(FZStream); end; inherited Destroy; end; function TZCompressionStream.Read(var buffer; count: Longint): Longint; begin raise EZCompressionError.Create(SZInvalid); end; function TZCompressionStream.Write(const buffer; count: Longint): Longint; var writeCount: Longint; begin result := count; FZStream.next_in := @buffer; FZStream.avail_in := count; while FZStream.avail_in > 0 do begin ZCompressCheck(ZDeflate(FZStream, zfNoFlush)); if FZStream.avail_out = 0 then begin writeCount := StreamWrite(FBuffer,SizeOf(FBuffer)); if writeCount = SizeOf(FBuffer) then begin FZStream.next_out := @FBuffer; FZStream.avail_out := SizeOf(FBuffer); DoProgress; end else begin StreamPosition := StreamPosition - writeCount; result := Cardinal(count) - FZStream.avail_in; FZStream.avail_in := 0; end; end; end; end; function TZCompressionStream.Seek(offset: Longint; origin: Word): Longint; begin if (offset = 0) and (origin = soFromCurrent) then begin result := FZStream.total_in; end else raise EZCompressionError.Create(SZInvalid); end; function TZCompressionStream.GetCompressionRate: Single; begin if FZStream.total_in = 0 then result := 0 else result := (1.0 - (FZStream.total_out / FZStream.total_in)) * 100.0; end; {** TZDecompressionStream ***********************************************************************} constructor TZDecompressionStream.Create(source: TStream); begin inherited Create(source); FZStream.next_in := @FBuffer; FZStream.avail_in := 0; ZDecompressCheck(ZInflateInit(FZStream)); end; constructor TZDecompressionStream.Create(source: TStream; windowBits: Integer); begin inherited Create(source); FZStream.next_in := @FBuffer; FZStream.avail_in := 0; ZDecompressCheck(ZInflateInit2(FZStream, windowBits)); end; destructor TZDecompressionStream.Destroy; begin ZInflateEnd(FZStream); inherited Destroy; end; function TZDecompressionStream.Read(var buffer; count: Longint): Longint; var zresult: Integer; begin FZStream.next_out := @buffer; FZStream.avail_out := count; zresult := Z_OK; while (FZStream.avail_out > 0) and (zresult <> Z_STREAM_END) do begin if FZStream.avail_in = 0 then begin FZStream.avail_in := StreamRead(FBuffer,SizeOf(FBuffer)); if FZStream.avail_in = 0 then begin result := Cardinal(count) - FZStream.avail_out; Exit; end; FZStream.next_in := @FBuffer; DoProgress; end; zresult := ZDecompressCheck(ZInflate(FZStream, zfNoFlush)); end; if (zresult = Z_STREAM_END) and (FZStream.avail_in > 0) then begin StreamPosition := StreamPosition - FZStream.avail_in; FZStream.avail_in := 0; end; result := Cardinal(count) - FZStream.avail_out; end; function TZDecompressionStream.Write(const Buffer; Count: Longint): Longint; begin raise EZDecompressionError.Create(SZInvalid); end; function TZDecompressionStream.Seek(Offset: Longint; Origin: Word): Longint; var buf: Array [0..8191] of Byte; i : Integer; begin if (offset = 0) and (origin = soFromBeginning) then begin ZDecompressCheck(ZInflateReset(FZStream)); FZStream.next_in := @FBuffer; FZStream.avail_in := 0; StreamPosition := 0; end else if ((offset >= 0) and (origin = soFromCurrent)) or (((Cardinal(offset) - FZStream.total_out) > 0) and (origin = soFromBeginning)) then begin if origin = soFromBeginning then Dec(offset, FZStream.total_out); if offset > 0 then begin for i := 1 to offset div SizeOf(buf) do ReadBuffer(buf, SizeOf(buf)); ReadBuffer(buf, offset mod SizeOf(buf)); end; end else if (offset = 0) and (origin = soFromEnd) then begin while Read(buf, SizeOf(buf)) > 0 do ; end else raise EZDecompressionError.Create(SZInvalid); result := FZStream.total_out; end; {** TZCustomBuffer ******************************************************************************} constructor TZCustomBuffer.Create; begin inherited Create; FillChar(FZStream, SizeOf(TZStreamRec), 0); FBuffer := Nil; FBufferCapacity := 0; FBufferSize := 0; end; destructor TZCustomBuffer.Destroy; begin BufferCapacity(0); inherited Destroy; end; procedure TZCustomBuffer.Clear; begin BufferCapacity(0); FBufferSize := 0; end; procedure TZCustomBuffer.Flush(flush: TZFlush); begin // to be implemented by descendents as needed end; function TZCustomBuffer.Write(const s: AnsiString): Integer; begin result := Write(Pointer(s), Length(s)); end; function TZCustomBuffer.Read(var buffer: Pointer; size: Integer): Integer; begin result := BufferSize; if size < result then result := size; BufferRead(buffer, result); end; function TZCustomBuffer.Read(var s: AnsiString): Integer; begin SetLength(s, BufferSize); result := Read(Pointer(s), Length(s)); end; procedure TZCustomBuffer.BufferWrite(const buffer: Pointer; size: Integer); begin if size > 0 then begin BufferCapacity(FBufferSize + size); Move(buffer^, Pointer(Integer(FBuffer) + FBufferSize)^, size); Inc(FBufferSize, size); end; end; procedure TZCustomBuffer.BufferRead(var buffer: Pointer; size: Integer); begin if size > 0 then begin Move(FBuffer^, buffer^, size); Move(Pointer(Integer(FBuffer) + size)^, FBuffer^, FBufferSize - size); Dec(FBufferSize, size); end; end; procedure TZCustomBuffer.BufferCapacity(capacity: Integer); const delta = 8192; // must be a power of 2 begin if capacity > 0 then begin capacity := (capacity + (delta - 1)) and not (delta - 1); end; if FBufferCapacity <> capacity then begin if capacity = 0 then FreeMem(FBuffer) else if FBufferCapacity = 0 then GetMem(FBuffer, capacity) else ReallocMem(FBuffer, capacity); FBufferCapacity := capacity; end; end; {** TZCompressionBuffer *************************************************************************} constructor TZCompressionBuffer.Create(level: TZCompressionLevel); begin inherited Create; ZCompressCheck(ZDeflateInit(FZStream, level)); end; constructor TZCompressionBuffer.Create(level: TZCompressionLevel; windowBits, memLevel: Integer; strategy: TZStrategy); begin inherited Create; ZCompressCheck(ZDeflateInit2(FZStream, level, windowBits, memLevel, strategy)); end; destructor TZCompressionBuffer.Destroy; begin ZCompressCheck(ZDeflateEnd(FZStream)); inherited Destroy; end; procedure TZCompressionBuffer.Clear; begin inherited Clear; ZCompressCheck(ZDeflateReset(FZStream)); end; procedure TZCompressionBuffer.Flush(flush: TZFlush); const outSize = 32768; var zresult : Integer; outBuffer: Array [0..outSize - 1] of Byte; outCount : Integer; begin FZStream.next_in := Nil; FZStream.avail_in := 0; repeat FZStream.next_out := @outBuffer; FZStream.avail_out := outSize; zresult := ZCompressCheck(ZDeflate(FZStream, flush)); outCount := outSize - FZStream.avail_out; BufferWrite(@outBuffer, outCount); until (zresult = Z_STREAM_END) or (FZStream.avail_out > 0); end; function TZCompressionBuffer.Write(const buffer: Pointer; size: Integer): Integer; const outSize = 32768; var zresult : Integer; outBuffer: Array [0..outSize - 1] of Byte; outCount : Integer; begin zresult := Z_OK; FZStream.next_in := buffer; FZStream.avail_in := size; while (zresult <> Z_STREAM_END) and (FZStream.avail_in > 0) do begin repeat FZStream.next_out := @outBuffer; FZStream.avail_out := outSize; zresult := ZCompressCheck(ZDeflate(FZStream, zfNoFlush)); outCount := outSize - FZStream.avail_out; BufferWrite(@outBuffer, outCount); until (zresult = Z_STREAM_END) or (FZStream.avail_out > 0); end; result := Cardinal(size) - FZStream.avail_in; end; {** TZDecompressionBuffer ***********************************************************************} constructor TZDecompressionBuffer.Create; begin inherited Create; ZDecompressCheck(ZInflateInit(FZStream)); end; constructor TZDecompressionBuffer.Create(windowBits: Integer); begin inherited Create; ZDecompressCheck(ZInflateInit2(FZStream, windowBits)); end; destructor TZDecompressionBuffer.Destroy; begin ZDecompressCheck(ZInflateEnd(FZStream)); inherited Destroy; end; procedure TZDecompressionBuffer.Clear; begin inherited Clear; ZDecompressCheck(ZInflateReset(FZStream)); end; function TZDecompressionBuffer.Write(const buffer: Pointer; size: Integer): Integer; const outSize = 32768; var zresult : Integer; outBuffer: Array [0..outSize - 1] of Byte; outCount : Integer; begin zresult := Z_OK; FZStream.next_in := buffer; FZStream.avail_in := size; while (zresult <> Z_STREAM_END) and (FZStream.avail_in > 0) do begin repeat FZStream.next_out := @outBuffer; FZStream.avail_out := outSize; zresult := ZDecompressCheck(ZInflate(FZStream, zfNoFlush), False); outCount := outSize - FZStream.avail_out; BufferWrite(@outBuffer, outCount); until (zresult = Z_STREAM_END) or (FZStream.avail_out > 0); end; result := Cardinal(size) - FZStream.avail_in; end; {** EZLibError **********************************************************************************} constructor EZLibError.Create(code: Integer; const dummy: String); begin inherited Create(z_errmsg[2 - code]); FErrorCode := code; end; constructor EZLibError.Create(error: TZError; const dummy: String); begin Create(ZErrors[error], dummy); end; procedure DecompressToUserBuf(const InBuf: Pointer; InBytes: Integer; const OutBuf: Pointer; BufSize: Integer); var strm: TZStreamRec; begin FillChar(strm, sizeof(strm), 0); // strm.zalloc := zlibAllocMem; // strm.zfree := zlibFreeMem; strm.next_in := InBuf; strm.avail_in := InBytes; strm.next_out := OutBuf; strm.avail_out := BufSize; DCheck(inflateInit_(strm, zlib_version, sizeof(strm))); try if DCheck(inflate(strm, Z_FINISH)) <> Z_STREAM_END then raise EZlibError.CreateRes(64672); finally DCheck(inflateEnd(strm)); end; end; end. ================================================ FILE: lib/zeosdbo/doc/html/bugreporting.html ================================================ Bug Reporting in ZEOS Library
ZeosLib - open source tools for your database solutions

Bug Reporting in ZEOS Library

Michael Seeger

Abstract

[Warning]Warning

(By Mark Daems, 29 May 2008) This Article is somewhat outdated as it describes some project organisational structures. (eg. QA group) This structure isn't available anymore. However, most observations concerning what a good bug report is still apply.

The currect bug reporting procedure is absolutely critical to improve the quality of ZEOS. It defines steps to fix bugs, to notify the reported user about the change and update the test harness to ensure the bug will never happen again. Unfortunately in free ware projets it's hard to maintain good test coverage. The Bug Report procedure allows to improve the test coverage and to increase the stability of the Libary afterward, when the code is written and released. It relieves developers because writing tests is partially moved to responsibilities of QA group.


1. Recommendation to a Bug Report

A "valid" bug report has to contain the following informations:

  • Database server and server version

  • Version of used components

  • Name component or class that raised the error

  • Information about user properties for components and/or classes

  • Exact description of the error

  • Sql query and table(s) structure and table(s) data for user specified table(s)

If it is necessary and possible the user may be asked for a sample application that reproduces the error

2. Bug Fixing Proecedure

  1. User submits a bug report on SourceForge Bug Tracker.

  2. Elaborate information about the bug and close the bug if it has no sense. Notify the user about the action taken and exlain why this was done (performed by QA Group)

  3. Implement a Bug Report Test Case which relicates the problem (performed by QA Group)

  4. Switch the bug to the responsible developer

  5. Fix the bug. Document yor changes in sourcecode, carefully! (performed by responsible developer)

  6. Fill out the bug report e-Form and document your doings, carefully! The given Template (bug_report_form.txt has to be saved as BugID.txt where ID means the Bug's ID from the SourceForge Bug Tracker.

  7. Close the bug report and notify the user about the changes done (if possible) and mention when it will be officially released (performed by responsible developer)

3. Bug Fixing Test

Bug Report Tests is a special category of tests it is obvious that bugs may happen in all groups of finctional tests described before. From that p erspective Bug Report Tests should repeat the hierarchy of functional tests:

  1. TZAbstractBugReportTestCase - a base abstract class for Bug Report Tests.

  2. TZGenericBugReport, TZPortableSQLBugReport and TZSpecificSQLBugReport - abstract classes for "Generic", "SQL Prtable" and "SQL Specific" tests.

  3. TZCompPortableSQLBugReport, TZCompMySQLBugReport, TZCompInterbaseBugReport, TZDbcPortableSQLBugReport, TZDbcMySQLBugReport, TZDbcInterbaseBugReport, etc. - specific test cases.

For Bug Report Test cases we set a convention to name test methodes as "Test" + ID, where ID is a unique number of associated bug report in Bug Tracker on SourceForge. That convention allows us to do following things:

  1. Enforce creation of bug repot for each found bug.

  2. Easy navigate between bug reports and related test cases.

  3. TZCompPortableSQLBugReport, TZCompMySQLBugReport, TZCompInterbaseBugReport, TZDbcPortableSQLBugReport, TZDbcMySQLBugReport, TZDbcInterbaseBugReport, etc. - specific test cases.

During bug fixing developer usually have to run a specific test case many times. To speed up the process we added to TZAbstractBugReportTestCase class a convenient function called SkipClosed. If SkipClosed property ist set to true for "bugreport" category in configuration file, SkipClosed returns true and allows to skip completed tests for fixed bugs. It dramatically decreases number of tests to run and makes developer's vork much more productive.

4. Sample Bug Report Testcase

  UNIT ZTestCompCore;
   
  INTERFACE
   
  {$I ZBugReport.inc}
   
  USES Classed, DB, TestFramework, ZDataset, ZConnection, ZDbcIntfs, ZBugReport,
       ZCompatibility, ZSqlUpdate, ZSqlProcessor;
   
  TYPE ZTestCompCoreBugReport = class (TZPortableSQLBugReportTestCase)
          :
          published
             :
             Procedure Test833197;
             :
       End;
   
  IMPLEMENTATION
   
  :
   
  {** Bugreport #833197:
  Refresh problem with filtered data. }
   
  Procedure ZTestCompCoreBugReport.Test833197;
  Var Connection: TZConnection;
      Query     : TZQuery;
  Begin
     If SkipClosed Then Exit;
      
     Connection       := Self.CreateDatasetConnection;
     Query            := TZQuery.Create (nil);
     Query.Connection := Connection;
     Query.SQL.Text   := 'SELECT * FROM poeple';
      
     Try
        Query.Open;
        Query.Filter   := 'p_name = "Aleksey Petrov"';
        Query.Filtered := True;
        CheckEquals (1, Query.RecordCount);
        Query.Refresh;
        CheckEquals (1, Query.RecordCount);
        Query.Close;
     Finally
        Connection.Free;
        Query.Free;
     End;
  End; // Test833197
   
  :
   
  INITIALIZATION
   
     TestFramework.RegisterTest (ZTestCompCoreBugReort.Suite);
   
  End.
  

(c) 1999 - 2006 The Zeos Development Group
================================================ FILE: lib/zeosdbo/doc/html/buildingtests.html ================================================ Building Tests for the ZEOS Library
ZeosLib - open source tools for your database solutions

Building Tests for the ZEOS Library

Abstract

This document describes how to set up the ZEOS Build & Test environment and shows how to compile gui and console based test applications to test the ZEOSLib code. It also describes the setup that has to be made for testing the library with various databases.


1. Requirements to build ZEOSLib tests

In order to run the tests for the ZEOSLib you have to be sure that you have insalled the following software on your system:

Make sure that the environment variable JAVA_HOME is set to the directory where you installed the Java Runtine or SDK (e. g. JAVA_HOME = c:\java\j2sdk1.4.2_06).

Also set the environment variable ANT_HOME to the directory where you installed Jakarta ANT (e. g. ANT_HOME = C:\Programs\ANT).

2. Build & Test Configuration

Before you are able to start compiling the ZEOS test applications you have to configure the compiler environment. All settings for compiling building and testing are stored in a file called build.properties. To get this file just copy the build_template.properties file in build directory and name it build.properties. The build.properties file has four sections that are important for compiling the test applications: "common" and "compilers". There is another section that determines which tests will be executed by calling test.cmd batchfile. This section is not important for compiling tests but it will also be documented.

In a Windows environment it is recommended that you use double backslash as directory separator. "Normal" slash will work but causes some problems in a Delphi 9 environment. In a Unix / Linux environment it is recommended use the "normal" slash as direcrory separator.

2.1. Common Section

The first section is the common-section it contains common informations for building the test applications:

  [common]
  project.home=d:/workshop/zeosdbo_rework 1
  release.version =6.5.2-beta  2
  copy.verbose=false 3
  dunit.dir=d:/programme/borland/delphi7/dunit/src 4
  kunit.dir= 5
  
1

The project directory

2

The version number of the ZEOSLib (put into version file).

3

Determines whether copy operations shall displayed on screen.

4

The source directory of DUnit.

5

The source directory of DUnit (for Kylix).

2.2. Compiler Section

The second section is the compiler-section it contains informations about the active compilers to use for building the test applications. Each supported compiler has its own "section". It describes wether the compiler (prefix of the key (e. g. "delphi5")) is active and determines the installation directory of the compiler.

  [compilers]
  delphi5.active=false 1
  delphi5.home=C:/Program Files/Borland/Delphi5 2
  :
  delphi9.active=true
  delphi9.home=d:\\programme\\borland\\bds\\3.0
  delphi9.bpl.dir=c:\\dokumente und einstellungen\\user\\eigene dateien\\borland studio-projekte\\bpl 3
  :
  kylix3.active=false 4
  kylix3.home=/opt/kylix3
  
1

"true" if the compiler is installed (active), "false" if not.

2

The installation path of the compiler (here: Delphi 5).

3

Special for Delhi 9: you have to specify your BPL-dir because in Delphi 9 the standardized ...\projects\bpl doesn't exist anymore (here: german Delphi / WinXP example).

4

Kylix 3 settings for compilation (Kylix 3 is not installed this is why kylix3.active=false)

2.3. Tests Section

This section is necessary to determine which tests will be run when executing the test.cmd batchfile (only makes sense when compiling the test applications as console applications).

  [tests]
  test.core=true 1
  test.parsesql=true 2
  test.dbc=true 3
  test.component=true 4
  test.bugreport=true 5
  test.performance=false 6
  
1

Execute core tests if set to "true".

2

Execute parsing tests if set to "true".

3

Execute connectivity tests if set to "true".

4

Execute component tests if set to "true".

5

Execute bug tests if set to "true".

6

Execute performance tests if set to "true".

3. Database Configuration

It is possible to run the ZEOS tests for a number of SQL servers that are currently running on the test machine. Therefor the Build and Test Environment has to be configured.

Setting up the database parameters is done in the test.properites file that is located in the "database" direcory. To get this file just copy the test_template.properties file and rename it to test.properties and then make your settings.

At the moment we do not execute performance tests so only the common section and the database sections are of importance for testing the ZEOS Library.

3.1. Common Section

The first section is the common-section it contains common informations about the databases to test by test applications:

  [common]
  common.connections=sqlite28,firebird15 1
  
1

This key holds the active servernames of the SQL servers that will be tested in the test applications. Corresponding to the servers given here there has to exist a "database section" with the same name that determines the database settings for testing. The server names for this key have to be seperated by comma.

3.2. Database Settings

Corresponding to the active servers listed in the common.connections key (here: SQLite 2.8 and Firebird 1.5.x) there are configuration sections that contain the settings for running tests with the given database. Each section consists of the same keys so we will take the Firebird 1.5 database configuration to explain them:

  [firebird15]
  firebird15.protocol=firebird-1.5 1
  firebird15.alias=firebird_zeoslib 2
  firebird15.host=localhost 3
  firebird15.port= 4
  firebird15.database=d:\SQLServerFarm\Firebird\15\Data\zeoslib.fdb 5
  firebird15.user=SYSDBA 6
  firebird15.password=masterkey 7
  firebird15.rebuild=yes 8
  firebird15.delimiter.type=SetTerm 9
  firebird15.delimiter=; 10
  firebird15.create.scripts=create_interbase.sql,populate_any.sql,populate_interbase.sql,create_interbase_bugreport.sql (11)
  firebird15.drop.scripts=drop_interbase.sql,drop_interbase_bugreport.sql (12)
  
1

DBC protocol name

2

BDE alias for performance tests

3

Host name

4

Port number

5

Database name

6

User name

7

User password

7

User password

7

Flag to rebuild database before each test

9

SQL delimiter type in SQL scripts (Default, Go, SetTerm or EmptyLine)

10

SQL delimiter string

(11)

SQL scripts to create database objects. All scripts have to be placed in the "database" directory (where the test.properties file is located).

(12)

SQL scripts to drop database objects. All scripts have to be placed in the "database" directory (where the test.properties file is located).

Due to techniques used in the ZEOS Testframework classes it is necessary to set a prefix in front of the key that is identical to the section name followed by a dot. E. g.: firebird15.password - where "firebird15" is the repeated name of the section (see above).

4. Compiling Tests

When all the required Software is installed and you made the configurations that are necessary for your test environment you are ready to start compiling the test applications. This is easyly done by calling the batch script "compiletests.cmd" from commandline in "build" directory. When all applications are successfully compiled you are able to test ZEOSLib funcionality.

ZEOS BTE splits the tests into seven parts (separate applications):

  • Bug Report Tests (ZTestBugReport.EXE)

  • Component Tests (ZTestComponentAll.EXE)

  • Core Tests (ZTestCoreAll.EXE)

  • Database Connectivity (DBC) Tests (ZTestDbcAll.EXE)

  • SQL Parser Tests (ZTestParseSqlAll.EXE)

  • Performance Tests - currently not executed - (ZTestPerformance.EXE)

The applications listed above are compiled into the build directory of the corresponding package (e. g.: ...\packages\delphi7\build). Normally the applications are compiled to execute as console applications but if you want to run them as GUI applications just remove the comment from "{$DEFINE TESTGUI}" in the ZEOS.INC file. If you now call one of the test applications they are executed in a GUI. If you want to create console test applications you just have to comment the "{$DEFINE TESTGUI}" again (in ZEOS.INC).

5. Running Tests

As written in section "Compiling Tests", it is possible to execute special tests (e. g. only Bug Report Tests) by calling the EXE-file explicitly. Depending on the settings you will start one console application or one GUI application. You also may run all tests by running them sequentially via batch script (consider to compile all the tests as a console application!)

Before you run tests make sure that all the database servers you want to test are up and running!

To do run all tests (that are defined to run in section "tests" of the build.properties file), automatically, just type "test" from a commandline in "build" directory. The test result is output to screen and into a log file located in the "build" subdirectory "logs". The logfile is called "test-YYYYMMDD.log" where "YYYYMMDD" is the current date.

(c) 1999 - 2006 The Zeos Development Group
================================================ FILE: lib/zeosdbo/doc/html/changes.html ================================================ ZeosDBO Change Notes
ZeosLib - open source tools for your database solutions

ZeosDBO Change Notes

ZeosLib Development Group


1. Changes in Release 7.0.1 - alpha (NOT RELEASED YET)

1.1. Bugs fixed from Mantis Bug Tracker

The bug tracker can be found at: http://zeosbugs.firmos.at

  • #0000216 [normal] Multiselect in TDbGrid wont work
  • #0000211 [normal] Save blob with sqlite and Delphi 2009/2010

1.2. Other Bugs fixed

1.3. Features added

1.4. Internal Changes

2. Changes in Release 7.0.0 - alpha (30.12.2009)

2.1. Bugs fixed from Mantis Bug Tracker

The bug tracker can be found at: http://zeosbugs.firmos.at

  • #0000208 [normal] TZAbstractRODataset bug and improvement (MIDAS IProviderSupport and IsUniDirectional)
  • #0000209 [normal] honor compiler conditional defines for all packages
  • #0000204 [normal] internalpost and bookmark
  • #0000203 [normal] MySQL Driver Fix and Optimatization
  • #0000202 [normal] Indonesian Translation Update
  • #0000201 [normal] Patch to solve some lib problems with SQLite3 under Linux.
  • #0000190 [normal] 64-bit support : first step (comon + mysql driver)
  • #0000178 [normal] Error compiling Zeos under Linux.
  • #0000178 [normal] INVALID_HANDLE_VALUE is undefined
  • #0000126 [normal] Quoting specific to PostgreSQL

2.2. Other Bugs fixed

2.3. Features added

  • [SQLite] removed support for SQLite2
  • [POSTGRES] Added new Postgres 8.4 SQL keywords (http://zeos.firmos.at/viewtopic.php?t=2523)
  • [COMMON] TZConnection.Pingserver now resets the ZConnection state when failing (http://zeos.firmos.at/viewtopic.php?t=2293)
  • [Common] Added ZURL unit to the core package. This unit provides splitting and composing routines for connect strings.
  • [IB/FB] Added support for milliseconds (http://zeos.firmos.at/viewtopic.php?t=2354)
  • [Oracle] Connections are now made using the OCIEnvNlsCreate method instead of OCIEnvInit and use property 'codepage=[UTF8,0..max Word value]' (http://zeos.firmos.at/viewtopic.php?t=2172)
  • [COMMON] Renamed IZObject.Hash to IZObject.GetHashCode after the new Delphi 2009 version (http://zeos.firmos.at/viewtopic.php?t=2131)
  • [COMMON] Default strings to TWideString fields on Delphi 2009 (http://zeos.firmos.at/viewtopic.php?t=2119)
  • [COMMON] Added BCB 2009 packages.
  • [COMMON] Added Delphi 2009 to the supported compilers. Big thanks to gto and mariuszekpl for this work!!
  • [COMMON] Added support for DefaultExpression TField property (#0000146)
  • [COMMON] (Delphi only issue) Added a test to avoid opening a dataset when ComponentState=csDestroying
  • [Mysql] Implemented reuse of prepared statements for mysql
  • [Common] Added Prepared property and Prepare/Unprepare methods to TZAbstractRODataset
  • [IB/FB] ZDbcInterbase6Utils.AffectedRows now also returns a value for select statements (http://zeos.firmos.at/viewtopic.php?t=2002)
  • [IB/FB] Add Connection timeout parameter (http://zeos.firmos.at/viewtopic.php?t=2002)
  • [POSTGRES] Limited default output of TZPostgresSQLDatabaseMetadata.GetTables to 'TABLE', 'VIEW' and 'TEMPORARY TABLE' (http://zeos.firmos.at/viewtopic.php?t=1960)
  • [COMMON] Sanity check: assert that row buffer length is not exceeded at a proper time - by HeidiSQL Team
  • [COMMON] Splitted IZDatabaseMetadata into IZDatabaseMetadata (retrieves info about DB content) and IZDatabaseInfo (retrieves info about server properties) (http://zeos.firmos.at/viewtopic.php?t=1946)
  • [POSTGRES] PostgreSQL UTF8 Charset Patch
  • [MYSQL] Removed support for mysql < 4.1
  • [COMMON] Removed packages for Delphi 5 and 6, Kylix 2 and CBuilder 5
  • [COMMON] New dataset option doDontSortOnPost (http://zeos.firmos.at/viewtopic.php?t=1931)
  • [COMMON] Added ZQuery.RefreshCurrentRow method
  • [MYSQL] Added Prepared Statements support (Experimental)
  • [COMMON] ZQuery property ValidateUpdateCount true by default

2.4. Internal Changes

  • [FPC] Removed T***IntDynArray types from ZCompatibility as FPC 2 and higher also defines these
  • [MYSQL] Cleanup of type/constant definitions in mysql plain drivers
  • [MYSQL] Updated libmysql versions in SVN repository
  • [COMMON] Added Delphi2009 to the automated build scripts and test suite
  • [DB2] Removed never used DB2 plain drivers
  • [COMMON] Reworked component bitmaps

3. Changes in Release 6.6.7 - stable (NOT RELEASED YET)

3.1. Bugs fixed from Mantis Bug Tracker

The bug tracker can be found at: http://zeosbugs.firmos.at

  • #0000218 [normal] Oracle NUMBER wrong conversion - New Oracle tests
  • #0000212 [normal] Oracle Dbc bugs

3.2. Other Bugs fixed

3.3. Features added

3.4. Internal Changes

  • [Lazarus/FPC] More tests enabled for Lazarus/FPC.
  • FPC : changing types of FHandle and HModul to PtrInt in ZCompatibility.pas and ZPlainLoader.pas for 64-bit compatibility (http://zeos.firmos.at/viewtopic.php?t=2358)
  • Add system path to testing path (to avoid installing oracle oci in different testing environments)
  • TZVariant : Putting vtBoolean, vtInteger, vtFloat.vtDatetime and vtPointer in a case record saves memory without any loss in function (http://zeos.firmos.at/viewtopic.php?t=2696)
  • [POSTGRES] A beter fix for bug report 136 (http://zeos.firmos.at/viewtopic.php?t=2599)
  • [Lazarus/FPC] Test database rebuild for Lazarus/FPC added.

4. Changes in Release 6.6.6 - stable (30.12.2009)

4.1. Bugs fixed from Mantis Bug Tracker

The bug tracker can be found at: http://zeosbugs.firmos.at

  • #0000177 [normal] Type mismatch error on runtime
  • #0000210 [Oracle] Bug inserting blob with length = 0
  • #0000187 [PostgreSQL] PingServer does (still) not detect lost connections
  • #0000207 [PostgreSQL] BlobRead Memory Leak
  • #0000194 [IB/FB] ZEOS is replicating NULL values on UPDATE statement
  • #0000173 [normal] unable to activate login dialog
  • #0000184 [Interbase 5] Can't get fields' list of dataset from Interbase 5.5 server
  • #0000183 [Lazarus] Icon for TZIBEventAlerter added

4.2. Other Bugs fixed

4.3. Features added

  • Zeoslib 6.6 is in it's stable phase. No features, except for eventual translations and docs, will (should) be added.
  • [COMMON] Added functions TRIM, VAL, CTOD, DTOS, LEFT and RIGHT.
  • [COMMON] New property FetchRow in ZDataSet (http://zeos.firmos.at/viewtopic.php?t=1857)

4.4. Internal Changes

  • [Lazarus/FPC] Test suite for Lazarus/FPC added.

5. Changes in Release 6.6.5 - stable (25.05.2009)

5.1. Bugs fixed from Mantis Bug Tracker

The bug tracker can be found at: http://zeosbugs.firmos.at

  • #0000179 [normal] Case problem for unit ZPlainMySqlConstants on linux
  • #0000002 [normal] FIREBIRD and NUMERIC/DECIMAL precision problem
  • #0000124 [normal] TZSQLMonitor access violation when destroying
  • #0000117 [normal] FPC - Float Fields with null values produce many exceptions
  • #0000150 [normal] Second JOIN in from clause was stripped by the SQL parser after ON or USING clause
  • #0000159 [normal] Fixed case of some *MySql* unit names
  • #0000165 [normal] Incorrect autogeneration of INSERT statement
  • #0000162 [normal] Precision issue when recording values from TClientDataSet

5.2. Other Bugs fixed

5.3. Features added

5.4. Internal Changes

  • NONE

6. Changes in Release 6.6.4 - stable (01.11.2008)

6.1. Bugs fixed from Mantis Bug Tracker

The bug tracker can be found at: http://zeosbugs.firmos.at

  • #0000147 [normal] Column mapping problem with TZUpdateSql and Refreshing data
  • #0000140 [normal] ZUpdateSQL set null as default datetime field value (Firebird)
  • #0000136 [normal] Memory leaking on failed Postgres connection
  • #0000139 [normal] Some MySQL units are still being compiled when only the SQLite protocol is enabled
  • #0000137 [normal] Exception Field '...' cannot be modified (calculated, lookup field) (Adjusted fix for Mantis Bug 99)
  • #0000133 [normal] Exception class EZSQLException : attempted update of read-only column (calculated)
  • #0000131 [normal] ZIBEventAlerter compile error in Lazarus/Linux
  • #0000129 [normal] Access Violation due to forget to assign Connection in TZQuery

6.2. Other Bugs fixed

6.3. Features added

  • NONE. Zeoslib 6.6 is in it's stable phase. No features, except for eventual translations and docs, will be added.

6.4. Internal Changes

  • NONE

7. Changes in Release 6.6.3 - stable (08.08.2008)

7.1. Bugs fixed from Mantis Bug Tracker

The bug tracker can be found at: http://zeosbugs.firmos.at

  • #0000123 [normal] Can not open TZTable in PostgreSQL (Replaced fix for Mantis Bug 97 (SVN rev. 344) by a more correct one)
  • #0000106 [normal] After Post of DataSet with Filtered=True, SortedFields defined, Row position is changed unexpectedly
  • #0000122 [normal] Problem with quoted fields (PostgreSQL keywords)
  • #0000121 [normal] ZQuery Insert/Update problem with MSSQL/ADO
  • #0000119 [normal] Memory leak in ZDbcSqLiteResultSet.pas
  • #0000113 [high] MYSQL - EZSQLException with message 'Column with name "Extra" was not found'. using latest MySQL 5.1.x
  • #0000108 [normal] Duplicated result when using locate, loPartialKey and Filter
  • #0000111 [normal] Lookup field value disappers on insert and edit and reappears after post or cancel
  • #0000105 [normal] Fields default expresion is determined from the wrong source
  • #0000095 [normal] It is impossible to be connected to base on tcpip
  • #0000099 [normal] Read only fields not really read only
  • #0000094 [normal] Invalid argument to time encode
  • #0000097 [normal] Cannot open table where tablename is similar to database name (Quoting TZTable.tablename)
  • #0000093 [normal] Wrong clearing of allocated data for SQLDA
  • #0000090 [normal] Default values from table are not used / Corrected Null fields handling in combination with autoinc and default values
  • #0000088 [normal] Delphi11 test packages missing in ZEOSLIB_TESTING_REV329
  • #0000086 [normal] Field values truncated
  • #0000087 [normal] Backslash gone in resultset
  • #0000082 [normal] Incorrect catalog name when no schema present and incorrect order
  • #0000080 [high] Naming convention in release build...

7.2. Other Bugs fixed

7.3. Features added

7.4. Internal Changes

8. Changes in Release 6.6.2 - rc (12.12.2007)

8.1. Bugs fixed from Mantis Bug Tracker

The bug tracker can be found at: http://zeosbugs.firmos.at

  • #0000022: [general] Split ZPlainMysql.inc
  • #0000023: [component] Problem using WideStrings and ADO protocol when chaging any WideString Field Data, same nature as Issue 0010 (fduenas)
  • #0000016: [core] Integer field treated as Largeint
  • #0000005: [postgresql] Memory grow when connection failed
  • #0000013: [interbase/firebird] can not use a string as parameter value for integer/long parameters
  • #0000019: [interbase/firebird] string parameters don't work for blob fields
  • #0000033: [interbase/firebird] Fixes a bug in UpdateString procedure for ZDbcInterbase6Utils
  • #0000034: [interbase/firebird] Lookup field make other field in TZQuery lost the value (disappear from display but still exists in database)
  • #0000020: [interbase/firebird] second call to stored proc fail with a parameter mismatch error (cipto_kh)
  • #0000040: [component] Error in conversion int64 to variant in InternalPost on Delphi/C++Builder 5 (ZAbstractDataset.pas)
  • #0000042: [general] Using the same component (TZStoredProcedure) after ExecProc then using Open it will crash (cipto_kh)
  • #0000037: [component] ZEOS AND LAZARUS 0.9.23 and FPC 2.1.3 WIN32 ERROR
  • #0000038: [component] Can't open sqlite databases with Umlauts like äöü in path (fixed)
  • #0000046: [component] fpc 2.1.4 cannot compile ZAbstractRODataset.pas
  • #0000028: [interbase/firebird] TZInterbase6DatabaseMetadata.HasNoWildcards - wrong result (cipto_kh)
  • #0000055: [component] Wrong index variable used when doing "refresh" in ZUpdateSQL component
  • #0000050: [postgresql] 'Access Violation' error on ZQuery.Open on table that has columns with non-standard type
  • #0000041: [postgresql] TZPostgreSQLDatabaseMetadata.GetSequences return not schema-qualified sequence list (ZDbcPostgreSqlMetadata.pas)
  • #0000049: [core] Lookup fields with int64 data type not work in Delphi/C++Builder 5
  • #0000007: [interbase/firebird] TZSequence error, value from prior database (cipto_kh)
  • #0000048: [general] TZSQLProcessor does not react when Script text is not properly delimited
  • #0000056: [component] Protection fault when doing an EAbort exception in BeforeConnect of TZConnection (patch incl.)
  • #0000064: [parsesql] Mysql /*! ...*/ special comments shouldn't be considered as real comments
  • #0000063: [component] TZSQLProcessor and comments handling
  • #0000061: [component] Wrong data returning in select
  • #0000065: [general] FPC 2.2 doesn't compile
  • #0000068: [postgresql] Wrong datatype declared
  • #0000043: [component] ReadOnlyQuery + TDataSetProvider = Blank fields on details
  • #0000059: [component] ZQuery-DSP-CDS empty field data fetched while using incremental fetching (PacketRecords>0
  • #0000027: [interbase/firebird] problem handling DEFAULT NULL in domain *AND* in table
  • #0000069: [general] Compiler Warnings in Delphi 2006
  • #0000071: [interbase/firebird] Floating point not display correctly (cipto_kh)
  • #0000076: [mysql] SSL Connection Error
  • #0000075: [sqlite] Memory Error Detected
  • #0000070: [general] Missing license files
  • #0000079: [dbc] Typo in SQl statement in TZInterbase6Connection.Open;
  • #0000017: [mysql] LargeInt fields treated as Variant
  • #0000060: [sqlite] Memory leaks in sqlite-3 driver

8.2. Other Bugs fixed

  • Metadata (mdTables) was missing remarks data (http://zeos.firmos.at/viewtopic.php?t=1567)
  • Memory leaks (http://zeos.firmos.at/viewtopic.php?t=1408)
  • Correction of child dataset refresh (http://zeos.firmos.at/viewtopic.php?t=1381)
  • Set autocommit issue when transaction isolation=tiNone (http://zeos.firmos.at/viewtopic.php?t=1251)
  • TZAdoDatabaseMetadata.GetColumns doesn't fetch database and schema names. (http://zeos.firmos.at/viewtopic.php?t=1252)
  • TZRowAccessor.CompareBuffers didn't work for stUnicodeStreams (http://zeos.firmos.at/viewtopic.php?t=1254)
  • TZSQLStrings.StatementCount = 1 when the statement is empty (http://zeos.firmos.at/viewtopic.php?t=1228)
  • Error handling empty string values (makes them NULLS) (http://zeos.firmos.at/viewtopic.php?t=1255)
  • Read blob truncates last byte for ADO (http://zeos.firmos.at/viewtopic.php?t=1250)
  • Close/Open sequence replaced by refresh in TZAbstractRODataset.RefreshParams (http://zeos.firmos.at/viewtopic.php?t=1093)
  • Wrong mysql version reference in GetMoreResults function
  • Required should be false if a field is not writable (http://zeos.firmos.at/viewtopic.php?t=767)
  • Avoid open/close of detail dataset on edit of master dataset (http://zeos.firmos.at/viewtopic.php?t=1093)
  • FreeAndNil fix in ZSequence - (http://zeos.firmos.at/viewtopic.php?t=1108)
  • Mysql fixes by HeidiSQL Team (Repository viewer at http://fisheye3.cenqua.com/changelog/heidisql)

    • Avoid an access violation within a for loop which got run once even when there were 0 columns in a result. (HeidiSql rev. 993)
    • Fix bug "SHOW FULL PROCESSLIST on mysql v4 server messes Zeos up". (HeidiSql rev. 775 and 900)
    • Fix handling default values. (HeidiSql rev. 505)
    • Zeos did not recognize UNSIGNED ZEROFILL columns as being UNSIGNED. (HeidiSql rev. 521)

8.3. Features added

  • All mysql_options() and connection clientflag settings can now be set using TZConnection.Properties (http://zeos.firmos.at/viewtopic.php?t=1528)
  • Updated indonesian translations (by tohenk)
  • Added Russian translation (by ormada)
  • Use Mysql_real_escape_string instead of mysql_escape_string when executing mysql emulated prepared statements
  • Added IZConnection.EscapeString function. This funtion returns a string that can be used in SQL statements. Uses Mysql_real_escape_string or Mysql_escape_string functions for mysql databases and EncodeCString function for other databases
  • FPC changes -> now zeoslib also works with MSEIDE - By MSEIDE team (http://www.homepage.bluewin.ch/msegui)
  • Added all reserved words, functions from mysql 5.1 documentation to metadata GetXXX functions (http://zeos.firmos.at/viewtopic.php?t=1213)
  • Replaced 'Select' in Getversion to Native library call
  • Added support for Mysql SSL connections
  • Added TZConnection.GetColumnNames function (http://zeos.firmos.at/viewtopic.php?t=1127)
  • Added Delphi2007 package files (http://zeos.firmos.at/viewtopic.php?t=1173)
  • Changed PingServer behaviour : Only return false when ping fails. No exception. This function is a check, so it should be allowed to return false. On demand of HeidiSql team.
  • Modified Readme text for mysql embedded server example
  • Added Multiple resultset support on Dbc level (http://zeos.firmos.at/viewtopic.php?t=459 and http://zeos.firmos.at/viewtopic.php?t=912)
  • ZDataset Events in Lazarus (http://zeos.firmos.at/viewtopic.php?t=1130)
  • New Features by HeidiSQL Team (Repository viewer at http://fisheye3.cenqua.com/changelog/heidisql)

    • Added unknown data types from mysql_com.h. (HeidiSQL rev. 835)
    • Make ConvertMySQLHandleToSQLType() more readable (HeidiSql rev. 676)
    • Ignore columns that do not originate from the table when resolving updates (HeidiSql rev. 555)
    • Added function TZAbstractResultSetMetadata.HasDefaultValue (HeidiSql rev. 504)
    • TZConnection.Reconnect added (HeidiSql rev. 53)

8.4. Internal changes

  • Release build script has been rewritten
  • Fixed the automatic build system and test suite. Works now certainly for D5, D7, D2006, D2007
  • Added SVN ant utilities to repository so build scripts should run on a standard Ant installation
  • Added Lazarus/Fpc to the automatic build system. Test suite is not available, however. Package *.pas files are necessary for automated build system.
  • Removed some compiler warnings and unused units.
  • Start of the zeoslib documentation project using doxygen

9. Changes in Release 6.6.1 - beta (25.02.2007)

9.1. Bugs fixed

  • #0000003: Field confusion in GetColumnInfo
  • #0000010: Widestring field's contents Using ado protocol and access database is unreadable

    When using a TzQuery or TZTable using ado protocol and an access database with OLEDB Jet engine, the contents of any TWideString field is unreadable (it returns symbols) and sometimes throws Out of Memory error.

  • #0000016: Integer field treated as Largeint
  • #0000003: Field confusion in GetColumnInfo
  • #0000021: ClientVersion and ServerVersion properties fail on closed connection

    When calling ClientVersion and ServerVersion on a closed mysql connection they refer to an unassigned object.

  • #0000023: Problem using WideStrings and ADO protocol when chaging any WideString Field Data, same nature as Issue #0000010

    When using a TzQuery or TZTable using ado protocol and an access database with OLEDB Jet engine, when changing the the contents of any TWideString field, the values is unreadable (it returns symbols) and sometimes throws Out of Memory error.

  • EOutofMemory with Delphi 2006 + Firebird (http://zeos.firmos.at/viewtopic.php?t=972)
  • Zeos 6.6-Beta: func GetTableNames() / PingServer (http://zeos.firmos.at/viewtopic.php?t=992)
  • Race happens? (http://zeos.firmos.at/viewtopic.php?t=974)
  • MySQL and FLOAT fields (precision) (http://zeos.firmos.at/viewtopic.php?t=930)
  • Memory Leak - ZeosLib 6.5.1, MySQL 4.1, Lazarus (http://zeos.firmos.at/viewtopic.php?t=812)
  • Bug in ZAbstractRODataset (6.6.0 beta version) (http://zeos.firmos.at/viewtopic.php?t=898)
  • Bug in ZDbcPostgreSqlMetadata.pas(6.6 beta) (http://zeos.firmos.at/viewtopic.php?t=839)
  • Postgres Blob field bug (http://zeos.firmos.at/viewtopic.php?t=931)
  • Do not work sorterfields (http://zeos.firmos.at/viewtopic.php?t=920)
  • Fix for TZInterbase6DatabaseMetadata.GetSequence (http://zeos.firmos.at/viewtopic.php?t=864)
  • ERangeError after FormCreate (http://zeos.firmos.at/viewtopic.php?t=902)
  • Delphi5 and MySql5 (http://zeos.firmos.at/viewtopic.php?t=886)
  • Zquery and Ztable not accept numeric database (http://zeos.firmos.at/viewtopic.php?t=882)
  • BCB6 ZDbc.bpk (http://zeos.firmos.at/viewtopic.php?t=854)
  • Fix for Bug in ZInterbase6Sequence.GetNextValue (http://zeos.firmos.at/viewtopic.php?t=856)
  • ztable problem : editing and TableName (http://zeos.firmos.at/viewtopic.php?t=748)
  • MySQL: Cannot update this query type(backticks) (http://zeos.firmos.at/viewtopic.php?t=552)
  • InterBase/FireBird BLOB handling error (http://zeos.firmos.at/viewtopic.php?t=855)
  • Duplicate messages in portuguese language (ttp://zeos.firmos.at/viewtopic.php?t=848)

10. Changes in Release 6.6.0 - beta (20.10.2006)

10.1. Features added

  • LinkedFieldNames vs. IndexFieldnames (See http://zeos.firmos.at/viewtopic.php?t=796)
  • New Dataset features : BeforeApplyUpdates (event), AfterApplyUpdates (event), SortType (property), EmptyDataSet (procedure)
  • Added separate drivers for embedded Firebird server (http://zeos.firmos.at/viewtopic.php?t=630)
  • Delphi 2006 packages
  • Mysql5 Support integrated
  • PostgreSQL 8.x Support integrated
  • Added Sybase Adapitive Serve Anywhere (ASA) Support for Versions 7, 8 and 9.
  • MySQL Ping Commando added
  • Insert "const" for ref-counted parameter (http://zeos.firmos.at/viewtopic.php?t=519)
  • MySQL Embedded Server Arguments (http://zeos.firmos.at/viewtopic.php?t=777)
  • separated Firebird from interbase/strict dll loading for Firebird
  • TZConnection: property 'Version', showing the current version
  • Support for fkInternalCalcFields in datasets
  • Added property DesignConnection: If DesignConnection is true connected is not set to true during runtime and must be set explicitly
  • Enabled all connection options for mysql. Now one can add the desired options by adding them to the connections property strings.
  • Rewrite of ZPlainMysqlXX files to add embedded server support for versions 4.0,4.1,5 of mysql
  • Added new library functions to plain mysql drivers (4.1)
  • Added new library functions to plain mysql drivers (3.23 and 3.20)
  • Error handling for Postgres now returns result codes from server
  • Two Phase Commit for PostgreSQL
  • Added parameter capability to TZSQLProcessor so you now can use parameters inside your SQL scripts like you do in "normal" queries.
  • Added const "ZEOS_VERSION" to ZClasses and added property "Version" to TZConnection.
  • Added support of fkInternalCalcFields for ZEOS datasets.
  • Added property "DesignConnection" to turn off active design time connections during runtime, automatically.
  • Added PropertyEditor for TField-properties in several components.
  • Added default values to the following properties:

    • TZAbstractRODataset.RequestLive: False
    • TZAbstractRODataset.ParamCheck: True
    • TZAbstractRODataset.ShowRecordTypes: [usUnmodified, usModified, usInserted]
    • TZAbstractRODataset.IsUniDirectional: False
    • TZAbstractRODataset.Options: [doCalcDefaults]
    • TZAbstractRODataset.ReadOnly: True
    • TZAbstractDataset.UpdateMode: umUpdateChanged
    • TZAbstractDataset.WhereMode: wmWhereKeyOnly
    • TZAbstractDataset.CachedUpdates: False
    • TZConnection.SQLHourGlass: False
    • TZQuery.ReadOnly: False
    • TZTable.ReadOnly: False
    • TZSqlMetadata.Scope: 0
    • TZSqlMetadata.Nullable: False
    • TZSqlMetadata.Unique: False
    • TZSqlMetadata.Approximate: False
  • /SG/ Changed default values for following properties:

    • TZConnection.ReadOnly: False
  • /SG/ Changed following default initializations:

    • - TZAbstractDataset.RequestLive := True;
    • TZConnection.ReadOnly := False;
  • /SG/ Changed following property names:

    • TZQuery.RequestLive --> TZQuery.ReadOnly
  • /SG/ Added parameter capability to TZSQLProcessor like in TZQuery.

10.2. Patches applied

  • Const and optimization (http://zeos.firmos.at/viewtopic.php?t=551)
  • MissingConsts, Inlining, SilentException (http://zeos.firmos.at/viewtopic.php?t=566)
  • Packages for delphi 6 (http://zeos.firmos.at/viewtopic.php?t=577)
  • PostgreSQL EncodeString() (http://zeos.firmos.at/viewtopic.php?t=589)
  • Date, Time and Float on Lazarus (http://zeos.firmos.at/viewtopic.php?t=598)
  • Updates for ZMessages (translations)
  • Const modifier added to function definitions where possible to improve speed (http://zeos.firmos.atviewtopic.php?t=519)

10.3. Bugs fixed

  • ZDbcConnection.pas contains wrong line breaks (http://zeos.firmos.at/viewtopic.php?t=553)
  • Other files with LF instead of CRLF (http://zeos.firmos.at/viewtopic.php?t=554)
  • svn rev. 59 (Linux filenames problem) (http://zeos.firmos.at/viewtopic.php?t=593)
  • error type date in lazarus (http://zeos.firmos.at/viewtopic.php?t=574)
  • MySQL v.5.0 .3+ and Decimals (http://zeos.firmos.at/viewtopic.php?t=605)
  • ZSqlUpdate append error (http://zeos.firmos.at/viewtopic.php?t=677)
  • Error opening Query (http://zeos.firmos.at/viewtopic.php?t=628)
  • Compiling in Borland C++ Builder 6 (http://zeos.firmos.at/viewtopic.php?t=694)
  • compiling for delphi5/6 (http://zeos.firmos.at/viewtopic.php?t=802)
  • Memory leak MSSQL2000 TZQuery.ExecSQL (http://zeos.firmos.at/viewtopic.php?t=788)
  • ZEOS_TESTING_REV_113 Sybase-Bug (http://zeos.firmos.at/viewtopic.php?t=822)
  • Removed Rangecheck Directive (all files) (FPC 2.0.2 is buggy)
  • Updated lazarus package for correct compilation. (Missing packages, corrupt package file,...)
  • Some more Lazarus package modifications
  • Memory leak bug fixed (http://zeos.firmos.at/viewtopic.php?t=461)
  • Delimiter problem in ZSQLProcessor fixed (http://zeos.firmos.at/viewtopic.php?t=527)
  • Fixed Delphi 5 install problems (http://zeos.firmos.at/viewtopic.php?t=335)
  • Added {$LIBSUFFIX 'X0'} to projectfiles of D7 and D2006 (http://zeos.firmos.at/viewtopic.php?t=561)
  • Removed ASA driver from Lazarus packages because not compilable in Lazarus.
  • Bug in GetIndexInfo (http://zeos.firmos.at/viewtopic.php?t=196)
  • Added GetClientVersion and GetServerVersion to Connection/Driver interfaces
  • Integrated contribution from Terence : Added more specific metadata clearcache possibilities.
  • Delphi 7 : Split up Component Package into Component and ComponentDesign (http://zeos.firmos.at/viewtopic.php?t=726)
  • Delphi 7 : Added compiler directives to avoid inclusion of not wanted database drivers. (http://zeos.firmos.at/viewtopic.php?t=746)
  • InternalPost (Procedure) (http://zeos.firmos.at/viewtopic.php?t=781)
  • Updatesql component (OnUpdate event)
  • Mssql Select * error (http://zeos.firmos.at/viewtopic.php?t=788)
  • Added Lazarus fixes : ASA support did not compile well.
  • Firebird: Memory leak bug fixed (http://zeos.firmos.at/viewtopic.php?t=461)
  • Corrections for non-strict dllloading
  • Bytea/blob - PostgreSQL - UNICODE/UTF8 (http://zeos.firmos.at/viewtopic.php?t=683)
  • Integrated patch from Fduenas concerning http://zeos.firmos.at/viewtopic.php?t=677
  • Mysql MetaData Patch to support temporary tables
  • Corrected the temporary tables patch. Now it tries to get information on a 'non-existing' table, just in case it is a temporarary one. If it is temporary the table is added to the cache If it's not, the resulting error is suppressed but the table will stay unknown.
  • Various modifications/extentions to Mysql DBC and Plain driver units - Written by fduenas and mdaems
  • Removed calls to Mysql datastructure where possible (Only necessary for mysql3.20) - written by mdaems
  • Bad tiReadCommited corrected (http://zeos.firmos.at/viewtopic.php?t=570)
  • Widestring Fields are always returning Null if one tries to access property Value.
  • Firebird 1.5: field named "STATUS_REG" that doesn't show in TZDataSet.
  • FPC/Lazarus: Connecting to a Firebird Database will cause a Range Check Error.
  • Zeos appears to be bringing back Postgresql money type as ftfloat instead of ftcurrency.
  • Row inserting is impossible with simple queries when TZQuery.ReadOnly property set to false and no TZQuery.UpdateObject defined.
  • In the metadata, all user tables were being reported as type VIEW.
  • Problem in ZSysUtils.BytesToVar().
  • Problem with TZAbstractDataset.InternalPost.
  • When using GetPChar() Result of GetPChar() points to unallocated memory.
  • ZeosDBO (Ado) update problem with TZUpdateSQL
  • Username property not refreshed if changed in login box
  • Problem with TZTable refresh method
  • IProviderSupport - PSUpdateRecord
  • Firebird 1.5 Read Only Database on CD
  • ZQuery's FieldsEditor brings diff. types for the same field
  • Login Dialog unstable appearance
  • Wrong results for lookup fields
  • open cursors in Oracle
  • Change data when Dataset.State = dsBrowse
  • Exception when deleting record with ClientDataSet
  • Strange behaviour Zeos - DBLookUpComboBox
  • CreateStatement and Properties
  • WideString Updates
  • MySQL:zeos doesnt assign default '0000-00-00' to Date Fields
  • TZAbstractRODataset.RereadRows;
  • CaseSensitive locate on WideString fields
  • Filter issues
  • AV error when opening a DML with a TZQuery using doSmartOpen
  • Incorrect TZPostgreSQLNotify definition
  • Access violation on large string fields.
  • MySQL Date/Time bug + Fix
  • Firebird 1.5: unsupported datatype
  • Startup failing if compiled with "Full Boolean Evaluation"
  • SetFieldData for ftString don't refresh
  • ADO TDateTime parameter wrong type
  • TZTable's TabeleName Property - not list with ADO protocol

11. Changes in Release 6.5

11.1. Release 6.5.1 - 23 Nov 2004

  • /CNL/ Fixed Bug#912639 Result sets were not decoded
  • /CNL/ Another version of PostgreSQLToSQLType() is added to boost execution speed

11.2. Release 6.5.1 - 17 July 2004

  • /SM/ Fixed Bug#1021705 Numeric values overflow
  • /SM/ Fixed Bug#1034795 Metadata don't filter the table type
  • /SM/ Fixed Bug#993352 problem with TZInterbase6DatabaseMetadata.GetTables table type SYSTEM TABLE
  • /SM/ Fixed Bug#991069 Creation of a DB and FKs in Firebird
  • /SS/ Fixed Bug#985629 Locate and Lookup don't find float fields.
  • /SS/ Added database error codes to rethrown exceptions in dataset.
  • /SS/ Fixed Bug#993981 MySQL and PostgreSQL drivers do not process float values if decimal separator other then “.”.
  • /SS/ Fixed Bug#995080 “List Index Out of Bounds” exception in Dataset.UpdateStatus on empty resultset.
  • /SS/ Fixed Bug#999658 Truncation of BigDecimal fields. Thanks to Kestutis Laurinavicius.
  • /SS/ Fixed Bug#1000534. SQL Parser error when “join ... on” clause contains functions with parameters.
  • /SS/ Fixed Bug#1004534 Access Violation when RecNo is called on closed Dataset.
  • /SS/ Fixed Bug#1045286 Method IsNull returns incorrect result for fields containing “” characters.
  • /SS/ Added support for cidr, inet and macaddr column types into PostgreSQL driver.

11.3. Release 6.5.0 - 10 March 2004

  • /SS/ Added IProviderSupport interface implementation to datasets.
  • /SS/ Added support for MySQL 4.1 database.
  • /SS/ Added support for PostgreSQL 7.4 database.
  • /SS/ Added support for Oracle 9i database.
  • /SS/ Fixed Bug#981208 SELECT * FROM mydb.mytable is not updateable.
  • /SS/ Replaced thrown exception type from Datasets to EZDatabaseError custom class.
  • /SS/ Fixed Bug#966267 Fixed processing OnEditError, OnPostError, OnDeleteError events.
  • /SS/ Fixed memory leak in Statement.Execute. Now all Connections, Statements and ResultSets must be explicitely closed before desposing.
  • /SS/ Added doSmartOpen option to Dataset to allow executing DML statements by Open without throwing exception.
  • /SM/ Fixed Bug#959307 TZDBLibCallableStatement.Execute Empty parameter string sever translate as null value
  • /SM/ Fixed Bug#907497 TZDBLibCallableStatement.ExecutePrepared Return incorrect string values of stored procedure
  • /SM/ Fixed Bug#951881 TZFirebirdNativeLibraryLoader Interbase do not work with INTERBASE_CRYPT enabled
  • /SM/ Fixed #956613 TZInterbase6DatabaseMetadata.GetTables Error in metadata reading
  • /SM/ Fixed #947915 TZInterbase6CallableStatement.ExecuteUpdatePrepared do noit raised exception in Stored Procedure
  • /SM/ Fixed #945251 TZAbstractDatabaseMetadata.GetTableTypes always returns “TABLE” as result, never“VIEW” and never “SYSTEM TABLE”.
  • /SS/ Fixed Bug#914057 ZSQLMonitor.SaveToFile don't use FileName.
  • /SM/ Fixed Bug #914436 Text fields with specified character set are not recognized in MySQL driver.
  • /SM/ Fixed Bug #914369 Fixed memory leaks in Interbase driver
  • /SS/ Fixed Bug#912220 PostgreSQL driver doesn't read oid blobs.
  • /SM/ Fixed Bug#909181 do not sets fields to null
  • /SM/ Fixed Bug #914436 Bug several MySQL TEXT Fields are not correct identified
  • /SS/ Fixed Bug #919395 Memory leak in TZExpressionParser.TokenizeExpression. Thanks to mocarts.
  • /SS/ Fixed Bug #919401 When dataset is in Edit mode function UpdatesPending always returns true does matter were changes made or not. Thanks to mocarts.
  • /SS/ Added processing for query parameters with ftGraphic type. Thanks to Pavel Blahovec.
  • /SS/ Added support for SQL specific syntax in Query.SQL and UpdateSQL.
  • /SS/ Added support for SQLite 2.8 database.
  • /SS/ Fixed Bug #924861 Memory leak, when client cannot connect to server
  • /SS/ Added depended compilation for drivers, included into TZConnection drivers list. Now users may select which drivers they want to use to decrease size of their applications. (See /src/Zeos.inc file for details)
  • /SS/ Refactored ZDBC metadata classes.
  • /SS/ Fixed processing of Int64 values in Dataset.Refresh.
  • /SS/ Fixed Bug #933623 'current transaction is aborted, commands ignored until end of transaction block.' error in postgresql when previous statement in transaction fails. Now if autocommit mode is set components automatically rollback failed statements. In manual commit mode developer should explicitely call Connection.Rollback.
  • /SS/ Added GetProtocolNames, GetCatalogNames, GetSchemaNames, GetTableNames, GetStoredProcNames methods into TZConnection component.
  • /SS/ Fixed Bug #824786 TZMetadata shows PostgreSQL 7.4 system tables from 'information_schema' as regular tables.
  • /SS/ Changed type for Dataset.ShowRecordTypes to TUpdateStatusSet.
  • /SS/ Fixed duplicated AfterScroll event in Query.Locate and Query.FindRecord methods.
  • /SS/ Fixed Bug#948940 Random “Can not update this query type” error in PostgreSQL driver. Thanks to Sergio Freue.
  • /SS/ Replaced RequestLive with ReadOnly property in TZTable component to make it more compatible with standard TTable.
  • /SS/ Added InTransaction property in TZConnectioncomponent.
  • /SS/ Fixed Bug#957126 Incorrect processing of empty strings in default values in MySQL driver. Thanks to Alex/ghost3k.

12. Changes in Release 6.1

12.1. Release 6.1.4 - 21 January 2004

  • /SS/ Fixed Bug#880459 Access Violation in ZSQLProcessor.Execute method when Connection is not assigned.
  • /SS/ Fixed Access Violation in MySQL driver when opening a resultset for queries which do not return any data.
  • /SS/ Fixed Bug#881634 Complex select statements return wrong field types.
  • /SS/ Fixed Bug#883027 Wrong comparison for rows with Int64 and Binary Array fields. Thanks to sskacar.
  • /SS/ Fixed Bug#884135 Problem in master-detail links with unsigned int keys.
  • /SS/ Fixed Bug#882150 Incorrect processing empty strings in filter expressions.
  • /SS/ Fixed Bug#887103 BeforeScroll and AfterScroll events are not working with SetRecNo. Thanks to Alexander Klenin.
  • /SS/ Fixed Bug#886841 Error in processing default values for columns with type enum(y,n) in MySQL driver.
  • /SM/ Fixed Bug#886914 Incorrect updating CHAR not null and empty fields in Interbase/Firebird driver.
  • /SM/ Fixed Bug#886854 Problem with field types for system fields in Firebirb 1.5 RC8 type
  • /SM/ Fixed Bug#882232 Invalid Color property value in ZUpdateSqlEditor.dfm
  • /SM/ Fixed Bug#865299 Interbase 5.5 wrong metadata reading
  • /SS/ Fixed a memory leak in TZSQLProcessor component. Thanks to Martin Fibiger.
  • /SS/ Fixed Bug#894367 Incorrect parsing queries with non-unique field column names.
  • /SS/ Fixed Bug#910804 Wrong processing regular expressions with '*abc' style patterns.

12.2. Release 6.1.3 - 11 December 2003

  • /SS/ Fixed leaving cached statement object in TDataset.ExecSQL after connection component changed.
  • /SS/ Fixed Bug#862261 Empty blobs sometimes included into Where clause of generated DML statements as <field>=NULL. It caused missed updates.
  • /SS/ Fixed compilation for Kylix 1 compiler.
  • /SS/ Added functions CONCAT, UPPER, LOWER, SUBSTR and STRPOS to filter expressions.
  • /SS/ Fixed Bug#864797 Filter Expressions don't process columns with NULL values correctly.
  • /SM/ Fixed Bug#860196 & #851664 Call Stored Procedures and Firebird 1.5
  • /SM/ Fixed bug #864622 ZQuery return numeric(3,1) fields as IntegerField
  • /SS/ Fixed bug #869609 Wrong behaviour of MySQL AutoIncremented fields
  • /SS/ Fixed error handling in CachedResultSet.DeleteRow method. Thanks for Tobias Giesen.
  • /SM/ Fixed bug #865585 Wrong exception behavior in ExecuteQuery and ExecuteQueryPrepared Thanks for Alex Gilev.
  • /SS/ Fixed processing connection timeout parameter for PostgreSQL.

12.3. Release 6.1.2 - 12 November 2003

  • /SS/ Added IS NULL, IS NOT NULL, NOT LIKE operations to Filter Expression.
  • /SS/ Fixed Bug#842678 AV when removing ZUpdateSQL from ZQuery.
  • /SS/ Added codepage (client codepage) and timeout connection timeout to MySQL and PostgreSQL drivers.
  • /SS/ Added single line comments started with -- to MySQL parser.
  • /SS/ Fixed Bug#841425 TZSQLProcessor did not skip empty statements and it cased database errors.
  • /SS/ Fixed Bug#837764 Transaction Isolation Level not set after Commit and Rollback in PostgreSql driver.
  • /SS/ Fixed Bug#840608 Where clause in generated DML statement was incorrect if it included NULL values.
  • /SS/ Fixed generation of UPDATE statements with UpdateMode=UpdateChanged.
  • /SS/ Fixed Bug#840218 Lookup method returned incorrect result field.
  • /SM/ Fixed Bug#833766 FloatField don't load scale correct
  • /SM/ Added support for interbase 7
  • /SM/ Fixed Bug#845312 Wrong float/double updating in ZDbcInterbase6Utils
  • /SM/ Fixed Bug#847593 Codepage don't set correctly
  • /SM/ Fixed Bug#841559 Triggers and messages
  • /SM/ Fixed Bug#843655 Blob fields don't updates
  • /SM/ Fixed Bug#847594 Exceptions descriptions
  • /SM/ Fixed Bug#844597 AV Error after closing window of ZQuery's Properties properties
  • /SM/ Fixed Bug#841515 C++ Builder 4 Error installing ZeosDBO
  • /SS/ Fixed Bug#849723 Time columns with “00:00:00” values are converted to NULLs in MySQL driver.
  • /SS/ Added doAlwaysDetailResync option to Dataset.Options which turns on/off synchronization between Master and Detail dataset when Master is in Edit or Insert mode.
  • /JF/ Fixed Bug#853690 AutoInc fields in MS SQL
  • /JF/ Fixed Bug#842694 Quoted Fields generated by TZUpdateSQL not accepted by MySQL
  • /JF/ Fixed Bug#841488 Problem with milliseconds in MS SQL dates
  • /SM/ Added support PostgreSql-7.3. Added libpq73.dll and potocol postgresq-7.3

12.4. Release 6.1.1 - 28 September 2003

  • /SS/ Added support for column default values defined in database. Default values of TField are still unsupported.
  • /SS/ Replaced Borland Variants with custom implementation. It solved many problems with data type convertions and Int64 support in filter expression, master/detail links, locate and many other places.
  • /SS/ Optimized Locate and Lookup methods in TDataset. The speed was increased up to 6 times.
  • /SS/ Added UpdateMode and WhereMode properties to TDataset. UpdateMode has two options: umUpdateChanged to post to database only updated fields and umUpdateAll to post all fields.TZWhereMode controls WHERE clause in posted DML statements. wmWhereKeyOnly includes in WHERE only key fields if they exist, wmWhereAll includes all fields.
  • /SS/ Added Options property to TDataset. Now it supports two options doOemTranslate to turn on Ansi to OEM translation in visual controls and doCalcDefaults to turn on/off calculation of column default values defined in database.
  • /SS/ Fixed Bug#816846. PostgreSQL text columns are included now into WHERE clause in autogenerated DML statements. Before they were skipped and it caused problems for tables with text columns where primary key was not defined.
  • /SS/ Fixed Bug#816850 “Changing blobs overwrite old values.
  • /SS/ Added SortedFields property to TDataset. The format of the SortedFields value should be:<Field Name> [ASC | DESC] [,...]
  • /SS/ Fixed Bug#810249. Added workaround to prevent objects self-destruction in contructors. The bug exist in Delphi 4 and C++ Builder 4 compilers. It decrements reference counter and destroys object if in constructor some interface method is called.
  • /SS/ Excluded ADO driver from Delphi 4 and BCB 4 packages due to lack of support OLE data types in that compilers.
  • /SS/ Fixed Bug#824792. Fixed “Interface not supported” error in TZMonitor in C++ Builder 5 compiler.
  • /SM/ Fixed Bugs #824948 and #824875 “Firebird 1.5 - Statement not allowed”.
  • /SM/ Fixed Bug#815955 “Wrong mapping numeric(15) to TIntegerField
  • /SM/ Fixed Bug#804112 “AutoCommit Interbase/Firebird transaction problem
  • /SM/ Fixed Bug#789879 “Firebird: Float->Numeric
  • /SM/ Fixed Bug#825029 “examples - Controls conflict names with Delphi7
  • /DD/ Fixed Bug#817612 “C++ Builder hpp generation bug
  • /SS/ Added support for PostgreSQL domains (user defined types). As a drawback all domain strings types have length 255 characters.
  • /SM/ Fixed Bug#815861 “Incorrect parsing of the Version#” for PostgreSql7.x betas.
  • /SS/ Fixed Bug#831776 “TZLoggingEvent is not found”.
  • /SS/ Fixed Bug#831559 “Usage SQL keywords in column names”.
  • /JF/ Feature Requests#831925. Added several connection parameters to MS SQL: application name, workstation name and few more.
  • /JF/ Fixed Bug#826621. Added reconnection in the case of network problems to MS SQL driver.
  • /JF/ Fixed Bug#817400 “Schema support for TZTable
  • /SS/ Fixed Bug#832467 “Filter expression does not process string constants contained single quote symbols inside”.
  • /SS/ Fixed Bug#830804 “Changing dataset fields order in runtime (dragging column in DBGrid for example) causes AV”.
  • /SS/ Fixed Bug#833197 “Refresh problem with filtered data”.
  • /JF/ Fixed issues related to ADO in Delphi 4 and C++ Builder 4 compilers.
  • /SS/ Added STRICT_DLL_LOADING definition into /src/Zeos.inc to prevent loading of libmysql.dll and libpq.dll libraries by default. If was done because of constant user problems with unsupported dlls. To enforce loading default libraries you should comment the definition and recompile the components.
  • /SS/ Added optimization for switching transaction modes in MySQL driver.
  • /JF/ Added support of SQLHourGlass cursor in the component.
  • /SS/ Fixed Bug#834798 “Locate with [loCaseInsensitive] parameters does not work”.

  • /SS/ Fixed Bug#839540 Logical operations don't work properly in filter expression.

12.5. Release 6.1.0 - 28 July 2003

  • /SS/ Rewritten SQL parsers, removed Parse package from the project.
  • /SS/ Modified TZSQLProcessor component.
  • /JF/ ADO driver is added.
  • /JF/ Modified TZBlobStream to support notification about change.
  • /SS/ Code has been optimized.
  • /SS/ Finished source code review.
  • /SS/ Added parameters to ZDBC statements.
  • /SS/ Added multiple statements property to TZUpdateSQL.
  • /SS/ Added TZSQLMonitor component.
  • /SS/ Added filter expressions
  • /JF/ Stored procedure support for mssql dblib interface, works for sybase also
  • /SS/ Added DataSource property in TDataset to support master-detail links.
  • /SS/ Added MasterSource, MasterFields and IndexFieldNames to support master-detail links with client-side filtering
  • /SS/ Added support for MySQL autoincremented fields
  • /JF/ Added support for Sybase and MS SQL identity fields
  • /JF/ Added support for exiting without error messages in case of broken connection
  • /JF/ Added some new metadata columns to getcolumns to support calculated fields
  • /JF/ Autoincremented field support for mssql, sybase and ado added to return the generated value.
  • /JF/ Added workaround for procedure parameter type query for sybase. It works only for ASE12.5 or above
  • /JF/ Added workaround for sybase structure 'AND NULL IS NULL' resulted in error: Invalid operator for datatype op: is null type: VOID TYPE.
  • /SS/ Added TZTable component.
  • /SS/ Added TZSQLMetadata component.
  • /SS/ Added caching for database metadata
  • /SM/ Fixed Bug#804112 AutoCommit Interbase/Firebird transaction problem.
  • /SM/ Fixed Bug#795832 Exception handling in Interbase statement
  • /SM/ Added Plain API for DB2

13. Changes in Release 6.0

13.1. Release 6.0.12 Patch#3 - 28 September 2003

  • /SS/ Fixed Bug#817607 Fail refreshing Query when field names contain spaces.
  • /SS/ Fixed AV when connection is destroyed before linked datasets (Thanks to Ask).
  • /SS/ Fixed Bug#826624 Incorrect converting for Int64 Params (Thanks to Dmitry Krylov)
  • /SS/ Fixed Bug#816925 Wrong mapping of Decimal and Numeric fields in MySQL
  • /SS/ Fixed Bug#826886 AV in TDataset.ExecSQL after disconnecting TZConnection.

13.2. Release 6.0.12 Patch #2 - 28 September 2003

  • /SS/ Fixed Bug#803616 Fail posting inserted and then updated records in cached updates mode.
  • /SS/ Fixed Bug#804323 Calculated fields in read only datasets.
  • /SS/ Fixed Bug#804640 Calculated fields of type TCurrencyField returns always 0.00.
  • /SS/ Fixed Bug#802548 Error “List Index out of Bounds (-1)” in Refresh method.
  • /SS/ Added missed events to TZSQLProcessor (Thanks to Josef Fuchs).
  • /SS/ Added support for LONGTEXT field type in MySQL driver.

13.3. Release 6.0.12 Patch #1 - 28 September 2003

  • /SS/ Fixed Bug#793351 access violation when assigning a field value
  • /JF/ Fixed Bug#791101 Transaction not working with MS SQL
  • /JF/ Fixed Bug#791096 “List index out of bounds” problem when canceling a newly added row.
  • /SS/ Fixed Bug#798336 Not passing large objects to Postgres DB.
  • /SS/ Fixed Bug#799863 Cannot see YEAR type in Delphi.

13.4. Release 6.0.12 - 18 July 2003

  • /SS/ Fixed Bug#773400. In plain interface for MySQL 4.0 the name of shared library was 'libmysqld.so' instead of 'libmysqlclient.so'
  • /SS/ Fixed Bug#772926 with incorrect TZDataset.Cancel behaviour.
  • /SS/ Fixed out of range exception in TZDataset.Last method.
  • /SS/ Fixed problem with incorrect order of dataset input parameters.
  • /JF/ Refresh problem solved
  • /SM/ Fixed Bug#768163 with unsigned int fields in MySQL

13.5. Release 6.0.11 - 08 July 2003

  • /SS/ Eliminated all overrided methods in API, fixed support for C++ Builder 4,5,6 compilers.
  • /SS/ Added optimization to TZAbstractDODataset.ExecSQL and TZEmulatedPreparedStatement. Now executing prepared statements without parameters about 10 times faster, with parameters - 25% faster.
  • /SS/ Fixed TZConnection.AutoCommit and TZConnection.TransactIsolationLevel property behavior.
  • /JF/ LoginPrompt support added. Delphi4 and Delphi5 needs some extra work.
  • /SM/ Fixed Bug #759184 empty string field return by SQL query with concatination fields
  • /SM/ Fixed Bug #707337 emty values for virtual columns
  • /SS/ Added support for quoted parameters in TZQuery and TZUpdateSQL.
  • /SS/ Fixed Bug#771217 caused by incorrect processing MySQL table names with special characters like 'my-table'
  • /SS/ Fixed Bug#773022: wrong TQuery.RecordCount after deletes
  • /SS/ Changed processing of “0000-00-00” dates in MySQL. Now they are treated as NULLs simular to ODBC drivers.

13.6. Release 6.0.10 - 13 June 2003

  • /SS/ Fixed Bug#752603 in TZDataset.GetFieldData method which set Field.IsNull = True all the time.
  • /SS/ Fixed Bug#753397: in bounds checking in TZCollection.SetCapacity which followed to Access Violation in Delphi 4.
  • /SM/ Finished scripts build & test environment
  • /SM/ Added Kylix2 support
  • /SM/ Fixed test framework and tests for Kylix/Linux support
  • /SS/ Fixed remaining issues with Delphi 4 and 5 compilers. The testing libraries for Delphi 4,5 are work as expected.
  • /SM/ Fixed Interbase datetime parameters
  • /JF/ Fixed varbinary datatype. It will be a blob field.
  • /SS/ Fixed bug#750912: Interbase Lookup fields.
  • /SM/ Fixed bug#754009: Cast error while fetching
  • /SM/ Added Firebird 1.5 support
  • /SM/ Fixed leak memory in GetBlob method for MySQL & PostgreSql
  • /SS/ Added support for MySQL 4.0 native client
  • /SS/ Fixed Bug#761300 Memory leak in TZReadOnlyQuery
  • /JF/ The TDataset's default Translate method is overriden in order to provide basic OEM/ANSI translation, but later it should be database specific.
  • /JF/ The previous one is removed because it caused more problems than it solved.

13.7. Release 6.0.9 - 18 May 2003

  • /SS/ Fixed bugs in TZCollection class and TZAbstractObject.Equals (Thanks for Karl Waclawek).
  • /SS/ Fixed Bug#733209 with incorrect decimal separator in TZToken.GetString. (Thanks to Leonardo Quaggiotto).
  • /SS/ Added support for MySQL boolean type /enum('Y','N')/
  • /SS/ Fixed Bug#726788 with mixed identificators in MySQL (Thanks to Maarten Bremer).
  • /SS/ Fixed bug in numeric tokenizer. Combinations of symbols '.e' and '.E' were always processed as numbers. For example: a.eq_id was tokenized as 'a' '.e' 'q_id' instead 'a' '.' 'eq_id'
  • /SM/ Added support Interbase 5, 6.X, Firebird 1.X
  • /SM/ GetImportedKeys, GetExportedKeys, GetIndexInfo done for Interbase Database Metadata
  • /SS/ Fixed Bug#740144 with search by Null fields in TZQuery.Locate
  • /SS/ Fixed Bug#740899. Expressions Field=NULL were not properly converted into Field IS NULL in where clauses.
  • /SS/ Completely rewritten SQL parsers because of peformance reasons.
  • /SS/ Fixed Bug#739514 with national string convertion for postgresql.
  • /JF/ Fixed Bug#728955 multiple results returned
  • /JF/ Fixed datatype handling in metadata getColumn to match the modifications via Seroukhov
  • /SS/ Fixed Bug#746225 with updating empty Memo fields.
  • /SM/ Fixed Interbase metadata GetPrimaryKeys, GetProcedures, GetProcedureColumns
  • /SS/ Fixed Bug#739448 with duplicated column names. Now if query returns columns: 'fld','fld','fld', result set will contain display labels 'fld','fld_1','fld_2'
  • /SS/ Fixed Bug#733236 with time fields convertion in TDataset.Locate.
  • /SS/ Optimized code, added DISABLE_CHECKING compiler definition into Zeos.inc file. According performance tests this definition gives about 10% speedup.
  • /SM/ Fixed problem with WasNull in fetch processing in InterbaseResultSet.
  • /SM/ Added example - controls.
  • /SS/ Fixed Bug#725053 with empty lookup fields
  • /SS/ Fixed Bug#739707: Variant convertion error in IZPreparedStatement.SetBlob
  • /JF/ Fixed Numeric scale errors in sybase, was caused by usage of float type instead of double
  • /JF/ Added a workaround for a bug? in mssql dblib interface. All text like '\'#13 was replaced to just #13. I just double the backslash in this case.

13.8. Release 6.0.8 - 15 April 2003

  • /SS/ Fixed Bug#722651 AV in TZDbcMySQLResultSet.GetTimestamp
  • /SS/ Added caching for Server version and data types in PostgreSQL connection.
  • /RFC/ Added packages for Kylix 1 and Kylix 3.

13.9. Release 6.0.7 - 13 April 2003

  • /SS/ Fixed Bug#706278 related to performance problems in MySQL
  • /SS/ Fixed Bug#715099 in TZAbstractRODataset.FindNext
  • /SS/ Added select parser for PostgreSQL
  • /SS/ Added generic support for case sensitive catalogs, tables and columns
  • /SS/ Fixed Bug#720785 in CachedResultSet error handling.
  • /SS/ Fixed Bug#720787 in SQL parser performance
  • /SS/ Added GetPChar/SetPChar methods to prevent multiple strings convertion
  • /SS/ Added performance optimization into PreparedStatement and GenericCacheResolver.
  • /SS/ Added packages for Kylix 1
  • /JF/ Fixed MS SQL and Sybase quotation problems
  • /JF/ Fixed FindColumn to properly support case sensitive and case insensitive columns

13.10. Release 6.0.6 - 30 March 2003

  • /SS/ Fixed AV in Dataset.GetFieldData method.
  • /SS/ Set default port for MySQL
  • /SS/ Fixed Bug#707339 caused by incorrect mapping for boolean type.
  • /SS/ Fixed Bug#707337 in PostgreSQL calculated columns.
  • /SS/ Fixed Bug#707364 AV in TZSQLProcessor when exception happens
  • /JF/ Optimized blob handling internally
  • /SS/ Added SetCachedUpdates method to permit changes after query open.
  • /SS/ Added BeforeRefresh and AfterRefresh events in Query components.
  • /SS/ Added useresult connection parameter for MySQL
  • /SS/ Made several fixes for PostgreSQL blobs.
  • /DD/ Added packages for C++ Builder 6.

13.11. Release 6.0.5 - 18 March 2003

  • /SS/ Modified transaction support for MySQL (Thanks to Pavel Shibanov).
  • /SS/ Added GetSupportedProtocols method to IZDriver
  • /SS/ Added packages for C++ Builder 4,5
  • /SS/ Fixed Access Violation in MySQL.GetColumns
  • /SS/ Fixed behavior of TZDataset.Last method.
  • /SM/ Added scripts for build & test environment, restructured project packages
  • /SS/ Added a property editor for ZConnection.Protocol
  • /SS/ Added 'oidasblob' connection parameter to PostgreSQL when oidasblob=false (default) Oid fields are treated as integer and bytea fields as Blobs. When oidasblob=true Oid fields represent Blobs and bytea fields are ByteArray[256].
  • /SS/ Added classes for Bug Report Test Cases
  • /SS/ Fixed bug#702368 "... wrong size ..." when column in bytea datatype.
  • /SM/ Fixed PostgreSQLToSQLType for PostgreSQL timestamptz datatype
  • /SS/ Fixed ArrayOutOfBounds exception in TZReadOnlyDataSet.Reread
  • /SS/ Fixed refreshing FieldDefs after SQL query update.

13.12. Release 6.0.4 - 24 February 2003

  • /SS/ Added a reference implementation for Plain API multiversion support. It includes TZNativeLibraryLoader, IZPlainDriver, IZMySQLPlainDriver and other classes and interfaces.
  • /SS/ Fixed SetTransactionIsolation for MySQL and PostgreSQL.
  • /SS/ Fixed MaxRows in CachedResultSet, MySQLResultSet and PostgreSQLResultSet.
  • /JF/ Modified SetTransactionIsolation for MsSql and Sybase
  • /SS/ Renamed ZUpdateSql into ZSqlUpdate and ZBlobStream into ZStreamBlob to prevent conflicts with an older zeos version.
  • /SS/ Modified PostgreSQL DBC API to use plain drivers.
  • /SS/ Added ErrorCode to EZSQLException
  • /SS/ Added ZSqlScript component

13.13. Release 6.0.3 - 17 February 2003

  • /JF/ Fixed problem with queries using parameters with the same name
  • /SS/ Implemented persistence for SQL Params in TZDataset and TZUpdateSQL.
  • /SS/ Added DesignTime test application.
  • /SS/ Implemented restoring SQL Params values after SQL query updates.

13.14. Release 6.0.2 - 9 February 2003

  • /SS/ Updated project examples
  • /SS/ Implemented reading FieldDefs on closed dataset. This feature is required to work with dataset columns in visual designer.
  • /SS/ Implemented writing PostgreSql blobs.
  • /SS/ Fixed three interface cycle references in Parse API which followed to massive memory leaks (Many thanks to Vincent Mahon, the author of MemCheck utility!)
  • /SM/ Added testing framework classes
  • /SS/ Fixed three interface cycle references in DBC API.
  • /SS/ Changed AbstractDatabaseMetadata and MySQLDatabaseMetadata classes to reduce repeatable code.

13.15. Release 6.0.1 - 2 February 2003

  • /SS/ Fixed date, time and datetime columns handling
  • /SS/ Implemented support primary keys in autogenerated where clauses
  • /SS/ Fixed problems with delete and insert in cached updates mode
  • /SS/ Added synchronization between TZConnection and TZDataset components
  • /SM/ Added icons and registration for non-visual components
  • /JF/ Made numerious changes in MS SQL connectivity API

13.16. Release 6.0.0 - 25 January 2003

  • Released the first alpha version with support for MySQL, PostgreSQL, Interbase 6+ and MS SQL.
(c) 1999 - 2006 The Zeos Development Group
================================================ FILE: lib/zeosdbo/doc/html/ede.css ================================================ /* >e-novative> DocBook Environment (eDE) */ /* (c) 2002 e-novative GmbH, Munich, Germany */ /* http://www.e-novative.de */ /* eDE Cascading Stylesheet for articles */ /* This file is part of eDE */ /* eDE is free software; you can redistribute it and/or modify */ /* it under the terms of the GNU General Public License as published by */ /* the Free Software Foundation; either version 2 of the License, or */ /* (at your option) any later version. */ /* eDE is distributed in the hope that it will be useful, */ /* but WITHOUT ANY WARRANTY; without even the implied warranty of */ /* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the */ /* GNU General Public License for more details. */ /* You should have received a copy of the GNU General Public License */ /* along with eDe; if not, write to the Free Software */ /* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* This CSS Stylesheet is used to format HTML articles generated by eDE. */ /* Note that due to different browser interpretation of the standards, the */ /* HTML pages still do not look exactly the same on every browser and system */ /* You should not modify this file directly (though you can), because */ /* any modifications to this file will be lost when you upgrade eDE. */ /* Instead, copy this file to article.css, then make your modifications. */ /* If a custom stylesheet article.css is present, eDE will use it. */ /* You can create a document-specific CSS stylesheet by creating a file named */ /* document_[document name].css, replacing [document_name] with the name of */ /* the eDE document you want to use the stylesheet for. */ /* You should never modify the CSS stylesheet in the output directory, since */ /* your changes would be overwritten when you transform the document again. */ /* eDE prefers document-specific stylesheets over custom stylesheets and */ /* custom stylesheets over the default e-novative stylesheet. */ /* Note that all CSS stylesheets will be named ede.css on deployment. */ /* Basic Settings: */ body { /* white background */ background-color: #fff; /* black foreground */ color: #000; /* center the body content in browser window */ margin: auto; /* padding ("inner margin") leaves space between */ /* browser window border and html body content */ padding: 24px; /* set width according to browser window width */ width: auto; /* text alignment */ text-align: justify; /* text-align: left; */ } /* sect1 heading */ h2 { /* list of fonts provides fallbacks if a font is not present */ font-family: Verdana, Arial, Helvetica, Sans-Serif; /* font size, relative to body font size */ font-size: 125%; /* bold face, higher number is more bold */ font-weight: 600; /* underlined text */ text-decoration: none; /* foreground color: dark blue */ color: #009; /* background color: gray */ background-color: #ddd; /* margin settings are top - right - bottom - left (think clockwise) */ margin: 15px 0 15px 0; /* padding ("inner margin") settings are top - right - bottom - left */ /* (think clockwise) */ padding: 12px 15px 12px 15px; } /* para */ p { /* font size, line height, font */ /* list of fonts provides fallbacks if a font is not present */ font: 12px/18px Verdana, Arial, Helvetica, Sans-Serif; /* margin (top - right - bottom - left) */ margin: 0 15px 6px 15px; } /* NEEDS TO BE CLEARED UP */ p, td, li, dt, dd { /* font size, line height, font */ /* list of fonts provides fallbacks if a font is not present */ font: 12px/18px Verdana, Arial, Helvetica, Sans-Serif; } /* set font for most elements */ /* p: paragraphs (regular text, docbook ) */ /* (...) */ /* body: anything else */ body, p, td, li, dt, dd, { /* set font size and line height */ /* list of fonts provides fallbacks if a font is not present */ font: 12px/18px Verdana, Arial, Helvetica, Sans-Serif; } /* images */ /* docbook: */ img { /* no margin */ margin: 0; /* no padding ("inner margin") */ padding: 0; /* no border */ border: 0; } /* emphasized text, can occur in most places */ /* docbook: */ em { /* bold face, higher number is more bold */ font-weight: 600; /* italic */ font-style: italic; } /* sect(ion)1 title */ h2 { /* list of fonts provides fallbacks if a font is not present */ font-family: Verdana, Arial, Helvetica, Sans-Serif; /* font size, relative to body font size */ font-size: 125%; /* bold face, higher number is more bold */ font-weight: 600; /* underlined text */ text-decoration: none; /* foreground color: dark blue */ color: #009; /* background color: gray */ background-color: #ddd; /* margin settings are top - right - bottom - left (think clockwise) */ margin: 15px 0 15px 0; /* padding ("inner margin") settings are top - right - bottom - left */ /* (think clockwise) */ padding: 12px 15px 12px 15px; } /* sect(ion)2 title */ h3 { /* list of fonts provides fallbacks if a font is not present */ font-family: Verdana, Arial, Helvetica, Sans-Serif; /* font size, relative to body font size */ font-size: 110%; /* bold face, higher number is more bold */ font-weight: 600; /* underlined text */ text-decoration: none; /* foreground color: dark blue */ color: #009; /* background-color is a very light grey */ /* alternative: #fff = white */ background-color: #fefefe; /* padding ("inner margin") settings are top - right - bottom - left */ /* (think clockwise) */ padding: 0 0 0 15px; } /* sect(ion)3 title */ h4 { /* list of fonts provides fallbacks if a font is not present */ font-family: Verdana, Arial, Helvetica, Sans-Serif; /* font size, relative to body font size */ font-size: 100%; /* bold face, higher number is more bold */ font-weight: 600; /* underlined text */ text-decoration: none; /* foreground color: dark blue */ color: #009; /* background-color is a very light grey */ /* alternative: #fff = white */ background-color: #fefefe; /* padding ("inner margin") settings are top - right - bottom - left */ /* (think clockwise) */ padding: 0 0 0 15px; } /* sect(ion)4 title */ h5 { /* list of fonts provides fallbacks if a font is not present */ font-family: Verdana, Arial, Helvetica, Sans-Serif; /* font size, relative to body font size */ font-size: 100%; /* bold face, higher number is more bold */ font-weight: 300; /* not underlined */ text-decoration: none ; /* foreground color: dark blue */ color: #009; /* background-color is a very light grey */ /* alternative: #fff = white */ background-color: #fefefe; /* padding ("inner margin") settings are top - right - bottom - left */ /* (think clockwise) */ padding: 0 0 0 15px; } /* the following formats refer to the docbook tags of the same name */ /* for more information, see the docbook reference at */ /* http://www.docbook.org/tdg/en/html/docbook.html */ .mediaobject { /* center */ text-align: center; } /* */ .calloutlist, .figure, .table { /* margin settings are top - right - bottom - left (think clockwise) */ margin: 15px 30px 15px 30px; } /* */ .itemizedlist, .variablelist { /* margin settings are top - right - bottom - left (think clockwise) */ margin: 15px 30px 15px 15px; } /* blockquote formatting is a little more complex */ /* because block quotes are rendered as a html table */ /* blockquote block */ .blockquote { /* override bottom margin, the other margins are inherited */ margin-bottom: 30px; } .blockquote p, .blockquote td { /* set font size and line height */ /* list of fonts provides fallbacks if a font is not present */ font: 12px/18px Verdana, Arial, Helvetica, Sans-Serif; /* bold face, higher number is more bold */ font-weight: 450; } .epigraph { /* override bottom margin, the other margins are inherited */ margin-bottom: 30px; } .epigraph p, .epigraph td { /* set font size and line height */ /* list of fonts provides fallbacks if a font is not present */ font: 10px/14px Verdana, Arial, Helvetica, Sans-Serif; /* bold face, higher number is more bold */ font-weight: 600; } /* custom e-novative header and footer that are displayed on all pages */ #customheader, #customfooter { /* list of fonts provides fallbacks if a font is not present */ font-family: Verdana, Arial, Helvetica, Sans-Serif; /* font size, relative to body font size */ font-size: 80%; /* line height, relative to body font size */ line-height: 200%; text-align: center; vertical-align: middle; color: #fff; background-color: #009; } /* leave more space between last paragraph and footer */ /* some browser do not add up the bottom margin of the prior element */ /* and the top margin of the footer */ #customfooter { margin-top: 15px; } /* table { margin: 0 15px 6px 15px; } */ /* title and navigation links in header and footer */ .navheader th, .navheader td, .navfooter th, .navfooter td { font-size: 11px; font-weight: 450; } /* table of contents, list of figures and list of tables */ .toc, .list-of-figures, .list-of-tables, .list-of-examples { /* margin settings are top - right - bottom - left (think clockwise) */ margin: 15px 30px 15px 15px; } /* the "headings" are rendered as paragraphs */ .toc p, .list-of-figures p, .list-of-tables p, .list-of-examples p { /* no margin */ margin: 0; } .figure { /* margin settings are top - right - bottom - left (think clockwise) */ margin: 5px 5px 5px 5px; /* no padding ("inner border") */ padding: 0; /* no border */ border: 0; /* center text */ text-align: center; } /* figure title */ .figure p, .table p, .example p { font-size: 80%; } /* acronym { border-bottom: 1px dashed #00cc00; cursor: help; } */ /* admonition headings */ div.note, div.important, div.warning, div.caution, div.tip { padding: 0px 15px 0px 0px; } div.note th, div.important th, div.warning th, div.caution th, div.tip th { /* set font size and line height */ /* list of fonts provides fallbacks if a font is not present */ font: 12px/18px Verdana, Arial, Helvetica, Sans-Serif; font-weight: 600; text-decoration: underline; /* left align */ text-align: left; } .note p, .important p, .warning p, .caution p, .tip p { margin: 0; } .note img, .important img, .warning img, .caution img, .tip img { margin: 0px 15px 0px 15px; } /* programlisting */ pre.programlisting { /* non-proportional font */ /* list of fonts provides fallbacks if a font is not present */ font-family: "Courier New", Courier, Monospace; /* color: black */ color: #000; /* background color: gray */ background-color: #eee; /* no margin */ margin: 0; /* gray dotted border, 1 px wide */ border: 1px dotted #ddd; /* padding ("inner margin") settings are top - right - bottom - left */ /* (think clockwise) */ padding: 6px 6px 6px 6px; } /* title page */ /* heading1 is used for document title */ h1 { /* list of fonts provides fallbacks if a font is not present */ font-family: Verdana, Arial, Helvetica, Sans-Serif; /* font size, relative to body font size */ font-size: 150%; /* bold face, higher number is more bold */ font-weight: 600; /* line height, relative to body line height */ line-height: 250%; /* center */ text-align: center; /* foreground color: dark blue */ color: #009; /* background color: gray */ background-color: #ddd; /* margin settings are top - right - bottom - left (think clockwise) */ margin: 15px 0 15px 0; /* no padding ("inner margin") */ padding: 0; } /* author on title page is formatted as h3 */ /* these settings overwrite the regular h3 settings */ h3.author { /* set font size and line height */ /* list of fonts provides fallbacks in case selected fonts are not present */ font: 12px/18px Verdana, Arial, Helvetica, Sans-Serif; /* bold face, higher number is more bold */ font-weight: 600; /* do not underline */ text-decoration: none; /* center text */ text-align: center; /* color: black */ color: #000; /* background-color is a very light grey */ /* alternative: #fff = white */ background-color: #fefefe; /* margin settings are top - right - bottom - left (think clockwise) */ margin: 0 15px 15px 15px; /* no padding */ padding: 0; /* no border */ border: 0; } /* copyright and date */ .copyright, .pubdate { /* list of fonts provides fallbacks if a font is not present */ font-family: Verdana, Arial, Helvetica, Sans-Serif; /* font size, relative to body font size */ font-size: 90%; /* center */ text-align: center; /* margin settings are top - right - bottom - left (think clockwise) */ margin: 15px 15px 15px 15px; /* no padding ("inner margin") */ padding: 0; /* no border */ border: 0; } /* legal notice box */ div.legalnotice { /* list of fonts provides fallbacks if a font is not present */ font-family: Verdana, Arial, Helvetica, Sans-Serif; /* font size, relative to body font size */ font-size: 90%; /* color: black */ color: #000; /* background color: gray */ background-color: #ddd; /* margin settings are top - right - bottom - left (think clockwise) */ margin: 10px 45px 10px 45px; /* padding ("inner margin") settings are top - right - bottom - left */ /* (think clockwise) */ padding: 5px 5px 5px 5px; /* solid black border, 1px wide */ border: 1px solid #000; } ================================================ FILE: lib/zeosdbo/doc/html/installation.html ================================================ ZeosDBO Installation Guide
ZeosLib - open source tools for your database solutions

ZeosDBO Installation Guide

ZeosLib Development Group

28 May 2008 (Updated 29/5/2008)


You can download the current (SVN) version from svn://www.firmos.at/zeos/trunk/

The development/testing branch is at svn://www.firmos.at/zeos/branches/testing/

Snapshots can be found at http://zeosdownloads.firmos.at/downloads/snapshots/

Official reaseses are published at the Zeoslib forum and the Zeoslib Sourceforge Project pages

  1. Unpack the archive to a folder (not for SVN versions, of course)

  2. Copy the required dlls for your database client to the windows system directory (usually Windows\System or winnt\system32) or use the database client installer.

    Attention : think about licence issues when working with the database client libraries. Not all software is freely distributable in all situations. These libraries are NOT a part of the zeoslib packages.
  3. Add the build Directory of the package you are about to install to Delphi's library path.

  4. Locate the package directory associated with your compiler and open the ZeosDbo.bpg project group. Load the project and compile the following components in the order listed (or just choose compile all from Project-Menu):

    • ZCore.bpl
    • ZParseSql.bpl
    • ZPlain.bpl
    • ZDbc.bpl
    • ZComponent.bpl

  5. If all the packages, listed above are successfully compiled you have to install the ZComponentDesign.bpl. After that all ZEOS components are available in the IDE.

    If the ZComponentDesign.bpl package isn't available for your compiler (eg. for fpc/lazarus), you should just install the ZComponent.bpl
  6. Create your own project and start adding the compoents through the IDE and set connection properties. For a quick tutorial, use the example provided with the project or browse the resources on the web page.

Observations:

  1. When installing the library under C++ Builder (any version) it is highly recommended to remove any previously installed version of ZEOSDBO.

    To do that you should first close C++ Builder (as some of these files may be locked) and remove the (ZCore|ZParseSql|ZPlain|Zdbc|ZComponent)(.bpl|.tds|.bpi|.lib) files from $(BCB)\Projects\Lib and $(BCB)\Projects\Bpl (where $(BCB) is something like C:\Program Files\Borland\CBuilder[4-6]).

  2. When compiling the library from ZeosDbo.bpg under C++ Builder you may receive some warnings like 'Unable to find package import XXX.bpi' and you may have to press Cancel multiple times to continue.

    We're trying to get rid of this annoying behaviour, but until then here are some possible ways to avoid it, if needed:

    1. Open, compile and install the packages (*.bpk) in the appropriate order (see Installation step #3) - i.e without using ZeosDbo.bpg.
    2. Open a command line in \packages\CBuilder[4-6] and do a manual make - like this: make -f ZeosDbo.bpg. This requires the PATH and LIB environment variables to be set properly, like this:

      SET BCB=d:\borland\cbuilder6
      
      SET PATH=%BCB%\bin
      
      SET LIB=%BCB%\lib
      Then open ZeosDbo.bpg in the IDE and install the packages the usual way.

  3. While installing ZEOSDBO under C++ Builder version 4 from the IDE, you may get this error when compiling the ZDbc package :

    [Pascal Fatal Error] ZDbcMetadata.pas(3076): Internal error: SY876.
    Currently, there is no known solution to this problem. Therefore,it is recommended to compile Zeoslib from the command line (issuing a make -f ZeosDBO.bpg from the directory /packages/cbuilder4 should accomplish this) and then to install the packages through menu Component->Install Packages.

(c) 1999 - 2006 The Zeos Development Group
================================================ FILE: lib/zeosdbo/doc/html/knownbugs.html ================================================ ZeosDBO Known Bugs
ZeosLib - open source tools for your database solutions

ZeosDBO Known Bugs

ZeosLib Development Group

23 September 2005


  1. Even if ZConnection.SQLHourGlass is set to "true" the mousepointer looks like an arrow. This is no bug of Zeos. DBScreen is not nil when using the unit DB which is used by several units of zeos, BUT is is initialized with a class-object which is not changing the cursor, the user sees (Forms. Screen.Cursor). This Object is initialized in unit DBCtrls. If you want to see the SQLHourGlass then you should add the unit DBCtrls to your uses-clause.
  2. Error while saving date using ADO and MSSQL Server. If a date has to be stored having a day less then 13, then it will be stored changing day with month (see: http://support.microsoft.com/default.aspx?scid=kb;en-us;327579).
  3. ADO (with MSAccess) returns smallInt instead of boolean type. This is the "normal" behaiviour of ADO. (Tested and approved with a TADODataSet and this also created a TSmallIntField).
  4. SQLHourGlass is never shown. Cursor is initialized in unit DBCtrls. If you want to see the SQLHourGlass then you have to add the unit DBCtrls to the uses-clause.
  5. RequestLive (since V 6.5.2 renamed to ReadOnly), CachedUpdates and UpdateObject are processed by ZeosDBO Query differently from standard TQuery. In ZeosDBO there is no correlation between them as it done in VCL. If your query is alive you must set RequestLive=true doesn't matter have you set CachedUpdates+UpdateObject or not. Otherwise, if RequestLive=false your query will be always read-only. UpdateObject can be used in non-cached mode as well as in cached mode.
  6. Because of the limitations of dblibrary only the first 255 char is returned for char and varchar columns.
  7. LargeInt fields are not completely supported in Delphi 4,5 and C++ Builder 4,5.
  8. Sybase does not support procedure parameter type query. Though a workaround was possible for ASE12.5 and above.
  9. Oracle provider for ADO is case sensitive for the table name when getting schema columns, the MS version is working right. Identifier convertion must be reviewed for ADO.
  10. If you are using dbgrid, all the records will be fetched because of a call to recordcount (in scrollbar). You can avoid this behavior if you turn on the Filtered property. In this case you can achieve fast open even on bigger resultsets.
(c) 1999 - 2006 The Zeos Development Group
================================================ FILE: lib/zeosdbo/doc/html/license.html ================================================ GNU LESSER GENERAL PUBLIC LICENSE
ZeosLib - open source tools for your database solutions

GNU LESSER GENERAL PUBLIC LICENSE


Copyright (C) 1991, 1999 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.

[This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.]

1. Preamble

The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users.

This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below.

When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things.

To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it.

For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights.

We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library.

To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others.

Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license.

Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs.

When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library.

We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances.

For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License.

In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system.

Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library.

The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run.

2. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you".

A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables.

The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".)

"Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library.

Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does.

1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library.

You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.

2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:

a) The modified work must itself be a software library.

b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change.

c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License.

d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful.

(For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.)

These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.

Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library.

In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.

3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices.

Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy.

This option is useful when you wish to copy part of the code of the Library into a program that is not a library.

4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange.

If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code.

5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License.

However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables.

When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law.

If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.)

Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself.

6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications.

You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things:

a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.)

b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with.

c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution.

d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place.

e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy.

For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.

It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute.

7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things:

a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above.

b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work.

8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.

9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it.

10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License.

11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library.

If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances.

It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.

This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.

12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.

13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.

Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation.

14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.

3. NO WARRANTY

15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

4. END OF TERMS AND CONDITIONS

5. How to Apply These Terms to Your New Libraries

If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License).

To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.

<one line to give the library's name and a brief idea of what it does.> Copyright (C) <year> <name of author>

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

Also add information on how to contact you by electronic and paper mail.

You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names:

Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker.

<signature of Ty Coon>, 1 April 1990 Ty Coon, President of Vice

That's all there is to it!

(c) 1999 - 2006 The Zeos Development Group
================================================ FILE: lib/zeosdbo/doc/html/overview.html ================================================ Overview of the Zeos Database Objects Architecture
ZeosLib - open source tools for your database solutions

Overview of the Zeos Database Objects Architecture

Sergey Seroukhov

Merlin Moncure

26 November 2003 (Updated 29/5/2008 by Mark Daems)


Direct access to SQL databases continues to be a vital technology even in today's enterprise environment. Thousands of two-tier client server applications are developed and maintained in the international business community. Most of them are built off of specially designed application programming interfaces (APIs) to retrieve relational data and execute SQL statements.

Currently, there is several standardized and widely used APIs to access SQL databases, such as ODBC, JDBC, and ADO. Borland also released their proprietary database middleware interface for its development tools, called the Borland Database Engine (BDE). Despite being freely distributed with Borland's popular line of application development tools, the BDE was unpopular because of complexities in installation and poor performance. As Delphi became one of the leading application development tools for the Windows platform, individuals and companies proposed alternative interfaces to the BDE. These “BDE Alternatives” optimized access to the database by directly using the native database driver, providing performance and feature advantages with respect to the BDE.

Realizing the limitations of the BDE, Borland proposed a new type of database interface called dbExpress. This interface was designed to broker access between Delphi and virtually any relational database through 3rd party drivers. Borland significantly improved the performance of dbExpress with respect to the BDE, but the implementation was buggy and supported only a limited subset of SQL that hampered functionality.

The Zeos Database Object component library (ZeosLib) is one of the best-known BDE alternatives. Originally the library was developed for MySQL and PostgreSQL databases, but support for other vendors was soon added. During the development process, certain limitations of the original design became more and more apparent. These limitations began to put a strain on the overall architecture and the development team decided a ground up rewrite was the best way to proceed. The new design was built to handle an extended feature list with several new requirements:

  1. Support for different compilers
  2. Versioning database driver system
  3. Database Insensitive” design for cross-database development
  4. Support for multiple high level interfaces (TDataset, dbExpress, Midas)
  5. Extensible feature system for server specific support

1. General Overview

To address multiple and sometimes inconsistent requirements the development team had to completely rethink the new architecture. It is complex with respect to previous designs but not over-designed. Each module put into the new design was carefully considered and carries special unique features. In this article we'll try to present you the new architecture and explain its purpose.

From a top-down view the library is separated into three logical layers:

  1. Plain API Layer
  2. Database Connectivity Layer
  3. Component Layer

The Plain API implements low-level functions specific to each SQL server. The Component API encapsulates the main library interface that is utilized by application developers. The DBC API is the middleware that retrieves, stores and modifies data for the high level components.

Each layer has several horizontal and/or vertical sub-layers semi-independently from each other (see picture 1). Let's go through each layer and look how all that works.

2. Plain API Layer

ZeosDBO components do not communicate directly with SQL servers. Instead they use native client libraries provided with SQL databases. The Plain API layer provides an access to functions of native client libraries, constants and data structures (usually written in plain C) from the Object Pascal language or C++.

That functionality was the original basis for ZeosDBO. Support for multiple versions of client libraries and SQL servers was the main deficiency of earlier designs...

Native library calls (dynamic libraries in Windows and shared libraries in Unix) are represented in programming language as regular functions. For example:

ZPlainMySql323.pas:

function mysql_init(Handle: PMYSQL): PMYSQL; external 'libmysql.dll';

Usually database APIs do not significantly change between versions. But because function calls do not allow polymorphism adding support for new versions of the Plain API is coding intensive. Hard coded approaches are inflexible and error-prone, which limit long term feasibility.

if Version = 'mysql-3.23' then
  ZPlainMySql323.mysql_init(...)
else ZPlainMySql40.mysql_init(...);

To implement polymorphism, simplify source code, and provide insulation from changes in SQL server protocols a new extremely thin interface layer was added into ZeosDBO. That layer is called “Plain Drivers” and implemented as follows:

// Generic MySQL driver interface
IZMySQLDriver = interface ...
  function mysql_init(...)
end;

// MySQL driver for version 3.23
TZMySQL323Driver = class (TInterfacedObject, IZMySQLDriver)
  function mysql_init(...)
end;

// MySQL driver for version 4.0
TZMySQL40Driver = class (TInterfacedObject, IZMySQLDriver)
  function mysql_init(...)
end;

function TZMySQL323Driver.mysql_init(...)
begin
  Result := ZPlainMySql323.mysql_init(...);
end;

function TZMySQL40Driver.mysql_init(...)
begin
  Result := ZPlainMySql40.mysql_init(...);
end;

Using such thin class wrapper allows easy addition of new client interfaces. The specific functionality that requires overriding is encapsulated in the Plain driver. The rest of the code now has a uniform method of providing native database calls, without requiring specific knowledge about the database server.

// Initialize plain driver
PlainDriver: IZMySqlDriver;

if Version = 'mysql-3.23' then
  PlainDriver := TZMySQL323Driver.Create()
else PlainDriver := TZMySQL40Driver.Create();

// Use plain driver
PlainDriver.mysql_init(...)

With this approach it is possible to use the same API for different SQL servers, independently of version.

3. Database Connectivity Layer

With native access provided to the database, Delphi database aware components can now expect database specific functionality in a uniform manner. However, each SQL server has different semantics that must be designed into the components to provide a universal generic interface. The main goal of the Zeos Database Objects is to provide this generic interface to the application developer.

In older versions of ZeosDBO, the intermediate interface was implemented as a class wrapper to the MySQL and PostgreSQL connection objects. These two databases have very similar capabilities so design of intermediate API was not complex. However, support for other SQL servers added new and very specific features. After several extensions to support these features the class architecture became was not clearly defined. Ultimately, the interface broke its encapsulation rules and the high level components were forced to make low level database calls.

To overcome this difficulty in the new version, the overall design was an abstract approach with an intermediate interface. Design of such an interface is not trivial. So to avoid new mistakes it was decided to avoid a proprietary design, and instead draw inspiration from a well-known database API.

As a prototype for the intermediate interface the development team chose JDBC 2.0. JDBC is one of the latest and more popular APIs in that database community. It covers various abstractions such as statements, result sets, stored procedures, blobs, and very rich metadata definitions.

JDBC API is implemented in Java through set of interfaces. Borland compilers support interfaces, so porting JDBC from Java to Object Pascal was straightforward. Data types and method names were generally preserved. Overloaded methods were avoided because of poor support in the C++ Builder family of compilers.

The main DBC interfaces are presented on picture 2.

Standard JDBC interfaces provide a uniform client API. To address functionality specific to different SQL servers, two general approaches were chosen.

1. Developers may initialize database connection object with list of string parameters. Each parameter switches server specific settings. For JDBC that method is not new.

Example: parameters can be defined in Connection URL -

zdbc:mysql://localhost/database?compress=true
or parameters can be passed to connection factory method
Params.Values['compress'] := 'true';
Connection := DriverManager.CreateConnectionWithParams(Url, Params);

Additionally in ZeosDBO developers extended other DBC interfaces to initialize other object with specific parameters, particularly Statement object:

Params.Values['oidasblod'] := 'true';
Statement := Connection.CreateStatementWithParams(Params);

2. In Object Pascal each class is able to implement multiple interfaces simultaneously. We used that to extend standard JDBC interfaces with new methods specific for each particular SQL server. Now each class known not only a standard interface but a server specific interface as well:

IZMySQLConnection = interface (IZConnection)
  function Ping(...);
  function Kill(..);
end;

TZMySQLConnection = class (TInterfacedObject, IZConnection, IZMySQLConnection);
...
end;

The next step in porting JDBC to Object Pascal was an implementation of cached data access. Actually, many servers provide support for sequential data access only. Caching data on the client side is the important element to implement random data access for the retrieved result sets. On the other hand, many high-level database interfaces use even more sophisticated caching algorithms. So implementation of universal caching algorithms in one place can be a compact and efficient solution.

Cached DBC layer has only few classes:

  1. TZRowAccessor - organize storage and access to fields of one single cached record in result set (pattern Flyweight).
  2. TZCachedResultSet - is a cached result set with random data access. It works on the top of another native non-cached result set with sequencial data access (pattern Decorator).
  3. IZCachedResolver - is an interface to handle special logic to post modified data back to SQL server (pattern Delegator).

The good thing about DBC interfaces that they are so generic, that additionally to regular SQL drivers it's easy to implement special adapters to other database interfaces such as Active Data Objects (ADO) for example.

DBC interfaces are generic, so providing support for additional databases or connectivity layers such as ADO is trivial.

4. Component Layer

The last top layer in ZeosDBO library implements dbware components. These components are used for development in Delphi, C++ Builder or Kylix. Currently Borland compilers support several standards for dbware components:

  1. TDataset descendent components
  2. DbExpress drivers
  3. Data providers for multi-tier Midas technology

At the time of this writing this article ZeosDBO library only supported TDataset descendent components. Implementation of other component types is scheduled for future versions.

The component class diagram is presented on picture 3:

  1. TZAbstractRODataset, TZAbstractDataset, TZAbstractStoredProc - abstract classes for TDataset descendant components
  2. TZReadOnlyQuery, TZQuery, TZStoredProc - universal TDataset descendant components
  3. TZReadOnlyXXSQLQuery, TZXXSQLQuery, TZXXSQLStoredProc - TDatasets specific for each supported SQL server. The way how they are propagating server specific functions is described in the previous chapter about DBC Layer.
  4. TZSQLMonitor, TZUpdateSQL, TZSQLProcessor - generic auxiliary components

TDataset uses maximum the DBC layer functionality to read, modify and store data. Additionally it implements extra functions to filter, search and sort data, connect to visual components and many other things.

5. Epilog

In this article we described the main ideas of the new architecture of Zeos Database Objects component library for native database access. This architecture was introduced in version 6.0 and demonstrated high flexibility and effectiveness. In version 6.1 the code was seriously revised and optimized, but the main principles of the architecture was not changed.

Functionality and flexibility incorporated in the architecture will meet adapt to new requirements in the future. Support for new SQL servers will be added as well as access to SQL specific functionality and support for other high level interfaces like dbExpress and Midas.

To familiarize with the library you may visit the project website at http://zeos.firmos.at or the development page on SourceForge athttp://www.sourceforge.net/projects/zeoslib

(c) 1999 - 2006 The Zeos Development Group
================================================ FILE: lib/zeosdbo/doc/html/parameters.html ================================================ ZeosDBO SQL Specific Parameters
ZeosLib - open source tools for your database solutions

ZeosDBO SQL Specific Parameters

ZeosLib Development Group

05 November 2003 (Updated 29/5/2008)


1. Project options

1.1. Conditional Defines

It is possible to avoid databasedrivers are compiled into your program executable if you're not planning to support the use of them. You can do this by commenting out the ENABLE_XXXX DEFINES in zeos.inc before compiling and installing zeoslib.

A more flexible way is to install zeoslib using the standard zeos.inc file and add some conditional DEFINE's to your project options. Supported values are:

  • ZEOS_DISABLE_MYSQL
  • ZEOS_DISABLE_ORACLE
  • ZEOS_DISABLE_SQLITE
  • ZEOS_DISABLE_ASA
  • ZEOS_DISABLE_INTERBASE
  • ZEOS_DISABLE_DBLIB
  • ZEOS_DISABLE_POSTGRESQL
  • ZEOS_DISABLE_ADO
To use this feature you must add the zeoslib source dir's to the search path of your project. So only the required features will be compiled in your project executable. (Make sure the zeoslib units are recompiled as well)

2. Generic Parameters

2.1. Connection parameters

  • defaults=[yes,no] - Calculate default values for NULL fields.

2.2. ZQuery parameters

  • defaults=[yes,no] - Calculate default values for NULL fields.

  • ValidateUpdateCount=[true,false] - Check if automatically generated updates of ZUpdateSQL updates only affect 1 record.

3. MySQL Driver Parameters

3.1. Connection parameters

  • compress=[yes,no] - Turn on/off compression protocol

  • dbless=[yes,no] - Connect to the real database or not (dbless mode)

  • useresult=[yes,no] - Fetching rows using UseResult instead StoreResult.

  • timeout=<seconds> - Connection timeout in seconds.

  • codepage=<client codepage> - Sets a client codepage. It executes a SET CHARACTER SET <client codepage> statement righ after connect. Refer your MySQL server manual for details.

  • all mysql_real_connect clientflags are now supported using the names from the enum type below. (Eg. CLIENT_MULTI_STATEMENTS=TRUE) :

    TMYSQL_CLIENT_OPTIONS =
    ( CLIENT_LONG_PASSWORD,	{  = 1;	  { new more secure passwords }
      CLIENT_FOUND_ROWS ,	{	  = 2;	  { Found instead of affected rows }
      CLIENT_LONG_FLAG	 ,	{ = 4;	  { Get all column flags }
      CLIENT_CONNECT_WITH_DB ,	{ = 8;	  { One can specify db on connect }
      CLIENT_NO_SCHEMA	 ,	{  = 16;	  { Don't allow database.table.column }
      CLIENT_COMPRESS	 ,	{  = 32;	  { Can use compression protcol }
      CLIENT_ODBC		 ,	{  = 64;	  { Odbc client }
      CLIENT_LOCAL_FILES	  ,	{ = 128;  { Can use LOAD DATA LOCAL }
      CLIENT_IGNORE_SPACE	 ,	{  = 256;  { Ignore spaces before '(' }
      CLIENT_CHANGE_USER    ,	{  = 512;  { Support the mysql_change_user() }
      CLIENT_INTERACTIVE    ,	{  = 1024; { This is an interactive client }
      CLIENT_SSL     ,	{         = 2048; { Switch to SSL after handshake }
      CLIENT_IGNORE_SIGPIPE  ,	{ = 4096; { IGNORE sigpipes }
      CLIENT_TRANSACTIONS    ,	{ = 8196; { Client knows about transactions }
      CLIENT_RESERVED     ,	{    = 16384; { Old flag for 4.1 protocol  }
      CLIENT_SECURE_CONNECTION  ,	{= 32768; { New 4.1 authentication }
      CLIENT_MULTI_STATEMENTS  ,	{= 65536; { Enable/disable multi-stmt support }
      CLIENT_MULTI_RESULTS  ,	{  = 131072; { Enable/disable multi-results }
      CLIENT_OPT_18,  {2^18 = 262144}
      CLIENT_OPT_19,{2^19 = 524288}
      CLIENT_OPT_20,  {2^20 = 1048576}
      CLIENT_OPT_21,   {2^21 = 2097152 }
      CLIENT_OPT_22,  {2^22 = 4194304}
      CLIENT_OPT_23,  {2^23 = 8388608 }
      CLIENT_OPT_24,   {2^24 = 16777216 }
      CLIENT_OPT_25,   {2^25 = 33554432}
      CLIENT_OPT_26,    {2^26 = 67108864}
      CLIENT_OPT_27,    {2^27 = 134217728}
      CLIENT_OPT_28,    {2^28 = 268435456}
      CLIENT_OPT_29,    {2^29 = 536870912}
      CLIENT_OPT_30,    {2^30 = 1073741824}
      CLIENT_REMEMBER_OPTIONS	{ = 2147483648; {Enable/disable multi-results });
              

  • all mysql_options are now supported using the names from the enum type below. (Eg. MYSQL_READ_DEFAULT_FILE=<filename>) :

      TMySqlOption = (
        MYSQL_OPT_CONNECT_TIMEOUT,
        MYSQL_OPT_COMPRESS,
        MYSQL_OPT_NAMED_PIPE,
        MYSQL_INIT_COMMAND,
        MYSQL_READ_DEFAULT_FILE,
        MYSQL_READ_DEFAULT_GROUP,
        MYSQL_SET_CHARSET_DIR,
        MYSQL_SET_CHARSET_NAME,
        MYSQL_OPT_LOCAL_INFILE,
        MYSQL_OPT_PROTOCOL,
        MYSQL_SHARED_MEMORY_BASE_NAME,
        MYSQL_OPT_READ_TIMEOUT,
        MYSQL_OPT_WRITE_TIMEOUT,
        MYSQL_OPT_USE_RESULT,
        MYSQL_OPT_USE_REMOTE_CONNECTION,
        MYSQL_OPT_USE_EMBEDDED_CONNECTION,
        MYSQL_OPT_GUESS_CONNECTION,
        MYSQL_SET_CLIENT_IP,
        MYSQL_SECURE_AUTH
      );
              

  • SSL connections are supported using this connection properties (using mysql_sll_set library call) :

        Properties.Strings = (
          'MYSQL_SSL=TRUE'
          'MYSQL_SSL_CA=D:/mysql/certs/ca-cert.pem'
          'MYSQL_SSL_CERT=D:/mysql/certs/client-cert.pem'
          'MYSQL_SSL_KEY=D:/mysql/certs/client-key.pem')
              

3.2. Statement parameters

  • useresult=[yes,no] - Fetching rows using UseResult instead StoreResult.

4. PostgreSQL Driver Parameters

4.1. Connection parameters

  • beginreq=[yes,no] - Is BEGIN required at the transaction start or not.

  • oidasblob=[yes,no] - Is Oid type treated as Large Object handle (blob) or as a regular integer.

  • timeout=<seconds> - Connection timeout in seconds.

  • codepage=<client codepage> - Sets a client codepage. It executes a SET CLIENT_ENCODING '<client codepage>' statement righ after connect.

  • sslmode=[disable, allow, prefer, require] - (From PostgreSQL docs:) This option determines whether or with what priority an SSL connection will be negotiated with the server. There are four modes: disable will attempt only an unencrypted SSL connection; allow will negotiate, trying first a non-SSL connection, then if that fails, trying an SSL connection; prefer (the default) will negotiate, trying first an SSL connection, then if that fails, trying a regular non-SSL connection; require will try only an SSL connection. If PostgreSQL is compiled without SSL support, using option require will cause an error, while options allow and prefer will be accepted but libpq will not in fact attempt an SSL connection.

  • requiressl=[0,1] - This option is deprecated in favor of the sslmode setting.

  • application_name=<application name> - (From PostgreSQL docs:) This option is typically set by an application upon connection to the server. The name will be displayed in the pg_stat_activity view and included in CSV log entries.

4.2. Statement parameters

  • oidasblob=[yes,no] - Is Oid type treated as Large Object handle (blob) or as a regular integer.

5. MS SQL Driver Parameters

5.1. Connection parameters

  • appname=<application name> - The given application name is sent to sqlserver.

  • workstation=<workstation name> - The given workstation name is sent to sqlserver

  • secure=[yes,no] - This means that SQL Server will use Windows Authentication security.

  • trusted=[yes,no] - This means that SQL Server will use Windows Authentication security.

  • language=<national language name> - The given language is sent to sqlserver. If language support is installed in the server, error messages are returned in the designated national language.

  • fallback=[yes,no] - Enables or disables failover support

  • timeout=<seconds> - Is the time-out value, or the number of seconds that DB-Library waits for a login response before timing out. A time-out value of 0 represents an infinite time-out period. The default time-out value is 60 seconds.

6. Interbase Driver Parameters

6.1. Connection parameters

  • codepage=<national language name> - The given language is sent to sqlserver. If language support is installed in the server, error messages are returned in the designated national language.

  • createNewDatabase=<sql command database creation> - Created new database before open database defined in TZConnection.

  • dialect=it is parameter of Interbase/Firebird sql dialect. dialect parameter is sinonim of isc_dpb_sql_dialect parameter.

  • RoleName=it is sinonim for isc_dpb_sql_role_name parameter Interbase/Firebird. It allow set user role name to work with database and to gain the privileges of that role.

  • hard_commit=[yes,no] - Use hard commits instead of soft commits.

6.2. Statement parameters

  • cursor=<cursor name> - The given cusor name is sent to sql server.

  • cashedblob=[yes,no] - This means that blob data fetch immediate if [yes] or used interbase blob if [no].

7. Oracle Driver Parameters

7.1. Connection parameters

  • codepage=[utf8,UTF8,0..max word value] - The codepage used by the oracle OCI to interprete strings sent to the server. For Lazarus this should be set to UTF8.

8. SQLite Driver Parameters

8.1. Connection parameters

  • busytimeout=<milliseconds> - Timeout before throwing an error because the database to be opened is locked

(c) 1999 - 2006 The Zeos Development Group
================================================ FILE: lib/zeosdbo/doc/html/readme.html ================================================ ZeosDBO Technical Info
ZeosLib - open source tools for your database solutions

ZeosDBO Technical Info

ZeosLib Development Group

09 July 2004 (Updated 29/5/2008)


ZeosDBO is a database middleware components for Borland development tools, including Delphi, C++ Builder and Kylix.

The following compilers are supported:

  • Delphi 5 - 7 and 9-11
  • Lazarus (FreePascal)
  • MSEide+MSEgui (FreePascal)
  • C++ Builder 5 - 6
  • Kylix 2 - 3

ZeosDBO supports direct connectivity to the following databases using the vendor provided, native interface:

  • MySQL 3.20 - 5.0
  • PostgreSQL 6.5 - 8.1
  • Firebird 1.0 - 2.0
  • Interbase 5.0 - 7.5
  • Microsoft SQL Server 7, 2000
  • Sybase ASE 12.0, 12.5
  • Oracle 9i
  • SQLite 2.8, 3.5

For other databases we propose to use implemented Active Data Objects (ADO) Bridge.

Advantages of using ZeosDBO:

  • Platform independance. The ZeosDBO is highly generic. Applications written in ZeosDBO can be migrated across databases without major changes.
  • ZeosDBO is open source, written for usability and extensibility.
  • ZeosDBO leverages the amazing power of the Delphi development environment without relying on a performance killing middleware.
  • ZeosDBO is an extremely thin abstraction layer, unlike 'thick' layered protocols like ADO and BDE.

Package contents:

  1. ZCore - Core classes and interfaces. Contains Java style objects and collections as well as compatibility types and functions.
  2. ZParseSql - SQL specific for syntax and lexical analysis.
  3. ZPlain - Native plain API to supported SQL servers.
  4. ZDbc - Port of Java Database Connectivity API (JDBC 2.0). DBC API acts as intermediate layer between Plain API and highlevel TDataset or DBExpress components
  5. ZComponent - visual components descended from TDataset.
  6. ZComponentDesign - design time components. This package is not available for all compilers. If present it's only needed to install the components in the IDE.

Installed components:

  1. TZConnection: This component encapsulates the database connection and transaction management.
  2. TZReadOnlyQuery: TDataset component to execute SQL queries and process data in read-only mode.
  3. TZQuery: TDataset component which allows data modifications in regular and cached mode.
  4. TZUpdateSQL: Analog of standard TUpdateSQL component to explicite definition of Insert/Update/Delete SQL statements for TDataset modifications.
  5. TZStoredProc: The component to execute SQL stored procedures.
  6. TZSQLProcessor: The component to execute SQL scripts for different SQL and various delimiter types.
  7. TZSQLMonitor: The component to monitor all outgoing SQL queries and other logging information.
  8. TZSQLMetadata: Specialized TDataset component which provides an access to database metadata such as tables, columns, indices, etc.

The project home page is here (for news, links and other project info): http://zeos.firmos.at

The sourceforge development site is located here (for technical resources and anonymous web based cvs access): http://www.sourceforge.net/projects/zeoslib

Thank you for using our software,

The ZeosLib Development Group

(c) 1999 - 2006 The Zeos Development Group
================================================ FILE: lib/zeosdbo/packages/DelphiXE/ZComponent.dpk ================================================ package ZComponent; {$R *.res} {$ALIGN 8} {$ASSERTIONS ON} {$BOOLEVAL OFF} {$DEBUGINFO ON} {$EXTENDEDSYNTAX ON} {$IMPORTEDDATA ON} {$IOCHECKS ON} {$LOCALSYMBOLS ON} {$LONGSTRINGS ON} {$OPENSTRINGS ON} {$OPTIMIZATION ON} {$OVERFLOWCHECKS ON} {$RANGECHECKS OFF} {$REFERENCEINFO ON} {$SAFEDIVIDE OFF} {$STACKFRAMES ON} {$TYPEDADDRESS OFF} {$VARSTRINGCHECKS ON} {$WRITEABLECONST OFF} {$MINENUMSIZE 1} {$IMAGEBASE $400000} {$DESCRIPTION 'Zeos Database Components'} {$LIBSUFFIX '150'} {$RUNONLY} {$IMPLICITBUILD OFF} {$I ZPackages.inc} requires rtl, dbrtl, ZPlain, ZDbc, ZCore, ZParseSql, vclactnband, vcl; contains ZSqlUpdate in '..\..\src\component\ZSqlUpdate.pas', ZAbstractDataset in '..\..\src\component\ZAbstractDataset.pas', ZAbstractRODataset in '..\..\src\component\ZAbstractRODataset.pas', ZStreamBlob in '..\..\src\component\ZStreamBlob.pas', ZAbstractConnection in '..\..\src\component\ZAbstractConnection.pas', ZGroupedConnection in '..\..\src\component\ZGroupedConnection.pas', ZConnectionGroup in '..\..\src\component\ZConnectionGroup.pas', ZConnection in '..\..\src\component\ZConnection.pas', ZDataset in '..\..\src\component\ZDataset.pas', ZDatasetUtils in '..\..\src\component\ZDatasetUtils.pas', ZSqlStrings in '..\..\src\component\ZSqlStrings.pas', ZSqlProcessor in '..\..\src\component\ZSqlProcessor.pas', ZSqlMonitor in '..\..\src\component\ZSqlMonitor.pas', ZStoredProcedure in '..\..\src\component\ZStoredProcedure.pas', ZAbstractTable in '..\..\src\component\ZAbstractTable.pas', ZSqlMetadata in '..\..\src\component\ZSqlMetadata.pas', ZSequence in '..\..\src\component\ZSequence.pas' {$IFDEF ENABLE_INTERBASE}, ZIBEventAlerter in '..\..\src\component\ZIBEventAlerter.pas' {$ENDIF} {$IFDEF ENABLE_POSTGRESQL}, ZPgEventAlerter in '..\..\src\component\ZPgEventAlerter.pas' {$ENDIF}; end. ================================================ FILE: lib/zeosdbo/packages/DelphiXE/ZComponent.dproj ================================================  {242b1e2c-c412-44f0-8a86-cf22da726ef0} ZComponent.dpk Debug DCC32 C:\Documents and Settings\All Users\Documentos\RAD Studio\5.0\Bpl\ZComponent110.bpl 12.3 Debug True Win32 Package VCL true true Base true true Base true WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;$(DCC_UnitAlias) build;$(DCC_UnitSearchPath) build $(BDSCOMMONDIR)\Bpl $(BDSCOMMONDIR)\Dcp 00400000 150 Zeos Database Components true build\ZComponent150.bpl true true true true true 7.0 False False True True 0 build build RELEASE;$(DCC_Define) $(BDSCOMMONDIR)\Bpl;$(DCC_ResourcePath) $(BDSCOMMONDIR)\Bpl;$(DCC_ObjPath) $(BDSCOMMONDIR)\Bpl;$(DCC_IncludePath) DEBUG;$(DCC_Define) 7.0 True True build build $(BDSCOMMONDIR)\Bpl;$(DCC_ResourcePath) $(BDSCOMMONDIR)\Bpl;$(DCC_ObjPath) $(BDSCOMMONDIR)\Bpl;$(DCC_IncludePath) MainSource
$ENDIF
Cfg_2 Base Base Cfg_1 Base
Delphi.Personality.12 Package True False 1 0 0 0 False False False False False 1031 1252 1.0.0.0 1.0.0.0 ZComponent.dpk True 12
================================================ FILE: lib/zeosdbo/packages/DelphiXE/ZComponentDesign.dpk ================================================ package ZComponentDesign; {$R *.res} {$R '..\..\src\component\ZComponent.dcr'} {$ALIGN 8} {$ASSERTIONS ON} {$BOOLEVAL OFF} {$DEBUGINFO ON} {$EXTENDEDSYNTAX ON} {$IMPORTEDDATA ON} {$IOCHECKS ON} {$LOCALSYMBOLS ON} {$LONGSTRINGS ON} {$OPENSTRINGS ON} {$OPTIMIZATION ON} {$OVERFLOWCHECKS ON} {$RANGECHECKS OFF} {$REFERENCEINFO ON} {$SAFEDIVIDE OFF} {$STACKFRAMES ON} {$TYPEDADDRESS OFF} {$VARSTRINGCHECKS ON} {$WRITEABLECONST OFF} {$MINENUMSIZE 1} {$IMAGEBASE $400000} {$DESCRIPTION 'Zeos Database Components'} {$LIBSUFFIX '150'} {$DESIGNONLY} {$IMPLICITBUILD OFF} requires dbrtl, designide, ZParseSql, ZCore, ZPlain, ZDbc, ZComponent; contains ZPropertyEditor in '..\..\src\component\ZPropertyEditor.pas', ZUpdateSqlEditor in '..\..\src\component\ZUpdateSqlEditor.pas' {ZUpdateSQLEditForm}, ZComponentReg in '..\..\src\component\ZComponentReg.pas'; end. ================================================ FILE: lib/zeosdbo/packages/DelphiXE/ZComponentDesign.dproj ================================================  {1c20799f-272f-4399-9075-20c658d0214d} ZComponentDesign.dpk Debug DCC32 C:\Documents and Settings\All Users\Documentos\RAD Studio\5.0\Bpl\ZComponentDesign110.bpl 12.3 Debug True Win32 Package None true true Base true true Base true WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;$(DCC_UnitAlias) build build;$(DCC_UnitSearchPath) $(BDSCOMMONDIR)\Bpl $(BDSCOMMONDIR)\Dcp true 150 00400000 Zeos Database Components build\ZComponentDesign150.bpl true true true true true 7.0 False False True True 0 build build $(BDSCOMMONDIR)\Bpl;$(DCC_ResourcePath) $(BDSCOMMONDIR)\Bpl;$(DCC_ObjPath) $(BDSCOMMONDIR)\Bpl;$(DCC_IncludePath) RELEASE DEBUG;$(DCC_Define) 7.0 True True build build $(BDSCOMMONDIR)\Bpl;$(DCC_ResourcePath) $(BDSCOMMONDIR)\Bpl;$(DCC_ObjPath) $(BDSCOMMONDIR)\Bpl;$(DCC_IncludePath) MainSource
ZUpdateSQLEditForm
Cfg_2 Base Base Cfg_1 Base
Delphi.Personality.12 Package True False 1 0 0 0 False False False False False 1033 1252 1.0.0.0 1.0.0.0 ZComponentDesign.dpk True 12
================================================ FILE: lib/zeosdbo/packages/DelphiXE/ZCore.dpk ================================================ package ZCore; {$R *.res} {$ALIGN 8} {$ASSERTIONS ON} {$BOOLEVAL OFF} {$DEBUGINFO ON} {$EXTENDEDSYNTAX ON} {$IMPORTEDDATA ON} {$IOCHECKS ON} {$LOCALSYMBOLS ON} {$LONGSTRINGS ON} {$OPENSTRINGS ON} {$OPTIMIZATION ON} {$OVERFLOWCHECKS ON} {$RANGECHECKS OFF} {$REFERENCEINFO ON} {$SAFEDIVIDE OFF} {$STACKFRAMES ON} {$TYPEDADDRESS OFF} {$VARSTRINGCHECKS ON} {$WRITEABLECONST OFF} {$MINENUMSIZE 1} {$IMAGEBASE $400000} {$DESCRIPTION 'Zeos Core Classes and Interfaces'} {$LIBSUFFIX '150'} {$RUNONLY} {$IMPLICITBUILD OFF} requires rtl; contains ZVariant in '..\..\src\core\ZVariant.pas', ZCollections in '..\..\src\core\ZCollections.pas', ZCompatibility in '..\..\src\core\ZCompatibility.pas', ZEncoding in '..\..\src\core\ZEncoding.pas', ZExpression in '..\..\src\core\ZExpression.pas', ZExprParser in '..\..\src\core\ZExprParser.pas', ZExprToken in '..\..\src\core\ZExprToken.pas', ZMatchPattern in '..\..\src\core\ZMatchPattern.pas', ZSysUtils in '..\..\src\core\ZSysUtils.pas', ZTokenizer in '..\..\src\core\ZTokenizer.pas', ZVariables in '..\..\src\core\ZVariables.pas', ZClasses in '..\..\src\core\ZClasses.pas', ZMessages in '..\..\src\core\ZMessages.pas', ZURL in '..\..\src\core\ZURL.pas', ZFunctions in '..\..\src\core\ZFunctions.pas', ZFunctionsConvert in '..\..\src\core\ZFunctionsConvert.pas', ZFunctionsDateTime in '..\..\src\core\ZFunctionsDateTime.pas', ZFunctionsMath in '..\..\src\core\ZFunctionsMath.pas', ZFunctionsOther in '..\..\src\core\ZFunctionsOther.pas', ZFunctionsStrings in '..\..\src\core\ZFunctionsStrings.pas'; end. ================================================ FILE: lib/zeosdbo/packages/DelphiXE/ZCore.dproj ================================================  {1a98c0b7-eb38-4725-9569-1c0bf5beb099} ZCore.dpk Debug DCC32 C:\Documents and Settings\All Users\Documentos\RAD Studio\5.0\Bpl\ZCore110.bpl 12.3 Debug True Win32 Package None true true Base true true Base true WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;$(DCC_UnitAlias) build;$(DCC_UnitSearchPath) build $(BDSCOMMONDIR)\Bpl $(BDSCOMMONDIR)\Dcp 00400000 150 Zeos Core Classes and Interfaces true build\ZCore150.bpl true true true true true 7.0 False False True True 0 build build RELEASE;$(DCC_Define) $(BDSCOMMONDIR)\Bpl;$(DCC_ResourcePath) $(BDSCOMMONDIR)\Bpl;$(DCC_ObjPath) $(BDSCOMMONDIR)\Bpl;$(DCC_IncludePath) DEBUG;$(DCC_Define) 7.0 True True build build $(BDSCOMMONDIR)\Bpl;$(DCC_ResourcePath) $(BDSCOMMONDIR)\Bpl;$(DCC_ObjPath) $(BDSCOMMONDIR)\Bpl;$(DCC_IncludePath) MainSource Cfg_2 Base Base Cfg_1 Base Delphi.Personality.12 Package True False 1 0 0 0 False False False False False 1031 1252 1.0.0.0 1.0.0.0 ZCore.dpk True 12 ================================================ FILE: lib/zeosdbo/packages/DelphiXE/ZDbc.dpk ================================================ package ZDbc; {$R *.res} {$ALIGN 8} {$ASSERTIONS ON} {$BOOLEVAL OFF} {$DEBUGINFO ON} {$EXTENDEDSYNTAX ON} {$IMPORTEDDATA ON} {$IOCHECKS ON} {$LOCALSYMBOLS ON} {$LONGSTRINGS ON} {$OPENSTRINGS ON} {$OPTIMIZATION ON} {$OVERFLOWCHECKS ON} {$RANGECHECKS OFF} {$REFERENCEINFO ON} {$SAFEDIVIDE OFF} {$STACKFRAMES ON} {$TYPEDADDRESS OFF} {$VARSTRINGCHECKS ON} {$WRITEABLECONST OFF} {$MINENUMSIZE 1} {$IMAGEBASE $400000} {$DESCRIPTION 'Zeos Low Level Database API'} {$LIBSUFFIX '150'} {$RUNONLY} {$IMPLICITBUILD OFF} {$I ZPackages.inc} requires ZParseSql, ZPlain, rtl, dbrtl; contains {$IFDEF ENABLE_DBLIB} ZDbcDbLib in '..\..\src\dbc\ZDbcDbLib.pas', ZDbcDbLibMetadata in '..\..\src\dbc\ZDbcDbLibMetadata.pas', ZDbcDbLibResultSet in '..\..\src\dbc\ZDbcDbLibResultSet.pas', ZDbcDbLibStatement in '..\..\src\dbc\ZDbcDbLibStatement.pas', ZDbcDbLibUtils in '..\..\src\dbc\ZDbcDbLibUtils.pas', {$ENDIF} {$IFDEF ENABLE_INTERBASE} ZDbcInterbase6 in '..\..\src\dbc\ZDbcInterbase6.pas', ZDbcInterbase6Metadata in '..\..\src\dbc\ZDbcInterbase6Metadata.pas', ZDbcInterbase6ResultSet in '..\..\src\dbc\ZDbcInterbase6ResultSet.pas', ZDbcInterbase6Statement in '..\..\src\dbc\ZDbcInterbase6Statement.pas', ZDbcInterbase6Utils in '..\..\src\dbc\ZDbcInterbase6Utils.pas', {$ENDIF} {$IFDEF ENABLE_MYSQL} ZDbcMySql in '..\..\src\dbc\ZDbcMySql.pas', ZDbcMySqlMetadata in '..\..\src\dbc\ZDbcMySqlMetadata.pas', ZDbcMySqlResultSet in '..\..\src\dbc\ZDbcMySqlResultSet.pas', ZDbcMySqlStatement in '..\..\src\dbc\ZDbcMySqlStatement.pas', ZDbcMySqlUtils in '..\..\src\dbc\ZDbcMySqlUtils.pas', {$ENDIF} {$IFDEF ENABLE_POSTGRESQL} ZDbcPostgreSql in '..\..\src\dbc\ZDbcPostgreSql.pas', ZDbcPostgreSqlMetadata in '..\..\src\dbc\ZDbcPostgreSqlMetadata.pas', ZDbcPostgreSqlResultSet in '..\..\src\dbc\ZDbcPostgreSqlResultSet.pas', ZDbcPostgreSqlStatement in '..\..\src\dbc\ZDbcPostgreSqlStatement.pas', ZDbcPostgreSqlUtils in '..\..\src\dbc\ZDbcPostgreSqlUtils.pas', {$ENDIF} {$IFDEF ENABLE_ADO} ZDbcAdo in '..\..\src\dbc\ZDbcAdo.pas', ZDbcAdoMetadata in '..\..\src\dbc\ZDbcAdoMetadata.pas', ZDbcAdoResultSet in '..\..\src\dbc\ZDbcAdoResultSet.pas', ZDbcAdoStatement in '..\..\src\dbc\ZDbcAdoStatement.pas', ZDbcAdoUtils in '..\..\src\dbc\ZDbcAdoUtils.pas', {$ENDIF} {$IFDEF ENABLE_ORACLE} ZDbcOracle in '..\..\src\dbc\ZDbcOracle.pas', ZDbcOracleUtils in '..\..\src\dbc\ZDbcOracleUtils.pas', ZDbcOracleStatement in '..\..\src\dbc\ZDbcOracleStatement.pas', ZDbcOracleResultSet in '..\..\src\dbc\ZDbcOracleResultSet.pas', ZDbcOracleMetadata in '..\..\src\dbc\ZDbcOracleMetadata.pas', {$ENDIF} {$IFDEF ENABLE_SQLITE} ZDbcSqLite in '..\..\src\dbc\ZDbcSqLite.pas', ZDbcSqLiteUtils in '..\..\src\dbc\ZDbcSqLiteUtils.pas', ZDbcSqLiteStatement in '..\..\src\dbc\ZDbcSqLiteStatement.pas', ZDbcSqLiteResultSet in '..\..\src\dbc\ZDbcSqLiteResultSet.pas', ZDbcSqLiteMetadata in '..\..\src\dbc\ZDbcSqLiteMetadata.pas', {$ENDIF} {$IFDEF ENABLE_ASA} ZDbcASAUtils in '..\..\src\dbc\ZDbcASAUtils.pas', ZDbcASAMetadata in '..\..\src\dbc\ZDbcASAMetadata.pas', ZDbcASAResultSet in '..\..\src\dbc\ZDbcASAResultSet.pas', ZDbcASAStatement in '..\..\src\dbc\ZDbcASAStatement.pas', ZDbcASA in '..\..\src\dbc\ZDbcASA.pas', {$ENDIF} {$IFDEF ENABLE_POOLED} ZDbcPooled in '..\..\src\dbc\ZDbcPooled.pas', {$ENDIF} ZDbcUtils in '..\..\src\dbc\ZDbcUtils.pas', ZDbcCachedResultSet in '..\..\src\dbc\ZDbcCachedResultSet.pas', ZDbcConnection in '..\..\src\dbc\ZDbcConnection.pas', ZDbcGenericResolver in '..\..\src\dbc\ZDbcGenericResolver.pas', ZDbcIntfs in '..\..\src\dbc\ZDbcIntfs.pas', ZDbcMetadata in '..\..\src\dbc\ZDbcMetadata.pas', ZDbcResultSet in '..\..\src\dbc\ZDbcResultSet.pas', ZDbcResultSetMetadata in '..\..\src\dbc\ZDbcResultSetMetadata.pas', ZDbcStatement in '..\..\src\dbc\ZDbcStatement.pas', ZDbcCache in '..\..\src\dbc\ZDbcCache.pas', ZDbcLogging in '..\..\src\dbc\ZDbcLogging.pas'; end. ================================================ FILE: lib/zeosdbo/packages/DelphiXE/ZDbc.dproj ================================================  {47d8573c-edfe-4827-93f9-d1e3ee5f6f1f} ZDbc.dpk Debug DCC32 C:\Documents and Settings\All Users\Documentos\RAD Studio\5.0\Bpl\ZDbc110.bpl 12.3 Debug True Win32 Package None true true Base true true Base true WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;$(DCC_UnitAlias) build;$(DCC_UnitSearchPath) build $(BDSCOMMONDIR)\Bpl $(BDSCOMMONDIR)\Dcp 00400000 150 Zeos Low Level Database API true build\ZDbc150.bpl true true true true true 7.0 False False True True 0 build build RELEASE;$(DCC_Define) $(BDSCOMMONDIR)\Bpl;$(DCC_ResourcePath) $(BDSCOMMONDIR)\Bpl;$(DCC_ObjPath) $(BDSCOMMONDIR)\Bpl;$(DCC_IncludePath) DEBUG;$(DCC_Define) 7.0 True True build build $(BDSCOMMONDIR)\Bpl;$(DCC_ResourcePath) $(BDSCOMMONDIR)\Bpl;$(DCC_ObjPath) $(BDSCOMMONDIR)\Bpl;$(DCC_IncludePath) MainSource Cfg_2 Base Base Cfg_1 Base Delphi.Personality.12 Package True False 1 0 0 0 False False False False False 1031 1252 1.0.0.0 1.0.0.0 ZDbc.dpk CodeGear Internet Components CodeGear WebSnap Components CodeGear C++Builder Office 2000 Servers Package CodeGear C++Builder Office XP Servers Package Microsoft Office 2000 Sample Automation Server Wrapper Components Microsoft Office XP Sample Automation Server Wrapper Components True 12 ================================================ FILE: lib/zeosdbo/packages/DelphiXE/ZPackages.inc ================================================ {$IFDEF FREEBSD} {$DEFINE UNIX} {$ENDIF} {$IFDEF LINUX} {$DEFINE UNIX} {$ENDIF} {$IFNDEF UNIX} {$I ..\..\src\Zeos.inc} {$ELSE} {$I ../../src/Zeos.inc} {$ENDIF} ================================================ FILE: lib/zeosdbo/packages/DelphiXE/ZParseSql.dpk ================================================ package ZParseSql; {$R *.res} {$ALIGN 8} {$ASSERTIONS ON} {$BOOLEVAL OFF} {$DEBUGINFO ON} {$EXTENDEDSYNTAX ON} {$IMPORTEDDATA ON} {$IOCHECKS ON} {$LOCALSYMBOLS ON} {$LONGSTRINGS ON} {$OPENSTRINGS ON} {$OPTIMIZATION ON} {$OVERFLOWCHECKS ON} {$RANGECHECKS OFF} {$REFERENCEINFO ON} {$SAFEDIVIDE OFF} {$STACKFRAMES ON} {$TYPEDADDRESS OFF} {$VARSTRINGCHECKS ON} {$WRITEABLECONST OFF} {$MINENUMSIZE 1} {$IMAGEBASE $400000} {$DESCRIPTION 'Zeos SQL Parsing Classes and Interfaces'} {$LIBSUFFIX '150'} {$RUNONLY} {$IMPLICITBUILD OFF} {$I ZPackages.inc} requires ZCore; contains {$IFDEF ENABLE_ADO} ZAdoToken in '..\..\src\parsesql\ZAdoToken.pas', {$ENDIF} {$IFDEF ENABLE_INTERBASE} ZInterbaseAnalyser in '..\..\src\parsesql\ZInterbaseAnalyser.pas', ZInterbaseToken in '..\..\src\parsesql\ZInterbaseToken.pas', {$ENDIF} {$IFDEF ENABLE_MYSQL} ZMySqlAnalyser in '..\..\src\parsesql\ZMySqlAnalyser.pas', ZMySqlToken in '..\..\src\parsesql\ZMySqlToken.pas', {$ENDIF} {$IFDEF ENABLE_POSTGRESQL} ZPostgreSqlAnalyser in '..\..\src\parsesql\ZPostgreSqlAnalyser.pas', ZPostgreSqlToken in '..\..\src\parsesql\ZPostgreSqlToken.pas', {$ENDIF} {$IFDEF ENABLE_DBLIB} ZSybaseAnalyser in '..\..\src\parsesql\ZSybaseAnalyser.pas', ZSybaseToken in '..\..\src\parsesql\ZSybaseToken.pas', {$ENDIF} {$IFDEF ENABLE_ORACLE} ZOracleToken in '..\..\src\parsesql\ZOracleToken.pas', ZOracleAnalyser in '..\..\src\parsesql\ZOracleAnalyser.pas', {$ENDIF} {$IFDEF ENABLE_SQLITE} ZSqLiteToken in '..\..\src\parsesql\ZSqLiteToken.pas', ZSqLiteAnalyser in '..\..\src\parsesql\ZSqLiteAnalyser.pas', {$ENDIF} ZGenericSqlToken in '..\..\src\parsesql\ZGenericSqlToken.pas', ZGenericSqlAnalyser in '..\..\src\parsesql\ZGenericSqlAnalyser.pas', ZScriptParser in '..\..\src\parsesql\ZScriptParser.pas', ZSelectSchema in '..\..\src\parsesql\ZSelectSchema.pas'; end. ================================================ FILE: lib/zeosdbo/packages/DelphiXE/ZParseSql.dproj ================================================  {39c78988-998b-49f3-8023-aaa95d43cffd} ZParseSql.dpk Debug DCC32 C:\Documents and Settings\All Users\Documentos\RAD Studio\5.0\Bpl\ZParseSql110.bpl 12.3 Debug True Win32 Package None true true Base true true Base true WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;$(DCC_UnitAlias) build;$(DCC_UnitSearchPath) build $(BDSCOMMONDIR)\Bpl $(BDSCOMMONDIR)\Dcp 00400000 150 Zeos SQL Parsing Classes and Interfaces true build\ZParseSql150.bpl true true true true true 7.0 False False True True 0 build build RELEASE;$(DCC_Define) $(BDSCOMMONDIR)\Bpl;$(DCC_ResourcePath) $(BDSCOMMONDIR)\Bpl;$(DCC_ObjPath) $(BDSCOMMONDIR)\Bpl;$(DCC_IncludePath) DEBUG;$(DCC_Define) 7.0 True True build build $(BDSCOMMONDIR)\Bpl;$(DCC_ResourcePath) $(BDSCOMMONDIR)\Bpl;$(DCC_ObjPath) $(BDSCOMMONDIR)\Bpl;$(DCC_IncludePath) MainSource Cfg_2 Base Base Cfg_1 Base Delphi.Personality.12 Package True False 1 0 0 0 False False False False False 1031 1252 1.0.0.0 1.0.0.0 ZParseSql.dpk True 12 ================================================ FILE: lib/zeosdbo/packages/DelphiXE/ZPlain.dpk ================================================ package ZPlain; {$R *.res} {$ALIGN 8} {$ASSERTIONS ON} {$BOOLEVAL OFF} {$DEBUGINFO ON} {$EXTENDEDSYNTAX ON} {$IMPORTEDDATA ON} {$IOCHECKS ON} {$LOCALSYMBOLS ON} {$LONGSTRINGS ON} {$OPENSTRINGS ON} {$OPTIMIZATION OFF} {$OVERFLOWCHECKS ON} {$RANGECHECKS ON} {$REFERENCEINFO ON} {$SAFEDIVIDE OFF} {$STACKFRAMES ON} {$TYPEDADDRESS OFF} {$VARSTRINGCHECKS ON} {$WRITEABLECONST OFF} {$MINENUMSIZE 1} {$IMAGEBASE $400000} {$DESCRIPTION 'Zeos Plain Database API'} {$LIBSUFFIX '150'} {$RUNONLY} {$IMPLICITBUILD OFF} {$I ZPackages.inc} requires ZCore, rtl, vcl; contains {$IFDEF ENABLE_DBLIB} ZPlainDbLibDriver in '..\..\src\plain\ZPlainDbLibDriver.pas', ZPlainDbLibConstants in '..\..\src\plain\ZPlainDbLibConstants.pas', {$ENDIF} {$IFDEF ENABLE_INTERBASE} ZPlainFirebirdDriver in '..\..\src\plain\ZPlainFirebirdDriver.pas', ZPlainFirebirdInterbaseConstants in '..\..\src\plain\ZPlainFirebirdInterbaseConstants.pas', {$ENDIF} {$IFDEF ENABLE_MYSQL} ZPlainMySqlDriver in '..\..\src\plain\ZPlainMySqlDriver.pas', ZPlainMySqlConstants in '..\..\src\plain\ZPlainMySqlConstants.pas', {$ENDIF} {$IFDEF ENABLE_POSTGRESQL} ZPlainPostgreSqlDriver in '..\..\src\plain\ZPlainPostgreSqlDriver.pas', {$ENDIF} {$IFDEF ENABLE_ADO} ZPlainAdoDriver in '..\..\src\plain\ZPlainAdoDriver.pas', ZPlainAdo in '..\..\src\plain\ZPlainAdo.pas', {$ENDIF} {$IFDEF ENABLE_ORACLE} ZPlainOracleDriver in '..\..\src\plain\ZPlainOracleDriver.pas', ZPlainOracleConstants in '..\..\src\plain\ZPlainOracleConstants.pas', {$ENDIF} {$IFDEF ENABLE_SQLITE} ZPlainSqLiteDriver in '..\..\src\plain\ZPlainSqLiteDriver.pas', {$ENDIF} {$IFDEF ENABLE_ASA} ZPlainASADriver in '..\..\src\plain\ZPlainASADriver.pas', ZPlainASAConstants in '..\..\src\plain\ZPlainASAConstants.pas', {$ENDIF} ZPlainDriver in '..\..\src\plain\ZPlainDriver.pas', ZPlainLoader in '..\..\src\plain\ZPlainLoader.pas'; end. ================================================ FILE: lib/zeosdbo/packages/DelphiXE/ZPlain.dproj ================================================  {839de593-a9a2-4848-98f6-2cab1973ee45} ZPlain.dpk Debug DCC32 C:\Documents and Settings\All Users\Documentos\RAD Studio\5.0\Bpl\ZPlain110.bpl 12.3 Debug True Win32 Package VCL true true Base true true Base true WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE;$(DCC_UnitAlias) $(BDSCOMMONDIR)\Bpl build build;$(DCC_UnitSearchPath) $(BDSCOMMONDIR)\Dcp build\ZPlain150.bpl 00400000 true true false Zeos Plain Database API true true true true 150 true 7.0 False False False True True True 0 3 build build RELEASE;$(DCC_Define) $(BDSCOMMONDIR)\Bpl;$(DCC_ResourcePath) $(BDSCOMMONDIR)\Bpl;$(DCC_ObjPath) $(BDSCOMMONDIR)\Bpl;$(DCC_IncludePath) DEBUG;$(DCC_Define) 7.0 False True True True 3 build build $(BDSCOMMONDIR)\Bpl;$(DCC_ResourcePath) $(BDSCOMMONDIR)\Bpl;$(DCC_ObjPath) $(BDSCOMMONDIR)\Bpl;$(DCC_IncludePath) MainSource Cfg_2 Base Base Cfg_1 Base Delphi.Personality.12 Package True False 1 0 0 0 False False False False False 1031 1252 1.0.0.0 1.0.0.0 ZPlain.dpk True 12 ================================================ FILE: lib/zeosdbo/packages/DelphiXE/ZeosDbo.groupproj ================================================  {6c337a05-41a2-4a84-b176-c57f5e15e0c9} Default.Personality.12 ================================================ FILE: lib/zeosdbo/packages/DelphiXE/events good.txt ================================================ Thread Start: Thread ID: 5176. Process ZSimple.exe (5388) Process Start: F:\Users\Mator\Downloads\ZEOSDBO-7.1.4-stable\examples\simple\ZSimple.exe. Base Address: $00400000. Process ZSimple.exe (5388) Module Load: ZSimple.exe. Has Debug Info. Base Address: $00400000. Process ZSimple.exe (5388) Module Load: ntdll.dll. No Debug Info. Base Address: $76FB0000. Process ZSimple.exe (5388) Module Load: KERNEL32.dll. No Debug Info. Base Address: $75530000. Process ZSimple.exe (5388) Module Load: KERNELBASE.dll. No Debug Info. Base Address: $75910000. Process ZSimple.exe (5388) Module Load: OLEAUT32.dll. No Debug Info. Base Address: $76960000. Process ZSimple.exe (5388) Module Load: ole32.dll. No Debug Info. Base Address: $751F0000. Process ZSimple.exe (5388) Module Load: msvcrt.dll. No Debug Info. Base Address: $749A0000. Process ZSimple.exe (5388) Module Load: GDI32.dll. No Debug Info. Base Address: $754A0000. Process ZSimple.exe (5388) Module Load: USER32.dll. No Debug Info. Base Address: $74A50000. Process ZSimple.exe (5388) Module Load: ADVAPI32.dll. No Debug Info. Base Address: $76B10000. Process ZSimple.exe (5388) Module Load: SECHOST.dll. No Debug Info. Base Address: $75990000. Process ZSimple.exe (5388) Module Load: RPCRT4.dll. No Debug Info. Base Address: $74DB0000. Process ZSimple.exe (5388) Module Load: SspiCli.dll. No Debug Info. Base Address: $74940000. Process ZSimple.exe (5388) Module Load: CRYPTBASE.dll. No Debug Info. Base Address: $74930000. Process ZSimple.exe (5388) Module Load: LPK.dll. No Debug Info. Base Address: $76AE0000. Process ZSimple.exe (5388) Module Load: USP10.dll. No Debug Info. Base Address: $74EC0000. Process ZSimple.exe (5388) Module Load: MSIMG32.dll. No Debug Info. Base Address: $6F400000. Process ZSimple.exe (5388) Module Load: VERSION.dll. No Debug Info. Base Address: $72BD0000. Process ZSimple.exe (5388) Module Load: COMCTL32.dll. No Debug Info. Base Address: $6E180000. Process ZSimple.exe (5388) Module Load: WINSPOOL.DRV. No Debug Info. Base Address: $6E760000. Process ZSimple.exe (5388) Module Load: apphelp.dll. No Debug Info. Base Address: $6EBC0000. Process ZSimple.exe (5388) Module Load: NULL.dll. No Debug Info. Base Address: $672F0000. Process ZSimple.exe (5388) Module Load: SHELL32.dll. No Debug Info. Base Address: $75BF0000. Process ZSimple.exe (5388) Module Load: SHLWAPI.dll. No Debug Info. Base Address: $76A80000. Process ZSimple.exe (5388) Module Load: USERENV.dll. No Debug Info. Base Address: $74D60000. Process ZSimple.exe (5388) Module Load: profapi.dll. No Debug Info. Base Address: $769F0000. Process ZSimple.exe (5388) Module Load: MPR.dll. No Debug Info. Base Address: $6F3E0000. Process ZSimple.exe (5388) Module Load: IMM32.dll. No Debug Info. Base Address: $75B50000. Process ZSimple.exe (5388) Module Load: MSCTF.dll. No Debug Info. Base Address: $74B60000. Process ZSimple.exe (5388) Module Load: UxTheme.dll. No Debug Info. Base Address: $6D910000. Process ZSimple.exe (5388) Module Load: dwmapi.dll. No Debug Info. Base Address: $6EBA0000. Process ZSimple.exe (5388) Module Load: COMCTL32.dll. No Debug Info. Base Address: $6F100000. Process ZSimple.exe (5388) Module Load: ole32.dll. No Debug Info. Base Address: $058B0000. Process ZSimple.exe (5388) Module Unload: ole32.dll. Process ZSimple.exe (5388) Module Load: ole32.dll. No Debug Info. Base Address: $05CA0000. Process ZSimple.exe (5388) Module Unload: ole32.dll. Process ZSimple.exe (5388) Module Load: CLBCatQ.DLL. No Debug Info. Base Address: $75640000. Process ZSimple.exe (5388) Module Load: libmysql.dll. No Debug Info. Base Address: $53EB0000. Process ZSimple.exe (5388) Module Load: Secur32.dll. No Debug Info. Base Address: $6E210000. Process ZSimple.exe (5388) Module Load: WS2_32.dll. No Debug Info. Base Address: $76A00000. Process ZSimple.exe (5388) Module Load: NSI.dll. No Debug Info. Base Address: $76A40000. Process ZSimple.exe (5388) Module Load: nlaapi.dll. No Debug Info. Base Address: $6E7C0000. Process ZSimple.exe (5388) Module Load: NAPINSP.dll. No Debug Info. Base Address: $6ECC0000. Process ZSimple.exe (5388) Thread Start: Thread ID: 4300. Process ZSimple.exe (5388) Module Load: PNRPNSP.dll. No Debug Info. Base Address: $6E520000. Process ZSimple.exe (5388) Module Load: MSWSOCK.dll. No Debug Info. Base Address: $6F950000. Process ZSimple.exe (5388) Module Load: DNSAPI.dll. No Debug Info. Base Address: $72CD0000. Process ZSimple.exe (5388) Module Load: WINRNR.dll. No Debug Info. Base Address: $6E510000. Process ZSimple.exe (5388) Module Load: mdnsNSP.dll. No Debug Info. Base Address: $6E540000. Process ZSimple.exe (5388) Module Load: IPHLPAPI.DLL. No Debug Info. Base Address: $72C90000. Process ZSimple.exe (5388) Module Load: WINNSI.DLL. No Debug Info. Base Address: $72C80000. Process ZSimple.exe (5388) Module Load: rasadhlp.dll. No Debug Info. Base Address: $6EB90000. Process ZSimple.exe (5388) Module Load: WSHTCPIP.dll. No Debug Info. Base Address: $6F8C0000. Process ZSimple.exe (5388) First chance exception at $7591C42D. Exception class EZSQLException with message 'SQL Error: Table 'mergeplugins.tsite' doesn't exist'. Process ZSimple.exe (5388) Thread Start: Thread ID: 4468. Process ZSimple.exe (5388) Thread Start: Thread ID: 4624. Process ZSimple.exe (5388) Thread Start: Thread ID: 3592. Process ZSimple.exe (5388) ================================================ FILE: lib/zeosdbo/src/Zeos.inc ================================================ {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} // Compilation directives for Lazarus {$IFDEF FPC} {$I ZeosLazarus.inc} {$ELSE} {$DEFINE DELPHI} // Defines that go for ALL still supported Delphi's (usually means they were under ifndef fpc) {$DEFINE WITH_DBCONSTS} // Delphi DBCONSTS, FPC DBCONST {$DEFINE WITH_ASLARGEINT} // tlargeint aslargeint. Fixed 2.6.0+ or 2.6.2+ probably {$DEFINE WITH_ASCURRENCY} // Has AsCurrency. {$DEFINE WITH_ASVARIANT} {$DEFINE WITH_IPROVIDER} // Turn on IProviderSupport interface {$DEFINE WITH_CHECKFIELDCOMPATIBILITY} {$DEFINE WITH_WIDEMEMO} // Have WIDEMEMO, For Delphi we turn these off if not applicable {$DEFINE WITH_FTWIDESTRING} // Have ftwidestring, For Delphi we turn these off if not applicable {$DEFINE WITH_WIDEFIELDS} // Wide-fields are supported (common define for ftWideString/ftWideMemo) {$DEFINE WITH_DBTABLES} // Have the BDE DBTables Unit {$DEFINE WITH_INLINE_ANSICOMPARETEXT} {$DEFINE WITH_FTDATASETSUPPORT} //ftDataSet is supported {$DEFINE WITH_CLASS_VARS} // Class variables/methods are supported {$DEFINE WITH_INLINE} // compiler supports inline methodes {$DEFINE WITH_FTGUID} // ftGuid is supported (binary 16Bytes) {$DEFINE WITH_FUNIDIRECTIONAL} //TDataSet have SetUniDirectional and GetUnidirectional {$ENDIF} // Compilation directives for Delphi4 // Not supported since Zeoslib 7.X {$IFDEF VER120} "Delphi versions below Delphi 7 aren't supported anymore" {$ENDIF} // Compilation directives for Delphi 5 // Not supported since Zeoslib 7.X {$IFDEF VER130} "Delphi versions below Delphi 7 aren't supported anymore" {$ENDIF} // Compilation directives for Delphi 6 // Not supported since Zeoslib 7.X {$IFDEF VER140} "Kylix3, CBuilder/Delphi Versions below version 7 aren't supported anymore" {$ENDIF} // Compilation directives for Delphi 7 {$IFDEF VER150} {$DEFINE VER150BELOW} // Used in zeos.inc only {$ENDIF} // Compilation directives for Delphi 8 {$IFDEF VER160} {$DEFINE VER150BELOW} // Used in zeos.inc only {$ENDIF} // Compilation directives for Delphi 9 (DELPHI 2005) {$IFDEF VER170} // No directives needed {$DEFINE VER150BELOW} // Used in zeos.inc only {$DEFINE VER170BELOW} // Used in Zeos.inc only {$ENDIF} // Compilation directives for BDS 2006 (Delphi 2006, BCB 2006) {$IFDEF VER180} {$DEFINE BDS4_UP} // Used in code {$ENDIF} // Compilation directives for Delphi 2007, Delphi .NET 2007 {$IFDEF VER185} {$DEFINE BDS4_UP} // Used in code {$ENDIF} // Compilation directives for Delphi 2009 {$IFDEF VER200} {$DEFINE VER200BELOW} // Used in code {$DEFINE DELPHI12_UP} // Used in code {$DEFINE BDS4_UP} // Used in code {$DEFINE BDS5_UP} // Used in code {$DEFINE WITH_INLINE_ANSISTRLCOMP} {$ENDIF} // Compilation directives for Delphi 2010 {$IFDEF VER210} {$DEFINE VER200BELOW} // Used in code {$DEFINE DELPHI12_UP} // Used in code {$DEFINE DELPHI14_UP} // used in tests only {$DEFINE BDS4_UP} // Used in code {$DEFINE BDS5_UP} // Used in code {$ENDIF} // Compilation directives for Delphi XE {$IFDEF VER220} {$DEFINE VER200BELOW} // Used in code {$DEFINE DELPHI12_UP} // Used in code {$DEFINE DELPHI14_UP} // used in tests only {$DEFINE DELPHI15_UP} // Used in zeos.inc only {$DEFINE BDS4_UP} // Used in code {$DEFINE BDS5_UP} // Used in code {$ENDIF} {$IFDEF LINUX} {$DEFINE UNIX} {$ENDIF} // Compilation directives for Delphi XE2 {$IFDEF VER230} {$DEFINE VER200BELOW} // Used in code {$DEFINE DELPHI12_UP} // Used in code {$DEFINE DELPHI14_UP} // used in tests only {$DEFINE DELPHI15_UP} // Used in zeos.inc only {$DEFINE DELPHI16_UP} // Used in code {$DEFINE BDS4_UP} // Used in code {$DEFINE BDS5_UP} // Used in code {$ENDIF} // Compilation directives for Delphi XE3 {$IFDEF VER240} {$DEFINE VER200BELOW} // Used in code {$DEFINE DELPHI12_UP} // Used in code {$DEFINE DELPHI14_UP} // used in tests only {$DEFINE DELPHI15_UP} // Used in zeos.inc only {$DEFINE DELPHI16_UP} // Used in code {$DEFINE DELPHI17_UP} // Used in code {$DEFINE BDS4_UP} // Used in code {$DEFINE BDS5_UP} // Used in code {$ENDIF} // Compilation directives for Delphi XE4 {$IFDEF VER250} {$DEFINE VER200BELOW} // Used in code {$DEFINE DELPHI12_UP} // Used in code {$DEFINE DELPHI14_UP} // used in tests only {$DEFINE DELPHI15_UP} // Used in zeos.inc only {$DEFINE DELPHI16_UP} // Used in code {$DEFINE DELPHI17_UP} // Used in zeos.inc only {$DEFINE DELPHI18_UP} // Used in zeos.inc only {$DEFINE BDS4_UP} // Used in code {$DEFINE BDS5_UP} // Used in code {$ENDIF} // Compilation directives for Delphi XE5 {$IFDEF VER260} {$DEFINE VER200BELOW} // Used in code {$DEFINE DELPHI12_UP} // Used in code {$DEFINE DELPHI14_UP} // used in tests only {$DEFINE DELPHI15_UP} // Used in zeos.inc only {$DEFINE DELPHI16_UP} // Used in code {$DEFINE DELPHI17_UP} // Used in zeos.inc only {$DEFINE DELPHI18_UP} // Used in zeos.inc only {$DEFINE DELPHI19_UP} {$DEFINE BDS4_UP} // Used in code {$DEFINE BDS5_UP} // Used in code {$ENDIF} // Compilation directives for Delphi XE6 by dieletro {$IFDEF VER270} {$DEFINE VER200BELOW} // Used in code {$DEFINE DELPHI12_UP} // Used in code {$DEFINE DELPHI14_UP} // used in tests only {$DEFINE DELPHI15_UP} // Used in zeos.inc only {$DEFINE DELPHI16_UP} // Used in code {$DEFINE DELPHI17_UP} // Used in zeos.inc only {$DEFINE DELPHI18_UP} // Used in zeos.inc only {$DEFINE DELPHI19_UP} // Used in zeos.inc only {$DEFINE DELPHI20_UP} //By dieletro Used in zeos.inc only {$DEFINE BDS4_UP} // Used in code {$DEFINE BDS5_UP} // Used in code {$ENDIF} // Compilation directives for Delphi XE7 by miab3 {$IFDEF VER280} {$DEFINE VER200BELOW} // Used in code {$DEFINE DELPHI12_UP} // Used in code {$DEFINE DELPHI14_UP} // used in tests only {$DEFINE DELPHI15_UP} // Used in zeos.inc only {$DEFINE DELPHI16_UP} // Used in code {$DEFINE DELPHI17_UP} // Used in zeos.inc only {$DEFINE DELPHI18_UP} // Used in zeos.inc only {$DEFINE DELPHI19_UP} // Used in zeos.inc only {$DEFINE DELPHI20_UP} //By dieletro Used in zeos.inc only {$DEFINE DELPHI21_UP} //Used in zeos.inc only {$DEFINE BDS4_UP} // Used in code {$DEFINE BDS5_UP} // Used in code {$ENDIF} // END of per Delphi version defines {$IFDEF BDS4_UP} {$DEFINE WITH_WIDESTRINGS_GETFIELDNAMES} //overload of GetFieldNames(List: TWideStrings) does exists; {$DEFINE WIDE_DATASET} // TWidedataset exists {$DEFINE WITH_PWIDECHAR_TOWIDESTRING} // Able to pass pwidechar to a widestring parameter {$DEFINE WITH_IPROVIDERWIDE} // IProvider -W widestring using interface {$DEFINE WITH_WIDESTRUTILS} // WideStrUtils Unit. {$DEFINE WITH_REPORTMEMORYLEAKSONSHUTDOWN} //ReportMemoryLeaksOnShutdown property does exists (testsuites) {$ENDIF} {$IFDEF DELPHI12_UP} {$DEFINE WITH_TBOOKMARK} // Have TBookmark {$DEFINE WITH_TRECORDBUFFER} // Abstract buffer type (pansichar or pbyte) {$DEFINE WITH_STSTRINGUNICODE} // ststring is unicodestring. {$DEFINE WITH_NEWTOBJECT} // allows new methods in TObject (D2009+/FPC 2.4.4) {$DEFINE WITH_CHARINSET} // D2009's poor substitute for character specific "xx in yy" {$DEFINE WITH_FTSHORTINT} // ftShortInt is supported {$DEFINE WITH_FTBYTE} // ftByte is supported {$DEFINE WITH_FTEXTENDED} // ftExtended is supported {$DEFINE WITH_FTLONGWORD} // ftLongWord is supported {$DEFINE WITH_ASBYTES} // AsBytes is supported {$DEFINE WITH_RAWBYTESTRING} // Have RawByteString CP $FFFFF {$DEFINE WITH_DEFAULTSYSTEMCODEPAGE} // determine the AnsiString CP {$DEFINE WITH_UNITANSISTRINGS} // Have unit AnsiStrings {$DEFINE WITH_TENCODING_CLASS} // Have class TEncoding {$UNDEF WITH_IPROVIDERWIDE} // IProvider -W widestring using interface is deprecated since UNICODE and wo't be called anymore {$DEFINE PWIDECHAR_IS_PUNICODECHAR} // PWideChar = ^UnicodeString {$ENDIF} {$IFDEF DELPHI14_UP} {$UNDEF WITH_INLINE_ANSICOMPARETEXT} // AnsiCompareText is no more inline declared {$DEFINE WITH_UINT64} // D2010 has virtually UInt64 {$DEFINE WITH_PUINT64} // D2010 has virtually PUInt64 {$ENDIF} {$IFDEF DELPHI15_UP} {$DEFINE WITH_FORMATSETTINGS} {$DEFINE WITH_UNICODEFROMLOCALECHARS} {$IFDEF WIN64} {$UNDEF WITH_DBTABLES} //BDE unit DBTables (TestSuites) isn't supported on CPU64 {$ENDIF} {$ENDIF} {$IFDEF VER150BELOW} {$UNDEF WITH_WIDEMEMO} {$UNDEF WITH_FTWIDESTRING} // D7 doesn't support TField.AsWideString {$UNDEF WITH_WIDEFIELDS} // absolutely no TWide-Fields support {$UNDEF WITH_CLASS_VARS} // absolutely no Class var/method support {$IFNDEF VER170BELOW} //D2005 supports inline {$UNDEF WITH_INLINE} // D7 doesn't support inline declarations {$ENDIF} {$DEFINE WITH_MILLISECONDOFTHEYEAR_BUG} //D7-D005 Bug -> a Int64 Cast of SecondOfTheYear(AValue) is missing {$ENDIF} {$IFDEF DELPHI16_UP} {$DEFINE WITH_SYSTEMCLASSES} //Need System.Classes {$DEFINE WITH_MAXLISTSIZE_DEPRECATED} //Since XE2 64Bit Integer = Int64 this value is deprecated {$DEFINE WITH_VCL_PREFIX} {$ENDIF} {$IFDEF DELPHI17_UP} {$UNDEF WIDE_DATASET} // TWideDataset and TDataSet are merged together: https://forums.embarcadero.com/thread.jspa?messageID=499588 {$DEFINE WITH_TVALUEBUFFER} // SetFieldData/GetFieldData and Parameters using TValueBuffer instead of Pointer {$DEFINE WITH_BOOKMARKDATA_TBOOKMARK} {$UNDEF WITH_WIDESTRINGS_GETFIELDNAMES} //GetFieldNames with TWideStrings has been removed {$DEFINE WITH_GENERIC_TLISTTFIELD} //GetFieldList() uses the generic TList {$ENDIF} {$IFDEF DELPHI18_UP} {$DEFINE WITH_VAR_TVALUEBUFFER} //GetFieldata overloads using !var! Buffer: TValueBuffer {$DEFINE WITH_BUFFERS_IS_TRECBUF} //Buffers[index] is TRecBuf type NativeInt {$DEFINE WITH_ANSISTRINGPOS_DEPRECATED} //AnsiStringPos deprecated moved to AnsiStrings {$DEFINE WITH_STRLEN_DEPRECATED} //StrLen deprecated moved to AnsiStrings {$DEFINE WITH_TOBJECTLIST_INLINE} //TObjectList.Remove, add ... are inlined need System.Types {$DEFINE WITH_ANSISTRCOMP_DEPRECATED} //AnsiStrComp is deprecated moved to AnsiStrings {$DEFINE WITH_ANSISTRLCOMP_DEPRECATED} //AnsiStrLComp is deprecated moved to AnsiStrings {$DEFINE WITH_STRDISPOSE_DEPRECATED} //StrDispose is deprecated moved to AnsiStrings {$DEFINE WITH_STRNEW_DEPRECATED} //StrNew is deprecated moved to AnsiStrings {$DEFINE WITH_STRCOPY_DEPRECATED} //StrCopy is deprecated moved to AnsiStrings {$DEFINE WITH_STRPCOPY_DEPRECATED} //StrPCopy is deprecated moved to AnsiStrings {$DEFINE WITH_STRPLCOPY_DEPRECATED} //StrPLCopy is deprecated moved to AnsiStrings {$DEFINE WITH_STRLCOPY_DEPRECATED} //StrLCopy is deprecated moved to AnsiStrings {$DEFINE WITH_STRLICOPY_DEPRECATED} //StrLICopy is deprecated moved to AnsiStrings {$DEFINE WITH_STRLICOMP_DEPRECATED} //StrLIComp is deprecated moved to AnsiStrings {$DEFINE WITH_GETCALCFIELDS_TRECBUF} //GetCalcFields expected no TRecordBuffer use TRecBuf type NativeInt instead {$ENDIF} {$IFDEF DELPHI20_UP} {$DEFINE WITH_IPROVIDERSUPPORT_NG} //supports IProviderSupportNG / IProviderSupport is deprecated {$DEFINE TFIELD_HAS_ASLONGWORD} //TField has supports virtual AsLongWord Gettet & Setter {$ENDIF} {$IFDEF DELPHI21_UP} {$UNDEF WITH_DBTABLES} //M.A. In Delphi XE7 no BDE {$ENDIF} {$IFNDEF WIN32} //global undefines {$UNDEF USE_FAST_TRUNC} {$ENDIF} // Debug/release compiler options {$D+} //force 4 byte enumerations. We are interfacing with c libraries !! {$Z+} {$IFOPT D-} {$DEFINE BINARY_RELEASE} {$ENDIF} {$IFDEF BINARY_RELEASE} // Settings for Release mode {$C-} {$I-} {$R-} {$L-} {$Q-} {$IFNDEF FPC} {$O+} {$W-} {$ENDIF} {$ELSE} // Settings for Debug mode {.$C+} {.$I+} {.$R+} {.$L+} {.$Q+} {.$IFNDEF FPC} {.$O-} {.$W+} {.$ENDIF} {$ENDIF} // Disables checking code. // Use Range checking option to turn on/off optimization {$IFOPT R-} {$DEFINE DISABLE_CHECKING} {$ENDIF} // Uncomment these defines to disable some DB drivers (reduce binary size) {.$DEFINE ZEOS_DISABLE_MYSQL} {.$DEFINE ZEOS_DISABLE_POSTGRESQL} {.$DEFINE ZEOS_DISABLE_DBLIB} {.$DEFINE ZEOS_DISABLE_ADO} {.$DEFINE ZEOS_DISABLE_INTERBASE} {.$DEFINE ZEOS_DISABLE_SQLITE} {.$DEFINE ZEOS_DISABLE_ORACLE} {.$DEFINE ZEOS_DISABLE_ASA} // Enables MySQL support in TZConnection/TZDataset {$IFNDEF ZEOS_DISABLE_MYSQL} {$DEFINE ENABLE_MYSQL} {$ENDIF} // Enables PostgreSQL support in TZConnection/TZDataset {$IFNDEF ZEOS_DISABLE_POSTGRESQL} {$DEFINE ENABLE_POSTGRESQL} {$ENDIF} // Enables Sybase/MSSQL support in TZConnection/TZDataset {$IFNDEF ZEOS_DISABLE_DBLIB} {$DEFINE ENABLE_DBLIB} {$ENDIF} // Enables ADO support in TZConnection/TZDataset {$IFNDEF ZEOS_DISABLE_ADO} {$IFNDEF FPC} {$IFNDEF UNIX} {$DEFINE ENABLE_ADO} {$ENDIF} {$ENDIF} {$ENDIF} // Enables Interbase/Firebird support in TZConnection/TZDataset {$IFNDEF ZEOS_DISABLE_INTERBASE} {$DEFINE ENABLE_INTERBASE} {$ENDIF} // Enables SQLite support in TZConnection/TZDataset {$IFNDEF ZEOS_DISABLE_SQLITE} {$DEFINE ENABLE_SQLITE} {$ENDIF} // Enables Oracle support in TZConnection/TZDataset {$IFNDEF ZEOS_DISABLE_ORACLE} {$DEFINE ENABLE_ORACLE} {$ENDIF} // Enables ASA support in TZConnection/TZDataset {$IFNDEF ZEOS_DISABLE_ASA} {$DEFINE ENABLE_ASA} {$ENDIF} // Enables Pooled connection support for all enabled db drivers in TZConnection/TZDataset {$IFNDEF ZEOS_DISABLE_POOLED} {$DEFINE ENABLE_POOLED} {$ENDIF} // Supported language. Now available languages: // ENGLISH, GERMAN, PORTUGUESE, DUTCH, SPANISH, ROMANA, INDONESIAN, RUSSIAN, CZECH, POLISH {$DEFINE ENGLISH} // Prevents loading default libmysql.dll {.$DEFINE MYSQL_STRICT_DLL_LOADING} // Prevents loading default firebird.dll {.$DEFINE FIREBIRD_STRICT_DLL_LOADING} // Prevents loading default libpq.dll {.$DEFINE POSTGRESQL_STRICT_DLL_LOADING} //Allows to see SQL exceptions as strings {$DEFINE INTERBASE_EXTENDED_MESSAGES} // Loads libcrypt.so before Firebird client library. // It fixes error "Undefined symbol: crypt". {$DEFINE INTERBASE_CRYPT} // Excludes old ZeosDBO from the performance tests {$DEFINE EXCLUDE_OLD_ZEOS_TEST} // Excludes DBExpress from the performance tests {$DEFINE EXCLUDE_DBX_TEST} // Excludes IBX from the performance tests {$DEFINE EXCLUDE_IBX_TEST} // Excludes BDE from the performance tests {$DEFINE EXCLUDE_BDE_TEST} // Registers property editors for the components. {$DEFINE WITH_PROPERTY_EDITOR} // Turn on multithreading {$DEFINE MULTI_THREADED} // In Version 6.1.5 there are several bugs with the TZSQLMetadata-Component // For Version 6.5.0 you should uncomment the following line {$DEFINE USE_METADATA} //Default. To validate an optimal updatecount of 1. Comment this define if this //dafault behavior isn't wanted. On the other hand you can suppress this //validation by adding the line ValidateUpdateCount=-1 or FALSE or OFF into the // TZDataSet-Component.Properties(TStrings) {$DEFINE WITH_VALIDATE_UPDATE_COUNT} // A large database may have many tables, colums and/or procedures!!! // Therefore there is the ability to show a warning // before retrieving a list of these database objects {.$DEFINE SHOW_WARNING} // Use libfbclient.so under linux // and not libfbembed.so when Firebird 1.5.2 is used under linux {$DEFINE USELIBFBCLIENTSO} // Use SynEdit for the SQL Editors. // Uncomment it when you will use SynEdit instead of a MemoEdit. // The SynEdit component must be installed on your system. // You can get SynEdit at http://synedit.sourceforge.net/ {.$DEFINE USE_SYNEDIT} ================================================ FILE: lib/zeosdbo/src/ZeosLazarus.inc ================================================ {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} // Compilation directives for Lazarus {$DEFINE WITH_UNIDIRECTIONALBUG} //still buggy with IsUnidirectional prop of TDataSet FPC still moves the recordBuffer-> visit TestReadOnlyQueryUniDirectional and TZAbstractRODataset.GetRecord // These are in a spearate file as Delphi compilers don't digest the macros stuff very well {$MACRO ON} // Macros needed for FPC_VERSION and FPC_RELEASE {$MODE DELPHI} {$INTERFACES COM} {$IFDEF FPC_FULLVERSION} // FPC_FULLVERSION was added in FPC 2.2.4 {$IF FPC_FULLVERSION<=20204} {$DEFINE OLDFPC} {$IFEND} // {$IF FPC_FULLVERSION>=20400} // 2.4.0 status is unknown. 2.4.2+ should be generally fine. // {$DEFINE FPC2_4UP} // {$IFEND} {$DEFINE WITH_FTWIDESTRING} // Supported from somewhere between 2.2 and 2.4 {$IF FPC_FULLVERSION>=20500} // Upgrade to 2.6.x asap. {$DEFINE FPC2_5UP} // Used in code {$DEFINE WITH_NEWTOBJECT} {$DEFINE WITH_IPROVIDER} {$IFEND} {$IF FPC_FULLVERSION>=20600} // assumes 2.5.1 pretty close to 2.6.0. Summer 2011 or newer {$DEFINE WITH_WIDEMEMO} {$DEFINE WITH_ASLARGEINT} // tlargeint aslargeint. Fixed 2.6.0+ or 2.6.2+ probably {$DEFINE WITH_ASCURRENCY} // Has AsCurrency. {$DEFINE WITH_ASVARIANT} {$DEFINE WITH_FORMATSETTINGS} {$DEFINE WITH_WIDEFIELDS} // Wide-fields are supported (common define for ftWideString/ftWideMemo) {$DEFINE PWIDECHAR_IS_PUNICODECHAR} {$DEFINE WITH_FTGUID} //TStringField descendant TGuidField is supported {$DEFINE FPC2_6UP} {$IFEND} {$IF FPC_FULLVERSION>=20602} {$DEFINE HAVE_TBYTES} // TBytes is declared only in FPC 2.6.2 instead of 2.6.0 as declared... {$ENDIF} {$IFDEF LCL} {$DEFINE WITH_LCONVENCODING} //Only available for Lazarus {$ENDIF} {$DEFINE LAZARUSUTF8HACK} // Places that fixed for the Lazarus convention that all strings are UTF8 are marked with this // ifdef. But probably most of them are adhoc hacks, and need revisiting in time. {$DEFINE WITH_FPC_FTTIME_BUG} //http://zeos.firmos.at/viewtopic.php?t=3534&postdays=0&postorder=asc&start=0 {$DEFINE WITH_FPC_BOF_BUG} //http://bugs.freepascal.org/view.php?id=22377 {$DEFINE WITH_FPC_MODIFIED_BUG} //http://bugs.freepascal.org/view.php?id=22381 {$DEFINE WITHOUT_VARBYTESASSTRING} {$DEFINE WITH_PWIDECHAR_TOWIDESTRING} {$DEFINE WITH_CLASS_VARS} {$ELSE} {$FATAL Versions Older than 2.2.4 are not supported!} {$ENDIF} {$DEFINE WITH_FUNIDIRECTIONAL} // FPC has references a field instead of a setter here. (at least in 2.6.0) {$IFDEF FPC_FULLVERSION>20601} {$UNDEF WITH_FPC_FTTIME_BUG} //seems like the never FPC2.6.2 also have fixed the NativData bug for TTimeFields+TDataSet {$ENDIF} {$IF FPC_FULLVERSION>20602} // will be introduced in 2.6.2 (and up to date 2.6.1) {$DEFINE WITH_INLINE} // compiler supports inline methodes {$IFEND} {$IF FPC_FULLVERSION>20700} // will be introduced in 2.7+ {$DEFINE WITH_TRECORDBUFFER} {$DEFINE WITH_TBOOKMARK} // Have TBookmark {$UNDEF WITH_FPC_BOF_BUG} {$UNDEF WITH_FPC_MODIFIED_BUG} {$DEFINE WITH_RAWBYTESTRING} // Have RawByteString CP $FFFFF {$DEFINE WITH_FPC_STRING_CONVERSATION} //After string conversations to RawByteString like AnsiZoUTF8 the results are equal to original value {$DEFINE WITH_DEFAULTSYSTEMCODEPAGE} {$DEFINE MISS_RBS_SETSTRING_OVERLOAD} //SetString overload for RawByteString is missing {$IFNDEF FPC_HAS_BUILTIN_WIDESTR_MANAGER} //Hack for *nix systems where i couldn't locate this define )): {$DEFINE FPC_HAS_BUILTIN_WIDESTR_MANAGER} {$ENDIF} {$IFEND} // todo // VIRTUALSETFIELDDATA: in nativeformat versions of SETFIELDDATA, inherited wasn't called. // Afaik that methoid is virtual in FPC since December 2006, and there is no comment why // it was ifdefed. We'll leave it off, and see if sb complains. // LAZARUSUTF8HACK : Places that fixed for the Lazarus convention that all strings are UTF8 are marked with this // ifdef. But probably most of them are adhoc hacks, and need constant reevaluation. // OLDFPC : IFDEF FPC's so old that I can't remember which version are put under IFDEF OLDFPC. In time these // blocks can be killed. {$IF defined(WITH_LCONVENCODING) and (defined(MSWINDOWS) or defined(FPC_HAS_BUILTIN_WIDESTR_MANAGER))} {$UNDEF WITH_LCONVENCODING} {$IFEND} {$IFDEF WITH_LCONVENCODING} {$IF declared(lcl_fullversion)} {$if lcl_fullversion>=1000000} //Lazarus >= 1.0.0 with delphi fix. {$DEFINE LCONVENCODING_HAS_CP852_FUNCTIONS} {$ifend} {$ifend} {$ENDIF} ================================================ FILE: lib/zeosdbo/src/component/ZAbstractConnection.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Database Connection Component } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZAbstractConnection; interface {$I ZComponent.inc} uses Types, {$IFNDEF UNIX} {$IFDEF ENABLE_ADO} ZDbcAdo, {$ENDIF} {$ENDIF} {$IFDEF ENABLE_DBLIB} ZDbcDbLib, {$ENDIF} {$IFDEF ENABLE_MYSQL} ZDbcMySql, {$ENDIF} {$IFDEF ENABLE_POSTGRESQL} ZDbcPostgreSql, {$ENDIF} {$IFDEF ENABLE_INTERBASE} ZDbcInterbase6, {$ENDIF} {$IFDEF ENABLE_SQLITE} ZDbcSqLite, {$ENDIF} {$IFDEF ENABLE_ORACLE} ZDbcOracle, {$ENDIF} {$IFDEF ENABLE_ASA} ZDbcASA, {$ENDIF} {$IFDEF ENABLE_POOLED} ZDbcPooled, {$ENDIF} SysUtils, Classes, {$IFDEF MSEgui}mclasses, mdb{$ELSE}DB{$ENDIF}, ZDbcIntfs, ZCompatibility, ZURL; type //HA 090811 New Type TZLoginEvent to make Username and Password persistent TZLoginEvent = procedure(Sender: TObject; var Username:string ; var Password: string) of object; {** Represents a component which wraps a connection to database. } { TZAbstractConnection } TZAbstractConnection = class(TComponent) private FUseMetaData: Boolean; {$IFNDEF UNICODE}FAutoEncode: Boolean;{$ENDIF} FControlsCodePage: TZControlsCodePage; {$IFDEF ZEOS_TEST_ONLY} FTestMode: Byte; {$ENDIF} function GetVersion: string; procedure SetUseMetadata(AValue: Boolean); procedure SetVersion(const Value: string); procedure SetControlsCodePage(const Value: TZControlsCodePage); protected FURL: TZURL; FCatalog: string; FAutoCommit: Boolean; FReadOnly: Boolean; FTransactIsolationLevel: TZTransactIsolationLevel; FConnection: IZConnection; FDatasets: TList; // Modified by cipto 8/1/2007 1:44:22 PM FSequences: TList; FLoginPrompt: Boolean; FStreamedConnected: Boolean; FExplicitTransactionCounter: Integer; FSQLHourGlass: Boolean; FDesignConnection: Boolean; FBeforeConnect: TNotifyEvent; FBeforeDisconnect: TNotifyEvent; FAfterDisconnect: TNotifyEvent; FAfterConnect: TNotifyEvent; FBeforeReconnect: TNotifyEvent; FAfterReconnect: TNotifyEvent; FOnCommit: TNotifyEvent; FOnRollback: TNotifyEvent; FOnStartTransaction: TNotifyEvent; //HA 090811 Change Type of FOnLogin to new TZLoginEvent //FOnLogin: TLoginEvent; FOnLogin: TZLoginEvent; FClientCodepage: String; function GetAutoEncode: Boolean; procedure SetAutoEncode(Value: Boolean); function GetHostName: string; procedure SetHostName(const Value: String); function GetConnPort: Integer; procedure SetConnPort(const Value: Integer); function GetDatabase: string; procedure SetDatabase(const Value: String); function GetUser: string; procedure SetUser(const Value: String); function GetPassword: string; procedure SetPassword(const Value: String); function GetLibLocation: String; procedure SetLibLocation(const Value: String); function GetProtocol: String; procedure SetProtocol(const Value: String); function GetProperties: TStrings; function GetConnected: Boolean; procedure SetConnected(Value: Boolean); procedure SetProperties(Value: TStrings); procedure SetTransactIsolationLevel(Value: TZTransactIsolationLevel); procedure SetAutoCommit(Value: Boolean); function GetDbcDriver: IZDriver; function GetInTransaction: Boolean; function GetClientVersion: Integer; function GetServerVersion: Integer; function GetClientVersionStr: String; function GetServerVersionStr: String; procedure DoBeforeConnect; procedure DoAfterConnect; procedure DoBeforeDisconnect; procedure DoAfterDisconnect; procedure DoBeforeReconnect; procedure DoAfterReconnect; procedure DoCommit; procedure DoRollback; procedure DoStartTransaction; procedure CheckConnected; procedure CheckAutoCommitMode; procedure CheckNonAutoCommitMode; function ConstructURL(const UserName, Password: string): string; procedure CloseAllDataSets; procedure UnregisterAllDataSets; // Modified by cipto 8/1/2007 1:48:17 PM procedure CloseAllSequences; //////////////////////////////////////// procedure Notification(AComponent: TComponent; Operation: TOperation); override; procedure Loaded; override; property StreamedConnected: Boolean read FStreamedConnected write FStreamedConnected; procedure SetClientCodePage(Const Value: String); //Egonhugeist public constructor Create(AOwner: TComponent); override; destructor Destroy; override; procedure Connect; virtual; procedure Disconnect; virtual; procedure Reconnect; function Ping: Boolean; virtual; procedure StartTransaction; virtual; procedure Commit; virtual; procedure Rollback; virtual; procedure PrepareTransaction(const transactionid: string); virtual; procedure CommitPrepared(const transactionid: string); virtual; procedure RollbackPrepared(const transactionid: string); virtual; function PingServer: Boolean; virtual; procedure RegisterDataSet(DataSet: TDataset); procedure UnregisterDataSet(DataSet: TDataset); function ExecuteDirect(SQL:string):boolean;overload; function ExecuteDirect(SQL:string; var RowsAffected:integer):boolean;overload; // Modified by cipto 8/2/2007 10:16:50 AM procedure RegisterSequence(Sequence: TComponent); procedure UnregisterSequence(Sequence: TComponent); /////////////////////////////////////////////////// procedure GetProtocolNames(List: TStrings); procedure GetCatalogNames(List: TStrings); procedure GetSchemaNames(List: TStrings); procedure GetTableNames(const Pattern: string; List: TStrings);overload; procedure GetTableNames(const schemaPattern, tablePattern: string; List: TStrings);overload; procedure GetTableNames(const schemaPattern, tablePattern: string; Types: TStringDynArray; List: TStrings);overload; procedure GetColumnNames(const TablePattern, ColumnPattern: string; List: TStrings); procedure GetStoredProcNames(const Pattern: string; List: TStrings); procedure GetTriggerNames(const TablePattern, SchemaPattern: string; List: TStrings); //EgonHugeist function GetBinaryEscapeStringFromString(const BinaryString: AnsiString): String; overload; function GetBinaryEscapeStringFromStream(const Stream: TStream): String; overload; function GetBinaryEscapeStringFromFile(const FileName: String): String; overload; function GetAnsiEscapeString(const Ansi: AnsiString): String; function GetURL: String; property InTransaction: Boolean read GetInTransaction; property HostName: string read GetHostName write SetHostName; property Port: Integer read GetConnPort write SetConnPort; property Database: string read GetDatabase write SetDatabase; property User: string read GetUser write SetUser; property Password: string read GetPassword write SetPassword; property Protocol: string read GetProtocol write SetProtocol; property LibLocation: string read GetLibLocation write SetLibLocation; property DbcDriver: IZDriver read GetDbcDriver; property DbcConnection: IZConnection read FConnection; property ClientVersion: Integer read GetClientVersion; property ServerVersion: Integer read GetServerVersion; property ClientVersionStr: String read GetClientVersionStr; property ServerVersionStr: String read GetServerVersionStr; procedure ShowSQLHourGlass; procedure HideSQLHourGlass; published property ControlsCodePage: TZControlsCodePage read FControlsCodePage write SetControlsCodePage; property AutoEncodeStrings: Boolean read GetAutoEncode write SetAutoEncode default True; property ClientCodepage: String read FClientCodepage write SetClientCodePage; //EgonHugeist property Catalog: string read FCatalog write FCatalog; property Properties: TStrings read GetProperties write SetProperties; property AutoCommit: Boolean read FAutoCommit write SetAutoCommit default True; property ReadOnly: Boolean read FReadOnly write FReadOnly default False; property UseMetadata: Boolean read FUseMetaData write SetUseMetadata default true; property TransactIsolationLevel: TZTransactIsolationLevel read FTransactIsolationLevel write SetTransactIsolationLevel default tiNone; property Connected: Boolean read GetConnected write SetConnected default False; property LoginPrompt: Boolean read FLoginPrompt write FLoginPrompt default False; property Version: string read GetVersion write SetVersion stored False; property DesignConnection: Boolean read FDesignConnection write FDesignConnection default False; property BeforeConnect: TNotifyEvent read FBeforeConnect write FBeforeConnect; property AfterConnect: TNotifyEvent read FAfterConnect write FAfterConnect; property BeforeDisconnect: TNotifyEvent read FBeforeDisconnect write FBeforeDisconnect; property AfterDisconnect: TNotifyEvent read FAfterDisconnect write FAfterDisconnect; property BeforeReconnect: TNotifyEvent read FBeforeReconnect write FBeforeReconnect; property AfterReconnect: TNotifyEvent read FAfterReconnect write FAfterReconnect; property SQLHourGlass: Boolean read FSQLHourGlass write FSQLHourGlass default False; property OnCommit: TNotifyEvent read FOnCommit write FOnCommit; property OnRollback: TNotifyEvent read FOnRollback write FOnRollback; //HA 090811 Change Type of FOnLogin to new TZLoginEvent //property OnLogin: TLoginEvent read FOnLogin write FOnLogin; property OnLogin: TZLoginEvent read FOnLogin write FOnLogin; property OnStartTransaction: TNotifyEvent read FOnStartTransaction write FOnStartTransaction; {$IFDEF ZEOS_TEST_ONLY} property TestMode : Byte read FTestMode write FTestMode; {$ENDIF} end; implementation uses ZMessages, ZClasses, ZAbstractRODataset, ZSysUtils, // Modified by cipto 8/2/2007 10:00:22 AM ZSequence, ZAbstractDataset, ZEncoding; var SqlHourGlassLock: Integer; CursorBackup: TDBScreenCursor; { TZAbstractConnection } {** Constructs this component and assignes the main properties. @param AOwner an owner component. } constructor TZAbstractConnection.Create(AOwner: TComponent); begin {$IFDEF UNICODE} FControlsCodePage := cCP_UTF16; {$ELSE} {$IFDEF FPC} FControlsCodePage := cCP_UTF8; {$ELSE} FControlsCodePage := cGET_ACP; {$ENDIF} {$ENDIF} FURL := TZURL.Create; inherited Create(AOwner); FAutoCommit := True; FReadOnly := False; FTransactIsolationLevel := tiNone; FConnection := nil; FUseMetadata := True; FDatasets := TList.Create; // Modified by cipto 8/1/2007 1:45:56 PM FSequences:= TList.Create; FLoginPrompt := False; FDesignConnection := False; end; {** Destroys this component and cleanups the memory. } destructor TZAbstractConnection.Destroy; begin Disconnect; UnregisterAllDataSets; FDatasets.Free; FURL.Free; // Modified by cipto 8/1/2007 1:47:37 PM FSequences.Clear; FSequences.Free; //////////////////////////////////////// inherited Destroy; end; function TZAbstractConnection.GetHostName: string; begin Result := FURL.HostName; end; procedure TZAbstractConnection.SetHostName(const Value: String); begin FURL.HostName := Value; end; function TZAbstractConnection.GetConnPort: Integer; begin Result := FURL.Port; end; procedure TZAbstractConnection.SetConnPort(const Value: Integer); begin FURL.Port := Value; end; function TZAbstractConnection.GetDatabase: string; begin Result := FURL.Database; end; procedure TZAbstractConnection.SetDatabase(const Value: String); begin FURL.Database := Value; end; function TZAbstractConnection.GetUser: string; begin Result := FURL.UserName; end; procedure TZAbstractConnection.SetUser(const Value: String); begin FURL.UserName := Value; end; function TZAbstractConnection.GetPassword: string; begin Result := FURL.Password; end; procedure TZAbstractConnection.SetPassword(const Value: String); begin FURL.Password := Value; end; function TZAbstractConnection.GetLibLocation: String; begin Result := FURL.LibLocation; end; procedure TZAbstractConnection.SetLibLocation(const Value: String); begin FURL.LibLocation := Value; end; function TZAbstractConnection.GetProtocol: String; begin Result := FURL.Protocol; end; procedure TZAbstractConnection.SetProtocol(const Value: String); begin FURL.Protocol := Value; end; function TZAbstractConnection.GetProperties: TStrings; begin Result := FURL.Properties; end; {** This methode is required to support proper component initialization. Without it, the connection can start connecting before every property is loaded! } procedure TZAbstractConnection.Loaded; begin inherited Loaded; try if FStreamedConnected then if (csDesigning in ComponentState) or not FDesignConnection then SetConnected(True); except if csDesigning in ComponentState then if Assigned(Classes.ApplicationHandleException) then Classes.ApplicationHandleException(ExceptObject) else ShowException(ExceptObject, ExceptAddr) else raise; end; end; {** EgonHugeist: Sets the ClientCode-Page-Property and adds or corrects it in the Info(Properties)-Strings @param string the ClientCharacterSet } procedure TZAbstractConnection.SetClientCodePage(Const Value: String); begin if ( Value = 'Not Connected!' ) or ( Value = 'Not implementet!' ) then //possible! -> result of PropertyEditor if not complete yet //Later we should remove this if the MeataData/Plaindriver-Informations //where complete FClientCodepage := Trim(FURL.Properties.Values['codepage']) else Self.FClientCodepage := Value; if ( Trim(FURL.Properties.Values['codepage']) <> FClientCodepage ) then FURL.Properties.Values['codepage'] := FClientCodepage; end; {** Gets an open connection flag. @return True if the connection is open or False otherwise. } function TZAbstractConnection.GetConnected: Boolean; begin Result := (FConnection <> nil) and not FConnection.IsClosed; end; {** Sets a new open connection flag. @param Value True to open the connection and False to close it. } procedure TZAbstractConnection.SetConnected(Value: Boolean); begin if (csReading in ComponentState) and Value then FStreamedConnected := True else begin if Value <> GetConnected then begin if Value then Connect else Disconnect; end; end; end; {** Sets a new connection properties. @param Value a list with new connection properties. } procedure TZAbstractConnection.SetProperties(Value: TStrings); begin if Value <> nil then begin if ( Trim(Value.Values['codepage']) <> '' ) then FClientCodepage := Trim(Value.Values['codepage']) else Value.Values['codepage'] := FClientCodepage; { check autoencodestrings } {$IF (defined(MSWINDOWS) or defined(WITH_LCONVENCODING) or defined(FPC_HAS_BUILTIN_WIDESTR_MANAGER)) and not defined(UNICODE)} if Connected then DbcConnection.AutoEncodeStrings := Value.Values['AutoEncodeStrings'] = 'ON'; FAutoEncode := Value.Values['AutoEncodeStrings'] = 'ON'; {$ELSE} {$IFDEF UNICODE} Value.Values['AutoEncodeStrings'] := 'ON'; {$ELSE} Value.Values['AutoEncodeStrings'] := ''; {$ENDIF} {$IFEND} if Value.IndexOf('controls_cp') = -1 then {$IFDEF UNICODE} if ControlsCodePage = cCP_UTF16 then Value.values['controls_cp'] := 'CP_UTF16' else Value.values['controls_cp'] := 'GET_ACP' {$ELSE} case ControlsCodePage of //automated check.. cCP_UTF16: Value.values['controls_cp'] := 'CP_UTF16'; cCP_UTF8: Value.values['controls_cp'] := 'CP_UTF8'; cGET_ACP: Value.values['controls_cp'] := 'GET_ACP'; end {$ENDIF} else {$IFDEF UNICODE} if Value.values['controls_cp'] = 'CP_UTF8' then begin Value.values['controls_cp'] := 'CP_UTF16'; FControlsCodePage := cCP_UTF16; end; {$ELSE} {$IFNDEF WITH_WIDEFIELDS} //old FPC and D7 if Value.values['controls_cp'] = 'CP_UTF16' then begin FControlsCodePage := cGET_ACP; Value.values['controls_cp'] := {$IFDEF DLEPHI}'GET_ACP'{$ELSE}'CP_UTF8'{$ENDIF}; end; {$ELSE} if Value.values['controls_cp'] = 'GET_ACP' then FControlsCodePage := cGET_ACP else if Value.values['controls_cp'] = 'CP_UTF8' then FControlsCodePage := cCP_UTF8 else if Value.values['controls_cp'] = 'CP_UTF16' then FControlsCodePage := cCP_UTF16 else case ControlsCodePage of //automated check.. cCP_UTF16: Value.values['controls_cp'] := 'CP_UTF16'; cCP_UTF8: Value.values['controls_cp'] := 'CP_UTF8'; cGET_ACP: Value.values['controls_cp'] := 'GET_ACP'; end; {$ENDIF} {$ENDIF} FURL.Properties.Text := Value.Text; end else FURL.Properties.Clear; end; {** Sets autocommit flag. @param Value True to turn autocommit on. } procedure TZAbstractConnection.SetAutoCommit(Value: Boolean); begin if FAutoCommit <> Value then begin if FExplicitTransactionCounter > 0 then raise Exception.Create(SInvalidOperationInTrans); FAutoCommit := Value; ShowSQLHourGlass; try if FConnection <> nil then FConnection.SetAutoCommit(Value); finally HideSqlHourGlass end; end; end; {** Sets transact isolation level. @param Value a transact isolation level. } procedure TZAbstractConnection.SetTransactIsolationLevel( Value: TZTransactIsolationLevel); begin if FTransactIsolationLevel <> Value then begin FTransactIsolationLevel := Value; ShowSqlhourGlass; try if FConnection <> nil then FConnection.SetTransactionIsolation(Value); finally HideSqlHourGlass end; end; end; {** Gets a ZDBC driver for the specified protocol. @returns a ZDBC driver interface. } function TZAbstractConnection.GetDbcDriver: IZDriver; begin if FConnection <> nil then Result := FConnection.GetDriver else Result := DriverManager.GetDriver(ConstructURL('', '')); end; {** Checks is the connection started a transaction. @returns True if connection in manual transaction mode and transaction is started. } function TZAbstractConnection.GetInTransaction: Boolean; begin CheckConnected; Result := not FAutoCommit or (FExplicitTransactionCounter > 0); end; {** Gets client's full version number. The format of the version resturned must be XYYYZZZ where X = Major version YYY = Minor version ZZZ = Sub version @return this clients's full version number } function TZAbstractConnection.GetClientVersion: Integer; begin if FConnection <> nil then Result := DbcConnection.GetClientVersion else Result := DriverManager.GetClientVersion(ConstructURL('', '')); end; {** Gets server's full version number. The format of the version resturned must be XYYYZZZ where X = Major version YYY = Minor version ZZZ = Sub version @return this clients's full version number } function TZAbstractConnection.GetServerVersion: Integer; begin CheckConnected; Result := DbcConnection.GetHostVersion; end; {** Gets client's full version number. The format of the version resturned must be XYYYZZZ where X = Major version YYY = Minor version ZZZ = Sub version @return this clients's full version number } function TZAbstractConnection.GetClientVersionStr: String; begin Result := FormatSQLVersion(GetClientVersion); end; {** Gets server's full version number. The format of the version resturned must be XYYYZZZ where X = Major version YYY = Minor version ZZZ = Sub version @return this clients's full version number } function TZAbstractConnection.GetServerVersionStr: String; begin Result := FormatSQLVersion(GetServerVersion); end; {** Constructs ZDBC connection URL string. @param UserName a name of the user. @param Password a user password. @returns a constructed connection URL. } function TZAbstractConnection.ConstructURL(const UserName, Password: string): string; begin Result := DriverManager.ConstructURL(FURL.Protocol, FURL.HostName, FURL.Database, UserName, Password, FURL.Port, FURL.Properties, FURL.LibLocation); end; {** Fires an event before connection open } procedure TZAbstractConnection.DoBeforeConnect; begin if Assigned(FBeforeConnect) then FBeforeConnect(Self); end; {** Fires an event after connection open } procedure TZAbstractConnection.DoAfterConnect; begin if Assigned(FAfterConnect) then FAfterConnect(Self); end; {** Fires an event before connection close } procedure TZAbstractConnection.DoBeforeDisconnect; begin if Assigned(FBeforeDisconnect) then FBeforeDisconnect(Self); end; {** Fires an event after connection close } procedure TZAbstractConnection.DoAfterDisconnect; begin if Assigned(FAfterDisconnect) then FAfterDisconnect(Self); end; {** Fires an event before reconnect } procedure TZAbstractConnection.DoBeforeReconnect; begin if Assigned(FBeforeReconnect) then FBeforeReconnect(Self); end; {** Fires an event after reconnect } procedure TZAbstractConnection.DoAfterReconnect; begin if Assigned(FAfterReconnect) then FAfterReconnect(Self); end; {** Fires an event after transaction commit } procedure TZAbstractConnection.DoCommit; begin if Assigned(FOnCommit) then FOnCommit(Self); end; {** Fires an event after transaction rollback } procedure TZAbstractConnection.DoRollback; begin if Assigned(FOnRollback) then FOnRollback(Self); end; {** Fires an event after transaction start } procedure TZAbstractConnection.DoStartTransaction; begin if Assigned(FOnStartTransaction) then FOnStartTransaction(Self); end; {** Establish a connection with database. } procedure TZAbstractConnection.Connect; var //Local variables declared in order to preserve the original property value //and to avoid the storage of password Username, Password: string; begin if FConnection = nil then begin // Fixes Zeos Bug 00056 // try DoBeforeConnect; // except //This is here to support aborting the Connection in BeforeConnect event without fatal errors // on E: EAbort do // Exit; // end; UserName := FURL.UserName; Password := FURL.Password; if FLoginPrompt then begin if Assigned(FOnLogin) then FOnLogin(Self, UserName, Password) else begin if Assigned(LoginDialogProc) then begin if not LoginDialogProc(FURL.Database, UserName, Password) then Exit; end else raise Exception.Create(SLoginPromptFailure); end; end; ShowSqlHourGlass; try FConnection := DriverManager.GetConnectionWithParams( ConstructURL(UserName, Password), FURL.Properties); try with FConnection do begin SetAutoCommit(FAutoCommit); SetReadOnly(FReadOnly); SetCatalog(FCatalog); SetTransactionIsolation(FTransactIsolationLevel); SetUseMetadata(FUseMetadata); Open; {$IFDEF ZEOS_TEST_ONLY} SetTestMode(FTestMode); {$ENDIF} end; except FConnection := nil; raise; end; finally HideSqlHourGlass; end; if not FConnection.IsClosed then DoAfterConnect; end; end; {** Closes and removes the connection with database } procedure TZAbstractConnection.Disconnect; begin if FConnection <> nil then begin DoBeforeDisconnect; ShowSqlHourGlass; try CloseAllDataSets; // Modified by cipto 8/2/2007 10:11:02 AM CloseAllSequences; FConnection.Close; finally FConnection := nil; HideSqlHourGlass; end; DoAfterDisconnect; end; end; {** Sends a ping to the server. } function TZAbstractConnection.Ping: Boolean; begin Result := (FConnection <> nil) and (FConnection.PingServer=0); end; {** Reconnect, doesn't destroy DataSets if successful. } procedure TZAbstractConnection.Reconnect; begin if FConnection <> nil then begin DoBeforeReconnect; ShowSqlHourGlass; try try FConnection.Close; FConnection.Open; except CloseAllDataSets; raise; end; finally HideSqlHourGlass; end; DoAfterReconnect; end; end; {** Checks if this connection is active. } procedure TZAbstractConnection.CheckConnected; begin if FConnection = nil then raise EZDatabaseError.Create(SConnectionIsNotOpened); end; {** Checks if this connection is in auto-commit mode. } procedure TZAbstractConnection.CheckNonAutoCommitMode; begin if FAutoCommit then raise EZDatabaseError.Create(SInvalidOpInAutoCommit); end; {** Checks if this connection is in auto-commit mode. } procedure TZAbstractConnection.CheckAutoCommitMode; begin if not FAutoCommit and (FExplicitTransactionCounter = 0) then raise EZDatabaseError.Create(SInvalidOpInNonAutoCommit); end; {** Commits the current transaction. } procedure TZAbstractConnection.StartTransaction; begin CheckAutoCommitMode; if FExplicitTransactionCounter = 0 then AutoCommit := False; DoStartTransaction; Inc(FExplicitTransactionCounter); end; {** Commits the current transaction. } type //To get protected methodes THack_ZAbstractDataset = Class(TZAbstractDataset); procedure TZAbstractConnection.Commit; var ExplicitTran: Boolean; i: Integer; begin CheckConnected; CheckNonAutoCommitMode; ExplicitTran := FExplicitTransactionCounter > 0; if FExplicitTransactionCounter < 2 then //when 0 then AutoCommit was turned off, when 1 StartTransaction was used begin ShowSQLHourGlass; try try for i := 0 to FDatasets.Count -1 do if Assigned(FDatasets[i]) then if TObject(FDatasets[i]) is TZAbstractDataset then THack_ZAbstractDataset(FDatasets[i]).DisposeCachedUpdates; FConnection.Commit; finally FExplicitTransactionCounter := 0; if ExplicitTran then AutoCommit := True; end; finally HideSQLHourGlass; end; DoCommit; end else Dec(FExplicitTransactionCounter); end; procedure TZAbstractConnection.CommitPrepared(const transactionid: string); var oldlev: TZTransactIsolationLevel; begin CheckAutoCommitMode; oldlev := TransactIsolationLevel; TransactIsolationLevel := tiNone; FConnection.CommitPrepared(transactionid); TransactIsolationLevel := oldLev; end; {** Rollbacks the current transaction. } procedure TZAbstractConnection.Rollback; var ExplicitTran: Boolean; begin CheckConnected; CheckNonAutoCommitMode; ExplicitTran := FExplicitTransactionCounter > 0; if FExplicitTransactionCounter < 2 then //when 0 then AutoCommit was turned off, when 1 StartTransaction was used begin ShowSQLHourGlass; try try FConnection.RollBack; finally FExplicitTransactionCounter := 0; if ExplicitTran then AutoCommit := True; end; finally HideSQLHourGlass; end; DoRollback; end else Dec(FExplicitTransactionCounter); end; procedure TZAbstractConnection.RollbackPrepared(const transactionid: string); var oldlev: TZTransactIsolationLevel; begin CheckAutoCommitMode; oldlev := TransactIsolationLevel; TransactIsolationLevel := tiNone; FConnection.RollbackPrepared(transactionid); TransactIsolationLevel := oldLev; end; {** Processes component notifications. @param AComponent a changed component object. @param Operation a component operation code. } procedure TZAbstractConnection.Notification(AComponent: TComponent; Operation: TOperation); begin inherited Notification(AComponent, Operation); if (Operation = opRemove) then begin if (AComponent is TDataset) then UnregisterDataSet(TDataset(AComponent)); if (AComponent is TZSequence) then UnregisterSequence(TZSequence(AComponent)); end; end; Function TZAbstractConnection.PingServer: Boolean; var LastState : boolean; begin Result := false; // Check connection status LastState := GetConnected; If FConnection <> Nil Then Begin Result := (FConnection.PingServer=0); // Connection now is false but was true If (Not Result) And (LastState) Then // Generate OnDisconnect event SetConnected(Result); End Else // Connection now is false but was true If LastState Then SetConnected(false); end; procedure TZAbstractConnection.PrepareTransaction(const transactionid: string); {var ExplicitTran: Boolean;} begin CheckConnected; CheckNonAutoCommitMode; if FExplicitTransactionCounter <> 1 then begin raise EZDatabaseError.Create(SInvalidOpPrepare); end; ShowSQLHourGlass; try try FConnection.PrepareTransaction(transactionid); finally FExplicitTransactionCounter := 0; AutoCommit := True; end; finally HideSQLHourGlass; end; end; {** Closes all registered datasets. } procedure TZAbstractConnection.CloseAllDataSets; var I: Integer; Current: TZAbstractRODataset; begin for I := 0 to FDatasets.Count - 1 do begin Current := TZAbstractRODataset(FDatasets[I]); try Current.UnPrepare; Current.Close; except // Ignore. end; end; end; {** Registers a new dataset object. @param DataSet a new dataset to be registered. } procedure TZAbstractConnection.RegisterDataSet(DataSet: TDataset); begin FDatasets.Add(DataSet); end; {** Unregisters a new dataset object. @param DataSet a new dataset to be unregistered. } procedure TZAbstractConnection.UnregisterDataSet(DataSet: TDataset); begin FDatasets.Remove(DataSet); end; {** Unregisters all dataset objects. } procedure TZAbstractConnection.UnregisterAllDataSets; var I: Integer; Current: TZAbstractRODataset; begin for I := FDatasets.Count - 1 downto 0 do begin Current := TZAbstractRODataset(FDatasets[I]); FDatasets.Remove(Current); try Current.Connection := nil; except // Ignore. end; end; end; {** Turn on sql hourglass cursor } procedure TZAbstractConnection.ShowSQLHourGlass; begin if not FSqlHourGlass then Exit; if SqlHourGlassLock = 0 then begin if Assigned(DBScreen) then begin CursorBackup := DBScreen.Cursor; if CursorBackup <> dcrOther then DBScreen.Cursor := dcrSQLWait; end; end; Inc(SqlHourGlassLock); end; {** Turn off sql hourglass cursor } procedure TZAbstractConnection.HideSQLHourGlass; begin if not FSqlHourGlass then Exit; if SqlHourGlassLock > 0 then Dec(SqlHourGlassLock); if SqlHourGlassLock = 0 then begin if CursorBackup <> dcrOther then if Assigned(DBScreen) then DBScreen.Cursor := CursorBackup; end; end; {** Fills string list with registered protocol names. @param List a string list to fill out. } procedure TZAbstractConnection.GetProtocolNames(List: TStrings); var I, J: Integer; Drivers: IZCollection; Driver: IZDriver; Protocols: TStringDynArray; begin List.Clear; Protocols := nil; // Makes compiler happy Drivers := DriverManager.GetDrivers; for I := 0 to Drivers.Count - 1 do begin Driver := Drivers[I] as IZDriver; Protocols := Driver.GetSupportedProtocols; for J := Low(Protocols) to High(Protocols) do List.Add(Protocols[J]); end; end; {** Fills string list with catalog names. @param List a string list to fill out. } procedure TZAbstractConnection.GetCatalogNames(List: TStrings); var Metadata: IZDatabaseMetadata; ResultSet: IZResultSet; begin CheckConnected; List.Clear; Metadata := DbcConnection.GetMetadata; ResultSet := Metadata.GetCatalogs; while ResultSet.Next do List.Add(ResultSet.GetStringByName('TABLE_CAT')); end; {** Fills string list with schema names. @param List a string list to fill out. } procedure TZAbstractConnection.GetSchemaNames(List: TStrings); var Metadata: IZDatabaseMetadata; ResultSet: IZResultSet; begin CheckConnected; List.Clear; Metadata := DbcConnection.GetMetadata; ResultSet := Metadata.GetSchemas; while ResultSet.Next do List.Add(ResultSet.GetStringByName('TABLE_SCHEM')); end; {** Fills string list with table names. @param Pattern a pattern for table names. @param List a string list to fill out. } procedure TZAbstractConnection.GetTableNames(const Pattern: string; List: TStrings); begin GetTableNames('', Pattern, nil, List); end; {** Fills string list with table names. @param tablePattern a pattern for table names. @param schemaPattern a pattern for schema names. @param List a string list to fill out. } procedure TZAbstractConnection.GetTableNames(const schemaPattern, tablePattern: string; List: TStrings); begin GetTableNames(schemaPattern, tablePattern, nil,List); end; {** Fills string list with table names. @param tablePattern a pattern for table names. @param schemaPattern a pattern for schema names. @param types a TStringDynArray specifying the table types to look for. possible values can be found by reading TZAbstractConnection.DbcConnection.GetMetadata.GetTableTypes eg. for PostGreSQL this includes :'TABLE', 'VIEW', 'INDEX', 'SEQUENCE', 'SYSTEM TABLE', 'SYSTEM TOAST TABLE', 'SYSTEM TOAST INDEX', 'SYSTEM VIEW', 'SYSTEM INDEX', 'TEMPORARY TABLE', 'TEMPORARY INDEX' @param List a string list to fill out. } procedure TZAbstractConnection.GetTableNames(const schemaPattern, tablePattern: string; Types: TStringDynArray; List: TStrings); var Metadata: IZDatabaseMetadata; ResultSet: IZResultSet; begin CheckConnected; List.Clear; Metadata := DbcConnection.GetMetadata; ResultSet := Metadata.GetTables('', schemaPattern, tablePattern, types); while ResultSet.Next do List.Add(ResultSet.GetStringByName('TABLE_NAME')); end; {** Fills string list with column names. @param TablePattern a pattern for table names. @param ColumnPattern a pattern for column names. @param List a string list to fill out. } procedure TZAbstractConnection.GetColumnNames(const TablePattern, ColumnPattern: string; List: TStrings); var Metadata: IZDatabaseMetadata; ResultSet: IZResultSet; begin CheckConnected; List.Clear; Metadata := DbcConnection.GetMetadata; ResultSet := Metadata.GetColumns('', '', TablePattern, ColumnPattern); while ResultSet.Next do List.Add(ResultSet.GetStringByName('COLUMN_NAME')); end; {** Fills string list with stored procedure names. @param Pattern a pattern for table names. @param List a string list to fill out. } procedure TZAbstractConnection.GetStoredProcNames(const Pattern: string; List: TStrings); var Metadata: IZDatabaseMetadata; ResultSet: IZResultSet; begin CheckConnected; List.Clear; Metadata := DbcConnection.GetMetadata; ResultSet := Metadata.GetProcedures('', '', Pattern); while ResultSet.Next do List.Add(ResultSet.GetStringByName('PROCEDURE_NAME')); end; {** EgonHugeist Returns Database-Triggers @Param TablePattern is a "like"-pattern to get Triggers of specified Table @SchemaPattern is Pattern to filter Schema-Trigger @List the Result-Trigger-List } procedure TZAbstractConnection.GetTriggerNames(const TablePattern, SchemaPattern: string; List: TStrings); begin CheckConnected; List.Clear; with DbcConnection.GetMetadata.GetTriggers('', SchemaPattern, TablePattern, '') do begin while Next do List.Add(GetStringByName('TRIGGER_NAME')); Close; end; end; {** EgonHugeist: Returns a EscapeState detectable String to inform the Tokenizer to do no UTF8Encoding if neccessary @param BinaryString Represents the BinaryString wich has to prepered @Result: A Prepared String like '~<|1023|<~''Binary-data-string(1023 Bytes)''~<|1023|<~ } function TZAbstractConnection.GetBinaryEscapeStringFromString(const BinaryString: AnsiString): String; begin CheckConnected; if Assigned(FConnection) then Result := FConnection.GetBinaryEscapeString(BinaryString); end; {** EgonHugeist: Returns a BinaryState detectable String to inform the Tokenizer to do no UTF8Encoding if neccessary @param Strem Represents the Stream wich has to prepered @Result: A Prepared String like '~<|1023|<~''Binary-data-string(1023 Char's)''~<|1023|<~ } function TZAbstractConnection.GetBinaryEscapeStringFromStream(const Stream: TStream): String; var FBlobSize: Integer; FBlobData: Pointer; TempAnsi: AnsiString; begin CheckConnected; if Assigned(FConnection) then begin if Assigned(Stream) then begin FBlobSize := Stream.Size; if FBlobSize > 0 then begin GetMem(FBlobData, FBlobSize); Stream.Position := 0; Stream.ReadBuffer(FBlobData^, FBlobSize); end else FBlobData := nil; end else begin FBlobSize := -1; FBlobData := nil; end; if (FBlobSize > 0) and Assigned(FBlobData) then System.SetString(TempAnsi, PAnsiChar(FBlobData), FBlobSize) else TempAnsi := ''; if Assigned(FBlobData) then FreeMem(FBlobData); Result := FConnection.GetBinaryEscapeString(TempAnsi); end; end; {** EgonHugeist: Returns a BinaryState detectable String to inform the Tokenizer to do no UTF8Encoding if neccessary @param FileNaem Represents the File wich has to prepered @Result: A Prepared String like '~<|1023|<~''Binary-data-string(1023 Char's)''~<|1023|<~ } function TZAbstractConnection.GetBinaryEscapeStringFromFile(const FileName: String): String; var FStream: TFileStream; begin CheckConnected; if FileExists(FileName) then begin FStream := TFileStream.Create(FileName, fmOpenRead); Result := GetBinaryEscapeStringFromStream(FStream); FreeAndNil(FStream); end; end; {** EgonHugeist: Returns a detectable String to inform the Tokenizer to do no UTF8Encoding if neccessary @param Ansi Represents the AnsiString wich has to prepered @Result: A Prepared String like '~<|1023|<~''Binary-data-string(1023 Char's)''~<|1023|<~ } function TZAbstractConnection.GetAnsiEscapeString(const Ansi: AnsiString): String; begin Result := DbcConnection.GetDriver.GetTokenizer.GetEscapeString(String(Ansi)); end; function TZAbstractConnection.GetURL: String; begin Result := ConstructURL(FURL.UserName, FURL.Password); end; function TZAbstractConnection.GetAutoEncode: Boolean; begin {$IFDEF UNICODE} Result := True; {$ELSE} {$IF defined(MSWINDOWS) or defined(WITH_LCONVENCODING) or defined(FPC_HAS_BUILTIN_WIDESTR_MANAGER)} if Connected then begin Result := DbcConnection.GetConSettings.AutoEncode; FAutoEncode := Result; end else Result := FAutoEncode; {$ELSE} Result := False; {$IFEND} {$ENDIF} end; procedure TZAbstractConnection.SetAutoEncode(Value: Boolean); begin {$IFNDEF UNICODE} {$IF defined(MSWINDOWS) or defined(WITH_LCONVENCODING) or defined(FPC_HAS_BUILTIN_WIDESTR_MANAGER)} if Value then FURL.Properties.Values['AutoEncodeStrings'] := 'ON' else FURL.Properties.Values['AutoEncodeStrings'] := ''; if Value <> FAutoEncode then begin FAutoEncode := Value; if Self.Connected then begin Connected := False; Connected := True; end; end; {$ELSE} FURL.Properties.Values['AutoEncodeStrings'] := ''; {$IFEND} {$ENDIF} end; {** Returns the current version of zeosdbo. } function TZAbstractConnection.GetVersion: string; begin Result := ZEOS_VERSION; end; procedure TZAbstractConnection.SetUseMetadata(AValue: Boolean); begin if FUseMetaData=AValue then Exit; FUseMetaData:=AValue; if FConnection <> nil then FConnection.SetUseMetadata(FUseMetadata); end; procedure TZAbstractConnection.SetControlsCodePage(const Value: TZControlsCodePage); procedure SetValue; begin {$IFDEF UNICODE} case Value of cCP_UTF16: begin Properties.values['controls_cp'] := 'CP_UTF16'; FControlsCodePage := Value; end; cCP_UTF8: begin Properties.values['controls_cp'] := 'CP_UTF16'; FControlsCodePage := cCP_UTF16; end; cGET_ACP: begin Properties.values['controls_cp'] := 'GET_ACP'; FControlsCodePage := Value; end; end; {$ELSE} {$IFDEF WITH_WIDEFIELDS} case Value of cCP_UTF16: begin Properties.values['controls_cp'] := 'CP_UTF16'; FControlsCodePage := Value; end; cCP_UTF8: begin Properties.values['controls_cp'] := 'CP_UTF8'; FControlsCodePage := Value; end; cGET_ACP: if ZDefaultSystemCodePage = zCP_UTF8 then begin Properties.values['controls_cp'] := 'CP_UTF8'; FControlsCodePage := cCP_UTF8; end else begin Properties.values['controls_cp'] := 'GET_ACP'; FControlsCodePage := Value; end; end; {$ELSE} //D7 or old FPC case Value of cCP_UTF16: begin Properties.values['controls_cp'] := 'CP_UTF8'; FControlsCodePage := cCP_UTF8; end; cCP_UTF8: begin Properties.values['controls_cp'] := 'CP_UTF8'; FControlsCodePage := Value; end; cGET_ACP: if ZDefaultSystemCodePage = zCP_UTF8 then begin Properties.values['controls_cp'] := 'CP_UTF8'; FControlsCodePage := cCP_UTF8; end else begin Properties.values['controls_cp'] := 'GET_ACP'; FControlsCodePage := Value; end; end; {$ENDIF} {$ENDIF} end; begin if Value <> FControlsCodePage then if Connected then begin Connected := False; SetValue; Connected := True; end else SetValue; end; procedure TZAbstractConnection.SetVersion(const Value: string); begin end; procedure TZAbstractConnection.CloseAllSequences; var I: Integer; Current: TZSequence; begin for I := 0 to FSequences.Count - 1 do begin Current := TZSequence(FSequences[I]); try Current.CloseSequence; except // Ignore. end; end; end; procedure TZAbstractConnection.RegisterSequence(Sequence: TComponent); begin FSequences.Add(TZSequence(Sequence)); end; procedure TZAbstractConnection.UnregisterSequence(Sequence: TComponent); begin if Assigned(FSequences) then FSequences.Remove(TZSequence(Sequence)); end; {** Executes the SQL statement immediately without the need of a TZQuery component @param SQL the statement to be executed. Returns an indication if execution was succesfull. } function TZAbstractConnection.ExecuteDirect(SQL : String) : boolean; var dummy : Integer; begin result:= ExecuteDirect(SQL,dummy); end; {** Executes the SQL statement immediately without the need of a TZQuery component @param SQL the statement to be executed. @param RowsAffected the number of rows that were affected by the statement. Returns an indication if execution was succesfull. } function TZAbstractConnection.ExecuteDirect(SQL: string; var RowsAffected: integer):boolean; var stmt : IZStatement; begin try try CheckConnected; stmt := DbcConnection.CreateStatement; RowsAffected:= stmt.ExecuteUpdate(SQL); result := (RowsAffected <> -1); except RowsAffected := -1; result := False; raise; {------ added by Henk 09-10-2012 --------} end; finally stmt:=nil; end; end; initialization SqlHourGlassLock := 0; end. ================================================ FILE: lib/zeosdbo/src/component/ZAbstractDataset.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Abstract Read/Write Dataset component } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZAbstractDataset; interface {$I ZComponent.inc} uses Variants, SysUtils, Classes, {$IFDEF MSEgui}mdb, mclasses{$ELSE}DB{$ENDIF}, ZSqlUpdate, ZDbcIntfs, ZVariant, ZDbcCache, ZDbcCachedResultSet, ZAbstractRODataset, ZCompatibility, ZSequence; type {$IFDEF oldFPC} // added in 2006, probably pre 2.2.4 TUpdateAction = (uaFail, uaAbort, uaSkip, uaRetry, uaApplied); {$ENDIF} {** Update Event type. } TUpdateRecordEvent = procedure(DataSet: TDataSet; UpdateKind: TUpdateKind; var UpdateAction: TUpdateAction) of object; {** Defines update modes for the resultsets. } TZUpdateMode = (umUpdateChanged, umUpdateAll); {** Defines where form types for resultsets. } TZWhereMode = (wmWhereKeyOnly, wmWhereAll); {** Abstract dataset component which supports read/write access and cached updates. } TZAbstractDataset = class(TZAbstractRODataset) private FCachedUpdatesBeforeMasterUpdate: Boolean; FCachedUpdates: Boolean; FUpdateObject: TZUpdateSQL; FCachedResultSet: IZCachedResultSet; FCachedResolver: IZCachedResolver; FOnApplyUpdateError: TDataSetErrorEvent; FOnUpdateRecord: TUpdateRecordEvent; FUpdateMode: TZUpdateMode; FWhereMode: TZWhereMode; FSequence: TZSequence; FSequenceField: string; FBeforeApplyUpdates: TNotifyEvent; {bangfauzan addition} FAfterApplyUpdates: TNotifyEvent; {bangfauzan addition} FDetailDataSets: TList; FDetailCachedUpdates: array of Boolean; private function GetUpdatesPending: Boolean; procedure SetUpdateObject(Value: TZUpdateSQL); procedure SetCachedUpdates(Value: Boolean); procedure SetWhereMode(Value: TZWhereMode); procedure SetUpdateMode(Value: TZUpdateMode); protected property CachedResultSet: IZCachedResultSet read FCachedResultSet write FCachedResultSet; property CachedResolver: IZCachedResolver read FCachedResolver write FCachedResolver; property UpdateMode: TZUpdateMode read FUpdateMode write SetUpdateMode default umUpdateChanged; property WhereMode: TZWhereMode read FWhereMode write SetWhereMode default wmWhereKeyOnly; procedure InternalClose; override; procedure InternalEdit; override; procedure InternalAddRecord(Buffer: Pointer; Append: Boolean); override; procedure InternalPost; override; procedure InternalDelete; override; procedure InternalUpdate; procedure InternalCancel; override; procedure DOBeforeApplyUpdates; {bangfauzan addition} procedure DOAfterApplyUpdates; {bangfauzan addition} function CreateStatement(const SQL: string; Properties: TStrings): IZPreparedStatement; override; function CreateResultSet(const SQL: string; MaxRows: Integer): IZResultSet; override; procedure Notification(AComponent: TComponent; Operation: TOperation); override; {$IFDEF WITH_IPROVIDER} function PSUpdateRecord(UpdateKind: TUpdateKind; Delta: TDataSet): Boolean; override; {$ENDIF} procedure RegisterDetailDataSet(Value: TZAbstractDataset; CachedUpdates: Boolean); procedure DisposeCachedUpdates; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; procedure ApplyUpdates; procedure CommitUpdates; procedure CancelUpdates; procedure RevertRecord; procedure RefreshCurrentRow(const RefreshDetails:Boolean); //FOS+ 07112006 procedure EmptyDataSet; {bangfauzan addition} public property UpdatesPending: Boolean read GetUpdatesPending; property Sequence: TZSequence read FSequence write FSequence; property SequenceField: string read FSequenceField write FSequenceField; published property UpdateObject: TZUpdateSQL read FUpdateObject write SetUpdateObject; property CachedUpdates: Boolean read FCachedUpdates write SetCachedUpdates default False; property OnApplyUpdateError: TDataSetErrorEvent read FOnApplyUpdateError write FOnApplyUpdateError; property OnUpdateRecord: TUpdateRecordEvent read FOnUpdateRecord write FOnUpdateRecord; property BeforeApplyUpdates: TNotifyEvent read FBeforeApplyUpdates write FBeforeApplyUpdates; {bangfauzan addition} property AfterApplyUpdates: TNotifyEvent read FAfterApplyUpdates write FAfterApplyUpdates; {bangfauzan addition} published property BeforeInsert; property AfterInsert; property BeforeEdit; property AfterEdit; property BeforePost; property AfterPost; property BeforeCancel; property AfterCancel; property BeforeDelete; property AfterDelete; property OnDeleteError; property OnEditError; property OnPostError; property OnNewRecord; end; implementation uses Math, ZMessages, ZDatasetUtils; { TZAbstractDataset } {** Constructs this object and assignes the mail properties. @param AOwner a component owner. } constructor TZAbstractDataset.Create(AOwner: TComponent); begin inherited Create(AOwner); FWhereMode := wmWhereKeyOnly; FUpdateMode := umUpdateChanged; RequestLive := True; FDetailDataSets := TList.Create; end; {** Destroys this object and cleanups the memory. } destructor TZAbstractDataset.Destroy; begin FreeAndNil(FDetailDataSets); inherited Destroy; end; {** Sets a new UpdateSQL object. @param Value a new UpdateSQL object. } procedure TZAbstractDataset.SetUpdateObject(Value: TZUpdateSQL); begin if FUpdateObject <> Value then begin if Assigned(FUpdateObject) then FUpdateObject.RemoveFreeNotification(Self); FUpdateObject := Value; if Assigned(FUpdateObject) then FUpdateObject.FreeNotification(Self); if Assigned(FUpdateObject) then FUpdateObject.DataSet := Self; if Active and (CachedResultSet <> nil) then begin if FUpdateObject <> nil then CachedResultSet.SetResolver(FUpdateObject) else CachedResultSet.SetResolver(CachedResolver); end; end; end; {** Sets a new CachedUpdates property value. @param Value a new CachedUpdates value. } procedure TZAbstractDataset.SetCachedUpdates(Value: Boolean); begin if FCachedUpdates <> Value then begin FCachedUpdates := Value; if Active and (CachedResultSet <> nil) then CachedResultSet.SetCachedUpdates(Value); end; end; {** Sets a new UpdateMode property value. @param Value a new UpdateMode value. } procedure TZAbstractDataset.SetUpdateMode(Value: TZUpdateMode); begin if FUpdateMode <> Value then begin FUpdateMode := Value; if Active then Close; end; end; {** Sets a new WhereMode property value. @param Value a new WhereMode value. } procedure TZAbstractDataset.SetWhereMode(Value: TZWhereMode); begin if FWhereMode <> Value then begin FWhereMode := Value; if Active then Close; end; end; {** Creates a DBC statement for the query. @param SQL an SQL query. @param Properties a statement specific properties. @returns a created DBC statement. } function TZAbstractDataset.CreateStatement( const SQL: string; Properties: TStrings): IZPreparedStatement; var Temp: TStrings; begin Temp := TStringList.Create; try Temp.AddStrings(Properties); { Sets update mode property.} case FUpdateMode of umUpdateAll: Temp.Values['update'] := 'all'; umUpdateChanged: Temp.Values['update'] := 'changed'; end; { Sets where mode property. } case FWhereMode of wmWhereAll: Temp.Values['where'] := 'all'; wmWhereKeyOnly: Temp.Values['where'] := 'keyonly'; end; Result := inherited CreateStatement(SQL, Temp); finally Temp.Free; end; end; {** Creates a DBC resultset for the query. @param SQL an SQL query. @param MaxRows a maximum rows number (-1 for all). @returns a created DBC resultset. } function TZAbstractDataset.CreateResultSet(const SQL: string; MaxRows: Integer): IZResultSet; begin Result := inherited CreateResultSet(SQL, MaxRows); if not Assigned(Result) then Exit; if Result.QueryInterface(IZCachedResultSet, FCachedResultSet) = 0 then begin CachedResultSet := Result as IZCachedResultSet; CachedResolver := CachedResultSet.GetResolver; CachedResultSet.SetCachedUpdates(CachedUpdates); if FUpdateObject <> nil then CachedResultSet.SetResolver(FUpdateObject); end; end; {** Performs internal query closing. } procedure TZAbstractDataset.InternalClose; begin inherited InternalClose; if not DoNotCloseResultset then begin if Assigned(CachedResultSet) then CachedResultSet.Close; CachedResultSet := nil; CachedResolver := nil; end; end; {** Performs an internal action before switch into edit mode. } procedure TZAbstractDataset.InternalEdit; begin end; {** Performs an internal record updates. } {$IFDEF FPC} {$HINTS OFF} {$ENDIF} procedure TZAbstractDataset.InternalUpdate; var RowNo: Integer; RowBuffer: PZRowBuffer; begin if (CachedResultSet <> nil) and GetActiveBuffer(RowBuffer) then begin RowNo := Integer(CurrentRows[CurrentRow - 1]); CachedResultSet.MoveAbsolute(RowNo); RowAccessor.RowBuffer := RowBuffer; PostToResultSet(CachedResultSet, FieldsLookupTable, Fields, RowAccessor); try CachedResultSet.UpdateRow; except on E: EZSQLThrowable do raise EZDatabaseError.CreateFromException(E); end; { Filters the row } if not FilterRow(RowNo) then begin CurrentRows.Delete(CurrentRow - 1); CurrentRow := Min(CurrentRows.Count, CurrentRow); end; end; end; {$IFDEF FPC} {$HINTS ON} {$ENDIF} {** Performs an internal adding a new record. @param Buffer a buffer of the new adding record. @param Append True if record should be added to the end of the result set. } {$IFDEF FPC} {$HINTS OFF} {$ENDIF} procedure TZAbstractDataset.InternalAddRecord(Buffer: Pointer; Append: Boolean); var RowNo: Integer; RowBuffer: PZRowBuffer; begin if not GetActiveBuffer(RowBuffer) or (RowBuffer <> Buffer) then raise EZDatabaseError.Create(SInternalError); if Append then FetchRows(0); if CachedResultSet <> nil then begin CachedResultSet.MoveToInsertRow; RowAccessor.RowBuffer := RowBuffer; PostToResultSet(CachedResultSet, FieldsLookupTable, Fields, RowAccessor); try CachedResultSet.InsertRow; except on E: EZSQLThrowable do raise EZDatabaseError.CreateFromException(E); end; RowNo := CachedResultSet.GetRow; FetchCount := FetchCount + 1; { Filters the row } if FilterRow(RowNo) then begin if Append then begin CurrentRows.Add(Pointer(RowNo)); CurrentRow := CurrentRows.Count; end else begin CurrentRow := Max(CurrentRow, 1); CurrentRows.Insert(CurrentRow - 1, Pointer(RowNo)); end; end; end; end; {$IFDEF FPC} {$HINTS ON} {$ENDIF} {** Performs an internal post updates. } {$IFDEF FPC} {$HINTS OFF} {$ENDIF} procedure TZAbstractDataset.InternalPost; var RowBuffer: PZRowBuffer; {$IFDEF WITH_TBOOKMARK} BM: TBookMark; {$ELSE} BM:TBookMarkStr; {$ENDIF} I: Integer; begin if (FSequenceField <> '') and Assigned(FSequence) then begin if FieldByName(FSequenceField).IsNull then FieldByName(FSequenceField).Value := FSequence.GetNextValue; end; //inherited; //AVZ - Firebird defaults come through when this is commented out if not GetActiveBuffer(RowBuffer) then raise EZDatabaseError.Create(SInternalError); Connection.ShowSqlHourGlass; try //revert Master Detail updates makes it possible to update // with ForeignKey contraints if Assigned(MasterLink.DataSet) then if (TDataSet(MasterLink.DataSet) is TZAbstractDataset) then if ( doUpdateMasterFirst in TZAbstractDataset(MasterLink.DataSet).Options ) or ( doUpdateMasterFirst in Options ) then begin //This is an detail-table FCachedUpdatesBeforeMasterUpdate := CachedUpdates; //buffer old value if not(CachedUpdates) then CachedUpdates := True; //Execute without writing TZAbstractDataset(MasterLink.DataSet).RegisterDetailDataSet(Self, TZAbstractDataset(MasterLink.DataSet).CachedUpdates); end; if State = dsInsert then InternalAddRecord(RowBuffer, False) else InternalUpdate; // Apply Detail updates now if FDetailDataSets.Count > 0 then for i := 0 to FDetailDataSets.Count -1 do if (TDataSet(FDetailDataSets.Items[i]) is TZAbstractDataset) then begin if not (Self.FDetailCachedUpdates[I]) then TZAbstractDataset(TDataSet(FDetailDataSets.Items[i])).ApplyUpdates; TZAbstractDataset(TDataSet(FDetailDataSets.Items[i])).CachedUpdates := Self.FDetailCachedUpdates[I]; end; FDetailDataSets.Clear; SetLength(FDetailCachedUpdates, 0); {BUG-FIX: bangfauzan addition} if (SortedFields <> '') and not (doDontSortOnPost in Options) then begin FreeFieldBuffers; SetState(dsBrowse); Resync([]); BM := Bookmark; if BookmarkValid({$IFDEF WITH_TBOOKMARK}BM{$ELSE}@BM{$ENDIF}) Then begin InternalGotoBookmark({$IFDEF WITH_TBOOKMARK}BM{$ELSE}@BM{$ENDIF}); Resync([rmExact, rmCenter]); end; DisableControls; InternalSort; BookMark:=BM; UpdateCursorPos; EnableControls; end; {end of bangfauzan addition} finally Connection.HideSqlHourGlass; //DetailLinks.Free; end; end; {** Performs an internal record removing. } procedure TZAbstractDataset.InternalDelete; var RowNo: Integer; RowBuffer: PZRowBuffer; begin if (CachedResultSet <> nil) and GetActiveBuffer(RowBuffer) then begin Connection.ShowSqlHourGlass; try RowNo := Integer(CurrentRows[CurrentRow - 1]); CachedResultSet.MoveAbsolute(RowNo); try CachedResultSet.DeleteRow; except on E: EZSQLThrowable do raise EZDatabaseError.CreateFromException(E); end; { Filters the row } if not FilterRow(RowNo) then begin CurrentRows.Delete(CurrentRow - 1); if not FetchRows(CurrentRow) then CurrentRow := Min(CurrentRows.Count, CurrentRow); end; finally Connection.HideSQLHourGlass; end; end; end; {** Performs an internal cancel updates. } procedure TZAbstractDataset.InternalCancel; var RowNo: Integer; RowBuffer: PZRowBuffer; begin if (CachedResultSet <> nil) and GetActiveBuffer(RowBuffer) and (CurrentRow > 0) and (State = dsEdit) then begin RowNo := Integer(CurrentRows[CurrentRow - 1]); CachedResultSet.MoveAbsolute(RowNo); RowAccessor.RowBuffer := RowBuffer; FetchFromResultSet(CachedResultSet, FieldsLookupTable, Fields, RowAccessor); end; end; {$IFDEF FPC} {$HINTS ON} {$ENDIF} {** Processes component notifications. @param AComponent a changed component object. @param Operation a component operation code. } procedure TZAbstractDataset.Notification(AComponent: TComponent; Operation: TOperation); begin inherited Notification(AComponent, Operation); if (Operation = opRemove) then begin if (AComponent = FUpdateObject) then begin Close; FUpdateObject := nil; end; if (AComponent = FSequence) then begin FSequence := nil; end; end; end; {** Applies all cached updates stored in the resultset. } procedure TZAbstractDataset.ApplyUpdates; begin if not Active then Exit; Connection.ShowSQLHourGlass; try if State in [dsEdit, dsInsert] then Post; DoBeforeApplyUpdates; {bangfauzan addition} if CachedResultSet <> nil then if Connection.AutoCommit and not ( Connection.TransactIsolationLevel in [tiReadCommitted, tiSerializable] ) then CachedResultSet.PostUpdates else CachedResultSet.PostUpdatesCached; if not (State in [dsInactive]) then Resync([]); DOAfterApplyUpdates; {bangfauzan addition} finally Connection.HideSqlHourGlass; end; end; {** Dispose all cached updates stored in the resultset. } procedure TZAbstractDataset.DisposeCachedUpdates; begin if Active then if Assigned(CachedResultSet) then CachedResultSet.DisposeCachedUpdates; end; {** Clears cached updates buffer. } procedure TZAbstractDataset.CommitUpdates; begin CheckBrowseMode; if CachedResultSet <> nil then CachedResultSet.CancelUpdates; end; {** Cancels all cached updates and clears the buffer. } procedure TZAbstractDataset.CancelUpdates; begin if State in [dsEdit, dsInsert] then Cancel; if CachedResultSet <> nil then CachedResultSet.CancelUpdates; if not (State in [dsInactive]) then RereadRows; end; {** Reverts the previous status for the current row. } procedure TZAbstractDataset.RefreshCurrentRow(const RefreshDetails:Boolean); var RowNo: integer; i: Integer; ostate:TDataSetState; begin if State=dsBrowse then begin if CachedResultSet <> nil then begin UpdateCursorPos; RowNo := Integer(CurrentRows[CurrentRow - 1]); CachedResultSet.MoveAbsolute(RowNo); CachedResultSet.RefreshRow; if not (State in [dsInactive]) then begin if RefreshDetails then Resync([]) else begin FetchFromResultSet(ResultSet, FieldsLookupTable, Fields, RowAccessor); ostate:=State; SetTempState(dsInternalCalc); try for I := 0 to Fields.Count - 1 do DataEvent(deFieldChange,ULong(Fields[i])); finally RestoreState(ostate); end; end; end; end; end else begin raise EZDatabaseError.Create(SInternalError); end; end; procedure TZAbstractDataset.RevertRecord; begin if State in [dsInsert] then begin Cancel; Exit; end; if State in [dsEdit] then Cancel; if CachedResultSet <> nil then CachedResultSet.RevertRecord; if not (State in [dsInactive]) then Resync([]); end; {** Checks is there cached updates pending in the buffer. @return True if there some pending cached updates. } function TZAbstractDataset.GetUpdatesPending: Boolean; begin if State = dsInactive then Result := False else if (CachedResultSet <> nil) and CachedResultSet.IsPendingUpdates then Result := True else if (State in [dsInsert, dsEdit]) then Result := Modified else Result := False; end; {$IFDEF WITH_IPROVIDER} {** Applies a single update to the underlying database table or tables. @param UpdateKind an update type. @param Delta a dataset where the current position shows the row to update. @returns True if updates were successfully applied. } {$IFDEF FPC} {$HINTS OFF} {$ENDIF} function TZAbstractDataset.PSUpdateRecord(UpdateKind: TUpdateKind; Delta: TDataSet): Boolean; var Bookmark: TBookmark; ActiveMode: Boolean; UpdateMode: Boolean; function LocateRecord: Boolean; var I: Integer; KeyFields: string; Temp: Variant; SrcField: TField; KeyValues: Variant; FieldRefs: TObjectDynArray; OnlyDataFields: Boolean; begin if Properties.Values['KeyFields'] <> '' then KeyFields := Properties.Values['KeyFields'] else KeyFields := DefineKeyFields(Fields); FieldRefs := DefineFields(Self, KeyFields, OnlyDataFields); Temp := VarArrayCreate([0, Length(FieldRefs) - 1], varVariant); for I := 0 to Length(FieldRefs) - 1 do begin SrcField := Delta.FieldByName(TField(FieldRefs[I]).FieldName); if SrcField <> nil then begin Temp[I] := SrcField.OldValue; end else Temp[I] := Null; end; if Length(FieldRefs) = 1 then KeyValues := Temp[0] else KeyValues := Temp; if KeyFields <> '' then Result := Locate(KeyFields, KeyValues, []) else Result := False; end; procedure CopyRecord(SrcDataset: TDataset; DestDataset: TDataset); var I: Integer; SrcField: TField; DestField: TField; SrcStream: TStream; DestStream: TStream; begin for I := 0 to DestDataset.FieldCount - 1 do begin DestField := DestDataset.Fields[I]; SrcField := SrcDataset.FieldByName(DestField.FieldName); if (SrcField = nil) or VarIsEmpty(SrcField.NewValue) then Continue; if SrcField.IsNull then begin DestField.Clear; Continue; end; case DestField.DataType of ftLargeInt: begin if SrcField.DataType = ftLargeInt then begin TLargeIntField(DestField).AsLargeInt := TLargeIntField(SrcField).AsLargeInt; end else DestField.AsInteger := SrcField.AsInteger; end; ftBlob, ftMemo {$IFDEF WITH_WIDEMEMO}, ftWideMemo{$ENDIF}: begin if SrcField.DataType in [ftBlob, ftMemo {$IFDEF WITH_WIDEMEMO}, ftWideMemo{$ENDIF}] then begin SrcStream := SrcDataset.CreateBlobStream(SrcField, bmRead); try DestStream := DestDataset.CreateBlobStream(DestField, bmWrite); try DestStream.CopyFrom(SrcStream, 0); finally DestStream.Free; end; finally SrcStream.Free; end; end else DestField.AsVariant := SrcField.AsVariant; end; else DestField.AsVariant := SrcField.AsVariant; end; end; end; begin Result := False; ActiveMode := Self.Active; UpdateMode := Self.RequestLive; if Self.RequestLive = False then Self.RequestLive := True; if Self.Active = False then Self.Open; CheckBrowseMode; try Self.DisableControls; { Saves the current position. } Bookmark := Self.GetBookmark; { Applies updates. } try case UpdateKind of ukModify: begin if LocateRecord then begin Self.Edit; CopyRecord(Delta, Self); Self.Post; Result := True; end; end; ukInsert: begin Self.Append; CopyRecord(Delta, Self); Self.Post; Result := True; end; ukDelete: begin if LocateRecord then begin Self.Delete; Result := True; end; end; end; except Result := False; end; { Restores the previous position. } try Self.GotoBookmark(Bookmark); except Self.First; end; Self.FreeBookmark(Bookmark); finally EnableControls; Self.RequestLive := UpdateMode; Self.Active := ActiveMode; end; end; {$IFDEF FPC} {$HINTS ON} {$ENDIF} {$ENDIF} procedure TZAbstractDataset.RegisterDetailDataSet(Value: TZAbstractDataset; CachedUpdates: Boolean); begin FDetailDataSets.Add(Value); SetLength(Self.FDetailCachedUpdates, Length(FDetailCachedUpdates)+1); FDetailCachedUpdates[High(FDetailCachedUpdates)] := CachedUpdates; end; {============================bangfauzan addition===================} procedure TZAbstractDataset.DOBeforeApplyUpdates; begin if assigned(BeforeApplyUpdates) then FBeforeApplyUpdates(Self); end; procedure TZAbstractDataset.DOAfterApplyUpdates; begin if assigned(AfterApplyUpdates) then FAfterApplyUpdates(Self); end; procedure TZAbstractDataset.EmptyDataSet; begin if Active then begin Self.CancelUpdates; Self.CurrentRows.Clear; Self.CurrentRow:=0; Resync([]); InitRecord(ActiveBuffer); end; end; {========================end of bangfauzan addition================} end. ================================================ FILE: lib/zeosdbo/src/component/ZAbstractRODataset.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Abstract Read/Only Dataset component } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZAbstractRODataset; interface {$I ZComponent.inc} uses {$IFNDEF UNIX} Windows, {$ENDIF} Variants, Types, SysUtils, Classes, {$IFDEF MSEgui}mclasses, mdb{$ELSE}DB{$ENDIF}, ZSysUtils, ZAbstractConnection, ZDbcIntfs, ZSqlStrings, Contnrs, ZDbcCache, ZDbcCachedResultSet, ZCompatibility, ZExpression {$IFDEF WITH_GENERIC_TLISTTFIELD}, Generics.Collections{$ENDIF}; type {$IFDEF xFPC} // fixed in r3943 or earlier 2006-06-25 TUpdateStatusSet = set of TUpdateStatus; EUpdateError = class(EDatabaseError) end; {$ENDIF} TSortType = (stAscending, stDescending, stIgnored); {bangfauzan addition} {** Options for dataset. } TZDatasetOption = (doOemTranslate, doCalcDefaults, doAlwaysDetailResync, doSmartOpen, doPreferPrepared, doDontSortOnPost, doUpdateMasterFirst); {** Set of dataset options. } TZDatasetOptions = set of TZDatasetOption; // Forward declarations. TZAbstractRODataset = class; {** Implements a Zeos specific database exception with SQL error code. } EZDatabaseError = class(EDatabaseError) private FErrorCode: Integer; FStatusCode: String; procedure SetStatusCode(const Value: String); public constructor Create(const Msg: string); constructor CreateFromException(E: EZSQLThrowable); property ErrorCode: Integer read FErrorCode write FErrorCode; property StatusCode: String read FStatusCode write SetStatusCode; end; {** Dataset Linker class. } TZDataLink = class(TMasterDataLink) private FDataset: TZAbstractRODataset; protected procedure ActiveChanged; override; procedure RecordChanged(Field: TField); override; public constructor Create(ADataset: TZAbstractRODataset); {$IFDEF FPC}reintroduce;{$ENDIF} end; {** Abstract dataset component optimized for read/only access. } {$IFDEF WITH_WIDEDATASET} TZAbstractRODataset = class(TWideDataSet) {$ELSE} TZAbstractRODataset = class(TDataSet) {$ENDIF} private {$IFNDEF WITH_FUNIDIRECTIONAL} FUniDirectional: Boolean; {$ENDIF} FCurrentRow: Integer; FRowAccessor: TZRowAccessor; FOldRowBuffer: PZRowBuffer; FNewRowBuffer: PZRowBuffer; FCurrentRows: TZSortedList; FFetchCount: Integer; FFieldsLookupTable: TIntegerDynArray; FRowsAffected: Integer; FFilterEnabled: Boolean; FFilterExpression: IZExpression; FFilterStack: TZExecutionStack; FFilterFieldRefs: TObjectDynArray; FInitFilterFields: Boolean; FRequestLive: Boolean; FFetchRow: integer; // added by Patyi FSQL: TZSQLStrings; FParams: TParams; FShowRecordTypes: TUpdateStatusSet; FOptions: TZDatasetOptions; FProperties: TStrings; FConnection: TZAbstractConnection; FStatement: IZPreparedStatement; FResultSet: IZResultSet; FRefreshInProgress: Boolean; FDataLink: TDataLink; FMasterLink: TMasterDataLink; FLinkedFields: string; {renamed by bangfauzan} FIndexFieldNames : String; {bangfauzan addition} FIndexFields: {$IFDEF WITH_GENERIC_TLISTTFIELD}TList{$ELSE}TList{$ENDIF}; FSortType : TSortType; {bangfauzan addition} FSortedFields: string; FSortedFieldRefs: TObjectDynArray; FSortedFieldIndices: TIntegerDynArray; FSortedFieldDirs: TBooleanDynArray; FSortedOnlyDataFields: Boolean; FSortRowBuffer1: PZRowBuffer; FSortRowBuffer2: PZRowBuffer; FPrepared: Boolean; FDoNotCloseResultset: Boolean; FUseCurrentStatment: Boolean; private function GetReadOnly: Boolean; procedure SetReadOnly(Value: Boolean); function GetSQL: TStrings; procedure SetSQL(Value: TStrings); function GetParamCheck: Boolean; procedure SetParamCheck(Value: Boolean); function GetParamChar: Char; procedure SetParamChar(Value: Char); procedure SetParams(Value: TParams); function GetShowRecordTypes: TUpdateStatusSet; procedure SetShowRecordTypes(Value: TUpdateStatusSet); procedure SetConnection(Value: TZAbstractConnection); procedure SetDataSource(Value: TDataSource); function GetMasterFields: string; procedure SetMasterFields(const Value: string); function GetMasterDataSource: TDataSource; procedure SetMasterDataSource(Value: TDataSource); function GetLinkedFields: string; {renamed by bangfauzan} procedure SetLinkedFields(const Value: string); {renamed by bangfauzan} function GetIndexFieldNames : String; {bangfauzan addition} procedure SetIndexFieldNames(Value : String); {bangfauzan addition} procedure SetOptions(Value: TZDatasetOptions); procedure SetSortedFields({const} Value: string); {bangfauzan modification} procedure SetProperties(const Value: TStrings); function GetSortType : TSortType; {bangfauzan addition} Procedure SetSortType(Value : TSortType); {bangfauzan addition} procedure UpdateSQLStrings(Sender: TObject); procedure ReadParamData(Reader: TReader); procedure WriteParamData(Writer: TWriter); procedure SetPrepared(Value : Boolean); {$IFNDEF WITH_FUNIDIRECTIONAL} procedure SetUniDirectional(const Value: boolean); {$ENDIF} function GetUniDirectional: boolean; protected procedure CheckOpened; procedure CheckConnected; procedure CheckBiDirectional; procedure CheckSQLQuery; virtual; procedure RaiseReadOnlyError; function FetchOneRow: Boolean; function FetchRows(RowCount: Integer): Boolean; function FilterRow(RowNo: Integer): Boolean; function GotoRow(RowNo: Integer): Boolean; // added by tohenk procedure RereadRows; procedure SetStatementParams(Statement: IZPreparedStatement; ParamNames: TStringDynArray; Params: TParams; DataLink: TDataLink); virtual; procedure MasterChanged(Sender: TObject); procedure MasterDisabled(Sender: TObject); procedure DoOnNewRecord; override; function GetDataSource: TDataSource; override; protected { Internal protected properties. } property RowAccessor: TZRowAccessor read FRowAccessor write FRowAccessor; property CurrentRow: Integer read FCurrentRow write FCurrentRow; property OldRowBuffer: PZRowBuffer read FOldRowBuffer write FOldRowBuffer; property NewRowBuffer: PZRowBuffer read FNewRowBuffer write FNewRowBuffer; property CurrentRows: TZSortedList read FCurrentRows write FCurrentRows; property FetchCount: Integer read FFetchCount write FFetchCount; property FieldsLookupTable: TIntegerDynArray read FFieldsLookupTable write FFieldsLookupTable; property FilterEnabled: Boolean read FFilterEnabled write FFilterEnabled; property FilterExpression: IZExpression read FFilterExpression write FFilterExpression; property FilterStack: TZExecutionStack read FFilterStack write FFilterStack; property FilterFieldRefs: TObjectDynArray read FFilterFieldRefs write FFilterFieldRefs; property InitFilterFields: Boolean read FInitFilterFields write FInitFilterFields; property Statement: IZPreparedStatement read FStatement write FStatement; property ResultSet: IZResultSet read FResultSet write FResultSet; property DataLink: TDataLink read FDataLink; property MasterLink: TMasterDataLink read FMasterLink; property IndexFields: {$IFDEF WITH_GENERIC_TLISTTFIELD}TList{$ELSE}TList{$ENDIF} read FIndexFields; { External protected properties. } property RequestLive: Boolean read FRequestLive write FRequestLive default False; property FetchRow: integer read FFetchRow write FFetchRow default 0; // added by Patyi property SQL: TStrings read GetSQL write SetSQL; property ParamCheck: Boolean read GetParamCheck write SetParamCheck default True; property ParamChar: Char read GetParamChar write SetParamChar default ':'; property Params: TParams read FParams write SetParams; property ReadOnly: Boolean read GetReadOnly write SetReadOnly default True; property ShowRecordTypes: TUpdateStatusSet read GetShowRecordTypes write SetShowRecordTypes default [usUnmodified, usModified, usInserted]; property IsUniDirectional: Boolean read GetUniDirectional write SetUniDirectional default False; property Properties: TStrings read FProperties write SetProperties; property Options: TZDatasetOptions read FOptions write SetOptions default [doCalcDefaults]; property DataSource: TDataSource read GetDataSource write SetDataSource; property MasterFields: string read GetMasterFields write SetMasterFields; property MasterSource: TDataSource read GetMasterDataSource write SetMasterDataSource; property LinkedFields: string read GetLinkedFields write SetLinkedFields; {renamed by bangfauzan} property IndexFieldNames:String read GetIndexFieldNames write SetIndexFieldNames; {bangfauzan addition} property DoNotCloseResultset: Boolean read FDoNotCloseResultset; protected { Abstracts methods } procedure InternalAddRecord(Buffer: Pointer; Append: Boolean); override; procedure InternalDelete; override; procedure InternalPost; override; procedure SetFieldData(Field: TField; Buffer: {$IFDEF WITH_TVALUEBUFFER}TValueBuffer{$ELSE}Pointer{$ENDIF}; NativeFormat: Boolean); override; procedure SetFieldData(Field: TField; Buffer: {$IFDEF WITH_TVALUEBUFFER}TValueBuffer{$ELSE}Pointer{$ENDIF}); override; procedure DefineProperties(Filer: TFiler); override; {$IFDEF WITH_TRECORDBUFFER} function GetRecord(Buffer: TRecordBuffer; GetMode: TGetMode; DoCheck: Boolean): TGetResult; override; {$ELSE} function GetRecord(Buffer: PChar; GetMode: TGetMode; DoCheck: Boolean): TGetResult; override; {$ENDIF} function GetRecordSize: Word; override; function GetActiveBuffer(var RowBuffer: PZRowBuffer): Boolean; {$IFDEF WITH_TRECORDBUFFER} function AllocRecordBuffer: TRecordBuffer; override; procedure FreeRecordBuffer(var Buffer: TRecordBuffer); override; {$ELSE} function AllocRecordBuffer: PChar; override; procedure FreeRecordBuffer(var Buffer: PChar); override; {$ENDIF} {$IFDEF WITH_FTDATASETSUPPORT} function CreateNestedDataSet(DataSetField: TDataSetField): TDataSet; override; {$ENDIF} procedure CloseBlob(Field: TField); override; function CreateStatement(const SQL: string; Properties: TStrings): IZPreparedStatement; virtual; function CreateResultSet(const SQL: string; MaxRows: Integer): IZResultSet; virtual; procedure CheckFieldCompatibility(Field: TField; FieldDef: TFieldDef); {$IFDEF WITH_CHECKFIELDCOMPATIBILITY} override;{$ENDIF} {$IFDEF WITH_TRECORDBUFFER} procedure ClearCalcFields(Buffer: TRecordBuffer); override; {$ELSE} procedure ClearCalcFields(Buffer: PChar); override; {$ENDIF} procedure InternalInitFieldDefs; override; procedure InternalOpen; override; procedure InternalClose; override; procedure InternalFirst; override; procedure InternalLast; override; {$IFDEF WITH_TRECORDBUFFER} procedure InternalInitRecord(Buffer: TRecordBuffer); override; {$ELSE} procedure InternalInitRecord(Buffer: PChar); override; {$ENDIF} procedure InternalGotoBookmark(Bookmark: Pointer); override; procedure InternalRefresh; override; procedure InternalHandleException; override; {$IFDEF WITH_TRECORDBUFFER} procedure InternalSetToRecord(Buffer: TRecordBuffer); override; procedure GetBookmarkData(Buffer: TRecordBuffer; Data:{$IFDEF WITH_BOOKMARKDATA_TBOOKMARK}TBookMark{$ELSE}Pointer{$ENDIF}); override; function GetBookmarkFlag(Buffer: TRecordBuffer): TBookmarkFlag; override; procedure SetBookmarkFlag(Buffer: TRecordBuffer; Value: TBookmarkFlag); override; procedure SetBookmarkData(Buffer: TRecordBuffer; Data: {$IFDEF WITH_BOOKMARKDATA_TBOOKMARK}TBookMark{$ELSE}Pointer{$ENDIF}); override; {$ELSE} procedure InternalSetToRecord(Buffer: PChar); override; procedure GetBookmarkData(Buffer: PChar; Data: Pointer); override; function GetBookmarkFlag(Buffer: PChar): TBookmarkFlag; override; procedure SetBookmarkFlag(Buffer: PChar; Value: TBookmarkFlag); override; procedure SetBookmarkData(Buffer: PChar; Data: Pointer); override; {$ENDIF} function InternalLocate(const KeyFields: string; const KeyValues: Variant; Options: TLocateOptions): LongInt; function FindRecord(Restart, GoForward: Boolean): Boolean; override; procedure SetFiltered(Value: Boolean); override; procedure SetFilterText(const Value: string); override; procedure SetAnotherResultset(const Value: IZResultSet); procedure InternalSort; function ClearSort(Item1, Item2: Pointer): Integer; function HighLevelSort(Item1, Item2: Pointer): Integer; function LowLevelSort(Item1, Item2: Pointer): Integer; function GetCanModify: Boolean; override; function GetRecNo: Integer; override; function GetRecordCount: Integer; override; procedure MoveRecNo(Value: Integer); procedure SetRecNo(Value: Integer); override; function IsCursorOpen: Boolean; override; procedure Notification(AComponent: TComponent; Operation: TOperation); override; procedure RefreshParams; virtual; procedure InternalPrepare; virtual; procedure InternalUnPrepare; virtual; protected {$IFDEF WITH_IPROVIDER} procedure PSStartTransaction; override; procedure PSEndTransaction(Commit: Boolean); override; // Silvio Clecio {$IFDEF WITH_IPROVIDERWIDE} function PSGetTableNameW: WideString; override; function PSGetQuoteCharW: WideString; override; function PSGetKeyFieldsW: WideString; override; procedure PSSetCommandText(const CommandText: WideString); overload; override; procedure PSSetCommandText(const CommandText: string); overload; override; //?? function PSGetCommandTextW: WideString; override; function PSExecuteStatement(const ASQL: WideString; AParams: TParams; ResultSet: Pointer = nil): Integer; override; {$ELSE} function PSGetTableName: string; override; function PSGetQuoteChar: string; override; function PSGetKeyFields: string; override; function PSExecuteStatement(const ASQL: string; AParams: TParams; ResultSet: Pointer = nil): Integer; override; procedure PSSetCommandText(const CommandText: string); override; {$ENDIF} function PSGetUpdateException(E: Exception; Prev: EUpdateError): EUpdateError; override; function PSIsSQLBased: Boolean; override; function PSIsSQLSupported: Boolean; override; procedure PSReset; override; function PSUpdateRecord(UpdateKind: TUpdateKind; Delta: TDataSet): Boolean; override; procedure PSExecute; override; function PSGetParams: TParams; override; procedure PSSetParams(AParams: TParams); override; function PSInTransaction: Boolean; override; {$ENDIF} public constructor Create(AOwner: TComponent); override; destructor Destroy; override; procedure FetchAll; virtual; // added by Patyi procedure ExecSQL; virtual; function RowsAffected: LongInt; function ParamByName(const Value: string): TParam; function Locate(const KeyFields: string; const KeyValues: Variant; Options: TLocateOptions): Boolean; override; function Lookup(const KeyFields: string; const KeyValues: Variant; const ResultFields: string): Variant; override; function IsSequenced: Boolean; override; function CompareBookmarks(Bookmark1, Bookmark2: TBookmark): Integer; override; function BookmarkValid(Bookmark: TBookmark): Boolean; override; function GetFieldData(Field: TField; {$IFDEF WITH_VAR_TVALUEBUFFER}var{$ENDIF}Buffer: {$IFDEF WITH_TVALUEBUFFER}TValueBuffer{$ELSE}Pointer{$ENDIF}): Boolean; override; function GetFieldData(Field: TField; {$IFDEF WITH_VAR_TVALUEBUFFER}var{$ENDIF}Buffer: {$IFDEF WITH_TVALUEBUFFER}TValueBuffer{$ELSE}Pointer{$ENDIF}; NativeFormat: Boolean): Boolean; override; function CreateBlobStream(Field: TField; Mode: TBlobStreamMode): TStream; override; function UpdateStatus: TUpdateStatus; override; function Translate(Src, Dest: PAnsiChar; ToOem: Boolean): Integer; override; procedure Prepare; procedure Unprepare; public property Active; property Prepared: Boolean read FPrepared write SetPrepared; property FieldDefs stored False; property DbcStatement: IZPreparedStatement read FStatement; property DbcResultSet: IZResultSet read FResultSet; published property Connection: TZAbstractConnection read FConnection write SetConnection; property SortedFields: string read FSortedFields write SetSortedFields; property SortType : TSortType read FSortType write SetSortType default stAscending; {bangfauzan addition} property AutoCalcFields; property BeforeOpen; property AfterOpen; property BeforeClose; property AfterClose; property BeforeRefresh; property AfterRefresh; property BeforeScroll; property AfterScroll; property OnCalcFields; property OnFilterRecord; property Filter; property Filtered; end; implementation uses Math, ZVariant, ZMessages, ZDatasetUtils, ZStreamBlob, ZSelectSchema, ZGenericSqlToken, ZTokenizer, ZGenericSqlAnalyser, ZAbstractDataset {$IFDEF WITH_DBCONSTS}, DBConsts {$ELSE}, DBConst{$ENDIF} {$IFDEF WITH_WIDESTRUTILS}, WideStrUtils{$ENDIF} {$IFDEF WITH_UNITANSISTRINGS}, AnsiStrings{$ENDIF}; { EZDatabaseError } {** Constructs a database exception with a string message. @param Msg a string message which describes the error. } constructor EZDatabaseError.Create(const Msg: string); begin inherited Create(Msg); end; {** Constructs a database exception from TZSQLThrowable instance. @param E an original TZSQLThrowable instance. } constructor EZDatabaseError.CreateFromException(E: EZSQLThrowable); begin inherited Create(E.Message); ErrorCode := E.ErrorCode; Statuscode:= E.StatusCode; end; procedure EZDatabaseError.SetStatusCode(const Value: String); begin FStatusCode := value; end; { TZDataLink } {** Creates this dataset link object. @param ADataset an owner linked dataset component. } constructor TZDataLink.Create(ADataset: TZAbstractRODataset); begin inherited Create(ADataset); FDataset := ADataset; end; {** Processes changes in state of linked dataset. } procedure TZDataLink.ActiveChanged; begin if FDataset.Active then FDataset.RefreshParams; end; {** Processes changes in fields of the linked dataset. @param Field a field which was changed. } procedure TZDataLink.RecordChanged(Field: TField); begin if (Field = nil) and FDataset.Active then FDataset.RefreshParams; end; { TZAbstractRODataset } {** Constructs this object and assignes the mail properties. @param AOwner a component owner. } constructor TZAbstractRODataset.Create(AOwner: TComponent); begin inherited Create(AOwner); FSQL := TZSQLStrings.Create; TZSQLStrings(FSQL).Dataset := Self; TZSQLStrings(FSQL).MultiStatements := False; FSQL.OnChange := UpdateSQLStrings; FParams := TParams.Create(Self); FCurrentRows := TZSortedList.Create; BookmarkSize := SizeOf(Integer); FShowRecordTypes := [usModified, usInserted, usUnmodified]; FRequestLive := False; FFetchRow := 0; // added by Patyi FOptions := [doCalcDefaults]; FFilterEnabled := False; FProperties := TStringList.Create; FFilterExpression := TZExpression.Create; FFilterExpression.Tokenizer := CommonTokenizer; FFilterStack := TZExecutionStack.Create; FDataLink := TZDataLink.Create(Self); FMasterLink := TMasterDataLink.Create(Self); FMasterLink.OnMasterChange := MasterChanged; FMasterLink.OnMasterDisable := MasterDisabled; {$IFDEF WITH_GENERIC_TLISTTFIELD} FIndexFields := TList.Create; {$ELSE} FIndexFields := TList.Create; {$ENDIF} end; {** Destroys this object and cleanups the memory. } destructor TZAbstractRODataset.Destroy; begin Unprepare; if Assigned(Connection) then begin try SetConnection(nil); except end; end; FreeAndNil(FSQL); FreeAndNil(FParams); FreeAndNil(FCurrentRows); FreeAndNil(FProperties); FreeAndNil(FFilterStack); FreeAndNil(FDataLink); FreeAndNil(FMasterLink); FreeAndNil(FIndexFields); inherited Destroy; end; {** Sets database connection object. @param Value a database connection object. } procedure TZAbstractRODataset.SetConnection(Value: TZAbstractConnection); begin if FConnection <> Value then begin if Active then Close; if Assigned(Statement) then Statement.Close; Statement := nil; if FConnection <> nil then FConnection.UnregisterDataSet(Self); FConnection := Value; if FConnection <> nil then FConnection.RegisterDataSet(Self); end; end; {** Gets the SQL query. @return the SQL query strings. } function TZAbstractRODataset.GetSQL: TStrings; begin Result := FSQL; end; {$IFNDEF WITH_FUNIDIRECTIONAL} function TZAbstractRODataset.SetUniDirectional(const Value: boolean); begin FUniDirectional := Value; end; {$ENDIF} {** Gets unidirectional state of dataset. @return the unidirectional flag (delphi). } function TZAbstractRODataset.GetUniDirectional: boolean; begin Result := {$IFNDEF WITH_FUNIDIRECTIONAL}FUniDirectional{$ELSE}inherited IsUniDirectional{$ENDIF}; end; {** Sets a new SQL query. @param Value a new SQL query. } procedure TZAbstractRODataset.SetSQL(Value: TStrings); begin FSQL.Assign(Value); end; {** Gets a parameters check value. @return a parameters check value. } function TZAbstractRODataset.GetParamCheck: Boolean; begin Result := FSQL.ParamCheck; end; {** Sets a new parameters check value. @param Value a parameters check value. } procedure TZAbstractRODataset.SetParamCheck(Value: Boolean); begin FSQL.ParamCheck := Value; UpdateSQLStrings(Self); end; {** Gets a parameters marker. @return a parameter marker. } function TZAbstractRODataset.GetParamChar: Char; begin Result := FSQL.ParamChar; end; {** Sets a new parameter marker. @param Value a parameter marker. } procedure TZAbstractRODataset.SetParamChar(Value: Char); begin FSQL.ParamChar := Value; UpdateSQLStrings(Self); end; {** Sets a new set of parameters. @param Value a set of parameters. } procedure TZAbstractRODataset.SetParams(Value: TParams); begin FParams.AssignValues(Value); end; {** Defines a persistent dataset properties. @param Filer a persistent manager object. } procedure TZAbstractRODataset.DefineProperties(Filer: TFiler); function WriteData: Boolean; begin if Filer.Ancestor <> nil then Result := not FParams.IsEqual(TZAbstractRODataset(Filer.Ancestor).FParams) else Result := FParams.Count > 0; end; begin inherited DefineProperties(Filer); Filer.DefineProperty('ParamData', ReadParamData, WriteParamData, WriteData); end; {** Reads parameter data from persistent storage. @param Reader an input data stream. } procedure TZAbstractRODataset.ReadParamData(Reader: TReader); begin Reader.ReadValue; Reader.ReadCollection(FParams); end; {** Writes parameter data from persistent storage. @param Writer an output data stream. } procedure TZAbstractRODataset.WriteParamData(Writer: TWriter); begin Writer.WriteCollection(Params); end; {** Gets a SQL parameter by its name. @param Value a parameter name. @return a found parameter object. } function TZAbstractRODataset.ParamByName(const Value: string): TParam; begin Result := FParams.ParamByName(Value); end; {** Updates parameters from SQL statement. @param Sender an event sender object. } procedure TZAbstractRODataset.UpdateSQLStrings(Sender: TObject); var I: Integer; OldParams: TParams; begin FieldDefs.Clear; if Active then Close else begin if assigned(Statement) then Statement.Close; Statement := nil; end; UnPrepare; OldParams := TParams.Create; OldParams.Assign(FParams); FParams.Clear; try for I := 0 to FSQL.ParamCount - 1 do FParams.CreateParam(ftUnknown, FSQL.ParamNames[I], ptUnknown); FParams.AssignValues(OldParams); finally OldParams.Free; end; end; {** Gets the ReadOnly property. @return True if the opened result set read only. } function TZAbstractRODataset.GetReadOnly: Boolean; begin Result := not RequestLive; end; {** Sets a new ReadOnly property. @param Value True to set result set read-only. } procedure TZAbstractRODataset.SetReadOnly(Value: Boolean); begin RequestLive := not Value; end; {** Gets a visible updated records types. @param return visible UpdateRecordTypes value. } function TZAbstractRODataset.GetShowRecordTypes: TUpdateStatusSet; begin Result := FShowRecordTypes; end; {** Sets a new visible updated records types. @param Value a new visible UpdateRecordTypes value. } procedure TZAbstractRODataset.SetShowRecordTypes(Value: TUpdateStatusSet); begin if Value <> FShowRecordTypes then begin FShowRecordTypes := Value; RereadRows; end; end; {** Checks if this dataset is opened. } procedure TZAbstractRODataset.CheckOpened; begin if not Active then DatabaseError(SOperationIsNotAllowed4); end; {** Checks if the database connection is assigned and tries to connect. } procedure TZAbstractRODataset.CheckConnected; begin if Connection = nil then raise EZDatabaseError.Create(SConnectionIsNotAssigned); Connection.Connect; end; {** Checks is the database has bidirectional access. } procedure TZAbstractRODataset.CheckBiDirectional; begin if IsUniDirectional then raise EZDatabaseError.Create(SOperationIsNotAllowed1); end; {** Checks the correct SQL query. } procedure TZAbstractRODataset.CheckSQLQuery; begin if FSQL.StatementCount < 1 then raise EZDatabaseError.Create(SQueryIsEmpty); if FSQL.StatementCount > 1 then raise EZDatabaseError.Create(SCanNotExecuteMoreQueries); end; {** Raises an error 'Operation is not allowed in read-only dataset. } procedure TZAbstractRODataset.RaiseReadOnlyError; begin raise EZDatabaseError.Create(SOperationIsNotAllowed2); end; {** Fetches specified number of records. @param RowCount a specified number of rows to be fetched. @return True if all required rows were fetched. } function TZAbstractRODataset.FetchRows(RowCount: Integer): Boolean; begin Connection.ShowSQLHourGlass; try if RowCount = 0 then begin while FetchOneRow do; Result := True; end else begin while (CurrentRows.Count < RowCount) do begin if not FetchOneRow then Break; end; Result := CurrentRows.Count >= RowCount; end; finally Connection.HideSQLHourGlass; end; end; {** Fetches one row from the result set. @return True if record was successfully fetched. } function TZAbstractRODataset.FetchOneRow: Boolean; begin repeat if (FetchCount = 0) or (ResultSet.GetRow = FetchCount) or ResultSet.MoveAbsolute(FetchCount) then Result := ResultSet.Next else Result := False; if Result then begin Inc(FFetchCount); if FilterRow(ResultSet.GetRow) then CurrentRows.Add(Pointer(ResultSet.GetRow)) else Continue; end; until True; end; {** Checks the specified row with the all filters. @param RowNo a number of the row. @return True if the row sutisfy to all filters. } function TZAbstractRODataset.FilterRow(RowNo: Integer): Boolean; var I: Integer; SavedRow: Integer; SavedRows: TZSortedList; SavedState: TDatasetState; begin Result := True; { Locates the result set to the specified row. } if ResultSet.GetRow <> RowNo then begin if not ResultSet.MoveAbsolute(RowNo) then Result := False; end; if not Result then Exit; { Checks record by ShowRecordType } if ResultSet.RowUpdated then Result := usModified in ShowRecordTypes else if ResultSet.RowInserted then Result := usInserted in ShowRecordTypes else if ResultSet.RowDeleted then Result := usDeleted in ShowRecordTypes else Result := usUnmodified in ShowRecordTypes; if not Result then Exit; { Check master-detail links } if MasterLink.Active then begin for I := 0 to MasterLink.Fields.Count - 1 do begin if I < IndexFields.Count then Result := CompareKeyFields(TField(IndexFields[I]), ResultSet, TField(MasterLink.Fields[I])); if not Result then Break; end; end; if not Result then Exit; { Checks record by OnFilterRecord event } if FilterEnabled and Assigned(OnFilterRecord) then begin SavedRow := CurrentRow; SavedRows := CurrentRows; CurrentRows := TZSortedList.Create; SavedState := SetTempState(dsNewValue); CurrentRows.Add(Pointer(RowNo)); CurrentRow := 1; try OnFilterRecord(Self, Result); except if Assigned(ApplicationHandleException) then ApplicationHandleException(Self); end; CurrentRow := SavedRow; CurrentRows.Free; CurrentRows := SavedRows; RestoreState(SavedState); end; if not Result then Exit; { Check the record by filter expression. } if FilterEnabled and (FilterExpression.Expression <> '') then begin if not InitFilterFields then begin FilterFieldRefs := DefineFilterFields(Self, FilterExpression); InitFilterFields := True; end; CopyDataFieldsToVars(FilterFieldRefs, ResultSet, FilterExpression.DefaultVariables); Result := FilterExpression.VariantManager.GetAsBoolean( FilterExpression.Evaluate4(FilterExpression.DefaultVariables, FilterExpression.DefaultFunctions, FilterStack)); end; if not Result then Exit; end; {** Go to specified row. @param RowNo a number of the row. @return True if the row successfully located. } function TZAbstractRODataset.GotoRow(RowNo: Integer): Boolean; var Index: Integer; begin Result := False; Index := CurrentRows.IndexOf(Pointer(RowNo)); if Index >= 0 then begin if Index < CurrentRow then CheckBiDirectional; CurrentRow := Index + 1; Result := True; end; end; {** Rereads all rows and applies a filter. } procedure TZAbstractRODataset.RereadRows; var I, RowNo: Integer; begin if not (State in [dsInactive]) and not IsUniDirectional then begin if (CurrentRow > 0) and (CurrentRow <= CurrentRows.Count) and (CurrentRows.Count > 0) then RowNo := Integer(CurrentRows[CurrentRow - 1]) else RowNo := -1; CurrentRows.Clear; for I := 1 to FetchCount do begin if FilterRow(I) then CurrentRows.Add(Pointer(I)); end; CurrentRow := CurrentRows.IndexOf(Pointer(RowNo)) + 1; CurrentRow := Min(Max(1, CurrentRow), CurrentRows.Count); if FSortedFields <> '' then InternalSort else Resync([]); end; end; {** Fill prepared statement with parameters. @param Statement a prepared SQL statement. @param ParamNames an array of parameter names. @param Params a collection of SQL parameters. @param DataLink a datalink to get parameters. } procedure TZAbstractRODataset.SetStatementParams(Statement: IZPreparedStatement; ParamNames: TStringDynArray; Params: TParams; DataLink: TDataLink); var I: Integer; TempParam, Param: TParam; Dataset: TDataset; Field: TField; begin if DataLink.Active then Dataset := DataLink.DataSet else Dataset := nil; TempParam := TParam.Create(nil); try for I := Low(ParamNames) to High(ParamNames) do begin if Assigned(Dataset) then Field := Dataset.FindField(ParamNames[I]) else Field := nil; if Assigned(Field) then begin TempParam.AssignField(Field); Param := TempParam; end else begin Param := Params.FindParam(ParamNames[I]); if not Assigned(Param) or (Param.ParamType in [ptOutput, ptResult]) then Continue; end; SetStatementParam(I+ 1, Statement, Param); end; finally TempParam.Free; end; end; {** Locates a specified record in dataset. @param Buffer a record buffer to put the contents of the row. @param GetMode a location mode. @param DoCheck flag to perform checking. @return a location result. } {$IFDEF WITH_TRECORDBUFFER} function TZAbstractRODataset.GetRecord(Buffer: TRecordBuffer; GetMode: TGetMode; DoCheck: Boolean): TGetResult; {$ELSE} function TZAbstractRODataset.GetRecord(Buffer: PChar; GetMode: TGetMode; DoCheck: Boolean): TGetResult; {$ENDIF} var RowNo: Integer; begin // mad stub for unidirectional (problem in TDataSet.MoveBuffer) - dont know about FPC // we always use same TDataSet-level buffer, because we can see only one row {$IFNDEF WITH_UNIDIRECTIONALBUG} if IsUniDirectional then Buffer := {$IFDEF WITH_BUFFERS_IS_TRECBUF}Pointer{$ENDIF}(Buffers[0]); {$ENDIF} Result := grOK; case GetMode of gmNext: begin if FetchRows(CurrentRow + 1) then CurrentRow := CurrentRow + 1 else Result := grEOF; end; gmPrior: begin CheckBiDirectional; if (CurrentRow > 1) and (CurrentRows.Count > 0) then CurrentRow := CurrentRow - 1 else Result := grBOF; end; gmCurrent: begin if CurrentRow < CurrentRows.Count then CheckBiDirectional; if CurrentRow = 0 then begin if CurrentRows.Count = 0 then FetchRows(1); CurrentRow := Min(CurrentRows.Count, 1); end else if not FetchRows(CurrentRow) then CurrentRow := Max(1, Min(CurrentRows.Count, CurrentRow)); if CurrentRows.Count = 0 then Result := grError; end; end; if Result = grOK then begin RowNo := Integer(CurrentRows[CurrentRow - 1]); if ResultSet.GetRow <> RowNo then ResultSet.MoveAbsolute(RowNo); RowAccessor.RowBuffer := PZRowBuffer(Buffer); RowAccessor.RowBuffer^.Index := RowNo; FetchFromResultSet(ResultSet, FieldsLookupTable, Fields, RowAccessor); FRowAccessor.RowBuffer^.BookmarkFlag := Ord(bfCurrent); GetCalcFields({$IFDEF WITH_GETCALCFIELDS_TRECBUF}NativeInt{$ENDIF}(Buffer)); end; if (Result = grError) and DoCheck then raise EZDatabaseError.Create(SNoMoreRecords); end; {** Gets the current record buffer depended on the current dataset state. @param RowBuffer a reference to the result row buffer. @return True if the buffer was defined. } function TZAbstractRODataset.GetActiveBuffer(var RowBuffer: PZRowBuffer): Boolean; var RowNo: Integer; CachedResultSet: IZCachedResultSet; begin RowBuffer := nil; case State of dsBrowse,dsblockread: if not IsEmpty then RowBuffer := PZRowBuffer(ActiveBuffer); dsEdit, dsInsert: RowBuffer := PZRowBuffer(ActiveBuffer); dsCalcFields: RowBuffer := PZRowBuffer(CalcBuffer); dsOldValue, dsNewValue, dsCurValue: begin RowNo := Integer(CurrentRows[CurrentRow - 1]); if RowNo <> ResultSet.GetRow then CheckBiDirectional; if State = dsOldValue then RowBuffer := OldRowBuffer else RowBuffer := NewRowBuffer; if RowBuffer.Index <> RowNo then begin RowAccessor.RowBuffer := RowBuffer; RowAccessor.Clear; if (ResultSet.GetRow = RowNo) or ResultSet.MoveAbsolute(RowNo) then begin if (State = dsOldValue) and (ResultSet. QueryInterface(IZCachedResultSet, CachedResultSet) = 0) then CachedResultSet.MoveToInitialRow; FetchFromResultSet(ResultSet, FieldsLookupTable, Fields, RowAccessor); RowBuffer.Index := RowNo; ResultSet.MoveToCurrentRow; end else RowBuffer := nil; end; end; end; Result := RowBuffer <> nil; end; function TZAbstractRODataset.GetFieldData(Field: TField; {$IFDEF WITH_VAR_TVALUEBUFFER}var{$ENDIF}Buffer: {$IFDEF WITH_TVALUEBUFFER}TValueBuffer{$ELSE}Pointer{$ENDIF}; NativeFormat: Boolean): Boolean; begin if Field.DataType in [ftWideString] then NativeFormat := True; Result := inherited GetFieldData(Field, Buffer, NativeFormat); end; {** Retrieves the column value and stores it into the field buffer. @param Field an field object to be retrieved. @param Buffer a field value buffer. @return True if non-null value was retrieved. } function TZAbstractRODataset.GetFieldData(Field: TField; {$IFDEF WITH_VAR_TVALUEBUFFER}var{$ENDIF}Buffer: {$IFDEF WITH_TVALUEBUFFER}TValueBuffer{$ELSE}Pointer{$ENDIF}): Boolean; var ColumnIndex: Integer; RowBuffer: PZRowBuffer; ACurrency: Double; Bts: TByteDynArray; {$IFNDEF WITH_WIDESTRUTILS} WS: WideString; {$ENDIF} begin if GetActiveBuffer(RowBuffer) then begin ColumnIndex := DefineFieldIndex(FieldsLookupTable, Field); RowAccessor.RowBuffer := RowBuffer; if Buffer <> nil then begin case Field.DataType of { Processes DateTime fields. } ftDate, ftTime, ftDateTime: begin if Field.DataType <> ftTime then DateTimeToNative(Field.DataType, RowAccessor.GetTimestamp(ColumnIndex, Result), Buffer) else DateTimeToNative(Field.DataType, RowAccessor.GetTime(ColumnIndex, Result), Buffer); Result := not Result; end; { Processes binary array fields. } ftBytes: begin Bts := RowAccessor.GetBytes(ColumnIndex, Result); System.Move(PAnsiChar(Bts)^, PAnsiChar(Buffer)^, Min(Length(Bts), RowAccessor.GetColumnDataSize(ColumnIndex))); Result := not Result; end; { Processes blob fields. } ftBlob, ftMemo, ftGraphic, ftFmtMemo {$IFDEF WITH_WIDEMEMO},ftWideMemo{$ENDIF} : Result := not RowAccessor.GetBlob(ColumnIndex, Result).IsEmpty; ftWideString: begin {$IFDEF WITH_WIDESTRUTILS} WStrCopy(PWideChar(Buffer), PWideChar(RowAccessor.GetUnicodeString(ColumnIndex, Result))); {$ELSE} //FPC: WideStrings are COM managed fields WS:=RowAccessor.GetUnicodeString(ColumnIndex, Result); //include null terminator in copy System.Move(PWideChar(WS)^,buffer^,(length(WS)+1)*sizeof(WideChar)); {$ENDIF} Result := not Result; end; ftString{$IFDEF WITH_FTGUID}, ftGUID{$ENDIF}: begin {$IFDEF WITH_STRCOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrCopy(PAnsiChar(Buffer), PAnsiChar({$IFDEF UNICODE}AnsiString{$ENDIF}(RowAccessor.GetString(ColumnIndex, Result)))); Result := not Result; end; {$IFDEF WITH_FTDATASETSUPPORT} ftDataSet: Result := not RowAccessor.GetDataSet(ColumnIndex, Result).IsEmpty; {$ENDIF} { Processes all other fields. } ftCurrency: begin {SizeOf(double) = 8Byte but SizeOf(Extented) = 10 Byte, so i need to convert the value} ACurrency := RowAccessor.GetDouble(ColumnIndex, Result); System.Move(Pointer(@ACurrency)^, Pointer(Buffer)^, SizeOf(Double)); Result := not Result; end; else begin System.Move(RowAccessor.GetColumnData(ColumnIndex, Result)^, Pointer(Buffer)^, RowAccessor.GetColumnDataSize(ColumnIndex)); Result := not Result; end; end; end else begin if Field.DataType in [ftBlob, ftMemo, ftGraphic, ftFmtMemo {$IFDEF WITH_WIDEMEMO},ftWideMemo{$ENDIF}] then Result := not RowAccessor.GetBlob(ColumnIndex, Result).IsEmpty else Result := not RowAccessor.IsNull(ColumnIndex); end; end else Result := False; end; {** Support for widestring field } procedure TZAbstractRODataset.SetFieldData(Field: TField; Buffer: {$IFDEF WITH_TVALUEBUFFER}TValueBuffer{$ELSE}Pointer{$ENDIF}; NativeFormat: Boolean); begin if Field.DataType in [ftWideString{$IFDEF WITH_WIDEMEMO}, ftWideMemo{$ENDIF}] then NativeFormat := True; {$IFNDEF VIRTUALSETFIELDDATA} inherited; {$ELSE} SetFieldData(Field, Buffer); {$ENDIF} end; {** Stores the column value from the field buffer. @param Field an field object to be stored. @param Buffer a field value buffer. } procedure TZAbstractRODataset.SetFieldData(Field: TField; Buffer: {$IFDEF WITH_TVALUEBUFFER}TValueBuffer{$ELSE}Pointer{$ENDIF}); var ColumnIndex: Integer; RowBuffer: PZRowBuffer; WasNull: Boolean; {$IFNDEF UNICODE} L: Cardinal; Temp: String; {$ENDIF} begin WasNull := False; if not Active then raise EZDatabaseError.Create(SOperationIsNotAllowed4); if not RequestLive and (Field.FieldKind = fkData) then RaiseReadOnlyError; // Check for readonly updates // Lookup values are requeried automatically on edit of all fields. // Didn't find a way to avoid this... if Field.ReadOnly and (Field.FieldKind <> fkLookup) and not (State in [dsSetKey, dsCalcFields, dsFilter, dsBlockRead, dsInternalCalc, dsOpening]) then DatabaseErrorFmt(SFieldReadOnly, [Field.DisplayName]); if not (State in dsWriteModes) then DatabaseError(SNotEditing, Self); if GetActiveBuffer(RowBuffer) then begin ColumnIndex := DefineFieldIndex(FieldsLookupTable, Field); RowAccessor.RowBuffer := RowBuffer; if State in [dsEdit, dsInsert] then Field.Validate(Buffer); if Assigned(Buffer) then begin case Field.DataType of ftDate, ftDateTime: { Processes Date/DateTime fields. } RowAccessor.SetTimestamp(ColumnIndex, NativeToDateTime(Field.DataType, Buffer)); ftTime: { Processes Time fields. } RowAccessor.SetTime(ColumnIndex, NativeToDateTime(Field.DataType, Buffer)); ftBytes: { Processes binary array fields. } RowAccessor.SetBytes(ColumnIndex, BufferToBytes(Pointer(Buffer), Field.Size)); ftWideString: { Processes widestring fields. } {$IFDEF WITH_PWIDECHAR_TOWIDESTRING} RowAccessor.SetUnicodeString(ColumnIndex, PWideChar(Buffer)); {$ELSE} RowAccessor.SetUnicodeString(ColumnIndex, PWideString(Buffer)^); {$ENDIF} ftString{$IFDEF WITH_FTGUID}, ftGUID{$ENDIF}: { Processes string fields. } {$IFDEF UNICODE} RowAccessor.SetString(ColumnIndex, String(PAnsichar(Buffer))); {$ELSE} begin L := {$IFDEF WITH_STRLEN_DEPRECATED}AnsiStrings.{$ENDIF}StrLen(PAnsiChar(Buffer)); SetLength(Temp, L); Move(PAnsiChar(Buffer)^, PAnsiChar(Temp)^, L); RowAccessor.SetString(ColumnIndex, Temp); end; {$ENDIF} ftCurrency: {SizeOf(curreny) = 8Byte but SizeOf(Extented) = 10 Byte, so i need to convert the value} RowAccessor.SetDouble(ColumnIndex, PDouble(Buffer)^); //cast Currrency to Extented else { Processes all other fields. } begin System.Move(Pointer(Buffer)^, RowAccessor.GetColumnData(ColumnIndex, WasNull)^, RowAccessor.GetColumnDataSize(ColumnIndex)); RowAccessor.SetNotNull(ColumnIndex); end; end; end else RowAccessor.SetNull(ColumnIndex); if not (State in [dsCalcFields, dsFilter, dsNewValue]) then DataEvent(deFieldChange, ULong(Field)); end else raise EZDatabaseError.Create(SRowDataIsNotAvailable); if Field.FieldKind = fkData then begin OldRowBuffer.Index := -1; NewRowBuffer.Index := -1; end; end; {** Checks is the cursor opened. @return True if the cursor is opened. } function TZAbstractRODataset.IsCursorOpen: Boolean; begin Result := ResultSet <> nil; end; {** Gets an affected rows by the last executed statement. @return a number of last updated rows. } function TZAbstractRODataset.RowsAffected: LongInt; begin Result := FRowsAffected; end; {** Gets the size of the record buffer. @return the size of the record buffer. } function TZAbstractRODataset.GetRecordSize: Word; begin Result := RowAccessor.RowSize; end; {** Allocates a buffer for new record. @return an allocated record buffer. } {$IFDEF WITH_TRECORDBUFFER} function TZAbstractRODataset.AllocRecordBuffer: TRecordBuffer; begin Result := TRecordBuffer(RowAccessor.Alloc); end; {$ELSE} function TZAbstractRODataset.AllocRecordBuffer: PChar; begin Result := PChar(RowAccessor.Alloc); end; {$ENDIF} {** Frees a previously allocated record buffer. @param Buffer a previously allocated buffer. } {$IFDEF WITH_TRECORDBUFFER} procedure TZAbstractRODataset.FreeRecordBuffer(var Buffer: TRecordBuffer); {$ELSE} procedure TZAbstractRODataset.FreeRecordBuffer(var Buffer: PChar); {$ENDIF} begin RowAccessor.DisposeBuffer(PZRowBuffer(Buffer)); end; {** Fetch all records. Added by Patyi } procedure TZAbstractRODataset.FetchAll; begin Connection.ShowSQLHourGlass; FetchRows(0); if Active then UpdateCursorPos; Connection.HideSQLHourGlass; end; {** Executes a DML SQL statement. } procedure TZAbstractRODataset.ExecSQL; begin if Active then begin Connection.ShowSQLHourGlass; try Close; finally Connection.HideSQLHourGlass; end; end; Prepare; Connection.ShowSQLHourGlass; try SetStatementParams(Statement, FSQL.Statements[0].ParamNamesArray, FParams, FDataLink); FRowsAffected := Statement.ExecuteUpdatePrepared; finally Connection.HideSQLHourGlass; end; end; {** Performs an internal initialization of field defiitions. } procedure TZAbstractRODataset.InternalInitFieldDefs; var I, J, Size: Integer; AutoInit: Boolean; FieldType: TFieldType; ResultSet: IZResultSet; FieldName: string; FName: string; begin FieldDefs.Clear; ResultSet := Self.ResultSet; AutoInit := ResultSet = nil; try { Opens an internal result set if query is closed. } if AutoInit then begin CheckSQLQuery; CheckConnected; Prepare; ResultSet := CreateResultSet(FSQL.Statements[0].SQL, 0); end; if not Assigned(ResultSet) then raise Exception.Create(SCanNotOpenResultSet); { Reads metadata from resultset. } with ResultSet.GetMetadata do begin if GetColumnCount > 0 then for I := 1 to GetColumnCount do begin FieldType := ConvertDbcToDatasetType(GetColumnType(I)); //if IsCurrency(I) then //FieldType := ftCurrency; if FieldType in [ftBytes, ftString, ftWidestring] then Size := GetPrecision(I) else {$IFDEF WITH_FTGUID} if FieldType = ftGUID then Size := 38 else {$ENDIF} Size := 0; J := 0; FieldName := GetColumnLabel(I); FName := FieldName; while FieldDefs.IndexOf(FName) >= 0 do begin Inc(J); FName := Format('%s_%d', [FieldName, J]); end; with TFieldDef.Create(FieldDefs, FName, FieldType, Size, False, I) do begin {$IFNDEF OLDFPC} Required := IsWritable(I) and (IsNullable(I) = ntNoNulls); {$ENDIF} if IsReadOnly(I) then Attributes := Attributes + [faReadonly]; Precision := GetPrecision(I); DisplayName := FName; end; end; end; finally { Closes localy opened resultset. } if AutoInit then begin if ResultSet <> nil then begin ResultSet.Close; ResultSet := nil; end; UnPrepare; end; end; end; {** Creates a DBC statement for the query. @param SQL an SQL query. @param Properties a statement specific properties. @returns a created DBC statement. } function TZAbstractRODataset.CreateStatement(const SQL: string; Properties: TStrings): IZPreparedStatement; var Temp: TStrings; begin Temp := TStringList.Create; try if Assigned(Properties) then Temp.AddStrings(Properties); { Define TDataset specific parameters. } if doCalcDefaults in FOptions then Temp.Values['defaults'] := 'true' else Temp.Values['defaults'] := 'false'; if doPreferPrepared in FOptions then Temp.Values['preferprepared'] := 'true' else Temp.Values['preferprepared'] := 'false'; Result := FConnection.DbcConnection.PrepareStatementWithParams(SQL, Temp); finally Temp.Free; end; end; {** Creates a DBC resultset for the query. @param SQL an SQL query. @param MaxRows a maximum rows number (-1 for all). @returns a created DBC resultset. } function TZAbstractRODataset.CreateResultSet(const SQL: string; MaxRows: Integer): IZResultSet; begin Connection.ShowSQLHourGlass; try SetStatementParams(Statement, FSQL.Statements[0].ParamNamesArray, FParams, FDataLink); if RequestLive then Statement.SetResultSetConcurrency(rcUpdatable) else Statement.SetResultSetConcurrency(rcReadOnly); Statement.SetFetchDirection(fdForward); if IsUniDirectional then Statement.SetResultSetType(rtForwardOnly) else Statement.SetResultSetType(rtScrollInsensitive); if MaxRows > 0 then Statement.SetMaxRows(MaxRows); if doSmartOpen in FOptions then begin if Statement.ExecutePrepared then Result := Statement.GetResultSet else Result := nil; end else Result := Statement.ExecuteQueryPrepared; finally Connection.HideSQLHourGlass; end; end; {** Performs internal query opening. } procedure TZAbstractRODataset.InternalOpen; var ColumnList: TObjectList; I: Integer; begin {$IFNDEF FPC} If (csDestroying in Componentstate) then raise Exception.Create(SCanNotOpenDataSetWhenDestroying); {$ENDIF} if not FUseCurrentStatment then Prepare; CurrentRow := 0; FetchCount := 0; CurrentRows.Clear; Connection.ShowSQLHourGlass; try { Creates an SQL statement and resultsets } if not FUseCurrentStatment then if FSQL.StatementCount> 0 then ResultSet := CreateResultSet(FSQL.Statements[0].SQL, -1) else ResultSet := CreateResultSet('', -1); if not Assigned(ResultSet) then begin if not (doSmartOpen in FOptions) then raise Exception.Create(SCanNotOpenResultSet) else Exit; end; { Initializes field and index defs. } if not FRefreshInProgress then InternalInitFieldDefs; if DefaultFields and not FRefreshInProgress then begin CreateFields; for i := 0 to Fields.Count -1 do if Fields[i].DataType in [ftString, ftWideString{$IFDEF WITH_FTGUID}, ftGUID{$ENDIF}] then {$IFDEF WITH_FTGUID} if Fields[i].DataType = ftGUID then Fields[i].DisplayWidth := 40 //to get a full view of the GUID values else {$ENDIF} if not (ResultSet.GetMetadata.GetColumnDisplaySize(I+1) = 0) then begin {$IFNDEF FPC}Fields[i].Size := ResultSet.GetMetadata.GetColumnDisplaySize(I+1);{$ENDIF} Fields[i].DisplayWidth := ResultSet.GetMetadata.GetColumnDisplaySize(I+1); end; end; BindFields(True); { Initializes accessors and buffers. } ColumnList := ConvertFieldsToColumnInfo(Fields); try RowAccessor := TZRowAccessor.Create(ColumnList, Connection.DbcConnection.GetConSettings); finally ColumnList.Free; end; FOldRowBuffer := PZRowBuffer(AllocRecordBuffer); FNewRowBuffer := PZRowBuffer(AllocRecordBuffer); FieldsLookupTable := CreateFieldsLookupTable(Fields); InitFilterFields := False; IndexFields.Clear; GetFieldList(IndexFields, FLinkedFields); {renamed by bangfauzan} { Performs sorting. } if FSortedFields <> '' then InternalSort; finally Connection.HideSQLHourGlass; end; end; {** Performs internal query closing. } procedure TZAbstractRODataset.InternalClose; begin if ResultSet <> nil then if not FDoNotCloseResultSet then ResultSet.Close; ResultSet := nil; if FOldRowBuffer <> nil then {$IFDEF WITH_TRECORDBUFFER} FreeRecordBuffer(TRecordBuffer(FOldRowBuffer)); // TRecordBuffer can be both pbyte and pchar in FPC. Don't assume. {$ELSE} FreeRecordBuffer(PChar(FOldRowBuffer)); {$ENDIF} FOldRowBuffer := nil; if FNewRowBuffer <> nil then {$IFDEF WITH_TRECORDBUFFER} FreeRecordBuffer(TRecordBuffer(FNewRowBuffer)); {$ELSE} FreeRecordBuffer(PChar(FNewRowBuffer)); {$ENDIF} FNewRowBuffer := nil; if RowAccessor <> nil then RowAccessor.Free; RowAccessor := nil; { Destroy default fields } if DefaultFields and not FRefreshInProgress then DestroyFields; CurrentRows.Clear; FieldsLookupTable := nil; end; {** Performs internal go to first record. } procedure TZAbstractRODataset.InternalFirst; begin if CurrentRow > 0 then CheckBiDirectional; CurrentRow := 0; end; {** Performs internal go to last record. } procedure TZAbstractRODataset.InternalLast; begin FetchRows(0); if CurrentRows.Count > 0 then CurrentRow := CurrentRows.Count + 1 else CurrentRow := 0; end; {** Processes internal exception handling. } procedure TZAbstractRODataset.InternalHandleException; begin // Application.HandleException(Self); end; {** Gets the maximum records count. @return the maximum records count. } function TZAbstractRODataset.GetRecordCount: LongInt; begin CheckActive; if not IsUniDirectional then FetchRows(FFetchRow); // the orginal code was FetchRows(0); modifyed by Patyi Result := CurrentRows.Count; end; {** Gets the current record number. @return the current record number. } function TZAbstractRODataset.GetRecNo: Longint; begin if Active then UpdateCursorPos; Result := CurrentRow; end; {** Moves current record to the specified record. @param Value a new current record number. } procedure TZAbstractRODataset.MoveRecNo(Value: Integer); var PreviousCurrentRow: Integer; begin Value := Max(1, Value); if Value < CurrentRow then CheckBiDirectional; if FetchRows(Value) then CurrentRow := Value else CurrentRow := CurrentRows.Count; PreviousCurrentRow := CurrentRow;//Resync moves the current row away try if not (State in [dsInactive]) then Resync([]); finally CurrentRow := PreviousCurrentRow; end; UpdateCursorPos; end; {** Sets a new currenct record number. @param Value a new current record number. } procedure TZAbstractRODataset.SetRecNo(Value: Integer); begin CheckOpened; Value := Max(1, Value); if Value < CurrentRow then CheckBiDirectional; DoBeforeScroll; MoveRecNo(Value); DoAfterScroll; end; {** Defines is the query editable? @return True if the query is editable. } function TZAbstractRODataset.GetCanModify: Boolean; begin Result := RequestLive; end; {** Gets a linked datasource. @returns a linked datasource. } function TZAbstractRODataset.GetDataSource: TDataSource; begin Result := DataLink.DataSource; end; {** Sets the value of the Prepared property. Setting to True prepares the query. Setting to False unprepares. @param Value a new value for the Prepared property. } procedure TZAbstractRODataset.SetPrepared(Value: Boolean); begin FUseCurrentStatment := False; FDoNotCloseResultSet := False; If Value <> FPrepared then begin If Value then InternalPrepare else InternalUnprepare; FPrepared := Value; end; end; {** Sets a new linked datasource. @param Value a new linked datasource. } procedure TZAbstractRODataset.SetDataSource(Value: TDataSource); begin {$IFNDEF FPC} if IsLinkedTo(Value) then {$ELSE} if Value.IsLinkedTo(Self) then {$ENDIF} raise EZDatabaseError.Create(SCircularLink); DataLink.DataSource := Value; end; {** Gets a master datasource. @returns a master datasource. } function TZAbstractRODataset.GetMasterDataSource: TDataSource; begin Result := MasterLink.DataSource; end; {** Sets a new master datasource. @param Value a new master datasource. } procedure TZAbstractRODataset.SetMasterDataSource(Value: TDataSource); begin {$IFNDEF FPC} if IsLinkedTo(Value) then {$ELSE} if Value.IsLinkedTo(Self) then {$ENDIF} raise EZDatabaseError.Create(SCircularLink); MasterLink.DataSource := Value; RereadRows; end; {** Gets master link fields. @returns a list with master fields. } function TZAbstractRODataset.GetMasterFields: string; begin Result := FMasterLink.FieldNames; end; {** Sets master link fields. @param Value a new master link fields. } procedure TZAbstractRODataset.SetMasterFields(const Value: string); begin if FMasterLink.FieldNames <> Value then begin FMasterLink.FieldNames := Value; RereadRows; end; end; {** Processes change events from the master dataset. @param Sender an event sender object. } procedure TZAbstractRODataset.MasterChanged(Sender: TObject); begin CheckBrowseMode; if (doAlwaysDetailResync in FOptions) or (FMasterLink.DataSet = nil) or not (FMasterLink.DataSet.State in [dsEdit, dsInsert]) then RereadRows; end; {** Processes disable events from the master dataset. @param Sender an event sender object. } procedure TZAbstractRODataset.MasterDisabled(Sender: TObject); begin RereadRows; end; {** Initializes new record with master fields. } {$WARNINGS OFF} procedure TZAbstractRODataset.DoOnNewRecord; var I: Integer; MasterField, DetailField: TField; Temp: Int64; P1, P2 : Integer; begin if MasterLink.Active and (MasterLink.Fields.Count > 0) then begin for I := 0 to MasterLink.Fields.Count - 1 do begin if I < IndexFields.Count then begin MasterField := TField(MasterLink.Fields[I]); DetailField := TField(IndexFields[I]); // Processes LargeInt fields. if (MasterField is TLargeIntField) or (DetailField is TLargeIntField) then begin if MasterField is TLargeIntField then Temp := TLargeIntField( MasterField).{$IFDEF WITH_ASLARGEINT}AsLargeInt{$ELSE}Value{$ENDIF} else Temp := MasterField.AsInteger; if DetailField is TLargeIntField then TLargeIntField(DetailField).{$IFDEF WITH_ASLARGEINT}AsLargeInt{$ELSE}Value{$ENDIF} := Temp else DetailField.AsString := IntToStr(Temp); end // Processes all other fields. else DetailField.Value := MasterField.Value; end; end; end else begin if DataLink.Active and (DataLink.dataset.Fields.Count > 0) then begin p1 := 1; p2 := 1; while (P1 <= Length(LinkedFields)) and (p2 <= Length(MasterFields)) do begin DetailField := FieldByName(ExtractFieldName(LinkedFields, P1)); MasterField := DataLink.DataSet.FieldByName (ExtractFieldName(MasterFields, P2)); DetailField.Assign(MasterField); end; end; end; inherited DoOnNewRecord; end; {$WARNINGS ON} {** Gets a list of index field names. @returns a list of index field names. } function TZAbstractRODataset.GetLinkedFields: string; {renamed by bangfauzan} begin Result := FLinkedFields; {renamed by bangfauzan} end; {** Sets a new list of index field names. @param Value a new list of index field names. } procedure TZAbstractRODataset.SetLinkedFields(const Value: string); {renamed by bangfauzan} begin if FLinkedFields <> Value then {renamed by bangfauzan} begin FLinkedFields := Value; {renamed by bangfauzan} IndexFields.Clear; if State <> dsInactive then begin GetFieldList(IndexFields, FLinkedFields); {renamed by bangfauzan} RereadRows; end; end; end; {** Sets a new set of dataset options. @param Value a new set of dataset options. } procedure TZAbstractRODataset.SetOptions(Value: TZDatasetOptions); begin if FOptions <> Value then FOptions := Value; end; {** Sets a new sorted fields. @param Value a new sorted fields. } procedure TZAbstractRODataset.SetSortedFields({const} Value: string); {bangfauzan modification} begin Value:=Trim(Value); {bangfauzan addition} if (FSortedFields <> Value) or (FIndexFieldNames <> Value)then {bangfauzan modification} begin FIndexFieldNames:=Value; FSortType := GetSortType; {bangfauzan addition} {removing ASC or DESC behind space} if (FSortType <> stIgnored) then begin {pawelsel modification} Value:=StringReplace(Value,' Desc','',[rfReplaceAll,rfIgnoreCase]); Value:=StringReplace(Value,' Asc','',[rfReplaceAll,rfIgnoreCase]); end; FSortedFields := Value; if Active then {InternalSort;} {bangfauzan modification} if (FSortedFields = '') then Self.InternalRefresh else InternalSort; {end of bangfauzan modification} end; end; {** Refreshes parameters and reopens the dataset. } procedure TZAbstractRODataset.RefreshParams; var DataSet: TDataSet; begin DisableControls; try if FDataLink.DataSource <> nil then begin DataSet := FDataLink.DataSource.DataSet; if DataSet <> nil then if DataSet.Active and not (DataSet.State in [dsSetKey, dsEdit]) then begin Refresh; end; end; finally EnableControls; end; end; {** Performs the internal preparation of the query. } procedure TZAbstractRODataset.InternalPrepare; begin CheckSQLQuery; CheckInactive; //AVZ - Need to check this CheckConnected; Connection.ShowSQLHourGlass; try if (FSQL.StatementCount > 0) and((Statement = nil) or (Statement.GetConnection.IsClosed)) then Statement := CreateStatement(FSQL.Statements[0].SQL, Properties) else if (Assigned(Statement)) then Statement.ClearParameters; finally Connection.HideSQLHourGlass; end; end; {** Rolls back the internal preparation of the query. } procedure TZAbstractRODataset.InternalUnPrepare; begin if Statement <> nil then begin Statement.Close; Statement := nil; end; end; {** Performs internal switch to the specified bookmark. @param Bookmark a specified bookmark. } procedure TZAbstractRODataset.InternalGotoBookmark(Bookmark: Pointer); begin if not GotoRow(PInteger(Bookmark)^) then raise EZDatabaseError.Create(SBookmarkWasNotFound); end; {** Performs an internal switch to the specified record. @param Buffer the specified row buffer. } {$IFDEF WITH_TRECORDBUFFER} procedure TZAbstractRODataset.InternalSetToRecord(Buffer: TRecordBuffer); {$ELSE} procedure TZAbstractRODataset.InternalSetToRecord(Buffer: PChar); {$ENDIF} begin GotoRow(PZRowBuffer(Buffer)^.Index); end; {** Performs an internal adding a new record. @param Buffer a buffer of the new adding record. @param Append True if record should be added to the end of the result set. } procedure TZAbstractRODataset.InternalAddRecord(Buffer: Pointer; Append: Boolean); begin RaiseReadOnlyError; end; {** Performs an internal record removing. } procedure TZAbstractRODataset.InternalDelete; begin RaiseReadOnlyError; end; {** Performs an internal post updates. } procedure TZAbstractRODataset.InternalPost; procedure Checkrequired; var I: longint; columnindex : integer; begin For I:=0 to Fields.Count-1 do With Fields[i] do Case State of dsEdit: if Required and not ReadOnly and (FieldKind=fkData) and IsNull then raise EZDatabaseError.Create(Format(SNeedField,[DisplayName])); dsInsert: if Required and not ReadOnly and (FieldKind=fkData) and IsNull then begin // allow autoincrement and defaulted fields to be null; columnindex := Resultset.FindColumn(Fields[i].FieldName); if (Columnindex = 0) or (not Resultset.GetMetadata.HasDefaultValue(columnIndex) and not Resultset.GetMetadata.IsAutoIncrement(columnIndex)) then raise EZDatabaseError.Create(Format(SNeedField,[DisplayName])); end; End; end; begin if not (Self is TZAbstractDataset) then RaiseReadOnlyError; Checkrequired; end; {** Gets a bookmark flag from the specified record. @param Buffer a pointer to the record buffer. @return a bookmark flag from the specified record. } {$IFDEF WITH_TRECORDBUFFER} function TZAbstractRODataset.GetBookmarkFlag(Buffer: TRecordBuffer): TBookmarkFlag; {$ELSE} function TZAbstractRODataset.GetBookmarkFlag(Buffer: PChar): TBookmarkFlag; {$ENDIF} begin Result := TBookmarkFlag(PZRowBuffer(Buffer)^.BookmarkFlag); end; {** Sets a new bookmark flag to the specified record. @param Buffer a pointer to the record buffer. @param Value a new bookmark flag to the specified record. } {$IFDEF WITH_TRECORDBUFFER} procedure TZAbstractRODataset.SetBookmarkFlag(Buffer: TRecordBuffer; Value: TBookmarkFlag); {$ELSE} procedure TZAbstractRODataset.SetBookmarkFlag(Buffer: PChar; Value: TBookmarkFlag); {$ENDIF} begin PZRowBuffer(Buffer)^.BookmarkFlag := Ord(Value); end; {** Gets bookmark value from the specified record. @param Buffer a pointer to the record buffer. @param Data a pointer to the bookmark value. } procedure TZAbstractRODataset.GetBookmarkData( Buffer: {$IFDEF WITH_TRECORDBUFFER}TRecordBuffer{$ELSE}PChar{$ENDIF}; Data: {$IFDEF WITH_BOOKMARKDATA_TBOOKMARK}TBookMark{$ELSE}Pointer{$ENDIF}); begin PInteger(Data)^ := PZRowBuffer(Buffer)^.Index; end; {** Sets a new bookmark value from the specified record. @param Buffer a pointer to the record buffer. @param Data a pointer to the bookmark value. } procedure TZAbstractRODataset.SetBookmarkData( Buffer: {$IFDEF WITH_TRECORDBUFFER}TRecordBuffer{$ELSE}PChar{$ENDIF}; Data: {$IFDEF WITH_BOOKMARKDATA_TBOOKMARK}TBookMark{$ELSE}Pointer{$ENDIF}); begin PZRowBuffer(Buffer)^.Index := PInteger(Data)^; end; {** Compare two specified bookmarks. @param Bookmark1 the first bookmark object. @param Bookmark2 the second bookmark object. @return 0 if bookmarks are equal, -1 if the first bookmark is less, 1 if the first bookmark is greatter. } function TZAbstractRODataset.CompareBookmarks(Bookmark1, Bookmark2: TBookmark): Integer; var Index1, Index2: Integer; begin Result := 0; if not Assigned(Bookmark1) or not Assigned(Bookmark2) then Exit; Index1 := CurrentRows.IndexOf(Pointer(PInteger(Bookmark1)^)); Index2 := CurrentRows.IndexOf(Pointer(PInteger(Bookmark2)^)); if Index1 < Index2 then Result := -1 else if Index1 > Index2 then Result := 1; end; {** Checks is the specified bookmark valid. @param Bookmark a bookmark object. @return True if the bookmark is valid. } function TZAbstractRODataset.BookmarkValid(Bookmark: TBookmark): Boolean; begin Result := False; if Active and Assigned(Bookmark) and (FResultSet <> nil) then try Result := CurrentRows.IndexOf(Pointer(PInteger(Bookmark)^)) >= 0; except Result := False; end; end; {** Performs an internal initialization of record buffer. @param Buffer a record buffer for initialization. } {$IFDEF WITH_TRECORDBUFFER} procedure TZAbstractRODataset.InternalInitRecord(Buffer: TRecordBuffer); {$ELSE} procedure TZAbstractRODataset.InternalInitRecord(Buffer: PChar); {$ENDIF} begin RowAccessor.ClearBuffer(PZRowBuffer(Buffer)); end; {** Performs an internal refreshing. } procedure TZAbstractRODataset.InternalRefresh; var RowNo: Integer; Found: Boolean; KeyFields: string; Temp: TZVariantDynArray; KeyValues: Variant; FieldRefs: TObjectDynArray; OnlyDataFields: Boolean; begin OnlyDataFields := False; FieldRefs := nil; if Active then begin if CurrentRow > 0 then begin RowNo := Integer(CurrentRows[CurrentRow - 1]); if ResultSet.GetRow <> RowNo then ResultSet.MoveAbsolute(RowNo); if Properties.Values['KeyFields'] <> '' then KeyFields := Properties.Values['KeyFields'] else KeyFields := DefineKeyFields(Fields); FieldRefs := DefineFields(Self, KeyFields, OnlyDataFields); SetLength(Temp, Length(FieldRefs)); RetrieveDataFieldsFromResultSet(FieldRefs, ResultSet, Temp); if Length(FieldRefs) = 1 then KeyValues := EncodeVariant(Temp[0]) else KeyValues := EncodeVariantArray(Temp); end else begin KeyFields := ''; KeyValues := Unassigned; end; DisableControls; try try FRefreshInProgress := True; InternalClose; InternalOpen; finally FRefreshInProgress := False; end; DoBeforeScroll; if KeyFields <> '' then Found := Locate(KeyFields, KeyValues, []) else Found := False; finally EnableControls; end; if not Found then begin DoBeforeScroll; DoAfterScroll; end; end; end; {** Finds the next record in a filtered query. @param Restart a True to find from the start of the query. @param GoForward True to navigate in the forward direction. @return True if a sutisfied row was found. } function TZAbstractRODataset.FindRecord(Restart, GoForward: Boolean): Boolean; var Index: Integer; SavedFilterEnabled: Boolean; begin { Checks the current state. } CheckBrowseMode; DoBeforeScroll; Result := False; { Defines an initial position position. } if Restart then begin if GoForward then Index := 1 else begin FetchRows(0); Index := CurrentRows.Count; end end else begin Index := CurrentRow; if GoForward then begin Inc(Index); if Index > CurrentRows.Count then FetchOneRow; end else Dec(Index); end; { Finds a record. } SavedFilterEnabled := FilterEnabled; try FilterEnabled := True; while (Index >= 1) and (Index <= CurrentRows.Count) do begin if FilterRow(Index) then begin Result := True; Break; end; if GoForward then begin Inc(Index); if Index > CurrentRows.Count then FetchOneRow; end else Dec(Index) end finally FilterEnabled := SavedFilterEnabled; end; { Sets a new found position. } SetFound(Result); if Result then begin MoveRecNo(Index); DoAfterScroll; end; end; {** Sets a filtering control flag. @param Value True to turn filtering On. } procedure TZAbstractRODataset.SetFiltered(Value: Boolean); begin if Value <> FilterEnabled then begin FilterEnabled := Value; inherited SetFiltered(Value); RereadRows; end; end; {** Sets a new filter expression string. @param Value a new filter expression. } procedure TZAbstractRODataset.SetFilterText(const Value: string); begin inherited SetFilterText(Value); FilterExpression.DefaultVariables.Clear; FilterExpression.Expression := Value; InitFilterFields := False; if FilterEnabled then RereadRows; end; {** Checks is the opened resultset sequensed? @return True if the opened resultset is sequenced. } function TZAbstractRODataset.IsSequenced: Boolean; begin Result := (not FilterEnabled); end; {** Processes component notifications. @param AComponent a changed component object. @param Operation a component operation code. } procedure TZAbstractRODataset.Notification(AComponent: TComponent; Operation: TOperation); begin inherited Notification(AComponent, Operation); if (Operation = opRemove) and (AComponent = FConnection) then begin Close; FConnection := nil; end; if (Operation = opRemove) and Assigned(FDataLink) and (AComponent = FDataLink.Datasource) then FDataLink.DataSource := nil; if (Operation = opRemove) and Assigned(FMasterLink) and (AComponent = FMasterLink.Datasource) then begin FMasterLink.DataSource := nil; RereadRows; end; end; {** Performs an internal record search. @param KeyFields a list of field names. @param KeyValues a list of field values. @param Options a search options. @return an index of found row or -1 if nothing was found. } function TZAbstractRODataset.InternalLocate(const KeyFields: string; const KeyValues: Variant; Options: TLocateOptions): LongInt; var I, RowNo, RowCount: Integer; FieldRefs: TObjectDynArray; FieldIndices: TIntegerDynArray; OnlyDataFields: Boolean; SearchRowBuffer: PZRowBuffer; DecodedKeyValues: TZVariantDynArray; RowValues: TZVariantDynArray; PartialKey: Boolean; CaseInsensitive: Boolean; begin OnlyDataFields := False; CheckBrowseMode; Result := -1; DecodedKeyValues := nil; PartialKey := loPartialKey in Options; CaseInsensitive := loCaseInsensitive in Options; FieldRefs := DefineFields(Self, KeyFields, OnlyDataFields); FieldIndices := nil; if FieldRefs = nil then Exit; DecodedKeyValues := DecodeVariantArray(KeyValues); { Checks for equal field and values number } if Length(FieldRefs) <> Length(DecodedKeyValues) then raise EZDatabaseError.Create(SIncorrectSearchFieldsNumber); SetLength(RowValues, Length(DecodedKeyValues)); if not OnlyDataFields then begin { Processes fields if come calculated or lookup fields are involved. } SearchRowBuffer := PZRowBuffer(AllocRecordBuffer); try I := 0; FieldIndices := DefineFieldIndices(FieldsLookupTable, FieldRefs); RowCount := CurrentRows.Count; while True do begin while (I >= RowCount) and FetchOneRow do RowCount := CurrentRows.Count; if I >= RowCount then Break; RowNo := Integer(CurrentRows[I]); ResultSet.MoveAbsolute(RowNo); RowAccessor.RowBuffer := SearchRowBuffer; RowAccessor.RowBuffer^.Index := RowNo; FetchFromResultSet(ResultSet, FieldsLookupTable, Fields, RowAccessor); {$IFDEF WITH_TRECORDBUFFER} GetCalcFields({$IFDEF WITH_GETCALCFIELDS_TRECBUF}NativeInt{$ELSE}TRecordBuffer{$ENDIF}(SearchRowBuffer)); {$ELSE} GetCalcFields(PChar(SearchRowBuffer)); {$ENDIF} RetrieveDataFieldsFromRowAccessor( FieldRefs, FieldIndices, RowAccessor, RowValues); if CompareDataFields(DecodedKeyValues, RowValues, PartialKey, CaseInsensitive) then begin Result := I + 1; Break; end; Inc(I); end; finally if SearchRowBuffer <> nil then {$IFDEF WITH_TRECORDBUFFER} FreeRecordBuffer(TRecordBuffer(SearchRowBuffer)); {$ELSE} FreeRecordBuffer(PChar(SearchRowBuffer)); {$ENDIF} end; end else begin PrepareValuesForComparison(FieldRefs, DecodedKeyValues, ResultSet, PartialKey, CaseInsensitive); { Processes only data fields. } I := 0; RowCount := CurrentRows.Count; while True do begin while (I >= RowCount) and FetchOneRow do RowCount := CurrentRows.Count; if I >= RowCount then Break; RowNo := Integer(CurrentRows[I]); ResultSet.MoveAbsolute(RowNo); if CompareFieldsFromResultSet(FieldRefs, DecodedKeyValues, ResultSet, PartialKey, CaseInsensitive) then begin Result := I + 1; Break; end; Inc(I); end; end; end; {** Locates an interested record by specified search criteria. @param KeyFields a list of field names. @param KeyValues a list of field values. @param Options a search options. @return True if record was found or False otherwise. } function TZAbstractRODataset.Locate(const KeyFields: string; const KeyValues: Variant; Options: TLocateOptions): Boolean; var Index: Integer; begin DoBeforeScroll; if (Active) then //AVZ Check if the dataset is active before performing locate - return false otherwise begin Index := InternalLocate(KeyFields, KeyValues, Options); if Index > 0 then begin MoveRecNo(Index); DoAfterScroll; Result := True; end else Result := False; SetFound(Result); end else begin Result := False; end; end; {** Lookups specified fields from the searched record. @param KeyValues a list of field names to search record. @param KeyValues an array of field values to search record. @param ResultFields a list of field names to return as a result. @return an array of requested field values. } function TZAbstractRODataset.Lookup(const KeyFields: string; const KeyValues: Variant; const ResultFields: string): Variant; var RowNo: Integer; FieldRefs: TObjectDynArray; FieldIndices: TIntegerDynArray; OnlyDataFields: Boolean; SearchRowBuffer: PZRowBuffer; ResultValues: TZVariantDynArray; begin OnlyDataFields := False; Result := Null; RowNo := InternalLocate(KeyFields, KeyValues, []); FieldRefs := nil; FieldIndices := nil; if RowNo < 0 then Exit; { Fill result array } FieldRefs := DefineFields(Self, ResultFields, OnlyDataFields); FieldIndices := DefineFieldIndices(FieldsLookupTable, FieldRefs); SetLength(ResultValues, Length(FieldRefs)); SearchRowBuffer := PZRowBuffer(AllocRecordBuffer); try RowNo := Integer(CurrentRows[RowNo - 1]); if ResultSet.GetRow <> RowNo then ResultSet.MoveAbsolute(RowNo); RowAccessor.RowBuffer := SearchRowBuffer; RowAccessor.RowBuffer^.Index := RowNo; FetchFromResultSet(ResultSet, FieldsLookupTable, Fields, RowAccessor); {$IFDEF WITH_TRECORDBUFFER} GetCalcFields({$IFDEF WITH_GETCALCFIELDS_TRECBUF}NativeInt{$ELSE}TRecordBuffer{$ENDIF}(SearchRowBuffer)); {$ELSE} GetCalcFields(PChar(SearchRowBuffer)); {$ENDIF} RetrieveDataFieldsFromRowAccessor( FieldRefs, FieldIndices, RowAccessor, ResultValues); finally {$IFDEF WITH_TRECORDBUFFER} FreeRecordBuffer(TRecordBuffer(SearchRowBuffer)); {$ELSE} FreeRecordBuffer(PChar(SearchRowBuffer)); {$ENDIF} end; if Length(FieldIndices) = 1 then Result := EncodeVariant(ResultValues[0]) else Result := EncodeVariantArray(ResultValues); end; {** Gets the updated status for the current row. @return the UpdateStatus value for the current row. } function TZAbstractRODataset.UpdateStatus: TUpdateStatus; var RowNo: Integer; begin Result := usUnmodified; if (ResultSet <> nil) and (CurrentRows.Count > 0) then begin RowNo := Integer(CurrentRows[CurrentRow - 1]); if ResultSet.GetRow <> RowNo then ResultSet.MoveAbsolute(RowNo); if ResultSet.RowInserted then Result := usInserted else if ResultSet.RowUpdated then Result := usModified else if ResultSet.RowDeleted then Result := usDeleted; end; end; {** Translates strings between ansi and oem character sets. } function TZAbstractRODataset.Translate(Src, Dest: PAnsiChar; ToOem: Boolean): Integer; begin if (Src <> nil) then begin Result := {$IFDEF WITH_STRLEN_DEPRECATED}AnsiStrings.{$ENDIF}StrLen(Src); {$IFNDEF UNIX} if doOemTranslate in FOptions then begin if ToOem then CharToOemA(Src, Dest) else OemToCharA(Src, Dest); Dest[Result] := #0; end else {$ENDIF} begin if (Src <> Dest) then {$IFDEF WITH_STRCOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrCopy(Dest, Src); end; end else Result := 0; end; {** Prepares the query. If this actually does happen at the database connection level depends on the specific implementation. } procedure TZAbstractRODataset.Prepare; begin Prepared := True; end; {** Unprepares the query. Before the query gets executed it must be prepared again. } procedure TZAbstractRODataset.Unprepare; begin Prepared := False; end; {** Creates a stream object for specified blob field. @param Field an interested field object. @param Mode a blob open mode. @return a created stream object. } function TZAbstractRODataset.CreateBlobStream(Field: TField; Mode: TBlobStreamMode): TStream; var ColumnIndex: Integer; RowBuffer: PZRowBuffer; Blob: IZBlob; WasNull: Boolean; begin WasNull := False; CheckActive; Result := nil; if (Field.DataType in [ftBlob, ftMemo, ftGraphic, ftFmtMemo {$IFDEF WITH_WIDEMEMO},ftWideMemo{$ENDIF}]) and GetActiveBuffer(RowBuffer) then begin ColumnIndex := DefineFieldIndex(FieldsLookupTable, Field); RowAccessor.RowBuffer := RowBuffer; if Mode = bmRead then begin case Field.DataType of ftMemo, ftFmtMemo: Result := RowAccessor.GetAsciiStream(ColumnIndex, WasNull); {$IFDEF WITH_WIDEMEMO} ftWideMemo: Result := RowAccessor.GetUnicodeStream(ColumnIndex, WasNull) {$ENDIF} else Result := RowAccessor.GetBinaryStream(ColumnIndex, WasNull); end; end else begin Blob := RowAccessor.GetBlob(ColumnIndex, WasNull); if Blob <> nil then Blob := Blob.Clone; RowAccessor.SetBlob(ColumnIndex, Blob); Result := TZBlobStream.Create(Field as TBlobField, Blob, Mode, FConnection.DbcConnection.GetConSettings); end; end; if Result = nil then Result := TMemoryStream.Create; end; {$IFDEF WITH_FTDATASETSUPPORT} function TZAbstractRODataset.CreateNestedDataSet(DataSetField: TDataSetField): TDataSet; begin Result := inherited CreateNestedDataSet(DataSetField); end; {$ENDIF} {** Closes the specified BLOB field. @param a BLOB field object. } procedure TZAbstractRODataset.CloseBlob(Field: TField); begin end; {** Closes the cursor-handles. Releases(not closing) the current resultset and opens the cursorhandles. The current statment is used further. @param the NewResultSet } procedure TZAbstractRODataset.SetAnotherResultset(const Value: IZResultSet); begin {EgonHugeist: I was forced to go this stupid sequence first i wanted to exclude parts of InternalOpen/Close but this didn't solve the DataSet issues. You can't init the fields as long the Cursor is not closed.. Which is equal to cursor open} if Assigned(Value) and ( Value <> ResultSet ) then begin FDoNotCloseResultSet := True; //hint for InternalClose SetState(dsInactive); CloseCursor; //Calls InternalOpen in his sequence so InternalClose must be prepared FDoNotCloseResultSet := False; //reset hint for InternalClose ResultSet := Value; //Assign the new resultset if not ResultSet.IsBeforeFirst then ResultSet.BeforeFirst; //need this. All from dataset buffered resultsets are EOR FUseCurrentStatment := True; //hint for InternalOpen OpenCursor{$IFDEF FPC}(False){$ENDIF}; //Calls InternalOpen in his sequence so InternalOpen must be prepared OpenCursorComplete; //set DataSet to dsActive FUseCurrentStatment := False; //reset hint for InternalOpen end; end; {** Performs sorting of the internal rows. } procedure TZAbstractRODataset.InternalSort; var I, RowNo: Integer; SavedRowBuffer: PZRowBuffer; begin if FIndexFieldNames = '' then exit; {bangfauzan addition} if (ResultSet <> nil) and not IsUniDirectional then begin FIndexFieldNames := Trim(FIndexFieldNames); {bangfauzan modification} DefineSortedFields(Self, {FSortedFields} FIndexFieldNames {bangfauzan modification}, FSortedFieldRefs, FSortedFieldDirs, FSortedOnlyDataFields); if (CurrentRow <= CurrentRows.Count) and (CurrentRows.Count > 0) and (CurrentRow > 0) then RowNo := Integer(CurrentRows[CurrentRow - 1]) else RowNo := -1; { Restores the previous order. } if Length(FSortedFieldRefs) = 0 then begin CurrentRows.Sort(ClearSort); end else begin FetchRows(0); if FSortedOnlyDataFields then begin { Converts field objects into field indices. } SetLength(FSortedFieldIndices, Length(FSortedFieldRefs)); for I := 0 to High(FSortedFieldRefs) do FSortedFieldIndices[I] := TField(FSortedFieldRefs[I]).FieldNo; { Performs a sorting. } CurrentRows.Sort(LowLevelSort); end else begin SavedRowBuffer := RowAccessor.RowBuffer; { Sorts using generic highlevel approach. } try { Allocates buffers for sorting. } RowAccessor.AllocBuffer(FSortRowBuffer1); RowAccessor.AllocBuffer(FSortRowBuffer2); { Converts field objects into field indices. } SetLength(FSortedFieldIndices, Length(FSortedFieldRefs)); for I := 0 to High(FSortedFieldRefs) do begin FSortedFieldIndices[I] := DefineFieldIndex(FieldsLookupTable, TField(FSortedFieldRefs[I])); end; { Performs sorting. } CurrentRows.Sort(HighLevelSort); finally { Disposed buffers for sorting. } RowAccessor.DisposeBuffer(FSortRowBuffer1); RowAccessor.DisposeBuffer(FSortRowBuffer2); RowAccessor.RowBuffer := SavedRowBuffer; end; end; end; CurrentRow := CurrentRows.IndexOf(Pointer(RowNo)) + 1; CurrentRow := Min(Max(0, CurrentRow), CurrentRows.Count); if not (State in [dsInactive]) then Resync([]); end; end; {** Clears list sorting and restores the previous order. @param Item1 a reference to the first row. @param Item2 a reference to the second row. @returns >0 if Item1 > Item2, <0 it Item1 < Item2 and 0 if Item1 and Item2 are equal. } function TZAbstractRODataset.ClearSort(Item1, Item2: Pointer): Integer; begin Result := Integer(Item1) - Integer(Item2); end; {** Sorting list using generic approach which is slow but may be used with calculated fields. @param Item1 a reference to the first row. @param Item2 a reference to the second row. @returns >0 if Item1 > Item2, <0 it Item1 < Item2 and 0 if Item1 and Item2 are equal. } function TZAbstractRODataset.HighLevelSort(Item1, Item2: Pointer): Integer; var RowNo: Integer; begin { Gets the first row. } RowNo := Integer(Item1); ResultSet.MoveAbsolute(RowNo); RowAccessor.RowBuffer := FSortRowBuffer1; RowAccessor.RowBuffer^.Index := RowNo; FetchFromResultSet(ResultSet, FieldsLookupTable, Fields, RowAccessor); FRowAccessor.RowBuffer^.BookmarkFlag := Ord(bfCurrent); {$IFDEF WITH_TRECORDBUFFER} GetCalcFields({$IFDEF WITH_GETCALCFIELDS_TRECBUF}NativeInt{$ELSE}TRecordBuffer{$ENDIF}(FSortRowBuffer1)); {$ELSE} GetCalcFields(PChar(FSortRowBuffer1)); {$ENDIF} { Gets the second row. } RowNo := Integer(Item2); ResultSet.MoveAbsolute(RowNo); RowAccessor.RowBuffer := FSortRowBuffer2; RowAccessor.RowBuffer^.Index := RowNo; FetchFromResultSet(ResultSet, FieldsLookupTable, Fields, RowAccessor); FRowAccessor.RowBuffer^.BookmarkFlag := Ord(bfCurrent); {$IFDEF WITH_TRECORDBUFFER} GetCalcFields({$IFDEF WITH_GETCALCFIELDS_TRECBUF}NativeInt{$ELSE}TRecordBuffer{$ENDIF}(FSortRowBuffer2)); {$ELSE} GetCalcFields(PChar(FSortRowBuffer2)); {$ENDIF} { Compare both records. } Result := RowAccessor.CompareBuffers(FSortRowBuffer1, FSortRowBuffer2, FSortedFieldIndices, FSortedFieldDirs); end; {** Sorting list using lowlevel approach which is fast but may not be used with calculated fields. @param Item1 a reference to the first row. @param Item2 a reference to the second row. @returns >0 if Item1 > Item2, <0 it Item1 < Item2 and 0 if Item1 and Item2 are equal. } function TZAbstractRODataset.LowLevelSort(Item1, Item2: Pointer): Integer; begin Result := ResultSet.CompareRows(Integer(Item1), Integer(Item2), FSortedFieldIndices, FSortedFieldDirs); end; {** Sets a new dataset properties. @param Value a dataset properties. } procedure TZAbstractRODataset.SetProperties(const Value: TStrings); begin FProperties.Assign(Value); end; {$IFDEF WITH_IPROVIDER} {** Starts a new transaction. } procedure TZAbstractRODataset.PSStartTransaction; begin if Assigned(FConnection) and not FConnection.AutoCommit then begin if not FConnection.Connected then FConnection.Connect; FConnection.StartTransaction; end; end; {** Completes previously started transaction. @param Commit a commit transaction flag. } procedure TZAbstractRODataset.PSEndTransaction(Commit: Boolean); begin if Assigned(FConnection) and FConnection.Connected and not FConnection.AutoCommit then begin if Commit then FConnection.Commit else FConnection.Rollback; end; end; {** Checks if this query is in transaction mode. @returns True if query in transaction. } function TZAbstractRODataset.PSInTransaction: Boolean; begin Result := Assigned(FConnection) and FConnection.Connected and (FConnection.TransactIsolationLevel <> tiNone) and not FConnection.AutoCommit; end; {** Returns a string quote character. @retuns a quote character. } {$IFDEF WITH_IPROVIDERWIDE} function TZAbstractRODataset.PSGetQuoteCharW: WideString; {$ELSE} function TZAbstractRODataset.PSGetQuoteChar: string; {$ENDIF} begin if Assigned(FConnection) then begin if not FConnection.Connected then FConnection.Connect; Result := FConnection.DbcConnection.GetMetadata.GetDatabaseInfo.GetIdentifierQuoteString; if Length(Result) > 1 then Result := Copy(Result, 1, 1); end else Result := '"'; end; {** Checks if dataset can execute any commands? @returns True if the query can execute any commands. } function TZAbstractRODataset.PSIsSQLSupported: Boolean; begin Result := True; end; {** Checks if dataset can execute SQL queries? @returns True if the query can execute SQL. } function TZAbstractRODataset.PSIsSQLBased: Boolean; begin Result := True; end; {** Resets this dataset. } procedure TZAbstractRODataset.PSReset; begin inherited PSReset; if Active then begin Refresh; First; end; end; {** Execute statement a SQL query. } procedure TZAbstractRODataset.PSExecute; begin ExecSQL; end; {** Gets query parameters. @returns parameters of this query. } function TZAbstractRODataset.PSGetParams: TParams; begin Result := Params; end; {** Set new query parameters @param AParams new parameters to set into this query. } procedure TZAbstractRODataset.PSSetParams(AParams: TParams); begin if AParams.Count > 0 then Params.Assign(AParams); end; {** Sets a command text for this query to execute. @param CommandText a command text for this query. } {$IFDEF WITH_IPROVIDERWIDE} procedure TZAbstractRODataset.PSSetCommandText(const CommandText: string); begin SQL.Text := CommandText; end; procedure TZAbstractRODataset.PSSetCommandText(const CommandText: WideString); {$ELSE} procedure TZAbstractRODataset.PSSetCommandText(const CommandText: string); {$ENDIF} begin SQL.Text := CommandText; end; {** Updates a record in the specified dataset. @param UpdateKind a type of the update. @param Delta a dataset with updates. } function TZAbstractRODataset.PSUpdateRecord(UpdateKind: TUpdateKind; Delta: TDataSet): Boolean; begin Result := False; end; {** Generates an EUpdateError object based on another exception object. @param E occured exception. @param Prev a previous update error. @returns a new created update error. } function TZAbstractRODataset.PSGetUpdateException(E: Exception; Prev: EUpdateError): EUpdateError; var PrevErrorCode: Integer; begin if E is EZSQLException then begin if Assigned(Prev) then PrevErrorCode := Prev.ErrorCode else PrevErrorCode := 0; Result := EUpdateError.Create(E.Message, '', EZSQLException(E).ErrorCode, PrevErrorCode, E); end else Result := EUpdateError.Create(E.Message, '', -1, -1, E); end; {** Gets a table name if table is only one in the SELECT SQL statement. @returns a table name or an empty string is SQL query is complex SELECT or not SELECT statement. } {$IFDEF WITH_IPROVIDERWIDE} function TZAbstractRODataset.PSGetTableNameW: WideString; {$ELSE} function TZAbstractRODataset.PSGetTableName: string; {$ENDIF} var Driver: IZDriver; Tokenizer: IZTokenizer; StatementAnalyser: IZStatementAnalyser; SelectSchema: IZSelectSchema; begin Result := ''; if FConnection <> nil then begin Driver := FConnection.DbcDriver; Tokenizer := Driver.GetTokenizer; StatementAnalyser := Driver.GetStatementAnalyser; SelectSchema := StatementAnalyser.DefineSelectSchemaFromQuery( Tokenizer, SQL.Text); if Assigned(SelectSchema) and (SelectSchema.TableCount = 1) then Result := SelectSchema.Tables[0].FullName; end; end; {** Defines a list of query primary key fields. @returns a semicolon delimited list of query key fields. } // Silvio Clecio {$IFDEF WITH_IPROVIDERWIDE} {$WARNINGS OFF} function TZAbstractRODataset.PSGetKeyFieldsW: WideString; begin Result := inherited PSGetKeyFieldsW; end; {$WARNINGS ON} {$ELSE} function TZAbstractRODataset.PSGetKeyFields: string; begin Result := inherited PSGetKeyFields; end; {$ENDIF} {** Executes a SQL statement with parameters. @param ASQL a SQL statement with parameters defined with question marks. @param AParams a collection of statement parameters. @param ResultSet a supplied result set reference (just ignored). @returns a number of updated rows. } {$IFDEF WITH_IPROVIDERWIDE} function TZAbstractRODataset.PSExecuteStatement(const ASQL: WideString; AParams: TParams; ResultSet: Pointer = nil): Integer; {$ELSE} function TZAbstractRODataset.PSExecuteStatement(const ASQL: string; AParams: TParams; ResultSet: Pointer): Integer; {$ENDIF} var I: Integer; Statement: IZPreparedStatement; ParamValue: TParam; begin if Assigned(FConnection) then begin if not FConnection.Connected then FConnection.Connect; Statement := FConnection.DbcConnection.PrepareStatement(ASQL); if (AParams <> nil) and (AParams.Count > 0) then for I := 0 to AParams.Count - 1 do begin ParamValue := AParams[I]; SetStatementParam(I+1, Statement, ParamValue); end; Result := Statement.ExecuteUpdatePrepared; end else Result := 0; end; {$ENDIF} procedure TZAbstractRODataset.CheckFieldCompatibility(Field: TField;FieldDef: TFieldDef); const {EH: hint all commented types are the fields the RowAccessor can't handle -> avoid stack killing moves in Get/SetFieldData() this Error trapping is made for User-added fields like calulateds ....} BaseFieldTypes: array[TFieldType] of TFieldType = ( //generic TFieldTypes of FPC and Delphi(since D7, of course): ftUnknown, ftString, ftSmallint, ftInteger, ftWord, // 0..4 ftBoolean, ftFloat, ftCurrency, ftFloat{ftBCD}, ftDate, ftTime, ftDateTime, // 5..11 ftBytes, ftBytes{ftVarBytes}, ftInteger{ftAutoInc}, ftBlob, ftMemo, ftBlob{ftGraphic}, ftMemo{ftFmtMemo}, // 12..18 ftBlob{ftParadoxOle}, ftBlob{ftDBaseOle}, ftBlob{ftTypedBinary}, ftUnknown{ftCursor}, ftString{ftFixedChar}, ftWideString, // 19..24 ftLargeint, ftUnknown{ftADT}, ftUnknown{ftArray}, ftUnknown{ftReference}, ftDataSet, ftBlob{ftOraBlob}, ftMemo{ftOraClob}, // 25..31 ftUnknown{ftVariant}, ftUnknown{ftInterface}, ftUnknown{ftIDispatch}, ftGuid, ftTimeStamp, ftFloat{ftFMTBcd} // 32..37 {$IFDEF FPC} //addition types for FPC , ftWideString{ftFixedWideChar}, ftWideMemo // 38..39 {$ELSE !FPC} {$IF CompilerVersion >= 18} //additional Types since D2006 and D2007 , ftWideString{ftFixedWideChar}, ftWideMemo, ftDateTime{ftOraTimeStamp}, ftDateTime{ftOraInterval} // 38..41 {$IF CompilerVersion >= 20} //additional Types since D2009 , ftLongWord, ftShortint, ftByte, ftExtended, ftUnknown{ftConnection}, ftUnknown{ftParams}, ftBlob{ftStream} //42..48 {$IF CompilerVersion >= 21} //additional Types since D2010 , ftDateTime{ftTimeStampOffset}, ftUnknown{ftObject}, ftSingle //49..51 {$IFEND CompilerVersion >= 21} {$IFEND CompilerVersion >= 20} {$IFEND CompilerVersion >= 18} {$ENDIF FPC} ); CheckTypeSizes = [ftBytes, ftVarBytes, ftBCD, ftReference]; begin with Field do begin if (BaseFieldTypes[DataType] <> BaseFieldTypes[FieldDef.DataType]) then DatabaseErrorFmt(SFieldTypeMismatch, [DisplayName, FieldTypeNames[DataType], FieldTypeNames[FieldDef.DataType]], Self); if (DataType in CheckTypeSizes) and (Size <> FieldDef.Size) then DatabaseErrorFmt(SFieldSizeMismatch, [DisplayName, Size, FieldDef.Size], Self); end; end; {** Reset the calculated (includes fkLookup) fields @param Buffer } {$IFDEF WITH_TRECORDBUFFER} procedure TZAbstractRODataset.ClearCalcFields(Buffer: TRecordBuffer); {$ELSE} procedure TZAbstractRODataset.ClearCalcFields(Buffer: PChar); {$ENDIF} var Index: Integer; begin RowAccessor.RowBuffer := PZRowBuffer(Buffer); for Index := 1 to Fields.Count do if (Fields[Index-1].FieldKind in [fkCalculated, fkLookup]) then RowAccessor.SetNull(DefineFieldindex(FFieldsLookupTable,Fields[Index-1])); end; {=======================bangfauzan addition========================} function TZAbstractRODataset.GetSortType: TSortType; var AscCount, DescCount: Integer; s: String; begin {pawelsel modification} AscCount:=0; DescCount:=0; s:=StringReplace(FIndexFieldNames,';',',',[rfReplaceAll]); while Pos(',',s)>0 do begin if Pos(' DESC',UpperCase(Copy(s,1,Pos(',',s))))>0 then Inc(DescCount) else Inc(AscCount); s:=Copy(s,Pos(',',s)+1,Length(s)-Pos(',',s)); end; if Length(s)>0 then if Pos(' DESC',UpperCase(s))>0 then Inc(DescCount) else Inc(AscCount); if (DescCount > 0) and (AscCount > 0) then Result:=stIgnored else if (DescCount > 0) then Result:=stDescending else Result:=stAscending; end; procedure TZAbstractRODataset.SetSortType(Value: TSortType); begin if FSortType <> Value then begin FSortType := Value; if (FSortType <> stIgnored) then begin {pawelsel modification} FSortedFields:=StringReplace(FSortedFields,' Desc','',[rfReplaceAll,rfIgnoreCase]); FSortedFields:=StringReplace(FSortedFields,' Asc','',[rfReplaceAll,rfIgnoreCase]); end; FIndexFieldNames:=GetIndexFieldNames; if Active then if (FSortedFields = '') then Self.InternalRefresh else InternalSort; end; end; function TZAbstractRODataset.GetIndexFieldNames : String; begin Result:=FSortedFields; if Result <> '' then begin {pawelsel modification} if FSortType = stAscending then begin Result:=StringReplace(Result,';',' Asc;',[rfReplaceAll]); Result:=StringReplace(Result,',',' Asc,',[rfReplaceAll]); Result:=Result+' Asc'; end; if FSortType = stDescending then begin Result:=StringReplace(Result,';',' Desc;',[rfReplaceAll]); Result:=StringReplace(Result,',',' Desc,',[rfReplaceAll]); Result:=Result+' Desc'; end; end; end; procedure TZAbstractRODataset.SetIndexFieldNames(Value: String); begin Value:=Trim(Value); {pawelsel modification} Value:=StringReplace(Value,'[','',[rfReplaceAll]); Value:=StringReplace(Value,']','',[rfReplaceAll]); if FIndexFieldNames <> Value then begin FIndexFieldNames := Value; FSortType:=GetSortType; if (FSortType <> stIgnored) then begin {pawelsel modification} Value:=StringReplace(Value,' Desc','',[rfReplaceAll,rfIgnoreCase]); Value:=StringReplace(Value,' Asc','',[rfReplaceAll,rfIgnoreCase]); end; FSortedFields:=Value; end; {Perform sorting} if Active then if (FSortedFields = '') then Self.InternalRefresh else InternalSort; end; {====================end of bangfauzan addition====================} end. ================================================ FILE: lib/zeosdbo/src/component/ZAbstractTable.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Abstract Table component } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZAbstractTable; interface {$I ZComponent.inc} uses SysUtils, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} ZAbstractDataset; type {** Abstract dataset component which works with one specified table. } TZAbstractTable = class(TZAbstractDataset) private FTableName: string; private function GetExists: Boolean; procedure SetTableName(const Value: string); protected {$IFDEF WITH_IPROVIDER} function PSIsSQLBased: Boolean; override; {$IFDEF WITH_IPROVIDERWIDE} function PSGetTableNameW: WideString; override; {$ELSE} function PSGetTableName: string; override; {$ENDIF} procedure PSSetCommandText(const ACommandText: string); override; {$ENDIF} protected property Exists: Boolean read GetExists; property TableName: string read FTableName write SetTableName; end; implementation { TZAbstractTable } {** Checks if a table with the corresponding name exists in the database. @return True if the the table exists. } function TZAbstractTable.GetExists: Boolean; var TableList: TStringList; begin TableList := TStringList.Create; try CheckConnected; Connection.GetTableNames(TableName, TableList); TableList.CaseSensitive := False; Result := (TableList.IndexOf(TableName) >= 0); // look for an exact match finally TableList.Free; end; end; {** Sets a new table name and generates a related SQL statement. @param Value a new name of table. } procedure TZAbstractTable.SetTableName(const Value: string); begin if FTableName <> Value then begin FTableName := Value; if Value <> '' then SQL.Text := Format('SELECT * FROM %s', [FTableName]) else SQL.Text := ''; end; end; {$IFDEF WITH_IPROVIDER} {** Checks if dataset can execute SQL queries? @returns True if the query can execute SQL. } function TZAbstractTable.PSIsSQLBased: Boolean; begin Result := False; end; {** Gets the name of the table. @returns the name of this table. } {$IFDEF WITH_IPROVIDERWIDE} function TZAbstractTable.PSGetTableNameW: WideString; {$ELSE} function TZAbstractTable.PSGetTableName: string; {$ENDIF} begin Result := TableName; end; {** Assignes a new name for this table. @param ACommandText a new name for this table. } procedure TZAbstractTable.PSSetCommandText(const ACommandText: string); begin TableName := ACommandText; end; {$ENDIF} end. ================================================ FILE: lib/zeosdbo/src/component/ZComponent.inc ================================================ {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} {$IFDEF LINUX} {$DEFINE UNIX} {$ENDIF} {$IFNDEF UNIX} {$I ..\Zeos.inc} {$ELSE} {$I ../Zeos.inc} {$ENDIF} ================================================ FILE: lib/zeosdbo/src/component/ZComponentReg.lrs ================================================ LazarusResources.Add('TZConnection','XPM',[ '/* XPM */'#13#10'static char * TZConnection.xpm_xpm[] = {'#13#10'"24 24 97 2' +'",'#13#10'" '#9'c #23236E",'#13#10'". '#9'c #000058",'#13#10'"+ '#9'c None' +'",'#13#10'"@ '#9'c #C8C8DA",'#13#10'"# '#9'c #282B6F",'#13#10'"$ '#9'c #ACD' +'5AC",'#13#10'"% '#9'c #89C489",'#13#10'"& '#9'c #65B265",'#13#10'"* '#9'c #' +'42A042",'#13#10'"= '#9'c #229022",'#13#10'"- '#9'c #349934",'#13#10'"; '#9 +'c #58AB58",'#13#10'"> '#9'c #7CBD7C",'#13#10'", '#9'c #A0CEA0",'#13#10'"'' ' +#9'c #C4E0C4",'#13#10'") '#9'c #FCFDFC",'#13#10'"! '#9'c #595D90",'#13#10'"~' +' '#9'c #004627",'#13#10'"{ '#9'c #007F00",'#13#10'"] '#9'c #259225",'#13#10 +'"^ '#9'c #B9DCB9",'#13#10'"/ '#9'c #F4F4F7",'#13#10'"( '#9'c #060B58",'#13 +#10'"_ '#9'c #000355",'#13#10'": '#9'c #00700A",'#13#10'"< '#9'c #148C14",' +#13#10'"[ '#9'c #ACACC8",'#13#10'"} '#9'c #001F41",'#13#10'"| '#9'c #008300"' +','#13#10'"1 '#9'c #00A500",'#13#10'"2 '#9'c #4B4B89",'#13#10'"3 '#9'c #003B' +'1F",'#13#10'"4 '#9'c #006A00",'#13#10'"5 '#9'c #007300",'#13#10'"6 '#9'c #0' +'07900",'#13#10'"7 '#9'c #007D00",'#13#10'"8 '#9'c #008000",'#13#10'"9 '#9'c' +' #008100",'#13#10'"0 '#9'c #008500",'#13#10'"a '#9'c #008B00",'#13#10'"b '#9 +'c #009200",'#13#10'"c '#9'c #009C00",'#13#10'"d '#9'c #00AF00",'#13#10'"e ' +#9'c #00B800",'#13#10'"f '#9'c #E8E8EF",'#13#10'"g '#9'c #0A0A5E",'#13#10'"h' +' '#9'c #040758",'#13#10'"i '#9'c #005705",'#13#10'"j '#9'c #006400",'#13#10 +'"k '#9'c #006B00",'#13#10'"l '#9'c #007200",'#13#10'"m '#9'c #008700",'#13 +#10'"n '#9'c #008E00",'#13#10'"o '#9'c #009500",'#13#10'"p '#9'c #00A300",' +#13#10'"q '#9'c #00AA00",'#13#10'"r '#9'c #00B100",'#13#10'"s '#9'c #9797BA"' +','#13#10'"t '#9'c #20325A",'#13#10'"u '#9'c #005D00",'#13#10'"v '#9'c #3838' +'7C",'#13#10'"w '#9'c #4A735D",'#13#10'"x '#9'c #010158",'#13#10'"y '#9'c #0' +'00255",'#13#10'"z '#9'c #B8B8EA",'#13#10'"A '#9'c #5F945F",'#13#10'"B '#9'c' +' #00A711",'#13#10'"C '#9'c #1717BE",'#13#10'"D '#9'c #00B001",'#13#10'"E '#9 +'c #003385",'#13#10'"F '#9'c #0000B8",'#13#10'"G '#9'c #006054",'#13#10'"H ' +#9'c #DFDFF5",'#13#10'"I '#9'c #008726",'#13#10'"J '#9'c #0003B4",'#13#10'"K' +' '#9'c #009B09",'#13#10'"L '#9'c #00189E",'#13#10'"M '#9'c #003B75",'#13#10 +'"N '#9'c #6A9C6A",'#13#10'"O '#9'c #033488",'#13#10'"P '#9'c #DEE9DE",'#13 +#10'"Q '#9'c #2A772A",'#13#10'"R '#9'c #0CB40C",'#13#10'"S '#9'c #8ECF9E",' +#13#10'"T '#9'c #FDFEFD",'#13#10'"U '#9'c #B3D1B3",'#13#10'"V '#9'c #84B884"' +','#13#10'"W '#9'c #61A861",'#13#10'"X '#9'c #3D993D",'#13#10'"Y '#9'c #1A8C' +'1A",'#13#10'"Z '#9'c #0D930D",'#13#10'"` '#9'c #30A830",'#13#10'" .'#9'c #5' +'4BD54",'#13#10'"..'#9'c #78CD78",'#13#10'"+.'#9'c #9CDE9C",'#13#10'"@.'#9'c' +' #EDF9ED",'#13#10'"#.'#9'c #F9FCF9",'#13#10'" . . . . + + + + + + + + + + ' +'+ + + + + + + + + ",'#13#10'"+ + @ . # $ % & * = - ; > , '' ) + + + + + + +' +' + ",'#13#10'"+ + ! . ~ { { { { { { { { { { ] ^ + + + + + + + ",'#13#10'"+ ' +'/ ( _ : { { { { { { { { { { { < + + + + + + + ",'#13#10'"+ [ . } { { { { { ' +'{ { { { { { | 1 + + + + + + + ",'#13#10'"+ 2 . 3 4 5 6 7 { 8 9 0 a b c d e ' +'+ + + + + + + ",'#13#10'"f g h i j k l 6 8 m n o c p q r e + + + + + + + ",' +#13#10'"s . t u j k l 6 8 m n o c p q r e + + + + + + + ",'#13#10'"v . w u j' +' k l 6 8 m n o c p q r e + + + + + + + ",'#13#10'". . x y y k l 6 8 m n o c' +' p q r e z + + + + + + ",'#13#10'"+ + A u j k l 6 8 m n o c p q r B C + + +' +' + + + ",'#13#10'"+ + A u j k l 6 8 m n o c p q D E F + + + + + + ",'#13#10 +'"+ + A u j k l 6 8 m n o c p q G F F H H H H H + ",'#13#10'"+ + A u j k l 6' +' 8 m n o c p I J F F F F F F F + ",'#13#10'"+ + A u j k l 6 8 m n o c K L F' +' F F F F F F F + ",'#13#10'"+ + A u j k l 6 8 m n o c M F F F F F F F F F +' +' ",'#13#10'"+ + A u j k l 6 8 m n o c M F F F F F F F F F + ",'#13#10'"+ + ' +'A u j k l 6 8 m n o c K L F F F F F F F F + ",'#13#10'"+ + A u j k l 6 8 m ' +'n o c p I J F F F F F F F + ",'#13#10'"+ + A u j k l 6 8 m n o c p q G F F ' +'H H H H H + ",'#13#10'"+ + N u j k l 6 8 m n o c p q D O F + + + + + + ",' +#13#10'"+ + P Q j k l 6 8 m n o c p q R S C + + + + + + ",'#13#10'"+ + + T U' +' V W X Y m Z ` ...+.@.+ z + + + + + + ",'#13#10'"+ + + + + + + + + #.+ + +' +' + + + + + + + + + + + "};'#13#10 ]); LazarusResources.Add('TZReadOnlyQuery','XPM',[ '/* XPM */'#13#10'static char * TZReadOnlyQuery.xpm_xpm[] = {'#13#10'"24 24 1' +'55 2",'#13#10'" '#9'c #23236E",'#13#10'". '#9'c #000058",'#13#10'"+ '#9'c ' +'None",'#13#10'"@ '#9'c #FBC5C5",'#13#10'"# '#9'c #F55050",'#13#10'"$ '#9'c ' +'#F23535",'#13#10'"% '#9'c #C8C8DA",'#13#10'"& '#9'c #2F2F76",'#13#10'"* '#9 +'c #F88787",'#13#10'"= '#9'c #F10202",'#13#10'"- '#9'c #F10000",'#13#10'"; ' +#9'c #F1CCCC",'#13#10'"> '#9'c #22167D",'#13#10'", '#9'c #342690",'#13#10'"' +''' '#9'c #6149C1",'#13#10'") '#9'c #634CC4",'#13#10'"! '#9'c #6551C6",'#13 +#10'"~ '#9'c #6755C8",'#13#10'"{ '#9'c #6A59CA",'#13#10'"] '#9'c #6C5ECC",' +#13#10'"^ '#9'c #6E62CF",'#13#10'"/ '#9'c #7166D1",'#13#10'"( '#9'c #736AD4"' +','#13#10'"_ '#9'c #9154A5",'#13#10'": '#9'c #F00001",'#13#10'"< '#9'c #F001' +'01",'#13#10'"[ '#9'c #A172B5",'#13#10'"} '#9'c #F4F4F7",'#13#10'"| '#9'c #0' +'6045E",'#13#10'"1 '#9'c #02015A",'#13#10'"2 '#9'c #533DB2",'#13#10'"3 '#9'c' +' #634DC3",'#13#10'"4 '#9'c #6651C5",'#13#10'"5 '#9'c #6755C7",'#13#10'"6 '#9 +'c #6A59CB",'#13#10'"7 '#9'c #6C5DCD",'#13#10'"8 '#9'c #6F62CF",'#13#10'"9 ' +#9'c #7165D2",'#13#10'"0 '#9'c #736AD3",'#13#10'"a '#9'c #CA2243",'#13#10'"b' +' '#9'c #D02E4A",'#13#10'"c '#9'c #ACACC8",'#13#10'"d '#9'c #171071",'#13#10 +'"e '#9'c #5E45BE",'#13#10'"f '#9'c #6049C0",'#13#10'"g '#9'c #634DC4",'#13 +#10'"h '#9'c #6551C5",'#13#10'"i '#9'c #6A5ACA",'#13#10'"j '#9'c #6C5DCC",' +#13#10'"k '#9'c #7165D1",'#13#10'"l '#9'c #E52832",'#13#10'"m '#9'c #F1EBEB"' +','#13#10'"n '#9'c #E72C34",'#13#10'"o '#9'c #4B4B89",'#13#10'"p '#9'c #A3A3' +'C2",'#13#10'"q '#9'c #B3B3B3",'#13#10'"r '#9'c #EB2F2F",'#13#10'"s '#9'c #E' +'8E8EF",'#13#10'"t '#9'c #0A0A5E",'#13#10'"u '#9'c #09095C",'#13#10'"v '#9'c' +' #EFEFF4",'#13#10'"w '#9'c #FEFEFE",'#13#10'"x '#9'c #F54F4F",'#13#10'"y '#9 +'c #DD3838",'#13#10'"z '#9'c #9797BA",'#13#10'"A '#9'c #3D3D77",'#13#10'"B ' +#9'c #B4B4B4",'#13#10'"C '#9'c #C18B8B",'#13#10'"D '#9'c #C18A8A",'#13#10'"E' +' '#9'c #38387C",'#13#10'"F '#9'c #8B8B9F",'#13#10'"G '#9'c #F78686",'#13#10 +'"H '#9'c #020259",'#13#10'"I '#9'c #06065B",'#13#10'"J '#9'c #FDFDFD",'#13 +#10'"K '#9'c #9494B8",'#13#10'"L '#9'c #181864",'#13#10'"M '#9'c #1A1A69",' +#13#10'"N '#9'c #616197",'#13#10'"O '#9'c #E7E7EF",'#13#10'"P '#9'c #D7D7E4"' +','#13#10'"Q '#9'c #4E4E8B",'#13#10'"R '#9'c #101060",'#13#10'"S '#9'c #1010' +'62",'#13#10'"T '#9'c #3F3F81",'#13#10'"U '#9'c #C1C1D6",'#13#10'"V '#9'c #2' +'72771",'#13#10'"W '#9'c #C9C9DB",'#13#10'"X '#9'c #3A3A75",'#13#10'"Y '#9'c' +' #6F6F90",'#13#10'"Z '#9'c #323271",'#13#10'"` '#9'c #2A2A6D",'#13#10'" .'#9 +'c #9D9DA8",'#13#10'"..'#9'c #07075B",'#13#10'"+.'#9'c #5B5B86",'#13#10'"@.' +#9'c #62628A",'#13#10'"#.'#9'c #131361",'#13#10'"$.'#9'c #88889D",'#13#10'"%' +'.'#9'c #1B1B65",'#13#10'"&.'#9'c #C0C0D5",'#13#10'"*.'#9'c #4F4F80",'#13#10 +'"=.'#9'c #E3E3EC",'#13#10'"-.'#9'c #ECECF2",'#13#10'";.'#9'c #9898BB",'#13 +#10'">.'#9'c #A5A5C4",'#13#10'",.'#9'c #68689C",'#13#10'"''.'#9'c #A9A9C6",' +#13#10'").'#9'c #D1D1E0",'#13#10'"!.'#9'c #404081",'#13#10'"~.'#9'c #424283"' +','#13#10'"{.'#9'c #34347A",'#13#10'"].'#9'c #8686AF",'#13#10'"^.'#9'c #F8F8' +'FA",'#13#10'"/.'#9'c #3A3A7D",'#13#10'"(.'#9'c #F0F0F5",'#13#10'"_.'#9'c #1' +'71767",'#13#10'":.'#9'c #131364",'#13#10'"<.'#9'c #FCFCFD",'#13#10'"[.'#9'c' +' #85859B",'#13#10'"}.'#9'c #4B4B7E",'#13#10'"|.'#9'c #151562",'#13#10'"1.'#9 +'c #3E3E77",'#13#10'"2.'#9'c #28286C",'#13#10'"3.'#9'c #A7A7AD",'#13#10'"4.' +#9'c #B2B2B3",'#13#10'"5.'#9'c #0F0F5F",'#13#10'"6.'#9'c #0E0E5F",'#13#10'"7' +'.'#9'c #F7F7F9",'#13#10'"8.'#9'c #0F0F61",'#13#10'"9.'#9'c #69699C",'#13#10 +'"0.'#9'c #ADADC9",'#13#10'"a.'#9'c #EEEEF3",'#13#10'"b.'#9'c #B6B6CF",'#13 +#10'"c.'#9'c #B7B7CF",'#13#10'"d.'#9'c #39397D",'#13#10'"e.'#9'c #9292B7",' +#13#10'"f.'#9'c #5F5F96",'#13#10'"g.'#9'c #434383",'#13#10'"h.'#9'c #E1E1EB"' +','#13#10'"i.'#9'c #0B0B5F",'#13#10'"j.'#9'c #121263",'#13#10'"k.'#9'c #8080' +'AB",'#13#10'"l.'#9'c #24246F",'#13#10'"m.'#9'c #010158",'#13#10'"n.'#9'c #D' +'3D3E2",'#13#10'"o.'#9'c #191968",'#13#10'"p.'#9'c #ABABC7",'#13#10'"q.'#9'c' +' #BCBCD3",'#13#10'"r.'#9'c #252570",'#13#10'"s.'#9'c #5C5C94",'#13#10'"t.'#9 +'c #E5E5ED",'#13#10'"u.'#9'c #D6D6E4",'#13#10'"v.'#9'c #181867",'#13#10'"w.' +#9'c #333379",'#13#10'"x.'#9'c #9C9CBE",'#13#10'" . . . . + + + + + + + + +' +' + + @ # $ $ # @ + + ",'#13#10'"+ + % . & + + + + + + + + + + * = - ; ; - =' +' * + ",'#13#10'"+ + > . , '' ) ! ~ { ] ^ / ( _ : - - ; ; - - < [ ",'#13#10 +'"+ } | 1 2 '' 3 4 5 6 7 8 9 0 a - - - ; ; - - - b ",'#13#10'"+ c . d e f g ' +'h ~ i j ^ k 0 l ; ; ; m m ; ; ; n ",'#13#10'"+ o . p + + + + + + + q + + $ ' +'; ; ; m m ; ; ; r ",'#13#10'"s t u v + + + + + + + q w w x - - - ; ; - - - ' +'y ",'#13#10'"z . A q q q q q q q q q B B C < - - ; ; - - < D ",'#13#10'"E .' +' F + + + + + + + + q + + + G = - ; ; - = * q ",'#13#10'". . H I I + + + + +' +' + q w w w J @ # $ $ # @ + q ",'#13#10'"+ + q q q q q q q q q q B B B q q q' +' q q q q q q ",'#13#10'"+ + q + + + + + + + + q + + + + + + + + + + + q ",' ,#13#10'"+ + q w w w w w w w + q w w w w w w w w w w w q ",'#13#10'"+ + q B B' +' B B B B B B q B B B B B B B B B B B q ",'#13#10'"+ + q + + + + + + + + q +' +' + + + + + + + + + + q ",'#13#10'"+ K L I M N O + + P Q R S T U + + . V w w' +' w w q ",'#13#10'"W . X Y Z . ` q ...u +.@.#.. $.B . %.B B B B q ",'#13#10 +'"&.. *.=.-.;.>.+ ,.. ''.q + ).. !.+ . V + + + + q ",'#13#10'"J ~.. . {.].^.' +'+ /.. (.q + + _.:.+ . V w w w w q ",'#13#10'"+ <.[.}.|.. 1.q 2.. 3.q q 4.5.' +'6.q . %.q q q q q ",'#13#10'";.E O + 7.t 8.+ 9.. 0.a.9.b.. o + . V + + + + ' +'+ ",'#13#10'"c.. d.e.f.. g.+ h.i.j.k.l.. m.n.+ . o.p.p.p.q.+ ",'#13#10'"+ ;' +'.r.I o.s.t.+ + u.o v.:.g.t ~.+ . . . . . w.+ ",'#13#10'"+ + + + + + + + + +' +' + + + + s x.+ + + + + + + + "};'#13#10 ]); LazarusResources.Add('TZConnectionGroup','XPM',[ '/* XPM */'#13#10'static char * TZConnectionGroup.xpm_xpm[] = {'#13#10'"24 24' +' 100 2",'#13#10'" '#9'c #23236E",'#13#10'". '#9'c #000058",'#13#10'"+ '#9 +'c None",'#13#10'"@ '#9'c #F8FAF8",'#13#10'"# '#9'c #95CA95",'#13#10'"$ '#9 +'c #5FAF5F",'#13#10'"% '#9'c #2F972F",'#13#10'"& '#9'c #0B850B",'#13#10'"* ' +#9'c #000000",'#13#10'"= '#9'c #080808",'#13#10'"- '#9'c #2F2F2F",'#13#10'";' +' '#9'c #A5A5A5",'#13#10'"> '#9'c #C8C8DA",'#13#10'", '#9'c #2F2F76",'#13#10 +'"'' '#9'c #44A144",'#13#10'") '#9'c #007F00",'#13#10'"! '#9'c #ADADAD",'#13 +#10'"~ '#9'c #616197",'#13#10'"{ '#9'c #8D8DB4",'#13#10'"] '#9'c #017701",' +#13#10'"^ '#9'c #018901",'#13#10'"/ '#9'c #FDFDFD",'#13#10'"( '#9'c #E9E9E9"' +','#13#10'"_ '#9'c #797979",'#13#10'": '#9'c #414141",'#13#10'"< '#9'c #F4F4' +'F7",'#13#10'"[ '#9'c #111163",'#13#10'"} '#9'c #07075C",'#13#10'"| '#9'c #E' +'2E2EC",'#13#10'"1 '#9'c #005C00",'#13#10'"2 '#9'c #007200",'#13#10'"3 '#9'c' +' #007B00",'#13#10'"4 '#9'c #007E00",'#13#10'"5 '#9'c #008000",'#13#10'"6 '#9 +'c #008600",'#13#10'"7 '#9'c #009000",'#13#10'"8 '#9'c #00AA00",'#13#10'"9 ' +#9'c #F6F6F6",'#13#10'"0 '#9'c #171717",'#13#10'"a '#9'c #ACACC8",'#13#10'"b' +' '#9'c #424283",'#13#10'"c '#9'c #005A00",'#13#10'"d '#9'c #006400",'#13#10 +'"e '#9'c #006F00",'#13#10'"f '#9'c #007900",'#13#10'"g '#9'c #008300",'#13 +#10'"h '#9'c #008E00",'#13#10'"i '#9'c #009800",'#13#10'"j '#9'c #00A200",' +#13#10'"k '#9'c #00AD00",'#13#10'"l '#9'c #070707",'#13#10'"m '#9'c #4B4B89"' +','#13#10'"n '#9'c #A3A3C2",'#13#10'"o '#9'c #010101",'#13#10'"p '#9'c #E8E8' +'EF",'#13#10'"q '#9'c #0A0A5E",'#13#10'"r '#9'c #0D0D60",'#13#10'"s '#9'c #E' +'FEFF4",'#13#10'"t '#9'c #9797BA",'#13#10'"u '#9'c #575790",'#13#10'"v '#9'c' +' #090909",'#13#10'"w '#9'c #38387C",'#13#10'"x '#9'c #C7C7DA",'#13#10'"y '#9 +'c #212121",'#13#10'"z '#9'c #DFDFDF",'#13#10'"A '#9'c #030359",'#13#10'"B ' +#9'c #06065B",'#13#10'"C '#9'c #565656",'#13#10'"D '#9'c #969696",'#13#10'"E' +' '#9'c #146614",'#13#10'"F '#9'c #14B314",'#13#10'"G '#9'c #CCCCCC",'#13#10 +'"H '#9'c #060606",'#13#10'"I '#9'c #0B0B0B",'#13#10'"J '#9'c #9D9D9D",'#13 +#10'"K '#9'c #AECBAE",'#13#10'"L '#9'c #1D751D",'#13#10'"M '#9'c #1DAC1D",' +#13#10'"N '#9'c #B3E6B3",'#13#10'"O '#9'c #B8B8B8",'#13#10'"P '#9'c #1A1A1A"' +','#13#10'"Q '#9'c #E7F0E7",'#13#10'"R '#9'c #B7D8B7",'#13#10'"S '#9'c #93CA' +'93",'#13#10'"T '#9'c #B7DFB7",'#13#10'"U '#9'c #E7F5E7",'#13#10'"V '#9'c #A' +'4A4A4",'#13#10'"W '#9'c #161616",'#13#10'"X '#9'c #B6B6B6",'#13#10'"Y '#9'c' +' #404040",'#13#10'"Z '#9'c #949494",'#13#10'"` '#9'c #E0E0E0",'#13#10'" .'#9 +'c #F7F7F7",'#13#10'"..'#9'c #FEFEFE",'#13#10'"+.'#9'c #040404",'#13#10'"@.' +#9'c #6F6F6F",'#13#10'"#.'#9'c #323232",'#13#10'"$.'#9'c #B3CEB3",'#13#10'"%' +'.'#9'c #A0A0A0",'#13#10'"&.'#9'c #2D2D2D",'#13#10'" . . . . + + + @ # $ % ' +'& % $ # @ * = - ; + + + ",'#13#10'"+ + > . , + + + '' ) ) ) ) ) ) ) '' * * ' +'* * ! + + ",'#13#10'"+ + ~ . { + + + ] ) ) ) ) ) ) ) ^ / ( _ * : + + ",'#13 +#10'"+ < [ } | + + + 1 2 3 4 ) 5 6 7 8 + + 9 * 0 + + ",'#13#10'"+ a . b + + ' +'+ + c d e f g h i j k + + + * l + + ",'#13#10'"+ m . n + + + + c d e f g h ' +'i j k + + + * o + + ",'#13#10'"p q r s + + + + c d e f g h i j k + + + o * ' +'+ + ",'#13#10'"t . u + + + + + c d e f g h i j k + + + v * 9 + ",'#13#10'"w' +' . x + + + + + c d e f g h i j k + + + y * z + ",'#13#10'". . A B B + + + c' +' d e f g h i j k + + + C * D + ",'#13#10'"+ + + + + + + + E d e f g h i j F' +' + + + G H I J ",'#13#10'"@ # $ % & % $ # K L e f g h i M N + + + + O P * "' +','#13#10'"'' ) ) ) ) ) ) ) '' + Q R S T U + + + + + + V W * ",'#13#10'"] ) ' +') ) ) ) ) ) ^ + + + + + + + + + + + X o I J ",'#13#10'"1 2 3 4 ) 5 6 7 8 + ' +'+ + + + + + + + + + Y * Z + ",'#13#10'"c d e f g h i j k + + + + + + + + + ' +'+ + l * ` + ",'#13#10'"c d e f g h i j k + + + + + + + + + + + * * .+ ",' +#13#10'"c d e f g h i j k + + + + + + + + + + + * * + + ",'#13#10'"c d e f g' +' h i j k + + + + + + + + + + + * * + + ",'#13#10'"c d e f g h i j k + + + +' +' + + + + + + ..* * + + ",'#13#10'"c d e f g h i j k + + + + + + + + + + ( *' +' +.+ + ",'#13#10'"E d e f g h i j F + + + + + + + + ..( @.* #.+ + ",'#13#10 +'"$.L e f g h i M N + + + + + + + + * * * * %.+ + ",'#13#10'"+ + Q R S T U +' +' + + + + + + + + + * l &.J + + + "};'#13#10 ]); LazarusResources.Add('TZPgEventAlerter','XPM',[ '/* XPM */'#13#10'static char * TZPgEventAlerter.xpm_xpm[] = {'#13#10'"24 24 ' +'259 2",'#13#10'" '#9'c #23236E",'#13#10'". '#9'c #000058",'#13#10'"+ '#9'c' +' None",'#13#10'"@ '#9'c #B0B0B0",'#13#10'"# '#9'c #000000",'#13#10'"$ '#9'c' +' #D4D4D4",'#13#10'"% '#9'c #C8C8DA",'#13#10'"& '#9'c #2F2F76",'#13#10'"* '#9 +'c #EBCF7C",'#13#10'"= '#9'c #616197",'#13#10'"- '#9'c #8D8DB4",'#13#10'"; ' +#9'c #584E1E",'#13#10'"> '#9'c #F2DB88",'#13#10'", '#9'c #F6EAB4",'#13#10'"' +''' '#9'c #C4A94C",'#13#10'") '#9'c #403816",'#13#10'"! '#9'c #F4F4F7",'#13 +#10'"~ '#9'c #101062",'#13#10'"{ '#9'c #06065C",'#13#10'"] '#9'c #DADAE4",' +#13#10'"^ '#9'c #FDFDFD",'#13#10'"/ '#9'c #F7F7F7",'#13#10'"( '#9'c #EFEFEF"' +','#13#10'"_ '#9'c #F3F3F3",'#13#10'": '#9'c #DFDFDF",'#13#10'"< '#9'c #D5D5' +'D5",'#13#10'"[ '#9'c #C6B165",'#13#10'"} '#9'c #FAF3CF",'#13#10'"| '#9'c #F' +'CF2BE",'#13#10'"1 '#9'c #F4E18F",'#13#10'"2 '#9'c #BD9D37",'#13#10'"3 '#9'c' +' #E9E9E9",'#13#10'"4 '#9'c #6D6D8A",'#13#10'"5 '#9'c #212163",'#13#10'"6 '#9 +'c #868687",'#13#10'"7 '#9'c #929292",'#13#10'"8 '#9'c #A6A6A6",'#13#10'"9 ' +#9'c #9C9C9C",'#13#10'"0 '#9'c #878888",'#13#10'"a '#9'c #7E7F80",'#13#10'"b' +' '#9'c #7E7F7F",'#13#10'"c '#9'c #838383",'#13#10'"d '#9'c #828486",'#13#10 +'"e '#9'c #6C6F71",'#13#10'"f '#9'c #F7E6A6",'#13#10'"g '#9'c #FEFAE7",'#13 +#10'"h '#9'c #FBEB9C",'#13#10'"i '#9'c #C5AA4A",'#13#10'"j '#9'c #594E1F",' +#13#10'"k '#9'c #989898",'#13#10'"l '#9'c #252869",'#13#10'"m '#9'c #4D6190"' +','#13#10'"n '#9'c #7E9BB2",'#13#10'"o '#9'c #899EB0",'#13#10'"p '#9'c #A3A9' +'AD",'#13#10'"q '#9'c #8C98A3",'#13#10'"r '#9'c #849EB4",'#13#10'"s '#9'c #7' +'495B0",'#13#10'"t '#9'c #7D9BB3",'#13#10'"u '#9'c #A4B8C7",'#13#10'"v '#9'c' +' #B7C8D6",'#13#10'"w '#9'c #C1A342",'#13#10'"x '#9'c #FAF2C4",'#13#10'"y '#9 +'c #FEF8D3",'#13#10'"z '#9'c #FFFADA",'#13#10'"A '#9'c #FDF1A8",'#13#10'"B ' +#9'c #EED060",'#13#10'"C '#9'c #AF820E",'#13#10'"D '#9'c #707D8F",'#13#10'"E' +' '#9'c #03055A",'#13#10'"F '#9'c #02055A",'#13#10'"G '#9'c #2D5E8B",'#13#10 +'"H '#9'c #31658F",'#13#10'"I '#9'c #5580A3",'#13#10'"J '#9'c #92AEC4",'#13 +#10'"K '#9'c #527EA1",'#13#10'"L '#9'c #356892",'#13#10'"M '#9'c #334553",' +#13#10'"N '#9'c #9D9153",'#13#10'"O '#9'c #FAE98D",'#13#10'"P '#9'c #FFF4B3"' +','#13#10'"Q '#9'c #FFF5BC",'#13#10'"R '#9'c #FFF092",'#13#10'"S '#9'c #FDEB' +'7A",'#13#10'"T '#9'c #F4D750",'#13#10'"U '#9'c #D8A717",'#13#10'"V '#9'c #7' +'97979",'#13#10'"W '#9'c #485A8D",'#13#10'"X '#9'c #11226B",'#13#10'"Y '#9'c' +' #326690",'#13#10'"Z '#9'c #86A4BD",'#13#10'"` '#9'c #698FAD",'#13#10'" .'#9 +'c #295477",'#13#10'"..'#9'c #221E0C",'#13#10'"+.'#9'c #F0D262",'#13#10'"@.' +#9'c #F8E379",'#13#10'"#.'#9'c #FAF0AC",'#13#10'"$.'#9'c #FAE77C",'#13#10'"%' +'.'#9'c #F9E161",'#13#10'"&.'#9'c #F1D145",'#13#10'"*.'#9'c #E6BE28",'#13#10 +'"=.'#9'c #C99507",'#13#10'"-.'#9'c #845C00",'#13#10'";.'#9'c #131C68",'#13 +#10'">.'#9'c #274F83",'#13#10'",.'#9'c #3F7097",'#13#10'"''.'#9'c #92ADC3",' +#13#10'").'#9'c #3A6C94",'#13#10'"!.'#9'c #C4A14E",'#13#10'"~.'#9'c #CDB369"' +','#13#10'"{.'#9'c #D2BA78",'#13#10'"].'#9'c #D8C38A",'#13#10'"^.'#9'c #D0B8' +'70",'#13#10'"/.'#9'c #C7AA53",'#13#10'"(.'#9'c #B78F23",'#13#10'"_.'#9'c #A' +'97A02",'#13#10'":.'#9'c #A07000",'#13#10'"<.'#9'c #8E6100",'#13#10'"[.'#9'c' +' #5B3C00",'#13#10'"}.'#9'c #000158",'#13#10'"|.'#9'c #010259",'#13#10'"1.'#9 +'c #9BB4C8",'#13#10'"2.'#9'c #6C91AF",'#13#10'"3.'#9'c #7295B2",'#13#10'"4.' +#9'c #517DA0",'#13#10'"5.'#9'c #0F0F0F",'#13#10'"6.'#9'c #5D86A7",'#13#10'"7' +'.'#9'c #5C85A6",'#13#10'"8.'#9'c #B4C7D6",'#13#10'"9.'#9'c #88A6BE",'#13#10 +'"0.'#9'c #B1C5D4",'#13#10'"a.'#9'c #97B1C6",'#13#10'"b.'#9'c #3C6D95",'#13 +#10'"c.'#9'c #6189A9",'#13#10'"d.'#9'c #A9BFD0",'#13#10'"e.'#9'c #90ACC2",' +#13#10'"f.'#9'c #A1B9CC",'#13#10'"g.'#9'c #FFEF8C",'#13#10'"h.'#9'c #D2D2D2"' +','#13#10'"i.'#9'c #5983A5",'#13#10'"j.'#9'c #87A5BE",'#13#10'"k.'#9'c #8FAB' +'C2",'#13#10'"l.'#9'c #507CA0",'#13#10'"m.'#9'c #6A90AE",'#13#10'"n.'#9'c #7' +'99AB6",'#13#10'"o.'#9'c #96B0C6",'#13#10'"p.'#9'c #254864",'#13#10'"q.'#9'c' +' #575858",'#13#10'"r.'#9'c #849CB0",'#13#10'"s.'#9'c #5882A4",'#13#10'"t.'#9 +'c #81A1BA",'#13#10'"u.'#9'c #82A2BB",'#13#10'"v.'#9'c #8BA8C0",'#13#10'"w.' +#9'c #447399",'#13#10'"x.'#9'c #407097",'#13#10'"y.'#9'c #84939F",'#13#10'"z' +'.'#9'c #919191",'#13#10'"A.'#9'c #8795A1",'#13#10'"B.'#9'c #6088A9",'#13#10 +'"C.'#9'c #7C9DB8",'#13#10'"D.'#9'c #326590",'#13#10'"E.'#9'c #87A5BD",'#13 +#10'"F.'#9'c #366992",'#13#10'"G.'#9'c #8CA9C0",'#13#10'"H.'#9'c #7396B2",' +#13#10'"I.'#9'c #7F8385",'#13#10'"J.'#9'c #C2C2C2",'#13#10'"K.'#9'c #83888D"' +','#13#10'"L.'#9'c #5781A4",'#13#10'"M.'#9'c #5F87A8",'#13#10'"N.'#9'c #84A3' +'BC",'#13#10'"O.'#9'c #376A93",'#13#10'"P.'#9'c #90ACC3",'#13#10'"Q.'#9'c #4' +'6749A",'#13#10'"R.'#9'c #6A8FAE",'#13#10'"S.'#9'c #8D9FAE",'#13#10'"T.'#9'c' +' #888888",'#13#10'"U.'#9'c #7C9AB3",'#13#10'"V.'#9'c #5E87A7",'#13#10'"W.'#9 +'c #356891",'#13#10'"X.'#9'c #9CB5C9",'#13#10'"Y.'#9'c #D9E2E9",'#13#10'"Z.' ,#9'c #7F8386",'#13#10'"`.'#9'c #A4A4A4",'#13#10'" +'#9'c #959595",'#13#10'".' +'+'#9'c #82929F",'#13#10'"++'#9'c #A0B7CA",'#13#10'"@+'#9'c #99A8B3",'#13#10 +'"#+'#9'c #B4C4D2",'#13#10'"$+'#9'c #98B1C6",'#13#10'"%+'#9'c #396B94",'#13 +#10'"&+'#9'c #81A0BA",'#13#10'"*+'#9'c #BDC5CC",'#13#10'"=+'#9'c #666667",' +#13#10'"-+'#9'c #818183",'#13#10'";+'#9'c #808080",'#13#10'">+'#9'c #BABABA"' +','#13#10'",+'#9'c #C9C9C9",'#13#10'"''+'#9'c #86888A",'#13#10'")+'#9'c #779' +'9B4",'#13#10'"!+'#9'c #7094B1",'#13#10'"~+'#9'c #838C92",'#13#10'"{+'#9'c #' +'5E5E5E",'#13#10'"]+'#9'c #97A4AF",'#13#10'"^+'#9'c #A5BCCE",'#13#10'"/+'#9 +'c #7195B2",'#13#10'"(+'#9'c #32658F",'#13#10'"_+'#9'c #92ADC4",'#13#10'":+' +#9'c #8AA7BF",'#13#10'"<+'#9'c #8EA6BA",'#13#10'"[+'#9'c #C0CCD5",'#13#10'"}' +'+'#9'c #828385",'#13#10'"|+'#9'c #AEAEAE",'#13#10'"1+'#9'c #FEFEFE",'#13#10 +'"2+'#9'c #77838C",'#13#10'"3+'#9'c #91ABC0",'#13#10'"4+'#9'c #87929B",'#13 +#10'"5+'#9'c #A3A6A8",'#13#10'"6+'#9'c #A3B4C3",'#13#10'"7+'#9'c #98ADBF",' +#13#10'"8+'#9'c #3E6F96",'#13#10'"9+'#9'c #B4C0CB",'#13#10'"0+'#9'c #89949C"' +','#13#10'"a+'#9'c #828A90",'#13#10'"b+'#9'c #7D7F80",'#13#10'"c+'#9'c #8E8E' +'8E",'#13#10'"d+'#9'c #F6F6F6",'#13#10'"e+'#9'c #EAEAEA",'#13#10'"f+'#9'c #7' +'07172",'#13#10'"g+'#9'c #696969",'#13#10'"h+'#9'c #828282",'#13#10'"i+'#9'c' +' #7C8286",'#13#10'"j+'#9'c #797E82",'#13#10'"k+'#9'c #808081",'#13#10'"l+'#9 +'c #7997AF",'#13#10'"m+'#9'c #47769B",'#13#10'"n+'#9'c #899198",'#13#10'"o+' +#9'c #858585",'#13#10'"p+'#9'c #B1B1B1",'#13#10'"q+'#9'c #FAFAFA",'#13#10'"r' +'+'#9'c #E6E6E6",'#13#10'"s+'#9'c #F9F9F9",'#13#10'"t+'#9'c #C3C3C3",'#13#10 +'"u+'#9'c #8F8F8F",'#13#10'"v+'#9'c #7A98B0",'#13#10'"w+'#9'c #5580A2",'#13 +#10'"x+'#9'c #84898D",'#13#10'"y+'#9'c #D0D0D0",'#13#10'"z+'#9'c #9F9FA0",' +#13#10'"A+'#9'c #809BB1",'#13#10'"B+'#9'c #658BAA",'#13#10'"C+'#9'c #7D7F81"' +','#13#10'"D+'#9'c #DDDDDD",'#13#10'"E+'#9'c #ACACAC",'#13#10'"F+'#9'c #89A0' +'B2",'#13#10'"G+'#9'c #F1F1F1",'#13#10'"H+'#9'c #88939C",'#13#10'"I+'#9'c #7' +'E8C97",'#13#10'"J+'#9'c #A5A5A5",'#13#10'" . . . . + + + + + + + + + + + @' +' # $ + + + + + ",'#13#10'"+ + % . & + + + + + + + + + + @ # * # $ + + + + "' +','#13#10'"+ + = . - + + + + + + + + + $ ; > , '' ) $ + + + ",'#13#10'"+ ! ~' +' { ] ^ + + / ( _ _ : < # [ } | 1 2 # + + + ",'#13#10'"3 4 . 5 6 7 8 9 0 a b' +' c d e ; f g + h i j $ + + ",'#13#10'"k l . m n o p q r s t u v # w x y z A' +' B C # + + ",'#13#10'"D E F G H I J K H H H L M N O P Q R S T U j V + ",'#13 +#10'"W . X Y Y Z ` Y Y Y Y ...+.@.#.$.%.&.*.=.-.# $ ",'#13#10'";.. >.Y ,.''' +'.).H Y Y Y # !.~.{.].^./.(._.:.<.[.# ",'#13#10'". . }.|.|.1.2.3.4.Y Y # # 5' +'.# # # # # # # # # # ",'#13#10'"6.Y Y Y 7.8.9.0.a.b.Y Y c.d.e.f.# g.# h.+ +' +' + + ",'#13#10'"s H Y Y i.j.Y 7.k.l.Y H m.n.4.o.p.# q.( + + + + ",'#13#10'"' +'r.Y Y Y s.t.Y H u.7.Y Y I v.w.o.x.y.z.+ + + + + ",'#13#10'"A.b.Y Y B.C.H D.' +'E.i.Y Y F.G.6.o.H.I.J.+ + + + + ",'#13#10'"K.L.Y Y M.N.H O.P.Q.Y Y Y R.e.1.' +'S.T./ + + + + + ",'#13#10'"6 U.H Y w.v.l.V.9.Y Y Y Y W.X.Y.Z.`.3 + + + + + ' +'",'#13#10'" +.+b.Y H ++@+#+$+%+Y Y Y H &+*+=+-+;+>++ + + + ",'#13#10'",+''+' +')+H !+~+{+]+^+/+(+Y Y %+_+:+<+[+}+|++ + + + ",'#13#10'"1+7 2+3+4+5+6+Z 7+j.' +'Y Y Y 8+9+0+a+b+c+d++ + + + ",'#13#10'"+ e+c+f+g+h+i+j+k+l+Y Y Y m+n+o+p+$ ' +'1++ + + + + ",'#13#10'"+ + q+r+s+: t+J.u+v+Y Y Y w+x+y++ + + + + + + + ",' +#13#10'"+ + + + + + + ^ z+A+Y Y Y B+C+D++ + + + + + + + ",'#13#10'"+ + + + +' +' + + + E+F+Y Y H t 0 G++ + + + + + + + ",'#13#10'"+ + + + + + + + J.H+s.).B' +'.I+J++ + + + + + + + + "};'#13#10 ]); LazarusResources.Add('TZGroupedConnection','XPM',[ '/* XPM */'#13#10'static char * TZGroupedConnection.xpm_xpm[] = {'#13#10'"24 ' +'24 101 2",'#13#10'" '#9'c #23236E",'#13#10'". '#9'c #000058",'#13#10'"+ '#9 +'c None",'#13#10'"@ '#9'c #000000",'#13#10'"# '#9'c #080808",'#13#10'"$ '#9 +'c #2F2F2F",'#13#10'"% '#9'c #A5A5A5",'#13#10'"& '#9'c #C8C8DA",'#13#10'"* ' +#9'c #2F2F76",'#13#10'"= '#9'c #ADADAD",'#13#10'"- '#9'c #616197",'#13#10'";' +' '#9'c #8D8DB4",'#13#10'"> '#9'c #FDFDFD",'#13#10'", '#9'c #E9E9E9",'#13#10 +'"'' '#9'c #797979",'#13#10'") '#9'c #414141",'#13#10'"! '#9'c #F4F4F7",'#13 +#10'"~ '#9'c #111163",'#13#10'"{ '#9'c #07075C",'#13#10'"] '#9'c #E2E2EC",' +#13#10'"^ '#9'c #F6F6F6",'#13#10'"/ '#9'c #171717",'#13#10'"( '#9'c #ACACC8"' +','#13#10'"_ '#9'c #424283",'#13#10'": '#9'c #070707",'#13#10'"< '#9'c #4B4B' +'89",'#13#10'"[ '#9'c #A3A3C2",'#13#10'"} '#9'c #010101",'#13#10'"| '#9'c #E' +'8E8EF",'#13#10'"1 '#9'c #0A0A5E",'#13#10'"2 '#9'c #0D0D60",'#13#10'"3 '#9'c' +' #EFEFF4",'#13#10'"4 '#9'c #F8FAF8",'#13#10'"5 '#9'c #95CA95",'#13#10'"6 '#9 +'c #5FAF5F",'#13#10'"7 '#9'c #2F972F",'#13#10'"8 '#9'c #0B850B",'#13#10'"9 ' +#9'c #9797BA",'#13#10'"0 '#9'c #575790",'#13#10'"a '#9'c #44A144",'#13#10'"b' +' '#9'c #007F00",'#13#10'"c '#9'c #090909",'#13#10'"d '#9'c #38387C",'#13#10 +'"e '#9'c #C7C7DA",'#13#10'"f '#9'c #017701",'#13#10'"g '#9'c #018901",'#13 +#10'"h '#9'c #212121",'#13#10'"i '#9'c #DFDFDF",'#13#10'"j '#9'c #030359",' +#13#10'"k '#9'c #06065B",'#13#10'"l '#9'c #005C00",'#13#10'"m '#9'c #007200"' +','#13#10'"n '#9'c #007B00",'#13#10'"o '#9'c #007E00",'#13#10'"p '#9'c #0080' +'00",'#13#10'"q '#9'c #008600",'#13#10'"r '#9'c #009000",'#13#10'"s '#9'c #0' +'0AA00",'#13#10'"t '#9'c #565656",'#13#10'"u '#9'c #969696",'#13#10'"v '#9'c' +' #005A00",'#13#10'"w '#9'c #006400",'#13#10'"x '#9'c #006F00",'#13#10'"y '#9 +'c #007900",'#13#10'"z '#9'c #008300",'#13#10'"A '#9'c #008E00",'#13#10'"B ' +#9'c #009800",'#13#10'"C '#9'c #00A200",'#13#10'"D '#9'c #00AD00",'#13#10'"E' +' '#9'c #CCCCCC",'#13#10'"F '#9'c #060606",'#13#10'"G '#9'c #0B0B0B",'#13#10 +'"H '#9'c #9D9D9D",'#13#10'"I '#9'c #EDEDED",'#13#10'"J '#9'c #B8B8B8",'#13 +#10'"K '#9'c #1A1A1A",'#13#10'"L '#9'c #A4A4A4",'#13#10'"M '#9'c #161616",' +#13#10'"N '#9'c #B6B6B6",'#13#10'"O '#9'c #ECECEC",'#13#10'"P '#9'c #404040"' +','#13#10'"Q '#9'c #949494",'#13#10'"R '#9'c #E0E0E0",'#13#10'"S '#9'c #1466' +'14",'#13#10'"T '#9'c #14B314",'#13#10'"U '#9'c #F7F7F7",'#13#10'"V '#9'c #B' +'3CEB3",'#13#10'"W '#9'c #1D751D",'#13#10'"X '#9'c #1DAC1D",'#13#10'"Y '#9'c' +' #B3E6B3",'#13#10'"Z '#9'c #E7F0E7",'#13#10'"` '#9'c #B7D8B7",'#13#10'" .'#9 +'c #93CA93",'#13#10'"..'#9'c #B7DFB7",'#13#10'"+.'#9'c #E7F5E7",'#13#10'"@.' +#9'c #FEFEFE",'#13#10'"#.'#9'c #040404",'#13#10'"$.'#9'c #6F6F6F",'#13#10'"%' +'.'#9'c #323232",'#13#10'"&.'#9'c #A0A0A0",'#13#10'"*.'#9'c #2D2D2D",'#13#10 +'" . . . . + + + + + + + + + + + @ # $ % + + + + ",'#13#10'"+ + & . * + + +' +' + + + + + + + + @ @ @ @ = + + + ",'#13#10'"+ + - . ; + + + + + + + + + + +' +' > , '' @ ) + + + ",'#13#10'"+ ! ~ { ] + + + + + + + + + + + + + ^ @ / + + ' +'+ ",'#13#10'"+ ( . _ + + + + + + + + + + + + + + + @ : + + + ",'#13#10'"+ <' +' . [ + + + + + + + + + + + + + + + @ } + + + ",'#13#10'"| 1 2 3 + 4 5 6 7 8' +' 7 6 5 4 + + + + + } @ + + + ",'#13#10'"9 . 0 + + a b b b b b b b a + + + +' +' + c @ ^ + + ",'#13#10'"d . e + + f b b b b b b b g + + + + + h @ i + + ",' +#13#10'". . j k k l m n o b p q r s + + + + + t @ u + + ",'#13#10'"+ + + + +' +' v w x y z A B C D + + + + + E F G H I ",'#13#10'"+ + + + + v w x y z A B C' +' D + + + + + + J K @ @ ",'#13#10'"+ + + + + v w x y z A B C D + + + + + + L' +' M @ @ ",'#13#10'"+ + + + + v w x y z A B C D + + + + + N } G H O ",'#13#10 +'"+ + + + + v w x y z A B C D + + + + + P @ Q + + ",'#13#10'"+ + + + + v w x' +' y z A B C D + + + + + : @ R + + ",'#13#10'"+ + + + + S w x y z A B C T + +' +' + + + @ @ U + + ",'#13#10'"+ + + + + V W x y z A B X Y + + + + + @ @ + + +' +' ",'#13#10'"+ + + + + + + Z ` ...+.+ + + + + + + @ @ + + + ",'#13#10'"+ + ' +'+ + + + + + + + + + + + + + + + @.@ @ + + + ",'#13#10'"+ + + + + + + + + + ' +'+ + + + + + + + , @ #.+ + + ",'#13#10'"+ + + + + + + + + + + + + + + + @., ' +'$.@ %.+ + + ",'#13#10'"+ + + + + + + + + + + + + + + + @ @ @ @ &.+ + + ",' +#13#10'"+ + + + + + + + + + + + + + + + @ : *.H + + + + "};'#13#10 ]); LazarusResources.Add('TZQuery','XPM',[ '/* XPM */'#13#10'static char * TZQuery.xpm_xpm[] = {'#13#10'"24 24 156 2",' +#13#10'" '#9'c #23236E",'#13#10'". '#9'c #000058",'#13#10'"+ '#9'c None",' +#13#10'"@ '#9'c #C8C8DA",'#13#10'"# '#9'c #2F2F76",'#13#10'"$ '#9'c #22167D"' +','#13#10'"% '#9'c #342690",'#13#10'"& '#9'c #6149C1",'#13#10'"* '#9'c #634C' +'C4",'#13#10'"= '#9'c #6551C6",'#13#10'"- '#9'c #6755C8",'#13#10'"; '#9'c #6' +'A59CA",'#13#10'"> '#9'c #6C5ECC",'#13#10'", '#9'c #6E62CF",'#13#10'"'' '#9 +'c #7166D1",'#13#10'") '#9'c #736AD4",'#13#10'"! '#9'c #756ED6",'#13#10'"~ ' +#9'c #7872D8",'#13#10'"{ '#9'c #7976DB",'#13#10'"] '#9'c #7C7ADE",'#13#10'"^' +' '#9'c #7E7FE0",'#13#10'"/ '#9'c #8183E2",'#13#10'"( '#9'c #8288E4",'#13#10 +'"_ '#9'c #858BE6",'#13#10'": '#9'c #8790E9",'#13#10'"< '#9'c #8A94EB",'#13 +#10'"[ '#9'c #F4F4F7",'#13#10'"} '#9'c #06045E",'#13#10'"| '#9'c #02015A",' +#13#10'"1 '#9'c #533DB2",'#13#10'"2 '#9'c #634DC3",'#13#10'"3 '#9'c #6651C5"' +','#13#10'"4 '#9'c #6755C7",'#13#10'"5 '#9'c #6A59CB",'#13#10'"6 '#9'c #6C5D' +'CD",'#13#10'"7 '#9'c #6F62CF",'#13#10'"8 '#9'c #7165D2",'#13#10'"9 '#9'c #7' +'36AD3",'#13#10'"0 '#9'c #7A77DB",'#13#10'"a '#9'c #7C7BDD",'#13#10'"b '#9'c' +' #7E7FDF",'#13#10'"c '#9'c #8387E4",'#13#10'"d '#9'c #858CE7",'#13#10'"e '#9 +'c #878FE9",'#13#10'"f '#9'c #8994EC",'#13#10'"g '#9'c #ACACC8",'#13#10'"h ' +#9'c #171071",'#13#10'"i '#9'c #5E45BE",'#13#10'"j '#9'c #6049C0",'#13#10'"k' +' '#9'c #634DC4",'#13#10'"l '#9'c #6551C5",'#13#10'"m '#9'c #6A5ACA",'#13#10 +'"n '#9'c #6C5DCC",'#13#10'"o '#9'c #7165D1",'#13#10'"p '#9'c #7773D8",'#13 +#10'"q '#9'c #7F7FDF",'#13#10'"r '#9'c #8083E2",'#13#10'"s '#9'c #8388E4",' +#13#10'"t '#9'c #858BE7",'#13#10'"u '#9'c #8994EB",'#13#10'"v '#9'c #4B4B89"' +','#13#10'"w '#9'c #A3A3C2",'#13#10'"x '#9'c #B3B3B3",'#13#10'"y '#9'c #E8E8' +'EF",'#13#10'"z '#9'c #0A0A5E",'#13#10'"A '#9'c #09095C",'#13#10'"B '#9'c #E' +'FEFF4",'#13#10'"C '#9'c #FEFEFE",'#13#10'"D '#9'c #FDFDFD",'#13#10'"E '#9'c' +' #9797BA",'#13#10'"F '#9'c #3D3D77",'#13#10'"G '#9'c #B4B4B4",'#13#10'"H '#9 +'c #38387C",'#13#10'"I '#9'c #8B8B9F",'#13#10'"J '#9'c #020259",'#13#10'"K ' +#9'c #06065B",'#13#10'"L '#9'c #9494B8",'#13#10'"M '#9'c #181864",'#13#10'"N' +' '#9'c #1A1A69",'#13#10'"O '#9'c #616197",'#13#10'"P '#9'c #E7E7EF",'#13#10 +'"Q '#9'c #D7D7E4",'#13#10'"R '#9'c #4E4E8B",'#13#10'"S '#9'c #101060",'#13 +#10'"T '#9'c #101062",'#13#10'"U '#9'c #3F3F81",'#13#10'"V '#9'c #C1C1D6",' +#13#10'"W '#9'c #272771",'#13#10'"X '#9'c #C9C9DB",'#13#10'"Y '#9'c #3A3A75"' +','#13#10'"Z '#9'c #6F6F90",'#13#10'"` '#9'c #323271",'#13#10'" .'#9'c #2A2A' +'6D",'#13#10'"..'#9'c #9D9DA8",'#13#10'"+.'#9'c #07075B",'#13#10'"@.'#9'c #5' +'B5B86",'#13#10'"#.'#9'c #62628A",'#13#10'"$.'#9'c #131361",'#13#10'"%.'#9'c' +' #88889D",'#13#10'"&.'#9'c #1B1B65",'#13#10'"*.'#9'c #C0C0D5",'#13#10'"=.'#9 +'c #4F4F80",'#13#10'"-.'#9'c #E3E3EC",'#13#10'";.'#9'c #ECECF2",'#13#10'">.' +#9'c #9898BB",'#13#10'",.'#9'c #A5A5C4",'#13#10'"''.'#9'c #68689C",'#13#10'"' +').'#9'c #A9A9C6",'#13#10'"!.'#9'c #D1D1E0",'#13#10'"~.'#9'c #404081",'#13#10 +'"{.'#9'c #424283",'#13#10'"].'#9'c #34347A",'#13#10'"^.'#9'c #8686AF",'#13 +#10'"/.'#9'c #F8F8FA",'#13#10'"(.'#9'c #3A3A7D",'#13#10'"_.'#9'c #F0F0F5",' +#13#10'":.'#9'c #171767",'#13#10'"<.'#9'c #131364",'#13#10'"[.'#9'c #FCFCFD"' +','#13#10'"}.'#9'c #85859B",'#13#10'"|.'#9'c #4B4B7E",'#13#10'"1.'#9'c #1515' +'62",'#13#10'"2.'#9'c #3E3E77",'#13#10'"3.'#9'c #28286C",'#13#10'"4.'#9'c #A' +'7A7AD",'#13#10'"5.'#9'c #B2B2B3",'#13#10'"6.'#9'c #0F0F5F",'#13#10'"7.'#9'c' +' #0E0E5F",'#13#10'"8.'#9'c #F7F7F9",'#13#10'"9.'#9'c #0F0F61",'#13#10'"0.'#9 +'c #69699C",'#13#10'"a.'#9'c #ADADC9",'#13#10'"b.'#9'c #EEEEF3",'#13#10'"c.' +#9'c #B6B6CF",'#13#10'"d.'#9'c #B7B7CF",'#13#10'"e.'#9'c #39397D",'#13#10'"f' +'.'#9'c #9292B7",'#13#10'"g.'#9'c #5F5F96",'#13#10'"h.'#9'c #434383",'#13#10 +'"i.'#9'c #E1E1EB",'#13#10'"j.'#9'c #0B0B5F",'#13#10'"k.'#9'c #121263",'#13 +#10'"l.'#9'c #8080AB",'#13#10'"m.'#9'c #24246F",'#13#10'"n.'#9'c #010158",' +#13#10'"o.'#9'c #D3D3E2",'#13#10'"p.'#9'c #191968",'#13#10'"q.'#9'c #ABABC7"' +','#13#10'"r.'#9'c #BCBCD3",'#13#10'"s.'#9'c #252570",'#13#10'"t.'#9'c #5C5C' +'94",'#13#10'"u.'#9'c #E5E5ED",'#13#10'"v.'#9'c #D6D6E4",'#13#10'"w.'#9'c #1' +'81867",'#13#10'"x.'#9'c #333379",'#13#10'"y.'#9'c #9C9CBE",'#13#10'" . . .' +' . + + + + + + + + + + + + + + + + + + + ",'#13#10'"+ + @ . # + + + + + + +' +' + + + + + + + + + + + + ",'#13#10'"+ + $ . % & * = - ; > , '' ) ! ~ { ] ^ ' +'/ ( _ : < ",'#13#10'"+ [ } | 1 & 2 3 4 5 6 7 8 9 ! ~ 0 a b / c d e f ",'#13 +#10'"+ g . h i j k l - m n , o 9 ! p 0 a q r s t : u ",'#13#10'"+ v . w + + ' +'+ + + + + x + + + + + + + + + + + x ",'#13#10'"y z A B + + + + + + + x C C ' +'C D + + + + + + + x ",'#13#10'"E . F x x x x x x x x x G G G x x x x x x x ' +'x x ",'#13#10'"H . I + + + + + + + + x + + + C + + + + + + + x ",'#13#10'".' +' . J K K + + + + + + x C C C D + + + + + + + x ",'#13#10'"+ + x x x x x x x' +' x x x G G G x x x x x x x x x ",'#13#10'"+ + x + + + + + + + + x + + + + +' ,' + + + + + + x ",'#13#10'"+ + x C C C C C C C + x C C C C C C C C C C C x "' +','#13#10'"+ + x G G G G G G G G x G G G G G G G G G G G x ",'#13#10'"+ + x ' +'+ + + + + + + + x + + + + + + + + + + + x ",'#13#10'"+ L M K N O P + + Q R ' +'S T U V + + . W C C C C x ",'#13#10'"X . Y Z ` . .x ..+.A @.#.$.. %.G . &.' +'G G G G x ",'#13#10'"*.. =.-.;.>.,.+ ''.. ).x + !.. ~.+ . W + + + + x ",'#13 +#10'"D {.. . ].^./.+ (.. _.x + + :.<.+ . W C C C C x ",'#13#10'"+ [.}.|.1.. ' +'2.x 3.. 4.x x 5.6.7.x . &.x x x x x ",'#13#10'">.H P + 8.z 9.+ 0.. a.b.0.c.' +'. v + . W + + + + + ",'#13#10'"d.. e.f.g.. h.+ i.j.k.l.m.. n.o.+ . p.q.q.q.' +'r.+ ",'#13#10'"+ >.s.K p.t.u.+ + v.v w.<.h.z {.+ . . . . . x.+ ",'#13#10'"+' +' + + + + + + + + + + + + + y y.+ + + + + + + + "};'#13#10 ]); LazarusResources.Add('TZUpdateSql','XPM',[ '/* XPM */'#13#10'static char * TZUpdateSql.xpm_xpm[] = {'#13#10'"24 24 192 2' +'",'#13#10'" '#9'c #23236E",'#13#10'". '#9'c #000058",'#13#10'"+ '#9'c None' +'",'#13#10'"@ '#9'c #F2C9C9",'#13#10'"# '#9'c #FDF3F3",'#13#10'"$ '#9'c #C8C' +'8DA",'#13#10'"% '#9'c #2F2F76",'#13#10'"& '#9'c #FFFEFE",'#13#10'"* '#9'c #' +'FEFDFD",'#13#10'"= '#9'c #FEFCFC",'#13#10'"- '#9'c #E68A8A",'#13#10'"; '#9 +'c #C80C0C",'#13#10'"> '#9'c #F7D8D8",'#13#10'", '#9'c #22167D",'#13#10'"'' ' +#9'c #342690",'#13#10'") '#9'c #6149C1",'#13#10'"! '#9'c #634CC4",'#13#10'"~' +' '#9'c #6551C6",'#13#10'"{ '#9'c #6755C8",'#13#10'"] '#9'c #6A59CA",'#13#10 +'"^ '#9'c #6C5ECC",'#13#10'"/ '#9'c #6E62CF",'#13#10'"( '#9'c #7166D1",'#13 +#10'"_ '#9'c #7467CF",'#13#10'": '#9'c #8F4A91",'#13#10'"< '#9'c #BE0B15",' +#13#10'"[ '#9'c #C70000",'#13#10'"} '#9'c #9D5E98",'#13#10'"| '#9'c #8A94EB"' +','#13#10'"1 '#9'c #F4F4F7",'#13#10'"2 '#9'c #06045E",'#13#10'"3 '#9'c #0201' +'5A",'#13#10'"4 '#9'c #533DB2",'#13#10'"5 '#9'c #634DC3",'#13#10'"6 '#9'c #6' +'651C5",'#13#10'"7 '#9'c #6755C7",'#13#10'"8 '#9'c #6A59CB",'#13#10'"9 '#9'c' +' #6C5DCD",'#13#10'"0 '#9'c #6F62CF",'#13#10'"a '#9'c #775DC2",'#13#10'"b '#9 +'c #C1070E",'#13#10'"c '#9'c #927CC6",'#13#10'"d '#9'c #ACACC8",'#13#10'"e ' +#9'c #171071",'#13#10'"f '#9'c #5E45BE",'#13#10'"g '#9'c #6049C0",'#13#10'"h' +' '#9'c #634DC4",'#13#10'"i '#9'c #6551C5",'#13#10'"j '#9'c #6A5ACA",'#13#10 +'"k '#9'c #6C5DCC",'#13#10'"l '#9'c #B01A36",'#13#10'"m '#9'c #9965A4",'#13 +#10'"n '#9'c #8994EB",'#13#10'"o '#9'c #4B4B89",'#13#10'"p '#9'c #A3A3C2",' +#13#10'"q '#9'c #B3B3B3",'#13#10'"r '#9'c #C90A0A",'#13#10'"s '#9'c #CD1D1D"' +','#13#10'"t '#9'c #ECADAD",'#13#10'"u '#9'c #F9F5F4",'#13#10'"v '#9'c #F2C5' +'C5",'#13#10'"w '#9'c #C60404",'#13#10'"x '#9'c #F3D0D0",'#13#10'"y '#9'c #F' +'2FBF2",'#13#10'"z '#9'c #E8E8EF",'#13#10'"A '#9'c #0A0A5E",'#13#10'"B '#9'c' +' #09095C",'#13#10'"C '#9'c #EFEFF4",'#13#10'"D '#9'c #DF6F6F",'#13#10'"E '#9 +'c #FEFBFB",'#13#10'"F '#9'c #E4F7E4",'#13#10'"G '#9'c #53CB53",'#13#10'"H ' +#9'c #FAECEC",'#13#10'"I '#9'c #FAE5E5",'#13#10'"J '#9'c #D8F3D8",'#13#10'"K' +' '#9'c #0CB60C",'#13#10'"L '#9'c #B2B2B2",'#13#10'"M '#9'c #9797BA",'#13#10 +'"N '#9'c #3D3D77",'#13#10'"O '#9'c #B4B4B4",'#13#10'"P '#9'c #9BB39B",'#13 +#10'"Q '#9'c #04B304",'#13#10'"R '#9'c #0BB30B",'#13#10'"S '#9'c #86B386",' +#13#10'"T '#9'c #88B388",'#13#10'"U '#9'c #84B284",'#13#10'"V '#9'c #7AB37A"' +','#13#10'"W '#9'c #21B321",'#13#10'"X '#9'c #00B300",'#13#10'"Y '#9'c #B2B3' +'B2",'#13#10'"Z '#9'c #38387C",'#13#10'"` '#9'c #8B8B9F",'#13#10'" .'#9'c #D' +'3F2D3",'#13#10'"..'#9'c #02B202",'#13#10'"+.'#9'c #64D064",'#13#10'"@.'#9'c' +' #020259",'#13#10'"#.'#9'c #06065B",'#13#10'"$.'#9'c #A0E2A0",'#13#10'"%.'#9 +'c #6BD16B",'#13#10'"&.'#9'c #FDFFFD",'#13#10'"*.'#9'c #89B389",'#13#10'"=.' +#9'c #01B201",'#13#10'"-.'#9'c #57B357",'#13#10'";.'#9'c #6AB26A",'#13#10'">' +'.'#9'c #6EB36E",'#13#10'",.'#9'c #77B277",'#13#10'"''.'#9'c #A9B2A9",'#13#10 +'").'#9'c #E5F7E5",'#13#10'"!.'#9'c #16B916",'#13#10'"~.'#9'c #FEFEFE",'#13 +#10'"{.'#9'c #F8FCF8",'#13#10'"].'#9'c #9494B8",'#13#10'"^.'#9'c #181864",' +#13#10'"/.'#9'c #1A1A69",'#13#10'"(.'#9'c #616197",'#13#10'"_.'#9'c #E7E7EF"' +','#13#10'":.'#9'c #D7D7E4",'#13#10'"<.'#9'c #4E4E8B",'#13#10'"[.'#9'c #1010' +'60",'#13#10'"}.'#9'c #101062",'#13#10'"|.'#9'c #3F3F81",'#13#10'"1.'#9'c #C' +'1C1D6",'#13#10'"2.'#9'c #272771",'#13#10'"3.'#9'c #C9C9DB",'#13#10'"4.'#9'c' +' #3A3A75",'#13#10'"5.'#9'c #6F6F90",'#13#10'"6.'#9'c #323271",'#13#10'"7.'#9 +'c #2A2A6D",'#13#10'"8.'#9'c #9D9DA8",'#13#10'"9.'#9'c #07075B",'#13#10'"0.' +#9'c #5B5B86",'#13#10'"a.'#9'c #62628A",'#13#10'"b.'#9'c #131361",'#13#10'"c' +'.'#9'c #88889D",'#13#10'"d.'#9'c #1B1B65",'#13#10'"e.'#9'c #C0C0D5",'#13#10 +'"f.'#9'c #4F4F80",'#13#10'"g.'#9'c #E3E3EC",'#13#10'"h.'#9'c #ECECF2",'#13 +#10'"i.'#9'c #9898BB",'#13#10'"j.'#9'c #A5A5C4",'#13#10'"k.'#9'c #68689C",' +#13#10'"l.'#9'c #A9A9C6",'#13#10'"m.'#9'c #D1D1E0",'#13#10'"n.'#9'c #404081"' +','#13#10'"o.'#9'c #FDFDFD",'#13#10'"p.'#9'c #424283",'#13#10'"q.'#9'c #3434' +'7A",'#13#10'"r.'#9'c #8686AF",'#13#10'"s.'#9'c #F8F8FA",'#13#10'"t.'#9'c #3' +'A3A7D",'#13#10'"u.'#9'c #F0F0F5",'#13#10'"v.'#9'c #171767",'#13#10'"w.'#9'c' +' #131364",'#13#10'"x.'#9'c #FCFCFD",'#13#10'"y.'#9'c #85859B",'#13#10'"z.'#9 +'c #4B4B7E",'#13#10'"A.'#9'c #151562",'#13#10'"B.'#9'c #3E3E77",'#13#10'"C.' +#9'c #28286C",'#13#10'"D.'#9'c #A7A7AD",'#13#10'"E.'#9'c #B2B2B3",'#13#10'"F' +'.'#9'c #0F0F5F",'#13#10'"G.'#9'c #0E0E5F",'#13#10'"H.'#9'c #F7F7F9",'#13#10 +'"I.'#9'c #0F0F61",'#13#10'"J.'#9'c #69699C",'#13#10'"K.'#9'c #ADADC9",'#13 +#10'"L.'#9'c #EEEEF3",'#13#10'"M.'#9'c #B6B6CF",'#13#10'"N.'#9'c #B7B7CF",' +#13#10'"O.'#9'c #39397D",'#13#10'"P.'#9'c #9292B7",'#13#10'"Q.'#9'c #5F5F96"' +','#13#10'"R.'#9'c #434383",'#13#10'"S.'#9'c #E1E1EB",'#13#10'"T.'#9'c #0B0B' +'5F",'#13#10'"U.'#9'c #121263",'#13#10'"V.'#9'c #8080AB",'#13#10'"W.'#9'c #2' +'4246F",'#13#10'"X.'#9'c #010158",'#13#10'"Y.'#9'c #D3D3E2",'#13#10'"Z.'#9'c' ,' #191968",'#13#10'"`.'#9'c #ABABC7",'#13#10'" +'#9'c #BCBCD3",'#13#10'".+'#9 +'c #252570",'#13#10'"++'#9'c #5C5C94",'#13#10'"@+'#9'c #E5E5ED",'#13#10'"#+' +#9'c #D6D6E4",'#13#10'"$+'#9'c #181867",'#13#10'"%+'#9'c #333379",'#13#10'"&' +'+'#9'c #9C9CBE",'#13#10'" . . . . + + + + + + + + + + + + + + @ # + + + ",' +#13#10'"+ + $ . % + + + + + + + + + + + & * = - ; > + + ",'#13#10'"+ + , . ' +''' ) ! ~ { ] ^ / ( _ : < [ [ [ [ [ [ } | ",'#13#10'"+ 1 2 3 4 ) 5 6 7 8 9 0' +' a b [ [ [ [ [ [ [ [ [ c ",'#13#10'"+ d . e f g h i { j k / l [ [ [ [ [ [ [' +' [ [ m n ",'#13#10'"+ o . p + + + + + + + q r s t u * & + v w x y q ",'#13 +#10'"z A B C + + + + + + + q D E F G + + + H I J K L ",'#13#10'"M . N q q q ' +'q q q q q q O P Q R S T U V W X X Y ",'#13#10'"Z . ` + + + + + + + + q ...' +'X X X X X X X X +.q ",'#13#10'". . @.#.#.+ + + + + + q $.X X X X X X X X %.' +'&.q ",'#13#10'"+ + q q q q q q q q q q O *.=.X -.;.>.,.''.q q q ",'#13#10'"' +'+ + q + + + + + + + + q + + ).!.+ + + + + + + q ",'#13#10'"+ + q ~.~.~.~.~.' +'~.~.+ q ~.~.~.{.~.~.~.~.~.~.~.q ",'#13#10'"+ + q O O O O O O O O q O O O O ' +'O O O O O O O q ",'#13#10'"+ + q + + + + + + + + q + + + + + + + + + + + q ' +'",'#13#10'"+ ].^.#./.(._.+ + :.<.[.}.|.1.+ + . 2.~.~.~.~.q ",'#13#10'"3.. 4' +'.5.6.. 7.q 8.9.B 0.a.b.. c.O . d.O O O O q ",'#13#10'"e.. f.g.h.i.j.+ k.. l' +'.q + m.. n.+ . 2.+ + + + q ",'#13#10'"o.p.. . q.r.s.+ t.. u.q + + v.w.+ . 2' +'.~.~.~.~.q ",'#13#10'"+ x.y.z.A.. B.q C.. D.q q E.F.G.q . d.q q q q q ",'#13 +#10'"i.Z _.+ H.A I.+ J.. K.L.J.M.. o + . 2.+ + + + + ",'#13#10'"N.. O.P.Q.. ' +'R.+ S.T.U.V.W.. X.Y.+ . Z.`.`.`. ++ ",'#13#10'"+ i..+#.Z.++@++ + #+o $+w.R.' +'A p.+ . . . . . %++ ",'#13#10'"+ + + + + + + + + + + + + + z &++ + + + + + ' +'+ + "};'#13#10 ]); LazarusResources.Add('TZSqlProcessor','XPM',[ '/* XPM */'#13#10'static char * TZSqlProcessor.xpm_xpm[] = {'#13#10'"24 24 19' +'6 2",'#13#10'" '#9'c #23236E",'#13#10'". '#9'c #000058",'#13#10'"+ '#9'c N' +'one",'#13#10'"@ '#9'c #F8FAF8",'#13#10'"# '#9'c #95CA95",'#13#10'"$ '#9'c #' +'5FAF5F",'#13#10'"% '#9'c #2F972F",'#13#10'"& '#9'c #0B850B",'#13#10'"* '#9 +'c #C8C8DA",'#13#10'"= '#9'c #191960",'#13#10'"- '#9'c #888A85",'#13#10'"; ' +#9'c #248123",'#13#10'"> '#9'c #007F00",'#13#10'", '#9'c #44A144",'#13#10'"' +''' '#9'c #616197",'#13#10'") '#9'c #8D8DB4",'#13#10'"! '#9'c #017701",'#13 +#10'"~ '#9'c #018901",'#13#10'"{ '#9'c #F4F4F7",'#13#10'"] '#9'c #111163",' +#13#10'"^ '#9'c #030359",'#13#10'"/ '#9'c #E2E2EC",'#13#10'"( '#9'c #DEDEDE"' +','#13#10'"_ '#9'c #E1E1E1",'#13#10'": '#9'c #E0E0E0",'#13#10'"< '#9'c #E2E2' +'E2",'#13#10'"[ '#9'c #E3E3E3",'#13#10'"} '#9'c #E4E4E4",'#13#10'"| '#9'c #0' +'05C00",'#13#10'"1 '#9'c #007200",'#13#10'"2 '#9'c #007B00",'#13#10'"3 '#9'c' +' #007E00",'#13#10'"4 '#9'c #008000",'#13#10'"5 '#9'c #008600",'#13#10'"6 '#9 +'c #009000",'#13#10'"7 '#9'c #00AA00",'#13#10'"8 '#9'c #ACACC8",'#13#10'"9 ' +#9'c #232363",'#13#10'"0 '#9'c #DFDFDF",'#13#10'"a '#9'c #B6B6B6",'#13#10'"b' +' '#9'c #B7B7B7",'#13#10'"c '#9'c #005A00",'#13#10'"d '#9'c #006400",'#13#10 +'"e '#9'c #006F00",'#13#10'"f '#9'c #007900",'#13#10'"g '#9'c #008300",'#13 +#10'"h '#9'c #008E00",'#13#10'"i '#9'c #009800",'#13#10'"j '#9'c #00A200",' +#13#10'"k '#9'c #00AD00",'#13#10'"l '#9'c #4B4B89",'#13#10'"m '#9'c #565874"' +','#13#10'"n '#9'c #E6E6E6",'#13#10'"o '#9'c #CE5C00",'#13#10'"p '#9'c #D276' +'2C",'#13#10'"q '#9'c #E7E7E7",'#13#10'"r '#9'c #E8E8EF",'#13#10'"s '#9'c #0' +'A0A5E",'#13#10'"t '#9'c #0D0D60",'#13#10'"u '#9'c #7F8182",'#13#10'"v '#9'c' +' #F5D400",'#13#10'"w '#9'c #FCAF3E",'#13#10'"x '#9'c #C47D44",'#13#10'"y '#9 +'c #9797BA",'#13#10'"z '#9'c #575790",'#13#10'"A '#9'c #E5E5E5",'#13#10'"B ' +#9'c #CE5E03",'#13#10'"C '#9'c #F57900",'#13#10'"D '#9'c #D68543",'#13#10'"E' +' '#9'c #38387C",'#13#10'"F '#9'c #C7C7DA",'#13#10'"G '#9'c #ADAFAC",'#13#10 +'"H '#9'c #CB6411",'#13#10'"I '#9'c #CA6A1C",'#13#10'"J '#9'c #B7B5B3",'#13 +#10'"K '#9'c #06065B",'#13#10'"L '#9'c #F47A03",'#13#10'"M '#9'c #DAA172",' +#13#10'"N '#9'c #E8E8E8",'#13#10'"O '#9'c #F37B06",'#13#10'"P '#9'c #C98147"' +','#13#10'"Q '#9'c #C2C2C2",'#13#10'"R '#9'c #0F620F",'#13#10'"S '#9'c #14B3' +'14",'#13#10'"T '#9'c #DCDCDC",'#13#10'"U '#9'c #D78D50",'#13#10'"V '#9'c #E' +'AEAEA",'#13#10'"W '#9'c #A4BFA4",'#13#10'"X '#9'c #1A731A",'#13#10'"Y '#9'c' +' #1DAC1D",'#13#10'"Z '#9'c #B3E6B3",'#13#10'"` '#9'c #FDFDFD",'#13#10'" .'#9 +'c #D06815",'#13#10'"..'#9'c #000000",'#13#10'"+.'#9'c #8A7B62",'#13#10'"@.' +#9'c #DB9F6E",'#13#10'"#.'#9'c #ECECEC",'#13#10'"$.'#9'c #EEEEEE",'#13#10'"%' +'.'#9'c #EBEBEB",'#13#10'"&.'#9'c #D5DFD5",'#13#10'"*.'#9'c #AACCAA",'#13#10 +'"=.'#9'c #92C992",'#13#10'"-.'#9'c #618B5F",'#13#10'";.'#9'c #E7F5E7",'#13 +#10'">.'#9'c #343434",'#13#10'",.'#9'c #B6B6B5",'#13#10'"''.'#9'c #FCFCFC",' +#13#10'").'#9'c #EDEDED",'#13#10'"!.'#9'c #F4F4F4",'#13#10'"~.'#9'c #878984"' +','#13#10'"{.'#9'c #9494B8",'#13#10'"].'#9'c #1A1A69",'#13#10'"^.'#9'c #5858' +'8E",'#13#10'"/.'#9'c #D3D3DC",'#13#10'"(.'#9'c #9999A6",'#13#10'"_.'#9'c #3' +'73774",'#13#10'":.'#9'c #111160",'#13#10'"<.'#9'c #0B0B5D",'#13#10'"[.'#9'c' +' #2C2C6E",'#13#10'"}.'#9'c #89899E",'#13#10'"|.'#9'c #1B1B66",'#13#10'"1.'#9 +'c #C9C9DB",'#13#10'"2.'#9'c #54548F",'#13#10'"3.'#9'c #545674",'#13#10'"4.' +#9'c #484887",'#13#10'"5.'#9'c #37377A",'#13#10'"6.'#9'c #CFCFD9",'#13#10'"7' +'.'#9'c #7777A2",'#13#10'"8.'#9'c #8484AC",'#13#10'"9.'#9'c #1A1A68",'#13#10 +'"0.'#9'c #B6B6CB",'#13#10'"a.'#9'c #24246F",'#13#10'"b.'#9'c #848681",'#13 +#10'"c.'#9'c #C0C0D5",'#13#10'"d.'#9'c #7171A2",'#13#10'"e.'#9'c #797A80",' +#13#10'"f.'#9'c #ECECF2",'#13#10'"g.'#9'c #8A8AAD",'#13#10'"h.'#9'c #9898B7"' +','#13#10'"i.'#9'c #606094",'#13#10'"j.'#9'c #9D9DBA",'#13#10'"k.'#9'c #C2C2' +'D2",'#13#10'"l.'#9'c #3B3B7D",'#13#10'"m.'#9'c #24246E",'#13#10'"n.'#9'c #4' +'24283",'#13#10'"o.'#9'c #34347A",'#13#10'"p.'#9'c #7979A3",'#13#10'"q.'#9'c' +' #E4E4E6",'#13#10'"r.'#9'c #353579",'#13#10'"s.'#9'c #E1E1E7",'#13#10'"t.'#9 +'c #F0F0F0",'#13#10'"u.'#9'c #151565",'#13#10'"v.'#9'c #FCFCFD",'#13#10'"w.' +#9'c #BEBED4",'#13#10'"x.'#9'c #39396A",'#13#10'"y.'#9'c #1E1E6B",'#13#10'"z' +'.'#9'c #595992",'#13#10'"A.'#9'c #3A3A7D",'#13#10'"B.'#9'c #EFEFF4",'#13#10 +'"C.'#9'c #161666",'#13#10'"D.'#9'c #272771",'#13#10'"E.'#9'c #9898BB",'#13 +#10'"F.'#9'c #E7E7EF",'#13#10'"G.'#9'c #B0B1AE",'#13#10'"H.'#9'c #838583",' +#13#10'"I.'#9'c #050559",'#13#10'"J.'#9'c #08085A",'#13#10'"K.'#9'c #38386A"' +','#13#10'"L.'#9'c #5C5D76",'#13#10'"M.'#9'c #7E8082",'#13#10'"N.'#9'c #6162' +'78",'#13#10'"O.'#9'c #282865",'#13#10'"P.'#9'c #14155E",'#13#10'"Q.'#9'c #B' +'1B1B0",'#13#10'"R.'#9'c #B7B7CF",'#13#10'"S.'#9'c #39397D",'#13#10'"T.'#9'c' +' #9292B7",'#13#10'"U.'#9'c #5F5F96",'#13#10'"V.'#9'c #434383",'#13#10'"W.'#9 +'c #E1E1EB",'#13#10'"X.'#9'c #0B0B5F",'#13#10'"Y.'#9'c #121263",'#13#10'"Z.' ,#9'c #8080AB",'#13#10'"`.'#9'c #010158",'#13#10'" +'#9'c #D3D3E2",'#13#10'".' +'+'#9'c #191968",'#13#10'"++'#9'c #ABABC7",'#13#10'"@+'#9'c #BCBCD3",'#13#10 +'"#+'#9'c #252570",'#13#10'"$+'#9'c #5C5C94",'#13#10'"%+'#9'c #E5E5ED",'#13 +#10'"&+'#9'c #D6D6E4",'#13#10'"*+'#9'c #181867",'#13#10'"=+'#9'c #131364",' +#13#10'"-+'#9'c #333379",'#13#10'";+'#9'c #9C9CBE",'#13#10'" . . . . + + + ' +'+ + + + + + + @ # $ % & % $ # @ ",'#13#10'"+ + * . = - - - - - - - - - - ; ' +'> > > > > > > , ",'#13#10'"+ + '' . ) + + + + + + + + + + ! > > > > > > > ~' +' ",'#13#10'"+ { ] ^ / ( _ : _ < < [ } } } | 1 2 3 > 4 5 6 7 ",'#13#10'"+ 8 ' +'. 9 + 0 < _ a a b b b b b c d e f g h i j k ",'#13#10'"+ l . m + : [ < < n ' +'n o p q q c d e f g h i j k ",'#13#10'"r s t u + _ } } a a o v w x a c d e ' +'f g h i j k ",'#13#10'"y . z - + < n A A B v w C D A c d e f g h i j k ",' +#13#10'"E . F - + G n 0 H v w C I J a c d e f g h i j k ",'#13#10'". . ^ ^ K' +' } + o v w L M N N N c d e f g h i j k ",'#13#10'"+ + + - + n o v w O P Q Q' +' Q Q R d e f g h i j S ",'#13#10'"+ + + - + T o w L U V V V V V W X e f g h' +' i Y Z ",'#13#10'"+ + + - ` ...+.@.#.$.%.#.$.%.#.%.&.*.=.-.;.+ + ",'#13#10 +'"+ + + - + >.o V ,.,.,.,.,.,.,.,.,.,.,.''.- + + + ",'#13#10'"+ + + - + q + ' +'%.V V ).V V V V V V V V !.~.+ + + ",'#13#10'"+ {. ^ ].^./.%.,.(._.:.<.[.}.' +',.,.. |.+ ~.+ + + ",'#13#10'"1.. 2.3.4.. 5.%.6.s t 7.8.9.. 0.%.. a.+ b.+ + ' +'+ ",'#13#10'"c.. d.e.f.g.h.%.i.. j.#.).k.. l.#.. m.+ ~.+ + + ",'#13#10'"` n' +'.. . o.p.q.%.r.. s.).$.t.u.] ).. a.+ - + + + ",'#13#10'"+ v.w.x.y.. z.+ A..' +' B.+ + + C.u.+ . D.+ - + + + ",'#13#10'"E.E F.G.H.I.J.- K.. L.M.K.N.. O.- .' +' P.- Q.+ + + ",'#13#10'"R.. S.T.U.. V.+ W.X.Y.Z.a.. `. ++ . .+++++++@++ ",' +#13#10'"+ E.#+K .+$+%++ + &+l *+=+V.s n.+ . . . . . -++ ",'#13#10'"+ + + + +' +' + + + + + + + + + r ;++ + + + + + + + "};'#13#10 ]); LazarusResources.Add('TZTable','XPM',[ '/* XPM */'#13#10'static char * TZTable.xpm_xpm[] = {'#13#10'"24 24 77 2",'#13 +#10'" '#9'c #23236E",'#13#10'". '#9'c #000058",'#13#10'"+ '#9'c None",'#13 +#10'"@ '#9'c #C8C8DA",'#13#10'"# '#9'c #2F2F76",'#13#10'"$ '#9'c #22167D",' +#13#10'"% '#9'c #342690",'#13#10'"& '#9'c #6149C1",'#13#10'"* '#9'c #634CC4"' +','#13#10'"= '#9'c #6551C6",'#13#10'"- '#9'c #6755C8",'#13#10'"; '#9'c #6A59' +'CA",'#13#10'"> '#9'c #6C5ECC",'#13#10'", '#9'c #6E62CF",'#13#10'"'' '#9'c #' +'7166D1",'#13#10'") '#9'c #736AD4",'#13#10'"! '#9'c #756ED6",'#13#10'"~ '#9 +'c #7872D8",'#13#10'"{ '#9'c #7976DB",'#13#10'"] '#9'c #7C7ADE",'#13#10'"^ ' +#9'c #7E7FE0",'#13#10'"/ '#9'c #8183E2",'#13#10'"( '#9'c #8288E4",'#13#10'"_' +' '#9'c #858BE6",'#13#10'": '#9'c #8790E9",'#13#10'"< '#9'c #8A94EB",'#13#10 +'"[ '#9'c #F4F4F7",'#13#10'"} '#9'c #06045E",'#13#10'"| '#9'c #02015A",'#13 +#10'"1 '#9'c #533DB2",'#13#10'"2 '#9'c #634DC3",'#13#10'"3 '#9'c #6651C5",' +#13#10'"4 '#9'c #6755C7",'#13#10'"5 '#9'c #6A59CB",'#13#10'"6 '#9'c #6C5DCD"' +','#13#10'"7 '#9'c #6F62CF",'#13#10'"8 '#9'c #7165D2",'#13#10'"9 '#9'c #736A' +'D3",'#13#10'"0 '#9'c #7A77DB",'#13#10'"a '#9'c #7C7BDD",'#13#10'"b '#9'c #7' +'E7FDF",'#13#10'"c '#9'c #8387E4",'#13#10'"d '#9'c #858CE7",'#13#10'"e '#9'c' +' #878FE9",'#13#10'"f '#9'c #8994EC",'#13#10'"g '#9'c #ACACC8",'#13#10'"h '#9 +'c #171071",'#13#10'"i '#9'c #5E45BE",'#13#10'"j '#9'c #6049C0",'#13#10'"k ' +#9'c #634DC4",'#13#10'"l '#9'c #6551C5",'#13#10'"m '#9'c #6A5ACA",'#13#10'"n' +' '#9'c #6C5DCC",'#13#10'"o '#9'c #7165D1",'#13#10'"p '#9'c #7773D8",'#13#10 +'"q '#9'c #7F7FDF",'#13#10'"r '#9'c #8083E2",'#13#10'"s '#9'c #8388E4",'#13 +#10'"t '#9'c #858BE7",'#13#10'"u '#9'c #8994EB",'#13#10'"v '#9'c #4B4B89",' +#13#10'"w '#9'c #A3A3C2",'#13#10'"x '#9'c #B3B3B3",'#13#10'"y '#9'c #E8E8EF"' +','#13#10'"z '#9'c #0A0A5E",'#13#10'"A '#9'c #09095C",'#13#10'"B '#9'c #EFEF' +'F4",'#13#10'"C '#9'c #FEFEFE",'#13#10'"D '#9'c #FDFDFD",'#13#10'"E '#9'c #9' +'797BA",'#13#10'"F '#9'c #3D3D77",'#13#10'"G '#9'c #B4B4B4",'#13#10'"H '#9'c' +' #38387C",'#13#10'"I '#9'c #8B8B9F",'#13#10'"J '#9'c #020259",'#13#10'"K '#9 +'c #06065B",'#13#10'"L '#9'c #B2B2B3",'#13#10'" . . . . + + + + + + + + + +' +' + + + + + + + + + ",'#13#10'"+ + @ . # + + + + + + + + + + + + + + + + + +' +' + ",'#13#10'"+ + $ . % & * = - ; > , '' ) ! ~ { ] ^ / ( _ : < ",'#13#10'"+' +' [ } | 1 & 2 3 4 5 6 7 8 9 ! ~ 0 a b / c d e f ",'#13#10'"+ g . h i j k l -' +' m n , o 9 ! p 0 a q r s t : u ",'#13#10'"+ v . w + + + + + + + x + + + + +' +' + + + + + + x ",'#13#10'"y z A B + + + + + + + x C C C D + + + + + + + x "' +','#13#10'"E . F x x x x x x x x x G G G x x x x x x x x x ",'#13#10'"H . I ' +'+ + + + + + + + x + + + C + + + + + + + x ",'#13#10'". . J K K + + + + + + ' +'x C C C D + + + + + + + x ",'#13#10'"+ + x x x x x x x x x x G G G x x x x ' +'x x x x x ",'#13#10'"+ + x + + + + + + + + x + + + + + + + + + + + x ",'#13 +#10'"+ + x C C C C C C C + x C C C C C C C C C C C x ",'#13#10'"+ + x G G G ' +'G G G G G x G G G G G G G G G G G x ",'#13#10'"+ + x + + + + + + + + x + + ' +'+ + + + + + + + + x ",'#13#10'"+ + x + + + + + + + + x + + + + + + + C C C ' +'C x ",'#13#10'"+ + x x x x x x x x x x x x x G G x x G G G G x ",'#13#10'"+' +' + x + + + + + + + + x + + + + + + + + + + + x ",'#13#10'"+ + x + + + + + +' +' + + x + + + + + + + C C C C x ",'#13#10'"+ + x x x x x x x x x x x L x x x' +' x x x x x x x ",'#13#10'"+ + + + + + + + + + + + + + + + + + + + + + + + "' +','#13#10'"+ + + + + + + + + + + + + + + + + + + + + + + + ",'#13#10'"+ + + ' +'+ + + + + + + + + + + + + + + + + + + + + ",'#13#10'"+ + + + + + + + + + + ' +'+ + + + + + + + + + + + + "};'#13#10 ]); LazarusResources.Add('TZStoredProc','XPM',[ '/* XPM */'#13#10'static char * TZStoredProc.xpm_xpm[] = {'#13#10'"24 24 169 ' +'2",'#13#10'" '#9'c #23236E",'#13#10'". '#9'c #000058",'#13#10'"+ '#9'c Non' +'e",'#13#10'"@ '#9'c #457ABE",'#13#10'"# '#9'c #C8C8DA",'#13#10'"$ '#9'c #28' +'2B6F",'#13#10'"% '#9'c #ACD5AC",'#13#10'"& '#9'c #89C489",'#13#10'"* '#9'c ' +'#65B265",'#13#10'"= '#9'c #42A042",'#13#10'"- '#9'c #229022",'#13#10'"; '#9 +'c #349934",'#13#10'"> '#9'c #58AB58",'#13#10'", '#9'c #64997A",'#13#10'"'' ' +#9'c #B8C3CE",'#13#10'") '#9'c #BCCDE3",'#13#10'"! '#9'c #BAC4D0",'#13#10'"~' +' '#9'c #595D90",'#13#10'"{ '#9'c #004627",'#13#10'"] '#9'c #007F00",'#13#10 +'"^ '#9'c #86A7D2",'#13#10'"/ '#9'c #6490C7",'#13#10'"( '#9'c #9DB8DA",'#13 +#10'"_ '#9'c #F4F4F7",'#13#10'": '#9'c #060B58",'#13#10'"< '#9'c #000355",' +#13#10'"[ '#9'c #00700A",'#13#10'"} '#9'c #ACACC8",'#13#10'"| '#9'c #001F41"' +','#13#10'"1 '#9'c #137029",'#13#10'"2 '#9'c #7CA1CF",'#13#10'"3 '#9'c #427B' +'B1",'#13#10'"4 '#9'c #5686C3",'#13#10'"5 '#9'c #4D7FBC",'#13#10'"6 '#9'c #8' +'2A5D1",'#13#10'"7 '#9'c #4B4B89",'#13#10'"8 '#9'c #003B1F",'#13#10'"9 '#9'c' +' #006A00",'#13#10'"0 '#9'c #007300",'#13#10'"a '#9'c #007900",'#13#10'"b '#9 +'c #007D00",'#13#10'"c '#9'c #008000",'#13#10'"d '#9'c #008100",'#13#10'"e ' +#9'c #427CB1",'#13#10'"f '#9'c #2D836A",'#13#10'"g '#9'c #B9C3CF",'#13#10'"h' +' '#9'c #8DA2BC",'#13#10'"i '#9'c #5584BE",'#13#10'"j '#9'c #E8E8EF",'#13#10 +'"k '#9'c #0A0A5E",'#13#10'"l '#9'c #040758",'#13#10'"m '#9'c #005705",'#13 +#10'"n '#9'c #006400",'#13#10'"o '#9'c #006B00",'#13#10'"p '#9'c #007200",' +#13#10'"q '#9'c #008700",'#13#10'"r '#9'c #008E00",'#13#10'"s '#9'c #139529"' +','#13#10'"t '#9'c #9797BA",'#13#10'"u '#9'c #20325A",'#13#10'"v '#9'c #005D' +'00",'#13#10'"w '#9'c #4980B7",'#13#10'"x '#9'c #458C93",'#13#10'"y '#9'c #7' +'192BB",'#13#10'"z '#9'c #38387C",'#13#10'"A '#9'c #4A735D",'#13#10'"B '#9'c' +' #009500",'#13#10'"C '#9'c #138329",'#13#10'"D '#9'c #8FAED5",'#13#10'"E '#9 +'c #010158",'#13#10'"F '#9'c #000255",'#13#10'"G '#9'c #5F945F",'#13#10'"H ' +#9'c #009C00",'#13#10'"I '#9'c #139129",'#13#10'"J '#9'c #00A300",'#13#10'"K' +' '#9'c #00AA00",'#13#10'"L '#9'c #00B100",'#13#10'"M '#9'c #00B800",'#13#10 +'"N '#9'c #9494B8",'#13#10'"O '#9'c #0D1458",'#13#10'"P '#9'c #000A4F",'#13 +#10'"Q '#9'c #002836",'#13#10'"R '#9'c #006708",'#13#10'"S '#9'c #00710D",' +#13#10'"T '#9'c #002B3D",'#13#10'"U '#9'c #000E4F",'#13#10'"V '#9'c #000952"' +','#13#10'"W '#9'c #002842",'#13#10'"X '#9'c #008015",'#13#10'"Y '#9'c #2727' +'71",'#13#10'"Z '#9'c #C9C9DB",'#13#10'"` '#9'c #1F305A",'#13#10'" .'#9'c #0' +'03921",'#13#10'"..'#9'c #001C3F",'#13#10'"+.'#9'c #001B42",'#13#10'"@.'#9'c' +' #000554",'#13#10'"#.'#9'c #000753",'#13#10'"$.'#9'c #004B2B",'#13#10'"%.'#9 +'c #005627",'#13#10'"&.'#9'c #00114E",'#13#10'"*.'#9'c #008615",'#13#10'"=.' +#9'c #C0C0D5",'#13#10'"-.'#9'c #2A415B",'#13#10'";.'#9'c #005209",'#13#10'">' +'.'#9'c #005C06",'#13#10'",.'#9'c #003F23",'#13#10'"''.'#9'c #00491F",'#13#10 +'").'#9'c #003434",'#13#10'"!.'#9'c #005E1D",'#13#10'"~.'#9'c #00850F",'#13 +#10'"{.'#9'c #002C41",'#13#10'"].'#9'c #FDFDFD",'#13#10'"^.'#9'c #424283",' +#13#10'"/.'#9'c #001446",'#13#10'"(.'#9'c #003829",'#13#10'"_.'#9'c #006E02"' +','#13#10'":.'#9'c #001D43",'#13#10'"<.'#9'c #008505",'#13#10'"[.'#9'c #000F' +'50",'#13#10'"}.'#9'c #000D51",'#13#10'"|.'#9'c #FCFCFD",'#13#10'"1.'#9'c #4' +'66E5D",'#13#10'"2.'#9'c #002733",'#13#10'"3.'#9'c #000B4D",'#13#10'"4.'#9'c' +' #002739",'#13#10'"5.'#9'c #000E50",'#13#10'"6.'#9'c #9898BB",'#13#10'"7.'#9 +'c #608D68",'#13#10'"8.'#9'c #006002",'#13#10'"9.'#9'c #000454",'#13#10'"0.' +#9'c #000652",'#13#10'"a.'#9'c #003433",'#13#10'"b.'#9'c #00601C",'#13#10'"c' +'.'#9'c #008B05",'#13#10'"d.'#9'c #004033",'#13#10'"e.'#9'c #007419",'#13#10 +'"f.'#9'c #00343E",'#13#10'"g.'#9'c #0ABA0A",'#13#10'"h.'#9'c #B7B7CF",'#13 +#10'"i.'#9'c #313475",'#13#10'"j.'#9'c #18443D",'#13#10'"k.'#9'c #002537",' +#13#10'"l.'#9'c #001D40",'#13#10'"m.'#9'c #000A51",'#13#10'"n.'#9'c #004A2B"' +','#13#10'"o.'#9'c #00164B",'#13#10'"p.'#9'c #000057",'#13#10'"q.'#9'c #0994' +'19",'#13#10'"r.'#9'c #9CE39C",'#13#10'"s.'#9'c #191968",'#13#10'"t.'#9'c #A' +'BABC7",'#13#10'"u.'#9'c #BCBCD3",'#13#10'"v.'#9'c #252570",'#13#10'"w.'#9'c' +' #05055B",'#13#10'"x.'#9'c #111460",'#13#10'"y.'#9'c #2F4267",'#13#10'"z.'#9 +'c #579660",'#13#10'"A.'#9'c #3D993D",'#13#10'"B.'#9'c #1A8C1A",'#13#10'"C.' +#9'c #00710E",'#13#10'"D.'#9'c #032B41",'#13#10'"E.'#9'c #040F54",'#13#10'"F' +'.'#9'c #060E57",'#13#10'"G.'#9'c #1F3560",'#13#10'"H.'#9'c #06085A",'#13#10 +'"I.'#9'c #3D407E",'#13#10'"J.'#9'c #333379",'#13#10'"K.'#9'c #F9FCF9",'#13 +#10'"L.'#9'c #9C9CBE",'#13#10'" . . . . + + + + + + + + + + + @ @ @ + + + +' +' + ",'#13#10'"+ + # . $ % & * = - ; > , @ @ '' @ ) @ ! @ @ + + ",'#13#10'"+' +' + ~ . { ] ] ] ] ] ] ] @ ) ^ @ / ( / @ ^ ) @ + ",'#13#10'"+ _ : < [ ] ] ] ]' +' ] ] ] @ ^ ( ( ( ( ( ( ( ^ @ + ",'#13#10'"+ } . | ] ] ] ] ] ] ] ] 1 @ ( 2 3' +' 4 5 6 ( @ ! + ",'#13#10'"+ 7 . 8 9 0 a b ] c d @ @ / ( e f g h i ( / @ @ "' ,','#13#10'"j k l m n o p a c q r @ ) ( ( 4 s + g 4 ( ( ) @ ",'#13#10'"t . u ' +'v n o p a c q r @ @ / ( w x g y 5 ( / @ @ ",'#13#10'"z . A v n o p a c q r ' +'B C @ ) 2 w 4 5 D ( @ ! + ",'#13#10'". . E F F o p a c q r B @ ^ ( ( ( ( ( ' +'( ( ^ @ + ",'#13#10'"+ + G v n o p a c q r B @ ) ^ @ / ( / @ ^ ) @ + ",'#13 +#10'"+ + G v n o p a c q r B H @ @ I @ ) @ ! @ @ + + ",'#13#10'"+ + G v n o ' +'p a c q r B H J K L @ @ @ + + + + + ",'#13#10'"+ + G v n o p a c q r B H J ' +'K L M + + + + + + + ",'#13#10'"+ + G v n o p a c q r B H J K L M + + + + + ' +'+ + ",'#13#10'"+ N O F P Q R a c S T U V W X L M . Y + + + + + ",'#13#10'"Z' +' . ` .... +.a [ @.#.$.%.&.. *.M . Y + + + + + ",'#13#10'"=.. -.;.>.,.''.a ' +').. !.B H ~.. {.M . Y + + + + + ",'#13#10'"].^.. . /.(._.a :.. <.B H J [.}.' +'M . Y + + + + + ",'#13#10'"+ |.1.2.3.. 4.a :.. <.B H J 5.5.M . Y + + + + + ' +'",'#13#10'"6.z 7.v 8.9.0.a a.. b.c.d.e.. f.g.. Y + + + + + ",'#13#10'"h.. i' +'.j.k.. l.a [ @.m.n.o.. p.q.r.. s.t.t.t.u.+ ",'#13#10'"+ 6.v.w.x.y.z.A.B.C.D' +'.E.F.G.H.I.+ . . . . . J.+ ",'#13#10'"+ + + + + + + + + K.+ + + + j L.+ + +' +' + + + + + "};'#13#10 ]); LazarusResources.Add('TZSqlMonitor','XPM',[ '/* XPM */'#13#10'static char * TZSqlMonitor.xpm_xpm[] = {'#13#10'"24 24 230 ' +'2",'#13#10'" '#9'c #23236E",'#13#10'". '#9'c #000058",'#13#10'"+ '#9'c Non' +'e",'#13#10'"@ '#9'c #C8C8DA",'#13#10'"# '#9'c #2F2F76",'#13#10'"$ '#9'c #DA' +'EBDA",'#13#10'"% '#9'c #ACD5AC",'#13#10'"& '#9'c #89C489",'#13#10'"* '#9'c ' +'#65B265",'#13#10'"= '#9'c #42A042",'#13#10'"- '#9'c #229022",'#13#10'"; '#9 +'c #349934",'#13#10'"> '#9'c #58AB58",'#13#10'", '#9'c #698968",'#13#10'"'' ' +#9'c #4C544B",'#13#10'") '#9'c #3E3F3E",'#13#10'"! '#9'c #414141",'#13#10'"~' +' '#9'c #404040",'#13#10'"{ '#9'c #3D3E3F",'#13#10'"] '#9'c #43443C",'#13#10 +'"^ '#9'c #A8A9A7",'#13#10'"/ '#9'c #616197",'#13#10'"( '#9'c #2B5C53",'#13 +#10'"_ '#9'c #007F00",'#13#10'": '#9'c #374A35",'#13#10'"< '#9'c #A3A4A1",' +#13#10'"[ '#9'c #E1DCE1",'#13#10'"} '#9'c #D8D2DB",'#13#10'"| '#9'c #D8D2DA"' +','#13#10'"1 '#9'c #D9D3DC",'#13#10'"2 '#9'c #D7D2D9",'#13#10'"3 '#9'c #9695' +'92",'#13#10'"4 '#9'c #595B57",'#13#10'"5 '#9'c #F4F4F7",'#13#10'"6 '#9'c #1' +'11163",'#13#10'"7 '#9'c #020458",'#13#10'"8 '#9'c #00700A",'#13#10'"9 '#9'c' +' #84B454",'#13#10'"0 '#9'c #699A39",'#13#10'"a '#9'c #72A145",'#13#10'"b '#9 +'c #71A143",'#13#10'"c '#9'c #72A144",'#13#10'"d '#9'c #699A38",'#13#10'"e ' +#9'c #85B556",'#13#10'"f '#9'c #C3C4BF",'#13#10'"g '#9'c #ACACC8",'#13#10'"h' +' '#9'c #162557",'#13#10'"i '#9'c #007800",'#13#10'"j '#9'c #3F403F",'#13#10 +'"k '#9'c #679B36",'#13#10'"l '#9'c #70A241",'#13#10'"m '#9'c #6FA140",'#13 +#10'"n '#9'c #679E35",'#13#10'"o '#9'c #699A3A",'#13#10'"p '#9'c #BABBB6",' +#13#10'"q '#9'c #4B4B89",'#13#10'"r '#9'c #3C5E5C",'#13#10'"s '#9'c #005D00"' +','#13#10'"t '#9'c #006A00",'#13#10'"u '#9'c #007300",'#13#10'"v '#9'c #0079' +'00",'#13#10'"w '#9'c #007D00",'#13#10'"x '#9'c #008000",'#13#10'"y '#9'c #0' +'08100",'#13#10'"z '#9'c #008500",'#13#10'"A '#9'c #DBD4DD",'#13#10'"B '#9'c' +' #73A145",'#13#10'"C '#9'c #77A74B",'#13#10'"D '#9'c #76A649",'#13#10'"E '#9 +'c #77A64A",'#13#10'"F '#9'c #70A240",'#13#10'"G '#9'c #BBBDB8",'#13#10'"H ' +#9'c #E8E8EF",'#13#10'"I '#9'c #0A0A5E",'#13#10'"J '#9'c #0D0D60",'#13#10'"K' +' '#9'c #598A5E",'#13#10'"L '#9'c #006400",'#13#10'"M '#9'c #006B00",'#13#10 +'"N '#9'c #007200",'#13#10'"O '#9'c #008700",'#13#10'"P '#9'c #008E00",'#13 +#10'"Q '#9'c #009500",'#13#10'"R '#9'c #404140",'#13#10'"S '#9'c #D4CDD7",' +#13#10'"T '#9'c #78A54B",'#13#10'"U '#9'c #79AA4B",'#13#10'"V '#9'c #81AF56"' +','#13#10'"W '#9'c #7FAE53",'#13#10'"X '#9'c #7FAF54",'#13#10'"Y '#9'c #7AAC' +'4C",'#13#10'"Z '#9'c #78A54C",'#13#10'"` '#9'c #B6B7B3",'#13#10'" .'#9'c #9' +'797BA",'#13#10'"..'#9'c #575790",'#13#10'"+.'#9'c #5F945F",'#13#10'"@.'#9'c' +' #D1CCD2",'#13#10'"#.'#9'c #538B1D",'#13#10'"$.'#9'c #457F0D",'#13#10'"%.'#9 +'c #4F8619",'#13#10'"&.'#9'c #4C8517",'#13#10'"*.'#9'c #4D8618",'#13#10'"=.' +#9'c #44800C",'#13#10'"-.'#9'c #538A1D",'#13#10'";.'#9'c #B7B8B3",'#13#10'">' +'.'#9'c #38387C",'#13#10'",.'#9'c #C7C7DA",'#13#10'"''.'#9'c #3D3E3C",'#13#10 +'").'#9'c #CBC9CA",'#13#10'"!.'#9'c #DAECC8",'#13#10'"~.'#9'c #BCCDAD",'#13 +#10'"{.'#9'c #C4D4B5",'#13#10'"].'#9'c #C3D2B3",'#13#10'"^.'#9'c #C4D2B3",' +#13#10'"/.'#9'c #BFCFAE",'#13#10'"(.'#9'c #D9EBC7",'#13#10'"_.'#9'c #B7B9B4"' +','#13#10'":.'#9'c #030359",'#13#10'"<.'#9'c #020358",'#13#10'"[.'#9'c #0002' +'55",'#13#10'"}.'#9'c #424440",'#13#10'"|.'#9'c #959693",'#13#10'"1.'#9'c #F' +'FF7FF",'#13#10'"2.'#9'c #FFF9FF",'#13#10'"3.'#9'c #FFFAFF",'#13#10'"4.'#9'c' +' #91938F",'#13#10'"5.'#9'c #118311",'#13#10'"6.'#9'c #3F6A3E",'#13#10'"7.'#9 +'c #898B86",'#13#10'"8.'#9'c #7E817B",'#13#10'"9.'#9'c #80827C",'#13#10'"0.' +#9'c #898B87",'#13#10'"a.'#9'c #727370",'#13#10'"b.'#9'c #CBCCCB",'#13#10'"c' +'.'#9'c #009C00",'#13#10'"d.'#9'c #00A300",'#13#10'"e.'#9'c #00AA00",'#13#10 +'"f.'#9'c #00B100",'#13#10'"g.'#9'c #00B800",'#13#10'"h.'#9'c #9494B8",'#13 +#10'"i.'#9'c #00094F",'#13#10'"j.'#9'c #002636",'#13#10'"k.'#9'c #006008",' +#13#10'"l.'#9'c #006B0D",'#13#10'"m.'#9'c #00293D",'#13#10'"n.'#9'c #000D4F"' +','#13#10'"o.'#9'c #000952",'#13#10'"p.'#9'c #002642",'#13#10'"q.'#9'c #007B' +'15",'#13#10'"r.'#9'c #272771",'#13#10'"s.'#9'c #C9C9DB",'#13#10'"t.'#9'c #5' +'4548F",'#13#10'"u.'#9'c #3B5C5C",'#13#10'"v.'#9'c #001A3F",'#13#10'"w.'#9'c' +' #001942",'#13#10'"x.'#9'c #006A0A",'#13#10'"y.'#9'c #000554",'#13#10'"z.'#9 +'c #000753",'#13#10'"A.'#9'c #00482B",'#13#10'"B.'#9'c #005227",'#13#10'"C.' +#9'c #00114E",'#13#10'"D.'#9'c #008115",'#13#10'"E.'#9'c #C0C0D5",'#13#10'"F' +'.'#9'c #7171A2",'#13#10'"G.'#9'c #54835E",'#13#10'"H.'#9'c #005606",'#13#10 +'"I.'#9'c #003B23",'#13#10'"J.'#9'c #00451F",'#13#10'"K.'#9'c #003134",'#13 +#10'"L.'#9'c #00591D",'#13#10'"M.'#9'c #007F0F",'#13#10'"N.'#9'c #002A41",' +#13#10'"O.'#9'c #FDFDFD",'#13#10'"P.'#9'c #424283",'#13#10'"Q.'#9'c #001246"' +','#13#10'"R.'#9'c #003429",'#13#10'"S.'#9'c #006802",'#13#10'"T.'#9'c #001B' +'43",'#13#10'"U.'#9'c #007F05",'#13#10'"V.'#9'c #000E50",'#13#10'"W.'#9'c #0' +'00C51",'#13#10'"X.'#9'c #FCFCFD",'#13#10'"Y.'#9'c #BEBED4",'#13#10'"Z.'#9'c' ,' #273E5A",'#13#10'"`.'#9'c #000A4D",'#13#10'" +'#9'c #002539",'#13#10'".+'#9 +'c #007E05",'#13#10'"++'#9'c #9898BB",'#13#10'"@+'#9'c #E7E7EF",'#13#10'"#+' +#9'c #6A9C6A",'#13#10'"$+'#9'c #005A02",'#13#10'"%+'#9'c #000354",'#13#10'"&' +'+'#9'c #000652",'#13#10'"*+'#9'c #003133",'#13#10'"=+'#9'c #005B1C",'#13#10 +'"-+'#9'c #008405",'#13#10'";+'#9'c #003D33",'#13#10'">+'#9'c #006F19",'#13 +#10'",+'#9'c #00323E",'#13#10'"''+'#9'c #B7B7CF",'#13#10'")+'#9'c #39397D",' +#13#10'"!+'#9'c #7F85A4",'#13#10'"~+'#9'c #0F2C46",'#13#10'"{+'#9'c #001C40"' +','#13#10'"]+'#9'c #000951",'#13#10'"^+'#9'c #00472B",'#13#10'"/+'#9'c #0015' +'4B",'#13#10'"(+'#9'c #000057",'#13#10'"_+'#9'c #008C0F",'#13#10'":+'#9'c #0' +'CB40C",'#13#10'"<+'#9'c #191968",'#13#10'"[+'#9'c #ABABC7",'#13#10'"}+'#9'c' +' #BCBCD3",'#13#10'"|+'#9'c #252570",'#13#10'"1+'#9'c #06065B",'#13#10'"2+'#9 +'c #181868",'#13#10'"3+'#9'c #404B78",'#13#10'"4+'#9'c #76A57F",'#13#10'"5+' +#9'c #61A861",'#13#10'"6+'#9'c #3D993D",'#13#10'"7+'#9'c #157523",'#13#10'"8' +'+'#9'c #00273E",'#13#10'"9+'#9'c #010D50",'#13#10'"0+'#9'c #030C55",'#13#10 +'"a+'#9'c #163156",'#13#10'"b+'#9'c #040859",'#13#10'"c+'#9'c #283969",'#13 +#10'"d+'#9'c #EDF9ED",'#13#10'"e+'#9'c #333379",'#13#10'"f+'#9'c #F9FCF9",' +#13#10'"g+'#9'c #9C9CBE",'#13#10'" . . . . + + + + + + + + + + + + + + + + ' +'+ + + ",'#13#10'"+ + @ . # $ % & * = - ; > , '' ) ! ~ ~ ~ ~ { ] ^ ",'#13#10 +'"+ + / . ( _ _ _ _ _ _ _ _ : < [ } | 1 } 2 [ 3 4 ",'#13#10'"+ 5 6 7 8 _ _ _' +' _ _ _ _ _ ) [ 9 0 a b c d e f ) ",'#13#10'"+ g . h i _ _ _ _ _ _ _ _ j } 0' +' k l m l n o p ! ",'#13#10'"+ q . r s t u v w _ x y z j A B m C D E F B G j' +' ",'#13#10'"H I J K s L M N v x O P Q R S T U V W X Y Z ` R ",'#13#10'" .. ' +'..+.s L M N v x O P Q ! @.#.$.%.&.*.=.-.;.! ",'#13#10'">.. ,.+.s L M N v x ' +'O P Q ''.).!.~.{.].^./.(._.''.",'#13#10'". . :.<.[.L M N v x O P Q }.|.+ 1.' +'2.2.2.3.+ 4.}.",'#13#10'"+ + + +.s L M N v x O P Q 5.6.7.8.8.8.8.9.0.a.b.",' +#13#10'"+ + + +.s L M N v x O P Q c.d.e.f.g.+ + + + + + ",'#13#10'"+ + + +.s' +' L M N v x O P Q c.d.e.f.g.+ + + + + + ",'#13#10'"+ + + +.s L M N v x O P Q' +' c.d.e.f.g.+ + + + + + ",'#13#10'"+ + + +.s L M N v x O P Q c.d.e.f.g.+ + +' +' + + + ",'#13#10'"+ h. <.i.j.k.N v l.m.n.o.p.q.e.f.. r.+ + + + + ",'#13#10 +'"s.. t.u.v.. w.N x.y.z.A.B.C.. D.f.. r.+ + + + + ",'#13#10'"E.. F.G.H.I.J.N' +' K.. L.P Q M.. N.f.. r.+ + + + + ",'#13#10'"O.P.. . Q.R.S.N T.. U.P Q c.V.W' +'.f.. r.+ + + + + ",'#13#10'"+ X.Y.Z.`.. +N T.. .+P Q c.V.V.f.. r.+ + + + +' +' ",'#13#10'"++>.@+#+$+%+&+N *+. =+-+;+>+. ,+f.. r.+ + + + + ",'#13#10'"''+.' +' )+!+~+. {+N x.y.]+^+/+. (+_+:+. <+[+[+[+}++ ",'#13#10'"+ ++|+1+2+3+4+5+6+7' +'+8+9+0+a+b+c+d+. . . . . e++ ",'#13#10'"+ + + + + + + + + + f++ + + H g++ +' +' + + + + + + "};'#13#10 ]); LazarusResources.Add('TZSqlMetaData','XPM',[ '/* XPM */'#13#10'static char * TZSqlMetaData.xpm_xpm[] = {'#13#10'"24 24 173' +' 2",'#13#10'" '#9'c #23236E",'#13#10'". '#9'c #000058",'#13#10'"+ '#9'c No' +'ne",'#13#10'"@ '#9'c #C8C8DA",'#13#10'"# '#9'c #282B6F",'#13#10'"$ '#9'c #A' +'CD5AC",'#13#10'"% '#9'c #89C489",'#13#10'"& '#9'c #65B265",'#13#10'"* '#9'c' +' #42A042",'#13#10'"= '#9'c #229022",'#13#10'"- '#9'c #349934",'#13#10'"; '#9 +'c #58AB58",'#13#10'"> '#9'c #7CBD7C",'#13#10'", '#9'c #A0CEA0",'#13#10'"'' ' +#9'c #C4E0C4",'#13#10'") '#9'c #FCFDFC",'#13#10'"! '#9'c #E7D99B",'#13#10'"~' +' '#9'c #CDAF2A",'#13#10'"{ '#9'c #C4A000",'#13#10'"] '#9'c #595D90",'#13#10 +'"^ '#9'c #004627",'#13#10'"/ '#9'c #007F00",'#13#10'"( '#9'c #259225",'#13 +#10'"_ '#9'c #BDC470",'#13#10'": '#9'c #FCE94F",'#13#10'"< '#9'c #F4F4F7",' +#13#10'"[ '#9'c #060B58",'#13#10'"} '#9'c #000355",'#13#10'"| '#9'c #00700A"' +','#13#10'"1 '#9'c #A79C03",'#13#10'"2 '#9'c #EDD400",'#13#10'"3 '#9'c #ACAC' +'C8",'#13#10'"4 '#9'c #001F41",'#13#10'"5 '#9'c #A40000",'#13#10'"6 '#9'c #4' +'B4B89",'#13#10'"7 '#9'c #003B1F",'#13#10'"8 '#9'c #006A00",'#13#10'"9 '#9'c' +' #007300",'#13#10'"0 '#9'c #007900",'#13#10'"a '#9'c #007D00",'#13#10'"b '#9 +'c #008000",'#13#10'"c '#9'c #008100",'#13#10'"d '#9'c #008500",'#13#10'"e ' +#9'c #EF2929",'#13#10'"f '#9'c #204A87",'#13#10'"g '#9'c #A3A230",'#13#10'"h' +' '#9'c #E8E8EF",'#13#10'"i '#9'c #0A0A5E",'#13#10'"j '#9'c #040758",'#13#10 +'"k '#9'c #005705",'#13#10'"l '#9'c #006400",'#13#10'"m '#9'c #006B00",'#13 +#10'"n '#9'c #007200",'#13#10'"o '#9'c #008700",'#13#10'"p '#9'c #008E00",' +#13#10'"q '#9'c #009500",'#13#10'"r '#9'c #CC0000",'#13#10'"s '#9'c #709DCD"' +','#13#10'"t '#9'c #9797BA",'#13#10'"u '#9'c #20325A",'#13#10'"v '#9'c #005D' +'00",'#13#10'"w '#9'c #804550",'#13#10'"x '#9'c #5A87BA",'#13#10'"y '#9'c #9' +'49157",'#13#10'"z '#9'c #38387C",'#13#10'"A '#9'c #4A735D",'#13#10'"B '#9'c' +' #729FCF",'#13#10'"C '#9'c #4070AC",'#13#10'"D '#9'c #010158",'#13#10'"E '#9 +'c #000255",'#13#10'"F '#9'c #6C465B",'#13#10'"G '#9'c #3D68A0",'#13#10'"H ' +#9'c #5280B8",'#13#10'"I '#9'c #3465A4",'#13#10'"J '#9'c #37629B",'#13#10'"K' +' '#9'c #B8C1CE",'#13#10'"L '#9'c #5F945F",'#13#10'"M '#9'c #009C00",'#13#10 +'"N '#9'c #00A300",'#13#10'"O '#9'c #00AA00",'#13#10'"P '#9'c #00B100",'#13 +#10'"Q '#9'c #00B800",'#13#10'"R '#9'c #9494B8",'#13#10'"S '#9'c #0D1458",' +#13#10'"T '#9'c #000A4F",'#13#10'"U '#9'c #002836",'#13#10'"V '#9'c #006708"' +','#13#10'"W '#9'c #00710D",'#13#10'"X '#9'c #002B3D",'#13#10'"Y '#9'c #000E' +'4F",'#13#10'"Z '#9'c #000952",'#13#10'"` '#9'c #002842",'#13#10'" .'#9'c #0' +'08015",'#13#10'"..'#9'c #272771",'#13#10'"+.'#9'c #C9C9DB",'#13#10'"@.'#9'c' +' #1F305A",'#13#10'"#.'#9'c #003921",'#13#10'"$.'#9'c #001C3F",'#13#10'"%.'#9 +'c #001B42",'#13#10'"&.'#9'c #000554",'#13#10'"*.'#9'c #000753",'#13#10'"=.' +#9'c #004B2B",'#13#10'"-.'#9'c #005627",'#13#10'";.'#9'c #00114E",'#13#10'">' +'.'#9'c #008615",'#13#10'",.'#9'c #C0C0D5",'#13#10'"''.'#9'c #2A415B",'#13#10 +'").'#9'c #005209",'#13#10'"!.'#9'c #005C06",'#13#10'"~.'#9'c #003F23",'#13 +#10'"{.'#9'c #00491F",'#13#10'"].'#9'c #003434",'#13#10'"^.'#9'c #005E1D",' +#13#10'"/.'#9'c #00850F",'#13#10'"(.'#9'c #002C41",'#13#10'"_.'#9'c #FDFDFD"' +','#13#10'":.'#9'c #424283",'#13#10'"<.'#9'c #001446",'#13#10'"[.'#9'c #0038' +'29",'#13#10'"}.'#9'c #006E02",'#13#10'"|.'#9'c #001D43",'#13#10'"1.'#9'c #0' +'08505",'#13#10'"2.'#9'c #000F50",'#13#10'"3.'#9'c #000D51",'#13#10'"4.'#9'c' +' #FCFCFD",'#13#10'"5.'#9'c #466E5D",'#13#10'"6.'#9'c #002733",'#13#10'"7.'#9 +'c #000B4D",'#13#10'"8.'#9'c #002739",'#13#10'"9.'#9'c #000E50",'#13#10'"0.' +#9'c #9898BB",'#13#10'"a.'#9'c #608D68",'#13#10'"b.'#9'c #006002",'#13#10'"c' +'.'#9'c #000454",'#13#10'"d.'#9'c #000652",'#13#10'"e.'#9'c #003433",'#13#10 +'"f.'#9'c #00601C",'#13#10'"g.'#9'c #008B05",'#13#10'"h.'#9'c #004033",'#13 +#10'"i.'#9'c #007419",'#13#10'"j.'#9'c #00343E",'#13#10'"k.'#9'c #0ABA0A",' +#13#10'"l.'#9'c #B7B7CF",'#13#10'"m.'#9'c #313475",'#13#10'"n.'#9'c #18443D"' +','#13#10'"o.'#9'c #002537",'#13#10'"p.'#9'c #001D40",'#13#10'"q.'#9'c #000A' +'51",'#13#10'"r.'#9'c #004A2B",'#13#10'"s.'#9'c #00164B",'#13#10'"t.'#9'c #0' +'00057",'#13#10'"u.'#9'c #099419",'#13#10'"v.'#9'c #9CE39C",'#13#10'"w.'#9'c' +' #191968",'#13#10'"x.'#9'c #ABABC7",'#13#10'"y.'#9'c #BCBCD3",'#13#10'"z.'#9 +'c #252570",'#13#10'"A.'#9'c #05055B",'#13#10'"B.'#9'c #111460",'#13#10'"C.' +#9'c #2F4267",'#13#10'"D.'#9'c #579660",'#13#10'"E.'#9'c #3D993D",'#13#10'"F' +'.'#9'c #1A8C1A",'#13#10'"G.'#9'c #00710E",'#13#10'"H.'#9'c #032B41",'#13#10 +'"I.'#9'c #040F54",'#13#10'"J.'#9'c #060E57",'#13#10'"K.'#9'c #1F3560",'#13 +#10'"L.'#9'c #06085A",'#13#10'"M.'#9'c #3D407E",'#13#10'"N.'#9'c #333379",' +#13#10'"O.'#9'c #F9FCF9",'#13#10'"P.'#9'c #9C9CBE",'#13#10'" . . . . + + + ' +'+ + + + + + + + + + + + + + + + ",'#13#10'"+ + @ . # $ % & * = - ; > , '' )' +' + ! ~ { ~ ! + + ",'#13#10'"+ + ] . ^ / / / / / / / / / / ( _ { : : : { ! +' +' ",'#13#10'"+ < [ } | / / / / / / / / / / / 1 : 2 2 2 : ~ + ",'#13#10'"+ 3 ' ,'. 4 / / / / / / / / 5 5 5 5 5 5 2 2 2 : { + ",'#13#10'"+ 6 . 7 8 9 0 a / b ' +'c d 5 e e e e 5 f g 2 : ~ + ",'#13#10'"h i j k l m n 0 b o p q 5 e r r e f ' +'s f : { ! + ",'#13#10'"t . u v l m n 0 b o p q 5 e r r w f x f y ! + + ",' +#13#10'"z . A v l m n 0 b o p q 5 e r r f B C B f + + + ",'#13#10'". . D E E' +' m n 0 b o p q 5 e e F G H I H J K + + ",'#13#10'"+ + L v l m n 0 b o p q 5' +' 5 5 f B B B B B f + + ",'#13#10'"+ + L v l m n 0 b o p q M N O f f f f f f' +' f + + ",'#13#10'"+ + L v l m n 0 b o p q M N O P Q + + + + + + + ",'#13#10 +'"+ + L v l m n 0 b o p q M N O P Q + + + + + + + ",'#13#10'"+ + L v l m n 0' +' b o p q M N O P Q + + + + + + + ",'#13#10'"+ R S E T U V 0 b W X Y Z ` .P' +' Q . ..+ + + + + ",'#13#10'"+.. @.#.$.. %.0 | &.*.=.-.;.. >.Q . ..+ + + + +' +' ",'#13#10'",.. ''.).!.~.{.0 ].. ^.q M /.. (.Q . ..+ + + + + ",'#13#10'"_.:' +'.. . <.[.}.0 |.. 1.q M N 2.3.Q . ..+ + + + + ",'#13#10'"+ 4.5.6.7.. 8.0 |..' +' 1.q M N 9.9.Q . ..+ + + + + ",'#13#10'"0.z a.v b.c.d.0 e.. f.g.h.i.. j.k..' +' ..+ + + + + ",'#13#10'"l.. m.n.o.. p.0 | &.q.r.s.. t.u.v.. w.x.x.x.y.+ ",' +#13#10'"+ 0.z.A.B.C.D.E.F.G.H.I.J.K.L.M.+ . . . . . N.+ ",'#13#10'"+ + + + +' +' + + + + O.+ + + + h P.+ + + + + + + + "};'#13#10 ]); LazarusResources.Add('TZSequence','XPM',[ '/* XPM */'#13#10'static char * TZSequence.xpm_xpm[] = {'#13#10'"24 24 116 2"' +','#13#10'" '#9'c #23236E",'#13#10'". '#9'c #000058",'#13#10'"+ '#9'c None"' +','#13#10'"@ '#9'c #FBC5C5",'#13#10'"# '#9'c #F55050",'#13#10'"$ '#9'c #F235' +'35",'#13#10'"% '#9'c #C8C8DA",'#13#10'"& '#9'c #2F2F76",'#13#10'"* '#9'c #D' +'AEBDA",'#13#10'"= '#9'c #ACD5AC",'#13#10'"- '#9'c #89C489",'#13#10'"; '#9'c' +' #65B265",'#13#10'"> '#9'c #42A042",'#13#10'", '#9'c #229022",'#13#10'"'' ' +#9'c #349934",'#13#10'") '#9'c #58AB58",'#13#10'"! '#9'c #7CBD7C",'#13#10'"~' +' '#9'c #A0CEA0",'#13#10'"{ '#9'c #D97667",'#13#10'"] '#9'c #F10101",'#13#10 +'"^ '#9'c #F10000",'#13#10'"/ '#9'c #F1CCCC",'#13#10'"( '#9'c #F10202",'#13 +#10'"_ '#9'c #F88787",'#13#10'": '#9'c #616197",'#13#10'"< '#9'c #2B5C53",' +#13#10'"[ '#9'c #007F00",'#13#10'"} '#9'c #366200",'#13#10'"| '#9'c #EF0000"' +','#13#10'"1 '#9'c #F4F4F7",'#13#10'"2 '#9'c #111163",'#13#10'"3 '#9'c #0204' +'58",'#13#10'"4 '#9'c #00700A",'#13#10'"5 '#9'c #A52700",'#13#10'"6 '#9'c #A' +'CACC8",'#13#10'"7 '#9'c #162557",'#13#10'"8 '#9'c #007800",'#13#10'"9 '#9'c' +' #DB2A1E",'#13#10'"0 '#9'c #F1EBEB",'#13#10'"a '#9'c #4B4B89",'#13#10'"b '#9 +'c #3C5E5C",'#13#10'"c '#9'c #005D00",'#13#10'"d '#9'c #006A00",'#13#10'"e ' +#9'c #007300",'#13#10'"f '#9'c #007900",'#13#10'"g '#9'c #007D00",'#13#10'"h' +' '#9'c #008000",'#13#10'"i '#9'c #008100",'#13#10'"j '#9'c #008500",'#13#10 +'"k '#9'c #008B00",'#13#10'"l '#9'c #DB2C1E",'#13#10'"m '#9'c #E8E8EF",'#13 +#10'"n '#9'c #0A0A5E",'#13#10'"o '#9'c #0D0D60",'#13#10'"p '#9'c #598A5E",' +#13#10'"q '#9'c #006400",'#13#10'"r '#9'c #006B00",'#13#10'"s '#9'c #007200"' +','#13#10'"t '#9'c #008700",'#13#10'"u '#9'c #008E00",'#13#10'"v '#9'c #0095' +'00",'#13#10'"w '#9'c #009C00",'#13#10'"x '#9'c #A53300",'#13#10'"y '#9'c #9' +'797BA",'#13#10'"z '#9'c #575790",'#13#10'"A '#9'c #5F945F",'#13#10'"B '#9'c' +' #367D00",'#13#10'"C '#9'c #EF0100",'#13#10'"D '#9'c #38387C",'#13#10'"E '#9 +'c #C7C7DA",'#13#10'"F '#9'c #00A300",'#13#10'"G '#9'c #715A00",'#13#10'"H ' +#9'c #030359",'#13#10'"I '#9'c #020358",'#13#10'"J '#9'c #000255",'#13#10'"K' +' '#9'c #00AA00",'#13#10'"L '#9'c #368800",'#13#10'"M '#9'c #A53900",'#13#10 +'"N '#9'c #00B100",'#13#10'"O '#9'c #00B800",'#13#10'"P '#9'c #4174B4",'#13 +#10'"Q '#9'c #B9C2CE",'#13#10'"R '#9'c #125827",'#13#10'"S '#9'c #B2C2D7",' +#13#10'"T '#9'c #126A27",'#13#10'"U '#9'c #7F9EC7",'#13#10'"V '#9'c #5F88BC"' +','#13#10'"W '#9'c #95AECE",'#13#10'"X '#9'c #7598C4",'#13#10'"Y '#9'c #3F73' +'A8",'#13#10'"Z '#9'c #517FB9",'#13#10'"` '#9'c #7B9CC6",'#13#10'" .'#9'c #1' +'27827",'#13#10'"..'#9'c #2A6464",'#13#10'"+.'#9'c #126127",'#13#10'"@.'#9'c' +' #23664F",'#13#10'"#.'#9'c #4075A4",'#13#10'"$.'#9'c #125D27",'#13#10'"%.'#9 +'c #126627",'#13#10'"&.'#9'c #4677AE",'#13#10'"*.'#9'c #41768B",'#13#10'"=.' +#9'c #2F6B75",'#13#10'"-.'#9'c #3F74A8",'#13#10'";.'#9'c #87A5CA",'#13#10'">' +'.'#9'c #0ABA0A",'#13#10'",.'#9'c #0CB40C",'#13#10'"''.'#9'c #9CE39C",'#13#10 +'").'#9'c #B8C1CD",'#13#10'"!.'#9'c #3A7F4F",'#13#10'"~.'#9'c #0D930D",'#13 +#10'"{.'#9'c #30A830",'#13#10'"].'#9'c #54BD54",'#13#10'"^.'#9'c #78CD78",' +#13#10'"/.'#9'c #9CDE9C",'#13#10'"(.'#9'c #EDF9ED",'#13#10'"_.'#9'c #F9FCF9"' +','#13#10'" . . . . + + + + + + + + + + + @ # $ $ # @ + + ",'#13#10'"+ + % ' +'. & * = - ; > , '' ) ! ~ { ] ^ / / ^ ( _ + ",'#13#10'"+ + : . < [ [ [ [ [ [' +' [ [ [ } | ^ ^ / / ^ ^ ( @ ",'#13#10'"+ 1 2 3 4 [ [ [ [ [ [ [ [ [ 5 ^ ^ ^ /' +' / ^ ^ ^ # ",'#13#10'"+ 6 . 7 8 [ [ [ [ [ [ [ [ [ 9 / / / 0 0 / / / $ ",'#13 +#10'"+ a . b c d e f g [ h i j k l / / / 0 0 / / / $ ",'#13#10'"m n o p c q ' +'r s f h t u v w x ^ ^ ^ / / ^ ^ ^ # ",'#13#10'"y . z A c q r s f h t u v w ' +'B C ^ ^ / / ^ ^ ( @ ",'#13#10'"D . E A c q r s f h t u v w F G C ^ / / ^ ( ' +'_ + ",'#13#10'". . H I J q r s f h t u v w F K L M $ $ # @ + + ",'#13#10'"+' +' + + A c q r s f h t u v w F K N O + + + + + + ",'#13#10'"+ + + A c P P P f' +' h t u v w F K N O + + + + + + ",'#13#10'"+ Q P P R P S P T P P u v w F K N' +' O + + + + + + ",'#13#10'"+ P S U P V W V P U S P v w F K N O + + + + + + "' +','#13#10'"+ P U W W W W W W W U P v w F K N O + + + + + + ",'#13#10'"+ Q P ' +'W X Y Z Y ` W P .v w F K N O + + + + + + ",'#13#10'"P P V W Y ..+.@.#.W V ' +'P P w F K N O + + + + + + ",'#13#10'"P S W W Z $.r %.Z W W S P w F K N O + ' +'+ + + + + ",'#13#10'"P P V W &.*.+.=.-.W V P P w F K N O + + + + + + ",'#13 +#10'"+ Q P S X &.Z Y ;.W P .v w F K N O + + + + + + ",'#13#10'"+ P U W W W ' +'W W W W U P v w F K N >.+ + + + + + ",'#13#10'"+ P S U P V W V P U S P v w ' +'F K ,.''.+ + + + + + ",'#13#10'"+ + P P ).P S P !.P P ~.{.].^./.(.+ + + + +' +' + + ",'#13#10'"+ + + + + P P P + + _.+ + + + + + + + + + + + + "};'#13#10 ]); LazarusResources.Add('TZIBEventAlerter','XPM',[ '/* XPM */'#13#10'static char * TZIBEventAlerter.xpm_xpm[] = {'#13#10'"24 24 ' +'158 2",'#13#10'" '#9'c #23236E",'#13#10'". '#9'c #000058",'#13#10'"+ '#9'c' +' None",'#13#10'"@ '#9'c #B0B0B0",'#13#10'"# '#9'c #000000",'#13#10'"$ '#9'c' +' #D4D4D4",'#13#10'"% '#9'c #C8C8DA",'#13#10'"& '#9'c #2F2F76",'#13#10'"* '#9 +'c #EBCF7C",'#13#10'"= '#9'c #616197",'#13#10'"- '#9'c #8D8DB4",'#13#10'"; ' +#9'c #584E1E",'#13#10'"> '#9'c #F2DB88",'#13#10'", '#9'c #F6EAB4",'#13#10'"' +''' '#9'c #C4A94C",'#13#10'") '#9'c #403816",'#13#10'"! '#9'c #F4F4F7",'#13 +#10'"~ '#9'c #111163",'#13#10'"{ '#9'c #07075C",'#13#10'"] '#9'c #E2E2EC",' +#13#10'"^ '#9'c #806A04",'#13#10'"/ '#9'c #E6CD62",'#13#10'"( '#9'c #FCFDDD"' +','#13#10'"_ '#9'c #F9ECBF",'#13#10'": '#9'c #8B7826",'#13#10'"< '#9'c #C6B1' +'65",'#13#10'"[ '#9'c #FAF3CF",'#13#10'"} '#9'c #FCF2BE",'#13#10'"| '#9'c #F' +'4E18F",'#13#10'"1 '#9'c #BD9D37",'#13#10'"2 '#9'c #ACACC8",'#13#10'"3 '#9'c' +' #424283",'#13#10'"4 '#9'c #E2BD3B",'#13#10'"5 '#9'c #FCFDAC",'#13#10'"6 '#9 +'c #F7E6A6",'#13#10'"7 '#9'c #FEFAE7",'#13#10'"8 '#9'c #FBEB9C",'#13#10'"9 ' +#9'c #C5AA4A",'#13#10'"0 '#9'c #594E1F",'#13#10'"a '#9'c #4B4B89",'#13#10'"b' +' '#9'c #8F888B",'#13#10'"c '#9'c #E3C649",'#13#10'"d '#9'c #C1A342",'#13#10 +'"e '#9'c #FAF2C4",'#13#10'"f '#9'c #FEF8D3",'#13#10'"g '#9'c #FFFADA",'#13 +#10'"h '#9'c #FDF1A8",'#13#10'"i '#9'c #EED060",'#13#10'"j '#9'c #AF820E",' +#13#10'"k '#9'c #E8E8EF",'#13#10'"l '#9'c #0A0A5E",'#13#10'"m '#9'c #0C0B5D"' +','#13#10'"n '#9'c #D3B13C",'#13#10'"o '#9'c #797979",'#13#10'"p '#9'c #9D91' +'53",'#13#10'"q '#9'c #FAE98D",'#13#10'"r '#9'c #FFF4B3",'#13#10'"s '#9'c #F' +'FF5BC",'#13#10'"t '#9'c #FFF092",'#13#10'"u '#9'c #FDEB7A",'#13#10'"v '#9'c' +' #F4D750",'#13#10'"w '#9'c #D8A717",'#13#10'"x '#9'c #9797BA",'#13#10'"y '#9 +'c #533A40",'#13#10'"z '#9'c #E4AC31",'#13#10'"A '#9'c #C08414",'#13#10'"B ' +#9'c #221E0C",'#13#10'"C '#9'c #F0D262",'#13#10'"D '#9'c #F8E379",'#13#10'"E' +' '#9'c #FAF0AC",'#13#10'"F '#9'c #FAE77C",'#13#10'"G '#9'c #F9E161",'#13#10 +'"H '#9'c #F1D145",'#13#10'"I '#9'c #E6BE28",'#13#10'"J '#9'c #C99507",'#13 +#10'"K '#9'c #845C00",'#13#10'"L '#9'c #38387C",'#13#10'"M '#9'c #C4B792",' +#13#10'"N '#9'c #FCF4DB",'#13#10'"O '#9'c #93691D",'#13#10'"P '#9'c #F89B0A"' +','#13#10'"Q '#9'c #A06707",'#13#10'"R '#9'c #F8A309",'#13#10'"S '#9'c #C4A1' +'4E",'#13#10'"T '#9'c #CDB369",'#13#10'"U '#9'c #D2BA78",'#13#10'"V '#9'c #D' +'8C38A",'#13#10'"W '#9'c #D0B870",'#13#10'"X '#9'c #C7AA53",'#13#10'"Y '#9'c' +' #B78F23",'#13#10'"Z '#9'c #A97A02",'#13#10'"` '#9'c #A07000",'#13#10'" .'#9 +'c #8E6100",'#13#10'"..'#9'c #5B3C00",'#13#10'"+.'#9'c #030359",'#13#10'"@.' +#9'c #06065B",'#13#10'"#.'#9'c #F99408",'#13#10'"$.'#9'c #0F0F0F",'#13#10'"%' +'.'#9'c #E1AB71",'#13#10'"&.'#9'c #E39427",'#13#10'"*.'#9'c #F18C12",'#13#10 +'"=.'#9'c #E29D3F",'#13#10'"-.'#9'c #F4B46E",'#13#10'";.'#9'c #FC8D04",'#13 +#10'">.'#9'c #F6CCA1",'#13#10'",.'#9'c #FFEF8C",'#13#10'"''.'#9'c #E0A468",' +#13#10'").'#9'c #EC9C2E",'#13#10'"!.'#9'c #F98407",'#13#10'"~.'#9'c #ADAE98"' +','#13#10'"{.'#9'c #FB7C05",'#13#10'"].'#9'c #E97419",'#13#10'"^.'#9'c #E4B2' +'90",'#13#10'"/.'#9'c #904E30",'#13#10'"(.'#9'c #FB7405",'#13#10'"_.'#9'c #E' +'97C1C",'#13#10'":.'#9'c #CC7328",'#13#10'"<.'#9'c #EA6C15",'#13#10'"[.'#9'c' +' #D18954",'#13#10'"}.'#9'c #A9551C",'#13#10'"|.'#9'c #FB6804",'#13#10'"1.'#9 +'c #FCE4BC",'#13#10'"2.'#9'c #B26426",'#13#10'"3.'#9'c #D97425",'#13#10'"4.' +#9'c #E86417",'#13#10'"5.'#9'c #D86C25",'#13#10'"6.'#9'c #C45B24",'#13#10'"7' +'.'#9'c #FB5804",'#13#10'"8.'#9'c #EC7B4E",'#13#10'"9.'#9'c #C6642A",'#13#10 +'"0.'#9'c #E95C16",'#13#10'"a.'#9'c #FCAC78",'#13#10'"b.'#9'c #FCA67F",'#13 +#10'"c.'#9'c #FB4804",'#13#10'"d.'#9'c #B2664A",'#13#10'"e.'#9'c #FCEDDF",' +#13#10'"f.'#9'c #DA4D1D",'#13#10'"g.'#9'c #DFA48B",'#13#10'"h.'#9'c #E75414"' +','#13#10'"i.'#9'c #FB3C04",'#13#10'"j.'#9'c #EA4511",'#13#10'"k.'#9'c #FB35' +'04",'#13#10'"l.'#9'c #DF3C14",'#13#10'"m.'#9'c #FCDCD1",'#13#10'"n.'#9'c #F' +'B2B04",'#13#10'"o.'#9'c #DF3315",'#13#10'"p.'#9'c #FB2404",'#13#10'"q.'#9'c' +' #FB1C04",'#13#10'"r.'#9'c #FC866E",'#13#10'"s.'#9'c #DF2412",'#13#10'"t.'#9 +'c #AC320C",'#13#10'"u.'#9'c #FC1504",'#13#10'"v.'#9'c #DC1D13",'#13#10'"w.' +#9'c #C61816",'#13#10'"x.'#9'c #FCC4BD",'#13#10'"y.'#9'c #FB0304",'#13#10'"z' +'.'#9'c #FA8C8A",'#13#10'"A.'#9'c #E90B09",'#13#10'" . . . . + + + + + + + ' +'+ + + + @ # $ + + + + + ",'#13#10'"+ + % . & + + + + + + + + + + @ # * # $ ' +'+ + + + ",'#13#10'"+ + = . - + + + + + + + + + $ ; > , '' ) $ + + + ",'#13 +#10'"+ ! ~ { ] + + ^ / ( + _ / : # < [ } | 1 # + + + ",'#13#10'"+ 2 . 3 + 4 ' +'5 + + + + + + $ ; 6 7 + 8 9 0 $ + + ",'#13#10'"+ a . b c + + + + + + + + # ' +'d e f g h i j # + + ",'#13#10'"k l m n + + + + + + + + o p q r s t u v w 0 ' +'o + ",'#13#10'"x . y + + + + + z A _ $ B C D E F G H I J K # $ ",'#13#10'"L' +' . M + + + N O P Q R # S T U V W X Y Z ` ...# ",'#13#10'". . +.@.@.( #.#.#' +'.#.P # # $.# # # # # # # # # # ",'#13#10'"%.&.+ + + + *.=.-.;.;.;.;.>.+ + #' ,' ,.# ;.+ + + + ",'#13#10'"*.''.+ + + + + + + ).!.!.!.*.+ + @ # ~.{.-.+ + + ' +'",'#13#10'"].^.+ + + + + + /.(.(.(.(._.+ + + + ( (.:.+ + + ",'#13#10'"<.[.+' +' + + + }.|.|.|.|.|.|.1.+ + + + 2.|.3.+ + + ",'#13#10'"4.5.+ + + 6.7.|.|.7.7' +'.|.8.+ + + + + 7.|.9.+ + + ",'#13#10'"0.7.+ + + 7.7.7.7.7.7.7.+ + + + + 0.7' +'.7.a.+ + + ",'#13#10'"b.c.d.+ e.c.c.c.c.c.c.f.+ + + g.h.c.c.7.( + + + ",'#13 +#10'"+ i.c.N + i.i.i.i.i.c.i.j.j.j.i.i.i.i.j.+ + + + ",'#13#10'"+ f.k.l.+ k.' +'k.k.k.k.k.k.k.k.k.k.k.k.k.m.+ + + + ",'#13#10'"+ + n.n.o.o.n.p.n.p.p.p.p.n.' +'n.n.n.n.l.+ + + + + ",'#13#10'"+ + e.q.q.r.q.q.q.q.q.q.q.q.q.q.q.s.+ + + + ' +'+ + ",'#13#10'"+ + + e.q.t.q.u.u.u.u.u.u.u.u.u.v.+ + + + + + + ",'#13#10'"+' +' + + + N w.x.y.y.y.y.y.y.y.y.z.+ + + + + + + + ",'#13#10'"+ + + + + + + e.w' +'.y.y.A.w.x.+ + + + + + + + + + "};'#13#10 ]); ================================================ FILE: lib/zeosdbo/src/component/ZComponentReg.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Database Components Registration } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZComponentReg; interface {$I ZComponent.inc} { Zeos palette names } const ZEOS_DB_PALETTE = 'Zeos Access'; procedure Register; implementation uses {$IFDEF WITH_PROPERTY_EDITOR} ZPropertyEditor, {$IFDEF FPC} PropEdits, ZUpdateSqlEditor, ComponentEditors, LResources, {$ELSE} {$IFNDEF UNIX} {$IFNDEF FPC} ZUpdateSqlEditor, {$ENDIF} {$ENDIF} DesignIntf, SysUtils, // **** Pitfiend addition, required to be able to put info in the delphi ide splash screen and about box ToolsAPI, // {$ENDIF} {$ENDIF} Classes, ZConnection, ZAbstractConnection, ZDataset, ZSqlUpdate, ZSqlProcessor, ZStoredProcedure, ZGroupedConnection, ZConnectionGroup , ZSqlMonitor, ZSqlMetadata, ZSequence {$IFDEF ENABLE_INTERBASE}, ZIBEventAlerter {$ENDIF} {$IFDEF ENABLE_POSTGRESQL}, ZPgEventAlerter {$ENDIF}; {** Registers components in a component palette. } procedure Register; {$IFNDEF FPC} // **** Pitfiend addition start {$IF DECLARED(IOTAAboutBoxServices)} // this allow to put a nice and pro entry in the delphi ide splash screen and about box var // AboutSvcs: IOTAAboutBoxServices; // {$IFEND} // {$ENDIF} // **** Pitfiend addition end begin RegisterComponents(ZEOS_DB_PALETTE, [ TZConnection, TZReadOnlyQuery, TZQuery, TZTable, TZUpdateSQL, TZConnectionGroup, TZGroupedConnection, TZStoredProc, TZSQLMetadata, TZSQLProcessor, TZSQLMonitor, TZSequence {$IFDEF ENABLE_INTERBASE}, TZIBEventAlerter {$ENDIF} {$IFDEF ENABLE_POSTGRESQL}, TZPgEventAlerter{$ENDIF}]) ; {$IFDEF WITH_ZSTRINGFIELDS} RegisterClasses([TZWideStringField, TZStringField]); {$ENDIF} {$IFNDEF FPC} // **** Pitfiend addition start {$IF DECLARED(IOTAAboutBoxServices)} if Assigned(SplashScreenServices) then SplashScreenServices.AddPluginBitmap('ZEOSLib Open Source Database Objects', 0); // to have a nice icon, a .res file must be included, then replace 0 by loadbitmap(HInstance, 'RESOURCENAME') if (BorlandIDEServices<>nil) and supports(BorlandIDEServices, IOTAAboutBoxServices, AboutSvcs) then AboutSvcs.AddPluginInfo('ZEOSLib', 'ZEOSLib'+sLineBreak+'OpenSource database components collection'+sLineBreak+sLineBreak+'Forum:http://zeoslib.sourceforge.net', 0, False, 'OpenSource'); // replace 0 by loadbitmap(HInstance, 'RESOURCENAME') {$IFEND} {$ENDIF} // **** Pitfiend addition end {$IFDEF WITH_PROPERTY_EDITOR} RegisterPropertyEditor(TypeInfo(string), TZConnection, 'ClientCodepage', TZClientCodePagePropertyEditor); {EgonHugeist} RegisterPropertyEditor(TypeInfo(string), TZConnection, 'Protocol', TZProtocolPropertyEditor); RegisterPropertyEditor(TypeInfo(string), TZConnection, 'Database', TZDatabasePropertyEditor); RegisterPropertyEditor(TypeInfo(string), TZConnection, 'Catalog', TZCatalogPropertyEditor); RegisterPropertyEditor(TypeInfo(string), TZConnection, 'LibraryLocation', TZLibLocationPropertyEditor); RegisterPropertyEditor(TypeInfo(string), TZConnectionGroup, 'Protocol', TZProtocolPropertyEditor); RegisterPropertyEditor(TypeInfo(string), TZConnectionGroup, 'Database', TZConnectionGroupPropertyEditor); RegisterPropertyEditor(TypeInfo(string), TZGroupedConnection, 'Catalog', TZGroupedConnectionCatalogPropertyEditor); RegisterPropertyEditor(TypeInfo(string), TZConnectionGroup, 'LibraryLocation', TZConnectionGroupLibLocationPropertyEditor); RegisterPropertyEditor(TypeInfo(string), TZQuery, 'LinkedFields', TZDataFieldPropertyEditor); {renamed by bangfauzan} RegisterPropertyEditor(TypeInfo(string), TZQuery, 'MasterFields', TZMasterFieldPropertyEditor); RegisterPropertyEditor(TypeInfo(string), TZQuery, 'SortedFields', TZDataFieldPropertyEditor); RegisterPropertyEditor(TypeInfo(string), TZQuery, 'SequenceField', TZDataFieldPropertyEditor); RegisterPropertyEditor(TypeInfo(string), TZReadOnlyQuery, 'LinkedFields', TZDataFieldPropertyEditor); {renamed by bangfauzan} RegisterPropertyEditor(TypeInfo(string), TZReadOnlyQuery, 'MasterFields', TZMasterFieldPropertyEditor); RegisterPropertyEditor(TypeInfo(string), TZReadOnlyQuery, 'SortedFields', TZDataFieldPropertyEditor); RegisterPropertyEditor(TypeInfo(string), TZTable, 'TableName', TZTableNamePropertyEditor); RegisterPropertyEditor(TypeInfo(string), TZTable, 'LinkedFields', TZDataFieldPropertyEditor); {renamed by bangfauzan} RegisterPropertyEditor(TypeInfo(string), TZTable, 'MasterFields', TZMasterFieldPropertyEditor); RegisterPropertyEditor(TypeInfo(string), TZTable, 'SortedFields', TZDataFieldPropertyEditor); RegisterPropertyEditor(TypeInfo(string), TZTable, 'SequenceField', TZDataFieldPropertyEditor); RegisterPropertyEditor(TypeInfo(string), TZStoredProc, 'StoredProcName', TZProcedureNamePropertyEditor); RegisterPropertyEditor(TypeInfo(string), TZStoredProc, 'SortedFields', TZDataFieldPropertyEditor); RegisterPropertyEditor(TypeInfo(string), TZSequence, 'SequenceName', TZSequenceNamePropertyEditor); {$IFDEF USE_METADATA} RegisterPropertyEditor(TypeInfo(string), TZSQLMetadata, 'Catalog', TZCatalogProperty); RegisterPropertyEditor(TypeInfo(string), TZSQLMetadata, 'ColumnName', TZColumnNamePropertyEditor); RegisterPropertyEditor(TypeInfo(string), TZSQLMetadata, 'ForeignCatalog', TZCatalogProperty); RegisterPropertyEditor(TypeInfo(string), TZSQLMetadata, 'ForeignSchema', TZSchemaPropertyEditor); RegisterPropertyEditor(TypeInfo(string), TZSQLMetadata, 'ForeignTableName', TZTableNamePropertyEditor); RegisterPropertyEditor(TypeInfo(string), TZSQLMetadata, 'LinkedFields', TZDataFieldPropertyEditor); {renamed by bangfauzan} RegisterPropertyEditor(TypeInfo(string), TZSQLMetadata, 'MasterFields', TZMasterFieldPropertyEditor); RegisterPropertyEditor(TypeInfo(string), TZSQLMetadata, 'ProcedureName', TZProcedureNamePropertyEditor); RegisterPropertyEditor(TypeInfo(string), TZSQLMetadata, 'Schema', TZSchemaPropertyEditor); RegisterPropertyEditor(TypeInfo(string), TZSQLMetadata, 'SequenceName', TZSequenceNamePropertyEditor); RegisterPropertyEditor(TypeInfo(string), TZSQLMetadata, 'SortedFields', TZDataFieldPropertyEditor); RegisterPropertyEditor(TypeInfo(string), TZSQLMetadata, 'TableName', TZTableNamePropertyEditor); RegisterPropertyEditor(TypeInfo(string), TZSQLMetadata, 'TypeName', TZTypeNamePropertyEditor); {$ENDIF} {$IFDEF FPC} RegisterComponentEditor(TZUpdateSQL, TZUpdateSQLEditor); {$ELSE} {$IFNDEF UNIX} RegisterComponentEditor(TZUpdateSQL, TZUpdateSQLEditor); {$ENDIF} {$ENDIF} {$ENDIF} end; {$IFDEF FPC} initialization {$I ZComponentReg.lrs} {$ENDIF} end. ================================================ FILE: lib/zeosdbo/src/component/ZConnection.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Database Connection Component } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZConnection; interface {$I ZComponent.inc} uses SysUtils, Classes, ZAbstractConnection, ZClasses; const ZEOS_MAJOR_VERSION = ZClasses.ZEOS_MAJOR_VERSION; ZEOS_MINOR_VERSION = ZClasses.ZEOS_MINOR_VERSION; ZEOS_SUB_VERSION = ZClasses.ZEOS_SUB_VERSION; ZEOS_STATUS = ZClasses.ZEOS_STATUS; ZEOS_VERSION = ZClasses.ZEOS_VERSION; type {** Represents a component which wraps a connection to database. } TZConnection = class(TZAbstractConnection) published property HostName: string read GetHostName write SetHostName; property Port: Integer read GetConnPort write SetConnPort; property Database: string read GetDatabase write SetDatabase; property User: string read GetUser write SetUser; property Password: string read GetPassword write SetPassword; property Protocol: string read GetProtocol write SetProtocol; property Catalog: string read FCatalog write FCatalog; property LibraryLocation: String read GetLibLocation write SetLibLocation; end; implementation end. ================================================ FILE: lib/zeosdbo/src/component/ZConnectionGroup.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Database Connection Component } { } { Originally written by una.bicicleta } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZConnectionGroup; interface {$I ZComponent.inc} uses SysUtils, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} Forms, Dialogs, ZDbcIntfs,ZCompatibility; const mask = '#20#39-VFFV'; { define your own mask } type TZConnectionGroup = class; TZConnectionGroupLink = class; TZConnectionGroupLink = class(TObject) private FSender: TObject; FOnChange: TNotifyEvent; public destructor Destroy; override; procedure Change; dynamic; property OnChange: TNotifyEvent read FOnChange write FOnChange; property Sender: TObject read FSender write FSender; end; {$HINTS OFF} TZConnectionGroup = class(TComponent) private FOnChange: TNotifyEvent; procedure DoChange(Sender: TObject); procedure Change; protected FClients: tList; FProtocol: string; FHostName: string; FPort: Integer; FDatabase: string; FUser: string; FPassword: string; FLibLocation: String; //FCatalog:string; procedure UnregisterAllDataSets; procedure SetUser(const Value: string); procedure SetPassword(const Value: string); procedure DefineProperties(filer: tfiler);override; procedure SetProtocol(const Value: string); procedure SetHostName(const Value: string); procedure SetConnPort(const Value: integer); procedure SetDatabase(const Value: string); procedure SetLibLocation(const Value: String); //procedure SetCatalog(const Value: string); function Encrypt(const str: string): string; //virtual; function Decrypt(const str: string): string; //virtual; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; procedure ReadPass(reader:treader); procedure WritePass(writer:twriter); procedure ReadUser(reader:treader); procedure WriteUser(writer:twriter); procedure RegisterChanges(Value: TZConnectionGroupLink); procedure UnregisterChanges(Value: TZConnectionGroupLink); published property Protocol: string read FProtocol write SetProtocol; property HostName: string read FHostName write SetHostName; property Port: Integer read FPort write SetConnPort default 0; property Database: string read FDatabase write SetDatabase; property User: string read FUser write SetUser stored false; property Password: string read FPassword write SetPassword stored false; property LibraryLocation: String read FLibLocation write SetLibLocation; //property Catalog: string read FCatalog write SetCatalog; property OnChange: TNotifyEvent read FOnChange write FOnChange; // -- todo ---- // add another property or event ? end; {$HINTS ON} implementation // === { TZConnectionGroupLink } ==================================================== destructor TZConnectionGroupLink.Destroy; begin if Sender is TZConnectionGroup then TZConnectionGroup(Sender).UnregisterChanges(Self); inherited Destroy; end; procedure TZConnectionGroupLink.Change; begin if Assigned(FOnChange) then FOnChange(Sender); end; // === { TZConnectionGroup } ============================================= constructor TZConnectionGroup.Create(AOwner: TComponent); begin inherited Create(AOwner); FClients := tList.Create; end; destructor TZConnectionGroup.Destroy; begin UnregisterAllDataSets; FClients := nil; FClients.Free; inherited Destroy; end; procedure TZConnectionGroup.DoChange(Sender: TObject); begin Change; end; procedure TZConnectionGroup.Change; var i:Integer; begin if Assigned(FOnChange) then begin FOnChange(Self); end; if FClients <> nil then for I := 0 to FClients.Count - 1 do TZConnectionGroupLink(FClients[I]).Change; end; // === { TZConnectionGroup } ============================================= function TZConnectionGroup.Decrypt(const str: string): string; var n: integer; begin result:=''; for n:=1 to length(str) do result:=result+ chr(ord(str[n]) xor ord(mask[((n-1) mod length(mask)) +1])); end; function TZConnectionGroup.Encrypt(const str: string): string; begin result:=Decrypt(str); { symmetrical encryption } end; procedure TZConnectionGroup.ReadPass(reader:treader); begin reader.readlistbegin; FPassword := Decrypt(reader.readstring); reader.readlistend; end; procedure TZConnectionGroup.WritePass(writer:twriter); begin writer.writelistbegin; writer.writestring(Encrypt(FPassword)); writer.writelistend; end; procedure TZConnectionGroup.ReadUser(reader:treader); begin reader.readlistbegin; FUser := Decrypt(reader.readstring); reader.readlistend; end; procedure TZConnectionGroup.WriteUser(writer:twriter); begin writer.writelistbegin; writer.writestring(Encrypt(FUser)); writer.writelistend; end; procedure TZConnectionGroup.DefineProperties(filer: tfiler); begin inherited defineproperties(filer); filer.DefineProperty('str1',ReadUser,WriteUser,true); filer.DefineProperty('str2',ReadPass,WritePass,true); end; procedure TZConnectionGroup.SetUser(const Value: string); begin if FUser <> Value then begin FUser := Value; Change; end; end; procedure TZConnectionGroup.SetPassword(const Value: string); begin if FPassword <> Value then begin FPassword := Value; Change; end; end; procedure TZConnectionGroup.SetProtocol(const Value: string); begin if FProtocol <> Value then begin FProtocol := Value; Change; end; end; procedure TZConnectionGroup.SetHostName(const Value: string); begin if FHostName <> Value then begin FHostName := Value; Change; end; end; procedure TZConnectionGroup.SetDatabase(const Value: string); begin if FDatabase <> Value then begin FDatabase := Value; Change; end; end; procedure TZConnectionGroup.SetLibLocation(const Value: String); begin if FLibLocation <> Value then begin FLibLocation := Value; Change; end; end; { procedure TZConnectionGroup.SetCatalog(const Value: string); begin if FCatalog <> Value then begin FCatalog := Value; Change; end; end; } procedure TZConnectionGroup.SetConnPort(const Value: integer); begin if FPort <> Value then begin FPort := Value; Change; end; end; procedure TZConnectionGroup.UnregisterAllDataSets; var I: Integer; Current: TZConnectionGroupLink; begin for I := FClients.Count - 1 downto 0 do begin Current := TZConnectionGroupLink(FClients[I]); FClients.Remove(Current); // try // Current := nil; // except // //Ignore // end; end; end; procedure TZConnectionGroup.RegisterChanges(Value: TZConnectionGroupLink); begin Value.Sender := Self; if FClients <> nil then FClients.Add(Value); end; procedure TZConnectionGroup.UnregisterChanges(Value: TZConnectionGroupLink); var I: Integer; begin if FClients <> nil then for I := 0 to FClients.Count - 1 do if FClients[I] = Value then begin Value.Sender := nil; FClients.Delete(I); Break; end; end; end. ================================================ FILE: lib/zeosdbo/src/component/ZDataset.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Universal Dataset component } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDataset; interface {$I ZComponent.inc} uses ZAbstractRODataset, ZAbstractDataset, ZAbstractTable {$IFDEF OLDFPC}, DB {$ENDIF}; type {** Implements an universal SQL query for read/only data access. } TZReadOnlyQuery = class (TZAbstractRODataSet) published property Active; property IsUniDirectional; property SQL; property ParamCheck; property Params; property FetchRow; // added by Patyi property Properties; property DataSource; property MasterFields; property MasterSource; property LinkedFields; {renamed by bangfauzan} property IndexFieldNames; {bangfauzan addition} property Options; end; {** Implements an universal SQL query for read/write data access. } TZQuery = class (TZAbstractDataSet) published property Active; property ReadOnly default False; property SQL; property ParamCheck; property ParamChar; property Params; property FetchRow; // added by Patyi property ShowRecordTypes; property Properties; property DataSource; property MasterFields; property MasterSource; property LinkedFields; {renamed by bangfauzan} property IndexFieldNames; {bangfauzan addition} property UpdateMode; property WhereMode; property Options; property Sequence; property SequenceField; end; {** Implements an universal SQL query for single table access. } TZTable = class (TZAbstractTable) public property Exists; published property Active; property ReadOnly default False; property TableName; property ShowRecordTypes; property Properties; property FetchRow; // added by Patyi property MasterFields; property MasterSource; property LinkedFields; {renamed by bangfauzan} property IndexFieldNames; {bangfauzan addition} property UpdateMode; property WhereMode; property Options; property Sequence; property SequenceField; end; implementation end. ================================================ FILE: lib/zeosdbo/src/component/ZDatasetUtils.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Dataset utility functions and classes } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDatasetUtils; interface {$I ZComponent.inc} uses Types, Classes, SysUtils, {$IFDEF MSEgui}mclasses, mdb{$ELSE}Db{$ENDIF}, Contnrs, {$IFDEF WITH_UNITANSISTRINGS}AnsiStrings, {$ENDIF} ZDbcIntfs, ZDbcCache, ZCompatibility, ZExpression, ZVariant, ZTokenizer; {** Converts DBC Field Type to TDataset Field Type. @param Value an initial DBC field type. @return a converted TDataset field type. } function ConvertDbcToDatasetType(Value: TZSQLType): TFieldType; {** Converts TDataset Field Type to DBC Field Type. @param Value an initial TDataset field type. @return a converted DBC field type. } function ConvertDatasetToDbcType(Value: TFieldType): TZSQLType; {** Converts field definitions into column information objects. @param Fields a collection of field definitions. @return a collection of column information objects. } function ConvertFieldsToColumnInfo(Fields: TFields): TObjectList; {** Fetches columns from specified resultset. @param ResultSet a source resultset. @param FieldsLookupTable a lookup table to define original index. @param Fields a collection of field definitions. @param RowAccessor a destination row accessor. } procedure FetchFromResultSet(ResultSet: IZResultSet; const FieldsLookupTable: TIntegerDynArray; Fields: TFields; RowAccessor: TZRowAccessor); {** Posts columns from specified resultset. @param ResultSet a source resultset. @param FieldsLookupTable a lookup table to define original index. @param Fields a collection of field definitions. @param RowAccessor a destination row accessor. } procedure PostToResultSet(ResultSet: IZResultSet; const FieldsLookupTable: TIntegerDynArray; Fields: TFields; RowAccessor: TZRowAccessor); {** Defines fields indices for the specified dataset. @param DataSet a dataset object. @param FieldNames a list of field names. @param OnlyDataFields True if only data fields selected. } function DefineFields(DataSet: TDataset; const FieldNames: string; var OnlyDataFields: Boolean): TObjectDynArray; {** Defins a indices of filter fields. @param Dataset a dataset object. @param Expression a expression calculator. @returns an array with field object references. } function DefineFilterFields(DataSet: TDataset; Expression: IZExpression): TObjectDynArray; {** Retrieves a set of specified field values. @param FieldRefs an array with interested field object references. @param ResultSet an initial result set object. @param ResultValues a container for result values. @return an array with field values. } procedure RetrieveDataFieldsFromResultSet(const FieldRefs: TObjectDynArray; ResultSet: IZResultSet; var ResultValues: TZVariantDynArray); {** Retrieves a set of specified field values. @param FieldRefs an array with interested field object references. @param FieldIndices an array with interested field indices. @param RowAccessor a row accessor object. @param ResultValues a container for result values. @return an array with field values. } procedure RetrieveDataFieldsFromRowAccessor(const FieldRefs: TObjectDynArray; const FieldIndices: TIntegerDynArray; RowAccessor: TZRowAccessor; var ResultValues: TZVariantDynArray); {** Copy a set of specified field values to variables. @param Fields an array with interested field object references. @param ResultSet an initial result set object. @param Variables a list of variables. } procedure CopyDataFieldsToVars(const Fields: TObjectDynArray; ResultSet: IZResultSet; Variables: IZVariablesList); {** Prepares values for comparison by CompareFieldsFromResultSet. @param FieldRefs an array with interested field object references. @param DecodedKeyValues given values. @param ResultSet a resultset to get field values. @param PartialKey True if values should be started with the keys. @param CaseInsensitive True if keys are case insensitive. } procedure PrepareValuesForComparison(const FieldRefs: TObjectDynArray; var DecodedKeyValues: TZVariantDynArray; ResultSet: IZResultSet; PartialKey: Boolean; CaseInsensitive: Boolean); {** Compares row field values with the given ones. @param KeyValues given values. @param RowValues row field values. @param PartialKey True if values should be started with the keys. @param CaseInsensitive True if keys are case insensitive. @return if values are equal. } function CompareDataFields(const KeyValues, RowValues: TZVariantDynArray; PartialKey: Boolean; CaseInsensitive: Boolean): Boolean; {** Compares row field values with the given ones. @param FieldRefs an array with interested field object references. @param KeyValues given values. @param RowValues row field values. @param PartialKey True if values should be started with the keys. @param CaseInsensitive True if keys are case insensitive. @return if values are equal. } function CompareFieldsFromResultSet(const FieldRefs: TObjectDynArray; const KeyValues: TZVariantDynArray; ResultSet: IZResultSet; PartialKey: Boolean; CaseInsensitive: Boolean): Boolean; {** Defines a list of key field names. @param Fields a collection of dataset fields. @return a list of key field names. } function DefineKeyFields(Fields: TFields): string; {** Converts datetime value into TDataset internal presentation. @param DataType a type of date-time field. @param Data a data which contains a value. @param Buffer a field buffer pointer } procedure DateTimeToNative(DataType: TFieldType; Data: TDateTime; Buffer: Pointer); {** Converts date times from TDataset internal presentation into datetime value. @param DataType a type of date-time field. @param Buffer a field buffer pointer @return a data which contains a value. } function NativeToDateTime(DataType: TFieldType; Buffer: Pointer): TDateTime; {** Compare values from two key fields. @param Field1 the first field object. @param ResultSet the resultset to read the first field value. @param Field2 the second field object. } function CompareKeyFields(Field1: TField; ResultSet: IZResultSet; Field2: TField): Boolean; {** Defins a indices and directions for sorted fields. @param Dataset a dataset object. @param SortedFields an encoded fields for sorting in the format [ASC | DESC] [, ...] @param FieldRefs a decoded field object references. @param FieldDirs a decoded field directions. @param OnlyDataFields True if only data fields selected. } procedure DefineSortedFields(DataSet: TDataset; const SortedFields: string; var FieldRefs: TObjectDynArray; var FieldDirs: TBooleanDynArray; var OnlyDataFields: Boolean); {** Creates a fields lookup table to define fixed position of the field in dataset. @param Fields a collection of TDataset fields in initial order. @returns a fields lookup table. } function CreateFieldsLookupTable(Fields: TFields): TIntegerDynArray; {** Defines an original field index in the dataset. @param FieldsLookupTable a lookup table to define original index. @param Field a TDataset field object. @returns an original fields index or -1 otherwise. } function DefineFieldIndex(const FieldsLookupTable: TIntegerDynArray; Field: TField): Integer; {** Defines an original field indices in the dataset. @param FieldsLookupTable a lookup table to define original index. @param FieldRefs a TDataset field object references. @returns an array with original fields indices. } function DefineFieldIndices(const FieldsLookupTable: TIntegerDynArray; const FieldRefs: TObjectDynArray): TIntegerDynArray; {** Splits up a qualified object name into pieces. Catalog, schema and objectname. } procedure SplitQualifiedObjectName(QualifiedName: string; var Catalog, Schema, ObjectName: string); overload; {** Splits up a qualified object name into pieces. Catalog, schema and objectname. } procedure SplitQualifiedObjectName(QualifiedName: string; const SupportsCatalogs, SupportsSchemas: Boolean; var Catalog, Schema, ObjectName: string); overload; {** Assigns a Statement value from a TParam @param Index the index of Statement.SetParam(Idex..); @param Statement the PrepredStatement where the values have been assigned @param Param the TParam where the value is assigned from } procedure SetStatementParam(Index: Integer; Statement: IZPreparedStatement; Param: TParam); {** Common variables. } var CommonTokenizer: IZTokenizer; implementation uses ZMessages, ZGenericSqlToken, ZDbcResultSetMetadata, ZAbstractRODataset, ZDbcUtils {$IFNDEF WITHOUT_VARBYTESASSTRING}, ZSysUtils{$ENDIF} {$IFDEF WITH_INLINE_ANSISTRLCOMP}, Windows{$ENDIF}; {** Converts DBC Field Type to TDataset Field Type. @param Value an initial DBC field type. @return a converted TDataset field type. } function ConvertDbcToDatasetType(Value: TZSQLType): TFieldType; begin case Value of stBoolean: Result := ftBoolean; stByte, stShort: Result := ftSmallInt; stInteger: Result := ftInteger; stLong: Result := ftLargeInt; stFloat, stDouble, stBigDecimal: Result := ftFloat; stString: Result := ftString; stBytes{$IFNDEF WITH_FTGUID}, stGUID{$ENDIF}: Result := ftBytes; {$IFDEF WITH_FTGUID} stGUID: Result := ftGUID; {$ENDIF} stDate: Result := ftDate; stTime: Result := ftTime; stTimestamp: Result := ftDateTime; stAsciiStream: Result := ftMemo; stBinaryStream: Result := ftBlob; stUnicodeString: Result := ftWideString; stUnicodeStream: Result := {$IFNDEF WITH_WIDEMEMO}ftWideString{$ELSE}ftWideMemo{$ENDIF}; {$IFDEF WITH_FTDATASETSUPPORT} stDataSet: Result := ftDataSet; {$ENDIF} else Result := ftUnknown; end; end; {** Converts TDataset Field Type to DBC Field Type. @param Value an initial TDataset field type. @return a converted DBC field type. } function ConvertDatasetToDbcType(Value: TFieldType): TZSQLType; begin case Value of ftBoolean: Result := stBoolean; ftSmallInt: Result := stShort; ftInteger, ftAutoInc: Result := stInteger; ftFloat: Result := stDouble; ftLargeInt: Result := stLong; ftCurrency: Result := stBigDecimal; ftString: Result := stString; ftBytes: Result := stBytes; ftDate: Result := stDate; ftTime: Result := stTime; ftDateTime: Result := stTimestamp; ftMemo: Result := stAsciiStream; ftBlob: Result := stBinaryStream; ftWideString: Result := stUnicodeString; {$IFDEF WITH_FTGUID} ftGuid: Result := stGUID; {$ENDIF} {$IFDEF WITH_WIDEMEMO} ftWideMemo: Result := stUnicodeStream; {$ENDIF} {$IFDEF WITH_FTDATASETSUPPORT} ftDataSet: Result := stDataSet; {$ENDIF} else Result := stUnknown; end; end; {** Converts field definitions into column information objects. @param Fields a collection of field definitions. @return a collection of column information objects. } function ConvertFieldsToColumnInfo(Fields: TFields): TObjectList; var I: Integer; Current: TField; ColumnInfo: TZColumnInfo; begin Result := TObjectList.Create(True); for I := 0 to Fields.Count - 1 do begin Current := Fields[I]; ColumnInfo := TZColumnInfo.Create; ColumnInfo.ColumnType := ConvertDatasetToDbcType(Current.DataType); ColumnInfo.ColumnName := Current.FieldName; ColumnInfo.Precision := Current.Size; //This is a hack for stUnicodeStream because there is only ftWideString for both type if ColumnInfo.ColumnType = stUnicodeString then if Current.Size > 10240 then ColumnInfo.ColumnType := stUnicodeStream; ColumnInfo.Scale := 0; ColumnInfo.ColumnLabel := Current.DisplayName; ColumnInfo.ColumnDisplaySize := Current.DisplayWidth; ColumnInfo.DefaultExpression := Current.DefaultExpression; Result.Add(ColumnInfo); end; end; {** Fetches columns from specified resultset. @param ResultSet a source resultset. @param FieldsLookupTable a lookup table to define original index. @param Fields a collection of field definitions. @param RowAccessor a destination row accessor. } procedure FetchFromResultSet(ResultSet: IZResultSet; const FieldsLookupTable: TIntegerDynArray; Fields: TFields; RowAccessor: TZRowAccessor); var I, FieldIndex: Integer; Current: TField; ColumnIndex, ColumnCount: Integer; begin RowAccessor.RowBuffer.Index := ResultSet.GetRow; ColumnCount := ResultSet.GetMetadata.GetColumnCount; for I := 0 to Fields.Count - 1 do begin Current := Fields[I]; if not (Current.FieldKind in [fkData, fkInternalCalc]) then Continue; ColumnIndex := Current.FieldNo; FieldIndex := DefineFieldIndex(FieldsLookupTable, Current); if (ColumnIndex < 1) or (ColumnIndex > ColumnCount) then Continue; case Current.DataType of ftBoolean: RowAccessor.SetBoolean(FieldIndex, ResultSet.GetBoolean(ColumnIndex)); ftSmallInt: RowAccessor.SetShort(FieldIndex, ResultSet.GetShort(ColumnIndex)); ftInteger, ftAutoInc: RowAccessor.SetInt(FieldIndex, ResultSet.GetInt(ColumnIndex)); ftFloat: RowAccessor.SetDouble(FieldIndex, ResultSet.GetDouble(ColumnIndex)); ftLargeInt: RowAccessor.SetLong(FieldIndex, ResultSet.GetLong(ColumnIndex)); ftCurrency: RowAccessor.SetBigDecimal(FieldIndex, ResultSet.GetBigDecimal(ColumnIndex)); ftString: // gto: do we need PChar here? //RowAccessor.SetPChar(FieldIndex, ResultSet.GetPChar(ColumnIndex)); RowAccessor.SetString(FieldIndex, ResultSet.GetString(ColumnIndex)); ftWidestring: RowAccessor.SetUnicodeString(FieldIndex, ResultSet.GetUnicodeString(ColumnIndex)); ftBytes{$IFDEF WITH_FTGUID}, ftGuid{$ENDIF}: RowAccessor.SetBytes(FieldIndex, ResultSet.GetBytes(ColumnIndex)); ftDate: RowAccessor.SetDate(FieldIndex, ResultSet.GetDate(ColumnIndex)); ftTime: RowAccessor.SetTime(FieldIndex, ResultSet.GetTime(ColumnIndex)); ftDateTime: RowAccessor.SetTimestamp(FieldIndex, ResultSet.GetTimestamp(ColumnIndex)); ftMemo, ftBlob {$IFDEF WITH_WIDEMEMO}, ftWideMemo{$ENDIF}: RowAccessor.SetBlob(FieldIndex, ResultSet.GetBlob(ColumnIndex)); {$IFDEF WITH_FTDATASETSUPPORT} ftDataSet: RowAccessor.SetDataSet(FieldIndex, ResultSet.GetDataSet(ColumnIndex)); {$ENDIF} end; if ResultSet.WasNull then RowAccessor.SetNull(FieldIndex); end; end; {** Posts columns from specified resultset. @param ResultSet a source resultset. @param FieldsLookupTable a lookup table to define original index. @param Fields a collection of field definitions. @param RowAccessor a destination row accessor. } procedure PostToResultSet(ResultSet: IZResultSet; const FieldsLookupTable: TIntegerDynArray; Fields: TFields; RowAccessor: TZRowAccessor); var I, FieldIndex: Integer; Current: TField; WasNull: Boolean; ColumnIndex, ColumnCount: Integer; Stream: TStream; begin WasNull := False; RowAccessor.RowBuffer.Index := ResultSet.GetRow; ColumnCount := ResultSet.GetMetadata.GetColumnCount; for I := 0 to Fields.Count - 1 do begin Current := Fields[I]; if Current.FieldKind <> fkData then Continue; ColumnIndex := Current.FieldNo; FieldIndex := DefineFieldIndex(FieldsLookupTable, Current); if (ColumnIndex < 1) or (ColumnIndex > ColumnCount) then Continue; // if (Current.Required = True) and (WasNull = True) then // raise EZDatabaseError.Create(Format(SFieldCanNotBeNull, [Current.FieldName])); case Current.DataType of ftBoolean: ResultSet.UpdateBoolean(ColumnIndex, RowAccessor.GetBoolean(FieldIndex, WasNull)); ftSmallInt: ResultSet.UpdateShort(ColumnIndex, RowAccessor.GetShort(FieldIndex, WasNull)); ftInteger, ftAutoInc: ResultSet.UpdateInt(ColumnIndex, RowAccessor.GetInt(FieldIndex, WasNull)); ftFloat: ResultSet.UpdateDouble(ColumnIndex, RowAccessor.GetDouble(FieldIndex, WasNull)); ftLargeInt: ResultSet.UpdateLong(ColumnIndex, RowAccessor.GetLong(FieldIndex, WasNull)); ftCurrency: ResultSet.UpdateBigDecimal(ColumnIndex, RowAccessor.GetBigDecimal(FieldIndex, WasNull)); ftString: ResultSet.UpdateString(ColumnIndex, RowAccessor.GetString(FieldIndex, WasNull)); ftWidestring: ResultSet.UpdateUnicodeString(ColumnIndex, RowAccessor.GetUnicodeString(FieldIndex, WasNull)); ftBytes{$IFDEF WITH_FTGUID}, ftGuid{$ENDIF}: ResultSet.UpdateBytes(ColumnIndex, RowAccessor.GetBytes(FieldIndex, WasNull)); ftDate: ResultSet.UpdateDate(ColumnIndex, RowAccessor.GetDate(FieldIndex, WasNull)); ftTime: ResultSet.UpdateTime(ColumnIndex, RowAccessor.GetTime(FieldIndex, WasNull)); ftDateTime: ResultSet.UpdateTimestamp(ColumnIndex, RowAccessor.GetTimestamp(FieldIndex, WasNull)); ftMemo: begin Stream := RowAccessor.GetAsciiStream(FieldIndex, WasNull); try ResultSet.UpdateAsciiStream(ColumnIndex, Stream); finally Stream.Free; end; end; {$IFDEF WITH_WIDEMEMO} ftWideMemo: begin Stream := RowAccessor.GetUnicodeStream(FieldIndex, WasNull); try ResultSet.UpdateUnicodeStream(ColumnIndex, Stream); finally Stream.Free; end; end; {$ENDIF} ftBlob: begin Stream := RowAccessor.GetBinaryStream(FieldIndex, WasNull); try ResultSet.UpdateBinaryStream(ColumnIndex, Stream); finally Stream.Free; end; end; {$IFDEF WITH_FTDATASETSUPPORT} ftDataSet: ResultSet.UpdateDataSet(ColumnIndex, RowAccessor.GetDataSet(FieldIndex, WasNull)); {$ENDIF} end; if WasNull then begin // Performance thing : // The default expression will only be set when necessary : if the value really IS null Resultset.UpdateDefaultExpression(ColumnIndex, RowAccessor.GetColumnDefaultExpression(FieldIndex)); ResultSet.UpdateNull(ColumnIndex); end; end; end; {** Defines fields indices for the specified dataset. @param DataSet a dataset object. @param FieldNames a list of field names. @param OnlyDataFields True if only data fields selected. } function DefineFields(DataSet: TDataset; const FieldNames: string; var OnlyDataFields: Boolean): TObjectDynArray; var I: Integer; Tokens: TStrings; TokenType: TZTokenType; TokenValue: string; Field: TField; FieldCount: Integer; begin OnlyDataFields := True; FieldCount := 0; SetLength(Result, FieldCount); Tokens := CommonTokenizer.TokenizeBufferToList(FieldNames, [toSkipEOF, toSkipWhitespaces, toUnifyNumbers, toDecodeStrings]); try for I := 0 to Tokens.Count - 1 do begin TokenType := TZTokenType({$IFDEF oldFPC}Pointer({$ENDIF} Tokens.Objects[I]{$IFDEF oldFPC}){$ENDIF}); TokenValue := Tokens[I]; Field := nil; if TokenType in [ttWord, ttQuoted] then begin Field := DataSet.FieldByName(TokenValue); end else if (TokenType = ttNumber) and (StrToIntDef(TokenValue, 0) < Dataset.Fields.Count) then begin Field := Dataset.Fields[StrToIntDef(TokenValue, 0)]; end else if (TokenValue <> ',') and (TokenValue <> ';') then begin raise EZDatabaseError.Create(Format(SIncorrectSymbol, [TokenValue])); end; if Field <> nil then begin OnlyDataFields := OnlyDataFields and (Field.FieldKind = fkData); Inc(FieldCount); SetLength(Result, FieldCount); Result[FieldCount - 1] := Field; end; end; finally Tokens.Free; end; if Length(Result) = 0 then Result := nil; end; {** Defins a indices of filter fields. @param Dataset a dataset object. @param Expression a expression calculator. @returns an array with field object references. } function DefineFilterFields(DataSet: TDataset; Expression: IZExpression): TObjectDynArray; var I: Integer; Current: TField; begin if Expression.Expression <> '' then begin SetLength(Result, Expression.DefaultVariables.Count); for I := 0 to Expression.DefaultVariables.Count - 1 do begin Current := DataSet.FindField(Expression.DefaultVariables.Names[I]); if Current <> nil then Result[I] := Current else Result[I] := nil; end; end else SetLength(Result, 0); end; {** Retrieves a set of specified field values. @param FieldRefs an array with interested field object references. @param ResultSet an initial result set object. @param ResultValues a container for result values. @return an array with field values. } procedure RetrieveDataFieldsFromResultSet(const FieldRefs: TObjectDynArray; ResultSet: IZResultSet; var ResultValues: TZVariantDynArray); var I, ColumnIndex: Integer; begin for I := 0 to High(FieldRefs) do begin ColumnIndex := TField(FieldRefs[I]).FieldNo; if ColumnIndex >= 0 then begin case TField(FieldRefs[I]).DataType of ftString: DefVarManager.SetAsString(ResultValues[I], ResultSet.GetString(ColumnIndex)); ftBoolean: DefVarManager.SetAsBoolean(ResultValues[I], ResultSet.GetBoolean(ColumnIndex)); ftSmallInt, ftInteger, ftAutoInc: DefVarManager.SetAsInteger(ResultValues[I], ResultSet.GetInt(ColumnIndex)); ftFloat: DefVarManager.SetAsFloat(ResultValues[I], ResultSet.GetDouble(ColumnIndex)); ftLargeInt: DefVarManager.SetAsInteger(ResultValues[I], ResultSet.GetLong(ColumnIndex)); ftCurrency: DefVarManager.SetAsFloat(ResultValues[I], ResultSet.GetBigDecimal(ColumnIndex)); ftDate, ftTime, ftDateTime: DefVarManager.SetAsDateTime(ResultValues[I], ResultSet.GetTimestamp(ColumnIndex)); ftWidestring: DefVarManager.SetAsUnicodeString(ResultValues[I], ResultSet.GetUnicodeString(ColumnIndex)); else DefVarManager.SetAsString(ResultValues[I], ResultSet.GetString(ColumnIndex)); end; if ResultSet.WasNull then ResultValues[I] := NullVariant; end else ResultValues[I] := NullVariant; end; end; {** Retrieves a set of specified field values. @param FieldRefs an array with interested field object references. @param FieldIndices an array with interested field indices. @param RowAccessor a row accessor object. @param ResultValues a container for result values. @return an array with field values. } procedure RetrieveDataFieldsFromRowAccessor(const FieldRefs: TObjectDynArray; const FieldIndices: TIntegerDynArray; RowAccessor: TZRowAccessor; var ResultValues: TZVariantDynArray); var I: Integer; ColumnIndex: Integer; WasNull: Boolean; begin WasNull := False; for I := 0 to High(FieldRefs) do begin ColumnIndex := FieldIndices[I]; case TField(FieldRefs[I]).DataType of ftString: DefVarManager.SetAsString(ResultValues[I], RowAccessor.GetString(ColumnIndex, WasNull)); ftBoolean: DefVarManager.SetAsBoolean(ResultValues[I], RowAccessor.GetBoolean(ColumnIndex, WasNull)); ftSmallInt, ftInteger, ftAutoInc: DefVarManager.SetAsInteger(ResultValues[I], RowAccessor.GetInt(ColumnIndex, WasNull)); ftFloat: DefVarManager.SetAsFloat(ResultValues[I], RowAccessor.GetDouble(ColumnIndex, WasNull)); ftLargeInt: DefVarManager.SetAsInteger(ResultValues[I], RowAccessor.GetLong(ColumnIndex, WasNull)); ftCurrency: DefVarManager.SetAsFloat(ResultValues[I], RowAccessor.GetBigDecimal(ColumnIndex, WasNull)); ftDate, ftTime, ftDateTime: DefVarManager.SetAsDateTime(ResultValues[I], RowAccessor.GetTimestamp(ColumnIndex, WasNull)); ftWidestring: DefVarManager.SetAsUnicodeString(ResultValues[I], RowAccessor.GetUnicodeString(ColumnIndex, WasNull)); else DefVarManager.SetAsString(ResultValues[I], RowAccessor.GetString(ColumnIndex, WasNull)); end; if WasNull then ResultValues[I] := NullVariant; end; end; {** Copy a set of specified field values to variables. @param Fields an array with interested field object references. @param ResultSet an initial result set object. @param Variables a list of variables. } {$IFDEF FPC} {$HINTS OFF} //Temp seems not to be init... {$ENDIF} procedure CopyDataFieldsToVars(const Fields: TObjectDynArray; ResultSet: IZResultSet; Variables: IZVariablesList); var I, ColumnIndex: Integer; Temp: TZVariant; begin for I := 0 to Length(Fields) - 1 do begin if Fields[I] = nil then Continue; ColumnIndex := TField(Fields[I]).FieldNo; if not ResultSet.IsNull(ColumnIndex) then begin case TField(Fields[I]).DataType of ftBoolean: DefVarManager.SetAsBoolean(Temp, ResultSet.GetBoolean(ColumnIndex)); ftSmallInt, ftInteger, ftAutoInc: DefVarManager.SetAsInteger(Temp, ResultSet.GetInt(ColumnIndex)); ftFloat: DefVarManager.SetAsFloat(Temp, ResultSet.GetDouble(ColumnIndex)); ftLargeInt: DefVarManager.SetAsInteger(Temp, ResultSet.GetLong(ColumnIndex)); ftCurrency: DefVarManager.SetAsFloat(Temp, ResultSet.GetBigDecimal(ColumnIndex)); ftDate: DefVarManager.SetAsDateTime(Temp, ResultSet.GetDate(ColumnIndex)); ftTime: DefVarManager.SetAsDateTime(Temp, ResultSet.GetTime(ColumnIndex)); ftDateTime: DefVarManager.SetAsDateTime(Temp, ResultSet.GetTimestamp(ColumnIndex)); ftWidestring: DefVarManager.SetAsUnicodeString(Temp, ResultSet.GetUnicodeString(ColumnIndex)); else DefVarManager.SetAsString(Temp, ResultSet.GetString(ColumnIndex)); end; Variables.Values[I] := Temp; end else begin DefVarManager.SetNull(Temp); Variables.Values[I] := Temp; end; end; end; {$IFDEF FPC} {$HINTS OFF} {$ENDIF} {** Compares row field values with the given ones. @param KeyValues given values. @param RowValues row field values. @param PartialKey True if values should be started with the keys. @param CaseInsensitive True if keys are case insensitive. @return if values are equal. } function CompareDataFields(const KeyValues, RowValues: TZVariantDynArray; PartialKey: Boolean; CaseInsensitive: Boolean): Boolean; var I: Integer; Value1, Value2: AnsiString; WValue1, WValue2: WideString; begin Result := True; for I := 0 to High(KeyValues) do begin case KeyValues[I].VType of vtUnicodeString: begin if CaseInsensitive then begin WValue1 := WideUpperCase(SoftVarManager.GetAsUnicodeString(KeyValues[I])); WValue2 := WideUpperCase(SoftVarManager.GetAsUnicodeString(RowValues[I])); if PartialKey then begin {$IFDEF UNICODE} Result := SysUtils.AnsiStrLComp(PWideChar(WValue2), PWideChar(WValue1), Length(WValue1)) = 0; {$ELSE} Value1 := AnsiString(WValue1); Value2 := AnsiString(WValue2); Result := AnsiStrLComp(PAnsiChar(Value2), PAnsiChar(Value1), Length(Value1)) = 0; {$ENDIF} end else Result := WValue1 = WValue2 end else begin WValue1 := SoftVarManager.GetAsUnicodeString(KeyValues[I]); WValue1 := SoftVarManager.GetAsUnicodeString(RowValues[I]); if PartialKey then begin {$IFDEF UNICODE} Result := SysUtils.AnsiStrLComp(PWideChar(WValue2), PWideChar(WValue1), Length(WValue1)) = 0; {$ELSE} Value1 := AnsiString(WValue1); Value2 := AnsiString(WValue2); Result := AnsiStrLComp(PAnsiChar(Value2), PAnsiChar(Value1), Length(Value1)) = 0; {$ENDIF} end else Result := SoftVarManager.Compare(KeyValues[I], RowValues[I]) = 0; end; end; else begin if CaseInsensitive then begin Value1 := AnsiString(AnsiUpperCase(SoftVarManager.GetAsString(KeyValues[I]))); Value2 := AnsiString(AnsiUpperCase(SoftVarManager.GetAsString(RowValues[I]))); if PartialKey then Result := {$IFDEF WITH_ANSISTRLCOMP_DEPRECATED}AnsiStrings.{$ENDIF}AnsiStrLComp(PAnsiChar(Value2), PAnsiChar(Value1), Length(Value1)) = 0 else Result := Value1 = Value2 end else begin Value1 := AnsiString(SoftVarManager.GetAsString(KeyValues[I])); Value2 := AnsiString(SoftVarManager.GetAsString(RowValues[I])); if PartialKey then Result := {$IFDEF WITH_ANSISTRLCOMP_DEPRECATED}AnsiStrings.{$ENDIF}AnsiStrLComp(PAnsiChar(Value2), PAnsiChar(Value1), Length(Value1)) = 0 else Result := SoftVarManager.Compare(KeyValues[I], RowValues[I]) = 0; end; end; end; if not Result then Break; end; end; {** Prepares values for comparison by CompareFieldsFromResultSet. @param FieldRefs an array with interested field object references. @param DecodedKeyValues given values. @param ResultSet a resultset to get field values. @param PartialKey True if values should be started with the keys. @param CaseInsensitive True if keys are case insensitive. } procedure PrepareValuesForComparison(const FieldRefs: TObjectDynArray; var DecodedKeyValues: TZVariantDynArray; ResultSet: IZResultSet; PartialKey: Boolean; CaseInsensitive: Boolean); var I: Integer; Current: TField; CurrentType : TZSQLType; begin { Preprocesses cycle variables. } for I := 0 to High(FieldRefs) do begin Current := TField(FieldRefs[I]); if DecodedKeyValues[I].VType = vtNull then Continue; CurrentType := ResultSet.GetMetadata.GetColumnType(Current.FieldNo); if PartialKey then begin if CurrentType = stUnicodeString then begin DecodedKeyValues[I] := SoftVarManager.Convert( DecodedKeyValues[I], vtUnicodeString); if CaseInsensitive then begin if DecodedKeyValues[I].VType = vtString then begin DecodedKeyValues[I].VString := Uppercase(DecodedKeyValues[I].VString); DecodedKeyValues[I].VUnicodeString := DecodedKeyValues[I].VString; end else begin DecodedKeyValues[I].VUnicodeString := WideUpperCase(DecodedKeyValues[I].VUnicodeString); end; end; end else begin DecodedKeyValues[I] := SoftVarManager.Convert( DecodedKeyValues[I], vtString); if CaseInsensitive then begin {$IFDEF LAZARUSUTF8HACK} // Is this correct? Assumes the Lazarus convention all strings are UTF8. But is that // true in this point, or should that be converted higher up? DecodedKeyValues[I].VString := WideUpperCase(UTF8Decode (DecodedKeyValues[I].VString)); {$ELSE} DecodedKeyValues[I].VString := AnsiUpperCase(DecodedKeyValues[I].VString); {$ENDIF} end; end; end else begin case CurrentType of stBoolean: DecodedKeyValues[I] := SoftVarManager.Convert( DecodedKeyValues[I], vtBoolean); stByte, stShort, stInteger, stLong: DecodedKeyValues[I] := SoftVarManager.Convert( DecodedKeyValues[I], vtInteger); stFloat, stDouble, stBigDecimal: DecodedKeyValues[I] := SoftVarManager.Convert( DecodedKeyValues[I], vtFloat); stUnicodeString: begin if CaseInsensitive then begin if DecodedKeyValues[I].VType = vtString then begin DecodedKeyValues[I].VString := Uppercase(DecodedKeyValues[I].VString); DecodedKeyValues[I].VUnicodeString := DecodedKeyValues[I].VString; end else begin DecodedKeyValues[I].VUnicodeString := WideUpperCase(DecodedKeyValues[I].VUnicodeString); end; end else begin DecodedKeyValues[I] := SoftVarManager.Convert( DecodedKeyValues[I], vtUnicodeString); end; end; stDate, stTime, stTimestamp: DecodedKeyValues[I] := SoftVarManager.Convert( DecodedKeyValues[I], vtDateTime); else if CaseInsensitive then begin DecodedKeyValues[I] := SoftVarManager.Convert( DecodedKeyValues[I], vtString); {$IFDEF LAZARUSUTF8HACK} // Is this correct? Assumes the Lazarus convention all strings are UTF8. But is that // true in this point, or should that be converted higher up? DecodedKeyValues[I].VString := WideUpperCase(UTF8Decode (DecodedKeyValues[I].VString)); {$ELSE} DecodedKeyValues[I].VString := AnsiUpperCase(DecodedKeyValues[I].VString); {$ENDIF} end else begin DecodedKeyValues[I] := SoftVarManager.Convert( DecodedKeyValues[I], vtString); end; end; end; end; end; {** Compares row field values with the given ones. @param FieldRefs an array with interested field object references. @param KeyValues given values. @param ResultSet a resultset to get field values. @param PartialKey True if values should be started with the keys. @param CaseInsensitive True if keys are case insensitive. @return if values are equal. } function CompareFieldsFromResultSet(const FieldRefs: TObjectDynArray; const KeyValues: TZVariantDynArray; ResultSet: IZResultSet; PartialKey: Boolean; CaseInsensitive: Boolean): Boolean; var I: Integer; ColumnIndex: Integer; AValue1, AValue2: AnsiString; WValue1, WValue2: WideString; CurrentType : TZSQLType; begin Result := True; for I := 0 to High(KeyValues) do begin ColumnIndex := TField(FieldRefs[I]).FieldNo; if KeyValues[I].VType = vtNull then begin Result := ResultSet.IsNull(ColumnIndex); if not Result then Break; Continue; end; CurrentType := ResultSet.GetMetadata.GetColumnType(ColumnIndex); if PartialKey then begin if CurrentType = stUnicodeString then begin WValue1 := KeyValues[I].VUnicodeString; WValue2 := ResultSet.GetUnicodeString(ColumnIndex); if CaseInsensitive then WValue2 := WideUpperCase(WValue2); {$IFDEF UNICODE} Result := SysUtils.AnsiStrLComp(PWideChar(WValue2), PWideChar(WValue1), Length(WValue1)) = 0; {$ELSE} AValue1 := UTF8ToAnsi(UTF8Encode(WValue1)); AValue2 := UTF8ToAnsi(UTF8Encode(WValue2)); Result := AnsiStrLComp(PAnsiChar(AValue2), PAnsiChar(AValue1), Length(AValue1)) = 0; {$ENDIF} end else begin AValue1 := AnsiString(KeyValues[I].VString); if (ResultSet.GetConSettings.ClientCodePage^.Encoding = ceAnsi) or (ResultSet.GetConSettings.AutoEncode and ( ResultSet.GetConSettings.CTRL_CP <> 65001 )) then AValue2 := AnsiString(ResultSet.GetString(ColumnIndex)) else AValue2 := AnsiString({$IFNDEF UNICODE}UTF8ToAnsi{$ENDIF}(ResultSet.GetString(ColumnIndex))); if CaseInsensitive then AValue2 := {$IFDEF WITH_UNITANSISTRINGS}AnsiStrings.{$ENDIF}AnsiUpperCase(AValue2); Result := {$IFDEF WITH_ANSISTRLCOMP_DEPRECATED}AnsiStrings.{$ENDIF}AnsiStrLComp(PAnsiChar(AValue2), PAnsiChar(AValue1), Length(AValue1)) = 0; end; end else begin case CurrentType of stBoolean: begin Result := KeyValues[I].VBoolean = ResultSet.GetBoolean(ColumnIndex); end; stByte, stShort, stInteger, stLong: begin Result := KeyValues[I].VInteger = ResultSet.GetLong(ColumnIndex); end; stFloat: Result := Abs(KeyValues[I].VFloat - ResultSet.GetBigDecimal(ColumnIndex)) < FLOAT_COMPARE_PRECISION_SINGLE; stDouble, stBigDecimal: begin Result := Abs(KeyValues[I].VFloat - ResultSet.GetBigDecimal(ColumnIndex)) < FLOAT_COMPARE_PRECISION; end; stDate, stTime, stTimestamp: begin Result := KeyValues[I].VDateTime = ResultSet.GetTimestamp(ColumnIndex); end; stUnicodeString: begin if CaseInsensitive then begin Result := KeyValues[I].VUnicodeString = WideUpperCase(ResultSet.GetUnicodeString(ColumnIndex)); end else begin Result := KeyValues[I].VUnicodeString = ResultSet.GetUnicodeString(ColumnIndex); end; end; else if CaseInsensitive then begin {$IFDEF LAZARUSUTF8HACK} Result := KeyValues[I].VString = AnsiUpperCase (Utf8ToAnsi(ResultSet.GetString(ColumnIndex))); {$ELSE} Result := KeyValues[I].VString = AnsiUpperCase(ResultSet.GetString(ColumnIndex)); {$ENDIF} end else begin Result := KeyValues[I].VString = ResultSet.GetString(ColumnIndex); end; end; end; Result := Result and not ResultSet.WasNull; if not Result then Break; end; end; {** Defines a list of key field names. @param Fields a collection of dataset fields. @return a list of key field names. } function DefineKeyFields(Fields: TFields): string; var I: Integer; Temp: string; begin Result := ''; for I := 0 to Fields.Count - 1 do begin if (Fields[I].FieldKind = fkData) and not (Fields[I].DataType in [ftBlob, ftMemo, ftBytes {$IFDEF WITH_WIDEMEMO}, ftWideMemo{$ENDIF}]) then begin if Result <> '' then Result := Result + ','; Temp := Fields[I].FieldName; if (Pos(' ', Temp) > 0) or (Pos('-', Temp) > 0) or (Pos('.', Temp) > 0) then Temp := '"' + Temp + '"'; Result := Result + Temp; end; end; end; {** Converts datetime value into TDataset internal presentation. @param DataType a type of date-time field. @param Data a data which contains a value. @param Buffer a field buffer pointer } procedure DateTimeToNative(DataType: TFieldType; Data: TDateTime; Buffer: Pointer); var TimeStamp: TTimeStamp; begin TimeStamp := DateTimeToTimeStamp(Data); case DataType of ftDate: Integer(Buffer^) := TimeStamp.Date; ftTime: Integer(Buffer^) := TimeStamp.Time; else TDateTime(Buffer^) := TimeStampToMSecs(TimeStamp); end; end; {** Converts date times from TDataset internal presentation into datetime value. @param DataType a type of date-time field. @param Buffer a field buffer pointer @return a data which contains a value. } function NativeToDateTime(DataType: TFieldType; Buffer: Pointer): TDateTime; {$IFNDEF OLDFPC} var TimeStamp: TTimeStamp; begin case DataType of ftDate: begin TimeStamp.Time := 0; TimeStamp.Date := Integer(Buffer^); end; ftTime: begin {$IFDEF WITH_FPC_FTTIME_BUG} TimeStamp := DateTimeToTimeStamp(TDateTime(Buffer^)); {$ELSE} TimeStamp.Time := Integer(Buffer^); TimeStamp.Date := DateDelta; {$ENDIF} end; else try {$IF not defined(cpui386) and defined(FPC)} TimeStamp := MSecsToTimeStamp(System.Trunc(Int(TDateTime(Buffer^)))); {$ELSE} TimeStamp := MSecsToTimeStamp(TDateTime(Buffer^)); {$IFEND} except TimeStamp.Time := 0; TimeStamp.Date := 0; end; end; Result := TimeStampToDateTime(TimeStamp); {$ELSE} begin Result := TDateTime(Buffer^); {$ENDIF} end; {** Compare values from two key fields. @param Field1 the first field object. @param ResultSet the resultset to read the first field value. @param Field2 the second field object. } function CompareKeyFields(Field1: TField; ResultSet: IZResultSet; Field2: TField): Boolean; begin Result := False; if Field1.FieldNo >= 1 then begin case Field1.DataType of ftBoolean: Result := ResultSet.GetBoolean(Field1.FieldNo) = Field2.AsBoolean; ftSmallInt, ftInteger, ftAutoInc: Result := ResultSet.GetInt(Field1.FieldNo) = Field2.AsInteger; ftFloat: begin Result := Abs(ResultSet.GetFloat(Field1.FieldNo) - Field2.AsFloat) < FLOAT_COMPARE_PRECISION; end; ftLargeInt: begin if Field2 is TLargeIntField then Result := ResultSet.GetLong(Field1.FieldNo) = TLargeIntField(Field2).AsLargeInt else Result := ResultSet.GetInt(Field1.FieldNo) = Field2.AsInteger; end; ftCurrency: begin Result := Abs(ResultSet.GetBigDecimal(Field1.FieldNo) - Field2.{$IFDEF WITH_ASCURRENCY}AsCurrency{$ELSE}AsFloat{$ENDIF}) < FLOAT_COMPARE_PRECISION; end; ftDate: Result := ResultSet.GetDate(Field1.FieldNo) = Field2.AsDateTime; ftTime: Result := ResultSet.GetTime(Field1.FieldNo) = Field2.AsDateTime; ftDateTime: Result := ResultSet.GetTimestamp(Field1.FieldNo) = Field2.AsDateTime; ftWideString: Result := ResultSet.GetUnicodeString(Field1.FieldNo) = Field2.{$IFDEF WITH_ASVARIANT}AsVariant{$ELSE}AsString{$ENDIF}; else Result := ResultSet.GetString(Field1.FieldNo) = Field2.AsString; end; end; end; {** Defins a indices and directions for sorted fields. @param Dataset a dataset object. @param SortedFields an encoded fields for sorting in the format [ASC | DESC] [, ...] @param FieldRefs a decoded field object references. @param FieldDirs a decoded field directions. @param OnlyDataFields True if only data fields selected. } procedure DefineSortedFields(DataSet: TDataset; const SortedFields: string; var FieldRefs: TObjectDynArray; var FieldDirs: TBooleanDynArray; var OnlyDataFields: Boolean); var I: Integer; Tokens: TStrings; TokenType: TZTokenType; TokenValue: string; Field: TField; FieldCount: Integer; begin OnlyDataFields := True; FieldCount := 0; SetLength(FieldRefs, FieldCount); SetLength(FieldDirs, FieldCount); Tokens := CommonTokenizer.TokenizeBufferToList(SortedFields, [toSkipEOF, toSkipWhitespaces, toUnifyNumbers, toDecodeStrings]); try for I := 0 to Tokens.Count - 1 do begin TokenType := TZTokenType({$IFDEF OLDFPC}Pointer({$ENDIF} Tokens.Objects[I]{$IFDEF OLDFPC}){$ENDIF}); TokenValue := Tokens[I]; Field := nil; if ((UpperCase(TokenValue) = 'DESC') or (UpperCase(TokenValue) = 'ASC')) and (FieldCount > 0) then begin FieldDirs[FieldCount - 1] := (UpperCase(TokenValue) <> 'DESC'); end else if TokenType in [ttWord, ttQuoted] then begin Field := DataSet.FieldByName(TokenValue) end else if (TokenType = ttNumber) and (StrToIntDef(TokenValue, 0) < Dataset.Fields.Count) then begin Field := Dataset.Fields[StrToIntDef(TokenValue, 0)]; end else if (TokenValue <> ',') and (TokenValue <> ';') then begin raise EZDatabaseError.Create(Format(SIncorrectSymbol, [TokenValue])); end; if Field <> nil then begin OnlyDataFields := OnlyDataFields and (Field.FieldKind = fkData); Inc(FieldCount); SetLength(FieldRefs, FieldCount); SetLength(FieldDirs, FieldCount); FieldRefs[FieldCount - 1] := Field; FieldDirs[FieldCount - 1] := True; end; end; finally Tokens.Free; end; end; {** Creates a fields lookup table to define fixed position of the field in dataset. @param Fields a collection of TDataset fields in initial order. @returns a fields lookup table. } function CreateFieldsLookupTable(Fields: TFields): TIntegerDynArray; var I: Integer; begin SetLength(Result, Fields.Count); for I := 0 to Fields.Count - 1 do Result[I] := Integer(Fields[I]); end; {** Defines an original field index in the dataset. @param FieldsLookupTable a lookup table to define original index. @param Field a TDataset field object. @returns an original fields index or -1 otherwise. } function DefineFieldIndex(const FieldsLookupTable: TIntegerDynArray; Field: TField): Integer; var I: Integer; begin Result := -1; for I := 0 to High(FieldsLookupTable) do begin if FieldsLookupTable[I] = Integer(Field) then begin Result := I + 1; Break; end; end; end; {** Defines an original field indices in the dataset. @param FieldsLookupTable a lookup table to define original index. @param FieldRefs a TDataset field object references. @returns an array with original fields indices. } function DefineFieldIndices(const FieldsLookupTable: TIntegerDynArray; const FieldRefs: TObjectDynArray): TIntegerDynArray; var I: Integer; begin if FieldRefs = nil then begin Result := nil; Exit; end; SetLength(Result, Length(FieldRefs)); for I := 0 to High(Result) do Result[I] := DefineFieldIndex(FieldsLookupTable, TField(FieldRefs[I])); end; {** Splits up a qualified object name into pieces. Catalog, schema and objectname. } procedure SplitQualifiedObjectName(QualifiedName: string; var Catalog, Schema, ObjectName: string); {$IFDEF OLDFPC} function ExtractStrings(Separators, WhiteSpace: TSysCharSet; Content: PChar; Strings: TStrings): Integer; var Head, Tail: PChar; EOS, InQuote: Boolean; QuoteChar: Char; Item: string; begin Result := 0; if (Content = nil) or (Content^ = #0) or (Strings = nil) then Exit; Tail := Content; InQuote := False; QuoteChar := #0; Strings.BeginUpdate; try repeat while CharInSet(Tail^, WhiteSpace + [#13, #10]) do Inc(Tail); Head := Tail; while True do begin while (InQuote and not CharInSet(Tail^, [QuoteChar, #0])) or not CharInSet(Tail^, Separators + [#0, #13, #10, '''', '"']) do Inc(Tail); if CharInSet(Tail^, ['''', '"']) then begin if (QuoteChar <> #0) and (QuoteChar = Tail^) then QuoteChar := #0 else QuoteChar := Tail^; InQuote := QuoteChar <> #0; Inc(Tail); end else Break; end; EOS := Tail^ = #0; if (Head <> Tail) and (Head^ <> #0) then begin if Strings <> nil then begin SetString(Item, Head, Tail - Head); Strings.Add(Item); end; Inc(Result); end; Inc(Tail); until EOS; finally Strings.EndUpdate; end; end; {$ENDIF} var SL: TStringList; I: Integer; begin SL := TStringList.Create; try Catalog := ''; Schema := ''; ObjectName := QualifiedName; ExtractStrings(['.'], [' '], PChar(QualifiedName), SL); case SL.Count of 0, 1: ; 2: begin Schema := SL.Strings[0]; ObjectName := SL.Strings[1]; end; 3: begin Catalog := SL.Strings[0]; Schema := SL.Strings[1]; ObjectName := SL.Strings[2]; end; else begin ObjectName := SL.Strings[SL.Count - 1]; Schema := SL.Strings[SL.Count - 2]; for I := 0 to SL.Count - 3 do begin Catalog := Catalog + SL.Strings[I]; if I < SL.Count - 3 then Catalog := Catalog + '.'; end; end; end; finally SL.Free; end; end; {** Splits up a qualified object name into pieces. Catalog, schema and objectname. } procedure SplitQualifiedObjectName(QualifiedName: string; const SupportsCatalogs, SupportsSchemas: Boolean; var Catalog, Schema, ObjectName: string); var SL: TStringList; I: Integer; begin if SupportsCatalogs and SupportsSchemas then SplitQualifiedObjectName(QualifiedName, Catalog, Schema, ObjectName) else begin SL := TStringList.Create; try Catalog := ''; Schema := ''; ObjectName := QualifiedName; ExtractStrings(['.'], [' '], PChar(QualifiedName), SL); case SL.Count of 0, 1: ; 2: begin if SupportsCatalogs then begin Catalog := SL.Strings[0]; if SupportsSchemas then Schema := SL.Strings[1] else ObjectName := SL.Strings[1]; end else if SupportsSchemas then begin Schema := SL.Strings[0]; ObjectName := SL.Strings[1]; end else ObjectName := SL.Strings[0]+'.'+SL.Strings[1]; end; 3: if SupportsCatalogs then begin Catalog := SL.Strings[0]; if SupportsSchemas then begin Schema := SL.Strings[1]; ObjectName := SL.Strings[2] end else ObjectName := SL.Strings[1]+'.'+SL.Strings[2]; end else if SupportsSchemas then begin Schema := SL.Strings[0]; ObjectName := SL.Strings[1]+'.'+SL.Strings[2]; end else ObjectName := SL.Strings[0]+'.'+SL.Strings[1]+'.'+SL.Strings[2]; else if SupportsCatalogs then begin Catalog := SL.Strings[0]; if SupportsSchemas then begin Schema := SL.Strings[1]; for i := 2 to SL.Count-1 do if i = 2 then ObjectName := SL.Strings[i] else ObjectName := ObjectName+'.'+SL.Strings[i]; end else begin ObjectName := ''; for i := 2 to SL.Count-1 do if I = 2 then ObjectName := SL.Strings[i] else ObjectName := ObjectName+'.'+SL.Strings[i]; end; end else if SupportsSchemas then begin Schema := SL.Strings[0]; for i := 1 to SL.Count-1 do if i = 1 then ObjectName := SL.Strings[i] else ObjectName := ObjectName+'.'+SL.Strings[i]; end else for i := 0 to SL.Count-1 do if I = 0 then ObjectName := SL.Strings[i] else ObjectName := ObjectName+'.'+SL.Strings[i]; end; finally SL.Free; end; end; end; {** Assigns a Statement value from a TParam @param Index the index of Statement.SetXxxx(ColumnIndex, xxx); @param Statement the PrepredStatement where the values have been assigned @param Param the TParam where the value is assigned from } procedure SetStatementParam(Index: Integer; Statement: IZPreparedStatement; Param: TParam); var Stream: TStream; TempBytes: TByteDynArray; {$IFDEF WITH_ASBYTES}Bts: TBytes;{$ENDIF} {$IFDEF WITHOUT_VARBYTESASSTRING}V: Variant;{$ENDIF} begin if Param.IsNull then Statement.SetNull(Index, ConvertDatasetToDbcType(Param.DataType)) else begin case Param.DataType of ftBoolean: Statement.SetBoolean(Index, Param.AsBoolean); ftSmallInt{$IFDEF WITH_FTSHORTINT}, ftShortInt{$ENDIF}: Statement.SetShort(Index, Param.AsSmallInt); ftInteger, ftAutoInc{$IFDEF WITH_FTBYTE}, ftByte{$ENDIF}: Statement.SetInt(Index, Param.AsInteger); ftFloat{$IFDEF WITH_FTEXTENDED}, ftExtended{$ENDIF}: Statement.SetDouble(Index, Param.AsFloat); {$IFDEF WITH_FTLONGWORD} ftLongWord: Statement.SetInt(Index, Integer(Param.AsLongWord)); {$ENDIF} ftLargeInt: Statement.SetLong(Index, StrToInt64(Param.AsString)); ftCurrency, ftBCD: Statement.SetBigDecimal(Index, Param.AsCurrency); ftString, ftFixedChar: Statement.SetString(Index, Param.AsString); {$IFDEF WITH_FTWIDESTRING} ftWideString: Statement.SetUnicodeString(Index, Param.AsWideString); {$ENDIF} ftBytes, ftVarBytes{$IFDEF WITH_FTGUID}, ftGuid{$ENDIF}: begin {$IFDEF WITH_ASBYTES} Bts := Param.AsBytes; SetLength(TempBytes, High(Bts)+1); System.Move(PAnsichar(Bts)^, PAnsichar(TempBytes)^, High(Bts)+1); {$ELSE} {$IFDEF WITHOUT_VARBYTESASSTRING} V := Param.Value; TempBytes := V; {$ELSE} TempBytes := StrToBytes(Param.AsString); {$ENDIF} {$ENDIF} Statement.SetBytes(Index, TempBytes); end; ftDate: Statement.SetDate(Index, Param.AsDate); ftTime: Statement.SetTime(Index, Param.AsTime); ftDateTime: Statement.SetTimestamp(Index, Param.AsDateTime); ftMemo: begin {EgonHugeist: On reading a Param as Memo the Stream reads Byte-wise on Changing to stUnicodeString/Delphi12Up a String is from Type wide/unicode so we have to give him back as Stream!} {$IFDEF UNICODE} Stream := Param.AsStream; {$ELSE} Stream := TStringStream.Create(Param.AsMemo); {$ENDIF} try Statement.SetAsciiStream(Index, Stream); finally Stream.Free; end; end; {$IFDEF WITH_WIDEMEMO} ftWideMemo: begin Stream := WideStringStream(Param.AsWideString); try Statement.SetUnicodeStream(Index, Stream); finally Stream.Free; end; end; {$ENDIF} ftBlob, ftGraphic: begin Stream := TStringStream.Create(Param.AsBlob); try Statement.SetBinaryStream(Index, Stream); finally Stream.Free; end; end; else raise EZDatabaseError.Create(SUnKnownParamDataType + IntToStr(Ord(Param.DataType))); end; end; end; initialization CommonTokenizer := TZGenericSQLTokenizer.Create; finalization CommonTokenizer := nil; end. ================================================ FILE: lib/zeosdbo/src/component/ZGroupedConnection.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Grouped Database Connection Component } { } { Originally written by una.bicicleta } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZGroupedConnection; interface {$I ZComponent.inc} uses SysUtils, Messages, Classes, ZDbcIntfs, DB,Forms, ZCompatibility, ZAbstractConnection, ZSequence, Dialogs, ZConnectionGroup {$IFDEF FPC}, LMessages{$ENDIF}; {$IFNDEF FPC} const CM_ZCONNECTIONGROUPCHANGED = WM_USER + 100; const CM_ZCONNECTIONGROUPCHANGE = WM_USER + 101; {$ELSE} const CM_ZCONNECTIONGROUPCHANGED = LM_USER + 100; const CM_ZCONNECTIONGROUPCHANGE = LM_USER + 101; {$ENDIF} type TMsgZDbConnecitionChange = record Msg: Cardinal; Sender: TComponent; ZConnectionGroup: TZConnectionGroup; Result: Longint; end; {$HINTS OFF} type TZGroupedConnection = class(tZAbstractConnection) protected FZConnectionGroup: TZConnectionGroup; FZConnectionGroupLink: TZConnectionGroupLink; procedure SetConnectionGroup(Value: TZConnectionGroup); procedure Notification(AComponent: TComponent; Operation: TOperation); override; private function getUser: string; function getPassword: string; function getHostName: string; function getDatabase: string; function GetLibLocation: String; //function getCatalog: string; procedure DoZConnectionGroupChange(Sender: TObject); procedure ParentZConnectionGroupChange(var Msg: TMessage); published property ConnectionGroup: TZConnectionGroup read FZConnectionGroup write SetConnectionGroup; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; end; {$HINTS ON} implementation procedure InternalZConnectionGroupChanged(AControl: TComponent; AZConnectionGroup: TZConnectionGroup); var Msg: TMsgZDbConnecitionChange; begin Msg.Msg := CM_ZCONNECTIONGROUPCHANGED; Msg.Sender := AControl; Msg.ZConnectionGroup := AZConnectionGroup; Msg.Result := 0; //AControl.Broadcast(Msg); end; // === { TZGroupedConnection } ============================================= constructor TZGroupedConnection .Create(AOwner: TComponent); begin inherited Create(AOwner); FZConnectionGroupLink := TZConnectionGroupLink.Create; FZConnectionGroupLink.OnChange := DoZConnectionGroupChange; end; destructor TZGroupedConnection .Destroy; begin FZConnectionGroupLink.Free; inherited Destroy; end; procedure TZGroupedConnection .DoZConnectionGroupChange(Sender: TObject); begin if (Sender is TZConnectionGroup) then begin FURL.UserName := (Sender as TZConnectionGroup).User; FURL.Protocol := (Sender as TZConnectionGroup).Protocol; FURL.Password := (Sender as TZConnectionGroup).Password; FURL.HostName := (Sender as TZConnectionGroup).HostName; FURL.Database := (Sender as TZConnectionGroup).Database; FURL.LibLocation := (Sender as TZConnectionGroup).LibraryLocation; end; end; procedure TZGroupedConnection .ParentZConnectionGroupChange(var Msg: TMessage); begin InternalZConnectionGroupChanged(Self, FZConnectionGroup); end; procedure TZGroupedConnection .Notification(AComponent: TComponent; Operation: TOperation); begin inherited Notification(AComponent, Operation); if (Operation = opRemove) then begin if (AComponent is TDataset) then UnregisterDataSet(TDataset(AComponent)); if (AComponent is TZSequence) then UnregisterSequence(TZSequence(AComponent)); if (AComponent = FZConnectionGroup) then FZConnectionGroup := nil; end; end; procedure TZGroupedConnection .SetConnectionGroup(Value: TZConnectionGroup); begin if FZConnectionGroup<>nil then FZConnectionGroup.UnRegisterChanges(FZConnectionGroupLink); FZConnectionGroup := Value; if Value <> nil then begin FZConnectionGroup.RegisterChanges(FZConnectionGroupLink); FURL.UserName := FZConnectionGroup.User; FURL.Protocol := FZConnectionGroup.Protocol; FURL.Password := FZConnectionGroup.Password; FURL.HostName := FZConnectionGroup.HostName; FURL.Database := FZConnectionGroup.Database; FURL.LibLocation := FZConnectionGroup.LibraryLocation; end; InternalZConnectionGroupChanged(Self, Value); end; function TZGroupedConnection .getUser: string; begin if FZConnectionGroup <> nil then begin FURL.UserName := FZConnectionGroup.User; Result := FURL.UserName; end else FURL.UserName := ''; end; { function TZGroupedConnection .getProtocol: string; begin if FZConnectionGroup <> nil then begin FProtocol := FZConnectionGroup.Protocol; Result := FProtocol; end else FProtocol := ''; end; } function TZGroupedConnection .getPassword: string; begin if FZConnectionGroup <> nil then begin FURL.Password := FZConnectionGroup.Password; Result := FURL.Password; end else FURL.Password := ''; end; function TZGroupedConnection .getHostName: string; begin if FZConnectionGroup <> nil then begin FURL.HostName := FZConnectionGroup.HostName; Result := FURL.HostName; end else FURL.HostName := ''; end; function TZGroupedConnection .getDatabase: string; begin if FZConnectionGroup <> nil then begin FURL.Database := FZConnectionGroup.Database; Result := FURL.Database; end else FURL.Database := ''; end; function TZGroupedConnection.GetLibLocation: String; begin if FZConnectionGroup <> nil then begin FURL.LibLocation := FZConnectionGroup.LibraryLocation; Result := FURL.LibLocation; end else FURL.LibLocation := ''; end; { function TZGroupedConnection .getCatalog: string; begin if FZConnectionGroup <> nil then begin FCatalog := FZConnectionGroup.Catalog; Result := FCatalog; end else FCatalog := ''; end; } end. ================================================ FILE: lib/zeosdbo/src/component/ZIBEventAlerter.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Interbase Database Connectivity Classes } { } { Copyright (c) 1999-2003 Zeos Development Group } { Written by Sergey Merkuriev } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZIBEventAlerter; {$I ZComponent.inc} interface uses SysUtils, Classes, {$IF defined(MSWINDOWS)and not defined(FPC)} Windows, {$IFEND} ZDbcInterbase6, ZConnection, ZDbcIntfs, ZPlainFirebirdDriver, ZPlainFirebirdInterbaseConstants; type TEventAlert = procedure(Sender: TObject; EventName: string; EventCount: longint; var CancelAlerts: boolean) of object; TErrorEvent = procedure(Sender: TObject; ErrorCode: integer) of object; TZIBEventAlerter = class(TComponent) private FEvents: TStrings; FOnEventAlert: TEventAlert; FThreads: TList; FNativeHandle: PISC_DB_HANDLE; ThreadException: boolean; FConnection: TZConnection; FOnError: TErrorEvent; FAutoRegister: boolean; FRegistered: boolean; procedure SetConnection(Value: TZConnection); procedure SetEvents(Value: TStrings); function GetRegistered: boolean; procedure SetRegistered(const Value: boolean); function GetPlainDriver: IZInterbasePlainDriver; protected { Protected declarations } function GetNativeHandle: PISC_DB_HANDLE; virtual; procedure EventChange(Sender: TObject); virtual; procedure ThreadEnded(Sender: TObject); virtual; procedure Notification(AComponent: TComponent; Operation: TOperation); override; public { Public declarations } constructor Create(AOwner: TComponent); override; destructor Destroy; override; procedure RegisterEvents; virtual; procedure UnRegisterEvents; virtual; property NativeHandle: PISC_DB_HANDLE read GetNativeHandle; property PlainDriver: IZInterbasePlainDriver read GetPlainDriver; procedure SetAutoRegister(const Value: boolean); function GetAutoRegister: boolean; published { Published declarations } property AutoRegister: boolean read GetAutoRegister write SetAutoRegister; property Connection: TZConnection read FConnection write SetConnection; property Events: TStrings read FEvents write SetEvents; property Registered: boolean read GetRegistered write SetRegistered; property OnEventAlert: TEventAlert read FOnEventAlert write FOnEventAlert; property OnError: TErrorEvent read FOnError write FOnError; end; implementation uses SyncObjs; const IB_MAX_EVENT_BLOCK = 15; // maximum events handled per block by InterBase IB_MAX_EVENT_LENGTH = 64; // maximum event name length threadvar FStatusVector: TARRAY_ISC_STATUS; type { TIBEventThread } TIBEventThread = class(TThread) private // IB API call parameters WhichEvent: integer; EventID: ISC_LONG; EventBuffer: PAnsiChar; EventBufferLen: Short; ResultBuffer: PAnsiChar; // Local use variables Signal: TSimpleEvent; EventsReceived, FirstTime: boolean; EventGroup, EventCount: integer; Parent: TZIBEventAlerter; FExceptObject: TObject; FExceptAddr: Pointer; FCancelAlerts: boolean; protected procedure Execute; override; procedure SignalEvent; virtual; procedure SignalTerminate; virtual; procedure RegisterEvents; virtual; procedure UnRegisterEvents; virtual; procedure QueueEvents; virtual; procedure SQueEvents; procedure ProcessEvents; virtual; procedure DoEvent; procedure DoHandleException; function HandleException: boolean; virtual; procedure UpdateResultBuffer(Length: UShort; Updated: PAnsiChar); public constructor Create(Owner: TZIBEventAlerter; EventGrp: integer; TermEvent: TNotifyEvent); virtual; destructor Destroy; override; end; Tsib_event_block = function(EventBuffer, ResultBuffer: PPAnsiChar; IDCount: UShort; Event1, Event2, Event3, Event4, Event5, Event6, Event7, Event8, Event9, Event10, Event11, Event12, Event13, Event14, Event15: PAnsiChar): ISC_LONG; cdecl; function TZIBEventAlerter.GetNativeHandle: PISC_DB_HANDLE; begin Result := (FConnection.DbcConnection as IZInterbase6Connection).GetDBHandle; end; function StatusVector: PISC_STATUS; begin Result := @FStatusVector; end; function StatusVectorArray: TARRAY_ISC_STATUS; begin Result := FStatusVector; end; { TZIBEventAlerter } constructor TZIBEventAlerter.Create(AOwner: TComponent); begin inherited Create(AOwner); ThreadException := False; FOnEventAlert := nil; FNativeHandle := nil; FConnection := nil; FAutoRegister := False; FEvents := TStringList.Create; with TStringList(FEvents) do begin Sorted := True; // dupIgnore only works when the TStringList is sorted OnChange := EventChange; // assign the routine which validates the event lenghts Duplicates := dupIgnore; // don't allow duplicate events end; FThreads := TList.Create; end; destructor TZIBEventAlerter.Destroy; begin try if Registered then UnRegisterEvents; except // silence any exceptions which might be raised // by UnRegisterEvents during destruction end; { If Assigned(FConnection) then FConnection.RemoveEventNotifier(Self); } FThreads.Free; FEvents.Free; inherited Destroy; end; procedure TZIBEventAlerter.Notification(AComponent: TComponent; Operation: TOperation); begin inherited Notification(AComponent, Operation); if (Operation = opRemove) and (AComponent = FConnection) then begin if Registered then UnRegisterEvents; FConnection := nil; end; end; // -> ms, 18/08/2004: // Modified so that now the DB connection will be made when events are registered // this is because the method UnregisterEvents of TIBEventThread needs a native // DB handle that can only be retrieved when DB connection is active. If the events // are registered correctly the DB connection must be established. If it is not // established this will be done here. This means that whenever events are registered // (by setting AutoRegister := True or calling RegisterEvents explicitly) and the // DB connection ist not established, this will be done here automatically (including // the retrieval of the native DB handle). Procedure TZIBEventAlerter.RegisterEvents; Var i: Integer; Begin If (not (csDesigning in ComponentState)) and (Assigned(FConnection)) Then Begin Try If (FThreads.Count = 0) Then Begin If (FEvents.Count > 0) Then Begin For i := 0 To ((FEvents.Count - 1) div IB_MAX_EVENT_BLOCK) Do FThreads.Add(TIBEventThread.Create(Self, i, ThreadEnded)); End; End; Finally FRegistered := FThreads.Count <> 0; If FRegistered Then Begin If not FConnection.Connected Then FConnection.Connect; FNativeHandle := GetNativeHandle; End; End; End; End; // RegisterEvents // -> ms, 18/08/2004: // Modified so that the native DB handle will now be retrieved by // method RegisterEvents. Retrieving it here caused an Exception // even if DB was connected. Procedure TZIBEventAlerter.SetConnection(Value: TZConnection); Var WasRegistered: boolean; Begin If (Value <> FConnection) Then Begin If (csDesigning in ComponentState) Then FConnection := Value Else Begin WasRegistered := Registered; If WasRegistered Then UnRegisterEvents; FConnection := Value; If WasRegistered Then RegisterEvents; End; End; End; // SetConnection procedure TZIBEventAlerter.SetEvents(Value: TStrings); begin FEvents.Assign(Value); end; procedure TZIBEventAlerter.SetRegistered(const Value: boolean); begin FRegistered := Value; if csDesigning in ComponentState then exit; if Value then RegisterEvents else UnRegisterEvents; end; procedure TZIBEventAlerter.UnregisterEvents; var i: integer; Temp: TIBEventThread; begin if csDesigning in ComponentState then exit; if (FThreads.Count > 0) then begin for i := (FThreads.Count - 1) downto 0 do begin Temp := TIBEventThread(FThreads[i]); FThreads.Delete(i); Temp.SignalTerminate; Temp.WaitFor; Temp.Free; end; end; FRegistered := FThreads.Count <> 0; end; function TZIBEventAlerter.GetPlainDriver: IZInterbasePlainDriver; begin Result := (FConnection.DbcConnection as IZInterbase6Connection).GetPlainDriver; end; { TIBEventThread } procedure EventCallback(P: Pointer; Length: Short; Updated: PAnsiChar); cdecl; begin if (Assigned(P) and Assigned(Updated)) then begin TIBEventThread(P).UpdateResultBuffer(Length, Updated); TIBEventThread(P).SignalEvent; end; end; procedure TIBEventThread.DoEvent; begin Parent.FOnEventAlert(Parent, Parent.FEvents[((EventGroup * IB_MAX_EVENT_BLOCK) + WhichEvent)], StatusVectorArray[WhichEvent], FCancelAlerts) end; procedure TIBEventThread.UpdateResultBuffer(Length: UShort; Updated: PAnsiChar); begin Move(Updated[0], ResultBuffer[0], Length); end; procedure TIBEventThread.QueueEvents; begin EventsReceived := False; Signal.ResetEvent; Synchronize(SQueEvents); end; procedure TIBEventThread.ProcessEvents; var i: integer; begin Parent.PlainDriver.isc_event_counts(StatusVector, EventBufferLen, EventBuffer, ResultBuffer); if (Assigned(Parent.FOnEventAlert) and (not FirstTime)) then begin FCancelAlerts := False; for i := 0 to (EventCount - 1) do begin if (StatusVectorArray[i] <> 0) then begin WhichEvent := i; Synchronize(DoEvent) end; end; end; FirstTime := False; end; procedure TIBEventThread.UnRegisterEvents; begin Parent.PlainDriver.isc_cancel_events(StatusVector, Parent.FNativeHandle, @EventID); Parent.PlainDriver.isc_free(EventBuffer); EventBuffer := nil; Parent.PlainDriver.isc_free(ResultBuffer); ResultBuffer := nil; end; procedure TIBEventThread.RegisterEvents; var sib_event_block: Tsib_event_block; function EBP(Index: integer): PAnsiChar; begin Inc(Index, (EventGroup * IB_MAX_EVENT_BLOCK)); if (Index > Parent.FEvents.Count) then Result := nil else {$IFDEF UNICODE} Result := PAnsiChar(AnsiString(Parent.FEvents[Index - 1])); {$ELSE} Result := PAnsiChar(Parent.FEvents[Index - 1]); {$ENDIF} end; begin EventBuffer := nil; ResultBuffer := nil; EventBufferLen := 0; FirstTime := True; EventCount := (Parent.FEvents.Count - (EventGroup * IB_MAX_EVENT_BLOCK)); if (EventCount > IB_MAX_EVENT_BLOCK) then EventCount := IB_MAX_EVENT_BLOCK; { if Parent.Connection.Protocol='interbase-6' then sib_event_block := Tsib_event_block(ZPlainInterbase6.isc_event_block) else if Parent.Connection.Protocol='firebird-1.0' then sib_event_block := Tsib_event_block(ZPlainFirebird10.isc_event_block) else if Parent.Connection.Protocol='firebird-1.5' then sib_event_block := Tsib_event_block(ZPlainFirebird15.isc_event_block) else if Parent.Connection.Protocol='firebirdd-1.5' then sib_event_block := Tsib_event_block(ZPlainFirebird15.isc_event_block) else if Parent.Connection.Protocol='firebird-2.0' then sib_event_block := Tsib_event_block(ZPlainFirebird20.isc_event_block) else if Parent.Connection.Protocol='firebirdd-2.0' then sib_event_block := Tsib_event_block(ZPlainFirebird20.isc_event_block) else if Parent.Connection.Protocol='firebird-2.1' then sib_event_block := Tsib_event_block(ZPlainFirebird21.isc_event_block) else if Parent.Connection.Protocol='firebirdd-2.1' then sib_event_block := Tsib_event_block(ZPlainFirebird21.isc_event_block) else sib_event_block := Tsib_event_block(ZPlainInterbase6.isc_event_block); } sib_event_block := Tsib_event_block(Parent.GetPlainDriver.GetFirebirdAPI.isc_event_block); EventBufferLen := sib_event_block(@EventBuffer, @ResultBuffer, EventCount, EBP(1), EBP(2), EBP(3), EBP(4), EBP(5), EBP(6), EBP(7), EBP(8), EBP(9), EBP(10), EBP(11), EBP(12), EBP(13), EBP(14), EBP(15)); end; procedure TIBEventThread.SignalEvent; begin EventsReceived := True; Signal.SetEvent; end; procedure TIBEventThread.SignalTerminate; begin if not Terminated then begin Terminate; Signal.SetEvent; end; end; procedure TIBEventThread.DoHandleException; begin SysUtils.ShowException(FExceptObject, FExceptAddr); end; function TIBEventThread.HandleException: boolean; begin if not Parent.ThreadException then begin Result := True; Parent.ThreadException := True; FExceptObject := ExceptObject; FExceptAddr := ExceptAddr; try if not (FExceptObject is EAbort) then Synchronize(DoHandleException); finally FExceptObject := nil; FExceptAddr := nil; end; end else Result := False; end; procedure TIBEventThread.Execute; begin RegisterEvents; QueueEvents; try repeat Signal.WaitFor(INFINITE); if EventsReceived then begin ProcessEvents; QueueEvents; end; until Terminated; ReturnValue := 0; except if HandleException then ReturnValue := 1 else ReturnValue := 0; end; end; {$WARNINGS OFF} constructor TIBEventThread.Create(Owner: TZIBEventAlerter; EventGrp: integer; TermEvent: TNotifyEvent); begin inherited Create(True); FCancelAlerts := False; Signal := TSimpleEvent.Create; Parent := Owner; EventGroup := EventGrp; OnTerminate := TermEvent; Resume; end; {$WARNINGS ON} destructor TIBEventThread.Destroy; begin try UnRegisterEvents; except if HandleException then ReturnValue := 1 else ReturnValue := 0; end; Signal.Free; inherited Destroy; end; procedure TZIBEventAlerter.EventChange(Sender: TObject); var i: integer; WasRegistered: boolean; begin WasRegistered := Registered; try if WasRegistered then UnRegisterEvents; TStringList(FEvents).OnChange := nil; try for i := (FEvents.Count - 1) downto 0 do begin if (FEvents[i] = EmptyStr) then begin FEvents.Delete(i); end else if (Length(FEvents[i]) > (IB_MAX_EVENT_LENGTH - 1)) then begin FEvents[i] := Copy(FEvents[i], 1, (IB_MAX_EVENT_LENGTH - 1)); end; end; finally TStringList(FEvents).OnChange := EventChange; end; finally if WasRegistered then RegisterEvents; end; end; function TZIBEventAlerter.GetRegistered: boolean; begin Result := FRegistered; end; procedure TZIBEventAlerter.ThreadEnded(Sender: TObject); var ThreadIdx: integer; begin if (Sender is TIBEventThread) then begin ThreadIdx := FThreads.IndexOf(Sender); if (ThreadIdx > -1) then FThreads.Delete(ThreadIdx); if (TIBEventThread(Sender).ReturnValue = 1) then begin if Registered then UnRegisterEvents; ThreadException := False; end end; end; procedure TZIBEventAlerter.SetAutoRegister(const Value: boolean); begin if FAutoRegister <> Value then begin FAutoRegister := Value; if FAutoRegister and (not Registered) and Assigned(FConnection) and FConnection.Connected then RegisterEvents; end; end; function TZIBEventAlerter.GetAutoRegister: boolean; begin Result := FAutoRegister; end; procedure TIBEventThread.SQueEvents; var Status: ISC_STATUS; begin Status := -999999; try Status := Parent.PlainDriver.isc_que_events(StatusVector, Parent.FNativeHandle, @EventID, EventBufferLen, EventBuffer, TISC_CALLBACK(@EventCallback), PVoid(Self)); except on E: Exception do if Status <> -999999 then if Assigned(Parent.OnError) then if E is EZSQLException then Parent.OnError(Parent, EZSQLException(E).ErrorCode) else Parent.OnError(Parent, 0); end; end; end. ================================================ FILE: lib/zeosdbo/src/component/ZPgEventAlerter.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Interbase Database Connectivity Classes } { } { Copyright (c) 1999-2003 Zeos Development Group } { Written by Sergey Merkuriev } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} {*********************************************************} { } { TZPgEventAlerter, Asynchronous notifying. } { By Ivan Rog - 2010 } { } { Contributors: } { Silvio Clecio - http://silvioprog.com.br } { } {*********************************************************} unit ZPgEventAlerter; interface {$I ZComponent.inc} uses SysUtils, Classes, ExtCtrls, ZDbcPostgreSql, ZPlainPostgreSqlDriver, ZConnection, ZAbstractRODataset; type TZPgNotifyEvent = procedure(Sender: TObject; Event: string; ProcessID: Integer; Payload: string) of object; { TZPgEventAlerter } TZPgEventAlerter = class (TComponent) private FActive : Boolean; FEvents : TStrings; FTimer : TTimer; FConnection: TZConnection; FNotifyFired : TZPgNotifyEvent; FProcessor : TZPgEventAlerter; //processor component - it will actually handle notifications received from DB //if processor is not assignet - component is handling notifications by itself FChildAlerters :TList; //list of TZPgEventAlerter that have our component attached as processor FChildEvents : TStrings; //list of actual events to be handled - gathered from events of all childe protected procedure SetActive (Value: Boolean); function GetInterval : Cardinal; procedure SetInterval (Value: Cardinal); procedure SetEvents (Value: TStrings); procedure SetConnection (Value: TZConnection); procedure TimerTick (Sender: TObject); procedure CheckEvents; procedure OpenNotify; procedure CloseNotify; procedure SetProcessor(Value: TZPgEventAlerter); procedure AddChildAlerter(Child: TZPgEventAlerter); procedure RemoveChildAlerter(Child: TZPgEventAlerter); procedure HandleNotify(Notify: PZPostgreSQLNotify); //launching OnNotify event fo Self and all child components (if event name is matched) procedure SetChildEvents (Value: TStrings); procedure RefreshEvents; //gathering all events from all child components (no duplicates), also propagating these events "down" to our processor public constructor Create (AOwner: TComponent); override; destructor Destroy; override; published property Connection: TZConnection read FConnection write SetConnection; property Active: Boolean read FActive write SetActive; property Events: TStrings read FEvents write SetEvents; property Interval: Cardinal read GetInterval write SetInterval default 250; property OnNotify: TZPgNotifyEvent read FNotifyFired write FNotifyFired; property Processor: TZPgEventAlerter read FProcessor write SetProcessor; //property to assign processor handling notifications property ChildEvents: TStrings read FChildEvents write SetChildEvents; //read onlu property to keep all events in one place end; implementation {$IFDEF WITH_UNITANSISTRINGS} uses AnsiStrings; {$ENDIF} { TZPgEventAlerter } constructor TZPgEventAlerter.Create(AOwner: TComponent); var I: Integer; begin inherited Create(AOwner); FEvents := TStringList.Create; FChildAlerters := TList.Create; FChildEvents := TStringList.Create; with TStringList(FEvents) do begin Duplicates := dupIgnore; end; with TStringList(FChildEvents) do begin Duplicates := dupIgnore; end; FTimer := TTimer.Create(Self); FTimer.Enabled := False; SetInterval(250); FTimer.OnTimer := TimerTick; FActive := False; if (csDesigning in ComponentState) and Assigned(AOwner) then for I := AOwner.ComponentCount - 1 downto 0 do if AOwner.Components[I] is TZConnection then begin FConnection := AOwner.Components[I] as TZConnection; Break; end; end; destructor TZPgEventAlerter.Destroy; begin if FProcessor = nil then CloseNotify; FEvents.Free; FTimer.Free; FChildAlerters.Free; FChildEvents.Free; inherited Destroy; end; procedure TZPgEventAlerter.SetInterval(Value: Cardinal); begin FTimer.Interval := Value; end; function TZPgEventAlerter.GetInterval: Cardinal; begin Result := FTimer.Interval; end; procedure TZPgEventAlerter.SetEvents(Value: TStrings); var I: Integer; begin FEvents.Assign(Value); for I := 0 to FEvents.Count -1 do FEvents[I] := Trim(FEvents[I]); RefreshEvents; //we must propagate events down to our processor end; procedure TZPgEventAlerter.SetActive(Value: Boolean); begin if FActive <> Value then begin if FProcessor = nil then begin if Value then begin RefreshEvents; OpenNotify; end else begin CloseNotify; end end else //we have processor attached - we dont need to open or close notifications begin FActive := Value; FProcessor.RefreshEvents; end; end; end; procedure TZPgEventAlerter.SetConnection(Value: TZConnection); begin if FConnection <> Value then begin if FProcessor = nil then //we are closing notifiers only whern there is no processor attached CloseNotify; FConnection := Value; end; end; procedure TZPgEventAlerter.TimerTick(Sender: TObject); begin if not FActive then FTimer.Enabled := False else begin if FProcessor <> nil then FTimer.Enabled := False else CheckEvents; end; end; procedure TZPgEventAlerter.OpenNotify; var I : Integer; Tmp : array [0..255] of AnsiChar; Handle : PZPostgreSQLConnect; ICon : IZPostgreSQLConnection; PlainDRV : IZPostgreSQLPlainDriver; Res: PGresult; begin if not Boolean(Pos('postgresql', FConnection.Protocol)) then raise EZDatabaseError.Create('Ivalid connection protocol. Need , get ' + FConnection.Protocol + '.'); if FActive then Exit; if not Assigned(FConnection) then Exit; if ((csLoading in ComponentState) or (csDesigning in ComponentState)) then Exit; if not FConnection.Connected then Exit; ICon := (FConnection.DbcConnection as IZPostgreSQLConnection); Handle := ICon.GetConnectionHandle; PlainDRV := ICon.GetPlainDriver; if Handle = nil then Exit; for I := 0 to FChildEvents.Count-1 do begin {$IFDEF WITH_STRPCOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrPCopy(Tmp, 'listen ' + AnsiString(FChildEvents.Strings[I])); Res := PlainDRV.ExecuteQuery(Handle, Tmp); if (PlainDRV.GetResultStatus(Res) <> TZPostgreSQLExecStatusType( PGRES_COMMAND_OK)) then begin PlainDRV.Clear(Res); Exit; end; PlainDRV.Clear(Res); end; FActive := True; FTimer.Enabled := True; end; procedure TZPgEventAlerter.CloseNotify; var I : Integer; tmp : array [0..255] of AnsiChar; Handle : PZPostgreSQLConnect; ICon : IZPostgreSQLConnection; PlainDRV : IZPostgreSQLPlainDriver; Res: PGresult; begin if not FActive then Exit; FActive := False; FTimer.Enabled := False; ICon := (FConnection.DbcConnection as IZPostgreSQLConnection); Handle := ICon.GetConnectionHandle; PlainDRV := ICon.GetPlainDriver; if Handle = nil then Exit; for I := 0 to FChildEvents.Count-1 do begin {$IFDEF WITH_STRPCOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrPCopy(Tmp, 'unlisten ' + AnsiString(FChildEvents.Strings[i])); Res := PlainDRV.ExecuteQuery(Handle, Tmp); if (PlainDRV.GetResultStatus(Res) <> TZPostgreSQLExecStatusType( PGRES_COMMAND_OK)) then begin PlainDRV.Clear(Res); Exit; end; PlainDRV.Clear(Res); end; end; procedure TZPgEventAlerter.CheckEvents; var Notify: PZPostgreSQLNotify; Handle : PZPostgreSQLConnect; ICon : IZPostgreSQLConnection; PlainDRV : IZPostgreSQLPlainDriver; begin ICon := (FConnection.DbcConnection as IZPostgreSQLConnection); Handle := ICon.GetConnectionHandle; if Handle=nil then begin FTimer.Enabled := False; FActive := False; Exit; end; if not FConnection.Connected then begin CloseNotify; Exit; end; PlainDRV := ICon.GetPlainDriver; if PlainDRV.ConsumeInput(Handle)=1 then begin while True do begin Notify := PlainDRV.Notifies(Handle); if Notify = nil then Break; HandleNotify(Notify); PlainDRV.FreeNotify(Notify); end; end; end; procedure TZPgEventAlerter.HandleNotify(Notify: PZPostgreSQLNotify); var i: Integer; CurrentChild: TZPgEventAlerter; begin if Assigned(FNotifyFired) and (FEvents.IndexOf(String(Notify{$IFDEF OLDFPC}^{$ENDIF}.relname)) <> -1) then FNotifyFired(Self, String(Notify{$IFDEF OLDFPC}^{$ENDIF}.relname), Notify{$IFDEF OLDFPC}^{$ENDIF}.be_pid,String(Notify{$IFDEF OLDFPC}^{$ENDIF}.payload)); for I := 0 to FChildAlerters.Count-1 do //propagating event to child listeners begin CurrentChild :=TZPgEventAlerter(FChildAlerters[i]); if CurrentChild.Active and (CurrentChild.ChildEvents.IndexOf(String(Notify{$IFDEF OLDFPC}^{$ENDIF}.relname)) <> -1) then //but only active ones CurrentChild.HandleNotify(Notify); end; end; procedure TZPgEventAlerter.SetProcessor(Value: TZPgEventAlerter); begin if FProcessor <> Value then begin if FProcessor <> nil then //remove assignment from old processor begin FProcessor.RemoveChildAlerter(Self); end; FProcessor := Value; if FProcessor <> nil then //add assignment to new processor begin if FProcessor.Connection <> FConnection then begin raise Exception.Create('Cannot set processor with different connection'); Exit; end; FProcessor.AddChildAlerter(Self); end; end; end; procedure TZPgEventAlerter.RefreshEvents; var i,j: integer; CurrentChild: TZPgEventAlerter; begin FChildEvents.Clear; for I := 0 to FChildAlerters.Count-1 do begin CurrentChild := TZPgEventAlerter(FChildAlerters[i]); if CurrentChild.Active or ((csLoading in ComponentState) or (csDesigning in ComponentState)) then begin //gathering vent namse from all childs for j := 0 to CurrentChild.ChildEvents.Count-1 do if FChildEvents.IndexOf(CurrentChild.ChildEvents.Strings[j]) = -1 then FChildEvents.Add(CurrentChild.ChildEvents.Strings[j]); end; end; for i := 0 to Events.Count-1 do if FChildEvents.IndexOf(Events.Strings[i]) = -1 then FChildEvents.Add(Events.Strings[i]); if FProcessor <> nil then //refreshing eventrs in our processor FProcessor.RefreshEvents else begin if Active then //refreshing listeners after change of events - to make sure we will listen for everything begin Active := False; Active := True; end; end; end; procedure TZPgEventAlerter.AddChildAlerter(Child: TZPgEventAlerter); begin FChildAlerters.Add(Child); RefreshEvents; end; procedure TZPgEventAlerter.RemoveChildAlerter(Child: TZPgEventAlerter); var i: integer; begin i := FChildAlerters.IndexOf(Child); FChildAlerters.Delete(i); RefreshEvents; end; procedure TZPgEventAlerter.SetChildEvents(Value: TStrings); begin Exit; end; end. ================================================ FILE: lib/zeosdbo/src/component/ZPropertyEditor.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Component Property Editors } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZPropertyEditor; interface {$I ZComponent.inc} {$IFDEF WITH_PROPERTY_EDITOR} uses Types, Classes, ZClasses, ZCompatibility, ZDbcIntfs, ZConnectionGroup, ZAbstractConnection, ZURL, {$IFDEF BDS4_UP} WideStrings, {$ENDIF} {$IFNDEF FPC} DesignIntf, DesignEditors; {$ELSE} PropEdits; {$ENDIF} type {** Implements the basic methods of the property editor. } TZStringProperty = class(TStringProperty) public function GetAttributes: TPropertyAttributes; override; procedure GetValueList(List: TStrings); virtual; abstract; procedure GetValues(Proc: TGetStrProc); override; function GetZComponent:TPersistent; virtual; end; {** Shows all Fields received from FieldDefs. } TZDataFieldPropertyEditor = class(TZStringProperty) public procedure GetValueList(List: TStrings); override; end; {** Shows all Fields received from IndexDefs - not used yet. } TZIndexFieldPropertyEditor = class(TZStringProperty) public procedure GetValueList(List: TStrings); override; end; {** Shows all Fields received from the MasterSource's DataSet.FieldDefs. } TZMasterFieldPropertyEditor = class(TZStringProperty) public procedure GetValueList(List: TStrings); override; end; {** Shows all Tables received from Connection.IZDatabaseMetadata. } TZTableNamePropertyEditor = class(TZStringProperty) public procedure GetValueList(List: TStrings); override; end; {** Shows all Procedures received from Connection.IZDatabaseMetadata. } TZProcedureNamePropertyEditor = class(TZStringProperty) public procedure GetValueList(List: TStrings); override; end; {** Shows all Sequences received from Connection.IZDatabaseMetadata. } TZSequenceNamePropertyEditor = class(TZStringProperty) public procedure GetValueList(List: TStrings); override; end; {** Implements a property editor for ZConnection.Protocol property. } TZProtocolPropertyEditor = class(TZStringProperty) public function GetValue: string; override; procedure GetValueList(List: TStrings); override; procedure SetValue(const Value: string); override; end; {** Implements a property editor for ZConnection.ClientCodePage property. } TZClientCodePagePropertyEditor = class(TZStringProperty) public function GetValue: string; override; procedure GetValueList(List: TStrings); override; procedure SetValue(const Value: string); override; end; {** Implements a property editor for ZConnection.Database property. } TZDatabasePropertyEditor = class(TZStringProperty) public function GetAttributes: TPropertyAttributes; override; function GetValue: string; override; procedure Edit; override; procedure GetValueList(List: TStrings); override; procedure SetValue(const Value: string); override; end; {** Implements a property editor for ZConnection.LibLocation property. } TZLibLocationPropertyEditor = class(TZStringProperty) public function GetAttributes: TPropertyAttributes; override; function GetValue: string; override; procedure Edit; override; procedure SetValue(const Value: string); override; end; // Modified by Una.Bicicleta 2010/10/31 {** Implements a property editor for ZConnectionGroup.Database property. } TZConnectionGroupPropertyEditor = class(TZStringProperty) public function GetAttributes: TPropertyAttributes; override; function GetValue: string; override; procedure Edit; override; procedure GetValueList(List: TStrings); override; procedure SetValue(const Value: string); override; end; {** Implements a property editor for ZGroupedConnection.Catalog property. } TZGroupedConnectionCatalogPropertyEditor = class(TZStringProperty) public function GetValue: string; override; procedure GetValueList(List: TStrings); override; procedure SetValue(const Value: string); override; end; {** Implements a property editor for ZGroupedConnection.LibLocation property. } {** added 2013/02/20 } TZConnectionGroupLibLocationPropertyEditor = class(TZStringProperty) public function GetAttributes: TPropertyAttributes; override; function GetValue: string; override; procedure Edit; override; procedure SetValue(const Value: string); override; end; ///////////////////////////////////////////////////////// {** Implements a property editor for ZConnection.Catalog property. } TZCatalogPropertyEditor = class(TZStringProperty) public function GetValue: string; override; procedure GetValueList(List: TStrings); override; procedure SetValue(const Value: string); override; end; {$IFDEF USE_METADATA} {** Shows all Catalogs received from Connection.IZDatabaseMetadata. } TZCatalogProperty = class(TZStringProperty) public procedure GetValueList(List: TStrings); override; end; {** Shows all Columns received from Connection.IZDatabaseMetadata. } TZColumnNamePropertyEditor = class(TZStringProperty) public procedure GetValueList(List: TStrings); override; end; {** Shows all Schemes received from Connection.IZDatabaseMetadata. } TZSchemaPropertyEditor = class(TZStringProperty) public procedure GetValueList(List: TStrings); override; end; {** Shows all Types received from Connection.IZDatabaseMetadata. } TZTypeNamePropertyEditor = class(TZStringProperty) public procedure GetValueList(List: TStrings); override; end; {$ENDIF} const CRLF = LineEnding; {$ENDIF} implementation {$IFDEF WITH_PROPERTY_EDITOR} uses SysUtils, Forms, Dialogs, Controls, DB, TypInfo, ZSysUtils, ZSelectSchema {$IFDEF USE_METADATA} , ZSqlMetadata {$ENDIF} {$IFNDEF UNIX} {$IFNDEF FPC} {$IFDEF ENABLE_ADO} , ZDbcAdoUtils {$ENDIF} {$ENDIF} {$ENDIF} {$IFDEF SHOW_WARNING} ,ZMessages {$ENDIF SHOW_WARNING} ; {$IFDEF FPC} procedure GetItemNames(FieldDefs: TFieldDefs; List: TStrings); overload; var i: Integer; begin List.Clear; for i := 0 to Pred(FieldDefs.Count) do List.Append(FieldDefs[i].Name); end; procedure GetItemNames(IndexDefs: TIndexDefs; List: TStrings); overload; var i: Integer; begin List.Clear; for i := 0 to Pred(IndexDefs.Count) do List.Append(IndexDefs[i].Name); end; {$ENDIF} { Returns the IndexDefs from Dataset } function GetIndexDefs(Component: TPersistent): TIndexDefs; var DataSet: TDataSet; begin DataSet := Component as TDataSet; Result := GetObjectProp(DataSet, 'IndexDefs') as TIndexDefs; if Assigned(Result) then begin Result.Updated := False; Result.Update; end; end; function IsEmpty(const s: string): Boolean; begin Result := Trim(s) = ''; end; { TZStringProperty } {** Gets a type of property attributes. @return a type of property attributes. } function TZStringProperty.GetAttributes: TPropertyAttributes; begin Result := [paValueList, paSortList]; end; {** Processes a list of list items. @param Proc a procedure to process the list items. } procedure TZStringProperty.GetValues(Proc: TGetStrProc); var i: Integer; Values: TStringList; begin Values := TStringList.Create; try GetValueList(Values); for i := 0 to Pred(Values.Count) do Proc(Values[i]); finally Values.Free; end; end; {** Gets the component that has the property. } function TZStringProperty.GetZComponent:TPersistent; begin Result:=GetComponent(0); end; { TZDataFieldPropertyEditor } {** Processes a list of list items. @param List the list to process the list items. } procedure TZDataFieldPropertyEditor.GetValueList(List: TStrings); begin try with (GetZComponent as TDataSet) do begin // Update the FieldDefs and return the Fieldnames FieldDefs.Updated := False; FieldDefs.Update; {$IFNDEF FPC} FieldDefs.GetItemNames(List); {$ELSE} GetItemNames(FieldDefs, List); {$ENDIF} end; except end; end; { TZIndexFieldPropertyEditor } procedure TZIndexFieldPropertyEditor.GetValueList(List: TStrings); begin {$IFNDEF FPC} GetIndexDefs(GetZComponent).GetItemNames(List); {$ELSE} GetItemNames(GetIndexDefs(GetZComponent), List); {$ENDIF} end; { TZMasterFieldPropertyEditor } procedure TZMasterFieldPropertyEditor.GetValueList(List: TStrings); var DataSource: TDataSource; begin DataSource := GetObjectProp(GetZComponent, 'MasterSource') as TDataSource; if (DataSource <> nil) and (DataSource.DataSet <> nil) then {$IFDEF WITH_WIDESTRINGS_GETFIELDNAMES} DataSource.DataSet.GetFieldNames(TWideStrings(List)); {$ELSE} DataSource.DataSet.GetFieldNames(List); {$ENDIF} end; { TZTableNamePropertyEditor } {** Processes a list of list items. @param List the list to process the list items. } procedure TZTableNamePropertyEditor.GetValueList(List: TStrings); var Connection: TZAbstractConnection; Metadata: IZDatabaseMetadata; ResultSet: IZResultSet; Schema, Tablename:String; IdentifierConvertor: IZIdentifierConvertor; Catalog: string; begin Connection := GetObjectProp(GetZComponent, 'Connection') as TZAbstractConnection; if Assigned(Connection) and Connection.Connected then begin Metadata := Connection.DbcConnection.GetMetadata; IdentifierConvertor := Metadata.GetIdentifierConvertor; Catalog := Connection.Catalog; Schema := ''; {$IFDEF USE_METADATA} if GetZComponent is TZSqlMetadata then begin Catalog := GetStrProp(GetZComponent, 'Catalog'); Schema := GetStrProp(GetZComponent, 'Schema'); {$IFDEF SHOW_WARNING} if not (IsEmpty(Catalog) and IsEmpty(Schema)) or (MessageDlg(SPropertyQuery + CRLF + SPropertyTables + CRLF + SPropertyExecute, mtWarning, [mbYes,mbNo], 0) = mrYes) then begin // continue end else exit; {$ENDIF} end; {$ENDIF} begin try // Look for the Tables of the defined Catalog and Schema ResultSet := Metadata.GetTables(Catalog, Schema, '', nil); while ResultSet.Next do begin TableName := ResultSet.GetStringByName('TABLE_NAME'); TableName := IdentifierConvertor.Quote(TableName); Schema := ResultSet.GetStringByName('TABLE_SCHEM'); (*if Connection.DbcConnection.GetMetadata.GetDatabaseInfo.SupportsCatalogsInTableDefinitions then if Catalog <> '' then if Schema <> '' then TableName := IdentifierConvertor.Quote(Catalog) + IdentifierConvertor.Quote(Schema) + '.' + TableName else TableName := {IdentifierConvertor.Quote(Catalog) + '.' + }TableName else if Schema <> '' then TableName := IdentifierConvertor.Quote(Schema) + '.' + TableName else TableName := TableName else if Schema <> '' then TableName := IdentifierConvertor.Quote(Schema) + '.' + TableName else TableName := TableName;*) if Schema <> '' then TableName := IdentifierConvertor.Quote(Schema) + '.' + TableName; if Catalog <> '' then TableName := IdentifierConvertor.Quote(Catalog) + '.' + TableName; List.Add(TableName); end; finally ResultSet.Close; end; end; end; end; { TZProcedureNamePropertyEditor } {** Processes a list of list items. @param List the list to process the list items. } procedure TZProcedureNamePropertyEditor.GetValueList(List: TStrings); var Connection: TZAbstractConnection; Metadata: IZDatabaseMetadata; IdentifierConvertor: IZIdentifierConvertor; ResultSet: IZResultSet; Catalog, Schema: string; ProcedureName: string; procedure ExtractOverload(OverloadSeparator: String); var I: Integer; SL: TStrings; begin SL := TStringList.Create; PutSplitString(SL, ProcedureName, OverloadSeparator); if SL.Count > 1 then begin SL.Delete(SL.Count -1); ProcedureName := ''; for i := 0 to SL.Count -1 do if ProcedureName = '' then ProcedureName := ProcedureName + SL[i] else ProcedureName := ProcedureName +OverloadSeparator+ SL[i]; //don't forget to give the delimiter back too end; end; begin Connection := GetObjectProp(GetZComponent, 'Connection') as TZAbstractConnection; if Assigned(Connection) and Connection.Connected then begin Metadata := Connection.DbcConnection.GetMetadata; IdentifierConvertor := Metadata.GetIdentifierConvertor; Catalog := Connection.Catalog; Schema := ''; {$IFDEF USE_METADATA} if GetZComponent is TZSqlMetadata then begin Catalog := GetStrProp(GetZComponent, 'Catalog'); Schema := GetStrProp(GetZComponent, 'Schema'); {$IFDEF SHOW_WARNING} if not (IsEmpty(Catalog) and IsEmpty(Schema)) or (MessageDlg(SPropertyQuery + CRLF + SPropertyProcedures + CRLF + SPropertyExecute, mtWarning, [mbYes,mbNo], 0) = mrYes) then begin // continue end else exit; {$ENDIF} end; {$ENDIF} begin try Metadata := Connection.DbcConnection.GetMetadata; // Look for the Procedures ResultSet := Metadata.GetProcedures(Catalog, Schema, ''); while ResultSet.Next do begin ProcedureName := ResultSet.GetStringByName('PROCEDURE_NAME'); if ( not Metadata.GetDatabaseInfo.SupportsOverloadPrefixInStoredProcedureName ) then if not ( StartsWith(ProcedureName, MetaData.GetDatabaseInfo.GetIdentifierQuoteString) or EndsWith(ProcedureName, MetaData.GetDatabaseInfo.GetIdentifierQuoteString) or (Pos('.', ProcedureName) > 0) ) then ProcedureName := IdentifierConvertor.Quote(ProcedureName); Schema := ResultSet.GetStringByName('PROCEDURE_SCHEM'); if Metadata.GetDatabaseInfo.SupportsCatalogsInProcedureCalls then if Catalog <> '' then if Schema <> '' then ProcedureName := IdentifierConvertor.Quote(Catalog) +'.'+ IdentifierConvertor.Quote(Schema) + '.' + ProcedureName else ProcedureName := ProcedureName else if Schema <> '' then ProcedureName := IdentifierConvertor.Quote(Schema) + '.' + ProcedureName else ProcedureName := ProcedureName else if Schema <> '' then ProcedureName := IdentifierConvertor.Quote(Schema) + '.' + ProcedureName else ProcedureName := ProcedureName; List.Add(ProcedureName); end; finally ResultSet.Close; end; end; end; end; { TZSequenceNamePropertyEditor } {** Gets a selected string value. @return a selected string value. } procedure TZSequenceNamePropertyEditor.GetValueList(List: TStrings); var Connection: TZAbstractConnection; Metadata: IZDatabaseMetadata; ResultSet: IZResultSet; {$IFDEF USE_METADATA} Catalog, Schema: string; {$ENDIF} begin Connection := GetObjectProp(GetZComponent, 'Connection') as TZAbstractConnection; if Assigned(Connection) and Connection.Connected then begin {$IFDEF USE_METADATA} if GetZComponent is TZSqlMetadata then begin Catalog := GetStrProp(GetZComponent, 'Catalog'); Schema := GetStrProp(GetZComponent, 'Schema'); {$IFDEF SHOW_WARNING} if not (IsEmpty(Catalog) and IsEmpty(Schema)) or (MessageDlg(SPropertyQuery + CRLF + SPropertySequences + CRLF + SPropertyExecute, mtWarning, [mbYes,mbNo], 0) = mrYes) then {$ENDIF} try Metadata := Connection.DbcConnection.GetMetadata; // Look for the Procedures of the defined Catalog and Schema ResultSet := Metadata.GetSequences(Catalog, Schema, ''); while ResultSet.Next do List.Add(ResultSet.GetStringByName('SEQUENCE_NAME')); finally ResultSet.Close; end; end else {$ENDIF} begin try Metadata := Connection.DbcConnection.GetMetadata; // Look for the Procedures ResultSet := Metadata.GetSequences(Connection.Catalog, '', ''); while ResultSet.Next do if ResultSet.GetStringByName('SEQUENCE_SCHEM') <> '' then List.Add(ResultSet.GetStringByName('SEQUENCE_SCHEM')+ '.'+ResultSet.GetStringByName('SEQUENCE_NAME')) else List.Add(ResultSet.GetStringByName('SEQUENCE_NAME')); finally ResultSet.Close; end; end; end; end; { TZProtocolPropertyEditor } {** Gets a selected string value. @return a selected string value. } function TZProtocolPropertyEditor.GetValue: string; begin Result := GetStrValue; end; {** Sets a new selected string value. @param Value a new selected string value. } procedure TZProtocolPropertyEditor.SetValue(const Value: string); begin SetStrValue(Value); if GetZComponent is TZAbstractConnection then (GetZComponent as TZAbstractConnection).Connected := False; end; {** Processes a list of list items. @param List the list to process the list items. } procedure TZProtocolPropertyEditor.GetValueList(List: TStrings); var I, J: Integer; Drivers: IZCollection; Protocols: TStringDynArray; begin Drivers := DriverManager.GetDrivers; Protocols := nil; for I := 0 to Drivers.Count - 1 do begin Protocols := (Drivers[I] as IZDriver).GetSupportedProtocols; for J := Low(Protocols) to High(Protocols) do List.Append(Protocols[J]); end; end; {TZClientCodePagePropertyEditor -> EgonHugeist 19.01.2012} {** Sets a new selected string value. @param Value a new selected string value. } function TZClientCodePagePropertyEditor.GetValue: string; begin Result := GetStrValue; end; {** Processes a list of list items. @param List the list to process the list items. } procedure TZClientCodePagePropertyEditor.GetValueList(List: TStrings); var Connection: TZAbstractConnection; I: Integer; SDyn: TStringDynArray; Url: TZURL; begin if GetZComponent is TZAbstractConnection then Connection := (GetZComponent as TZAbstractConnection) else Connection := nil; if Assigned(Connection) then begin if Connection.Protocol = '' then List.Append('No Protocol selected!') else begin Url := TZURL.Create; Url.Protocol := Connection.Protocol; SDyn := DriverManager.GetDriver(Url.URL).GetSupportedClientCodePages(Url, {$IFNDEF UNICODE}Connection.AutoEncodeStrings, {$ENDIF}True, Connection.ControlsCodePage); Url.Free; for i := 0 to high(SDyn) do List.Append(SDyn[i]); TStringList(List).Sort; end; end; end; {** Sets a new selected string value. @param Value a new selected string value. } procedure TZClientCodePagePropertyEditor.SetValue(const Value: string); begin SetStrValue(Value); if GetZComponent is TZAbstractConnection then (GetZComponent as TZAbstractConnection).Connected := False; end; { TZDatabasePropertyEditor } {** Gets a type of property attributes. @return a type of property attributes. } function TZDatabasePropertyEditor.GetAttributes: TPropertyAttributes; begin if GetZComponent is TZAbstractConnection then begin if ((GetZComponent as TZAbstractConnection).Protocol = 'mssql') or ((GetZComponent as TZAbstractConnection).Protocol = 'sybase') then Result := inherited GetAttributes else Result := [paDialog]; end; end; {** Gets a selected string value. @return a selected string value. } function TZDatabasePropertyEditor.GetValue: string; begin Result := GetStrValue; end; {** Sets a new selected string value. @param Value a new selected string value. } procedure TZDatabasePropertyEditor.SetValue(const Value: string); begin SetStrValue(Value); if GetZComponent is TZAbstractConnection then (GetZComponent as TZAbstractConnection).Connected := False; end; {** Processes a list of list items. @param List the list to process the list items. } procedure TZDatabasePropertyEditor.GetValueList(List: TStrings); var DbcConnection: IZConnection; Url: string; begin if GetZComponent is TZAbstractConnection then try URL := (GetZComponent as TZAbstractConnection).GetURL; (GetZComponent as TZAbstractConnection).ShowSqlHourGlass; try DbcConnection := DriverManager.GetConnectionWithParams(Url, (GetZComponent as TZAbstractConnection).Properties); with DbcConnection.GetMetadata.GetCatalogs do try while Next do List.Append(GetStringByName('TABLE_CAT')); finally Close; end; finally (GetZComponent as TZAbstractConnection).HideSqlHourGlass; end; except // raise; end; end; {** Brings up the proper database property editor dialog. } procedure TZDatabasePropertyEditor.Edit; var OD: TOpenDialog; begin if GetZComponent is TZAbstractConnection then begin if ((GetZComponent as TZAbstractConnection).Protocol = 'mssql') or ((GetZComponent as TZAbstractConnection).Protocol = 'sybase') then inherited {$IFNDEF UNIX} {$IFNDEF FPC} {$IFDEF ENABLE_ADO} else if ((GetZComponent as TZAbstractConnection).Protocol = 'ado') then (GetZComponent as TZAbstractConnection).Database := PromptDataSource(Application.Handle, (GetZComponent as TZAbstractConnection).Database) {$ENDIF} {$ENDIF} {$ENDIF} else begin OD := TOpenDialog.Create(nil); try OD.InitialDir := ExtractFilePath((GetZComponent as TZAbstractConnection).Database); if OD.Execute then (GetZComponent as TZAbstractConnection).Database := OD.FileName; finally OD.Free; end; end; end else inherited; end; { TZLibLocationPropertyEditor } {** Gets a type of property attributes. @return a type of property attributes. } function TZLibLocationPropertyEditor.GetAttributes: TPropertyAttributes; begin if GetZComponent is TZAbstractConnection then Result := [paDialog]; end; {** Gets a selected string value. @return a selected string value. } function TZLibLocationPropertyEditor.GetValue: string; begin Result := GetStrValue; end; {** Sets a new selected string value. @param Value a new selected string value. } procedure TZLibLocationPropertyEditor.SetValue(const Value: string); begin SetStrValue(Value); if GetZComponent is TZAbstractConnection then (GetZComponent as TZAbstractConnection).Connected := False; end; {** Brings up the proper LibLocation property editor dialog. } procedure TZLibLocationPropertyEditor.Edit; var OD: TOpenDialog; begin if GetZComponent is TZAbstractConnection then begin OD := TOpenDialog.Create(nil); try OD.InitialDir := ExtractFilePath((GetZComponent as TZAbstractConnection).LibLocation); if OD.Execute then (GetZComponent as TZAbstractConnection).LibLocation := OD.FileName; finally OD.Free; end; end else inherited; end; { TZCatalogPropertyEditor } {** Gets a selected string value. @return a selected string value. } function TZCatalogPropertyEditor.GetValue: string; begin Result := GetStrValue; end; {** Sets a new selected string value. @param Value a new selected string value. } procedure TZCatalogPropertyEditor.SetValue(const Value: string); begin SetStrValue(Value); end; {** Processes a list of list items. @param List the list to process the list items. } procedure TZCatalogPropertyEditor.GetValueList(List: TStrings); var DbcConnection: IZConnection; Url: string; begin if GetZComponent is TZAbstractConnection then try URL := (GetZComponent as TZAbstractConnection).GetURL; (GetZComponent as TZAbstractConnection).ShowSqlHourGlass; try DbcConnection := DriverManager.GetConnectionWithParams(Url, (GetZComponent as TZAbstractConnection).Properties); if Assigned(DbcConnection) then if DbcConnection.GetMetadata.GetDatabaseInfo.SupportsCatalogsInDataManipulation then with DbcConnection.GetMetadata.GetCatalogs do try while Next do List.Append(GetStringByName('TABLE_CAT')); finally Close; end else if DbcConnection.GetMetadata.GetDatabaseInfo.SupportsSchemasInDataManipulation then with DbcConnection.GetMetadata.GetSchemas do try while Next do List.Append(GetStringByName('TABLE_SCHEM')); finally Close; end; finally (GetZComponent as TZAbstractConnection).HideSqlHourGlass; end; except // raise; end; end; {$IFDEF USE_METADATA} { TZCatalogProperty } {** Processes a list of list items. @param List the list to process the list items. } procedure TZCatalogProperty.GetValueList(List: TStrings); var Connection: TZAbstractConnection; Metadata: IZDatabaseMetadata; ResultSet: IZResultSet; begin Connection := GetObjectProp(GetZComponent, 'Connection') as TZAbstractConnection; if Assigned(Connection) and Connection.Connected then try Metadata := Connection.DbcConnection.GetMetadata; ResultSet := Metadata.GetCatalogs; while ResultSet.Next do List.Add(ResultSet.GetStringByName('TABLE_CAT')); finally ResultSet.Close; end; end; { TZColumnNamePropertyEditor } {** Processes a list of list items. @param List the list to process the list items. } procedure TZColumnNamePropertyEditor.GetValueList(List: TStrings); var Connection: TZAbstractConnection; Metadata: IZDatabaseMetadata; ResultSet: IZResultSet; Catalog, Schema, TableName: string; begin Connection := GetObjectProp(GetZComponent, 'Connection') as TZAbstractConnection; if Assigned(Connection) and Connection.Connected then begin Catalog := GetStrProp(GetZComponent, 'Catalog'); Schema := GetStrProp(GetZComponent, 'Schema'); TableName := GetStrProp(GetZComponent, 'TableName'); {$IFDEF SHOW_WARNING} if not IsEmpty(TableName) or not (IsEmpty(Schema) and IsEmpty(Schema)) or (MessageDlg(SPropertyQuery + CRLF + SPropertyTables + CRLF + SPropertyExecute, mtWarning, [mbYes,mbNo], 0) = mrYes) then {$ENDIF} try Metadata := Connection.DbcConnection.GetMetadata; // Look for the Columns of the defined Catalog, Schema and TableName ResultSet := Metadata.GetColumns(Catalog, Schema, TableName, ''); while ResultSet.Next do if List.IndexOf(ResultSet.GetStringByName('COLUMN_NAME')) = -1 then List.Add(ResultSet.GetStringByName('COLUMN_NAME')); finally ResultSet.Close; end; end; end; { TZSchemaPropertyEditor } {** Processes a list of list items. @param List the list to process the list items. } procedure TZSchemaPropertyEditor.GetValueList(List: TStrings); var Connection: TZAbstractConnection; Metadata: IZDatabaseMetadata; ResultSet: IZResultSet; begin Connection := GetObjectProp(GetZComponent, 'Connection') as TZAbstractConnection; if Assigned(Connection) and Connection.Connected then try Metadata := Connection.DbcConnection.GetMetadata; ResultSet := Metadata.GetSchemas; while ResultSet.Next do List.Add(ResultSet.GetStringByName('TABLE_SCHEM')); finally ResultSet.Close; end; end; { TZTypeNamePropertyEditor } {** Processes a list of list items. @param List the list to process the list items. } procedure TZTypeNamePropertyEditor.GetValueList(List: TStrings); var Connection: TZAbstractConnection; Metadata: IZDatabaseMetadata; ResultSet: IZResultSet; begin Connection := GetObjectProp(GetZComponent, 'Connection') as TZAbstractConnection; if Assigned(Connection) and Connection.Connected then try Metadata := Connection.DbcConnection.GetMetadata; ResultSet := Metadata.GetTypeInfo; while ResultSet.Next do List.Add(ResultSet.GetStringByName('TYPE_NAME')); finally ResultSet.Close; end; end; //xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx { TZConnectionGroupCatalogPropertyEditor } function TZGroupedConnectionCatalogPropertyEditor.GetValue: string; begin Result := GetStrValue; end; procedure TZGroupedConnectionCatalogPropertyEditor.SetValue(const Value: string); begin SetStrValue(Value); end; procedure TZGroupedConnectionCatalogPropertyEditor.GetValueList(List: TStrings); var DbcConnection: IZConnection; Url: string; begin if GetZComponent is TZAbstractConnection then try URL := (GetZComponent as TZAbstractConnection).GetURL; (GetZComponent as TZAbstractConnection).ShowSqlHourGlass; try DbcConnection := DriverManager.GetConnectionWithParams(Url, (GetZComponent as TZAbstractConnection).Properties); with DbcConnection.GetMetadata.GetCatalogs do try while Next do List.Append(GetStringByName('TABLE_CAT')); finally Close; end; finally (GetZComponent as TZAbstractConnection).HideSqlHourGlass; end; except // raise; end; end; { TZConnectionGroupPropertyEditor } {** Gets a type of property attributes. @return a type of property attributes. } function TZConnectionGroupPropertyEditor.GetAttributes: TPropertyAttributes; begin if GetZComponent is TZConnectionGroup then begin if ((GetZComponent as TZConnectionGroup).Protocol = 'mssql') or ((GetZComponent as TZConnectionGroup).Protocol = 'sybase') then Result := inherited GetAttributes else Result := [paDialog]; end; end; {** Gets a selected string value. @return a selected string value. } function TZConnectionGroupPropertyEditor.GetValue: string; begin Result := GetStrValue; end; {** Sets a new selected string value. @param Value a new selected string value. } procedure TZConnectionGroupPropertyEditor.SetValue(const Value: string); begin SetStrValue(Value); // if GetZComponent is TZConnectionGroup then // (GetZComponent as TZConnectionGroup).Connected := False; end; {** Processes a list of list items. @param List the list to process the list items. } procedure TZConnectionGroupPropertyEditor.GetValueList(List: TStrings); var DbcConnection: IZConnection; begin if GetZComponent is TZConnectionGroup then try DbcConnection := (GetZComponent as TZAbstractConnection).DbcConnection; with DbcConnection.GetMetadata.GetCatalogs do try while Next do List.Append(GetStringByName('TABLE_CAT')); finally Close; end; except // raise; end; end; {** Brings up the proper database property editor dialog. } procedure TZConnectionGroupPropertyEditor.Edit; var OD: TOpenDialog; begin if GetZComponent is TZConnectionGroup then begin if ((GetZComponent as TZConnectionGroup).Protocol = 'mssql') or ((GetZComponent as TZConnectionGroup).Protocol = 'sybase') then inherited {$IFNDEF UNIX} {$IFNDEF FPC} {$IFDEF ENABLE_ADO} else if ((GetZComponent as TZConnectionGroup).Protocol = 'ado') then (GetZComponent as TZConnectionGroup).Database := PromptDataSource(Application.Handle, (GetZComponent as TZConnectionGroup).Database) {$ENDIF} {$ENDIF} {$ENDIF} else begin OD := TOpenDialog.Create(nil); try OD.InitialDir := ExtractFilePath((GetZComponent as TZConnectionGroup).Database); if OD.Execute then (GetZComponent as TZConnectionGroup).Database := OD.FileName; finally OD.Free; end; end; end else inherited; end; {** added 2013/02/20 } { TZConnectionGroupLibLocationPropertyEditor } {** Gets a type of property attributes. @return a type of property attributes. } function TZConnectionGroupLibLocationPropertyEditor.GetAttributes: TPropertyAttributes; begin if GetZComponent is TZConnectionGroup then Result := [paDialog]; end; {** Gets a selected string value. @return a selected string value. } function TZConnectionGroupLibLocationPropertyEditor.GetValue: string; begin Result := GetStrValue; end; {** Sets a new selected string value. @param Value a new selected string value. } procedure TZConnectionGroupLibLocationPropertyEditor.SetValue(const Value: string); begin SetStrValue(Value); //if GetZComponent is TZAbstractConnection then // (GetZComponent as TZAbstractConnection).Connected := False; end; {** Brings up the proper LibLocation property editor dialog. } procedure TZConnectionGroupLibLocationPropertyEditor.Edit; var OD: TOpenDialog; begin if GetZComponent is TZConnectionGroup then begin OD := TOpenDialog.Create(nil); try OD.InitialDir := ExtractFilePath((GetZComponent as TZConnectionGroup).LibraryLocation); if OD.Execute then (GetZComponent as TZConnectionGroup).LibraryLocation := OD.FileName; finally OD.Free; end; end else inherited; end; {$ENDIF} {$ENDIF} end. ================================================ FILE: lib/zeosdbo/src/component/ZQuerySQLEditor.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { SQL Monitor component } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZQuerySQLEditor; {$I ZComponent.inc} interface uses {$IFDEF MSWINDOWS} Windows, Messages, {$ENDIF} {$IFDEF FPC} LCLIntf, {$ENDIF} SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Graphtype, StdCtrls, ExtCtrls, ComCtrls, Buttons, ZDataset, Menus, ZMessages; //{$IFDEF USE_SYNEDIT} //, SynEdit, SynEditHighlighter, SynHighlighterSQL //{$IFDEF FPC} //, SynCompletion //{$ELSE} //, SynCompletionProposal //{$ENDIF} //{$ENDIF}; type { TZQuerySQLEditorForm } TZQuerySQLEditorForm = class(TForm) private mnuSave: TMenuItem; mnuLoad: TMenuItem; dlgOpen: TOpenDialog; PopupMenu1: TPopupMenu; dlgSave: TSaveDialog; btnOk: TBitBtn; btnCancel: TBitBtn; Panel2: TPanel; tbsSelect: TTabSheet; Panel1: TPanel; Splitter2: TSplitter; ListBoxRelations: TListBox; ListBoxFields: TListBox; Splitter1: TSplitter; Panel3: TPanel; lblAlias: TLabel; edtAlias: TEdit; btnGenerate: TButton; btnCheck: TButton; chkReplace: TCheckBox; btnTest: TButton; edtSelect: TMemo; //{$IFDEF USE_SYNEDIT} //edtSelect: TSynEdit; //SynSQLSyn1: TSynSQLSyn; //{$IFDEF FPC} //SynCompletion:TSynCompletion; //{$ELSE} //SynCompletion:TSynCompletionProposal; //{$ENDIF} //{$ELSE} //edtSelect: TMemo; //{$ENDIF} FDS: TZQuery; FSaveConnected: Boolean; procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure ListBoxRelationsDblClick(Sender: TObject); procedure ListBoxRelationsSelectionChange(Sender: TObject; User: boolean); procedure PageControl1Change(Sender: TObject); procedure ZeosQuerySQLEditorDestroy(Sender: TObject); procedure btnGenerateClick(Sender: TObject); procedure btnTestClick(Sender: TObject); procedure mnuLoadClick(Sender: TObject); procedure mnuSaveClick(Sender: TObject); procedure LoadTableList; procedure FillIdentifier; function ActiveEditor:TMemo; //function ActiveEditor:{$IFDEF USE_SYNEDIT} TSynEdit {$ELSE} TMemo {$ENDIF}; //{$IFDEF USE_SYNEDIT} //{$IFDEF FPC} //procedure ccComplete(var Value: ansistring; Shift: TShiftState); //procedure ccExecute(Sender: TObject); //{$ELSE} //procedure ccComplete(Sender: TObject; var Value: string; //Shift: TShiftState; Index: Integer; EndToken: Char); //procedure ccExecute(Kind: SynCompletionType; Sender: TObject; //var CurrentInput: string; var x, y: Integer; var CanExecute: Boolean); //{$ENDIF} //{$ENDIF} public PageControl1: TPageControl; constructor CreateEditor(ADS:TZQuery); end; var ZeosQuerySQLEditorForm: TZQuerySQLEditorForm; implementation uses ZSqlTestForm, ZDbcIntfs, ZCompatibility; const SQLDefaultFilter = 'SQL files (*.sql)|*.sql'; { TZeosROSQLEditor } constructor TZQuerySQLEditorForm.CreateEditor(ADS: TZQuery); begin inherited CreateNew(Application,0); Height := 613; Left := 315; Top := 142; TextHeight := 13; Width := 768; Position := poDesktopCenter; Caption := sFormEditor; OnClose := FormClose; OnDestroy := ZeosQuerySQLEditorDestroy; btnOk := TBitBtn.Create(self); with btnOk do begin Parent := self; Anchors := [akRight, akBottom]; Default := True; Height := 25; Kind := bkOk; Left := 593; ModalResult := mrOk; TabOrder := 3; TabStop := True; Top := 552; Width := 75; Caption := SButtonOk; end; btnCancel := TBitBtn.Create(self); with btnCancel do begin Parent := self; Anchors := [akRight, akBottom]; Default := True; Height := 25; Kind := bkCancel; Left := 677; ModalResult := mrCancel; TabOrder := 4; TabStop := True; Top := 552; Width := 75; Caption := SButtonCancel; end; btnGenerate := TButton.Create(self); with btnGenerate do begin Parent := self; Anchors := [akLeft,akBottom]; Caption := SButtonGenerate; Height := 25; Left := 8; OnClick := btnGenerateClick; TabOrder := 0; TabStop := True; Top := 552; Width := 75; end; btnCheck := TButton.Create(self); with btnCheck do begin Parent := self; Anchors := [akLeft,akBottom]; Caption := SButtonCheck; Enabled := False; Height := 25; Left := 88; TabOrder := 1; TabStop := True; Top := 552; Visible := False; Width := 75; end; btnTest := TButton.Create(self); with btnTest do begin Parent := self; Anchors := [akLeft,akBottom]; Caption := SButtonTest; Height := 25; Left := 168; OnClick := btnTestClick; TabOrder := 2; TabStop := True; Top := 552; Width := 75; end; dlgOpen := TOpenDialog.Create(self); with dlgOpen do begin FilterIndex :=0; Options := [ofEnableSizing,ofViewDetail]; Title := SDialogOpenTitle; Filter := SQLDefaultFilter; end; dlgSave := TSaveDialog.Create(self); with dlgSave do begin FilterIndex :=0; Options := [ofEnableSizing,ofViewDetail]; Title := SDialogSaveTitle; Filter := SQLDefaultFilter; end; mnuLoad := TMenuItem.Create(self); with mnuLoad do begin Caption := SMenuLoad; OnClick := mnuLoadClick; end; mnuSave := TMenuItem.Create(self); with mnuSave do begin Caption := SMenuSave; OnClick := mnuSaveClick; end; PopupMenu1 := TPopupMenu.Create(self); with PopupMenu1 do begin AutoPopup := true; Items.Add(mnuLoad); Items.Add(mnuSave); end; Panel2 := TPanel.Create(self); with Panel2 do begin Parent := self; Align := alTop; Anchors := [akTop,akLeft,akRight,akBottom]; FullRepaint := False; Height := 545; Left := 0; TabOrder := 5; TabStop := False; Top := 0; Width := 768; end; Splitter1 := TSplitter.Create(self); with Splitter1 do begin Parent := Panel2; Align := alRight; Anchors := [akTop,akRight,akBottom]; Height := 543; Left := 518; Top := 1; Width := 5; end; PageControl1 := TPageControl.Create(self); with PageControl1 do begin Parent := Panel2; Align := alClient; Anchors := [akTop,akLeft,akRight,akBottom]; Height := 543; Left := 1; OnChange := PageControl1Change; TabIndex := 0; TabOrder := 0; TabPosition := tpTop; TabStop := True; Top := 1; Width := 517; end; tbsSelect := TTabSheet.Create(self); with tbsSelect do begin Parent := PageControl1; Caption := STabSheetSelect; Height := 513; Left := 2; Top := 28; Width := 513; end; Panel1 := TPanel.Create(self); with Panel1 do begin Parent := Panel2; Align := alRight; Anchors := [akTop,akRight,akBottom]; FullRepaint := false; Height := 543; Left := 523; TabOrder := 1; TabStop := False; Top := 1; Width := 244; end; Splitter2 := TSplitter.Create(self); with Splitter2 do begin Parent := Panel1; Align := alBottom; Anchors := [akLeft,akRight,akBottom]; Cursor := crVSplit; Height := 9; Left := 1; Top := 271; Width := 242; end; ListBoxRelations := TListBox.Create(self); with ListBoxRelations do begin Parent := Panel1; Align := alClient; Anchors := [akTop,akLeft,akRight,akBottom]; Height := 198; ItemHeight := 13; Left := 1; OnDblClick := ListBoxRelationsDblClick; OnSelectionChange := ListBoxRelationsSelectionChange; TabOrder := 0; Top := 73; Width := 242 end; ListBoxFields := TListBox.Create(self); with ListBoxFields do begin Parent := Panel1; Align := alBottom; Anchors := [akLeft,akRight,akBottom]; Height := 262; ItemHeight := 13; Left := 1; MultiSelect := True; TabOrder := 1; Top := 280; Width := 242; end; Panel3 := TPanel.Create(self); with Panel3 do begin Parent := Panel1; Align := alTop; Anchors := [akTop,akLeft,akRight,akBottom]; BevelOuter := bvNone; FullRepaint := False; Height := 72; Left := 1; TabOrder := 2; TabStop := False; Top := 1; Width := 242; end; edtAlias := TEdit.Create(self); with edtAlias do begin Parent := Panel3; Anchors := [akTop,akLeft]; Height := 21; Left := 80; TabOrder := 0; Top := 8; Width := 153; end; lblAlias := TLabel.Create(self); with lblAlias do begin Parent := Panel3; Anchors := [akTop, akLeft]; Caption := STableAlias; FocusControl := edtAlias; Height := 13; Left := 8; Top := 16; Width := 68; end; chkReplace := TCheckBox.Create(self); with chkReplace do begin Parent := Panel3; Anchors := [akTop,akLeft]; Caption := SReplaceSQL; Checked := True; Height := 17; Left := 8; TabOrder := 1; TabStop := True; Top := 40; Width := 97; end; edtSelect := TMemo.Create(self); with edtSelect do begin Parent := tbsSelect; Align := alClient; Anchors := [akTop,akLeft,akRight,akBottom]; Font.Height := -14; {$IFDEF MSWINDOWS} Font.Name := 'Courier New'; {$ENDIF} Font.Pitch := fpFixed; Height := 513; Left := 0; PopupMenu := PopupMenu1; TabOrder := 0; TabStop := True; Top := 0; Width := 513; end; //{$IFDEF USE_SYNEDIT} //with SynSQLSyn1 do //begin //TableNameAttri.Background:=clWindow; //TableNameAttri.Foreground:=clGreen; //TableNameAttri.Style:=[fsUnderline]; //with ADS.Connection do //if (strpos(PChar(Protocol),'firebird') <> nil) or //(strpos(PChar(Protocol),'interbase') <> nil) then //begin //SQLDialect:=sqlInterbase6; //end //else if Protocol = 'mssql' then //begin //SQLDialect:=sqlMSSQL2K; //end //else if (strpos(PChar(Protocol),'mysql') <> nil) then //begin //SQLDialect:=sqlMySQL; //end //else if (strpos(PChar(Protocol),'postgresql') <> nil) then //begin //SQLDialect:=sqlStandard; //end //else if Protocol = 'sybase' then //begin //SQLDialect:=sqlSybase; //end; //DefaultFilter:=SQLDefaultFilter; //end; //{$IFDEF FPC} //SynCompletion:=TSynCompletion.Create(Self); //{$ELSE} //SynCompletion:=TSynCompletionProposal.Create(Self); //{$ENDIF} //with SynCompletion do begin //AddEditor(edtSelect); //ItemList.Clear; //OnCodeCompletion:=ccComplete; //OnExecute:=ccExecute; //end; //{$ENDIF} FSaveConnected := True; FDS:=ADS; if Assigned(FDS) then begin if not FDS.Connection.Connected then begin FSaveConnected := False; FDS.Connection.Connected := True; end; edtSelect.Lines.Text:=FDS.SQL.Text; LoadTableList; FillIdentifier; end; end; procedure TZQuerySQLEditorForm.FillIdentifier; var i:integer; begin //{$IFDEF USE_SYNEDIT} //SynSQLSyn1.TableNames.Clear; //for i:=0 to ListBoxRelations.Items.Count-1 do //begin //SynSQLSyn1.TableNames.Add(ListBoxRelations.Items[i]); //end; //{$ENDIF} end; procedure TZQuerySQLEditorForm.FormClose(Sender: TObject; var Action: TCloseAction); begin if (ModalResult=mrOk) and Assigned(FDS) then begin FDS.SQL.Text:=edtSelect.Lines.Text; end; end; procedure TZQuerySQLEditorForm.LoadTableList; var Metadata: IZDatabaseMetadata; TableTypes: TStringDynArray; begin if Assigned(FDS.Connection) and FDS.Connection.Connected then begin Metadata := FDS.Connection.DbcConnection.GetMetadata; SetLength(TableTypes, 2); TableTypes[0] := 'TABLE'; TableTypes[1] := 'VIEW'; FDS.Connection.ShowSQLHourGlass; ListBoxRelations.Items.Clear; with Metadata.GetTables(FDS.Connection.Catalog, '', '', TableTypes) do try while Next do if ListBoxRelations.Items.IndexOf(trim(GetString(3))) = -1 then ListBoxRelations.Items.Add(trim(GetString(3))); finally Close; end; FDS.Connection.HideSQLHourGlass; end; end; function TZQuerySQLEditorForm.ActiveEditor:TMemo; //function TZQuerySQLEditorForm.ActiveEditor: //{$IFDEF USE_SYNEDIT}TSynEdit{$ELSE}TMemo{$ENDIF}; begin case PageControl1.ActivePageIndex of 0:Result:=edtSelect; end; end; procedure TZQuerySQLEditorForm.ListBoxRelationsDblClick( Sender: TObject); var i:integer; Als, FieldsStr:string; begin if ActiveEditor<>nil then with ActiveEditor do begin if chkReplace.Checked then Lines.Clear; if ListBoxFields.SelCount=0 then begin Lines.Add('select'); Lines.Add(' *'); Lines.Add('from'); Lines.Add(' '+ListBoxRelations.Items[ListBoxRelations.ItemIndex]+' '+edtAlias.Text); end else begin Lines.Add('select'); if edtAlias.Text<>'' then Als:=edtAlias.Text else Als:=ListBoxRelations.Items[ListBoxRelations.ItemIndex]; FieldsStr:=''; for i:=0 to ListBoxFields.Items.Count-1 do begin if ListBoxFields.Selected[i] then begin if FieldsStr<>'' then Lines.Add(FieldsStr+','); FieldsStr:=' '+Als+'.'+ListBoxFields.Items[i]; end; end; if FieldsStr<>'' then Lines.Add(FieldsStr); Lines.Add('from'); Lines.Add(' '+ListBoxRelations.Items[ListBoxRelations.ItemIndex]+' '+edtAlias.Text); end; end; end; procedure TZQuerySQLEditorForm.ListBoxRelationsSelectionChange(Sender: TObject; User: boolean); var Metadata: IZDatabaseMetadata; TPName: string; StrEsc: string; begin if Assigned(FDS.Connection) and FDS.Connection.Connected then begin FDS.Connection.ShowSQLHourGlass; Metadata := FDS.Connection.DbcConnection.GetMetadata; with ListBoxFields do begin ItemIndex := -1; Items.BeginUpdate; Items.Clear; Items.EndUpdate; end; if ListBoxRelations.ItemIndex >= 0 then begin TPName := ListBoxRelations.Items[ListBoxRelations.ItemIndex]; with Metadata.GetColumns(FDS.Connection.Catalog,'', TPName,'') do try while Next do if ListBoxFields.Items.IndexOf(GetStringByName('COLUMN_NAME')) = -1 then ListBoxFields.Items.Add(GetStringByName('COLUMN_NAME')); finally Close; end; end; FDS.Connection.HideSQLHourGlass; end; end; procedure TZQuerySQLEditorForm.PageControl1Change(Sender: TObject); begin case PageControl1.ActivePageIndex of 0:edtSelect.SetFocus; end; end; procedure TZQuerySQLEditorForm.ZeosQuerySQLEditorDestroy(Sender: TObject); begin if not FSaveConnected then FDS.Connection.Connected := False; end; procedure TZQuerySQLEditorForm.btnGenerateClick(Sender: TObject); begin ListBoxRelationsDblClick(nil); end; procedure TZQuerySQLEditorForm.btnTestClick(Sender: TObject); begin if Assigned(FDS.Connection) and FDS.Connection.Connected then begin ZeosSQLEditorTestForm:=TZeosSQLEditorTestForm.Create(Application); with ZeosSQLEditorTestForm do begin try ZeosSQL.Connection:=FDS.Connection; ZeosSQL.SQL.Text:=ActiveEditor.Lines.Text; ZeosSQL.Active := true; ShowModal except on E:Exception do ShowMessage(E.Message); end; Free; end; end; end; procedure TZQuerySQLEditorForm.mnuLoadClick(Sender: TObject); begin if (dlgOpen.Execute) then ActiveEditor.Lines.LoadFromFile(dlgOpen.FileName); end; procedure TZQuerySQLEditorForm.mnuSaveClick(Sender: TObject); begin if dlgSave.Execute then ActiveEditor.Lines.SaveToFile(dlgSave.FileName); end; //{$IFDEF USE_SYNEDIT} //procedure TZQuerySQLEditorForm.ccComplete //{$IFDEF FPC} //(var Value: ansistring; //Shift: TShiftState) //{$ELSE} //(Sender: TObject; var Value: string; //Shift: TShiftState; Index: Integer; EndToken: Char) //{$ENDIF} //; //begin //end; //procedure TZQuerySQLEditorForm.ccExecute //{$IFDEF FPC} //(Sender: TObject) //{$ELSE} //(Kind: SynCompletionType; Sender: TObject; //var CurrentInput: string; var x, y: Integer; var CanExecute: Boolean) //{$ENDIF} //; //function GetCurWord:string; //var //S:string; //i,j:integer; //begin //Result:=''; //with ActiveEditor do //begin //S:=Trim(Copy(LineText, 1, CaretX)); //I:=Length(S); //while (i>0) and (S[i]<>'.') do Dec(I); //if (I>0) then //begin //J:=i-1; ////Get table name //while (j>0) and CharInSet(S[j], ['A'..'z','"']) do Dec(j); //Result:=trim(Copy(S, j+1, i-j-1)); //end; //end; //end; //var //S:string; //Metadata: IZDatabaseMetadata; //StrEsc: string; //begin //S:=AnsiUpperCase(GetCurWord); //if S<>'' then //begin //if Assigned(FDS.Connection) and FDS.Connection.Connected then //begin //FDS.Connection.ShowSQLHourGlass; //Metadata := FDS.Connection.DbcConnection.GetMetadata; //SynCompletion.ItemList.Clear; //{$IFDEF FPC} //SynCompletion.OnPaintItem; //{$ELSE} //{$ENDIF} //with Metadata.GetColumns(FDS.Connection.Catalog,'',S,'') do //try //while Next do //if SynCompletion.ItemList.IndexOf(GetStringByName('COLUMN_NAME')) = -1 then //SynCompletion.ItemList.Add(GetStringByName('COLUMN_NAME')); //finally //Close; //end; //FDS.Connection.HideSQLHourGlass; //end; //end; //end; //{$ENDIF} end. ================================================ FILE: lib/zeosdbo/src/component/ZROSqlEditor.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { SQL Monitor component } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZROSqlEditor; {$I ZComponent.inc} interface uses {$IFDEF MSWINDOWS} // 64-bit too Windows, Messages, {$ENDIF} {$IFDEF FPC} LCLIntf, {$ENDIF} SysUtils, Classes, Graphics, Controls, Forms, Dialogs, Graphtype, StdCtrls, ExtCtrls, ComCtrls, Buttons, ZDataset, Menus, ZMessages; //{$IFDEF USE_SYNEDIT} //, SynEdit, SynEditHighlighter, SynHighlighterSQL //{$IFDEF FPC} //, SynCompletion //{$ELSE} //, SynCompletionProposal //{$ENDIF} //{$ENDIF}; type { TZROSQLEditorForm } TZROSQLEditorForm = class(TForm) private mnuSave: TMenuItem; mnuLoad: TMenuItem; dlgOpen: TOpenDialog; PopupMenu1: TPopupMenu; dlgSave: TSaveDialog; btnOk: TBitBtn; btnCancel: TBitBtn; Panel2: TPanel; tbsSelect: TTabSheet; Panel1: TPanel; Splitter2: TSplitter; ListBoxRelations: TListBox; ListBoxFields: TListBox; Splitter1: TSplitter; Panel3: TPanel; lblAlias: TLabel; edtAlias: TEdit; btnGenerate: TButton; btnCheck: TButton; chkReplace: TCheckBox; btnTest: TButton; edtSelect: TMemo; //{$IFDEF USE_SYNEDIT} //edtSelect: TSynEdit; //SynSQLSyn1: TSynSQLSyn; //{$IFDEF FPC} //SynCompletion:TSynCompletion; //{$ELSE} //SynCompletion:TSynCompletionProposal; //{$ENDIF} //{$ELSE} //edtSelect: TMemo; //{$ENDIF} FDS: TZReadOnlyQuery; FSaveConnected: Boolean; procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure ListBoxRelationsDblClick(Sender: TObject); procedure ListBoxRelationsSelectionChange(Sender: TObject; User: boolean); procedure PageControl1Change(Sender: TObject); procedure ZeosROSQLEditorDestroy(Sender: TObject); procedure btnGenerateClick(Sender: TObject); procedure btnTestClick(Sender: TObject); procedure mnuLoadClick(Sender: TObject); procedure mnuSaveClick(Sender: TObject); procedure LoadTableList; procedure FillIdentifier; function ActiveEditor:TMemo; //function ActiveEditor:{$IFDEF USE_SYNEDIT} TSynEdit {$ELSE} TMemo {$ENDIF}; //{$IFDEF USE_SYNEDIT} //{$IFDEF FPC} //procedure ccComplete(var Value: ansistring; Shift: TShiftState); //procedure ccExecute(Sender: TObject); //{$ELSE} //procedure ccComplete(Sender: TObject; var Value: string; //Shift: TShiftState; Index: Integer; EndToken: Char); //procedure ccExecute(Kind: SynCompletionType; Sender: TObject; //var CurrentInput: string; var x, y: Integer; var CanExecute: Boolean); //{$ENDIF} //{$ENDIF} public PageControl1: TPageControl; constructor CreateEditor(ADS:TZReadOnlyQuery); end; var ZeosROSQLEditorForm: TZROSQLEditorForm; implementation uses ZSqlTestForm, ZDbcIntfs, ZCompatibility; const SQLDefaultFilter = 'SQL files (*.sql)|*.sql'; { TZeosROSQLEditor } constructor TZROSQLEditorForm.CreateEditor(ADS: TZReadOnlyQuery); begin inherited CreateNew(Application,0); Height := 613; Left := 315; Top := 142; TextHeight := 13; Width := 768; Position := poDesktopCenter; Caption := sFormEditor; OnClose := FormClose; OnDestroy := ZeosROSQLEditorDestroy; btnOk := TBitBtn.Create(self); with btnOk do begin Parent := self; Anchors := [akRight, akBottom]; Default := True; Height := 25; Kind := bkOk; Left := 593; ModalResult := mrOk; TabOrder := 3; TabStop := True; Top := 552; Width := 75; Caption := SButtonOk; end; btnCancel := TBitBtn.Create(self); with btnCancel do begin Parent := self; Anchors := [akRight, akBottom]; Default := True; Height := 25; Kind := bkCancel; Left := 677; ModalResult := mrCancel; TabOrder := 4; TabStop := True; Top := 552; Width := 75; Caption := SButtonCancel; end; btnGenerate := TButton.Create(self); with btnGenerate do begin Parent := self; Anchors := [akLeft,akBottom]; Caption := SButtonGenerate; Height := 25; Left := 8; OnClick := btnGenerateClick; TabOrder := 0; TabStop := True; Top := 552; Width := 75; end; btnCheck := TButton.Create(self); with btnCheck do begin Parent := self; Anchors := [akLeft,akBottom]; Caption := SButtonCheck; Enabled := False; Height := 25; Left := 88; TabOrder := 1; TabStop := True; Top := 552; Visible := False; Width := 75; end; btnTest := TButton.Create(self); with btnTest do begin Parent := self; Anchors := [akLeft,akBottom]; Caption := SButtonTest; Height := 25; Left := 168; OnClick := btnTestClick; TabOrder := 2; TabStop := True; Top := 552; Width := 75; end; dlgOpen := TOpenDialog.Create(self); with dlgOpen do begin FilterIndex :=0; Options := [ofEnableSizing,ofViewDetail]; Title := SDialogOpenTitle; Filter := SQLDefaultFilter; end; dlgSave := TSaveDialog.Create(self); with dlgSave do begin FilterIndex :=0; Options := [ofEnableSizing,ofViewDetail]; Title := SDialogSaveTitle; Filter := SQLDefaultFilter; end; mnuLoad := TMenuItem.Create(self); with mnuLoad do begin Caption := SMenuLoad; OnClick := mnuLoadClick; end; mnuSave := TMenuItem.Create(self); with mnuSave do begin Caption := SMenuSave; OnClick := mnuSaveClick; end; PopupMenu1 := TPopupMenu.Create(self); with PopupMenu1 do begin AutoPopup := true; Items.Add(mnuLoad); Items.Add(mnuSave); end; Panel2 := TPanel.Create(self); with Panel2 do begin Parent := self; Align := alTop; Anchors := [akTop,akLeft,akRight,akBottom]; FullRepaint := False; Height := 545; Left := 0; TabOrder := 5; TabStop := False; Top := 0; Width := 768; end; Splitter1 := TSplitter.Create(self); with Splitter1 do begin Parent := Panel2; Align := alRight; Anchors := [akTop,akRight,akBottom]; Height := 543; Left := 518; Top := 1; Width := 5; end; PageControl1 := TPageControl.Create(self); with PageControl1 do begin Parent := Panel2; Align := alClient; Anchors := [akTop,akLeft,akRight,akBottom]; Height := 543; Left := 1; OnChange := PageControl1Change; TabIndex := 0; TabOrder := 0; TabPosition := tpTop; TabStop := True; Top := 1; Width := 517; end; tbsSelect := TTabSheet.Create(self); with tbsSelect do begin Parent := PageControl1; Caption := STabSheetSelect; Height := 513; Left := 2; Top := 28; Width := 513; end; Panel1 := TPanel.Create(self); with Panel1 do begin Parent := Panel2; Align := alRight; Anchors := [akTop,akRight,akBottom]; FullRepaint := false; Height := 543; Left := 523; TabOrder := 1; TabStop := False; Top := 1; Width := 244; end; Splitter2 := TSplitter.Create(self); with Splitter2 do begin Parent := Panel1; Align := alBottom; Anchors := [akLeft,akRight,akBottom]; Cursor := crVSplit; Height := 9; Left := 1; Top := 271; Width := 242; end; ListBoxRelations := TListBox.Create(self); with ListBoxRelations do begin Parent := Panel1; Align := alClient; Anchors := [akTop,akLeft,akRight,akBottom]; Height := 198; ItemHeight := 13; Left := 1; OnDblClick := ListBoxRelationsDblClick; OnSelectionChange := ListBoxRelationsSelectionChange; TabOrder := 0; Top := 73; Width := 242 end; ListBoxFields := TListBox.Create(self); with ListBoxFields do begin Parent := Panel1; Align := alBottom; Anchors := [akLeft,akRight,akBottom]; Height := 262; ItemHeight := 13; Left := 1; MultiSelect := True; TabOrder := 1; Top := 280; Width := 242; end; Panel3 := TPanel.Create(self); with Panel3 do begin Parent := Panel1; Align := alTop; Anchors := [akTop,akLeft,akRight,akBottom]; BevelOuter := bvNone; FullRepaint := False; Height := 72; Left := 1; TabOrder := 2; TabStop := False; Top := 1; Width := 242; end; edtAlias := TEdit.Create(self); with edtAlias do begin Parent := Panel3; Anchors := [akTop,akLeft]; Height := 21; Left := 80; TabOrder := 0; Top := 8; Width := 153; end; lblAlias := TLabel.Create(self); with lblAlias do begin Parent := Panel3; Anchors := [akTop, akLeft]; Caption := STableAlias; FocusControl := edtAlias; Height := 13; Left := 8; Top := 16; Width := 68; end; chkReplace := TCheckBox.Create(self); with chkReplace do begin Parent := Panel3; Anchors := [akTop,akLeft]; Caption := SReplaceSQL; Checked := True; Height := 17; Left := 8; TabOrder := 1; TabStop := True; Top := 40; Width := 97; end; edtSelect := TMemo.Create(self); with edtSelect do begin Parent := tbsSelect; Align := alClient; Anchors := [akTop,akLeft,akRight,akBottom]; Font.Height := -14; {$IFDEF MSWINDOWS} Font.Name := 'Courier New'; {$ENDIF} Font.Pitch := fpFixed; Height := 513; Left := 0; PopupMenu := PopupMenu1; TabOrder := 0; TabStop := True; Top := 0; Width := 513; end; //{$IFDEF USE_SYNEDIT} //with SynSQLSyn1 do //begin //TableNameAttri.Background:=clWindow; //TableNameAttri.Foreground:=clGreen; //TableNameAttri.Style:=[fsUnderline]; //with ADS.Connection do //if (strpos(PChar(Protocol),'firebird') <> nil) or //(strpos(PChar(Protocol),'interbase') <> nil) then //begin //SQLDialect:=sqlInterbase6; //end //else if Protocol = 'mssql' then //begin //SQLDialect:=sqlMSSQL2K; //end //else if (strpos(PChar(Protocol),'mysql') <> nil) then //begin //SQLDialect:=sqlMySQL; //end //else if (strpos(PChar(Protocol),'postgresql') <> nil) then //begin //SQLDialect:=sqlStandard; //end //else if Protocol = 'sybase' then //begin //SQLDialect:=sqlSybase; //end; //DefaultFilter:=SQLDefaultFilter; //end; //{$IFDEF FPC} //SynCompletion:=TSynCompletion.Create(Self); //{$ELSE} //SynCompletion:=TSynCompletionProposal.Create(Self); //{$ENDIF} //with SynCompletion do begin //AddEditor(edtSelect); //ItemList.Clear; //OnCodeCompletion:=ccComplete; //OnExecute:=ccExecute; //end; //{$ENDIF} FSaveConnected := True; FDS:=ADS; if Assigned(FDS) then begin if not FDS.Connection.Connected then begin FSaveConnected := False; FDS.Connection.Connected := True; end; edtSelect.Lines.Text:=FDS.SQL.Text; LoadTableList; FillIdentifier; end; end; procedure TZROSQLEditorForm.FillIdentifier; var i:integer; begin //{$IFDEF USE_SYNEDIT} //SynSQLSyn1.TableNames.Clear; //for i:=0 to ListBoxRelations.Items.Count-1 do //begin //SynSQLSyn1.TableNames.Add(ListBoxRelations.Items[i]); //end; //{$ENDIF} end; procedure TZROSQLEditorForm.FormClose(Sender: TObject; var Action: TCloseAction); begin if (ModalResult=mrOk) and Assigned(FDS) then begin FDS.SQL.Text:=edtSelect.Lines.Text; end; end; procedure TZROSQLEditorForm.LoadTableList; var Metadata: IZDatabaseMetadata; TableTypes: TStringDynArray; begin if Assigned(FDS.Connection) and FDS.Connection.Connected then begin Metadata := FDS.Connection.DbcConnection.GetMetadata; SetLength(TableTypes, 2); TableTypes[0] := 'TABLE'; TableTypes[1] := 'VIEW'; FDS.Connection.ShowSQLHourGlass; ListBoxRelations.Items.Clear; with Metadata.GetTables(FDS.Connection.Catalog, '', '', TableTypes) do try while Next do if ListBoxRelations.Items.IndexOf(trim(GetString(3))) = -1 then ListBoxRelations.Items.Add(trim(GetString(3))); finally Close; end; FDS.Connection.HideSQLHourGlass; end; end; function TZROSQLEditorForm.ActiveEditor:TMemo; //function TZROSQLEditorForm.ActiveEditor: //{$IFDEF USE_SYNEDIT}TSynEdit{$ELSE}TMemo{$ENDIF}; begin case PageControl1.ActivePageIndex of 0:Result:=edtSelect; end; end; procedure TZROSQLEditorForm.ListBoxRelationsDblClick( Sender: TObject); var i:integer; Als, FieldsStr:string; begin if ActiveEditor<>nil then with ActiveEditor do begin if chkReplace.Checked then Lines.Clear; if ListBoxFields.SelCount=0 then begin Lines.Add('select'); Lines.Add(' *'); Lines.Add('from'); Lines.Add(' '+ListBoxRelations.Items[ListBoxRelations.ItemIndex]+' '+edtAlias.Text); end else begin Lines.Add('select'); if edtAlias.Text<>'' then Als:=edtAlias.Text else Als:=ListBoxRelations.Items[ListBoxRelations.ItemIndex]; FieldsStr:=''; for i:=0 to ListBoxFields.Items.Count-1 do begin if ListBoxFields.Selected[i] then begin if FieldsStr<>'' then Lines.Add(FieldsStr+','); FieldsStr:=' '+Als+'.'+ListBoxFields.Items[i]; end; end; if FieldsStr<>'' then Lines.Add(FieldsStr); Lines.Add('from'); Lines.Add(' '+ListBoxRelations.Items[ListBoxRelations.ItemIndex]+' '+edtAlias.Text); end; end; end; procedure TZROSQLEditorForm.ListBoxRelationsSelectionChange(Sender: TObject; User: boolean); var Metadata: IZDatabaseMetadata; TPName: string; StrEsc: string; begin if Assigned(FDS.Connection) and FDS.Connection.Connected then begin FDS.Connection.ShowSQLHourGlass; Metadata := FDS.Connection.DbcConnection.GetMetadata; with ListBoxFields do begin ItemIndex := -1; Items.BeginUpdate; Items.Clear; Items.EndUpdate; end; if ListBoxRelations.ItemIndex >= 0 then begin TPName := ListBoxRelations.Items[ListBoxRelations.ItemIndex]; with Metadata.GetColumns(FDS.Connection.Catalog,'', TPName,'') do try while Next do if ListBoxFields.Items.IndexOf(GetStringByName('COLUMN_NAME')) = -1 then ListBoxFields.Items.Add(GetStringByName('COLUMN_NAME')); finally Close; end; end; FDS.Connection.HideSQLHourGlass; end; end; procedure TZROSQLEditorForm.PageControl1Change(Sender: TObject); begin case PageControl1.ActivePageIndex of 0:edtSelect.SetFocus; end; end; procedure TZROSQLEditorForm.ZeosROSQLEditorDestroy(Sender: TObject); begin if not FSaveConnected then FDS.Connection.Connected := False; end; procedure TZROSQLEditorForm.btnGenerateClick(Sender: TObject); begin ListBoxRelationsDblClick(nil); end; procedure TZROSQLEditorForm.btnTestClick(Sender: TObject); begin if Assigned(FDS.Connection) and FDS.Connection.Connected then begin ZeosSQLEditorTestForm:=TZeosSQLEditorTestForm.Create(Application); with ZeosSQLEditorTestForm do begin try ZeosSQL.Connection:=FDS.Connection; ZeosSQL.SQL.Text:=ActiveEditor.Lines.Text; ZeosSQL.Active := true; ShowModal except on E:Exception do ShowMessage(E.Message); end; Free; end; end; end; procedure TZROSQLEditorForm.mnuLoadClick(Sender: TObject); begin if (dlgOpen.Execute) then ActiveEditor.Lines.LoadFromFile(dlgOpen.FileName); end; procedure TZROSQLEditorForm.mnuSaveClick(Sender: TObject); begin if dlgSave.Execute then ActiveEditor.Lines.SaveToFile(dlgSave.FileName); end; //{$IFDEF USE_SYNEDIT} //procedure TZROSQLEditorForm.ccComplete //{$IFDEF FPC} //(var Value: ansistring; //Shift: TShiftState) //{$ELSE} //(Sender: TObject; var Value: string; //Shift: TShiftState; Index: Integer; EndToken: Char) //{$ENDIF} //; //begin //end; //procedure TZROSQLEditorForm.ccExecute //{$IFDEF FPC} //(Sender: TObject) //{$ELSE} //(Kind: SynCompletionType; Sender: TObject; //var CurrentInput: string; var x, y: Integer; var CanExecute: Boolean) //{$ENDIF} //; //function GetCurWord:string; //var //S:string; //i,j:integer; //begin //Result:=''; //with ActiveEditor do //begin //S:=Trim(Copy(LineText, 1, CaretX)); //I:=Length(S); //while (i>0) and (S[i]<>'.') do Dec(I); //if (I>0) then //begin //J:=i-1; ////Get table name //while (j>0) and CharInSet(S[j], ['A'..'z','"']) do Dec(j); //Result:=trim(Copy(S, j+1, i-j-1)); //end; //end; //end; //var //S:string; //Metadata: IZDatabaseMetadata; //StrEsc: string; //begin //S:=AnsiUpperCase(GetCurWord); //if S<>'' then //begin //if Assigned(FDS.Connection) and FDS.Connection.Connected then //begin //FDS.Connection.ShowSQLHourGlass; //Metadata := FDS.Connection.DbcConnection.GetMetadata; //SynCompletion.ItemList.Clear; //{$IFDEF FPC} //SynCompletion.OnPaintItem; //{$ELSE} //{$ENDIF} //with Metadata.GetColumns(FDS.Connection.Catalog,'',S,'') do //try //while Next do //if SynCompletion.ItemList.IndexOf(GetStringByName('COLUMN_NAME')) = -1 then //SynCompletion.ItemList.Add(GetStringByName('COLUMN_NAME')); //finally //Close; //end; //FDS.Connection.HideSQLHourGlass; //end; //end; //end; //{$ENDIF} end. ================================================ FILE: lib/zeosdbo/src/component/ZSequence.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Database Sequence Component } { } { Originally written by Stefan Glienke } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZSequence; interface {$I ZComponent.inc} uses SysUtils, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} ZDbcIntfs, ZConnection; type {** Represents a component which wraps a sequence to database. } TZSequence = class(TComponent) private FSequence: IZSequence; FConnection: TZConnection; FSequenceName: string; FBlockSize: Integer; procedure SetConnection(const Value: TZConnection); procedure SetBlockSize(const Value: Integer); procedure SetSequenceName(const Value: string); protected procedure Notification(AComponent: TComponent; Operation: TOperation); override; function GetSequence: IZSequence; public constructor Create(AOwner: TComponent); override; // Modified by cipto 8/2/2007 12:09:21 PM destructor Destroy; override; function GetCurrentValue: Int64; function GetNextValue: Int64; function GetCurrentValueSQL: string; // Get the Sequence as SQL-Text function GetNextValueSQL: string; // Get the Sequence as SQL-Text // Modified by cipto 8/2/2007 10:04:41 AM procedure CloseSequence; published property BlockSize: Integer read FBlockSize write SetBlockSize default 1; property Connection: TZConnection read FConnection write SetConnection; property SequenceName: string read FSequenceName write SetSequenceName; end; implementation { TZSequence } procedure TZSequence.CloseSequence; begin if Assigned(FSequence) then FSequence:=nil; end; constructor TZSequence.Create(AOwner: TComponent); begin inherited; FBlockSize := 1; end; {** Gets the current unique key generated by this sequence. @param the next generated unique key. } destructor TZSequence.Destroy; begin // Modified by cipto 8/3/2007 10:35:41 AM if Assigned(FConnection) then FConnection.UnregisterSequence(self); inherited; end; function TZSequence.GetCurrentValue: Int64; begin GetSequence; if Assigned(FSequence) then Result := FSequence.GetCurrentValue else Result := 0; end; function TZSequence.GetCurrentValueSQL: string; begin GetSequence; if Assigned(FSequence) then begin Result := FSequence.GetCurrentValueSQL; end else begin Result := 'IMPLEMENT'; end; end; {** Gets the next unique key generated by this sequence. @param the next generated unique key. } function TZSequence.GetNextValue: Int64; begin GetSequence; if Assigned(FSequence) then Result := FSequence.GetNextValue else Result := 0; end; function TZSequence.GetNextValueSQL: string; begin GetSequence; if Assigned(FSequence) then begin Result := FSequence.GetNextValueSQL; end else begin Result := 'IMPLEMENT'; end; end; function TZSequence.GetSequence: IZSequence; begin if not Assigned(FSequence) then begin if Assigned(FConnection) and Assigned(FConnection.DbcConnection) then FSequence := FConnection.DbcConnection.CreateSequence( FSequenceName, FBlockSize); end; Result := FSequence; end; {** Processes component notifications. @param AComponent a changed component object. @param Operation a component operation code. } procedure TZSequence.Notification(AComponent: TComponent; Operation: TOperation); begin inherited Notification(AComponent, Operation); if (Operation = opRemove) and (AComponent = FConnection) then begin // Modified by cipto 8/2/2007 12:07:57 PM FConnection := nil; if Assigned(FSequence) then FSequence := nil; end; end; procedure TZSequence.SetBlockSize(const Value: Integer); begin FBlockSize := Value; GetSequence; if Assigned(FSequence) then FSequence.SetBlockSize(FBlockSize); end; procedure TZSequence.SetConnection(const Value: TZConnection); begin if FConnection <> Value then begin if Assigned(FSequence) then FSequence := nil; FConnection := Value; // Modified by cipto 8/2/2007 11:59:58 AM if Assigned(FConnection) then FConnection.RegisterSequence(self); GetSequence; end; end; procedure TZSequence.SetSequenceName(const Value: string); begin FSequenceName := Value; GetSequence; if Assigned(FSequence) then FSequence.SetName(FSequenceName); end; end. ================================================ FILE: lib/zeosdbo/src/component/ZSqlMetadata.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { SQL Metadata Dataset component } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZSqlMetadata; interface {$I ZComponent.inc} uses SysUtils, Classes, ZDbcIntfs, ZAbstractRODataset; type {** Defines an enumiration for SQL metadata resultsets. } TZMetadataType = (mdProcedures, mdProcedureColumns, mdTables, mdSchemas, mdCatalogs, mdTableTypes, mdColumns, mdColumnPrivileges, mdTablePrivileges, mdBestRowIdentifier, mdVersionColumns, mdPrimaryKeys, mdImportedKeys, mdExportedKeys, mdCrossReference, mdTypeInfo, mdTriggers, mdIndexInfo, mdSequences, mdUserDefinedTypes); {** Abstract dataset component which works with one specified table. } TZSQLMetadata = class(TZAbstractRODataset) private FMetadataType: TZMetadataType; FCatalog: string; FSchema: string; FTableName: string; FTriggerName: string; FColumnName: string; FProcedureName: string; FScope: Integer; FNullable: Boolean; FForeignCatalog: string; FForeignSchema: string; FForeignTableName: string; FUnique: Boolean; FApproximate: Boolean; FTypeName: string; FSequenceName: string; procedure SetMetadataType(Value: TZMetadataType); protected function CreateResultSet(const SQL: string; MaxRows: Integer): IZResultSet; override; procedure CheckSQLQuery; override; published property MetadataType: TZMetadataType read FMetadataType write SetMetadataType; property Catalog: string read FCatalog write FCatalog; property Schema: string read FSchema write FSchema; property TableName: string read FTableName write FTableName; property ColumnName: string read FColumnName write FColumnName; property ProcedureName: string read FProcedureName write FProcedureName; property Scope: Integer read FScope write FScope default 0; property Nullable: Boolean read FNullable write FNullable default False; property ForeignCatalog: string read FForeignCatalog write FForeignCatalog; property ForeignSchema: string read FForeignSchema write FForeignSchema; property ForeignTableName: string read FForeignTableName write FForeignTableName; property Unique: Boolean read FUnique write FUnique default False; property Approximate: Boolean read FApproximate write FApproximate default False; property TypeName: string read FTypeName write FTypeName; property SequenceName: string read FSequenceName write FSequenceName; property TriggerName: String read FTriggerName write FTriggerName; property Active; property MasterFields; property MasterSource; property LinkedFields; {renamed by bangfauzan} end; implementation { TZSQLMetadata } {** Sets a new SQL metadata type. @param Value a new SQL metadata type. } procedure TZSQLMetadata.SetMetadataType(Value: TZMetadataType); begin if FMetadataType <> Value then begin Active := False; FMetadataType := Value; end; end; {** Creates a DBC resultset for the query. @param SQL an SQL query. @param MaxRows a maximum rows number (-1 for all). @returns a created DBC resultset. } {$IFDEF FPC} {$HINTS OFF} {$ENDIF} function TZSQLMetadata.CreateResultSet(const SQL: string; MaxRows: Integer): IZResultSet; var Metadata: IZDatabaseMetadata; begin Connection.ShowSQLHourGlass; try Metadata := Connection.DbcConnection.GetMetadata; case FMetadataType of mdProcedures: Result := Metadata.GetProcedures(FCatalog, FSchema, FProcedureName); mdProcedureColumns: Result := Metadata.GetProcedureColumns(FCatalog, FSchema, FProcedureName, FColumnName); mdTables: Result := Metadata.GetTables(FCatalog, FSchema, FTableName, nil); mdSchemas: Result := Metadata.GetSchemas; mdCatalogs: Result := Metadata.GetCatalogs; mdTableTypes: Result := Metadata.GetTableTypes; mdTriggers: Result := Metadata.GetTriggers(FCatalog, FSchema, FTableName, FTriggerName); mdColumns: Result := Metadata.GetColumns(FCatalog, FSchema, FTableName, FColumnName); mdColumnPrivileges: Result := Metadata.GetColumnPrivileges(FCatalog, FSchema, FTableName, FColumnName); mdTablePrivileges: Result := Metadata.GetTablePrivileges(FCatalog, FSchema, FTableName); mdBestRowIdentifier: Result := Metadata.GetBestRowIdentifier(FCatalog, FSchema, FTableName, FScope, FNullable); mdVersionColumns: Result := Metadata.GetVersionColumns(FCatalog, FSchema, FTableName); mdPrimaryKeys: Result := Metadata.GetPrimaryKeys(FCatalog, FSchema, FTableName); mdImportedKeys: Result := Metadata.GetImportedKeys(FCatalog, FSchema, FTableName); mdExportedKeys: Result := Metadata.GetExportedKeys(FCatalog, FSchema, FTableName); mdCrossReference: Result := Metadata.GetCrossReference(FCatalog, FSchema, FTableName, FForeignCatalog, FForeignSchema, FForeignTableName); mdTypeInfo: Result := Metadata.GetTypeInfo; mdIndexInfo: Result := Metadata.GetIndexInfo(FCatalog, FSchema, FTableName, FUnique, FApproximate); mdSequences: Result := Metadata.GetSequences(FCatalog, FSchema, FSequenceName); mdUserDefinedTypes: Result := Metadata.GetUDTs(FCatalog, FSchema, FTypeName, nil); end; finally Connection.HideSQLHourGlass; end; end; {$IFDEF FPC} {$HINTS ON} {$ENDIF} {** Checks the SQL query. The query has no meaning for this class. } procedure TZSQLMetadata.CheckSQLQuery; begin // Here sql has no meaning. So it should not be tested. end; end. ================================================ FILE: lib/zeosdbo/src/component/ZSqlMonitor.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { SQL Monitor component } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZSqlMonitor; interface {$I ZComponent.inc} uses SysUtils, Classes, Contnrs, {$IFDEF MSEgui}mclasses,{$ENDIF} ZClasses, ZCompatibility, ZDbcIntfs, ZDbcLogging; type {** Repeat declaration of TZLoggingEvent. } TZLoggingEvent = ZDbcLogging.TZLoggingEvent; {** Repeat declaration of TZLoggingFormatter. } IZLoggingFormatter = ZDbcLogging.IZLoggingFormatter; TZLoggingFormatter = ZDbcLogging.TZLoggingFormatter; {** Declares event before logging. } TZTraceEvent = procedure(Sender: TObject; Event: TZLoggingEvent; var LogTrace: Boolean) of object; {** Declares event after logging. } TZTraceLogEvent = procedure(Sender: TObject; Event: TZLoggingEvent) of object; {** Implements an object to log events from SQL client. } TZSQLMonitor = class(TComponent, IZLoggingListener, IZInterface) private FActive: Boolean; FAutoSave: Boolean; FFileName: string; FMaxTraceCount: Integer; FTraceList: TObjectList; FOnTrace: TZTraceEvent; FOnLogTrace: TZTraceLogEvent; FLoggingFormatter : IZLoggingFormatter; function GetTraceCount: Integer; function GetTraceItem(Index: Integer): TZLoggingEvent; procedure SetActive(const Value: Boolean); procedure SetMaxTraceCount(const Value: Integer); procedure TruncateTraceList(Count: Integer); procedure DoTrace(Event: TZLoggingEvent; var LogTrace: Boolean); procedure DoLogTrace(Event: TZLoggingEvent); public constructor Create(AOwner: TComponent); override; destructor Destroy; override; procedure LogEvent(Event: TZLoggingEvent); procedure Save(); procedure SaveToFile(const FileName: string); property TraceCount: Integer read GetTraceCount; property TraceList[Index: Integer]: TZLoggingEvent read GetTraceItem; property LoggingFormatter: IZLoggingFormatter read FLoggingFormatter write FLoggingFormatter; published property Active: Boolean read FActive write SetActive default False; property AutoSave: Boolean read FAutoSave write FAutoSave default False; property FileName: string read FFileName write FFileName; property MaxTraceCount: Integer read FMaxTraceCount write SetMaxTraceCount; property OnTrace: TZTraceEvent read FOnTrace write FOnTrace; property OnLogTrace: TZTraceLogEvent read FOnLogTrace write FOnLogTrace; end; implementation {$IFDEF WITH_UNITANSISTRINGS} uses AnsiStrings; {$ENDIF} { TZSQLMonitor } {** Constructs this object and assignes main properties. @param AOwner a component owner. } constructor TZSQLMonitor.Create(AOwner: TComponent); begin inherited Create(AOwner); FTraceList := TObjectList.Create; FMaxTraceCount := 100; end; {** Destroys this object and cleanups the memory. } destructor TZSQLMonitor.Destroy; begin SetActive(False); FTraceList.Free; inherited Destroy; end; {** Gets a number of stored logging events. @returns a number of stored logging events. } function TZSQLMonitor.GetTraceCount: Integer; begin Result := FTraceList.Count; end; {** Gets a logging event by it's index. @param Index an event index. @retuns a requested event object. } function TZSQLMonitor.GetTraceItem(Index: Integer): TZLoggingEvent; begin Result := TZLoggingEvent(FTraceList[Index]); end; {** Sets an active state for this monitor. @param Value True to activate this monitor and False to deactivate it. } procedure TZSQLMonitor.SetActive(const Value: Boolean); begin if FActive <> Value then begin if Value then DriverManager.AddLoggingListener(Self) else if Assigned(DriverManager) then DriverManager.RemoveLoggingListener(Self); FActive := Value; end; end; {** Sets a new number of logging events in the storage. @param Value a new number of logging events. } procedure TZSQLMonitor.SetMaxTraceCount(const Value: Integer); begin if Value <> FMaxTraceCount then begin FMaxTraceCount := Value; TruncateTraceList(Value); end; end; {** Truncates a storage of logging events to the specified limit. @param Count a number of events in the storage. } procedure TZSQLMonitor.TruncateTraceList(Count: Integer); begin while FTraceList.Count > Count do FTraceList.Delete(0); end; {** Invokes an event listener after logging event. @param Event a logging event object. } procedure TZSQLMonitor.DoLogTrace(Event: TZLoggingEvent); begin if Assigned(FOnLogTrace) then FOnLogTrace(Self, Event); end; {** Invokes an event listener before logging event. @param Event a logging event object. @param LogTrace a flag which switches storing the event. } procedure TZSQLMonitor.DoTrace(Event: TZLoggingEvent; var LogTrace: Boolean); begin if Assigned(FOnTrace) then FOnTrace(Self, Event, LogTrace); end; {** Saves the logging events into predefined file set in FileName property. } procedure TZSQLMonitor.Save; begin SaveToFile(FFileName); end; {** Saves the logging events to the specified file. @param FileName a name of the file to write the events. } procedure TZSQLMonitor.SaveToFile(const FileName: string); var I: Integer; Stream: TFileStream; Temp: Ansistring; Buffer: PAnsiChar; begin if not FileExists(FileName) then Stream := TFileStream.Create(FileName, fmCreate) else Stream := TFileStream.Create(FileName, fmOpenWrite or fmShareDenyWrite); try for I := 0 to FTraceList.Count - 1 do begin Temp := AnsiString(TZLoggingEvent(FTraceList[I]).AsString + LineEnding); Buffer := PAnsiChar(Temp); Stream.Write(Buffer^, {$IFDEF WITH_STRLEN_DEPRECATED}AnsiStrings.{$ENDIF}StrLen(Buffer) * sizeof(Ansichar)); end; finally Stream.Free; end; end; {** Handles a new incoming logging event. @param Event an incoming logging event. } procedure TZSQLMonitor.LogEvent(Event: TZLoggingEvent); var LogTrace: Boolean; Stream: TFileStream; Temp: Ansistring; Buffer: PAnsiChar; begin LogTrace := True; DoTrace(Event, LogTrace); if not LogTrace then Exit; { Store the event. } if FMaxTraceCount <> 0 then begin if FMaxTraceCount > 0 then TruncateTraceList(FMaxTraceCount - 1); FTraceList.Add(TZLoggingEvent.Create(Event.Category, Event.Protocol, Event.Message, Event.ErrorCode, Event.Error)); end; { Save the event. } if FAutoSave and (FFileName <> '') then begin if not FileExists(FFileName) then Stream := TFileStream.Create(FFileName, fmCreate) else Stream := TFileStream.Create(FFileName, fmOpenReadWrite or fmShareDenyWrite); try Stream.Seek(0, soFromEnd); Temp := AnsiString(Event.AsString(FLoggingFormatter) + LineEnding); Buffer := PAnsiChar(Temp); Stream.Write(Buffer^, {$IFDEF WITH_STRLEN_DEPRECATED}AnsiStrings.{$ENDIF}StrLen(Buffer)*sizeof(Ansichar)); finally Stream.Free; end; end; DoLogTrace(Event); end; end. ================================================ FILE: lib/zeosdbo/src/component/ZSqlProcessor.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Unidatabase SQLProcessor component } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZSqlProcessor; interface {$I ZComponent.inc} uses Types, Classes, SysUtils, {$IFDEF MSEgui}mclasses, mdb{$ELSE}DB{$ENDIF}, ZDbcIntfs, ZAbstractConnection, ZScriptParser, ZSqlStrings, ZCompatibility; type {** Forward definition of TZSQLProcessor. } TZSQLProcessor = class; {** Defines an error handle action. } TZErrorHandleAction = (eaFail, eaAbort, eaSkip, eaRetry); {** Defines an Processor notification event. } TZProcessorNotifyEvent = procedure(Processor: TZSQLProcessor; StatementIndex: Integer) of object; {** Defines an Processor error handling event. } TZProcessorErrorEvent = procedure(Processor: TZSQLProcessor; StatementIndex: Integer; E: Exception; var ErrorHandleAction: TZErrorHandleAction) of object; {** Implements a unidatabase component which parses and executes SQL Scripts. } { TZSQLProcessor } TZSQLProcessor = class (TComponent) private FParams: TParams; FScript: TZSQLStrings; FScriptParser: TZSQLScriptParser; FConnection: TZAbstractConnection; FBeforeExecute: TZProcessorNotifyEvent; FAfterExecute: TZProcessorNotifyEvent; FOnError: TZProcessorErrorEvent; procedure SetParams(Value: TParams); function GetScript: TStrings; procedure SetScript(Value: TStrings); function GetStatementCount: Integer; function GetStatement(Index: Integer): string; procedure SetConnection(Value: TZAbstractConnection); function GetDelimiterType: TZDelimiterType; procedure SetDelimiterType(Value: TZDelimiterType); function GetDelimiter: string; procedure SetDelimiter(const Value: string); function GetCleanupStatements: Boolean; procedure SetCleanupStatements(const Value: Boolean); function GetParamCheck: Boolean; procedure SetParamCheck(Value: Boolean); function GetParamChar: Char; procedure SetParamChar(Value: Char); procedure UpdateSQLStrings(Sender: TObject); protected procedure CheckConnected; function DoOnError(StatementIndex: Integer; E: Exception): TZErrorHandleAction; procedure DoBeforeExecute(StatementIndex: Integer); procedure DoAfterExecute(StatementIndex: Integer); function CreateStatement(const SQL: string; Properties: TStrings): IZPreparedStatement; virtual; procedure SetStatementParams(Statement: IZPreparedStatement; const ParamNames: TStringDynArray; Params: TParams); virtual; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; procedure LoadFromStream(Stream: TStream); procedure LoadFromFile(const FileName: string); procedure Execute; procedure Parse; procedure Clear; function ParamByName(const Value: string): TParam; property StatementCount: Integer read GetStatementCount; property Statements[Index: Integer]: string read GetStatement; published property ParamCheck: Boolean read GetParamCheck write SetParamCheck default True; property ParamChar: Char read GetParamChar write SetParamChar default ':'; property Params: TParams read FParams write SetParams; property Script: TStrings read GetScript write SetScript; property Connection: TZAbstractConnection read FConnection write SetConnection; property DelimiterType: TZDelimiterType read GetDelimiterType write SetDelimiterType default dtDefault; property Delimiter: string read GetDelimiter write SetDelimiter; property CleanupStatements: Boolean read GetCleanupStatements write SetCleanupStatements default False; property OnError: TZProcessorErrorEvent read FOnError write FOnError; property AfterExecute: TZProcessorNotifyEvent read FAfterExecute write FAfterExecute; property BeforeExecute: TZProcessorNotifyEvent read FBeforeExecute write FBeforeExecute; end; implementation uses ZMessages, ZDbcUtils, ZAbstractRODataset, ZDatasetUtils; { TZSQLProcessor } {** Creates this Processor component and assignes the main properties. @param AOwner an owner component. } constructor TZSQLProcessor.Create(AOwner: TComponent); begin inherited Create(AOwner); FParams := TParams.Create(Self); FScript := TZSQLStrings.Create; FScript.Dataset := Self; FScript.OnChange := UpdateSQLStrings; FScriptParser := TZSQLScriptParser.Create; FScriptParser.DelimiterType := dtDefault; FScriptParser.Delimiter := ';'; FScriptParser.CleanupStatements := False; end; {** Destroys this component and cleanups the memory. } destructor TZSQLProcessor.Destroy; begin FreeAndNil(FParams); FreeAndNil(FScript); FreeAndNil(FScriptParser); FConnection := nil; inherited Destroy; end; {** Gets a parsed statement by it's index. @return a SQL statement. } function TZSQLProcessor.GetStatement(Index: Integer): string; begin if (FScriptParser.UncompletedStatement <> '') and (Index = FScriptParser.StatementCount) then Result := FScriptParser.UncompletedStatement else Result := FScriptParser.Statements[Index]; end; {** Gets a statements count. @return a number of parsed statements. } function TZSQLProcessor.GetStatementCount: Integer; begin Result := FScriptParser.StatementCount; if FScriptParser.UncompletedStatement <> '' then Inc(Result); end; {** Sets a new SQL connection component. @param Value am SQL connection component. } procedure TZSQLProcessor.SetConnection(Value: TZAbstractConnection); begin if FConnection <> Value then begin FConnection := Value; FScriptParser.ClearUncompleted; end; end; {** Gets a script delimiter type; } function TZSQLProcessor.GetDelimiterType: TZDelimiterType; begin Result := FScriptParser.DelimiterType; end; {** Sets a new Processor delimiter type. @param Value a new Processor delimiter type. } procedure TZSQLProcessor.SetDelimiterType(Value: TZDelimiterType); begin if FScriptParser.DelimiterType <> Value then begin FScriptParser.DelimiterType := Value; FScriptParser.ClearUncompleted; end; end; {** Gets a script delimiter; } function TZSQLProcessor.GetDelimiter: string; begin Result := FScriptParser.Delimiter; end; {** Sets a new Processor delimiter. @param Value a new Processor delimiter. } procedure TZSQLProcessor.SetDelimiter(const Value: string); begin if FScriptParser.Delimiter <> Value then begin FScriptParser.Delimiter := Value; FScriptParser.ClearUncompleted; end; end; {** Sets a new set of parameters. @param Value a set of parameters. } procedure TZSQLProcessor.SetParams(Value: TParams); begin FParams.AssignValues(Value); end; {** Sets a new SQL script. @param Value a new SQL script. } procedure TZSQLProcessor.SetScript(Value: TStrings); begin FScript.Assign(Value); FScriptParser.ClearUncompleted; end; {** Checks is the database connection assignes and tries to connect. } procedure TZSQLProcessor.CheckConnected; begin if Connection = nil then raise EZDatabaseError.Create(SConnectionIsNotAssigned); Connection.Connect; end; {** Clears Processor contents and all parsed statements. } procedure TZSQLProcessor.Clear; begin FScript.Clear; FScriptParser.ClearUncompleted; end; {** Performs OnError Event and returns an error handle action. @param StatementIndex an index of the statement which failt. @param E an exception object. @return an error handle action. } function TZSQLProcessor.DoOnError(StatementIndex: Integer; E: Exception): TZErrorHandleAction; begin Result := eaFail; if Assigned(FOnError) then FOnError(Self, StatementIndex, E, Result); end; {** Performs an action before execute a statement. @param StatementIndex an index of the executing statement. } procedure TZSQLProcessor.DoBeforeExecute(StatementIndex: Integer); begin if Assigned(FBeforeExecute) then FBeforeExecute(Self, StatementIndex); end; {** Performs an action action execute a statement. @param StatementIndex an index of the executing statement. } procedure TZSQLProcessor.DoAfterExecute(StatementIndex: Integer); begin if Assigned(FAfterExecute) then FAfterExecute(Self, StatementIndex); end; {** Loads a SQL Processor from the local file. @param FileName a name of the file. } procedure TZSQLProcessor.LoadFromFile(const FileName: string); begin FScript.LoadFromFile(FileName); end; {** Loads a SQL Processor from the stream. @param Stream a stream object. } procedure TZSQLProcessor.LoadFromStream(Stream: TStream); begin FScript.LoadFromStream(Stream); end; {** Executes a parsed SQL Processor. } procedure TZSQLProcessor.Execute; var I: Integer; Statement: IZPreparedStatement; Action: TZErrorHandleAction; SQL: TZSQLStrings; begin if Connection = nil then raise EZDatabaseError.Create(SConnectionIsNotAssigned); FConnection.ShowSQLHourGlass; try SQL := TZSQLStrings.Create; SQL.Dataset := Self; SQL.ParamCheck := FScript.ParamCheck; SQL.MultiStatements := False; Parse; for I := 0 to Pred(StatementCount) do begin Action := eaSkip; DoBeforeExecute(I); repeat try SQL.Text := GetStatement(I); {http://zeos.firmos.at/viewtopic.php?t=2885&start=0&postdays=0&postorder=asc&highlight=} if SQL.StatementCount > 0 then begin Statement := CreateStatement(SQL.Statements[0].SQL, nil); SetStatementParams(Statement, SQL.Statements[0].ParamNamesArray, FParams); Statement.ExecuteUpdatePrepared; end; Statement := nil; except on E: Exception do begin if Assigned(Statement) then Statement := nil; Action := DoOnError(I, E); if Action = eaFail then RaiseSQLException(E) else if Action = eaAbort then Exit; end; end; until Action <> eaRetry; DoAfterExecute(I); end; finally FreeAndNil(SQL); Connection.HideSQLHourGlass; end; end; {** Gets a SQL parameter by its name. @param Value a parameter name. @return a found parameter object. } function TZSQLProcessor.ParamByName(const Value: string): TParam; begin Result := FParams.ParamByName(Value); end; {** Parses the loaded SQL Processor. } procedure TZSQLProcessor.Parse; begin CheckConnected; FScriptParser.Tokenizer := Connection.DbcDriver.GetTokenizer; // mdaems 20060429 : Clear would reset the delimiter of the scriptparser // FScriptParser.Clear; FScriptParser.ClearUncompleted; FScriptParser.ParseText(FScript.Text); end; {** Creates a DBC statement for the query. @param SQL an SQL query. @param Properties a statement specific properties. @returns a created DBC statement. } function TZSQLProcessor.CreateStatement(const SQL: string; Properties: TStrings): IZPreparedStatement; var Temp: TStrings; begin Temp := TStringList.Create; try if Assigned(Properties) then Temp.AddStrings(Properties); Result := FConnection.DbcConnection.PrepareStatementWithParams(SQL, Temp); finally Temp.Free; end; end; {** Fill prepared statement with parameters. @param Statement a prepared SQL statement. @param ParamNames an array of parameter names. @param Params a collection of SQL parameters. } procedure TZSQLProcessor.SetStatementParams(Statement: IZPreparedStatement; const ParamNames: TStringDynArray; Params: TParams); var I: Integer; TempParam, Param: TParam; begin TempParam := TParam.Create(nil); try for I := Low(ParamNames) to High(ParamNames) do begin Param := Params.FindParam(ParamNames[I]); if not Assigned(Param) or (Param.ParamType in [ptOutput, ptResult]) then Continue; SetStatementParam(I+1, Statement, Param); end; finally TempParam.Free; end; end; {** Gets the SQL script. @return the SQL script strings. } function TZSQLProcessor.GetScript: TStrings; begin Result := FScript; end; {** Updates parameters from SQL statement. @param Sender an event sender object. } procedure TZSQLProcessor.UpdateSQLStrings(Sender: TObject); var I: Integer; OldParams: TParams; begin OldParams := TParams.Create; OldParams.Assign(FParams); FParams.Clear; try for I := 0 to FScript.ParamCount - 1 do FParams.CreateParam(ftUnknown, FScript.ParamNames[I], ptUnknown); FParams.AssignValues(OldParams); finally OldParams.Free; end; end; {** Gets a parameters check value. @return a parameters check value. } function TZSQLProcessor.GetParamCheck: Boolean; begin Result := FScript.ParamCheck; end; {** Sets a new parameters check value. @param Value a parameters check value. } procedure TZSQLProcessor.SetParamCheck(Value: Boolean); begin FScript.ParamCheck := Value; UpdateSQLStrings(Self); end; {** Gets a parameters marker. @return a parameter marker. } function TZSQLProcessor.GetParamChar: Char; begin Result := FScript.ParamChar; end; {** Sets a new parameter marker. @param Value a parameter marker. } procedure TZSQLProcessor.SetParamChar(Value: Char); begin FScript.ParamChar := Value; UpdateSQLStrings(Self); end; function TZSQLProcessor.GetCleanupStatements: Boolean; begin Result := FScriptParser.CleanupStatements; end; procedure TZSQLProcessor.SetCleanupStatements(const Value: Boolean); begin if FScriptParser.CleanupStatements <> Value then begin FScriptParser.CleanupStatements := Value; FScriptParser.ClearUncompleted; end; end; end. ================================================ FILE: lib/zeosdbo/src/component/ZSqlStrings.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { SQL Query Strings component } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZSqlStrings; interface {$I ZComponent.inc} uses Types, Classes, SysUtils, {$IFDEF MSEgui}mclasses,{$ENDIF}Contnrs, ZDbcIntfs, ZTokenizer, ZGenericSqlToken, ZCompatibility; type {** Represents a SQL statement description object. } TZSQLStatement = class (TObject) private FSQL: string; FParamIndices: TIntegerDynArray; FParams: TStrings; function GetParamCount: Integer; function GetParamName(Index: Integer): string; function GetParamNamesArray: TStringDynArray; public constructor Create(const SQL: string; const ParamIndices: TIntegerDynArray; Params: TStrings); property SQL: string read FSQL; property ParamCount: Integer read GetParamCount; property ParamNames[Index: Integer]: string read GetParamName; property ParamIndices: TIntegerDynArray read FParamIndices; property ParamNamesArray: TStringDynArray read GetParamNamesArray; end; {** Imlements a string list with SQL statements. } { TZSQLStrings } TZSQLStrings = class (TStringList) private FDataset: TObject; FParamCheck: Boolean; FStatements: TObjectList; FParams: TStringList; FMultiStatements: Boolean; FParamChar: Char; function GetParamCount: Integer; function GetParamName(Index: Integer): string; function GetStatement(Index: Integer): TZSQLStatement; function GetStatementCount: Integer; function GetTokenizer: IZTokenizer; procedure SetDataset(Value: TObject); procedure SetParamCheck(Value: Boolean); procedure SetParamChar(Value: Char); procedure SetMultiStatements(Value: Boolean); protected procedure Changed; override; function FindParam(const ParamName: string): Integer; procedure RebuildAll; public constructor Create; destructor Destroy; override; property Dataset: TObject read FDataset write SetDataset; property ParamCheck: Boolean read FParamCheck write SetParamCheck; property ParamCount: Integer read GetParamCount; property ParamChar: Char read FParamChar write SetParamChar; property ParamNames[Index: Integer]: string read GetParamName; property StatementCount: Integer read GetStatementCount; property Statements[Index: Integer]: TZSQLStatement read GetStatement; property MultiStatements: Boolean read FMultiStatements write SetMultiStatements; end; implementation uses ZMessages, ZAbstractRODataset, ZDatasetUtils, ZSqlProcessor; { TZSQLStatement } {** Creates a SQL statement object and assignes the main properties. @param SQL a SQL statement. @param ParamIndices a parameter indices. @param Params a list with all parameter names. } constructor TZSQLStatement.Create(const SQL: string; const ParamIndices: TIntegerDynArray; Params: TStrings); begin FSQL := SQL; FParamIndices := ParamIndices; FParams := Params; end; {** Gets a parameters count for this statement. @return a parameters count. } function TZSQLStatement.GetParamCount: Integer; begin if Assigned(FParamIndices) then Result := High(FParamIndices) - Low(FParamIndices) + 1 else Result := 0; end; {** Gets a parameter name by it's index inside the statement. @return a parameter name. } function TZSQLStatement.GetParamName(Index: Integer): string; begin if Assigned(FParamIndices) then Result := FParams[FParamIndices[Index + Low(FParamIndices)]] else Result := ''; end; {** Gets an array of parameter names. @return an array of parameter names. } function TZSQLStatement.GetParamNamesArray: TStringDynArray; var I: Integer; begin SetLength(Result, High(FParamIndices) - Low(FParamIndices) + 1); for I := Low(Result) to High(Result) do Result[I] := FParams[FParamIndices[I + Low(FParamIndices)]]; end; { TZSQLStrings } {** Creates a SQL strings object and assigns the main properties. } constructor TZSQLStrings.Create; begin inherited Create; { -> needed to run the TestSuite else Inheritance(Self).Methods fails} FParams := TStringList.Create; FParamCheck := True; FStatements := TObjectList.Create; FMultiStatements := True; FParamChar :=':'; end; {** Destroys this object and cleanups the memory. } destructor TZSQLStrings.Destroy; begin FreeAndNil(FParams); FreeAndNil(FStatements); FDataSet := nil; inherited Destroy; end; {** Gets a parameter count. @return a count of SQL parameters. } function TZSQLStrings.GetParamCount: Integer; begin Result := FParams.Count; end; {** Gets parameter name by it's index. @param Index a parameter index. @return a parameter name. } function TZSQLStrings.GetParamName(Index: Integer): string; begin Result := FParams[Index]; end; {** Gets a SQL statements count. @return a SQL statements count. } function TZSQLStrings.GetStatementCount: Integer; begin Result := FStatements.Count; end; function TZSQLStrings.GetTokenizer: IZTokenizer; var Tokenizer: IZTokenizer; Driver: IZDriver; begin { Defines a SQL specific tokenizer object. } Tokenizer := CommonTokenizer; if FDataset is TZAbstractRODataset then begin if Assigned(TZAbstractRODataset(FDataset).Connection) then begin Driver := TZAbstractRODataset(FDataset).Connection.DbcDriver; if Assigned(Driver) then Tokenizer := Driver.GetTokenizer; end; end else if FDataset is TZSQLProcessor then begin if Assigned(TZSQLProcessor(FDataset).Connection) then begin Driver := TZSQLProcessor(FDataset).Connection.DbcDriver; if Assigned(Driver) then Tokenizer := Driver.GetTokenizer; end; end; Result:=Tokenizer; end; {** Gets a SQL statement by it's index. @param Index a SQL statement index. @return a SQL statement object. } function TZSQLStrings.GetStatement(Index: Integer): TZSQLStatement; begin Result := TZSQLStatement(FStatements[Index]); end; {** Sets a new ParamCheck value. @param Value a new ParamCheck value. } procedure TZSQLStrings.SetParamCheck(Value: Boolean); begin if FParamCheck <> Value then begin FParamCheck := Value; RebuildAll; end; end; {** Sets a new ParamChar value. @param Value a new ParamCheck value. } procedure TZSQLStrings.SetParamChar(Value: Char); begin if FParamChar <> Value then begin If not(GetTokenizer.GetCharacterState(Value) is TZSymbolstate) Then raise EZDatabaseError.Create('Ongeldige ParamChar waarde : '+Value); FParamChar := Value; RebuildAll; end; end; {** Sets a new MultiStatements value. @param Value a new MultiStatements value. } procedure TZSQLStrings.SetMultiStatements(Value: Boolean); begin if FMultiStatements <> Value then begin FMultiStatements := Value; RebuildAll; end; end; {** Sets a new correspondent dataset object. @param Value a new dataset object. } procedure TZSQLStrings.SetDataset(Value: TObject); begin if FDataset <> Value then begin FDataset := Value; RebuildAll; end; end; {** Finds a parameter by it's name. @param ParamName a parameter name. @return an index of found parameters or -1 if nothing was found. } function TZSQLStrings.FindParam(const ParamName: string): Integer; begin FParams.CaseSensitive := False; Result := FParams.IndexOf(ParamName); end; {** Rebuilds all SQL statements. } procedure TZSQLStrings.RebuildAll; var Tokens: TStrings; TokenValue: string; TokenType: TZTokenType; TokenIndex: Integer; ParamIndex: Integer; ParamIndices: TIntegerDynArray; ParamIndexCount: Integer; ParamName, SQL: string; Tokenizer: IZTokenizer; procedure NextToken; begin TokenType := TZTokenType({$IFDEF FPC}Pointer({$ENDIF} Tokens.Objects[TokenIndex]{$IFDEF FPC}){$ENDIF}); TokenValue := Tokens[TokenIndex]; Inc(TokenIndex); end; begin if not (Assigned(FParams) and Assigned(FStatements)) then exit; //Alexs FParams.Clear; FStatements.Clear; SQL := ''; ParamIndexCount := 0; SetLength(ParamIndices, ParamIndexCount); { Optimization for empty query. } If Length(Trim(Text)) = 0 then Exit; { Optimization for single query without parameters. } if (not FParamCheck or (Pos(FParamChar, Text) = 0)) and (not FMultiStatements or (Pos(';', Text) = 0)) then begin FStatements.Add(TZSQLStatement.Create(Text, ParamIndices, FParams)); Exit; end; Tokenizer:=GetTokenizer; Tokens := Tokenizer.TokenizeBufferToList(Text, [toSkipComments, toUnifyWhitespaces]); try TokenIndex := 0; repeat NextToken; { Processes parameters. } if ParamCheck and (TokenValue = FParamChar) then begin NextToken; if (TokenType <> ttEOF) and (TokenValue <> FParamChar) then begin { Check for correct parameter type. } if not (TokenType in [ttWord, ttQuoted, ttQuotedIdentifier, ttKeyWord]) then raise EZDatabaseError.Create(SIncorrectToken); SQL := SQL + '?'; ParamName := TokenValue; if (ParamName <> '') and CharInSet(ParamName[1], [#39, '`', '"', '[']) then begin ParamName := Tokenizer.GetQuoteState. DecodeString(ParamName, ParamName[1]); end; ParamIndex := FindParam(ParamName); if ParamIndex < 0 then ParamIndex := FParams.Add(ParamName); Inc(ParamIndexCount); SetLength(ParamIndices, ParamIndexCount); ParamIndices[ParamIndexCount - 1] := ParamIndex; Continue; end; end; { Adds a DML statement. } if (TokenType = ttEOF) or (FMultiStatements and (TokenValue = ';')) then begin SQL := Trim(SQL); if SQL <> '' then FStatements.Add(TZSQLStatement.Create(SQL, ParamIndices, FParams)); SQL := ''; ParamIndexCount := 0; SetLength(ParamIndices, ParamIndexCount); end { Adds a default token. } else SQL := SQL + TokenValue; until TokenType = ttEOF; finally Tokens.Free; end; end; {** Performs action when the content of this string list is changed. } procedure TZSQLStrings.Changed; begin if UpdateCount = 0 then RebuildAll; inherited Changed; end; end. ================================================ FILE: lib/zeosdbo/src/component/ZSqlTestForm.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { SQL Monitor component } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZSqlTestForm; {$I ZComponent.inc} interface uses {$IFDEF MSWINDOWS} Windows, Messages, {$ENDIF} Classes, SysUtils, Forms, Controls, Graphics, Dialogs, ExtCtrls, DBGrids, Buttons, DB, ZDataset, ZMessages; type { TZeosSQLEditorTestForm } TZeosSQLEditorTestForm = class(TForm) private { private declarations } Button1: TButton; Datasource1: TDatasource; dbGrid1: TdbGrid; Panel1: TPanel; public { public declarations } ZeosSQL: TZReadOnlyQuery; constructor Create(AOwner: TComponent); end; var ZeosSQLEditorTestForm: TZeosSQLEditorTestForm; implementation constructor TZeosSQLEditorTestForm.Create(AOwner: TComponent); begin inherited Create(AOwner); Caption := SFormTest; ClientHeight := 300; ClientWidth := 683; Height := 300; Left := 291; Top := 323; Width := 683; ZeosSQL := TZReadOnlyQuery.Create(self); Datasource1 := TDataSource.Create(self); Datasource1.DataSet := ZeosSQL; Panel1 := TPanel.Create(self); with Panel1 do begin Parent := self; Anchors := [akTop,akLeft,akRight]; Align := alTop; Left :=0; Height := 42; Top := 0; Width := 683; TabStop := False; end; Button1 := TButton.Create(self); with Button1 do begin Parent := Panel1; Anchors := [akTop,akLeft]; Cancel := True; Default := True; ModalResult := mrOk; Caption := SButtonClose; Left := 600; Height := 25; Top := 8; Width := 75; TabOrder := 0; TabStop := True; end; dbGrid1 := TdbGrid.Create(self); with dbGrid1 do begin Parent := self; Anchors := [akTop,akLeft,akRight,akBottom]; DataSource := Datasource1; Options := [dgTitles,dgIndicator,dgColumnResize,dgColLines,dgRowLines, dgTabs,dgAlwaysShowSelection,dgConfirmDelete,dgCancelOnExit]; ReadOnly := True; Align := alClient; DefaultRowHeight := 24; Left := 0; Height := 258; TabOrder := 1; TabStop := True; Top := 42; Width := 683; end; end; end. ================================================ FILE: lib/zeosdbo/src/component/ZSqlUpdate.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Unidatabase UpdateSQL component } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZSqlUpdate; interface {$I ZComponent.inc} uses SysUtils, Classes, {$IFDEF MSEgui}mclasses, mdb{$ELSE}DB{$ENDIF}, ZDbcIntfs, ZDbcCachedResultSet, ZDbcCache, ZSqlStrings; type {ADDED BY fduenas} TZBeforeSQLStatementEvent = procedure(const Sender: TObject; StatementIndex: Integer; out Execute: Boolean ) of object; TZAfterSQLStatementEvent = procedure(const Sender: TObject; StatementIndex: Integer) of object; TZAfterInsertSQLStatementEvent = procedure(const Sender: TObject; StatementIndex: Integer; out UpdateAutoIncFields: Boolean ) of object; {** Implements an object which manages SQL DML statements to update TDatasets. } TZUpdateSQL = class(TComponent, IZCachedResolver) private FDataSet: TDataSet; FDeleteSQL: TZSQLStrings; FInsertSQL: TZSQLStrings; FModifySQL: TZSQLStrings; //FOSPATCH FRefreshSQL: TZSQLStrings; //FOSPATCH FParamCheck: Boolean; FParams: TParams; FMultiStatements: Boolean; FBeforeDeleteSQL: TNotifyEvent; FBeforeInsertSQL: TNotifyEvent; FBeforeModifySQL: TNotifyEvent; FAfterDeleteSQL: TNotifyEvent; FAfterInsertSQL: TNotifyEvent; FAfterModifySQL: TNotifyEvent; FUseSequenceFieldForRefreshSQL: Boolean; {New Statement Events added by Fduenas} FBeforeDeleteSQLStatement: TZBeforeSQLStatementEvent; FAfterDeleteSQLStatement: TZAfterSQLStatementEvent; FBeforeInsertSQLStatement: TZBeforeSQLStatementEvent; FAfterInsertSQLStatement: TZAfterInsertSQLStatementEvent; FBeforeModifySQLStatement: TZBeforeSQLStatementEvent; FAfterModifySQLStatement: TZAfterSQLStatementEvent; procedure SetUseSequenceFieldForRefreshSQL(const Value: Boolean); procedure SetDataset(Value: TDataset); function GetSQL(UpdateKind: TUpdateKind): TStrings; procedure SetSQL(UpdateKind: TUpdateKind; Value: TStrings); function GetParamsCount: Word; procedure SetParamsList(Value: TParams); procedure SetParamCheck(Value: Boolean); procedure SetMultiStatements(Value: Boolean); function GetDeleteSQL: TStrings; procedure SetDeleteSQL(Value: TStrings); function GetInsertSQL: TStrings; procedure SetInsertSQL(Value: TStrings); function GetModifySQL: TStrings; procedure SetModifySQL(Value: TStrings); //FOSPATCH function GetRefreshSQL: TStrings; procedure SetRefreshSQL(Value: TStrings); //FOSPATCH procedure ReadParamData(Reader: TReader); procedure WriteParamData(Writer: TWriter); protected procedure Apply_RefreshResultSet(const Sender:IZCachedResultSet;const RefreshResultSet: IZResultSet;const RefreshRowAccessor:TZRowAccessor); procedure DefineProperties(Filer: TFiler); override; procedure CalculateDefaults(Sender: IZCachedResultSet; RowAccessor: TZRowAccessor); procedure PostUpdates(Sender: IZCachedResultSet; UpdateType: TZRowUpdateType; OldRowAccessor, NewRowAccessor: TZRowAccessor); {BEGIN of PATCH [1185969]: Do tasks after posting updates. ie: Updating AutoInc fields in MySQL } procedure UpdateAutoIncrementFields(Sender: IZCachedResultSet; UpdateType: TZRowUpdateType; OldRowAccessor, NewRowAccessor: TZRowAccessor; Resolver: IZCachedResolver); {END of PATCH [1185969]: Do tasks after posting updates. ie: Updating AutoInc fields in MySQL } procedure RefreshCurrentRow(Sender: IZCachedResultSet;RowAccessor: TZRowAccessor);//FOS+ 07112006 procedure Rebuild(SQLStrings: TZSQLStrings); procedure RebuildAll; procedure FillStatement(ResultSet: IZCachedResultSet; Statement: IZPreparedStatement; Config: TZSQLStatement; OldRowAccessor, NewRowAccessor: TZRowAccessor); procedure UpdateParams(Sender: TObject); procedure DoBeforeDeleteSQL; procedure DoBeforeInsertSQL; procedure DoBeforeModifySQL; procedure DoAfterDeleteSQL; procedure DoAfterInsertSQL; procedure DoAfterModifySQL; procedure DoBeforeDeleteSQLStatement(const Sender: TObject; StatementIndex: Integer; out Execute: Boolean); procedure DoBeforeInsertSQLStatement(const Sender: TObject; StatementIndex: Integer; out Execute: Boolean); procedure DoBeforeModifySQLStatement(const Sender: TObject; StatementIndex: Integer; out Execute: Boolean); procedure DoAfterDeleteSQLStatement(const Sender: TObject; StatementIndex: Integer); procedure DoAfterInsertSQLStatement(const Sender: TObject; StatementIndex: Integer; out UpdateAutoIncFields: Boolean) ; procedure DoAfterModifySQLStatement(const Sender: TObject; StatementIndex: Integer); public constructor Create(AOwner: TComponent); override; destructor Destroy; override; property SQL[UpdateKind: TUpdateKind]: TStrings read GetSQL write SetSQL; property ParamCount: Word read GetParamsCount; property DataSet: TDataSet read FDataSet write SetDataSet; published property DeleteSQL: TStrings read GetDeleteSQL write SetDeleteSQL; property InsertSQL: TStrings read GetInsertSQL write SetInsertSQL; property ModifySQL: TStrings read GetModifySQL write SetModifySQL; //FOSPATCH property RefreshSQL: TStrings read GetRefreshSQL write SetRefreshSQL; //FOSPATCH property UseSequenceFieldForRefreshSQL:Boolean read FUseSequenceFieldForRefreshSQL write SetUseSequenceFieldForRefreshSQL; property Params: TParams read FParams write SetParamsList stored False; property ParamCheck: Boolean read FParamCheck write SetParamCheck default True; property MultiStatements: Boolean read FMultiStatements write SetMultiStatements default True; property BeforeDeleteSQL: TNotifyEvent read FBeforeDeleteSQL write FBeforeDeleteSQL; property BeforeInsertSQL: TNotifyEvent read FBeforeInsertSQL write FBeforeInsertSQL; property BeforeModifySQL: TNotifyEvent read FBeforeModifySQL write FBeforeModifySQL; property AfterDeleteSQL: TNotifyEvent read FAfterDeleteSQL write FAfterDeleteSQL; property AfterInsertSQL: TNotifyEvent read FAfterInsertSQL write FAfterInsertSQL; property AfterModifySQL: TNotifyEvent read FAfterModifySQL write FAfterModifySQL; {New Events Fired by executed Statement} property BeforeDeleteSQLStatement: TZBeforeSQLStatementEvent read FBeforeDeleteSQLStatement write FBeforeDeleteSQLStatement; property BeforeInsertSQLStatement: TZBeforeSQLStatementEvent read FBeforeInsertSQLStatement write FBeforeInsertSQLStatement; property BeforeModifySQLStatement: TZBeforeSQLStatementEvent read FBeforeModifySQLStatement write FBeforeModifySQLStatement; property AfterDeleteSQLStatement: TZAfterSQLStatementEvent read FAfterDeleteSQLStatement write FAfterDeleteSQLStatement; property AfterInsertSQLStatement: TZAfterInsertSQLStatementEvent read FAfterInsertSQLStatement write FAfterInsertSQLStatement; property AfterModifySQLStatement: TZAfterSQLStatementEvent read FAfterModifySQLStatement write FAfterModifySQLStatement; end; implementation uses ZGenericSqlToken, ZDatasetUtils, ZAbstractRODataset,ZAbstractDataset, ZSysUtils, ZDbcUtils,ZMessages; { TZUpdateSQL } {** Constructs this object and assignes main properties. @param AOwner a component owner. } constructor TZUpdateSQL.Create(AOwner: TComponent); begin inherited Create(AOwner); FDeleteSQL := TZSQLStrings.Create; FDeleteSQL.OnChange := UpdateParams; FInsertSQL := TZSQLStrings.Create; FInsertSQL.OnChange := UpdateParams; FModifySQL := TZSQLStrings.Create; FModifySQL.OnChange := UpdateParams; //FOSPATCH FRefreshSQL := TZSQLStrings.Create; FRefreshSQL.OnChange:= UpdateParams; //FOSPATCH FParams := TParams.Create(Self); FParamCheck := True; FMultiStatements := True; end; {** Destroys this object and cleanups the memory. } destructor TZUpdateSQL.Destroy; begin FParams.Free; FDeleteSQL.Free; FInsertSQL.Free; FModifySQL.Free; FRefreshSQL.Free; inherited Destroy; end; {** Store the related dataset object for update sql editor } procedure TZUpdateSQL.SetDataset(Value: TDataset); begin FDataSet := Value; FDeleteSQL.Dataset := Value; FInsertSQL.Dataset := Value; FModifySQL.Dataset := Value; end; {** Gets a DML statements for specified action. @param UpdateKind a type of the DML statements. @return a stored DML statement. } function TZUpdateSQL.GetSQL(UpdateKind: TUpdateKind): TStrings; begin case UpdateKind of ukModify: Result := FModifySQL; ukInsert: Result := FInsertSQL; else Result := FDeleteSQL; end; end; {** Sets a DML statements for specified action. @param UpdateKind a type of the DML statements. @param Value a DML statements to be set. } procedure TZUpdateSQL.SetSQL(UpdateKind: TUpdateKind; Value: TStrings); begin case UpdateKind of ukModify: FModifySQL.Assign(Value); ukInsert: FInsertSQL.Assign(Value); ukDelete: FDeleteSQL.Assign(Value); end; end; {** Get parameters count. @return a parameters count. } function TZUpdateSQL.GetParamsCount: Word; begin Result := FParams.Count; end; function TZUpdateSQL.GetRefreshSQL: TStrings; begin Result := FRefreshSQL; end; {** Sets parameters checking flag. @param Value a new parameters checking flag. } procedure TZUpdateSQL.SetParamCheck(Value: Boolean); begin if FParamCheck <> Value then begin FParamCheck := Value; FModifySQL.ParamCheck := Value; FInsertSQL.ParamCheck := Value; FDeleteSQL.ParamCheck := Value; RebuildAll; end; end; {** Sets multiple statements flag. @param Value a new multiple statements flag. } procedure TZUpdateSQL.SetMultiStatements(Value: Boolean); begin if FMultiStatements <> Value then begin FMultiStatements := Value; FModifySQL.MultiStatements := Value; FInsertSQL.MultiStatements := Value; FDeleteSQL.MultiStatements := Value; RebuildAll; end; end; {** Set a new list of SQL parameters. @param Value a new list of SQL parameters. } procedure TZUpdateSQL.SetParamsList(Value: TParams); begin FParams.AssignValues(Value); end; procedure TZUpdateSQL.SetRefreshSQL(Value: TStrings); begin FRefreshSQL.Assign(Value); end; procedure TZUpdateSQL.SetUseSequenceFieldForRefreshSQL(const Value: Boolean); begin FUseSequenceFieldForRefreshSQL := Value; end; {** Defines a persistent dataset properties. @param Filer a persistent manager object. } procedure TZUpdateSQL.DefineProperties(Filer: TFiler); function WriteData: Boolean; begin if Filer.Ancestor <> nil then Result := not FParams.IsEqual(TZUpdateSQL(Filer.Ancestor).FParams) else Result := FParams.Count > 0; end; begin inherited DefineProperties(Filer); Filer.DefineProperty('ParamData', ReadParamData, WriteParamData, WriteData); end; {** Reads parameter data from persistent storage. @param Reader an input data stream. } procedure TZUpdateSQL.ReadParamData(Reader: TReader); begin Reader.ReadValue; Reader.ReadCollection(FParams); end; {** Writes parameter data from persistent storage. @param Writer an output data stream. } procedure TZUpdateSQL.WriteParamData(Writer: TWriter); begin Writer.WriteCollection(Params); end; {** Gets strings with Delete statements. @return strings with Delete statements. } function TZUpdateSQL.GetDeleteSQL: TStrings; begin Result := FDeleteSQL; end; {** Sets a new Delete SQL statement. @param Value a new Delete SQL statement. } procedure TZUpdateSQL.SetDeleteSQL(Value: TStrings); begin FDeleteSQL.Assign(Value); end; {** Gets strings with Insert statements. @return strings with Insert statements. } function TZUpdateSQL.GetInsertSQL: TStrings; begin Result := FInsertSQL; end; {** Sets a new Insert SQL statement. @param Value a new Insert SQL statement. } procedure TZUpdateSQL.SetInsertSQL(Value: TStrings); begin FInsertSQL.Assign(Value); end; {** Gets strings with Modify statements. @return strings with Modify statements. } function TZUpdateSQL.GetModifySQL: TStrings; begin Result := FModifySQL; end; {** Sets a new Modify SQL statement. @param Value a new Modify SQL statement. } procedure TZUpdateSQL.SetModifySQL(Value: TStrings); begin FModifySQL.Assign(Value); end; {** Updates all parameters. @param Sender an event sender object. } procedure TZUpdateSQL.UpdateParams(Sender: TObject); begin RebuildAll; end; {** Rebuilds parameters and inserts a new one from specified sql statements. @param SQLStrings a strings with SQL statements. } procedure TZUpdateSQL.Rebuild(SQLStrings: TZSQLStrings); var I: Integer; begin for I := 0 to SQLStrings.ParamCount - 1 do begin if FParams.FindParam(SQLStrings.ParamNames[I]) = nil then FParams.CreateParam(ftUnknown, SQLStrings.ParamNames[I], ptUnknown); end; end; {** Rebuilds all internal structures including parameters from SQL statements. } procedure TZUpdateSQL.RebuildAll; var OldParams: TParams; begin OldParams := TParams.Create; OldParams.Assign(FParams); FParams.Clear; try Rebuild(FModifySQL); Rebuild(FInsertSQL); Rebuild(FDeleteSQL); //FOSPATCH Rebuild(FRefreshSQL); //FOSPATCH FParams.AssignValues(OldParams); finally OldParams.Free; end; end; procedure TZUpdateSQL.RefreshCurrentRow(Sender: IZCachedResultSet; RowAccessor: TZRowAccessor); var Config: TZSQLStrings; Statement: IZPreparedStatement; RefreshResultSet: IZResultSet; begin Config:=FRefreshSQL; if CONFIG.StatementCount=1 then begin Statement := Sender.GetStatement.GetConnection.PrepareStatement(Config.Statements[0].SQL); FillStatement(Sender, Statement, Config.Statements[0],RowAccessor, RowAccessor); RefreshResultSet:=Statement.ExecuteQueryPrepared; Apply_RefreshResultSet(Sender,RefreshResultSet,RowAccessor); end; end; {** Fills the specified statement with stored or given parameters. @param ResultSet a source result set object. @param Statement a DBC statement object. @param Config a SQLStatement configuration. @param OldRowAccessor an accessor object to old column values. @param NewRowAccessor an accessor object to new column values. } procedure TZUpdateSQL.FillStatement(ResultSet: IZCachedResultSet; Statement: IZPreparedStatement; Config: TZSQLStatement; OldRowAccessor, NewRowAccessor: TZRowAccessor); var I, ColumnIndex: Integer; ParamValue: TParam; ParamName: string; OldParam: Boolean; WasNull: Boolean; RowAccessor: TZRowAccessor; TempBlob: IZBlob; begin WasNull := False; for I := 0 to Config.ParamCount - 1 do begin ParamValue := Params.FindParam(Config.ParamNames[I]); ParamName := Config.ParamNames[I]; OldParam := False;{Seqparam:=False;} if StrLIComp(PChar(ParamName), 'NEW_', 4) = 0 then begin ParamName := Copy(ParamName, 5, Length(ParamName) - 4) end else if StrLIComp(PChar(ParamName), 'OLD_', 4) = 0 then begin ParamName := Copy(ParamName, 5, Length(ParamName) - 4); OldParam := True; end; ColumnIndex := ResultSet.FindColumn(ParamName); if ColumnIndex > 0 then begin if OldParam then RowAccessor := OldRowAccessor else RowAccessor := NewRowAccessor; if StrToBoolEx(DefineStatementParameter( ResultSet.GetStatement, 'defaults', 'true')) then Statement.SetDefaultValue(I + 1, ResultSet.GetMetadata.GetDefaultValue(ColumnIndex)); case ResultSet.GetMetadata.GetColumnType(ColumnIndex) of stBoolean: Statement.SetBoolean(I + 1, RowAccessor.GetBoolean(ColumnIndex, WasNull)); stByte: Statement.SetByte(I + 1, RowAccessor.GetByte(ColumnIndex, WasNull)); stShort: Statement.SetShort(I + 1, RowAccessor.GetShort(ColumnIndex, WasNull)); stInteger: Statement.SetInt(I + 1, RowAccessor.GetInt(ColumnIndex, WasNull)); stLong: Statement.SetLong(I + 1, RowAccessor.GetLong(ColumnIndex, WasNull)); stFloat: Statement.SetFloat(I + 1, RowAccessor.GetFloat(ColumnIndex, WasNull)); stDouble: Statement.SetDouble(I + 1, RowAccessor.GetDouble(ColumnIndex, WasNull)); stBigDecimal: Statement.SetBigDecimal(I + 1, RowAccessor.GetBigDecimal(ColumnIndex, WasNull)); stString: Statement.SetString(I + 1, RowAccessor.GetString(ColumnIndex, WasNull)); //smells like DataLoss stUnicodeString: Statement.SetUnicodeString(I + 1, RowAccessor.GetUnicodeString(ColumnIndex, WasNull)); stBytes: Statement.SetBytes(I + 1, RowAccessor.GetBytes(ColumnIndex, WasNull)); stDate: Statement.SetDate(I + 1, RowAccessor.GetDate(ColumnIndex, WasNull)); stTime: Statement.SetTime(I + 1, RowAccessor.GetTime(ColumnIndex, WasNull)); stTimestamp: Statement.SetTimestamp(I + 1, RowAccessor.GetTimestamp(ColumnIndex, WasNull)); stAsciiStream: begin TempBlob := RowAccessor.GetBlob(ColumnIndex, WasNull); if not TempBlob.IsEmpty then Statement.SetBlob(I + 1, stAsciiStream, TempBlob) else Statement.SetNull(I + 1, stAsciiStream); end; stUnicodeStream: begin TempBlob := RowAccessor.GetBlob(ColumnIndex, WasNull); if not TempBlob.IsEmpty then Statement.SetBlob(I + 1, stUnicodeStream, TempBlob) else Statement.SetNull(I + 1, stUnicodeStream); end; stBinaryStream: begin TempBlob := RowAccessor.GetBlob(ColumnIndex, WasNull); if not TempBlob.IsEmpty then Statement.SetBlob(I + 1, stBinaryStream, TempBlob) else Statement.SetNull(I + 1, stBinaryStream); end; end; if WasNull then begin Statement.SetNull(I + 1, ResultSet.GetMetadata.GetColumnType(ColumnIndex)) end; end else SetStatementParam(I+1, Statement, ParamValue); end; end; {** Apply the Refreshed values. @param RefreshResultSet a result set object. @param RefreshRowAccessor an accessor object to column values. } procedure TZUpdateSQL.Apply_RefreshResultSet(const Sender:IZCachedResultSet; const RefreshResultSet: IZResultSet; const RefreshRowAccessor: TZRowAccessor); var I: Integer; RefreshColumnIndex:integer; RefreshColumnName:String; RefreshColumnType:TZSQLType; begin if Assigned(RefreshResultSet) then begin if not RefreshResultSet.First then begin raise EZDatabaseError.Create(SUpdateSQLNoResult); end; for I := 1 to RefreshResultSet.GetMetadata.GetColumnCount do begin RefreshColumnName:=RefreshResultSet.GetMetadata.GetColumnLabel(I); // What Column from Resultset should be updated RefreshColumnIndex := Sender.FindColumn(RefreshColumnName); // Is the Column available in the select ? if RefreshColumnIndex=0 then begin continue; // Column not found in Select from Dataset end; if RefreshResultSet.IsNull(I) then begin RefreshRowAccessor.SetNull(RefreshColumnIndex); end else begin RefreshColumnType := RefreshResultSet.GetMetadata.GetColumnType(I); // Type of Column ? case RefreshColumnType of stBoolean: RefreshRowAccessor.SetBoolean(RefreshColumnIndex, RefreshResultSet.GetBoolean(I)); stByte: RefreshRowAccessor.SetByte(RefreshColumnIndex, RefreshResultSet.GetByte(I)); stShort: RefreshRowAccessor.SetShort(RefreshColumnIndex, RefreshResultSet.GetShort(I)); stInteger: RefreshRowAccessor.SetInt(RefreshColumnIndex, RefreshResultSet.GetInt(I)); stLong: RefreshRowAccessor.SetLong(RefreshColumnIndex, RefreshResultSet.GetLong(I)); stFloat: RefreshRowAccessor.SetFloat(RefreshColumnIndex, RefreshResultSet.GetFloat(I)); stDouble: RefreshRowAccessor.SetDouble(RefreshColumnIndex, RefreshResultSet.GetDouble(I)); stBigDecimal: RefreshRowAccessor.SetBigDecimal(RefreshColumnIndex, RefreshResultSet.GetBigDecimal(I)); // gto: do we need PChar here? //stString: RefreshRowAccessor.SetPChar(RefreshColumnIndex, RefreshResultSet.GetPChar(I)); stString: RefreshRowAccessor.SetString(RefreshColumnIndex, String(RefreshResultSet.GetString(I))); stUnicodeString: RefreshRowAccessor.SetUnicodeString(RefreshColumnIndex, RefreshResultSet.GetUnicodeString(I)); stBytes: RefreshRowAccessor.SetBytes(RefreshColumnIndex, RefreshResultSet.GetBytes(I)); stDate: RefreshRowAccessor.SetDate(RefreshColumnIndex, RefreshResultSet.GetDate(I)); stTime: RefreshRowAccessor.SetTime(RefreshColumnIndex, RefreshResultSet.GetTime(I)); stTimestamp: RefreshRowAccessor.SetTimestamp(RefreshColumnIndex, RefreshResultSet.GetTimestamp(I)); stAsciiStream, stUnicodeStream, stBinaryStream:RefreshRowAccessor.SetBlob(RefreshColumnIndex, RefreshResultSet.GetBlob(I)); end; end; end; end; end; {** Calculate default values for the fields. @param Sender a cached result set object. @param RowAccessor an accessor object to column values. } procedure TZUpdateSQL.CalculateDefaults(Sender: IZCachedResultSet; RowAccessor: TZRowAccessor); begin {BEGIN PATCH [1214009] TZUpdateSQL - implemented feature to Calculate default values} Sender.GetNativeResolver.CalculateDefaults(Sender, RowAccessor); {END PATCH [1214009] TZUpdateSQL - implemented feature to Calculate default values} end; {** Posts updates to database. @param Sender a cached result set object. @param UpdateType a type of updates. @param OldRowAccessor an accessor object to old column values. @param NewRowAccessor an accessor object to new column values. } procedure TZUpdateSQL.PostUpdates(Sender: IZCachedResultSet; UpdateType: TZRowUpdateType; OldRowAccessor, NewRowAccessor: TZRowAccessor); var I: Integer; Statement: IZPreparedStatement; Config: TZSQLStrings; CalcDefaultValues, ExecuteStatement, UpdateAutoIncFields: Boolean; Refresh_OldSQL:String; RefreshResultSet: IZResultSet; lValidateUpdateCount : Boolean; lUpdateCount : Integer; begin if (UpdateType = utDeleted) and (OldRowAccessor.RowBuffer.UpdateType = utInserted) then Exit; case UpdateType of utInserted: Config := FInsertSQL; utDeleted: Config := FDeleteSQL; utModified: Config := FModifySQL; else Exit; end; case UpdateType of utInserted: DoBeforeInsertSQL; utDeleted: DoBeforeDeleteSQL; utModified: DoBeforeModifySQL; end; if Dataset is TZAbstractRODataset then (Dataset as TZAbstractRODataset).Connection.ShowSqlHourGlass; CalcDefaultValues := ZSysUtils.StrToBoolEx(DefineStatementParameter(Sender.GetStatement,'defaults','true')); try for I := 0 to Config.StatementCount - 1 do begin Statement := Sender.GetStatement.GetConnection. PrepareStatement(Config.Statements[I].SQL); FillStatement(Sender, Statement, Config.Statements[I], OldRowAccessor, NewRowAccessor); {BEGIN of PATCH [1185969]: Do tasks after posting updates. ie: Updating AutoInc fields in MySQL } {Update AutoInc Field Tasks will be only executed if the UpdateAutoIncFields in the AfterInsertSQLStatement event returns true } ExecuteStatement := true; UpdateAutoIncFields := false; case UpdateType of utDeleted: DoBeforeDeleteSQLStatement(Self, I, ExecuteStatement); utInserted: DoBeforeInsertSQLStatement(Self, I, ExecuteStatement); utModified: DoBeforeModifySQLStatement(Self, I, ExecuteStatement); end; if ExecuteStatement then begin lValidateUpdateCount := StrToBoolEx( Sender.GetStatement.GetParameters.Values['ValidateUpdateCount']); lUpdateCount := Statement.ExecuteUpdatePrepared; if (lValidateUpdateCount) and (lUpdateCount <> 1) then raise EZSQLException.Create(Format(SInvalidUpdateCount, [lUpdateCount])); case UpdateType of utDeleted: DoAfterDeleteSQLStatement(Self, I); utInserted: begin DoAfterInsertSQLStatement(Self, I, UpdateAutoIncFields); if CalcDefaultValues and UpdateAutoIncFields then UpdateAutoIncrementFields(Sender, UpdateType, OldRowAccessor, NewRowAccessor, Self); end; utModified: DoAfterModifySQLStatement(Self,I); end; end; {END of PATCH [1185969]: Do tasks after posting updates. ie: Updating AutoInc fields in MySQL } end; //FOSPATCH case UpdateType of utInserted,utModified: begin if FRefreshSql.Text<>'' then begin Refresh_OldSQL:=FRefreshSql.Text; try Config:=FRefreshSQL; if UpdateType=utInserted then begin if Dataset is TZAbstractDataset then begin if FUseSequenceFieldForRefreshSQL then begin if assigned(TZAbstractDataset(DataSet).Sequence) and (TZAbstractDataset(DataSet).SequenceField<>'') then begin Config.Text := StringReplace(UpperCase(Config.Text), ':OLD_'+UpperCase(TZAbstractDataset(DataSet).SequenceField), TZAbstractDataset(DataSet).Sequence.GetCurrentValueSQL,[rfReplaceAll]); end; end; end; end; if CONFIG.StatementCount=1 then begin Statement := Sender.GetStatement.GetConnection.PrepareStatement(Config.Statements[0].SQL); FillStatement(Sender, Statement, Config.Statements[0],OldRowAccessor, NewRowAccessor); RefreshResultSet:=Statement.ExecuteQueryPrepared; Apply_RefreshResultSet(Sender,RefreshResultSet,NewRowAccessor); end; finally FRefreshSQL.Text:=Refresh_OldSQL; end; end; end; end; //FOSPATCH finally if Dataset is TZAbstractRODataset then (Dataset as TZAbstractRODataset).Connection.HideSQLHourGlass; end; case UpdateType of utInserted: DoAfterInsertSQL; utDeleted: DoAfterDeleteSQL; utModified: DoAfterModifySQL; end; end; {** Fires an event before delete Statement } procedure TZUpdateSQL.DoBeforeDeleteSQL; begin if Assigned(FBeforeDeleteSQL) then FBeforeDeleteSQL(Self); end; {** Fires an event before insert Statement } procedure TZUpdateSQL.DoBeforeInsertSQL; begin if Assigned(BeforeInsertSQL) then FBeforeInsertSQL(Self); end; {** Fires an event before modify Statement } procedure TZUpdateSQL.DoBeforeModifySQL; begin if Assigned(FBeforeModifySQL) then FBeforeModifySQL(Self); end; {** Fires an event after delete Statement } procedure TZUpdateSQL.DoAfterDeleteSQL; begin if Assigned(FAfterDeleteSQL) then FAfterDeleteSQL(Self); end; {** Fires an event after insert Statement } procedure TZUpdateSQL.DoAfterInsertSQL; begin if Assigned(FAfterInsertSQL) then FAfterInsertSQL(Self); end; {** Fires an event after modify Statement } procedure TZUpdateSQL.DoAfterModifySQL; begin if Assigned(FAfterModifySQL) then FAfterModifySQL(Self); end; {BEGIN of PATCH [1185969]: Do tasks after posting updates. ie: Updating AutoInc fields in MySQL } procedure TZUpdateSQL.UpdateAutoIncrementFields(Sender: IZCachedResultSet; UpdateType: TZRowUpdateType; OldRowAccessor, NewRowAccessor: TZRowAccessor; Resolver: IZCachedResolver); begin with Sender.GetNativeResolver do begin UpdateAutoIncrementFields(Sender, UpdateType, OldRowAccessor, NewRowAccessor, Resolver); end; end; {END of PATCH [1185969]: Do tasks after posting updates. ie: Updating AutoInc fields in MySQL } {NEW Methods for Events to validate at Statement level } procedure TZUpdateSQL.DoAfterDeleteSQLStatement(const Sender: TObject; StatementIndex: Integer); begin if Assigned(FAfterDeleteSQLStatement) then FAfterDeleteSQLStatement(Self, StatementIndex); end; procedure TZUpdateSQL.DoAfterInsertSQLStatement(const Sender: TObject; StatementIndex: Integer; out UpdateAutoIncFields: Boolean); begin if Assigned(FAfterInsertSQLStatement) then FAfterInsertSQLStatement(Self, StatementIndex, UpdateAutoIncFields); end; procedure TZUpdateSQL.DoAfterModifySQLStatement(const Sender: TObject; StatementIndex: Integer); begin if Assigned(FAfterModifySQLStatement) then FAfterModifySQLStatement(Self, StatementIndex); end; procedure TZUpdateSQL.DoBeforeDeleteSQLStatement(const Sender: TObject; StatementIndex: Integer; out Execute: Boolean); begin if Assigned(FBeforeDeleteSQLStatement) then FBeforeDeleteSQLStatement(Self, StatementIndex, Execute); end; procedure TZUpdateSQL.DoBeforeInsertSQLStatement(const Sender: TObject; StatementIndex: Integer; out Execute: Boolean); begin if Assigned(FBeforeInsertSQLStatement) then FBeforeInsertSQLStatement(Self, StatementIndex, Execute); end; procedure TZUpdateSQL.DoBeforeModifySQLStatement(const Sender: TObject; StatementIndex: Integer; out Execute: Boolean); begin if Assigned(FBeforeModifySQLStatement) then FBeforeModifySQLStatement(Self, StatementIndex, Execute); end; end. ================================================ FILE: lib/zeosdbo/src/component/ZStoredProcedure.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Abstract StoredProc component } { } { Originally written by Sergey Seroukhov } { & Janos Fegyverneki } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZStoredProcedure; interface {$I ZComponent.inc} uses Types, SysUtils, Classes, {$IFDEF MSEgui}mclasses, mdb{$ELSE}DB{$ENDIF}, ZDbcIntfs, ZAbstractDataset, ZCompatibility; type {** Abstract dataset to access to stored procedures. } TZStoredProc = class(TZAbstractDataset) private FMetaResultSet: IZResultset; procedure RetrieveParamValues; function GetStoredProcName: string; procedure SetStoredProcName(const Value: string); function GetParamType(const Value: TZProcedureColumnType): TParamType; protected function CreateStatement(const SQL: string; Properties: TStrings): IZPreparedStatement; override; procedure SetStatementParams(Statement: IZPreparedStatement; ParamNames: TStringDynArray; Params: TParams; DataLink: TDataLink); override; procedure InternalOpen; override; procedure InternalClose; override; protected {$IFDEF WITH_IPROVIDER} function PSIsSQLBased: Boolean; override; procedure PSExecute; override; {$IFDEF WITH_IPROVIDERWIDE} function PSGetTableNameW: WideString; override; {$ELSE} function PSGetTableName: string; override; {$ENDIF} procedure PSSetCommandText(const ACommandText: string); override; {$ENDIF} public procedure ExecProc; virtual; procedure FirstResultSet; procedure PreviousResultSet; procedure NextResultSet; procedure LastResultSet; procedure SetResultSet(const Index: Integer); function ResultSetCount: Integer; function BOR: Boolean; function EOR: Boolean; published property Active; property ParamCheck; property Params; property ShowRecordTypes; property Options; property StoredProcName: string read GetStoredProcName write SetStoredProcName; end; implementation uses ZAbstractRODataset, ZMessages, ZDatasetUtils {$IFDEF WITH_ASBYTES}, ZSysUtils{$ENDIF} {$IFDEF WITH_INLINE_ANSICOMPARETEXT}, Windows{$ENDIF}; { TZStoredProc } {** Creates a DBC statement for the query. @param SQL an SQL query. @param Properties a statement specific properties. @returns a created DBC statement. } {$IFDEF FPC} {$HINTS OFF} {$ENDIF} function TZStoredProc.CreateStatement(const SQL: string; Properties: TStrings): IZPreparedStatement; var I: Integer; CallableStatement: IZCallableStatement; Catalog, Schema, ObjectName: string; begin CallableStatement := Connection.DbcConnection.PrepareCallWithParams( Trim(SQL), Properties); CallableStatement.ClearParameters; if Supports(CallableStatement, IZParamNamedCallableStatement) then if Assigned(FMetaResultSet) then FMetaResultSet.BeforeFirst else begin //i need allways all types to cast and there names SplitQualifiedObjectName(Trim(SQL), Catalog, Schema, ObjectName); ObjectName := Connection.DbcConnection.GetMetadata.AddEscapeCharToWildcards(ObjectName); FMetaResultSet := Connection.DbcConnection.GetMetadata.GetProcedureColumns(Catalog, Schema, ObjectName, ''); end; for I := 0 to Params.Count - 1 do begin CallableStatement.RegisterParamType( I+1, ord(Params[I].ParamType)); if Params[I].ParamType in [ptResult, ptOutput, ptInputOutput] then CallableStatement.RegisterOutParameter(I + 1, Ord(ConvertDatasetToDbcType(Params[I].DataType))); if Supports(CallableStatement, IZParamNamedCallableStatement) and Assigned(FMetaResultSet) then if FMetaResultSet.Next then (CallableStatement as IZParamNamedCallableStatement).RegisterParamTypeAndName( I, FMetaResultSet.GetString(7), Params[i].Name, FMetaResultSet.GetInt(8), FMetaResultSet.GetInt(9)); end; Result := CallableStatement; end; {$IFDEF FPC} {$HINTS ON} {$ENDIF} {** Fill prepared statement with parameters. @param Statement a prepared SQL statement. @param ParamNames an array of parameter names. @param Params a collection of SQL parameters. @param DataLink a datalink to get parameters. } {$IFDEF FPC} {$HINTS OFF} {$ENDIF} procedure TZStoredProc.SetStatementParams(Statement: IZPreparedStatement; ParamNames: TStringDynArray; Params: TParams; DataLink: TDataLink); var I: Integer; Param: TParam; begin for I := 0 to Params.Count - 1 do begin Param := Params[I]; if Params[I].ParamType in [ptResult, ptOutput] then Continue; SetStatementParam(I+1, Statement, Param); end; end; {$IFDEF FPC} {$HINTS ON} {$ENDIF} {** Retrieves parameter values from callable statement. } procedure TZStoredProc.RetrieveParamValues; var I: Integer; Param: TParam; FCallableStatement: IZCallableStatement; TempBlob: IZBlob; begin if Assigned(Statement) then Statement.QueryInterface(IZCallableStatement, FCallableStatement); if not Assigned(FCallableStatement) then Exit; for I := 0 to Params.Count - 1 do begin Param := Params[I]; if not (Param.ParamType in [ptResult, ptOutput, ptInputOutput]) then Continue; if FCallableStatement.IsNull(I + 1) then Param.Clear else case Param.DataType of ftBoolean: Param.AsBoolean := FCallableStatement.GetBoolean(I + 1); ftSmallInt: Param.AsSmallInt := FCallableStatement.GetShort(I + 1); ftInteger, ftAutoInc: Param.AsInteger := FCallableStatement.GetInt(I + 1); ftFloat: Param.AsFloat := FCallableStatement.GetDouble(I + 1); ftLargeInt: Param.Value := FCallableStatement.GetLong(I + 1); ftString: begin Param.AsString := FCallableStatement.GetString(I + 1); {$IFDEF UNICODE}Param.DataType := ftString;{$ENDIF} //Hack: D12_UP sets ftWideString on assigning a UnicodeString end; ftWideString: {$IFDEF WITH_FTWIDESTRING}Param.AsWideString{$ELSE}Param.Value{$ENDIF} := FCallableStatement.GetUnicodeString(I + 1); ftMemo: begin Param.AsMemo := FCallableStatement.GetString(I + 1); {$IFDEF UNICODE}Param.DataType := ftMemo;{$ENDIF} //Hack: D12_UP sets ftWideMemo on assigning a UnicodeString end; {$IFDEF WITH_WIDEMEMO} ftWideMemo: begin Param.AsWideString := FCallableStatement.GetUnicodeString(I + 1); Param.DataType := ftWideMemo; end; {$ENDIF} ftBytes, ftVarBytes: Param.Value := FCallableStatement.GetBytes(I + 1); ftDate: Param.AsDate := FCallableStatement.GetDate(I + 1); ftTime: Param.AsTime := FCallableStatement.GetTime(I + 1); ftDateTime: Param.AsDateTime := FCallableStatement.GetTimestamp(I + 1); ftBlob: begin TempBlob := FCallableStatement.GetValue(I +1).VInterface as IZBlob; if not TempBlob.IsEmpty then Param.SetBlobData({$IFDEF WITH_TVALUEBUFFER}TValueBuffer{$ENDIF}(TempBlob.GetBuffer), TempBlob.Length); TempBlob := nil; end else raise EZDatabaseError.Create(SUnKnownParamDataType); end; end; end; {** Performs internal query opening. } procedure TZStoredProc.InternalOpen; begin inherited InternalOpen; RetrieveParamValues; end; {** Performs internal query closing. } procedure TZStoredProc.InternalClose; begin inherited InternalClose; end; function TZStoredProc.GetStoredProcName: string; begin Result := Trim(SQL.Text); end; {$IFDEF FPC} {$HINTS OFF} {$ENDIF} procedure TZStoredProc.SetStoredProcName(const Value: string); var OldParams: TParams; Catalog, Schema, ObjectName: string; ColumnType: Integer; begin if AnsiCompareText(Trim(SQL.Text), Trim(Value)) <> 0 then begin SQL.Text := Value; if ParamCheck and (Value <> '') and not (csLoading in ComponentState) and Assigned(Connection) then begin CheckConnected; Connection.ShowSQLHourGlass; try SplitQualifiedObjectName(Value, Connection.DbcConnection.GetMetadata.GetDatabaseInfo.SupportsCatalogsInProcedureCalls, Connection.DbcConnection.GetMetadata.GetDatabaseInfo.SupportsSchemasInProcedureCalls, Catalog, Schema, ObjectName); ObjectName := Connection.DbcConnection.GetMetadata.AddEscapeCharToWildcards(ObjectName); FMetaResultSet := Connection.DbcConnection.GetMetadata.GetProcedureColumns(Catalog, Schema, ObjectName, ''); OldParams := TParams.Create; try OldParams.Assign(Params); Params.Clear; while FMetaResultSet.Next do begin ColumnType := FMetaResultSet.GetIntByName('COLUMN_TYPE'); if ColumnType >= 0 then //-1 is result column Params.CreateParam(ConvertDbcToDatasetType(TZSqlType(FMetaResultSet.GetIntByName('DATA_TYPE'))), FMetaResultSet.GetStringByName('COLUMN_NAME'), GetParamType(TZProcedureColumnType(ColumnType))); end; Params.AssignValues(OldParams); finally OldParams.Free; end; finally Connection.HideSQLHourGlass; end; end; end; end; {$IFDEF FPC} {$HINTS ON} {$ENDIF} procedure TZStoredProc.ExecProc; begin Connection.ShowSQLHourGlass; try if Active then Close; ExecSQL; RetrieveParamValues; finally Connection.HideSQLHourGlass; end; end; {** Procedure the First retrieved resultset if the givens } procedure TZStoredProc.FirstResultSet; begin if Assigned(Statement) then if (Statement as IZCallableStatement).HasMoreResultSets then SetAnotherResultset((Statement as IZCallableStatement).GetFirstResultSet); end; {** Procedure the Previous retrieved resultset if the givens } procedure TZStoredProc.PreviousResultSet; begin if Assigned(Statement) then if (Statement as IZCallableStatement).HasMoreResultSets then SetAnotherResultset((Statement as IZCallableStatement).GetPreviousResultSet); end; {** Procedure the Next retrieved resultset if the givens } procedure TZStoredProc.NextResultSet; begin if Assigned(Statement) then if (Statement as IZCallableStatement).HasMoreResultSets then SetAnotherResultset((Statement as IZCallableStatement).GetNextResultSet); end; {** Procedure the Last retrieved resultset if the givens } procedure TZStoredProc.LastResultSet; begin if Assigned(Statement) then if (Statement as IZCallableStatement).HasMoreResultSets then SetAnotherResultset((Statement as IZCallableStatement).GetLastResultSet); end; {** Retrieves a ResultSet by his index. @param Integer the index of the Resultset @result IZResultSet of the Index or nil. } procedure TZStoredProc.SetResultSet(const Index: Integer); begin if Assigned(Statement) then if ( Index < 0 ) or ( Index > (Statement as IZCallableStatement).GetResultSetCount -1 ) then raise Exception.Create(Format(SListIndexError, [Index])) else SetAnotherResultset((Statement as IZCallableStatement).GetResultSetByIndex(Index)); end; {** Returns the Count of retrived ResultSets. @result Integer Count } function TZStoredProc.ResultSetCount: Integer; begin Result := 0; if Assigned(Statement) then if (Statement as IZCallableStatement).HasMoreResultSets then Result := (Statement as IZCallableStatement).GetResultSetCount; end; {** First ResultSet? @result True if first ResultSet } function TZStoredProc.BOR: Boolean; begin Result := True; if Assigned(Statement) then if (Statement as IZCallableStatement).HasMoreResultSets then Result := (Statement as IZCallableStatement).BOR; end; {** Last ResultSet? @result True if Last ResultSet } function TZStoredProc.EOR: Boolean; begin Result := True; if Assigned(Statement) then if (Statement as IZCallableStatement).HasMoreResultSets then Result := (Statement as IZCallableStatement).EOR; end; {** Converts procedure column type to dataset param type. @param Value a initial procedure column type. @return a corresponding param type. } function TZStoredProc.GetParamType(const Value: TZProcedureColumnType): TParamType; begin case Value of pctIn: Result := ptInput; pctInOut: Result := ptInputOutput; pctOut: Result := ptOutput; pctReturn: Result := ptResult; pctResultSet: Result := ptResult; else Result := ptUnknown; end; end; {$IFDEF WITH_IPROVIDER} {** Checks if dataset can execute SQL queries? @returns True if the query can execute SQL. } function TZStoredProc.PSIsSQLBased: Boolean; begin Result := False; end; {** Gets the name of the stored procedure. @returns the name of this stored procedure. } {$IFDEF WITH_IPROVIDERWIDE} function TZStoredProc.PSGetTableNameW: WideString; {$ELSE} function TZStoredProc.PSGetTableName: string; {$ENDIF} begin Result := StoredProcName; end; {** Executes this stored procedure. } procedure TZStoredProc.PSExecute; begin ExecProc; end; {** Assignes a new name for this stored procedure. @param ACommandText a new name for this stored procedure. } procedure TZStoredProc.PSSetCommandText(const ACommandText: string); begin StoredProcName := ACommandText; end; {$ENDIF} end. ================================================ FILE: lib/zeosdbo/src/component/ZStreamBlob.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Blob streams classes } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZStreamBlob; interface {$I ZComponent.inc} uses Classes, SysUtils, {$IFDEF MSEgui}mclasses, mdb{$ELSE}DB{$ENDIF}, {$IFDEF WITH_WIDESTRUTILS}WideStrUtils, {$ENDIF} ZDbcIntfs, ZCompatibility; type {** Implements a class for blobs stream. } TZBlobStream = class(TMemoryStream) private FField: TBlobField; FBlob: IZBlob; FMode: TBlobStreamMode; FConSettings: PZConSettings; protected property Blob: IZBlob read FBlob write FBlob; property Mode: TBlobStreamMode read FMode write FMode; public constructor Create(Field: TBlobField; Blob: IZBlob; Mode: TBlobStreamMode; ConSettings: PZConSettings); destructor Destroy; override; end; implementation uses ZEncoding; { TZBlobStream } {** Constructs this object and assignes the main properties. @param Blob } constructor TZBlobStream.Create(Field: TBlobField; Blob: IZBlob; Mode: TBlobStreamMode; ConSettings: PZConSettings); var TempStream: TStream; begin inherited Create; FBlob := Blob; FMode := Mode; FField := Field; FConSettings := ConSettings; if (Mode in [bmRead, bmReadWrite]) and not Blob.IsEmpty then begin TempStream := Blob.GetStream; try TempStream.Position := 0; CopyFrom(TempStream, TempStream.Size); Position := 0; finally TempStream.Free; end; end end; type THackedDataset = class(TDataset); {** Destroys this object and cleanups the memory. } destructor TZBlobStream.Destroy; {$IFDEF WITH_WIDEMEMO} var TempStream: TStream; {$ENDIF} begin if Mode in [bmWrite, bmReadWrite] then begin if Assigned(Self.Memory) then begin {$IFDEF WITH_WIDEMEMO} if FField.DataType = ftWideMemo then begin TempStream := GetValidatedUnicodeStream(Memory, Cardinal(Size), FConSettings, False); Blob.SetStream(TempStream, True); TempStream.Free; end else {$ENDIF} Blob.SetStream(Self) end else Blob.SetStream(nil); try if Assigned(FField.Dataset) then THackedDataset(FField.DataSet).DataEvent(deFieldChange, ULong(FField)); except ApplicationHandleException(Self); end; end; inherited Destroy; end; end. ================================================ FILE: lib/zeosdbo/src/component/ZUpdateSqlEditor.dfm ================================================ object ZUpdateSQLEditForm: TZUpdateSQLEditForm Left = 339 Top = 271 Width = 406 Height = 293 ActiveControl = UpdateTableName Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'MS Sans Serif' Font.Style = [] OldCreateOrder = True Position = poScreenCenter OnCloseQuery = FormCloseQuery OnCreate = FormCreate OnDestroy = FormDestroy PixelsPerInch = 96 TextHeight = 13 object PageControl: TPageControl Left = 0 Top = 0 Width = 390 Height = 223 ActivePage = SQLPage Align = alClient TabOrder = 0 OnChanging = PageControlChanging object FieldsPage: TTabSheet Caption = 'Options' object GroupBox1: TGroupBox Left = 0 Top = 0 Width = 382 Height = 195 Align = alClient Caption = ' SQL Generation ' TabOrder = 0 DesignSize = ( 382 195) object Label1: TLabel Left = 8 Top = 24 Width = 61 Height = 13 Caption = 'Table &Name:' FocusControl = UpdateTableName end object Label3: TLabel Left = 128 Top = 24 Width = 51 Height = 13 Anchors = [akTop, akRight] Caption = '&Key Fields:' FocusControl = KeyFieldList end object Label4: TLabel Left = 256 Top = 24 Width = 68 Height = 13 Anchors = [akTop, akRight] Caption = 'Update &Fields:' FocusControl = UpdateFieldList end object UpdateTableName: TComboBox Left = 8 Top = 40 Width = 113 Height = 21 TabOrder = 0 OnChange = UpdateTableNameChange OnClick = UpdateTableNameClick end object KeyFieldList: TListBox Left = 126 Top = 40 Width = 117 Height = 146 Anchors = [akLeft, akTop, akBottom] ItemHeight = 13 MultiSelect = True PopupMenu = FieldListPopup TabOrder = 6 OnClick = SettingsChanged end object UpdateFieldList: TListBox Left = 254 Top = 40 Width = 120 Height = 146 Anchors = [akLeft, akTop, akRight, akBottom] ItemHeight = 13 MultiSelect = True PopupMenu = FieldListPopup TabOrder = 7 OnClick = SettingsChanged end object GenerateButton: TButton Left = 8 Top = 136 Width = 113 Height = 22 Caption = '&Generate SQL' TabOrder = 4 OnClick = GenerateButtonClick end object PrimaryKeyButton: TButton Left = 8 Top = 112 Width = 113 Height = 22 Caption = 'Select &Primary Keys' TabOrder = 3 OnClick = PrimaryKeyButtonClick end object DefaultButton: TButton Left = 8 Top = 88 Width = 113 Height = 21 Caption = '&Dataset Defaults' Enabled = False TabOrder = 2 OnClick = DefaultButtonClick end object QuoteFields: TCheckBox Left = 8 Top = 168 Width = 113 Height = 15 Caption = '&Quote Field Names' TabOrder = 5 OnClick = SettingsChanged end object GetTableFieldsButton: TButton Left = 8 Top = 64 Width = 113 Height = 21 Caption = 'Get &Table Fields' TabOrder = 1 OnClick = GetTableFieldsButtonClick end end end object SQLPage: TTabSheet Caption = 'SQL' object Label2: TLabel Left = 8 Top = 40 Width = 48 Height = 13 Caption = 'S&QL Text:' FocusControl = SQLMemo end object SQLMemo: TMemo Left = 8 Top = 56 Width = 368 Height = 130 Align = alCustom Anchors = [akLeft, akTop, akRight, akBottom] ScrollBars = ssVertical TabOrder = 0 WordWrap = False OnKeyPress = SQLMemoKeyPress end object StatementType: TRadioGroup Left = 0 Top = 0 Width = 382 Height = 35 Align = alTop Caption = 'Statement Type' Columns = 3 Items.Strings = ( '&Modify' '&Insert' '&Delete') TabOrder = 1 OnClick = StatementTypeClick end end end object Panel1: TPanel Left = 0 Top = 223 Width = 390 Height = 34 Align = alBottom TabOrder = 1 DesignSize = ( 390 34) object OkButton: TButton Left = 162 Top = 5 Width = 65 Height = 22 Anchors = [akRight, akBottom] Caption = '&OK' Default = True ModalResult = 1 TabOrder = 0 OnClick = OkButtonClick end object CancelButton: TButton Left = 239 Top = 5 Width = 65 Height = 22 Anchors = [akRight, akBottom] Cancel = True Caption = 'Cancel' ModalResult = 2 TabOrder = 1 end object HelpButton: TButton Left = 315 Top = 5 Width = 65 Height = 22 Anchors = [akRight, akBottom] Caption = '&Help' TabOrder = 2 OnClick = HelpButtonClick end end object FieldListPopup: TPopupMenu Left = 54 Top = 270 object miSelectAll: TMenuItem Caption = '&Select All' OnClick = SelectAllClick end object miClearAll: TMenuItem Caption = '&Clear All' OnClick = ClearAllClick end end end ================================================ FILE: lib/zeosdbo/src/component/ZUpdateSqlEditor.lfm ================================================ object ZUpdateSQLEditForm: TZUpdateSQLEditForm Left = 447 Height = 258 Top = 246 Width = 398 Caption = 'ZUpdateSQLEditForm' ClientHeight = 258 ClientWidth = 398 Font.Height = -11 Font.Name = 'MS Sans Serif' OnCloseQuery = FormCloseQuery OnCreate = FormCreate OnDestroy = FormDestroy OnResize = FormResize Position = poScreenCenter LCLVersion = '1.1' object PageControl: TPageControl Left = 0 Height = 221 Top = 0 Width = 398 ActivePage = SQLPage Align = alClient TabIndex = 1 TabOrder = 0 OnChanging = PageControlChanging object FieldsPage: TTabSheet Caption = 'Options' ClientHeight = 195 ClientWidth = 390 object GroupBox1: TGroupBox Left = 0 Height = 195 Top = 0 Width = 390 Align = alClient Caption = ' SQL Generation ' ClientHeight = 177 ClientWidth = 386 TabOrder = 0 object Label1: TLabel Left = 16 Height = 14 Top = 8 Width = 62 Caption = 'Table &Name:' FocusControl = UpdateTableName ParentColor = False end object Label3: TLabel Left = 143 Height = 14 Top = 8 Width = 52 Anchors = [akTop, akRight] Caption = '&Key Fields:' FocusControl = KeyFieldList ParentColor = False end object Label4: TLabel Left = 265 Height = 14 Top = 8 Width = 69 Anchors = [akTop, akRight] Caption = 'Update &Fields:' FocusControl = UpdateFieldList ParentColor = False end object QuoteFields: TCheckBox Left = 16 Height = 17 Top = 152 Width = 110 Caption = '&Quote Field Names' OnClick = SettingsChanged TabOrder = 5 end object UpdateTableName: TComboBox Left = 16 Height = 21 Top = 24 Width = 113 ItemHeight = 13 OnChange = UpdateTableNameChange OnClick = UpdateTableNameClick TabOrder = 0 end object GenerateButton: TButton Left = 16 Height = 22 Top = 120 Width = 113 Caption = '&Generate SQL' OnClick = GenerateButtonClick TabOrder = 4 end object PrimaryKeyButton: TButton Left = 16 Height = 22 Top = 96 Width = 113 Caption = 'Select &Primary Keys' OnClick = PrimaryKeyButtonClick TabOrder = 3 end object DefaultButton: TButton Left = 16 Height = 21 Top = 72 Width = 113 Caption = '&Dataset Defaults' Enabled = False OnClick = DefaultButtonClick TabOrder = 2 end object GetTableFieldsButton: TButton Left = 16 Height = 21 Top = 48 Width = 113 Caption = 'Get &Table Fields' OnClick = GetTableFieldsButtonClick TabOrder = 1 end object UpdateFieldList: TListBox Left = 264 Height = 144 Top = 24 Width = 118 Anchors = [akTop, akRight, akBottom] ItemHeight = 0 MultiSelect = True OnClick = SettingsChanged PopupMenu = FieldListPopup TabOrder = 7 end object KeyFieldList: TListBox Left = 136 Height = 144 Top = 24 Width = 117 Anchors = [akTop, akLeft, akRight, akBottom] ItemHeight = 0 MultiSelect = True OnClick = SettingsChanged PopupMenu = FieldListPopup TabOrder = 6 end end end object SQLPage: TTabSheet Caption = 'SQL' ClientHeight = 195 ClientWidth = 390 object Label2: TLabel Left = 8 Height = 14 Top = 40 Width = 49 Caption = 'S&QL Text:' FocusControl = SQLMemo ParentColor = False end object SQLMemo: TMemo Left = 8 Height = 129 Top = 56 Width = 373 Align = alCustom Anchors = [akTop, akLeft, akRight, akBottom] OnKeyPress = SQLMemoKeyPress ScrollBars = ssVertical TabOrder = 0 WordWrap = False end object StatementType: TRadioGroup Left = 0 Height = 35 Top = 0 Width = 390 Align = alTop AutoFill = True Caption = 'Statement Type' ChildSizing.LeftRightSpacing = 6 ChildSizing.TopBottomSpacing = 6 ChildSizing.EnlargeHorizontal = crsHomogenousChildResize ChildSizing.EnlargeVertical = crsHomogenousChildResize ChildSizing.ShrinkHorizontal = crsScaleChilds ChildSizing.ShrinkVertical = crsScaleChilds ChildSizing.Layout = cclLeftToRightThenTopToBottom ChildSizing.ControlsPerLine = 3 ClientHeight = 17 ClientWidth = 386 Columns = 3 Items.Strings = ( '&Modify' '&Insert' '&Delete' ) OnClick = StatementTypeClick TabOrder = 1 end end end object Panel1: TPanel Left = 0 Height = 37 Top = 221 Width = 398 Align = alBottom BevelOuter = bvNone ClientHeight = 37 ClientWidth = 398 TabOrder = 1 object OkButton: TButton Left = 168 Height = 22 Top = 7 Width = 65 Anchors = [akRight, akBottom] Caption = '&OK' Default = True ModalResult = 1 OnClick = OkButtonClick TabOrder = 0 end object CancelButton: TButton Left = 245 Height = 22 Top = 7 Width = 65 Anchors = [akRight, akBottom] Cancel = True Caption = 'Cancel' ModalResult = 2 TabOrder = 1 end object HelpButton: TButton Left = 321 Height = 22 Top = 7 Width = 65 Anchors = [akRight, akBottom] Caption = '&Help' OnClick = HelpButtonClick TabOrder = 2 end end object FieldListPopup: TPopupMenu left = 54 top = 270 object miSelectAll: TMenuItem Caption = '&Select All' OnClick = SelectAllClick end object miClearAll: TMenuItem Caption = '&Clear All' OnClick = ClearAllClick end end end ================================================ FILE: lib/zeosdbo/src/component/ZUpdateSqlEditor.lrs ================================================ { This is an automatically generated lazarus resource file } LazarusResources.Add('TZUpdateSQLEditForm','FORMDATA',[ 'TPF0'#19'TZUpdateSQLEditForm'#18'ZUpdateSQLEditForm'#4'Left'#3#191#1#6'Heigh' +'t'#3#2#1#3'Top'#3#246#0#5'Width'#3#142#1#7'Caption'#6#18'ZUpdateSQLEditForm' +#12'ClientHeight'#3#2#1#11'ClientWidth'#3#142#1#11'Font.Height'#2#245#9'Font' +'.Name'#6#13'MS Sans Serif'#12'OnCloseQuery'#7#14'FormCloseQuery'#8'OnCreate' +#7#10'FormCreate'#9'OnDestroy'#7#11'FormDestroy'#8'OnResize'#7#10'FormResize' +#8'Position'#7#14'poScreenCenter'#10'LCLVersion'#6#3'1.1'#0#12'TPageControl' +#11'PageControl'#4'Left'#2#0#6'Height'#3#221#0#3'Top'#2#0#5'Width'#3#142#1#10 +'ActivePage'#7#7'SQLPage'#5'Align'#7#8'alClient'#8'TabIndex'#2#1#8'TabOrder' +#2#0#10'OnChanging'#7#19'PageControlChanging'#0#9'TTabSheet'#10'FieldsPage'#7 +'Caption'#6#7'Options'#12'ClientHeight'#3#195#0#11'ClientWidth'#3#134#1#0#9 +'TGroupBox'#9'GroupBox1'#4'Left'#2#0#6'Height'#3#195#0#3'Top'#2#0#5'Width'#3 +#134#1#5'Align'#7#8'alClient'#7'Caption'#6#16' SQL Generation '#12'ClientHei' +'ght'#3#177#0#11'ClientWidth'#3#130#1#8'TabOrder'#2#0#0#6'TLabel'#6'Label1'#4 +'Left'#2#16#6'Height'#2#14#3'Top'#2#8#5'Width'#2'>'#7'Caption'#6#12'Table &N' +'ame:'#12'FocusControl'#7#15'UpdateTableName'#11'ParentColor'#8#0#0#6'TLabel' +#6'Label3'#4'Left'#3#143#0#6'Height'#2#14#3'Top'#2#8#5'Width'#2'4'#7'Anchors' +#11#5'akTop'#7'akRight'#0#7'Caption'#6#12'&Key Fields:'#12'FocusControl'#7#12 +'KeyFieldList'#11'ParentColor'#8#0#0#6'TLabel'#6'Label4'#4'Left'#3#9#1#6'Hei' +'ght'#2#14#3'Top'#2#8#5'Width'#2'E'#7'Anchors'#11#5'akTop'#7'akRight'#0#7'Ca' +'ption'#6#15'Update &Fields:'#12'FocusControl'#7#15'UpdateFieldList'#11'Pare' +'ntColor'#8#0#0#9'TCheckBox'#11'QuoteFields'#4'Left'#2#16#6'Height'#2#17#3'T' +'op'#3#152#0#5'Width'#2'n'#7'Caption'#6#18'&Quote Field Names'#7'OnClick'#7 +#15'SettingsChanged'#8'TabOrder'#2#5#0#0#9'TComboBox'#15'UpdateTableName'#4 +'Left'#2#16#6'Height'#2#21#3'Top'#2#24#5'Width'#2'q'#10'ItemHeight'#2#13#8'O' +'nChange'#7#21'UpdateTableNameChange'#7'OnClick'#7#20'UpdateTableNameClick'#8 +'TabOrder'#2#0#0#0#7'TButton'#14'GenerateButton'#4'Left'#2#16#6'Height'#2#22 +#3'Top'#2'x'#5'Width'#2'q'#7'Caption'#6#13'&Generate SQL'#7'OnClick'#7#19'Ge' +'nerateButtonClick'#8'TabOrder'#2#4#0#0#7'TButton'#16'PrimaryKeyButton'#4'Le' +'ft'#2#16#6'Height'#2#22#3'Top'#2'`'#5'Width'#2'q'#7'Caption'#6#20'Select &P' +'rimary Keys'#7'OnClick'#7#21'PrimaryKeyButtonClick'#8'TabOrder'#2#3#0#0#7'T' +'Button'#13'DefaultButton'#4'Left'#2#16#6'Height'#2#21#3'Top'#2'H'#5'Width'#2 +'q'#7'Caption'#6#17'&Dataset Defaults'#7'Enabled'#8#7'OnClick'#7#18'DefaultB' +'uttonClick'#8'TabOrder'#2#2#0#0#7'TButton'#20'GetTableFieldsButton'#4'Left' +#2#16#6'Height'#2#21#3'Top'#2'0'#5'Width'#2'q'#7'Caption'#6#17'Get &Table Fi' +'elds'#7'OnClick'#7#25'GetTableFieldsButtonClick'#8'TabOrder'#2#1#0#0#8'TLis' +'tBox'#15'UpdateFieldList'#4'Left'#3#8#1#6'Height'#3#144#0#3'Top'#2#24#5'Wid' +'th'#2'v'#7'Anchors'#11#5'akTop'#7'akRight'#8'akBottom'#0#10'ItemHeight'#2#0 +#11'MultiSelect'#9#7'OnClick'#7#15'SettingsChanged'#9'PopupMenu'#7#14'FieldL' +'istPopup'#8'TabOrder'#2#7#0#0#8'TListBox'#12'KeyFieldList'#4'Left'#3#136#0#6 +'Height'#3#144#0#3'Top'#2#24#5'Width'#2'u'#7'Anchors'#11#5'akTop'#6'akLeft'#7 +'akRight'#8'akBottom'#0#10'ItemHeight'#2#0#11'MultiSelect'#9#7'OnClick'#7#15 +'SettingsChanged'#9'PopupMenu'#7#14'FieldListPopup'#8'TabOrder'#2#6#0#0#0#0#9 +'TTabSheet'#7'SQLPage'#7'Caption'#6#3'SQL'#12'ClientHeight'#3#195#0#11'Clien' +'tWidth'#3#134#1#0#6'TLabel'#6'Label2'#4'Left'#2#8#6'Height'#2#14#3'Top'#2'(' +#5'Width'#2'1'#7'Caption'#6#10'S&QL Text:'#12'FocusControl'#7#7'SQLMemo'#11 +'ParentColor'#8#0#0#5'TMemo'#7'SQLMemo'#4'Left'#2#8#6'Height'#3#129#0#3'Top' +#2'8'#5'Width'#3'u'#1#5'Align'#7#8'alCustom'#7'Anchors'#11#5'akTop'#6'akLeft' +#7'akRight'#8'akBottom'#0#10'OnKeyPress'#7#15'SQLMemoKeyPress'#10'ScrollBars' +#7#10'ssVertical'#8'TabOrder'#2#0#8'WordWrap'#8#0#0#11'TRadioGroup'#13'State' +'mentType'#4'Left'#2#0#6'Height'#2'#'#3'Top'#2#0#5'Width'#3#134#1#5'Align'#7 +#5'alTop'#8'AutoFill'#9#7'Caption'#6#14'Statement Type'#28'ChildSizing.LeftR' +'ightSpacing'#2#6#28'ChildSizing.TopBottomSpacing'#2#6#29'ChildSizing.Enlarg' +'eHorizontal'#7#24'crsHomogenousChildResize'#27'ChildSizing.EnlargeVertical' +#7#24'crsHomogenousChildResize'#28'ChildSizing.ShrinkHorizontal'#7#14'crsSca' +'leChilds'#26'ChildSizing.ShrinkVertical'#7#14'crsScaleChilds'#18'ChildSizin' +'g.Layout'#7#29'cclLeftToRightThenTopToBottom'#27'ChildSizing.ControlsPerLin' +'e'#2#3#12'ClientHeight'#2#17#11'ClientWidth'#3#130#1#7'Columns'#2#3#13'Item' +'s.Strings'#1#6#7'&Modify'#6#7'&Insert'#6#7'&Delete'#0#7'OnClick'#7#18'State' +'mentTypeClick'#8'TabOrder'#2#1#0#0#0#0#6'TPanel'#6'Panel1'#4'Left'#2#0#6'He' +'ight'#2'%'#3'Top'#3#221#0#5'Width'#3#142#1#5'Align'#7#8'alBottom'#10'BevelO' +'uter'#7#6'bvNone'#12'ClientHeight'#2'%'#11'ClientWidth'#3#142#1#8'TabOrder' +#2#1#0#7'TButton'#8'OkButton'#4'Left'#3#168#0#6'Height'#2#22#3'Top'#2#7#5'Wi' +'dth'#2'A'#7'Anchors'#11#7'akRight'#8'akBottom'#0#7'Caption'#6#3'&OK'#7'Defa' +'ult'#9#11'ModalResult'#2#1#7'OnClick'#7#13'OkButtonClick'#8'TabOrder'#2#0#0 ,#0#7'TButton'#12'CancelButton'#4'Left'#3#245#0#6'Height'#2#22#3'Top'#2#7#5'W' +'idth'#2'A'#7'Anchors'#11#7'akRight'#8'akBottom'#0#6'Cancel'#9#7'Caption'#6#6 +'Cancel'#11'ModalResult'#2#2#8'TabOrder'#2#1#0#0#7'TButton'#10'HelpButton'#4 +'Left'#3'A'#1#6'Height'#2#22#3'Top'#2#7#5'Width'#2'A'#7'Anchors'#11#7'akRigh' +'t'#8'akBottom'#0#7'Caption'#6#5'&Help'#7'OnClick'#7#15'HelpButtonClick'#8'T' +'abOrder'#2#2#0#0#0#10'TPopupMenu'#14'FieldListPopup'#4'left'#2'6'#3'top'#3 +#14#1#0#9'TMenuItem'#11'miSelectAll'#7'Caption'#6#11'&Select All'#7'OnClick' +#7#14'SelectAllClick'#0#0#9'TMenuItem'#10'miClearAll'#7'Caption'#6#10'&Clear' +' All'#7'OnClick'#7#13'ClearAllClick'#0#0#0#0 ]); ================================================ FILE: lib/zeosdbo/src/component/ZUpdateSqlEditor.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { UpdateSql property editor } { } { Originally written by Janos Fegyverneki } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZUpdateSqlEditor; interface {$I ZComponent.inc} uses {$IFNDEF FPC} DesignEditors, {$ELSE} PropEdits, Buttons, ComponentEditors, {$ENDIF} Forms, DB, ExtCtrls, StdCtrls, Controls, ComCtrls, Classes, SysUtils, {$IFNDEF FPC}Windows, {$ELSE}LCLIntf, LResources, {$ENDIF} Menus, ZAbstractDataset, {$IFDEF UNIX} {$IFNDEF FPC} QMenus, QTypes, QExtCtrls, QStdCtrls, QControls, QComCtrls, {$ENDIF} {$ENDIF} ZSqlUpdate; type TWaitMethod = procedure of object; { TZUpdateSQLEditForm } TZUpdateSQLEditForm = class(TForm) Label2: TLabel; Label3: TLabel; Label4: TLabel; GenerateButton: TButton; Panel1: TPanel; PrimaryKeyButton: TButton; DefaultButton: TButton; UpdateTableName: TComboBox; FieldsPage: TTabSheet; SQLPage: TTabSheet; PageControl: TPageControl; KeyFieldList: TListBox; UpdateFieldList: TListBox; GroupBox1: TGroupBox; Label1: TLabel; SQLMemo: TMemo; StatementType: TRadioGroup; QuoteFields: TCheckBox; GetTableFieldsButton: TButton; FieldListPopup: TPopupMenu; miSelectAll: TMenuItem; miClearAll: TMenuItem; OkButton: TButton; CancelButton: TButton; HelpButton: TButton; procedure FormCreate(Sender: TObject); procedure FormResize(Sender: TObject); procedure HelpButtonClick(Sender: TObject); procedure StatementTypeClick(Sender: TObject); procedure OkButtonClick(Sender: TObject); procedure DefaultButtonClick(Sender: TObject); procedure GenerateButtonClick(Sender: TObject); procedure PrimaryKeyButtonClick(Sender: TObject); procedure PageControlChanging(Sender: TObject; var AllowChange: Boolean); procedure FormDestroy(Sender: TObject); procedure GetTableFieldsButtonClick(Sender: TObject); procedure SettingsChanged(Sender: TObject); procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean); procedure UpdateTableNameChange(Sender: TObject); procedure UpdateTableNameClick(Sender: TObject); procedure SelectAllClick(Sender: TObject); procedure ClearAllClick(Sender: TObject); procedure SQLMemoKeyPress(Sender: TObject; var Key: Char); private StmtIndex: Integer; DataSet: TZAbstractDataset; QuoteChar: string; ConnectionOpened: Boolean; UpdateSQL: TZUpdateSQL; FSettingsChanged: Boolean; FDatasetDefaults: Boolean; SQLText: array[TUpdateKind] of TStrings; function GetTableRef(const TabName: string): string; function Edit: Boolean; procedure GenWhereClause(const TabAlias: string; KeyFields, SQL: TStrings); procedure GenDeleteSQL(const TableName: string; KeyFields, SQL: TStrings); procedure GenInsertSQL(const TableName: string; UpdateFields, SQL: TStrings); procedure GenModifySQL(const TableName: string; KeyFields, UpdateFields, SQL: TStrings); procedure GenerateSQL; procedure GetDataSetFieldNames; procedure GetTableFieldNames; procedure InitGenerateOptions; procedure InitUpdateTableNames; procedure SetButtonStates; procedure SelectPrimaryKeyFields; procedure SetDefaultSelections; procedure ShowWait(WaitMethod: TWaitMethod); end; { TSQLParser } TSQLToken = (stSymbol, stAlias, stNumber, stComma, stEQ, stOther, stLParen, stRParen, stEnd, stSemiColon); TSQLParser = class private FText: string; FSourcePtr: PChar; FTokenPtr: PChar; FTokenString: string; FToken: TSQLToken; FSymbolQuoted: Boolean; FQuoteString: string; function NextToken: TSQLToken; function TokenSymbolIs(const S: string): Boolean; procedure Reset; public constructor Create(const Text, QuoteString: string); procedure GetSelectTableNames(List: TStrings); procedure GetUpdateTableName(var TableName: string); procedure GetUpdateFields(List: TStrings); procedure GetWhereFields(List: TStrings); end; TZUpdateSqlEditor = class(TComponentEditor) public procedure ExecuteVerb(Index: Integer); override; function GetVerb(Index: Integer): string; override; function GetVerbCount: Integer; override; procedure Edit; override; end; function EditUpdateSQL(AZUpdateSQL: TZUpdateSQL): Boolean; resourcestring SSQLDataSetOpen = 'Unable to determine field names for %s'; SNoDataSet = 'No dataset association'; SSQLGenSelect = 'Must select at least one key field and one update field'; SSQLNotGenerated = 'Update SQL statements not generated, exit anyway?'; implementation {$IFNDEF FPC} {$R *.dfm} {$ENDIF} uses Dialogs, {$IFNDEF FPC}LibHelp, {$ENDIF}TypInfo, ZCompatibility, ZSqlMetadata, ZDbcIntfs, ZTokenizer, ZGenericSqlAnalyser, ZSelectSchema, ZDbcMetadata; function InternalQuoteIdentifier(const S, QuoteString: string): string; begin Result := S; if Length(QuoteString) > 1 then Result := QuoteString[1] + Result + QuoteString[2] else if Length(QuoteString) = 1 then Result := QuoteString[1] + Result + QuoteString[1]; end; { TZUpdateSqlEditor } procedure TZUpdateSqlEditor.ExecuteVerb(Index: Integer); begin if Index = 0 then EditUpdateSQL(TZUpdateSQL(Component)); end; {$IFDEF FPC} {$HINTS OFF} {$ENDIF} function TZUpdateSqlEditor.GetVerb(Index: Integer): string; begin Result := 'UpdateSql editor...'; end; {$IFDEF FPC} {$HINTS ON} {$ENDIF} function TZUpdateSqlEditor.GetVerbCount: Integer; begin Result := 1; end; procedure TZUpdateSqlEditor.Edit; begin EditUpdateSQL(TZUpdateSQL(Component)); end; { Global Interface functions } function EditUpdateSQL(AZUpdateSQL: TZUpdateSQL): Boolean; begin with TZUpdateSQLEditForm.Create(Application) do try UpdateSQL := AZUpdateSQL; Result := Edit; finally Free; end; end; { Utility Routines } procedure GetSelectedItems(ListBox: TListBox; List: TStrings); var I: Integer; begin List.Clear; for I := 0 to ListBox.Items.Count - 1 do if ListBox.Selected[I] then List.AddObject(ListBox.Items[I], ListBox.Items.Objects[I]); end; function SetSelectedItems(ListBox: TListBox; List: TStrings): Integer; var I: Integer; begin Result := 0; ListBox.Items.BeginUpdate; try for I := 0 to ListBox.Items.Count - 1 do if List.IndexOf(ListBox.Items[I]) > -1 then begin ListBox.Selected[I] := True; Inc(Result); end else ListBox.Selected[I] := False; if ListBox.Items.Count > 0 then begin ListBox.ItemIndex := 0; ListBox.TopIndex := 0; end; finally ListBox.Items.EndUpdate; end; end; procedure SelectAll(ListBox: TListBox); var I: Integer; begin ListBox.Items.BeginUpdate; try with ListBox do for I := 0 to Items.Count - 1 do Selected[I] := True; if ListBox.Items.Count > 0 then begin ListBox.ItemIndex := 0; ListBox.TopIndex := 0; end; finally ListBox.Items.EndUpdate; end; end; procedure GetDataKeyNames(Dataset: TDataset; ErrorName: string; List: TStrings); var I: Integer; begin with Dataset do try FieldDefs.Update; List.BeginUpdate; try List.Clear; for I := 0 to FieldDefs.Count - 1 do {$IFNDEF FPC} if not (FieldDefs[I].DataType in [Low(TBlobType)..High(TBlobType)]) then {$ELSE} if not (FieldDefs[I].DataType in [ftBlob..ftTypedBinary]) then {$ENDIF} List.AddObject(FieldDefs[I].Name, Pointer(not FieldDefs[I].Required)); finally List.EndUpdate; end; except if ErrorName <> '' then MessageDlg(Format(SSQLDataSetOpen, [ErrorName]), mtError, [mbOK], 0); end; end; procedure GetDataFieldNames(Dataset: TDataset; ErrorName: string; List: TStrings); var I: Integer; begin with Dataset do try FieldDefs.Update; List.BeginUpdate; try List.Clear; for I := 0 to FieldDefs.Count - 1 do List.AddObject(FieldDefs[I].Name, Pointer(not FieldDefs[I].Required)); finally List.EndUpdate; end; except if ErrorName <> '' then MessageDlg(Format(SSQLDataSetOpen, [ErrorName]), mtError, [mbOK], 0); end; end; procedure ParseUpdateSQL(const SQL, QuoteString: string; var TableName: string; UpdateFields: TStrings; WhereFields: TStrings); begin with TSQLParser.Create(SQL, QuoteString) do try GetUpdateTableName(TableName); if Assigned(UpdateFields) then begin Reset; GetUpdateFields(UpdateFields); end; if Assigned(WhereFields) then begin Reset; GetWhereFields(WhereFields); end; finally Free; end; end; { TSQLParser } constructor TSQLParser.Create(const Text, QuoteString: string); begin FText := Text; FSourcePtr := PChar(Text); FQuoteString := QuoteString; if FQuoteString = '' then FQuoteString := '""'; if Length(FQuoteString) = 1 then FQuoteString := FQuoteString + FQuoteString; NextToken; end; function TSQLParser.NextToken: TSQLToken; var P, TokenStart: PChar; IsParam: Boolean; {$IFNDEF FPC} function IsKatakana(const Chr: Byte): Boolean; begin Result := (SysLocale.PriLangID = LANG_JAPANESE) and (Chr in [$A1..$DF]); end; {$ENDIF} begin if FToken = stEnd then SysUtils.Abort; FTokenString := ''; FSymbolQuoted := False; P := FSourcePtr; while (P^ <> #0) and (P^ <= ' ') do Inc(P); FTokenPtr := P; case P^ of 'A'..'Z', 'a'..'z', '_', '$', #127..#255: begin TokenStart := P; if not SysLocale.FarEast then begin Inc(P); while CharInSet(P^, ['A'..'Z', 'a'..'z', '0'..'9', '_', '"', '$', #127..#255] ) do Inc(P); if P^ = '.' then Inc(P);//!!! This must be added for syslocale fareast also end else begin while TRUE do begin if CharInSet(P^, ['A'..'Z', 'a'..'z', '0'..'9', '_', '.', '"', '$']) or {$IFNDEF FPC}IsKatakana(Byte(P^)){$ELSE}False{$ENDIF} then Inc(P) else if CharInSet(P^, LeadBytes) then Inc(P, 2) else Break; end; end; SetString(FTokenString, TokenStart, P - TokenStart); FToken := stSymbol; end; '-', '0'..'9': begin TokenStart := P; Inc(P); while CharInSet(P^, ['0'..'9', '.', 'e', 'E', '+', '-'] )do Inc(P); SetString(FTokenString, TokenStart, P - TokenStart); FToken := stNumber; end; ',': begin Inc(P); FToken := stComma; end; ';': begin Inc(P); FToken := stSemiColon; end; '=': begin Inc(P); FToken := stEQ; end; '(': begin Inc(P); FToken := stLParen; end; ')': begin Inc(P); FToken := stRParen; end; #0: FToken := stEnd; else if P^ = FQuoteString[1] then begin Inc(P); IsParam := P^ = ':'; if IsParam then Inc(P); TokenStart := P; while not CharInSet(P^, [FQuoteString[2], #0]) do Inc(P); SetString(FTokenString, TokenStart, P - TokenStart); Inc(P); if P^ = '.' then begin FTokenString := FTokenString + '.'; Inc(P); end; Trim(FTokenString); FToken := stSymbol; FSymbolQuoted := True; end else begin FToken := stOther; Inc(P); end; end; FSourcePtr := P; if (FToken = stSymbol) and (FTokenString[Length(FTokenString)] = '.') then FToken := stAlias; Result := FToken; end; procedure TSQLParser.Reset; begin FSourcePtr := PChar(FText); FToken := stSymbol; NextToken; end; function TSQLParser.TokenSymbolIs(const S: string): Boolean; begin Result := (FToken = stSymbol) and (CompareText(FTokenString, S) = 0); end; procedure TSQLParser.GetSelectTableNames(List: TStrings); begin List.BeginUpdate; try List.Clear; if TokenSymbolIs('SELECT') then { Do not localize } try while not TokenSymbolIs('FROM') do NextToken; { Do not localize } NextToken; while FToken = stSymbol do begin List.AddObject(FTokenString, Pointer(Integer(FSymbolQuoted))); if NextToken = stSymbol then NextToken; if FToken = stComma then NextToken else break; end; except end; finally List.EndUpdate; end; end; procedure TSQLParser.GetUpdateTableName(var TableName: string); begin if TokenSymbolIs('UPDATE') and (NextToken = stSymbol) then { Do not localize } TableName := FTokenString else TableName := ''; end; procedure TSQLParser.GetUpdateFields(List: TStrings); begin List.BeginUpdate; try List.Clear; if TokenSymbolIs('UPDATE') then { Do not localize } try while not TokenSymbolIs('SET') do NextToken; { Do not localize } NextToken; while True do begin if FToken = stAlias then NextToken; if FToken <> stSymbol then Break; List.Add(FTokenString); if NextToken <> stEQ then Break; while NextToken <> stComma do if TokenSymbolIs('WHERE') or TokenSymbolIs('UPDATE') then Exit;{ Do not localize } NextToken; end; except end; finally List.EndUpdate; end; end; procedure TSQLParser.GetWhereFields(List: TStrings); begin List.BeginUpdate; try List.Clear; if TokenSymbolIs('UPDATE') then { Do not localize } try while not TokenSymbolIs('WHERE') do NextToken; { Do not localize } NextToken; while True do begin while FToken in [stLParen, stRParen, stAlias, stOther] do NextToken; if FToken <> stSymbol then Break; List.Add(FTokenString); NextToken; if (FToken <> stEQ) and not TokenSymbolIs('IS') then Break; while true do begin NextToken; if FToken in [stEnd, stSemiColon] then Exit; //!!!!stSemiColon should be the statement separator if TokenSymbolIs('AND') then Break; { Do not localize } end; NextToken; end; except end; finally List.EndUpdate; end; end; { TUpdateSQLEditor } { Private Methods } function TZUpdateSQLEditForm.Edit: Boolean; var Index: TUpdateKind; DataSetName: string; begin Result := False; ConnectionOpened := False; if Assigned(UpdateSQL.DataSet) and (UpdateSQL.DataSet is TZAbstractDataset) then begin DataSet := TZAbstractDataset(UpdateSQL.DataSet); DataSetName := Format('%s%s%s', [DataSet.Owner.Name, DotSep, DataSet.Name]); if Assigned(DataSet.Connection) and not DataSet.Connection.Connected then begin DataSet.Connection.Connect; ConnectionOpened := True; end; end else DataSetName := SNoDataSet; Caption := Format('%s%s%s (%s)', [UpdateSQL.Owner.Name, DotSep, UpdateSQL.Name, DataSetName]); try for Index := Low(TUpdateKind) to High(TUpdateKind) do begin SQLText[Index] := TStringList.Create; SQLText[Index].Assign(UpdateSQL.SQL[Index]); end; StatementType.ItemIndex := 0; StatementTypeClick(Self); InitUpdateTableNames; ShowWait(InitGenerateOptions); PageControl.ActivePage := PageControl.Pages[0]; if ShowModal = mrOk then begin for Index := low(TUpdateKind) to high(TUpdateKind) do UpdateSQL.SQL[Index] := SQLText[Index]; Result := True; end; finally for Index := Low(TUpdateKind) to High(TUpdateKind) do SQLText[Index].Free; end; end; procedure TZUpdateSQLEditForm.GenWhereClause(const TabAlias: string; KeyFields, SQL: TStrings); var I: Integer; BindText: string; FieldName: string; OldFieldName: string; begin SQL.Add('WHERE'); { Do not localize } for I := 0 to KeyFields.Count - 1 do begin FieldName := KeyFields[I]; OldFieldName := 'OLD_' + FieldName; if QuoteFields.Checked then FieldName := InternalQuoteIdentifier(FieldName, QuoteChar); if not Assigned(KeyFields.Objects[I]) then BindText := Format(' %s%s = :%s', { Do not localize } [TabAlias, FieldName, OldFieldName]) else BindText := Format(' ((%0:s%1:s IS NULL AND :%2:s IS NULL) OR (%0:s%1:s = :%2:s))', { Do not localize } [TabAlias, FieldName, OldFieldName]); if I < KeyFields.Count - 1 then BindText := Format('%s AND',[BindText]); { Do not localize } SQL.Add(BindText); end; end; procedure TZUpdateSQLEditForm.GenDeleteSQL(const TableName: string; KeyFields, SQL: TStrings); begin SQL.Add(Format('DELETE FROM %s', [TableName])); { Do not localize } GenWhereClause(GetTableRef(TableName), KeyFields, SQL); end; procedure TZUpdateSQLEditForm.GenInsertSQL(const TableName: string; UpdateFields, SQL: TStrings); procedure GenFieldList(const TabName, ParamChar: String); var L: string; I: integer; Comma: string; FieldName: string; begin L := ' ('; Comma := ', '; for I := 0 to UpdateFields.Count - 1 do begin if I = UpdateFields.Count - 1 then Comma := ''; FieldName := UpdateFields[I]; if QuoteFields.Checked and (ParamChar = '') then FieldName := InternalQuoteIdentifier(FieldName, QuoteChar); L := Format('%s%s%s%s',[L, ParamChar, FieldName, Comma]); if (Length(L) > 70) and (I <> UpdateFields.Count - 1) then begin SQL.Add(L); L := ' '; end; end; SQL.Add(L+')'); end; begin SQL.Add(Format('INSERT INTO %s', [TableName])); { Do not localize } GenFieldList(GetTableRef(TableName), ''); SQL.Add('VALUES'); { Do not localize } GenFieldList('', ':'); end; procedure TZUpdateSQLEditForm.GenModifySQL(const TableName: string; KeyFields, UpdateFields, SQL: TStrings); var I: integer; Comma: string; TableRef: string; FieldName: string; begin SQL.Add(Format('UPDATE %s SET', [TableName])); { Do not localize } Comma := ','; TableRef := GetTableRef(TableName); for I := 0 to UpdateFields.Count - 1 do begin if I = UpdateFields.Count -1 then Comma := ''; FieldName := UpdateFields[I]; if QuoteFields.Checked then FieldName := InternalQuoteIdentifier(FieldName, QuoteChar); SQL.Add(Format(' %s = :%s%s', [FieldName, UpdateFields[I], Comma])); end; GenWhereClause(TableRef, KeyFields, SQL); end; procedure TZUpdateSQLEditForm.GenerateSQL; function QuotedTableName(const BaseName: string): string; begin if QuoteFields.Checked then Result := InternalQuoteIdentifier(BaseName, QuoteChar) else Result := BaseName; end; var KeyFields: TStringList; UpdateFields: TStringList; TableName: string; begin if (KeyFieldList.SelCount = 0) or (UpdateFieldList.SelCount = 0) then raise Exception.Create(SSQLGenSelect); KeyFields := TStringList.Create; try GetSelectedItems(KeyFieldList, KeyFields); UpdateFields := TStringList.Create; try GetSelectedItems(UpdateFieldList, UpdateFields); TableName := QuotedTableName(UpdateTableName.Text); if (SQLText[ukDelete].Text <> '') or (SQLText[ukInsert].Text <> '') or (SQLText[ukModify].Text <> '') then if MessageDlg('The SQL property is not empty. Do you want to clear it before the generation?', mtWarning, [mbYes, mbNo], 0) = mrYes then begin SQLText[ukDelete].Clear; SQLText[ukInsert].Clear; SQLText[ukModify].Clear; end else begin SQLText[ukDelete].Text := SQLText[ukDelete].Text + '';//!!!Statement separator should be added SQLText[ukDelete].Add(''); SQLText[ukInsert].Text := SQLText[ukInsert].Text + '';//!!!Statement separator should be added SQLText[ukInsert].Add(''); SQLText[ukModify].Text := SQLText[ukModify].Text + '';//!!!Statement separator should be added SQLText[ukModify].Add(''); end; GenDeleteSQL(TableName, KeyFields, SQLText[ukDelete]); GenInsertSQL(TableName, UpdateFields, SQLText[ukInsert]); GenModifySQL(TableName, KeyFields, UpdateFields, SQLText[ukModify]); SQLMemo.Modified := False; StatementTypeClick(Self); PageControl.SelectNextPage(True); finally UpdateFields.Free; end; finally KeyFields.Free; end; end; procedure TZUpdateSQLEditForm.GetDataSetFieldNames; begin if Assigned(DataSet) and Assigned(Dataset.Connection) then begin GetDataKeyNames(DataSet, DataSet.Name, KeyFieldList.Items); GetDataFieldNames(DataSet, DataSet.Name, UpdateFieldList.Items); end; end; procedure TZUpdateSQLEditForm.GetTableFieldNames; var ResultSet: IZResultSet; begin if Assigned(DataSet) and Assigned(DataSet.Connection) and Assigned(DataSet.Connection.dbcConnection)then begin KeyFieldList.Clear; UpdateFieldList.Clear; ResultSet := DataSet.Connection.DbcConnection.GetMetadata.GetColumns('', '', UpdateTableName.Text, ''); if Assigned(ResultSet) then begin while ResultSet.Next do begin if ResultSet.GetBooleanByName('SEARCHABLE') then KeyFieldList.Items.AddObject(ResultSet.GetStringByName('COLUMN_NAME'), Pointer(ResultSet.GetIntByName('NULLABLE') <> 0)); if ResultSet.GetBooleanByName('WRITABLE') then UpdateFieldList.Items.Add(ResultSet.GetStringByName('COLUMN_NAME')) ; end; end; FDatasetDefaults := False; end; end; function TZUpdateSQLEditForm.GetTableRef(const TabName: string): string; begin if QuoteChar <> '' then Result := TabName + '.' else REsult := ''; end; procedure TZUpdateSQLEditForm.InitGenerateOptions; var UpdTabName: string; procedure InitFromDataSet; begin // If this is a Query with more than 1 table in the "from" clause then // initialize the list of fields from the table rather than the dataset. if (UpdateTableName.Items.Count > 1) then GetTableFieldNames else begin GetDataSetFieldNames; FDatasetDefaults := True; end; SetDefaultSelections; end; procedure InitFromUpdateSQL; var UpdFields, WhFields: TStrings; begin UpdFields := TStringList.Create; try WhFields := TStringList.Create; try ParseUpdateSQL(SQLText[ukModify].Text, QuoteChar, UpdTabName, UpdFields, WhFields); GetDataSetFieldNames; if SetSelectedItems(UpdateFieldList, UpdFields) < 1 then SelectAll(UpdateFieldList); if SetSelectedItems(KeyFieldList, WhFields) < 1 then SelectAll(KeyFieldList); finally WhFields.Free; end; finally UpdFields.Free; end; end; begin // If there are existing update SQL statements, try to initialize the // dialog with the fields that correspond to them. if SQLText[ukModify].Count > 0 then begin ParseUpdateSQL(SQLText[ukModify].Text, QuoteChar, UpdTabName, nil, nil); // If the table name from the update statement is not part of the // dataset, then initialize from the dataset instead. if (UpdateTableName.Items.Count > 0) and (UpdateTableName.Items.IndexOf(UpdTabName) > -1) then begin UpdateTableName.Text := UpdTabName; InitFromUpdateSQL; end else begin InitFromDataSet; UpdateTableName.Items.Add(UpdTabName); end; end else InitFromDataSet; SetButtonStates; end; type THackDataSet = class(TZAbstractDataset); procedure TZUpdateSQLEditForm.InitUpdateTableNames; var I: Integer; TableName: string; Tokenizer: IZTokenizer; StatementAnalyser: IZStatementAnalyser; SelectSchema: IZSelectSchema; begin QuoteChar := '""'; if Assigned(DataSet) and Assigned(DataSet.Connection) and Assigned(DataSet.Connection.DbcConnection)then begin QuoteChar := DataSet.Connection.DbcConnection.GetMetadata.GetDatabaseInfo. GetIdentifierQuoteString; if Length(QuoteChar) = 1 then QuoteChar := QuoteChar + QuoteChar; { Parses the Select statement and retrieves a schema object. } Tokenizer := DataSet.Connection.DbcDriver.GetTokenizer; StatementAnalyser := DataSet.Connection.DbcDriver.GetStatementAnalyser; SelectSchema := StatementAnalyser.DefineSelectSchemaFromQuery(Tokenizer, THackDataSet(DataSet).SQL.Text); if Assigned(SelectSchema) then begin UpdateTableName.Clear; for I := 0 to SelectSchema.TableCount - 1 do UpdateTableName.Items.Add(SelectSchema.Tables[I].Table);//!!!Schema support end; end else if Assigned(Dataset) then begin TableName := ''; if SQLText[ukModify].Count > 0 then ParseUpdateSql(SQLText[ukModify].Text, QuoteChar, TableName, nil, nil); if TableName <> '' then UpdateTableName.Items.Add(TableName); end; if UpdateTableName.Items.Count > 0 then UpdateTableName.ItemIndex := 0; end; procedure TZUpdateSQLEditForm.SetButtonStates; begin GetTableFieldsButton.Enabled := UpdateTableName.Text <> ''; PrimaryKeyButton.Enabled := GetTableFieldsButton.Enabled and (KeyFieldList.Items.Count > 0); GenerateButton.Enabled := GetTableFieldsButton.Enabled and (UpdateFieldList.Items.Count > 0) and (KeyFieldList.Items.Count > 0); DefaultButton.Enabled := Assigned(DataSet) and not FDatasetDefaults; end; procedure TZUpdateSQLEditForm.SelectPrimaryKeyFields; var I: Integer; Index: Integer; PKeys: TZSQLMetadata; begin if KeyFieldList.Items.Count < 1 then Exit; with Dataset do begin for I := 0 to KeyFieldList.Items.Count - 1 do KeyFieldList.Selected[I] := False; PKeys := TZSQLMetadata.Create(nil); try PKeys.Connection := Connection; PKeys.TableName := UpdateTableName.Text; PKeys.MetadataType := mdPrimaryKeys; PKeys.Open; PKeys.First; while not PKeys.Eof do begin Index := KeyFieldList.Items.IndexOf(PKeys.FieldByName('COLUMN_NAME').AsString); if Index > -1 then KeyFieldList.Selected[Index] := True; PKeys.Next; end; finally PKeys.Free; end; end; end; procedure TZUpdateSQLEditForm.SetDefaultSelections; var DSFields: TStringList; begin if FDatasetDefaults or not Assigned(DataSet) then begin SelectAll(UpdateFieldList); SelectAll(KeyFieldList); end else if (DataSet.FieldDefs.Count > 0) then begin DSFields := TStringList.Create; try GetDataFieldNames(DataSet, '', DSFields); SetSelectedItems(KeyFieldList, DSFields); SetSelectedItems(UpdateFieldList, DSFields); finally DSFields.Free; end; end; end; procedure TZUpdateSQLEditForm.ShowWait(WaitMethod: TWaitMethod); begin Screen.Cursor := crHourGlass; try WaitMethod; finally Screen.Cursor := crDefault; end; end; { Event Handlers } procedure TZUpdateSQLEditForm.FormCreate(Sender: TObject); begin // HelpContext := hcDUpdateSQL; end; procedure TZUpdateSQLEditForm.FormResize(Sender: TObject); Var i: Integer; begin i := PageControl.Height - 92; If i < 0 Then i := 0; SQLMemo.Height := i; end; procedure TZUpdateSQLEditForm.HelpButtonClick(Sender: TObject); begin Application.HelpContext(HelpContext); end; procedure TZUpdateSQLEditForm.StatementTypeClick(Sender: TObject); begin if SQLMemo.Modified then SQLText[TUpdateKind(StmtIndex)].Assign(SQLMemo.Lines); StmtIndex := StatementType.ItemIndex; SQLMemo.Lines.Assign(SQLText[TUpdateKind(StmtIndex)]); end; procedure TZUpdateSQLEditForm.OkButtonClick(Sender: TObject); begin if SQLMemo.Modified then SQLText[TUpdateKind(StmtIndex)].Assign(SQLMemo.Lines); end; procedure TZUpdateSQLEditForm.DefaultButtonClick(Sender: TObject); begin with UpdateTableName do if Items.Count > 0 then ItemIndex := 0; ShowWait(GetDataSetFieldNames); FDatasetDefaults := True; SetDefaultSelections; KeyfieldList.SetFocus; SetButtonStates; end; procedure TZUpdateSQLEditForm.GenerateButtonClick(Sender: TObject); begin GenerateSQL; FSettingsChanged := False; end; procedure TZUpdateSQLEditForm.PrimaryKeyButtonClick(Sender: TObject); begin ShowWait(SelectPrimaryKeyFields); SettingsChanged(Sender); end; procedure TZUpdateSQLEditForm.PageControlChanging(Sender: TObject; var AllowChange: Boolean); begin if (PageControl.ActivePage = PageControl.Pages[0]) and not SQLPage.Enabled then AllowChange := False; end; procedure TZUpdateSQLEditForm.FormDestroy(Sender: TObject); begin if ConnectionOpened then DataSet.Connection.Disconnect; end; procedure TZUpdateSQLEditForm.GetTableFieldsButtonClick(Sender: TObject); begin ShowWait(GetTableFieldNames); SetDefaultSelections; SettingsChanged(Sender); end; procedure TZUpdateSQLEditForm.SettingsChanged(Sender: TObject); begin FSettingsChanged := True; FDatasetDefaults := False; SetButtonStates; end; procedure TZUpdateSQLEditForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin if (ModalResult = mrOK) and FSettingsChanged then CanClose := MessageDlg(SSQLNotGenerated, mtConfirmation, mbYesNoCancel, 0) = mrYes; end; procedure TZUpdateSQLEditForm.UpdateTableNameChange(Sender: TObject); begin SettingsChanged(Sender); end; procedure TZUpdateSQLEditForm.UpdateTableNameClick(Sender: TObject); begin if not Visible then Exit; GetTableFieldsButtonClick(Sender); end; procedure TZUpdateSQLEditForm.SelectAllClick(Sender: TObject); begin SelectAll(FieldListPopup.PopupComponent as TListBox); end; procedure TZUpdateSQLEditForm.ClearAllClick(Sender: TObject); var I: Integer; begin with FieldListPopup.PopupComponent as TListBox do begin Items.BeginUpdate; try for I := 0 to Items.Count - 1 do Selected[I] := False; finally Items.EndUpdate; end; end; end; procedure TZUpdateSQLEditForm.SQLMemoKeyPress(Sender: TObject; var Key: Char); begin if Key = #27 then Close; end; {$IFDEF FPC} initialization {$i ZUpdateSqlEditor.lrs} {$ENDIF} end. ================================================ FILE: lib/zeosdbo/src/core/ZClasses.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Core classes and interfaces } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZClasses; interface {$I ZCore.inc} uses SysUtils, Classes; const ZEOS_MAJOR_VERSION = 7; ZEOS_MINOR_VERSION = 1; ZEOS_SUB_VERSION = 4; ZEOS_STATUS = 'stable'; ZEOS_VERSION = '7.1.4-stable'; {$IFDEF ENABLE_POOLED} {Pooled Protocol Prefix, including final dot} PooledPrefix = 'pooled.'; {$ENDIF} type {$IFDEF OLDFPC} PDateTime = ^TDateTime; TAggregatedObject = class(TObject) private FController: Pointer; function GetController: IInterface; protected {$IFDEF FPC2_5UP} function QueryInterface({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; virtual; function _AddRef : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; function _Release : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; {$ELSE} function QueryInterface(const iid : tguid;out obj) : longint;stdcall; function _AddRef : longint;stdcall; function _Release : longint;stdcall; {$ENDIF} public constructor Create(const Controller: IInterface); property Controller: IInterface read GetController; end; TContainedObject = class(TAggregatedObject, IInterface) protected {$IFDEF FPC2_5UP} function QueryInterface({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; override; {$ELSE} function QueryInterface(const iid : tguid;out obj) : longint;stdcall; {$ENDIF} end; {$ENDIF} {** Replacement for generic interface type. } IZInterface = IUnknown; {** Represents an interface for all abstract object. } IZObject = interface(IZInterface) ['{EF46E5F7-00CF-4DDA-BED0-057D6686AEE0}'] function Equals(const Value: IZInterface): Boolean; function GetHashCode: LongInt; function Clone: IZInterface; function ToString: string; function InstanceOf(const IId: TGUID): Boolean; end; {** Represents a fake interface for coparable objects. } IZComparable = interface(IZObject) ['{04112081-F07B-4BBF-A757-817816EB67C1}'] end; {** Represents an interface to clone objects. } IZClonnable = interface(IZObject) ['{ECB7F3A4-7B2E-4130-BA66-54A2D43C0149}'] end; {** Represents a generic collection iterator interface. } IZIterator = interface(IZObject) ['{D964DDD0-2308-4D9B-BD36-5810632512F7}'] function HasNext: Boolean; function Next: IZInterface; end; {** Represents a collection of object interfaces. } IZCollection = interface(IZClonnable) ['{51417C87-F992-4CAD-BC53-CF3925DD6E4C}'] function Get(Index: Integer): IZInterface; procedure Put(Index: Integer; const Item: IZInterface); function IndexOf(const Item: IZInterface): Integer; function GetCount: Integer; function GetIterator: IZIterator; function First: IZInterface; function Last: IZInterface; function Add(const Item: IZInterface): Integer; procedure Insert(Index: Integer; const Item: IZInterface); function Remove(const Item: IZInterface): Integer; procedure Exchange(Index1, Index2: Integer); procedure Delete(Index: Integer); procedure Clear; function Contains(const Item: IZInterface): Boolean; function ContainsAll(const Col: IZCollection): Boolean; function AddAll(const Col: IZCollection): Boolean; function RemoveAll(const Col: IZCollection): Boolean; property Count: Integer read GetCount; property Items[Index: Integer]: IZInterface read Get write Put; default; end; {** Represents a hash map interface. } IZHashMap = interface(IZClonnable) ['{782C64F4-AD09-4F56-AF2B-E4193A05BBCE}'] function Get(const Key: IZInterface): IZInterface; procedure Put(const Key: IZInterface; const Value: IZInterface); function GetKeys: IZCollection; function GetValues: IZCollection; function GetCount: Integer; function Remove(Key: IZInterface): Boolean; procedure Clear; property Count: Integer read GetCount; property Keys: IZCollection read GetKeys; property Values: IZCollection read GetValues; end; {** Represents a stack interface. } IZStack = interface(IZClonnable) ['{8FEA0B3F-0C02-4E70-BD8D-FB0F42D4497B}'] function Peek: IZInterface; function Pop: IZInterface; procedure Push(Value: IZInterface); function GetCount: Integer; property Count: Integer read GetCount; end; {$IFDEF WITH_NEWTOBJECT} // to suppress the overload warning of the Equals overload, Marco. (overload a non overload-declared funtion) {$WARNINGS OFF} {$ENDIF} {** Implements an abstract interfaced object. } TZAbstractObject = class(TInterfacedObject, IZObject) public function Equals(const Value: IZInterface): Boolean; {$IFDEF WITH_NEWTOBJECT}overload;{$ENDIF} virtual; function GetHashCode: LongInt; function Clone: IZInterface; virtual; function ToString: string;{$IFDEF WITH_NEWTOBJECT}override{$ELSE} virtual{$ENDIF} ; function InstanceOf(const IId: TGUID): Boolean; end; {$IFDEF WITH_NEWTOBJECT} {$WARNINGS ON} {$ENDIF} implementation uses ZMessages, ZCompatibility; {$IFDEF oldFPC} { TAggregatedObject } constructor TAggregatedObject.Create(const Controller: IInterface); begin FController := Pointer(Controller); end; function TAggregatedObject.GetController: IInterface; begin Result := IInterface(FController); end; {$IFDEF FPC2_5UP} function TAggregatedObject.QueryInterface({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint; {$ELSE} function TAggregatedObject.QueryInterface(const iid : tguid;out obj) : longint;stdcall; {$ENDIF} begin Result := IInterface(FController).QueryInterface(IID, Obj); end; function TAggregatedObject._AddRef: longint; begin Result := IInterface(FController)._AddRef; end; function TAggregatedObject._Release : longint; begin Result := IInterface(FController)._Release; end; { TContainedObject } {$IFDEF FPC2_5UP} function TContainedObject.QueryInterface({$IFDEF FPC_HAS_CONSTREF}constref{$ELSE}const{$ENDIF} iid : tguid;out obj) : longint;{$IFNDEF WINDOWS}cdecl{$ELSE}stdcall{$ENDIF}; {$ELSE} function TContainedObject.QueryInterface(const iid : tguid;out obj) : longint;stdcall; {$ENDIF} begin if GetInterface(IID, Obj) then Result := S_OK else Result := E_NOINTERFACE; end; {$ENDIF} { TZAbstractObject } {** Checks is the specified value equals to this object. @param Value an interface to some object. @return True if the objects are identical. } function TZAbstractObject.Equals(const Value: IZInterface): Boolean; begin if Value <> nil then begin Result := (IZInterface(Self) = Value) or ((Self as IZInterface) = (Value as IZInterface)); end else Result := False; end; {** Gets a unique hash for this object. @return a unique hash for this object. } function TZAbstractObject.GetHashCode: LongInt; begin Result := LongInt(Self); end; {** Clones an object instance. @return a clonned object instance. } function TZAbstractObject.Clone: IZInterface; begin raise Exception.Create(SClonningIsNotSupported); result := nil; end; {** Checks is this object implements a specified interface. @param IId an interface id. @return True if this object support the interface. } function TZAbstractObject.InstanceOf(const IId: TGUID): Boolean; begin Result := GetInterfaceEntry(IId) <> nil; end; {** Converts this object into the string representation. @return a string representation for this object. } function TZAbstractObject.ToString: string; begin Result := Format('%s <%p>', [ClassName, Pointer(Self)]) end; end. ================================================ FILE: lib/zeosdbo/src/core/ZCollections.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Core collection and map classes } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZCollections; interface {$I ZCore.inc} uses Classes, ZClasses; type {** Implements an iterator for regular TZCollection collection. } TZIterator = class (TZAbstractObject, IZIterator) private FCollection: IZCollection; FCurrentIndex: Integer; public constructor Create(const Col: IZCollection); function HasNext: Boolean; function Next: IZInterface; end; {** Interface list types. } TZInterfaceList = array[0..{$IFDEF WITH_MAXLISTSIZE_DEPRECATED}Maxint div 16{$ELSE}MaxListSize{$ENDIF} - 1] of IZInterface; PZInterfaceList = ^TZInterfaceList; {** Implenments a collection of interfaces. } TZCollection = class(TZAbstractObject, IZCollection, IZClonnable) private FList: PZInterfaceList; FCount: Integer; FCapacity: Integer; protected class procedure Error(const Msg: string; Data: Integer); procedure Grow; procedure SetCapacity(NewCapacity: Integer); procedure SetCount(NewCount: Integer); public constructor Create; destructor Destroy; override; function Clone: IZInterface; override; function ToString: string; override; function Get(Index: Integer): IZInterface; procedure Put(Index: Integer; const Item: IZInterface); function IndexOf(const Item: IZInterface): Integer; function GetCount: Integer; function GetIterator: IZIterator; function First: IZInterface; function Last: IZInterface; function Add(const Item: IZInterface): Integer; procedure Insert(Index: Integer; const Item: IZInterface); function Remove(const Item: IZInterface): Integer; procedure Exchange(Index1, Index2: Integer); procedure Delete(Index: Integer); procedure Clear; function Contains(const Item: IZInterface): Boolean; function ContainsAll(const Col: IZCollection): Boolean; function AddAll(const Col: IZCollection): Boolean; function RemoveAll(const Col: IZCollection): Boolean; property Count: Integer read GetCount; property Items[Index: Integer]: IZInterface read Get write Put; default; end; {** Implements an unmodifiable collection of interfaces. } TZUnmodifiableCollection = class(TZAbstractObject, IZCollection, IZClonnable) private FCollection: IZCollection; private procedure RaiseException; public constructor Create(Collection: IZCollection); destructor Destroy; override; function Clone: IZInterface; override; function ToString: string; override; function Get(Index: Integer): IZInterface; procedure Put(Index: Integer; const Item: IZInterface); function IndexOf(const Item: IZInterface): Integer; function GetCount: Integer; function GetIterator: IZIterator; function First: IZInterface; function Last: IZInterface; function Add(const Item: IZInterface): Integer; procedure Insert(Index: Integer; const Item: IZInterface); function Remove(const Item: IZInterface): Integer; procedure Exchange(Index1, Index2: Integer); procedure Delete(Index: Integer); procedure Clear; function Contains(const Item: IZInterface): Boolean; function ContainsAll(const Col: IZCollection): Boolean; function AddAll(const Col: IZCollection): Boolean; function RemoveAll(const Col: IZCollection): Boolean; property Count: Integer read GetCount; property Items[Index: Integer]: IZInterface read Get write Put; default; end; {** Implements a hash map of interfaces. } TZHashMap = class(TZAbstractObject, IZHashMap, IZClonnable) private FKeys: IZCollection; FReadOnlyKeys: IZCollection; FValues: IZCollection; FReadOnlyValues: IZCollection; public constructor Create; destructor Destroy; override; function Clone: IZInterface; override; function Get(const Key: IZInterface): IZInterface; procedure Put(const Key: IZInterface; const Value: IZInterface); function GetKeys: IZCollection; function GetValues: IZCollection; function GetCount: Integer; function Remove(Key: IZInterface): Boolean; procedure Clear; property Count: Integer read GetCount; property Keys: IZCollection read GetKeys; property Values: IZCollection read GetValues; end; {** Implements a stack of interfaces. } TZStack = class(TZAbstractObject, IZStack, IZClonnable) private FValues: IZCollection; public constructor Create; destructor Destroy; override; function Clone: IZInterface; override; function ToString: string; override; function Peek: IZInterface; function Pop: IZInterface; procedure Push(Value: IZInterface); function GetCount: Integer; property Count: Integer read GetCount; end; implementation uses SysUtils, ZMessages; {$IFDEF FPC} {$HINTS OFF} {$ENDIF} { TZIterator } {** Creates this iterator for the specified interface list. @param List a list of interfaces. } constructor TZIterator.Create(const Col: IZCollection); begin FCollection := Col; FCurrentIndex := 0; end; {** Checks has the iterated collection more elements. @return True if iterated collection has more elements. } function TZIterator.HasNext: Boolean; begin Result := FCurrentIndex < FCollection.Count; end; {** Gets a next iterated element from the collection. @return a next iterated element from the collection or null if no more elements. } function TZIterator.Next: IZInterface; begin if FCurrentIndex < FCollection.Count then begin Result := FCollection[FCurrentIndex]; Inc(FCurrentIndex); end else Result := nil; end; { TZCollection } {** Creates this collection and assignes main properties. } constructor TZCollection.Create; begin end; {** Destroys this object and frees the memory. } destructor TZCollection.Destroy; begin Clear; end; {** Raises a collection error. @param Msg an error message. @param Data a integer value to describe an error. } class procedure TZCollection.Error(const Msg: string; Data: Integer); {$IFNDEF FPC} function ReturnAddr: Pointer; asm MOV EAX,[EBP+4] end; {$ENDIF} begin {$IFDEF FPC} raise EListError.CreateFmt(Msg,[Data]) at get_caller_addr(get_frame); {$ELSE} raise EListError.CreateFmt(Msg, [Data]) at ReturnAddr; {$ENDIF} end; {** Increases an element count. } procedure TZCollection.Grow; var Delta: Integer; begin if FCapacity > 64 then Delta := FCapacity div 4 else begin if FCapacity > 8 then Delta := 16 else Delta := 4; end; SetCapacity(FCapacity + Delta); end; {** Sets a new list capacity. @param NewCapacity a new list capacity. } procedure TZCollection.SetCapacity(NewCapacity: Integer); begin {$IFOPT R+} if (NewCapacity < FCount) or (NewCapacity > {$IFDEF WITH_MAXLISTSIZE_DEPRECATED}Maxint div 16{$ELSE}MaxListSize{$ENDIF}) then Error(SListCapacityError, NewCapacity); {$ENDIF} if NewCapacity <> FCapacity then begin ReallocMem(FList, NewCapacity * SizeOf(IZInterface)); if NewCapacity > FCapacity then FillChar(FList^[FCount], (NewCapacity - FCapacity) * SizeOf(IZInterface), 0); FCapacity := NewCapacity; end; end; {** Sets a new element count. @param NewCount a new element count. } procedure TZCollection.SetCount(NewCount: Integer); var I: Integer; begin {$IFOPT R+} if (NewCount < 0) or (NewCount > {$IFDEF WITH_MAXLISTSIZE_DEPRECATED}Maxint div 16{$ELSE}MaxListSize{$ENDIF}) then Error(SListCountError, NewCount); {$ENDIF} if NewCount > FCapacity then SetCapacity(NewCount); if NewCount < FCount then begin for I := FCount - 1 downto NewCount do FList^[I] := nil; end; FCount := NewCount; end; {** Clones the instance of this object. @return a reference to the clonned object. } function TZCollection.Clone: IZInterface; var I: Integer; Collection: IZCollection; Clonnable: IZClonnable; begin Collection := TZCollection.Create; for I := 0 to FCount - 1 do begin if FList^[I].QueryInterface(IZClonnable, Clonnable) = 0 then Collection.Add(Clonnable.Clone) else Collection.Add(FList^[I]); end; Result := Collection; end; {** Adds a new object at the and of this collection. @param Item an object to be added. @return a position of the added object. } function TZCollection.Add(const Item: IZInterface): Integer; begin Result := FCount; if Result = FCapacity then Grow; // FList^[Result] := Item as IZInterface; // enourmous Memory Hole in FPC > 2.0.2 Release FList^[Result] := Item; Inc(FCount); end; {** Adds all elements from the specified collection into this collection. @param Col a collection of objects to be added. @return True is the collection was changed. } function TZCollection.AddAll(const Col: IZCollection): Boolean; var I: Integer; begin Result := Col.Count > 0; for I := 0 to Col.Count - 1 do Add(Col[I]); end; {** Clears the content of this collection. } procedure TZCollection.Clear; begin SetCount(0); SetCapacity(0); end; {** Checks is the specified object is stored in this collection. @return True if the object was found in the collection. } function TZCollection.Contains(const Item: IZInterface): Boolean; begin Result := IndexOf(Item) >= 0; end; {** Checks are all the object in this collection. @param Col a collection of objects to be checked. @return True if all objects are in this collection. } function TZCollection.ContainsAll(const Col: IZCollection): Boolean; var I: Integer; begin Result := Col.Count > 0; for I := 0 to Col.Count - 1 do begin if IndexOf(Col[I]) < 0 then begin Result := False; Break; end; end; end; {** Deletes an object from the specified position. } procedure TZCollection.Delete(Index: Integer); begin {$IFOPT R+} if (Index < 0) or (Index >= FCount) then Error(SListIndexError, Index); {$ENDIF} FList^[Index] := nil; Dec(FCount); if Index < FCount then begin System.Move(FList^[Index + 1], FList^[Index], (FCount - Index) * SizeOf(IZInterface)); {now nil pointer or on replacing the entry we'll get a bad interlockdecrement} Pointer(FList^[FCount]) := nil; //see http://sourceforge.net/p/zeoslib/tickets/100/ end; end; {** Exchanges two element in the collection. @param Index1 an index of the first element. @param Index2 an index of the second element. } procedure TZCollection.Exchange(Index1, Index2: Integer); var Item: IZInterface; begin {$IFOPT R+} if (Index1 < 0) or (Index1 >= FCount) then Error(SListIndexError, Index1); if (Index2 < 0) or (Index2 >= FCount) then Error(SListIndexError, Index2); {$ENDIF} Item := FList^[Index1]; FList^[Index1] := FList^[Index2]; FList^[Index2] := Item; end; {** Gets the first element from this collection. @return the first element. } function TZCollection.First: IZInterface; begin Result := Get(0); end; {** Gets a collection element from the specified position. @param Index a position index of the element. @return a requested element. } function TZCollection.Get(Index: Integer): IZInterface; begin {$IFOPT R+} if (Index < 0) or (Index >= FCount) then Error(SListIndexError, Index); {$ENDIF} Result := FList^[Index]; end; {** Gets a number of the stored element in this collection. @return a number of stored elements. } function TZCollection.GetCount: Integer; begin Result := FCount; end; {** Gets a created iterator for this collection. @return a created iterator for this collection. } function TZCollection.GetIterator: IZIterator; begin Result := TZIterator.Create(Self); end; {** Defines an index of the specified object inside this colleciton. @param Item an object to be found. @return an object position index or -1 if it was not found. } function TZCollection.IndexOf(const Item: IZInterface): Integer; var I: Integer; Comparable: IZComparable; Unknown: IZInterface; begin Result := -1; if (FCount = 0) or (Item = nil) then Exit; { Find IComparable objects } if Item.QueryInterface(IZComparable, Comparable) = 0 then begin for I := 0 to FCount - 1 do begin if Comparable.Equals(FList^[I]) then begin Result := I; Break; end; end; Comparable := nil; end { Find ordinary objects } else begin Unknown := Item; for I := 0 to FCount - 1 do begin if Unknown = FList^[I] then begin Result := I; Break; end; end; Unknown := nil; end; end; {** Inserts an object into specified position. @param Index a position index. @param Item an object to be inserted. } procedure TZCollection.Insert(Index: Integer; const Item: IZInterface); begin {$IFOPT R+} if (Index < 0) or (Index > FCount) then Error(SListIndexError, Index); {$ENDIF} if FCount = FCapacity then Grow; if Index < FCount then begin System.Move(FList^[Index], FList^[Index + 1], (FCount - Index) * SizeOf(IZInterface)); {now nil pointer or on replacing the entry we'll get a bad interlockdecrement} Pointer(Flist^[Index]) := nil; //see http://sourceforge.net/p/zeoslib/tickets/100/ end; FList^[Index] := Item; Inc(FCount); end; {** Gets the last object from this collection. @return the last object. } function TZCollection.Last: IZInterface; begin Result := Get(FCount - 1); end; {** Puts a specified object into defined position. @param Index a position index. @param Items ab object to be put. } procedure TZCollection.Put(Index: Integer; const Item: IZInterface); begin {$IFOPT R+} if (Index < 0) or (Index >= FCount) then Error(SListIndexError, Index); {$ENDIF} FList^[Index] := Item; end; {** Removes an existed object which equals to the specified one. @param Item an object to be removed. @return an index of the removed object. } function TZCollection.Remove(const Item: IZInterface): Integer; begin Result := IndexOf(Item); if Result >= 0 then Delete(Result); end; {** Removes all the elements from the specified collection. @param Col a collection of object to be removed. @return True if this collection was changed. } function TZCollection.RemoveAll(const Col: IZCollection): Boolean; var I: Integer; begin Result := False; for I := 0 to Col.Count - 1 do Result := (Remove(Col[I]) >= 0) or Result; end; {** Gets a string representation for this object. } function TZCollection.ToString: string; var I: Integer; TempObject: IZObject; begin Result := ''; for I := 0 to FCount - 1 do begin if I > 0 then Result := Result + ','; if FList^[I].QueryInterface(IZObject, TempObject) = 0 then Result := Result + TempObject.ToString else Result := Result + Format('<%p>', [Pointer(FList^[I])]); end; Result := '[' + Result + ']'; end; { TZUnmodifiableCollection } {** Constructs this object and assignes main properties. @param Collection an initial modifiable list of interfaces. } constructor TZUnmodifiableCollection.Create(Collection: IZCollection); begin inherited Create; FCollection := Collection; end; {** Destroys this object and frees the memory. } destructor TZUnmodifiableCollection.Destroy; begin FCollection := nil; inherited Destroy; end; {** Clones the instance of this object. @return a reference to the clonned object. } function TZUnmodifiableCollection.Clone: IZInterface; begin Result := TZUnmodifiableCollection.Create(FCollection); end; {** Raises invalid operation exception. } procedure TZUnmodifiableCollection.RaiseException; begin raise EInvalidOperation.Create(SImmutableOpIsNotAllowed); end; {** Adds a new object at the and of this collection. @param Item an object to be added. @return a position of the added object. } function TZUnmodifiableCollection.Add(const Item: IZInterface): Integer; begin Result := -1; RaiseException; end; {** Adds all elements from the specified collection into this collection. @param Col a collection of objects to be added. @return True is the collection was changed. } function TZUnmodifiableCollection.AddAll(const Col: IZCollection): Boolean; begin Result := False; RaiseException; end; {** Clears the content of this collection. } procedure TZUnmodifiableCollection.Clear; begin RaiseException; end; {** Checks is the specified object is stored in this collection. @return True if the object was found in the collection. } function TZUnmodifiableCollection.Contains(const Item: IZInterface): Boolean; begin Result := FCollection.Contains(Item); end; {** Checks are all the object in this collection. @param Col a collection of objects to be checked. @return True if all objects are in this collection. } function TZUnmodifiableCollection.ContainsAll(const Col: IZCollection): Boolean; begin Result := FCollection.ContainsAll(Col); end; {** Deletes an object from the specified position. } procedure TZUnmodifiableCollection.Delete(Index: Integer); begin RaiseException; end; {** Exchanges two element in the collection. @param Index1 an index of the first element. @param Index2 an index of the second element. } procedure TZUnmodifiableCollection.Exchange(Index1, Index2: Integer); begin RaiseException; end; {** Gets the first element from this collection. @return the first element. } function TZUnmodifiableCollection.First: IZInterface; begin Result := FCollection.First; end; {** Gets a collection element from the specified position. @param Index a position index of the element. @return a requested element. } function TZUnmodifiableCollection.Get(Index: Integer): IZInterface; begin Result := FCollection[Index]; end; {** Gets a number of the stored element in this collection. @return a number of stored elements. } function TZUnmodifiableCollection.GetCount: Integer; begin Result := FCollection.Count; end; {** Gets a created iterator for this collection. @return a created iterator for this collection. } function TZUnmodifiableCollection.GetIterator: IZIterator; begin Result := TZIterator.Create(Self); end; {** Defines an index of the specified object inside this colleciton. @param Item an object to be found. @return an object position index or -1 if it was not found. } function TZUnmodifiableCollection.IndexOf(const Item: IZInterface): Integer; begin Result := FCollection.IndexOf(Item); end; {** Inserts an object into specified position. @param Index a position index. @param Item an object to be inserted. } procedure TZUnmodifiableCollection.Insert(Index: Integer; const Item: IZInterface); begin RaiseException; end; {** Gets the last object from this collection. @return the last object. } function TZUnmodifiableCollection.Last: IZInterface; begin Result := FCollection.Last; end; {** Puts a specified object into defined position. @param Index a position index. @param Items ab object to be put. } procedure TZUnmodifiableCollection.Put(Index: Integer; const Item: IZInterface); begin RaiseException; end; {** Removes an existed object which equals to the specified one. @param Item an object to be removed. @return an index of the removed object. } function TZUnmodifiableCollection.Remove(const Item: IZInterface): Integer; begin Result := -1; RaiseException; end; {** Removes all the elements from the specified collection. @param Col a collection of object to be removed. @return True if this collection was changed. } function TZUnmodifiableCollection.RemoveAll(const Col: IZCollection): Boolean; begin Result := False; RaiseException; end; {** Gets a string representation for this object. } function TZUnmodifiableCollection.ToString: string; begin Result := FCollection.ToString; end; { TZHashMap } {** Creates this hash map and assignes main properties. } constructor TZHashMap.Create; begin inherited Create; FKeys := TZCollection.Create; FValues := TZCollection.Create; FReadOnlyKeys := TZUnmodifiableCollection.Create(FKeys); FReadOnlyValues := TZUnmodifiableCollection.Create(FValues); end; {** Destroys this object and frees the memory. } destructor TZHashMap.Destroy; begin FReadOnlyKeys := nil; FReadOnlyValues := nil; FKeys := nil; FValues := nil; inherited Destroy; end; {** Clones the instance of this object. @return a reference to the clonned object. } function TZHashMap.Clone: IZInterface; var HashMap: TZHashMap; begin HashMap := TZHashMap.Create; HashMap.FKeys := IZCollection(FKeys.Clone); HashMap.FReadOnlyKeys := IZCollection(FReadOnlyKeys.Clone); HashMap.FValues := IZCollection(FValues.Clone); HashMap.FReadOnlyValues := IZCollection(FReadOnlyValues.Clone); Result := HashMap; end; {** Gets a interface by it's key. @param Key a key interface. @return a found value interface or nil otherwise. } function TZHashMap.Get(const Key: IZInterface): IZInterface; var Index: Integer; begin Index := FKeys.IndexOf(Key); if Index >= 0 then Result := FValues[Index] else Result := nil; end; {** Put a new key/value pair interfaces. @param Key a key interface. @param Value a value interface. } procedure TZHashMap.Put(const Key: IZInterface; const Value: IZInterface); var Index: Integer; begin Index := FKeys.IndexOf(Key); if Index >= 0 then FValues[Index] := Value else begin FKeys.Add(Key); FValues.Add(Value); end; end; {** Gets a readonly collection of keys. @return a readonly collection of keys. } function TZHashMap.GetKeys: IZCollection; begin Result := FReadOnlyKeys; end; {** Gets a readonly collection of values. @return a readonly collection of values. } function TZHashMap.GetValues: IZCollection; begin Result := FReadOnlyValues; end; {** Gets a number of elements in this hash map. @return a number of elements in this hash map. } function TZHashMap.GetCount: Integer; begin Result := FKeys.Count; end; {** Removes the element from the map by it's key. @param Key a key of the element. @return true of the hash map was changed. } function TZHashMap.Remove(Key: IZInterface): Boolean; var Index: Integer; begin Index := FKeys.IndexOf(Key); if Index >= 0 then begin FKeys.Delete(Index); FValues.Delete(Index); Result := True; end else Result := False; end; {** Clears this hash map and removes all elements. } procedure TZHashMap.Clear; begin FKeys.Clear; FValues.Clear; end; { TZStack } {** Constructs this object and assignes the main properties. } constructor TZStack.Create; begin FValues := TZCollection.Create; end; {** Destroys this object and cleanups the memory. } destructor TZStack.Destroy; begin FValues := nil; inherited Destroy; end; {** Clones the instance of this object. @return a reference to the clonned object. } function TZStack.Clone: IZInterface; var Stack: TZStack; begin Stack := TZStack.Create; Stack.FValues := IZCollection(FValues.Clone); Result := Stack; end; {** Gets a count of the stored elements. @return an elements count. } function TZStack.GetCount: Integer; begin Result := FValues.Count; end; {** Gets an element from the top this stack without removing it. @return an element from the top of the stack. } function TZStack.Peek: IZInterface; begin if FValues.Count > 0 then Result := FValues[FValues.Count - 1] else Result := nil; end; {** Gets an element from the top this stack and remove it. @return an element from the top of the stack. } function TZStack.Pop: IZInterface; begin if FValues.Count > 0 then begin Result := FValues[FValues.Count - 1]; FValues.Delete(FValues.Count - 1); end else Result := nil; end; {** Puts a new element to the top of this stack. @param Value a new element to be put. } procedure TZStack.Push(Value: IZInterface); begin FValues.Add(Value); end; {** Gets a string representation for this object. } function TZStack.ToString: string; begin Result := FValues.ToString; end; end. ================================================ FILE: lib/zeosdbo/src/core/ZCompatibility.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Compatibility Classes and Functions } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZCompatibility; interface {$I ZCore.inc} uses Variants, {$IFDEF FPC} {$IFDEF UNIX} dynlibs, {$endif} {$ENDIF} {$IFDEF WITH_WIDESTRUTILS} WideStrUtils, {$ENDIF} {$If defined(MSWINDOWS) and not defined(FPC)} Windows, {$IFEND} Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} {$IFDEF WITH_LCONVENCODING} LConvEncoding,{$ENDIF} Types, SysUtils; type {$IFDEF FPC} ULong = {$IFDEF WIN64}LongWord{$ELSE}PTRUINT{$ENDIF}; // EgonHugeist: Use always a 4Byte Integer as long the PlainDriver dll's are 32Bit for Windows64 //on the other hand MySQL64 and FB64 have problems on Win64! ULongLong = QWord; NativeInt = PtrInt; NativeUInt = PtrUInt; PNativeUInt = ^NativeUInt; {$ELSE} {$IFNDEF DELPHI16_UP} NativeInt = Integer; NativeUInt = LongWord; PNativeUInt = ^NativeUInt; PWord = ^Word; // M.A. {$ENDIF} ULong = LongWord; ULongLong = {$IFDEF WITH_UINT64}Uint64{$ELSE}Int64{$ENDIF}; //delphi dont have Unsigned Int64 type {$ENDIF} PULong = ^ULong; PULongLong = ^ULongLong; UInt = LongWord; PUInt = ^UInt; ZPPWideChar = ^PWideChar;//BCB issue: PPWideChar is not part of system TObjectDynArray = array of TObject; {$IFDEF FPC} type TDBScreenCursor = (dcrDefault, dcrHourGlass, dcrSQLWait, dcrOther); IDBScreen = interface ['{29A1C508-6ADC-44CD-88DE-4F51B25D5995}'] function GetCursor: TDBScreenCursor; procedure SetCursor(Cursor: TDBScreenCursor); property Cursor: TDBScreenCursor read GetCursor write SetCursor; end; var LoginDialogProc: function (const ADatabaseName: string; var AUserName, APassword: string): Boolean; DBScreen: IDBScreen; {$ENDIF} {$IFNDEF FPC} //delphi and windows const LineEnding = #13#10; Brackets = ['(',')','[',']','{','}']; StdWordDelims = [#0..' ',',','.',';','/','\',':','''','"','`'] + Brackets; function Hash(S : AnsiString) : LongWord; function AnsiProperCase(const S: string; const WordDelims: TSysCharSet): string; {$ENDIF} {$IFDEF WINDOWS} const SharedSuffix='.dll'; {$ELSE} {$IFDEF DARWIN} const SharedSuffix='.dylib'; {$ELSE} {$IFDEF UNIX} const SharedSuffix='.so'; {$ELSE} const SharedSuffix='.dll'; //Delphi {$ENDIF} {$ENDIF} {$ENDIF} {$IFDEF UNIX} {$IFDEF FPC} const RTLD_GLOBAL = $101; INVALID_HANDLE_VALUE = 0; type HMODULE = PtrInt; function LoadLibrary(ModuleName: PChar): HMODULE; function FreeLibrary(Module: HMODULE): LongBool; function GetProcAddress(Module: HMODULE; Proc: PChar): Pointer; {$ENDIF} {$ENDIF} {EgonHugeist:} type {$IFNDEF WITH_RAWBYTESTRING} RawByteString = AnsiString; {$ENDIF} ZWideString = {$IFDEF PWIDECHAR_IS_PUNICODECHAR}UnicodeString{$ELSE}WideString{$ENDIF}; type {declare move or converter functions for the String Types} TZAnsiToRaw = function (const Src: AnsiString; const RawCP: Word): RawByteString; TZRawToAnsi = function (const Src: RawByteString; const RawCP: Word): AnsiString; TZAnsiToUTF8 = function (const Src: AnsiString): UTF8String; TZUTF8ToAnsi = function (const Src: UTF8String): AnsiString; TZRawToUTF8 = function (const Src: RawByteString; const CP: Word): UTF8String; TZUTF8ToRaw = function (const Src: UTF8String; const CP: Word): RawByteString; TZRawToString = function (const Src: RawByteString; const RawCP, StringCP: Word): String; TZStringToRaw = function (const Src: String; const StringCP, RawCP: Word): RawByteString; TZUTF8ToString = function (const Src: UTF8String; const StringCP: Word): String; TZStringToUTF8 = function (const Src: String; const StringCP: Word): UTF8String; TZAnsiToString = function (const Src: AnsiString; const StringCP: Word): String; TZStringToAnsi = function (const Src: String; const StringCP: Word): AnsiString; TZRawToUnicode = function (const S: RawByteString; const CP: Word): ZWideString; TZUnicodeToRaw = function (const US: ZWideString; CP: Word): RawByteString; TZUnicodeToString = function (const Src: ZWideString; const StringCP: Word): String; TZStringToUnicode = function (const Src: String; const StringCP: Word): ZWideString; {** Defines the Target Ansi codepages for the Controls } TZControlsCodePage = ({$IFDEF UNICODE}cCP_UTF16, cCP_UTF8, cGET_ACP{$ELSE}{$IFDEF FPC}cCP_UTF8, cCP_UTF16, cGET_ACP{$ELSE}cGET_ACP, cCP_UTF8, cCP_UTF16{$ENDIF}{$ENDIF}); TZCharEncoding = ( ceDefault, //Internal switch for the two Functions below do not use it as a CodePage-declaration! ceAnsi, //Base Ansi-String: prefered CodePage ceUTF8, //UTF8_Unicode: 1-4Byte/Char ceUTF16, //Wide or Unicode string encoding for Field-mapping ceUTF32); //reserved {Here it's possible to add some more, to handle the Ansi->Unicode-Translations} PZCodePage = ^TZCodePage; TZCodePage = record Name: String; //Name of Client-CharacterSet ID: Integer; //may be an ordinal value of predefined Types or the database used id} CharWidth: Integer; //count of Bytes per char Encoding: TZCharEncoding; //The Type of String-Translation handling CP: Word; //The CodePage the AnsiString must have to ZAlias: String; //A possible (saver?) CharacterSet which is more Zeos compatible... If it's empty it will be ignored!!! IsStringFieldCPConsistent: Boolean; //Is the current client characterset codepage consistent for all codepages? end; TConvertEncodingFunctions = record ZAnsiToUTF8: TZAnsiToUTF8; ZUTF8ToAnsi: TZUTF8ToAnsi; ZUTF8ToString: TZUTF8ToString; ZStringToUTF8: TZStringToUTF8; ZAnsiToRaw: TZAnsiToRaw; ZRawToAnsi: TZRawToAnsi; ZRawToUTF8: TZRawToUTF8; ZUTF8ToRaw: TZUTF8ToRaw; ZStringToRaw: TZStringToRaw; ZRawToString: TZRawToString; ZAnsiToString: TZAnsiToString; ZStringToAnsi: TZStringToAnsi; ZUnicodeToRaw: TZUnicodeToRaw; ZRawToUnicode: TZRawToUnicode; ZUnicodeToString: TZUnicodeToString; ZStringToUnicode: TZStringToUnicode; end; PZConSettings = ^TZConSettings; TZConSettings = record AutoEncode: Boolean; //Check Encoding and or convert string with FromCP ToCP CPType: TZControlsCodePage; //the CP-Settings type the controls do expect CTRL_CP: Word; //Target CP of string conversion (CP_ACP/CP_UPF8) ConvFuncs: TConvertEncodingFunctions; //a rec for the Convert functions used by the objects ClientCodePage: PZCodePage; //The codepage informations of the current characterset DateFormat: String; {$IFDEF WITH_LCONVENCODING} PlainConvertFunc: TConvertEncodingFunction; DbcConvertFunc: TConvertEncodingFunction; {$ENDIF} end; TZCodePagedObject = Class(TInterfacedObject) private FConSettings: PZConSettings; protected function ZDbcString(const Ansi: RawByteString; ConSettings: PZConSettings): String; overload; function ZDbcString(const Ansi: RawByteString; FromCP: Word): String; overload; function ZDbcString(const Ansi: RawByteString; const Encoding: TZCharEncoding = ceDefault): String; overload; function ZDbcString(const AStr: ZWideString; const Encoding: TZCharEncoding = ceDefault): String; overload; function ZDbcUnicodeString(const AStr: RawByteString): ZWideString; overload; function ZDbcUnicodeString(const AStr: RawByteString; const FromCP: Word): ZWideString; overload; {$IFDEF WITH_RAWBYTESTRING} function ZDbcUnicodeString(const AStr: String; const FromCP: Word): ZWideString; overload; {$ENDIF} function ZPlainString(const AStr: String; ConSettings: PZConSettings): RawByteString; overload; function ZPlainString(const AStr: String; ConSettings: PZConSettings; const ToCP: Word): RawByteString; overload; function ZPlainString(const AStr: String; const Encoding: TZCharEncoding = ceDefault): RawByteString; overload; function ZPlainString(const AStr: WideString; const Encoding: TZCharEncoding = ceDefault): RawByteString; overload; function ZPlainString(const AStr: WideString; ConSettings: PZConSettings): RawByteString; overload; function ZPlainString(const AStr: WideString; ConSettings: PZConSettings; const ToCP: Word): RawByteString; overload; function ZPlainUnicodeString(const AStr: String): WideString; procedure SetConSettingsFromInfo(Info: TStrings); property ConSettings: PZConSettings read FConSettings write FConSettings; public destructor Destroy; override; end; {$IFDEF WITH_LCONVENCODING} function NoConvert(const s: string): string; {$ENDIF} {$IF not Declared(DetectUTF8Encoding)} {$DEFINE ZDetectUTF8Encoding} Type TEncodeType = (etUSASCII, etUTF8, etANSI); function DetectUTF8Encoding(Ansi: RawByteString): TEncodeType; {$IFEND} {$IFNDEF WITH_CHARINSET} function CharInSet(C: AnsiChar; const CharSet: TSysCharSet): Boolean; overload; function CharInSet(C: WideChar; const CharSet: TSysCharSet): Boolean; overload; {$ENDIF} {$IF not Declared(UTF8ToString)} {$DEFINE ZUTF8ToString} function UTF8ToString(const s: RawByteString): ZWideString; {$IFEND} var ClientCodePageDummy: TZCodepage = (Name: ''; ID: 0; CharWidth: 1; Encoding: ceAnsi; CP: $ffff; ZAlias: ''); ConSettingsDummy: TZConSettings = (AutoEncode: False; CPType: {$IFDEF DELPHI}{$IFDEF UNICODE}cCP_UTF16{$ELSE}cGET_ACP{$ENDIF}{$ELSE}cCP_UTF8{$ENDIF}; ClientCodePage: @ClientCodePageDummy; {$IFDEF WITH_LCONVENCODING} PlainConvertFunc: @NoConvert; DbcConvertFunc: @NoConvert; {$ENDIF} ); implementation uses ZEncoding; {$IFDEF ZDetectUTF8Encoding} function DetectUTF8Encoding(Ansi: RawByteString): TEncodeType; //EgonHugeist: Detect a valid UTF8Sequence var I, Len: Integer; Source: PAnsiChar; function P(Pos: Integer = 0): Byte; begin Result := Byte(Source[Pos]); end; procedure IncPos(X: Integer = 1); begin inc(Source, X); inc(i, X); end; begin Result := etUSASCII; if Ansi = '' then Exit; Len := Length(Ansi); Source := PAnsiChar(Ansi); // skip US-ASCII Chars they are allways valid. I := 0; while ( I <= Len ) do begin if P >= $80 then break; IncPos; end; if i > Len then exit; //US ACII //No US-Ascii at all. while I < Len do begin case p of $00..$7F: //Ascii IncPos; $C2..$DF: // non-overlong 2-byte if (I+1 < Len) and (P(1) in [$80..$BF]) then IncPos(2) else break; $E0: // excluding overlongs if (I+2 < Len) and (P(1) in [$A0..$BF]) and (P(2) in [$80..$BF]) then IncPos(3) else break; $E1..$EF: // straight 3-byte & excluding surrogates if (i+2 < Len) and (P(1) in [$80..$BF]) and (P(2) in [$80..$BF]) then IncPos(3) else break; $F0: // planes 1-3 if (i+3 < Len) and (P(1) in [$90..$BF]) and (P(2) in [$80..$BF]) and (P(3) in [$80..$BF]) then IncPos(4) else break; $F1..$F3: // planes 4-15 if (i+3 < Len) and (P(1) in [$80..$BF]) and (P(2) in [$80..$BF]) and (P(3) in [$80..$BF]) then IncPos(4) else break; $F4: // plane 16 if (i+3 < Len) and (P(1) in [$80..$8F]) and (P(2) in [$80..$BF]) and (P(3) in [$80..$BF]) then IncPos(4) else break; else break; end; end; if i = Len then Result := etUTF8 //UTF8 else Result := etANSI; //Ansi end; {$ENDIF} {** EgonHugeist: Now use the new Functions to get encoded Strings instead of hard-coded Compiler-Directives or UTF8Encode/Decode: function ZDbcString(const Ansi: AnsiString; const Encoding: TZCharEncoding = ceDefault): String; function ZPlainString(const Str: String; const Encoding: TZCharEncoding = ceDefault): AnsiString; These functions do auto arrange the in/out-coming AnsiStrings in dependency of the used CharacterSet and the used Compiler whithout String-DataLoss!!. So my thouths where use only these two function for all String/Ansi/Unicode-handlings of DBC-layer. Which means in full effect no more directives in Zeos Source-Code then here to do this handling. @param Ansi: the String which has to be handled. @param Encoding is set to Default-Character-Set we've choosen bevor (on conecting) Change this if you need some Transtations to a specified Encoding. Example: CharacterSet was set to Latin1 and some "special"-String MUST BE UTF8 instead of Latin1. (SSL-Keys eventualy) @param Convert ignored for Delphi means if the Chararacters should be propper to the specified codepage IS there a need for it? AnsiEncoded adaps automaticaly to WideString So what about coming UTF16/32???? } function TZCodePagedObject.ZDbcString(const Ansi: RawByteString; ConSettings: PZConSettings): String; {$IFDEF WITH_FPC_STRING_CONVERSATION} var TempAnsi: RawByteString; {$ENDIF} begin {$IFNDEF UNICODE} if not ConSettings^.AutoEncode then Result := Ansi else {$ENDIF} case ConSettings^.ClientCodePage^.Encoding of ceUTF8: {$IFDEF UNICODE} Result := UTF8ToString(Ansi); {$ELSE} if ( ConSettings^.CPType in [cCP_UTF8, cCP_UTF16] ) then Result := Ansi else {$IFDEF WITH_LCONVENCODING} Result := ConSettings.DbcConvertFunc(Ansi); {$ELSE} {$IFDEF WITH_FPC_STRING_CONVERSATION} begin //avoid string conversion -> move memory TempAnsi := AnsiToStringEx(Ansi, ConSettings^.ClientCodePage^.CP, ConSettings^.CTRL_CP); SetLength(Result, Length(TempAnsi)); Move(PAnsiChar(TempAnsi)^, PAnsiChar(Result)^, Length(TempAnsi)); end; {$ELSE} Result := AnsiToStringEx(Ansi, ConSettings^.ClientCodePage^.CP, ConSettings^.CTRL_CP); {$ENDIF} {$ENDIF} {$ENDIF} else {$IFDEF UNICODE} Result := AnsiToStringEx(Ansi, ConSettings^.ClientCodePage^.CP); {$ELSE} if ConSettings.AutoEncode then if ConSettings^.ClientCodePage^.CP = zCP_NONE then //that's not nice it slows down the incoming strings! Find a way to determine allways the current server CP case DetectUTF8Encoding(Ansi) of etUSASCII: Result := Ansi; etAnsi: if ConSettings^.CTRL_CP = zCP_UTF8 then {$IFDEF WITH_FPC_STRING_CONVERSATION} begin //avoid string conversion -> move memory TempAnsi := AnsiToUTF8(Ansi); //hope we've compatible results ))): SetLength(Result, Length(TempAnsi)); Move(PAnsiChar(TempAnsi)^, PAnsiChar(Result)^, Length(TempAnsi)); end {$ELSE} Result := AnsiToUTF8(Ansi) //hope we've compatible results ))): {$ENDIF} else Result := Ansi; else if ConSettings^.CTRL_CP = zCP_UTF8 then Result := Ansi else {$IFDEF WITH_FPC_STRING_CONVERSATION} begin //avoid string conversion -> move memory TempAnsi := AnsiToStringEx(Ansi, zCP_UTF8, ConSettings.CTRL_CP); SetLength(Result, Length(TempAnsi)); Move(PAnsiChar(TempAnsi)^, PAnsiChar(Result)^, Length(TempAnsi)); end; {$ELSE} {$IFDEF WITH_LCONVENCODING} Result := Ansi; {$ELSE} Result := AnsiToStringEx(Ansi, zCP_UTF8, ConSettings.CTRL_CP); {$ENDIF} {$ENDIF} end else {$IFDEF WITH_LCONVENCODING} Result := ConSettings.DbcConvertFunc(Ansi) {$ELSE} {$IFDEF WITH_FPC_STRING_CONVERSATION} begin //avoid string conversion -> move memory TempAnsi := AnsiToStringEx(Ansi, ConSettings.ClientCodePage.CP, ConSettings.CTRL_CP); SetLength(Result, Length(TempAnsi)); Move(PAnsiChar(TempAnsi)^, PAnsiChar(Result)^, Length(TempAnsi)); end {$ELSE} Result := AnsiToStringEx(Ansi, ConSettings.ClientCodePage.CP, ConSettings.CTRL_CP) {$ENDIF} {$ENDIF} else Result := Ansi; {$ENDIF} end; end; function TZCodePagedObject.ZDbcString(const Ansi: RawByteString; FromCP: Word): String; var CurrentCP: Word; CurrentEncoding: TZCharEncoding; begin if FromCP = FConsettings.ClientCodePage.CP then Result := ZDbcString(Ansi, ConSettings) else begin CurrentCP := FConsettings.ClientCodePage.CP; CurrentEncoding := FConSettings.ClientCodePage.Encoding; if ( FromCP = zCP_UTF8 ) then FConSettings.ClientCodePage.Encoding := ceUTF8 else FConSettings.ClientCodePage.Encoding := ceAnsi; FConsettings.ClientCodePage.CP := FromCP; Result := ZDbcString(Ansi, FConSettings); FConsettings.ClientCodePage.CP := CurrentCP; FConSettings.ClientCodePage.Encoding := CurrentEncoding; end; end; function TZCodePagedObject.ZDbcString(const Ansi: RawByteString; const Encoding: TZCharEncoding = ceDefault): String; var TempEncoding, UseEncoding: TZCharEncoding; begin if Encoding = ceDefault then if not Assigned(FConSettings.ClientCodePage) then raise Exception.Create('CodePage-Informations not Assigned!') else UseEncoding := FConSettings.ClientCodePage^.Encoding else UseEncoding := Encoding; {$IFNDEF UNICODE} if not FConSettings.AutoEncode and ( FConSettings.ClientCodePage^.Encoding = UseEncoding ) then Result := Ansi else {$ENDIF} begin TempEncoding := FConSettings^.ClientCodePage^.Encoding; FConSettings.ClientCodePage^.Encoding := UseEncoding; Result := ZDbcString(Ansi, FConSettings); FConSettings^.ClientCodePage^.Encoding := TempEncoding; end; end; function TZCodePagedObject.ZDbcUnicodeString(const AStr: RawByteString): ZWideString; begin {$IFNDEF WITH_LCONVENCODING} Result := ZRawToUnicode(AStr, FConSettings.ClientCodePage.CP); {$ELSE} case Consettings.ClientCodePage.Encoding of ceAnsi: Result := UTF8Decode(ConSettings.DbcConvertFunc(AStr)); //!!!!SLOW, Job down twice (Ansi up to wide to UTF8 to Wide) else Result := UTF8ToString(AStr) end; {$ENDIF} end; function TZCodePagedObject.ZDbcString(const AStr: ZWideString; const Encoding: TZCharEncoding = ceDefault): String; {$IFDEF WITH_FPC_STRING_CONVERSATION} var TempAnsi: RawByteString; {$ENDIF} begin {$IFDEF UNICODE} Result := AStr; {$ELSE} if not ConSettings.AutoEncode then Result := String(AStr) else {$IFDEF WITH_LCONVENCODING} Result := UTF8Encode(AStr); {$ELSE} {$IFDEF WITH_FPC_STRING_CONVERSATION} begin //avoid string conversion -> move memory TempAnsi := ZUnicodeToRaw(AStr, FConSettings.CTRL_CP); SetLength(Result, Length(TempAnsi)); Move(PAnsiChar(TempAnsi)^, PAnsiChar(Result)^, Length(TempAnsi)); end {$ELSE} Result := ZUnicodeToRaw(AStr, FConSettings.CTRL_CP); {$ENDIF} {$ENDIF} {$ENDIF} end; function TZCodePagedObject.ZDbcUnicodeString(const AStr: RawByteString; const FromCP: Word): ZWideString; begin {$IFNDEF WITH_LCONVENCODING} Result := ZRawToUnicode(AStr, FromCP); {$ELSE} if FromCP = zCP_UTF8 then Result := UTF8Decode(AStr) else if FromCP = ConSettings.ClientCodePage.CP then Result := UTF8Decode(ConSettings.DbcConvertFunc(AStr)) else Result := WideString(AStr); //default WideString cast, can't convert {$ENDIF} end; {$IFDEF WITH_RAWBYTESTRING} function TZCodePagedObject.ZDbcUnicodeString(const AStr: String; const FromCP: Word): ZWideString; begin {$IFDEF UNICODE} Result := AStr; {$ELSE} {$IFNDEF WITH_LCONVENCODING} Result := ZRawToUnicode(AStr, FromCP); {$ELSE} if FromCP = zCP_UTF8 then Result := UTF8Decode(AStr) else if FromCP = ConSettings.ClientCodePage.CP then Result := UTF8Decode(ConSettings.DbcConvertFunc(AStr)) else Result := WideString(AStr); //default WideString cast, can't convert {$ENDIF} {$ENDIF} end; {$ENDIF} {** EgonHugeist: Now use the new Functions to get encoded Strings instead of hard-Coded Compiler-Directives or UTF8Encode/Decode: function ZPlainString(const Str: String; const Encoding: TZCharEncoding = ceDefault): AnsiString; These functions do auto arrange the in/out-coming AnsiStrings in dependency of the used CharacterSet and the database uses whithout String-DataLoss!! (if possible -> UTF8 is save). @param AStr: the String which has to be handled. @param Encoding is set to Default-Character-Set we've choosen bevor (on conecting) Change this if you need some Transtations to a specified Encoding. Example: CharacterSet was set to Latin1 and some "special"-String MUST BE UTF8 instead of Latin1. (SSL-Keys eventualy) } function TZCodePagedObject.ZPlainString(const AStr: String; ConSettings: PZConSettings): RawByteString; {$IFDEF WITH_FPC_STRING_CONVERSATION} var TempAnsi: RawByteString; {$ENDIF} begin case ConSettings.ClientCodePage.Encoding of ceUTF8: {$IFDEF UNICODE} Result := UTF8Encode(AStr); {$ELSE} if ConSettings.AutoEncode then if DetectUTF8Encoding(AStr) in [etUTF8, etUSASCII] then Result := AStr else if ( ConSettings.CTRL_CP = zCP_UTF8 ) or (ConSettings.CTRL_CP = zCP_UTF8) then //avoid "no success" for expected Codepage UTF8 of the Controls {$IFDEF WITH_FPC_STRING_CONVERSATION} begin //avoid string conversion -> move memory TempAnsi := AnsiToUTF8(AStr); SetLength(Result, Length(TempAnsi)); Move(PAnsiChar(TempAnsi)^, PAnsiChar(Result)^, Length(TempAnsi)); end {$ELSE} Result := AnsiToUTF8(AStr) {$ENDIF} else {$IFDEF WITH_FPC_STRING_CONVERSATION} begin //avoid string conversion -> move memory TempAnsi := StringToAnsiEx(AStr, ConSettings.CTRL_CP, zCP_UTF8); SetLength(Result, Length(TempAnsi)); Move(PAnsiChar(TempAnsi)^, PAnsiChar(Result)^, Length(TempAnsi)); end {$ELSE} {$IFDEF WITH_LCONVENCODING} Result := AnsiToUTF8(AStr) {$ELSE} Result := StringToAnsiEx(AStr, ConSettings.CTRL_CP, zCP_UTF8) {$ENDIF} {$ENDIF} else Result := AStr; {$ENDIF} else begin {$IFDEF UNICODE} Result := StringToAnsiEx(AStr, ConSettings.ClientCodePage.CP); {$ELSE} if ConSettings.AutoEncode then case DetectUTF8Encoding(AStr) of etUSASCII: Result := AStr; etAnsi: {$IFDEF WITH_LCONVENCODING} if ConSettings.CTRL_CP = ConSettings.ClientCodePage.CP then Result := AStr else Result := ConSettings.PlainConvertFunc(AnsiToUTF8(AStr)); {$ELSE} Result := Astr; {$ENDIF} else {$IFDEF WITH_LCONVENCODING} Result := ConSettings.PlainConvertFunc(AStr); {$ELSE} {$IFDEF WITH_FPC_STRING_CONVERSATION} begin if ConSettings.ClientCodePage.CP = zCP_NONE then TempAnsi := UTF8ToAnsi(AStr) //hope it's compatible we don't know the server CP here!! else TempAnsi := StringToAnsiEx(AStr, zCP_UTF8, ConSettings.ClientCodePage.CP); //avoid string conversion -> move memory SetLength(Result, Length(TempAnsi)); Move(PAnsiChar(TempAnsi)^, PAnsiChar(Result)^, Length(TempAnsi)); end; {$ELSE} if ConSettings.ClientCodePage.CP = zCP_NONE then Result := UTF8ToAnsi(AStr) //hope it's compatible we don't know the server CP here!! else Result := StringToAnsiEx(AStr, zCP_UTF8, ConSettings.ClientCodePage.CP); {$ENDIF} {$ENDIF} end else Result := AStr; {$ENDIF} end; end; end; function TZCodePagedObject.ZPlainString(const AStr: String; ConSettings: PZConSettings; const ToCP: Word): RawByteString; var CurrentCP: Word; CurrentEncoding: TZCharEncoding; begin if ToCP = ConSettings.ClientCodePage.CP then Result := ZPlainString(AStr, ConSettings) else begin CurrentCP := ConSettings.ClientCodePage.CP; CurrentEncoding := ConSettings.ClientCodePage.Encoding; ConSettings.ClientCodePage.CP := ToCP; if ( ToCP = zCP_UTF8 ) then ConSettings.ClientCodePage.Encoding := ceUTF8 else ConSettings.ClientCodePage.Encoding := ceAnsi; Result := ZPlainString(AStr, ConSettings); ConSettings.ClientCodePage.CP := CurrentCP; ConSettings.ClientCodePage.Encoding := CurrentEncoding; end; end; function TZCodePagedObject.ZPlainString(const AStr: String; const Encoding: TZCharEncoding = ceDefault): RawByteString; var TempEncoding, UseEncoding: TZCharEncoding; begin if Encoding = ceDefault then if not Assigned(FConSettings.ClientCodePage) then raise Exception.Create('CodePage-Informations not Assigned!') else UseEncoding := FConSettings.ClientCodePage^.Encoding else UseEncoding := Encoding; {$IFNDEF UNICODE} if not FConSettings.AutoEncode and ( FConSettings.ClientCodePage^.Encoding = UseEncoding ) then Result := AStr else {$ENDIF} begin TempEncoding := FConSettings.ClientCodePage.Encoding; FConSettings.ClientCodePage.Encoding := UseEncoding; Result := ZPlainString(AStr, FConSettings); FConSettings.ClientCodePage.Encoding := TempEncoding; end; end; function TZCodePagedObject.ZPlainString(const AStr: WideString; const Encoding: TZCharEncoding = ceDefault): RawByteString; var TempEncoding, UseEncoding: TZCharEncoding; begin if Encoding = ceDefault then if not Assigned(FConSettings.ClientCodePage) then raise Exception.Create('CodePage-Informations not Assigned!') else UseEncoding := FConSettings.ClientCodePage^.Encoding else UseEncoding := Encoding; TempEncoding := FConSettings.ClientCodePage.Encoding; FConSettings.ClientCodePage.Encoding := UseEncoding; Result := ZPlainString(AStr, FConSettings); FConSettings.ClientCodePage.Encoding := TempEncoding; end; function TZCodePagedObject.ZPlainString(const AStr: WideString; ConSettings: PZConSettings): RawByteString; begin {$IFDEF WITH_LCONVENCODING} Result := ConSettings.PlainConvertFunc(UTF8Encode(AStr)); {$ELSE} Result := ZUnicodeToRaw(AStr, ConSettings^.ClientCodePage^.CP); {$ENDIF} end; function TZCodePagedObject.ZPlainString(const AStr: WideString; ConSettings: PZConSettings; const ToCP: Word): RawByteString; var CurrentCP: Word; CurrentEncoding: TZCharEncoding; begin if ToCP = ConSettings.ClientCodePage.CP then Result := ZPlainString(AStr, ConSettings) else begin CurrentCP := ConSettings.ClientCodePage.CP; CurrentEncoding := ConSettings.ClientCodePage.Encoding; ConSettings.ClientCodePage.CP := ToCP; if ( ToCP = zCP_UTF8 ) then ConSettings.ClientCodePage.Encoding := ceUTF8 else ConSettings.ClientCodePage.Encoding := ceAnsi; Result := ZPlainString(AStr, ConSettings); ConSettings.ClientCodePage.CP := CurrentCP; ConSettings.ClientCodePage.Encoding := CurrentEncoding; end; end; function TZCodePagedObject.ZPlainUnicodeString(const AStr: String): WideString; begin {$IFDEF UNICODE} Result := AStr; {$ELSE} if FConSettings.AutoEncode then case DetectUTF8Encoding(AStr) of etUTF8, etUSASCII: Result := UTF8Decode(AStr); else Result := WideString(AStr); end else {$IFDEF WITH_LCONVENCODING} Result := UTF8ToString(AStr); {$ELSE} Result := ZRawToUnicode(AStr, FConSettings.CTRL_CP); {$ENDIF} {$ENDIF} end; procedure TZCodePagedObject.SetConSettingsFromInfo(Info: TStrings); begin if Assigned(Info) and Assigned(FConSettings) then begin {$IFDEF UNICODE} ConSettings.CTRL_CP := ZDefaultSystemCodePage; if Info.values['controls_cp'] = 'GET_ACP' then ConSettings.CPType := cGET_ACP else ConSettings.CPType := cCP_UTF16; ConSettings.AutoEncode := True; {$ELSE} {$IF defined(MSWINDOWS) or defined(FPC_HAS_BUILTIN_WIDESTR_MANAGER) or defined(WITH_LCONVENCODING)} ConSettings.AutoEncode := Info.Values['AutoEncodeStrings'] = 'ON'; //compatibitity Option for existing Applications; {$ELSE} ConSettings.AutoEncode := False; {$IFEND} if Info.values['controls_cp'] = 'GET_ACP' then begin ConSettings.CPType := cGET_ACP; ConSettings.CTRL_CP := ZDefaultSystemCodePage; end else if Info.values['controls_cp'] = 'CP_UTF8' then begin ConSettings.CPType := cCP_UTF8; ConSettings.CTRL_CP := zCP_UTF8; end else if Info.values['controls_cp'] = 'CP_UTF16' then begin {$IF defined(MSWINDOWS) or defined(FPC_HAS_BUILTIN_WIDESTR_MANAGER) or defined(WITH_LCONVENCODING)} ConSettings.CPType := {$IFDEF WITH_WIDEFIELDS}cCP_UTF16{$ELSE}cCP_UTF8{$ENDIF}; ConSettings.CTRL_CP := ZDefaultSystemCodePage; ConSettings.AutoEncode := True; {$ELSE} if ConSettings.ClientCodePage.Encoding = ceUTF8 then begin ConSettings.CPType := {$IFDEF WITH_WIDEFIELDS}cCP_UTF16{$ELSE}cCP_UTF8{$ENDIF}; ConSettings.CTRL_CP := zCP_UTF8; ConSettings.AutoEncode := True; end else begin ConSettings.CPType := cCP_UTF8; ConSettings.CTRL_CP := zCP_UTF8; ConSettings.AutoEncode := False; end; {$IFEND} end else // nothing was found set defaults begin {$IFDEF FPC} ConSettings.CPType := cCP_UTF8; ConSettings.CTRL_CP := zCP_UTF8; {$ELSE} ConSettings.CPType := cGET_ACP; ConSettings.CTRL_CP := GetACP; {$ENDIF} end; {$ENDIF} end; end; destructor TZCodePagedObject.Destroy; begin inherited Destroy; end; {$IFDEF WITH_LCONVENCODING} function NoConvert(const s: string): string; begin Result := S; end; {$ENDIF} {$IFDEF UNIX} {$IFDEF FPC} function LoadLibrary(ModuleName: PChar): HMODULE; begin Result := dynlibs.LoadLibrary(ModuleName); end; function FreeLibrary(Module: HMODULE): LongBool; begin Result := dynlibs.FreeLibrary(Module); end; function GetProcAddress(Module: HMODULE; Proc: PChar): Pointer; begin Result := dynlibs.GetProcAddress(Module,Proc) end; {$ENDIF} {$ENDIF} {$IFNDEF FPC} function Hash(S : AnsiString) : LongWord; Var thehash,g,I : LongWord; begin thehash:=0; For I:=1 to Length(S) do { 0 terminated } begin thehash:=thehash shl 4; {$IFOPT Q+} {$DEFINE OverFlowCheckEnabled} {$OVERFLOWCHECKS OFF} {$ENDIF} inc(theHash,Ord(S[i])); {$IFDEF OverFlowCheckEnabled} {$OVERFLOWCHECKS ON} {$ENDIF} g:=thehash and LongWord($f shl 28); if g<>0 then begin thehash:=thehash xor (g shr 24); thehash:=thehash xor g; end; end; If theHash=0 then Hash:=$ffffffff else Hash:=TheHash; end; function AnsiProperCase(const S: string; const WordDelims: TSysCharSet): string; var P,PE : PChar; begin Result:=AnsiLowerCase(S); P:=PChar(pointer(Result)); PE:=P+Length(Result); while (P 0 ) then begin SetLength(Bytes, Size +2); System.move(Buffer^, Pointer(Bytes)^, Size); if FromDB then //do not check encoding twice Result := GetValidatedUnicodeStream(PAnsiChar(Bytes), ConSettings, FromDB) else case TestEncoding(Bytes, Size, ConSettings) of ceDefault: case Consettings.ClientCodePage.Encoding of ceUTF8: US := UTF8ToString(PAnsiChar(Bytes)); ceAnsi: {$IFDEF WITH_LCONVENCODING} US := ZWideString(PAnsiChar(Bytes)); //cast means random success {$ELSE} if ( ConSettings.CTRL_CP = zCP_UTF8) then US := ZWideString(PAnsiChar(Bytes)) //random success else US := ZRawToUnicode(PAnsiChar(Bytes), ConSettings.CTRL_CP); {$ENDIF} end; ceAnsi: //We've to start from the premisse we've got a Unicode string i there begin SetLength(US, Size div 2); System.Move(PWideChar(Bytes)^, PWideChar(US)^, Size); end; ceUTF8: US := UTF8ToString(PAnsiChar(Bytes)); ceUTF16: begin SetLength(US, Size div 2); System.Move(PWideChar(Bytes)^, PWideChar(US)^, Size); end; end; Len := Length(US)*2; if not Assigned(Result) and (Len > 0) then begin Result := TMemoryStream.Create; Result.Size := Len; System.Move(PWideChar(US)^, TMemoryStream(Result).Memory^, Len); Result.Position := 0; end; SetLength(Bytes, 0); end; end; function GetValidatedUnicodeStream(const Ansi: RawByteString; ConSettings: PZConSettings; FromDB: Boolean): TStream; var Len: Integer; US: ZWideString; begin Result := nil; if Ansi <> '' then begin if FromDB then {$IFDEF WITH_LCONVENCODING} US := UTF8ToString(Consettings.DbcConvertFunc(Ansi)) {$ELSE} US := ZRawToUnicode(Ansi, ConSettings.ClientCodePage.CP) {$ENDIF} else case DetectUTF8Encoding(Ansi) of etUSASCII, etUTF8: US := UTF8ToString(Ansi); etAnsi: {$IFDEF WITH_LCONVENCODING} US := ZWideString(Ansi); //random success {$ELSE} if ( ConSettings.CTRL_CP = zCP_UTF8) then US := ZWideString(Ansi) //random success else US := ZRawToUnicode(Ansi, ConSettings.CTRL_CP); {$ENDIF} end; Len := Length(US)*2; if Len > 0 then begin Result := TMemoryStream.Create; Result.Size := Len; System.Move(PWideChar(US)^, TMemoryStream(Result).Memory^, Len); Result.Position := 0; end; end; end; procedure SetConvertFunctions(ConSettings: PZConSettings); begin ConSettings^.ConvFuncs.ZAnsiToUTF8 := nil; ConSettings^.ConvFuncs.ZUTF8ToAnsi:= nil; ConSettings^.ConvFuncs.ZUTF8ToString:= nil; ConSettings^.ConvFuncs.ZStringToUTF8:= nil; ConSettings^.ConvFuncs.ZAnsiToRaw:= nil; ConSettings^.ConvFuncs.ZRawToAnsi:= nil; ConSettings^.ConvFuncs.ZRawToUTF8:= nil; ConSettings^.ConvFuncs.ZUTF8ToRaw:= nil; ConSettings^.ConvFuncs.ZStringToRaw:= nil; ConSettings^.ConvFuncs.ZAnsiToString := nil; ConSettings^.ConvFuncs.ZStringToAnsi := nil; ConSettings^.ConvFuncs.ZRawToString:= nil; ConSettings^.ConvFuncs.ZUnicodeToRaw:= nil; ConSettings^.ConvFuncs.ZRawToUnicode:= nil; ConSettings^.ConvFuncs.ZUnicodeToString:= nil; ConSettings^.ConvFuncs.ZStringToUnicode:= nil; //Let's start with the AnsiTo/From types.. // Ansi to/from UTF8String if ZCompatibleCodePages(ZDefaultSystemCodePage, zCP_UTF8) then begin ConSettings^.ConvFuncs.ZAnsiToUTF8 := @ZMoveAnsiToUTF8; ConSettings^.ConvFuncs.ZUTF8ToAnsi := @ZMoveUTF8ToAnsi; end else begin ConSettings^.ConvFuncs.ZAnsiToUTF8 := @ZConvertAnsiToUTF8; ConSettings^.ConvFuncs.ZUTF8ToAnsi := @ZConvertUTF8ToAnsi; end; // Ansi to/from String if ZCompatibleCodePages(ZDefaultSystemCodePage, ConSettings^.CTRL_CP) then begin ConSettings^.ConvFuncs.ZAnsiToString := @ZMoveAnsiToString; if ConSettings^.AutoEncode then ConSettings^.ConvFuncs.ZStringToAnsi := @ZConvertStringToAnsiWithAutoEncode else ConSettings^.ConvFuncs.ZStringToAnsi := @ZMoveStringToAnsi; end else begin ConSettings^.ConvFuncs.ZAnsiToString := @ZConvertAnsiToString; if ConSettings^.AutoEncode then ConSettings^.ConvFuncs.ZStringToAnsi := @ZConvertStringToAnsiWithAutoEncode else ConSettings^.ConvFuncs.ZStringToAnsi := @ZConvertStringToAnsi; end; if ConSettings^.ClientCodePage^.IsStringFieldCPConsistent then begin // raw to/from UTF8 if ZCompatibleCodePages(ConSettings^.ClientCodePage^.CP, zCP_UTF8) then begin ConSettings^.ConvFuncs.ZRawToUTF8 := @ZMoveRawToUTF8; ConSettings^.ConvFuncs.ZUTF8ToRaw := @ZMoveUTF8ToRaw; end else begin ConSettings^.ConvFuncs.ZRawToUTF8 := @ZConvertRawToUTF8; ConSettings^.ConvFuncs.ZUTF8ToRaw := @ZConvertUTF8ToRaw; end; // raw to/from ansi if ZCompatibleCodePages(ConSettings^.ClientCodePage^.CP, ZDefaultSystemCodePage) then begin ConSettings^.ConvFuncs.ZAnsiToRaw := @ZMoveAnsiToRaw; ConSettings^.ConvFuncs.ZRawToAnsi := @ZMoveRawToAnsi; end else begin ConSettings^.ConvFuncs.ZAnsiToRaw := @ZConvertAnsiToRaw; ConSettings^.ConvFuncs.ZRawToAnsi := @ZConvertRawToAnsi; end; // raw to/from unicode if ConSettings^.ClientCodePage^.CP = zCP_NONE then begin if ConSettings^.AutoEncode then ConSettings^.ConvFuncs.ZRawToUnicode := @ZUnknownRawToUnicodeWithAutoEncode else ConSettings^.ConvFuncs.ZRawToUnicode := @ZUnknownRawToUnicode; ConSettings^.ConvFuncs.ZUnicodeToRaw := @ZUnicodeToUnknownRaw; end else begin ConSettings^.ConvFuncs.ZRawToUnicode := @ZRawToUnicode; ConSettings^.ConvFuncs.ZUnicodeToRaw := @ZUnicodeToRaw; end; //last but not least the String to/from converters //string represents the DataSet/IZResultSet Strings if ZCompatibleCodePages(ConSettings^.CTRL_CP, zCP_UTF8) then begin ConSettings^.ConvFuncs.ZUTF8ToString := @ZMoveUTF8ToString; if ConSettings^.AutoEncode then ConSettings^.ConvFuncs.ZStringToUTF8 := @ZConvertStringToUTF8WithAutoEncode else ConSettings^.ConvFuncs.ZStringToUTF8 := @ZMoveStringToUTF8; end else begin ConSettings^.ConvFuncs.ZUTF8ToString := @ZConvertUTF8ToString; if ConSettings^.AutoEncode then ConSettings^.ConvFuncs.ZStringToUTF8 := @ZConvertStringToUTF8WithAutoEncode else ConSettings^.ConvFuncs.ZStringToUTF8 := @ZConvertStringToUTF8 end; {$IFDEF UNICODE} Consettings^.ConvFuncs.ZStringToRaw := @ZConvertStringToRaw; Consettings^.ConvFuncs.ZRawToString := @ZConvertRawToString; ConSettings^.ConvFuncs.ZUnicodeToString := @ZConvertUnicodeToString; Consettings^.ConvFuncs.ZStringToUnicode := @ZConvertStringToUnicode; {$ELSE} {String To/From Raw} if ZCompatibleCodePages(ConSettings^.ClientCodePage^.CP, ConSettings^.CTRL_CP) then begin Consettings^.ConvFuncs.ZRawToString := @ZMoveRawToString; if ConSettings^.AutoEncode then Consettings^.ConvFuncs.ZStringToRaw := @ZConvertStringToRawWithAutoEncode else Consettings^.ConvFuncs.ZStringToRaw := @ZMoveStringToRaw; end else if ConSettings^.AutoEncode then begin Consettings^.ConvFuncs.ZRawToString := @ZConvertRawToString; Consettings^.ConvFuncs.ZStringToRaw := @ZConvertStringToRawWithAutoEncode; end else begin Consettings^.ConvFuncs.ZStringToRaw := @ZMoveStringToRaw; Consettings^.ConvFuncs.ZRawToString := @ZMoveRawToString; end; {String To/From Unicode} if ConSettings^.CTRL_CP = zCP_UTF8 then Consettings^.ConvFuncs.ZUnicodeToString := @ZConvertUnicodeToString_CPUTF8 else Consettings^.ConvFuncs.ZUnicodeToString := @ZConvertUnicodeToString; if ConSettings^.AutoEncode then Consettings^.ConvFuncs.ZStringToUnicode := @ZConvertStringToUnicodeWithAutoEncode else if ConSettings^.CTRL_CP = zCP_UTF8 then Consettings^.ConvFuncs.ZStringToUnicode := @ZConvertString_CPUTF8ToUnicode else Consettings^.ConvFuncs.ZStringToUnicode := @ZConvertStringToUnicode; {$ENDIF} end else //autoencode strings is allways true begin ConSettings^.ConvFuncs.ZUTF8ToString := @ZConvertUTF8ToString; ConSettings^.ConvFuncs.ZStringToUTF8 := @ZConvertStringToUTF8WithAutoEncode; ConSettings^.ConvFuncs.ZAnsiToRaw := @ZConvertAnsiToRaw; ConSettings^.ConvFuncs.ZRawToAnsi := @ZConvertRawToAnsi; ConSettings^.ConvFuncs.ZRawToUTF8 := @ZConvertRawToUTF8; ConSettings^.ConvFuncs.ZUTF8ToRaw := @ZConvertUTF8ToRaw; Consettings^.ConvFuncs.ZStringToRaw := @ZConvertStringToRawWithAutoEncode; Consettings^.ConvFuncs.ZRawToString := @ZConvertRawToString; Consettings^.ConvFuncs.ZUnicodeToRaw := @ZUnicodeToRaw; Consettings^.ConvFuncs.ZRawToUnicode := @ZRawToUnicode; ConSettings^.ConvFuncs.ZUnicodeToString := @ZConvertUnicodeToString; Consettings^.ConvFuncs.ZStringToUnicode := @ZConvertStringToUnicodeWithAutoEncode; end; end; end. ================================================ FILE: lib/zeosdbo/src/core/ZExprParser.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Expression Parser classes and interfaces } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZExprParser; interface {$I ZCore.inc} uses SysUtils, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} Contnrs, ZCompatibility, ZVariant, ZTokenizer; type {** Define types of expression tokens. } TZExpressionTokenType = ( ttUnknown, ttLeftBrace, ttRightBrace, ttLeftSquareBrace, ttRightSquareBrace, ttPlus, ttMinus, ttStar, ttSlash, ttProcent, ttPower, ttEqual, ttNotEqual, ttMore, ttLess, ttEqualMore, ttEqualLess, ttAnd, ttOr, ttXor, ttIs, ttNull, ttNot, ttLike, ttNotLike, ttIsNull, ttIsNotNull, ttComma, ttUnary, ttFunction, ttVariable, ttConstant ); {** Defines a parser exception. } TZParseError = class (Exception); {** Defines an expression token holder. } TZExpressionToken = class (TObject) private FTokenType: TZExpressionTokenType; FValue: TZVariant; public constructor Create(TokenType: TZExpressionTokenType; const Value: TZVariant); property TokenType: TZExpressionTokenType read FTokenType write FTokenType; property Value: TZVariant read FValue write FValue; end; {** Implements an expression parser class. } TZExpressionParser = class (TObject) private FTokenizer: IZTokenizer; FExpression: string; FInitialTokens: TObjectList; FTokenIndex: Integer; FResultTokens: TObjectList; FVariables: TStrings; function HasMoreTokens: Boolean; function GetToken: TZExpressionToken; function GetNextToken: TZExpressionToken; procedure ShiftToken; function CheckTokenTypes( TokenTypes: array of TZExpressionTokenType): Boolean; procedure TokenizeExpression; procedure SyntaxAnalyse; procedure SyntaxAnalyse1; procedure SyntaxAnalyse2; procedure SyntaxAnalyse3; procedure SyntaxAnalyse4; procedure SyntaxAnalyse5; procedure SyntaxAnalyse6; public constructor Create(Tokenizer: IZTokenizer); destructor Destroy; override; procedure Parse(Expression: string); procedure Clear; property Tokenizer: IZTokenizer read FTokenizer write FTokenizer; property Expression: string read FExpression write Parse; property ResultTokens: TObjectList read FResultTokens; property Variables: TStrings read FVariables; end; implementation uses ZSysUtils, ZMessages; { TZExpressionToken } {** Creates an expression token object. @param TokenType a type of the token. @param Value a token value. } constructor TZExpressionToken.Create(TokenType: TZExpressionTokenType; const Value: TZVariant); begin FTokenType := TokenType; FValue := Value; end; const {** Defines a list of operators. } OperatorTokens: array[0..24] of string = ( '(', ')', '[', ']', '+', '-', '*', '/', '%', '^', '=', '<>', '!=', '>', '<', '>=', '<=', 'AND', 'OR', 'XOR', 'NOT', 'IS', 'NULL', 'LIKE', ',' ); {** Defines a list of operator codes. } OperatorCodes: array[0..24] of TZExpressionTokenType = ( ttLeftBrace, ttRightBrace, ttLeftSquareBrace, ttRightSquareBrace, ttPlus, ttMinus, ttStar, ttSlash, ttProcent, ttPower, ttEqual, ttNotEqual, ttNotEqual, ttMore, ttLess, ttEqualMore, ttEqualLess, ttAnd, ttOr, ttXor, ttNot, ttIs, ttNull, ttLike, ttComma ); { TZExpressionParser } {** Creates this expression parser object. @param Tokenizer an expression tokenizer. } constructor TZExpressionParser.Create(Tokenizer: IZTokenizer); begin FTokenizer := Tokenizer; FExpression := ''; FInitialTokens := TObjectList.Create; FTokenIndex := 0; FResultTokens := TObjectList.Create; FVariables := TStringList.Create; end; {** Destroyes this object and cleanups the memory. } destructor TZExpressionParser.Destroy; begin FreeAndNil(FInitialTokens); FreeAndNil(FResultTokens); FreeAndNil(FVariables); FTokenizer := Nil; inherited Destroy; end; {** Clears parsing result. } procedure TZExpressionParser.Clear; begin FExpression := ''; FInitialTokens.Clear; FResultTokens.Clear; FTokenIndex := 0; FVariables.Clear; end; {** Sets a new expression string and parses it into internal byte code. @param expression a new expression string. } procedure TZExpressionParser.Parse(Expression: string); begin Clear; FExpression := Trim(Expression); if FExpression <> '' then begin TokenizeExpression; SyntaxAnalyse; if HasMoreTokens then begin raise TZParseError.Create( Format(SSyntaxErrorNear, [SoftVarManager.GetAsString(GetToken.Value)])); end; end; end; {** Checks are there more tokens for processing. @return TRUE if some tokens are present. } function TZExpressionParser.HasMoreTokens: Boolean; begin Result := FTokenIndex < FInitialTokens.Count; end; {** Gets the current token object. @param tokens a collection of tokens. @returns the current token object. } function TZExpressionParser.GetToken: TZExpressionToken; begin if FTokenIndex < FInitialTokens.Count then Result := TZExpressionToken(FInitialTokens[FTokenIndex]) else Result := nil; end; {** Gets the next token object. @param tokens a collection of tokens. @returns the next token object. } function TZExpressionParser.GetNextToken: TZExpressionToken; begin if (FTokenIndex + 1) < FInitialTokens.Count then Result := TZExpressionToken(FInitialTokens[FTokenIndex + 1]) else Result := nil; end; {** Shifts the current token object. } procedure TZExpressionParser.ShiftToken; begin Inc(FTokenIndex); end; {** Checks available token types with token types from the list. If they match it shifts the tokens. @param TokenTypes a list of token types to compare. @return True if token types match. } function TZExpressionParser.CheckTokenTypes( TokenTypes: array of TZExpressionTokenType): Boolean; var I: Integer; Temp: TZExpressionToken; begin Result := False; for I := Low(TokenTypes) to High(TokenTypes) do begin if (FTokenIndex + I) < FInitialTokens.Count then begin Temp := TZExpressionToken(FInitialTokens[FTokenIndex + I]); Result := Temp.TokenType = TokenTypes[I]; end else Result := False; if not Result then Break; end; if Result then Inc(FTokenIndex, Length(TokenTypes)); end; {** Tokenizes the given expression and prepares an initial tokens list. } procedure TZExpressionParser.TokenizeExpression; var I: Integer; TokenIndex: Integer; Temp: string; Tokens: TStrings; TokenType: TZExpressionTokenType; TokenValue: TZVariant; begin Tokens := FTokenizer.TokenizeBufferToList(FExpression, [toSkipWhitespaces, toSkipComments, toSkipEOF, toDecodeStrings]); try TokenIndex := 0; while TokenIndex < Tokens.Count do begin TokenType := ttUnknown; TokenValue := NullVariant; case TZTokenType({$IFDEF FPC}Pointer({$ENDIF} Tokens.Objects[TokenIndex]{$IFDEF FPC}){$ENDIF}) of ttKeyword: begin Temp := UpperCase(Tokens[TokenIndex]); if Temp = 'TRUE' then begin TokenType := ttConstant; TokenValue:= EncodeBoolean(True); end else if Temp = 'FALSE' then begin TokenType := ttConstant; TokenValue:= EncodeBoolean(False); end else begin for I := Low(OperatorTokens) to High(OperatorTokens) do begin if OperatorTokens[I] = Temp then begin TokenType := OperatorCodes[I]; Break; end; end; end; end; ttWord: begin TokenType := ttVariable; Temp := Tokens[TokenIndex]; if FVariables.IndexOf(Temp) < 0 then FVariables.Add(Temp); TokenValue:= EncodeString(Temp); end; ttInteger: begin TokenType := ttConstant; TokenValue:= EncodeInteger(StrToInt64(Tokens[TokenIndex])); end; ttFloat: begin TokenType := ttConstant; TokenValue:= EncodeFloat(SqlStrToFloat(AnsiString(Tokens[TokenIndex]))); end; ttQuoted: begin TokenType := ttConstant; TokenValue:= EncodeString(Tokens[TokenIndex]); end; ttSymbol: begin Temp := Tokens[TokenIndex]; for I := Low(OperatorTokens) to High(OperatorTokens) do begin if Temp = OperatorTokens[I] then begin TokenType := OperatorCodes[I]; Break; end; end; end; ttTime,ttDate,ttDateTime: begin TokenType := ttConstant; TokenValue:= EncodeDateTime(StrToDateTime(Tokens[TokenIndex])); end; end; if TokenType = ttUnknown then raise TZParseError.Create(Format(SUnknownSymbol, [Tokens[TokenIndex]])); Inc(TokenIndex); FInitialTokens.Add(TZExpressionToken.Create(TokenType, TokenValue)); end; finally Tokens.Free; end; end; {** Performs a syntax analyze at level 0. } procedure TZExpressionParser.SyntaxAnalyse; var Token: TZExpressionToken; begin if not HasMoreTokens then raise TZParseError.Create(SUnexpectedExprEnd); SyntaxAnalyse1; while HasMoreTokens do begin Token := GetToken; if not (Token.TokenType in [ttAnd, ttOr, ttXor]) then Break; ShiftToken; SyntaxAnalyse1; FResultTokens.Add(TZExpressionToken.Create(Token.TokenType, NullVariant)); end; end; {** Performs a syntax analyze at level 1. } procedure TZExpressionParser.SyntaxAnalyse1; var Token: TZExpressionToken; begin if not HasMoreTokens then raise TZParseError.Create(SUnexpectedExprEnd); Token := GetToken; if Token.TokenType = ttNot then begin ShiftToken; SyntaxAnalyse2; FResultTokens.Add(TZExpressionToken.Create(Token.TokenType, NullVariant)); end else SyntaxAnalyse2; end; {** Performs a syntax analyze at level 2. } procedure TZExpressionParser.SyntaxAnalyse2; var Token: TZExpressionToken; begin if not HasMoreTokens then raise TZParseError.Create(SUnexpectedExprEnd); SyntaxAnalyse3; while HasMoreTokens do begin Token := GetToken; if not (Token.TokenType in [ttEqual, ttNotEqual, ttMore, ttLess, ttEqualMore, ttEqualLess]) then Break; ShiftToken; SyntaxAnalyse3; FResultTokens.Add(TZExpressionToken.Create(Token.TokenType, NullVariant)); end; end; {** Performs a syntax analyze at level 3. } procedure TZExpressionParser.SyntaxAnalyse3; var Token: TZExpressionToken; begin if not HasMoreTokens then raise TZParseError.Create(SUnexpectedExprEnd); SyntaxAnalyse4; while HasMoreTokens do begin Token := GetToken; if Token.TokenType in [ttPlus, ttMinus, ttLike] then begin ShiftToken; SyntaxAnalyse4; FResultTokens.Add(TZExpressionToken.Create(Token.TokenType, NullVariant)); end else if CheckTokenTypes([ttNot, ttLike]) then begin SyntaxAnalyse4; FResultTokens.Add(TZExpressionToken.Create(ttNotLike, NullVariant)); end else if CheckTokenTypes([ttIs, ttNull]) then begin FResultTokens.Add(TZExpressionToken.Create(ttIsNull, NullVariant)); end else if CheckTokenTypes([ttIs, ttNot, ttNull]) then begin FResultTokens.Add(TZExpressionToken.Create(ttIsNotNull, NullVariant)); end else Break; end; end; {** Performs a syntax analyze at level 4. } procedure TZExpressionParser.SyntaxAnalyse4; var Token: TZExpressionToken; begin if not HasMoreTokens then raise TZParseError.Create(SUnexpectedExprEnd); SyntaxAnalyse5; while HasMoreTokens do begin Token := GetToken; if not (Token.TokenType in [ttStar, ttSlash, ttProcent]) then Break; ShiftToken; SyntaxAnalyse5; FResultTokens.Add(TZExpressionToken.Create(Token.TokenType, NullVariant)); end; end; {** Performs a syntax analyze at level 5. } procedure TZExpressionParser.SyntaxAnalyse5; var Token: TZExpressionToken; begin if not HasMoreTokens then raise TZParseError.Create(SUnexpectedExprEnd); SyntaxAnalyse6; while HasMoreTokens do begin Token := GetToken; if Token.TokenType <> ttPower then Break; ShiftToken; SyntaxAnalyse6; FResultTokens.Add(TZExpressionToken.Create(Token.TokenType, NullVariant)); end; end; {** Performs a syntax analyze at level 6. } procedure TZExpressionParser.SyntaxAnalyse6; var ParamsCount: Integer; Unary, Token: TZExpressionToken; Primitive, NextToken: TZExpressionToken; Temp: TZVariant; begin if not HasMoreTokens then raise TZParseError.Create(SUnexpectedExprEnd); Unary := GetToken; if Unary.TokenType = ttPlus then begin Unary := nil; ShiftToken; end else if Unary.TokenType = ttMinus then begin Unary.TokenType := ttUnary; ShiftToken; end else Unary := nil; if not HasMoreTokens then raise TZParseError.Create(SUnexpectedExprEnd); Primitive := GetToken; NextToken := GetNextToken; if (Primitive.TokenType = ttVariable) and (NextToken <> nil) and (NextToken.TokenType = ttLeftBrace) then Primitive.TokenType := ttFunction; if Primitive.TokenType in [ttConstant, ttVariable] then begin ShiftToken; FResultTokens.Add(TZExpressionToken.Create( Primitive.TokenType, Primitive.Value)); end else if Primitive.TokenType = ttLeftBrace then begin ShiftToken; SyntaxAnalyse; if not HasMoreTokens then raise TZParseError.Create(SUnexpectedExprEnd); Primitive := GetToken; if Primitive.TokenType <> ttRightBrace then raise TZParseError.Create(SRightBraceExpected); ShiftToken; end else if Primitive.TokenType = ttFunction then begin ShiftToken; Token := GetToken; if Token.TokenType <> ttLeftBrace then raise TZParseError.Create(SInternalError); ParamsCount := 0; repeat ShiftToken; Token := GetToken; if (Token = nil) or (Token.TokenType = ttRightBrace) then Break; Inc(ParamsCount); SyntaxAnalyse; Token := GetToken; until (Token = nil) or (Token.TokenType <> ttComma); if not HasMoreTokens then raise TZParseError.Create(SUnexpectedExprEnd); if Token.TokenType <> ttRightBrace then raise TZParseError.Create(SRightBraceExpected); ShiftToken; Temp:= EncodeInteger(ParamsCount); FResultTokens.Add(TZExpressionToken.Create(ttConstant, Temp)); FResultTokens.Add(TZExpressionToken.Create(Primitive.TokenType, Primitive.Value)); end else raise TZParseError.Create(SSyntaxError); if Unary <> nil then FResultTokens.Add(TZExpressionToken.Create(Unary.TokenType, NullVariant)); end; end. ================================================ FILE: lib/zeosdbo/src/core/ZExprToken.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { String tokenizing classes for Expressions } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZExprToken; interface {$I ZCore.inc} uses Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, ZSysUtils, ZTokenizer; type {** Implements an Expression-specific number state object. } TZExpressionNumberState = class (TZNumberState) public function NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; override; end; {** Implements an Expression-specific quote string state object. } TZExpressionQuoteState = class (TZQuoteState) public function NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; override; function EncodeString(const Value: string; QuoteChar: Char): string; override; function DecodeString(const Value: string; QuoteChar: Char): string; override; end; {** This state will either delegate to a comment-handling state, or return a token with just a slash in it. } TZExpressionCommentState = class (TZCppCommentState) public function NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; override; end; {** Implements a symbol state object. } TZExpressionSymbolState = class (TZSymbolState) public constructor Create; end; {** Implements a word state object. } TZExpressionWordState = class (TZWordState) public constructor Create; function NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; override; end; {** Implements a default tokenizer object. } TZExpressionTokenizer = class (TZTokenizer) public constructor Create; end; implementation uses ZCompatibility; const {** List of keywords. } Keywords: array [0..8] of string = ( 'AND','OR','NOT','XOR','LIKE','IS','NULL','TRUE','FALSE' ); { TZExpressionNumberState } //gto: all operations on Streams should be done without presuming the size // of the read var, like Stream.Read(LastChar, 1), to read 1 char // // Instead, operations should use SizeOf(Type), like this: // Stream.Read(LastChar, 1 * SizeOf(Char)) // // This is unicode safe and ansi (Delphi under 2009) compatible {** Return a number token from a reader. @return a number token from a reader } function TZExpressionNumberState.NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; var TempChar: Char; FloatPoint: Boolean; LastChar: Char; function ReadDecDigits: string; begin Result := ''; LastChar := #0; while Stream.Read(LastChar, 1 * SizeOf(Char)) > 0 do begin if CharInSet(LastChar, ['0'..'9']) then begin Result := Result + LastChar; LastChar := #0; end else begin Stream.Seek(-(1 * SizeOf(Char)), soFromCurrent); Break; end; end; end; begin FloatPoint := FirstChar = '.'; Result.Value := FirstChar; Result.TokenType := ttUnknown; LastChar := #0; { Reads the first part of the number before decimal point } if not FloatPoint then begin Result.Value := Result.Value + ReadDecDigits; FloatPoint := LastChar = '.'; if FloatPoint then begin Stream.Read(TempChar, 1 * SizeOf(Char)); Result.Value := Result.Value + TempChar; end; end; { Reads the second part of the number after decimal point } if FloatPoint then Result.Value := Result.Value + ReadDecDigits; { Reads a power part of the number } if CharInSet(LastChar, ['e', 'E']) then begin Stream.Read(TempChar, 1 * SizeOf(Char)); Result.Value := Result.Value + TempChar; FloatPoint := True; Stream.Read(TempChar, 1 * SizeOf(Char)); if CharInSet(TempChar, ['0'..'9', '-', '+']) then Result.Value := Result.Value + TempChar + ReadDecDigits else begin Result.Value := Copy(Result.Value, 1, Length(Result.Value) - 1); Stream.Seek(-(2 * SizeOf(Char)), soFromCurrent); end; end; { Prepare the result } if Result.Value = '.' then begin if Tokenizer.SymbolState <> nil then Result := Tokenizer.SymbolState.NextToken(Stream, FirstChar, Tokenizer); end else begin if FloatPoint then Result.TokenType := ttFloat else Result.TokenType := ttInteger; end; end; { TZExpressionSQLQuoteState } {** Return a quoted string token from a reader. This method will collect characters until it sees a match to the character that the tokenizer used to switch to this state. @return a quoted string token from a reader } function TZExpressionQuoteState.NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; var ReadChar: Char; LastChar: Char; begin if FirstChar = '"' then Result.TokenType := ttWord else Result.TokenType := ttQuoted; Result.Value := FirstChar; LastChar := #0; while Stream.Read(ReadChar, 1 * SizeOf(Char)) > 0 do begin if (LastChar = FirstChar) and (ReadChar <> FirstChar) then begin Stream.Seek(-(1 * SizeOf(Char)), soFromCurrent); Break; end; Result.Value := Result.Value + ReadChar; if LastChar = '\' then LastChar := #0 else if (LastChar = FirstChar) and (ReadChar = FirstChar) then LastChar := #0 else LastChar := ReadChar; end; end; {** Encodes a string value. @param Value a string value to be encoded. @param QuoteChar a string quote character. @returns an encoded string. } function TZExpressionQuoteState.EncodeString(const Value: string; QuoteChar: Char): string; begin if CharInSet(QuoteChar, ['''', '"']) then Result := QuoteChar + EncodeCString(Value) + QuoteChar else Result := Value; end; {** Decodes a string value. @param Value a string value to be decoded. @param QuoteChar a string quote character. @returns an decoded string. } function TZExpressionQuoteState.DecodeString(const Value: string; QuoteChar: Char): string; begin if (Length(Value) >= 2) and CharInSet(QuoteChar, ['''', '"']) and (Value[1] = QuoteChar) and (Value[Length(Value)] = QuoteChar) then Result := DecodeCString(Copy(Value, 2, Length(Value) - 2)) else Result := Value; end; { TZExpressionCommentState } {** Gets an Expression specific comments like /* */. @return either just a slash token, or the results of delegating to a comment-handling state } function TZExpressionCommentState.NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; var ReadChar: Char; ReadNum: Integer; begin Result.TokenType := ttUnknown; Result.Value := FirstChar; if FirstChar = '/' then begin ReadNum := Stream.Read(ReadChar, 1 * SizeOf(Char)); if (ReadNum > 0) and (ReadChar = '*') then begin Result.TokenType := ttComment; Result.Value := '/*' + GetMultiLineComment(Stream); end else begin if ReadNum > 0 then Stream.Seek(-(1 * SizeOf(Char)), soFromCurrent); end; end; if (Result.TokenType = ttUnknown) and (Tokenizer.SymbolState <> nil) then Result := Tokenizer.SymbolState.NextToken(Stream, FirstChar, Tokenizer); end; { TZExpressionSymbolState } {** Creates this Expression-specific symbol state object. } constructor TZExpressionSymbolState.Create; begin inherited Create; Add('<='); Add('>='); Add('<>'); Add('!='); end; { TZExpressionWordState } {** Constructs this Expression-specific word state object. } constructor TZExpressionWordState.Create; begin SetWordChars(#0, #191, False); SetWordChars(#192, high(char), True); SetWordChars('a', 'z', True); SetWordChars('A', 'Z', True); SetWordChars('0', '9', True); SetWordChars('_', '_', True); end; {** Gets a word tokens or special operators. @return a processed token. } function TZExpressionWordState.NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; var I: Integer; Temp: string; begin Result := inherited NextToken(Stream, FirstChar, Tokenizer); Temp := UpperCase(Result.Value); for I := Low(Keywords) to High(Keywords) do begin if Temp = Keywords[I] then begin Result.TokenType := ttKeyword; Break; end; end; end; { TZExpressionTokenizer } {** Constructs a tokenizer with a default state table (as described in the class comment). } constructor TZExpressionTokenizer.Create; begin WhitespaceState := TZWhitespaceState.Create; SymbolState := TZExpressionSymbolState.Create; NumberState := TZExpressionNumberState.Create; QuoteState := TZExpressionQuoteState.Create; WordState := TZExpressionWordState.Create; CommentState := TZExpressionCommentState.Create; SetCharacterState(#0, #32, WhitespaceState); SetCharacterState(#33, #191, SymbolState); SetCharacterState(#192, High(Char), WordState); SetCharacterState('a', 'z', WordState); SetCharacterState('A', 'Z', WordState); SetCharacterState('_', '_', WordState); SetCharacterState('0', '9', NumberState); SetCharacterState('.', '.', NumberState); SetCharacterState('"', '"', QuoteState); SetCharacterState('''', '''', QuoteState); SetCharacterState('/', '/', CommentState); end; end. ================================================ FILE: lib/zeosdbo/src/core/ZExpression.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Expression classes and interfaces } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZExpression; interface {$I ZCore.inc} uses SysUtils, Classes, {$IFDEF WITH_TOBJECTLIST_INLINE}System.Contnrs, {$ENDIF} ZClasses, ZCompatibility, ZVariant, ZTokenizer, ZExprParser; type {** Defines an expression exception. } TZExpressionError = class (Exception); {** Defines an execution stack object. } TZExecutionStack = class (TObject) private FValues: TZVariantDynArray; FCount: Integer; FCapacity: Integer; function GetValue(Index: Integer): TZVariant; public constructor Create; procedure DecStackPointer(const Value : integer); function Pop: TZVariant; function Peek: TZVariant; procedure Push(Value: TZVariant); function GetParameter(Index: Integer): TZVariant; procedure Swap; procedure Clear; property Count: Integer read FCount; property Values[Index: Integer]: TZVariant read GetValue; end; {** Defines a list of variables. } IZVariablesList = interface (IZInterface) ['{F4347F46-32F3-4021-B6DB-7A39BF171275}'] function GetCount: Integer; function GetName(Index: Integer): string; function GetValue(Index: Integer): TZVariant; procedure SetValue(Index: Integer; const Value: TZVariant); function GetValueByName(const Name: string): TZVariant; procedure SetValueByName(const Name: string; const Value: TZVariant); procedure Add(const Name: string; const Value: TZVariant); procedure Remove(const Name: string); function FindByName(const Name: string): Integer; procedure ClearValues; procedure Clear; property Count: Integer read GetCount; property Names[Index: Integer]: string read GetName; property Values[Index: Integer]: TZVariant read GetValue write SetValue; property NamedValues[const Index: string]: TZVariant read GetValueByName write SetValueByName; end; {** Defines a function interface. } IZFunction = interface (IZInterface) ['{E9B3AFF9-6CD9-49C8-AB66-C8CF60ED8686}'] function GetName: string; function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; property Name: string read GetName; end; {** Defines a list of functions. } IZFunctionsList = interface (IZInterface) ['{54453054-F012-475B-84C3-7E5C46187FDB}'] function GetCount: Integer; function GetName(Index: Integer): string; function GetFunction(Index: Integer): IZFunction; procedure Add(Func: IZFunction); procedure Remove(const Name: string); function FindByName(const Name: string): Integer; procedure Clear; property Count: Integer read GetCount; property Names[Index: Integer]: string read GetName; property Functions[Index: Integer]: IZFunction read GetFunction; end; {** Defines an interface to expression calculator. } IZExpression = interface (IZInterface) ['{26F9D379-5618-446C-8999-D50FBB2F8560}'] function GetTokenizer: IZTokenizer; procedure SetTokenizer(Value: IZTokenizer); function GetExpression: string; procedure SetExpression(const Value: string); function GetVariantManager: IZVariantManager; procedure SetVariantManager(Value: IZVariantManager); function GetDefaultVariables: IZVariablesList; procedure SetDefaultVariables(Value: IZVariablesList); function GetDefaultFunctions: IZFunctionsList; procedure SetDefaultFunctions(Value: IZFunctionsList); function GetAutoVariables: Boolean; procedure SetAutoVariables(Value: Boolean); function Evaluate: TZVariant; function Evaluate2(Variables: IZVariablesList): TZVariant; function Evaluate3(Variables: IZVariablesList; Functions: IZFunctionsList): TZVariant; function Evaluate4(Variables: IZVariablesList; Functions: IZFunctionsList; Stack: TZExecutionStack): TZVariant; procedure CreateVariables(Variables: IZVariablesList); procedure Clear; property Tokenizer: IZTokenizer read GetTokenizer write SetTokenizer; property Expression: string read GetExpression write SetExpression; property VariantManager: IZVariantManager read GetVariantManager write SetVariantManager; property DefaultVariables: IZVariablesList read GetDefaultVariables write SetDefaultVariables; property DefaultFunctions: IZFunctionsList read GetDefaultFunctions write SetDefaultFunctions; property AutoVariables: Boolean read GetAutoVariables write SetAutoVariables; end; {** Implements an expression calculator class. } TZExpression = class (TInterfacedObject, IZExpression) private FTokenizer: IZTokenizer; FDefaultVariables: IZVariablesList; FDefaultFunctions: IZFunctionsList; FVariantManager: IZVariantManager; FParser: TZExpressionParser; FAutoVariables: Boolean; function GetTokenizer: IZTokenizer; procedure SetTokenizer(Value: IZTokenizer); function GetExpression: string; procedure SetExpression(const Value: string); function GetVariantManager: IZVariantManager; procedure SetVariantManager(Value: IZVariantManager); function GetDefaultVariables: IZVariablesList; procedure SetDefaultVariables(Value: IZVariablesList); function GetDefaultFunctions: IZFunctionsList; procedure SetDefaultFunctions(Value: IZFunctionsList); function GetAutoVariables: Boolean; procedure SetAutoVariables(Value: Boolean); public constructor Create; constructor CreateWithExpression(const Expression: string); destructor Destroy; override; function Evaluate: TZVariant; function Evaluate2(Variables: IZVariablesList): TZVariant; function Evaluate3(Variables: IZVariablesList; Functions: IZFunctionsList): TZVariant; function Evaluate4(Variables: IZVariablesList; Functions: IZFunctionsList; Stack: TZExecutionStack): TZVariant; procedure CreateVariables(Variables: IZVariablesList); procedure Clear; property Expression: string read GetExpression write SetExpression; property VariantManager: IZVariantManager read GetVariantManager write SetVariantManager; property DefaultVariables: IZVariablesList read GetDefaultVariables write SetDefaultVariables; property DefaultFunctions: IZFunctionsList read GetDefaultFunctions write SetDefaultFunctions; property AutoVariables: Boolean read GetAutoVariables write SetAutoVariables; end; implementation uses ZMessages, ZExprToken, ZVariables, ZFunctions, ZMatchPattern; { TZExecutionStack } {** Creates this object. } constructor TZExecutionStack.Create; begin FCapacity := 100; SetLength(FValues, FCapacity); FCount := 0; end; {** Gets a value from absolute position in the stack. @param Index a value index. @returns a variant value from requested position. } function TZExecutionStack.GetValue(Index: Integer): TZVariant; begin Result := FValues[Index]; end; {** Gets a value from the top of the stack without removing it. @returns a value from the top. } function TZExecutionStack.Peek: TZVariant; begin if FCount > 0 then Result := FValues[FCount - 1] else Result := NullVariant; end; {** Gets a function parameter by index. @param a function parameter index. O is used for parameter count. @returns a parameter value. } function TZExecutionStack.GetParameter(Index: Integer): TZVariant; begin if FCount <= Index then raise TZExpressionError.Create(SStackIsEmpty); Result := FValues[FCount - Index - 1]; end; procedure TZExecutionStack.DecStackPointer(const Value : integer); begin Dec(FCount, Value); if FCount < 0 then begin FCount := 0; raise TZExpressionError.Create(SStackIsEmpty); end; end; {** Gets a value from the top and removes it from the stack. @returns a value from the top. } function TZExecutionStack.Pop: TZVariant; begin Result := NullVariant; if FCount <= 0 then raise TZExpressionError.Create(SStackIsEmpty); Dec(FCount); Result := FValues[FCount]; end; {** Puts a value to the top of the stack. } procedure TZExecutionStack.Push(Value: TZVariant); begin if FCapacity = FCount then begin Inc(FCapacity, 64); SetLength(FValues, FCapacity); end; DefVarManager.Assign(Value, FValues[FCount]); Inc(FCount); end; {** Swaps two values on the top of the stack. } procedure TZExecutionStack.Swap; var Temp: TZVariant; begin if FCount <= 1 then raise TZExpressionError.Create(SStackIsEmpty); Temp := FValues[FCount - 1]; FValues[FCount - 1] := FValues[FCount - 2]; FValues[FCount - 2] := Temp; end; {** Clears this stack. } procedure TZExecutionStack.Clear; begin FCount := 0; end; { TZExpression } {** Creates this expression calculator object. } constructor TZExpression.Create; begin FTokenizer := TZExpressionTokenizer.Create; FDefaultVariables := TZVariablesList.Create; FDefaultFunctions := TZDefaultFunctionsList.Create; FVariantManager := TZSoftVariantManager.Create; FParser := TZExpressionParser.Create(FTokenizer); FAutoVariables := True; end; {** Creates this expression calculator and assignes expression string. @param Expression an expression string. } constructor TZExpression.CreateWithExpression(const Expression: string); begin Create; SetExpression(Expression); end; {** Destroys this object and cleanups the memory. } destructor TZExpression.Destroy; begin FTokenizer := nil; FDefaultVariables := nil; FDefaultFunctions := nil; FVariantManager := nil; FParser.Free; inherited Destroy; end; {** Gets the current auto variables create flag. @returns the auto variables create flag. } function TZExpression.GetAutoVariables: Boolean; begin Result := FAutoVariables; end; {** Sets a new auto variables create flag. @param value a new auto variables create flag. } procedure TZExpression.SetAutoVariables(Value: Boolean); begin FAutoVariables := Value; end; {** Gets a list of default functions. @returns a list of default functions. } function TZExpression.GetDefaultFunctions: IZFunctionsList; begin Result := FDefaultFunctions; end; {** Sets a new list of functions. @param Value a new list of functions. } procedure TZExpression.SetDefaultFunctions(Value: IZFunctionsList); begin FDefaultFunctions := Value; end; {** Gets a list of default variables. @returns a list of default variables. } function TZExpression.GetDefaultVariables: IZVariablesList; begin Result := FDefaultVariables; end; {** Sets a new list of variables. @param Value a new list of variables. } procedure TZExpression.SetDefaultVariables(Value: IZVariablesList); begin FDefaultVariables := Value; end; {** Gets the current set expression string. @returns the current expression string. } function TZExpression.GetExpression: string; begin Result := FParser.Expression; end; {** Sets a new expression string. @param Value a new expression string. } procedure TZExpression.SetExpression(const Value: string); begin FParser.Expression := Value; if FAutoVariables then CreateVariables(FDefaultVariables); end; {** Gets a reference to the current variant manager. @returns a reference to the current variant manager. } function TZExpression.GetVariantManager: IZVariantManager; begin Result := FVariantManager; end; {** Sets a new variant manager. @param Value a new variant manager. } procedure TZExpression.SetVariantManager(Value: IZVariantManager); begin FVariantManager := Value; end; {** Gets the current expression tokenizer. @returns the current expression tokenizer. } function TZExpression.GetTokenizer: IZTokenizer; begin Result := FTokenizer; end; {** Sets a new expression tokenizer. @param Value a new expression tokenizer. } procedure TZExpression.SetTokenizer(Value: IZTokenizer); begin FTokenizer := Value; FParser.Tokenizer := Value; end; {** Clears this class from all data. } procedure TZExpression.Clear; begin FParser.Clear; FDefaultVariables.Clear; end; {** Creates an empty variables. @param Variables a list of variables. } procedure TZExpression.CreateVariables(Variables: IZVariablesList); var I: Integer; Name: string; begin for I := 0 to FParser.Variables.Count - 1 do begin Name := FParser.Variables[I]; if Variables.FindByName(Name) < 0 then Variables.Add(Name, NullVariant); end; end; {** Evaluates this expression. @returns an evaluated expression value. } function TZExpression.Evaluate: TZVariant; begin Result := Evaluate3(FDefaultVariables, FDefaultFunctions); end; {** Evaluates this expression. @param Variables a list of variables. @returns an evaluated expression value. } function TZExpression.Evaluate2(Variables: IZVariablesList): TZVariant; begin Result := Evaluate3(Variables, FDefaultFunctions); end; {** Evaluates this expression. @param Variables a list of variables. @param Functions a list of functions. @returns an evaluated expression value. } function TZExpression.Evaluate3(Variables: IZVariablesList; Functions: IZFunctionsList): TZVariant; var Stack: TZExecutionStack; begin Stack := TZExecutionStack.Create; try Result := Evaluate4(Variables, Functions, Stack); finally Stack.Free; end; end; {** Evaluates this expression. @param Variables a list of variables. @param Functions a list of functions. @param Stack an execution stack. @returns an evaluated expression value. } function TZExpression.Evaluate4(Variables: IZVariablesList; Functions: IZFunctionsList; Stack: TZExecutionStack): TZVariant; var I, Index, ParamsCount: Integer; Current: TZExpressionToken; Value1, Value2: TZVariant; begin Stack.Clear; for I := 0 to FParser.ResultTokens.Count - 1 do begin Current := TZExpressionToken(FParser.ResultTokens[I]); case Current.TokenType of ttConstant: Stack.Push(Current.Value); { ttVariable: begin Index := Variables.FindByName(DefVarManager.GetAsString(Current.Value)); if Index < 0 then begin raise TZExpressionError.Create( Format(SVariableWasNotFound, [DefVarManager.GetAsString(Current.Value)])); end; Value1 := Variables.Values[Index]; Stack.Push(Value1) end; } ttVariable: begin if Current.Value.VType = vtString then begin Index := Variables.FindByName(Current.Value.VString); if Index < 0 then begin raise TZExpressionError.Create( Format(SVariableWasNotFound, [Current.Value.VString])); end; Current.Value := EncodeInteger(Index); end; if Current.Value.VType = vtInteger then Stack.Push(Variables.Values[Current.Value.VInteger]) else raise TZExpressionError.Create( Format(SSyntaxErrorNear, [SoftVarManager.GetAsString(Current.Value)])); end; { ttFunction: begin Index := Functions.FindByName(DefVarManager.GetAsString(Current.Value)); if Index < 0 then begin raise TZExpressionError.Create( Format(SFunctionWasNotFound, [DefVarManager.GetAsString(Current.Value)])); end; Value1 := Functions.Functions[Index].Execute(Stack, FVariantManager); ParamsCount := DefVarManager.GetAsInteger(Stack.Pop); while ParamsCount > 0 do begin Stack.Pop; Dec(ParamsCount); end; Stack.Push(Value1); end; } ttFunction: begin if Current.Value.VType = vtString then begin Index := Functions.FindByName(Current.Value.VString); if Index < 0 then begin raise TZExpressionError.Create( Format(SFunctionWasNotFound, [Current.Value.VString])); end; Current.Value := EncodeInterface(Functions.Functions[Index]); end; if Current.Value.VType = vtInterface then begin Value1 := IZFunction(Current.Value.VInterface).Execute(Stack, FVariantManager); ParamsCount := DefVarManager.GetAsInteger(Stack.Pop); Stack.DecStackPointer(ParamsCount); Stack.Push(Value1); end else raise TZExpressionError.Create( Format(SSyntaxErrorNear, [SoftVarManager.GetAsString(Current.Value)])); end; ttAnd: begin Value2 := Stack.Pop; Value1 := Stack.Pop; Stack.Push(FVariantManager.OpAnd(Value1, Value2)); end; ttOr: begin Value2 := Stack.Pop; Value1 := Stack.Pop; Stack.Push(FVariantManager.OpOr(Value1, Value2)); end; ttXor: begin Value2 := Stack.Pop; Value1 := Stack.Pop; Stack.Push(FVariantManager.OpXor(Value1, Value2)); end; ttNot: Stack.Push(FVariantManager.OpNot(Stack.Pop)); ttPlus: begin Value2 := Stack.Pop; Value1 := Stack.Pop; Stack.Push(FVariantManager.OpAdd(Value1, Value2)); end; ttMinus: begin Value2 := Stack.Pop; Value1 := Stack.Pop; Stack.Push(FVariantManager.OpSub(Value1, Value2)); end; ttStar: begin Value2 := Stack.Pop; Value1 := Stack.Pop; Stack.Push(FVariantManager.OpMul(Value1, Value2)); end; ttSlash: begin Value2 := Stack.Pop; Value1 := Stack.Pop; Stack.Push(FVariantManager.OpDiv(Value1, Value2)); end; ttProcent: begin Value2 := Stack.Pop; Value1 := Stack.Pop; Stack.Push(FVariantManager.OpMod(Value1, Value2)); end; ttEqual: begin Value2 := Stack.Pop; Value1 := Stack.Pop; Stack.Push(FVariantManager.OpEqual(Value1, Value2)); end; ttNotEqual: begin Value2 := Stack.Pop; Value1 := Stack.Pop; Stack.Push(FVariantManager.OpNotEqual(Value1, Value2)); end; ttMore: begin Value2 := Stack.Pop; Value1 := Stack.Pop; Stack.Push(FVariantManager.OpMore(Value1, Value2)); end; ttLess: begin Value2 := Stack.Pop; Value1 := Stack.Pop; Stack.Push(FVariantManager.OpLess(Value1, Value2)); end; ttEqualMore: begin Value2 := Stack.Pop; Value1 := Stack.Pop; Stack.Push(FVariantManager.OpMoreEqual(Value1, Value2)); end; ttEqualLess: begin Value2 := Stack.Pop; Value1 := Stack.Pop; Stack.Push(FVariantManager.OpLessEqual(Value1, Value2)); end; ttPower: begin Value2 := Stack.Pop; Value1 := Stack.Pop; Stack.Push(FVariantManager.OpPow(Value1, Value2)); end; ttUnary: Stack.Push(FVariantManager.OpNegative(Stack.Pop)); ttLike: begin Value2 := Stack.Pop; Value1 := Stack.Pop; Stack.Push(EncodeBoolean( IsMatch(FVariantManager.GetAsString(Value2), FVariantManager.GetAsString(Value1)))); end; ttNotLike: begin Value2 := Stack.Pop; Value1 := Stack.Pop; Stack.Push(EncodeBoolean( not IsMatch(FVariantManager.GetAsString(Value2), FVariantManager.GetAsString(Value1)))); end; ttIsNull: begin Value1 := Stack.Pop; Stack.Push(EncodeBoolean(FVariantManager.IsNull(Value1))); end; ttIsNotNull: begin Value1 := Stack.Pop; Stack.Push(EncodeBoolean(not FVariantManager.IsNull(Value1))); end; else raise TZExpressionError.Create(SInternalError); end; end; if Stack.Count <> 1 then raise TZExpressionError.Create(SInternalError); Result := Stack.Pop; end; end. ================================================ FILE: lib/zeosdbo/src/core/ZFunctions.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Variables classes and interfaces } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZFunctions; interface {$I ZCore.inc} uses SysUtils, Classes, ZClasses, ZCollections, ZCompatibility, ZVariant, ZExpression; type {** Implements a list of functions. } { TZFunctionsList } TZFunctionsList = class (TInterfacedObject, IZFunctionsList) private FFunctions: IZCollection; FCapacity : Integer; FKeys : Array of LongInt; procedure SetKeyCapacity(const NewCapacity : Integer); procedure SetKey(const aKey : LongInt; const aPosition : Integer); procedure RegenerateKey(const aPosition : Integer); procedure RegenerateKeys; protected property Functions: IZCollection read FFunctions write FFunctions; function FindByKeyAndName(const aKey : LongInt; const aName: string): Integer; public constructor Create; destructor Destroy; override; function GetCount: Integer; function GetName(Index: Integer): string; function GetFunction(Index: Integer): IZFunction; procedure Add(Func: IZFunction); procedure Remove(const Name: string); function FindByName(const Name: string): Integer; procedure Clear; end; {** Implements an abstract function. } { TZAbstractFunction } TZAbstractFunction = class (TInterfacedObject, IZFunction) private FName: string; protected function GetName: string; function CheckParamsCount(Stack: TZExecutionStack; ExpectedCount: Integer): Integer; public constructor Create(aName : string); function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; virtual; abstract; property Name: string read GetName; end; {** Implements a default function list. } TZDefaultFunctionsList = class (TZFunctionsList) public constructor Create; end; implementation uses ZMessages, ZFunctionsMath, ZFunctionsDateTime, ZFunctionsStrings, ZFunctionsConvert, ZFunctionsOther; { TZFunctionsList } {** Constructs this object. } constructor TZFunctionsList.Create; begin FFunctions := TZCollection.Create; SetKeyCapacity(0); end; {** Destroys this object and cleanup the memory. } destructor TZFunctionsList.Destroy; begin SetKeyCapacity(0); FFunctions := nil; inherited Destroy; end; {** Sets the capacity of the internal Keystorage. } procedure TZFunctionsList.SetKeyCapacity(const NewCapacity : Integer); begin if NewCapacity <> FCapacity then begin SetLength(FKeys, NewCapacity); FCapacity := NewCapacity; end; end; {** Sets a key to the Keystorage } procedure TZFunctionsList.SetKey(const aKey : LongInt; const aPosition : Integer); begin if aPosition >= FCapacity then SetKeyCapacity(FCapacity+16); FKeys[aPosition] := aKey end; {** Regenerates a given key } procedure TZFunctionsList.RegenerateKey(const aPosition : Integer); begin SetKey(Hash({$IFDEF UNICODE}AnsiString{$ENDIF}((FFunctions[aPosition] as IZFunction).Name)), aPosition); end; {** Regenerates all keys } procedure TZFunctionsList.RegenerateKeys; var I : Integer; begin SetKeyCapacity(0); for I := 0 to FFunctions.Count - 1 do RegenerateKey(i); end; {** Finds a function reference by its Name and Hashkey } function TZFunctionsList.FindByKeyAndName(const aKey : LongInt; const aName: string): Integer; var I: Integer; begin Result := -1; for I := 0 to FFunctions.Count - 1 do begin if aKey = FKeys[i] then begin if aName = (FFunctions[I] as IZFunction).Name then begin Result := I; Break; end; end; end; end; {** Finds a function reference } function TZFunctionsList.FindByName(const Name: string): Integer; var aName: string; begin aName := Uppercase(Name); Result := FindByKeyAndName(Hash({$IFDEF UNICODE}AnsiString{$ENDIF}(aName)), aName); end; {** Adds a new function to this list. @param Func a function reference. } procedure TZFunctionsList.Add(Func: IZFunction); var Index: Integer; aKey : LongInt; aName: string; begin aName := Uppercase(Func.Name); aKey := Hash({$IFDEF UNICODE}AnsiString{$ENDIF}(aName)); Index := FindByKeyAndName(aKey, aName); if Index < 0 then begin FFunctions.Add(Func); SetKey(aKey, FFunctions.Count-1); end else raise TZExpressionError.Create('Function '+Func.Name+' already defined!'); end; {** Removes a reference to a function by it's name. @param Name a name of the function to be removed. } procedure TZFunctionsList.Remove(const Name: string); var Index: Integer; begin Index := FindByName(Name); if Index >= 0 then begin FFunctions.Delete(Index); RegenerateKeys; end; end; {** Cleans the list of registered functions. } procedure TZFunctionsList.Clear; begin FFunctions.Clear; SetKeyCapacity(0); end; {** Gets a number of registered functions. @returns a number of registered functions. } function TZFunctionsList.GetCount: Integer; begin Result := FFunctions.Count; end; {** Gets a function reference by it's index. @param Index a function index. @returns a function reference. } function TZFunctionsList.GetFunction(Index: Integer): IZFunction; begin Result := FFunctions[Index] as IZFunction; end; {** Gets a name of the functions by it's index. @param Index a functon index. @returns a name of the function. } function TZFunctionsList.GetName(Index: Integer): string; begin Result := (FFunctions[Index] as IZFunction).Name; end; { TZDefaultFunctionsList } {** Constructs a default functions list and adds all available standard functions. } constructor TZDefaultFunctionsList.Create; begin inherited Create; AddMathFunctions(Self); AddStringFunctions(Self); AddConvertFunctions(Self); AddOtherFunctions(Self); AddDateTimeFunctions(Self); end; { TZAbstractFunction } {** Creates the function with a user defined name. } constructor TZAbstractFunction.Create(aName : string); begin inherited Create; FName := UpperCase(aName); end; {** Gets the assigned function name. @returns the assigned function name. } function TZAbstractFunction.GetName: string; begin Result := FName; end; {** Checks the function parameter count number. @param Stack a stack object. @param ExpectedCount a number of expected parameters. @returns a real number of parameters. } function TZAbstractFunction.CheckParamsCount(Stack: TZExecutionStack; ExpectedCount: Integer): Integer; begin Result := DefVarManager.GetAsInteger(Stack.GetParameter(0)); if Result <> ExpectedCount then begin raise TZExpressionError.Create(Format(SParametersError, [ExpectedCount, Result])); end; end; end. ================================================ FILE: lib/zeosdbo/src/core/ZFunctionsConvert.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Variables classes and interfaces } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZFunctionsConvert; interface {$I ZCore.inc} uses SysUtils, ZFunctions, ZExpression, ZVariant; {** Conversion functions } type {** Str <> Float} {** Implements a VAL function. } TZValFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Str <> Date} {** Implements a CTOD function. } TZCtodFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a DTOS function. } TZDtosFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a DTOS function. } TZFormatDateTimeFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; procedure AddConvertFunctions(Functions : TZFunctionsList); implementation var InternalDefaultFormatSettings : TFormatSettings; {******* DefaultFormatSettings : TFormatSettings = ( CurrencyFormat: 1; NegCurrFormat: 5; ThousandSeparator: ','; DecimalSeparator: '.'; CurrencyDecimals: 2; DateSeparator: '-'; TimeSeparator: ':'; ListSeparator: ','; CurrencyString: '$'; ShortDateFormat: 'd/m/y'; LongDateFormat: 'dd" "mmmm" "yyyy'; TimeAMString: 'AM'; TimePMString: 'PM'; ShortTimeFormat: 'hh:nn'; LongTimeFormat: 'hh:nn:ss'; ShortMonthNames: ('Jan','Feb','Mar','Apr','May','Jun', 'Jul','Aug','Sep','Oct','Nov','Dec'); LongMonthNames: ('January','February','March','April','May','June', 'July','August','September','October','November','December'); ShortDayNames: ('Sun','Mon','Tue','Wed','Thu','Fri','Sat'); LongDayNames: ('Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'); TwoDigitYearCenturyWindow: 50; ); ******} { TZValFunction } function TZValFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsFloat(Result, StrToFloatDef(Stack.GetParameter(1).VString, 0, InternalDefaultFormatSettings)); end; { TZCtodFunction } function TZCtodFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; var Value: TZVariant; begin CheckParamsCount(Stack, 1); Value := Stack.GetParameter(1); VariantManager.SetAsDateTime(Result, StrToDateDef(Value.VString, 0)); end; { TZDtosFunction } function TZDtosFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; var Value: TZVariant; begin CheckParamsCount(Stack, 1); Value := Stack.GetParameter(1); VariantManager.SetAsString(Result, FormatDateTime('yyyymmdd', Value.VDateTime)); end; { TZFormatDateTimeFunction } function TZFormatDateTimeFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 2); VariantManager.SetAsString(Result, FormatDateTime(Stack.GetParameter(2).VString, Stack.GetParameter(1).VDateTime)); end; procedure AddConvertFunctions(Functions : TZFunctionsList); begin Functions.Add(TZValFunction.Create('VAL')); Functions.Add(TZDtosFunction.Create('DTOS')); Functions.Add(TZCtodFunction.Create('CTOD')); Functions.Add(TZFormatDateTimeFunction.Create('FORMATDATETIME')); end; initialization // InternalDefaultFormatSettings := DefaultFormatSettings; InternalDefaultFormatSettings.ThousandSeparator := ','; InternalDefaultFormatSettings.DecimalSeparator := '.'; end. ================================================ FILE: lib/zeosdbo/src/core/ZFunctionsDateTime.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Variables classes and interfaces } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZFunctionsDateTime; interface {$I ZCore.inc} uses SysUtils, ZFunctions, ZExpression, ZVariant; {** Date & time functions} type {** Implements a DATE function. } TZDateFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a TIME function. } TZTimeFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a NOW function. } TZNowFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a ENCODEDATE function. } TZEncodeDateFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a ENCODETIME function. } TZEncodeTimeFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a COMPOSEDATETIME function. } { TZComposeDateTimeFunction } TZComposeDateTimeFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a INCDATE function. } TZIncDateFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a INCTIME function. } TZIncTimeFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a ISLEAPYEAR function. } TZIsLeapYearFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {-------------------- Extracting functions ----------------------------} {** Implements a DATEOF function. } TZDateOfFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a TIMEOF function. } TZTimeOfFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a YEAROF function. } TZYearOfFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a MONTHOF function. } TZMonthOfFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a DAYOF function. } TZDayOfFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a HOUROF function. } TZHourOfFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a MINUTEOF function. } TZMinuteOfFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a SECONDOF function. } TZSecondOfFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a MILLISECONDOF function. } TZMilliSecondOfFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {-------------------- *OFTHEYEAR Extracting functions ----------------------------} {** Implements a WEEKOFTHEYEAR function. } TZWeekOfTheYearFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a DAYOFTHEYEAR function. } TZDayOfTheYearFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a HOUROFTHEYEAR function. } TZHourOfTheYearFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a MINUTEOFTHEYEAR function. } TZMinuteOfTheYearFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a SECONDOFTHEYEAR function. } TZSecondOfTheYearFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a MILLISECONDOFTHEYEAR function. } TZMilliSecondOfTheYearFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {-------------------- *OFTHEMONTH Extracting functions ----------------------------} {** Implements a WEEKOFTHEMONTH function. } TZWeekOfTheMonthFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a HOUROFTHEMONTH function. } TZHourOfTheMonthFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a MINUTEOFTHEMONTH function. } TZMinuteOfTheMonthFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a SECONDOFTHEMONTH function. } TZSecondOfTheMonthFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a MILLISECONDOFTHEMONTH function. } TZMilliSecondOfTheMonthFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {-------------------- *OFTHEWEEK Extracting functions ----------------------------} {** Implements a DAYOfTheWeek function. } TZDayOfTheWeekFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a HOUROfTheWeek function. } TZHourOfTheWeekFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a MINUTEOfTheWeek function. } TZMinuteOfTheWeekFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a SECONDOfTheWeek function. } TZSecondOfTheWeekFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a MILLISECONDOfTheWeek function. } TZMilliSecondOfTheWeekFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {---------------- *OFTHEDAY Extracting functions --------------------} {** Implements a MINUTEOFTHEDAY function. } TZMinuteOfTheDayFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a SECONDOFTHEDAY function. } TZSecondOfTheDayFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a MILLISECONDOFTHEDAY function. } TZMilliSecondOfTheDayFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {---------------- *OfTheHour Extracting functions --------------------} {** Implements a SECONDOFTHEHOUR function. } TZSecondOfTheHourFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a MILLISECONDOFTHEHOUR function. } TZMilliSecondOfTheHourFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {---------------- *OFTHEMINUTE Extracting functions --------------------} {** Implements a MILLISECONDOfTheHour function. } TZMilliSecondOfTheMinuteFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {---------------- *BETWEEN functions --------------------} {** Implements a YEARSBETWEEN function. } TZYearsBetweenFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a MONTHSBETWEEN function. } TZMonthsBetweenFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a WEEKSBETWEEN function. } TZWeeksBetweenFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a DAYSBETWEEN function. } TZDaysBetweenFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a HOURSBETWEEN function. } TZHoursBetweenFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a MINUTESBETWEEN function. } TZMinutesBetweenFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a SECONDSBETWEEN function. } TZSecondsBetweenFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a MILLISECONDSBETWEEN function. } TZMillisecondsBetweenFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; procedure AddDateTimeFunctions(Functions : TZFunctionsList); implementation uses ZMessages, DateUtils; Function IncDate(const aDate : TDateTime; const aYear, aMonth, aWeek, aDay : LongInt) : TDateTime; begin Result := aDate; if aYear <> 0 then Result := IncYear(Result, aYear); if aMonth <> 0 then Result := IncMonth(Result, aMonth); if aWeek <> 0 then Result := IncWeek(Result, aWeek); if aDay <> 0 then Result := IncDay(Result, aDay); end; Function IncTime(const aDate : TDateTime; const aHour, aMinute, aSecond, aMillisec : LongInt) : TDateTime; begin Result := IncHour(IncMinute(IncSecond(IncMillisecond(aDate, aMilliSec),aSecond),aMinute),aHour); end; { TZDateFunction } function TZDateFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 0); VariantManager.SetAsDateTime(Result, Date); end; { TZTimeFunction } {** Executes this function. @param Stack the stack object. @param VariantManager a reference to variant processor object. @returns a function value. } function TZTimeFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 0); VariantManager.SetAsDateTime(Result, Time); end; { TZNowFunction } function TZNowFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 0); VariantManager.SetAsDateTime(Result, Now); end; { TZEncodeDateFunction } function TZEncodeDateFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; var ParamsCount: Integer; Year , Month, Day : LongInt; begin ParamsCount := VariantManager.GetAsInteger(Stack.GetParameter(0)); Year := 0; Month := 1; Day := 1; if ParamsCount > 0 then Year := VariantManager.GetAsInteger(Stack.GetParameter(ParamsCount)); if ParamsCount > 1 then Month := VariantManager.GetAsInteger(Stack.GetParameter(ParamsCount-1)); if ParamsCount > 2 then Day := VariantManager.GetAsInteger(Stack.GetParameter(ParamsCount-2)); VariantManager.SetAsDateTime(Result, EncodeDate(Year,Month,Day)); end; { TZEncodeDateFunction } function TZEncodeTimeFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; var ParamsCount: Integer; Hour , Minute, Second, MilliSecond : LongInt; begin ParamsCount := VariantManager.GetAsInteger(Stack.GetParameter(0)); Hour := 0; Minute := 0; Second := 0; MilliSecond := 0; if ParamsCount > 0 then Hour := VariantManager.GetAsInteger(Stack.GetParameter(ParamsCount)); if ParamsCount > 1 then Minute := VariantManager.GetAsInteger(Stack.GetParameter(ParamsCount-1)); if ParamsCount > 2 then Second := VariantManager.GetAsInteger(Stack.GetParameter(ParamsCount-2)); if ParamsCount > 3 then MilliSecond := VariantManager.GetAsInteger(Stack.GetParameter(ParamsCount-3)); VariantManager.SetAsDateTime(Result, EncodeTime(Hour,Minute,Second,MilliSecond)); end; { TZComposeDateTimeFunction } function TZComposeDateTimeFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 2); VariantManager.SetAsDateTime(Result, VariantManager.GetAsDateTime(Stack.GetParameter(2))+ VariantManager.GetAsDateTime(Stack.GetParameter(1))); end; { TZIncDateFunction } function TZIncDateFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; var ParamsCount: Integer; Date : TDateTime; Year , Month, Week, Day : LongInt; begin ParamsCount := VariantManager.GetAsInteger(Stack.GetParameter(0)); if (ParamsCount <= 2) then raise TZExpressionError.Create(SExpectedMoreParams); Date := VariantManager.GetAsDateTime(Stack.GetParameter(ParamsCount)); Year := VariantManager.GetAsInteger(Stack.GetParameter(ParamsCount-1)); Month := 0; Week := 0; Day := 0; if ParamsCount > 2 then Month := VariantManager.GetAsInteger(Stack.GetParameter(ParamsCount-2)); if ParamsCount > 3 then Week := VariantManager.GetAsInteger(Stack.GetParameter(ParamsCount-3)); if ParamsCount > 4 then Day := VariantManager.GetAsInteger(Stack.GetParameter(ParamsCount-4)); VariantManager.SetAsDateTime(Result, IncDate(Date,Year,Month,Week,Day)); end; { TZIncTimeFunction } function TZIncTimeFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; var ParamsCount: Integer; Date : TDateTime; Hour , Minute, Second, MilliSecond : LongInt; begin ParamsCount := VariantManager.GetAsInteger(Stack.GetParameter(0)); if (ParamsCount <= 2) then raise TZExpressionError.Create(SExpectedMoreParams); Date := VariantManager.GetAsDateTime(Stack.GetParameter(ParamsCount)); Hour := VariantManager.GetAsInteger(Stack.GetParameter(ParamsCount-1)); Minute := 0; Second := 0; MilliSecond := 0; if ParamsCount > 2 then Minute := VariantManager.GetAsInteger(Stack.GetParameter(ParamsCount-2)); if ParamsCount > 3 then Second := VariantManager.GetAsInteger(Stack.GetParameter(ParamsCount-3)); if ParamsCount > 4 then MilliSecond := VariantManager.GetAsInteger(Stack.GetParameter(ParamsCount-4)); VariantManager.SetAsDateTime(Result, IncTime(Date, Hour,Minute,Second,MilliSecond)); end; { TZIsLeapYearFunction } function TZIsLeapYearFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsBoolean(Result, IsLeapYear( VariantManager.GetAsInteger(Stack.GetParameter(1)))); end; { TZDateOfFunction } function TZDateOfFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsDateTime(Result, DateOf( VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZTimeOfFunction } function TZTimeOfFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsDateTime(Result, TimeOf( VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZYearOfFunction } function TZYearOfFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsInteger(Result, YearOf( VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZMonthOfFunction } function TZMonthOfFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsInteger(Result, MonthOf( VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZDayOfFunction } function TZDayOfFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsInteger(Result, DayOf( VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZHourOfFunction } function TZHourOfFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsInteger(Result, HourOf( VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZMinuteOfFunction } function TZMinuteOfFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsInteger(Result, MinuteOf( VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZSecondOfFunction } function TZSecondOfFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsInteger(Result, SecondOf( VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZMilliSecondOfFunction } function TZMilliSecondOfFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsInteger(Result, MilliSecondOf( VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZWeekOfTheYearFunction } function TZWeekOfTheYearFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsInteger(Result, WeekOfTheYear( VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZDayOfTheYearFunction } function TZDayOfTheYearFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsInteger(Result, DayOfTheYear( VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZHourOfTheYearFunction } function TZHourOfTheYearFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsInteger(Result, HourOfTheYear( VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZMinuteOfTheYearFunction } function TZMinuteOfTheYearFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsInteger(Result, MinuteOfTheYear( VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZSecondOfTheYearFunction } function TZSecondOfTheYearFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsInteger(Result, SecondOfTheYear( VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZMilliSecondOfTheYearFunction } function TZMilliSecondOfTheYearFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; {$IFDEF WITH_MILLISECONDOFTHEYEAR_BUG} function MilliSecondOfTheYear(const AValue: TDateTime): Int64; begin Result := MilliSecondOf(AValue) + Int64(SecondOfTheYear(AValue)) * MSecsPerSec; end; {$ENDIF} begin CheckParamsCount(Stack, 1); VariantManager.SetAsInteger(Result, MilliSecondOfTheYear( VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZWeekOfTheMonthFunction } function TZWeekOfTheMonthFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsInteger(Result, WeekOfTheMonth( VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZHourOfTheMonthFunction } function TZHourOfTheMonthFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsInteger(Result, HourOfTheMonth( VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZMinuteOfTheMonthFunction } function TZMinuteOfTheMonthFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsInteger(Result, MinuteOfTheMonth( VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZSecondOfTheMonthFunction } function TZSecondOfTheMonthFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsInteger(Result, SecondOfTheMonth( VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZMilliSecondOfTheMonthFunction } function TZMilliSecondOfTheMonthFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsInteger(Result, MilliSecondOfTheMonth( VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZDayOfTheWeekFunction } function TZDayOfTheWeekFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsInteger(Result, DayOfTheWeek( VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZHourOfTheWeekFunction } function TZHourOfTheWeekFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsInteger(Result, HourOfTheWeek( VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZMinuteOfTheWeekFunction } function TZMinuteOfTheWeekFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsInteger(Result, MinuteOfTheWeek( VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZSecondOfTheWeekFunction } function TZSecondOfTheWeekFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsInteger(Result, SecondOfTheWeek( VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZMilliSecondOfTheWeekFunction } function TZMilliSecondOfTheWeekFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsInteger(Result, MilliSecondOfTheWeek( VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZMinuteOfTheDayFunction } function TZMinuteOfTheDayFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsInteger(Result, MinuteOfTheDay( VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZSecondOfTheDayFunction } function TZSecondOfTheDayFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsInteger(Result, SecondOfTheDay( VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZMilliSecondOfTheDayFunction } function TZMilliSecondOfTheDayFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsInteger(Result, MilliSecondOfTheDay( VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZSecondOfTheHourFunction } function TZSecondOfTheHourFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsInteger(Result, SecondOfTheHour( VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZMilliSecondOfTheHourFunction } function TZMilliSecondOfTheHourFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsInteger(Result, MilliSecondOfTheHour( VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZMilliSecondOfTheMinuteFunction } function TZMilliSecondOfTheMinuteFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsInteger(Result, MilliSecondOfTheMinute( VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZYearsBetweenFunction } function TZYearsBetweenFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 2); VariantManager.SetAsInteger(Result, YearsBetween( VariantManager.GetAsDateTime(Stack.GetParameter(2)), VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZMonthsBetweenFunction } function TZMonthsBetweenFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 2); VariantManager.SetAsInteger(Result, MonthsBetween( VariantManager.GetAsDateTime(Stack.GetParameter(2)), VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZWeeksBetweenFunction } function TZWeeksBetweenFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 2); VariantManager.SetAsInteger(Result, WeeksBetween( VariantManager.GetAsDateTime(Stack.GetParameter(2)), VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZDaysBetweenFunction } function TZDaysBetweenFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 2); VariantManager.SetAsInteger(Result, DaysBetween( VariantManager.GetAsDateTime(Stack.GetParameter(2)), VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZHoursBetweenFunction } function TZHoursBetweenFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 2); VariantManager.SetAsInteger(Result, HoursBetween( VariantManager.GetAsDateTime(Stack.GetParameter(2)), VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZMinutesBetweenFunction } function TZMinutesBetweenFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 2); VariantManager.SetAsInteger(Result, MinutesBetween( VariantManager.GetAsDateTime(Stack.GetParameter(2)), VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZSecondsBetweenFunction } function TZSecondsBetweenFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 2); VariantManager.SetAsInteger(Result, SecondsBetween( VariantManager.GetAsDateTime(Stack.GetParameter(2)), VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; { TZHoursBetweenFunction } function TZMillisecondsBetweenFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 2); VariantManager.SetAsInteger(Result, MillisecondsBetween( VariantManager.GetAsDateTime(Stack.GetParameter(2)), VariantManager.GetAsDateTime(Stack.GetParameter(1)))); end; procedure AddDateTimeFunctions(Functions : TZFunctionsList); begin Functions.Add(TZDateFunction.Create('DATE')); Functions.Add(TZTimeFunction.Create('TIME')); Functions.Add(TZNowFunction.Create('NOW')); // First the Aliases Functions.Add(TZEncodeDateFunction.Create('ENCD')); Functions.Add(TZEncodeTimeFunction.Create('ENCT')); // Functions.Add(TZComposeDateTimeFunction.Create('COMPDT')); Functions.Add(TZIncDateFunction.Create('INCD')); Functions.Add(TZIncTimeFunction.Create('INCT')); Functions.Add(TZIsLeapYearFunction.Create('LEAPY')); // Functions.Add(TZDateOfFunction.Create('DATEOF')); // Functions.Add(TZTimeOfFunction.Create('TIMEOF')); // Functions.Add(TZYearOfFunction.Create('YEAROF')); // Functions.Add(TZMonthOfFunction.Create('MONTHOF')); // Functions.Add(TZDayOfFunction.Create('DAYOF')); // Functions.Add(TZHourOfFunction.Create('HOUROF')); Functions.Add(TZMinuteOfFunction.Create('MINOF')); Functions.Add(TZSecondOfFunction.Create('SECOF')); Functions.Add(TZMilliSecondOfFunction.Create('MSECOF')); Functions.Add(TZWeekOfTheYearFunction.Create('WofY')); Functions.Add(TZDayOfTheYearFunction.Create('DofY')); Functions.Add(TZHourOfTheYearFunction.Create('HofY')); Functions.Add(TZMinuteOfTheYearFunction.Create('MINofY')); Functions.Add(TZSecondOfTheYearFunction.Create('SECofY')); Functions.Add(TZMilliSecondOfTheYearFunction.Create('MSECofY')); Functions.Add(TZWeekOfTheMonthFunction.Create('WofM')); Functions.Add(TZHourOfTheMonthFunction.Create('HofM')); Functions.Add(TZMinuteOfTheMonthFunction.Create('MINofM')); Functions.Add(TZSecondOfTheMonthFunction.Create('SECofM')); Functions.Add(TZMilliSecondOfTheMonthFunction.Create('MSECofM')); Functions.Add(TZDayOfTheWeekFunction.Create('DofW')); Functions.Add(TZHourOfTheWeekFunction.Create('HofW')); Functions.Add(TZMinuteOfTheWeekFunction.Create('MINofW')); Functions.Add(TZSecondOfTheWeekFunction.Create('SECofW')); Functions.Add(TZMilliSecondOfTheWeekFunction.Create('MSECofW')); Functions.Add(TZMinuteOfTheDayFunction.Create('MINofD')); Functions.Add(TZSecondOfTheDayFunction.Create('SECofD')); Functions.Add(TZMilliSecondOfTheDayFunction.Create('MSECofD')); Functions.Add(TZSecondOfTheHourFunction.Create('SECofH')); Functions.Add(TZMilliSecondOfTheHourFunction.Create('MSECofH')); Functions.Add(TZMilliSecondOfTheMinuteFunction.Create('MSECofMIN')); Functions.Add(TZYearsBetweenFunction.Create('YBTW')); Functions.Add(TZMonthsBetweenFunction.Create('MBTW')); Functions.Add(TZWeeksBetweenFunction.Create('WBTW')); Functions.Add(TZDaysBetweenFunction.Create('DBTW')); Functions.Add(TZHoursBetweenFunction.Create('HBTW')); Functions.Add(TZMinutesBetweenFunction.Create('MINBTW')); Functions.Add(TZSecondsBetweenFunction.Create('SECBTW')); Functions.Add(TZMilliSecondsBetweenFunction.Create('MSECBTW')); // End of Aliases Functions.Add(TZEncodeDateFunction.Create('ENCODEDATE')); Functions.Add(TZEncodeTimeFunction.Create('ENCODETIME')); Functions.Add(TZComposeDateTimeFunction.Create('COMPOSEDATETIME')); Functions.Add(TZIncDateFunction.Create('INCDATE')); Functions.Add(TZIncTimeFunction.Create('INCTIME')); Functions.Add(TZIsLeapYearFunction.Create('ISLEAPYEAR')); Functions.Add(TZDateOfFunction.Create('DATEOF')); Functions.Add(TZTimeOfFunction.Create('TIMEOF')); Functions.Add(TZYearOfFunction.Create('YEAROF')); Functions.Add(TZMonthOfFunction.Create('MONTHOF')); Functions.Add(TZDayOfFunction.Create('DAYOF')); Functions.Add(TZHourOfFunction.Create('HOUROF')); Functions.Add(TZMinuteOfFunction.Create('MINUTEOF')); Functions.Add(TZSecondOfFunction.Create('SECONDOF')); Functions.Add(TZMilliSecondOfFunction.Create('MILLISECONDOF')); Functions.Add(TZWeekOfTheYearFunction.Create('WEEKOFTHEYEAR')); Functions.Add(TZDayOfTheYearFunction.Create('DAYOFTHEYEAR')); Functions.Add(TZHourOfTheYearFunction.Create('HOUROFTHEYEAR')); Functions.Add(TZMinuteOfTheYearFunction.Create('MINUTEOFTHEYEAR')); Functions.Add(TZSecondOfTheYearFunction.Create('SECONDOFTHEYEAR')); Functions.Add(TZMilliSecondOfTheYearFunction.Create('MILLISECONDOFTHEYEAR')); Functions.Add(TZWeekOfTheMonthFunction.Create('WEEKOFTHEMONTH')); Functions.Add(TZHourOfTheMonthFunction.Create('HOUROFTHEMONTH')); Functions.Add(TZMinuteOfTheMonthFunction.Create('MINUTEOFTHEMONTH')); Functions.Add(TZSecondOfTheMonthFunction.Create('SECONDOFTHEMONTH')); Functions.Add(TZMilliSecondOfTheMonthFunction.Create('MILLISECONDOFTHEMONTH')); Functions.Add(TZDayOfTheWeekFunction.Create('DAYOFTHEWEEK')); Functions.Add(TZHourOfTheWeekFunction.Create('HOUROFTHEWEEK')); Functions.Add(TZMinuteOfTheWeekFunction.Create('MINUTEOFTHEWEEK')); Functions.Add(TZSecondOfTheWeekFunction.Create('SECONDOFTHEWEEK')); Functions.Add(TZMilliSecondOfTheWeekFunction.Create('MILLISECONDOFTHEWEEK')); Functions.Add(TZMinuteOfTheDayFunction.Create('MINUTEOFTHEDAY')); Functions.Add(TZSecondOfTheDayFunction.Create('SECONDOFTHEDAY')); Functions.Add(TZMilliSecondOfTheDayFunction.Create('MILLISECONDOFTHEDAY')); Functions.Add(TZSecondOfTheHourFunction.Create('SECONDOFTHEHOUR')); Functions.Add(TZMilliSecondOfTheHourFunction.Create('MILLISECONDOFTHEHOUR')); Functions.Add(TZMilliSecondOfTheMinuteFunction.Create('MILLISECONDOFTHEMINUTE')); Functions.Add(TZYearsBetweenFunction.Create('YEARSBETWEEN')); Functions.Add(TZMonthsBetweenFunction.Create('MONTHSBETWEEN')); Functions.Add(TZWeeksBetweenFunction.Create('WEEKSBETWEEN')); Functions.Add(TZDaysBetweenFunction.Create('DAYSBETWEEN')); Functions.Add(TZHoursBetweenFunction.Create('HOURSBETWEEN')); Functions.Add(TZMinutesBetweenFunction.Create('MINUTESBETWEEN')); Functions.Add(TZSecondsBetweenFunction.Create('SECONDSBETWEEN')); Functions.Add(TZMilliSecondsBetweenFunction.Create('MILLISECONDSBETWEEN')); end; end. ================================================ FILE: lib/zeosdbo/src/core/ZFunctionsMath.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Variables classes and interfaces } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZFunctionsMath; interface {$I ZCore.inc} uses SysUtils, ZFunctions, ZExpression, ZVariant; {** Math functions } type {** Implements a E function. } TZEFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a PI function. } TZPIFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a RND function. } TZRndFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a ABS function. } TZAbsFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Trigonometric } {** Implements a COS function. } TZCosFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a COT function. } TZCotFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a SIN function. } TZSinFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a TAN function. } TZTanFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a ACOS function. } TZAcosFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a ASIN function. } TZAsinFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a ATAN function. } TZAtanFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Rounding } {** Implements a ROUND function. } TZRoundFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a TRUNC function. } TZTruncFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a INT function. } TZIntFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a FRAC function. } TZFracFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a CEIL function. } TZCeilFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a FLOOR function. } TZFloorFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Logarithmic } {** Implements a EXP function. } TZExpFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a LOG function. } TZLogFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a LOG10 function. } TZLog10Function = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a SQR function. } TZSqrFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; procedure AddMathFunctions(Functions : TZFunctionsList); implementation uses Math; {$IFDEF FPC} {$HINTS OFF} {$ENDIF} { TZEFunction } {** Executes this function. @param Stack the stack object. @param VariantManager a reference to variant processor object. @returns a function value. } function TZEFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 0); VariantManager.SetAsFloat(Result, Exp(1)); end; { TZPIFunction } {** Executes this function. @param Stack the stack object. @param VariantManager a reference to variant processor object. @returns a function value. } function TZPIFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 0); VariantManager.SetAsFloat(Result, PI); end; { TZRndFunction } {** Executes this function. @param Stack the stack object. @param VariantManager a reference to variant processor object. @returns a function value. } function TZRndFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 0); VariantManager.SetAsFloat(Result, Random); end; { TZAbsFunction } {** Executes this function. @param Stack the stack object. @param VariantManager a reference to variant processor object. @returns a function value. } function TZAbsFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; var Value: TZVariant; begin CheckParamsCount(Stack, 1); Value := Stack.GetParameter(1); if Value.VType = vtInteger then VariantManager.SetAsInteger(Result, Abs(Value.VInteger)) else if Value.VType = vtFloat then VariantManager.SetAsFloat(Result, Abs(Value.VFloat)) else Result := Value; end; { TZExpFunction } {** Executes this function. @param Stack the stack object. @param VariantManager a reference to variant processor object. @returns a function value. } function TZExpFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsFloat(Result, Exp( VariantManager.GetAsFloat(Stack.GetParameter(1)))); end; { TZLogFunction } {** Executes this function. @param Stack the stack object. @param VariantManager a reference to variant processor object. @returns a function value. } function TZLogFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsFloat(Result, Ln( VariantManager.GetAsFloat(Stack.GetParameter(1)))); end; { TZLog10Function } {** Executes this function. @param Stack the stack object. @param VariantManager a reference to variant processor object. @returns a function value. } function TZLog10Function.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsFloat(Result, Log10( VariantManager.GetAsFloat(Stack.GetParameter(1)))); end; { TZCosFunction } {** Executes this function. @param Stack the stack object. @param VariantManager a reference to variant processor object. @returns a function value. } function TZCosFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsFloat(Result, Cos( VariantManager.GetAsFloat(Stack.GetParameter(1)))); end; { TZCotFunction } {** Executes this function. @param Stack the stack object. @param VariantManager a reference to variant processor object. @returns a function value. } function TZCotFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsFloat(Result, Cotan( VariantManager.GetAsFloat(Stack.GetParameter(1)))); end; { TZSinFunction } {** Executes this function. @param Stack the stack object. @param VariantManager a reference to variant processor object. @returns a function value. } function TZSinFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsFloat(Result, Sin( VariantManager.GetAsFloat(Stack.GetParameter(1)))); end; { TZTanFunction } {** Executes this function. @param Stack the stack object. @param VariantManager a reference to variant processor object. @returns a function value. } function TZTanFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsFloat(Result, Tan( VariantManager.GetAsFloat(Stack.GetParameter(1)))); end; { TZAcosFunction } {** Executes this function. @param Stack the stack object. @param VariantManager a reference to variant processor object. @returns a function value. } function TZAcosFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsFloat(Result, ArcCos( VariantManager.GetAsFloat(Stack.GetParameter(1)))); end; { TZAsinFunction } {** Executes this function. @param Stack the stack object. @param VariantManager a reference to variant processor object. @returns a function value. } function TZAsinFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsFloat(Result, ArcSin( VariantManager.GetAsFloat(Stack.GetParameter(1)))); end; { TZAtanFunction } {** Executes this function. @param Stack the stack object. @param VariantManager a reference to variant processor object. @returns a function value. } function TZAtanFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsFloat(Result, ArcTan( VariantManager.GetAsFloat(Stack.GetParameter(1)))); end; { TZCeilFunction } {** Executes this function. @param Stack the stack object. @param VariantManager a reference to variant processor object. @returns a function value. } function TZCeilFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsInteger(Result, Ceil( VariantManager.GetAsFloat(Stack.GetParameter(1)))); end; { TZFloorFunction } {** Executes this function. @param Stack the stack object. @param VariantManager a reference to variant processor object. @returns a function value. } function TZFloorFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsInteger(Result, Floor( VariantManager.GetAsFloat(Stack.GetParameter(1)))); end; { TZRoundFunction } {** Executes this function. @param Stack the stack object. @param VariantManager a reference to variant processor object. @returns a function value. } function TZRoundFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsInteger(Result, Round(VariantManager.GetAsFloat(Stack.GetParameter(1)))); end; { TZTruncFunction } {** Executes this function. @param Stack the stack object. @param VariantManager a reference to variant processor object. @returns a function value. } function TZTruncFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsInteger(Result, Trunc(VariantManager.GetAsFloat(Stack.GetParameter(1)))); end; { TZIntFunction } {** Executes this function. @param Stack the stack object. @param VariantManager a reference to variant processor object. @returns a function value. } function TZIntFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsFloat(Result, Int(VariantManager.GetAsFloat(Stack.GetParameter(1)))); end; { TZFracFunction } {** Executes this function. @param Stack the stack object. @param VariantManager a reference to variant processor object. @returns a function value. } function TZFracFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsFloat(Result, Frac(VariantManager.GetAsFloat(Stack.GetParameter(1)))); end; { TZSqrFunction } {** Executes this function. @param Stack the stack object. @param VariantManager a reference to variant processor object. @returns a function value. } function TZSqrFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsFloat(Result, Sqrt( VariantManager.GetAsFloat(Stack.GetParameter(1)))); end; procedure AddMathFunctions(Functions : TZFunctionsList); begin Functions.Add(TZEFunction.Create('E')); Functions.Add(TZPIFunction.Create('PI')); Functions.Add(TZRndFunction.Create('RND')); Functions.Add(TZAbsFunction.Create('ABS')); Functions.Add(TZExpFunction.Create('EXP')); Functions.Add(TZLogFunction.Create('LOG')); Functions.Add(TZLog10Function.Create('LOG10')); Functions.Add(TZCosFunction.Create('COS')); Functions.Add(TZSinFunction.Create('SIN')); Functions.Add(TZTanFunction.Create('TAN')); Functions.Add(TZCotFunction.Create('COT')); Functions.Add(TZAcosFunction.Create('ACOS')); Functions.Add(TZAsinFunction.Create('ASIN')); Functions.Add(TZAtanFunction.Create('ATAN')); Functions.Add(TZRoundFunction.Create('ROUND')); Functions.Add(TZCeilFunction.Create('CEIL')); Functions.Add(TZFloorFunction.Create('FLOOR')); Functions.Add(TZIntFunction.Create('INT')); Functions.Add(TZTruncFunction.Create('TRUNC')); Functions.Add(TZFracFunction.Create('FRAC')); Functions.Add(TZSqrFunction.Create('SQR')); Functions.Add(TZSqrFunction.Create('SQRT')); end; end. ================================================ FILE: lib/zeosdbo/src/core/ZFunctionsOther.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Variables classes and interfaces } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZFunctionsOther; interface {$I ZCore.inc} uses SysUtils, ZFunctions, ZExpression, ZVariant; {** Other functions} type {** Implements a EMPTY function. } TZEmptyFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a MIN function. } TZMinFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a MAX function. } TZMaxFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a SUM function. } TZSumFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a IIF function. } TZIIFFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a CASEF function. } TZCASEFFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; procedure AddOtherFunctions(Functions : TZFunctionsList); implementation uses ZMessages; { TZEmptyFunction } {** Executes this function. @param Stack the stack object. @param VariantManager a reference to variant processor object. @returns a function value. } function TZEmptyFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; var Value: TZVariant; begin CheckParamsCount(Stack, 1); Value := Stack.GetParameter(1); VariantManager.SetAsBoolean(Result, VariantManager.IsNull(Value)); end; { TZMinFunction } {** Executes this function. @param Stack the stack object. @param VariantManager a reference to variant processor object. @returns a function value. } function TZMinFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; var I, ParamsCount: Integer; Value: TZVariant; begin ParamsCount := VariantManager.GetAsInteger(Stack.GetParameter(0)); if ParamsCount < 2 then raise TZExpressionError.Create(SExpectedMoreParams); Result := Stack.GetParameter(ParamsCount); for I := 1 to ParamsCount - 1 do begin Value := Stack.GetParameter(I); if VariantManager.Compare(Result, Value) > 0 then Result := Value; end; end; { TZMaxFunction } {** Executes this function. @param Stack the stack object. @param VariantManager a reference to variant processor object. @returns a function value. } function TZMaxFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; var I, ParamsCount: Integer; Value: TZVariant; begin ParamsCount := VariantManager.GetAsInteger(Stack.GetParameter(0)); if ParamsCount < 2 then raise TZExpressionError.Create(SExpectedMoreParams); Result := Stack.GetParameter(ParamsCount); for I := 1 to ParamsCount - 1 do begin Value := Stack.GetParameter(I); if VariantManager.Compare(Result, Value) < 0 then Result := Value; end; end; { TZSumFunction } {** Executes this function. @param Stack the stack object. @param VariantManager a reference to variant processor object. @returns a function value. } function TZSumFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; var I, ParamsCount: Integer; begin ParamsCount := VariantManager.GetAsInteger(Stack.GetParameter(0)); if ParamsCount < 2 then raise TZExpressionError.Create(SExpectedMoreParams); Result := Stack.GetParameter(ParamsCount); for I := ParamsCount - 1 downto 1 do Result := VariantManager.OpAdd(Result, Stack.GetParameter(I)); end; { TZIIFFunction } {** Executes this function. @param Stack the stack object. @param VariantManager a reference to variant processor object. @returns a function value. } function TZIIFFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 3); if VariantManager.GetAsBoolean(Stack.GetParameter(3)) then Result := Stack.GetParameter(2) else Result := Stack.GetParameter(1); end; { TZCASEFFunction } {** Executes this function. @param Stack the stack object. @param VariantManager a reference to variant processor object. @returns a function value. } function TZCASEFFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; var ParamsCount, Index : Integer; begin ParamsCount := VariantManager.GetAsInteger(Stack.GetParameter(0)); if ParamsCount < 2 then raise TZExpressionError.Create(SExpectedMoreParams); Index := VariantManager.GetAsInteger(Stack.GetParameter(ParamsCount)); if ParamsCount < (Index+2) then raise TZExpressionError.Create(SExpectedMoreParams); Result := Stack.GetParameter(ParamsCount-Index-1) end; procedure AddOtherFunctions(Functions : TZFunctionsList); begin Functions.Add(TZEmptyFunction.Create('EMPTY')); Functions.Add(TZMinFunction.Create('MIN')); Functions.Add(TZMaxFunction.Create('MAX')); Functions.Add(TZSumFunction.Create('SUM')); Functions.Add(TZIIFFunction.Create('IIF')); Functions.Add(TZCASEFFunction.Create('CASEF')); end; end. ================================================ FILE: lib/zeosdbo/src/core/ZFunctionsStrings.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Variables classes and interfaces } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZFunctionsStrings; interface {$I ZCore.inc} uses SysUtils, ZFunctions, ZExpression, ZVariant; {** String functions} type {** Implements a CONCAT function. } TZConcatFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a SUBSTR function. } TZSubStrFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a LEFT function. } TZLeftFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a RIGHT function. } TZRightFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a STRPOS function. } TZStrPosFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a LENGTH function. } TZLengthFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a UPPER function. } TZUpperFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a LOWER function. } TZLowerFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a CAPITALIZE function. } TZCapitalizeFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a TRIM function. } TZTrimFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a LTRIM function. } TZLTrimFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a RTRIM function. } TZRTrimFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a SOUNDEX function. } TZSoundexFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; {** Implements a LEVENSHTEINDIST function. } TZLevenshteinDistanceFunction = class (TZAbstractFunction) public function Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; override; end; Function Capitalize(const s:string; Delims : string = '') : string; Function LevenshteinDistance(const s1, s2: string; const DoUpcase : BOOLEAN = TRUE): Integer; procedure AddStringFunctions(Functions : TZFunctionsList); {$IFNDEF FPC} {$ENDIF} implementation uses Math, StrUtils, ZMessages, ZCompatibility; Function Capitalize(const s:string; Delims : string = '') : string; var sDelims : set of ansichar; i : integer; begin if Delims = '' then sDelims := StdWordDelims else begin sDelims := []; for i:=1 to Length(Delims) do Include(sDelims,AnsiChar(Delims[i])) end; Result := AnsiProperCase(s, sDelims); end; Function LevenshteinDistance(const s1, s2: string; const DoUpcase : BOOLEAN = TRUE): Integer; var d : array of array of Integer; s,t : string; Start, Len1, Len2, i, j, Cost : Integer; begin Len1 := Length(s1); Len2 := Length(s2); if Len1 = 0 then begin Result := Len2; Exit; end; if Len2 = 0 then begin Result := Len1; Exit; end; if DoUpcase then begin s := Uppercase(s1); t := Uppercase(s2); end else begin s := s1; t := s2; end; start := 1; // trim off the matching items at the beginning while (start <= Len1) and (start <= Len2) and (s[start] = t[start]) do INC(start); // trim off the matching items at the end while (start <= Len1) and (start <= Len2) and (s[Len1] = t[Len2]) do begin DEC(Len1); DEC(Len2); end; DEC(Start); DEC(Len1, Start); DEC(Len2, Start); if Len1 = 0 then begin Result := Len2; Exit; end; if Len2 = 0 then begin Result := Len1; Exit; end; setlength(d, Len1 + 1, Len2 + 1); for i := 0 to Len1 do d[i, 0] := i; for j := 0 to Len2 do d[0, j] := j; // only loop over the items that are different for i := 1 to Len1 do begin for j := 1 to Len2 do begin Cost := ABS(ORD(s[i+start] <> t[j+start])); d[i, j] := Min( Min(d[i-1,j]+1, // deletion d[i,j-1]+1), // insertion d[i-1,j-1]+Cost); // substitution end; end; Result := d[Len1, Len2]; end; {**** This is the original not optimized version Function LevenshteinDistance(const s1, s2: string; const DoUpcase : BOOLEAN = TRUE): Integer; var d : array of array of Integer; s,t : string; Len1, Len2, i, j, Cost : Integer; begin Len1 := Length(s1); Len2 := Length(s2); if Len1 = 0 then begin Result := Len2; Exit; end; if Len2 = 0 then begin Result := Len1; Exit; end; if DoUpcase then begin s := Upcase(s1); t := Upcase(s2); end else begin s := s1; t := s2; end; setlength(d, Len1 + 1, Len2 + 1); for i := 0 to Len1 do d[i, 0] := i; for j := 0 to Len2 do d[0, j] := j; for i := 1 to Len1 do begin for j := 1 to Len2 do begin Cost := ABS(ORD(s[i] <> t[j])); d[i, j] := Min( Min(d[i-1,j]+1, d[i,j-1]+1), d[i-1,j-1]+Cost); end; end; Result := d[Len1, Len2]; end; ******} { TZConcatFunction } {** Executes this function. @param Stack the stack object. @param VariantManager a reference to variant processor object. @returns a function value. } function TZConcatFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; var I, ParamsCount: Integer; Temp: string; begin ParamsCount := VariantManager.GetAsInteger(Stack.GetParameter(0)); if ParamsCount < 2 then raise TZExpressionError.Create(SExpectedMoreParams); Temp := VariantManager.GetAsString(Stack.GetParameter(ParamsCount)); for I := ParamsCount - 1 downto 1 do Temp := Temp + VariantManager.GetAsString(Stack.GetParameter(I)); VariantManager.SetAsString(Result, Temp); end; { TZSubStrFunction } {** Executes this function. @param Stack the stack object. @param VariantManager a reference to variant processor object. @returns a function value. } function TZSubStrFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 3); VariantManager.SetAsString(Result, Copy( VariantManager.GetAsString(Stack.GetParameter(3)), VariantManager.GetAsInteger(Stack.GetParameter(2)), VariantManager.GetAsInteger(Stack.GetParameter(1)))); end; { TZLeftFunction } function TZLeftFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; var Value1, Value2: TZVariant; begin CheckParamsCount(Stack, 2); Value1 := Stack.GetParameter(2); Value2 := Stack.GetParameter(1); VariantManager.SetAsString(Result, LeftStr(Value1.VString, Value2.VInteger)); end; { TZRightFunction } function TZRightFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; var Value1, Value2: TZVariant; begin CheckParamsCount(Stack, 2); Value1 := Stack.GetParameter(2); Value2 := Stack.GetParameter(1); VariantManager.SetAsString(Result, RightStr(Value1.VString, Value2.VInteger)); end; { TZStrPosFunction } {** Executes this function. @param Stack the stack object. @param VariantManager a reference to variant processor object. @returns a function value. } function TZStrPosFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 2); VariantManager.SetAsInteger(Result, Pos( VariantManager.GetAsString(Stack.GetParameter(2)), VariantManager.GetAsString(Stack.GetParameter(1)))); end; { TZLengthFunction } {** Executes this function. @param Stack the stack object. @param VariantManager a reference to variant processor object. @returns a function value. } function TZLengthFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsInteger(Result, Length(VariantManager.GetAsString(Stack.GetParameter(1)))); end; { TZLowerFunction } {** Executes this function. @param Stack the stack object. @param VariantManager a reference to variant processor object. @returns a function value. } function TZLowerFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsString(Result, AnsiLowerCase( VariantManager.GetAsString(Stack.GetParameter(1)))); end; { TZUpperFunction } {** Executes this function. @param Stack the stack object. @param VariantManager a reference to variant processor object. @returns a function value. } function TZUpperFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; begin CheckParamsCount(Stack, 1); VariantManager.SetAsString(Result, AnsiUpperCase( VariantManager.GetAsString(Stack.GetParameter(1)))); end; { TZCapitalizeFunction } function TZCapitalizeFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; var ParamsCount: Integer; begin ParamsCount := VariantManager.GetAsInteger(Stack.GetParameter(0)); if (ParamsCount < 1) then raise TZExpressionError.Create(SExpectedMoreParams); if (ParamsCount < 2) then VariantManager.SetAsString(Result, Capitalize( VariantManager.GetAsString(Stack.GetParameter(1)))) else VariantManager.SetAsString(Result, Capitalize( VariantManager.GetAsString(Stack.GetParameter(2)), VariantManager.GetAsString(Stack.GetParameter(1)))) end; { TZTrimFunction } function TZTrimFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; var Value: TZVariant; begin CheckParamsCount(Stack, 1); Value := Stack.GetParameter(1); VariantManager.SetAsString(Result, Trim(Value.VString)); end; { TZLTrimFunction } function TZLTrimFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; var Value: TZVariant; begin CheckParamsCount(Stack, 1); Value := Stack.GetParameter(1); VariantManager.SetAsString(Result, TrimLeft(Value.VString)); end; { TZRTrimFunction } function TZRTrimFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; var Value: TZVariant; begin CheckParamsCount(Stack, 1); Value := Stack.GetParameter(1); VariantManager.SetAsString(Result, TrimRight(Value.VString)); end; { TZSoundexFunction } function TZSoundexFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; var ParamsCount: Integer; begin ParamsCount := VariantManager.GetAsInteger(Stack.GetParameter(0)); if (ParamsCount < 1) then raise TZExpressionError.Create(SExpectedMoreParams); if (ParamsCount < 2) then VariantManager.SetAsString(Result, Soundex( VariantManager.GetAsString(Stack.GetParameter(1)))) else VariantManager.SetAsString(Result, Soundex( VariantManager.GetAsString(Stack.GetParameter(2)), VariantManager.GetAsInteger(Stack.GetParameter(1)))) end; function TZLevenshteinDistanceFunction.Execute(Stack: TZExecutionStack; VariantManager: IZVariantManager): TZVariant; var ParamsCount: Integer; begin ParamsCount := VariantManager.GetAsInteger(Stack.GetParameter(0)); if (ParamsCount < 2) then raise TZExpressionError.Create(SExpectedMoreParams); if (ParamsCount < 3) then VariantManager.SetAsInteger(Result, LevenshteinDistance( VariantManager.GetAsString(Stack.GetParameter(2)), VariantManager.GetAsString(Stack.GetParameter(1)))) else VariantManager.SetAsInteger(Result, LevenshteinDistance( VariantManager.GetAsString(Stack.GetParameter(3)), VariantManager.GetAsString(Stack.GetParameter(2)), VariantManager.GetAsBoolean(Stack.GetParameter(1)))) end; procedure AddStringFunctions(Functions : TZFunctionsList); begin Functions.Add(TZConcatFunction.Create('CONCAT')); Functions.Add(TZSubStrFunction.Create('SUBSTR')); Functions.Add(TZLeftFunction.Create('LEFT')); Functions.Add(TZRightFunction.Create('RIGHT')); Functions.Add(TZStrPosFunction.Create('STRPOS')); Functions.Add(TZLengthFunction.Create('LENGTH')); Functions.Add(TZUpperFunction.Create('UPPER')); Functions.Add(TZLowerFunction.Create('LOWER')); Functions.Add(TZCapitalizeFunction.Create('CAP')); Functions.Add(TZCapitalizeFunction.Create('CAPITALIZE')); Functions.Add(TZTrimFunction.Create('TRIM')); Functions.Add(TZLTrimFunction.Create('LTRIM')); Functions.Add(TZRTrimFunction.Create('RTRIM')); Functions.Add(TZSoundexFunction.Create('SOUNDEX')); Functions.Add(TZLevenshteinDistanceFunction.Create('LEVDIST')); Functions.Add(TZLevenshteinDistanceFunction.Create('LEVENSHTEINDISTANCE')); end; end. ================================================ FILE: lib/zeosdbo/src/core/ZMatchPattern.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Regular Expressions } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZMatchPattern; { Author: Kevin Boylan Ported By: Sergey Seroukhov This code is meant to allow wildcard pattern matches. It is VERY useful for matching filename wildcard patterns. It allows unix grep-like pattern comparisons, for instance: ? Matches any single characer * Matches any contiguous characters [abc] Matches a or b or c at that position [^abc] Matches anything but a or b or c at that position [!abc] Ditto [a-e] Matches a through e at that position 'ma?ch.*' -Would match match.exe, mavch.dat, march.on, etc 'this [e-n]s a [!zy]est' - Would match 'this is a test', but would not match 'this as a yest' This is a Delphi VCL translation from C code that was downloaded from CIS. C code was written by J. Kerceval and released to public domain 02/20/1991. This code is ofcourse also public domain. I would appreciate it if you would let me know if you find any bugs. I would also appreciate any notes sent my way letting me know if you find it useful. } {$I ZCore.inc} interface uses SysUtils; { Check if Text equal to pattern } function IsMatch(const Pattern, Text: string): Boolean; implementation const { Match defines } MATCH_PATTERN = 6; MATCH_LITERAL = 5; MATCH_RANGE = 4; MATCH_ABORT = 3; MATCH_END = 2; MATCH_VALID = 1; { Pattern defines } { PATTERN_VALID = 0; PATTERN_ESC = -1; PATTERN_RANGE = -2; PATTERN_CLOSE = -3; PATTERN_EMPTY = -4; }{ Character defines } MATCH_CHAR_SINGLE = '?'; MATCH_CHAR_KLEENE_CLOSURE = '*'; MATCH_CHAR_RANGE_OPEN = '['; MATCH_CHAR_RANGE = '-'; MATCH_CHAR_RANGE_CLOSE = ']'; MATCH_CHAR_CARET_NEGATE = '^'; MATCH_CHAR_EXCLAMATION_NEGATE = '!'; function Matche(Pattern, Text: string): Integer; forward; function MatchAfterStar(Pattern, Text: string): Integer; forward; //function IsPattern(Pattern: string): Boolean; forward; function IsMatch(const Pattern, Text: string): Boolean; begin Result := (Matche(Pattern, Text) = 1); end; function Matche(Pattern, Text: string): Integer; var RangeStart, RangeEnd, P, T, PLen, TLen: Integer; Invert, MemberMatch, Loop: Boolean; begin P := 1; T := 1; Pattern := AnsiLowerCase(pattern); Text := AnsiLowerCase(Text); PLen := Length(pattern); TLen := Length(text); Result := 0; while ((Result = 0) and (P <= PLen)) do begin if T > TLen then begin if (Pattern[P] = MATCH_CHAR_KLEENE_CLOSURE) and (P+1 > PLen) then Result := MATCH_VALID else Result := MATCH_ABORT; Exit; end else case (Pattern[P]) of MATCH_CHAR_KLEENE_CLOSURE: Result := MatchAfterStar(Copy(Pattern,P,PLen),Copy(Text,T,TLen)); MATCH_CHAR_RANGE_OPEN: begin Inc(P); Invert := False; if (Pattern[P] = MATCH_CHAR_EXCLAMATION_NEGATE) or (Pattern[P] = MATCH_CHAR_CARET_NEGATE) then begin Invert := True; Inc(P); end; if (Pattern[P] = MATCH_CHAR_RANGE_CLOSE) then begin Result := MATCH_PATTERN; Exit; end; MemberMatch := False; Loop := True; while (Loop and (Pattern[P] <> MATCH_CHAR_RANGE_CLOSE)) do begin RangeStart := P; RangeEnd := P; Inc(P); if P > PLen then begin Result := MATCH_PATTERN; Exit; end; if Pattern[P] = MATCH_CHAR_RANGE then begin Inc(P); RangeEnd := P; if (P > PLen) or (Pattern[RangeEnd] = MATCH_CHAR_RANGE_CLOSE) then begin Result := MATCH_PATTERN; Exit; end; Inc(P); end; if P > PLen then begin Result := MATCH_PATTERN; Exit; end; if RangeStart < RangeEnd then begin if (Text[T] >= Pattern[RangeStart]) and (Text[T] <= Pattern[RangeEnd]) then begin MemberMatch := True; Loop := False; end; end else begin if (Text[T] >= Pattern[RangeEnd]) and (Text[T] <= Pattern[RangeStart]) then begin MemberMatch := True; Loop := False; end; end; end; if (Invert and MemberMatch) or (not (Invert or MemberMatch)) then begin Result := MATCH_RANGE; Exit; end; if MemberMatch then while (P <= PLen) and (Pattern[P] <> MATCH_CHAR_RANGE_CLOSE) do Inc(P); if P > PLen then begin Result := MATCH_PATTERN; Exit; end; end; else if Pattern[P] <> MATCH_CHAR_SINGLE then if Pattern[P] <> Text[T] then Result := MATCH_LITERAL; end; Inc(P); Inc(T); end; if Result = 0 then if T <= TLen then Result := MATCH_END else Result := MATCH_VALID; end; function MatchAfterStar(Pattern, Text: string): Integer; var P, T, PLen, TLen: Integer; begin Result := 0; P := 1; T := 1; PLen := Length(Pattern); TLen := Length(Text); if (TLen = 1) and (PLen = 1) then //pattern like '*ring*' schould not match if Text 'A' begin Result := MATCH_VALID; Exit; end; if (PLen = 0) or (TLen = 0) then begin Result := MATCH_ABORT; Exit; end; while ((T <= TLen) and (P < PLen)) and ((Pattern[P] = MATCH_CHAR_SINGLE) or (Pattern[P] = MATCH_CHAR_KLEENE_CLOSURE)) do begin if Pattern[P] = MATCH_CHAR_SINGLE then Inc(T); Inc(P); end; if T >= TLen then begin Result := MATCH_ABORT; Exit; end; if P >= PLen then begin Result := MATCH_VALID; Exit; end; repeat if (Pattern[P] = Text[T]) or (Pattern[P] = MATCH_CHAR_RANGE_OPEN) then begin Pattern := Copy(Pattern, P, PLen); Text := Copy(Text, T, TLen); PLen := Length(Pattern); TLen := Length(Text); p := 1; t := 1; Result := Matche(Pattern, Text); if Result <> MATCH_VALID then Result := 0;//retry until end of Text, (check below) or Result valid end; Inc(T); if (T > TLen) or (P > PLen) then begin Result := MATCH_ABORT; Exit; end; until Result <> 0; end; (* function IsPattern(const Pattern: string): Boolean; var I: Integer; begin Result := False; for I := 1 to Length(Pattern) do if Pos(Pattern[I], '[]?*') > 0 then begin Result := True; Exit; end; end; *) end. ================================================ FILE: lib/zeosdbo/src/core/ZMessages.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Constant messages used by Zeos } { } { This unit contains all the messages that are output by } { ZEOS methods. One of the given language can be activated} { by setting the language in -> } { ZEOS.inc (e.g.: $DEFINE GERMAN). } { If no language is defined english will be used. } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZMessages; interface {$I ZCore.inc} procedure loadmessages(); resourcestring cSLibraryNotCompatible = 'Client-Library %s found but could not be loaded. Check compile-target and library compatibility!'; //--- added by Serge Girard -------------------------------------------------------- {$IFDEF FRENCH} cSSQLError1 = 'Erreur SQL: %s'; cSSQLError2 = 'Erreur SQL: %s Code: %d'; cSSQLError3 = 'Erreur SQL: %s Code: %d SQL: %s'; cSSQLError4 = 'Erreur SQL: %s Code: %d Message: %s'; cSListCapacityError = 'Capacit de liste hors limite (%d)'; cSListCountError = 'Compteur de liste (count) hors limite (%d)'; cSListIndexError = 'Index de liste hors limite (%d)'; cSClonningIsNotSupported = 'Le clonage n''est pas support pour cette classe'; cSImmutableOpIsNotAllowed = 'L''opration n''est pas permise sur des collections non modifiables'; cSStackIsEmpty = 'La pile est vide'; cSVariableWasNotFound = 'Variable "%s" non trouve'; cSFunctionWasNotFound = 'Fonction "%s" non trouve'; cSInternalError = 'Erreur interne'; cSSyntaxErrorNear = 'Erreur de syntaxe proche de "%s"'; cSSyntaxError = 'Erreur de syntaxe'; cSUnknownSymbol = 'Symbole inconnu "%s"'; cSUnexpectedExprEnd = 'Fin d''expression imprvue'; cSRightBraceExpected = ') attendue'; cSParametersError = '%d paramtres attendus mais %d ont t trouvs'; cSExpectedMoreParams = 'Plus de deux paramtres sont attendus'; cSInvalidVarByteArray = 'Tableau de VarByte non valide'; cSVariableAlreadyExists = 'La variable "%s" existe dj'; cSTypesMismatch = 'Types non concordants'; cSUnsupportedVariantType = 'Type variant non support'; cSUnsupportedOperation = 'Opration non supporte'; cSTokenizerIsNotDefined = 'l''objet Tokenizer n''est pas dfini'; cSLibraryNotFound = 'Acune des bibliothques dynamiques ne peut tre trouve ou charge: %s !'#10#13'Utilisez TZConnection.LibraryLocation si l''emplacement est incorrect.'; cSEncodeDateIsNotSupported = 'Cette version ne supporte pas isc_encode_sql_date'; cSEncodeTimeIsNotSupported = 'Cette version ne supporte pas isc_encode_sql_time'; cSEncodeTimestampIsNotSupported = 'Cette version ne supporte pas isc_encode_sql_timestamp'; cSDecodeDateIsNotSupported = 'Cette version ne supporte pas isc_decode_sql_date'; cSDecodeTimeIsNotSupported = 'Cette version ne supporte pas isc_decode_sql_time'; cSDecodeTimestampIsNotSupported = 'Cette version ne supporte pas isc_decode_sql_timestamp'; cSCanNotRetrieveResultSetData = 'Ne peut rcuprer l''ensemble de donnes rsultant'; cSRowBufferIsNotAssigned = 'Le buffer de ligne n''est pas assign'; cSColumnIsNotAccessable = 'Colonne d''index %d inaccessible'; cSConvertionIsNotPossible = 'Conversion impossible de la colonne %d de %s vers %s'; cSCanNotAccessBlobRecord = 'Ne peut accder au blob de la colonne %d avec le type %s'; cSRowDataIsNotAvailable = 'Ligne de donnes non disponible'; cSResolverIsNotSpecified = 'L''objet Resolver n''est pas indiqu'; cSResultsetIsAlreadyOpened = 'L''ensemble rsultat est dj ouvert'; cSCanNotUpdateEmptyRow = 'Ne peut mettre jour une ligne vide'; cSCanNotUpdateDeletedRow = 'Ne peut mettre jour une ligne supprime'; cSCanNotDeleteEmptyRow = 'Ne peut supprimer un ligne vide'; cSCannotUseCommit = 'Vous ne pouvez pas utiliser COMMIT en mode AUTOCOMMIT'; cSCannotUseRollBack = 'Vous ne pouvez pas utiliser ROLLBACK en mode AUTOCOMMIT'; cSCanNotUpdateComplexQuery = 'Ne peut mettre jour une requte complexe impliquant plus d''une table'; cSCanNotUpdateThisQueryType = 'Ne peut mettre jour ce type de requte'; cSDriverWasNotFound = 'Le driver de base de donnes demand n''a pas t trouv'; cSCanNotConnectToServer = 'Ne peut se connecter au serveur SQL'; cSTableIsNotSpecified = 'La table n''est pas spcifie'; cSLiveResultSetsAreNotSupported = 'Une requte actualisable n''est pas supporte par cette classe'; cSInvalidInputParameterCount = 'Le nombre de paramtres attendu est infrieur au prvu'; cSIsolationIsNotSupported = 'Niveau d''isolation de transaction non support'; cSColumnWasNotFound = 'Colonne de nom "%s" non trouve'; cSWrongTypeForBlobParameter = 'Type incorrect pour le paramtre Blob'; cSIncorrectConnectionURL = 'Connexion URL: %s incorrect'; cSUnsupportedProtocol = 'Protocole: %s non support'; cSUnsupportedByDriver = 'Le driver d''origine ne supporte pas cette fonctionnalit: [%s]'; cSConnectionIsNotOpened = 'Connexion non encore ouverte'; cSInvalidOpInAutoCommit = 'Opration non valide en mode AutoCommit'; cSInvalidOpInNonAutoCommit = 'Opration non valide si le mode n''est pas AutoCommit'; cSInvalidOpPrepare = 'Prparer une transaction n''est possible qu''en en dmarrant une (Starttransaction) d''abord (!)'; cSConnectionIsNotAssigned = 'La connexion la base donnes n''est pas indiqu'; cSQueryIsEmpty = 'La requte SQL est vide'; cSCanNotExecuteMoreQueries = 'Ne peut excuter plus d''une requte'; cSOperationIsNotAllowed1 = 'Cette opration n''est pas permise en mode FORWARD ONLY'; cSOperationIsNotAllowed2 = 'Cette opration n''est pas permise en mode READ ONLY'; cSOperationIsNotAllowed3 = 'Cette opration n''est pas permise en mode %s'; cSOperationIsNotAllowed4 = 'Cette opration n''est pas permise en mode sur un ensemble de donnes ferm'; cSNoMoreRecords = 'Plus d''enregistrements dans l''ensemble de donnes'; cSCanNotOpenResultSet = 'Ne peut ouvrir un ensemble de donnes'; cSCanNotOpenDataSetWhenDestroying ='Ne peut ouvrir un ensemble de donnes alors que l''tat du composant est dsDestroying'; cSCircularLink = 'Lien circulaire cr par le Datasource'; cSBookmarkWasNotFound = 'Le marque page (Bookmark) n''a pas t trouv'; cSIncorrectSearchFieldsNumber = 'Nombre incorrect de valeurs de recherche'; cSInvalidOperationInTrans = 'Opration invalide dans un mode de transaction explicite'; cSIncorrectSymbol = 'Symbole incorrect dans la liste des champs "%s".'; cSIncorrectToken = 'Token incorrect suivi par ":"'; cSIncorrectParamChar = 'Valeur non valide pour ParamChar'; cSSelectedTransactionIsolation = 'Le niveau d''isolation de transaction slectionn n''est pas support'; cSDriverNotSupported = 'Driver non support %s'; cSPattern2Long = 'Le Pattern est trop long'; cSDriverNotCapableOutParameters = 'Le Driver n''est pas capable d''utiliser des paramtres'; cSStatementIsNotAllowed = 'Dclaration non permise'; cSStoredProcIsNotAllowed = 'La procdure stocke n''est pas permise'; cSCannotPerformOperation = 'Ne peut effectuer cette opration sur une ensemble de donnes ferm'; cSInvalidState = 'tat non valide'; cSErrorConvertion = 'Erreur de conversion'; cSDataTypeDoesNotSupported = 'Type de donne non support'; cSUnsupportedParameterType = 'Type de paramtre non support'; cSUnsupportedDataType = 'Type de donne non support'; cSErrorConvertionField = 'Erreur de conversion pour le champ "%s" vers le type SQL "%s"'; cSBadOCI = 'Mauvaise version OCI [%s] . Version 8.0.3 ou plus ancienne requise'; cSConnect2AsUser = 'Connexion "%s" en tant qu''utilisateur "%s"'; cSUnknownError = 'Erreur inconnue'; cSFieldNotFound1 = 'Champ "%s" non trouv'; cSFieldNotFound2 = 'Champ %d non trouv'; cSLoginPromptFailure = 'Ne peut trouver le dialogue d''identification par dfaut. Ajoutez ,S.V.P. DBLogDlg dans la section uses section de votre fichier principal.'; cSPropertyQuery = 'La requte peut prendre un certain temps sur des bases de donnes importantes!'; cSPropertyTables = 'Vous devriez la limiter via Catalogue et/ou Schma.'; cSPropertyColumns = 'Vous devriez la limiter via Catalogue, Schma et/ou Nom de Table.'; cSPropertyProcedures = 'Vous devriez la limiter via Catalogue et/ou Schema.'; cSPropertySequences = 'Vous devriez la limiter via Catalogue et/ou Schema.'; cSPropertyExecute = 'La Requte doit-elle s''excuter quand mme?'; cSFormTest = 'diteur SQL ZEOS Test'; cSButtonClose = '&Fermer'; cSFormEditor = 'diteur SQL ZEOS'; cSTabSheetSelect = 'Select SQL'; cSMenuLoad = 'Charger'; cSMenuSave = 'Sauver'; cSButtonGenerate = '&Gnrer'; cSButtonCheck = '&Vrifier'; cSButtonTest = '&Tester'; cSButtonOk = '&OK'; cSButtonCancel = 'A&nnuler'; cSTableAlias = 'T&able alias'; cSReplaceSQL = '&Remplacer le SQL'; cSDialogOpenTitle = 'Ouvrir fichier SQL'; cSDialogSaveTitle = 'Sauver dans un fichier SQL'; cSSQLEditor = 'diteur SQL'; cSDatabaseDialog = 'Ouvrir base existante'; cSUpdateSQLNoResult = '"Update Refresh SQL" ne fourni aucun ensemble de rsultat'; cSUpdateSQLRefreshStatementcount ='La dclaration de l''"Update Refresh SQL" ne peut tre qu''unique'; {$IFDEF FPC} cSNotEditing = 'L''ensemble de donnes n''est ni en modification ni en insertion'; cSFieldTypeMismatch = 'Diffrence de type pour le champ ''%s'', attendu: %s trouv: %s'; cSFieldSizeMismatch = 'Diffrence de taille pour le champ ''%s'', attendue: %d trouve: %d'; {$ENDIF} cSNeedField = 'Le champ %s est requis, mais non renseign.'; cSFailedtoInitPrepStmt = 'La dclaration a choue l''initialisation'; cSFailedtoPrepareStmt = 'La dclaration a choue durant le processus de prparation'; cSFailedToBindAllValues = 'L''application a chou pr-relier toutes les valeurs'; cSAttemptExecOnBadPrep = 'Tentative d''excuter une dclaration avant une prparation russie.'; cSBindingFailure = 'chec relier l''ensemble des paramtres'; cSPreparedStmtExecFailure = 'La prparation de la dclaration a chou'; cSBoundVarStrIndexMissing = 'Nom de la variable de relation "%s" inexistant'; cSBindVarOutOfRange = 'Index de la variable de relation hors limite: %d'; cSFailedToBindResults = 'L''application a chou lier l''ensemble rsultat'; //FOS+ 07112006 cSRefreshRowOnlySupportedWithUpdateObject = 'La mthode "refreshrow" n''est permise qu''avec un objet de mise jour(Update)'; cSMustBeInBrowseMode = 'Opration uniquement permise dans l''tat dsBROWSE'; cSUnKnownParamDataType = 'Param.DataType inconnu'; cSFieldReadOnly = ' A un champ en lecture seule on ne peut assigner une valeur : %s'; cSInvalidUpdateCount = '%d enregistrement(s) mis jour. Un seul urait du l''tre.'; cSRowBufferWidthExceeded ='La taille du buffer de lignes a t dpasse. Essayez d''utiliser moins ou de plus longues colonnes dans la requte SQL.'; //--- end added by Serge Girard ------------------------------------ {$ELSE !FRENCH} // -> ms, 09/05/2005 {$IFDEF PORTUGUESE} cSSQLError1 = 'Erro SQL: %s'; cSSQLError2 = 'Erro SQL: %s Cdigo: %d'; cSSQLError3 = 'Erro SQL: %s Cdigo: %d SQL: %s'; cSSQLError4 = 'Erro SQL: %s Cdigo: %d Mensagem: %s'; cSListCapacityError = 'Capacidade da Lista fora do limite (%d)'; cSListCountError = 'Contagem da Lista fora do limite (%d)'; cSListIndexError = 'ndice da Lista fora do limite (%d)'; cSClonningIsNotSupported = 'Clonagem no suportada por esta classe'; cSImmutableOpIsNotAllowed = 'A operao no permitida para coleo imutvel'; cSStackIsEmpty = 'Pilha est vazia'; cSVariableWasNotFound = 'Varivel "%s" no foi encontrada'; cSFunctionWasNotFound = 'Function "%s" no foi encontrada'; cSInternalError = 'Erro interno'; cSSyntaxErrorNear = 'Erro de sintaxe prximo a "%s"'; cSSyntaxError = 'Erro de sintaxe'; cSUnknownSymbol = 'Smbolo desconhecido "%s"'; cSUnexpectedExprEnd = 'Final inesperado de expresso'; cSRightBraceExpected = ') esperado'; cSParametersError = 'Esperado %d parmetros mas foi encontrado %d'; cSExpectedMoreParams = 'Esperado mais que 2 parmetros'; cSInvalidVarByteArray = 'VarByte array invlido'; cSVariableAlreadyExists = 'Varivel "%s" j existe'; cSTypesMismatch = 'Tipos no combinam'; cSUnsupportedVariantType = 'Tipo variante no suportado'; cSUnsupportedOperation = 'Operao no suportada'; cSTokenizerIsNotDefined = 'Sinalizador no definido'; cSLibraryNotFound = 'Nenhuma biblioteca dinmica da lista %s foi encontrada'; cSEncodeDateIsNotSupported = 'Esta verso no suporta isc_encode_sql_date'; cSEncodeTimeIsNotSupported = 'Esta verso no suporta supported isc_encode_sql_time'; cSEncodeTimestampIsNotSupported = 'Esta verso no suporta supported isc_encode_sql_timestamp'; cSDecodeDateIsNotSupported = 'Esta verso no suporta isc_decode_sql_date'; cSDecodeTimeIsNotSupported = 'Esta verso no suporta isc_decode_sql_time'; cSDecodeTimestampIsNotSupported = 'Esta verso no suporta isc_decode_sql_timestamp'; cSCanNotRetrieveResultSetData = 'No foi possvel obter os dados do ResultSet'; cSRowBufferIsNotAssigned = 'Buffer da Linha no atribudo'; cSColumnIsNotAccessable = 'Coluna com ndice %d no acessvel'; cSConvertionIsNotPossible = 'A converso da coluna %d de %s para %s no possvel'; cSCanNotAccessBlobRecord = 'No possvel acessar um registro BLOB na coluna %d com o tipo %s'; cSRowDataIsNotAvailable = 'Dados na Linha no disponveis'; cSResolverIsNotSpecified = 'Resolver no foi especificado para este ResultSet'; cSResultsetIsAlreadyOpened = 'ResultSet j est aberto'; cSCanNotUpdateEmptyRow = 'No possvel atualizar uma linha vazia'; cSCanNotUpdateDeletedRow = 'No possvel atualizar uma linha apagada'; cSCanNotDeleteEmptyRow = 'No possvel apagar uma linha vazia'; cSCannotUseCommit = 'Voc no pode usar Commit no modo AutoCommit'; cSCannotUseRollBack = 'Voc no pode usar Rollback no modo AutoCommit'; cSCanNotUpdateComplexQuery = 'No possvel atualizar uma query complexa com mais de uma tabela'; cSCanNotUpdateThisQueryType = 'No possvel atualizar este tipo de query'; cSDriverWasNotFound = 'O driver de banco de dados requisitado no foi encontrado'; cSCanNotConnectToServer = 'No foi possvel conectar ao servidor SQL'; cSTableIsNotSpecified = 'Tabela no especificada'; cSLiveResultSetsAreNotSupported = 'Live query no suportado por esta classe'; cSInvalidInputParameterCount = 'A contagem do parmetro de entrada menor que o esperado'; cSIsolationIsNotSupported = 'O nvel de isolamento da Transao no suportado'; cSColumnWasNotFound = 'Coluna com o nome "%s" no foi encontrada'; cSWrongTypeForBlobParameter = 'Tipo errado para parmetro Blob'; cSIncorrectConnectionURL = 'Conexo incorreta URL: %s'; cSUnsupportedProtocol = 'Protocolo no suportado: %s'; cSUnsupportedByDriver = 'O Driver no suporta este recurso nativamente: [%s]'; cSConnectionIsNotOpened = 'Conexo ainda no est aberta.'; cSInvalidOpInAutoCommit = 'Operao invlida no modo AutoCommit.'; cSInvalidOpInNonAutoCommit = 'Operao invlida quando o modo AutoCommit False.'; cSInvalidOpPrepare = 'Prepare transaction somente possvel aps comandar StartTransaction'; cSConnectionIsNotAssigned = 'Componente de conexo de banco de dados no atribudo'; cSQueryIsEmpty = 'A consulta SQL est vazia'; cSCanNotExecuteMoreQueries = 'No possvel executar mais que uma query'; cSOperationIsNotAllowed1 = 'Operao no permitida no modo FORWARD ONLY'; cSOperationIsNotAllowed2 = 'Operao no permitida no modo READ ONLY'; cSOperationIsNotAllowed3 = 'Operao no permitida no modo %s'; cSOperationIsNotAllowed4 = 'Operao no permitida para DataSet fechado'; cSNoMoreRecords = 'Nenhum registro no ResultSet'; cSCanNotOpenResultSet = 'No foi possvel abrir o ResultSet'; cSCanNotOpenDataSetWhenDestroying ='Translate : Cannot open a dataset when the componentstate is dsDestroying'; cSCircularLink = 'DataSource possui um link circular'; cSBookmarkWasNotFound = 'Bookmark no foi encontrado'; cSIncorrectSearchFieldsNumber = 'Nmero incorreto de valores de campos de procura'; cSInvalidOperationInTrans = 'Operao invlida no modo de transao explcita'; cSIncorrectSymbol = 'Smbolo incorreto na lista de campos "%s".'; cSIncorrectToken = 'Sinal incorreto seguido por ":"'; cSIncorrectParamChar = 'TRANSLATE : Invalid value for ParamChar'; cSSelectedTransactionIsolation = 'O nvel selecionado do isolamento da transao no suportado'; cSDriverNotSupported = 'Driver no suportado %s'; cSPattern2Long = 'Padro muito longo'; cSDriverNotCapableOutParameters = 'O Driver no suporta a passagem de parmetros'; cSStatementIsNotAllowed = 'Declarao no permitida'; cSStoredProcIsNotAllowed = 'A stored procedure no permitida'; cSCannotPerformOperation = 'No possvel executar a operao num ResultSet fechado'; cSInvalidState = 'Estado invlido'; cSErrorConvertion = 'Erro de converso'; cSDataTypeDoesNotSupported = 'Tipo de dado no suportado'; cSUnsupportedParameterType = 'Tipo de parmetro no suportado'; cSUnsupportedDataType = 'Tipo de dado no suportado'; cSErrorConvertionField = 'Erro de converso para do campo "%s" para SQLType "%s"'; cSBadOCI = 'Verso de OCI incompatvel [% s]. Requer 8.0.3 ou mais antigo'; cSConnect2AsUser = 'Conecte "% s" como usurio "% s"'; cSUnknownError = 'Erro desconhecido'; cSFieldNotFound1 = 'Campo "%s" no foi encontrado'; cSFieldNotFound2 = 'Campo %d no foi encontrado'; cSLoginPromptFailure = 'No foi possvel encontrar o dilogo padro de login. Por favor adicione DBLogDlg para a seo uses de seu arquivo principal.'; cSPropertyQuery = 'A Query poder demorar em bancos de dados grandes!'; cSPropertyTables = 'Voc deveria limitar por Catalogo e/ou Esquema.'; cSPropertyColumns = 'Voc deveria limitar por Catalogo, Esquema e/ou Tabela.'; cSPropertyProcedures = 'Voc deveria limitar por Catalogo e/ou Esquema.'; cSPropertySequences = 'Voc deveria limitar por Catalogo e/ou Esquema..'; cSPropertyExecute = 'Executar a Query de qualquer maneira?'; cSFormTest = 'Teste Editor ZEOS SQL'; cSButtonClose = '&Fechar'; cSFormEditor = 'Editor ZEOS SQL'; cSTabSheetSelect = 'SQL Select'; cSMenuLoad = 'Carregar'; cSMenuSave = 'Salvar'; cSButtonGenerate = '&Gerar'; cSButtonCheck = '&Verificar'; cSButtonTest = '&Testar'; cSButtonOk = '&OK'; cSButtonCancel = '&Cancelar'; cSTableAlias = '&Alias Tabela'; cSReplaceSQL = '&Substituir SQL'; cSDialogOpenTitle = 'Abrir Arquivo SQL'; cSDialogSaveTitle = 'Salvar Arquivo SQL'; cSSQLEditor = 'Editor SQL'; cSDatabaseDialog = 'Abrir Banco de Dados existente'; cSUpdateSQLNoResult = 'SQL Update Refresh resultou num conjunto vazio'; cSUpdateSQLRefreshStatementcount ='Usar somente 1 declarao SQL para Update Refresh'; {$IFDEF FPC} cSNotEditing = 'Dataset no est em modo de edio ou insero'; cSFieldTypeMismatch = 'Tipo invlido para o campo ''%s'', esperado: %s atual: %s'; cSFieldSizeMismatch = 'Tamanho Invlido para o campo ''%s'', esperado: %d atual: %d'; {$ENDIF} cSNeedField = 'O campo %s obrigatrio, mas no foi preenchido.'; cSFailedtoInitPrepStmt = 'A declarao preparada falhou ao inicializar'; cSFailedtoPrepareStmt = 'A declarao falhou durante o processo de preparo'; cSFailedToBindAllValues = 'A Aplicao falhou na traduo de todos os valores'; cSAttemptExecOnBadPrep = 'Tentativa de executar uma declarao que no foi corretamente preparada'; cSBindingFailure = 'Falha ao traduzir o conjunto de parmetros'; cSPreparedStmtExecFailure = 'A declarao preparada falhou ao executar'; cSBoundVarStrIndexMissing = 'ndice de texto "%s" da varivel de limite no existe'; cSBindVarOutOfRange = 'ndice da varivel de limite fora de alcance: %d'; cSFailedToBindResults = 'A Aplicao falhou ao tratar o result set'; cSRefreshRowOnlySupportedWithUpdateObject = 'O mtodo RefreshRow somente suportado com um update object'; cSMustBeInBrowseMode = 'A Operao permitida somente no modo dsBrowse'; cSUnKnownParamDataType = 'Param.DataType de tipo desconhecido'; cSFieldReadOnly = 'O campo %d somente leitura e no pde receber dados'; cSInvalidUpdateCount = '%d registro(s) atualizados. Apenas um registro deveria ter sido atualizado.'; cSRowBufferWidthExceeded ='O tamanho do buffer para linhas (Rows) foi excedido. Tente usar menos ou mais colunas na query SQL'; {$ELSE} {$IFDEF DUTCH} cSSQLError1 = 'SQL Fout: %s'; cSSQLError2 = 'SQL Fout: %s Code: %d'; cSSQLError3 = 'SQL Fout: %s Code: %d SQL: %s'; cSSQLError4 = 'SQL Fout: %s Code: %d Bericht: %s'; cSListCapacityError = 'Lijst capaciteit buiten bereik (%d)'; cSListCountError = 'Lijst aantal buiten bereik (%d)'; cSListIndexError = 'Lijst index buiten bereik (%d)'; cSClonningIsNotSupported = 'Kloonen worden niet ondersteund in deze klasse'; cSImmutableOpIsNotAllowed = 'Deze operatie is niet ondersteund voor immutable collection'; cSStackIsEmpty = 'Stack is leeg'; cSVariableWasNotFound = 'Variabele "%s" niet gevonden'; cSFunctionWasNotFound = 'Functie "%s" niet gevonden'; cSInternalError = 'Interne fout'; cSSyntaxErrorNear = 'Syntaxis fout bij "%s"'; cSSyntaxError = 'Syntaxis fout'; cSUnknownSymbol = 'Onbekend symbool "%s"'; cSUnexpectedExprEnd = 'Onverwacht einde van de expressie'; cSRightBraceExpected = ') verwacht'; cSParametersError = 'Verwacht worden %d parameters maar er zijn er %d gevonden'; cSExpectedMoreParams = 'Meer dan 2 parameters werden verwacht'; cSInvalidVarByteArray = 'Ongeldig VarByte array'; cSVariableAlreadyExists = 'Variabele "%s" bestaat al'; cSTypesMismatch = 'Types komen niet overeen'; cSUnsupportedVariantType = 'Niet ondersteund variant type'; cSUnsupportedOperation = 'Niet ondersteunde operatie'; cSTokenizerIsNotDefined = 'Tokenizer is niet gedefinieerd'; cSLibraryNotFound = 'DLL van de lijst %s werd niet gevonden'; cSEncodeDateIsNotSupported = 'Deze versie ondersteunt isc_encode_sql_date niet'; cSEncodeTimeIsNotSupported = 'Deze versie ondersteunt isc_encode_sql_time niet'; cSEncodeTimestampIsNotSupported = 'Deze versie ondersteunt isc_encode_sql_timestamp niet'; cSDecodeDateIsNotSupported = 'Deze versie ondersteunt isc_decode_sql_date niet'; cSDecodeTimeIsNotSupported = 'Deze versie ondersteunt isc_decode_sql_time niet'; cSDecodeTimestampIsNotSupported = 'Deze versie ondersteunt isc_decode_sql_timestamp niet'; cSCanNotRetrieveResultSetData = 'Kan ResultSet data niet ophalen'; cSRowBufferIsNotAssigned = 'Row buffer is niet toegekend'; cSColumnIsNotAccessable = 'Kolom met index %d is niet bereikbaar'; cSConvertionIsNotPossible = 'Conversie is niet mogelijk voor kolom %d van %s tot %s'; cSCanNotAccessBlobRecord = 'Kan het blob record in kolom %d met type %s niet benaderen'; cSRowDataIsNotAvailable = 'Rij data is niet beschikbaar'; cSResolverIsNotSpecified = 'Resolver is niet gespecificeerd voor deze ResultSet'; cSResultsetIsAlreadyOpened = 'ResultSet is al geopend'; cSCanNotUpdateEmptyRow = 'Kan een lege rij niet updaten'; cSCanNotUpdateDeletedRow = 'Kan een verwijderde rij niet updaten'; cSCanNotDeleteEmptyRow = 'Kan een lege rij niet verwijderen'; cSCannotUseCommit = 'Commit in autocommit mode is niet mogelijk'; cSCannotUseRollBack = 'Rollback in autocommit mode is niet mogelijk'; cSCanNotUpdateComplexQuery = 'Kan een complexe query met meerdere tabellen niet updaten'; cSCanNotUpdateThisQueryType = 'Kan dit query type niet updaten'; cSDriverWasNotFound = 'Gevraagde database driver is niet gevonden'; cSCanNotConnectToServer = 'Kan geen verbinding maken met de SQL server'; cSTableIsNotSpecified = 'Tabel is niet gespecifieerd'; cSLiveResultSetsAreNotSupported = 'Live query is niet ondersteund door deze klasse'; cSInvalidInputParameterCount = 'Input parameter aantal is lager dan verwacht'; cSIsolationIsNotSupported = 'Transactie isolatie niveau wordt niet ondersteund'; cSColumnWasNotFound = 'Kolom met naam "%s" bestaat niet'; cSWrongTypeForBlobParameter = 'Verkeerde type voor Blob parameter'; cSIncorrectConnectionURL = 'Ongeldige connectie URL: %s'; cSUnsupportedProtocol = 'Niet ondersteund protocol: %s'; cSUnsupportedByDriver = 'De driver ondersteunt deze functie niet: [%s]'; cSConnectionIsNotOpened = 'Verbinding is niet gemaakt.'; cSInvalidOpInAutoCommit = 'Ongeldige operatie in AutoCommit mode.'; cSInvalidOpInNonAutoCommit = 'Ongeldige operatie in non AutoCommit mode.'; cSInvalidOpPrepare = 'Transactie voorbereiden is enkel mogelijk bij de eerste aanroep van Starttransaction!'; cSConnectionIsNotAssigned = 'Database connectie component is niet toegekend'; cSQueryIsEmpty = 'SQL Query is leeg'; cSCanNotExecuteMoreQueries = 'Kan niet meerdere queries uitvoeren'; cSOperationIsNotAllowed1 = 'Bewerking is niet toegestaan in FORWARD ONLY mode'; cSOperationIsNotAllowed2 = 'Bewerking is niet toegestaan in READ ONLY mode'; cSOperationIsNotAllowed3 = 'Bewerking is niet toegestaan in %s mode'; cSOperationIsNotAllowed4 = 'Bewerking is niet toegestaan voor gesloten dataset'; cSNoMoreRecords = 'Geen records meer aanwezig in ResultSet'; cSCanNotOpenResultSet = 'Kan een ResultSet niet openen'; cSCanNotOpenDataSetWhenDestroying ='Kan een Dataset niet openen wanneer de componentstate=dsDestroying'; cSCircularLink = 'Databron maakt een oneindige verbindingslus'; cSBookmarkWasNotFound = 'Bookmark niet gevonden'; cSIncorrectSearchFieldsNumber = 'Incorrect aantal zoekvelden'; cSInvalidOperationInTrans = 'Ongeldige operatie in explicit transaction mode'; cSIncorrectSymbol = 'Ongeldig symbool in veld lijst "%s".'; cSIncorrectToken = 'Ongeldig teken gevolgd door ":"'; cSIncorrectParamChar = 'TRANSLATE : Invalid value for ParamChar'; cSSelectedTransactionIsolation = 'Geselecteerd transactie isolatie niveau niet ondersteund'; cSDriverNotSupported = 'Driver niet ondersteund %s'; cSPattern2Long = 'Patroon is te lang'; cSDriverNotCapableOutParameters = 'Driver ondersteunt geen out parameters'; cSStatementIsNotAllowed = 'Statement is niet toegestaan'; cSStoredProcIsNotAllowed = 'Stored procedures zijn niet toegestaan'; cSCannotPerformOperation = 'Kan operatie niet uitvoeren op een gesloten ResultSet'; cSInvalidState = 'Ongeldige status'; cSErrorConvertion = 'Conversiefout'; cSDataTypeDoesNotSupported = 'Data type is niet onderstuend'; cSUnsupportedParameterType = 'Niet ondersteund parameter type'; cSUnsupportedDataType = 'Niet ondersteund data type'; cSErrorConvertionField = 'Conversie fout voor veld "%s" naar SQLType "%s"'; cSBadOCI = 'Ongeschikte OCI version [%s]. Vereist is 8.0.3 of nieuwer'; cSConnect2AsUser = 'Verbinden met "%s" als gebruiker "%s"'; cSUnknownError = 'Onbekende fout'; cSFieldNotFound1 = 'Veld "%s" niet gevonden'; cSFieldNotFound2 = 'Veld %d niet gevonden'; cSLoginPromptFailure = 'Kan de standaard login prompt niet vinden. Voeg DBLogDlg toe aan de uses sectie.'; cSPropertyQuery = 'De Query kan enige tijd duren bij grote databases!'; cSPropertyTables = 'Limiet op Catalog en/of Schema is vereist.'; cSPropertyColumns = 'Limiet op Catalog, Schema en/of tablenaam is vereist.'; cSPropertyProcedures = 'Limiet op Catalog en/of Schema is vereist.'; cSPropertySequences = 'Limiet op Catalog en/of Schema is vereist.'; cSPropertyExecute = 'Dient de Query toch te worden uitgevoerd?'; cSFormTest = 'ZEOS SQL Editor Test'; cSButtonClose = '&Sluiten'; cSFormEditor = 'ZEOS SQL Editor'; cSTabSheetSelect = 'Select SQL'; cSMenuLoad = 'Laden'; cSMenuSave = 'Opslaan'; cSButtonGenerate = '&Genereren'; cSButtonCheck = 'C&heck'; cSButtonTest = '&Test'; cSButtonOk = '&OK'; cSButtonCancel = '&Annuleren'; cSTableAlias = 'Tabel al&ias'; cSReplaceSQL = '&Vervang SQL'; cSDialogOpenTitle = 'SQL Bestand Openen'; cSDialogSaveTitle = 'SQL Bestand Opslaan'; cSSQLEditor = 'SQL Editor'; cSDatabaseDialog = 'Open bestaande database'; cSUpdateSQLNoResult = 'Der zuvor aktualisierte SQL liefert kein Resultset zurck'; cSUpdateSQLRefreshStatementcount ='Update Refresh SQL Statement count moet 1 zijn'; {$IFDEF FPC} cSNotEditing = 'Dataset is niet in edit of insert modus'; cSFieldTypeMismatch = 'Type mismatch voor veld ''%s'', verwacht: %s actueel: %s'; cSFieldSizeMismatch = 'Size mismatch voor veld ''%s'', verwacht: %d actueel: %d'; {$ENDIF} cSNeedField = 'Veld %s is verplicht, maar niet ingevuld.'; cSFailedtoInitPrepStmt = 'Initialisatie van Prepared statement mislukt'; cSFailedtoPrepareStmt = 'Statement mislukt tijdens prepare'; cSFailedToBindAllValues = 'Pre-bind van alle waarden is mislukt'; cSAttemptExecOnBadPrep = 'Poging om een statement uit te voeren voor een succesvolle prepare'; cSBindingFailure = 'Binding van parameterset mislukt'; cSPreparedStmtExecFailure = 'Uitvoeren van Prepared statement mislukt'; cSBoundVarStrIndexMissing = 'Tekst index van bound variable bestaat niet: "%s"'; cSBindVarOutOfRange = 'Bound variable index buiten bereik: %d'; cSFailedToBindResults = 'Binding van resultaat mislukt'; cSRefreshRowOnlySupportedWithUpdateObject = 'De refreshrow methode is enkel ondersteund vooreen update object'; cSMustBeInBrowseMode = 'Bewerking is enkel toegestaan in dsBROWSE status'; cSUnKnownParamDataType = 'Param.DataType is onbekend'; cSFieldReadOnly = 'Readonly veld kan geen waarde toegewezen krijgen: %d'; cSInvalidUpdateCount = '%d record(s) gewijzigd. Slechts 1 record had gewijzigd mogen zijn.'; cSRowBufferWidthExceeded ='Rij buffer grootte overschreden. Probeer minder kolommen te gebruiken in je SQL query.'; {$ELSE} // <- ms, 09/05/2005 // -> ms, 03/05/2005 {$IFDEF GERMAN} cSSQLError1 = 'SQL Fehler: %s'; cSSQLError2 = 'SQL Fehler: %s Code: %d'; cSSQLError3 = 'SQL Fehler: %s Code: %d SQL: %s'; cSSQLError4 = 'SQL Fehler: %s Code: %d Meldung: %s'; cSListCapacityError = 'Die Listenkapazitt bersteigt die definierte Grenze (%d)'; cSListCountError = 'Der Listenzhler ist auerhalb seiner definierten Grenzen (%d)'; cSListIndexError = 'Der Listenindex ist auerhalb der definierten Grenzen (%d)'; cSClonningIsNotSupported = 'Diese Klasse kann nicht geklont werden'; cSImmutableOpIsNotAllowed = 'Diese Operation ist bei nicht nderbaren Collections nicht erlaubt'; cSStackIsEmpty = 'Der Stack ist leer'; cSVariableWasNotFound = 'Die Variable "%s" wurde nicht gefunden'; cSFunctionWasNotFound = 'Die Funktion "%s" wurde nicht gefunden'; cSInternalError = 'Interner Fehler'; cSSyntaxErrorNear = 'Syntax Fehler bei "%s"'; cSSyntaxError = 'Syntax Fehler'; cSUnknownSymbol = 'Unbekanntes Symbol "%s"'; cSUnexpectedExprEnd = 'Unerwartetes Ende des Ausdrucks'; cSRightBraceExpected = ') erwartet'; cSParametersError = 'Es werden %d Parameter erwartet, aber nur %d Parameter gefunden'; cSExpectedMoreParams = 'Es werden mehr als zwei Parameter erwartet'; cSInvalidVarByteArray = 'Ungltiges VarByte Array'; cSVariableAlreadyExists = 'Die Variable "%s" existiert bereits'; cSTypesMismatch = 'Inkompatible Typen'; cSUnsupportedVariantType = 'Nicht untersttzter Variant-Typ'; cSUnsupportedOperation = 'Nicht untersttzte Operation'; cSUnsupportedByDriver = 'Der Treiber untersttzt dieses Feature nicht von haus aus: [%s]'; cSTokenizerIsNotDefined = 'Tokenizer wurde nicht definiert'; cSLibraryNotFound = 'Es wurde keine der in %s gelisteten DLL''s gefunden'; cSEncodeDateIsNotSupported = 'Diese Version untersttzt "isc_encode_sql_date" nicht'; cSEncodeTimeIsNotSupported = 'Diese Version untersttzt "isc_encode_sql_time" nicht'; cSEncodeTimestampIsNotSupported = 'Diese Version untersttzt "isc_encode_sql_timestamp" nicht'; cSDecodeDateIsNotSupported = 'Diese Version untersttzt "isc_decode_sql_date" nicht'; cSDecodeTimeIsNotSupported = 'Diese Version untersttzt "isc_decode_sql_time" nicht'; cSDecodeTimestampIsNotSupported = 'Diese Version untersttzt "isc_decode_sql_timestamp" nicht'; cSCanNotRetrieveResultSetData = 'Die Ergebnismenge kann nicht ermittelt werden'; cSRowBufferIsNotAssigned = 'Der Zeilen-Buffer ist nicht zugewiesen'; cSColumnIsNotAccessable = 'Auf die Spalte (Tabellenfeld) mit dem Index %d kann nicht zugegriffen werden'; cSConvertionIsNotPossible = 'Eine Konvertierung der Spalte (Tabellenfeld) %d von %s bis %s kann nicht durchgefhrt werden'; cSCanNotAccessBlobRecord = 'Auf den BLOB-Datensatz in Spalte (Tabellenfeld) %d vom Typ %s kann nicht zugegriffen werden'; cSRowDataIsNotAvailable = 'Die Zeilendaten (Datensatzdaten) sind nicht verfgbar'; cSResolverIsNotSpecified = 'Fr diese Ergebnismenge wurde kein sog. "Resolver" angegeben'; cSResultsetIsAlreadyOpened = 'Die Ergebnismenge ist bereits geffnet'; cSCanNotUpdateEmptyRow = 'Eine leere Datenzeile kann nicht aktualisiert werden'; cSCanNotUpdateDeletedRow = 'Eine gelschte Datenzeile kann nicht aktualisiert werden'; cSCanNotDeleteEmptyRow = 'Eine leere Datenzeile kann nicht gelscht werden'; cSCannotUseCommit = 'COMMIT kann im AUTOCOMMIT-Modus nicht verwendet werden'; cSCannotUseRollBack = 'ROLLBACK kann im AUTOCOMMIT-Modus nicht verwendet werden'; cSCanNotUpdateComplexQuery = 'Ein Query, dessen Ergebnismenge aus mehr als einer Tabelle stammt, kann nicht aktualisiert werden'; cSCanNotUpdateThisQueryType = 'Diese Art von Queries kann nicht aktualisiert werden'; cSDriverWasNotFound = 'Der angegebene Datenbanktreiber wurde nicht gefunden'; cSCanNotConnectToServer = 'Kann keine Verbindung zum SQL Server herstellen'; cSTableIsNotSpecified = 'Tabelle ist nicht spezifiziert'; cSLiveResultSetsAreNotSupported = 'Ein "Live Query" wird von dieser Klasse nicht untersttzt'; cSInvalidInputParameterCount = 'Es wurden weniger Eingabeparameter angegeben, als erwartet'; cSIsolationIsNotSupported = 'Der gewhlte Trasaktions-Isolationslevel wird nicht untersttzt'; cSColumnWasNotFound = 'Eine Tabellenspalte namens "%s" wurde nicht gefunden'; cSWrongTypeForBlobParameter = 'Falscher Typ fr einen BLOB-Parameter'; cSIncorrectConnectionURL = 'Falsche Verbindungs-URL: %s'; cSUnsupportedProtocol = 'Nicht untersttztes Protokoll: %s'; cSConnectionIsNotOpened = 'Die Verbindung zur Datenbank ist noch nicht hergestellt'; cSInvalidOpInAutoCommit = 'Ungltige Operation im AUTOCOMMIT-Modus'; cSInvalidOpInNonAutoCommit = 'Ungltige Operation auerhalb des AUTOCOMMIT-Modus'; cSInvalidOpPrepare = 'Transaktion vorzubereiten ist nur beim ersten Aufruf von Starttransaction mglich!'; cSConnectionIsNotAssigned = 'Die Datenbank-Verbindungskomponente ist nicht angegeben'; cSQueryIsEmpty = 'SQL Query leer'; cSCanNotExecuteMoreQueries = 'Mehr als ein Query kann nicht abgearbeitet werden'; cSOperationIsNotAllowed1 = 'Die Operation ist im FORWARD ONLY Modus nicht erlaubt'; cSOperationIsNotAllowed2 = 'Die Operation ist im READ ONLY Modus nicht erlaubt'; cSOperationIsNotAllowed3 = 'Die Operation ist im %s Modus nicht erlaubt'; cSOperationIsNotAllowed4 = 'Die Operation ist bei einem geschlossenen DataSet nicht erlaubt'; cSNoMoreRecords = 'Es gibt keine weiteren Datenstze in der Ergebnismenge'; cSCanNotOpenResultSet = 'Die Ergebnismenge kann nicht geffnet werden'; cSCanNotOpenDataSetWhenDestroying ='Translate : Cannot open a dataset when the componentstate is dsDestroying'; cSCircularLink = 'Die DataSource hat einen zirkulren Verweis'; cSBookmarkWasNotFound = 'Das Lesezeichen (Bookmark) wurde nicht gefunden'; cSIncorrectSearchFieldsNumber = 'Die Anzahl der Suchfeldwerte ist nicht korrekt'; cSInvalidOperationInTrans = 'Ungltige Operatio im Zustand einer expliziten Transaktion'; cSIncorrectSymbol = 'Falsches Symbol in der Feldliste "%s".'; cSIncorrectToken = 'Falsches Token gefolgt von ":"'; cSIncorrectParamChar = 'TRANSLATE : Invalid value for ParamChar'; cSSelectedTransactionIsolation = 'Der gewhlte Transaktions-Isolationslevel wird nicht untersttzt'; cSDriverNotSupported = 'Der Treiber wird nicht untersttzt: %s'; cSPattern2Long = 'Das Muster (Pattern) ist zu lang'; cSDriverNotCapableOutParameters = 'Der Treiber beherrscht keine Parameter'; cSStatementIsNotAllowed = 'Diese Anweisung ist nicht erlaubt'; cSStoredProcIsNotAllowed = 'Diese Stored Procedure ist nicht erlaubt'; cSCannotPerformOperation = 'Auf eine geschlossene Ergebnismenge knnen keine Operationen ausgefhrt werden'; cSInvalidState = 'Ungltiger Status'; cSErrorConvertion = 'Konvertierungsfehler'; cSDataTypeDoesNotSupported = 'Der Datentyp wird nicht untersttzt'; cSUnsupportedParameterType = 'Der Parametertyp wird nicht untersttzt'; cSUnsupportedDataType = 'Der Datentyp wird nicht untersttzt'; cSErrorConvertionField = 'Konvertierungsfehler bei Feld "%s" nach SQL-Typ "%s"'; cSBadOCI = 'Die OCI Version 8.0.3 (oder lter) wird bentigt! Aktuelle Version: %s'; cSConnect2AsUser = 'Verbinde zu "%s" als User "%s"'; cSUnknownError = 'Unbekannter Fehler'; cSFieldNotFound1 = 'Das Feld "%s" wurde nicht gefunden'; cSFieldNotFound2 = 'Das Feld %d wurde nicht gefunden'; cSLoginPromptFailure = 'Der Standard-Login-Dialog konnte nicht gefunden werden. Bitte DBLogDlg in die USES-Sektion der Haupt-Unit hinzufgen'; cSPropertyQuery = 'Die Abfrage kann bei groen Datenbanken eine Weile dauern!'; cSPropertyTables = 'Sie sollte durch die Angabe von Catalog und/oder Schema eingeschrnkt werden.'; cSPropertyColumns = 'Sie sollte durch die Angabe von Catalog, Schema und/oder Tabellenname eingeschrnkt werden.'; cSPropertyProcedures = 'Sie sollte durch die Angabe von Catalog und/oder Schema eingeschrnkt werden.'; cSPropertySequences = 'Sie sollte durch die Angabe von Catalog und/oder Schema eingeschrnkt werden.'; cSPropertyExecute = 'Soll die Abfrage trotzdem ausgefhrt werden?'; cSFormTest = 'ZEOS SQL Editor Test'; cSButtonClose = '&Schlieen'; cSFormEditor = 'ZEOS SQL Editor'; cSTabSheetSelect = 'SQL aus&whlen'; cSMenuLoad = 'ffnen'; cSMenuSave = 'Speichern'; cSButtonGenerate = '&Generieren'; cSButtonCheck = 'Syntax &Prfen'; cSButtonTest = 'Befehl &Testen'; cSButtonOk = '&OK'; cSButtonCancel = '&Abbruch'; cSTableAlias = 'Tabllen-Alias'; cSReplaceSQL = 'SQL &ersetzen'; cSDialogOpenTitle = 'SQL Script ffnen'; cSDialogSaveTitle = 'SQL Script speichern'; cSSQLEditor = 'SQL Editor'; cSDatabaseDialog = 'Existierende Datenbank ffnen'; cSUpdateSQLNoResult = 'Translate : Update Refresh SQL delivered no resultset'; cSUpdateSQLRefreshStatementcount ='Translate : Update Refresh SQL Statement count must be 1'; {$IFDEF FPC} cSNotEditing = 'Das DataSet ist nicht im "edit" oder "insert" Modus.'; cSFieldTypeMismatch = 'Der Typ fr Feld ''%s'' stimmt nicht. Erwartet wird %s der Typ ist aber momentan %s'; cSFieldSizeMismatch = 'Die Gre des Feldes ''%s'' stimmt nicht. Erwartet wird %d die Gre ist aber momentan %d'; {$ENDIF} cSNeedField = 'Translate: Field %s is required, but not supplied.'; cSFailedtoInitPrepStmt = 'Translate: Prepared statement failed to initialize'; cSFailedtoPrepareStmt = 'Translate: Statement failed during prepare process'; cSFailedToBindAllValues = 'Translate: Application failed to pre-bind all values'; cSAttemptExecOnBadPrep = 'Translate: Attempt made to execute a statement before a successful preparation.'; cSBindingFailure = 'Translate: Failed to bind parameter set'; cSPreparedStmtExecFailure = 'Translate: Prepared statement failed to execute'; cSBoundVarStrIndexMissing = 'Translate: Bound variable text index "%s" does not exist'; cSBindVarOutOfRange = 'Translate: Bound variable index out of range: %d'; cSFailedToBindResults = 'Translate: Application failed to bind to the result set'; cSRefreshRowOnlySupportedWithUpdateObject = 'TRANSLATE: The refreshrow method is only supported with an update object'; cSMustBeInBrowseMode = 'TRANSLATE: Operation is only allowed in dsBROWSE state'; cSUnKnownParamDataType = 'TRANSLATE: Unknown Param.DataType'; cSFieldReadOnly = 'Translate : Readonly field can''t be assigned a value: %d'; cSInvalidUpdateCount = 'Translate : %d record(s) updated. Only one record should have been updated.'; cSRowBufferWidthExceeded ='Translate: Row buffer width exceeded. Try using fewer or longer columns in SQL query.'; {$ELSE} // -> fduenas, 28/06/2005 {$IFDEF SPANISH} //Spanish translations cSSQLError1 = 'Error SQL: %s'; cSSQLError2 = 'Error SQL: %s Cdigo: %d'; cSSQLError3 = 'Error SQL: %s Cdigo: %d SQL: %s'; cSSQLError4 = 'Error SQL: %s Cdigo: %d Mensage: %s'; cSListCapacityError = 'List capacity fuera de lmites (%d)'; cSListCountError = 'List count fuera de lmites (%d)'; cSListIndexError = 'List index fuera de lmites (%d)'; cSClonningIsNotSupported = 'La Clonacin no est soportada por esta clase'; cSImmutableOpIsNotAllowed = 'Operacin no permitida en colecciones no modificables'; cSStackIsEmpty = 'La Pila (Stack) est vaca'; cSVariableWasNotFound = 'Variable "%s" no encontrada'; cSFunctionWasNotFound = 'Funcin "%s" no encontrada'; cSInternalError = 'Error interno'; cSSyntaxErrorNear = 'Error de sintaxis cerca de "%s"'; cSSyntaxError = 'Error de sintaxis'; cSUnknownSymbol = 'Smbolo "%s" desconocido'; cSUnexpectedExprEnd = 'Fin de expresin inesperado'; cSRightBraceExpected = ') esperado'; cSParametersError = 'Se esperaban %d parmetros pero solo %d fueron encontrados'; cSExpectedMoreParams = 'Se esperaban ms de dos parmetros'; cSInvalidVarByteArray = 'Arreglo VarByte invlido'; cSVariableAlreadyExists = 'La variable "%s" ya existe'; cSTypesMismatch = 'Los Tipos no coinciden'; cSUnsupportedVariantType = 'Tipo de Variant no soportando'; cSUnsupportedOperation = 'Operacin no soportada'; cSTokenizerIsNotDefined = 'El objeto Tokenizer no est definido'; cSLibraryNotFound = 'Ninguna librera dinmica de la lista %s fue encontrada'; cSEncodeDateIsNotSupported = 'Esta versin no soporta isc_encode_sql_date'; cSEncodeTimeIsNotSupported = 'Esta versin no soporta isc_encode_sql_time'; cSEncodeTimestampIsNotSupported = 'Esta versin no soporta isc_encode_sql_timestamp'; cSDecodeDateIsNotSupported = 'Esta versin no soporta isc_decode_sql_date'; cSDecodeTimeIsNotSupported = 'Esta versin no soporta isc_decode_sql_time'; cSDecodeTimestampIsNotSupported = 'Esta versin no soporta isc_decode_sql_timestamp'; cSCanNotRetrieveResultSetData = 'No se pueden obtener datos del Resultset'; cSRowBufferIsNotAssigned = 'Buffer de lnea no asignado'; cSColumnIsNotAccessable = 'La columna con ndice %d no est accesible'; cSConvertionIsNotPossible = 'La conversin no es posible para la columna %d de %s a %s'; cSCanNotAccessBlobRecord = 'No se puede accesar al registro del blob en la columna %d con tipo %s'; cSRowDataIsNotAvailable = 'Datos de lnea no disponibles'; cSResolverIsNotSpecified = 'El objeto Resolver no est especificado para este ResultSet'; cSResultsetIsAlreadyOpened = 'El Resultset ya est abierto'; cSCanNotUpdateEmptyRow = 'No se puede actualizar una lnea vaca'; cSCanNotUpdateDeletedRow = 'No se puede actualizar una lnea borrada'; cSCanNotDeleteEmptyRow = 'No se puede borrar una lnea vaca'; cSCannotUseCommit = 'No se puede usar COMMIT en modo AUTOCOMMIT'; cSCannotUseRollBack = 'No se puede usar ROLLBACK en modo AUTOCOMMIT'; cSCanNotUpdateComplexQuery = 'No se puede actualizar una consulta compleja que haga referencia a ms de una tabla'; cSCanNotUpdateThisQueryType = 'No se puede actualizar este tipo de consulta'; cSDriverWasNotFound = 'No se encontr el controlador de base de datos solicitado'; cSCanNotConnectToServer = 'No puede conectarse al servidor SQL'; cSTableIsNotSpecified = 'La Tabla no est especificada'; cSLiveResultSetsAreNotSupported = 'La consulta actualizable no es soportada por esta clase'; cSInvalidInputParameterCount = 'El nmero de parmetros de tipo Input es menor al esperado'; cSIsolationIsNotSupported = 'Nivel de aislamiento de transaccin no soportado'; cSColumnWasNotFound = 'Columna con nombre "%s" no encontrada'; cSWrongTypeForBlobParameter = 'Tipo incorrecto para el parmetro Blob'; cSIncorrectConnectionURL = 'URL de conexin incorrecta: %s'; cSUnsupportedProtocol = 'Protocolo no soportado: %s'; cSUnsupportedByDriver = 'Translate: Driver can not support this feature natively: [%s]'; cSConnectionIsNotOpened = 'La conexin no ha sido abierta todava'; cSInvalidOpInAutoCommit = 'Operacin invlida en modo AutoCommit'; cSInvalidOpInNonAutoCommit = 'Operacin invlida en modo No-AutoCommit'; cSInvalidOpPrepare = 'Translate : Prepare transaction only possible on matching first(!) Starttransaction'; cSConnectionIsNotAssigned = 'El componente de conexin a base de datos no est asigando'; cSQueryIsEmpty = 'La Consulta SQL est vaca'; cSCanNotExecuteMoreQueries = 'No se puede ejecutar ms de una consulta'; cSOperationIsNotAllowed1 = 'Operacin no permitida en modo FORWARD ONLY'; cSOperationIsNotAllowed2 = 'Operacin no permitida en modo READ ONLY (Solo lectura)'; cSOperationIsNotAllowed3 = 'Operacin no permitida en modo %s'; cSOperationIsNotAllowed4 = 'Operacin no permitida en un dataset cerrado'; cSNoMoreRecords = 'No hay ms registros en el Resultset'; cSCanNotOpenResultSet = 'No se puede abrir el Resultset'; cSCanNotOpenDataSetWhenDestroying ='Translate : Cannot open a dataset when the componentstate is dsDestroying'; cSCircularLink = 'Datasource hace una referencia cclica'; cSBookmarkWasNotFound = 'Bookmark no encontrado'; cSIncorrectSearchFieldsNumber = 'Nmero incorrecto de valores de bsqueda'; cSInvalidOperationInTrans = 'Operacin invlida en modo de transaccin explcita'; cSIncorrectSymbol = 'Smbolo incorrecto en la lista de campos "%s".'; cSIncorrectToken = 'Token incorrecto seguido de ":"'; cSIncorrectParamChar = 'TRANSLATE : Invalid value for ParamChar'; cSSelectedTransactionIsolation = 'El Nivel seleccionado de aislamiento de transaccin no est soportado'; cSDriverNotSupported = 'Controlador %s no soportado'; cSPattern2Long = 'Patrn de bsqueda demasiado largo'; cSDriverNotCapableOutParameters = 'El controlador no tiene cualidades para manejar parmetros'; cSStatementIsNotAllowed = 'Sentencia no permitida'; cSStoredProcIsNotAllowed = 'El procedimiento alamacenado no est permitido'; cSCannotPerformOperation = 'No se puede efectuar la operacin en un resultset cerrado'; cSInvalidState = 'Estado Invlido'; cSErrorConvertion = 'Error de conversin'; cSDataTypeDoesNotSupported = 'Tipo de datos no soportado'; cSUnsupportedParameterType = 'Tipo de parmetro no soportado'; cSUnsupportedDataType = 'Tipo de datos no soportado'; cSErrorConvertionField = 'Error de conversin del campo "%s" al Tipo SQL "%s"'; cSBadOCI = 'Versin de OCI [%s] no aceptable. Se requiere versin 8.0.3 o menor'; cSConnect2AsUser = 'Conectando a "%s" como usuario "%s"'; cSUnknownError = 'Error desconocido'; cSFieldNotFound1 = 'Campo "%s" no encontrado'; cSFieldNotFound2 = 'Campo %d no encontrado'; cSLoginPromptFailure = 'Cuadro de Dilogo por omisin para autenticacin no encontrado.'+#10#13+ 'Por favor agregue la unidad DBLogDlg a la seccin uses de la unidad principal de su proyecto.'; cSPropertyQuery = 'La Consulta puede tardar un poco en bases de datos extensas!'; cSPropertyTables = 'Debera limitarlas mediante Catalog y/o Schema.'; cSPropertyColumns = 'Debera limitarlas mediante Catalog, Schema y/o TableName.'; cSPropertyProcedures = 'Debera limitarlos mediante Catalog y/or Schema.'; cSPropertySequences = 'Debera limitarlos mediante Catalog y/or Schema.'; cSPropertyExecute = 'Desea ejecutar la consulta de todos modos?'; cSFormTest = 'Prueba del Editor ZEOS SQL'; cSButtonClose = '&Cerrar'; cSFormEditor = 'Editor ZEOS SQL'; cSTabSheetSelect = 'Seleccionar SQL'; cSMenuLoad = 'Cargar...'; cSMenuSave = 'Guardar...'; cSButtonGenerate = '&Generar'; cSButtonCheck = 'C&hecar'; cSButtonTest = 'Pro&bar'; cSButtonOk = '&Aceptar'; cSButtonCancel = '&Cancelar'; cSTableAlias = 'A&lias de la tabla'; cSReplaceSQL = '&Reemplazar SQL'; cSDialogOpenTitle = 'Abrir archivo SQL'; cSDialogSaveTitle = 'Guardar archivo SQL'; cSSQLEditor = 'Editor SQL'; cSDatabaseDialog = 'Abrir base de datos existente'; cSUpdateSQLNoResult = 'Translate : Update Refresh SQL delivered no resultset'; cSUpdateSQLRefreshStatementcount ='Translate : Update Refresh SQL Statement count must be 1'; {$IFDEF FPC} cSNotEditing = 'El Dataset no se encuentra en modo de edicin o insercin'; cSFieldTypeMismatch = 'El Tipo de dato no coincide para el campo ''%s'', se espera: %s, actual: %s'; cSFieldSizeMismatch = 'El Tamao de dato no coincide para el campo ''%s'', se espera: %d, actual: %d'; {$ENDIF} cSNeedField = 'Translate: Field %s is required, but not supplied.'; cSFailedtoInitPrepStmt = 'Translate: Prepared statement failed to initialize'; cSFailedtoPrepareStmt = 'Translate: Statement failed during prepare process'; cSFailedToBindAllValues = 'Translate: Application failed to pre-bind all values'; cSAttemptExecOnBadPrep = 'Translate: Attempt made to execute a statement before a successful preparation.'; cSBindingFailure = 'Translate: Failed to bind parameter set'; cSPreparedStmtExecFailure = 'Translate: Prepared statement failed to execute'; cSBoundVarStrIndexMissing = 'Translate: Bound variable text index "%s" does not exist'; cSBindVarOutOfRange = 'Translate: Bound variable index out of range: %d'; cSFailedToBindResults = 'Translate: Application failed to bind to the result set'; cSRefreshRowOnlySupportedWithUpdateObject = 'TRANSLATE: The refreshrow method is only supported with an update object'; cSMustBeInBrowseMode = 'TRANSLATE: Operation is only allowed in dsBROWSE state'; cSUnKnownParamDataType = 'TRANSLATE: Unknown Param.DataType'; cSFieldReadOnly = 'Translate : Readonly field can''t be assigned a value: %d'; cSInvalidUpdateCount = 'Translate : %d record(s) updated. Only one record should have been updated.'; cSRowBufferWidthExceeded ='Translate: Row buffer width exceeded. Try using fewer or longer columns in SQL query.'; {$ELSE} {$IFDEF ROMANA} SSQLError1 = 'SQL Eroare: %s'; cSSQLError2 = 'SQL Eroare: %s Cod: %d'; cSSQLError3 = 'SQL Eroare: %s Cod: %d SQL: %s'; cSSQLError4 = 'SQL Eroare: %s Cod: %d Mesaj: %s'; cSListCapacityError = 'Capacitatea listei este n afara limitelor (%d)'; cSListCountError = 'Contorul listei este n afara limitelor (%d)'; cSListIndexError = 'Indexul listei este n afara limitelor (%d)'; cSClonningIsNotSupported = 'Clonning nu este suportat de aceast clas'; cSImmutableOpIsNotAllowed = 'Operaia nu este permis ori colecia nu este modificabil'; cSStackIsEmpty = 'Stiva este goal'; cSVariableWasNotFound = 'Variabila "%s" nu a fost gsit'; cSFunctionWasNotFound = 'Funcia "%s" nu a fost gsit'; cSInternalError = 'Eroare Intern'; cSSyntaxErrorNear = 'Eroare de sintax lng "%s"'; cSSyntaxError = 'Eroare de sintax'; cSUnknownSymbol = 'Simbol necunoscut "%s"'; cSUnexpectedExprEnd = 'Final neateptat pentru expresie'; cSRightBraceExpected = ') ateptat'; cSParametersError = 'parametrul %d a fost ateptat dar %d a fost gsit'; cSExpectedMoreParams = 'Mai nult de doi parametrii sunt ateptai'; cSInvalidVarByteArray = 'Arie VarByte invalid'; cSVariableAlreadyExists = 'Variabila "%s" deja exist'; cSTypesMismatch = 'Tip nepotrivit'; cSUnsupportedVariantType = 'Tip variant neasteptat'; cSUnsupportedOperation = 'Operaie nesuportat'; cSTokenizerIsNotDefined = 'Simbolistica nu este definit'; cSLibraryNotFound = 'None of the dynamic libraries can be found: %s'; cSEncodeDateIsNotSupported = 'Aceast versiune nu suport isc_encode_sql_date'; cSEncodeTimeIsNotSupported = 'Aceast versiune nu suport isc_encode_sql_time'; cSEncodeTimestampIsNotSupported = 'Aceast versiune nu suport isc_encode_sql_timestamp'; cSDecodeDateIsNotSupported = 'Aceast versiune nu suport isc_decode_sql_date'; cSDecodeTimeIsNotSupported = 'Aceast versiune nu suport isc_decode_sql_time'; cSDecodeTimestampIsNotSupported = 'Aceast versiune nu suport isc_decode_sql_timestamp'; cSCanNotRetrieveResultSetData = 'Nu pot returna Resultset data'; cSRowBufferIsNotAssigned = 'Row buffer nu este asignat'; cSColumnIsNotAccessable = 'Column with index %d nu este accesibil'; cSConvertionIsNotPossible = 'Conversia nu este posibil pentru coloana %d din %s n %s'; cSCanNotAccessBlobRecord = 'Nu pot aceesa nregistrarea blob n coloana %d cu tipul %s'; cSRowDataIsNotAvailable = 'Row data nu este disponibil'; cSResolverIsNotSpecified = 'Resolver nu este specificat pentru acest ResultSet'; cSResultsetIsAlreadyOpened = 'Resultset este deja deschis'; cSCanNotUpdateEmptyRow = 'Nu pot updata o nregistrare goal'; cSCanNotUpdateDeletedRow = 'Nu pot updata o nregistrare tears'; cSCanNotDeleteEmptyRow = 'Nu pot terge o nregistrare goal'; cSCannotUseCommit = 'Nu poi folosi COMMIT n modul AUTOCOMMIT '; cSCannotUseRollBack = 'Nu poi folosi ROLLBACK n modul AUTOCOMMIT '; cSCanNotUpdateComplexQuery = 'Nu pot updata un query complex cu mai mult de un tabel'; cSCanNotUpdateThisQueryType = 'Nu pot updata acest tip de query'; cSDriverWasNotFound = 'Driverul pentru baza de date nu a fost gsit'; cSCanNotConnectToServer = 'Nu ma pot conecta la serverul SQL'; cSTableIsNotSpecified = 'Tbelul nu este specificat'; cSLiveResultSetsAreNotSupported = 'Live query is not supported by this class'; cSInvalidInputParameterCount = 'Input parameter count is less then expected'; cSIsolationIsNotSupported = 'Transaction isolation level nu este suportat'; cSColumnWasNotFound = 'Coloana cu numele "%s" nu a fost fsit'; cSWrongTypeForBlobParameter = 'Tip greit pentru parametru Blob'; cSIncorrectConnectionURL = 'Conexiune URL incorect: %s'; cSUnsupportedProtocol = 'Protocol nesuportat: %s'; cSUnsupportedByDriver = 'Driver nu poate suporta aceast facilitate : [%s]'; cSConnectionIsNotOpened = 'Conexiune nu este deschis inc'; cSInvalidOpInAutoCommit = 'Operaie invalid n modul AutoCommit'; cSInvalidOpInNonAutoCommit = 'Operaie invalid n modul non AutoCommit '; cSInvalidOpPrepare = 'Prepare transaction only possible on matching first(!) Starttransaction'; cSConnectionIsNotAssigned = 'Nu este asignat o component Database connection'; cSQueryIsEmpty = 'SQL Query este gol'; cSCanNotExecuteMoreQueries = 'Nu pot executa mai mult de un query'; cSOperationIsNotAllowed1 = 'Operaia nu este permis n modul FORWARD ONLY '; cSOperationIsNotAllowed2 = 'Operaia nu este permis n modul READ ONLY'; cSOperationIsNotAllowed3 = 'Operaia nu este permis n modul %s '; cSOperationIsNotAllowed4 = 'Operaia nu este permis pentru n dataset nchis'; cSNoMoreRecords = 'Nu mai sunt nregistrri n Resultset'; cSCanNotOpenResultSet = 'Nu pot deschide Resultset'; cSCanNotOpenDataSetWhenDestroying ='Translate : Cannot open a dataset when the componentstate is dsDestroying'; cSCircularLink = 'Datasource makes a circular link'; cSBookmarkWasNotFound = 'Bookmark nu a fost gsit'; cSIncorrectSearchFieldsNumber = 'Numr incorect of search field values'; cSInvalidOperationInTrans = 'Operaie invalid n modul explicit transaction'; cSIncorrectSymbol = 'Simbol incorect n lista de cmpuri "%s".'; cSIncorrectToken = 'Incorect token dup ":"'; cSIncorrectParamChar = 'TRANSLATE : Invalid value for ParamChar'; cSSelectedTransactionIsolation = 'Selected transaction isolation level is not supported'; cSDriverNotSupported = 'Driver nesuportat %s'; cSPattern2Long = 'Pattern is too long'; cSDriverNotCapableOutParameters = 'Driver nu este capabil s mnuie parametrii'; cSStatementIsNotAllowed = 'Statement nu sunt permise'; cSStoredProcIsNotAllowed = 'The stored proc nu sunt permise'; cSCannotPerformOperation = 'Nu se pot face operaii cu Resultset nchis'; cSInvalidState = 'Stare invalid'; cSErrorConvertion = 'Eroare de conversie'; cSDataTypeDoesNotSupported = 'Tip de dat nesuportat'; cSUnsupportedParameterType = 'Tip parametru nesuportat'; cSUnsupportedDataType = 'Tip dat nesuportat'; cSErrorConvertionField = 'Eroare de conversie pentru cmpul "%s" n TipSQL "%s"'; cSBadOCI = 'Bad OCI version [%s]. Version 8.0.3 or older is required'; cSConnect2AsUser = 'Conectare la "%s" ca utlizator "%s"'; cSUnknownError = 'Eroare necunoscut'; cSFieldNotFound1 = 'Cmpul "%s" nu a fost gsit'; cSFieldNotFound2 = 'Cmpul %d nu a fost gsit'; cSLoginPromptFailure = 'Nu gsesc fereastra de dialog implicit pentru login. V rog adugai DBLogDlg n seciunea uses.'; cSPropertyQuery = 'The Query may last a while on large databases!'; cSPropertyTables = 'You should limit it by Catalog and/or Schema.'; cSPropertyColumns = 'You should limit it by Catalog, Schema and/or TableName.'; cSPropertyProcedures = 'You should limit it by Catalog and/or Schema.'; cSPropertySequences = 'You should limit it by Catalog and/or Schema.'; cSPropertyExecute = 'Query va fi executat oricum?'; cSFormTest = 'ZEOS SQL Editor Test'; cSButtonClose = 'n&chide'; cSFormEditor = 'ZEOS SQL Editor'; cSTabSheetSelect = 'Select SQL'; cSMenuLoad = 'Deschide'; cSMenuSave = 'Salvare'; cSButtonGenerate = '&Generare'; cSButtonCheck = 'Verificare'; cSButtonTest = '&Test'; cSButtonOk = '&OK'; cSButtonCancel = 'Revo&care'; cSTableAlias = 'T&able alias'; cSReplaceSQL = '&Replace SQL'; cSDialogOpenTitle = 'Deschide Fiier SQL'; cSDialogSaveTitle = 'Salveaz Fiier SQL'; cSSQLEditor = 'SQL Editor'; cSDatabaseDialog = 'Deschide baz date existent'; cSUpdateSQLNoResult = '"Update Refresh SQL" furnizat nu este un recordset'; cSUpdateSQLRefreshStatementcount ='Declaraia "Update Refresh SQL" ca numr trebuie s fie una'; {$IFDEF FPC} cSNotEditing = 'Dataset nu este n modul de editare sau inserare'; cSFieldTypeMismatch = 'Tip nepotrivit pentru cmpul ''%s'', ateptat: %s actual: %s'; cSFieldSizeMismatch = 'Dimensiune nepotrivit pentru cmpul ''%s'', ateptat: %d actual: %d'; {$ENDIF} cSNeedField = 'Translate: Field %s is required, but not supplied.'; cSFailedtoInitPrepStmt = 'Translate: Prepared statement failed to initialize'; cSFailedtoPrepareStmt = 'Translate: Statement failed during prepare process'; cSFailedToBindAllValues = 'Translate: Application failed to pre-bind all values'; cSAttemptExecOnBadPrep = 'Translate: Attempt made to execute a statement before a successful preparation.'; cSBindingFailure = 'Translate: Failed to bind parameter set'; cSPreparedStmtExecFailure = 'Translate: Prepared statement failed to execute'; cSBoundVarStrIndexMissing = 'Translate: Bound variable text index "%s" does not exist'; cSBindVarOutOfRange = 'Translate: Bound variable index out of range: %d'; cSFailedToBindResults = 'Translate: Application failed to bind to the result set'; cSRefreshRowOnlySupportedWithUpdateObject = 'TRANSLATE: The refreshrow method is only supported with an update object'; cSMustBeInBrowseMode = 'TRANSLATE: Operation is only allowed in dsBROWSE state'; cSUnKnownParamDataType = 'TRANSLATE: Unknown Param.DataType'; cSRowBufferWidthExceeded ='Translate: Row buffer width exceeded. Try using fewer or longer columns in SQL query.'; // <-- added by tohenk {$ELSE} {$IFDEF INDONESIAN} cSSQLError1 = 'Kesalahan SQL: %s'; cSSQLError2 = 'Kesalahan SQL: %s Kode: %d'; cSSQLError3 = 'Kesalahan SQL: %s Kode: %d SQL: %s'; cSSQLError4 = 'Kesalahan SQL: %s Kode: %d Pesan: %s'; cSListCapacityError = 'Kapasitas List diluar jangkauan (%d)'; cSListCountError = 'Jumlah List diluar jangkauan (%d)'; cSListIndexError = 'Indeks List diluar jangkauan (%d)'; cSClonningIsNotSupported = 'Class ini tidak mendukung kloning'; cSImmutableOpIsNotAllowed = 'Operasi tidak diperkenankan pada koleksi yang tidak dapat diubah'; cSStackIsEmpty = 'Stack kosong'; cSVariableWasNotFound = 'Variabel "%s" tidak ada'; cSFunctionWasNotFound = 'Fungsi "%s" tidak ada'; cSInternalError = 'Kesalahan internal'; cSSyntaxErrorNear = 'Kesalahan Syntax di dekat "%s"'; cSSyntaxError = 'Kesalahan Syntax'; cSUnknownSymbol = 'Simbol tidak dikenali "%s"'; cSUnexpectedExprEnd = 'Tidak dibutuhkan, akhir dari ekspresi'; cSRightBraceExpected = ') dibutuhkan'; cSParametersError = '%d parameter dibutuhkan tapi terdapat %d parameter'; cSExpectedMoreParams = 'Dibutuhkan lebih dari dua parameter'; cSInvalidVarByteArray = 'array VarByte tidak valid'; cSVariableAlreadyExists = 'Variabel "%s" sudah ada'; cSTypesMismatch = 'Tipe tidak sesuai'; cSUnsupportedVariantType = 'Tipe variant tidak didukung'; cSUnsupportedOperation = 'Operasi tidak didukung'; cSTokenizerIsNotDefined = 'Tokenizer belum ditentukan'; cSLibraryNotFound = 'Tidak ada library ditemukan: %s'; cSEncodeDateIsNotSupported = 'Versi ini tidak mendukung isc_encode_sql_date'; cSEncodeTimeIsNotSupported = 'Versi ini tidak mendukung isc_encode_sql_time'; cSEncodeTimestampIsNotSupported = 'Versi ini tidak mendukung isc_encode_sql_timestamp'; cSDecodeDateIsNotSupported = 'Versi ini tidak mendukung isc_decode_sql_date'; cSDecodeTimeIsNotSupported = 'Versi ini tidak mendukung isc_decode_sql_time'; cSDecodeTimestampIsNotSupported = 'Versi ini tidak mendukung isc_decode_sql_timestamp'; cSCanNotRetrieveResultSetData = 'Tidak dapat mengambil data Resultset'; cSRowBufferIsNotAssigned = 'Row buffer tidak disediakan'; cSColumnIsNotAccessable = 'Kolom dengan indeks %d tidak dapat diakses'; cSConvertionIsNotPossible = 'Konversi tidak dimungkinkan pada kolom %d dari %s ke %s'; cSCanNotAccessBlobRecord = 'Tidak dapat mengakses rekord `blob` pada kolom %d dengan tipe %s'; cSRowDataIsNotAvailable = 'Data Row tidak tersedia'; cSResolverIsNotSpecified = 'Resolver belum ditentukan pada ResultSet ini'; cSResultsetIsAlreadyOpened = 'Resultset sudah terbuka'; cSCanNotUpdateEmptyRow = 'Tidak dapat meng-update row kosong'; cSCanNotUpdateDeletedRow = 'Tidak dapat meng-update row terhapus'; cSCanNotDeleteEmptyRow = 'Tidak dapat meng-hapus row kosong'; cSCannotUseCommit = 'COMMIT tidak dapat digunakan pada mode AUTOCOMMIT'; cSCannotUseRollBack = 'ROLLBACK tidak dapat digunakan pada mode AUTOCOMMIT'; cSCanNotUpdateComplexQuery = 'Tidak dapat meng-update query kompleks dengan lebih dari satu tabel'; cSCanNotUpdateThisQueryType = 'Tidak dapat meng-update query dengan tipe ini'; cSDriverWasNotFound = 'Driver database yang diminta tidak ada'; cSCanNotConnectToServer = 'Tidak dapat terhubung ke server SQL'; cSTableIsNotSpecified = 'Tabel belum ditentukan'; cSLiveResultSetsAreNotSupported = 'Live query tidak didukung oleh Class ini'; cSInvalidInputParameterCount = 'Jumlah parameter Input kurang dari yang dibutuhkan'; cSIsolationIsNotSupported = 'Level Isolasi Transaksi tidak didukung'; cSColumnWasNotFound = 'Kolom dengan nama "%s" tidak ada'; cSWrongTypeForBlobParameter = 'Salah tipe untuk parameter Blob'; cSIncorrectConnectionURL = 'Salah koneksi URL: %s'; cSUnsupportedProtocol = 'Protokol tidak didukung: %s'; cSUnsupportedByDriver = 'Driver tidak mendukung fitur: [%s]'; cSConnectionIsNotOpened = 'Koneksi belum dibuka'; cSInvalidOpInAutoCommit = 'Operasi tidak valid pada mode AUTOCOMMIT'; cSInvalidOpInNonAutoCommit = 'Operasi tidak valid pada mode non AUTOCOMMIT'; cSInvalidOpPrepare = 'Persiapan transaksi hanya mungkin pada (!) Starttransaction pertama'; cSConnectionIsNotAssigned = 'Komponen koneksi Database tidak ditentukan'; cSQueryIsEmpty = 'Query SQL kosong'; cSCanNotExecuteMoreQueries = 'Tidak dapat meng-eksekusi lebih dari satu query'; cSOperationIsNotAllowed1 = 'Operasi tidak diperkenankan pada mode FORWARD ONLY'; cSOperationIsNotAllowed2 = 'Operasi tidak diperkenankan pada mode READ ONLY'; cSOperationIsNotAllowed3 = 'Operasi tidak diperkenankan pada mode %s'; cSOperationIsNotAllowed4 = 'Operasi tidak diperkenankan pada dataset tertutup'; cSNoMoreRecords = 'Tidak ada rekord lagi pada Resultset'; cSCanNotOpenResultSet = 'Tidak dapat membuka Resultset'; cSCanNotOpenDataSetWhenDestroying ='Translate : Cannot open a dataset when the componentstate is dsDestroying'; cSCircularLink = 'Terjadi hubungan Datasource circular'; cSBookmarkWasNotFound = 'Bookmark tidak ada'; cSIncorrectSearchFieldsNumber = 'Salah jumlah nilai field pada pencarian'; cSInvalidOperationInTrans = 'Operasi tidak valid pada mode explicit transaction'; cSIncorrectSymbol = 'Simbol salah pada daftar field "%s".'; cSIncorrectToken = 'Token salah setelah ":"'; cSIncorrectParamChar = 'TRANSLATE : Invalid value for ParamChar'; cSSelectedTransactionIsolation = 'Level Isolasi Transaksi terpilih tidak didukung'; cSDriverNotSupported = 'Driver tidak mendukung %s'; cSPattern2Long = 'Pola terlalu panjang'; cSDriverNotCapableOutParameters = 'Driver tidak mampu menangani parameter'; cSStatementIsNotAllowed = 'Statement tidak diperbolehkan'; cSStoredProcIsNotAllowed = 'StoredProc tidak diperbolehkan'; cSCannotPerformOperation = 'Tidak dapat melakukan operasi pada Resultset tertutup'; cSInvalidState = 'Sate tidak valid'; cSErrorConvertion = 'Kesalahan konversi'; cSDataTypeDoesNotSupported = 'Tipe Data tidak didukung'; cSUnsupportedParameterType = 'Tidak mendukung tipe parameter'; cSUnsupportedDataType = 'Tidak mendukung tipe data'; cSErrorConvertionField = 'Kesalahan konversi field "%s" ke Tipe SQL "%s"'; cSBadOCI = 'OCI version [%s] tidak sah. Dibutuhkan versi 8.0.3 atau terdahulu'; cSConnect2AsUser = 'Koneksi ke "%s" dengan user "%s"'; cSUnknownError = 'Kesalahan tidak diketahui'; cSFieldNotFound1 = 'Field "%s" tidak ada'; cSFieldNotFound2 = 'Field %d tidak ada'; cSLoginPromptFailure = 'Tidak ada dialog Login default. Silahkan tambahkan DBLogDlg ke klausula `uses` pada file utama.'; cSPropertyQuery = 'Query mungkin berlangsung lama pada database besar!'; cSPropertyTables = 'Batasi dengan Katalog data/atau Skema.'; cSPropertyColumns = 'Batasi dengan Katalog, Skema dan/atau Nama Tabel.'; cSPropertyProcedures = 'Batasi dengan Katalog dan/atau Skema.'; cSPropertySequences = 'Batasi dengan Katalog dan/atau Skema.'; cSPropertyExecute = 'Apakah Query jadi dieksekusi?'; cSFormTest = 'Tes Editor SQLZEOS'; cSButtonClose = '&Tutup'; cSFormEditor = 'Editor SQL ZEOS'; cSTabSheetSelect = 'SQL Select'; cSMenuLoad = 'Ambil'; cSMenuSave = 'Simpan'; cSButtonGenerate = '&Generate'; cSButtonCheck = '&Cek'; cSButtonTest = 'T&es'; cSButtonOk = '&OK'; cSButtonCancel = '&Batal'; cSTableAlias = 'Alias T&abel'; cSReplaceSQL = 'SQL &Replace'; cSDialogOpenTitle = 'Buka File SQL'; cSDialogSaveTitle = 'Simpan File SQL'; cSSQLEditor = 'Editor SQL'; cSDatabaseDialog = 'Buka database yang tersedia'; cSUpdateSQLNoResult = 'Tidak ada Resultset pada Update Refresh SQL'; cSUpdateSQLRefreshStatementcount ='Jumlah Statement pada Update Refresh SQL harus 1'; {$IFDEF FPC} cSNotEditing = 'Dataset tidak dalam mode edit atau sisip'; cSFieldTypeMismatch = 'Tipe tidak sesuai pada field ''%s'', seharusnya: %s aktual: %s'; cSFieldSizeMismatch = 'Ukuran tidak sesuai pada field ''%s'', seharusnya: %d aktual: %d'; {$ENDIF} cSNeedField = 'Field %s diperlukan, namun tidak disediakan.'; cSFailedtoInitPrepStmt = 'Gagal inisialisasi Prepared statement'; cSFailedtoPrepareStmt = 'Statemen gagal sewaktu proses persiapan'; cSFailedToBindAllValues = 'Aplikasi gagal dalam penggabungan pendahuluan semua nilai'; cSAttemptExecOnBadPrep = 'Percobaan eksekusi statemen dilakukan sebelum persiapan berhasil.'; cSBindingFailure = 'Gagal menggabungkan parameter'; cSPreparedStmtExecFailure = 'Prepared Statement gagal dieksekusi'; cSBoundVarStrIndexMissing = 'Teks variabel indeks "%s" tidak ada'; cSBindVarOutOfRange = 'Variabel indeks diluar jangkauan: %d'; cSFailedToBindResults = 'Aplikasi gagal pada penggabungan ke Resultset'; cSRefreshRowOnlySupportedWithUpdateObject = 'Metode RefreshRow hanya didukung oleh obyek Update'; cSMustBeInBrowseMode = 'Operasi hanya diperbolehkan pada status dsBrowse'; cSUnKnownParamDataType = 'Param.DataType tidak dikenal'; cSFieldReadOnly = 'Field readonly tidak dapat diberikan nilai: %d'; cSInvalidUpdateCount = '%d rekord terupdate. Seharusnya hanya satu rekord yang terupdate.'; cSRowBufferWidthExceeded = 'Lebar buffer baris terlampaui. Coba kurangi atau gunakan kolom yang lebih panjang dalam query SQL.'; // <--- end added by tohenk //--- begin added by ORMADA -------------------------------------------------- {$ELSE} {$IFDEF RUSSIAN} cSSQLError1 = ' SQL : %s'; cSSQLError2 = ' SQL : %s : %d'; cSSQLError3 = ' SQL : %s : %d SQL: %s'; cSSQLError4 = ' SQL : %s : %d : %s'; cSListCapacityError = ' (%d)'; cSListCountError = ' (%d)'; cSListIndexError = ' (%d)'; cSClonningIsNotSupported = ' '; cSImmutableOpIsNotAllowed = ' '; cSStackIsEmpty = ' '; cSVariableWasNotFound = ' "%s" '; cSFunctionWasNotFound = ' "%s" '; cSInternalError = ' '; cSSyntaxErrorNear = ' "%s"'; cSSyntaxError = ' '; cSUnknownSymbol = ' "%s"'; cSUnexpectedExprEnd = ' '; cSRightBraceExpected = ') '; cSParametersError = ' %d , %d'; cSExpectedMoreParams = ' 2- '; cSInvalidVarByteArray = ' (VarByte)'; cSVariableAlreadyExists = ' "%s" '; cSTypesMismatch = ' '; cSUnsupportedVariantType = ' (variant) '; cSUnsupportedOperation = ' '; cSTokenizerIsNotDefined = ' '; cSLibraryNotFound = ' : %s'; cSEncodeDateIsNotSupported = ' isc_encode_sql_date'; cSEncodeTimeIsNotSupported = ' isc_encode_sql_time'; cSEncodeTimestampIsNotSupported = ' isc_encode_sql_timestamp'; cSDecodeDateIsNotSupported = ' isc_decode_sql_date'; cSDecodeTimeIsNotSupported = ' isc_decode_sql_time'; cSDecodeTimestampIsNotSupported = ' isc_decode_sql_timestamp'; cSCanNotRetrieveResultSetData = ' (Resultset)'; cSRowBufferIsNotAssigned = ' '; cSColumnIsNotAccessable = ' %d'; cSConvertionIsNotPossible = ' %d %s %s'; cSCanNotAccessBlobRecord = ' blob %d %s'; cSRowDataIsNotAvailable = ' '; cSResolverIsNotSpecified = ' (ResultSet) Resolver'; cSResultsetIsAlreadyOpened = ' (Resultset) '; cSCanNotUpdateEmptyRow = ' '; cSCanNotUpdateDeletedRow = ' '; cSCanNotDeleteEmptyRow = ' '; cSCannotUseCommit = ' COMMIT AUTOCOMMIT '; cSCannotUseRollBack = ' ROLLBACK AUTOCOMMIT '; cSCanNotUpdateComplexQuery = ' '; cSCanNotUpdateThisQueryType = ' '; cSDriverWasNotFound = ' '; cSCanNotConnectToServer = ' SQL '; cSTableIsNotSpecified = ' '; cSLiveResultSetsAreNotSupported = ' '; cSInvalidInputParameterCount = ' is '; cSIsolationIsNotSupported = ' '; cSColumnWasNotFound = ' "%s"'; cSWrongTypeForBlobParameter = ' Blob '; cSIncorrectConnectionURL = ' (URL) : %s'; cSUnsupportedProtocol = ' : %s'; cSUnsupportedByDriver = ' : [%s]'; cSConnectionIsNotOpened = ' '; cSInvalidOpInAutoCommit = ' (AutoCommit)'; cSInvalidOpInNonAutoCommit = ' (non AutoCommit)'; cSInvalidOpPrepare = ' (!) StartTransaction'; cSConnectionIsNotAssigned = ' '; cSQueryIsEmpty = 'SQL '; cSCanNotExecuteMoreQueries = ' '; cSOperationIsNotAllowed1 = ' (FORWARD ONLY)'; cSOperationIsNotAllowed2 = ' (READ ONLY)'; cSOperationIsNotAllowed3 = ' %s '; cSOperationIsNotAllowed4 = ' '; cSNoMoreRecords = ' (Resultset) '; cSCanNotOpenResultSet = ' (Resultset)'; cSCanNotOpenDataSetWhenDestroying ='Translate : Cannot open a dataset when the componentstate is dsDestroying'; cSCircularLink = ' (Datasource) '; cSBookmarkWasNotFound = ' (Bookmark) '; cSIncorrectSearchFieldsNumber = ' Incorrect number of search field values'; cSInvalidOperationInTrans = ' '; cSIncorrectSymbol = ' "%s".'; cSIncorrectToken = ' ":"'; cSIncorrectParamChar = 'TRANSLATE : Invalid value for ParamChar'; cSSelectedTransactionIsolation = ' '; cSDriverNotSupported = ' %s'; cSPattern2Long = ' '; cSDriverNotCapableOutParameters = ' '; cSStatementIsNotAllowed = ' '; cSStoredProcIsNotAllowed = ' '; cSCannotPerformOperation = ' (Resultset)'; cSInvalidState = ' '; cSErrorConvertion = ' '; cSDataTypeDoesNotSupported = ' '; cSUnsupportedParameterType = ' '; cSUnsupportedDataType = ' '; cSErrorConvertionField = ' "%s" SQLType "%s"'; cSBadOCI = ' OCI [%s]. 8.0.3 '; cSConnect2AsUser = ' "%s" "%s"'; cSUnknownError = ' '; cSFieldNotFound1 = ' "%s" '; cSFieldNotFound2 = ' %d '; cSLoginPromptFailure = ' . DBLogDlg uses .'; cSPropertyQuery = ' The Query may last a while on large databases!'; cSPropertyTables = ' (Catalog) / (Schema)'; cSPropertyColumns = ' (Catalog), (Schema) / (TableName).'; cSPropertyProcedures = ' (Catalog) / (Schema).'; cSPropertySequences = ' (Catalog) / (Schema).'; cSPropertyExecute = ' ?'; cSFormTest = 'ZEOS SQL '; cSButtonClose = '&'; cSFormEditor = 'ZEOS SQL '; cSTabSheetSelect = ' SQL'; cSMenuLoad = ''; cSMenuSave = ''; cSButtonGenerate = '&'; cSButtonCheck = '&'; cSButtonTest = '&'; cSButtonOk = '&'; cSButtonCancel = '&'; cSTableAlias = '& '; cSReplaceSQL = '& SQL'; cSDialogOpenTitle = ' SQL '; cSDialogSaveTitle = ' SQL '; cSSQLEditor = 'SQL '; cSDatabaseDialog = ' '; cSUpdateSQLNoResult = ' (Refresh) '; cSUpdateSQLRefreshStatementcount = 'Refresh '; {$IFDEF FPC} cSNotEditing = ' (Dataset) '; cSFieldTypeMismatch = ' ''%s'', %s : %s'; cSFieldSizeMismatch = ' ''%s'' , : %d : %d'; {$ENDIF} cSNeedField = 'Translate: Field %s is required, but not supplied.'; cSFailedtoInitPrepStmt = ' '; cSFailedtoPrepareStmt = ' '; cSFailedToBindAllValues = ' - '; cSAttemptExecOnBadPrep = ' .'; cSBindingFailure = ' '; cSPreparedStmtExecFailure = ' '; cSBoundVarStrIndexMissing = ' "%s" '; cSBindVarOutOfRange = ' : %d'; cSFailedToBindResults = ' (bind) '; cSRefreshRowOnlySupportedWithUpdateObject = ' (RefreshRow) '; cSMustBeInBrowseMode = ' (dsBROWSE)'; cSUnKnownParamDataType = ' (Param.DataType)'; //--- end added by ORMADA ---------------------------------------------------- cSFieldReadOnly = 'Translate : Readonly field can''t be assigned a value: %d'; cSInvalidUpdateCount = 'Translate : %d record(s) updated. Only one record should have been updated.'; cSRowBufferWidthExceeded ='Translate: Row buffer width exceeded. Try using fewer or longer columns in SQL query.'; {$ELSE} //--- added by Petr Stasiak - pestasoft.com ------------------------------------ {$IFDEF CZECH} cSSQLError1 = 'SQL chyba: %s'; cSSQLError2 = 'SQL chyba: %s kd: %d'; cSSQLError3 = 'SQL chyba: %s kd: %d SQL: %s'; cSSQLError4 = 'SQL chyba: %s kd: %d Hlen: %s'; cSListCapacityError = 'Kapacita seznamu je mimo rozsah (%d)'; cSListCountError = 'Poet seznam je mimo rozsah (%d)'; cSListIndexError = 'Index v seznamu je mimo rozsah (%d)'; cSClonningIsNotSupported = 'Klonovn nen v tto td podporovno'; cSImmutableOpIsNotAllowed = 'Tato operace nen povolena na nemniteln "collections"'; cSStackIsEmpty = 'Zsobnk je przdn'; cSVariableWasNotFound = 'Promn "%s" neexistuje'; cSFunctionWasNotFound = 'Funkce "%s" neexistuje'; cSInternalError = 'Intern chyba'; cSSyntaxErrorNear = 'Chybn syntaxe "%s"'; cSSyntaxError = 'Chybn syntaxe'; cSUnknownSymbol = 'Neznm symbol "%s"'; cSUnexpectedExprEnd = 'Neoekvan konec vrazu'; cSRightBraceExpected = ') oekvn(o/a/y)'; cSParametersError = '%d parametr oekvno, ale %d existuje'; cSExpectedMoreParams = 'Je oekvno vce, ne 2 parametry'; cSInvalidVarByteArray = 'Nesprvn VarByte array'; cSVariableAlreadyExists = 'Promn "%s" ji existuje'; cSTypesMismatch = 'Nesouhlasn typy'; cSUnsupportedVariantType = 'Nepodporovan typ variant'; cSUnsupportedOperation = 'Nepodporovan operace'; cSTokenizerIsNotDefined = 'Nen definovn "Tokenizer"'; cSLibraryNotFound = 'Neexistuje dll knihovna(y): %s'; cSEncodeDateIsNotSupported = 'Tato verze nepodporuje isc_encode_sql_date'; cSEncodeTimeIsNotSupported = 'Tato verze nepodporuje isc_encode_sql_time'; cSEncodeTimestampIsNotSupported = 'Tato verze nepodporuje isc_encode_sql_timestamp'; cSDecodeDateIsNotSupported = 'Tato verze nepodporuje isc_decode_sql_date'; cSDecodeTimeIsNotSupported = 'Tato verze nepodporuje isc_decode_sql_time'; cSDecodeTimestampIsNotSupported = 'Tato verze nepodporuje isc_decode_sql_timestamp'; cSCanNotRetrieveResultSetData = 'Nelze zskat data "Resultset"'; cSRowBufferIsNotAssigned = 'Nen piazen dkov buffer'; cSColumnIsNotAccessable = 'Sloupec s indexem %d nen pstupn'; cSConvertionIsNotPossible = 'Pevod sloupce %d nen mon z %s na %s'; cSCanNotAccessBlobRecord = 'Nelze pistupovat k blob zznamu ze zloupce %d pes typ %s'; cSRowDataIsNotAvailable = 'dkov data nejsou pstupn'; cSResolverIsNotSpecified = 'Nen specifikovn "rozklada" pro tento vsledek'; cSResultsetIsAlreadyOpened = '"Resultset" byl ji oteven'; cSCanNotUpdateEmptyRow = 'Nelze aktualizovat przdn dek'; cSCanNotUpdateDeletedRow = 'Nelze aktualizovat smazan dek'; cSCanNotDeleteEmptyRow = 'Nelze vymazat przdn dek'; cSCannotUseCommit = 'Nepouvejte COMMIT v mdu AUTOCOMMIT'; cSCannotUseRollBack = 'Nelze pout ROLLBACK v AUTOCOMMIT mdu'; cSCanNotUpdateComplexQuery = 'Nelze aktualizovat komplexn dotaz pro vce, ne jednu tabulku'; cSCanNotUpdateThisQueryType = 'Nelze aktualizovat tento typ dotazu'; cSDriverWasNotFound = 'Poadovan databzov ovlada nenalezen'; cSCanNotConnectToServer = 'Nezdailo se pipojen k SQL serveru'; cSTableIsNotSpecified = 'Tabulka nen specifikovna'; cSLiveResultSetsAreNotSupported = '"iv" dotaz nen podporovn v tto td'; cSInvalidInputParameterCount = 'Poet vstupnch parametr neodpovd oekvanmu potu'; cSIsolationIsNotSupported = 'Mra izolace transakce nen podporovna'; cSColumnWasNotFound = 'Sloupec s nzvem "%s" neexistuje'; cSWrongTypeForBlobParameter = 'Nesprvn typ pro Blob parametr'; cSIncorrectConnectionURL = 'Nesprvn tvar URL adresy: %s'; cSUnsupportedProtocol = 'Nepodporovan protokol: %s'; cSUnsupportedByDriver = 'Ovlada nepodporuje tuto vlastnost: [%s]'; cSConnectionIsNotOpened = 'Spojen nen oteveno'; cSInvalidOpInAutoCommit = 'Nesprvn operace v mdu AutoCommit'; cSInvalidOpInNonAutoCommit = 'Nesprvn operace v mdu NE AutoCommit'; cSInvalidOpPrepare = '"Prepare" transakce je mon pouze jako prvn! Starttransaction'; cSConnectionIsNotAssigned = 'Nen piazen komponent "connection"'; cSQueryIsEmpty = 'SQL dotaz je przdn'; cSCanNotExecuteMoreQueries = 'Nelze spustit vce, ne 1 dotaz'; cSOperationIsNotAllowed1 = 'Operace nen povolena v mdu "FORWARD ONLY"'; cSOperationIsNotAllowed2 = 'Operace nen povolena v mdu "READ ONLY"'; cSOperationIsNotAllowed3 = 'Operace nen povolena v mdu "%s"'; cSOperationIsNotAllowed4 = 'Operace nen povolena pro zaven zdroj dat (dataset)'; cSNoMoreRecords = 'Nejsou dal zznamy'; cSCanNotOpenResultSet = 'Nelze otevt vsledek dotazu'; cSCanNotOpenDataSetWhenDestroying ='Translate : Cannot open a dataset when the componentstate is dsDestroying'; cSCircularLink = 'Datasource vytv cyklick dotaz'; cSBookmarkWasNotFound = 'Zloka neexistuje'; cSIncorrectSearchFieldsNumber = 'Nesprvn poet vyhledvanch poloek'; cSInvalidOperationInTrans = 'Nesprvn operace v explicitnm transaknm mdu'; cSIncorrectSymbol = 'Nesprvn symbol v seznamu poloek "%s".'; cSIncorrectToken = 'Za ":" nsleduje nesprvn znak'; cSIncorrectParamChar = 'TRANSLATE : Invalid value for ParamChar'; cSSelectedTransactionIsolation = 'Vybran mra izolace transakc nen podporovna'; cSDriverNotSupported = 'Ovlada %s nen podporovn'; cSPattern2Long = 'Pattern je pli dlouh'; cSDriverNotCapableOutParameters = 'Ovlada nen schopen pijmat parametry'; cSStatementIsNotAllowed = 'Pkaz nen povolen'; cSStoredProcIsNotAllowed = '"stored proc" nen povolena'; cSCannotPerformOperation = 'Nelze provst operaci na uzavenm vsledku dotazu (Resultset)'; cSInvalidState = 'Nesprvn stav'; cSErrorConvertion = 'Chyba pevodu'; cSDataTypeDoesNotSupported = 'Tento typ dat nen podporovn'; cSUnsupportedParameterType = 'Nepodporovan typ parametru'; cSUnsupportedDataType = 'Nepodporovan typ dat'; cSErrorConvertionField = 'Chyba pevodu sloupce "%s" na SQLTyp "%s"'; cSBadOCI = 'patn verze OCI [%s]. Je vyadovna 8.0.3 nebo star'; cSConnect2AsUser = 'Pipojit k "%s" jako "%s"'; cSUnknownError = 'Neznm chyba'; cSFieldNotFound1 = 'Sloupec "%s" neexistuje'; cSFieldNotFound2 = 'Sloupec %d neexistuje'; cSLoginPromptFailure = 'Nelze najt vchoz pihlaovac dialog. Prosm pidejte DBLogDlg do sekce USES vaeho zdrojovho souboru.'; cSPropertyQuery = 'Dotaz me bt posledn u vlelkch databz!'; cSPropertyTables = 'Mlo by bt limitovno katalogen a/nebo schmatem.'; cSPropertyColumns = 'Mlo by bt limitovno katalogem, schmatem a/nebo nzvem tabulky.'; cSPropertyProcedures = 'Mlo by bt limitovno katalogen a/nebo schmatem.'; cSPropertySequences = 'Mlo by bt limitovno katalogen a/nebo schmatem.'; cSPropertyExecute = 'M se dotaz pesto vykonat?'; cSFormTest = 'ZEOS SQL Editor Test'; cSButtonClose = '&Zavt'; cSFormEditor = 'ZEOS SQL Editor'; cSTabSheetSelect = 'Select SQL'; cSMenuLoad = 'Nast'; cSMenuSave = 'Uloit'; cSButtonGenerate = '&Generovat'; cSButtonCheck = '&Kontrola'; cSButtonTest = '&Test'; cSButtonOk = '&OK'; cSButtonCancel = 'Z&ruit'; cSTableAlias = '&Alias tabulky'; cSReplaceSQL = 'Nah&radit SQL'; cSDialogOpenTitle = 'Otevt SQL soubor'; cSDialogSaveTitle = 'Uloit SQL soubor'; cSSQLEditor = 'SQL Editor'; cSDatabaseDialog = 'Otevt existujc databzi'; cSUpdateSQLNoResult = 'Update Refresh SQL nevrtilo dn vsledek'; cSUpdateSQLRefreshStatementcount ='Poet Update Refresh SQL pkaz mus bt 1'; {$IFDEF FPC} cSNotEditing = 'Dataset nen v editanm (edit), ani vkldacm (insert) reimu'; cSFieldTypeMismatch = 'Nesprvn typ pro sloupec ''%s'', oekvno: %s aktuln: %s'; cSFieldSizeMismatch = 'Nesprvn velikost sloupce ''%s'', oekvno: %d aktuln: %d'; {$ENDIF} cSNeedField = 'Sloupce %s je poadovn, ale nezadn.'; cSFailedtoInitPrepStmt = 'Pipravovan pkaz nelze inicializovat'; cSFailedtoPrepareStmt = 'Pkaz selhal bhem ppravy procesu'; cSFailedToBindAllValues = 'Aplikace zkolabovala ped ppravou vech hodnot'; cSAttemptExecOnBadPrep = 'Pokoute sespustit pkaz ped dokonenm jeho ppravy.'; cSBindingFailure = 'Chyba pi zskvn sady parametr'; cSPreparedStmtExecFailure = 'Pipravovan pkaz selhal pi vykonvn'; cSBoundVarStrIndexMissing = 'Index textov promn "%s" neexistuje'; cSBindVarOutOfRange = 'Index promen je mimo rozsah: %d'; cSFailedToBindResults = 'Aplikace selhala pi zskvn vsledk dotazu'; //FOS+ 07112006 cSRefreshRowOnlySupportedWithUpdateObject = 'Metoda "refreshrow" je podporovna pouze v "update object"'; cSMustBeInBrowseMode = 'Operace je povolena pouze ve stavu dsBROWSE'; cSUnKnownParamDataType = 'Neznm parametr.typ dat (Param.DataType)'; cSFieldReadOnly = 'Sloupec pouze pro ten neme bt piazen k hodnot: %d'; cSInvalidUpdateCount = '%d zznam() aktualizovno. Pouze jeden zznam byl zmnn.'; cSRowBufferWidthExceeded ='Translate: Row buffer width exceeded. Try using fewer or longer columns in SQL query.'; //--- end added by Petr Stasiak - pestasoft.com ------------------------------------ {$ELSE} //--- added by pawelsel -------------------------------------------------------- {$IFDEF POLISH} cSSQLError1 = 'Bd SQL: %s'; cSSQLError2 = 'Bd SQL: %s Kod: %d'; cSSQLError3 = 'Bd SQL: %s Kod: %d SQL: %s'; cSSQLError4 = 'Bd SQL: %s Kod: %d Komunikat: %s'; cSListCapacityError = 'Przekroczona pojemno listy (%d)'; cSListCountError = 'Licznik listy poza zakresem (%d)'; cSListIndexError = 'Indeks listy poza zakresem (%d)'; cSClonningIsNotSupported = 'Ta klasa nie obsuguje klonowania'; cSImmutableOpIsNotAllowed = 'Niedozwolona operacja na niezmienialnych kolekcjach'; cSStackIsEmpty = 'Stos jest pusty'; cSVariableWasNotFound = 'Nie znaleziono zmiennej "%s"'; cSFunctionWasNotFound = 'Nie znaleziono funkcji "%s"'; cSInternalError = 'Bd wewntrzny'; cSSyntaxErrorNear = 'Bd skadni przy "%s"'; cSSyntaxError = 'Bd skadni'; cSUnknownSymbol = 'Nieznany symbol "%s"'; cSUnexpectedExprEnd = 'Nieoczekiwany koniec wyraenia'; cSRightBraceExpected = 'Oczekiwano znaku )'; cSParametersError = 'Oczekiwana ilo parametrw: %d, znaleziono: %d'; cSExpectedMoreParams = 'Oczekiwano wicej ni dwa parametry'; cSInvalidVarByteArray = 'Bdna tablica VarByte'; cSVariableAlreadyExists = 'Zmienna "%s" ju istnieje'; cSTypesMismatch = 'Niezgodno typw'; cSUnsupportedVariantType = 'Nieznany typ danych'; cSUnsupportedOperation = 'Nieznana operacja'; cSTokenizerIsNotDefined = 'Nie zdefiniowano tokenizera'; cSLibraryNotFound = 'Nie znaleziono adnej z bibliotek dynamicznych: %s'; cSEncodeDateIsNotSupported = 'Ta wersja nie obsuguje isc_encode_sql_date'; cSEncodeTimeIsNotSupported = 'Ta wersja nie obsuguje isc_encode_sql_time'; cSEncodeTimestampIsNotSupported = 'Ta wersja nie obsuguje isc_encode_sql_timestamp'; cSDecodeDateIsNotSupported = 'Ta wersja nie obsuguje isc_decode_sql_date'; cSDecodeTimeIsNotSupported = 'Ta wersja nie obsuguje isc_decode_sql_time'; cSDecodeTimestampIsNotSupported = 'Ta wersja nie obsuguje isc_decode_sql_timestamp'; cSCanNotRetrieveResultSetData = 'Nie mona pobra danych wynikowych'; cSRowBufferIsNotAssigned = 'Nie przypisano bufora wiersza'; cSColumnIsNotAccessable = 'Kolumna o numerze %d jest niedostpna'; cSConvertionIsNotPossible = 'Konwersja kolumny o numerze %d z %s na %s jest niemoliwa'; cSCanNotAccessBlobRecord = 'Brak dostpu do rekordu typu blob w kolumnie %d z typem %s'; cSRowDataIsNotAvailable = 'Dane wiersza s niedostpne'; cSResolverIsNotSpecified = 'Ten ResultSet nie ma okrelonego Resolver-a'; cSResultsetIsAlreadyOpened = 'ResultSet jest ju otwarty'; cSCanNotUpdateEmptyRow = 'Nie mona aktualizowa pustego wiersza'; cSCanNotUpdateDeletedRow = 'Nie mona aktualizowa usunitego wiersza'; cSCanNotDeleteEmptyRow = 'Nie mona usun pustego wiersza'; cSCannotUseCommit = 'Nie mona uy COMMIT w trybie AUTOCOMMIT'; cSCannotUseRollBack = 'Nie mona uy ROLLBACK w trybie AUTOCOMMIT'; cSCanNotUpdateComplexQuery = 'Nie mona aktualizowa zapytania zoonego z wicej ni jednej tabeli'; cSCanNotUpdateThisQueryType = 'Nie mona aktualizowa tego typu zapytania'; cSDriverWasNotFound = 'Nie znaleziono wymaganego sterownika bazy danych'; cSCanNotConnectToServer = 'Nie mona poczy si z serwerem SQL'; cSTableIsNotSpecified = 'Nie okrelono tabeli'; cSLiveResultSetsAreNotSupported = '"Live query" nie jest obsugiwane przez t klas'; cSInvalidInputParameterCount = 'Liczba parametrw wejsciowych jest mniejsza ni oczekiwana'; cSIsolationIsNotSupported = 'Poziom izolacji transakcji nie jest obsugiwany'; cSColumnWasNotFound = 'Nie znaleziono kolumny o nazwie "%s"'; cSWrongTypeForBlobParameter = 'Bdny typ parametru Blob'; cSIncorrectConnectionURL = 'Bdny URL poczenia: %s'; cSUnsupportedProtocol = 'Nieobsugiwany protok: %s'; cSUnsupportedByDriver = 'Sterownik nie obsuguje tej waciwoci natywnie: [%s]'; cSConnectionIsNotOpened = 'Jeszcze nie nawizano poczenia'; cSInvalidOpInAutoCommit = 'Bdna operacja w trybie AutoCommit'; cSInvalidOpInNonAutoCommit = 'Bdna operacja przy wyczonym AutoCommit'; cSInvalidOpPrepare = 'Przygotowanie transakcji moliwe jest tylko przy pierwszym(!) Starttransaction'; cSConnectionIsNotAssigned = 'Nie przypisano komponentu poczenia do bazy danych'; cSQueryIsEmpty = 'Zapytanie SQL jest puste'; cSCanNotExecuteMoreQueries = 'Nie mona wykona wicej ni jednego zapytania'; cSOperationIsNotAllowed1 = 'Niedozwolona operacja w trybie FORWARD ONLY'; cSOperationIsNotAllowed2 = 'Niedozwolona operacja w trybie READ ONLY'; cSOperationIsNotAllowed3 = 'Niedozwolona operacja w trybie %s'; cSOperationIsNotAllowed4 = 'Niedozwolona operacja przy zamnitym rdle danych'; cSNoMoreRecords = 'Nie ma ju wicej rekordw wynikowych'; cSCanNotOpenResultSet = 'Nie mozna otworzy danych wynikowych'; cSCanNotOpenDataSetWhenDestroying ='Translate : Cannot open a dataset when the componentstate is dsDestroying'; cSCircularLink = 'Datasource tworzy powizanie cykliczne'; cSBookmarkWasNotFound = 'Nie znaleziono zakadki (Bookmark)'; cSIncorrectSearchFieldsNumber = 'Bdna liczba pl do wyszukiwania'; cSInvalidOperationInTrans = 'Bdna operacja w trybie transakcji'; cSIncorrectSymbol = 'Bdny symbol w licie pl "%s".'; cSIncorrectToken = 'Bdny wyraz za ":"'; cSIncorrectParamChar = 'TRANSLATE : Invalid value for ParamChar'; cSSelectedTransactionIsolation = 'Wybrany poziom izolacji transakcji nie jest obsugiwany'; cSDriverNotSupported = 'Nie obsugiwany sterownik %s'; cSPattern2Long = 'Wzorzec jest zbyt dugi'; cSDriverNotCapableOutParameters = 'Sterownik nie potrafi obsuy parametrw'; cSStatementIsNotAllowed = 'Niedozwolone wyraenie'; cSStoredProcIsNotAllowed = 'Niedozwolona procedura skadowana'; cSCannotPerformOperation = 'Nie mona wykona operacji na zamknitym zbiorze danych'; cSInvalidState = 'Bdny stan'; cSErrorConvertion = 'Bd konwersji'; cSDataTypeDoesNotSupported = 'Nieobsugiwany typ dannych'; cSUnsupportedParameterType = 'Nieobsugiwany typ parametru'; cSUnsupportedDataType = 'Nieobsugiwany typ danych'; cSErrorConvertionField = 'Bd konwersji pola "%s" na SQLType "%s"'; cSBadOCI = 'Za wersja OCI [%s]. Wymagana wersja 8.0.3 lub starsza'; cSConnect2AsUser = 'Poczenie z "%s" jako uytkownik "%s"'; cSUnknownError = 'Nieznany bd'; cSFieldNotFound1 = 'Nie znaleziono pola "%s"'; cSFieldNotFound2 = 'Nie znaleziono pola %d'; cSLoginPromptFailure = 'Nie znaleziono domylnego dialogu logowania. Prosz doda DBLogDlg do sekcji uses gwnego pliku aplikacji.'; cSPropertyQuery = 'Zapytanie moe chwil potrwa na wikszej bazie danych!'; cSPropertyTables = 'Powiniene ucili Katalog i/lub Schemat.'; cSPropertyColumns = 'Powiniene ucili Katalog, Schemat i/lub NazwTabeli.'; cSPropertyProcedures = 'Powiniene ucili Katalog i/lub Schemat.'; cSPropertySequences = 'Powiniene ucili Katalog i/lub Schemat.'; cSPropertyExecute = 'Czy mimo to wykona zapytanie?'; cSFormTest = 'Test Edytora SQL ZEOS'; cSButtonClose = '&Zamknij'; cSFormEditor = 'Edytor SQL ZEOS'; cSTabSheetSelect = 'Wybr SQL'; cSMenuLoad = 'aduj'; cSMenuSave = 'Zapisz'; cSButtonGenerate = '&Generuj'; cSButtonCheck = '&Sprawd'; cSButtonTest = '&Test'; cSButtonOk = '&OK'; cSButtonCancel = 'A&nuluj'; cSTableAlias = '&Alias tabeli'; cSReplaceSQL = 'Za&mie SQL'; cSDialogOpenTitle = 'Otwrz plik SQL'; cSDialogSaveTitle = 'Zapisz plik SQL'; cSSQLEditor = 'Edytor SQL'; cSDatabaseDialog = 'Otwrz istniejc baz'; cSUpdateSQLNoResult = 'Update Refresh SQL nie zwrcio adnych danych'; cSUpdateSQLRefreshStatementcount ='Wyraenie Update Refresh SQL musi zwrci 1 rekord danych'; {$IFDEF FPC} cSNotEditing = 'Dataset nie jest w trybie "edit" lub "insert"'; cSFieldTypeMismatch = 'Niezgodno typw dla pola ''%s'', oczekiwano: %s otrzymano: %s'; cSFieldSizeMismatch = 'Niezgodno rozmiarw pola ''%s'', oczekiwano: %d otrzymano: %d'; {$ENDIF} cSNeedField = 'Pole %s jest wymagane.'; cSFailedtoInitPrepStmt = 'Nie udao si zainicjalizowa przygotowanego zapytania'; cSFailedtoPrepareStmt = 'Bd w wyraeniu podczas procesu przygotowania'; cSFailedToBindAllValues = 'Bd aplikacji podczas przypisywania danych'; cSAttemptExecOnBadPrep = 'Prba uruchomienia wyraenia przed zakoczeniem przygotowywania.'; cSBindingFailure = 'Bd przypisywania zbioru parametrw'; cSPreparedStmtExecFailure = 'Bd wykonania przygotowanego zapytania'; cSBoundVarStrIndexMissing = 'Nie istnieje zmienna licznikowa "%s"'; cSBindVarOutOfRange = 'Warto zmiennej licznikowej poza zakresem: %d'; cSFailedToBindResults = 'Bd aplikacji podczas czenia do wynikw zapytania'; //FOS+ 07112006 cSRefreshRowOnlySupportedWithUpdateObject = 'Metoda refreshrow jest obsugiwana tylko przez obiekt typu "update"'; cSMustBeInBrowseMode = 'Operacja jest dozwolona tylko w stanie dsBROWSE'; cSUnKnownParamDataType = 'Nieznany Param.DataType'; cSFieldReadOnly = 'Nie mona przypisa do pola tylko do odczytu wartoci: %d'; cSInvalidUpdateCount = 'Liczba zaktualizowanych rekordw: %d. tylko jeden rekord powinien by zaktualizowany.'; cSRowBufferWidthExceeded ='Translate: Row buffer width exceeded. Try using fewer or longer columns in SQL query.'; {$ELSE} // default: ENGLISH cSSQLError1 = 'SQL Error: %s'; cSSQLError2 = 'SQL Error: %s Code: %d'; cSSQLError3 = 'SQL Error: %s Code: %d SQL: %s'; cSSQLError4 = 'SQL Error: %s Code: %d Message: %s'; cSListCapacityError = 'List capacity out of bounds (%d)'; cSListCountError = 'List count out of bounds (%d)'; cSListIndexError = 'List index out of bounds (%d)'; cSClonningIsNotSupported = 'Clonning is not supported by this class'; cSImmutableOpIsNotAllowed = 'The operation is not allowed on not changeable collections'; cSStackIsEmpty = 'Stack is empty'; cSVariableWasNotFound = 'Variable "%s" was not found'; cSFunctionWasNotFound = 'Function "%s" was not found'; cSInternalError = 'Internal error'; cSSyntaxErrorNear = 'Syntax error near "%s"'; cSSyntaxError = 'Syntax error'; cSUnknownSymbol = 'Unknown symbol "%s"'; cSUnexpectedExprEnd = 'Unexpected end of expression'; cSRightBraceExpected = ') expected'; cSParametersError = '%d parameters were expected but %d were found'; cSExpectedMoreParams = 'More than two parameters are expected'; cSInvalidVarByteArray = 'Invalid VarByte array'; cSVariableAlreadyExists = 'Variable "%s" already exists'; cSTypesMismatch = 'Types mismatch'; cSUnsupportedVariantType = 'Unsupported variant type'; cSUnsupportedOperation = 'Unsupported operation'; cSTokenizerIsNotDefined = 'Tokenizer is not defined'; cSLibraryNotFound = 'None of the dynamic libraries can be found or is not loadable: %s !'#10#13'Use TZConnection.LibraryLocation if the location is invalid.'; cSEncodeDateIsNotSupported = 'This version does not support isc_encode_sql_date'; cSEncodeTimeIsNotSupported = 'This version does not support isc_encode_sql_time'; cSEncodeTimestampIsNotSupported = 'This version does not support isc_encode_sql_timestamp'; cSDecodeDateIsNotSupported = 'This version does not support isc_decode_sql_date'; cSDecodeTimeIsNotSupported = 'This version does not support isc_decode_sql_time'; cSDecodeTimestampIsNotSupported = 'This version does not support isc_decode_sql_timestamp'; cSCanNotRetrieveResultSetData = 'Cannot retrieve Resultset data'; cSRowBufferIsNotAssigned = 'Row buffer is not assigned'; cSColumnIsNotAccessable = 'Column with index %d is not accessable'; cSConvertionIsNotPossible = 'Convertion is not possible for column %d from %s to %s'; cSCanNotAccessBlobRecord = 'Cannot access blob record in column %d with type %s'; cSRowDataIsNotAvailable = 'Row data is not available'; cSResolverIsNotSpecified = 'Resolver is not specified for this ResultSet'; cSResultsetIsAlreadyOpened = 'Resultset is already open'; cSCanNotUpdateEmptyRow = 'Cannot update an empty row'; cSCanNotUpdateDeletedRow = 'Cannot update a deleted row'; cSCanNotDeleteEmptyRow = 'Cannot delete an empty row'; cSCannotUseCommit = 'You cannot use COMMIT in AUTOCOMMIT mode'; cSCannotUseRollBack = 'You cannot use ROLLBACK in AUTOCOMMIT mode'; cSCanNotUpdateComplexQuery = 'Cannot update a complex query with more then one table'; cSCanNotUpdateThisQueryType = 'Cannot update this query type'; cSDriverWasNotFound = 'Requested database driver was not found'; cSCanNotConnectToServer = 'Cannot connect to SQL server'; cSTableIsNotSpecified = 'Table is not specified'; cSLiveResultSetsAreNotSupported = 'Live query is not supported by this class'; cSInvalidInputParameterCount = 'Input parameter count is less then expected'; cSIsolationIsNotSupported = 'Transaction isolation level is not supported'; cSColumnWasNotFound = 'Column with name "%s" was not found'; cSWrongTypeForBlobParameter = 'Wrong type for Blob parameter'; cSIncorrectConnectionURL = 'Incorrect connection URL: %s'; cSUnsupportedProtocol = 'Unsupported protocol: %s'; cSUnsupportedByDriver = 'Driver can not support this feature natively: [%s]'; cSConnectionIsNotOpened = 'Connection is not opened yet'; cSInvalidOpInAutoCommit = 'Invalid operation in AutoCommit mode'; cSInvalidOpInNonAutoCommit = 'Invalid operation in non AutoCommit mode'; cSInvalidOpPrepare = 'Prepare transaction only possible on matching first(!) Starttransaction'; cSConnectionIsNotAssigned = 'Database connection component is not assigned'; cSQueryIsEmpty = 'SQL Query is empty'; cSCanNotExecuteMoreQueries = 'Cannot execute more then one query'; cSOperationIsNotAllowed1 = 'Operation is not allowed in FORWARD ONLY mode'; cSOperationIsNotAllowed2 = 'Operation is not allowed in READ ONLY mode'; cSOperationIsNotAllowed3 = 'Operation is not allowed in %s mode'; cSOperationIsNotAllowed4 = 'Operation is not allowed for closed dataset'; cSNoMoreRecords = 'No more records in the Resultset'; cSCanNotOpenResultSet = 'Can not open a Resultset'; cSCanNotOpenDataSetWhenDestroying ='Cannot open a dataset when the componentstate is dsDestroying'; cSCircularLink = 'Datasource makes a circular link'; cSBookmarkWasNotFound = 'Bookmark was not found'; cSIncorrectSearchFieldsNumber = 'Incorrect number of search field values'; cSInvalidOperationInTrans = 'Invalid operation in explicit transaction mode'; cSIncorrectSymbol = 'Incorrect symbol in field list "%s".'; cSIncorrectToken = 'Incorrect token followed by ":"'; cSIncorrectParamChar = 'Invalid value for ParamChar'; cSSelectedTransactionIsolation = 'Selected transaction isolation level is not supported'; cSDriverNotSupported = 'Driver not supported %s'; cSPattern2Long = 'Pattern is too long'; cSDriverNotCapableOutParameters = 'Driver is not capable to handle parameters'; cSStatementIsNotAllowed = 'Statement is not allowed'; cSStoredProcIsNotAllowed = 'The stored proc is not allowed'; cSCannotPerformOperation = 'Can not perform operation on closed Resultset'; cSInvalidState = 'Invalid state'; cSErrorConvertion = 'Convertion error'; cSDataTypeDoesNotSupported = 'Data type is not supported'; cSUnsupportedParameterType = 'Unsupported parameter type'; cSUnsupportedDataType = 'Unsupported data type'; cSErrorConvertionField = 'Conversion error for field "%s" to SQLType "%s"'; cSBadOCI = 'Bad OCI version [%s]. Version 8.0.3 or older is required'; cSConnect2AsUser = 'Connect to "%s" as user "%s"'; cSUnknownError = 'Unknown error'; cSFieldNotFound1 = 'Field "%s" was not found'; cSFieldNotFound2 = 'Field %d was not found'; cSLoginPromptFailure = 'Can not find default login prompt dialog. Please add DBLogDlg to the uses section of your main file.'; cSPropertyQuery = 'The Query may last a while on large databases!'; cSPropertyTables = 'You should limit it by Catalog and/or Schema.'; cSPropertyColumns = 'You should limit it by Catalog, Schema and/or TableName.'; cSPropertyProcedures = 'You should limit it by Catalog and/or Schema.'; cSPropertySequences = 'You should limit it by Catalog and/or Schema.'; cSPropertyExecute = 'Should the Query be executed anyway?'; cSFormTest = 'ZEOS SQL Editor Test'; cSButtonClose = '&Close'; cSFormEditor = 'ZEOS SQL Editor'; cSTabSheetSelect = 'Select SQL'; cSMenuLoad = 'Load'; cSMenuSave = 'Save'; cSButtonGenerate = '&Generate'; cSButtonCheck = 'C&heck'; cSButtonTest = '&Test'; cSButtonOk = '&OK'; cSButtonCancel = '&Cancel'; cSTableAlias = 'T&able alias'; cSReplaceSQL = '&Replace SQL'; cSDialogOpenTitle = 'Open SQL File'; cSDialogSaveTitle = 'Save SQL File'; cSSQLEditor = 'SQL Editor'; cSDatabaseDialog = 'Open existing database'; cSUpdateSQLNoResult = 'Update Refresh SQL delivered no resultset'; cSUpdateSQLRefreshStatementcount ='Update Refresh SQL Statement count must be 1'; {$IFDEF FPC} cSNotEditing = 'Dataset not in edit or insert mode'; cSFieldTypeMismatch = 'Type mismatch for field ''%s'', expecting: %s actual: %s'; cSFieldSizeMismatch = 'Size mismatch for field ''%s'', expecting: %d actual: %d'; {$ENDIF} cSNeedField = 'Field %s is required, but not supplied.'; cSFailedtoInitPrepStmt = 'Prepared statement failed to initialize'; cSFailedtoPrepareStmt = 'Statement failed during prepare process'; cSFailedToBindAllValues = 'Application failed to pre-bind all values'; cSAttemptExecOnBadPrep = 'Attempt made to execute a statement before a successful preparation.'; cSBindingFailure = 'Failed to bind parameter set'; cSPreparedStmtExecFailure = 'Prepared statement failed to execute'; cSBoundVarStrIndexMissing = 'Bound variable text index "%s" does not exist'; cSBindVarOutOfRange = 'Bound variable index out of range: %d'; cSFailedToBindResults = 'Application failed to bind to the result set'; //FOS+ 07112006 cSRefreshRowOnlySupportedWithUpdateObject = 'The refreshrow method is only supported with an update object'; cSMustBeInBrowseMode = 'Operation is only allowed in dsBROWSE state'; cSUnKnownParamDataType = 'Unknown Param.DataType'; cSFieldReadOnly = 'Readonly field can''t be assigned a value: %s'; cSInvalidUpdateCount = '%d record(s) updated. Only one record should have been updated.'; cSRowBufferWidthExceeded ='Row buffer width exceeded. Try using fewer or longer columns in SQL query.'; {$ENDIF} // POLISH {$ENDIF} // CZECH {$ENDIF} // RUSSIAN {$ENDIF} // INDONESIAN <--- added by tohenk {$ENDIF} // ROMANA {$ENDIF} //SPANISH {$ENDIF} // GERMAN {$ENDIF} // DUTCH {$ENDIF} // PORTUGUESE {$ENDIF FRENCH} var SSQLError1: String; SSQLError2: String; SSQLError3: String; SSQLError4: String; SListCapacityError: String; SListCountError: String; SListIndexError: String; SClonningIsNotSupported: String; SImmutableOpIsNotAllowed: String; SStackIsEmpty: String; SVariableWasNotFound: String; SFunctionWasNotFound: String; SInternalError: String; SSyntaxErrorNear: String; SSyntaxError: String; SUnknownSymbol: String; SUnexpectedExprEnd: String; SRightBraceExpected: String; SParametersError: String; SExpectedMoreParams: String; SInvalidVarByteArray: String; SVariableAlreadyExists: String; STypesMismatch: String; SUnsupportedVariantType: String; SUnsupportedOperation: String; STokenizerIsNotDefined: String; SLibraryNotFound: String; SLibraryNotCompatible: String; SEncodeDateIsNotSupported: String; SEncodeTimeIsNotSupported: String; SEncodeTimestampIsNotSupported: String; SDecodeDateIsNotSupported: String; SDecodeTimeIsNotSupported: String; SDecodeTimestampIsNotSupported: String; SCanNotRetrieveResultSetData: String; SRowBufferIsNotAssigned: String; SColumnIsNotAccessable: String; SConvertionIsNotPossible: String; SCanNotAccessBlobRecord: String; SRowDataIsNotAvailable: String; SResolverIsNotSpecified: String; SResultsetIsAlreadyOpened: String; SCanNotUpdateEmptyRow: String; SCanNotUpdateDeletedRow: String; SCanNotDeleteEmptyRow: String; SCannotUseCommit: String; SCannotUseRollBack: String; SCanNotUpdateComplexQuery: String; SCanNotUpdateThisQueryType: String; SDriverWasNotFound: String; SCanNotConnectToServer: String; STableIsNotSpecified: String; SLiveResultSetsAreNotSupported: String; SInvalidInputParameterCount: String; SIsolationIsNotSupported: String; SColumnWasNotFound: String; SWrongTypeForBlobParameter: String; SIncorrectConnectionURL: String; SUnsupportedProtocol: String; SUnsupportedByDriver : String; SConnectionIsNotOpened: String; SInvalidOpInAutoCommit: String; SInvalidOpInNonAutoCommit: String; SInvalidOpPrepare: String; SConnectionIsNotAssigned: String; SQueryIsEmpty: String; SCanNotExecuteMoreQueries: String; SOperationIsNotAllowed1: String; SOperationIsNotAllowed2: String; SOperationIsNotAllowed3: String; SOperationIsNotAllowed4: String; SNoMoreRecords: String; SCanNotOpenResultSet: String; SCanNotOpenDataSetWhenDestroying: String; SCircularLink: String; SBookmarkWasNotFound: String; SIncorrectSearchFieldsNumber: String; SInvalidOperationInTrans: String; SIncorrectSymbol: String; SIncorrectToken: String; SIncorrectParamChar: String; SSelectedTransactionIsolation: String; SDriverNotSupported: String; SPattern2Long: String; SDriverNotCapableOutParameters: String; SStatementIsNotAllowed: String; SStoredProcIsNotAllowed: String; SCannotPerformOperation: String; SInvalidState: String; SErrorConvertion: String; SDataTypeDoesNotSupported: String; SUnsupportedParameterType: String; SUnsupportedDataType: String; SErrorConvertionField: String; SBadOCI: String; SConnect2AsUser: String; SUnknownError: String; SFieldNotFound1: String; SFieldNotFound2: String; SLoginPromptFailure: String; SPropertyQuery: String; SPropertyTables: String; SPropertyColumns: String; SPropertyProcedures: String; SPropertySequences: String; SPropertyExecute: String; SFormTest: String; SButtonClose: String; SFormEditor: String; STabSheetSelect: String; SMenuLoad: String; SMenuSave: String; SButtonGenerate: String; SButtonCheck: String; SButtonTest: String; SButtonOk: String; SButtonCancel: String; STableAlias: String; SReplaceSQL: String; SDialogOpenTitle: String; SDialogSaveTitle: String; SSQLEditor: String; SDatabaseDialog: String; SUpdateSQLNoResult: String; SUpdateSQLRefreshStatementcount: String; {$IFDEF FPC} SNotEditing: String; SFieldTypeMismatch: String; SFieldSizeMismatch: String; {$ENDIF} SNeedField: String; SFailedtoInitPrepStmt: String; SFailedtoPrepareStmt: String; SFailedToBindAllValues: String; SAttemptExecOnBadPrep: String; SBindingFailure: String; SPreparedStmtExecFailure: String; SBoundVarStrIndexMissing: String; SBindVarOutOfRange: String; SFailedToBindResults: String; SRefreshRowOnlySupportedWithUpdateObject: String; SMustBeInBrowseMode: String; SUnKnownParamDataType: String; SFieldReadOnly: String; SInvalidUpdateCount: String; SRowBufferWidthExceeded: String; implementation procedure loadmessages(); begin SSQLError1 := cSSQLError1; SSQLError2 := cSSQLError2; SSQLError3 := cSSQLError3; SSQLError4 := cSSQLError4; SListCapacityError := cSListCapacityError; SListCountError := cSListCountError; SListIndexError := cSListIndexError; SClonningIsNotSupported := cSClonningIsNotSupported; SImmutableOpIsNotAllowed := cSImmutableOpIsNotAllowed; SStackIsEmpty := cSStackIsEmpty; SVariableWasNotFound := cSVariableWasNotFound; SFunctionWasNotFound := cSFunctionWasNotFound; SInternalError := cSInternalError; SSyntaxErrorNear := cSSyntaxErrorNear; SSyntaxError := cSSyntaxError; SUnknownSymbol := cSUnknownSymbol; SUnexpectedExprEnd := cSUnexpectedExprEnd; SRightBraceExpected := cSRightBraceExpected; SParametersError := cSParametersError; SExpectedMoreParams := cSExpectedMoreParams; SInvalidVarByteArray := cSInvalidVarByteArray; SVariableAlreadyExists := cSVariableAlreadyExists; STypesMismatch := cSTypesMismatch; SUnsupportedVariantType := cSUnsupportedVariantType; SUnsupportedOperation := cSUnsupportedOperation; STokenizerIsNotDefined := cSTokenizerIsNotDefined; SLibraryNotFound := cSLibraryNotFound; SLibraryNotCompatible := cSLibraryNotCompatible; SEncodeDateIsNotSupported := cSEncodeDateIsNotSupported; SEncodeTimeIsNotSupported := cSEncodeTimeIsNotSupported; SEncodeTimestampIsNotSupported := cSEncodeTimestampIsNotSupported; SDecodeDateIsNotSupported := cSDecodeDateIsNotSupported; SDecodeTimeIsNotSupported := cSDecodeTimeIsNotSupported; SDecodeTimestampIsNotSupported := cSDecodeTimestampIsNotSupported; SCanNotRetrieveResultSetData := cSCanNotRetrieveResultSetData; SRowBufferIsNotAssigned := cSRowBufferIsNotAssigned; SColumnIsNotAccessable := cSColumnIsNotAccessable; SConvertionIsNotPossible := cSConvertionIsNotPossible; SCanNotAccessBlobRecord := cSCanNotAccessBlobRecord; SRowDataIsNotAvailable := cSRowDataIsNotAvailable; SResolverIsNotSpecified := cSResolverIsNotSpecified; SResultsetIsAlreadyOpened := cSResultsetIsAlreadyOpened; SCanNotUpdateEmptyRow := cSCanNotUpdateEmptyRow; SCanNotUpdateDeletedRow := cSCanNotUpdateDeletedRow; SCanNotDeleteEmptyRow := cSCanNotDeleteEmptyRow; SCannotUseCommit := cSCannotUseCommit; SCannotUseRollBack := cSCannotUseRollBack; SCanNotUpdateComplexQuery := cSCanNotUpdateComplexQuery; SCanNotUpdateThisQueryType := cSCanNotUpdateThisQueryType; SDriverWasNotFound := cSDriverWasNotFound; SCanNotConnectToServer := cSCanNotConnectToServer; STableIsNotSpecified := cSTableIsNotSpecified; SLiveResultSetsAreNotSupported := cSLiveResultSetsAreNotSupported; SInvalidInputParameterCount := cSInvalidInputParameterCount; SIsolationIsNotSupported := cSIsolationIsNotSupported; SColumnWasNotFound := cSColumnWasNotFound; SWrongTypeForBlobParameter := cSWrongTypeForBlobParameter; SIncorrectConnectionURL := cSIncorrectConnectionURL; SUnsupportedProtocol := cSUnsupportedProtocol; SUnsupportedByDriver := cSUnsupportedByDriver; SConnectionIsNotOpened := cSConnectionIsNotOpened; SInvalidOpInAutoCommit := cSInvalidOpInAutoCommit; SInvalidOpInNonAutoCommit := cSInvalidOpInNonAutoCommit; SInvalidOpPrepare := cSInvalidOpPrepare; SConnectionIsNotAssigned := cSConnectionIsNotAssigned; SQueryIsEmpty := cSQueryIsEmpty; SCanNotExecuteMoreQueries := cSCanNotExecuteMoreQueries; SOperationIsNotAllowed1 := cSOperationIsNotAllowed1; SOperationIsNotAllowed2 := cSOperationIsNotAllowed2; SOperationIsNotAllowed3 := cSOperationIsNotAllowed3; SOperationIsNotAllowed4 := cSOperationIsNotAllowed4; SNoMoreRecords := cSNoMoreRecords; SCanNotOpenResultSet := cSCanNotOpenResultSet; SCanNotOpenDataSetWhenDestroying := cSCanNotOpenDataSetWhenDestroying; SCircularLink := cSCircularLink; SBookmarkWasNotFound := cSBookmarkWasNotFound; SIncorrectSearchFieldsNumber := cSIncorrectSearchFieldsNumber; SInvalidOperationInTrans := cSInvalidOperationInTrans; SIncorrectSymbol := cSIncorrectSymbol; SIncorrectToken := cSIncorrectToken; SIncorrectParamChar := cSIncorrectParamChar; SSelectedTransactionIsolation := cSSelectedTransactionIsolation; SDriverNotSupported := cSDriverNotSupported; SPattern2Long := cSPattern2Long; SDriverNotCapableOutParameters := cSDriverNotCapableOutParameters; SStatementIsNotAllowed := cSStatementIsNotAllowed; SStoredProcIsNotAllowed := cSStoredProcIsNotAllowed; SCannotPerformOperation := cSCannotPerformOperation; SInvalidState := cSInvalidState; SErrorConvertion := cSErrorConvertion; SDataTypeDoesNotSupported := cSDataTypeDoesNotSupported; SUnsupportedParameterType := cSUnsupportedParameterType; SUnsupportedDataType := cSUnsupportedDataType; SErrorConvertionField := cSErrorConvertionField; SBadOCI := cSBadOCI; SConnect2AsUser := cSConnect2AsUser; SUnknownError := cSUnknownError; SFieldNotFound1 := cSFieldNotFound1; SFieldNotFound2 := cSFieldNotFound2; SLoginPromptFailure := cSLoginPromptFailure; SPropertyQuery := cSPropertyQuery; SPropertyTables := cSPropertyTables; SPropertyColumns := cSPropertyColumns; SPropertyProcedures := cSPropertyProcedures; SPropertySequences := cSPropertySequences; SPropertyExecute := cSPropertyExecute; SFormTest := cSFormTest; SButtonClose := cSButtonClose; SFormEditor := cSFormEditor; STabSheetSelect := cSTabSheetSelect; SMenuLoad := cSMenuLoad; SMenuSave := cSMenuSave; SButtonGenerate := cSButtonGenerate; SButtonCheck := cSButtonCheck; SButtonTest := cSButtonTest; SButtonOk := cSButtonOk; SButtonCancel := cSButtonCancel; STableAlias := cSTableAlias; SReplaceSQL := cSReplaceSQL; SDialogOpenTitle := cSDialogOpenTitle; SDialogSaveTitle := cSDialogSaveTitle; SSQLEditor := cSSQLEditor; SDatabaseDialog := cSDatabaseDialog; SUpdateSQLNoResult := cSUpdateSQLNoResult; SUpdateSQLRefreshStatementcount := cSUpdateSQLRefreshStatementcount; {$IFDEF FPC} SNotEditing := cSNotEditing; SFieldTypeMismatch := cSFieldTypeMismatch; SFieldSizeMismatch := cSFieldSizeMismatch; {$ENDIF} SNeedField := cSNeedField; SFailedtoInitPrepStmt := cSFailedtoInitPrepStmt; SFailedtoPrepareStmt := cSFailedtoPrepareStmt; SFailedToBindAllValues := cSFailedToBindAllValues; SAttemptExecOnBadPrep := cSAttemptExecOnBadPrep; SBindingFailure := cSBindingFailure; SPreparedStmtExecFailure := cSPreparedStmtExecFailure; SBoundVarStrIndexMissing := cSBoundVarStrIndexMissing; SBindVarOutOfRange := cSBindVarOutOfRange; SFailedToBindResults := cSFailedToBindResults; SRefreshRowOnlySupportedWithUpdateObject := cSRefreshRowOnlySupportedWithUpdateObject; SMustBeInBrowseMode := cSMustBeInBrowseMode; SUnKnownParamDataType := cSUnKnownParamDataType; SFieldReadOnly := cSFieldReadOnly; SInvalidUpdateCount := cSInvalidUpdateCount; SRowBufferWidthExceeded := cSRowBufferWidthExceeded; end; initialization loadmessages; end. ================================================ FILE: lib/zeosdbo/src/core/ZSysUtils.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { System Utility Classes and Functions } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZSysUtils; interface {$I ZCore.inc} uses Variants, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, Types, ZMessages, ZCompatibility; type {** Modified comaprison function. } TZListSortCompare = function (Item1, Item2: Pointer): Integer of object; {** Modified list of pointers. } TZSortedList = class (TList) protected procedure QuickSort(SortList: PPointerList; L, R: Integer; SCompare: TZListSortCompare); public procedure Sort(Compare: TZListSortCompare); end; {** Determines a position of a first delimiter. @param Delimiters a string with possible delimiters. @param Str a string to be checked. @return a position of the first found delimiter or 0 if no delimiters was found. } function FirstDelimiter(const Delimiters, Str: string): Integer; {** Determines a position of a LAST delimiter. @param Delimiters a string with possible delimiters. @param Str a string to be checked. @return a position of the last found delimiter or 0 if no delimiters was found. } function LastDelimiter(const Delimiters, Str: string): Integer; {** Compares two PWideChars without stopping at #0 (Unicode Version) @param P1 first PWideChars @param P2 seconds PWideChars @return True if the memory at P1 and P2 are equal } function MemLCompUnicode(P1, P2: PWideChar; Len: Integer): Boolean; {** Compares two PAnsiChars without stopping at #0 @param P1 first PAnsiChar @param P2 seconds PAnsiChar @return True if the memory at P1 and P2 are equal } function MemLCompAnsi(P1, P2: PAnsiChar; Len: Integer): Boolean; {** Checks is the string starts with substring. @param Str a string to be checked. @param SubStr a string to test at the start of the Str. @return True if Str started with SubStr; } function StartsWith(const Str, SubStr: ZWideString): Boolean; overload; function StartsWith(const Str, SubStr: RawByteString): Boolean; overload; {** Checks is the string ends with substring. @param Str a string to be checked. @param SubStr a string to test at the end of the Str. @return True if Str ended with SubStr; } function EndsWith(const Str, SubStr: ZWideString): Boolean; overload; function EndsWith(const Str, SubStr: RawByteString): Boolean; overload; {** Converts SQL string into float value. @param Str an SQL string with comma delimiter. @param Def a default value if the string can not be converted. @return a converted value or Def if conversion was failt. } {$IFDEF WITH_RAWBYTESTRING} function SQLStrToFloatDef(Str: RawByteString; Def: Extended): Extended; overload; {$ENDIF} function SQLStrToFloatDef(Str: String; Def: Extended): Extended; overload; {** Converts SQL string into float value. @param Str an SQL string with comma delimiter. @return a converted value or Def if conversion was failt. } function SQLStrToFloat(const Str: AnsiString): Extended; {** Converts a character buffer into pascal string. @param Buffer a character buffer pointer. @param Length a buffer length. @return a string retrived from the buffer. } function BufferToStr(Buffer: PWideChar; Length: LongInt): string; overload; function BufferToStr(Buffer: PAnsiChar; Length: LongInt): string; overload; function BufferToBytes(Buffer: Pointer; Length: LongInt): TByteDynArray; {** Converts a string into boolean value. @param Str a string value. @return True is Str = 'Y'/'YES'/'T'/'TRUE'/<>0 } function StrToBoolEx(Str: string): Boolean; {** Converts a boolean into string value. @param Bool a boolean value. @return "True" or "False" } function BoolToStrEx(Bool: Boolean): String; {** Checks if the specified string can represent an IP address. @param Str a string value. @return True if the string can represent an IP address or False otherwise. } function IsIpAddr(const Str: string): Boolean; {** Splits string using the multiple chars. @param Str the source string @param Delimiters the delimiters string @return the result list where plased delimited string } function SplitString(const Str, Delimiters: string): TStrings; {** Puts to list a splitted string using the multiple chars which replaces the previous list content. @param List a list with strings. @param Str the source string @param Delimiters the delimiters string } procedure PutSplitString(List: TStrings; const Str, Delimiters: string); {** Appends to list a splitted string using the multiple chars. @param List a list with strings. @param Str the source string @param Delimiters the delimiters string } procedure AppendSplitString(List: TStrings; const Str, Delimiters: string); {** Composes a string from the specified strings list delimited with a special character. @param List a list of strings. @param Delimiter a delimiter string. @return a composed string from the list. } function ComposeString(List: TStrings; const Delimiter: string): string; {** Converts a float value into SQL string with '.' delimiter. @param Value a float value to be converted. @return a converted string value. } function FloatToSQLStr(Value: Extended): string; {** Puts to list a splitted string using the delimiter string which replaces the previous list content. @param List a list with strings. @param Str the source string @param Delimiters the delimiter string } procedure PutSplitStringEx(List: TStrings; const Str, Delimiter: string); {** Splits string using the delimiter string. @param Str the source string @param Delimiters the delimiter string @return the result list where plased delimited string } function SplitStringEx(const Str, Delimiter: string): TStrings; {** Appends to list a splitted string using the delimeter string. @param List a list with strings. @param Str the source string @param Delimiters the delimiters string } procedure AppendSplitStringEx(List: TStrings; const Str, Delimiter: string); {** Converts bytes into a AnsiString representation. @param Value an array of bytes to be converted. @return a converted AnsiString. } function BytesToStr(const Value: TByteDynArray): AnsiString; {** Converts AnsiString into an array of bytes. @param Value a AnsiString to be converted. @return a converted array of bytes. } function StrToBytes(const Value: AnsiString): TByteDynArray; overload; {$IFDEF WITH_RAWBYTESTRING} {** Converts a UTF8String into an array of bytes. @param Value a UTF8String to be converted. @return a converted array of bytes. } function StrToBytes(const Value: UTF8String): TByteDynArray; overload; {** Converts a UTF8String into an array of bytes. @param Value a UTF8String to be converted. @return a converted array of bytes. } function StrToBytes(const Value: RawByteString): TByteDynArray; overload; {** Converts a RawByteString into an array of bytes. @param Value a RawByteString to be converted. @return a converted array of bytes. } {$ENDIF} function StrToBytes(const Value: WideString): TByteDynArray; overload; {** Converts a String into an array of bytes. @param Value a String to be converted. @return a converted array of bytes. } {$IFDEF PWIDECHAR_IS_PUNICODECHAR} function StrToBytes(const Value: UnicodeString): TByteDynArray; overload; {$ENDIF} {** Converts bytes into a variant representation. @param Value an array of bytes to be converted. @return a converted variant. } function BytesToVar(const Value: TByteDynArray): Variant; {** Converts variant into an array of bytes. @param Value a varaint to be converted. @return a converted array of bytes. } function VarToBytes(const Value: Variant): TByteDynArray; {** Converts Ansi SQL Date/Time to TDateTime @param Value a date and time string. @return a decoded TDateTime value. } function AnsiSQLDateToDateTime(const Value: string): TDateTime; {** Converts Timestamp String to TDateTime @param Value a timestamp string. @return a decoded TDateTime value. } function TimestampStrToDateTime(const Value: string): TDateTime; {** Converts TDateTime to Ansi SQL Date/Time @param Value an encoded TDateTime value. @return a date and time string. } function DateTimeToAnsiSQLDate(Value: TDateTime; WithMMSec: Boolean = False): string; {** Converts an string into escape PostgreSQL format. @param Value a regular string. @return a string in PostgreSQL escape format. } function EncodeCString(const Value: string): string; {** Converts an string from escape PostgreSQL format. @param Value a string in PostgreSQL escape format. @return a regular string. } function DecodeCString(const Value: string): string; {** Replace chars in the string @param Source a char to search. @param Target a char to replace. @param Str a source string. @return a string with replaced chars. } function ReplaceChar(const Source, Target: Char; const Str: string): string; {** Copy buffer to the pascal string @param Buffer a buffer with data @param Length a buffer length @return a buffer content } function MemPas(Buffer: PChar; Length: LongInt): string; {** Decodes a Full Version Value encoded with the format: (major_version * 1,000,000) + (minor_version * 1,000) + sub_version into separated major, minor and subversion values @param FullVersion an integer containing the Full Version to decode. @param MajorVersion an integer containing the Major Version decoded. @param MinorVersion an integer containing the Minor Version decoded. @param SubVersion an integer contaning the Sub Version (revision) decoded. } procedure DecodeSQLVersioning(const FullVersion: Integer; out MajorVersion: Integer; out MinorVersion: Integer; out SubVersion: Integer); {** Encodes major, minor and subversion (revision) values in this format: (major_version * 1,000,000) + (minor_version * 1,000) + sub_version For example, 4.1.12 is returned as 4001012. @param MajorVersion an integer containing the Major Version. @param MinorVersion an integer containing the Minor Version. @param SubVersion an integer containing the Sub Version (revision). @return an integer containing the full version. } function EncodeSQLVersioning(const MajorVersion: Integer; const MinorVersion: Integer; const SubVersion: Integer): Integer; {** Formats a Zeos SQL Version format to X.Y.Z where: X = major_version Y = minor_version Z = sub version @param SQLVersion an integer @return Formated Zeos SQL Version Value. } function FormatSQLVersion( const SQLVersion: Integer ): String; {** Arranges thousand and decimal separator to a System-defaults @param the value which has to be converted and arranged @return a valid floating value } function ZStrToFloat(Value: PAnsiChar): Extended; overload; {** Arranges thousand and decimal separator to a System-defaults @param the value which has to be converted and arranged @return a valid floating value } function ZStrToFloat(Value: AnsiString): Extended; overload; procedure ZSetString(const Src: PAnsiChar; var Dest: AnsiString); overload; procedure ZSetString(const Src: PAnsiChar; const Len: Cardinal; var Dest: AnsiString); overload; procedure ZSetString(const Src: PAnsiChar; var Dest: UTF8String); overload; procedure ZSetString(const Src: PAnsiChar; const Len: Cardinal; var Dest: UTF8String); overload; procedure ZSetString(const Src: PAnsiChar; const Len: Cardinal; var Dest: ZWideString); overload; {$IFDEF WITH_RAWBYTESTRING} procedure ZSetString(const Src: PAnsiChar; var Dest: RawByteString); overload; procedure ZSetString(const Src: PAnsiChar; const Len: Cardinal; var Dest: RawByteString); overload; {$ENDIF} implementation uses ZMatchPattern, StrUtils {$IFDEF WITH_UNITANSISTRINGS}, AnsiStrings{$ENDIF}; {** Determines a position of a first delimiter. @param Delimiters a string with possible delimiters. @param Str a string to be checked. @return a position of the first found delimiter or 0 if no delimiters was found. } function FirstDelimiter(const Delimiters, Str: string): Integer; var I, Index: Integer; begin Result := 0; for I := 1 to Length(Delimiters) do begin Index := Pos(Delimiters[I], Str); if (Index > 0) and ((Index < Result) or (Result = 0)) then Result := Index; end; end; {** Determines a position of a LAST delimiter. @param Delimiters a string with possible delimiters. @param Str a string to be checked. @return a position of the last found delimiter or 0 if no delimiters was found. } function LastDelimiter(const Delimiters, Str: string): Integer; var I, Index: Integer; begin Result := 0; for I := Length(Str) downto 1 do begin Index := Pos(Str[I], Delimiters); if (Index > 0) then begin Result := I; Break; end; end; end; {** Compares two PWideChars without stopping at #0 (Unicode Version) @param P1 first PWideChar @param P2 seconds PWideChar @return True if the memory at P1 and P2 are equal } function MemLCompUnicode(P1, P2: PWideChar; Len: Integer): Boolean; begin while (Len > 0) and (P1^ = P2^) do begin Inc(P1); Inc(P2); Dec(Len); end; Result := Len = 0; end; {** Compares two PAnsiChars without stopping at #0 @param P1 first PAnsiChar @param P2 seconds PAnsiChar @return True if the memory at P1 and P2 are equal } function MemLCompAnsi(P1, P2: PAnsiChar; Len: Integer): Boolean; begin while (Len > 0) and (P1^ = P2^) do begin Inc(P1); Inc(P2); Dec(Len); end; Result := Len = 0; end; {** Checks is the string starts with substring. @param Str a string to be checked. @param SubStr a string to test at the start of the Str. @return True if Str started with SubStr; } function StartsWith(const Str, SubStr: ZWideString): Boolean; var LenSubStr: Integer; begin LenSubStr := Length(SubStr); if SubStr = '' then Result := True else if LenSubStr <= Length(Str) then Result := MemLCompUnicode(PWideChar(Str), PWideChar(SubStr), LenSubStr) else Result := False; end; function StartsWith(const Str, SubStr: RawByteString): Boolean; overload; var LenSubStr: Integer; begin LenSubStr := Length(SubStr); if SubStr = '' then Result := True else if LenSubStr <= Length(Str) then Result := MemLCompAnsi(PAnsiChar(Str), PAnsiChar(SubStr), LenSubStr) else Result := False; end; {** Checks is the string ends with substring. @param Str a string to be checked. @param SubStr a string to test at the end of the Str. @return True if Str ended with SubStr; } function EndsWith(const Str, SubStr: ZWideString): Boolean; var LenSubStr: Integer; LenStr: Integer; begin if SubStr = '' then Result := False // act like Delphi's AnsiEndsStr() else begin LenSubStr := Length(SubStr); LenStr := Length(Str); if LenSubStr <= LenStr then Result := MemLCompUnicode(PWideChar(Pointer(Str)) + LenStr - LenSubStr, Pointer(SubStr), LenSubStr) else Result := False; end; end; function EndsWith(const Str, SubStr: RawByteString): Boolean; var LenSubStr: Integer; LenStr: Integer; begin if SubStr = '' then Result := False // act like Delphi's AnsiEndsStr() else begin LenSubStr := Length(SubStr); LenStr := Length(Str); if LenSubStr <= LenStr then Result := MemLCompAnsi(PAnsiChar(Pointer(Str)) + LenStr - LenSubStr, Pointer(SubStr), LenSubStr) else Result := False; end; end; function ConvertMoneyToFloat(MoneyString: String): String; var I: Integer; begin if MoneyString = '' then Result := '' else begin if CharInSet(Char(MoneyString[1]), ['0'..'9', '-']) then Result := MoneyString else for i := 1 to Length(MoneyString) do if CharInSet(Char(MoneyString[I]), ['0'..'9', '-']) then begin if I > 1 then begin //Money type Result := Copy(MoneyString, I, Length(MoneyString)-i+1); if Pos(',', Result) > 0 then if Pos('.', Result) > 0 then begin Result := Copy(Result, 1, Pos(',', Result)-1); while Pos('.', Result) > 0 do Result := Copy(Result, 1, Pos('.', Result)-1)+Copy(Result, Pos('.', Result)+1, Length(Result)); //remove ThousandSeparator Result := Result + '.'+Copy(MoneyString, Pos(',', MoneyString)+1, Length(MoneyString)); end else Result[Pos(',', Result)] := '.'; end; Break; end; end; end; {** Converts SQL string into float value. @param Str an SQL string with comma delimiter. @param Def a default value if the string can not be converted. @return a converted value or Def if conversion was failt. } {$IFDEF WITH_RAWBYTESTRING} function SQLStrToFloatDef(Str: RawByteString; Def: Extended): Extended; var OldDecimalSeparator: Char; OldThousandSeparator: Char; AString: String; begin if Str = '' then Result := Def else begin OldDecimalSeparator := {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}DecimalSeparator; OldThousandSeparator := {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}ThousandSeparator; {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}DecimalSeparator := '.'; {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}ThousandSeparator := ','; if not CharInSet(Char(String(Str)[1]), ['0'..'9', '-']) then AString := ConvertMoneyToFloat(String(Str)) else AString := String(Str); Result := StrToFloatDef(AString, Def); {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}DecimalSeparator := OldDecimalSeparator; {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}ThousandSeparator := OldThousandSeparator; end; end; {$ENDIF} function SQLStrToFloatDef(Str: String; Def: Extended): Extended; var OldDecimalSeparator: Char; OldThousandSeparator: Char; AString: String; begin if Str = '' then Result := Def else begin OldDecimalSeparator := {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}DecimalSeparator; OldThousandSeparator := {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}ThousandSeparator; {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}DecimalSeparator := '.'; {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}ThousandSeparator := ','; if not CharInSet(Char(Str[1]), ['0'..'9', '-']) then AString := ConvertMoneyToFloat(Str) else AString := Str; Result := StrToFloatDef(AString, Def); {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}DecimalSeparator := OldDecimalSeparator; {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}ThousandSeparator := OldThousandSeparator; end; end; {** Converts SQL string into float value. @param Str an SQL string with comma delimiter. @return a converted value or Def if conversion was failt. } function SQLStrToFloat(const Str: AnsiString): Extended; var OldDecimalSeparator: Char; begin OldDecimalSeparator := {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}DecimalSeparator; {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}DecimalSeparator := '.'; try Result := StrToFloat(String(Str)); finally {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}DecimalSeparator := OldDecimalSeparator; end; end; { Convert string buffer into pascal string } function BufferToStr(Buffer: PWideChar; Length: LongInt): string; var s : Widestring; begin Result := ''; if Assigned(Buffer) then begin SetString(s, Buffer, Length div SizeOf(Char)); Result := s; end; end; { Convert string buffer into pascal string } function BufferToStr(Buffer: PAnsiChar; Length: LongInt): string; begin Result := ''; if Assigned(Buffer) then SetString(Result, Buffer, Length); end; function BufferToBytes(Buffer: Pointer; Length: LongInt): TByteDynArray; begin SetLength(Result, Length); System.Move(Buffer^, Pointer(Result)^, Length); end; {** Converts a string into boolean value. @param Str a string value. @return True is Str = 'Y'/'YES'/'T'/'TRUE'/<>0 } function StrToBoolEx(Str: string): Boolean; begin Str := UpperCase(Str); Result := (Str = 'Y') or (Str = 'YES') or (Str = 'T') or (Str = 'TRUE') or (StrToIntDef(Str, 0) <> 0); end; {** Converts a boolean into string value. @param Bool a boolean value. @return "True" or "False" } function BoolToStrEx(Bool: Boolean): String; begin if Bool then Result := 'True' else Result := 'False'; end; {** Checks if the specified string can represent an IP address. @param Str a string value. @return True if the string can represent an IP address or False otherwise. } function IsIpAddr(const Str: string): Boolean; var I, N, M, Pos, Val: Integer; begin if IsMatch('*.*.*.*', Str) then begin N := 0; M := 0; Pos := 1; for I := 1 to Length(Str) do begin if I - Pos > 3 then Break; if Str[I] = '.' then begin {ticked #73/#24 patch } Val := StrToIntDef(Copy(Str, Pos, I - Pos), -1); if not ((Val > -1 ) and (Val < 256)) then Break; Inc(N); Pos := I + 1; end; if CharInSet(Str[I], ['0'..'9']) then Inc(M); end; Result := (M + N = Length(Str)) and (N = 3); end else Result := False; end; procedure SplitToStringList(List: TStrings; Str: string; const Delimiters: string); var DelimPos: Integer; begin repeat DelimPos := FirstDelimiter(Delimiters, Str); if DelimPos > 0 then begin if DelimPos > 1 then List.Add(Copy(Str, 1, DelimPos - 1)); Str := Copy(Str, DelimPos + 1, Length(Str) - DelimPos); end else Break; until DelimPos <= 0; if Str <> '' then List.Add(Str); end; {** Splits string using the multiple chars. @param Str the source string @param Delimiters the delimiters string @return the result list where plased delimited string } function SplitString(const Str, Delimiters: string): TStrings; begin Result := TStringList.Create; try SplitToStringList(Result, Str, Delimiters); except Result.Free; raise; end; end; {** Puts to list a splitted string using the multiple chars which replaces the previous list content. @param List a list with strings. @param Str the source string @param Delimiters the delimiters string } procedure PutSplitString(List: TStrings; const Str, Delimiters: string); begin List.Clear; SplitToStringList(List, Str, Delimiters); end; {** Appends to list a splitted string using the multiple chars. @param List a list with strings. @param Str the source string @param Delimiters the delimiters string } procedure AppendSplitString(List: TStrings; const Str, Delimiters: string); begin SplitToStringList(List, Str, Delimiters); end; {** Composes a string from the specified strings list delimited with a special character. @param List a list of strings. @param Delimiter a delimiter string. @return a composed string from the list. } function ComposeString(List: TStrings; const Delimiter: string): string; var i, Len, DelimLen: Integer; S: string; P: PChar; begin DelimLen := Length(Delimiter); Len := 0; if List.Count > 0 then begin Inc(Len, Length(List[0])); for i := 1 to List.Count - 1 do Inc(Len, DelimLen + Length(List[i])); end; SetLength(Result, Len); P := Pointer(Result); for i := 0 to List.Count - 1 do begin if (i > 0) and (DelimLen > 0) then begin Move(Pointer(Delimiter)^, P^, DelimLen * SizeOf(Char)); Inc(P, DelimLen); end; S := List[i]; Len := Length(S); if Len > 0 then begin Move(Pointer(S)^, P^, Len * SizeOf(Char)); Inc(P, Len); end; end; end; {** Converts a float value into SQL string with '.' delimiter. @param Value a float value to be converted. @return a converted string value. } function FloatToSQLStr(Value: Extended): string; var OldDecimalSeparator: Char; begin OldDecimalSeparator := {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}DecimalSeparator; {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}DecimalSeparator := '.'; try Result := FloatToStr(Value); finally {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}DecimalSeparator := OldDecimalSeparator; end; end; {** Split a single string using the delimiter, appending the resulting strings to the List. (gto: New version, now unicode safe and without the bug which adds a blank line before the last found string) @param List a list to append the result. @param Str the source string @param Delimiters the delimiter string } procedure SplitToStringListEx(List: TStrings; const Str, Delimiter: string); var temp: string; i: integer; begin temp := Str + Delimiter; repeat i := List.Add(Copy(temp, 0, AnsiPos(Delimiter, temp) - 1)); Delete(temp, 1, Length(List[i] + Delimiter)); until temp = ''; end; {** Puts to list a splitted string using the delimiter string which replaces the previous list content. @param List a list with strings. @param Str the source string @param Delimiters the delimiter string } procedure PutSplitStringEx(List: TStrings; const Str, Delimiter: string); begin List.Clear; SplitToStringListEx(List, Str, Delimiter); end; {** Splits string using the delimiter string. @param Str the source string @param Delimiters the delimiter string @return the result list where plased delimited string } function SplitStringEx(const Str, Delimiter: string): TStrings; begin Result := TStringList.Create; try SplitToStringListEx(Result, Str, Delimiter); except Result.Free; raise; end; end; {** Appends to list a splitted string using the delimeter string. @param List a list with strings. @param Str the source string @param Delimiters the delimiters string } procedure AppendSplitStringEx(List: TStrings; const Str, Delimiter: string); begin SplitToStringListEx(List, Str, Delimiter); end; {** Converts bytes into a AnsiString representation. @param Value an array of bytes to be converted. @return a converted AnsiString. } function BytesToStr(const Value: TByteDynArray): AnsiString; begin SetString(Result, PAnsiChar(@Value[0]), Length(Value)) end; {** Converts AnsiString into an array of bytes. @param Value a AnsiString to be converted. @return a converted array of bytes. } function StrToBytes(const Value: AnsiString): TByteDynArray; var L: Integer; begin L := Length(Value); SetLength(Result, L); if Value <> '' then Move(Value[1], Result[0], L) end; {$IFDEF WITH_RAWBYTESTRING} {** Converts a UTF8String into an array of bytes. @param Value a UTF8String to be converted. @return a converted array of bytes. } function StrToBytes(const Value: UTF8String): TByteDynArray; var L: Integer; begin L := Length(Value); SetLength(Result, L); if Value <> '' then Move(Value[1], Result[0], L) end; {** Converts a RawByteString into an array of bytes. @param Value a RawByteString to be converted. @return a converted array of bytes. } function StrToBytes(const Value: RawByteString): TByteDynArray; var L: Integer; begin L := Length(Value); SetLength(Result, L); if Value <> '' then Move(Value[1], Result[0], L) end; {$ENDIF} {** Converts a WideString into an array of bytes. @param Value a String to be converted. @return a converted array of bytes. } function StrToBytes(const Value: WideString): TByteDynArray; var L: Integer; begin L := Length(Value)*2; SetLength(Result, L); if Value <> '' then Move(Value[1], Result[0], L) end; {** Converts a String into an array of bytes. @param Value a String to be converted. @return a converted array of bytes. } {$IFDEF PWIDECHAR_IS_PUNICODECHAR} function StrToBytes(const Value: UnicodeString): TByteDynArray; var L: Integer; begin L := Length(Value) * SizeOf(Char); SetLength(Result, L); if Value <> '' then Move(Value[1], Result[0], L) end; {$ENDIF} {** Converts bytes into a variant representation. @param Value an array of bytes to be converted. @return a converted variant. } function BytesToVar(const Value: TByteDynArray): Variant; var I: Integer; begin Result := VarArrayCreate([0, Length(Value) - 1], varByte); for I := 0 to Length(Value) - 1 do Result[I] := Value[I]; end; {** Converts variant into an array of bytes. @param Value a varaint to be converted. @return a converted array of bytes. } function VarToBytes(const Value: Variant): TByteDynArray; var I: Integer; begin if not (VarIsArray(Value) and (VarArrayDimCount(Value) = 1) and ((VarType(Value) and VarTypeMask) = varByte)) then raise Exception.Create(SInvalidVarByteArray); SetLength(Result, VarArrayHighBound(Value, 1) + 1); for I := 0 to VarArrayHighBound(Value, 1) do Result[I] := Value[I]; end; {** Converts Ansi SQL Date/Time (yyyy-mm-dd hh:nn:ss or yyyy-mm-dd hh:nn:ss.zzz) to TDateTime @param Value a date and time string. @return a decoded TDateTime value. } function AnsiSQLDateToDateTime(const Value: string): TDateTime; var Year, Month, Day, Hour, Min, Sec, MSec: Word; Temp: string; DateFound: Boolean; procedure ExtractTime(AString: String); var dotPos: Integer; begin Hour := StrToIntDef(Copy(AString, 1, 2), 0); Min := StrToIntDef(Copy(AString, 4, 2), 0); Sec := StrToIntDef(Copy(AString, 7, 2), 0); //it the time Length is bigger than 8, it can have milliseconds and it ... dotPos := 0; MSec := 0; if Length(AString) > 8 then dotPos :=Pos ('.', AString); //if the dot are found, milliseconds are present. if dotPos > 0 then begin MSec := StrToIntDef(LeftStr(RightStr(AString,Length(AString)-dotPos)+'000',3),0); end; end; begin Temp := Value; Result := 0; DateFound := False; if Length(Temp) >= 10 then begin Year := StrToIntDef(Copy(Temp, 1, 4), 0); Month := StrToIntDef(Copy(Temp, 6, 2), 0); Day := StrToIntDef(Copy(Temp, 9, 2), 0); if (Year <> 0) and (Month <> 0) and (Day <> 0) then begin try Result := EncodeDate(Year, Month, Day); DateFound := True; except end; end; Temp := RightStr(Temp, Length(Temp)-11); end; if (Length(Temp) >= 8) or ( not DateFound ) then begin if DateFound then ExtractTime(Temp) else ExtractTime(Value); try if Result >= 0 then Result := Result + EncodeTime(Hour, Min, Sec, MSec) else Result := Result - EncodeTime(Hour, Min, Sec, MSec) except end; end; end; {** Converts Timestamp String to TDateTime @param Value a timestamp string. @return a decoded TDateTime value. } function TimestampStrToDateTime(const Value: string): TDateTime; var Year, Month, Day, Hour, Min, Sec: Integer; StrLength, StrPos, StrPosPrev: Integer; // function CharMatch( matchchars: string ): boolean; // try to match as much characters as possible begin StrPosPrev:= StrPos; Result:= false; while StrPos<=StrLength do if pos(Value[StrPos], matchchars) > 0 then begin inc(StrPos); Result := true; end else break; end; begin Result := 0; StrPos:= 1; StrLength := Length(Value); if not CharMatch('1234567890') then exit; // year Year := StrToIntDef(Copy(Value, StrPosPrev, StrPos-StrPosPrev), 0); if not CharMatch('-/\') then exit; if not CharMatch('1234567890') then exit; // month Month:= StrToIntDef(Copy(Value, StrPosPrev, StrPos-StrPosPrev), 0); if not CharMatch('-/\') then exit; if not CharMatch('1234567890') then exit; // day Day:= StrToIntDef(Copy(Value, StrPosPrev, StrPos-StrPosPrev), 0); try Result := EncodeDate(Year, Month, Day); except end; // if not CharMatch(' ') then exit; if not CharMatch('1234567890') then exit; // hour Hour := StrToIntDef(Copy(Value, StrPosPrev, StrPos-StrPosPrev), 0); if not CharMatch('-/\') then exit; if not CharMatch('1234567890') then exit; // minute Min:= StrToIntDef(Copy(Value, StrPosPrev, StrPos-StrPosPrev), 0); if not CharMatch('-/\') then exit; if not CharMatch('1234567890') then exit; // second Sec:= StrToIntDef(Copy(Value, StrPosPrev, StrPos-StrPosPrev), 0); try Result := REsult + EncodeTime(Hour, Min, Sec,0); except end; end; {** Converts TDateTime to Ansi SQL Date/Time @param Value an encoded TDateTime value. @return a date and time string. } function DateTimeToAnsiSQLDate(Value: TDateTime; WithMMSec: Boolean = False): string; var a, MSec:Word; begin if WithMMSec then begin DecodeTime(Value,a,a,a,MSec); if MSec=0 then Result := FormatDateTime('yyyy-mm-dd hh:nn:ss', Value) else Result := FormatDateTime('yyyy-mm-dd hh:nn:ss.zzz', Value); end else Result := FormatDateTime('yyyy-mm-dd hh:nn:ss', Value) end; { TZSortedList } {** Performs quick sort algorithm for the list. } procedure TZSortedList.QuickSort(SortList: PPointerList; L, R: Integer; SCompare: TZListSortCompare); var I, J: Integer; P, T: Pointer; begin repeat I := L; J := R; P := SortList^[(L + R) shr 1]; repeat while (I < R) And (SCompare(SortList^[I], P) < 0) do //check I against R too since the pointer can be nil Inc(I); while (J > L) And (SCompare(SortList^[J], P) > 0) do //check j against L too since the pointer can be nil Dec(J); if I <= J then begin T := SortList^[I]; SortList^[I] := SortList^[J]; SortList^[J] := T; Inc(I); Dec(J); end; until I > J; if L < J then QuickSort(SortList, L, J, SCompare); L := I; until I >= R; end; {** Performs sorting for this list. @param Compare a comparison function. } procedure TZSortedList.Sort(Compare: TZListSortCompare); begin if (List <> nil) and (Count > 0) then {$IFDEF DELPHI16_UP} QuickSort(@List, 0, Count - 1, Compare); {$ELSE} QuickSort(List, 0, Count - 1, Compare); {$ENDIF} end; {** Converts an string into escape PostgreSQL format. @param Value a regular string. @return a string in PostgreSQL escape format. } function EncodeCString(const Value: string): string; var I: Integer; SrcLength, DestLength: Integer; SrcBuffer, DestBuffer: PChar; begin SrcLength := Length(Value); SrcBuffer := PChar(Value); DestLength := 0; for I := 1 to SrcLength do begin if CharInSet(SrcBuffer^, [#0]) then Inc(DestLength, 4) else if CharInSet(SrcBuffer^, ['"', '''', '\']) then Inc(DestLength, 2) else Inc(DestLength); Inc(SrcBuffer); end; SrcBuffer := PChar(Value); SetLength(Result, DestLength); DestBuffer := PChar(Result); for I := 1 to SrcLength do begin if CharInSet(SrcBuffer^, [#0]) then begin DestBuffer[0] := '\'; DestBuffer[1] := Chr(Ord('0') + (Byte(SrcBuffer^) shr 6)); DestBuffer[2] := Chr(Ord('0') + ((Byte(SrcBuffer^) shr 3) and $07)); DestBuffer[3] := Chr(Ord('0') + (Byte(SrcBuffer^) and $07)); Inc(DestBuffer, 4); end else if CharInSet(SrcBuffer^, ['"', '''', '\']) then begin DestBuffer[0] := '\'; DestBuffer[1] := SrcBuffer^; Inc(DestBuffer, 2); end else begin DestBuffer^ := SrcBuffer^; Inc(DestBuffer); end; Inc(SrcBuffer); end; end; {** Converts an string from escape PostgreSQL format. @param Value a string in PostgreSQL escape format. @return a regular string. } function DecodeCString(const Value: string): string; var SrcLength, DestLength: Integer; SrcBuffer, DestBuffer: PChar; begin SrcLength := Length(Value); SrcBuffer := PChar(Value); SetLength(Result, SrcLength); DestLength := 0; DestBuffer := PChar(Result); while SrcLength > 0 do begin if SrcBuffer^ = '\' then begin Inc(SrcBuffer); if CharInSet(SrcBuffer^, ['0'..'9']) then begin DestBuffer^ := Chr(((Byte(SrcBuffer[0]) - Ord('0')) shl 6) or ((Byte(SrcBuffer[1]) - Ord('0')) shl 3) or ((Byte(SrcBuffer[2]) - Ord('0')))); Inc(SrcBuffer, 3); Dec(SrcLength, 4); end else begin case SrcBuffer^ of 'r': DestBuffer^ := #13; 'n': DestBuffer^ := #10; 't': DestBuffer^ := #9; else DestBuffer^ := SrcBuffer^; end; Inc(SrcBuffer); Dec(SrcLength, 2); end end else begin DestBuffer^ := SrcBuffer^; Inc(SrcBuffer); Dec(SrcLength); end; Inc(DestBuffer); Inc(DestLength); end; SetLength(Result, DestLength); end; {** Replace chars in the string @param Source a char to search. @param Target a char to replace. @param Str a source string. @return a string with replaced chars. } function ReplaceChar(const Source, Target: Char; const Str: string): string; var P: PChar; I:Integer; begin Result := Str; UniqueString(Result); P := Pointer(Result); for i := 0 to Length(Str) - 1 do begin if P^ = Source then P^ := Target; Inc(P); end; end; {** Copy buffer to the pascal string @param Buffer a buffer with data @param Length a buffer length @return a buffer content } function MemPas(Buffer: PChar; Length: LongInt): string; begin Result := ''; if Assigned(Buffer) then SetString(Result, Buffer, Length); end; {** Decodes a full version value encoded with Zeos SQL format: (major_version * 1,000,000) + (minor_version * 1,000) + sub_version into separated major, minor and subversion values @param FullVersion an integer containing the Full Version to decode. @param MajorVersion an integer containing the Major Version decoded. @param MinorVersion an integer containing the Minor Version decoded. @param SubVersion an integer contaning the Sub Version (revision) decoded. } procedure DecodeSQLVersioning(const FullVersion: Integer; out MajorVersion: Integer; out MinorVersion: Integer; out SubVersion: Integer); begin MajorVersion := FullVersion div 1000000; MinorVersion := (FullVersion - (MajorVersion * 1000000)) div 1000; SubVersion := FullVersion-(MajorVersion*1000000)-(MinorVersion*1000); end; {** Encodes major, minor and subversion (revision) values in Zeos SQL format: (major_version * 1,000,000) + (minor_version * 1,000) + sub_version For example, 4.1.12 is returned as 4001012. @param MajorVersion an integer containing the Major Version. @param MinorVersion an integer containing the Minor Version. @param SubVersion an integer containing the Sub Version (revision). @return an integer containing the full version. } function EncodeSQLVersioning(const MajorVersion: Integer; const MinorVersion: Integer; const SubVersion: Integer): Integer; begin Result := (MajorVersion * 1000000) + (MinorVersion * 1000) + SubVersion; end; {** Formats a Zeos SQL Version format to X.Y.Z where: X = major_version Y = minor_version Z = sub version @param SQLVersion an integer @return Formated Zeos SQL Version Value. } function FormatSQLVersion(const SQLVersion: Integer): string; var MajorVersion, MinorVersion, SubVersion: Integer; begin DecodeSQLVersioning(SQLVersion, MajorVersion, MinorVersion, SubVersion); Result := IntToStr(MajorVersion)+'.'+IntToStr(MinorVersion)+'.'+IntToStr(SubVersion); end; {** Arranges thousand and decimal separator to a System-defaults @param the value which has to be converted and arranged @return a valid floating value } function ZStrToFloat(Value: PAnsiChar): Extended; var OldDecimalSeparator, OldThousandSeparator: Char; begin OldDecimalSeparator := {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}DecimalSeparator; OldThousandSeparator := {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}ThousandSeparator; if {$IFDEF WITH_ANSISTRINGPOS_DEPRECATED}AnsiStrings.{$ENDIF}AnsiStrPos(PAnsiChar(Value), PAnsiChar(AnsiString(OldDecimalSeparator))) = nil then if {$IFDEF WITH_ANSISTRINGPOS_DEPRECATED}AnsiStrings.{$ENDIF}AnsiStrPos(PAnsiChar(Value), PAnsiChar(AnsiString(OldThousandSeparator))) = nil then //No DecimalSeparator and no ThousandSeparator Result := StrToFloat(String(Value)) else begin //wrong DecimalSepartor {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}DecimalSeparator := OldThousandSeparator; {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}ThousandSeparator := OldDecimalSeparator; Result := StrToFloat(String(Value)); end else if {$IFDEF WITH_ANSISTRINGPOS_DEPRECATED}AnsiStrings.{$ENDIF}AnsiStrPos(PAnsiChar(Value), PAnsiChar(AnsiString(OldThousandSeparator))) = nil then //default DecimalSepartor Result := StrToFloat(String(Value)) else if {$IFDEF WITH_STRLEN_DEPRECATED}AnsiStrings.{$ENDIF}StrLen({$IFDEF WITH_ANSISTRINGPOS_DEPRECATED}AnsiStrings.{$ENDIF}AnsiStrPos(PAnsiChar(Value), PAnsiChar(AnsiString(OldDecimalSeparator)))) < {$IFDEF WITH_STRLEN_DEPRECATED}AnsiStrings.{$ENDIF}StrLen({$IFDEF WITH_ANSISTRINGPOS_DEPRECATED}AnsiStrings.{$ENDIF}AnsiStrPos(PAnsiChar(Value), PAnsiChar(AnsiString(OldThousandSeparator)))) then //default DecimalSepartor and ThousandSeparator Result := StrToFloat(String(Value)) else begin //wrong DecimalSepartor and ThousandSeparator {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}DecimalSeparator := OldThousandSeparator; {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}ThousandSeparator := OldDecimalSeparator; Result := StrToFloat(String(Value)); end; {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}DecimalSeparator := OldDecimalSeparator; {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}ThousandSeparator := OldThousandSeparator; end; {** Arranges thousand and decimal separator to a System-defaults @param the value which has to be converted and arranged @return a valid floating value } function ZStrToFloat(Value: AnsiString): Extended; begin Result := ZStrToFloat(PAnsiChar(Value)); end; procedure ZSetString(const Src: PAnsiChar; var Dest: AnsiString); begin if Assigned(Src) then ZSetString(Src, {$IFDEF WITH_STRLEN_DEPRECATED}AnsiStrings.{$ENDIF}StrLen(Src), Dest) else Dest := ''; end; procedure ZSetString(const Src: PAnsiChar; const Len: Cardinal; var Dest: AnsiString); begin if ( Len = 0 ) or ( Src = nil ) then Dest := '' else begin SetLength(Dest, Len); Move(Src^, PAnsiChar(Dest)^, Len); end; end; procedure ZSetString(const Src: PAnsiChar; var Dest: UTF8String); begin if Assigned(Src) then ZSetString(Src, {$IFDEF WITH_STRLEN_DEPRECATED}AnsiStrings.{$ENDIF}StrLen(Src), Dest) else Dest := ''; end; procedure ZSetString(const Src: PAnsiChar; const Len: Cardinal; var Dest: UTF8String); begin if ( Len = 0 ) or ( Src = nil ) then Dest := '' else begin SetLength(Dest, Len); Move(Src^, PAnsiChar(Dest)^, Len); end; end; procedure ZSetString(const Src: PAnsiChar; const Len: Cardinal; var Dest: ZWideString); overload; begin if ( Len = 0 ) or ( Src = nil ) then Dest := '' else begin SetLength(Dest, Len div 2); Move(Src^, PWideChar(Dest)^, Len); end; end; {$IFDEF WITH_RAWBYTESTRING} procedure ZSetString(const Src: PAnsiChar; var Dest: RawByteString); begin if Assigned(Src) then ZSetString(Src, {$IFDEF WITH_STRLEN_DEPRECATED}AnsiStrings.{$ENDIF}StrLen(Src), Dest) else Dest := ''; end; procedure ZSetString(const Src: PAnsiChar; const Len: Cardinal; var Dest: RawByteString); begin if ( Len = 0 ) or ( Src = nil ) then Dest := '' else begin SetLength(Dest, Len); Move(Src^, PAnsiChar(Dest)^, Len); end; end; {$ENDIF} end. ================================================ FILE: lib/zeosdbo/src/core/ZTokenizer.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { String tokenizing classes and interfaces } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZTokenizer; interface {$I ZCore.inc} uses Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, ZClasses, ZCompatibility; type {** Objects of this class represent a type of token, such as "number", "symbol" or "word". } TZTokenType = (ttUnknown, ttEOF, ttFloat, ttInteger, ttHexDecimal, ttNumber, ttSymbol, ttQuoted, ttQuotedIdentifier, ttWord, ttKeyword, ttWhitespace, ttComment, ttSpecial, ttTime, ttDate, ttDateTime, ttEscape); {** Defines options for tokenizing strings. } TZTokenOption = (toSkipUnknown, toSkipWhitespaces, toSkipComments, toSkipEOF, toUnifyWhitespaces, toUnifyNumbers, toDecodeStrings); TZTokenOptions = set of TZTokenOption; {** A token represents a logical chunk of a string. For example, a typical tokenizer would break the string "1.23 <= 12.3" into three tokens: the number 1.23, a less-than-or-equal symbol, and the number 12.3. A token is a receptacle, and relies on a tokenizer to decide precisely how to divide a string into tokens. } TZToken = {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif} record Value: string; TokenType: TZTokenType; end; {** Defines a dynamic array of tokens. } TZTokenDynArray = array of TZToken; // Forward declaration TZTokenizer = class; {** A tokenizerState returns a token, given a reader, an initial character read from the reader, and a tokenizer that is conducting an overall tokenization of the reader. The tokenizer will typically have a character state table that decides which state to use, depending on an initial character. If a single character is insufficient, a state such as SlashState will read a second character, and may delegate to another state, such as SlashStarState. This prospect of delegation is the reason that the nextToken() method has a tokenizer argument. } TZTokenizerState = class (TObject) public function NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; virtual; abstract; end; {** EgonHugeist: A EsacapeState object returns bininary/String-data from a reader. This state's idea is save work-around of DataSet given binary/String-Data. So it has some requirements to pick out this data from the SQL- String: First: We have to define one or some Chars to detect this state. Example: If data data was given like; ~<|:%d|<~'...Binary/StringData...'~<|:%d|<~ we are able to predetect this State. Second: The parameter d represents an Integer(Count of Chars) if we do not use this it's possible that the Tokenizer is vinny-nilly on getting binary-Data! Third: The GenerigResolver who assambles the insert/update Statements has to add this ass prefix and suffix. Fourth: The User of this Component has to know this too. So has to do this previously if he want to insert/update binary-data in a self assembled Query. So i think it would be better to add an published read-only Property like: EscapeChars: String; If we did this corectly we are able to disassemble all queries and do execute the nessesary UTF8Encoding of the TZQuoteState and TZWordState which represents either Quoted-String-Data or Catalog/Table/Alias/Field name-spaces. This State is only neccessary for Delphi2009+ ( 2009 and later) and results of it's mixing nByte-Chars and binary-Data 1Byte-Chars. } TZEscapeState = class (TZTokenizerState) function NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; override; end; {** A NumberState object returns a number from a reader. This state's idea of a number allows an optional, initial minus sign, followed by one or more digits. A decimal point and another string of digits may follow these digits. } TZNumberState = class (TZTokenizerState) public function NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; override; end; {** A quoteState returns a quoted string token from a reader. This state will collect characters until it sees a match to the character that the tokenizer used to switch to this state. For example, if a tokenizer uses a double- quote character to enter this state, then nextToken() will search for another double-quote until it finds one or finds the end of the reader. } TZQuoteState = class (TZTokenizerState) public function NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; override; function EncodeString(const Value: string; QuoteChar: Char): string; virtual; function DecodeString(const Value: string; QuoteChar: Char): string; virtual; end; {** A CommentState object returns a comment from a reader. } TZCommentState = class (TZTokenizerState) public function NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; override; end; {** This state will either delegate to a comment-handling state, or return a token with just a slash in it. } TZCppCommentState = class (TZCommentState) protected function GetMultiLineComment(Stream: TStream): string; virtual; function GetSingleLineComment(Stream: TStream): string; virtual; public function NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; override; end; {** This state will either delegate to a comment-handling state, or return a token with just a slash in it. } TZCCommentState = class (TZCppCommentState) public function NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; override; end; {*Fix for C++ Builder hpp generation bug - #817612 *} (*$HPPEMIT 'namespace Ztokenizer {class DELPHICLASS TZSymbolNode;}' *) // Forward declaration TZSymbolNode = class; TZSymbolNodeArray = array of TZSymbolNode; {** A SymbolNode object is a member of a tree that contains all possible prefixes of allowable symbols. Multi- character symbols appear in a SymbolNode tree with one node for each character. For example, the symbol =:~ will appear in a tree as three nodes. The first node contains an equals sign, and has a child; that child contains a colon and has a child; this third child contains a tilde, and has no children of its own. If the colon node had another child for a dollar sign character, then the tree would contain the symbol =:$. A tree of SymbolNode objects collaborate to read a (potentially multi-character) symbol from an input stream. A root node with no character of its own finds an initial node that represents the first character in the input. This node looks to see if the next character in the stream matches one of its children. If so, the node delegates its reading task to its child. This approach walks down the tree, pulling symbols from the input that match the path down the tree. When a node does not have a child that matches the next character, we will have read the longest possible symbol prefix. This prefix may or may not be a valid symbol. Consider a tree that has had =:~ added and has not had =: added. In this tree, of the three nodes that contain =:~, only the first and third contain complete symbols. If, say, the input contains =:a, the colon node will not have a child that matches the 'a' and so it will stop reading. The colon node has to "unread": it must push back its character, and ask its parent to unread. Unreading continues until it reaches an ancestor that represents a valid symbol. } TZSymbolNode = class (TObject) private FCharacter: Char; FChildren: TZSymbolNodeArray; FValid: Boolean; FParent: TZSymbolNode; protected procedure AddDescendantLine(const Value: string); function DeepestRead(Stream: TStream): TZSymbolNode; function EnsureChildWithChar(Value: Char): TZSymbolNode; function FindChildWithChar(Value: Char): TZSymbolNode; virtual; function FindDescendant(const Value: string): TZSymbolNode; function UnreadToValid(Stream: TStream): TZSymbolNode; property Children: TZSymbolNodeArray read FChildren write FChildren; property Character: Char read FCharacter write FCharacter; property Valid: Boolean read FValid write FValid; property Parent: TZSymbolNode read FParent write FParent; public constructor Create(Parent: TZSymbolNode; Character: Char); destructor Destroy; override; function Ancestry: string; virtual; end; {** This class is a special case of a SymbolNode. A SymbolRootNode object has no symbol of its own, but has children that represent all possible symbols. } TZSymbolRootNode = class (TZSymbolNode) protected function FindChildWithChar(Value: Char): TZSymbolNode; override; public constructor Create; procedure Add(const Value: string); function Ancestry: string; override; function NextSymbol(Stream: TStream; FirstChar: Char): string; end; {** The idea of a symbol is a character that stands on its own, such as an ampersand or a parenthesis. For example, when tokenizing the expression (isReady)& (isWilling) , a typical tokenizer would return 7 tokens, including one for each parenthesis and one for the ampersand. Thus a series of symbols such as )&( becomes three tokens, while a series of letters such as isReady becomes a single word token.

Multi-character symbols are an exception to the rule that a symbol is a standalone character. For example, a tokenizer may want less-than-or-equals to tokenize as a single token. This class provides a method for establishing which multi-character symbols an object of this class should treat as single symbols. This allows, for example, "cat <= dog" to tokenize as three tokens, rather than splitting the less-than and equals symbols into separate tokens.

By default, this state recognizes the following multi- character symbols: !=, :-, <=, >= } TZSymbolState = class (TZTokenizerState) private FSymbols: TZSymbolRootNode; protected property Symbols: TZSymbolRootNode read FSymbols write FSymbols; public constructor Create; destructor Destroy; override; function NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; override; procedure Add(const Value: string); virtual; end; {** A whitespace state ignores whitespace (such as blanks and tabs), and returns the tokenizer's next token. By default, all characters from 0 to 32 are whitespace. } TZWhitespaceState = class (TZTokenizerState) private FWhitespaceChars: array[0..ord(high(char))] of Boolean; public constructor Create; function NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; override; procedure SetWhitespaceChars(FromChar: Char; ToChar: Char; Enable: Boolean); end; {** A wordState returns a word from a reader. Like other states, a tokenizer transfers the job of reading to this state, depending on an initial character. Thus, the tokenizer decides which characters may begin a word, and this state determines which characters may appear as a second or later character in a word. These are typically different sets of characters; in particular, it is typical for digits to appear as parts of a word, but not as the initial character of a word.

By default, the following characters may appear in a word. The method setWordChars() allows customizing this.

        From    To
         'a', 'z'
         'A', 'Z'
         '0', '9'

        as well as: minus sign, underscore, and apostrophe.
    
} TZWordState = class (TZTokenizerState) private FWordChars: array[0..ord(high(char))] of Boolean; public constructor Create; function NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; override; procedure SetWordChars(FromChar: Char; ToChar: Char; Enable: Boolean); end; {** A tokenizer divides a string into tokens. This class is highly customizable with regard to exactly how this division occurs, but it also has defaults that are suitable for many languages. This class assumes that the character values read from the string lie in the range 0-255. For example, the Unicode value of a capital A is 65, so System.out.println((char)65); prints out a capital A.

The behavior of a tokenizer depends on its character state table. This table is an array of 256 TokenizerState states. The state table decides which state to enter upon reading a character from the input string.

For example, by default, upon reading an 'A', a tokenizer will enter a "word" state. This means the tokenizer will ask a WordState object to consume the 'A', along with the characters after the 'A' that form a word. The state's responsibility is to consume characters and return a complete token.

The default table sets a SymbolState for every character from 0 to 255, and then overrides this with:

        From    To     State
          0     ' '    whitespaceState
         'a'    'z'    wordState
         'A'    'Z'    wordState
        160     255    wordState
         '0'    '9'    numberState
         '-'    '-'    numberState
         '.'    '.'    numberState
         '"'    '"'    quoteState
        '\''   '\''    quoteState
         '/'    '/'    slashState
    
In addition to allowing modification of the state table, this class makes each of the states above available. Some of these states are customizable. For example, wordState allows customization of what characters can be part of a word, after the first character. } IZTokenizer = interface (IZInterface) ['{C7CF190B-C45B-4AB4-A406-5999643DF6A0}'] function TokenizeBufferToList(const Buffer: string; Options: TZTokenOptions): TStrings; function TokenizeStreamToList(Stream: TStream; Options: TZTokenOptions): TStrings; function TokenizeBuffer(const Buffer: string; Options: TZTokenOptions): TZTokenDynArray; function TokenizeStream(Stream: TStream; Options: TZTokenOptions): TZTokenDynArray; function GetCommentState: TZCommentState; function GetNumberState: TZNumberState; function GetQuoteState: TZQuoteState; function GetSymbolState: TZSymbolState; function GetWhitespaceState: TZWhitespaceState; function GetWordState: TZWordState; function GetCharacterState(StartChar: Char): TZTokenizerState; function AnsiGetEscapeString(const Ansi: RawByteString): String; {$IF defined(FPC) and defined(WITH_RAWBYTESTRING)} function GetEscapeString(const EscapeString: RawByteString): RawByteString; {$ELSE} function GetEscapeString(const EscapeString: String): String; {$IFEND} end; {** Implements a default tokenizer object. } TZTokenizer = class (TZAbstractObject, IZTokenizer) private FCharacterStates: array[0..ord(high(char))] of TZTokenizerState; FCommentState: TZCommentState; FNumberState: TZNumberState; FQuoteState: TZQuoteState; FSymbolState: TZSymbolState; FWhitespaceState: TZWhitespaceState; FWordState: TZWordState; FEscapeState: TZEscapeState; //EgonHugeist protected function CheckEscapeState(const ActualState: TZTokenizerState; Stream: TStream; const FirstChar: Char): TZTokenizerState; virtual; public constructor Create; destructor Destroy; override; function AnsiGetEscapeString(const EscapeString: RawByteString): String; virtual; {$IF defined(FPC) and defined(WITH_RAWBYTESTRING)} function GetEscapeString(const EscapeString: RawByteString): RawByteString; {$ELSE} function GetEscapeString(const EscapeString: String): String; {$IFEND} function TokenizeBufferToList(const Buffer: string; Options: TZTokenOptions): TStrings; function TokenizeStreamToList(Stream: TStream; Options: TZTokenOptions): TStrings; function TokenizeBuffer(const Buffer: string; Options: TZTokenOptions): TZTokenDynArray; function TokenizeStream(Stream: TStream; Options: TZTokenOptions): TZTokenDynArray; function GetCharacterState(StartChar: Char): TZTokenizerState; procedure SetCharacterState(FromChar, ToChar: Char; State: TZTokenizerState); function GetEscapeState: TZEscapeState; function GetCommentState: TZCommentState; function GetNumberState: TZNumberState; function GetQuoteState: TZQuoteState; function GetSymbolState: TZSymbolState; function GetWhitespaceState: TZWhitespaceState; function GetWordState: TZWordState; property EscapeState: TZEscapeState read FEscapeState write FEscapeState; property CommentState: TZCommentState read FCommentState write FCommentState; property NumberState: TZNumberState read FNumberState write FNumberState; property QuoteState: TZQuoteState read FQuoteState write FQuoteState; property SymbolState: TZSymbolState read FSymbolState write FSymbolState; property WhitespaceState: TZWhitespaceState read FWhitespaceState write FWhitespaceState; property WordState: TZWordState read FWordState write FWordState; end; const EscapeMarkSequence = String('~<|'); implementation uses Math, StrUtils; {$IFDEF FPC} {$HINTS OFF} {$ENDIF} { TZEscapeState } //EgonHugeist {** Return a quoted Escape-data-string of token from a reader. This method will collect characters until it sees a match to the character that the tokenizer used to switch to this state. @return a quoted string token from a reader } function TZEscapeState.NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; var TempChar: Char; TempStr, LenString: string; I, IReadCount: Integer; function ReadNextCharToTempChar: Boolean; begin Result := True; if Stream.Read(TempChar, 1 * SizeOf(Char)) = 0 then begin Result := False; TempChar := #0; end else Inc(iReadCount); end; procedure RollbackStream; begin Stream.Seek(-(iReadCount * SizeOf(Char)), soFromCurrent); Result.Value := ''; IReadCount := 0; end; function CheckMarkChars(Marks: String): Boolean; var iMark: Integer; begin Result := False; if ( TempChar = Copy(Marks, 1, 1) ) then for iMark := 2 to Length(Marks) do //First Char was predetected begin if ReadNextCharToTempChar then begin if not ( TempChar = Copy(Marks, iMark, 1) ) then begin RollbackStream; Exit; end; end else begin RollbackStream; Exit; end; end else begin RollbackStream; Exit; end; Result := True; end; function ReadLengthString: String; var B: Boolean; begin Result := ''; //init value repeat B := ReadNextCharToTempChar; if B then if CharInSet(TempChar, ['0'..'9']) then Result := Result+TempChar; until ( not CharInSet(TempChar, ['0'..'9'])) or ( not B ); end; begin Result.TokenType := ttUnknown; Result.Value := ''; iReadCount := 0; //init Value TempStr := ''; TempChar := FirstChar; //FirstChar: ~ if not CheckMarkChars(EscapeMarkSequence) then Exit; //All inMark-Chars where test. //Now Check for Numeric Chars until MarkOut was found or #0 was Resulted LenString := ReadLengthString; if LenString = '' then begin RollbackStream; Exit; end; //Now Check the TempChar for it's hits on cBinDetectCharsOut if not CheckMarkChars(ReverseString(EscapeMarkSequence)) then Exit; //OutMarks where Found too. So let's read the BinarayData to the TempStr //Including the Quotes for i := 0 to StrToInt(LenString) do begin if not ReadNextCharToTempChar then Exit else TempStr := TempStr + TempChar; end; //Done and still in here! Post Data to Result! Result.Value := Copy(TempStr, 1, Length(TempStr)-1); //Now Check for in Chars again.. if not CheckMarkChars(EscapeMarkSequence) then Exit; //MarkIn-Chars where found now compare the read-length TempStr := LenString; //Save to before compare LenString := ReadLengthString; if ( LenString = '' ) or ( LenString <> TempStr ) then begin RollbackStream; Exit; end; //Now Check the TempChar for it's hits on Escape-Detect-CharsOut again.. if not CheckMarkChars(ReverseString(EscapeMarkSequence)) then Exit; //MarkOut-Chars where found again now we are ready here //everything was fine! Now we are sure Escape data was here Result.TokenType := ttEscape; //End.. end; { TZNumberState } {** Return a number token from a reader. @return a number token from a reader } function TZNumberState.NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; var ReadNum: Integer; AbsorbedLeadingMinus: Boolean; AbsorbedDot: Boolean; GotAdigit: Boolean; function AbsorbDigits: string; begin Result := ''; while CharInSet(FirstChar, ['0'..'9']) do begin GotAdigit := True; Result := Result + FirstChar; ReadNum := Stream.Read(FirstChar, 1 * SizeOf(Char)); if ReadNum = 0 then Break; end; end; begin { Initializes the process. } ReadNum := 0; AbsorbedLeadingMinus := False; AbsorbedDot := False; GotAdigit := False; Result.TokenType := ttUnknown; Result.Value := ''; { Parses left part of the number. } if FirstChar = '-' then begin ReadNum := Stream.Read(FirstChar, 1 * SizeOf(Char)); Result.Value := '-'; AbsorbedLeadingMinus := True; end; Result.Value := Result.Value + AbsorbDigits; { Parses right part of the number. } if FirstChar = '.' then begin AbsorbedDot := True; Result.Value := Result.Value + '.'; ReadNum := Stream.Read(FirstChar, 1 * SizeOf(Char)); if ReadNum > 0 then Result.Value := Result.Value + AbsorbDigits; end; { Pushback wrong symbols. } Stream.Seek(-ReadNum, soFromCurrent); { Gets a token result. } if not GotAdigit then begin if AbsorbedLeadingMinus and AbsorbedDot then begin Stream.Seek(-(1 * SizeOf(Char)), soFromCurrent); if Tokenizer.SymbolState <> nil then Result := Tokenizer.SymbolState.NextToken(Stream, '-', Tokenizer); end else if AbsorbedLeadingMinus then begin if Tokenizer.SymbolState <> nil then Result := Tokenizer.SymbolState.NextToken(Stream, '-', Tokenizer) end else if AbsorbedDot then begin if Tokenizer.SymbolState <> nil then Result := Tokenizer.SymbolState.NextToken(Stream, '.', Tokenizer); end; end else begin if AbsorbedDot then Result.TokenType := ttFloat else Result.TokenType := ttInteger; end; end; { TZQuoteState } {** Return a quoted string token from a reader. This method will collect characters until it sees a match to the character that the tokenizer used to switch to this state. @return a quoted string token from a reader } function TZQuoteState.NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; var TempChar: Char; TempStr: string; begin TempStr := FirstChar; repeat if Stream.Read(TempChar, 1 * SizeOf(Char)) = 0 then TempChar := FirstChar; TempStr := TempStr + TempChar; until TempChar = FirstChar; Result.TokenType := ttQuoted; Result.Value := TempStr; end; {** Encodes a string value. @param Value a string value to be encoded. @param QuoteChar a string quote character. @returns an encoded string. } function TZQuoteState.EncodeString(const Value: string; QuoteChar: Char): string; begin Result := QuoteChar + Value + QuoteChar; end; {** Decodes a string value. @param Value a string value to be decoded. @param QuoteChar a string quote character. @returns an decoded string. } function TZQuoteState.DecodeString(const Value: string; QuoteChar: Char): string; begin if (Length(Value) >= 2) and (Value[1] = QuoteChar) and (Value[Length(Value)] = Value[1]) then Result := Copy(Value, 2, Length(Value) - 2) else Result := Value; end; { TZBasicCommentState } {** Either delegate to a comment-handling state, or return a token with just a slash in it. @return either just a slash token, or the results of delegating to a comment-handling state } function TZCommentState.NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; var ReadChar: Char; ReadStr: string; begin ReadStr := FirstChar; while (Stream.Read(ReadChar, 1 * SizeOf(Char)) > 0) and not CharInSet(ReadChar, [#10, #13]) do ReadStr := ReadStr + ReadChar; if CharInSet(ReadChar, [#10, #13]) then Stream.Seek(-(1 * SizeOf(Char)), soFromCurrent); Result.TokenType := ttComment; Result.Value := ReadStr; end; { TZCppCommentState } {** Ignore everything up to a closing star and slash, and then return the tokenizer's next token. @return the tokenizer's next token } function TZCppCommentState.GetMultiLineComment(Stream: TStream): string; var ReadChar, LastChar: Char; begin LastChar := #0; Result := ''; while Stream.Read(ReadChar, 1 * SizeOf(Char)) > 0 do begin Result := Result + ReadChar; if (LastChar = '*') and (ReadChar = '/') then Break; LastChar := ReadChar; end; end; {** Ignore everything up to an end-of-line and return the tokenizer's next token. @return the tokenizer's next token } function TZCppCommentState.GetSingleLineComment(Stream: TStream): string; var ReadChar: Char; begin Result := ''; while (Stream.Read(ReadChar, 1 * SizeOf(Char)) > 0) and not CharInSet(ReadChar, [#10, #13]) do Result := Result + ReadChar; // mdaems : for single line comments the line ending must be included // as it should never be stripped off or unified with other whitespace characters if CharInSet(ReadChar, [#10, #13]) then begin Result := Result + ReadChar; // ludob Linux line terminator is just LF, don't read further if we already have LF if (ReadChar<>#10) and (Stream.Read(ReadChar, 1 * SizeOf(Char)) > 0) then if CharInSet(ReadChar, [#10, #13]) then Result := Result + ReadChar else Stream.Seek(-(1 * SizeOf(Char)), soFromCurrent); end; end; {** Either delegate to a comment-handling state, or return a token with just a slash in it. @return either just a slash token, or the results of delegating to a comment-handling state } function TZCppCommentState.NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; var ReadChar: Char; ReadNum: Integer; begin Result.TokenType := ttUnknown; Result.Value := FirstChar; ReadNum := Stream.Read(ReadChar, 1 * SizeOf(Char)); if (ReadNum > 0) and (ReadChar = '*') then begin Result.TokenType := ttComment; Result.Value := '/*' + GetMultiLineComment(Stream); end else if (ReadNum > 0) and (ReadChar = '/') then begin Result.TokenType := ttComment; Result.Value := '//' + GetSingleLineComment(Stream); end else begin if ReadNum > 0 then Stream.Seek(-(1 * SizeOf(Char)), soFromCurrent); if Tokenizer.SymbolState <> nil then Result := Tokenizer.SymbolState.NextToken(Stream, FirstChar, Tokenizer); end; end; { TZCCommentState } {** Gets a C specific comments like /* */. @return either just a slash token, or the results of delegating to a comment-handling state } function TZCCommentState.NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; var ReadChar: Char; ReadNum: Integer; begin Result.TokenType := ttUnknown; Result.Value := FirstChar; if FirstChar = '/' then begin ReadNum := Stream.Read(ReadChar, 1 * SizeOf(Char)); if (ReadNum > 0) and (ReadChar = '*') then begin Result.TokenType := ttComment; Result.Value := '/*' + GetMultiLineComment(Stream); end else begin if ReadNum > 0 then Stream.Seek(-(1 * SizeOf(Char)), soFromCurrent); end; end; if (Result.TokenType = ttUnknown) and (Tokenizer.SymbolState <> nil) then Result := Tokenizer.SymbolState.NextToken(Stream, FirstChar, Tokenizer); end; { TZSymbolNode } {** Constructs a SymbolNode with the given parent, representing the given character. @param Parent this node's parent @param Character this node's character } constructor TZSymbolNode.Create(Parent: TZSymbolNode; Character: Char); begin FParent := Parent; FCharacter := Character; FValid := False; SetLength(FChildren, 256); end; {** Destroys this symbol object and cleanups the memory. } destructor TZSymbolNode.Destroy; var I: Integer; begin for I := 0 to 255 do begin if FChildren[I] <> nil then FChildren[I].Free else Break; end; SetLength(FChildren, 0); FParent := nil; inherited Destroy; end; {** Add a line of descendants that represent the characters in the given string. } procedure TZSymbolNode.AddDescendantLine(const Value: string); var Node: TZSymbolNode; begin if Length(Value) > 0 then begin Node := EnsureChildWithChar(Value[1]); Node.AddDescendantLine(Copy(Value, 2, Length(Value) - 1)); end; end; {** Show the symbol this node represents. @return the symbol this node represents } function TZSymbolNode.Ancestry: string; begin Result := FParent.Ancestry + FCharacter; end; {** Find the descendant that takes as many characters as possible from the input. } function TZSymbolNode.DeepestRead(Stream: TStream): TZSymbolNode; var TempChar: Char; Node: TZSymbolNode; ReadNum: Integer; begin ReadNum := Stream.Read(TempChar, 1 * SizeOf(Char)); if ReadNum > 0 then Node := FindChildWithChar(TempChar) else Node := nil; if Node = nil then begin Stream.Seek(-ReadNum, soFromCurrent); Result := Self; end else Result := Node.DeepestRead(Stream); end; {** Find or create a child for the given character. } function TZSymbolNode.EnsureChildWithChar(Value: Char): TZSymbolNode; var N: Integer; begin Result := FindChildWithChar(Value); if Result = nil then begin N := 0; while (FChildren[N] <> nil) and (N <= 255) do Inc(N); if N <= 255 then begin Result := TZSymbolNode.Create(Self, Value); FChildren[N] := Result; end; end; end; {** Find a child with the given character. } function TZSymbolNode.FindChildWithChar(Value: Char): TZSymbolNode; var I: Integer; Current: TZSymbolNode; begin Result := nil; for I := 0 to 255 do begin Current := Children[I]; if (Current = nil) or (Current.Character = Value) then begin Result := Current; Break; end; end; end; {** Find a descendant which is down the path the given string indicates. } function TZSymbolNode.FindDescendant(const Value: string): TZSymbolNode; var TempChar: Char; begin if Length(Value) > 0 then TempChar := Value[1] else TempChar := #0; Result := FindChildWithChar(TempChar); if (Length(Value) > 1) and (Result <> nil) then Result := Result.FindDescendant(Copy(Value, 2, Length(Value) - 1)); end; {** Unwind to a valid node; this node is "valid" if its ancestry represents a complete symbol. If this node is not valid, put back the character and ask the parent to unwind. } function TZSymbolNode.UnreadToValid(Stream: TStream): TZSymbolNode; begin if not FValid then begin Stream.Seek(-(1 * SizeOf(Char)), soFromCurrent); Result := FParent.UnreadToValid(Stream); end else Result := Self; end; { TZSymbolRootNode } {** Create and initialize a root node. } constructor TZSymbolRootNode.Create; var I: Integer; begin inherited Create(nil, #0); for I := 0 to 255 do begin FChildren[I] := TZSymbolNode.Create(Self, Chr(I)); FChildren[I].Valid := True; end; end; {** Add the given string as a symbol. @param String the character sequence to add } procedure TZSymbolRootNode.Add(const Value: string); var TempChar: Char; Node: TZSymbolNode; begin if Length(Value) > 0 then TempChar := Value[1] else TempChar := #0; Node := EnsureChildWithChar(TempChar); Node.AddDescendantLine(Copy(Value, 2, Length(Value) - 1)); FindDescendant(Value).Valid := True; end; {** A root node has no parent and no character of its own, so its ancestry is "". @return an empty string } function TZSymbolRootNode.Ancestry: string; begin Result := ''; end; {** A root node maintains its children in an array instead of a Vector, to be faster. } function TZSymbolRootNode.FindChildWithChar(Value: Char): TZSymbolNode; begin Result := FChildren[Ord(Value)]; end; {** Return a symbol string from a reader. @param Stream a reader to read from @param FirstChar the first character of this symbol, already read from the reader @return a symbol string from a reader } function TZSymbolRootNode.NextSymbol(Stream: TStream; FirstChar: Char): string; var Node: TZSymbolNode; begin Node := FindChildWithChar(FirstChar); Node := Node.DeepestRead(Stream); Node := Node.UnreadToValid(Stream); Result := Node.Ancestry; end; { TZSymbolState } {** Constructs a symbol state with a default idea of what multi-character symbols to accept (as described in the class comment). } constructor TZSymbolState.Create; begin FSymbols := TZSymbolRootNode.Create; end; {** Destroys this object and cleanups the memory. } destructor TZSymbolState.Destroy; begin FSymbols.Free; inherited Destroy; end; {** Add a multi-character symbol. @param Value the symbol to add, such as "=:=" } procedure TZSymbolState.Add(const Value: string); begin FSymbols.Add(Value); end; {** Return a symbol token from a reader. @return a symbol token from a reader } function TZSymbolState.NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; begin Result.TokenType := ttSymbol; Result.Value := FSymbols.NextSymbol(Stream, FirstChar); end; { TZWhitespaceState } {** Constructs a whitespace state with a default idea of what characters are, in fact, whitespace. } constructor TZWhitespaceState.Create; begin SetWhitespaceChars(' ', high(char), False); SetWhitespaceChars(Chr(0), ' ', True); end; {** Ignore whitespace (such as blanks and tabs), and return the tokenizer's next token. @return the tokenizer's next token } function TZWhitespaceState.NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; var ReadNum: Integer; ReadChar: Char; ReadStr: string; begin ReadStr := FirstChar; ReadNum := 0; while True do begin ReadNum := Stream.Read(ReadChar, 1 * SizeOf(Char)); if (ReadNum = 0) or not FWhitespaceChars[Ord(ReadChar)] then Break; ReadStr := ReadStr + ReadChar; end; if ReadNum > 0 then Stream.Seek(-(1 * SizeOf(Char)), soFromCurrent); Result.TokenType := ttWhitespace; Result.Value := ReadStr; end; {** Establish the given characters as whitespace to ignore. @param FromChar first character index. @param ToChar last character index. @param Enable true, if this state should ignore characters in the given range } procedure TZWhitespaceState.SetWhitespaceChars(FromChar, ToChar: Char; Enable: Boolean); var I: Integer; begin for I := Ord(FromChar) to MinIntValue([Ord(ToChar), 255]) do FWhitespaceChars[I] := Enable; end; { TZWordState } {** Constructs a word state with a default idea of what characters are admissible inside a word (as described in the class comment). } constructor TZWordState.Create; begin SetWordChars(#0, #191, False); SetWordChars(#192, high(char), True); SetWordChars('a', 'z', True); SetWordChars('A', 'Z', True); SetWordChars('0', '9', True); SetWordChars('-', '-', True); SetWordChars('_', '_', True); SetWordChars('''', '''', True); end; {** Return a word token from a reader. @return a word token from a reader } function TZWordState.NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; var TempChar: Char; ReadNum: Integer; Value: string; begin Value := FirstChar; repeat ReadNum := Stream.Read(TempChar, 1 * SizeOf(Char)); if (ReadNum = 0) or not FWordChars[Ord(TempChar)] then Break; Value := Value + TempChar; until False; if ReadNum > 0 then Stream.Seek(-(1 * SizeOf(Char)), soFromCurrent); Result.TokenType := ttWord; Result.Value := Value; end; {** Establish characters in the given range as valid characters for part of a word after the first character. Note that the tokenizer must determine which characters are valid as the beginning character of a word. @param FromChar first character index. @param ToChar last character index. @param Enable true, if this state should ignore characters in the given range } procedure TZWordState.SetWordChars(FromChar, ToChar: Char; Enable: Boolean); var I: Integer; begin for I := Ord(FromChar) to MinIntValue([Ord(ToChar), Ord(high(char)) ]) do FWordChars[I] := Enable; end; { TZTokenizer } {** Constructs a tokenizer with a default state table (as described in the class comment). } constructor TZTokenizer.Create; begin FSymbolState := TZSymbolState.Create; with TZSymbolState(FSymbolState) do begin Add('<>'); Add('<='); Add('>='); end; FEscapeState := TZEscapeState.Create; FNumberState := TZNumberState.Create; FQuoteState := TZQuoteState.Create; FWhitespaceState := TZWhitespaceState.Create; FWordState := TZWordState.Create; FCommentState := TZCppCommentState.Create; SetCharacterState(#0, #32, FWhitespaceState); SetCharacterState(#33, #191, FSymbolState); SetCharacterState(#192, High(Char), FWordState); SetCharacterState('a', 'z', FWordState); SetCharacterState('A', 'Z', FWordState); SetCharacterState('0', '9', FNumberState); SetCharacterState('-', '-', FNumberState); SetCharacterState('.', '.', FNumberState); SetCharacterState('"', '"', FQuoteState); SetCharacterState('''', '''', FQuoteState); SetCharacterState('/', '/', FCommentState); end; {** Destroys this object and cleanups the memory. } destructor TZTokenizer.Destroy; begin if FEscapeState <> nil then FEscapeState.Free; if FCommentState <> nil then FCommentState.Free; if FNumberState <> nil then FNumberState.Free; if FQuoteState <> nil then FQuoteState.Free; if FSymbolState <> nil then FSymbolState.Free; if FWhitespaceState <> nil then FWhitespaceState.Free; if FWordState <> nil then FWordState.Free; inherited Destroy; end; {** Gets an initial state object for the specified character. @return an initial state object for the character. } function TZTokenizer.GetCharacterState(StartChar: Char): TZTokenizerState; begin Result := FCharacterStates[Ord(StartChar)]; end; {** Change the state the tokenizer will enter upon reading any character between "from" and "to". @param FromChar first character index. @param ToChar last character index. @param State the state to enter upon reading a character between "fromChar" and "toChar" } procedure TZTokenizer.SetCharacterState(FromChar, ToChar: Char; State: TZTokenizerState); var I: Integer; const ORDMAXCHAR = ord(high(char)); begin for I := Ord(FromChar) to MinIntValue([Ord(ToChar), ORDMAXCHAR]) do FCharacterStates[I] := State; end; {** Tokenizes a string buffer into a dynamic array of tokens. @param Buffer a string buffer to be tokenized. @param Options a set of tokenizer options. @returns a dynamic array of tokens } function TZTokenizer.TokenizeBuffer(const Buffer: string; Options: TZTokenOptions): TZTokenDynArray; var Stream: TStream; begin Stream := TStringStream.Create(Buffer{$IFDEF WITH_TENCODING_CLASS}, TEncoding.Unicode{$ENDIF}); try Result := TokenizeStream(Stream, Options); finally Stream.Free; end; end; function TZTokenizer.AnsiGetEscapeString(const EscapeString: RawByteString): String; var Temp: String; begin Temp := EscapeMarkSequence+IntToStr(Length(EscapeString))+ReverseString(EscapeMarkSequence); if Length(EscapeString) > 0 then Result := Temp+String(EscapeString)+Temp else Result := 'NULL'; end; {$IF defined(FPC) and defined(WITH_RAWBYTESTRING)} function TZTokenizer.GetEscapeString(const EscapeString: RawByteString): RawByteString; {$ELSE} function TZTokenizer.GetEscapeString(const EscapeString: String): String; {$IFEND} var Temp: String; begin Temp := EscapeMarkSequence+IntToStr(Length(EscapeString))+ReverseString(EscapeMarkSequence); if Length(EscapeString) > 0 then {$IF defined(FPC) and defined(WITH_RAWBYTESTRING)} Result := RawByteString(Temp)+EscapeString+RawByteString(Temp) {$ELSE} Result := Temp+EscapeString+Temp {$IFEND} else Result := ''; end; {** EgonHugeist: Checks if SymboState is EscapeState and sets it ... @param Stream the Read-Stream which has to checked for Next-Chars. @FirstChar The FirstChar which was readed and sets the Symbolstate @returns either the given SymbolState or the EscapeState } function TZTokenizer.CheckEscapeState(const ActualState: TZTokenizerState; Stream: TStream; const FirstChar: Char): TZTokenizerState; var NextChar: Char; iReadCount, I: Integer; begin Result := ActualState; iReadCount := 0; if ( FirstChar = EscapeMarkSequence[1]) then //Token was set so check if its Escape begin for i := 2 to Length(EscapeMarkSequence) do if Stream.Read(NextChar, 1 * SizeOf(Char)) > 0 then //Read next Char begin Inc(IReadCount); //increment count of read-Chars if NextChar <> EscapeMarkSequence[I] then //Compare Chars begin Stream.Seek(-(iReadCount * SizeOf(Char)), soFromCurrent); //Seek Stream back to starting Position Exit; end end else Continue; end else Exit; Stream.Seek(-(iReadCount * SizeOf(Char)), soFromCurrent); //Seek Stream back to starting Position Result := Self.EscapeState; end; {** Tokenizes a string buffer into a list of tokens. @param Buffer a string buffer to be tokenized. @param Options a set of tokenizer options. @returns a string list where Items are tokens and Objects are token types. } function TZTokenizer.TokenizeBufferToList(const Buffer: string; Options: TZTokenOptions): TStrings; var Stream: TStream; begin Stream := TStringStream.Create(Buffer{$IFDEF WITH_TENCODING_CLASS}, TEncoding.Unicode{$ENDIF}); try Result := TokenizeStreamToList(Stream, Options); finally Stream.Free; end; end; {** Tokenizes a stream into a dynamic array of tokens. @param Stream a stream to be tokenized. @param Options a set of tokenizer options. @returns a dynamic array of tokens } function TZTokenizer.TokenizeStream(Stream: TStream; Options: TZTokenOptions): TZTokenDynArray; var I: Integer; List: TStrings; begin List := TokenizeStreamToList(Stream, Options); try SetLength(Result, List.Count); for I := 0 to List.Count - 1 do begin Result[I].Value := List[I]; Result[I].TokenType := TZTokenType({$IFDEF FPC}Pointer({$ENDIF} List.Objects[I]{$IFDEF FPC}){$ENDIF}); end; finally List.Free; end; end; {** Tokenizes a stream into a string list of tokens. @param Stream a stream to be tokenized. @param Options a set of tokenizer options. @returns a string list where Items are tokens and Objects are token types. } function TZTokenizer.TokenizeStreamToList(Stream: TStream; Options: TZTokenOptions): TStrings; var FirstChar: Char; Token: TZToken; LastTokenType: TZTokenType; State: TZTokenizerState; begin Result := TStringList.Create; LastTokenType := ttUnknown; while Stream.Read(FirstChar, 1 * SizeOf(Char)) > 0 do begin State := FCharacterStates[Ord(FirstChar)]; if State <> nil then begin State := CheckEscapeState(State, Stream, FirstChar); Token := State.NextToken(Stream, FirstChar, Self); { Decode strings. } if (State is TZQuoteState) and (toDecodeStrings in Options) then begin Token.Value := (State as TZQuoteState).DecodeString( Token.Value, FirstChar); end; { Skips comments if option set. } if (Token.TokenType = ttComment) and (toSkipComments in Options) then Continue; { Skips whitespaces if option set. } if (Token.TokenType = ttWhitespace) and (toSkipWhitespaces in Options) then Continue; { Unifies whitespaces if option set. } if (Token.TokenType = ttWhitespace) and (toUnifyWhitespaces in Options) then begin if LastTokenType = ttWhitespace then Continue; Token.Value := ' '; end; { Unifies numbers if option set. } if (Token.TokenType in [ttInteger, ttFloat, ttHexDecimal]) and (toUnifyNumbers in Options) then Token.TokenType := ttNumber; { If an integer is immediately followed by a string they should be seen as one string} if ((Token.TokenType = ttWord)and(LastTokenType = ttInteger)) then begin Token.Value := Result[Result.Count-1] + Token.Value; Result.Delete(Result.Count-1); end; { Add a read token. } LastTokenType := Token.TokenType; Result.AddObject(Token.Value, TObject(Ord(Token.TokenType))); end { Skips unknown chars if option set. } else if not (toSkipUnknown in Options) then Result.AddObject(FirstChar, TObject(Ord(ttUnknown))); end; { Adds an EOF if option is not set. } if not (toSkipEOF in Options) then Result.AddObject('', TObject(Ord(ttEOF))); end; {** Gets a tokenizer default Escape state. @returns a tokenizer default Escape state. } function TZTokenizer.GetEscapeState: TZEscapeState; begin Result := EscapeState; end; {** Gets a tokenizer default comment state. @returns a tokenizer default comment state. } function TZTokenizer.GetCommentState: TZCommentState; begin Result := CommentState; end; {** Gets a tokenizer default number state. @returns a tokenizer default number state. } function TZTokenizer.GetNumberState: TZNumberState; begin Result := NumberState; end; {** Gets a tokenizer default quote state. @returns a tokenizer default quote state. } function TZTokenizer.GetQuoteState: TZQuoteState; begin Result := QuoteState; end; {** Gets a tokenizer default symbol state. @returns a tokenizer default symbol state. } function TZTokenizer.GetSymbolState: TZSymbolState; begin Result := SymbolState; end; {** Gets a tokenizer default whitespace state. @returns a tokenizer default whitespace state. } function TZTokenizer.GetWhitespaceState: TZWhitespaceState; begin Result := WhitespaceState; end; {** Gets a tokenizer default word state. @returns a tokenizer default word state. } function TZTokenizer.GetWordState: TZWordState; begin Result := WordState; end; end. ================================================ FILE: lib/zeosdbo/src/core/ZURL.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Test Case for TZURL Class } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZURL; interface {$I ZCore.inc} uses Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils; type TZURLStringList = Class(TStringList) protected function GetTextStr: string; override; procedure SetTextStr(const Value: string); override; function GetURLText: String; public property URLText: String read GetURLText; end; TZURL = class private FPrefix: string; FProtocol: string; FHostName: string; FPort: Integer; FDatabase: string; FUserName: string; FPassword: string; FLibLocation: String; FProperties: TZURLStringList; FOnPropertiesChange: TNotifyEvent; procedure SetPrefix(const Value: string); procedure SetProtocol(const Value: string); procedure SetHostName(const Value: string); procedure SetConnPort(const Value: Integer); function GetDatabase: string; procedure SetDatabase(const Value: string); function GetUserName: string; procedure SetUserName(const Value: string); function GetPassword: string; procedure SetPassword(const Value: string); function GetLibLocation: String; procedure SetLibLocation(const Value: String); function GetURL: string; procedure SetURL(const Value: string); procedure DoOnPropertiesChange(Sender: TObject); function GetParamAndValue(AString: String; Var Param, Value: String): Boolean; procedure AddValues(Values: TStrings); public constructor Create; overload; constructor Create(const AURL: String); overload; constructor Create(const AURL: String; Info: TStrings); overload; constructor Create(const AURL: TZURL); overload; constructor Create(Const AURL, AHostName: string; const APort: Integer; const ADatabase, AUser, APassword: string; Info: TStrings); overload; destructor Destroy; override; property Prefix: string read FPrefix write SetPrefix; property Protocol: string read FProtocol write SetProtocol; property HostName: string read FHostName write SetHostName; property Port: Integer read FPort write SetConnPort; property Database: string read GetDatabase write SetDatabase; property UserName: string read GetUserName write SetUserName; property Password: string read GetPassword write SetPassword; property LibLocation: string read GetLibLocation write SetLibLocation; property Properties: TZURLStringList read FProperties; property URL: string read GetURL write SetURL; property OnPropertiesChange: TNotifyEvent read FOnPropertiesChange write FOnPropertiesChange; end; implementation uses ZCompatibility, StrUtils; {TZURLStringList} function TZURLStringList.GetTextStr: string; begin Result := inherited GetTextStr; Result := StringReplace(Result, #9, ';', [rfReplaceAll]); //unescape the #9 char to ';' end; procedure TZURLStringList.SetTextStr(const Value: string); begin inherited SetTextStr(StringReplace(Value, ';', #9, [rfReplaceAll])); //escape the ';' char to #9 end; function TZURLStringList.GetURLText: String; begin Result := StringReplace(GetTextStr, ';', #9, [rfReplaceAll]); //keep all ';' escaped Result := StringReplace(Result, LineEnding, ';', [rfReplaceAll]); //return a URL-usable string if Result[Length(Result)] = ';' then Result := Copy(Result, 1, Length(Result)-1); end; { TZURL } constructor TZURL.Create; begin inherited; FPrefix := 'zdbc'; FProperties := TZURLStringList.Create; FProperties.CaseSensitive := False; FProperties.NameValueSeparator := '='; FProperties.OnChange := DoOnPropertiesChange; end; constructor TZURL.Create(const AURL: String); begin Create; Self.URL := AURL; end; constructor TZURL.Create(const AURL: String; Info: TStrings); begin Create(AURL); if Assigned(Info) then AddValues(Info); end; constructor TZURL.Create(const AURL: TZURL); begin Create(AURL.URL); end; constructor TZURL.Create(Const AURL, AHostName: string; const APort: Integer; const ADatabase, AUser, APassword: string; Info: TStrings); begin Create(AURL); Self.HostName := AHostName; Self.Port := APort; Self.Database := ADataBase; Self.UserName := AUser; Self.Password := APassword; if Assigned(Info) then AddValues(Info); end; destructor TZURL.Destroy; begin FProperties.Free; inherited; end; procedure TZURL.SetPrefix(const Value: string); begin FPrefix := Value; end; procedure TZURL.SetProtocol(const Value: string); begin FProtocol := Value; end; procedure TZURL.SetHostName(const Value: string); begin FHostName := StringReplace(Value, ';', #9, [rfReplaceAll]); //escape the ';' char to #9 end; procedure TZURL.SetConnPort(const Value: Integer); begin FPort := Value; end; function TZURL.GetDatabase: string; begin Result := StringReplace(FDatabase, #9, ';', [rfReplaceAll]); //unescape the #9 char to ';' end; procedure TZURL.SetDatabase(const Value: string); begin FDatabase := StringReplace(Value, ';', #9, [rfReplaceAll]); //escape the ';' char to #9 end; function TZURL.GetUserName: string; begin Result := StringReplace(FUserName, #9, ';', [rfReplaceAll]); //unescape the #9 char to ';' end; procedure TZURL.SetUserName(const Value: string); begin FUserName := StringReplace(Value, ';', #9, [rfReplaceAll]); //escape the ';' char to #9 end; function TZURL.GetPassword: string; begin Result := StringReplace(FPassword, #9, ';', [rfReplaceAll]); //unescape the #9 char to ';' end; procedure TZURL.SetPassword(const Value: string); begin FPassword := StringReplace(Value, ';', #9, [rfReplaceAll]); //escape the ';' char to #9 end; function TZURL.GetLibLocation: String; begin Result := StringReplace(FLibLocation, #9, ';', [rfReplaceAll]); //unescape the #9 char to ';' end; procedure TZURL.SetLibLocation(const Value: String); begin FLibLocation := StringReplace(Value, ';', #9, [rfReplaceAll]); //escape the ';' char to #9 end; function TZURL.GetURL: string; var hasParamPart : boolean; procedure AddParamPart(const ParamPart: String); begin if hasParamPart then Result := Result + ';' else Result := Result + '?'; Result := Result + ParamPart; hasParamPart := True; end; begin Result := ''; hasParamPart := false; // Prefix Result := Result + Prefix + ':'; // Protocol Result := Result + Protocol + ':'; Result := Result + '//'; //Allways set the doubleslash to avoid unix '/' path issues if host is empty // HostName/Port if HostName <> '' then begin Result := Result + HostName; if Port <> 0 then Result := Result + ':' + IntToStr(Port); end; // Database if Database <> '' then Result := Result + '/' + FDatabase; // UserName if FUserName <> '' then AddParamPart('username=' + FUserName); // Password if FPassword <> '' then AddParamPart('password=' + FPassword); // Properties if Properties.Count > 0 then AddParamPart(Properties.GetURLText); //Adds the escaped string // LibLocation if FLibLocation <> '' then AddParamPart('LibLocation='+ FLibLocation); end; procedure TZURL.SetURL(const Value: string); var APrefix: string; AProtocol: string; AHostName: string; APort: string; ADatabase: string; AUserName: string; APassword: string; AProperties: TStrings; AValue: string; I: Integer; begin APrefix := ''; AProtocol := ''; AHostName := ''; APort := ''; ADatabase := ''; AUserName := ''; APassword := ''; AProperties := TStringList.Create; try AValue := Value; // APrefix I := Pos(':', AValue); if I = 0 then raise Exception.Create('TZURL.SetURL - The prefix is missing'); APrefix := Copy(AValue, 1, I - 1); Delete(AValue, 1, I); // AProtocol I := Pos(':', AValue); if I = 0 then raise Exception.Create('TZURL.SetURL - The protocol is missing'); AProtocol := Copy(AValue, 1, I - 1); Delete(AValue, 1, I); // AHostName if Pos('//', AValue) = 1 then begin Delete(AValue, 1, 2); if (Pos(':', AValue) > 0) and ((Pos(':', AValue) < Pos('/', AValue)) or (Pos('/', AValue)=0)) then AHostName := Copy(AValue, 1, Pos(':', AValue) - 1) else if Pos('/', AValue) > 0 then AHostName := Copy(AValue, 1, Pos('/', AValue) - 1) else if Pos('?', AValue) > 0 then AHostName := Copy(AValue, 1, Pos('?', AValue) - 1) else AHostName := AValue; Delete(AValue, 1, Length(AHostName)); // APort if Pos(':', AValue) = 1 then begin Delete(AValue, 1, 1); if Pos('/', AValue) > 0 then APort := Copy(AValue, 1, Pos('/', AValue) - 1) else if Pos('?', AValue) > 0 then APort := Copy(AValue, 1, Pos('?', AValue) - 1) else APort := AValue; Delete(AValue, 1, Length(APort)); end; end; if Pos('/', AValue) = 1 then Delete(AValue, 1, 1); // ADatabase I := Pos('?', AValue); if I > 0 then begin ADatabase := Copy(AValue, 1, I - 1); Delete(AValue, 1, I); AProperties.Text := StringReplace(AValue, ';', LineEnding, [rfReplaceAll]); end else ADatabase := AValue; FPrefix := APrefix; FProtocol := AProtocol; FHostName := AHostName; FPort := StrToIntDef(APort, 0); FDatabase := ADatabase; FUserName := AUserName; FPassword := APassword; FProperties.Text := AProperties.Text; finally AProperties.Free; end; end; procedure TZURL.DoOnPropertiesChange(Sender: TObject); begin FProperties.OnChange := nil; try if FProperties.Values['UID'] <> '' then begin UserName := FProperties.Values['UID']; FProperties.Delete(FProperties.IndexOfName('UID')); end; if FProperties.Values['PWD'] <> '' then begin Password := FProperties.Values['PWD']; FProperties.Delete(FProperties.IndexOfName('PWD')); end; if FProperties.Values['username'] <> '' then begin UserName := FProperties.Values['username']; FProperties.Delete(FProperties.IndexOfName('username')); end; if FProperties.Values['password'] <> '' then begin Password := FProperties.Values['password']; FProperties.Delete(FProperties.IndexOfName('password')); end; if FProperties.Values['LibLocation'] <> '' then begin LibLocation := FProperties.Values['LibLocation']; FProperties.Delete(FProperties.IndexOfName('LibLocation')); end; finally FProperties.OnChange := DoOnPropertiesChange; end; if Assigned(FOnPropertiesChange) then FOnPropertiesChange(Sender); end; function TZURL.GetParamAndValue(AString: String; Var Param, Value: String): Boolean; var DelimPos: Integer; begin DelimPos := PosEx('=', AString); Result := DelimPos <> 0; Param := ''; Value := ''; if DelimPos <> 0 then begin Param := Copy(AString, 1, DelimPos -1); Value := Copy(AString, DelimPos+1, Length(AString)-DelimPos); Result := Value <> ''; //avoid loosing empty but added Params. e.g TestIdentifierQuotes end; end; procedure TZURL.AddValues(Values: TStrings); var I: Integer; Param, Value: String; begin for i := 0 to Values.Count -1 do if GetParamAndValue(Values[i], Param, Value) then FProperties.Values[Param] := Value else FProperties.Add(Values[i]); end; end. ================================================ FILE: lib/zeosdbo/src/core/ZVariables.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Variables classes and interfaces } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZVariables; interface {$I ZCore.inc} uses SysUtils, Classes, Contnrs, ZCompatibility, ZVariant, ZExpression; type {** Implements a variable holder object. } TZVariable = class (TObject) private FName: string; FValue: TZVariant; public constructor Create(const Name: string; const Value: TZVariant); property Name: string read FName write FName; property Value: TZVariant read FValue write FValue; end; {** Implements a variables list. } TZVariablesList = class (TInterfacedObject, IZVariablesList) private FVariables: TObjectList; public constructor Create; destructor Destroy; override; function GetCount: Integer; function GetName(Index: Integer): string; function GetValue(Index: Integer): TZVariant; procedure SetValue(Index: Integer; const Value: TZVariant); function GetValueByName(const Name: string): TZVariant; procedure SetValueByName(const Name: string; const Value: TZVariant); procedure Add(const Name: string; const Value: TZVariant); procedure Remove(const Name: string); function FindByName(const Name: string): Integer; procedure ClearValues; procedure Clear; end; implementation uses ZMessages; { TZVariable } {** Creates a new instance of variable @param Name a variable name. @param Value a variable value. } constructor TZVariable.Create(const Name: string; const Value: TZVariant); begin FName := Name; FValue := Value; end; { TZVariablesList } {** Creates this variable list object. } constructor TZVariablesList.Create; begin FVariables := TObjectList.Create(True); end; {** Destroys this object and cleanups the memory. } destructor TZVariablesList.Destroy; begin FVariables.Clear; FreeAndNil(FVariables); inherited Destroy; end; {** Finds a variable by specified name. @param Name a name of the variable. @returns a found variable index or -1 otherwise. } function TZVariablesList.FindByName(const Name: string): Integer; var I: Integer; Current: TZVariable; UpperName: string; begin Result := -1; UpperName := UpperCase(Name); for I := 0 to FVariables.Count - 1 do begin Current := TZVariable(FVariables[I]); if Current.Name = UpperName then begin Result := I; Break; end; end; end; {** Adds a new variable with value. @param Name a name of the new variable. @param Value a value for the new variable. } procedure TZVariablesList.Add(const Name: string; const Value: TZVariant); begin if FindByName(Name) >= 0 then raise Exception.Create(Format(SVariableAlreadyExists, [Name])); FVariables.Add(TZVariable.Create(UpperCase(Name), Value)); end; {** Removes a variable by specified name. @param Name a name of variable to be removed. } procedure TZVariablesList.Remove(const Name: string); var Index: Integer; begin Index := FindByName(Name); if Index >= 0 then FVariables.Delete(Index); end; {** Clears all variables. } procedure TZVariablesList.Clear; begin FVariables.Clear; end; {** Clears only variable values. } procedure TZVariablesList.ClearValues; var I: Integer; begin for I := 0 to FVariables.Count - 1 do TZVariable(FVariables[I]).Value := NullVariant; end; {** Gets a number of registered variables. @returns a number of all registered variables. } function TZVariablesList.GetCount: Integer; begin Result := FVariables.Count; end; {** Gets a variable name by it's index. @param Index a variable index. @returns a variable name. } function TZVariablesList.GetName(Index: Integer): string; begin Result := TZVariable(FVariables[Index]).Name; end; {** Gets a variable value by it's index. @param Index a variable index. @returns a variable value } function TZVariablesList.GetValue(Index: Integer): TZVariant; begin Result := TZVariable(FVariables[Index]).Value; end; {** Gets a variable name by it's name. @param Name a variable name. @returns a variable value. } function TZVariablesList.GetValueByName(const Name: string): TZVariant; var Index: Integer; begin Index := FindByName(Name); if Index >= 0 then Result := TZVariable(FVariables[Index]).Value else Result := NullVariant; end; {** Sets a variable name by it's index. @param Index a variable index. @param Value a variable value. } procedure TZVariablesList.SetValue(Index: Integer; const Value: TZVariant); begin TZVariable(FVariables[Index]).Value := Value; end; {** Sets a variable name by it's name. @param Index a variable name. @param Value a variable value. } procedure TZVariablesList.SetValueByName(const Name: string; const Value: TZVariant); var Index: Integer; begin Index := FindByName(Name); if Index >= 0 then TZVariable(FVariables[Index]).Value := Value else Add(Name, Value); end; end. ================================================ FILE: lib/zeosdbo/src/core/ZVariant.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Variant Processing Classes } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZVariant; interface {$I ZCore.inc} uses {$IFNDEF FPC} Windows, //need for inline {$ENDIF} Classes, SysUtils, Types, ZCompatibility, ZClasses, ZSysUtils; const {** Precision for float values comparison } FLOAT_COMPARE_PRECISION = 1.0e-5; FLOAT_COMPARE_PRECISION_SINGLE = 1.5e-5; {FPC - Compatibility for SQLite (currently) } JULIAN_DAY_DISTANCE = 2415018.5; //distance from "julian day 0" (January 1, 4713 BC 12:00AM) to "1899-12-30 00:00AM"} type {** Defines variant types. } TZVariantType = (vtNull, vtBoolean, vtInteger, vtFloat, vtBytes, vtString, vtAnsiString, vtUTF8String, vtRawByteString, vtUnicodeString, //String Types vtDateTime, vtPointer, vtInterface); {** Defines a variant structure. } TZVariant = {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif} record VType: TZVariantType; VString: String; VAnsiString: AnsiString; VRawByteString: RawByteString; VUTF8String: UTF8String; VUnicodeString: ZWideString; VBytes: TByteDynArray; VInterface: IZInterface; case TZVariantType of vtBoolean: (VBoolean: Boolean); vtInteger: (VInteger: Int64); vtFloat: (VFloat: Extended); VtDateTime: (VDateTime: Double); // M.A. was TDateTime VtPointer: (VPointer: Pointer); end; PZVariant = ^TZVariant; {** Defines an array of variants. } TZVariantDynArray = array of TZVariant; {** Defines a variant processing exception. } EZVariantException = class (Exception); {** Defines an interface for variant data. } {** Defines a Variant Manager interface. } IZVariantManager = interface (IZInterface) ['{DAA373D9-1A98-4AA8-B65E-4C23167EE83F}'] function IsNull(const Value: TZVariant): Boolean; procedure SetNull(var Value: TZVariant); function Convert(const Value: TZVariant; NewType: TZVariantType): TZVariant; procedure Assign(const SrcValue: TZVariant; var DstValue: TZVariant); function Clone(const Value: TZVariant): TZVariant; function Compare(const Value1, Value2: TZVariant): Integer; function GetAsBoolean(const Value: TZVariant): Boolean; function GetAsBytes(const Value: TZVariant): TByteDynArray; function GetAsInteger(const Value: TZVariant): Int64; function GetAsFloat(const Value: TZVariant): Extended; function GetAsString(const Value: TZVariant): String; function GetAsAnsiString(const Value: TZVariant): AnsiString; function GetAsRawByteString(const Value: TZVariant): RawByteString; overload; function GetAsUTF8String(const Value: TZVariant): UTF8String; function GetAsUnicodeString(const Value: TZVariant): ZWideString; function GetAsDateTime(const Value: TZVariant): TDateTime; function GetAsPointer(const Value: TZVariant): Pointer; function GetAsInterface(const Value: TZVariant): IZInterface; procedure SetAsBoolean(var Value: TZVariant; Data: Boolean); procedure SetAsBytes(var Value: TZVariant; const Data: TByteDynArray); procedure SetAsInteger(var Value: TZVariant; Data: Int64); procedure SetAsFloat(var Value: TZVariant; Data: Extended); procedure SetAsString(var Value: TZVariant; const Data: String); procedure SetAsAnsiString(var Value: TZVariant; const Data: AnsiString); procedure SetAsUTF8String(var Value: TZVariant; const Data: UTF8String); procedure SetAsRawByteString(var Value: TZVariant; const Data: RawByteString); procedure SetAsUnicodeString(var Value: TZVariant; const Data: ZWideString); procedure SetAsDateTime(var Value: TZVariant; Data: TDateTime); procedure SetAsPointer(var Value: TZVariant; Data: Pointer); procedure SetAsInterface(var Value: TZVariant; Data: IZInterface); function OpAdd(const Value1, Value2: TZVariant): TZVariant; function OpSub(const Value1, Value2: TZVariant): TZVariant; function OpMul(const Value1, Value2: TZVariant): TZVariant; function OpDiv(const Value1, Value2: TZVariant): TZVariant; function OpMod(const Value1, Value2: TZVariant): TZVariant; function OpPow(const Value1, Value2: TZVariant): TZVariant; function OpAnd(const Value1, Value2: TZVariant): TZVariant; function OpOr(const Value1, Value2: TZVariant): TZVariant; function OpXor(const Value1, Value2: TZVariant): TZVariant; function OpNot(const Value: TZVariant): TZVariant; function OpNegative(const Value: TZVariant): TZVariant; function OpEqual(const Value1, Value2: TZVariant): TZVariant; function OpNotEqual(const Value1, Value2: TZVariant): TZVariant; function OpMore(const Value1, Value2: TZVariant): TZVariant; function OpLess(const Value1, Value2: TZVariant): TZVariant; function OpMoreEqual(const Value1, Value2: TZVariant): TZVariant; function OpLessEqual(const Value1, Value2: TZVariant): TZVariant; end; {** Implements a variant manager with strict convertion rules. } TZDefaultVariantManager = class (TInterfacedObject, IZVariantManager) private ZAnsiToUTF8: TZAnsiToUTF8; ZUTF8ToAnsi: TZUTF8ToAnsi; ZUTF8ToString: TZUTF8ToString; ZStringToUTF8: TZStringToUTF8; FSystemCodePage: Word; protected procedure RaiseTypeMismatchError; procedure RaiseUnsupportedOperation; public constructor Create; function Convert(const Value: TZVariant; NewType: TZVariantType): TZVariant; virtual; procedure Assign(const SrcValue: TZVariant; var DstValue: TZVariant); function Clone(const Value: TZVariant): TZVariant; function Compare(const Value1, Value2: TZVariant): Integer; function IsNull(const Value: TZVariant): Boolean; procedure SetNull(var Value: TZVariant); function GetAsBoolean(const Value: TZVariant): Boolean; function GetAsBytes(const Value: TZVariant): TByteDynArray; function GetAsInteger(const Value: TZVariant): Int64; function GetAsFloat(const Value: TZVariant): Extended; function GetAsString(const Value: TZVariant): String; function GetAsAnsiString(const Value: TZVariant): AnsiString; function GetAsUTF8String(const Value: TZVariant): UTF8String; function GetAsRawByteString(const Value: TZVariant): RawByteString; overload; function GetAsUnicodeString(const Value: TZVariant): ZWideString; function GetAsDateTime(const Value: TZVariant): TDateTime; function GetAsPointer(const Value: TZVariant): Pointer; function GetAsInterface(const Value: TZVariant): IZInterface; procedure SetAsBoolean(var Value: TZVariant; Data: Boolean); procedure SetAsBytes(var Value: TZVariant; const Data: TByteDynArray); procedure SetAsInteger(var Value: TZVariant; Data: Int64); procedure SetAsFloat(var Value: TZVariant; Data: Extended); procedure SetAsString(var Value: TZVariant; const Data: String); procedure SetAsAnsiString(var Value: TZVariant; const Data: AnsiString); procedure SetAsUTF8String(var Value: TZVariant; const Data: UTF8String); procedure SetAsRawByteString(var Value: TZVariant; const Data: RawByteString); procedure SetAsUnicodeString(var Value: TZVariant; const Data: ZWideString); procedure SetAsDateTime(var Value: TZVariant; Data: TDateTime); procedure SetAsPointer(var Value: TZVariant; Data: Pointer); procedure SetAsInterface(var Value: TZVariant; Data: IZInterface); function OpAdd(const Value1, Value2: TZVariant): TZVariant; function OpSub(const Value1, Value2: TZVariant): TZVariant; function OpMul(const Value1, Value2: TZVariant): TZVariant; function OpDiv(const Value1, Value2: TZVariant): TZVariant; function OpMod(const Value1, Value2: TZVariant): TZVariant; function OpPow(const Value1, Value2: TZVariant): TZVariant; function OpAnd(const Value1, Value2: TZVariant): TZVariant; function OpOr(const Value1, Value2: TZVariant): TZVariant; function OpXor(const Value1, Value2: TZVariant): TZVariant; function OpNot(const Value: TZVariant): TZVariant; function OpNegative(const Value: TZVariant): TZVariant; function OpEqual(const Value1, Value2: TZVariant): TZVariant; function OpNotEqual(const Value1, Value2: TZVariant): TZVariant; function OpMore(const Value1, Value2: TZVariant): TZVariant; function OpLess(const Value1, Value2: TZVariant): TZVariant; function OpMoreEqual(const Value1, Value2: TZVariant): TZVariant; function OpLessEqual(const Value1, Value2: TZVariant): TZVariant; end; {** Implements a variant manager with soft convertion rules. } TZSoftVariantManager = class (TZDefaultVariantManager) public function Convert(const Value: TZVariant; NewType: TZVariantType): TZVariant; override; end; IZClientVariantManager = Interface(IZVariantManager) ['{73A1A2C7-7C38-4620-B7FE-2426BF839BE5}'] function GetAsRawByteString(const Value: TZVariant; const RawCP: Word): RawByteString; overload; End; {** Implements a variant manager with connection related convertion rules. } TZClientVariantManager = class (TZDefaultVariantManager, IZClientVariantManager) private FConSettings: PZConSettings; public constructor Create(const ConSettings: PZConSettings); function Convert(const Value: TZVariant; NewType: TZVariantType): TZVariant; override; function GetAsRawByteString(const Value: TZVariant; const RawCP: Word): RawByteString; overload; end; type {** Represents any value interface. } IZAnyValue = interface (IZClonnable) ['{E81988B3-FD0E-4524-B658-B309B02F0B6A}'] function IsNull: Boolean; function GetValue: TZVariant; function GetBoolean: Boolean; function GetBytes: TByteDynArray; function GetInteger: Int64; function GetFloat: Extended; function GetString: String; function GetAnsiString: AnsiString; function GetUTF8String: UTF8String; function GetUnicodeString: ZWideString; function GetDateTime: TDateTime; end; {** Implements an any value object. } TZAnyValue = class(TZAbstractObject, IZAnyValue, IZComparable) private FValue: TZVariant; public constructor Create(const Value: TZVariant); constructor CreateWithBoolean(Value: Boolean); constructor CreateWithInteger(Value: Int64); constructor CreateWithFloat(Value: Extended); constructor CreateWithString(const Value: String); {$IFDEF UNICODE} // unicodeType is a (dummy) default parameter to avoid // the problem described in https://forums.codegear.com/thread.jspa?messageID=65681 // when dcc creates header (.hpp)-files for c++ builder. Both 'String' and // 'UnicodeString' translate into 'UnicodeString' in C++ builder 2009/2010, and // CreateWithString and CreateWithUnicodeString would result in duplicate // C++ constructors. constructor CreateWithUnicodeString(const Value: String; unicodeType: Boolean=true); {$ELSE} constructor CreateWithUnicodeString(const Value: WideString); {$ENDIF} constructor CreateWithDateTime(Value: TDateTime); function IsNull: Boolean; function GetValue: TZVariant; function GetBoolean: Boolean; function GetBytes: TByteDynArray; function GetInteger: Int64; function GetFloat: Extended; function GetString: String; function GetAnsiString: AnsiString; function GetUTF8String: UTF8String; function GetUnicodeString: ZWideString; function GetDateTime: TDateTime; function Equals(const Value: IZInterface): Boolean; override; function Clone: IZInterface; override; function ToString: string; override; end; {** Encodes a custom variant value into standard variant. @param Value a custom variant value to be encoded. @returns an encoded standard variant. } function EncodeVariant(const Value: TZVariant): Variant; {** Encodes an array of custom variant values into array of standard variants. @param Value an array of custom variant values to be encoded. @returns an encoded array of standard variants. } function EncodeVariantArray(const Value: TZVariantDynArray): Variant; {** Decodes a standard variant value into custom variant. @param Value a standard variant value to be decoded. @returns an decoded custom variant. } function DecodeVariant(const Value: Variant): TZVariant; {** Decodes an array of standard variant values into array of custom variants. @param Value an array of standard variant values to be decoded. @returns an decoded array of custom variants. } function DecodeVariantArray(const Value: Variant): TZVariantDynArray; {** Encodes null into a custom variant. @returns an decoded custom variant. } function EncodeNull : TZVariant; {** Encodes a boolean into a custom variant. @param Value a boolean value to be encoded. @returns an encoded custom variant. } function EncodeBoolean(const Value: Boolean): TZVariant; {** Encodes a Byte array into a custom variant. @param Value a boolean value to be encoded. @returns an encoded custom variant. } function EncodeBytes(const Value: TByteDynArray): TZVariant; {** Encodes an integer into a custom variant. @param Value an intger value to be encoded. @returns an encoded custom variant. } function EncodeInteger(const Value: Int64): TZVariant; {** Encodes a float into a custom variant. @param Value a float value to be encoded. @returns an encoded custom variant. } function EncodeFloat(const Value: Extended): TZVariant; {** Encodes a String into a custom variant. @param Value a String value to be encoded. @returns an encoded custom variant. } function EncodeString(const Value: String): TZVariant; {** Encodes a AnsiString into a custom variant. @param Value a AnsiString value to be encoded. @returns an encoded custom variant. } function EncodeAnsiString(const Value: AnsiString): TZVariant; {** Encodes a UTF8String into a custom variant. @param Value a UTF8String value to be encoded. @returns an encoded custom variant. } function EncodeUTF8String(const Value: UTF8String): TZVariant; {** Encodes a RawByteString into a custom variant. @param Value a RawByteString value to be encoded. @param CP the CoodePage of the Value string. @returns an encoded custom variant. } function EncodeRawByteString(const Value: RawByteString): TZVariant; {** Encodes a unicodestring into a custom variant. @param Value a unicodestring value to be encoded. @returns an encoded custom variant. } function EncodeUnicodeString(const Value: ZWideString): TZVariant; {** Encodes a TDateTime into a custom variant. @param Value a TDateTime value to be encoded. @returns an encoded custom variant. } function EncodeDateTime(const Value: TDateTime): TZVariant; {** Encodes a pointer into a custom variant. @param Value a pointer value to be encoded. @returns an encoded custom variant. } function EncodePointer(const Value: Pointer): TZVariant; {** Encodes an interface into a custom variant. @param Value an interface value to be encoded. @returns an encoded custom variant. } function EncodeInterface(const Value: IZInterface): TZVariant; var {** Declares a default variant manager with strict convertion rules. } DefVarManager: IZVariantManager; {** Declares a variant manager with soft convertion rules. } SoftVarManager: IZVariantManager; {** A NULL Variant Value. } NullVariant: TZVariant; implementation uses Variants, Math, ZMessages, ZEncoding {$IFDEF WITH_ANSISTRCOMP_DEPRECATED}, AnsiStrings{$ENDIF}; { TZDefaultVariantManager } {** Constructs this object and assignes the main properties. } constructor TZDefaultVariantManager.Create; begin inherited; FSystemCodePage := ZDefaultSystemCodePage; if ZCompatibleCodePages(zCP_UTF8, FSystemCodePage) then begin ZAnsiToUTF8 := @ZMoveAnsiToUTF8; ZUTF8ToAnsi := @ZMoveUTF8ToAnsi; ZUTF8ToString := @ZMoveUTF8ToString; ZStringToUTF8 := @ZMoveStringToUTF8; end else begin ZAnsiToUTF8 := @ZConvertAnsiToUTF8; ZUTF8ToAnsi := @ZConvertUTF8ToAnsi; ZUTF8ToString := @ZConvertUTF8ToString; ZStringToUTF8 := @ZConvertStringToUTF8; end; end; {** Assignes one variant value to another one. @param SrcValue a source variant value. @param DstValue a destination variant value. } procedure TZDefaultVariantManager.Assign(const SrcValue: TZVariant; var DstValue: TZVariant); begin DstValue.VType := SrcValue.VType; case SrcValue.VType of vtBoolean: DstValue.VBoolean := SrcValue.VBoolean; vtBytes: DstValue.VBytes := SrcValue.VBytes; vtInteger: DstValue.VInteger := SrcValue.VInteger; vtFloat: DstValue.VFloat := SrcValue.VFloat; vtString: DstValue.VString := SrcValue.VString; vtAnsiString: DstValue.VAnsiString := SrcValue.VAnsiString; vtRawByteString: DstValue.VRawByteString := SrcValue.VRawByteString; vtUTF8String: DstValue.VUTF8String := SrcValue.VUTF8String; vtUnicodeString: DstValue.VUnicodeString := SrcValue.VUnicodeString; vtDateTime: DstValue.VDateTime := SrcValue.VDateTime; vtPointer: DstValue.VPointer := SrcValue.VPointer; vtInterface: DstValue.VInterface := SrcValue.VInterface; end; end; {** Clones a variant value. @param Value a source variant value. @returns a clonned variant value. } function TZDefaultVariantManager.Clone(const Value: TZVariant): TZVariant; begin Assign(Value, Result); end; {** Raises a type mismatch exception. } procedure TZDefaultVariantManager.RaiseTypeMismatchError; begin raise EZVariantException.Create(STypesMismatch); end; {** Raises an unsupported operation exception. } procedure TZDefaultVariantManager.RaiseUnsupportedOperation; begin raise EZVariantException.Create(SUnsupportedOperation); end; {** Converts a specified variant value to a new type. @param Value a variant value to be converted. @param NewType a type of the result variant value. @returns a converted variant value. } function TZDefaultVariantManager.Convert(const Value: TZVariant; NewType: TZVariantType): TZVariant; begin Result.VType := NewType; case NewType of vtBoolean: case Value.VType of vtNull: Result.VBoolean := False; vtBoolean: Result.VBoolean := Value.VBoolean; else RaiseTypeMismatchError; end; vtBytes: case Value.VType of vtNull: Result.VBytes := nil; vtBytes: Result.VBytes := Value.VBytes; vtString: Result.VBytes := StrToBytes(Value.VString); vtAnsiString: Result.VBytes := StrToBytes(Value.VAnsiString); vtRawByteString: Result.VBytes := StrToBytes(Value.VRawByteString); vtUTF8String: Result.VBytes := StrToBytes(Value.VUTF8String); vtUnicodeString: Result.VBytes := StrToBytes(Value.VUnicodeString); else RaiseTypeMismatchError; end; vtInteger: case Value.VType of vtNull: Result.VInteger := 0; vtBoolean: if Value.VBoolean then Result.VInteger := 1 else Result.VInteger := 0; vtInteger: Result.VInteger := Value.VInteger; else RaiseTypeMismatchError; end; vtFloat: case Value.VType of vtNull: Result.VFloat := 0; vtBoolean: if Value.VBoolean then Result.VFloat := 1 else Result.VFloat := 0; vtInteger: Result.VFloat := Value.VInteger; vtFloat: Result.VFloat := Value.VFloat; else RaiseTypeMismatchError; end; vtString: case Value.VType of vtNull: Result.VString := ''; vtBytes: Result.VString := {$IFDEF UNICODE}String{$ENDIF}(BytesToStr(Value.VBytes)); vtString: Result.VString := Value.VString; vtAnsiString: Result.VString := {$IFDEF UNICODE}String{$ENDIF}(Value.VAnsiString); vtUTF8String: Result.VString := ZUTF8ToString(Value.VUTF8String, FSystemCodePage); vtUnicodeString: Result.VString := {$IFNDEF UNICODE}String{$ENDIF}(Value.VUnicodeString); else RaiseTypeMismatchError; end; vtAnsiString: case Value.VType of vtNull: Result.VAnsiString := ''; vtBytes: Result.VAnsiString := BytesToStr(Value.VBytes); vtString: Result.VAnsiString := {$IFDEF UNICODE}AnsiString{$ENDIF}(Value.VString); vtAnsiString: Result.VAnsiString := Value.VAnsiString; vtUTF8String: Result.VAnsiString := ZUTF8ToAnsi(Value.VUTF8String); vtUnicodeString: Result.VAnsiString := AnsiString(Value.VUnicodeString); else RaiseTypeMismatchError; end; vtUTF8String: case Value.VType of vtNull: Result.VUTF8String := ''; vtBytes: ZSetString(PAnsiChar(Value.VBytes), Length(Value.VBytes), Result.VUTF8String); vtString: Result.VUTF8String := ZStringToUTF8(Value.VString, FSystemCodePage); vtAnsiString: Result.VUTF8String := ZAnsiToUTF8(Value.VAnsiString); vtUTF8String: Result.VUTF8String := Value.VUTF8String; vtUnicodeString: {$IFDEF WITH_RAWBYTESTRING} Result.VUTF8String := UTF8String(Value.VUnicodeString); {$ELSE} Result.VUTF8String := UTF8Encode(Value.VUnicodeString); {$ENDIF} else RaiseTypeMismatchError; end; vtRawByteString: case Value.VType of vtNull: Result.VRawByteString := ''; vtBytes: ZSetString(PAnsiChar(Value.VBytes), Length(Value.VBytes), Result.VRawByteString); vtRawByteString: Result.VRawByteString := Value.VRawByteString; else RaiseTypeMismatchError; end; vtUnicodeString: case Value.VType of vtNull: Result.VUnicodeString := ''; vtString: Result.VUnicodeString := {$IFNDEF UNICODE}ZWideString{$ENDIF}(Value.VString); //Cast ansi to Wide/Unicode vtAnsiString: Result.VUnicodeString := ZWideString(Value.VAnsiString); //Cast ansi to Wide/Unicode vtUTF8String: Result.VUnicodeString := {$IFDEF WITH_RAWBYTESTRING} ZWideString(Value.VUTF8String); {$ELSE} UTF8ToString(PAnsiChar(Value.VUTF8String)); {$ENDIF} vtUnicodeString: Result.VUnicodeString := Value.VUnicodeString; else RaiseTypeMismatchError; end; vtDateTime: case Value.VType of vtNull: Result.VDateTime := 0; vtDateTime: Result.VDateTime := Value.VDateTime; else RaiseTypeMismatchError; end; vtPointer: case Value.VType of vtNull: Result.VPointer := nil; vtPointer: Result.VPointer := Value.VPointer; else RaiseTypeMismatchError; end; vtInterface: case Value.VType of vtNull: Result.VInterface := nil; vtInterface: Result.VInterface := Value.VInterface; else RaiseTypeMismatchError; end; end; end; {** Compares two variant values. @param Value1 the first variant value. @param Value2 the second variant value. @return <0 if Value1 < Value 2, =0 if Value1 = Value2, >0 if Value1 > Value2 } function TZDefaultVariantManager.Compare(const Value1, Value2: TZVariant): Integer; var TempFloat: Extended; TempDateTime: TDateTime; begin case Value1.VType of vtNull: begin if IsNull(Value2) then Result := 0 else Result := -1; end; vtBoolean: begin if GetAsBoolean(Value2) then begin if Value1.VBoolean then Result := 0 else Result := -1; end else begin if Value1.VBoolean then Result := 1 else Result := 0; end; end; vtInteger: Result := Value1.VInteger - GetAsInteger(Value2); vtFloat: begin TempFloat := GetAsFloat(Value2); if Value1.VFloat - TempFloat < -FLOAT_COMPARE_PRECISION then Result := -1 else if Value1.VFloat - TempFloat > FLOAT_COMPARE_PRECISION then Result := 1 else Result := 0; end; { TODO -oEgonHugeist -cOptimierung : String typed needs to be reviewed for a more optimal way. Simple ByteCompare instead of functions which are codepage dependent should be faster, thought. } vtString: Result := AnsiStrComp(PChar(Value1.VString), PChar(GetAsString(Value2))); vtAnsiString: Result := {$IFDEF WITH_ANSISTRCOMP_DEPRECATED}AnsiStrings.{$ENDIF}AnsiStrComp(PAnsiChar(Value1.VAnsiString), PAnsiChar(GetAsAnsiString(Value2))); vtUTF8String: Result := {$IFDEF WITH_ANSISTRCOMP_DEPRECATED}AnsiStrings.{$ENDIF}AnsiStrComp(PAnsiChar(GetAsAnsiString(Value1)), PAnsiChar(GetAsAnsiString(Value2))); vtRawByteString: Result := {$IFDEF WITH_ANSISTRCOMP_DEPRECATED}AnsiStrings.{$ENDIF}AnsiStrComp(PAnsiChar(GetAsAnsiString(Value1)), PAnsiChar(GetAsAnsiString(Value2))); vtUnicodeString: {$IFNDEF FPC} {$IFDEF UNICODE} Result := AnsiCompareStr(Value1.VUnicodeString, GetAsUnicodeString(Value2)); {$ELSE} Result := WideCompareStr(Value1.VUnicodeString, GetAsUnicodeString(Value2)); {$ENDIF} {$ELSE} Result := AnsiCompareStr(AnsiString(Value1.VUnicodeString), GetAsString(Value2)); {$ENDIF} vtDateTime: begin TempDateTime := GetAsDateTime(Value2); if Value1.VDateTime < TempDateTime then Result := -1 else if Value1.VDateTime > TempDateTime then Result := 1 else Result := 0; end; vtPointer: Result := sign(NativeInt(Value1.VPointer) - GetAsInteger(Value2)); else Result := 0; end; end; {** Checks is the specified value NULL. @param Value a value to be checked. @returns True if variant has NULL value. } function TZDefaultVariantManager.IsNull(const Value: TZVariant): Boolean; begin Result := Value.VType = vtNull; end; {** Sets the NULL value to specified variant. @param Value variant value to be set to NULL. } procedure TZDefaultVariantManager.SetNull(var Value: TZVariant); begin Value := EncodeNull; end; {** Gets a variant to boolean value. @param Value a variant to be converted. @param a result value. } function TZDefaultVariantManager.GetAsBoolean( const Value: TZVariant): Boolean; begin Result := Convert(Value, vtBoolean).VBoolean; end; {** Gets a variant to boolean value. @param Value a variant to be converted. @param a result value. } function TZDefaultVariantManager.GetAsBytes( const Value: TZVariant): TByteDynArray; begin Result := Convert(Value, vtBytes).VBytes; end; {** Gets a variant to integer value. @param Value a variant to be converted. @param a result value. } function TZDefaultVariantManager.GetAsInteger( const Value: TZVariant): Int64; begin Result := Convert(Value, vtInteger).VInteger; end; {** Gets a variant to float value. @param Value a variant to be converted. @param a result value. } function TZDefaultVariantManager.GetAsFloat( const Value: TZVariant): Extended; begin Result := Convert(Value, vtFloat).VFloat; end; {** Gets a variant to string value. @param Value a variant to be converted. @param a result value. } function TZDefaultVariantManager.GetAsString( const Value: TZVariant): String; begin Result := Convert(Value, vtString).VString; end; {** Gets a variant to string value. @param Value a variant to be converted. @param a result value. } function TZDefaultVariantManager.GetAsAnsiString( const Value: TZVariant): AnsiString; begin Result := Convert(Value, vtAnsiString).VAnsiString; end; function TZDefaultVariantManager.GetAsUTF8String(const Value: TZVariant): UTF8String; begin Result := Convert(Value, vtUTF8String).VUTF8String; end; function TZDefaultVariantManager.GetAsRawByteString(const Value: TZVariant): RawByteString; begin Result := Convert(Value, vtRawByteString).VRawByteString; end; {** Gets a variant to unicode string value. @param Value a variant to be converted. @param a result value. } function TZDefaultVariantManager.GetAsUnicodeString( const Value: TZVariant): ZWideString; begin Result := Convert(Value, vtUnicodeString).VUnicodeString; end; {** Gets a variant to date and time value. @param Value a variant to be converted. @param a result value. } function TZDefaultVariantManager.GetAsDateTime( const Value: TZVariant): TDateTime; begin Result := Convert(Value, vtDateTime).VDateTime; end; {** Gets a variant to pointer value. @param Value a variant to be converted. @param a result value. } function TZDefaultVariantManager.GetAsPointer( const Value: TZVariant): Pointer; begin Result := Convert(Value, vtPointer).VPointer; end; {** Gets a variant to interface value. @param Value a variant to be converted. @param a result value. } function TZDefaultVariantManager.GetAsInterface( const Value: TZVariant): IZInterface; begin Result := Convert(Value, vtInterface).VInterface; end; {** Assignes a boolean value to variant. @param Value a variant to store the value. @param Data a value to be assigned. } procedure TZDefaultVariantManager.SetAsBoolean(var Value: TZVariant; Data: Boolean); begin Value := EncodeBoolean(Data); end; {** Assignes a Byte array value to variant. @param Value a variant to store the value. @param Data a value to be assigned. } procedure TZDefaultVariantManager.SetAsBytes(var Value: TZVariant; const Data: TByteDynArray); begin Value := EncodeBytes(Data); end; {** Assignes an integer value to variant. @param Value a variant to store the value. @param Data a value to be assigned. } procedure TZDefaultVariantManager.SetAsInteger(var Value: TZVariant; Data: Int64); begin Value := EncodeInteger(Data); end; {** Assignes a float value to variant. @param Value a variant to store the value. @param Data a value to be assigned. } procedure TZDefaultVariantManager.SetAsFloat(var Value: TZVariant; Data: Extended); begin Value := EncodeFloat(Data); end; {** Assignes a String value to variant. @param Value a variant to store the value. @param Data a value to be assigned. } procedure TZDefaultVariantManager.SetAsString(var Value: TZVariant; const Data: String); begin Value := EncodeString(Data); end; {** Assignes a AnsiString value to variant. @param Value a variant to store the value. @param Data a value to be assigned. } procedure TZDefaultVariantManager.SetAsAnsiString(var Value: TZVariant; const Data: AnsiString); begin Value := EncodeAnsiString(Data); end; {** Assignes a UTF8string value to variant. @param Value a variant to store the value. @param Data a value to be assigned. } procedure TZDefaultVariantManager.SetAsUTF8String(var Value: TZVariant; const Data: UTF8String); begin Value := EncodeUTF8String(Data); end; {** Assignes a RawByteString value to variant. @param Value a variant to store the value. @param Data a value to be assigned. @param CP the CodePage of the Data string } procedure TZDefaultVariantManager.SetAsRawByteString(var Value: TZVariant; const Data: RawByteString); begin Value := EncodeRawByteString(Data); end; {** Assignes a unicode string value to variant. @param Value a variant to store the value. @param Data a value to be assigned. } procedure TZDefaultVariantManager.SetAsUnicodeString(var Value: TZVariant; const Data: ZWideString); begin Value := EncodeUnicodeString(Data); end; {** Assignes a datetime value to variant. @param Value a variant to store the value. @param Data a value to be assigned. } procedure TZDefaultVariantManager.SetAsDateTime(var Value: TZVariant; Data: TDateTime); begin Value := EncodeDateTime(Data); end; {** Assignes a pointer value to variant. @param Value a variant to store the value. @param Data a value to be assigned. } procedure TZDefaultVariantManager.SetAsPointer(var Value: TZVariant; Data: Pointer); begin Value := EncodePointer(Data); end; {** Assignes a interface value to variant. @param Value a variant to store the value. @param Data a value to be assigned. } procedure TZDefaultVariantManager.SetAsInterface(var Value: TZVariant; Data: IZInterface); begin Value := EncodeInterface(Data); end; {** Performs '+' operation. @param Value1 the first variant argument. @param Value2 the second variant argument. @returns an operation result. } function TZDefaultVariantManager.OpAdd(const Value1, Value2: TZVariant): TZVariant; begin case Value1.VType of vtNull: Result := EncodeNull; vtInteger: Result := EncodeInteger(Value1.VInteger + GetAsInteger(Value2)); vtFloat: Result := EncodeFloat(Value1.VFloat + GetAsFloat(Value2)); vtString: Result := EncodeString(Value1.VString + GetAsString(Value2)); vtAnsiString: Result := EncodeAnsiString(Value1.VAnsiString + GetAsAnsiString(Value2)); vtUTF8String: Result := EncodeUTF8String(Value1.VUTF8String + GetAsUTF8String(Value2)); vtRawByteString: Result := EncodeRawByteString(Value1.VRawByteString + GetAsRawByteString(Value2)); vtUnicodeString: Result := EncodeUnicodeString(Value1.VUnicodeString + GetAsUnicodeString(Value2)); vtDateTime: Result := EncodeDateTime(Value1.VDateTime + GetAsDateTime(Value2)); else RaiseUnsupportedOperation; end; end; {** Performs '&' operation. @param Value1 the first variant argument. @param Value2 the second variant argument. @returns an operation result. } function TZDefaultVariantManager.OpAnd(const Value1, Value2: TZVariant): TZVariant; begin case Value1.VType of vtNull: Result := EncodeNull; vtBoolean: Result := EncodeBoolean(Value1.VBoolean and GetAsBoolean(Value2)); vtInteger: Result := EncodeInteger(Value1.VInteger and GetAsInteger(Value2)); else RaiseUnsupportedOperation; end; end; {** Performs '/' operation. @param Value1 the first variant argument. @param Value2 the second variant argument. @returns an operation result. } function TZDefaultVariantManager.OpDiv(const Value1, Value2: TZVariant): TZVariant; begin case Value1.VType of vtNull: Result := EncodeNull; vtInteger: Result := EncodeInteger(Value1.VInteger div GetAsInteger(Value2)); vtFloat: Result := EncodeFloat(Value1.VFloat / GetAsFloat(Value2)); else RaiseUnsupportedOperation; end; end; {** Performs '=' operation. @param Value1 the first variant argument. @param Value2 the second variant argument. @returns an operation result. } function TZDefaultVariantManager.OpEqual(const Value1, Value2: TZVariant): TZVariant; begin Result := EncodeBoolean(Compare(Value1, Value2) = 0); end; {** Performs '<' operation. @param Value1 the first variant argument. @param Value2 the second variant argument. @returns an operation result. } function TZDefaultVariantManager.OpLess(const Value1, Value2: TZVariant): TZVariant; begin Result := EncodeBoolean(Compare(Value1, Value2) < 0); end; {** Performs '<=' operation. @param Value1 the first variant argument. @param Value2 the second variant argument. @returns an operation result. } function TZDefaultVariantManager.OpLessEqual(const Value1, Value2: TZVariant): TZVariant; begin Result := EncodeBoolean(Compare(Value1, Value2) <= 0); end; {** Performs '%' operation. @param Value1 the first variant argument. @param Value2 the second variant argument. @returns an operation result. } function TZDefaultVariantManager.OpMod(const Value1, Value2: TZVariant): TZVariant; begin case Value1.VType of vtNull: Result := EncodeNull; vtInteger: Result := EncodeInteger(Value1.VInteger mod GetAsInteger(Value2)); else RaiseUnsupportedOperation; end; end; {** Performs '>' operation. @param Value1 the first variant argument. @param Value2 the second variant argument. @returns an operation result. } function TZDefaultVariantManager.OpMore(const Value1, Value2: TZVariant): TZVariant; begin Result := EncodeBoolean(Compare(Value1, Value2) > 0); end; {** Performs '>=' operation. @param Value1 the first variant argument. @param Value2 the second variant argument. @returns an operation result. } function TZDefaultVariantManager.OpMoreEqual(const Value1, Value2: TZVariant): TZVariant; begin Result := EncodeBoolean(Compare(Value1, Value2) >= 0); end; {** Performs '*' operation. @param Value1 the first variant argument. @param Value2 the second variant argument. @returns an operation result. } function TZDefaultVariantManager.OpMul(const Value1, Value2: TZVariant): TZVariant; begin case Value1.VType of vtNull: Result := EncodeNull; vtInteger: Result := EncodeInteger(Value1.VInteger * GetAsInteger(Value2)); vtFloat: Result := EncodeFloat(Value1.VFloat * GetAsFloat(Value2)); else RaiseUnsupportedOperation; end; end; {** Performs unary '-' operation. @param Value the variant argument. @returns an operation result. } function TZDefaultVariantManager.OpNegative(const Value: TZVariant): TZVariant; begin case Value.VType of vtNull: Result := EncodeNull; vtInteger: Result := EncodeInteger(-Value.VInteger); vtFloat: Result := EncodeFloat(-Value.VFloat); else RaiseUnsupportedOperation; end; end; {** Performs '~' operation. @param Value the variant argument. @returns an operation result. } function TZDefaultVariantManager.OpNot(const Value: TZVariant): TZVariant; begin case Value.VType of vtNull: Result := EncodeNull; vtBoolean: Result := EncodeBoolean(not Value.VBoolean); vtInteger: Result := EncodeInteger(not Value.VInteger); else RaiseUnsupportedOperation; end; end; {** Performs '<>' operation. @param Value1 the first variant argument. @param Value2 the second variant argument. @returns an operation result. } function TZDefaultVariantManager.OpNotEqual(const Value1, Value2: TZVariant): TZVariant; begin Result := EncodeBoolean(Compare(Value1, Value2) <> 0); end; {** Performs '|' operation. @param Value1 the first variant argument. @param Value2 the second variant argument. @returns an operation result. } function TZDefaultVariantManager.OpOr(const Value1, Value2: TZVariant): TZVariant; begin case Value1.VType of vtNull: SetNull(Result); vtBoolean: Result := EncodeBoolean(Value1.VBoolean or GetAsBoolean(Value2)); vtInteger: Result := EncodeInteger(Value1.VInteger or GetAsInteger(Value2)); else RaiseUnsupportedOperation; end; end; {** Performs '^' operation. @param Value1 the first variant argument. @param Value2 the second variant argument. @returns an operation result. } function TZDefaultVariantManager.OpPow(const Value1, Value2: TZVariant): TZVariant; begin case Value1.VType of vtNull: Result := EncodeNull; vtInteger: Result := EncodeFloat(Power(Value1.VInteger, GetAsInteger(Value2))); vtFloat: Result := EncodeFloat(Power(Value1.VFloat, GetAsFloat(Value2))); else RaiseUnsupportedOperation; end; end; {** Performs '-' operation. @param Value1 the first variant argument. @param Value2 the second variant argument. @returns an operation result. } function TZDefaultVariantManager.OpSub(const Value1, Value2: TZVariant): TZVariant; begin case Value1.VType of vtNull: Result := EncodeNull; vtInteger: Result := EncodeInteger(Value1.VInteger - GetAsInteger(Value2)); vtFloat: Result := EncodeFloat(Value1.VFloat - GetAsFloat(Value2)); else RaiseUnsupportedOperation; end; end; {** Performs '^' operation. @param Value1 the first variant argument. @param Value2 the second variant argument. @returns an operation result. } function TZDefaultVariantManager.OpXor(const Value1, Value2: TZVariant): TZVariant; var TempBool1, TempBool2: Boolean; TempInteger1, TempInteger2: Int64; begin case Value1.VType of vtNull: Result := EncodeNull; vtBoolean: begin TempBool1 := Value1.VBoolean; TempBool2 := GetAsBoolean(Value2); Result := EncodeBoolean((TempBool1 and not TempBool2) or (not TempBool1 and TempBool2)); end; vtInteger: begin TempInteger1 := Value1.VInteger; TempInteger2 := GetAsInteger(Value2); Result := EncodeInteger((TempInteger1 and not TempInteger2) or (not TempInteger1 and TempInteger2)); end; else RaiseUnsupportedOperation; end; end; { TZSoftVariantManager } {** Converts a specified variant value to a new type. @param Value a variant value to be converted. @param NewType a type of the result variant value. @returns a converted variant value. } function TZSoftVariantManager.Convert(const Value: TZVariant; NewType: TZVariantType): TZVariant; begin Result.VType := NewType; case NewType of vtBoolean: case Value.VType of vtNull: Result.VBoolean := False; vtBoolean: Result.VBoolean := Value.VBoolean; vtInteger: Result.VBoolean := Value.VInteger <> 0; vtFloat: Result.VBoolean := Value.VFloat <> 0; vtString: Result.VBoolean := StrToBoolEx(Value.VString); vtAnsiString: Result.VBoolean := StrToBoolEx({$IFDEF UNICODE}String{$ENDIF}(Value.VAnsiString)); vtUTF8String: Result.VBoolean := StrToBoolEx({$IFDEF UNICODE}String{$ENDIF}(Value.VUTF8String)); vtRawByteString: Result.VBoolean := StrToBoolEx({$IFDEF UNICODE}String{$ENDIF}(Value.VRawByteString)); vtUnicodeString: Result.VBoolean := StrToBoolEx({$IFNDEF UNICODE}String{$ENDIF}(Value.VUnicodeString)); vtDateTime: Result.VBoolean := Value.VDateTime <> 0; vtPointer: RaiseTypeMismatchError; vtInterface: RaiseTypeMismatchError; end; vtBytes: case Value.VType of vtNull: Result.VBytes := nil; vtBytes: Result.VBytes := Value.VBytes; vtString: Result.VBytes := StrToBytes(Value.VString); vtAnsiString: Result.VBytes := StrToBytes(Value.VAnsiString); vtRawByteString: Result.VBytes := StrToBytes(Value.VRawByteString); vtUTF8String: Result.VBytes := StrToBytes(Value.VUTF8String); vtUnicodeString: Result.VBytes := StrToBytes(Value.VUnicodeString); else RaiseTypeMismatchError; end; vtInteger: case Value.VType of vtNull: Result.VInteger := 0; vtBoolean: if Value.VBoolean then Result.VInteger := 1 else Result.VInteger := 0; vtInteger: Result.VInteger := Value.VInteger; vtFloat: Result.VInteger := Trunc(Value.VFloat); vtString: Result.VInteger := StrToInt64Def(Value.VString, 0); vtAnsiString: Result.VInteger := StrToInt64Def({$IFDEF UNICODE}String{$ENDIF}(Value.VAnsiString), 0); vtUTF8String: Result.VInteger := StrToInt64Def({$IFDEF UNICODE}String{$ENDIF}(Value.VUTF8String), 0); vtRawByteString: Result.VInteger := StrToInt64Def({$IFDEF UNICODE}String{$ENDIF}(Value.VRawByteString), 0); vtUnicodeString: Result.VInteger := StrToInt64Def({$IFNDEF UNICODE}String{$ENDIF}(Value.VUnicodeString), 0); vtDateTime: Result.VInteger := Trunc(Value.VDateTime); vtPointer: Result.VInteger := NativeInt(Value.VPointer); vtInterface: RaiseTypeMismatchError; end; vtFloat: case Value.VType of vtNull: Result.VFloat := 0; vtBoolean: if Value.VBoolean then Result.VFloat := 1 else Result.VFloat := 0; vtInteger: Result.VFloat := Value.VInteger; vtFloat: Result.VFloat := Value.VFloat; vtString: Result.VFloat := SqlStrToFloatDef(Value.VString, 0); vtAnsiString: Result.VFloat := SqlStrToFloatDef({$IFDEF UNICODE}String{$ENDIF}(Value.VAnsiString), 0); vtUTF8String: Result.VFloat := SqlStrToFloatDef({$IFDEF UNICODE}String{$ENDIF}(Value.VUTF8String), 0); vtRawByteString: Result.VFloat := SqlStrToFloatDef(Value.VRawByteString, 0); vtUnicodeString: Result.VFloat := SqlStrToFloatDef(AnsiString(Value.VUnicodeString), 0); vtDateTime: Result.VFloat := Value.VDateTime; else RaiseTypeMismatchError; end; vtString: case Value.VType of vtNull: Result.VString := ''; vtBoolean: if Value.VBoolean then Result.VString := 'TRUE' else Result.VString := 'FALSE'; vtBytes: ZSetString(PAnsiChar(Value.VBytes), Length(Value.VBytes), Result.VString); vtInteger: Result.VString := IntToStr(Value.VInteger); vtFloat: Result.VString := FloatToSqlStr(Value.VFloat); vtString: Result.VString := Value.VString; vtAnsiString: Result.VString := {$IFDEF UNICODE}String{$ENDIF}(Value.VAnsiString); vtUTF8String: Result.VString := ZUTF8ToString(Value.VUTF8String, FSystemCodePage); vtUnicodeString: Result.VString := Value.VUnicodeString; //hint: VarArrayOf(['Test']) returns allways varOleStr which is type WideString don't change that again vtDateTime: Result.VString := DateTimeToAnsiSQLDate(Value.VDateTime); // gto: Not a real threat, as it's converting dates (unicode safe) else RaiseTypeMismatchError; end; vtAnsiString: case Value.VType of vtNull: Result.VAnsiString := ''; vtBoolean: if Value.VBoolean then Result.VAnsiString := 'TRUE' else Result.VAnsiString := 'FALSE'; vtInteger: Result.VAnsiString := {$IFDEF UNICODE}AnsiString{$ENDIF}(IntToStr(Value.VInteger)); vtFloat: Result.VAnsiString := {$IFDEF UNICODE}AnsiString{$ENDIF}(FloatToSqlStr(Value.VFloat)); vtString: Result.VAnsiString := {$IFDEF UNICODE}AnsiString{$ENDIF}(Value.VString); vtAnsiString: Result.VAnsiString := Value.VAnsiString; vtUTF8String: Result.VAnsiString := ZUTF8ToAnsi(Value.VUTF8String); vtUnicodeString: Result.VAnsiString := AnsiString(Value.VUnicodeString); vtDateTime: Result.VAnsiString := {$IFDEF UNICODE}AnsiString{$ENDIF}(DateTimeToAnsiSQLDate(Value.VDateTime)); else RaiseTypeMismatchError; end; vtUTF8String: case Value.VType of vtNull: Result.VUTF8String := ''; vtBoolean: if Value.VBoolean then Result.VUTF8String := 'TRUE' else Result.VUTF8String := 'FALSE'; vtInteger: Result.VUTF8String := UTF8String(IntToStr(Value.VInteger)); vtFloat: Result.VUTF8String := UTF8String(FloatToSqlStr(Value.VFloat)); vtString: Result.VUTF8String := ZStringToUTF8(Value.VString, FSystemCodePage); vtAnsiString: Result.VUTF8String := ZAnsiToUTF8(Value.VAnsiString); vtUTF8String: Result.VUTF8String := Value.VUTF8String; vtUnicodeString: {$IFDEF WITH_RAWBYTESTRING} Result.VUTF8String := UTF8String(Value.VUnicodeString); {$ELSE} Result.VUTF8String := UTF8Encode(Value.VUnicodeString); {$ENDIF} vtDateTime: Result.VUTF8String := UTF8String(DateTimeToAnsiSQLDate(Value.VDateTime)); else RaiseTypeMismatchError; end; vtUnicodeString: case Value.VType of vtNull: Result.VUnicodeString := ''; vtBoolean: if Value.VBoolean then Result.VUnicodeString := 'TRUE' else Result.VUnicodeString := 'FALSE'; vtInteger: Result.VUnicodeString := {$IFNDEF UNICODE}ZWideString{$ENDIF}(IntToStr(Value.VInteger)); vtFloat: Result.VUnicodeString := {$IFNDEF UNICODE}ZWideString{$ENDIF}(FloatToSqlStr(Value.VFloat)); vtString: Result.VUnicodeString := {$IFNDEF UNICODE}ZWideString{$ENDIF}(Value.VString); vtAnsiString: Result.VUnicodeString := ZWideString(Value.VAnsiString); vtUTF8String: Result.VUnicodeString := {$IFDEF UNICODE}UTF8ToString{$ELSE}UTF8Decode{$ENDIF}(PAnsiChar(Value.VUTF8String)); vtUnicodeString: Result.VUnicodeString := Value.VUnicodeString; vtDateTime: Result.VUnicodeString := ZWideString(DateTimeToAnsiSQLDate(Value.VDateTime)); else RaiseTypeMismatchError; end; vtDateTime: case Value.VType of vtNull: Result.VDateTime := 0; vtBoolean: RaiseTypeMismatchError; vtInteger: Result.VDateTime := Value.VInteger; vtFloat: Result.VDateTime := Value.VFloat; vtString: Result.VDateTime := AnsiSQLDateToDateTime(Value.VString); vtAnsiString: Result.VDateTime := AnsiSQLDateToDateTime({$IFDEF UNICODE}String{$ENDIF}(Value.VAnsiString)); vtUTF8String: Result.VDateTime := AnsiSQLDateToDateTime({$IFDEF UNICODE}String{$ENDIF}(Value.VUTF8String)); vtRawByteString: Result.VDateTime := AnsiSQLDateToDateTime({$IFDEF UNICODE}String{$ENDIF}(Value.VRawByteString)); vtUnicodeString: Result.VDateTime := AnsiSQLDateToDateTime({$IFNDEF UNICODE}String{$ENDIF}(Value.VUnicodeString)); vtDateTime: Result.VDateTime := Value.VDateTime; else RaiseTypeMismatchError; end; vtPointer: case Value.VType of vtNull: Result.VPointer := nil; vtBoolean: RaiseTypeMismatchError; vtInteger: Result.VPointer := Pointer(Value.VInteger); else RaiseTypeMismatchError; end; vtInterface: case Value.VType of vtNull: Result.VInterface := nil; vtInterface: Result.VInterface := Value.VInterface; else end; end; end; { TZClientVariantManager } {** Constructs this object and assignes the main properties. @param ClientCodePage the current ClientCodePage. } constructor TZClientVariantManager.Create(const ConSettings: PZConSettings); begin inherited Create; //Set all standart converters functions FConSettings := ConSettings; end; {** Converts a specified variant value to a new type. @param Value a variant value to be converted. @param NewType a type of the result variant value. @returns a converted variant value. } function TZClientVariantManager.Convert(const Value: TZVariant; NewType: TZVariantType): TZVariant; begin Result.VType := NewType; case NewType of vtBoolean: case Value.VType of vtNull: Result.VBoolean := False; vtBoolean: Result.VBoolean := Value.VBoolean; vtInteger: Result.VBoolean := Value.VInteger <> 0; vtFloat: Result.VBoolean := Value.VFloat <> 0; vtString: Result.VBoolean := StrToBoolEx(Value.VString); vtAnsiString: Result.VBoolean := StrToBoolEx({$IFDEF UNICODE}String{$ENDIF}(Value.VAnsiString)); vtUTF8String: Result.VBoolean := StrToBoolEx({$IFDEF UNICODE}String{$ENDIF}(Value.VUTF8String)); vtRawByteString: Result.VBoolean := StrToBoolEx({$IFDEF UNICODE}String{$ENDIF}(Value.VRawByteString)); vtUnicodeString: Result.VBoolean := StrToBoolEx({$IFNDEF UNICODE}String{$ENDIF}(Value.VUnicodeString)); vtDateTime: Result.VBoolean := Value.VDateTime <> 0; else RaiseTypeMismatchError; end; vtBytes: case Value.VType of vtNull: Result.VBytes := nil; vtBytes: Result.VBytes := Value.VBytes; vtString: Result.VBytes := StrToBytes(Value.VString); vtAnsiString: Result.VBytes := StrToBytes(Value.VAnsiString); vtRawByteString: Result.VBytes := StrToBytes(Value.VRawByteString); vtUTF8String: Result.VBytes := StrToBytes(Value.VUTF8String); vtUnicodeString: Result.VBytes := StrToBytes(Value.VUnicodeString); else RaiseTypeMismatchError; end; vtInteger: case Value.VType of vtNull: Result.VInteger := 0; vtBoolean: if Value.VBoolean then Result.VInteger := 1 else Result.VInteger := 0; vtInteger: Result.VInteger := Value.VInteger; vtFloat: Result.VInteger := Trunc(Value.VFloat); vtString: Result.VInteger := StrToInt64Def(Value.VString, 0); vtAnsiString: Result.VInteger := StrToInt64Def({$IFDEF UNICODE}String{$ENDIF}(Value.VAnsiString), 0); vtUTF8String: Result.VInteger := StrToInt64Def({$IFDEF UNICODE}String{$ENDIF}(Value.VUTF8String), 0); vtRawByteString: Result.VInteger := StrToInt64Def({$IFDEF UNICODE}String{$ENDIF}(Value.VRawByteString), 0); vtUnicodeString: Result.VInteger := StrToInt64Def({$IFNDEF UNICODE}String{$ENDIF}(Value.VUnicodeString), 0); vtDateTime: Result.VInteger := Trunc(Value.VDateTime); vtPointer: Result.VInteger := NativeInt(Value.VPointer); vtInterface: RaiseTypeMismatchError; end; vtFloat: case Value.VType of vtNull: Result.VFloat := 0; vtBoolean: if Value.VBoolean then Result.VFloat := 1 else Result.VFloat := 0; vtInteger: Result.VFloat := Value.VInteger; vtFloat: Result.VFloat := Value.VFloat; vtString: Result.VFloat := SqlStrToFloatDef(Value.VString, 0); vtAnsiString: Result.VFloat := SqlStrToFloatDef({$IFDEF UNICODE}String{$ENDIF}(Value.VAnsiString), 0); vtUTF8String: Result.VFloat := SqlStrToFloatDef({$IFDEF UNICODE}String{$ENDIF}(Value.VUTF8String), 0); vtRawByteString: Result.VFloat := SqlStrToFloatDef(Value.VRawByteString, 0); vtUnicodeString: Result.VFloat := SqlStrToFloatDef({$IFNDEF UNICODE}String{$ENDIF}(Value.VUnicodeString), 0); vtDateTime: Result.VFloat := Value.VDateTime; else RaiseTypeMismatchError; end; vtString: case Value.VType of vtNull: Result.VString := ''; vtBoolean: if Value.VBoolean then Result.VString := 'TRUE' else Result.VString := 'FALSE'; vtBytes: Result.VString := {$IFDEF UNICODE}String{$ENDIF}(BytesToStr(Value.VBytes)); vtInteger: Result.VString := IntToStr(Value.VInteger); vtFloat: Result.VString := FloatToSqlStr(Value.VFloat); vtString: Result.VString := Value.VString; vtAnsiString: Result.VString := FConSettings^.ConvFuncs.ZAnsiToString(Value.VAnsiString, FConSettings^.CTRL_CP); vtUTF8String: Result.VString := FConSettings^.ConvFuncs.ZUTF8ToString(Value.VUTF8String, FConSettings^.CTRL_CP); vtRawByteString: Result.VString := FConSettings^.ConvFuncs.ZRawToString(Value.VRawByteString, FConSettings^.ClientCodePage^.CP, FConSettings^.CTRL_CP); vtUnicodeString: //hint: VarArrayOf(['Test']) returns allways varOleStr which is type WideString don't change that again //this hint means a cast instead of convert. The user should better use WideString constants! Result.VString := FConSettings^.ConvFuncs.ZUnicodeToString(Value.VUnicodeString, FConSettings^.CTRL_CP); vtDateTime: Result.VString := DateTimeToAnsiSQLDate(Value.VDateTime); else RaiseTypeMismatchError; end; vtAnsiString: case Value.VType of vtNull: Result.VAnsiString := ''; vtBoolean: if Value.VBoolean then Result.VAnsiString := 'TRUE' else Result.VAnsiString := 'FALSE'; vtInteger: Result.VAnsiString := {$IFDEF UNICODE}AnsiString{$ENDIF}(IntToStr(Value.VInteger)); vtFloat: Result.VAnsiString := {$IFDEF UNICODE}AnsiString{$ENDIF}(FloatToSqlStr(Value.VFloat)); vtString: Result.VAnsiString := FConSettings^.ConvFuncs.ZStringToAnsi(Value.VString, FConSettings^.CTRL_CP); vtAnsiString: Result.VAnsiString := Value.VAnsiString; vtUTF8String: Result.VAnsiString := FConSettings^.ConvFuncs.ZUTF8ToAnsi(Value.VUTF8String); vtRawByteString: Result.VAnsiString := FConSettings^.ConvFuncs.ZRawToAnsi(Value.VRawByteString, FConSettings^.ClientCodePage^.CP); vtUnicodeString: Result.VAnsiString := AnsiString(Value.VUnicodeString); vtDateTime: Result.VAnsiString := {$IFDEF UNICODE}AnsiString{$ENDIF}(DateTimeToAnsiSQLDate(Value.VDateTime)); else RaiseTypeMismatchError; end; vtUTF8String: case Value.VType of vtNull: Result.VUTF8String := ''; vtBoolean: if Value.VBoolean then Result.VUTF8String := 'TRUE' else Result.VUTF8String := 'FALSE'; vtInteger: Result.VUTF8String := {$IFDEF WITH_RAWBYTESTRING}UTF8String{$ENDIF}(IntToStr(Value.VInteger)); vtFloat: Result.VUTF8String := {$IFDEF WITH_RAWBYTESTRING}UTF8String{$ENDIF}(FloatToSqlStr(Value.VFloat)); vtString: Result.VUTF8String := FConSettings^.ConvFuncs.ZStringToUTF8(Value.VString, FConSettings^.CTRL_CP); vtAnsiString: Result.VUTF8String := FConSettings^.ConvFuncs.ZAnsiToUTF8(Value.VAnsiString); vtUTF8String: Result.VUTF8String := Value.VUTF8String; vtRawByteString: Result.VUTF8String := FConSettings^.ConvFuncs.ZRawToUTF8(Value.VRawByteString, FConSettings^.ClientCodePage^.CP); vtUnicodeString: {$IFDEF WITH_RAWBYTESTRING} Result.VUTF8String := UTF8String(Value.VUnicodeString); {$ELSE} Result.VUTF8String := UTF8Encode(Value.VUnicodeString); {$ENDIF} vtDateTime: Result.VUTF8String := {$IFDEF WITH_RAWBYTESTRING}UTF8String{$ENDIF}(DateTimeToAnsiSQLDate(Value.VDateTime)); else RaiseTypeMismatchError; end; vtRawByteString: case Value.VType of vtNull: Result.VRawByteString := ''; vtBoolean: if Value.VBoolean then Result.VRawByteString := 'TRUE' else Result.VRawByteString := 'FALSE'; vtInteger: Result.VRawByteString := {$IFDEF WITH_RAWBYTESTRING}RawByteString{$ENDIF}(IntToStr(Value.VInteger)); vtFloat: Result.VRawByteString := {$IFDEF WITH_RAWBYTESTRING}RawByteString{$ENDIF}(FloatToSqlStr(Value.VFloat)); vtString: Result.VRawByteString := FConSettings^.ConvFuncs.ZStringToRaw(Value.VString, FConSettings^.CTRL_CP, FConSettings^.ClientCodePage^.CP); vtAnsiString: Result.VRawByteString := FConSettings^.ConvFuncs.ZAnsiToRaw(Value.VAnsiString, FConSettings^.ClientCodePage^.CP); vtUTF8String: Result.VRawByteString := FConSettings^.ConvFuncs.ZUTF8ToRaw(Value.VUTF8String, FConSettings^.ClientCodePage^.CP); vtRawByteString: Result.VRawByteString := Value.VRawByteString; vtUnicodeString: Result.VRawByteString := FConSettings^.ConvFuncs.ZUnicodeToRaw(Value.VUnicodeString, FConSettings^.ClientCodePage^.CP); vtDateTime: Result.VRawByteString := {$IFDEF WITH_RAWBYTESTRING}RawByteString{$ENDIF}(DateTimeToAnsiSQLDate(Value.VDateTime)); else RaiseTypeMismatchError; end; vtUnicodeString: case Value.VType of vtNull: Result.VUnicodeString := ''; vtBoolean: if Value.VBoolean then Result.VUnicodeString := 'TRUE' else Result.VUnicodeString := 'FALSE'; vtInteger: Result.VUnicodeString := ZWideString(IntToStr(Value.VInteger)); vtFloat: Result.VUnicodeString := ZWideString(FloatToSqlStr(Value.VFloat)); vtString: Result.VUnicodeString := FConSettings^.ConvFuncs.ZStringToUnicode(Value.VString, FConSettings^.CTRL_CP); vtAnsiString: Result.VUnicodeString := ZWideString(Value.VAnsiString); vtUTF8String: Result.VUnicodeString := {$IFDEF UNICODE}UTF8ToString{$ELSE}UTF8Decode{$ENDIF}(PAnsiChar(Value.VUTF8String)); vtRawByteString: Result.VUnicodeString := FConSettings^.ConvFuncs.ZRawToUnicode(Value.VRawByteString, FConSettings^.ClientCodePage^.CP); vtUnicodeString: Result.VUnicodeString := Value.VUnicodeString; vtDateTime: Result.VUnicodeString := ZWideString(DateTimeToAnsiSQLDate(Value.VDateTime)); else RaiseTypeMismatchError; end; vtDateTime: case Value.VType of vtNull: Result.VDateTime := 0; vtInteger: Result.VDateTime := Value.VInteger; vtFloat: Result.VDateTime := Value.VFloat; vtString: Result.VDateTime := AnsiSQLDateToDateTime(Value.VString); vtAnsiString: Result.VDateTime := AnsiSQLDateToDateTime({$IFDEF UNICODE}String{$ENDIF}(Value.VAnsiString)); vtUTF8String: Result.VDateTime := AnsiSQLDateToDateTime({$IFDEF WITH_RAWBYTESTRING}String{$ENDIF}(Value.VUTF8String)); vtRawByteString: Result.VDateTime := AnsiSQLDateToDateTime({$IFDEF WITH_RAWBYTESTRING}String{$ENDIF}(Value.VRawByteString)); vtUnicodeString: Result.VDateTime := AnsiSQLDateToDateTime({$IFNDEF UNICODE}String{$ENDIF}(Value.VUnicodeString)); vtDateTime: Result.VDateTime := Value.VDateTime; else RaiseTypeMismatchError; end; vtPointer: case Value.VType of vtNull: Result.VPointer := nil; vtBoolean: RaiseTypeMismatchError; vtInteger: Result.VPointer := Pointer(Value.VInteger); else RaiseTypeMismatchError; end; vtInterface: case Value.VType of vtNull: Result.VInterface := nil; vtInterface: Result.VInterface := Value.VInterface; else RaiseTypeMismatchError; end; end; end; {$WARNINGS OFF} //suppress [Pascal Warning] ZVariant.pas(1926): W1035 Return value of function 'TZClientVariantManager.GetAsRawByteString' might be undefined function TZClientVariantManager.GetAsRawByteString(const Value: TZVariant; const RawCP: Word): RawByteString; var US: ZWideString; begin case Value.VType of vtNull: Result := ''; vtBoolean: if Value.VBoolean then Result := 'TRUE' else Result := 'FALSE'; vtBytes: ZSetString(PAnsiChar(Value.VBytes), Length(Value.VBytes), Result); vtInteger: Result := {$IFDEF WITH_RAWBYTESTRING}RawByteString{$ENDIF}(IntToStr(Value.VInteger)); vtFloat: Result := {$IFDEF WITH_RAWBYTESTRING}RawByteString{$ENDIF}(FloatToSqlStr(Value.VFloat)); vtString: Result := ZConvertStringToRawWithAutoEncode(Value.VString, FConSettings^.CTRL_CP, RawCP); vtAnsiString: if ZCompatibleCodePages(ZDefaultSystemCodePage, RawCP) then Result := ZMoveAnsiToRaw(Value.VAnsiString, RawCP) else Result := ZConvertAnsiToRaw(Value.VAnsiString, RawCP); vtUTF8String: if ZCompatibleCodePages(zCP_UTF8, RawCP) then Result := ZMoveUTF8ToRaw(Value.VUTF8String, RawCP) else Result := ZConvertUTF8ToRaw(Value.VUTF8String, RawCP); vtRawByteString: if ZCompatibleCodePages(FConSettings^.ClientCodePage^.CP, RawCP) then Result := Value.VRawByteString else begin US := ZRawToUnicode(Value.VRawByteString, FConSettings^.ClientCodePage^.CP); Result := ZUnicodeToRaw(US, RawCP); end; vtUnicodeString: Result := ZUnicodeToRaw(Value.VUnicodeString, RawCP); vtDateTime: Result := {$IFDEF WITH_RAWBYTESTRING}RawByteString{$ENDIF}(DateTimeToAnsiSQLDate(Value.VDateTime)); else RaiseTypeMismatchError; end; end; {$WARNINGS ON} { TZAnyValue } {** Constructs this object and assignes the main properties. @param Value an any value. } constructor TZAnyValue.Create(const Value: TZVariant); begin FValue := Value; end; {** Constructs this object and assignes the main properties. @param Value a boolean value. } constructor TZAnyValue.CreateWithBoolean(Value: Boolean); begin FValue := EncodeBoolean(Value); end; {** Constructs this object and assignes the main properties. @param Value a datetime value. } constructor TZAnyValue.CreateWithDateTime(Value: TDateTime); begin FValue := EncodeDateTime(Value); end; {** Constructs this object and assignes the main properties. @param Value a float value. } constructor TZAnyValue.CreateWithFloat(Value: Extended); begin FValue := EncodeFloat(Value); end; {** Constructs this object and assignes the main properties. @param Value a integer value. } constructor TZAnyValue.CreateWithInteger(Value: Int64); begin FValue := EncodeInteger(Value); end; {** Constructs this object and assignes the main properties. @param Value a string value. } constructor TZAnyValue.CreateWithString(const Value: String); begin FValue := EncodeString(Value); end; {** Constructs this object and assignes the main properties. @param Value a unicode string value. } {$IFDEF UNICODE} constructor TZAnyValue.CreateWithUnicodeString(const Value: String; unicodeType : Boolean = true); {$ELSE} constructor TZAnyValue.CreateWithUnicodeString(const Value: WideString); {$ENDIF} begin FValue := EncodeUnicodeString(Value); end; {** Clones an object instance. @return a clonned object instance. } function TZAnyValue.Clone: IZInterface; begin Result := TZAnyValue.Create(FValue); end; {** Compares this and another property. @return True is properties are equal. } function TZAnyValue.Equals(const Value: IZInterface): Boolean; var Temp: IZAnyValue; begin if Value <> nil then begin if Value.QueryInterface(IZAnyValue, Temp) = 0 then begin Result := SoftVarManager.Compare(FValue, Temp.GetValue) = 0; Temp := nil; end else Result := inherited Equals(Value); end else Result := False; end; {** Gets a stored any value. @return a stored any value. } function TZAnyValue.GetValue: TZVariant; begin Result := FValue; end; {** Converts this object into the string representation. @return a string representation for this object. } function TZAnyValue.ToString: string; begin Result := GetString; end; {** Checks is the stored value contains NULL. @returns True if NULL is stored. } function TZAnyValue.IsNull: Boolean; begin Result := SoftVarManager.IsNull(FValue); end; {** Gets a stored value converted to double. @return a stored value converted to double. } function TZAnyValue.GetFloat: Extended; begin Result := SoftVarManager.GetAsFloat(FValue); end; {** Gets a stored value converted to integer. @return a stored value converted to integer. } function TZAnyValue.GetInteger: Int64; begin Result := SoftVarManager.GetAsInteger(FValue); end; {** Gets a stored value converted to String. @return a stored value converted to string. } function TZAnyValue.GetString: String; begin Result := SoftVarManager.GetAsString(FValue); end; {** Gets a stored value converted to AnsiString. @return a stored value converted to string. } function TZAnyValue.GetAnsiString: AnsiString; begin Result := SoftVarManager.GetAsAnsiString(FValue); end; {** Gets a stored value converted to AnsiString. @return a stored value converted to string. } function TZAnyValue.GetUTF8String: UTF8String; begin Result := SoftVarManager.GetAsUTF8String(FValue); end; {** Gets a stored value converted to boolean. @return a stored value converted to boolean. } function TZAnyValue.GetBoolean: Boolean; begin Result := SoftVarManager.GetAsBoolean(FValue); end; {** Gets a stored value converted to byte array. @return a stored value converted to a byte array. } function TZAnyValue.GetBytes: TByteDynArray; begin Result := SoftVarManager.GetAsBytes(FValue); end; {** Gets a stored value converted to unicode string. @return a stored value converted to unicode string. } function TZAnyValue.GetUnicodeString: ZWideString; begin Result := SoftVarManager.GetAsUnicodeString(FValue); end; {** Gets a stored value converted to datetime. @return a stored value converted to datetime. } function TZAnyValue.GetDateTime: TDateTime; begin Result := SoftVarManager.GetAsDateTime(FValue); end; {** Encodes a custom variant value into standard variant. @param Value a custom variant value to be encoded. @returns an encoded standard variant. } function EncodeVariant(const Value: TZVariant): Variant; begin case Value.VType of vtBoolean: Result := Value.VBoolean; vtBytes: Result := BytesToVar(Value.VBytes); vtInteger: if (Value.VInteger > -MaxInt) and (Value.VInteger < MaxInt) then Result := Integer(Value.VInteger) else {$ifdef fpc} Result := Value.VInteger; {$else} Result := IntToStr(Value.VInteger); {$endif} vtFloat: Result := Value.VFloat; vtString: Result := Value.VString; vtAnsiString: Result := Value.VAnsiString; vtUTF8String: Result := Value.VUTF8String; vtRawByteString: Result := Value.VRawByteString; vtUnicodeString: Result := Value.VUnicodeString; vtDateTime: Result := Value.VDateTime; vtPointer: {$ifdef fpc} Result := NativeInt(Value.VPointer); {$else} Result := NativeUInt(Value.VPointer); {$endif} vtInterface: Result := Value.VInterface; else Result := Null; end; end; {** Encodes an array of custom variant values into array of standard variants. @param Value an array of custom variant values to be encoded. @returns an encoded array of standard variants. } function EncodeVariantArray(const Value: TZVariantDynArray): Variant; var I, L: Integer; begin L := Length(Value); Result := VarArrayCreate([0, L - 1], varVariant); for I := 0 to L - 1 do Result[I] := EncodeVariant(Value[I]); end; {** Decodes a standard variant value into custom variant. @param Value a standard variant value to be decoded. @returns an decoded custom variant. } function DecodeVariant(const Value: Variant): TZVariant; begin case VarType(Value) of varSmallint, varInteger, varByte: Result := EncodeInteger(Integer(Value)); varBoolean: Result := EncodeBoolean(Value); varString: Result := EncodeString(Value); {$IFDEF UNICODE} varUString: Result := EncodeUnicodeString(Value); {$ENDIF} varSingle, varDouble, varCurrency: Result := EncodeFloat(Value); varUnknown: Result := EncodeInterface(Value); varOleStr: Result := EncodeUnicodeString(Value); varDate: Result := EncodeDateTime(Value); varShortInt, varWord, varLongWord: Result := EncodeInteger(Value); varInt64{$IFDEF BDS5_UP},varUInt64{$ENDIF}: Result := EncodeInteger(Value); else Result := EncodeNull; end; end; {** Decodes an array of standard variant values into array of custom variants. @param Value an array of standard variant values to be decoded. @returns an decoded array of custom variants. } function DecodeVariantArray(const Value: Variant): TZVariantDynArray; var I, L, H: Integer; begin if VarIsArray(Value) then begin L := VarArrayLowBound(Value, 1); H := VarArrayHighBound(Value, 1); SetLength(Result, H - L + 1); for I := L to H do Result[I - L] := DecodeVariant(Value[I]); end else begin SetLength(Result, 1); Result[0] := DecodeVariant(Value); end; end; {** Creates a null variant. } function EncodeNull: TZVariant; begin Result.VType := vtNull; end; {** Creates a boolean variant. @param Value a value to be assigned. } function EncodeBoolean(const Value: Boolean): TZVariant; begin Result.VType := vtBoolean; Result.VBoolean := Value; end; {** Creates a bytes array variant. @param Value a value to be assigned. } function EncodeBytes(const Value: TByteDynArray): TZVariant; begin Result.VType := vtBytes; Result.VBytes := Value; end; {** Creates a integer variant. @param Value a value to be assigned. } function EncodeInteger(const Value: Int64): TZVariant; begin Result.VType := vtInteger; Result.VInteger := Value; end; {** Creates a float variant. @param Value a value to be assigned. } function EncodeFloat(const Value: Extended): TZVariant; begin Result.VType := vtFloat; Result.VFloat := Value; end; {** Creates a AnsiString variant. @param Value a value to be assigned. } function EncodeString(const Value: String): TZVariant; begin Result.VType := vtString; Result.VString := Value; end; {** Creates a AnsiString variant. @param Value a value to be assigned. } function EncodeAnsiString(const Value: AnsiString): TZVariant; begin Result.VType := vtAnsiString; Result.VAnsiString := Value; end; {** Creates a UTF8String variant. @param Value a value to be assigned. } function EncodeUTF8String(const Value: UTF8String): TZVariant; begin Result.VType := vtUTF8String; Result.VUTF8String := Value; end; {** Creates a UTF8String variant. @param Value a value to be assigned. } function EncodeRawByteString(const Value: RawByteString): TZVariant; begin Result.VType := vtRawByteString; Result.VRawByteString := Value; end; {** Creates a UnicodeString variant. @param Value a value to be assigned. } function EncodeUnicodeString(const Value: ZWideString): TZVariant; begin Result.VType := vtUnicodeString; Result.VUnicodeString := Value; end; {** Creates a TDateTime variant. @param Value a value to be assigned. } function EncodeDateTime(const Value: TDateTime): TZVariant; begin Result.VType := vtDateTime; Result.VDateTime := Value; end; {** Creates a pointer variant. @param Value a value to be assigned. } function EncodePointer(const Value: Pointer): TZVariant; begin Result.VType := vtPointer; Result.VPointer := Value; end; {** Creates an Interface variant. @param Value a value to be assigned. } function EncodeInterface(const Value: IZInterface): TZVariant; begin Result.VType := vtInterface; Result.VInterface := Value; end; initialization DefVarManager := TZDefaultVariantManager.Create; SoftVarManager := TZSoftVariantManager.Create; NullVariant := EncodeNull; finalization DefVarManager := nil; SoftVarManager := nil; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbc.inc ================================================ {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} {$IFDEF LINUX} {$DEFINE UNIX} {$ENDIF} {$IFNDEF UNIX} {$I ..\Zeos.inc} {$ELSE} {$I ../Zeos.inc} {$ENDIF} ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcASA.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Interbase Database Connectivity Classes } { } { Originally written by Sergey Merkuriev } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcASA; interface {$I ZDbc.inc} uses ZCompatibility, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} Contnrs, SysUtils, ZDbcIntfs, ZDbcConnection, ZPlainASADriver, ZTokenizer, ZDbcGenericResolver, ZURL, ZPlainDriver, ZGenericSqlAnalyser, ZPlainASAConstants; type {** Implements a ASA Database Driver. } {$WARNINGS OFF} TZASADriver = class(TZAbstractDriver) public constructor Create; override; function Connect(const Url: TZURL): IZConnection; override; function GetMajorVersion: Integer; override; function GetMinorVersion: Integer; override; function GetTokenizer: IZTokenizer; override; function GetStatementAnalyser: IZStatementAnalyser; override; end; {$WARNINGS ON} {** Represents a ASA specific connection interface. } IZASAConnection = interface (IZConnection) ['{FAAAFCE0-F550-4098-96C6-580145813EBF}'] function GetDBHandle: PZASASQLCA; function GetPlainDriver: IZASAPlainDriver; // procedure CreateNewDatabase(SQL: String); end; {** Implements ASA Database Connection. } TZASAConnection = class(TZAbstractConnection, IZASAConnection) private FSQLCA: TZASASQLCA; FHandle: PZASASQLCA; private procedure StartTransaction; virtual; function DetermineASACharSet: String; protected procedure InternalCreate; override; public destructor Destroy; override; function GetDBHandle: PZASASQLCA; function GetPlainDriver: IZASAPlainDriver; // procedure CreateNewDatabase(SQL: String); function CreateRegularStatement(Info: TStrings): IZStatement; override; function CreatePreparedStatement(const SQL: string; Info: TStrings): IZPreparedStatement; override; function CreateCallableStatement(const SQL: string; Info: TStrings): IZCallableStatement; override; procedure Commit; override; procedure Rollback; override; procedure SetOption(Temporary: Integer; User: PAnsiChar; const Option: string; const Value: string); procedure Open; override; procedure Close; override; end; {** Implements a specialized cached resolver for ASA. } TZASACachedResolver = class(TZGenericCachedResolver) public function FormCalculateStatement(Columns: TObjectList): string; override; end; var {** The common driver manager object. } ASADriver: IZDriver; implementation uses ZDbcASAMetadata, ZDbcASAStatement, ZDbcASAUtils, ZSybaseToken, ZSybaseAnalyser, ZDbcLogging{$IFDEF WITH_UNITANSISTRINGS}, AnsiStrings{$ENDIF}; { TZASADriver } {** Attempts to make a database connection to the given URL. The driver should return "null" if it realizes it is the wrong kind of driver to connect to the given URL. This will be common, as when the JDBC driver manager is asked to connect to a given URL it passes the URL to each loaded driver in turn.

The driver should raise a SQLException if it is the right driver to connect to the given URL, but has trouble connecting to the database.

The java.util.Properties argument can be used to passed arbitrary string tag/value pairs as connection arguments. Normally at least "user" and "password" properties should be included in the Properties. @param url the URL of the database to which to connect @param info a list of arbitrary string tag/value pairs as connection arguments. Normally at least a "user" and "password" property should be included. @return a Connection object that represents a connection to the URL } {$WARNINGS OFF} function TZASADriver.Connect(const Url: TZURL): IZConnection; begin Result := TZASAConnection.Create(Url); end; {$WARNINGS ON} {** Constructs this object with default properties. } constructor TZASADriver.Create; begin inherited Create; AddSupportedProtocol(AddPlainDriverToCache(TZASA7PlainDriver.Create)); AddSupportedProtocol(AddPlainDriverToCache(TZASA8PlainDriver.Create)); AddSupportedProtocol(AddPlainDriverToCache(TZASA9PlainDriver.Create)); AddSupportedProtocol(AddPlainDriverToCache(TZASA12PlainDriver.Create)); end; {** Gets the driver's major version number. Initially this should be 1. @return this driver's major version number } function TZASADriver.GetMajorVersion: Integer; begin Result := 1; end; {** Gets the driver's minor version number. Initially this should be 0. @return this driver's minor version number } function TZASADriver.GetMinorVersion: Integer; begin Result := 0; end; {** Gets a SQL syntax tokenizer. @returns a SQL syntax tokenizer object. } function TZASADriver.GetTokenizer: IZTokenizer; begin if Tokenizer = nil then Tokenizer := TZSybaseTokenizer.Create; Result := Tokenizer; end; {** Creates a statement analyser object. @returns a statement analyser object. } function TZASADriver.GetStatementAnalyser: IZStatementAnalyser; begin if Analyser = nil then Analyser := TZSybaseStatementAnalyser.Create; Result := Analyser; end; { TZASAConnection } {** Releases a Connection's database and JDBC resources immediately instead of waiting for them to be automatically released.

Note: A Connection is automatically closed when it is garbage collected. Certain fatal errors also result in a closed Connection. } procedure TZASAConnection.Close; begin if Closed or (not Assigned(PlainDriver))then Exit; if AutoCommit then Commit else Rollback; GetPlainDriver.db_string_disconnect( FHandle, nil); CheckASAError( GetPlainDriver, FHandle, lcDisconnect); FHandle := nil; if GetPlainDriver.db_fini( @FSQLCA) = 0 then begin DriverManager.LogError( lcConnect, PlainDriver.GetProtocol, 'Inititalizing SQLCA', 0, 'Error closing SQLCA'); raise EZSQLException.CreateWithCode( 0, 'Error closing SQLCA'); end; DriverManager.LogMessage(lcDisconnect, PlainDriver.GetProtocol, Format('DISCONNECT FROM "%s"', [Database])); inherited Close; end; {** Commit current transaction } procedure TZASAConnection.Commit; begin if Closed or AutoCommit then Exit; if FHandle <> nil then begin GetPlainDriver.db_commit( FHandle, 0); CheckASAError( GetPlainDriver, FHandle, lcTransaction); DriverManager.LogMessage(lcTransaction, PlainDriver.GetProtocol, 'TRANSACTION COMMIT'); end; end; {** Constructs this object and assignes the main properties. } procedure TZASAConnection.InternalCreate; begin Self.FMetadata := TZASADatabaseMetadata.Create(Self, URL); end; {** Creates a CallableStatement object for calling database stored procedures. The CallableStatement object provides methods for setting up its IN and OUT parameters, and methods for executing the call to a stored procedure.

Note: This method is optimized for handling stored procedure call statements. Some drivers may send the call statement to the database when the method prepareCall is done; others may wait until the CallableStatement object is executed. This has no direct effect on users; however, it does affect which method throws certain SQLExceptions. Result sets created using the returned CallableStatement will have forward-only type and read-only concurrency, by default. @param sql a SQL statement that may contain one or more '?' parameter placeholders. Typically this statement is a JDBC function call escape string. @param Info a statement parameters. @return a new CallableStatement object containing the pre-compiled SQL statement } function TZASAConnection.CreateCallableStatement(const SQL: string; Info: TStrings): IZCallableStatement; begin if IsClosed then Open; Result := TZASACallableStatement.Create(Self, SQL, Info); end; {** Creates a PreparedStatement object for sending parameterized SQL statements to the database. A SQL statement with or without IN parameters can be pre-compiled and stored in a PreparedStatement object. This object can then be used to efficiently execute this statement multiple times.

Note: This method is optimized for handling parametric SQL statements that benefit from precompilation. If the driver supports precompilation, the method prepareStatement will send the statement to the database for precompilation. Some drivers may not support precompilation. In this case, the statement may not be sent to the database until the PreparedStatement is executed. This has no direct effect on users; however, it does affect which method throws certain SQLExceptions. Result sets created using the returned PreparedStatement will have forward-only type and read-only concurrency, by default. @param sql a SQL statement that may contain one or more '?' IN parameter placeholders @return a new PreparedStatement object containing the pre-compiled statement } function TZASAConnection.CreatePreparedStatement(const SQL: string; Info: TStrings): IZPreparedStatement; begin if IsClosed then Open; Result := TZASAPreparedStatement.Create(Self, SQL, Info); end; {** Creates a Statement object for sending SQL statements to the database. SQL statements without parameters are normally executed using Statement objects. If the same SQL statement is executed many times, it is more efficient to use a PreparedStatement object.

Result sets created using the returned Statement object will by default have forward-only type and read-only concurrency. @param Info a statement parameters. @return a new Statement object } function TZASAConnection.CreateRegularStatement( Info: TStrings): IZStatement; begin if IsClosed then Open; Result := TZASAStatement.Create(Self, Info); end; {** Destroys this object and cleanups the memory. } destructor TZASAConnection.Destroy; begin if not Closed then Close; inherited; end; {** Get database connection handle. @return database handle } function TZASAConnection.GetDBHandle: PZASASQLCA; begin Result := FHandle; end; {** Return native interbase plain driver @return plain driver } function TZASAConnection.GetPlainDriver: IZASAPlainDriver; begin Result := PlainDriver as IZASAPlainDriver; end; {** Opens a connection to database server with specified parameters. } procedure TZASAConnection.Open; var ConnectionString, Links: string; begin if not Closed then Exit; FHandle := nil; ConnectionString := ''; try if GetPlainDriver.db_init( @FSQLCA) = 0 then begin DriverManager.LogError( lcConnect, PlainDriver.GetProtocol, 'Inititalizing SQLCA', 0, 'Error initializing SQLCA'); raise EZSQLException.CreateWithCode( 0, 'Error initializing SQLCA'); end; FHandle := @FSQLCA; if HostName <> '' then ConnectionString := ConnectionString + 'ENG="' + HostName + '"; '; if User <> '' then ConnectionString := ConnectionString + 'UID="' + User + '"; '; if Password <> '' then ConnectionString := ConnectionString + 'PWD="' + Password + '"; '; if Database <> '' then begin if CompareText( ExtractFileExt( Database), '.db') = 0 then ConnectionString := ConnectionString + 'DBF="' + Database + '"; ' else ConnectionString := ConnectionString + 'DBN="' + Database + '"; '; end; Links := ''; if Info.Values['CommLinks'] <> '' then Links := 'CommLinks=' + Info.Values['CommLinks']; if Info.Values['LINKS'] <> '' then Links := 'LINKS=' + Info.Values['LINKS']; if (Links = '') and (Port <> 0) then Links := 'LINKS=tcpip(PORT=' + IntToStr(Port) + ')'; if Links <> '' then ConnectionString := ConnectionString + Links + '; '; GetPlainDriver.db_string_connect(FHandle, PAnsiChar(AnsiString(ConnectionString))); CheckASAError( GetPlainDriver, FHandle, lcConnect); DriverManager.LogMessage(lcConnect, PlainDriver.GetProtocol, Format('CONNECT TO "%s" AS USER "%s"', [Database, User])); if ( FClientCodePage <> '' ) then if ( GetPlainDriver.db_change_char_charset(FHandle, PAnsiChar(AnsiString(FClientCodePage))) = 0 ) or ( GetPlainDriver.db_change_nchar_charset(FHandle, PAnsiChar(AnsiString(FClientCodePage))) = 0 ) then CheckASAError( GetPlainDriver, FHandle, lcOther, 'Set client CharacterSet failed.'); StartTransaction; //SetConnOptions RowCount; except on E: Exception do begin if Assigned( FHandle) then GetPlainDriver.db_fini( FHandle); FHandle := nil; raise; end; end; inherited Open; if FClientCodePage = '' then CheckCharEncoding(DetermineASACharSet); end; {** Drops all changes made since the previous commit/rollback and releases any database locks currently held by this Connection. This method should be used only when auto- commit has been disabled. @see #setAutoCommit } procedure TZASAConnection.Rollback; begin if Closed or AutoCommit then Exit; if Assigned( FHandle) then begin GetPlainDriver.db_rollback( FHandle, 0); CheckASAError( GetPlainDriver, FHandle, lcTransaction); DriverManager.LogMessage(lcTransaction, PlainDriver.GetProtocol, 'TRANSACTION ROLLBACK'); end; end; procedure TZASAConnection.SetOption(Temporary: Integer; User: PAnsiChar; const Option: string; const Value: string); var SQLDA: PASASQLDA; Sz: Integer; S: string; begin if Assigned( FHandle) then begin Sz := SizeOf( TASASQLDA) - 32767 * SizeOf( TZASASQLVAR); SQLDA := AllocMem( Sz); try {$IFDEF WITH_STRPLCOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrPLCopy( SQLDA.sqldaid, 'SQLDA ', 8); SQLDA.sqldabc := Sz; SQLDA.sqln := 1; SQLDA.sqld := 1; SQLDA.sqlVar[0].sqlType := DT_STRING; SQLDA.sqlVar[0].sqlLen := Length( Value)+1; SQLDA.sqlVar[0].sqlData := PAnsiChar(AnsiString(Value)); GetPlainDriver.db_setoption(FHandle, Temporary, User, PAnsiChar(AnsiString(Option)), SQLDA); CheckASAError( GetPlainDriver, FHandle, lcOther); S := String(User); DriverManager.LogMessage( lcOther, PlainDriver.GetProtocol, Format( 'SET OPTION %s.%s = %s', [ S, Option, Value])); finally FreeMem( SQLDA); end; end; end; {** Start transaction } procedure TZASAConnection.StartTransaction; var ASATL: integer; begin if AutoCommit then SetOption( 1, nil, 'CHAINED', 'OFF') else SetOption( 1, nil, 'CHAINED', 'ON'); ASATL := Ord( TransactIsolationLevel); if ASATL > 1 then ASATL := ASATL - 1; SetOption( 1, nil, 'ISOLATION_LEVEL', IntToStr( ASATL)); end; function TZASAConnection.DetermineASACharSet: String; var Stmt: IZStatement; RS: IZResultSet; begin Stmt := Self.CreateRegularStatement(Info); RS := Stmt.ExecuteQuery('SELECT DB_PROPERTY( ''CharSet'')'); if RS.Next then Result := RS.GetString(1) else Result := ''; RS := nil; Stmt.Close; Stmt := nil; end; { TZASACachedResolver } {** Forms a where clause for SELECT statements to calculate default values. @param Columns a collection of key columns. @param OldRowAccessor an accessor object to old column values. } function TZASACachedResolver.FormCalculateStatement( Columns: TObjectList): string; var I: Integer; Current: TZResolverParameter; begin Result := ''; if Columns.Count = 0 then Exit; for I := 0 to Columns.Count - 1 do begin Current := TZResolverParameter(Columns[I]); if Result <> '' then Result := Result + ','; if Current.DefaultValue <> '' then Result := Result + Current.DefaultValue else Result := Result + 'NULL'; end; Result := 'SELECT ' + Result; end; initialization ASADriver := TZASADriver.Create; DriverManager.RegisterDriver(ASADriver); finalization if Assigned(DriverManager) then DriverManager.DeregisterDriver(ASADriver); ASADriver := nil; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcASAMetadata.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Interbase Database Connectivity Classes } { } { Originally written by Sergey Merkuriev } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcASAMetadata; interface {$I ZDbc.inc} uses Types, Classes, SysUtils, ZDbcIntfs, ZDbcMetadata, ZCompatibility, ZDbcConnection, ZDbcASA, ZURL; type // technobot 2008-06-28 - methods moved as is from TZASADatabaseMetadata: {** Implements ASA Database Information. } TZASADatabaseInfo = class(TZAbstractDatabaseInfo) public constructor Create(const Metadata: TZAbstractDatabaseMetadata); destructor Destroy; override; // database/driver/server info: function GetDatabaseProductName: string; override; function GetDatabaseProductVersion: string; override; function GetDriverName: string; override; // function GetDriverVersion: string; override; -> Same as parent function GetDriverMajorVersion: Integer; override; function GetDriverMinorVersion: Integer; override; // function GetServerVersion: string; -> Not implemented // capabilities (what it can/cannot do): // function AllProceduresAreCallable: Boolean; override; -> Not implemented // function AllTablesAreSelectable: Boolean; override; -> Not implemented function SupportsMixedCaseIdentifiers: Boolean; override; function SupportsMixedCaseQuotedIdentifiers: Boolean; override; // function SupportsAlterTableWithAddColumn: Boolean; override; -> Not implemented // function SupportsAlterTableWithDropColumn: Boolean; override; -> Not implemented // function SupportsColumnAliasing: Boolean; override; -> Not implemented // function SupportsConvert: Boolean; override; -> Not implemented // function SupportsConvertForTypes(FromType: TZSQLType; ToType: TZSQLType): // Boolean; override; -> Not implemented // function SupportsTableCorrelationNames: Boolean; override; -> Not implemented // function SupportsDifferentTableCorrelationNames: Boolean; override; -> Not implemented function SupportsExpressionsInOrderBy: Boolean; override; function SupportsOrderByUnrelated: Boolean; override; function SupportsGroupBy: Boolean; override; function SupportsGroupByUnrelated: Boolean; override; function SupportsGroupByBeyondSelect: Boolean; override; // function SupportsLikeEscapeClause: Boolean; override; -> Not implemented // function SupportsMultipleResultSets: Boolean; override; -> Not implemented // function SupportsMultipleTransactions: Boolean; override; -> Not implemented // function SupportsNonNullableColumns: Boolean; override; -> Not implemented // function SupportsMinimumSQLGrammar: Boolean; override; -> Not implemented // function SupportsCoreSQLGrammar: Boolean; override; -> Not implemented // function SupportsExtendedSQLGrammar: Boolean; override; -> Not implemented // function SupportsANSI92EntryLevelSQL: Boolean; override; -> Not implemented // function SupportsANSI92IntermediateSQL: Boolean; override; -> Not implemented // function SupportsANSI92FullSQL: Boolean; override; -> Not implemented function SupportsIntegrityEnhancementFacility: Boolean; override; // function SupportsOuterJoins: Boolean; override; -> Not implemented // function SupportsFullOuterJoins: Boolean; override; -> Not implemented // function SupportsLimitedOuterJoins: Boolean; override; -> Not implemented function SupportsSchemasInDataManipulation: Boolean; override; function SupportsSchemasInProcedureCalls: Boolean; override; function SupportsSchemasInTableDefinitions: Boolean; override; function SupportsSchemasInIndexDefinitions: Boolean; override; function SupportsSchemasInPrivilegeDefinitions: Boolean; override; function SupportsCatalogsInDataManipulation: Boolean; override; function SupportsCatalogsInProcedureCalls: Boolean; override; function SupportsCatalogsInTableDefinitions: Boolean; override; function SupportsCatalogsInIndexDefinitions: Boolean; override; function SupportsCatalogsInPrivilegeDefinitions: Boolean; override; function SupportsPositionedDelete: Boolean; override; function SupportsPositionedUpdate: Boolean; override; function SupportsSelectForUpdate: Boolean; override; function SupportsStoredProcedures: Boolean; override; function SupportsSubqueriesInComparisons: Boolean; override; function SupportsSubqueriesInExists: Boolean; override; function SupportsSubqueriesInIns: Boolean; override; function SupportsSubqueriesInQuantifieds: Boolean; override; function SupportsCorrelatedSubqueries: Boolean; override; function SupportsUnion: Boolean; override; function SupportsUnionAll: Boolean; override; function SupportsOpenCursorsAcrossCommit: Boolean; override; function SupportsOpenCursorsAcrossRollback: Boolean; override; function SupportsOpenStatementsAcrossCommit: Boolean; override; function SupportsOpenStatementsAcrossRollback: Boolean; override; function SupportsTransactions: Boolean; override; function SupportsTransactionIsolationLevel(Level: TZTransactIsolationLevel): Boolean; override; function SupportsDataDefinitionAndDataManipulationTransactions: Boolean; override; function SupportsDataManipulationTransactionsOnly: Boolean; override; function SupportsResultSetType(_Type: TZResultSetType): Boolean; override; function SupportsResultSetConcurrency(_Type: TZResultSetType; Concurrency: TZResultSetConcurrency): Boolean; override; // function SupportsBatchUpdates: Boolean; override; -> Not implemented // maxima: function GetMaxBinaryLiteralLength: Integer; override; function GetMaxCharLiteralLength: Integer; override; function GetMaxColumnNameLength: Integer; override; function GetMaxColumnsInGroupBy: Integer; override; function GetMaxColumnsInIndex: Integer; override; function GetMaxColumnsInOrderBy: Integer; override; function GetMaxColumnsInSelect: Integer; override; function GetMaxColumnsInTable: Integer; override; function GetMaxConnections: Integer; override; function GetMaxCursorNameLength: Integer; override; function GetMaxIndexLength: Integer; override; function GetMaxSchemaNameLength: Integer; override; function GetMaxProcedureNameLength: Integer; override; function GetMaxCatalogNameLength: Integer; override; function GetMaxRowSize: Integer; override; function GetMaxStatementLength: Integer; override; function GetMaxStatements: Integer; override; function GetMaxTableNameLength: Integer; override; function GetMaxTablesInSelect: Integer; override; function GetMaxUserNameLength: Integer; override; // policies (how are various data and operations handled): // function IsReadOnly: Boolean; override; -> Not implemented // function IsCatalogAtStart: Boolean; override; -> Not implemented function DoesMaxRowSizeIncludeBlobs: Boolean; override; // function NullsAreSortedHigh: Boolean; override; -> Not implemented // function NullsAreSortedLow: Boolean; override; -> Not implemented function NullsAreSortedAtStart: Boolean; override; // function NullsAreSortedAtEnd: Boolean; override; -> Not implemented // function NullPlusNonNullIsNull: Boolean; override; -> Not implemented function UsesLocalFiles: Boolean; override; function UsesLocalFilePerTable: Boolean; override; function StoresUpperCaseIdentifiers: Boolean; override; function StoresLowerCaseIdentifiers: Boolean; override; function StoresMixedCaseIdentifiers: Boolean; override; function StoresUpperCaseQuotedIdentifiers: Boolean; override; function StoresLowerCaseQuotedIdentifiers: Boolean; override; function StoresMixedCaseQuotedIdentifiers: Boolean; override; function GetDefaultTransactionIsolation: TZTransactIsolationLevel; override; function DataDefinitionCausesTransactionCommit: Boolean; override; function DataDefinitionIgnoredInTransactions: Boolean; override; // interface details (terms, keywords, etc): // function GetIdentifierQuoteString: string; override; -> Not implemented function GetSchemaTerm: string; override; function GetProcedureTerm: string; override; function GetCatalogTerm: string; override; function GetCatalogSeparator: string; override; function GetSQLKeywords: string; override; function GetNumericFunctions: string; override; function GetStringFunctions: string; override; function GetSystemFunctions: string; override; function GetTimeDateFunctions: string; override; function GetSearchStringEscape: string; override; function GetExtraNameCharacters: string; override; end; {** Implements ASA Database Metadata. } TZASADatabaseMetadata = class(TZAbstractDatabaseMetadata) private FASAConnection: TZASAConnection; function ComposeObjectString(const S: String; Const NullText: String = 'null'; QuoteChar: Char = #39): String; protected function CreateDatabaseInfo: IZDatabaseInfo; override; // technobot 2008-06-28 function UncachedGetTables(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const Types: TStringDynArray): IZResultSet; override; function UncachedGetSchemas: IZResultSet; override; // function UncachedGetCatalogs: IZResultSet; override; -> Not implemented function UncachedGetTableTypes: IZResultSet; override; function UncachedGetColumns(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const ColumnNamePattern: string): IZResultSet; override; function UncachedGetTablePrivileges(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string): IZResultSet; override; function UncachedGetColumnPrivileges(const Catalog: string; const Schema: string; const Table: string; const ColumnNamePattern: string): IZResultSet; override; function UncachedGetPrimaryKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; override; function UncachedGetImportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; override; function UncachedGetExportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; override; function UncachedGetCrossReference(const PrimaryCatalog: string; const PrimarySchema: string; const PrimaryTable: string; const ForeignCatalog: string; const ForeignSchema: string; const ForeignTable: string): IZResultSet; override; function UncachedGetIndexInfo(const Catalog: string; const Schema: string; const Table: string; Unique: Boolean; Approximate: Boolean): IZResultSet; override; // function UncachedGetSequences(const Catalog: string; const SchemaPattern: string; // const SequenceNamePattern: string): IZResultSet; virtual; -> Not implemented function UncachedGetProcedures(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string): IZResultSet; override; function UncachedGetProcedureColumns(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string; const ColumnNamePattern: string): IZResultSet; override; function UncachedGetVersionColumns(const Catalog: string; const Schema: string; const Table: string): IZResultSet; override; function UncachedGetTypeInfo: IZResultSet; override; function UncachedGetUDTs(const Catalog: string; const SchemaPattern: string; const TypeNamePattern: string; const Types: TIntegerDynArray): IZResultSet; override; public constructor Create(Connection: TZAbstractConnection; const Url: TZURL); override; end; implementation uses ZDbcASAUtils, ZDbcUtils; { TZASADatabaseInfo } {** Constructs this object. @param Metadata the interface of the correpsonding database metadata object } constructor TZASADatabaseInfo.Create(const Metadata: TZAbstractDatabaseMetadata); begin inherited; end; {** Destroys this object and cleanups the memory. } destructor TZASADatabaseInfo.Destroy; begin inherited; end; //---------------------------------------------------------------------- // First, a variety of minor information about the target database. {** Are NULL values sorted at the start regardless of sort order? @return true if so; false otherwise } function TZASADatabaseInfo.NullsAreSortedAtStart: Boolean; begin Result := True; end; {** What's the name of this database product? @return database product name } function TZASADatabaseInfo.GetDatabaseProductName: string; begin Result := 'Sybase ASA'; end; {** What's the version of this database product? @return database version } function TZASADatabaseInfo.GetDatabaseProductVersion: string; begin Result := '7.0+'; end; {** What's the name of this JDBC driver? @return JDBC driver name } function TZASADatabaseInfo.GetDriverName: string; begin Result := 'Zeos Database Connectivity Driver for Sybase ASA'; end; {** What's this JDBC driver's major version number? @return JDBC driver major version } function TZASADatabaseInfo.GetDriverMajorVersion: Integer; begin Result := 1; end; {** What's this JDBC driver's minor version number? @return JDBC driver minor version number } function TZASADatabaseInfo.GetDriverMinorVersion: Integer; begin Result := 0; end; {** Does the database store tables in a local file? @return true if so; false otherwise } function TZASADatabaseInfo.UsesLocalFiles: Boolean; begin Result := False; end; {** Does the database use a file for each table? @return true if the database uses a local file for each table } function TZASADatabaseInfo.UsesLocalFilePerTable: Boolean; begin Result := False; end; {** Does the database treat mixed case unquoted SQL identifiers as case sensitive and as a result store them in mixed case? A JDBC CompliantTM driver will always return false. @return true if so; false otherwise } function TZASADatabaseInfo.SupportsMixedCaseIdentifiers: Boolean; begin Result := False; end; {** Does the database treat mixed case unquoted SQL identifiers as case insensitive and store them in upper case? @return true if so; false otherwise } function TZASADatabaseInfo.StoresUpperCaseIdentifiers: Boolean; begin Result := False; end; {** Does the database treat mixed case unquoted SQL identifiers as case insensitive and store them in lower case? @return true if so; false otherwise } function TZASADatabaseInfo.StoresLowerCaseIdentifiers: Boolean; begin Result := False; end; {** Does the database treat mixed case unquoted SQL identifiers as case insensitive and store them in mixed case? @return true if so; false otherwise } function TZASADatabaseInfo.StoresMixedCaseIdentifiers: Boolean; begin Result := True; end; {** Does the database treat mixed case quoted SQL identifiers as case sensitive and as a result store them in mixed case? A JDBC CompliantTM driver will always return true. @return true if so; false otherwise } function TZASADatabaseInfo.SupportsMixedCaseQuotedIdentifiers: Boolean; begin Result := False; end; {** Does the database treat mixed case quoted SQL identifiers as case insensitive and store them in upper case? @return true if so; false otherwise } function TZASADatabaseInfo.StoresUpperCaseQuotedIdentifiers: Boolean; begin Result := False; end; {** Does the database treat mixed case quoted SQL identifiers as case insensitive and store them in lower case? @return true if so; false otherwise } function TZASADatabaseInfo.StoresLowerCaseQuotedIdentifiers: Boolean; begin Result := False; end; {** Does the database treat mixed case quoted SQL identifiers as case insensitive and store them in mixed case? @return true if so; false otherwise } function TZASADatabaseInfo.StoresMixedCaseQuotedIdentifiers: Boolean; begin Result := True; end; {** Gets a comma-separated list of all a database's SQL keywords that are NOT also SQL92 keywords. @return the list } function TZASADatabaseInfo.GetSQLKeywords: string; begin Result := 'add,all,alter,and,any,as,asc,backup,begin,between,bigint,binary,'+ 'bit,bottom,break,by,call,capability,cascade,case,cast,char,'+ 'char_convert,character,check,checkpoint,close,comment,commit,'+ 'connect,constraint,contains,continue,convert,create,cross,cube,'+ 'current,cursor,date,dbspace,deallocate,dec,decimal,declare,'+ 'default,delete,deleting,desc,distinct,do,double,drop,dynamic,'+ 'else,elseif,encrypted,end,endif,escape,exception,exec,execute,'+ 'existing,exists,externlogin,fetch,first,float,for,foreign,'+ 'forward,from,full,goto,grant,group,having,holdlock,identified,'+ 'if,in,index,inner,inout,insensitive,insert,inserting,install,'+ 'instead,int,integer,integrated,into,iq,is,isolation,join,key,'+ 'left,like,lock,login,long,match,membership,message,mode,modify,'+ 'natural,new,no,noholdlock,not,notify,null,numeric,of,off,on,open,'+ 'option,options,or,order,others,out,outer,over,passthrough,'+ 'precision,prepare,primary,print,privileges,proc,procedure,'+ 'publication,raiserror,readtext,real,reference,references,release,'+ 'remote,remove,rename,reorganize,resource,restore,restrict,return'+ 'revoke,right,rollback,rollup,save,savepoint,schedule,scroll,'+ 'select,sensitive,session,set,setuser,share,smallint,some,sqlcode,'+ 'sqlstate,start,stop,subtrans,subtransaction,synchronize,'+ 'syntax_error,table,temporary,then,time,timestamp,tinyint,to,top,'+ 'tran,trigger,truncate,tsequal,union,unique,unknown,unsigned,'+ 'update,updating,user,using,validate,values,varbinary,varchar,'+ 'variable,varying,view,wait,waitfor,when,where,while,with,'+ 'with_lparen,work,writetext'; end; {** Gets a comma-separated list of math functions. These are the X/Open CLI math function names used in the JDBC function escape clause. @return the list } function TZASADatabaseInfo.GetNumericFunctions: string; begin Result := 'ABS,ACOS,ASIN,ATAN,ATN2,CEILING,COS,COT,DEGREES,EXP,FLOOR,LOG,'+ 'LOG10,MOD,PI,POWER,RADIANS,RAND,REMAINDER,ROUND,SIGN,SIN,SQRT,'+ 'TAN,TRUNCATE,TRUNCNUM'; end; {** Gets a comma-separated list of string functions. These are the X/Open CLI string function names used in the JDBC function escape clause. @return the list } function TZASADatabaseInfo.GetStringFunctions: string; begin Result := 'ASCII,BYTE_LENGTH,BYTE_SUBSTR,CHAR,CHARINDEX,CHAR_LENGTH,COMPARE,'+ 'CSCONVERT,DIFFERENCE,INSERTSTR,LCASE,LEFT,LENGTH,LOCATE,LOWER,'+ 'LTRIM,PATINDEX,REPEAT,REPLACE,REPLICATE,RIGHT,RTRIM,SIMILAR,'+ 'SORTKEY,SOUNDEX,SPACE,STR,STRING,STRTOUUID,STUFF,SUBSTRING,TRIM,'+ 'UCASE,UPPER,UUIDTOSTR'; end; {** Gets a comma-separated list of system functions. These are the X/Open CLI system function names used in the JDBC function escape clause. @return the list } function TZASADatabaseInfo.GetSystemFunctions: string; begin Result := 'CONNECTION_PROPERTY,DATALENGTH,DB_ID,DB_NAME,DB_PROPERTY,'+ 'EVENT_CONDITION,EVENT_CONDITION_NAME,EVENT_PARAMETER,'+ 'NEXT_CONNECTION,NEXT_DATABASE,PROPERTY,PROPERTY_DESCRIPTION,'+ 'PROPERTY_NAME,PROPERTY_NUMBER,Col_length,Col_name,Datalength,'+ 'Index_col,Object_id,Object_name,Suser_id,Suser_name,Tsequal,'+ 'User_id,User_name,ARGN,COALESCE,ESTIMATE,ESTIMATE_SOURCE,'+ 'EXPERIENCE_ESTIMATE,EXPLANATION,GET_IDENTITY,GRAPHICAL_PLAN,'+ 'GRAPHICAL_ULPLAN,GREATER,IDENTITY,IFNULL,INDEX_ESTIMATE,ISNULL,'+ 'LESSER,LONG_ULPLAN,NEWID,NULLIF,NUMBER,PLAN,REWRITE,SHORT_ULPLAN,'+ 'SQLDIALECT,TRACEBACK,TRANSACTSQL,VAREXISTS,WATCOMSQL,TEXTPTR'; end; {** Gets a comma-separated list of time and date functions. @return the list } function TZASADatabaseInfo.GetTimeDateFunctions: string; begin Result := 'DATE,DATEADD,DATEDIFF,DATEFORMAT,DATENAME,DATEPART,DATETIME,DAY,'+ 'DAYNAME,DAYS,DOW,GETDATE,HOUR,HOURS,MINUTE,MINUTES,MONTH,'+ 'MONTHNAME,MONTHS,NOW,QUARTER,SECOND,SECONDS,TODAY,WEEKS,YEARS,YMD'; end; {** Gets the string that can be used to escape wildcard characters. This is the string that can be used to escape '_' or '%' in the string pattern style catalog search parameters.

The '_' character represents any single character.

The '%' character represents any sequence of zero or more characters. @return the string used to escape wildcard characters } function TZASADatabaseInfo.GetSearchStringEscape: string; begin Result := '\'; end; {** Gets all the "extra" characters that can be used in unquoted identifier names (those beyond a-z, A-Z, 0-9 and _). @return the string containing the extra characters } function TZASADatabaseInfo.GetExtraNameCharacters: string; begin Result := '@#$'; end; //-------------------------------------------------------------------- // Functions describing which features are supported. {** Are expressions in "ORDER BY" lists supported? @return true if so; false otherwise } function TZASADatabaseInfo.SupportsExpressionsInOrderBy: Boolean; begin Result := True; end; {** Can an "ORDER BY" clause use columns not in the SELECT statement? @return true if so; false otherwise } function TZASADatabaseInfo.SupportsOrderByUnrelated: Boolean; begin Result := True; end; {** Is some form of "GROUP BY" clause supported? @return true if so; false otherwise } function TZASADatabaseInfo.SupportsGroupBy: Boolean; begin Result := True; end; {** Can a "GROUP BY" clause use columns not in the SELECT? @return true if so; false otherwise } function TZASADatabaseInfo.SupportsGroupByUnrelated: Boolean; begin Result := True; end; {** Can a "GROUP BY" clause add columns not in the SELECT provided it specifies all the columns in the SELECT? @return true if so; false otherwise } function TZASADatabaseInfo.SupportsGroupByBeyondSelect: Boolean; begin Result := False; end; {** Is the SQL Integrity Enhancement Facility supported? @return true if so; false otherwise } function TZASADatabaseInfo.SupportsIntegrityEnhancementFacility: Boolean; begin Result := True; end; {** What's the database vendor's preferred term for "schema"? @return the vendor term } function TZASADatabaseInfo.GetSchemaTerm: string; begin Result := 'OWNER'; end; {** What's the database vendor's preferred term for "procedure"? @return the vendor term } function TZASADatabaseInfo.GetProcedureTerm: string; begin Result := 'PROCEDURE'; end; {** What's the database vendor's preferred term for "catalog"? @return the vendor term } function TZASADatabaseInfo.GetCatalogTerm: string; begin Result := ''; end; {** What's the separator between catalog and table name? @return the separator string } function TZASADatabaseInfo.GetCatalogSeparator: string; begin Result := ''; end; {** Can a schema name be used in a data manipulation statement? @return true if so; false otherwise } function TZASADatabaseInfo.SupportsSchemasInDataManipulation: Boolean; begin Result := True; end; {** Can a schema name be used in a procedure call statement? @return true if so; false otherwise } function TZASADatabaseInfo.SupportsSchemasInProcedureCalls: Boolean; begin Result := True; end; {** Can a schema name be used in a table definition statement? @return true if so; false otherwise } function TZASADatabaseInfo.SupportsSchemasInTableDefinitions: Boolean; begin Result := True; end; {** Can a schema name be used in an index definition statement? @return true if so; false otherwise } function TZASADatabaseInfo.SupportsSchemasInIndexDefinitions: Boolean; begin Result := False; end; {** Can a schema name be used in a privilege definition statement? @return true if so; false otherwise } function TZASADatabaseInfo.SupportsSchemasInPrivilegeDefinitions: Boolean; begin Result := False; end; {** Can a catalog name be used in a data manipulation statement? @return true if so; false otherwise } function TZASADatabaseInfo.SupportsCatalogsInDataManipulation: Boolean; begin Result := False; end; {** Can a catalog name be used in a procedure call statement? @return true if so; false otherwise } function TZASADatabaseInfo.SupportsCatalogsInProcedureCalls: Boolean; begin Result := False; end; {** Can a catalog name be used in a table definition statement? @return true if so; false otherwise } function TZASADatabaseInfo.SupportsCatalogsInTableDefinitions: Boolean; begin Result := False; end; {** Can a catalog name be used in an index definition statement? @return true if so; false otherwise } function TZASADatabaseInfo.SupportsCatalogsInIndexDefinitions: Boolean; begin Result := False; end; {** Can a catalog name be used in a privilege definition statement? @return true if so; false otherwise } function TZASADatabaseInfo.SupportsCatalogsInPrivilegeDefinitions: Boolean; begin Result := False; end; {** Is positioned DELETE supported? @return true if so; false otherwise } function TZASADatabaseInfo.SupportsPositionedDelete: Boolean; begin Result := True; end; {** Is positioned UPDATE supported? @return true if so; false otherwise } function TZASADatabaseInfo.SupportsPositionedUpdate: Boolean; begin Result := True; end; {** Is SELECT for UPDATE supported? @return true if so; false otherwise } function TZASADatabaseInfo.SupportsSelectForUpdate: Boolean; begin Result := True; end; {** Are stored procedure calls using the stored procedure escape syntax supported? @return true if so; false otherwise } function TZASADatabaseInfo.SupportsStoredProcedures: Boolean; begin Result := True; end; {** Are subqueries in comparison expressions supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZASADatabaseInfo.SupportsSubqueriesInComparisons: Boolean; begin Result := True; end; {** Are subqueries in 'exists' expressions supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZASADatabaseInfo.SupportsSubqueriesInExists: Boolean; begin Result := True; end; {** Are subqueries in 'in' statements supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZASADatabaseInfo.SupportsSubqueriesInIns: Boolean; begin Result := True; end; {** Are subqueries in quantified expressions supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZASADatabaseInfo.SupportsSubqueriesInQuantifieds: Boolean; begin Result := True; end; {** Are correlated subqueries supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZASADatabaseInfo.SupportsCorrelatedSubqueries: Boolean; begin Result := True; end; {** Is SQL UNION supported? @return true if so; false otherwise } function TZASADatabaseInfo.SupportsUnion: Boolean; begin Result := True; end; {** Is SQL UNION ALL supported? @return true if so; false otherwise } function TZASADatabaseInfo.SupportsUnionAll: Boolean; begin Result := True; end; {** Can cursors remain open across commits? @return true if cursors always remain open; false if they might not remain open } function TZASADatabaseInfo.SupportsOpenCursorsAcrossCommit: Boolean; begin Result := True; end; {** Can cursors remain open across rollbacks? @return true if cursors always remain open; false if they might not remain open } function TZASADatabaseInfo.SupportsOpenCursorsAcrossRollback: Boolean; begin Result := True; end; {** Can statements remain open across commits? @return true if statements always remain open; false if they might not remain open } function TZASADatabaseInfo.SupportsOpenStatementsAcrossCommit: Boolean; begin Result := True; end; {** Can statements remain open across rollbacks? @return true if statements always remain open; false if they might not remain open } function TZASADatabaseInfo.SupportsOpenStatementsAcrossRollback: Boolean; begin Result := True; end; //---------------------------------------------------------------------- // The following group of methods exposes various limitations // based on the target database with the current driver. // Unless otherwise specified, a result of zero means there is no // limit, or the limit is not known. {** How many hex characters can you have in an inline binary literal? @return max binary literal length in hex characters; a result of zero means that there is no limit or the limit is not known } function TZASADatabaseInfo.GetMaxBinaryLiteralLength: Integer; begin Result := 0; end; {** What's the max length for a character literal? @return max literal length; a result of zero means that there is no limit or the limit is not known } function TZASADatabaseInfo.GetMaxCharLiteralLength: Integer; begin Result := 32768; end; {** What's the limit on column name length? @return max column name length; a result of zero means that there is no limit or the limit is not known } function TZASADatabaseInfo.GetMaxColumnNameLength: Integer; begin Result := 128; end; {** What's the maximum number of columns in a "GROUP BY" clause? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZASADatabaseInfo.GetMaxColumnsInGroupBy: Integer; begin Result := 0; end; {** What's the maximum number of columns allowed in an index? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZASADatabaseInfo.GetMaxColumnsInIndex: Integer; begin Result := 1000000; end; {** What's the maximum number of columns in an "ORDER BY" clause? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZASADatabaseInfo.GetMaxColumnsInOrderBy: Integer; begin Result := 1000000; end; {** What's the maximum number of columns in a "SELECT" list? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZASADatabaseInfo.GetMaxColumnsInSelect: Integer; begin Result := 1000000; end; {** What's the maximum number of columns in a table? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZASADatabaseInfo.GetMaxColumnsInTable: Integer; begin Result := 1000000; end; {** How many active connections can we have at a time to this database? @return max number of active connections; a result of zero means that there is no limit or the limit is not known } function TZASADatabaseInfo.GetMaxConnections: Integer; begin Result := 0; end; {** What's the maximum cursor name length? @return max cursor name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZASADatabaseInfo.GetMaxCursorNameLength: Integer; begin Result := 128; end; {** Retrieves the maximum number of bytes for an index, including all of the parts of the index. @return max index length in bytes, which includes the composite of all the constituent parts of the index; a result of zero means that there is no limit or the limit is not known } function TZASADatabaseInfo.GetMaxIndexLength: Integer; begin Result := 0; end; {** What's the maximum length allowed for a schema name? @return max name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZASADatabaseInfo.GetMaxSchemaNameLength: Integer; begin Result := 128; end; {** What's the maximum length of a procedure name? @return max name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZASADatabaseInfo.GetMaxProcedureNameLength: Integer; begin Result := 128; end; {** What's the maximum length of a catalog name? @return max name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZASADatabaseInfo.GetMaxCatalogNameLength: Integer; begin Result := 0; end; {** What's the maximum length of a single row? @return max row size in bytes; a result of zero means that there is no limit or the limit is not known } function TZASADatabaseInfo.GetMaxRowSize: Integer; begin Result := 0; end; {** Did getMaxRowSize() include LONGVARCHAR and LONGVARBINARY blobs? @return true if so; false otherwise } function TZASADatabaseInfo.DoesMaxRowSizeIncludeBlobs: Boolean; begin Result := False; end; {** What's the maximum length of an SQL statement? @return max length in bytes; a result of zero means that there is no limit or the limit is not known } function TZASADatabaseInfo.GetMaxStatementLength: Integer; begin Result := 0; end; {** How many active statements can we have open at one time to this database? @return the maximum number of statements that can be open at one time; a result of zero means that there is no limit or the limit is not known } function TZASADatabaseInfo.GetMaxStatements: Integer; begin Result := 0; end; {** What's the maximum length of a table name? @return max name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZASADatabaseInfo.GetMaxTableNameLength: Integer; begin Result := 128; end; {** What's the maximum number of tables in a SELECT statement? @return the maximum number of tables allowed in a SELECT statement; a result of zero means that there is no limit or the limit is not known } function TZASADatabaseInfo.GetMaxTablesInSelect: Integer; begin Result := 0; end; {** What's the maximum length of a user name? @return max user name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZASADatabaseInfo.GetMaxUserNameLength: Integer; begin Result := 30; end; //---------------------------------------------------------------------- {** What's the database's default transaction isolation level? The values are defined in java.sql.Connection. @return the default isolation level @see Connection } function TZASADatabaseInfo.GetDefaultTransactionIsolation: TZTransactIsolationLevel; begin Result := tiReadUncommitted; end; {** Are transactions supported? If not, invoking the method commit is a noop and the isolation level is TRANSACTION_NONE. @return true if transactions are supported; false otherwise } function TZASADatabaseInfo.SupportsTransactions: Boolean; begin Result := True; end; {** Does this database support the given transaction isolation level? @param level the values are defined in java.sql.Connection @return true if so; false otherwise @see Connection } function TZASADatabaseInfo.SupportsTransactionIsolationLevel( Level: TZTransactIsolationLevel): Boolean; begin Result := True; end; {** Are both data definition and data manipulation statements within a transaction supported? @return true if so; false otherwise } function TZASADatabaseInfo. SupportsDataDefinitionAndDataManipulationTransactions: Boolean; begin Result := True; end; {** Are only data manipulation statements within a transaction supported? @return true if so; false otherwise } function TZASADatabaseInfo. SupportsDataManipulationTransactionsOnly: Boolean; begin Result := False; end; {** Does a data definition statement within a transaction force the transaction to commit? @return true if so; false otherwise } function TZASADatabaseInfo.DataDefinitionCausesTransactionCommit: Boolean; begin Result := True; end; {** Is a data definition statement within a transaction ignored? @return true if so; false otherwise } function TZASADatabaseInfo.DataDefinitionIgnoredInTransactions: Boolean; begin Result := False; end; {** Does the database support the given result set type? @param type defined in java.sql.ResultSet @return true if so; false otherwise } function TZASADatabaseInfo.SupportsResultSetType( _Type: TZResultSetType): Boolean; begin Result := True; end; {** Does the database support the concurrency type in combination with the given result set type? @param type defined in java.sql.ResultSet @param concurrency type defined in java.sql.ResultSet @return true if so; false otherwise } function TZASADatabaseInfo.SupportsResultSetConcurrency( _Type: TZResultSetType; Concurrency: TZResultSetConcurrency): Boolean; begin Result := True; end; { TZASADatabaseMetadata } {** Constructs this object and assignes the main properties. @param Connection a database connection object. @param Url a database connection url string. @param Info an extra connection properties. } constructor TZASADatabaseMetadata.Create(Connection: TZAbstractConnection; const Url: TZURL); begin inherited Create(Connection, Url); FASAConnection := Connection as TZASAConnection; end; {** Composes a object name, AnsiQuotedStr or NullText @param S the object string @param NullText the "NULL"-Text default: 'null' @param QuoteChar the QuoteChar default: ' @return 'null' if S is '' or S if s is already Quoted or AnsiQuotedStr(S, #39) } function TZASADatabaseMetadata.ComposeObjectString(const S: String; Const NullText: String = 'null'; QuoteChar: Char = #39): String; begin if S = '' then Result := NullText else if IC.IsQuoted(s) then Result := S else Result := AnsiQuotedStr(S, QuoteChar); end; {** Constructs a database information object and returns the interface to it. Used internally by the constructor. @return the database information object interface } function TZASADatabaseMetadata.CreateDatabaseInfo: IZDatabaseInfo; begin Result := TZASADatabaseInfo.Create(Self); end; {** Gets a description of the stored procedures available in a catalog.

Only procedure descriptions matching the schema and procedure name criteria are returned. They are ordered by PROCEDURE_SCHEM, and PROCEDURE_NAME.

Each procedure description has the the following columns:

  1. PROCEDURE_CAT String => procedure catalog (may be null)
  2. PROCEDURE_SCHEM String => procedure schema (may be null)
  3. PROCEDURE_NAME String => procedure name
  4. reserved for future use
  5. reserved for future use
  6. reserved for future use
  7. REMARKS String => explanatory comment on the procedure
  8. PROCEDURE_TYPE short => kind of procedure:
    • procedureResultUnknown - May return a result
    • procedureNoResult - Does not return a result
    • procedureReturnsResult - Returns a result
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param procedureNamePattern a procedure name pattern @return ResultSet - each row is a procedure description @see #getSearchStringEscape } function TZASADatabaseMetadata.UncachedGetProcedures(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string): IZResultSet; begin Result:=inherited UncachedGetProcedures(Catalog, SchemaPattern, ProcedureNamePattern); with GetStatement.ExecuteQuery( Format('exec sp_jdbc_stored_procedures %s, %s, %s', [ComposeObjectString(Catalog), ComposeObjectString(SchemaPattern), ComposeObjectString(ProcedureNamePattern)])) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('PROCEDURE_CAT', ''); Result.UpdateStringByName('PROCEDURE_SCHEM', GetStringByName('PROCEDURE_SCHEM')); Result.UpdateStringByName('PROCEDURE_NAME', GetStringByName('PROCEDURE_NAME')); Result.UpdateStringByName('REMARKS', GetStringByName('REMARKS')); Result.UpdateShortByName('PROCEDURE_TYPE', GetShortByName('PROCEDURE_TYPE')); Result.InsertRow; end; Close; end; end; {** Gets a description of a catalog's stored procedure parameters and result columns.

Only descriptions matching the schema, procedure and parameter name criteria are returned. They are ordered by PROCEDURE_SCHEM and PROCEDURE_NAME. Within this, the return value, if any, is first. Next are the parameter descriptions in call order. The column descriptions follow in column number order.

Each row in the ResultSet is a parameter description or column description with the following fields:

  1. PROCEDURE_CAT String => procedure catalog (may be null)
  2. PROCEDURE_SCHEM String => procedure schema (may be null)
  3. PROCEDURE_NAME String => procedure name
  4. COLUMN_NAME String => column/parameter name
  5. COLUMN_TYPE Short => kind of column/parameter:
    • procedureColumnUnknown - nobody knows
    • procedureColumnIn - IN parameter
    • procedureColumnInOut - INOUT parameter
    • procedureColumnOut - OUT parameter
    • procedureColumnReturn - procedure return value
    • procedureColumnResult - result column in ResultSet
  6. DATA_TYPE short => SQL type from java.sql.Types
  7. TYPE_NAME String => SQL type name, for a UDT type the type name is fully qualified
  8. PRECISION int => precision
  9. LENGTH int => length in bytes of data
  10. SCALE short => scale
  11. RADIX short => radix
  12. NULLABLE short => can it contain NULL?
    • procedureNoNulls - does not allow NULL values
    • procedureNullable - allows NULL values
    • procedureNullableUnknown - nullability unknown
  13. REMARKS String => comment describing parameter/column

Note: Some databases may not return the column descriptions for a procedure. Additional columns beyond REMARKS can be defined by the database. @param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param procedureNamePattern a procedure name pattern @param columnNamePattern a column name pattern @return ResultSet - each row describes a stored procedure parameter or column @see #getSearchStringEscape } function TZASADatabaseMetadata.UncachedGetProcedureColumns(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string; const ColumnNamePattern: string): IZResultSet; begin Result:=inherited UncachedGetProcedureColumns(Catalog, SchemaPattern, ProcedureNamePattern, ColumnNamePattern); with GetStatement.ExecuteQuery( Format('exec sp_jdbc_getprocedurecolumns %s, %s, %s, %s', [ComposeObjectString(Catalog), ComposeObjectString(SchemaPattern), ComposeObjectString(ProcedureNamePattern), ComposeObjectString(ColumnNamePattern)])) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('PROCEDURE_CAT', ''); Result.UpdateStringByName('PROCEDURE_SCHEM', GetStringByName('PROCEDURE_SCHEM')); Result.UpdateStringByName('PROCEDURE_NAME', GetStringByName('PROCEDURE_NAME')); Result.UpdateStringByName('COLUMN_NAME', GetStringByName('COLUMN_NAME')); case GetShortByName('COLUMN_TYPE') of 1: Result.UpdateShortByName('COLUMN_TYPE', Ord(pctIn)); 2: Result.UpdateShortByName('COLUMN_TYPE', Ord(pctInOut)); 3: Result.UpdateShortByName('COLUMN_TYPE', Ord(pctOut)); 5: Result.UpdateShortByName('COLUMN_TYPE', Ord(pctReturn)); else Result.UpdateShortByName('COLUMN_TYPE', Ord(pctUnknown)); end; Result.UpdateShortByName('DATA_TYPE', Ord(ConvertASAJDBCToSqlType(GetShortByName('DATA_TYPE'), ConSettings.CPType))); Result.UpdateStringByName('TYPE_NAME', GetStringByName('TYPE_NAME')); Result.UpdateIntByName('PRECISION', GetIntByName('PRECISION')); Result.UpdateIntByName('LENGTH', GetIntByName('LENGTH')); Result.UpdateShortByName('SCALE', GetShortByName('SCALE')); Result.UpdateShortByName('RADIX', GetShortByName('RADIX')); Result.UpdateShortByName('NULLABLE', GetShortByName('NULLABLE')); Result.UpdateStringByName('REMARKS', GetStringByName('REMARKS')); Result.InsertRow; end; Close; end; end; {** Gets a description of tables available in a catalog.

Only table descriptions matching the catalog, schema, table name and type criteria are returned. They are ordered by TABLE_TYPE, TABLE_SCHEM and TABLE_NAME.

Each table description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. TABLE_TYPE String => table type. Typical types are "TABLE", "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM".
  5. REMARKS String => explanatory comment on the table

Note: Some databases may not return information for all tables. @param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param tableNamePattern a table name pattern @param types a list of table types to include; null returns all types @return ResultSet - each row is a table description @see #getSearchStringEscape } function TZASADatabaseMetadata.UncachedGetTables(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const Types: TStringDynArray): IZResultSet; var I: Integer; TableTypes: string; begin Result:=inherited UncachedGetTables(Catalog, SchemaPattern, TableNamePattern, Types); TableTypes := ''; for I := 0 to Length(Types) - 1 do begin if TableTypes <> '' then TableTypes := TableTypes + ','; TableTypes := TableTypes + AnsiQuotedStr(Types[I], ''''); end; with GetStatement.ExecuteQuery( Format('exec sp_jdbc_tables %s, %s, %s, %s', [ComposeObjectString(TableNamePattern), ComposeObjectString(SchemaPattern), ComposeObjectString(Catalog), ComposeObjectString(TableTypes, 'null', '"')])) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TABLE_CAT', ''); Result.UpdateStringByName('TABLE_SCHEM', GetStringByName('TABLE_SCHEM')); Result.UpdateStringByName('TABLE_NAME', GetStringByName('TABLE_NAME')); Result.UpdateStringByName('TABLE_TYPE', GetStringByName('TABLE_TYPE')); Result.UpdateStringByName('REMARKS', GetStringByName('REMARKS')); Result.InsertRow; end; Close; end; end; {** Gets the schema names available in this database. The results are ordered by schema name.

The schema column is:

  1. TABLE_SCHEM String => schema name
@return ResultSet - each row has a single String column that is a schema name } function TZASADatabaseMetadata.UncachedGetSchemas: IZResultSet; begin Result:=inherited UncachedGetSchemas; with GetStatement.ExecuteQuery('select TABLE_SCHEM=name from sysusers where suid >= -2 order by name' {'exec sp_jdbc_getschemas'}) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TABLE_SCHEM', GetStringByName('TABLE_SCHEM')); Result.InsertRow; end; Close; end; end; {** Gets the table types available in this database. The results are ordered by table type.

The table type is:

  1. TABLE_TYPE String => table type. Typical types are "TABLE", "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM".
@return ResultSet - each row has a single String column that is a table type } function TZASADatabaseMetadata.UncachedGetTableTypes: IZResultSet; const TablesTypes: array [0..4] of String = ( 'TABLE', 'BASE', 'SYSTEM', 'VIEW', 'GLOBAL TEMPORARY'); var I: Integer; begin Result:=inherited UncachedGetTableTypes; for I := 0 to 4 do begin Result.MoveToInsertRow; Result.UpdateString(1, TablesTypes[I]); Result.InsertRow; end; end; {** Gets a description of table columns available in the specified catalog.

Only column descriptions matching the catalog, schema, table and column name criteria are returned. They are ordered by TABLE_SCHEM, TABLE_NAME and ORDINAL_POSITION.

Each column description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. COLUMN_NAME String => column name
  5. DATA_TYPE short => SQL type from java.sql.Types
  6. TYPE_NAME String => Data source dependent type name, for a UDT the type name is fully qualified
  7. COLUMN_SIZE int => column size. For char or date types this is the maximum number of characters, for numeric or decimal types this is precision.
  8. BUFFER_LENGTH is not used.
  9. DECIMAL_DIGITS int => the number of fractional digits
  10. NUM_PREC_RADIX int => Radix (typically either 10 or 2)
  11. NULLABLE int => is NULL allowed?
    • columnNoNulls - might not allow NULL values
    • columnNullable - definitely allows NULL values
    • columnNullableUnknown - nullability unknown
  12. REMARKS String => comment describing column (may be null)
  13. COLUMN_DEF String => default value (may be null)
  14. SQL_DATA_TYPE int => unused
  15. SQL_DATETIME_SUB int => unused
  16. CHAR_OCTET_LENGTH int => for char types the maximum number of bytes in the column
  17. ORDINAL_POSITION int => index of column in table (starting at 1)
  18. IS_NULLABLE String => "NO" means column definitely does not allow NULL values; "YES" means the column might allow NULL values. An empty string means nobody knows.
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param tableNamePattern a table name pattern @param columnNamePattern a column name pattern @return ResultSet - each row is a column description @see #getSearchStringEscape } function TZASADatabaseMetadata.UncachedGetColumns(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const ColumnNamePattern: string): IZResultSet; begin Result:=inherited UncachedGetColumns(Catalog, SchemaPattern, TableNamePattern, ColumnNamePattern); with GetStatement.ExecuteQuery( Format('exec sp_jdbc_columns %s, %s, %s, %s', [ComposeObjectString(TableNamePattern), ComposeObjectString(SchemaPattern), ComposeObjectString(Catalog), ComposeObjectString(ColumnNamePattern)])) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TABLE_CAT', ''); Result.UpdateStringByName('TABLE_SCHEM', GetStringByName('TABLE_SCHEM')); Result.UpdateStringByName('TABLE_NAME', GetStringByName('TABLE_NAME')); Result.UpdateStringByName('COLUMN_NAME', GetStringByName('COLUMN_NAME')); //The value in the resultset will be used // Result.UpdateShortByName('DATA_TYPE', // Ord(ConvertASAJDBCToSqlType(GetShortByName('DATA_TYPE')))); Result.UpdateStringByName('TYPE_NAME', GetStringByName('TYPE_NAME')); //Result.UpdateIntByName('COLUMN_SIZE', //GetIntByName('COLUMN_SIZE')); Result.UpdateIntByName('BUFFER_LENGTH', GetIntByName('BUFFER_LENGTH')); Result.UpdateIntByName('DECIMAL_DIGITS', GetIntByName('DECIMAL_DIGITS')); Result.UpdateIntByName('NUM_PREC_RADIX', GetShortByName('NUM_PREC_RADIX')); Result.UpdateStringByName('REMARKS', GetStringByName('REMARKS')); Result.UpdateStringByName('COLUMN_DEF', GetStringByName('COLUMN_DEF')); Result.UpdateShortByName('SQL_DATA_TYPE', GetShortByName('SQL_DATA_TYPE')); Result.UpdateShortByName('SQL_DATETIME_SUB', GetShortByName('SQL_DATETIME_SUB')); Result.UpdateIntByName('CHAR_OCTET_LENGTH', GetIntByName('CHAR_OCTET_LENGTH')); Result.UpdateIntByName('ORDINAL_POSITION', GetIntByName('ORDINAL_POSITION')); Result.UpdateBooleanByName('AUTO_INCREMENT', CompareText( Trim( String(GetStringByName('COLUMN_DEF'))), 'autoincrement') = 0 ); Result.UpdateNullByName('CASE_SENSITIVE'); Result.UpdateBooleanByName('SEARCHABLE', False); Result.UpdateStringByName('IS_NULLABLE', GetStringByName( 'IS_NULLABLE')); Result.UpdateShortByName('NULLABLE', GetShortByName( 'NULLABLE')); Result.UpdateBooleanByName('WRITABLE', True); Result.UpdateBooleanByName('DEFINITELYWRITABLE', True); Result.UpdateBooleanByName('READONLY', False); Result.InsertRow; end; Close; end; Result.First; with GetStatement.ExecuteQuery( Format('select c.column_id,c.nulls '+ 'from SYS.SYSCOLUMN as c join SYS.SYSTABLE as t on c.table_id=t.table_id '+ 'where t.table_name like %s escape ''\'' and '+ 'USER_NAME(t.creator) like %s escape ''\'' and '+ 'c.column_name like %s escape ''\'' and c.column_type=''C'' '+ 'order by USER_NAME(t.creator) asc,t.table_name asc,c.column_id asc', [ComposeObjectString(TableNamePattern, '''%'''), ComposeObjectString(SchemaPattern, '''%'''), ComposeObjectString(ColumnNamePattern, '''%''')])) do begin while Next do begin while Result.GetIntByName( 'ORDINAL_POSITION') <> GetIntByName( 'column_id') do Result.Next; Result.UpdateBooleanByName( 'WRITABLE', False); Result.UpdateBooleanByName( 'DEFINITELYWRITABLE', False); Result.UpdateBooleanByName( 'READONLY', True); if GetStringByName( 'nulls') = 'N' then begin Result.UpdateShortByName( 'NULLABLE', 0); Result.UpdateStringByName( 'IS_NULLABLE', 'NO'); end; Result.UpdateRow; end; Close; end; end; {** Gets a description of the access rights for a table's columns.

Only privileges matching the column name criteria are returned. They are ordered by COLUMN_NAME and PRIVILEGE.

Each privilige description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. COLUMN_NAME String => column name
  5. GRANTOR => grantor of access (may be null)
  6. GRANTEE String => grantee of access
  7. PRIVILEGE String => name of access (SELECT, INSERT, UPDATE, REFRENCES, ...)
  8. IS_GRANTABLE String => "YES" if grantee is permitted to grant to others; "NO" if not; null if unknown
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @param columnNamePattern a column name pattern @return ResultSet - each row is a column privilege description @see #getSearchStringEscape } function TZASADatabaseMetadata.UncachedGetColumnPrivileges(const Catalog: string; const Schema: string; const Table: string; const ColumnNamePattern: string): IZResultSet; begin Result:=inherited UncachedGetColumnPrivileges(Catalog, Schema, Table, ColumnNamePattern); with GetStatement.ExecuteQuery( Format('exec sp_jdbc_getcolumnprivileges %s, %s, %s, %s', [ComposeObjectString(Catalog), ComposeObjectString(Schema), ComposeObjectString(Table), ComposeObjectString(ColumnNamePattern)])) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TABLE_CAT', ''); Result.UpdateStringByName('TABLE_SCHEM', GetStringByName('TABLE_SCHEM')); Result.UpdateStringByName('TABLE_NAME', GetStringByName('TABLE_NAME')); Result.UpdateStringByName('COLUMN_NAME', GetStringByName('COLUMN_NAME')); Result.UpdateStringByName('GRANTOR', GetStringByName('GRANTOR')); Result.UpdateStringByName('GRANTEE', GetStringByName('GRANTEE')); Result.UpdateStringByName('PRIVILEGE', GetStringByName('PRIVILEGE')); Result.UpdateStringByName('IS_GRANTABLE', GetStringByName('IS_GRANTABLE')); Result.InsertRow; end; Close; end; end; {** Gets a description of the access rights for each table available in a catalog. Note that a table privilege applies to one or more columns in the table. It would be wrong to assume that this priviledge applies to all columns (this may be true for some systems but is not true for all.)

Only privileges matching the schema and table name criteria are returned. They are ordered by TABLE_SCHEM, TABLE_NAME, and PRIVILEGE.

Each privilige description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. GRANTOR => grantor of access (may be null)
  5. GRANTEE String => grantee of access
  6. PRIVILEGE String => name of access (SELECT, INSERT, UPDATE, REFRENCES, ...)
  7. IS_GRANTABLE String => "YES" if grantee is permitted to grant to others; "NO" if not; null if unknown
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param tableNamePattern a table name pattern @return ResultSet - each row is a table privilege description @see #getSearchStringEscape } function TZASADatabaseMetadata.UncachedGetTablePrivileges(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string): IZResultSet; begin Result:=inherited UncachedGetTablePrivileges(Catalog, SchemaPattern, TableNamePattern); with GetStatement.ExecuteQuery( Format('exec sp_jdbc_gettableprivileges %s, %s, %s', [ComposeObjectString(Catalog), ComposeObjectString(SchemaPattern), ComposeObjectString(TableNamePattern)])) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TABLE_CAT', ''); Result.UpdateStringByName('TABLE_SCHEM', GetStringByName('TABLE_SCHEM')); Result.UpdateStringByName('TABLE_NAME', GetStringByName('TABLE_NAME')); Result.UpdateStringByName('GRANTOR', GetStringByName('GRANTOR')); Result.UpdateStringByName('GRANTEE', GetStringByName('GRANTEE')); Result.UpdateStringByName('PRIVILEGE', GetStringByName('PRIVILEGE')); Result.UpdateStringByName('IS_GRANTABLE', GetStringByName('IS_GRANTABLE')); Result.InsertRow; end; Close; end; end; {** Gets a description of a table's columns that are automatically updated when any value in a row is updated. They are unordered.

Each column description has the following columns:

  1. SCOPE short => is not used
  2. COLUMN_NAME String => column name
  3. DATA_TYPE short => SQL data type from java.sql.Types
  4. TYPE_NAME String => Data source dependent type name
  5. COLUMN_SIZE int => precision
  6. BUFFER_LENGTH int => length of column value in bytes
  7. DECIMAL_DIGITS short => scale
  8. PSEUDO_COLUMN short => is this a pseudo column like an Oracle ROWID
    • versionColumnUnknown - may or may not be pseudo column
    • versionColumnNotPseudo - is NOT a pseudo column
    • versionColumnPseudo - is a pseudo column
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a column description @exception SQLException if a database access error occurs } function TZASADatabaseMetadata.UncachedGetVersionColumns(const Catalog: string; const Schema: string; const Table: string): IZResultSet; begin Result:=inherited UncachedGetVersionColumns(Catalog, Schema, Table); with GetStatement.ExecuteQuery( Format('exec sp_jdbc_getversioncolumns %s, %s, %s', [ComposeObjectString(Catalog), ComposeObjectString(Schema), ComposeObjectString(Table)])) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateShortByName('SCOPE', GetShortByName('SCOPE')); Result.UpdateStringByName('COLUMN_NAME', GetStringByName('COLUMN_NAME')); Result.UpdateShortByName('DATA_TYPE', Ord(ConvertASAJDBCToSqlType(GetShortByName('DATA_TYPE'), ConSettings.CPType))); Result.UpdateStringByName('TYPE_NAME', GetStringByName('TYPE_NAME')); Result.UpdateIntByName('COLUMN_SIZE', GetIntByName('COLUMN_SIZE')); Result.UpdateIntByName('BUFFER_LENGTH', GetIntByName('BUFFER_LENGTH')); Result.UpdateIntByName('DECIMAL_DIGITS', GetIntByName('DECIMAL_DIGITS')); Result.UpdateShortByName('PSEUDO_COLUMN', GetShortByName('PSEUDO_COLUMN')); Result.InsertRow; end; Close; end; end; {** Gets a description of a table's primary key columns. They are ordered by COLUMN_NAME.

Each primary key column description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. COLUMN_NAME String => column name
  5. KEY_SEQ short => sequence number within primary key
  6. PK_NAME String => primary key name (may be null)
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a primary key column description @exception SQLException if a database access error occurs } function TZASADatabaseMetadata.UncachedGetPrimaryKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; begin Result:=inherited UncachedGetPrimaryKeys(Catalog, Schema, Table); with GetStatement.ExecuteQuery( Format('exec sp_jdbc_primarykey %s, %s, %s', [ComposeObjectString(Catalog), ComposeObjectString(Schema), ComposeObjectString(Table)])) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TABLE_CAT', ''); Result.UpdateStringByName('TABLE_SCHEM', GetStringByName('TABLE_SCHEM')); Result.UpdateStringByName('TABLE_NAME', GetStringByName('TABLE_NAME')); Result.UpdateStringByName('COLUMN_NAME', GetStringByName('COLUMN_NAME')); Result.UpdateShortByName('KEY_SEQ', GetShortByName('KEY_SEQ')); Result.UpdateStringByName('PK_NAME', GetStringByName('PK_NAME')); Result.InsertRow; end; Close; end; end; {** Gets a description of the primary key columns that are referenced by a table's foreign key columns (the primary keys imported by a table). They are ordered by PKTABLE_CAT, PKTABLE_SCHEM, PKTABLE_NAME, and KEY_SEQ.

Each primary key column description has the following columns:

  1. PKTABLE_CAT String => primary key table catalog being imported (may be null)
  2. PKTABLE_SCHEM String => primary key table schema being imported (may be null)
  3. PKTABLE_NAME String => primary key table name being imported
  4. PKCOLUMN_NAME String => primary key column name being imported
  5. FKTABLE_CAT String => foreign key table catalog (may be null)
  6. FKTABLE_SCHEM String => foreign key table schema (may be null)
  7. FKTABLE_NAME String => foreign key table name
  8. FKCOLUMN_NAME String => foreign key column name
  9. KEY_SEQ short => sequence number within foreign key
  10. UPDATE_RULE short => What happens to foreign key when primary is updated:
    • importedNoAction - do not allow update of primary key if it has been imported
    • importedKeyCascade - change imported key to agree with primary key update
    • importedKeySetNull - change imported key to NULL if its primary key has been updated
    • importedKeySetDefault - change imported key to default values if its primary key has been updated
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
  11. DELETE_RULE short => What happens to the foreign key when primary is deleted.
    • importedKeyNoAction - do not allow delete of primary key if it has been imported
    • importedKeyCascade - delete rows that import a deleted key
    • importedKeySetNull - change imported key to NULL if its primary key has been deleted
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
    • importedKeySetDefault - change imported key to default if its primary key has been deleted
  12. FK_NAME String => foreign key name (may be null)
  13. PK_NAME String => primary key name (may be null)
  14. DEFERRABILITY short => can the evaluation of foreign key constraints be deferred until commit
    • importedKeyInitiallyDeferred - see SQL92 for definition
    • importedKeyInitiallyImmediate - see SQL92 for definition
    • importedKeyNotDeferrable - see SQL92 for definition
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a primary key column description @see #getExportedKeys } function TZASADatabaseMetadata.UncachedGetImportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; begin Result:=inherited UncachedGetImportedKeys(Catalog, Schema, Table); with GetStatement.ExecuteQuery( Format('exec sp_jdbc_importkey %s, %s, %s', [ComposeObjectString(Catalog), ComposeObjectString(Schema), ComposeObjectString(Table)])) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('PKTABLE_CAT', ''); Result.UpdateStringByName('PKTABLE_SCHEM', GetStringByName('PKTABLE_SCHEM')); Result.UpdateStringByName('PKTABLE_NAME', GetStringByName('PKTABLE_NAME')); Result.UpdateStringByName('PKCOLUMN_NAME', GetStringByName('PKCOLUMN_NAME')); Result.UpdateStringByName('FKTABLE_CAT', ''); Result.UpdateStringByName('FKTABLE_SCHEM', GetStringByName('FKTABLE_SCHEM')); Result.UpdateStringByName('FKTABLE_NAME', GetStringByName('FKTABLE_NAME')); Result.UpdateStringByName('FKCOLUMN_NAME', GetStringByName('FKCOLUMN_NAME')); Result.UpdateShortByName('KEY_SEQ', GetShortByName('KEY_SEQ')); Result.UpdateShortByName('UPDATE_RULE', GetShortByName('UPDATE_RULE')); Result.UpdateShortByName('DELETE_RULE', GetShortByName('DELETE_RULE')); Result.UpdateStringByName('FK_NAME', GetStringByName('FK_NAME')); Result.UpdateStringByName('PK_NAME', GetStringByName('PK_NAME')); Result.UpdateIntByName('DEFERRABILITY', GetIntByName('DEFERRABILITY')); Result.InsertRow; end; Close; end; end; {** Gets a description of the foreign key columns that reference a table's primary key columns (the foreign keys exported by a table). They are ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, and KEY_SEQ.

Each foreign key column description has the following columns:

  1. PKTABLE_CAT String => primary key table catalog (may be null)
  2. PKTABLE_SCHEM String => primary key table schema (may be null)
  3. PKTABLE_NAME String => primary key table name
  4. PKCOLUMN_NAME String => primary key column name
  5. FKTABLE_CAT String => foreign key table catalog (may be null) being exported (may be null)
  6. FKTABLE_SCHEM String => foreign key table schema (may be null) being exported (may be null)
  7. FKTABLE_NAME String => foreign key table name being exported
  8. FKCOLUMN_NAME String => foreign key column name being exported
  9. KEY_SEQ short => sequence number within foreign key
  10. UPDATE_RULE short => What happens to foreign key when primary is updated:
    • importedNoAction - do not allow update of primary key if it has been imported
    • importedKeyCascade - change imported key to agree with primary key update
    • importedKeySetNull - change imported key to NULL if its primary key has been updated
    • importedKeySetDefault - change imported key to default values if its primary key has been updated
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
  11. DELETE_RULE short => What happens to the foreign key when primary is deleted.
    • importedKeyNoAction - do not allow delete of primary key if it has been imported
    • importedKeyCascade - delete rows that import a deleted key
    • importedKeySetNull - change imported key to NULL if its primary key has been deleted
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
    • importedKeySetDefault - change imported key to default if its primary key has been deleted
  12. FK_NAME String => foreign key name (may be null)
  13. PK_NAME String => primary key name (may be null)
  14. DEFERRABILITY short => can the evaluation of foreign key constraints be deferred until commit
    • importedKeyInitiallyDeferred - see SQL92 for definition
    • importedKeyInitiallyImmediate - see SQL92 for definition
    • importedKeyNotDeferrable - see SQL92 for definition
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a foreign key column description @see #getImportedKeys } function TZASADatabaseMetadata.UncachedGetExportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; var KeySeq: Integer; begin Result:=inherited UncachedGetExportedKeys(Catalog, Schema, Table); KeySeq := 0; with GetStatement.ExecuteQuery( Format('exec sp_jdbc_exportkey %s, %s, %s', [ComposeObjectString(Catalog), ComposeObjectString(Schema), ComposeObjectString(Table)])) do begin while Next do begin Inc(KeySeq); Result.MoveToInsertRow; Result.UpdateStringByName('PKTABLE_CAT', ''); Result.UpdateStringByName('PKTABLE_SCHEM', GetStringByName('PKTABLE_SCHEM')); Result.UpdateStringByName('PKTABLE_NAME', GetStringByName('PKTABLE_NAME')); Result.UpdateStringByName('PKCOLUMN_NAME', GetStringByName('PKCOLUMN_NAME')); Result.UpdateStringByName('FKTABLE_CAT', ''); Result.UpdateStringByName('FKTABLE_SCHEM', GetStringByName('FKTABLE_SCHEM')); Result.UpdateStringByName('FKTABLE_NAME', GetStringByName('FKTABLE_NAME')); Result.UpdateStringByName('FKCOLUMN_NAME', GetStringByName('FKCOLUMN_NAME')); Result.UpdateShortByName('KEY_SEQ', KeySeq); Result.UpdateShortByName('UPDATE_RULE', GetShortByName('UPDATE_RULE')); Result.UpdateShortByName('DELETE_RULE', GetShortByName('DELETE_RULE')); Result.UpdateStringByName('FK_NAME', GetStringByName('FK_NAME')); Result.UpdateStringByName('PK_NAME', GetStringByName('PK_NAME')); Result.UpdateIntByName('DEFERRABILITY', GetIntByName('DEFERRABILITY')); Result.InsertRow; end; Close; end; end; {** Gets a description of the foreign key columns in the foreign key table that reference the primary key columns of the primary key table (describe how one table imports another's key.) This should normally return a single foreign key/primary key pair (most tables only import a foreign key from a table once.) They are ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, and KEY_SEQ.

Each foreign key column description has the following columns:

  1. PKTABLE_CAT String => primary key table catalog (may be null)
  2. PKTABLE_SCHEM String => primary key table schema (may be null)
  3. PKTABLE_NAME String => primary key table name
  4. PKCOLUMN_NAME String => primary key column name
  5. FKTABLE_CAT String => foreign key table catalog (may be null) being exported (may be null)
  6. FKTABLE_SCHEM String => foreign key table schema (may be null) being exported (may be null)
  7. FKTABLE_NAME String => foreign key table name being exported
  8. FKCOLUMN_NAME String => foreign key column name being exported
  9. KEY_SEQ short => sequence number within foreign key
  10. UPDATE_RULE short => What happens to foreign key when primary is updated:
    • importedNoAction - do not allow update of primary key if it has been imported
    • importedKeyCascade - change imported key to agree with primary key update
    • importedKeySetNull - change imported key to NULL if its primary key has been updated
    • importedKeySetDefault - change imported key to default values if its primary key has been updated
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
  11. DELETE_RULE short => What happens to the foreign key when primary is deleted.
    • importedKeyNoAction - do not allow delete of primary key if it has been imported
    • importedKeyCascade - delete rows that import a deleted key
    • importedKeySetNull - change imported key to NULL if its primary key has been deleted
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
    • importedKeySetDefault - change imported key to default if its primary key has been deleted
  12. FK_NAME String => foreign key name (may be null)
  13. PK_NAME String => primary key name (may be null)
  14. DEFERRABILITY short => can the evaluation of foreign key constraints be deferred until commit
    • importedKeyInitiallyDeferred - see SQL92 for definition
    • importedKeyInitiallyImmediate - see SQL92 for definition
    • importedKeyNotDeferrable - see SQL92 for definition
@param primaryCatalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param primarySchema a schema name; "" retrieves those without a schema @param primaryTable the table name that exports the key @param foreignCatalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param foreignSchema a schema name; "" retrieves those without a schema @param foreignTable the table name that imports the key @return ResultSet - each row is a foreign key column description @see #getImportedKeys } function TZASADatabaseMetadata.UncachedGetCrossReference(const PrimaryCatalog: string; const PrimarySchema: string; const PrimaryTable: string; const ForeignCatalog: string; const ForeignSchema: string; const ForeignTable: string): IZResultSet; begin Result:=inherited UncachedGetCrossReference(PrimaryCatalog, PrimarySchema, PrimaryTable, ForeignCatalog, ForeignSchema, ForeignTable); with GetStatement.ExecuteQuery( Format('exec sp_jdbc_getcrossreferences %s, %s, %s, %s, %s, %s', [ComposeObjectString(PrimaryCatalog), ComposeObjectString(PrimarySchema), ComposeObjectString(PrimaryTable), ComposeObjectString(ForeignCatalog), ComposeObjectString(ForeignSchema), ComposeObjectString(ForeignTable)])) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('PKTABLE_CAT', ''); Result.UpdateStringByName('PKTABLE_SCHEM', GetStringByName('PKTABLE_SCHEM')); Result.UpdateStringByName('PKTABLE_NAME', GetStringByName('PKTABLE_NAME')); Result.UpdateStringByName('PKCOLUMN_NAME', GetStringByName('PKCOLUMN_NAME')); Result.UpdateStringByName('FKTABLE_CAT', ''); Result.UpdateStringByName('FKTABLE_SCHEM', GetStringByName('FKTABLE_SCHEM')); Result.UpdateStringByName('FKTABLE_NAME', GetStringByName('FKTABLE_NAME')); Result.UpdateStringByName('FKCOLUMN_NAME', GetStringByName('FKCOLUMN_NAME')); Result.UpdateShortByName('KEY_SEQ', GetShortByName('KEY_SEQ')); Result.UpdateShortByName('UPDATE_RULE', GetShortByName('UPDATE_RULE')); Result.UpdateShortByName('DELETE_RULE', GetShortByName('DELETE_RULE')); Result.UpdateStringByName('FK_NAME', GetStringByName('FK_NAME')); Result.UpdateStringByName('PK_NAME', GetStringByName('PK_NAME')); Result.UpdateIntByName('DEFERRABILITY', GetIntByName('DEFERRABILITY')); Result.InsertRow; end; Close; end; end; {** Gets a description of all the standard SQL types supported by this database. They are ordered by DATA_TYPE and then by how closely the data type maps to the corresponding JDBC SQL type.

Each type description has the following columns:

  1. TYPE_NAME String => Type name
  2. DATA_TYPE short => SQL data type from java.sql.Types
  3. PRECISION int => maximum precision
  4. LITERAL_PREFIX String => prefix used to quote a literal (may be null)
  5. LITERAL_SUFFIX String => suffix used to quote a literal (may be null)
  6. CREATE_PARAMS String => parameters used in creating the type (may be null)
  7. NULLABLE short => can you use NULL for this type?
    • typeNoNulls - does not allow NULL values
    • typeNullable - allows NULL values
    • typeNullableUnknown - nullability unknown
  8. CASE_SENSITIVE boolean=> is it case sensitive?
  9. SEARCHABLE short => can you use "WHERE" based on this type:
    • typePredNone - No support
    • typePredChar - Only supported with WHERE .. LIKE
    • typePredBasic - Supported except for WHERE .. LIKE
    • typeSearchable - Supported for all WHERE ..
  10. UNSIGNED_ATTRIBUTE boolean => is it unsigned?
  11. FIXED_PREC_SCALE boolean => can it be a money value?
  12. AUTO_INCREMENT boolean => can it be used for an auto-increment value?
  13. LOCAL_TYPE_NAME String => localized version of type name (may be null)
  14. MINIMUM_SCALE short => minimum scale supported
  15. MAXIMUM_SCALE short => maximum scale supported
  16. SQL_DATA_TYPE int => unused
  17. SQL_DATETIME_SUB int => unused
  18. NUM_PREC_RADIX int => usually 2 or 10
@return ResultSet - each row is an SQL type description } function TZASADatabaseMetadata.UncachedGetTypeInfo: IZResultSet; begin Result:=inherited UncachedGetTypeInfo; with GetStatement.ExecuteQuery('exec sp_jdbc_datatype_info') do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TYPE_NAME', GetStringByName('TYPE_NAME')); Result.UpdateShortByName('DATA_TYPE', Ord(ConvertASAJDBCToSqlType(GetShortByName('DATA_TYPE'), ConSettings.CPType))); Result.UpdateIntByName('PRECISION', GetIntByName('PRECISION')); Result.UpdateStringByName('LITERAL_PREFIX', GetStringByName('LITERAL_PREFIX')); Result.UpdateStringByName('LITERAL_SUFFIX', GetStringByName('LITERAL_SUFFIX')); Result.UpdateStringByName('CREATE_PARAMS', GetStringByName('CREATE_PARAMS')); Result.UpdateShortByName('NULLABLE', GetShortByName('NULLABLE')); Result.UpdateBooleanByName('CASE_SENSITIVE', GetShortByName('CASE_SENSITIVE') = 1); Result.UpdateShortByName('SEARCHABLE', GetShortByName('SEARCHABLE')); Result.UpdateBooleanByName('UNSIGNED_ATTRIBUTE', GetShortByName('UNSIGNED_ATTRIBUTE') = 1); Result.UpdateBooleanByName('FIXED_PREC_SCALE', GetShortByName('FIXED_PREC_SCALE') = 1); Result.UpdateBooleanByName('AUTO_INCREMENT', GetShortByName('AUTO_INCREMENT') = 1); Result.UpdateStringByName('LOCAL_TYPE_NAME', GetStringByName('LOCAL_TYPE_NAME')); Result.UpdateShortByName('MINIMUM_SCALE', GetShortByName('MINIMUM_SCALE')); Result.UpdateShortByName('MAXIMUM_SCALE', GetShortByName('MAXIMUM_SCALE')); Result.UpdateShortByName('SQL_DATA_TYPE', GetShortByName('SQL_DATA_TYPE')); Result.UpdateShortByName('SQL_DATETIME_SUB', GetShortByName('SQL_DATETIME_SUB')); Result.UpdateShortByName('NUM_PREC_RADIX', GetShortByName('NUM_PREC_RADIX')); Result.InsertRow; end; Close; end; end; {** Gets a description of a table's indices and statistics. They are ordered by NON_UNIQUE, TYPE, INDEX_NAME, and ORDINAL_POSITION.

Each index column description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. NON_UNIQUE boolean => Can index values be non-unique? false when TYPE is tableIndexStatistic
  5. INDEX_QUALIFIER String => index catalog (may be null); null when TYPE is tableIndexStatistic
  6. INDEX_NAME String => index name; null when TYPE is tableIndexStatistic
  7. TYPE short => index type:
    • tableIndexStatistic - this identifies table statistics that are returned in conjuction with a table's index descriptions
    • tableIndexClustered - this is a clustered index
    • tableIndexHashed - this is a hashed index
    • tableIndexOther - this is some other style of index
  8. ORDINAL_POSITION short => column sequence number within index; zero when TYPE is tableIndexStatistic
  9. COLUMN_NAME String => column name; null when TYPE is tableIndexStatistic
  10. ASC_OR_DESC String => column sort sequence, "A" => ascending, "D" => descending, may be null if sort sequence is not supported; null when TYPE is tableIndexStatistic
  11. CARDINALITY int => When TYPE is tableIndexStatistic, then this is the number of rows in the table; otherwise, it is the number of unique values in the index.
  12. PAGES int => When TYPE is tableIndexStatisic then this is the number of pages used for the table, otherwise it is the number of pages used for the current index.
  13. FILTER_CONDITION String => Filter condition, if any. (may be null)
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @param unique when true, return only indices for unique values; when false, return indices regardless of whether unique or not @param approximate when true, result is allowed to reflect approximate or out of data values; when false, results are requested to be accurate @return ResultSet - each row is an index column description } function TZASADatabaseMetadata.UncachedGetIndexInfo(const Catalog: string; const Schema: string; const Table: string; Unique: Boolean; Approximate: Boolean): IZResultSet; var Is_Unique, Accuracy: string; begin Result:=inherited UncachedGetIndexInfo(Catalog, Schema, Table, Unique, Approximate); if Unique then Is_Unique := '''1''' else Is_Unique := '''0'''; if Approximate then Accuracy := '''1''' else Accuracy := '''0'''; with GetStatement.ExecuteQuery( Format('exec sp_jdbc_getindexinfo %s, %s, %s, %s, %s', [ComposeObjectString(Catalog), ComposeObjectString(Schema), ComposeObjectString(Table), Is_Unique, Accuracy])) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TABLE_CAT', ''); Result.UpdateStringByName('TABLE_SCHEM', GetStringByName('TABLE_SCHEM')); Result.UpdateStringByName('TABLE_NAME', GetStringByName('TABLE_NAME')); Result.UpdateBooleanByName('NON_UNIQUE', GetShortByName('NON_UNIQUE') = 1); Result.UpdateStringByName('INDEX_QUALIFIER', GetStringByName('INDEX_QUALIFIER')); Result.UpdateStringByName('INDEX_NAME', GetStringByName('INDEX_NAME')); Result.UpdateShortByName('TYPE', GetShortByName('TYPE')); Result.UpdateShortByName('ORDINAL_POSITION', GetShortByName('ORDINAL_POSITION')); Result.UpdateStringByName('COLUMN_NAME', GetStringByName('COLUMN_NAME')); Result.UpdateStringByName('ASC_OR_DESC', GetStringByName('ASC_OR_DESC')); Result.UpdateIntByName('CARDINALITY', GetIntByName('CARDINALITY')); Result.UpdateIntByName('PAGES', GetIntByName('PAGES')); Result.UpdateStringByName('FILTER_CONDITION', GetStringByName('FILTER_CONDITION')); Result.InsertRow; end; Close; end; end; {** Gets a description of the user-defined types defined in a particular schema. Schema-specific UDTs may have type JAVA_OBJECT, STRUCT, or DISTINCT.

Only types matching the catalog, schema, type name and type criteria are returned. They are ordered by DATA_TYPE, TYPE_SCHEM and TYPE_NAME. The type name parameter may be a fully-qualified name. In this case, the catalog and schemaPattern parameters are ignored.

Each type description has the following columns:

  1. TYPE_CAT String => the type's catalog (may be null)
  2. TYPE_SCHEM String => type's schema (may be null)
  3. TYPE_NAME String => type name
  4. CLASS_NAME String => Java class name
  5. DATA_TYPE String => type value defined in java.sql.Types. One of JAVA_OBJECT, STRUCT, or DISTINCT
  6. REMARKS String => explanatory comment on the type

Note: If the driver does not support UDTs, an empty result set is returned. @param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param typeNamePattern a type name pattern; may be a fully-qualified name @param types a list of user-named types to include (JAVA_OBJECT, STRUCT, or DISTINCT); null returns all types @return ResultSet - each row is a type description } function TZASADatabaseMetadata.UncachedGetUDTs(const Catalog: string; const SchemaPattern: string; const TypeNamePattern: string; const Types: TIntegerDynArray): IZResultSet; var I: Integer; UDTypes: string; begin Result:=inherited UncachedGetUDTs(Catalog, SchemaPattern, TypeNamePattern, Types); UDTypes := ''; for I := 0 to Length(Types) - 1 do begin if Length(UDTypes) > 0 then UDTypes := UDTypes + ','; UDTypes := UDTypes + AnsiQuotedStr(IntToStr(Types[I]), ''''); end; with GetStatement.ExecuteQuery( Format('exec sp_jdbc_getudts %s, %s, %s, %s', [ComposeObjectString(Catalog), ComposeObjectString(SchemaPattern, '''%'''), ComposeObjectString(TypeNamePattern, '''%'''), ComposeObjectString(UDTypes, 'null', '"')])) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TYPE_CAT', GetStringByName('TYPE_CAT')); Result.UpdateStringByName('TYPE_SCHEM', GetStringByName('TYPE_SCHEM')); Result.UpdateStringByName('TYPE_NAME', GetStringByName('TYPE_NAME')); Result.UpdateStringByName('JAVA_CLASS', GetStringByName('JAVA_CLASS')); Result.UpdateShortByName('DATA_TYPE', Ord(ConvertASAJDBCToSqlType(GetShortByName('DATA_TYPE'), ConSettings.CPType))); Result.UpdateStringByName('REMARKS', GetStringByName('REMARKS')); Result.InsertRow; end; Close; end; end; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcASAResultSet.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Interbase Database Connectivity Classes } { } { Originally written by Sergey Merkuriev } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcASAResultSet; interface {$I ZDbc.inc} uses {$IFDEF WITH_TOBJECTLIST_INLINE}System.Types, System.Contnrs{$ELSE}Types{$ENDIF}, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} ZSysUtils, ZDbcIntfs, ZDbcResultSet, ZDbcASA, ZPlainASADriver, ZCompatibility, ZDbcResultSetMetadata, ZDbcASAUtils, ZMessages, ZVariant; type {** Implements ASA ResultSet. } TZASAResultSet = class(TZAbstractResultSet) private FCachedBlob: boolean; FFetchStat: Integer; FCursorName: AnsiString; FStmtNum: SmallInt; FSqlData: IZASASQLDA; FParamsSqlData: IZASASQLDA; FUpdateSqlData: IZASASQLDA; FASAConnection: IZASAConnection; FInsert: Boolean; FUpdate: Boolean; FDelete: Boolean; protected procedure Open; override; procedure PrepareUpdateSQLData; virtual; function GetFieldValue(ColumnIndex: Integer): Variant; function InternalGetString(ColumnIndex: Integer): RawByteString; override; public constructor Create(Statement: IZStatement; SQL: string; var StmtNum: SmallInt; CursorName: AnsiString; SqlData: IZASASQLDA; ParamsSqlData: IZASASQLDA; CachedBlob: boolean); function GetCursorName: AnsiString; override; procedure Close; override; function IsNull(ColumnIndex: Integer): Boolean; override; function GetBoolean(ColumnIndex: Integer): Boolean; override; function GetByte(ColumnIndex: Integer): Byte; override; function GetShort(ColumnIndex: Integer): SmallInt; override; function GetInt(ColumnIndex: Integer): Integer; override; function GetLong(ColumnIndex: Integer): Int64; override; function GetFloat(ColumnIndex: Integer): Single; override; function GetDouble(ColumnIndex: Integer): Double; override; function GetBigDecimal(ColumnIndex: Integer): Extended; override; function GetBytes(ColumnIndex: Integer): TByteDynArray; override; function GetDate(ColumnIndex: Integer): TDateTime; override; function GetTime(ColumnIndex: Integer): TDateTime; override; function GetTimestamp(ColumnIndex: Integer): TDateTime; override; function GetBlob(ColumnIndex: Integer): IZBlob; override; function Last: Boolean; override; function MoveAbsolute(Row: Integer): Boolean; override; function MoveRelative(Rows: Integer): Boolean; override; function Previous: Boolean; override; function Next: Boolean; override; function RowUpdated: Boolean; override; function RowInserted: Boolean; override; function RowDeleted: Boolean; override; procedure UpdateNull(ColumnIndex: Integer); override; procedure UpdateBoolean(ColumnIndex: Integer; Value: Boolean); override; procedure UpdateByte(ColumnIndex: Integer; Value: ShortInt); override; procedure UpdateShort(ColumnIndex: Integer; Value: SmallInt); override; procedure UpdateInt(ColumnIndex: Integer; Value: Integer); override; procedure UpdateLong(ColumnIndex: Integer; Value: Int64); override; procedure UpdateFloat(ColumnIndex: Integer; Value: Single); override; procedure UpdateDouble(ColumnIndex: Integer; Value: Double); override; procedure UpdateBigDecimal(ColumnIndex: Integer; Value: Extended); override; procedure UpdatePChar(ColumnIndex: Integer; Value: PChar); override; procedure UpdateString(ColumnIndex: Integer; const Value: String); override; procedure UpdateUnicodeString(ColumnIndex: Integer; const Value: WideString); override; procedure UpdateBytes(ColumnIndex: Integer; const Value: TByteDynArray); override; procedure UpdateDate(ColumnIndex: Integer; Value: TDateTime); override; procedure UpdateTime(ColumnIndex: Integer; Value: TDateTime); override; procedure UpdateTimestamp(ColumnIndex: Integer; Value: TDateTime); override; procedure UpdateAsciiStream(ColumnIndex: Integer; Value: TStream); override; procedure UpdateUnicodeStream(ColumnIndex: Integer; Value: TStream); override; procedure UpdateBinaryStream(ColumnIndex: Integer; Value: TStream); override; procedure UpdateValue(ColumnIndex: Integer; const Value: TZVariant); override; procedure InsertRow; override; procedure UpdateRow; override; procedure DeleteRow; override; procedure RefreshRow; override; procedure CancelRowUpdates; override; procedure MoveToInsertRow; override; procedure MoveToCurrentRow; override; property SQLData: IZASASQLDA read FSQLData; end; IZASABlob = interface(IZBlob) ['{1E043426-5856-4953-88B8-F6FB276B7B61}'] procedure ReadBlob; end; {** Implements external blob wrapper object for PostgreSQL. } TZASABlob = class(TZAbstractBlob, IZASABlob) private FBlobRead: Boolean; FResultSet: TZASAResultSet; FColID: Integer; protected procedure ReadBlob; public constructor Create( ResultSet: TZASAResultSet; ColID: Integer); constructor CreateWithStream(Stream: TStream; Connection: IZConnection); constructor CreateWithData(Data: Pointer; Size: Integer; Connection: IZConnection); function IsEmpty: Boolean; override; function Clone: IZBlob; override; function GetStream: TStream; override; function GetString: RawByteString; override; function GetUnicodeString: WideString; override; function GetBytes: TByteDynArray; override; property BlobSize; property BlobData; end; implementation uses {$IFNDEF FPC} Variants, {$ENDIF} SysUtils, Math, ZdbcLogging, ZPlainASAConstants, ZDbcUtils, ZEncoding; { TZASAResultSet } {** Constructs this object, assignes main properties and opens the record set. @param Statement a related SQL statement object. @param handle a Interbase6 database connect handle. @param the statement previously prepared @param the sql out data previously allocated @param the Interbase sql dialect } constructor TZASAResultSet.Create(Statement: IZStatement; SQL: string; var StmtNum: SmallInt; CursorName: AnsiString; SqlData: IZASASQLDA; ParamsSqlData: IZASASQLDA; CachedBlob: boolean); begin inherited Create( Statement, SQL, nil,Statement.GetConnection.GetConSettings); FFetchStat := 0; FSqlData := SqlData; FCursorName := CursorName; FCachedBlob := CachedBlob; FASAConnection := Statement.GetConnection as IZASAConnection; FDelete := False; FInsert := False; FUpdate := False; FParamsSqlData := ParamsSqlData; FStmtNum := StmtNum; ResultSetType := rtScrollSensitive; ResultSetConcurrency := rcUpdatable; Open; end; {** Return field value by it index @param the index column 0 first, 1 second ... @return the field value as variant type } function TZASAResultSet.GetFieldValue(ColumnIndex: Integer): Variant; begin CheckClosed; if FInsert or ( FUpdate and FUpdateSQLData.IsAssigned( ColumnIndex - 1)) then Result := FUpdateSqlData.GetValue( ColumnIndex - 1) else Result := FSqlData.GetValue( ColumnIndex - 1); LastWasNull := IsNull( ColumnIndex); end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.BigDecimal in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @param scale the number of digits to the right of the decimal point @return the column value; if the value is SQL NULL, the value returned is null } function TZASAResultSet.GetBigDecimal(ColumnIndex: Integer): Extended; begin CheckClosed; CheckColumnConvertion(ColumnIndex, stBigDecimal); if FInsert or ( FUpdate and FUpdateSQLData.IsAssigned( ColumnIndex - 1)) then Result := FUpdateSqlData.GetBigDecimal( ColumnIndex - 1) else Result := FSqlData.GetBigDecimal( ColumnIndex - 1); LastWasNull := IsNull( ColumnIndex); end; {** Returns the value of the designated column in the current row of this ResultSet object as a Blob object in the Java programming language. @param ColumnIndex the first column is 1, the second is 2, ... @return a Blob object representing the SQL BLOB value in the specified column } function TZASAResultSet.GetBlob(ColumnIndex: Integer): IZBlob; var Blob: IZASABlob; TempStream: TStream; begin Result := nil; CheckClosed; CheckBlobColumn(ColumnIndex); LastWasNull := IsNull(ColumnIndex); if LastWasNull then Exit; Blob := TZASABlob.Create( Self, ColumnIndex - 1); if FCachedBlob then Blob.ReadBlob; if ( GetMetadata.GetColumnType(ColumnIndex) in [stUnicodeStream, stAsciiStream] ) then begin case GetMetaData.GetColumnType(ColumnIndex) of stAsciiStream: Blob.SetString(GetValidatedAnsiString(Blob.GetString, ConSettings, True)); else begin TempStream := GetValidatedUnicodeStream(Blob.GetBuffer, Blob.Length, ConSettings, True); Blob.SetStream(TempStream, True); TempStream.Free; end; end; end; Result := Blob; end; {** Gets the value of the designated column in the current row of this ResultSet object as a boolean in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is false } function TZASAResultSet.GetBoolean(ColumnIndex: Integer): Boolean; begin CheckClosed; CheckColumnConvertion(ColumnIndex, stBoolean); if FInsert or ( FUpdate and FUpdateSQLData.IsAssigned( ColumnIndex - 1)) then Result := FUpdateSqlData.GetBoolean( ColumnIndex - 1) else Result := FSqlData.GetBoolean( ColumnIndex - 1); LastWasNull := IsNull( ColumnIndex); end; {** Gets the value of the designated column in the current row of this ResultSet object as a byte in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZASAResultSet.GetByte(ColumnIndex: Integer): Byte; begin CheckClosed; CheckColumnConvertion(ColumnIndex, stByte); if FInsert or ( FUpdate and FUpdateSQLData.IsAssigned( ColumnIndex - 1)) then Result := FUpdateSqlData.GetByte( ColumnIndex - 1) else Result := FSqlData.GetByte( ColumnIndex - 1); LastWasNull := IsNull( ColumnIndex); end; {** Gets the value of the designated column in the current row of this ResultSet object as a byte array in the Java programming language. The bytes represent the raw values returned by the driver. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZASAResultSet.GetBytes( ColumnIndex: Integer): TByteDynArray; begin CheckClosed; CheckColumnConvertion(ColumnIndex, stBytes); if FInsert or ( FUpdate and FUpdateSQLData.IsAssigned( ColumnIndex - 1)) then Result := FUpdateSqlData.GetBytes( ColumnIndex - 1) else Result := FSqlData.GetBytes( ColumnIndex - 1); LastWasNull := IsNull( ColumnIndex); end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Date object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZASAResultSet.GetDate(ColumnIndex: Integer): TDateTime; begin CheckClosed; CheckColumnConvertion(ColumnIndex, stDate); if FInsert or ( FUpdate and FUpdateSQLData.IsAssigned( ColumnIndex - 1)) then Result := FUpdateSqlData.GetDate( ColumnIndex - 1) else Result := FSqlData.GetDate( ColumnIndex - 1); LastWasNull := IsNull( ColumnIndex); end; {** Gets the value of the designated column in the current row of this ResultSet object as a double in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZASAResultSet.GetDouble(ColumnIndex: Integer): Double; begin CheckClosed; CheckColumnConvertion(ColumnIndex, stDouble); if FInsert or ( FUpdate and FUpdateSQLData.IsAssigned( ColumnIndex - 1)) then Result := FUpdateSqlData.GetDouble( ColumnIndex - 1) else Result := FSqlData.GetDouble( ColumnIndex - 1); LastWasNull := IsNull( ColumnIndex); end; {** Gets the value of the designated column in the current row of this ResultSet object as a float in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZASAResultSet.GetFloat(ColumnIndex: Integer): Single; begin CheckClosed; CheckColumnConvertion(ColumnIndex, stFloat); if FInsert or ( FUpdate and FUpdateSQLData.IsAssigned( ColumnIndex - 1)) then Result := FUpdateSqlData.GetFloat( ColumnIndex - 1) else Result := FSqlData.GetFloat( ColumnIndex - 1); LastWasNull := IsNull( ColumnIndex); end; {** Gets the value of the designated column in the current row of this ResultSet object as an int in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZASAResultSet.GetInt(ColumnIndex: Integer): Integer; begin CheckClosed; CheckColumnConvertion(ColumnIndex, stInteger); if FInsert or ( FUpdate and FUpdateSQLData.IsAssigned( ColumnIndex - 1)) then Result := FUpdateSqlData.GetInt( ColumnIndex - 1) else Result := FSqlData.GetInt( ColumnIndex - 1); LastWasNull := IsNull( ColumnIndex); end; {** Gets the value of the designated column in the current row of this ResultSet object as a long in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZASAResultSet.GetLong(ColumnIndex: Integer): Int64; begin CheckClosed; CheckColumnConvertion(ColumnIndex, stLong); if FInsert or ( FUpdate and FUpdateSQLData.IsAssigned( ColumnIndex - 1)) then Result := FUpdateSqlData.GetLong( ColumnIndex - 1) else Result := FSqlData.GetLong( ColumnIndex - 1); LastWasNull := IsNull( ColumnIndex); end; {** Gets the value of the designated column in the current row of this ResultSet object as a short in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZASAResultSet.GetShort(ColumnIndex: Integer): SmallInt; begin CheckClosed; CheckColumnConvertion(ColumnIndex, stShort); if FInsert or ( FUpdate and FUpdateSQLData.IsAssigned( ColumnIndex - 1)) then Result := FUpdateSqlData.GetShort( ColumnIndex - 1) else Result := FSqlData.GetShort( ColumnIndex - 1); LastWasNull := IsNull( ColumnIndex); end; {** Gets the value of the designated column in the current row of this ResultSet object as a String in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZASAResultSet.InternalGetString(ColumnIndex: Integer): RawByteString; begin CheckClosed; CheckColumnConvertion( ColumnIndex, stString); if FInsert or ( FUpdate and FUpdateSQLData.IsAssigned( ColumnIndex - 1)) then Result := FUpdateSqlData.GetString( ColumnIndex - 1) else Result := FSqlData.GetString( ColumnIndex - 1); LastWasNull := IsNull( ColumnIndex); end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Time object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZASAResultSet.GetTime(ColumnIndex: Integer): TDateTime; begin CheckClosed; CheckColumnConvertion(ColumnIndex, stTime); if FInsert or ( FUpdate and FUpdateSQLData.IsAssigned( ColumnIndex - 1)) then Result := FUpdateSqlData.GetTime( ColumnIndex - 1) else Result := FSqlData.GetTime( ColumnIndex - 1); LastWasNull := IsNull( ColumnIndex); end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null @exception SQLException if a database access error occurs } function TZASAResultSet.GetTimestamp(ColumnIndex: Integer): TDateTime; begin CheckClosed; CheckColumnConvertion(ColumnIndex, stTimestamp); if FInsert or ( FUpdate and FUpdateSQLData.IsAssigned( ColumnIndex - 1)) then Result := FUpdateSqlData.GetTimestamp( ColumnIndex - 1) else Result := FSqlData.GetTimestamp( ColumnIndex - 1); LastWasNull := IsNull( ColumnIndex); end; {** Indicates if the value of the designated column in the current row of this ResultSet object is Null. @param columnIndex the first column is 1, the second is 2, ... @return if the value is SQL NULL, the value returned is true. false otherwise. } function TZASAResultSet.IsNull(ColumnIndex: Integer): Boolean; begin CheckClosed; if FInsert or ( FUpdate and FUpdateSQLData.IsAssigned( ColumnIndex - 1)) then Result := FUpdateSqlData.IsNull( ColumnIndex - 1) else Result := FSqlData.IsNull(ColumnIndex - 1); end; function TZASAResultSet.Last: Boolean; begin if LastRowNo <> MaxInt then Result := MoveAbsolute( LastRowNo) else Result := MoveAbsolute( -1); end; {** Moves the cursor to the given row number in this ResultSet object.

If the row number is positive, the cursor moves to the given row number with respect to the beginning of the result set. The first row is row 1, the second is row 2, and so on.

If the given row number is negative, the cursor moves to an absolute row position with respect to the end of the result set. For example, calling the method absolute(-1) positions the cursor on the last row; calling the method absolute(-2) moves the cursor to the next-to-last row, and so on.

An attempt to position the cursor beyond the first/last row in the result set leaves the cursor before the first row or after the last row.

Note: Calling absolute(1) is the same as calling first(). Calling absolute(-1) is the same as calling last(). @return true if the cursor is on the result set; false otherwise } function TZASAResultSet.MoveAbsolute(Row: Integer): Boolean; begin Result := False; if (MaxRows > 0) and (Row >= MaxRows) then Exit; FASAConnection.GetPlainDriver.db_fetch( FASAConnection.GetDBHandle, PAnsiChar(FCursorName), CUR_ABSOLUTE, Row, FSqlData.GetData, BlockSize, CUR_FORREGULAR); ZDbcASAUtils.CheckASAError( FASAConnection.GetPlainDriver, FASAConnection.GetDBHandle, lcOther); if FASAConnection.GetDBHandle.sqlCode <> SQLE_NOTFOUND then begin RowNo := Row; Result := True; FFetchStat := 0; FDelete := False; FInsert := False; FUpdate := False; end else begin FFetchStat := FASAConnection.GetDBHandle.sqlerrd[2]; if FFetchStat > 0 then LastRowNo := Max( Row - FFetchStat, 0); end; end; function TZASAResultSet.MoveRelative(Rows: Integer): Boolean; begin Result := False; if (RowNo > LastRowNo) or ((MaxRows > 0) and (RowNo >= MaxRows)) then Exit; FASAConnection.GetPlainDriver.db_fetch( FASAConnection.GetDBHandle, PAnsiChar( FCursorName), CUR_RELATIVE, Rows, FSqlData.GetData, BlockSize, CUR_FORREGULAR); ZDbcASAUtils.CheckASAError( FASAConnection.GetPlainDriver, FASAConnection.GetDBHandle, lcOther, '', SQLE_CURSOR_NOT_OPEN); //handle a known null resultset issue (cursor not open) if FASAConnection.GetDBHandle.sqlCode = SQLE_CURSOR_NOT_OPEN then Exit; if FASAConnection.GetDBHandle.sqlCode <> SQLE_NOTFOUND then begin if ( RowNo > 0) or ( RowNo + Rows < 0) then RowNo := RowNo + Rows; Result := True; FFetchStat := 0; FDelete := False; FInsert := False; FUpdate := False; end else begin FFetchStat := FASAConnection.GetDBHandle.sqlerrd[2]; if ( FFetchStat > 0) and ( RowNo > 0) then LastRowNo := Max( RowNo + Rows - FFetchStat, 0); end; end; function TZASAResultSet.Previous: Boolean; begin Result := MoveRelative( -1); end; {** Moves the cursor down one row from its current position. A ResultSet cursor is initially positioned before the first row; the first call to the method next makes the first row the current row; the second call makes the second row the current row, and so on.

If an input stream is open for the current row, a call to the method next will implicitly close it. A ResultSet object's warning chain is cleared when a new row is read. @return true if the new current row is valid; false if there are no more rows } function TZASAResultSet.Next: Boolean; begin Result := MoveRelative( 1); end; {** Opens this recordset. } procedure TZASAResultSet.Open; var i: Integer; FieldSqlType: TZSQLType; ColumnInfo: TZColumnInfo; begin if FStmtNum = 0 then raise EZSQLException.Create(SCanNotRetrieveResultSetData); ColumnsInfo.Clear; for i := 0 to FSqlData.GetFieldCount - 1 do begin ColumnInfo := TZColumnInfo.Create; with ColumnInfo, FSqlData do begin FieldSqlType := GetFieldSqlType(I); ColumnName := GetFieldName(I); // TableName := GetFieldRelationName(I); ColumnLabel := ColumnName; ColumnType := FieldSqlType; case FieldSqlType of stString, stUnicodeString: Precision := GetFieldSize(FieldSqlType, ConSettings, GetFieldLength(I)-4, ConSettings.ClientCodePage.CharWidth, @ColumnDisplaySize, True); end; ReadOnly := False; if IsNullable(I) then Nullable := ntNullable else Nullable := ntNoNulls; Nullable := ntNullable; Scale := GetFieldScale(I); AutoIncrement := False; //Signed := False; CaseSensitive := False; end; ColumnsInfo.Add(ColumnInfo); end; LastRowNo := MaxInt; inherited Open; end; procedure TZASAResultSet.Close; begin FSqlData := nil; FParamsSqlData := nil; FUpdateSqlData := nil; if FCursorName <> '' then begin FASAConnection.GetPlainDriver.db_close(FASAConnection.GetDBHandle, PAnsiChar(FCursorName)); FCursorName := ''; end; inherited Close; end; function TZASAResultSet.GetCursorName: AnsiString; begin Result := FCursorName; end; function TZASAResultSet.RowUpdated: Boolean; begin Result := FUpdate; end; function TZASAResultSet.RowInserted: Boolean; begin Result := FInsert; end; function TZASAResultSet.RowDeleted: Boolean; begin Result := FDelete; end; procedure TZASAResultSet.PrepareUpdateSQLData; begin FUpdate := not FInsert; if not Assigned( FUpdateSQLData) then begin FUpdateSQLData := TZASASQLDA.Create( FASAConnection.GetPlainDriver, FASAConnection.GetDBHandle, FCursorName, ConSettings, FSQLData.GetFieldCount); end else if FUpdateSQLData.GetFieldCount = 0 then FUpdateSQLData.AllocateSQLDA( FSQLData.GetFieldCount); end; procedure TZASAResultSet.UpdateNull(ColumnIndex: Integer); begin PrepareUpdateSQLData; FUpdateSqlData.UpdateNull( ColumnIndex, True); end; procedure TZASAResultSet.UpdateBoolean(ColumnIndex: Integer; Value: Boolean); begin PrepareUpdateSQLData; FUpdateSqlData.UpdateBoolean( ColumnIndex, Value); end; procedure TZASAResultSet.UpdateByte(ColumnIndex: Integer; Value: ShortInt); begin PrepareUpdateSQLData; FUpdateSqlData.UpdateByte( ColumnIndex, Value); end; procedure TZASAResultSet.UpdateShort(ColumnIndex: Integer; Value: SmallInt); begin PrepareUpdateSQLData; FUpdateSqlData.UpdateShort( ColumnIndex, Value); end; procedure TZASAResultSet.UpdateInt(ColumnIndex: Integer; Value: Integer); begin PrepareUpdateSQLData; FUpdateSqlData.UpdateInt( ColumnIndex, Value); end; procedure TZASAResultSet.UpdateLong(ColumnIndex: Integer; Value: Int64); begin PrepareUpdateSQLData; FUpdateSqlData.UpdateLong( ColumnIndex, Value); end; procedure TZASAResultSet.UpdateFloat(ColumnIndex: Integer; Value: Single); begin PrepareUpdateSQLData; FUpdateSqlData.UpdateFloat( ColumnIndex, Value); end; procedure TZASAResultSet.UpdateDouble(ColumnIndex: Integer; Value: Double); begin PrepareUpdateSQLData; FUpdateSqlData.UpdateDouble( ColumnIndex, Value); end; procedure TZASAResultSet.UpdateBigDecimal(ColumnIndex: Integer; Value: Extended); begin PrepareUpdateSQLData; FUpdateSqlData.UpdateBigDecimal( ColumnIndex, Value); end; procedure TZASAResultSet.UpdatePChar(ColumnIndex: Integer; Value: PChar); begin PrepareUpdateSQLData; FUpdateSqlData.UpdatePChar( ColumnIndex, Value); end; procedure TZASAResultSet.UpdateString(ColumnIndex: Integer; const Value: String); begin PrepareUpdateSQLData; FUpdateSqlData.UpdateString(ColumnIndex, ZPlainString(Value)); end; procedure TZASAResultSet.UpdateUnicodeString(ColumnIndex: Integer; const Value: WideString); begin PrepareUpdateSQLData; FUpdateSqlData.UpdateString(ColumnIndex, ZPlainString(Value)); end; procedure TZASAResultSet.UpdateBytes(ColumnIndex: Integer; const Value: TByteDynArray); begin PrepareUpdateSQLData; FUpdateSqlData.UpdateBytes( ColumnIndex, Value); end; procedure TZASAResultSet.UpdateDate(ColumnIndex: Integer; Value: TDateTime); begin PrepareUpdateSQLData; FUpdateSqlData.UpdateDate( ColumnIndex, Value); end; procedure TZASAResultSet.UpdateTime(ColumnIndex: Integer; Value: TDateTime); begin PrepareUpdateSQLData; FUpdateSqlData.UpdateTime( ColumnIndex, Value); end; procedure TZASAResultSet.UpdateTimestamp(ColumnIndex: Integer; Value: TDateTime); begin PrepareUpdateSQLData; FUpdateSqlData.UpdateTimestamp( ColumnIndex, Value); end; procedure TZASAResultSet.UpdateAsciiStream(ColumnIndex: Integer; Value: TStream); begin PrepareUpdateSQLData; FUpdateSqlData.WriteBlob( ColumnIndex, Value, stAsciiStream); end; procedure TZASAResultSet.UpdateUnicodeStream(ColumnIndex: Integer; Value: TStream); begin PrepareUpdateSQLData; FUpdateSqlData.WriteBlob( ColumnIndex, Value, stUnicodeStream); end; procedure TZASAResultSet.UpdateBinaryStream(ColumnIndex: Integer; Value: TStream); begin PrepareUpdateSQLData; FUpdateSqlData.WriteBlob( ColumnIndex, Value, stBinaryStream); end; procedure TZASAResultSet.UpdateValue(ColumnIndex: Integer; const Value: TZVariant); begin PrepareUpdateSQLData; FUpdateSqlData.UpdateValue( ColumnIndex, EncodeVariant( Value)); end; procedure TZASAResultSet.InsertRow; begin if Assigned( FUpdateSQLData) and FInsert then begin FASAConnection.GetPlainDriver.db_put_into( FASAConnection.GetDBHandle, PAnsiChar(FCursorName), FUpdateSQLData.GetData, FSQLData.GetData); ZDbcASAUtils.CheckASAError( FASAConnection.GetPlainDriver, FASAConnection.GetDBHandle, lcOther, 'Insert row'); FInsert := false; FUpdateSQLData.FreeSQLDA; end; end; procedure TZASAResultSet.UpdateRow; begin if Assigned( FUpdateSQLData) and FUpdate then begin FASAConnection.GetPlainDriver.db_update( FASAConnection.GetDBHandle, PAnsiChar(FCursorName), FUpdateSQLData.GetData); ZDbcASAUtils.CheckASAError( FASAConnection.GetPlainDriver, FASAConnection.GetDBHandle, lcOther, 'Update row:' + IntToStr( RowNo)); FUpdate := false; FUpdateSQLData.FreeSQLDA; end; end; procedure TZASAResultSet.DeleteRow; begin FASAConnection.GetPlainDriver.db_delete( FASAConnection.GetDBHandle, PAnsiChar(FCursorName)); ZDbcASAUtils.CheckASAError( FASAConnection.GetPlainDriver, FASAConnection.GetDBHandle, lcOther, 'Delete row:' + IntToStr( RowNo)); FDelete := True; if LastRowNo <> MaxInt then LastRowNo := LastRowNo - FASAConnection.GetDBHandle.sqlerrd[2]; end; procedure TZASAResultSet.RefreshRow; begin MoveRelative( 0); end; procedure TZASAResultSet.CancelRowUpdates; begin FUpdate := false; if Assigned( FUpdateSQLData) then FUpdateSQLData.FreeSQLDA; end; procedure TZASAResultSet.MoveToInsertRow; begin FInsert := true; end; procedure TZASAResultSet.MoveToCurrentRow; begin FInsert := false; if Assigned( FUpdateSQLData) then FUpdateSQLData.FreeSQLDA; end; { TZASABlob } function TZASABlob.Clone: IZBlob; var Dt: Pointer; begin Dt := nil; if BlobSize > 0 then begin GetMem( Dt, BlobSize); System.Move( BlobData^, Dt^, BlobSize); end; Result := TZASABlob.CreateWithData( Dt, BlobSize, FConnection); end; {** Reads the blob information by blob handle. @param handle a Interbase6 database connect handle. @param the statement previously prepared } constructor TZASABlob.Create( ResultSet: TZASAResultSet; ColID: Integer); begin inherited Create; FConnection := ResultSet.GetStatement.GetConnection; FBlobRead := False; FResultSet := ResultSet; FColID := ColID; end; constructor TZASABlob.CreateWithStream(Stream: TStream; Connection: IZConnection); begin inherited CreateWithStream(Stream, Connection); FBlobRead := true; end; constructor TZASABlob.CreateWithData(Data: Pointer; Size: Integer; Connection: IZConnection); begin inherited Create; FConnection := Connection; BlobData := Data; BlobSize := Size; Updated := False; FBlobRead := true; end; function TZASABlob.GetBytes: TByteDynArray; begin ReadBlob; Result := inherited GetBytes; end; function TZASABlob.GetStream: TStream; begin ReadBlob; Result := inherited GetStream; end; function TZASABlob.GetString: RawByteString; begin ReadBlob; Result := inherited GetString; end; function TZASABlob.GetUnicodeString: WideString; begin Result := inherited GetUnicodeString; end; function TZASABlob.IsEmpty: Boolean; begin ReadBlob; Result := inherited IsEmpty; end; procedure TZASABlob.ReadBlob; var Size: LongWord; Buffer: Pointer; begin if FBlobRead then Exit; if Assigned(BlobData) then FreeMem(BlobData); if FResultSet.FInsert or ( FResultSet.FUpdate and FResultSet.FUpdateSQLData.IsAssigned( FColID)) then FResultSet.FUpdateSQLData.ReadBlobToMem( FColID, Buffer, Size) else FResultSet.FSQLData.ReadBlobToMem( FColID, Buffer, Size); BlobSize := Size; BlobData := Buffer; FBlobRead := True; end; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcASAStatement.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Interbase Database Connectivity Classes } { } { Originally written by Sergey Merkuriev } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcASAStatement; interface {$I ZDbc.inc} uses Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, ZDbcIntfs, ZDbcStatement, ZDbcASA, ZDbcASAUtils, ZDbcASAResultSet, ZPlainASADriver, ZCompatibility, ZDbcLogging, ZVariant, ZMessages; type {** Implements Generic ASA Statement. } TZASAStatement = class(TZAbstractStatement) private FCachedBlob: Boolean; FStmtNum: SmallInt; FASAConnection: IZASAConnection; FSQLData: IZASASQLDA; FMoreResults: Boolean; function InternalExecuteQuery(const SQL: RawByteString): IZResultSet; public constructor Create(Connection: IZConnection; Info: TStrings); destructor Destroy; override; procedure Close; override; procedure Cancel; override; function GetWarnings: EZSQLWarning; override; procedure ClearWarnings; override; function GetMoreResults: Boolean; override; function ExecuteQuery(const SQL: RawByteString): IZResultSet; override; function ExecuteUpdate(const SQL: RawByteString): Integer; override; function Execute(const SQL: RawByteString): Boolean; override; end; {** Implements Prepared SQL Statement. } TZASAPreparedStatement = class(TZAbstractPreparedStatement) private FCachedBlob: boolean; FStmtNum: SmallInt; FASAConnection: IZASAConnection; FParamSQLData: IZASASQLDA; FSQLData: IZASASQLDA; FMoreResults: Boolean; FPrepared: Boolean; public constructor Create(Connection: IZConnection; const SQL: string; Info: TStrings); destructor Destroy; override; procedure Close; override; procedure Cancel; override; function GetWarnings: EZSQLWarning; override; procedure ClearWarnings; override; function GetMoreResults: Boolean; override; function ExecuteQuery(const SQL: RawByteString): IZResultSet; override; function ExecuteUpdate(const SQL: RawByteString): Integer; override; function Execute(const SQL: RawByteString): Boolean; override; function ExecuteQueryPrepared: IZResultSet; override; function ExecuteUpdatePrepared: Integer; override; function ExecutePrepared: Boolean; override; end; TZASACallableStatement = class(TZAbstractCallableStatement) private FCachedBlob: boolean; FStmtNum: SmallInt; FASAConnection: IZASAConnection; FParamSQLData: IZASASQLDA; FSQLData: IZASASQLDA; FMoreResults: Boolean; FPrepared: Boolean; protected procedure FetchOutParams( Value: IZASASQLDA); function GetProcedureSQL: RawByteString; public constructor Create(Connection: IZConnection; const SQL: string; Info: TStrings); destructor Destroy; override; procedure Close; override; procedure Cancel; override; function GetWarnings: EZSQLWarning; override; procedure ClearWarnings; override; function GetMoreResults: Boolean; override; function ExecuteQuery(const SQL: RawByteString): IZResultSet; override; function ExecuteUpdate(const SQL: RawByteString): Integer; override; function Execute(const SQL: RawByteString): Boolean; override; function ExecuteQueryPrepared: IZResultSet; override; function ExecuteUpdatePrepared: Integer; override; function ExecutePrepared: Boolean; override; end; implementation uses ZSysUtils, ZDbcUtils, ZPlainASAConstants; { TZASAStatement } function TZASAStatement.InternalExecuteQuery(const SQL: RawByteString): IZResultSet; var Cursor: AnsiString; CursorOptions: SmallInt; begin Close; with FASAConnection do begin try GetPlainDriver.db_prepare_describe( GetDBHandle, nil, @FStmtNum, PAnsiChar(ASQL), FSQLData.GetData, SQL_PREPARE_DESCRIBE_STMTNUM + SQL_PREPARE_DESCRIBE_OUTPUT + SQL_PREPARE_DESCRIBE_VARRESULT, 0); ZDbcASAUtils.CheckASAError(GetPlainDriver, GetDBHandle, lcExecute, LogSQL); FMoreResults := GetDBHandle.sqlerrd[2] = 0; if not FMoreResults then begin if FSQLData.GetData^.sqld <= 0 then begin Result := nil; Exit; end else if ( FSQLData.GetData^.sqld > FSQLData.GetData^.sqln) then begin FSQLData.AllocateSQLDA( FSQLData.GetData^.sqld); GetPlainDriver.db_describe( GetDBHandle, nil, @FStmtNum, FSQLData.GetData, SQL_DESCRIBE_OUTPUT); ZDbcASAUtils.CheckASAError( GetPlainDriver, GetDBHandle, lcExecute, LogSQL); end; FSQLData.InitFields; end; if ResultSetConcurrency = rcUpdatable then CursorOptions := CUR_OPEN_DECLARE + CUR_UPDATE else CursorOptions := CUR_OPEN_DECLARE + CUR_READONLY; if ResultSetType = rtScrollInsensitive then CursorOptions := CursorOptions + CUR_INSENSITIVE; Cursor := CursorName; GetPlainDriver.db_open(GetDBHandle, PAnsiChar(Cursor), nil, @FStmtNum, nil, FetchSize, 0, CursorOptions); ZDbcASAUtils.CheckASAError( GetPlainDriver, GetDBHandle, lcExecute, LogSQL); Closed := false; if FMoreResults then DescribeCursor( FASAConnection, FSQLData, Cursor, LogSQL); LastUpdateCount := -1; Result := GetCachedResultSet( LogSQL, Self, TZASAResultSet.Create( Self, LogSQL, FStmtNum, Cursor, FSQLData, nil, FCachedBlob)); { Logging SQL Command } DriverManager.LogMessage( lcExecute, GetPlainDriver.GetProtocol, LogSQL); except on E: Exception do begin Self.Close; raise; end; end; end; end; {** Constructs this object and assignes the main properties. @param Connection a database connection object. @param Handle a connection handle pointer. @param Dialect a dialect Interbase SQL must be 1 or 2 or 3. @param Info a statement parameters. } constructor TZASAStatement.Create(Connection: IZConnection; Info: TStrings); begin inherited Create(Connection, Info); FASAConnection := Connection as IZASAConnection; FetchSize := BlockSize; ResultSetConcurrency := rcUpdatable; ResultSetType := rtScrollSensitive; FCachedBlob := StrToBoolEx(DefineStatementParameter(Self, 'cashedblob', 'true')); CursorName := AnsiString(RandomString(12)); FSQLData := TZASASQLDA.Create( FASAConnection.GetPlainDriver, FASAConnection.GetDBHandle, CursorName, ConSettings); end; destructor TZASAStatement.Destroy; begin FSQLData := nil; inherited; end; procedure TZASAStatement.Close; begin if not Closed then begin FASAConnection.GetPlainDriver.db_close(FASAConnection.GetDBHandle, PAnsiChar(CursorName)); Closed := false; end; if FStmtNum <> 0 then begin FASAConnection.GetPlainDriver.db_dropstmt( FASAConnection.GetDBHandle, nil, nil, @FStmtNum); FStmtNum := 0; end; inherited; end; procedure TZASAStatement.Cancel; begin with FASAConnection do begin GetPlainDriver.db_cancel_request( GetDBHandle); ZDbcASAUtils.CheckASAError( GetPlainDriver, GetDBHandle, lcExecute); end; end; function TZASAStatement.GetWarnings: EZSQLWarning; begin Result := inherited GetWarnings; end; procedure TZASAStatement.ClearWarnings; begin inherited; end; function TZASAStatement.GetMoreResults: Boolean; var SQLData: IZASASQLDA; begin Result := FMoreResults; if FMoreResults then begin with FASAConnection do begin GetPlainDriver.db_resume(GetDBHandle, PAnsiChar(CursorName)); ZDbcASAUtils.CheckASAError( GetPlainDriver, GetDBHandle, lcExecute); if GetDBHandle.sqlcode = SQLE_PROCEDURE_COMPLETE then Result := false else begin SQLData := TZASAResultSet(LastResultSet).SQLData; DescribeCursor( FASAConnection, TZASASQLDA( SQLData), CursorName, ''); end; end; end; end; {** Executes an SQL statement that returns a single ResultSet object. @param sql typically this is a static SQL SELECT statement @return a ResultSet object that contains the data produced by the given query; never null } function TZASAStatement.ExecuteQuery(const SQL: RawByteString): IZResultSet; begin ASQL := SQL; Result := InternalExecuteQuery(ASQL); if Result = nil then raise EZSQLException.Create( SCanNotRetrieveResultSetData) end; {** Executes an SQL INSERT, UPDATE or DELETE statement. In addition, SQL statements that return nothing, such as SQL DDL statements, can be executed. @param sql an SQL INSERT, UPDATE or DELETE statement or an SQL statement that returns nothing @return either the row count for INSERT, UPDATE or DELETE statements, or 0 for SQL statements that return nothing } {$HINTS OFF} function TZASAStatement.ExecuteUpdate(const SQL: RawByteString): Integer; begin ASQL := SQL; Close; Result := -1; with FASAConnection do begin GetPlainDriver.db_execute_imm(GetDBHandle, PAnsiChar(ASQL)); ZDbcASAUtils.CheckASAError( GetPlainDriver, GetDBHandle, lcExecute, LogSQL); Result := GetDBHandle.sqlErrd[2]; LastUpdateCount := Result; { Logging SQL Command } DriverManager.LogMessage(lcExecute, GetPlainDriver.GetProtocol, LogSQL); end; end; {$HINTS ON} {** Executes an SQL statement that may return multiple results. Under some (uncommon) situations a single SQL statement may return multiple result sets and/or update counts. Normally you can ignore this unless you are (1) executing a stored procedure that you know may return multiple results or (2) you are dynamically executing an unknown SQL string. The methods execute, getMoreResults, getResultSet, and getUpdateCount let you navigate through multiple results. The execute method executes an SQL statement and indicates the form of the first result. You can then use the methods getResultSet or getUpdateCount to retrieve the result, and getMoreResults to move to any subsequent result(s). @param sql any SQL statement @return true if the next result is a ResultSet object; false if it is an update count or there are no more results @see #getResultSet @see #getUpdateCount @see #getMoreResults } function TZASAStatement.Execute(const SQL: RawByteString): Boolean; begin ASQL := SQL; LastResultSet := InternalExecuteQuery(ASQL); Result := Assigned(LastResultSet); if not Result then ExecuteUpdate(ASQL); end; { TZASAPreparedStatement } {** Constructs this object and assignes the main properties. @param Connection a database connection object. @param Handle a connection handle pointer. @param Dialect a dialect Interbase SQL must be 1 or 2 or 3. @param Info a statement parameters. } constructor TZASAPreparedStatement.Create(Connection: IZConnection; const SQL: string; Info: TStrings); begin inherited Create(Connection, SQL, Info); FASAConnection := Connection as IZASAConnection; FetchSize := BlockSize; ResultSetConcurrency := rcUpdatable; ResultSetType := rtScrollSensitive; FCachedBlob := StrToBoolEx(DefineStatementParameter(Self, 'cashedblob', 'true')); CursorName := AnsiString(RandomString(12)); FParamSQLData := TZASASQLDA.Create( FASAConnection.GetPlainDriver, FASAConnection.GetDBHandle, CursorName, ConSettings); FSQLData := TZASASQLDA.Create( FASAConnection.GetPlainDriver, FASAConnection.GetDBHandle, CursorName, ConSettings); ASAPrepare( FASAConnection, FSQLData, FParamSQLData, ASQL, LogSQL, @FStmtNum, FPrepared, FMoreResults); end; destructor TZASAPreparedStatement.Destroy; begin FSQLData := nil; FParamSQLData := nil; inherited; end; procedure TZASAPreparedStatement.Close; begin if not Closed then begin FASAConnection.GetPlainDriver.db_close( FASAConnection.GetDBHandle, PAnsiChar(CursorName)); Closed := false; end; if FStmtNum <> 0 then begin FASAConnection.GetPlainDriver.db_dropstmt( FASAConnection.GetDBHandle, nil, nil, @FStmtNum); FStmtNum := 0; end; inherited; end; procedure TZASAPreparedStatement.Cancel; begin with FASAConnection do begin GetPlainDriver.db_cancel_request( GetDBHandle); ZDbcASAUtils.CheckASAError( GetPlainDriver, GetDBHandle, lcExecute, SQL); end; end; function TZASAPreparedStatement.GetWarnings: EZSQLWarning; begin Result := inherited GetWarnings; end; procedure TZASAPreparedStatement.ClearWarnings; begin inherited; end; function TZASAPreparedStatement.GetMoreResults: Boolean; begin Result := FMoreResults; if FMoreResults then begin with FASAConnection do begin GetPlainDriver.db_resume(GetDBHandle, PAnsiChar(CursorName)); ZDbcASAUtils.CheckASAError( GetPlainDriver, GetDBHandle, lcExecute); if GetDBHandle.sqlcode = SQLE_PROCEDURE_COMPLETE then Result := false else DescribeCursor( FASAConnection, TZASASQLDA( FSQLData), CursorName, ''); end; end; end; {** Executes an SQL statement that may return multiple results. Under some (uncommon) situations a single SQL statement may return multiple result sets and/or update counts. Normally you can ignore this unless you are (1) executing a stored procedure that you know may return multiple results or (2) you are dynamically executing an unknown SQL string. The methods execute, getMoreResults, getResultSet, and getUpdateCount let you navigate through multiple results. The execute method executes an SQL statement and indicates the form of the first result. You can then use the methods getResultSet or getUpdateCount to retrieve the result, and getMoreResults to move to any subsequent result(s). @param sql any SQL statement @return true if the next result is a ResultSet object; false if it is an update count or there are no more results @see #getResultSet @see #getUpdateCount @see #getMoreResults } function TZASAPreparedStatement.Execute(const SQL: RawByteString): Boolean; begin if ASQL <> SQL then begin Close; ASQL := SQL; ASAPrepare( FASAConnection, FSQLData, FParamSQLData, ASQL, LogSQL, @FStmtNum, FPrepared, FMoreResults); end; Result := ExecutePrepared; end; {** Executes any kind of SQL statement. Some prepared statements return multiple results; the execute method handles these complex statements as well as the simpler form of statements handled by the methods executeQuery and executeUpdate. @see Statement#execute } function TZASAPreparedStatement.ExecutePrepared: Boolean; begin if FMoreResults or ( FSQLData.GetData.sqld > 0) then begin LastResultSet := ExecuteQueryPrepared; Result := true; end else begin ExecuteUpdatePrepared; Result := false; end; end; {** Executes an SQL statement that returns a single ResultSet object. @param sql typically this is a static SQL SELECT statement @return a ResultSet object that contains the data produced by the given query; never null } function TZASAPreparedStatement.ExecuteQuery(const SQL: RawByteString): IZResultSet; begin if ASQL <> SQL then begin Close; ASQL := SQL; ASAPrepare( FASAConnection, FSQLData, FParamSQLData, ASQL, LogSQL, @FStmtNum, FPrepared, FMoreResults); end; Result := ExecuteQueryPrepared; end; {** Executes the SQL query in this PreparedStatement object and returns the result set generated by the query. @return a ResultSet object that contains the data produced by the query; never null } {$HINTS OFF} function TZASAPreparedStatement.ExecuteQueryPrepared: IZResultSet; var Cursor: AnsiString; CursorOptions: SmallInt; begin with FASAConnection do begin PrepareParameters( GetPlainDriver, InParamValues, InParamTypes, InParamCount, FParamSQLData, FASAConnection.GetConSettings); if ResultSetConcurrency = rcUpdatable then CursorOptions := CUR_OPEN_DECLARE + CUR_UPDATE else CursorOptions := CUR_OPEN_DECLARE + CUR_READONLY; if ResultSetType = rtScrollInsensitive then CursorOptions := CursorOptions + CUR_INSENSITIVE; Cursor := CursorName; GetPlainDriver.db_open(GetDBHandle, PAnsiChar(Cursor), nil, @FStmtNum, FParamSQLData.GetData, FetchSize, 0, CursorOptions); ZDbcASAUtils.CheckASAError( GetPlainDriver, GetDBHandle, lcExecute, SQL); Closed := false; try if FMoreResults then DescribeCursor( FASAConnection, TZASASQLDA( FSQLData), Cursor, ''); LastUpdateCount := -1; Result := GetCachedResultSet( SQL, Self, TZASAResultSet.Create( Self, SQL, FStmtNum, Cursor, FSQLData, nil, FCachedBlob)); { Logging SQL Command } DriverManager.LogMessage( lcExecute, GetPlainDriver.GetProtocol, LogSQL); except on E: Exception do begin Self.Close; raise; end; end; end; end; {$HINTS ON} {** Executes an SQL INSERT, UPDATE or DELETE statement. In addition, SQL statements that return nothing, such as SQL DDL statements, can be executed. @param sql an SQL INSERT, UPDATE or DELETE statement or an SQL statement that returns nothing @return either the row count for INSERT, UPDATE or DELETE statements, or 0 for SQL statements that return nothing } function TZASAPreparedStatement.ExecuteUpdate(const SQL: RawByteString): Integer; begin if ASQL <> SQL then begin Close; ASQL := SQL; ASAPrepare( FASAConnection, FSQLData, FParamSQLData, ASQL, LogSQL, @FStmtNum, FPrepared, FMoreResults); end; Result := ExecuteUpdatePrepared; end; {** Executes the SQL INSERT, UPDATE or DELETE statement in this PreparedStatement object. In addition, SQL statements that return nothing, such as SQL DDL statements, can be executed. @return either the row count for INSERT, UPDATE or DELETE statements; or 0 for SQL statements that return nothing } {$HINTS OFF} function TZASAPreparedStatement.ExecuteUpdatePrepared: Integer; begin Result := -1; with FASAConnection do begin PrepareParameters( GetPlainDriver, InParamValues, InParamTypes, InParamCount, FParamSQLData, FASAConnection.GetConSettings); GetPlainDriver.db_execute_into( GetDBHandle, nil, nil, @FStmtNum, FParamSQLData.GetData, nil); ZDbcASAUtils.CheckASAError( GetPlainDriver, GetDBHandle, lcExecute, SQL, SQLE_TOO_MANY_RECORDS); Result := GetDBHandle.sqlErrd[2]; LastUpdateCount := Result; { Logging SQL Command } DriverManager.LogMessage(lcExecute, GetPlainDriver.GetProtocol, SQL); end; end; {$HINTS ON} { TZASACallableStatement } {** Constructs this object and assignes the main properties. @param Connection a database connection object. @param Handle a connection handle pointer. @param Info a statement parameters. } constructor TZASACallableStatement.Create(Connection: IZConnection; const SQL: string; Info: TStrings); begin inherited Create(Connection, SQL, Info); FASAConnection := Connection as IZASAConnection; FetchSize := BlockSize; ResultSetConcurrency := rcUpdatable; ResultSetType := rtScrollSensitive; FCachedBlob := StrToBoolEx(DefineStatementParameter(Self, 'cashedblob', 'true')); CursorName := AnsiString(RandomString(12)); FParamSQLData := TZASASQLDA.Create( FASAConnection.GetPlainDriver, FASAConnection.GetDBHandle, CursorName, ConSettings); FSQLData := TZASASQLDA.Create( FASAConnection.GetPlainDriver, FASAConnection.GetDBHandle, CursorName, ConSettings); end; destructor TZASACallableStatement.Destroy; begin FSQLData := nil; FParamSQLData := nil; inherited; end; procedure TZASACallableStatement.Close; begin if not Closed then begin FASAConnection.GetPlainDriver.db_close(FASAConnection.GetDBHandle, PAnsiChar(CursorName)); Closed := false; end; if FStmtNum <> 0 then begin FASAConnection.GetPlainDriver.db_dropstmt( FASAConnection.GetDBHandle, nil, nil, @FStmtNum); FStmtNum := 0; end; inherited; end; procedure TZASACallableStatement.Cancel; begin with FASAConnection do begin GetPlainDriver.db_cancel_request( GetDBHandle); ZDbcASAUtils.CheckASAError( GetPlainDriver, GetDBHandle, lcExecute, SQL); end; end; function TZASACallableStatement.GetWarnings: EZSQLWarning; begin Result := inherited GetWarnings; end; procedure TZASACallableStatement.ClearWarnings; begin inherited; end; function TZASACallableStatement.GetMoreResults: Boolean; begin Result := FMoreResults; if FMoreResults then begin with FASAConnection do begin GetPlainDriver.db_resume(GetDBHandle, PAnsiChar(CursorName)); ZDbcASAUtils.CheckASAError( GetPlainDriver, GetDBHandle, lcExecute); if GetDBHandle.sqlcode = SQLE_PROCEDURE_COMPLETE then Result := false else DescribeCursor( FASAConnection, TZASASQLDA( FSQLData), CursorName, ''); end; end; end; {** Executes an SQL statement that may return multiple results. Under some (uncommon) situations a single SQL statement may return multiple result sets and/or update counts. Normally you can ignore this unless you are (1) executing a stored procedure that you know may return multiple results or (2) you are dynamically executing an unknown SQL string. The methods execute, getMoreResults, getResultSet, and getUpdateCount let you navigate through multiple results. The execute method executes an SQL statement and indicates the form of the first result. You can then use the methods getResultSet or getUpdateCount to retrieve the result, and getMoreResults to move to any subsequent result(s). @param sql any SQL statement @return true if the next result is a ResultSet object; false if it is an update count or there are no more results @see #getResultSet @see #getUpdateCount @see #getMoreResults } function TZASACallableStatement.Execute(const SQL: RawByteString): Boolean; var ProcSQL: RawByteString; begin TrimInParameters; ProcSQL := GetProcedureSQL; if not FPrepared or ( ASQL <> ProcSQL) then begin Close; ASQL := ProcSQL; ASAPrepare( FASAConnection, FSQLData, FParamSQLData, ASQL, LogSQL, @FStmtNum, FPrepared, FMoreResults); end; Result := ExecutePrepared; end; {** Executes any kind of SQL statement. Some prepared statements return multiple results; the execute method handles these complex statements as well as the simpler form of statements handled by the methods executeQuery and executeUpdate. @see Statement#execute } function TZASACallableStatement.ExecutePrepared: Boolean; begin if not FPrepared then Result := Execute(ASQL) else begin if FMoreResults or ( ( FSQLData.GetData.sqld > 0) and ( FSQLData.GetData.sqlVar[0].sqlInd^ and DT_PROCEDURE_OUT = 0)) then begin LastResultSet := ExecuteQueryPrepared; Result := true; end else begin ExecuteUpdatePrepared; Result := false; end; end; end; {** Executes an SQL statement that returns a single ResultSet object. @param sql typically this is a static SQL SELECT statement @return a ResultSet object that contains the data produced by the given query; never null } function TZASACallableStatement.ExecuteQuery(const SQL: RawByteString): IZResultSet; var ProcSQL: RawByteString; begin TrimInParameters; ProcSQL := GetProcedureSQL; if not FPrepared or ( ASQL <> ProcSQL) then begin Close; ASQL := ProcSQL; ASAPrepare( FASAConnection, FSQLData, FParamSQLData, ASQL, LogSQL, @FStmtNum, FPrepared, FMoreResults); end; Result := ExecuteQueryPrepared; end; {** Executes the SQL query in this PreparedStatement object and returns the result set generated by the query. @return a ResultSet object that contains the data produced by the query; never null } {$HINTS OFF} function TZASACallableStatement.ExecuteQueryPrepared: IZResultSet; var Cursor: AnsiString; CursorOptions: SmallInt; begin if not FPrepared then Result := ExecuteQuery(ASQL) else begin with FASAConnection do begin PrepareParameters( GetPlainDriver, InParamValues, InParamTypes, InParamCount, FParamSQLData, FASAConnection.GetConSettings); if ResultSetConcurrency = rcUpdatable then CursorOptions := CUR_OPEN_DECLARE + CUR_UPDATE else CursorOptions := CUR_OPEN_DECLARE + CUR_READONLY; if ResultSetType = rtScrollInsensitive then CursorOptions := CursorOptions + CUR_INSENSITIVE; Cursor := CursorName; GetPlainDriver.db_open(GetDBHandle, PAnsiChar(Cursor), nil, @FStmtNum, FParamSQLData.GetData, FetchSize, 0, CursorOptions); ZDbcASAUtils.CheckASAError( GetPlainDriver, GetDBHandle, lcExecute, LogSQL); Closed := false; try if FMoreResults then DescribeCursor( FASAConnection, TZASASQLDA( FSQLData), Cursor, LogSQL); LastUpdateCount := -1; Result := GetCachedResultSet( LogSQL, Self, TZASAResultSet.Create( Self, LogSQL, FStmtNum, Cursor, FSQLData, nil, FCachedBlob)); { Logging SQL Command } DriverManager.LogMessage( lcExecute, GetPlainDriver.GetProtocol, LogSQL); except on E: Exception do begin Self.Close; raise; end; end; end; end; end; {$HINTS ON} {** Executes an SQL INSERT, UPDATE or DELETE statement. In addition, SQL statements that return nothing, such as SQL DDL statements, can be executed. @param sql an SQL INSERT, UPDATE or DELETE statement or an SQL statement that returns nothing @return either the row count for INSERT, UPDATE or DELETE statements, or 0 for SQL statements that return nothing } function TZASACallableStatement.ExecuteUpdate(const SQL: RawByteString): Integer; var ProcSQL: RawByteString; begin TrimInParameters; ProcSQL := GetProcedureSQL; if not FPrepared or ( ASQL <> ProcSQL) then begin Close; ASQL := ProcSQL; ASAPrepare( FASAConnection, FSQLData, FParamSQLData, ASQL, LogSQL, @FStmtNum, FPrepared, FMoreResults); end; Result := ExecuteUpdatePrepared; end; {** Executes the SQL INSERT, UPDATE or DELETE statement in this PreparedStatement object. In addition, SQL statements that return nothing, such as SQL DDL statements, can be executed. @return either the row count for INSERT, UPDATE or DELETE statements; or 0 for SQL statements that return nothing } function TZASACallableStatement.ExecuteUpdatePrepared: Integer; begin if not FPrepared then Result := ExecuteUpdate( SQL) else begin // Result := -1; with FASAConnection do begin PrepareParameters( GetPlainDriver, InParamValues, InParamTypes, InParamCount, FParamSQLData, FASAConnection.GetConSettings); GetPlainDriver.db_execute_into( GetDBHandle, nil, nil, @FStmtNum, FParamSQLData.GetData, FSQLData.GetData); ZDbcASAUtils.CheckASAError( GetPlainDriver, GetDBHandle, lcExecute, SQL); Result := GetDBHandle.sqlErrd[2]; LastUpdateCount := Result; { Fetch data and fill Output params } FetchOutParams( FSQLData); { Logging SQL Command } DriverManager.LogMessage(lcExecute, GetPlainDriver.GetProtocol, SQL); end; end; end; {** Set output parameters values from IZResultSQLDA. @param Value a IZASASQLDA object. } procedure TZASACallableStatement.FetchOutParams( Value: IZASASQLDA); var I: Integer; L: LongWord; Temp: TZVariant; TempBlob: IZBlob; P: Pointer; begin SetOutParamCount(Value.GetFieldCount); for I := 0 to Value.GetFieldCount-1 do begin if Value.IsNull(I) then DefVarManager.SetNull(Temp) else case Value.GetFieldSqlType(I) of stBoolean: DefVarManager.SetAsBoolean(Temp, Value.GetBoolean(I)); stByte: DefVarManager.SetAsInteger(Temp, Value.GetByte(I)); stShort: DefVarManager.SetAsInteger(Temp, Value.GetShort(I)); stInteger: DefVarManager.SetAsInteger(Temp, Value.GetInt(I)); stLong: DefVarManager.SetAsInteger(Temp, Value.GetLong(I)); stFloat: DefVarManager.SetAsFloat(Temp, Value.GetFloat(I)); stDouble: DefVarManager.SetAsFloat(Temp, Value.GetDouble(I)); stBigDecimal: DefVarManager.SetAsFloat(Temp, Value.GetBigDecimal(I)); stString: DefVarManager.SetAsString(Temp, ZDbcString(Value.GetString(I))); stUnicodeString: DefVarManager.SetAsUnicodeString(Temp, ZDbcUnicodeString(Value.GetString(I))); stBytes: DefVarManager.SetAsBytes( Temp, Value.GetBytes( I)); stDate: DefVarManager.SetAsDateTime(Temp, Value.GetDate(I)); stTime: DefVarManager.SetAsDateTime(Temp, Value.GetTime(I)); stTimestamp: DefVarManager.SetAsDateTime(Temp, Value.GetTimestamp(I)); stAsciiStream, stUnicodeStream, stBinaryStream: begin GetMem( P, PZASABlobStruct( Value.GetData.sqlvar[I].sqlData).untrunc_len); Value.ReadBlobToMem( I, P, L); TempBlob := TZASABlob.CreateWithData( P, L, GetConnection); FreeMem(P); DefVarManager.SetAsInterface( Temp, TempBlob); end; end; OutParamValues[I] := Temp; end; end; {** Create sql string for calling stored procedure. @param SelectProc indicate use EXECUTE PROCEDURE or SELECT staement @return a Stored Procedure SQL string } function TZASACallableStatement.GetProcedureSql: RawByteString; function GenerateParamsStr(Count: integer): string; var I: integer; begin for I := 0 to Count - 1 do begin if Result <> '' then Result := Result + ','; Result := Result + '?'; end; end; var InParams: string; begin InParams := GenerateParamsStr( High( InParamValues) + 1); if InParams <> '' then InParams := '(' + InParams + ')'; Result := ZPlainString('call ' + SQL + InParams); end; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcASAUtils.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { ASA Database Connectivity Classes } { } { Originally written by Sergey Seroukhov } { and Sergey Merkuriev } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcASAUtils; interface {$I ZDbc.inc} uses Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, Types, ZSysUtils, ZDbcIntfs, ZPlainASADriver, ZDbcLogging, ZCompatibility, ZDbcASA, ZDbcStatement, ZVariant, ZPlainASAConstants; const StdVars = 20; MinBLOBSize = 256; BlockSize = 20; type { ASA Error Class} EZASAConvertError = class(Exception); TZASADECLTYPE = record sqlType: SmallInt; sqlLen : Word; end; { Base interface for sqlda } IZASASQLDA = interface ['{7606E8EB-9FC8-4F76-8D91-E23AB96409E1}'] procedure AllocateSQLDA( NumVars: Word); procedure InitFields; procedure FreeSQLDA; function GetData: PASASQLDA; function IsBlob(const Index: Word): boolean; function IsNullable(const Index: Word): boolean; function GetFieldCount: Integer; function GetFieldName(const Index: Word): string; function GetFieldIndex(const Name: String): Word; function GetFieldScale(const Index: Word): integer; function GetFieldSqlType(const Index: Word): TZSQLType; function GetFieldLength(const Index: Word): Word; procedure UpdateNull(const Index: Integer; Value: boolean); procedure UpdateBoolean(const Index: Integer; Value: boolean); procedure UpdateByte(const Index: Integer; Value: Byte); procedure UpdateShort(const Index: Integer; Value: SmallInt); procedure UpdateInt(const Index: Integer; Value: Integer); procedure UpdateLong(const Index: Integer; Value: Int64); procedure UpdateFloat(const Index: Integer; Value: Single); procedure UpdateDouble(const Index: Integer; Value: Double); procedure UpdateBigDecimal(const Index: Integer; Value: Extended); procedure UpdatePChar(const Index: Integer; Value: PChar); procedure UpdateString(const Index: Integer; Value: RawByteString); procedure UpdateBytes(const Index: Integer; Value: TByteDynArray); procedure UpdateDate(const Index: Integer; Value: TDateTime); procedure UpdateTime(const Index: Integer; Value: TDateTime); procedure UpdateTimestamp(const Index: Integer; Value: TDateTime); procedure UpdateValue(const Index: Word; Value: Variant); procedure WriteBlob(const Index: Integer; Stream: TStream; const BlobType: TZSQLType); function IsNull(const Index: Integer): Boolean; function IsAssigned(const Index: Integer): Boolean; function GetBoolean(const Index: Integer): Boolean; function GetByte(const Index: Integer): Byte; function GetShort(const Index: Integer): SmallInt; function GetInt(const Index: Integer): Integer; function GetLong(const Index: Integer): Int64; function GetFloat(const Index: Integer): Single; function GetDouble(const Index: Integer): Double; function GetBigDecimal(const Index: Integer): Extended; function GetPChar(const Index: Integer): PAnsiChar; function GetString(const Index: Integer): RawByteString; function GetBytes(const Index: Integer): TByteDynArray; function GetDate(const Index: Integer): TDateTime; function GetTime(const Index: Integer): TDateTime; function GetTimestamp(const Index: Integer): TDateTime; function GetValue(const Index: Word): Variant; procedure ReadBlobToMem(const Index: Word; var Buffer: Pointer; var Length: LongWord); procedure ReadBlobToStream(const Index: Word; Stream: TStream); procedure ReadBlobToString(const Index: Word; var str: RawByteString); procedure ReadBlobToVariant(const Index: Word; var Value: Variant); end; { Base class contain core functions to work with sqlda structure Can allocate memory for sqlda structure get basic information } TZASASQLDA = class (TInterfacedObject, IZASASQLDA) private FConSettings: PZConSettings; FSQLDA: PASASQLDA; FPlainDriver: IZASAPlainDriver; FHandle: PZASASQLCA; FCursorName: AnsiString; procedure CreateException( Msg: string); procedure CheckIndex(const Index: Word); procedure CheckRange(const Index: Word); procedure SetFieldType(const Index: Word; ASAType: Smallint; Len: LongWord; SetDeclType: Boolean = true); overload; procedure SetFieldType(ToSQLDA: PASASQLDA; const Index: Word; ASAType: Smallint; Len: LongWord; SetDeclType: Boolean = true); overload; protected FDeclType: array of TZASADECLTYPE; procedure ReadBlob(const Index: Word; Buffer: Pointer; Length: LongWord); public constructor Create(PlainDriver: IZASAPlainDriver; Handle: PZASASQLCA; CursorName: AnsiString; ConSettings: PZConSettings; NumVars: Word = StdVars); destructor Destroy; override; procedure AllocateSQLDA( NumVars: Word); procedure InitFields; procedure FreeSQLDA; function GetData: PASASQLDA; function IsBlob(const Index: Word): boolean; function IsNullable(const Index: Word): boolean; function GetFieldCount: Integer; function GetFieldName(const Index: Word): string; function GetFieldIndex(const Name: String): Word; function GetFieldScale(const Index: Word): Integer; function GetFieldSqlType(const Index: Word): TZSQLType; function GetFieldLength(const Index: Word): Word; procedure UpdateNull(const Index: Integer; Value: boolean); procedure UpdateBoolean(const Index: Integer; Value: boolean); procedure UpdateByte(const Index: Integer; Value: Byte); procedure UpdateShort(const Index: Integer; Value: SmallInt); procedure UpdateInt(const Index: Integer; Value: Integer); procedure UpdateLong(const Index: Integer; Value: Int64); procedure UpdateFloat(const Index: Integer; Value: Single); procedure UpdateDouble(const Index: Integer; Value: Double); procedure UpdateBigDecimal(const Index: Integer; Value: Extended); procedure UpdatePChar(const Index: Integer; Value: PChar); procedure UpdateString(const Index: Integer; Value: RawByteString); procedure UpdateBytes(const Index: Integer; Value: TByteDynArray); procedure UpdateDate(const Index: Integer; Value: TDateTime); procedure UpdateTime(const Index: Integer; Value: TDateTime); procedure UpdateDateTime(const Index: Integer; Value: TDateTime); procedure UpdateTimestamp(const Index: Integer; Value: TDateTime); procedure UpdateValue(const Index: Word; Value: Variant); procedure WriteBlob(const Index: Integer; Stream: TStream; const BlobType: TZSQLType); function IsNull(const Index: Integer): Boolean; function IsAssigned(const Index: Integer): Boolean; function GetBoolean(const Index: Integer): Boolean; function GetByte(const Index: Integer): Byte; function GetShort(const Index: Integer): SmallInt; function GetInt(const Index: Integer): Integer; function GetLong(const Index: Integer): Int64; function GetFloat(const Index: Integer): Single; function GetDouble(const Index: Integer): Double; function GetBigDecimal(const Index: Integer): Extended; function GetPChar(const Index: Integer): PAnsiChar; function GetString(const Index: Integer): RawByteString; function GetBytes(const Index: Integer): TByteDynArray; function GetDate(const Index: Integer): TDateTime; function GetTime(const Index: Integer): TDateTime; function GetTimestamp(const Index: Integer): TDateTime; function GetValue(const Index: Word): Variant; procedure ReadBlobToMem(const Index: Word; var Buffer: Pointer; var Length: LongWord); procedure ReadBlobToStream(const Index: Word; Stream: TStream); procedure ReadBlobToString(const Index: Word; var str: RawByteString); procedure ReadBlobToVariant(const Index: Word; var Value: Variant); end; {** Converts a ASA native type into ZDBC SQL types. @param FieldHandle a handler to field description structure. @return a SQL undepended type. } function ConvertASATypeToSQLType(const SQLType: SmallInt; const CtrlsCPType: TZControlsCodePage): TZSQLType; {** Converts a ASA native type into String. @param SQLType Field of TASASQLVar structure. @return type description. } function ConvertASATypeToString( SQLType: SmallInt): String; function ConvertASAJDBCToSqlType(const FieldType: SmallInt; CtrlsCPType: TZControlsCodePage): TZSQLType; { procedure TSQLTimeStampToASADateTime( DT: TSQLTimeStamp; const ASADT: PZASASQLDateTime); function ASADateTimeToSQLTimeStamp( ASADT: PZASASQLDateTime): TSQLTimeStamp; } {** Checks for possible sql errors. @param PlainDriver a MySQL plain driver. @param Handle a MySQL connection handle. @param LogCategory a logging category. @param LogMessage a logging message. } procedure CheckASAError(PlainDriver: IZASAPlainDriver; Handle: PZASASQLCA; LogCategory: TZLoggingCategory; LogMessage: string = ''; SupressExceptionID: Integer = 0); function GetCachedResultSet(SQL: string; Statement: IZStatement; NativeResultSet: IZResultSet): IZResultSet; procedure DescribeCursor( FASAConnection: IZASAConnection; FSQLData: IZASASQLDA; Cursor: AnsiString; SQL: String); procedure ASAPrepare( FASAConnection: IZASAConnection; FSQLData, FParamsSQLData: IZASASQLDA; const SQL: RawByteString; const LogSQL: String; StmtNum: PSmallInt; var FPrepared, FMoreResults: Boolean); procedure PrepareParameters( PlainDriver: IZASAPlainDriver; InParamValues: TZVariantDynArray; InParamTypes: TZSQLTypeArray; InParamCount: Integer; ParamSqlData: IZASASQLDA; ConSettings: PZConSettings); function RandomString( Len: integer): string; implementation uses Variants, ZMessages, ZDbcCachedResultSet, Math, ZEncoding {$IFDEF WITH_UNITANSISTRINGS}, AnsiStrings{$ENDIF}; { TZASASQLDA } procedure TZASASQLDA.CreateException( Msg: string); begin DriverManager.LogError( lcOther, FPlainDriver.GetProtocol, '', -1, Msg); raise EZSQLException.Create( Format( SSQLError1, [ Msg])); end; {** Check range count fields. If index out of range raised exception. @param Index the index field } procedure TZASASQLDA.CheckIndex(const Index: Word); begin Assert( Assigned( FSQLDA), 'SQLDA not initialized.'); Assert( Index < Word(FSQLDA.sqld), 'Out of Range.'); end; procedure TZASASQLDA.CheckRange(const Index: Word); begin CheckIndex( Index); Assert( Assigned( FSQLDA.sqlVar[ Index].sqlData), 'No memory for variable in SQLDA.'); end; procedure TZASASQLDA.SetFieldType(ToSQLDA: PASASQLDA; const Index: Word; ASAType: Smallint; Len: LongWord; SetDeclType: Boolean = true); begin CheckIndex(Index); with ToSQLDA.sqlvar[Index] do begin if ( ASAType and $FFFE = DT_LONGBINARY) or ( ASAType and $FFFE = DT_LONGNVARCHAR) or ( ASAType and $FFFE = DT_LONGVARCHAR) then begin if Assigned( sqlData) then ReallocMem( sqlData, SizeOf( TZASABlobStruct) + Len) else GetMem( sqlData, SizeOf( TZASABlobStruct) + Len); PZASABlobStruct( sqlData).array_len := Len; PZASABlobStruct( sqlData).stored_len := 0; PZASABlobStruct( sqlData).untrunc_len := 0; PZASABlobStruct( sqlData).arr[0] := #0; Inc( Len, SizeOf( TZASABlobStruct)); end else begin if ( ASAType and $FFFE = DT_BINARY) or ( ASAType and $FFFE = DT_VARCHAR) then Inc( Len, SizeOf( TZASASQLSTRING)); if Assigned( sqlData) then ReallocMem( sqlData, Len) else GetMem( sqlData, Len); if ( ASAType and $FFFE = DT_BINARY) or ( ASAType and $FFFE = DT_VARCHAR) then PZASASQLSTRING( sqlData).length := 0; end; sqlType := ASAType; sqllen := Len; if SetDeclType then begin FDeclType[Index].sqlType := sqlType; FDeclType[Index].sqlLen := sqlLen; end; end; end; procedure TZASASQLDA.SetFieldType(const Index: Word; ASAType: Smallint; Len: LongWord; SetDeclType: Boolean = true); begin SetFieldType(FSQLDA, Index, ASAType, Len, SetDeclType); end; constructor TZASASQLDA.Create(PlainDriver: IZASAPlainDriver; Handle: PZASASQLCA; CursorName: AnsiString; ConSettings: PZConSettings; NumVars: Word = StdVars); begin FPlainDriver := PlainDriver; FHandle := Handle; FCursorName := CursorName; AllocateSQLDA(NumVars); FConSettings := ConSettings; inherited Create; end; destructor TZASASQLDA.Destroy; begin FreeSQLDA; inherited; end; {** Reallocate SQLDA to fields count length @param Value the count fields } procedure TZASASQLDA.AllocateSQLDA( NumVars: Word); begin FreeSQLDA; FSQLDA := FPlainDriver.db_alloc_sqlda( NumVars); if not Assigned( FSQLDA) then CreateException( 'Not enough memory for SQLDA'); SetLength(FDeclType, FSQLDA.sqln); end; {** Allocate memory for SQLVar in SQLDA structure for every fields by it length. } procedure TZASASQLDA.InitFields; var i: Integer; begin if Assigned( FSQLDA) then begin for i := 0 to FSQLDA.sqld-1 do begin FDeclType[i].sqlType := FSQLDA.sqlVar[i].sqlType; FDeclType[i].sqlLen := FSQLDA.sqlVar[i].sqlLen; case FSQLDA.sqlVar[i].sqlType and $FFFE of DT_DATE, DT_TIME, DT_TIMESTAMP: begin FSQLDA.sqlVar[i].sqlType := DT_TIMESTAMP_STRUCT + ( FSQLDA.sqlVar[i].sqlType and $0001); FSQLDA.sqlVar[i].sqlLen := SizeOf( TZASASQLDateTime); end; DT_DECIMAL: begin FSQLDA.sqlVar[i].sqlType := DT_DOUBLE + ( FSQLDA.sqlVar[i].sqlType and $0001); FSQLDA.sqlVar[i].sqlLen := SizeOf( Double); end; DT_STRING, DT_FIXCHAR, DT_VARCHAR, DT_LONGVARCHAR: if FSQLDA.sqlVar[i].sqlLen < MinBLOBSize then FSQLDA.sqlVar[i].sqlType := DT_VARCHAR + ( FSQLDA.sqlVar[i].sqlType and $0001) else begin FSQLDA.sqlVar[i].sqlType := DT_LONGVARCHAR + ( FSQLDA.sqlVar[i].sqlType and $0001); FSQLDA.sqlVar[i].sqlLen := 0; end; DT_BINARY, DT_LONGBINARY: if FSQLDA.sqlVar[i].sqlLen < MinBLOBSize then FSQLDA.sqlVar[i].sqlType := DT_BINARY + ( FSQLDA.sqlVar[i].sqlType and $0001) else begin FSQLDA.sqlVar[i].sqlType := DT_LONGBINARY + ( FSQLDA.sqlVar[i].sqlType and $0001); FSQLDA.sqlVar[i].sqlLen := 0; end; end; SetFieldType( i, FSQLDA.sqlVar[i].sqlType, FSQLDA.sqlVar[i].sqlLen, False); end; end; end; {** Clear allocated data for SQLDA parameters } procedure TZASASQLDA.FreeSQLDA; var i: integer; begin if Assigned( FSQLDA) then begin for i := 0 to FSQLDA.sqln-1 do begin FSQLDA.sqlVar[i].sqlInd := nil; if Assigned( FSQLDA.sqlVar[i].sqlData) then begin FreeMem( FSQLDA.sqlVar[i].sqlData); FSQLDA.sqlVar[i].sqlData := nil; end; end; FPlainDriver.db_free_sqlda( FSQLDA); FSQLDA := nil; end; SetLength(FDeclType, 0); FDeclType := nil; end; {** Return pointer to SQLDA structure } function TZASASQLDA.GetData: PASASQLDA; begin Result := FSQLDA; end; {** Indicate blob field @param Index the index fields @return true if blob field overwise false } function TZASASQLDA.IsBlob(const Index: Word): boolean; begin Result := GetFieldSqlType( Index) in [ stAsciiStream, stUnicodeStream, stBinaryStream]; end; {** Indicate nullable field @param Index the index fields @return true if field nullable overwise false } function TZASASQLDA.IsNullable(const Index: Word): boolean; begin CheckIndex(Index); Result := FSQLDA.sqlvar[Index].sqlType and 1 = 1 end; {** Get fields count not allocated. @return fields count } function TZASASQLDA.GetFieldCount: Integer; begin if Assigned( FSQLDA) then Result := FSQLDA.sqld else Result := 0; end; {** Return Name for field @param Index the index fields @return the name } function TZASASQLDA.GetFieldName(const Index: Word): string; {$IFDEF WITH_RAWBYTESTRING} var Temp: RawByteString; {$ENDIF} begin CheckIndex(Index); {$IFDEF WITH_RAWBYTESTRING} SetLength(Temp, FSQLDA.sqlvar[Index].sqlname.length-1); Move(FSQLDA.sqlvar[Index].sqlname.data, PAnsiChar(Temp)^, FSQLDA.sqlvar[Index].sqlname.length-1); Result := FPlainDriver.ZDbcString(Temp, FConSettings); {$ELSE} SetString( Result, FSQLDA.sqlvar[Index].sqlname.data, FSQLDA.sqlvar[Index].sqlname.length-1); {$ENDIF} end; {** Return field index by it name @param Index the index fields @return the index field } function TZASASQLDA.GetFieldIndex(const Name: String): Word; begin for Result := 0 to FSQLDA.sqld - 1 do if FSQLDA.sqlvar[Result].sqlname.length = Length(name) then if {$IFDEF WITH_STRLICOMP_DEPRECATED}AnsiStrings.{$ENDIF}StrLIComp(@FSQLDA.sqlvar[Result].sqlname.data, PAnsiChar(FPlainDriver.ZPlainString(Name, FConSettings)), Length(name)) = 0 then Exit; CreateException( Format( SFieldNotFound1, [name])); Result := 0; // satisfy compiler end; {** Return field length @param Index the index fields @return the field lenth } function TZASASQLDA.GetFieldLength(const Index: Word): Word; begin CheckIndex( Index); if FSQLDA.sqlvar[Index].sqlType and $FFFE <> DT_DECIMAL then Result := FSQLDA.sqlvar[Index].sqlLen else Result := (FSQLDA.sqlvar[Index].sqlLen and $FF) div 2 + 1; end; {** Return field scale @param Index the index fields @return the field scale } function TZASASQLDA.GetFieldScale(const Index: Word): integer; begin CheckIndex(Index); if FSQLDA.sqlvar[Index].sqlType and $FFFE <> DT_DECIMAL then Result := 0 else Result := FSQLDA.sqlvar[Index].sqlLen div 256; end; {** Convert ASA sql type to SQLType @param Index the index fields @return the SQLType } function TZASASQLDA.GetFieldSqlType(const Index: Word): TZSQLType; begin CheckIndex(Index); if FSQLDA.sqlvar[Index].sqlType and $FFFE <> DT_TIMESTAMP_STRUCT then Result := ConvertASATypeToSQLType(FSQLDA.sqlvar[Index].sqlType, FConSettings.CPType) else Result := ConvertASATypeToSQLType( FDeclType[Index].sqlType, FConSettings.CPType) end; {** Set up parameter null value @param Index the target parameter index @param Value the source value } procedure TZASASQLDA.UpdateNull(const Index: Integer; Value: Boolean); begin CheckIndex( Index); with FSQLDA.sqlvar[ Index] do begin if not Assigned( sqlData) then SetFieldType( Index, DT_TINYINT or 1, SizeOf( Byte)); if Value then sqlind^ := -1 //NULL else sqlind^ := 0; //NOT NULL end; end; {** Set up parameter Boolean value @param Index the target parameter index @param Value the source value } procedure TZASASQLDA.UpdateBoolean(const Index: Integer; Value: boolean); begin CheckIndex( Index); SetFieldType( Index, DT_BIT or 1, SizeOf( Byte)); with FSQLDA.sqlvar[Index] do begin case sqlType and $FFFE of DT_SMALLINT, DT_UNSSMALLINT : PSmallint(sqldata)^ := ord(Value); DT_INT, DT_UNSINT : PInteger(sqldata)^ := ord(Value); DT_FLOAT : PSingle(sqldata)^ := ord(Value); DT_DOUBLE : PDouble(sqldata)^ := ord(Value); DT_VARCHAR: begin PZASASQLSTRING( sqlData).length := 1; {$IFDEF WITH_STRPLCOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrPLCopy( @PZASASQLSTRING( sqlData).data[0], AnsiString(IntToStr(ord(Value))), sqllen-3); end; DT_TINYINT, DT_BIT : PByte(sqldata)^ := ord(Value); DT_BIGINT, DT_UNSBIGINT : PInt64(sqldata)^ := ord(Value); else CreateException( SUnsupportedParameterType); end; if (sqlind <> nil) then sqlind^ := 0; // not null end; end; {** Set up parameter Byte value @param Index the target parameter index @param Value the source value } procedure TZASASQLDA.UpdateByte(const Index: Integer; Value: Byte); begin CheckIndex( Index); SetFieldType( Index, DT_TINYINT or 1, SizeOf( Byte)); with FSQLDA.sqlvar[Index] do begin case sqlType and $FFFE of DT_SMALLINT, DT_UNSSMALLINT : PWord(sqldata)^ := Value; //was PSmallint DT_INT, DT_UNSINT : PInteger(sqldata)^ := Value; DT_FLOAT : PSingle(sqldata)^ := Value; DT_DOUBLE : PDouble(sqldata)^ := Value; DT_VARCHAR: begin PZASASQLSTRING( sqlData).length := Length( IntToStr( Value)); {$IFDEF WITH_STRPLCOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrPLCopy( @PZASASQLSTRING( sqlData).data[0], AnsiString(IntToStr(Value)), sqllen-3); end; DT_TINYINT, DT_BIT : PByte(sqldata)^ := Value; DT_BIGINT, DT_UNSBIGINT : PInt64(sqldata)^ := Value; else CreateException( SUnsupportedParameterType); end; if (sqlind <> nil) then sqlind^ := 0; // not null end; end; {** Set up parameter short value @param Index the target parameter index @param Value the source value } procedure TZASASQLDA.UpdateShort(const Index: Integer; Value: SmallInt); begin CheckIndex( Index); SetFieldType( Index, DT_SMALLINT or 1, SizeOf( SmallInt)); with FSQLDA.sqlvar[Index] do begin case sqlType and $FFFE of DT_SMALLINT, DT_UNSSMALLINT : PSmallInt(sqldata)^ := Value; DT_INT, DT_UNSINT : PInteger(sqldata)^ := Value; DT_FLOAT : PSingle(sqldata)^ := Value; DT_DOUBLE : PDouble(sqldata)^ := Value; DT_VARCHAR: begin PZASASQLSTRING( sqlData).length := Length( IntToStr( Value)); {$IFDEF WITH_STRPLCOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrPLCopy( @PZASASQLSTRING( sqlData).data[0], AnsiString(IntToStr(Value)), sqllen-3); end; DT_TINYINT, DT_BIT : PByte(sqldata)^ := Value; DT_BIGINT, DT_UNSBIGINT : PInt64(sqldata)^ := Value; else CreateException( SUnsupportedParameterType); end; if (sqlind <> nil) then sqlind^ := 0; // not null end; end; {** Set up parameter integer value @param Index the target parameter index @param Value the source value } procedure TZASASQLDA.UpdateInt(const Index: Integer; Value: Integer); begin CheckIndex( Index); SetFieldType( Index, DT_INT or 1, SizeOf( Integer)); with FSQLDA.sqlvar[Index] do begin case sqlType and $FFFE of DT_SMALLINT, DT_UNSSMALLINT : PSmallint(sqldata)^ := Value; DT_INT, DT_UNSINT : PInteger(sqldata)^ := Value; DT_FLOAT : PSingle(sqldata)^ := Value; DT_DOUBLE : PDouble(sqldata)^ := Value; DT_VARCHAR: begin PZASASQLSTRING( sqlData).length := Length( IntToStr(Value)); {$IFDEF WITH_STRPLCOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrPLCopy( @PZASASQLSTRING( sqlData).data[0], AnsiString(IntToStr( Value)), sqllen-3); end; DT_TINYINT, DT_BIT : PByte(sqldata)^ := Value; DT_BIGINT, DT_UNSBIGINT : PInt64(sqldata)^ := Value; else CreateException( SUnsupportedParameterType); end; if (sqlind <> nil) then sqlind^ := 0; // not null end; end; {** Set up parameter Long value @param Index the target parameter index @param Value the source value } procedure TZASASQLDA.UpdateLong(const Index: integer; Value: Int64); begin CheckIndex( Index); SetFieldType( Index, DT_BIGINT or 1, SizeOf( Int64)); with FSQLDA.sqlvar[Index] do begin case sqlType and $FFFE of DT_SMALLINT, DT_UNSSMALLINT : PSmallint(sqldata)^ := Value; DT_INT, DT_UNSINT : PInteger(sqldata)^ := Value; DT_FLOAT : PSingle(sqldata)^ := Value; DT_DOUBLE : PDouble(sqldata)^ := Value; DT_VARCHAR: begin PZASASQLSTRING( sqlData).length := Length( IntToStr( Value)); {$IFDEF WITH_STRPLCOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrPLCopy( @PZASASQLSTRING( sqlData).data[0], AnsiString(IntToStr(Value)), sqllen-3); end; DT_TINYINT, DT_BIT : PByte(sqldata)^ := Value; DT_BIGINT, DT_UNSBIGINT : PInt64(sqldata)^ := Value; else CreateException( SUnsupportedParameterType); end; if (sqlind <> nil) then sqlind^ := 0; // not null end; end; {** Set up parameter Float value @param Index the target parameter index @param Value the source value } procedure TZASASQLDA.UpdateFloat(const Index: Integer; Value: Single); begin CheckIndex( Index); SetFieldType( Index, DT_FLOAT or 1, SizeOf( Single)); with FSQLDA.sqlvar[Index] do begin case sqlType and $FFFE of DT_SMALLINT, DT_UNSSMALLINT : PSmallint(sqldata)^ := Trunc( Value); DT_INT, DT_UNSINT : PInteger(sqldata)^ := Trunc( Value); DT_FLOAT : PSingle(sqldata)^ := Value; DT_DOUBLE : PDouble(sqldata)^ := Value; DT_VARCHAR: begin PZASASQLSTRING( sqlData).length := Length( FloatToStr( Value)); {$IFDEF WITH_STRPLCOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrPLCopy( @PZASASQLSTRING( sqlData).data[0], AnsiString(FloatToStr(Value)), sqllen-3); end; DT_TINYINT, DT_BIT : PByte(sqldata)^ := Trunc( Value); DT_BIGINT, DT_UNSBIGINT : PInt64(sqldata)^ := Trunc( Value); else CreateException( SUnsupportedParameterType); end; if (sqlind <> nil) then sqlind^ := 0; // not null end; end; {** Set up parameter Double value @param Index the target parameter index @param Value the source value } procedure TZASASQLDA.UpdateDouble(const Index: Integer; Value: Double); begin CheckIndex( Index); SetFieldType( Index, DT_DOUBLE or 1, SizeOf( Double)); with FSQLDA.sqlvar[Index] do begin case sqlType and $FFFE of DT_SMALLINT, DT_UNSSMALLINT : PSmallint(sqldata)^ := Trunc( Value); DT_INT, DT_UNSINT : PInteger(sqldata)^ := Trunc( Value); DT_FLOAT : PSingle(sqldata)^ := Value; DT_DOUBLE : PDouble(sqldata)^ := Value; DT_VARCHAR: begin PZASASQLSTRING( sqlData).length := Length( FloatToStr( Value)); {$IFDEF WITH_STRPLCOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrPLCopy( @PZASASQLSTRING( sqlData).data[0], AnsiString(FloatToStr( Value)), sqllen-3); end; DT_TINYINT, DT_BIT : PByte(sqldata)^ := Trunc( Value); DT_BIGINT, DT_UNSBIGINT : PInt64(sqldata)^ := Trunc( Value); else CreateException( SUnsupportedParameterType); end; if (sqlind <> nil) then sqlind^ := 0; // not null end; end; {** Set up parameter BigDecimal value @param Index the target parameter index @param Value the source value } procedure TZASASQLDA.UpdateBigDecimal(const Index: Integer; Value: Extended); begin CheckIndex( Index); SetFieldType( Index, DT_DOUBLE or 1, SizeOf( Double)); with FSQLDA.sqlvar[Index] do begin case sqlType and $FFFE of DT_SMALLINT, DT_UNSSMALLINT : PSmallint(sqldata)^ := Trunc( Value); DT_INT, DT_UNSINT : PInteger(sqldata)^ := Trunc( Value); DT_FLOAT : PSingle(sqldata)^ := Value; DT_DOUBLE : PDouble(sqldata)^ := Value; DT_VARCHAR: begin PZASASQLSTRING( sqlData).length := Length( FloatToStr( Value)); {$IFDEF WITH_STRPLCOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrPLCopy( @PZASASQLSTRING( sqlData).data[0], AnsiString(FloatToStr( Value)), sqllen-3); end; DT_TINYINT, DT_BIT : PByte(sqldata)^ := Trunc( Value); DT_BIGINT, DT_UNSBIGINT : PInt64(sqldata)^ := Trunc( Value); else CreateException( SUnsupportedParameterType); end; if (sqlind <> nil) then sqlind^ := 0; // not null end; end; {** Set up parameter PAnsiChar value @param Index the target parameter index @param Value the source value } procedure TZASASQLDA.UpdatePChar(const Index: Integer; Value: PChar); var BlobSize: Integer; AnsiTmp: RawByteString; begin CheckIndex( Index); AnsiTmp := FPlainDriver.ZPlainString(Value, FConSettings); BlobSize := StrLen( Value); if BlobSize < MinBLOBSize then SetFieldType( Index, DT_VARCHAR or 1, MinBLOBSize - 1) else SetFieldType( Index, DT_LONGVARCHAR or 1, BlobSize); with FSQLDA.sqlvar[Index] do begin case sqlType and $FFFE of DT_VARCHAR: begin PZASASQLSTRING( sqlData).length := BlobSize; {$IFDEF WITH_STRLCOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrLCopy( @PZASASQLSTRING( sqlData).data[0], PAnsiChar(AnsiTmp), BlobSize); end; DT_LONGVARCHAR: begin {$IFDEF WITH_STRLCOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrLCopy( @PZASABlobStruct( sqlData).arr[0], PAnsiChar(AnsiTmp), BlobSize); PZASABlobStruct( sqlData).stored_len := BlobSize; PZASABlobStruct( sqlData).untrunc_len := BlobSize; end; else CreateException( SUnsupportedParameterType); end; if (sqlind <> nil) then sqlind^ := 0; // not null end; end; {** Set up parameter String value @param Index the target parameter index @param Value the source value } procedure TZASASQLDA.UpdateString(const Index: Integer; Value: RawByteString); var BlobSize: Integer; begin CheckIndex( Index); BlobSize := Length( Value); if BlobSize < MinBLOBSize then SetFieldType( Index, DT_VARCHAR or 1, MinBLOBSize - 1) else SetFieldType( Index, DT_LONGVARCHAR or 1, BlobSize); with FSQLDA.sqlvar[Index] do begin case sqlType and $FFFE of DT_VARCHAR: begin PZASASQLSTRING( sqlData).length := BlobSize; {$IFDEF WITH_STRPLCOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrPLCopy( @PZASASQLSTRING( sqlData).data[0], Value, BlobSize); end; DT_LONGVARCHAR: begin {$IFDEF WITH_STRPLCOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrPLCopy( @PZASABlobStruct( sqlData).arr[0], Value, BlobSize); PZASABlobStruct( sqlData).stored_len := BlobSize; PZASABlobStruct( sqlData).untrunc_len := BlobSize; end; else CreateException( SUnsupportedParameterType); end; if (sqlind <> nil) then sqlind^ := 0; // not null end; end; {** Set up parameter byte value @param Index the target parameter index @param Value the source value } procedure TZASASQLDA.UpdateBytes(const Index: Integer; Value: TByteDynArray); var BlobSize: Integer; begin CheckIndex( Index); BlobSize := Length( Value); if BlobSize < MinBLOBSize then SetFieldType( Index, DT_BINARY or 1, MinBLOBSize - 1) else SetFieldType( Index, DT_LONGBINARY or 1, BlobSize); with FSQLDA.sqlvar[Index] do begin case sqlType and $FFFE of DT_BINARY: begin PZASASQLSTRING( sqlData).length := BlobSize; Move( Value[0], PZASASQLSTRING( sqlData).data[0], BlobSize); end; DT_LONGBINARY: begin Move( Value[0], PZASABlobStruct( sqlData).arr[0], BlobSize); PZASABlobStruct( sqlData).stored_len := BlobSize; PZASABlobStruct( sqlData).untrunc_len := BlobSize; end; else CreateException( SUnsupportedParameterType); end; if (sqlind <> nil) then sqlind^ := 0; // not null end; end; {** Set up parameter Date value @param Index the target parameter index @param Value the source value } procedure TZASASQLDA.UpdateDate(const Index: Integer; Value: TDateTime); begin UpdateDateTime(Index, Value); FDeclType[Index].sqlType := DT_DATE; end; {** Set up parameter Time value @param Index the target parameter index @param Value the source value } procedure TZASASQLDA.UpdateTime(const Index: Integer; Value: TDateTime); begin UpdateDateTime(Index, Value); FDeclType[Index].sqlType := DT_TIME; end; {** Set up parameter DateTime value @param Index the target parameter index @param Value the source value } procedure TZASASQLDA.UpdateDateTime(const Index: Integer; Value: TDateTime); var y, m, d: word; hr, min, sec, msec: word; begin CheckIndex( Index); SetFieldType( Index, DT_TIMESTAMP_STRUCT or 1, SizeOf( TZASASQLDateTime)); with FSQLDA.sqlvar[Index] do begin case sqlType and $FFFE of DT_TIMESTAMP_STRUCT: begin DecodeDate( Value, y, m, d); DecodeTime( Value, hr, min, sec, msec); PZASASQLDateTime( sqlData).Year := y; PZASASQLDateTime( sqlData).Month := m - 1; PZASASQLDateTime( sqlData).Day := d; PZASASQLDateTime( sqlData).Hour := hr; PZASASQLDateTime( sqlData).Minute := min; PZASASQLDateTime( sqlData).Second := sec; PZASASQLDateTime( sqlData).MicroSecond := msec * 1000; PZASASQLDateTime( sqlData).Day_of_Week := 0; PZASASQLDateTime( sqlData).Day_of_Year := 0; end; else CreateException( SUnsupportedParameterType); end; if (sqlind <> nil) then sqlind^ := 0; // not null end; FDeclType[Index].sqlType := DT_TIMESTAMP; end; {** Set up parameter Timestamp value @param Index the target parameter index @param Value the source value } procedure TZASASQLDA.UpdateTimestamp(const Index: Integer; Value: TDateTime); begin UpdateDateTime(Index, Value); end; {** Set up parameter Type value @param Index the target parameter index @param Value the source value } procedure TZASASQLDA.UpdateValue(const Index: Word; Value: Variant); begin case VarType(Value) of varEmpty, varNull : UpdateNull( Index, True); varSmallint : UpdateShort( Index, Value); varInteger : UpdateInt( Index, Value); varSingle : UpdateFloat( Index, Value); varDouble : UpdateDouble( Index, Value); varCurrency : UpdateBigDecimal( Index, Value); varDate : UpdateDateTime( Index, Value); varStrArg, varString : UpdateString(Index, AnsiString(Value)); varOleStr : UpdateString(Index, FPlainDriver.ZPlainString(WideString(Value), FConSettings)); varBoolean : UpdateBoolean( Index, Value); varByte : UpdateByte( Index, Value); varInt64 : UpdateLong( Index, Value); varShortInt : UpdateByte( Index, Value); varLongWord : UpdateInt( Index, Value); varWord : UpdateShort( Index, Value); else if VarArrayDimCount( Value) = 1 then begin UpdateBytes( Index, VarArrayLock( Value)); VarArrayUnlock( Value); end else CreateException( SUnsupportedParameterType); end; end; {** Write stream to blob field @param Index an index field number @param Stream the souse data stream } procedure TZASASQLDA.WriteBlob(const Index: Integer; Stream: TStream; const BlobType: TZSQLType); var BlobSize: Integer; begin CheckIndex( Index); stream.Position := 0; BlobSize := stream.Size; case BlobType of stAsciiStream: SetFieldType( Index, DT_LONGVARCHAR or 1, BlobSize); stUnicodeStream: SetFieldType( Index, DT_LONGNVARCHAR or 1, BlobSize); stBinaryStream: SetFieldType( Index, DT_LONGBINARY or 1, BlobSize); else CreateException( SUnsupportedParameterType); end; {case FSQLDA.sqlvar[Index].sqlType and $FFFE of DT_LONGVARCHAR: SetFieldType( Index, DT_LONGVARCHAR or 1, BlobSize); DT_LONGBINARY: SetFieldType( Index, DT_LONGBINARY or 1, BlobSize); DT_LONGNVARCHAR: SetFieldType( Index, DT_LONGNVARCHAR or 1, BlobSize); end; SetFieldType( Index, DT_LONGBINARY or 1, BlobSize);} with FSQLDA.sqlvar[Index] do begin case sqlType and $FFFE of DT_LONGVARCHAR, DT_LONGNVARCHAR, DT_LONGBINARY: begin stream.ReadBuffer( PZASABlobStruct( sqlData).arr[0], BlobSize); stream.Position := 0; PZASABlobStruct( sqlData).stored_len := BlobSize; PZASABlobStruct( sqlData).untrunc_len := BlobSize; end; else CreateException( SUnsupportedParameterType); end; if (sqlind <> nil) then sqlind^ := 0; // not null end; end; {** Indicate field null @param Index the field index @return true if fied value NULL overwise false } function TZASASQLDA.IsNull(const Index: Integer): Boolean; begin CheckIndex( Index); with FSQLDA.sqlvar[Index] do Result := Assigned( sqlind) and (sqlind^ < 0); end; {** Indicate sqldata assigned @param Index the field index @return true if assigned field data } function TZASASQLDA.IsAssigned(const Index: Integer): Boolean; begin CheckIndex( Index); with FSQLDA.sqlvar[Index] do Result := Assigned( sqldata); end; {** Return BigDecimal field value @param Index the field index @return the field BigDecimal value } function TZASASQLDA.GetBigDecimal(const Index: Integer): Extended; var s: RawByteString; begin CheckRange(Index); with FSQLDA.sqlvar[Index] do begin Result := 0; if (sqlind^ < 0) then Exit; case sqlType and $FFFE of DT_SMALLINT : Result := PSmallint(sqldata)^; DT_UNSSMALLINT : Result := PWord(sqldata)^; DT_INT : Result := PInteger(sqldata)^; DT_UNSINT : Result := PLongWord(sqldata)^; DT_FLOAT : Result := PSingle(sqldata)^; DT_DOUBLE : Result := PDouble(sqldata)^; DT_VARCHAR: begin {$IFDEF WITH_RAWBYTESTRING} SetLength(s, PZASASQLSTRING( sqlData).length); Move(PAnsiChar(@PZASASQLSTRING(sqlData).data[0])^, PAnsichar(s)^, PZASASQLSTRING( sqlData).length); {$ELSE} SetString(s, PAnsiChar(@PZASASQLSTRING(sqlData).data[0]), PZASASQLSTRING( sqlData).length); {$ENDIF} Result := ZStrToFloat(s); end; DT_TINYINT, DT_BIT : Result := PByte(sqldata)^; DT_BIGINT, DT_UNSBIGINT : Result := PInt64(sqldata)^; else CreateException( Format( SErrorConvertionField, [ GetFieldName(Index), ConvertASATypeToString( sqlType)])); end; end; end; {** Return Boolean field value @param Index the field index @return the field boolean value } function TZASASQLDA.GetBoolean(const Index: Integer): Boolean; var s: RawByteString; begin CheckRange(Index); with FSQLDA.sqlvar[Index] do begin Result := False; if (sqlind^ < 0) then Exit; case sqlType and $FFFE of DT_SMALLINT : Result := PSmallint(sqldata)^ <> 0; DT_UNSSMALLINT : Result := PWord(sqldata)^ <> 0; DT_INT : Result := PInteger(sqldata)^ <> 0; DT_UNSINT : Result := PLongWord(sqldata)^ <> 0; DT_FLOAT : Result := PSingle(sqldata)^ <> 0; DT_DOUBLE : Result := PDouble(sqldata)^ <> 0; DT_VARCHAR: begin {$IFDEF WITH_RAWBYTESTRING} SetLength(s, PZASASQLSTRING( sqlData).length); Move(PAnsiChar(@PZASASQLSTRING(sqlData).data[0])^, PAnsiChar(S)^, PZASASQLSTRING( sqlData).length); {$ELSE} SetString(s, PAnsiChar(@PZASASQLSTRING(sqlData).data[0]), PZASASQLSTRING( sqlData).length); {$ENDIF} Result := StrToInt(String(s)) = 1; end; DT_TINYINT, DT_BIT : Result := PByte(sqldata)^ <> 0; DT_BIGINT, DT_UNSBIGINT : Result := PInt64(sqldata)^ <> 0; else CreateException( Format( SErrorConvertionField, [ GetFieldName(Index), ConvertASATypeToString( sqlType)])); end; end; end; {** Return Byte field value @param Index the field index @return the field Byte value } function TZASASQLDA.GetByte(const Index: Integer): Byte; var s: RawByteString; begin CheckRange(Index); with FSQLDA.sqlvar[Index] do begin Result := 0; if (sqlind^ < 0) then Exit; case sqlType and $FFFE of DT_SMALLINT : Result := PSmallint(sqldata)^; DT_UNSSMALLINT : Result := PWord(sqldata)^; DT_INT : Result := PInteger(sqldata)^; DT_UNSINT : Result := PLongWord(sqldata)^; DT_FLOAT : Result := Trunc( PSingle(sqldata)^); DT_DOUBLE : Result := Trunc( PDouble(sqldata)^); DT_VARCHAR: begin {$IFDEF WITH_RAWBYTESTRING} SetLength(s, PZASASQLSTRING( sqlData).length); Move(PAnsiChar(@PZASASQLSTRING(sqlData).data[0])^, PAnsiChar(S)^, PZASASQLSTRING( sqlData).length); {$ELSE} SetString(s, PAnsiChar(@PZASASQLSTRING(sqlData).data[0]), PZASASQLSTRING( sqlData).length); {$ENDIF} Result := StrToInt(String(s)); end; DT_TINYINT, DT_BIT : Result := PByte(sqldata)^; DT_BIGINT, DT_UNSBIGINT : Result := PInt64(sqldata)^; else CreateException( Format( SErrorConvertionField, [ GetFieldName(Index), ConvertASATypeToString( sqlType)])); end; end; end; {** Return Bytes field value @param Index the field index @return the field Bytes value } function TZASASQLDA.GetBytes(const Index: Integer): TByteDynArray; begin CheckRange(Index); with FSQLDA.sqlvar[Index] do begin Result := nil; if (sqlind^ < 0) then Exit; case sqlType and $FFFE of DT_BINARY: begin SetLength( Result, PZASASQLSTRING( sqlData).length); Move(PZASASQLSTRING(sqlData).data[0], Result[0], PZASASQLSTRING(sqlData).length); end; else CreateException( Format( SErrorConvertionField, [ GetFieldName(Index), ConvertASATypeToString( sqlType)])); end; end; end; {** Return Date field value @param Index the field index @return the field Date value } function TZASASQLDA.GetDate(const Index: Integer): TDateTime; begin Result := Trunc( GetTimestamp( Index)); end; {** Return Double field value @param Index the field index @return the field Double value } function TZASASQLDA.GetDouble(const Index: Integer): Double; var s: RawByteString; begin CheckRange(Index); with FSQLDA.sqlvar[Index] do begin Result := 0; if (sqlind^ < 0) then Exit; case sqlType and $FFFE of DT_SMALLINT : Result := PSmallint(sqldata)^; DT_UNSSMALLINT : Result := PWord(sqldata)^; DT_INT : Result := PInteger(sqldata)^; DT_UNSINT : Result := PLongWord(sqldata)^; DT_FLOAT : Result := PSingle(sqldata)^; DT_DOUBLE : Result := PDouble(sqldata)^; DT_VARCHAR: begin {$IFDEF WITH_RAWBYTESTRING} SetLength(s, PZASASQLSTRING( sqlData).length); Move(PAnsiChar(@PZASASQLSTRING(sqlData).data[0])^, PAnsiChar(S)^, PZASASQLSTRING( sqlData).length); {$ELSE} SetString(s, PAnsiChar(@PZASASQLSTRING(sqlData).data[0]), PZASASQLSTRING( sqlData).length); {$ENDIF} Result := ZStrToFloat(s); end; DT_TINYINT, DT_BIT : Result := PByte(sqldata)^; DT_BIGINT, DT_UNSBIGINT : Result := PInt64(sqldata)^; else CreateException( Format( SErrorConvertionField, [ GetFieldName(Index), ConvertASATypeToString( sqlType)])); end; end; end; {** Return Float field value @param Index the field index @return the field Float value } function TZASASQLDA.GetFloat(const Index: Integer): Single; var s: RawByteString; begin CheckRange(Index); with FSQLDA.sqlvar[Index] do begin Result := 0; if (sqlind^ < 0) then Exit; case sqlType and $FFFE of DT_SMALLINT : Result := PSmallint(sqldata)^; DT_UNSSMALLINT : Result := PWord(sqldata)^; DT_INT : Result := PInteger(sqldata)^; DT_UNSINT : Result := PLongWord(sqldata)^; DT_FLOAT : Result := PSingle(sqldata)^; DT_DOUBLE : Result := PDouble(sqldata)^; DT_VARCHAR: begin {$IFDEF WITH_RAWBYTESTRING} SetLength(s, PZASASQLSTRING( sqlData).length); Move(PAnsiChar(@PZASASQLSTRING(sqlData).data[0])^, PAnsiChar(S)^, PZASASQLSTRING( sqlData).length); {$ELSE} SetString(s, PAnsiChar(@PZASASQLSTRING(sqlData).data[0]), PZASASQLSTRING( sqlData).length); {$ENDIF} Result := ZStrToFloat(s); end; DT_TINYINT, DT_BIT : Result := PByte(sqldata)^; DT_BIGINT, DT_UNSBIGINT : Result := PInt64(sqldata)^; else CreateException( Format( SErrorConvertionField, [ GetFieldName(Index), ConvertASATypeToString( sqlType)])); end; end; end; {** Return Integer field value @param Index the field index @return the field Integer value } function TZASASQLDA.GetInt(const Index: Integer): Integer; var s: RawByteString; begin CheckRange(Index); with FSQLDA.sqlvar[Index] do begin Result := 0; if (sqlind^ < 0) then Exit; case sqlType and $FFFE of DT_SMALLINT : Result := PSmallint(sqldata)^; DT_UNSSMALLINT : Result := PWord(sqldata)^; DT_INT : Result := PInteger(sqldata)^; DT_UNSINT : Result := PLongWord(sqldata)^; DT_FLOAT : Result := Trunc( PSingle(sqldata)^); DT_DOUBLE : Result := Trunc( PDouble(sqldata)^); DT_VARCHAR: begin {$IFDEF WITH_RAWBYTESTRING} SetLength(s, PZASASQLSTRING( sqlData).length); Move(PAnsiChar(@PZASASQLSTRING(sqlData).data[0])^, PAnsiChar(S)^, PZASASQLSTRING( sqlData).length); {$ELSE} SetString(s, PAnsiChar(@PZASASQLSTRING(sqlData).data[0]), PZASASQLSTRING( sqlData).length); {$ENDIF} Result := StrToInt(String(s)); end; DT_TINYINT, DT_BIT : Result := PByte(sqldata)^; DT_BIGINT, DT_UNSBIGINT : Result := PInt64(sqldata)^; else CreateException( Format( SErrorConvertionField, [ GetFieldName(Index), ConvertASATypeToString( sqlType)])); end; end; end; {** Return Long field value @param Index the field index @return the field Long value } function TZASASQLDA.GetLong(const Index: Integer): Int64; var s: RawByteString; begin CheckRange(Index); with FSQLDA.sqlvar[Index] do begin Result := 0; if (sqlind^ < 0) then Exit; case sqlType and $FFFE of DT_SMALLINT : Result := PSmallint(sqldata)^; DT_UNSSMALLINT : Result := PWord(sqldata)^; DT_INT : Result := PInteger(sqldata)^; DT_UNSINT : Result := PLongWord(sqldata)^; DT_FLOAT : Result := Trunc( PSingle(sqldata)^); DT_DOUBLE : Result := Trunc( PDouble(sqldata)^); DT_VARCHAR: begin {$IFDEF WITH_RAWBYTESTRING} SetLength(s, PZASASQLSTRING( sqlData).length); Move(PAnsiChar(@PZASASQLSTRING(sqlData).data[0])^, PAnsiChar(S)^, PZASASQLSTRING( sqlData).length); {$ELSE} SetString(s, PAnsiChar(@PZASASQLSTRING(sqlData).data[0]), PZASASQLSTRING( sqlData).length); {$ENDIF} Result := StrToInt64(String(s)); end; DT_TINYINT, DT_BIT : Result := PByte(sqldata)^; DT_BIGINT, DT_UNSBIGINT : Result := PInt64(sqldata)^; else CreateException( Format( SErrorConvertionField, [ GetFieldName(Index), ConvertASATypeToString( sqlType)])); end; end; end; {** Return PAnsiChar field value @param Index the field index @return the field PAnsiChar value } function TZASASQLDA.GetPChar(const Index: Integer): PAnsiChar; begin CheckRange(Index); with FSQLDA.sqlvar[Index] do begin Result := nil; if (sqlind^ < 0) then Exit; case sqlType and $FFFE of DT_VARCHAR: begin GetMem( Result, PZASASQLSTRING( sqlData).length + 1); {$IFDEF WITH_STRLCOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrLCopy( Result, @PZASASQLSTRING( sqlData).data[0], PZASASQLSTRING( sqlData).length); end; else Result := PAnsiChar(GetString(Index)); end; end; end; {** Return String field value @param Index the field index @return the field String value } function TZASASQLDA.GetString(const Index: Integer): RawByteString; begin CheckRange(Index); with FSQLDA.sqlvar[Index] do begin Result := ''; if (sqlind^ < 0) then Exit; case sqlType and $FFFE of DT_SMALLINT : Result := RawByteString(IntToStr( PSmallint(sqldata)^)); DT_UNSSMALLINT : Result := RawByteString(IntToStr( PWord(sqldata)^)); DT_INT : Result := RawByteString(IntToStr( PInteger(sqldata)^)); DT_UNSINT : Result := RawByteString(IntToStr( PLongWord(sqldata)^)); DT_FLOAT : Result := RawByteString(FloatToStr( PSingle(sqldata)^)); DT_DOUBLE : Result := RawByteString(FloatToStr( PDouble(sqldata)^)); DT_VARCHAR : begin {$IFDEF WITH_RAWBYTESTRING} SetLength(Result, PZASASQLSTRING( sqlData).length); Move(PAnsiChar(@PZASASQLSTRING(sqlData).data[0])^, PAnsiChar(Result)^, PZASASQLSTRING( sqlData).length); {$ELSE} SetString(Result, PAnsiChar(@PZASASQLSTRING(sqlData).data[0]), PZASASQLSTRING( sqlData).length); {$ENDIF} end; DT_LONGVARCHAR : ReadBlobToString( Index, Result); DT_TIMESTAMP_STRUCT : Result := RawByteString(DateToStr( GetTimestamp( Index))); DT_TINYINT : Result := RawByteString(IntToStr( PByte(sqldata)^)); DT_BIT : Result := RawByteString(BoolToStr( ( PByte(sqldata)^ = 1), True)); DT_BIGINT, DT_UNSBIGINT : Result := RawByteString(IntToStr( PInt64(sqldata)^)); else CreateException( Format( SErrorConvertionField, [ GetFieldName(Index), ConvertASATypeToString( sqlType)])); end; end; end; {** Return Short field value @param Index the field index @return the field Short value } function TZASASQLDA.GetShort(const Index: Integer): SmallInt; var s: RawByteString; begin CheckRange(Index); with FSQLDA.sqlvar[Index] do begin Result := 0; if (sqlind^ < 0) then Exit; case sqlType and $FFFE of DT_SMALLINT : Result := PSmallint(sqldata)^; DT_UNSSMALLINT : Result := PWord(sqldata)^; DT_INT : Result := PInteger(sqldata)^; // DT_UNSINT : Result := PLongWord(sqldata)^; DT_FLOAT : Result := Trunc( PSingle(sqldata)^); DT_DOUBLE : Result := Trunc( PDouble(sqldata)^); DT_VARCHAR: begin {$IFDEF WITH_RAWBYTESTRING} SetLength(s, PZASASQLSTRING( sqlData).length); Move(PAnsiChar(@PZASASQLSTRING(sqlData).data[0])^, PAnsiChar(S)^, PZASASQLSTRING( sqlData).length); {$ELSE} SetString(s, PAnsiChar(@PZASASQLSTRING(sqlData).data[0]), PZASASQLSTRING( sqlData).length); {$ENDIF} Result := StrToInt(String(s)); end; DT_TINYINT, DT_BIT : Result := PByte(sqldata)^; DT_BIGINT, DT_UNSBIGINT : Result := PInt64(sqldata)^; else CreateException( Format( SErrorConvertionField, [ GetFieldName(Index), ConvertASATypeToString( sqlType)])); end; end; end; {** Return Time field value @param Index the field index @return the field Time value } function TZASASQLDA.GetTime(const Index: Integer): TDateTime; begin Result := Frac( GetTimestamp( Index)); end; {** Return Timestamp field value @param Index the field index @return the field Timestamp value } function TZASASQLDA.GetTimestamp(const Index: Integer): TDateTime; begin CheckRange( Index); with FSQLDA.sqlvar[Index] do begin Result := 0; if (sqlind^ < 0) then Exit; case sqlType and $FFFE of DT_TIMESTAMP_STRUCT: begin Result := EncodeDate( PZASASQLDateTime( sqlData).Year, PZASASQLDateTime( sqlData).Month + 1, PZASASQLDateTime( sqlData).Day) + EncodeTime( PZASASQLDateTime( sqlData).Hour, PZASASQLDateTime( sqlData).Minute, PZASASQLDateTime( sqlData).Second, PZASASQLDateTime( sqlData).MicroSecond div 1000); end; else CreateException( Format( SErrorConvertionField, [ GetFieldName(Index), ConvertASATypeToString( sqlType)])); end; end; end; {** Return Variant field value @param Index the field index @return the field Variant value } function TZASASQLDA.GetValue(const Index: Word): Variant; var s: RawByteString; begin CheckRange(Index); with FSQLDA.sqlvar[Index] do begin VarClear(Result); if (sqlind^ < 0) then Exit; case sqlType and $FFFE of DT_SMALLINT : Result := PSmallint(sqldata)^; DT_UNSSMALLINT : Result := PWord(sqldata)^; DT_INT : Result := PInteger(sqldata)^; // DT_UNSINT : Result := PLongWord(sqldata)^; DT_FLOAT : Result := PSingle(sqldata)^; DT_DOUBLE : Result := PDouble(sqldata)^; DT_VARCHAR: begin {$IFDEF WITH_RAWBYTESTRING} SetLength(s, PZASASQLSTRING( sqlData).length); Move(PAnsiChar(@PZASASQLSTRING(sqlData).data[0])^, PAnsiChar(S)^, PZASASQLSTRING( sqlData).length); {$ELSE} SetString(s, PAnsiChar(@PZASASQLSTRING(sqlData).data[0]), PZASASQLSTRING( sqlData).length); {$ENDIF} Result := s; end; DT_LONGVARCHAR, DT_LONGBINARY : ReadBlobToVariant(Index, Result); DT_TIMESTAMP_STRUCT : Result := GetTimeStamp( Index); DT_TINYINT : Result := PByte(sqldata)^; DT_BIT : Result := Boolean( PByte(sqldata)^); DT_BIGINT, DT_UNSBIGINT : Result := PInt64(sqldata)^; else CreateException( Format( SErrorConvertionField, [ GetFieldName(Index), ConvertASATypeToString( sqlType)])); end; end; end; procedure TZASASQLDA.ReadBlob(const Index: Word; Buffer: Pointer; Length: LongWord); var TempSQLDA: PASASQLDA; Offs, Rd: LongWord; const BlockSize = 32700; begin with FSQLDA.sqlvar[Index] do begin if ( ( sqlType and $FFFE = DT_LONGVARCHAR) or ( sqlType and $FFFE = DT_LONGNVARCHAR) or ( sqlType and $FFFE = DT_LONGBINARY)) and ( PZASABlobStruct( sqlData).array_len > 0) then begin Assert( PZASABlobStruct( sqlData).array_len = PZASABlobStruct( sqlData).untrunc_len, 'Blob Record is not correctly initialized'); if PZASABlobStruct( sqlData).array_len <> Length then CreateException( 'Could''nt complete BLOB-Read'); move( PZASABlobStruct( sqlData).arr[0], PAnsiChar( Buffer)[0], PZASABlobStruct( sqlData).array_len); end else begin TempSQLDA := FPlainDriver.db_alloc_sqlda( 1); if not Assigned( TempSQLDA) then CreateException( 'Not enough memory for SQLDA'); try with TempSQLDA.sqlvar[ 0] do begin case Self.GetFieldSqlType(Index) of stAsciiStream: SetFieldType(TempSQLDA, 0, DT_LONGVARCHAR, Min( BlockSize, Length)); stUnicodeStream: SetFieldType(TempSQLDA, 0, DT_LONGNVARCHAR, Min( BlockSize, Length)); stBinaryStream: SetFieldType(TempSQLDA, 0, DT_LONGBINARY, Min( BlockSize, Length)); else sqlType := DT_FIXCHAR; end; sqlname.length := 0; sqlname.data[0] := #0; TempSQLDA.sqld := TempSQLDA.sqln; Offs := 0; Rd := 0; while True do begin FPlainDriver.db_get_data(FHandle, PAnsiChar(FCursorName), Index + 1, Offs, TempSQLDA); CheckASAError( FPlainDriver, FHandle, lcOther); if ( sqlind^ < 0 ) then break; Inc( Rd, PZASABlobStruct( sqlData)^.stored_len); if Offs = 0 then ReallocMem(Buffer, PZASABlobStruct( sqlData)^.untrunc_len); Move((PZASABlobStruct( sqlData)^.arr[0]), (PAnsiChar(Buffer)+Offs)^, PZASABlobStruct( sqlData)^.stored_len); if ( sqlind^ = 0 ) or ( RD = Length) then break; Inc( Offs, PZASABlobStruct( sqlData)^.stored_len); sqllen := Min( BlockSize, Length-Rd); end; if Rd <> Length then CreateException( 'Could''nt complete BLOB-Read'); DriverManager.LogMessage( lcExecute, FPlainDriver.GetProtocol, Format( 'GET DATA for Column: %s', [ GetFieldName(Index)])); FreeMem(sqlData, SizeOf(TZASABlobStruct)+Min( BlockSize, Length)); FPlainDriver.db_free_sqlda( TempSQLDA); TempSQLDA := nil; end; except if Assigned( TempSQLDA) then FPlainDriver.db_free_sqlda( TempSQLDA); raise; end; end; end; end; {** Read blob data to Buffer @param Index an filed index @param Str destination string } procedure TZASASQLDA.ReadBlobToMem(const Index: Word; var Buffer: Pointer; var Length: LongWord); begin CheckRange(Index); with FSQLDA.sqlvar[Index] do begin Buffer := nil; Length := 0; if (sqlind^ < 0) then Exit; if ( ( sqlType and $FFFE = DT_LONGVARCHAR) or ( sqlType and $FFFE = DT_LONGBINARY)) then begin Length := PZASABlobStruct( sqlData).untrunc_len; GetMem( Buffer, Length); ReadBlob( Index, Buffer, Length); end else CreateException( Format( SErrorConvertionField, [ GetFieldName(Index), ConvertASATypeToString( sqlType)])); end; end; {** Read blob data to string @param Index an filed index @param Str destination string } procedure TZASASQLDA.ReadBlobToString(const Index: Word; var Str: RawByteString); begin CheckRange(Index); with FSQLDA.sqlvar[Index] do begin Str := ''; if (sqlind^ < 0) then Exit; if sqlType and $FFFE = DT_LONGVARCHAR then begin SetLength( Str, PZASABlobStruct( sqlData).untrunc_len); ReadBlob(Index, PAnsiChar(Str), Length(Str)); end else CreateException( Format( SErrorConvertionField, [ GetFieldName(Index), ConvertASATypeToString( sqlType)])); end; end; {** Read blob data to stream @param Index an filed index @param Stream destination stream object } procedure TZASASQLDA.ReadBlobToStream(const Index: Word; Stream: TStream); begin CheckRange(Index); with FSQLDA.sqlvar[Index] do begin Stream.Size := 0; if (sqlind^ < 0) then Exit; if ( ( sqlType and $FFFE = DT_LONGVARCHAR) or ( sqlType and $FFFE = DT_LONGBINARY)) and ( Stream is TMemoryStream) then begin Stream.Size := PZASABlobStruct( sqlData).untrunc_len; ReadBlob( Index, TMemoryStream( Stream).Memory, Stream.Size); end else CreateException( Format( SErrorConvertionField, [ GetFieldName(Index), ConvertASATypeToString( sqlType)])); end; end; {** Read blob data to variant value @param Index an filed index @param Value destination variant value } procedure TZASASQLDA.ReadBlobToVariant(const Index: Word; var Value: Variant); var PData: Pointer; begin CheckRange(Index); with FSQLDA.sqlvar[Index] do begin Value := Null; if (sqlind^ < 0) then Exit; if ( ( sqlType and $FFFE = DT_LONGVARCHAR) or ( sqlType and $FFFE = DT_LONGBINARY)) then begin Value := VarArrayCreate( [ 0, PZASABlobStruct( sqlData).untrunc_len-1], varByte); PData := VarArrayLock( Value); try ReadBlob( Index, PData, PZASABlobStruct( sqlData).untrunc_len); finally VarArrayUnlock( Value); end; end else CreateException( Format( SErrorConvertionField, [ GetFieldName(Index), ConvertASATypeToString( sqlType)])); end; end; {** Converts a ASA native types into ZDBC SQL types. @param SQLType Field of TASASQLVar structure. @return a SQL undepended type. } function ConvertASATypeToSQLType(const SQLType: SmallInt; const CtrlsCPType: TZControlsCodePage): TZSQLType; begin case SQLType and $FFFE of DT_NOTYPE: Result := stUnknown; DT_SMALLINT: Result := stShort; DT_INT: Result := stInteger; DT_DECIMAL: Result := stDouble; //BCD Fields not supported DT_FLOAT: Result := stFloat; DT_DOUBLE: Result := stDouble; DT_DATE: Result := stDate; DT_VARIABLE, DT_STRING, DT_FIXCHAR, DT_VARCHAR, DT_NSTRING, DT_NFIXCHAR, DT_NVARCHAR: if (CtrlsCPType = cCP_UTF16) then Result := stUnicodeString else Result := stString; DT_LONGVARCHAR, DT_LONGNVARCHAR: if (CtrlsCPType = cCP_UTF16) then Result := stUnicodeStream else Result := stAsciiStream; DT_TIME: Result := stTime; DT_TIMESTAMP: Result := stTimestamp; DT_TIMESTAMP_STRUCT: Result := stTimestamp; DT_BINARY: Result := stBytes; DT_LONGBINARY: Result := stBinaryStream; DT_TINYINT: Result := stByte; DT_BIGINT: Result := stLong; DT_UNSINT: Result := stInteger; DT_UNSSMALLINT: Result := stShort; DT_UNSBIGINT: Result := stLong; DT_BIT: Result := stBoolean; else Result := stUnknown; end; end; {** Converts a ASA native type into String. @param SQLType Field of TASASQLVar structure. @return type description. } function ConvertASATypeToString( SQLType: SmallInt): String; begin case SQLType and $FFFE of DT_SMALLINT: Result := 'DT_SMALLINT'; DT_INT: Result := 'DT_INT'; DT_DECIMAL: Result := 'DT_DECIMAL'; //BCD Fields not supported DT_FLOAT: Result := 'DT_FLOAT'; DT_DOUBLE: Result := 'DT_DOUBLE'; DT_DATE: Result := 'DT_DATE'; DT_VARIABLE: Result := 'DT_VARIABLE'; DT_STRING: Result := 'DT_STRING'; DT_FIXCHAR: Result := 'DT_FIXCHAR'; DT_VARCHAR: Result := 'DT_VARCHAR'; DT_LONGVARCHAR: Result := 'DT_LONGVARCHAR'; DT_TIME: Result := 'DT_TIME'; DT_TIMESTAMP: Result := 'DT_TIMESTAMP'; DT_TIMESTAMP_STRUCT: Result := 'DT_TIMESTAMP_STRUCT'; DT_BINARY: Result := 'DT_BINARY'; DT_LONGBINARY: Result := 'DT_LONGBINARY'; DT_TINYINT: Result := 'DT_TINYINT'; DT_BIGINT: Result := 'DT_BIGINT'; DT_UNSINT: Result := 'DT_UNSINT'; DT_UNSSMALLINT: Result := 'DT_UNSSMALLINT'; DT_UNSBIGINT: Result := 'DT_UNSBIGINT'; DT_BIT: Result := 'DT_BIT'; DT_NSTRING: Result := 'DT_NSTRING'; DT_NFIXCHAR: Result := 'DT_NFIXCHAR'; DT_NVARCHAR: Result := 'DT_NVARCHAR'; DT_LONGNVARCHAR: Result := 'DT_LONGNVARCHAR'; else Result := 'Unknown'; end; end; {** Converts an ODBC native types into ZDBC SQL types. @param FieldType dblibc native field type. @return a SQL undepended type. } function ConvertASAJDBCToSqlType(const FieldType: SmallInt; CtrlsCPType: TZControlsCodePage): TZSQLType; begin case FieldType of 1, 12, -8, -9: if (CtrlsCPType = cCP_UTF16) then Result := stUnicodeString else Result := stString; -7: Result := stBoolean; -6: Result := stByte; 5: Result := stShort; 4: Result := stInteger; -5 : Result := stLong; 6, 7, 8: Result := stDouble; 2, 3: Result := stDouble; //BCD Feld 11, 93: Result := stTimestamp; -1, -10: if (CtrlsCPType = cCP_UTF16) then Result := stUnicodeStream else Result := stAsciiStream; -4, -11, 1111: Result := stBinaryStream; -3, -2: Result := stBytes; 92: Result := stTime; 91: Result := stDate; else Result := stUnknown; end; end; { procedure TSQLTimeStampToASADateTime( DT: TSQLTimeStamp; const ASADT: PZASASQLDateTime); begin ASADT.Year := DT.Year; ASADT.Month := DT.Month - 1; ASADT.Day := DT.Day; ASADT.Hour := DT.Hour; ASADT.Minute := DT.Minute; ASADT.Second := DT.Second; ASADT.MicroSecond := DT.Fractions * 10; ASADT.Day_of_Week := 0; ASADT.Day_of_Year := 0; end; function ASADateTimeToSQLTimeStamp( ASADT: PZASASQLDateTime): TSQLTimeStamp; begin DT.Year := ASADT.Year; DT.Month := ASADT.Month + 1; DT.Day := ASADT.Day; DT.Hour := ASADT.Hour; DT.Minute := ASADT.Minute; DT.Second := ASADT.Second; DT.Fractions := ASADT.MicroSecond div 10; end; } {** Checks for possible sql errors. @param PlainDriver a MySQL plain driver. @param Handle a MySQL connection handle. @param LogCategory a logging category. @param LogMessage a logging message. } procedure CheckASAError( PlainDriver: IZASAPlainDriver; Handle: PZASASQLCA; LogCategory: TZLoggingCategory; LogMessage: string = ''; SupressExceptionID: Integer = 0); var ErrorBuf: array[0..1024] of AnsiChar; ErrorMessage: string; begin if Handle.SqlCode < SQLE_NOERROR then begin ErrorMessage := String(PlainDriver.sqlError_Message( Handle, ErrorBuf, SizeOf( ErrorBuf))); //SyntaxError Position in SQLCount if not (SupressExceptionID = Handle.SqlCode ) then begin DriverManager.LogError( LogCategory, PlainDriver.GetProtocol, LogMessage, Handle.SqlCode, ErrorMessage); raise EZSQLException.CreateWithCode( Handle.SqlCode, Format(SSQLError1, [ErrorMessage])); end; end; end; {** Create CachedResultSet with using TZCachedResultSet and return it. @param SQL a sql query command @param Statement a zeos statement object @param NativeResultSet a native result set @return cached ResultSet } function GetCachedResultSet(SQL: string; Statement: IZStatement; NativeResultSet: IZResultSet): IZResultSet; var CachedResultSet: TZCachedResultSet; begin if (Statement.GetResultSetConcurrency <> rcReadOnly) or (Statement.GetResultSetType <> rtForwardOnly) then begin CachedResultSet := TZCachedResultSet.Create( NativeResultSet, SQL, nil, Statement.GetConnection.GetConSettings); CachedResultSet.SetResolver( TZASACachedResolver.Create( Statement, NativeResultSet.GetMetadata)); CachedResultSet.SetConcurrency( Statement.GetResultSetConcurrency); Result := CachedResultSet; end else Result := NativeResultSet; end; procedure DescribeCursor( FASAConnection: IZASAConnection; FSQLData: IZASASQLDA; Cursor: AnsiString; SQL: String); begin FSQLData.AllocateSQLDA( StdVars); with FASAConnection do begin GetPlainDriver.db_describe_cursor(GetDBHandle, PAnsiChar(Cursor), FSQLData.GetData, SQL_DESCRIBE_OUTPUT); ZDbcASAUtils.CheckASAError( GetPlainDriver, GetDBHandle, lcExecute, SQL); if FSQLData.GetData^.sqld <= 0 then raise EZSQLException.Create( SCanNotRetrieveResultSetData) else if ( FSQLData.GetData^.sqld > FSQLData.GetData^.sqln) then begin FSQLData.AllocateSQLDA( FSQLData.GetData^.sqld); GetPlainDriver.db_describe_cursor(GetDBHandle, PAnsiChar(Cursor), FSQLData.GetData, SQL_DESCRIBE_OUTPUT); ZDbcASAUtils.CheckASAError(GetPlainDriver, GetDBHandle, lcExecute, SQL); end; FSQLData.InitFields; end; end; procedure ASAPrepare( FASAConnection: IZASAConnection; FSQLData, FParamsSQLData: IZASASQLDA; const SQL: RawByteString; const LogSQL: String; StmtNum: PSmallInt; var FPrepared, FMoreResults: Boolean); begin with FASAConnection do begin if FPrepared then begin FParamsSQLData.AllocateSQLDA( StdVars); FSQLData.AllocateSQLDA( StdVars); if StmtNum^ <> 0 then begin GetPlainDriver.db_dropstmt( GetDBHandle, nil, nil, StmtNum); StmtNum^ := 0; end; end; try GetPlainDriver.db_prepare_describe( GetDBHandle, nil, StmtNum, PAnsiChar(SQL), FParamsSQLData.GetData, SQL_PREPARE_DESCRIBE_STMTNUM + SQL_PREPARE_DESCRIBE_INPUT + SQL_PREPARE_DESCRIBE_VARRESULT, 0); ZDbcASAUtils.CheckASAError(GetPlainDriver, GetDBHandle, lcExecute, LogSQL); FMoreResults := GetDBHandle.sqlerrd[2] = 0; if FParamsSQLData.GetData^.sqld > FParamsSQLData.GetData^.sqln then begin FParamsSQLData.AllocateSQLDA( FParamsSQLData.GetData^.sqld); GetPlainDriver.db_describe( GetDBHandle, nil, StmtNum, FParamsSQLData.GetData, SQL_DESCRIBE_INPUT); ZDbcASAUtils.CheckASAError( GetPlainDriver, GetDBHandle, lcExecute, LogSQL); end; if not FMoreResults then begin GetPlainDriver.db_describe( GetDBHandle, nil, StmtNum, FSQLData.GetData, SQL_DESCRIBE_OUTPUT); ZDbcASAUtils.CheckASAError( GetPlainDriver, GetDBHandle, lcExecute, LogSQL); if FSQLData.GetData^.sqld > FSQLData.GetData^.sqln then begin FSQLData.AllocateSQLDA( FSQLData.GetData^.sqld); GetPlainDriver.db_describe( GetDBHandle, nil, StmtNum, FSQLData.GetData, SQL_DESCRIBE_OUTPUT); ZDbcASAUtils.CheckASAError( GetPlainDriver, GetDBHandle, lcExecute, LogSQL); end; FSQLData.InitFields; end; FPrepared := true; { Logging SQL Command } DriverManager.LogMessage( lcExecute, GetPlainDriver.GetProtocol, 'Prepare: '+ LogSQL); except on E: Exception do begin if StmtNum^ <> 0 then GetPlainDriver.db_dropstmt( GetDBHandle, nil, nil, StmtNum); raise; end; end; end; end; procedure PrepareParameters( PlainDriver: IZASAPlainDriver; InParamValues: TZVariantDynArray; InParamTypes: TZSQLTypeArray; InParamCount: Integer; ParamSqlData: IZASASQLDA; ConSettings: PZConSettings); var i: Integer; TempBlob: IZBlob; TempStream: TStream; begin if InParamCount <> ParamSqlData.GetFieldCount then raise EZSQLException.Create( SInvalidInputParameterCount); for i := 0 to ParamSqlData.GetFieldCount-1 do if DefVarManager.IsNull( InParamValues[i])then ParamSqlData.UpdateNull( i, True) else case InParamTypes[i] of stBoolean: ParamSqlData.UpdateBoolean( i, SoftVarManager.GetAsBoolean( InParamValues[i])); stByte: ParamSqlData.UpdateByte( i, SoftVarManager.GetAsInteger( InParamValues[i])); stShort: ParamSqlData.UpdateShort( i, SoftVarManager.GetAsInteger( InParamValues[i])); stInteger: ParamSqlData.UpdateInt( i, SoftVarManager.GetAsInteger( InParamValues[i])); stLong: ParamSqlData.UpdateLong( i, SoftVarManager.GetAsInteger( InParamValues[i])); stFloat: ParamSqlData.UpdateFloat( i, SoftVarManager.GetAsFloat( InParamValues[i])); stDouble: ParamSqlData.UpdateDouble( i, SoftVarManager.GetAsFloat( InParamValues[i])); stBigDecimal: ParamSqlData.UpdateBigDecimal( i, SoftVarManager.GetAsFloat( InParamValues[i])); stString: ParamSqlData.UpdateString( i, PlainDriver.ZPlainString(SoftVarManager.GetAsString( InParamValues[i]), ConSettings)); stUnicodeString: ParamSqlData.UpdateString( i, PlainDriver.ZPlainString(SoftVarManager.GetAsUnicodeString( InParamValues[i]), ConSettings)); stBytes: ParamSqlData.UpdateBytes( i, SoftVarManager.GetAsBytes( InParamValues[i])); stDate: ParamSqlData.UpdateDate( i, SoftVarManager.GetAsDateTime( InParamValues[i])); stTime: ParamSqlData.UpdateTime( i, SoftVarManager.GetAsDateTime( InParamValues[i])); stTimestamp: ParamSqlData.UpdateTimestamp( i, SoftVarManager.GetAsDateTime( InParamValues[i])); stAsciiStream, stUnicodeStream, stBinaryStream: begin TempBlob := DefVarManager.GetAsInterface(InParamValues[I]) as IZBlob; if not TempBlob.IsEmpty then begin if (InParamTypes[i] in [stUnicodeStream, stAsciiStream]) then TempStream := TStringStream.Create(GetValidatedAnsiStringFromBuffer(TempBlob.GetBuffer, TempBlob.Length, TempBlob.WasDecoded, ConSettings)) else TempStream := TempBlob.GetStream; if Assigned(TempStream) then begin ParamSqlData.WriteBlob(I, TempStream, InParamTypes[i]); TempStream.Free; end; end; end; else raise EZASAConvertError.Create( SUnsupportedParameterType); end; end; {** Generate specific length random string and return it @param Len a length result string @return random string } function RandomString( Len: integer): string; begin Result := ''; while Length( Result) < Len do Result := Result + IntToStr( Trunc( Random( High( Integer)))); if Length( Result) > Len then Result := Copy( Result, 1, Len); end; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcAdo.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { ADO Connectivity Classes } { } { Originally written by Janos Fegyverneki } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcAdo; interface {$I ZDbc.inc} uses Types, Classes, ZDbcConnection, ZDbcIntfs, ZCompatibility, ZPlainDriver, ZPlainAdoDriver, ZPlainAdo, ZURL, ZTokenizer; type {** Implements Ado Database Driver. } {$WARNINGS OFF} TZAdoDriver = class(TZAbstractDriver) public constructor Create; override; function Connect(const Url: TZURL): IZConnection; override; function GetMajorVersion: Integer; override; function GetMinorVersion: Integer; override; function GetTokenizer: IZTokenizer; override; end; {$WARNINGS ON} {** Represents an Ado specific connection interface. } IZAdoConnection = interface (IZConnection) ['{50D1AF76-0174-41CD-B90B-4FB770EFB14F}'] function GetAdoConnection: ZPlainAdo.Connection; procedure InternalExecuteStatement(const SQL: string); procedure CheckAdoError; end; {** Implements a generic Ado Connection. } TZAdoConnection = class(TZAbstractConnection, IZAdoConnection) private procedure ReStartTransactionSupport; protected FAdoConnection: ZPlainAdo.Connection; function GetAdoConnection: ZPlainAdo.Connection; procedure InternalExecuteStatement(const SQL: string); procedure CheckAdoError; procedure StartTransaction; procedure InternalCreate; override; public destructor Destroy; override; function GetBinaryEscapeString(const Value: TByteDynArray): String; overload; override; function GetBinaryEscapeString(const Value: RawByteString): String; overload; override; function CreateRegularStatement(Info: TStrings): IZStatement; override; function CreatePreparedStatement(const SQL: string; Info: TStrings): IZPreparedStatement; override; function CreateCallableStatement(const SQL: string; Info: TStrings): IZCallableStatement; override; function NativeSQL(const SQL: string): string; override; procedure SetAutoCommit(AutoCommit: Boolean); override; procedure SetTransactionIsolation(Level: TZTransactIsolationLevel); override; procedure Commit; override; procedure Rollback; override; procedure Open; override; procedure Close; override; procedure SetReadOnly(ReadOnly: Boolean); override; procedure SetCatalog(const Catalog: string); override; function GetCatalog: string; override; function GetWarnings: EZSQLWarning; override; procedure ClearWarnings; override; end; var {** The common driver manager object. } AdoDriver: IZDriver; implementation uses Variants, SysUtils, ActiveX, ZDbcUtils, ZDbcLogging, ZAdoToken, ZSysUtils, ZDbcAdoStatement, ZDbcAdoMetaData; const //adXactUnspecified IL: array[TZTransactIsolationLevel] of TOleEnum = (adXactChaos, adXactReadUncommitted, adXactReadCommitted, adXactRepeatableRead, adXactSerializable); { TZDBLibDriver } {** Constructs this object with default properties. } constructor TZAdoDriver.Create; begin inherited Create; AddSupportedProtocol(AddPlainDriverToCache(TZAdoPlainDriver.Create)); end; {** Attempts to make a database connection to the given URL. } {$WARNINGS OFF} function TZAdoDriver.Connect(const Url: TZURL): IZConnection; begin Result := TZAdoConnection.Create(Url); end; {$WARNINGS ON} {** Gets the driver's major version number. Initially this should be 1. @return this driver's major version number } function TZAdoDriver.GetMajorVersion: Integer; begin Result := 1; end; {** Gets the driver's minor version number. Initially this should be 0. @return this driver's minor version number } function TZAdoDriver.GetMinorVersion: Integer; begin Result := 0; end; function TZAdoDriver.GetTokenizer: IZTokenizer; begin if Tokenizer = nil then Tokenizer := TZAdoSQLTokenizer.Create; Result := Tokenizer; end; { TZAdoConnection } procedure TZAdoConnection.InternalCreate; begin FAdoConnection := CoConnection.Create; Self.FMetadata := TZAdoDatabaseMetadata.Create(Self, URL); Open; end; {** Destroys this object and cleanups the memory. } destructor TZAdoConnection.Destroy; begin Close; FAdoConnection := nil; inherited Destroy; end; {** Just return the Ado Connection } function TZAdoConnection.GetAdoConnection: ZPlainAdo.Connection; begin Result := FAdoConnection; end; {** Executes simple statements internally. } procedure TZAdoConnection.InternalExecuteStatement(const SQL: string); var RowsAffected: OleVariant; begin try FAdoConnection.Execute(SQL, RowsAffected, adExecuteNoRecords); DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, SQL); except on E: Exception do begin DriverManager.LogError(lcExecute, PlainDriver.GetProtocol, SQL, 0, E.Message); raise; end; end; end; procedure TZAdoConnection.CheckAdoError; begin end; {** Starts a transaction support. } procedure TZAdoConnection.ReStartTransactionSupport; begin if Closed then Exit; if not (AutoCommit or (GetTransactionIsolation = tiNone)) then StartTransaction; end; {** Opens a connection to database server with specified parameters. } procedure TZAdoConnection.Open; var LogMessage: string; begin if not Closed then Exit; LogMessage := Format('CONNECT TO "%s" AS USER "%s"', [Database, User]); try if ReadOnly then FAdoConnection.Set_Mode(adModeRead) else FAdoConnection.Set_Mode(adModeUnknown); FAdoConnection.Open(Database, User, Password, -1{adConnectUnspecified}); FAdoConnection.Set_CursorLocation(adUseClient); DriverManager.LogMessage(lcConnect, PLainDriver.GetProtocol, LogMessage); if FClientCodePage <> 'CP_ADO' then CheckCharEncoding('CP_ADO', True) except on E: Exception do begin DriverManager.LogError(lcConnect, PlainDriver.GetProtocol, LogMessage, 0, E.Message); raise; end; end; inherited Open; FAdoConnection.IsolationLevel := IL[GetTransactionIsolation]; ReStartTransactionSupport; end; function TZAdoConnection.GetBinaryEscapeString(const Value: TByteDynArray): String; begin Result := GetSQLHexString(PAnsiChar(Value), Length(Value), True); if GetAutoEncodeStrings then Result := GetDriver.GetTokenizer.GetEscapeString(Result) end; function TZAdoConnection.GetBinaryEscapeString(const Value: RawByteString): String; begin Result := GetSQLHexString(PAnsiChar(Value), Length(Value), True); if GetAutoEncodeStrings then Result := GetDriver.GetTokenizer.GetEscapeString(Result) end; {** Creates a Statement object for sending SQL statements to the database. SQL statements without parameters are normally executed using Statement objects. If the same SQL statement is executed many times, it is more efficient to use a PreparedStatement object.

Result sets created using the returned Statement object will by default have forward-only type and read-only concurrency. @param Info a statement parameters. @return a new Statement object } function TZAdoConnection.CreateRegularStatement(Info: TStrings): IZStatement; begin if IsClosed then Open; Result := TZAdoStatement.Create(PlainDriver, Self, '', Info); end; {** Creates a PreparedStatement object for sending parameterized SQL statements to the database. A SQL statement with or without IN parameters can be pre-compiled and stored in a PreparedStatement object. This object can then be used to efficiently execute this statement multiple times.

Note: This method is optimized for handling parametric SQL statements that benefit from precompilation. If the driver supports precompilation, the method prepareStatement will send the statement to the database for precompilation. Some drivers may not support precompilation. In this case, the statement may not be sent to the database until the PreparedStatement is executed. This has no direct effect on users; however, it does affect which method throws certain SQLExceptions. Result sets created using the returned PreparedStatement will have forward-only type and read-only concurrency, by default. @param sql a SQL statement that may contain one or more '?' IN parameter placeholders @param Info a statement parameters. @return a new PreparedStatement object containing the pre-compiled statement } function TZAdoConnection.CreatePreparedStatement( const SQL: string; Info: TStrings): IZPreparedStatement; begin if IsClosed then Open; Result := TZAdoPreparedStatement.Create(PlainDriver, Self, SQL, Info); end; {** Creates a CallableStatement object for calling database stored procedures. The CallableStatement object provides methods for setting up its IN and OUT parameters, and methods for executing the call to a stored procedure.

Note: This method is optimized for handling stored procedure call statements. Some drivers may send the call statement to the database when the method prepareCall is done; others may wait until the CallableStatement object is executed. This has no direct effect on users; however, it does affect which method throws certain SQLExceptions. Result sets created using the returned CallableStatement will have forward-only type and read-only concurrency, by default. @param sql a SQL statement that may contain one or more '?' parameter placeholders. Typically this statement is a JDBC function call escape string. @param Info a statement parameters. @return a new CallableStatement object containing the pre-compiled SQL statement } function TZAdoConnection.CreateCallableStatement(const SQL: string; Info: TStrings): IZCallableStatement; begin if IsClosed then Open; Result := TZAdoCallableStatement.Create(PlainDriver, Self, SQL, Info); end; {** Converts the given SQL statement into the system's native SQL grammar. A driver may convert the JDBC sql grammar into its system's native SQL grammar prior to sending it; this method returns the native form of the statement that the driver would have sent. @param sql a SQL statement that may contain one or more '?' parameter placeholders @return the native form of this statement } function TZAdoConnection.NativeSQL(const SQL: string): string; begin Result := SQL; end; {** Sets this connection's auto-commit mode. If a connection is in auto-commit mode, then all its SQL statements will be executed and committed as individual transactions. Otherwise, its SQL statements are grouped into transactions that are terminated by a call to either the method commit or the method rollback. By default, new connections are in auto-commit mode. The commit occurs when the statement completes or the next execute occurs, whichever comes first. In the case of statements returning a ResultSet, the statement completes when the last row of the ResultSet has been retrieved or the ResultSet has been closed. In advanced cases, a single statement may return multiple results as well as output parameter values. In these cases the commit occurs when all results and output parameter values have been retrieved. @param autoCommit true enables auto-commit; false disables auto-commit. } procedure TZAdoConnection.SetAutoCommit(AutoCommit: Boolean); begin if GetAutoCommit = AutoCommit then Exit; if not Closed and AutoCommit then begin if (FAdoConnection.State = adStateOpen) and (GetTransactionIsolation <> tiNone) then begin FAdoConnection.CommitTrans; DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, 'COMMIT'); end; end; inherited; ReStartTransactionSupport; end; {** Attempts to change the transaction isolation level to the one given. The constants defined in the interface Connection are the possible transaction isolation levels.

Note: This method cannot be called while in the middle of a transaction. @param level one of the TRANSACTION_* isolation values with the exception of TRANSACTION_NONE; some databases may not support other values @see DatabaseMetaData#supportsTransactionIsolationLevel } procedure TZAdoConnection.SetTransactionIsolation( Level: TZTransactIsolationLevel); begin if GetTransactionIsolation = Level then Exit; if not Closed and not AutoCommit and (GetTransactionIsolation <> tiNone) then begin FAdoConnection.CommitTrans; DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, 'COMMIT'); end; inherited; if not Closed then FAdoConnection.IsolationLevel := IL[Level]; RestartTransactionSupport; end; {** Starts a new transaction. Used internally. } procedure TZAdoConnection.StartTransaction; var LogMessage: string; begin LogMessage := 'BEGIN TRANSACTION'; try FAdoConnection.BeginTrans; DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, LogMessage); except on E: Exception do begin DriverManager.LogError(lcExecute, PlainDriver.GetProtocol, LogMessage, 0, E.Message); raise; end; end; end; {** Makes all changes made since the previous commit/rollback permanent and releases any database locks currently held by the Connection. This method should be used only when auto-commit mode has been disabled. @see #setAutoCommit } procedure TZAdoConnection.Commit; var LogMessage: string; begin LogMessage := 'COMMIT'; if not (AutoCommit or (GetTransactionIsolation = tiNone)) then try FAdoConnection.CommitTrans; DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, LogMessage); StartTransaction; except on E: Exception do begin DriverManager.LogError(lcExecute, PlainDriver.GetProtocol, LogMessage, 0, E.Message); raise; end; end; end; {** Drops all changes made since the previous commit/rollback and releases any database locks currently held by this Connection. This method should be used only when auto- commit has been disabled. @see #setAutoCommit } procedure TZAdoConnection.Rollback; var LogMessage: string; begin LogMessage := 'ROLLBACK'; if not (AutoCommit or (GetTransactionIsolation = tiNone)) then try FAdoConnection.RollbackTrans; DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, LogMessage); StartTransaction; except on E: Exception do begin DriverManager.LogError(lcExecute, PlainDriver.GetProtocol, LogMessage, 0, E.Message); raise; end; end; end; {** Releases a Connection's database and JDBC resources immediately instead of waiting for them to be automatically released.

Note: A Connection is automatically closed when it is garbage collected. Certain fatal errors also result in a closed Connection. } procedure TZAdoConnection.Close; var LogMessage: string; begin if Closed or (not Assigned(PlainDriver)) then Exit; SetAutoCommit(True); LogMessage := Format('CLOSE CONNECTION TO "%s"', [Database]); try if FAdoConnection.State = adStateOpen then FAdoConnection.Close; DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, LogMessage); except on E: Exception do begin DriverManager.LogError(lcExecute, PlainDriver.GetProtocol, LogMessage, 0, E.Message); raise; end; end; inherited; end; {** Puts this connection in read-only mode as a hint to enable database optimizations.

Note: This method cannot be called while in the middle of a transaction. @param readOnly true enables read-only mode; false disables read-only mode. } procedure TZAdoConnection.SetReadOnly(ReadOnly: Boolean); begin inherited; end; {** Sets a catalog name in order to select a subspace of this Connection's database in which to work. If the driver does not support catalogs, it will silently ignore this request. } procedure TZAdoConnection.SetCatalog(const Catalog: string); var LogMessage: string; begin if Closed then Exit; LogMessage := Format('SET CATALOG %s', [Catalog]); try FAdoConnection.DefaultDatabase := Catalog; DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, LogMessage); except on E: Exception do begin DriverManager.LogError(lcExecute, PlainDriver.GetProtocol, LogMessage, 0, E.Message); raise; end; end; end; {** Returns the Connection's current catalog name. @return the current catalog name or null } function TZAdoConnection.GetCatalog: string; begin Result := FAdoConnection.DefaultDatabase; end; {** Returns the first warning reported by calls on this Connection.

Note: Subsequent warnings will be chained to this SQLWarning. @return the first SQLWarning or null } function TZAdoConnection.GetWarnings: EZSQLWarning; begin Result := nil; end; {** Clears all warnings reported for this Connection object. After a call to this method, the method getWarnings returns null until a new warning is reported for this Connection. } procedure TZAdoConnection.ClearWarnings; begin end; initialization AdoDriver := TZAdoDriver.Create; DriverManager.RegisterDriver(AdoDriver); finalization if Assigned(DriverManager) then DriverManager.DeregisterDriver(AdoDriver); AdoDriver := nil; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcAdoMetadata.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Ado metadata information } { } { Originally written by Janos Fegyverneki } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcAdoMetadata; interface {$I ZDbc.inc} uses Types, Classes, SysUtils, ZSysUtils, ZClasses, ZDbcIntfs, ZDbcMetadata, ZDbcResultSet, ZDbcCachedResultSet, ZDbcResultsetMetadata, ZURL, ZCompatibility, ZGenericSqlAnalyser, ZPlainAdo, ZDbcConnection; type // technobot 2008-06-27 - methods moved as is from TZAdoDatabaseMetadata: {** Implements Ado Database Information. } TZAdoDatabaseInfo = class(TZAbstractDatabaseInfo) public constructor Create(const Metadata: TZAbstractDatabaseMetadata); // database/driver/server info: function GetDatabaseProductName: string; override; function GetDatabaseProductVersion: string; override; function GetDriverName: string; override; // function GetDriverVersion: string; override; -> Same as parent function GetDriverMajorVersion: Integer; override; function GetDriverMinorVersion: Integer; override; // function GetServerVersion: string; -> Not implemented // capabilities (what it can/cannot do): // function AllProceduresAreCallable: Boolean; override; -> Not implemented // function AllTablesAreSelectable: Boolean; override; -> Not implemented function SupportsMixedCaseIdentifiers: Boolean; override; function SupportsMixedCaseQuotedIdentifiers: Boolean; override; // function SupportsAlterTableWithAddColumn: Boolean; override; -> Not implemented // function SupportsAlterTableWithDropColumn: Boolean; override; -> Not implemented // function SupportsColumnAliasing: Boolean; override; -> Not implemented // function SupportsConvert: Boolean; override; -> Not implemented // function SupportsConvertForTypes(FromType: TZSQLType; ToType: TZSQLType): // Boolean; override; -> Not implemented // function SupportsTableCorrelationNames: Boolean; override; -> Not implemented // function SupportsDifferentTableCorrelationNames: Boolean; override; -> Not implemented function SupportsExpressionsInOrderBy: Boolean; override; function SupportsOrderByUnrelated: Boolean; override; function SupportsGroupBy: Boolean; override; function SupportsGroupByUnrelated: Boolean; override; function SupportsGroupByBeyondSelect: Boolean; override; // function SupportsLikeEscapeClause: Boolean; override; -> Not implemented // function SupportsMultipleResultSets: Boolean; override; -> Not implemented // function SupportsMultipleTransactions: Boolean; override; -> Not implemented // function SupportsNonNullableColumns: Boolean; override; -> Not implemented // function SupportsMinimumSQLGrammar: Boolean; override; -> Not implemented // function SupportsCoreSQLGrammar: Boolean; override; -> Not implemented // function SupportsExtendedSQLGrammar: Boolean; override; -> Not implemented // function SupportsANSI92EntryLevelSQL: Boolean; override; -> Not implemented // function SupportsANSI92IntermediateSQL: Boolean; override; -> Not implemented // function SupportsANSI92FullSQL: Boolean; override; -> Not implemented function SupportsIntegrityEnhancementFacility: Boolean; override; // function SupportsOuterJoins: Boolean; override; -> Not implemented // function SupportsFullOuterJoins: Boolean; override; -> Not implemented // function SupportsLimitedOuterJoins: Boolean; override; -> Not implemented function SupportsSchemasInDataManipulation: Boolean; override; function SupportsSchemasInProcedureCalls: Boolean; override; function SupportsSchemasInTableDefinitions: Boolean; override; function SupportsSchemasInIndexDefinitions: Boolean; override; function SupportsSchemasInPrivilegeDefinitions: Boolean; override; function SupportsCatalogsInDataManipulation: Boolean; override; function SupportsCatalogsInProcedureCalls: Boolean; override; function SupportsCatalogsInTableDefinitions: Boolean; override; function SupportsCatalogsInIndexDefinitions: Boolean; override; function SupportsCatalogsInPrivilegeDefinitions: Boolean; override; function SupportsOverloadPrefixInStoredProcedureName: Boolean; override; function SupportsPositionedDelete: Boolean; override; function SupportsPositionedUpdate: Boolean; override; function SupportsSelectForUpdate: Boolean; override; function SupportsStoredProcedures: Boolean; override; function SupportsSubqueriesInComparisons: Boolean; override; function SupportsSubqueriesInExists: Boolean; override; function SupportsSubqueriesInIns: Boolean; override; function SupportsSubqueriesInQuantifieds: Boolean; override; function SupportsCorrelatedSubqueries: Boolean; override; function SupportsUnion: Boolean; override; function SupportsUnionAll: Boolean; override; function SupportsOpenCursorsAcrossCommit: Boolean; override; function SupportsOpenCursorsAcrossRollback: Boolean; override; function SupportsOpenStatementsAcrossCommit: Boolean; override; function SupportsOpenStatementsAcrossRollback: Boolean; override; function SupportsTransactions: Boolean; override; function SupportsTransactionIsolationLevel(Level: TZTransactIsolationLevel): Boolean; override; function SupportsDataDefinitionAndDataManipulationTransactions: Boolean; override; function SupportsDataManipulationTransactionsOnly: Boolean; override; function SupportsResultSetType(_Type: TZResultSetType): Boolean; override; function SupportsResultSetConcurrency(_Type: TZResultSetType; Concurrency: TZResultSetConcurrency): Boolean; override; // function SupportsBatchUpdates: Boolean; override; -> Not implemented function SupportsNonEscapedSearchStrings: Boolean; override; function SupportsUpdateAutoIncrementFields: Boolean; override; // maxima: function GetMaxBinaryLiteralLength: Integer; override; function GetMaxCharLiteralLength: Integer; override; function GetMaxColumnNameLength: Integer; override; function GetMaxColumnsInGroupBy: Integer; override; function GetMaxColumnsInIndex: Integer; override; function GetMaxColumnsInOrderBy: Integer; override; function GetMaxColumnsInSelect: Integer; override; function GetMaxColumnsInTable: Integer; override; function GetMaxConnections: Integer; override; function GetMaxCursorNameLength: Integer; override; function GetMaxIndexLength: Integer; override; function GetMaxSchemaNameLength: Integer; override; function GetMaxProcedureNameLength: Integer; override; function GetMaxCatalogNameLength: Integer; override; function GetMaxRowSize: Integer; override; function GetMaxStatementLength: Integer; override; function GetMaxStatements: Integer; override; function GetMaxTableNameLength: Integer; override; function GetMaxTablesInSelect: Integer; override; function GetMaxUserNameLength: Integer; override; // policies (how are various data and operations handled): // function IsReadOnly: Boolean; override; -> Not implemented // function IsCatalogAtStart: Boolean; override; -> Not implemented function DoesMaxRowSizeIncludeBlobs: Boolean; override; // function NullsAreSortedHigh: Boolean; override; -> Not implemented // function NullsAreSortedLow: Boolean; override; -> Not implemented // function NullsAreSortedAtStart: Boolean; override; -> Not implemented // function NullsAreSortedAtEnd: Boolean; override; -> Not implemented // function NullPlusNonNullIsNull: Boolean; override; -> Not implemented // function UsesLocalFiles: Boolean; override; -> Not implemented function UsesLocalFilePerTable: Boolean; override; function StoresUpperCaseIdentifiers: Boolean; override; function StoresLowerCaseIdentifiers: Boolean; override; function StoresMixedCaseIdentifiers: Boolean; override; function StoresUpperCaseQuotedIdentifiers: Boolean; override; function StoresLowerCaseQuotedIdentifiers: Boolean; override; function StoresMixedCaseQuotedIdentifiers: Boolean; override; function GetDefaultTransactionIsolation: TZTransactIsolationLevel; override; function DataDefinitionCausesTransactionCommit: Boolean; override; function DataDefinitionIgnoredInTransactions: Boolean; override; // interface details (terms, keywords, etc): function GetSchemaTerm: string; override; function GetProcedureTerm: string; override; function GetCatalogTerm: string; override; function GetCatalogSeparator: string; override; function GetSQLKeywords: string; override; function GetNumericFunctions: string; override; function GetStringFunctions: string; override; function GetSystemFunctions: string; override; function GetTimeDateFunctions: string; override; function GetSearchStringEscape: string; override; function GetExtraNameCharacters: string; override; end; {** Implements Ado Metadata. } TZAdoDatabaseMetadata = class(TZAbstractDatabaseMetadata) private FAdoConnection: ZPlainAdo.Connection; FSupportedSchemasInitialized: Boolean; function AdoOpenSchema(Schema: Integer; const Args: array of const): ZPlainAdo.RecordSet; procedure InitializeSchemas; function SchemaSupported(SchemaId: Integer): Boolean; // (technobot) should be moved to TZAdoDatabaseInfo? function FindSchema(SchemaId: Integer): Integer; function BuildRestrictions(SchemaId: Integer; const Args: array of const): Variant; protected function CreateDatabaseInfo: IZDatabaseInfo; override; // technobot 2008-06-27 function DecomposeObjectString(const S: String): String; override; function UncachedGetTables(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const Types: TStringDynArray): IZResultSet; override; function UncachedGetSchemas: IZResultSet; override; function UncachedGetCatalogs: IZResultSet; override; function UncachedGetTableTypes: IZResultSet; override; function UncachedGetColumns(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const ColumnNamePattern: string): IZResultSet; override; function UncachedGetTablePrivileges(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string): IZResultSet; override; function UncachedGetColumnPrivileges(const Catalog: string; const Schema: string; const Table: string; const ColumnNamePattern: string): IZResultSet; override; function UncachedGetPrimaryKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; override; function UncachedGetImportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; override; function UncachedGetExportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; override; function UncachedGetCrossReference(const PrimaryCatalog: string; const PrimarySchema: string; const PrimaryTable: string; const ForeignCatalog: string; const ForeignSchema: string; const ForeignTable: string): IZResultSet; override; function UncachedGetIndexInfo(const Catalog: string; const Schema: string; const Table: string; Unique: Boolean; Approximate: Boolean): IZResultSet; override; // function UncachedGetSequences(const Catalog: string; const SchemaPattern: string; // const SequenceNamePattern: string): IZResultSet; virtual; -> Not implemented function UncachedGetProcedures(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string): IZResultSet; override; function UncachedGetProcedureColumns(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string; const ColumnNamePattern: string): IZResultSet; override; function UncachedGetVersionColumns(const Catalog: string; const Schema: string; const Table: string): IZResultSet; override; function UncachedGetTypeInfo: IZResultSet; override; function UncachedGetUDTs(const Catalog: string; const SchemaPattern: string; const TypeNamePattern: string; const Types: TIntegerDynArray): IZResultSet; override; public constructor Create(Connection: TZAbstractConnection; const Url: TZURL); override; destructor Destroy; override; // function GetTokenizer: IZTokenizer; override; end; implementation uses {$IFNDEF FPC} Variants, {$ENDIF} Math, ZDbcUtils, ZCollections, ZGenericSqlToken, ZDbcAdoUtils, ZDbcAdo, OleDB, ZDbcAdoResultSet; type TSuppSchemaRec = record SchemaGuid: TGuid; SupportedRestrictions: Integer; AdoSchemaId: Integer; end; IDBSchemaRowset = interface(IUnknown) ['{0c733a7b-2a1c-11ce-ade5-00aa0044773d}'] function GetRowset( pUnkOuter : IUnknown; const rguidSchema : TGUID; cRestrictions : Integer; var rgRestrictions : PVariant;{!!was: const VARIANT __RPC_FAR rgRestrictions[ ],} const riid : IUnknown; cPropertySets : Integer; var rgPropertySets : TDBPROPSET; var ppRowset : IUnknown) : HResult; stdcall; function GetSchemas( var pcSchemas : Integer; var prgSchemas : PGUID; var prgRestrictionSupport : PInteger) : HResult; stdcall; end; var SupportedSchemas: array of TSuppSchemaRec; { TZAdoDatabaseInfo } {** Constructs this object. @param Metadata the interface of the correpsonding database metadata object @param IdentifierQuotes the default Quotes for Identifiers used by the driver } constructor TZAdoDatabaseInfo.Create(const Metadata: TZAbstractDatabaseMetadata); begin inherited Create(MetaData, '[]'); end; //---------------------------------------------------------------------- // First, a variety of minor information about the target database. {** What's the name of this database product? @return database product name } function TZAdoDatabaseInfo.GetDatabaseProductName: string; begin Result := 'ado'; end; {** What's the version of this database product? @return database version } function TZAdoDatabaseInfo.GetDatabaseProductVersion: string; begin Result := (Metadata.GetConnection as IZAdoConnection).GetAdoConnection.Version; end; {** What's the name of this JDBC driver? @return JDBC driver name } function TZAdoDatabaseInfo.GetDriverName: string; begin Result := 'Zeos Database Connectivity Driver for Microsoft ADO'; end; {** What's this JDBC driver's major version number? @return JDBC driver major version } function TZAdoDatabaseInfo.GetDriverMajorVersion: Integer; begin Result := 1; end; {** What's this JDBC driver's minor version number? @return JDBC driver minor version number } function TZAdoDatabaseInfo.GetDriverMinorVersion: Integer; begin Result := 0; end; {** Does the database use a file for each table? @return true if the database uses a local file for each table } function TZAdoDatabaseInfo.UsesLocalFilePerTable: Boolean; begin Result := False; end; {** Does the database treat mixed case unquoted SQL identifiers as case sensitive and as a result store them in mixed case? A JDBC CompliantTM driver will always return false. @return true if so; false otherwise } function TZAdoDatabaseInfo.SupportsMixedCaseIdentifiers: Boolean; begin Result := False; end; {** Does the database treat mixed case unquoted SQL identifiers as case insensitive and store them in upper case? @return true if so; false otherwise } function TZAdoDatabaseInfo.StoresUpperCaseIdentifiers: Boolean; begin Result := True; end; {** Does the database treat mixed case unquoted SQL identifiers as case insensitive and store them in lower case? @return true if so; false otherwise } function TZAdoDatabaseInfo.StoresLowerCaseIdentifiers: Boolean; begin Result := True; end; {** Does the database treat mixed case unquoted SQL identifiers as case insensitive and store them in mixed case? @return true if so; false otherwise } function TZAdoDatabaseInfo.StoresMixedCaseIdentifiers: Boolean; begin Result := True; end; {** Does the database treat mixed case quoted SQL identifiers as case sensitive and as a result store them in mixed case? A JDBC CompliantTM driver will always return true. @return true if so; false otherwise } function TZAdoDatabaseInfo.SupportsMixedCaseQuotedIdentifiers: Boolean; begin Result := True; end; {** Does the database treat mixed case quoted SQL identifiers as case insensitive and store them in upper case? @return true if so; false otherwise } function TZAdoDatabaseInfo.StoresUpperCaseQuotedIdentifiers: Boolean; begin Result := True; end; {** Does the database treat mixed case quoted SQL identifiers as case insensitive and store them in lower case? @return true if so; false otherwise } function TZAdoDatabaseInfo.StoresLowerCaseQuotedIdentifiers: Boolean; begin Result := True; end; {** Does the database treat mixed case quoted SQL identifiers as case insensitive and store them in mixed case? @return true if so; false otherwise } function TZAdoDatabaseInfo.StoresMixedCaseQuotedIdentifiers: Boolean; begin Result := True; end; {** Gets a comma-separated list of all a database's SQL keywords that are NOT also SQL92 keywords. @return the list } function TZAdoDatabaseInfo.GetSQLKeywords: string; begin { TODO -ofjanos -cAPI : SQL Keywords that are not SQL92 compliant } Result := ''; end; {** Gets a comma-separated list of math functions. These are the X/Open CLI math function names used in the JDBC function escape clause. @return the list } function TZAdoDatabaseInfo.GetNumericFunctions: string; begin Result := 'ABS,ACOS,ASIN,ATAN,ATN2,CEILING,COS,COT,DEGREES,EXP,FLOOR,LOG,LOG10,'+ 'PI,POWER,RADIANS,RAND,ROUND,SIGN,SIN,SQUARE,SQRT,TAN'; end; {** Gets a comma-separated list of string functions. These are the X/Open CLI string function names used in the JDBC function escape clause. @return the list } function TZAdoDatabaseInfo.GetStringFunctions: string; begin Result := 'ASCII,CHAR,CHARINDEX,DIFFERENCE,LEFT,LEN,LOWER,LTRIM,NCHAR,PATINDEX,'+ 'REPLACE,QUOTENAME,REPLICATE,REVERSE,RIGHT,RTRIM,SOUNDEX,SPACE,STR,'+ 'STUFF,SUBSTRING,UNICODE,UPPER'; end; {** Gets a comma-separated list of system functions. These are the X/Open CLI system function names used in the JDBC function escape clause. @return the list } function TZAdoDatabaseInfo.GetSystemFunctions: string; begin Result := 'APP_NAME,CASE,CAST,CONVERT,COALESCE,CURRENT_TIMESTAMP,CURRENT_USER,'+ 'DATALENGTH,@@ERROR,FORMATMESSAGE,GETANSINULL,HOST_ID,HOST_NAME,'+ 'IDENT_INCR,IDENT_SEED,@@IDENTITY,IDENTITY,ISDATE,ISNULL,ISNUMERIC,'+ 'NEWID,NULLIF,PARSENAME,PERMISSIONS,@@ROWCOUNT,SESSION_USER,STATS_DATE,'+ 'SYSTEM_USER,@@TRANCOUNT,USER_NAME'; end; {** Gets a comma-separated list of time and date functions. @return the list } function TZAdoDatabaseInfo.GetTimeDateFunctions: string; begin Result := 'DATEADD,DATEDIFF,DATENAME,DATEPART,DAY,GETDATE,MONTH,YEAR'; end; {** Gets the string that can be used to escape wildcard characters. This is the string that can be used to escape '_' or '%' in the string pattern style catalog search parameters.

The '_' character represents any single character.

The '%' character represents any sequence of zero or more characters. @return the string used to escape wildcard characters } function TZAdoDatabaseInfo.GetSearchStringEscape: string; begin { TODO -ofjanos -cgeneral : In sql server this must be specified as the parameter of like. example: WHERE ColumnA LIKE '%5/%%' ESCAPE '/' } Result := '/'; end; {** Gets all the "extra" characters that can be used in unquoted identifier names (those beyond a-z, A-Z, 0-9 and _). @return the string containing the extra characters } function TZAdoDatabaseInfo.GetExtraNameCharacters: string; begin Result := '@$#'; end; //-------------------------------------------------------------------- // Functions describing which features are supported. {** Are expressions in "ORDER BY" lists supported? @return true if so; false otherwise } function TZAdoDatabaseInfo.SupportsExpressionsInOrderBy: Boolean; begin Result := True; end; {** Can an "ORDER BY" clause use columns not in the SELECT statement? @return true if so; false otherwise } function TZAdoDatabaseInfo.SupportsOrderByUnrelated: Boolean; begin Result := True; end; {** Is some form of "GROUP BY" clause supported? @return true if so; false otherwise } function TZAdoDatabaseInfo.SupportsGroupBy: Boolean; begin Result := True; end; {** Can a "GROUP BY" clause use columns not in the SELECT? @return true if so; false otherwise } function TZAdoDatabaseInfo.SupportsGroupByUnrelated: Boolean; begin Result := True; end; {** Can a "GROUP BY" clause add columns not in the SELECT provided it specifies all the columns in the SELECT? @return true if so; false otherwise } function TZAdoDatabaseInfo.SupportsGroupByBeyondSelect: Boolean; begin Result := True; end; {** Is the SQL Integrity Enhancement Facility supported? @return true if so; false otherwise } function TZAdoDatabaseInfo.SupportsIntegrityEnhancementFacility: Boolean; begin Result := False; end; {** What's the database vendor's preferred term for "schema"? @return the vendor term } function TZAdoDatabaseInfo.GetSchemaTerm: string; begin Result := 'owner'; end; {** What's the database vendor's preferred term for "procedure"? @return the vendor term } function TZAdoDatabaseInfo.GetProcedureTerm: string; begin Result := 'procedure'; end; {** What's the database vendor's preferred term for "catalog"? @return the vendor term } function TZAdoDatabaseInfo.GetCatalogTerm: string; begin Result := 'database'; end; {** What's the separator between catalog and table name? @return the separator string } function TZAdoDatabaseInfo.GetCatalogSeparator: string; begin Result := '.'; end; {** Can a schema name be used in a data manipulation statement? @return true if so; false otherwise } function TZAdoDatabaseInfo.SupportsSchemasInDataManipulation: Boolean; begin Result := True; end; {** Can a schema name be used in a procedure call statement? @return true if so; false otherwise } function TZAdoDatabaseInfo.SupportsSchemasInProcedureCalls: Boolean; begin Result := True; end; {** Can a schema name be used in a table definition statement? @return true if so; false otherwise } function TZAdoDatabaseInfo.SupportsSchemasInTableDefinitions: Boolean; begin Result := True; end; {** Can a schema name be used in an index definition statement? @return true if so; false otherwise } function TZAdoDatabaseInfo.SupportsSchemasInIndexDefinitions: Boolean; begin Result := True; end; {** Can a schema name be used in a privilege definition statement? @return true if so; false otherwise } function TZAdoDatabaseInfo.SupportsSchemasInPrivilegeDefinitions: Boolean; begin Result := True; end; {** Can a catalog name be used in a data manipulation statement? @return true if so; false otherwise } function TZAdoDatabaseInfo.SupportsCatalogsInDataManipulation: Boolean; begin Result := True; end; {** Can a catalog name be used in a procedure call statement? @return true if so; false otherwise } function TZAdoDatabaseInfo.SupportsCatalogsInProcedureCalls: Boolean; begin Result := True; end; {** Can a catalog name be used in a table definition statement? @return true if so; false otherwise } function TZAdoDatabaseInfo.SupportsCatalogsInTableDefinitions: Boolean; begin Result := True; end; {** Can a catalog name be used in an index definition statement? @return true if so; false otherwise } function TZAdoDatabaseInfo.SupportsCatalogsInIndexDefinitions: Boolean; begin Result := True; end; {** Can a catalog name be used in a privilege definition statement? @return true if so; false otherwise } function TZAdoDatabaseInfo.SupportsCatalogsInPrivilegeDefinitions: Boolean; begin Result := True; end; {** Can a stored procedure have an additional overload suffix? @return true if so; false otherwise } function TZAdoDatabaseInfo.SupportsOverloadPrefixInStoredProcedureName: Boolean; begin Result := True; end; {** Is positioned DELETE supported? @return true if so; false otherwise } function TZAdoDatabaseInfo.SupportsPositionedDelete: Boolean; begin //CURRENT OF //Specifies that the DELETE is done at the current position of the specified cursor. Result := True; end; {** Is positioned UPDATE supported? @return true if so; false otherwise } function TZAdoDatabaseInfo.SupportsPositionedUpdate: Boolean; begin Result := True; end; {** Is SELECT for UPDATE supported? @return true if so; false otherwise } function TZAdoDatabaseInfo.SupportsSelectForUpdate: Boolean; begin Result := True; end; {** Are stored procedure calls using the stored procedure escape syntax supported? @return true if so; false otherwise } function TZAdoDatabaseInfo.SupportsStoredProcedures: Boolean; begin Result := True; end; {** Are subqueries in comparison expressions supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZAdoDatabaseInfo.SupportsSubqueriesInComparisons: Boolean; begin Result := True; end; {** Are subqueries in 'exists' expressions supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZAdoDatabaseInfo.SupportsSubqueriesInExists: Boolean; begin Result := True; end; {** Are subqueries in 'in' statements supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZAdoDatabaseInfo.SupportsSubqueriesInIns: Boolean; begin Result := True; end; {** Are subqueries in quantified expressions supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZAdoDatabaseInfo.SupportsSubqueriesInQuantifieds: Boolean; begin Result := True; end; {** Are correlated subqueries supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZAdoDatabaseInfo.SupportsCorrelatedSubqueries: Boolean; begin Result := True; end; {** Is SQL UNION supported? @return true if so; false otherwise } function TZAdoDatabaseInfo.SupportsUnion: Boolean; begin Result := True; end; {** Is SQL UNION ALL supported? @return true if so; false otherwise } function TZAdoDatabaseInfo.SupportsUnionAll: Boolean; begin Result := True; end; {** Can cursors remain open across commits? @return true if cursors always remain open; false if they might not remain open } function TZAdoDatabaseInfo.SupportsOpenCursorsAcrossCommit: Boolean; begin Result := True; end; {** Can cursors remain open across rollbacks? @return true if cursors always remain open; false if they might not remain open } function TZAdoDatabaseInfo.SupportsOpenCursorsAcrossRollback: Boolean; begin Result := True; end; {** Can statements remain open across commits? @return true if statements always remain open; false if they might not remain open } function TZAdoDatabaseInfo.SupportsOpenStatementsAcrossCommit: Boolean; begin Result := False; end; {** Can statements remain open across rollbacks? @return true if statements always remain open; false if they might not remain open } function TZAdoDatabaseInfo.SupportsOpenStatementsAcrossRollback: Boolean; begin Result := False; end; //---------------------------------------------------------------------- // The following group of methods exposes various limitations // based on the target database with the current driver. // Unless otherwise specified, a result of zero means there is no // limit, or the limit is not known. {** How many hex characters can you have in an inline binary literal? @return max binary literal length in hex characters; a result of zero means that there is no limit or the limit is not known } function TZAdoDatabaseInfo.GetMaxBinaryLiteralLength: Integer; begin Result := 16000; end; {** What's the max length for a character literal? @return max literal length; a result of zero means that there is no limit or the limit is not known } function TZAdoDatabaseInfo.GetMaxCharLiteralLength: Integer; begin Result := 8000; end; {** What's the limit on column name length? @return max column name length; a result of zero means that there is no limit or the limit is not known } function TZAdoDatabaseInfo.GetMaxColumnNameLength: Integer; begin Result := 128; end; {** What's the maximum number of columns in a "GROUP BY" clause? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZAdoDatabaseInfo.GetMaxColumnsInGroupBy: Integer; begin Result := 0; end; {** What's the maximum number of columns allowed in an index? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZAdoDatabaseInfo.GetMaxColumnsInIndex: Integer; begin Result := 16; end; {** What's the maximum number of columns in an "ORDER BY" clause? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZAdoDatabaseInfo.GetMaxColumnsInOrderBy: Integer; begin Result := 0; end; {** What's the maximum number of columns in a "SELECT" list? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZAdoDatabaseInfo.GetMaxColumnsInSelect: Integer; begin Result := 4096; end; {** What's the maximum number of columns in a table? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZAdoDatabaseInfo.GetMaxColumnsInTable: Integer; begin Result := 1024; end; {** How many active connections can we have at a time to this database? @return max number of active connections; a result of zero means that there is no limit or the limit is not known } function TZAdoDatabaseInfo.GetMaxConnections: Integer; begin Result := 0; end; {** What's the maximum cursor name length? @return max cursor name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZAdoDatabaseInfo.GetMaxCursorNameLength: Integer; begin Result := 128; end; {** Retrieves the maximum number of bytes for an index, including all of the parts of the index. @return max index length in bytes, which includes the composite of all the constituent parts of the index; a result of zero means that there is no limit or the limit is not known } function TZAdoDatabaseInfo.GetMaxIndexLength: Integer; begin Result := 900; end; {** What's the maximum length allowed for a schema name? @return max name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZAdoDatabaseInfo.GetMaxSchemaNameLength: Integer; begin Result := 128; end; {** What's the maximum length of a procedure name? @return max name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZAdoDatabaseInfo.GetMaxProcedureNameLength: Integer; begin Result := 128; end; {** What's the maximum length of a catalog name? @return max name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZAdoDatabaseInfo.GetMaxCatalogNameLength: Integer; begin Result := 128; end; {** What's the maximum length of a single row? @return max row size in bytes; a result of zero means that there is no limit or the limit is not known } function TZAdoDatabaseInfo.GetMaxRowSize: Integer; begin Result := 8060; end; {** Did getMaxRowSize() include LONGVARCHAR and LONGVARBINARY blobs? @return true if so; false otherwise } function TZAdoDatabaseInfo.DoesMaxRowSizeIncludeBlobs: Boolean; begin Result := False; end; {** What's the maximum length of an SQL statement? @return max length in bytes; a result of zero means that there is no limit or the limit is not known } function TZAdoDatabaseInfo.GetMaxStatementLength: Integer; begin Result := 0; end; {** How many active statements can we have open at one time to this database? @return the maximum number of statements that can be open at one time; a result of zero means that there is no limit or the limit is not known } function TZAdoDatabaseInfo.GetMaxStatements: Integer; begin Result := 0; end; {** What's the maximum length of a table name? @return max name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZAdoDatabaseInfo.GetMaxTableNameLength: Integer; begin Result := 128; end; {** What's the maximum number of tables in a SELECT statement? @return the maximum number of tables allowed in a SELECT statement; a result of zero means that there is no limit or the limit is not known } function TZAdoDatabaseInfo.GetMaxTablesInSelect: Integer; begin Result := 256; end; {** What's the maximum length of a user name? @return max user name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZAdoDatabaseInfo.GetMaxUserNameLength: Integer; begin Result := 128; end; //---------------------------------------------------------------------- {** What's the database's default transaction isolation level? The values are defined in java.sql.Connection. @return the default isolation level @see Connection } function TZAdoDatabaseInfo.GetDefaultTransactionIsolation: TZTransactIsolationLevel; begin Result := tiReadCommitted; end; {** Are transactions supported? If not, invoking the method commit is a noop and the isolation level is TRANSACTION_NONE. @return true if transactions are supported; false otherwise } function TZAdoDatabaseInfo.SupportsTransactions: Boolean; begin Result := True; end; {** Does this database support the given transaction isolation level? @param level the values are defined in java.sql.Connection @return true if so; false otherwise @see Connection } function TZAdoDatabaseInfo.SupportsTransactionIsolationLevel( Level: TZTransactIsolationLevel): Boolean; begin Result := True; end; {** Are both data definition and data manipulation statements within a transaction supported? @return true if so; false otherwise } function TZAdoDatabaseInfo. SupportsDataDefinitionAndDataManipulationTransactions: Boolean; begin Result := True; end; {** Are only data manipulation statements within a transaction supported? @return true if so; false otherwise } function TZAdoDatabaseInfo. SupportsDataManipulationTransactionsOnly: Boolean; begin Result := False; end; {** Does a data definition statement within a transaction force the transaction to commit? @return true if so; false otherwise } function TZAdoDatabaseInfo.DataDefinitionCausesTransactionCommit: Boolean; begin Result := False; end; {** Is a data definition statement within a transaction ignored? @return true if so; false otherwise } function TZAdoDatabaseInfo.DataDefinitionIgnoredInTransactions: Boolean; begin Result := False; end; {** Does the database support the given result set type? @param type defined in java.sql.ResultSet @return true if so; false otherwise } function TZAdoDatabaseInfo.SupportsResultSetType( _Type: TZResultSetType): Boolean; begin Result := True; end; {** Does the database support the concurrency type in combination with the given result set type? @param type defined in java.sql.ResultSet @param concurrency type defined in java.sql.ResultSet @return true if so; false otherwise } function TZAdoDatabaseInfo.SupportsResultSetConcurrency( _Type: TZResultSetType; Concurrency: TZResultSetConcurrency): Boolean; begin Result := True; end; {** Does the Database or Actual Version understand non escaped search strings? @return true if the DataBase does understand non escaped search strings } function TZAdoDatabaseInfo.SupportsNonEscapedSearchStrings: Boolean; begin Result := True; end; {** Does the Database support updating auto incremental fields? @return true if the DataBase allows it. } function TZAdoDatabaseInfo.SupportsUpdateAutoIncrementFields: Boolean; begin Result := False; end; { TZAdoDatabaseMetadata } {** Constructs this object and assignes the main properties. @param Connection a database connection object. @param Url a database connection url string. @param Info an extra connection properties. } constructor TZAdoDatabaseMetadata.Create(Connection: TZAbstractConnection; const Url: TZURL); begin inherited Create(Connection, Url); FAdoConnection := nil; end; {** Destroys this object and cleanups the memory. } destructor TZAdoDatabaseMetadata.Destroy; begin inherited Destroy; end; {** Constructs a database information object and returns the interface to it. Used internally by the constructor. @return the database information object interface } function TZAdoDatabaseMetadata.CreateDatabaseInfo: IZDatabaseInfo; begin Result := TZAdoDatabaseInfo.Create(Self); end; function TZAdoDatabaseMetadata.DecomposeObjectString(const S: String): String; begin if S = '' then Result := S else if IC.IsQuoted(S) then Result := IC.ExtractQuote(S) else Result := s; end; {** Gets a description of the stored procedures available in a catalog.

Only procedure descriptions matching the schema and procedure name criteria are returned. They are ordered by PROCEDURE_SCHEM, and PROCEDURE_NAME.

Each procedure description has the the following columns:

  1. PROCEDURE_CAT String => procedure catalog (may be null)
  2. PROCEDURE_SCHEM String => procedure schema (may be null)
  3. PROCEDURE_NAME String => procedure name
  4. reserved for future use
  5. reserved for future use
  6. reserved for future use
  7. REMARKS String => explanatory comment on the procedure
  8. PROCEDURE_TYPE short => kind of procedure:
    • procedureResultUnknown - May return a result
    • procedureNoResult - Does not return a result
    • procedureReturnsResult - Returns a result
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param procedureNamePattern a procedure name pattern @return ResultSet - each row is a procedure description @see #getSearchStringEscape } function TZAdoDatabaseMetadata.UncachedGetProcedures(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string): IZResultSet; var AdoRecordSet: ZPlainAdo.RecordSet; begin Result:=inherited UncachedGetProcedures(Catalog, SchemaPattern, ProcedureNamePattern); AdoRecordSet := AdoOpenSchema(adSchemaProcedures, [Catalog, SchemaPattern, ProcedureNamePattern, '']); if Assigned(AdoRecordSet) then begin with TZAdoResultSet.Create(GetStatement, '', AdoRecordSet) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('PROCEDURE_CAT', GetStringByName('PROCEDURE_CATALOG')); Result.UpdateStringByName('PROCEDURE_SCHEM', GetStringByName('PROCEDURE_SCHEMA')); Result.UpdateStringByName('PROCEDURE_NAME', GetStringByName('PROCEDURE_NAME')); Result.UpdateStringByName('REMARKS', GetStringByName('DESCRIPTION')); Result.UpdateShortByName('PROCEDURE_TYPE', GetShortByName('PROCEDURE_TYPE') - 1); Result.InsertRow; end; Close; Free; end; end; end; {** Gets a description of a catalog's stored procedure parameters and result columns.

Only descriptions matching the schema, procedure and parameter name criteria are returned. They are ordered by PROCEDURE_SCHEM and PROCEDURE_NAME. Within this, the return value, if any, is first. Next are the parameter descriptions in call order. The column descriptions follow in column number order.

Each row in the ResultSet is a parameter description or column description with the following fields:

  1. PROCEDURE_CAT String => procedure catalog (may be null)
  2. PROCEDURE_SCHEM String => procedure schema (may be null)
  3. PROCEDURE_NAME String => procedure name
  4. COLUMN_NAME String => column/parameter name
  5. COLUMN_TYPE Short => kind of column/parameter:
    • procedureColumnUnknown - nobody knows
    • procedureColumnIn - IN parameter
    • procedureColumnInOut - INOUT parameter
    • procedureColumnOut - OUT parameter
    • procedureColumnReturn - procedure return value
    • procedureColumnResult - result column in ResultSet
  6. DATA_TYPE short => SQL type from java.sql.Types
  7. TYPE_NAME String => SQL type name, for a UDT type the type name is fully qualified
  8. PRECISION int => precision
  9. LENGTH int => length in bytes of data
  10. SCALE short => scale
  11. RADIX short => radix
  12. NULLABLE short => can it contain NULL?
    • procedureNoNulls - does not allow NULL values
    • procedureNullable - allows NULL values
    • procedureNullableUnknown - nullability unknown
  13. REMARKS String => comment describing parameter/column

Note: Some databases may not return the column descriptions for a procedure. Additional columns beyond REMARKS can be defined by the database. @param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param procedureNamePattern a procedure name pattern @param columnNamePattern a column name pattern @return ResultSet - each row describes a stored procedure parameter or column @see #getSearchStringEscape } function TZAdoDatabaseMetadata.UncachedGetProcedureColumns(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string; const ColumnNamePattern: string): IZResultSet; var AdoRecordSet: ZPlainAdo.RecordSet; begin Result:=inherited UncachedGetProcedureColumns(Catalog, SchemaPattern, ProcedureNamePattern, ColumnNamePattern); AdoRecordSet := AdoOpenSchema(adSchemaProcedureParameters, [Catalog, SchemaPattern, ProcedureNamePattern]); if Assigned(AdoRecordSet) then begin with TZAdoResultSet.Create(GetStatement, '', AdoRecordSet) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('PROCEDURE_CAT', GetStringByName('PROCEDURE_CATALOG')); Result.UpdateStringByName('PROCEDURE_SCHEM', GetStringByName('PROCEDURE_SCHEMA')); Result.UpdateStringByName('PROCEDURE_NAME', GetStringByName('PROCEDURE_NAME')); Result.UpdateStringByName('COLUMN_NAME', GetStringByName('PARAMETER_NAME')); case GetShortByName('PARAMETER_TYPE') of 1: Result.UpdateShortByName('COLUMN_TYPE', Ord(pctIn)); 2: Result.UpdateShortByName('COLUMN_TYPE', Ord(pctInOut)); 3: Result.UpdateShortByName('COLUMN_TYPE', Ord(pctOut)); 4: Result.UpdateShortByName('COLUMN_TYPE', Ord(pctReturn)); else Result.UpdateShortByName('COLUMN_TYPE', Ord(pctUnknown)); end; Result.UpdateShortByName('DATA_TYPE', Ord(ConvertAdoToSqlType(GetShortByName('DATA_TYPE'), ConSettings.CPType))); Result.UpdateStringByName('TYPE_NAME', GetStringByName('TYPE_NAME')); Result.UpdateIntByName('PRECISION', GetIntByName('NUMERIC_PRECISION')); Result.UpdateIntByName('LENGTH', GetIntByName('CHARACTER_OCTET_LENGTH')); Result.UpdateShortByName('SCALE', GetShortByName('NUMERIC_SCALE')); // Result.UpdateShortByName('RADIX', GetShortByName('RADIX')); Result.UpdateShortByName('NULLABLE', 2); if GetStringByName('IS_NULLABLE') = 'NO' then Result.UpdateShortByName('NULLABLE', 0); if GetStringByName('IS_NULLABLE') = 'YES' then Result.UpdateShortByName('NULLABLE', 1); Result.UpdateStringByName('REMARKS', GetStringByName('DESCRIPTION')); Result.InsertRow; end; Close; Free; end; end; end; {** Gets a description of tables available in a catalog.

Only table descriptions matching the catalog, schema, table name and type criteria are returned. They are ordered by TABLE_TYPE, TABLE_SCHEM and TABLE_NAME.

Each table description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. TABLE_TYPE String => table type. Typical types are "TABLE", "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM".
  5. REMARKS String => explanatory comment on the table

Note: Some databases may not return information for all tables. @param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param tableNamePattern a table name pattern @param types a list of table types to include; null returns all types @return ResultSet - each row is a table description @see #getSearchStringEscape } function TZAdoDatabaseMetadata.UncachedGetTables(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const Types: TStringDynArray): IZResultSet; var I: Integer; TableTypes: string; AdoRecordSet: ZPlainAdo.RecordSet; begin Result:=inherited UncachedGetTables(Catalog, SchemaPattern, TableNamePattern, Types); for I := Low(Types) to High(Types) do begin if Length(TableTypes) > 0 then TableTypes := TableTypes + ','; TableTypes := TableTypes + Types[I]; end; AdoRecordSet := AdoOpenSchema(adSchemaTables, [Catalog, SchemaPattern, TableNamePattern, TableTypes]); if Assigned(AdoRecordSet) then begin with TZAdoResultSet.Create(GetStatement, '', AdoRecordset) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TABLE_CAT', GetStringByName('TABLE_CATALOG')); Result.UpdateStringByName('TABLE_SCHEM', GetStringByName('TABLE_SCHEMA')); Result.UpdateStringByName('TABLE_NAME', GetStringByName('TABLE_NAME')); Result.UpdateStringByName('TABLE_TYPE', GetStringByName('TABLE_TYPE')); Result.UpdateStringByName('REMARKS', GetStringByName('DESCRIPTION')); Result.InsertRow; end; Close; Free; end; end; end; {** Gets the schema names available in this database. The results are ordered by schema name.

The schema column is:

  1. TABLE_SCHEM String => schema name
@return ResultSet - each row has a single String column that is a schema name } function TZAdoDatabaseMetadata.UncachedGetSchemas: IZResultSet; var AdoRecordSet: ZPlainAdo.RecordSet; begin Result:=inherited UncachedGetSchemas; AdoRecordSet := AdoOpenSchema(adSchemaSchemata, []); if Assigned(AdoRecordSet) then begin with TZAdoResultSet.Create(GetStatement, '', AdoRecordSet) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TABLE_SCHEM', GetStringByName('SCHEMA_NAME')); Result.InsertRow; end; Close; Free; end; end; end; {** Gets the catalog names available in this database. The results are ordered by catalog name.

The catalog column is:

  1. TABLE_CAT String => catalog name
@return ResultSet - each row has a single String column that is a catalog name } function TZAdoDatabaseMetadata.UncachedGetCatalogs: IZResultSet; var AdoRecordSet: ZPlainAdo.RecordSet; begin Result:=inherited UncachedGetCatalogs; AdoRecordSet := AdoOpenSchema(adSchemaCatalogs, []); if Assigned(AdoRecordSet) then begin with TZAdoResultSet.Create(GetStatement, '', AdoRecordSet) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TABLE_CAT', GetStringByName('CATALOG_NAME')); Result.InsertRow; end; Close; Free; end; end; end; {** Gets the table types available in this database. The results are ordered by table type.

The table type is:

  1. TABLE_TYPE String => table type. Typical types are "TABLE", "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM".
@return ResultSet - each row has a single String column that is a table type } function TZAdoDatabaseMetadata.UncachedGetTableTypes: IZResultSet; const TableTypes: array[0..7] of string = ( 'ALIAS', 'TABLE', 'SYNONYM', 'SYSTEM TABLE', 'VIEW', 'GLOBAL TEMPORARY', 'LOCAL TEMPORARY', 'SYSTEM VIEW' ); var I: Integer; begin Result:=inherited UncachedGetTableTypes; for I := 0 to 7 do begin Result.MoveToInsertRow; Result.UpdateStringByName('TABLE_TYPE', TableTypes[I]); Result.InsertRow; end; end; {** Gets a description of table columns available in the specified catalog.

Only column descriptions matching the catalog, schema, table and column name criteria are returned. They are ordered by TABLE_SCHEM, TABLE_NAME and ORDINAL_POSITION.

Each column description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. COLUMN_NAME String => column name
  5. DATA_TYPE short => SQL type from java.sql.Types
  6. TYPE_NAME String => Data source dependent type name, for a UDT the type name is fully qualified
  7. COLUMN_SIZE int => column size. For char or date types this is the maximum number of characters, for numeric or decimal types this is precision.
  8. BUFFER_LENGTH is not used.
  9. DECIMAL_DIGITS int => the number of fractional digits
  10. NUM_PREC_RADIX int => Radix (typically either 10 or 2)
  11. NULLABLE int => is NULL allowed?
    • columnNoNulls - might not allow NULL values
    • columnNullable - definitely allows NULL values
    • columnNullableUnknown - nullability unknown
  12. REMARKS String => comment describing column (may be null)
  13. COLUMN_DEF String => default value (may be null)
  14. SQL_DATA_TYPE int => unused
  15. SQL_DATETIME_SUB int => unused
  16. CHAR_OCTET_LENGTH int => for char types the maximum number of bytes in the column
  17. ORDINAL_POSITION int => index of column in table (starting at 1)
  18. IS_NULLABLE String => "NO" means column definitely does not allow NULL values; "YES" means the column might allow NULL values. An empty string means nobody knows.
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param tableNamePattern a table name pattern @param columnNamePattern a column name pattern @return ResultSet - each row is a column description @see #getSearchStringEscape } function TZAdoDatabaseMetadata.UncachedGetColumns(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const ColumnNamePattern: string): IZResultSet; var AdoRecordSet: ZPlainAdo.RecordSet; Flags: Integer; SQLType: TZSQLType; begin Result:=inherited UncachedGetColumns(Catalog, SchemaPattern, TableNamePattern, ColumnNamePattern); AdoRecordSet := AdoOpenSchema(adSchemaColumns, [DecomposeObjectString(Catalog), DecomposeObjectString(SchemaPattern), DecomposeObjectString(TableNamePattern), DecomposeObjectString(ColumnNamePattern)]); if Assigned(AdoRecordSet) then begin AdoRecordSet.Sort := 'ORDINAL_POSITION'; with TZAdoResultSet.Create(GetStatement, '', AdoRecordSet) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TABLE_CAT', GetStringByName('TABLE_CATALOG')); Result.UpdateStringByName('TABLE_SCHEM', GetStringByName('TABLE_SCHEMA')); Result.UpdateStringByName('TABLE_NAME', GetStringByName('TABLE_NAME')); Result.UpdateStringByName('COLUMN_NAME', GetStringByName('COLUMN_NAME')); SQLType := ConvertAdoToSqlType(GetShortByName('DATA_TYPE'), ConSettings.CPType); Flags := GetIntByName('COLUMN_FLAGS'); //!!!If the field type is long then this is the only way to know it because it just returns string type if ((Flags and DBCOLUMNFLAGS_ISLONG) <> 0 ) and (SQLType in [stBytes, stString, stUnicodeString]) then case SQLType of stBytes: SQLType := stBinaryStream; stString: SQLType := stAsciiStream; stUnicodeString: SQLType := stUnicodeStream; end; Result.UpdateShortByName('DATA_TYPE', Ord(SQLType)); Result.UpdateIntByName('COLUMN_SIZE', GetIntByName('CHARACTER_MAXIMUM_LENGTH')); Result.UpdateIntByName('BUFFER_LENGTH', GetIntByName('CHARACTER_MAXIMUM_LENGTH')); Result.UpdateIntByName('DECIMAL_DIGITS', GetIntByName('NUMERIC_SCALE')); Result.UpdateIntByName('NUM_PREC_RADIX', GetShortByName('NUMERIC_PRECISION')); if GetBooleanByName('IS_NULLABLE') then Result.UpdateShortByName('NULLABLE', 1) else Result.UpdateShortByName('NULLABLE', 0); Result.UpdateStringByName('REMARKS', GetStringByName('DESCRIPTION')); Result.UpdateStringByName('COLUMN_DEF', GetStringByName('COLUMN_DEFAULT')); Result.UpdateShortByName('SQL_DATETIME_SUB', GetShortByName('DATETIME_PRECISION')); Result.UpdateIntByName('CHAR_OCTET_LENGTH', GetIntByName('CHARACTER_OCTET_LENGTH')); Result.UpdateIntByName('ORDINAL_POSITION', GetIntByName('ORDINAL_POSITION')); if UpperCase(GetStringByName('IS_NULLABLE')) = 'FALSE' then Result.UpdateStringByName('IS_NULLABLE', 'NO') else Result.UpdateStringByName('IS_NULLABLE', 'YES'); Result.UpdateBooleanByName('WRITABLE', (Flags and (DBCOLUMNFLAGS_WRITE or DBCOLUMNFLAGS_WRITEUNKNOWN) <> 0)); Result.UpdateBooleanByName('DEFINITELYWRITABLE', (Flags and (DBCOLUMNFLAGS_WRITE) <> 0)); Result.UpdateBooleanByName('READONLY', (Flags and (DBCOLUMNFLAGS_WRITE or DBCOLUMNFLAGS_WRITEUNKNOWN) = 0)); Result.UpdateBooleanByName('SEARCHABLE', (Flags and (DBCOLUMNFLAGS_ISLONG) = 0)); Result.UpdateNullByName('AUTO_INCREMENT'); Result.InsertRow; end; Close; Free; end; end; end; {** Gets a description of the access rights for a table's columns.

Only privileges matching the column name criteria are returned. They are ordered by COLUMN_NAME and PRIVILEGE.

Each privilige description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. COLUMN_NAME String => column name
  5. GRANTOR => grantor of access (may be null)
  6. GRANTEE String => grantee of access
  7. PRIVILEGE String => name of access (SELECT, INSERT, UPDATE, REFRENCES, ...)
  8. IS_GRANTABLE String => "YES" if grantee is permitted to grant to others; "NO" if not; null if unknown
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @param columnNamePattern a column name pattern @return ResultSet - each row is a column privilege description @see #getSearchStringEscape } function TZAdoDatabaseMetadata.UncachedGetColumnPrivileges(const Catalog: string; const Schema: string; const Table: string; const ColumnNamePattern: string): IZResultSet; var AdoRecordSet: ZPlainAdo.RecordSet; begin Result:=inherited UncachedGetColumnPrivileges(Catalog, Schema, Table, ColumnNamePattern); AdoRecordSet := AdoOpenSchema(adSchemaColumnPrivileges, [Catalog, Schema, Table, ColumnNamePattern]); if Assigned(AdoRecordSet) then begin with TZAdoResultSet.Create(GetStatement, '', AdoRecordSet) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TABLE_CAT', GetStringByName('TABLE_CATALOG')); Result.UpdateStringByName('TABLE_SCHEM', GetStringByName('TABLE_SCHEMA')); Result.UpdateStringByName('TABLE_NAME', GetStringByName('TABLE_NAME')); Result.UpdateStringByName('COLUMN_NAME', GetStringByName('COLUMN_NAME')); Result.UpdateStringByName('GRANTOR', GetStringByName('GRANTOR')); Result.UpdateStringByName('GRANTEE', GetStringByName('GRANTEE')); Result.UpdateStringByName('PRIVILEGE', GetStringByName('PRIVILEGE_TYPE')); if GetBooleanByName('IS_GRANTABLE') then Result.UpdateStringByName('IS_GRANTABLE', 'YES') else Result.UpdateStringByName('IS_GRANTABLE', 'NO'); Result.InsertRow; end; Close; Free; end; end; end; {** Gets a description of the access rights for each table available in a catalog. Note that a table privilege applies to one or more columns in the table. It would be wrong to assume that this priviledge applies to all columns (this may be true for some systems but is not true for all.)

Only privileges matching the schema and table name criteria are returned. They are ordered by TABLE_SCHEM, TABLE_NAME, and PRIVILEGE.

Each privilige description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. GRANTOR => grantor of access (may be null)
  5. GRANTEE String => grantee of access
  6. PRIVILEGE String => name of access (SELECT, INSERT, UPDATE, REFRENCES, ...)
  7. IS_GRANTABLE String => "YES" if grantee is permitted to grant to others; "NO" if not; null if unknown
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param tableNamePattern a table name pattern @return ResultSet - each row is a table privilege description @see #getSearchStringEscape } function TZAdoDatabaseMetadata.UncachedGetTablePrivileges(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string): IZResultSet; var AdoRecordSet: ZPlainAdo.RecordSet; begin Result:=inherited UncachedGetTablePrivileges(Catalog, SchemaPattern, TableNamePattern); AdoRecordSet := AdoOpenSchema(adSchemaTablePrivileges, [Catalog, SchemaPattern, TableNamePattern]); if Assigned(AdoRecordSet) then begin with TZAdoResultSet.Create(GetStatement, '', AdoRecordSet) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TABLE_CAT', GetStringByName('TABLE_CATALOG')); Result.UpdateStringByName('TABLE_SCHEM', GetStringByName('TABLE_SCHEMA')); Result.UpdateStringByName('TABLE_NAME', GetStringByName('TABLE_NAME')); Result.UpdateStringByName('GRANTOR', GetStringByName('GRANTOR')); Result.UpdateStringByName('GRANTEE', GetStringByName('GRANTEE')); Result.UpdateStringByName('PRIVILEGE', GetStringByName('PRIVILEGE_TYPE')); if GetBooleanByName('IS_GRANTABLE') then Result.UpdateStringByName('IS_GRANTABLE', 'YES') else Result.UpdateStringByName('IS_GRANTABLE', 'NO'); Result.InsertRow; end; Close; Free; end; end; end; {** Gets a description of a table's columns that are automatically updated when any value in a row is updated. They are unordered.

Each column description has the following columns:

  1. SCOPE short => is not used
  2. COLUMN_NAME String => column name
  3. DATA_TYPE short => SQL data type from java.sql.Types
  4. TYPE_NAME String => Data source dependent type name
  5. COLUMN_SIZE int => precision
  6. BUFFER_LENGTH int => length of column value in bytes
  7. DECIMAL_DIGITS short => scale
  8. PSEUDO_COLUMN short => is this a pseudo column like an Oracle ROWID
    • versionColumnUnknown - may or may not be pseudo column
    • versionColumnNotPseudo - is NOT a pseudo column
    • versionColumnPseudo - is a pseudo column
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a column description @exception SQLException if a database access error occurs } function TZAdoDatabaseMetadata.UncachedGetVersionColumns(const Catalog: string; const Schema: string; const Table: string): IZResultSet; const DBCOLUMNFLAGS_ISROWVER = $00000200; var AdoRecordSet: ZPlainAdo.RecordSet; begin Result:=inherited UncachedGetVersionColumns(Catalog, Schema, Table); AdoRecordSet := AdoOpenSchema(adSchemaColumns, [Catalog, Schema, Table]); if Assigned(AdoRecordSet) then begin with TZAdoResultSet.Create(GetStatement, '', AdoRecordSet) do begin while Next do begin if (GetIntByName('COLUMN_FLAGS') and DBCOLUMNFLAGS_ISROWVER) = 0 then Continue; Result.MoveToInsertRow; Result.UpdateShortByName('SCOPE', 0); Result.UpdateStringByName('COLUMN_NAME', GetStringByName('COLUMN_NAME')); Result.UpdateShortByName('DATA_TYPE', Ord(ConvertAdoToSqlType(GetShortByName('DATA_TYPE'), ConSettings.CPType))); Result.UpdateStringByName('TYPE_NAME', GetStringByName('TYPE_NAME')); Result.UpdateIntByName('COLUMN_SIZE', GetIntByName('CHARACTER_OCTET_LENGTH')); Result.UpdateIntByName('BUFFER_LENGTH', GetIntByName('CHARACTER_OCTET_LENGTH')); Result.UpdateIntByName('DECIMAL_DIGITS', GetIntByName('NUMERIC_SCALE')); Result.UpdateShortByName('PSEUDO_COLUMN', 0); Result.InsertRow; end; Close; Free; end; end; end; {** Gets a description of a table's primary key columns. They are ordered by COLUMN_NAME.

Each primary key column description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. COLUMN_NAME String => column name
  5. KEY_SEQ short => sequence number within primary key
  6. PK_NAME String => primary key name (may be null)
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a primary key column description @exception SQLException if a database access error occurs } function TZAdoDatabaseMetadata.UncachedGetPrimaryKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; var AdoRecordSet: ZPlainAdo.RecordSet; begin Result:=inherited UncachedGetPrimaryKeys(Catalog, Schema, Table); AdoRecordSet := AdoOpenSchema(adSchemaPrimaryKeys, [Catalog, Schema, Table]); if Assigned(AdoRecordSet) then begin with TZAdoResultSet.Create(GetStatement, '', AdoRecordSet) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TABLE_CAT', GetStringByName('TABLE_CATALOG')); Result.UpdateStringByName('TABLE_SCHEM', GetStringByName('TABLE_SCHEMA')); Result.UpdateStringByName('TABLE_NAME', GetStringByName('TABLE_NAME')); Result.UpdateStringByName('COLUMN_NAME', GetStringByName('COLUMN_NAME')); Result.UpdateShortByName('KEY_SEQ', GetShortByName('ORDINAL')); if FindColumn('PK_NAME') >= 1 then begin Result.UpdateStringByName('PK_NAME', GetStringByName('PK_NAME')); end; Result.InsertRow; end; Close; Free; end; end; end; {** Gets a description of the primary key columns that are referenced by a table's foreign key columns (the primary keys imported by a table). They are ordered by PKTABLE_CAT, PKTABLE_SCHEM, PKTABLE_NAME, and KEY_SEQ.

Each primary key column description has the following columns:

  1. PKTABLE_CAT String => primary key table catalog being imported (may be null)
  2. PKTABLE_SCHEM String => primary key table schema being imported (may be null)
  3. PKTABLE_NAME String => primary key table name being imported
  4. PKCOLUMN_NAME String => primary key column name being imported
  5. FKTABLE_CAT String => foreign key table catalog (may be null)
  6. FKTABLE_SCHEM String => foreign key table schema (may be null)
  7. FKTABLE_NAME String => foreign key table name
  8. FKCOLUMN_NAME String => foreign key column name
  9. KEY_SEQ short => sequence number within foreign key
  10. UPDATE_RULE short => What happens to foreign key when primary is updated:
    • importedNoAction - do not allow update of primary key if it has been imported
    • importedKeyCascade - change imported key to agree with primary key update
    • importedKeySetNull - change imported key to NULL if its primary key has been updated
    • importedKeySetDefault - change imported key to default values if its primary key has been updated
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
  11. DELETE_RULE short => What happens to the foreign key when primary is deleted.
    • importedKeyNoAction - do not allow delete of primary key if it has been imported
    • importedKeyCascade - delete rows that import a deleted key
    • importedKeySetNull - change imported key to NULL if its primary key has been deleted
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
    • importedKeySetDefault - change imported key to default if its primary key has been deleted
  12. FK_NAME String => foreign key name (may be null)
  13. PK_NAME String => primary key name (may be null)
  14. DEFERRABILITY short => can the evaluation of foreign key constraints be deferred until commit
    • importedKeyInitiallyDeferred - see SQL92 for definition
    • importedKeyInitiallyImmediate - see SQL92 for definition
    • importedKeyNotDeferrable - see SQL92 for definition
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a primary key column description @see #getExportedKeys } function TZAdoDatabaseMetadata.UncachedGetImportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; begin Result := UncachedGetCrossReference('', '', '', Catalog, Schema, Table); end; {** Gets a description of the foreign key columns that reference a table's primary key columns (the foreign keys exported by a table). They are ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, and KEY_SEQ.

Each foreign key column description has the following columns:

  1. PKTABLE_CAT String => primary key table catalog (may be null)
  2. PKTABLE_SCHEM String => primary key table schema (may be null)
  3. PKTABLE_NAME String => primary key table name
  4. PKCOLUMN_NAME String => primary key column name
  5. FKTABLE_CAT String => foreign key table catalog (may be null) being exported (may be null)
  6. FKTABLE_SCHEM String => foreign key table schema (may be null) being exported (may be null)
  7. FKTABLE_NAME String => foreign key table name being exported
  8. FKCOLUMN_NAME String => foreign key column name being exported
  9. KEY_SEQ short => sequence number within foreign key
  10. UPDATE_RULE short => What happens to foreign key when primary is updated:
    • importedNoAction - do not allow update of primary key if it has been imported
    • importedKeyCascade - change imported key to agree with primary key update
    • importedKeySetNull - change imported key to NULL if its primary key has been updated
    • importedKeySetDefault - change imported key to default values if its primary key has been updated
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
  11. DELETE_RULE short => What happens to the foreign key when primary is deleted.
    • importedKeyNoAction - do not allow delete of primary key if it has been imported
    • importedKeyCascade - delete rows that import a deleted key
    • importedKeySetNull - change imported key to NULL if its primary key has been deleted
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
    • importedKeySetDefault - change imported key to default if its primary key has been deleted
  12. FK_NAME String => foreign key name (may be null)
  13. PK_NAME String => primary key name (may be null)
  14. DEFERRABILITY short => can the evaluation of foreign key constraints be deferred until commit
    • importedKeyInitiallyDeferred - see SQL92 for definition
    • importedKeyInitiallyImmediate - see SQL92 for definition
    • importedKeyNotDeferrable - see SQL92 for definition
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a foreign key column description @see #getImportedKeys } function TZAdoDatabaseMetadata.UncachedGetExportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; begin Result := UncachedGetCrossReference(Catalog, Schema, Table, '', '', ''); end; {** Gets a description of the foreign key columns in the foreign key table that reference the primary key columns of the primary key table (describe how one table imports another's key.) This should normally return a single foreign key/primary key pair (most tables only import a foreign key from a table once.) They are ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, and KEY_SEQ.

Each foreign key column description has the following columns:

  1. PKTABLE_CAT String => primary key table catalog (may be null)
  2. PKTABLE_SCHEM String => primary key table schema (may be null)
  3. PKTABLE_NAME String => primary key table name
  4. PKCOLUMN_NAME String => primary key column name
  5. FKTABLE_CAT String => foreign key table catalog (may be null) being exported (may be null)
  6. FKTABLE_SCHEM String => foreign key table schema (may be null) being exported (may be null)
  7. FKTABLE_NAME String => foreign key table name being exported
  8. FKCOLUMN_NAME String => foreign key column name being exported
  9. KEY_SEQ short => sequence number within foreign key
  10. UPDATE_RULE short => What happens to foreign key when primary is updated:
    • importedNoAction - do not allow update of primary key if it has been imported
    • importedKeyCascade - change imported key to agree with primary key update
    • importedKeySetNull - change imported key to NULL if its primary key has been updated
    • importedKeySetDefault - change imported key to default values if its primary key has been updated
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
  11. DELETE_RULE short => What happens to the foreign key when primary is deleted.
    • importedKeyNoAction - do not allow delete of primary key if it has been imported
    • importedKeyCascade - delete rows that import a deleted key
    • importedKeySetNull - change imported key to NULL if its primary key has been deleted
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
    • importedKeySetDefault - change imported key to default if its primary key has been deleted
  12. FK_NAME String => foreign key name (may be null)
  13. PK_NAME String => primary key name (may be null)
  14. DEFERRABILITY short => can the evaluation of foreign key constraints be deferred until commit
    • importedKeyInitiallyDeferred - see SQL92 for definition
    • importedKeyInitiallyImmediate - see SQL92 for definition
    • importedKeyNotDeferrable - see SQL92 for definition
@param primaryCatalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param primarySchema a schema name; "" retrieves those without a schema @param primaryTable the table name that exports the key @param foreignCatalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param foreignSchema a schema name; "" retrieves those without a schema @param foreignTable the table name that imports the key @return ResultSet - each row is a foreign key column description @see #getImportedKeys } function TZAdoDatabaseMetadata.UncachedGetCrossReference(const PrimaryCatalog: string; const PrimarySchema: string; const PrimaryTable: string; const ForeignCatalog: string; const ForeignSchema: string; const ForeignTable: string): IZResultSet; var AdoRecordSet: ZPlainAdo.RecordSet; function GetRuleType(const Rule: String): TZImportedKey; begin if Rule = 'RESTRICT' then Result := ikRestrict else if Rule = 'NO ACTION' then Result := ikNoAction else if Rule = 'CASCADE' then Result := ikCascade else if Rule = 'SET DEFAULT' then Result := ikSetDefault else if Rule = 'SET NULL' then Result := ikSetNull else Result := ikNotDeferrable; //impossible! end; begin Result:=inherited UncachedGetCrossReference(PrimaryCatalog, PrimarySchema, PrimaryTable, ForeignCatalog, ForeignSchema, ForeignTable); AdoRecordSet := AdoOpenSchema(adSchemaForeignKeys, [PrimaryCatalog, PrimarySchema, PrimaryTable, ForeignCatalog, ForeignSchema, ForeignTable]); if Assigned(AdoRecordSet) then begin with TZAdoResultSet.Create(GetStatement, '', AdoRecordSet) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('PKTABLE_CAT', GetStringByName('PK_TABLE_CATALOG')); Result.UpdateStringByName('PKTABLE_SCHEM', GetStringByName('PK_TABLE_SCHEMA')); Result.UpdateStringByName('PKTABLE_NAME', GetStringByName('PK_TABLE_NAME')); Result.UpdateStringByName('PKCOLUMN_NAME', GetStringByName('PK_COLUMN_NAME')); Result.UpdateStringByName('FKTABLE_CAT', GetStringByName('FK_TABLE_CATALOG')); Result.UpdateStringByName('FKTABLE_SCHEM', GetStringByName('FK_TABLE_SCHEMA')); Result.UpdateStringByName('FKTABLE_NAME', GetStringByName('FK_TABLE_NAME')); Result.UpdateStringByName('FKCOLUMN_NAME', GetStringByName('FK_COLUMN_NAME')); Result.UpdateShortByName('KEY_SEQ', GetShortByName('ORDINAL')); Result.UpdateShortByName('UPDATE_RULE', Ord(GetRuleType(GetStringByName('UPDATE_RULE')))); Result.UpdateShortByName('DELETE_RULE', Ord(GetRuleType(GetStringByName('DELETE_RULE')))); Result.UpdateStringByName('FK_NAME', GetStringByName('FK_NAME')); Result.UpdateStringByName('PK_NAME', GetStringByName('PK_NAME')); Result.UpdateIntByName('DEFERRABILITY', GetShortByName('DEFERRABILITY')); Result.InsertRow; end; Close; Free; end; end; end; {** Gets a description of all the standard SQL types supported by this database. They are ordered by DATA_TYPE and then by how closely the data type maps to the corresponding JDBC SQL type.

Each type description has the following columns:

  1. TYPE_NAME String => Type name
  2. DATA_TYPE short => SQL data type from java.sql.Types
  3. PRECISION int => maximum precision
  4. LITERAL_PREFIX String => prefix used to quote a literal (may be null)
  5. LITERAL_SUFFIX String => suffix used to quote a literal (may be null)
  6. CREATE_PARAMS String => parameters used in creating the type (may be null)
  7. NULLABLE short => can you use NULL for this type?
    • typeNoNulls - does not allow NULL values
    • typeNullable - allows NULL values
    • typeNullableUnknown - nullability unknown
  8. CASE_SENSITIVE boolean=> is it case sensitive?
  9. SEARCHABLE short => can you use "WHERE" based on this type:
    • typePredNone - No support
    • typePredChar - Only supported with WHERE .. LIKE
    • typePredBasic - Supported except for WHERE .. LIKE
    • typeSearchable - Supported for all WHERE ..
  10. UNSIGNED_ATTRIBUTE boolean => is it unsigned?
  11. FIXED_PREC_SCALE boolean => can it be a money value?
  12. AUTO_INCREMENT boolean => can it be used for an auto-increment value?
  13. LOCAL_TYPE_NAME String => localized version of type name (may be null)
  14. MINIMUM_SCALE short => minimum scale supported
  15. MAXIMUM_SCALE short => maximum scale supported
  16. SQL_DATA_TYPE int => unused
  17. SQL_DATETIME_SUB int => unused
  18. NUM_PREC_RADIX int => usually 2 or 10
@return ResultSet - each row is an SQL type description } function TZAdoDatabaseMetadata.UncachedGetTypeInfo: IZResultSet; var AdoRecordSet: ZPlainAdo.RecordSet; begin Result:=inherited UncachedGetTypeInfo; AdoRecordSet := AdoOpenSchema(adSchemaProviderTypes, []); if Assigned(AdoRecordSet) then begin with TZAdoResultSet.Create(GetStatement, '', AdoRecordSet) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TYPE_NAME', GetStringByName('TYPE_NAME')); Result.UpdateShortByName('DATA_TYPE', Ord(ConvertAdoToSqlType(GetShortByName('DATA_TYPE'), ConSettings.CPType))); Result.UpdateIntByName('PRECISION', 0);//GetIntByName('PRECISION')); Result.UpdateStringByName('LITERAL_PREFIX', GetStringByName('LITERAL_PREFIX')); Result.UpdateStringByName('LITERAL_SUFFIX', GetStringByName('LITERAL_SUFFIX')); Result.UpdateStringByName('CREATE_PARAMS', GetStringByName('CREATE_PARAMS')); if GetBooleanByName('IS_NULLABLE') then Result.UpdateShortByName('NULLABLE', 1) else Result.UpdateShortByName('NULLABLE', 0); Result.UpdateBooleanByName('CASE_SENSITIVE', GetBooleanByName('CASE_SENSITIVE')); Result.UpdateShortByName('SEARCHABLE', GetShortByName('SEARCHABLE')); Result.UpdateBooleanByName('UNSIGNED_ATTRIBUTE', GetBooleanByName('UNSIGNED_ATTRIBUTE')); Result.UpdateBooleanByName('FIXED_PREC_SCALE', GetBooleanByName('FIXED_PREC_SCALE')); Result.UpdateBooleanByName('AUTO_INCREMENT', False); Result.UpdateStringByName('LOCAL_TYPE_NAME', GetStringByName('LOCAL_TYPE_NAME')); Result.UpdateShortByName('MINIMUM_SCALE', GetShortByName('MINIMUM_SCALE')); Result.UpdateShortByName('MAXIMUM_SCALE', GetShortByName('MAXIMUM_SCALE')); // Result.UpdateShortByName('SQL_DATA_TYPE', // GetShortByName('SQL_DATA_TYPE')); // Result.UpdateShortByName('SQL_DATETIME_SUB', // GetShortByName('SQL_DATETIME_SUB')); // Result.UpdateShortByName('NUM_PREC_RADIX', // GetShortByName('NUM_PREC_RADIX')); Result.InsertRow; end; Close; Free; end; end; end; {** Gets a description of a table's indices and statistics. They are ordered by NON_UNIQUE, TYPE, INDEX_NAME, and ORDINAL_POSITION.

Each index column description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. NON_UNIQUE boolean => Can index values be non-unique? false when TYPE is tableIndexStatistic
  5. INDEX_QUALIFIER String => index catalog (may be null); null when TYPE is tableIndexStatistic
  6. INDEX_NAME String => index name; null when TYPE is tableIndexStatistic
  7. TYPE short => index type:
    • tableIndexStatistic - this identifies table statistics that are returned in conjuction with a table's index descriptions
    • tableIndexClustered - this is a clustered index
    • tableIndexHashed - this is a hashed index
    • tableIndexOther - this is some other style of index
  8. ORDINAL_POSITION short => column sequence number within index; zero when TYPE is tableIndexStatistic
  9. COLUMN_NAME String => column name; null when TYPE is tableIndexStatistic
  10. ASC_OR_DESC String => column sort sequence, "A" => ascending, "D" => descending, may be null if sort sequence is not supported; null when TYPE is tableIndexStatistic
  11. CARDINALITY int => When TYPE is tableIndexStatistic, then this is the number of rows in the table; otherwise, it is the number of unique values in the index.
  12. PAGES int => When TYPE is tableIndexStatisic then this is the number of pages used for the table, otherwise it is the number of pages used for the current index.
  13. FILTER_CONDITION String => Filter condition, if any. (may be null)
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @param unique when true, return only indices for unique values; when false, return indices regardless of whether unique or not @param approximate when true, result is allowed to reflect approximate or out of data values; when false, results are requested to be accurate @return ResultSet - each row is an index column description } function TZAdoDatabaseMetadata.UncachedGetIndexInfo(const Catalog: string; const Schema: string; const Table: string; Unique: Boolean; Approximate: Boolean): IZResultSet; var AdoRecordSet: ZPlainAdo.RecordSet; begin Result:=inherited UncachedGetIndexInfo(Catalog, Schema, Table, Unique, Approximate); AdoRecordSet := AdoOpenSchema(adSchemaIndexes, [Catalog, Schema, '', '', Table]); if Assigned(AdoRecordSet) then begin with TZAdoResultSet.Create(GetStatement, '', AdoRecordSet) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TABLE_CAT', GetStringByName('TABLE_CATALOG')); Result.UpdateStringByName('TABLE_SCHEM', GetStringByName('TABLE_SCHEMA')); Result.UpdateStringByName('TABLE_NAME', GetStringByName('TABLE_NAME')); Result.UpdateBooleanByName('NON_UNIQUE', not GetBooleanByName('UNIQUE')); Result.UpdateStringByName('INDEX_QUALIFIER', GetStringByName('INDEX_CATALOG')); Result.UpdateStringByName('INDEX_NAME', GetStringByName('INDEX_NAME')); Result.UpdateShortByName('TYPE', GetShortByName('TYPE')); Result.UpdateShortByName('ORDINAL_POSITION', GetShortByName('ORDINAL_POSITION')); Result.UpdateStringByName('COLUMN_NAME', GetStringByName('COLUMN_NAME')); //!!! Result.UpdateStringByName('ASC_OR_DESC', // GetStringByName('COLLATION')); Result.UpdateIntByName('CARDINALITY', GetIntByName('CARDINALITY')); Result.UpdateIntByName('PAGES', GetIntByName('PAGES')); Result.UpdateStringByName('FILTER_CONDITION', GetStringByName('FILTER_CONDITION')); Result.InsertRow; end; Close; Free; end; end; end; {** Gets a description of the user-defined types defined in a particular schema. Schema-specific UDTs may have type JAVA_OBJECT, STRUCT, or DISTINCT.

Only types matching the catalog, schema, type name and type criteria are returned. They are ordered by DATA_TYPE, TYPE_SCHEM and TYPE_NAME. The type name parameter may be a fully-qualified name. In this case, the catalog and schemaPattern parameters are ignored.

Each type description has the following columns:

  1. TYPE_CAT String => the type's catalog (may be null)
  2. TYPE_SCHEM String => type's schema (may be null)
  3. TYPE_NAME String => type name
  4. CLASS_NAME String => Java class name
  5. DATA_TYPE String => type value defined in java.sql.Types. One of JAVA_OBJECT, STRUCT, or DISTINCT
  6. REMARKS String => explanatory comment on the type

Note: If the driver does not support UDTs, an empty result set is returned. @param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param typeNamePattern a type name pattern; may be a fully-qualified name @param types a list of user-named types to include (JAVA_OBJECT, STRUCT, or DISTINCT); null returns all types @return ResultSet - each row is a type description } function TZAdoDatabaseMetadata.UncachedGetUDTs(const Catalog: string; const SchemaPattern: string; const TypeNamePattern: string; const Types: TIntegerDynArray): IZResultSet; begin Result:=inherited UncachedGetUDTs(Catalog, SchemaPattern, TypeNamePattern, Types); // AdoRecordSet := AdoOpenSchema(adSchemaIndexes, Restrictions); // if Assigned(AdoRecordSet) then // with GetStatement.ExecuteQuery( // Format('select TYPE_CAT = db_name(), TYPE_SCHEM = user_name(uid),' // + ' TYPE_NAME = st.name, DATA_TYPE from master.dbo.spt_datatype_info' // + ' sti left outer join systypes st on (sti.ss_dtype = st.xtype)' // + ' where st.xusertype > 255 and user_name(uid) like %s and st.name' // + ' like %s', [SchemaPattern, TypeNamePattern])) do // while Next do // begin // Result.MoveToInsertRow; // Result.UpdateString('TYPE_CAT', GetString('TYPE_CAT')); // Result.UpdateString('TYPE_SCHEM', GetString('TYPE_SCHEM')); // Result.UpdateString('TYPE_NAME', GetString('TYPE_NAME')); // Result.UpdateNull('JAVA_CLASS'); // Result.UpdateShort('DATA_TYPE', GetShort('DATA_TYPE')); // Result.UpdateNull('REMARKS'); // Result.InsertRow; // end; end; {** Open a schema rowset from ado @Schema Ado identifier @Args Variant array with restrictions @return ADO recordset with the schemas; nil if the schema is not supported } function TZAdoDatabaseMetadata.AdoOpenSchema(Schema: Integer; const Args: array of const): ZPlainAdo.RecordSet; var Restrictions: Variant; begin Result := nil; if not FSupportedSchemasInitialized then InitializeSchemas; if not SchemaSupported(Schema) then Exit; try Restrictions := BuildRestrictions(Schema, Args); Result := (GetConnection as IZAdoConnection).GetAdoConnection. OpenSchema(Schema, Restrictions, EmptyParam); except Result := nil; end; end; {** Initialize supported schemas and restrictions from the OleDB provider } procedure TZAdoDatabaseMetadata.InitializeSchemas; var AdoConnection: IZAdoConnection; OleDBSession: IUnknown; SchemaRS: IDBSchemaRowset; PG, OriginalPG: PGUID; IA: PIntegerArray; Nr: Integer; I: Integer; begin if not FSupportedSchemasInitialized then begin if not Assigned(FAdoConnection) then begin GetConnection.QueryInterface(IZAdoConnection, AdoConnection); FAdoConnection := AdoConnection.GetAdoConnection; end; (FAdoConnection as ADOConnectionConstruction).Get_Session(OleDBSession); if Assigned(OleDBSession) then begin OleDBSession.QueryInterface(IDBSchemaRowset, SchemaRS); if Assigned(SchemaRS) then begin SchemaRS.GetSchemas(Nr, PG, PInteger(IA)); OriginalPG := PG; SetLength(SupportedSchemas, Nr); for I := 0 to Nr - 1 do begin SupportedSchemas[I].SchemaGuid := PG^; SupportedSchemas[I].SupportedRestrictions := IA^[I]; SupportedSchemas[I].AdoSchemaId := ConvertOleDBToAdoSchema(PG^); Inc({$IFDEF DELPHI16_UP}NativeInt{$ELSE}Integer{$ENDIF}(PG), SizeOf(TGuid)); //M.A. Inc(Integer(PG), SizeOf(TGuid)); end; FSupportedSchemasInitialized := True; if Assigned(OriginalPG) then ZAdoMalloc.Free(OriginalPG); if Assigned(IA) then ZAdoMalloc.Free(IA); end; end; end; end; {** Find the Schema Id in the supported schemas @SchemaId Ado identifier @return Index of the schema in the supported schemas array } function TZAdoDatabaseMetadata.FindSchema(SchemaId: Integer): Integer; var I: Integer; begin Result := -1; for I := 0 to Length(SupportedSchemas) - 1 do if SupportedSchemas[I].AdoSchemaId = SchemaId then begin Result := I; Break; end; end; {** Is the schema supported by the OleDB provider? @SchemaId Ado identifier @return True if the schema is supported } function TZAdoDatabaseMetadata.SchemaSupported(SchemaId: Integer): Boolean; begin Result := FindSchema(SchemaId) > -1; end; {** Build a variant array from the provided parameters based on the supported restrictions @SchemaId Ado identifier @Args Restrictions @return Variant array of restrictions } function TZAdoDatabaseMetadata.BuildRestrictions(SchemaId: Integer; const Args: array of const): Variant; var SchemaIndex: Integer; I: Integer; begin Result := Null; if High(Args) = -1 then Exit; SchemaIndex := FindSchema(SchemaId); if SchemaIndex = -1 then Exit; Result := VarArrayCreate([0, High(Args)], varVariant); for I := 0 to High(Args) do begin if (SupportedSchemas[SchemaIndex].SupportedRestrictions and (1 shl I)) <> 0 then begin {$IFDEF UNICODE} Result[I] := string(Args[I].VPWideChar); if (Args[I].VType = VtUnicodeString) then if string(Args[I].VPWideChar) = '' then {$ELSE} Result[I] := string(Args[I].VAnsiString); if (Args[I].VType = vtAnsiString) then if string(Args[I].VAnsiString) = '' then {$ENDIF} Result[I] := UnAssigned; end else Result[I] := UnAssigned; end; end; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcAdoResultSet.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Ado Resultset common functionality } { } { Originally written by Janos Fegyverneki } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcAdoResultSet; interface {$I ZDbc.inc} uses {$IFNDEF FPC} DateUtils, {$ENDIF} {$IFDEF WITH_TOBJECTLIST_INLINE}System.Types, System.Contnrs{$ELSE}Types{$ENDIF}, Classes, SysUtils, ZClasses, ZSysUtils, ZCollections, ZDbcIntfs, ZDbcGenericResolver, ZDbcCachedResultSet, ZDbcCache, ZDbcResultSet, ZDbcResultsetMetadata, ZCompatibility, ZDbcAdo, ZPlainAdoDriver, ZPlainAdo; type {** Implements Ado ResultSet. } TZAdoResultSet = class(TZAbstractResultSet) private AdoColTypeCache: TIntegerDynArray; AdoColumnCount: Integer; FFirstFetch: Boolean; protected FAdoRecordSet: ZPlainAdo.RecordSet; procedure Open; override; public constructor Create(Statement: IZStatement; SQL: string; AdoRecordSet: ZPlainAdo.RecordSet); destructor Destroy; override; procedure Close; override; function Next: Boolean; override; function MoveAbsolute(Row: Integer): Boolean; override; function GetRow: Integer; override; function IsNull(ColumnIndex: Integer): Boolean; override; function GetString(ColumnIndex: Integer): String; override; function GetUnicodeString(ColumnIndex: Integer): WideString; override; function GetBoolean(ColumnIndex: Integer): Boolean; override; function GetByte(ColumnIndex: Integer): Byte; override; function GetShort(ColumnIndex: Integer): SmallInt; override; function GetInt(ColumnIndex: Integer): Integer; override; function GetLong(ColumnIndex: Integer): Int64; override; function GetFloat(ColumnIndex: Integer): Single; override; function GetDouble(ColumnIndex: Integer): Double; override; function GetBigDecimal(ColumnIndex: Integer): Extended; override; function GetBytes(ColumnIndex: Integer): TByteDynArray; override; function GetDate(ColumnIndex: Integer): TDateTime; override; function GetTime(ColumnIndex: Integer): TDateTime; override; function GetTimestamp(ColumnIndex: Integer): TDateTime; override; function GetBlob(ColumnIndex: Integer): IZBlob; override; end; {** Implements a cached resolver with Ado specific functionality. } TZAdoCachedResolver = class (TZGenericCachedResolver, IZCachedResolver) private FHandle: ZPlainAdo.Command; FAutoColumnIndex: Integer; public constructor Create(Handle: ZPlainAdo.Connection; Statement: IZStatement; Metadata: IZResultSetMetadata); procedure PostUpdates(Sender: IZCachedResultSet; UpdateType: TZRowUpdateType; OldRowAccessor, NewRowAccessor: TZRowAccessor); override; end; implementation uses Variants, Math, OleDB, ZMessages, ZDbcUtils, ZDbcAdoUtils, ZEncoding; {** Creates this object and assignes the main properties. @param Statement an SQL statement object. @param SQL an SQL query string. @param AdoRecordSet a ADO recordset object, the source of the ResultSet. } constructor TZAdoResultSet.Create(Statement: IZStatement; SQL: string; AdoRecordSet: ZPlainAdo.RecordSet); begin inherited Create(Statement, SQL, nil, Statement.GetConnection.GetConSettings); FAdoRecordSet := AdoRecordSet; Open; end; {** Destroys this object and cleanups the memory. } destructor TZAdoResultSet.Destroy; begin Close; inherited; end; {** Opens this recordset and initializes the Column information. } procedure TZAdoResultSet.Open; var OleDBRowset: IUnknown; OleDBColumnsInfo: IColumnsInfo; pcColumns: NativeUInt; prgInfo, OriginalprgInfo: PDBColumnInfo; ppStringsBuffer: PWideChar; I: Integer; FieldSize: Integer; ColumnInfo: TZColumnInfo; ColName: string; ColType: Integer; HasAutoIncProp: Boolean; F: ZPlainAdo.Field20; S: string; J: Integer; begin //Check if the current statement can return rows if not Assigned(FAdoRecordSet) or (FAdoRecordSet.State = adStateClosed) then raise EZSQLException.Create(SCanNotRetrieveResultSetData); (FAdoRecordSet as ADORecordsetConstruction).Get_Rowset(OleDBRowset); OleDBRowset.QueryInterface(IColumnsInfo, OleDBColumnsInfo); OleDBColumnsInfo.GetColumnInfo(pcColumns, prgInfo, ppStringsBuffer); OriginalprgInfo := prgInfo; { Fills the column info } ColumnsInfo.Clear; AdoColumnCount := FAdoRecordSet.Fields.Count; SetLength(AdoColTypeCache, AdoColumnCount); HasAutoIncProp := False; if AdoColumnCount > 0 then for I := 0 to FAdoRecordSet.Fields.Item[0].Properties.Count - 1 do if FAdoRecordSet.Fields.Item[0].Properties.Item[I].Name = 'ISAUTOINCREMENT' then begin HasAutoIncProp := True; Break; end; if Assigned(prgInfo) then if prgInfo.iOrdinal = 0 then Inc(NativeInt(prgInfo), SizeOf(TDBColumnInfo)); for I := 0 to AdoColumnCount - 1 do begin ColumnInfo := TZColumnInfo.Create; F := FAdoRecordSet.Fields.Item[I]; ColName := F.Name; ColType := F.Type_; ColumnInfo.ColumnLabel := ColName; ColumnInfo.ColumnName := ColName; ColumnInfo.ColumnType := ConvertAdoToSqlType(ColType, ConSettings.CPType); FieldSize := F.DefinedSize; if FieldSize < 0 then FieldSize := 0; if F.Type_ = adGuid then ColumnInfo.ColumnDisplaySize := 38 else ColumnInfo.ColumnDisplaySize := FieldSize; ColumnInfo.Precision := FieldSize; ColumnInfo.Currency := ColType = adCurrency; ColumnInfo.Signed := False; S := ''; for J := 0 to F.Properties.Count - 1 do S := S+F.Properties.Item[J].Name + '=' + VarToStr(F.Properties.Item[J].Value) + ', '; if HasAutoIncProp then ColumnInfo.AutoIncrement := F.Properties.Item['ISAUTOINCREMENT'].Value; if ColType in [adTinyInt, adSmallInt, adInteger, adBigInt, adCurrency, adDecimal, adDouble, adNumeric, adSingle] then ColumnInfo.Signed := True; ColumnInfo.Writable := (prgInfo.dwFlags and (DBCOLUMNFLAGS_WRITE or DBCOLUMNFLAGS_WRITEUNKNOWN) <> 0) and (F.Properties.Item['BASECOLUMNNAME'].Value <> null) and not ColumnInfo.AutoIncrement; ColumnInfo.ReadOnly := (prgInfo.dwFlags and (DBCOLUMNFLAGS_WRITE or DBCOLUMNFLAGS_WRITEUNKNOWN) = 0) or ColumnInfo.AutoIncrement; ColumnInfo.Searchable := (prgInfo.dwFlags and DBCOLUMNFLAGS_ISLONG) = 0; if (prgInfo.dwFlags and DBCOLUMNFLAGS_ISLONG) <> 0 then case ColumnInfo.ColumnType of stString: ColumnInfo.ColumnType := stAsciiStream; stUnicodeString: ColumnInfo.ColumnType := stUnicodeStream; end; ColumnsInfo.Add(ColumnInfo); AdoColTypeCache[I] := ColType; Inc(NativeInt(prgInfo), SizeOf(TDBColumnInfo)); //M.A. Inc(Integer(prgInfo), SizeOf(TDBColumnInfo)); end; if Assigned(ppStringsBuffer) then ZAdoMalloc.Free(ppStringsBuffer); if Assigned(OriginalprgInfo) then ZAdoMalloc.Free(OriginalprgInfo); FFirstFetch := True; inherited; end; {** Releases this ResultSet object's database and ADO resources immediately instead of waiting for this to happen when it is automatically closed.

Note: A ResultSet object is automatically closed by the Statement object that generated it when that Statement object is closed, re-executed, or is used to retrieve the next result from a sequence of multiple results. A ResultSet object is also automatically closed when it is garbage collected. } procedure TZAdoResultSet.Close; begin FAdoRecordSet := nil; inherited; end; {** Moves the cursor down one row from its current position. A ResultSet cursor is initially positioned before the first row; the first call to the method next makes the first row the current row; the second call makes the second row the current row, and so on.

If an input stream is open for the current row, a call to the method next will implicitly close it. A ResultSet object's warning chain is cleared when a new row is read. @return true if the new current row is valid; false if there are no more rows } function TZAdoResultSet.Next: Boolean; begin Result := False; if FAdoRecordSet.BOF and FAdoRecordSet.EOF then Exit; if FAdoRecordSet.BOF then FAdoRecordSet.MoveFirst else if not FAdoRecordSet.EOF and not FFirstFetch then FAdoRecordSet.MoveNext; FFirstFetch := False; Result := not FAdoRecordSet.EOF; end; {** Moves the cursor to the given row number in this ResultSet object.

If the row number is positive, the cursor moves to the given row number with respect to the beginning of the result set. The first row is row 1, the second is row 2, and so on.

If the given row number is negative, the cursor moves to an absolute row position with respect to the end of the result set. For example, calling the method absolute(-1) positions the cursor on the last row; calling the method absolute(-2) moves the cursor to the next-to-last row, and so on.

An attempt to position the cursor beyond the first/last row in the result set leaves the cursor before the first row or after the last row.

Note: Calling absolute(1) is the same as calling first(). Calling absolute(-1) is the same as calling last(). @return true if the cursor is on the result set; false otherwise } function TZAdoResultSet.MoveAbsolute(Row: Integer): Boolean; begin if FAdoRecordSet.EOF or FAdoRecordSet.BOF then FAdoRecordSet.MoveFirst; if Row > 0 then FAdoRecordSet.Move(Row - 1, adBookmarkFirst) else FAdoRecordSet.Move(Abs(Row) - 1, adBookmarkLast); Result := not (FAdoRecordSet.EOF or FAdoRecordSet.BOF); end; {** Retrieves the current row number. The first row is number 1, the second number 2, and so on. @return the current row number; 0 if there is no current row } function TZAdoResultSet.GetRow: Integer; begin if FAdoRecordSet.EOF or FAdoRecordSet.BOF then Result := -1 else Result := FAdoRecordSet.AbsolutePosition; end; {** Indicates if the value of the designated column in the current row of this ResultSet object is Null. @param columnIndex the first column is 1, the second is 2, ... @return if the value is SQL NULL, the value returned is true. false otherwise. } function TZAdoResultSet.IsNull(ColumnIndex: Integer): Boolean; begin Result := VarIsNull(FAdoRecordSet.Fields.Item[ColumnIndex - 1].Value) or VarIsEmpty(FAdoRecordSet.Fields.Item[ColumnIndex - 1].Value); end; {** Gets the value of the designated column in the current row of this ResultSet object as a String in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZAdoResultSet.GetString(ColumnIndex: Integer): String; {var NL: Integer;} begin Result := ''; LastWasNull := IsNull(ColumnIndex); if LastWasNull then Exit; if (VarType(FAdoRecordSet.Fields.Item[ColumnIndex - 1].Value) = varOleStr) {$IFDEF UNICODE} or ( VarType(FAdoRecordSet.Fields.Item[ColumnIndex - 1].Value) = varUString){$ENDIF} then Result := ZDbcString(ZWideString(FAdoRecordSet.Fields.Item[ColumnIndex - 1].Value)) else Result := ZDbcString(AnsiString(FAdoRecordSet.Fields.Item[ColumnIndex - 1].Value)) {Why this? It cuts wanted trailing spaces! NL := Length(Result); while (NL > 0) and (Result[NL] = ' ') do Dec(NL); SetLength(Result, NL);} end; {** Gets the value of the designated column in the current row of this ResultSet object as a WideString in the Delphi programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZAdoResultSet.GetUnicodeString(ColumnIndex: Integer): WideString; {var NL: Integer;} begin Result := ''; LastWasNull := IsNull(ColumnIndex); if LastWasNull then Exit; Result := FAdoRecordSet.Fields.Item[ColumnIndex - 1].Value; {Why this? It cuts wanted trailing spaces! NL := Length(Result); while (NL > 0) and (Result[NL] = ' ') do Dec(NL); SetLength(Result, NL);} end; {** Gets the value of the designated column in the current row of this ResultSet object as a boolean in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is false } function TZAdoResultSet.GetBoolean(ColumnIndex: Integer): Boolean; begin Result := False; LastWasNull := IsNull(ColumnIndex); if LastWasNull then Exit; try Result := FAdoRecordSet.Fields.Item[ColumnIndex - 1].Value; except Result := False; end; end; {** Gets the value of the designated column in the current row of this ResultSet object as a byte in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZAdoResultSet.GetByte(ColumnIndex: Integer): Byte; begin Result := 0; LastWasNull := IsNull(ColumnIndex); if LastWasNull then Exit; try Result := FAdoRecordSet.Fields.Item[ColumnIndex - 1].Value; except Result := 0; end; end; {** Gets the value of the designated column in the current row of this ResultSet object as a short in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZAdoResultSet.GetShort(ColumnIndex: Integer): SmallInt; begin Result := 0; LastWasNull := IsNull(ColumnIndex); if LastWasNull then Exit; try Result := FAdoRecordSet.Fields.Item[ColumnIndex - 1].Value; except Result := 0; end; end; {** Gets the value of the designated column in the current row of this ResultSet object as an int in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZAdoResultSet.GetInt(ColumnIndex: Integer): Integer; begin Result := 0; LastWasNull := IsNull(ColumnIndex); if LastWasNull then Exit; try Result := FAdoRecordSet.Fields.Item[ColumnIndex - 1].Value; except Result := 0; end; end; {** Gets the value of the designated column in the current row of this ResultSet object as a long in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZAdoResultSet.GetLong(ColumnIndex: Integer): Int64; begin Result := 0; LastWasNull := IsNull(ColumnIndex); if LastWasNull then Exit; try Result := FAdoRecordSet.Fields.Item[ColumnIndex - 1].Value; except Result := 0; end; end; {** Gets the value of the designated column in the current row of this ResultSet object as a float in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZAdoResultSet.GetFloat(ColumnIndex: Integer): Single; begin Result := 0; LastWasNull := IsNull(ColumnIndex); if LastWasNull then Exit; try Result := FAdoRecordSet.Fields.Item[ColumnIndex - 1].Value; except Result := 0; end; end; {** Gets the value of the designated column in the current row of this ResultSet object as a double in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZAdoResultSet.GetDouble(ColumnIndex: Integer): Double; begin Result := 0; LastWasNull := IsNull(ColumnIndex); if LastWasNull then Exit; try Result := FAdoRecordSet.Fields.Item[ColumnIndex - 1].Value; except Result := 0; end; end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.BigDecimal in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @param scale the number of digits to the right of the decimal point @return the column value; if the value is SQL NULL, the value returned is null } function TZAdoResultSet.GetBigDecimal(ColumnIndex: Integer): Extended; begin Result := 0; LastWasNull := IsNull(ColumnIndex); if LastWasNull then Exit; try Result := FAdoRecordSet.Fields.Item[ColumnIndex - 1].Value; except Result := 0; end; end; {** Gets the value of the designated column in the current row of this ResultSet object as a byte array in the Java programming language. The bytes represent the raw values returned by the driver. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZAdoResultSet.GetBytes(ColumnIndex: Integer): TByteDynArray; var V: Variant; GUID: TGUID; begin SetLength(Result, 0); LastWasNull := IsNull(ColumnIndex); if LastWasNull then Exit; V := FAdoRecordSet.Fields.Item[ColumnIndex - 1].Value; if VarType(V) = varByte then Result := V else if TZColumnInfo(ColumnsInfo[ColumnIndex-1]).ColumnType = stGUID then begin SetLength(Result, 16); GUID := StringToGUID(V); System.Move(Pointer(@GUID)^, Pointer(Result)^, 16); end else Result := V end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Date object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZAdoResultSet.GetDate(ColumnIndex: Integer): TDateTime; begin Result := 0; LastWasNull := IsNull(ColumnIndex); if LastWasNull then Exit; try Result := FAdoRecordSet.Fields.Item[ColumnIndex - 1].Value; except Result := 0; end; end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Time object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZAdoResultSet.GetTime(ColumnIndex: Integer): TDateTime; begin Result := 0; LastWasNull := IsNull(ColumnIndex); if LastWasNull then Exit; try Result := FAdoRecordSet.Fields.Item[ColumnIndex - 1].Value; except Result := 0; end; end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null @exception SQLException if a database access error occurs } function TZAdoResultSet.GetTimestamp(ColumnIndex: Integer): TDateTime; begin Result := 0; LastWasNull := IsNull(ColumnIndex); if LastWasNull then Exit; try Result := FAdoRecordSet.Fields.Item[ColumnIndex - 1].Value; except Result := 0; end; end; {** Returns the value of the designated column in the current row of this ResultSet object as a Blob object in the Java programming language. @param ColumnIndex the first column is 1, the second is 2, ... @return a Blob object representing the SQL BLOB value in the specified column } function TZAdoResultSet.GetBlob(ColumnIndex: Integer): IZBlob; var V: Variant; P: Pointer; begin Result := nil; LastWasNull := IsNull(ColumnIndex); if LastWasNull then Exit; V := FAdoRecordSet.Fields.Item[ColumnIndex - 1].Value; if VarIsStr(V) {$IFDEF UNICODE} or ( VarType(V) = varUString){$ENDIF} then begin Result := TZAbstractBlob.CreateWithStream(nil, GetStatement.GetConnection); case GetMetadata.GetColumnType(ColumnIndex) of stAsciiStream: if (VarType(V) = varOleStr) {$IFDEF UNICODE} or ( VarType(V) = varUString){$ENDIF} then if ConSettings^.AutoEncode then if ConSettings^.CPType = cCP_UTF8 then Result.SetString(UTF8Encode(V)) else Result.SetString(AnsiString(V)) else Result.SetString(AnsiString(V)) else Result.SetString(GetValidatedAnsiString(V, ConSettings, True)); stUnicodeStream: Result.SetUnicodeString(WideString(V)); else Result.SetString(RawByteString(V)); end; end; if VarIsArray(V) then begin P := VarArrayLock(V); try Result := TZAbstractBlob.CreateWithData(P, VarArrayHighBound(V, 1)+1, GetStatement.GetConnection); finally VarArrayUnLock(V); end; end; end; { TZAdoCachedResolver } {** Creates a Ado specific cached resolver object. @param PlainDriver a native Ado plain driver. @param Handle a Ado specific query handle. @param Statement a related SQL statement object. @param Metadata a resultset metadata reference. } constructor TZAdoCachedResolver.Create(Handle: ZPlainAdo.Connection; Statement: IZStatement; Metadata: IZResultSetMetadata); var I: Integer; begin inherited Create(Statement, Metadata); FHandle := ZPlainAdo.CoCommand.Create; FHandle._Set_ActiveConnection(Handle); FHandle.CommandText := 'SELECT @@IDENTITY'; FHandle.CommandType := adCmdText; { Defines an index of autoincrement field. } FAutoColumnIndex := 0; for I := 1 to Metadata.GetColumnCount do begin if Metadata.IsAutoIncrement(I) and (Metadata.GetColumnType(I) in [stByte, stShort, stInteger, stLong]) then begin FAutoColumnIndex := I; Break; end; end; end; {** Posts updates to database. @param Sender a cached result set object. @param UpdateType a type of updates. @param OldRowAccessor an accessor object to old column values. @param NewRowAccessor an accessor object to new column values. } procedure TZAdoCachedResolver.PostUpdates(Sender: IZCachedResultSet; UpdateType: TZRowUpdateType; OldRowAccessor, NewRowAccessor: TZRowAccessor); var Recordset: ZPlainAdo.Recordset; RA: OleVariant; begin inherited PostUpdates(Sender, UpdateType, OldRowAccessor, NewRowAccessor); if (UpdateType = utInserted) and (FAutoColumnIndex > 0) and OldRowAccessor.IsNull(FAutoColumnIndex) then begin Recordset := FHandle.Execute(RA, null, 0); if Recordset.RecordCount > 0 then NewRowAccessor.SetLong(FAutoColumnIndex, Recordset.Fields.Item[0].Value); end; end; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcAdoStatement.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { ADO Statement Classes } { } { Originally written by Janos Fegyverneki } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcAdoStatement; interface {$I ZDbc.inc} uses Types, Classes, SysUtils, ZCompatibility, ZClasses, ZSysUtils, ZCollections, ZDbcIntfs, ZPlainDriver, ZDbcStatement, ZDbcAdo, ZPlainAdoDriver, ZPlainAdo, ZVariant, ZDbcAdoUtils; type {** Implements Generic ADO Statement. } TZAdoStatement = class(TZAbstractStatement) protected AdoRecordSet: ZPlainAdo.RecordSet; FPlainDriver: IZPlainDriver; FAdoConnection: IZAdoConnection; SQL: String; function IsSelect(const SQL: string): Boolean; public constructor Create(PlainDriver: IZPlainDriver; Connection: IZConnection; SQL: string; Info: TStrings); destructor Destroy; override; procedure Close; override; function ExecuteQuery(const SQL: ZWideString): IZResultSet; override; function ExecuteUpdate(const SQL: ZWideString): Integer; override; function Execute(const SQL: ZWideString): Boolean; override; function ExecuteQuery(const SQL: RawByteString): IZResultSet; override; function ExecuteUpdate(const SQL: RawByteString): Integer; override; function Execute(const SQL: RawByteString): Boolean; override; function GetMoreResults: Boolean; override; end; {** Implements Prepared ADO Statement. } TZAdoPreparedStatement = class(TZAbstractPreparedStatement) private FPlainDriver: IZPlainDriver; AdoRecordSet: ZPlainAdo.RecordSet; FAdoCommand: ZPlainAdo.Command; FAdoConnection: IZAdoConnection; protected procedure PrepareInParameters; override; procedure BindInParameters; override; public constructor Create(PlainDriver: IZPlainDriver; Connection: IZConnection; SQL: string; Info: TStrings); destructor Destroy; override; function ExecuteQueryPrepared: IZResultSet; override; function ExecuteUpdatePrepared: Integer; override; function ExecutePrepared: Boolean; override; function GetMoreResults: Boolean; override; procedure Unprepare; override; end; {** Implements Callable ADO Statement. } TZAdoCallableStatement = class(TZAbstractCallableStatement) private FPlainDriver: IZPlainDriver; AdoRecordSet: ZPlainAdo.RecordSet; FAdoCommand: ZPlainAdo.Command; FAdoConnection: IZAdoConnection; FDirectionTypes: TDirectionTypes; protected function GetOutParam(ParameterIndex: Integer): TZVariant; override; procedure PrepareInParameters; override; procedure BindInParameters; override; public constructor Create(PlainDriver: IZPlainDriver; Connection: IZConnection; SQL: string; Info: TStrings); function ExecuteQueryPrepared: IZResultSet; override; function ExecuteUpdatePrepared: Integer; override; function ExecutePrepared: Boolean; override; procedure RegisterParamType(ParameterIndex: Integer; ParamType: Integer); override; function GetMoreResults: Boolean; override; procedure Unprepare; override; end; implementation uses {$IFNDEF FPC} Variants, {$ENDIF} OleDB, ComObj, {$IFDEF WITH_TOBJECTLIST_INLINE} System.Contnrs{$ELSE} Contnrs{$ENDIF}, {$IFNDEF UNICODE}ZEncoding,{$ENDIF} ZDbcLogging, ZDbcCachedResultSet, ZDbcResultSet, ZDbcAdoResultSet, ZDbcMetadata, ZDbcResultSetMetadata, ZDbcUtils; constructor TZAdoStatement.Create(PlainDriver: IZPlainDriver; Connection: IZConnection; SQL: string; Info: TStrings); begin inherited Create(Connection, Info); FPlainDriver := PlainDriver; FAdoConnection := Connection as IZAdoConnection; end; destructor TZAdoStatement.Destroy; begin FAdoConnection := nil; inherited; end; procedure TZAdoStatement.Close; begin inherited; AdoRecordSet := nil; end; function TZAdoStatement.IsSelect(const SQL: string): Boolean; begin Result := Uppercase(Copy(TrimLeft(Sql), 1, 6)) = 'SELECT'; end; function TZAdoStatement.ExecuteQuery(const SQL: ZWideString): IZResultSet; begin {$IFDEF UNICODE} WSQL := SQL; {$ENDIF} Result := nil; LastResultSet := nil; LastUpdateCount := -1; if not Execute(LogSql) then while (not GetMoreResults) and (LastUpdateCount > -1) do ; Result := LastResultSet end; function TZAdoStatement.ExecuteUpdate(const SQL: ZWideString): Integer; var RC: OleVariant; begin try LastResultSet := nil; LastUpdateCount := -1; {$IFDEF UNICODE} WSQL := SQL; {$ENDIF} if IsSelect(LogSQL) then begin AdoRecordSet := CoRecordSet.Create; AdoRecordSet.MaxRecords := MaxRows; AdoRecordSet.Open(SQL, FAdoConnection.GetAdoConnection, adOpenStatic, adLockOptimistic, adAsyncFetch); LastResultSet := GetCurrentResultSet(AdoRecordSet, FAdoConnection, Self, LogSQL, ConSettings, ResultSetConcurrency); LastUpdateCount := RC; AdoRecordSet.Close; AdoRecordSet := nil; end else AdoRecordSet := FAdoConnection.GetAdoConnection.Execute(WSQL, RC, adExecuteNoRecords); Result := RC; LastUpdateCount := Result; DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, LogSQL); except on E: Exception do begin DriverManager.LogError(lcExecute, FPlainDriver.GetProtocol, LogSQL, 0, E.Message); raise; end; end end; function TZAdoStatement.Execute(const SQL: ZWideString): Boolean; var RC: OleVariant; begin try {$IFDEF UNICODE} WSQL := SQL; {$ENDIF} LastResultSet := nil; LastUpdateCount := -1; Self.SQL := sql; if IsSelect(SSQL) then begin AdoRecordSet := CoRecordSet.Create; AdoRecordSet.MaxRecords := MaxRows; AdoRecordSet.Open(SQL, FAdoConnection.GetAdoConnection, adOpenStatic, adLockOptimistic, adAsyncFetch); end else AdoRecordSet := FAdoConnection.GetAdoConnection.Execute(WSQL, RC, adExecuteNoRecords); LastResultSet := GetCurrentResultSet(AdoRecordSet, FAdoConnection, Self, LogSQL, ConSettings, ResultSetConcurrency); Result := Assigned(LastResultSet); LastUpdateCount := RC; DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, LogSQL); except on E: Exception do begin DriverManager.LogError(lcExecute, FPlainDriver.GetProtocol, LogSQL, 0, E.Message); raise; end; end end; function TZAdoStatement.ExecuteQuery(const SQL: RawByteString): IZResultSet; begin if ASQL <> SQL then ASQL := SQL; Result := ExecuteQuery(WSQL); end; function TZAdoStatement.ExecuteUpdate(const SQL: RawByteString): Integer; begin if ASQL <> SQL then ASQL := SQL; Result := ExecuteUpdate(WSQL); end; function TZAdoStatement.Execute(const SQL: RawByteString): Boolean; begin if ASQL <> SQL then ASQL := SQL; Result := Execute(WSQL); end; function TZAdoStatement.GetMoreResults: Boolean; var RC: OleVariant; begin Result := False; LastResultSet := nil; LastUpdateCount := -1; if Assigned(AdoRecordSet) then begin AdoRecordSet := AdoRecordSet.NextRecordset(RC); LastResultSet := GetCurrentResultSet(AdoRecordSet, FAdoConnection, Self, SQL, ConSettings, ResultSetConcurrency); Result := Assigned(LastResultSet); LastUpdateCount := RC; end; end; constructor TZAdoPreparedStatement.Create(PlainDriver: IZPlainDriver; Connection: IZConnection; SQL: string; Info: TStrings); begin FAdoCommand := CoCommand.Create; inherited Create(Connection, SQL, Info); FAdoCommand.CommandText := WSQL; FAdoConnection := Connection as IZAdoConnection; FPlainDriver := PlainDriver; FAdoCommand._Set_ActiveConnection(FAdoConnection.GetAdoConnection); end; destructor TZAdoPreparedStatement.Destroy; begin AdoRecordSet := nil; FAdoConnection := nil; inherited; FAdoCommand := nil; end; procedure TZAdoPreparedStatement.PrepareInParameters; begin if InParamCount > 0 then RefreshParameters(FAdoCommand); FAdoCommand.Prepared := True; end; procedure TZAdoPreparedStatement.BindInParameters; var I: Integer; begin if InParamCount = 0 then Exit else for i := 0 to InParamCount-1 do if DefVarManager.IsNull(InParamValues[i]) then if (InParamDefaultValues[i] <> '') and (UpperCase(InParamDefaultValues[i]) <> 'NULL') and StrToBoolEx(DefineStatementParameter(Self, 'defaults', 'true')) then begin DefVarManager.SetAsString(InParamValues[i], InParamDefaultValues[i]); ADOSetInParam(FAdoCommand, FAdoConnection, InParamCount, I+1, InParamTypes[i], InParamValues[i], adParamInput) end else ADOSetInParam(FAdoCommand, FAdoConnection, InParamCount, I+1, InParamTypes[i], NullVariant, adParamInput) else ADOSetInParam(FAdoCommand, FAdoConnection, InParamCount, I+1, InParamTypes[i], InParamValues[i], adParamInput); end; {** Executes the SQL query in this PreparedStatement object and returns the result set generated by the query. @return a ResultSet object that contains the data produced by the query; never null } function TZAdoPreparedStatement.ExecuteQueryPrepared: IZResultSet; begin if not ExecutePrepared then while (not GetMoreResults) and (LastUpdateCount > -1) do ; Result := LastResultSet; end; {** Executes the SQL INSERT, UPDATE or DELETE statement in this PreparedStatement object. In addition, SQL statements that return nothing, such as SQL DDL statements, can be executed. @return either the row count for INSERT, UPDATE or DELETE statements; or 0 for SQL statements that return nothing } function TZAdoPreparedStatement.ExecuteUpdatePrepared: Integer; begin ExecutePrepared; Result := LastUpdateCount; end; {** Executes any kind of SQL statement. Some prepared statements return multiple results; the execute method handles these complex statements as well as the simpler form of statements handled by the methods executeQuery and executeUpdate. @see Statement#execute } function TZAdoPreparedStatement.ExecutePrepared: Boolean; var RC: OleVariant; begin LastResultSet := nil; LastUpdateCount := -1; Prepare; BindInParameters; try if IsSelect(SQL) then begin AdoRecordSet := CoRecordSet.Create; AdoRecordSet.MaxRecords := MaxRows; AdoRecordSet._Set_ActiveConnection(FAdoCommand.Get_ActiveConnection); AdoRecordSet.Open(FAdoCommand, EmptyParam, adOpenForwardOnly, adLockOptimistic, adAsyncFetch); end else AdoRecordSet := FAdoCommand.Execute(RC, EmptyParam, -1{, adExecuteNoRecords}); LastResultSet := GetCurrentResultSet(AdoRecordSet, FAdoConnection, Self, SQL, ConSettings, ResultSetConcurrency); LastUpdateCount := RC; Result := Assigned(LastResultSet); DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, SQL); except on E: Exception do begin DriverManager.LogError(lcExecute, FPlainDriver.GetProtocol, SQL, 0, E.Message); raise; end; end end; function TZAdoPreparedStatement.GetMoreResults: Boolean; var RC: OleVariant; begin Result := False; LastResultSet := nil; LastUpdateCount := -1; if Assigned(AdoRecordSet) then begin AdoRecordSet := AdoRecordSet.NextRecordset(RC); LastResultSet := GetCurrentResultSet(AdoRecordSet, FAdoConnection, Self, SQL, ConSettings, ResultSetConcurrency); Result := Assigned(LastResultSet); LastUpdateCount := RC; end; end; procedure TZAdoPreparedStatement.Unprepare; begin if FAdoCommand.Prepared then FAdoCommand.Prepared := False; inherited; end; { TZAdoCallableStatement } constructor TZAdoCallableStatement.Create(PlainDriver: IZPlainDriver; Connection: IZConnection; SQL: string; Info: TStrings); begin inherited Create(Connection, SQL, Info); FAdoCommand := CoCommand.Create; FAdoCommand.CommandText := WSQL; FAdoConnection := Connection as IZAdoConnection; FPlainDriver := PlainDriver; FAdoCommand._Set_ActiveConnection(FAdoConnection.GetAdoConnection); FAdoCommand.CommandType := adCmdStoredProc; end; function TZAdoCallableStatement.ExecuteQueryPrepared: IZResultSet; var I: Integer; ColumnInfo: TZColumnInfo; ColumnsInfo: TObjectList; RS: TZVirtualResultSet; IndexAlign: TIntegerDynArray; P: Pointer; Stream: TStream; begin ExecutePrepared; SetLength(IndexAlign, 0); ColumnsInfo := TObjectList.Create(True); Stream := nil; try for I := 0 to FAdoCommand.Parameters.Count -1 do if FAdoCommand.Parameters.Item[i].Direction in [adParamOutput, adParamInputOutput, adParamReturnValue] then begin SetLength(IndexAlign, Length(IndexAlign)+1); ColumnInfo := TZColumnInfo.Create; with ColumnInfo do begin ColumnLabel := FAdoCommand.Parameters.Item[i].Name; ColumnType := ConvertAdoToSqlType(FAdoCommand.Parameters.Item[I].Type_, ConSettings.CPType); ColumnDisplaySize := FAdoCommand.Parameters.Item[I].Precision; Precision := FAdoCommand.Parameters.Item[I].Precision; IndexAlign[High(IndexAlign)] := I; end; ColumnsInfo.Add(ColumnInfo); end; RS := TZVirtualResultSet.CreateWithColumns(ColumnsInfo, '', ConSettings); with RS do begin SetType(rtScrollInsensitive); SetConcurrency(rcReadOnly); RS.MoveToInsertRow; for i := 1 to ColumnsInfo.Count do case TZColumnInfo(ColumnsInfo[i-1]).ColumnType of stBoolean: RS.UpdateBoolean(i, FAdoCommand.Parameters.Item[IndexAlign[i-1]].Value); stByte, stShort, stInteger, stLong: RS.UpdateInt(i, FAdoCommand.Parameters.Item[IndexAlign[i-1]].Value); stFloat, stDouble, stBigDecimal: RS.UpdateFloat(i, FAdoCommand.Parameters.Item[IndexAlign[i-1]].Value); stString: RS.UpdateString(i, FAdoCommand.Parameters.Item[IndexAlign[i-1]].Value); stAsciiStream: begin Stream := TStringStream.Create(AnsiString(FAdoCommand.Parameters.Item[IndexAlign[i-1]].Value)); RS.UpdateAsciiStream(I, Stream); Stream.Free; end; stUnicodeString: RS.UpdateUnicodeString(i, FAdoCommand.Parameters.Item[IndexAlign[i-1]].Value); stUnicodeStream: begin Stream := WideStringStream(WideString(FAdoCommand.Parameters.Item[IndexAlign[i-1]].Value)); RS.UpdateUnicodeStream(I, Stream); FreeAndNil(Stream); end; stBytes: RS.UpdateBytes(i, FAdoCommand.Parameters.Item[IndexAlign[i-1]].Value); stDate: RS.UpdateDate(i, FAdoCommand.Parameters.Item[IndexAlign[i-1]].Value); stTime: RS.UpdateTime(i, FAdoCommand.Parameters.Item[IndexAlign[i-1]].Value); stTimestamp: RS.UpdateTimestamp(i, FAdoCommand.Parameters.Item[IndexAlign[i-1]].Value); stBinaryStream: begin if VarIsStr(FAdoCommand.Parameters.Item[IndexAlign[i-1]].Value) then begin Stream := TStringStream.Create(AnsiString(FAdoCommand.Parameters.Item[IndexAlign[i-1]].Value)); RS.UpdateBinaryStream(I, Stream); FreeAndNil(Stream); end else if VarIsArray(FAdoCommand.Parameters.Item[IndexAlign[i-1]].Value) then begin P := VarArrayLock(FAdoCommand.Parameters.Item[IndexAlign[i-1]].Value); try Stream := TMemoryStream.Create; Stream.Size := VarArrayHighBound(FAdoCommand.Parameters.Item[IndexAlign[i-1]].Value, 1)+1; System.Move(P^, TMemoryStream(Stream).Memory^, Stream.Size); RS.UpdateBinaryStream(I, Stream); FreeAndNil(Stream); finally VarArrayUnLock(FAdoCommand.Parameters.Item[IndexAlign[i-1]].Value); end; end; end else RS.UpdateNull(i); end; RS.InsertRow; end; Result := RS; finally ColumnsInfo.Free; if Assigned(Stream) then Stream.Free; end; end; {** Executes the SQL INSERT, UPDATE or DELETE statement in this PreparedStatement object. In addition, SQL statements that return nothing, such as SQL DDL statements, can be executed. @return either the row count for INSERT, UPDATE or DELETE statements; or 0 for SQL statements that return nothing } function TZAdoCallableStatement.ExecuteUpdatePrepared: Integer; begin ExecutePrepared; Result := LastUpdateCount; end; {** Executes any kind of SQL statement. Some prepared statements return multiple results; the execute method handles these complex statements as well as the simpler form of statements handled by the methods executeQuery and executeUpdate. @see Statement#execute } function TZAdoCallableStatement.ExecutePrepared: Boolean; var RC: OleVariant; begin LastResultSet := nil; LastUpdateCount := -1; if Not Prepared then Prepare; BindInParameters; try if IsSelect(SQL) then begin AdoRecordSet := CoRecordSet.Create; AdoRecordSet.MaxRecords := MaxRows; AdoRecordSet._Set_ActiveConnection(FAdoCommand.Get_ActiveConnection); AdoRecordSet.Open(FAdoCommand, EmptyParam, adOpenForwardOnly, adLockOptimistic, adAsyncFetch); end else AdoRecordSet := FAdoCommand.Execute(RC, EmptyParam, -1{, adExecuteNoRecords}); LastResultSet := GetCurrentResultSet(AdoRecordSet, FAdoConnection, Self, SQL, ConSettings, ResultSetConcurrency); LastUpdateCount := RC; Result := Assigned(LastResultSet); DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, SQL); except on E: Exception do begin DriverManager.LogError(lcExecute, FPlainDriver.GetProtocol, SQL, 0, E.Message); raise; end; end end; procedure TZAdoCallableStatement.RegisterParamType(ParameterIndex: Integer; ParamType: Integer); begin inherited RegisterParamType(ParameterIndex, ParamType); if Length(FDirectionTypes) < ParameterIndex then SetLength(FDirectionTypes, ParameterIndex); case Self.FDBParamTypes[ParameterIndex-1] of 1: //ptInput FDirectionTypes[ParameterIndex-1] := adParamInput; 2: //ptOut FDirectionTypes[ParameterIndex-1] := adParamOutput; 3: //ptInputOutput FDirectionTypes[ParameterIndex-1] := adParamInputOutput; 4: //ptResult FDirectionTypes[ParameterIndex-1] := adParamReturnValue; else //ptUnknown FDirectionTypes[ParameterIndex-1] := adParamUnknown; end; end; function TZAdoCallableStatement.GetMoreResults: Boolean; var RC: OleVariant; begin Result := False; LastResultSet := nil; LastUpdateCount := -1; if Assigned(AdoRecordSet) then begin AdoRecordSet := AdoRecordSet.NextRecordset(RC); LastResultSet := GetCurrentResultSet(AdoRecordSet, FAdoConnection, Self, SQL, ConSettings, ResultSetConcurrency); Result := Assigned(LastResultSet); LastUpdateCount := RC; end; end; procedure TZAdoCallableStatement.Unprepare; begin if FAdoCommand.Prepared then FAdoCommand.Prepared := False; inherited; end; function TZAdoCallableStatement.GetOutParam(ParameterIndex: Integer): TZVariant; var Temp: Variant; V: Variant; P: Pointer; TempBlob: IZBLob; begin if ParameterIndex > OutParamCount then Result := NullVariant else begin Temp := FAdoCommand.Parameters.Item[ParameterIndex - 1].Value; case ConvertAdoToSqlType(FAdoCommand.Parameters.Item[ParameterIndex - 1].Type_, ConSettings.CPType) of stBoolean: DefVarManager.SetAsBoolean(Result, Temp); stByte, stShort, stInteger, stLong: DefVarManager.SetAsInteger(Result, Temp); stFloat, stDouble, stBigDecimal: DefVarManager.SetAsFloat(Result, Temp); stString, stAsciiStream: DefVarManager.SetAsString(Result, Temp); stUnicodeString, stUnicodeStream: DefVarManager.SetAsUnicodeString(Result, Temp); stBytes: DefVarManager.SetAsBytes(Result, VarToBytes(Temp)); stDate, stTime, stTimestamp: DefVarManager.SetAsDateTime(Result, Temp); stBinaryStream: begin if VarIsStr(V) then begin TempBlob := TZAbstractBlob.CreateWithStream(nil, GetConnection); TempBlob.SetString(AnsiString(V)); end else if VarIsArray(V) then begin P := VarArrayLock(V); try TempBlob := TZAbstractBlob.CreateWithData(P, VarArrayHighBound(V, 1)+1, GetConnection); finally VarArrayUnLock(V); end; end; DefVarManager.SetAsInterface(Result, TempBlob); TempBlob := nil; end else DefVarManager.SetNull(Result); end; end; LastWasNull := DefVarManager.IsNull(Result) or VarIsNull(Temp) or VarIsClear(Temp); end; procedure TZAdoCallableStatement.PrepareInParameters; begin if InParamCount > 0 then RefreshParameters(FAdoCommand, @FDirectionTypes); FAdoCommand.Prepared := True; end; procedure TZAdoCallableStatement.BindInParameters; var I: Integer; begin if InParamCount = 0 then Exit else for i := 0 to InParamCount-1 do if FDBParamTypes[i] in [1,3] then //ptInput, ptInputOutput if DefVarManager.IsNull(InParamValues[i]) then if (InParamDefaultValues[i] <> '') and (UpperCase(InParamDefaultValues[i]) <> 'NULL') and StrToBoolEx(DefineStatementParameter(Self, 'defaults', 'true')) then begin DefVarManager.SetAsString(InParamValues[i], InParamDefaultValues[i]); ADOSetInParam(FAdoCommand, FAdoConnection, InParamCount, I+1, InParamTypes[i], InParamValues[i], adParamInput) end else ADOSetInParam(FAdoCommand, FAdoConnection, InParamCount, I+1, InParamTypes[i], NullVariant, FDirectionTypes[i]) else ADOSetInParam(FAdoCommand, FAdoConnection, InParamCount, I+1, InParamTypes[i], InParamValues[i], FDirectionTypes[i]) else ADOSetInParam(FAdoCommand, FAdoConnection, InParamCount, I+1, InParamTypes[i], NullVariant, FDirectionTypes[i]); end; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcAdoUtils.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { ADO Specific Utilities } { } { Originally written by Janos Fegyverneki } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcAdoUtils; interface {$I ZDbc.inc} uses Windows, Classes, SysUtils, ActiveX, ZDbcIntfs, ZCompatibility, ZPlainAdo, ZDbcAdo, ZVariant, ZDbcStatement; type PDirectionTypes = ^TDirectionTypes; TDirectionTypes = array of TOleEnum; {** Converts an ADO native types into string related. @param FieldType dblibc native field type. @return a string data type name. } function ConvertAdoToTypeName(FieldType: SmallInt): string; {** Converts a Ado native types into ZDBC SQL types. @param FieldType dblibc native field type. @return a SQL undepended type. } function ConvertAdoToSqlType(const FieldType: SmallInt; const CtrlsCPType: TZControlsCodePage; UseCtrsCPType: Boolean = True): TZSQLType; {** Converts a Zeos type into ADO types. @param FieldType zeos field type. @return a ADO datatype. } function ConvertSqlTypeToAdo(FieldType: TZSQLType): Integer; {** Converts a Variant type into ADO types. @param VT Variant datatype. @return a ADO datatype. } {$IFDEF FPC} function ConvertVariantToAdo(VT: Integer): Integer; {$ELSE} function ConvertVariantToAdo(VT: TVarType): Integer; {$ENDIF} {** Converts a TZResultSetType type into ADO cursor type. @param ResultSetType. @return a ADO cursor type. } function ConvertResultSetTypeToAdo(ResultSetType: TZResultSetType): Integer; {** Converts a TZResultSetConcurrency type into ADO lock type. @param ResultSetConcurrency. @return a ADO lock type. } function ConvertResultSetConcurrencyToAdo(ResultSetConcurrency: TZResultSetConcurrency): Integer; {** Converts a OLEDB schema guid into ADO schema ID usable with OpenSchema. @param OleDBSchema schema guid. @return a ADO schema id. } function ConvertOleDBToAdoSchema(OleDBSchema: TGUID): Integer; {** Brings up the ADO connection string builder dialog. } function PromptDataSource(Handle: THandle; InitialString: WideString): WideString; function GetCurrentResultSet(AdoRecordSet: ZPlainAdo.RecordSet; Connection: IZAdoConnection; Statement: IZStatement; Const SQL: String; ConSettings: PZConSettings; const ResultSetConcurrency: TZResultSetConcurrency): IZResultSet; function IsSelect(const SQL: string): Boolean; {** Sets a variant value into specified parameter. @param AdoCommand the ole command @param Connection the Connection interface @param ParameterIndex a index of the parameter. @param SqlType a parameter SQL type. @paran Value a new parameter value. } procedure ADOSetInParam(AdoCommand: ZPlainAdo.Command; Connection: IZConnection; ParamCount: Integer; const ParameterIndex: Integer; const SQLType: TZSQLType; const Value: TZVariant; const ParamDirection: ParameterDirectionEnum); procedure RefreshParameters(AdoCommand: ZPlainAdo.Command; DirectionTypes: PDirectionTypes = nil); var {** Required to free memory allocated by oledb } ZAdoMalloc: IMalloc; implementation uses ComObj, OleDB, Variants, ZSysUtils, ZDbcAdoResultSet, ZDbcCachedResultSet, ZDbcResultSet, ZEncoding; {** Converts an ADO native types into string related. @param FieldType dblibc native field type. @return a string data type name. } function ConvertAdoToTypeName(FieldType: SmallInt): string; begin case FieldType of adChar : Result := 'Char'; adVarChar : Result := 'VarChar'; adBSTR : Result := 'BSTR'; adWChar : Result := 'WChar'; adVarWChar : Result := 'VarWChar'; adBoolean : Result := 'Boolean'; adTinyInt : Result := 'TinyInt'; adUnsignedTinyInt : Result := 'UnsignedTinyInt'; adSmallInt : Result := 'SmallInt'; adUnsignedSmallInt : Result := 'UnsignedSmallInt'; adInteger : Result := 'Integer'; adUnsignedInt : Result := 'UnsignedInt'; adBigInt : Result := 'BigInt'; adUnsignedBigInt : Result := 'UnsignedBigInt'; adSingle : Result := 'Single'; adDouble : Result := 'Double'; adDecimal : Result := 'Decimal'; adNumeric : Result := 'Numeric'; adVarNumeric : Result := 'VarNumeric'; adCurrency : Result := 'Currency'; adDBDate : Result := 'DBDate'; adDBTime : Result := 'DBTime'; adDate : Result := 'Date'; adDBTimeStamp : Result := 'DBTimeStamp'; adFileTime : Result := 'FileTime'; adLongVarChar : Result := 'LongVarChar'; adLongVarWChar : Result := 'LongVarWChar'; adBinary : Result := 'Binary'; adVarBinary : Result := 'VarBinary'; adLongVarBinary : Result := 'LongVarBinary'; adGUID : Result := 'GUID'; adEmpty : Result := 'Empty'; adError : Result := 'Error'; adArray : Result := 'Array'; adChapter : Result := 'Chapter'; adIDispatch : Result := 'IDispatch'; adIUnknown : Result := 'IUnknown'; adPropVariant : Result := 'PropVariant'; adUserDefined : Result := 'UserDefined'; adVariant : Result := 'Variant'; else Result := 'Unknown'; end; end; {** Converts a Ado native types into ZDBC SQL types. @param FieldType dblibc native field type. @return a SQL undepended type. } function ConvertAdoToSqlType(const FieldType: SmallInt; const CtrlsCPType: TZControlsCodePage; UseCtrsCPType: Boolean = True): TZSQLType; begin case FieldType of adChar, adVarChar, adBSTR: Result := stString; adWChar, adVarWChar: Result := stUnicodeString; adBoolean: Result := stBoolean; //Bug #889223, bug with tinyint on mssql // adTinyInt, adUnsignedTinyInt: Result := stByte; adTinyInt, adUnsignedTinyInt: Result := stShort; adSmallInt, adUnsignedSmallInt: Result := stShort; adInteger, adUnsignedInt: Result := stInteger; adBigInt, adUnsignedBigInt: Result := stLong; adSingle: Result := stFloat; adDouble: Result := stDouble; adDecimal: Result := stBigDecimal; adNumeric, adVarNumeric: Result := stBigDecimal; adCurrency: Result := stBigDecimal; adDBDate: Result := stDate; adDBTime: Result := stTime; adDate : Result := stDate; adDBTimeStamp, adFileTime: Result := stTimestamp; adLongVarChar: Result := stAsciiStream; adLongVarWChar: Result := stUnicodeStream; adBinary, adVarBinary: Result := stBytes; adLongVarBinary: Result := stBinaryStream; adGUID: Result := stGUID; adEmpty, adError, AdArray, adChapter, adIDispatch, adIUnknown, adPropVariant, adUserDefined, adVariant: Result := stString; else Result := stString; end; if UseCtrsCPType then case CtrlsCPType of cCP_UTF16: case Result of stString: Result := stUnicodeString; stAsciiStream: Result := stUnicodeStream; end; else case Result of stUnicodeString: Result := stString; stUnicodeStream: Result := stAsciiStream; end; end; end; {** Converts a Zeos type into ADO types. @param FieldType zeos field type. @return a ADO datatype. } function ConvertSqlTypeToAdo(FieldType: TZSQLType): Integer; begin case FieldType of stString: Result := adVarChar; stUnicodeString: Result := adVarWChar; stBoolean: Result := adBoolean; stByte: Result := adTinyInt; stShort: Result := adSmallInt; stInteger: Result := adInteger; stLong: Result := adBigInt; stBigDecimal: Result := adDecimal; stFloat: Result := adSingle; stDouble: Result := adDouble; stDate: Result := adDBDate; stTime: Result := adDBTime; stTimestamp: Result := adDBTimeStamp; stBytes: Result := adVarBinary; stGUID: Result := adGUID; stAsciiStream: Result := adLongVarChar; stUnicodeStream: Result := adLongVarWChar; stBinaryStream: Result := adLongVarBinary; else Result := adEmpty; end; end; {** Converts a Variant type into ADO types. @param VT Variant datatype. @return a ADO datatype. } {$IFDEF FPC} function ConvertVariantToAdo(VT: Integer): Integer; {$ELSE} function ConvertVariantToAdo(VT: TVarType): Integer; {$ENDIF} begin case VT and varTypeMask of varEmpty: Result := adEmpty; varNull: Result := adVarChar; varSmallint: Result := adSmallInt; varInteger: Result := adInteger; varSingle: Result := adSingle; varDouble: Result := adDouble; varCurrency: Result := adCurrency; varDate: Result := adDate; varOleStr: Result := adVarWChar; varDispatch: Result := adIDispatch; varError: Result := adError; varBoolean: Result := adBoolean; varVariant: Result := adVariant; varUnknown: Result := adIUnknown; {$IFNDEF FPC} varShortInt: Result := adTinyInt; {$ENDIF} varByte: if (VT and varArray) <> 0 then Result := adLongVarBinary else Result := adUnsignedTinyInt; {$IFNDEF FPC} varWord: Result := adUnsignedSmallInt; varLongWord: Result := adUnsignedInt; varInt64: Result := adBigInt; {$ENDIF} varStrArg: Result := adWChar; varString: Result := adVarChar; {$IFDEF UNICODE} varUString: Result := adVarChar; {$ENDIF} varAny: Result := adEmpty; else Result := adEmpty; end; end; {** Converts a TZResultSetType type into ADO cursor type. @param ResultSetType. @return a ADO cursor type. } function ConvertResultSetTypeToAdo(ResultSetType: TZResultSetType): Integer; begin case ResultSetType of rtForwardOnly: Result := adOpenForwardOnly; rtScrollInsensitive: Result := adOpenStatic; rtScrollSensitive: Result := adOpenDynamic; else Result := -1;//adOpenUnspecified; end end; {** Converts a TZResultSetConcurrency type into ADO lock type. @param ResultSetConcurrency. @return a ADO lock type. } function ConvertResultSetConcurrencyToAdo(ResultSetConcurrency: TZResultSetConcurrency): Integer; begin case ResultSetConcurrency of rcReadOnly: Result := adLockReadOnly; rcUpdatable: Result := adLockOptimistic; else Result := -1;//adLockUnspecified; end end; {** Converts a OLEDB schema guid into ADO schema ID usable with OpenSchema. @param OleDBSchema schema guid. @return a ADO schema id. } function ConvertOleDBToAdoSchema(OleDBSchema: TGUID): Integer; begin Result := -1; if IsEqualGuid(OleDBSchema, DBSCHEMA_ASSERTIONS) then Result := 0; if IsEqualGuid(OleDBSchema, DBSCHEMA_CATALOGS) then Result := 1; if IsEqualGuid(OleDBSchema, DBSCHEMA_CHARACTER_SETS) then Result := 2; if IsEqualGuid(OleDBSchema, DBSCHEMA_COLLATIONS) then Result := 3; if IsEqualGuid(OleDBSchema, DBSCHEMA_COLUMNS) then Result := 4; if IsEqualGuid(OleDBSchema, DBSCHEMA_CHECK_CONSTRAINTS) then Result := 5; if IsEqualGuid(OleDBSchema, DBSCHEMA_CONSTRAINT_COLUMN_USAGE) then Result := 6; if IsEqualGuid(OleDBSchema, DBSCHEMA_CONSTRAINT_TABLE_USAGE) then Result := 7; if IsEqualGuid(OleDBSchema, DBSCHEMA_KEY_COLUMN_USAGE) then Result := 8; if IsEqualGuid(OleDBSchema, DBSCHEMA_REFERENTIAL_CONSTRAINTS) then Result := 9; if IsEqualGuid(OleDBSchema, DBSCHEMA_TABLE_CONSTRAINTS) then Result := 10; if IsEqualGuid(OleDBSchema, DBSCHEMA_COLUMN_DOMAIN_USAGE) then Result := 11; if IsEqualGuid(OleDBSchema, DBSCHEMA_INDEXES) then Result := 12; if IsEqualGuid(OleDBSchema, DBSCHEMA_COLUMN_PRIVILEGES) then Result := 13; if IsEqualGuid(OleDBSchema, DBSCHEMA_TABLE_PRIVILEGES) then Result := 14; if IsEqualGuid(OleDBSchema, DBSCHEMA_USAGE_PRIVILEGES) then Result := 15; if IsEqualGuid(OleDBSchema, DBSCHEMA_PROCEDURES) then Result := 16; if IsEqualGuid(OleDBSchema, DBSCHEMA_SCHEMATA) then Result := 17; if IsEqualGuid(OleDBSchema, DBSCHEMA_SQL_LANGUAGES) then Result := 18; if IsEqualGuid(OleDBSchema, DBSCHEMA_STATISTICS) then Result := 19; if IsEqualGuid(OleDBSchema, DBSCHEMA_TABLES) then Result := 20; if IsEqualGuid(OleDBSchema, DBSCHEMA_TRANSLATIONS) then Result := 21; if IsEqualGuid(OleDBSchema, DBSCHEMA_PROVIDER_TYPES) then Result := 22; if IsEqualGuid(OleDBSchema, DBSCHEMA_VIEWS) then Result := 23; if IsEqualGuid(OleDBSchema, DBSCHEMA_VIEW_COLUMN_USAGE) then Result := 24; if IsEqualGuid(OleDBSchema, DBSCHEMA_VIEW_TABLE_USAGE) then Result := 25; if IsEqualGuid(OleDBSchema, DBSCHEMA_PROCEDURE_PARAMETERS) then Result := 26; if IsEqualGuid(OleDBSchema, DBSCHEMA_FOREIGN_KEYS) then Result := 27; if IsEqualGuid(OleDBSchema, DBSCHEMA_PRIMARY_KEYS) then Result := 28; if IsEqualGuid(OleDBSchema, DBSCHEMA_PROCEDURE_COLUMNS) then Result := 29; if IsEqualGuid(OleDBSchema, MDSCHEMA_CUBES) then Result := 32; if IsEqualGuid(OleDBSchema, MDSCHEMA_DIMENSIONS) then Result := 33; if IsEqualGuid(OleDBSchema, MDSCHEMA_HIERARCHIES) then Result := 34; if IsEqualGuid(OleDBSchema, MDSCHEMA_LEVELS) then Result := 35; if IsEqualGuid(OleDBSchema, MDSCHEMA_MEASURES) then Result := 36; if IsEqualGuid(OleDBSchema, MDSCHEMA_PROPERTIES) then Result := 37; if IsEqualGuid(OleDBSchema, MDSCHEMA_MEMBERS) then Result := 38; if IsEqualGuid(OleDBSchema, DBPROPSET_TRUSTEE) then Result := 39; end; {** Brings up the ADO connection string builder dialog. } function PromptDataSource(Handle: THandle; InitialString: WideString): WideString; var DataInit: IDataInitialize; DBPrompt: IDBPromptInitialize; DataSource: IUnknown; InitStr: PWideChar; begin Result := InitialString; DataInit := CreateComObject(CLSID_DataLinks) as IDataInitialize; if InitialString <> '' then DataInit.GetDataSource(nil, CLSCTX_INPROC_SERVER, PWideChar(InitialString), IUnknown, DataSource); DBPrompt := CreateComObject(CLSID_DataLinks) as IDBPromptInitialize; if Succeeded(DBPrompt.PromptDataSource(nil, Handle, DBPROMPTOPTIONS_PROPERTYSHEET, 0, nil, nil, IUnknown, DataSource)) then begin InitStr := nil; DataInit.GetInitializationString(DataSource, True, InitStr); Result := InitStr; end; end; function GetCurrentResultSet(AdoRecordSet: ZPlainAdo.RecordSet; Connection: IZAdoConnection; Statement: IZStatement; Const SQL: String; ConSettings: PZConSettings; const ResultSetConcurrency: TZResultSetConcurrency): IZResultSet; var NativeResultSet: IZResultSet; begin Result := nil; if Assigned(AdoRecordset) then if (AdoRecordSet.State and adStateOpen) = adStateOpen then begin NativeResultSet := TZAdoResultSet.Create(Statement, SQL, AdoRecordSet); if ResultSetConcurrency = rcUpdatable then Result := TZCachedResultSet.Create(NativeResultSet, SQL, TZAdoCachedResolver.Create(Connection.GetAdoConnection, Statement, NativeResultSet.GetMetaData), ConSettings) else Result := NativeResultSet; end; end; function IsSelect(const SQL: string): Boolean; begin Result := Uppercase(Copy(TrimLeft(Sql), 1, 6)) = 'SELECT'; end; {** Sets a variant value into specified parameter. @param AdoCommand the ole command @param Connection the Connection interface @param ParameterIndex a index of the parameter. @param SqlType a parameter SQL type. @paran Value a new parameter value. } procedure ADOSetInParam(AdoCommand: ZPlainAdo.Command; Connection: IZConnection; ParamCount: Integer; const ParameterIndex: Integer; const SQLType: TZSQLType; const Value: TZVariant; const ParamDirection: ParameterDirectionEnum); var S: Integer; B: IZBlob; V: Variant; T: Integer; P: ZPlainAdo.Parameter; RetValue: TZVariant; TmpSQLType: TZSQLType; begin RetValue:= Value; TmpSQLType := SQLType; if not (RetValue.VType = vtNull) and (RetValue.VType = vtInterface) and (SQLType in [stAsciiStream, stUnicodeStream, stBinaryStream]) then begin B := DefVarManager.GetAsInterface(Value) as IZBlob; if B.IsEmpty then RetValue := NullVariant else case SQLType of stAsciiStream: begin {$IFDEF UNICODE} DefVarManager.SetAsString(RetValue, String(B.GetString)); {$ELSE} DefVarManager.SetAsString(RetValue, GetValidatedAnsiStringFromBuffer(B.GetBuffer, B.Length, Connection.GetConSettings)); {$ENDIF} TmpSQLType := stString; end; stUnicodeStream: begin if B.Connection = nil then B := TZAbstractBlob.CreateWithData(B.GetBuffer, B.Length, Connection, B.WasDecoded); DefVarManager.SetAsUnicodeString(RetValue, B.GetUnicodeString); TmpSQLType := stUnicodeString; end; stBinaryStream: begin if Assigned(B) then DefVarManager.SetAsBytes(RetValue, B.GetBytes); TmpSQLType := stBytes; end; end; end; case RetValue.VType of vtNull: V := Null; vtBoolean: V := SoftVarManager.GetAsBoolean(RetValue); vtBytes: V := SoftVarManager.GetAsBytes(RetValue); vtInteger: V := Integer(SoftVarManager.GetAsInteger(RetValue)); vtFloat: V := SoftVarManager.GetAsFloat(RetValue); vtString: {$IFDEF UNICODE} V := SoftVarManager.GetAsString(RetValue); {$ELSE} if ParamDirection = adParamInputOutput then //can't say why but bidirectional params need to be converted first. //On the other hand they where not refreshed after second call! Is there a problem with Variant vs. OleVariant and strings? begin V := WideString(SoftVarManager.GetAsString(RetValue)); TmpSQLType := stUnicodeString; end else if SQLType = stAsciiStream then V := SoftVarManager.GetAsString(RetValue) else V := Connection.GetIZPlainDriver.ZPlainString(SoftVarManager.GetAsString(RetValue), Connection.GetConSettings); {$ENDIF} vtUnicodeString: V := WideString(SoftVarManager.GetAsUnicodeString(RetValue)); vtDateTime: V := TDateTime(SoftVarManager.GetAsDateTime(RetValue)); end; S := 0; //init val case TmpSQLType of stString: begin S := Length(VarToStr(V)); if S = 0 then S := 1; //V := Null; patch by zx - see http://zeos.firmos.at/viewtopic.php?t=1255 end; stUnicodeString: begin S := Length(VarToWideStr(V))*2; //strange! Need size in bytes!! if S = 0 then S := 1; //V := Null; patch by zx - see http://zeos.firmos.at/viewtopic.php?t=1255 end; stBytes: begin //V := StrToBytes(VarToStr(V)); if (VarType(V) and varArray) <> 0 then S := VarArrayHighBound(V, 1) + 1; if S = 0 then V := Null; end; end; if VarIsNull(V) or (SQLType = stBytes) then T := ConvertSqlTypeToAdo(TmpSQLType) else T := ConvertVariantToAdo(VarType(V)); if ParameterIndex <= ParamCount then begin P := AdoCommand.Parameters.Item[ParameterIndex - 1]; P.Direction := ParamDirection; //set ParamDirection! Bidirection is requires for callables f.e. if not VarIsNull(V) then //align new size and type begin P.Type_ := T; P.Size := S; end; if VarIsClear(P.Value) or (P.Value <> V) or (TmpSQLType = stBytes) then //Check if Param is cleared, unasigned or different P.Value := V; end else AdoCommand.Parameters.Append(AdoCommand.CreateParameter( 'P' + IntToStr(ParameterIndex), T, ParamDirection, S, V)); end; procedure RefreshParameters(AdoCommand: ZPlainAdo.Command; DirectionTypes: PDirectionTypes = nil); procedure RefreshFromOleDB; var I: Integer; ParamCount: NativeUInt; ParamInfo: PDBParamInfoArray; NamesBuffer: POleStr; Name: WideString; Parameter: _Parameter; Direction: ParameterDirectionEnum; OLEDBCommand: ICommand; OLEDBParameters: ICommandWithParameters; CommandPrepare: ICommandPrepare; begin OLEDBCommand := (AdoCommand as ADOCommandConstruction).OLEDBCommand as ICommand; OLEDBCommand.QueryInterface(ICommandWithParameters, OLEDBParameters); OLEDBParameters.SetParameterInfo(0, nil, nil); if Assigned(OLEDBParameters) then begin ParamInfo := nil; NamesBuffer := nil; try OLEDBCommand.QueryInterface(ICommandPrepare, CommandPrepare); if Assigned(CommandPrepare) then CommandPrepare.Prepare(0); if OLEDBParameters.GetParameterInfo(ParamCount, PDBPARAMINFO(ParamInfo), @NamesBuffer) = S_OK then for I := 0 to ParamCount - 1 do with ParamInfo[I] do begin { When no default name, fabricate one like ADO does } if pwszName = nil then Name := 'Param' + IntToStr(I+1) else { Do not localize } Name := pwszName; { ADO maps DBTYPE_BYTES to adVarBinary } if wType = DBTYPE_BYTES then wType := adVarBinary; { ADO maps DBTYPE_STR to adVarChar } if wType = DBTYPE_STR then wType := adVarChar; { ADO maps DBTYPE_WSTR to adVarWChar } if wType = DBTYPE_WSTR then wType := adVarWChar; Direction := dwFlags and $F; { Verify that the Direction is initialized } if Assigned(DirectionTypes) then Parameter := AdoCommand.CreateParameter(Name, wType, DirectionTypes^[i], ulParamSize, EmptyParam) else begin if Direction = adParamUnknown then Direction := adParamInput; Parameter := AdoCommand.CreateParameter(Name, wType, Direction, ulParamSize, EmptyParam); end; Parameter.Precision := bPrecision; Parameter.NumericScale := ParamInfo[I].bScale; Parameter.Attributes := dwFlags and $FFFFFFF0; { Mask out Input/Output flags } end; finally if Assigned(CommandPrepare) then CommandPrepare.Unprepare; if (ParamInfo <> nil) then ZAdoMalloc.Free(ParamInfo); if (NamesBuffer <> nil) then ZAdoMalloc.Free(NamesBuffer); end; end; end; procedure RefreshFromADO; var I: Integer; Parameter: _Parameter; begin with AdoCommand do try Parameters.Refresh; for I := 0 to Parameters.Count - 1 do with Parameters[I] do begin { We can't use the instance of the parameter in the ADO collection because it will be freed when the connection is closed even though we have a reference to it. So instead we create our own and copy the settings } if Assigned(DirectionTypes) then Parameter := CreateParameter(Name, Type_, DirectionTypes^[i], Size, EmptyParam) else Parameter := CreateParameter(Name, Type_, Direction, Size, EmptyParam); Parameter.Precision := Precision; Parameter.NumericScale := NumericScale; Parameter.Attributes := Attributes; end; except { do nothing } end; end; begin if ( AdoCommand.CommandType = adCmdText ) then RefreshFromOLEDB else RefreshFromADO; end; initialization OleCheck(CoGetMalloc(1, ZAdoMalloc)); finalization ZAdoMalloc := nil; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcCache.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Caching Classes and Interfaces } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcCache; interface {$I ZDbc.inc} uses {$IFDEF MSWINDOWS} Windows, {$ENDIF} Types, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, Contnrs, ZClasses, ZDbcIntfs, ZDbcResultSet, ZDbcResultSetMetadata, ZVariant, ZCompatibility; type {** Defines a row status type. } TZRowUpdateType = (utUnmodified, utModified, utInserted, utDeleted); TZRowUpdateTypes = set of TZRowUpdateType; TZByteArray = array[0..4096 * SizeOf(Pointer)] of Byte; {** Defines a header for row buffer. } {ludob. Notes on alignment: Columns contains a record per field with the structure null:byte; fielddata:anything; field records are addressed through offsets in Columns stored in FColumnOffsets. Since anything can be stored as fielddata including pointers, fielddata needs to be aligned to pointer. To do this Columns is aligned to pointer and FColumnOffsets is aligned to pointer - 1 (the null:byte). The latter is done in TZRowAccessor.Create where FColumnOffsets is filled in. FPC_REQUIRES_PROPER_ALIGNMENT is a fpc build in define} TZRowBuffer = {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif} record Index: Integer; UpdateType: TZRowUpdateType; BookmarkFlag: Byte; {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT} dummyalign:pointer; {$endif} Columns: TZByteArray; end; PZRowBuffer = ^TZRowBuffer; {** Implements a column buffer accessor. } TZRowAccessor = class(TZCodePagedObject) private FRowSize: Integer; FColumnsSize: Integer; FColumnCount: Integer; FColumnNames: array of string; FColumnCases: array of Boolean; FColumnTypes: array of TZSQLType; FColumnLengths: array of Integer; FColumnOffsets: array of Integer; FColumnDefaultExpressions: array of string; FBuffer: PZRowBuffer; FHasBlobs: Boolean; FTemp: String; function GetColumnSize(ColumnInfo: TZColumnInfo): Integer; function GetBlobObject(Buffer: PZRowBuffer; ColumnIndex: Integer): IZBlob; procedure SetBlobObject(Buffer: PZRowBuffer; ColumnIndex: Integer; Value: IZBlob); function InternalGetBytes(Buffer: PZRowBuffer; ColumnIndex: Integer): TByteDynArray; procedure InternalSetBytes(Buffer: PZRowBuffer; ColumnIndex: Integer; Value: TByteDynArray; NewPointer: Boolean = False); procedure InternalSetString(Buffer: PZRowBuffer; ColumnIndex: Integer; Value: String; NewPointer: Boolean = False); procedure InternalSetUnicodeString(Buffer: PZRowBuffer; ColumnIndex: Integer; Value: ZWideString; NewPointer: Boolean = False); protected procedure CheckColumnIndex(ColumnIndex: Integer); procedure CheckColumnConvertion(ColumnIndex: Integer; ResultType: TZSQLType); public constructor Create(ColumnsInfo: TObjectList; ConSettings: PZConSettings); destructor Destroy; override; function AllocBuffer(var Buffer: PZRowBuffer): PZRowBuffer; procedure InitBuffer(Buffer: PZRowBuffer); procedure CopyBuffer(SrcBuffer: PZRowBuffer; DestBuffer: PZRowBuffer); procedure MoveBuffer(SrcBuffer: PZRowBuffer; DestBuffer: PZRowBuffer); procedure CloneBuffer(SrcBuffer: PZRowBuffer; DestBuffer: PZRowBuffer); procedure ClearBuffer(Buffer: PZRowBuffer); procedure DisposeBuffer(Buffer: PZRowBuffer); function CompareBuffers(Buffer1, Buffer2: PZRowBuffer; ColumnIndices: TIntegerDynArray; ColumnDirs: TBooleanDynArray): Integer; function Alloc: PZRowBuffer; procedure Init; procedure CopyTo(DestBuffer: PZRowBuffer); procedure CopyFrom(SrcBuffer: PZRowBuffer); procedure MoveTo(DestBuffer: PZRowBuffer); procedure MoveFrom(SrcBuffer: PZRowBuffer); procedure CloneTo(DestBuffer: PZRowBuffer); procedure CloneFrom(SrcBuffer: PZRowBuffer); procedure Clear; procedure Dispose; function GetColumnData(ColumnIndex: Integer; var IsNull: Boolean): Pointer; function GetColumnDataSize(ColumnIndex: Integer): Integer; function GetColumnName(ColumnIndex: Integer): string; function GetColumnCase(ColumnIndex: Integer): Boolean; function GetColumnType(ColumnIndex: Integer): TZSQLType; function GetColumnLength(ColumnIndex: Integer): Integer; function GetColumnOffSet(ColumnIndex: Integer): Integer; function GetColumnDefaultExpression(ColumnIndex: Integer): string; procedure SetColumnDefaultExpression(ColumnIndex: Integer; Value: string); //====================================================================== // Methods for accessing results by column index //====================================================================== function IsNull(ColumnIndex: Integer): Boolean; function GetPChar(ColumnIndex: Integer; var IsNull: Boolean): PChar; function GetString(ColumnIndex: Integer; var IsNull: Boolean): String; function GetUnicodeString(ColumnIndex: Integer; var IsNull: Boolean): WideString; function GetBoolean(ColumnIndex: Integer; var IsNull: Boolean): Boolean; function GetByte(ColumnIndex: Integer; var IsNull: Boolean): ShortInt; function GetShort(ColumnIndex: Integer; var IsNull: Boolean): SmallInt; function GetInt(ColumnIndex: Integer; var IsNull: Boolean): Integer; function GetLong(ColumnIndex: Integer; var IsNull: Boolean): Int64; function GetFloat(ColumnIndex: Integer; var IsNull: Boolean): Single; function GetDouble(ColumnIndex: Integer; var IsNull: Boolean): Double; function GetBigDecimal(ColumnIndex: Integer; var IsNull: Boolean): Extended; function GetBytes(ColumnIndex: Integer; var IsNull: Boolean): TByteDynArray; function GetDate(ColumnIndex: Integer; var IsNull: Boolean): TDateTime; function GetTime(ColumnIndex: Integer; var IsNull: Boolean): TDateTime; function GetTimestamp(ColumnIndex: Integer; var IsNull: Boolean): TDateTime; function GetAsciiStream(ColumnIndex: Integer; var IsNull: Boolean): TStream; function GetUnicodeStream(ColumnIndex: Integer; var IsNull: Boolean): TStream; function GetBinaryStream(ColumnIndex: Integer; var IsNull: Boolean): TStream; function GetBlob(ColumnIndex: Integer; var IsNull: Boolean): IZBlob; function GetDataSet(ColumnIndex: Integer; var IsNull: Boolean): IZDataSet; function GetValue(ColumnIndex: Integer): TZVariant; //--------------------------------------------------------------------- // Updates //--------------------------------------------------------------------- procedure SetNotNull(ColumnIndex: Integer); procedure SetNull(ColumnIndex: Integer); procedure SetBoolean(ColumnIndex: Integer; Value: Boolean); procedure SetByte(ColumnIndex: Integer; Value: ShortInt); procedure SetShort(ColumnIndex: Integer; Value: SmallInt); procedure SetInt(ColumnIndex: Integer; Value: Integer); procedure SetLong(ColumnIndex: Integer; Value: Int64); procedure SetFloat(ColumnIndex: Integer; Value: Single); procedure SetDouble(ColumnIndex: Integer; Value: Double); procedure SetBigDecimal(ColumnIndex: Integer; Value: Extended); procedure SetPChar(ColumnIndex: Integer; Value: PChar); procedure SetString(ColumnIndex: Integer; Value: String); procedure SetUnicodeString(ColumnIndex: Integer; Value: WideString); procedure SetBytes(ColumnIndex: Integer; Value: TByteDynArray); procedure SetDate(ColumnIndex: Integer; Value: TDateTime); procedure SetTime(ColumnIndex: Integer; Value: TDateTime); procedure SetTimestamp(ColumnIndex: Integer; Value: TDateTime); procedure SetAsciiStream(ColumnIndex: Integer; Value: TStream); procedure SetUnicodeStream(ColumnIndex: Integer; Value: TStream); procedure SetBinaryStream(ColumnIndex: Integer; Value: TStream); procedure SetBlob(ColumnIndex: Integer; Value: IZBlob); procedure SetDataSet(ColumnIndex: Integer; Value: IZDataSet); procedure SetValue(ColumnIndex: Integer; Value: TZVariant); property ColumnsSize: Integer read FColumnsSize; property RowSize: Integer read FRowSize; property RowBuffer: PZRowBuffer read FBuffer write FBuffer; end; const RowHeaderSize = SizeOf(TZRowBuffer) - SizeOf(TZByteArray); implementation uses Math, ZMessages, ZSysUtils, ZDbcUtils {$IFDEF WITH_UNITANSISTRINGS}, AnsiStrings{$ENDIF}; { TZRowAccessor } {** Creates this object and assignes the main properties. @param ColumnsInfo a collection with column information. } constructor TZRowAccessor.Create(ColumnsInfo: TObjectList; ConSettings: PZConSettings); var I: Integer; Current: TZColumnInfo; begin Self.ConSettings := ConSettings; FBuffer := nil; FColumnCount := ColumnsInfo.Count; FColumnsSize := 0; {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT} FColumnsSize:=align(FColumnsSize+1,sizeof(pointer))-1; {$endif} SetLength(FColumnNames, FColumnCount); SetLength(FColumnCases, FColumnCount); SetLength(FColumnTypes, FColumnCount); SetLength(FColumnLengths, FColumnCount); SetLength(FColumnOffsets, FColumnCount); SetLength(FColumnDefaultExpressions, FColumnCount); FHasBlobs := False; for I := 0 to FColumnCount - 1 do begin Current := TZColumnInfo(ColumnsInfo[I]); FColumnNames[I] := Current.ColumnName; FColumnCases[I] := Current.CaseSensitive; FColumnTypes[I] := Current.ColumnType; FColumnLengths[I] := GetColumnSize(Current); FColumnOffsets[I] := FColumnsSize; FColumnDefaultExpressions[I] := Current.DefaultExpression; Inc(FColumnsSize, FColumnLengths[I] + 1); {$ifdef FPC_REQUIRES_PROPER_ALIGNMENT} FColumnsSize:=align(FColumnsSize+1,sizeof(pointer))-1; {$endif} if Current.ColumnType in [stBytes, stString, stUnicodeString] then FColumnLengths[I] := Current.Precision; if Current.ColumnType = stGUID then FColumnLengths[I] := 16; if FColumnsSize > SizeOf(TZByteArray)-1 then raise EZSQLException.Create(SRowBufferWidthExceeded); FHasBlobs := FHasBlobs or (FColumnTypes[I] in [stAsciiStream, stUnicodeStream, stBinaryStream]); end; FRowSize := FColumnsSize + RowHeaderSize; end; {** Destroys this object and cleanups the memory. } destructor TZRowAccessor.Destroy; begin inherited Destroy; end; {** Checks is the column index correct and row buffer is available. @param ColumnIndex an index of column. } procedure TZRowAccessor.CheckColumnIndex(ColumnIndex: Integer); begin if not Assigned(FBuffer) then raise EZSQLException.Create(SRowBufferIsNotAssigned); if (ColumnIndex <= 0) or (ColumnIndex > FColumnCount) then begin raise EZSQLException.Create( Format(SColumnIsNotAccessable, [ColumnIndex])); end; end; {** Checks is the column convertion from one type to another type allowed. @param ColumnIndex an index of column. @param ResultType a requested data type. @return true if convertion is allowed or throw exception otherwise. } procedure TZRowAccessor.CheckColumnConvertion(ColumnIndex: Integer; ResultType: TZSQLType); begin if not Assigned(FBuffer) then raise EZSQLException.Create(SRowBufferIsNotAssigned); if (ColumnIndex <= 0) or (ColumnIndex > FColumnCount) then begin raise EZSQLException.Create( Format(SColumnIsNotAccessable, [ColumnIndex])); end; if not CheckConvertion(FColumnTypes[ColumnIndex - 1], ResultType) then begin raise EZSQLException.Create( Format(SConvertionIsNotPossible, [ColumnIndex, DefineColumnTypeName(FColumnTypes[ColumnIndex - 1]), DefineColumnTypeName(ResultType)])); end; end; {** Gets a size of column with the specified type. @param ColumnInfo a column information struct. @return a size for the column with the specified type. } function TZRowAccessor.GetColumnSize(ColumnInfo: TZColumnInfo): Integer; begin case ColumnInfo.ColumnType of stBoolean: Result := SizeOf(WordBool); stByte: Result := SizeOf(Byte); stShort: Result := SizeOf(SmallInt); stInteger: Result := SizeOf(Integer); stLong: Result := SizeOf(Int64); stFloat: Result := SizeOf(Single); stDouble: Result := SizeOf(Double); stBigDecimal: Result := SizeOf(Extended); stString: Result := SizeOf(Pointer); stUnicodeString: Result := SizeOf(Pointer); stBytes, stGUID: Result := SizeOf(Pointer) + SizeOf(SmallInt); stDate, stTime, stTimestamp: Result := SizeOf(TDateTime); stAsciiStream, stUnicodeStream, stBinaryStream, stDataSet: Result := SizeOf(Pointer); else Result := 0; end; end; {** Gets a stream from the specified columns. @param Buffer a row buffer. @param ColumnIndex an index of the column. } function TZRowAccessor.GetBlobObject(Buffer: PZRowBuffer; ColumnIndex: Integer): IZBlob; var BlobPtr: PPointer; NullPtr: {$IFDEF WIN64}PBoolean{$ELSE}PByte{$ENDIF}; begin BlobPtr := PPointer(@Buffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1]); NullPtr := {$IFDEF WIN64}PBoolean{$ELSE}PByte{$ENDIF}(@Buffer.Columns[FColumnOffsets[ColumnIndex - 1]]); {$IFNDEF FPC} if NullPtr^ = {$IFDEF WIN64}false{$ELSE}0{$ENDIF} then //M.A. if NullPtr^ = 0 then {$ELSE} if NullPtr^ = 0 then {$ENDIF} Result := IZBlob(BlobPtr^) else Result := nil; end; {** Sets a blob into the specified columns. @param Buffer a row buffer. @param ColumnIndex an index of the column. @param Value a stream object to be set. } procedure TZRowAccessor.SetBlobObject(Buffer: PZRowBuffer; ColumnIndex: Integer; Value: IZBlob); var BlobPtr: PPointer; NullPtr: {$IFDEF WIN64}PBoolean{$ELSE}PByte{$ENDIF}; begin BlobPtr := PPointer(@Buffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1]); NullPtr := {$IFDEF WIN64}PBoolean{$ELSE}PByte{$ENDIF}(@Buffer.Columns[FColumnOffsets[ColumnIndex - 1]]); {$IFNDEF FPC} if NullPtr^ = {$IFDEF WIN64}false{$ELSE}0{$ENDIF} then //M.A. if NullPtr^ = 0 then {$ELSE} if NullPtr^ = 0 then {$ENDIF} IZBlob(BlobPtr^) := nil else BlobPtr^ := nil; IZBlob(BlobPtr^) := Value; if Value <> nil then {$IFNDEF FPC} NullPtr^ := {$IFDEF WIN64}false{$ELSE}0{$ENDIF} //M.A. NullPtr^ := 0 else NullPtr^ := {$IFDEF WIN64}true{$ELSE}1{$ENDIF}; //M.A. NullPtr^ := 1; {$ELSE} NullPtr^ := 0 else NullPtr^ := 1; {$ENDIF} end; function TZRowAccessor.InternalGetBytes(Buffer: PZRowBuffer; ColumnIndex: Integer): TByteDynArray; var P: PPointer; L: SmallInt; begin Result := nil; if ( Buffer.Columns[FColumnOffsets[ColumnIndex - 1]] = 0 )then begin L := PSmallInt(@Buffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1 + SizeOf(Pointer)])^; SetLength(Result, L); if L > 0 then begin P := PPointer(@Buffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1]); Move(P^^, Pointer(Result)^, L); end; end; end; procedure TZRowAccessor.InternalSetBytes(Buffer: PZRowBuffer; ColumnIndex: Integer; Value: TByteDynArray; NewPointer: Boolean = False); var P: PPointer; L: SmallInt; begin if Assigned(Buffer) then begin if NewPointer then PNativeUInt(@Buffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1])^ := 0; P := PPointer(@Buffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1]); L := Min(Length(Value), FColumnLengths[ColumnIndex - 1]); PSmallInt(@FBuffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1 + SizeOf(Pointer)])^ := L; if L > 0 then begin ReallocMem(P^, L); System.Move(Pointer(Value)^, P^^, L); end else if PNativeUInt(@Buffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1])^ > 0 then begin System.Dispose(P^); PNativeUInt(@Buffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1])^ := 0; end; end; end; procedure TZRowAccessor.InternalSetString(Buffer: PZRowBuffer; ColumnIndex: Integer; Value: String; NewPointer: Boolean = False); var C: PPChar; L: SmallInt; begin if Assigned(Buffer) then begin if NewPointer then PNativeUInt(@Buffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1])^ := 0; C := PPChar(@Buffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1]); L := Min(FColumnLengths[ColumnIndex - 1], Length(Value)); ReallocMem(C^, L * SizeOf(Char) + SizeOf(Char)); System.Move(PChar(Value)^, C^^, L * SizeOf(Char)); (C^+L)^ := #0; //set #0 terminator if a truncation is required end; end; procedure TZRowAccessor.InternalSetUnicodeString(Buffer: PZRowBuffer; ColumnIndex: Integer; Value: ZWideString; NewPointer: Boolean = False); var W: ZPPWideChar; L: SmallInt; begin if Assigned(Buffer) then begin if NewPointer then PNativeUInt(@Buffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1])^ := 0; W := ZPPWideChar(@Buffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1]); L := Min(Length(Value), FColumnLengths[ColumnIndex - 1]); Value := System.Copy(Value, 1, L); L := L * 2 + 2; ReallocMem(W^, L); System.Move(PWideChar(Value)^, W^^, L); end; end; {** Allocates a new row buffer and sets it into the variable. @param Buffer a pointer to row buffer. @return a pointer to the allocated buffer. } function TZRowAccessor.AllocBuffer(var Buffer: PZRowBuffer): PZRowBuffer; begin GetMem(Buffer, FRowSize); InitBuffer(Buffer); Result := Buffer; end; {** Disposes the specified row buffer. @param Buffer a pointer to row buffer. } procedure TZRowAccessor.DisposeBuffer(Buffer: PZRowBuffer); begin if Assigned(Buffer) then begin ClearBuffer(Buffer); FreeMem(Buffer); end; end; {** Initializes the row buffer. @param Buffer a pointer to row buffer. } procedure TZRowAccessor.InitBuffer(Buffer: PZRowBuffer); var I : Integer; begin if Assigned(Buffer) then with Buffer^ do begin Index := 0; BookmarkFlag := 0;//bfCurrent; UpdateType := utUnmodified; FillChar(Columns, FColumnsSize, 0); for I := 0 to FColumnCount - 1 do Columns[FColumnOffsets[I]] := 1; end; end; {** Copies the row buffer from source to destination row. @param SrcBuffer a pointer to source row buffer. @param DestBuffer a pointer to destination row buffer. } procedure TZRowAccessor.CopyBuffer(SrcBuffer: PZRowBuffer; DestBuffer: PZRowBuffer); var I: Integer; begin ClearBuffer(DestBuffer); with DestBuffer^ do begin Index := SrcBuffer^.Index; UpdateType := SrcBuffer^.UpdateType; BookmarkFlag := SrcBuffer^.BookmarkFlag; System.Move(SrcBuffer^.Columns, Columns, FColumnsSize); for I := 0 to FColumnCount - 1 do case FColumnTypes[I] of stAsciiStream, stUnicodeStream, stBinaryStream: if (Columns[FColumnOffsets[I]] = 0) then begin Columns[FColumnOffsets[I]] := 1; SetBlobObject(DestBuffer, I + 1, GetBlobObject(SrcBuffer, I + 1)); end; stString: InternalSetString(DestBuffer, I +1, PPChar(@SrcBuffer.Columns[FColumnOffsets[I] + 1])^, True); stUnicodeString: InternalSetUnicodeString(DestBuffer, I +1, ZPPWideChar(@SrcBuffer.Columns[FColumnOffsets[I] + 1])^, True); stBytes,stGUID: InternalSetBytes(DestBuffer, I +1, InternalGetBytes(SrcBuffer, I +1), True); end; end; end; {** Moves the row buffer from source to destination row. Source buffer is cleaned up after the operation. @param SrcBuffer a pointer to source row buffer. @param DestBuffer a pointer to destination row buffer. } procedure TZRowAccessor.MoveBuffer(SrcBuffer: PZRowBuffer; DestBuffer: PZRowBuffer); begin CopyBuffer(SrcBuffer, DestBuffer); ClearBuffer(SrcBuffer); end; {** Clones the row buffer from source to destination row. @param SrcBuffer a pointer to source row buffer. @param DestBuffer a pointer to destination row buffer. } procedure TZRowAccessor.CloneBuffer(SrcBuffer: PZRowBuffer; DestBuffer: PZRowBuffer); var I: Integer; Blob: IZBlob; begin ClearBuffer(DestBuffer); with DestBuffer^ do begin Index := SrcBuffer^.Index; UpdateType := SrcBuffer^.UpdateType; BookmarkFlag := SrcBuffer^.BookmarkFlag; System.Move(SrcBuffer^.Columns, Columns, FColumnsSize); for I := 0 to FColumnCount - 1 do case FColumnTypes[I] of stAsciiStream, stUnicodeStream, stBinaryStream: if (Columns[FColumnOffsets[I]] = 0) then begin Columns[FColumnOffsets[I]] := 1; Blob := GetBlobObject(SrcBuffer, I + 1); if Blob <> nil then Blob := Blob.Clone; SetBlobObject(DestBuffer, I + 1, Blob); end; stString: InternalSetString(DestBuffer, I +1, PPChar(@SrcBuffer.Columns[FColumnOffsets[I] + 1])^, True); stUnicodeString: InternalSetUnicodeString(DestBuffer, I +1, ZPPWideChar(@SrcBuffer.Columns[FColumnOffsets[I] + 1])^, True); stBytes,stGUID: InternalSetBytes(DestBuffer, I +1, InternalGetBytes(SrcBuffer, I +1), True); end; end; end; {** Compares fields from two row buffers. @param Buffer1 the first row buffer to compare. @param Buffer2 the second row buffer to compare. @param ColumnIndices column indices to compare. @param ColumnDirs compare direction for each columns. } function TZRowAccessor.CompareBuffers(Buffer1, Buffer2: PZRowBuffer; ColumnIndices: TIntegerDynArray; ColumnDirs: TBooleanDynArray): Integer; var I: Integer; ColumnIndex: Integer; Length1, Length2: SmallInt; ValuePtr1, ValuePtr2: Pointer; Blob1, Blob2: IZBlob; BlobEmpty1, BlobEmpty2: Boolean; Bts1, Bts2: TByteDynArray; begin Result := 0; for I := Low(ColumnIndices) to High(ColumnIndices) do begin ColumnIndex := ColumnIndices[I] - 1; { Checks for both Null columns. } if (Buffer1.Columns[FColumnOffsets[ColumnIndex]] = 1) and (Buffer2.Columns[FColumnOffsets[ColumnIndex]] = 1) then Continue; { Checks for not-Null and Null columns. } if Buffer1.Columns[FColumnOffsets[ColumnIndex]] <> Buffer2.Columns[FColumnOffsets[ColumnIndex]] then begin if not (FColumnTypes[ColumnIndex] in [stAsciiStream, stUnicodeStream, stBinaryStream]) then begin Result := Buffer2.Columns[FColumnOffsets[ColumnIndex]] - Buffer1.Columns[FColumnOffsets[ColumnIndex]]; if not ColumnDirs[I] then Result := -Result; Break; end; end; { Compares column values. } ValuePtr1 := @Buffer1.Columns[FColumnOffsets[ColumnIndex] + 1]; ValuePtr2 := @Buffer2.Columns[FColumnOffsets[ColumnIndex] + 1]; case FColumnTypes[ColumnIndex] of stByte: Result := Ord((PByte(ValuePtr1)^ > PByte(ValuePtr2)^))-Ord((PByte(ValuePtr1)^ < PByte(ValuePtr2)^)); stShort: Result := Ord((PShortInt(ValuePtr1)^ > PShortInt(ValuePtr2)^))-Ord((PShortInt(ValuePtr1)^ < PShortInt(ValuePtr2)^)); stInteger: Result := Ord((PLongInt(ValuePtr1)^ > PLongInt(ValuePtr2)^))-Ord((PLongInt(ValuePtr1)^ < PLongInt(ValuePtr2)^)); stLong: Result := Ord((PInt64(ValuePtr1)^ > PInt64(ValuePtr2)^))-Ord((PInt64(ValuePtr1)^ < PInt64(ValuePtr2)^)); stFloat: Result := Ord((PSingle(ValuePtr1)^ > PSingle(ValuePtr2)^))-Ord((PSingle(ValuePtr1)^ < PSingle(ValuePtr2)^)); stDouble: Result := Ord((PDouble(ValuePtr1)^ > PDouble(ValuePtr2)^))-Ord((PDouble(ValuePtr1)^ < PDouble(ValuePtr2)^)); stBigDecimal: Result := Ord((PExtended(ValuePtr1)^ > PExtended(ValuePtr2)^))-Ord((PExtended(ValuePtr1)^ < PExtended(ValuePtr2)^)); stBoolean: Result := Ord((PWordBool(ValuePtr1)^ > PWordBool(ValuePtr2)^))-Ord((PWordBool(ValuePtr1)^ < PWordBool(ValuePtr2)^)); stDate, stTime, stTimestamp: Result := Ord((PDateTime(ValuePtr1)^ > PDateTime(ValuePtr2)^))-Ord((PDateTime(ValuePtr1)^ < PDateTime(ValuePtr2)^)); {$IFDEF UNICODE} stUnicodeString,stString: Result := WideCompareStr(PWideChar(ValuePtr1^), PWideChar(ValuePtr2^)); {$ELSE} stString: {$IFDEF MSWINDOWS} //Windows can handle nil pointers Linux not FPC-Bug? Result := AnsiStrComp(PAnsiChar(ValuePtr1^), PAnsiChar(ValuePtr2^)); {$ELSE} if Assigned(PPAnsichar(ValuePtr1)^) and Assigned(PPAnsiChar(ValuePtr2)^) then Result := AnsiStrComp(PAnsiChar(ValuePtr1^), PAnsiChar(ValuePtr2^)) else if not Assigned(PPAnsichar(ValuePtr1)^) and not Assigned(PPAnsiChar(ValuePtr2)^) then Result := 0 else Result := -1; {$ENDIF} stUnicodeString: Result := WideCompareStr(PWideChar(ValuePtr1^), PWideChar(ValuePtr2^)); {$ENDIF} stBytes,stGUID: begin Length1 := PSmallInt(@Buffer1.Columns[FColumnOffsets[ColumnIndex] + 1 + SizeOf(Pointer)])^; Length2 := PSmallInt(@Buffer2.Columns[FColumnOffsets[ColumnIndex] + 1 + SizeOf(Pointer)])^; Result := Length1 - Length2; if Result = 0 then begin Bts1 := InternalGetBytes(Buffer1, ColumnIndex+1); Bts2 := InternalGetBytes(Buffer2, ColumnIndex+1); if (Assigned(Bts1) and Assigned(Bts2)) then if MemLCompAnsi(PAnsiChar(Bts1), PAnsiChar(Bts2), Length1) then Result := 0 else Result := 1 else if not Assigned(Bts1) and not Assigned(Bts2) then Result := 0 else if Assigned(Bts1) then Result := 1 else Result := -1; end; end; stAsciiStream, stBinaryStream, stUnicodeStream: begin Blob1 := GetBlobObject(Buffer1, ColumnIndex + 1); BlobEmpty1 := (Blob1 = nil) or (Blob1.IsEmpty); Blob2 := GetBlobObject(Buffer2, ColumnIndex + 1); BlobEmpty2 := (Blob2 = nil) or (Blob2.IsEmpty); if (BlobEmpty1 = True) and (BlobEmpty2 = True) then Continue else if (BlobEmpty1 <> BlobEmpty2) then begin if BlobEmpty1 then Result := -1 else Result := 1; end else if FColumnTypes[ColumnIndex] = stAsciiStream then {$IFDEF WITH_UNITANSISTRINGS} Result := AnsiStrings.AnsiCompareStr(Blob1.GetString, Blob2.GetString) {$ELSE} Result := AnsiCompareStr(Blob1.GetString, Blob2.GetString) {$ENDIF} else if FColumnTypes[ColumnIndex] = stBinaryStream then Result := CompareStr(Blob1.GetString, Blob2.GetString) else if FColumnTypes[ColumnIndex] = stUnicodeStream then Result := WideCompareStr(Blob1.GetUnicodeString, Blob2.GetUnicodeString); end; end; if Result <> 0 then begin if not ColumnDirs[I] then Result := -Result; Break; end; end; end; {** Cleans the specified row buffer. @param Buffer a pointer to row buffer. } procedure TZRowAccessor.ClearBuffer(Buffer: PZRowBuffer); var I: Integer; P: PPointer; begin with Buffer^ do begin Index := -1; UpdateType := utUnmodified; BookmarkFlag := 0; for I := 0 to FColumnCount - 1 do case FColumnTypes[I] of stAsciiStream, stUnicodeStream, stBinaryStream: if (Columns[FColumnOffsets[I]] = 0) then SetBlobObject(Buffer, I + 1, nil); stBytes,stGUID,stString, stUnicodeString: if PNativeUInt(@Columns[FColumnOffsets[I] +1])^ > 0 then begin P := PPointer(@Columns[FColumnOffsets[I] +1]); System.Dispose(P^); end; end; FillChar(Columns, FColumnsSize, 0); for I := 0 to FColumnCount - 1 do Columns[FColumnOffsets[I]] := 1; end; end; {** Allocates a new row buffer. @return a pointer to the allocated buffer. } function TZRowAccessor.Alloc: PZRowBuffer; begin Result := AllocBuffer(FBuffer); end; {** Disposes an associated row buffer. } procedure TZRowAccessor.Dispose; begin DisposeBuffer(FBuffer); FBuffer := nil; end; {** Initializes the associated row buffer. } procedure TZRowAccessor.Init; begin InitBuffer(FBuffer); end; {** Copies the associated row buffer into a specified one. @param DestBuffer a destination row buffer. } procedure TZRowAccessor.CopyTo(DestBuffer: PZRowBuffer); begin CopyBuffer(FBuffer, DestBuffer); end; {** Copies the associated row buffer from a specified one. @param SrcBuffer a source row buffer. } procedure TZRowAccessor.CopyFrom(SrcBuffer: PZRowBuffer); begin CopyBuffer(SrcBuffer, FBuffer); end; {** Moves the associated row buffer into a specified one. @param DestBuffer a destination row buffer. } procedure TZRowAccessor.MoveTo(DestBuffer: PZRowBuffer); begin MoveBuffer(FBuffer, DestBuffer); end; {** Moves the associated row buffer from a specified one. @param SrcBuffer a source row buffer. } procedure TZRowAccessor.MoveFrom(SrcBuffer: PZRowBuffer); begin MoveBuffer(SrcBuffer, FBuffer); end; {** Clones the associated row buffer into a specified one. @param DestBuffer a destination row buffer. } procedure TZRowAccessor.CloneTo(DestBuffer: PZRowBuffer); begin CloneBuffer(FBuffer, DestBuffer); end; {** Clones the associated row buffer from a specified one. @param SrcBuffer a source row buffer. } procedure TZRowAccessor.CloneFrom(SrcBuffer: PZRowBuffer); begin CloneBuffer(SrcBuffer, FBuffer); end; {** Cleans the associated row buffer. } procedure TZRowAccessor.Clear; begin ClearBuffer(FBuffer); end; {** Gets the case sensitive flag of a column data buffer. @param ColumnIndex the first column is 1, the second is 2, ... @return the case sensitive flag of the column data buffer. } function TZRowAccessor.GetColumnCase(ColumnIndex: Integer): Boolean; begin CheckColumnIndex(ColumnIndex); Result := FColumnCases[ColumnIndex-1]; end; {** Gets a pointer to the column data buffer. @param ColumnIndex the first column is 1, the second is 2, ... @return a pointer to the column data buffer. } function TZRowAccessor.GetColumnData(ColumnIndex: Integer; var IsNull: Boolean): Pointer; begin CheckColumnConvertion(ColumnIndex, stString); Result := @FBuffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1]; IsNull := FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] = 1; end; {** Gets a size of the column data buffer. @param ColumnIndex the first column is 1, the second is 2, ... @return a size of the column data buffer. } function TZRowAccessor.GetColumnDataSize(ColumnIndex: Integer): Integer; begin CheckColumnConvertion(ColumnIndex, stString); Result := FColumnLengths[ColumnIndex - 1]; end; {** Gets then length of a column data buffer. @param ColumnIndex the first column is 1, the second is 2, ... @return the length of the column data buffer. } function TZRowAccessor.GetColumnLength(ColumnIndex: Integer): Integer; begin CheckColumnIndex(ColumnIndex); Result := FColumnLengths[ColumnIndex-1]; end; {** Gets then name of a column data buffer. @param ColumnIndex the first column is 1, the second is 2, ... @return the name of the column data buffer. } function TZRowAccessor.GetColumnName(ColumnIndex: Integer): string; begin CheckColumnIndex(ColumnIndex); Result := FColumnNames[ColumnIndex-1]; end; {** Gets then offset of a column data buffer. @param ColumnIndex the first column is 1, the second is 2, ... @return then offset of the column data buffer. } function TZRowAccessor.GetColumnOffSet(ColumnIndex: Integer): Integer; begin CheckColumnIndex(ColumnIndex); Result := FColumnOffSets[ColumnIndex-1]; end; {** Gets then SQLType of a column data buffer. @param ColumnIndex the first column is 1, the second is 2, ... @return the SQLType of the column data buffer. } function TZRowAccessor.GetColumnType(ColumnIndex: Integer): TZSQLType; begin CheckColumnIndex(ColumnIndex); Result := FColumnTypes[ColumnIndex-1]; end; function TZRowAccessor.GetColumnDefaultExpression(ColumnIndex: Integer): string; begin CheckColumnIndex(ColumnIndex); Result := FColumnDefaultExpressions[ColumnIndex-1]; end; procedure TZRowAccessor.SetColumnDefaultExpression(ColumnIndex: Integer; Value: string); begin FColumnDefaultExpressions[ColumnIndex-1] := Value; end; // //====================================================================== // Methods for accessing results by column index //====================================================================== {** Indicates if the value of the designated column in the current row of this ResultSet object is Null. @param ColumnIndex the first column is 1, the second is 2, ... @return if the value is SQL NULL, the value returned is true. false otherwise. } function TZRowAccessor.IsNull(ColumnIndex: Integer): Boolean; var TempBlob: IZBlob; begin CheckColumnConvertion(ColumnIndex, stString); Result := FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] = 1; if not Result and (FColumnTypes[ColumnIndex - 1] in [stAsciiStream, stBinaryStream, stUnicodeStream]) then begin TempBlob := GetBlobObject(FBuffer, ColumnIndex); Result := (TempBlob = nil) or TempBlob.IsEmpty; end; end; {** Gets the value of the designated column in the current row of this ResultSet object as a PChar in the Delphi programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZRowAccessor.GetPChar(ColumnIndex: Integer; var IsNull: Boolean): PChar; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stString); {$ENDIF} Result := nil; if FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] = 0 then begin case FColumnTypes[ColumnIndex - 1] of stString{$IFDEF UNICODE}, stUnicodeString{$ENDIF}: Result := PPChar(FBuffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1])^; else begin FTemp := GetString(ColumnIndex, IsNull); Result := PChar(FTemp); end; end; IsNull := False; end else IsNull := True; end; {** Gets the value of the designated column in the current row of this ResultSet object as a String in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZRowAccessor.GetString(ColumnIndex: Integer; var IsNull: Boolean): String; var TempBlob: IZBlob; GUID: TGUID; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stString); {$ENDIF} Result := ''; if FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] = 0 then begin case FColumnTypes[ColumnIndex - 1] of stBoolean: if GetBoolean(ColumnIndex, IsNull) then Result := 'True' else Result := 'False'; stByte: Result := IntToStr(GetByte(ColumnIndex, IsNull)); stShort: Result := IntToStr(GetShort(ColumnIndex, IsNull)); stInteger: Result := IntToStr(GetInt(ColumnIndex, IsNull)); stLong: Result := IntToStr(GetLong(ColumnIndex, IsNull)); stFloat: Result := FloatToSQLStr(GetFloat(ColumnIndex, IsNull)); stDouble: Result := FloatToSQLStr(GetDouble(ColumnIndex, IsNull)); stBigDecimal: Result := FloatToSQLStr(GetBigDecimal(ColumnIndex, IsNull)); stString: Result := PPChar(@FBuffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1])^; stUnicodeString, stUnicodeStream: Result := ZDbcString(GetUnicodeString(ColumnIndex, IsNull)); //wide down to expect codpage Ansi stBytes: Result := String(BytesToStr(GetBytes(ColumnIndex, IsNull))); stGUID: begin System.Move(Pointer(GetBytes(ColumnIndex, IsNull))^, GUID, 16); Result := GUIDToString(GUID); end; stDate: Result := FormatDateTime('yyyy-mm-dd', GetDate(ColumnIndex, IsNull)); stTime: Result := FormatDateTime('hh:mm:ss', GetTime(ColumnIndex, IsNull)); stTimestamp: Result := FormatDateTime('yyyy-mm-dd hh:mm:ss', GetTimestamp(ColumnIndex, IsNull)); stAsciiStream, stBinaryStream: begin TempBlob := GetBlobObject(FBuffer, ColumnIndex); if (TempBlob <> nil) and not TempBlob.IsEmpty then Result := String(TempBlob.GetString); end; end; IsNull := False; end else IsNull := True; end; {** Gets the value of the designated column in the current row of this ResultSet object as a WideString in the ObjectPascal programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZRowAccessor.GetUnicodeString(ColumnIndex: Integer; var IsNull: Boolean): WideString; var TempBlob: IZBlob; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stUnicodeString); {$ENDIF} Result := ''; if FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] = 0 then begin case FColumnTypes[ColumnIndex - 1] of stUnicodeString{$IFDEF UNICODE}, stString{$ENDIF}: Result := ZPPWideChar(@FBuffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1])^; stUnicodeStream: begin TempBlob := GetBlobObject(FBuffer, ColumnIndex); if (TempBlob <> nil) and not TempBlob.IsEmpty then Result := TempBlob.GetUnicodeString; end; {$IFNDEF UNICODE} stString: Result := ZDbcUnicodeString(GetString(ColumnIndex, IsNull), ConSettings.CTRL_CP); {$ENDIF} else Result := WideString(GetString(ColumnIndex, IsNull)); end; IsNull := False; end else IsNull := True; end; {** Gets the value of the designated column in the current row of this ResultSet object as a boolean in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is false } function TZRowAccessor.GetBoolean(ColumnIndex: Integer; var IsNull: Boolean): Boolean; var TempStr: string; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stBoolean); {$ENDIF} Result := False; if FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] = 0 then begin case FColumnTypes[ColumnIndex - 1] of stBoolean: Result := PWordBool(@FBuffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1])^; stByte: Result := GetByte(ColumnIndex, IsNull) <> 0; stShort: Result := GetShort(ColumnIndex, IsNull) <> 0; stInteger: Result := GetInt(ColumnIndex, IsNull) <> 0; stLong: Result := GetLong(ColumnIndex, IsNull) <> 0; stFloat: Result := GetFloat(ColumnIndex, IsNull) <> 0; stDouble: Result := GetDouble(ColumnIndex, IsNull) <> 0; stBigDecimal: Result := GetBigDecimal(ColumnIndex, IsNull) <> 0; stString, stUnicodeString: begin TempStr := UpperCase(GetString(ColumnIndex, IsNull)); Result := (TempStr = 'T') or (TempStr = 'Y') or (TempStr = 'TRUE') or (TempStr = 'YES'); end; end; IsNull := False; end else IsNull := True; end; {** Gets the value of the designated column in the current row of this ResultSet object as a byte in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZRowAccessor.GetByte(ColumnIndex: Integer; var IsNull: Boolean): ShortInt; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stByte); {$ENDIF} Result := 0; if FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] = 0 then begin case FColumnTypes[ColumnIndex - 1] of stBoolean: if GetBoolean(ColumnIndex, IsNull) then Result := 1 else Result := 0; stByte: Result := PShortInt(@FBuffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1])^; stShort: Result := GetShort(ColumnIndex, IsNull); stInteger: Result := GetInt(ColumnIndex, IsNull); stLong: Result := GetLong(ColumnIndex, IsNull); stFloat: Result := Trunc(GetFloat(ColumnIndex, IsNull)); stDouble: Result := Trunc(GetDouble(ColumnIndex, IsNull)); stBigDecimal: Result := Trunc(GetBigDecimal(ColumnIndex, IsNull)); stString, stUnicodeString: Result := StrToIntDef(GetString(ColumnIndex, IsNull), 0); end; IsNull := False; end else IsNull := True; end; {** Gets the value of the designated column in the current row of this ResultSet object as a short in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZRowAccessor.GetShort(ColumnIndex: Integer; var IsNull: Boolean): SmallInt; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stShort); {$ENDIF} Result := 0; if FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] = 0 then begin case FColumnTypes[ColumnIndex - 1] of stBoolean: if GetBoolean(ColumnIndex, IsNull) then Result := 1 else Result := 0; stByte: Result := GetByte(ColumnIndex, IsNull); stShort: Result := PSmallInt(@FBuffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1])^; stInteger: Result := GetInt(ColumnIndex, IsNull); stLong: Result := GetLong(ColumnIndex, IsNull); stFloat: Result := Trunc(GetFloat(ColumnIndex, IsNull)); stDouble: Result := Trunc(GetDouble(ColumnIndex, IsNull)); stBigDecimal: Result := Trunc(GetBigDecimal(ColumnIndex, IsNull)); stString, stUnicodeString: Result := StrToIntDef(GetString(ColumnIndex, IsNull), 0); end; IsNull := False; end else IsNull := True; end; {** Gets the value of the designated column in the current row of this ResultSet object as an int in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZRowAccessor.GetInt(ColumnIndex: Integer; var IsNull: Boolean): Integer; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stInteger); {$ENDIF} Result := 0; if FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] = 0 then begin case FColumnTypes[ColumnIndex - 1] of stBoolean: if GetBoolean(ColumnIndex, IsNull) then Result := 1 else Result := 0; stByte: Result := GetByte(ColumnIndex, IsNull); stShort: Result := GetShort(ColumnIndex, IsNull); stInteger: Result := PInteger(@FBuffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1])^; stLong: Result := GetLong(ColumnIndex, IsNull); stFloat: Result := Trunc(GetFloat(ColumnIndex, IsNull)); stDouble: Result := Trunc(GetDouble(ColumnIndex, IsNull)); stBigDecimal: Result := Trunc(GetBigDecimal(ColumnIndex, IsNull)); stString, stUnicodeString: Result := StrToIntDef(GetString(ColumnIndex, IsNull), 0); end; IsNull := False; end else IsNull := True; end; {** Gets the value of the designated column in the current row of this ResultSet object as a long in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZRowAccessor.GetLong(ColumnIndex: Integer; var IsNull: Boolean): Int64; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stLong); {$ENDIF} Result := 0; if FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] = 0 then begin case FColumnTypes[ColumnIndex - 1] of stBoolean: if GetBoolean(ColumnIndex, IsNull) then Result := 1 else Result := 0; stByte: Result := GetByte(ColumnIndex, IsNull); stShort: Result := GetShort(ColumnIndex, IsNull); stInteger: Result := GetInt(ColumnIndex, IsNull); stLong: Result := PInt64(@FBuffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1])^; stFloat: Result := Trunc(GetFloat(ColumnIndex, IsNull)); stDouble: Result := Trunc(GetDouble(ColumnIndex, IsNull)); stBigDecimal: Result := Trunc(GetBigDecimal(ColumnIndex, IsNull)); stString, stUnicodeString: Result := StrToIntDef(GetString(ColumnIndex, IsNull), 0); end; IsNull := False; end else IsNull := True; end; {** Gets the value of the designated column in the current row of this ResultSet object as a float in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZRowAccessor.GetFloat(ColumnIndex: Integer; var IsNull: Boolean): Single; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stFloat); {$ENDIF} Result := 0; if FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] = 0 then begin case FColumnTypes[ColumnIndex - 1] of stBoolean: if GetBoolean(ColumnIndex, IsNull) then Result := 1 else Result := 0; stByte: Result := GetByte(ColumnIndex, IsNull); stShort: Result := GetShort(ColumnIndex, IsNull); stInteger: Result := GetInt(ColumnIndex, IsNull); stLong: Result := GetLong(ColumnIndex, IsNull); stFloat: Result := PSingle(@FBuffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1])^; stDouble: Result := GetDouble(ColumnIndex, IsNull); stBigDecimal: Result := GetBigDecimal(ColumnIndex, IsNull); stString, stUnicodeString: Result := SQLStrToFloatDef(AnsiString(GetString(ColumnIndex, IsNull)), 0); end; IsNull := False; end else IsNull := True; end; {** Gets the value of the designated column in the current row of this ResultSet object as a double in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZRowAccessor.GetDouble(ColumnIndex: Integer; var IsNull: Boolean): Double; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stDouble); {$ENDIF} Result := 0; if FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] = 0 then begin case FColumnTypes[ColumnIndex - 1] of stBoolean: if GetBoolean(ColumnIndex, IsNull) then Result := 1 else Result := 0; stByte: Result := GetByte(ColumnIndex, IsNull); stShort: Result := GetShort(ColumnIndex, IsNull); stInteger: Result := GetInt(ColumnIndex, IsNull); stLong: Result := GetLong(ColumnIndex, IsNull); stFloat: Result := GetFloat(ColumnIndex, IsNull); stDouble: Result := PDouble(@FBuffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1])^; stBigDecimal: Result := GetBigDecimal(ColumnIndex, IsNull); stString, stUnicodeString: Result := SQLStrToFloatDef(AnsiString(GetString(ColumnIndex, IsNull)), 0); end; IsNull := False; end else IsNull := True; end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.BigDecimal in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @param scale the number of digits to the right of the decimal point @return the column value; if the value is SQL NULL, the value returned is null } function TZRowAccessor.GetBigDecimal(ColumnIndex: Integer; var IsNull: Boolean): Extended; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stBigDecimal); {$ENDIF} Result := 0; if FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] = 0 then begin case FColumnTypes[ColumnIndex - 1] of stBoolean: if GetBoolean(ColumnIndex, IsNull) then Result := 1 else Result := 0; stByte: Result := GetByte(ColumnIndex, IsNull); stShort: Result := GetShort(ColumnIndex, IsNull); stInteger: Result := GetInt(ColumnIndex, IsNull); stLong: Result := GetLong(ColumnIndex, IsNull); stFloat: Result := GetFloat(ColumnIndex, IsNull); stDouble: Result := GetDouble(ColumnIndex, IsNull); stBigDecimal: Result := PExtended(@FBuffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1])^; stString, stUnicodeString: Result := SQLStrToFloatDef(AnsiString(GetString(ColumnIndex, IsNull)), 0); end; IsNull := False; end else IsNull := True; end; {** Gets the value of the designated column in the current row of this ResultSet object as a byte array in the Java programming language. The bytes represent the raw values returned by the driver. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZRowAccessor.GetBytes(ColumnIndex: Integer; var IsNull: Boolean): TByteDynArray; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stBytes); {$ENDIF} Result := nil; if FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] = 0 then begin case FColumnTypes[ColumnIndex - 1] of stBytes,stGUID: Result := InternalGetBytes(FBuffer, ColumnIndex); stBinaryStream: Result := GetBlob(ColumnIndex, IsNull).GetBytes; else Result := StrToBytes(AnsiString(GetString(ColumnIndex, IsNull))); end; IsNull := False; end else IsNull := True; end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Date object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZRowAccessor.GetDate(ColumnIndex: Integer; var IsNull: Boolean): TDateTime; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stDate); {$ENDIF} Result := 0; if FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] = 0 then begin case FColumnTypes[ColumnIndex - 1] of stDate, stTime, stTimestamp: Result := Int(PDateTime(@FBuffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1])^); stString, stUnicodeString: Result := Trunc(AnsiSQLDateToDateTime(GetString(ColumnIndex, IsNull))); end; IsNull := False; end else IsNull := True; end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Time object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZRowAccessor.GetTime(ColumnIndex: Integer; var IsNull: Boolean): TDateTime; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stTime); {$ENDIF} Result := 0; if FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] = 0 then begin case FColumnTypes[ColumnIndex - 1] of stDate, stTime, stTimestamp: Result := Frac(PDateTime(@FBuffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1])^); stString, stUnicodeString: Result := Frac(AnsiSQLDateToDateTime(GetString(ColumnIndex, IsNull))); end; IsNull := False; end else IsNull := True; end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null @exception SQLException if a database access error occurs } function TZRowAccessor.GetTimestamp(ColumnIndex: Integer; var IsNull: Boolean): TDateTime; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stTimestamp); {$ENDIF} Result := 0; if FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] = 0 then begin case FColumnTypes[ColumnIndex - 1] of stDate, stTime, stTimestamp: Result := PDateTime(@FBuffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1])^; stString, stUnicodeString: Result := AnsiSQLDateToDateTime(GetString(ColumnIndex, IsNull)); end; IsNull := False; end else IsNull := True; end; {** Gets the value of the designated column in the current row of this ResultSet object as a stream of ASCII characters. The value can then be read in chunks from the stream. This method is particularly suitable for retrieving large LONGVARCHAR values. The JDBC driver will do any necessary conversion from the database format into ASCII.

Note: All the data in the returned stream must be read prior to getting the value of any other column. The next call to a getXXX method implicitly closes the stream. Also, a stream may return 0 when the method InputStream.available is called whether there is data available or not. @param columnIndex the first column is 1, the second is 2, ... @return a Java input stream that delivers the database column value as a stream of one-byte ASCII characters; if the value is SQL NULL, the value returned is null } function TZRowAccessor.GetAsciiStream(ColumnIndex: Integer; var IsNull: Boolean): TStream; var TempBlob: IZBlob; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stAsciiStream); {$ENDIF} TempBlob := GetBlobObject(FBuffer, ColumnIndex); if (TempBlob <> nil) and not TempBlob.IsEmpty then Result := TempBlob.GetStream else Result := nil; IsNull := Result = nil; end; {** Gets the value of a column in the current row as a stream of Gets the value of the designated column in the current row of this ResultSet object as as a stream of Unicode characters. The value can then be read in chunks from the stream. This method is particularly suitable for retrieving largeLONGVARCHARvalues. The JDBC driver will do any necessary conversion from the database format into Unicode. The byte format of the Unicode stream must be Java UTF-8, as specified in the Java virtual machine specification.

Note: All the data in the returned stream must be read prior to getting the value of any other column. The next call to a getXXX method implicitly closes the stream. Also, a stream may return 0 when the method InputStream.available is called whether there is data available or not. @param columnIndex the first column is 1, the second is 2, ... @return a Java input stream that delivers the database column value as a stream in Java UTF-8 byte format; if the value is SQL NULL, the value returned is null } function TZRowAccessor.GetUnicodeStream(ColumnIndex: Integer; var IsNull: Boolean): TStream; var TempBlob: IZBlob; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stUnicodeStream); {$ENDIF} TempBlob := GetBlobObject(FBuffer, ColumnIndex); if (TempBlob <> nil) and not TempBlob.IsEmpty then Result := TempBlob.GetUnicodeStream else Result := nil; IsNull := Result = nil; end; {** Gets the value of a column in the current row as a stream of Gets the value of the designated column in the current row of this ResultSet object as a binary stream of uninterpreted bytes. The value can then be read in chunks from the stream. This method is particularly suitable for retrieving large LONGVARBINARY values.

Note: All the data in the returned stream must be read prior to getting the value of any other column. The next call to a getXXX method implicitly closes the stream. Also, a stream may return 0 when the method InputStream.available is called whether there is data available or not. @param columnIndex the first column is 1, the second is 2, ... @return a Java input stream that delivers the database column value as a stream of uninterpreted bytes; if the value is SQL NULL, the value returned is null } function TZRowAccessor.GetBinaryStream(ColumnIndex: Integer; var IsNull: Boolean): TStream; var TempBlob: IZBlob; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stBinaryStream); {$ENDIF} TempBlob := GetBlobObject(FBuffer, ColumnIndex); if (TempBlob <> nil) and not TempBlob.IsEmpty then Result := TempBlob.GetStream else Result := nil; IsNull := Result = nil; end; {** Returns the value of the designated column in the current row of this ResultSet object as a Blob object in the Java programming language. @param ColumnIndex the first column is 1, the second is 2, ... @return a Blob object representing the SQL BLOB value in the specified column } function TZRowAccessor.GetBlob(ColumnIndex: Integer; var IsNull: Boolean): IZBlob; begin {$IFNDEF DISABLE_CHECKING} CheckColumnIndex(ColumnIndex); if not (FColumnTypes[ColumnIndex - 1] in [stAsciiStream, stBinaryStream, stUnicodeStream]) then begin raise EZSQLException.Create( Format(SCanNotAccessBlobRecord, [ColumnIndex, DefineColumnTypeName(FColumnTypes[ColumnIndex - 1])])); end; {$ENDIF} Result := GetBlobObject(FBuffer, ColumnIndex); IsNull := Result = nil; if Result = nil then begin Result := TZAbstractBlob.CreateWithStream(nil, nil); SetBlobObject(FBuffer, ColumnIndex, Result); end; end; {** Returns the value of the designated column in the current row of this ResultSet object as a ResultSet object in the Java programming language. @param ColumnIndex the first column is 1, the second is 2, ... @return a ResultSet object representing the SQL ResultSet value in the specified column } function TZRowAccessor.GetDataSet(ColumnIndex: Integer; var IsNull: Boolean): IZDataSet; var Ptr: PPointer; NullPtr: {$IFDEF WIN64}PBoolean{$ELSE}PByte{$ENDIF}; begin {$IFNDEF DISABLE_CHECKING} CheckColumnIndex(ColumnIndex); if not (FColumnTypes[ColumnIndex - 1] = stDataSet) then begin raise EZSQLException.Create( Format(SCanNotAccessBlobRecord, [ColumnIndex, DefineColumnTypeName(FColumnTypes[ColumnIndex - 1])])); end; {$ENDIF} Ptr := PPointer(@FBuffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1]); NullPtr := {$IFDEF WIN64}PBoolean{$ELSE}PByte{$ENDIF}(@FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]]); {$IFNDEF FPC} if NullPtr^ = {$IFDEF WIN64}false{$ELSE}0{$ENDIF} then {$ELSE} if NullPtr^ = 0 then {$ENDIF} Result := IZDataSet(Ptr^) else Result := nil; end; {** Gets the value of the designated column in the current row of this ResultSet object as a Variant value. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZRowAccessor.GetValue(ColumnIndex: Integer): TZVariant; var ValuePtr: Pointer; IsNull: Boolean; begin IsNull := False; if FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] = 0 then begin ValuePtr := @FBuffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1]; case FColumnTypes[ColumnIndex - 1] of stByte: begin Result.VType := vtInteger; Result.VInteger := PShortInt(ValuePtr)^; end; stShort: begin Result.VType := vtInteger; Result.VInteger := PSmallInt(ValuePtr)^; end; stInteger: begin Result.VType := vtInteger; Result.VInteger := PInteger(ValuePtr)^; end; stLong: begin Result.VType := vtInteger; Result.VInteger := PInt64(ValuePtr)^; end; stFloat: begin Result.VType := vtFloat; Result.VFloat := PSingle(ValuePtr)^; end; stDouble: begin Result.VType := vtFloat; Result.VFloat := PDouble(ValuePtr)^; end; stBigDecimal: begin Result.VType := vtFloat; Result.VFloat := PExtended(ValuePtr)^; end; stBoolean: begin Result.VType := vtBoolean; Result.VBoolean := PWordBool(ValuePtr)^; end; stDate, stTime, stTimestamp: begin Result.VType := vtDateTime; Result.VDateTime := PDateTime(ValuePtr)^; end; stString: begin Result.VType := vtString; Result.VString := PChar(ValuePtr); end; stUnicodeString: begin Result.VType := vtUnicodeString; Result.VUnicodeString := GetUnicodeString(ColumnIndex, IsNull); end; stBytes,stGUID,stAsciiStream, stBinaryStream: begin Result.VType := vtString; Result.VString := GetString(ColumnIndex, IsNull); end; stUnicodeStream: begin Result.VType := vtUnicodeString; Result.VUnicodeString := GetUnicodeString(ColumnIndex, IsNull); end; stDataSet: begin Result.VType := vtInterface; Result.VInterface := GetDataSet(ColumnIndex, IsNull); end; else Result.VType := vtNull; end; end else Result.VType := vtNull; end; //--------------------------------------------------------------------- // Updates //--------------------------------------------------------------------- {** Gives a not nullable column a null value. The SetXXX methods are used to Set column values in the current row or the insert row. The SetXXX methods do not Set the underlying database; instead the SetRow or insertRow methods are called to Set the database. @param columnIndex the first column is 1, the second is 2, ... } procedure TZRowAccessor.SetNotNull(ColumnIndex: Integer); begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stString); {$ENDIF} if (FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] = 1) and (FColumnTypes[ColumnIndex - 1] in [stAsciiStream, stBinaryStream, stUnicodeStream]) then begin SetBlobObject(FBuffer, ColumnIndex, nil); end; FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] := 0; end; {** Gives a nullable column a null value. The SetXXX methods are used to Set column values in the current row or the insert row. The SetXXX methods do not Set the underlying database; instead the SetRow or insertRow methods are called to Set the database. @param columnIndex the first column is 1, the second is 2, ... } procedure TZRowAccessor.SetNull(ColumnIndex: Integer); begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stString); {$ENDIF} if (FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] = 0) then case FColumnTypes[ColumnIndex - 1] of stAsciiStream, stBinaryStream, stUnicodeStream: SetBlobObject(FBuffer, ColumnIndex, nil); stBytes,stGUID, stString, stUnicodeString: if PNativeUInt(@FBuffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1])^ > 0 then begin System.Dispose(PPointer(@FBuffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1])^); PNativeUInt(@FBuffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1])^ := 0; end; end; FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] := 1; end; {** Sets the designated column with a boolean value. The SetXXX methods are used to Set column values in the current row or the insert row. The SetXXX methods do not Set the underlying database; instead the SetRow or insertRow methods are called to Set the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZRowAccessor.SetBoolean(ColumnIndex: Integer; Value: Boolean); var TempInt: Integer; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stBoolean); {$ENDIF} if Value then TempInt := 1 else TempInt := 0; case FColumnTypes[ColumnIndex - 1] of stBoolean: begin FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] := 0; PWordBool(@FBuffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1])^ := Value; end; stByte: SetByte(ColumnIndex, TempInt); stShort: SetShort(ColumnIndex, TempInt); stInteger: SetInt(ColumnIndex, TempInt); stLong: SetLong(ColumnIndex, TempInt); stFloat: SetFloat(ColumnIndex, TempInt); stDouble: SetDouble(ColumnIndex, TempInt); stBigDecimal: SetBigDecimal(ColumnIndex, TempInt); stString, stUnicodeString: if Value then SetString(ColumnIndex, 'True') else SetString(ColumnIndex, 'False'); end; end; {** Sets the designated column with a byte value. The SetXXX methods are used to Set column values in the current row or the insert row. The SetXXX methods do not Set the underlying database; instead the SetRow or insertRow methods are called to Set the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZRowAccessor.SetByte(ColumnIndex: Integer; Value: ShortInt); begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stByte); {$ENDIF} case FColumnTypes[ColumnIndex - 1] of stBoolean: SetBoolean(ColumnIndex, Value <> 0); stByte: begin FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] := 0; PShortInt(@FBuffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1])^ := Value; end; stShort: SetShort(ColumnIndex, Value); stInteger: SetInt(ColumnIndex, Value); stLong: SetLong(ColumnIndex, Value); stFloat: SetFloat(ColumnIndex, Value); stDouble: SetDouble(ColumnIndex, Value); stBigDecimal: SetBigDecimal(ColumnIndex, Value); stString, stUnicodeString: SetString(ColumnIndex, IntToStr(Value)); end; end; {** Sets the designated column with a short value. The SetXXX methods are used to Set column values in the current row or the insert row. The SetXXX methods do not Set the underlying database; instead the SetRow or insertRow methods are called to Set the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZRowAccessor.SetShort(ColumnIndex: Integer; Value: SmallInt); begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stShort); {$ENDIF} case FColumnTypes[ColumnIndex - 1] of stBoolean: SetBoolean(ColumnIndex, Value <> 0); stByte: SetByte(ColumnIndex, Value); stShort: begin FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] := 0; PSmallInt(@FBuffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1])^ := Value; end; stInteger: SetInt(ColumnIndex, Value); stLong: SetLong(ColumnIndex, Value); stFloat: SetFloat(ColumnIndex, Value); stDouble: SetDouble(ColumnIndex, Value); stBigDecimal: SetBigDecimal(ColumnIndex, Value); stString, stUnicodeString: SetString(ColumnIndex, IntToStr(Value)); end; end; {** Sets the designated column with an int value. The SetXXX methods are used to Set column values in the current row or the insert row. The SetXXX methods do not Set the underlying database; instead the SetRow or insertRow methods are called to Set the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZRowAccessor.SetInt(ColumnIndex: Integer; Value: Integer); begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stInteger); {$ENDIF} case FColumnTypes[ColumnIndex - 1] of stBoolean: SetBoolean(ColumnIndex, Value <> 0); stByte: SetByte(ColumnIndex, Value); stShort: SetShort(ColumnIndex, Value); stInteger: begin FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] := 0; PInteger(@FBuffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1])^ := Value; end; stLong: SetLong(ColumnIndex, Value); stFloat: SetFloat(ColumnIndex, Value); stDouble: SetDouble(ColumnIndex, Value); stBigDecimal: SetBigDecimal(ColumnIndex, Value); stString, stUnicodeString: SetString(ColumnIndex, IntToStr(Value)); end; end; {** Sets the designated column with a long value. The SetXXX methods are used to Set column values in the current row or the insert row. The SetXXX methods do not Set the underlying database; instead the SetRow or insertRow methods are called to Set the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZRowAccessor.SetLong(ColumnIndex: Integer; Value: Int64); begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stLong); {$ENDIF} case FColumnTypes[ColumnIndex - 1] of stBoolean: SetBoolean(ColumnIndex, Value <> 0); stByte: SetByte(ColumnIndex, Value); stShort: SetShort(ColumnIndex, Value); stInteger: SetInt(ColumnIndex, Value); stLong: begin FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] := 0; PInt64(@FBuffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1])^ := Value; end; stFloat: SetFloat(ColumnIndex, Value); stDouble: SetDouble(ColumnIndex, Value); stBigDecimal: SetBigDecimal(ColumnIndex, Value); stString, stUnicodeString: SetString(ColumnIndex, IntToStr(Value)); end; end; {** Sets the designated column with a float value. The SetXXX methods are used to Set column values in the current row or the insert row. The SetXXX methods do not Set the underlying database; instead the SetRow or insertRow methods are called to Set the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZRowAccessor.SetFloat(ColumnIndex: Integer; Value: Single); begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stFloat); {$ENDIF} case FColumnTypes[ColumnIndex - 1] of stBoolean: SetBoolean(ColumnIndex, Value <> 0); stByte: SetByte(ColumnIndex, Trunc(Value)); stShort: SetShort(ColumnIndex, Trunc(Value)); stInteger: SetInt(ColumnIndex, Trunc(Value)); stLong: SetLong(ColumnIndex, Trunc(Value)); stFloat: begin FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] := 0; PSingle(@FBuffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1])^ := Value; end; stDouble: SetDouble(ColumnIndex, Value); stBigDecimal: SetBigDecimal(ColumnIndex, Value); stString, stUnicodeString: SetString(ColumnIndex, FloatToSQLStr(Value)); end; end; {** Sets the designated column with a double value. The SetXXX methods are used to Set column values in the current row or the insert row. The SetXXX methods do not Set the underlying database; instead the SetRow or insertRow methods are called to Set the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZRowAccessor.SetDouble(ColumnIndex: Integer; Value: Double); begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stDouble); {$ENDIF} case FColumnTypes[ColumnIndex - 1] of stBoolean: SetBoolean(ColumnIndex, Value <> 0); stByte: SetByte(ColumnIndex, Trunc(Value)); stShort: SetShort(ColumnIndex, Trunc(Value)); stInteger: SetInt(ColumnIndex, Trunc(Value)); stLong: SetLong(ColumnIndex, Trunc(Value)); stFloat: SetFloat(ColumnIndex, Value); stDouble: begin FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] := 0; PDouble(@FBuffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1])^ := Value; end; stBigDecimal: SetBigDecimal(ColumnIndex, Value); stString, stUnicodeString: SetString(ColumnIndex, FloatToSQLStr(Value)); end; end; {** Sets the designated column with a java.math.BigDecimal value. The SetXXX methods are used to Set column values in the current row or the insert row. The SetXXX methods do not Set the underlying database; instead the SetRow or insertRow methods are called to Set the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZRowAccessor.SetBigDecimal(ColumnIndex: Integer; Value: Extended); begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stBigDecimal); {$ENDIF} case FColumnTypes[ColumnIndex - 1] of stBoolean: SetBoolean(ColumnIndex, Value <> 0); stByte: SetByte(ColumnIndex, Trunc(Value)); stShort: SetShort(ColumnIndex, Trunc(Value)); stInteger: SetInt(ColumnIndex, Trunc(Value)); stLong: SetLong(ColumnIndex, Trunc(Value)); stFloat: SetFloat(ColumnIndex, Value); stDouble: SetDouble(ColumnIndex, Value); stBigDecimal: begin FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] := 0; PExtended(@FBuffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1])^ := Value; end; stString, stUnicodeString: SetString(ColumnIndex, FloatToSQLStr(Value)); end; end; {** Sets the designated column with a String value. The SetXXX methods are used to Set column values in the current row or the insert row. The SetXXX methods do not Set the underlying database; instead the SetRow or insertRow methods are called to Set the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZRowAccessor.SetPChar(ColumnIndex: Integer; Value: PChar); begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stString); {$ENDIF} case FColumnTypes[ColumnIndex - 1] of stString{$IFDEF UNICODE}, stUnicodeString{$ENDIF}: begin if Value <> nil then begin FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] := 0; SetString(ColumnIndex, Value); end else FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] := 1; end; else SetString(ColumnIndex, Value); end; end; {** Sets the designated column with a String value. The SetXXX methods are used to Set column values in the current row or the insert row. The SetXXX methods do not Set the underlying database; instead the SetRow or insertRow methods are called to Set the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZRowAccessor.SetString(ColumnIndex: Integer; Value: String); var TempStr: string; IsNull: Boolean; GUID: TGUID; Bts: TByteDynArray; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stString); {$ENDIF} IsNull := False; case FColumnTypes[ColumnIndex - 1] of stBoolean: begin TempStr := UpperCase(Value); SetBoolean(ColumnIndex, (TempStr = 'Y') or (TempStr = 'T') or (TempStr = 'YES') or (TempStr = 'TRUE')); end; stByte: SetByte(ColumnIndex, StrToIntDef(Value, 0)); stShort: SetShort(ColumnIndex, StrToIntDef(Value, 0)); stInteger: SetInt(ColumnIndex, StrToIntDef(Value, 0)); stLong: SetLong(ColumnIndex, StrToIntDef(Value, 0)); stFloat: SetFloat(ColumnIndex, SQLStrToFloatDef(AnsiString(Value), 0)); stDouble: SetDouble(ColumnIndex, SQLStrToFloatDef(AnsiString(Value), 0)); stBigDecimal: SetBigDecimal(ColumnIndex, SQLStrToFloatDef(AnsiString(Value), 0)); stString: begin InternalSetString(FBuffer, ColumnIndex, Value); FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] := 0; end; stUnicodeString: {$IFDEF UNICODE} SetUnicodeString(ColumnIndex, Value); {$ELSE} SetUnicodeString(ColumnIndex, ZDbcUnicodeString(Value, ConSettings.CTRL_CP)); {$ENDIF} stBytes: SetBytes(ColumnIndex, StrToBytes(AnsiString(Value))); stGUID: begin GUID := StringToGUID(Value); SetLength(Bts, 16); System.Move(Pointer(@GUID)^, Pointer(Bts)^, 16); SetBytes(ColumnIndex, Bts); end; stDate: SetDate(ColumnIndex, AnsiSQLDateToDateTime(Value)); stTime: SetTime(ColumnIndex, AnsiSQLDateToDateTime(Value)); stTimestamp: SetTimestamp(ColumnIndex, AnsiSQLDateToDateTime(Value)); stUnicodeStream: {$IFDEF UNICODE} GetBlob(ColumnIndex, IsNull).SetUnicodeString(Value); {$ELSE} GetBlob(ColumnIndex, IsNull).SetString(ZDbcUnicodeString(Value, ConSettings.CTRL_CP)); {$ENDIF} stAsciiStream: GetBlob(ColumnIndex, IsNull).SetString(ZPlainString(Value, ConSettings, ConSettings.CTRL_CP)); stBinaryStream: GetBlob(ColumnIndex, IsNull).SetString(RawByteString(Value)); end; end; {** Sets the designated column with a WideString value. The SetXXX methods are used to Set column values in the current row or the insert row. The SetXXX methods do not Set the underlying database; instead the SetRow or insertRow methods are called to Set the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZRowAccessor.SetUnicodeString(ColumnIndex: Integer; Value: WideString); var IsNull: Boolean; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stString); {$ENDIF} case FColumnTypes[ColumnIndex - 1] of stUnicodeString{$IFDEF UNICODE},stString{$ENDIF}: begin FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] := 0; InternalSetUnicodeString(FBuffer, ColumnIndex, Value); end; stUnicodeStream: GetBlob(ColumnIndex, IsNull).SetUnicodeString(Value); else SetString(ColumnIndex, ZDbcString(Value)); end; end; {** Sets the designated column with a byte array value. The SetXXX methods are used to Set column values in the current row or the insert row. The SetXXX methods do not Set the underlying database; instead the SetRow or insertRow methods are called to Set the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZRowAccessor.SetBytes(ColumnIndex: Integer; Value: TByteDynArray); var IsNull: Boolean; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stBytes); {$ENDIF} if Value <> nil then begin FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] := 0; case FColumnTypes[ColumnIndex - 1] of stBytes,stGUID: InternalSetBytes(FBuffer, ColumnIndex, Value); stBinaryStream: GetBlob(ColumnIndex, IsNull).SetBytes(Value); else SetString(ColumnIndex, String(BytesToStr(Value))); end; end else SetNull(ColumnIndex); end; {** Sets the designated column with a java.sql.Date value. The SetXXX methods are used to Set column values in the current row or the insert row. The SetXXX methods do not Set the underlying database; instead the SetRow or insertRow methods are called to Set the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZRowAccessor.SetDate(ColumnIndex: Integer; Value: TDateTime); begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stTimestamp); {$ENDIF} case FColumnTypes[ColumnIndex - 1] of stDate: begin FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] := 0; PDateTime(@FBuffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1])^ := Trunc(Value); end; stTimestamp: SetTimestamp(ColumnIndex, Trunc(Value)); stString, stUnicodeString: SetString(ColumnIndex, FormatDateTime('yyyy-mm-dd', Value)); end; end; {** Sets the designated column with a java.sql.Time value. The SetXXX methods are used to Set column values in the current row or the insert row. The SetXXX methods do not Set the underlying database; instead the SetRow or insertRow methods are called to Set the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZRowAccessor.SetTime(ColumnIndex: Integer; Value: TDateTime); begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stTime); {$ENDIF} case FColumnTypes[ColumnIndex - 1] of stTime: begin FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] := 0; PDateTime(@FBuffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1])^ := Frac(Value); end; stTimestamp: SetTimestamp(ColumnIndex, Frac(Value)); stString, stUnicodeString: SetString(ColumnIndex, FormatDateTime('hh:nn:ss', Value)); end; end; {** Sets the designated column with a java.sql.Timestamp value. The SetXXX methods are used to Set column values in the current row or the insert row. The SetXXX methods do not Set the underlying database; instead the SetRow or insertRow methods are called to Set the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZRowAccessor.SetTimestamp(ColumnIndex: Integer; Value: TDateTime); begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stTimestamp); {$ENDIF} case FColumnTypes[ColumnIndex - 1] of stDate: SetDate(ColumnIndex, Value); stTime: SetTime(ColumnIndex, Value); stTimestamp: begin FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]] := 0; PDateTime(@FBuffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1])^ := Value; end; stString, stUnicodeString: SetString(ColumnIndex, FormatDateTime('yyyy-mm-dd hh:nn:ss', Value)); end; end; {** Sets the designated column with an ascii stream value. The SetXXX methods are used to Set column values in the current row or the insert row. The SetXXX methods do not Set the underlying database; instead the SetRow or insertRow methods are called to Set the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZRowAccessor.SetAsciiStream(ColumnIndex: Integer; Value: TStream); var IsNull: Boolean; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stAsciiStream); {$ENDIF} IsNull := False; GetBlob(ColumnIndex, IsNull).SetStream(Value); end; {** Sets the designated column with a binary stream value. The SetXXX methods are used to Set column values in the current row or the insert row. The SetXXX methods do not Set the underlying database; instead the SetRow or insertRow methods are called to Set the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value @param length the length of the stream } procedure TZRowAccessor.SetBinaryStream(ColumnIndex: Integer; Value: TStream); var IsNull: Boolean; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stBinaryStream); {$ENDIF} IsNull := False; GetBlob(ColumnIndex, IsNull).SetStream(Value); end; {** Sets the designated column with a character stream value. The SetXXX methods are used to Set column values in the current row or the insert row. The SetXXX methods do not Set the underlying database; instead the SetRow or insertRow methods are called to Set the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZRowAccessor.SetUnicodeStream(ColumnIndex: Integer; Value: TStream); var IsNull: Boolean; begin IsNull := False; {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stUnicodeStream); {$ENDIF} GetBlob(ColumnIndex, IsNull).SetStream(Value, True); end; {** Sets the blob wrapper object to the specified column. @param ColumnIndex the first column is 1, the second is 2, ... @param Value a blob wrapper object to be set. } procedure TZRowAccessor.SetBlob(ColumnIndex: Integer; Value: IZBlob); begin {$IFNDEF DISABLE_CHECKING} CheckColumnIndex(ColumnIndex); if not (FColumnTypes[ColumnIndex - 1] in [stAsciiStream, stBinaryStream, stUnicodeStream]) then begin raise EZSQLException.Create( Format(SCanNotAccessBlobRecord, [ColumnIndex, DefineColumnTypeName(FColumnTypes[ColumnIndex - 1])])); end; {$ENDIF} SetBlobObject(FBuffer, ColumnIndex, Value); end; {** Sets the blob wrapper object to the specified column. @param ColumnIndex the first column is 1, the second is 2, ... @param Value a ResultSet wrapper object to be set. } procedure TZRowAccessor.SetDataSet(ColumnIndex: Integer; Value: IZDataSet); var Ptr: PPointer; NullPtr: {$IFDEF WIN64}PBoolean{$ELSE}PByte{$ENDIF}; begin {$IFNDEF DISABLE_CHECKING} CheckColumnIndex(ColumnIndex); if not (FColumnTypes[ColumnIndex - 1] = stDataSet) then begin raise EZSQLException.Create( Format(SCanNotAccessBlobRecord, [ColumnIndex, DefineColumnTypeName(FColumnTypes[ColumnIndex - 1])])); end; {$ENDIF} Ptr := PPointer(@FBuffer.Columns[FColumnOffsets[ColumnIndex - 1] + 1]); NullPtr := {$IFDEF WIN64}PBoolean{$ELSE}PByte{$ENDIF}(@FBuffer.Columns[FColumnOffsets[ColumnIndex - 1]]); {$IFNDEF FPC} if NullPtr^ = {$IFDEF WIN64}false{$ELSE}0{$ENDIF} then //M.A. if NullPtr^ = 0 then {$ELSE} if NullPtr^ = 0 then {$ENDIF} IZDataSet(Ptr^) := nil else Ptr^ := nil; IZDataSet(Ptr^) := Value; if Value <> nil then {$IFNDEF FPC} NullPtr^ := {$IFDEF WIN64}false{$ELSE}0{$ENDIF} //M.A. NullPtr^ := 0 else NullPtr^ := {$IFDEF WIN64}true{$ELSE}1{$ENDIF}; //M.A. NullPtr^ := 1; {$ELSE} NullPtr^ := 0 else NullPtr^ := 1; {$ENDIF} end; {** Sets the designated column with a Variant value. The SetXXX methods are used to Set column values in the current row or the insert row. The SetXXX methods do not Set the underlying database; instead the SetRow or insertRow methods are called to Set the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZRowAccessor.SetValue(ColumnIndex: Integer; Value: TZVariant); begin case Value.VType of vtNull: SetNull(ColumnIndex); vtBoolean: SetBoolean(ColumnIndex, Value.VBoolean); vtInteger: SetLong(ColumnIndex, Value.VInteger); vtFloat: SetBigDecimal(ColumnIndex, Value.VFloat); vtBytes: SetBytes(ColumnIndex, Value.VBytes); vtString: SetString(ColumnIndex, Value.VString); vtUnicodeString: SetUnicodeString(ColumnIndex, Value.VUnicodeString); vtDateTime: SetTimestamp(ColumnIndex, Value.VDateTime); end; end; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcCachedResultSet.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Caching Classes and Interfaces } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcCachedResultSet; interface {$I ZDbc.inc} uses Types, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, Contnrs, ZClasses, ZDbcIntfs, ZDbcResultSet, ZDbcCache, ZCompatibility; type // Forward declarations. IZCachedResultSet = interface; {** Resolver to post updates. } IZCachedResolver = interface (IZInterface) ['{546ED716-BB88-468C-8CCE-D7111CF5E1EF}'] procedure CalculateDefaults(Sender: IZCachedResultSet; RowAccessor: TZRowAccessor); procedure PostUpdates(Sender: IZCachedResultSet; UpdateType: TZRowUpdateType; OldRowAccessor, NewRowAccessor: TZRowAccessor); {BEGIN of PATCH [1185969]: Do tasks after posting updates. ie: Updating AutoInc fields in MySQL } procedure UpdateAutoIncrementFields(Sender: IZCachedResultSet; UpdateType: TZRowUpdateType; OldRowAccessor, NewRowAccessor: TZRowAccessor; Resolver: IZCachedResolver); {END of PATCH [1185969]: Do tasks after posting updates. ie: Updating AutoInc fields in MySQL } procedure RefreshCurrentRow(Sender: IZCachedResultSet;RowAccessor: TZRowAccessor); //FOS+ 07112006 end; {** Represents a cached result set. } IZCachedResultSet = interface (IZResultSet) ['{BAF24A92-C8CE-4AB4-AEBC-3D4A9BCB0946}'] function GetResolver: IZCachedResolver; procedure SetResolver(Resolver: IZCachedResolver); {BEGIN PATCH [1214009] Calc Defaults in TZUpdateSQL and Added Methods to GET and SET the database Native Resolver will help to implemented feature to Calculate default values in TZUpdateSQL comment: add this properties to get the original Resolver this will be useful whn using TZUpdateSQL //added by fduenas } function GetNativeResolver: IZCachedResolver; {END PATCH [1214009] CalcDefaults in TZUpdateSQL and Added Methods to GET the DB NativeResolver} function IsCachedUpdates: Boolean; procedure SetCachedUpdates(Value: Boolean); function IsPendingUpdates: Boolean; procedure PostUpdates; procedure CancelUpdates; procedure PostUpdatesCached; procedure DisposeCachedUpdates; procedure RevertRecord; procedure MoveToInitialRow; procedure RefreshRow; // FOS+ 071106 end; {** Implements cached ResultSet. } TZAbstractCachedResultSet = class (TZAbstractResultSet, IZCachedResultSet) private FCachedUpdates: Boolean; FRowsList: TList; FInitialRowsList: TList; FCurrentRowsList: TList; FSelectedRow: PZRowBuffer; FUpdatedRow: PZRowBuffer; FInsertedRow: PZRowBuffer; FRowAccessor: TZRowAccessor; FNewRowAccessor: TZRowAccessor; FOldRowAccessor: TZRowAccessor; FNextRowIndex: Integer; FResolver: IZCachedResolver; {BEGIN PATCH [1214009] CalcDefaults in TZUpdateSQL and Added Methods to GET the DB NativeResolver} FNativeResolver: IZCachedResolver; {END PATCH [1214009] CalcDefaults in TZUpdateSQL and Added Methods to GET the DB NativeResolver} protected procedure CheckAvailable; procedure CheckUpdatable; procedure Open; override; function GetNextRowIndex: Integer; procedure CalculateRowDefaults(RowAccessor: TZRowAccessor); virtual; procedure PostRowUpdates(OldRowAccessor, NewRowAccessor: TZRowAccessor); virtual; function LocateRow(RowsList: TList; RowIndex: Integer): Integer; function AppendRow(Row: PZRowBuffer): PZRowBuffer; procedure PrepareRowForUpdates; property CachedUpdates: Boolean read FCachedUpdates write FCachedUpdates; property RowsList: TList read FRowsList write FRowsList; property InitialRowsList: TList read FInitialRowsList write FInitialRowsList; property CurrentRowsList: TList read FCurrentRowsList write FCurrentRowsList; property SelectedRow: PZRowBuffer read FSelectedRow write FSelectedRow; property UpdatedRow: PZRowBuffer read FUpdatedRow write FUpdatedRow; property InsertedRow: PZRowBuffer read FInsertedRow write FInsertedRow; property RowAccessor: TZRowAccessor read FRowAccessor write FRowAccessor; property OldRowAccessor: TZRowAccessor read FOldRowAccessor write FOldRowAccessor; property NewRowAccessor: TZRowAccessor read FNewRowAccessor write FNewRowAccessor; property NextRowIndex: Integer read FNextRowIndex write FNextRowIndex; property Resolver: IZCachedResolver read FResolver write FResolver; {BEGIN PATCH [1214009] CalcDefaults in TZUpdateSQL and Added Methods to GET the DB NativeResolver} property NativeResolver: IZCachedResolver read FNativeResolver; {END PATCH [1214009] CalcDefaults in TZUpdateSQL and Added Methods to GET the DB NativeResolver} public constructor CreateWithStatement(SQL: string; Statement: IZStatement; ConSettings: PZConSettings); constructor CreateWithColumns(ColumnsInfo: TObjectList; SQL: string; ConSettings: PZConSettings); destructor Destroy; override; procedure Close; override; //====================================================================== // Methods for accessing results by column index //====================================================================== function IsNull(ColumnIndex: Integer): Boolean; override; function GetPChar(ColumnIndex: Integer): PChar; override; function GetString(ColumnIndex: Integer): String; override; function GetUnicodeString(ColumnIndex: Integer): Widestring; override; function GetBoolean(ColumnIndex: Integer): Boolean; override; function GetByte(ColumnIndex: Integer): Byte; override; function GetShort(ColumnIndex: Integer): SmallInt; override; function GetInt(ColumnIndex: Integer): Integer; override; function GetLong(ColumnIndex: Integer): Int64; override; function GetFloat(ColumnIndex: Integer): Single; override; function GetDouble(ColumnIndex: Integer): Double; override; function GetBigDecimal(ColumnIndex: Integer): Extended; override; function GetBytes(ColumnIndex: Integer): TByteDynArray; override; function GetDate(ColumnIndex: Integer): TDateTime; override; function GetTime(ColumnIndex: Integer): TDateTime; override; function GetTimestamp(ColumnIndex: Integer): TDateTime; override; function GetBlob(ColumnIndex: Integer): IZBlob; override; function GetDefaultExpression(ColumnIndex: Integer): string; override; //--------------------------------------------------------------------- // Traversal/Positioning //--------------------------------------------------------------------- function MoveAbsolute(Row: Integer): Boolean; override; //--------------------------------------------------------------------- // Updates //--------------------------------------------------------------------- function RowUpdated: Boolean; override; function RowInserted: Boolean; override; function RowDeleted: Boolean; override; procedure UpdateNull(ColumnIndex: Integer); override; procedure UpdateBoolean(ColumnIndex: Integer; Value: Boolean); override; procedure UpdateByte(ColumnIndex: Integer; Value: ShortInt); override; procedure UpdateShort(ColumnIndex: Integer; Value: SmallInt); override; procedure UpdateInt(ColumnIndex: Integer; Value: Integer); override; procedure UpdateLong(ColumnIndex: Integer; Value: Int64); override; procedure UpdateFloat(ColumnIndex: Integer; Value: Single); override; procedure UpdateDouble(ColumnIndex: Integer; Value: Double); override; procedure UpdateBigDecimal(ColumnIndex: Integer; Value: Extended); override; procedure UpdatePChar(ColumnIndex: Integer; Value: PChar); override; procedure UpdateString(ColumnIndex: Integer; const Value: String); override; procedure UpdateUnicodeString(ColumnIndex: Integer; const Value: WideString); override; procedure UpdateBytes(ColumnIndex: Integer; const Value: TByteDynArray); override; procedure UpdateDate(ColumnIndex: Integer; Value: TDateTime); override; procedure UpdateTime(ColumnIndex: Integer; Value: TDateTime); override; procedure UpdateTimestamp(ColumnIndex: Integer; Value: TDateTime); override; procedure UpdateAsciiStream(ColumnIndex: Integer; Value: TStream); override; procedure UpdateUnicodeStream(ColumnIndex: Integer; Value: TStream); override; procedure UpdateBinaryStream(ColumnIndex: Integer; Value: TStream); override; procedure UpdateDefaultExpression(ColumnIndex: Integer; const Value: string); override; procedure InsertRow; override; procedure UpdateRow; override; procedure DeleteRow; override; procedure CancelRowUpdates; override; procedure RefreshRow;override;// FOS+ 071106 procedure MoveToInsertRow; override; procedure MoveToCurrentRow; override; function CompareRows(Row1, Row2: Integer; const ColumnIndices: TIntegerDynArray; const ColumnDirs: TBooleanDynArray): Integer; override; //--------------------------------------------------------------------- // Cached Updates //--------------------------------------------------------------------- function GetResolver: IZCachedResolver; procedure SetResolver(Resolver: IZCachedResolver); {BEGIN PATCH [1214009] CalcDefaults in TZUpdateSQL and Added Methods to GET the DB NativeResolver} function GetNativeResolver: IZCachedResolver; {END PATCH [1214009] CalcDefaults in TZUpdateSQL and Added Methods to GET the DB NativeResolver} function IsCachedUpdates: Boolean; procedure SetCachedUpdates(Value: Boolean); function IsPendingUpdates: Boolean; virtual; procedure PostUpdates; virtual; procedure CancelUpdates; virtual; procedure RevertRecord; virtual; procedure MoveToInitialRow; virtual; procedure PostUpdatesCached; virtual; procedure DisposeCachedUpdates; virtual; end; {** Implements Abstract cached ResultSet. This class should be extended with database specific logic to form SQL data manipulation statements. } TZCachedResultSet = class(TZAbstractCachedResultSet) private FResultSet: IZResultSet; protected procedure Open; override; function Fetch: Boolean; virtual; procedure FetchAll; virtual; property ResultSet: IZResultSet read FResultSet write FResultSet; public constructor Create(ResultSet: IZResultSet; SQL: string; Resolver: IZCachedResolver; ConSettings: PZConSettings); destructor Destroy; override; procedure Close; override; function GetMetaData: IZResultSetMetaData; override; function IsAfterLast: Boolean; override; function IsLast: Boolean; override; procedure AfterLast; override; function Last: Boolean; override; function MoveAbsolute(Row: Integer): Boolean; override; end; implementation uses ZMessages, ZDbcResultSetMetadata, ZDbcGenericResolver, ZDbcUtils, ZEncoding; { TZAbstractCachedResultSet } {** Creates this object and assignes the main properties. @param Statement an SQL statement object. @param SQL an SQL query. } constructor TZAbstractCachedResultSet.CreateWithStatement(SQL: string; Statement: IZStatement; ConSettings: PZConSettings); begin inherited Create(Statement, SQL, nil, ConSettings); FCachedUpdates := False; end; {** Creates this object and assignes the main properties. @param SQL an SQL query. @param ColumnsInfo a columns info for cached rows. } constructor TZAbstractCachedResultSet.CreateWithColumns( ColumnsInfo: TObjectList; SQL: string; ConSettings: PZConSettings); begin inherited Create(nil, SQL, nil, ConSettings); CopyColumnsInfo(ColumnsInfo, Self.ColumnsInfo); FCachedUpdates := False; Open; end; {** Destroys this object and cleanups the memory. } destructor TZAbstractCachedResultSet.Destroy; begin FResolver := nil; {BEGIN PATCH [1214009] CalcDefaults in TZUpdateSQL and Added Methods to GET the DB NativeResolver} FNativeResolver := nil; {END PATCH [1214009] CalcDefaults in TZUpdateSQL and Added Methods to GET the DB NativeResolver} inherited Destroy; end; {** Checks for availability of the cached buffer. } procedure TZAbstractCachedResultSet.CheckAvailable; begin CheckClosed; if (FRowAccessor = nil) or (FRowAccessor.RowBuffer = nil) then raise EZSQLException.Create(SRowDataIsNotAvailable); end; {** Checks is the cached buffer updatable. } procedure TZAbstractCachedResultSet.CheckUpdatable; begin CheckAvailable; if ResultSetConcurrency <> rcUpdatable then RaiseReadOnlyException; end; {** Generates the next row index value. @return the new generated row index. } function TZAbstractCachedResultSet.GetNextRowIndex: Integer; begin Result := FNextRowIndex; Inc(FNextRowIndex); end; {** Finds a row with specified index among list of rows. @param RowsList a list of rows. @param Index a row index. @return a found row buffer of null otherwise. } function TZAbstractCachedResultSet.LocateRow(RowsList: TList; RowIndex: Integer): Integer; var I: Integer; begin Result := -1; for I := 0 to RowsList.Count - 1 do begin if PZRowBuffer(RowsList[I]).Index = RowIndex then begin Result := I; Break; end; end; end; {** Appends a row to the list of rows if such row is not exist. @param Row a row buffer. @return an appended row buffer. } function TZAbstractCachedResultSet.AppendRow(Row: PZRowBuffer): PZRowBuffer; begin if LocateRow(FInitialRowsList, Row.Index) < 0 then begin FRowAccessor.AllocBuffer(Result); FRowAccessor.CopyBuffer(Row, Result); FInitialRowsList.Add(Result); FCurrentRowsList.Add(Row); end else Result := nil; end; {** Prepares the current selected row for updates. } procedure TZAbstractCachedResultSet.PrepareRowForUpdates; begin if (RowAccessor.RowBuffer = FSelectedRow) and (FSelectedRow <> FUpdatedRow) then begin FSelectedRow := FUpdatedRow; RowAccessor.RowBuffer := FSelectedRow; RowAccessor.CloneFrom(PZRowBuffer(FRowsList[RowNo - 1])); end; end; {** Calculates column default values.. @param RowAccessor a row accessor which contains new column values. } procedure TZAbstractCachedResultSet.CalculateRowDefaults( RowAccessor: TZRowAccessor); begin {$IFNDEF DISABLE_CHECKING} if Resolver = nil then raise EZSQLException.Create(SResolverIsNotSpecified); {$ENDIF} Resolver.CalculateDefaults(Self, RowAccessor); end; {** Post changes to database server. @param OldRowAccessor a row accessor which contains old column values. @param NewRowAccessor a row accessor which contains new or updated column values. } procedure TZAbstractCachedResultSet.PostRowUpdates(OldRowAccessor, NewRowAccessor: TZRowAccessor); begin {$IFNDEF DISABLE_CHECKING} if Resolver = nil then raise EZSQLException.Create(SResolverIsNotSpecified); {$ENDIF} Resolver.PostUpdates(Self, NewRowAccessor.RowBuffer.UpdateType, OldRowAccessor, NewRowAccessor); end; {** Gets a cached updates resolver object. @return a cached updates resolver object. } function TZAbstractCachedResultSet.GetResolver: IZCachedResolver; begin Result := FResolver; end; {** Sets a new cached updates resolver object. @param Resolver a cached updates resolver object. } procedure TZAbstractCachedResultSet.SetResolver(Resolver: IZCachedResolver); begin FResolver := Resolver; {BEGIN PATCH [1214009] CalcDefaults in TZUpdateSQL and Added Methods to GET the DB NativeResolver} if FNativeResolver = nil then FNativeResolver := Resolver; {END PATCH [1214009] CalcDefaults in TZUpdateSQL and Added Methods to GET the DB NativeResolver} end; {BEGIN PATCH [1214009] CalcDefaults in TZUpdateSQL and Added Methods to GET the DB NativeResolver} {** Gets a Native cached updates resolver object. @return a Native cached updates resolver object. } function TZAbstractCachedResultSet.GetNativeResolver: IZCachedResolver; begin Result := FNativeResolver; end; {END PATCH [1214009] CalcDefaults in TZUpdateSQL and Added Methods to GET the DB NativeResolver} {** Checks is the cached updates mode turned on. @return True if the cached updates mode turned on. } function TZAbstractCachedResultSet.IsCachedUpdates: Boolean; begin Result := FCachedUpdates; end; {** Switched the cached updates mode. @param Value boolean flag which turns on/off the cached updates mode. } procedure TZAbstractCachedResultSet.SetCachedUpdates(Value: Boolean); begin if FCachedUpdates <> Value then begin FCachedUpdates := Value; if not FCachedUpdates then PostUpdates; end; end; {** Checks is cached updates pending. @return True if the cached updates pending. } function TZAbstractCachedResultSet.IsPendingUpdates: Boolean; begin Result := FInitialRowsList.Count > 0; end; {** Moves to the current row with initial column values. } procedure TZAbstractCachedResultSet.MoveToInitialRow; var Index: Integer; begin CheckClosed; if (RowNo >= 1) and (RowNo <= LastRowNo) and (FSelectedRow <> nil) then begin Index := LocateRow(FInitialRowsList, FSelectedRow.Index); if Index >= 0 then begin FSelectedRow := FInitialRowsList[Index]; FRowAccessor.RowBuffer := FSelectedRow; end; end else FRowAccessor.RowBuffer := nil; end; {** Posts all saved updates to the server. } procedure TZAbstractCachedResultSet.PostUpdates; begin CheckClosed; if FInitialRowsList.Count > 0 then begin while FInitialRowsList.Count > 0 do begin OldRowAccessor.RowBuffer := PZRowBuffer(FInitialRowsList[0]); NewRowAccessor.RowBuffer := PZRowBuffer(FCurrentRowsList[0]); { Updates default field values. } if NewRowAccessor.RowBuffer.UpdateType = utInserted then CalculateRowDefaults(NewRowAccessor); { Posts row updates and processes the exceptions. } PostRowUpdates(OldRowAccessor, NewRowAccessor); { If post was Ok - update the row update type. } if NewRowAccessor.RowBuffer.UpdateType <> utDeleted then begin NewRowAccessor.RowBuffer.UpdateType := utUnmodified; if (FSelectedRow <> nil) and (FSelectedRow.Index = NewRowAccessor.RowBuffer.Index) then FSelectedRow.UpdateType := utUnmodified; end; { Removes cached rows. } OldRowAccessor.Dispose; FInitialRowsList.Delete(0); FCurrentRowsList.Delete(0); end; end; end; {** Posts all saved updates to the server but keeps them cached. } procedure TZAbstractCachedResultSet.PostUpdatesCached; var i: Integer; begin CheckClosed; if FInitialRowsList.Count > 0 then begin i := 0; while i < FInitialRowsList.Count do begin OldRowAccessor.RowBuffer := PZRowBuffer(FInitialRowsList[i]); NewRowAccessor.RowBuffer := PZRowBuffer(FCurrentRowsList[i]); Inc(i); { Updates default field values. } if NewRowAccessor.RowBuffer.UpdateType = utInserted then CalculateRowDefaults(NewRowAccessor); { Posts row updates. } PostRowUpdates(OldRowAccessor, NewRowAccessor); end; end; end; {** Frees the updates and marks records as unmodified. Complements PostUpdatesCached. } procedure TZAbstractCachedResultSet.DisposeCachedUpdates; begin while FInitialRowsList.Count > 0 do begin OldRowAccessor.RowBuffer := PZRowBuffer(FInitialRowsList[0]); NewRowAccessor.RowBuffer := PZRowBuffer(FCurrentRowsList[0]); if NewRowAccessor.RowBuffer.UpdateType <> utDeleted then begin NewRowAccessor.RowBuffer.UpdateType := utUnmodified; if (FSelectedRow <> nil) and (FSelectedRow.Index = NewRowAccessor.RowBuffer.Index) then FSelectedRow.UpdateType := utUnmodified; end; { Remove cached rows. } OldRowAccessor.Dispose; FInitialRowsList.Delete(0); FCurrentRowsList.Delete(0); end; end; {** Cancels updates for all rows. } procedure TZAbstractCachedResultSet.CancelUpdates; var InitialRow, CurrentRow: PZRowBuffer; begin CheckClosed; while FInitialRowsList.Count > 0 do begin InitialRow := PZRowBuffer(FInitialRowsList[0]); CurrentRow := PZRowBuffer(FCurrentRowsList[0]); if CurrentRow.UpdateType = utInserted then InitialRow.UpdateType := utDeleted; FRowAccessor.CopyBuffer(InitialRow, CurrentRow); if (FSelectedRow = FUpdatedRow) and (FSelectedRow.Index = InitialRow.Index) then FRowAccessor.CopyBuffer(InitialRow, FSelectedRow); FRowAccessor.DisposeBuffer(InitialRow); FInitialRowsList.Delete(0); FCurrentRowsList.Delete(0); end; end; {** Cancels updates for the current row. } procedure TZAbstractCachedResultSet.RefreshRow; begin if Resolver = nil then raise EZSQLException.Create(SResolverIsNotSpecified); Resolver.RefreshCurrentRow(Self,RowAccessor); end; procedure TZAbstractCachedResultSet.RevertRecord; var Index: Integer; InitialRow, CurrentRow: PZRowBuffer; begin CheckClosed; if (RowNo >= 1) and (RowNo <= LastRowNo) then begin Index := LocateRow(FInitialRowsList, FSelectedRow.Index); if Index >= 0 then begin InitialRow := PZRowBuffer(FInitialRowsList[Index]); CurrentRow := PZRowBuffer(FRowsList[RowNo - 1]); if CurrentRow.UpdateType = utInserted then InitialRow.UpdateType := utDeleted; FRowAccessor.CopyBuffer(InitialRow, CurrentRow); if (FSelectedRow = FUpdatedRow) then FRowAccessor.CopyBuffer(InitialRow, FSelectedRow); FRowAccessor.DisposeBuffer(InitialRow); FInitialRowsList.Delete(Index); FCurrentRowsList.Delete(Index); end; end; end; {** Opens this recordset. } procedure TZAbstractCachedResultSet.Open; begin if not Closed then raise EZSQLException.Create(SResultsetIsAlreadyOpened); FRowsList := TList.Create; FInitialRowsList := TList.Create; FCurrentRowsList := TList.Create; FRowAccessor := TZRowAccessor.Create(ColumnsInfo, ConSettings); FOldRowAccessor := TZRowAccessor.Create(ColumnsInfo, ConSettings); FNewRowAccessor := TZRowAccessor.Create(ColumnsInfo, ConSettings); FRowAccessor.AllocBuffer(FUpdatedRow); FRowAccessor.AllocBuffer(FInsertedRow); FSelectedRow := nil; FNextRowIndex := 0; if (Resolver = nil) and (GetConcurrency = rcUpdatable) then Resolver := TZGenericCachedResolver.Create(GetStatement, GetMetadata); inherited Open; end; {** Releases this ResultSet object's database and JDBC resources immediately instead of waiting for this to happen when it is automatically closed.

Note: A ResultSet object is automatically closed by the Statement object that generated it when that Statement object is closed, re-executed, or is used to retrieve the next result from a sequence of multiple results. A ResultSet object is also automatically closed when it is garbage collected. } procedure TZAbstractCachedResultSet.Close; var I: Integer; begin inherited Close; if Assigned(FRowAccessor) then begin for I := 0 to FRowsList.Count - 1 do FRowAccessor.DisposeBuffer(PZRowBuffer(FRowsList[I])); for I := 0 to FInitialRowsList.Count - 1 do FRowAccessor.DisposeBuffer(PZRowBuffer(FInitialRowsList[I])); FRowAccessor.DisposeBuffer(FUpdatedRow); FUpdatedRow := nil; FRowAccessor.DisposeBuffer(FInsertedRow); FInsertedRow := nil; FSelectedRow := nil; FreeAndNil(FRowsList); FreeAndNil(FInitialRowsList); FreeAndNil(FCurrentRowsList); FreeAndNil(FRowAccessor); FreeAndNil(FOldRowAccessor); FreeAndNil(FNewRowAccessor); end; end; //====================================================================== // Methods for accessing results by column index //====================================================================== {** Indicates if the value of the designated column in the current row of this ResultSet object is Null. @param columnIndex the first column is 1, the second is 2, ... @return if the value is SQL NULL, the value returned is true. false otherwise. } function TZAbstractCachedResultSet.IsNull(ColumnIndex: Integer): Boolean; begin {$IFNDEF DISABLE_CHECKING} CheckAvailable; {$ENDIF} Result := FRowAccessor.IsNull(ColumnIndex); end; {** Gets the value of the designated column in the current row of this ResultSet object as a PAnsiChar in the Delphi programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZAbstractCachedResultSet.GetPChar(ColumnIndex: Integer): PChar; begin {$IFNDEF DISABLE_CHECKING} CheckAvailable; {$ENDIF} Result := FRowAccessor.GetPChar(ColumnIndex, LastWasNull); end; {** Gets the value of the designated column in the current row of this ResultSet object as a String in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZAbstractCachedResultSet.GetString(ColumnIndex: Integer): String; begin {$IFNDEF DISABLE_CHECKING} CheckAvailable; {$ENDIF} Result := FRowAccessor.GetString(ColumnIndex, LastWasNull); end; {** Gets the value of the designated column in the current row of this ResultSet object as a Widestring in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZAbstractCachedResultSet.GetUnicodeString(ColumnIndex: Integer): Widestring; begin {$IFNDEF DISABLE_CHECKING} CheckAvailable; {$ENDIF} Result := FRowAccessor.GetUnicodeString(ColumnIndex, LastWasNull); end; {** Gets the value of the designated column in the current row of this ResultSet object as a boolean in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is false } function TZAbstractCachedResultSet.GetBoolean(ColumnIndex: Integer): Boolean; begin {$IFNDEF DISABLE_CHECKING} CheckAvailable; {$ENDIF} Result := FRowAccessor.GetBoolean(ColumnIndex, LastWasNull); end; {** Gets the value of the designated column in the current row of this ResultSet object as a byte in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZAbstractCachedResultSet.GetByte(ColumnIndex: Integer): Byte; begin {$IFNDEF DISABLE_CHECKING} CheckAvailable; {$ENDIF} Result := FRowAccessor.GetByte(ColumnIndex, LastWasNull); end; {** Gets the value of the designated column in the current row of this ResultSet object as a short in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZAbstractCachedResultSet.GetShort(ColumnIndex: Integer): SmallInt; begin {$IFNDEF DISABLE_CHECKING} CheckAvailable; {$ENDIF} Result := FRowAccessor.GetShort(ColumnIndex, LastWasNull); end; {** Gets the value of the designated column in the current row of this ResultSet object as an int in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZAbstractCachedResultSet.GetInt(ColumnIndex: Integer): Integer; begin {$IFNDEF DISABLE_CHECKING} CheckAvailable; {$ENDIF} Result := FRowAccessor.GetInt(ColumnIndex, LastWasNull); end; {** Gets the value of the designated column in the current row of this ResultSet object as a long in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZAbstractCachedResultSet.GetLong(ColumnIndex: Integer): Int64; begin {$IFNDEF DISABLE_CHECKING} CheckAvailable; {$ENDIF} Result := FRowAccessor.GetLong(ColumnIndex, LastWasNull); end; {** Gets the value of the designated column in the current row of this ResultSet object as a float in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZAbstractCachedResultSet.GetFloat(ColumnIndex: Integer): Single; begin {$IFNDEF DISABLE_CHECKING} CheckAvailable; {$ENDIF} Result := FRowAccessor.GetFloat(ColumnIndex, LastWasNull); end; {** Gets the value of the designated column in the current row of this ResultSet object as a double in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZAbstractCachedResultSet.GetDouble(ColumnIndex: Integer): Double; begin {$IFNDEF DISABLE_CHECKING} CheckAvailable; {$ENDIF} Result := FRowAccessor.GetDouble(ColumnIndex, LastWasNull); end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.BigDecimal in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @param scale the number of digits to the right of the decimal point @return the column value; if the value is SQL NULL, the value returned is null } function TZAbstractCachedResultSet.GetBigDecimal(ColumnIndex: Integer): Extended; begin {$IFNDEF DISABLE_CHECKING} CheckAvailable; {$ENDIF} Result := FRowAccessor.GetBigDecimal(ColumnIndex, LastWasNull); end; {** Gets the value of the designated column in the current row of this ResultSet object as a byte array in the Java programming language. The bytes represent the raw values returned by the driver. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZAbstractCachedResultSet.GetBytes(ColumnIndex: Integer): TByteDynArray; begin {$IFNDEF DISABLE_CHECKING} CheckAvailable; {$ENDIF} Result := FRowAccessor.GetBytes(ColumnIndex, LastWasNull); end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Date object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZAbstractCachedResultSet.GetDate(ColumnIndex: Integer): TDateTime; begin {$IFNDEF DISABLE_CHECKING} CheckAvailable; {$ENDIF} Result := FRowAccessor.GetDate(ColumnIndex, LastWasNull); end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Time object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZAbstractCachedResultSet.GetTime(ColumnIndex: Integer): TDateTime; begin {$IFNDEF DISABLE_CHECKING} CheckAvailable; {$ENDIF} Result := FRowAccessor.GetTime(ColumnIndex, LastWasNull); end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null @exception SQLException if a database access error occurs } function TZAbstractCachedResultSet.GetTimestamp(ColumnIndex: Integer): TDateTime; begin {$IFNDEF DISABLE_CHECKING} CheckAvailable; {$ENDIF} Result := FRowAccessor.GetTimestamp(ColumnIndex, LastWasNull); end; {** Returns the value of the designated column in the current row of this ResultSet object as a Blob object in the Java programming language. @param ColumnIndex the first column is 1, the second is 2, ... @return a Blob object representing the SQL BLOB value in the specified column } function TZAbstractCachedResultSet.GetBlob(ColumnIndex: Integer): IZBlob; begin {$IFNDEF DISABLE_CHECKING} CheckAvailable; {$ENDIF} Result := FRowAccessor.GetBlob(ColumnIndex, LastWasNull); end; {** Gets the DefaultExpression value of the designated column in the current row of this ResultSet object as a String. @param columnIndex the first column is 1, the second is 2, ... @return the DefaultExpression value } function TZAbstractCachedResultSet.GetDefaultExpression(ColumnIndex: Integer): string; begin {$IFNDEF DISABLE_CHECKING} CheckAvailable; {$ENDIF} Result := FRowAccessor.GetColumnDefaultExpression(ColumnIndex); end; //--------------------------------------------------------------------- // Updates //--------------------------------------------------------------------- {** Gives a nullable column a null value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... } procedure TZAbstractCachedResultSet.UpdateNull(ColumnIndex: Integer); begin {$IFNDEF DISABLE_CHECKING} CheckUpdatable; {$ENDIF} PrepareRowForUpdates; FRowAccessor.SetNull(ColumnIndex); end; {** Updates the designated column with a boolean value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractCachedResultSet.UpdateBoolean(ColumnIndex: Integer; Value: Boolean); begin {$IFNDEF DISABLE_CHECKING} CheckUpdatable; {$ENDIF} PrepareRowForUpdates; FRowAccessor.SetBoolean(ColumnIndex, Value); end; {** Updates the designated column with a byte value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractCachedResultSet.UpdateByte(ColumnIndex: Integer; Value: ShortInt); begin {$IFNDEF DISABLE_CHECKING} CheckUpdatable; {$ENDIF} PrepareRowForUpdates; FRowAccessor.SetByte(ColumnIndex, Value); end; {** Updates the designated column with a short value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractCachedResultSet.UpdateShort(ColumnIndex: Integer; Value: SmallInt); begin {$IFNDEF DISABLE_CHECKING} CheckUpdatable; {$ENDIF} PrepareRowForUpdates; FRowAccessor.SetShort(ColumnIndex, Value); end; {** Updates the designated column with an int value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractCachedResultSet.UpdateInt(ColumnIndex, Value: Integer); begin {$IFNDEF DISABLE_CHECKING} CheckUpdatable; {$ENDIF} PrepareRowForUpdates; FRowAccessor.SetInt(ColumnIndex, Value); end; {** Updates the designated column with a long value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractCachedResultSet.UpdateLong(ColumnIndex: Integer; Value: Int64); begin {$IFNDEF DISABLE_CHECKING} CheckUpdatable; {$ENDIF} PrepareRowForUpdates; FRowAccessor.SetLong(ColumnIndex, Value); end; {** Updates the designated column with a float value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractCachedResultSet.UpdateFloat(ColumnIndex: Integer; Value: Single); begin {$IFNDEF DISABLE_CHECKING} CheckUpdatable; {$ENDIF} PrepareRowForUpdates; FRowAccessor.SetFloat(ColumnIndex, Value); end; {** Updates the designated column with a double value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractCachedResultSet.UpdateDouble(ColumnIndex: Integer; Value: Double); begin {$IFNDEF DISABLE_CHECKING} CheckUpdatable; {$ENDIF} PrepareRowForUpdates; FRowAccessor.SetDouble(ColumnIndex, Value); end; {** Updates the designated column with a java.math.BigDecimal value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractCachedResultSet.UpdateBigDecimal(ColumnIndex: Integer; Value: Extended); begin {$IFNDEF DISABLE_CHECKING} CheckUpdatable; {$ENDIF} PrepareRowForUpdates; FRowAccessor.SetBigDecimal(ColumnIndex, Value); end; {** Updates the designated column with a String value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractCachedResultSet.UpdatePChar(ColumnIndex: Integer; Value: PChar); begin {$IFNDEF DISABLE_CHECKING} CheckUpdatable; {$ENDIF} PrepareRowForUpdates; FRowAccessor.SetPChar(ColumnIndex, Value); end; {** Updates the designated column with a String value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractCachedResultSet.UpdateString(ColumnIndex: Integer; const Value: String); begin {$IFNDEF DISABLE_CHECKING} CheckUpdatable; {$ENDIF} PrepareRowForUpdates; FRowAccessor.SetString(ColumnIndex, Value); end; {** Updates the designated column with a Widestring value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractCachedResultSet.UpdateUnicodeString(ColumnIndex: Integer; const Value: WideString); begin {$IFNDEF DISABLE_CHECKING} CheckUpdatable; {$ENDIF} PrepareRowForUpdates; FRowAccessor.SetUnicodeString(ColumnIndex, Value); end; {** Updates the designated column with a byte array value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractCachedResultSet.UpdateBytes(ColumnIndex: Integer; const Value: TByteDynArray); begin {$IFNDEF DISABLE_CHECKING} CheckUpdatable; {$ENDIF} PrepareRowForUpdates; FRowAccessor.SetBytes(ColumnIndex, Value); end; {** Updates the designated column with a java.sql.Date value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractCachedResultSet.UpdateDate(ColumnIndex: Integer; Value: TDateTime); begin {$IFNDEF DISABLE_CHECKING} CheckUpdatable; {$ENDIF} PrepareRowForUpdates; FRowAccessor.SetDate(ColumnIndex, Value); end; {** Updates the designated column with a java.sql.Time value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractCachedResultSet.UpdateTime(ColumnIndex: Integer; Value: TDateTime); begin {$IFNDEF DISABLE_CHECKING} CheckUpdatable; {$ENDIF} PrepareRowForUpdates; FRowAccessor.SetTime(ColumnIndex, Value); end; {** Updates the designated column with a java.sql.Timestamp value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractCachedResultSet.UpdateTimestamp(ColumnIndex: Integer; Value: TDateTime); begin {$IFNDEF DISABLE_CHECKING} CheckUpdatable; {$ENDIF} PrepareRowForUpdates; FRowAccessor.SetTimestamp(ColumnIndex, Value); end; {** Updates the designated column with an ascii stream value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractCachedResultSet.UpdateAsciiStream(ColumnIndex: Integer; Value: TStream); begin {$IFNDEF DISABLE_CHECKING} CheckUpdatable; {$ENDIF} PrepareRowForUpdates; FRowAccessor.SetAsciiStream(ColumnIndex, Value); end; {** Updates the designated column with a binary stream value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value @param length the length of the stream } procedure TZAbstractCachedResultSet.UpdateBinaryStream( ColumnIndex: Integer; Value: TStream); begin {$IFNDEF DISABLE_CHECKING} CheckUpdatable; {$ENDIF} PrepareRowForUpdates; FRowAccessor.SetBinaryStream(ColumnIndex, Value); end; {** Updates the designated column with a character stream value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractCachedResultSet.UpdateUnicodeStream( ColumnIndex: Integer; Value: TStream); var TempStream: TStream; begin {$IFNDEF DISABLE_CHECKING} CheckUpdatable; {$ENDIF} PrepareRowForUpdates; {EgonHugeist: Findout, wat's comming in! To avoid User-Bugs it is possible that a PAnsiChar OR a PWideChar was written into the Stream!!! And these chars could be trunced with changing the Stream.Size.} if Assigned(Value) then begin TempStream := GetValidatedUnicodeStream(TMemoryStream(Value).Memory, Value.Size, ConSettings, False); FRowAccessor.SetUnicodeStream(ColumnIndex, TempStream); TempStream.Free; end else FRowAccessor.SetUnicodeStream(ColumnIndex, nil); end; {** Updates the DefaultExpression of the designated column with a String value. This changes the behaviour of the RowAccessor used by the Resultset @param columnIndex the first column is 1, the second is 2, ... @param x the new DefaultExpression value for the column } procedure TZAbstractCachedResultSet.UpdateDefaultExpression(ColumnIndex: Integer; const Value: string); begin FNewRowAccessor.SetColumnDefaultExpression(ColumnIndex, Value); end; //--------------------------------------------------------------------- // Processing methods //--------------------------------------------------------------------- {** Moves the cursor to the given row number in this ResultSet object.

If the row number is positive, the cursor moves to the given row number with respect to the beginning of the result set. The first row is row 1, the second is row 2, and so on.

If the given row number is negative, the cursor moves to an absolute row position with respect to the end of the result set. For example, calling the method absolute(-1) positions the cursor on the last row; calling the method absolute(-2) moves the cursor to the next-to-last row, and so on.

An attempt to position the cursor beyond the first/last row in the result set leaves the cursor before the first row or after the last row.

Note: Calling absolute(1) is the same as calling first(). Calling absolute(-1) is the same as calling last(). @return true if the cursor is on the result set; false otherwise } function TZAbstractCachedResultSet.MoveAbsolute(Row: Integer): Boolean; begin {$IFNDEF DISABLE_CHECKING} CheckClosed; if (ResultSetType = rtForwardOnly) and (Row < RowNo) then RaiseForwardOnlyException; {$ENDIF} if (Row >= 0) and (Row <= LastRowNo + 1) then begin RowNo := Row; if (Row >= 1) and (Row <= LastRowNo) then begin Result := True; FSelectedRow := PZRowBuffer(FRowsList[Row - 1]); RowAccessor.RowBuffer := FSelectedRow; end else begin Result := False; FSelectedRow := nil; RowAccessor.RowBuffer := FSelectedRow; end; end else Result := False; end; {** Indicates whether the current row has been updated. The value returned depends on whether or not the result set can detect updates. @return true if the row has been visibly updated by the owner or another, and updates are detected } function TZAbstractCachedResultSet.RowUpdated: Boolean; var CurrentRow: PZRowBuffer; begin if (RowNo >= 1) and (RowNo <= LastRowNo) then begin CurrentRow := PZRowBuffer(FRowsList[RowNo - 1]); Result := CurrentRow^.UpdateType = utModified; end else Result := False; end; {** Indicates whether the current row has had an insertion. The value returned depends on whether or not this ResultSet object can detect visible inserts. @return true if a row has had an insertion and insertions are detected; false otherwise } function TZAbstractCachedResultSet.RowInserted: Boolean; var CurrentRow: PZRowBuffer; begin if (RowNo >= 1) and (RowNo <= LastRowNo) then begin CurrentRow := PZRowBuffer(FRowsList[RowNo - 1]); Result := CurrentRow^.UpdateType = utInserted; end else Result := False; end; {** Indicates whether a row has been deleted. A deleted row may leave a visible "hole" in a result set. This method can be used to detect holes in a result set. The value returned depends on whether or not this ResultSet object can detect deletions. @return true if a row was deleted and deletions are detected; false otherwise } function TZAbstractCachedResultSet.RowDeleted: Boolean; var UpdateType: TZRowUpdateType; begin if (RowNo >= 1) and (RowNo <= LastRowNo) then begin UpdateType := PZRowBuffer(FRowsList[RowNo - 1])^.UpdateType; Result := UpdateType = utDeleted; end else Result := False; end; {** Inserts the contents of the insert row into this ResultSet object and into the database. The cursor must be on the insert row when this method is called. } procedure TZAbstractCachedResultSet.InsertRow; var TempRow: PZRowBuffer; begin CheckClosed; { Creates a new row. } TempRow := FRowAccessor.RowBuffer; FRowAccessor.Alloc; FRowAccessor.MoveFrom(FInsertedRow); FRowAccessor.RowBuffer^.UpdateType := utInserted; FRowAccessor.RowBuffer^.Index := GetNextRowIndex; AppendRow(FRowAccessor.RowBuffer); { Posts non-cached updates. } if not FCachedUpdates then begin try PostUpdates; except on E: Exception do begin { Restore the previous state. } FRowAccessor.DisposeBuffer(FInitialRowsList[FInitialRowsList.Count - 1]); FInitialRowsList.Delete(FInitialRowsList.Count - 1); FRowAccessor.DisposeBuffer(FCurrentRowsList[FCurrentRowsList.Count - 1]); FCurrentRowsList.Delete(FCurrentRowsList.Count - 1); FRowAccessor.RowBuffer := TempRow; { Reraises the exception. } RaiseSQLException(E); end; end; end; FRowsList.Add(FRowAccessor.RowBuffer); LastRowNo := FRowsList.Count; MoveAbsolute(LastRowNo); end; {** Updates the underlying database with the new contents of the current row of this ResultSet object. This method cannot be called when the cursor is on the insert row. } procedure TZAbstractCachedResultSet.UpdateRow; begin CheckUpdatable; if (RowNo < 1) or (RowNo > LastRowNo) then raise EZSQLException.Create(SCanNotUpdateEmptyRow); if PZRowBuffer(FRowsList[RowNo - 1]).UpdateType = utDeleted then raise EZSQLException.Create(SCanNotUpdateDeletedRow); if FSelectedRow <> FUpdatedRow then Exit; AppendRow(FRowsList[RowNo - 1]); FSelectedRow := PZRowBuffer(FRowsList[RowNo - 1]); FRowAccessor.CopyBuffer(FUpdatedRow, FSelectedRow); FRowAccessor.RowBuffer := FSelectedRow; if FSelectedRow.UpdateType = utUnmodified then FSelectedRow.UpdateType := utModified; { Posts non-cached updates. } if not FCachedUpdates then begin try PostUpdates; except on E: Exception do begin { Restore the previous state. } FRowAccessor.DisposeBuffer(FRowsList[RowNo - 1]); FRowsList[RowNo - 1] := FInitialRowsList[FInitialRowsList.Count - 1]; FInitialRowsList.Delete(FInitialRowsList.Count - 1); FCurrentRowsList.Delete(FCurrentRowsList.Count - 1); FSelectedRow := PZRowBuffer(FRowsList[RowNo - 1]); FRowAccessor.RowBuffer := FSelectedRow; { Reraises the exception. } RaiseSQLException(E); end; end; end; end; {** Deletes the current row from this ResultSet object and from the underlying database. This method cannot be called when the cursor is on the insert row. } procedure TZAbstractCachedResultSet.DeleteRow; begin CheckUpdatable; if (RowNo < 1) or (RowNo > LastRowNo) or (FSelectedRow = nil) then raise EZSQLException.Create(SCanNotDeleteEmptyRow); if FSelectedRow^.UpdateType = utInserted then RevertRecord else begin AppendRow(FRowsList[RowNo - 1]); FSelectedRow^.UpdateType := utDeleted; if FSelectedRow = FUpdatedRow then FRowAccessor.CopyBuffer(FUpdatedRow, FRowsList[RowNo - 1]); { Posts non-cached updates. } if not FCachedUpdates then begin try PostUpdates; except on E: Exception do begin { Restores the previous state. } FRowAccessor.DisposeBuffer(FRowsList[RowNo - 1]); FRowsList[RowNo - 1] := FInitialRowsList[FInitialRowsList.Count - 1]; FSelectedRow := FRowsList[RowNo - 1]; FInitialRowsList.Delete(FInitialRowsList.Count - 1); FCurrentRowsList.Delete(FCurrentRowsList.Count - 1); { Rethrows the exception. } RaiseSQLException(E); end; end; end; end; end; {** Cancels the updates made to the current row in this ResultSet object. This method may be called after calling an updateXXX method(s) and before calling the method updateRow to roll back the updates made to a row. If no updates have been made or updateRow has already been called, this method has no effect. } procedure TZAbstractCachedResultSet.CancelRowUpdates; begin MoveAbsolute(RowNo); end; {** Moves the cursor to the insert row. The current cursor position is remembered while the cursor is positioned on the insert row. The insert row is a special row associated with an updatable result set. It is essentially a buffer where a new row may be constructed by calling the updateXXX methods prior to inserting the row into the result set. Only the updateXXX, getXXX, and insertRow methods may be called when the cursor is on the insert row. All of the columns in a result set must be given a value each time this method is called before calling insertRow. An updateXXX method must be called before a getXXX method can be called on a column value. } procedure TZAbstractCachedResultSet.MoveToInsertRow; begin CheckClosed; FRowAccessor.RowBuffer := FInsertedRow; end; {** Moves the cursor to the remembered cursor position, usually the current row. This method has no effect if the cursor is not on the insert row. } procedure TZAbstractCachedResultSet.MoveToCurrentRow; begin CheckClosed; if (RowNo >= 1) and (RowNo <= LastRowNo) then FRowAccessor.RowBuffer := FSelectedRow else FRowAccessor.RowBuffer := nil; end; {** Compares fields from two row buffers. @param Row1 the first row buffer to compare. @param Row2 the second row buffer to compare. @param ColumnIndices column indices to compare. @param ColumnDirs compare direction for each columns. } function TZAbstractCachedResultSet.CompareRows(Row1, Row2: Integer; const ColumnIndices: TIntegerDynArray; const ColumnDirs: TBooleanDynArray): Integer; var RowBuffer1, RowBuffer2: PZRowBuffer; begin {$IFNDEF DISABLE_CHECKING} if ResultSetType = rtForwardOnly then RaiseForwardOnlyException; {$ENDIF} RowBuffer1 := PZRowBuffer(FRowsList[Row1 - 1]); RowBuffer2 := PZRowBuffer(FRowsList[Row2 - 1]); Result := FRowAccessor.CompareBuffers(RowBuffer1, RowBuffer2, ColumnIndices, ColumnDirs); end; { TZCachedResultSet } {** Creates this object and assignes the main properties. @param ResultSet a wrapped resultset object. @param Resolver a cached updates resolver object. } constructor TZCachedResultSet.Create(ResultSet: IZResultSet; SQL: string; Resolver: IZCachedResolver; ConSettings: PZConSettings); begin inherited Create(ResultSet.GetStatement, SQL, nil, ConSettings); FResultSet := ResultSet; FResolver := Resolver; {BEGIN PATCH [1214009] CalcDefaults in TZUpdateSQL and Added Methods to GET the DB NativeResolver} FNativeResolver := Resolver; {END PATCH [1214009] CalcDefaults in TZUpdateSQL and Added Methods to GET the DB NativeResolver} Open; end; {** Destroys this object and cleanups the memory. } destructor TZCachedResultSet.Destroy; begin inherited Destroy; end; {** Fetches one row from the wrapped result set object. @return True if row was successfuly fetched or False otherwise. } function TZCachedResultSet.Fetch: Boolean; var I: Integer; TempRow: PZRowBuffer; begin Result := FResultSet.Next; if not Result or ((MaxRows > 0) and (LastRowNo >= MaxRows)) then Exit; TempRow := RowAccessor.RowBuffer; try RowAccessor.Alloc; RowAccessor.RowBuffer.Index := GetNextRowIndex; RowAccessor.RowBuffer.UpdateType := utUnmodified; for I := 1 to ColumnsInfo.Count do begin case TZColumnInfo(ColumnsInfo[I - 1]).ColumnType of stBoolean: RowAccessor.SetBoolean(I, ResultSet.GetBoolean(I)); stByte: RowAccessor.SetByte(I, ResultSet.GetByte(I)); stShort: RowAccessor.SetShort(I, ResultSet.GetShort(I)); stInteger: RowAccessor.SetInt(I, ResultSet.GetInt(I)); stLong: RowAccessor.SetLong(I, ResultSet.GetLong(I)); stFloat: RowAccessor.SetFloat(I, ResultSet.GetFloat(I)); stDouble: RowAccessor.SetDouble(I, ResultSet.GetDouble(I)); stBigDecimal: RowAccessor.SetBigDecimal(I, ResultSet.GetBigDecimal(I)); stString: RowAccessor.SetString(I, ResultSet.GetString(I)); stUnicodeString: RowAccessor.SetUnicodeString(I, ResultSet.GetUnicodeString(I)); stBytes,stGUID: RowAccessor.SetBytes(I, ResultSet.GetBytes(I)); stDate: RowAccessor.SetDate(I, ResultSet.GetDate(I)); stTime: RowAccessor.SetTime(I, ResultSet.GetTime(I)); stTimestamp: RowAccessor.SetTimestamp(I, ResultSet.GetTimestamp(I)); stAsciiStream, stBinaryStream, stUnicodeStream: RowAccessor.SetBlob(I, ResultSet.GetBlob(I)); stDataSet: RowAccessor.SetDataSet(i, ResultSet.GetDataSet(I)); end; if ResultSet.WasNull then RowAccessor.SetNull(I); end; RowsList.Add(RowAccessor.RowBuffer); LastRowNo := RowsList.Count; finally RowAccessor.RowBuffer := TempRow; end; end; {** Fetches all of the rest rows from the wrapped result set. } procedure TZCachedResultSet.FetchAll; begin while Fetch do; end; {** Opens this recordset. } procedure TZCachedResultSet.Open; var I: Integer; ColumnInfo: TZColumnInfo; MetaData : IZResultSetMetaData; begin ColumnsInfo.Clear; MetaData := FResultSet.GetMetadata; for I := 1 to Metadata.GetColumnCount do begin ColumnInfo := TZColumnInfo.Create; with ColumnInfo do begin Currency := Metadata.IsCurrency(I); Signed := Metadata.IsSigned(I); ColumnDisplaySize := Metadata.GetColumnDisplaySize(I); ColumnLabel := Metadata.GetColumnLabel(I); Precision := Metadata.GetPrecision(I); Scale := Metadata.GetScale(I); ColumnType := Metadata.GetColumnType(I); end; ColumnsInfo.Add(ColumnInfo); end; inherited Open; end; {** Releases this ResultSet object's database and JDBC resources immediately instead of waiting for this to happen when it is automatically closed.

Note: A ResultSet object is automatically closed by the Statement object that generated it when that Statement object is closed, re-executed, or is used to retrieve the next result from a sequence of multiple results. A ResultSet object is also automatically closed when it is garbage collected. } procedure TZCachedResultSet.Close; begin inherited Close; ColumnsInfo.Clear; If Assigned(FResultset) then FResultset.Close; FResultSet := nil; end; {** Retrieves the number, types and properties of this ResultSet object's columns. @return the description of this ResultSet object's columns } function TZCachedResultSet.GetMetadata: IZResultSetMetadata; begin Result := ResultSet.GetMetadata; end; {** Indicates whether the cursor is after the last row in this ResultSet object. @return true if the cursor is after the last row; false if the cursor is at any other position or the result set contains no rows } function TZCachedResultSet.IsAfterLast: Boolean; begin FetchAll; Result := inherited IsAfterLast; end; {** Moves the cursor to the end of this ResultSet object, just after the last row. This method has no effect if the result set contains no rows. } procedure TZCachedResultSet.AfterLast; begin FetchAll; inherited AfterLast; end; {** Indicates whether the cursor is on the last row of this ResultSet object. Note: Calling the method isLast may be expensive because the JDBC driver might need to fetch ahead one row in order to determine whether the current row is the last row in the result set. @return true if the cursor is on the last row; false otherwise } function TZCachedResultSet.IsLast: Boolean; begin FetchAll; Result := inherited IsLast; end; {** Moves the cursor to the last row in this ResultSet object. @return true if the cursor is on a valid row; false if there are no rows in the result set } function TZCachedResultSet.Last: Boolean; begin FetchAll; Result := inherited Last; end; {** Moves the cursor to the given row number in this ResultSet object.

If the row number is positive, the cursor moves to the given row number with respect to the beginning of the result set. The first row is row 1, the second is row 2, and so on.

If the given row number is negative, the cursor moves to an absolute row position with respect to the end of the result set. For example, calling the method absolute(-1) positions the cursor on the last row; calling the method absolute(-2) moves the cursor to the next-to-last row, and so on.

An attempt to position the cursor beyond the first/last row in the result set leaves the cursor before the first row or after the last row.

Note: Calling absolute(1) is the same as calling first(). Calling absolute(-1) is the same as calling last(). @return true if the cursor is on the result set; false otherwise } function TZCachedResultSet.MoveAbsolute(Row: Integer): Boolean; begin { Checks for maximum row. } Result := False; if (MaxRows > 0) and (Row > MaxRows) then Exit; { Processes negative rows } if Row < 0 then begin FetchAll; Row := LastRowNo - Row + 1; if Row < 0 then Row := 0; end else { Processes moving after last row } while (LastRowNo < Row) and Fetch do; Result := inherited MoveAbsolute(Row); end; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcConnection.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Abstract Database Connectivity Classes } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcConnection; interface {$I ZDbc.inc} uses {$IFDEF FPC} {$IFDEF WIN32} Comobj, {$ENDIF} {$ENDIF} {$IFDEF WITH_LCONVENCODING} LConvEncoding, {$ENDIF} Types, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, ZClasses, ZDbcIntfs, ZTokenizer, ZCompatibility, ZGenericSqlToken, ZGenericSqlAnalyser, ZPlainDriver, ZURL, ZCollections, ZVariant; type {** Implements Abstract Database Driver. } {$WARNINGS OFF} //to supress the deprecated Warning of connect TZAbstractDriver = class(TInterfacedObject, IZDriver) private FTokenizer: IZTokenizer; FAnalyser: IZStatementAnalyser; protected FCachedPlainDrivers: IZHashMap; FSupportedProtocols: TStringDynArray; procedure AddSupportedProtocol(AProtocol: String); function AddPlainDriverToCache(PlainDriver: IZPlainDriver; const Protocol: string = ''; LibLocation: string = ''): String; function GetPlainDriverFromCache(const Protocol, LibLocation: string): IZPlainDriver; function GetPlainDriver(const Url: TZURL; const InitDriver: Boolean = True): IZPlainDriver; virtual; property Tokenizer: IZTokenizer read FTokenizer write FTokenizer; property Analyser: IZStatementAnalyser read FAnalyser write FAnalyser; public constructor Create; virtual; destructor Destroy; override; function GetSupportedProtocols: TStringDynArray; function GetSupportedClientCodePages(const Url: TZURL; Const {$IFNDEF UNICODE}AutoEncode, {$ENDIF} SupportedsOnly: Boolean; CtrlsCPType: TZControlsCodePage = cCP_UTF16): TStringDynArray; function Connect(const Url: string; Info: TStrings = nil): IZConnection; overload; deprecated; function Connect(const Url: TZURL): IZConnection; overload; virtual; function AcceptsURL(const Url: string): Boolean; virtual; function GetPropertyInfo(const Url: string; Info: TStrings): TStrings; virtual; function GetMajorVersion: Integer; virtual; function GetMinorVersion: Integer; virtual; function GetSubVersion: Integer; virtual; function GetTokenizer: IZTokenizer; virtual; function GetStatementAnalyser: IZStatementAnalyser; virtual; function GetClientVersion(const Url: string): Integer; virtual; end; {$WARNINGS OFF} {** Implements Abstract Database Connection. } { TZAbstractConnection } TZAbstractConnection = class(TZCodePagedObject, IZConnection) private FDriver: IZDriver; FIZPlainDriver: IZPlainDriver; FAutoCommit: Boolean; FReadOnly: Boolean; FTransactIsolationLevel: TZTransactIsolationLevel; FClosed: Boolean; FURL: TZURL; FUseMetadata: Boolean; function GetHostName: string; procedure SetHostName(const Value: String); function GetPort: Integer; procedure SetConnPort(const Value: Integer); function GetDatabase: string; procedure SetDatabase(const Value: String); function GetUser: string; procedure SetUser(const Value: String); function GetPassword: string; procedure SetPassword(const Value: String); function GetInfo: TStrings; protected FDisposeCodePage: Boolean; FUndefinedVarcharAsStringLength: Integer; //used for PostgreSQL and SQLite FClientCodePage: String; FMetadata: TContainedObject; {$IFDEF ZEOS_TEST_ONLY} FTestMode: Byte; {$ENDIF} procedure InternalCreate; virtual; abstract; function GetEncoding: TZCharEncoding; function GetConSettings: PZConSettings; procedure CheckCharEncoding(const CharSet: String; const DoArrange: Boolean = False); function GetClientCodePageInformations: PZCodePage; //EgonHugeist function GetAutoEncodeStrings: Boolean; //EgonHugeist procedure SetAutoEncodeStrings(const Value: Boolean); procedure OnPropertiesChange(Sender: TObject); virtual; procedure RaiseUnsupportedException; function CreateRegularStatement(Info: TStrings): IZStatement; virtual; function CreatePreparedStatement(const SQL: string; Info: TStrings): IZPreparedStatement; virtual; function CreateCallableStatement(const SQL: string; Info: TStrings): IZCallableStatement; virtual; property Driver: IZDriver read FDriver write FDriver; property PlainDriver: IZPlainDriver read FIZPlainDriver write FIZPlainDriver; property HostName: string read GetHostName write SetHostName; property Port: Integer read GetPort write SetConnPort; property Database: string read GetDatabase write SetDatabase; property User: string read GetUser write SetUser; property Password: string read GetPassword write SetPassword; property Info: TStrings read GetInfo; property AutoCommit: Boolean read FAutoCommit write FAutoCommit; property ReadOnly: Boolean read FReadOnly write FReadOnly; property URL: TZURL read FURL; property TransactIsolationLevel: TZTransactIsolationLevel read FTransactIsolationLevel write FTransactIsolationLevel; property Closed: Boolean read FClosed write FClosed; public constructor Create(Driver: IZDriver; const Url: string; PlainDriver: IZPlainDriver; const HostName: string; Port: Integer; const Database: string; const User: string; const Password: string; Info: TStrings); overload; deprecated; constructor Create(const ZUrl: TZURL); overload; destructor Destroy; override; function CreateStatement: IZStatement; function PrepareStatement(const SQL: string): IZPreparedStatement; function PrepareCall(const SQL: string): IZCallableStatement; function CreateStatementWithParams(Info: TStrings): IZStatement; function PrepareStatementWithParams(const SQL: string; Info: TStrings): IZPreparedStatement; function PrepareCallWithParams(const SQL: string; Info: TStrings): IZCallableStatement; function CreateNotification(const Event: string): IZNotification; virtual; function CreateSequence(const Sequence: string; BlockSize: Integer): IZSequence; virtual; function NativeSQL(const SQL: string): string; virtual; procedure SetAutoCommit(AutoCommit: Boolean); virtual; function GetAutoCommit: Boolean; virtual; procedure Commit; virtual; procedure Rollback; virtual; //2Phase Commit Support initially for PostgresSQL (firmos) 21022006 procedure PrepareTransaction(const transactionid: string);virtual; procedure CommitPrepared(const transactionid: string);virtual; procedure RollbackPrepared(const transactionid: string);virtual; //Ping Support initially for MySQL 27032006 (firmos) function PingServer: Integer; virtual; function EscapeString(Value: RawByteString): RawByteString; virtual; procedure Open; virtual; procedure Close; virtual; function IsClosed: Boolean; virtual; function GetDriver: IZDriver; function GetIZPlainDriver: IZPlainDriver; function GetMetadata: IZDatabaseMetadata; function GetParameters: TStrings; {ADDED by fduenas 15-06-2006} function GetClientVersion: Integer; virtual; function GetHostVersion: Integer; virtual; {END ADDED by fduenas 15-06-2006} function GetDescription: AnsiString; procedure SetReadOnly(ReadOnly: Boolean); virtual; function IsReadOnly: Boolean; virtual; procedure SetCatalog(const Catalog: string); virtual; function GetCatalog: string; virtual; procedure SetTransactionIsolation(Level: TZTransactIsolationLevel); virtual; function GetTransactionIsolation: TZTransactIsolationLevel; virtual; function GetWarnings: EZSQLWarning; virtual; procedure ClearWarnings; virtual; function GetBinaryEscapeString(const Value: RawByteString): String; overload; virtual; function GetBinaryEscapeString(const Value: TByteDynArray): String; overload; virtual; function GetEscapeString(const Value: ZWideString): ZWideString; overload; virtual; function GetEscapeString(const Value: RawByteString): RawByteString; overload; virtual; function UseMetadata: boolean; procedure SetUseMetadata(Value: Boolean); {$IFDEF ZEOS_TEST_ONLY} function GetTestMode : Byte; procedure SetTestMode(Mode: Byte); {$ENDIF} end; {** Implements Abstract Database notification. } TZAbstractNotification = class(TInterfacedObject, IZNotification) private FEventName: string; FConnection: IZConnection; protected property EventName: string read FEventName write FEventName; property Connection: IZConnection read FConnection write FConnection; public constructor Create(Connection: IZConnection; EventName: string); function GetEvent: string; procedure Listen; virtual; procedure Unlisten; virtual; procedure DoNotify; virtual; function CheckEvents: string; virtual; function GetConnection: IZConnection; virtual; end; {** Implements Abstract Sequence generator. } TZAbstractSequence = class(TInterfacedObject, IZSequence) private FName: string; FBlockSize: Integer; FConnection: IZConnection; protected function GetName: string; virtual; function GetBlockSize: Integer; virtual; procedure SetName(const Value: string); virtual; procedure SetBlockSize(const Value: Integer); virtual; property Connection: IZConnection read FConnection write FConnection; public constructor Create(Connection: IZConnection; Name: string; BlockSize: Integer); function GetCurrentValue: Int64; virtual; function GetNextValue: Int64; virtual; function GetCurrentValueSQL: string; virtual; abstract; function GetNextValueSQL: string; virtual; abstract; function GetConnection: IZConnection; virtual; property Name: string read GetName write SetName; property BlockSize: Integer read GetBlockSize write SetBlockSize; end; implementation uses ZMessages, ZSysUtils, ZDbcMetadata, ZDbcUtils, ZEncoding {$IFDEF WITH_UNITANSISTRINGS},AnsiStrings{$ENDIF}; { TZAbstractDriver } {** Constructs this object with default properties. } constructor TZAbstractDriver.Create; begin FCachedPlainDrivers := TZHashMap.Create; end; {** Destroys this object and cleanups the memory. } destructor TZAbstractDriver.Destroy; begin FTokenizer := nil; FAnalyser := nil; FCachedPlainDrivers.Clear; FCachedPlainDrivers := nil; inherited Destroy; end; function TZAbstractDriver.GetSupportedProtocols: TStringDynArray; begin Result := FSupportedProtocols; end; {** EgonHugeist: Get names of the supported CharacterSets. For example: ASCII, UTF8... } function TZAbstractDriver.GetSupportedClientCodePages(const Url: TZURL; Const {$IFNDEF UNICODE}AutoEncode,{$ENDIF} SupportedsOnly: Boolean; CtrlsCPType: TZControlsCodePage = cCP_UTF16): TStringDynArray; var Plain: IZPlainDriver; begin Plain := GetPlainDriverFromCache(Url.Protocol, ''); if Assigned(Plain) then Result := Plain.GetSupportedClientCodePages({$IFNDEF UNICODE}AutoEncode,{$ENDIF} not SupportedsOnly, CtrlsCPType); end; {** Attempts to make a database connection to the given URL. The driver should return "null" if it realizes it is the wrong kind of driver to connect to the given URL. This will be common, as when the JDBC driver manager is asked to connect to a given URL it passes the URL to each loaded driver in turn.

The driver should raise a SQLException if it is the right driver to connect to the given URL, but has trouble connecting to the database.

The java.util.Properties argument can be used to passed arbitrary string tag/value pairs as connection arguments. Normally at least "user" and "password" properties should be included in the Properties. @param url the URL of the database to which to connect @param info a list of arbitrary string tag/value pairs as connection arguments. Normally at least a "user" and "password" property should be included. @return a Connection object that represents a connection to the URL } {$WARNINGS OFF} function TZAbstractDriver.Connect(const Url: string; Info: TStrings): IZConnection; var TempURL: TZURL; begin TempURL := TZURL.Create(Url, Info); try Result := Connect(TempURL); finally TempUrl.Free; end; end; function TZAbstractDriver.Connect(const Url: TZURL): IZConnection; begin Result := nil; end; {$WARNINGS ON} {** Returns true if the driver thinks that it can open a connection to the given URL. Typically drivers will return true if they understand the subprotocol specified in the URL and false if they don't. @param url the URL of the database @return true if this driver can connect to the given URL } function TZAbstractDriver.AcceptsURL(const Url: string): Boolean; var I: Integer; Protocols: TStringDynArray; begin Result := False; Protocols := GetSupportedProtocols; for I := Low(Protocols) to High(Protocols) do begin Result := StartsWith(LowerCase(Url), Format('zdbc:%s:', [LowerCase(Protocols[I])])); if Result then Break; end; end; procedure TZAbstractDriver.AddSupportedProtocol(AProtocol: String); begin SetLength(FSupportedProtocols, Length(FSupportedProtocols)+1); FSupportedProtocols[High(FSupportedProtocols)] := AProtocol; end; function TZAbstractDriver.AddPlainDriverToCache(PlainDriver: IZPlainDriver; const Protocol: string = ''; LibLocation: string = ''): String; var TempKey: IZAnyValue; begin if Protocol = '' then begin Result := PlainDriver.GetProtocol; TempKey := TZAnyValue.CreateWithString(PlainDriver.GetProtocol) end else begin Result := Protocol; TempKey := TZAnyValue.CreateWithString(Protocol+LibLocation); end; FCachedPlainDrivers.Put(TempKey, PlainDriver); end; function TZAbstractDriver.GetPlainDriverFromCache(const Protocol, LibLocation: string): IZPlainDriver; var TempKey: IZAnyValue; TempPlain: IZPlainDriver; begin TempKey := TZAnyValue.CreateWithString(Protocol+LibLocation); Result := FCachedPlainDrivers.Get(TempKey) as IZPlainDriver; if Result = nil then begin TempKey := nil; TempKey := TZAnyValue.CreateWithString(Protocol); TempPlain := FCachedPlainDrivers.Get(TempKey) as IZPlainDriver; if Assigned(TempPlain) then Result := TempPlain.Clone; end; end; {** Gets plain driver for selected protocol. @param Url a database connection URL. @return a selected plaindriver. } function TZAbstractDriver.GetPlainDriver(const Url: TZURL; const InitDriver: Boolean): IZPlainDriver; begin Result := GetPlainDriverFromCache(Url.Protocol, Url.LibLocation); if Assigned(Result) and InitDriver then Result.Initialize(Url.LibLocation); end; {** Gets information about the possible properties for this driver.

The getPropertyInfo method is intended to allow a generic GUI tool to discover what properties it should prompt a human for in order to get enough information to connect to a database. Note that depending on the values the human has supplied so far, additional values may become necessary, so it may be necessary to iterate though several calls to getPropertyInfo. @param url the URL of the database to which to connect @param info a proposed list of tag/value pairs that will be sent on connect open @return an array of DriverPropertyInfo objects describing possible properties. This array may be an empty array if no properties are required. } function TZAbstractDriver.GetPropertyInfo(const Url: string; Info: TStrings): TStrings; begin Result := nil; end; {** Gets the driver's major version number. Initially this should be 1. @return this driver's major version number } function TZAbstractDriver.GetMajorVersion: Integer; begin Result := 1; end; {** Gets the driver's minor version number. Initially this should be 0. @return this driver's minor version number } function TZAbstractDriver.GetMinorVersion: Integer; begin Result := 0; end; {** Gets the driver's sub version (revision) number. Initially this should be 0. @return this driver's sub version number } function TZAbstractDriver.GetSubVersion: Integer; begin Result := 0; end; {** Creates a generic statement analyser object. @returns a generic statement analyser object. } function TZAbstractDriver.GetStatementAnalyser: IZStatementAnalyser; begin if Analyser = nil then Analyser := TZGenericStatementAnalyser.Create; Result := Analyser; end; {** Creates a generic tokenizer object. @returns a created generic tokenizer object. } function TZAbstractDriver.GetTokenizer: IZTokenizer; begin if Tokenizer = nil then Tokenizer := TZGenericSQLTokenizer.Create; Result := Tokenizer; end; {** Returns the version of the plain driver library that will be used to open a connection to the given URL. @param url the URL of the database @return the version number of the plain driver library for the give URL } function TZAbstractDriver.GetClientVersion(const Url: string): Integer; begin Result := 0; end; { TZAbstractConnection } function TZAbstractConnection.GetHostName: string; begin Result := FURL.HostName; end; procedure TZAbstractConnection.SetHostName(const Value: String); begin FURL.HostName := Value; end; function TZAbstractConnection.GetPort: Integer; begin Result := FURL.Port; end; procedure TZAbstractConnection.SetConnPort(const Value: Integer); begin FURL.Port := Value; end; function TZAbstractConnection.GetDatabase: string; begin Result := FURL.Database; end; procedure TZAbstractConnection.SetDatabase(const Value: String); begin FURL.Database := Value; end; function TZAbstractConnection.GetUser: string; begin Result := FURL.UserName; end; procedure TZAbstractConnection.SetUser(const Value: String); begin FURL.UserName := Value; end; function TZAbstractConnection.GetPassword: string; begin Result := FURL.Password; end; procedure TZAbstractConnection.SetPassword(const Value: String); begin FURL.Password := Value; end; function TZAbstractConnection.GetInfo: TStrings; begin Result := FURL.Properties; end; function TZAbstractConnection.GetEncoding: TZCharEncoding; begin Result := ConSettings.ClientCodePage^.Encoding; end; function TZAbstractConnection.GetConSettings: PZConSettings; begin Result := ConSettings; end; {** EgonHugeist: Check if the given Charset for Compiler/Database-Support!! Not supported means if there is a pissible String-DataLoss. So it raises an Exception if case of settings. This handling is an improofment to inform Zeos-Users about the troubles the given CharacterSet may have. @param CharSet the CharacterSet which has to be proofed @param DoArrange represents a switch to check and set a aternative ZAlias as default. This means it ignores the choosen Client-CharacterSet and sets a "more" Zeos-Compatible Client-CharacterSet if known. } procedure TZAbstractConnection.CheckCharEncoding(const CharSet: String; const DoArrange: Boolean = False); begin ConSettings.ClientCodePage := GetIZPlainDriver.ValidateCharEncoding(CharSet, DoArrange); FClientCodePage := ConSettings.ClientCodePage^.Name; //resets the developer choosen ClientCodePage {$IFDEF WITH_LCONVENCODING} SetConvertFunctions(ConSettings.CTRL_CP, ConSettings.ClientCodePage.CP, ConSettings.PlainConvertFunc, ConSettings.DbcConvertFunc); {$ENDIF} ZEncoding.SetConvertFunctions(ConSettings); end; {** EgonHugeist: this is a compatibility-Option for exiting Applictions. Zeos is now able to preprepare direct insered SQL-Statements. Means do the UTF8-preparation if the CharacterSet was choosen. So we do not need to do the SQLString + UTF8Encode(Edit1.Test) for example. @result True if coPreprepareSQL was choosen in the TZAbstractConnection } function TZAbstractConnection.GetAutoEncodeStrings: Boolean; begin {$IFDEF UNICODE} Result := True; {$ELSE} Result := ConSettings.AutoEncode; {$ENDIF} end; procedure TZAbstractConnection.SetAutoEncodeStrings(const Value: Boolean); begin {$IFNDEF UNICODE} ConSettings.AutoEncode := Value; {$ENDIF} end; {** EgonHugeist and MDeams: The old deprecadet constructor which was used from the descendant classes. We left him here for compatibility reasons to exesting projects which using the DbcConnections directly Constructs this object and assignes the main properties. @param Driver the parent ZDBC driver. @param Url a connection URL. @param PlainDriver a versioned ZPlainDriver object interface. @param HostName a name of the host. @param Port a port number (0 for default port). @param Database a name pof the database. @param User a user name. @param Password a user password. @param Info a string list with extra connection parameters. } {$WARNINGS OFF} //suppress the deprecatad warning of calling create from internal constructor TZAbstractConnection.Create(Driver: IZDriver; const Url: string; PlainDriver: IZPlainDriver; const HostName: string; Port: Integer; const Database: string; const User: string; const Password: string; Info: TStrings); var TempURL: TZURL; begin TempURL := TZURL.Create(Url, HostName, Port, Database, User, Password, Info); Create(TempURL); TempURL.Free; end; {$WARNINGS OFF} {** Constructs this object and assignes the main properties. @param Url a connection ZURL-class which exports all connection parameters. } constructor TZAbstractConnection.Create(const ZUrl: TZURL); begin FClosed := True; if not assigned(ZUrl) then raise Exception.Create('ZUrl is not assigned!') else FURL := TZURL.Create(); FDriver := DriverManager.GetDriver(ZURL.URL); FIZPlainDriver := FDriver.GetPlainDriver(ZUrl); FURL.OnPropertiesChange := OnPropertiesChange; FURL.URL := ZUrl.URL; FClientCodePage := Info.Values['codepage']; {CheckCharEncoding} ConSettings := New(PZConSettings); SetConSettingsFromInfo(Info); CheckCharEncoding(FClientCodePage, True); FAutoCommit := True; FReadOnly := True; FTransactIsolationLevel := tiNone; FUseMetadata := True; InternalCreate; {$IFDEF ZEOS_TEST_ONLY} FTestMode := 0; {$ENDIF} end; {** Destroys this object and cleanups the memory. } destructor TZAbstractConnection.Destroy; begin if not FClosed then Close; FreeAndNil(FMetadata); FURL.Free; FIZPlainDriver := nil; FDriver := nil; if Assigned(ConSettings) then Dispose(ConSettings); inherited Destroy; end; {** Opens a connection to database server with specified parameters. } procedure TZAbstractConnection.Open; begin FClosed := False; end; {** Raises unsupported operation exception. } procedure TZAbstractConnection.RaiseUnsupportedException; begin raise EZSQLException.Create(SUnsupportedOperation); end; {** Creates a Statement object for sending SQL statements to the database. SQL statements without parameters are normally executed using Statement objects. If the same SQL statement is executed many times, it is more efficient to use a PreparedStatement object.

Result sets created using the returned Statement object will by default have forward-only type and read-only concurrency. @return a new Statement object } function TZAbstractConnection.CreateStatement: IZStatement; begin Result := CreateStatementWithParams(nil); end; {** Creates a Statement object for sending SQL statements to the database. SQL statements without parameters are normally executed using Statement objects. If the same SQL statement is executed many times, it is more efficient to use a PreparedStatement object.

Result sets created using the returned Statement object will by default have forward-only type and read-only concurrency. @param Info a statement parameters. @return a new Statement object } function TZAbstractConnection.CreateStatementWithParams(Info: TStrings): IZStatement; var UsedInfo: TStrings; begin UsedInfo := Info; If StrToBoolEx(GetInfo.Values['preferprepared']) then begin If UsedInfo = nil then UsedInfo := TSTringList.Create; UsedInfo.Append('preferprepared=TRUE'); end; Result := CreateRegularStatement(UsedInfo); if UsedInfo <> Info then UsedInfo.Free; end; {** Creates a regular statement object. @param SQL a SQL query string. @param Info a statement parameters. @returns a created statement. } function TZAbstractConnection.CreateRegularStatement( Info: TStrings): IZStatement; begin Result := nil; RaiseUnsupportedException; end; {** Creates a PreparedStatement object for sending parameterized SQL statements to the database. A SQL statement with or without IN parameters can be pre-compiled and stored in a PreparedStatement object. This object can then be used to efficiently execute this statement multiple times.

Note: This method is optimized for handling parametric SQL statements that benefit from precompilation. If the driver supports precompilation, the method prepareStatement will send the statement to the database for precompilation. Some drivers may not support precompilation. In this case, the statement may not be sent to the database until the PreparedStatement is executed. This has no direct effect on users; however, it does affect which method throws certain SQLExceptions. Result sets created using the returned PreparedStatement will have forward-only type and read-only concurrency, by default. @param sql a SQL statement that may contain one or more '?' IN parameter placeholders @return a new PreparedStatement object containing the pre-compiled statement } function TZAbstractConnection.PrepareStatement(const SQL: string): IZPreparedStatement; begin Result := CreatePreparedStatement(SQL, nil); end; {** Creates a PreparedStatement object for sending parameterized SQL statements to the database. @param SQL a SQL statement that may contain one or more '?' IN parameter placeholders @param Info a statement parameters. @return a new PreparedStatement object containing the pre-compiled statement } function TZAbstractConnection.PrepareStatementWithParams(const SQL: string; Info: TStrings): IZPreparedStatement; var UsedInfo: TStrings; begin UsedInfo := Info; If StrToBoolEx(GetInfo.Values['preferprepared']) then begin If UsedInfo = nil then UsedInfo := TSTringList.Create; UsedInfo.Append('preferprepared=TRUE'); end; Result := CreatePreparedStatement(SQL, UsedInfo); if UsedInfo <> Info then UsedInfo.Free; end; procedure TZAbstractConnection.PrepareTransaction(const transactionid: string); begin RaiseUnsupportedException; end; {** Creates a prepared statement object. @param SQL a SQL query string. @param Info a statement parameters. @returns a created statement. } function TZAbstractConnection.CreatePreparedStatement(const SQL: string; Info: TStrings): IZPreparedStatement; begin Result := nil; RaiseUnsupportedException; end; {** Creates a CallableStatement object for calling database stored procedures. The CallableStatement object provides methods for setting up its IN and OUT parameters, and methods for executing the call to a stored procedure.

Note: This method is optimized for handling stored procedure call statements. Some drivers may send the call statement to the database when the method prepareCall is done; others may wait until the CallableStatement object is executed. This has no direct effect on users; however, it does affect which method throws certain SQLExceptions. Result sets created using the returned CallableStatement will have forward-only type and read-only concurrency, by default. @param sql a SQL statement that may contain one or more '?' parameter placeholders. Typically this statement is a JDBC function call escape string. @return a new CallableStatement object containing the pre-compiled SQL statement } function TZAbstractConnection.PrepareCall( const SQL: string): IZCallableStatement; begin Result := CreateCallableStatement(SQL, nil); end; {** Creates a CallableStatement object for calling database stored procedures. The CallableStatement object provides methods for setting up its IN and OUT parameters, and methods for executing the call to a stored procedure. @param SQL a SQL statement that may contain one or more '?' parameter placeholders. Typically this statement is a JDBC function call escape string. @param Info a statement parameters. @return a new CallableStatement object containing the pre-compiled SQL statement } function TZAbstractConnection.PrepareCallWithParams(const SQL: string; Info: TStrings): IZCallableStatement; var UsedInfo: TStrings; begin UsedInfo := Info; If StrToBoolEx(GetInfo.Values['preferprepared']) then begin If UsedInfo = nil then UsedInfo := TSTringList.Create; UsedInfo.Append('preferprepared=TRUE'); end; Result := CreateCallableStatement(SQL, UsedInfo); if UsedInfo <> Info then UsedInfo.Free; end; {** Creates a callable statement object. @param SQL a SQL query string. @param Info a statement parameters. @returns a created statement. } function TZAbstractConnection.CreateCallableStatement(const SQL: string; Info: TStrings): IZCallableStatement; begin Result := nil; RaiseUnsupportedException; end; {** Creates an object to send/recieve notifications from SQL server. @param Event an event name. @returns a created notification object. } function TZAbstractConnection.CreateNotification(const Event: string): IZNotification; begin Result := nil; RaiseUnsupportedException; end; {** Creates a sequence generator object. @param Sequence a name of the sequence generator. @param BlockSize a number of unique keys requested in one trip to SQL server. @returns a created sequence object. } function TZAbstractConnection.CreateSequence(const Sequence: string; BlockSize: Integer): IZSequence; begin Result := nil; RaiseUnsupportedException; end; {** Converts the given SQL statement into the system's native SQL grammar. A driver may convert the JDBC sql grammar into its system's native SQL grammar prior to sending it; this method returns the native form of the statement that the driver would have sent. @param sql a SQL statement that may contain one or more '?' parameter placeholders @return the native form of this statement } function TZAbstractConnection.NativeSQL(const SQL: string): string; begin Result := SQL; end; {** Sets this connection's auto-commit mode. If a connection is in auto-commit mode, then all its SQL statements will be executed and committed as individual transactions. Otherwise, its SQL statements are grouped into transactions that are terminated by a call to either the method commit or the method rollback. By default, new connections are in auto-commit mode. The commit occurs when the statement completes or the next execute occurs, whichever comes first. In the case of statements returning a ResultSet, the statement completes when the last row of the ResultSet has been retrieved or the ResultSet has been closed. In advanced cases, a single statement may return multiple results as well as output parameter values. In these cases the commit occurs when all results and output parameter values have been retrieved. @param autoCommit true enables auto-commit; false disables auto-commit. } procedure TZAbstractConnection.SetAutoCommit(AutoCommit: Boolean); begin FAutoCommit := AutoCommit; end; {** Gets the current auto-commit state. @return the current state of auto-commit mode @see #setAutoCommit } function TZAbstractConnection.GetAutoCommit: Boolean; begin Result := FAutoCommit; end; {** Makes all changes made since the previous commit/rollback permanent and releases any database locks currently held by the Connection. This method should be used only when auto-commit mode has been disabled. @see #setAutoCommit } procedure TZAbstractConnection.Commit; begin RaiseUnsupportedException; end; procedure TZAbstractConnection.CommitPrepared(const transactionid: string); begin RaiseUnsupportedException; end; {** Drops all changes made since the previous commit/rollback and releases any database locks currently held by this Connection. This method should be used only when auto- commit has been disabled. @see #setAutoCommit } procedure TZAbstractConnection.Rollback; begin RaiseUnsupportedException; end; procedure TZAbstractConnection.RollbackPrepared(const transactionid: string); begin RaiseUnsupportedException; end; {** Ping Current Connection's server, if client was disconnected, the connection is resumed. @return 0 if succesfull or error code if any error occurs } function TZAbstractConnection.PingServer: Integer; begin Result := 1; RaiseUnsupportedException; end; {** Escape a string so it's acceptable for the Connection's server. @param value string that should be escaped @return Escaped string } function TZAbstractConnection.EscapeString(Value : RawByteString) : RawByteString; begin Result := AnsiString(EncodeCString(String(Value))); end; {** Releases a Connection's database and JDBC resources immediately instead of waiting for them to be automatically released.

Note: A Connection is automatically closed when it is garbage collected. Certain fatal errors also result in a closed Connection. } procedure TZAbstractConnection.Close; begin if FDisposeCodePage then begin Dispose(ConSettings^.ClientCodePage); ConSettings^.ClientCodePage := nil; FDisposeCodePage := False; end; FClosed := True; end; {** Tests to see if a Connection is closed. @return true if the connection is closed; false if it's still open } function TZAbstractConnection.IsClosed: Boolean; begin Result := FClosed; end; {** Gets the parent ZDBC driver. @returns the parent ZDBC driver interface. } function TZAbstractConnection.GetDriver: IZDriver; begin Result := FDriver; end; {** Gets the plain driver. @returns the plain driver interface. } function TZAbstractConnection.GetIZPlainDriver: IZPlainDriver; begin result := FIZPlainDriver; end; {** Gets the metadata regarding this connection's database. A Connection's database is able to provide information describing its tables, its supported SQL grammar, its stored procedures, the capabilities of this connection, and so on. This information is made available through a DatabaseMetaData object. @return a DatabaseMetaData object for this Connection } function TZAbstractConnection.GetMetadata: IZDatabaseMetadata; begin Result := FMetadata as IZDatabaseMetadata; end; {** Gets a connection parameters. @returns a list with connection parameters. } function TZAbstractConnection.GetParameters: TStrings; begin Result := Info; end; {** Gets the client's full version number. Initially this should be 0. The format of the version resturned must be XYYYZZZ where X = Major version YYY = Minor version ZZZ = Sub version @return this clients's full version number } function TZAbstractConnection.GetClientVersion: Integer; begin Result := 0; end; {** Gets the host's full version number. Initially this should be 0. The format of the version returned must be XYYYZZZ where X = Major version YYY = Minor version ZZZ = Sub version @return this server's full version number } function TZAbstractConnection.GetHostVersion: Integer; begin Result := 0; end; function TZAbstractConnection.GetDescription: AnsiString; begin PlainDriver.GetDescription; end; {END ADDED by fduenas 15-06-2006} {** Puts this connection in read-only mode as a hint to enable database optimizations.

Note: This method cannot be called while in the middle of a transaction. @param readOnly true enables read-only mode; false disables read-only mode. } procedure TZAbstractConnection.SetReadOnly(ReadOnly: Boolean); begin FReadOnly := ReadOnly; end; {** Tests to see if the connection is in read-only mode. @return true if connection is read-only and false otherwise } function TZAbstractConnection.IsReadOnly: Boolean; begin Result := FReadOnly; end; {** Sets a catalog name in order to select a subspace of this Connection's database in which to work. If the driver does not support catalogs, it will silently ignore this request. } procedure TZAbstractConnection.SetCatalog(const Catalog: string); begin end; {** Returns the Connection's current catalog name. @return the current catalog name or null } function TZAbstractConnection.GetCatalog: string; begin Result := ''; end; {** Attempts to change the transaction isolation level to the one given. The constants defined in the interface Connection are the possible transaction isolation levels.

Note: This method cannot be called while in the middle of a transaction. @param level one of the TRANSACTION_* isolation values with the exception of TRANSACTION_NONE; some databases may not support other values @see DatabaseMetaData#supportsTransactionIsolationLevel } procedure TZAbstractConnection.SetTransactionIsolation( Level: TZTransactIsolationLevel); begin FTransactIsolationLevel := Level; end; {** Gets this Connection's current transaction isolation level. @return the current TRANSACTION_* mode value } function TZAbstractConnection.GetTransactionIsolation: TZTransactIsolationLevel; begin Result := FTransactIsolationLevel; end; {** Returns the first warning reported by calls on this Connection.

Note: Subsequent warnings will be chained to this SQLWarning. @return the first SQLWarning or null } function TZAbstractConnection.GetWarnings: EZSQLWarning; begin Result := nil; end; {** Clears all warnings reported for this Connection object. After a call to this method, the method getWarnings returns null until a new warning is reported for this Connection. } procedure TZAbstractConnection.ClearWarnings; begin end; function TZAbstractConnection.UseMetadata: boolean; begin result := FUseMetadata; end; procedure TZAbstractConnection.SetUseMetadata(Value: Boolean); begin FUseMetadata := Value; end; {$IFDEF ZEOS_TEST_ONLY} function TZAbstractConnection.GetTestMode: Byte; begin Result := FTestMode; end; procedure TZAbstractConnection.SetTestMode(Mode: Byte); begin FTestMode := Mode; end; {$ENDIF} {** EgonHugeist: Returns the BinaryString in a Tokenizer-detectable kind If the Tokenizer don't need to predetect it Result = BinaryString @param Value represents the Binary-String @param EscapeMarkSequence represents a Tokenizer detectable EscapeSequence (Len >= 3) @result the detectable Binary String } function TZAbstractConnection.GetBinaryEscapeString(const Value: RawByteString): String; begin if GetAutoEncodeStrings then //Set detect-sequence only if Prepreparing should be done else it's not server-understandable. Result := Self.GetDriver.GetTokenizer.AnsiGetEscapeString(GetSQLHexString(PAnsiChar(Value), Length(Value))) else Result := GetSQLHexString(PAnsiChar(Value), Length(Value)); end; function TZAbstractConnection.GetBinaryEscapeString(const Value: TByteDynArray): String; begin if GetAutoEncodeStrings then //Set detect-sequence only if Prepreparing should be done else it's not server-understandable. Result := Self.GetDriver.GetTokenizer.AnsiGetEscapeString(GetSQLHexString(PAnsiChar(Value), Length(Value))) else Result := GetSQLHexString(PAnsiChar(Value), Length(Value)); end; function TZAbstractConnection.GetEscapeString(const Value: ZWideString): ZWideString; begin if GetAutoEncodeStrings then if StartsWith(Value, '''') and EndsWith(Value, '''') then Result := GetDriver.GetTokenizer.GetEscapeString(Value) else {$IFDEF UNICODE} Result := AnsiQuotedStr(Value, #39) {$ELSE} Result := ZDbcUnicodeString(GetDriver.GetTokenizer.GetEscapeString(AnsiQuotedStr(ZPlainString(Value), #39))) {$ENDIF} else if StartsWith(Value, '''') and EndsWith(Value, '''') then Result := Value else {$IFDEF UNICODE} Result := AnsiQuotedStr(Value, #39); {$ELSE} Result := ZDbcUnicodeString(AnsiQuotedStr(ZPlainString(Value), #39)); {$ENDIF} end; function TZAbstractConnection.GetEscapeString(const Value: RawByteString): RawByteString; begin if GetAutoEncodeStrings then if StartsWith(Value, '''') and EndsWith(Value, '''') then Result := {$IFNDEF UNICODE}GetDriver.GetTokenizer.GetEscapeString{$ENDIF}(Value) else {$IFDEF WITH_UNITANSISTRINGS} AnsiStrings.AnsiQuotedStr(Value, #39) {$ELSE} Result := GetDriver.GetTokenizer.GetEscapeString(AnsiQuotedStr(ZDbcString(Value), #39)) {$ENDIF} else if StartsWith(Value, '''') and EndsWith(Value, '''') then Result := Value else Result := {$IFDEF WITH_UNITANSISTRINGS}AnsiStrings.{$ENDIF}AnsiQuotedStr(Value, #39); end; {** Result 100% Compiler-Compatible And sets it Result to ClientCodePage by calling the PlainDriver.GetClientCodePageInformations function @param ClientCharacterSet the CharacterSet which has to be checked @result PZCodePage see ZCompatible.pas } function TZAbstractConnection.GetClientCodePageInformations: PZCodePage; //EgonHugeist begin Result := ConSettings.ClientCodePage end; procedure TZAbstractConnection.OnPropertiesChange(Sender: TObject); begin // do nothing in base class end; { TZAbstractNotification } {** Creates this object and assignes the main properties. @param Connection a database connection object. @param EventName a name of the SQL event. } constructor TZAbstractNotification.Create(Connection: IZConnection; EventName: string); begin FConnection := Connection; FEventName := EventName; end; {** Gets an event name. @return an event name for this notification. } function TZAbstractNotification.GetEvent: string; begin Result := FEventName; end; {** Sets a listener to the specified event. } procedure TZAbstractNotification.Listen; begin end; {** Removes a listener to the specified event. } procedure TZAbstractNotification.Unlisten; begin end; {** Checks for any pending events. @return a string with incoming events?? } function TZAbstractNotification.CheckEvents: string; begin Result := ''; end; {** Sends a notification string. } procedure TZAbstractNotification.DoNotify; begin end; {** Returns the Connection object that produced this Statement object. @return the connection that produced this statement } function TZAbstractNotification.GetConnection: IZConnection; begin Result := FConnection; end; { TZAbstractSequence } {** Creates this sequence object. @param Connection an SQL connection interface. @param Name a name of the sequence generator. @param BlockSize a number of unique keys requested in one trip to server. } constructor TZAbstractSequence.Create(Connection: IZConnection; Name: string; BlockSize: Integer); begin FConnection := Connection; FName := Name; FBlockSize := BlockSize; end; {** Returns the Connection object that produced this Statement object. @return the connection that produced this statement } function TZAbstractSequence.GetConnection: IZConnection; begin Result := FConnection; end; {** Returns a name of the sequence generator. @return a name of this sequence generator. } function TZAbstractSequence.GetName: string; begin Result := FName; end; {** Returns the assigned block size for this sequence. @return the assigned block size. } function TZAbstractSequence.GetBlockSize: Integer; begin Result := FBlockSize; end; {** Gets the current unique key generated by this sequence. @param the last generated unique key. } function TZAbstractSequence.GetCurrentValue: Int64; begin Result := 0; end; { function TZAbstractSequence.GetCurrentValueSQL: String; begin result:='IMPLEMENT'; end; } {** Gets the next unique key generated by this sequence. @param the next generated unique key. } function TZAbstractSequence.GetNextValue: Int64; begin Result := 0; end; { function TZAbstractSequence.GetNextValueSQL: String; begin result:='IMPLEMENT'; end; } {** Sets the block size for this sequence. @param Value the block size. } procedure TZAbstractSequence.SetBlockSize(const Value: Integer); begin FBlockSize := Value; end; {** Sets a name of the sequence generator. @param Value a name of this sequence generator. } procedure TZAbstractSequence.SetName(const Value: string); begin FName := Value; end; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcDbLib.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { DBLib Connectivity Classes } { } { Originally written by Janos Fegyverneki } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcDbLib; interface {$I ZDbc.inc} uses {$IFDEF FPC} {$IFDEF WIN32} Comobj, {$ENDIF} {$ENDIF} Types, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} ZDbcConnection, ZDbcIntfs, ZCompatibility, ZDbcLogging, ZPlainDbLibDriver, ZPlainDbLibConstants, ZTokenizer, ZGenericSqlAnalyser, ZURL, ZPlainDriver; type TDBLibProvider = (dpMsSQL, dpSybase); {** Implements DBLib Database Driver. } {$WARNINGS OFF} TZDBLibDriver = class(TZAbstractDriver) public constructor Create; override; function Connect(const Url: TZURL): IZConnection; override; function GetMajorVersion: Integer; override; function GetMinorVersion: Integer; override; function GetTokenizer: IZTokenizer; override; function GetStatementAnalyser: IZStatementAnalyser; override; end; {$WARNINGS ON} {** Represents a DBLib specific connection interface. } IZDBLibConnection = interface (IZConnection) ['{6B0662A2-FF2A-4415-B6B0-AAC047EA0671}'] function FreeTDS: Boolean; function GetProvider: TDBLibProvider; function GetPlainDriver: IZDBLibPlainDriver; function GetConnectionHandle: PDBPROCESS; procedure InternalExecuteStatement(const SQL: string); procedure CheckDBLibError(LogCategory: TZLoggingCategory; const LogMessage: string); end; {** Implements a generic DBLib Connection. } TZDBLibConnection = class(TZAbstractConnection, IZDBLibConnection) private FProvider: TDBLibProvider; FFreeTDS: Boolean; function FreeTDS: Boolean; function GetProvider: TDBLibProvider; procedure ReStartTransactionSupport; procedure InternalSetTransactionIsolation(Level: TZTransactIsolationLevel); procedure DetermineMSDateFormat; function DetermineMSServerCollation: String; function DetermineMSServerCodePage(const Collation: String): Word; protected FHandle: PDBPROCESS; procedure InternalCreate; override; procedure InternalExecuteStatement(const SQL: string); virtual; procedure InternalLogin; virtual; function GetPlainDriver: IZDBLibPlainDriver; function GetConnectionHandle: PDBPROCESS; procedure CheckDBLibError(LogCategory: TZLoggingCategory; const LogMessage: string); virtual; procedure StartTransaction; virtual; public function CreateRegularStatement(Info: TStrings): IZStatement; override; function CreatePreparedStatement(const SQL: string; Info: TStrings): IZPreparedStatement; override; function CreateCallableStatement(const SQL: string; Info: TStrings): IZCallableStatement; override; function NativeSQL(const SQL: string): string; override; procedure SetAutoCommit(AutoCommit: Boolean); override; procedure SetTransactionIsolation(Level: TZTransactIsolationLevel); override; procedure Commit; override; procedure Rollback; override; procedure Open; override; procedure Close; override; procedure SetReadOnly(ReadOnly: Boolean); override; procedure SetCatalog(const Catalog: string); override; function GetCatalog: string; override; function GetWarnings: EZSQLWarning; override; procedure ClearWarnings; override; function GetBinaryEscapeString(const Value: TByteDynArray): String; overload; override; function GetBinaryEscapeString(const Value: RawByteString): String; overload; override; end; var {** The common driver manager object. } DBLibDriver: IZDriver; implementation uses {$IFDEF WITH_UNITANSISTRINGS}AnsiStrings,{$ENDIF} SysUtils, ZSysUtils, ZMessages, ZDbcUtils, ZDbcDbLibStatement, ZEncoding, ZDbcDbLibMetadata, ZSybaseToken, ZSybaseAnalyser{$IFDEF FPC}, ZClasses{$ENDIF}; { TZDBLibDriver } {** Constructs this object with default properties. } constructor TZDBLibDriver.Create; begin inherited Create; AddSupportedProtocol(AddPlainDriverToCache(TZDBLibMSSQL7PlainDriver.Create)); AddSupportedProtocol(AddPlainDriverToCache(TZDBLibSybaseASE125PlainDriver.Create)); AddSupportedProtocol(AddPlainDriverToCache(TZFreeTDS42MsSQLPlainDriver.Create)); AddSupportedProtocol(AddPlainDriverToCache(TZFreeTDS42SybasePlainDriver.Create)); AddSupportedProtocol(AddPlainDriverToCache(TZFreeTDS50PlainDriver.Create)); AddSupportedProtocol(AddPlainDriverToCache(TZFreeTDS70PlainDriver.Create)); AddSupportedProtocol(AddPlainDriverToCache(TZFreeTDS71PlainDriver.Create)); AddSupportedProtocol(AddPlainDriverToCache(TZFreeTDS72PlainDriver.Create)); end; {** Attempts to make a database connection to the given URL. } {$WARNINGS OFF} function TZDBLibDriver.Connect(const Url: TZURL): IZConnection; begin Result := TZDBLibConnection.Create(Url); end; {$WARNINGS ON} {** Gets the driver's major version number. Initially this should be 1. @return this driver's major version number } function TZDBLibDriver.GetMajorVersion: Integer; begin Result := 1; end; {** Gets the driver's minor version number. Initially this should be 0. @return this driver's minor version number } function TZDBLibDriver.GetMinorVersion: Integer; begin Result := 0; end; {** Gets a SQL syntax tokenizer. @returns a SQL syntax tokenizer object. } function TZDBLibDriver.GetTokenizer: IZTokenizer; begin if Tokenizer = nil then Tokenizer := TZSybaseTokenizer.Create; Result := Tokenizer; end; {** Creates a statement analyser object. @returns a statement analyser object. } function TZDBLibDriver.GetStatementAnalyser: IZStatementAnalyser; begin if Analyser = nil then Analyser := TZSybaseStatementAnalyser.Create; Result := Analyser; end; { TZDBLibConnection } {** Constructs this object and assignes the main properties. } procedure TZDBLibConnection.InternalCreate; begin FDisposeCodePage := False; if Pos('mssql', LowerCase(Url.Protocol)) > 0 then begin FMetadata := TZMsSqlDatabaseMetadata.Create(Self, Url); FProvider := dpMsSQL; end else if Pos('sybase', LowerCase(Url.Protocol)) > 0 then begin FMetadata := TZSybaseDatabaseMetadata.Create(Self, Url); FProvider := dpSybase; end else FMetadata := nil; FFreeTDS := Pos('FreeTDS', Url.Protocol) > 0; FHandle := nil; end; {** Destroys this object and cleanups the memory. } function TZDBLibConnection.FreeTDS: Boolean; begin Result := FFreeTDS; end; function TZDBLibConnection.GetProvider: TDBLibProvider; begin Result := FProvider; end; {** Executes simple statements internally. } procedure TZDBLibConnection.InternalExecuteStatement(const SQL: string); var LSQL: string; ASQL: RawByteString; begin FHandle := GetConnectionHandle; if GetPlainDriver.dbCancel(FHandle) <> DBSUCCEED then CheckDBLibError(lcExecute, SQL); if FProvider = dpMsSQL then LSQL := StringReplace(Sql, '\'#13, '\\'#13, [rfReplaceAll]) else LSQL := SQL; ASQL := AnsiString(LSQL); if GetPlainDriver.dbcmd(FHandle, PAnsiChar(ASQL)) <> DBSUCCEED then CheckDBLibError(lcExecute, LSQL); if GetPlainDriver.dbsqlexec(FHandle) <> DBSUCCEED then CheckDBLibError(lcExecute, LSQL); repeat GetPlainDriver.dbresults(FHandle); GetPlainDriver.dbcanquery(FHandle); until GetPlainDriver.dbmorecmds(FHandle) = DBFAIL; CheckDBLibError(lcExecute, LSQL); DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, LSQL); end; {** Login procedure can be overriden for special settings. } procedure TZDBLibConnection.InternalLogin; var Loginrec: PLOGINREC; LogMessage: string; S: string; lLogFile : String; begin LogMessage := Format('CONNECT TO "%s"', [HostName]); LoginRec := GetPLainDriver.dbLogin; try //Common parameters S := Info.Values['workstation']; if S <> '' then GetPlainDriver.dbSetLHost(LoginRec, PAnsiChar(AnsiString(S))); S := Info.Values['appname']; if S <> '' then GetPlainDriver.dbSetLApp(LoginRec, PAnsiChar(AnsiString(S))); S := Info.Values['language']; if S <> '' then GetPlainDriver.dbSetLNatLang(LoginRec, PAnsiChar(AnsiString(S))); S := Info.Values['timeout']; if S <> '' then GetPlainDriver.dbSetLoginTime(StrToIntDef(S, 60)); if FFreeTDS then begin if StrToBoolEx(Info.Values['log']) or StrToBoolEx(Info.Values['logging']) or StrToBoolEx(Info.Values['tds_dump']) then begin lLogFile := Info.Values['logfile']; if lLogFile = '' then lLogFile := Info.Values['log_file']; if lLogFile = '' then lLogFile := Info.Values['tds_dump_file']; if lLogFile = '' then lLogFile := ChangeFileExt(ParamStr(0), '.tdslog'); (GetPlainDriver as IZFreeTDSPlainDriver).tdsDump_Open(lLogFile); end; end; //mssql specific parameters if ( FProvider = dpMsSQL ) then begin if ( StrToBoolEx(Info.Values['NTAuth']) or StrToBoolEx(Info.Values['trusted']) or StrToBoolEx(Info.Values['secure']) ) and ( not FFreeTDS ) then begin GetPlainDriver.dbsetlsecure(LoginRec); LogMessage := LogMessage + ' USING WINDOWS AUTHENTICATION'; end else begin GetPlainDriver.dbsetluser(LoginRec, PAnsiChar(AnsiString(User))); GetPlainDriver.dbsetlpwd(LoginRec, PAnsiChar(AnsiString(Password))); LogMessage := LogMessage + Format(' AS USER "%s"', [User]); end; end; //sybase specific parameters if FProvider = dpSybase then begin S := Info.Values['codepage']; if S <> '' then GetPlainDriver.dbSetLCharSet(LoginRec, PAnsiChar(ZPlainString(S))); GetPlainDriver.dbsetluser(LoginRec, PAnsiChar(ZPlainString(User))); GetPlainDriver.dbsetlpwd(LoginRec, PAnsiChar(ZPlainString(Password))); LogMessage := LogMessage + Format(' AS USER "%s"', [User]); end; CheckDBLibError(lcConnect, LogMessage); FHandle := GetPlainDriver.dbOpen(LoginRec, PAnsiChar(AnsiString(HostName))); CheckDBLibError(lcConnect, LogMessage); DriverManager.LogMessage(lcConnect, PlainDriver.GetProtocol, LogMessage); finally GetPLainDriver.dbLoginFree(LoginRec); end; end; function TZDBLibConnection.GetPlainDriver: IZDBLibPlainDriver; begin Result := PlainDriver as IZDBLibPlainDriver; end; function TZDBLibConnection.GetConnectionHandle: PDBPROCESS; begin if FProvider = dpMsSQL then if GetPlainDriver.dbDead(FHandle) then begin Closed := True; Open; end; Result := FHandle; end; procedure TZDBLibConnection.CheckDBLibError(LogCategory: TZLoggingCategory; const LogMessage: string); begin try GetPlainDriver.CheckError(FHandle); except on E: Exception do begin DriverManager.LogError(LogCategory, PlainDriver.GetProtocol, LogMessage, 0, E.Message); raise; end; end; end; {** Starts a transaction support. } procedure TZDBLibConnection.ReStartTransactionSupport; begin if Closed then Exit; if not (AutoCommit or (GetTransactionIsolation = tiNone)) then StartTransaction; end; {** Opens a connection to database server with specified parameters. } procedure TZDBLibConnection.Open; var LogMessage: string; begin if not Closed then Exit; InternalLogin; LogMessage := Format('USE %s', [Database]); if FProvider = dpMsSQL then begin if GetPlainDriver.dbUse(FHandle, PAnsiChar(AnsiString(Database))) <> DBSUCCEED then CheckDBLibError(lcConnect, LogMessage); end else if GetPlainDriver.dbUse(FHandle, PAnsiChar(ZPlainString(Database))) <> DBSUCCEED then CheckDBLibError(lcConnect, LogMessage); DriverManager.LogMessage(lcConnect, PlainDriver.GetProtocol, LogMessage); LogMessage := 'set textlimit=2147483647'; if GetPlainDriver.dbsetopt(FHandle, GetPlainDriver.GetVariables.dboptions[Z_TEXTLIMIT] , '2147483647') <> DBSUCCEED then CheckDBLibError(lcConnect, LogMessage); DriverManager.LogMessage(lcConnect, PlainDriver.GetProtocol, LogMessage); InternalExecuteStatement('set textsize 2147483647 set quoted_identifier on'); inherited Open; if FProvider = dpMsSQL then begin if FClientCodePage = '' then begin FDisposeCodePage := True; ConSettings^.ClientCodePage := New(PZCodePage); ConSettings^.ClientCodePage^.CP := ZDefaultSystemCodePage; //need a tempory CP for the SQL preparation ConSettings^.ClientCodePage^.Encoding := ceAnsi; ConSettings^.ClientCodePage^.Name := DetermineMSServerCollation; ConSettings^.ClientCodePage^.IsStringFieldCPConsistent := True; ConSettings^.ClientCodePage^.CP := DetermineMSServerCodePage(ConSettings^.ClientCodePage^.Name); SetConvertFunctions(ConSettings); end; DetermineMSDateFormat; end else ConSettings.DateFormat := 'yyyy/mm/dd'; InternalSetTransactionIsolation(GetTransactionIsolation); ReStartTransactionSupport; end; {** Creates a Statement object for sending SQL statements to the database. SQL statements without parameters are normally executed using Statement objects. If the same SQL statement is executed many times, it is more efficient to use a PreparedStatement object.

Result sets created using the returned Statement object will by default have forward-only type and read-only concurrency. @return a new Statement object } function TZDBLibConnection.CreateRegularStatement(Info: TStrings): IZStatement; begin if IsClosed then Open; Result := TZDBLibStatement.Create(Self, Info); end; {** Creates a PreparedStatement object for sending parameterized SQL statements to the database. A SQL statement with or without IN parameters can be pre-compiled and stored in a PreparedStatement object. This object can then be used to efficiently execute this statement multiple times.

Note: This method is optimized for handling parametric SQL statements that benefit from precompilation. If the driver supports precompilation, the method prepareStatement will send the statement to the database for precompilation. Some drivers may not support precompilation. In this case, the statement may not be sent to the database until the PreparedStatement is executed. This has no direct effect on users; however, it does affect which method throws certain SQLExceptions. Result sets created using the returned PreparedStatement will have forward-only type and read-only concurrency, by default. @param sql a SQL statement that may contain one or more '?' IN parameter placeholders @param Info a statement parameters. @return a new PreparedStatement object containing the pre-compiled statement } function TZDBLibConnection.CreatePreparedStatement( const SQL: string; Info: TStrings): IZPreparedStatement; begin if IsClosed then Open; Result := TZDBLibPreparedStatementEmulated.Create(Self, SQL, Info); end; {** Creates a CallableStatement object for calling database stored procedures. The CallableStatement object provides methods for setting up its IN and OUT parameters, and methods for executing the call to a stored procedure.

Note: This method is optimized for handling stored procedure call statements. Some drivers may send the call statement to the database when the method prepareCall is done; others may wait until the CallableStatement object is executed. This has no direct effect on users; however, it does affect which method throws certain SQLExceptions. Result sets created using the returned CallableStatement will have forward-only type and read-only concurrency, by default. @param sql a SQL statement that may contain one or more '?' parameter placeholders. Typically this statement is a JDBC function call escape string. @param Info a statement parameters. @return a new CallableStatement object containing the pre-compiled SQL statement } function TZDBLibConnection.CreateCallableStatement( const SQL: string; Info: TStrings): IZCallableStatement; begin if IsClosed then Open; Result := TZDBLibCallableStatement.Create(Self, SQL, Info); end; {** Converts the given SQL statement into the system's native SQL grammar. A driver may convert the JDBC sql grammar into its system's native SQL grammar prior to sending it; this method returns the native form of the statement that the driver would have sent. @param sql a SQL statement that may contain one or more '?' parameter placeholders @return the native form of this statement } function TZDBLibConnection.NativeSQL(const SQL: string): string; begin Result := SQL; end; {** Sets this connection's auto-commit mode. If a connection is in auto-commit mode, then all its SQL statements will be executed and committed as individual transactions. Otherwise, its SQL statements are grouped into transactions that are terminated by a call to either the method commit or the method rollback. By default, new connections are in auto-commit mode. The commit occurs when the statement completes or the next execute occurs, whichever comes first. In the case of statements returning a ResultSet, the statement completes when the last row of the ResultSet has been retrieved or the ResultSet has been closed. In advanced cases, a single statement may return multiple results as well as output parameter values. In these cases the commit occurs when all results and output parameter values have been retrieved. @param autoCommit true enables auto-commit; false disables auto-commit. } procedure TZDBLibConnection.SetAutoCommit(AutoCommit: Boolean); begin if GetAutoCommit = AutoCommit then Exit; if not Closed and AutoCommit then InternalExecuteStatement('commit'); inherited; ReStartTransactionSupport; end; procedure TZDBLibConnection.InternalSetTransactionIsolation(Level: TZTransactIsolationLevel); const IL: array[TZTransactIsolationLevel, 0..1] of string = (('READ COMMITTED', '1'), ('READ UNCOMMITTED', '0'), ('READ COMMITTED', '1'), ('REPEATABLE READ', '2'), ('SERIALIZABLE', '3')); var Index: Integer; S: string; begin Index := -1; if FProvider = dpMsSQL then Index := 0; if FProvider = dpSybase then Index := 1; S := 'SET TRANSACTION ISOLATION LEVEL ' + IL[GetTransactionIsolation, Index]; InternalExecuteStatement(S); if not (AutoCommit) then InternalExecuteStatement('BEGIN TRANSACTION'); end; procedure TZDBLibConnection.DetermineMSDateFormat; var Tmp: AnsiString; begin Tmp := 'SELECT dateformat FROM master.dbo.syslanguages WHERE name = @@LANGUAGE'; if (GetPlainDriver.dbcmd(FHandle, Pointer(Tmp)) <> DBSUCCEED) or (GetPlainDriver.dbsqlexec(FHandle) <> DBSUCCEED) or (GetPlainDriver.dbresults(FHandle) <> DBSUCCEED) or (GetPlainDriver.dbcmdrow(FHandle) <> DBSUCCEED) or (GetPlainDriver.dbnextrow(FHandle) <> REG_ROW) then CheckDBLibError(lcOther, String(Tmp)) else SetString(Tmp, PAnsiChar(GetPlainDriver.dbdata(FHandle, 1)), GetPlainDriver.dbDatLen(FHandle, 1)); GetPlainDriver.dbCancel(FHandle); ConSettings.DateFormat := String(Tmp); if ConSettings.DateFormat = 'dmy' then ConSettings.DateFormat := 'dd/mm/yyyy' else if ConSettings.DateFormat = 'mdy' then ConSettings.DateFormat := 'mm/dd/yyyy' else ConSettings.DateFormat := 'yyyy/mm/dd' end; function TZDBLibConnection.DetermineMSServerCollation: String; var Tmp: AnsiString; begin Tmp := 'SELECT DATABASEPROPERTYEX('+ {$IFDEF WITH_UNITANSISTRINGS}AnsiStrings.{$ENDIF}AnsiQuotedStr(AnsiString(DataBase), #39)+ ', ''Collation'') as DatabaseCollation'; if (GetPlainDriver.dbcmd(FHandle, Pointer(Tmp)) <> DBSUCCEED) or (GetPlainDriver.dbsqlexec(FHandle) <> DBSUCCEED) or (GetPlainDriver.dbresults(FHandle) <> DBSUCCEED) or (GetPlainDriver.dbcmdrow(FHandle) <> DBSUCCEED) or (GetPlainDriver.dbnextrow(FHandle) <> REG_ROW) then CheckDBLibError(lcOther, String(Tmp)) else ZSetString(PAnsiChar(GetPlainDriver.dbdata(FHandle, 1)), GetPlainDriver.dbDatLen(FHandle, 1), Tmp); GetPlainDriver.dbCancel(FHandle); Result := String(Tmp); end; function TZDBLibConnection.DetermineMSServerCodePage(const Collation: String): Word; var Tmp: AnsiString; begin Result := High(Word); Tmp := 'SELECT COLLATIONPROPERTY('+ {$IFDEF WITH_UNITANSISTRINGS}AnsiStrings.{$ENDIF}AnsiQuotedStr( AnsiString(Collation), #39)+ ', ''Codepage'') as Codepage'; if (GetPlainDriver.dbcmd(FHandle, Pointer(Tmp)) <> DBSUCCEED) or (GetPlainDriver.dbsqlexec(FHandle) <> DBSUCCEED) or (GetPlainDriver.dbresults(FHandle) <> DBSUCCEED) or (GetPlainDriver.dbcmdrow(FHandle) <> DBSUCCEED) or (GetPlainDriver.dbnextrow(FHandle) <> REG_ROW) then CheckDBLibError(lcOther, String(Tmp)) else begin ZSetString(PAnsiChar(GetPlainDriver.dbdata(FHandle, 1)), GetPlainDriver.dbDatLen(FHandle, 1), Tmp); Result := StrToInt(String(Tmp)); end; GetPlainDriver.dbCancel(FHandle); end; {** Attempts to change the transaction isolation level to the one given. The constants defined in the interface Connection are the possible transaction isolation levels.

Note: This method cannot be called while in the middle of a transaction. @param level one of the TRANSACTION_* isolation values with the exception of TRANSACTION_NONE; some databases may not support other values @see DatabaseMetaData#supportsTransactionIsolationLevel } procedure TZDBLibConnection.SetTransactionIsolation( Level: TZTransactIsolationLevel); begin if GetTransactionIsolation = Level then Exit; if not Closed and not AutoCommit and (GetTransactionIsolation <> tiNone) then InternalExecuteStatement('commit'); inherited; if not Closed then InternalSetTransactionIsolation(Level); RestartTransactionSupport; end; {** Starts a new transaction. Used internally. } procedure TZDBLibConnection.StartTransaction; begin InternalExecuteStatement('begin transaction'); end; {** Makes all changes made since the previous commit/rollback permanent and releases any database locks currently held by the Connection. This method should be used only when auto-commit mode has been disabled. @see #setAutoCommit } procedure TZDBLibConnection.Commit; begin if AutoCommit then raise Exception.Create(SCannotUseCommit); InternalExecuteStatement('commit'); StartTransaction; end; {** Drops all changes made since the previous commit/rollback and releases any database locks currently held by this Connection. This method should be used only when auto- commit has been disabled. @see #setAutoCommit } procedure TZDBLibConnection.Rollback; begin if AutoCommit then raise Exception.Create(SCannotUseRollBack); InternalExecuteStatement('rollback'); StartTransaction; end; {** Releases a Connection's database and JDBC resources immediately instead of waiting for them to be automatically released.

Note: A Connection is automatically closed when it is garbage collected. Certain fatal errors also result in a closed Connection. } procedure TZDBLibConnection.Close; var LogMessage: string; begin if Closed then Exit; if Assigned(PlainDriver) then begin if not GetPlainDriver.dbDead(FHandle) then InternalExecuteStatement('if @@trancount > 0 rollback'); LogMessage := Format('CLOSE CONNECTION TO "%s" DATABASE "%s"', [HostName, Database]); if GetPlainDriver.dbclose(FHandle) <> DBSUCCEED then CheckDBLibError(lcDisConnect, LogMessage); DriverManager.LogMessage(lcDisconnect, PlainDriver.GetProtocol, LogMessage); end; FHandle := nil; inherited; end; {** Puts this connection in read-only mode as a hint to enable database optimizations.

Note: This method cannot be called while in the middle of a transaction. @param readOnly true enables read-only mode; false disables read-only mode. } procedure TZDBLibConnection.SetReadOnly(ReadOnly: Boolean); begin { TODO -ofjanos -cAPI : I think it is not supported in this way } inherited; end; {** Sets a catalog name in order to select a subspace of this Connection's database in which to work. If the driver does not support catalogs, it will silently ignore this request. } procedure TZDBLibConnection.SetCatalog(const Catalog: string); var LogMessage: string; begin if (Catalog <> '') and not Closed then begin LogMessage := Format('SET CATALOG %s', [Catalog]); if FProvider = dpMsSQL then begin if GetPLainDriver.dbUse(FHandle, PAnsiChar(AnsiString(Catalog))) <> DBSUCCEED then CheckDBLibError(lcOther, LogMessage); end else if GetPLainDriver.dbUse(FHandle, PAnsiChar(ZPlainString(Catalog))) <> DBSUCCEED then CheckDBLibError(lcOther, LogMessage); DriverManager.LogMessage(lcOther, PLainDriver.GetProtocol, LogMessage); end; end; {** Returns the Connection's current catalog name. @return the current catalog name or null } function TZDBLibConnection.GetCatalog: string; begin Result := String(GetPlainDriver.dbName(FHandle)); CheckDBLibError(lcOther, 'GETCATALOG'); end; {** Returns the first warning reported by calls on this Connection.

Note: Subsequent warnings will be chained to this SQLWarning. @return the first SQLWarning or null } function TZDBLibConnection.GetWarnings: EZSQLWarning; begin Result := nil; end; {** Clears all warnings reported for this Connection object. After a call to this method, the method getWarnings returns null until a new warning is reported for this Connection. } procedure TZDBLibConnection.ClearWarnings; var LogMessage: string; begin if Closed then Exit; if not GetPlainDriver.dbDead(FHandle) then InternalExecuteStatement('if @@trancount > 0 rollback'); LogMessage := Format('CLOSE CONNECTION TO "%s" DATABASE "%s"', [HostName, Database]); if GetPlainDriver.dbclose(FHandle) <> DBSUCCEED then CheckDBLibError(lcDisConnect, LogMessage); DriverManager.LogMessage(lcDisconnect, GetPlainDriver.GetProtocol, LogMessage); FHandle := nil; inherited; end; function TZDBLibConnection.GetBinaryEscapeString(const Value: TByteDynArray): String; begin Result := GetSQLHexString(PAnsiChar(Value), Length(Value), True); if GetAutoEncodeStrings then Result := GetDriver.GetTokenizer.GetEscapeString(Result) end; function TZDBLibConnection.GetBinaryEscapeString(const Value: RawByteString): String; begin Result := GetSQLHexString(PAnsiChar(Value), Length(Value), True); if GetAutoEncodeStrings then Result := GetDriver.GetTokenizer.GetEscapeString(Result) end; initialization DBLibDriver := TZDBLibDriver.Create; DriverManager.RegisterDriver(DBLibDriver); finalization if Assigned(DriverManager) then DriverManager.DeregisterDriver(DBLibDriver); DBLibDriver := nil; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcDbLibMetadata.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { MsSql Database metadata information } { } { Originally written by Janos Fegyverneki } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcDbLibMetadata; interface {$I ZDbc.inc} uses Types, Classes, SysUtils, ZSysUtils, ZDbcIntfs, ZDbcMetadata, ZURL, ZCompatibility, ZDbcConnection, ZSelectSchema; type // technobot 2008-06-25 - methods moved as is from TZDbLibBaseDatabaseMetadata: {** Implements MsSql Database Information. } TZDbLibDatabaseInfo = class(TZAbstractDatabaseInfo) public // database/driver/server info: function GetDatabaseProductName: string; override; function GetDatabaseProductVersion: string; override; function GetDriverName: string; override; // function GetDriverVersion: string; override; -> Same as parent function GetDriverMajorVersion: Integer; override; function GetDriverMinorVersion: Integer; override; // function GetServerVersion: string; -> Not implemented // capabilities (what it can/cannot do): // function AllProceduresAreCallable: Boolean; override; -> Not implemented // function AllTablesAreSelectable: Boolean; override; -> Not implemented function SupportsMixedCaseIdentifiers: Boolean; override; function SupportsMixedCaseQuotedIdentifiers: Boolean; override; // function SupportsAlterTableWithAddColumn: Boolean; override; -> Not implemented // function SupportsAlterTableWithDropColumn: Boolean; override; -> Not implemented // function SupportsColumnAliasing: Boolean; override; -> Not implemented // function SupportsConvert: Boolean; override; -> Not implemented // function SupportsConvertForTypes(FromType: TZSQLType; ToType: TZSQLType): // Boolean; override; -> Not implemented // function SupportsTableCorrelationNames: Boolean; override; -> Not implemented // function SupportsDifferentTableCorrelationNames: Boolean; override; -> Not implemented function SupportsExpressionsInOrderBy: Boolean; override; function SupportsOrderByUnrelated: Boolean; override; function SupportsGroupBy: Boolean; override; function SupportsGroupByUnrelated: Boolean; override; function SupportsGroupByBeyondSelect: Boolean; override; // function SupportsLikeEscapeClause: Boolean; override; -> Not implemented // function SupportsMultipleResultSets: Boolean; override; -> Not implemented // function SupportsMultipleTransactions: Boolean; override; -> Not implemented // function SupportsNonNullableColumns: Boolean; override; -> Not implemented // function SupportsMinimumSQLGrammar: Boolean; override; -> Not implemented // function SupportsCoreSQLGrammar: Boolean; override; -> Not implemented // function SupportsExtendedSQLGrammar: Boolean; override; -> Not implemented // function SupportsANSI92EntryLevelSQL: Boolean; override; -> Not implemented // function SupportsANSI92IntermediateSQL: Boolean; override; -> Not implemented // function SupportsANSI92FullSQL: Boolean; override; -> Not implemented function SupportsIntegrityEnhancementFacility: Boolean; override; // function SupportsOuterJoins: Boolean; override; -> Not implemented // function SupportsFullOuterJoins: Boolean; override; -> Not implemented // function SupportsLimitedOuterJoins: Boolean; override; -> Not implemented function SupportsSchemasInDataManipulation: Boolean; override; function SupportsSchemasInProcedureCalls: Boolean; override; function SupportsSchemasInTableDefinitions: Boolean; override; function SupportsSchemasInIndexDefinitions: Boolean; override; function SupportsSchemasInPrivilegeDefinitions: Boolean; override; function SupportsCatalogsInDataManipulation: Boolean; override; function SupportsCatalogsInProcedureCalls: Boolean; override; function SupportsCatalogsInTableDefinitions: Boolean; override; function SupportsCatalogsInIndexDefinitions: Boolean; override; function SupportsCatalogsInPrivilegeDefinitions: Boolean; override; function SupportsPositionedDelete: Boolean; override; function SupportsPositionedUpdate: Boolean; override; function SupportsSelectForUpdate: Boolean; override; function SupportsStoredProcedures: Boolean; override; function SupportsSubqueriesInComparisons: Boolean; override; function SupportsSubqueriesInExists: Boolean; override; function SupportsSubqueriesInIns: Boolean; override; function SupportsSubqueriesInQuantifieds: Boolean; override; function SupportsCorrelatedSubqueries: Boolean; override; function SupportsUnion: Boolean; override; function SupportsUnionAll: Boolean; override; function SupportsOpenCursorsAcrossCommit: Boolean; override; function SupportsOpenCursorsAcrossRollback: Boolean; override; function SupportsOpenStatementsAcrossCommit: Boolean; override; function SupportsOpenStatementsAcrossRollback: Boolean; override; function SupportsTransactions: Boolean; override; function SupportsTransactionIsolationLevel(Level: TZTransactIsolationLevel): Boolean; override; function SupportsDataDefinitionAndDataManipulationTransactions: Boolean; override; function SupportsDataManipulationTransactionsOnly: Boolean; override; function SupportsResultSetType(_Type: TZResultSetType): Boolean; override; function SupportsResultSetConcurrency(_Type: TZResultSetType; Concurrency: TZResultSetConcurrency): Boolean; override; // function SupportsBatchUpdates: Boolean; override; -> Not implemented // maxima: function GetMaxBinaryLiteralLength: Integer; override; function GetMaxCharLiteralLength: Integer; override; function GetMaxColumnNameLength: Integer; override; function GetMaxColumnsInGroupBy: Integer; override; function GetMaxColumnsInIndex: Integer; override; function GetMaxColumnsInOrderBy: Integer; override; function GetMaxColumnsInSelect: Integer; override; function GetMaxColumnsInTable: Integer; override; function GetMaxConnections: Integer; override; function GetMaxCursorNameLength: Integer; override; function GetMaxIndexLength: Integer; override; function GetMaxSchemaNameLength: Integer; override; function GetMaxProcedureNameLength: Integer; override; function GetMaxCatalogNameLength: Integer; override; function GetMaxRowSize: Integer; override; function GetMaxStatementLength: Integer; override; function GetMaxStatements: Integer; override; function GetMaxTableNameLength: Integer; override; function GetMaxTablesInSelect: Integer; override; function GetMaxUserNameLength: Integer; override; // policies (how are various data and operations handled): // function IsReadOnly: Boolean; override; -> Not implemented // function IsCatalogAtStart: Boolean; override; -> Not implemented function DoesMaxRowSizeIncludeBlobs: Boolean; override; // function NullsAreSortedHigh: Boolean; override; -> Not implemented // function NullsAreSortedLow: Boolean; override; -> Not implemented // function NullsAreSortedAtStart: Boolean; override; -> Not implemented // function NullsAreSortedAtEnd: Boolean; override; -> Not implemented // function NullPlusNonNullIsNull: Boolean; override; -> Not implemented // function UsesLocalFiles: Boolean; override; -> Not implemented function UsesLocalFilePerTable: Boolean; override; function StoresUpperCaseIdentifiers: Boolean; override; function StoresLowerCaseIdentifiers: Boolean; override; function StoresMixedCaseIdentifiers: Boolean; override; function StoresUpperCaseQuotedIdentifiers: Boolean; override; function StoresLowerCaseQuotedIdentifiers: Boolean; override; function StoresMixedCaseQuotedIdentifiers: Boolean; override; function GetDefaultTransactionIsolation: TZTransactIsolationLevel; override; function DataDefinitionCausesTransactionCommit: Boolean; override; function DataDefinitionIgnoredInTransactions: Boolean; override; // interface details (terms, keywords, etc): function GetSchemaTerm: string; override; function GetProcedureTerm: string; override; function GetCatalogTerm: string; override; function GetCatalogSeparator: string; override; function GetSQLKeywords: string; override; function GetNumericFunctions: string; override; function GetStringFunctions: string; override; function GetSystemFunctions: string; override; function GetTimeDateFunctions: string; override; function GetSearchStringEscape: string; override; function GetExtraNameCharacters: string; override; end; TZMsSqlDatabaseInfo = class(TZDbLibDatabaseInfo) // database/driver/server info: function GetDatabaseProductName: string; override; function GetDatabaseProductVersion: string; override; function GetDriverName: string; override; end; TZSybaseDatabaseInfo = class(TZDbLibDatabaseInfo) // database/driver/server info: function GetDatabaseProductName: string; override; function GetDatabaseProductVersion: string; override; function GetDriverName: string; override; end; {** Implements DbLib Database Metadata. } TZDbLibBaseDatabaseMetadata = class(TZAbstractDatabaseMetadata) protected function ComposeObjectString(const S: String; Const NullText: String = 'null'; QuoteChar: Char = #39): String; function DecomposeObjectString(const S: String): String; override; function CreateDatabaseInfo: IZDatabaseInfo; override; // technobot 2008-06-25 function UncachedGetImportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; override; function UncachedGetExportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; override; end; {** Implements MsSql Database Metadata. } TZMsSqlDatabaseMetadata = class(TZDbLibBaseDatabaseMetadata) protected function CreateDatabaseInfo: IZDatabaseInfo; override; // technobot 2008-06-25 function UncachedGetTables(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const Types: TStringDynArray): IZResultSet; override; function UncachedGetSchemas: IZResultSet; override; function UncachedGetCatalogs: IZResultSet; override; function UncachedGetTableTypes: IZResultSet; override; function UncachedGetColumns(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const ColumnNamePattern: string): IZResultSet; override; function UncachedGetTablePrivileges(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string): IZResultSet; override; function UncachedGetColumnPrivileges(const Catalog: string; const Schema: string; const Table: string; const ColumnNamePattern: string): IZResultSet; override; function UncachedGetPrimaryKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; override; function UncachedGetCrossReference(const PrimaryCatalog: string; const PrimarySchema: string; const PrimaryTable: string; const ForeignCatalog: string; const ForeignSchema: string; const ForeignTable: string): IZResultSet; override; function UncachedGetIndexInfo(const Catalog: string; const Schema: string; const Table: string; Unique: Boolean; Approximate: Boolean): IZResultSet; override; function UncachedGetProcedures(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string): IZResultSet; override; function UncachedGetProcedureColumns(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string; const ColumnNamePattern: string): IZResultSet; override; function UncachedGetVersionColumns(const Catalog: string; const Schema: string; const Table: string): IZResultSet; override; function UncachedGetTypeInfo: IZResultSet; override; end; {** Implements Sybase Database Metadata. } TZSybaseDatabaseMetadata = class(TZDbLibBaseDatabaseMetadata) protected function CreateDatabaseInfo: IZDatabaseInfo; override; // technobot 2008-06-25 function UncachedGetTables(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const Types: TStringDynArray): IZResultSet; override; function UncachedGetSchemas: IZResultSet; override; function UncachedGetCatalogs: IZResultSet; override; function UncachedGetTableTypes: IZResultSet; override; function UncachedGetColumns(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const ColumnNamePattern: string): IZResultSet; override; function UncachedGetTablePrivileges(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string): IZResultSet; override; function UncachedGetColumnPrivileges(const Catalog: string; const Schema: string; const Table: string; const ColumnNamePattern: string): IZResultSet; override; function UncachedGetPrimaryKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; override; function UncachedGetImportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; override; function UncachedGetExportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; override; function UncachedGetCrossReference(const PrimaryCatalog: string; const PrimarySchema: string; const PrimaryTable: string; const ForeignCatalog: string; const ForeignSchema: string; const ForeignTable: string): IZResultSet; override; function UncachedGetIndexInfo(const Catalog: string; const Schema: string; const Table: string; Unique: Boolean; Approximate: Boolean): IZResultSet; override; function UncachedGetProcedures(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string): IZResultSet; override; function UncachedGetProcedureColumns(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string; const ColumnNamePattern: string): IZResultSet; override; function UncachedGetVersionColumns(const Catalog: string; const Schema: string; const Table: string): IZResultSet; override; function UncachedGetTypeInfo: IZResultSet; override; function UncachedGetUDTs(const Catalog: string; const SchemaPattern: string; const TypeNamePattern: string; const Types: TIntegerDynArray): IZResultSet; override; end; implementation uses ZDbcUtils, ZDbcDbLibUtils; { TZDbLibDatabaseInfo } {** //---------------------------------------------------------------------- // First, a variety of minor information about the target database. {** What's the name of this database product? @return database product name } function TZDbLibDatabaseInfo.GetDatabaseProductName: string; begin Result := ''; end; {** What's the version of this database product? @return database version } function TZDbLibDatabaseInfo.GetDatabaseProductVersion: string; begin Result := ''; end; {** What's the name of this JDBC driver? @return JDBC driver name } function TZDbLibDatabaseInfo.GetDriverName: string; begin Result := 'Zeos Abstract Database Connectivity Driver for DbLib Server'; end; {** What's this JDBC driver's major version number? @return JDBC driver major version } function TZDbLibDatabaseInfo.GetDriverMajorVersion: Integer; begin Result := 1; end; {** What's this JDBC driver's minor version number? @return JDBC driver minor version number } function TZDbLibDatabaseInfo.GetDriverMinorVersion: Integer; begin Result := 0; end; {** Does the database use a file for each table? @return true if the database uses a local file for each table } function TZDbLibDatabaseInfo.UsesLocalFilePerTable: Boolean; begin Result := False; end; {** Does the database treat mixed case unquoted SQL identifiers as case sensitive and as a result store them in mixed case? A JDBC CompliantTM driver will always return false. @return true if so; false otherwise } function TZDbLibDatabaseInfo.SupportsMixedCaseIdentifiers: Boolean; begin Result := False; end; {** Does the database treat mixed case unquoted SQL identifiers as case insensitive and store them in upper case? @return true if so; false otherwise } function TZDbLibDatabaseInfo.StoresUpperCaseIdentifiers: Boolean; begin Result := True; end; {** Does the database treat mixed case unquoted SQL identifiers as case insensitive and store them in lower case? @return true if so; false otherwise } function TZDbLibDatabaseInfo.StoresLowerCaseIdentifiers: Boolean; begin Result := True; end; {** Does the database treat mixed case unquoted SQL identifiers as case insensitive and store them in mixed case? @return true if so; false otherwise } function TZDbLibDatabaseInfo.StoresMixedCaseIdentifiers: Boolean; begin Result := True; end; {** Does the database treat mixed case quoted SQL identifiers as case sensitive and as a result store them in mixed case? A JDBC CompliantTM driver will always return true. @return true if so; false otherwise } function TZDbLibDatabaseInfo.SupportsMixedCaseQuotedIdentifiers: Boolean; begin Result := True; end; {** Does the database treat mixed case quoted SQL identifiers as case insensitive and store them in upper case? @return true if so; false otherwise } function TZDbLibDatabaseInfo.StoresUpperCaseQuotedIdentifiers: Boolean; begin Result := True; end; {** Does the database treat mixed case quoted SQL identifiers as case insensitive and store them in lower case? @return true if so; false otherwise } function TZDbLibDatabaseInfo.StoresLowerCaseQuotedIdentifiers: Boolean; begin Result := True; end; {** Does the database treat mixed case quoted SQL identifiers as case insensitive and store them in mixed case? @return true if so; false otherwise } function TZDbLibDatabaseInfo.StoresMixedCaseQuotedIdentifiers: Boolean; begin Result := True; end; {** Gets a comma-separated list of all a database's SQL keywords that are NOT also SQL92 keywords. @return the list } function TZDbLibDatabaseInfo.GetSQLKeywords: string; begin { TODO -ofjanos -cAPI : SQL Keywords that are not SQL92 compliant } Result := ''; end; {** Gets a comma-separated list of math functions. These are the X/Open CLI math function names used in the JDBC function escape clause. @return the list } function TZDbLibDatabaseInfo.GetNumericFunctions: string; begin Result := 'ABS,ACOS,ASIN,ATAN,ATN2,CEILING,COS,COT,DEGREES,EXP,FLOOR,LOG,LOG10,'+ 'PI,POWER,RADIANS,RAND,ROUND,SIGN,SIN,SQUARE,SQRT,TAN'; end; {** Gets a comma-separated list of string functions. These are the X/Open CLI string function names used in the JDBC function escape clause. @return the list } function TZDbLibDatabaseInfo.GetStringFunctions: string; begin Result := 'ASCII,CHAR,CHARINDEX,DIFFERENCE,LEFT,LEN,LOWER,LTRIM,NCHAR,PATINDEX,'+ 'REPLACE,QUOTENAME,REPLICATE,REVERSE,RIGHT,RTRIM,SOUNDEX,SPACE,STR,'+ 'STUFF,SUBSTRING,UNICODE,UPPER'; end; {** Gets a comma-separated list of system functions. These are the X/Open CLI system function names used in the JDBC function escape clause. @return the list } function TZDbLibDatabaseInfo.GetSystemFunctions: string; begin Result := 'APP_NAME,CASE,CAST,CONVERT,COALESCE,CURRENT_TIMESTAMP,CURRENT_USER,'+ 'DATALENGTH,@@ERROR,FORMATMESSAGE,GETANSINULL,HOST_ID,HOST_NAME,'+ 'IDENT_INCR,IDENT_SEED,@@IDENTITY,IDENTITY,ISDATE,ISNULL,ISNUMERIC,'+ 'NEWID,NULLIF,PARSENAME,PERMISSIONS,@@ROWCOUNT,SESSION_USER,STATS_DATE,'+ 'SYSTEM_USER,@@TRANCOUNT,USER_NAME'; end; {** Gets a comma-separated list of time and date functions. @return the list } function TZDbLibDatabaseInfo.GetTimeDateFunctions: string; begin Result := 'DATEADD,DATEDIFF,DATENAME,DATEPART,DAY,GETDATE,MONTH,YEAR'; end; {** Gets the string that can be used to escape wildcard characters. This is the string that can be used to escape '_' or '%' in the string pattern style catalog search parameters.

The '_' character represents any single character.

The '%' character represents any sequence of zero or more characters. @return the string used to escape wildcard characters } function TZDbLibDatabaseInfo.GetSearchStringEscape: string; begin { TODO -ofjanos -cgeneral : In sql server this must be specified as the parameter of like. example: WHERE ColumnA LIKE '%5/%%' ESCAPE '/' } Result := '/'; end; {** Gets all the "extra" characters that can be used in unquoted identifier names (those beyond a-z, A-Z, 0-9 and _). @return the string containing the extra characters } function TZDbLibDatabaseInfo.GetExtraNameCharacters: string; begin Result := '@$#'; end; //-------------------------------------------------------------------- // Functions describing which features are supported. {** Are expressions in "ORDER BY" lists supported? @return true if so; false otherwise } function TZDbLibDatabaseInfo.SupportsExpressionsInOrderBy: Boolean; begin Result := True; end; {** Can an "ORDER BY" clause use columns not in the SELECT statement? @return true if so; false otherwise } function TZDbLibDatabaseInfo.SupportsOrderByUnrelated: Boolean; begin Result := True; end; {** Is some form of "GROUP BY" clause supported? @return true if so; false otherwise } function TZDbLibDatabaseInfo.SupportsGroupBy: Boolean; begin Result := True; end; {** Can a "GROUP BY" clause use columns not in the SELECT? @return true if so; false otherwise } function TZDbLibDatabaseInfo.SupportsGroupByUnrelated: Boolean; begin Result := True; end; {** Can a "GROUP BY" clause add columns not in the SELECT provided it specifies all the columns in the SELECT? @return true if so; false otherwise } function TZDbLibDatabaseInfo.SupportsGroupByBeyondSelect: Boolean; begin Result := True; end; {** Is the SQL Integrity Enhancement Facility supported? @return true if so; false otherwise } function TZDbLibDatabaseInfo.SupportsIntegrityEnhancementFacility: Boolean; begin Result := False; end; {** What's the database vendor's preferred term for "schema"? @return the vendor term } function TZDbLibDatabaseInfo.GetSchemaTerm: string; begin Result := 'owner'; end; {** What's the database vendor's preferred term for "procedure"? @return the vendor term } function TZDbLibDatabaseInfo.GetProcedureTerm: string; begin Result := 'procedure'; end; {** What's the database vendor's preferred term for "catalog"? @return the vendor term } function TZDbLibDatabaseInfo.GetCatalogTerm: string; begin Result := 'database'; end; {** What's the separator between catalog and table name? @return the separator string } function TZDbLibDatabaseInfo.GetCatalogSeparator: string; begin Result := '.'; end; {** Can a schema name be used in a data manipulation statement? @return true if so; false otherwise } function TZDbLibDatabaseInfo.SupportsSchemasInDataManipulation: Boolean; begin Result := True; end; {** Can a schema name be used in a procedure call statement? @return true if so; false otherwise } function TZDbLibDatabaseInfo.SupportsSchemasInProcedureCalls: Boolean; begin Result := True; end; {** Can a schema name be used in a table definition statement? @return true if so; false otherwise } function TZDbLibDatabaseInfo.SupportsSchemasInTableDefinitions: Boolean; begin Result := True; end; {** Can a schema name be used in an index definition statement? @return true if so; false otherwise } function TZDbLibDatabaseInfo.SupportsSchemasInIndexDefinitions: Boolean; begin Result := True; end; {** Can a schema name be used in a privilege definition statement? @return true if so; false otherwise } function TZDbLibDatabaseInfo.SupportsSchemasInPrivilegeDefinitions: Boolean; begin Result := True; end; {** Can a catalog name be used in a data manipulation statement? @return true if so; false otherwise } function TZDbLibDatabaseInfo.SupportsCatalogsInDataManipulation: Boolean; begin Result := True; end; {** Can a catalog name be used in a procedure call statement? @return true if so; false otherwise } function TZDbLibDatabaseInfo.SupportsCatalogsInProcedureCalls: Boolean; begin Result := True; end; {** Can a catalog name be used in a table definition statement? @return true if so; false otherwise } function TZDbLibDatabaseInfo.SupportsCatalogsInTableDefinitions: Boolean; begin Result := True; end; {** Can a catalog name be used in an index definition statement? @return true if so; false otherwise } function TZDbLibDatabaseInfo.SupportsCatalogsInIndexDefinitions: Boolean; begin Result := True; end; {** Can a catalog name be used in a privilege definition statement? @return true if so; false otherwise } function TZDbLibDatabaseInfo.SupportsCatalogsInPrivilegeDefinitions: Boolean; begin Result := True; end; {** Is positioned DELETE supported? @return true if so; false otherwise } function TZDbLibDatabaseInfo.SupportsPositionedDelete: Boolean; begin //CURRENT OF //Specifies that the DELETE is done at the current position of the specified cursor. Result := True; end; {** Is positioned UPDATE supported? @return true if so; false otherwise } function TZDbLibDatabaseInfo.SupportsPositionedUpdate: Boolean; begin Result := True; end; {** Is SELECT for UPDATE supported? @return true if so; false otherwise } function TZDbLibDatabaseInfo.SupportsSelectForUpdate: Boolean; begin Result := True; end; {** Are stored procedure calls using the stored procedure escape syntax supported? @return true if so; false otherwise } function TZDbLibDatabaseInfo.SupportsStoredProcedures: Boolean; begin Result := True; end; {** Are subqueries in comparison expressions supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZDbLibDatabaseInfo.SupportsSubqueriesInComparisons: Boolean; begin Result := True; end; {** Are subqueries in 'exists' expressions supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZDbLibDatabaseInfo.SupportsSubqueriesInExists: Boolean; begin Result := True; end; {** Are subqueries in 'in' statements supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZDbLibDatabaseInfo.SupportsSubqueriesInIns: Boolean; begin Result := True; end; {** Are subqueries in quantified expressions supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZDbLibDatabaseInfo.SupportsSubqueriesInQuantifieds: Boolean; begin Result := True; end; {** Are correlated subqueries supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZDbLibDatabaseInfo.SupportsCorrelatedSubqueries: Boolean; begin Result := True; end; {** Is SQL UNION supported? @return true if so; false otherwise } function TZDbLibDatabaseInfo.SupportsUnion: Boolean; begin Result := True; end; {** Is SQL UNION ALL supported? @return true if so; false otherwise } function TZDbLibDatabaseInfo.SupportsUnionAll: Boolean; begin Result := True; end; {** Can cursors remain open across commits? @return true if cursors always remain open; false if they might not remain open } function TZDbLibDatabaseInfo.SupportsOpenCursorsAcrossCommit: Boolean; begin Result := True; end; {** Can cursors remain open across rollbacks? @return true if cursors always remain open; false if they might not remain open } function TZDbLibDatabaseInfo.SupportsOpenCursorsAcrossRollback: Boolean; begin Result := True; end; {** Can statements remain open across commits? @return true if statements always remain open; false if they might not remain open } function TZDbLibDatabaseInfo.SupportsOpenStatementsAcrossCommit: Boolean; begin Result := False; end; {** Can statements remain open across rollbacks? @return true if statements always remain open; false if they might not remain open } function TZDbLibDatabaseInfo.SupportsOpenStatementsAcrossRollback: Boolean; begin Result := False; end; //---------------------------------------------------------------------- // The following group of methods exposes various limitations // based on the target database with the current driver. // Unless otherwise specified, a result of zero means there is no // limit, or the limit is not known. {** How many hex characters can you have in an inline binary literal? @return max binary literal length in hex characters; a result of zero means that there is no limit or the limit is not known } function TZDbLibDatabaseInfo.GetMaxBinaryLiteralLength: Integer; begin Result := 16000; end; {** What's the max length for a character literal? @return max literal length; a result of zero means that there is no limit or the limit is not known } function TZDbLibDatabaseInfo.GetMaxCharLiteralLength: Integer; begin Result := 8000; end; {** What's the limit on column name length? @return max column name length; a result of zero means that there is no limit or the limit is not known } function TZDbLibDatabaseInfo.GetMaxColumnNameLength: Integer; begin Result := 128; end; {** What's the maximum number of columns in a "GROUP BY" clause? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZDbLibDatabaseInfo.GetMaxColumnsInGroupBy: Integer; begin Result := 0; end; {** What's the maximum number of columns allowed in an index? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZDbLibDatabaseInfo.GetMaxColumnsInIndex: Integer; begin Result := 16; end; {** What's the maximum number of columns in an "ORDER BY" clause? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZDbLibDatabaseInfo.GetMaxColumnsInOrderBy: Integer; begin Result := 0; end; {** What's the maximum number of columns in a "SELECT" list? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZDbLibDatabaseInfo.GetMaxColumnsInSelect: Integer; begin Result := 4096; end; {** What's the maximum number of columns in a table? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZDbLibDatabaseInfo.GetMaxColumnsInTable: Integer; begin Result := 1024; end; {** How many active connections can we have at a time to this database? @return max number of active connections; a result of zero means that there is no limit or the limit is not known } function TZDbLibDatabaseInfo.GetMaxConnections: Integer; begin Result := 0; end; {** What's the maximum cursor name length? @return max cursor name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZDbLibDatabaseInfo.GetMaxCursorNameLength: Integer; begin Result := 128; end; {** Retrieves the maximum number of bytes for an index, including all of the parts of the index. @return max index length in bytes, which includes the composite of all the constituent parts of the index; a result of zero means that there is no limit or the limit is not known } function TZDbLibDatabaseInfo.GetMaxIndexLength: Integer; begin Result := 900; end; {** What's the maximum length allowed for a schema name? @return max name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZDbLibDatabaseInfo.GetMaxSchemaNameLength: Integer; begin Result := 128; end; {** What's the maximum length of a procedure name? @return max name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZDbLibDatabaseInfo.GetMaxProcedureNameLength: Integer; begin Result := 128; end; {** What's the maximum length of a catalog name? @return max name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZDbLibDatabaseInfo.GetMaxCatalogNameLength: Integer; begin Result := 128; end; {** What's the maximum length of a single row? @return max row size in bytes; a result of zero means that there is no limit or the limit is not known } function TZDbLibDatabaseInfo.GetMaxRowSize: Integer; begin Result := 8060; end; {** Did getMaxRowSize() include LONGVARCHAR and LONGVARBINARY blobs? @return true if so; false otherwise } function TZDbLibDatabaseInfo.DoesMaxRowSizeIncludeBlobs: Boolean; begin Result := False; end; {** What's the maximum length of an SQL statement? @return max length in bytes; a result of zero means that there is no limit or the limit is not known } function TZDbLibDatabaseInfo.GetMaxStatementLength: Integer; begin Result := 0; end; {** How many active statements can we have open at one time to this database? @return the maximum number of statements that can be open at one time; a result of zero means that there is no limit or the limit is not known } function TZDbLibDatabaseInfo.GetMaxStatements: Integer; begin Result := 0; end; {** What's the maximum length of a table name? @return max name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZDbLibDatabaseInfo.GetMaxTableNameLength: Integer; begin Result := 128; end; {** What's the maximum number of tables in a SELECT statement? @return the maximum number of tables allowed in a SELECT statement; a result of zero means that there is no limit or the limit is not known } function TZDbLibDatabaseInfo.GetMaxTablesInSelect: Integer; begin Result := 256; end; {** What's the maximum length of a user name? @return max user name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZDbLibDatabaseInfo.GetMaxUserNameLength: Integer; begin Result := 128; end; //---------------------------------------------------------------------- {** What's the database's default transaction isolation level? The values are defined in java.sql.Connection. @return the default isolation level @see Connection } function TZDbLibDatabaseInfo.GetDefaultTransactionIsolation: TZTransactIsolationLevel; begin Result := tiReadCommitted; end; {** Are transactions supported? If not, invoking the method commit is a noop and the isolation level is TRANSACTION_NONE. @return true if transactions are supported; false otherwise } function TZDbLibDatabaseInfo.SupportsTransactions: Boolean; begin Result := True; end; {** Does this database support the given transaction isolation level? @param level the values are defined in java.sql.Connection @return true if so; false otherwise @see Connection } function TZDbLibDatabaseInfo.SupportsTransactionIsolationLevel( Level: TZTransactIsolationLevel): Boolean; begin Result := True; end; {** Are both data definition and data manipulation statements within a transaction supported? @return true if so; false otherwise } function TZDbLibDatabaseInfo. SupportsDataDefinitionAndDataManipulationTransactions: Boolean; begin Result := True; end; {** Are only data manipulation statements within a transaction supported? @return true if so; false otherwise } function TZDbLibDatabaseInfo. SupportsDataManipulationTransactionsOnly: Boolean; begin Result := False; end; {** Does a data definition statement within a transaction force the transaction to commit? @return true if so; false otherwise } function TZDbLibDatabaseInfo.DataDefinitionCausesTransactionCommit: Boolean; begin Result := False; end; {** Is a data definition statement within a transaction ignored? @return true if so; false otherwise } function TZDbLibDatabaseInfo.DataDefinitionIgnoredInTransactions: Boolean; begin Result := False; end; {** Does the database support the given result set type? @param type defined in java.sql.ResultSet @return true if so; false otherwise } function TZDbLibDatabaseInfo.SupportsResultSetType( _Type: TZResultSetType): Boolean; begin Result := True; end; {** Does the database support the concurrency type in combination with the given result set type? @param type defined in java.sql.ResultSet @param concurrency type defined in java.sql.ResultSet @return true if so; false otherwise } function TZDbLibDatabaseInfo.SupportsResultSetConcurrency( _Type: TZResultSetType; Concurrency: TZResultSetConcurrency): Boolean; begin Result := True; end; { TZDbLibBaseDatabaseMetadata } {** Composes a object name, AnsiQuotedStr or NullText @param S the object string @param NullText the "NULL"-Text default: 'null' @param QuoteChar the QuoteChar default: ' @return 'null' if S is '' or S if s is already Quoted or AnsiQuotedStr(S, #39) } function TZDbLibBaseDatabaseMetadata.ComposeObjectString(const S: String; Const NullText: String = 'null'; QuoteChar: Char = #39): String; begin if S = '' then Result := NullText else if IC.IsQuoted(s) then Result := S else Result := AnsiQuotedStr(S, QuoteChar); end; {** Decomposes a object name, AnsiQuotedStr or NullText @param S the object string @return 'null' if S is '' or S if s is already Quoted or AnsiQuotedStr(S, #39) } function TZDbLibBaseDatabaseMetadata.DecomposeObjectString(const S: String): String; begin if S = '' then Result := 'null' else begin if IC.IsQuoted(s) then Result := IC.ExtractQuote(s) else Result := S; Result := AnsiQuotedStr(Result, #39); end; end; {** Constructs a database information object and returns the interface to it. Used internally by the constructor. @return the database information object interface } function TZDbLibBaseDatabaseMetadata.CreateDatabaseInfo: IZDatabaseInfo; begin Result := TZDbLibDatabaseInfo.Create(Self); end; {** Gets a description of the primary key columns that are referenced by a table's foreign key columns (the primary keys imported by a table). They are ordered by PKTABLE_CAT, PKTABLE_SCHEM, PKTABLE_NAME, and KEY_SEQ.

Each primary key column description has the following columns:

  1. PKTABLE_CAT String => primary key table catalog being imported (may be null)
  2. PKTABLE_SCHEM String => primary key table schema being imported (may be null)
  3. PKTABLE_NAME String => primary key table name being imported
  4. PKCOLUMN_NAME String => primary key column name being imported
  5. FKTABLE_CAT String => foreign key table catalog (may be null)
  6. FKTABLE_SCHEM String => foreign key table schema (may be null)
  7. FKTABLE_NAME String => foreign key table name
  8. FKCOLUMN_NAME String => foreign key column name
  9. KEY_SEQ short => sequence number within foreign key
  10. UPDATE_RULE short => What happens to foreign key when primary is updated:
    • importedNoAction - do not allow update of primary key if it has been imported
    • importedKeyCascade - change imported key to agree with primary key update
    • importedKeySetNull - change imported key to NULL if its primary key has been updated
    • importedKeySetDefault - change imported key to default values if its primary key has been updated
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
  11. DELETE_RULE short => What happens to the foreign key when primary is deleted.
    • importedKeyNoAction - do not allow delete of primary key if it has been imported
    • importedKeyCascade - delete rows that import a deleted key
    • importedKeySetNull - change imported key to NULL if its primary key has been deleted
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
    • importedKeySetDefault - change imported key to default if its primary key has been deleted
  12. FK_NAME String => foreign key name (may be null)
  13. PK_NAME String => primary key name (may be null)
  14. DEFERRABILITY short => can the evaluation of foreign key constraints be deferred until commit
    • importedKeyInitiallyDeferred - see SQL92 for definition
    • importedKeyInitiallyImmediate - see SQL92 for definition
    • importedKeyNotDeferrable - see SQL92 for definition
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a primary key column description @see #getExportedKeys } function TZDbLibBaseDatabaseMetadata.UncachedGetImportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; begin Result := UncachedGetCrossReference('', '', '', Catalog, Schema, Table); end; {** Gets a description of the foreign key columns that reference a table's primary key columns (the foreign keys exported by a table). They are ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, and KEY_SEQ.

Each foreign key column description has the following columns:

  1. PKTABLE_CAT String => primary key table catalog (may be null)
  2. PKTABLE_SCHEM String => primary key table schema (may be null)
  3. PKTABLE_NAME String => primary key table name
  4. PKCOLUMN_NAME String => primary key column name
  5. FKTABLE_CAT String => foreign key table catalog (may be null) being exported (may be null)
  6. FKTABLE_SCHEM String => foreign key table schema (may be null) being exported (may be null)
  7. FKTABLE_NAME String => foreign key table name being exported
  8. FKCOLUMN_NAME String => foreign key column name being exported
  9. KEY_SEQ short => sequence number within foreign key
  10. UPDATE_RULE short => What happens to foreign key when primary is updated:
    • importedNoAction - do not allow update of primary key if it has been imported
    • importedKeyCascade - change imported key to agree with primary key update
    • importedKeySetNull - change imported key to NULL if its primary key has been updated
    • importedKeySetDefault - change imported key to default values if its primary key has been updated
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
  11. DELETE_RULE short => What happens to the foreign key when primary is deleted.
    • importedKeyNoAction - do not allow delete of primary key if it has been imported
    • importedKeyCascade - delete rows that import a deleted key
    • importedKeySetNull - change imported key to NULL if its primary key has been deleted
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
    • importedKeySetDefault - change imported key to default if its primary key has been deleted
  12. FK_NAME String => foreign key name (may be null)
  13. PK_NAME String => primary key name (may be null)
  14. DEFERRABILITY short => can the evaluation of foreign key constraints be deferred until commit
    • importedKeyInitiallyDeferred - see SQL92 for definition
    • importedKeyInitiallyImmediate - see SQL92 for definition
    • importedKeyNotDeferrable - see SQL92 for definition
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a foreign key column description @see #getImportedKeys } function TZDbLibBaseDatabaseMetadata.UncachedGetExportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; begin Result := UncachedGetCrossReference(Catalog, Schema, Table, '', '', ''); end; {** What's the name of this database product? @return database product name } function TZMsSqlDatabaseInfo.GetDatabaseProductName: string; begin Result := 'MS SQL'; end; {** What's the version of this database product? @return database version } function TZMsSqlDatabaseInfo.GetDatabaseProductVersion: string; begin Result := '7+'; end; {** What's the name of this JDBC driver? @return JDBC driver name } function TZMsSqlDatabaseInfo.GetDriverName: string; begin Result := 'Zeos Database Connectivity Driver for Microsoft SQL Server'; end; {** What's the name of this database product? @return database product name } function TZSybaseDatabaseInfo.GetDatabaseProductName: string; begin Result := 'Sybase'; end; {** What's the version of this database product? @return database version } function TZSybaseDatabaseInfo.GetDatabaseProductVersion: string; begin Result := '12+'; end; {** What's the name of this JDBC driver? @return JDBC driver name } function TZSybaseDatabaseInfo.GetDriverName: string; begin Result := 'Zeos Database Connectivity Driver for Sybase ASE Server'; end; { TZMsSqlDatabaseMetadata } {** Constructs a database information object and returns the interface to it. Used internally by the constructor. @return the database information object interface } function TZMsSqlDatabaseMetadata.CreateDatabaseInfo: IZDatabaseInfo; begin Result := TZMsSqlDatabaseInfo.Create(Self); end; {** Gets a description of the stored procedures available in a catalog.

Only procedure descriptions matching the schema and procedure name criteria are returned. They are ordered by PROCEDURE_SCHEM, and PROCEDURE_NAME.

Each procedure description has the the following columns:

  1. PROCEDURE_CAT String => procedure catalog (may be null)
  2. PROCEDURE_SCHEM String => procedure schema (may be null)
  3. PROCEDURE_NAME String => procedure name
  4. reserved for future use
  5. reserved for future use
  6. reserved for future use
  7. REMARKS String => explanatory comment on the procedure
  8. PROCEDURE_TYPE short => kind of procedure:
    • procedureResultUnknown - May return a result
    • procedureNoResult - Does not return a result
    • procedureReturnsResult - Returns a result
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param procedureNamePattern a procedure name pattern @return ResultSet - each row is a procedure description @see #getSearchStringEscape } function TZMsSqlDatabaseMetadata.UncachedGetProcedures(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string): IZResultSet; begin Result:=inherited UncachedGetProcedures(Catalog, SchemaPattern, ProcedureNamePattern); with GetStatement.ExecuteQuery( Format('exec sp_stored_procedures %s, %s, %s', [ComposeObjectString(ProcedureNamePattern), ComposeObjectString(SchemaPattern), ComposeObjectString(Catalog)])) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('PROCEDURE_CAT', GetStringByName('PROCEDURE_QUALIFIER')); Result.UpdateStringByName('PROCEDURE_SCHEM', GetStringByName('PROCEDURE_OWNER')); Result.UpdateStringByName('PROCEDURE_NAME', GetStringByName('PROCEDURE_NAME')); Result.UpdateStringByName('REMARKS', GetStringByName('REMARKS')); Result.UpdateShortByName('PROCEDURE_TYPE', 0); Result.InsertRow; end; Close; end; Result.BeforeFirst; end; {** Gets a description of a catalog's stored procedure parameters and result columns.

Only descriptions matching the schema, procedure and parameter name criteria are returned. They are ordered by PROCEDURE_SCHEM and PROCEDURE_NAME. Within this, the return value, if any, is first. Next are the parameter descriptions in call order. The column descriptions follow in column number order.

Each row in the ResultSet is a parameter description or column description with the following fields:

  1. PROCEDURE_CAT String => procedure catalog (may be null)
  2. PROCEDURE_SCHEM String => procedure schema (may be null)
  3. PROCEDURE_NAME String => procedure name
  4. COLUMN_NAME String => column/parameter name
  5. COLUMN_TYPE Short => kind of column/parameter:
    • procedureColumnUnknown - nobody knows
    • procedureColumnIn - IN parameter
    • procedureColumnInOut - INOUT parameter
    • procedureColumnOut - OUT parameter
    • procedureColumnReturn - procedure return value
    • procedureColumnResult - result column in ResultSet
  6. DATA_TYPE short => SQL type from java.sql.Types
  7. TYPE_NAME String => SQL type name, for a UDT type the type name is fully qualified
  8. PRECISION int => precision
  9. LENGTH int => length in bytes of data
  10. SCALE short => scale
  11. RADIX short => radix
  12. NULLABLE short => can it contain NULL?
    • procedureNoNulls - does not allow NULL values
    • procedureNullable - allows NULL values
    • procedureNullableUnknown - nullability unknown
  13. REMARKS String => comment describing parameter/column

Note: Some databases may not return the column descriptions for a procedure. Additional columns beyond REMARKS can be defined by the database. @param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param procedureNamePattern a procedure name pattern @param columnNamePattern a column name pattern @return ResultSet - each row describes a stored procedure parameter or column @see #getSearchStringEscape } function TZMsSqlDatabaseMetadata.UncachedGetProcedureColumns(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string; const ColumnNamePattern: string): IZResultSet; begin Result:=inherited UncachedGetProcedureColumns(Catalog, SchemaPattern, ProcedureNamePattern, ColumnNamePattern); with GetStatement.ExecuteQuery( Format('exec sp_sproc_columns %s, %s, %s, %s', [ComposeObjectString(ProcedureNamePattern), ComposeObjectString(SchemaPattern), ComposeObjectString(Catalog), ComposeObjectString(ColumnNamePattern)])) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('PROCEDURE_CAT', GetStringByName('PROCEDURE_QUALIFIER')); Result.UpdateStringByName('PROCEDURE_SCHEM', GetStringByName('PROCEDURE_OWNER')); Result.UpdateStringByName('PROCEDURE_NAME', GetStringByName('PROCEDURE_NAME')); Result.UpdateStringByName('COLUMN_NAME', GetStringByName('COLUMN_NAME')); case GetShortByName('COLUMN_TYPE') of 1: Result.UpdateShortByName('COLUMN_TYPE', Ord(pctIn)); 2: Result.UpdateShortByName('COLUMN_TYPE', Ord(pctInOut)); 3: Result.UpdateShortByName('COLUMN_TYPE', Ord(pctUnknown)); 4: Result.UpdateShortByName('COLUMN_TYPE', Ord(pctInOut)); 5: Result.UpdateShortByName('COLUMN_TYPE', Ord(pctReturn)); else Result.UpdateShortByName('COLUMN_TYPE', Ord(pctUnknown)); end; Result.UpdateShortByName('DATA_TYPE', Ord(ConvertODBCToSqlType(GetShortByName('DATA_TYPE'), ConSettings.CPType))); Result.UpdateStringByName('TYPE_NAME', GetStringByName('TYPE_NAME')); Result.UpdateIntByName('PRECISION', GetIntByName('PRECISION')); Result.UpdateIntByName('LENGTH', GetIntByName('LENGTH')); Result.UpdateShortByName('SCALE', GetShortByName('SCALE')); Result.UpdateShortByName('RADIX', GetShortByName('RADIX')); Result.UpdateShortByName('NULLABLE', 2); if GetStringByName('IS_NULLABLE') = 'NO' then Result.UpdateShortByName('NULLABLE', 0); if GetStringByName('IS_NULLABLE') = 'YES' then Result.UpdateShortByName('NULLABLE', 1); Result.UpdateStringByName('REMARKS', GetStringByName('REMARKS')); Result.InsertRow; end; Close; end; Result.BeforeFirst; end; {** Gets a description of tables available in a catalog.

Only table descriptions matching the catalog, schema, table name and type criteria are returned. They are ordered by TABLE_TYPE, TABLE_SCHEM and TABLE_NAME.

Each table description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. TABLE_TYPE String => table type. Typical types are "TABLE", "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM".
  5. REMARKS String => explanatory comment on the table

Note: Some databases may not return information for all tables. @param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param tableNamePattern a table name pattern @param types a list of table types to include; null returns all types @return ResultSet - each row is a table description @see #getSearchStringEscape } function TZMsSqlDatabaseMetadata.UncachedGetTables(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const Types: TStringDynArray): IZResultSet; var I: Integer; TableTypes: string; begin Result:=inherited UncachedGetTables(Catalog, SchemaPattern, TableNamePattern, Types); TableTypes := ''; for I := 0 to Length(Types) - 1 do begin if Length(TableTypes) > 0 then TableTypes := TableTypes + ','; TableTypes := TableTypes + AnsiQuotedStr(Types[I], ''''); end; if TableTypes = '' then TableTypes := 'null' else TableTypes := AnsiQuotedStr(TableTypes, '"'); with GetStatement.ExecuteQuery( Format('exec sp_tables %s, %s, %s, %s', [ComposeObjectString(TableNamePattern), ComposeObjectString(SchemaPattern), ComposeObjectString(Catalog), TableTypes])) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TABLE_CAT', GetStringByName('TABLE_QUALIFIER')); Result.UpdateStringByName('TABLE_SCHEM', GetStringByName('TABLE_OWNER')); Result.UpdateStringByName('TABLE_NAME', GetStringByName('TABLE_NAME')); Result.UpdateStringByName('TABLE_TYPE', GetStringByName('TABLE_TYPE')); Result.UpdateStringByName('REMARKS', GetStringByName('REMARKS')); Result.InsertRow; end; Close; end; Result.BeforeFirst; end; {** Gets the schema names available in this database. The results are ordered by schema name.

The schema column is:

  1. TABLE_SCHEM String => schema name
@return ResultSet - each row has a single String column that is a schema name } function TZMsSqlDatabaseMetadata.UncachedGetSchemas: IZResultSet; begin Result:=inherited UncachedGetSchemas; with GetStatement.ExecuteQuery( 'select name as TABLE_OWNER from sysusers where islogin = 1') do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TABLE_SCHEM', GetStringByName('TABLE_OWNER')); Result.InsertRow; end; Close; end; Result.BeforeFirst; end; {** Gets the catalog names available in this database. The results are ordered by catalog name.

The catalog column is:

  1. TABLE_CAT String => catalog name
@return ResultSet - each row has a single String column that is a catalog name } function TZMsSqlDatabaseMetadata.UncachedGetCatalogs: IZResultSet; begin Result:=inherited UncachedGetCatalogs; with GetStatement.ExecuteQuery('exec sp_databases') do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TABLE_CAT', GetStringByName('DATABASE_NAME')); Result.InsertRow; end; Close; end; Result.BeforeFirst; end; {** Gets the table types available in this database. The results are ordered by table type.

The table type is:

  1. TABLE_TYPE String => table type. Typical types are "TABLE", "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM".
@return ResultSet - each row has a single String column that is a table type } function TZMsSqlDatabaseMetadata.UncachedGetTableTypes: IZResultSet; const TableTypes: array[0..2] of string = ('SYSTEM TABLE', 'TABLE', 'VIEW'); var I: Integer; begin Result:=inherited UncachedGetTableTypes; for I := 0 to 2 do begin Result.MoveToInsertRow; Result.UpdateStringByName('TABLE_TYPE', TableTypes[I]); Result.InsertRow; end; Result.BeforeFirst; end; {** Gets a description of table columns available in the specified catalog.

Only column descriptions matching the catalog, schema, table and column name criteria are returned. They are ordered by TABLE_SCHEM, TABLE_NAME and ORDINAL_POSITION.

Each column description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. COLUMN_NAME String => column name
  5. DATA_TYPE short => SQL type from java.sql.Types
  6. TYPE_NAME String => Data source dependent type name, for a UDT the type name is fully qualified
  7. COLUMN_SIZE int => column size. For char or date types this is the maximum number of characters, for numeric or decimal types this is precision.
  8. BUFFER_LENGTH is not used.
  9. DECIMAL_DIGITS int => the number of fractional digits
  10. NUM_PREC_RADIX int => Radix (typically either 10 or 2)
  11. NULLABLE int => is NULL allowed?
    • columnNoNulls - might not allow NULL values
    • columnNullable - definitely allows NULL values
    • columnNullableUnknown - nullability unknown
  12. REMARKS String => comment describing column (may be null)
  13. COLUMN_DEF String => default value (may be null)
  14. SQL_DATA_TYPE int => unused
  15. SQL_DATETIME_SUB int => unused
  16. CHAR_OCTET_LENGTH int => for char types the maximum number of bytes in the column
  17. ORDINAL_POSITION int => index of column in table (starting at 1)
  18. IS_NULLABLE String => "NO" means column definitely does not allow NULL values; "YES" means the column might allow NULL values. An empty string means nobody knows.
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param tableNamePattern a table name pattern @param columnNamePattern a column name pattern @return ResultSet - each row is a column description @see #getSearchStringEscape } function TZMsSqlDatabaseMetadata.UncachedGetColumns(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const ColumnNamePattern: string): IZResultSet; var SQLType: TZSQLType; begin Result:=inherited UncachedGetColumns(Catalog, SchemaPattern, TableNamePattern, ColumnNamePattern); with GetStatement.ExecuteQuery( Format('exec sp_columns %s, %s, %s, %s', [ComposeObjectString(TableNamePattern), ComposeObjectString(SchemaPattern), ComposeObjectString(Catalog), ComposeObjectString(ColumnNamePattern)])) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TABLE_CAT', GetStringByName('TABLE_QUALIFIER')); Result.UpdateStringByName('TABLE_SCHEM', GetStringByName('TABLE_OWNER')); Result.UpdateStringByName('TABLE_NAME', GetStringByName('TABLE_NAME')); Result.UpdateStringByName('COLUMN_NAME', GetStringByName('COLUMN_NAME')); //The value in the resultset will be used SQLType := ConvertODBCToSqlType(GetShortByName('DATA_TYPE'), ConSettings.CPType); if SQLType = stUnknown then Result.UpdateNullByName('DATA_TYPE') else Result.UpdateShortByName('DATA_TYPE', Ord(SQLType)); if ( SQLType = stBytes) and (UpperCase(GetStringByName('TYPE_NAME')) = 'UNIQUEIDENTIFIER') then Result.UpdateShortByName('DATA_TYPE', Ord(stGUID)); Result.UpdateStringByName('TYPE_NAME', GetStringByName('TYPE_NAME')); Result.UpdateIntByName('COLUMN_SIZE', GetIntByName('LENGTH')); Result.UpdateIntByName('BUFFER_LENGTH', GetIntByName('LENGTH')); Result.UpdateIntByName('DECIMAL_DIGITS', GetIntByName('SCALE')); Result.UpdateIntByName('NUM_PREC_RADIX', GetShortByName('RADIX')); Result.UpdateIntByName('NULLABLE', 2); if GetStringByName('IS_NULLABLE') = 'NO' then Result.UpdateShortByName('NULLABLE', 0); if GetStringByName('IS_NULLABLE') = 'YES' then Result.UpdateShortByName('NULLABLE', 1); Result.UpdateStringByName('REMARKS', GetStringByName('REMARKS')); Result.UpdateStringByName('COLUMN_DEF', GetStringByName('COLUMN_DEF')); Result.UpdateShortByName('SQL_DATA_TYPE', GetShortByName('SQL_DATA_TYPE')); Result.UpdateShortByName('SQL_DATETIME_SUB', GetShortByName('SQL_DATETIME_SUB')); Result.UpdateIntByName('CHAR_OCTET_LENGTH', GetIntByName('CHAR_OCTET_LENGTH')); Result.UpdateIntByName('ORDINAL_POSITION', GetIntByName('ORDINAL_POSITION')); Result.UpdateStringByName('IS_NULLABLE', GetStringByName('IS_NULLABLE')); Result.UpdateBooleanByName('SEARCHABLE', not (GetShortByName('SS_DATA_TYPE') in [34, 35])); Result.InsertRow; end; Close; end; Result.BeforeFirst; with GetStatement.ExecuteQuery( Format('select c.colid, c.name, c.type, c.prec, c.scale, c.colstat,' + ' c.status, c.iscomputed from syscolumns c inner join' + ' sysobjects o on (o.id = c.id) where o.name COLLATE Latin1_General_CS_AS = %s and c.number=0 order by colid', [DeComposeObjectString(TableNamePattern)])) do // hint http://blog.sqlauthority.com/2007/04/30/case-sensitive-sql-query-search/ for the collation setting to get a case sensitive behavior begin while Next do begin Result.Next; Result.UpdateBooleanByName('AUTO_INCREMENT', (GetShortByName('status') and $80) <> 0); Result.UpdateNullByName('CASE_SENSITIVE'); Result.UpdateBooleanByName('SEARCHABLE', Result.GetBooleanByName('SEARCHABLE') and (GetIntByName('iscomputed') = 0)); Result.UpdateBooleanByName('WRITABLE', ((GetShortByName('status') and $80) = 0) (*and (GetShortByName('type') <> 37)*) // <<<< *DEBUG WARUM? and (GetIntByName('iscomputed') = 0)); Result.UpdateBooleanByName('DEFINITELYWRITABLE', Result.GetBooleanByName('WRITABLE')); Result.UpdateBooleanByName('READONLY', not Result.GetBooleanByName('WRITABLE')); if Result.GetBooleanByName('AUTO_INCREMENT') then begin Result.UpdateShortByName('NULLABLE', 1); Result.UpdateStringByName('IS_NULLABLE', 'YES'); end; Result.UpdateRow; end; Close; end; Result.BeforeFirst; end; {** Gets a description of the access rights for a table's columns.

Only privileges matching the column name criteria are returned. They are ordered by COLUMN_NAME and PRIVILEGE.

Each privilige description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. COLUMN_NAME String => column name
  5. GRANTOR => grantor of access (may be null)
  6. GRANTEE String => grantee of access
  7. PRIVILEGE String => name of access (SELECT, INSERT, UPDATE, REFRENCES, ...)
  8. IS_GRANTABLE String => "YES" if grantee is permitted to grant to others; "NO" if not; null if unknown
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @param columnNamePattern a column name pattern @return ResultSet - each row is a column privilege description @see #getSearchStringEscape } function TZMsSqlDatabaseMetadata.UncachedGetColumnPrivileges(const Catalog: string; const Schema: string; const Table: string; const ColumnNamePattern: string): IZResultSet; begin Result:=inherited UncachedGetColumnPrivileges(Catalog, Schema, Table, ColumnNamePattern); with GetStatement.ExecuteQuery( Format('exec sp_column_privileges %s, %s, %s, %s', [ComposeObjectString(Table), ComposeObjectString(Schema), ComposeObjectString(Catalog), ComposeObjectString(ColumnNamePattern)])) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TABLE_CAT', GetStringByName('TABLE_QUALIFIER')); Result.UpdateStringByName('TABLE_SCHEM', GetStringByName('TABLE_OWNER')); Result.UpdateStringByName('TABLE_NAME', GetStringByName('TABLE_NAME')); Result.UpdateStringByName('COLUMN_NAME', GetStringByName('COLUMN_NAME')); Result.UpdateStringByName('GRANTOR', GetStringByName('GRANTOR')); Result.UpdateStringByName('GRANTEE', GetStringByName('GRANTEE')); Result.UpdateStringByName('PRIVILEGE', GetStringByName('PRIVILEGE')); Result.UpdateStringByName('IS_GRANTABLE', GetStringByName('IS_GRANTABLE')); Result.InsertRow; end; Close; end; Result.BeforeFirst; end; {** Gets a description of the access rights for each table available in a catalog. Note that a table privilege applies to one or more columns in the table. It would be wrong to assume that this priviledge applies to all columns (this may be true for some systems but is not true for all.)

Only privileges matching the schema and table name criteria are returned. They are ordered by TABLE_SCHEM, TABLE_NAME, and PRIVILEGE.

Each privilige description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. GRANTOR => grantor of access (may be null)
  5. GRANTEE String => grantee of access
  6. PRIVILEGE String => name of access (SELECT, INSERT, UPDATE, REFRENCES, ...)
  7. IS_GRANTABLE String => "YES" if grantee is permitted to grant to others; "NO" if not; null if unknown
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param tableNamePattern a table name pattern @return ResultSet - each row is a table privilege description @see #getSearchStringEscape } function TZMsSqlDatabaseMetadata.UncachedGetTablePrivileges(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string): IZResultSet; begin Result:=inherited UncachedGetTablePrivileges(Catalog, SchemaPattern, TableNamePattern); with GetStatement.ExecuteQuery( Format('exec sp_table_privileges %s, %s, %s', [ComposeObjectString(TableNamePattern), ComposeObjectString(SchemaPattern), ComposeObjectString(Catalog)])) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TABLE_CAT', GetStringByName('TABLE_QUALIFIER')); Result.UpdateStringByName('TABLE_SCHEM', GetStringByName('TABLE_OWNER')); Result.UpdateStringByName('TABLE_NAME', GetStringByName('TABLE_NAME')); Result.UpdateStringByName('GRANTOR', GetStringByName('GRANTOR')); Result.UpdateStringByName('GRANTEE', GetStringByName('GRANTEE')); Result.UpdateStringByName('PRIVILEGE', GetStringByName('PRIVILEGE')); Result.UpdateStringByName('IS_GRANTABLE', GetStringByName('IS_GRANTABLE')); Result.InsertRow; end; Close; end; Result.BeforeFirst; end; {** Gets a description of a table's columns that are automatically updated when any value in a row is updated. They are unordered.

Each column description has the following columns:

  1. SCOPE short => is not used
  2. COLUMN_NAME String => column name
  3. DATA_TYPE short => SQL data type from java.sql.Types
  4. TYPE_NAME String => Data source dependent type name
  5. COLUMN_SIZE int => precision
  6. BUFFER_LENGTH int => length of column value in bytes
  7. DECIMAL_DIGITS short => scale
  8. PSEUDO_COLUMN short => is this a pseudo column like an Oracle ROWID
    • versionColumnUnknown - may or may not be pseudo column
    • versionColumnNotPseudo - is NOT a pseudo column
    • versionColumnPseudo - is a pseudo column
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a column description @exception SQLException if a database access error occurs } function TZMsSqlDatabaseMetadata.UncachedGetVersionColumns(const Catalog: string; const Schema: string; const Table: string): IZResultSet; var MSCol_Type: string; begin Result:=inherited UncachedGetVersionColumns(Catalog, Schema, Table); MSCol_Type := '''V'''; with GetStatement.ExecuteQuery( Format('exec sp_special_columns %s, %s, %s, %s', [ComposeObjectString(Table), ComposeObjectString(Schema), ComposeObjectString(Catalog), MSCol_Type])) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateShortByName('SCOPE', GetShortByName('SCOPE')); Result.UpdateStringByName('COLUMN_NAME', GetStringByName('COLUMN_NAME')); Result.UpdateShortByName('DATA_TYPE', Ord(ConvertODBCToSqlType(GetShortByName('DATA_TYPE'), ConSettings.CPType))); Result.UpdateStringByName('TYPE_NAME', GetStringByName('TYPE_NAME')); Result.UpdateIntByName('COLUMN_SIZE', GetIntByName('LENGTH')); Result.UpdateIntByName('BUFFER_LENGTH', GetIntByName('LENGTH')); Result.UpdateIntByName('DECIMAL_DIGITS', GetIntByName('SCALE')); Result.UpdateShortByName('PSEUDO_COLUMN', GetShortByName('PSEUDO_COLUMN')); Result.InsertRow; end; Close; end; Result.BeforeFirst; end; {** Gets a description of a table's primary key columns. They are ordered by COLUMN_NAME.

Each primary key column description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. COLUMN_NAME String => column name
  5. KEY_SEQ short => sequence number within primary key
  6. PK_NAME String => primary key name (may be null)
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a primary key column description @exception SQLException if a database access error occurs } function TZMsSqlDatabaseMetadata.UncachedGetPrimaryKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; begin Result:=inherited UncachedGetPrimaryKeys(Catalog, Schema, Table); with GetStatement.ExecuteQuery( Format('exec sp_pkeys %s, %s, %s', [ComposeObjectString(Table), ComposeObjectString(Schema), ComposeObjectString(Catalog)])) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TABLE_CAT', GetStringByName('TABLE_QUALIFIER')); Result.UpdateStringByName('TABLE_SCHEM', GetStringByName('TABLE_OWNER')); Result.UpdateStringByName('TABLE_NAME', GetStringByName('TABLE_NAME')); Result.UpdateStringByName('COLUMN_NAME', GetStringByName('COLUMN_NAME')); Result.UpdateShortByName('KEY_SEQ', GetShortByName('KEY_SEQ')); Result.UpdateStringByName('PK_NAME', GetStringByName('PK_NAME')); Result.InsertRow; end; Close; end; Result.BeforeFirst; end; {** Gets a description of the foreign key columns in the foreign key table that reference the primary key columns of the primary key table (describe how one table imports another's key.) This should normally return a single foreign key/primary key pair (most tables only import a foreign key from a table once.) They are ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, and KEY_SEQ.

Each foreign key column description has the following columns:

  1. PKTABLE_CAT String => primary key table catalog (may be null)
  2. PKTABLE_SCHEM String => primary key table schema (may be null)
  3. PKTABLE_NAME String => primary key table name
  4. PKCOLUMN_NAME String => primary key column name
  5. FKTABLE_CAT String => foreign key table catalog (may be null) being exported (may be null)
  6. FKTABLE_SCHEM String => foreign key table schema (may be null) being exported (may be null)
  7. FKTABLE_NAME String => foreign key table name being exported
  8. FKCOLUMN_NAME String => foreign key column name being exported
  9. KEY_SEQ short => sequence number within foreign key
  10. UPDATE_RULE short => What happens to foreign key when primary is updated:
    • importedNoAction - do not allow update of primary key if it has been imported
    • importedKeyCascade - change imported key to agree with primary key update
    • importedKeySetNull - change imported key to NULL if its primary key has been updated
    • importedKeySetDefault - change imported key to default values if its primary key has been updated
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
  11. DELETE_RULE short => What happens to the foreign key when primary is deleted.
    • importedKeyNoAction - do not allow delete of primary key if it has been imported
    • importedKeyCascade - delete rows that import a deleted key
    • importedKeySetNull - change imported key to NULL if its primary key has been deleted
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
    • importedKeySetDefault - change imported key to default if its primary key has been deleted
  12. FK_NAME String => foreign key name (may be null)
  13. PK_NAME String => primary key name (may be null)
  14. DEFERRABILITY short => can the evaluation of foreign key constraints be deferred until commit
    • importedKeyInitiallyDeferred - see SQL92 for definition
    • importedKeyInitiallyImmediate - see SQL92 for definition
    • importedKeyNotDeferrable - see SQL92 for definition
@param primaryCatalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param primarySchema a schema name; "" retrieves those without a schema @param primaryTable the table name that exports the key @param foreignCatalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param foreignSchema a schema name; "" retrieves those without a schema @param foreignTable the table name that imports the key @return ResultSet - each row is a foreign key column description @see #getImportedKeys } function TZMsSqlDatabaseMetadata.UncachedGetCrossReference(const PrimaryCatalog: string; const PrimarySchema: string; const PrimaryTable: string; const ForeignCatalog: string; const ForeignSchema: string; const ForeignTable: string): IZResultSet; var KeySeq: Integer; begin Result:=inherited UncachedGetCrossReference(PrimaryCatalog, PrimarySchema, PrimaryTable, ForeignCatalog, ForeignSchema, ForeignTable); KeySeq := 0; with GetStatement.ExecuteQuery( Format('exec sp_fkeys %s, %s, %s, %s, %s, %s', [ComposeObjectString(PrimaryTable), ComposeObjectString(PrimarySchema), ComposeObjectString(PrimaryCatalog), ComposeObjectString(ForeignTable), ComposeObjectString(ForeignSchema), ComposeObjectString(ForeignCatalog)])) do begin while Next do begin Inc(KeySeq); Result.MoveToInsertRow; Result.UpdateStringByName('PKTABLE_CAT', GetStringByName('PKTABLE_QUALIFIER')); Result.UpdateStringByName('PKTABLE_SCHEM', GetStringByName('PKTABLE_OWNER')); Result.UpdateStringByName('PKTABLE_NAME', GetStringByName('PKTABLE_NAME')); Result.UpdateStringByName('PKCOLUMN_NAME', GetStringByName('PKCOLUMN_NAME')); Result.UpdateStringByName('FKTABLE_CAT', GetStringByName('FKTABLE_QUALIFIER')); Result.UpdateStringByName('FKTABLE_SCHEM', GetStringByName('FKTABLE_OWNER')); Result.UpdateStringByName('FKTABLE_NAME', GetStringByName('FKTABLE_NAME')); Result.UpdateStringByName('FKCOLUMN_NAME', GetStringByName('FKCOLUMN_NAME')); Result.UpdateShortByName('KEY_SEQ', KeySeq); Result.UpdateShortByName('UPDATE_RULE', GetShortByName('UPDATE_RULE')); Result.UpdateShortByName('DELETE_RULE', GetShortByName('DELETE_RULE')); Result.UpdateStringByName('FK_NAME', GetStringByName('FK_NAME')); Result.UpdateStringByName('PK_NAME', GetStringByName('PK_NAME')); Result.UpdateIntByName('DEFERRABILITY', 0); Result.InsertRow; end; Close; end; Result.BeforeFirst; end; {** Gets a description of all the standard SQL types supported by this database. They are ordered by DATA_TYPE and then by how closely the data type maps to the corresponding JDBC SQL type.

Each type description has the following columns:

  1. TYPE_NAME String => Type name
  2. DATA_TYPE short => SQL data type from java.sql.Types
  3. PRECISION int => maximum precision
  4. LITERAL_PREFIX String => prefix used to quote a literal (may be null)
  5. LITERAL_SUFFIX String => suffix used to quote a literal (may be null)
  6. CREATE_PARAMS String => parameters used in creating the type (may be null)
  7. NULLABLE short => can you use NULL for this type?
    • typeNoNulls - does not allow NULL values
    • typeNullable - allows NULL values
    • typeNullableUnknown - nullability unknown
  8. CASE_SENSITIVE boolean=> is it case sensitive?
  9. SEARCHABLE short => can you use "WHERE" based on this type:
    • typePredNone - No support
    • typePredChar - Only supported with WHERE .. LIKE
    • typePredBasic - Supported except for WHERE .. LIKE
    • typeSearchable - Supported for all WHERE ..
  10. UNSIGNED_ATTRIBUTE boolean => is it unsigned?
  11. FIXED_PREC_SCALE boolean => can it be a money value?
  12. AUTO_INCREMENT boolean => can it be used for an auto-increment value?
  13. LOCAL_TYPE_NAME String => localized version of type name (may be null)
  14. MINIMUM_SCALE short => minimum scale supported
  15. MAXIMUM_SCALE short => maximum scale supported
  16. SQL_DATA_TYPE int => unused
  17. SQL_DATETIME_SUB int => unused
  18. NUM_PREC_RADIX int => usually 2 or 10
@return ResultSet - each row is an SQL type description } function TZMsSqlDatabaseMetadata.UncachedGetTypeInfo: IZResultSet; begin Result:=inherited UncachedGetTypeInfo; with GetStatement.ExecuteQuery('exec sp_datatype_info') do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TYPE_NAME', GetStringByName('TYPE_NAME')); Result.UpdateShortByName('DATA_TYPE', Ord(ConvertODBCToSqlType(GetShortByName('DATA_TYPE'), ConSettings.CPType))); Result.UpdateIntByName('PRECISION', GetIntByName('PRECISION')); Result.UpdateStringByName('LITERAL_PREFIX', GetStringByName('LITERAL_PREFIX')); Result.UpdateStringByName('LITERAL_SUFFIX', GetStringByName('LITERAL_SUFFIX')); Result.UpdateStringByName('CREATE_PARAMS', GetStringByName('CREATE_PARAMS')); Result.UpdateShortByName('NULLABLE', GetShortByName('NULLABLE')); Result.UpdateBooleanByName('CASE_SENSITIVE', GetShortByName('CASE_SENSITIVE') = 1); Result.UpdateShortByName('SEARCHABLE', GetShortByName('SEARCHABLE')); Result.UpdateBooleanByName('UNSIGNED_ATTRIBUTE', GetShortByName('UNSIGNED_ATTRIBUTE') = 1); Result.UpdateBooleanByName('FIXED_PREC_SCALE', GetShortByName('MONEY') = 1); Result.UpdateBooleanByName('AUTO_INCREMENT', GetShortByName('AUTO_INCREMENT') = 1); Result.UpdateStringByName('LOCAL_TYPE_NAME', GetStringByName('LOCAL_TYPE_NAME')); Result.UpdateShortByName('MINIMUM_SCALE', GetShortByName('MINIMUM_SCALE')); Result.UpdateShortByName('MAXIMUM_SCALE', GetShortByName('MAXIMUM_SCALE')); Result.UpdateShortByName('SQL_DATA_TYPE', GetShortByName('SQL_DATA_TYPE')); Result.UpdateShortByName('SQL_DATETIME_SUB', GetShortByName('SQL_DATETIME_SUB')); Result.UpdateShortByName('NUM_PREC_RADIX', GetShortByName('NUM_PREC_RADIX')); Result.InsertRow; end; Close; end; Result.BeforeFirst; end; {** Gets a description of a table's indices and statistics. They are ordered by NON_UNIQUE, TYPE, INDEX_NAME, and ORDINAL_POSITION.

Each index column description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. NON_UNIQUE boolean => Can index values be non-unique? false when TYPE is tableIndexStatistic
  5. INDEX_QUALIFIER String => index catalog (may be null); null when TYPE is tableIndexStatistic
  6. INDEX_NAME String => index name; null when TYPE is tableIndexStatistic
  7. TYPE short => index type:
    • tableIndexStatistic - this identifies table statistics that are returned in conjuction with a table's index descriptions
    • tableIndexClustered - this is a clustered index
    • tableIndexHashed - this is a hashed index
    • tableIndexOther - this is some other style of index
  8. ORDINAL_POSITION short => column sequence number within index; zero when TYPE is tableIndexStatistic
  9. COLUMN_NAME String => column name; null when TYPE is tableIndexStatistic
  10. ASC_OR_DESC String => column sort sequence, "A" => ascending, "D" => descending, may be null if sort sequence is not supported; null when TYPE is tableIndexStatistic
  11. CARDINALITY int => When TYPE is tableIndexStatistic, then this is the number of rows in the table; otherwise, it is the number of unique values in the index.
  12. PAGES int => When TYPE is tableIndexStatisic then this is the number of pages used for the table, otherwise it is the number of pages used for the current index.
  13. FILTER_CONDITION String => Filter condition, if any. (may be null)
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @param unique when true, return only indices for unique values; when false, return indices regardless of whether unique or not @param approximate when true, result is allowed to reflect approximate or out of data values; when false, results are requested to be accurate @return ResultSet - each row is an index column description } function TZMsSqlDatabaseMetadata.UncachedGetIndexInfo(const Catalog: string; const Schema: string; const Table: string; Unique: Boolean; Approximate: Boolean): IZResultSet; var Is_Unique, Accuracy: string; begin Result:=inherited UncachedGetIndexInfo(Catalog, Schema, Table, Unique, Approximate); if Unique then Is_Unique := '''Y''' else Is_Unique := '''N'''; if Approximate then Accuracy := '''Q''' else Accuracy := '''E'''; with GetStatement.ExecuteQuery( Format('exec sp_statistics %s, %s, %s, ''%%'', %s, %s', [ComposeObjectString(Table), ComposeObjectString(Schema), ComposeObjectString(Catalog), Is_Unique, Accuracy])) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TABLE_CAT', GetStringByName('TABLE_QUALIFIER')); Result.UpdateStringByName('TABLE_SCHEM', GetStringByName('TABLE_OWNER')); Result.UpdateStringByName('TABLE_NAME', GetStringByName('TABLE_NAME')); Result.UpdateBooleanByName('NON_UNIQUE', GetShortByName('NON_UNIQUE') = 1); Result.UpdateStringByName('INDEX_QUALIFIER', GetStringByName('INDEX_QUALIFIER')); Result.UpdateStringByName('INDEX_NAME', GetStringByName('INDEX_NAME')); Result.UpdateShortByName('TYPE', GetShortByName('TYPE')); Result.UpdateShortByName('ORDINAL_POSITION', GetShortByName('SEQ_IN_INDEX')); Result.UpdateStringByName('COLUMN_NAME', GetStringByName('COLUMN_NAME')); Result.UpdateStringByName('ASC_OR_DESC', GetStringByName('COLLATION')); Result.UpdateIntByName('CARDINALITY', GetIntByName('CARDINALITY')); Result.UpdateIntByName('PAGES', GetIntByName('PAGES')); Result.UpdateStringByName('FILTER_CONDITION', GetStringByName('FILTER_CONDITION')); Result.InsertRow; end; Close; end; Result.BeforeFirst; end; { TZSybaseDatabaseMetadata } {** Constructs a database information object and returns the interface to it. Used internally by the constructor. @return the database information object interface } function TZSybaseDatabaseMetadata.CreateDatabaseInfo: IZDatabaseInfo; begin Result := TZSybaseDatabaseInfo.Create(Self); end; {** Gets a description of the stored procedures available in a catalog.

Only procedure descriptions matching the schema and procedure name criteria are returned. They are ordered by PROCEDURE_SCHEM, and PROCEDURE_NAME.

Each procedure description has the the following columns:

  1. PROCEDURE_CAT String => procedure catalog (may be null)
  2. PROCEDURE_SCHEM String => procedure schema (may be null)
  3. PROCEDURE_NAME String => procedure name
  4. reserved for future use
  5. reserved for future use
  6. reserved for future use
  7. REMARKS String => explanatory comment on the procedure
  8. PROCEDURE_TYPE short => kind of procedure:
    • procedureResultUnknown - May return a result
    • procedureNoResult - Does not return a result
    • procedureReturnsResult - Returns a result
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param procedureNamePattern a procedure name pattern @return ResultSet - each row is a procedure description @see #getSearchStringEscape } function TZSybaseDatabaseMetadata.UncachedGetProcedures(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string): IZResultSet; begin Result:=inherited UncachedGetProcedures(Catalog, SchemaPattern, ProcedureNamePattern); with GetStatement.ExecuteQuery( Format('exec sp_jdbc_stored_procedures %s, %s, %s', [ComposeObjectString(Catalog), ComposeObjectString(SchemaPattern), ComposeObjectString(ProcedureNamePattern)])) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('PROCEDURE_CAT', GetStringByName('PROCEDURE_CAT')); Result.UpdateStringByName('PROCEDURE_SCHEM', GetStringByName('PROCEDURE_SCHEM')); Result.UpdateStringByName('PROCEDURE_NAME', GetStringByName('PROCEDURE_NAME')); Result.UpdateStringByName('REMARKS', GetStringByName('REMARKS')); Result.UpdateShortByName('PROCEDURE_TYPE', GetShortByName('PROCEDURE_TYPE')); Result.InsertRow; end; Close; end; end; {** Gets a description of a catalog's stored procedure parameters and result columns.

Only descriptions matching the schema, procedure and parameter name criteria are returned. They are ordered by PROCEDURE_SCHEM and PROCEDURE_NAME. Within this, the return value, if any, is first. Next are the parameter descriptions in call order. The column descriptions follow in column number order.

Each row in the ResultSet is a parameter description or column description with the following fields:

  1. PROCEDURE_CAT String => procedure catalog (may be null)
  2. PROCEDURE_SCHEM String => procedure schema (may be null)
  3. PROCEDURE_NAME String => procedure name
  4. COLUMN_NAME String => column/parameter name
  5. COLUMN_TYPE Short => kind of column/parameter:
    • procedureColumnUnknown - nobody knows
    • procedureColumnIn - IN parameter
    • procedureColumnInOut - INOUT parameter
    • procedureColumnOut - OUT parameter
    • procedureColumnReturn - procedure return value
    • procedureColumnResult - result column in ResultSet
  6. DATA_TYPE short => SQL type from java.sql.Types
  7. TYPE_NAME String => SQL type name, for a UDT type the type name is fully qualified
  8. PRECISION int => precision
  9. LENGTH int => length in bytes of data
  10. SCALE short => scale
  11. RADIX short => radix
  12. NULLABLE short => can it contain NULL?
    • procedureNoNulls - does not allow NULL values
    • procedureNullable - allows NULL values
    • procedureNullableUnknown - nullability unknown
  13. REMARKS String => comment describing parameter/column

Note: Some databases may not return the column descriptions for a procedure. Additional columns beyond REMARKS can be defined by the database. @param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param procedureNamePattern a procedure name pattern @param columnNamePattern a column name pattern @return ResultSet - each row describes a stored procedure parameter or column @see #getSearchStringEscape } function TZSybaseDatabaseMetadata.UncachedGetProcedureColumns(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string; const ColumnNamePattern: string): IZResultSet; var ProcNamePart: string; NumberPart: string; status2: Integer; begin Result:=inherited UncachedGetProcedureColumns(Catalog, SchemaPattern, ProcedureNamePattern, ColumnNamePattern); with GetStatement.ExecuteQuery( Format('exec sp_jdbc_getprocedurecolumns %s, %s, %s, %s', [ComposeObjectString(Catalog), ComposeObjectString(SchemaPattern), ComposeObjectString(ProcedureNamePattern), ComposeObjectString(ColumnNamePattern)])) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('PROCEDURE_CAT', GetStringByName('PROCEDURE_CAT')); Result.UpdateStringByName('PROCEDURE_SCHEM', GetStringByName('PROCEDURE_SCHEM')); Result.UpdateStringByName('PROCEDURE_NAME', GetStringByName('PROCEDURE_NAME')); Result.UpdateStringByName('COLUMN_NAME', GetStringByName('COLUMN_NAME')); case GetShortByName('COLUMN_TYPE') of 0, 1: Result.UpdateShortByName('COLUMN_TYPE', Ord(pctIn)); 2: Result.UpdateShortByName('COLUMN_TYPE', Ord(pctInOut)); 3: Result.UpdateShortByName('COLUMN_TYPE', Ord(pctUnknown)); 4: Result.UpdateShortByName('COLUMN_TYPE', Ord(pctInOut)); 5: Result.UpdateShortByName('COLUMN_TYPE', Ord(pctReturn)); else Result.UpdateShortByName('COLUMN_TYPE', Ord(pctUnknown)); end; Result.UpdateShortByName('DATA_TYPE', Ord(ConvertODBCToSqlType(GetShortByName('DATA_TYPE'), ConSettings.CPType))); Result.UpdateStringByName('TYPE_NAME', GetStringByName('TYPE_NAME')); Result.UpdateIntByName('PRECISION', GetIntByName('PRECISION')); Result.UpdateIntByName('LENGTH', GetIntByName('LENGTH')); Result.UpdateShortByName('SCALE', GetShortByName('SCALE')); Result.UpdateShortByName('RADIX', GetShortByName('RADIX')); Result.UpdateShortByName('NULLABLE', GetShortByName('NULLABLE')); Result.UpdateStringByName('REMARKS', GetStringByName('REMARKS')); Result.InsertRow; end; Close; end; Result.BeforeFirst; NumberPart := '1'; ProcNamePart := ''; if AnsiPos(';', ProcNamePart) > 0 then begin NumberPart := Copy(ProcNamePart, LastDelimiter(';', ProcNamePart) + 1, Length(ProcNamePart)); if NumberPart = '' then NumberPart := '1'; ProcNamePart := Copy(ProcNamePart, 1, LastDelimiter(';', ProcNamePart)); if ProcNamePart[Length(ProcNamePart)] = ';' then Delete(ProcNamePart, Length(ProcNamePart), 1); end; //status2 is added in sybase ASE 12.5 to store the storedprocedure parameters // input/output type this column does not exists in prior versions. // In prior versions there is no way to determine between input or output type. with GetStatement.ExecuteQuery( Format('select c.* from syscolumns c inner join sysobjects o on' + ' (o.id = c.id) where o.name = %s and c.number = %s order by colid', [AnsiQuotedStr(ProcNamePart, ''''), NumberPart])) do begin Result.Next;//Skip return parameter while Next do begin Result.Next; if FindColumn('status2') >= 1 then status2 := GetShortByName('status2') else status2 := 0; case status2 of 0, 1: Result.UpdateShortByName('COLUMN_TYPE', Ord(pctIn)); 2: Result.UpdateShortByName('COLUMN_TYPE', Ord(pctInOut)); 3: Result.UpdateShortByName('COLUMN_TYPE', Ord(pctUnknown)); 4: Result.UpdateShortByName('COLUMN_TYPE', Ord(pctInOut)); 5: Result.UpdateShortByName('COLUMN_TYPE', Ord(pctReturn)); else Result.UpdateShortByName('COLUMN_TYPE', Ord(pctUnknown)); end; Result.UpdateRow; end; Close; end; end; {** Gets a description of tables available in a catalog.

Only table descriptions matching the catalog, schema, table name and type criteria are returned. They are ordered by TABLE_TYPE, TABLE_SCHEM and TABLE_NAME.

Each table description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. TABLE_TYPE String => table type. Typical types are "TABLE", "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM".
  5. REMARKS String => explanatory comment on the table

Note: Some databases may not return information for all tables. @param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param tableNamePattern a table name pattern @param types a list of table types to include; null returns all types @return ResultSet - each row is a table description @see #getSearchStringEscape } function TZSybaseDatabaseMetadata.UncachedGetTables(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const Types: TStringDynArray): IZResultSet; var I: Integer; TableTypes: string; begin Result:=inherited UncachedGetTables(Catalog, SchemaPattern, TableNamePattern, Types); TableTypes := ''; for I := 0 to Length(Types) - 1 do begin if TableTypes <> '' then TableTypes := TableTypes + ','; TableTypes := TableTypes + AnsiQuotedStr(Types[I], ''''); end; with GetStatement.ExecuteQuery( Format('exec sp_jdbc_tables %s, %s, %s, %s', [ComposeObjectString(TableNamePattern), ComposeObjectString(SchemaPattern), ComposeObjectString(Catalog), ComposeObjectString(TableTypes)])) do begin while Next do while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TABLE_CAT', GetStringByName('TABLE_CAT')); Result.UpdateStringByName('TABLE_SCHEM', GetStringByName('TABLE_SCHEM')); Result.UpdateStringByName('TABLE_NAME', GetStringByName('TABLE_NAME')); Result.UpdateStringByName('TABLE_TYPE', GetStringByName('TABLE_TYPE')); Result.UpdateStringByName('REMARKS', GetStringByName('REMARKS')); Result.InsertRow; end; Close; end; end; {** Gets the schema names available in this database. The results are ordered by schema name.

The schema column is:

  1. TABLE_SCHEM String => schema name
@return ResultSet - each row has a single String column that is a schema name } function TZSybaseDatabaseMetadata.UncachedGetSchemas: IZResultSet; begin Result:=inherited UncachedGetSchemas; with GetStatement.ExecuteQuery('exec sp_jdbc_getschemas') do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TABLE_SCHEM', GetStringByName('TABLE_SCHEM')); Result.InsertRow; end; Close; end; end; {** Gets the catalog names available in this database. The results are ordered by catalog name.

The catalog column is:

  1. TABLE_CAT String => catalog name
@return ResultSet - each row has a single String column that is a catalog name } function TZSybaseDatabaseMetadata.UncachedGetCatalogs: IZResultSet; begin Result:=inherited UncachedGetCatalogs; with GetStatement.ExecuteQuery('exec sp_jdbc_getcatalogs') do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TABLE_CAT', GetStringByName('TABLE_CAT')); Result.InsertRow; end; Close; end; end; {** Gets the table types available in this database. The results are ordered by table type.

The table type is:

  1. TABLE_TYPE String => table type. Typical types are "TABLE", "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM".
@return ResultSet - each row has a single String column that is a table type } function TZSybaseDatabaseMetadata.UncachedGetTableTypes: IZResultSet; const TableTypes: array[0..2] of string = ('SYSTEM TABLE', 'TABLE', 'VIEW'); var I: Integer; begin Result:=inherited UncachedGetTableTypes; for I := 0 to 2 do begin Result.MoveToInsertRow; Result.UpdateStringByName('TABLE_TYPE', TableTypes[I]); Result.InsertRow; end; end; {** Gets a description of table columns available in the specified catalog.

Only column descriptions matching the catalog, schema, table and column name criteria are returned. They are ordered by TABLE_SCHEM, TABLE_NAME and ORDINAL_POSITION.

Each column description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. COLUMN_NAME String => column name
  5. DATA_TYPE short => SQL type from java.sql.Types
  6. TYPE_NAME String => Data source dependent type name, for a UDT the type name is fully qualified
  7. COLUMN_SIZE int => column size. For char or date types this is the maximum number of characters, for numeric or decimal types this is precision.
  8. BUFFER_LENGTH is not used.
  9. DECIMAL_DIGITS int => the number of fractional digits
  10. NUM_PREC_RADIX int => Radix (typically either 10 or 2)
  11. NULLABLE int => is NULL allowed?
    • columnNoNulls - might not allow NULL values
    • columnNullable - definitely allows NULL values
    • columnNullableUnknown - nullability unknown
  12. REMARKS String => comment describing column (may be null)
  13. COLUMN_DEF String => default value (may be null)
  14. SQL_DATA_TYPE int => unused
  15. SQL_DATETIME_SUB int => unused
  16. CHAR_OCTET_LENGTH int => for char types the maximum number of bytes in the column
  17. ORDINAL_POSITION int => index of column in table (starting at 1)
  18. IS_NULLABLE String => "NO" means column definitely does not allow NULL values; "YES" means the column might allow NULL values. An empty string means nobody knows.
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param tableNamePattern a table name pattern @param columnNamePattern a column name pattern @return ResultSet - each row is a column description @see #getSearchStringEscape } function TZSybaseDatabaseMetadata.UncachedGetColumns(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const ColumnNamePattern: string): IZResultSet; begin Result:=inherited UncachedGetColumns(Catalog, SchemaPattern, TableNamePattern, ColumnNamePattern); with GetStatement.ExecuteQuery( Format('exec sp_jdbc_columns %s, %s, %s, %s', [ComposeObjectString(TableNamePattern), ComposeObjectString(SchemaPattern), ComposeObjectString(Catalog), ComposeObjectString(ColumnNamePattern)])) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TABLE_CAT', ''{GetStringByName('TABLE_CAT')}); Result.UpdateStringByName('TABLE_SCHEM', ''{GetStringByName('TABLE_SCHEM')}); Result.UpdateStringByName('TABLE_NAME', GetStringByName('TABLE_NAME')); Result.UpdateStringByName('COLUMN_NAME', GetStringByName('COLUMN_NAME')); //The value in the resultset will be used // Result.UpdateShortByName('DATA_TYPE', // Ord(ConvertODBCToSqlType(GetShortByName('DATA_TYPE')))); Result.UpdateStringByName('TYPE_NAME', GetStringByName('TYPE_NAME')); Result.UpdateIntByName('COLUMN_SIZE', GetIntByName('COLUMN_SIZE')); Result.UpdateIntByName('BUFFER_LENGTH', GetIntByName('BUFFER_LENGTH')); Result.UpdateIntByName('DECIMAL_DIGITS', GetIntByName('DECIMAL_DIGITS')); Result.UpdateIntByName('NUM_PREC_RADIX', GetShortByName('NUM_PREC_RADIX')); Result.UpdateShortByName('NULLABLE', GetShortByName('NULLABLE')); Result.UpdateStringByName('REMARKS', GetStringByName('REMARKS')); Result.UpdateStringByName('COLUMN_DEF', GetStringByName('COLUMN_DEF')); Result.UpdateShortByName('SQL_DATA_TYPE', GetShortByName('SQL_DATA_TYPE')); Result.UpdateShortByName('SQL_DATETIME_SUB', GetShortByName('SQL_DATETIME_SUB')); Result.UpdateIntByName('CHAR_OCTET_LENGTH', GetIntByName('CHAR_OCTET_LENGTH')); Result.UpdateIntByName('ORDINAL_POSITION', GetIntByName('ORDINAL_POSITION')); Result.UpdateStringByName('IS_NULLABLE', GetStringByName('IS_NULLABLE')); Result.InsertRow; end; Close; end; Result.BeforeFirst; with GetStatement.ExecuteQuery( Format('select c.colid, c.name, c.type, c.prec, c.scale, c.status' + ' from syscolumns c inner join sysobjects o on (o.id = c.id)' + ' where o.name = %s order by colid', [AnsiQuotedStr(TableNamePattern, '''')])) do begin while Next do begin Result.Next; Result.UpdateBooleanByName('AUTO_INCREMENT', (GetShortByName('status') and $80) <> 0); Result.UpdateNullByName('CASE_SENSITIVE'); Result.UpdateBooleanByName('SEARCHABLE', not (GetShortByName('type') in [34, 35])); Result.UpdateBooleanByName('WRITABLE', ((GetShortByName('status') and $80) = 0) (*and (GetShortByName('type') <> 37)*)); // <<<< *DEBUG WARUM? Result.UpdateBooleanByName('DEFINITELYWRITABLE', Result.GetBooleanByName('WRITABLE')); Result.UpdateBooleanByName('READONLY', not Result.GetBooleanByName('WRITABLE')); if Result.GetBooleanByName('AUTO_INCREMENT') then begin Result.UpdateShortByName('NULLABLE', 1); Result.UpdateStringByName('IS_NULLABLE', 'YES'); end; Result.UpdateRow; end; Close; end; end; {** Gets a description of the access rights for a table's columns.

Only privileges matching the column name criteria are returned. They are ordered by COLUMN_NAME and PRIVILEGE.

Each privilige description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. COLUMN_NAME String => column name
  5. GRANTOR => grantor of access (may be null)
  6. GRANTEE String => grantee of access
  7. PRIVILEGE String => name of access (SELECT, INSERT, UPDATE, REFRENCES, ...)
  8. IS_GRANTABLE String => "YES" if grantee is permitted to grant to others; "NO" if not; null if unknown
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @param columnNamePattern a column name pattern @return ResultSet - each row is a column privilege description @see #getSearchStringEscape } function TZSybaseDatabaseMetadata.UncachedGetColumnPrivileges(const Catalog: string; const Schema: string; const Table: string; const ColumnNamePattern: string): IZResultSet; begin Result:=inherited UncachedGetColumnPrivileges(Catalog, Schema, Table, ColumnNamePattern); with GetStatement.ExecuteQuery( Format('exec sp_jdbc_getcolumnprivileges %s, %s, %s, %s', [ComposeObjectString(Catalog), ComposeObjectString(Schema), ComposeObjectString(Table), ComposeObjectString(ColumnNamePattern, '''%''')])) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TABLE_CAT', GetStringByName('TABLE_CAT')); Result.UpdateStringByName('TABLE_SCHEM', GetStringByName('TABLE_SCHEM')); Result.UpdateStringByName('TABLE_NAME', GetStringByName('TABLE_NAME')); Result.UpdateStringByName('COLUMN_NAME', GetStringByName('COLUMN_NAME')); Result.UpdateStringByName('GRANTOR', GetStringByName('GRANTOR')); Result.UpdateStringByName('GRANTEE', GetStringByName('GRANTEE')); Result.UpdateStringByName('PRIVILEGE', GetStringByName('PRIVILEGE')); Result.UpdateStringByName('IS_GRANTABLE', GetStringByName('IS_GRANTABLE')); Result.InsertRow; end; Close; end; end; {** Gets a description of the access rights for each table available in a catalog. Note that a table privilege applies to one or more columns in the table. It would be wrong to assume that this priviledge applies to all columns (this may be true for some systems but is not true for all.)

Only privileges matching the schema and table name criteria are returned. They are ordered by TABLE_SCHEM, TABLE_NAME, and PRIVILEGE.

Each privilige description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. GRANTOR => grantor of access (may be null)
  5. GRANTEE String => grantee of access
  6. PRIVILEGE String => name of access (SELECT, INSERT, UPDATE, REFRENCES, ...)
  7. IS_GRANTABLE String => "YES" if grantee is permitted to grant to others; "NO" if not; null if unknown
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param tableNamePattern a table name pattern @return ResultSet - each row is a table privilege description @see #getSearchStringEscape } function TZSybaseDatabaseMetadata.UncachedGetTablePrivileges(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string): IZResultSet; begin Result:=inherited UncachedGetTablePrivileges(Catalog, SchemaPattern, TableNamePattern); with GetStatement.ExecuteQuery( Format('exec sp_jdbc_gettableprivileges %s, %s, %s', [ComposeObjectString(Catalog), ComposeObjectString(SchemaPattern), ComposeObjectString(TableNamePattern)])) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TABLE_CAT', GetStringByName('TABLE_CAT')); Result.UpdateStringByName('TABLE_SCHEM', GetStringByName('TABLE_SCHEM')); Result.UpdateStringByName('TABLE_NAME', GetStringByName('TABLE_NAME')); Result.UpdateStringByName('GRANTOR', GetStringByName('GRANTOR')); Result.UpdateStringByName('GRANTEE', GetStringByName('GRANTEE')); Result.UpdateStringByName('PRIVILEGE', GetStringByName('PRIVILEGE')); Result.UpdateStringByName('IS_GRANTABLE', GetStringByName('IS_GRANTABLE')); Result.InsertRow; end; Close; end; end; {** Gets a description of a table's columns that are automatically updated when any value in a row is updated. They are unordered.

Each column description has the following columns:

  1. SCOPE short => is not used
  2. COLUMN_NAME String => column name
  3. DATA_TYPE short => SQL data type from java.sql.Types
  4. TYPE_NAME String => Data source dependent type name
  5. COLUMN_SIZE int => precision
  6. BUFFER_LENGTH int => length of column value in bytes
  7. DECIMAL_DIGITS short => scale
  8. PSEUDO_COLUMN short => is this a pseudo column like an Oracle ROWID
    • versionColumnUnknown - may or may not be pseudo column
    • versionColumnNotPseudo - is NOT a pseudo column
    • versionColumnPseudo - is a pseudo column
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a column description @exception SQLException if a database access error occurs } function TZSybaseDatabaseMetadata.UncachedGetVersionColumns(const Catalog: string; const Schema: string; const Table: string): IZResultSet; begin Result:=inherited UncachedGetVersionColumns(Catalog, Schema, Table); with GetStatement.ExecuteQuery( Format('exec sp_jdbc_getversioncolumns %s, %s, %s', [ComposeObjectString(Catalog), ComposeObjectString(Schema), ComposeObjectString(Table)])) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateShortByName('SCOPE', GetShortByName('SCOPE')); Result.UpdateStringByName('COLUMN_NAME', GetStringByName('COLUMN_NAME')); Result.UpdateShortByName('DATA_TYPE', Ord(ConvertODBCToSqlType(GetShortByName('DATA_TYPE'), ConSettings.CPType))); Result.UpdateStringByName('TYPE_NAME', GetStringByName('TYPE_NAME')); Result.UpdateIntByName('COLUMN_SIZE', GetIntByName('COLUMN_SIZE')); Result.UpdateIntByName('BUFFER_LENGTH', GetIntByName('BUFFER_LENGTH')); Result.UpdateIntByName('DECIMAL_DIGITS', GetIntByName('DECIMAL_DIGITS')); Result.UpdateShortByName('PSEUDO_COLUMN', GetShortByName('PSEUDO_COLUMN')); Result.InsertRow; end; Close; end; end; {** Gets a description of a table's primary key columns. They are ordered by COLUMN_NAME.

Each primary key column description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. COLUMN_NAME String => column name
  5. KEY_SEQ short => sequence number within primary key
  6. PK_NAME String => primary key name (may be null)
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a primary key column description @exception SQLException if a database access error occurs } function TZSybaseDatabaseMetadata.UncachedGetPrimaryKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; begin Result:=inherited UncachedGetPrimaryKeys(Catalog, Schema, Table); with GetStatement.ExecuteQuery( Format('exec sp_jdbc_primarykey %s, %s, %s', [ComposeObjectString(Catalog), ComposeObjectString(Schema), ComposeObjectString(Table)])) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TABLE_CAT', GetStringByName('TABLE_CAT')); Result.UpdateStringByName('TABLE_SCHEM', GetStringByName('TABLE_SCHEM')); Result.UpdateStringByName('TABLE_NAME', GetStringByName('TABLE_NAME')); Result.UpdateStringByName('COLUMN_NAME', GetStringByName('COLUMN_NAME')); Result.UpdateShortByName('KEY_SEQ', GetShortByName('KEY_SEQ')); Result.UpdateStringByName('PK_NAME', GetStringByName('PK_NAME')); Result.InsertRow; end; Close; end; end; {** Gets a description of the primary key columns that are referenced by a table's foreign key columns (the primary keys imported by a table). They are ordered by PKTABLE_CAT, PKTABLE_SCHEM, PKTABLE_NAME, and KEY_SEQ.

Each primary key column description has the following columns:

  1. PKTABLE_CAT String => primary key table catalog being imported (may be null)
  2. PKTABLE_SCHEM String => primary key table schema being imported (may be null)
  3. PKTABLE_NAME String => primary key table name being imported
  4. PKCOLUMN_NAME String => primary key column name being imported
  5. FKTABLE_CAT String => foreign key table catalog (may be null)
  6. FKTABLE_SCHEM String => foreign key table schema (may be null)
  7. FKTABLE_NAME String => foreign key table name
  8. FKCOLUMN_NAME String => foreign key column name
  9. KEY_SEQ short => sequence number within foreign key
  10. UPDATE_RULE short => What happens to foreign key when primary is updated:
    • importedNoAction - do not allow update of primary key if it has been imported
    • importedKeyCascade - change imported key to agree with primary key update
    • importedKeySetNull - change imported key to NULL if its primary key has been updated
    • importedKeySetDefault - change imported key to default values if its primary key has been updated
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
  11. DELETE_RULE short => What happens to the foreign key when primary is deleted.
    • importedKeyNoAction - do not allow delete of primary key if it has been imported
    • importedKeyCascade - delete rows that import a deleted key
    • importedKeySetNull - change imported key to NULL if its primary key has been deleted
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
    • importedKeySetDefault - change imported key to default if its primary key has been deleted
  12. FK_NAME String => foreign key name (may be null)
  13. PK_NAME String => primary key name (may be null)
  14. DEFERRABILITY short => can the evaluation of foreign key constraints be deferred until commit
    • importedKeyInitiallyDeferred - see SQL92 for definition
    • importedKeyInitiallyImmediate - see SQL92 for definition
    • importedKeyNotDeferrable - see SQL92 for definition
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a primary key column description @see #getExportedKeys } function TZSybaseDatabaseMetadata.UncachedGetImportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; begin Result:=inherited UncachedGetImportedKeys(Catalog, Schema, Table); with GetStatement.ExecuteQuery( Format('exec sp_jdbc_importkey %s, %s, %s', [ComposeObjectString(Catalog), ComposeObjectString(Schema), ComposeObjectString(Table)])) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('PKTABLE_CAT', GetStringByName('PKTABLE_CAT')); Result.UpdateStringByName('PKTABLE_SCHEM', GetStringByName('PKTABLE_SCHEM')); Result.UpdateStringByName('PKTABLE_NAME', GetStringByName('PKTABLE_NAME')); Result.UpdateStringByName('PKCOLUMN_NAME', GetStringByName('PKCOLUMN_NAME')); Result.UpdateStringByName('FKTABLE_CAT', GetStringByName('FKTABLE_CAT')); Result.UpdateStringByName('FKTABLE_SCHEM', GetStringByName('FKTABLE_SCHEM')); Result.UpdateStringByName('FKTABLE_NAME', GetStringByName('FKTABLE_NAME')); Result.UpdateStringByName('FKCOLUMN_NAME', GetStringByName('FKCOLUMN_NAME')); Result.UpdateShortByName('KEY_SEQ', GetShortByName('KEY_SEQ')); Result.UpdateShortByName('UPDATE_RULE', GetShortByName('UPDATE_RULE')); Result.UpdateShortByName('DELETE_RULE', GetShortByName('DELETE_RULE')); Result.UpdateStringByName('FK_NAME', GetStringByName('FK_NAME')); Result.UpdateStringByName('PK_NAME', GetStringByName('PK_NAME')); Result.UpdateIntByName('DEFERRABILITY', GetIntByName('DEFERRABILITY')); Result.InsertRow; end; Close; end; end; {** Gets a description of the foreign key columns that reference a table's primary key columns (the foreign keys exported by a table). They are ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, and KEY_SEQ.

Each foreign key column description has the following columns:

  1. PKTABLE_CAT String => primary key table catalog (may be null)
  2. PKTABLE_SCHEM String => primary key table schema (may be null)
  3. PKTABLE_NAME String => primary key table name
  4. PKCOLUMN_NAME String => primary key column name
  5. FKTABLE_CAT String => foreign key table catalog (may be null) being exported (may be null)
  6. FKTABLE_SCHEM String => foreign key table schema (may be null) being exported (may be null)
  7. FKTABLE_NAME String => foreign key table name being exported
  8. FKCOLUMN_NAME String => foreign key column name being exported
  9. KEY_SEQ short => sequence number within foreign key
  10. UPDATE_RULE short => What happens to foreign key when primary is updated:
    • importedNoAction - do not allow update of primary key if it has been imported
    • importedKeyCascade - change imported key to agree with primary key update
    • importedKeySetNull - change imported key to NULL if its primary key has been updated
    • importedKeySetDefault - change imported key to default values if its primary key has been updated
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
  11. DELETE_RULE short => What happens to the foreign key when primary is deleted.
    • importedKeyNoAction - do not allow delete of primary key if it has been imported
    • importedKeyCascade - delete rows that import a deleted key
    • importedKeySetNull - change imported key to NULL if its primary key has been deleted
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
    • importedKeySetDefault - change imported key to default if its primary key has been deleted
  12. FK_NAME String => foreign key name (may be null)
  13. PK_NAME String => primary key name (may be null)
  14. DEFERRABILITY short => can the evaluation of foreign key constraints be deferred until commit
    • importedKeyInitiallyDeferred - see SQL92 for definition
    • importedKeyInitiallyImmediate - see SQL92 for definition
    • importedKeyNotDeferrable - see SQL92 for definition
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a foreign key column description @see #getImportedKeys } function TZSybaseDatabaseMetadata.UncachedGetExportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; begin Result:=inherited UncachedGetExportedKeys(Catalog, Schema, Table); with GetStatement.ExecuteQuery( Format('exec sp_jdbc_exportkey %s, %s, %s', [ComposeObjectString(Catalog), ComposeObjectString(Schema), ComposeObjectString(Table)])) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('PKTABLE_CAT', GetStringByName('PKTABLE_CAT')); Result.UpdateStringByName('PKTABLE_SCHEM', GetStringByName('PKTABLE_SCHEM')); Result.UpdateStringByName('PKTABLE_NAME', GetStringByName('PKTABLE_NAME')); Result.UpdateStringByName('PKCOLUMN_NAME', GetStringByName('PKCOLUMN_NAME')); Result.UpdateStringByName('FKTABLE_CAT', GetStringByName('FKTABLE_CAT')); Result.UpdateStringByName('FKTABLE_SCHEM', GetStringByName('FKTABLE_SCHEM')); Result.UpdateStringByName('FKTABLE_NAME', GetStringByName('FKTABLE_NAME')); Result.UpdateStringByName('FKCOLUMN_NAME', GetStringByName('FKCOLUMN_NAME')); Result.UpdateShortByName('KEY_SEQ', GetShortByName('KEY_SEQ')); Result.UpdateShortByName('UPDATE_RULE', GetShortByName('UPDATE_RULE')); Result.UpdateShortByName('DELETE_RULE', GetShortByName('DELETE_RULE')); Result.UpdateStringByName('FK_NAME', GetStringByName('FK_NAME')); Result.UpdateStringByName('PK_NAME', GetStringByName('PK_NAME')); Result.UpdateIntByName('DEFERRABILITY', GetIntByName('DEFERRABILITY')); Result.InsertRow; end; Close; end; end; {** Gets a description of the foreign key columns in the foreign key table that reference the primary key columns of the primary key table (describe how one table imports another's key.) This should normally return a single foreign key/primary key pair (most tables only import a foreign key from a table once.) They are ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, and KEY_SEQ.

Each foreign key column description has the following columns:

  1. PKTABLE_CAT String => primary key table catalog (may be null)
  2. PKTABLE_SCHEM String => primary key table schema (may be null)
  3. PKTABLE_NAME String => primary key table name
  4. PKCOLUMN_NAME String => primary key column name
  5. FKTABLE_CAT String => foreign key table catalog (may be null) being exported (may be null)
  6. FKTABLE_SCHEM String => foreign key table schema (may be null) being exported (may be null)
  7. FKTABLE_NAME String => foreign key table name being exported
  8. FKCOLUMN_NAME String => foreign key column name being exported
  9. KEY_SEQ short => sequence number within foreign key
  10. UPDATE_RULE short => What happens to foreign key when primary is updated:
    • importedNoAction - do not allow update of primary key if it has been imported
    • importedKeyCascade - change imported key to agree with primary key update
    • importedKeySetNull - change imported key to NULL if its primary key has been updated
    • importedKeySetDefault - change imported key to default values if its primary key has been updated
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
  11. DELETE_RULE short => What happens to the foreign key when primary is deleted.
    • importedKeyNoAction - do not allow delete of primary key if it has been imported
    • importedKeyCascade - delete rows that import a deleted key
    • importedKeySetNull - change imported key to NULL if its primary key has been deleted
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
    • importedKeySetDefault - change imported key to default if its primary key has been deleted
  12. FK_NAME String => foreign key name (may be null)
  13. PK_NAME String => primary key name (may be null)
  14. DEFERRABILITY short => can the evaluation of foreign key constraints be deferred until commit
    • importedKeyInitiallyDeferred - see SQL92 for definition
    • importedKeyInitiallyImmediate - see SQL92 for definition
    • importedKeyNotDeferrable - see SQL92 for definition
@param primaryCatalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param primarySchema a schema name; "" retrieves those without a schema @param primaryTable the table name that exports the key @param foreignCatalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param foreignSchema a schema name; "" retrieves those without a schema @param foreignTable the table name that imports the key @return ResultSet - each row is a foreign key column description @see #getImportedKeys } function TZSybaseDatabaseMetadata.UncachedGetCrossReference(const PrimaryCatalog: string; const PrimarySchema: string; const PrimaryTable: string; const ForeignCatalog: string; const ForeignSchema: string; const ForeignTable: string): IZResultSet; begin Result:=inherited UncachedGetCrossReference(PrimaryCatalog, PrimarySchema, PrimaryTable, ForeignCatalog, ForeignSchema, ForeignTable); with GetStatement.ExecuteQuery( Format('exec sp_jdbc_getcrossreferences %s, %s, %s, %s, %s, %s', [ComposeObjectString(PrimaryCatalog), ComposeObjectString(PrimarySchema), ComposeObjectString(PrimaryTable), ComposeObjectString(ForeignCatalog), ComposeObjectString(ForeignSchema), ComposeObjectString(ForeignTable)])) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('PKTABLE_CAT', GetStringByName('PKTABLE_CAT')); Result.UpdateStringByName('PKTABLE_SCHEM', GetStringByName('PKTABLE_SCHEM')); Result.UpdateStringByName('PKTABLE_NAME', GetStringByName('PKTABLE_NAME')); Result.UpdateStringByName('PKCOLUMN_NAME', GetStringByName('PKCOLUMN_NAME')); Result.UpdateStringByName('FKTABLE_CAT', GetStringByName('FKTABLE_CAT')); Result.UpdateStringByName('FKTABLE_SCHEM', GetStringByName('FKTABLE_SCHEM')); Result.UpdateStringByName('FKTABLE_NAME', GetStringByName('FKTABLE_NAME')); Result.UpdateStringByName('FKCOLUMN_NAME', GetStringByName('FKCOLUMN_NAME')); Result.UpdateShortByName('KEY_SEQ', GetShortByName('KEY_SEQ')); Result.UpdateShortByName('UPDATE_RULE', GetShortByName('UPDATE_RULE')); Result.UpdateShortByName('DELETE_RULE', GetShortByName('DELETE_RULE')); Result.UpdateStringByName('FK_NAME', GetStringByName('FK_NAME')); Result.UpdateStringByName('PK_NAME', GetStringByName('PK_NAME')); Result.UpdateIntByName('DEFERRABILITY', GetIntByName('DEFERRABILITY')); Result.InsertRow; end; Close; end; end; {** Gets a description of all the standard SQL types supported by this database. They are ordered by DATA_TYPE and then by how closely the data type maps to the corresponding JDBC SQL type.

Each type description has the following columns:

  1. TYPE_NAME String => Type name
  2. DATA_TYPE short => SQL data type from java.sql.Types
  3. PRECISION int => maximum precision
  4. LITERAL_PREFIX String => prefix used to quote a literal (may be null)
  5. LITERAL_SUFFIX String => suffix used to quote a literal (may be null)
  6. CREATE_PARAMS String => parameters used in creating the type (may be null)
  7. NULLABLE short => can you use NULL for this type?
    • typeNoNulls - does not allow NULL values
    • typeNullable - allows NULL values
    • typeNullableUnknown - nullability unknown
  8. CASE_SENSITIVE boolean=> is it case sensitive?
  9. SEARCHABLE short => can you use "WHERE" based on this type:
    • typePredNone - No support
    • typePredChar - Only supported with WHERE .. LIKE
    • typePredBasic - Supported except for WHERE .. LIKE
    • typeSearchable - Supported for all WHERE ..
  10. UNSIGNED_ATTRIBUTE boolean => is it unsigned?
  11. FIXED_PREC_SCALE boolean => can it be a money value?
  12. AUTO_INCREMENT boolean => can it be used for an auto-increment value?
  13. LOCAL_TYPE_NAME String => localized version of type name (may be null)
  14. MINIMUM_SCALE short => minimum scale supported
  15. MAXIMUM_SCALE short => maximum scale supported
  16. SQL_DATA_TYPE int => unused
  17. SQL_DATETIME_SUB int => unused
  18. NUM_PREC_RADIX int => usually 2 or 10
@return ResultSet - each row is an SQL type description } function TZSybaseDatabaseMetadata.UncachedGetTypeInfo: IZResultSet; begin Result:=inherited UncachedGetTypeInfo; with GetStatement.ExecuteQuery('exec sp_jdbc_datatype_info') do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TYPE_NAME', GetStringByName('TYPE_NAME')); Result.UpdateShortByName('DATA_TYPE', Ord(ConvertODBCToSqlType(GetShortByName('DATA_TYPE'), ConSettings.CPType))); Result.UpdateIntByName('PRECISION', GetIntByName('PRECISION')); Result.UpdateStringByName('LITERAL_PREFIX', GetStringByName('LITERAL_PREFIX')); Result.UpdateStringByName('LITERAL_SUFFIX', GetStringByName('LITERAL_SUFFIX')); Result.UpdateStringByName('CREATE_PARAMS', GetStringByName('CREATE_PARAMS')); Result.UpdateShortByName('NULLABLE', GetShortByName('NULLABLE')); Result.UpdateBooleanByName('CASE_SENSITIVE', GetShortByName('CASE_SENSITIVE') = 1); Result.UpdateShortByName('SEARCHABLE', GetShortByName('SEARCHABLE')); Result.UpdateBooleanByName('UNSIGNED_ATTRIBUTE', GetShortByName('UNSIGNED_ATTRIBUTE') = 1); Result.UpdateBooleanByName('FIXED_PREC_SCALE', GetShortByName('FIXED_PREC_SCALE') = 1); Result.UpdateBooleanByName('AUTO_INCREMENT', GetShortByName('AUTO_INCREMENT') = 1); Result.UpdateStringByName('LOCAL_TYPE_NAME', GetStringByName('LOCAL_TYPE_NAME')); Result.UpdateShortByName('MINIMUM_SCALE', GetShortByName('MINIMUM_SCALE')); Result.UpdateShortByName('MAXIMUM_SCALE', GetShortByName('MAXIMUM_SCALE')); Result.UpdateShortByName('SQL_DATA_TYPE', GetShortByName('SQL_DATA_TYPE')); Result.UpdateShortByName('SQL_DATETIME_SUB', GetShortByName('SQL_DATETIME_SUB')); Result.UpdateShortByName('NUM_PREC_RADIX', GetShortByName('NUM_PREC_RADIX')); Result.InsertRow; end; Close; end; end; {** Gets a description of a table's indices and statistics. They are ordered by NON_UNIQUE, TYPE, INDEX_NAME, and ORDINAL_POSITION.

Each index column description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. NON_UNIQUE boolean => Can index values be non-unique? false when TYPE is tableIndexStatistic
  5. INDEX_QUALIFIER String => index catalog (may be null); null when TYPE is tableIndexStatistic
  6. INDEX_NAME String => index name; null when TYPE is tableIndexStatistic
  7. TYPE short => index type:
    • tableIndexStatistic - this identifies table statistics that are returned in conjuction with a table's index descriptions
    • tableIndexClustered - this is a clustered index
    • tableIndexHashed - this is a hashed index
    • tableIndexOther - this is some other style of index
  8. ORDINAL_POSITION short => column sequence number within index; zero when TYPE is tableIndexStatistic
  9. COLUMN_NAME String => column name; null when TYPE is tableIndexStatistic
  10. ASC_OR_DESC String => column sort sequence, "A" => ascending, "D" => descending, may be null if sort sequence is not supported; null when TYPE is tableIndexStatistic
  11. CARDINALITY int => When TYPE is tableIndexStatistic, then this is the number of rows in the table; otherwise, it is the number of unique values in the index.
  12. PAGES int => When TYPE is tableIndexStatisic then this is the number of pages used for the table, otherwise it is the number of pages used for the current index.
  13. FILTER_CONDITION String => Filter condition, if any. (may be null)
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @param unique when true, return only indices for unique values; when false, return indices regardless of whether unique or not @param approximate when true, result is allowed to reflect approximate or out of data values; when false, results are requested to be accurate @return ResultSet - each row is an index column description } function TZSybaseDatabaseMetadata.UncachedGetIndexInfo(const Catalog: string; const Schema: string; const Table: string; Unique: Boolean; Approximate: Boolean): IZResultSet; var Is_Unique, Accuracy: string; begin Result:=inherited UncachedGetIndexInfo(Catalog, Schema, Table, Unique, Approximate); if Unique then Is_Unique := '''1''' else Is_Unique := '''0'''; if Approximate then Accuracy := '''1''' else Accuracy := '''0'''; with GetStatement.ExecuteQuery( Format('exec sp_jdbc_getindexinfo %s, %s, %s, %s, %s', [ComposeObjectString(Catalog), ComposeObjectString(Schema), ComposeObjectString(Table), Is_Unique, Accuracy])) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TABLE_CAT', GetStringByName('TABLE_CAT')); Result.UpdateStringByName('TABLE_SCHEM', GetStringByName('TABLE_SCHEM')); Result.UpdateStringByName('TABLE_NAME', GetStringByName('TABLE_NAME')); Result.UpdateBooleanByName('NON_UNIQUE', GetShortByName('NON_UNIQUE') = 1); Result.UpdateStringByName('INDEX_QUALIFIER', GetStringByName('INDEX_QUALIFIER')); Result.UpdateStringByName('INDEX_NAME', GetStringByName('INDEX_NAME')); Result.UpdateShortByName('TYPE', GetShortByName('TYPE')); Result.UpdateShortByName('ORDINAL_POSITION', GetShortByName('ORDINAL_POSITION')); Result.UpdateStringByName('COLUMN_NAME', GetStringByName('COLUMN_NAME')); Result.UpdateStringByName('ASC_OR_DESC', GetStringByName('ASC_OR_DESC')); Result.UpdateIntByName('CARDINALITY', GetIntByName('CARDINALITY')); Result.UpdateIntByName('PAGES', GetIntByName('PAGES')); Result.UpdateStringByName('FILTER_CONDITION', GetStringByName('FILTER_CONDITION')); Result.InsertRow; end; Close; end; end; {** Gets a description of the user-defined types defined in a particular schema. Schema-specific UDTs may have type JAVA_OBJECT, STRUCT, or DISTINCT.

Only types matching the catalog, schema, type name and type criteria are returned. They are ordered by DATA_TYPE, TYPE_SCHEM and TYPE_NAME. The type name parameter may be a fully-qualified name. In this case, the catalog and schemaPattern parameters are ignored.

Each type description has the following columns:

  1. TYPE_CAT String => the type's catalog (may be null)
  2. TYPE_SCHEM String => type's schema (may be null)
  3. TYPE_NAME String => type name
  4. CLASS_NAME String => Java class name
  5. DATA_TYPE String => type value defined in java.sql.Types. One of JAVA_OBJECT, STRUCT, or DISTINCT
  6. REMARKS String => explanatory comment on the type

Note: If the driver does not support UDTs, an empty result set is returned. @param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param typeNamePattern a type name pattern; may be a fully-qualified name @param types a list of user-named types to include (JAVA_OBJECT, STRUCT, or DISTINCT); null returns all types @return ResultSet - each row is a type description } function TZSybaseDatabaseMetadata.UncachedGetUDTs(const Catalog: string; const SchemaPattern: string; const TypeNamePattern: string; const Types: TIntegerDynArray): IZResultSet; var I: Integer; UDTypes: string; begin Result:=inherited UncachedGetUDTs(Catalog, SchemaPattern, TypeNamePattern, Types); UDTypes := ''; for I := 0 to Length(Types) - 1 do begin if Length(UDTypes) > 0 then UDTypes := UDTypes + ','; UDTypes := UDTypes + AnsiQuotedStr(IntToStr(Types[I]), ''''); end; with GetStatement.ExecuteQuery( Format('exec sp_jdbc_getudts %s, %s, %s, %s', [ComposeObjectString(Catalog), ComposeObjectString(SchemaPattern, '''%'''), ComposeObjectString(TypeNamePattern, '''%'''), ComposeObjectString(UDTypes)])) do begin while Next do while Next do begin Result.MoveToInsertRow; Result.UpdateStringByName('TYPE_CAT', GetStringByName('TYPE_CAT')); Result.UpdateStringByName('TYPE_SCHEM', GetStringByName('TYPE_SCHEM')); Result.UpdateStringByName('TYPE_NAME', GetStringByName('TYPE_NAME')); Result.UpdateStringByName('JAVA_CLASS', GetStringByName('JAVA_CLASS')); Result.UpdateShortByName('DATA_TYPE', Ord(ConvertODBCToSqlType(GetShortByName('DATA_TYPE'), ConSettings.CPType))); Result.UpdateStringByName('REMARKS', GetStringByName('REMARKS')); Result.InsertRow; end; Close; end; end; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcDbLibResultSet.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { DBLib Resultset common functionality } { } { Originally written by Janos Fegyverneki } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcDbLibResultSet; interface {$I ZDbc.inc} uses {$IFNDEF FPC} DateUtils, {$ENDIF} {$IFDEF WITH_TOBJECTLIST_INLINE}System.Types, System.Contnrs{$ELSE}Types{$ENDIF}, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, ZDbcIntfs, ZDbcResultSet, ZCompatibility, ZDbcResultsetMetadata, ZDbcGenericResolver, ZDbcCachedResultSet, ZDbcCache, ZDbcDBLib, ZPlainDbLibConstants, ZPlainDBLibDriver; type {** Implements DBLib ResultSet. } TZDBLibResultSet = class(TZAbstractResultSet) private FSQL: string; FHandle: PDBPROCESS; DBLibColTypeCache: TSmallIntDynArray; DBLibColumnCount: Integer; procedure CheckColumnIndex(ColumnIndex: Integer); protected FDBLibConnection: IZDBLibConnection; FPlainDriver: IZDBLibPlainDriver; procedure Open; override; function InternalGetString(ColumnIndex: Integer): RawByteString; override; public constructor Create(Statement: IZStatement; SQL: string); destructor Destroy; override; procedure Close; override; function IsNull(ColumnIndex: Integer): Boolean; override; function GetString(ColumnIndex: Integer): String; override; function GetUnicodeString(ColumnIndex: Integer): WideString; override; function GetBoolean(ColumnIndex: Integer): Boolean; override; function GetByte(ColumnIndex: Integer): Byte; override; function GetShort(ColumnIndex: Integer): SmallInt; override; function GetInt(ColumnIndex: Integer): Integer; override; function GetLong(ColumnIndex: Integer): Int64; override; function GetFloat(ColumnIndex: Integer): Single; override; function GetDouble(ColumnIndex: Integer): Double; override; function GetBigDecimal(ColumnIndex: Integer): Extended; override; function GetBytes(ColumnIndex: Integer): TByteDynArray; override; function GetDate(ColumnIndex: Integer): TDateTime; override; function GetTime(ColumnIndex: Integer): TDateTime; override; function GetTimestamp(ColumnIndex: Integer): TDateTime; override; function GetBlob(ColumnIndex: Integer): IZBlob; override; function MoveAbsolute(Row: Integer): Boolean; override; function Next: Boolean; override; end; {** Implements a cached resolver with mssql and sybase specific functionality. } TZDBLibCachedResolver = class (TZGenericCachedResolver, IZCachedResolver) private FAutoColumnIndex: Integer; public constructor Create(Statement: IZStatement; Metadata: IZResultSetMetadata); procedure PostUpdates(Sender: IZCachedResultSet; UpdateType: TZRowUpdateType; OldRowAccessor, NewRowAccessor: TZRowAccessor); override; end; implementation uses ZMessages, ZDbcLogging, ZDbcDBLibUtils, ZEncoding {$IFDEF WITH_UNITANSISTRINGS}, AnsiStrings{$ENDIF} {$IFDEF WITH_WIDESTRUTILS}, WideStrUtils {$ENDIF} ; { TZDBLibResultSet } {** Constructs this object, assignes main properties and opens the record set. @param Statement a related SQL statement object. @param Handle a DBLib specific query handle. } constructor TZDBLibResultSet.Create(Statement: IZStatement; SQL: string); begin inherited Create(Statement, SQL, nil, Statement.GetConnection.GetConSettings); Statement.GetConnection.QueryInterface(IZDBLibConnection, FDBLibConnection); FPlainDriver := FDBLibConnection.GetPlainDriver; FHandle := FDBLibConnection.GetConnectionHandle; FSQL := SQL; Open; end; {** Destroys this object and cleanups the memory. } destructor TZDBLibResultSet.Destroy; begin { TODO -ofjanos -cGeneral : Does it need close here? } Close; inherited Destroy; end; {** Opens this recordset. } procedure TZDBLibResultSet.Open; var I: Integer; ColumnInfo: TZColumnInfo; ColName: string; ColType: Integer; begin //Check if the current statement can return rows if FPlainDriver.dbCmdRow(FHandle) <> DBSUCCEED then raise EZSQLException.Create(SCanNotRetrieveResultSetData); { Fills the column info } ColumnsInfo.Clear; DBLibColumnCount := FPlainDriver.dbnumcols(FHandle); SetLength(DBLibColTypeCache, DBLibColumnCount + 1); for I := 1 to DBLibColumnCount do begin ColName := FPlainDriver.ZDbcString(FPlainDriver.dbColName(FHandle, I), FDBLibConnection.GetConSettings); ColType := FPlainDriver.dbColtype(FHandle, I); ColumnInfo := TZColumnInfo.Create; ColumnInfo.ColumnLabel := ColName; ColumnInfo.ColumnName := ColName; if Self.FDBLibConnection.FreeTDS then ColumnInfo.ColumnType := ConvertFreeTDSToSqlType(ColType, ConSettings.CPType) else ColumnInfo.ColumnType := ConvertDBLibToSqlType(ColType, ConSettings.CPType); ColumnInfo.Currency := (ColType = FPlainDriver.GetVariables.datatypes[Z_SQLMONEY]) or (ColType = FPlainDriver.GetVariables.datatypes[Z_SQLMONEY4]) or (ColType = FPlainDriver.GetVariables.datatypes[Z_SQLMONEYN]);; ColumnInfo.Precision := FPlainDriver.dbCollen(FHandle, I); ColumnInfo.Scale := 0; if ColType = FPlainDriver.GetVariables.datatypes[Z_SQLINT1] then ColumnInfo.Signed := False else ColumnInfo.Signed := True; ColumnsInfo.Add(ColumnInfo); DBLibColTypeCache[I] := ColType; end; inherited Open; end; {** Releases this ResultSet object's database and JDBC resources immediately instead of waiting for this to happen when it is automatically closed.

Note: A ResultSet object is automatically closed by the Statement object that generated it when that Statement object is closed, re-executed, or is used to retrieve the next result from a sequence of multiple results. A ResultSet object is also automatically closed when it is garbage collected. } procedure TZDBLibResultSet.Close; begin { TODO -ofjanos -cGeneral : Maybe it needs a dbcanquery here. } // if Assigned(FHandle) then // if not FPlainDriver.dbDead(FHandle) then // if FPlainDriver.dbCanQuery(FHandle) <> DBSUCCEED then // FDBLibConnection.CheckDBLibError(lcDisconnect, 'CLOSE QUERY'); FHandle := nil; SetLength(DBLibColTypeCache, 0); inherited Close; end; {** Checks if the columnindex is in the proper range. An exception is generated if somthing is not ok. @param columnIndex the first column is 1, the second is 2, ... } procedure TZDBLibResultSet.CheckColumnIndex(ColumnIndex: Integer); begin if (ColumnIndex > DBLibColumnCount) or (ColumnIndex < 1) then begin raise EZSQLException.Create( Format(SColumnIsNotAccessable, [ColumnIndex])); end; end; {** Indicates if the value of the designated column in the current row of this ResultSet object is Null. @param columnIndex the first column is 1, the second is 2, ... @return if the value is SQL NULL, the value returned is true. false otherwise. } function TZDBLibResultSet.IsNull(ColumnIndex: Integer): Boolean; begin CheckClosed; CheckColumnIndex(ColumnIndex); Result := FPlainDriver.dbData(FHandle, ColumnIndex) = nil; end; {** Gets the value of the designated column in the current row of this ResultSet object as a String in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZDBLibResultSet.GetString(ColumnIndex: Integer): String; var Tmp: RawByteString; begin if TZColumnInfo(ColumnsInfo[ColumnIndex-1]).ColumnType in [stString, stUnicodeString, stAsciiStream, stUnicodeStream] then if TZColumnInfo(ColumnsInfo[ColumnIndex-1]).InternalColumnType = stUnknown then begin Tmp := InternalGetString(ColumnIndex); case DetectUTF8Encoding(Tmp) of etUTF8: begin if TZColumnInfo(ColumnsInfo[ColumnIndex-1]).ColumnType in [stString, stUnicodeString] then TZColumnInfo(ColumnsInfo[ColumnIndex-1]).InternalColumnType := stUnicodeString else TZColumnInfo(ColumnsInfo[ColumnIndex-1]).InternalColumnType := stUnicodeStream; Result := ZDbcString(Tmp, zCP_UTF8) end; etAnsi: begin if TZColumnInfo(ColumnsInfo[ColumnIndex-1]).ColumnType in [stString, stUnicodeString] then TZColumnInfo(ColumnsInfo[ColumnIndex-1]).InternalColumnType := stString else TZColumnInfo(ColumnsInfo[ColumnIndex-1]).InternalColumnType := stAsciiStream; Result := ZDbcString(tmp, ConSettings^.ClientCodePage^.CP) end; else Result := ZDbcString(tmp); end; end else if TZColumnInfo(ColumnsInfo[ColumnIndex-1]).InternalColumnType in [stUnicodeString, stUnicodeStream] then Result := ZDbcString(InternalGetString(ColumnIndex), zCP_UTF8) else Result := ZDbcString(InternalGetString(ColumnIndex), ConSettings^.ClientCodePage^.CP) else Result := String(InternalGetString(ColumnIndex)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a WideString in the Delphi programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZDBLibResultSet.GetUnicodeString(ColumnIndex: Integer): WideString; var Tmp: RawByteString; begin if TZColumnInfo(ColumnsInfo[ColumnIndex-1]).ColumnType in [stString, stUnicodeString, stAsciiStream, stUnicodeStream] then if TZColumnInfo(ColumnsInfo[ColumnIndex-1]).InternalColumnType = stUnknown then begin Tmp := InternalGetString(ColumnIndex); case DetectUTF8Encoding(Tmp) of etUTF8: begin if TZColumnInfo(ColumnsInfo[ColumnIndex-1]).ColumnType in [stString, stUnicodeString] then TZColumnInfo(ColumnsInfo[ColumnIndex-1]).InternalColumnType := stUnicodeString else TZColumnInfo(ColumnsInfo[ColumnIndex-1]).InternalColumnType := stUnicodeStream; Result := ZDbcUnicodeString(Tmp, zCP_UTF8) end; etAnsi: begin if TZColumnInfo(ColumnsInfo[ColumnIndex-1]).ColumnType in [stString, stUnicodeString] then TZColumnInfo(ColumnsInfo[ColumnIndex-1]).InternalColumnType := stString else TZColumnInfo(ColumnsInfo[ColumnIndex-1]).InternalColumnType := stAsciiStream; Result := ZDbcUnicodeString(tmp, ConSettings^.ClientCodePage^.CP) end; else Result := ZDbcUnicodeString(tmp); end; end else if TZColumnInfo(ColumnsInfo[ColumnIndex-1]).InternalColumnType in [stUnicodeString, stUnicodeStream] then Result := ZDbcUnicodeString(InternalGetString(ColumnIndex), zCP_UTF8) else Result := ZDbcUnicodeString(InternalGetString(ColumnIndex), ConSettings^.ClientCodePage^.CP) else Result := WideString(InternalGetString(ColumnIndex)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a String in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZDBLibResultSet.InternalGetString(ColumnIndex: Integer): RawByteString; var DL: Integer; Data: Pointer; DT: Integer; begin CheckClosed; CheckColumnIndex(ColumnIndex); DL := FPlainDriver.dbDatLen(FHandle, ColumnIndex); Data := FPlainDriver.dbdata(FHandle, ColumnIndex); DT := DBLibColTypeCache[ColumnIndex]; LastWasNull := Data = nil; Result := ''; if Assigned(Data) then begin if (DT = FPlainDriver.GetVariables.datatypes[Z_SQLCHAR]) or (DT = FPlainDriver.GetVariables.datatypes[Z_SQLTEXT]) then begin while (DL > 0) and (PAnsiChar(NativeUint(Data) + NativeUint(DL - 1))^ = ' ') do Dec(DL); if DL > 0 then begin SetLength(Result, DL); Move(Data^, PAnsiChar(Result)^, DL); end; end else if (DT = FPlainDriver.GetVariables.datatypes[Z_SQLIMAGE]) then begin SetLength(Result, DL); Move(Data^, PAnsiChar(Result)^, DL); end else begin SetLength(Result, 4001); DL := FPlainDriver.dbconvert(FHandle, DT, Data, DL, FPlainDriver.GetVariables.datatypes[Z_SQLCHAR], Pointer(PAnsiChar(Result)), Length(Result)); while (DL > 0) and (Result[DL] = ' ') do Dec(DL); SetLength(Result, DL); end; end; //else FDBLibConnection.CheckDBLibError(lcOther, 'GETSTRING'); end; {** Gets the value of the designated column in the current row of this ResultSet object as a boolean in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is false } function TZDBLibResultSet.GetBoolean(ColumnIndex: Integer): Boolean; var DL: Integer; Data: Pointer; DT: Integer; begin CheckClosed; CheckColumnIndex(ColumnIndex); DL := FPlainDriver.dbdatlen(FHandle, ColumnIndex); Data := FPlainDriver.dbdata(FHandle, ColumnIndex); DT := DBLibColTypeCache[ColumnIndex]; LastWasNull := Data = nil; Result := False; if Assigned(Data) then begin if DT = FPlainDriver.GetVariables.datatypes[Z_SQLBIT] then Result := PBoolean(Data)^ else begin FPlainDriver.dbconvert(FHandle, DT, Data, DL, FPlainDriver.GetVariables.datatypes[Z_SQLBIT], @Result, SizeOf(Result)); end; end; FDBLibConnection.CheckDBLibError(lcOther, 'GETBOOLEAN'); end; {** Gets the value of the designated column in the current row of this ResultSet object as a byte in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZDBLibResultSet.GetByte(ColumnIndex: Integer): Byte; var DL: Integer; Data: Pointer; DT: Integer; begin CheckClosed; CheckColumnIndex(ColumnIndex); DL := FPlainDriver.dbdatlen(FHandle, ColumnIndex); Data := FPlainDriver.dbdata(FHandle, ColumnIndex); DT := DBLibColTypeCache[ColumnIndex]; LastWasNull := Data = nil; Result := 0; if Assigned(Data) then begin if DT = FPlainDriver.GetVariables.datatypes[Z_SQLINT1] then Result := PByte(Data)^ else begin FPlainDriver.dbconvert(FHandle, DT, Data, DL, FPlainDriver.GetVariables.datatypes[Z_SQLINT1], @Result, SizeOf(Result)); end; end; FDBLibConnection.CheckDBLibError(lcOther, 'GETBYTE'); end; {** Gets the value of the designated column in the current row of this ResultSet object as a short in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZDBLibResultSet.GetShort(ColumnIndex: Integer): SmallInt; var DL: Integer; Data: Pointer; DT: Integer; begin CheckClosed; CheckColumnIndex(ColumnIndex); DL := FPlainDriver.dbdatlen(FHandle, ColumnIndex); Data := FPlainDriver.dbdata(FHandle, ColumnIndex); DT := DBLibColTypeCache[ColumnIndex]; LastWasNull := Data = nil; Result := 0; if Assigned(Data) then begin if DT = FPlainDriver.GetVariables.datatypes[Z_SQLINT2] then Result := PSmallInt(Data)^ else begin FPlainDriver.dbconvert(FHandle, DT, Data, DL, FPlainDriver.GetVariables.datatypes[Z_SQLINT2], @Result, SizeOf(Result)); end; end; FDBLibConnection.CheckDBLibError(lcOther, 'GETSHORT'); end; {** Gets the value of the designated column in the current row of this ResultSet object as an int in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZDBLibResultSet.GetInt(ColumnIndex: Integer): Integer; var DL: Integer; Data: Pointer; DT: Integer; begin CheckClosed; CheckColumnIndex(ColumnIndex); DL := FPlainDriver.dbdatlen(FHandle, ColumnIndex); Data := FPlainDriver.dbdata(FHandle, ColumnIndex); DT := DBLibColTypeCache[ColumnIndex]; LastWasNull := Data = nil; Result := 0; if Assigned(Data) then begin if DT = FPlainDriver.GetVariables.datatypes[Z_SQLINT4] then Result := PLongint(Data)^ else begin FPlainDriver.dbconvert(FHandle, DT, Data, DL, FPlainDriver.GetVariables.datatypes[Z_SQLINT4], @Result, SizeOf(Result)); end; end; FDBLibConnection.CheckDBLibError(lcOther, 'GETINT'); end; {** Gets the value of the designated column in the current row of this ResultSet object as a long in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZDBLibResultSet.GetLong(ColumnIndex: Integer): Int64; begin Result := GetInt(ColumnIndex); end; {** Gets the value of the designated column in the current row of this ResultSet object as a float in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZDBLibResultSet.GetFloat(ColumnIndex: Integer): Single; var DL: Integer; Data: Pointer; DT: Integer; begin CheckClosed; CheckColumnIndex(ColumnIndex); DL := FPlainDriver.dbdatlen(FHandle, ColumnIndex); Data := FPlainDriver.dbdata(FHandle, ColumnIndex); DT := DBLibColTypeCache[ColumnIndex]; LastWasNull := Data = nil; Result := 0; if Assigned(Data) then begin if DT = FPlainDriver.GetVariables.datatypes[Z_SQLFLT4] then Result := PSingle(Data)^ else begin FPlainDriver.dbconvert(FHandle, DT, Data, DL, FPlainDriver.GetVariables.datatypes[Z_SQLFLT4], @Result, SizeOf(Result)); end; end; FDBLibConnection.CheckDBLibError(lcOther, 'GETFLOAT'); end; {** Gets the value of the designated column in the current row of this ResultSet object as a double in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZDBLibResultSet.GetDouble(ColumnIndex: Integer): Double; var DL: Integer; Data: Pointer; DT: Integer; begin CheckClosed; CheckColumnIndex(ColumnIndex); DL := FPlainDriver.dbdatlen(FHandle, ColumnIndex); Data := FPlainDriver.dbdata(FHandle, ColumnIndex); DT := DBLibColTypeCache[ColumnIndex]; LastWasNull := Data = nil; Result := 0; if Assigned(Data) then begin if DT = FPlainDriver.GetVariables.datatypes[Z_SQLFLT8] then Result := PDouble(Data)^ else begin FPlainDriver.dbconvert(FHandle, DT, Data, DL, FPlainDriver.GetVariables.datatypes[Z_SQLFLT8], @Result, SizeOf(Result)); end; end; FDBLibConnection.CheckDBLibError(lcOther, 'GETDOUBLE'); end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.BigDecimal in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @param scale the number of digits to the right of the decimal point @return the column value; if the value is SQL NULL, the value returned is null } function TZDBLibResultSet.GetBigDecimal(ColumnIndex: Integer): Extended; begin Result := GetDouble(ColumnIndex); end; {** Gets the value of the designated column in the current row of this ResultSet object as a byte array in the Java programming language. The bytes represent the raw values returned by the driver. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZDBLibResultSet.GetBytes(ColumnIndex: Integer): TByteDynArray; var DL: Integer; Data: Pointer; begin CheckClosed; CheckColumnIndex(ColumnIndex); DL := FPlainDriver.dbdatlen(FHandle, ColumnIndex); Data := FPlainDriver.dbdata(FHandle, ColumnIndex); FDBLibConnection.CheckDBLibError(lcOther, 'GETBYTES'); LastWasNull := Data = nil; SetLength(Result, DL); if Assigned(Data) then Move(PAnsiChar(Data)^, Result[0], DL); end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Date object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZDBLibResultSet.GetDate(ColumnIndex: Integer): TDateTime; begin Result := System.Int(GetTimestamp(ColumnIndex)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Time object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZDBLibResultSet.GetTime(ColumnIndex: Integer): TDateTime; begin Result := Frac(GetTimestamp(ColumnIndex)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null @exception SQLException if a database access error occurs } function TZDBLibResultSet.GetTimestamp(ColumnIndex: Integer): TDateTime; var DL: Integer; Data: Pointer; DT: Integer; TempDate: DBDATETIME; tdsTempDate: TTDSDBDATETIME; begin CheckClosed; CheckColumnIndex(ColumnIndex); DL := FPlainDriver.dbdatlen(FHandle, ColumnIndex); Data := FPlainDriver.dbdata(FHandle, ColumnIndex); DT := DBLibColTypeCache[ColumnIndex]; LastWasNull := Data = nil; Result := 0; if Assigned(Data) then begin if DT = FPlainDriver.GetVariables.datatypes[Z_SQLDATETIME] then if FDBLibConnection.FreeTDS then //type diff Result := PTDSDBDATETIME(Data)^.dtdays + 2 + (PTDSDBDATETIME(Data)^.dttime / 25920000) else Result := PDBDATETIME(Data)^.dtdays + 2 + (PDBDATETIME(Data)^.dttime / 25920000) else if FDBLibConnection.FreeTDS then //type diff begin FPlainDriver.dbconvert(FHandle, DT, Data, DL, FPlainDriver.GetVariables.datatypes[Z_SQLDATETIME], @tdsTempDate, SizeOf(tdsTempDate)); Result := tdsTempDate.dtdays + 2 + (tdsTempDate.dttime / 25920000); end else begin FPlainDriver.dbconvert(FHandle, DT, Data, DL, FPlainDriver.GetVariables.datatypes[Z_SQLDATETIME], @TempDate, SizeOf(TempDate)); Result := TempDate.dtdays + 2 + (TempDate.dttime / 25920000); end; end; FDBLibConnection.CheckDBLibError(lcOther, 'GETTIMESTAMP'); end; {** Returns the value of the designated column in the current row of this ResultSet object as a Blob object in the Java programming language. @param ColumnIndex the first column is 1, the second is 2, ... @return a Blob object representing the SQL BLOB value in the specified column } function TZDBLibResultSet.GetBlob(ColumnIndex: Integer): IZBlob; var DL: Integer; Data: Pointer; TempStream: TStream; TempAnsi: RawByteString; begin CheckClosed; CheckColumnIndex(ColumnIndex); CheckBlobColumn(ColumnIndex); DL := FPlainDriver.dbdatlen(FHandle, ColumnIndex); Data := FPlainDriver.dbdata(FHandle, ColumnIndex); LastWasNull := Data = nil; Result := TZAbstractBlob.CreateWithData(Data, DL, FDBLibConnection); if (GetMetaData.GetColumnType(ColumnIndex) in [stAsciiStream, stUnicodeStream]) then begin TempAnsi := Result.GetString; if ( Length(TempAnsi) = 1) and (TempAnsi[1] = ' ') then TempAnsi := '' else TempAnsi := {$IFDEF WITH_UNITANSISTRINGS}AnsiStrings.{$ENDIF}StringReplace(TempAnsi, #0, '', [rfReplaceAll]); if (GetMetaData.GetColumnType(ColumnIndex) = stAsciiStream ) then Result.SetString(ZEncoding.GetValidatedAnsiString(TempAnsi, ConSettings, True)) else begin if TempAnsi = '' then TempStream := TMemoryStream.Create else TempStream := ZEncoding.GetValidatedUnicodeStream(TempAnsi, ConSettings, True); Result.SetStream(TempStream, True); TempStream.Free; end; end; end; {** Moves the cursor to the given row number in this ResultSet object.

If the row number is positive, the cursor moves to the given row number with respect to the beginning of the result set. The first row is row 1, the second is row 2, and so on.

If the given row number is negative, the cursor moves to an absolute row position with respect to the end of the result set. For example, calling the method absolute(-1) positions the cursor on the last row; calling the method absolute(-2) moves the cursor to the next-to-last row, and so on.

An attempt to position the cursor beyond the first/last row in the result set leaves the cursor before the first row or after the last row.

Note: Calling absolute(1) is the same as calling first(). Calling absolute(-1) is the same as calling last(). @return true if the cursor is on the result set; false otherwise } function TZDBLibResultSet.MoveAbsolute(Row: Integer): Boolean; begin Result := False; RaiseUnsupportedException; end; {** Moves the cursor down one row from its current position. A ResultSet cursor is initially positioned before the first row; the first call to the method next makes the first row the current row; the second call makes the second row the current row, and so on.

If an input stream is open for the current row, a call to the method next will implicitly close it. A ResultSet object's warning chain is cleared when a new row is read. @return true if the new current row is valid; false if there are no more rows } function TZDBLibResultSet.Next: Boolean; begin Result := False; if FPlainDriver.GetProtocol = 'mssql' then if FPlainDriver.dbDead(FHandle) then Exit; //!!! maybe an error message other than dbconnection is dead should be raised case FPlainDriver.dbnextrow(FHandle) of REG_ROW: Result := True; NO_MORE_ROWS: ; DBFAIL: FDBLibConnection.CheckDBLibError(lcOther, 'NEXT'); BUF_FULL: ;//should not happen because we are not using dblibc buffering. else // If a compute row is read, the computeid of the row is returned Result := False; end; end; { TZDBLibCachedResolver } {** Creates a DBLib specific cached resolver object. @param PlainDriver a native DBLib plain driver. @param Handle a DBLib specific query handle. @param Statement a related SQL statement object. @param Metadata a resultset metadata reference. } constructor TZDBLibCachedResolver.Create(Statement: IZStatement; Metadata: IZResultSetMetadata); begin inherited Create(Statement, Metadata); { Defines an index of autoincrement field. } FAutoColumnIndex := -1; end; {** Posts updates to database. @param Sender a cached result set object. @param UpdateType a type of updates. @param OldRowAccessor an accessor object to old column values. @param NewRowAccessor an accessor object to new column values. } procedure TZDBLibCachedResolver.PostUpdates(Sender: IZCachedResultSet; UpdateType: TZRowUpdateType; OldRowAccessor, NewRowAccessor: TZRowAccessor); var Statement: IZStatement; ResultSet: IZResultSet; I: Integer; begin inherited PostUpdates(Sender, UpdateType, OldRowAccessor, NewRowAccessor); { Defines an index of autoincrement field. } if FAutoColumnIndex = -1 then begin FAutoColumnIndex := 0; for I := 1 to Metadata.GetColumnCount do begin if Metadata.IsAutoIncrement(I) then begin FAutoColumnIndex := I; Break; end; end; end; if (UpdateType = utInserted) and (FAutoColumnIndex > 0) and OldRowAccessor.IsNull(FAutoColumnIndex) then begin Statement := Connection.CreateStatement; ResultSet := Statement.ExecuteQuery('SELECT @@IDENTITY'); try if ResultSet.Next then NewRowAccessor.SetLong(FAutoColumnIndex, ResultSet.GetLong(1)); finally ResultSet.Close; Statement.Close; end; end; end; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcDbLibStatement.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { DBLib Statement common functionality } { } { Originally written by Janos Fegyverneki } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcDbLibStatement; interface {$I ZDbc.inc} uses Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, ZCompatibility, ZClasses, ZSysUtils, ZCollections, ZDbcIntfs, ZDbcStatement, ZDbcDbLib, ZPlainDbLibConstants, ZPlainDbLibDriver; type {** Implements Generic DBLib Statement. } TZDBLibStatement = class(TZAbstractStatement) protected FDBLibConnection: IZDBLibConnection; FPlainDriver: IZDBLibPlainDriver; FHandle: PDBPROCESS; FResults: IZCollection; FRetrievedResultSet: IZResultSet; FRetrievedUpdateCount: Integer; procedure InternalExecuteStatement(SQL: RawByteString); procedure FetchResults; virtual; public constructor Create(Connection: IZConnection; Info: TStrings); procedure Close; override; function GetMoreResults: Boolean; override; function ExecuteQuery(const SQL: RawByteString): IZResultSet; override; function ExecuteUpdate(const SQL: RawByteString): Integer; override; function Execute(const SQL: RawByteString): Boolean; override; end; {** Implements Prepared SQL Statement. With emulation} TZDBLibPreparedStatementEmulated = class(TZEmulatedPreparedStatement) private FPlainDriver: IZDBLibPlainDriver; protected function GetEscapeString(Value: string): string; function PrepareAnsiSQLQuery: RawByteString; override; function PrepareAnsiSQLParam(ParamIndex: Integer; const NChar: Boolean): RawByteString; reintroduce; function CreateExecStatement: IZStatement; override; public constructor Create(Connection: IZConnection; SQL: string; Info: TStrings); function GetMetaData: IZResultSetMetaData; override; function ExecuteQueryPrepared: IZResultSet; override; function ExecuteUpdatePrepared: Integer; override; function ExecutePrepared: Boolean; override; end; TZDBLibCallableStatement = class(TZAbstractCallableStatement) private FSQL: string; FDBLibConnection: IZDBLibConnection; FPlainDriver: IZDBLibPlainDriver; FHandle: PDBPROCESS; FLastRowsAffected: Integer;//Workaround for sybase FRetrievedResultSet: IZResultSet; FRetrievedUpdateCount: Integer; procedure FetchResults; virtual; procedure FetchRowCount; virtual; protected procedure SetInParamCount(NewParamCount: Integer); override; public constructor Create(Connection: IZConnection; ProcName: string; Info: TStrings); procedure Close; override; procedure RegisterOutParameter(ParameterIndex: Integer; SqlType: Integer); override; function GetMoreResults: Boolean; override; function ExecuteQueryPrepared: IZResultSet; override; function ExecuteUpdatePrepared: Integer; override; function ExecutePrepared: Boolean; override; end; type {** Interface for storing counter. } IZUpdateCount = interface(IZInterface) ['{03219BB4-E07F-4A50-80CD-291FEA629697}'] procedure SetCount(Value: Integer); function GetCount: Integer; end; TZUpdateCount = class(TInterfacedObject, IZUpdateCount) private FCount: Integer; public constructor Create(ACount: Integer); procedure SetCount(Value: Integer); virtual; function GetCount: Integer; virtual; property Count: Integer read GetCount write SetCount; end; implementation uses Types, ZDbcLogging, ZDbcCachedResultSet, ZDbcDbLibUtils, ZDbcDbLibResultSet, ZVariant{$IFDEF WITH_UNITANSISTRINGS}, AnsiStrings{$ENDIF}; constructor TZUpdateCount.Create(ACount: Integer); begin inherited Create; FCount := ACount; end; procedure TZUpdateCount.SetCount(Value: Integer); begin FCount := Value; end; function TZUpdateCount.GetCount: Integer; begin Result := FCount; end; { TZDBLibStatement } {** Constructs this object and assignes the main properties. @param Connection a database connection object. @param Info a statement parameters. } constructor TZDBLibStatement.Create(Connection: IZConnection; Info: TStrings); begin inherited Create(Connection, Info); Connection.QueryInterface(IZDBLibConnection, FDBLibConnection); if Assigned(FDBLibConnection) then FPLainDriver := FDBLibConnection.GetPlainDriver; FHandle := FDBLibConnection.GetConnectionHandle; ResultSetType := rtScrollInsensitive; FResults := TZCollection.Create; end; procedure TZDBLibStatement.Close; var I: Integer; RS: IZResultSet; begin for i := 0 to FResults.Count -1 do if supports(FResults[i], IZResultSet, RS) then //possible IZUpdateCount RS.Close; FResults.Clear; FRetrievedResultSet := nil; inherited Close; end; {** Executes a Statement. Used internally to execute statements. @param Handle a DBLib connection handle. @sql string containing the statements to execute } procedure TZDBLibStatement.InternalExecuteStatement(SQL: RawByteString); var Ansi: RawByteString; begin if FDBLibConnection.GetProvider = dpMsSQL then //This one is to avoid a bug in dblib interface as it drops a single backslash before line end Ansi := {$IFDEF WITH_UNITANSISTRINGS}AnsiStrings.{$ENDIF}StringReplace(SQL, '\'#13, '\\'#13, [rfReplaceAll]) else //This one is to avoid sybase error: Invalid operator for datatype op: is null type: VOID TYPE Ansi := {$IFDEF WITH_UNITANSISTRINGS}AnsiStrings.{$ENDIF}StringReplace(SQL, ' AND NULL IS NULL', '', [rfReplaceAll]); FHandle := FDBLibConnection.GetConnectionHandle; FPlainDriver := FDBLibConnection.GetPlainDriver; if FPlainDriver.dbcancel(FHandle) <> DBSUCCEED then FDBLibConnection.CheckDBLibError(lcExecute, LogSQL); if FPlainDriver.dbcmd(FHandle, PAnsiChar(Ansi)) <> DBSUCCEED then FDBLibConnection.CheckDBLibError(lcExecute, LogSQL); if FPlainDriver.dbsqlexec(FHandle) <> DBSUCCEED then FDBLibConnection.CheckDBLibError(lcExecute, LogSQL); DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, LogSQL); end; {** Moves to a Statement object's next result. It returns true if this result is a ResultSet object. This method also implicitly closes any current ResultSet object obtained with the method getResultSet.

There are no more results when the following is true:

        (!getMoreResults() && (getUpdateCount() == -1)
  
@return true if the next result is a ResultSet object; false if it is an update count or there are no more results @see #execute } function TZDBLibStatement.GetMoreResults: Boolean; var ResultSet: IZResultSet; UpdateCount: IZUpdateCount; begin Result := False; FRetrievedResultSet := nil; FRetrievedUpdateCount := -1; if FResults.Count > 0 then begin try Result := FResults.Items[0].QueryInterface(IZResultSet, ResultSet) = 0; if Result then begin FRetrievedResultSet := ResultSet; FRetrievedUpdateCount := 0; end else begin if FResults.Items[0].QueryInterface(IZUpdateCount, UpdateCount) = 0 then FRetrievedUpdateCount := UpdateCount.GetCount; end; FResults.Delete(0); finally ResultSet := nil; UpdateCount := nil; end; end; end; {** Fetches all results and creates a cachedresultset object for each resultset and a ZUpdateCount object for each count value. } procedure TZDBLibStatement.FetchResults; var NativeResultSet: TZDBLibResultSet; CachedResultSet: TZCachedResultSet; RS: IZResultSet; RowsAffected: Integer; begin for RowsAffected := 0 to FResults.Count -1 do if Supports(FResults[RowsAffected], IZResultSet, RS) then RS.Close; FResults.Clear; //Sybase does not seem to return dbCount at all, so a workaround is made RowsAffected := -2; while FPlainDriver.dbresults(FHandle) = DBSUCCEED do begin if FPlainDriver.dbcmdrow(FHandle) = DBSUCCEED then begin NativeResultSet := TZDBLibResultSet.Create(Self, LogSQL); NativeResultSet.SetConcurrency(rcReadOnly); CachedResultSet := TZCachedResultSet.Create(NativeResultSet, LogSQL, TZDBLibCachedResolver.Create(Self, NativeResultSet.GetMetaData), ConSettings); CachedResultSet.SetType(rtScrollInsensitive);//!!!Cached resultsets are allways this CachedResultSet.Last; CachedResultSet.BeforeFirst; //!!!Just to invoke fetchall CachedResultSet.SetConcurrency(GetResultSetConcurrency); FResults.Add(CachedResultSet); end else begin RowsAffected := FPlainDriver.dbCount(FHandle); if RowsAffected > -1 then FResults.Add(TZUpdateCount.Create(RowsAffected)); end; FPlainDriver.dbCanQuery(FHandle); end; FDBLibConnection.CheckDBLibError(lcOther, 'FETCHRESULTS'); if not FDBLibConnection.FreeTDS then if RowsAffected = -1 then begin FDBLibConnection.InternalExecuteStatement('select @@rowcount'); try FPlainDriver.dbresults(FHandle); NativeResultSet := TZDBLibResultSet.Create(Self, 'select @@rowcount'); try if NativeResultset.Next then RowsAffected := NativeResultSet.GetInt(1); finally NativeResultSet.Close; end; FResults.Add(TZUpdateCount.Create(RowsAffected)); finally FPlainDriver.dbCancel(FHandle); end; FDBLibConnection.CheckDBLibError(lcOther, 'FETCHRESULTS'); end; end; {** Executes an SQL statement that returns a single ResultSet object. @param sql typically this is a static SQL SELECT statement @return a ResultSet object that contains the data produced by the given query; never null } function TZDBLibStatement.ExecuteQuery(const SQL: RawByteString): IZResultSet; begin Result := nil; if ASQL <> SQL then ASQL := SQL; try InternalExecuteStatement(ASQL); FetchResults; repeat if GetMoreResults then Result := FRetrievedResultSet else if FRetrievedUpdateCount = -1 then Break; until False; finally FRetrievedResultSet := nil; end; end; {** Executes an SQL INSERT, UPDATE or DELETE statement. In addition, SQL statements that return nothing, such as SQL DDL statements, can be executed. @param sql an SQL INSERT, UPDATE or DELETE statement or an SQL statement that returns nothing @return either the row count for INSERT, UPDATE or DELETE statements, or 0 for SQL statements that return nothing } function TZDBLibStatement.ExecuteUpdate(const SQL: RawByteString): Integer; begin if ASQL <> SQL then ASQL := SQL; InternalExecuteStatement(ASQL); FetchResults; GetMoreResults; Result := FRetrievedUpdateCount; FRetrievedResultSet := nil; end; {** Executes an SQL statement that may return multiple results. Under some (uncommon) situations a single SQL statement may return multiple result sets and/or update counts. Normally you can ignore this unless you are (1) executing a stored procedure that you know may return multiple results or (2) you are dynamically executing an unknown SQL string. The methods execute, getMoreResults, getResultSet, and getUpdateCount let you navigate through multiple results. The execute method executes an SQL statement and indicates the form of the first result. You can then use the methods getResultSet or getUpdateCount to retrieve the result, and getMoreResults to move to any subsequent result(s). @param sql any SQL statement @return true if the next result is a ResultSet object; false if it is an update count or there are no more results } function TZDBLibStatement.Execute(const SQL: RawByteString): Boolean; begin if ASQL <> SQL then ASQL := SQL; InternalExecuteStatement(ASQL); FetchResults; Result := GetMoreResults; LastResultSet := FRetrievedResultSet; LastUpdateCount := FRetrievedUpdateCount; FRetrievedResultSet := nil; end; { TZDBLibPreparedStatementEmulated } {** Constructs this object and assignes the main properties. @param Connection a database connection object. @param Info a statement parameters. @param Handle a connection handle pointer. } constructor TZDBLibPreparedStatementEmulated.Create(Connection: IZConnection; SQL: string; Info: TStrings); begin inherited Create(Connection, SQL, Info); FPlainDriver := (Connection as IZDBLibConnection).GetPlainDriver; ResultSetType := rtScrollInsensitive; FNeedNCharDetection := True; end; {** Converts an string into escape DBLib format. @param Value a regular string. @return a string in DBLib escape format. } function TZDBLibPreparedStatementEmulated.GetEscapeString(Value: string): string; begin Result := AnsiQuotedStr(Value, ''''); end; function TZDBLibPreparedStatementEmulated.PrepareAnsiSQLQuery: RawByteString; var I: Integer; ParamIndex: Integer; Tokens: TStrings; begin ParamIndex := 0; Result := ''; Tokens := TokenizeSQLQuery; for I := 0 to Tokens.Count - 1 do begin if Tokens[I] = '?' then begin Result := Result + PrepareAnsiSQLParam(ParamIndex, ((i > 0) and (Tokens[i-1] = 'N'))); Inc(ParamIndex); end else Result := Result + ZPlainString(Tokens[I]); end; {$IFNDEF UNICODE} if GetConnection.AutoEncodeStrings then Result := GetConnection.GetDriver.GetTokenizer.GetEscapeString(Result); {$ENDIF} end; {** Prepares an SQL parameter for the query. @param ParameterIndex the first parameter is 1, the second is 2, ... @return a string representation of the parameter. } function TZDBLibPreparedStatementEmulated.PrepareAnsiSQLParam(ParamIndex: Integer; const NChar: Boolean): RawByteString; begin if InParamCount <= ParamIndex then Result := 'NULL' else begin Result := PrepareSQLParameter(InParamValues[ParamIndex], InParamTypes[ParamIndex], ConSettings, FPlainDriver, NChar); end; end; {** Gets the number, types and properties of a ResultSet object's columns. @return the description of a ResultSet object's columns } function TZDBLibPreparedStatementEmulated.GetMetaData: IZResultSetMetaData; begin Result := nil; end; {** Executes the SQL query in this PreparedStatement object and returns the result set generated by the query. @return a ResultSet object that contains the data produced by the query; never null } function TZDBLibPreparedStatementEmulated.ExecutePrepared: Boolean; begin Result := inherited Execute(PrepareAnsiSQLQuery); end; {** Executes the SQL query in this PreparedStatement object and returns the result set generated by the query. @return a ResultSet object that contains the data produced by the query; never null } function TZDBLibPreparedStatementEmulated.ExecuteQueryPrepared: IZResultSet; begin Result := inherited ExecuteQuery(PrepareAnsiSQLQuery); end; {** Executes the SQL INSERT, UPDATE or DELETE statement in this PreparedStatement object. In addition, SQL statements that return nothing, such as SQL DDL statements, can be executed. @return either the row count for INSERT, UPDATE or DELETE statements; or 0 for SQL statements that return nothing } function TZDBLibPreparedStatementEmulated.ExecuteUpdatePrepared: Integer; begin Result := inherited ExecuteUpdate(PrepareAnsiSQLQuery); end; {** Creates a temporary statement which executes queries. @param Info a statement parameters. @return a created statement object. } function TZDBLibPreparedStatementEmulated.CreateExecStatement: IZStatement; begin Result := TZDBLibStatement.Create(Connection, Info); end; constructor TZDBLibCallableStatement.Create(Connection: IZConnection; ProcName: string; Info: TStrings); begin inherited Create(Connection, ProcName, Info); Connection.QueryInterface(IZDBLibConnection, FDBLibConnection); if Assigned(FDBLibConnection) then FPLainDriver := FDBLibConnection.GetPlainDriver; FHandle := FDBLibConnection.GetConnectionHandle; ResultSetType := rtScrollInsensitive; end; procedure TZDBLibCallableStatement.Close; begin FRetrievedResultSet := nil; inherited Close; end; procedure TZDBLibCallableStatement.FetchResults; var NativeResultSet: TZDBLibResultSet; CachedResultSet: TZCachedResultSet; begin //Sybase does not seem to return dbCount at all, so a workaround is made FLastRowsAffected := -2; while FPlainDriver.dbresults(FHandle) = DBSUCCEED do begin if FPlainDriver.dbcmdrow(FHandle) = DBSUCCEED then begin NativeResultSet := TZDBLibResultSet.Create(Self, FSQL); NativeResultSet.SetConcurrency(rcReadOnly); CachedResultSet := TZCachedResultSet.Create(NativeResultSet, FSQL, TZDBLibCachedResolver.Create(Self, NativeResultSet.GetMetaData), ConSettings); CachedResultSet.SetType(rtScrollInsensitive);//!!!Cached resultsets are allways this CachedResultSet.Last; CachedResultSet.BeforeFirst; //!!!Just to invoke fetchall CachedResultSet.SetConcurrency(GetResultSetConcurrency); FResultSets.Add(CachedResultSet); end else begin FLastRowsAffected := FPlainDriver.dbCount(FHandle); if FLastRowsAffected > -1 then FResultSets.Add(TZUpdateCount.Create(FLastRowsAffected)); end; end; FDBLibConnection.CheckDBLibError(lcOther, 'FETCHRESULTS'); end; procedure TZDBLibCallableStatement.FetchRowCount; var NativeResultSet: TZDBLibResultSet; begin //Sybase does not seem to return dbCount at all, so a workaround is made if FLastRowsAffected = -1 then begin FDBLibConnection.InternalExecuteStatement('select @@rowcount'); try FPlainDriver.dbresults(FHandle); NativeResultSet := TZDBLibResultSet.Create(Self, 'select @@rowcount'); try if NativeResultset.Next then FLastRowsAffected := NativeResultSet.GetInt(1); finally NativeResultset.Close; end; FResultSets.Add(TZUpdateCount.Create(FLastRowsAffected)); finally FPlainDriver.dbCancel(FHandle); end; FDBLibConnection.CheckDBLibError(lcOther, 'FETCHRESULTS'); end; end; {** Moves to a Statement object's next result. It returns true if this result is a ResultSet object. This method also implicitly closes any current ResultSet object obtained with the method getResultSet.

There are no more results when the following is true:

        (!getMoreResults() && (getUpdateCount() == -1)
  
@return true if the next result is a ResultSet object; false if it is an update count or there are no more results @see #execute } function TZDBLibCallableStatement.GetMoreResults: Boolean; var ResultSet: IZResultSet; UpdateCount: IZUpdateCount; begin Result := False; FRetrievedResultSet := nil; FRetrievedUpdateCount := -1; if FResultSets.Count > 0 then begin try Result := Supports(FResultSets[0], IZResultSet, ResultSet); if Result then begin FRetrievedResultSet := ResultSet; FRetrievedUpdateCount := 0; end else if Supports(FResultSets[0], IZUpdateCount, UpdateCount) then FRetrievedUpdateCount := UpdateCount.GetCount; FResultSets.Delete(0); finally ResultSet := nil; UpdateCount := nil; end; end; end; function TZDBLibCallableStatement.ExecuteQueryPrepared: IZResultSet; begin if not ExecutePrepared then while not GetMoreResults and (FRetrievedUpdateCount <> -1) do; Result := FRetrievedResultSet; FRetrievedResultSet := nil; end; function TZDBLibCallableStatement.ExecuteUpdatePrepared: Integer; begin if ExecutePrepared then while GetMoreResults and (FRetrievedUpdateCount = -1) do; Result := FRetrievedUpdateCount; FRetrievedResultSet := nil; end; procedure TZDBLibCallableStatement.RegisterOutParameter(ParameterIndex: Integer; SqlType: Integer); begin SetOutParamCount(ParameterIndex); OutParamTypes[ParameterIndex - 1] := TZSqlType(SqlType); //Count inparams must equal count outparams to correct set paramters if InParamCount < ParameterIndex then SetInParamCount(ParameterIndex); end; function TZDBLibCallableStatement.ExecutePrepared: Boolean; var S: RawByteString; I, ParamIndex, DatLen: Integer; RetParam: Byte; DatBoolean: Boolean; DatByte: Byte; DatShort: SmallInt; DatInteger: Integer; DatFloat: Single; DatDouble: Double; DatString: RawByteString; DatMoney: Currency; DatDBDATETIME: DBDATETIME; DatBytes: TByteDynArray; Temp: TZVariant; ParamType: TZSQLType; TempBlob: IZBlob; begin S := {$IFDEF WITH_UNITANSISTRINGS}AnsiStrings.{$ENDIF}Trim(ASql); if FPLainDriver.dbRPCInit(FHandle, Pointer(S), 0) <> DBSUCCEED then FDBLibConnection.CheckDBLibError(lcOther, 'EXECUTEPREPARED:dbRPCInit'); for I := 1 to InParamCount - 1 do//The 0 parameter is the return value begin RetParam := 0; if OutParamTypes[I] <> stUnknown then RetParam := DBRPCRETURN; ParamType := InParamTypes[I]; if ParamType = stUnknown then ParamType := OutParamTypes[I]; if DefVarManager.IsNull(InParamValues[I]) and (InParamTypes[I] <> stUnknown) then begin if FDBLibConnection.FreeTDS then FPlainDriver.dbRpcParam(FHandle, nil, RetParam, ConvertSqlTypeToFreeTDSType(InParamTypes[I]), -1, 0, nil) else FPlainDriver.dbRpcParam(FHandle, nil, RetParam, ConvertSqlTypeToDBLibType(InParamTypes[I]), -1, 0, nil) end else begin case ParamType of stBoolean: begin DatBoolean := SoftVarManager.GetAsBoolean(InParamValues[I]); FPlainDriver.dbRpcParam(FHandle, nil, RetParam, FPlainDriver.GetVariables.datatypes[Z_SQLINT1], -1, -1, @DatBoolean); end; stByte: begin DatByte := Byte(SoftVarManager.GetAsInteger(InParamValues[I])); FPlainDriver.dbRpcParam(FHandle, nil, RetParam, FPlainDriver.GetVariables.datatypes[Z_SQLINT1], -1, -1, @DatByte); end; stShort: begin DatShort := SmallInt(SoftVarManager.GetAsInteger(InParamValues[I])); FPlainDriver.dbRpcParam(FHandle, nil, RetParam, FPlainDriver.GetVariables.datatypes[Z_SQLINT2], -1, -1, @DatShort); end; stInteger, stLong: begin DatInteger := Integer(SoftVarManager.GetAsInteger(InParamValues[I])); FPlainDriver.dbRpcParam(FHandle, nil, RetParam, FPlainDriver.GetVariables.datatypes[Z_SQLINT4], -1, -1, @DatInteger); end; stFloat: begin DatFloat := SoftVarManager.GetAsFloat(InParamValues[I]); FPlainDriver.dbRpcParam(FHandle, nil, RetParam, FPlainDriver.GetVariables.datatypes[Z_SQLFLT4], -1, -1, @DatFloat); end; stDouble, stBigDecimal: begin DatDouble := SoftVarManager.GetAsFloat(InParamValues[I]); FPlainDriver.dbRpcParam(FHandle, nil, RetParam, FPlainDriver.GetVariables.datatypes[Z_SQLFLT8], -1, -1, @DatDouble); end; stString: begin DatString := ZPlainString(SoftVarManager.GetAsString(InParamValues[I])); if DatString = ''then DatLen := 1 else DatLen := Length(DatString); FPlainDriver.dbRpcParam(FHandle, nil, RetParam, FPlainDriver.GetVariables.datatypes[Z_SQLCHAR], MaxInt, DatLen, PAnsiChar(DatString)); end; stUnicodeString: begin DatString := UTF8Encode(SoftVarManager.GetAsUnicodeString(InParamValues[I])); if DatString = '' then DatLen := 1 else DatLen := Length(DatString); FPlainDriver.dbRpcParam(FHandle, nil, RetParam, FPlainDriver.GetVariables.datatypes[Z_SQLCHAR], MaxInt, DatLen, PAnsiChar(DatString)); end; stDate: begin DatString := AnsiString(FormatDateTime('yyyymmdd', SoftVarManager.GetAsDateTime(InParamValues[I]))); FPlainDriver.dbRpcParam(FHandle, nil, RetParam, FPlainDriver.GetVariables.datatypes[Z_SQLCHAR], MaxInt, Length(DatString), PAnsiChar(DatString)); end; stTime: begin DatString := AnsiString(FormatDateTime('hh":"mm":"ss":"zzz', SoftVarManager.GetAsDateTime(InParamValues[I]))); FPlainDriver.dbRpcParam(FHandle, nil, RetParam, FPlainDriver.GetVariables.datatypes[Z_SQLCHAR], MaxInt, Length(DatString), PAnsiChar(DatString)); end; stTimeStamp: begin DatString := AnsiString(FormatDateTime('yyyymmdd hh":"mm":"ss":"zzz', SoftVarManager.GetAsDateTime(InParamValues[I]))); FPlainDriver.dbRpcParam(FHandle, nil, RetParam, FPlainDriver.GetVariables.datatypes[Z_SQLCHAR], MaxInt, Length(DatString), PAnsiChar(DatString)); end; stAsciiStream, stUnicodeStream, stBinaryStream: begin TempBlob := SoftVarManager.GetAsInterface(InParamValues[I]) as IZBlob; DatString := TempBlob.GetString; if DatString = '' then DatLen := 1 else DatLen := Length(DatString); if ParamType = stBinaryStream then FPlainDriver.dbRpcParam(FHandle, nil, RetParam, FPlainDriver.GetVariables.datatypes[Z_SQLBINARY], MaxInt, Length(DatString), PAnsiChar(DatString)) else FPlainDriver.dbRpcParam(FHandle, nil, RetParam, FPlainDriver.GetVariables.datatypes[Z_SQLTEXT], FPlainDriver.GetVariables.dboptions[Z_TEXTSIZE], DatLen, PAnsiChar(DatString)); end; stBytes: begin DatString := AnsiString(SoftVarManager.GetAsString(InParamValues[I])); FPlainDriver.dbRpcParam(FHandle, nil, RetParam, FPlainDriver.GetVariables.datatypes[Z_SQLBINARY], MaxInt, Length(DatString), PAnsiChar(DatString)); end; else FPlainDriver.dbRpcParam(FHandle, nil, 0, FPlainDriver.GetVariables.datatypes[Z_SQLCHAR], 0, 0, nil); end; end; end; if FPLainDriver.dbRpcExec(FHandle) <> DBSUCCEED then FDBLibConnection.CheckDBLibError(lcOther, 'EXECUTEPREPARED:dbRPCExec'); FetchResults; Result := GetMoreResults; if FPLainDriver.dbHasRetStat(FHandle) then DefVarManager.SetAsInteger(Temp, FPlainDriver.dbRetStatus(FHandle)) else Temp := NullVariant; OutParamValues[0] := Temp; //set function RETURN_VALUE ParamIndex := 1; for I := 1 to OutParamCount - 1 do begin if OutParamTypes[I] = stUnknown then Continue; if FPlainDriver.dbRetData(FHandle, ParamIndex) = nil then Temp := NullVariant else begin if FDBLibConnection.FreeTDS then case FPLainDriver.dbRetType(FHandle, ParamIndex) of TDSSQLCHAR, TDSSQLBINARY: begin DatLen := FPLainDriver.dbRetLen(FHandle, ParamIndex); SetLength(DatBytes, DatLen); Move(PAnsiChar(FPLainDriver.dbRetData(FHandle, ParamIndex))^, DatBytes[0], Length(DatBytes)); DefVarManager.SetAsString(Temp, String(BytesToStr(DatBytes))); end; TDSSQLINT1: DefVarManager.SetAsInteger(Temp, PByte(FPlainDriver.dbRetData(FHandle, ParamIndex))^); TDSSQLINT2: DefVarManager.SetAsInteger(Temp, PSmallInt(FPLainDriver.dbRetData(FHandle, ParamIndex))^); TDSSQLINT4: DefVarManager.SetAsInteger(Temp, PInteger(FPLainDriver.dbRetData(FHandle, ParamIndex))^); TDSSQLFLT4: DefVarManager.SetAsFloat(Temp, PSingle(FPLainDriver.dbRetData(FHandle, ParamIndex))^); TDSSQLFLT8: DefVarManager.SetAsFloat(Temp, PDouble(FPLainDriver.dbRetData(FHandle, ParamIndex))^); TDSSQLMONEY4: begin FPlainDriver.dbConvert(FHandle, TDSSQLMONEY4, FPlainDriver.dbRetData(FHandle, ParamIndex), 4, TDSSQLMONEY, @DatMoney, 8); DefVarManager.SetAsFloat(Temp, DatMoney); end; TDSSQLMONEY: DefVarManager.SetAsFloat(Temp, PCurrency(FPLainDriver.dbRetData(FHandle, ParamIndex))^); TDSSQLDECIMAL: begin FPLainDriver.dbConvert(FHandle, TDSSQLDECIMAL, FPLainDriver.dbRetData(FHandle, ParamIndex), FPLainDriver.dbRetLen(FHandle, ParamIndex), TDSSQLFLT8, @DatDouble, 8); DefVarManager.SetAsFloat(Temp, DatDouble); end; TDSSQLNUMERIC: begin FPLainDriver.dbConvert(FHandle, TDSSQLNUMERIC, FPLainDriver.dbRetData(FHandle, ParamIndex), FPLainDriver.dbRetLen(FHandle, ParamIndex), TDSSQLFLT8, @DatDouble, 8); DefVarManager.SetAsFloat(Temp, DatDouble); end; TDSSQLDATETIM4: begin FPLainDriver.dbConvert(FHandle, TDSSQLDATETIM4, FPLainDriver.dbRetData(FHandle, ParamIndex), 4, TDSSQLDATETIME, @DatDBDATETIME, 8); DefVarManager.SetAsDateTime(Temp, DatDBDATETIME.dtdays + 2 + (DatDBDATETIME.dttime / 25920000)); end; TDSSQLDATETIME: begin DatDBDATETIME := PDBDATETIME( FPLainDriver.dbRetData(FHandle, ParamIndex))^; DefVarManager.SetAsDateTime(Temp, DatDBDATETIME.dtdays + 2 + (DatDBDATETIME.dttime / 25920000)); end; else Temp := NullVariant; end else case FPLainDriver.dbRetType(FHandle, ParamIndex) of DBLIBSQLCHAR, DBLIBSQLBINARY: begin DatLen := FPLainDriver.dbRetLen(FHandle, ParamIndex); SetLength(DatBytes, DatLen); Move(PAnsiChar(FPLainDriver.dbRetData(FHandle, ParamIndex))^, DatBytes[0], Length(DatBytes)); DefVarManager.SetAsString(Temp, String(BytesToStr(DatBytes))); end; DBLIBSQLINT1: DefVarManager.SetAsInteger(Temp, PByte(FPlainDriver.dbRetData(FHandle, ParamIndex))^); DBLIBSQLINT2: DefVarManager.SetAsInteger(Temp, PSmallInt(FPLainDriver.dbRetData(FHandle, ParamIndex))^); DBLIBSQLINT4: DefVarManager.SetAsInteger(Temp, PInteger(FPLainDriver.dbRetData(FHandle, ParamIndex))^); DBLIBSQLFLT4: DefVarManager.SetAsFloat(Temp, PSingle(FPLainDriver.dbRetData(FHandle, ParamIndex))^); DBLIBSQLFLT8: DefVarManager.SetAsFloat(Temp, PDouble(FPLainDriver.dbRetData(FHandle, ParamIndex))^); DBLIBSQLMONEY4: begin FPlainDriver.dbConvert(FHandle, DBLIBSQLMONEY4, FPlainDriver.dbRetData(FHandle, ParamIndex), 4, DBLIBSQLMONEY, @DatMoney, 8); DefVarManager.SetAsFloat(Temp, DatMoney); end; DBLIBSQLMONEY: DefVarManager.SetAsFloat(Temp, PCurrency(FPLainDriver.dbRetData(FHandle, ParamIndex))^); DBLIBSQLDECIMAL: begin FPLainDriver.dbConvert(FHandle, DBLIBSQLDECIMAL, FPLainDriver.dbRetData(FHandle, ParamIndex), FPLainDriver.dbRetLen(FHandle, ParamIndex), DBLIBSQLFLT8, @DatDouble, 8); DefVarManager.SetAsFloat(Temp, DatDouble); end; DBLIBSQLNUMERIC: begin FPLainDriver.dbConvert(FHandle, DBLIBSQLNUMERIC, FPLainDriver.dbRetData(FHandle, ParamIndex), FPLainDriver.dbRetLen(FHandle, ParamIndex), DBLIBSQLFLT8, @DatDouble, 8); DefVarManager.SetAsFloat(Temp, DatDouble); end; DBLIBSQLDATETIM4: begin FPLainDriver.dbConvert(FHandle, DBLIBSQLDATETIM4, FPLainDriver.dbRetData(FHandle, ParamIndex), 4, DBLIBSQLDATETIME, @DatDBDATETIME, 8); DefVarManager.SetAsDateTime(Temp, DatDBDATETIME.dtdays + 2 + (DatDBDATETIME.dttime / 25920000)); end; DBLIBSQLDATETIME: begin DatDBDATETIME := PDBDATETIME( FPLainDriver.dbRetData(FHandle, ParamIndex))^; DefVarManager.SetAsDateTime(Temp, DatDBDATETIME.dtdays + 2 + (DatDBDATETIME.dttime / 25920000)); end; else Temp := NullVariant; end; end; OutParamValues[I] := Temp; Inc(ParamIndex); end; //Workaround for sybase. the dbCount does not work, so a select @@rowcount is //made but this cleared the returned output parameters, so this is moved here //after reading the output parameters FetchRowCount; DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, Format('EXEC %s', [SQL])); end; procedure TZDBLibCallableStatement.SetInParamCount(NewParamCount: Integer); begin inherited SetInParamCount(NewParamCount); if OutParamCount < NewParamCount then SetOutParamCount(NewParamCount); end; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcDbLibUtils.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { DBLib Utility Functions } { } { Originally written by Janos Fegyverneki } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcDbLibUtils; interface {$I ZDbc.inc} uses Classes, SysUtils, ZVariant, ZDbcIntfs, ZPlainDBLibDriver, ZCompatibility; {** Converts an ODBC native types into ZDBC SQL types. @param FieldType dblibc native field type. @return a SQL undepended type. } function ConvertODBCToSqlType(FieldType: SmallInt; CtrlsCPType: TZControlsCodePage): TZSQLType; {** Converts a DBLib native types into ZDBC SQL types. @param FieldType dblibc native field type. @return a SQL undepended type. } function ConvertDBLibToSqlType(FieldType: SmallInt; CtrlsCPType: TZControlsCodePage): TZSQLType; function ConvertFreeTDSToSqlType(const FieldType: SmallInt; const CtrlsCPType: TZControlsCodePage): TZSQLType; {** Convert string DBLib field type to SqlType @param string field type value @result the SqlType field type value } function ConvertDBLibTypeToSqlType(Value: string): TZSQLType; {** Converts ZDBC SQL types into MS SQL native types. @param FieldType dblibc native field type. @return a SQL undepended type. } function ConvertSqlTypeToDBLibType(FieldType: TZSQLType): Integer; function ConvertSqlTypeToFreeTDSType(FieldType: TZSQLType): Integer; {** Converts ZDBC SQL types into MS SQL native types. @param FieldType dblibc native field type. @return a SQL undepended type. } function ConvertSqlTypeToDBLibTypeName(FieldType: TZSQLType): string; function ConvertSqlTypeToFreeTDSTypeName(FieldType: TZSQLType): string; {** Converts a DBLib nullability value into ZDBC TZColumnNullableType. @param DBLibNullability dblibc native nullability. @return a SQL TZColumnNullableType. } function ConvertDBLibNullability(DBLibNullability: Byte): TZColumnNullableType; {** Prepares an SQL parameter for the query. @param ParameterIndex the first parameter is 1, the second is 2, ... @return a string representation of the parameter. } function PrepareSQLParameter(Value: TZVariant; ParamType: TZSQLType; ConSettings: PZConSettings; PlainDriver: IZDBLibPlainDriver; const NChar: Boolean = False): RawByteString; implementation uses Types, ZSysUtils, ZPlainDbLibConstants, ZEncoding, ZDbcUtils {$IFDEF WITH_UNITANSISTRINGS}, AnsiStrings{$ENDIF}; {** Converts an ODBC native types into ZDBC SQL types. @param FieldType dblibc native field type. @return a SQL undepended type. } function ConvertODBCToSqlType(FieldType: SmallInt; CtrlsCPType: TZControlsCodePage): TZSQLType; begin case FieldType of 1, 12, -8, -9: Result := stString; -7{bit}: Result := stBoolean; //Bug #889223, bug with tinyint on mssql // -6: Result := stByte; -5: Result := stLong; -6: Result := stShort; 5: Result := stShort; 4: Result := stInteger; 2, 3, 6, 7, 8: Result := stDouble; 11, 93: Result := stTimestamp; -1, -10: Result := stAsciiStream; -4{image}: Result := stBinaryStream; -2{binary},-3{varbinary},-11{uniqueidentifier}: Result := stBytes; else Result := stUnknown; end; if CtrlsCPType = cCP_UTF16 then case Result of stString: Result := stUnicodeString; stAsciiStream: Result := stUnicodeStream; end; end; {** Converts a DBLib native types into ZDBC SQL types. @param FieldType dblibc native field type. @return a SQL undepended type. } function ConvertDBLibToSqlType(FieldType: SmallInt; CtrlsCPType: TZControlsCodePage): TZSQLType; begin case FieldType of DBLIBSQLCHAR: Result := stString; DBLIBSQLBIT: Result := stBoolean; //Bug #889223, bug with tinyint on mssql // DBLIBSQLINT1: Result := stByte; DBLIBSQLINT1: Result := stShort; DBLIBSQLINT2: Result := stShort; DBLIBSQLINT4: Result := stInteger; DBLIBSQLFLT4: Result := stDouble; DBLIBSQLFLT8: Result := stDouble; DBLIBSQLMONEY4: Result := stDouble; DBLIBSQLMONEY: Result := stDouble; DBLIBSQLDATETIM4: Result := stTimestamp; DBLIBSQLDATETIME: Result := stTimestamp; DBLIBSQLTEXT: Result := stAsciiStream; DBLIBSQLIMAGE: Result := stBinaryStream; DBLIBSQLBINARY: Result := stBinaryStream; else Result := stUnknown; end; if CtrlsCPType = cCP_UTF16 then case Result of stString: Result := stUnicodeString; stAsciiStream: Result := stUnicodeStream; end; end; {** Converts a FreeTDS native types into ZDBC SQL types. @param FieldType dblibc native field type. @return a SQL undepended type. } function ConvertFreeTDSToSqlType(const FieldType: SmallInt; const CtrlsCPType: TZControlsCodePage): TZSQLType; begin case FieldType of SYBCHAR, SYBVARCHAR, XSYBCHAR, XSYBVARCHAR: Result := stString; SYBINTN, SYBINT4: Result := stInteger; SYBINT8: Result := stLong; SYBNUMERIC: Result := stBigDecimal; SYBINT1, SYBINT2: Result := stShort; SYBFLT8, SYBFLTN, SYBREAL, SYBDECIMAL: Result := stDouble; SYBDATETIME, SYBDATETIME4, SYBDATETIMN: Result := stTimestamp; SYBBIT, SYBBITN: Result := stBoolean; SYBTEXT: Result := stAsciiStream; SYBNTEXT: Result := stUnicodeStream; SYBIMAGE: Result := stBinaryStream; SYBBINARY, SYBVARBINARY, XSYBBINARY, XSYBVARBINARY: Result := stBytes; SYBMONEY4, SYBMONEY, SYBMONEYN: Result := stDouble; SYBVOID: Result := stUnknown; SYBNVARCHAR, XSYBNCHAR, XSYBNVARCHAR: Result := stUnicodeString; SYBMSXML: Result := stBinaryStream; SYBUNIQUE: Result := stString; SYBVARIANT: Result := stString; SYBMSUDT: Result := stString; else Result := stUnknown; end; if CtrlsCPType = cCP_UTF16 then case Result of stString: Result := stUnicodeString; stAsciiStream: Result := stUnicodeStream; end; end; {** Convert string DBLib field type to SqlType @param string field type value @result the SqlType field type value } function ConvertDBLibTypeToSqlType(Value: string): TZSQLType; begin Result := stUnknown; end; {** Converts ZDBC SQL types into DBLib native types. @param FieldType dblibc native field type. @return a SQL undepended type. } function ConvertSqlTypeToDBLibType(FieldType: TZSQLType): Integer; begin Result := -1; case FieldType of stBoolean: Result := DBLIBSQLBIT; stByte: Result := DBLIBSQLINT1; stShort: Result := DBLIBSQLINT2; stInteger: Result := DBLIBSQLINT4; stLong: Result := DBLIBSQLFLT8; stFloat: Result := DBLIBSQLFLT8; stDouble: Result := DBLIBSQLFLT8; stBigDecimal: Result := DBLIBSQLFLT8; stString: Result := DBLIBSQLCHAR; stBytes: Result := DBLIBSQLBINARY; stDate: Result := DBLIBSQLDATETIME; stTime: Result := DBLIBSQLDATETIME; stTimestamp: Result := DBLIBSQLDATETIME; stAsciiStream: Result := DBLIBSQLTEXT; stUnicodeStream: Result := DBLIBSQLIMAGE; stBinaryStream: Result := DBLIBSQLIMAGE; end; end; {** Converts ZDBC SQL types into DBLib native types. @param FieldType dblibc native field type. @return a SQL undepended type. } function ConvertSqlTypeToDBLibTypeName(FieldType: TZSQLType): string; begin Result := ''; case FieldType of stBoolean: Result := 'bit'; stByte: Result := 'tinyint'; stShort: Result := 'smallint'; stInteger: Result := 'int'; stLong: Result := 'bigint'; stFloat: Result := 'float(24)'; stDouble: Result := 'float(53)'; stBigDecimal: Result := 'float(53)'; stString: Result := 'varchar(8000)'; stBytes: Result := 'varbinary(8000)'; stDate: Result := 'datetime'; stTime: Result := 'datetime'; stTimestamp: Result := 'datetime'; stAsciiStream: Result := 'text'; stUnicodeStream: Result := 'ntext'; stBinaryStream: Result := 'image'; end; end; {** Converts ZDBC SQL types into FreeTDS native types. @param FieldType dblibc native field type. @return a SQL undepended type. } function ConvertSqlTypeToFreeTDSType(FieldType: TZSQLType): Integer; begin Result := -1; case FieldType of stBoolean: Result := SYBBIT; stByte: Result := SYBINT1; stShort: Result := SYBINT2; stInteger: Result := SYBINT4; stLong: Result := SYBFLT8; stFloat: Result := SYBFLT8; stDouble: Result := SYBFLT8; stBigDecimal: Result := SYBFLT8; stString: Result := SYBCHAR; stUnicodeString: Result := SYBNVARCHAR; stBytes: Result := SYBBINARY; stDate: Result := SYBDATETIME; stTime: Result := SYBDATETIME; stTimestamp: Result := SYBDATETIME; stAsciiStream: Result := SYBTEXT; stUnicodeStream: Result := SYBNTEXT; stBinaryStream: Result := SYBIMAGE; end; end; {** Converts ZDBC SQL types into FreeTDS native types. @param FieldType dblibc native field type. @return a SQL undepended type. } function ConvertSqlTypeToFreeTDSTypeName(FieldType: TZSQLType): string; begin Result := ''; case FieldType of stBoolean: Result := 'bit'; stByte: Result := 'tinyint'; stShort: Result := 'smallint'; stInteger: Result := 'int'; stLong: Result := 'bigint'; stFloat: Result := 'float(24)'; stDouble: Result := 'float(53)'; stBigDecimal: Result := 'float(53)'; stString: Result := 'varchar(8000)'; stUnicodeString: Result := 'nvarchar(4000)'; stBytes: Result := 'varbinary(8000)'; stDate: Result := 'datetime'; stTime: Result := 'datetime'; stTimestamp: Result := 'datetime'; stAsciiStream: Result := 'text'; stUnicodeStream: Result := 'ntext'; stBinaryStream: Result := 'image'; end; end; {** Converts a DBLib nullability value into ZDBC TZColumnNullableType. @param DBLibNullability dblibc native nullability. @return a SQL TZColumnNullableType. } function ConvertDBLibNullability(DBLibNullability: Byte): TZColumnNullableType; const Nullability: array[0..2] of TZColumnNullableType = (ntNoNulls, ntNullable, ntNullableUnknown); begin Result := Nullability[DBLibNullability]; end; {** Prepares an SQL parameter for the query. @param ParameterIndex the first parameter is 1, the second is 2, ... @return a string representation of the parameter. } function PrepareSQLParameter(Value: TZVariant; ParamType: TZSQLType; ConSettings: PZConSettings; PlainDriver: IZDBLibPlainDriver; const NChar: Boolean = False): RawByteString; var TempBytes: TByteDynArray; TempBlob: IZBlob; begin TempBytes := nil; if DefVarManager.IsNull(Value) then Result := 'NULL' else begin case ParamType of stBoolean: if SoftVarManager.GetAsBoolean(Value) then Result := '1' else Result := '0'; stByte, stShort, stInteger, stLong, stFloat, stDouble, stBigDecimal: Result := RawByteString(SoftVarManager.GetAsString(Value)); stString: if NChar then Result := {$IFDEF WITH_UNITANSISTRINGS}AnsiStrings.{$ENDIF}AnsiQuotedStr(PlainDriver.ZPlainString(SoftVarManager.GetAsString(Value), ConSettings, zCP_UTF8), '''') else Result := {$IFDEF WITH_UNITANSISTRINGS}AnsiStrings.{$ENDIF}AnsiQuotedStr(PlainDriver.ZPlainString(SoftVarManager.GetAsString(Value), ConSettings), ''''); stUnicodeString: if NChar then Result := {$IFDEF WITH_UNITANSISTRINGS}AnsiStrings.{$ENDIF}AnsiQuotedStr(UTF8Encode(SoftVarManager.GetAsUnicodeString(Value)),'''') else Result := {$IFDEF WITH_UNITANSISTRINGS}AnsiStrings.{$ENDIF}AnsiQuotedStr(PlainDriver.ZPlainString(SoftVarManager.GetAsUnicodeString(Value), ConSettings),''''); stBytes: begin TempBytes := SoftVarManager.GetAsBytes(Value); if Length(TempBytes) = 0 then Result := 'NULL' else Result := GetSQLHexAnsiString(PAnsiChar(TempBytes), Length(TempBytes), True); end; stDate: Result := RawByteString('''' + FormatDateTime(ConSettings^.DateFormat, SoftVarManager.GetAsDateTime(Value)) + ''''); stTime: Result := RawByteString('''' + FormatDateTime('hh":"mm":"ss":"zzz', SoftVarManager.GetAsDateTime(Value)) + ''''); stTimestamp: Result := RawByteString('''' + FormatDateTime(ConSettings^.DateFormat+' hh":"mm":"ss":"zzz', SoftVarManager.GetAsDateTime(Value)) + ''''); stAsciiStream, stUnicodeStream, stBinaryStream: begin TempBlob := DefVarManager.GetAsInterface(Value) as IZBlob; if not TempBlob.IsEmpty then begin if ParamType = stBinaryStream then Result := GetSQLHexAnsiString(PAnsiChar(TempBlob.GetBuffer), TempBlob.Length, True) else if NChar then {$IFDEF WITH_UNITANSISTRINGS} Result := AnsiStrings.AnsiQuotedStr(AnsiStrings.StringReplace( GetValidatedAnsiStringFromBuffer(TempBlob.GetBuffer, TempBlob.Length, ConSettings, zCP_UTF8), #0, '', [rfReplaceAll]), '''') else Result := AnsiStrings.AnsiQuotedStr(AnsiStrings.StringReplace( GetValidatedAnsiStringFromBuffer(TempBlob.GetBuffer, TempBlob.Length, TempBlob.WasDecoded, ConSettings), #0, '', [rfReplaceAll]), '''') {$ELSE} Result := AnsiQuotedStr(StringReplace( GetValidatedAnsiStringFromBuffer(TempBlob.GetBuffer, TempBlob.Length, ConSettings, zCP_UTF8), #0, '', [rfReplaceAll]), '''') else Result := AnsiQuotedStr(StringReplace( GetValidatedAnsiStringFromBuffer(TempBlob.GetBuffer, TempBlob.Length, TempBlob.WasDecoded, ConSettings), #0, '', [rfReplaceAll]), '''') {$ENDIF} end else Result := 'NULL'; TempBlob := nil; end; else Result := 'NULL'; end; end; end; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcGenericResolver.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Generic Cached Resolver } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcGenericResolver; interface {$I ZDbc.inc} uses Types, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, Contnrs, ZVariant, ZDbcIntfs, ZDbcCache, ZDbcCachedResultSet, ZCompatibility, ZSelectSchema; type {** Implements a resolver parameter object. } TZResolverParameter = class (TObject) private FColumnIndex: Integer; FColumnName: string; FColumnType: TZSQLType; FNewValue: Boolean; FDefaultValue: string; public constructor Create(ColumnIndex: Integer; ColumnName: string; ColumnType: TZSQLType; NewValue: Boolean; DefaultValue: string); property ColumnIndex: Integer read FColumnIndex write FColumnIndex; property ColumnName: string read FColumnName write FColumnName; property ColumnType: TZSQLType read FColumnType write FColumnType; property NewValue: Boolean read FNewValue write FNewValue; property DefaultValue: string read FDefaultValue write FDefaultValue; end; {** Implements a generic cached resolver object which generates DML SQL statements and posts resultset updates to database. } { TZGenericCachedResolver } TZGenericCachedResolver = class (TInterfacedObject, IZCachedResolver) private FConnection: IZConnection; FStatement : IZStatement; FMetadata: IZResultSetMetadata; FDatabaseMetadata: IZDatabaseMetadata; FIdentifierConvertor: IZIdentifierConvertor; FInsertColumns: TObjectList; FUpdateColumns: TObjectList; FWhereColumns: TObjectList; FCalcDefaults: Boolean; FWhereAll: Boolean; FUpdateAll: Boolean; InsertStatement : IZPreparedStatement; UpdateStatement : IZPreparedStatement; DeleteStatement : IZPreparedStatement; protected procedure CopyResolveParameters(FromList, ToList: TObjectList); function ComposeFullTableName(Catalog, Schema, Table: string): string; function DefineTableName: string; function CreateResolverStatement(SQL : String):IZPreparedStatement; procedure DefineCalcColumns(Columns: TObjectList; RowAccessor: TZRowAccessor); procedure DefineInsertColumns(Columns: TObjectList); procedure DefineUpdateColumns(Columns: TObjectList; OldRowAccessor, NewRowAccessor: TZRowAccessor); procedure DefineWhereKeyColumns(Columns: TObjectList); procedure DefineWhereAllColumns(Columns: TObjectList; IgnoreKeyColumn: Boolean = False); function CheckKeyColumn(ColumnIndex: Integer): Boolean; virtual; procedure FillStatement(Statement: IZPreparedStatement; Params: TObjectList; OldRowAccessor, NewRowAccessor: TZRowAccessor); property Connection: IZConnection read FConnection write FConnection; property Metadata: IZResultSetMetadata read FMetadata write FMetadata; property DatabaseMetadata: IZDatabaseMetadata read FDatabaseMetadata write FDatabaseMetadata; property IdentifierConvertor: IZIdentifierConvertor read FIdentifierConvertor write FIdentifierConvertor; property InsertColumns: TObjectList read FInsertColumns; property UpdateColumns: TObjectList read FUpdateColumns; property WhereColumns: TObjectList read FWhereColumns; property CalcDefaults: Boolean read FCalcDefaults write FCalcDefaults; property WhereAll: Boolean read FWhereAll write FWhereAll; property UpdateAll: Boolean read FUpdateAll write FUpdateAll; public constructor Create(Statement: IZStatement; Metadata: IZResultSetMetadata); destructor Destroy; override; function FormWhereClause(Columns: TObjectList; OldRowAccessor: TZRowAccessor): string; virtual; function FormInsertStatement(Columns: TObjectList; NewRowAccessor: TZRowAccessor): string; function FormUpdateStatement(Columns: TObjectList; OldRowAccessor, NewRowAccessor: TZRowAccessor): string; function FormDeleteStatement(Columns: TObjectList; OldRowAccessor: TZRowAccessor): string; function FormCalculateStatement(Columns: TObjectList): string; virtual; procedure CalculateDefaults(Sender: IZCachedResultSet; RowAccessor: TZRowAccessor); procedure PostUpdates(Sender: IZCachedResultSet; UpdateType: TZRowUpdateType; OldRowAccessor, NewRowAccessor: TZRowAccessor); virtual; {BEGIN of PATCH [1185969]: Do tasks after posting updates. ie: Updating AutoInc fields in MySQL } procedure UpdateAutoIncrementFields(Sender: IZCachedResultSet; UpdateType: TZRowUpdateType; OldRowAccessor, NewRowAccessor: TZRowAccessor; Resolver: IZCachedResolver); virtual; {END of PATCH [1185969]: Do tasks after posting updates. ie: Updating AutoInc fields in MySQL } procedure RefreshCurrentRow(Sender: IZCachedResultSet;RowAccessor: TZRowAccessor); //FOS+ 07112006 end; implementation uses ZMessages, ZSysUtils, ZDbcMetadata, ZDbcUtils; { TZResolverParameter } {** Constructs this resolver parameter and assignes the main properties. @param ColumnIndex a result set column index. @param ColumnName a result set column name. @param NewValue True for new value and False for an old one. @param DefaultValue a default column value to evalute on server. } constructor TZResolverParameter.Create(ColumnIndex: Integer; ColumnName: string; ColumnType: TZSQLType; NewValue: Boolean; DefaultValue: string); begin FColumnType := ColumnType; FColumnIndex := ColumnIndex; FColumnName := ColumnName; FNewValue := NewValue; FDefaultValue := DefaultValue; end; { TZGenericCachedResolver } {** Creates a cached resolver and assignes the main properties. @param ResultSet a related ResultSet object. } constructor TZGenericCachedResolver.Create(Statement: IZStatement; Metadata: IZResultSetMetadata); begin FStatement := Statement; FConnection := Statement.GetConnection; FMetadata := Metadata; FDatabaseMetadata := Statement.GetConnection.GetMetadata; FIdentifierConvertor := FDatabaseMetadata.GetIdentifierConvertor; FInsertColumns := TObjectList.Create(True); FWhereColumns := TObjectList.Create(True); FUpdateColumns := TObjectList.Create(True); FCalcDefaults := StrToBoolEx(DefineStatementParameter(Statement, 'defaults', 'true')); FUpdateAll := UpperCase(DefineStatementParameter(Statement, 'update', 'changed')) = 'ALL'; FWhereAll := UpperCase(DefineStatementParameter(Statement, 'where', 'keyonly')) = 'ALL'; InsertStatement := nil; UpdateStatement := nil; DeleteStatement := nil; end; {** Destroys this object and cleanups the memory. } destructor TZGenericCachedResolver.Destroy; begin FMetadata := nil; FDatabaseMetadata := nil; FreeAndNil(FInsertColumns); FreeAndNil(FUpdateColumns); FreeAndNil(FWhereColumns); inherited Destroy; end; {** Copies resolver parameters from source list to destination list. @param FromList the source object list. @param ToList the destination object list. } procedure TZGenericCachedResolver.CopyResolveParameters( FromList: TObjectList; ToList: TObjectList); var I: Integer; Current: TZResolverParameter; begin for I := 0 to FromList.Count - 1 do begin Current := TZResolverParameter(FromList[I]); if Current.ColumnName <> '' then ToList.Add(TZResolverParameter.Create(Current.ColumnIndex, Current.ColumnName, Current.ColumnType, Current.NewValue, '')); end; end; {** Composes a fully quilified table name. @param Catalog a table catalog name. @param Schema a table schema name. @param Table a table name. @return a fully qualified table name. } function TZGenericCachedResolver.ComposeFullTableName(Catalog, Schema, Table: string): string; begin if Table <> '' then begin Result := IdentifierConvertor.Quote(Table); if Schema <> '' then Result := IdentifierConvertor.Quote(Schema) + '.' + Result; if Catalog <> '' then Result := IdentifierConvertor.Quote(Catalog) + '.' + Result; end else Result := ''; end; {** Defines a table name from the select statement. } function TZGenericCachedResolver.DefineTableName: string; var I: Integer; Temp: string; begin Result := ''; for I := 1 to Metadata.GetColumnCount do begin Temp := ComposeFullTableName(Metadata.GetCatalogName(I), Metadata.GetSchemaName(I), Metadata.GetTableName(I)); if (Result = '') and (Temp <> '') then Result := Temp else if (Result <> '') and (Temp <> '') and (Temp <> Result) then raise EZSQLException.Create(SCanNotUpdateComplexQuery); end; if Result = '' then raise EZSQLException.Create(SCanNotUpdateThisQueryType); end; function TZGenericCachedResolver.CreateResolverStatement(SQL: String): IZPreparedStatement; var Temp : TStrings; begin if StrToBoolEx(FStatement.GetParameters.Values['preferprepared']) then begin Temp := TStringList.Create; Temp.Values['preferprepared'] := 'true'; if not ( Connection.GetParameters.Values['chunk_size'] = '' ) then //ordered by precedence Temp.Values['chunk_size'] := Connection.GetParameters.Values['chunk_size'] else Temp.Values['chunk_size'] := FStatement.GetParameters.Values['chunk_size']; Result := Connection.PrepareStatementWithParams(SQL, Temp); Temp.Free; end else Result := Connection.PrepareStatement(SQL); end; {** Gets a collection of data columns for INSERT statements. @param Columns a collection of columns. } procedure TZGenericCachedResolver.DefineInsertColumns(Columns: TObjectList); var I: Integer; begin { Precache insert parameters. } if InsertColumns.Count = 0 then begin for I := 1 to Metadata.GetColumnCount do begin if (Metadata.GetTableName(I) <> '') and (Metadata.GetColumnName(I) <> '') and Metadata.IsWritable(I) then begin InsertColumns.Add(TZResolverParameter.Create(I, Metadata.GetColumnName(I), Metadata.GetColumnType(I), True, '')); end; end; end; { Use cached insert parameters } CopyResolveParameters(InsertColumns, Columns); end; {** Gets a collection of data columns for UPDATE statements. @param Columns a collection of columns. @param OldRowAccessor an accessor object to old column values. @param NewRowAccessor an accessor object to new column values. } procedure TZGenericCachedResolver.DefineUpdateColumns( Columns: TObjectList; OldRowAccessor, NewRowAccessor: TZRowAccessor); var I: Integer; ColumnIndices: TIntegerDynArray; ColumnDirs: TBooleanDynArray; begin { Use precached parameters. } if UpdateAll and (UpdateColumns.Count > 0) then begin CopyResolveParameters(UpdateColumns, Columns); Exit; end; { Defines parameters for UpdateAll mode. } if UpdateAll then begin for I := 1 to Metadata.GetColumnCount do begin if (Metadata.GetTableName(I) <> '') and (Metadata.GetColumnName(I) <> '') and Metadata.IsWritable(I) then begin UpdateColumns.Add(TZResolverParameter.Create(I, Metadata.GetColumnName(I), Metadata.GetColumnType(I), True, '')); end; end; CopyResolveParameters(UpdateColumns, Columns); end { Defines parameters for UpdateChanged mode. } else begin SetLength(ColumnIndices, 1); SetLength(ColumnDirs, 1); ColumnDirs[0] := True; for I := 1 to Metadata.GetColumnCount do begin ColumnIndices[0] := I; if (Metadata.GetTableName(I) <> '') and (Metadata.GetColumnName(I) <> '') and Metadata.IsWritable(I) and (OldRowAccessor.CompareBuffers( OldRowAccessor.RowBuffer, NewRowAccessor.RowBuffer, ColumnIndices, ColumnDirs) <> 0)then begin Columns.Add(TZResolverParameter.Create(I, Metadata.GetColumnName(I), Metadata.GetColumnType(I), True, '')); end; end; end; end; {** Gets a collection of where key columns for DELETE or UPDATE DML statements. @param Columns a collection of key columns. } procedure TZGenericCachedResolver.DefineWhereKeyColumns(Columns: TObjectList); var I: Integer; Found: Boolean; ColumnName: string; Catalog, Schema, Table: string; PrimaryKeys: IZResultSet; begin { Use precached values. } if WhereColumns.Count > 0 then begin CopyResolveParameters(WhereColumns, Columns); Exit; end; { Defines catalog, schema and a table. } Table := DefineTableName; for I := 1 to Metadata.GetColumnCount do begin Table := Metadata.GetTableName(I); if Table <> '' then begin Schema := Metadata.GetSchemaName(I); Catalog := Metadata.GetCatalogName(I); Break; end; end; { Tryes to define primary keys. } if not WhereAll then begin {For exact results: quote all identifiers SEE: http://sourceforge.net/p/zeoslib/tickets/81/ If table names have mixed case ConstructNameCondition will return wrong results and we fall back to WhereAll} PrimaryKeys := DatabaseMetadata.GetPrimaryKeys(IdentifierConvertor.Quote(Catalog), IdentifierConvertor.Quote(Schema), IdentifierConvertor.Quote(Table)); while PrimaryKeys.Next do begin ColumnName := PrimaryKeys.GetString(4); Found := False; for I := 1 to Metadata.GetColumnCount do begin if (ColumnName = Metadata.GetColumnName(I)) and (Table = Metadata.GetTableName(I)) then begin Found := True; Break; end; end; if not Found then begin WhereColumns.Clear; Break; end; WhereColumns.Add(TZResolverParameter.Create(I, ColumnName, stUnknown, False, '')); end; end; if WhereColumns.Count > 0 then CopyResolveParameters(WhereColumns, Columns) else DefineWhereAllColumns(Columns); end; {** Gets a collection of where all columns for DELETE or UPDATE DML statements. @param Columns a collection of key columns. } procedure TZGenericCachedResolver.DefineWhereAllColumns(Columns: TObjectList; IgnoreKeyColumn: Boolean = False); var I: Integer; begin { Use precached values. } if WhereColumns.Count > 0 then begin CopyResolveParameters(WhereColumns, Columns); Exit; end; { Takes a a key all non-blob fields. } for I := 1 to Metadata.GetColumnCount do begin if CheckKeyColumn(I) then WhereColumns.Add(TZResolverParameter.Create(I, Metadata.GetColumnName(I), Metadata.GetColumnType(I), False, '')) else if IgnoreKeyColumn then WhereColumns.Add(TZResolverParameter.Create(I, Metadata.GetColumnName(I), Metadata.GetColumnType(I), False, '')); end; if ( WhereColumns.Count = 0 ) and ( not IgnoreKeyColumn ) then DefineWhereAllColumns(Columns, True) else { Copy defined parameters to target columns } CopyResolveParameters(WhereColumns, Columns); end; {** Checks is the specified column can be used in where clause. @param ColumnIndex an index of the column. @returns true if column can be included into where clause. } function TZGenericCachedResolver.CheckKeyColumn(ColumnIndex: Integer): Boolean; begin Result := (Metadata.GetTableName(ColumnIndex) <> '') and (Metadata.GetColumnName(ColumnIndex) <> '') and Metadata.IsSearchable(ColumnIndex) and not (Metadata.GetColumnType(ColumnIndex) in [stUnknown, stAsciiStream, stBinaryStream, stUnicodeStream]); end; {** Gets a collection of data columns to initialize before INSERT statements. @param Columns a collection of columns. @param RowAccessor an accessor object to column values. } procedure TZGenericCachedResolver.DefineCalcColumns(Columns: TObjectList; RowAccessor: TZRowAccessor); var I: Integer; begin for I := 1 to Metadata.GetColumnCount do begin if RowAccessor.IsNull(I) and (Metadata.GetTableName(I) <> '') and ((Metadata.GetDefaultValue(I) <> '') or (RowAccessor.GetColumnDefaultExpression(I) <> '')) then begin // DefaultExpression takes takes precedence on database default value if RowAccessor.GetColumnDefaultExpression(I) <> '' then Columns.Add(TZResolverParameter.Create(I, Metadata.GetColumnName(I), Metadata.GetColumnType(I), True, RowAccessor.GetColumnDefaultExpression(I))) else Columns.Add(TZResolverParameter.Create(I, Metadata.GetColumnName(I), Metadata.GetColumnType(I), True, Metadata.GetDefaultValue(I))); end; end; end; {** Fills the specified statement with stored or given parameters. @param ResultSet a source result set object. @param Statement a DBC statement object. @param Config an UpdateStatement configuration. @param OldRowAccessor an accessor object to old column values. @param NewRowAccessor an accessor object to new column values. } procedure TZGenericCachedResolver.FillStatement(Statement: IZPreparedStatement; Params: TObjectList; OldRowAccessor, NewRowAccessor: TZRowAccessor); var I: Integer; ColumnIndex: Integer; Current: TZResolverParameter; RowAccessor: TZRowAccessor; WasNull: Boolean; begin WasNull := False; for I := 0 to Params.Count - 1 do begin Current := TZResolverParameter(Params[I]); if Current.NewValue then RowAccessor := NewRowAccessor else RowAccessor := OldRowAccessor; ColumnIndex := Current.ColumnIndex; if FCalcDefaults then Statement.SetDefaultValue(I + 1, Metadata.GetDefaultValue(ColumnIndex)); case Metadata.GetColumnType(ColumnIndex) of stBoolean: Statement.SetBoolean(I + 1, RowAccessor.GetBoolean(ColumnIndex, WasNull)); stByte: Statement.SetByte(I + 1, RowAccessor.GetByte(ColumnIndex, WasNull)); stShort: Statement.SetShort(I + 1, RowAccessor.GetShort(ColumnIndex, WasNull)); stInteger: Statement.SetInt(I + 1, RowAccessor.GetInt(ColumnIndex, WasNull)); stLong: Statement.SetLong(I + 1, RowAccessor.GetLong(ColumnIndex, WasNull)); stFloat: Statement.SetFloat(I + 1, RowAccessor.GetFloat(ColumnIndex, WasNull)); stDouble: Statement.SetDouble(I + 1, RowAccessor.GetDouble(ColumnIndex, WasNull)); stBigDecimal: Statement.SetBigDecimal(I + 1, RowAccessor.GetBigDecimal(ColumnIndex, WasNull)); stString: Statement.SetString(I + 1, RowAccessor.GetString(ColumnIndex, WasNull)); stUnicodeString: Statement.SetUnicodeString(I + 1, RowAccessor.GetUnicodeString(ColumnIndex, WasNull)); stBytes, stGUID: Statement.SetBytes(I + 1, RowAccessor.GetBytes(ColumnIndex, WasNull)); stDate: Statement.SetDate(I + 1, RowAccessor.GetDate(ColumnIndex, WasNull)); stTime: Statement.SetTime(I + 1, RowAccessor.GetTime(ColumnIndex, WasNull)); stTimestamp: Statement.SetTimestamp(I + 1, RowAccessor.GetTimestamp(ColumnIndex, WasNull)); stAsciiStream: Statement.SetBlob(I + 1, stAsciiStream, RowAccessor.GetBlob(ColumnIndex, WasNull)); stUnicodeStream: Statement.SetBlob(I + 1, stUnicodeStream, RowAccessor.GetBlob(ColumnIndex, WasNull)); stBinaryStream: Statement.SetBlob(I + 1, stBinaryStream, RowAccessor.GetBlob(ColumnIndex, WasNull)); end; if WasNull then Statement.SetNull(I + 1, Metadata.GetColumnType(ColumnIndex)) end; end; {** Forms a where clause for UPDATE or DELETE DML statements. @param Columns a collection of key columns. @param OldRowAccessor an accessor object to old column values. } function TZGenericCachedResolver.FormWhereClause(Columns: TObjectList; OldRowAccessor: TZRowAccessor): string; var I, N: Integer; Current: TZResolverParameter; begin Result := ''; N := Columns.Count - WhereColumns.Count; for I := 0 to WhereColumns.Count - 1 do begin Current := TZResolverParameter(WhereColumns[I]); if Result <> '' then Result := Result + ' AND '; Result := Result + IdentifierConvertor.Quote(Current.ColumnName); if OldRowAccessor.IsNull(Current.ColumnIndex) then begin Result := Result + ' IS NULL '; Columns.Delete(N); end else begin Result := Result + '=?'; Inc(N); end; end; if Result <> '' then Result := ' WHERE ' + Result; end; {** Forms a where clause for INSERT statements. @param Columns a collection of key columns. @param NewRowAccessor an accessor object to new column values. } function TZGenericCachedResolver.FormInsertStatement(Columns: TObjectList; NewRowAccessor: TZRowAccessor): string; var I: Integer; Current: TZResolverParameter; TableName: string; Temp1, Temp2: string; l1: Integer; procedure Append(const app: String); begin if Length(Temp1) < l1 + length(app) then SetLength(Temp1, 2 * (length(app) + l1)); Move(app[1], Temp1[l1+1], length(app)*SizeOf(Char)); Inc(l1, length(app)); end; begin TableName := DefineTableName; DefineInsertColumns(Columns); if Columns.Count = 0 then begin Result := ''; Exit; end; Temp1 := ''; l1 := 0; SetLength(Temp2, 2 * Columns.Count - 1); for I := 0 to Columns.Count - 1 do begin Current := TZResolverParameter(Columns[I]); if Temp1 <> '' then Append(','); Append(IdentifierConvertor.Quote(Current.ColumnName)); if I > 0 then Temp2[I*2] := ','; Temp2[I*2+1] := '?'; end; SetLength(Temp1, l1); Result := Format('INSERT INTO %s (%s) VALUES (%s)', [TableName, Temp1, Temp2]); end; {** Forms a where clause for UPDATE statements. @param Columns a collection of key columns. @param OldRowAccessor an accessor object to old column values. @param NewRowAccessor an accessor object to new column values. } function TZGenericCachedResolver.FormUpdateStatement(Columns: TObjectList; OldRowAccessor, NewRowAccessor: TZRowAccessor): string; var I: Integer; Current: TZResolverParameter; TableName: string; Temp: string; begin TableName := DefineTableName; DefineUpdateColumns(Columns, OldRowAccessor, NewRowAccessor); if Columns.Count = 0 then begin Result := ''; Exit; end; Temp := ''; for I := 0 to Columns.Count - 1 do begin Current := TZResolverParameter(Columns[I]); if Temp <> '' then Temp := Temp + ','; Temp := Temp + IdentifierConvertor.Quote(Current.ColumnName) + '=?'; end; Result := Format('UPDATE %s SET %s', [TableName, Temp]); DefineWhereKeyColumns(Columns); Result := Result + FormWhereClause(Columns, OldRowAccessor); end; {** Forms a where clause for DELETE statements. @param Columns a collection of key columns. @param OldRowAccessor an accessor object to old column values. } function TZGenericCachedResolver.FormDeleteStatement(Columns: TObjectList; OldRowAccessor: TZRowAccessor): string; var TableName: string; begin TableName := DefineTableName; Result := Format('DELETE FROM %s', [TableName]); DefineWhereKeyColumns(Columns); Result := Result + FormWhereClause(Columns, OldRowAccessor); end; {** Forms a where clause for SELECT statements to calculate default values. @param Columns a collection of key columns. @param OldRowAccessor an accessor object to old column values. } function TZGenericCachedResolver.FormCalculateStatement( Columns: TObjectList): string; var I: Integer; Current: TZResolverParameter; begin Result := ''; if Columns.Count = 0 then Exit; for I := 0 to Columns.Count - 1 do begin Current := TZResolverParameter(Columns[I]); if Result <> '' then Result := Result + ','; if Current.DefaultValue <> '' then Result := Result + Current.DefaultValue else Result := Result + 'NULL'; end; Result := 'SELECT ' + Result; end; {** Posts updates to database. @param Sender a cached result set object. @param UpdateType a type of updates. @param OldRowAccessor an accessor object to old column values. @param NewRowAccessor an accessor object to new column values. } procedure TZGenericCachedResolver.PostUpdates(Sender: IZCachedResultSet; UpdateType: TZRowUpdateType; OldRowAccessor, NewRowAccessor: TZRowAccessor); var Statement : IZPreparedStatement; SQL : string; SQLParams : TObjectList; lUpdateCount : Integer; lValidateUpdateCount : Boolean; begin if (UpdateType = utDeleted) and (OldRowAccessor.RowBuffer.UpdateType = utInserted) then Exit; SQLParams := TObjectList.Create(True); try case UpdateType of utInserted: begin SQL := FormInsertStatement(SQLParams, NewRowAccessor); If Assigned(InsertStatement) and (SQL <> InsertStatement.GetSQL) then InsertStatement := nil; If not Assigned(InsertStatement) then InsertStatement := CreateResolverStatement(SQL); Statement := InsertStatement; end; utDeleted: begin SQL := FormDeleteStatement(SQLParams, OldRowAccessor); If Assigned(DeleteStatement) and (SQL <> DeleteStatement.GetSQL) then DeleteStatement := nil; If not Assigned(DeleteStatement) then DeleteStatement := CreateResolverStatement(SQL); Statement := DeleteStatement; end; utModified: begin SQL := FormUpdateStatement(SQLParams, OldRowAccessor, NewRowAccessor); If SQL =''then // no fields have been changed exit; If Assigned(UpdateStatement) and (SQL <> UpdateStatement.GetSQL) then UpdateStatement := nil; If not Assigned(UpdateStatement) then UpdateStatement := CreateResolverStatement(SQL); Statement := UpdateStatement; end; else Exit; end; if SQL <> '' then begin FillStatement(Statement, SQLParams, OldRowAccessor, NewRowAccessor); // if Property ValidateUpdateCount isn't set : assume it's true lValidateUpdateCount := (Sender.GetStatement.GetParameters.IndexOfName('ValidateUpdateCount') = -1) or StrToBoolEx(Sender.GetStatement.GetParameters.Values['ValidateUpdateCount']); lUpdateCount := Statement.ExecuteUpdatePrepared; {$IFDEF WITH_VALIDATE_UPDATE_COUNT} if (lValidateUpdateCount) and (lUpdateCount <> 1 ) then raise EZSQLException.Create(Format(SInvalidUpdateCount, [lUpdateCount])); {$ENDIF} end; finally FreeAndNil(SQLParams); end; end; procedure TZGenericCachedResolver.RefreshCurrentRow(Sender: IZCachedResultSet; RowAccessor: TZRowAccessor); begin raise EZSQLException.Create(SRefreshRowOnlySupportedWithUpdateObject); end; {** Calculate default values for the fields. @param Sender a cached result set object. @param RowAccessor an accessor object to column values. } procedure TZGenericCachedResolver.CalculateDefaults( Sender: IZCachedResultSet; RowAccessor: TZRowAccessor); var I: Integer; SQL: string; SQLParams: TObjectList; Statement: IZStatement; ResultSet: IZResultSet; Metadata: IZResultSetMetadata; Current: TZResolverParameter; begin if not FCalcDefaults then Exit; SQLParams := TObjectList.Create(True); try DefineCalcColumns(SQLParams, RowAccessor); SQL := FormCalculateStatement(SQLParams); if SQL = '' then Exit; { Executes statement and fills default fields. } Statement := Connection.CreateStatement; try ResultSet := Statement.ExecuteQuery(SQL); if ResultSet.Next then begin Metadata := ResultSet.GetMetadata; for I := 1 to Metadata.GetColumnCount do begin Current := TZResolverParameter(SQLParams[I - 1]); try case Current.ColumnType of stBoolean: RowAccessor.SetBoolean(Current.ColumnIndex, ResultSet.GetBoolean(I)); stByte: RowAccessor.SetByte(Current.ColumnIndex, ResultSet.GetByte(I)); stShort: RowAccessor.SetShort(Current.ColumnIndex, ResultSet.GetShort(I)); stInteger: RowAccessor.SetInt(Current.ColumnIndex, ResultSet.GetInt(I)); stLong: RowAccessor.SetLong(Current.ColumnIndex, ResultSet.GetLong(I)); stFloat: RowAccessor.SetFloat(Current.ColumnIndex, ResultSet.GetFloat(I)); stDouble: RowAccessor.SetDouble(Current.ColumnIndex, ResultSet.GetDouble(I)); stBigDecimal: RowAccessor.SetBigDecimal(Current.ColumnIndex, ResultSet.GetBigDecimal(I)); stString, stAsciiStream: RowAccessor.SetString(Current.ColumnIndex, ResultSet.GetString(I)); stUnicodeString, stUnicodeStream: RowAccessor.SetUnicodeString(Current.ColumnIndex, ResultSet.GetUnicodeString(I)); stBytes, stGUID: RowAccessor.SetBytes(Current.ColumnIndex, ResultSet.GetBytes(I)); stDate: RowAccessor.SetDate(Current.ColumnIndex, ResultSet.GetDate(I)); stTime: RowAccessor.SetTime(Current.ColumnIndex, ResultSet.GetTime(I)); stTimestamp: RowAccessor.SetTimestamp(Current.ColumnIndex, ResultSet.GetTimestamp(I)); end; if ResultSet.WasNull then RowAccessor.SetNull(Current.ColumnIndex); except { Supress any errors in default fields. } end; end; end; ResultSet.Close; finally Statement.Close; end; finally FreeAndNil(SQLParams); end; end; {BEGIN of PATCH [1185969]: Do tasks after posting updates. ie: Updating AutoInc fields in MySQL } procedure TZGenericCachedResolver.UpdateAutoIncrementFields( Sender: IZCachedResultSet; UpdateType: TZRowUpdateType; OldRowAccessor, NewRowAccessor: TZRowAccessor; Resolver: IZCachedResolver); begin //Should be implemented at Specific database Level Cached resolver end; {END of PATCH [1185969]: Do tasks after posting updates. ie: Updating AutoInc fields in MySQL } end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcInterbase6.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Interbase Database Connectivity Classes } { } { Originally written by Sergey Merkuriev } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcInterbase6; interface {$I ZDbc.inc} uses Types, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, Contnrs, ZPlainFirebirdDriver, ZPlainDriver, ZCompatibility, ZDbcUtils, ZDbcIntfs, ZDbcConnection, ZPlainFirebirdInterbaseConstants, ZSysUtils, ZDbcLogging, ZDbcInterbase6Utils, ZDbcGenericResolver, ZTokenizer, ZGenericSqlAnalyser, ZURL; type {** Implements Interbase6 Database Driver. } {$WARNINGS OFF} TZInterbase6Driver = class(TZAbstractDriver) public constructor Create; override; function Connect(const Url: TZURL): IZConnection; override; function GetMajorVersion: Integer; override; function GetMinorVersion: Integer; override; function GetTokenizer: IZTokenizer; override; function GetStatementAnalyser: IZStatementAnalyser; override; end; {$WARNINGS ON} {** Represents a Interbase specific connection interface. } IZInterbase6Connection = interface (IZConnection) ['{E870E4FE-21EB-4725-B5D8-38B8A2B12D0B}'] function GetDBHandle: PISC_DB_HANDLE; function GetTrHandle: PISC_TR_HANDLE; function GetDialect: Word; function GetPlainDriver: IZInterbasePlainDriver; procedure CreateNewDatabase(const SQL: String); end; {** Implements Interbase6 Database Connection. } { TZInterbase6Connection } TZInterbase6Connection = class(TZAbstractConnection, IZInterbase6Connection) private FDialect: Word; FHandle: TISC_DB_HANDLE; FTrHandle: TISC_TR_HANDLE; FStatusVector: TARRAY_ISC_STATUS; FHardCommit: boolean; FDisposeClientCodePage: Boolean; private procedure StartTransaction; virtual; protected procedure InternalCreate; override; public destructor Destroy; override; function GetDBHandle: PISC_DB_HANDLE; function GetTrHandle: PISC_TR_HANDLE; function GetDialect: Word; function GetPlainDriver: IZInterbasePlainDriver; procedure CreateNewDatabase(const SQL: String); function CreateRegularStatement(Info: TStrings): IZStatement; override; function CreatePreparedStatement(const SQL: string; Info: TStrings): IZPreparedStatement; override; function CreateCallableStatement(const SQL: string; Info: TStrings): IZCallableStatement; override; function CreateSequence(const Sequence: string; BlockSize: Integer): IZSequence; override; procedure Commit; override; procedure Rollback; override; function PingServer: Integer; override; procedure Open; override; procedure Close; override; function GetBinaryEscapeString(const Value: RawByteString): String; override; function GetBinaryEscapeString(const Value: TByteDynArray): String; override; function GetEscapeString(const Value: RawByteString): RawByteString; override; function GetEscapeString(const Value: ZWideString): ZWideString; override; end; {** Implements a specialized cached resolver for Interbase/Firebird. } TZInterbase6CachedResolver = class(TZGenericCachedResolver) public function FormCalculateStatement(Columns: TObjectList): string; override; end; {** Implements a Interbase 6 sequence. } TZInterbase6Sequence = class(TZAbstractSequence) public function GetCurrentValue: Int64; override; function GetNextValue: Int64; override; function GetCurrentValueSQL: string; override; function GetNextValueSQL: string; override; end; var {** The common driver manager object. } Interbase6Driver: IZDriver; implementation uses ZDbcInterbase6Statement, ZDbcInterbase6Metadata, ZEncoding, ZInterbaseToken, ZInterbaseAnalyser {$IFDEF WITH_UNITANSISTRINGS}, AnsiStrings{$ENDIF}; { TZInterbase6Driver } {** Attempts to make a database connection to the given URL. The driver should return "null" if it realizes it is the wrong kind of driver to connect to the given URL. This will be common, as when the JDBC driver manager is asked to connect to a given URL it passes the URL to each loaded driver in turn.

The driver should raise a SQLException if it is the right driver to connect to the given URL, but has trouble connecting to the database.

The java.util.Properties argument can be used to passed arbitrary string tag/value pairs as connection arguments. Normally at least "user" and "password" properties should be included in the Properties. @param url the URL of the database to which to connect @param info a list of arbitrary string tag/value pairs as connection arguments. Normally at least a "user" and "password" property should be included. @return a Connection object that represents a connection to the URL } {$WARNINGS OFF} function TZInterbase6Driver.Connect(const Url: TZURL): IZConnection; begin Result := TZInterbase6Connection.Create(Url); end; {$WARNINGS ON} {** Constructs this object with default properties. } constructor TZInterbase6Driver.Create; begin inherited Create; AddSupportedProtocol(AddPlainDriverToCache(TZInterbase6PlainDriver.Create)); AddSupportedProtocol(AddPlainDriverToCache(TZFirebird10PlainDriver.Create)); AddSupportedProtocol(AddPlainDriverToCache(TZFirebird15PlainDriver.Create)); AddSupportedProtocol(AddPlainDriverToCache(TZFirebird20PlainDriver.Create)); AddSupportedProtocol(AddPlainDriverToCache(TZFirebird21PlainDriver.Create)); AddSupportedProtocol(AddPlainDriverToCache(TZFirebird25PlainDriver.Create)); // embedded drivers AddSupportedProtocol(AddPlainDriverToCache(TZFirebirdD15PlainDriver.Create)); AddSupportedProtocol(AddPlainDriverToCache(TZFirebirdD20PlainDriver.Create)); AddSupportedProtocol(AddPlainDriverToCache(TZFirebirdD21PlainDriver.Create)); AddSupportedProtocol(AddPlainDriverToCache(TZFirebirdD25PlainDriver.Create)); end; {** Gets the driver's major version number. Initially this should be 1. @return this driver's major version number } function TZInterbase6Driver.GetMajorVersion: Integer; begin Result := 1; end; {** Gets the driver's minor version number. Initially this should be 0. @return this driver's minor version number } function TZInterbase6Driver.GetMinorVersion: Integer; begin Result := 0; end; {** Gets a SQL syntax tokenizer. @returns a SQL syntax tokenizer object. } function TZInterbase6Driver.GetTokenizer: IZTokenizer; begin if Tokenizer = nil then Tokenizer := TZInterbaseTokenizer.Create; Result := Tokenizer; end; {** Creates a statement analyser object. @returns a statement analyser object. } function TZInterbase6Driver.GetStatementAnalyser: IZStatementAnalyser; begin if Analyser = nil then Analyser := TZInterbaseStatementAnalyser.Create; Result := Analyser; end; { TZInterbase6Connection } {** Releases a Connection's database and JDBC resources immediately instead of waiting for them to be automatically released.

Note: A Connection is automatically closed when it is garbage collected. Certain fatal errors also result in a closed Connection. } procedure TZInterbase6Connection.Close; begin if Closed or (not Assigned(PlainDriver)) then Exit; if FTrHandle <> 0 then begin if AutoCommit then begin GetPlainDriver.isc_commit_transaction(@FStatusVector, @FTrHandle); DriverManager.LogMessage(lcTransaction, PlainDriver.GetProtocol, Format('COMMIT TRANSACTION "%s"', [Database])); end else begin GetPlainDriver.isc_rollback_transaction(@FStatusVector, @FTrHandle); DriverManager.LogMessage(lcTransaction, PlainDriver.GetProtocol, Format('ROLLBACK TRANSACTION "%s"', [Database])); end; FTrHandle := 0; CheckInterbase6Error(GetPlainDriver, FStatusVector, lcDisconnect); end; if FHandle <> 0 then begin GetPlainDriver.isc_detach_database(@FStatusVector, @FHandle); FHandle := 0; CheckInterbase6Error(GetPlainDriver, FStatusVector, lcDisconnect); end; DriverManager.LogMessage(lcConnect, PlainDriver.GetProtocol, Format('DISCONNECT FROM "%s"', [Database])); inherited Close; end; {** Commit current transaction } procedure TZInterbase6Connection.Commit; begin if Closed then Exit; if FTrHandle <> 0 then begin if FHardCommit then begin GetPlainDriver.isc_commit_transaction(@FStatusVector, @FTrHandle); FTrHandle := 0; end else GetPlainDriver.isc_commit_retaining(@FStatusVector, @FTrHandle); CheckInterbase6Error(GetPlainDriver, FStatusVector, lcTransaction); DriverManager.LogMessage(lcTransaction, PlainDriver.GetProtocol, 'TRANSACTION COMMIT'); end; end; {** Constructs this object and assignes the main properties. } procedure TZInterbase6Connection.InternalCreate; var RoleName: string; UserSetDialect: string; ConnectTimeout : integer; begin FDisposeClientCodePage := False; Self.FMetadata := TZInterbase6DatabaseMetadata.Create(Self, Url); FHardCommit := StrToBoolEx(URL.Properties.Values['hard_commit']); { Sets a default Interbase port } if Self.Port = 0 then Self.Port := 3050; { set default sql dialect it can be overriden } FDialect := 3; UserSetDialect := Trim(URL.Properties.Values['dialect']); if UserSetDialect <> '' then FDialect := StrToIntDef(UserSetDialect, FDialect); { Processes connection properties. } self.Info.Values['isc_dpb_username'] := Url.UserName; self.Info.Values['isc_dpb_password'] := Url.Password; if FClientCodePage = '' then //was set on inherited Create(...) if URL.Properties.Values['isc_dpb_lc_ctype'] <> '' then //Check if Dev set's it manually begin FClientCodePage := URL.Properties.Values['isc_dpb_lc_ctype']; CheckCharEncoding(FClientCodePage, True); end; URL.Properties.Values['isc_dpb_lc_ctype'] := FClientCodePage; RoleName := Trim(URL.Properties.Values['rolename']); if RoleName <> '' then URL.Properties.Values['isc_dpb_sql_role_name'] := UpperCase(RoleName); ConnectTimeout := StrToIntDef(URL.Properties.Values['timeout'], -1); if ConnectTimeout >= 0 then URL.Properties.Values['isc_dpb_connect_timeout'] := IntToStr(ConnectTimeout); end; {** Creates a Statement object for sending SQL statements to the database. SQL statements without parameters are normally executed using Statement objects. If the same SQL statement is executed many times, it is more efficient to use a PreparedStatement object.

Result sets created using the returned Statement object will by default have forward-only type and read-only concurrency. @param Info a statement parameters. @return a new Statement object } function TZInterbase6Connection.CreateRegularStatement(Info: TStrings): IZStatement; begin if IsClosed then Open; Result := TZInterbase6Statement.Create(Self, Info); end; {** Destroys this object and cleanups the memory. } destructor TZInterbase6Connection.Destroy; begin if not Closed then Close; if FDisposeClientCodePage then Dispose(ConSettings^.ClientCodePage); //FreeMem for own created ClientCodePage rec inherited Destroy; end; {** Get database connection handle. @return database handle } function TZInterbase6Connection.GetDBHandle: PISC_DB_HANDLE; begin Result := @FHandle; end; {** Return Interbase dialect number. Dialect a dialect Interbase SQL must be 1 or 2 or 3. @return dialect number } function TZInterbase6Connection.GetDialect: Word; begin Result := FDialect; end; {** Return native interbase plain driver @return plain driver } function TZInterbase6Connection.GetPlainDriver: IZInterbasePlainDriver; begin Result := PlainDriver as IZInterbasePlainDriver; end; {** Get Interbase transaction handle @return transaction handle } function TZInterbase6Connection.GetTrHandle: PISC_TR_HANDLE; begin if (FHardCommit and (FTrHandle = 0)) then StartTransaction; Result := @FTrHandle; end; {** Opens a connection to database server with specified parameters. } procedure TZInterbase6Connection.Open; const sCS_NONE = 'NONE'; var DPB: PAnsiChar; FDPBLength: Word; DBName: array[0..512] of AnsiChar; TmpClientCodePageOld, TmpClientCodePageNew: PZCodePage; begin if not Closed then Exit; if TransactIsolationLevel = tiReadUncommitted then raise EZSQLException.Create('Isolation level do not capable'); if ConSettings^.ClientCodePage = nil then CheckCharEncoding(FClientCodePage, True); DPB := GenerateDPB(Info, FDPBLength, FDialect); if HostName <> '' then begin if Port <> 3050 then {$IFDEF WITH_STRPCOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrPCopy(DBName, ZPlainString(HostName + '/' + IntToStr(Port) + ':' + Database)) else {$IFDEF WITH_STRPCOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrPCopy(DBName, ZPlainString(HostName + ':' + Database)) end else {$IFDEF WITH_STRPCOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrPCopy(DBName, ZPlainString(Database)); try { Create new db if needed } if Info.Values['createNewDatabase'] <> '' then begin CreateNewDatabase(Info.Values['createNewDatabase']); { Logging connection action } DriverManager.LogMessage(lcConnect, PlainDriver.GetProtocol, Format('CREATE DATABASE "%s" AS USER "%s"', [Info.Values['createNewDatabase'], User])); URL.Properties.Values['createNewDatabase'] := ''; //Allready Connected now if successfully created end else begin FHandle := 0; { Connect to Interbase6 database. } GetPlainDriver.isc_attach_database(@FStatusVector, {$IFDEF WITH_STRLEN_DEPRECATED}AnsiStrings.{$ENDIF}StrLen(DBName), DBName, @FHandle, FDPBLength, DPB); { Check connection error } CheckInterbase6Error(GetPlainDriver, FStatusVector, lcConnect); end; { Logging connection action } DriverManager.LogMessage(lcConnect, PlainDriver.GetProtocol, Format('CONNECT TO "%s" AS USER "%s"', [Database, User])); { Start transaction } if not FHardCommit then StartTransaction; inherited Open; {Check for ClientCodePage: if empty switch to database-defaults and/or check for charset 'NONE' which has a different byte-width and no conversations where done except the collumns using collations} with GetMetadata.GetCollationAndCharSet('', '', '', '') do begin if Next then if FCLientCodePage = '' then begin FCLientCodePage := GetString(6); CheckCharEncoding(FClientCodePage); end else if GetString(6) = sCS_NONE then if not ( FClientCodePage = sCS_NONE ) then begin URL.Properties.Values['isc_dpb_lc_ctype'] := sCS_NONE; FClientCodePage := sCS_NONE; {save the user wanted CodePage-Informations} TmpClientCodePageOld := ConSettings.ClientCodePage; { charset 'NONE' can't converty anything and write 'Data as is'! If another charset was set on attaching the Server then all column collations are retrieved with newly choosen collation. BUT NO string convertations where done! So we need a reopen (since we can set the Client-CharacterSet only on connecting) to determine charset 'NONE' corectly. Then the column collations have there proper CharsetID's to encode all strings correctly. } Self.Close; Self.Open; { Create a new PZCodePage for the new environment-variables } TmpClientCodePageNew := New(PZCodePage); TmpClientCodePageNew.Name := sCS_NONE; TmpClientCodePageNew.ID := CS_NONE; TmpClientCodePageNew.CharWidth := 1; TmpClientCodePageNew.Encoding := TmpClientCodePageOld.Encoding; TmpClientCodePageNew.CP := TmpClientCodePageOld.CP; TmpClientCodePageNew.ZAlias := ''; TmpClientCodePageNew.IsStringFieldCPConsistent := False; ConSettings.ClientCodePage := TmpClientCodePageNew; SetConvertFunctions(ConSettings); //now let's the converters again FDisposeClientCodePage := True; {Also reset the MetaData ConSettings} (FMetadata as TZInterbase6DatabaseMetadata).ConSettings := ConSettings; { now we're able to read and write strings for columns without a spezial declared collation for charset 'NONE' with the user choosen CodePage and Encoding } end; Close; end; if FClientCodePage = sCS_NONE then ConSettings.AutoEncode := True; //Must be set! finally {$IFDEF WITH_STRDISPOSE_DEPRECATED}AnsiStrings.{$ENDIF}StrDispose(DPB); end; end; {** Creates a PreparedStatement object for sending parameterized SQL statements to the database. A SQL statement with or without IN parameters can be pre-compiled and stored in a PreparedStatement object. This object can then be used to efficiently execute this statement multiple times.

Note: This method is optimized for handling parametric SQL statements that benefit from precompilation. If the driver supports precompilation, the method prepareStatement will send the statement to the database for precompilation. Some drivers may not support precompilation. In this case, the statement may not be sent to the database until the PreparedStatement is executed. This has no direct effect on users; however, it does affect which method throws certain SQLExceptions. Result sets created using the returned PreparedStatement will have forward-only type and read-only concurrency, by default. @param sql a SQL statement that may contain one or more '?' IN parameter placeholders @return a new PreparedStatement object containing the pre-compiled statement } function TZInterbase6Connection.CreatePreparedStatement( const SQL: string; Info: TStrings): IZPreparedStatement; begin if IsClosed then Open; Result := TZInterbase6PreparedStatement.Create(Self, SQL, Info); end; {** Creates a CallableStatement object for calling database stored procedures. The CallableStatement object provides methods for setting up its IN and OUT parameters, and methods for executing the call to a stored procedure.

Note: This method is optimized for handling stored procedure call statements. Some drivers may send the call statement to the database when the method prepareCall is done; others may wait until the CallableStatement object is executed. This has no direct effect on users; however, it does affect which method throws certain SQLExceptions. Result sets created using the returned CallableStatement will have forward-only type and read-only concurrency, by default. @param sql a SQL statement that may contain one or more '?' parameter placeholders. Typically this statement is a JDBC function call escape string. @param Info a statement parameters. @return a new CallableStatement object containing the pre-compiled SQL statement } function TZInterbase6Connection.CreateCallableStatement(const SQL: string; Info: TStrings): IZCallableStatement; begin if IsClosed then Open; Result := TZInterbase6CallableStatement.Create(Self, SQL, Info); end; {** Drops all changes made since the previous commit/rollback and releases any database locks currently held by this Connection. This method should be used only when auto- commit has been disabled. @see #setAutoCommit } procedure TZInterbase6Connection.Rollback; begin if FTrHandle <> 0 then begin if FHardCommit then begin GetPlainDriver.isc_rollback_transaction(@FStatusVector, @FTrHandle); FTrHandle := 0; end else GetPlainDriver.isc_rollback_retaining(@FStatusVector, @FTrHandle); CheckInterbase6Error(GetPlainDriver, FStatusVector); DriverManager.LogMessage(lcTransaction, PlainDriver.GetProtocol, 'TRANSACTION ROLLBACK'); end; end; {** Checks if a connection is still alive by doing a call to isc_database_info It does not matter what info we request, we are not looking at it, as long as it is something which should _always_ work if the connection is there. We check if the error returned is one of the net_* errors described in the firebird client documentation (335544721 .. 335544727). Returns 0 if the connection is OK Returns non zeor if the connection is not OK } function TZInterbase6Connection.PingServer: integer; var DatabaseInfoCommand: Char; Buffer: array[0..IBBigLocalBufferLength - 1] of AnsiChar; ErrorCode: ISC_STATUS; begin DatabaseInfoCommand := Char(isc_info_reads); ErrorCode := GetPlainDriver.isc_database_info(@FStatusVector, @FHandle, 1, @DatabaseInfoCommand, IBLocalBufferLength, Buffer); if (ErrorCode >= 335544721) and (ErrorCode <= 335544727) then result := -1 else result := 0; end; {** Start Interbase transaction } procedure TZInterbase6Connection.StartTransaction; var Params: TStrings; PTEB: PISC_TEB; begin PTEB := nil; Params := TStringList.Create; { Set transaction parameters by TransactIsolationLevel } //Params.Values['isc_dpb_lc_ctype'] := FClientCodePage; //Set CharacterSet allways if option is set Params.Add('isc_tpb_version3'); case TransactIsolationLevel of tiReadCommitted: begin Params.Add('isc_tpb_read_committed'); Params.Add('isc_tpb_rec_version'); Params.Add('isc_tpb_nowait'); end; tiRepeatableRead: begin Params.Add('isc_tpb_concurrency'); Params.Add('isc_tpb_nowait'); end; tiSerializable: begin Params.Add('isc_tpb_consistency'); end; else begin { Add user defined parameters for transaction } Params.Clear; Params.AddStrings(Info); end; end; try { GenerateTPB return PTEB with null pointer tpb_address from default transaction } PTEB := GenerateTPB(Params, FHandle); GetPlainDriver.isc_start_multiple(@FStatusVector, @FTrHandle, 1, PTEB); CheckInterbase6Error(GetPlainDriver, FStatusVector, lcTransaction); DriverManager.LogMessage(lcTransaction, PlainDriver.GetProtocol, 'TRANSACTION STARTED.'); finally FreeAndNil(Params); {$IFDEF WITH_STRDISPOSE_DEPRECATED}AnsiStrings.{$ENDIF}StrDispose(PTEB.tpb_address); FreeMem(PTEB); end end; {** Creates new database @param SQL a sql strinf for creation database } procedure TZInterbase6Connection.CreateNewDatabase(const SQL: String); var TrHandle: TISC_TR_HANDLE; begin TrHandle := 0; GetPlainDriver.isc_dsql_execute_immediate(@FStatusVector, @FHandle, @TrHandle, 0, PAnsiChar({$IFDEF UNICODE}AnsiString{$ENDIF}(sql)), FDialect, nil); CheckInterbase6Error(GetPlainDriver, FStatusVector, lcExecute, SQL); end; function TZInterbase6Connection.GetBinaryEscapeString(const Value: RawByteString): String; begin //http://tracker.firebirdsql.org/browse/CORE-2789 if EndsWith(GetPlainDriver.GetProtocol, '2.5') then if (Length(Value)*2+3) < 32*1024 then Result := GetSQLHexString(PAnsiChar(Value), Length(Value)) else raise Exception.Create('Binary data out of range! Use parameters!') else raise Exception.Create('Your Firebird-Version does''t support Binary-Data in SQL-Statements! Use parameters!'); end; function TZInterbase6Connection.GetBinaryEscapeString(const Value: TByteDynArray): String; begin //http://tracker.firebirdsql.org/browse/CORE-2789 if EndsWith(GetPlainDriver.GetProtocol, '2.5') then if (Length(Value)*2+3) < 32*1024 then Result := GetSQLHexString(PAnsiChar(Value), Length(Value)) else raise Exception.Create('Binary data out of range! Use parameters!') else raise Exception.Create('Your Firebird-Version does''t support Binary-Data in SQL-Statements! Use parameters!'); end; function TZInterbase6Connection.GetEscapeString(const Value: RawByteString): RawByteString; begin //http://www.firebirdsql.org/manual/qsg10-firebird-sql.html if GetAutoEncodeStrings then if StartsWith(Value, RawByteString('''')) and EndsWith(Value, RawByteString('''')) then {$IFDEF UNICODE} Result := Value {$ELSE} Result := GetDriver.GetTokenizer.GetEscapeString(Value) {$ENDIF} else {$IFDEF UNICODE} Result := #39+{$IFDEF WITH_UNITANSISTRINGS}AnsiStrings.{$ENDIF}StringReplace(Value, #39, #39#39, [rfReplaceAll])+#39 {$ELSE} Result := GetDriver.GetTokenizer.GetEscapeString(#39+StringReplace(Value, #39, #39#39, [rfReplaceAll])+#39) {$ENDIF} else if StartsWith(Value, RawByteString('''')) and EndsWith(Value, RawByteString('''')) then Result := Value else Result := #39+{$IFDEF WITH_UNITANSISTRINGS}AnsiStrings.{$ENDIF}StringReplace(Value, #39, #39#39, [rfReplaceAll])+#39; end; function TZInterbase6Connection.GetEscapeString(const Value: ZWideString): ZWideString; begin //http://www.firebirdsql.org/manual/qsg10-firebird-sql.html if GetAutoEncodeStrings then if StartsWith(Value, ZWideString('''')) and EndsWith(Value, ZWideString('''')) then {$IFDEF UNICODE} Result := GetDriver.GetTokenizer.GetEscapeString(Value) {$ELSE} Result := Value {$ENDIF} else {$IFDEF UNICODE} Result := GetDriver.GetTokenizer.GetEscapeString(#39+StringReplace(Value, #39, #39#39, [rfReplaceAll])+#39) {$ELSE} Result := ZDbcUnicodeString(GetDriver.GetTokenizer.GetEscapeString(#39+StringReplace(ZPlainString(Value), #39, #39#39, [rfReplaceAll])+#39)) {$ENDIF} else if StartsWith(Value, ZWideString('''')) and EndsWith(Value, ZWideString('''')) then Result := Value else {$IFDEF UNICODE} Result := #39+StringReplace(Value, #39, #39#39, [rfReplaceAll])+#39; {$ELSE} Result := ZDbcUnicodeString(#39+StringReplace(ZPlainString(Value), #39, #39#39, [rfReplaceAll])+#39); {$ENDIF} end; {** Creates a sequence generator object. @param Sequence a name of the sequence generator. @param BlockSize a number of unique keys requested in one trip to SQL server. @returns a created sequence object. } function TZInterbase6Connection.CreateSequence(const Sequence: string; BlockSize: Integer): IZSequence; begin Result := TZInterbase6Sequence.Create(Self, Sequence, BlockSize); end; { TZInterbase6CachedResolver } {** Forms a where clause for SELECT statements to calculate default values. @param Columns a collection of key columns. @param OldRowAccessor an accessor object to old column values. } function TZInterbase6CachedResolver.FormCalculateStatement( Columns: TObjectList): string; // --> ms, 30/10/2005 var iPos: Integer; begin Result := inherited FormCalculateStatement(Columns); if Result <> '' then begin iPos := pos('FROM', uppercase(Result)); if iPos > 0 then begin Result := copy(Result, 1, iPos+3) + ' RDB$DATABASE'; end else begin Result := Result + ' FROM RDB$DATABASE'; end; end; // <-- ms end; { TZInterbase6Sequence } {** Gets the current unique key generated by this sequence. @param the next generated unique key. } function TZInterbase6Sequence.GetCurrentValue: Int64; var Statement: IZStatement; ResultSet: IZResultSet; begin Statement := Connection.CreateStatement; ResultSet := Statement.ExecuteQuery(Format( 'SELECT GEN_ID("%s", 0) FROM rdb$generators ' + 'WHERE rdb$generators.rdb$generator_name = ''%s''', [Name, Name])); if ResultSet.Next then Result := ResultSet.GetLong(1) else Result := inherited GetCurrentValue; ResultSet.Close; Statement.Close; end; {** Gets the next unique key generated by this sequence. @param the next generated unique key. } function TZInterbase6Sequence.GetCurrentValueSQL: string; begin Result := Format(' GEN_ID("%s", 0) ', [Name]); end; function TZInterbase6Sequence.GetNextValue: Int64; var Statement: IZStatement; ResultSet: IZResultSet; begin Statement := Connection.CreateStatement; ResultSet := Statement.ExecuteQuery(Format( 'SELECT GEN_ID("%s", %d) FROM rdb$generators ' + 'WHERE rdb$generators.rdb$generator_name = ''%s''', [Name, BlockSize, Name])); if ResultSet.Next then Result := ResultSet.GetLong(1) else Result := inherited GetNextValue; ResultSet.Close; Statement.Close; end; function TZInterbase6Sequence.GetNextValueSQL: string; begin Result := Format(' GEN_ID("%s", %d) ', [Name, BlockSize]); end; initialization Interbase6Driver := TZInterbase6Driver.Create; DriverManager.RegisterDriver(Interbase6Driver); finalization if Assigned(DriverManager) then DriverManager.DeregisterDriver(Interbase6Driver); Interbase6Driver := nil; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcInterbase6Metadata.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Interbase Database Connectivity Classes } { } { Originally written by Sergey Merkuriev } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcInterbase6Metadata; interface {$I ZDbc.inc} uses Types, Classes, SysUtils, ZSysUtils, ZDbcIntfs, ZDbcMetadata, ZCompatibility, ZDbcConnection, ZDbcInterbase6, ZURL; type // technobot 2008-06-25 - methods moved as is from TZInterbase6DatabaseMetadata: {** Implements Interbase6 Database Information. } TZInterbase6DatabaseInfo = class(TZAbstractDatabaseInfo) private FServerVersion: string; // function UncachedGetUDTs(const Catalog: string; const SchemaPattern: string; // const TypeNamePattern: string; const Types: TIntegerDynArray): IZResultSet; override; public // database/driver/server info: function GetDatabaseProductName: string; override; function GetDatabaseProductVersion: string; override; function GetDriverName: string; override; // function GetDriverVersion: string; override; -> Same as parent function GetDriverMajorVersion: Integer; override; function GetDriverMinorVersion: Integer; override; function GetServerVersion: string; // capabilities (what it can/cannot do): // function AllProceduresAreCallable: Boolean; override; -> Not implemented // function AllTablesAreSelectable: Boolean; override; -> Not implemented function SupportsMixedCaseIdentifiers: Boolean; override; function SupportsMixedCaseQuotedIdentifiers: Boolean; override; // function SupportsAlterTableWithAddColumn: Boolean; override; -> Not implemented // function SupportsAlterTableWithDropColumn: Boolean; override; -> Not implemented // function SupportsColumnAliasing: Boolean; override; -> Not implemented // function SupportsConvert: Boolean; override; -> Not implemented // function SupportsConvertForTypes(FromType: TZSQLType; ToType: TZSQLType): // Boolean; override; -> Not implemented // function SupportsTableCorrelationNames: Boolean; override; -> Not implemented // function SupportsDifferentTableCorrelationNames: Boolean; override; -> Not implemented function SupportsExpressionsInOrderBy: Boolean; override; function SupportsOrderByUnrelated: Boolean; override; function SupportsGroupBy: Boolean; override; function SupportsGroupByUnrelated: Boolean; override; function SupportsGroupByBeyondSelect: Boolean; override; // function SupportsLikeEscapeClause: Boolean; override; -> Not implemented // function SupportsMultipleResultSets: Boolean; override; -> Not implemented // function SupportsMultipleTransactions: Boolean; override; -> Not implemented // function SupportsNonNullableColumns: Boolean; override; -> Not implemented // function SupportsMinimumSQLGrammar: Boolean; override; -> Not implemented // function SupportsCoreSQLGrammar: Boolean; override; -> Not implemented // function SupportsExtendedSQLGrammar: Boolean; override; -> Not implemented // function SupportsANSI92EntryLevelSQL: Boolean; override; -> Not implemented // function SupportsANSI92IntermediateSQL: Boolean; override; -> Not implemented // function SupportsANSI92FullSQL: Boolean; override; -> Not implemented function SupportsIntegrityEnhancementFacility: Boolean; override; // function SupportsOuterJoins: Boolean; override; -> Not implemented // function SupportsFullOuterJoins: Boolean; override; -> Not implemented // function SupportsLimitedOuterJoins: Boolean; override; -> Not implemented function SupportsSchemasInDataManipulation: Boolean; override; function SupportsSchemasInProcedureCalls: Boolean; override; function SupportsSchemasInTableDefinitions: Boolean; override; function SupportsSchemasInIndexDefinitions: Boolean; override; function SupportsSchemasInPrivilegeDefinitions: Boolean; override; function SupportsCatalogsInDataManipulation: Boolean; override; function SupportsCatalogsInProcedureCalls: Boolean; override; function SupportsCatalogsInTableDefinitions: Boolean; override; function SupportsCatalogsInIndexDefinitions: Boolean; override; function SupportsCatalogsInPrivilegeDefinitions: Boolean; override; function SupportsPositionedDelete: Boolean; override; function SupportsPositionedUpdate: Boolean; override; function SupportsSelectForUpdate: Boolean; override; function SupportsStoredProcedures: Boolean; override; function SupportsSubqueriesInComparisons: Boolean; override; function SupportsSubqueriesInExists: Boolean; override; function SupportsSubqueriesInIns: Boolean; override; function SupportsSubqueriesInQuantifieds: Boolean; override; function SupportsCorrelatedSubqueries: Boolean; override; function SupportsUnion: Boolean; override; function SupportsUnionAll: Boolean; override; function SupportsOpenCursorsAcrossCommit: Boolean; override; function SupportsOpenCursorsAcrossRollback: Boolean; override; function SupportsOpenStatementsAcrossCommit: Boolean; override; function SupportsOpenStatementsAcrossRollback: Boolean; override; function SupportsTransactions: Boolean; override; function SupportsTransactionIsolationLevel(Level: TZTransactIsolationLevel): Boolean; override; function SupportsDataDefinitionAndDataManipulationTransactions: Boolean; override; function SupportsDataManipulationTransactionsOnly: Boolean; override; function SupportsResultSetType(_Type: TZResultSetType): Boolean; override; function SupportsResultSetConcurrency(_Type: TZResultSetType; Concurrency: TZResultSetConcurrency): Boolean; override; // function SupportsBatchUpdates: Boolean; override; -> Not implemented // maxima: function GetMaxBinaryLiteralLength: Integer; override; function GetMaxCharLiteralLength: Integer; override; function GetMaxColumnNameLength: Integer; override; function GetMaxColumnsInGroupBy: Integer; override; function GetMaxColumnsInIndex: Integer; override; function GetMaxColumnsInOrderBy: Integer; override; function GetMaxColumnsInSelect: Integer; override; function GetMaxColumnsInTable: Integer; override; function GetMaxConnections: Integer; override; function GetMaxCursorNameLength: Integer; override; function GetMaxIndexLength: Integer; override; function GetMaxSchemaNameLength: Integer; override; function GetMaxProcedureNameLength: Integer; override; function GetMaxCatalogNameLength: Integer; override; function GetMaxRowSize: Integer; override; function GetMaxStatementLength: Integer; override; function GetMaxStatements: Integer; override; function GetMaxTableNameLength: Integer; override; function GetMaxTablesInSelect: Integer; override; function GetMaxUserNameLength: Integer; override; // policies (how are various data and operations handled): // function IsReadOnly: Boolean; override; -> Not implemented // function IsCatalogAtStart: Boolean; override; -> Not implemented function DoesMaxRowSizeIncludeBlobs: Boolean; override; // function NullsAreSortedHigh: Boolean; override; -> Not implemented // function NullsAreSortedLow: Boolean; override; -> Not implemented // function NullsAreSortedAtStart: Boolean; override; -> Not implemented // function NullsAreSortedAtEnd: Boolean; override; -> Not implemented // function NullPlusNonNullIsNull: Boolean; override; -> Not implemented // function UsesLocalFiles: Boolean; override; -> Not implemented function UsesLocalFilePerTable: Boolean; override; function StoresUpperCaseIdentifiers: Boolean; override; function StoresLowerCaseIdentifiers: Boolean; override; function StoresMixedCaseIdentifiers: Boolean; override; function StoresUpperCaseQuotedIdentifiers: Boolean; override; function StoresLowerCaseQuotedIdentifiers: Boolean; override; function StoresMixedCaseQuotedIdentifiers: Boolean; override; function GetDefaultTransactionIsolation: TZTransactIsolationLevel; override; function DataDefinitionCausesTransactionCommit: Boolean; override; function DataDefinitionIgnoredInTransactions: Boolean; override; // interface details (terms, keywords, etc): function GetSchemaTerm: string; override; function GetProcedureTerm: string; override; function GetCatalogTerm: string; override; function GetCatalogSeparator: string; override; function GetSQLKeywords: string; override; function GetNumericFunctions: string; override; function GetStringFunctions: string; override; function GetSystemFunctions: string; override; function GetTimeDateFunctions: string; override; function GetSearchStringEscape: string; override; function GetExtraNameCharacters: string; override; end; {** Implements Interbase6 Database Metadata. } TZInterbase6DatabaseMetadata = class(TZAbstractDatabaseMetadata) private function GetPrivilege(Privilege: string): string; protected function CreateDatabaseInfo: IZDatabaseInfo; override; // technobot 2008-06-25 function ConstructNameCondition(Pattern: string; Column: string): string; override; function UncachedGetTables(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const Types: TStringDynArray): IZResultSet; override; // function UncachedGetSchemas: IZResultSet; override; -> Not implemented // function UncachedGetCatalogs: IZResultSet; override; -> Not Implemented function UncachedGetTableTypes: IZResultSet; override; function UncachedGetColumns(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const ColumnNamePattern: string): IZResultSet; override; function UncachedGetTablePrivileges(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string): IZResultSet; override; function UncachedGetColumnPrivileges(const Catalog: string; const Schema: string; const Table: string; const ColumnNamePattern: string): IZResultSet; override; function UncachedGetPrimaryKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; override; function UncachedGetImportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; override; function UncachedGetExportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; override; function UncachedGetCrossReference(const PrimaryCatalog: string; const PrimarySchema: string; const PrimaryTable: string; const ForeignCatalog: string; const ForeignSchema: string; const ForeignTable: string): IZResultSet; override; function UncachedGetIndexInfo(const Catalog: string; const Schema: string; const Table: string; Unique: Boolean; Approximate: Boolean): IZResultSet; override; function UncachedGetSequences(const Catalog: string; const SchemaPattern: string; const SequenceNamePattern: string): IZResultSet; override; function UncachedGetProcedures(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string): IZResultSet; override; function UncachedGetProcedureColumns(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string; const ColumnNamePattern: string): IZResultSet; override; function UncachedGetVersionColumns(const Catalog: string; const Schema: string; const Table: string): IZResultSet; override; function UncachedGetTypeInfo: IZResultSet; override; function UncachedGetTriggers(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const TriggerNamePattern: string): IZResultSet; override; //EgonHugesit function UncachedGetCollationAndCharSet(const Catalog, SchemaPattern, TableNamePattern, ColumnNamePattern: string): IZResultSet; override; //EgonHugeist function UncachedGetCharacterSets: IZResultSet; override; //EgonHugeist public property ConSettings; end; implementation uses ZMessages, ZDbcInterbase6Utils, ZDbcUtils; { TZInterbase6DatabaseInfo } //---------------------------------------------------------------------- // First, a variety of minor information about the target database. {** What's the name of this database product? @return database product name } function TZInterbase6DatabaseInfo.GetDatabaseProductName: string; begin Result := 'Interbase/Firebird'; end; {** What's the version of this database product? @return database version } function TZInterbase6DatabaseInfo.GetDatabaseProductVersion: string; begin Result := '6.0+'; end; {** What's the name of this JDBC driver? @return JDBC driver name } function TZInterbase6DatabaseInfo.GetDriverName: string; begin Result := 'Zeos Database Connectivity Driver for Interbase and Firebird'; end; {** What's this JDBC driver's major version number? @return JDBC driver major version } function TZInterbase6DatabaseInfo.GetDriverMajorVersion: Integer; begin Result := 1; end; {** What's this JDBC driver's minor version number? @return JDBC driver minor version number } function TZInterbase6DatabaseInfo.GetDriverMinorVersion: Integer; begin Result := 0; end; {** Gets the version of the server. @returns the version of the server. } function TZInterbase6DatabaseInfo.GetServerVersion: string; var FIBConnection: IZInterbase6Connection; begin if FServerVersion = '' then begin FIBConnection := Metadata.GetConnection as IZInterbase6Connection; FServerVersion := String(GetVersion(FIBConnection.GetPlainDriver, FIBConnection.GetDBHandle)); end; Result := FServerVersion; end; {** Does the database use a file for each table? @return true if the database uses a local file for each table } function TZInterbase6DatabaseInfo.UsesLocalFilePerTable: Boolean; begin Result := False; end; {** Does the database treat mixed case unquoted SQL identifiers as case sensitive and as a result store them in mixed case? A JDBC CompliantTM driver will always return false. @return true if so; false otherwise } function TZInterbase6DatabaseInfo.SupportsMixedCaseIdentifiers: Boolean; begin Result := True; end; {** Does the database treat mixed case unquoted SQL identifiers as case insensitive and store them in upper case? @return true if so; false otherwise } function TZInterbase6DatabaseInfo.StoresUpperCaseIdentifiers: Boolean; begin Result := True; end; {** Does the database treat mixed case unquoted SQL identifiers as case insensitive and store them in lower case? @return true if so; false otherwise } function TZInterbase6DatabaseInfo.StoresLowerCaseIdentifiers: Boolean; begin Result := False; end; {** Does the database treat mixed case unquoted SQL identifiers as case insensitive and store them in mixed case? @return true if so; false otherwise } function TZInterbase6DatabaseInfo.StoresMixedCaseIdentifiers: Boolean; begin Result := False; end; {** Does the database treat mixed case quoted SQL identifiers as case sensitive and as a result store them in mixed case? A JDBC CompliantTM driver will always return true. @return true if so; false otherwise } function TZInterbase6DatabaseInfo.SupportsMixedCaseQuotedIdentifiers: Boolean; begin Result := True; end; {** Does the database treat mixed case quoted SQL identifiers as case insensitive and store them in upper case? @return true if so; false otherwise } function TZInterbase6DatabaseInfo.StoresUpperCaseQuotedIdentifiers: Boolean; begin Result := False; end; {** Does the database treat mixed case quoted SQL identifiers as case insensitive and store them in lower case? @return true if so; false otherwise } function TZInterbase6DatabaseInfo.StoresLowerCaseQuotedIdentifiers: Boolean; begin Result := False; end; {** Does the database treat mixed case quoted SQL identifiers as case insensitive and store them in mixed case? @return true if so; false otherwise } function TZInterbase6DatabaseInfo.StoresMixedCaseQuotedIdentifiers: Boolean; begin Result := True; end; {** Gets a comma-separated list of all a database's SQL keywords that are NOT also SQL92 keywords. @return the list } function TZInterbase6DatabaseInfo.GetSQLKeywords: string; begin Result := 'ACTIVE,AFTER,ASCENDING,BASE_NAME,BEFORE,BLOB,' + 'CACHE,CHECK_POINT_LENGTH,COMPUTED,CONDITIONAL,CONTAINING,' + 'CSTRING,DATABASE,RDB$DB_KEY,DEBUG,DESCENDING,DO,ENTRY_POINT,' + 'EXIT,FILE,FILTER,FUNCTION,GDSCODE,GENERATOR,GEN_ID,' + 'GROUP_COMMIT_WAIT_TIME,IF,INACTIVE,INPUT_TYPE,INDEX,' + 'LOGFILE,LOG_BUFFER_SIZE,MANUAL,MAXIMUM_SEGMENT,MERGE, MESSAGE,' + 'MODULE_NAME,NCHAR,NUM_LOG_BUFFERS,OUTPUT_TYPE,OVERFLOW,PAGE,' + 'PAGES,PAGE_SIZE,PARAMETER,PASSWORD,PLAN,POST_EVENT,PROTECTED,' + 'RAW_PARTITIONS,RESERV,RESERVING,RETAIN,RETURNING_VALUES,RETURNS,' + 'SEGMENT,SHADOW,SHARED,SINGULAR,SNAPSHOT,SORT,STABILITY,STARTS,' + 'STARTING,STATISTICS,SUB_TYPE,SUSPEND,TRIGGER,VARIABLE,RECORD_VERSION,' + 'WAIT,WHILE,WORK,VALUE,POSITION,USER,CURRENCY,OPTION,DATE,START,END,USER,' + 'READ,PARENT,TYPE'+ {Ticket #63: http://sourceforge.net/p/zeoslib/tickets/62/} ',DEC,TIME,MIN,MAX'+ {FireBird 3.0} ',DETERMINISTIC,OVER,RETURN,SCROLL,SQLSTATE'; end; {** Gets a comma-separated list of math functions. These are the X/Open CLI math function names used in the JDBC function escape clause. @return the list } function TZInterbase6DatabaseInfo.GetNumericFunctions: string; begin Result := ''; end; {** Gets a comma-separated list of string functions. These are the X/Open CLI string function names used in the JDBC function escape clause. @return the list } function TZInterbase6DatabaseInfo.GetStringFunctions: string; begin Result := ''; end; {** Gets a comma-separated list of system functions. These are the X/Open CLI system function names used in the JDBC function escape clause. @return the list } function TZInterbase6DatabaseInfo.GetSystemFunctions: string; begin Result := ''; end; {** Gets a comma-separated list of time and date functions. @return the list } function TZInterbase6DatabaseInfo.GetTimeDateFunctions: string; begin Result := ''; end; {** Gets the string that can be used to escape wildcard characters. This is the string that can be used to escape '_' or '%' in the string pattern style catalog search parameters.

The '_' character represents any single character.

The '%' character represents any sequence of zero or more characters. @return the string used to escape wildcard characters } function TZInterbase6DatabaseInfo.GetSearchStringEscape: string; begin Result := '\'; end; {** Gets all the "extra" characters that can be used in unquoted identifier names (those beyond a-z, A-Z, 0-9 and _). @return the string containing the extra characters } function TZInterbase6DatabaseInfo.GetExtraNameCharacters: string; begin Result := '$'; end; //-------------------------------------------------------------------- // Functions describing which features are supported. {** Are expressions in "ORDER BY" lists supported? @return true if so; false otherwise } function TZInterbase6DatabaseInfo.SupportsExpressionsInOrderBy: Boolean; begin Result := False; end; {** Can an "ORDER BY" clause use columns not in the SELECT statement? @return true if so; false otherwise } function TZInterbase6DatabaseInfo.SupportsOrderByUnrelated: Boolean; begin Result := True; end; {** Is some form of "GROUP BY" clause supported? @return true if so; false otherwise } function TZInterbase6DatabaseInfo.SupportsGroupBy: Boolean; begin Result := True; end; {** Can a "GROUP BY" clause use columns not in the SELECT? @return true if so; false otherwise } function TZInterbase6DatabaseInfo.SupportsGroupByUnrelated: Boolean; begin Result := True; end; {** Can a "GROUP BY" clause add columns not in the SELECT provided it specifies all the columns in the SELECT? @return true if so; false otherwise } function TZInterbase6DatabaseInfo.SupportsGroupByBeyondSelect: Boolean; begin Result := True; end; {** Is the SQL Integrity Enhancement Facility supported? @return true if so; false otherwise } function TZInterbase6DatabaseInfo.SupportsIntegrityEnhancementFacility: Boolean; begin Result := False; end; {** What's the database vendor's preferred term for "schema"? @return the vendor term } function TZInterbase6DatabaseInfo.GetSchemaTerm: string; begin Result := ''; end; {** What's the database vendor's preferred term for "procedure"? @return the vendor term } function TZInterbase6DatabaseInfo.GetProcedureTerm: string; begin Result := 'PROCEDURE'; end; {** What's the database vendor's preferred term for "catalog"? @return the vendor term } function TZInterbase6DatabaseInfo.GetCatalogTerm: string; begin Result := ''; end; {** What's the separator between catalog and table name? @return the separator string } function TZInterbase6DatabaseInfo.GetCatalogSeparator: string; begin Result := ''; end; {** Can a schema name be used in a data manipulation statement? @return true if so; false otherwise } function TZInterbase6DatabaseInfo.SupportsSchemasInDataManipulation: Boolean; begin Result := False; end; {** Can a schema name be used in a procedure call statement? @return true if so; false otherwise } function TZInterbase6DatabaseInfo.SupportsSchemasInProcedureCalls: Boolean; begin Result := False; end; {** Can a schema name be used in a table definition statement? @return true if so; false otherwise } function TZInterbase6DatabaseInfo.SupportsSchemasInTableDefinitions: Boolean; begin Result := False; end; {** Can a schema name be used in an index definition statement? @return true if so; false otherwise } function TZInterbase6DatabaseInfo.SupportsSchemasInIndexDefinitions: Boolean; begin Result := False; end; {** Can a schema name be used in a privilege definition statement? @return true if so; false otherwise } function TZInterbase6DatabaseInfo.SupportsSchemasInPrivilegeDefinitions: Boolean; begin Result := False; end; {** Can a catalog name be used in a data manipulation statement? @return true if so; false otherwise } function TZInterbase6DatabaseInfo.SupportsCatalogsInDataManipulation: Boolean; begin Result := False; end; {** Can a catalog name be used in a procedure call statement? @return true if so; false otherwise } function TZInterbase6DatabaseInfo.SupportsCatalogsInProcedureCalls: Boolean; begin Result := False; end; {** Can a catalog name be used in a table definition statement? @return true if so; false otherwise } function TZInterbase6DatabaseInfo.SupportsCatalogsInTableDefinitions: Boolean; begin Result := False; end; {** Can a catalog name be used in an index definition statement? @return true if so; false otherwise } function TZInterbase6DatabaseInfo.SupportsCatalogsInIndexDefinitions: Boolean; begin Result := False; end; {** Can a catalog name be used in a privilege definition statement? @return true if so; false otherwise } function TZInterbase6DatabaseInfo.SupportsCatalogsInPrivilegeDefinitions: Boolean; begin Result := False; end; {** Is positioned DELETE supported? @return true if so; false otherwise } function TZInterbase6DatabaseInfo.SupportsPositionedDelete: Boolean; begin Result := True; end; {** Is positioned UPDATE supported? @return true if so; false otherwise } function TZInterbase6DatabaseInfo.SupportsPositionedUpdate: Boolean; begin Result := True; end; {** Is SELECT for UPDATE supported? @return true if so; false otherwise } function TZInterbase6DatabaseInfo.SupportsSelectForUpdate: Boolean; begin Result := True; end; {** Are stored procedure calls using the stored procedure escape syntax supported? @return true if so; false otherwise } function TZInterbase6DatabaseInfo.SupportsStoredProcedures: Boolean; begin Result := True; end; {** Are subqueries in comparison expressions supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZInterbase6DatabaseInfo.SupportsSubqueriesInComparisons: Boolean; begin Result := True; end; {** Are subqueries in 'exists' expressions supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZInterbase6DatabaseInfo.SupportsSubqueriesInExists: Boolean; begin Result := True; end; {** Are subqueries in 'in' statements supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZInterbase6DatabaseInfo.SupportsSubqueriesInIns: Boolean; begin Result := False; end; {** Are subqueries in quantified expressions supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZInterbase6DatabaseInfo.SupportsSubqueriesInQuantifieds: Boolean; begin Result := True; end; {** Are correlated subqueries supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZInterbase6DatabaseInfo.SupportsCorrelatedSubqueries: Boolean; begin Result := True; end; {** Is SQL UNION supported? @return true if so; false otherwise } function TZInterbase6DatabaseInfo.SupportsUnion: Boolean; begin Result := True; end; {** Is SQL UNION ALL supported? @return true if so; false otherwise } function TZInterbase6DatabaseInfo.SupportsUnionAll: Boolean; begin Result := True; end; {** Can cursors remain open across commits? @return true if cursors always remain open; false if they might not remain open } function TZInterbase6DatabaseInfo.SupportsOpenCursorsAcrossCommit: Boolean; begin Result := False; end; {** Can cursors remain open across rollbacks? @return true if cursors always remain open; false if they might not remain open } function TZInterbase6DatabaseInfo.SupportsOpenCursorsAcrossRollback: Boolean; begin Result := False; end; {** Can statements remain open across commits? @return true if statements always remain open; false if they might not remain open } function TZInterbase6DatabaseInfo.SupportsOpenStatementsAcrossCommit: Boolean; begin Result := True; end; {** Can statements remain open across rollbacks? @return true if statements always remain open; false if they might not remain open } function TZInterbase6DatabaseInfo.SupportsOpenStatementsAcrossRollback: Boolean; begin Result := True; end; //---------------------------------------------------------------------- // The following group of methods exposes various limitations // based on the target database with the current driver. // Unless otherwise specified, a result of zero means there is no // limit, or the limit is not known. {** How many hex characters can you have in an inline binary literal? @return max binary literal length in hex characters; a result of zero means that there is no limit or the limit is not known } function TZInterbase6DatabaseInfo.GetMaxBinaryLiteralLength: Integer; begin Result := 0; end; {** What's the max length for a character literal? @return max literal length; a result of zero means that there is no limit or the limit is not known } function TZInterbase6DatabaseInfo.GetMaxCharLiteralLength: Integer; begin Result := 1024; end; {** What's the limit on column name length? @return max column name length; a result of zero means that there is no limit or the limit is not known } function TZInterbase6DatabaseInfo.GetMaxColumnNameLength: Integer; begin Result := 31; end; {** What's the maximum number of columns in a "GROUP BY" clause? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZInterbase6DatabaseInfo.GetMaxColumnsInGroupBy: Integer; begin Result := 16; end; {** What's the maximum number of columns allowed in an index? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZInterbase6DatabaseInfo.GetMaxColumnsInIndex: Integer; begin Result := 16; end; {** What's the maximum number of columns in an "ORDER BY" clause? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZInterbase6DatabaseInfo.GetMaxColumnsInOrderBy: Integer; begin Result := 16; end; {** What's the maximum number of columns in a "SELECT" list? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZInterbase6DatabaseInfo.GetMaxColumnsInSelect: Integer; begin Result := 32767; end; {** What's the maximum number of columns in a table? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZInterbase6DatabaseInfo.GetMaxColumnsInTable: Integer; begin Result := 32767; end; {** How many active connections can we have at a time to this database? @return max number of active connections; a result of zero means that there is no limit or the limit is not known } function TZInterbase6DatabaseInfo.GetMaxConnections: Integer; begin Result := 0; end; {** What's the maximum cursor name length? @return max cursor name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZInterbase6DatabaseInfo.GetMaxCursorNameLength: Integer; begin Result := 31; end; {** Retrieves the maximum number of bytes for an index, including all of the parts of the index. @return max index length in bytes, which includes the composite of all the constituent parts of the index; a result of zero means that there is no limit or the limit is not known } function TZInterbase6DatabaseInfo.GetMaxIndexLength: Integer; begin Result := 198; end; {** What's the maximum length allowed for a schema name? @return max name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZInterbase6DatabaseInfo.GetMaxSchemaNameLength: Integer; begin Result := 0; end; {** What's the maximum length of a procedure name? @return max name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZInterbase6DatabaseInfo.GetMaxProcedureNameLength: Integer; begin Result := 0; end; {** What's the maximum length of a catalog name? @return max name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZInterbase6DatabaseInfo.GetMaxCatalogNameLength: Integer; begin Result := 27; end; {** What's the maximum length of a single row? @return max row size in bytes; a result of zero means that there is no limit or the limit is not known } function TZInterbase6DatabaseInfo.GetMaxRowSize: Integer; begin Result := 32664; end; {** Did getMaxRowSize() include LONGVARCHAR and LONGVARBINARY blobs? @return true if so; false otherwise } function TZInterbase6DatabaseInfo.DoesMaxRowSizeIncludeBlobs: Boolean; begin Result := False; end; {** What's the maximum length of an SQL statement? @return max length in bytes; a result of zero means that there is no limit or the limit is not known } function TZInterbase6DatabaseInfo.GetMaxStatementLength: Integer; begin Result := 640; end; {** How many active statements can we have open at one time to this database? @return the maximum number of statements that can be open at one time; a result of zero means that there is no limit or the limit is not known } function TZInterbase6DatabaseInfo.GetMaxStatements: Integer; begin Result := 0; end; {** What's the maximum length of a table name? @return max name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZInterbase6DatabaseInfo.GetMaxTableNameLength: Integer; begin Result := 31; end; {** What's the maximum number of tables in a SELECT statement? @return the maximum number of tables allowed in a SELECT statement; a result of zero means that there is no limit or the limit is not known } function TZInterbase6DatabaseInfo.GetMaxTablesInSelect: Integer; begin Result := 16; end; {** What's the maximum length of a user name? @return max user name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZInterbase6DatabaseInfo.GetMaxUserNameLength: Integer; begin Result := 31; end; //---------------------------------------------------------------------- {** What's the database's default transaction isolation level? The values are defined in java.sql.Connection. @return the default isolation level @see Connection } function TZInterbase6DatabaseInfo.GetDefaultTransactionIsolation: TZTransactIsolationLevel; begin Result := tiSerializable; end; {** Are transactions supported? If not, invoking the method commit is a noop and the isolation level is TRANSACTION_NONE. @return true if transactions are supported; false otherwise } function TZInterbase6DatabaseInfo.SupportsTransactions: Boolean; begin Result := True; end; {** Does this database support the given transaction isolation level? @param level the values are defined in java.sql.Connection @return true if so; false otherwise @see Connection } function TZInterbase6DatabaseInfo.SupportsTransactionIsolationLevel( Level: TZTransactIsolationLevel): Boolean; begin case Level of tiRepeatableRead, tiReadCommitted, tiSerializable: Result := True; tiReadUncommitted: Result := False; tiNone: Result := False; //MAY BE FIX IT else Result := False; end; end; {** Are both data definition and data manipulation statements within a transaction supported? @return true if so; false otherwise } function TZInterbase6DatabaseInfo. SupportsDataDefinitionAndDataManipulationTransactions: Boolean; begin Result := True; end; {** Are only data manipulation statements within a transaction supported? @return true if so; false otherwise } function TZInterbase6DatabaseInfo. SupportsDataManipulationTransactionsOnly: Boolean; begin Result := False; end; {** Does a data definition statement within a transaction force the transaction to commit? @return true if so; false otherwise } function TZInterbase6DatabaseInfo.DataDefinitionCausesTransactionCommit: Boolean; begin Result := True; end; {** Is a data definition statement within a transaction ignored? @return true if so; false otherwise } function TZInterbase6DatabaseInfo.DataDefinitionIgnoredInTransactions: Boolean; begin Result := False; end; {** Does the database support the given result set type? @param type defined in java.sql.ResultSet @return true if so; false otherwise } function TZInterbase6DatabaseInfo.SupportsResultSetType( _Type: TZResultSetType): Boolean; begin Result := _Type = rtScrollInsensitive; end; {** Does the database support the concurrency type in combination with the given result set type? @param type defined in java.sql.ResultSet @param concurrency type defined in java.sql.ResultSet @return true if so; false otherwise } function TZInterbase6DatabaseInfo.SupportsResultSetConcurrency( _Type: TZResultSetType; Concurrency: TZResultSetConcurrency): Boolean; begin Result := (_Type = rtScrollInsensitive) and (Concurrency = rcReadOnly); end; { TZInterbase6DatabaseMetadata } {** Constructs a database information object and returns the interface to it. Used internally by the constructor. @return the database information object interface } function TZInterbase6DatabaseMetadata.CreateDatabaseInfo: IZDatabaseInfo; begin Result := TZInterbase6DatabaseInfo.Create(Self); end; function TZInterbase6DatabaseMetadata.ConstructNameCondition(Pattern: string; Column: string): string; begin Result := Inherited ConstructnameCondition(Pattern,'trim('+Column+')'); end; function TZInterbase6DatabaseMetadata.UncachedGetTriggers(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const TriggerNamePattern: string): IZResultSet; var SQL: string; LTriggerNamePattern: string; LTableNamePattern: string; begin Result:=inherited UncachedGetTriggers(Catalog, SchemaPattern, TableNamePattern, TriggerNamePattern); LTriggerNamePattern := ConstructNameCondition(TriggerNamePattern, 'RDB$TRIGGER_NAME'); LTableNamePattern := ConstructNameCondition(TableNamePattern, 'RDB$RELATION_NAME'); If LTriggerNamePattern <> '' then LTriggerNamePattern := ' and ' + LTriggerNamePattern; If LTableNamePattern <> '' then LTableNamePattern := ' and ' + LTableNamePattern; SQL := 'SELECT RDB$TRIGGER_NAME, RDB$RELATION_NAME,' + ' RDB$TRIGGER_TYPE, RDB$TRIGGER_INACTIVE,' + ' RDB$TRIGGER_SOURCE, RDB$DESCRIPTION FROM RDB$TRIGGERS' + ' WHERE 1=1' + LTriggerNamePattern + LTableNamePattern; with GetConnection.CreateStatement.ExecuteQuery(SQL) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateNull(1); Result.UpdateNull(2); Result.UpdateString(3, GetString(1)); //RDB$TRIGGER_NAME Result.UpdateString(4, GetString(2)); //RDB$RELATION_NAME Result.UpdateShort(5, GetShort(3)); //RDB$TRIGGER_TYPE Result.UpdateShort(6, GetShort(4)); //RDB$TRIGGER_INACTIVE Result.UpdateString(7, GetString(5)); //RDB$TRIGGER_SOURCE Result.UpdateString(8, GetString(6)); //RDB$DESCRIPTION Result.InsertRow; end; Close; end; end; {** Gets a description of the stored procedures available in a catalog.

Only procedure descriptions matching the schema and procedure name criteria are returned. They are ordered by PROCEDURE_SCHEM, and PROCEDURE_NAME.

Each procedure description has the the following columns:

  1. PROCEDURE_CAT String => procedure catalog (may be null)
  2. PROCEDURE_SCHEM String => procedure schema (may be null)
  3. PROCEDURE_NAME String => procedure name
  4. reserved for future use
  5. reserved for future use
  6. reserved for future use
  7. REMARKS String => explanatory comment on the procedure
  8. PROCEDURE_TYPE short => kind of procedure:
    • procedureResultUnknown - May return a result
    • procedureNoResult - Does not return a result
    • procedureReturnsResult - Returns a result
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param procedureNamePattern a procedure name pattern @return ResultSet - each row is a procedure description @see #getSearchStringEscape } function TZInterbase6DatabaseMetadata.UncachedGetProcedures(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string): IZResultSet; var SQL: string; LProcedureNamePattern: string; begin Result:=inherited UncachedGetProcedures(Catalog, SchemaPattern, ProcedureNamePattern); LProcedureNamePattern := ConstructNameCondition(ProcedureNamePattern, 'RDB$PROCEDURE_NAME'); If LProcedureNamePattern <> '' then LProcedureNamePattern := ' and ' + LProcedureNamePattern; SQL := 'SELECT RDB$PROCEDURE_NAME, RDB$PROCEDURE_OUTPUTS,' + ' RDB$DESCRIPTION FROM RDB$PROCEDURES' + ' WHERE 1=1' + LProcedureNamePattern; with GetConnection.CreateStatement.ExecuteQuery(SQL) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateNull(1); Result.UpdateNull(2); Result.UpdateString(3, GetString(1)); //RDB$PROCEDURE_NAME Result.UpdateNull(4); Result.UpdateNull(5); Result.UpdateNull(6); Result.UpdateString(7, GetString(3)); //RDB$DESCRIPTION if IsNull(2) then //RDB$PROCEDURE_OUTPUTS Result.UpdateInt(8, Ord(prtNoResult)) else Result.UpdateInt(8, Ord(prtReturnsResult)); Result.InsertRow; end; Close; end; end; {** Gets a description of a catalog's stored procedure parameters and result columns.

Only descriptions matching the schema, procedure and parameter name criteria are returned. They are ordered by PROCEDURE_SCHEM and PROCEDURE_NAME. Within this, the return value, if any, is first. Next are the parameter descriptions in call order. The column descriptions follow in column number order.

Each row in the ResultSet is a parameter description or column description with the following fields:

  1. PROCEDURE_CAT String => procedure catalog (may be null)
  2. PROCEDURE_SCHEM String => procedure schema (may be null)
  3. PROCEDURE_NAME String => procedure name
  4. COLUMN_NAME String => column/parameter name
  5. COLUMN_TYPE Short => kind of column/parameter:
    • procedureColumnUnknown - nobody knows
    • procedureColumnIn - IN parameter
    • procedureColumnInOut - INOUT parameter
    • procedureColumnOut - OUT parameter
    • procedureColumnReturn - procedure return value
    • procedureColumnResult - result column in ResultSet
  6. DATA_TYPE short => SQL type from java.sql.Types
  7. TYPE_NAME String => SQL type name, for a UDT type the type name is fully qualified
  8. PRECISION int => precision
  9. LENGTH int => length in bytes of data
  10. SCALE short => scale
  11. RADIX short => radix
  12. NULLABLE short => can it contain NULL?
    • procedureNoNulls - does not allow NULL values
    • procedureNullable - allows NULL values
    • procedureNullableUnknown - nullability unknown
  13. REMARKS String => comment describing parameter/column

Note: Some databases may not return the column descriptions for a procedure. Additional columns beyond REMARKS can be defined by the database. @param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param procedureNamePattern a procedure name pattern @param columnNamePattern a column name pattern @return ResultSet - each row describes a stored procedure parameter or column @see #getSearchStringEscape } function TZInterbase6DatabaseMetadata.UncachedGetProcedureColumns(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string; const ColumnNamePattern: string): IZResultSet; var SQL: string; LProcedureNamePattern, LColumnNamePattern: string; TypeName, SubTypeName: Integer; ColumnIndexes : Array[1..8] of integer; begin Result:=inherited UncachedGetProcedureColumns(Catalog, SchemaPattern, ProcedureNamePattern, ColumnNamePattern); LProcedureNamePattern := ConstructNameCondition(ProcedureNamePattern, 'P.RDB$PROCEDURE_NAME'); LColumnNamePattern := ConstructNameCondition(ColumnNamePattern, 'PP.RDB$PARAMETER_NAME'); If LProcedureNamePattern <> '' then LProcedureNamePattern := ' and ' + LProcedureNamePattern; If LColumnNamePattern <> '' then LColumnNamePattern := ' and ' + LColumnNamePattern; if (StrPos(PChar(GetDatabaseInfo.GetServerVersion), 'Interbase 5') <> nil) or (StrPos(PChar(GetDatabaseInfo.GetServerVersion), 'V5.') <> nil) then begin SQL := ' SELECT P.RDB$PROCEDURE_NAME, PP.RDB$PARAMETER_NAME,' + ' PP.RDB$PARAMETER_TYPE, F.RDB$FIELD_TYPE, F.RDB$FIELD_SUB_TYPE,' + ' F.RDB$FIELD_SCALE, F.RDB$FIELD_LENGTH, F.RDB$NULL_FLAG,' + ' PP.RDB$DESCRIPTION, F.RDB$FIELD_SCALE as RDB$FIELD_PRECISION,' + ' F.RDB$NULL_FLAG FROM RDB$PROCEDURES P' + ' JOIN RDB$PROCEDURE_PARAMETERS PP ON P.RDB$PROCEDURE_NAME' + '=PP.RDB$PROCEDURE_NAME JOIN RDB$FIELDS F ON PP.RDB$FIELD_SOURCE' + '=F.RDB$FIELD_NAME ' + ' WHERE 1=1' + LProcedureNamePattern + LColumnNamePattern + ' ORDER BY P.RDB$PROCEDURE_NAME,' + ' PP.RDB$PARAMETER_TYPE, PP.RDB$PARAMETER_NUMBER'; end else begin SQL := ' SELECT P.RDB$PROCEDURE_NAME, PP.RDB$PARAMETER_NAME,' + ' PP.RDB$PARAMETER_TYPE, F.RDB$FIELD_TYPE, F.RDB$FIELD_SUB_TYPE,' + ' F.RDB$FIELD_SCALE, F.RDB$FIELD_LENGTH, F.RDB$NULL_FLAG,' + ' PP.RDB$DESCRIPTION, F.RDB$FIELD_PRECISION, F.RDB$NULL_FLAG ' + ' FROM RDB$PROCEDURES P JOIN RDB$PROCEDURE_PARAMETERS PP ON' + ' P.RDB$PROCEDURE_NAME = PP.RDB$PROCEDURE_NAME ' + ' JOIN RDB$FIELDS F ON PP.RDB$FIELD_SOURCE = F.RDB$FIELD_NAME ' + ' WHERE 1=1' + LProcedureNamePattern + LColumnNamePattern + ' ORDER BY P.RDB$PROCEDURE_NAME,' + ' PP.RDB$PARAMETER_TYPE, PP.RDB$PARAMETER_NUMBER'; end; with GetConnection.CreateStatement.ExecuteQuery(SQL) do begin ColumnIndexes[1] := FindColumn('RDB$PROCEDURE_NAME'); ColumnIndexes[2] := FindColumn('RDB$PARAMETER_NAME'); ColumnIndexes[3] := FindColumn('RDB$PARAMETER_TYPE'); ColumnIndexes[4] := FindColumn('RDB$FIELD_TYPE'); ColumnIndexes[5] := FindColumn('RDB$FIELD_SUB_TYPE'); ColumnIndexes[6] := FindColumn('RDB$FIELD_PRECISION'); ColumnIndexes[7] := FindColumn('RDB$FIELD_SCALE'); ColumnIndexes[8] := FindColumn('RDB$NULL_FLAG'); while Next do begin TypeName := GetInt(ColumnIndexes[4]); SubTypeName := GetInt(ColumnIndexes[5]); Result.MoveToInsertRow; Result.UpdateNull(1); //PROCEDURE_CAT Result.UpdateNull(2); //PROCEDURE_SCHEM Result.UpdateString(3, GetString(ColumnIndexes[1])); //TABLE_NAME Result.UpdateString(4, GetString(ColumnIndexes[2])); //COLUMN_NAME case GetInt(ColumnIndexes[3]) of 0: Result.UpdateInt(5, Ord(pctIn)); 1: Result.UpdateInt(5, Ord(pctOut)); else Result.UpdateInt(5, Ord(pctUnknown)); end; Result.UpdateInt(6, Ord(ConvertInterbase6ToSqlType(TypeName, SubTypeName, ConSettings.CPType))); //DATA_TYPE Result.UpdateString(7,GetString(ColumnIndexes[4])); //TYPE_NAME Result.UpdateInt(10, GetInt(ColumnIndexes[6])); Result.UpdateNull(9); //BUFFER_LENGTH Result.UpdateInt(10, GetInt(ColumnIndexes[7])); Result.UpdateInt(11, 10); Result.UpdateInt(12, GetInt(ColumnIndexes[8])); Result.UpdateString(12, GetString(ColumnIndexes[6])); Result.InsertRow; end; Close; end; end; {** Gets a description of tables available in a catalog.

Only table descriptions matching the catalog, schema, table name and type criteria are returned. They are ordered by TABLE_TYPE, TABLE_SCHEM and TABLE_NAME.

Each table description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. TABLE_TYPE String => table type. Typical types are "TABLE", "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM".
  5. REMARKS String => explanatory comment on the table

Note: Some databases may not return information for all tables. @param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param tableNamePattern a table name pattern @param types a list of table types to include; null returns all types @return ResultSet - each row is a table description @see #getSearchStringEscape } function TZInterbase6DatabaseMetadata.UncachedGetTables(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const Types: TStringDynArray): IZResultSet; var SQL, TableType: string; I, SystemFlag: Integer; TableNameCondition: string; begin Result:=inherited UncachedGetTables(Catalog, SchemaPattern, TableNamePattern, Types); TableNameCondition := ConstructNameCondition(TableNamePattern, 'a.RDB$RELATION_NAME'); If TableNameCondition <> '' then TableNameCondition := ' and ' + TableNameCondition; SQL := 'SELECT DISTINCT a.RDB$RELATION_NAME, a.RDB$SYSTEM_FLAG, ' + ' a.RDB$VIEW_SOURCE, a.RDB$DESCRIPTION FROM RDB$RELATIONS a' + ' WHERE 1=1' + TableNameCondition; with GetConnection.CreateStatement.ExecuteQuery(SQL) do begin while Next do begin SystemFlag := GetInt(2); //RDB$SYSTEM_FLAG if SystemFlag = 0 then begin if IsNull(3) then //RDB$VIEW_SOURCE TableType := 'TABLE' else TableType := 'VIEW'; end else TableType := 'SYSTEM TABLE'; if Length(Types) = 0 then begin Result.MoveToInsertRow; Result.UpdateNull(1); Result.UpdateNull(2); Result.UpdateString(3, GetString(1)); //RDB$RELATION_NAME Result.UpdateString(4, TableType); Result.UpdateString(5, Copy(GetString(4),1,255)); //RDB$DESCRIPTION Result.InsertRow; end else begin for I := 0 to High(Types) do begin if Types[I] = TableType then begin Result.MoveToInsertRow; Result.UpdateNull(1); Result.UpdateNull(2); Result.UpdateString(3, GetString(1)); //RDB$RELATION_NAME Result.UpdateString(4, TableType); Result.UpdateString(5, Copy(GetString(4),1,255)); //RDB$DESCRIPTION Result.InsertRow; end; end; end; end; Close; end; end; {** Gets the table types available in this database. The results are ordered by table type.

The table type is:

  1. TABLE_TYPE String => table type. Typical types are "TABLE", "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM".
@return ResultSet - each row has a single String column that is a table type } function TZInterbase6DatabaseMetadata.UncachedGetTableTypes: IZResultSet; const TablesTypes: array [0..2] of String = ('TABLE', 'VIEW', 'SYSTEM TABLE'); var I: Integer; begin Result:=inherited UncachedGetTableTypes; for I := 0 to 2 do begin Result.MoveToInsertRow; Result.UpdateString(1, TablesTypes[I]); Result.InsertRow; end; end; {** Gets a description of table columns available in the specified catalog.

Only column descriptions matching the catalog, schema, table and column name criteria are returned. They are ordered by TABLE_SCHEM, TABLE_NAME and ORDINAL_POSITION.

Each column description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. COLUMN_NAME String => column name
  5. DATA_TYPE short => SQL type from java.sql.Types
  6. TYPE_NAME String => Data source dependent type name, for a UDT the type name is fully qualified
  7. COLUMN_SIZE int => column size. For char or date types this is the maximum number of characters, for numeric or decimal types this is precision.
  8. BUFFER_LENGTH is not used.
  9. DECIMAL_DIGITS int => the number of fractional digits
  10. NUM_PREC_RADIX int => Radix (typically either 10 or 2)
  11. NULLABLE int => is NULL allowed?
    • columnNoNulls - might not allow NULL values
    • columnNullable - definitely allows NULL values
    • columnNullableUnknown - nullability unknown
  12. REMARKS String => comment describing column (may be null)
  13. COLUMN_DEF String => default value (may be null)
  14. SQL_DATA_TYPE int => unused
  15. SQL_DATETIME_SUB int => unused
  16. CHAR_OCTET_LENGTH int => for char types the maximum number of bytes in the column
  17. ORDINAL_POSITION int => index of column in table (starting at 1)
  18. IS_NULLABLE String => "NO" means column definitely does not allow NULL values; "YES" means the column might allow NULL values. An empty string means nobody knows.
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param tableNamePattern a table name pattern @param columnNamePattern a column name pattern @return ResultSet - each row is a column description @see #getSearchStringEscape } function TZInterbase6DatabaseMetadata.UncachedGetColumns(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const ColumnNamePattern: string): IZResultSet; var SQL, ColumnName, DefaultValue: String; TypeName, SubTypeName, FieldScale: integer; LTableNamePattern, LColumnNamePattern: string; ColumnIndexes : Array[1..15] of integer; SQLType: TZSQLType; begin Result:=inherited UncachedGetColumns(Catalog, SchemaPattern, TableNamePattern, ColumnNamePattern); LTableNamePattern := ConstructNameCondition(TableNamePattern, 'a.RDB$RELATION_NAME'); LColumnNamePattern := ConstructNameCondition(ColumnNamePattern, 'a.RDB$FIELD_NAME'); If LTableNamePattern <> '' then LTableNamePattern := ' and ' + LTableNamePattern; If LColumnNamePattern <> '' then LColumnNamePattern := ' and ' + LColumnNamePattern; if (StrPos(PChar(GetDatabaseInfo.GetServerVersion), 'Interbase 5') <> nil) or (StrPos(PChar(GetDatabaseInfo.GetServerVersion), 'V5.') <> nil) then begin SQL := 'SELECT a.RDB$RELATION_NAME, a.RDB$FIELD_NAME, a.RDB$FIELD_POSITION,' + ' a.RDB$NULL_FLAG, b. RDB$FIELD_LENGTH, b.RDB$FIELD_SCALE,' + ' c.RDB$TYPE_NAME, b.RDB$FIELD_TYPE, b.RDB$FIELD_SUB_TYPE,' + ' b.RDB$DESCRIPTION, b.RDB$CHARACTER_LENGTH, b.RDB$FIELD_SCALE' + ' as RDB$FIELD_PRECISION, a.RDB$DEFAULT_SOURCE, b.RDB$DEFAULT_SOURCE' + ' as RDB$DEFAULT_SOURCE_DOMAIN, b.RDB$COMPUTED_SOURCE as RDB$COMPUTED_SOURCE' + ' , b.RDB$CHARACTER_SET_ID FROM RDB$RELATION_FIELDS a' + ' JOIN RDB$FIELDS b ON (b.RDB$FIELD_NAME = a.RDB$FIELD_SOURCE)' + ' LEFT JOIN RDB$TYPES c ON b.RDB$FIELD_TYPE = c.RDB$TYPE' + ' and c.RDB$FIELD_NAME = ''RDB$FIELD_TYPE''' + ' WHERE 1=1' + LTableNamePattern + LColumnNamePattern + ' ORDER BY a.RDB$RELATION_NAME, a.RDB$FIELD_POSITION'; end else begin SQL := ' SELECT a.RDB$RELATION_NAME, a.RDB$FIELD_NAME, a.RDB$FIELD_POSITION,' + ' a.RDB$NULL_FLAG, a.RDB$DEFAULT_VALUE, b. RDB$FIELD_LENGTH,' + ' b.RDB$FIELD_SCALE, c.RDB$TYPE_NAME, b.RDB$FIELD_TYPE,' + ' b.RDB$FIELD_SUB_TYPE, b.RDB$DESCRIPTION, b.RDB$CHARACTER_LENGTH,' + ' b.RDB$FIELD_PRECISION, a.RDB$DEFAULT_SOURCE, b.RDB$DEFAULT_SOURCE' + ' as RDB$DEFAULT_SOURCE_DOMAIN,b.RDB$COMPUTED_SOURCE as RDB$COMPUTED_SOURCE' + ' , b.RDB$CHARACTER_SET_ID FROM RDB$RELATION_FIELDS a' + ' JOIN RDB$FIELDS b ON (b.RDB$FIELD_NAME = a.RDB$FIELD_SOURCE)' + ' LEFT JOIN RDB$TYPES c ON (b.RDB$FIELD_TYPE = c.RDB$TYPE' + ' and c.RDB$FIELD_NAME = ''RDB$FIELD_TYPE'')' + ' WHERE 1=1' + LTableNamePattern + LColumnNamePattern + ' ORDER BY a.RDB$RELATION_NAME, a.RDB$FIELD_POSITION'; end; with GetConnection.CreateStatement.ExecuteQuery(SQL) do begin ColumnIndexes[1] := FindColumn('RDB$FIELD_TYPE'); ColumnIndexes[2] := FindColumn('RDB$FIELD_SUB_TYPE'); ColumnIndexes[3] := FindColumn('RDB$FIELD_SCALE'); ColumnIndexes[4] := FindColumn('RDB$FIELD_NAME'); ColumnIndexes[5] := FindColumn('RDB$DEFAULT_SOURCE'); ColumnIndexes[6] := FindColumn('RDB$DEFAULT_SOURCE_DOMAIN'); ColumnIndexes[7] := FindColumn('RDB$RELATION_NAME'); ColumnIndexes[8] := FindColumn('RDB$TYPE_NAME'); ColumnIndexes[9] := FindColumn('RDB$FIELD_PRECISION'); ColumnIndexes[10] := FindColumn('RDB$FIELD_LENGTH'); ColumnIndexes[11] := FindColumn('RDB$NULL_FLAG'); ColumnIndexes[12] := FindColumn('RDB$DESCRIPTION'); ColumnIndexes[13] := FindColumn('RDB$FIELD_POSITION'); ColumnIndexes[14] := FindColumn('RDB$COMPUTED_SOURCE'); ColumnIndexes[15] := FindColumn('RDB$CHARACTER_SET_ID'); while Next do begin TypeName := GetInt(ColumnIndexes[1]); if TypeName = 14 then //'TEXT' SubTypeName := GetInt(ColumnIndexes[15]) //need a way to determine CS_Binary (octets) for stBytes on the other hand the subtype is useless here else SubTypeName := GetInt(ColumnIndexes[2]); FieldScale := GetInt(ColumnIndexes[3]); ColumnName := GetString(ColumnIndexes[4]); if (GetString(ColumnIndexes[14]) <> '') then //AVZ -- not isNull(14) was not working correcly here could be ' ' - subselect begin //Computed by Source & Sub Selects //AVZ if ((TypeName = 16) and (FieldScale < 0)) then SubTypeName := 1; // Fix for 0 subtype which removes decimals end; DefaultValue := GetString(ColumnIndexes[5]); if DefaultValue = '' then DefaultValue := GetString(ColumnIndexes[6]); if StartsWith(Trim(UpperCase(DefaultValue)), 'DEFAULT') then begin DefaultValue := Trim(StringReplace(DefaultValue, 'DEFAULT ', '', [rfIgnoreCase])); end; IF (UpperCase(DefaultValue)= '''NOW''') or (UpperCase(DefaultValue)= '"NOW"')then case TypeName of 12: DefaultValue := 'CURRENT_DATE'; 13: DefaultValue := 'CURRENT_TIME'; 35: DefaultValue := 'CURRENT_TIMESTAMP'; else begin end; end; Result.MoveToInsertRow; Result.UpdateNull(1); //TABLE_CAT Result.UpdateNull(2); //TABLE_SCHEM Result.UpdateString(3, GetString(ColumnIndexes[7])); //TABLE_NAME Result.UpdateString(4, ColumnName); //COLUMN_NAME SQLType := ConvertInterbase6ToSqlType(TypeName, SubTypeName , ConSettings.CPType); Result.UpdateInt(5, Ord(SQLType)); // TYPE_NAME case TypeName of 7 : Result.UpdateString(6, 'SMALLINT'); 8 : Result.UpdateString(6, 'INTEGER' ); 16 : begin if (SubTypeName = 0) then Result.UpdateString(6, GetString(ColumnIndexes[8])); if (SubTypeName = 1) then Result.UpdateString(6, 'NUMERIC'); if (SubTypeName = 2) then Result.UpdateString(6, 'DECIMAL'); end; 37 : Result.UpdateString(6, 'VARCHAR'); // Instead of VARYING else Result.UpdateString(6, GetString(ColumnIndexes[8])); end; // COLUMN_SIZE. case TypeName of 7, 8 : Result.UpdateInt(7, 0); 16 : Result.UpdateInt(7, GetInt(ColumnIndexes[9])); 37, 38: Result.UpdateNull(7); //the defaults of the resultsets will be used if null {if ( ConSettings.ClientCodePage.ID = 0 ) then //CharcterSet 'NONE' Result.UpdateInt(7, GetFieldSize(SQLType, ConSettings, GetInt(ColumnIndexes[10]), GetConnection.GetIZPlainDriver.ValidateCharEncoding(SubTypeName).CharWidth, nil, True)) //FireBird return Char*Bytes for Varchar else Result.UpdateInt(7, GetFieldSize(SQLType, ConSettings, GetInt(ColumnIndexes[10]), ConSettings.ClientCodePage.CharWidth, nil, True)); //FireBird return Char*Bytes for Varchar} else Result.UpdateInt(7, GetInt(ColumnIndexes[10])); end; Result.UpdateNull(8); //BUFFER_LENGTH if FieldScale < 0 then Result.UpdateInt(9, -1 * FieldScale) //DECIMAL_DIGITS else Result.UpdateInt(9, 0); //DECIMAL_DIGITS Result.UpdateInt(10, 10); //NUM_PREC_RADIX if GetInt(ColumnIndexes[11]) <> 0 then Result.UpdateInt(11, Ord(ntNoNulls)) //NULLABLE else Result.UpdateInt(11, Ord(ntNullable)); Result.UpdateString(12, Copy(GetString(ColumnIndexes[12]),1,255)); //REMARKS Result.UpdateString(13, DefaultValue); //COLUMN_DEF Result.UpdateNull(14); //SQL_DATA_TYPE Result.UpdateNull(15); //SQL_DATETIME_SUB Result.UpdateInt(16, GetInt(7)); //CHAR_OCTET_LENGTH Result.UpdateInt(17, GetInt(ColumnIndexes[13]) + 1); //ORDINAL_POSITION if IsNull(ColumnIndexes[11]) then Result.UpdateString(18, 'YES') //IS_NULLABLE else Result.UpdateString(18, 'NO'); //IS_NULLABLE Result.UpdateNull(19); //AUTO_INCREMENT if CompareStr(ColumnName, UpperCase(ColumnName)) = 0 then Result.UpdateBoolean(20, False) //CASE_SENSITIVE else Result.UpdateBoolean(20, True); //CASE_SENSITIVE Result.UpdateBoolean(21, True); //SEARCHABLE if isNull(ColumnIndexes[14]) then begin Result.UpdateBoolean(22, True); //WRITABLE Result.UpdateBoolean(23, True); //DEFINITELYWRITABLE Result.UpdateBoolean(24, False); //READONLY end else begin Result.UpdateBoolean(22, False); //WRITABLE Result.UpdateBoolean(23, False); //DEFINITELYWRITABLE Result.UpdateBoolean(24, True); //READONLY end; Result.InsertRow; end; Close; end; end; {** Gets a description of the access rights for a table's columns.

Only privileges matching the column name criteria are returned. They are ordered by COLUMN_NAME and PRIVILEGE.

Each privilige description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. COLUMN_NAME String => column name
  5. GRANTOR => grantor of access (may be null)
  6. GRANTEE String => grantee of access
  7. PRIVILEGE String => name of access (SELECT, INSERT, UPDATE, REFRENCES, ...)
  8. IS_GRANTABLE String => "YES" if grantee is permitted to grant to others; "NO" if not; null if unknown
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @param columnNamePattern a column name pattern @return ResultSet - each row is a column privilege description @see #getSearchStringEscape } function TZInterbase6DatabaseMetadata.UncachedGetColumnPrivileges(const Catalog: string; const Schema: string; const Table: string; const ColumnNamePattern: string): IZResultSet; var SQL: string; TableName, FieldName, Privilege: String; Grantor, Grantee, Grantable: String; LColumnNamePattern, LTable: String; begin Result:=inherited UncachedGetColumnPrivileges(Catalog, Schema, Table, ColumnNamePattern); LTable := ConstructNameCondition(AddEscapeCharToWildcards(Table), 'a.RDB$RELATION_NAME'); LColumnNamePattern := ConstructNameCondition(ColumnNamePattern, 'a.RDB$FIELD_NAME'); if LTable <> '' then LTable := ' and ' + LTable; if LColumnNamePattern <> '' then LColumnNamePattern := ' and ' + LColumnNamePattern; SQL := 'SELECT a.RDB$USER, a.RDB$GRANTOR, a.RDB$PRIVILEGE,' + ' a.RDB$GRANT_OPTION, a.RDB$RELATION_NAME, a.RDB$FIELD_NAME ' + ' FROM RDB$USER_PRIVILEGES a, RDB$TYPES b ' + ' WHERE a.RDB$OBJECT_TYPE = b.RDB$TYPE ' + LTable + LColumnNamePattern + ' and b.RDB$TYPE_NAME IN (''RELATION'', ''VIEW'',' + ' ''COMPUTED_FIELD'', ''FIELD'' ) AND b.RDB$FIELD_NAME' + '=''RDB$OBJECT_TYPE'' ORDER BY a.RDB$FIELD_NAME, a.RDB$PRIVILEGE ' ; with GetConnection.CreateStatement.ExecuteQuery(SQL) do begin while Next do begin TableName := GetString(5); //RDB$RELATION_NAME FieldName := GetString(6); //RDB$FIELD_NAME Privilege := GetPrivilege(GetString(3)); //RDB$PRIVILEGE Grantor := GetString(2); //RDB$GRANTOR Grantee := GetString(1); //RDB$USER if Grantor = Grantee then Grantable := 'YES' else Grantable := 'NO'; if FieldName = '' then begin LTable := ConstructNameCondition(TableName, 'a.RDB$RELATION_NAME'); SQL := 'SELECT RDB$FIELD_NAME FROM RDB$RELATION_FIELDS A' + ' WHERE ' + LTable + LColumnNamePattern; with GetConnection.CreateStatement.ExecuteQuery(SQL) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateNull(1); Result.UpdateNull(2); Result.UpdateString(3, TableName); Result.UpdateString(4, GetString(1)); Result.UpdateString(5, Grantor); Result.UpdateString(6, Grantee); Result.UpdateString(7, Privilege); Result.UpdateString(8, Grantable); Result.InsertRow; end; Close; end; end else begin Result.MoveToInsertRow; Result.UpdateNull(1); Result.UpdateNull(2); Result.UpdateString(3, TableName); Result.UpdateString(4, FieldName); Result.UpdateString(5, Grantor); Result.UpdateString(6, Grantee); Result.UpdateString(7, Privilege); Result.UpdateString(8, Grantable); Result.InsertRow; end; end; Close; end; end; {** Gets a description of the access rights for each table available in a catalog. Note that a table privilege applies to one or more columns in the table. It would be wrong to assume that this priviledge applies to all columns (this may be true for some systems but is not true for all.)

Only privileges matching the schema and table name criteria are returned. They are ordered by TABLE_SCHEM, TABLE_NAME, and PRIVILEGE.

Each privilige description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. GRANTOR => grantor of access (may be null)
  5. GRANTEE String => grantee of access
  6. PRIVILEGE String => name of access (SELECT, INSERT, UPDATE, REFRENCES, ...)
  7. IS_GRANTABLE String => "YES" if grantee is permitted to grant to others; "NO" if not; null if unknown
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param tableNamePattern a table name pattern @return ResultSet - each row is a table privilege description @see #getSearchStringEscape } function TZInterbase6DatabaseMetadata.UncachedGetTablePrivileges(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string): IZResultSet; var SQL: string; TableName, Privilege, Grantor: String; Grantee, Grantable: String; LTableNamePattern: String; begin Result:=inherited UncachedGetTablePrivileges(Catalog, SchemaPattern, TableNamePattern); LTableNamePattern := ConstructNameCondition(TableNamePattern, 'a.RDB$RELATION_NAME'); if LTableNamePattern <> '' then LTableNamePattern := ' and ' + LTableNamePattern; SQL := 'SELECT a.RDB$USER, a.RDB$GRANTOR, a.RDB$PRIVILEGE,' + ' a.RDB$GRANT_OPTION, a.RDB$RELATION_NAME FROM RDB$USER_PRIVILEGES a,' + ' RDB$TYPES b WHERE a.RDB$OBJECT_TYPE = b.RDB$TYPE AND ' + ' b.RDB$TYPE_NAME IN (''RELATION'', ''VIEW'', ''COMPUTED_FIELD'',' + ' ''FIELD'' ) AND a.RDB$FIELD_NAME IS NULL '+ LTableNamePattern + ' ORDER BY a.RDB$RELATION_NAME, a.RDB$PRIVILEGE'; with GetConnection.CreateStatement.ExecuteQuery(SQL) do begin while Next do begin TableName := GetString(5); //RDB$RELATION_NAME Privilege := GetPrivilege(GetString(3)); //RDB$PRIVILEGE Grantor := GetString(2); //RDB$GRANTOR Grantee := GetString(1); //RDB$USER if Grantor = Grantee then Grantable := 'YES' else Grantable := 'NO'; Result.MoveToInsertRow; Result.UpdateNull(1); Result.UpdateNull(2); Result.UpdateString(3, TableName); Result.UpdateString(4, Grantor); Result.UpdateString(5, Grantee); Result.UpdateString(6, Privilege); Result.UpdateString(7, Grantable); Result.InsertRow; end; Close; end; end; {** Gets a description of a table's columns that are automatically updated when any value in a row is updated. They are unordered.

Each column description has the following columns:

  1. SCOPE short => is not used
  2. COLUMN_NAME String => column name
  3. DATA_TYPE short => SQL data type from java.sql.Types
  4. TYPE_NAME String => Data source dependent type name
  5. COLUMN_SIZE int => precision
  6. BUFFER_LENGTH int => length of column value in bytes
  7. DECIMAL_DIGITS short => scale
  8. PSEUDO_COLUMN short => is this a pseudo column like an Oracle ROWID
    • versionColumnUnknown - may or may not be pseudo column
    • versionColumnNotPseudo - is NOT a pseudo column
    • versionColumnPseudo - is a pseudo column
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a column description @exception SQLException if a database access error occurs } function TZInterbase6DatabaseMetadata.UncachedGetVersionColumns(const Catalog: string; const Schema: string; const Table: string): IZResultSet; begin Result:=inherited UncachedGetVersionColumns(Catalog, Schema, Table); Result.MoveToInsertRow; Result.UpdateNull(1); Result.UpdateString(2, 'ctid'); // Result.UpdateInt(3, GetSQLType('tid')); //FIX IT Result.UpdateString(4, 'tid'); Result.UpdateNull(5); Result.UpdateNull(6); Result.UpdateNull(7); Result.UpdateInt(4, Ord(vcPseudo)); Result.InsertRow; end; {** Gets a description of a table's primary key columns. They are ordered by COLUMN_NAME.

Each primary key column description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. COLUMN_NAME String => column name
  5. KEY_SEQ short => sequence number within primary key
  6. PK_NAME String => primary key name (may be null)
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a primary key column description @exception SQLException if a database access error occurs } function TZInterbase6DatabaseMetadata.UncachedGetPrimaryKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; var SQL: string; LTable: string; begin LTable := ConstructNameCondition(AddEscapeCharToWildcards(Table), 'a.RDB$RELATION_NAME'); if LTable <> '' then LTable := ' AND ' + LTable; SQL := ' SELECT null as TABLE_CAT, null as TABLE_SCHEM,' + ' a.RDB$RELATION_NAME as TABLE_NAME, b.RDB$FIELD_NAME as COLUMN_NAME,' + ' b.RDB$FIELD_POSITION+1 as KEY_SEQ, a.RDB$INDEX_NAME as PK_NAME' + ' FROM RDB$RELATION_CONSTRAINTS a JOIN RDB$INDEX_SEGMENTS b ON' + ' (a.RDB$INDEX_NAME = b.RDB$INDEX_NAME)' + ' WHERE RDB$CONSTRAINT_TYPE = ''PRIMARY KEY''' + LTable + ' ORDER BY a.RDB$RELATION_NAME, b.RDB$FIELD_NAME'; Result := CopyToVirtualResultSet( GetConnection.CreateStatement.ExecuteQuery(SQL), ConstructVirtualResultSet(PrimaryKeyColumnsDynArray)); end; {** Gets a description of the primary key columns that are referenced by a table's foreign key columns (the primary keys imported by a table). They are ordered by PKTABLE_CAT, PKTABLE_SCHEM, PKTABLE_NAME, and KEY_SEQ.

Each primary key column description has the following columns:

  1. PKTABLE_CAT String => primary key table catalog being imported (may be null)
  2. PKTABLE_SCHEM String => primary key table schema being imported (may be null)
  3. PKTABLE_NAME String => primary key table name being imported
  4. PKCOLUMN_NAME String => primary key column name being imported
  5. FKTABLE_CAT String => foreign key table catalog (may be null)
  6. FKTABLE_SCHEM String => foreign key table schema (may be null)
  7. FKTABLE_NAME String => foreign key table name
  8. FKCOLUMN_NAME String => foreign key column name
  9. KEY_SEQ short => sequence number within foreign key
  10. UPDATE_RULE short => What happens to foreign key when primary is updated:
    • importedNoAction - do not allow update of primary key if it has been imported
    • importedKeyCascade - change imported key to agree with primary key update
    • importedKeySetNull - change imported key to NULL if its primary key has been updated
    • importedKeySetDefault - change imported key to default values if its primary key has been updated
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
  11. DELETE_RULE short => What happens to the foreign key when primary is deleted.
    • importedKeyNoAction - do not allow delete of primary key if it has been imported
    • importedKeyCascade - delete rows that import a deleted key
    • importedKeySetNull - change imported key to NULL if its primary key has been deleted
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
    • importedKeySetDefault - change imported key to default if its primary key has been deleted
  12. FK_NAME String => foreign key name (may be null)
  13. PK_NAME String => primary key name (may be null)
  14. DEFERRABILITY short => can the evaluation of foreign key constraints be deferred until commit
    • importedKeyInitiallyDeferred - see SQL92 for definition
    • importedKeyInitiallyImmediate - see SQL92 for definition
    • importedKeyNotDeferrable - see SQL92 for definition
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a primary key column description @see #getExportedKeys } function TZInterbase6DatabaseMetadata.UncachedGetImportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; var SQL: string; LTable: string; begin Result:=inherited UncachedGetImportedKeys(Catalog, Schema, Table); LTable := ConstructNameCondition(AddEscapeCharToWildcards(Table), 'RELC_FOR.RDB$RELATION_NAME'); // Modified by cipto 6/11/2007 4:53:02 PM if LTable <> '' then LTable := ' AND ' + LTable; SQL := 'SELECT RELC_PRIM.RDB$RELATION_NAME, ' // 1 prim.RDB$ key table name + ' IS_PRIM.RDB$FIELD_NAME, ' // 2 prim.RDB$ key column name + ' RELC_FOR.RDB$RELATION_NAME, ' // 3 foreign key table name + ' IS_FOR.RDB$FIELD_NAME, ' // 4 foreign key column name + ' IS_FOR.RDB$FIELD_POSITION, ' // 5 key sequence + ' REFC_PRIM.RDB$UPDATE_RULE, ' // 6 + ' REFC_PRIM.RDB$DELETE_RULE, ' // 7 + ' RELC_FOR.RDB$CONSTRAINT_NAME, ' // 8 foreign key constraint name + ' RELC_PRIM.RDB$CONSTRAINT_NAME ' // 9 primary key constraint name + ' FROM RDB$RELATION_CONSTRAINTS RELC_FOR, RDB$REF_CONSTRAINTS REFC_FOR, ' + ' RDB$RELATION_CONSTRAINTS RELC_PRIM, RDB$REF_CONSTRAINTS REFC_PRIM, ' + ' RDB$INDEX_SEGMENTS IS_PRIM, RDB$INDEX_SEGMENTS IS_FOR ' + ' WHERE RELC_FOR.RDB$CONSTRAINT_TYPE = ''FOREIGN KEY'' ' + LTable + ' AND RELC_FOR.RDB$CONSTRAINT_NAME=REFC_FOR.RDB$CONSTRAINT_NAME' + ' and REFC_FOR.RDB$CONST_NAME_UQ = RELC_PRIM.RDB$CONSTRAINT_NAME and ' + ' RELC_PRIM.RDB$CONSTRAINT_TYPE = ''PRIMARY KEY'' and ' // useful check, anyay + ' RELC_PRIM.RDB$INDEX_NAME = IS_PRIM.RDB$INDEX_NAME and ' + ' IS_FOR.RDB$INDEX_NAME = RELC_FOR.RDB$INDEX_NAME and ' + ' IS_PRIM.RDB$FIELD_POSITION = IS_FOR.RDB$FIELD_POSITION and ' + ' REFC_PRIM.RDB$CONSTRAINT_NAME = RELC_FOR.RDB$CONSTRAINT_NAME ' + ' ORDER BY RELC_PRIM.RDB$RELATION_NAME, IS_FOR.RDB$FIELD_POSITION '; with GetConnection.CreateStatement.ExecuteQuery(SQL) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateNull(1); //PKTABLE_CAT Result.UpdateNull(2); //PKTABLE_SCHEM Result.UpdateString(3, GetString(1)); //PKTABLE_NAME Result.UpdateString(4, GetString(2)); //PKCOLUMN_NAME Result.UpdateNull(5); //FKTABLE_CAT Result.UpdateNull(6); //FKTABLE_SCHEM Result.UpdateString(7, GetString(3)); //FKTABLE_NAME Result.UpdateString(8, GetString(4)); //FKCOLUMN_NAME Result.UpdateInt(9, GetInt(5) + 1); //KEY_SEQ if GetString(6) = 'RESTRICT' then //UPDATE_RULE Result.UpdateInt(10, Ord(ikRestrict)) else if GetString(6) = 'NO ACTION' then Result.UpdateInt(10, Ord(ikNoAction)) else if GetString(6) = 'SET DEFAULT' then Result.UpdateInt(10, Ord(ikSetDefault)) else if GetString(6) = 'CASCADE' then Result.UpdateInt(10, Ord(ikCascade)) else if GetString(6) = 'SET NULL' then Result.UpdateInt(10, Ord(ikSetNull)); if GetString(7) = 'RESTRICT' then //DELETE_RULE Result.UpdateInt(11, Ord(ikRestrict)) else if GetString(7) = 'NO ACTION' then Result.UpdateInt(11, Ord(ikNoAction)) else if GetString(7) = 'SET DEFAULT' then Result.UpdateInt(11, Ord(ikSetDefault)) else if GetString(7) = 'CASCADE' then Result.UpdateInt(11, Ord(ikCascade)) else if GetString(7) = 'SET NULL' then Result.UpdateInt(11, Ord(ikSetNull)); Result.UpdateString(12, GetString(8)); //FK_NAME Result.UpdateString(13, GetString(9)); //PK_NAME Result.UpdateNull(14); //DEFERABILITY Result.InsertRow; end; Close; end; end; {** Gets a description of the foreign key columns that reference a table's primary key columns (the foreign keys exported by a table). They are ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, and KEY_SEQ.

Each foreign key column description has the following columns:

  1. PKTABLE_CAT String => primary key table catalog (may be null)
  2. PKTABLE_SCHEM String => primary key table schema (may be null)
  3. PKTABLE_NAME String => primary key table name
  4. PKCOLUMN_NAME String => primary key column name
  5. FKTABLE_CAT String => foreign key table catalog (may be null) being exported (may be null)
  6. FKTABLE_SCHEM String => foreign key table schema (may be null) being exported (may be null)
  7. FKTABLE_NAME String => foreign key table name being exported
  8. FKCOLUMN_NAME String => foreign key column name being exported
  9. KEY_SEQ short => sequence number within foreign key
  10. UPDATE_RULE short => What happens to foreign key when primary is updated:
    • importedNoAction - do not allow update of primary key if it has been imported
    • importedKeyCascade - change imported key to agree with primary key update
    • importedKeySetNull - change imported key to NULL if its primary key has been updated
    • importedKeySetDefault - change imported key to default values if its primary key has been updated
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
  11. DELETE_RULE short => What happens to the foreign key when primary is deleted.
    • importedKeyNoAction - do not allow delete of primary key if it has been imported
    • importedKeyCascade - delete rows that import a deleted key
    • importedKeySetNull - change imported key to NULL if its primary key has been deleted
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
    • importedKeySetDefault - change imported key to default if its primary key has been deleted
  12. FK_NAME String => foreign key name (may be null)
  13. PK_NAME String => primary key name (may be null)
  14. DEFERRABILITY short => can the evaluation of foreign key constraints be deferred until commit
    • importedKeyInitiallyDeferred - see SQL92 for definition
    • importedKeyInitiallyImmediate - see SQL92 for definition
    • importedKeyNotDeferrable - see SQL92 for definition
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a foreign key column description @see #getImportedKeys } function TZInterbase6DatabaseMetadata.UncachedGetExportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; var SQL: string; LTable: string; begin Result:=inherited UncachedGetExportedKeys(Catalog, Schema, Table); LTable := ConstructNameCondition(AddEscapeCharToWildcards(Table), 'RC_PRIM.RDB$RELATION_NAME'); // Modified by cipto 6/11/2007 4:54:02 PM if LTable <> '' then LTable := ' AND ' + LTable; SQL := ' SELECT RC_PRIM.RDB$RELATION_NAME, ' // prim.RDB$ key Table name + ' IS_PRIM.RDB$FIELD_NAME, ' // prim.RDB$ key column name + ' RC_FOR.RDB$RELATION_NAME, ' // foreign key Table name + ' IS_FOR.RDB$FIELD_NAME, ' // foreign key column name + ' IS_FOR.RDB$FIELD_POSITION, ' // key sequence + ' REFC_PRIM.RDB$UPDATE_RULE, ' // if update or delete rule is null, interpret as RESTRICT + ' REFC_PRIM.RDB$DELETE_RULE, ' + ' RC_FOR.RDB$CONSTRAINT_NAME, ' // foreign key constraint name + ' RC_PRIM.RDB$CONSTRAINT_NAME ' // primary key constraint name + ' FROM RDB$RELATION_CONSTRAINTS RC_FOR, RDB$REF_CONSTRAINTS REFC_FOR, ' + ' RDB$RELATION_CONSTRAINTS RC_PRIM, RDB$REF_CONSTRAINTS REFC_PRIM, ' + ' RDB$INDEX_SEGMENTS IS_PRIM, RDB$INDEX_SEGMENTS IS_FOR ' + ' WHERE RC_PRIM.RDB$CONSTRAINT_TYPE = ''PRIMARY KEY'' '+ LTable + ' and REFC_FOR.RDB$CONST_NAME_UQ = RC_PRIM.RDB$CONSTRAINT_NAME' + ' and RC_FOR.RDB$CONSTRAINT_NAME = REFC_FOR.RDB$CONSTRAINT_NAME and ' + ' RC_FOR.RDB$CONSTRAINT_TYPE = ''FOREIGN KEY'' and '// useful check, anyay + ' RC_PRIM.RDB$INDEX_NAME = IS_PRIM.RDB$INDEX_NAME and ' + ' IS_FOR.RDB$INDEX_NAME = RC_FOR.RDB$INDEX_NAME and ' + ' IS_PRIM.RDB$FIELD_POSITION = IS_FOR.RDB$FIELD_POSITION and ' + ' REFC_PRIM.RDB$CONSTRAINT_NAME = RC_FOR.RDB$CONSTRAINT_NAME ' + ' ORDER BY RC_FOR.RDB$RELATION_NAME, IS_FOR.RDB$FIELD_POSITION '; with GetConnection.CreateStatement.ExecuteQuery(SQL) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateNull(1); //PKTABLE_CAT Result.UpdateNull(2); //PKTABLE_SCHEM Result.UpdateString(3, GetString(1)); //PKTABLE_NAME Result.UpdateString(4, GetString(2)); //PKCOLUMN_NAME Result.UpdateNull(5); //FKTABLE_CAT Result.UpdateNull(6); //FKTABLE_SCHEM' Result.UpdateString(7, GetString(3)); //FKTABLE_NAME Result.UpdateString(8, GetString(4)); //FKCOLUMN_NAME Result.UpdateInt(9, GetInt(5) + 1); //KEY_SEQ if GetString(6) = 'RESTRICT' then //UPDATE_RULE Result.UpdateInt(10, Ord(ikRestrict)) else if GetString(6) = 'NO ACTION' then Result.UpdateInt(10, Ord(ikNoAction)) else if GetString(6) = 'SET DEFAULT' then Result.UpdateInt(10, Ord(ikSetDefault)) else if GetString(6) = 'CASCADE' then Result.UpdateInt(10, Ord(ikCascade)) else if GetString(6) = 'SET NULL' then Result.UpdateInt(10, Ord(ikSetNull)); if GetString(7) = 'RESTRICT' then //DELETE_RULE Result.UpdateInt(11, Ord(ikRestrict)) else if GetString(7) = 'NO ACTION' then Result.UpdateInt(11, Ord(ikNoAction)) else if GetString(7) = 'SET DEFAULT' then Result.UpdateInt(11, Ord(ikSetDefault)) else if GetString(7) = 'CASCADE' then Result.UpdateInt(11, Ord(ikCascade)) else if GetString(7) = 'SET NULL' then Result.UpdateInt(11, Ord(ikSetNull)); Result.UpdateString(12, GetString(8)); //FK_NAME Result.UpdateString(13, GetString(9)); //PK_NAME Result.UpdateNull(14); //DEFERABILITY Result.InsertRow; end; Close; end; end; {** EgonHugeist: Gets a description of the foreign key columns in the foreign key table that reference the primary key columns of the primary key table (describe how one table imports another's key.) This should normally return a single foreign key/primary key pair (most tables only import a foreign key from a table once.) They are ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, and KEY_SEQ.

Each foreign key column description has the following columns:

  1. PKTABLE_CAT String => primary key table catalog (may be null)
  2. PKTABLE_SCHEM String => primary key table schema (may be null)
  3. PKTABLE_NAME String => primary key table name
  4. PKCOLUMN_NAME String => primary key column name
  5. FKTABLE_CAT String => foreign key table catalog (may be null) being exported (may be null)
  6. FKTABLE_SCHEM String => foreign key table schema (may be null) being exported (may be null)
  7. FKTABLE_NAME String => foreign key table name being exported
  8. FKCOLUMN_NAME String => foreign key column name being exported
  9. KEY_SEQ short => sequence number within foreign key
  10. UPDATE_RULE short => What happens to foreign key when primary is updated:
    • importedNoAction - do not allow update of primary key if it has been imported
    • importedKeyCascade - change imported key to agree with primary key update
    • importedKeySetNull - change imported key to NULL if its primary key has been updated
    • importedKeySetDefault - change imported key to default values if its primary key has been updated
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
  11. DELETE_RULE short => What happens to the foreign key when primary is deleted.
    • importedKeyNoAction - do not allow delete of primary key if it has been imported
    • importedKeyCascade - delete rows that import a deleted key
    • importedKeySetNull - change imported key to NULL if its primary key has been deleted
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
    • importedKeySetDefault - change imported key to default if its primary key has been deleted
  12. FK_NAME String => foreign key name (may be null)
  13. PK_NAME String => primary key name (may be null)
  14. DEFERRABILITY short => can the evaluation of foreign key constraints be deferred until commit
    • importedKeyInitiallyDeferred - see SQL92 for definition
    • importedKeyInitiallyImmediate - see SQL92 for definition
    • importedKeyNotDeferrable - see SQL92 for definition
@param primaryCatalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param primarySchema a schema name; "" retrieves those without a schema @param primaryTable the table name that exports the key @param foreignCatalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param foreignSchema a schema name; "" retrieves those without a schema @param foreignTable the table name that imports the key @return ResultSet - each row is a foreign key column description @see #getImportedKeys } function TZInterbase6DatabaseMetadata.UncachedGetCrossReference( const PrimaryCatalog: string; const PrimarySchema: string; const PrimaryTable: string; const ForeignCatalog: string; const ForeignSchema: string; const ForeignTable: string): IZResultSet; var KeySeq: Integer; LCatalog, SQLString, LPTable, LFTable: String; function GetRuleType(const Rule: String): TZImportedKey; begin if Rule = 'RESTRICT' then Result := ikRestrict else if Rule = 'NO ACTION' then Result := ikNoAction else if Rule = 'CASCADE' then Result := ikCascade else if Rule = 'SET DEFAULT' then Result := ikSetDefault else if Rule = 'SET NULL' then Result := ikSetNull else Result := ikNotDeferrable; //impossible! end; begin if PrimaryCatalog = '' then LCatalog := GetConnection.GetCatalog else LCatalog := PrimaryCatalog; LPTable := ConstructNameCondition(AddEscapeCharToWildcards(PrimaryTable), 'i2.RDB$RELATION_NAME'); LFTable := ConstructNameCondition(AddEscapeCharToWildcards(ForeignTable), 'rc.RDB$RELATION_NAME'); if LPTable <> '' then LPTable := ' AND ' + LPTable; if LFTable <> '' then LFTable := ' AND ' + LFTable; Result:=inherited UncachedGetCrossReference(PrimaryCatalog, PrimarySchema, PrimaryTable, ForeignCatalog, ForeignSchema, ForeignTable); SQLString := 'SELECT '+ 'i2.RDB$RELATION_NAME AS PKTABLE_NAME, '+ 's2.RDB$FIELD_NAME AS PKCOLUMN_NAME, '+ 'rc.RDB$RELATION_NAME as FKTABLE_NAME, '+ 's.RDB$FIELD_NAME AS FKCOLUMN_NAME, '+ 'refc.RDB$UPDATE_RULE AS UPDATE_RULE, '+ 'refc.RDB$DELETE_RULE AS DELETE_RULE, '+ 'i.RDB$INDEX_NAME AS FK_NAME, '+ 's2.RDB$INDEX_NAME as PK_NAME, '+ 'rc.RDB$DEFERRABLE AS DEFERRABILITY '+ 'FROM RDB$INDEX_SEGMENTS s '+ 'LEFT JOIN RDB$INDICES i ON i.RDB$INDEX_NAME = s.RDB$INDEX_NAME '+ 'LEFT JOIN RDB$RELATION_CONSTRAINTS rc ON rc.RDB$INDEX_NAME = s.RDB$INDEX_NAME '+ 'LEFT JOIN RDB$REF_CONSTRAINTS refc ON rc.RDB$CONSTRAINT_NAME = refc.RDB$CONSTRAINT_NAME '+ 'LEFT JOIN RDB$RELATION_CONSTRAINTS rc2 ON rc2.RDB$CONSTRAINT_NAME = refc.RDB$CONST_NAME_UQ '+ 'LEFT JOIN RDB$INDICES i2 ON i2.RDB$INDEX_NAME = rc2.RDB$INDEX_NAME '+ 'LEFT JOIN RDB$INDEX_SEGMENTS s2 ON i2.RDB$INDEX_NAME = s2.RDB$INDEX_NAME '+ 'WHERE rc.RDB$CONSTRAINT_TYPE = ''FOREIGN KEY'' '+ 'AND rc.RDB$CONSTRAINT_TYPE IS NOT NULL '+LPTable+LFTable; KeySeq := 0; with GetConnection.CreateStatement.ExecuteQuery(SQLString) do begin while Next do begin Inc(KeySeq); Result.MoveToInsertRow; Result.UpdateString(1, LCatalog); //PKTABLE_CAT Result.UpdateNull(2); //PKTABLE_SCHEM Result.UpdateString(3, GetString(1)); //PKTABLE_NAME Result.UpdateString(4, GetString(2)); //PKCOLUMN_NAME Result.UpdateString(5, LCatalog); //PKTABLE_CAT Result.UpdateNull(6); //FKTABLE_SCHEM Result.UpdateString(7, GetString(3)); //FKTABLE_NAME Result.UpdateString(8, GetString(4)); //FKCOLUMN_NAME Result.UpdateShort(9, KeySeq); //KEY_SEQ Result.UpdateShort(10, Ord(GetRuleType(GetString(5)))); //UPDATE_RULE Result.UpdateShort(11, Ord(GetRuleType(GetString(6)))); //DELETE_RULE Result.UpdateString(12, GetString(7)); //FK_NAME Result.UpdateString(13, GetString(8)); //PK_NAME if GetString(9) = 'NO' then Result.UpdateShort(14, Ord(ikNotDeferrable)) //DEFERRABILITY else Result.UpdateShort(14, Ord(ikInitiallyDeferred)); //DEFERRABILITY Result.InsertRow; end; Close; end; end; {** Gets a description of all the standard SQL types supported by this database. They are ordered by DATA_TYPE and then by how closely the data type maps to the corresponding JDBC SQL type.

Each type description has the following columns:

  1. TYPE_NAME String => Type name
  2. DATA_TYPE short => SQL data type from java.sql.Types
  3. PRECISION int => maximum precision
  4. LITERAL_PREFIX String => prefix used to quote a literal (may be null)
  5. LITERAL_SUFFIX String => suffix used to quote a literal (may be null)
  6. CREATE_PARAMS String => parameters used in creating the type (may be null)
  7. NULLABLE short => can you use NULL for this type?
    • typeNoNulls - does not allow NULL values
    • typeNullable - allows NULL values
    • typeNullableUnknown - nullability unknown
  8. CASE_SENSITIVE boolean=> is it case sensitive?
  9. SEARCHABLE short => can you use "WHERE" based on this type:
    • typePredNone - No support
    • typePredChar - Only supported with WHERE .. LIKE
    • typePredBasic - Supported except for WHERE .. LIKE
    • typeSearchable - Supported for all WHERE ..
  10. UNSIGNED_ATTRIBUTE boolean => is it unsigned?
  11. FIXED_PREC_SCALE boolean => can it be a money value?
  12. AUTO_INCREMENT boolean => can it be used for an auto-increment value?
  13. LOCAL_TYPE_NAME String => localized version of type name (may be null)
  14. MINIMUM_SCALE short => minimum scale supported
  15. MAXIMUM_SCALE short => maximum scale supported
  16. SQL_DATA_TYPE int => unused
  17. SQL_DATETIME_SUB int => unused
  18. NUM_PREC_RADIX int => usually 2 or 10
@return ResultSet - each row is an SQL type description } function TZInterbase6DatabaseMetadata.UncachedGetTypeInfo: IZResultSet; var SQL: string; begin Result:=inherited UncachedGetTypeInfo; SQL := ' SELECT RDB$TYPE, RDB$TYPE_NAME FROM RDB$TYPES ' + ' WHERE RDB$FIELD_NAME = ''RDB$FIELD_TYPE'' '; with GetConnection.CreateStatement.ExecuteQuery(SQL) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateString(1, GetString(2)); Result.UpdateInt(2, Ord(ConvertInterbase6ToSqlType(GetInt(1), 0, ConSettings.CPType))); Result.UpdateInt(3, 9); Result.UpdateInt(7, Ord(ntNoNulls)); Result.UpdateBoolean(8, false); Result.UpdateBoolean(9, false); Result.UpdateBoolean(11, false); Result.UpdateBoolean(12, false); Result.UpdateInt(18, 10); Result.InsertRow; end; Close; end; end; {** Gets a description of a table's indices and statistics. They are ordered by NON_UNIQUE, TYPE, INDEX_NAME, and ORDINAL_POSITION.

Each index column description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. NON_UNIQUE boolean => Can index values be non-unique? false when TYPE is tableIndexStatistic
  5. INDEX_QUALIFIER String => index catalog (may be null); null when TYPE is tableIndexStatistic
  6. INDEX_NAME String => index name; null when TYPE is tableIndexStatistic
  7. TYPE short => index type:
    • tableIndexStatistic - this identifies table statistics that are returned in conjuction with a table's index descriptions
    • tableIndexClustered - this is a clustered index
    • tableIndexHashed - this is a hashed index
    • tableIndexOther - this is some other style of index
  8. ORDINAL_POSITION short => column sequence number within index; zero when TYPE is tableIndexStatistic
  9. COLUMN_NAME String => column name; null when TYPE is tableIndexStatistic
  10. ASC_OR_DESC String => column sort sequence, "A" => ascending, "D" => descending, may be null if sort sequence is not supported; null when TYPE is tableIndexStatistic
  11. CARDINALITY int => When TYPE is tableIndexStatistic, then this is the number of rows in the table; otherwise, it is the number of unique values in the index.
  12. PAGES int => When TYPE is tableIndexStatisic then this is the number of pages used for the table, otherwise it is the number of pages used for the current index.
  13. FILTER_CONDITION String => Filter condition, if any. (may be null)
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @param unique when true, return only indices for unique values; when false, return indices regardless of whether unique or not @param approximate when true, result is allowed to reflect approximate or out of data values; when false, results are requested to be accurate @return ResultSet - each row is an index column description } function TZInterbase6DatabaseMetadata.UncachedGetIndexInfo(const Catalog: string; const Schema: string; const Table: string; Unique: Boolean; Approximate: Boolean): IZResultSet; var SQL : string; LTable: String; begin LTable := ConstructNameCondition(Table, 'I.RDB$RELATION_NAME'); if LTable <> '' then LTable := ' AND ' + LTable; Result:=inherited UncachedGetIndexInfo(Catalog, Schema, Table, Unique, Approximate); SQL := ' SELECT I.RDB$RELATION_NAME, I.RDB$UNIQUE_FLAG, I.RDB$INDEX_NAME,' + ' ISGMT.RDB$FIELD_POSITION, ISGMT.RDB$FIELD_NAME, I.RDB$INDEX_TYPE,' + ' I.RDB$SEGMENT_COUNT, COUNT (DISTINCT P.RDB$PAGE_NUMBER) ' + ' FROM RDB$INDICES I JOIN RDB$INDEX_SEGMENTS ISGMT ON' + ' I.RDB$INDEX_NAME = ISGMT.RDB$INDEX_NAME JOIN RDB$RELATIONS R ON' + ' (R.RDB$RELATION_NAME = I.RDB$RELATION_NAME) JOIN RDB$PAGES P ON' + ' (P.RDB$RELATION_ID = R.RDB$RELATION_ID AND P.RDB$PAGE_TYPE = 7' + ' OR P.RDB$PAGE_TYPE = 6) WHERE '; if Unique then SQL := SQL + ' I.RDB$UNIQUE_FLAG = 1 AND '; SQL := SQL + 'I.RDB$RELATION_NAME != '''' ' + LTable + ' GROUP BY ' + ' I.RDB$INDEX_NAME, I.RDB$RELATION_NAME, I.RDB$UNIQUE_FLAG, ' + ' ISGMT.RDB$FIELD_POSITION, ISGMT.RDB$FIELD_NAME, I.RDB$INDEX_TYPE, ' + ' I.RDB$SEGMENT_COUNT ORDER BY 1,2,3,4'; with GetConnection.CreateStatement.ExecuteQuery(SQL) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateNull(1); //TABLE_CAT Result.UpdateNull(2); //TABLE_SCHEM Result.UpdateString(3, GetString(1)); //TABLE_NAME, RDB$RELATION_NAME Result.UpdateBoolean(4, not GetBoolean(2)); //NON_UNIQUE, RDB$UNIQUE_FLAG Result.UpdateNull(5); //INDEX_QUALIFIER Result.UpdateString(6, GetString(3)); //INDEX_NAME, RDB$INDEX_NAME Result.UpdateInt(7, Ord(ntNoNulls)); //TYPE Result.UpdateInt(8, GetInt(4) + 1); //ORDINAL_POSITION, RDB$FIELD_POSITION Result.UpdateString(9, GetString(5)); //COLUMN_NAME, RDB$FIELD_NAME Result.UpdateNull(10); //ASC_OR_DESC Result.UpdateNull(11); //CARDINALITY Result.UpdateInt(12, GetInt(7)); //PAGES, RDB$SEGMENT_COUNT Result.UpdateNull(13); //FILTER_CONDITION Result.InsertRow; end; Close; end; end; function TZInterbase6DatabaseMetadata.UncachedGetSequences(const Catalog, SchemaPattern, SequenceNamePattern: string): IZResultSet; var SQL: string; LSequenceNamePattern: string; begin Result:=inherited UncachedGetSequences(Catalog, SchemaPattern, SequenceNamePattern); LSequenceNamePattern := ConstructNameCondition(SequenceNamePattern, 'RDB$GENERATOR_NAME'); if LSequenceNamePattern <> '' then LSequenceNamePattern := ' and '+LSequenceNamePattern; SQL := ' SELECT RDB$GENERATOR_NAME FROM RDB$GENERATORS ' + 'WHERE (RDB$SYSTEM_FLAG IS NULL OR RDB$SYSTEM_FLAG = 0)'+ LSequenceNamePattern; with GetConnection.CreateStatement.ExecuteQuery(SQL) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateNull(1); Result.UpdateNull(2); Result.UpdateString(3, GetString(1)); //RDB$GENERATOR_NAME Result.InsertRow; end; Close; end; end; {** Gets a privilege name. @param Interbase privilege name @returns a JDBC privilege name. } function TZInterbase6DatabaseMetadata.GetPrivilege(Privilege: string): string; begin if Privilege = 'S' then Result := 'SELECT' else if Privilege = 'I' then Result := 'INSERT' else if Privilege = 'U' then Result := 'UPDATE' else if Privilege = 'D' then Result := 'DELETE' else if Privilege = 'R' then Result := 'REFERENCE' else Result := ''; end; {** Gets the used Collation and CharacterSet of spezified Object. @param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" and Catolog "" retrieves nothing @param table a table name; "" retrieves the Schema Colloation and CharacterSet @param ColumnNamePattern ColumnPattern;"" retrieves the Table(if @param TablePattern is set) or Schema(if @param TablePattern is NULL) Colloation and CharacterSet @return ResultSet - each row is a Collation, CharacterSet, ID, and ByteLength per Char of speziefied Object } function TZInterbase6DatabaseMetadata.UncachedGetCollationAndCharSet(const Catalog, SchemaPattern, TableNamePattern, ColumnNamePattern: string): IZResultSet; //EgonHugeist var SQL, LCatalog: string; ColumnNameCondition, TableNameCondition: string; begin if Catalog = '' then begin if SchemaPattern <> '' then LCatalog := SchemaPattern else LCatalog := FDatabase; end else LCatalog := Catalog; TableNameCondition := ConstructNameCondition(TableNamePattern,'R.RDB$RELATION_NAME'); ColumnNameCondition := ConstructNameCondition(ColumnNamePattern,'R.RDB$FIELD_NAME'); If TableNameCondition <> '' then TableNameCondition := ' and ' + TableNameCondition; If ColumnNameCondition <> '' then ColumnNameCondition := ' and ' + ColumnNameCondition; Result:=inherited UncachedGetCollationAndCharSet(Catalog, SchemaPattern, TableNamePattern, ColumnNamePattern); if LCatalog <> '' then begin if TableNamePattern <> '' then begin if ColumnNamePattern <> '' then begin SQL := 'SELECT C.RDB$CHARACTER_SET_NAME, C.RDB$DEFAULT_COLLATE_NAME, '+ 'C.RDB$CHARACTER_SET_ID, C.RDB$BYTES_PER_CHARACTER '+ 'FROM RDB$RELATION_FIELDS R '+ 'right join RDB$FIELDS F on R.RDB$FIELD_SOURCE = F.RDB$FIELD_NAME '+ 'left join RDB$CHARACTER_SETS C on C.RDB$CHARACTER_SET_ID = F.RDB$CHARACTER_SET_ID '+ 'left join RDB$TYPES T on F.RDB$FIELD_TYPE = T.RDB$TYPE'+ 'where T.RDB$FIELD_NAME=''RDB$FIELD_TYPE'' '+ ColumnNameCondition+TableNameCondition+ 'order by R.RDB$FIELD_POSITION;'; with GetConnection.CreateStatement.ExecuteQuery(SQL) do begin if Next then begin if not ( GetString(FindColumn('RDB$CHARACTER_SET_NAME')) = 'NONE' ) then begin Result.MoveToInsertRow; Result.UpdateString(1, LCatalog); //COLLATION_CATALOG Result.UpdateString(2, LCatalog); //COLLATION_SCHEMA Result.UpdateString(3, TableNamePattern); //COLLATION_TABLE Result.UpdateString(4, ColumnNamePattern);//COLLATION_COLUMN Result.UpdateString(5, GetString(FindColumn('RDB$DEFAULT_COLLATE_NAME'))); //COLLATION_NAME Result.UpdateString(6, GetString(FindColumn('RDB$CHARACTER_SET_NAME'))); //CHARACTER_SET_NAME Result.UpdateShort(7, GetShort(FindColumn('RDB$CHARACTER_SET_ID'))); //CHARACTER_SET_ID Result.UpdateShort(8, GetShort(FindColumn('RDB$BYTES_PER_CHARACTER'))); //CHARACTER_SET_SIZE Result.InsertRow; Close; Exit; end; end; Close; end; end; end; end; {Brings Defaults for Table or Database up} SQL := 'SELECT D.RDB$CHARACTER_SET_NAME, CS.RDB$DEFAULT_COLLATE_NAME, '+ 'CS.RDB$CHARACTER_SET_ID, CS.RDB$BYTES_PER_CHARACTER '+ 'FROM RDB$DATABASE D '+ 'LEFT JOIN RDB$CHARACTER_SETS CS on '+ 'D.RDB$CHARACTER_SET_NAME = CS.RDB$CHARACTER_SET_NAME; '; with GetConnection.CreateStatement.ExecuteQuery(SQL) do begin if Next then begin Result.MoveToInsertRow; Result.UpdateString(1, LCatalog); //COLLATION_CATALOG Result.UpdateString(2, LCatalog); //COLLATION_SCHEMA Result.UpdateString(3, TableNamePattern); //COLLATION_TABLE Result.UpdateNull(4);//COLLATION_COLUMN Result.UpdateString(5, GetString(FindColumn('RDB$DEFAULT_COLLATE_NAME'))); //COLLATION_NAME Result.UpdateString(6, GetString(FindColumn('RDB$CHARACTER_SET_NAME'))); //CHARACTER_SET_NAME Result.UpdateShort(7, GetShort(FindColumn('RDB$CHARACTER_SET_ID'))); //CHARACTER_SET_ID Result.UpdateShort(8, GetShort(FindColumn('RDB$BYTES_PER_CHARACTER'))); //CHARACTER_SET_SIZE Result.InsertRow; end; Close; end; end; {** Gets the supported CharacterSets: @return ResultSet - each row is a CharacterSetName and it's ID } function TZInterbase6DatabaseMetadata.UncachedGetCharacterSets: IZResultSet; //EgonHugeist begin Result:=inherited UncachedGetCharacterSets; with GetConnection.CreateStatement.ExecuteQuery( 'SELECT RDB$CHARACTER_SET_NAME, RDB$CHARACTER_SET_ID '+ 'FROM RDB$CHARACTER_SETS') do begin while Next do begin Result.MoveToInsertRow; Result.UpdateString(1, GetString(FindColumn('RDB$CHARACTER_SET_NAME'))); //CHARACTER_SET_NAME Result.UpdateString(2, GetString(FindColumn('RDB$CHARACTER_SET_ID'))); //CHARACTER_SET_ID Result.InsertRow; end; Close; end; end; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcInterbase6ResultSet.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Interbase Database Connectivity Classes } { } { Originally written by Sergey Merkuriev } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcInterbase6ResultSet; interface {$I ZDbc.inc} uses {$IFDEF WITH_TOBJECTLIST_INLINE}System.Types, System.Contnrs{$ELSE}Types{$ENDIF}, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} ZDbcIntfs, ZDbcResultSet, ZDbcInterbase6, ZPlainFirebirdInterbaseConstants, ZPlainFirebirdDriver, ZCompatibility, ZDbcResultSetMetadata, ZMessages, ZDbcInterbase6Utils; type {** Implements Interbase ResultSet. } TZInterbase6ResultSet = class(TZAbstractResultSet) private FCachedBlob: boolean; FFetchStat: Integer; FCursorName: AnsiString; FStmtHandle: TISC_STMT_HANDLE; FSqlData: IZResultSQLDA; FIBConnection: IZInterbase6Connection; protected procedure Open; override; function GetFieldValue(ColumnIndex: Integer): Variant; function InternalGetString(ColumnIndex: Integer): RawByteString; override; public constructor Create(Statement: IZStatement; SQL: string; var StatementHandle: TISC_STMT_HANDLE; CursorName: AnsiString; SqlData: IZResultSQLDA; CachedBlob: boolean); destructor Destroy; override; procedure Close; override; function GetCursorName: AnsiString; override; function IsNull(ColumnIndex: Integer): Boolean; override; function GetString(ColumnIndex: Integer): String; override; function GetUnicodeString(ColumnIndex: Integer): WideString; override; function GetBoolean(ColumnIndex: Integer): Boolean; override; function GetByte(ColumnIndex: Integer): Byte; override; function GetShort(ColumnIndex: Integer): SmallInt; override; function GetInt(ColumnIndex: Integer): Integer; override; function GetLong(ColumnIndex: Integer): Int64; override; function GetFloat(ColumnIndex: Integer): Single; override; function GetDouble(ColumnIndex: Integer): Double; override; function GetBigDecimal(ColumnIndex: Integer): Extended; override; function GetBytes(ColumnIndex: Integer): TByteDynArray; override; function GetDate(ColumnIndex: Integer): TDateTime; override; function GetTime(ColumnIndex: Integer): TDateTime; override; function GetTimestamp(ColumnIndex: Integer): TDateTime; override; function GetBlob(ColumnIndex: Integer): IZBlob; override; function MoveAbsolute(Row: Integer): Boolean; override; function Next: Boolean; override; end; {** Implements external blob wrapper object for Intebase/Firbird. } TZInterbase6Blob = class(TZAbstractBlob) private FBlobId: TISC_QUAD; FBlobRead: Boolean; FIBConnection: IZInterbase6Connection; protected procedure ReadBlob; public constructor Create(IBConnection: IZInterbase6Connection; var BlobId: TISC_QUAD); function IsEmpty: Boolean; override; function Clone: IZBlob; override; function GetStream: TStream; override; function GetString: RawByteString; override; function GetUnicodeString: WideString; override; function GetBytes: TByteDynArray; override; end; implementation uses {$IFNDEF FPC} Variants, {$ENDIF} SysUtils, ZDbcUtils, ZEncoding, ZDbcLogging; { TZInterbase6ResultSet } {** Releases this ResultSet object's database and JDBC resources immediately instead of waiting for this to happen when it is automatically closed.

Note: A ResultSet object is automatically closed by the Statement object that generated it when that Statement object is closed, re-executed, or is used to retrieve the next result from a sequence of multiple results. A ResultSet object is also automatically closed when it is garbage collected. } procedure TZInterbase6ResultSet.Close; begin if FStmtHandle <> 0 then begin { Free output allocated memory } FSqlData := nil; { Free allocate sql statement } FreeStatement(FIBConnection.GetPlainDriver, FStmtHandle, DSQL_CLOSE); //AVZ end; inherited Close; end; {** Constructs this object, assignes main properties and opens the record set. @param Statement a related SQL statement object. @param handle a Interbase6 database connect handle. @param the statement previously prepared @param the sql out data previously allocated @param the Interbase sql dialect } constructor TZInterbase6ResultSet.Create(Statement: IZStatement; SQL: string; var StatementHandle: TISC_STMT_HANDLE; CursorName: AnsiString; SqlData: IZResultSQLDA; CachedBlob: boolean); begin inherited Create(Statement, SQL, nil, Statement.GetConnection.GetConSettings); FFetchStat := 0; FSqlData := SqlData; FCursorName := CursorName; FCachedBlob := CachedBlob; FIBConnection := Statement.GetConnection as IZInterbase6Connection; FStmtHandle := StatementHandle; ResultSetType := rtForwardOnly; ResultSetConcurrency := rcReadOnly; Open; end; {** Free memory and destriy component } destructor TZInterbase6ResultSet.Destroy; begin if not Closed then Close; inherited Destroy; end; {** Return field value by it index @param the index column 0 first, 1 second ... @return the field value as variant type } function TZInterbase6ResultSet.GetFieldValue(ColumnIndex: Integer): Variant; begin CheckClosed; Result := FSqlData.GetValue(ColumnIndex); end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.BigDecimal in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @param scale the number of digits to the right of the decimal point @return the column value; if the value is SQL NULL, the value returned is null } function TZInterbase6ResultSet.GetBigDecimal(ColumnIndex: Integer): Extended; begin CheckClosed; {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stBigDecimal); {$ENDIF} Result := FSqlData.GetBigDecimal(ColumnIndex - 1); LastWasNull := IsNull(ColumnIndex); end; {** Returns the value of the designated column in the current row of this ResultSet object as a Blob object in the Java programming language. @param ColumnIndex the first column is 1, the second is 2, ... @return a Blob object representing the SQL BLOB value in the specified column } {$IFDEF FPC} {$HINTS OFF} {$ENDIF} function TZInterbase6ResultSet.GetBlob(ColumnIndex: Integer): IZBlob; var Size: Integer; Buffer: Pointer; BlobId: TISC_QUAD; TempStream: TStream; begin Result := nil; CheckClosed; CheckBlobColumn(ColumnIndex); LastWasNull := IsNull(ColumnIndex); if LastWasNull then Exit; TempStream := nil; if FCachedBlob then begin try BlobId := FSqlData.GetQuad(ColumnIndex - 1); with FIBConnection do ReadBlobBufer(GetPlainDriver, GetDBHandle, GetTrHandle, BlobId, Size, Buffer); if Size = 0 then begin TempStream := TMemoryStream.Create; Result := TZAbstractBlob.CreateWithStream(TempStream, FIBConnection, GetMetaData.GetColumnType(ColumnIndex) = stUnicodeStream); end else case GetMetaData.GetColumnType(ColumnIndex) of stBinaryStream: Result := TZAbstractBlob.CreateWithData(Buffer, Size, FIBConnection); stAsciiStream: begin Result := TZAbstractBlob.CreateWithData(Buffer, Size, FIBConnection); TempStream := TStringStream.Create(GetValidatedAnsiString(Result.GetString, Consettings, True)); Result.SetStream(TempStream); end; else begin TempStream := GetValidatedUnicodeStream(Buffer, Size, ConSettings, True); Result := TZAbstractBlob.CreateWithStream(TempStream, FIBConnection, True); end; end; finally if Assigned(TempStream) then FreeAndNil(TempStream); FreeMem(Buffer, Size); end; end else begin BlobId := FSqlData.GetQuad(ColumnIndex - 1); Result := TZInterbase6Blob.Create(FIBConnection, BlobId); end; end; {$IFDEF FPC} {$HINTS ON} {$ENDIF} {** Gets the value of the designated column in the current row of this ResultSet object as a boolean in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is false } function TZInterbase6ResultSet.GetBoolean(ColumnIndex: Integer): Boolean; begin CheckClosed; {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stBoolean); {$ENDIF} Result := FSqlData.GetBoolean(ColumnIndex - 1); LastWasNull := IsNull(ColumnIndex); end; {** Gets the value of the designated column in the current row of this ResultSet object as a byte in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZInterbase6ResultSet.GetByte(ColumnIndex: Integer): Byte; begin CheckClosed; {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stByte); {$ENDIF} Result := FSqlData.GetByte(ColumnIndex - 1); LastWasNull := IsNull(ColumnIndex); end; {** Gets the value of the designated column in the current row of this ResultSet object as a byte array in the Java programming language. The bytes represent the raw values returned by the driver. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZInterbase6ResultSet.GetBytes(ColumnIndex: Integer): TByteDynArray; begin CheckClosed; {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stBytes); {$ENDIF} Result := FSqlData.GetBytes(ColumnIndex - 1); LastWasNull := IsNull(ColumnIndex); end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Date object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZInterbase6ResultSet.GetDate(ColumnIndex: Integer): TDateTime; begin CheckClosed; {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stDate); {$ENDIF} Result := FSqlData.GetDate(ColumnIndex - 1); LastWasNull := IsNull(ColumnIndex); end; {** Gets the value of the designated column in the current row of this ResultSet object as a double in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZInterbase6ResultSet.GetDouble(ColumnIndex: Integer): Double; begin CheckClosed; {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stDouble); {$ENDIF} Result := FSqlData.GetDouble(ColumnIndex - 1); LastWasNull := IsNull(ColumnIndex); end; {** Gets the value of the designated column in the current row of this ResultSet object as a float in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZInterbase6ResultSet.GetFloat(ColumnIndex: Integer): Single; begin CheckClosed; {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stFloat); {$ENDIF} Result := FSqlData.GetFloat(ColumnIndex - 1); LastWasNull := IsNull(ColumnIndex); end; {** Gets the value of the designated column in the current row of this ResultSet object as an int in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZInterbase6ResultSet.GetInt(ColumnIndex: Integer): Integer; begin CheckClosed; {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stInteger); {$ENDIF} Result := FSqlData.GetInt(ColumnIndex - 1); LastWasNull := IsNull(ColumnIndex); end; {** Gets the value of the designated column in the current row of this ResultSet object as a long in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZInterbase6ResultSet.GetLong(ColumnIndex: Integer): Int64; begin CheckClosed; {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stLong); {$ENDIF} Result := FSqlData.GetLong(ColumnIndex - 1); LastWasNull := IsNull(ColumnIndex); end; {** Gets the value of the designated column in the current row of this ResultSet object as a short in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZInterbase6ResultSet.GetShort(ColumnIndex: Integer): SmallInt; begin CheckClosed; {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stShort); {$ENDIF} Result := FSqlData.GetShort(ColumnIndex - 1); LastWasNull := IsNull(ColumnIndex); end; {** Gets the value of the designated column in the current row of this ResultSet object as a String in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZInterbase6ResultSet.InternalGetString(ColumnIndex: Integer): RawByteString; begin CheckClosed; {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stString); {$ENDIF} LastWasNull := IsNull(ColumnIndex); Result := FSqlData.GetString(ColumnIndex - 1); end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Time object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZInterbase6ResultSet.GetTime(ColumnIndex: Integer): TDateTime; begin CheckClosed; {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stTime); {$ENDIF} Result := FSqlData.GetTime(ColumnIndex - 1); LastWasNull := IsNull(ColumnIndex); end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null @exception SQLException if a database access error occurs } function TZInterbase6ResultSet.GetTimestamp(ColumnIndex: Integer): TDateTime; begin CheckClosed; {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stTimestamp); {$ENDIF} Result := FSqlData.GetTimestamp(ColumnIndex - 1); LastWasNull := IsNull(ColumnIndex); end; {** Indicates if the value of the designated column in the current row of this ResultSet object is Null. @param columnIndex the first column is 1, the second is 2, ... @return if the value is SQL NULL, the value returned is true. false otherwise. } function TZInterbase6ResultSet.IsNull(ColumnIndex: Integer): Boolean; begin CheckClosed; Result := FSqlData.IsNull(ColumnIndex - 1); end; {** Gets the value of the designated column in the current row of this ResultSet object as a String in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZInterbase6ResultSet.GetString(ColumnIndex: Integer): String; begin CheckClosed; {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stString); {$ENDIF} LastWasNull := IsNull(ColumnIndex); if ( ConSettings.ClientCodePage.ID = CS_NONE ) then //CharacterSet 'NONE' doesn't convert anything! Data as is! case FSqlData.GetIbSqlType(ColumnIndex -1) of SQL_VARYING, SQL_TEXT: if FSqlData.GetIbSqlSubType(ColumnIndex -1) = CS_NONE then Result := ZDbcString(FSqlData.GetString(ColumnIndex - 1)) else Result := ZDbcString(FSqlData.GetString(ColumnIndex - 1), FIBConnection.GetPlainDriver.ValidateCharEncoding(FSqlData.GetIbSqlSubType(ColumnIndex -1)).CP); else Result := ZDbcString(FSqlData.GetString(ColumnIndex - 1)); end else Result := ZDbcString(FSqlData.GetString(ColumnIndex - 1)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a WideString in the Delphi programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZInterbase6ResultSet.GetUnicodeString(ColumnIndex: Integer): WideString; begin CheckClosed; {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stString); {$ENDIF} LastWasNull := IsNull(ColumnIndex); if ( ConSettings.ClientCodePage.ID = CS_NONE ) then //CharacterSet 'NONE' doesn't convert anything! Data as is! case FSqlData.GetIbSqlType(ColumnIndex -1) of SQL_VARYING, SQL_TEXT: if FSqlData.GetIbSqlSubType(ColumnIndex -1) = CS_NONE then Result := ZDbcUnicodeString(FSqlData.GetString(ColumnIndex - 1)) else Result := ZDbcUnicodeString(FSqlData.GetString(ColumnIndex - 1), FIBConnection.GetPlainDriver.ValidateCharEncoding(FSqlData.GetIbSqlSubType(ColumnIndex -1)).CP); else Result := ZDbcUnicodeString(FSqlData.GetString(ColumnIndex - 1)); end else Result := ZDbcUnicodeString(FSqlData.GetString(ColumnIndex - 1)); end; {** Moves the cursor to the given row number in this ResultSet object.

If the row number is positive, the cursor moves to the given row number with respect to the beginning of the result set. The first row is row 1, the second is row 2, and so on.

If the given row number is negative, the cursor moves to an absolute row position with respect to the end of the result set. For example, calling the method absolute(-1) positions the cursor on the last row; calling the method absolute(-2) moves the cursor to the next-to-last row, and so on.

An attempt to position the cursor beyond the first/last row in the result set leaves the cursor before the first row or after the last row.

Note: Calling absolute(1) is the same as calling first(). Calling absolute(-1) is the same as calling last(). @return true if the cursor is on the result set; false otherwise } function TZInterbase6ResultSet.MoveAbsolute(Row: Integer): Boolean; begin Result := False; RaiseForwardOnlyException; end; {** Moves the cursor down one row from its current position. A ResultSet cursor is initially positioned before the first row; the first call to the method next makes the first row the current row; the second call makes the second row the current row, and so on.

If an input stream is open for the current row, a call to the method next will implicitly close it. A ResultSet object's warning chain is cleared when a new row is read. @return true if the new current row is valid; false if there are no more rows } function TZInterbase6ResultSet.Next: Boolean; var StatusVector: TARRAY_ISC_STATUS; begin { Checks for maximum row. } Result := False; if (MaxRows > 0) and (LastRowNo >= MaxRows) then Exit; { Fetch row. } if (ResultSetType = rtForwardOnly) and (FFetchStat = 0) then begin with FIBConnection do begin if (FCursorName = '') then //AVZ - Test for ExecProc - this is for multiple rows begin FFetchStat := GetPlainDriver.isc_dsql_fetch(@StatusVector, @FStmtHandle, GetDialect, FSqlData.GetData); end else begin FFetchStat := 1; Result := True; end; end; if FFetchStat = 0 then begin RowNo := RowNo + 1; LastRowNo := RowNo; Result := True; end else if not Result then CheckInterbase6Error(FIBConnection.GetPlainDriver, StatusVector, lcOther); end; end; {** Opens this recordset. } procedure TZInterbase6ResultSet.Open; var I: Integer; FieldSqlType: TZSQLType; ColumnInfo: TZColumnInfo; ZCodePageInfo: PZCodePage; begin if FStmtHandle=0 then raise EZSQLException.Create(SCanNotRetrieveResultSetData); ColumnsInfo.Clear; for I := 0 to FSqlData.GetFieldCount - 1 do begin ColumnInfo := TZColumnInfo.Create; with ColumnInfo, FSqlData do begin ColumnName := GetFieldSqlName(I); TableName := GetFieldRelationName(I); ColumnLabel := GetFieldAliasName(I); FieldSqlType := GetFieldSqlType(I); ColumnType := FieldSqlType; if FieldSqlType in [stString, stUnicodeString] then begin ZCodePageInfo := FIBConnection.GetPlainDriver.ValidateCharEncoding(GetIbSqlSubType(I)); //get column CodePage info Precision := GetFieldSize(ColumnType, ConSettings, GetIbSqlLen(I), ZCodePageInfo^.CharWidth, @ColumnDisplaySize, True); end; if FieldSQLType = stBytes then Precision := GetIbSqlLen(I); ReadOnly := (TableName = '') or (ColumnName = '') or (ColumnName = 'RDB$DB_KEY') or (FieldSqlType = ZDbcIntfs.stUnknown); if IsNullable(I) then Nullable := ntNullable else Nullable := ntNoNulls; Scale := GetFieldScale(I); CaseSensitive := UpperCase(ColumnName) <> ColumnName; //non quoted fields are uppercased by default end; ColumnsInfo.Add(ColumnInfo); end; inherited Open; end; function TZInterbase6ResultSet.GetCursorName: AnsiString; begin Result := FCursorName; end; { TZInterbase6Blob } function TZInterbase6Blob.Clone: IZBlob; begin Result := TZInterbase6Blob.Create(FIBConnection, FBlobId); end; {** Reads the blob information by blob handle. @param handle a Interbase6 database connect handle. @param the statement previously prepared } constructor TZInterbase6Blob.Create(IBConnection: IZInterbase6Connection; var BlobId: TISC_QUAD); begin FBlobId := BlobId; FBlobRead := False; FIBConnection := IBConnection; end; function TZInterbase6Blob.GetBytes: TByteDynArray; begin ReadBlob; Result := inherited GetBytes; end; function TZInterbase6Blob.GetStream: TStream; begin ReadBlob; Result := inherited GetStream; end; function TZInterbase6Blob.GetString: RawByteString; begin ReadBlob; Result := inherited GetString; end; function TZInterbase6Blob.GetUnicodeString: WideString; begin ReadBlob; Result := inherited GetUnicodeString; end; function TZInterbase6Blob.IsEmpty: Boolean; begin ReadBlob; Result := inherited IsEmpty; end; {$IFDEF FPC} {$HINTS OFF} {$ENDIF} procedure TZInterbase6Blob.ReadBlob; var Size: Integer; Buffer: Pointer; begin if FBlobRead then Exit; with FIBConnection do ReadBlobBufer(GetPlainDriver, GetDBHandle, GetTrHandle, FBlobId, Size, Buffer); BlobSize := Size; BlobData := Buffer; FBlobRead := True; end; {$IFDEF FPC} {$HINTS ON} {$ENDIF} end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcInterbase6Statement.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Interbase Database Connectivity Classes } { } { Originally written by Sergey Merkuriev } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcInterbase6Statement; interface {$I ZDbc.inc} uses Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, Types, ZDbcIntfs, ZDbcStatement, ZDbcInterbase6, ZDbcInterbase6Utils, ZDbcInterbase6ResultSet, ZPlainFirebirdInterbaseConstants, ZCompatibility, ZDbcLogging, ZVariant, ZMessages; type {** Implements Generic Interbase6 Statement. } TZInterbase6Statement = class(TZAbstractStatement) private FCachedBlob: boolean; FStatusVector: TARRAY_ISC_STATUS; FIBConnection: IZInterbase6Connection; protected function CheckInterbase6Error(const Sql: string = '') : Integer; public constructor Create(Connection: IZConnection; Info: TStrings); function ExecuteQuery(const SQL: RawByteString): IZResultSet; override; function ExecuteUpdate(const SQL: RawByteString): Integer; override; function Execute(const SQL: RawByteString): Boolean; override; end; {** Implements Prepared SQL Statement. } { TZInterbase6PreparedStatement } TZInterbase6PreparedStatement = class(TZAbstractPreparedStatement) private FCachedBlob: boolean; FParamSQLData: IZParamsSQLDA; FStatusVector: TARRAY_ISC_STATUS; FIBConnection: IZInterbase6Connection; Cursor: AnsiString; SQLData: IZResultSQLDA; StmtHandle: TISC_STMT_HANDLE; StatementType: TZIbSqlStatementType; protected procedure PrepareInParameters; override; procedure SetASQL(const Value: RawByteString); override; procedure SetWSQL(const Value: ZWideString); override; procedure BindInParameters; override; procedure UnPrepareInParameters; override; function CheckInterbase6Error(const Sql: string = '') : Integer; public constructor Create(Connection: IZConnection; const SQL: string; Info: TStrings); destructor Destroy; override; procedure Prepare; override; procedure Unprepare; override; function ExecuteQueryPrepared: IZResultSet; override; function ExecuteUpdatePrepared: Integer; override; function ExecutePrepared: Boolean; override; end; TZInterbase6CallableStatement = class(TZAbstractPreparedCallableStatement) private FCachedBlob: boolean; FParamSQLData: IZParamsSQLDA; FResultSQLData: IZResultSQLDA; FStmtHandle: TISC_STMT_HANDLE; FStatementType: TZIbSqlStatementType; FStatusVector: TARRAY_ISC_STATUS; FIBConnection: IZInterbase6Connection; protected procedure CheckInterbase6Error(const Sql: string = ''); procedure FetchOutParams(Value: IZResultSQLDA); function GetProcedureSql(SelectProc: boolean): string; procedure PrepareInParameters; override; procedure BindInParameters; override; procedure UnPrepareInParameters; override; public constructor Create(Connection: IZConnection; const SQL: string; Info: TStrings); destructor Destroy; override; procedure Unprepare; override; function ExecuteQueryPrepared: IZResultSet; override; function ExecuteUpdatePrepared: Integer; override; function ExecutePrepared: Boolean; override; end; implementation uses ZSysUtils, ZDbcUtils; { TZInterbase6Statement } {** Check interbase error status @param Sql the used sql tring @return ErrorCode for possible Database Disconnect } function TZInterbase6Statement.CheckInterbase6Error(const Sql: string = '') : Integer; begin Result := ZDbcInterbase6Utils.CheckInterbase6Error(FIBConnection.GetPlainDriver, FStatusVector, lcExecute, SQL); end; {** Constructs this object and assignes the main properties. @param Connection a database connection object. @param Handle a connection handle pointer. @param Dialect a dialect Interbase SQL must be 1 or 2 or 3. @param Info a statement parameters. } constructor TZInterbase6Statement.Create(Connection: IZConnection; Info: TStrings); begin inherited Create(Connection, Info); FIBConnection := Connection as IZInterbase6Connection; ResultSetType := rtScrollInsensitive; FCachedBlob := StrToBoolEx(DefineStatementParameter(Self, 'cashedblob', 'true')); end; {** Destroys this object and cleanups the memory. } {** Executes an SQL statement that returns a single ResultSet object. @param sql typically this is a static SQL SELECT statement @return a ResultSet object that contains the data produced by the given query; never null } {$HINTS OFF} function TZInterbase6Statement.ExecuteQuery(const SQL: RawByteString): IZResultSet; var Cursor: AnsiString; SQLData: IZResultSQLDA; StmtHandle: TISC_STMT_HANDLE; StatementType: TZIbSqlStatementType; iError : Integer; //For closing the database //AVZ begin StmtHandle := 0; iError := 0; {$IFNDEF UNICODE}ASQL := SQL;{$ENDIF} //preprepares SQL and sets AnsiSQL(ASQL) with FIBConnection do begin SQLData := TZResultSQLDA.Create(GetPlainDriver, GetDBHandle, GetTrHandle, ConSettings); try StatementType := ZDbcInterbase6Utils.PrepareStatement(GetPlainDriver, GetDBHandle, GetTrHandle, GetDialect, ASQL, SSQL, StmtHandle); PrepareResultSqlData(GetPlainDriver, GetDBHandle, GetDialect, SSQL, StmtHandle, SQLData); DriverManager.LogMessage(lcExecute, GetPlainDriver.GetProtocol, SSQL); GetPlainDriver.isc_dsql_execute(@FStatusVector, GetTrHandle, @StmtHandle, GetDialect, SQLData.GetData); iError := CheckInterbase6Error(SSQL); if (StatementType in [stSelect, stExecProc]) and (SQLData.GetFieldCount <> 0) then begin if CursorName <> '' then begin Cursor := CursorName; GetPlainDriver.isc_dsql_set_cursor_name(@FStatusVector, @StmtHandle, PAnsiChar(Cursor), 0); CheckInterbase6Error(SSQL); end; Result := CreateIBResultSet(SSQL, Self, TZInterbase6ResultSet.Create(Self, LogSQL, StmtHandle, Cursor, SQLData, FCachedBlob)); end else if (iError <> DISCONNECT_ERROR) then raise EZSQLException.Create(SCanNotRetrieveResultSetData); except on E: Exception do begin FreeStatement(GetPlainDriver, StmtHandle, DSQL_drop); //Free Stmt handle only if Execution fails. Otherwise the ResultSet will do this raise; end; end; end; end; {$HINTS OFF} {** Executes an SQL INSERT, UPDATE or DELETE statement. In addition, SQL statements that return nothing, such as SQL DDL statements, can be executed. @param sql an SQL INSERT, UPDATE or DELETE statement or an SQL statement that returns nothing @return either the row count for INSERT, UPDATE or DELETE statements, or 0 for SQL statements that return nothing } {$HINTS OFF} function TZInterbase6Statement.ExecuteUpdate(const SQL: RawByteString): Integer; var StmtHandle: TISC_STMT_HANDLE; StatementType: TZIbSqlStatementType; begin Result := -1; StmtHandle := 0; with FIBConnection do begin try {$IFNDEF UNICODE}ASQL := SQL;{$ENDIF} //preprepares SQL and sets AnsiSQL(ASQL) StatementType := ZDbcInterbase6Utils.PrepareStatement(GetPlainDriver, GetDBHandle, GetTrHandle, GetDialect, ASQL, SSQL, StmtHandle); DriverManager.LogMessage(lcExecute, GetPlainDriver.GetProtocol, SSQL); GetPlainDriver.isc_dsql_execute2(@FStatusVector, GetTrHandle, @StmtHandle, GetDialect, nil, nil); CheckInterbase6Error(SSQL); case StatementType of stCommit, stRollback, stUnknown: Result := -1; else begin Result := GetAffectedRows(GetPlainDriver, StmtHandle, StatementType); LastUpdateCount := Result; end; end; { Autocommit statement. } if Connection.GetAutoCommit then Connection.Commit; { Logging SQL Command } finally FreeStatement(GetPlainDriver, StmtHandle, DSQL_drop); //Free Stmt handle because of single executions without a prepared state end; end; end; {$HINTS ON} {** Executes an SQL statement that may return multiple results. Under some (uncommon) situations a single SQL statement may return multiple result sets and/or update counts. Normally you can ignore this unless you are (1) executing a stored procedure that you know may return multiple results or (2) you are dynamically executing an unknown SQL string. The methods execute, getMoreResults, getResultSet, and getUpdateCount let you navigate through multiple results. The execute method executes an SQL statement and indicates the form of the first result. You can then use the methods getResultSet or getUpdateCount to retrieve the result, and getMoreResults to move to any subsequent result(s). @param sql any SQL statement @return true if the next result is a ResultSet object; false if it is an update count or there are no more results @see #getResultSet @see #getUpdateCount @see #getMoreResults } {$HINTS OFF} function TZInterbase6Statement.Execute(const SQL: RawByteString): Boolean; var Cursor: AnsiString; SQLData: IZResultSQLDA; StmtHandle: TISC_STMT_HANDLE; StatementType: TZIbSqlStatementType; begin StmtHandle := 0; with FIBConnection do begin try Result := False; {$IFNDEF UNICODE}ASQL := SQL;{$ENDIF} //preprepares SQL and sets AnsiSQL(ASQL) StatementType := ZDbcInterbase6Utils.PrepareStatement(GetPlainDriver, GetDBHandle, GetTrHandle, GetDialect, ASQL, LogSQL, StmtHandle); { Check statement type } // if not (StatementType in [stExecProc]) then // raise EZSQLException.Create(SStatementIsNotAllowed); { Create Result SQLData if statement returns result } if StatementType in [stSelect, stExecProc] then begin SQLData := TZResultSQLDA.Create(GetPlainDriver, GetDBHandle, GetTrHandle, ConSettings); PrepareResultSqlData(GetPlainDriver, GetDBHandle, GetDialect, LogSQL, StmtHandle, SQLData); end; DriverManager.LogMessage(lcExecute, GetPlainDriver.GetProtocol, SSQL); { Execute prepared statement } GetPlainDriver.isc_dsql_execute(@FStatusVector, GetTrHandle, @StmtHandle, GetDialect, nil); CheckInterbase6Error(LogSQL); { Set updated rows count } LastUpdateCount := GetAffectedRows(GetPlainDriver, StmtHandle, StatementType); case StatementType of stInsert, stDelete, stUpdate, stSelectForUpdate: Result := False; else Result := True; end; { Create ResultSet if possible else free Stateent Handle } if (StatementType in [stSelect, stExecProc]) and (SQLData.GetFieldCount <> 0) then begin if CursorName <> '' then begin Cursor := CursorName; GetPlainDriver.isc_dsql_set_cursor_name(@FStatusVector, @StmtHandle, PAnsiChar(Cursor), 0); CheckInterbase6Error(sSQL); end; LastResultSet := CreateIBResultSet(SSQL, Self, TZInterbase6ResultSet.Create(Self, SSQL, StmtHandle, Cursor, SQLData, FCachedBlob)); end else begin LastResultSet := nil; FreeStatement(GetPlainDriver, StmtHandle, DSQL_drop); end; { Autocommit statement. } if Connection.GetAutoCommit then Connection.Commit; except on E: Exception do begin FreeStatement(GetPlainDriver, StmtHandle, DSQL_drop); //Free Stmt handle because of single executions without a prepared state raise; end; end; end; end; {$HINTS ON} { TZInterbase6PreparedStatement } procedure TZInterbase6PreparedStatement.PrepareInParameters; var StatusVector: TARRAY_ISC_STATUS; begin With FIBConnection do begin {create the parameter bind structure} FParamSQLData := TZParamsSQLDA.Create(GetPlainDriver, GetDBHandle, GetTrHandle, ConSettings); {check dynamic sql} GetPlainDriver.isc_dsql_describe_bind(@StatusVector, @StmtHandle, GetDialect, FParamSQLData.GetData); ZDbcInterbase6Utils.CheckInterbase6Error(GetPlainDriver, StatusVector, lcExecute, SSQL); { Resize XSQLDA structure if needed } if FParamSQLData.GetData^.sqld > FParamSQLData.GetData^.sqln then begin FParamSQLData.AllocateSQLDA; GetPlainDriver.isc_dsql_describe_bind(@StatusVector, @StmtHandle, GetDialect,FParamSQLData.GetData); ZDbcInterbase6Utils.CheckInterbase6Error(GetPlainDriver, StatusVector, lcExecute, SSQL); end; FParamSQLData.InitFields(True); end; inherited PrepareInParameters; end; procedure TZInterbase6PreparedStatement.SetASQL(const Value: RawByteString); begin if ( ASQL <> Value ) and Prepared then Unprepare; inherited SetASQL(Value); end; procedure TZInterbase6PreparedStatement.SetWSQL(const Value: ZWideString); begin if ( WSQL <> Value ) and Prepared then Unprepare; inherited SetWSQL(Value); end; procedure TZInterbase6PreparedStatement.BindInParameters; begin BindSQLDAInParameters(FIBConnection.GetPlainDriver, InParamValues, InParamTypes, InParamCount, FParamSQLData, GetConnection.GetConSettings); inherited BindInParameters; end; procedure TZInterbase6PreparedStatement.UnPrepareInParameters; begin if assigned(FParamSQLData) then FParamSQLData.FreeParamtersValues; end; {** Check interbase error status @param Sql the used sql tring @return Integer - Error Code to test for graceful database disconnection } function TZInterbase6PreparedStatement.CheckInterbase6Error(const Sql: string) : Integer; begin Result := ZDbcInterbase6Utils.CheckInterbase6Error(FIBConnection.GetPlainDriver, FStatusVector, lcExecute, SQL); end; {** Constructs this object and assignes the main properties. @param Connection a database connection object. @param Handle a connection handle pointer. @param Dialect a dialect Interbase SQL must be 1 or 2 or 3. @param Info a statement parameters. } constructor TZInterbase6PreparedStatement.Create(Connection: IZConnection; const SQL: string; Info: TStrings); begin inherited Create(Connection, SQL, Info); FIBConnection := Connection as IZInterbase6Connection; ResultSetType := rtScrollInsensitive; FCachedBlob := StrToBoolEx(DefineStatementParameter(Self, 'cashedblob', 'true')); StmtHandle := 0; Prepare; end; destructor TZInterbase6PreparedStatement.Destroy; begin inherited Destroy; FreeStatement(FIBConnection.GetPlainDriver, StmtHandle, DSQL_drop); end; procedure TZInterbase6PreparedStatement.Prepare; begin with FIBConnection do begin StatementType := ZDbcInterbase6Utils.PrepareStatement(GetPlainDriver, GetDBHandle, GetTrHandle, GetDialect, ASQL, LogSQL, StmtHandle); //allocate handle if required or reuse it if StatementType in [stSelect, stExecProc] then begin SQLData := TZResultSQLDA.Create(GetPlainDriver, GetDBHandle, GetTrHandle , ConSettings); PrepareResultSqlData(GetPlainDriver, GetDBHandle, GetDialect, SQL, StmtHandle, SQLData); end; end; CheckInterbase6Error(SQL); LogPrepStmtMessage(lcPrepStmt, SQL); inherited Prepare; end; procedure TZInterbase6PreparedStatement.Unprepare; begin if StmtHandle <> 0 then //check if prepare did fail. otherwise we unprepare the handle FreeStatement(FIBConnection.GetPlainDriver, StmtHandle, DSQL_UNPREPARE); //unprepare avoids new allocation for the stmt handle inherited Unprepare; end; {** Executes any kind of SQL statement. Some prepared statements return multiple results; the execute method handles these complex statements as well as the simpler form of statements handled by the methods executeQuery and executeUpdate. @see Statement#execute } {$HINTS OFF} function TZInterbase6PreparedStatement.ExecutePrepared: Boolean; begin Result := False; if not Prepared then Prepare; with FIBConnection do begin try BindInParameters; if (StatementType = stSelect) then //AVZ Get many rows - only need to use execute not execute2 GetPlainDriver.isc_dsql_execute(@FStatusVector, GetTrHandle, @StmtHandle, GetDialect, FParamSQLData.GetData) else begin CursorName := 'ExecProc'+RandomString(12); //AVZ - Need a way to return one row so we give the cursor a name if (SQLData = nil) then GetPlainDriver.isc_dsql_execute2(@FStatusVector, GetTrHandle, @StmtHandle, GetDialect, FParamSQLData.GetData, nil) //not expecting a result else GetPlainDriver.isc_dsql_execute2(@FStatusVector, GetTrHandle, @StmtHandle, GetDialect, FParamSQLData.GetData, SQLData.GetData); //expecting a result end; CheckInterbase6Error(SQL); LastUpdateCount := GetAffectedRows(GetPlainDriver, StmtHandle, StatementType); case StatementType of stInsert, stDelete, stUpdate, stSelectForUpdate: Result := False; else Result := True; end; { Create ResultSet if possible else free Statement Handle } if (StatementType in [stSelect, stExecProc]) and (SQLData.GetFieldCount <> 0) then begin LastResultSet := CreateIBResultSet(SQL, Self, TZInterbase6ResultSet.Create(Self, SQL, StmtHandle, Cursor, SQLData, FCachedBlob)); end else begin LastResultSet := nil; end; { Autocommit statement. } if Connection.GetAutoCommit then Connection.Commit; except on E: Exception do begin {EH: do not Close the Stmt if execution fails !!} //FreeStatement(GetPlainDriver, StmtHandle, DSQL_CLOSE); //AVZ raise; end; end; end; inherited ExecutePrepared; end; {$HINTS ON} {** Executes the SQL query in this PreparedStatement object and returns the result set generated by the query. @return a ResultSet object that contains the data produced by the query; never null } {$HINTS OFF} function TZInterbase6PreparedStatement.ExecuteQueryPrepared: IZResultSet; var iError : Integer; //Check for database disconnect AVZ begin if not Prepared then Prepare; with FIBConnection do begin try BindInParameters; if (StatementType = stSelect) then //AVZ Get many rows - only need to use execute not execute2 GetPlainDriver.isc_dsql_execute(@FStatusVector, GetTrHandle, @StmtHandle, GetDialect, FParamSQLData.GetData) else begin CursorName := 'ExecProc'+RandomString(12); //AVZ - Need a way to return one row so we give the cursor a name if (SQLData = nil) then GetPlainDriver.isc_dsql_execute2(@FStatusVector, GetTrHandle, @StmtHandle, GetDialect, FParamSQLData.GetData, nil) //not expecting a result else GetPlainDriver.isc_dsql_execute2(@FStatusVector, GetTrHandle, @StmtHandle, GetDialect, FParamSQLData.GetData, SQLData.GetData); //expecting a result end; iError := CheckInterbase6Error(SQL); if (StatementType in [stSelect, stExecProc]) and (SQLData.GetFieldCount <> 0) then begin if CursorName <> '' then begin Cursor := CursorName; GetPlainDriver.isc_dsql_set_cursor_name(@FStatusVector, @StmtHandle, PAnsiChar(Cursor), 0); iError := CheckInterbase6Error(SQL); end; if (iError <> DISCONNECT_ERROR) then Result := CreateIBResultSet(LogSQL, Self, TZInterbase6ResultSet.Create(Self, LogSQL, StmtHandle, Cursor, SQLData, FCachedBlob)); end else if (iError <> DISCONNECT_ERROR) then //AVZ raise EZSQLException.Create(SCanNotRetrieveResultSetData) else Result := nil; except on E: Exception do begin //The cursor will be already closed for exec2 if (Pos('ExecProc', String(CursorName)) <> 0) then StmtHandle := 0; {EH: do not Close the Stmt if execution fails !! This will be done on unprepare} //FreeStatement(GetPlainDriver, StmtHandle, DSQL_CLOSE); //AVZ raise; end; end; end; inherited ExecuteQueryPrepared; end; {$HINTS ON} {** Executes the SQL INSERT, UPDATE or DELETE statement in this PreparedStatement object. In addition, SQL statements that return nothing, such as SQL DDL statements, can be executed. @return either the row count for INSERT, UPDATE or DELETE statements; or 0 for SQL statements that return nothing } {$HINTS OFF} function TZInterbase6PreparedStatement.ExecuteUpdatePrepared: Integer; var iError : Integer; //Implementation for graceful disconnect AVZ begin Result := -1; if not Prepared then Prepare; with FIBConnection do begin BindInParameters; GetPlainDriver.isc_dsql_execute(@FStatusVector, GetTrHandle, @StmtHandle, GetDialect, FParamSQLData.GetData); iError := CheckInterbase6Error(SQL); Result := GetAffectedRows(GetPlainDriver, StmtHandle, StatementType); LastUpdateCount := Result; case StatementType of stCommit, stRollback, stUnknown: Result := -1; stSelect: FreeStatement(GetPlainDriver, StmtHandle, DSQL_CLOSE); //AVZ end; { Autocommit statement. } if Connection.GetAutoCommit and ( StatementType <> stSelect ) then Connection.Commit; end; inherited ExecuteUpdatePrepared; //Trail for the disconnection of the database gracefully - AVZ if (iError = DISCONNECT_ERROR) then begin Result := DISCONNECT_ERROR; end; end; {$HINTS ON} { TZInterbase6CallableStatement } {** Check interbase error status @param Sql the used sql tring } procedure TZInterbase6CallableStatement.CheckInterbase6Error(const Sql: string); begin ZDbcInterbase6Utils.CheckInterbase6Error(FIBConnection.GetPlainDriver, FStatusVector, lcExecute, SQL); end; {** Constructs this object and assignes the main properties. @param Connection a database connection object. @param Handle a connection handle pointer. @param Dialect a dialect Interbase SQL must be 1 or 2 or 3. @param Info a statement parameters. } constructor TZInterbase6CallableStatement.Create(Connection: IZConnection; const SQL: string; Info: TStrings); begin inherited Create(Connection, SQL, Info); FIBConnection := Connection as IZInterbase6Connection; ResultSetType := rtScrollInsensitive; FCachedBlob := StrToBoolEx(DefineStatementParameter(Self, 'cashedblob', 'true')); with FIBConnection do begin FParamSQLData := TZParamsSQLDA.Create(GetPlainDriver, GetDBHandle, GetTrHandle, ConSettings); FResultSQLData := TZResultSQLDA.Create(GetPlainDriver, GetDBHandle, GetTrHandle, ConSettings); end; end; procedure TZInterbase6CallableStatement.PrepareInParameters; begin with FIBConnection do begin { Prepare statement } FStatementType := ZDbcInterbase6Utils.PrepareStatement(GetPlainDriver, GetDBHandle, GetTrHandle, GetDialect, ZPlainString(ProcSql), ProcSQL, FStmtHandle); PrepareResultSqlData(GetPlainDriver, GetDBHandle, GetDialect, SQL, FStmtHandle, FResultSQLData); PrepareParameters(GetPlainDriver, ProcSql, GetDialect, FStmtHandle, FParamSQLData); end; end; procedure TZInterbase6CallableStatement.BindInParameters; begin BindSQLDAInParameters(FIBConnection.GetPlainDriver, InParamValues, InParamTypes, InParamCount, FParamSQLData, ConSettings); inherited BindInParameters; end; procedure TZInterbase6CallableStatement.UnPrepareInParameters; begin if assigned(FParamSQLData) then FParamSQLData.FreeParamtersValues; end; procedure TZInterbase6CallableStatement.Unprepare; begin inherited Unprepare; FreeStatement(FIBConnection.GetPlainDriver, FStmtHandle, DSQL_unprepare); if FStmtHandle <> 0 then // Free statement-hande! On the other hand: Exception! begin FreeStatement(FIBConnection.GetPlainDriver, FStmtHandle, DSQL_drop); FStmtHandle := 0; end; end; destructor TZInterbase6CallableStatement.Destroy; begin inherited Destroy; if FStmtHandle <> 0 then FreeStatement(FIBConnection.GetPlainDriver, FStmtHandle, DSQL_drop); FResultSQLData := nil; FParamSQLData := nil; end; {** Executes any kind of SQL statement. Some prepared statements return multiple results; the execute method handles these complex statements as well as the simpler form of statements handled by the methods executeQuery and executeUpdate. @see Statement#execute } {$HINTS OFF} function TZInterbase6CallableStatement.ExecutePrepared: Boolean; var Cursor: AnsiString; begin Result := False; with FIBConnection do begin ProcSql := GetProcedureSql(False); BindInParameters; DriverManager.LogMessage(lcExecute, GetPlainDriver.GetProtocol, SQL); try GetPlainDriver.isc_dsql_execute2(@FStatusVector, GetTrHandle, @FStmtHandle, GetDialect, FParamSQLData.GetData, Self.FResultSQLData.GetData); CheckInterbase6Error(SQL); LastUpdateCount := GetAffectedRows(GetPlainDriver, FStmtHandle, FStatementType); case FStatementType of stInsert, stDelete, stUpdate, stSelectForUpdate: Result := False; else Result := True; end; { Create ResultSet if possible else free Stateent Handle, ResultSQlData and ParamSqlData } if (FStatementType in [stSelect, stExecProc]) and (FResultSQLData.GetFieldCount <> 0) then begin Cursor := RandomString(12); LastResultSet := CreateIBResultSet(SQL, Self, TZInterbase6ResultSet.Create(Self, SQL, FStmtHandle, Cursor, FResultSQLData, FCachedBlob)); end else begin { Fetch data and fill Output params } FetchOutParams(FResultSQLData); FreeStatement(GetPlainDriver, FStmtHandle, DSQL_CLOSE); //AVZ LastResultSet := nil; end; { Autocommit statement. } if Connection.GetAutoCommit then Connection.Commit; except on E: Exception do begin //FreeStatement(GetPlainDriver, FStmtHandle, DSQL_CLOSE); //AVZ raise; end; end; end; end; {$HINTS ON} {** Executes the SQL query in this PreparedStatement object and returns the result set generated by the query. @return a ResultSet object that contains the data produced by the query; never null } {$HINTS OFF} function TZInterbase6CallableStatement.ExecuteQueryPrepared: IZResultSet; var Cursor: AnsiString; begin with FIBConnection do begin ProcSql := GetProcedureSql(True); //Prepares the Statement BindInParameters; try DriverManager.LogMessage(lcExecute, GetPlainDriver.GetProtocol, ProcSql); if (FStatementType = stSelect) then //AVZ Get many rows - only need to use execute not execute2 GetPlainDriver.isc_dsql_execute(@FStatusVector, GetTrHandle, @FStmtHandle, GetDialect, FParamSQLData.GetData) else begin CursorName := 'ExecProc'+RandomString(12); //AVZ - Need a way to return one row so we give the cursor a name GetPlainDriver.isc_dsql_execute2(@FStatusVector, GetTrHandle, @FStmtHandle, GetDialect, FParamSQLData.GetData, FResultSQLData.GetData); end; CheckInterbase6Error(ProcSql); if (FStatementType in [stSelect, stExecProc]) and (FResultSQLData.GetFieldCount <> 0) then begin if CursorName <> '' then begin Cursor := CursorName; GetPlainDriver.isc_dsql_set_cursor_name(@FStatusVector, @FStmtHandle, PAnsiChar(Cursor), 0); CheckInterbase6Error(ProcSql); end; Result := CreateIBResultSet(ProcSql, Self, TZInterbase6ResultSet.Create(Self, ProcSql, FStmtHandle, Cursor, FResultSQLData, FCachedBlob)); end; except on E: Exception do begin //FreeStatement(GetPlainDriver, FStmtHandle, DSQL_unprepare); //AVZ raise; end; end; end; end; {$HINTS ON} {** Executes the SQL INSERT, UPDATE or DELETE statement in this PreparedStatement object. In addition, SQL statements that return nothing, such as SQL DDL statements, can be executed. @return either the row count for INSERT, UPDATE or DELETE statements; or 0 for SQL statements that return nothing } function TZInterbase6CallableStatement.ExecuteUpdatePrepared: Integer; begin with FIBConnection do begin try ProcSQL := Self.GetProcedureSql(False); BindInParameters; DriverManager.LogMessage(lcExecute, GetPlainDriver.GetProtocol, ProcSQL); GetPlainDriver.isc_dsql_execute2(@FStatusVector, GetTrHandle, @FStmtHandle, GetDialect, FParamSQLData.GetData, FResultSQLData.GetData); CheckInterbase6Error(ProcSql); Result := GetAffectedRows(GetPlainDriver, FStmtHandle, FStatementType); LastUpdateCount := Result; { Fetch data and fill Output params } FetchOutParams(FResultSQLData); { Autocommit statement. } if Connection.GetAutoCommit then Connection.Commit; finally //FreeStatement(GetPlainDriver, FStmtHandle, DSQL_unprepare); //AVZ -- unprepare the statement - not close it end; end; end; {** Set output parameters values from TZResultSQLDA. @param Value a TZResultSQLDA object. } procedure TZInterbase6CallableStatement.FetchOutParams( Value: IZResultSQLDA); var ParamIndex, I: Integer; Temp: TZVariant; begin I := 0; for ParamIndex := 0 to OutParamCount - 1 do begin if not (FDBParamTypes[ParamIndex] in [2, 3, 4]) then // ptOutput, ptInputOutput, ptResult Continue; if I >= Value.GetFieldCount then Break; if Value.IsNull(I) then DefVarManager.SetNull(Temp) else case Value.GetFieldSqlType(I) of stBoolean: DefVarManager.SetAsBoolean(Temp, Value.GetBoolean(I)); stByte: DefVarManager.SetAsInteger(Temp, Value.GetByte(I)); stBytes: DefVarManager.SetAsBytes(Temp, Value.GetBytes(I)); stShort: DefVarManager.SetAsInteger(Temp, Value.GetShort(I)); stInteger: DefVarManager.SetAsInteger(Temp, Value.GetInt(I)); stLong: DefVarManager.SetAsInteger(Temp, Value.GetLong(I)); stFloat: DefVarManager.SetAsFloat(Temp, Value.GetFloat(I)); stDouble: DefVarManager.SetAsFloat(Temp, Value.GetDouble(I)); stBigDecimal: DefVarManager.SetAsFloat(Temp, Value.GetBigDecimal(I)); stString: DefVarManager.SetAsString(Temp, ZDbcString(Value.GetString(I))); stUnicodeString: DefVarManager.SetAsUnicodeString(Temp, ZDbcUnicodeString(Value.GetString(I))); stDate: DefVarManager.SetAsDateTime(Temp, Value.GetDate(I)); stTime: DefVarManager.SetAsDateTime(Temp, Value.GetTime(I)); stTimestamp: DefVarManager.SetAsDateTime(Temp, Value.GetTimestamp(I)); end; OutParamValues[ParamIndex] := Temp; Inc(I); end; end; {** Create sql string for calling stored procedure. @param SelectProc indicate use EXECUTE PROCEDURE or SELECT staement @return a Stored Procedure SQL string } function TZInterbase6CallableStatement.GetProcedureSql(SelectProc: boolean): string; function GenerateParamsStr(Count: integer): string; var I: integer; begin Result := ''; //init Result -> FPC for I := 0 to Count - 1 do begin if I > 0 then Result := Result + ','; Result := Result + '?'; end; end; var InParams: string; begin TrimInParameters; InParams := GenerateParamsStr(High(InParamValues) + 1); if InParams <> '' then InParams := '(' + InParams + ')'; if SelectProc then Result := 'SELECT * FROM ' + SQL + InParams else Result := 'EXECUTE PROCEDURE ' + SQL + InParams; end; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcInterbase6Utils.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Interbase Database Connectivity Classes } { } { Originally written by Sergey Merkuriev } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcInterbase6Utils; interface {$I ZDbc.inc} uses SysUtils, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} Types, ZDbcIntfs, ZDbcStatement, ZPlainFirebirdDriver, ZCompatibility, ZPlainFirebirdInterbaseConstants, ZDbcCachedResultSet, ZDbcLogging, ZMessages, ZVariant, ZTokenizer; type { Interbase Statement Type } TZIbSqlStatementType = (stUnknown, stSelect, stInsert, stUpdate, stDelete, stDDL, stGetSegment, stPutSegment, stExecProc, stStartTrans, stCommit, stRollback, stSelectForUpdate, stSetGenerator, stDisconnect); { Interbase Error Class} EZIBConvertError = class(Exception); { Paparameter string name and it value} TZIbParam = record Name: AnsiString; Number: word; end; PZIbParam = ^TZIbParam; { Interbase blob Information structure contain iformation about blob size in bytes, segments count, segment size in bytes and blob type Note: blob type can be text an binary } TIbBlobInfo = record NumSegments: Word; MaxSegmentSize: Word; BlobType: SmallInt; TotalSize: LongInt; end; { Base interface for sqlda } IZSQLDA = interface ['{2D0D6029-B31C-4E39-89DC-D86D20437C35}'] procedure InitFields(Parameters: boolean); procedure AllocateSQLDA; procedure FreeParamtersValues; function GetData: PXSQLDA; function IsBlob(const Index: Word): boolean; function IsNullable(const Index: Word): boolean; function GetFieldCount: Integer; function GetFieldSqlName(const Index: Word): String; function GetFieldRelationName(const Index: Word): String; function GetFieldOwnerName(const Index: Word): String; function GetFieldAliasName(const Index: Word): String; function GetFieldIndex(const Name: AnsiString): Word; function GetFieldScale(const Index: Word): integer; function GetFieldSqlType(const Index: Word): TZSQLType; function GetFieldLength(const Index: Word): SmallInt; function GetIbSqlType(const Index: Word): Smallint; function GetIbSqlSubType(const Index: Word): Smallint; function GetIbSqlLen(const Index: Word): Smallint; end; { parameters interface sqlda} IZParamsSQLDA = interface(IZSQLDA) ['{D2C3D5E1-F3A6-4223-9A6E-3048B99A06C4}'] procedure WriteBlob(const Index: Integer; Stream: TStream); procedure UpdateNull(const Index: Integer; Value: boolean); procedure UpdateBoolean(const Index: Integer; Value: boolean); procedure UpdateByte(const Index: Integer; Value: ShortInt); procedure UpdateShort(const Index: Integer; Value: SmallInt); procedure UpdateInt(const Index: Integer; Value: Integer); procedure UpdateLong(const Index: Integer; Value: Int64); procedure UpdateFloat(const Index: Integer; Value: Single); procedure UpdateDouble(const Index: Integer; Value: Double); procedure UpdateBigDecimal(const Index: Integer; Value: Extended); procedure UpdatePChar(const Index: Integer; Value: PAnsiChar); procedure UpdateString(const Index: Integer; Value: RawByteString); procedure UpdateBytes(const Index: Integer; Value: TByteDynArray); procedure UpdateDate(const Index: Integer; Value: TDateTime); procedure UpdateTime(const Index: Integer; Value: TDateTime); procedure UpdateTimestamp(const Index: Integer; Value: TDateTime); procedure UpdateQuad(const Index: Word; const Value: TISC_QUAD); end; { Result interface for sqlda} IZResultSQLDA = interface(IZSQLDA) ['{D2C3D5E1-F3A6-4223-9A6E-3048B99A06C4}'] procedure ReadBlobFromStream(const Index: Word; Stream: TStream); procedure ReadBlobFromString(const Index: Word; var str: AnsiString); procedure ReadBlobFromVariant(const Index: Word; var Value: Variant); function IsNull(const Index: Integer): Boolean; function GetPChar(const Index: Integer): PChar; function GetString(const Index: Integer): RawByteString; function GetBoolean(const Index: Integer): Boolean; function GetByte(const Index: Integer): Byte; function GetShort(const Index: Integer): SmallInt; function GetInt(const Index: Integer): Integer; function GetLong(const Index: Integer): Int64; function GetFloat(const Index: Integer): Single; function GetDouble(const Index: Integer): Double; function GetBigDecimal(const Index: Integer): Extended; function GetBytes(const Index: Integer): TByteDynArray; function GetDate(const Index: Integer): TDateTime; function GetTime(const Index: Integer): TDateTime; function GetTimestamp(const Index: Integer): TDateTime; function GetValue(const Index: Word): Variant; function GetQuad(const Index: Integer): TISC_QUAD; end; { Base class contain core functions to work with sqlda structure Can allocate memory for sqlda structure get basic information } TZSQLDA = class (TZCodePagedObject, IZSQLDA) private FHandle: PISC_DB_HANDLE; FTransactionHandle: PISC_TR_HANDLE; FXSQLDA: PXSQLDA; FPlainDriver: IZInterbasePlainDriver; Temp: AnsiString; procedure CheckRange(const Index: Word); procedure IbReAlloc(var P; OldSize, NewSize: Integer); procedure SetFieldType(const Index: Word; Size: Integer; Code: Smallint; Scale: Smallint); public constructor Create(PlainDriver: IZInterbasePlainDriver; Handle: PISC_DB_HANDLE; TransactionHandle: PISC_TR_HANDLE; ConSettings: PZConSettings); virtual; procedure InitFields(Parameters: boolean); procedure AllocateSQLDA; virtual; procedure FreeParamtersValues; function IsBlob(const Index: Word): boolean; function IsNullable(const Index: Word): boolean; function GetFieldCount: Integer; function GetFieldSqlName(const Index: Word): String; function GetFieldOwnerName(const Index: Word): String; function GetFieldRelationName(const Index: Word): String; function GetFieldAliasName(const Index: Word): String; function GetFieldIndex(const Name: AnsiString): Word; function GetFieldScale(const Index: Word): integer; function GetFieldSqlType(const Index: Word): TZSQLType; function GetFieldLength(const Index: Word): SmallInt; function GetData: PXSQLDA; function GetIbSqlType(const Index: Word): Smallint; function GetIbSqlSubType(const Index: Word): Smallint; function GetIbSqlLen(const Index: Word): Smallint; end; { Parameters class for sqlda structure. It clas can only write data to parameters/fields } TZParamsSQLDA = class (TZSQLDA, IZParamsSQLDA) private procedure EncodeString(Code: Smallint; const Index: Word; const Str: RawByteString); procedure EncodeBytes(Code: Smallint; const Index: Word; const Value: TByteDynArray); procedure UpdateDateTime(const Index: Integer; Value: TDateTime); public destructor Destroy; override; procedure WriteBlob(const Index: Integer; Stream: TStream); procedure UpdateNull(const Index: Integer; Value: boolean); procedure UpdateBoolean(const Index: Integer; Value: boolean); procedure UpdateByte(const Index: Integer; Value: ShortInt); procedure UpdateShort(const Index: Integer; Value: SmallInt); procedure UpdateInt(const Index: Integer; Value: Integer); procedure UpdateLong(const Index: Integer; Value: Int64); procedure UpdateFloat(const Index: Integer; Value: Single); procedure UpdateDouble(const Index: Integer; Value: Double); procedure UpdateBigDecimal(const Index: Integer; Value: Extended); procedure UpdatePChar(const Index: Integer; Value: PAnsiChar); procedure UpdateString(const Index: Integer; Value: RawByteString); procedure UpdateBytes(const Index: Integer; Value: TByteDynArray); procedure UpdateDate(const Index: Integer; Value: TDateTime); procedure UpdateTime(const Index: Integer; Value: TDateTime); procedure UpdateTimestamp(const Index: Integer; Value: TDateTime); procedure UpdateQuad(const Index: Word; const Value: TISC_QUAD); end; { Resultset class for sqlda structure. It class read data from sqlda fields } TZResultSQLDA = class (TZSQLDA, IZResultSQLDA) private function DecodeString(const Code: Smallint; const Index: Word): RawByteString; procedure DecodeString2(const Code: Smallint; const Index: Word; out Str: RawByteString); protected FDefaults: array of Variant; public destructor Destroy; override; procedure AllocateSQLDA; override; procedure ReadBlobFromStream(const Index: Word; Stream: TStream); procedure ReadBlobFromString(const Index: Word; var str: AnsiString); procedure ReadBlobFromVariant(const Index: Word; var Value: Variant); function IsNull(const Index: Integer): Boolean; function GetPChar(const Index: Integer): PChar; function GetString(const Index: Integer): RawByteString; function GetBoolean(const Index: Integer): Boolean; function GetByte(const Index: Integer): Byte; function GetShort(const Index: Integer): SmallInt; function GetInt(const Index: Integer): Integer; function GetLong(const Index: Integer): Int64; function GetFloat(const Index: Integer): Single; function GetDouble(const Index: Integer): Double; function GetBigDecimal(const Index: Integer): Extended; function GetBytes(const Index: Integer): TByteDynArray; function GetDate(const Index: Integer): TDateTime; function GetTime(const Index: Integer): TDateTime; function GetTimestamp(const Index: Integer): TDateTime; function GetValue(const Index: Word): Variant; function GetQuad(const Index: Integer): TISC_QUAD; end; function RandomString(Len: integer): AnsiString; function CreateIBResultSet(SQL: string; Statement: IZStatement; NativeResultSet: IZResultSet): IZResultSet; {Interbase6 Connection Functions} function GenerateDPB(Info: TStrings; var FDPBLength, Dialect: Word): PAnsiChar; function GenerateTPB(Params: TStrings; var Handle: TISC_DB_HANDLE): PISC_TEB; function GetInterbase6DatabaseParamNumber(const Value: AnsiString): word; function GetInterbase6TransactionParamNumber(const Value: AnsiString): word; { Interbase6 errors functions } function GetNameSqlType(Value: Word): AnsiString; function CheckInterbase6Error(PlainDriver: IZInterbasePlainDriver; StatusVector: TARRAY_ISC_STATUS; LoggingCategory: TZLoggingCategory = lcOther; SQL: string = '') : Integer; { Interbase information functions} function GetVersion(PlainDriver: IZInterbasePlainDriver; Handle: PISC_DB_HANDLE): AnsiString; function GetDBImplementationNo(PlainDriver: IZInterbasePlainDriver; Handle: PISC_DB_HANDLE): LongInt; function GetDBImplementationClass(PlainDriver: IZInterbasePlainDriver; Handle: PISC_DB_HANDLE): LongInt; function GetLongDbInfo(PlainDriver: IZInterbasePlainDriver; Handle: PISC_DB_HANDLE; DatabaseInfoCommand: Integer): LongInt; function GetStringDbInfo(PlainDriver: IZInterbasePlainDriver; Handle: PISC_DB_HANDLE; DatabaseInfoCommand: Integer): AnsiString; function GetDBSQLDialect(PlainDriver: IZInterbasePlainDriver; Handle: PISC_DB_HANDLE): Integer; { Interbase statement functions} function PrepareStatement(PlainDriver: IZInterbasePlainDriver; Handle: PISC_DB_HANDLE; TrHandle: PISC_TR_HANDLE; Dialect: Word; SQL: RawByteString; LogSQL: String; var StmtHandle: TISC_STMT_HANDLE): TZIbSqlStatementType; procedure PrepareResultSqlData(PlainDriver: IZInterbasePlainDriver; Handle: PISC_DB_HANDLE; Dialect: Word; LogSQL: string; var StmtHandle: TISC_STMT_HANDLE; SqlData: IZResultSQLDA); procedure PrepareParameters(PlainDriver: IZInterbasePlainDriver; LogSQL: string; Dialect: Word; var StmtHandle: TISC_STMT_HANDLE; ParamSqlData: IZParamsSQLDA); procedure BindSQLDAInParameters(PlainDriver: IZInterbasePlainDriver; InParamValues: TZVariantDynArray; InParamTypes: TZSQLTypeArray; InParamCount: Integer; ParamSqlData: IZParamsSQLDA; ConSettings: PZConSettings); procedure FreeStatement(PlainDriver: IZInterbasePlainDriver; StatementHandle: TISC_STMT_HANDLE; Options : Word); function GetStatementType(PlainDriver: IZInterbasePlainDriver; StmtHandle: TISC_STMT_HANDLE): TZIbSqlStatementType; function GetAffectedRows(PlainDriver: IZInterbasePlainDriver; StmtHandle: TISC_STMT_HANDLE; StatementType: TZIbSqlStatementType): integer; function ConvertInterbase6ToSqlType(SqlType, SqlSubType: Integer; const CtrlsCPType: TZControlsCodePage): TZSqlType; { interbase blob routines } procedure GetBlobInfo(PlainDriver: IZInterbasePlainDriver; BlobHandle: TISC_BLOB_HANDLE; var BlobInfo: TIbBlobInfo); procedure ReadBlobBufer(PlainDriver: IZInterbasePlainDriver; Handle: PISC_DB_HANDLE; TransactionHandle: PISC_TR_HANDLE; BlobId: TISC_QUAD; var Size: Integer; var Buffer: Pointer); function GetIBScaleDivisor(Scale: SmallInt): Int64; const { Default Interbase blob size for readig } DefaultBlobSegmentSize = 16 * 1024; IBScaleDivisor: array[-15..-1] of Int64 = (1000000000000000,100000000000000, 10000000000000,1000000000000,100000000000,10000000000,1000000000,100000000, 10000000,1000000,100000,10000,1000,100,10); { count database parameters } MAX_DPB_PARAMS = 67; { prefix database parameters names it used in paramters scann procedure } BPBPrefix = 'isc_dpb_'; { list database parameters and their apropriate numbers } DatabaseParams: array [0..MAX_DPB_PARAMS]of TZIbParam = ( (Name:'isc_dpb_version1'; Number: isc_dpb_version1), (Name:'isc_dpb_cdd_pathname'; Number: isc_dpb_cdd_pathname), (Name:'isc_dpb_allocation'; Number: isc_dpb_allocation), (Name:'isc_dpb_journal'; Number: isc_dpb_journal), (Name:'isc_dpb_page_size'; Number: isc_dpb_page_size), (Name:'isc_dpb_num_buffers'; Number: isc_dpb_num_buffers), (Name:'isc_dpb_buffer_length'; Number: isc_dpb_buffer_length), (Name:'isc_dpb_debug'; Number: isc_dpb_debug), (Name:'isc_dpb_garbage_collect'; Number: isc_dpb_garbage_collect), (Name:'isc_dpb_verify'; Number: isc_dpb_verify), (Name:'isc_dpb_sweep'; Number: isc_dpb_sweep), (Name:'isc_dpb_enable_journal'; Number: isc_dpb_enable_journal), (Name:'isc_dpb_disable_journal'; Number: isc_dpb_disable_journal), (Name:'isc_dpb_dbkey_scope'; Number: isc_dpb_dbkey_scope), (Name:'isc_dpb_number_of_users'; Number: isc_dpb_number_of_users), (Name:'isc_dpb_trace'; Number: isc_dpb_trace), (Name:'isc_dpb_no_garbage_collect'; Number: isc_dpb_no_garbage_collect), (Name:'isc_dpb_damaged'; Number: isc_dpb_damaged), (Name:'isc_dpb_license'; Number: isc_dpb_license), (Name:'isc_dpb_sys_user_name'; Number: isc_dpb_sys_user_name), (Name:'isc_dpb_encrypt_key'; Number: isc_dpb_encrypt_key), (Name:'isc_dpb_activate_shadow'; Number: isc_dpb_activate_shadow), (Name:'isc_dpb_sweep_interval'; Number: isc_dpb_sweep_interval), (Name:'isc_dpb_delete_shadow'; Number: isc_dpb_delete_shadow), (Name:'isc_dpb_force_write'; Number: isc_dpb_force_write), (Name:'isc_dpb_begin_log'; Number: isc_dpb_begin_log), (Name:'isc_dpb_quit_log'; Number: isc_dpb_quit_log), (Name:'isc_dpb_no_reserve'; Number: isc_dpb_no_reserve), (Name:'isc_dpb_username'; Number: isc_dpb_user_name), (Name:'isc_dpb_password'; Number: isc_dpb_password), (Name:'isc_dpb_password_enc'; Number: isc_dpb_password_enc), (Name:'isc_dpb_sys_user_name_enc'; Number: isc_dpb_sys_user_name_enc), (Name:'isc_dpb_interp'; Number: isc_dpb_interp), (Name:'isc_dpb_online_dump'; Number: isc_dpb_online_dump), (Name:'isc_dpb_old_file_size'; Number: isc_dpb_old_file_size), (Name:'isc_dpb_old_num_files'; Number: isc_dpb_old_num_files), (Name:'isc_dpb_old_file'; Number: isc_dpb_old_file), (Name:'isc_dpb_old_start_page'; Number: isc_dpb_old_start_page), (Name:'isc_dpb_old_start_seqno'; Number: isc_dpb_old_start_seqno), (Name:'isc_dpb_old_start_file'; Number: isc_dpb_old_start_file), (Name:'isc_dpb_drop_walfile'; Number: isc_dpb_drop_walfile), (Name:'isc_dpb_old_dump_id'; Number: isc_dpb_old_dump_id), (Name:'isc_dpb_wal_backup_dir'; Number: isc_dpb_wal_backup_dir), (Name:'isc_dpb_wal_chkptlen'; Number: isc_dpb_wal_chkptlen), (Name:'isc_dpb_wal_numbufs'; Number: isc_dpb_wal_numbufs), (Name:'isc_dpb_wal_bufsize'; Number: isc_dpb_wal_bufsize), (Name:'isc_dpb_wal_grp_cmt_wait'; Number: isc_dpb_wal_grp_cmt_wait), (Name:'isc_dpb_lc_messages'; Number: isc_dpb_lc_messages), (Name:'isc_dpb_lc_ctype'; Number: isc_dpb_lc_ctype), (Name:'isc_dpb_cache_manager'; Number: isc_dpb_cache_manager), (Name:'isc_dpb_shutdown'; Number: isc_dpb_shutdown), (Name:'isc_dpb_online'; Number: isc_dpb_online), (Name:'isc_dpb_shutdown_delay'; Number: isc_dpb_shutdown_delay), (Name:'isc_dpb_reserved'; Number: isc_dpb_reserved), (Name:'isc_dpb_overwrite'; Number: isc_dpb_overwrite), (Name:'isc_dpb_sec_attach'; Number: isc_dpb_sec_attach), (Name:'isc_dpb_disable_wal'; Number: isc_dpb_disable_wal), (Name:'isc_dpb_connect_timeout'; Number: isc_dpb_connect_timeout), (Name:'isc_dpb_dummy_packet_interval'; Number: isc_dpb_dummy_packet_interval), (Name:'isc_dpb_gbak_attach'; Number: isc_dpb_gbak_attach), (Name:'isc_dpb_sql_role_name'; Number: isc_dpb_sql_role_name), (Name:'isc_dpb_set_page_buffers'; Number: isc_dpb_set_page_buffers), (Name:'isc_dpb_working_directory'; Number: isc_dpb_working_directory), (Name:'isc_dpb_sql_dialect'; Number: isc_dpb_SQL_dialect), (Name:'isc_dpb_set_db_readonly'; Number: isc_dpb_set_db_readonly), (Name:'isc_dpb_set_db_sql_dialect'; Number: isc_dpb_set_db_SQL_dialect), (Name:'isc_dpb_gfix_attach'; Number: isc_dpb_gfix_attach), (Name:'isc_dpb_gstat_attach'; Number: isc_dpb_gstat_attach) ); { count transaction parameters } MAX_TPB_PARAMS = 16; { prefix transaction parameters names it used in paramters scann procedure } TPBPrefix = 'isc_tpb_'; { list transaction parameters and their apropriate numbers } TransactionParams: array [0..MAX_TPB_PARAMS]of TZIbParam = ( (Name:'isc_tpb_version1'; Number: isc_tpb_version1), (Name:'isc_tpb_version3'; Number: isc_tpb_version3), (Name:'isc_tpb_consistency'; Number: isc_tpb_consistency), (Name:'isc_tpb_concurrency'; Number: isc_tpb_concurrency), (Name:'isc_tpb_exclusive'; Number: isc_tpb_exclusive), (Name:'isc_tpb_shared'; Number: isc_tpb_shared), (Name:'isc_tpb_protected'; Number: isc_tpb_protected), (Name:'isc_tpb_wait'; Number: isc_tpb_wait), (Name:'isc_tpb_nowait'; Number: isc_tpb_nowait), (Name:'isc_tpb_read'; Number: isc_tpb_read), (Name:'isc_tpb_write'; Number: isc_tpb_write), (Name:'isc_tpb_ignore_limbo'; Number: isc_tpb_ignore_limbo), (Name:'isc_tpb_read_committed'; Number: isc_tpb_read_committed), (Name:'isc_tpb_rec_version'; Number: isc_tpb_rec_version), (Name:'isc_tpb_no_rec_version'; Number: isc_tpb_no_rec_version), (Name:'isc_tpb_lock_read'; Number: isc_tpb_lock_read), (Name:'isc_tpb_lock_write'; Number: isc_tpb_lock_write) ); implementation uses Variants, ZSysUtils, Math, ZDbcInterbase6, ZEncoding {$IFDEF WITH_UNITANSISTRINGS}, AnsiStrings{$ENDIF}; {** Generate specific length random string and return it @param Len a length result string @return random string } function RandomString(Len: integer): AnsiString; begin Result := ''; while Length(Result) < Len do Result := Result + AnsiString(IntToStr(Trunc(Random(High(Integer))))); if Length(Result) > Len then Result := Copy(Result, 1, Len); end; {** Create CachedResultSet with using TZCachedResultSet and return it. @param SQL a sql query command @param Statement a zeos statement object @param NativeResultSet a native result set @return cached ResultSet } function CreateIBResultSet(SQL: string; Statement: IZStatement; NativeResultSet: IZResultSet): IZResultSet; var CachedResolver: TZInterbase6CachedResolver; CachedResultSet: TZCachedResultSet; begin if (Statement.GetResultSetConcurrency <> rcReadOnly) or (Statement.GetResultSetType <> rtForwardOnly) then begin CachedResolver := TZInterbase6CachedResolver.Create(Statement, NativeResultSet.GetMetadata); CachedResultSet := TZCachedResultSet.Create(NativeResultSet, SQL, CachedResolver, Statement.GetConnection.GetConSettings); CachedResultSet.SetConcurrency(Statement.GetResultSetConcurrency); Result := CachedResultSet; end else Result := NativeResultSet; end; {** Generate database connection string by connection information @param DPB - a database connection string @param Dialect - a sql dialect number @param Info - a list connection interbase parameters @return a generated string length } function GenerateDPB(Info: TStrings; var FDPBLength, Dialect: Word): PAnsiChar; var I, Pos, PValue: Integer; ParamNo: Word; Buffer: String; DPB, ParamName, ParamValue: AnsiString; begin FDPBLength := 1; DPB := AnsiChar(isc_dpb_version1); for I := 0 to Info.Count - 1 do begin Buffer := Info.Strings[I]; Pos := FirstDelimiter(' ='#9#10#13, Buffer); ParamName := AnsiString(Copy(Buffer, 1, Pos - 1)); Delete(Buffer, 1, Pos); ParamValue := AnsiString(Buffer); ParamNo := GetInterbase6DatabaseParamNumber(ParamName); case ParamNo of 0: Continue; isc_dpb_set_db_SQL_dialect: Dialect := StrToIntDef(String(ParamValue), 0); isc_dpb_user_name, isc_dpb_password, isc_dpb_password_enc, isc_dpb_sys_user_name, isc_dpb_license, isc_dpb_encrypt_key, isc_dpb_lc_messages, isc_dpb_lc_ctype, isc_dpb_sql_role_name, isc_dpb_connect_timeout: begin DPB := DPB + AnsiChar(ParamNo) + AnsiChar(Length(ParamValue)) + ParamValue; Inc(FDPBLength, 2 + Length(ParamValue)); end; isc_dpb_num_buffers, isc_dpb_dbkey_scope, isc_dpb_force_write, isc_dpb_no_reserve, isc_dpb_damaged, isc_dpb_verify: begin DPB := DPB + AnsiChar(ParamNo) + #1 + AnsiChar(StrToInt(String(ParamValue))); Inc(FDPBLength, 3); end; isc_dpb_sweep: begin DPB := DPB + AnsiChar(ParamNo) + #1 + AnsiChar(isc_dpb_records); Inc(FDPBLength, 3); end; isc_dpb_sweep_interval: begin PValue := StrToInt(String(ParamValue)); DPB := DPB + AnsiChar(ParamNo) + #4 + PAnsiChar(@PValue)[0] + PAnsiChar(@PValue)[1] + PAnsiChar(@PValue)[2] + PAnsiChar(@PValue)[3]; Inc(FDPBLength, 6); end; isc_dpb_activate_shadow, isc_dpb_delete_shadow, isc_dpb_begin_log, isc_dpb_quit_log: begin DPB := DPB + AnsiChar(ParamNo) + #1 + #0; Inc(FDPBLength, 3); end; end; end; {$IFDEF UNICODE} Result := AnsiStrAlloc(FDPBLength + 1); {$ELSE} Result := StrAlloc(FDPBLength + 1); {$ENDIF} {$IFDEF WITH_STRPCOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrPCopy(Result, DPB); end; {** Generate transaction structuer by connection information @param Params - a transaction parameters list @param Dialect - a database connection handle @return a transaction ISC structure } function GenerateTPB(Params: TStrings; var Handle: TISC_DB_HANDLE): PISC_TEB; var I: Integer; TPBLength,ParamNo: Word; TempStr, ParamValue: AnsiString; TPB: PAnsiChar; IsolationLevel: Boolean; begin TPBLength := 0; TempStr := ''; IsolationLevel := False; { Prepare transaction parameters string } for I := 0 to Params.Count - 1 do begin ParamValue := AnsiString(Params.Strings[I]); ParamNo := GetInterbase6TransactionParamNumber(ParamValue); case ParamNo of 0: Continue; isc_tpb_lock_read, isc_tpb_lock_write: begin TempStr := TempStr + AnsiChar(ParamNo) + AnsiChar(Length(ParamValue)) + ParamValue; Inc(TPBLength, Length(ParamValue) + 2); end; else begin TempStr := TempStr + AnsiChar(ParamNo); Inc(TPBLength, 1); end; end; { Check what was set use transaction isolation level } if not IsolationLevel then case ParamNo of isc_tpb_concurrency, isc_tpb_consistency, isc_tpb_read_committed: IsolationLevel := True else IsolationLevel := False; end; end; { Allocate transaction parameters PAnsiChar buffer if temporally parameters string is empty the set null pointer for default database transaction} if (TPBLength > 0) and (IsolationLevel) then begin {$IFDEF UNICODE} TPB := AnsiStrAlloc(TPBLength + 1); {$ELSE} TPB := StrAlloc(TPBLength + 1); {$ENDIF} TPB := {$IFDEF WITH_STRPCOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrPCopy(TPB, TempStr); end else TPB := nil; { Allocate transaction structure } Result := AllocMem(SizeOf(TISC_TEB)); with Result^ do begin db_handle := @Handle; tpb_length := TPBLength; tpb_address := TPB; end; end; {** Return interbase connection parameter number by it name @param Value - a connection parameter name @return - connection parameter number } function GetInterbase6DatabaseParamNumber(const Value: AnsiString): Word; var I: Integer; ParamName: AnsiString; begin ParamName := {$IFDEF WITH_UNITANSISTRINGS}AnsiStrings.{$ENDIF}AnsiLowerCase(Value); Result := 0; if System.Pos(BPBPrefix, String(ParamName)) = 1 then for I := 1 to MAX_DPB_PARAMS do begin if ParamName = DatabaseParams[I].Name then begin Result := DatabaseParams[I].Number; Break; end; end; end; {** Return interbase transaction parameter number by it name @param Value - a transaction parameter name @return - transaction parameter number } function GetInterbase6TransactionParamNumber(const Value: AnsiString): Word; var I: Integer; ParamName: AnsiString; begin ParamName := {$IFDEF WITH_UNITANSISTRINGS}AnsiStrings.{$ENDIF}AnsiLowerCase(Value); Result := 0; if System.Pos(TPBPrefix, String(ParamName)) = 1 then for I := 1 to MAX_TPB_PARAMS do begin if ParamName = TransactionParams[I].Name then begin Result := TransactionParams[I].Number; Break; end; end; end; {** Converts a Interbase6 native types into ZDBC SQL types. @param the interbase type @param the interbase subtype @return a SQL undepended type. Note: The interbase type and subtype get from RDB$TYPES table } function ConvertInterbase6ToSqlType(SqlType, SqlSubType: Integer; const CtrlsCPType: TZControlsCodePage): TZSQLType; begin Result := ZDbcIntfs.stUnknown; case SqlType of blr_bool, blr_not_nullable: Result := stBoolean; blr_varying2, blr_varying, blr_cstring, blr_cstring2, blr_domain_name, blr_domain_name2, blr_column_name, blr_column_name2: Result := stString; blr_text, blr_text2: case SqlSubType of CS_BINARY: Result := stBytes; else Result := stString; end; blr_d_float: Result := stDouble; blr_float: Result := stFloat; blr_double: Result := stDouble; blr_blob_id, blr_quad: Result := stLong; blr_int64: case SqlSubType of RDB_NUMBERS_NONE: Result := stLong; RDB_NUMBERS_NUMERIC: Result := stDouble; RDB_NUMBERS_DECIMAL: Result := stBigDecimal; end; blr_long: begin case SqlSubType of RDB_NUMBERS_NONE: Result := stInteger; RDB_NUMBERS_NUMERIC: Result := stDouble; RDB_NUMBERS_DECIMAL: Result := stBigDecimal; end; end; blr_short: begin case SqlSubType of RDB_NUMBERS_NONE: Result := stShort; RDB_NUMBERS_NUMERIC: Result := stDouble; RDB_NUMBERS_DECIMAL: Result := stDouble; end; end; blr_sql_date: Result := stDate; blr_sql_time: Result := stTime; blr_timestamp: Result := stTimestamp; blr_blob, blr_blob2: begin case SqlSubType of { Blob Subtypes } { types less than zero are reserved for customer use } isc_blob_untyped: Result := stBinaryStream; { internal subtypes } isc_blob_text: Result := stAsciiStream; isc_blob_blr: Result := stBinaryStream; isc_blob_acl: Result := stAsciiStream; isc_blob_ranges: Result := stBinaryStream; isc_blob_summary: Result := stBinaryStream; isc_blob_format: Result := stAsciiStream; isc_blob_tra: Result := stAsciiStream; isc_blob_extfile: Result := stAsciiStream; isc_blob_debug_info: Result := stBinaryStream; end; end; else Result := ZDbcIntfs.stUnknown; end; if ( CtrlsCPType = cCP_UTF16) then case result of stString: Result := stUnicodeString; stAsciiStream: Result := stUnicodeStream; end; end; {** Return Interbase SqlType by it number @param Value the SqlType number } function GetNameSqlType(Value: Word): AnsiString; begin case Value of SQL_VARYING: Result := 'SQL_VARYING'; SQL_TEXT: Result := 'SQL_TEXT'; SQL_DOUBLE: Result := 'SQL_DOUBLE'; SQL_FLOAT: Result := 'SQL_FLOAT'; SQL_LONG: Result := 'SQL_LONG'; SQL_SHORT: Result := 'SQL_SHORT'; SQL_TIMESTAMP: Result := 'SQL_TIMESTAMP'; SQL_BLOB: Result := 'SQL_BLOB'; SQL_D_FLOAT: Result := 'SQL_D_FLOAT'; SQL_ARRAY: Result := 'SQL_ARRAY'; SQL_QUAD: Result := 'SQL_QUAD'; SQL_TYPE_TIME: Result := 'SQL_TYPE_TIME'; SQL_TYPE_DATE: Result := 'SQL_TYPE_DATE'; SQL_INT64: Result := 'SQL_INT64'; SQL_BOOLEAN: Result := 'SQL_BOOLEAN'; else Result := 'Unknown'; end end; {** Checks for possible sql errors. @param PlainDriver a Interbase Plain drver @param StatusVector a status vector. It contain information about error @param Sql a sql query commend @Param Integer Return is the ErrorCode that happened - for disconnecting the database } function CheckInterbase6Error(PlainDriver: IZInterbasePlainDriver; StatusVector: TARRAY_ISC_STATUS; LoggingCategory: TZLoggingCategory = lcOther; SQL: string = '') : Integer; var Msg: array[0..1024] of AnsiChar; PStatusVector: PISC_STATUS; ErrorMessage, ErrorSqlMessage: string; ErrorCode: LongInt; begin Result := 0; if (StatusVector[0] = 1) and (StatusVector[1] > 0) then begin ErrorMessage := ''; PStatusVector := @StatusVector; while PlainDriver.isc_interprete(Msg, @PStatusVector) > 0 do ErrorMessage := ErrorMessage + ' ' + String(Msg); ErrorCode := PlainDriver.isc_sqlcode(@StatusVector); PlainDriver.isc_sql_interprete(ErrorCode, Msg, 1024); ErrorSqlMessage := String(Msg); {$IFDEF INTERBASE_EXTENDED_MESSAGES} if SQL <> '' then SQL := Format(' The SQL: %s; ', [SQL]); {$ENDIF} if ErrorMessage <> '' then begin DriverManager.LogError(LoggingCategory, PlainDriver.GetProtocol, ErrorMessage, ErrorCode, ErrorSqlMessage + SQL); //AVZ Ignore error codes for disconnected database -901, -902 if ((ErrorCode <> -901) and (ErrorCode <> -902)) then begin {$IFDEF INTERBASE_EXTENDED_MESSAGES} raise EZSQLException.CreateWithCode(ErrorCode, Format('SQL Error: %s. Error Code: %d. %s', [ErrorMessage, ErrorCode, ErrorSqlMessage]) + SQL); {$ELSE} raise EZSQLException.CreateWithCode(ErrorCode, Format('SQL Error: %s. Error Code: %d. %s', [ErrorMessage, ErrorCode, ErrorSqlMessage])); {$ENDIF} end else begin //AVZ -- Added exception back in to help error trapping raise EZSQLException.CreateWithCode(ErrorCode, Format('SQL Error: %s. Error Code: %d. %s', [ErrorMessage, ErrorCode, ErrorSqlMessage])); Result := DISCONNECT_ERROR; end; end; end; end; {** Prepare statement and create statement handle. @param PlainDriver a interbase plain driver @param Handle a interbase connection handle @param TrHandle a transaction handle @param Dialect a interbase sql dialect number @param Sql a sql query @param StmtHandle a statement handle @param SqlData a interbase sql result data @return sql statement type } function PrepareStatement(PlainDriver: IZInterbasePlainDriver; Handle: PISC_DB_HANDLE; TrHandle: PISC_TR_HANDLE; Dialect: Word; SQL: RawByteString; LogSQL: String; var StmtHandle: TISC_STMT_HANDLE): TZIbSqlStatementType; var StatusVector: TARRAY_ISC_STATUS; iError : Integer; //Error for disconnect begin { Allocate an sql statement } if StmtHandle = 0 then begin PlainDriver.isc_dsql_allocate_statement(@StatusVector, Handle, @StmtHandle); CheckInterbase6Error(PlainDriver, StatusVector, lcOther, LogSQL); end; { Prepare an sql statement } PlainDriver.isc_dsql_prepare(@StatusVector, TrHandle, @StmtHandle, 0, PAnsiChar(SQL), Dialect, nil); iError := CheckInterbase6Error(PlainDriver, StatusVector, lcPrepStmt, LogSQL); //Check for disconnect AVZ { Set Statement Type } if (iError <> DISCONNECT_ERROR) then //AVZ Result := GetStatementType(PlainDriver, StmtHandle) else Result := stDisconnect; if Result in [stUnknown, stGetSegment, stPutSegment, stStartTrans] then begin FreeStatement(PlainDriver, StmtHandle, DSQL_CLOSE); //AVZ raise EZSQLException.Create(SStatementIsNotAllowed); end; end; {** Describe SQLDA and allocate memory for result values. @param PlainDriver a interbase plain driver @param Handle a interbase connection handle @param Dialect a interbase sql dialect number @param Sql a sql query @param StmtHandle a statement handle @param SqlData a interbase sql result data } procedure PrepareResultSqlData(PlainDriver: IZInterbasePlainDriver; Handle: PISC_DB_HANDLE; Dialect: Word; LogSQL: string; var StmtHandle: TISC_STMT_HANDLE; SqlData: IZResultSQLDA); var StatusVector: TARRAY_ISC_STATUS; begin { Initialise ouput param and fields } PlainDriver.isc_dsql_describe(@StatusVector, @StmtHandle, Dialect, SqlData.GetData); CheckInterbase6Error(PlainDriver, StatusVector, lcExecute, LogSQL); if SqlData.GetData^.sqld > SqlData.GetData^.sqln then begin SqlData.AllocateSQLDA; PlainDriver.isc_dsql_describe(@StatusVector, @StmtHandle, Dialect, SqlData.GetData); CheckInterbase6Error(PlainDriver, StatusVector, lcExecute, LogSql); end; SqlData.InitFields(False); end; {** Return interbase statement type by statement handle @param PlainDriver a interbase plain driver @param StmtHandle a statement handle @return interbase statement type } function GetStatementType(PlainDriver: IZInterbasePlainDriver; StmtHandle: TISC_STMT_HANDLE): TZIbSqlStatementType; var TypeItem: AnsiChar; StatusVector: TARRAY_ISC_STATUS; StatementLength: integer; StatementBuffer: array[0..7] of AnsiChar; begin Result := stUnknown; TypeItem := AnsiChar(isc_info_sql_stmt_type); { Get information about a prepared DSQL statement. } PlainDriver.isc_dsql_sql_info(@StatusVector, @StmtHandle, 1, @TypeItem, SizeOf(StatementBuffer), StatementBuffer); CheckInterbase6Error(PlainDriver, StatusVector); if StatementBuffer[0] = AnsiChar(isc_info_sql_stmt_type) then begin StatementLength := PlainDriver.isc_vax_integer( @StatementBuffer[1], 2); Result := TZIbSqlStatementType(PlainDriver.isc_vax_integer( @StatementBuffer[3], StatementLength)); end; end; {** Free interbse allocated statement and SQLDA for input and utput parameters @param the interbase plain driver @param the interbse statement handle } procedure FreeStatement(PlainDriver: IZInterbasePlainDriver; StatementHandle: TISC_STMT_HANDLE; Options: Word); var StatusVector: TARRAY_ISC_STATUS; begin if StatementHandle <> 0 then PlainDriver.isc_dsql_free_statement(@StatusVector, @StatementHandle, Options); //CheckInterbase6Error(PlainDriver, StatusVector); //raises an unwanted exception if Connection was reopened See: http://sourceforge.net/p/zeoslib/tickets/40/ end; {** Get affected rows. Note: it function may call after statement execution @param PlainDriver a interbase plain driver @param StmtHandle a statement handle @param StatementType a statement type @return affected rows } function GetAffectedRows(PlainDriver: IZInterbasePlainDriver; StmtHandle: TISC_STMT_HANDLE; StatementType: TZIbSqlStatementType): Integer; var ReqInfo: AnsiChar; OutBuffer: array[0..255] of AnsiChar; StatusVector: TARRAY_ISC_STATUS; begin Result := -1; ReqInfo := AnsiChar(isc_info_sql_records); if PlainDriver.isc_dsql_sql_info(@StatusVector, @StmtHandle, 1, @ReqInfo, SizeOf(OutBuffer), OutBuffer) > 0 then Exit; CheckInterbase6Error(PlainDriver, StatusVector); if OutBuffer[0] = AnsiChar(isc_info_sql_records) then begin case StatementType of stUpdate: Result := PlainDriver.isc_vax_integer(@OutBuffer[6], 4); stDelete: Result := PlainDriver.isc_vax_integer(@OutBuffer[13], 4); stSelect: Result := PlainDriver.isc_vax_integer(@OutBuffer[20], 4); stInsert: Result := PlainDriver.isc_vax_integer(@OutBuffer[27], 4); else Result := -1; end; end; end; {** Prepare sql statement parameters and fill parameters by values @param PlainDriver a interbase plain driver @param Dialect a interbase sql dialect number @param StmtHandle a statement handle @param SqlData a interbase sql result data } procedure PrepareParameters(PlainDriver: IZInterbasePlainDriver; LogSQL: string; Dialect: Word; var StmtHandle: TISC_STMT_HANDLE; ParamSqlData: IZParamsSQLDA); var StatusVector: TARRAY_ISC_STATUS; begin {check dynamic sql} PlainDriver.isc_dsql_describe_bind(@StatusVector, @StmtHandle, Dialect, ParamSqlData.GetData); CheckInterbase6Error(PlainDriver, StatusVector, lcExecute, LogSQL); { Resize XSQLDA structure if needed } if ParamSqlData.GetData^.sqld > ParamSqlData.GetData^.sqln then begin ParamSqlData.AllocateSQLDA; PlainDriver.isc_dsql_describe_bind(@StatusVector, @StmtHandle, Dialect, ParamSqlData.GetData); CheckInterbase6Error(PlainDriver, StatusVector, lcExecute, LogSQL); end; ParamSqlData.InitFields(True); end; procedure BindSQLDAInParameters(PlainDriver: IZInterbasePlainDriver; InParamValues: TZVariantDynArray; InParamTypes: TZSQLTypeArray; InParamCount: Integer; ParamSqlData: IZParamsSQLDA; ConSettings: PZConSettings); var I: Integer; TempBlob: IZBlob; TempStream: TStream; begin if InParamCount <> ParamSqlData.GetFieldCount then raise EZSQLException.Create(SInvalidInputParameterCount); {$R-} for I := 0 to ParamSqlData.GetFieldCount - 1 do begin ParamSqlData.UpdateNull(I, DefVarManager.IsNull(InParamValues[I])); if DefVarManager.IsNull(InParamValues[I])then Continue else case InParamTypes[I] of stBoolean: ParamSqlData.UpdateBoolean(I, SoftVarManager.GetAsBoolean(InParamValues[I])); stByte: ParamSqlData.UpdateByte(I, SoftVarManager.GetAsInteger(InParamValues[I])); stShort: ParamSqlData.UpdateShort(I, SoftVarManager.GetAsInteger(InParamValues[I])); stInteger: ParamSqlData.UpdateInt(I, SoftVarManager.GetAsInteger(InParamValues[I])); stLong: ParamSqlData.UpdateLong(I, SoftVarManager.GetAsInteger(InParamValues[I])); stFloat: ParamSqlData.UpdateFloat(I, SoftVarManager.GetAsFloat(InParamValues[I])); stDouble: ParamSqlData.UpdateDouble(I, SoftVarManager.GetAsFloat(InParamValues[I])); stBigDecimal: ParamSqlData.UpdateBigDecimal(I, SoftVarManager.GetAsFloat(InParamValues[I])); stString: if ( ConSettings.ClientCodePage.ID = CS_NONE ) and not (ParamSqlData.GetIbSqlSubType(I) = CS_NONE) then //CharSet 'NONE' writes data 'as is'! ParamSqlData.UpdateString(I, PlainDriver.ZPlainString(SoftVarManager.GetAsString(InParamValues[I]), ConSettings, PlainDriver.ValidateCharEncoding(ParamSqlData.GetIbSqlSubType(I)).CP)) else ParamSqlData.UpdateString(I, PlainDriver.ZPlainString(SoftVarManager.GetAsString(InParamValues[I]), ConSettings)); stUnicodeString: if ( ConSettings.ClientCodePage.ID = CS_NONE ) and not (ParamSqlData.GetIbSqlSubType(I) = CS_NONE) then //CharSet 'NONE' writes data 'as is'! ParamSqlData.UpdateString(I, PlainDriver.ZPlainString(SoftVarManager.GetAsUnicodeString(InParamValues[I]), ConSettings, PlainDriver.ValidateCharEncoding(ParamSqlData.GetIbSqlSubType(I)).CP)) else ParamSqlData.UpdateString(I, PlainDriver.ZPlainString(SoftVarManager.GetAsUnicodeString(InParamValues[I]), ConSettings)); stBytes: ParamSqlData.UpdateBytes(I, SoftVarManager.GetAsBytes(InParamValues[I])); stDate: ParamSqlData.UpdateDate(I, SoftVarManager.GetAsDateTime(InParamValues[I])); stTime: ParamSqlData.UpdateTime(I, SoftVarManager.GetAsDateTime(InParamValues[I])); stTimestamp: ParamSqlData.UpdateTimestamp(I, SoftVarManager.GetAsDateTime(InParamValues[I])); stAsciiStream, stUnicodeStream, stBinaryStream: begin TempBlob := DefVarManager.GetAsInterface(InParamValues[I]) as IZBlob; if not TempBlob.IsEmpty then begin if (ParamSqlData.GetFieldSqlType(i) in [stUnicodeStream, stAsciiStream] ) then TempStream := TStringStream.Create(GetValidatedAnsiStringFromBuffer(TempBlob.GetBuffer, TempBlob.Length, TempBlob.WasDecoded, ConSettings)) else TempStream := TempBlob.GetStream; if Assigned(TempStream) then begin ParamSqlData.WriteBlob(I, TempStream); TempStream.Free; end; end; end else raise EZIBConvertError.Create(SUnsupportedParameterType); end; end; {$IFOPT D+} {$ENDIF} end; {** Read blob information by it handle such as blob segment size, segments count, blob size and type. @param PlainDriver @param BlobInfo the blob information structure } procedure GetBlobInfo(PlainDriver: IZInterbasePlainDriver; BlobHandle: TISC_BLOB_HANDLE; var BlobInfo: TIbBlobInfo); var Items: array[0..3] of AnsiChar; Results: array[0..99] of AnsiChar; I, ItemLength: Integer; Item: Integer; StatusVector: TARRAY_ISC_STATUS; begin I := 0; Items[0] := AnsiChar(isc_info_blob_num_segments); Items[1] := AnsiChar(isc_info_blob_max_segment); Items[2] := AnsiChar(isc_info_blob_total_length); Items[3] := AnsiChar(isc_info_blob_type); if PlainDriver.isc_blob_info(@StatusVector, @BlobHandle, 4, @items[0], SizeOf(Results), @Results[0]) > 0 then CheckInterbase6Error(PlainDriver, StatusVector); while (I < SizeOf(Results)) and (Results[I] <> AnsiChar(isc_info_end)) do begin Item := Integer(Results[I]); Inc(I); ItemLength := PlainDriver.isc_vax_integer(@results[I], 2); Inc(I, 2); case Item of isc_info_blob_num_segments: BlobInfo.NumSegments := PlainDriver.isc_vax_integer(@Results[I], ItemLength); isc_info_blob_max_segment: BlobInfo.MaxSegmentSize := PlainDriver.isc_vax_integer(@Results[I], ItemLength); isc_info_blob_total_length: BlobInfo.TotalSize := PlainDriver.isc_vax_integer(@Results[I], ItemLength); isc_info_blob_type: BlobInfo.BlobType := PlainDriver.isc_vax_integer(@Results[I], ItemLength); end; Inc(i, ItemLength); end; end; {** Read blob field data to stream by it ISC_QUAD value Note: DefaultBlobSegmentSize constant used for limit segment size reading @param Handle the database connection handle @param TransactionHandle the transaction handle @param BlobId the ISC_QUAD structure @param Size the result buffer size @param Buffer the pointer to result buffer Note: Buffer must be nill. Function self allocate memory for data and return it size } procedure ReadBlobBufer(PlainDriver: IZInterbasePlainDriver; Handle: PISC_DB_HANDLE; TransactionHandle: PISC_TR_HANDLE; BlobId: TISC_QUAD; var Size: Integer; var Buffer: Pointer); var TempBuffer: PAnsiChar; BlobInfo: TIbBlobInfo; BlobSize, CurPos: LongInt; BytesRead, SegmentLenght: UShort; BlobHandle: TISC_BLOB_HANDLE; StatusVector: TARRAY_ISC_STATUS; begin BlobHandle := 0; CurPos := 0; // SegmentLenght := UShort(DefaultBlobSegmentSize); { open blob } PlainDriver.isc_open_blob2(@StatusVector, Handle, TransactionHandle, @BlobHandle, @BlobId, 0 , nil); CheckInterbase6Error(PlainDriver, StatusVector); { get blob info } GetBlobInfo(PlainDriver, BlobHandle, BlobInfo); BlobSize := BlobInfo.TotalSize; Size := BlobSize; SegmentLenght := BlobInfo.MaxSegmentSize; { Allocates a blob buffer } Buffer := AllocMem(BlobSize); TempBuffer := Buffer; { Copies data to blob buffer } while CurPos < BlobSize do begin if (CurPos + SegmentLenght > BlobSize) then SegmentLenght := BlobSize - CurPos; if not(PlainDriver.isc_get_segment(@StatusVector, @BlobHandle, @BytesRead, SegmentLenght, TempBuffer) = 0) or (StatusVector[1] <> isc_segment) then CheckInterbase6Error(PlainDriver, StatusVector); Inc(CurPos, BytesRead); Inc(TempBuffer, BytesRead); BytesRead := 0; end; { close blob handle } PlainDriver.isc_close_blob(@StatusVector, @BlobHandle); CheckInterbase6Error(PlainDriver, StatusVector); end; function GetIBScaleDivisor(Scale: SmallInt): Int64; var i: Integer; begin Result := 1; if Scale > 0 then for i := 1 to Scale do Result := Result * 10 else if Scale < 0 then for i := -1 downto Scale do Result := Result * 10; end; {** Return interbase server version string @param PlainDriver a interbase plain driver @param Handle the database connection handle @return interbase version string } function GetVersion(PlainDriver: IZInterbasePlainDriver; Handle: PISC_DB_HANDLE): AnsiString; var DatabaseInfoCommand: AnsiChar; StatusVector: TARRAY_ISC_STATUS; Buffer: array[0..IBBigLocalBufferLength - 1] of AnsiChar; begin DatabaseInfoCommand := AnsiChar(isc_info_version); PlainDriver.isc_database_info(@StatusVector, Handle, 1, @DatabaseInfoCommand, IBBigLocalBufferLength, Buffer); CheckInterbase6Error(PlainDriver, StatusVector); Buffer[5 + Integer(Buffer[4])] := #0; result := AnsiString(PAnsiChar(@Buffer[5])); end; {** Return interbase database implementation @param PlainDriver a interbase plain driver @param Handle the database connection handle @return interbase database implementation } function GetDBImplementationNo(PlainDriver: IZInterbasePlainDriver; Handle: PISC_DB_HANDLE): LongInt; var DatabaseInfoCommand: AnsiChar; StatusVector: TARRAY_ISC_STATUS; Buffer: array[0..IBBigLocalBufferLength - 1] of AnsiChar; begin DatabaseInfoCommand := AnsiChar(isc_info_implementation); PlainDriver.isc_database_info(@StatusVector, Handle, 1, @DatabaseInfoCommand, IBLocalBufferLength, Buffer); CheckInterbase6Error(PlainDriver, StatusVector); result := PlainDriver.isc_vax_integer(@Buffer[3], 1); end; {** Return interbase database implementation class @param PlainDriver a interbase plain driver @param Handle the database connection handle @return interbase database implementation class } function GetDBImplementationClass(PlainDriver: IZInterbasePlainDriver; Handle: PISC_DB_HANDLE): LongInt; var DatabaseInfoCommand: AnsiChar; StatusVector: TARRAY_ISC_STATUS; Buffer: array[0..IBBigLocalBufferLength - 1] of AnsiChar; begin DatabaseInfoCommand := AnsiChar(isc_info_implementation); PlainDriver.isc_database_info(@StatusVector, Handle, 1, @DatabaseInfoCommand, IBLocalBufferLength, Buffer); CheckInterbase6Error(PlainDriver, StatusVector); result := PlainDriver.isc_vax_integer(@Buffer[4], 1); end; {** Return interbase database info @param PlainDriver a interbase plain driver @param Handle the database connection handle @param DatabaseInfoCommand a database information command @return interbase database info } function GetLongDbInfo(PlainDriver: IZInterbasePlainDriver; Handle: PISC_DB_HANDLE; DatabaseInfoCommand: Integer): LongInt; var Length: Integer; DatabaseInfoCommand1: AnsiChar; StatusVector: TARRAY_ISC_STATUS; Buffer: array[0..IBBigLocalBufferLength - 1] of AnsiChar; begin DatabaseInfoCommand1 := AnsiChar(DatabaseInfoCommand); PlainDriver.isc_database_info(@StatusVector, Handle, 1, @DatabaseInfoCommand1, IBLocalBufferLength, Buffer); CheckInterbase6Error(PlainDriver, StatusVector); Length := PlainDriver.isc_vax_integer(@Buffer[1], 2); Result := PlainDriver.isc_vax_integer(@Buffer[4], Length); end; {** Return interbase database info string @param PlainDriver a interbase plain driver @param Handle a database connection handle @param DatabaseInfoCommand a database information command @return interbase database info string } function GetStringDbInfo(PlainDriver: IZInterbasePlainDriver; Handle: PISC_DB_HANDLE; DatabaseInfoCommand: Integer): AnsiString; var DatabaseInfoCommand1: AnsiChar; StatusVector: TARRAY_ISC_STATUS; Buffer: array[0..IBBigLocalBufferLength - 1] of AnsiChar; begin DatabaseInfoCommand1 := AnsiChar(DatabaseInfoCommand); PlainDriver.isc_database_info(@StatusVector, Handle, 1, @DatabaseInfoCommand1, IBLocalBufferLength, Buffer); CheckInterbase6Error(PlainDriver, StatusVector); Buffer[4 + Integer(Buffer[3])] := #0; Result := AnsiString(PAnsiChar(@Buffer[4])); end; {** Return interbase database dialect @param PlainDriver a interbase plain driver @param Handle the database connection handle @return interbase database dialect } function GetDBSQLDialect(PlainDriver: IZInterbasePlainDriver; Handle: PISC_DB_HANDLE): Integer; var Length: Integer; DatabaseInfoCommand1: AnsiChar; StatusVector: TARRAY_ISC_STATUS; Buffer: array[0..IBBigLocalBufferLength - 1] of AnsiChar; begin DatabaseInfoCommand1 := AnsiChar(isc_info_db_SQL_Dialect); PlainDriver.isc_database_info(@StatusVector, Handle, 1, @DatabaseInfoCommand1, IBLocalBufferLength, Buffer); CheckInterbase6Error(PlainDriver, StatusVector); if (Buffer[0] <> AnsiChar(isc_info_db_SQL_dialect)) then Result := 1 else begin Length := PlainDriver.isc_vax_integer(@Buffer[1], 2); Result := PlainDriver.isc_vax_integer(@Buffer[3], Length); end; end; { TSQLDA } constructor TZSQLDA.Create(PlainDriver: IZInterbasePlainDriver; Handle: PISC_DB_HANDLE; TransactionHandle: PISC_TR_HANDLE; ConSettings: PZConSettings); begin Self.ConSettings := ConSettings; FPlainDriver := PlainDriver; FHandle := Handle; FTransactionHandle := TransactionHandle; GetMem(FXSQLDA, XSQLDA_LENGTH(0)); FillChar(FXSQLDA^, XSQLDA_LENGTH(0), 0); FXSQLDA.sqln := 0; FXSQLDA.sqld := 0; FXSQLDA.version := SQLDA_VERSION1; end; {** Allocate memory for SQLVar in SQLDA structure for every fields by it length. } procedure TZSQLDA.InitFields(Parameters: boolean); var I: Integer; SqlVar: PXSQLVAR; begin {$R-} for I := 0 to FXSQLDA.sqld - 1 do begin SqlVar := @FXSQLDA.SqlVar[I]; case SqlVar.sqltype and (not 1) of SQL_BOOLEAN, SQL_TEXT, SQL_TYPE_DATE, SQL_TYPE_TIME, SQL_DATE, SQL_BLOB, SQL_ARRAY, SQL_QUAD, SQL_SHORT, SQL_LONG, SQL_INT64, SQL_DOUBLE, SQL_FLOAT, SQL_D_FLOAT: begin if SqlVar.sqllen = 0 then IbReAlloc(SqlVar.sqldata, 0, 1) else IbReAlloc(SqlVar.sqldata, 0, SqlVar.sqllen) end; SQL_VARYING: IbReAlloc(SqlVar.sqldata, 0, SqlVar.sqllen + 2) end; if Parameters = True then begin //This code used when allocated sqlind parameter for Param SQLDA SqlVar.sqltype := SqlVar.sqltype or 1; IbReAlloc(SqlVar.sqlind, 0, SizeOf(Short)) end else begin //This code used when allocated sqlind parameter for Result SQLDA if (SqlVar.sqltype and 1) <> 0 then ReallocMem(SqlVar.sqlind, SizeOf(Short)) else SqlVar.sqlind := nil; end; end; {$IFOPT D+} {$R+} {$ENDIF} end; {** Clear allocated data for SQLDA paramters } procedure TZSQLDA.FreeParamtersValues; var I: Integer; SqlVar: PXSQLVAR; begin {$R-} for I := 0 to FXSQLDA.sqln - 1 do begin SqlVar := @FXSQLDA.SqlVar[I]; FreeMem(SqlVar.sqldata); FreeMem(SqlVar.sqlind); SqlVar.sqldata := nil; SqlVar.sqlind := nil; end; {$IFOPT D+} {$R+} {$ENDIF} end; {** Chech reange count fields. If index out of range raised exception. @param Index the index field } procedure TZSQLDA.CheckRange(const Index: Word); begin Assert(Index < Word(FXSQLDA.sqln), 'Out of Range.'); end; {** Return alias name for field @param Index the index fields @return the alias name } function TZSQLDA.GetFieldAliasName(const Index: Word): String; begin CheckRange(Index); {$R-} SetString(Temp, FXSQLDA.sqlvar[Index].aliasname, FXSQLDA.sqlvar[Index].aliasname_length); Result := ZDbcString(Temp); {$IFOPT D+} {$R+} {$ENDIF} end; {** Return pointer to SQLDA structure } function TZSQLDA.GetData: PXSQLDA; begin result := FXSQLDA; end; {** Get fields count not allocated. @return fields count } function TZSQLDA.GetFieldCount: Integer; begin Result := FXSQLDA.sqld; end; {** Return field index by it name @param Index the index fields @return the index field } function TZSQLDA.GetFieldIndex(const Name: AnsiString): Word; begin {$R-} for Result := 0 to GetFieldCount - 1 do if FXSQLDA.sqlvar[Result].aliasname_length = Length(name) then if {$IFDEF WITH_STRLICOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrLIComp(@FXSQLDA.sqlvar[Result].aliasname, PAnsiChar(Name), FXSQLDA.sqlvar[Result].aliasname_length) = 0 then Exit; raise Exception.Create(Format(SFieldNotFound1, [name])); {$IFOPT D+} {$R+} {$ENDIF} end; {** Return field length @param Index the index fields @return the field lenth } function TZSQLDA.GetFieldLength(const Index: Word): SmallInt; begin {$R-} case GetIbSqlType(Index) of SQL_TEXT: Result := GetIbSqlLen(Index); SQL_VARYING: Result := GetIbSqlLen(Index); //SQL_VARYING: Result := FPlainDriver.isc_vax_integer(GetData.sqlvar[Index].sqldata, 2); //AVZ else Result := GetIbSqlLen(Index); end; {$IFOPT D+} {$R+} {$ENDIF} end; {** Return field scale @param Index the index fields @return the field scale } function TZSQLDA.GetFieldScale(const Index: Word): integer; begin CheckRange(Index); {$R-} Result := Abs(FXSQLDA.sqlvar[Index].sqlscale); {$IFOPT D+} {$R+} {$ENDIF} end; {** Convert Interbase sql type to SQLType @param Index the index fields @return the SQLType } function TZSQLDA.GetFieldSqlType(const Index: Word): TZSQLType; var SqlScale: Integer; SqlSubType: Integer; begin SqlScale := GetFieldScale(Index); SqlSubType := GetIbSqlSubType(Index); case GetIbSqlType(Index) of SQL_VARYING, SQL_TEXT: case SqlSubType of 1: {Octets} Result := stBytes; else Result := stString; end; SQL_LONG: begin if SqlScale = 0 then Result := stInteger else Result := stDouble; end; SQL_SHORT: begin if SqlScale = 0 then Result := stShort else Result := stFloat; //Numeric with low precision end; SQL_FLOAT: Result := stFloat; SQL_DOUBLE: Result := stDouble; SQL_DATE: Result := stTimestamp; SQL_TYPE_TIME: Result := stTime; SQL_TYPE_DATE: Result := stDate; SQL_INT64: begin if SqlScale = 0 then Result := stLong else if Abs(SqlScale) <= 4 then Result := stDouble else Result := stBigDecimal; end; SQL_QUAD, SQL_ARRAY, SQL_BLOB: begin if SqlSubType = isc_blob_text then Result := stAsciiStream else Result := stBinaryStream; end; //SQL_ARRAY: Result := stBytes; else Result := stString; end; if ( ConSettings.CPType = cCP_UTF16 ) then case result of stString: Result := stUnicodeString; stAsciiStream: Result := stUnicodeStream; end; end; {** Return own name for field @param Index the index fields @return the own name } function TZSQLDA.GetFieldOwnerName(const Index: Word): String; begin CheckRange(Index); {$R-} {$IFDEF WITH_RAWBYTESTRING} SetLength(Temp, FXSQLDA.sqlvar[Index].OwnName_length); System.Move(FXSQLDA.sqlvar[Index].OwnName, PAnsiChar(Temp)^, FXSQLDA.sqlvar[Index].OwnName_length); {$ELSE} SetString(Temp, FXSQLDA.sqlvar[Index].OwnName, FXSQLDA.sqlvar[Index].OwnName_length); {$ENDIF} Result := ZDbcString(Temp); {$IFOPT D+} {$R+} {$ENDIF} end; {** Return real name for field @param Index the index fields @return the real name } function TZSQLDA.GetFieldRelationName(const Index: Word): String; begin CheckRange(Index); {$R-} {$IFDEF WITH_RAWBYTESTRING} SetLength(Temp, FXSQLDA.sqlvar[Index].RelName_length); System.Move(FXSQLDA.sqlvar[Index].RelName, PAnsiChar(Temp)^, FXSQLDA.sqlvar[Index].RelName_length); {$ELSE} SetString(Temp, FXSQLDA.sqlvar[Index].RelName, FXSQLDA.sqlvar[Index].RelName_length); {$ENDIF} Result := ZDbcString(Temp); {$IFOPT D+} {$R+} {$ENDIF} end; {** Get Interbase sql fields lenth @param Index the index fields @return Interbase sql fields lenth } function TZSQLDA.GetIbSqlLen(const Index: Word): Smallint; begin CheckRange(Index); {$R-} result := FXSQLDA.sqlvar[Index].sqllen; {$IFOPT D+} {$R+} {$ENDIF} end; {** Return sql name for field @param Index the index fields @return the sql name } function TZSQLDA.GetFieldSqlName(const Index: Word): String; begin CheckRange(Index); {$R-} {$IFDEF WITH_RAWBYTESTRING} SetLength(Temp, FXSQLDA.sqlvar[Index].sqlname_length); System.Move(FXSQLDA.sqlvar[Index].sqlname, PAnsiChar(Temp)^, FXSQLDA.sqlvar[Index].sqlname_length); {$ELSE} SetString(Temp, FXSQLDA.sqlvar[Index].sqlname, FXSQLDA.sqlvar[Index].sqlname_length); {$ENDIF} Result := ZDbcString(Temp); {$IFOPT D+} {$R+} {$ENDIF} end; {** Get Interbase subsql type @param Index the index fields @return the Interbase subsql } function TZSQLDA.GetIbSqlSubType(const Index: Word): Smallint; begin CheckRange(Index); {$R-} result := FXSQLDA.sqlvar[Index].sqlsubtype; {$IFOPT D+} {$R+} {$ENDIF} end; {** Get Interbase sql type @param Index the index fields @return the interbase sql type } function TZSQLDA.GetIbSqlType(const Index: Word): Smallint; begin CheckRange(Index); {$R-} result := FXSQLDA.sqlvar[Index].sqltype and not (1); {$IFOPT D+} {$R+} {$ENDIF} end; {** Reallocate memory and fill memory by #0 @param pointer to memory block @param old size of memory block @param new size of memory block } procedure TZSQLDA.IbReAlloc(var P; OldSize, NewSize: Integer); begin ReallocMem(Pointer(P), NewSize); if NewSize > OldSize then Fillchar((PAnsiChar(P) + OldSize)^, NewSize - OldSize, #0); end; procedure TZSQLDA.SetFieldType(const Index: Word; Size: Integer; Code: Smallint; Scale: Smallint); begin CheckRange(Index); {$R-} with FXSQLDA.sqlvar[Index] do begin sqltype := Code; if Scale <= 0 then sqlscale := Scale; sqllen := Size; if (Size > 0) then IbReAlloc(sqldata, 0, Size) else begin FreeMem(sqldata); sqldata := nil; end; end; {$IFOPT D+} {$R+} {$ENDIF} end; {** Indicate blob field @param Index the index fields @return true if blob field overwise false } function TZSQLDA.IsBlob(const Index: Word): boolean; begin CheckRange(Index); {$R-} result := ((FXSQLDA.sqlvar[Index].sqltype and not(1)) = SQL_BLOB); {$IFOPT D+} {$R+} {$ENDIF} end; {** Indicate blob field @param Index the index fields @return true if field nullable overwise false } function TZSQLDA.IsNullable(const Index: Word): boolean; begin CheckRange(Index); {$R-} Result := FXSQLDA.sqlvar[Index].sqltype and 1 = 1 {$IFOPT D+} {$R+} {$ENDIF} end; {** Reallocate SQLDA to fields count length @param Value the count fields } procedure TZSQLDA.AllocateSQLDA; begin IbReAlloc(FXSQLDA, XSQLDA_LENGTH(FXSQLDA.sqln), XSQLDA_LENGTH(FXSQLDA.sqld)); FXSQLDA.sqln := FXSQLDA.sqld; end; { TParamsSQLDA } {** Free allocated memory and free object } destructor TZParamsSQLDA.Destroy; begin FreeParamtersValues; FreeMem(FXSQLDA); inherited Destroy; end; {** Encode pascal string to Interbase paramter buffer @param Code the Interbase data type @param Index the index target filed @param Str the source string } procedure TZParamsSQLDA.EncodeString(Code: Smallint; const Index: Word; const Str: RawByteString); var Len: Cardinal; begin Len := Length(Str); {$R-} with FXSQLDA.sqlvar[Index] do case Code of SQL_TEXT : begin if (sqllen = 0) and (Str <> '') then //Manits: #0000249/pktfag GetMem(sqldata, Len) else IbReAlloc(sqldata, 0, Len + 1); sqllen := Len; Move(PAnsiChar(Str)^, sqldata^, sqllen); end; SQL_VARYING : begin sqllen := Len + 2; if sqllen = 0 then //Egonhugeist: Todo: Need test case. Can't believe this line is correct! sqllen is min 2 GetMem(sqldata, Len + 2) else IbReAlloc(sqldata, 0, Len + 2); PISC_VARYING(sqldata).strlen := Len; Move(PAnsiChar(Str)^, PISC_VARYING(sqldata).str, PISC_VARYING(sqldata).strlen); end; end; {$IFOPT D+} {$R+} {$ENDIF} end; {** Encode Bytes dynamic array to Interbase paramter buffer @param Code the Interbase data type @param Index the index target filed @param Value the source array } procedure TZParamsSQLDA.EncodeBytes(Code: Smallint; const Index: Word; const Value: TByteDynArray); var Len: Cardinal; begin Len := Length(Value); {$R-} with FXSQLDA.sqlvar[Index] do case Code of SQL_TEXT : begin if (sqllen = 0) and ( Len <> 0 ) then //Manits: #0000249/pktfag GetMem(sqldata, Len) else IbReAlloc(sqldata, 0, Len + 1); sqllen := Len; Move(Pointer(Value)^, sqldata^, sqllen); end; SQL_VARYING : begin sqllen := Len + 2; if sqllen = 0 then //Egonhugeist: Todo: Need test case. Can't believe this line is correct! sqllen is min 2 GetMem(sqldata, Len + 2) else IbReAlloc(sqldata, 0, Len + 2); PISC_VARYING(sqldata).strlen := Len; Move(Pointer(Value)^, PISC_VARYING(sqldata).str, PISC_VARYING(sqldata).strlen); end; end; {$IFOPT D+} {$R+} {$ENDIF} end; {** Set up parameter BigDecimal value @param Index the target parameter index @param Value the source value } procedure TZParamsSQLDA.UpdateBigDecimal(const Index: Integer; Value: Extended); var SQLCode: SmallInt; begin CheckRange(Index); {$R-} with FXSQLDA.sqlvar[Index] do begin if (sqlind <> nil) and (sqlind^ = -1) then Exit; SQLCode := (sqltype and not(1)); if (sqlscale < 0) then begin //http://code.google.com/p/fbclient/wiki/DatatypeMapping case SQLCode of SQL_SHORT : PSmallInt(sqldata)^ := Trunc(Value * IBScaleDivisor[sqlscale]); SQL_LONG : PInteger(sqldata)^ := Trunc(Value * IBScaleDivisor[sqlscale]); SQL_INT64, SQL_QUAD : //PInt64(sqldata)^ := Trunc(Value * GetIBScaleDivisor(sqlscale)); EgonHugeist: Trunc seems to have rounding issues! //remain issues if decimal digits > scale than we've school learned rounding success randomly only //each aproach did fail: RoundTo(Value, sqlscale*-1), Round etc. //so the developer has to take PInt64(sqldata)^ := StrToInt64(FloatToStrF(RoundTo(Value, sqlscale) * GetIBScaleDivisor(sqlscale), ffFixed, 18, 0)); SQL_DOUBLE : PDouble(sqldata)^ := Value; //I have tested with Query.ParamByName ().AsCurrency to check this, problem does not lie with straight SQL else raise EZIBConvertError.Create(SUnsupportedDataType); end; end else case SQLCode of SQL_DOUBLE : PDouble(sqldata)^ := Value; SQL_LONG : PInteger(sqldata)^ := Trunc(Value); SQL_D_FLOAT, SQL_FLOAT : PSingle(sqldata)^ := Value; SQL_BOOLEAN : PSmallint(sqldata)^ := Trunc(Value); SQL_SHORT : PSmallint(sqldata)^ := Trunc(Value); SQL_INT64 : PInt64(sqldata)^ := Trunc(Value); SQL_TEXT : EncodeString(SQL_TEXT, Index, AnsiString(FloatToStr(Value))); SQL_VARYING : EncodeString(SQL_VARYING, Index, AnsiString(FloatToStr(Value))); else raise EZIBConvertError.Create(SUnsupportedDataType); end; if (sqlind <> nil) then sqlind^ := 0; // not null end; {$IFOPT D+} {$R+} {$ENDIF} end; {** Set up parameter Boolean value @param Index the target parameter index @param Value the source value } procedure TZParamsSQLDA.UpdateBoolean(const Index: Integer; Value: boolean); var SQLCode: SmallInt; begin CheckRange(Index); {$R-} with FXSQLDA.sqlvar[Index] do begin if (sqlind <> nil) and (sqlind^ = -1) then Exit; SQLCode := (sqltype and not(1)); if (sqlscale < 0) then begin case SQLCode of SQL_SHORT : PSmallInt(sqldata)^ := ord(Value) * IBScaleDivisor[sqlscale]; SQL_LONG : PInteger(sqldata)^ := ord(Value) * IBScaleDivisor[sqlscale]; SQL_INT64, SQL_QUAD : PInt64(sqldata)^ := ord(Value) * IBScaleDivisor[sqlscale]; SQL_DOUBLE : PDouble(sqldata)^ := ord(Value); else raise EZIBConvertError.Create(SUnsupportedParameterType); end; end else case SQLCode of SQL_DOUBLE : PDouble(sqldata)^ := ord(Value); SQL_LONG : PInteger(sqldata)^ := ord(Value); SQL_D_FLOAT, SQL_FLOAT : PSingle(sqldata)^ := ord(Value); SQL_BOOLEAN : PSmallint(sqldata)^ := ord(Value); SQL_SHORT : PSmallint(sqldata)^ := ord(Value); SQL_INT64 : PInt64(sqldata)^ := ord(Value); SQL_TEXT : EncodeString(SQL_TEXT, Index, AnsiString(IntToStr(ord(Value)))); SQL_VARYING : EncodeString(SQL_VARYING, Index, AnsiString(IntToStr(ord(Value)))); else raise EZIBConvertError.Create(SUnsupportedParameterType); end; if (sqlind <> nil) then sqlind^ := 0; // not null end; {$IFOPT D+} {$R+} {$ENDIF} end; {** Set up parameter Byte value @param Index the target parameter index @param Value the source value } procedure TZParamsSQLDA.UpdateByte(const Index: Integer; Value: ShortInt); var SQLCode: SmallInt; begin CheckRange(Index); SetFieldType(Index, sizeof(Smallint), SQL_SHORT + 1, 0); {$R-} with FXSQLDA.sqlvar[Index] do begin if (sqlind <> nil) and (sqlind^ = -1) then Exit; SQLCode := (sqltype and not(1)); if (sqlscale < 0) then begin case SQLCode of SQL_SHORT : PSmallInt(sqldata)^ := Value * IBScaleDivisor[sqlscale]; SQL_LONG : PInteger(sqldata)^ := Value * IBScaleDivisor[sqlscale]; SQL_INT64, SQL_QUAD : PInt64(sqldata)^ := Value * IBScaleDivisor[sqlscale]; SQL_DOUBLE : PDouble(sqldata)^ := Value; else raise EZIBConvertError.Create(SUnsupportedParameterType); end; end else case SQLCode of SQL_DOUBLE : PDouble(sqldata)^ := Value; SQL_LONG : PInteger(sqldata)^ := Value; SQL_D_FLOAT, SQL_FLOAT : PSingle(sqldata)^ := Value; SQL_BOOLEAN: begin if FPlainDriver.GetProtocol <> 'interbase-7' then raise EZIBConvertError.Create(SUnsupportedDataType); PSmallint(sqldata)^ := Value; end; SQL_SHORT : PSmallint(sqldata)^ := Value; SQL_INT64 : PInt64(sqldata)^ := Value; SQL_TEXT : EncodeString(SQL_TEXT, Index, AnsiString(IntToStr(Value))); SQL_VARYING : EncodeString(SQL_VARYING, Index, AnsiString(IntToStr(Value))); else raise EZIBConvertError.Create(SUnsupportedParameterType); end; if (sqlind <> nil) then sqlind^ := 0; // not null end; {$IFOPT D+} {$R+} {$ENDIF} end; {** Set up parameter byte value @param Index the target parameter index @param Value the source value } procedure TZParamsSQLDA.UpdateBytes(const Index: Integer; Value: TByteDynArray); var SQLCode: SmallInt; Stream: TStream; Len: Integer; begin CheckRange(Index); // SetFieldType(Index, Length(Value) + 1, SQL_TEXT + 1, 0); {$R-} with FXSQLDA.sqlvar[Index] do begin if (sqlind <> nil) and (sqlind^ = -1) then Exit; SQLCode := (sqltype and not(1)); case SQLCode of SQL_TEXT : EncodeBytes(SQL_TEXT, Index, Value); SQL_VARYING : EncodeBytes(SQL_VARYING, Index, Value); SQL_LONG : PInteger (sqldata)^ := Round(ZStrToFloat(BytesToStr(Value)) * IBScaleDivisor[sqlscale]); //AVZ SQL_SHORT : PInteger (sqldata)^ := StrToInt(String(BytesToStr(Value))); SQL_TYPE_DATE : EncodeString(SQL_DATE, Index, BytesToStr(Value)); SQL_DOUBLE : PDouble (sqldata)^ := ZStrToFloat(BytesToStr(Value)) * IBScaleDivisor[sqlscale]; //AVZ SQL_D_FLOAT, SQL_FLOAT : PSingle (sqldata)^ := ZStrToFloat(BytesToStr(Value)) * IBScaleDivisor[sqlscale]; //AVZ SQL_INT64 : PInt64(sqldata)^ := Trunc(ZStrToFloat(BytesToStr(Value)) * IBScaleDivisor[sqlscale]); //AVZ - INT64 value was not recognized SQL_BLOB, SQL_QUAD: begin Stream := TMemoryStream.Create; try Len := Length(Value); Stream.Size := Len; System.Move(Pointer(Value)^, TMemoryStream(Stream).Memory^, Len); WriteBlob(index, Stream); finally Stream.Free; end; end; else raise EZIBConvertError.Create(SErrorConvertion); end; if (sqlind <> nil) then sqlind^ := 0; // not null end; {$IFOPT D+} {$R+} {$ENDIF} end; {** Set up parameter Date value @param Index the target parameter index @param Value the source value } procedure TZParamsSQLDA.UpdateDate(const Index: Integer; Value: TDateTime); begin SetFieldType(Index, sizeof(Integer), SQL_TYPE_DATE + 1, 0); UpdateDateTime(Index, Value); end; {** Set up parameter DateTime value @param Index the target parameter index @param Value the source value } procedure TZParamsSQLDA.UpdateDateTime(const Index: Integer; Value: TDateTime); var y, m, d: word; hr, min, sec, msec: word; SQLCode: SmallInt; TmpDate: TCTimeStructure; begin CheckRange(Index); {$R-} with FXSQLDA.sqlvar[Index] do begin DecodeDate(Value, y, m, d); DecodeTime(Value, hr, min, sec, msec); TmpDate.tm_year := y - 1900; TmpDate.tm_mon := m - 1; TmpDate.tm_mday := d; TmpDate.tm_hour := hr; TmpDate.tm_min := min; TmpDate.tm_sec := sec; TmpDate.tm_wday := 0; TmpDate.tm_yday := 0; TmpDate.tm_isdst := 0; if (sqlind <> nil) and (sqlind^ = -1) then Exit; SQLCode := (sqltype and not(1)); case SQLCode of SQL_TYPE_DATE : FPlainDriver.isc_encode_sql_date(@TmpDate, PISC_DATE(sqldata)); SQL_TYPE_TIME : begin FPlainDriver.isc_encode_sql_time(@TmpDate, PISC_TIME(sqldata)); PISC_TIME(sqldata)^ := PISC_TIME(sqldata)^ + msec*10; end; SQL_TIMESTAMP : begin FPlainDriver.isc_encode_timestamp(@TmpDate,PISC_TIMESTAMP(sqldata)); PISC_TIMESTAMP(sqldata).timestamp_time :=PISC_TIMESTAMP(sqldata).timestamp_time + msec*10; end; else raise EZIBConvertError.Create(SInvalidState); end; if (sqlind <> nil) then sqlind^ := 0; // not null end; {$IFOPT D+} {$R+} {$ENDIF} end; {** Set up parameter Double value @param Index the target parameter index @param Value the source value } procedure TZParamsSQLDA.UpdateDouble(const Index: Integer; Value: Double); var SQLCode: SmallInt; begin CheckRange(Index); SetFieldType(Index, sizeof(double), SQL_DOUBLE + 1, 0); {$R-} with FXSQLDA.sqlvar[Index] do begin if (sqlind <> nil) and (sqlind^ = -1) then Exit; SQLCode := (sqltype and not(1)); if (sqlscale < 0) then begin case SQLCode of SQL_SHORT : PSmallInt(sqldata)^ := Trunc(Value * IBScaleDivisor[sqlscale]); SQL_LONG : PInteger(sqldata)^ := Trunc(Value * IBScaleDivisor[sqlscale]); SQL_INT64, SQL_QUAD : PInt64(sqldata)^ := Trunc(Value * IBScaleDivisor[sqlscale]); SQL_DOUBLE : PDouble(sqldata)^ := Value; else raise EZIBConvertError.Create(SUnsupportedDataType); end; end else case SQLCode of SQL_DOUBLE : PDouble(sqldata)^ := Value; SQL_LONG : PInteger(sqldata)^ := Trunc(Value); SQL_D_FLOAT, SQL_FLOAT : PSingle(sqldata)^ := Value; SQL_BOOLEAN : PSmallint(sqldata)^ := Trunc(Value); SQL_SHORT : PSmallint(sqldata)^ := Trunc(Value); SQL_INT64 : PInt64(sqldata)^ := Trunc(Value); SQL_TEXT : EncodeString(SQL_TEXT, Index, AnsiString(FloatToStr(Value))); SQL_VARYING : EncodeString(SQL_VARYING, Index, AnsiString(FloatToStr(Value))); else raise EZIBConvertError.Create(SUnsupportedDataType); end; if (sqlind <> nil) then sqlind^ := 0; // not null end; {$IFOPT D+} {$R+} {$ENDIF} end; {** Set up parameter Float value @param Index the target parameter index @param Value the source value } procedure TZParamsSQLDA.UpdateFloat(const Index: Integer; Value: Single); var SQLCode: SmallInt; begin CheckRange(Index); SetFieldType(Index, sizeof(Single), SQL_FLOAT + 1, 1); {$R-} with FXSQLDA.sqlvar[Index] do begin if (sqlind <> nil) and (sqlind^ = -1) then Exit; SQLCode := (sqltype and not(1)); if (sqlscale < 0) then begin case SQLCode of SQL_SHORT : PSmallInt(sqldata)^ := Trunc(Value * IBScaleDivisor[sqlscale]); SQL_LONG : PInteger(sqldata)^ := Trunc(Value * IBScaleDivisor[sqlscale]); SQL_INT64, SQL_QUAD : PInt64(sqldata)^ := Trunc(Value * IBScaleDivisor[sqlscale]); SQL_DOUBLE : PDouble(sqldata)^ := Value; SQL_D_FLOAT, SQL_FLOAT : PSingle(sqldata)^ := Value; else raise EZIBConvertError.Create(SUnsupportedDataType); end; end else case SQLCode of SQL_DOUBLE : PDouble(sqldata)^ := Value; SQL_LONG : PInteger(sqldata)^ := Trunc(Value); SQL_D_FLOAT, SQL_FLOAT : PSingle(sqldata)^ := Value; SQL_BOOLEAN : PSmallint(sqldata)^ := Trunc(Value); SQL_SHORT : PSmallint(sqldata)^ := Trunc(Value); SQL_INT64 : PInt64(sqldata)^ := Trunc(Value); SQL_TEXT : EncodeString(SQL_TEXT, Index, AnsiString(FloatToStr(Value))); SQL_VARYING : EncodeString(SQL_VARYING, Index, AnsiString(FloatToStr(Value))); else raise EZIBConvertError.Create(SUnsupportedDataType); end; if (sqlind <> nil) then sqlind^ := 0; // not null end; {$IFOPT D+} {$R+} {$ENDIF} end; {** Set up parameter integer value @param Index the target parameter index @param Value the source value } procedure TZParamsSQLDA.UpdateInt(const Index: Integer; Value: Integer); var SQLCode: SmallInt; begin CheckRange(Index); SetFieldType(Index, sizeof(Integer), SQL_LONG + 1, 0); {$R-} with FXSQLDA.sqlvar[Index] do begin if (sqlind <> nil) and (sqlind^ = -1) then Exit; SQLCode := (sqltype and not(1)); if (sqlscale < 0) then begin case SQLCode of SQL_SHORT : PSmallInt(sqldata)^ := Value * IBScaleDivisor[sqlscale]; SQL_LONG : PInteger(sqldata)^ := Value * IBScaleDivisor[sqlscale]; SQL_INT64, SQL_QUAD : PInt64(sqldata)^ := Value * IBScaleDivisor[sqlscale]; SQL_DOUBLE : PDouble(sqldata)^ := Value; else raise EZIBConvertError.Create(SUnsupportedDataType); end; end else case SQLCode of SQL_DOUBLE : PDouble(sqldata)^ := Value; SQL_LONG : PInteger(sqldata)^ := Value; SQL_D_FLOAT, SQL_FLOAT : PSingle(sqldata)^ := Value; SQL_BOOLEAN : PSmallint(sqldata)^ := Value; SQL_SHORT : PSmallint(sqldata)^ := Value; SQL_INT64 : PInt64(sqldata)^ := Value; SQL_TEXT : EncodeString(SQL_TEXT, Index, AnsiString(IntToStr(Value))); SQL_VARYING : EncodeString(SQL_VARYING, Index, AnsiString(IntToStr(Value))); else raise EZIBConvertError.Create(SUnsupportedDataType); end; if (sqlind <> nil) then sqlind^ := 0; // not null end; {$IFOPT D+} {$R+} {$ENDIF} end; {** Set up parameter Long value @param Index the target parameter index @param Value the source value } procedure TZParamsSQLDA.UpdateLong(const Index: integer; Value: Int64); var SQLCode: SmallInt; begin CheckRange(Index); SetFieldType(Index, sizeof(Int64), SQL_INT64 + 1, 0); {$R-} with FXSQLDA.sqlvar[Index] do begin if (sqlind <> nil) and (sqlind^ = -1) then Exit; SQLCode := (sqltype and not(1)); if (sqlscale < 0) then begin case SQLCode of SQL_SHORT : PSmallInt(sqldata)^ := Value * IBScaleDivisor[sqlscale]; SQL_LONG : PInteger(sqldata)^ := Value * IBScaleDivisor[sqlscale]; SQL_INT64, SQL_QUAD : PInt64(sqldata)^ := Value * IBScaleDivisor[sqlscale]; SQL_DOUBLE : PDouble(sqldata)^ := Value; else raise EZIBConvertError.Create(SUnsupportedDataType); end; end else case SQLCode of SQL_DOUBLE : PDouble(sqldata)^ := Value; SQL_LONG : PInteger(sqldata)^ := Value; SQL_D_FLOAT, SQL_FLOAT : PSingle(sqldata)^ := Value; SQL_BOOLEAN : PSmallint(sqldata)^ := Value; SQL_SHORT : PSmallint(sqldata)^ := Value; SQL_INT64 : PInt64(sqldata)^ := Value; SQL_TEXT : EncodeString(SQL_TEXT, Index, AnsiString(IntToStr(Value))); SQL_VARYING : EncodeString(SQL_VARYING, Index, AnsiString(IntToStr(Value))); else raise EZIBConvertError.Create(SUnsupportedDataType); end; if (sqlind <> nil) then sqlind^ := 0; // not null end; {$IFOPT D+} {$R+} {$ENDIF} end; {** Set up parameter null value @param Index the target parameter index @param Value the source value } procedure TZParamsSQLDA.UpdateNull(const Index: Integer; Value: boolean); begin CheckRange(Index); {$R-} with FXSQLDA.sqlvar[Index] do if (sqlind <> nil) then case Value of True : sqlind^ := -1; //NULL False : sqlind^ := 0; //NOT NULL end; {$IFOPT D+} {$R+} {$ENDIF} end; {** Set up parameter PAnsiChar value @param Index the target parameter index @param Value the source value } procedure TZParamsSQLDA.UpdatePChar(const Index: Integer; Value: PAnsiChar); var TempString: AnsiString; begin TempString := Value; UpdateString(Index, TempString); end; {** Set up parameter Interbase QUAD value @param Index the target parameter index @param Value the source value } procedure TZParamsSQLDA.UpdateQuad(const Index: Word; const Value: TISC_QUAD); begin CheckRange(Index); SetFieldType(Index, sizeof(TISC_QUAD), SQL_QUAD + 1, 0); {$R-} with FXSQLDA.sqlvar[Index] do if not ((sqlind <> nil) and (sqlind^ = -1)) then begin case (sqltype and not(1)) of SQL_QUAD, SQL_DOUBLE, SQL_INT64, SQL_BLOB, SQL_ARRAY: PISC_QUAD(sqldata)^ := Value; else raise EZIBConvertError.Create(SUnsupportedDataType); end; if (sqlind <> nil) then sqlind^ := 0; // not null end else raise EZIBConvertError.Create(SUnsupportedDataType); {$IFOPT D+} {$R+} {$ENDIF} end; {** Set up parameter short value @param Index the target parameter index @param Value the source value } procedure TZParamsSQLDA.UpdateShort(const Index: Integer; Value: SmallInt); var SQLCode: SmallInt; begin CheckRange(Index); SetFieldType(Index, sizeof(Smallint), SQL_SHORT + 1, 0); {$R-} with FXSQLDA.sqlvar[Index] do begin if (sqlind <> nil) and (sqlind^ = -1) then Exit; SQLCode := (sqltype and not(1)); if (sqlscale < 0) then begin case SQLCode of SQL_SHORT : PSmallInt(sqldata)^ := Value * IBScaleDivisor[sqlscale]; SQL_LONG : PInteger(sqldata)^ := Value * IBScaleDivisor[sqlscale]; SQL_INT64, SQL_QUAD : PInt64(sqldata)^ := Value * IBScaleDivisor[sqlscale]; SQL_DOUBLE : PDouble(sqldata)^ := Value; else raise EZIBConvertError.Create(SUnsupportedDataType); end; end else case SQLCode of SQL_DOUBLE : PDouble(sqldata)^ := Value; SQL_LONG : PInteger(sqldata)^ := Value; SQL_D_FLOAT, SQL_FLOAT : PSingle(sqldata)^ := Value; SQL_BOOLEAN : PSmallint(sqldata)^ := Value; SQL_SHORT : PSmallint(sqldata)^ := Value; SQL_INT64 : PInt64(sqldata)^ := Value; SQL_TEXT : EncodeString(SQL_TEXT, Index, AnsiString(IntToStr(Value))); SQL_VARYING : EncodeString(SQL_VARYING, Index, AnsiString(IntToStr(Value))); else raise EZIBConvertError.Create(SUnsupportedDataType); end; if (sqlind <> nil) then sqlind^ := 0; // not null end; {$IFOPT D+} {$R+} {$ENDIF} end; {** Set up parameter String value @param Index the target parameter index @param Value the source value } procedure TZParamsSQLDA.UpdateString(const Index: Integer; Value: RawByteString); var SQLCode: SmallInt; Stream: TStream; begin CheckRange(Index); // SetFieldType(Index, Length(Value) + 1, SQL_TEXT + 1, 0); {$R-} with FXSQLDA.sqlvar[Index] do begin if (sqlind <> nil) and (sqlind^ = -1) then Exit; SQLCode := (sqltype and not(1)); case SQLCode of SQL_TEXT : EncodeString(SQL_TEXT, Index, Value); SQL_VARYING : EncodeString(SQL_VARYING, Index, Value); SQL_LONG : PInteger (sqldata)^ := StrToInt(String(Value)); //AVZ SQL_SHORT : PSmallInt (sqldata)^ := StrToInt(String(Value)); SQL_TYPE_DATE : EncodeString(SQL_DATE, Index, Value); SQL_DOUBLE : PDouble (sqldata)^ := ZStrToFloat(Value) * IBScaleDivisor[sqlscale]; //AVZ SQL_D_FLOAT, SQL_FLOAT : PSingle (sqldata)^ := ZStrToFloat(Value) * IBScaleDivisor[sqlscale]; //AVZ SQL_INT64 : PInt64(sqldata)^ := Trunc(ZStrToFloat(Value) * IBScaleDivisor[sqlscale]); //AVZ - INT64 value was not recognized SQL_BLOB, SQL_QUAD: begin Stream := TStringStream.Create(Value); try WriteBlob(index, Stream); finally Stream.Free; end; end; else raise EZIBConvertError.Create(SErrorConvertion); end; if (sqlind <> nil) then sqlind^ := 0; // not null end; {$IFOPT D+} {$R+} {$ENDIF} end; {** Set up parameter Time value @param Index the target parameter index @param Value the source value } procedure TZParamsSQLDA.UpdateTime(const Index: Integer; Value: TDateTime); begin SetFieldType(Index, sizeof(Cardinal), SQL_TYPE_TIME + 1, 0); UpdateDateTime(Index, Value); end; {** Set up parameter Timestamp value @param Index the target parameter index @param Value the source value } procedure TZParamsSQLDA.UpdateTimestamp(const Index: Integer; Value: TDateTime); begin SetFieldType(Index, sizeof(TISC_QUAD), SQL_TIMESTAMP + 1, 0); UpdateDateTime(Index, Value); end; {** Write stream to blob field @param Index an index field number @param Stream the souse data stream } procedure TZParamsSQLDA.WriteBlob(const Index: Integer; Stream: TStream); var Buffer: PAnsiChar; BlobId: TISC_QUAD; BlobHandle: TISC_BLOB_HANDLE; StatusVector: TARRAY_ISC_STATUS; BlobSize, CurPos, SegLen: Integer; begin BlobHandle := 0; Stream.Seek(0, 0); { create blob handle } FPlainDriver.isc_create_blob2(@StatusVector, FHandle, FTransactionHandle, @BlobHandle, @BlobId, 0, nil); CheckInterbase6Error(FPlainDriver, StatusVector); Stream.Position := 0; BlobSize := Stream.Size; Buffer := AllocMem(BlobSize); Try Stream.ReadBuffer(Buffer^, BlobSize); { put data to blob } CurPos := 0; SegLen := DefaultBlobSegmentSize; while (CurPos < BlobSize) do begin if (CurPos + SegLen > BlobSize) then SegLen := BlobSize - CurPos; if FPlainDriver.isc_put_segment(@StatusVector, @BlobHandle, SegLen, PAnsiChar(@Buffer[CurPos])) > 0 then CheckInterbase6Error(FPlainDriver, StatusVector); Inc(CurPos, SegLen); end; { close blob handle } FPlainDriver.isc_close_blob(@StatusVector, @BlobHandle); CheckInterbase6Error(FPlainDriver, StatusVector); Stream.Seek(0, 0); UpdateQuad(Index, BlobId); Finally Freemem(Buffer); End; end; { TResultSQLDA } {** Decode Interbase field value to pascal string @param Code the Interbase data type @param Index field index @result the field string } function TZResultSQLDA.DecodeString(const Code: Smallint; const Index: Word): RawByteString; var l: integer; procedure SetAnsi(Ansi: PAnsiChar; Len: Longint); begin SetLength(Result, Len); System.Move(Ansi^, PAnsiChar(Result)^, Len); end; begin {$R-} with FXSQLDA.sqlvar[Index] do case Code of SQL_TEXT: begin SetAnsi(sqldata, sqllen); // Trim only spaces. TrimRight also removes other characters) l := sqllen; while (l > 0) and (Result[l] = ' ') do dec(l); if l < sqllen then result := copy(result, 1, l); end; SQL_VARYING : SetAnsi(PISC_VARYING(sqldata).str, PISC_VARYING(sqldata).strlen); end; {$IFOPT D+} {$R+} {$ENDIF} end; {** Decode Interbase field value to pascal string @param Code the Interbase data type @param Index field index @param Str the field string } procedure TZResultSQLDA.DecodeString2(const Code: Smallint; const Index: Word; out Str: RawByteString); begin Str := DecodeString(Code, Index); end; {** Return BigDecimal field value @param Index the field index @return the field BigDecimal value } function TZResultSQLDA.GetBigDecimal(const Index: Integer): Extended; var SQLCode: SmallInt; begin CheckRange(Index); {$R-} with FXSQLDA.sqlvar[Index] do begin Result := 0; if (sqlind <> nil) and (sqlind^ = -1) then Exit; SQLCode := (sqltype and not(1)); if (sqlscale < 0) then begin case SQLCode of SQL_SHORT : Result := PSmallInt(sqldata)^ / IBScaleDivisor[sqlscale]; SQL_LONG : Result := PInteger(sqldata)^ / IBScaleDivisor[sqlscale]; SQL_INT64, SQL_QUAD : Result := PInt64(sqldata)^ / IBScaleDivisor[sqlscale]; SQL_DOUBLE : Result := PDouble(sqldata)^; else raise EZIBConvertError.Create(Format(SErrorConvertionField, [GetFieldAliasName(Index), GetNameSqlType(SQLCode)])); end; end else case SQLCode of SQL_DOUBLE : Result := PDouble(sqldata)^; SQL_LONG : Result := PInteger(sqldata)^; SQL_D_FLOAT, SQL_FLOAT : Result := PSingle(sqldata)^; SQL_BOOLEAN : Result := PSmallint(sqldata)^; SQL_SHORT : Result := PSmallint(sqldata)^; SQL_INT64 : Result := PInt64(sqldata)^; SQL_TEXT : Result := StrToFloat(String(DecodeString(SQL_TEXT, Index))); SQL_VARYING : Result := StrToFloat(String(DecodeString(SQL_VARYING, Index))); else raise EZIBConvertError.Create(Format(SErrorConvertionField, [GetFieldAliasName(Index), GetNameSqlType(SQLCode)])); end; end; {$IFOPT D+} {$R+} {$ENDIF} end; {** Return Boolean field value @param Index the field index @return the field boolean value } function TZResultSQLDA.GetBoolean(const Index: Integer): Boolean; var SQLCode: SmallInt; begin CheckRange(Index); {$R-} with FXSQLDA.sqlvar[Index] do begin Result := False; if (sqlind <> nil) and (sqlind^ = -1) then Exit; SQLCode := (sqltype and not(1)); if (sqlscale < 0) then begin case SQLCode of SQL_SHORT : Result := PSmallInt(sqldata)^ div IBScaleDivisor[sqlscale] <> 0; SQL_LONG : Result := PInteger(sqldata)^ div IBScaleDivisor[sqlscale] <> 0; SQL_INT64, SQL_QUAD : Result := PInt64(sqldata)^ div IBScaleDivisor[sqlscale] <> 0; SQL_DOUBLE : Result := Trunc(PDouble(sqldata)^) > 0; else raise EZIBConvertError.Create(Format(SErrorConvertionField, [GetFieldAliasName(Index), GetNameSqlType(SQLCode)])); end; end else case SQLCode of SQL_DOUBLE : Result := Trunc(PDouble(sqldata)^) <> 0; SQL_LONG : Result := PInteger(sqldata)^ <> 0; SQL_D_FLOAT, SQL_FLOAT : Result := Trunc(PSingle(sqldata)^) <> 0; SQL_BOOLEAN : Result := PSmallint(sqldata)^ <> 0; SQL_SHORT : Result := PSmallint(sqldata)^ <> 0; SQL_INT64 : Result := PInt64(sqldata)^ <> 0; SQL_TEXT : Result := StrToInt(String(DecodeString(SQL_TEXT, Index))) <> 0; SQL_VARYING : Result := StrToInt(String(DecodeString(SQL_VARYING, Index))) <> 0; else raise EZIBConvertError.Create(Format(SErrorConvertionField, [GetFieldAliasName(Index), GetNameSqlType(SQLCode)])); end; end; {$IFOPT D+} {$R+} {$ENDIF} end; {** Return Byte field value @param Index the field index @return the field Byte value } function TZResultSQLDA.GetByte(const Index: Integer): Byte; begin Result := Byte(GetShort(Index)); end; {** Return Bytes field value @param Index the field index @return the field Bytes value } function TZResultSQLDA.GetBytes(const Index: Integer): TByteDynArray; var SQLCode: SmallInt; begin CheckRange(Index); Result := nil; {$R-} with FXSQLDA.sqlvar[Index] do begin if (sqlind <> nil) and (sqlind^ = -1) then Exit; SQLCode := (sqltype and not(1)); case SQLCode of SQL_TEXT, SQL_VARYING: begin SetLength(Result, sqllen); System.Move(PAnsiChar(sqldata)^, Pointer(Result)^, sqllen); end; else raise EZIBConvertError.Create(Format(SErrorConvertionField, [GetFieldAliasName(Index), GetNameSqlType(SQLCode)])); end; end; {$IFOPT D+} {$R+} {$ENDIF} end; {** Return Date field value @param Index the field index @return the field Date value } function TZResultSQLDA.GetDate(const Index: Integer): TDateTime; begin Result := Trunc(GetTimestamp(Index)); end; {** Return Double field value @param Index the field index @return the field Double value } function TZResultSQLDA.GetDouble(const Index: Integer): Double; var SQLCode: SmallInt; begin CheckRange(Index); {$R-} with FXSQLDA.sqlvar[Index] do begin Result := 0; if (sqlind <> nil) and (sqlind^ = -1) then Exit; SQLCode := (sqltype and not(1)); if (sqlscale < 0) then begin case SQLCode of SQL_SHORT : Result := PSmallInt(sqldata)^ / IBScaleDivisor[sqlscale]; SQL_LONG : Result := PInteger(sqldata)^ / IBScaleDivisor[sqlscale]; SQL_INT64, SQL_QUAD : Result := PInt64(sqldata)^ / IBScaleDivisor[sqlscale]; SQL_DOUBLE : Result := PDouble(sqldata)^; else raise EZIBConvertError.Create(Format(SErrorConvertionField, [GetFieldAliasName(Index), GetNameSqlType(SQLCode)])); end; end else case SQLCode of SQL_DOUBLE : Result := PDouble(sqldata)^; SQL_LONG : Result := PInteger(sqldata)^; SQL_D_FLOAT, SQL_FLOAT : Result := PSingle(sqldata)^; SQL_BOOLEAN : Result := PSmallint(sqldata)^; SQL_SHORT : Result := PSmallint(sqldata)^; SQL_INT64 : Result := PInt64(sqldata)^; SQL_TEXT : Result := StrToFloat(String(DecodeString(SQL_TEXT, Index))); SQL_VARYING : Result := StrToFloat(String(DecodeString(SQL_VARYING, Index))); else raise EZIBConvertError.Create(Format(SErrorConvertionField, [GetFieldAliasName(Index), GetNameSqlType(SQLCode)])); end; end; {$IFOPT D+} {$R+} {$ENDIF} end; {** Return Float field value @param Index the field index @return the field Float value } function TZResultSQLDA.GetFloat(const Index: Integer): Single; var SQLCode: SmallInt; begin CheckRange(Index); {$R-} with FXSQLDA.sqlvar[Index] do begin Result := 0; if (sqlind <> nil) and (sqlind^ = -1) then Exit; SQLCode := (sqltype and not(1)); if (sqlscale < 0) then begin case SQLCode of SQL_SHORT : Result := PSmallInt(sqldata)^ / IBScaleDivisor[sqlscale]; SQL_LONG : Result := PInteger(sqldata)^ / IBScaleDivisor[sqlscale]; SQL_INT64, SQL_QUAD : Result := PInt64(sqldata)^ / IBScaleDivisor[sqlscale]; SQL_DOUBLE : Result := PDouble(sqldata)^; else raise EZIBConvertError.Create(Format(SErrorConvertionField, [GetFieldAliasName(Index), GetNameSqlType(SQLCode)])); end; end else case SQLCode of SQL_DOUBLE : Result := PDouble(sqldata)^; SQL_LONG : Result := PInteger(sqldata)^; SQL_D_FLOAT, SQL_FLOAT : Result := PSingle(sqldata)^; SQL_BOOLEAN : Result := PSmallint(sqldata)^; SQL_SHORT : Result := PSmallint(sqldata)^; SQL_INT64 : Result := PInt64(sqldata)^; SQL_TEXT : Result := StrToFloat(String(DecodeString(SQL_TEXT, Index))); SQL_VARYING : Result := StrToFloat(String(DecodeString(SQL_VARYING, Index))); else raise EZIBConvertError.Create(Format(SErrorConvertionField, [GetFieldAliasName(Index), GetNameSqlType(SQLCode)])); end; end; {$IFOPT D+} {$R+} {$ENDIF} end; {** Return Integer field value @param Index the field index @return the field Integer value } function TZResultSQLDA.GetInt(const Index: Integer): Integer; begin Result := Integer(GetLong(Index)); end; {** Return Long field value @param Index the field index @return the field Long value } function TZResultSQLDA.GetLong(const Index: Integer): Int64; var SQLCode: SmallInt; begin CheckRange(Index); {$R-} with FXSQLDA.sqlvar[Index] do begin Result := 0; if (sqlind <> nil) and (sqlind^ = -1) then Exit; SQLCode := (sqltype and not(1)); if (sqlscale < 0) then begin case SQLCode of SQL_SHORT : Result := PSmallInt(sqldata)^ div IBScaleDivisor[sqlscale]; SQL_LONG : Result := PInteger(sqldata)^ div IBScaleDivisor[sqlscale]; SQL_INT64, SQL_QUAD : Result := PInt64(sqldata)^ div IBScaleDivisor[sqlscale]; SQL_DOUBLE : Result := Trunc(PDouble(sqldata)^); else raise EZIBConvertError.Create(Format(SErrorConvertionField, [GetFieldAliasName(Index), GetNameSqlType(SQLCode)])); end; end else case SQLCode of SQL_DOUBLE : Result := Trunc(PDouble(sqldata)^); SQL_LONG : Result := PInteger(sqldata)^; SQL_D_FLOAT, SQL_FLOAT : Result := Trunc(PSingle(sqldata)^); SQL_BOOLEAN : Result := PSmallint(sqldata)^; SQL_SHORT : Result := PSmallint(sqldata)^; SQL_INT64 : Result := PInt64(sqldata)^; SQL_TEXT : Result := StrToInt(String(DecodeString(SQL_TEXT, Index))); SQL_VARYING : Result := StrToInt(String(DecodeString(SQL_VARYING, Index))); else raise EZIBConvertError.Create(Format(SErrorConvertionField, [GetFieldAliasName(Index), GetNameSqlType(SQLCode)])); end; end; {$IFOPT D+} {$R+} {$ENDIF} end; {** Return PAnsiChar field value @param Index the field index @return the field PAnsiChar value } function TZResultSQLDA.GetPChar(const Index: Integer): PChar; var TempStr: String; begin TempStr := ZDbcString(GetString(Index)); Result := PChar(TempStr); end; {** Return Short field value @param Index the field index @return the field Short value } function TZResultSQLDA.GetShort(const Index: Integer): SmallInt; var SQLCode: SmallInt; begin CheckRange(Index); {$R-} with FXSQLDA.sqlvar[Index] do begin Result := 0; if (sqlind <> nil) and (sqlind^ = -1) then Exit; SQLCode := (sqltype and not(1)); if (sqlscale < 0) then begin case SQLCode of SQL_SHORT : Result := PSmallInt(sqldata)^ div IBScaleDivisor[sqlscale]; SQL_LONG : Result := PInteger(sqldata)^ div IBScaleDivisor[sqlscale]; SQL_INT64, SQL_QUAD : Result := PInt64(sqldata)^ div IBScaleDivisor[sqlscale]; SQL_DOUBLE : Result := Trunc(PDouble(sqldata)^); else raise EZIBConvertError.Create(Format(SErrorConvertionField, [GetFieldAliasName(Index), GetNameSqlType(SQLCode)])); end; end else case SQLCode of SQL_DOUBLE : Result := Trunc(PDouble(sqldata)^); SQL_LONG : Result := PInteger(sqldata)^; SQL_D_FLOAT, SQL_FLOAT : Result := Trunc(PSingle(sqldata)^); SQL_BOOLEAN : Result := PSmallint(sqldata)^; SQL_SHORT : Result := PSmallint(sqldata)^; SQL_INT64 : Result := PInt64(sqldata)^; SQL_TEXT : Result := StrToInt(String(DecodeString(SQL_TEXT, Index))); SQL_VARYING : Result := StrToInt(String(DecodeString(SQL_VARYING, Index))); else raise EZIBConvertError.Create(Format(SErrorConvertionField, [GetFieldAliasName(Index), GetNameSqlType(SQLCode)])); end; end; {$IFOPT D+} {$R+} {$ENDIF} end; {** Return String field value @param Index the field index @return the field String value } function TZResultSQLDA.GetString(const Index: Integer): RawByteString; var SQLCode: SmallInt; TempAnsi: AnsiString; begin CheckRange(Index); Result := ''; {$R-} with FXSQLDA.sqlvar[Index] do begin if (sqlind <> nil) and (sqlind^ = -1) then Exit; SQLCode := (sqltype and not(1)); if (sqlscale < 0) then begin case SQLCode of SQL_SHORT : Result := RawByteString(FloatToStr(PSmallInt(sqldata)^ / IBScaleDivisor[sqlscale])); SQL_LONG : Result := RawByteString(FloatToStr(PInteger(sqldata)^ / IBScaleDivisor[sqlscale])); SQL_INT64, SQL_QUAD : Result := RawByteString(FloatToStr(PInt64(sqldata)^ / IBScaleDivisor[sqlscale])); SQL_DOUBLE : Result := RawByteString(FloatToStr(PDouble(sqldata)^)); else raise EZIBConvertError.Create(Format(SErrorConvertionField, [GetFieldAliasName(Index), GetNameSqlType(SQLCode)])); end; end else case SQLCode of SQL_DOUBLE : Result := RawByteString(FloatToStr(PDouble(sqldata)^)); SQL_LONG : Result := RawByteString(IntToStr(PInteger(sqldata)^)); SQL_D_FLOAT, SQL_FLOAT : Result := RawByteString(FloatToStr(PSingle(sqldata)^)); SQL_BOOLEAN : if Boolean(PSmallint(sqldata)^) = True then Result := 'YES' else Result := 'NO'; SQL_SHORT : Result := RawByteString(IntToStr(PSmallint(sqldata)^)); SQL_INT64 : Result := RawByteString(IntToStr(PInt64(sqldata)^)); SQL_TEXT : DecodeString2(SQL_TEXT, Index, Result); SQL_VARYING : DecodeString2(SQL_VARYING, Index, Result); SQL_BLOB : if VarIsEmpty(FDefaults[Index]) then begin ReadBlobFromString(Index, TempAnsi); FDefaults[Index] := TempAnsi; end else Result := {$IFDEF WITH_FPC_STRING_CONVERSATION}AnsiString{$ELSE}RawByteString{$ENDIF}(FDefaults[Index]); else raise EZIBConvertError.Create(Format(SErrorConvertionField, [GetFieldAliasName(Index), GetNameSqlType(SQLCode)])); end; end; {$IFOPT D+} {$R+} {$ENDIF} end; {** Return Time field value @param Index the field index @return the field Time value } function TZResultSQLDA.GetTime(const Index: Integer): TDateTime; begin Result := Frac(GetTimestamp(Index)); end; {** Return Timestamp field value @param Index the field index @return the field Timestamp value } function TZResultSQLDA.GetTimestamp(const Index: Integer): TDateTime; var TempDate: TCTimeStructure; begin CheckRange(Index); {$R-} with FXSQLDA.sqlvar[Index] do begin Result := 0; if (sqlind <> nil) and (sqlind^ = -1) then Exit; case (sqltype and not(1)) of SQL_TIMESTAMP : begin FPlainDriver.isc_decode_timestamp(PISC_TIMESTAMP(sqldata), @TempDate); Result := SysUtils.EncodeDate(TempDate.tm_year + 1900, TempDate.tm_mon + 1, TempDate.tm_mday) + EncodeTime(TempDate.tm_hour, TempDate.tm_min, TempDate.tm_sec, Word((PISC_TIMESTAMP(sqldata).timestamp_time mod 10000) div 10)); end; SQL_TYPE_DATE : begin FPlainDriver.isc_decode_sql_date(PISC_DATE(sqldata), @TempDate); Result := SysUtils.EncodeDate(Word(TempDate.tm_year + 1900), Word(TempDate.tm_mon + 1), Word(TempDate.tm_mday)); end; SQL_TYPE_TIME : begin FPlainDriver.isc_decode_sql_time(PISC_TIME(sqldata), @TempDate); Result := SysUtils.EncodeTime(Word(TempDate.tm_hour), Word(TempDate.tm_min), Word(TempDate.tm_sec), Word((PISC_TIME(sqldata)^ mod 10000) div 10)); end; else Result := Trunc(GetDouble(Index)); end; end; {$IFOPT D+} {$R+} {$ENDIF} end; {** Indicate field null @param Index the field index @return true if fied value NULL overwise false } function TZResultSQLDA.IsNull(const Index: Integer): Boolean; begin CheckRange(Index); {$R-} with FXSQLDA.sqlvar[Index] do Result := (sqlind <> nil) and (sqlind^ = ISC_NULL); {$IFOPT D+} {$R+} {$ENDIF} end; {** Return Interbase QUAD field value @param Index the field index @return the field Interbase QUAD value } function TZResultSQLDA.GetQuad(const Index: Integer): TISC_QUAD; begin CheckRange(Index); {$R-} with FXSQLDA.sqlvar[Index] do if not ((sqlind <> nil) and (sqlind^ = -1)) then case (sqltype and not(1)) of SQL_QUAD, SQL_DOUBLE, SQL_INT64, SQL_BLOB, SQL_ARRAY: result := PISC_QUAD(sqldata)^; else raise EZIBConvertError.Create(SUnsupportedDataType + ' ' + inttostr((sqltype and not(1)))); end else raise EZIBConvertError.Create('Invalid State.'); {$IFOPT D+} {$R+} {$ENDIF} end; {** Return Variant field value @param Index the field index @return the field Variant value } function TZResultSQLDA.GetValue(const Index: Word): Variant; var SQLCode: SmallInt; begin CheckRange(Index); with FXSQLDA.sqlvar[Index] do begin VarClear(Result); if (sqlind <> nil) and (sqlind^ = -1) then Exit; SQLCode := (sqltype and not(1)); if (sqlscale < 0) then begin case SQLCode of SQL_SHORT : Result := PSmallInt(sqldata)^ / IBScaleDivisor[sqlscale]; SQL_LONG : Result := PInteger(sqldata)^ / IBScaleDivisor[sqlscale]; SQL_INT64, SQL_QUAD : Result := PInt64(sqldata)^ / IBScaleDivisor[sqlscale]; SQL_DOUBLE : Result := PDouble(sqldata)^; else raise EZIBConvertError.Create(Format(SErrorConvertionField, [GetFieldAliasName(Index), GetNameSqlType(SQLCode)])); end; end else case SQLCode of SQL_DOUBLE : Result := PDouble(sqldata)^; SQL_TIMESTAMP : Result := GetTimestamp(Index); SQL_TYPE_DATE : Result := GetDate(Index); SQL_TYPE_TIME : Result := GetTime(Index); SQL_LONG : Result := PInteger(sqldata)^; SQL_D_FLOAT, SQL_FLOAT : Result := PSingle(sqldata)^; SQL_BOOLEAN: begin if FPlainDriver.GetProtocol <> 'interbase-7' then raise EZIBConvertError.Create(SUnsupportedDataType); Result := IntToStr(PSmallint(sqldata)^); end; SQL_SHORT : Result := PSmallint(sqldata)^; SQL_INT64 : Result := PInt64(sqldata)^; SQL_TEXT : Result := DecodeString(SQL_TEXT, Index); SQL_VARYING : Result := DecodeString(SQL_VARYING, Index); SQL_BLOB : if VarIsEmpty(FDefaults[Index]) then begin ReadBlobFromVariant(Index, FDefaults[Index]); Result := FDefaults[Index]; end else Result := Double(FDefaults[Index]); else raise EZIBConvertError.Create(Format(SErrorConvertionField, [GetFieldAliasName(Index), GetNameSqlType(SQLCode)])); end; end; end; destructor TZResultSQLDA.Destroy; begin FreeParamtersValues; FreeMem(FXSQLDA); inherited Destroy; end; {** Read blob data to string @param Index an filed index @param Str destination string } procedure TZResultSQLDA.ReadBlobFromString(const Index: Word; var Str: AnsiString); var Size: LongInt; Buffer: Pointer; begin ReadBlobBufer(FPlainDriver, FHandle, FTransactionHandle, GetQuad(Index), Size, Buffer); try SetLength(Str, Size); SetString(Str, PAnsiChar(Buffer), Size); finally FreeMem(Buffer, Size); end; end; {** Read blob data to stream @param Index an filed index @param Stream destination stream object } procedure TZResultSQLDA.ReadBlobFromStream(const Index: Word; Stream: TStream); var Size: LongInt; Buffer: Pointer; begin ReadBlobBufer(FPlainDriver, FHandle, FTransactionHandle, GetQuad(Index), Size, Buffer); try Stream.Seek(0, 0); Stream.Write(Buffer^, Size); Stream.Seek(0, 0); finally FreeMem(Buffer, Size); end; end; {** Read blob data to variant value @param Index an filed index @param Value destination variant value } procedure TZResultSQLDA.ReadBlobFromVariant(const Index: Word; var Value: Variant); var Size: LongInt; Buffer: Pointer; PData: Pointer; begin ReadBlobBufer(FPlainDriver, FHandle, FTransactionHandle, GetQuad(Index), Size, Buffer); Value := VarArrayCreate([0, Size-1], varByte); PData := VarArrayLock(Value); try move(Buffer^, PData^, Size); finally VarArrayUnlock(Value); FreeMem(Buffer, Size); end; end; procedure TZResultSQLDA.AllocateSQLDA; begin inherited AllocateSQLDA; SetLength(FDefaults, GetFieldCount); end; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcIntfs.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Database Connectivity Interfaces } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcIntfs; interface {$I ZDbc.inc} uses Types, Classes, {$IFDEF MSEgui}mclasses, mdb{$ELSE}DB{$ENDIF}, SysUtils, ZClasses, ZCollections, ZCompatibility, ZTokenizer, ZSelectSchema, ZGenericSqlAnalyser, ZDbcLogging, ZVariant, ZPlainDriver, ZURL; const { Constants from JDBC DatabaseMetadata } TypeSearchable = 3; ProcedureReturnsResult = 2; // Exceptions type {** Abstract SQL exception. } EZSQLThrowable = class(Exception) private FErrorCode: Integer; FStatusCode: String; public constructor Create(const Msg: string); constructor CreateWithCode(const ErrorCode: Integer; const Msg: string); constructor CreateWithStatus(const StatusCode: String; const Msg: string); constructor CreateClone(const E:EZSQLThrowable); property ErrorCode: Integer read FErrorCode; property StatusCode: string read FStatuscode; // The "String" Errocode // FirmOS end; {** Generic SQL exception. } EZSQLException = class(EZSQLThrowable); {** Generic SQL warning. } EZSQLWarning = class(EZSQLThrowable); // Data types type {** Defines supported SQL types. } TZSQLType = (stUnknown, stBoolean, stByte, stShort, stInteger, stLong, stFloat, stDouble, stBigDecimal, stString, stUnicodeString, stBytes, stDate, stTime, stTimestamp, stDataSet, stGUID, stAsciiStream, stUnicodeStream, stBinaryStream); {** Defines a transaction isolation level. } TZTransactIsolationLevel = (tiNone, tiReadUncommitted, tiReadCommitted, tiRepeatableRead, tiSerializable); {** Defines a resultset fetch direction. } TZFetchDirection = (fdForward, fdReverse, fdUnknown); {** Defines a type of result set. } TZResultSetType = (rtForwardOnly, rtScrollInsensitive, rtScrollSensitive); {** Defines a result set concurrency type. } TZResultSetConcurrency = (rcReadOnly, rcUpdatable); {** Defines a nullable type for the column. } TZColumnNullableType = (ntNoNulls, ntNullable, ntNullableUnknown); {** Defines a result type for the procedures. } TZProcedureResultType = (prtUnknown, prtNoResult, prtReturnsResult); {** Defines a column type for the procedures. } TZProcedureColumnType = (pctUnknown, pctIn, pctInOut, pctOut, pctReturn, pctResultSet); {** Defines a best row identifier. } TZBestRowIdentifier = (brUnknown, brNotPseudo, brPseudo); {** Defines a scope best row identifier. } TZScopeBestRowIdentifier = (sbrTemporary, sbrTransaction, sbrSession); {** Defines a version column. } TZVersionColumn = (vcUnknown, vcNotPseudo, vcPseudo); {** } TZImportedKey = (ikCascade, ikRestrict, ikSetNull, ikNoAction, ikSetDefault, ikInitiallyDeferred, ikInitiallyImmediate, ikNotDeferrable); TZTableIndex = (tiStatistic, tiClustered, tiHashed, tiOther); {** Defines a post update mode. } TZPostUpdatesMode = (poColumnsAll, poColumnsChanged); {** Defines a locate mode. } TZLocateUpdatesMode = (loWhereAll, loWhereChanged, loWhereKeyOnly); // Interfaces type // Forward declarations IZDriverManager = interface; IZDriver = interface; IZConnection = interface; IZDatabaseMetadata = interface; IZDatabaseInfo = interface; IZStatement = interface; IZPreparedStatement = interface; IZCallableStatement = interface; IZResultSet = interface; IZResultSetMetadata = interface; IZBlob = interface; IZNotification = interface; IZSequence = interface; IZDataSet = interface; {** Driver Manager interface. } IZDriverManager = interface(IZInterface) ['{8874B9AA-068A-4C0C-AE75-9DB1EA9E3720}'] function GetConnection(const Url: string): IZConnection; function GetConnectionWithParams(const Url: string; Info: TStrings): IZConnection; function GetConnectionWithLogin(const Url: string; const User: string; const Password: string): IZConnection; function GetDriver(const Url: string): IZDriver; function GetClientVersion(const Url: string): Integer; procedure RegisterDriver(Driver: IZDriver); procedure DeregisterDriver(Driver: IZDriver); function GetDrivers: IZCollection; function GetLoginTimeout: Integer; procedure SetLoginTimeout(Seconds: Integer); procedure AddLoggingListener(Listener: IZLoggingListener); procedure RemoveLoggingListener(Listener: IZLoggingListener); procedure LogMessage(Category: TZLoggingCategory; const Protocol: string; const Msg: string); procedure LogError(Category: TZLoggingCategory; const Protocol: string; const Msg: string; ErrorCode: Integer; const Error: string); function ConstructURL(const Protocol, HostName, Database, UserName, Password: String; const Port: Integer; const Properties: TStrings = nil; const LibLocation: String = ''): String; procedure ResolveDatabaseUrl(const Url: string; out HostName: string; out Port: Integer; out Database: string; out UserName: string; out Password: string; ResultInfo: TStrings = nil); overload; procedure ResolveDatabaseUrl(const Url: string; out Database: string); overload; end; {** Database Driver interface. } IZDriver = interface(IZInterface) ['{2157710E-FBD8-417C-8541-753B585332E2}'] function GetSupportedProtocols: TStringDynArray; function GetSupportedClientCodePages(const Url: TZURL; Const {$IFNDEF UNICODE}AutoEncode,{$ENDIF} SupportedsOnly: Boolean; CtrlsCPType: TZControlsCodePage = cCP_UTF16): TStringDynArray; function Connect(const Url: string; Info: TStrings): IZConnection; overload; function Connect(const Url: TZURL): IZConnection; overload; function GetClientVersion(const Url: string): Integer; function AcceptsURL(const Url: string): Boolean; function GetPlainDriver(const Url: TZURL; const InitDriver: Boolean = True): IZPlainDriver; function GetPropertyInfo(const Url: string; Info: TStrings): TStrings; function GetMajorVersion: Integer; function GetMinorVersion: Integer; function GetSubVersion: Integer; function GetTokenizer: IZTokenizer; function GetStatementAnalyser: IZStatementAnalyser; end; {** Database Connection interface. } IZConnection = interface(IZInterface) ['{8EEBBD1A-56D1-4EC0-B3BD-42B60591457F}'] function CreateStatement: IZStatement; function PrepareStatement(const SQL: string): IZPreparedStatement; function PrepareCall(const SQL: string): IZCallableStatement; function CreateStatementWithParams(Info: TStrings): IZStatement; function PrepareStatementWithParams(const SQL: string; Info: TStrings): IZPreparedStatement; function PrepareCallWithParams(const SQL: string; Info: TStrings): IZCallableStatement; function CreateNotification(const Event: string): IZNotification; function CreateSequence(const Sequence: string; BlockSize: Integer): IZSequence; function NativeSQL(const SQL: string): string; procedure SetAutoCommit(Value: Boolean); function GetAutoCommit: Boolean; procedure Commit; procedure Rollback; //2Phase Commit Support initially for PostgresSQL (firmos) 21022006 procedure PrepareTransaction(const transactionid: string); procedure CommitPrepared(const transactionid: string); procedure RollbackPrepared(const transactionid: string); //Ping Server Support (firmos) 27032006 function PingServer: Integer; function EscapeString(Value: RawByteString): RawByteString; procedure Open; procedure Close; function IsClosed: Boolean; function GetDriver: IZDriver; function GetIZPlainDriver: IZPlainDriver; function GetMetadata: IZDatabaseMetadata; function GetParameters: TStrings; function GetClientVersion: Integer; function GetHostVersion: Integer; procedure SetReadOnly(Value: Boolean); function IsReadOnly: Boolean; procedure SetCatalog(const Value: string); function GetCatalog: string; procedure SetTransactionIsolation(Value: TZTransactIsolationLevel); function GetTransactionIsolation: TZTransactIsolationLevel; function GetWarnings: EZSQLWarning; procedure ClearWarnings; function UseMetadata: boolean; procedure SetUseMetadata(Value: Boolean); //EgonHugeist function GetBinaryEscapeString(const Value: RawByteString): String; overload; function GetBinaryEscapeString(const Value: TByteDynArray): String; overload; function GetEscapeString(const Value: ZWideString): ZWideString; overload; function GetEscapeString(const Value: RawByteString): RawByteString; overload; function GetClientCodePageInformations: PZCodePage; function GetAutoEncodeStrings: Boolean; procedure SetAutoEncodeStrings(const Value: Boolean); property AutoEncodeStrings: Boolean read GetAutoEncodeStrings write SetAutoEncodeStrings; function GetEncoding: TZCharEncoding; function GetConSettings: PZConSettings; {$IFDEF ZEOS_TEST_ONLY} function GetTestMode : Byte; procedure SetTestMode(Mode: Byte); {$ENDIF} end; {** Database metadata interface. } IZDatabaseMetadata = interface(IZInterface) ['{FE331C2D-0664-464E-A981-B4F65B85D1A8}'] function GetURL: string; function GetUserName: string; function GetDatabaseInfo: IZDatabaseInfo; function GetTriggers(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const TriggerNamePattern: string): IZResultSet; //EgonHugeist 30.03.2011 function GetCollationAndCharSet(const Catalog, Schema, TableName, ColumnName: String): IZResultSet; //EgonHugeist 10.01.2012 function GetCharacterSets: IZResultSet; //EgonHugeist 19.01.2012 function GetProcedures(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string): IZResultSet; function GetProcedureColumns(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string; const ColumnNamePattern: string): IZResultSet; function GetTables(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const Types: TStringDynArray): IZResultSet; function GetSchemas: IZResultSet; function GetCatalogs: IZResultSet; function GetTableTypes: IZResultSet; function GetColumns(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const ColumnNamePattern: string): IZResultSet; function GetColumnPrivileges(const Catalog: string; const Schema: string; const Table: string; const ColumnNamePattern: string): IZResultSet; function GetTablePrivileges(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string): IZResultSet; function GetBestRowIdentifier(const Catalog: string; const Schema: string; const Table: string; Scope: Integer; Nullable: Boolean): IZResultSet; function GetVersionColumns(const Catalog: string; const Schema: string; const Table: string): IZResultSet; function GetPrimaryKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; function GetImportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; function GetExportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; function GetCrossReference(const PrimaryCatalog: string; const PrimarySchema: string; const PrimaryTable: string; const ForeignCatalog: string; const ForeignSchema: string; const ForeignTable: string): IZResultSet; function GetTypeInfo: IZResultSet; function GetIndexInfo(const Catalog: string; const Schema: string; const Table: string; Unique: Boolean; Approximate: Boolean): IZResultSet; function GetSequences(const Catalog: string; const SchemaPattern: string; const SequenceNamePattern: string): IZResultSet; function GetUDTs(const Catalog: string; const SchemaPattern: string; const TypeNamePattern: string; const Types: TIntegerDynArray): IZResultSet; function GetConnection: IZConnection; function GetIdentifierConvertor: IZIdentifierConvertor; procedure ClearCache;overload; procedure ClearCache(const Key: string);overload; function AddEscapeCharToWildcards(const Pattern:string): string; function NormalizePatternCase(Pattern:String): string; end; {** Database information interface. Used to describe the database as a whole (version, capabilities, policies, etc). } // technobot 2008-06-24 IZDatabaseInfo = interface(IZInterface) ['{107CA354-F594-48F9-8E08-CD797F151EA0}'] // database/driver/server info: function GetDatabaseProductName: string; function GetDatabaseProductVersion: string; function GetDriverName: string; function GetDriverVersion: string; function GetDriverMajorVersion: Integer; function GetDriverMinorVersion: Integer; function GetServerVersion: string; // capabilities (what it can/cannot do): function AllProceduresAreCallable: Boolean; function AllTablesAreSelectable: Boolean; function SupportsMixedCaseIdentifiers: Boolean; function SupportsMixedCaseQuotedIdentifiers: Boolean; function SupportsAlterTableWithAddColumn: Boolean; function SupportsAlterTableWithDropColumn: Boolean; function SupportsColumnAliasing: Boolean; function SupportsConvert: Boolean; function SupportsConvertForTypes(FromType: TZSQLType; ToType: TZSQLType): Boolean; function SupportsTableCorrelationNames: Boolean; function SupportsDifferentTableCorrelationNames: Boolean; function SupportsExpressionsInOrderBy: Boolean; function SupportsOrderByUnrelated: Boolean; function SupportsGroupBy: Boolean; function SupportsGroupByUnrelated: Boolean; function SupportsGroupByBeyondSelect: Boolean; function SupportsLikeEscapeClause: Boolean; function SupportsMultipleResultSets: Boolean; function SupportsMultipleTransactions: Boolean; function SupportsNonNullableColumns: Boolean; function SupportsMinimumSQLGrammar: Boolean; function SupportsCoreSQLGrammar: Boolean; function SupportsExtendedSQLGrammar: Boolean; function SupportsANSI92EntryLevelSQL: Boolean; function SupportsANSI92IntermediateSQL: Boolean; function SupportsANSI92FullSQL: Boolean; function SupportsIntegrityEnhancementFacility: Boolean; function SupportsOuterJoins: Boolean; function SupportsFullOuterJoins: Boolean; function SupportsLimitedOuterJoins: Boolean; function SupportsSchemasInDataManipulation: Boolean; function SupportsSchemasInProcedureCalls: Boolean; function SupportsSchemasInTableDefinitions: Boolean; function SupportsSchemasInIndexDefinitions: Boolean; function SupportsSchemasInPrivilegeDefinitions: Boolean; function SupportsCatalogsInDataManipulation: Boolean; function SupportsCatalogsInProcedureCalls: Boolean; function SupportsCatalogsInTableDefinitions: Boolean; function SupportsCatalogsInIndexDefinitions: Boolean; function SupportsCatalogsInPrivilegeDefinitions: Boolean; function SupportsOverloadPrefixInStoredProcedureName: Boolean; function SupportsPositionedDelete: Boolean; function SupportsPositionedUpdate: Boolean; function SupportsSelectForUpdate: Boolean; function SupportsStoredProcedures: Boolean; function SupportsSubqueriesInComparisons: Boolean; function SupportsSubqueriesInExists: Boolean; function SupportsSubqueriesInIns: Boolean; function SupportsSubqueriesInQuantifieds: Boolean; function SupportsCorrelatedSubqueries: Boolean; function SupportsUnion: Boolean; function SupportsUnionAll: Boolean; function SupportsOpenCursorsAcrossCommit: Boolean; function SupportsOpenCursorsAcrossRollback: Boolean; function SupportsOpenStatementsAcrossCommit: Boolean; function SupportsOpenStatementsAcrossRollback: Boolean; function SupportsTransactions: Boolean; function SupportsTransactionIsolationLevel(Level: TZTransactIsolationLevel): Boolean; function SupportsDataDefinitionAndDataManipulationTransactions: Boolean; function SupportsDataManipulationTransactionsOnly: Boolean; function SupportsResultSetType(_Type: TZResultSetType): Boolean; function SupportsResultSetConcurrency(_Type: TZResultSetType; Concurrency: TZResultSetConcurrency): Boolean; function SupportsBatchUpdates: Boolean; function SupportsNonEscapedSearchStrings: Boolean; function SupportsUpdateAutoIncrementFields: Boolean; // maxima: function GetMaxBinaryLiteralLength: Integer; function GetMaxCharLiteralLength: Integer; function GetMaxColumnNameLength: Integer; function GetMaxColumnsInGroupBy: Integer; function GetMaxColumnsInIndex: Integer; function GetMaxColumnsInOrderBy: Integer; function GetMaxColumnsInSelect: Integer; function GetMaxColumnsInTable: Integer; function GetMaxConnections: Integer; function GetMaxCursorNameLength: Integer; function GetMaxIndexLength: Integer; function GetMaxSchemaNameLength: Integer; function GetMaxProcedureNameLength: Integer; function GetMaxCatalogNameLength: Integer; function GetMaxRowSize: Integer; function GetMaxStatementLength: Integer; function GetMaxStatements: Integer; function GetMaxTableNameLength: Integer; function GetMaxTablesInSelect: Integer; function GetMaxUserNameLength: Integer; // policies (how are various data and operations handled): function IsReadOnly: Boolean; function IsCatalogAtStart: Boolean; function DoesMaxRowSizeIncludeBlobs: Boolean; function NullsAreSortedHigh: Boolean; function NullsAreSortedLow: Boolean; function NullsAreSortedAtStart: Boolean; function NullsAreSortedAtEnd: Boolean; function NullPlusNonNullIsNull: Boolean; function UsesLocalFiles: Boolean; function UsesLocalFilePerTable: Boolean; function StoresUpperCaseIdentifiers: Boolean; function StoresLowerCaseIdentifiers: Boolean; function StoresMixedCaseIdentifiers: Boolean; function StoresUpperCaseQuotedIdentifiers: Boolean; function StoresLowerCaseQuotedIdentifiers: Boolean; function StoresMixedCaseQuotedIdentifiers: Boolean; function GetDefaultTransactionIsolation: TZTransactIsolationLevel; function DataDefinitionCausesTransactionCommit: Boolean; function DataDefinitionIgnoredInTransactions: Boolean; // interface details (terms, keywords, etc): function GetIdentifierQuoteString: string; function GetSchemaTerm: string; function GetProcedureTerm: string; function GetCatalogTerm: string; function GetCatalogSeparator: string; function GetSQLKeywords: string; function GetNumericFunctions: string; function GetStringFunctions: string; function GetSystemFunctions: string; function GetTimeDateFunctions: string; function GetSearchStringEscape: string; function GetExtraNameCharacters: string; end; {** Generic SQL statement interface. } IZStatement = interface(IZInterface) ['{22CEFA7E-6A6D-48EC-BB9B-EE66056E90F1}'] function ExecuteQuery(const SQL: ZWideString): IZResultSet; overload; function ExecuteUpdate(const SQL: ZWideString): Integer; overload; function Execute(const SQL: ZWideString): Boolean; overload; function ExecuteQuery(const SQL: RawByteString): IZResultSet; overload; function ExecuteUpdate(const SQL: RawByteString): Integer; overload; function Execute(const SQL: RawByteString): Boolean; overload; procedure Close; function GetMaxFieldSize: Integer; procedure SetMaxFieldSize(Value: Integer); function GetMaxRows: Integer; procedure SetMaxRows(Value: Integer); procedure SetEscapeProcessing(Value: Boolean); function GetQueryTimeout: Integer; procedure SetQueryTimeout(Value: Integer); procedure Cancel; procedure SetCursorName(const Value: AnsiString); function GetResultSet: IZResultSet; function GetUpdateCount: Integer; function GetMoreResults: Boolean; procedure SetFetchDirection(Value: TZFetchDirection); function GetFetchDirection: TZFetchDirection; procedure SetFetchSize(Value: Integer); function GetFetchSize: Integer; procedure SetResultSetConcurrency(Value: TZResultSetConcurrency); function GetResultSetConcurrency: TZResultSetConcurrency; procedure SetResultSetType(Value: TZResultSetType); function GetResultSetType: TZResultSetType; procedure SetPostUpdates(Value: TZPostUpdatesMode); function GetPostUpdates: TZPostUpdatesMode; procedure SetLocateUpdates(Value: TZLocateUpdatesMode); function GetLocateUpdates: TZLocateUpdatesMode; procedure AddBatch(const SQL: string); procedure ClearBatch; function ExecuteBatch: TIntegerDynArray; function GetConnection: IZConnection; function GetParameters: TStrings; function GetChunkSize: Integer; function GetWarnings: EZSQLWarning; procedure ClearWarnings; function GetEncodedSQL(const SQL: {$IF defined(FPC) and defined(WITH_RAWBYTESTRING)}RawByteString{$ELSE}String{$IFEND}): RawByteString; end; {** Prepared SQL statement interface. } IZPreparedStatement = interface(IZStatement) ['{990B8477-AF11-4090-8821-5B7AFEA9DD70}'] function ExecuteQueryPrepared: IZResultSet; function ExecuteUpdatePrepared: Integer; function ExecutePrepared: Boolean; function GetSQL : String; // procedure Prepare; // procedure Unprepare; // function IsPrepared: Boolean; procedure SetDefaultValue(ParameterIndex: Integer; const Value: string); procedure SetNull(ParameterIndex: Integer; SQLType: TZSQLType); procedure SetBoolean(ParameterIndex: Integer; Value: Boolean); procedure SetByte(ParameterIndex: Integer; Value: Byte); procedure SetShort(ParameterIndex: Integer; Value: SmallInt); procedure SetInt(ParameterIndex: Integer; Value: Integer); procedure SetLong(ParameterIndex: Integer; Value: Int64); procedure SetFloat(ParameterIndex: Integer; Value: Single); procedure SetDouble(ParameterIndex: Integer; Value: Double); procedure SetBigDecimal(ParameterIndex: Integer; Value: Extended); procedure SetPChar(ParameterIndex: Integer; Value: PChar); procedure SetString(ParameterIndex: Integer; const Value: String); procedure SetUnicodeString(ParameterIndex: Integer; const Value: ZWideString); //AVZ procedure SetBytes(ParameterIndex: Integer; const Value: TByteDynArray); procedure SetDate(ParameterIndex: Integer; Value: TDateTime); procedure SetTime(ParameterIndex: Integer; Value: TDateTime); procedure SetTimestamp(ParameterIndex: Integer; Value: TDateTime); procedure SetAsciiStream(ParameterIndex: Integer; Value: TStream); procedure SetUnicodeStream(ParameterIndex: Integer; Value: TStream); procedure SetBinaryStream(ParameterIndex: Integer; Value: TStream); procedure SetBlob(ParameterIndex: Integer; SQLType: TZSQLType; Value: IZBlob); procedure SetValue(ParameterIndex: Integer; const Value: TZVariant); procedure ClearParameters; procedure AddBatchPrepared; function GetMetadata: IZResultSetMetadata; end; {** Callable SQL statement interface. } IZCallableStatement = interface(IZPreparedStatement) ['{E6FA6C18-C764-4C05-8FCB-0582BDD1EF40}'] function IsFunction: Boolean; { Multiple ResultSet support API } function HasMoreResultSets: Boolean; function GetFirstResultSet: IZResultSet; function GetPreviousResultSet: IZResultSet; function GetNextResultSet: IZResultSet; function GetLastResultSet: IZResultSet; function BOR: Boolean; function EOR: Boolean; function GetResultSetByIndex(const Index: Integer): IZResultSet; function GetResultSetCount: Integer; procedure RegisterOutParameter(ParameterIndex: Integer; SQLType: Integer); procedure RegisterParamType(ParameterIndex:integer;ParamType:Integer); function WasNull: Boolean; function IsNull(ParameterIndex: Integer): Boolean; function GetPChar(ParameterIndex: Integer): PChar; function GetString(ParameterIndex: Integer): String; function GetUnicodeString(ParameterIndex: Integer): WideString; function GetBoolean(ParameterIndex: Integer): Boolean; function GetByte(ParameterIndex: Integer): Byte; function GetShort(ParameterIndex: Integer): SmallInt; function GetInt(ParameterIndex: Integer): Integer; function GetLong(ParameterIndex: Integer): Int64; function GetFloat(ParameterIndex: Integer): Single; function GetDouble(ParameterIndex: Integer): Double; function GetBigDecimal(ParameterIndex: Integer): Extended; function GetBytes(ParameterIndex: Integer): TByteDynArray; function GetDate(ParameterIndex: Integer): TDateTime; function GetTime(ParameterIndex: Integer): TDateTime; function GetTimestamp(ParameterIndex: Integer): TDateTime; function GetValue(ParameterIndex: Integer): TZVariant; end; IZParamNamedCallableStatement = interface(IZCallableStatement) ['{99882891-81B2-4F3E-A3D7-35B6DCAA7136}'] procedure RegisterParamTypeAndName(const ParameterIndex:integer; const ParamTypeName, ParamName: String; Const ColumnSize, Precision: Integer); end; {** Rows returned by SQL query. } IZResultSet = interface(IZInterface) ['{8F4C4D10-2425-409E-96A9-7142007CC1B2}'] function Next: Boolean; procedure Close; function WasNull: Boolean; //====================================================================== // Methods for accessing results by column index //====================================================================== function IsNull(ColumnIndex: Integer): Boolean; function GetPChar(ColumnIndex: Integer): PChar; function GetString(ColumnIndex: Integer): String; function GetBinaryString(ColumnIndex: Integer): RawByteString; function GetUnicodeString(ColumnIndex: Integer): WideString; function GetBoolean(ColumnIndex: Integer): Boolean; function GetByte(ColumnIndex: Integer): Byte; function GetShort(ColumnIndex: Integer): SmallInt; function GetInt(ColumnIndex: Integer): Integer; function GetLong(ColumnIndex: Integer): Int64; function GetFloat(ColumnIndex: Integer): Single; function GetDouble(ColumnIndex: Integer): Double; function GetBigDecimal(ColumnIndex: Integer): Extended; function GetBytes(ColumnIndex: Integer): TByteDynArray; function GetDate(ColumnIndex: Integer): TDateTime; function GetTime(ColumnIndex: Integer): TDateTime; function GetTimestamp(ColumnIndex: Integer): TDateTime; function GetAsciiStream(ColumnIndex: Integer): TStream; function GetUnicodeStream(ColumnIndex: Integer): TStream; function GetBinaryStream(ColumnIndex: Integer): TStream; function GetBlob(ColumnIndex: Integer): IZBlob; function GetDataSet(ColumnIndex: Integer): IZDataSet; function GetValue(ColumnIndex: Integer): TZVariant; function GetDefaultExpression(ColumnIndex: Integer): string; //====================================================================== // Methods for accessing results by column name //====================================================================== function IsNullByName(const ColumnName: string): Boolean; function GetPCharByName(const ColumnName: string): PChar; function GetStringByName(const ColumnName: string): String; function GetBinaryStringByName(const ColumnName: string): RawByteString; function GetUnicodeStringByName(const ColumnName: string): WideString; function GetBooleanByName(const ColumnName: string): Boolean; function GetByteByName(const ColumnName: string): Byte; function GetShortByName(const ColumnName: string): SmallInt; function GetIntByName(const ColumnName: string): Integer; function GetLongByName(const ColumnName: string): Int64; function GetFloatByName(const ColumnName: string): Single; function GetDoubleByName(const ColumnName: string): Double; function GetBigDecimalByName(const ColumnName: string): Extended; function GetBytesByName(const ColumnName: string): TByteDynArray; function GetDateByName(const ColumnName: string): TDateTime; function GetTimeByName(const ColumnName: string): TDateTime; function GetTimestampByName(const ColumnName: string): TDateTime; function GetAsciiStreamByName(const ColumnName: string): TStream; function GetUnicodeStreamByName(const ColumnName: string): TStream; function GetBinaryStreamByName(const ColumnName: string): TStream; function GetBlobByName(const ColumnName: string): IZBlob; function GetDataSetByName(const ColumnName: String): IZDataSet; function GetValueByName(const ColumnName: string): TZVariant; //===================================================================== // Advanced features: //===================================================================== function GetWarnings: EZSQLWarning; procedure ClearWarnings; function GetCursorName: AnsiString; function GetMetadata: IZResultSetMetadata; function FindColumn(const ColumnName: string): Integer; //--------------------------------------------------------------------- // Traversal/Positioning //--------------------------------------------------------------------- function IsBeforeFirst: Boolean; function IsAfterLast: Boolean; function IsFirst: Boolean; function IsLast: Boolean; procedure BeforeFirst; procedure AfterLast; function First: Boolean; function Last: Boolean; function GetRow: Integer; function MoveAbsolute(Row: Integer): Boolean; function MoveRelative(Rows: Integer): Boolean; function Previous: Boolean; //--------------------------------------------------------------------- // Properties //--------------------------------------------------------------------- procedure SetFetchDirection(Value: TZFetchDirection); function GetFetchDirection: TZFetchDirection; procedure SetFetchSize(Value: Integer); function GetFetchSize: Integer; function GetType: TZResultSetType; function GetConcurrency: TZResultSetConcurrency; function GetPostUpdates: TZPostUpdatesMode; function GetLocateUpdates: TZLocateUpdatesMode; //--------------------------------------------------------------------- // Updates //--------------------------------------------------------------------- function RowUpdated: Boolean; function RowInserted: Boolean; function RowDeleted: Boolean; procedure UpdateNull(ColumnIndex: Integer); procedure UpdateBoolean(ColumnIndex: Integer; Value: Boolean); procedure UpdateByte(ColumnIndex: Integer; Value: ShortInt); procedure UpdateShort(ColumnIndex: Integer; Value: SmallInt); procedure UpdateInt(ColumnIndex: Integer; Value: Integer); procedure UpdateLong(ColumnIndex: Integer; Value: Int64); procedure UpdateFloat(ColumnIndex: Integer; Value: Single); procedure UpdateDouble(ColumnIndex: Integer; Value: Double); procedure UpdateBigDecimal(ColumnIndex: Integer; Value: Extended); procedure UpdatePChar(ColumnIndex: Integer; Value: PChar); procedure UpdateString(ColumnIndex: Integer; const Value: String); procedure UpdateBinaryString(ColumnIndex: Integer; const Value: RawByteString); procedure UpdateUnicodeString(ColumnIndex: Integer; const Value: WideString); procedure UpdateBytes(ColumnIndex: Integer; const Value: TByteDynArray); procedure UpdateDate(ColumnIndex: Integer; Value: TDateTime); procedure UpdateTime(ColumnIndex: Integer; Value: TDateTime); procedure UpdateTimestamp(ColumnIndex: Integer; Value: TDateTime); procedure UpdateAsciiStream(ColumnIndex: Integer; Value: TStream); procedure UpdateUnicodeStream(ColumnIndex: Integer; Value: TStream); procedure UpdateBinaryStream(ColumnIndex: Integer; Value: TStream); procedure UpdateDataSet(ColumnIndex: Integer; Value: IZDataSet); procedure UpdateValue(ColumnIndex: Integer; const Value: TZVariant); procedure UpdateDefaultExpression(ColumnIndex: Integer; const Value: string); //====================================================================== // Methods for accessing results by column name //====================================================================== procedure UpdateNullByName(const ColumnName: string); procedure UpdateBooleanByName(const ColumnName: string; Value: Boolean); procedure UpdateByteByName(const ColumnName: string; Value: ShortInt); procedure UpdateShortByName(const ColumnName: string; Value: SmallInt); procedure UpdateIntByName(const ColumnName: string; Value: Integer); procedure UpdateLongByName(const ColumnName: string; Value: Int64); procedure UpdateFloatByName(const ColumnName: string; Value: Single); procedure UpdateDoubleByName(const ColumnName: string; Value: Double); procedure UpdateBigDecimalByName(const ColumnName: string; Value: Extended); procedure UpdatePCharByName(const ColumnName: string; Value: PChar); procedure UpdateStringByName(const ColumnName: string; const Value: String); procedure UpdateBinaryStringByName(const ColumnName: string; const Value: RawByteString); procedure UpdateUnicodeStringByName(const ColumnName: string; const Value: WideString); procedure UpdateBytesByName(const ColumnName: string; const Value: TByteDynArray); procedure UpdateDateByName(const ColumnName: string; Value: TDateTime); procedure UpdateTimeByName(const ColumnName: string; Value: TDateTime); procedure UpdateTimestampByName(const ColumnName: string; Value: TDateTime); procedure UpdateAsciiStreamByName(const ColumnName: string; Value: TStream); procedure UpdateUnicodeStreamByName(const ColumnName: string; Value: TStream); procedure UpdateBinaryStreamByName(const ColumnName: string; Value: TStream); procedure UpdateDataSetByName(const ColumnName: string; Value: IZDataSet); procedure UpdateValueByName(const ColumnName: string; const Value: TZVariant); procedure InsertRow; procedure UpdateRow; procedure DeleteRow; procedure RefreshRow; procedure CancelRowUpdates; procedure MoveToInsertRow; procedure MoveToCurrentRow; // procedure MoveToSearchRow; // function Search(CaseInsensitive, PartialKey: Boolean): Boolean; // function Compare(Row: Integer; CaseInsensitive, PartialKey: Boolean): // Boolean; function CompareRows(Row1, Row2: Integer; const ColumnIndices: TIntegerDynArray; const ColumnDirs: TBooleanDynArray): Integer; function GetStatement: IZStatement; function GetConSettings: PZConsettings; end; {** TDataSet interface} IZDataSet = interface(IZInterface) ['{DBC24011-EF26-4FD8-AC8B-C3E01619494A}'] function GetDataSet: TDataSet; function IsEmpty: Boolean; end; {** ResultSet metadata interface. } IZResultSetMetadata = interface(IZInterface) ['{47CA2144-2EA7-42C4-8444-F5154369B2D7}'] function GetColumnCount: Integer; function IsAutoIncrement(Column: Integer): Boolean; function IsCaseSensitive(Column: Integer): Boolean; function IsSearchable(Column: Integer): Boolean; function IsCurrency(Column: Integer): Boolean; function IsNullable(Column: Integer): TZColumnNullableType; function IsSigned(Column: Integer): Boolean; function GetColumnDisplaySize(Column: Integer): Integer; function GetColumnLabel(Column: Integer): string; function GetColumnName(Column: Integer): string; function GetSchemaName(Column: Integer): string; function GetPrecision(Column: Integer): Integer; function GetScale(Column: Integer): Integer; function GetTableName(Column: Integer): string; function GetCatalogName(Column: Integer): string; function GetColumnType(Column: Integer): TZSQLType; function GetColumnTypeName(Column: Integer): string; function IsReadOnly(Column: Integer): Boolean; function IsWritable(Column: Integer): Boolean; function IsDefinitelyWritable(Column: Integer): Boolean; function GetDefaultValue(Column: Integer): string; function HasDefaultValue(Column: Integer): Boolean; end; {** External or internal blob wrapper object. } IZBlob = interface(IZInterface) ['{47D209F1-D065-49DD-A156-EFD1E523F6BF}'] function IsEmpty: Boolean; function IsUpdated: Boolean; function Length: LongInt; function WasDecoded: Boolean; function Connection: IZConnection; function GetString: RawByteString; procedure SetString(const Value: RawByteString); function GetUnicodeString: WideString; procedure SetUnicodeString(const Value: WideString); function GetBytes: TByteDynArray; procedure SetBytes(const Value: TByteDynArray); function GetUnicodeStream: TStream; function GetStream: TStream; procedure SetStream(Value: TStream; Encoded: Boolean = False); function GetBuffer: Pointer; procedure SetBuffer(Buffer: Pointer; Length: Integer); procedure Clear; function Clone: IZBlob; end; {** Database notification interface. } IZNotification = interface(IZInterface) ['{BF785C71-EBE9-4145-8DAE-40674E45EF6F}'] function GetEvent: string; procedure Listen; procedure Unlisten; procedure DoNotify; function CheckEvents: string; function GetConnection: IZConnection; end; {** Database sequence generator interface. } IZSequence = interface(IZInterface) ['{A9A54FE5-0DBE-492F-8DA6-04AC5FCE779C}'] function GetName: string; function GetBlockSize: Integer; procedure SetName(const Value: string); procedure SetBlockSize(const Value: Integer); function GetCurrentValue: Int64; function GetNextValue: Int64; function GetCurrentValueSQL: string; function GetNextValueSQL: string; function GetConnection: IZConnection; end; var {** The common driver manager object. } DriverManager: IZDriverManager; implementation uses ZMessages; type {** Driver Manager interface. } TZDriverManager = class(TInterfacedObject, IZDriverManager) private FDrivers: IZCollection; FLoginTimeout: Integer; FLoggingListeners: IZCollection; FURL: TZURL; public constructor Create; destructor Destroy; override; function GetConnection(const Url: string): IZConnection; function GetConnectionWithParams(const Url: string; Info: TStrings): IZConnection; function GetConnectionWithLogin(const Url: string; const User: string; const Password: string): IZConnection; function GetDriver(const Url: string): IZDriver; procedure RegisterDriver(Driver: IZDriver); procedure DeregisterDriver(Driver: IZDriver); function GetDrivers: IZCollection; function GetClientVersion(const Url: string): Integer; function GetLoginTimeout: Integer; procedure SetLoginTimeout(Value: Integer); procedure AddLoggingListener(Listener: IZLoggingListener); procedure RemoveLoggingListener(Listener: IZLoggingListener); procedure LogMessage(Category: TZLoggingCategory; const Protocol: string; const Msg: string); procedure LogError(Category: TZLoggingCategory; const Protocol: string; const Msg: string; ErrorCode: Integer; const Error: string); function ConstructURL(const Protocol, HostName, Database, UserName, Password: String; const Port: Integer; const Properties: TStrings = nil; const LibLocation: String = ''): String; procedure ResolveDatabaseUrl(const Url: string; out HostName: string; out Port: Integer; out Database: string; out UserName: string; out Password: string; ResultInfo: TStrings = nil); overload; procedure ResolveDatabaseUrl(const Url: string; out Database: string); overload; end; { TZDriverManager } {** Constructs this object with default properties. } constructor TZDriverManager.Create; begin FDrivers := TZCollection.Create; FLoginTimeout := 0; FLoggingListeners := TZCollection.Create; FURL := TZURL.Create; end; {** Destroys this object and cleanups the memory. } destructor TZDriverManager.Destroy; begin FURL.Free; FDrivers := nil; FLoggingListeners := nil; inherited Destroy; end; {** Gets a collection of registered drivers. @return an unmodifiable collection with registered drivers. } function TZDriverManager.GetDrivers: IZCollection; begin Result := TZUnmodifiableCollection.Create(FDrivers); end; {** Gets a login timeout value. @return a login timeout. } function TZDriverManager.GetLoginTimeout: Integer; begin Result := FLoginTimeout; end; {** Sets a new login timeout value. @param Seconds a new login timeout in seconds. } procedure TZDriverManager.SetLoginTimeout(Value: Integer); begin FLoginTimeout := Value; end; {** Registers a driver for specific database. @param Driver a driver to be registered. } procedure TZDriverManager.RegisterDriver(Driver: IZDriver); begin if not FDrivers.Contains(Driver) then FDrivers.Add(Driver); end; {** Unregisters a driver for specific database. @param Driver a driver to be unregistered. } procedure TZDriverManager.DeregisterDriver(Driver: IZDriver); begin FDrivers.Remove(Driver); end; {** Gets a driver which accepts the specified url. @param Url a database connection url. @return a found driver or null otherwise. } function TZDriverManager.GetDriver(const Url: string): IZDriver; var I: Integer; Current: IZDriver; begin Result := nil; for I := 0 to FDrivers.Count - 1 do begin Current := FDrivers[I] as IZDriver; if Current.AcceptsURL(Url) then begin Result := Current; Break; end; end; end; {** Locates a required driver and opens a connection to the specified database. @param Url a database connection Url. @param Info an extra connection parameters. @return an opened connection. } function TZDriverManager.GetConnectionWithParams(const Url: string; Info: TStrings): IZConnection; var Driver: IZDriver; begin Driver := GetDriver(Url); if Driver = nil then raise EZSQLException.Create(SDriverWasNotFound); Result := Driver.Connect(Url, Info); end; {** Locates a required driver and returns the client library version number. @param Url a database connection Url. @return client library version number. } function TZDriverManager.GetClientVersion(const Url: string): Integer; var Driver: IZDriver; begin Driver := GetDriver(Url); if Driver = nil then raise EZSQLException.Create(SDriverWasNotFound); Result := Driver.GetClientVersion(Url); end; {** Locates a required driver and opens a connection to the specified database. @param Url a database connection Url. @param User a user's name. @param Password a user's password. @return an opened connection. } function TZDriverManager.GetConnectionWithLogin(const Url: string; const User: string; const Password: string): IZConnection; var Info: TStrings; begin Info := TStringList.Create; try Info.Add('username=' + User); Info.Add('password=' + Password); Result := GetConnectionWithParams(Url, Info); finally Info.Free; end; end; {** Locates a required driver and opens a connection to the specified database. @param Url a database connection Url. @return an opened connection. } function TZDriverManager.GetConnection(const Url: string): IZConnection; begin Result := GetConnectionWithParams(Url, nil); end; {** Adds a logging listener to log SQL events. @param Listener a logging interface to be added. } procedure TZDriverManager.AddLoggingListener(Listener: IZLoggingListener); begin FLoggingListeners.Add(Listener); end; {** Removes a logging listener from the list. @param Listener a logging interface to be removed. } procedure TZDriverManager.RemoveLoggingListener(Listener: IZLoggingListener); begin FLoggingListeners.Remove(Listener); end; {** Logs a message about event with error result code. @param Category a category of the message. @param Protocol a name of the protocol. @param Msg a description message. @param ErrorCode an error code. @param Error an error message. } procedure TZDriverManager.LogError(Category: TZLoggingCategory; const Protocol: string; const Msg: string; ErrorCode: Integer; const Error: string); var I: Integer; Listener: IZLoggingListener; Event: TZLoggingEvent; begin if FLoggingListeners.Count = 0 then Exit; Event := TZLoggingEvent.Create(Category, Protocol, Msg, ErrorCode, Error); try for I := 0 to FLoggingListeners.Count - 1 do begin Listener := FLoggingListeners[I] as IZLoggingListener; try Listener.LogEvent(Event); except end; end; finally Event.Destroy; end; end; {** Logs a message about event with normal result code. @param Category a category of the message. @param Protocol a name of the protocol. @param Msg a description message. } procedure TZDriverManager.LogMessage(Category: TZLoggingCategory; const Protocol: string; const Msg: string); begin if FLoggingListeners.Count = 0 then Exit; LogError(Category, Protocol, Msg, 0, ''); end; {** Constructs a valid URL @param Protocol the Driver-protocol (must be assigned). @param HostName the hostname (could be empty). @param Database the connection-database (could be empty). @param UserName the username (could be empty). @param Password the password(could be empty). @param Port the Server-Port (could be 0). @param Properties the Database-Properties (could be empty). } function TZDriverManager.ConstructURL(const Protocol, HostName, Database, UserName, Password: String; const Port: Integer; const Properties: TStrings = nil; const LibLocation: String = ''): String; begin FURL.Protocol := Protocol; FURL.HostName := HostName; FURL.Database := DataBase; FURL.UserName := UserName; FURL.Password := Password; FURL.Port := Port; if Assigned(Properties) then FURL.Properties.Text := Properties.Text; FURL.LibLocation := LibLocation; Result := FURL.URL; end; {** Resolves a database URL and fills the database connection parameters. @param Url an initial database URL. @param HostName a name of the database host. @param Port a port number. @param Database a database name. @param UserName a name of the database user. @param Password a user's password. @param ResutlInfo a result info parameters. } procedure TZDriverManager.ResolveDatabaseUrl(const Url: string; out HostName: string; out Port: Integer; out Database: string; out UserName: string; out Password: string; ResultInfo: TStrings = nil); begin FURL.URL := Url; HostName := FURL.HostName; Port := FURL.Port; DataBase := FURL.Database; UserName := FURL.UserName; PassWord := FURL.Password; if Assigned(ResultInfo) then ResultInfo.Text := FURL.Properties.Text; end; {** Resolves a database URL and fills the database parameter for MetaData. @param Url an initial database URL. @param Database a database name. } procedure TZDriverManager.ResolveDatabaseUrl(const Url: string; out Database: string); begin FURL.URL := Url; DataBase := FURL.Database; end; { EZSQLThrowable } {** Creates an exception with message string. @param Msg a error description. } constructor EZSQLThrowable.CreateClone(const E: EZSQLThrowable); begin inherited Create(E.Message); FErrorCode:=E.ErrorCode; FStatusCode:=E.Statuscode; end; constructor EZSQLThrowable.Create(const Msg: string); begin inherited Create(Msg); FErrorCode := -1; end; {** Creates an exception with message string. @param Msg a error description. @param ErrorCode a native server error code. } constructor EZSQLThrowable.CreateWithCode(const ErrorCode: Integer; const Msg: string); begin inherited Create(Msg); FErrorCode := ErrorCode; end; constructor EZSQLThrowable.CreateWithStatus(const StatusCode, Msg: string); begin inherited Create(Msg); FStatusCode := StatusCode; end; initialization DriverManager := TZDriverManager.Create; finalization DriverManager := nil; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcLogging.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Database Logging Classes and Interfaces } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcLogging; interface {$I ZDbc.inc} uses SysUtils, ZClasses; type {** Defines a time or the message. } TZLoggingCategory = (lcConnect, lcDisconnect, lcTransaction, lcExecute, lcOther, lcPrepStmt, lcBindPrepStmt, lcExecPrepStmt, lcUnprepStmt); {** Defines a object for logging event. } TZLoggingEvent = class; {** Defines an interface to format logging events. } IZLoggingFormatter = interface (IZInterface) // ['{53559F5F-AC22-4DDC-B2EA-45D21ADDD2D5}'] function Format(LoggingEvent: TZLoggingEvent) : string; end; { TZLoggingFormatter } {** Defines a object for logging event. } TZLoggingFormatter = class (TInterfacedObject, IZLoggingFormatter) private public function Format(LoggingEvent: TZLoggingEvent) : string; virtual; end; {** Defines a object for logging event. } TZLoggingEvent = class (TObject) private FCategory: TZLoggingCategory; FProtocol: string; FMessage: string; FErrorCode: Integer; FError: string; FTimestamp: TDateTime; public constructor Create(Category: TZLoggingCategory; Protocol: string; Msg: string; ErrorCode: Integer; Error: string); function AsString(LoggingFormatter:IZLoggingFormatter = nil): string; property Category: TZLoggingCategory read FCategory; property Protocol: string read FProtocol; property Message: string read FMessage; property ErrorCode: Integer read FErrorCode; property Error: string read FError; property Timestamp: TDateTime read FTimestamp; end; {** Defines an interface to accept logging events. } IZLoggingListener = interface (IZInterface) ['{53559F5F-AC22-4DDC-B2EA-45D21ADDD2D4}'] procedure LogEvent(Event: TZLoggingEvent); end; implementation var DefaultLoggingFormatter: TZLoggingFormatter; { TZLoggingFormatter } function TZLoggingFormatter.Format(LoggingEvent: TZLoggingEvent): string; begin Result := FormatDateTime('yyyy-mm-dd hh:mm:ss', LoggingEvent.Timestamp) + ' cat: '; case LoggingEvent.Category of lcConnect: Result := Result + 'Connect'; lcDisconnect: Result := Result + 'Disconnect'; lcTransaction: Result := Result + 'Transaction'; lcExecute: Result := Result + 'Execute'; lcPrepStmt: Result := Result + 'Prepare'; lcBindPrepStmt: Result := Result + 'Bind prepared'; lcExecPrepStmt: Result := Result + 'Execute prepared'; lcUnprepStmt: Result := Result + 'Unprepare prepared'; else Result := Result + 'Other'; end; if LoggingEvent.Protocol <> '' then Result := Result + ', proto: ' + LoggingEvent.Protocol; Result := Result + ', msg: ' + LoggingEvent.Message; if (LoggingEvent.ErrorCode <> 0) or (LoggingEvent.Error <> '') then begin Result := Result + ', errcode: ' + IntToStr(LoggingEvent.ErrorCode) + ', error: ' + LoggingEvent.Error; end; end; { TZLoggingEvent } {** Constructs this logging event. @param Protocol a DBC protocol. @param Msg a description message. @param ErrorCode an error code. @param Error an error message. } constructor TZLoggingEvent.Create(Category: TZLoggingCategory; Protocol: string; Msg: string; ErrorCode: Integer; Error: string); begin FCategory := Category; FProtocol := Protocol; FMessage := Msg; FErrorCode := ErrorCode; FError := Error; FTimestamp := Now; end; {** Gets a string representation for this event. @returns a string representation. } function TZLoggingEvent.AsString(LoggingFormatter:IZLoggingFormatter = nil): string; begin If Assigned(LoggingFormatter) then Result := LoggingFormatter.Format(Self) else Result := DefaultLoggingFormatter.Format(Self); end; initialization DefaultLoggingFormatter := TZLoggingFormatter.Create; finalization DefaultLoggingFormatter.Free; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcMetadata.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Abstract Database Connectivity Classes } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcMetadata; interface {$I ZDbc.inc} uses {$IFDEF FPC} {$IFDEF WIN32} Comobj, {$ENDIF} {$ENDIF} Types, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, Contnrs, ZSysUtils, ZClasses, ZDbcIntfs, ZDbcResultSetMetadata, ZDbcCachedResultSet, ZDbcCache, ZCompatibility, ZSelectSchema, ZURL, ZDbcConnection; const procedureColumnUnknown = 0; procedureColumnIn = 1; procedureColumnInOut = 2; procedureColumnOut = 4; procedureColumnReturn = 5; procedureColumnResult = 3; procedureNoNulls = 0; procedureNullable = 1; procedureNullableUnknown = 2; type TZWildcardsSet= {$IFDEF UNICODE}TSysCharSet{$ELSE}set of Char{$ENDIF}; {** Defines a metadata resultset column definition. } TZMetadataColumnDef = {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif} record Name: string; SQLType: TZSQLType; Length: Integer end; {** Defines a dynamic array of metadata column definitions. } TZMetadataColumnDefs = array of TZMetadataColumnDef; {** Represents a Virtual ResultSet interface. } IZVirtualResultSet = interface(IZCachedResultSet) ['{D84055AC-BCD5-40CD-B408-6F11AF000C96}'] procedure SetType(Value: TZResultSetType); procedure SetConcurrency(Value: TZResultSetConcurrency); end; {** Implements Virtual ResultSet. } TZVirtualResultSet = class(TZAbstractCachedResultSet, IZVirtualResultSet) protected procedure CalculateRowDefaults(RowAccessor: TZRowAccessor); override; procedure PostRowUpdates(OldRowAccessor, NewRowAccessor: TZRowAccessor); override; public constructor CreateWithStatement(const SQL: string; Statement: IZStatement; ConSettings: PZConSettings); constructor CreateWithColumns(ColumnsInfo: TObjectList; const SQL: string; ConSettings: PZConSettings); destructor Destroy; override; end; {** Implements Abstract Database Metadata. } { TZAbstractDatabaseMetadata } TZAbstractDatabaseMetadata = class(TContainedObject, IZDatabaseMetadata) private FConnection: Pointer; FUrl: TZURL; FCachedResultSets: IZHashMap; FDatabaseInfo: IZDatabaseInfo; FConSettings: PZConSettings; FIC: IZIdentifierConvertor; function GetInfo: TStrings; function GetURLString: String; function StripEscape(const Pattern: string): string; function HasNoWildcards(const Pattern: string): boolean; protected FDatabase: String; WildcardsArray: array of char; //Added by Cipto function EscapeString(const S: string): string; virtual; function DecomposeObjectString(const S: String): String; virtual; function CreateDatabaseInfo: IZDatabaseInfo; virtual; // technobot 2008-06-24 function GetStatement: IZSTatement; // technobot 2008-06-28 - moved from descendants { Metadata ResultSets Caching. } procedure AddResultSetToCache(const Key: string; ResultSet: IZResultSet); function GetResultSetFromCache(const Key: string): IZResultSet; function ConstructVirtualResultSet(ColumnsDefs: TZMetadataColumnDefs): IZVirtualResultSet; function CopyToVirtualResultSet(SrcResultSet: IZResultSet; DestResultSet: IZVirtualResultSet): IZVirtualResultSet; function CloneCachedResultSet(ResultSet: IZResultSet): IZResultSet; function ConstructNameCondition(Pattern: string; Column: string): string; virtual; function AddEscapeCharToWildcards(const Pattern:string): string; function GetWildcardsSet:TZWildcardsSet; procedure FillWildcards; virtual; function NormalizePatternCase(Pattern:String): string; property Url: string read GetURLString; property Info: TStrings read GetInfo; property CachedResultSets: IZHashMap read FCachedResultSets write FCachedResultSets; property ConSettings: PZConSettings read FConSettings write FConSettings; property IC: IZIdentifierConvertor read FIC; protected function UncachedGetTables(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const Types: TStringDynArray): IZResultSet; virtual; function UncachedGetSchemas: IZResultSet; virtual; function UncachedGetCatalogs: IZResultSet; virtual; function UncachedGetTableTypes: IZResultSet; virtual; function UncachedGetColumns(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const ColumnNamePattern: string): IZResultSet; virtual; function UncachedGetTablePrivileges(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string): IZResultSet; virtual; function UncachedGetColumnPrivileges(const Catalog: string; const Schema: string; const Table: string; const ColumnNamePattern: string): IZResultSet; virtual; function UncachedGetPrimaryKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; virtual; function UncachedGetImportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; virtual; function UncachedGetExportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; virtual; function UncachedGetCrossReference(const PrimaryCatalog: string; const PrimarySchema: string; const PrimaryTable: string; const ForeignCatalog: string; const ForeignSchema: string; const ForeignTable: string): IZResultSet; virtual; function UncachedGetIndexInfo(const Catalog: string; const Schema: string; const Table: string; Unique: Boolean; Approximate: Boolean): IZResultSet; virtual; function UncachedGetSequences(const Catalog: string; const SchemaPattern: string; const SequenceNamePattern: string): IZResultSet; virtual; function UncachedGetTriggers(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const TriggerNamePattern: string): IZResultSet; virtual; //EgonHugeist function UncachedGetCollationAndCharSet(const Catalog, SchemaPattern, TableNamePattern, ColumnNamePattern: string): IZResultSet; virtual; //EgonHugeist function UncachedGetCharacterSets: IZResultSet; virtual; //EgonHugeist function UncachedGetProcedures(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string): IZResultSet; virtual; function UncachedGetProcedureColumns(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string; const ColumnNamePattern: string): IZResultSet; virtual; function UncachedGetBestRowIdentifier(const Catalog: string; const Schema: string; const Table: string; Scope: Integer; Nullable: Boolean): IZResultSet; virtual; function UncachedGetVersionColumns(const Catalog: string; const Schema: string; const Table: string): IZResultSet; virtual; function UncachedGetTypeInfo: IZResultSet; virtual; function UncachedGetUDTs(const Catalog: string; const SchemaPattern: string; const TypeNamePattern: string; const Types: TIntegerDynArray): IZResultSet; virtual; public constructor Create(Connection: TZAbstractConnection; const Url: TZURL); virtual; destructor Destroy; override; function GetURL: string; virtual; function GetUserName: string; virtual; function GetDatabaseInfo: IZDatabaseInfo; // technobot 2008-06-24 - see also CreateDatabaseInfo method. function GetTables(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const Types: TStringDynArray): IZResultSet; function GetSchemas: IZResultSet; function GetCatalogs: IZResultSet; function GetTableTypes: IZResultSet; function GetColumns(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const ColumnNamePattern: string): IZResultSet; function GetTablePrivileges(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string): IZResultSet; function GetColumnPrivileges(const Catalog: string; const Schema: string; const Table: string; const ColumnNamePattern: string): IZResultSet; function GetPrimaryKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; function GetImportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; function GetExportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; function GetCrossReference(const PrimaryCatalog: string; const PrimarySchema: string; const PrimaryTable: string; const ForeignCatalog: string; const ForeignSchema: string; const ForeignTable: string): IZResultSet; function GetIndexInfo(const Catalog: string; const Schema: string; const Table: string; Unique: Boolean; Approximate: Boolean): IZResultSet; function GetCollationAndCharSet(const Catalog, Schema, TableName, ColumnName: String): IZResultSet; //EgonHugeist function GetCharacterSets: IZResultSet; //EgonHugeist function GetTriggers(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const TriggerNamePattern: string): IZResultSet; //EgonHugesit function GetSequences(const Catalog: string; const SchemaPattern: string; const SequenceNamePattern: string): IZResultSet; function GetProcedures(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string): IZResultSet; function GetProcedureColumns(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string; const ColumnNamePattern: string): IZResultSet; function GetBestRowIdentifier(const Catalog: string; const Schema: string; const Table: string; Scope: Integer; Nullable: Boolean): IZResultSet; function GetVersionColumns(const Catalog: string; const Schema: string; const Table: string): IZResultSet; function GetTypeInfo: IZResultSet; function GetUDTs(const Catalog: string; const SchemaPattern: string; const TypeNamePattern: string; const Types: TIntegerDynArray): IZResultSet; function GetConnection: IZConnection; virtual; function GetIdentifierConvertor: IZIdentifierConvertor; virtual; procedure ClearCache; overload;virtual; procedure ClearCache(const Key: string);overload;virtual; // --> technobot 2008-06-14: metadata cache key retrieval API: function GetTablesCacheKey(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const Types: TStringDynArray): string; function GetSchemasCacheKey: string; function GetCatalogsCacheKey: string; function GetTableTypesCacheKey: string; function GetColumnsCacheKey(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const ColumnNamePattern: string): string; function GetColumnPrivilegesCacheKey(const Catalog: string; const Schema: string; const Table: string; const ColumnNamePattern: string): string; function GetTablePrivilegesCacheKey(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string): string; function GetPrimaryKeysCacheKey(const Catalog: string; const Schema: string; const Table: string): string; function GetImportedKeysCacheKey(const Catalog: string; const Schema: string; const Table: string): string; function GetExportedKeysCacheKey(const Catalog: string; const Schema: string; const Table: string): string; function GetCrossReferenceCacheKey(const PrimaryCatalog: string; const PrimarySchema: string; const PrimaryTable: string; const ForeignCatalog: string; const ForeignSchema: string; const ForeignTable: string): string; function GetIndexInfoCacheKey(const Catalog: string; const Schema: string; const Table: string; const Unique: Boolean; const Approximate: Boolean): string; function GetSequencesCacheKey(const Catalog: string; const SchemaPattern: string; const SequenceNamePattern: string): string; function GetCollationAndCharSetCacheKey(const Catalog, SchemaPattern, TableNamePattern, ColumnPattern: String): string; //EgonHugeist function GetCharacterSetsCacheKey: String; //EgonHugeist function GetTriggersCacheKey(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const TriggerNamePattern: string): string; //EgonHugeist function GetProceduresCacheKey(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string): string; function GetProcedureColumnsCacheKey(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string; const ColumnNamePattern: string): string; function GetBestRowIdentifierCacheKey(const Catalog: string; const Schema: string; const Table: string; const Scope: Integer; const Nullable: Boolean): string; function GetVersionColumnsCacheKey(const Catalog: string; const Schema: string; const Table: string): string; function GetTypeInfoCacheKey: string; function GetUDTsCacheKey(const Catalog: string; const SchemaPattern: string; const TypeNamePattern: string; const Types: TIntegerDynArray): string; procedure GetCacheKeys(List: TStrings); // <-- technobot 2008-06-14 end; // technobot 2008-06-24 - methods moved as is from TZAbstractDatabaseMetadata: {** Implements Abstract Database Information. } TZAbstractDatabaseInfo = class(TInterfacedObject, IZDatabaseInfo) private FMetadata: TZAbstractDatabaseMetadata; protected FIdentifierQuotes: String; property Metadata: TZAbstractDatabaseMetadata read FMetadata; public constructor Create(const Metadata: TZAbstractDatabaseMetadata); overload; constructor Create(const Metadata: TZAbstractDatabaseMetadata; const IdentifierQuotes: String); overload; destructor Destroy; override; // database/driver/server info: function GetDatabaseProductName: string; virtual; function GetDatabaseProductVersion: string; virtual; function GetDriverName: string; virtual; function GetDriverVersion: string; virtual; function GetDriverMajorVersion: Integer; virtual; function GetDriverMinorVersion: Integer; virtual; function GetServerVersion: string; // capabilities (what it can/cannot do): function AllProceduresAreCallable: Boolean; virtual; function AllTablesAreSelectable: Boolean; virtual; function SupportsMixedCaseIdentifiers: Boolean; virtual; function SupportsMixedCaseQuotedIdentifiers: Boolean; virtual; function SupportsAlterTableWithAddColumn: Boolean; virtual; function SupportsAlterTableWithDropColumn: Boolean; virtual; function SupportsColumnAliasing: Boolean; virtual; function SupportsConvert: Boolean; virtual; function SupportsConvertForTypes(FromType: TZSQLType; ToType: TZSQLType): Boolean; virtual; function SupportsTableCorrelationNames: Boolean; virtual; function SupportsDifferentTableCorrelationNames: Boolean; virtual; function SupportsExpressionsInOrderBy: Boolean; virtual; function SupportsOrderByUnrelated: Boolean; virtual; function SupportsGroupBy: Boolean; virtual; function SupportsGroupByUnrelated: Boolean; virtual; function SupportsGroupByBeyondSelect: Boolean; virtual; function SupportsLikeEscapeClause: Boolean; virtual; function SupportsMultipleResultSets: Boolean; virtual; function SupportsMultipleTransactions: Boolean; virtual; function SupportsNonNullableColumns: Boolean; virtual; function SupportsMinimumSQLGrammar: Boolean; virtual; function SupportsCoreSQLGrammar: Boolean; virtual; function SupportsExtendedSQLGrammar: Boolean; virtual; function SupportsANSI92EntryLevelSQL: Boolean; virtual; function SupportsANSI92IntermediateSQL: Boolean; virtual; function SupportsANSI92FullSQL: Boolean; virtual; function SupportsIntegrityEnhancementFacility: Boolean; virtual; function SupportsOuterJoins: Boolean; virtual; function SupportsFullOuterJoins: Boolean; virtual; function SupportsLimitedOuterJoins: Boolean; virtual; function SupportsSchemasInDataManipulation: Boolean; virtual; function SupportsSchemasInProcedureCalls: Boolean; virtual; function SupportsSchemasInTableDefinitions: Boolean; virtual; function SupportsSchemasInIndexDefinitions: Boolean; virtual; function SupportsSchemasInPrivilegeDefinitions: Boolean; virtual; function SupportsCatalogsInDataManipulation: Boolean; virtual; function SupportsCatalogsInProcedureCalls: Boolean; virtual; function SupportsCatalogsInTableDefinitions: Boolean; virtual; function SupportsCatalogsInIndexDefinitions: Boolean; virtual; function SupportsCatalogsInPrivilegeDefinitions: Boolean; virtual; function SupportsOverloadPrefixInStoredProcedureName: Boolean; virtual; function SupportsPositionedDelete: Boolean; virtual; function SupportsPositionedUpdate: Boolean; virtual; function SupportsSelectForUpdate: Boolean; virtual; function SupportsStoredProcedures: Boolean; virtual; function SupportsSubqueriesInComparisons: Boolean; virtual; function SupportsSubqueriesInExists: Boolean; virtual; function SupportsSubqueriesInIns: Boolean; virtual; function SupportsSubqueriesInQuantifieds: Boolean; virtual; function SupportsCorrelatedSubqueries: Boolean; virtual; function SupportsUnion: Boolean; virtual; function SupportsUnionAll: Boolean; virtual; function SupportsOpenCursorsAcrossCommit: Boolean; virtual; function SupportsOpenCursorsAcrossRollback: Boolean; virtual; function SupportsOpenStatementsAcrossCommit: Boolean; virtual; function SupportsOpenStatementsAcrossRollback: Boolean; virtual; function SupportsTransactions: Boolean; virtual; function SupportsTransactionIsolationLevel(Level: TZTransactIsolationLevel): Boolean; virtual; function SupportsDataDefinitionAndDataManipulationTransactions: Boolean; virtual; function SupportsDataManipulationTransactionsOnly: Boolean; virtual; function SupportsResultSetType(_Type: TZResultSetType): Boolean; virtual; function SupportsResultSetConcurrency(_Type: TZResultSetType; Concurrency: TZResultSetConcurrency): Boolean; virtual; function SupportsBatchUpdates: Boolean; virtual; function SupportsNonEscapedSearchStrings: Boolean; virtual; function SupportsUpdateAutoIncrementFields: Boolean; virtual; // maxima: function GetMaxBinaryLiteralLength: Integer; virtual; function GetMaxCharLiteralLength: Integer; virtual; function GetMaxColumnNameLength: Integer; virtual; function GetMaxColumnsInGroupBy: Integer; virtual; function GetMaxColumnsInIndex: Integer; virtual; function GetMaxColumnsInOrderBy: Integer; virtual; function GetMaxColumnsInSelect: Integer; virtual; function GetMaxColumnsInTable: Integer; virtual; function GetMaxConnections: Integer; virtual; function GetMaxCursorNameLength: Integer; virtual; function GetMaxIndexLength: Integer; virtual; function GetMaxSchemaNameLength: Integer; virtual; function GetMaxProcedureNameLength: Integer; virtual; function GetMaxCatalogNameLength: Integer; virtual; function GetMaxRowSize: Integer; virtual; function GetMaxStatementLength: Integer; virtual; function GetMaxStatements: Integer; virtual; function GetMaxTableNameLength: Integer; virtual; function GetMaxTablesInSelect: Integer; virtual; function GetMaxUserNameLength: Integer; virtual; // policies (how are various data and operations handled): function IsReadOnly: Boolean; virtual; function IsCatalogAtStart: Boolean; virtual; function DoesMaxRowSizeIncludeBlobs: Boolean; virtual; function NullsAreSortedHigh: Boolean; virtual; function NullsAreSortedLow: Boolean; virtual; function NullsAreSortedAtStart: Boolean; virtual; function NullsAreSortedAtEnd: Boolean; virtual; function NullPlusNonNullIsNull: Boolean; virtual; function UsesLocalFiles: Boolean; virtual; function UsesLocalFilePerTable: Boolean; virtual; function StoresUpperCaseIdentifiers: Boolean; virtual; function StoresLowerCaseIdentifiers: Boolean; virtual; function StoresMixedCaseIdentifiers: Boolean; virtual; function StoresUpperCaseQuotedIdentifiers: Boolean; virtual; function StoresLowerCaseQuotedIdentifiers: Boolean; virtual; function StoresMixedCaseQuotedIdentifiers: Boolean; virtual; function GetDefaultTransactionIsolation: TZTransactIsolationLevel; virtual; function DataDefinitionCausesTransactionCommit: Boolean; virtual; function DataDefinitionIgnoredInTransactions: Boolean; virtual; // interface details (terms, keywords, etc): function GetIdentifierQuoteString: string; function GetSchemaTerm: string; virtual; function GetProcedureTerm: string; virtual; function GetCatalogTerm: string; virtual; function GetCatalogSeparator: string; virtual; function GetSQLKeywords: string; virtual; function GetNumericFunctions: string; virtual; function GetStringFunctions: string; virtual; function GetSystemFunctions: string; virtual; function GetTimeDateFunctions: string; virtual; function GetSearchStringEscape: string; virtual; function GetExtraNameCharacters: string; virtual; end; {** Implements a default Case Sensitive/Unsensitive identifier convertor. } TZDefaultIdentifierConvertor = class (TZAbstractObject, IZIdentifierConvertor) private FMetadata: Pointer; function GetMetaData: IZDatabaseMetadata; protected property Metadata: IZDatabaseMetadata read GetMetaData; function IsLowerCase(const Value: string): Boolean; function IsUpperCase(const Value: string): Boolean; function IsSpecialCase(const Value: string): Boolean; virtual; public constructor Create(Metadata: IZDatabaseMetadata); function IsCaseSensitive(const Value: string): Boolean; function IsQuoted(const Value: string): Boolean; virtual; function Quote(const Value: string): string; virtual; function ExtractQuote(const Value: string): string; virtual; end; function GetTablesMetaDataCacheKey(Const Catalog:String; Const SchemaPattern:String;Const TableNamePattern:String;const Types: TStringDynArray):String; deprecated; // (technobot) use TZAbstractDatabaseMetadata.GetTablesCacheKey instead var CharacterSetsColumnsDynArray: TZMetadataColumnDefs; //EgonHugeist CollationCharSetColumnsDynArray: TZMetadataColumnDefs; //EgonHugeist TriggersColumnsDynArray: TZMetadataColumnDefs; //EgonHugeist TriggersColColumnsDynArray: TZMetadataColumnDefs; ProceduresColumnsDynArray: TZMetadataColumnDefs; ProceduresColColumnsDynArray: TZMetadataColumnDefs; TableColumnsDynArray: TZMetadataColumnDefs; SchemaColumnsDynArray: TZMetadataColumnDefs; CatalogColumnsDynArray: TZMetadataColumnDefs; TableTypeColumnsDynArray: TZMetadataColumnDefs; TableColColumnsDynArray: TZMetadataColumnDefs; TableColPrivColumnsDynArray: TZMetadataColumnDefs; TablePrivColumnsDynArray: TZMetadataColumnDefs; BestRowIdentColumnsDynArray: TZMetadataColumnDefs; TableColVerColumnsDynArray: TZMetadataColumnDefs; PrimaryKeyColumnsDynArray: TZMetadataColumnDefs; ImportedKeyColumnsDynArray: TZMetadataColumnDefs; ExportedKeyColumnsDynArray: TZMetadataColumnDefs; CrossRefColumnsDynArray: TZMetadataColumnDefs; TypeInfoColumnsDynArray: TZMetadataColumnDefs; IndexInfoColumnsDynArray: TZMetadataColumnDefs; SequenceColumnsDynArray: TZMetadataColumnDefs; UDTColumnsDynArray: TZMetadataColumnDefs; implementation uses ZVariant, ZCollections, ZMessages; { TZAbstractDatabaseInfo } {** Constructs this object. @param Metadata the interface of the correpsonding database metadata object } constructor TZAbstractDatabaseInfo.Create(const Metadata: TZAbstractDatabaseMetadata); begin Create(MetaData, '"'); end; {** Constructs this object. @param Metadata the interface of the correpsonding database metadata object @param IdentifierQuotes What's the string used to quote SQL identifiers? This returns a space " " if identifier quoting isn't supported. A JDBC CompliantTM driver always uses a double quote character. } constructor TZAbstractDatabaseInfo.Create(const Metadata: TZAbstractDatabaseMetadata; const IdentifierQuotes: String); begin inherited Create; FMetadata := Metadata; if FMetaData.FUrl.Properties.IndexOfName('identifier_quotes') > -1 then //prevent to loose emty quotes '' !!! FIdentifierQuotes := FMetaData.FUrl.Properties.Values['identifier_quotes'] else if IdentifierQuotes = '' then FIdentifierQuotes := '"' else FIdentifierQuotes := IdentifierQuotes; end; {** Destroys this object and cleanups the memory. } destructor TZAbstractDatabaseInfo.Destroy; begin FMetadata := nil; inherited; end; //---------------------------------------------------------------------- // First, a variety of minor information about the target database. {** Can all the procedures returned by getProcedures be called by the current user? @return true if so; false otherwise } function TZAbstractDatabaseInfo.AllProceduresAreCallable: Boolean; begin Result := True; end; {** Can all the tables returned by getTable be SELECTed by the current user? @return true if so; false otherwise } function TZAbstractDatabaseInfo.AllTablesAreSelectable: Boolean; begin Result := True; end; {** Is the database in read-only mode? @return true if so; false otherwise } function TZAbstractDatabaseInfo.IsReadOnly: Boolean; begin Result := False; end; {** Are NULL values sorted high? @return true if so; false otherwise } function TZAbstractDatabaseInfo.NullsAreSortedHigh: Boolean; begin Result := False; end; {** Are NULL values sorted low? @return true if so; false otherwise } function TZAbstractDatabaseInfo.NullsAreSortedLow: Boolean; begin Result := False; end; {** Are NULL values sorted at the start regardless of sort order? @return true if so; false otherwise } function TZAbstractDatabaseInfo.NullsAreSortedAtStart: Boolean; begin Result := False; end; {** Are NULL values sorted at the end regardless of sort order? @return true if so; false otherwise } function TZAbstractDatabaseInfo.NullsAreSortedAtEnd: Boolean; begin Result := False; end; {** What's the name of this database product? @return database product name } function TZAbstractDatabaseInfo.GetDatabaseProductName: string; begin Result := ''; end; {** What's the version of this database product? @return database version } function TZAbstractDatabaseInfo.GetDatabaseProductVersion: string; begin Result := ''; end; {** What's the name of this JDBC driver? @return JDBC driver name } function TZAbstractDatabaseInfo.GetDriverName: string; begin Result := 'Zeos Database Connectivity Driver'; end; {** What's the version of this JDBC driver? @return JDBC driver version } function TZAbstractDatabaseInfo.GetDriverVersion: string; begin Result := Format('%d.%d', [GetDriverMajorVersion, GetDriverMinorVersion]); end; {** What's this JDBC driver's major version number? @return JDBC driver major version } function TZAbstractDatabaseInfo.GetDriverMajorVersion: Integer; begin Result := 1; end; {** What's this JDBC driver's minor version number? @return JDBC driver minor version number } function TZAbstractDatabaseInfo.GetDriverMinorVersion: Integer; begin Result := 0; end; {** Returns the server version @return the server version string } function TZAbstractDatabaseInfo.GetServerVersion: string; begin Result := ''; end; {** Does the database store tables in a local file? @return true if so; false otherwise } function TZAbstractDatabaseInfo.UsesLocalFiles: Boolean; begin Result := True; end; {** Does the database use a file for each table? @return true if the database uses a local file for each table } function TZAbstractDatabaseInfo.UsesLocalFilePerTable: Boolean; begin Result := False; end; {** Does the database treat mixed case unquoted SQL identifiers as case sensitive and as a result store them in mixed case? A JDBC CompliantTM driver will always return false. @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsMixedCaseIdentifiers: Boolean; begin Result := False; end; {** Does the database treat mixed case unquoted SQL identifiers as case insensitive and store them in upper case? @return true if so; false otherwise } function TZAbstractDatabaseInfo.StoresUpperCaseIdentifiers: Boolean; begin Result := False; end; {** Does the database treat mixed case unquoted SQL identifiers as case insensitive and store them in lower case? @return true if so; false otherwise } function TZAbstractDatabaseInfo.StoresLowerCaseIdentifiers: Boolean; begin Result := False; end; {** Does the database treat mixed case unquoted SQL identifiers as case insensitive and store them in mixed case? @return true if so; false otherwise } function TZAbstractDatabaseInfo.StoresMixedCaseIdentifiers: Boolean; begin Result := True; end; {** Does the database treat mixed case quoted SQL identifiers as case sensitive and as a result store them in mixed case? A JDBC CompliantTM driver will always return true. @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsMixedCaseQuotedIdentifiers: Boolean; begin Result := True; end; {** Does the database treat mixed case quoted SQL identifiers as case insensitive and store them in upper case? @return true if so; false otherwise } function TZAbstractDatabaseInfo.StoresUpperCaseQuotedIdentifiers: Boolean; begin Result := False; end; {** Does the database treat mixed case quoted SQL identifiers as case insensitive and store them in lower case? @return true if so; false otherwise } function TZAbstractDatabaseInfo.StoresLowerCaseQuotedIdentifiers: Boolean; begin Result := False; end; {** Does the database treat mixed case quoted SQL identifiers as case insensitive and store them in mixed case? @return true if so; false otherwise } function TZAbstractDatabaseInfo.StoresMixedCaseQuotedIdentifiers: Boolean; begin Result := False; end; {** What's the string used to quote SQL identifiers? This returns a space " " if identifier quoting isn't supported. A JDBC CompliantTM driver always uses a double quote character. @return the quoting string } function TZAbstractDatabaseInfo.GetIdentifierQuoteString: string; begin Result := FIdentifierQuotes; end; {** Gets a comma-separated list of all a database's SQL keywords that are NOT also SQL92 keywords. @return the list } function TZAbstractDatabaseInfo.GetSQLKeywords: string; begin Result := ''; end; {** Gets a comma-separated list of math functions. These are the X/Open CLI math function names used in the JDBC function escape clause. @return the list } function TZAbstractDatabaseInfo.GetNumericFunctions: string; begin Result := ''; end; {** Gets a comma-separated list of string functions. These are the X/Open CLI string function names used in the JDBC function escape clause. @return the list } function TZAbstractDatabaseInfo.GetStringFunctions: string; begin Result := ''; end; {** Gets a comma-separated list of system functions. These are the X/Open CLI system function names used in the JDBC function escape clause. @return the list } function TZAbstractDatabaseInfo.GetSystemFunctions: string; begin Result := ''; end; {** Gets a comma-separated list of time and date functions. @return the list } function TZAbstractDatabaseInfo.GetTimeDateFunctions: string; begin Result := ''; end; {** Gets the string that can be used to escape wildcard characters. This is the string that can be used to escape '_' or '%' in the string pattern style catalog search parameters.

The '_' character represents any single character.

The '%' character represents any sequence of zero or more characters. @return the string used to escape wildcard characters } function TZAbstractDatabaseInfo.GetSearchStringEscape: string; begin Result := '%'; end; {** Gets all the "extra" characters that can be used in unquoted identifier names (those beyond a-z, A-Z, 0-9 and _). @return the string containing the extra characters } function TZAbstractDatabaseInfo.GetExtraNameCharacters: string; begin Result := ''; end; //-------------------------------------------------------------------- // Functions describing which features are supported. {** Is "ALTER TABLE" with add column supported? @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsAlterTableWithAddColumn: Boolean; begin Result := True; end; {** Is "ALTER TABLE" with drop column supported? @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsAlterTableWithDropColumn: Boolean; begin Result := True; end; {** Is column aliasing supported?

If so, the SQL AS clause can be used to provide names for computed columns or to provide alias names for columns as required. A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsColumnAliasing: Boolean; begin Result := True; end; {** Are concatenations between NULL and non-NULL values NULL? For SQL-92 compliance, a JDBC technology-enabled driver will return true. @return true if so; false otherwise } function TZAbstractDatabaseInfo.NullPlusNonNullIsNull: Boolean; begin Result := True; end; {** Is the CONVERT function between SQL types supported? @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsConvert: Boolean; begin Result := False; end; {** Is CONVERT between the given SQL types supported? @param fromType the type to convert from @param toType the type to convert to @return true if so; false otherwise @see Types } function TZAbstractDatabaseInfo.SupportsConvertForTypes( FromType: TZSQLType; ToType: TZSQLType): Boolean; begin Result := False; end; {** Are table correlation names supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsTableCorrelationNames: Boolean; begin Result := True; end; {** If table correlation names are supported, are they restricted to be different from the names of the tables? @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsDifferentTableCorrelationNames: Boolean; begin Result := False; end; {** Are expressions in "ORDER BY" lists supported? @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsExpressionsInOrderBy: Boolean; begin Result := True; end; {** Can an "ORDER BY" clause use columns not in the SELECT statement? @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsOrderByUnrelated: Boolean; begin Result := True; end; {** Is some form of "GROUP BY" clause supported? @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsGroupBy: Boolean; begin Result := True; end; {** Can a "GROUP BY" clause use columns not in the SELECT? @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsGroupByUnrelated: Boolean; begin Result := True; end; {** Can a "GROUP BY" clause add columns not in the SELECT provided it specifies all the columns in the SELECT? @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsGroupByBeyondSelect: Boolean; begin Result := False; end; {** Is the escape character in "LIKE" clauses supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsLikeEscapeClause: Boolean; begin Result := True; end; {** Are multiple ResultSet from a single execute supported? @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsMultipleResultSets: Boolean; begin Result := True; end; {** Can we have multiple transactions open at once (on different connections)? @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsMultipleTransactions: Boolean; begin Result := True; end; {** Can columns be defined as non-nullable? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsNonNullableColumns: Boolean; begin Result := True; end; {** Is the ODBC Minimum SQL grammar supported? All JDBC CompliantTM drivers must return true. @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsMinimumSQLGrammar: Boolean; begin Result := True; end; {** Is the ODBC Core SQL grammar supported? @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsCoreSQLGrammar: Boolean; begin Result := True; end; {** Is the ODBC Extended SQL grammar supported? @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsExtendedSQLGrammar: Boolean; begin Result := True; end; {** Is the ANSI92 entry level SQL grammar supported? All JDBC CompliantTM drivers must return true. @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsANSI92EntryLevelSQL: Boolean; begin Result := True; end; {** Is the ANSI92 intermediate SQL grammar supported? @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsANSI92IntermediateSQL: Boolean; begin Result := True; end; {** Is the ANSI92 full SQL grammar supported? @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsANSI92FullSQL: Boolean; begin Result := True; end; {** Is the SQL Integrity Enhancement Facility supported? @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsIntegrityEnhancementFacility: Boolean; begin Result := False; end; {** Is some form of outer join supported? @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsOuterJoins: Boolean; begin Result := True; end; {** Are full nested outer joins supported? @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsFullOuterJoins: Boolean; begin Result := True; end; {** Is there limited support for outer joins? (This will be true if supportFullOuterJoins is true.) @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsLimitedOuterJoins: Boolean; begin Result := True; end; {** What's the database vendor's preferred term for "schema"? @return the vendor term } function TZAbstractDatabaseInfo.GetSchemaTerm: string; begin Result := 'Schema'; end; {** What's the database vendor's preferred term for "procedure"? @return the vendor term } function TZAbstractDatabaseInfo.GetProcedureTerm: string; begin Result := 'Procedure'; end; {** What's the database vendor's preferred term for "catalog"? @return the vendor term } function TZAbstractDatabaseInfo.GetCatalogTerm: string; begin Result := 'Catalog'; end; {** Does a catalog appear at the start of a qualified table name? (Otherwise it appears at the end) @return true if it appears at the start } function TZAbstractDatabaseInfo.IsCatalogAtStart: Boolean; begin Result := False; end; {** What's the separator between catalog and table name? @return the separator string } function TZAbstractDatabaseInfo.GetCatalogSeparator: string; begin Result := '.'; end; {** Can a schema name be used in a data manipulation statement? @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsSchemasInDataManipulation: Boolean; begin Result := False; end; {** Can a schema name be used in a procedure call statement? @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsSchemasInProcedureCalls: Boolean; begin Result := False; end; {** Can a schema name be used in a table definition statement? @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsSchemasInTableDefinitions: Boolean; begin Result := False; end; {** Can a schema name be used in an index definition statement? @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsSchemasInIndexDefinitions: Boolean; begin Result := False; end; {** Can a schema name be used in a privilege definition statement? @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsSchemasInPrivilegeDefinitions: Boolean; begin Result := False; end; {** Can a catalog name be used in a data manipulation statement? @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsCatalogsInDataManipulation: Boolean; begin Result := False; end; {** Can a catalog name be used in a procedure call statement? @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsCatalogsInProcedureCalls: Boolean; begin Result := False; end; {** Can a catalog name be used in a table definition statement? @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsCatalogsInTableDefinitions: Boolean; begin Result := False; end; {** Can a catalog name be used in an index definition statement? @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsCatalogsInIndexDefinitions: Boolean; begin Result := False; end; {** Can a catalog name be used in a privilege definition statement? @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsCatalogsInPrivilegeDefinitions: Boolean; begin Result := False; end; {** Can a stored procedure have an additional overload suffix? @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsOverloadPrefixInStoredProcedureName: Boolean; begin Result := False; end; {** Is positioned DELETE supported? @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsPositionedDelete: Boolean; begin Result := False; end; {** Is positioned UPDATE supported? @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsPositionedUpdate: Boolean; begin Result := False; end; {** Is SELECT for UPDATE supported? @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsSelectForUpdate: Boolean; begin Result := False; end; {** Are stored procedure calls using the stored procedure escape syntax supported? @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsStoredProcedures: Boolean; begin Result := False; end; {** Are subqueries in comparison expressions supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsSubqueriesInComparisons: Boolean; begin Result := False; end; {** Are subqueries in 'exists' expressions supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsSubqueriesInExists: Boolean; begin Result := False; end; {** Are subqueries in 'in' statements supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsSubqueriesInIns: Boolean; begin Result := False; end; {** Are subqueries in quantified expressions supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsSubqueriesInQuantifieds: Boolean; begin Result := False; end; {** Are correlated subqueries supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsCorrelatedSubqueries: Boolean; begin Result := False; end; {** Is SQL UNION supported? @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsUnion: Boolean; begin Result := False; end; {** Is SQL UNION ALL supported? @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsUnionAll: Boolean; begin Result := False; end; {** Can cursors remain open across commits? @return true if cursors always remain open; false if they might not remain open } function TZAbstractDatabaseInfo.SupportsOpenCursorsAcrossCommit: Boolean; begin Result := False; end; {** Can cursors remain open across rollbacks? @return true if cursors always remain open; false if they might not remain open } function TZAbstractDatabaseInfo.SupportsOpenCursorsAcrossRollback: Boolean; begin Result := False; end; {** Can statements remain open across commits? @return true if statements always remain open; false if they might not remain open } function TZAbstractDatabaseInfo.SupportsOpenStatementsAcrossCommit: Boolean; begin Result := True; end; {** Can statements remain open across rollbacks? @return true if statements always remain open; false if they might not remain open } function TZAbstractDatabaseInfo.SupportsOpenStatementsAcrossRollback: Boolean; begin Result := True; end; //---------------------------------------------------------------------- // The following group of methods exposes various limitations // based on the target database with the current driver. // Unless otherwise specified, a result of zero means there is no // limit, or the limit is not known. {** How many hex characters can you have in an inline binary literal? @return max binary literal length in hex characters; a result of zero means that there is no limit or the limit is not known } function TZAbstractDatabaseInfo.GetMaxBinaryLiteralLength: Integer; begin Result := 0; end; {** What's the max length for a character literal? @return max literal length; a result of zero means that there is no limit or the limit is not known } function TZAbstractDatabaseInfo.GetMaxCharLiteralLength: Integer; begin Result := 0; end; {** What's the limit on column name length? @return max column name length; a result of zero means that there is no limit or the limit is not known } function TZAbstractDatabaseInfo.GetMaxColumnNameLength: Integer; begin Result := 0; end; {** What's the maximum number of columns in a "GROUP BY" clause? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZAbstractDatabaseInfo.GetMaxColumnsInGroupBy: Integer; begin Result := 0; end; {** What's the maximum number of columns allowed in an index? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZAbstractDatabaseInfo.GetMaxColumnsInIndex: Integer; begin Result := 0; end; {** What's the maximum number of columns in an "ORDER BY" clause? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZAbstractDatabaseInfo.GetMaxColumnsInOrderBy: Integer; begin Result := 0; end; {** What's the maximum number of columns in a "SELECT" list? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZAbstractDatabaseInfo.GetMaxColumnsInSelect: Integer; begin Result := 0; end; {** What's the maximum number of columns in a table? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZAbstractDatabaseInfo.GetMaxColumnsInTable: Integer; begin Result := 0; end; {** How many active connections can we have at a time to this database? @return max number of active connections; a result of zero means that there is no limit or the limit is not known } function TZAbstractDatabaseInfo.GetMaxConnections: Integer; begin Result := 0; end; {** What's the maximum cursor name length? @return max cursor name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZAbstractDatabaseInfo.GetMaxCursorNameLength: Integer; begin Result := 0; end; {** Retrieves the maximum number of bytes for an index, including all of the parts of the index. @return max index length in bytes, which includes the composite of all the constituent parts of the index; a result of zero means that there is no limit or the limit is not known } function TZAbstractDatabaseInfo.GetMaxIndexLength: Integer; begin Result := 0; end; {** What's the maximum length allowed for a schema name? @return max name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZAbstractDatabaseInfo.GetMaxSchemaNameLength: Integer; begin Result := 0; end; {** What's the maximum length of a procedure name? @return max name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZAbstractDatabaseInfo.GetMaxProcedureNameLength: Integer; begin Result := 0; end; {** What's the maximum length of a catalog name? @return max name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZAbstractDatabaseInfo.GetMaxCatalogNameLength: Integer; begin Result := 0; end; {** What's the maximum length of a single row? @return max row size in bytes; a result of zero means that there is no limit or the limit is not known } function TZAbstractDatabaseInfo.GetMaxRowSize: Integer; begin Result := 0; end; {** Did getMaxRowSize() include LONGVARCHAR and LONGVARBINARY blobs? @return true if so; false otherwise } function TZAbstractDatabaseInfo.DoesMaxRowSizeIncludeBlobs: Boolean; begin Result := True; end; {** What's the maximum length of an SQL statement? @return max length in bytes; a result of zero means that there is no limit or the limit is not known } function TZAbstractDatabaseInfo.GetMaxStatementLength: Integer; begin Result := 0; end; {** How many active statements can we have open at one time to this database? @return the maximum number of statements that can be open at one time; a result of zero means that there is no limit or the limit is not known } function TZAbstractDatabaseInfo.GetMaxStatements: Integer; begin Result := 0; end; {** What's the maximum length of a table name? @return max name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZAbstractDatabaseInfo.GetMaxTableNameLength: Integer; begin Result := 0; end; {** What's the maximum number of tables in a SELECT statement? @return the maximum number of tables allowed in a SELECT statement; a result of zero means that there is no limit or the limit is not known } function TZAbstractDatabaseInfo.GetMaxTablesInSelect: Integer; begin Result := 0; end; {** What's the maximum length of a user name? @return max user name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZAbstractDatabaseInfo.GetMaxUserNameLength: Integer; begin Result := 0; end; //---------------------------------------------------------------------- {** What's the database's default transaction isolation level? The values are defined in java.sql.Connection. @return the default isolation level @see Connection } function TZAbstractDatabaseInfo.GetDefaultTransactionIsolation: TZTransactIsolationLevel; begin Result := tiReadCommitted; end; {** Are transactions supported? If not, invoking the method commit is a noop and the isolation level is TRANSACTION_NONE. @return true if transactions are supported; false otherwise } function TZAbstractDatabaseInfo.SupportsTransactions: Boolean; begin Result := True; end; {** Does this database support the given transaction isolation level? @param level the values are defined in java.sql.Connection @return true if so; false otherwise @see Connection } function TZAbstractDatabaseInfo.SupportsTransactionIsolationLevel( Level: TZTransactIsolationLevel): Boolean; begin Result := True; end; {** Are both data definition and data manipulation statements within a transaction supported? @return true if so; false otherwise } function TZAbstractDatabaseInfo. SupportsDataDefinitionAndDataManipulationTransactions: Boolean; begin Result := True; end; {** Are only data manipulation statements within a transaction supported? @return true if so; false otherwise } function TZAbstractDatabaseInfo. SupportsDataManipulationTransactionsOnly: Boolean; begin Result := False; end; {** Does a data definition statement within a transaction force the transaction to commit? @return true if so; false otherwise } function TZAbstractDatabaseInfo.DataDefinitionCausesTransactionCommit: Boolean; begin Result := True; end; {** Is a data definition statement within a transaction ignored? @return true if so; false otherwise } function TZAbstractDatabaseInfo.DataDefinitionIgnoredInTransactions: Boolean; begin Result := False; end; {** Does the database support the given result set type? @param type defined in java.sql.ResultSet @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsResultSetType( _Type: TZResultSetType): Boolean; begin Result := True; end; {** Does the database support the concurrency type in combination with the given result set type? @param type defined in java.sql.ResultSet @param concurrency type defined in java.sql.ResultSet @return true if so; false otherwise } function TZAbstractDatabaseInfo.SupportsResultSetConcurrency( _Type: TZResultSetType; Concurrency: TZResultSetConcurrency): Boolean; begin Result := True; end; {** Indicates whether the driver supports batch updates. @return true if the driver supports batch updates; false otherwise } function TZAbstractDatabaseInfo.SupportsBatchUpdates: Boolean; begin Result := True; end; {** Does the Database or Actual Version understand non escaped search strings? @return true if the DataBase does understand non escaped search strings } function TZAbstractDatabaseInfo.SupportsNonEscapedSearchStrings: Boolean; begin Result := False; end; {** Does the Database support updating auto incremental fields? @return true if the DataBase allows it. } function TZAbstractDatabaseInfo.SupportsUpdateAutoIncrementFields: Boolean; begin Result := True; end; { TZAbstractDatabaseMetadata } {** Constructs this object and assignes the main properties. @param Connection a database connection object. @param Url a database connection url string. } constructor TZAbstractDatabaseMetadata.Create(Connection: TZAbstractConnection; const Url: TZURL); begin inherited Create(Connection as IZConnection); FIC := Self.GetIdentifierConvertor; FConnection := Pointer(Connection as IZConnection); FUrl := Url; FCachedResultSets := TZHashMap.Create; FDatabaseInfo := CreateDatabaseInfo; FDatabase := Url.Database; FConSettings := IZConnection(FConnection).GetConSettings; FillWildcards; end; function TZAbstractDatabaseMetadata.GetInfo: TStrings; begin Result := FURL.Properties; end; function TZAbstractDatabaseMetadata.GetURLString: String; begin Result := FURL.URL; end; {** Remove escapes from pattren string @param Pattern a sql pattern @return string without escapes } function TZAbstractDatabaseMetadata.StripEscape(const Pattern: string): string; var I: Integer; PreviousChar: Char; EscapeChar: string; begin PreviousChar := #0; Result := ''; EscapeChar := GetDatabaseInfo.GetSearchStringEscape; for I := 1 to Length(Pattern) do begin if (Pattern[i] <> EscapeChar) then begin Result := Result + Pattern[I]; PreviousChar := Pattern[I]; end else begin if (PreviousChar = EscapeChar) then begin Result := Result + Pattern[I]; PreviousChar := #0; end else PreviousChar := Pattern[i]; end; end; end; {** Check if pattern does not contain wildcards @param Pattern a sql pattern @return if pattern contain wildcards return true otherwise false } function TZAbstractDatabaseMetadata.HasNoWildcards(const Pattern: string ): boolean; var I: Integer; PreviousCharWasEscape: Boolean; EscapeChar,PreviousChar: Char; WildcardsSet: TZWildcardsSet; begin Result := False; PreviousChar := #0; PreviousCharWasEscape := False; EscapeChar := Char(GetDatabaseInfo.GetSearchStringEscape[1]); WildcardsSet := GetWildcardsSet; for I := 1 to Length(Pattern) do begin if (not PreviousCharWasEscape) and CharInset(Pattern[I], WildcardsSet) then Exit; PreviousCharWasEscape := (Pattern[I] = EscapeChar) and (PreviousChar <> EscapeChar); if (PreviousCharWasEscape) and (Pattern[I] = EscapeChar) then PreviousChar := #0 else PreviousChar := Pattern[I]; end; Result := True; end; function TZAbstractDatabaseMetadata.EscapeString(const S: string): string; begin Result := '''' + S + ''''; end; function TZAbstractDatabaseMetadata.DecomposeObjectString(const S: String): String; begin if IC.IsQuoted(s) then Result := IC.ExtractQuote(s) else Result := s; end; {** Destroys this object and cleanups the memory.} destructor TZAbstractDatabaseMetadata.Destroy; begin FIC := nil; FUrl := nil; FCachedResultSets.Clear; FCachedResultSets := nil; FDatabaseInfo := nil; inherited Destroy; end; {** Constructs a database information object and returns the interface to it. Used internally by the constructor. @return the database information object interface } function TZAbstractDatabaseMetadata.CreateDatabaseInfo: IZDatabaseInfo; begin Result := TZAbstractDatabaseInfo.Create(Self); end; {** Creates and returns a statement object. @return the statement object } function TZAbstractDatabaseMetadata.GetStatement: IZSTatement; begin Result := GetConnection.CreateStatement; end; {** Retrieves the connection that produced this metadata object. @return the connection that produced this metadata object } function TZAbstractDatabaseMetadata.GetConnection: IZConnection; begin Result := IZConnection(FConnection); end; {** Constructs a virtual result set object. @param ColumnsDefs an array of column definition objects. @return a created result set. } function TZAbstractDatabaseMetadata.ConstructVirtualResultSet( ColumnsDefs: TZMetadataColumnDefs): IZVirtualResultSet; var I: Integer; ColumnInfo: TZColumnInfo; ColumnsInfo: TObjectList; begin ColumnsInfo := TObjectList.Create(True); try for I := 0 to High(ColumnsDefs) do begin ColumnInfo := TZColumnInfo.Create; with ColumnInfo do begin ColumnLabel := ColumnsDefs[I].Name; ColumnType := ColumnsDefs[I].SQLType; ColumnDisplaySize := ColumnsDefs[I].Length; Precision := ColumnsDefs[I].Length; end; ColumnsInfo.Add(ColumnInfo); end; Result := TZVirtualResultSet.CreateWithColumns(ColumnsInfo, '', IZConnection(FConnection).GetConSettings); with Result do begin SetType(rtScrollInsensitive); SetConcurrency(rcUpdatable); end; finally ColumnsInfo.Free; end; end; {** Clears all cached metadata. } procedure TZAbstractDatabaseMetadata.ClearCache; begin FCachedResultSets.Clear; end; {** Clears specific cached metadata. } procedure TZAbstractDatabaseMetadata.ClearCache(const Key: string); var TempKey: IZAnyValue; begin TempKey := TZAnyValue.CreateWithString(Key); FCachedResultSets.Remove(TempKey); end; {** Adds resultset to the internal cache. @param Key a resultset unique key value. @param ResultSet a resultset interface. } procedure TZAbstractDatabaseMetadata.AddResultSetToCache(const Key: string; ResultSet: IZResultSet); var TempKey: IZAnyValue; begin TempKey := TZAnyValue.CreateWithString(Key); FCachedResultSets.Put(TempKey, CloneCachedResultSet(ResultSet)); end; {** Gets a resultset interface from the internal cache by key. @param Key a resultset unique key value. @returns a cached resultset interface or nil otherwise. } function TZAbstractDatabaseMetadata.GetResultSetFromCache( const Key: string): IZResultSet; var TempKey: IZAnyValue; begin TempKey := TZAnyValue.CreateWithString(Key); Result := FCachedResultSets.Get(TempKey) as IZResultSet; if Result <> nil then Result := CloneCachedResultSet(Result); end; {** Copies on result set to another one from the current position. @param SrcResultSet a source result set. @param DestResultSet a destination result set. @returns a destination result set. } function TZAbstractDatabaseMetadata.CopyToVirtualResultSet( SrcResultSet: IZResultSet; DestResultSet: IZVirtualResultSet): IZVirtualResultSet; var I: Integer; Metadata: IZResultSetMetadata; begin DestResultSet.SetType(rtScrollInsensitive); DestResultSet.SetConcurrency(rcUpdatable); Metadata := SrcResultSet.GetMetadata; while SrcResultSet.Next do begin DestResultSet.MoveToInsertRow; for I := 1 to Metadata.GetColumnCount do begin case Metadata.GetColumnType(I) of stBoolean: DestResultSet.UpdateBoolean(I, SrcResultSet.GetBoolean(I)); stByte: DestResultSet.UpdateByte(I, SrcResultSet.GetByte(I)); stShort: DestResultSet.UpdateShort(I, SrcResultSet.GetShort(I)); stInteger: DestResultSet.UpdateInt(I, SrcResultSet.GetInt(I)); stLong: DestResultSet.UpdateLong(I, SrcResultSet.GetLong(I)); stFloat: DestResultSet.UpdateFloat(I, SrcResultSet.GetFloat(I)); stDouble: DestResultSet.UpdateDouble(I, SrcResultSet.GetDouble(I)); stBigDecimal: DestResultSet.UpdateBigDecimal(I, SrcResultSet.GetBigDecimal(I)); stString: DestResultSet.UpdateString(I, SrcResultSet.GetString(I)); stUnicodeString: DestResultSet.UpdateUnicodeString(I, SrcResultSet.GetUnicodeString(I)); stBytes: DestResultSet.UpdateBytes(I, SrcResultSet.GetBytes(I)); stDate: DestResultSet.UpdateDate(I, SrcResultSet.GetDate(I)); stTime: DestResultSet.UpdateTime(I, SrcResultSet.GetTime(I)); stTimestamp: DestResultSet.UpdateTimestamp(I, SrcResultSet.GetTimestamp(I)); stAsciiStream, stUnicodeStream, stBinaryStream: DestResultSet.UpdateString(I, SrcResultSet.GetString(I)); end; if SrcResultSet.WasNull then DestResultSet.UpdateNull(I); end; DestResultSet.InsertRow; end; DestResultSet.BeforeFirst; DestResultSet.SetConcurrency(rcReadOnly); Result := DestResultSet; end; {** Clones the cached resultset. @param ResultSet the resultset to be cloned. @returns the clone of the specified resultset. } function TZAbstractDatabaseMetadata.CloneCachedResultSet( ResultSet: IZResultSet): IZResultSet; var I: Integer; Metadata: IZResultSetMetadata; ColumnInfo: TZColumnInfo; ColumnsInfo: TObjectList; begin Result := nil; Metadata := ResultSet.GetMetadata; ColumnsInfo := TObjectList.Create(True); try for I := 1 to Metadata.GetColumnCount do begin ColumnInfo := TZColumnInfo.Create; with ColumnInfo do begin ColumnLabel := Metadata.GetColumnLabel(I); ColumnType := Metadata.GetColumnType(I); ColumnDisplaySize := Metadata.GetPrecision(I); Precision := Metadata.GetPrecision(I); end; ColumnsInfo.Add(ColumnInfo); end; ResultSet.BeforeFirst; Result := CopyToVirtualResultSet(ResultSet, TZVirtualResultSet.CreateWithColumns(ColumnsInfo, '', IZConnection(Self.FConnection).GetConSettings)); ResultSet.BeforeFirst; finally ColumnsInfo.Free; end; end; {** Takes a name patternand column name and retuen an appropriate SQL clause @param Pattern a sql pattren @parma Column a sql column name @return processed string for query } function TZAbstractDatabaseMetadata.ConstructNameCondition(Pattern: string; Column: string): string; const Spaces = ''; var WorkPattern: string; begin Result := ''; if (Length(Pattern) > 2 * 31) then raise EZSQLException.Create(SPattern2Long); if (Pattern = '%') or (Pattern = '') then Exit; WorkPattern:=NormalizePatternCase(Pattern); if HasNoWildcards(WorkPattern) then begin WorkPattern := StripEscape(WorkPattern); Result := Format('%s = %s', [Column, EscapeString(WorkPattern)]); end else begin Result := Format('%s like %s', [Column, EscapeString(WorkPattern+'%')]); end; end; {** What's the url for this database? @return the url or null if it cannot be generated } function TZAbstractDatabaseMetadata.GetURL: string; begin Result := GetURLString; end; {** What's our user name as known to the database? @return our database user name } function TZAbstractDatabaseMetadata.GetUserName: string; begin Result := FURL.UserName; end; {** Returns general information about the database (version, capabilities, policies, etc). @return the database information object interface. } function TZAbstractDatabaseMetadata.GetDatabaseInfo: IZDatabaseInfo; begin Result := FDatabaseInfo; end; {** Gets a description of the stored procedures available in a catalog.

Only procedure descriptions matching the schema and procedure name criteria are returned. They are ordered by PROCEDURE_SCHEM, and PROCEDURE_NAME.

Each procedure description has the the following columns:

  1. PROCEDURE_CAT String => procedure catalog (may be null)
  2. PROCEDURE_SCHEM String => procedure schema (may be null)
  3. PROCEDURE_NAME String => procedure name
  4. reserved for future use
  5. reserved for future use
  6. reserved for future use
  7. REMARKS String => explanatory comment on the procedure
  8. PROCEDURE_TYPE short => kind of procedure:
    • procedureResultUnknown - May return a result
    • procedureNoResult - Does not return a result
    • procedureReturnsResult - Returns a result
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param procedureNamePattern a procedure name pattern @return ResultSet - each row is a procedure description @see #getSearchStringEscape } function TZAbstractDatabaseMetadata.GetProcedures(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string): IZResultSet; var Key: string; begin if not GetConnection.UseMetadata then begin Result := ConstructVirtualResultSet(ProceduresColumnsDynArray); exit; end; Key := GetProceduresCacheKey(Catalog, SchemaPattern, ProcedureNamePattern); Result := GetResultSetFromCache(Key); if Result = nil then begin Result := UncachedGetProcedures(Catalog, SchemaPattern, ProcedureNamePattern); AddResultSetToCache(Key, Result); end; end; {** Gets a description of the stored procedures available in a catalog.

Only procedure descriptions matching the schema and procedure name criteria are returned. They are ordered by PROCEDURE_SCHEM, and PROCEDURE_NAME.

Each procedure description has the the following columns:

  1. PROCEDURE_CAT String => procedure catalog (may be null)
  2. PROCEDURE_SCHEM String => procedure schema (may be null)
  3. PROCEDURE_NAME String => procedure name
  4. reserved for future use
  5. reserved for future use
  6. reserved for future use
  7. REMARKS String => explanatory comment on the procedure
  8. PROCEDURE_TYPE short => kind of procedure:
    • procedureResultUnknown - May return a result
    • procedureNoResult - Does not return a result
    • procedureReturnsResult - Returns a result
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param procedureNamePattern a procedure name pattern @return ResultSet - each row is a procedure description @see #getSearchStringEscape } function TZAbstractDatabaseMetadata.UncachedGetProcedures(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string): IZResultSet; begin Result := ConstructVirtualResultSet(ProceduresColumnsDynArray); end; {** Gets a description of a catalog's stored procedure parameters and result columns.

Only descriptions matching the schema, procedure and parameter name criteria are returned. They are ordered by PROCEDURE_SCHEM and PROCEDURE_NAME. Within this, the return value, if any, is first. Next are the parameter descriptions in call order. The column descriptions follow in column number order.

Each row in the ResultSet is a parameter description or column description with the following fields:

  1. PROCEDURE_CAT String => procedure catalog (may be null)
  2. PROCEDURE_SCHEM String => procedure schema (may be null)
  3. PROCEDURE_NAME String => procedure name
  4. COLUMN_NAME String => column/parameter name
  5. COLUMN_TYPE Short => kind of column/parameter:
    • procedureColumnUnknown - nobody knows
    • procedureColumnIn - IN parameter
    • procedureColumnInOut - INOUT parameter
    • procedureColumnOut - OUT parameter
    • procedureColumnReturn - procedure return value
    • procedureColumnResult - result column in ResultSet
  6. DATA_TYPE short => SQL type from java.sql.Types
  7. TYPE_NAME String => SQL type name, for a UDT type the type name is fully qualified
  8. PRECISION int => precision
  9. LENGTH int => length in bytes of data
  10. SCALE short => scale
  11. RADIX short => radix
  12. NULLABLE short => can it contain NULL?
    • procedureNoNulls - does not allow NULL values
    • procedureNullable - allows NULL values
    • procedureNullableUnknown - nullability unknown
  13. REMARKS String => comment describing parameter/column

Note: Some databases may not return the column descriptions for a procedure. Additional columns beyond REMARKS can be defined by the database. @param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param procedureNamePattern a procedure name pattern @param columnNamePattern a column name pattern @return ResultSet - each row describes a stored procedure parameter or column @see #getSearchStringEscape } function TZAbstractDatabaseMetadata.GetProcedureColumns(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string; const ColumnNamePattern: string): IZResultSet; var Key: string; begin if not GetConnection.UseMetadata then begin Result := ConstructVirtualResultSet(ProceduresColColumnsDynArray); exit; end; Key := GetProcedureColumnsCacheKey(Catalog, SchemaPattern, ProcedureNamePattern, ColumnNamePattern); Result := GetResultSetFromCache(Key); if Result = nil then begin Result := UncachedGetProcedureColumns(Catalog, SchemaPattern, ProcedureNamePattern, ColumnNamePattern); AddResultSetToCache(Key, Result); end; end; {** Gets a description of a catalog's stored procedure parameters and result columns.

Only descriptions matching the schema, procedure and parameter name criteria are returned. They are ordered by PROCEDURE_SCHEM and PROCEDURE_NAME. Within this, the return value, if any, is first. Next are the parameter descriptions in call order. The column descriptions follow in column number order.

Each row in the ResultSet is a parameter description or column description with the following fields:

  1. PROCEDURE_CAT String => procedure catalog (may be null)
  2. PROCEDURE_SCHEM String => procedure schema (may be null)
  3. PROCEDURE_NAME String => procedure name
  4. COLUMN_NAME String => column/parameter name
  5. COLUMN_TYPE Short => kind of column/parameter:
    • procedureColumnUnknown - nobody knows
    • procedureColumnIn - IN parameter
    • procedureColumnInOut - INOUT parameter
    • procedureColumnOut - OUT parameter
    • procedureColumnReturn - procedure return value
    • procedureColumnResult - result column in ResultSet
  6. DATA_TYPE short => SQL type from java.sql.Types
  7. TYPE_NAME String => SQL type name, for a UDT type the type name is fully qualified
  8. PRECISION int => precision
  9. LENGTH int => length in bytes of data
  10. SCALE short => scale
  11. RADIX short => radix
  12. NULLABLE short => can it contain NULL?
    • procedureNoNulls - does not allow NULL values
    • procedureNullable - allows NULL values
    • procedureNullableUnknown - nullability unknown
  13. REMARKS String => comment describing parameter/column

Note: Some databases may not return the column descriptions for a procedure. Additional columns beyond REMARKS can be defined by the database. @param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param procedureNamePattern a procedure name pattern @param columnNamePattern a column name pattern @return ResultSet - each row describes a stored procedure parameter or column @see #getSearchStringEscape } function TZAbstractDatabaseMetadata.UncachedGetProcedureColumns(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string; const ColumnNamePattern: string): IZResultSet; begin Result := ConstructVirtualResultSet(ProceduresColColumnsDynArray); end; function TZAbstractDatabaseMetadata.GetTriggers(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const TriggerNamePattern: string): IZResultSet; var Key: string; begin if not GetConnection.UseMetadata then begin Result := ConstructVirtualResultSet(TriggersColumnsDynArray); exit; end; Key := GetTriggersCacheKey(Catalog, SchemaPattern, TableNamePattern, TriggerNamePattern); Result := GetResultSetFromCache(Key); if Result = nil then begin Result := UncachedGetTriggers(Catalog, SchemaPattern, TableNamePattern, TriggerNamePattern); AddResultSetToCache(Key, Result); end; end; function TZAbstractDatabaseMetadata.UncachedGetTriggers(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const TriggerNamePattern: string): IZResultSet; begin Result := ConstructVirtualResultSet(TriggersColumnsDynArray); end; function TZAbstractDatabaseMetadata.GetCollationAndCharSet(const Catalog, Schema, TableName, ColumnName: String): IZResultSet; var Key: string; begin if not GetConnection.UseMetadata then begin Result := ConstructVirtualResultSet(CollationCharSetColumnsDynArray); exit; end; Key := GetCollationAndCharSetCacheKey(Catalog, Schema, TableName, ColumnName); Result := GetResultSetFromCache(Key); if Result = nil then begin Result := UncachedGetCollationAndCharSet(Catalog, Schema, TableName, ColumnName); AddResultSetToCache(Key, Result); end; end; function TZAbstractDatabaseMetadata.GetCharacterSets: IZResultSet; //EgonHugeist var Key: string; begin if not GetConnection.UseMetadata then begin Result := ConstructVirtualResultSet(CharacterSetsColumnsDynArray); exit; end; Key := GetCharacterSetsCacheKey; Result := GetResultSetFromCache(Key); if Result = nil then begin Result := UncachedGetCharacterSets; AddResultSetToCache(Key, Result); end; end; function TZAbstractDatabaseMetadata.UncachedGetCollationAndCharSet(const Catalog, SchemaPattern, TableNamePattern, ColumnNamePattern: string): IZResultSet; begin Result := ConstructVirtualResultSet(CollationCharSetColumnsDynArray); end; function TZAbstractDatabaseMetadata.UncachedGetCharacterSets: IZResultSet; //EgonHugeist begin Result := ConstructVirtualResultSet(CharacterSetsColumnsDynArray); end; function TZAbstractDatabaseMetadata.GetCollationAndCharSetCacheKey(const Catalog, SchemaPattern, TableNamePattern, ColumnPattern: String): string; begin Result := Format('get-CollationAndCharSet:%s:%s:%s:%s', [Catalog, SchemaPattern, TableNamePattern, ColumnPattern]); end; function TZAbstractDatabaseMetadata.GetCharacterSetsCacheKey: String; //EgonHugeist begin Result := 'get-charactersets'; end; function TZAbstractDatabaseMetadata.GetTriggersCacheKey(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const TriggerNamePattern: string): string; begin Result := Format('get-trigger:%s:%s:%s:%s', [Catalog, SchemaPattern, TableNamePattern, TriggerNamePattern]); end; {** Gets a description of tables available in a catalog.

Only table descriptions matching the catalog, schema, table name and type criteria are returned. They are ordered by TABLE_TYPE, TABLE_SCHEM and TABLE_NAME.

Each table description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. TABLE_TYPE String => table type. Typical types are "TABLE", "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM".
  5. REMARKS String => explanatory comment on the table

Note: Some databases may not return information for all tables. @param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param tableNamePattern a table name pattern @param types a list of table types to include; null returns all types @return ResultSet - each row is a table description @see #getSearchStringEscape } function TZAbstractDatabaseMetadata.GetTables(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const Types: TStringDynArray): IZResultSet; var Key: string; begin if not GetConnection.UseMetadata then begin Result := ConstructVirtualResultSet(TableColumnsDynArray); exit; end; Key := GetTablesCacheKey(Catalog, SchemaPattern, TableNamePattern, Types); Result := GetResultSetFromCache(Key); if Result = nil then begin Result := UncachedGetTables(Catalog, SchemaPattern, TableNamePattern, Types); AddResultSetToCache(Key, Result); end; end; {** Gets a description of tables available in a catalog.

Only table descriptions matching the catalog, schema, table name and type criteria are returned. They are ordered by TABLE_TYPE, TABLE_SCHEM and TABLE_NAME.

Each table description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. TABLE_TYPE String => table type. Typical types are "TABLE", "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM".
  5. REMARKS String => explanatory comment on the table

Note: Some databases may not return information for all tables. @param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param tableNamePattern a table name pattern @param types a list of table types to include; null returns all types @return ResultSet - each row is a table description @see #getSearchStringEscape } function TZAbstractDatabaseMetadata.UncachedGetTables(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const Types: TStringDynArray): IZResultSet; begin Result := ConstructVirtualResultSet(TableColumnsDynArray); end; {** Gets the schema names available in this database. The results are ordered by schema name.

The schema column is:

  1. TABLE_SCHEM String => schema name
@return ResultSet - each row has a single String column that is a schema name } function TZAbstractDatabaseMetadata.GetSchemas: IZResultSet; var Key: string; begin if not GetConnection.UseMetadata then begin Result := ConstructVirtualResultSet(SchemaColumnsDynArray); exit; end; Key := GetSchemasCacheKey; Result := GetResultSetFromCache(Key); if Result = nil then begin Result := UncachedGetSchemas; AddResultSetToCache(Key, Result); end; end; {** Gets the schema names available in this database. The results are ordered by schema name.

The schema column is:

  1. TABLE_SCHEM String => schema name
@return ResultSet - each row has a single String column that is a schema name } function TZAbstractDatabaseMetadata.UncachedGetSchemas: IZResultSet; begin Result := ConstructVirtualResultSet(SchemaColumnsDynArray); end; {** Gets the catalog names available in this database. The results are ordered by catalog name.

The catalog column is:

  1. TABLE_CAT String => catalog name
@return ResultSet - each row has a single String column that is a catalog name } function TZAbstractDatabaseMetadata.GetCatalogs: IZResultSet; var Key: string; begin if not GetConnection.UseMetadata then begin Result := ConstructVirtualResultSet(CatalogColumnsDynArray); exit; end; Key := GetCatalogsCacheKey; Result := GetResultSetFromCache(Key); if Result = nil then begin Result := UncachedGetCatalogs; AddResultSetToCache(Key, Result); end; end; {** Gets the catalog names available in this database. The results are ordered by catalog name.

The catalog column is:

  1. TABLE_CAT String => catalog name
@return ResultSet - each row has a single String column that is a catalog name } function TZAbstractDatabaseMetadata.UncachedGetCatalogs: IZResultSet; begin Result := ConstructVirtualResultSet(CatalogColumnsDynArray); end; {** Gets the table types available in this database. The results are ordered by table type.

The table type is:

  1. TABLE_TYPE String => table type. Typical types are "TABLE", "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM".
@return ResultSet - each row has a single String column that is a table type } function TZAbstractDatabaseMetadata.GetTableTypes: IZResultSet; var Key: string; begin if not GetConnection.UseMetadata then begin Result := ConstructVirtualResultSet(TableTypeColumnsDynArray); exit; end; Key := GetTableTypesCacheKey; Result := GetResultSetFromCache(Key); if Result = nil then begin Result := UncachedGetTableTypes; AddResultSetToCache(Key, Result); end; end; {** Gets the table types available in this database. The results are ordered by table type.

The table type is:

  1. TABLE_TYPE String => table type. Typical types are "TABLE", "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM".
@return ResultSet - each row has a single String column that is a table type } function TZAbstractDatabaseMetadata.UncachedGetTableTypes: IZResultSet; begin Result := ConstructVirtualResultSet(TableTypeColumnsDynArray); end; {** Gets a description of table columns available in the specified catalog.

Only column descriptions matching the catalog, schema, table and column name criteria are returned. They are ordered by TABLE_SCHEM, TABLE_NAME and ORDINAL_POSITION.

Each column description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. COLUMN_NAME String => column name
  5. DATA_TYPE short => SQL type from java.sql.Types
  6. TYPE_NAME String => Data source dependent type name, for a UDT the type name is fully qualified
  7. COLUMN_SIZE int => column size. For char or date types this is the maximum number of characters, for numeric or decimal types this is precision.
  8. BUFFER_LENGTH is not used.
  9. DECIMAL_DIGITS int => the number of fractional digits
  10. NUM_PREC_RADIX int => Radix (typically either 10 or 2)
  11. NULLABLE int => is NULL allowed?
    • columnNoNulls - might not allow NULL values
    • columnNullable - definitely allows NULL values
    • columnNullableUnknown - nullability unknown
  12. REMARKS String => comment describing column (may be null)
  13. COLUMN_DEF String => default value (may be null)
  14. SQL_DATA_TYPE int => unused
  15. SQL_DATETIME_SUB int => unused
  16. CHAR_OCTET_LENGTH int => for char types the maximum number of bytes in the column
  17. ORDINAL_POSITION int => index of column in table (starting at 1)
  18. IS_NULLABLE String => "NO" means column definitely does not allow NULL values; "YES" means the column might allow NULL values. An empty string means nobody knows.
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param tableNamePattern a table name pattern @param columnNamePattern a column name pattern @return ResultSet - each row is a column description @see #getSearchStringEscape } function TZAbstractDatabaseMetadata.GetColumns(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const ColumnNamePattern: string): IZResultSet; var Key: string; begin if not GetConnection.UseMetadata then begin Result := ConstructVirtualResultSet(TableColColumnsDynArray); exit; end; Key := GetColumnsCacheKey(Catalog, SchemaPattern, TableNamePattern, ColumnNamePattern); Result := GetResultSetFromCache(Key); if Result = nil then begin Result := UncachedGetColumns(Catalog, SchemaPattern, TableNamePattern, ColumnNamePattern); AddResultSetToCache(Key, Result); end; end; {** Gets a description of table columns available in the specified catalog.

Only column descriptions matching the catalog, schema, table and column name criteria are returned. They are ordered by TABLE_SCHEM, TABLE_NAME and ORDINAL_POSITION.

Each column description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. COLUMN_NAME String => column name
  5. DATA_TYPE short => SQL type from java.sql.Types
  6. TYPE_NAME String => Data source dependent type name, for a UDT the type name is fully qualified
  7. COLUMN_SIZE int => column size. For char or date types this is the maximum number of characters, for numeric or decimal types this is precision.
  8. BUFFER_LENGTH is not used.
  9. DECIMAL_DIGITS int => the number of fractional digits
  10. NUM_PREC_RADIX int => Radix (typically either 10 or 2)
  11. NULLABLE int => is NULL allowed?
    • columnNoNulls - might not allow NULL values
    • columnNullable - definitely allows NULL values
    • columnNullableUnknown - nullability unknown
  12. REMARKS String => comment describing column (may be null)
  13. COLUMN_DEF String => default value (may be null)
  14. SQL_DATA_TYPE int => unused
  15. SQL_DATETIME_SUB int => unused
  16. CHAR_OCTET_LENGTH int => for char types the maximum number of bytes in the column
  17. ORDINAL_POSITION int => index of column in table (starting at 1)
  18. IS_NULLABLE String => "NO" means column definitely does not allow NULL values; "YES" means the column might allow NULL values. An empty string means nobody knows.
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param tableNamePattern a table name pattern @param columnNamePattern a column name pattern @return ResultSet - each row is a column description @see #getSearchStringEscape } function TZAbstractDatabaseMetadata.UncachedGetColumns(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const ColumnNamePattern: string): IZResultSet; begin Result := ConstructVirtualResultSet(TableColColumnsDynArray); end; {** Gets a description of the access rights for a table's columns.

Only privileges matching the column name criteria are returned. They are ordered by COLUMN_NAME and PRIVILEGE.

Each privilige description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. COLUMN_NAME String => column name
  5. GRANTOR => grantor of access (may be null)
  6. GRANTEE String => grantee of access
  7. PRIVILEGE String => name of access (SELECT, INSERT, UPDATE, REFRENCES, ...)
  8. IS_GRANTABLE String => "YES" if grantee is permitted to grant to others; "NO" if not; null if unknown
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @param columnNamePattern a column name pattern @return ResultSet - each row is a column privilege description @see #getSearchStringEscape } function TZAbstractDatabaseMetadata.GetColumnPrivileges(const Catalog: string; const Schema: string; const Table: string; const ColumnNamePattern: string): IZResultSet; var Key: string; begin if not GetConnection.UseMetadata then begin Result := ConstructVirtualResultSet(TableColPrivColumnsDynArray); exit; end; Key := GetColumnPrivilegesCacheKey(Catalog, Schema, Table, ColumnNamePattern); Result := GetResultSetFromCache(Key); if Result = nil then begin Result := UncachedGetColumnPrivileges(Catalog, Schema, Table, ColumnNamePattern); AddResultSetToCache(Key, Result); end; end; {** Gets a description of the access rights for a table's columns.

Only privileges matching the column name criteria are returned. They are ordered by COLUMN_NAME and PRIVILEGE.

Each privilige description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. COLUMN_NAME String => column name
  5. GRANTOR => grantor of access (may be null)
  6. GRANTEE String => grantee of access
  7. PRIVILEGE String => name of access (SELECT, INSERT, UPDATE, REFRENCES, ...)
  8. IS_GRANTABLE String => "YES" if grantee is permitted to grant to others; "NO" if not; null if unknown
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @param columnNamePattern a column name pattern @return ResultSet - each row is a column privilege description @see #getSearchStringEscape } function TZAbstractDatabaseMetadata.UncachedGetColumnPrivileges(const Catalog: string; const Schema: string; const Table: string; const ColumnNamePattern: string): IZResultSet; begin Result := ConstructVirtualResultSet(TableColPrivColumnsDynArray); end; {** Gets a description of the access rights for each table available in a catalog. Note that a table privilege applies to one or more columns in the table. It would be wrong to assume that this priviledge applies to all columns (this may be true for some systems but is not true for all.)

Only privileges matching the schema and table name criteria are returned. They are ordered by TABLE_SCHEM, TABLE_NAME, and PRIVILEGE.

Each privilige description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. GRANTOR => grantor of access (may be null)
  5. GRANTEE String => grantee of access
  6. PRIVILEGE String => name of access (SELECT, INSERT, UPDATE, REFRENCES, ...)
  7. IS_GRANTABLE String => "YES" if grantee is permitted to grant to others; "NO" if not; null if unknown
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param tableNamePattern a table name pattern @return ResultSet - each row is a table privilege description @see #getSearchStringEscape } function TZAbstractDatabaseMetadata.GetTablePrivileges(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string): IZResultSet; var Key: string; begin if not GetConnection.UseMetadata then begin Result := ConstructVirtualResultSet(TablePrivColumnsDynArray); exit; end; Key := GetTablePrivilegesCacheKey(Catalog, SchemaPattern, TableNamePattern); Result := GetResultSetFromCache(Key); if Result = nil then begin Result := UncachedGetTablePrivileges(Catalog, SchemaPattern, TableNamePattern); AddResultSetToCache(Key, Result); end; end; {** Gets a description of the access rights for each table available in a catalog. Note that a table privilege applies to one or more columns in the table. It would be wrong to assume that this priviledge applies to all columns (this may be true for some systems but is not true for all.)

Only privileges matching the schema and table name criteria are returned. They are ordered by TABLE_SCHEM, TABLE_NAME, and PRIVILEGE.

Each privilige description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. GRANTOR => grantor of access (may be null)
  5. GRANTEE String => grantee of access
  6. PRIVILEGE String => name of access (SELECT, INSERT, UPDATE, REFRENCES, ...)
  7. IS_GRANTABLE String => "YES" if grantee is permitted to grant to others; "NO" if not; null if unknown
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param tableNamePattern a table name pattern @return ResultSet - each row is a table privilege description @see #getSearchStringEscape } function TZAbstractDatabaseMetadata.UncachedGetTablePrivileges(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string): IZResultSet; begin Result := ConstructVirtualResultSet(TablePrivColumnsDynArray); end; {** Gets a description of a table's optimal set of columns that uniquely identifies a row. They are ordered by SCOPE.

Each column description has the following columns:

  1. SCOPE short => actual scope of result
    • bestRowTemporary - very temporary, while using row
    • bestRowTransaction - valid for remainder of current transaction
    • bestRowSession - valid for remainder of current session
  2. COLUMN_NAME String => column name
  3. DATA_TYPE short => SQL data type from java.sql.Types
  4. TYPE_NAME String => Data source dependent type name, for a UDT the type name is fully qualified
  5. COLUMN_SIZE int => precision
  6. BUFFER_LENGTH int => not used
  7. DECIMAL_DIGITS short => scale
  8. PSEUDO_COLUMN short => is this a pseudo column like an Oracle ROWID
    • bestRowUnknown - may or may not be pseudo column
    • bestRowNotPseudo - is NOT a pseudo column
    • bestRowPseudo - is a pseudo column
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @param scope the scope of interest; use same values as SCOPE @param nullable include columns that are nullable? @return ResultSet - each row is a column description } function TZAbstractDatabaseMetadata.GetBestRowIdentifier(const Catalog: string; const Schema: string; const Table: string; Scope: Integer; Nullable: Boolean): IZResultSet; var Key: string; begin if not GetConnection.UseMetadata then begin Result := ConstructVirtualResultSet(BestRowIdentColumnsDynArray); exit; end; Key := GetBestRowIdentifierCacheKey(Catalog, Schema, Table, Scope, Nullable); Result := GetResultSetFromCache(Key); if Result = nil then begin Result := UncachedGetBestRowIdentifier(Catalog, Schema, Table, Scope, Nullable); AddResultSetToCache(Key, Result); end; end; {** Gets a description of a table's optimal set of columns that uniquely identifies a row. They are ordered by SCOPE.

Each column description has the following columns:

  1. SCOPE short => actual scope of result
    • bestRowTemporary - very temporary, while using row
    • bestRowTransaction - valid for remainder of current transaction
    • bestRowSession - valid for remainder of current session
  2. COLUMN_NAME String => column name
  3. DATA_TYPE short => SQL data type from java.sql.Types
  4. TYPE_NAME String => Data source dependent type name, for a UDT the type name is fully qualified
  5. COLUMN_SIZE int => precision
  6. BUFFER_LENGTH int => not used
  7. DECIMAL_DIGITS short => scale
  8. PSEUDO_COLUMN short => is this a pseudo column like an Oracle ROWID
    • bestRowUnknown - may or may not be pseudo column
    • bestRowNotPseudo - is NOT a pseudo column
    • bestRowPseudo - is a pseudo column
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @param scope the scope of interest; use same values as SCOPE @param nullable include columns that are nullable? @return ResultSet - each row is a column description } function TZAbstractDatabaseMetadata.UncachedGetBestRowIdentifier(const Catalog: string; const Schema: string; const Table: string; Scope: Integer; Nullable: Boolean): IZResultSet; var IndexName: string; ColumnNames: TStrings; begin Result := ConstructVirtualResultSet(BestRowIdentColumnsDynArray); ColumnNames := TStringList.Create; try { Tries primary keys. } with GetPrimaryKeys(Catalog, Schema, Table) do begin while Next do ColumnNames.Add(GetStringByName('COLUMN_NAME')); Close; end; { Tries unique indices. } if ColumnNames.Count = 0 then begin with GetIndexInfo(Catalog, Schema, Table, True, False) do begin IndexName := ''; while Next do begin if IndexName = '' then IndexName := GetStringByName('INDEX_NAME'); if GetStringByName('INDEX_NAME') = IndexName then ColumnNames.Add(GetStringByName('COLUMN_NAME')); end; Close; end; end; with GetColumns(Catalog, Schema, Table, '') do begin while Next do begin if (ColumnNames.Count <> 0) and (ColumnNames.IndexOf( GetStringByName('COLUMN_NAME')) < 0) then Continue; if (ColumnNames.Count = 0) and (TZSQLType(GetIntByName('DATA_TYPE')) in [stBytes, stBinaryStream, stAsciiStream, stUnicodeStream]) then Continue; Result.MoveToInsertRow; Result.UpdateInt(1, Ord(sbrSession)); Result.UpdateString(2, GetStringByName('COLUMN_NAME')); Result.UpdateInt(3, GetIntByName('DATA_TYPE')); Result.UpdateString(4, GetStringByName('TYPE_NAME')); Result.UpdateInt(5, GetIntByName('COLUMN_SIZE')); Result.UpdateInt(6, GetIntByName('BUFFER_LENGTH')); Result.UpdateInt(7, GetIntByName('DECIMAL_DIGITS')); Result.UpdateInt(8, Ord(brNotPseudo)); Result.InsertRow; end; Close; end; finally ColumnNames.Free; end; end; {** Gets a description of a table's columns that are automatically updated when any value in a row is updated. They are unordered.

Each column description has the following columns:

  1. SCOPE short => is not used
  2. COLUMN_NAME String => column name
  3. DATA_TYPE short => SQL data type from java.sql.Types
  4. TYPE_NAME String => Data source dependent type name
  5. COLUMN_SIZE int => precision
  6. BUFFER_LENGTH int => length of column value in bytes
  7. DECIMAL_DIGITS short => scale
  8. PSEUDO_COLUMN short => is this a pseudo column like an Oracle ROWID
    • versionColumnUnknown - may or may not be pseudo column
    • versionColumnNotPseudo - is NOT a pseudo column
    • versionColumnPseudo - is a pseudo column
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a column description @exception SQLException if a database access error occurs } function TZAbstractDatabaseMetadata.GetVersionColumns(const Catalog: string; const Schema: string; const Table: string): IZResultSet; var Key: string; begin if not GetConnection.UseMetadata then begin Result := ConstructVirtualResultSet(TableColVerColumnsDynArray); exit; end; Key := GetVersionColumnsCacheKey(Catalog, Schema, Table); Result := GetResultSetFromCache(Key); if Result = nil then begin Result := UncachedGetVersionColumns(Catalog, Schema, Table); AddResultSetToCache(Key, Result); end; end; {** Gets a description of a table's columns that are automatically updated when any value in a row is updated. They are unordered.

Each column description has the following columns:

  1. SCOPE short => is not used
  2. COLUMN_NAME String => column name
  3. DATA_TYPE short => SQL data type from java.sql.Types
  4. TYPE_NAME String => Data source dependent type name
  5. COLUMN_SIZE int => precision
  6. BUFFER_LENGTH int => length of column value in bytes
  7. DECIMAL_DIGITS short => scale
  8. PSEUDO_COLUMN short => is this a pseudo column like an Oracle ROWID
    • versionColumnUnknown - may or may not be pseudo column
    • versionColumnNotPseudo - is NOT a pseudo column
    • versionColumnPseudo - is a pseudo column
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a column description @exception SQLException if a database access error occurs } function TZAbstractDatabaseMetadata.UncachedGetVersionColumns(const Catalog: string; const Schema: string; const Table: string): IZResultSet; begin Result := ConstructVirtualResultSet(TableColVerColumnsDynArray); end; {** Gets a description of a table's primary key columns. They are ordered by COLUMN_NAME.

Each primary key column description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. COLUMN_NAME String => column name
  5. KEY_SEQ short => sequence number within primary key
  6. PK_NAME String => primary key name (may be null)
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a primary key column description @exception SQLException if a database access error occurs } function TZAbstractDatabaseMetadata.GetPrimaryKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; var Key: string; begin if not GetConnection.UseMetadata then begin Result := ConstructVirtualResultSet(PrimaryKeyColumnsDynArray); exit; end; Key := GetPrimaryKeysCacheKey(Catalog, Schema, Table); Result := GetResultSetFromCache(Key); if Result = nil then begin Result := UncachedGetPrimaryKeys(Catalog, Schema, Table); AddResultSetToCache(Key, Result); end; end; {** Gets a description of a table's primary key columns. They are ordered by COLUMN_NAME.

Each primary key column description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. COLUMN_NAME String => column name
  5. KEY_SEQ short => sequence number within primary key
  6. PK_NAME String => primary key name (may be null)
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a primary key column description @exception SQLException if a database access error occurs } function TZAbstractDatabaseMetadata.UncachedGetPrimaryKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; begin Result := ConstructVirtualResultSet(PrimaryKeyColumnsDynArray); end; {** Gets a description of the primary key columns that are referenced by a table's foreign key columns (the primary keys imported by a table). They are ordered by PKTABLE_CAT, PKTABLE_SCHEM, PKTABLE_NAME, and KEY_SEQ.

Each primary key column description has the following columns:

  1. PKTABLE_CAT String => primary key table catalog being imported (may be null)
  2. PKTABLE_SCHEM String => primary key table schema being imported (may be null)
  3. PKTABLE_NAME String => primary key table name being imported
  4. PKCOLUMN_NAME String => primary key column name being imported
  5. FKTABLE_CAT String => foreign key table catalog (may be null)
  6. FKTABLE_SCHEM String => foreign key table schema (may be null)
  7. FKTABLE_NAME String => foreign key table name
  8. FKCOLUMN_NAME String => foreign key column name
  9. KEY_SEQ short => sequence number within foreign key
  10. UPDATE_RULE short => What happens to foreign key when primary is updated:
    • importedNoAction - do not allow update of primary key if it has been imported
    • importedKeyCascade - change imported key to agree with primary key update
    • importedKeySetNull - change imported key to NULL if its primary key has been updated
    • importedKeySetDefault - change imported key to default values if its primary key has been updated
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
  11. DELETE_RULE short => What happens to the foreign key when primary is deleted.
    • importedKeyNoAction - do not allow delete of primary key if it has been imported
    • importedKeyCascade - delete rows that import a deleted key
    • importedKeySetNull - change imported key to NULL if its primary key has been deleted
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
    • importedKeySetDefault - change imported key to default if its primary key has been deleted
  12. FK_NAME String => foreign key name (may be null)
  13. PK_NAME String => primary key name (may be null)
  14. DEFERRABILITY short => can the evaluation of foreign key constraints be deferred until commit
    • importedKeyInitiallyDeferred - see SQL92 for definition
    • importedKeyInitiallyImmediate - see SQL92 for definition
    • importedKeyNotDeferrable - see SQL92 for definition
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a primary key column description @see #getExportedKeys } function TZAbstractDatabaseMetadata.GetImportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; var Key: string; begin if not GetConnection.UseMetadata then begin Result := ConstructVirtualResultSet(ImportedKeyColumnsDynArray); exit; end; Key := GetImportedKeysCacheKey(Catalog, Schema, Table); Result := GetResultSetFromCache(Key); if Result = nil then begin Result := UncachedGetImportedKeys(Catalog, Schema, Table); AddResultSetToCache(Key, Result); end; end; {** Gets a description of the primary key columns that are referenced by a table's foreign key columns (the primary keys imported by a table). They are ordered by PKTABLE_CAT, PKTABLE_SCHEM, PKTABLE_NAME, and KEY_SEQ.

Each primary key column description has the following columns:

  1. PKTABLE_CAT String => primary key table catalog being imported (may be null)
  2. PKTABLE_SCHEM String => primary key table schema being imported (may be null)
  3. PKTABLE_NAME String => primary key table name being imported
  4. PKCOLUMN_NAME String => primary key column name being imported
  5. FKTABLE_CAT String => foreign key table catalog (may be null)
  6. FKTABLE_SCHEM String => foreign key table schema (may be null)
  7. FKTABLE_NAME String => foreign key table name
  8. FKCOLUMN_NAME String => foreign key column name
  9. KEY_SEQ short => sequence number within foreign key
  10. UPDATE_RULE short => What happens to foreign key when primary is updated:
    • importedNoAction - do not allow update of primary key if it has been imported
    • importedKeyCascade - change imported key to agree with primary key update
    • importedKeySetNull - change imported key to NULL if its primary key has been updated
    • importedKeySetDefault - change imported key to default values if its primary key has been updated
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
  11. DELETE_RULE short => What happens to the foreign key when primary is deleted.
    • importedKeyNoAction - do not allow delete of primary key if it has been imported
    • importedKeyCascade - delete rows that import a deleted key
    • importedKeySetNull - change imported key to NULL if its primary key has been deleted
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
    • importedKeySetDefault - change imported key to default if its primary key has been deleted
  12. FK_NAME String => foreign key name (may be null)
  13. PK_NAME String => primary key name (may be null)
  14. DEFERRABILITY short => can the evaluation of foreign key constraints be deferred until commit
    • importedKeyInitiallyDeferred - see SQL92 for definition
    • importedKeyInitiallyImmediate - see SQL92 for definition
    • importedKeyNotDeferrable - see SQL92 for definition
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a primary key column description @see #getExportedKeys } function TZAbstractDatabaseMetadata.UncachedGetImportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; begin Result := ConstructVirtualResultSet(ImportedKeyColumnsDynArray); end; {** Gets a description of the foreign key columns that reference a table's primary key columns (the foreign keys exported by a table). They are ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, and KEY_SEQ.

Each foreign key column description has the following columns:

  1. PKTABLE_CAT String => primary key table catalog (may be null)
  2. PKTABLE_SCHEM String => primary key table schema (may be null)
  3. PKTABLE_NAME String => primary key table name
  4. PKCOLUMN_NAME String => primary key column name
  5. FKTABLE_CAT String => foreign key table catalog (may be null) being exported (may be null)
  6. FKTABLE_SCHEM String => foreign key table schema (may be null) being exported (may be null)
  7. FKTABLE_NAME String => foreign key table name being exported
  8. FKCOLUMN_NAME String => foreign key column name being exported
  9. KEY_SEQ short => sequence number within foreign key
  10. UPDATE_RULE short => What happens to foreign key when primary is updated:
    • importedNoAction - do not allow update of primary key if it has been imported
    • importedKeyCascade - change imported key to agree with primary key update
    • importedKeySetNull - change imported key to NULL if its primary key has been updated
    • importedKeySetDefault - change imported key to default values if its primary key has been updated
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
  11. DELETE_RULE short => What happens to the foreign key when primary is deleted.
    • importedKeyNoAction - do not allow delete of primary key if it has been imported
    • importedKeyCascade - delete rows that import a deleted key
    • importedKeySetNull - change imported key to NULL if its primary key has been deleted
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
    • importedKeySetDefault - change imported key to default if its primary key has been deleted
  12. FK_NAME String => foreign key name (may be null)
  13. PK_NAME String => primary key name (may be null)
  14. DEFERRABILITY short => can the evaluation of foreign key constraints be deferred until commit
    • importedKeyInitiallyDeferred - see SQL92 for definition
    • importedKeyInitiallyImmediate - see SQL92 for definition
    • importedKeyNotDeferrable - see SQL92 for definition
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a foreign key column description @see #getImportedKeys } function TZAbstractDatabaseMetadata.GetExportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; var Key: string; begin if not GetConnection.UseMetadata then begin Result := ConstructVirtualResultSet(ExportedKeyColumnsDynArray); exit; end; Key := GetExportedKeysCacheKey(Catalog, Schema, Table); Result := GetResultSetFromCache(Key); if Result = nil then begin Result := UncachedGetExportedKeys(Catalog, Schema, Table); AddResultSetToCache(Key, Result); end; end; {** Gets a description of the foreign key columns that reference a table's primary key columns (the foreign keys exported by a table). They are ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, and KEY_SEQ.

Each foreign key column description has the following columns:

  1. PKTABLE_CAT String => primary key table catalog (may be null)
  2. PKTABLE_SCHEM String => primary key table schema (may be null)
  3. PKTABLE_NAME String => primary key table name
  4. PKCOLUMN_NAME String => primary key column name
  5. FKTABLE_CAT String => foreign key table catalog (may be null) being exported (may be null)
  6. FKTABLE_SCHEM String => foreign key table schema (may be null) being exported (may be null)
  7. FKTABLE_NAME String => foreign key table name being exported
  8. FKCOLUMN_NAME String => foreign key column name being exported
  9. KEY_SEQ short => sequence number within foreign key
  10. UPDATE_RULE short => What happens to foreign key when primary is updated:
    • importedNoAction - do not allow update of primary key if it has been imported
    • importedKeyCascade - change imported key to agree with primary key update
    • importedKeySetNull - change imported key to NULL if its primary key has been updated
    • importedKeySetDefault - change imported key to default values if its primary key has been updated
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
  11. DELETE_RULE short => What happens to the foreign key when primary is deleted.
    • importedKeyNoAction - do not allow delete of primary key if it has been imported
    • importedKeyCascade - delete rows that import a deleted key
    • importedKeySetNull - change imported key to NULL if its primary key has been deleted
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
    • importedKeySetDefault - change imported key to default if its primary key has been deleted
  12. FK_NAME String => foreign key name (may be null)
  13. PK_NAME String => primary key name (may be null)
  14. DEFERRABILITY short => can the evaluation of foreign key constraints be deferred until commit
    • importedKeyInitiallyDeferred - see SQL92 for definition
    • importedKeyInitiallyImmediate - see SQL92 for definition
    • importedKeyNotDeferrable - see SQL92 for definition
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a foreign key column description @see #getImportedKeys } function TZAbstractDatabaseMetadata.UncachedGetExportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; begin Result := ConstructVirtualResultSet(ExportedKeyColumnsDynArray); end; {** Gets a description of the foreign key columns in the foreign key table that reference the primary key columns of the primary key table (describe how one table imports another's key.) This should normally return a single foreign key/primary key pair (most tables only import a foreign key from a table once.) They are ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, and KEY_SEQ.

Each foreign key column description has the following columns:

  1. PKTABLE_CAT String => primary key table catalog (may be null)
  2. PKTABLE_SCHEM String => primary key table schema (may be null)
  3. PKTABLE_NAME String => primary key table name
  4. PKCOLUMN_NAME String => primary key column name
  5. FKTABLE_CAT String => foreign key table catalog (may be null) being exported (may be null)
  6. FKTABLE_SCHEM String => foreign key table schema (may be null) being exported (may be null)
  7. FKTABLE_NAME String => foreign key table name being exported
  8. FKCOLUMN_NAME String => foreign key column name being exported
  9. KEY_SEQ short => sequence number within foreign key
  10. UPDATE_RULE short => What happens to foreign key when primary is updated:
    • importedNoAction - do not allow update of primary key if it has been imported
    • importedKeyCascade - change imported key to agree with primary key update
    • importedKeySetNull - change imported key to NULL if its primary key has been updated
    • importedKeySetDefault - change imported key to default values if its primary key has been updated
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
  11. DELETE_RULE short => What happens to the foreign key when primary is deleted.
    • importedKeyNoAction - do not allow delete of primary key if it has been imported
    • importedKeyCascade - delete rows that import a deleted key
    • importedKeySetNull - change imported key to NULL if its primary key has been deleted
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
    • importedKeySetDefault - change imported key to default if its primary key has been deleted
  12. FK_NAME String => foreign key name (may be null)
  13. PK_NAME String => primary key name (may be null)
  14. DEFERRABILITY short => can the evaluation of foreign key constraints be deferred until commit
    • importedKeyInitiallyDeferred - see SQL92 for definition
    • importedKeyInitiallyImmediate - see SQL92 for definition
    • importedKeyNotDeferrable - see SQL92 for definition
@param primaryCatalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param primarySchema a schema name; "" retrieves those without a schema @param primaryTable the table name that exports the key @param foreignCatalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param foreignSchema a schema name; "" retrieves those without a schema @param foreignTable the table name that imports the key @return ResultSet - each row is a foreign key column description @see #getImportedKeys } function TZAbstractDatabaseMetadata.GetCrossReference(const PrimaryCatalog: string; const PrimarySchema: string; const PrimaryTable: string; const ForeignCatalog: string; const ForeignSchema: string; const ForeignTable: string): IZResultSet; var Key: string; begin if not GetConnection.UseMetadata then begin Result := ConstructVirtualResultSet(CrossRefColumnsDynArray); exit; end; Key := GetCrossReferenceCacheKey(PrimaryCatalog, PrimarySchema, PrimaryTable, ForeignCatalog, ForeignSchema, ForeignTable); Result := GetResultSetFromCache(Key); if Result = nil then begin Result := UncachedGetCrossReference(PrimaryCatalog, PrimarySchema, PrimaryTable, ForeignCatalog, ForeignSchema, ForeignTable); AddResultSetToCache(Key, Result); end; end; {** Gets a description of the foreign key columns in the foreign key table that reference the primary key columns of the primary key table (describe how one table imports another's key.) This should normally return a single foreign key/primary key pair (most tables only import a foreign key from a table once.) They are ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, and KEY_SEQ.

Each foreign key column description has the following columns:

  1. PKTABLE_CAT String => primary key table catalog (may be null)
  2. PKTABLE_SCHEM String => primary key table schema (may be null)
  3. PKTABLE_NAME String => primary key table name
  4. PKCOLUMN_NAME String => primary key column name
  5. FKTABLE_CAT String => foreign key table catalog (may be null) being exported (may be null)
  6. FKTABLE_SCHEM String => foreign key table schema (may be null) being exported (may be null)
  7. FKTABLE_NAME String => foreign key table name being exported
  8. FKCOLUMN_NAME String => foreign key column name being exported
  9. KEY_SEQ short => sequence number within foreign key
  10. UPDATE_RULE short => What happens to foreign key when primary is updated:
    • importedNoAction - do not allow update of primary key if it has been imported
    • importedKeyCascade - change imported key to agree with primary key update
    • importedKeySetNull - change imported key to NULL if its primary key has been updated
    • importedKeySetDefault - change imported key to default values if its primary key has been updated
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
  11. DELETE_RULE short => What happens to the foreign key when primary is deleted.
    • importedKeyNoAction - do not allow delete of primary key if it has been imported
    • importedKeyCascade - delete rows that import a deleted key
    • importedKeySetNull - change imported key to NULL if its primary key has been deleted
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
    • importedKeySetDefault - change imported key to default if its primary key has been deleted
  12. FK_NAME String => foreign key name (may be null)
  13. PK_NAME String => primary key name (may be null)
  14. DEFERRABILITY short => can the evaluation of foreign key constraints be deferred until commit
    • importedKeyInitiallyDeferred - see SQL92 for definition
    • importedKeyInitiallyImmediate - see SQL92 for definition
    • importedKeyNotDeferrable - see SQL92 for definition
@param primaryCatalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param primarySchema a schema name; "" retrieves those without a schema @param primaryTable the table name that exports the key @param foreignCatalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param foreignSchema a schema name; "" retrieves those without a schema @param foreignTable the table name that imports the key @return ResultSet - each row is a foreign key column description @see #getImportedKeys } function TZAbstractDatabaseMetadata.UncachedGetCrossReference(const PrimaryCatalog: string; const PrimarySchema: string; const PrimaryTable: string; const ForeignCatalog: string; const ForeignSchema: string; const ForeignTable: string): IZResultSet; begin Result := ConstructVirtualResultSet(CrossRefColumnsDynArray); end; {** Gets a description of all the standard SQL types supported by this database. They are ordered by DATA_TYPE and then by how closely the data type maps to the corresponding JDBC SQL type.

Each type description has the following columns:

  1. TYPE_NAME String => Type name
  2. DATA_TYPE short => SQL data type from java.sql.Types
  3. PRECISION int => maximum precision
  4. LITERAL_PREFIX String => prefix used to quote a literal (may be null)
  5. LITERAL_SUFFIX String => suffix used to quote a literal (may be null)
  6. CREATE_PARAMS String => parameters used in creating the type (may be null)
  7. NULLABLE short => can you use NULL for this type?
    • typeNoNulls - does not allow NULL values
    • typeNullable - allows NULL values
    • typeNullableUnknown - nullability unknown
  8. CASE_SENSITIVE boolean=> is it case sensitive?
  9. SEARCHABLE short => can you use "WHERE" based on this type:
    • typePredNone - No support
    • typePredChar - Only supported with WHERE .. LIKE
    • typePredBasic - Supported except for WHERE .. LIKE
    • typeSearchable - Supported for all WHERE ..
  10. UNSIGNED_ATTRIBUTE boolean => is it unsigned?
  11. FIXED_PREC_SCALE boolean => can it be a money value?
  12. AUTO_INCREMENT boolean => can it be used for an auto-increment value?
  13. LOCAL_TYPE_NAME String => localized version of type name (may be null)
  14. MINIMUM_SCALE short => minimum scale supported
  15. MAXIMUM_SCALE short => maximum scale supported
  16. SQL_DATA_TYPE int => unused
  17. SQL_DATETIME_SUB int => unused
  18. NUM_PREC_RADIX int => usually 2 or 10
@return ResultSet - each row is an SQL type description } function TZAbstractDatabaseMetadata.GetTypeInfo: IZResultSet; var Key: string; begin if not GetConnection.UseMetadata then begin Result := ConstructVirtualResultSet(TypeInfoColumnsDynArray); exit; end; Key := GetTypeInfoCacheKey; Result := GetResultSetFromCache(Key); if Result = nil then begin Result := UncachedGetTypeInfo; AddResultSetToCache(Key, Result); end; end; {** Gets a description of all the standard SQL types supported by this database. They are ordered by DATA_TYPE and then by how closely the data type maps to the corresponding JDBC SQL type.

Each type description has the following columns:

  1. TYPE_NAME String => Type name
  2. DATA_TYPE short => SQL data type from java.sql.Types
  3. PRECISION int => maximum precision
  4. LITERAL_PREFIX String => prefix used to quote a literal (may be null)
  5. LITERAL_SUFFIX String => suffix used to quote a literal (may be null)
  6. CREATE_PARAMS String => parameters used in creating the type (may be null)
  7. NULLABLE short => can you use NULL for this type?
    • typeNoNulls - does not allow NULL values
    • typeNullable - allows NULL values
    • typeNullableUnknown - nullability unknown
  8. CASE_SENSITIVE boolean=> is it case sensitive?
  9. SEARCHABLE short => can you use "WHERE" based on this type:
    • typePredNone - No support
    • typePredChar - Only supported with WHERE .. LIKE
    • typePredBasic - Supported except for WHERE .. LIKE
    • typeSearchable - Supported for all WHERE ..
  10. UNSIGNED_ATTRIBUTE boolean => is it unsigned?
  11. FIXED_PREC_SCALE boolean => can it be a money value?
  12. AUTO_INCREMENT boolean => can it be used for an auto-increment value?
  13. LOCAL_TYPE_NAME String => localized version of type name (may be null)
  14. MINIMUM_SCALE short => minimum scale supported
  15. MAXIMUM_SCALE short => maximum scale supported
  16. SQL_DATA_TYPE int => unused
  17. SQL_DATETIME_SUB int => unused
  18. NUM_PREC_RADIX int => usually 2 or 10
@return ResultSet - each row is an SQL type description } function TZAbstractDatabaseMetadata.UncachedGetTypeInfo: IZResultSet; begin Result := ConstructVirtualResultSet(TypeInfoColumnsDynArray); end; {** Gets a description of a table's indices and statistics. They are ordered by NON_UNIQUE, TYPE, INDEX_NAME, and ORDINAL_POSITION.

Each index column description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. NON_UNIQUE boolean => Can index values be non-unique? false when TYPE is tableIndexStatistic
  5. INDEX_QUALIFIER String => index catalog (may be null); null when TYPE is tableIndexStatistic
  6. INDEX_NAME String => index name; null when TYPE is tableIndexStatistic
  7. TYPE short => index type:
    • tableIndexStatistic - this identifies table statistics that are returned in conjuction with a table's index descriptions
    • tableIndexClustered - this is a clustered index
    • tableIndexHashed - this is a hashed index
    • tableIndexOther - this is some other style of index
  8. ORDINAL_POSITION short => column sequence number within index; zero when TYPE is tableIndexStatistic
  9. COLUMN_NAME String => column name; null when TYPE is tableIndexStatistic
  10. ASC_OR_DESC String => column sort sequence, "A" => ascending, "D" => descending, may be null if sort sequence is not supported; null when TYPE is tableIndexStatistic
  11. CARDINALITY int => When TYPE is tableIndexStatistic, then this is the number of rows in the table; otherwise, it is the number of unique values in the index.
  12. PAGES int => When TYPE is tableIndexStatisic then this is the number of pages used for the table, otherwise it is the number of pages used for the current index.
  13. FILTER_CONDITION String => Filter condition, if any. (may be null)
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @param unique when true, return only indices for unique values; when false, return indices regardless of whether unique or not @param approximate when true, result is allowed to reflect approximate or out of data values; when false, results are requested to be accurate @return ResultSet - each row is an index column description } function TZAbstractDatabaseMetadata.GetIndexInfo(const Catalog: string; const Schema: string; const Table: string; Unique: Boolean; Approximate: Boolean): IZResultSet; var Key: string; begin if not GetConnection.UseMetadata then begin Result := ConstructVirtualResultSet(IndexInfoColumnsDynArray); exit; end; Key := GetIndexInfoCacheKey(Catalog, Schema, Table, Unique, Approximate); Result := GetResultSetFromCache(Key); if Result = nil then begin Result := UncachedGetIndexInfo(Catalog, Schema, Table, Unique, Approximate); AddResultSetToCache(Key, Result); end; end; {** Gets a description of a table's indices and statistics. They are ordered by NON_UNIQUE, TYPE, INDEX_NAME, and ORDINAL_POSITION.

Each index column description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. NON_UNIQUE boolean => Can index values be non-unique? false when TYPE is tableIndexStatistic
  5. INDEX_QUALIFIER String => index catalog (may be null); null when TYPE is tableIndexStatistic
  6. INDEX_NAME String => index name; null when TYPE is tableIndexStatistic
  7. TYPE short => index type:
    • tableIndexStatistic - this identifies table statistics that are returned in conjuction with a table's index descriptions
    • tableIndexClustered - this is a clustered index
    • tableIndexHashed - this is a hashed index
    • tableIndexOther - this is some other style of index
  8. ORDINAL_POSITION short => column sequence number within index; zero when TYPE is tableIndexStatistic
  9. COLUMN_NAME String => column name; null when TYPE is tableIndexStatistic
  10. ASC_OR_DESC String => column sort sequence, "A" => ascending, "D" => descending, may be null if sort sequence is not supported; null when TYPE is tableIndexStatistic
  11. CARDINALITY int => When TYPE is tableIndexStatistic, then this is the number of rows in the table; otherwise, it is the number of unique values in the index.
  12. PAGES int => When TYPE is tableIndexStatisic then this is the number of pages used for the table, otherwise it is the number of pages used for the current index.
  13. FILTER_CONDITION String => Filter condition, if any. (may be null)
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @param unique when true, return only indices for unique values; when false, return indices regardless of whether unique or not @param approximate when true, result is allowed to reflect approximate or out of data values; when false, results are requested to be accurate @return ResultSet - each row is an index column description } function TZAbstractDatabaseMetadata.UncachedGetIndexInfo(const Catalog: string; const Schema: string; const Table: string; Unique: Boolean; Approximate: Boolean): IZResultSet; begin Result := ConstructVirtualResultSet(IndexInfoColumnsDynArray); end; function TZAbstractDatabaseMetadata.GetSequences(const Catalog: string; const SchemaPattern: string; const SequenceNamePattern: string): IZResultSet; var Key: string; begin if not GetConnection.UseMetadata then begin Result := ConstructVirtualResultSet(SequenceColumnsDynArray); exit; end; Key := GetSequencesCacheKey(Catalog, SchemaPattern, SequenceNamePattern); Result := GetResultSetFromCache(Key); if Result = nil then begin Result := UncachedGetSequences(Catalog, SchemaPattern, SequenceNamePattern); AddResultSetToCache(Key, Result); end; end; function TZAbstractDatabaseMetadata.UncachedGetSequences(const Catalog: string; const SchemaPattern: string; const SequenceNamePattern: string): IZResultSet; begin Result := ConstructVirtualResultSet(SequenceColumnsDynArray); end; {** Gets a description of the user-defined types defined in a particular schema. Schema-specific UDTs may have type JAVA_OBJECT, STRUCT, or DISTINCT.

Only types matching the catalog, schema, type name and type criteria are returned. They are ordered by DATA_TYPE, TYPE_SCHEM and TYPE_NAME. The type name parameter may be a fully-qualified name. In this case, the catalog and schemaPattern parameters are ignored.

Each type description has the following columns:

  1. TYPE_CAT String => the type's catalog (may be null)
  2. TYPE_SCHEM String => type's schema (may be null)
  3. TYPE_NAME String => type name
  4. CLASS_NAME String => Java class name
  5. DATA_TYPE String => type value defined in java.sql.Types. One of JAVA_OBJECT, STRUCT, or DISTINCT
  6. REMARKS String => explanatory comment on the type

Note: If the driver does not support UDTs, an empty result set is returned. @param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param typeNamePattern a type name pattern; may be a fully-qualified name @param types a list of user-named types to include (JAVA_OBJECT, STRUCT, or DISTINCT); null returns all types @return ResultSet - each row is a type description } function TZAbstractDatabaseMetadata.GetUDTs(const Catalog: string; const SchemaPattern: string; const TypeNamePattern: string; const Types: TIntegerDynArray): IZResultSet; var Key: string; begin if not GetConnection.UseMetadata then begin Result := ConstructVirtualResultSet(UDTColumnsDynArray); exit; end; Key := GetUDTsCacheKey(Catalog, SchemaPattern, TypeNamePattern, Types); Result := GetResultSetFromCache(Key); if Result = nil then begin Result := UncachedGetUDTs(Catalog, SchemaPattern, TypeNamePattern, Types); AddResultSetToCache(Key, Result); end; end; {** Gets a description of the user-defined types defined in a particular schema. Schema-specific UDTs may have type JAVA_OBJECT, STRUCT, or DISTINCT.

Only types matching the catalog, schema, type name and type criteria are returned. They are ordered by DATA_TYPE, TYPE_SCHEM and TYPE_NAME. The type name parameter may be a fully-qualified name. In this case, the catalog and schemaPattern parameters are ignored.

Each type description has the following columns:

  1. TYPE_CAT String => the type's catalog (may be null)
  2. TYPE_SCHEM String => type's schema (may be null)
  3. TYPE_NAME String => type name
  4. CLASS_NAME String => Java class name
  5. DATA_TYPE String => type value defined in java.sql.Types. One of JAVA_OBJECT, STRUCT, or DISTINCT
  6. REMARKS String => explanatory comment on the type

Note: If the driver does not support UDTs, an empty result set is returned. @param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param typeNamePattern a type name pattern; may be a fully-qualified name @param types a list of user-named types to include (JAVA_OBJECT, STRUCT, or DISTINCT); null returns all types @return ResultSet - each row is a type description } function TZAbstractDatabaseMetadata.UncachedGetUDTs(const Catalog: string; const SchemaPattern: string; const TypeNamePattern: string; const Types: TIntegerDynArray): IZResultSet; begin Result := ConstructVirtualResultSet(UDTColumnsDynArray); end; {** Creates ab identifier convertor object. @returns an identifier convertor object. } function TZAbstractDatabaseMetadata.GetIdentifierConvertor: IZIdentifierConvertor; begin Result := TZDefaultIdentifierConvertor.Create(Self); end; {** Add escape character in the pattern that has wildcards character @param Pattern The pattern that would be escaped @return Escaped Pattern } function TZAbstractDatabaseMetadata.AddEscapeCharToWildcards( const Pattern: string): string; var i:Integer; EscapeChar : string; begin if GetDatabaseInfo.SupportsNonEscapedSearchStrings then Result := Pattern else begin EscapeChar := GetDatabaseInfo.GetSearchStringEscape; if WildcardsArray<>nil then begin Result:=StringReplace(Pattern,EscapeChar,EscapeChar+EscapeChar,[rfReplaceAll]); for i:=0 to High(WildcardsArray) do Result:=StringReplace(Result,WildcardsArray[i],EscapeChar+WildcardsArray[i],[rfReplaceAll]); end; end; end; {** Set the Wildcards character for WildcardsArray variable. Overrride this method if the wildcards character is different in other database } procedure TZAbstractDatabaseMetadata.FillWildcards; begin SetLength(WildcardsArray,1); WildcardsArray[0]:='%'; {SetLength(WildcardsArray,2); WildcardsArray[0]:='_'; <---- seems to be a trublemaker, no idea how to test it with our tests. See http://zeoslib.sourceforge.net/viewtopic.php?f=40&t=13184 WildcardsArray[1]:='%';} end; function TZAbstractDatabaseMetadata.NormalizePatternCase(Pattern:String): string; begin if not GetIdentifierConvertor.IsQuoted(Pattern) then if FDatabaseInfo.StoresUpperCaseIdentifiers then Result := UpperCase(Pattern) else if FDatabaseInfo.StoresLowerCaseIdentifiers then Result := LowerCase(Pattern) else Result := Pattern else Result := GetIdentifierConvertor.ExtractQuote(Pattern); end; {** Get the Wildscards in set of char type @return TZWildcardsSet type } function TZAbstractDatabaseMetadata.GetWildcardsSet:TZWildcardsSet; var i:Integer; begin Result:=[]; for i:=0 to High(WildcardsArray) do Result:=Result+[WildcardsArray[i]]; end; //---------------------------------------------------------------------- // Metadata cache key retrieval API (technobot 2008-06-14): {** returns cache key for GetProcedures metadata entry @param Catalog a catalog name @param SchemaPattern a schema name pattern @param ProcedureNamePattern a procedure name pattern @return the cache key string } function TZAbstractDatabaseMetadata.GetProceduresCacheKey(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string): string; begin Result := Format('get-procedures:%s:%s:%s', [Catalog, SchemaPattern, ProcedureNamePattern]); end; {** returns cache key for GetProcedureColumns metadata entry @param Catalog a catalog name @param SchemaPattern a schema name pattern @param ProcedureNamePattern a procedure name pattern @param ColumnNamePattern a column name pattern @return the cache key string } function TZAbstractDatabaseMetadata.GetProcedureColumnsCacheKey(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string; const ColumnNamePattern: string): string; begin Result := Format('get-procedure-columns:%s:%s:%s:%s', [Catalog, SchemaPattern, ProcedureNamePattern, ColumnNamePattern]); end; {** returns cache key for GetTables metadata entry @param Catalog a catalog name @param SchemaPattern a schema name pattern @param TableNamePattern a table name pattern @param Types table types list @return the cache key string } function TZAbstractDatabaseMetadata.GetTablesCacheKey(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const Types: TStringDynArray): string; var I: Integer; Key: string; begin Key := ''; for I := Low(Types) to High(Types) do Key := Key + ':' + Types[I]; Result := Format('get-tables:%s:%s:%s:%s', [Catalog, SchemaPattern, TableNamePattern, Key]); end; {** returns cache key for GetSchemas metadata entry @return the cache key string } function TZAbstractDatabaseMetadata.GetSchemasCacheKey: string; begin Result := 'get-schemas'; end; {** returns cache key for GetCatalogs metadata entry @return the cache key string } function TZAbstractDatabaseMetadata.GetCatalogsCacheKey: string; begin Result := 'get-catalogs'; end; {** returns cache key for GetTableTypes metadata entry @return the cache key string } function TZAbstractDatabaseMetadata.GetTableTypesCacheKey: string; begin Result := 'get-table-types'; end; {** returns cache key for GetColumns metadata entry @param Catalog a catalog name @param SchemaPattern a schema name pattern @param TableNamePattern a table name pattern @param ColumnNamePattern a column name pattern @return the cache key string } function TZAbstractDatabaseMetadata.GetColumnsCacheKey(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const ColumnNamePattern: string): string; begin Result := Format('get-columns:%s:%s:%s:%s', [Catalog, SchemaPattern, TableNamePattern, ColumnNamePattern]); end; {** returns cache key for GetColumnPrivileges metadata entry @param Catalog a catalog name @param Schema a schema name @param Table a table name @param ColumnNamePattern a column name pattern @return the cache key string } function TZAbstractDatabaseMetadata.GetColumnPrivilegesCacheKey( const Catalog: string; const Schema: string; const Table: string; const ColumnNamePattern: string): string; begin Result := Format('get-column-privileges:%s:%s:%s:%s', [Catalog, Schema, Table, ColumnNamePattern]); end; {** returns cache key for GetTablePrivileges metadata entry @param Catalog a catalog name @param SchemaPattern a schema name pattern @param TableNamePattern a table name pattern @return the cache key string } function TZAbstractDatabaseMetadata.GetTablePrivilegesCacheKey( const Catalog: string; const SchemaPattern: string; const TableNamePattern: string): string; begin Result := Format('get-table-privileges:%s:%s:%s', [Catalog, SchemaPattern, TableNamePattern]); end; {** returns cache key for GetBestRowIdentifier metadata entry @param Catalog a catalog name @param Schema a schema name @param Table a table name @param Scope the scope of interest @param Nullable include columns that are nullable? @return the cache key string } function TZAbstractDatabaseMetadata.GetBestRowIdentifierCacheKey( const Catalog: string; const Schema: string; const Table: string; const Scope: Integer; const Nullable: Boolean): string; begin Result := Format('get-best-row-identifier:%s:%s:%s:%d:%s', [Catalog, Schema, Table, Scope, BoolToStr(Nullable)]); end; {** returns cache key for GetVersionColumns metadata entry @param Catalog a catalog name @param Schema a schema name @param Table a table name @return the cache key string } function TZAbstractDatabaseMetadata.GetVersionColumnsCacheKey( const Catalog: string; const Schema: string; const Table: string): string; begin Result := Format('get-version-columns:%s:%s:%s', [Catalog, Schema, Table]); end; {** returns cache key for GetPrimaryKeys metadata entry @param Catalog a catalog name @param Schema a schema name @param Table a table name @return the cache key string } function TZAbstractDatabaseMetadata.GetPrimaryKeysCacheKey(const Catalog: string; const Schema: string; const Table: string): string; begin Result := Format('get-primary-keys:%s:%s:%s', [Catalog, Schema, Table]); end; {** returns cache key for GetImportedKeys metadata entry @param Catalog a catalog name @param Schema a schema name @param Table a table name @return the cache key string } function TZAbstractDatabaseMetadata.GetImportedKeysCacheKey(const Catalog: string; const Schema: string; const Table: string): string; begin Result := Format('get-imported-keys:%s:%s:%s', [Catalog, Schema, Table]); end; {** returns cache key for GetExportedKeys metadata entry @param Catalog a catalog name @param Schema a schema name @param Table a table name @return the cache key string } function TZAbstractDatabaseMetadata.GetExportedKeysCacheKey(const Catalog: string; const Schema: string; const Table: string): string; begin Result := Format('get-exported-keys:%s:%s:%s', [Catalog, Schema, Table]); end; {** returns cache key for GetCrossReference metadata entry @param PrimaryCatalog a catalog name for the primary table @param PrimarySchema a schema name for the primary table @param PrimaryTable the table name that exports the key @param ForeignCatalog a catalog name for the foreign table @param ForeignSchema a schema name for the foreign table @param ForeignTable the table name that imports the key @return the cache key string } function TZAbstractDatabaseMetadata.GetCrossReferenceCacheKey( const PrimaryCatalog: string; const PrimarySchema: string; const PrimaryTable: string; const ForeignCatalog: string; const ForeignSchema: string; const ForeignTable: string): string; begin Result := Format('get-cross-reference:%s:%s:%s:%s:%s:%s', [PrimaryCatalog, PrimarySchema, PrimaryTable, ForeignCatalog, ForeignSchema, ForeignTable]); end; {** returns cache key for GetTypeInfo metadata entry @return the cache key string } function TZAbstractDatabaseMetadata.GetTypeInfoCacheKey: string; begin Result := 'get-type-info'; end; {** returns cache key for GetIndexInfo metadata entry @param Catalog a catalog name @param Schema a schema name @param Table a table name @param Unique when true, return key for a metadata entry that should contain only indices for unique values; when false, return key for a metadata entry that may contain indices to non-unique values @param Approximate when true, return key for a metadata entry that may include approximate or out of data values; when false, return key for a metadata entry that should contain only accurate results @return the cache key string } function TZAbstractDatabaseMetadata.GetIndexInfoCacheKey(const Catalog: string; const Schema: string; const Table: string; const Unique: Boolean; const Approximate: Boolean): string; begin Result := Format('get-index-info:%s:%s:%s:%s:%s', [Catalog, Schema, Table, BoolToStr(Unique), BoolToStr(Approximate)]); end; {** returns cache key for GetSequences metadata entry @param Catalog a catalog name @param SchemaPattern a schema name pattern @param SequenceNamePattern a sequence name pattern @return the cache key string } function TZAbstractDatabaseMetadata.GetSequencesCacheKey(const Catalog: string; const SchemaPattern: string; const SequenceNamePattern: string): string; begin Result := Format('get-sequences:%s:%s:%s', [Catalog, SchemaPattern, SequenceNamePattern]); end; {** returns cache key for GetUDTs metadata entry @param Catalog a catalog name @param SchemaPattern a schema name pattern @param TypeNamePattern a type name pattern @param Types a list of user-named types to include @return the cache key string } function TZAbstractDatabaseMetadata.GetUDTsCacheKey(const Catalog: string; const SchemaPattern: string; const TypeNamePattern: string; const Types: TIntegerDynArray): string; var I: Integer; begin Result := ''; for I := Low(Types) to High(Types) do Result := Result + ':' + IntToStr(Types[I]); Result := Format('get-udts:%s:%s:%s%s', [Catalog, SchemaPattern, TypeNamePattern, Result]); end; {** fills string list with the keys for the currently cached metadata entries @param List a string list to fill out } procedure TZAbstractDatabaseMetadata.GetCacheKeys(List: TStrings); var I: Integer; begin List.Clear; with CachedResultSets.Keys do for I := 0 to Count-1 do List.Add((Items[I] as IZAnyValue).GetString); end; // End of metadata cache key retrieval API (technobot 2008-06-14) //---------------------------------------------------------------------- { TZVirtualResultSet } {** Creates this object and assignes the main properties. @param Statement an SQL statement object. @param SQL an SQL query string. } constructor TZVirtualResultSet.CreateWithStatement(const SQL: string; Statement: IZStatement; ConSettings: PZConSettings); begin inherited CreateWithStatement(SQL, Statement, ConSettings); end; {** Creates this object and assignes the main properties. @param ColumnsInfo a columns info for cached rows. @param SQL an SQL query string. } constructor TZVirtualResultSet.CreateWithColumns(ColumnsInfo: TObjectList; const SQL: string; ConSettings: PZConSettings); begin inherited CreateWithColumns(ColumnsInfo, SQL, ConSettings); end; {** Destroys this object and cleanups the memory. } destructor TZVirtualResultSet.Destroy; begin inherited Destroy; end; {** Calculates column default values.. @param RowAccessor a row accessor which contains new column values. } procedure TZVirtualResultSet.CalculateRowDefaults(RowAccessor: TZRowAccessor); begin end; {** Post changes to database server. @param OldRowAccessor a row accessor which contains old column values. @param NewRowAccessor a row accessor which contains new or updated column values. } procedure TZVirtualResultSet.PostRowUpdates(OldRowAccessor, NewRowAccessor: TZRowAccessor); begin end; { TZDefaultIdentifierConvertor } {** Constructs this default identifier convertor object. @param Metadata a database metadata interface. } constructor TZDefaultIdentifierConvertor.Create( Metadata: IZDatabaseMetadata); begin inherited Create; FMetadata := Pointer(Metadata); end; function TZDefaultIdentifierConvertor.GetMetaData; begin if Assigned(FMetadata) then Result := IZDatabaseMetadata(FMetadata) else Result := nil; end; {** Checks is the specified string in lower case. @param an identifier string. @return True is the identifier string in lower case. } function TZDefaultIdentifierConvertor.IsLowerCase(const Value: string): Boolean; var I: Integer; begin Result := True; for I := 1 to Length(Value) do begin if not CharInSet(Value[I], ['a'..'z','0'..'9','_']) then begin Result := False; Break; end; end; end; {** Checks is the specified string in upper case. @param an identifier string. @return True is the identifier string in upper case. } function TZDefaultIdentifierConvertor.IsUpperCase(const Value: string): Boolean; var I: Integer; begin Result := True; for I := 1 to Length(Value) do begin if not CharInSet(Value[I], ['A'..'Z','0'..'9','_']) then begin Result := False; Break; end; end; end; {** Checks is the specified string in special case. @param an identifier string. @return True is the identifier string in mixed case. } function TZDefaultIdentifierConvertor.IsSpecialCase(const Value: string): Boolean; var I: Integer; begin Result := False; if CharInSet(Value[1], ['0'..'9']) then begin Result := True; exit; end; for I := 1 to Length(Value) do begin if not CharInSet(Value[I], ['A'..'Z','a'..'z','0'..'9','_']) then begin Result := True; Break; end; end; end; {** Checks is the string case sensitive. @return True if the string case sensitive. } function TZDefaultIdentifierConvertor.IsCaseSensitive(const Value: string): Boolean; const AnsiSQLKeywords = 'insert,update,delete,select,drop,create,from,set,values,' + 'where,order,group,by,having,into,as,table,index,primary,key,on,is,null,' + 'char,varchar,integer,number,alter,column,value,' + 'current,top,login,status,version'; var Keywords: string; begin if Value = '' then Result := False else if IsSpecialCase(Value) then Result := True else if IsLowerCase(Value) then Result := Metadata.GetDatabaseInfo.StoresUpperCaseIdentifiers else if IsUpperCase(Value) then Result := Metadata.GetDatabaseInfo.StoresLowerCaseIdentifiers else Result := not Metadata.GetDatabaseInfo.StoresMixedCaseIdentifiers; { Checks for reserved keywords. } if not Result then begin Keywords := ',' + AnsiSQLKeywords + ',' + LowerCase(Metadata.GetDatabaseInfo.GetSQLKeywords) + ','; Result := Pos(',' + LowerCase(Value) + ',', Keywords) > 0; end; end; {** Checks is the string quoted. @return True is the string quoted. } function TZDefaultIdentifierConvertor.IsQuoted(const Value: string): Boolean; var QuoteDelim: string; begin QuoteDelim := Metadata.GetDatabaseInfo.GetIdentifierQuoteString; Result := (QuoteDelim <> '') and (Value <> '') and (QuoteDelim[1] = Value[1]); end; {** Extracts the quote from the idenfitier string. @param an identifier string. @return a extracted and processed string. } function TZDefaultIdentifierConvertor.ExtractQuote(const Value: string): string; begin if IsQuoted(Value) then begin Result := Copy(Value, 2, Length(Value) - 2); if not Metadata.GetDatabaseInfo.StoresMixedCaseQuotedIdentifiers then begin if Metadata.GetDatabaseInfo.StoresLowerCaseQuotedIdentifiers then Result := LowerCase(Result) else if Metadata.GetDatabaseInfo.StoresUpperCaseQuotedIdentifiers then Result := UpperCase(Result); end; end else begin Result := Value; if not Metadata.GetDatabaseInfo.StoresMixedCaseIdentifiers then begin if Metadata.GetDatabaseInfo.StoresLowerCaseIdentifiers then Result := LowerCase(Result) else if Metadata.GetDatabaseInfo.StoresUpperCaseIdentifiers then Result := UpperCase(Result); end; end; end; {** Quotes the identifier string. @param an identifier string. @return a quoted string. } function TZDefaultIdentifierConvertor.Quote(const Value: string): string; var QuoteDelim: string; begin Result := Value; if IsCaseSensitive(Value) then begin QuoteDelim := Metadata.GetDatabaseInfo.GetIdentifierQuoteString; if Length(QuoteDelim) > 1 then Result := QuoteDelim[1] + Result + QuoteDelim[2] else if Length(QuoteDelim) = 1 then Result := QuoteDelim[1] + Result + QuoteDelim[1]; end; end; {** rerurns cache key for get tables metadata entry @param Catalog catalog name @param SchemaPattern schema pattern @param TableNamePattern table name pattern @param Types table types @return the cache key string @deprecated use TZAbstractDatabaseMetadata.GetTablesCacheKey instead } function GetTablesMetaDataCacheKey(Const Catalog:String; Const SchemaPattern:String; Const TableNamePattern:String;const Types: TStringDynArray):String; Var I : Integer; Key : String; begin Key := ''; for I := Low(Types) to High(Types) do Key := Key + ':' + Types[I]; Result:= Format('get-tables:%s:%s:%s:%s', [Catalog, SchemaPattern, TableNamePattern, Key]); end; const CharacterSetsColumnsCount = 2; CharacterSetsColumns: array[1..CharacterSetsColumnsCount] of TZMetadataColumnDef =( (Name: 'CHARACTER_SET_NAME'; SQLType: stString; Length: 35), (Name: 'CHARACTER_SET_ID'; SQLType: stShort; Length: 0) ); CollationCharSetColumnsCount = 8; //EgonHugeist CollationCharSetColumns: array[1..CollationCharSetColumnsCount] of TZMetadataColumnDef =( (Name: 'COLLATION_CATALOG'; SQLType: stString; Length: 35), (Name: 'COLLATION_SCHEMA'; SQLType: stString; Length: 35), (Name: 'COLLATION_TABLE'; SQLType: stString; Length: 35), (Name: 'COLLATION_COLUMN'; SQLType: stString; Length: 35), (Name: 'COLLATION_NAME'; SQLType: stString; Length: 35), (Name: 'CHARACTER_SET_NAME'; SQLType: stString; Length: 35), (Name: 'CHARACTER_SET_ID'; SQLType: stShort; Length: 0), (Name: 'CHARACTER_SET_SIZE'; SQLType: stShort; Length: 0) ); TriggersColumnCount = 8; //EgonHugeist TriggersColumns: array[1..TriggersColumnCount] of TZMetadataColumnDef =( (Name: 'TRIGGER_CAT'; SQLType: stString; Length: 255), (Name: 'TRIGGER_SCHEM'; SQLType: stString; Length: 255), (Name: 'TRIGGER_NAME'; SQLType: stString; Length: 255), //RDB$TRIGGER_NAME (Name: 'TRIGGER_RELATION'; SQLType: stString; Length: 255), //RDB$RELATION_NAME (Name: 'TRIGGER_TYPE'; SQLType: stShort; Length: 0), //RDB$TRIGGER_TYPE (Name: 'TRIGGER_INACTIVE'; SQLType: stShort; Length: 0), //RDB$TRIGGER_INACTIVE (Name: 'TRIGGER_SOURCE'; SQLType: stString; Length: 3000), //RDB$TRIGGER_SOURCE (Name: 'TRIGGER_DESCRIPTION'; SQLType: stString; Length: 255) //RDB$DESCRIPTION ); ProceduresColumnCount = 8; ProceduresColumns: array[1..ProceduresColumnCount] of TZMetadataColumnDef =( (Name: 'PROCEDURE_CAT'; SQLType: stString; Length: 255), (Name: 'PROCEDURE_SCHEM'; SQLType: stString; Length: 255), (Name: 'PROCEDURE_NAME'; SQLType: stString; Length: 255), (Name: 'PROCEDURE_OVERLOAD'; SQLType: stString; Length: 255), (Name: 'RESERVED1'; SQLType: stString; Length: 255), (Name: 'RESERVED2'; SQLType: stString; Length: 255), (Name: 'REMARKS'; SQLType: stString; Length: 255), (Name: 'PROCEDURE_TYPE'; SQLType: stShort; Length: 0) ); ProceduresColColumnCount = 13; ProceduresColColumns: array[1..ProceduresColColumnCount] of TZMetadataColumnDef =( (Name: 'PROCEDURE_CAT'; SQLType: stString; Length: 255), (Name: 'PROCEDURE_SCHEM'; SQLType: stString; Length: 255), (Name: 'PROCEDURE_NAME'; SQLType: stString; Length: 255), (Name: 'COLUMN_NAME'; SQLType: stString; Length: 255), (Name: 'COLUMN_TYPE'; SQLType: stShort; Length: 0), (Name: 'DATA_TYPE'; SQLType: stShort; Length: 0), (Name: 'TYPE_NAME'; SQLType: stString; Length: 255), (Name: 'PRECISION'; SQLType: stInteger; Length: 0), (Name: 'LENGTH'; SQLType: stInteger; Length: 0), (Name: 'SCALE'; SQLType: stShort; Length: 0), (Name: 'RADIX'; SQLType: stShort; Length: 0), (Name: 'NULLABLE'; SQLType: stShort; Length: 0), (Name: 'REMARKS'; SQLType: stString; Length: 255) ); TableColumnCount = 5; TableColumns: array[1..TableColumnCount] of TZMetadataColumnDef =( (Name: 'TABLE_CAT'; SQLType: stString; Length: 255), (Name: 'TABLE_SCHEM'; SQLType: stString; Length: 255), (Name: 'TABLE_NAME'; SQLType: stString; Length: 255), (Name: 'TABLE_TYPE'; SQLType: stString; Length: 255), (Name: 'REMARKS'; SQLType: stString; Length: 255) ); SchemaColumnCount = 1; SchemaColumns: array[1..SchemaColumnCount] of TZMetadataColumnDef =( (Name: 'TABLE_SCHEM'; SQLType: stString; Length: 255) ); CatalogColumnCount = 1; CatalogColumns: array[1..CatalogColumnCount] of TZMetadataColumnDef =( (Name: 'TABLE_CAT'; SQLType: stString; Length: 255) ); TableTypeColumnCount = 1; TableTypeColumns: array[1..TableTypeColumnCount] of TZMetadataColumnDef =( (Name: 'TABLE_TYPE'; SQLType: stString; Length: 255) ); TableColColumnCount = 24; TableColColumns: array[1..TableColColumnCount] of TZMetadataColumnDef =( (Name: 'TABLE_CAT'; SQLType: stString; Length: 255), (Name: 'TABLE_SCHEM'; SQLType: stString; Length: 255), (Name: 'TABLE_NAME'; SQLType: stString; Length: 255), (Name: 'COLUMN_NAME'; SQLType: stString; Length: 255), (Name: 'DATA_TYPE'; SQLType: stShort; Length: 0), (Name: 'TYPE_NAME'; SQLType: stString; Length: 255), (Name: 'COLUMN_SIZE'; SQLType: stInteger; Length: 0), (Name: 'BUFFER_LENGTH'; SQLType: stInteger; Length: 0), (Name: 'DECIMAL_DIGITS'; SQLType: stInteger; Length: 0), (Name: 'NUM_PREC_RADIX'; SQLType: stInteger; Length: 0), (Name: 'NULLABLE'; SQLType: stInteger; Length: 0), (Name: 'REMARKS'; SQLType: stString; Length: 255), (Name: 'COLUMN_DEF'; SQLType: stString; Length: 255), (Name: 'SQL_DATA_TYPE'; SQLType: stInteger; Length: 0), (Name: 'SQL_DATETIME_SUB'; SQLType: stInteger; Length: 0), (Name: 'CHAR_OCTET_LENGTH'; SQLType: stInteger; Length: 0), (Name: 'ORDINAL_POSITION'; SQLType: stInteger; Length: 0), (Name: 'IS_NULLABLE'; SQLType: stString; Length: 255), (Name: 'AUTO_INCREMENT'; SQLType: stBoolean; Length: 0), (Name: 'CASE_SENSITIVE'; SQLType: stBoolean; Length: 0), (Name: 'SEARCHABLE'; SQLType: stBoolean; Length: 0), (Name: 'WRITABLE'; SQLType: stBoolean; Length: 0), (Name: 'DEFINITELYWRITABLE'; SQLType: stBoolean; Length: 0), (Name: 'READONLY'; SQLType: stBoolean; Length: 0) ); TableColPrivColumnCount = 8; TableColPrivColumns: array[1..TableColPrivColumnCount] of TZMetadataColumnDef =( (Name: 'TABLE_CAT'; SQLType: stString; Length: 255), (Name: 'TABLE_SCHEM'; SQLType: stString; Length: 255), (Name: 'TABLE_NAME'; SQLType: stString; Length: 255), (Name: 'COLUMN_NAME'; SQLType: stString; Length: 255), (Name: 'GRANTOR'; SQLType: stString; Length: 255), (Name: 'GRANTEE'; SQLType: stString; Length: 255), (Name: 'PRIVILEGE'; SQLType: stString; Length: 255), (Name: 'IS_GRANTABLE'; SQLType: stString; Length: 255) ); TablePrivColumnCount = 7; TablePrivColumns: array[1..TablePrivColumnCount] of TZMetadataColumnDef =( (Name: 'TABLE_CAT'; SQLType: stString; Length: 255), (Name: 'TABLE_SCHEM'; SQLType: stString; Length: 255), (Name: 'TABLE_NAME'; SQLType: stString; Length: 255), (Name: 'GRANTOR'; SQLType: stString; Length: 255), (Name: 'GRANTEE'; SQLType: stString; Length: 255), (Name: 'PRIVILEGE'; SQLType: stString; Length: 255), (Name: 'IS_GRANTABLE'; SQLType: stString; Length: 255) ); BestRowIdentColumnCount = 8; BestRowIdentColumns: array[1..BestRowIdentColumnCount] of TZMetadataColumnDef =( (Name: 'SCOPE'; SQLType: stShort; Length: 0), (Name: 'COLUMN_NAME'; SQLType: stString; Length: 255), (Name: 'DATA_TYPE'; SQLType: stShort; Length: 0), (Name: 'TYPE_NAME'; SQLType: stString; Length: 255), (Name: 'COLUMN_SIZE'; SQLType: stInteger; Length: 0), (Name: 'BUFFER_LENGTH'; SQLType: stInteger; Length: 0), (Name: 'DECIMAL_DIGITS'; SQLType: stShort; Length: 0), (Name: 'PSEUDO_COLUMN'; SQLType: stShort; Length: 0) ); TableColVerColumnCount = 8; TableColVerColumns: array[1..TableColVerColumnCount] of TZMetadataColumnDef =( (Name: 'SCOPE'; SQLType: stShort; Length: 0), (Name: 'COLUMN_NAME'; SQLType: stString; Length: 255), (Name: 'DATA_TYPE'; SQLType: stShort; Length: 0), (Name: 'TYPE_NAME'; SQLType: stString; Length: 255), (Name: 'COLUMN_SIZE'; SQLType: stInteger; Length: 0), (Name: 'BUFFER_LENGTH'; SQLType: stInteger; Length: 0), (Name: 'DECIMAL_DIGITS'; SQLType: stShort; Length: 0), (Name: 'PSEUDO_COLUMN'; SQLType: stShort; Length: 0) ); PrimaryKeyColumnCount = 6; PrimaryKeyColumns: array[1..PrimaryKeyColumnCount] of TZMetadataColumnDef =( (Name: 'TABLE_CAT'; SQLType: stString; Length: 255), (Name: 'TABLE_SCHEM'; SQLType: stString; Length: 255), (Name: 'TABLE_NAME'; SQLType: stString; Length: 255), (Name: 'COLUMN_NAME'; SQLType: stString; Length: 255), (Name: 'KEY_SEQ'; SQLType: stShort; Length: 0), (Name: 'PK_NAME'; SQLType: stString; Length: 255) ); ImportedKeyColumnCount = 14; ImportedKeyColumns: array[1..ImportedKeyColumnCount] of TZMetadataColumnDef =( (Name: 'PKTABLE_CAT'; SQLType: stString; Length: 255), (Name: 'PKTABLE_SCHEM'; SQLType: stString; Length: 255), (Name: 'PKTABLE_NAME'; SQLType: stString; Length: 255), (Name: 'PKCOLUMN_NAME'; SQLType: stString; Length: 255), (Name: 'FKTABLE_CAT'; SQLType: stString; Length: 255), (Name: 'FKTABLE_SCHEM'; SQLType: stString; Length: 255), (Name: 'FKTABLE_NAME'; SQLType: stString; Length: 255), (Name: 'FKCOLUMN_NAME'; SQLType: stString; Length: 255), (Name: 'KEY_SEQ'; SQLType: stShort; Length: 0), (Name: 'UPDATE_RULE'; SQLType: stShort; Length: 0), (Name: 'DELETE_RULE'; SQLType: stShort; Length: 0), (Name: 'FK_NAME'; SQLType: stString; Length: 255), (Name: 'PK_NAME'; SQLType: stString; Length: 255), (Name: 'DEFERRABILITY'; SQLType: stShort; Length: 0) ); ExportedKeyColumnCount = 14; ExportedKeyColumns: array[1..ExportedKeyColumnCount] of TZMetadataColumnDef =( (Name: 'PKTABLE_CAT'; SQLType: stString; Length: 255), (Name: 'PKTABLE_SCHEM'; SQLType: stString; Length: 255), (Name: 'PKTABLE_NAME'; SQLType: stString; Length: 255), (Name: 'PKCOLUMN_NAME'; SQLType: stString; Length: 255), (Name: 'FKTABLE_CAT'; SQLType: stString; Length: 255), (Name: 'FKTABLE_SCHEM'; SQLType: stString; Length: 255), (Name: 'FKTABLE_NAME'; SQLType: stString; Length: 255), (Name: 'FKCOLUMN_NAME'; SQLType: stString; Length: 255), (Name: 'KEY_SEQ'; SQLType: stShort; Length: 0), (Name: 'UPDATE_RULE'; SQLType: stShort; Length: 0), (Name: 'DELETE_RULE'; SQLType: stShort; Length: 0), (Name: 'FK_NAME'; SQLType: stString; Length: 255), (Name: 'PK_NAME'; SQLType: stString; Length: 255), (Name: 'DEFERRABILITY'; SQLType: stShort; Length: 0) ); CrossRefColumnCount = 14; CrossRefColumns: array[1..CrossRefColumnCount] of TZMetadataColumnDef =( (Name: 'PKTABLE_CAT'; SQLType: stString; Length: 255), (Name: 'PKTABLE_SCHEM'; SQLType: stString; Length: 255), (Name: 'PKTABLE_NAME'; SQLType: stString; Length: 255), (Name: 'PKCOLUMN_NAME'; SQLType: stString; Length: 255), (Name: 'FKTABLE_CAT'; SQLType: stString; Length: 255), (Name: 'FKTABLE_SCHEM'; SQLType: stString; Length: 255), (Name: 'FKTABLE_NAME'; SQLType: stString; Length: 255), (Name: 'FKCOLUMN_NAME'; SQLType: stString; Length: 255), (Name: 'KEY_SEQ'; SQLType: stShort; Length: 0), (Name: 'UPDATE_RULE'; SQLType: stShort; Length: 0), (Name: 'DELETE_RULE'; SQLType: stShort; Length: 0), (Name: 'FK_NAME'; SQLType: stString; Length: 255), (Name: 'PK_NAME'; SQLType: stString; Length: 255), (Name: 'DEFERRABILITY'; SQLType: stShort; Length: 0) ); TypeInfoColumnCount = 18; TypeInfoColumns: array[1..TypeInfoColumnCount] of TZMetadataColumnDef =( (Name: 'TYPE_NAME'; SQLType: stString; Length: 255), (Name: 'DATA_TYPE'; SQLType: stShort; Length: 0), (Name: 'PRECISION'; SQLType: stInteger; Length: 0), (Name: 'LITERAL_PREFIX'; SQLType: stString; Length: 255), (Name: 'LITERAL_SUFFIX'; SQLType: stString; Length: 255), (Name: 'CREATE_PARAMS'; SQLType: stString; Length: 255), (Name: 'NULLABLE'; SQLType: stShort; Length: 0), (Name: 'CASE_SENSITIVE'; SQLType: stBoolean; Length: 0), (Name: 'SEARCHABLE'; SQLType: stShort; Length: 0), (Name: 'UNSIGNED_ATTRIBUTE'; SQLType: stBoolean; Length: 0), (Name: 'FIXED_PREC_SCALE'; SQLType: stBoolean; Length: 0), (Name: 'AUTO_INCREMENT'; SQLType: stBoolean; Length: 0), (Name: 'LOCAL_TYPE_NAME'; SQLType: stString; Length: 255), (Name: 'MINIMUM_SCALE'; SQLType: stShort; Length: 0), (Name: 'MAXIMUM_SCALE'; SQLType: stShort; Length: 0), (Name: 'SQL_DATA_TYPE'; SQLType: stInteger; Length: 0), (Name: 'SQL_DATETIME_SUB'; SQLType: stInteger; Length: 0), (Name: 'NUM_PREC_RADIX'; SQLType: stInteger; Length: 0) ); IndexInfoColumnCount = 13; IndexInfoColumns: array[1..IndexInfoColumnCount] of TZMetadataColumnDef =( (Name: 'TABLE_CAT'; SQLType: stString; Length: 255), (Name: 'TABLE_SCHEM'; SQLType: stString; Length: 255), (Name: 'TABLE_NAME'; SQLType: stString; Length: 255), (Name: 'NON_UNIQUE'; SQLType: stBoolean; Length: 0), (Name: 'INDEX_QUALIFIER'; SQLType: stString; Length: 255), (Name: 'INDEX_NAME'; SQLType: stString; Length: 255), (Name: 'TYPE'; SQLType: stShort; Length: 0), (Name: 'ORDINAL_POSITION'; SQLType: stShort; Length: 0), (Name: 'COLUMN_NAME'; SQLType: stString; Length: 255), (Name: 'ASC_OR_DESC'; SQLType: stString; Length: 255), (Name: 'CARDINALITY'; SQLType: stInteger; Length: 0), (Name: 'PAGES'; SQLType: stInteger; Length: 0), (Name: 'FILTER_CONDITION'; SQLType: stString; Length: 255) ); SequenceColumnCount = 3; SequenceColumns: array[1..SequenceColumnCount] of TZMetadataColumnDef = ( (Name: 'SEQUENCE_CAT'; SQLType: stString; Length: 255), (Name: 'SEQUENCE_SCHEM'; SQLType: stString; Length: 255), (Name: 'SEQUENCE_NAME'; SQLType: stString; Length: 255) ); UDTColumnCount = 6; UDTColumns: array[1..UDTColumnCount] of TZMetadataColumnDef =( (Name: 'TYPE_CAT'; SQLType: stString; Length: 255), (Name: 'TYPE_SCHEM'; SQLType: stString; Length: 255), (Name: 'TYPE_NAME'; SQLType: stString; Length: 255), (Name: 'CLASS_NAME'; SQLType: stString; Length: 255), (Name: 'DATA_TYPE'; SQLType: stShort; Length: 0), (Name: 'REMARKS'; SQLType: stString; Length: 255) ); var I: Integer; initialization SetLength(CharacterSetsColumnsDynArray, CharacterSetsColumnsCount); for I := 1 to CharacterSetsColumnsCount do CharacterSetsColumnsDynArray[I - 1] := CharacterSetsColumns[I]; SetLength(CollationCharSetColumnsDynArray, CollationCharSetColumnsCount); for I := 1 to CollationCharSetColumnsCount do CollationCharSetColumnsDynArray[I - 1] := CollationCharSetColumns[I]; SetLength(TriggersColumnsDynArray, TriggersColumnCount); for I := 1 to TriggersColumnCount do TriggersColumnsDynArray[I - 1] := TriggersColumns[I]; SetLength(ProceduresColumnsDynArray, ProceduresColumnCount); for I := 1 to ProceduresColumnCount do ProceduresColumnsDynArray[I - 1] := ProceduresColumns[I]; SetLength(ProceduresColColumnsDynArray, ProceduresColColumnCount); for I := 1 to ProceduresColColumnCount do ProceduresColColumnsDynArray[I - 1] := ProceduresColColumns[I]; SetLength(TableColumnsDynArray, TableColumnCount); for I := 1 to TableColumnCount do TableColumnsDynArray[I - 1] := TableColumns[I]; SetLength(SchemaColumnsDynArray, SchemaColumnCount); for I := 1 to SchemaColumnCount do SchemaColumnsDynArray[I - 1] := SchemaColumns[I]; SetLength(CatalogColumnsDynArray, CatalogColumnCount); for I := 1 to CatalogColumnCount do CatalogColumnsDynArray[I - 1] := CatalogColumns[I]; SetLength(TableTypeColumnsDynArray, TableTypeColumnCount); for I := 1 to TableTypeColumnCount do TableTypeColumnsDynArray[I - 1] := TableTypeColumns[I]; SetLength(TableColColumnsDynArray, TableColColumnCount); for I := 1 to TableColColumnCount do TableColColumnsDynArray[I - 1] := TableColColumns[I]; SetLength(TableColPrivColumnsDynArray, TableColPrivColumnCount); for I := 1 to TableColPrivColumnCount do TableColPrivColumnsDynArray[I - 1] := TableColPrivColumns[I]; SetLength(TablePrivColumnsDynArray, TablePrivColumnCount); for I := 1 to TablePrivColumnCount do TablePrivColumnsDynArray[I - 1] := TablePrivColumns[I]; SetLength(BestRowIdentColumnsDynArray, BestRowIdentColumnCount); for I := 1 to BestRowIdentColumnCount do BestRowIdentColumnsDynArray[I - 1] := BestRowIdentColumns[I]; SetLength(TableColVerColumnsDynArray, TableColVerColumnCount); for I := 1 to TableColVerColumnCount do TableColVerColumnsDynArray[I - 1] := TableColVerColumns[I]; SetLength(PrimaryKeyColumnsDynArray, PrimaryKeyColumnCount); for I := 1 to PrimaryKeyColumnCount do PrimaryKeyColumnsDynArray[I - 1] := PrimaryKeyColumns[I]; SetLength(ImportedKeyColumnsDynArray, ImportedKeyColumnCount); for I := 1 to ImportedKeyColumnCount do ImportedKeyColumnsDynArray[I - 1] := ImportedKeyColumns[I]; SetLength(ExportedKeyColumnsDynArray, ExportedKeyColumnCount); for I := 1 to ExportedKeyColumnCount do ExportedKeyColumnsDynArray[I - 1] := ExportedKeyColumns[I]; SetLength(CrossRefColumnsDynArray, CrossRefColumnCount); for I := 1 to CrossRefColumnCount do CrossRefColumnsDynArray[I - 1] := CrossRefColumns[I]; SetLength(TypeInfoColumnsDynArray, TypeInfoColumnCount); for I := 1 to TypeInfoColumnCount do TypeInfoColumnsDynArray[I - 1] := TypeInfoColumns[I]; SetLength(IndexInfoColumnsDynArray, IndexInfoColumnCount); for I := 1 to IndexInfoColumnCount do IndexInfoColumnsDynArray[I - 1] := IndexInfoColumns[I]; SetLength(SequenceColumnsDynArray, SequenceColumnCount); for I := 1 to SequenceColumnCount do SequenceColumnsDynArray[I - 1] := SequenceColumns[I]; SetLength(UDTColumnsDynArray, UDTColumnCount); for I := 1 to UDTColumnCount do UDTColumnsDynArray[I - 1] := UDTColumns[I]; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcMySql.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { MySQL Database Connectivity Classes } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcMySql; interface {$I ZDbc.inc} uses Types, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, ZCompatibility, ZDbcIntfs, ZDbcConnection, ZPlainMySqlDriver, ZPlainDriver, ZURL, ZDbcLogging, ZTokenizer, ZGenericSqlAnalyser, ZPlainMySqlConstants; type {** Implements MySQL Database Driver. } { TZMySQLDriver } {$WARNINGS OFF} TZMySQLDriver = class(TZAbstractDriver) protected function GetPlainDriver(const Url: TZURL; const InitDriver: Boolean = True): IZPlainDriver; override; public constructor Create; override; function Connect(const Url: TZURL): IZConnection; override; function GetMajorVersion: Integer; override; function GetMinorVersion: Integer; override; function GetTokenizer: IZTokenizer; override; function GetStatementAnalyser: IZStatementAnalyser; override; function GetClientVersion(const Url: string): Integer; override; end; {$WARNINGS ON} {** Represents a MYSQL specific connection interface. } IZMySQLConnection = interface (IZConnection) ['{68E33DD3-4CDC-4BFC-8A28-E9F2EE94E457}'] function GetPlainDriver: IZMySQLPlainDriver; function GetConnectionHandle: PZMySQLConnect; end; {** Implements MySQL Database Connection. } TZMySQLConnection = class(TZAbstractConnection, IZMySQLConnection) private FCatalog: string; FHandle: PZMySQLConnect; protected procedure InternalCreate; override; public destructor Destroy; override; function CreateRegularStatement(Info: TStrings): IZStatement; override; function CreatePreparedStatement(const SQL: string; Info: TStrings): IZPreparedStatement; override; function CreateCallableStatement(const SQL: string; Info: TStrings): IZCallableStatement; override; procedure Commit; override; procedure Rollback; override; function PingServer: Integer; override; function EscapeString(Value: RawByteString): RawByteString; override; procedure Open; override; procedure Close; override; procedure SetCatalog(const Catalog: string); override; function GetCatalog: string; override; procedure SetTransactionIsolation(Level: TZTransactIsolationLevel); override; procedure SetAutoCommit(AutoCommit: Boolean); override; {ADDED by fduenas 15-06-2006} function GetClientVersion: Integer; override; function GetHostVersion: Integer; override; {END ADDED by fduenas 15-06-2006} function GetPlainDriver: IZMySQLPlainDriver; function GetConnectionHandle: PZMySQLConnect; function GetEscapeString(const Value: ZWideString): ZWideString; override; function GetEscapeString(const Value: RawByteString): RawByteString; override; end; var {** The common driver manager object. } MySQLDriver: IZDriver; implementation uses ZMessages, ZSysUtils, ZDbcUtils, ZDbcMySqlStatement, ZMySqlToken, ZDbcMySqlUtils, ZDbcMySqlMetadata, ZMySqlAnalyser, TypInfo, Math, ZEncoding; { TZMySQLDriver } {** Constructs this object with default properties. } constructor TZMySQLDriver.Create; begin inherited Create; AddSupportedProtocol(AddPlainDriverToCache(TZMySQL5PlainDriver.Create(GetTokenizer), 'mysql')); AddSupportedProtocol(AddPlainDriverToCache(TZMySQL41PlainDriver.Create(GetTokenizer))); AddSupportedProtocol(AddPlainDriverToCache(TZMySQL5PlainDriver.Create(GetTokenizer))); AddSupportedProtocol(AddPlainDriverToCache(TZMySQLD41PlainDriver.Create(GetTokenizer))); AddSupportedProtocol(AddPlainDriverToCache(TZMySQLD5PlainDriver.Create(GetTokenizer))); AddSupportedProtocol(AddPlainDriverToCache(TZMariaDB5PlainDriver.Create(GetTokenizer))); end; {** Attempts to make a database connection to the given URL. The driver should return "null" if it realizes it is the wrong kind of driver to connect to the given URL. This will be common, as when the JDBC driver manager is asked to connect to a given URL it passes the URL to each loaded driver in turn.

The driver should raise a SQLException if it is the right driver to connect to the given URL, but has trouble connecting to the database.

The java.util.Properties argument can be used to passed arbitrary string tag/value pairs as connection arguments. Normally at least "user" and "password" properties should be included in the Properties. @param url the URL of the database to which to connect @param info a list of arbitrary string tag/value pairs as connection arguments. Normally at least a "user" and "password" property should be included. @return a Connection object that represents a connection to the URL } {$WARNINGS OFF} function TZMySQLDriver.Connect(const Url: TZURL): IZConnection; begin Result := TZMySQLConnection.Create(Url); end; {$WARNINGS ON} {** Gets the driver's major version number. Initially this should be 1. @return this driver's major version number } function TZMySQLDriver.GetMajorVersion: Integer; begin Result := 1; end; {** Gets the driver's minor version number. Initially this should be 0. @return this driver's minor version number } function TZMySQLDriver.GetMinorVersion: Integer; begin Result := 1; end; {** Gets a SQL syntax tokenizer. @returns a SQL syntax tokenizer object. } function TZMySQLDriver.GetTokenizer: IZTokenizer; begin if Tokenizer = nil then Tokenizer := TZMySQLTokenizer.Create; Result := Tokenizer; end; {** Creates a statement analyser object. @returns a statement analyser object. } function TZMySQLDriver.GetStatementAnalyser: IZStatementAnalyser; begin if Analyser = nil then Analyser := TZMySQLStatementAnalyser.Create; Result := Analyser; end; {** Gets plain driver for selected protocol. @param Url a database connection URL. @return a selected plaindriver. } function TZMySQLDriver.GetPlainDriver(const Url: TZURL; const InitDriver: Boolean = True): IZPlainDriver; begin // added by tohenk, 2009-10-11 // before PlainDriver is initialized, we can perform pre-library loading // requirement check here, e.g. Embedded server argument params Result := inherited GetPlainDriver(URL, False); if Assigned(Result) then begin if Url.Properties.Count >0 then (Result as IZMySQLPlainDriver).SetDriverOptions(Url.Properties); // end added by tohenk, 2009-10-11 if InitDriver then Result.Initialize(Url.LibLocation); end else raise Exception.Create('Can''t receive Plaindriver!'); end; {** Returns the version of the plain driver library that will be used to open a connection to the given URL. @param url the URL of the database @return the version number of the plain driver library for the give URL } function TZMySQLDriver.GetClientVersion(const Url: string): Integer; var TempURL: TZURL; begin TempURL := TZURL.Create(Url); Result := ConvertMySQLVersionToSQLVersion((GetPlainDriver(TempUrl) as IZMySQLPlainDriver).GetClientVersion); TempUrl.Free end; { TZMySQLConnection } {** Constructs this object and assignes the main properties. } procedure TZMySQLConnection.InternalCreate; begin FMetaData := TZMySQLDatabaseMetadata.Create(Self, Url); if Self.Port = 0 then Self.Port := MYSQL_PORT; AutoCommit := True; TransactIsolationLevel := tiNone; FHandle := nil; { Processes connection properties. } Open; end; {** Destroys this object and cleanups the memory. } destructor TZMySQLConnection.Destroy; begin inherited Destroy; end; {** Opens a connection to database server with specified parameters. } procedure TZMySQLConnection.Open; var LogMessage: string; OldLevel: TZTransactIsolationLevel; OldAutoCommit: Boolean; UIntOpt: UInt; MyBoolOpt: Byte; ClientFlag : Cardinal; SslCa, SslCaPath, SslKey, SslCert, SslCypher: PAnsiChar; myopt: TMySQLOption; sMyOpt: string; my_client_Opt:TMYSQL_CLIENT_OPTIONS; sMy_client_Opt, sMy_client_Char_Set:String; ClientVersion: Integer; SQL: PAnsiChar; label setuint; begin if not Closed then Exit; LogMessage := Format('CONNECT TO "%s" AS USER "%s"', [Database, User]); FHandle := GetPlainDriver.Init(FHandle); {EgonHugeist: Arrange Client-CodePage/CharacterSet first Now we know if UTFEncoding is neccessary or not} sMy_client_Char_Set := String(GetPlainDriver.GetConnectionCharacterSet(FHandle)); ConSettings^.ClientCodePage := GetPlainDriver.ValidateCharEncoding(sMy_client_Char_Set); ZEncoding.SetConvertFunctions(ConSettings); {EgonHugeist: Now we know in which kind of CharacterSet we have to send the next Connection-Properties before we can change to the CharacterSet we want to have here.. This sets also all environment-variables to the Codepaged Object. Now the compatibility-functions ZString/ZPlainString working like Database-expected Data has to be!!. } try { Sets a default port number. } if Port = 0 then Port := MYSQL_PORT; { Turn on compression protocol. } if StrToBoolEx(Info.Values['compress']) and (Info.Values['MYSQL_OPT_COMPRESS'] = '') and (Info.IndexOf('MYSQL_OPT_COMPRESS') = -1) then Info.Values['MYSQL_OPT_COMPRESS'] := Info.Values['compress']; //check if user allready did set the value! { Sets connection timeout. } if (StrToIntDef(Info.Values['timeout'], 0) >= 0) and (Info.Values['MYSQL_OPT_CONNECT_TIMEOUT'] = '') then //check if user allready did set the value! Info.Values['MYSQL_OPT_CONNECT_TIMEOUT'] := Info.Values['timeout']; (*Added lines to handle option parameters 21 november 2007 marco cotroneo*) ClientVersion := GetPlainDriver.GetClientVersion; for myopt := low(TMySQLOption) to high(TMySQLOption) do begin sMyOpt:= GetEnumName(typeInfo(TMySQLOption), integer(myOpt)); if ClientVersion >= TMySqlOptionMinimumVersion[myopt] then //version checked (: case myopt of {unsigned int options ...} MYSQL_OPT_CONNECT_TIMEOUT, MYSQL_OPT_PROTOCOL, MYSQL_OPT_READ_TIMEOUT, MYSQL_OPT_WRITE_TIMEOUT: if Info.Values[sMyOpt] <> '' then begin setuint: UIntOpt := StrToIntDef(Info.Values[sMyOpt], 0); GetPlainDriver.SetOptions(FHandle, myopt, @UIntOpt); end; MYSQL_OPT_LOCAL_INFILE: {optional empty or unsigned int} if Info.Values[sMyOpt] <> '' then goto setuint else if Info.IndexOf(sMyOpt) > -1 then GetPlainDriver.SetOptions(FHandle, myopt, nil); { no value options } MYSQL_OPT_COMPRESS, MYSQL_OPT_GUESS_CONNECTION, MYSQL_OPT_NAMED_PIPE, MYSQL_OPT_USE_REMOTE_CONNECTION, MYSQL_OPT_USE_EMBEDDED_CONNECTION, MYSQL_OPT_USE_RESULT, MYSQL_OPT_CONNECT_ATTR_RESET: if (Info.Values[sMyOpt] <> '') or (Info.IndexOf(sMyOpt) > -1) then GetPlainDriver.SetOptions(FHandle, myopt, nil); { my_bool * options} MYSQL_REPORT_DATA_TRUNCATION, MYSQL_SECURE_AUTH, MYSQL_OPT_RECONNECT, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, MYSQL_ENABLE_CLEARTEXT_PLUGIN, MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS, MYSQL_OPT_SSL_ENFORCE: if Info.Values[sMyOpt] <> '' then begin MyBoolOpt := Ord(StrToBoolEx(Info.Values[sMyOpt])); GetPlainDriver.SetOptions(FHandle, myopt, @MyBoolOpt); end; { unsigned char * options } MYSQL_OPT_SSL_KEY, MYSQL_OPT_SSL_CERT, MYSQL_OPT_SSL_CA, MYSQL_OPT_SSL_CAPATH, MYSQL_OPT_SSL_CIPHER: ;//skip, processed down below else if Info.Values[sMyOpt] <> '' then GetPlainDriver.SetOptions(FHandle, myopt, PAnsiChar( ConSettings^.ConvFuncs.ZStringToRaw(Info.Values[sMyOpt], ConSettings^.CTRL_CP, ConSettings^.ClientCodePage^.CP))); end; end; { Set ClientFlag } ClientFlag := 0; if Not StrToBoolEx(Info.Values['dbless']) then ClientFlag := trunc(power(2, GetEnumValue( TypeInfo(TMYSQL_CLIENT_OPTIONS),'_CLIENT_CONNECT_WITH_DB'))); for my_client_Opt := low(TMYSQL_CLIENT_OPTIONS) to high(TMYSQL_CLIENT_OPTIONS) do begin sMy_client_Opt:= GetEnumName(typeInfo(TMYSQL_CLIENT_OPTIONS), integer(my_client_Opt)); if StrToBoolEx(Info.Values[sMy_client_Opt]) then ClientFlag:= ClientFlag or trunc(power(2, GetEnumValue(TypeInfo(TMYSQL_CLIENT_OPTIONS),sMy_client_Opt))); end; { Set SSL properties before connect} SslKey := nil; SslCert := nil; SslCa := nil; SslCaPath := nil; SslCypher := nil; {EgonHugeist: If these Paramters MUST BE UTF8 then leave Param ceUTF8 in the ZPlainString-function like else remove it and it adapts to default codepage} if StrToBoolEx(Info.Values['MYSQL_SSL']) then begin if Info.Values['MYSQL_SSL_KEY'] <> '' then SslKey := PAnsiChar(ZPlainString(Info.Values['MYSQL_SSL_KEY'], ceUTF8)); if Info.Values['MYSQL_SSL_CERT'] <> '' then SslCert := PAnsiChar(ZPlainString(Info.Values['MYSQL_SSL_CERT'], ceUTF8)); if Info.Values['MYSQL_SSL_CA'] <> '' then SslCa := PAnsiChar(ZPlainString(Info.Values['MYSQL_SSL_CA'], ceUTF8)); if Info.Values['MYSQL_SSL_CAPATH'] <> '' then SslCaPath := PAnsiChar(ZPlainString(Info.Values['MYSQL_SSL_CAPATH'], ceUTF8)); if Info.Values['MYSQL_SSL_CYPHER'] <> '' then SslCypher := PAnsiChar(ZPlainString(Info.Values['MYSQL_SSL_CYPHER'], ceUTF8)); GetPlainDriver.SslSet(FHandle, SslKey, SslCert, SslCa, SslCaPath, SslCypher); DriverManager.LogMessage(lcConnect, PlainDriver.GetProtocol, 'SSL options set'); end; { Connect to MySQL database. } if GetPlainDriver.RealConnect(FHandle, PAnsiChar(ZPlainString(HostName)), PAnsiChar(ZPlainString(User)), PAnsiChar(ZPlainString(Password)), PAnsiChar(ZPlainString(Database)), Port, nil, ClientFlag) = nil then begin CheckMySQLError(GetPlainDriver, FHandle, lcConnect, LogMessage); DriverManager.LogError(lcConnect, PlainDriver.GetProtocol, LogMessage, 0, SUnknownError); raise EZSQLException.Create(SCanNotConnectToServer); end; DriverManager.LogMessage(lcConnect, PlainDriver.GetProtocol, LogMessage); { Fix Bugs in certain Versions where real_conncet resets the Reconnect flag } if (Info.Values['MYSQL_OPT_RECONNECT'] <> '') and ((ClientVersion>=50013) and (ClientVersion<50019)) or ((ClientVersion>=50100) and (ClientVersion<50106)) then begin MyBoolOpt := Ord(StrToBoolEx(Info.Values['MYSQL_OPT_RECONNECT'])); GetPlainDriver.SetOptions(FHandle, MYSQL_OPT_RECONNECT, @MyBoolOpt); end; if (FClientCodePage = '') and (sMy_client_Char_Set <> '') then FClientCodePage := sMy_client_Char_Set; if (FClientCodePage <> sMy_client_Char_Set) then begin SQL := PAnsiChar(ZPlainString(Format('SET NAMES %s', [FClientCodePage]))); GetPlainDriver.ExecQuery(FHandle, SQL); CheckMySQLError(GetPlainDriver, FHandle, lcExecute, String(SQL)); DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, String(SQL)); end; Self.CheckCharEncoding(FClientCodePage); { Sets transaction isolation level. } OldLevel := TransactIsolationLevel; TransactIsolationLevel := tiNone; SetTransactionIsolation(OldLevel); { Sets an auto commit mode. } OldAutoCommit := AutoCommit; AutoCommit := True; SetAutoCommit(OldAutoCommit); except GetPlainDriver.Close(FHandle); GetPlainDriver.Despose(FHandle); FHandle := nil; raise; end; inherited Open; if FClientCodePage = '' then //workaround for MySQL 4 down begin with CreateStatement.ExecuteQuery('show variables like "character_set_database"') do begin if Next then FClientCodePage := GetString(2); Close; end; ConSettings^.ClientCodePage := GetPlainDriver.ValidateCharEncoding(FClientCodePage); ZEncoding.SetConvertFunctions(ConSettings); end end; {** Ping Current Connection's server, if client was disconnected, the connection is resumed. @return 0 if succesfull or error code if any error occurs } function TZMySQLConnection.PingServer: Integer; const PING_ERROR_ZEOSCONNCLOSED = -1; var Closing: boolean; begin Closing := FHandle = nil; if Closed or Closing then Result := PING_ERROR_ZEOSCONNCLOSED else Result := GetPlainDriver.Ping(FHandle); end; {** Escape a string so it's acceptable for the Connection's server. @param value string that should be escaped @return Escaped string } function TZMySQLConnection.EscapeString(Value: RawByteString): RawByteString; begin Result := PlainDriver.EscapeString(Self.FHandle, Value, ConSettings); end; {** Creates a Statement object for sending SQL statements to the database. SQL statements without parameters are normally executed using Statement objects. If the same SQL statement is executed many times, it is more efficient to use a PreparedStatement object.

Result sets created using the returned Statement object will by default have forward-only type and read-only concurrency. @param Info a statement parameters. @return a new Statement object } function TZMySQLConnection.CreateRegularStatement(Info: TStrings): IZStatement; begin if IsClosed then Open; Result := TZMySQLStatement.Create(GetPlainDriver, Self, Info, FHandle); end; {** Creates a PreparedStatement object for sending parameterized SQL statements to the database. A SQL statement with or without IN parameters can be pre-compiled and stored in a PreparedStatement object. This object can then be used to efficiently execute this statement multiple times.

Note: This method is optimized for handling parametric SQL statements that benefit from precompilation. If the driver supports precompilation, the method prepareStatement will send the statement to the database for precompilation. Some drivers may not support precompilation. In this case, the statement may not be sent to the database until the PreparedStatement is executed. This has no direct effect on users; however, it does affect which method throws certain SQLExceptions. Result sets created using the returned PreparedStatement will have forward-only type and read-only concurrency, by default. @param sql a SQL statement that may contain one or more '?' IN parameter placeholders @param Info a statement parameters. @return a new PreparedStatement object containing the pre-compiled statement } function TZMySQLConnection.CreatePreparedStatement(const SQL: string; Info: TStrings): IZPreparedStatement; begin if IsClosed then Open; if Assigned(Info) then if StrToBoolEx(Info.Values['preferprepared']) then Result := TZMySQLPreparedStatement.Create(GetPlainDriver, Self, SQL, Info) else Result := TZMySQLEmulatedPreparedStatement.Create(GetPlainDriver, Self, SQL, Info, FHandle) else Result := TZMySQLEmulatedPreparedStatement.Create(GetPlainDriver, Self, SQL, Info, FHandle); end; {** Creates a CallableStatement object for calling database stored procedures. The CallableStatement object provides methods for setting up its IN and OUT parameters, and methods for executing the call to a stored procedure.

Note: This method is optimized for handling stored procedure call statements. Some drivers may send the call statement to the database when the method prepareCall is done; others may wait until the CallableStatement object is executed. This has no direct effect on users; however, it does affect which method throws certain SQLExceptions. Result sets created using the returned CallableStatement will have forward-only type and read-only concurrency, by default. @param sql a SQL statement that may contain one or more '?' parameter placeholders. Typically this statement is a JDBC function call escape string. @param Info a statement parameters. @return a new CallableStatement object containing the pre-compiled SQL statement } function TZMySQLConnection.CreateCallableStatement(const SQL: string; Info: TStrings): IZCallableStatement; begin Result := TZMySQLCallableStatement.Create(GetPlainDriver, Self, SQL, Info, FHandle); end; {** Makes all changes made since the previous commit/rollback permanent and releases any database locks currently held by the Connection. This method should be used only when auto-commit mode has been disabled. @see #setAutoCommit } procedure TZMySQLConnection.Commit; begin if (TransactIsolationLevel <> tiNone) and (AutoCommit <> True) and not Closed then begin If not GEtPlaindriver.Commit(FHandle) then CheckMySQLError(GetPlainDriver, FHandle, lcExecute, 'Native Commit call'); DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, 'Native Commit call'); end; end; {** Drops all changes made since the previous commit/rollback and releases any database locks currently held by this Connection. This method should be used only when auto- commit has been disabled. @see #setAutoCommit } procedure TZMySQLConnection.Rollback; begin if (TransactIsolationLevel <> tiNone) and (AutoCommit <> True) and not Closed then begin If not GetPlaindriver.Rollback(FHandle) then CheckMySQLError(GetPlainDriver, FHandle, lcExecute, 'Native Rollback call'); DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, 'Native Rollback call'); end; end; {** Releases a Connection's database and JDBC resources immediately instead of waiting for them to be automatically released.

Note: A Connection is automatically closed when it is garbage collected. Certain fatal errors also result in a closed Connection. } procedure TZMySQLConnection.Close; var LogMessage: string; begin if ( Closed ) or (not Assigned(PlainDriver)) then Exit; GetPlainDriver.Close(FHandle); GetPlainDriver.Despose(FHandle); FHandle := nil; LogMessage := Format('DISCONNECT FROM "%s"', [Database]); DriverManager.LogMessage(lcDisconnect, GetPlainDriver.GetProtocol, LogMessage); inherited Close; end; {** Gets a selected catalog name. @return a selected catalog name. } function TZMySQLConnection.GetCatalog: string; begin Result := FCatalog; end; {** Sets a new selected catalog name. @param Catalog a selected catalog name. } procedure TZMySQLConnection.SetCatalog(const Catalog: string); begin FCatalog := Catalog; end; {** Sets a new transact isolation level. @param Level a new transact isolation level. } procedure TZMySQLConnection.SetTransactionIsolation( Level: TZTransactIsolationLevel); var SQL: PAnsiChar; testResult: Integer; begin if TransactIsolationLevel <> Level then begin inherited SetTransactionIsolation(Level); testResult := 1; if not Closed then begin case TransactIsolationLevel of tiNone, tiReadUncommitted: begin SQL := 'SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED'; testResult := GetPlainDriver.ExecQuery(FHandle, SQL); end; tiReadCommitted: begin SQL := 'SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED'; testResult := GetPlainDriver.ExecQuery(FHandle, SQL); end; tiRepeatableRead: begin SQL := 'SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ'; testResult := GetPlainDriver.ExecQuery(FHandle, SQL); end; tiSerializable: begin SQL := 'SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE'; testResult := GetPlainDriver.ExecQuery(FHandle, SQL); end; else SQL := ''; end; if (testResult <> 0) then CheckMySQLError(GetPlainDriver, FHandle, lcExecute, String(SQL)); if SQL <> '' then DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, String(SQL)); end; end; end; {** Sets this connection's auto-commit mode. If a connection is in auto-commit mode, then all its SQL statements will be executed and committed as individual transactions. Otherwise, its SQL statements are grouped into transactions that are terminated by a call to either the method commit or the method rollback. By default, new connections are in auto-commit mode. The commit occurs when the statement completes or the next execute occurs, whichever comes first. In the case of statements returning a ResultSet, the statement completes when the last row of the ResultSet has been retrieved or the ResultSet has been closed. In advanced cases, a single statement may return multiple results as well as output parameter values. In these cases the commit occurs when all results and output parameter values have been retrieved. @param autoCommit true enables auto-commit; false disables auto-commit. } procedure TZMySQLConnection.SetAutoCommit(AutoCommit: Boolean); begin if AutoCommit <> Self.AutoCommit then begin inherited SetAutoCommit(AutoCommit); if not Closed then begin if not GetPlaindriver.SetAutocommit(FHandle, AutoCommit) then CheckMySQLError(GetPlainDriver, FHandle, lcExecute, 'Native SetAutoCommit '+BoolToStrEx(AutoCommit)+'call'); DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, 'Native SetAutoCommit '+BoolToStrEx(AutoCommit)+'call'); end; end; end; {** Gets client's full version number. The format of the version returned must be XYYYZZZ where X = Major version YYY = Minor version ZZZ = Sub version @return this clients's full version number } function TZMySQLConnection.GetClientVersion: Integer; begin Result := ConvertMySQLVersionToSQLVersion( GetPlainDriver.GetClientVersion ); end; {** Gets server's full version number. The format of the returned version must be XYYYZZZ where X = Major version YYY = Minor version ZZZ = Sub version @return this clients's full version number } function TZMySQLConnection.GetHostVersion: Integer; begin Result := ConvertMySQLVersionToSQLVersion( GetPlainDriver.GetServerVersion(FHandle) ); CheckMySQLError(GetPlainDriver, FHandle, lcExecute, 'mysql_get_server_version()'); end; {** Gets a reference to MySQL connection handle. @return a reference to MySQL connection handle. } function TZMySQLConnection.GetConnectionHandle: PZMySQLConnect; begin Result := FHandle; end; {** Gets a MySQL plain driver interface. @return a MySQL plain driver interface. } function TZMySQLConnection.GetPlainDriver: IZMySQLPlainDriver; begin Result := Self.PlainDriver as IZMySQLPlainDriver; end; {** EgonHugeist: Returns the BinaryString in a Tokenizer-detectable kind If the Tokenizer don't need to predetect it Result := BinaryString @param Value represents the Binary-String @param EscapeMarkSequence represents a Tokenizer detectable EscapeSequence (Len >= 3) @result the detectable Binary String } function TZMySQLConnection.GetEscapeString(const Value: ZWideString): ZWideString; begin Result := inherited GetEscapeString(GetPlainDriver.EscapeString(FHandle, Value, ConSettings)); end; function TZMySQLConnection.GetEscapeString(const Value: RawByteString): RawByteString; begin Result := inherited GetEscapeString(GetPlainDriver.EscapeString(FHandle, Value, ConSettings)); end; initialization MySQLDriver := TZMySQLDriver.Create; DriverManager.RegisterDriver(MySQLDriver); finalization if DriverManager <> nil then DriverManager.DeregisterDriver(MySQLDriver); MySQLDriver := nil; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcMySqlMetadata.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { MySQL Database Connectivity Classes } { } { Originally written by Sergey Seroukhov } { and Sergey Merkuriev } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcMySqlMetadata; interface {$I ZDbc.inc} uses Types, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, ZClasses, ZSysUtils, ZDbcIntfs, ZDbcMetadata, ZDbcResultSet, ZDbcConnection, ZDbcCachedResultSet, ZDbcResultSetMetadata, ZURL, ZCompatibility; type // technobot 2008-06-26 - methods moved as is from TZMySQLDatabaseMetadata: {** Implements MySQL Database Information. } TZMySQLDatabaseInfo = class(TZAbstractDatabaseInfo) protected procedure GetVersion(var MajorVersion, MinorVersion: integer); public constructor Create(const Metadata: TZAbstractDatabaseMetadata); // database/driver/server info: function GetDatabaseProductName: string; override; function GetDatabaseProductVersion: string; override; function GetDriverName: string; override; // function GetDriverVersion: string; override; -> Same as parent function GetDriverMajorVersion: Integer; override; function GetDriverMinorVersion: Integer; override; // function GetServerVersion: string; -> Not implemented // capabilities (what it can/cannot do): // function AllProceduresAreCallable: Boolean; override; -> Not implemented // function AllTablesAreSelectable: Boolean; override; -> Not implemented // function SupportsMixedCaseIdentifiers: Boolean; override; -> Not implemented // function SupportsMixedCaseQuotedIdentifiers: Boolean; override; -> Not implemented // function SupportsAlterTableWithAddColumn: Boolean; override; -> Not implemented // function SupportsAlterTableWithDropColumn: Boolean; override; -> Not implemented // function SupportsColumnAliasing: Boolean; override; -> Not implemented // function SupportsConvert: Boolean; override; -> Not implemented // function SupportsConvertForTypes(FromType: TZSQLType; ToType: TZSQLType): // Boolean; override; -> Not implemented // function SupportsTableCorrelationNames: Boolean; override; -> Not implemented // function SupportsDifferentTableCorrelationNames: Boolean; override; -> Not implemented // function SupportsExpressionsInOrderBy: Boolean; override; -> Not implemented function SupportsOrderByUnrelated: Boolean; override; // function SupportsGroupBy: Boolean; override; -> Not implemented function SupportsGroupByUnrelated: Boolean; override; function SupportsGroupByBeyondSelect: Boolean; override; // function SupportsLikeEscapeClause: Boolean; override; -> Not implemented // function SupportsMultipleResultSets: Boolean; override; -> Not implemented // function SupportsMultipleTransactions: Boolean; override; -> Not implemented // function SupportsNonNullableColumns: Boolean; override; -> Not implemented // function SupportsMinimumSQLGrammar: Boolean; override; -> Not implemented // function SupportsCoreSQLGrammar: Boolean; override; -> Not implemented // function SupportsExtendedSQLGrammar: Boolean; override; -> Not implemented // function SupportsANSI92EntryLevelSQL: Boolean; override; -> Not implemented // function SupportsANSI92IntermediateSQL: Boolean; override; -> Not implemented // function SupportsANSI92FullSQL: Boolean; override; -> Not implemented function SupportsIntegrityEnhancementFacility: Boolean; override; // function SupportsOuterJoins: Boolean; override; -> Not implemented // function SupportsFullOuterJoins: Boolean; override; -> Not implemented // function SupportsLimitedOuterJoins: Boolean; override; -> Not implemented // function SupportsSchemasInDataManipulation: Boolean; override; -> Not implemented // function SupportsSchemasInProcedureCalls: Boolean; override; -> Not implemented // function SupportsSchemasInTableDefinitions: Boolean; override; -> Not implemented // function SupportsSchemasInIndexDefinitions: Boolean; override; -> Not implemented // function SupportsSchemasInPrivilegeDefinitions: Boolean; override; -> Not implemented function SupportsCatalogsInDataManipulation: Boolean; override; // function SupportsCatalogsInProcedureCalls: Boolean; override; -> Not implemented function SupportsCatalogsInTableDefinitions: Boolean; override; // function SupportsCatalogsInIndexDefinitions: Boolean; override; -> Not implemented // function SupportsCatalogsInPrivilegeDefinitions: Boolean; override; -> Not implemented // function SupportsPositionedDelete: Boolean; override; -> Not implemented // function SupportsPositionedUpdate: Boolean; override; -> Not implemented // function SupportsSelectForUpdate: Boolean; override; -> Not implemented // function SupportsStoredProcedures: Boolean; override; -> Not implemented function SupportsSubqueriesInComparisons: Boolean; override; // function SupportsSubqueriesInExists: Boolean; override; -> Not implemented // function SupportsSubqueriesInIns: Boolean; override; -> Not implemented // function SupportsSubqueriesInQuantifieds: Boolean; override; -> Not implemented // function SupportsCorrelatedSubqueries: Boolean; override; -> Not implemented // function SupportsUnion: Boolean; override; -> Not implemented function SupportsUnionAll: Boolean; override; // function SupportsOpenCursorsAcrossCommit: Boolean; override; -> Not implemented // function SupportsOpenCursorsAcrossRollback: Boolean; override; -> Not implemented function SupportsOpenStatementsAcrossCommit: Boolean; override; function SupportsOpenStatementsAcrossRollback: Boolean; override; // function SupportsTransactions: Boolean; override; -> Not implemented // function SupportsTransactionIsolationLevel(Level: TZTransactIsolationLevel): // Boolean; override; -> Not implemented function SupportsDataDefinitionAndDataManipulationTransactions: Boolean; override; function SupportsDataManipulationTransactionsOnly: Boolean; override; // function SupportsResultSetType(_Type: TZResultSetType): Boolean; override; -> Not implemented // function SupportsResultSetConcurrency(_Type: TZResultSetType; // Concurrency: TZResultSetConcurrency): Boolean; override; -> Not implemented // function SupportsBatchUpdates: Boolean; override; -> Not implemented // maxima: function GetMaxBinaryLiteralLength: Integer; override; function GetMaxCharLiteralLength: Integer; override; function GetMaxColumnNameLength: Integer; override; function GetMaxColumnsInGroupBy: Integer; override; function GetMaxColumnsInIndex: Integer; override; function GetMaxColumnsInOrderBy: Integer; override; function GetMaxColumnsInSelect: Integer; override; function GetMaxColumnsInTable: Integer; override; function GetMaxConnections: Integer; override; function GetMaxCursorNameLength: Integer; override; function GetMaxIndexLength: Integer; override; // function GetMaxSchemaNameLength: Integer; override; -> Not implemented // function GetMaxProcedureNameLength: Integer; override; -> Not implemented function GetMaxCatalogNameLength: Integer; override; function GetMaxRowSize: Integer; override; function GetMaxStatementLength: Integer; override; function GetMaxStatements: Integer; override; function GetMaxTableNameLength: Integer; override; function GetMaxTablesInSelect: Integer; override; function GetMaxUserNameLength: Integer; override; // policies (how are various data and operations handled): // function IsReadOnly: Boolean; override; -> Not implemented // function IsCatalogAtStart: Boolean; override; -> Not implemented function DoesMaxRowSizeIncludeBlobs: Boolean; override; // function NullsAreSortedHigh: Boolean; override; -> Not implemented // function NullsAreSortedLow: Boolean; override; -> Not implemented // function NullsAreSortedAtStart: Boolean; override; -> Not implemented // function NullsAreSortedAtEnd: Boolean; override; -> Not implemented // function NullPlusNonNullIsNull: Boolean; override; -> Not implemented // function UsesLocalFiles: Boolean; override; -> Not implemented function UsesLocalFilePerTable: Boolean; override; // function StoresUpperCaseIdentifiers: Boolean; override; -> Not implemented // function StoresLowerCaseIdentifiers: Boolean; override; -> Not implemented function StoresMixedCaseIdentifiers: Boolean; override; // function StoresUpperCaseQuotedIdentifiers: Boolean; override; -> Not implemented // function StoresLowerCaseQuotedIdentifiers: Boolean; override; -> Not implemented // function StoresMixedCaseQuotedIdentifiers: Boolean; override; -> Not implemented function GetDefaultTransactionIsolation: TZTransactIsolationLevel; override; // function DataDefinitionCausesTransactionCommit: Boolean; override; -> Not implemented // function DataDefinitionIgnoredInTransactions: Boolean; override; -> Not implemented // interface details (terms, keywords, etc): function GetSchemaTerm: string; override; function GetProcedureTerm: string; override; function GetCatalogTerm: string; override; // function GetCatalogSeparator: string; override; -> Not implemented function GetSQLKeywords: string; override; function GetNumericFunctions: string; override; function GetStringFunctions: string; override; function GetSystemFunctions: string; override; function GetTimeDateFunctions: string; override; function GetSearchStringEscape: string; override; function GetExtraNameCharacters: string; override; end; {** Implements MySQL Database Metadata. } TZMySQLDatabaseMetadata = class(TZAbstractDatabaseMetadata) protected function CreateDatabaseInfo: IZDatabaseInfo; override; // technobot 2008-06-26 procedure GetCatalogAndNamePattern(const Catalog, SchemaPattern, NamePattern: string; out OutCatalog, OutNamePattern: string); function UncachedGetTables(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const Types: TStringDynArray): IZResultSet; override; // function UncachedGetSchemas: IZResultSet; override; -> Not implemented function UncachedGetCatalogs: IZResultSet; override; function UncachedGetTableTypes: IZResultSet; override; function UncachedGetColumns(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const ColumnNamePattern: string): IZResultSet; override; function UncachedGetTablePrivileges(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string): IZResultSet; override; function UncachedGetColumnPrivileges(const Catalog: string; const Schema: string; const Table: string; const ColumnNamePattern: string): IZResultSet; override; function UncachedGetPrimaryKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; override; function UncachedGetImportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; override; function UncachedGetExportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; override; function UncachedGetCrossReference(const PrimaryCatalog: string; const PrimarySchema: string; const PrimaryTable: string; const ForeignCatalog: string; const ForeignSchema: string; const ForeignTable: string): IZResultSet; override; function UncachedGetIndexInfo(const Catalog: string; const Schema: string; const Table: string; Unique: Boolean; Approximate: Boolean): IZResultSet; override; // function UncachedGetSequences(const Catalog: string; const SchemaPattern: string; // const SequenceNamePattern: string): IZResultSet; override; -> Not implemented function UncachedGetProcedures(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string): IZResultSet; override; function UncachedGetProcedureColumns(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string; const ColumnNamePattern: string): IZResultSet; override; function UncachedGetVersionColumns(const Catalog: string; const Schema: string; const Table: string): IZResultSet; override; function UncachedGetTypeInfo: IZResultSet; override; // function UncachedGetUDTs(const Catalog: string; const SchemaPattern: string; // const TypeNamePattern: string; const Types: TIntegerDynArray): IZResultSet; override; function UncachedGetCollationAndCharSet(const Catalog, SchemaPattern, TableNamePattern, ColumnNamePattern: string): IZResultSet; override; //EgonHugeist function UncachedGetCharacterSets: IZResultSet; override; //EgonHugeist public destructor Destroy; override; end; implementation uses Math, ZMessages, ZDbcUtils, ZCollections, ZDbcMySqlUtils; { TZMySQLDatabaseInfo } {** Constructs this object. @param Metadata the interface of the correpsonding database metadata object } constructor TZMySQLDatabaseInfo.Create(const Metadata: TZAbstractDatabaseMetadata); begin inherited Create(MetaData, '`'); end; //---------------------------------------------------------------------- // First, a variety of minor information about the target database. {** What's the name of this database product? @return database product name } function TZMySQLDatabaseInfo.GetDatabaseProductName: string; begin Result := 'MySQL'; end; {** What's the version of this database product? @return database version } function TZMySQLDatabaseInfo.GetDatabaseProductVersion: string; begin Result := '3+'; end; {** What's the name of this JDBC driver? @return JDBC driver name } function TZMySQLDatabaseInfo.GetDriverName: string; begin Result := 'Zeos Database Connectivity Driver for MySQL'; end; {** What's this JDBC driver's major version number? @return JDBC driver major version } function TZMySQLDatabaseInfo.GetDriverMajorVersion: Integer; begin Result := 1; end; {** What's this JDBC driver's minor version number? @return JDBC driver minor version number } function TZMySQLDatabaseInfo.GetDriverMinorVersion: Integer; begin Result := 1; end; {** Does the database use a file for each table? @return true if the database uses a local file for each table } function TZMySQLDatabaseInfo.UsesLocalFilePerTable: Boolean; begin Result := True; end; {** Does the database treat mixed case unquoted SQL identifiers as case insensitive and store them in mixed case? @return true if so; false otherwise } function TZMySQLDatabaseInfo.StoresMixedCaseIdentifiers: Boolean; begin Result := True; end; {** Gets a comma-separated list of all a database's SQL keywords that are NOT also SQL92 keywords. @return the list } function TZMySQLDatabaseInfo.GetSQLKeywords: string; begin Result := 'AUTO_INCREMENT,BINARY,BLOB,ENUM,INFILE,LOAD,MEDIUMINT,OPTION,' + 'OUTFILE,REPLACE,SET,TEXT,UNSIGNED,ZEROFILL'; { mdaems : added all reserved words indicated by mysql documentation (up to mysql 5.1)} Result := Result + 'ACCESSIBLE,ADD,ALL,ALTER,ANALYZE,AND,ASC,ASENSITIVE,' + ' BEFORE,BETWEEN,BIGINT,BOTH,CALL,CASCADE,CASE,CHANGE,CHARACTER,CHECK,' + 'COLLATE,COLUMN,CONDITION,CONSTRAINT,CONTINUE,CONVERT,CROSS,' + 'CURRENT_DATE,CURRENT_TIME,CURRENT_TIMESTAMP,CURRENT_USER,CURSOR,' + 'DATABASE,DATABASES,DAY_HOUR,DAY_MICROSECOND,DAY_MINUTE,DAY_SECOND,' + 'DEC,DECIMAL,DECLARE,DEFAULT,DELAYED,DESC,DESCRIBE,DETERMINISTIC,' + 'DISTINCT,DISTINCTROW,DIV,DOUBLE,DUAL,EACH,ELSE,ELSEIF,ENCLOSED,' + 'ESCAPED,EXISTS,EXIT,EXPLAIN,FALSE,FETCH,FLOAT,FLOAT4,FLOAT8,FOR,' + 'FORCE,FOREIGN,FULLTEXT,GENERAL,GRANT,HIGH_PRIORITY,HOUR_MICROSECOND,' + 'HOUR_MINUTE,HOUR_SECOND,IF,IGNORE,IGNORE_SERVER_IDS,IN,INNER,INOUT,INSENSITIVE,INT,' + 'INT1,INT2,INT3,INT4,INT8,INTERVAL,ITERATE,JOIN,KEYS,KILL,LEADING,' + 'LEAVE,LEFT,LIKE,LIMIT,LINEAR,LINES,LOCALTIME,LOCALTIMESTAMP,LOCK,' + 'LONG,LONGBLOB,LONGTEXT,LOOP,LOW_PRIORITY,MASTER_HEARTBEAT_PERIOD,MASTER_SSL_VERIFY_SERVER_CERT,' + 'MATCH,MAXVALUE,MEDIUMBLOB,MEDIUMTEXT,MIDDLEINT,MINUTE_MICROSECOND,MINUTE_SECOND,' + 'MOD,MODIFIES,NATURAL,NOT,NO_WRITE_TO_BINLOG,NUMERIC,OPTIMIZE,' + 'OPTIONALLY,OR,OUT,OUTER,PRECISION,PROCEDURE,PURGE,RANGE,READ,READS,' + 'READ_ONLY,READ_WRITE,REAL,REFERENCES,REGEXP,RELEASE,RENAME,REPEAT,' + 'REQUIRE,RESIGNAL SIGNAL,RESTRICT,RETURN,REVOKE,RIGHT,RLIKE,SCHEMA,SCHEMAS,' + 'SECOND_MICROSECOND,SENSITIVE,SEPARATOR,SHOW,SLOW,SMALLINT,SPATIAL,' + 'SPECIFIC,SQL,SQLEXCEPTION,SQLSTATE,SQLWARNING,SQL_BIG_RESULT,' + 'SQL_CALC_FOUND_ROWS,SQL_SMALL_RESULT,SSL,STARTING,STRAIGHT_JOIN,' + 'TERMINATED,THEN,TINYBLOB,TINYINT,TINYTEXT,TO,TRAILING,TRIGGER,' + 'TRUE,UNDO,UNION,UNIQUE,UNLOCK,USAGE,USE,USING,UTC_DATE,UTC_TIME,' + 'UTC_TIMESTAMP,VARBINARY,VARCHARACTER,VARYING,WHEN,WHILE,WITH,' + 'WRITE,X509,XOR,YEAR_MONTH,ACCESSIBLE,LINEAR,' + 'MASTER_SSL_VERIFY_SERVER_CERT,RANGE,READ_ONLY,READ_WRITE'; end; {** Gets a comma-separated list of math functions. These are the X/Open CLI math function names used in the JDBC function escape clause. @return the list } function TZMySQLDatabaseInfo.GetNumericFunctions: string; begin Result := 'ABS,ACOS,ASIN,ATAN,ATAN2,BIT_COUNT,CEILING,COS,COT,DEGREES,EXP,' + 'FLOOR,LOG,LOG10,MAX,MIN,MOD,PI,POW,POWER,RADIANS,RAND,ROUND,SIN,SQRT,' + 'TAN,TRUNCATE'; { mdaems : added all numeric functions indicated by mysql documentation (up to mysql 5.1)} Result := Result + 'BIT_COUNT,CEIL,CRC32,LN,LOG2,SIGN,UUID'; end; {** Gets a comma-separated list of string functions. These are the X/Open CLI string function names used in the JDBC function escape clause. @return the list } function TZMySQLDatabaseInfo.GetStringFunctions: string; begin Result := 'ASCII,CHAR,CHAR_LENGTH,CHARACTER_LENGTH,CONCAT,ELT,FIELD,' + 'FIND_IN_SET,INSERT,INSTR,INTERVAL,LCASE,LEFT,LENGTH,LOCATE,LOWER,LTRIM,' + 'MID,POSITION,OCTET_LENGTH,REPEAT,REPLACE,REVERSE,RIGHT,RTRIM,SPACE,' + 'SOUNDEX,SUBSTRING,SUBSTRING_INDEX,TRIM,UCASE,UPPER'; { mdaems : added all string functions indicated by mysql documentation (up to mysql 5.1)} Result := Result + 'AES_DECRYPT,AES_ENCRYPT,BIN,BIT_LENGTH,CHARSET,' + 'COERCIBILITY,COLLATION,COMPRESS,CONCAT_WS,DECODE,DES_DECRYPT,DES_ENCRYPT,' + 'ENCODE,ENCRYPT,EXPORT_SET,FORMAT,HEX,LOAD_FILE,LPAD,MAKE_SET,MD5,OCT,ORD,' + 'QUOTE,RPAD,STRCMP,SHA,SHA1,SUBSTR,UNHEX,EXTRACTVALUE,UPDATEXML,' + 'UNCOMPRESS,UNCOMPRESSED_LENGTH'; end; {** Gets a comma-separated list of system functions. These are the X/Open CLI system function names used in the JDBC function escape clause. @return the list } function TZMySQLDatabaseInfo.GetSystemFunctions: string; begin Result := 'DATABASE,USER,SYSTEM_USER,SESSION_USER,PASSWORD,ENCRYPT,' + 'LAST_INSERT_ID,VERSION'; { mdaems : added all system functions indicated by mysql documentation (up to mysql 5.1)} Result := Result + 'BENCHMARK,CONNECTION_ID,CURRENT_USER,DEFAULT,FOUND_ROWS,' + 'GET_LOCK,INET_ATON,INET_NTOA,IS_FREE_LOCK,IS_USED_LOCK,MASTER_POS_WAIT,' + 'NAME_CONST,OLD_PASSWORD,RELEASE_LOCK,ROW_COUNT,SCHEMA,SLEEP'; end; {** Gets a comma-separated list of time and date functions. @return the list } function TZMySQLDatabaseInfo.GetTimeDateFunctions: string; begin Result := 'DAYOFWEEK,WEEKDAY,DAYOFMONTH,DAYOFYEAR,MONTH,DAYNAME,MONTHNAME,' + 'QUARTER,WEEK,YEAR,HOUR,MINUTE,SECOND,PERIOD_ADD,PERIOD_DIFF,TO_DAYS,' + 'FROM_DAYS,DATE_FORMAT,TIME_FORMAT,CURDATE,CURRENT_DATE,CURTIME,' + 'CURRENT_TIME,NOW,SYSDATE,CURRENT_TIMESTAMP,UNIX_TIMESTAMP,FROM_UNIXTIME,' + 'SEC_TO_TIME,TIME_TO_SEC'; { mdaems : added all time and date functions indicated by mysql documentation (up to mysql 5.1)} Result := Result + 'ADDDATE,ADDTIME,CONVERT_TZ,CURRENT_TIMESTAMP,DATE_ADD,' + 'DATE_SUB,DATE,DATEDIFF,DAYOFWEEK,GET_FORMAT,LAST_DAY,LOCALTIME,' + 'LOCALTIMESTAMP,MAKEDATE,MAKETIME,MICROSECOND,STR_TO_DATE,SUBDATE,SUBTIME,' + 'TIMEDIFF,TIMESTAMP,TIMESTAMPADD,TIMESTAMPDIFF,UTC_DATE,UTC_TIME,' + 'UTC_TIMESTAMP,WEEKOFYEAR,YEARWEEK'; end; {** Gets the string that can be used to escape wildcard characters. This is the string that can be used to escape '_' or '%' in the string pattern style catalog search parameters.

The '_' character represents any single character.

The '%' character represents any sequence of zero or more characters. @return the string used to escape wildcard characters } function TZMySQLDatabaseInfo.GetSearchStringEscape: string; begin Result := '\'; end; {** Gets all the "extra" characters that can be used in unquoted identifier names (those beyond a-z, A-Z, 0-9 and _). @return the string containing the extra characters } function TZMySQLDatabaseInfo.GetExtraNameCharacters: string; begin Result := ''; end; //-------------------------------------------------------------------- // Functions describing which features are supported. {** Can an "ORDER BY" clause use columns not in the SELECT statement? @return true if so; false otherwise } function TZMySQLDatabaseInfo.SupportsOrderByUnrelated: Boolean; var MajorVersion: Integer; MinorVersion: Integer; begin GetVersion(MajorVersion, MinorVersion); // changed from False by mdaems. After testing with lower versions, please correct. Result := MajorVersion >= 5; end; {** Can a "GROUP BY" clause use columns not in the SELECT? @return true if so; false otherwise } function TZMySQLDatabaseInfo.SupportsGroupByUnrelated: Boolean; begin Result := False; end; {** Can a "GROUP BY" clause add columns not in the SELECT provided it specifies all the columns in the SELECT? @return true if so; false otherwise } function TZMySQLDatabaseInfo.SupportsGroupByBeyondSelect: Boolean; begin Result := True; end; {** Is the SQL Integrity Enhancement Facility supported? @return true if so; false otherwise } function TZMySQLDatabaseInfo.SupportsIntegrityEnhancementFacility: Boolean; begin Result := False; end; {** What's the database vendor's preferred term for "schema"? @return the vendor term } function TZMySQLDatabaseInfo.GetSchemaTerm: string; begin Result := ''; end; {** What's the database vendor's preferred term for "procedure"? @return the vendor term } function TZMySQLDatabaseInfo.GetProcedureTerm: string; begin Result := ''; end; {** What's the database vendor's preferred term for "catalog"? @return the vendor term } function TZMySQLDatabaseInfo.GetCatalogTerm: string; begin Result := 'Database'; end; {** Can a catalog name be used in a data manipulation statement? @return true if so; false otherwise } function TZMySQLDatabaseInfo.SupportsCatalogsInDataManipulation: Boolean; var MajorVersion: Integer; MinorVersion: Integer; begin GetVersion(MajorVersion, MinorVersion); Result := ((MajorVersion = 3) and (MinorVersion >= 22)) or (MajorVersion > 3); end; {** Can a catalog name be used in a table definition statement? @return true if so; false otherwise } function TZMySQLDatabaseInfo.SupportsCatalogsInTableDefinitions: Boolean; begin Result := False; end; {** Are subqueries in comparison expressions supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZMySQLDatabaseInfo.SupportsSubqueriesInComparisons: Boolean; begin Result := True; end; {** Is SQL UNION ALL supported? @return true if so; false otherwise } function TZMySQLDatabaseInfo.SupportsUnionAll: Boolean; var MajorVersion: Integer; MinorVersion: Integer; begin GetVersion(MajorVersion, MinorVersion); Result := MajorVersion >= 4; end; {** Can statements remain open across commits? @return true if statements always remain open; false if they might not remain open } function TZMySQLDatabaseInfo.SupportsOpenStatementsAcrossCommit: Boolean; begin Result := False; end; {** Can statements remain open across rollbacks? @return true if statements always remain open; false if they might not remain open } function TZMySQLDatabaseInfo.SupportsOpenStatementsAcrossRollback: Boolean; begin Result := False; end; //---------------------------------------------------------------------- // The following group of methods exposes various limitations // based on the target database with the current driver. // Unless otherwise specified, a result of zero means there is no // limit, or the limit is not known. {** How many hex characters can you have in an inline binary literal? @return max binary literal length in hex characters; a result of zero means that there is no limit or the limit is not known } function TZMySQLDatabaseInfo.GetMaxBinaryLiteralLength: Integer; begin Result := 16777208; end; {** What's the max length for a character literal? @return max literal length; a result of zero means that there is no limit or the limit is not known } function TZMySQLDatabaseInfo.GetMaxCharLiteralLength: Integer; begin Result := 16777208; end; {** What's the limit on column name length? @return max column name length; a result of zero means that there is no limit or the limit is not known } function TZMySQLDatabaseInfo.GetMaxColumnNameLength: Integer; begin Result := 64; end; {** What's the maximum number of columns in a "GROUP BY" clause? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZMySQLDatabaseInfo.GetMaxColumnsInGroupBy: Integer; begin Result := 16; end; {** What's the maximum number of columns allowed in an index? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZMySQLDatabaseInfo.GetMaxColumnsInIndex: Integer; begin Result := 16; end; {** What's the maximum number of columns in an "ORDER BY" clause? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZMySQLDatabaseInfo.GetMaxColumnsInOrderBy: Integer; begin Result := 16; end; {** What's the maximum number of columns in a "SELECT" list? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZMySQLDatabaseInfo.GetMaxColumnsInSelect: Integer; begin Result := 256; end; {** What's the maximum number of columns in a table? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZMySQLDatabaseInfo.GetMaxColumnsInTable: Integer; begin Result := 512; end; {** How many active connections can we have at a time to this database? @return max number of active connections; a result of zero means that there is no limit or the limit is not known } function TZMySQLDatabaseInfo.GetMaxConnections: Integer; begin Result := 0; end; {** What's the maximum cursor name length? @return max cursor name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZMySQLDatabaseInfo.GetMaxCursorNameLength: Integer; begin Result := 64; end; {** Retrieves the maximum number of bytes for an index, including all of the parts of the index. @return max index length in bytes, which includes the composite of all the constituent parts of the index; a result of zero means that there is no limit or the limit is not known } function TZMySQLDatabaseInfo.GetMaxIndexLength: Integer; begin Result := 128; end; {** What's the maximum length of a catalog name? @return max name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZMySQLDatabaseInfo.GetMaxCatalogNameLength: Integer; begin Result := 32; end; {** What's the maximum length of a single row? @return max row size in bytes; a result of zero means that there is no limit or the limit is not known } function TZMySQLDatabaseInfo.GetMaxRowSize: Integer; begin Result := 2147483639; end; {** Did getMaxRowSize() include LONGVARCHAR and LONGVARBINARY blobs? @return true if so; false otherwise } function TZMySQLDatabaseInfo.DoesMaxRowSizeIncludeBlobs: Boolean; begin Result := True; end; {** What's the maximum length of an SQL statement? @return max length in bytes; a result of zero means that there is no limit or the limit is not known } function TZMySQLDatabaseInfo.GetMaxStatementLength: Integer; begin Result := 65531; end; {** How many active statements can we have open at one time to this database? @return the maximum number of statements that can be open at one time; a result of zero means that there is no limit or the limit is not known } function TZMySQLDatabaseInfo.GetMaxStatements: Integer; begin Result := 0; end; {** What's the maximum length of a table name? @return max name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZMySQLDatabaseInfo.GetMaxTableNameLength: Integer; begin Result := 64; end; {** What's the maximum number of tables in a SELECT statement? @return the maximum number of tables allowed in a SELECT statement; a result of zero means that there is no limit or the limit is not known } function TZMySQLDatabaseInfo.GetMaxTablesInSelect: Integer; begin Result := 256; end; {** What's the maximum length of a user name? @return max user name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZMySQLDatabaseInfo.GetMaxUserNameLength: Integer; begin Result := 16; end; //---------------------------------------------------------------------- {** What's the database's default transaction isolation level? The values are defined in java.sql.Connection. @return the default isolation level @see Connection } function TZMySQLDatabaseInfo.GetDefaultTransactionIsolation: TZTransactIsolationLevel; begin Result := tiNone; end; {** Are both data definition and data manipulation statements within a transaction supported? @return true if so; false otherwise } function TZMySQLDatabaseInfo. SupportsDataDefinitionAndDataManipulationTransactions: Boolean; begin Result := True; end; {** Are only data manipulation statements within a transaction supported? @return true if so; false otherwise } function TZMySQLDatabaseInfo.SupportsDataManipulationTransactionsOnly: Boolean; begin case Metadata.GetConnection.GetTransactionIsolation of tiReadUncommitted: Result := True; tiReadCommitted: Result := True; tiRepeatableRead: Result := True; tiSerializable: Result := True; else Result := False; end; end; {** Gets the MySQL version info. @param MajorVesion the major version of MySQL server. @param MinorVersion the minor version of MySQL server. } procedure TZMySQLDatabaseInfo.GetVersion(var MajorVersion, MinorVersion: Integer); var VersionList: TStrings; Subversion : integer; begin DecodeSqlVersioning(Metadata.GetConnection.GetHostVersion, MajorVersion,MinorVersion, Subversion); if (Majorversion < 4) or ((majorversion=4) and (Minorversion = 0)) then with Metadata.GetConnection.CreateStatement.ExecuteQuery('SELECT VERSION()') do begin VersionList := SplitString(String(GetString(1)), '.-'); try if VersionList.Count >= 2 then begin MajorVersion := StrToIntDef(VersionList.Strings[0], 0); MinorVersion := StrToIntDef(VersionList.Strings[1], 0); end; finally VersionList.Free; end; Close; end; end; { TZMySQLDatabaseMetadata } {** Destroys this object and cleanups the memory. } destructor TZMySQLDatabaseMetadata.Destroy; begin inherited Destroy; end; {** Constructs a database information object and returns the interface to it. Used internally by the constructor. @return the database information object interface } function TZMySQLDatabaseMetadata.CreateDatabaseInfo: IZDatabaseInfo; begin Result := TZMySQLDatabaseInfo.Create(Self); end; procedure TZMySQLDatabaseMetadata.GetCatalogAndNamePattern(const Catalog, SchemaPattern, NamePattern: string; out OutCatalog, OutNamePattern: string); begin if Catalog = '' then begin if SchemaPattern <> '' then OutCatalog := NormalizePatternCase(SchemaPattern) else OutCatalog := NormalizePatternCase(FDatabase); end else OutCatalog := NormalizePatternCase(Catalog); if NamePattern = '' then OutNamePattern := '%' else OutNamePattern := NormalizePatternCase(NamePattern); end; {** Gets a description of tables available in a catalog.

Only table descriptions matching the catalog, schema, table name and type criteria are returned. They are ordered by TABLE_TYPE, TABLE_SCHEM and TABLE_NAME.

Each table description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. TABLE_TYPE String => table type. Typical types are "TABLE", "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM".
  5. REMARKS String => explanatory comment on the table

Note: Some databases may not return information for all tables. @param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param tableNamePattern a table name pattern @param types a list of table types to include; null returns all types @return ResultSet - each row is a table description @see #getSearchStringEscape } function TZMySQLDatabaseMetadata.UncachedGetTables(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const Types: TStringDynArray): IZResultSet; var LCatalog, LTableNamePattern: string; begin Result := inherited UncachedGetTables(Catalog, SchemaPattern, TableNamePattern, Types); GetCatalogAndNamePattern(Catalog, SchemaPattern, TableNamePattern, LCatalog, LTableNamePattern); with GetConnection.CreateStatement.ExecuteQuery( Format('SHOW TABLES FROM %s LIKE ''%s''', [IC.Quote(LCatalog), LTableNamePattern])) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateString(1, LCatalog); Result.UpdateString(3, GetString(1)); Result.UpdateString(4, 'TABLE'); Result.InsertRow; end; Close; end; // If a table was specified but not found, check if it could be a temporary table if not Result.First and (LTableNamePattern <> '%') then begin try EnterSilentMySQLError; try if GetConnection.CreateStatement.ExecuteQuery( Format('SHOW COLUMNS FROM %s.%s', [IC.Quote(LCatalog), IC.Quote(LTableNamePattern)])).Next then begin Result.MoveToInsertRow; Result.UpdateString(1, LCatalog); Result.UpdateString(3, LTableNamePattern); Result.UpdateString(4, 'TABLE'); Result.InsertRow; end; finally LeaveSilentMySQLError; end; except on EZMySQLSilentException do ; on EZSQLException do ; end; end; end; {** Gets the catalog names available in this database. The results are ordered by catalog name.

The catalog column is:

  1. TABLE_CAT String => catalog name
@return ResultSet - each row has a single String column that is a catalog name } function TZMySQLDatabaseMetadata.UncachedGetCatalogs: IZResultSet; begin Result:=inherited UncachedGetCatalogs; with GetConnection.CreateStatement.ExecuteQuery('SHOW DATABASES') do begin while Next do begin Result.MoveToInsertRow; Result.UpdateString(1, GetString(1)); Result.InsertRow; end; Close; end; end; {** Gets the table types available in this database. The results are ordered by table type.

The table type is:

  1. TABLE_TYPE String => table type. Typical types are "TABLE", "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM".
@return ResultSet - each row has a single String column that is a table type } function TZMySQLDatabaseMetadata.UncachedGetTableTypes: IZResultSet; begin Result:=inherited UncachedGetTableTypes; Result.MoveToInsertRow; Result.UpdateString(1, 'TABLE'); Result.InsertRow; end; {** Gets a description of table columns available in the specified catalog.

Only column descriptions matching the catalog, schema, table and column name criteria are returned. They are ordered by TABLE_SCHEM, TABLE_NAME and ORDINAL_POSITION.

Each column description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. COLUMN_NAME String => column name
  5. DATA_TYPE short => SQL type from java.sql.Types
  6. TYPE_NAME String => Data source dependent type name, for a UDT the type name is fully qualified
  7. COLUMN_SIZE int => column size. For char or date types this is the maximum number of characters, for numeric or decimal types this is precision.
  8. BUFFER_LENGTH is not used.
  9. DECIMAL_DIGITS int => the number of fractional digits
  10. NUM_PREC_RADIX int => Radix (typically either 10 or 2)
  11. NULLABLE int => is NULL allowed?
    • columnNoNulls - might not allow NULL values
    • columnNullable - definitely allows NULL values
    • columnNullableUnknown - nullability unknown
  12. REMARKS String => comment describing column (may be null)
  13. COLUMN_DEF String => default value (may be null)
  14. SQL_DATA_TYPE int => unused
  15. SQL_DATETIME_SUB int => unused
  16. CHAR_OCTET_LENGTH int => for char types the maximum number of bytes in the column
  17. ORDINAL_POSITION int => index of column in table (starting at 1)
  18. IS_NULLABLE String => "NO" means column definitely does not allow NULL values; "YES" means the column might allow NULL values. An empty string means nobody knows.
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param tableNamePattern a table name pattern @param columnNamePattern a column name pattern @return ResultSet - each row is a column description @see #getSearchStringEscape } function TZMySQLDatabaseMetadata.UncachedGetColumns(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const ColumnNamePattern: string): IZResultSet; var I: Integer; MySQLType: TZSQLType; TempCatalog, TempColumnNamePattern, TempTableNamePattern: string; TypeName, TypeInfoSecond: String; Nullable, DefaultValue: String; HasDefaultValue: Boolean; ColumnSize, ColumnDecimals: Integer; OrdPosition: Integer; TableNameList: TStrings; TableNameLength: Integer; ColumnIndexes : Array[1..6] of integer; Res : IZResultset; begin Res:=inherited UncachedGetColumns(Catalog, SchemaPattern, TableNamePattern, ColumnNamePattern); GetCatalogAndNamePattern(Catalog, SchemaPattern, ColumnNamePattern, TempCatalog, TempColumnNamePattern); TableNameLength := 0; TableNameList := TStringList.Create; try with GetTables(Catalog, SchemaPattern, TableNamePattern, nil) do begin while Next do begin TableNameList.Add(GetString(3)); //TABLE_NAME TableNameLength := Max(TableNameLength, Length(TableNameList[TableNameList.Count - 1])); end; Close; end; for I := 0 to TableNameList.Count - 1 do begin OrdPosition := 1; TempTableNamePattern := TableNameList.Strings[I]; with GetConnection.CreateStatement.ExecuteQuery( Format('SHOW FULL COLUMNS FROM %s.%s LIKE ''%s''', [IC.Quote(TempCatalog), IC.Quote(TempTableNamePattern), TempColumnNamePattern])) do begin ColumnIndexes[1] := FindColumn('Field'); ColumnIndexes[2] := FindColumn('Type'); ColumnIndexes[3] := FindColumn('Null'); ColumnIndexes[4] := FindColumn('Extra'); ColumnIndexes[5] := FindColumn('Default'); ColumnIndexes[6] := FindColumn('Collation'); while Next do begin {initialise some variables} Res.MoveToInsertRow; Res.UpdateString(1, TempCatalog); Res.UpdateString(2, ''); Res.UpdateString(3, TempTableNamePattern) ; Res.UpdateString(4, GetString(ColumnIndexes[1])); ConvertMySQLColumnInfoFromString(GetString(ColumnIndexes[2]), ConSettings, TypeName, TypeInfoSecond, MySQLType, ColumnSize, ColumnDecimals); Res.UpdateInt(5, Ord(MySQLType)); Res.UpdateString(6, TypeName); Res.UpdateInt(7, ColumnSize); Res.UpdateInt(8, MAXBUF); Res.UpdateInt(9, ColumnDecimals); Res.UpdateNull(10); { Sets nullable fields. } Nullable := GetString(ColumnIndexes[3]); if Nullable <> '' then if Nullable = 'YES' then begin Res.UpdateInt(11, Ord(ntNullable)); Res.UpdateString(18, 'YES'); end else begin Res.UpdateInt(11, Ord(ntNoNulls)); Res.UpdateString(18, 'NO'); end else begin Res.UpdateInt(11, 0); Res.UpdateString(18, 'NO'); end; Res.UpdateString(12, GetString(ColumnIndexes[4])); // MySQL is a bit bizarre. if IsNull(ColumnIndexes[5]) then begin // MySQL bizarity 1: // NULL actually means that the default is NULL. // Superfluous, since there's a NULL / NOT NULL flag to control whether the field may have no value. // So we just ignore this, the field gets set to NULL if nothing was specified... HasDefaultValue := false; DefaultValue := ''; end else begin DefaultValue := GetString(ColumnIndexes[5]); if not (DefaultValue = '') then HasDefaultValue := true else begin // MySQL bizarity 2: // For CHAR, BLOB, TEXT and SET types, '' either means: default value is '' or: no default value // There's absolutely no way of telling when using SHOW COLUMNS FROM, // the correct information can /only/ be discerned by using information_schema. // TODO: For now, just use '' as default value for these types, but this should really be fixed to use information_schema. // For ENUM types, '' means: default value is first value in enum set // For other types, '' means: no default value HasDefaultValue := false; if Pos('blob', TypeName) > 0 then HasDefaultValue := true; if Pos('text', TypeName) > 0 then HasDefaultValue := true; if Pos('char', TypeName) > 0 then HasDefaultValue := true; if 'set' = TypeName then HasDefaultValue := true; if 'enum' = TypeName then begin HasDefaultValue := true; DefaultValue := Copy(TypeInfoSecond, 2,length(TypeInfoSecond)-1); DefaultValue := Copy(DefaultValue, 1, Pos('''', DefaultValue) - 1); end; end; end; if HasDefaultValue then begin // String values in the 'Default value' field are not escaped with apostrophes. // Guess this makes it impossible to specify a function call or similar via default values. if (MySQLType in [stString, stUnicodeString, stBinaryStream, stAsciiStream]) then begin // Since we changed date/time-related columntypes to be presented // as strings, we need to move the CURRENT_TIMESTAMP-check to here. // Also left the other line in order to minimize the changes in ZeosLib if DefaultValue <> 'CURRENT_TIMESTAMP' then DefaultValue := '''' + DefaultValue + '''' end else if (MySQLType in [stDate, stTime, stTimestamp]) then begin if DefaultValue <> 'CURRENT_TIMESTAMP' then DefaultValue := '''' + DefaultValue + '''' end else if (MySQLType = stBoolean) and (TypeName = 'enum') then begin if (DefaultValue = 'y') or (DefaultValue = 'Y') then DefaultValue := '1' else DefaultValue := '0'; end; end; Res.UpdateString(13, DefaultValue); Res.UpdateNull(14); Res.UpdateNull(15); Res.UpdateInt(17, OrdPosition); Res.UpdateBoolean(19, //AUTO_INCREMENT Trim(LowerCase(GetString(ColumnIndexes[4]))) = 'auto_increment'); //Extra Res.UpdateBoolean(20, //CASE_SENSITIVE IC.IsCaseSensitive(GetString(ColumnIndexes[1]))); //Field Res.UpdateBoolean(21, True); //SEARCHABLE Res.UpdateBoolean(22, True); //WRITABLE Res.UpdateBoolean(23, True); //DEFINITELYWRITABLE Res.UpdateBoolean(24, False); //READONLY Inc(OrdPosition); Res.InsertRow; end; Close; end; end; finally TableNameList.Free; end; Result := Res; end; {** Gets a description of the access rights for a table's columns.

Only privileges matching the column name criteria are returned. They are ordered by COLUMN_NAME and PRIVILEGE.

Each privilige description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. COLUMN_NAME String => column name
  5. GRANTOR => grantor of access (may be null)
  6. GRANTEE String => grantee of access
  7. PRIVILEGE String => name of access (SELECT, INSERT, UPDATE, REFRENCES, ...)
  8. IS_GRANTABLE String => "YES" if grantee is permitted to grant to others; "NO" if not; null if unknown
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @param columnNamePattern a column name pattern @return ResultSet - each row is a column privilege description @see #getSearchStringEscape } function TZMySQLDatabaseMetadata.UncachedGetColumnPrivileges(const Catalog: string; const Schema: string; const Table: string; const ColumnNamePattern: string): IZResultSet; var I: Integer; Host, Database, Grantor, User, FullUser: String; AllPrivileges, ColumnName, Privilege: String; PrivilegesList: TStrings; ColumnNameCondition, TableNameCondition, SchemaCondition: string; begin Result:=inherited UncachedGetColumnPrivileges(Catalog, Schema, Table, ColumnNamePattern); If Catalog = '' then If Schema <> '' then SchemaCondition := ConstructNameCondition(Schema,'c.db') else SchemaCondition := ConstructNameCondition(FDatabase,'c.db') else SchemaCondition := ConstructNameCondition(Catalog,'c.db'); TableNameCondition := ConstructNameCondition(Table,'c.table_name'); ColumnNameCondition := ConstructNameCondition(ColumnNamePattern,'c.column_name'); If SchemaCondition <> '' then SchemaCondition := ' and ' + SchemaCondition; If TableNameCondition <> '' then TableNameCondition := ' and ' + TableNameCondition; If ColumnNameCondition <> '' then ColumnNameCondition := ' and ' + ColumnNameCondition; PrivilegesList := TStringList.Create; try with GetConnection.CreateStatement.ExecuteQuery( 'SELECT c.host, c.db, t.grantor, c.user, c.table_name,' + ' c.column_name, c.column_priv FROM mysql.columns_priv c,' + ' mysql.tables_priv t WHERE c.host=t.host AND c.db=t.db' + ' AND c.table_name=t.table_name' + SchemaCondition + TableNameCondition + ColumnNameCondition ) do begin while Next do begin Host := GetString(1); Database := GetString(2); Grantor := GetString(4); User := GetString(5); if User = '' then User := '%'; if Host <> '' then FullUser := User + '@' + Host; ColumnName := GetString(6); AllPrivileges := GetString(7); PutSplitString(PrivilegesList, AllPrivileges, ','); for I := 0 to PrivilegesList.Count - 1 do begin Result.MoveToInsertRow; Privilege := Trim(PrivilegesList.Strings[I]); Result.UpdateString(1, Database); Result.UpdateNull(2); Result.UpdateString(3, Table); Result.UpdateString(4, ColumnName); Result.UpdateString(5, Grantor); Result.UpdateString(6, FullUser); Result.UpdateString(7, Privilege); Result.UpdateNull(8); Result.InsertRow; end; end; Close; end; finally PrivilegesList.Free; end; end; {** Gets a description of the access rights for each table available in a catalog. Note that a table privilege applies to one or more columns in the table. It would be wrong to assume that this priviledge applies to all columns (this may be true for some systems but is not true for all.)

Only privileges matching the schema and table name criteria are returned. They are ordered by TABLE_SCHEM, TABLE_NAME, and PRIVILEGE.

Each privilige description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. GRANTOR => grantor of access (may be null)
  5. GRANTEE String => grantee of access
  6. PRIVILEGE String => name of access (SELECT, INSERT, UPDATE, REFRENCES, ...)
  7. IS_GRANTABLE String => "YES" if grantee is permitted to grant to others; "NO" if not; null if unknown
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param tableNamePattern a table name pattern @return ResultSet - each row is a table privilege description @see #getSearchStringEscape } function TZMySQLDatabaseMetadata.UncachedGetTablePrivileges(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string): IZResultSet; var I: Integer; Host, Database, Table, Grantor, User, FullUser: String; AllPrivileges, Privilege: String; PrivilegesList: TStrings; TableNameCondition, SchemaCondition: string; begin Result:=inherited UncachedGetTablePrivileges(Catalog, SchemaPattern, TableNamePattern); If Catalog = '' then If SchemaPattern <> '' then SchemaCondition := ConstructNameCondition(SchemaPattern,'db') else SchemaCondition := ConstructNameCondition(FDatabase,'db') else SchemaCondition := ConstructNameCondition(Catalog,'db'); TableNameCondition := ConstructNameCondition(TableNamePattern,'table_name'); If SchemaCondition <> '' then SchemaCondition := ' and ' + SchemaCondition; If TableNameCondition <> '' then TableNameCondition := ' and ' + TableNameCondition; PrivilegesList := TStringList.Create; try with GetConnection.CreateStatement.ExecuteQuery( 'SELECT host,db,table_name,grantor,user,table_priv' + ' from mysql.tables_priv WHERE 1=1' + SchemaCondition + TableNameCondition ) do begin while Next do begin Host := GetString(1); Database := GetString(2); Table := GetString(3); Grantor := GetString(4); User := GetString(5); if User = '' then User := '%'; if Host <> '' then FullUser := User + '@' + Host; AllPrivileges := GetString(6); PutSplitString(PrivilegesList, AllPrivileges, ','); for I := 0 to PrivilegesList.Count - 1 do begin Result.MoveToInsertRow; Privilege := Trim(PrivilegesList.Strings[I]); Result.UpdateString(1, Database); Result.UpdateNull(2); Result.UpdateString(3, Table); Result.UpdateString(4, Grantor); Result.UpdateString(5, FullUser); Result.UpdateString(6, Privilege); Result.UpdateNull(7); Result.InsertRow; end; end; Close; end; finally PrivilegesList.Free; end; end; {** Gets a description of a table's primary key columns. They are ordered by COLUMN_NAME.

Each primary key column description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. COLUMN_NAME String => column name
  5. KEY_SEQ short => sequence number within primary key
  6. PK_NAME String => primary key name (may be null)
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a primary key column description @exception SQLException if a database access error occurs } function TZMySQLDatabaseMetadata.UncachedGetPrimaryKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; var KeyType: string; LCatalog, LTable: string; ColumnIndexes : Array[1..3] of integer; begin if Table = '' then raise Exception.Create(STableIsNotSpecified); //CHANGE IT! Result:=inherited UncachedGetPrimaryKeys(Catalog, Schema, Table); GetCatalogAndNamePattern(Catalog, Schema, Table, LCatalog, LTable); with GetConnection.CreateStatement.ExecuteQuery( Format('SHOW KEYS FROM %s.%s', [IC.Quote(LCatalog), IC.Quote(LTable)])) do begin ColumnIndexes[1] := FindColumn('Key_name'); ColumnIndexes[2] := FindColumn('Column_name'); ColumnIndexes[3] := FindColumn('Seq_in_index'); while Next do begin KeyType := UpperCase(String(GetString(ColumnIndexes[1]))); KeyType := Copy(KeyType, 1, 3); if KeyType = 'PRI' then begin Result.MoveToInsertRow; Result.UpdateString(1, LCatalog); Result.UpdateString(2, ''); Result.UpdateString(3, Table); Result.UpdateString(4, GetString(ColumnIndexes[2])); Result.UpdateString(5, GetString(ColumnIndexes[3])); Result.UpdateNull(6); Result.InsertRow; end; end; Close; end; end; {** Gets a description of the primary key columns that are referenced by a table's foreign key columns (the primary keys imported by a table). They are ordered by PKTABLE_CAT, PKTABLE_SCHEM, PKTABLE_NAME, and KEY_SEQ.

Each primary key column description has the following columns:

  1. PKTABLE_CAT String => primary key table catalog being imported (may be null)
  2. PKTABLE_SCHEM String => primary key table schema being imported (may be null)
  3. PKTABLE_NAME String => primary key table name being imported
  4. PKCOLUMN_NAME String => primary key column name being imported
  5. FKTABLE_CAT String => foreign key table catalog (may be null)
  6. FKTABLE_SCHEM String => foreign key table schema (may be null)
  7. FKTABLE_NAME String => foreign key table name
  8. FKCOLUMN_NAME String => foreign key column name
  9. KEY_SEQ short => sequence number within foreign key
  10. UPDATE_RULE short => What happens to foreign key when primary is updated:
    • importedNoAction - do not allow update of primary key if it has been imported
    • importedKeyCascade - change imported key to agree with primary key update
    • importedKeySetNull - change imported key to NULL if its primary key has been updated
    • importedKeySetDefault - change imported key to default values if its primary key has been updated
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
  11. DELETE_RULE short => What happens to the foreign key when primary is deleted.
    • importedKeyNoAction - do not allow delete of primary key if it has been imported
    • importedKeyCascade - delete rows that import a deleted key
    • importedKeySetNull - change imported key to NULL if its primary key has been deleted
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
    • importedKeySetDefault - change imported key to default if its primary key has been deleted
  12. FK_NAME String => foreign key name (may be null)
  13. PK_NAME String => primary key name (may be null)
  14. DEFERRABILITY short => can the evaluation of foreign key constraints be deferred until commit
    • importedKeyInitiallyDeferred - see SQL92 for definition
    • importedKeyInitiallyImmediate - see SQL92 for definition
    • importedKeyNotDeferrable - see SQL92 for definition
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a primary key column description @see #getExportedKeys } function TZMySQLDatabaseMetadata.UncachedGetImportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; var I: Integer; KeySeq: Integer; LCatalog, LTable: string; TableType, Comment, Keys: String; CommentList, KeyList: TStrings; ColumnIndexes : Array[1..2] of integer; begin if Table = '' then raise Exception.Create(STableIsNotSpecified); //CHANGE IT! Result := inherited UncachedGetImportedKeys(Catalog, Schema, Table); GetCatalogAndNamePattern(Catalog, Schema, Table, LCatalog, LTable); KeyList := TStringList.Create; CommentList := TStringList.Create; try with GetConnection.CreateStatement.ExecuteQuery( Format('SHOW TABLE STATUS FROM %s LIKE ''%s''', [IC.Quote(LCatalog), LTable])) do begin ColumnIndexes[1] := FindColumn('Type'); ColumnIndexes[2] := FindColumn('Comment'); while Next do begin TableType := GetString(ColumnIndexes[1]); if (TableType <> '') and (LowerCase(TableType) = 'innodb') then begin Comment := GetString(ColumnIndexes[2]); if Comment <> '' then begin PutSplitString(CommentList, Comment, ';'); KeySeq := 0; if CommentList.Count > 4 then begin for I := 0 to CommentList.Count - 1 do begin Keys := CommentList.Strings[1]; Result.MoveToInsertRow; PutSplitString(KeyList, Keys, '() /'); Result.UpdateString(1, KeyList.Strings[2]); // PKTABLE_CAT Result.UpdateNull(2); // PKTABLE_SCHEM Result.UpdateString(3, KeyList.Strings[3]); // PKTABLE_NAME Result.UpdateString(4, KeyList.Strings[4]); // PKCOLUMN_NAME Result.UpdateString(5, LCatalog); Result.UpdateNull(6);// FKTABLE_SCHEM Result.UpdateString(7, Table); // FKTABLE_NAME Result.UpdateString(8, KeyList.Strings[0]); // FKCOLUMN_NAME Result.UpdateInt(9, KeySeq); // KEY_SEQ Result.UpdateInt(10, Ord(ikSetDefault)); // UPDATE_RULE Result.UpdateInt(11, Ord(ikSetDefault)); // DELETE_RULE Result.UpdateNull(12); // FK_NAME Result.UpdateNull(13); // PK_NAME Result.UpdateInt(14, Ord(ikSetDefault)); // DEFERRABILITY Inc(KeySeq); Result.InsertRow; end; end; end; end; end; Close; end; finally KeyList.Free; CommentList.Free; end; end; {** Gets a description of the foreign key columns that reference a table's primary key columns (the foreign keys exported by a table). They are ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, and KEY_SEQ.

Each foreign key column description has the following columns:

  1. PKTABLE_CAT String => primary key table catalog (may be null)
  2. PKTABLE_SCHEM String => primary key table schema (may be null)
  3. PKTABLE_NAME String => primary key table name
  4. PKCOLUMN_NAME String => primary key column name
  5. FKTABLE_CAT String => foreign key table catalog (may be null) being exported (may be null)
  6. FKTABLE_SCHEM String => foreign key table schema (may be null) being exported (may be null)
  7. FKTABLE_NAME String => foreign key table name being exported
  8. FKCOLUMN_NAME String => foreign key column name being exported
  9. KEY_SEQ short => sequence number within foreign key
  10. UPDATE_RULE short => What happens to foreign key when primary is updated:
    • importedNoAction - do not allow update of primary key if it has been imported
    • importedKeyCascade - change imported key to agree with primary key update
    • importedKeySetNull - change imported key to NULL if its primary key has been updated
    • importedKeySetDefault - change imported key to default values if its primary key has been updated
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
  11. DELETE_RULE short => What happens to the foreign key when primary is deleted.
    • importedKeyNoAction - do not allow delete of primary key if it has been imported
    • importedKeyCascade - delete rows that import a deleted key
    • importedKeySetNull - change imported key to NULL if its primary key has been deleted
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
    • importedKeySetDefault - change imported key to default if its primary key has been deleted
  12. FK_NAME String => foreign key name (may be null)
  13. PK_NAME String => primary key name (may be null)
  14. DEFERRABILITY short => can the evaluation of foreign key constraints be deferred until commit
    • importedKeyInitiallyDeferred - see SQL92 for definition
    • importedKeyInitiallyImmediate - see SQL92 for definition
    • importedKeyNotDeferrable - see SQL92 for definition
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a foreign key column description @see #getImportedKeys } function TZMySQLDatabaseMetadata.UncachedGetExportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; var I: Integer; KeySeq: Integer; LCatalog, LTable: string; TableType, Comment, Keys: String; CommentList, KeyList: TStrings; ColumnIndexes : Array[1..3] of integer; begin if Table = '' then raise Exception.Create(STableIsNotSpecified); //CHANGE IT! Result:=inherited UncachedGetExportedKeys(Catalog, Schema, Table); GetCatalogAndNamePattern(Catalog, Schema, Table, LCatalog, LTable); KeyList := TStringList.Create; CommentList := TStringList.Create; try with GetConnection.CreateStatement.ExecuteQuery( Format('SHOW TABLE STATUS FROM %s', [IC.Quote(LCatalog)])) do begin ColumnIndexes[1] := FindColumn('Type'); ColumnIndexes[2] := FindColumn('Comment'); ColumnIndexes[3] := FindColumn('Name'); while Next do begin TableType := GetString(ColumnIndexes[1]); if (TableType <> '') and (LowerCase(TableType) = 'innodb') then begin Comment := GetString(ColumnIndexes[2]); if Comment <> '' then begin PutSplitString(CommentList, Comment, ';'); KeySeq := 0; if CommentList.Count > 4 then begin for I := 0 to CommentList.Count-1 do begin Keys := CommentList.Strings[1]; Result.MoveToInsertRow; PutSplitString(KeyList, Keys, '() /'); Result.UpdateString(5, LCatalog); Result.UpdateNull(6);// FKTABLE_SCHEM Result.UpdateString(7, GetString(ColumnIndexes[3])); // FKTABLE_NAME Result.UpdateString(8, KeyList.Strings[0]); // PKTABLE_CAT Result.UpdateString(1, KeyList.Strings[2]); // PKTABLE_CAT Result.UpdateNull(2); // PKTABLE_SCHEM Result.UpdateString(3, Table); // PKTABLE_NAME Result.UpdateInt(9, KeySeq); // KEY_SEQ Result.UpdateInt(10, Ord(ikSetDefault)); // UPDATE_RULE Result.UpdateInt(11, Ord(ikSetDefault)); // DELETE_RULE Result.UpdateNull(12); // FK_NAME Result.UpdateNull(13); // PK_NAME Result.UpdateInt(14, Ord(ikSetDefault)); // DEFERRABILITY Inc(KeySeq); Result.InsertRow; end; end; end; end; end; Close; end; finally KeyList.Free; CommentList.Free; end; end; {** Gets a description of the foreign key columns in the foreign key table that reference the primary key columns of the primary key table (describe how one table imports another's key.) This should normally return a single foreign key/primary key pair (most tables only import a foreign key from a table once.) They are ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, and KEY_SEQ.

Each foreign key column description has the following columns:

  1. PKTABLE_CAT String => primary key table catalog (may be null)
  2. PKTABLE_SCHEM String => primary key table schema (may be null)
  3. PKTABLE_NAME String => primary key table name
  4. PKCOLUMN_NAME String => primary key column name
  5. FKTABLE_CAT String => foreign key table catalog (may be null) being exported (may be null)
  6. FKTABLE_SCHEM String => foreign key table schema (may be null) being exported (may be null)
  7. FKTABLE_NAME String => foreign key table name being exported
  8. FKCOLUMN_NAME String => foreign key column name being exported
  9. KEY_SEQ short => sequence number within foreign key
  10. UPDATE_RULE short => What happens to foreign key when primary is updated:
    • importedNoAction - do not allow update of primary key if it has been imported
    • importedKeyCascade - change imported key to agree with primary key update
    • importedKeySetNull - change imported key to NULL if its primary key has been updated
    • importedKeySetDefault - change imported key to default values if its primary key has been updated
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
  11. DELETE_RULE short => What happens to the foreign key when primary is deleted.
    • importedKeyNoAction - do not allow delete of primary key if it has been imported
    • importedKeyCascade - delete rows that import a deleted key
    • importedKeySetNull - change imported key to NULL if its primary key has been deleted
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
    • importedKeySetDefault - change imported key to default if its primary key has been deleted
  12. FK_NAME String => foreign key name (may be null)
  13. PK_NAME String => primary key name (may be null)
  14. DEFERRABILITY short => can the evaluation of foreign key constraints be deferred until commit
    • importedKeyInitiallyDeferred - see SQL92 for definition
    • importedKeyInitiallyImmediate - see SQL92 for definition
    • importedKeyNotDeferrable - see SQL92 for definition
@param primaryCatalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param primarySchema a schema name; "" retrieves those without a schema @param primaryTable the table name that exports the key @param foreignCatalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param foreignSchema a schema name; "" retrieves those without a schema @param foreignTable the table name that imports the key @return ResultSet - each row is a foreign key column description @see #getImportedKeys } function TZMySQLDatabaseMetadata.UncachedGetCrossReference(const PrimaryCatalog: string; const PrimarySchema: string; const PrimaryTable: string; const ForeignCatalog: string; const ForeignSchema: string; const ForeignTable: string): IZResultSet; var I: Integer; KeySeq: Integer; LForeignCatalog: string; TableType, Comment, Keys: string; CommentList, KeyList: TStrings; ColumnIndexes : Array[1..3] of integer; begin if PrimaryTable = '' then raise Exception.Create(STableIsNotSpecified); //CHANGE IT! Result:=inherited UncachedGetCrossReference(PrimaryCatalog, PrimarySchema, PrimaryTable, ForeignCatalog, ForeignSchema, ForeignTable); if ForeignCatalog = '' then LForeignCatalog := FDatabase else LForeignCatalog := ForeignCatalog; KeyList := TStringList.Create; CommentList := TStringList.Create; try with GetConnection.CreateStatement.ExecuteQuery( Format('SHOW TABLE STATUS FROM %s', [IC.Quote(LForeignCatalog)])) do begin ColumnIndexes[1] := FindColumn('Type'); ColumnIndexes[2] := FindColumn('Comment'); ColumnIndexes[3] := FindColumn('Name'); while Next do begin TableType := GetString(ColumnIndexes[1]); if (TableType <> '') and (LowerCase(TableType) = 'innodb') then begin Comment := GetString(ColumnIndexes[2]); if Comment = '' then begin PutSplitString(CommentList, Comment, ';'); KeySeq := 0; if CommentList.Count > 4 then begin for I := 0 to CommentList.Count-1 do begin Keys := CommentList.Strings[1]; Result.MoveToInsertRow; PutSplitString(KeyList, Keys, '() /'); Result.UpdateString(5, LForeignCatalog); if ForeignSchema = '' then Result.UpdateNull(6) // FKTABLE_SCHEM else Result.UpdateString(6, ForeignSchema); if ForeignTable <> GetString(ColumnIndexes[3]) then Continue else Result.UpdateString(7, GetString(ColumnIndexes[3])); // FKTABLE_NAME Result.UpdateString(8, KeyList.Strings[0]); // PKTABLE_CAT Result.UpdateString(1, KeyList.Strings[2]); // PKTABLE_CAT if PrimarySchema = '' then Result.UpdateNull(2) // PKTABLE_SCHEM else Result.UpdateString(2, PrimarySchema); // PKTABLE_SCHEM if PrimaryTable = KeyList.Strings[3] then Continue; Result.UpdateString(3, PrimaryTable); // PKTABLE_NAME Result.UpdateString(4, KeyList.Strings[4]); // PKCOLUMN_NAME Result.UpdateInt(9, KeySeq); // KEY_SEQ Result.UpdateInt(10, Ord(ikSetDefault)); // UPDATE_RULE Result.UpdateInt(11, Ord(ikSetDefault)); // DELETE_RULE Result.UpdateNull(12); // FK_NAME Result.UpdateNull(13); // PK_NAME Result.UpdateInt(14, Ord(ikSetDefault)); // DEFERRABILITY Inc(KeySeq); Result.InsertRow; end; end; end; end; end; Close; end; finally KeyList.Free; CommentList.Free; end; end; {** Gets a description of all the standard SQL types supported by this database. They are ordered by DATA_TYPE and then by how closely the data type maps to the corresponding JDBC SQL type.

Each type description has the following columns:

  1. TYPE_NAME String => Type name
  2. DATA_TYPE short => SQL data type from java.sql.Types
  3. PRECISION int => maximum precision
  4. LITERAL_PREFIX String => prefix used to quote a literal (may be null)
  5. LITERAL_SUFFIX String => suffix used to quote a literal (may be null)
  6. CREATE_PARAMS String => parameters used in creating the type (may be null)
  7. NULLABLE short => can you use NULL for this type?
    • typeNoNulls - does not allow NULL values
    • typeNullable - allows NULL values
    • typeNullableUnknown - nullability unknown
  8. CASE_SENSITIVE boolean=> is it case sensitive?
  9. SEARCHABLE short => can you use "WHERE" based on this type:
    • typePredNone - No support
    • typePredChar - Only supported with WHERE .. LIKE
    • typePredBasic - Supported except for WHERE .. LIKE
    • typeSearchable - Supported for all WHERE ..
  10. UNSIGNED_ATTRIBUTE boolean => is it unsigned?
  11. FIXED_PREC_SCALE boolean => can it be a money value?
  12. AUTO_INCREMENT boolean => can it be used for an auto-increment value?
  13. LOCAL_TYPE_NAME String => localized version of type name (may be null)
  14. MINIMUM_SCALE short => minimum scale supported
  15. MAXIMUM_SCALE short => maximum scale supported
  16. SQL_DATA_TYPE int => unused
  17. SQL_DATETIME_SUB int => unused
  18. NUM_PREC_RADIX int => usually 2 or 10
@return ResultSet - each row is an SQL type description } function TZMySQLDatabaseMetadata.UncachedGetTypeInfo: IZResultSet; const MaxTypeCount = 33; TypeNames: array[1..MaxTypeCount] of string = ( 'BIT', 'BOOL', 'TINYINT', 'BIGINT', 'MEDIUMBLOB', 'LONG VARBINARY', 'LONGBLOB', 'BLOB', 'TINYBLOB', 'VARBINARY', 'BINARY', 'LONG VARCHAR', 'MEDIUMTEXT', 'LONGTEXT', 'TEXT', 'TINYTEXT', 'CHAR', 'VARCHAR', 'NUMERIC', 'DECIMAL', 'INTEGER', 'INT', 'MEDIUMINT', 'SMALLINT', 'DOUBLE', 'FLOAT', 'REAL', 'ENUM', 'SET', 'DATE', 'TIME', 'DATETIME', 'TIMESTAMP'); TypeCodes: array[1..MaxTypeCount] of TZSQLType = ( stByte, stBoolean, stShort, stLong, stBinaryStream, stBinaryStream, stBinaryStream, stBinaryStream, stBinaryStream, stBytes, stBytes, stString, stAsciiStream, stAsciiStream, stAsciiStream, stAsciiStream, stString, stString, stBigDecimal, stBigDecimal, stInteger, stInteger, stInteger, stShort, stDouble, stFloat, stFloat, stString, stString, stDate, stTime, stTimestamp, stTimestamp); TypePrecision: array[1..MaxTypeCount] of Integer = ( 1, -1, 4, 16, 16777215, 16777215, MAXBUF, 65535, 255, 255, 255, 16777215, 16777215, 2147483647, 65535, 255, 255, 255, 17, 17, 10, 10, 7, 4, 17, 10, 10, 65535, 64, -1, -1, -1, -1); var I: Integer; begin Result:=inherited UncachedGetTypeInfo; for I := 1 to MaxTypeCount do begin Result.MoveToInsertRow; Result.UpdateString(1, TypeNames[I]); Result.UpdateInt(2, Ord(TypeCodes[I])); if TypePrecision[I] >= 0 then Result.UpdateInt(3, TypePrecision[I]) else Result.UpdateNull(3); if TypeCodes[I] in [stString, stBytes, stDate, stTime, stTimeStamp, stBinaryStream, stAsciiStream] then begin Result.UpdateString(4, ''''); Result.UpdateString(5, ''''); end else begin Result.UpdateNull(4); Result.UpdateNull(5); end; Result.UpdateNull(6); Result.UpdateInt(7, Ord(ntNullable)); Result.UpdateBoolean(8, False); Result.UpdateBoolean(9, False); Result.UpdateBoolean(11, False); Result.UpdateBoolean(12, False); Result.UpdateBoolean(12, TypeNames[I] = 'INTEGER'); Result.UpdateNull(13); Result.UpdateNull(14); Result.UpdateNull(15); Result.UpdateNull(16); Result.UpdateNull(17); Result.UpdateInt(18, 10); Result.InsertRow; end; end; {** Gets a description of a table's indices and statistics. They are ordered by NON_UNIQUE, TYPE, INDEX_NAME, and ORDINAL_POSITION.

Each index column description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. NON_UNIQUE boolean => Can index values be non-unique? false when TYPE is tableIndexStatistic
  5. INDEX_QUALIFIER String => index catalog (may be null); null when TYPE is tableIndexStatistic
  6. INDEX_NAME String => index name; null when TYPE is tableIndexStatistic
  7. TYPE short => index type:
    • tableIndexStatistic - this identifies table statistics that are returned in conjuction with a table's index descriptions
    • tableIndexClustered - this is a clustered index
    • tableIndexHashed - this is a hashed index
    • tableIndexOther - this is some other style of index
  8. ORDINAL_POSITION short => column sequence number within index; zero when TYPE is tableIndexStatistic
  9. COLUMN_NAME String => column name; null when TYPE is tableIndexStatistic
  10. ASC_OR_DESC String => column sort sequence, "A" => ascending, "D" => descending, may be null if sort sequence is not supported; null when TYPE is tableIndexStatistic
  11. CARDINALITY int => When TYPE is tableIndexStatistic, then this is the number of rows in the table; otherwise, it is the number of unique values in the index.
  12. PAGES int => When TYPE is tableIndexStatisic then this is the number of pages used for the table, otherwise it is the number of pages used for the current index.
  13. FILTER_CONDITION String => Filter condition, if any. (may be null)
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @param unique when true, return only indices for unique values; when false, return indices regardless of whether unique or not @param approximate when true, result is allowed to reflect approximate or out of data values; when false, results are requested to be accurate @return ResultSet - each row is an index column description } function TZMySQLDatabaseMetadata.UncachedGetIndexInfo(const Catalog: string; const Schema: string; const Table: string; Unique: Boolean; Approximate: Boolean): IZResultSet; var LCatalog, LTable: string; ColumnIndexes : Array[1..7] of integer; begin if Table = '' then raise Exception.Create(STableIsNotSpecified); //CHANGE IT! Result:=inherited UncachedGetIndexInfo(Catalog, Schema, Table, Unique, Approximate); GetCatalogAndNamePattern(Catalog, Schema, Table, LCatalog, LTable); with GetConnection.CreateStatement.ExecuteQuery( Format('SHOW INDEX FROM %s.%s', [IC.Quote(LCatalog), IC.Quote(LTable)])) do begin ColumnIndexes[1] := FindColumn('Table'); ColumnIndexes[2] := FindColumn('Non_unique'); ColumnIndexes[3] := FindColumn('Key_name'); ColumnIndexes[4] := FindColumn('Seq_in_index'); ColumnIndexes[5] := FindColumn('Column_name'); ColumnIndexes[6] := FindColumn('Collation'); ColumnIndexes[7] := FindColumn('Cardinality'); while Next do begin Result.MoveToInsertRow; Result.UpdateString(1, LCatalog); Result.UpdateNull(2); Result.UpdateString(3, GetString(ColumnIndexes[1])); if GetInt(ColumnIndexes[2]) = 0 then Result.UpdateString(4, 'true') else Result.UpdateString(4, 'false'); Result.UpdateNull(5); Result.UpdateString(6, GetString(ColumnIndexes[3])); Result.UpdateInt(7, Ord(tiOther)); Result.UpdateInt(8, GetInt(ColumnIndexes[4])); Result.UpdateString(9, GetString(ColumnIndexes[5])); Result.UpdateString(10, GetString(ColumnIndexes[6])); Result.UpdateString(11, GetString(ColumnIndexes[7])); Result.UpdateInt(12, 0); Result.UpdateNull(13); Result.InsertRow; end; Close; end; end; {** Gets a description of the stored procedures available in a catalog.

Only procedure descriptions matching the schema and procedure name criteria are returned. They are ordered by PROCEDURE_SCHEM, and PROCEDURE_NAME.

Each procedure description has the the following columns:

  1. PROCEDURE_CAT String => procedure catalog (may be null)
  2. PROCEDURE_SCHEM String => procedure schema (may be null)
  3. PROCEDURE_NAME String => procedure name
  4. reserved for future use
  5. reserved for future use
  6. reserved for future use
  7. REMARKS String => explanatory comment on the procedure
  8. PROCEDURE_TYPE short => kind of procedure:
    • procedureResultUnknown - May return a result
    • procedureNoResult - Does not return a result
    • procedureReturnsResult - Returns a result
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param procedureNamePattern a procedure name pattern @return ResultSet - each row is a procedure description @see #getSearchStringEscape } function TZMySQLDatabaseMetadata.UncachedGetProcedures(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string): IZResultSet; var SQL: string; ProcedureNameCondition, SchemaCondition: string; begin If Catalog = '' then If SchemaPattern <> '' then SchemaCondition := ConstructNameCondition(SchemaPattern,'p.db') else SchemaCondition := ConstructNameCondition(FDatabase,'p.db') else SchemaCondition := ConstructNameCondition(Catalog,'p.db'); ProcedureNameCondition := ConstructNameCondition(ProcedureNamePattern,'p.name'); If SchemaCondition <> '' then SchemaCondition := ' and ' + SchemaCondition; If ProcedureNameCondition <> '' then ProcedureNameCondition := ' and ' + ProcedureNameCondition; SQL := 'SELECT NULL AS PROCEDURE_CAT, p.db AS PROCEDURE_SCHEM, '+ 'p.name AS PROCEDURE_NAME, NULL AS RESERVED1, NULL AS RESERVED2, '+ 'NULL AS RESERVED3, p.comment AS REMARKS, '+ IntToStr(ProcedureReturnsResult)+' AS PROCEDURE_TYPE from mysql.proc p '+ 'WHERE 1=1' + SchemaCondition + ProcedureNameCondition+ ' ORDER BY p.db, p.name'; Result := CopyToVirtualResultSet( GetConnection.CreateStatement.ExecuteQuery(SQL), ConstructVirtualResultSet(ProceduresColumnsDynArray)); end; {** Gets a description of a catalog's stored procedure parameters and result columns.

Only descriptions matching the schema, procedure and parameter name criteria are returned. They are ordered by PROCEDURE_SCHEM and PROCEDURE_NAME. Within this, the return value, if any, is first. Next are the parameter descriptions in call order. The column descriptions follow in column number order.

Each row in the ResultSet is a parameter description or column description with the following fields:

  1. PROCEDURE_CAT String => procedure catalog (may be null)
  2. PROCEDURE_SCHEM String => procedure schema (may be null)
  3. PROCEDURE_NAME String => procedure name
  4. COLUMN_NAME String => column/parameter name
  5. COLUMN_TYPE Short => kind of column/parameter:
    • procedureColumnUnknown - nobody knows
    • procedureColumnIn - IN parameter
    • procedureColumnInOut - INOUT parameter
    • procedureColumnOut - OUT parameter
    • procedureColumnReturn - procedure return value
    • procedureColumnResult - result column in ResultSet
  6. DATA_TYPE short => SQL type from java.sql.Types
  7. TYPE_NAME String => SQL type name, for a UDT type the type name is fully qualified
  8. PRECISION int => precision
  9. LENGTH int => length in bytes of data
  10. SCALE short => scale
  11. RADIX short => radix
  12. NULLABLE short => can it contain NULL?
    • procedureNoNulls - does not allow NULL values
    • procedureNullable - allows NULL values
    • procedureNullableUnknown - nullability unknown
  13. REMARKS String => comment describing parameter/column

Note: Some databases may not return the column descriptions for a procedure. Additional columns beyond REMARKS can be defined by the database. @param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param procedureNamePattern a procedure name pattern @param columnNamePattern a column name pattern @return ResultSet - each row describes a stored procedure parameter or column @see #getSearchStringEscape } function TZMySQLDatabaseMetadata.UncachedGetProcedureColumns(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string; const ColumnNamePattern: string): IZResultSet; var SQL, TypeName, Temp: string; ParamList, Params, Names, Returns: TStrings; I, ColumnSize, Precision: Integer; FieldType: TZSQLType; ProcedureNameCondition, SchemaCondition: string; function GetNextName(const AName: String; NameEmpty: Boolean = False): String; var N: Integer; begin if (Names.IndexOf(AName) = -1) and not NameEmpty then begin Names.Add(AName); Result := AName; end else for N := 1 to MaxInt do if Names.IndexOf(AName+IntToStr(N)) = -1 then begin Names.Add(AName+IntToStr(N)); Result := AName+IntToStr(N); Break; end; end; function DecomposeParamFromList(AList: TStrings): String; var J, I, N: Integer; Temp: String; procedure AddTempString(Const Value: String); begin if Temp = '' then Temp := Trim(Value) else Temp := Temp + LineEnding+ Trim(Value); end; begin J := 0; Temp := ''; for I := 0 to AList.Count -1 do if J < AList.Count then begin if (Pos('(', (AList[J])) > 0) and (Pos(')', (AList[J])) = 0) then if ( Pos('real', LowerCase(AList[J])) > 0 ) or ( Pos('float', LowerCase(AList[J])) > 0 ) or ( Pos('decimal', LowerCase(AList[J])) > 0 ) or ( Pos('numeric', LowerCase(AList[J])) > 0 ) or ( Pos('double', LowerCase(AList[J])) > 0 ) then begin AddTempString(AList[j]+','+AList[j+1]); Inc(j); end else if ( Pos('set', LowerCase(AList[J])) > 0 ) and ( Pos(')', LowerCase(AList[J])) = 0 ) then begin TypeName := AList[J]; for N := J+1 to AList.Count-1 do begin TypeName := TypeName +','+AList[N]; if Pos(')', AList[N]) > 0 then Break; end; AddTempString(TypeName); J := N; end else AddTempString(AList[j]) else if not (AList[j] = '') then AddTempString(AList[j]); Inc(J); end; Result := Temp; end; begin If Catalog = '' then If SchemaPattern <> '' then SchemaCondition := ConstructNameCondition(SchemaPattern,'p.db') else SchemaCondition := ConstructNameCondition(FDatabase,'p.db') else SchemaCondition := ConstructNameCondition(Catalog,'p.db'); ProcedureNameCondition := ConstructNameCondition(ProcedureNamePattern,'p.name'); If SchemaCondition <> '' then SchemaCondition := ' and ' + SchemaCondition; If ProcedureNameCondition <> '' then ProcedureNameCondition := ' and ' + ProcedureNameCondition; Result := inherited UncachedGetProcedureColumns(Catalog, SchemaPattern, ProcedureNamePattern, ColumnNamePattern); SQL := 'SELECT p.db AS PROCEDURE_CAT, NULL AS PROCEDURE_SCHEM, '+ 'p.name AS PROCEDURE_NAME, p.param_list AS PARAMS, p.comment AS REMARKS, '+ IntToStr(ProcedureReturnsResult)+' AS PROCEDURE_TYPE, p.returns AS RETURN_VALUES '+ ' from mysql.proc p where 1 = 1'+SchemaCondition+ProcedureNameCondition+ ' ORDER BY p.db, p.name'; try with GetConnection.CreateStatement.ExecuteQuery(SQL) do begin ParamList := TStringList.Create; Params := TStringList.Create; Names := TStringList.Create; Returns := TStringList.Create; while Next do begin PutSplitString(ParamList, Trim(GetString(4)), ','); PutSplitString(ParamList, DecomposeParamFromList(ParamList), LineEnding); PutSplitString(Returns, Trim(GetString(7)), ','); PutSplitString(Returns, DecomposeParamFromList(Returns), LineEnding); for I := 0 to Returns.Count-1 do begin Returns[i] := 'RETURNS '+Returns[i]; ParamList.Add(Returns[i]); end; for i := 0 to ParamList.Count -1 do begin PutSplitString(Params, ParamList[i], ' '); if Params.Count = 2 then {no name available} if Params[0] = 'RETURNS' then Params.Insert(1,'') else if (UpperCase(Params[1]) = 'IN') or (UpperCase(Params[1]) = 'INOUT') or (UpperCase(Params[1]) = 'OUT') then Params.Insert(1,'') else Params.Insert(0,'IN'); //Function in value Result.MoveToInsertRow; Result.UpdateString(1, GetString(1)); //PROCEDURE_CAT Result.UpdateString(2, GetString(2)); //PROCEDURE_SCHEM Result.UpdateString(3, GetString(3)); //PROCEDURE_NAME ConvertMySQLColumnInfoFromString(Params[2], ConSettings, TypeName, Temp, FieldType, ColumnSize, Precision); { process COLUMN_NAME } if Params[1] = '' then if Params[0] = 'RETURNS' then Result.UpdateString(4, 'ReturnValue') else Result.UpdateString(4, GetNextName('$', True)) else if IC.IsQuoted(Params[1]) then Result.UpdateString(4, GetNextName(Copy(Params[1], 2, Length(Params[1])-2), (Length(Params[1])=2))) else Result.UpdateString(4, GetNextName(Params[1])); { COLUMN_TYPE } if UpperCase(Params[0]) = 'OUT' then Result.UpdateInt(5, Ord(pctOut)) else if UpperCase(Params[0]) = 'INOUT' then Result.UpdateInt(5, Ord(pctInOut)) else if UpperCase(Params[0]) = 'IN' then Result.UpdateInt(5, Ord(pctIn)) else if UpperCase(Params[0]) = 'RETURNS' then Result.UpdateInt(5, Ord(pctReturn)) else Result.UpdateInt(5, Ord(pctUnknown)); { DATA_TYPE } Result.UpdateInt(6, Ord(FieldType)); { TYPE_NAME } Result.UpdateString(7, TypeName); { PRECISION } Result.UpdateInt(8, ColumnSize); { LENGTH } Result.UpdateInt(9, Precision); Result.UpdateNull(10); Result.UpdateNull(11); Result.UpdateInt(12, Ord(ntNullableUnknown)); Result.UpdateNull(13); Result.InsertRow; end; end; Close; end; finally FreeAndNil(Names); FreeAndNil(Params); FreeAndNil(ParamList); FreeAndNil(Returns); end; end; {** Gets a description of a table's columns that are automatically updated when any value in a row is updated. They are unordered.

Each column description has the following columns:

  1. SCOPE short => is not used
  2. COLUMN_NAME String => column name
  3. DATA_TYPE short => SQL data type from java.sql.Types
  4. TYPE_NAME String => Data source dependent type name
  5. COLUMN_SIZE int => precision
  6. BUFFER_LENGTH int => length of column value in bytes
  7. DECIMAL_DIGITS short => scale
  8. PSEUDO_COLUMN short => is this a pseudo column like an Oracle ROWID
    • versionColumnUnknown - may or may not be pseudo column
    • versionColumnNotPseudo - is NOT a pseudo column
    • versionColumnPseudo - is a pseudo column
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a column description @exception SQLException if a database access error occurs } function TZMySQLDatabaseMetadata.UncachedGetVersionColumns(const Catalog, Schema, Table: string): IZResultSet; begin Result:=inherited UncachedGetVersionColumns(Catalog, Schema, Table); Result.MoveToInsertRow; Result.UpdateNull(1); Result.UpdateString(2, 'ctid'); // Result.UpdateInt(3, GetSQLType('tid')); //FIX IT Result.UpdateString(4, 'tid'); Result.UpdateNull(5); Result.UpdateNull(6); Result.UpdateNull(7); Result.UpdateInt(4, Ord(vcPseudo)); Result.InsertRow; end; {** Gets the used Collation and CharacterSet of spezified Object. @param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" and Catolog "" retrieves nothing @param table a table name; "" retrieves the Schema Colloation and CharacterSet @param ColumnNamePattern ColumnPattern;"" retrieves the Table(if @param TablePattern is set) or Schema(if @param TablePattern is NULL) Colloation and CharacterSet @return ResultSet - each row is a Collation, CharacterSet, ID, and ByteLength per Char of speziefied Object } function TZMySQLDatabaseMetadata.UncachedGetCollationAndCharSet(const Catalog, SchemaPattern, TableNamePattern, ColumnNamePattern: string): IZResultSet; //EgonHugeist var SQL, LCatalog: string; ColumnNameCondition, TableNameCondition, SchemaCondition: string; begin if Catalog = '' then begin if SchemaPattern <> '' then LCatalog := SchemaPattern else LCatalog := FDatabase; end else LCatalog := Catalog; If Catalog = '' then If SchemaPattern <> '' then SchemaCondition := ConstructNameCondition(SchemaPattern,'TABLE_SCHEMA') else SchemaCondition := ConstructNameCondition(FDatabase,'TABLE_SCHEMA') else SchemaCondition := ConstructNameCondition(Catalog,'TABLE_SCHEMA'); TableNameCondition := ConstructNameCondition(TableNamePattern,'TABLE_NAME'); ColumnNameCondition := ConstructNameCondition(ColumnNamePattern,'COLUMN_NAME'); If SchemaCondition <> '' then SchemaCondition := ' and ' + SchemaCondition; If TableNameCondition <> '' then TableNameCondition := ' and ' + TableNameCondition; If ColumnNameCondition <> '' then ColumnNameCondition := ' and ' + ColumnNameCondition; Result:=inherited UncachedGetCollationAndCharSet(Catalog, SchemaPattern, TableNamePattern, ColumnNamePattern); if SchemaCondition <> '' then begin if TableNamePattern <> '' then begin if ColumnNamePattern <> '' then begin SQL := 'SELECT CLMS.COLLATION_NAME, CLMS.CHARACTER_SET_NAME, CS.MAXLEN '+ 'FROM INFORMATION_SCHEMA.COLUMNS CLMS '+ 'LEFT JOIN INFORMATION_SCHEMA.CHARACTER_SETS CS '+ 'ON CS.DEFAULT_COLLATE_NAME = CLMS.COLLATION_NAME '+ 'WHERE 1=1'+ SchemaCondition + TableNameCondition + ColumnNameCondition; with GetConnection.CreateStatement.ExecuteQuery(SQL) do begin if Next then begin Result.MoveToInsertRow; Result.UpdateString(1, LCatalog); //COLLATION_CATALOG Result.UpdateString(2, LCatalog); //COLLATION_SCHEMA Result.UpdateString(3, TableNamePattern); //COLLATION_TABLE Result.UpdateString(4, ColumnNamePattern);//COLLATION_COLUMN Result.UpdateString(5, GetString(FindColumn('COLLATION_NAME'))); //COLLATION_NAME Result.UpdateString(6, GetString(FindColumn('CHARACTER_SET_NAME'))); //CHARACTER_SET_NAME Result.UpdateNull(7); //CHARACTER_SET_ID Result.UpdateShort(8, GetShort(FindColumn('MAXLEN'))); //CHARACTER_SET_SIZE Result.InsertRow; end; Close; end; end else begin SQL := 'SELECT TBLS.TABLE_COLLATION, CS.CHARACTER_SET_NAME, CS.MAXLEN '+ 'FROM INFORMATION_SCHEMA.TABLES TBLS LEFT JOIN '+ 'INFORMATION_SCHEMA.CHARACTER_SETS CS ON '+ 'TBLS.TABLE_COLLATION = CS.DEFAULT_COLLATE_NAME '+ 'WHERE 1=1'+ SchemaCondition + TableNameCondition; with GetConnection.CreateStatement.ExecuteQuery(SQL) do begin if Next then begin Result.MoveToInsertRow; Result.UpdateString(1, LCatalog); //COLLATION_CATALOG Result.UpdateString(2, LCatalog); //COLLATION_SCHEMA Result.UpdateString(3, TableNamePattern); //COLLATION_TABLE Result.UpdateString(5, GetString(FindColumn('TABLE_COLLATION'))); //COLLATION_NAME Result.UpdateString(6, GetString(FindColumn('CHARACTER_SET_NAME'))); //CHARACTER_SET_NAME Result.UpdateNull(7); //CHARACTER_SET_ID Result.UpdateShort(8, GetShort(FindColumn('MAXLEN'))); //CHARACTER_SET_SIZE Result.InsertRow; end; Close; end; end; end else begin SchemaCondition := ConstructNameCondition(LCatalog, 'and SCHEMA_NAME'); SQL := 'SELECT S.DEFAULT_COLLATION_NAME, S.DEFAULT_CHARACTER_SET_NAME, '+ 'CS.MAXLEN FROM INFORMATION_SCHEMA.SCHEMATA S '+ 'LEFT JOIN INFORMATION_SCHEMA.CHARACTER_SETS CS '+ 'ON CS.DEFAULT_COLLATE_NAME = S.DEFAULT_COLLATION_NAME '+ 'WHERE 1=1 '+ SchemaCondition; with GetConnection.CreateStatement.ExecuteQuery(SQL) do begin if Next then begin Result.MoveToInsertRow; Result.UpdateString(1, LCatalog); //COLLATION_CATALOG Result.UpdateString(2, LCatalog); //COLLATION_SCHEMA Result.UpdateNull(3); //COLLATION_TABLE Result.UpdateNull(4);//COLLATION_COLUMN Result.UpdateString(5, GetString(FindColumn('DEFAULT_COLLATION_NAME'))); //COLLATION_NAME Result.UpdateString(6, GetString(FindColumn('DEFAULT_CHARACTER_SET_NAME'))); //CHARACTER_SET_NAME Result.UpdateNull(7); //CHARACTER_SET_ID Result.UpdateShort(8, GetShort(FindColumn('MAXLEN'))); //CHARACTER_SET_SIZE Result.InsertRow; end; Close; end; end; end; end; {** Gets the supported CharacterSets: @return ResultSet - each row is a CharacterSetName and it's ID } function TZMySQLDatabaseMetadata.UncachedGetCharacterSets: IZResultSet; //EgonHugeist begin Result:=inherited UncachedGetCharacterSets; with GetConnection.CreateStatement.ExecuteQuery( 'SELECT CHARACTER_SET_NAME '+ 'FROM INFORMATION_SCHEMA.CHARACTER_SETS') do begin while Next do begin Result.MoveToInsertRow; Result.UpdateString(1, GetString(FindColumn('CHARACTER_SET_NAME'))); //CHARACTER_SET_NAME Result.UpdateNull(2); //CHARACTER_SET_ID Result.InsertRow; end; Close; end; end; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcMySqlResultSet.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { MySQL Database Connectivity Classes } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcMySqlResultSet; interface {$I ZDbc.inc} uses Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, Types, Contnrs, ZDbcIntfs, ZDbcResultSet, ZDbcResultSetMetadata, ZCompatibility, ZDbcCache, ZDbcCachedResultSet, ZDbcGenericResolver, ZDbcMySqlStatement, ZPlainMySqlDriver, ZPlainMySqlConstants; type {** Implements MySQL ResultSet Metadata. } TZMySQLResultSetMetadata = class(TZAbstractResultSetMetadata) public function GetColumnType(Column: Integer): TZSQLType; override; end; {** Implements MySQL ResultSet. } TZMySQLResultSet = class(TZAbstractResultSet) private FHandle: PZMySQLConnect; FQueryHandle: PZMySQLResult; FRowHandle: PZMySQLRow; FPlainDriver: IZMySQLPlainDriver; FUseResult: Boolean; FIgnoreUseResult: Boolean; TempStr: String; protected procedure Open; override; function InternalGetString(ColumnIndex: Integer): RawByteString; override; public constructor Create(PlainDriver: IZMySQLPlainDriver; Statement: IZStatement; SQL: string; Handle: PZMySQLConnect; UseResult: Boolean; AffectedRows: PInteger; IgnoreUseResult: Boolean = False); destructor Destroy; override; procedure Close; override; function IsNull(ColumnIndex: Integer): Boolean; override; function GetPChar(ColumnIndex: Integer): PChar; override; function GetBoolean(ColumnIndex: Integer): Boolean; override; function GetByte(ColumnIndex: Integer): Byte; override; function GetShort(ColumnIndex: Integer): SmallInt; override; function GetInt(ColumnIndex: Integer): Integer; override; function GetLong(ColumnIndex: Integer): Int64; override; function GetFloat(ColumnIndex: Integer): Single; override; function GetDouble(ColumnIndex: Integer): Double; override; function GetBigDecimal(ColumnIndex: Integer): Extended; override; function GetBytes(ColumnIndex: Integer): TByteDynArray; override; function GetDate(ColumnIndex: Integer): TDateTime; override; function GetTime(ColumnIndex: Integer): TDateTime; override; function GetTimestamp(ColumnIndex: Integer): TDateTime; override; function GetBlob(ColumnIndex: Integer): IZBlob; override; function MoveAbsolute(Row: Integer): Boolean; override; function Next: Boolean; override; procedure ReleaseHandle; end; {** Implements Prepared MySQL ResultSet. } TZMySQLPreparedResultSet = class(TZAbstractResultSet) private FHandle: PZMySQLConnect; FPrepStmt: PZMySqlPrepStmt; FResultMetaData : PZMySQLResult; FPlainDriver: IZMySQLPlainDriver; FUseResult: Boolean; FColumnArray: TZMysqlColumnBuffer; FBindBuffer: TZMySqlResultSetBindBuffer; function bufferasint64(ColumnIndex: Integer): Int64; function bufferasextended(ColumnIndex: Integer): Extended; protected function InternalGetString(ColumnIndex: Integer): RawByteString; override; procedure Open; override; public constructor Create(PlainDriver: IZMySQLPlainDriver; Statement: IZStatement; SQL: string; Handle: PZMySQLConnect; UseResult: Boolean); destructor Destroy; override; procedure Close; override; function IsNull(ColumnIndex: Integer): Boolean; override; function GetBoolean(ColumnIndex: Integer): Boolean; override; function GetByte(ColumnIndex: Integer): Byte; override; function GetShort(ColumnIndex: Integer): SmallInt; override; function GetInt(ColumnIndex: Integer): Integer; override; function GetLong(ColumnIndex: Integer): Int64; override; function GetFloat(ColumnIndex: Integer): Single; override; function GetDouble(ColumnIndex: Integer): Double; override; function GetBigDecimal(ColumnIndex: Integer): Extended; override; function GetBytes(ColumnIndex: Integer): TByteDynArray; override; function GetDate(ColumnIndex: Integer): TDateTime; override; function GetTime(ColumnIndex: Integer): TDateTime; override; function GetTimestamp(ColumnIndex: Integer): TDateTime; override; function GetAsciiStream(ColumnIndex: Integer): TStream; override; function GetUnicodeStream(ColumnIndex: Integer): TStream; override; function GetBinaryStream(ColumnIndex: Integer): TStream; override; function GetBlob(ColumnIndex: Integer): IZBlob; override; function MoveAbsolute(Row: Integer): Boolean; override; function Next: Boolean; override; end; {** Implements a cached resolver with MySQL specific functionality. } TZMySQLCachedResolver = class (TZGenericCachedResolver, IZCachedResolver) private FHandle: PZMySQLConnect; FPlainDriver: IZMySQLPlainDriver; FAutoColumnIndex: Integer; FStatement: IZMysqlStatement; public constructor Create(PlainDriver: IZMySQLPlainDriver; Handle: PZMySQLConnect; Statement: IZMysqlStatement; Metadata: IZResultSetMetadata); function FormWhereClause(Columns: TObjectList; OldRowAccessor: TZRowAccessor): string; override; procedure PostUpdates(Sender: IZCachedResultSet; UpdateType: TZRowUpdateType; OldRowAccessor, NewRowAccessor: TZRowAccessor); override; // --> ms, 31/10/2005 function FormCalculateStatement(Columns: TObjectList): string; override; // <-- ms {BEGIN of PATCH [1185969]: Do tasks after posting updates. ie: Updating AutoInc fields in MySQL } procedure UpdateAutoIncrementFields(Sender: IZCachedResultSet; UpdateType: TZRowUpdateType; OldRowAccessor, NewRowAccessor: TZRowAccessor; Resolver: IZCachedResolver); override; {END of PATCH [1185969]: Do tasks after posting updates. ie: Updating AutoInc fields in MySQL } end; implementation uses Math, ZMessages, ZDbcMySqlUtils, ZMatchPattern, ZDbcMysql, ZEncoding, ZSysUtils; { TZMySQLResultSetMetadata } {** Retrieves the designated column's SQL type. @param column the first column is 1, the second is 2, ... @return SQL type from java.sql.Types } function TZMySQLResultSetMetadata.GetColumnType(Column: Integer): TZSQLType; begin if not Loaded then LoadColumns; Result := TZColumnInfo(ResultSet.ColumnsInfo[Column - 1]).ColumnType; end; { TZMySQLResultSet } {** Constructs this object, assignes main properties and opens the record set. @param PlainDriver a native MySQL plain driver. @param Statement a related SQL statement object. @param Handle a MySQL specific query handle. @param UseResult True to use results, False to store result. } constructor TZMySQLResultSet.Create(PlainDriver: IZMySQLPlainDriver; Statement: IZStatement; SQL: string; Handle: PZMySQLConnect; UseResult: Boolean; AffectedRows: PInteger; IgnoreUseResult: Boolean = False); begin inherited Create(Statement, SQL, TZMySQLResultSetMetadata.Create( Statement.GetConnection.GetMetadata, SQL, Self), Statement.GetConnection.GetConSettings); FHandle := Handle; FQueryHandle := nil; FRowHandle := nil; FPlainDriver := PlainDriver; ResultSetConcurrency := rcReadOnly; FUseResult := UseResult; FIgnoreUseResult := IgnoreUseResult; Open; if Assigned(AffectedRows) then AffectedRows^ := LastRowNo; end; {** Destroys this object and cleanups the memory. } destructor TZMySQLResultSet.Destroy; begin inherited Destroy; end; {** Opens this recordset. } procedure TZMySQLResultSet.Open; var I: Integer; FieldHandle: PZMySQLField; begin if ResultSetConcurrency = rcUpdatable then raise EZSQLException.Create(SLiveResultSetsAreNotSupported); if FUseResult and (not FIgnoreUseResult) then begin FQueryHandle := FPlainDriver.UseResult(FHandle); LastRowNo := 0; end else begin FQueryHandle := FPlainDriver.StoreResult(FHandle); if Assigned(FQueryHandle) then LastRowNo := FPlainDriver.GetRowCount(FQueryHandle) else LastRowNo := 0; end; if not Assigned(FQueryHandle) then raise EZSQLException.Create(SCanNotRetrieveResultSetData); { Fills the column info. } ColumnsInfo.Clear; for I := 0 to FPlainDriver.GetFieldCount(FQueryHandle) - 1 do begin FPlainDriver.SeekField(FQueryHandle, I); FieldHandle := FPlainDriver.FetchField(FQueryHandle); if FieldHandle = nil then Break; ColumnsInfo.Add(GetMySQLColumnInfoFromFieldHandle(FPlainDriver, FieldHandle, ConSettings, FUseResult)); end; inherited Open; end; {** Releases this ResultSet object's database and JDBC resources immediately instead of waiting for this to happen when it is automatically closed.

Note: A ResultSet object is automatically closed by the Statement object that generated it when that Statement object is closed, re-executed, or is used to retrieve the next result from a sequence of multiple results. A ResultSet object is also automatically closed when it is garbage collected. } procedure TZMySQLResultSet.Close; begin if FQueryHandle <> nil then begin FPlainDriver.FreeResult(FQueryHandle); while(FPlainDriver.RetrieveNextRowset(FHandle) = 0) do begin FQueryHandle := FPlainDriver.StoreResult(FHandle); if FQueryHandle <> nil then begin FPlainDriver.FreeResult(FQueryHandle); end; end; end; FQueryHandle := nil; FRowHandle := nil; inherited Close; end; {** Indicates if the value of the designated column in the current row of this ResultSet object is Null. @param columnIndex the first column is 1, the second is 2, ... @return if the value is SQL NULL, the value returned is true. false otherwise. } function TZMySQLResultSet.IsNull(ColumnIndex: Integer): Boolean; var Temp: PAnsiChar; begin {$IFNDEF DISABLE_CHECKING} CheckClosed; if FRowHandle = nil then raise EZSQLException.Create(SRowDataIsNotAvailable); {$ENDIF} Temp := FPlainDriver.GetFieldData(FRowHandle, ColumnIndex - 1); Result := (Temp = nil); if not Result and (TZAbstractResultSetMetadata(Metadata). GetColumnType(ColumnIndex) in [stDate, stTimestamp]) then begin Result := (AnsiSQLDateToDateTime(String(Temp)) = 0) and (TimestampStrToDateTime(String(Temp)) = 0); end; end; {** Gets the value of the designated column in the current row of this ResultSet object as a PAnsiChar in the Delphi programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZMySQLResultSet.GetPChar(ColumnIndex: Integer): PChar; begin {$IFNDEF DISABLE_CHECKING} CheckClosed; if FRowHandle = nil then raise EZSQLException.Create(SRowDataIsNotAvailable); {$ENDIF} TempStr := ZDbcString(FPlainDriver.GetFieldData(FRowHandle, ColumnIndex - 1)); Result := PChar(TempStr); LastWasNull := Result = nil; end; {** Gets the value of the designated column in the current row of this ResultSet object as a String. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZMySQLResultSet.InternalGetString(ColumnIndex: Integer): RawByteString; var LengthPointer: PULong; Length: ULong; Buffer: PAnsiChar; begin {$IFNDEF DISABLE_CHECKING} CheckClosed; if FRowHandle = nil then raise EZSQLException.Create(SRowDataIsNotAvailable); {$ENDIF} ColumnIndex := ColumnIndex - 1; LengthPointer := FPlainDriver.FetchLengths(FQueryHandle); if LengthPointer <> nil then Length := PULong(NativeUint(LengthPointer) + NativeUInt(ColumnIndex) * SizeOf(ULOng))^ else Length := 0; Buffer := FPlainDriver.GetFieldData(FRowHandle, ColumnIndex); LastWasNull := Buffer = nil; Result := ''; if not LastWasNull then {$IFDEF WITH_RAWBYTESTRING} begin SetLength(Result, Length); Move(Buffer^, PAnsiChar(Result)^, Length); end; {$ELSE} SetString(Result, Buffer, Length); {$ENDIF} end; {** Gets the value of the designated column in the current row of this ResultSet object as a boolean in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is false } function TZMySQLResultSet.GetBoolean(ColumnIndex: Integer): Boolean; var Temp: string; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stBoolean); {$ENDIF} Temp := UpperCase(String(InternalGetString(ColumnIndex))); Result := (Temp = 'Y') or (Temp = 'YES') or (Temp = 'T') or (Temp = 'TRUE') or (StrToIntDef(Temp, 0) <> 0); end; {** Gets the value of the designated column in the current row of this ResultSet object as a byte in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZMySQLResultSet.GetByte(ColumnIndex: Integer): Byte; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stByte); {$ENDIF} Result := Byte(StrToIntDef(String(InternalGetString(ColumnIndex)), 0)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a short in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZMySQLResultSet.GetShort(ColumnIndex: Integer): SmallInt; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stShort); {$ENDIF} Result := SmallInt(StrToIntDef(String(InternalGetString(ColumnIndex)), 0)); end; {** Gets the value of the designated column in the current row of this ResultSet object as an int in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZMySQLResultSet.GetInt(ColumnIndex: Integer): Integer; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stInteger); {$ENDIF} Result := StrToIntDef(String(InternalGetString(ColumnIndex)), 0); end; {** Gets the value of the designated column in the current row of this ResultSet object as a long in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZMySQLResultSet.GetLong(ColumnIndex: Integer): Int64; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stLong); {$ENDIF} Result := StrToInt64Def(String(InternalGetString(ColumnIndex)), 0); end; {** Gets the value of the designated column in the current row of this ResultSet object as a float in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZMySQLResultSet.GetFloat(ColumnIndex: Integer): Single; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stFloat); {$ENDIF} Result := SQLStrToFloatDef(InternalGetString(ColumnIndex), 0); end; {** Gets the value of the designated column in the current row of this ResultSet object as a double in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZMySQLResultSet.GetDouble(ColumnIndex: Integer): Double; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stDouble); {$ENDIF} Result := SQLStrToFloatDef(InternalGetString(ColumnIndex), 0); end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.BigDecimal in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @param scale the number of digits to the right of the decimal point @return the column value; if the value is SQL NULL, the value returned is null } function TZMySQLResultSet.GetBigDecimal(ColumnIndex: Integer): Extended; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stBigDecimal); {$ENDIF} Result := SQLStrToFloatDef(InternalGetString(ColumnIndex), 0); end; {** Gets the value of the designated column in the current row of this ResultSet object as a byte array in the Java programming language. The bytes represent the raw values returned by the driver. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZMySQLResultSet.GetBytes(ColumnIndex: Integer): TByteDynArray; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stBytes); {$ENDIF} Result := StrToBytes(InternalGetString(ColumnIndex)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Date object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZMySQLResultSet.GetDate(ColumnIndex: Integer): TDateTime; var Value: string; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stDate); {$ENDIF} Value := String(InternalGetString(ColumnIndex)); LastWasNull := (LastWasNull or (Copy(Value, 1, 10)='0000-00-00')); if LastWasNull then begin Result := 0; Exit; end; if IsMatch('????-??-??*', Value) then Result := Trunc(AnsiSQLDateToDateTime(Value)) else Result := Trunc(TimestampStrToDateTime(Value)); LastWasNull := Result = 0; end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Time object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZMySQLResultSet.GetTime(ColumnIndex: Integer): TDateTime; var Value: string; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stTime); {$ENDIF} Value := String(InternalGetString(ColumnIndex)); if LastWasNull then begin Result := 0; Exit; end; if IsMatch('*??:??:??*', Value) then Result := Frac(AnsiSQLDateToDateTime(Value)) else Result := Frac(TimestampStrToDateTime(Value)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null @exception SQLException if a database access error occurs } function TZMySQLResultSet.GetTimestamp(ColumnIndex: Integer): TDateTime; var Temp: string; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stTimestamp); {$ENDIF} Temp := String(GetPChar(ColumnIndex)); if LastWasNull then begin Result := 0; Exit; end; if IsMatch('????-??-??*', Temp) or IsMatch('??:??:??*', Temp) then Result := AnsiSQLDateToDateTime(Temp) else Result := TimestampStrToDateTime(Temp); LastWasNull := Result = 0; end; {** Returns the value of the designated column in the current row of this ResultSet object as a Blob object in the Java programming language. @param ColumnIndex the first column is 1, the second is 2, ... @return a Blob object representing the SQL BLOB value in the specified column } function TZMySQLResultSet.GetBlob(ColumnIndex: Integer): IZBlob; var Stream: TStream; begin {$IFNDEF DISABLE_CHECKING} CheckBlobColumn(ColumnIndex); {$ENDIF} Stream := nil; try if not IsNull(ColumnIndex) then begin case GetMetaData.GetColumnType(ColumnIndex) of stAsciiStream: Stream := TStringStream.Create(GetValidatedAnsiString(InternalGetString(ColumnIndex), ConSettings, True)); stUnicodeStream: Stream := GetValidatedUnicodeStream(InternalGetString(ColumnIndex), ConSettings, True); else Stream := TStringStream.Create(InternalGetString(ColumnIndex)); end; if not Assigned(Stream) then //improve TZTestCompMySQLBugReport.Test1045286 Stream := TMemoryStream.Create; Result := TZAbstractBlob.CreateWithStream(Stream, GetStatement.GetConnection, GetMetaData.GetColumnType(ColumnIndex) = stUnicodeStream); end else Result := TZAbstractBlob.CreateWithStream(nil, GetStatement.GetConnection); finally if Assigned(Stream) then Stream.Free; end; end; {** Moves the cursor to the given row number in this ResultSet object.

If the row number is positive, the cursor moves to the given row number with respect to the beginning of the result set. The first row is row 1, the second is row 2, and so on.

If the given row number is negative, the cursor moves to an absolute row position with respect to the end of the result set. For example, calling the method absolute(-1) positions the cursor on the last row; calling the method absolute(-2) moves the cursor to the next-to-last row, and so on.

An attempt to position the cursor beyond the first/last row in the result set leaves the cursor before the first row or after the last row.

Note: Calling absolute(1) is the same as calling first(). Calling absolute(-1) is the same as calling last(). @return true if the cursor is on the result set; false otherwise } function TZMySQLResultSet.MoveAbsolute(Row: Integer): Boolean; begin CheckClosed; { Checks for maximum row. } Result := False; if (MaxRows > 0) and (Row > MaxRows) then Exit; if not FUseResult then begin { Process negative rows. } if Row < 0 then begin Row := LastRowNo - Row + 1; if Row < 0 then Row := 0; end; if (Row >= 0) and (Row <= LastRowNo + 1) then begin RowNo := Row; if (Row >= 1) and (Row <= LastRowNo) then begin FPlainDriver.SeekData(FQueryHandle, RowNo - 1); FRowHandle := FPlainDriver.FetchRow(FQueryHandle); end else FRowHandle := nil; end; Result := FRowHandle <> nil; end else RaiseForwardOnlyException; end; {** Moves the cursor down one row from its current position. A ResultSet cursor is initially positioned before the first row; the first call to the method next makes the first row the current row; the second call makes the second row the current row, and so on.

If an input stream is open for the current row, a call to the method next will implicitly close it. A ResultSet object's warning chain is cleared when a new row is read. @return true if the new current row is valid; false if there are no more rows } function TZMySQLResultSet.Next: Boolean; begin { Checks for maximum row. } Result := False; if (MaxRows > 0) and (RowNo >= MaxRows) then Exit; if Assigned(FQueryHandle) then FRowHandle := FPlainDriver.FetchRow(FQueryHandle); if FRowHandle <> nil then begin RowNo := RowNo + 1; if LastRowNo < RowNo then LastRowNo := RowNo; Result := True; end else begin if RowNo <= LastRowNo then RowNo := LastRowNo + 1; Result := False; end; end; procedure TZMySQLResultSet.ReleaseHandle; begin if FQueryHandle <> nil then FPlainDriver.FreeResult(FQueryHandle); FQueryHandle := nil; end; { TZMySQLPreparedResultSet } {** Constructs this object, assignes main properties and opens the record set. @param PlainDriver a native MySQL plain driver. @param Statement a related SQL statement object. @param Handle a MySQL specific query handle. @param UseResult True to use results, False to store result. } constructor TZMySQLPreparedResultSet.Create(PlainDriver: IZMySQLPlainDriver; Statement: IZStatement; SQL: string; Handle: PZMySQLConnect; UseResult: Boolean); var tempPrepStmt : IZMysqlPreparedStatement; begin inherited Create(Statement, SQL, TZMySQLResultSetMetadata.Create( Statement.GetConnection.GetMetadata, SQL, Self), Statement.GetConnection.GetConSettings); FHandle := Handle; tempPrepStmt := Statement as IZMysqlPreparedStatement; FPrepStmt:= tempPrepStmt.GetStmtHandle; FResultMetaData := nil; FPlainDriver := PlainDriver; ResultSetConcurrency := rcReadOnly; FUseResult := UseResult; Open; end; {** Destroys this object and cleanups the memory. } destructor TZMySQLPreparedResultSet.Destroy; begin inherited Destroy; end; {** Opens this recordset. } procedure TZMySQLPreparedResultSet.Open; const one = AnsiString('1'); var I: Integer; ColumnInfo: TZColumnInfo; FieldHandle: PZMySQLField; FieldCount: Integer; begin if ResultSetConcurrency = rcUpdatable then raise EZSQLException.Create(SLiveResultSetsAreNotSupported); FieldCount := FPlainDriver.GetPreparedFieldCount(FPrepStmt); if FieldCount = 0 then raise EZSQLException.Create(SCanNotRetrieveResultSetData); FResultMetaData := FPlainDriver.GetPreparedMetaData(FPrepStmt); if not Assigned(FResultMetaData) then raise EZSQLException.Create(SCanNotRetrieveResultSetData); if FUseResult then LastRowNo := 0 else begin FPlainDriver.StmtAttrSet(FPrepStmt,STMT_ATTR_UPDATE_MAX_LENGTH,PAnsiChar(one)); if (FPlainDriver.StorePreparedResult(FPrepStmt)=0) then LastRowNo := FPlainDriver.GetPreparedNumRows(FPrepStmt) else LastRowNo := 0; end; { Initialize Bind Array and Column Array } FBindBuffer := TZMySqlResultSetBindBuffer.Create(FPlainDriver,FieldCount,FColumnArray); { Fills the column info. } ColumnsInfo.Clear; for I := 0 to FPlainDriver.GetFieldCount(FResultMetaData) - 1 do begin FPlainDriver.SeekField(FResultMetaData, I); FieldHandle := FPlainDriver.FetchField(FResultMetaData); if FieldHandle = nil then Break; ColumnInfo := GetMySQLColumnInfoFromFieldHandle(FPlainDriver, FieldHandle, GetStatement.GetConnection.GetConSettings, FUseResult); ColumnsInfo.Add(ColumnInfo); FBindBuffer.AddColumn(FPlainDriver, FieldHandle); end; FPlainDriver.FreeResult(FResultMetaData); FResultMetaData := nil; if (FPlainDriver.BindResult(FPrepStmt,FBindBuffer.GetBufferAddress)<>0) then raise EZSQLException.Create(SFailedToBindResults); inherited Open; end; {** Releases this ResultSet object's database and JDBC resources immediately instead of waiting for this to happen when it is automatically closed.

Note: A ResultSet object is automatically closed by the Statement object that generated it when that Statement object is closed, re-executed, or is used to retrieve the next result from a sequence of multiple results. A ResultSet object is also automatically closed when it is garbage collected. } procedure TZMySQLPreparedResultSet.Close; begin if Assigned(FResultMetaData) then FPlainDriver.FreeResult(FResultMetaData); FResultMetaData := nil; if Assigned(FBindBuffer) then FreeAndNil(FBindBuffer); if Assigned(FPrepStmt) then begin FPlainDriver.FreePreparedResult(FPrepStmt); while(FPlainDriver.GetPreparedNextResult(FPrepStmt) = 0) do FPlainDriver.FreePreparedResult(FPrepStmt); end; inherited Close; end; {** Indicates if the value of the designated column in the current row of this ResultSet object is Null. @param columnIndex the first column is 1, the second is 2, ... @return if the value is SQL NULL, the value returned is true. false otherwise. } function TZMySQLPreparedResultSet.IsNull(ColumnIndex: Integer): Boolean; begin {$IFNDEF DISABLE_CHECKING} CheckClosed; {$ENDIF} Result := FColumnArray[ColumnIndex-1].is_null =1; end; {** Gets the value of the designated column in the current row of this ResultSet object as a String in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZMySQLPreparedResultSet.InternalGetString(ColumnIndex: Integer): RawByteString; begin {$IFNDEF DISABLE_CHECKING} CheckClosed; {$ENDIF} Result := PAnsiChar(FColumnArray[ColumnIndex - 1].buffer); LastWasNull := FColumnArray[ColumnIndex-1].is_null =1; end; {** Gets the value of the designated column in the current row of this ResultSet object as a boolean in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is false } function TZMySQLPreparedResultSet.GetBoolean(ColumnIndex: Integer): Boolean; var Temp: string; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stBoolean); {$ENDIF} Temp := UpperCase(String(InternalGetString(ColumnIndex))); Result := (Temp = 'Y') or (Temp = 'YES') or (Temp = 'T') or (Temp = 'TRUE') or (StrToIntDef(Temp, 0) <> 0); end; {** Gets the value of the designated column in the current row of this ResultSet object as a byte in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZMySQLPreparedResultSet.GetByte(ColumnIndex: Integer): Byte; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stByte); {$ENDIF} Result := Byte(bufferasInt64(ColumnIndex)); LastWasNull := FColumnArray[ColumnIndex-1].is_null =1; end; {** Gets the value of the designated column in the current row of this ResultSet object as a short in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZMySQLPreparedResultSet.GetShort(ColumnIndex: Integer): SmallInt; Begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stShort); {$ENDIF} Result := Integer(bufferasInt64(ColumnIndex)); LastWasNull := FColumnArray[ColumnIndex-1].is_null =1; end; {** Gets the value of the designated column in the current row of this ResultSet object as an int in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZMySQLPreparedResultSet.GetInt(ColumnIndex: Integer): Integer; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stInteger); {$ENDIF} Result := bufferasInt64(ColumnIndex); LastWasNull := FColumnArray[ColumnIndex-1].is_null =1; end; {** Gets the value of the designated column in the current row of this ResultSet object as a long in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZMySQLPreparedResultSet.GetLong(ColumnIndex: Integer): Int64; Begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stLong); {$ENDIF} Result := bufferasInt64(ColumnIndex); LastWasNull := FColumnArray[ColumnIndex-1].is_null =1; end; {** Gets the value of the designated column in the current row of this ResultSet object as a float in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZMySQLPreparedResultSet.GetFloat(ColumnIndex: Integer): Single; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stFloat); {$ENDIF} Result := BufferAsExtended(ColumnIndex); LastWasNull := FColumnArray[ColumnIndex-1].is_null =1; end; {** Gets the value of the designated column in the current row of this ResultSet object as a double in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZMySQLPreparedResultSet.GetDouble(ColumnIndex: Integer): Double; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stDouble); {$ENDIF} Result := BufferAsExtended(ColumnIndex); LastWasNull := FColumnArray[ColumnIndex-1].is_null =1; end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.BigDecimal in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @param scale the number of digits to the right of the decimal point @return the column value; if the value is SQL NULL, the value returned is null } function TZMySQLPreparedResultSet.GetBigDecimal(ColumnIndex: Integer): Extended; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stBigDecimal); {$ENDIF} Result := BufferAsExtended(ColumnIndex); LastWasNull := FColumnArray[ColumnIndex-1].is_null =1; end; {** Gets the value of the designated column in the current row of this ResultSet object as a byte array in the Java programming language. The bytes represent the raw values returned by the driver. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZMySQLPreparedResultSet.GetBytes(ColumnIndex: Integer): TByteDynArray; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stBytes); {$ENDIF} Result := StrToBytes(InternalGetString(ColumnIndex)); LastWasNull := FColumnArray[ColumnIndex-1].is_null =1; end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Date object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZMySQLPreparedResultSet.GetDate(ColumnIndex: Integer): TDateTime; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stDate); {$ENDIF} if not sysUtils.TryEncodeDate(PMYSQL_TIME(FColumnArray[ColumnIndex - 1].buffer)^.Year, PMYSQL_TIME(FColumnArray[ColumnIndex - 1].buffer)^.Month, PMYSQL_TIME(FColumnArray[ColumnIndex - 1].buffer)^.Day, Result) then Result := encodeDate(1900, 1, 1); LastWasNull := FColumnArray[ColumnIndex-1].is_null =1; end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Time object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZMySQLPreparedResultSet.GetTime(ColumnIndex: Integer): TDateTime; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stTime); {$ENDIF} if not sysUtils.TryEncodeTime(PMYSQL_TIME(FColumnArray[ColumnIndex - 1].buffer)^.Hour, PMYSQL_TIME(FColumnArray[ColumnIndex - 1].buffer)^.Minute, PMYSQL_TIME(FColumnArray[ColumnIndex - 1].buffer)^.Second, 0, Result) then Result := encodeTime(0,0,0,0); LastWasNull := FColumnArray[ColumnIndex-1].is_null =1; end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null @exception SQLException if a database access error occurs } function TZMySQLPreparedResultSet.GetTimestamp(ColumnIndex: Integer): TDateTime; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stTimestamp); {$ENDIF} Result := GetDate(ColumnIndex) + GetTime(ColumnIndex); LastWasNull := FColumnArray[ColumnIndex-1].is_null =1; end; {** Gets the value of the designated column in the current row of this ResultSet object as a stream of ASCII characters. The value can then be read in chunks from the stream. This method is particularly suitable for retrieving large LONGVARCHAR values. The JDBC driver will do any necessary conversion from the database format into ASCII.

Note: All the data in the returned stream must be read prior to getting the value of any other column. The next call to a getXXX method implicitly closes the stream. Also, a stream may return 0 when the method InputStream.available is called whether there is data available or not. @param columnIndex the first column is 1, the second is 2, ... @return a Java input stream that delivers the database column value as a stream of one-byte ASCII characters; if the value is SQL NULL, the value returned is null } function TZMySQLPreparedResultSet.GetAsciiStream(ColumnIndex: Integer): TStream; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stAsciiStream); {$ENDIF} Result := TStringStream.Create(InternalGetString(ColumnIndex)); LastWasNull := FColumnArray[ColumnIndex-1].is_null =1; end; {** Gets the value of a column in the current row as a stream of Gets the value of the designated column in the current row of this ResultSet object as as a stream of Unicode characters. The value can then be read in chunks from the stream. This method is particularly suitable for retrieving largeLONGVARCHARvalues. The JDBC driver will do any necessary conversion from the database format into Unicode. The byte format of the Unicode stream must be Java UTF-8, as specified in the Java virtual machine specification.

Note: All the data in the returned stream must be read prior to getting the value of any other column. The next call to a getXXX method implicitly closes the stream. Also, a stream may return 0 when the method InputStream.available is called whether there is data available or not. @param columnIndex the first column is 1, the second is 2, ... @return a Java input stream that delivers the database column value as a stream in Java UTF-8 byte format; if the value is SQL NULL, the value returned is null } function TZMySQLPreparedResultSet.GetUnicodeStream(ColumnIndex: Integer): TStream; var WS: ZWideString; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stUnicodeStream); {$ENDIF} WS := ZDbcUnicodeString(InternalGetString(ColumnIndex)); Result := TMemoryStream.Create; Result.Write(PWideChar(WS)^, Length(WS) *2); Result.Position := 0; LastWasNull := FColumnArray[ColumnIndex-1].is_null =1; end; {** Gets the value of a column in the current row as a stream of Gets the value of the designated column in the current row of this ResultSet object as a binary stream of uninterpreted bytes. The value can then be read in chunks from the stream. This method is particularly suitable for retrieving large LONGVARBINARY values.

Note: All the data in the returned stream must be read prior to getting the value of any other column. The next call to a getXXX method implicitly closes the stream. Also, a stream may return 0 when the method InputStream.available is called whether there is data available or not. @param columnIndex the first column is 1, the second is 2, ... @return a Java input stream that delivers the database column value as a stream of uninterpreted bytes; if the value is SQL NULL, the value returned is null } function TZMySQLPreparedResultSet.GetBinaryStream(ColumnIndex: Integer): TStream; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stBinaryStream); {$ENDIF} Result := TMemoryStream.Create; Result.Write(FColumnArray[ColumnIndex - 1].buffer[0], FColumnArray[ColumnIndex - 1].length); Result.Position := 0; LastWasNull := FColumnArray[ColumnIndex-1].is_null =1; end; {** Returns the value of the designated column in the current row of this ResultSet object as a Blob object in the Java programming language. @param ColumnIndex the first column is 1, the second is 2, ... @return a Blob object representing the SQL BLOB value in the specified column } function TZMySQLPreparedResultSet.GetBlob(ColumnIndex: Integer): IZBlob; var Stream: TStream; begin Result := nil; {$IFNDEF DISABLE_CHECKING} CheckBlobColumn(ColumnIndex); {$ENDIF} LastWasNull := IsNull(ColumnIndex); if LastWasNull then Exit; Stream := nil; try if not LastWasNull then begin case GetMetadata.GetColumnType(ColumnIndex) of stBinaryStream: Stream := GetBinaryStream(ColumnIndex); stUnicodeStream: Stream := GetUnicodeStream(ColumnIndex); else Stream := TStringStream.Create(GetValidatedAnsiString(InternalGetString(ColumnIndex), ConSettings, True)); end; Result := TZAbstractBlob.CreateWithStream(Stream, GetStatement.GetConnection, GetMetadata.GetColumnType(ColumnIndex) = stUnicodeStream) end else Result := TZAbstractBlob.CreateWithStream(nil, GetStatement.GetConnection); finally if Assigned(Stream) then Stream.Free; end; end; function TZMySQLPreparedResultSet.bufferasint64(ColumnIndex: Integer): Int64; begin //http://dev.mysql.com/doc/refman/5.1/de/numeric-types.html if FBindBuffer.GetBufferIsSigned(ColumnIndex) then Case FBindBuffer.GetBufferType(ColumnIndex) of FIELD_TYPE_DECIMAL: Result := 0; FIELD_TYPE_TINY: Result := PByte(FColumnArray[ColumnIndex-1].buffer)^; FIELD_TYPE_SHORT: Result := PWord(FColumnArray[ColumnIndex-1].buffer)^; FIELD_TYPE_LONG: Result := PCardinal(FColumnArray[ColumnIndex-1].buffer)^; FIELD_TYPE_FLOAT: Result := 0; FIELD_TYPE_DOUBLE: Result := 0; FIELD_TYPE_NULL: Result := 0; FIELD_TYPE_TIMESTAMP: Result := 0; FIELD_TYPE_LONGLONG: Result := PULongLong(FColumnArray[ColumnIndex-1].buffer)^; FIELD_TYPE_INT24: Result := PCardinal(FColumnArray[ColumnIndex-1].buffer)^; (*FIELD_TYPE_DATE = 10, FIELD_TYPE_TIME = 11, FIELD_TYPE_DATETIME = 12,*) FIELD_TYPE_YEAR: Result := PWord(FColumnArray[ColumnIndex-1].buffer)^; (*FIELD_TYPE_NEWDATE = 14, FIELD_TYPE_VARCHAR = 15, //<--ADDED by fduenas 20-06-2006 FIELD_TYPE_BIT: ; FIELD_TYPE_NEWDECIMAL = 246, //<--ADDED by fduenas 20-06-2006 FIELD_TYPE_ENUM = 247, FIELD_TYPE_SET = 248, FIELD_TYPE_TINY_BLOB, FIELD_TYPE_MEDIUM_BLOB, FIELD_TYPE_LONG_BLOB, FIELD_TYPE_BLOB: Result := 0; FIELD_TYPE_VAR_STRING = 253, FIELD_TYPE_STRING: = 254, FIELD_TYPE_GEOMETRY: = 255*) else Result := 0; end else Case FBindBuffer.GetBufferType(ColumnIndex) of FIELD_TYPE_DECIMAL: Result := 0; FIELD_TYPE_TINY: Result := PShortInt(FColumnArray[ColumnIndex-1].buffer)^; FIELD_TYPE_SHORT: Result := PSmallInt(FColumnArray[ColumnIndex-1].buffer)^; FIELD_TYPE_LONG: Result := PInteger(FColumnArray[ColumnIndex-1].buffer)^; FIELD_TYPE_FLOAT: Result := 0; FIELD_TYPE_DOUBLE: Result := 0; FIELD_TYPE_NULL: Result := 0; FIELD_TYPE_TIMESTAMP: Result := 0; FIELD_TYPE_LONGLONG: Result := PInt64(FColumnArray[ColumnIndex-1].buffer)^; FIELD_TYPE_INT24: Result := PInteger(FColumnArray[ColumnIndex-1].buffer)^; (*FIELD_TYPE_DATE = 10, FIELD_TYPE_TIME = 11, FIELD_TYPE_DATETIME = 12, *) FIELD_TYPE_YEAR: Result := PSmallInt(FColumnArray[ColumnIndex-1].buffer)^; (*FIELD_TYPE_NEWDATE = 14, FIELD_TYPE_VARCHAR = 15, //<--ADDED by fduenas 20-06-2006 FIELD_TYPE_BIT: ; FIELD_TYPE_NEWDECIMAL = 246, //<--ADDED by fduenas 20-06-2006 FIELD_TYPE_ENUM = 247, FIELD_TYPE_SET = 248, FIELD_TYPE_TINY_BLOB, FIELD_TYPE_MEDIUM_BLOB, FIELD_TYPE_LONG_BLOB, FIELD_TYPE_BLOB: Result := 0; FIELD_TYPE_VAR_STRING = 253, FIELD_TYPE_STRING: = 254, FIELD_TYPE_GEOMETRY: = 255*) else Result := 0; end; end; function TZMySQLPreparedResultSet.bufferasextended(ColumnIndex: Integer): Extended; begin Case FBindBuffer.GetBufferType(ColumnIndex) of FIELD_TYPE_FLOAT: Result := psingle(FColumnArray[ColumnIndex-1].buffer)^; FIELD_TYPE_DOUBLE: Result := pdouble(FColumnArray[ColumnIndex-1].buffer)^; else Result := SQLStrToFloatDef(InternalGetString(ColumnIndex), 0); End end; {** Moves the cursor to the given row number in this ResultSet object.

If the row number is positive, the cursor moves to the given row number with respect to the beginning of the result set. The first row is row 1, the second is row 2, and so on.

If the given row number is negative, the cursor moves to an absolute row position with respect to the end of the result set. For example, calling the method absolute(-1) positions the cursor on the last row; calling the method absolute(-2) moves the cursor to the next-to-last row, and so on.

An attempt to position the cursor beyond the first/last row in the result set leaves the cursor before the first row or after the last row.

Note: Calling absolute(1) is the same as calling first(). Calling absolute(-1) is the same as calling last(). @return true if the cursor is on the result set; false otherwise } function TZMySQLPreparedResultSet.MoveAbsolute(Row: Integer): Boolean; begin CheckClosed; { Checks for maximum row. } Result := False; if (MaxRows > 0) and (Row > MaxRows) then Exit; if not FUseResult then begin { Process negative rows. } if Row < 0 then begin Row := LastRowNo - Row + 1; if Row < 0 then Row := 0; end; if (Row >= 0) and (Row <= LastRowNo + 1) then begin RowNo := Row; if (Row >= 1) and (Row <= LastRowNo) then begin FPlainDriver.SeekPreparedData(FPrepStmt, RowNo - 1); Result := (FPlainDriver.FetchBoundResults(FPrepStmt) =0); end; end; end else RaiseForwardOnlyException; end; {** Moves the cursor down one row from its current position. A ResultSet cursor is initially positioned before the first row; the first call to the method next makes the first row the current row; the second call makes the second row the current row, and so on.

If an input stream is open for the current row, a call to the method next will implicitly close it. A ResultSet object's warning chain is cleared when a new row is read. @return true if the new current row is valid; false if there are no more rows } function TZMySQLPreparedResultSet.Next: Boolean; begin { Checks for maximum row. } Result := False; if (MaxRows > 0) and (RowNo >= MaxRows) then Exit; if FPlainDriver.FetchBoundResults(FPrepStmt) in [0, MYSQL_DATA_TRUNCATED] then begin RowNo := RowNo + 1; if LastRowNo < RowNo then LastRowNo := RowNo; Result := True; end else begin if RowNo <= LastRowNo then RowNo := LastRowNo + 1; Result := False; end; end; { TZMySQLCachedResolver } {** Creates a MySQL specific cached resolver object. @param PlainDriver a native MySQL plain driver. @param Handle a MySQL specific query handle. @param Statement a related SQL statement object. @param Metadata a resultset metadata reference. } constructor TZMySQLCachedResolver.Create(PlainDriver: IZMySQLPlainDriver; Handle: PZMySQLConnect; Statement: IZMysqlStatement; Metadata: IZResultSetMetadata); var I: Integer; begin inherited Create(Statement, Metadata); FPlainDriver := PlainDriver; FHandle := Handle; FStatement := Statement as IZMysqlStatement; { Defines an index of autoincrement field. } FAutoColumnIndex := 0; for I := 1 to Metadata.GetColumnCount do begin if Metadata.IsAutoIncrement(I) and (Metadata.GetColumnType(I) in [stByte, stShort, stInteger, stLong]) then begin FAutoColumnIndex := I; Break; end; end; end; {** Forms a where clause for UPDATE or DELETE DML statements. @param Columns a collection of key columns. @param OldRowAccessor an accessor object to old column values. } function TZMySQLCachedResolver.FormWhereClause(Columns: TObjectList; OldRowAccessor: TZRowAccessor): string; var I, N: Integer; Current: TZResolverParameter; begin Result := ''; N := Columns.Count - WhereColumns.Count; for I := 0 to WhereColumns.Count - 1 do begin Current := TZResolverParameter(WhereColumns[I]); if Result <> '' then Result := Result + ' AND '; Result := Result + IdentifierConvertor.Quote(Current.ColumnName); if OldRowAccessor.IsNull(Current.ColumnIndex) then begin if not (Metadata.IsNullable(Current.ColumnIndex) = ntNullable) then case OldRowAccessor.GetColumnType(Current.ColumnIndex) of stDate: if I > 0 then begin Current := TZResolverParameter(WhereColumns[I-1]); Result := Result+ '=''0000-00-00'' OR '+Result + ' IS NULL'; Columns.Add(TZResolverParameter.Create(Current.ColumnIndex, Current.ColumnName, Current.ColumnType, Current.NewValue, '')); end; stTime: if I > 0 then begin Current := TZResolverParameter(WhereColumns[I-1]); Result := Result+ '=''00:00:00'' OR '+Result + ' IS NULL'; Columns.Add(TZResolverParameter.Create(Current.ColumnIndex, Current.ColumnName, Current.ColumnType, Current.NewValue, '')); end; stTimeStamp: if I > 0 then begin Current := TZResolverParameter(WhereColumns[I-1]); Result := Result+ '=''0000-00-00 00:00:00'' OR '+Result + ' IS NULL'; Columns.Add(TZResolverParameter.Create(Current.ColumnIndex, Current.ColumnName, Current.ColumnType, Current.NewValue, '')); end; else Result := Result + ' IS NULL'; end else Result := Result + ' IS NULL '; Columns.Delete(N); end else begin Result := Result + '=?'; Inc(N); end; end; if Result <> '' then Result := ' WHERE ' + Result; end; {** Posts updates to database. @param Sender a cached result set object. @param UpdateType a type of updates. @param OldRowAccessor an accessor object to old column values. @param NewRowAccessor an accessor object to new column values. } procedure TZMySQLCachedResolver.PostUpdates(Sender: IZCachedResultSet; UpdateType: TZRowUpdateType; OldRowAccessor, NewRowAccessor: TZRowAccessor); begin inherited PostUpdates(Sender, UpdateType, OldRowAccessor, NewRowAccessor); if (UpdateType = utInserted) then begin UpdateAutoIncrementFields(Sender, UpdateType, OldRowAccessor, NewRowAccessor, Self); end; end; {** Do Tasks after Post updates to database. @param Sender a cached result set object. @param UpdateType a type of updates. @param OldRowAccessor an accessor object to old column values. @param NewRowAccessor an accessor object to new column values. } procedure TZMySQLCachedResolver.UpdateAutoIncrementFields( Sender: IZCachedResultSet; UpdateType: TZRowUpdateType; OldRowAccessor, NewRowAccessor: TZRowAccessor; Resolver: IZCachedResolver); var Plaindriver : IZMysqlPlainDriver; begin inherited UpdateAutoIncrementFields(Sender, UpdateType, OldRowAccessor, NewRowAccessor, Resolver); if not ((FAutoColumnIndex > 0) and (OldRowAccessor.IsNull(FAutoColumnIndex) or (OldRowAccessor.GetValue(FAutoColumnIndex).VInteger=0))) then exit; Plaindriver := (Connection as IZMysqlConnection).GetPlainDriver; // THIS IS WRONG, I KNOW (MDAEMS) : which function to use depends on the insert statement, not the resultset statement { IF FStatement.IsPreparedStatement then NewRowAccessor.SetLong(FAutoColumnIndex, PlainDriver.GetPreparedInsertID(FStatement.GetStmtHandle)) else} NewRowAccessor.SetLong(FAutoColumnIndex, PlainDriver.GetLastInsertID(FHandle)); end; {** Forms a where clause for SELECT statements to calculate default values. @param Columns a collection of key columns. @param OldRowAccessor an accessor object to old column values. } function TZMySQLCachedResolver.FormCalculateStatement( Columns: TObjectList): string; var I: Integer; Current: TZResolverParameter; begin Result := ''; if Columns.Count = 0 then Exit; for I := 0 to Columns.Count - 1 do begin Current := TZResolverParameter(Columns[I]); if Result <> '' then Result := Result + ','; if Current.DefaultValue <> '' then Result := Result + Current.DefaultValue else Result := Result + 'NULL'; end; Result := 'SELECT ' + Result; end; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcMySqlStatement.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { MySQL Database Connectivity Classes } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcMySqlStatement; interface {$I ZDbc.inc} uses Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, ZClasses, ZDbcIntfs, ZDbcStatement, ZDbcMySql, ZVariant, ZPlainMySqlDriver, ZPlainMySqlConstants, ZCompatibility, ZDbcLogging; type {** Represents a MYSQL specific connection interface. } IZMySQLStatement = interface (IZStatement) ['{A05DB91F-1E40-46C7-BF2E-25D74978AC83}'] function IsUseResult: Boolean; function IsPreparedStatement: Boolean; function GetStmtHandle: PZMySqlPrepStmt; end; {** Represents a MYSQL prepared Statement specific connection interface. } IZMySQLPreparedStatement = interface (IZMySQLStatement) ['{A05DB91F-1E40-46C7-BF2E-25D74978AC83}'] end; {** Implements Generic MySQL Statement. } TZMySQLStatement = class(TZAbstractStatement, IZMySQLStatement) private FHandle: PZMySQLConnect; FPlainDriver: IZMySQLPlainDriver; FUseResult: Boolean; function CreateResultSet(const SQL: string): IZResultSet; function GetStmtHandle : PZMySqlPrepStmt; public constructor Create(PlainDriver: IZMySQLPlainDriver; Connection: IZConnection; Info: TStrings; Handle: PZMySQLConnect); function ExecuteQuery(const SQL: RawByteString): IZResultSet; override; function ExecuteUpdate(const SQL: RawByteString): Integer; override; function Execute(const SQL: RawByteString): Boolean; override; function GetMoreResults: Boolean; override; function IsUseResult: Boolean; function IsPreparedStatement: Boolean; end; {** Implements Prepared SQL Statement. } TZMySQLEmulatedPreparedStatement = class(TZEmulatedPreparedStatement) private FHandle: PZMySQLConnect; FPlainDriver: IZMySQLPlainDriver; FUseDefaults: Boolean; protected function CreateExecStatement: IZStatement; override; function PrepareAnsiSQLParam(ParamIndex: Integer): RawByteString; override; public constructor Create(PlainDriver: IZMySQLPlainDriver; Connection: IZConnection; const SQL: string; Info: TStrings; Handle: PZMySQLConnect); end; TZMysqlColumnBuffer = Array of PDOBindRecord2; { TZMySQLBindBuffer } {** Encapsulates a MySQL bind buffer. } TZMySQLAbstractBindBuffer = class(TZAbstractObject) protected FAddedColumnCount : Integer; FBindOffsets: MYSQL_BINDOFFSETS; FBindArray: Array of byte; FPColumnArray: ^TZMysqlColumnBuffer; public constructor Create(PlainDriver:IZMysqlPlainDriver; const BindCount : Integer; var ColumnArray:TZMysqlColumnBuffer); function GetColumnArray : TZMysqlColumnBuffer; function GetBufferAddress : Pointer; function GetBufferType(ColumnIndex: Integer): TMysqlFieldTypes; function GetBufferIsSigned(ColumnIndex: Integer): Boolean; end; {** Encapsulates a MySQL bind buffer for ResultSets. } TZMySQLResultSetBindBuffer = class(TZMySQLAbstractBindBuffer) public procedure AddColumn(PlainDriver: IZMysqlPlainDriver; const FieldHandle: PZMySQLField); end; {** Encapsulates a MySQL bind buffer for updates. } TZMySQLParamBindBuffer = class(TZMySQLAbstractBindBuffer) public procedure AddColumn(buffertype: TMysqlFieldTypes; const field_length: integer; const largeblobparameter: boolean); end; {** Implements Prepared SQL Statement. } { TZMySQLPreparedStatement } TZMySQLPreparedStatement = class(TZAbstractPreparedStatement,IZMySQLPreparedStatement) private FHandle: PZMySQLConnect; FMySQLConnection: IZMySQLConnection; FStmtHandle: PZMySqlPrepStmt; FPlainDriver: IZMySQLPlainDriver; FUseResult: Boolean; FUseDefaults: Boolean; FColumnArray: TZMysqlColumnBuffer; FParamBindBuffer: TZMySQLParamBindBuffer; function CreateResultSet(const SQL: string): IZResultSet; function getFieldType (testVariant: TZVariant): TMysqlFieldTypes; protected function GetStmtHandle : PZMySqlPrepStmt; procedure BindInParameters; override; procedure UnPrepareInParameters; override; public property StmtHandle: PZMySqlPrepStmt read GetStmtHandle; constructor Create(PlainDriver: IZMysqlPlainDriver; Connection: IZConnection; const SQL: string; Info: TStrings); procedure Prepare; override; destructor Destroy; override; function ExecuteQueryPrepared: IZResultSet; override; function ExecuteUpdatePrepared: Integer; override; function ExecutePrepared: Boolean; override; function IsUseResult: Boolean; function IsPreparedStatement: Boolean; end; {** Implements callable Postgresql Statement. } TZMySQLCallableStatement = class(TZAbstractCallableStatement, IZMySQLStatement, IZParamNamedCallableStatement) private FPlainDriver: IZMysqlPlainDriver; FHandle: PZMySQLConnect; FQueryHandle: PZMySQLResult; FUseResult: Boolean; FParamNames: array [0..1024] of String; FParamTypeNames: array [0..1024] of String; FUseDefaults: Boolean; function GetCallSQL: RawByteString; function GetOutParamSQL: String; function GetSelectFunctionSQL: RawByteString; function PrepareAnsiSQLParam(ParamIndex: Integer): RawByteString; function GetStmtHandle : PZMySqlPrepStmt; protected procedure ClearResultSets; override; procedure BindInParameters; override; function CreateResultSet(const SQL: string): IZResultSet; procedure FetchOutParams(ResultSet: IZResultSet); procedure RegisterParamTypeAndName(const ParameterIndex:integer; const ParamTypeName, ParamName: String; Const ColumnSize, Precision: Integer); public constructor Create(PlainDriver: IZMySQLPlainDriver; Connection: IZConnection; const SQL: string; Info: TStrings; Handle: PZMySQLConnect); function Execute(const SQL: RawByteString): Boolean; override; function ExecuteQuery(const SQL: RawByteString): IZResultSet; override; function ExecuteUpdate(const SQL: RawByteString): Integer; override; function ExecuteQueryPrepared: IZResultSet; override; function ExecuteUpdatePrepared: Integer; override; function IsUseResult: Boolean; function IsPreparedStatement: Boolean; function HasMoreResultSets: Boolean; override; function GetFirstResultSet: IZResultSet; override; function GetPreviousResultSet: IZResultSet; override; function GetNextResultSet: IZResultSet; override; function GetLastResultSet: IZResultSet; override; function BOR: Boolean; override; function EOR: Boolean; override; function GetResultSetByIndex(const Index: Integer): IZResultSet; override; function GetResultSetCount: Integer; override; end; implementation uses Types, Math, DateUtils, ZDbcMySqlUtils, ZDbcMySqlResultSet, ZSysUtils, ZDbcResultSetMetadata, ZMessages, ZDbcCachedResultSet, ZDbcUtils, ZEncoding, ZDbcResultSet{$IFDEF WITH_UNITANSISTRINGS}, AnsiStrings{$ENDIF}; { TZMySQLStatement } {** Constructs this object and assignes the main properties. @param PlainDriver a native MySQL plain driver. @param Connection a database connection object. @param Handle a connection handle pointer. @param Info a statement parameters. } constructor TZMySQLStatement.Create(PlainDriver: IZMySQLPlainDriver; Connection: IZConnection; Info: TStrings; Handle: PZMySQLConnect); begin inherited Create(Connection, Info); FHandle := Handle; FPlainDriver := PlainDriver; ResultSetType := rtScrollInsensitive; FUseResult := StrToBoolEx(DefineStatementParameter(Self, 'useresult', 'false')); end; {** Checks is use result should be used in result sets. @return True use result in result sets, False store result in result sets. } function TZMySQLStatement.IsUseResult: Boolean; begin Result := FUseResult; end; {** Checks if this is a prepared mysql statement. @return False This is not a prepared mysql statement. } function TZMySQLStatement.IsPreparedStatement: Boolean; begin Result := False; end; function TZMySQLStatement.GetStmtHandle: PZMySqlPrepStmt; begin Result := nil; end; {** Creates a result set based on the current settings. @return a created result set object. } function TZMySQLStatement.CreateResultSet(const SQL: string): IZResultSet; var CachedResolver: TZMySQLCachedResolver; NativeResultSet: TZMySQLResultSet; CachedResultSet: TZCachedResultSet; begin NativeResultSet := TZMySQLResultSet.Create(FPlainDriver, Self, SQL, FHandle, FUseResult, nil); NativeResultSet.SetConcurrency(rcReadOnly); if (GetResultSetConcurrency <> rcReadOnly) or (FUseResult and (GetResultSetType <> rtForwardOnly)) then begin CachedResolver := TZMySQLCachedResolver.Create(FPlainDriver, FHandle, Self, NativeResultSet.GetMetaData); CachedResultSet := TZCachedResultSet.Create(NativeResultSet, SQL, CachedResolver, ConSettings); CachedResultSet.SetConcurrency(GetResultSetConcurrency); Result := CachedResultSet; end else Result := NativeResultSet; end; {** Executes an SQL statement that returns a single ResultSet object. @param sql typically this is a static SQL SELECT statement @return a ResultSet object that contains the data produced by the given query; never null } function TZMySQLStatement.ExecuteQuery(const SQL: RawByteString): IZResultSet; begin ASQL := SQL; Result := nil; if FPlainDriver.ExecQuery(FHandle, PAnsiChar(ASQL)) = 0 then begin DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, LogSQL); if not FPlainDriver.ResultSetExists(FHandle) then raise EZSQLException.Create(SCanNotOpenResultSet); Result := CreateResultSet(LogSQL); end else CheckMySQLError(FPlainDriver, FHandle, lcExecute, LogSQL); end; {** Executes an SQL INSERT, UPDATE or DELETE statement. In addition, SQL statements that return nothing, such as SQL DDL statements, can be executed. @param sql an SQL INSERT, UPDATE or DELETE statement or an SQL statement that returns nothing @return either the row count for INSERT, UPDATE or DELETE statements, or 0 for SQL statements that return nothing } function TZMySQLStatement.ExecuteUpdate(const SQL: RawByteString): Integer; var QueryHandle: PZMySQLResult; HasResultset : Boolean; begin ASQL := SQL; Result := -1; if FPlainDriver.ExecQuery(FHandle, PAnsichar(ASQL)) = 0 then begin DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, LogSQL); HasResultSet := FPlainDriver.ResultSetExists(FHandle); { Process queries with result sets } if HasResultSet then begin QueryHandle := FPlainDriver.StoreResult(FHandle); if QueryHandle <> nil then begin Result := FPlainDriver.GetRowCount(QueryHandle); FPlainDriver.FreeResult(QueryHandle); end else Result := FPlainDriver.GetAffectedRows(FHandle); while(FPlainDriver.RetrieveNextRowset(FHandle) = 0) do begin QueryHandle := FPlainDriver.StoreResult(FHandle); if QueryHandle <> nil then begin FPlainDriver.FreeResult(QueryHandle); end; end; end { Process regular query } else Result := FPlainDriver.GetAffectedRows(FHandle); end else CheckMySQLError(FPlainDriver, FHandle, lcExecute, LogSQL); LastUpdateCount := Result; end; {** Executes an SQL statement that may return multiple results. Under some (uncommon) situations a single SQL statement may return multiple result sets and/or update counts. Normally you can ignore this unless you are (1) executing a stored procedure that you know may return multiple results or (2) you are dynamically executing an unknown SQL string. The methods execute, getMoreResults, getResultSet, and getUpdateCount let you navigate through multiple results. The execute method executes an SQL statement and indicates the form of the first result. You can then use the methods getResultSet or getUpdateCount to retrieve the result, and getMoreResults to move to any subsequent result(s). @param sql any SQL statement @return true if the next result is a ResultSet object; false if it is an update count or there are no more results } function TZMySQLStatement.Execute(const SQL: RawByteString): Boolean; var HasResultset : Boolean; begin ASQL := SQL; Result := False; if FPlainDriver.ExecQuery(FHandle, PAnsiChar(ASQL)) = 0 then begin DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, LogSQL); HasResultSet := FPlainDriver.ResultSetExists(FHandle); { Process queries with result sets } if HasResultSet then begin Result := True; LastResultSet := CreateResultSet(LogSQL); end { Processes regular query. } else begin Result := False; LastUpdateCount := FPlainDriver.GetAffectedRows(FHandle); end; end else CheckMySQLError(FPlainDriver, FHandle, lcExecute, LogSQL); end; {** Moves to a Statement object's next result. It returns true if this result is a ResultSet object. This method also implicitly closes any current ResultSet object obtained with the method getResultSet.

There are no more results when the following is true:

        (!getMoreResults() && (getUpdateCount() == -1)
  
@return true if the next result is a ResultSet object; false if it is an update count or there are no more results @see #execute } function TZMySQLStatement.GetMoreResults: Boolean; var AStatus: integer; begin Result := inherited GetMoreResults; if FPlainDriver.GetClientVersion >= 40100 then begin AStatus := FPlainDriver.RetrieveNextRowset(FHandle); if AStatus > 0 then CheckMySQLError(FPlainDriver, FHandle, lcExecute, SSQL) else Result := (AStatus = 0); if LastResultSet <> nil then LastResultSet.Close; LastResultSet := nil; LastUpdateCount := -1; if FPlainDriver.ResultSetExists(FHandle) then LastResultSet := CreateResultSet(SSQL) else LastUpdateCount := FPlainDriver.GetAffectedRows(FHandle); end; end; { TZMySQLEmulatedPreparedStatement } {** Constructs this object and assignes the main properties. @param PlainDriver a native MySQL Plain driver. @param Connection a database connection object. @param Info a statement parameters. @param Handle a connection handle pointer. } constructor TZMySQLEmulatedPreparedStatement.Create(PlainDriver: IZMySQLPlainDriver; Connection: IZConnection; const SQL: string; Info: TStrings; Handle: PZMySQLConnect); begin inherited Create(Connection, SQL, Info); FHandle := Handle; FPlainDriver := PlainDriver; ResultSetType := rtScrollInsensitive; FUseDefaults := StrToBoolEx(DefineStatementParameter(Self, 'defaults', 'true')); end; {** Creates a temporary statement which executes queries. @param Info a statement parameters. @return a created statement object. } function TZMySQLEmulatedPreparedStatement.CreateExecStatement: IZStatement; begin Result := TZMySQLStatement.Create(FPlainDriver, Connection, Info,FHandle); end; {** Prepares an SQL parameter for the query. @param ParameterIndex the first parameter is 1, the second is 2, ... @return a string representation of the parameter. } function TZMySQLEmulatedPreparedStatement.PrepareAnsiSQLParam(ParamIndex: Integer): RawByteString; var Value: TZVariant; TempBytes: TByteDynArray; TempBlob: IZBlob; AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond: Word; begin TempBytes := nil; if InParamCount <= ParamIndex then raise EZSQLException.Create(SInvalidInputParameterCount); Value := InParamValues[ParamIndex]; if DefVarManager.IsNull(Value) then if FUseDefaults and (InParamDefaultValues[ParamIndex] <> '') then Result := ConSettings^.ConvFuncs.ZStringToRaw(InParamDefaultValues[ParamIndex], ConSettings^.CTRL_CP, ConSettings^.ClientCodePage^.CP) else Result := 'NULL' else begin case InParamTypes[ParamIndex] of stBoolean: if SoftVarManager.GetAsBoolean(Value) then Result := '''Y''' else Result := '''N'''; stByte, stShort, stInteger, stLong, stBigDecimal, stFloat, stDouble: Result := RawByteString(SoftVarManager.GetAsString(Value)); stBytes: begin TempBytes := SoftVarManager.GetAsBytes(Value); Result := GetSQLHexAnsiString(PAnsiChar(TempBytes), Length(TempBytes)); end; stString: Result := FPlainDriver.EscapeString(FHandle, ZPlainString(SoftVarManager.GetAsString(Value)), ConSettings, True); stUnicodeString: Result := FPlainDriver.EscapeString(FHandle, ZPlainString(SoftVarManager.GetAsUnicodeString(Value)), ConSettings, True); stDate: begin DecodeDateTime(SoftVarManager.GetAsDateTime(Value), AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond); Result := RawByteString('''' + Format('%0.4d-%0.2d-%0.2d', [AYear, AMonth, ADay]) + ''''); end; stTime: begin DecodeDateTime(SoftVarManager.GetAsDateTime(Value), AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond); Result := RawByteString('''' + Format('%0.2d:%0.2d:%0.2d', [AHour, AMinute, ASecond]) + ''''); end; stTimestamp: begin DecodeDateTime(SoftVarManager.GetAsDateTime(Value), AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond); Result := RawByteString('''' + Format('%0.4d-%0.2d-%0.2d %0.2d:%0.2d:%0.2d', [AYear, AMonth, ADay, AHour, AMinute, ASecond]) + ''''); end; stAsciiStream, stUnicodeStream, stBinaryStream: begin TempBlob := DefVarManager.GetAsInterface(Value) as IZBlob; if not TempBlob.IsEmpty then begin case InParamTypes[ParamIndex] of stBinaryStream: Result := GetSQLHexAnsiString(PAnsichar(TempBlob.GetBuffer), TempBlob.Length); else Result := FPlainDriver.EscapeString(FHandle, GetValidatedAnsiStringFromBuffer(TempBlob.GetBuffer, TempBlob.Length, TempBlob.WasDecoded, ConSettings), ConSettings, True); end; end else Result := 'NULL'; end; end; end; end; { TZMySQLPreparedStatement } {** Constructs this object and assignes the main properties. @param PlainDriver a Oracle plain driver. @param Connection a database connection object. @param Info a statement parameters. @param Handle a connection handle pointer. } constructor TZMySQLPreparedStatement.Create( PlainDriver: IZMySQLPlainDriver; Connection: IZConnection; const SQL: string; Info: TStrings); begin inherited Create(Connection, SQL, Info); FMySQLConnection := Connection as IZMySQLConnection; FHandle := FMysqlConnection.GetConnectionHandle; FPlainDriver := PlainDriver; ResultSetType := rtScrollInsensitive; FUseResult := StrToBoolEx(DefineStatementParameter(Self, 'useresult', 'false')); FUseDefaults := StrToBoolEx(DefineStatementParameter(Self, 'defaults', 'true')); Prepare; end; {** Destroys this object and cleanups the memory. } destructor TZMySQLPreparedStatement.Destroy; begin FStmtHandle := FPlainDriver.ClosePrepStmt(FStmtHandle); inherited Destroy; end; procedure TZMySQLPreparedStatement.Prepare; begin FStmtHandle := FPlainDriver.InitializePrepStmt(FHandle); if (FStmtHandle = nil) then begin CheckMySQLPrepStmtError(FPlainDriver, FStmtHandle, lcPrepStmt, SFailedtoInitPrepStmt); exit; end; if (FPlainDriver.PrepareStmt(FStmtHandle, PAnsiChar(ASQL), length(ASQL)) <> 0) then begin CheckMySQLPrepStmtError(FPlainDriver, FStmtHandle, lcPrepStmt, SFailedtoPrepareStmt); exit; end; LogPrepStmtMessage(lcPrepStmt, SQL); inherited Prepare; end; {** Checks is use result should be used in result sets. @return True use result in result sets, False store result in result sets. } function TZMySQLPreparedStatement.IsUseResult: Boolean; begin Result := FUseResult; end; {** Checks if this is a prepared mysql statement. @return True This is a prepared mysql statement. } function TZMySQLPreparedStatement.IsPreparedStatement: Boolean; begin Result := True; end; {** Creates a result set based on the current settings. @return a created result set object. } function TZMySQLPreparedStatement.CreateResultSet(const SQL: string): IZResultSet; var CachedResolver: TZMySQLCachedResolver; NativeResultSet: TZMySQLPreparedResultSet; CachedResultSet: TZCachedResultSet; begin NativeResultSet := TZMySQLPreparedResultSet.Create(FPlainDriver, Self, SQL, FHandle, FUseResult); NativeResultSet.SetConcurrency(rcReadOnly); if (GetResultSetConcurrency <> rcReadOnly) or (FUseResult and (GetResultSetType <> rtForwardOnly)) then begin CachedResolver := TZMySQLCachedResolver.Create(FPlainDriver, FHandle, (Self as IZMysqlStatement), NativeResultSet.GetMetaData); CachedResultSet := TZCachedResultSet.Create(NativeResultSet, SQL, CachedResolver, ConSettings); CachedResultSet.SetConcurrency(GetResultSetConcurrency); Result := CachedResultSet; end else Result := NativeResultSet; end; procedure TZMysqlPreparedStatement.BindInParameters; var PBuffer: Pointer; year, month, day, hour, minute, second, millisecond: word; MyType: TMysqlFieldTypes; I, OffSet, PieceSize: integer; TempBlob: IZBlob; TempAnsi: RawByteString; begin //http://dev.mysql.com/doc/refman/5.0/en/storage-requirements.html if InParamCount = 0 then exit; { Initialize Bind Array and Column Array } FParamBindBuffer := TZMySqlParamBindBuffer.Create(FPlainDriver,InParamCount,FColumnArray); For I := 0 to InParamCount - 1 do begin if (InParamValues[I].VType = vtNull) and (InParamDefaultValues[I] <> '') and StrToBoolEx(DefineStatementParameter(Self, 'defaults', 'true')) then SoftVarManager.SetAsString(InParamValues[I], Copy(InParamDefaultValues[I], 2, Length(InParamDefaultValues[I])-2)); MyType := GetFieldType(InParamValues[I]); case MyType of FIELD_TYPE_VARCHAR: begin TempAnsi := ZPlainString(InParamValues[I].VUnicodeString); FParamBindBuffer.AddColumn(FIELD_TYPE_STRING, Length(TempAnsi),false); end; FIELD_TYPE_STRING: begin TempAnsi := ZPlainString(InParamValues[I].VString); FParamBindBuffer.AddColumn(FIELD_TYPE_STRING, Length(TempAnsi),false); end; FIELD_TYPE_BLOB: begin TempBlob := (InParamValues[I].VInterface as IZBlob); if TempBlob.IsEmpty then DefVarManager.SetNull(InParamValues[I]) else if InParamTypes[I] = stBinaryStream then FParamBindBuffer.AddColumn(FIELD_TYPE_BLOB, TempBlob.Length, TempBlob.Length > ChunkSize) else begin TempAnsi := GetValidatedAnsiStringFromBuffer(TempBlob.GetBuffer, TempBlob.Length, TempBlob.WasDecoded, ConSettings); TempBlob := TZAbstractBlob.CreateWithData(PAnsiChar(TempAnsi), Length(TempAnsi)); TempBlob.SetString(TempAnsi); InParamValues[I].VInterface := TempBlob; FParamBindBuffer.AddColumn(FIELD_TYPE_STRING, TempBlob.Length, TempBlob.Length > ChunkSize); end; end; FIELD_TYPE_TINY: FParamBindBuffer.AddColumn(FIELD_TYPE_STRING,1,false); FIELD_TYPE_TINY_BLOB: FParamBindBuffer.AddColumn(MyType,Length(InParamValues[i].VBytes),false); else FParamBindBuffer.AddColumn(MyType,getMySQLFieldSize(MyType, 0),false); end; PBuffer := @FColumnArray[I].buffer[0]; if InParamValues[I].VType=vtNull then FColumnArray[I].is_null := 1 else FColumnArray[I].is_null := 0; case FParamBindBuffer.GetBufferType(I+1) of FIELD_TYPE_FLOAT: Single(PBuffer^) := InParamValues[I].VFloat; FIELD_TYPE_DOUBLE: Double(PBuffer^) := InParamValues[I].VFloat; FIELD_TYPE_STRING: case MyType of FIELD_TYPE_TINY: if InParamValues[I].VBoolean then PAnsiChar(PBuffer)^ := 'Y' else PAnsiChar(PBuffer)^ := 'N'; FIELD_TYPE_VARCHAR: System.Move(PAnsiChar(TempAnsi)^, PBuffer^, Length(TempAnsi)); FIELD_TYPE_BLOB: if not (Length(TempAnsi) > ChunkSize ) then System.Move(PAnsiChar(TempAnsi)^, PBuffer^, Length(TempAnsi)); else System.Move(PAnsiChar(TempAnsi)^, PBuffer^, Length(TempAnsi)); end; FIELD_TYPE_LONGLONG: Int64(PBuffer^) := InParamValues[I].VInteger; FIELD_TYPE_DATETIME: begin DecodeDateTime(InParamValues[I].VDateTime, Year, Month, Day, hour, minute, second, millisecond); PMYSQL_TIME(PBuffer)^.year := year; PMYSQL_TIME(PBuffer)^.month := month; PMYSQL_TIME(PBuffer)^.day := day; PMYSQL_TIME(PBuffer)^.hour := hour; PMYSQL_TIME(PBuffer)^.minute := minute; PMYSQL_TIME(PBuffer)^.second := second; PMYSQL_TIME(PBuffer)^.second_part := millisecond; end; FIELD_TYPE_TINY_BLOB: System.Move(PAnsiChar(InParamValues[i].VBytes)^, PBuffer^, Length(InParamValues[i].VBytes)); FIELD_TYPE_MEDIUM_BLOB, FIELD_TYPE_LONG_BLOB, FIELD_TYPE_BLOB: begin if TempBlob.Length<=ChunkSize then System.Move(TempBlob.GetBuffer^, PBuffer^, TempBlob.Length); TempBlob := nil; end; FIELD_TYPE_NULL:; end; end; if (FPlainDriver.BindParameters(FStmtHandle, FParamBindBuffer.GetBufferAddress) <> 0) then begin checkMySQLPrepStmtError (FPlainDriver, FStmtHandle, lcPrepStmt, SBindingFailure); exit; end; inherited BindInParameters; // Send large blobs in chuncks For I := 0 to InParamCount - 1 do begin if FParamBindBuffer.GetBufferType(I+1) in [FIELD_TYPE_STRING,FIELD_TYPE_BLOB] then begin MyType := GetFieldType(InParamValues[I]); if MyType = FIELD_TYPE_BLOB then begin TempBlob := (InParamValues[I].VInterface as IZBlob); if TempBlob.Length>ChunkSize then begin OffSet := 0; PieceSize := ChunkSize; while OffSet < TempBlob.Length do begin if OffSet+PieceSize > TempBlob.Length then PieceSize := TempBlob.Length - OffSet; if (FPlainDriver.SendPreparedLongData(FStmtHandle, I, PAnsiChar(TempBlob.GetBuffer)+OffSet, PieceSize) <> 0) then begin checkMySQLPrepStmtError (FPlainDriver, FStmtHandle, lcPrepStmt, SBindingFailure); exit; end; Inc(OffSet, PieceSize); end; end; TempBlob:=nil; end; end; end; end; procedure TZMySQLPreparedStatement.UnPrepareInParameters; begin // Empty : Mysql can't prepare datastructures before the actual parameters are known, because the // number/datatype of parameters isn't returned by the server. inherited UnPrepareInParameters; end; function TZMysqlPreparedStatement.getFieldType (testVariant: TZVariant): TMysqlFieldTypes; begin case testVariant.vType of vtNull: Result := FIELD_TYPE_TINY; vtBoolean: Result := FIELD_TYPE_TINY; vtBytes: Result := FIELD_TYPE_TINY_BLOB; vtInteger: Result := FIELD_TYPE_LONGLONG; vtFloat: Result := FIELD_TYPE_DOUBLE; vtString: Result := FIELD_TYPE_STRING; vtDateTime: Result := FIELD_TYPE_DATETIME; vtUnicodeString: Result := FIELD_TYPE_VARCHAR; vtInterface: Result := FIELD_TYPE_BLOB; else raise EZSQLException.Create(SUnsupportedDataType); end; end; {** Executes the SQL query in this PreparedStatement object and returns the result set generated by the query. @return a ResultSet object that contains the data produced by the query; never null } function TZMySQLPreparedStatement.ExecuteQueryPrepared: IZResultSet; begin Result := nil; BindInParameters; if (self.FPlainDriver.ExecuteStmt(FStmtHandle) <> 0) then try checkMySQLPrepStmtError(FPlainDriver,FStmtHandle, lcExecPrepStmt, SPreparedStmtExecFailure); except if Assigned(FParamBindBuffer) then FreeAndNil(FParamBindBuffer); raise; end; if Assigned(FParamBindBuffer) then FreeAndNil(FParamBindBuffer); if FPlainDriver.GetPreparedFieldCount(FStmtHandle) = 0 then raise EZSQLException.Create(SCanNotOpenResultSet); Result := CreateResultSet(SQL); inherited ExecuteQueryPrepared; end; {** Executes the SQL INSERT, UPDATE or DELETE statement in this PreparedStatement object. In addition, SQL statements that return nothing, such as SQL DDL statements, can be executed. @return either the row count for INSERT, UPDATE or DELETE statements; or 0 for SQL statements that return nothing } function TZMySQLPreparedStatement.ExecuteUpdatePrepared: Integer; begin BindInParameters; if (self.FPlainDriver.ExecuteStmt(FStmtHandle) <> 0) then try checkMySQLPrepStmtError(FPlainDriver,FStmtHandle, lcExecPrepStmt, SPreparedStmtExecFailure); except if Assigned(FParamBindBuffer) then FreeAndNil(FParamBindBuffer); //MemLeak closed raise; end; if Assigned(FParamBindBuffer) then FreeAndNil(FParamBindBuffer); //MemLeak closed { Process queries with result sets } if FPlainDriver.GetPreparedFieldCount(FStmtHandle) > 0 then begin FPlainDriver.StorePreparedResult(FStmtHandle); Result := FPlainDriver.GetPreparedAffectedRows(FStmtHandle); if Assigned(FStmtHandle) then begin FPlainDriver.FreePreparedResult(FStmtHandle); while(FPlainDriver.GetPreparedNextResult(FStmtHandle) = 0) do FPlainDriver.FreePreparedResult(FStmtHandle); end; end { Process regular query } else Result := FPlainDriver.GetPreparedAffectedRows(FStmtHandle); LastUpdateCount := Result; Inherited ExecuteUpdatePrepared; end; {** Executes any kind of SQL statement. Some prepared statements return multiple results; the execute method handles these complex statements as well as the simpler form of statements handled by the methods executeQuery and executeUpdate. @see Statement#execute } function TZMySQLPreparedStatement.ExecutePrepared: Boolean; begin BindInParameters; if (FPlainDriver.ExecuteStmt(FStmtHandle) <> 0) then try checkMySQLPrepStmtError(FPlainDriver,FStmtHandle, lcExecPrepStmt, SPreparedStmtExecFailure); except if Assigned(FParamBindBuffer) then FreeAndNil(FParamBindBuffer); //MemLeak closed raise; end; if Assigned(FParamBindBuffer) then FreeAndNil(FParamBindBuffer); //MemLeak closed if FPlainDriver.GetPreparedFieldCount(FStmtHandle) > 0 then begin Result := True; LastResultSet := CreateResultSet(SQL); end { Processes regular query. } else begin Result := False; LastUpdateCount := FPlainDriver.GetPreparedAffectedRows(FStmtHandle); end; inherited ExecutePrepared; end; function TZMySQLPreparedStatement.GetStmtHandle: PZMySqlPrepStmt; begin Result := FStmtHandle; end; { TZMySQLCallableStatement } {** Create sql string for calling stored procedure. @return a Stored Procedure SQL string } function TZMySQLCallableStatement.GetCallSQL: RawByteString; function GenerateParamsStr(Count: integer): RawByteString; var I: integer; begin Result := ''; for I := 0 to Count-1 do begin if I > 0 then Result := Result + ', '; if FDBParamTypes[i] in [1, 2, 3, 4] then Result := Result + '@'+ZPlainString(FParamNames[I]) end; end; var InParams: RawByteString; begin if HasOutParameter then InParams := GenerateParamsStr(OutParamCount) else InParams := GenerateParamsStr(InParamCount); Result := 'CALL '+ZPlainString(SQL)+'('+InParams+')'; end; function TZMySQLCallableStatement.GetOutParamSQL: String; function GenerateParamsStr(Count: integer): string; var I: integer; begin Result := ''; I := 0; while True do if (FDBParamTypes[i] = 0) or ( I = Length(FDBParamTypes)) then break else begin if FDBParamTypes[i] in [2, 3, 4] then begin if Result <> '' then Result := Result + ','; if FParamTypeNames[i] = '' then Result := Result + ' @'+FParamNames[I]+' AS '+FParamNames[I] else Result := Result + ' CAST(@'+FParamNames[I]+ ' AS '+FParamTypeNames[i]+') AS '+FParamNames[I]; end; Inc(i); end; end; var OutParams: String; begin OutParams := GenerateParamsStr(Self.OutParamCount-Length(InParamValues)); Result := 'SELECT '+ OutParams; end; function TZMySQLCallableStatement.GetSelectFunctionSQL: RawByteString; function GenerateInParamsStr: RawByteString; var I: Integer; begin Result := ''; for i := 0 to Length(InParamValues) -1 do if Result = '' then Result := PrepareAnsiSQLParam(I) else Result := Result+', '+ PrepareAnsiSQLParam(I); end; var InParams: RawByteString; begin InParams := GenerateInParamsStr; Result := 'SELECT '+ZPlainString(SQL)+'('+InParams+')'; Result := Result + ' AS ReturnValue'; end; {** Executes an SQL INSERT, UPDATE or DELETE statement. In addition, SQL statements that return nothing, such as SQL DDL statements, can be executed. @param sql an SQL INSERT, UPDATE or DELETE statement or an SQL statement that returns nothing @return either the row count for INSERT, UPDATE or DELETE statements, or 0 for SQL statements that return nothing } function TZMySQLCallableStatement.PrepareAnsiSQLParam(ParamIndex: Integer): RawByteString; var Value: TZVariant; TempBytes: TByteDynArray; TempBlob: IZBlob; AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond: Word; begin TempBytes := nil; if InParamCount <= ParamIndex then raise EZSQLException.Create(SInvalidInputParameterCount); Value := InParamValues[ParamIndex]; if DefVarManager.IsNull(Value) then if FUseDefaults and (InParamDefaultValues[ParamIndex] <> '') then Result := ConSettings^.ConvFuncs.ZStringToRaw(InParamDefaultValues[ParamIndex], ConSettings^.CTRL_CP, ConSettings^.ClientCodePage^.CP) else Result := 'NULL' else begin case InParamTypes[ParamIndex] of stBoolean: if SoftVarManager.GetAsBoolean(Value) then Result := '''Y''' else Result := '''N'''; stByte, stShort, stInteger, stLong, stBigDecimal, stFloat, stDouble: Result := RawByteString(SoftVarManager.GetAsString(Value)); stBytes: begin TempBytes := SoftVarManager.GetAsBytes(Value); Result := GetSQLHexAnsiString(PAnsiChar(TempBytes), Length(TempBytes)); end; stString: Result := FPlainDriver.EscapeString(FHandle, ZPlainString(SoftVarManager.GetAsString(Value), ConSettings), ConSettings, True); stUnicodeString: Result := FPlainDriver.EscapeString(FHandle, ZPlainString(SoftVarManager.GetAsUnicodeString(Value)), ConSettings, True); stDate: begin DecodeDateTime(SoftVarManager.GetAsDateTime(Value), AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond); Result := '''' + RawByteString(Format('%0.4d-%0.2d-%0.2d', [AYear, AMonth, ADay])) + ''''; end; stTime: begin DecodeDateTime(SoftVarManager.GetAsDateTime(Value), AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond); Result := '''' + RawByteString(Format('%0.2d:%0.2d:%0.2d', [AHour, AMinute, ASecond])) + ''''; end; stTimestamp: begin DecodeDateTime(SoftVarManager.GetAsDateTime(Value), AYear, AMonth, ADay, AHour, AMinute, ASecond, AMilliSecond); Result := '''' + RawByteString(Format('%0.4d-%0.2d-%0.2d %0.2d:%0.2d:%0.2d', [AYear, AMonth, ADay, AHour, AMinute, ASecond])) + ''''; end; stAsciiStream, stUnicodeStream, stBinaryStream: begin TempBlob := DefVarManager.GetAsInterface(Value) as IZBlob; if not TempBlob.IsEmpty then case InParamTypes[ParamIndex] of stBinaryStream: Result := GetSQLHexAnsiString(PAnsichar(TempBlob.GetBuffer), TempBlob.Length); else Result := FPlainDriver.EscapeString(FHandle, GetValidatedAnsiStringFromBuffer(TempBlob.GetBuffer, TempBlob.Length, TempBlob.WasDecoded, ConSettings), ConSettings, True); end else Result := 'NULL'; end; end; end; end; function TZMySQLCallableStatement.GetStmtHandle: PZMySqlPrepStmt; begin Result := nil; end; procedure TZMySQLCallableStatement.ClearResultSets; begin inherited; FPlainDriver.FreeResult(FQueryHandle); FQueryHandle := nil; end; procedure TZMySQLCallableStatement.BindInParameters; var I: integer; ExecQuery: RawByteString; begin I := 0; ExecQuery := ''; while True do if (i = Length(FDBParamTypes)) then break else begin if FDBParamTypes[i] in [1, 3] then //ptInputOutput if ExecQuery = '' then ExecQuery := 'SET @'+ZPlainString(FParamNames[i])+' = '+PrepareAnsiSQLParam(I) else ExecQuery := ExecQuery + ', @'+ZPlainString(FParamNames[i])+' = '+PrepareAnsiSQLParam(I); Inc(i); end; if not (ExecQuery = '') then if FPlainDriver.ExecQuery(Self.FHandle, PAnsiChar(ExecQuery)) = 0 then DriverManager.LogMessage(lcBindPrepStmt, FPlainDriver.GetProtocol, String(ExecQuery)) else CheckMySQLError(FPlainDriver, FHandle, lcExecute, String(ExecQuery)); end; {** Creates a result set based on the current settings. @return a created result set object. } function TZMySQLCallableStatement.CreateResultSet(const SQL: string): IZResultSet; var CachedResolver: TZMySQLCachedResolver; NativeResultSet: TZMySQLResultSet; CachedResultSet: TZCachedResultSet; begin NativeResultSet := TZMySQLResultSet.Create(FPlainDriver, Self, SQL, FHandle, FUseResult, @LastUpdateCount, not IsFunction); NativeResultSet.SetConcurrency(rcReadOnly); if (GetResultSetConcurrency <> rcReadOnly) or (FUseResult and (GetResultSetType <> rtForwardOnly)) or (not IsFunction) then begin CachedResolver := TZMySQLCachedResolver.Create(FPlainDriver, FHandle, Self, NativeResultSet.GetMetaData); CachedResultSet := TZCachedResultSet.Create(NativeResultSet, SQL, CachedResolver, ConSettings); CachedResultSet.SetConcurrency(rcReadOnly); {Need to fetch all data. The handles must be released for mutiple Resultsets} CachedResultSet.AfterLast;//Fetch all CachedResultSet.BeforeFirst;//Move to first pos NativeResultSet.ReleaseHandle; //Release the handles Result := CachedResultSet; end else Result := NativeResultSet; end; {** Sets output parameters from a ResultSet @param Value a IZResultSet object. } procedure TZMySQLCallableStatement.FetchOutParams(ResultSet: IZResultSet); var ParamIndex, I: Integer; Temp: TZVariant; HasRows: Boolean; begin ResultSet.BeforeFirst; HasRows := ResultSet.Next; I := 1; for ParamIndex := 0 to OutParamCount - 1 do begin if not (FDBParamTypes[ParamIndex] in [2, 3, 4]) then // ptOutput, ptInputOutput, ptResult Continue; if I > ResultSet.GetMetadata.GetColumnCount then Break; if (not HasRows) or (ResultSet.IsNull(I)) then DefVarManager.SetNull(Temp) else case ResultSet.GetMetadata.GetColumnType(I) of stBoolean: DefVarManager.SetAsBoolean(Temp, ResultSet.GetBoolean(I)); stByte: DefVarManager.SetAsInteger(Temp, ResultSet.GetByte(I)); stBytes: DefVarManager.SetAsBytes(Temp, ResultSet.GetBytes(I)); stShort: DefVarManager.SetAsInteger(Temp, ResultSet.GetShort(I)); stInteger: DefVarManager.SetAsInteger(Temp, ResultSet.GetInt(I)); stLong: DefVarManager.SetAsInteger(Temp, ResultSet.GetLong(I)); stFloat: DefVarManager.SetAsFloat(Temp, ResultSet.GetFloat(I)); stDouble: DefVarManager.SetAsFloat(Temp, ResultSet.GetDouble(I)); stBigDecimal: DefVarManager.SetAsFloat(Temp, ResultSet.GetBigDecimal(I)); stString, stAsciiStream: DefVarManager.SetAsString(Temp, ResultSet.GetString(I)); stUnicodeString, stUnicodeStream: DefVarManager.SetAsUnicodeString(Temp, ResultSet.GetUnicodeString(I)); stDate: DefVarManager.SetAsDateTime(Temp, ResultSet.GetDate(I)); stTime: DefVarManager.SetAsDateTime(Temp, ResultSet.GetTime(I)); stTimestamp: DefVarManager.SetAsDateTime(Temp, ResultSet.GetTimestamp(I)); stBinaryStream: DefVarManager.SetAsInterface(Temp, ResultSet.GetBlob(I)); else DefVarManager.SetAsString(Temp, ResultSet.GetString(I)); end; OutParamValues[ParamIndex] := Temp; Inc(I); end; ResultSet.BeforeFirst; end; procedure TZMySQLCallableStatement.RegisterParamTypeAndName(const ParameterIndex:integer; const ParamTypeName, ParamName: String; Const ColumnSize, Precision: Integer); begin FParamNames[ParameterIndex] := ParamName; if ( Pos('char', LowerCase(ParamTypeName)) > 0 ) or ( Pos('set', LowerCase(ParamTypeName)) > 0 ) then FParamTypeNames[ParameterIndex] := 'CHAR('+IntToStr(ColumnSize)+')' else if ( Pos('set', LowerCase(ParamTypeName)) > 0 ) then FParamTypeNames[ParameterIndex] := 'CHAR('+IntToStr(ColumnSize)+')' else if ( Pos('datetime', LowerCase(ParamTypeName)) > 0 ) or ( Pos('timestamp', LowerCase(ParamTypeName)) > 0 ) then FParamTypeNames[ParameterIndex] := 'DATETIME' else if ( Pos('date', LowerCase(ParamTypeName)) > 0 ) then FParamTypeNames[ParameterIndex] := 'DATE' else if ( Pos('time', LowerCase(ParamTypeName)) > 0 ) then FParamTypeNames[ParameterIndex] := 'TIME' else if ( Pos('int', LowerCase(ParamTypeName)) > 0 ) or ( Pos('year', LowerCase(ParamTypeName)) > 0 ) then FParamTypeNames[ParameterIndex] := 'SIGNED' else if ( Pos('binary', LowerCase(ParamTypeName)) > 0 ) then FParamTypeNames[ParameterIndex] := 'BINARY('+IntToStr(ColumnSize)+')' else FParamTypeNames[ParameterIndex] := ''; end; constructor TZMySQLCallableStatement.Create(PlainDriver: IZMySQLPlainDriver; Connection: IZConnection; const SQL: string; Info: TStrings; Handle: PZMySQLConnect); begin inherited Create(Connection, SQL, Info); FHandle := Handle; FPlainDriver := PlainDriver; ResultSetType := rtScrollInsensitive; FUseResult := StrToBoolEx(DefineStatementParameter(Self, 'useresult', 'false')); FUseDefaults := StrToBoolEx(DefineStatementParameter(Self, 'defaults', 'true')) end; {** Executes an SQL statement that returns a single ResultSet object. @param sql typically this is a static SQL SELECT statement @return a ResultSet object that contains the data produced by the given query; never null } function TZMySQLCallableStatement.ExecuteQuery(const SQL: RawByteString): IZResultSet; begin Result := nil; ASQL := SQL; if FPlainDriver.ExecQuery(FHandle, PAnsiChar(SQL)) = 0 then begin DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, SSQL); if not FPlainDriver.ResultSetExists(FHandle) then raise EZSQLException.Create(SCanNotOpenResultSet); if IsFunction then ClearResultSets; FResultSets.Add(CreateResultSet(SSQL)); if FPlainDriver.CheckAnotherRowset(FHandle) then begin while FPlainDriver.RetrieveNextRowset(FHandle) = 0 do if FPlainDriver.CheckAnotherRowset(FHandle) then FResultSets.Add(CreateResultSet(SSQL)) else break; CheckMySQLError(FPlainDriver, FHandle, lcExecute, SSQL); end; FActiveResultset := FResultSets.Count-1; Result := IZResultSet(FResultSets[FActiveResultset]); end else CheckMySQLError(FPlainDriver, FHandle, lcExecute, SSQL); end; {** Executes an SQL INSERT, UPDATE or DELETE statement. In addition, SQL statements that return nothing, such as SQL DDL statements, can be executed. @param sql an SQL INSERT, UPDATE or DELETE statement or an SQL statement that returns nothing @return either the row count for INSERT, UPDATE or DELETE statements, or 0 for SQL statements that return nothing } function TZMySQLCallableStatement.ExecuteUpdate(const SQL: RawByteString): Integer; begin Result := -1; ASQL := SQL; if FPlainDriver.ExecQuery(FHandle, PAnsiChar(ASQL)) = 0 then begin { Process queries with result sets } if FPlainDriver.ResultSetExists(FHandle) then begin ClearResultSets; FActiveResultset := 0; FResultSets.Add(CreateResultSet(LogSQL)); if FPlainDriver.CheckAnotherRowset(FHandle) then begin Result := LastUpdateCount; while FPlainDriver.RetrieveNextRowset(FHandle) = 0 do if FPlainDriver.CheckAnotherRowset(FHandle) then begin FResultSets.Add(CreateResultSet(SSQL)); inc(Result, LastUpdateCount); //LastUpdateCount will be returned from ResultSet.Open end else break; CheckMySQLError(FPlainDriver, FHandle, lcExecute, SSQL); end else Result := LastUpdateCount; FActiveResultset := FResultSets.Count-1; LastResultSet := IZResultSet(FResultSets[FActiveResultset]); end else { Process regular query } Result := FPlainDriver.GetAffectedRows(FHandle); end else CheckMySQLError(FPlainDriver, FHandle, lcExecute, SSQL); LastUpdateCount := Result; end; {** Executes an SQL statement that may return multiple results. Under some (uncommon) situations a single SQL statement may return multiple result sets and/or update counts. Normally you can ignore this unless you are (1) executing a stored procedure that you know may return multiple results or (2) you are dynamically executing an unknown SQL string. The methods execute, getMoreResults, getResultSet, and getUpdateCount let you navigate through multiple results. The execute method executes an SQL statement and indicates the form of the first result. You can then use the methods getResultSet or getUpdateCount to retrieve the result, and getMoreResults to move to any subsequent result(s). @param sql any SQL statement @return true if the next result is a ResultSet object; false if it is an update count or there are no more results } function TZMySQLCallableStatement.Execute(const SQL: RawByteString): Boolean; var HasResultset : Boolean; begin Result := False; {$IFNDEF UNICODE}ASQL := SQL;{$ENDIF} if FPlainDriver.ExecQuery(FHandle, PAnsiChar(ASQL)) = 0 then begin DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, LogSQL); HasResultSet := FPlainDriver.ResultSetExists(FHandle); { Process queries with result sets } if HasResultSet then begin Result := True; LastResultSet := CreateResultSet(LogSQL); end { Processes regular query. } else begin Result := False; LastUpdateCount := FPlainDriver.GetAffectedRows(FHandle); end; end else CheckMySQLError(FPlainDriver, FHandle, lcExecute, LogSQL); end; {** Executes the SQL query in this PreparedStatement object and returns the result set generated by the query. @return a ResultSet object that contains the data produced by the query; never null } function TZMySQLCallableStatement.ExecuteQueryPrepared: IZResultSet; begin if IsFunction then begin TrimInParameters; Result := ExecuteQuery(GetSelectFunctionSQL); end else begin BindInParameters; ExecuteUpdate(GetCallSQL); if OutParamCount > 0 then Result := ExecuteQuery(ZPlainString(GetOutParamSQL)) //Get the Last Resultset else Result := GetLastResultSet; end; if Assigned(Result) then FetchOutParams(Result); end; {** Executes the SQL INSERT, UPDATE or DELETE statement in this PreparedStatement object. In addition, SQL statements that return nothing, such as SQL DDL statements, can be executed. @return either the row count for INSERT, UPDATE or DELETE statements; or 0 for SQL statements that return nothing } function TZMySQLCallableStatement.ExecuteUpdatePrepared: Integer; begin if IsFunction then begin TrimInParameters; Result := ExecuteUpdate(GetSelectFunctionSQL); FetchOutParams(LastResultSet); end else begin BindInParameters; Result := ExecuteUpdate(GetCallSQL); if OutParamCount > 0 then FetchOutParams(ExecuteQuery(ZPlainString(GetOutParamSQL))); //Get the Last Resultset Inc(Result, LastUpdateCount); end; end; {** Checks is use result should be used in result sets. @return True use result in result sets, False store result in result sets. } function TZMySQLCallableStatement.IsUseResult: Boolean; begin Result := FUseResult; end; {** Checks if this is a prepared mysql statement. @return False This is not a prepared mysql statement. } function TZMySQLCallableStatement.IsPreparedStatement: Boolean; begin Result := False; end; {** Are more resultsets retrieved? @result Returns True if more resultsets are retrieved } function TZMySQLCallableStatement.HasMoreResultSets: Boolean; begin Result := FResultSets.Count > 1; end; {** Get the first resultset.. @result IZResultSet if supported } function TZMySQLCallableStatement.GetNextResultSet: IZResultSet; begin if ( FActiveResultset < FResultSets.Count-1) and ( FResultSets.Count > 1) then begin Inc(FActiveResultset); Result := IZResultSet(FResultSets[FActiveResultset]); end else if FResultSets.Count = 0 then Result := nil else Result := IZResultSet(FResultSets[FActiveResultset]); end; {** Get the previous resultset.. @result IZResultSet if supported } function TZMySQLCallableStatement.GetPreviousResultSet: IZResultSet; begin if ( FActiveResultset > 0) and ( FResultSets.Count > 0) then begin Dec(FActiveResultset); Result := IZResultSet(FResultSets[FActiveResultset]); end else if FResultSets.Count = 0 then Result := nil else Result := IZResultSet(FResultSets[FActiveResultset]); end; {** Get the next resultset.. @result IZResultSet if supported } function TZMySQLCallableStatement.GetFirstResultSet: IZResultSet; begin if FResultSets.Count = 0 then Result := nil else begin FActiveResultset := 0; Result := IZResultSet(FResultSets[0]); end; end; {** Get the last resultset.. @result IZResultSet if supported } function TZMySQLCallableStatement.GetLastResultSet: IZResultSet; begin if FResultSets.Count = 0 then Result := nil else begin FActiveResultset := FResultSets.Count -1; Result := IZResultSet(FResultSets[FResultSets.Count -1]); end; end; {** First ResultSet? @result True if first ResultSet } function TZMySQLCallableStatement.BOR: Boolean; begin Result := FActiveResultset = 0; end; {** Last ResultSet? @result True if Last ResultSet } function TZMySQLCallableStatement.EOR: Boolean; begin Result := FActiveResultset = FResultSets.Count -1; end; {** Retrieves a ResultSet by his index. @param Integer the index of the Resultset @result IZResultSet of the Index or nil. } function TZMySQLCallableStatement.GetResultSetByIndex(const Index: Integer): IZResultSet; begin Result := nil; if ( Index < 0 ) or ( Index > FResultSets.Count -1 ) then raise Exception.Create(Format(SListIndexError, [Index])) else Result := IZResultSet(FResultSets[Index]); end; {** Returns the Count of retrived ResultSets. @result Integer Count } function TZMySQLCallableStatement.GetResultSetCount: Integer; begin Result := FResultSets.Count; end; { TZMySQLAbstractBindBuffer } constructor TZMySQLAbstractBindBuffer.Create(PlainDriver: IZMysqlPlainDriver; const BindCount: Integer; var ColumnArray: TZMysqlColumnBuffer); begin inherited Create; FBindOffsets := PlainDriver.GetBindOffsets; if FBindOffsets.buffer_type=0 then raise EZSQLException.Create('Unknown dll version : '+IntToStr(PlainDriver.GetClientVersion)); FPColumnArray := @ColumnArray; setlength(FBindArray,0); setlength(ColumnArray,BindCount); setlength(FBindArray,BindCount*FBindOffsets.size); end; function TZMySQLAbstractBindBuffer.GetColumnArray: TZMysqlColumnBuffer; begin result := FPColumnArray^; end; function TZMySQLAbstractBindBuffer.GetBufferAddress: Pointer; begin result := @FBindArray[0]; end; function TZMySQLAbstractBindBuffer.GetBufferType(ColumnIndex: Integer): TMysqlFieldTypes; begin result := PTMysqlFieldTypes(@FbindArray[NativeUInt((ColumnIndex-1)*FBindOffsets.size)+FBindOffsets.buffer_type])^; end; function TZMySQLAbstractBindBuffer.GetBufferIsSigned(ColumnIndex: Integer): Boolean; begin result := PByte(@FbindArray[NativeUInt((ColumnIndex-1)*FBindOffsets.size)+FBindOffsets.is_unsigned])^ <> 0; end; { TZMySQLResultSetBindBuffer } procedure TZMySQLResultSetBindBuffer.AddColumn(PlainDriver: IZMysqlPlainDriver; const FieldHandle: PZMySQLField); var buffertype: TMysqlFieldTypes; ColOffset: NativeUInt; begin buffertype := PlainDriver.GetFieldType(FieldHandle); Inc(FAddedColumnCount); With FPColumnArray^[FAddedColumnCount-1] do begin case buffertype of FIELD_TYPE_DATE: Length := sizeOf(MYSQL_TIME); FIELD_TYPE_TIME: Length := sizeOf(MYSQL_TIME); FIELD_TYPE_DATETIME: Length := sizeOf(MYSQL_TIME); FIELD_TYPE_TIMESTAMP: Length := sizeOf(MYSQL_TIME); FIELD_TYPE_TINY: Length := 1; FIELD_TYPE_SHORT: Length := 2; FIELD_TYPE_LONG: Length := 4; FIELD_TYPE_LONGLONG: Length := 8; FIELD_TYPE_FLOAT: Length := 4; FIELD_TYPE_DOUBLE: Length := 8; FIELD_TYPE_NEWDECIMAL: Length := 11; FIELD_TYPE_BLOB, FIELD_TYPE_MEDIUM_BLOB, FIELD_TYPE_LONG_BLOB, FIELD_TYPE_GEOMETRY: Length := PlainDriver.GetFieldMaxLength(FieldHandle)+1; FIELD_TYPE_VARCHAR, FIELD_TYPE_VAR_STRING, FIELD_TYPE_STRING: Length := Min(MaxBlobSize, Max(PlainDriver.GetFieldLength(FieldHandle), PlainDriver.GetFieldMaxLength(FieldHandle)))+1; else Length := PlainDriver.GetFieldLength(FieldHandle); end; SetLength(Buffer, Length); end; ColOffset := NativeUInt((FAddedColumnCount-1)*FBindOffsets.size); PTMysqlFieldTypes(@FbindArray[ColOffset+FBindOffsets.buffer_type])^ := buffertype; PULong(@FbindArray[ColOffset+FBindOffsets.buffer_length])^ := FPColumnArray^[FAddedColumnCount-1].length; PByte(@FbindArray[ColOffset+FBindOffsets.is_unsigned])^:= PlainDriver.GetFieldFlags(FieldHandle) and UNSIGNED_FLAG; PPointer(@FbindArray[ColOffset+FBindOffsets.buffer])^:= @FPColumnArray^[FAddedColumnCount-1].buffer[0]; PPointer(@FbindArray[ColOffset+FBindOffsets.length])^:= @FPColumnArray^[FAddedColumnCount-1].length; PPointer(@FbindArray[ColOffset+FBindOffsets.is_null])^:= @FPColumnArray^[FAddedColumnCount-1].is_null; end; { TZMySQLParamBindBuffer } // largeblobparameter: true to indicate that parameter is a blob that will be // sent chunked. Set to false for result set columns. procedure TZMySQLParamBindBuffer.AddColumn(buffertype: TMysqlFieldTypes; const field_length: integer; const largeblobparameter: boolean); var tempbuffertype: TMysqlFieldTypes; ColOffset:NativeUInt; begin Case buffertype of FIELD_TYPE_DECIMAL, FIELD_TYPE_NEWDECIMAL: tempbuffertype := FIELD_TYPE_DOUBLE; Else tempbuffertype := buffertype; End; Inc(FAddedColumnCount); With FPColumnArray^[FAddedColumnCount-1] do begin length := getMySQLFieldSize(tempbuffertype,field_length); if largeblobparameter then begin is_Null := 0; buffer := nil; end else if field_length = 0 then begin is_Null := 1; buffer := nil; end else begin if tempbuffertype in [FIELD_TYPE_TINY_BLOB, FIELD_TYPE_MEDIUM_BLOB, FIELD_TYPE_LONG_BLOB, FIELD_TYPE_BLOB, FIELD_TYPE_VAR_STRING, FIELD_TYPE_STRING] then //ludob: mysql adds terminating #0 on top of data. Avoid buffer overrun. SetLength(buffer,length+1) else SetLength(buffer,length); is_null := 0; end; end; ColOffset:=NativeUInt((FAddedColumnCount-1)*FBindOffsets.size); PTMysqlFieldTypes(@FbindArray[ColOffset+FBindOffsets.buffer_type])^:=tempbuffertype; PULong(@FbindArray[ColOffset+FBindOffsets.buffer_length])^ := FPColumnArray^[FAddedColumnCount-1].length; PByte(@FbindArray[ColOffset+FBindOffsets.is_unsigned])^:= 0; PPointer(@FbindArray[ColOffset+FBindOffsets.buffer])^:= @FPColumnArray^[FAddedColumnCount-1].buffer[0]; PPointer(@FbindArray[ColOffset+FBindOffsets.length])^:= @FPColumnArray^[FAddedColumnCount-1].length; PPointer(@FbindArray[ColOffset+FBindOffsets.is_null])^:= @FPColumnArray^[FAddedColumnCount-1].is_null; end; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcMySqlUtils.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { MySQL Database Connectivity Classes } { } { Originally written by Sergey Seroukhov } { and Sergey Merkuriev } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcMySqlUtils; interface {$I ZDbc.inc} uses Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, StrUtils, ZSysUtils, ZDbcIntfs, ZPlainMySqlDriver, ZPlainMySqlConstants, ZDbcLogging, ZCompatibility, ZDbcResultSetMetadata; const MAXBUF = 65535; type {** Silent exception } EZMySQLSilentException = class(EAbort); {** Converts a MySQL native types into ZDBC SQL types. @param PlainDriver a native MySQL plain driver. @param FieldHandle a handler to field description structure. @param FieldFlags field flags. @return a SQL undepended type. } function ConvertMySQLHandleToSQLType(PlainDriver: IZMySQLPlainDriver; FieldHandle: PZMySQLField; FieldFlags: Integer; const CtrlsCPType: TZControlsCodePage): TZSQLType; {** Convert string mysql field type to SQLType @param string field type value @result the SQLType field type value } function ConvertMySQLTypeToSQLType(TypeName, TypeNameFull: string; const CtrlsCPType: TZControlsCodePage): TZSQLType; {** Checks for possible sql errors. @param PlainDriver a MySQL plain driver. @param Handle a MySQL connection handle. @param LogCategory a logging category. @param LogMessage a logging message. } procedure CheckMySQLError(PlainDriver: IZMySQLPlainDriver; Handle: PZMySQLConnect; LogCategory: TZLoggingCategory; const LogMessage: string); procedure CheckMySQLPrepStmtError(PlainDriver: IZMySQLPlainDriver; Handle: PZMySQLConnect; LogCategory: TZLoggingCategory; const LogMessage: string); procedure EnterSilentMySQLError; procedure LeaveSilentMySQLError; {** Decodes a MySQL Version Value encoded with format: (major_version * 10,000) + (minor_version * 100) + sub_version into separated major, minor and subversion values @param MySQLVersion an integer containing the MySQL Full Version to decode. @param MajorVersion an integer containing the Major Version decoded. @param MinorVersion an integer containing the Minor Version decoded. @param SubVersion an integer contaning the Sub Version (revision) decoded. } procedure DecodeMySQLVersioning(const MySQLVersion: Integer; out MajorVersion: Integer; out MinorVersion: Integer; out SubVersion: Integer); {** Encodes major, minor and subversion (revision) values in MySQL format: (major_version * 10,000) + (minor_version * 100) + sub_version For example, 4.1.12 is returned as 40112. @param MajorVersion an integer containing the Major Version. @param MinorVersion an integer containing the Minor Version. @param SubVersion an integer containing the Sub Version (revision). @return an integer containing the full version. } function EncodeMySQLVersioning(const MajorVersion: Integer; const MinorVersion: Integer; const SubVersion: Integer): Integer; {** Decodes a MySQL Version Value and Encodes it to a Zeos SQL Version format: (major_version * 1,000,000) + (minor_version * 1,000) + sub_version into separated major, minor and subversion values @param MySQLVersion an integer containing the Full Version to decode. @return Encoded Zeos SQL Version Value. } function ConvertMySQLVersionToSQLVersion( const MySQLVersion: Integer ): Integer; function getMySQLFieldSize (field_type: TMysqlFieldTypes; field_size: LongWord): LongWord; {** Returns a valid TZColumnInfo from a FieldHandle @param PlainDriver the MySQL PlainDriver interface @param FieldHandle the handle of the fetched field @returns a new TZColumnInfo } function GetMySQLColumnInfoFromFieldHandle(PlainDriver: IZMySQLPlainDriver; const FieldHandle: PZMySQLField; ConSettings: PZConSettings; const bUseResult:boolean): TZColumnInfo; procedure ConvertMySQLColumnInfoFromString(const TypeInfo: String; ConSettings: PZConSettings; out TypeName, TypeInfoSecond: String; out FieldType: TZSQLType; out ColumnSize: Integer; out Precision: Integer); implementation uses ZMessages, Math, ZDbcUtils; threadvar SilentMySQLError: Integer; procedure EnterSilentMySQLError; begin Inc(SilentMySQLError); end; procedure LeaveSilentMySQLError; begin Dec(SilentMySQLError); end; {** Converts a MySQL native types into ZDBC SQL types. @param PlainDriver a native MySQL plain driver. @param FieldHandle a handler to field description structure. @param FieldFlags a field flags. @return a SQL undepended type. } function ConvertMySQLHandleToSQLType(PlainDriver: IZMySQLPlainDriver; FieldHandle: PZMySQLField; FieldFlags: Integer; const CtrlsCPType: TZControlsCodePage): TZSQLType; function Signed: Boolean; begin Result := (UNSIGNED_FLAG and FieldFlags) = 0; end; begin case PlainDriver.GetFieldType(FieldHandle) of FIELD_TYPE_TINY: if not Signed and (PlainDriver.GetFieldLength(FieldHandle)=1) then Result := stByte else Result := stShort; FIELD_TYPE_YEAR, FIELD_TYPE_SHORT: if Signed then Result := stShort else Result := stInteger; FIELD_TYPE_INT24, FIELD_TYPE_LONG: if Signed then Result := stInteger else Result := stLong; FIELD_TYPE_LONGLONG: if Signed then Result := stLong else Result := stBigDecimal; FIELD_TYPE_FLOAT: Result := stDouble; FIELD_TYPE_DECIMAL, FIELD_TYPE_NEWDECIMAL: {ADDED FIELD_TYPE_NEWDECIMAL by fduenas 20-06-2006} if PlainDriver.GetFieldDecimals(FieldHandle) = 0 then if PlainDriver.GetFieldLength(FieldHandle) < 11 then Result := stInteger else Result := stLong else Result := stDouble; FIELD_TYPE_DOUBLE: Result := stDouble; FIELD_TYPE_DATE, FIELD_TYPE_NEWDATE: Result := stDate; FIELD_TYPE_TIME: Result := stTime; FIELD_TYPE_DATETIME, FIELD_TYPE_TIMESTAMP: Result := stTimestamp; FIELD_TYPE_TINY_BLOB, FIELD_TYPE_MEDIUM_BLOB, FIELD_TYPE_LONG_BLOB, FIELD_TYPE_BLOB: if (FieldFlags and BINARY_FLAG) = 0 then If ( CtrlsCPType = cCP_UTF16) then Result := stUnicodeStream else Result := stAsciiStream else Result := stBinaryStream; FIELD_TYPE_BIT: Result := stShort; FIELD_TYPE_VARCHAR, FIELD_TYPE_VAR_STRING, FIELD_TYPE_STRING: if (FieldFlags and BINARY_FLAG) = 0 then if ( CtrlsCPType = cCP_UTF16) then Result := stUnicodeString else Result := stString else Result := stBytes; FIELD_TYPE_ENUM: Result := stString; FIELD_TYPE_SET: Result := stString; FIELD_TYPE_NULL: // Example: SELECT NULL FROM DUAL Result := stString; FIELD_TYPE_GEOMETRY: // Todo: Would be nice to show as WKT. Result := stBinaryStream; else raise Exception.Create('Unknown MySQL data type!'); end; end; {** Convert string mysql field type to SQLType @param string field type value @result the SQLType field type value } function ConvertMySQLTypeToSQLType(TypeName, TypeNameFull: string; const CtrlsCPType: TZControlsCodePage): TZSQLType; const GeoTypes: array[0..7] of string = ( 'POINT','LINESTRING','POLYGON','GEOMETRY', 'MULTIPOINT','MULTILINESTRING','MULTIPOLYGON','GEOMETRYCOLLECTION' ); var IsUnsigned: Boolean; Posi, Len, i: Integer; Spec: string; begin TypeName := UpperCase(TypeName); TypeNameFull := UpperCase(TypeNameFull); Result := stUnknown; Posi := FirstDelimiter(' ', TypeName); if Posi > 0 then TypeName := Copy(TypeName, 1, Posi - 1); Spec := ''; Posi := FirstDelimiter(' ', TypeNameFull); if Posi > 0 then Spec := Copy(TypeNameFull, Posi + 1, Length(TypeNameFull)-Posi); IsUnsigned := Pos('UNSIGNED', Spec) > 0; if TypeName = 'TINYINT' then begin if not IsUnsigned then Result := stShort else Result := stByte; end else if TypeName = 'YEAR' then Result := stShort else if TypeName = 'SMALLINT' then begin if IsUnsigned then Result := stInteger else Result := stShort; end else if TypeName = 'MEDIUMINT' then Result := stInteger else if (TypeName = 'INT') or (TypeName = 'INTEGER') then begin if IsUnsigned then Result := stLong else Result := stInteger end else if TypeName = 'BIGINT' then Result := stLong else if TypeName = 'INT24' then Result := stLong else if TypeName = 'REAL' then begin if IsUnsigned then Result := stDouble else Result := stFloat; end else if TypeName = 'FLOAT' then begin // if IsUnsigned then Result := stDouble // else Result := stFloat; end else if TypeName = 'DECIMAL' then begin if EndsWith(TypeNameFull, ',0)') then begin Len := StrToInt(Copy(TypeNameFull, 9, Length(TypeNameFull) - 11)); if Len < 10 then Result := stInteger else Result := stLong; end else Result := stDouble; end else if TypeName = 'DOUBLE' then Result := stDouble else if TypeName = 'CHAR' then Result := stString else if TypeName = 'VARCHAR' then Result := stString else if TypeName = 'VARBINARY' then Result := stBytes else if TypeName = 'BINARY' then Result := stBytes else if TypeName = 'DATE' then Result := stDate else if TypeName = 'TIME' then Result := stTime else if TypeName = 'TIMESTAMP' then Result := stTimestamp else if TypeName = 'DATETIME' then Result := stTimestamp else if TypeName = 'TINYBLOB' then Result := stBinaryStream else if TypeName = 'BLOB' then Result := stBinaryStream else if TypeName = 'MEDIUMBLOB' then Result := stBinaryStream else if TypeName = 'LONGBLOB' then Result := stBinaryStream else if TypeName = 'TINYTEXT' then Result := stAsciiStream else if TypeName = 'TEXT' then Result := stAsciiStream else if TypeName = 'MEDIUMTEXT' then Result := stAsciiStream else if TypeName = 'LONGTEXT' then Result := stAsciiStream else if TypeName = 'ENUM' then begin if (TypeNameFull = 'ENUM(''Y'',''N'')') or (TypeNameFull = 'ENUM(''N'',''Y'')') then Result := stBoolean else Result := stString; end else if TypeName = 'SET' then Result := stString else if TypeName = 'BIT' then Result := stShort else for i := 0 to Length(GeoTypes) - 1 do if GeoTypes[i] = TypeName then Result := stBinaryStream; if ( CtrlsCPType = cCP_UTF16) then case result of stString: Result := stUnicodeString; stAsciiStream: Result := stUnicodeStream; end; if Result = stUnknown then raise Exception.Create('Unknown MySQL data type!'); end; {** Checks for possible sql errors. @param PlainDriver a MySQL plain driver. @param Handle a MySQL connection handle. @param LogCategory a logging category. @param LogMessage a logging message. } procedure CheckMySQLError(PlainDriver: IZMySQLPlainDriver; Handle: PZMySQLConnect; LogCategory: TZLoggingCategory; const LogMessage: string); var ErrorMessage: string; ErrorCode: Integer; begin ErrorMessage := Trim(String(PlainDriver.GetLastError(Handle))); ErrorCode := PlainDriver.GetLastErrorCode(Handle); if (ErrorCode <> 0) and (ErrorMessage <> '') then begin if SilentMySQLError > 0 then raise EZMySQLSilentException.CreateFmt(SSQLError1, [ErrorMessage]); DriverManager.LogError(LogCategory, PlainDriver.GetProtocol, LogMessage, ErrorCode, ErrorMessage); raise EZSQLException.CreateWithCode(ErrorCode, Format(SSQLError1, [ErrorMessage])); end; end; procedure CheckMySQLPrepStmtError(PlainDriver: IZMySQLPlainDriver; Handle: PZMySQLConnect; LogCategory: TZLoggingCategory; const LogMessage: string); var ErrorMessage: string; ErrorCode: Integer; begin ErrorMessage := Trim(String(PlainDriver.GetLastPreparedError(Handle))); ErrorCode := PlainDriver.GetLastPreparedErrorCode(Handle); if (ErrorCode <> 0) and (ErrorMessage <> '') then begin if SilentMySQLError > 0 then raise EZMySQLSilentException.CreateFmt(SSQLError1, [ErrorMessage]); DriverManager.LogError(LogCategory,PlainDriver.GetProtocol,LogMessage,ErrorCode, ErrorMessage); raise EZSQLException.CreateWithCode(ErrorCode, Format(SSQLError1, [ErrorMessage])); end; end; {** Decodes a MySQL Version Value encoded with format: (major_version * 10,000) + (minor_version * 100) + sub_version into separated major, minor and subversion values @param MySQLVersion an integer containing the MySQL Full Version to decode. @param MajorVersion an integer containing the Major Version decoded. @param MinorVersion an integer containing the Minor Version decoded. @param SubVersion an integer contaning the Sub Version (revision) decoded. } procedure DecodeMySQLVersioning(const MySQLVersion: Integer; out MajorVersion: Integer; out MinorVersion: Integer; out SubVersion: Integer); begin MajorVersion := MySQLVersion div 10000; MinorVersion := (MySQLVersion - (MajorVersion * 10000)) div 100; SubVersion := MySQLVersion-(MajorVersion*10000)-(MinorVersion*100); end; {** Encodes major, minor and subversion (revision) values in MySQL format: (major_version * 10,000) + (minor_version * 100) + sub_version For example, 4.1.12 is returned as 40112. @param MajorVersion an integer containing the Major Version. @param MinorVersion an integer containing the Minor Version. @param SubVersion an integer containing the Sub Version (revision). @return an integer containing the full version. } function EncodeMySQLVersioning(const MajorVersion: Integer; const MinorVersion: Integer; const SubVersion: Integer): Integer; begin Result := (MajorVersion * 10000) + (MinorVersion * 100) + SubVersion; end; {** Decodes a MySQL Version Value and Encodes it to a Zeos SQL Version format: (major_version * 1,000,000) + (minor_version * 1,000) + sub_version into separated major, minor and subversion values So it transforms a version in format XYYZZ to XYYYZZZ where: X = major_version Y = minor_version Z = sub version @param MySQLVersion an integer containing the Full MySQL Version to decode. @return Encoded Zeos SQL Version Value. } function ConvertMySQLVersionToSQLVersion( const MySQLVersion: Integer ): integer; var MajorVersion, MinorVersion, SubVersion: Integer; begin DecodeMySQLVersioning(MySQLVersion,MajorVersion,MinorVersion,SubVersion); Result := EncodeSQLVersioning(MajorVersion,MinorVersion,SubVersion); end; function getMySQLFieldSize (field_type: TMysqlFieldTypes; field_size: LongWord): LongWord; var FieldSize: LongWord; Begin FieldSize := field_size; case field_type of FIELD_TYPE_TINY: Result := 1; FIELD_TYPE_SHORT: Result := 2; FIELD_TYPE_LONG: Result := 4; FIELD_TYPE_LONGLONG: Result := 8; FIELD_TYPE_FLOAT: Result := 4; FIELD_TYPE_DOUBLE: Result := 8; FIELD_TYPE_DATE: Result := sizeOf(MYSQL_TIME); FIELD_TYPE_TIME: Result := sizeOf(MYSQL_TIME); FIELD_TYPE_DATETIME: Result := sizeOf(MYSQL_TIME); FIELD_TYPE_TINY_BLOB: Result := FieldSize; //stBytes FIELD_TYPE_BLOB: Result := FieldSize; FIELD_TYPE_STRING: Result := FieldSize; else Result := 255; {unknown ??} end; end; {** Returns a valid TZColumnInfo from a FieldHandle @param PlainDriver the MySQL PlainDriver interface @param FieldHandle the handle of the fetched field @returns a new TZColumnInfo } function GetMySQLColumnInfoFromFieldHandle(PlainDriver: IZMySQLPlainDriver; const FieldHandle: PZMySQLField; ConSettings: PZConSettings; const bUseResult:boolean): TZColumnInfo; var FieldFlags: Integer; FieldLength: ULong; begin if Assigned(FieldHandle) then begin Result := TZColumnInfo.Create; FieldFlags := PlainDriver.GetFieldFlags(FieldHandle); Result.ColumnLabel := PlainDriver.ZDbcString(PlainDriver.GetFieldName(FieldHandle), ConSettings); Result.ColumnName := PlainDriver.ZDbcString(PlainDriver.GetFieldOrigName(FieldHandle), ConSettings); Result.TableName := PlainDriver.ZDbcString(PlainDriver.GetFieldTable(FieldHandle), ConSettings); Result.ReadOnly := (PlainDriver.GetFieldTable(FieldHandle) = ''); Result.Writable := not Result.ReadOnly; Result.ColumnType := ConvertMySQLHandleToSQLType(PlainDriver, FieldHandle, FieldFlags, ConSettings.CPType); FieldLength:=PlainDriver.GetFieldLength(FieldHandle); //EgonHugeist: arrange the MBCS field DisplayWidth to a proper count of Chars if Result.ColumnType in [stString, stUnicodeString] then case PlainDriver.GetFieldCharsetNr(FieldHandle) of 1, 84, {Big5} 95, 96, {cp932 japanese} 19, 85, {euckr} 24, 86, {gb2312} 38, 87, {gbk} 13, 88, {sjis} 35, 90, 128..151: {ucs2} begin Result.ColumnDisplaySize := (FieldLength div 4); Result.Precision := GetFieldSize(Result.ColumnType, ConSettings, Result.ColumnDisplaySize, 2, nil); end; 33, 83, 192..215, { utf8 } 97, 98, { eucjpms} 12, 91: {ujis} begin Result.ColumnDisplaySize := (FieldLength div 3); Result.Precision := GetFieldSize(Result.ColumnType, ConSettings, Result.ColumnDisplaySize, 3, nil); end; 54, 55, 101..124, {utf16} 56, 62, {utf16le} 60, 61, 160..183, {utf32} 45, 46, 224..247: {utf8mb4} begin Result.ColumnDisplaySize := (FieldLength div 4); Result.Precision := GetFieldSize(Result.ColumnType, ConSettings, Result.ColumnDisplaySize, 4, nil); end; else //1-Byte charsets begin Result.ColumnDisplaySize := FieldLength; Result.Precision := GetFieldSize(Result.ColumnType, ConSettings, Result.ColumnDisplaySize, 1, nil); end; end else Result.Precision := min(MaxBlobSize,FieldLength); if PlainDriver.GetFieldType(FieldHandle) in [FIELD_TYPE_BLOB,FIELD_TYPE_MEDIUM_BLOB,FIELD_TYPE_LONG_BLOB,FIELD_TYPE_STRING, FIELD_TYPE_VAR_STRING] then begin if bUseResult then //PMYSQL_FIELD(Field)^.max_length not valid Result.MaxLenghtBytes:=Result.Precision else Result.MaxLenghtBytes:=PlainDriver.GetFieldMaxLength(FieldHandle); end else Result.MaxLenghtBytes:=FieldLength; Result.Scale := PlainDriver.GetFieldDecimals(FieldHandle); if (AUTO_INCREMENT_FLAG and FieldFlags <> 0) or (TIMESTAMP_FLAG and FieldFlags <> 0) then Result.AutoIncrement := True; if UNSIGNED_FLAG and FieldFlags <> 0 then Result.Signed := False else Result.Signed := True; if NOT_NULL_FLAG and FieldFlags <> 0 then Result.Nullable := ntNoNulls else Result.Nullable := ntNullable; // Properties not set via query results here will be fetched from table metadata. end else Result := nil; end; procedure ConvertMySQLColumnInfoFromString(const TypeInfo: String; ConSettings: PZConSettings; out TypeName, TypeInfoSecond: String; out FieldType: TZSQLType; out ColumnSize: Integer; out Precision: Integer); var TypeInfoList: TStrings; TypeInfoFirst: String; J, TempPos: Integer; begin TypeInfoList := TStringList.Create; TypeInfoFirst := ''; TypeInfoSecond := ''; Precision := 0; ColumnSize := 0; if StrPos(PChar(TypeInfo), '(') <> nil then begin PutSplitString(TypeInfoList, TypeInfo, '()'); TypeInfoFirst := TypeInfoList.Strings[0]; TypeInfoSecond := TypeInfoList.Strings[1]; end else TypeInfoFirst := TypeInfo; TypeInfoFirst := LowerCase(TypeInfoFirst); TypeName := TypeInfoFirst; FieldType := ConvertMySQLTypeToSQLType(TypeInfoFirst, TypeInfo, Consettings.CPType); { the column type is ENUM} if TypeInfoFirst = 'enum' then begin PutSplitString(TypeInfoList, TypeInfoSecond, ','); for J := 0 to TypeInfoList.Count-1 do ColumnSize := Max(ColumnSize, Length(TypeInfoList.Strings[J])); end else { the column type is decimal } if ( Pos(',', TypeInfoSecond) > 0 ) and not ( TypeInfoFirst = 'set' ) then begin TempPos := FirstDelimiter(',', TypeInfoSecond); ColumnSize := StrToIntDef(Copy(TypeInfoSecond, 1, TempPos - 1), 0); Precision := StrToIntDef(Copy(TypeInfoSecond, TempPos + 1, Length(TypeInfoSecond) - TempPos), 0); end else begin { the column type is other } if (TypeInfoSecond <> '') and not (TypeInfoFirst = 'set') then ColumnSize := StrToIntDef(TypeInfoSecond, 0) else if TypeInfoFirst = 'tinyint' then ColumnSize := 1 else if TypeInfoFirst = 'smallint' then ColumnSize := 6 else if TypeInfoFirst = 'mediumint' then ColumnSize := 6 else if TypeInfoFirst = 'int' then ColumnSize := 11 else if TypeInfoFirst = 'integer' then ColumnSize := 11 else if TypeInfoFirst = 'bigint' then ColumnSize := 25 else if TypeInfoFirst = 'int24' then ColumnSize := 25 else if TypeInfoFirst = 'real' then ColumnSize := 12 else if TypeInfoFirst = 'float' then ColumnSize := 12 else if TypeInfoFirst = 'decimal' then ColumnSize := 12 else if TypeInfoFirst = 'numeric' then ColumnSize := 12 else if TypeInfoFirst = 'double' then ColumnSize := 22 else if TypeInfoFirst = 'char' then ColumnSize := 1 else if TypeInfoFirst = 'varchar' then ColumnSize := 255 else if TypeInfoFirst = 'date' then ColumnSize := 10 else if TypeInfoFirst = 'time' then ColumnSize := 8 else if TypeInfoFirst = 'timestamp' then ColumnSize := 19 else if TypeInfoFirst = 'datetime' then ColumnSize := 19 else if TypeInfoFirst = 'tinyblob' then ColumnSize := 255 else if TypeInfoFirst = 'blob' then ColumnSize := MAXBUF else if TypeInfoFirst = 'mediumblob' then ColumnSize := 16277215//may be 65535 else if TypeInfoFirst = 'longblob' then ColumnSize := High(Integer)//2147483657//may be 65535 else if TypeInfoFirst = 'tinytext' then ColumnSize := 255 else if TypeInfoFirst = 'text' then ColumnSize := 65535 else if TypeInfoFirst = 'mediumtext' then ColumnSize := 16277215 //may be 65535 else if TypeInfoFirst = 'enum' then ColumnSize := 255 else if TypeInfoFirst = 'set' then ColumnSize := 255; end; if FieldType in [stString, stUnicodeString] then ColumnSize := GetFieldSize(FieldType, consettings, ColumnSize, ConSettings.ClientCodePage.CharWidth, nil); FreeAndNil(TypeInfoList); end; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcOracle.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Oracle Database Connectivity Classes } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcOracle; interface {$I ZDbc.inc} uses Types, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, Contnrs, ZCompatibility, ZDbcIntfs, ZDbcConnection, ZPlainOracleDriver, ZDbcLogging, ZTokenizer, ZDbcGenericResolver, ZURL, ZGenericSqlAnalyser, ZPlainOracleConstants; type {** Implements Oracle Database Driver. } {$WARNINGS OFF} TZOracleDriver = class(TZAbstractDriver) public constructor Create; override; function Connect(const Url: TZURL): IZConnection; override; function GetMajorVersion: Integer; override; function GetMinorVersion: Integer; override; function GetTokenizer: IZTokenizer; override; function GetStatementAnalyser: IZStatementAnalyser; override; end; {$WARNINGS ON} {** Represents a Oracle specific connection interface. } IZOracleConnection = interface (IZConnection) ['{C7F36FDF-8A64-477B-A0EB-3E8AB7C09F8D}'] function GetPlainDriver: IZOraclePlainDriver; function GetConnectionHandle: POCIEnv; function GetContextHandle: POCISvcCtx; function GetErrorHandle: POCIError; function GetServerHandle: POCIServer; function GetSessionHandle: POCISession; function GetTransactionHandle: POCITrans; function GetDescribeHandle: POCIDescribe; end; {** Implements Oracle Database Connection. } TZOracleConnection = class(TZAbstractConnection, IZOracleConnection) private FCatalog: string; FHandle: POCIEnv; FContextHandle: POCISvcCtx; FErrorHandle: POCIError; FServerHandle: POCIServer; FSessionHandle: POCISession; FTransHandle: POCITrans; FDescibeHandle: POCIDescribe; protected procedure InternalCreate; override; procedure StartTransactionSupport; public destructor Destroy; override; function CreateRegularStatement(Info: TStrings): IZStatement; override; function CreatePreparedStatement(const SQL: string; Info: TStrings): IZPreparedStatement; override; function CreateCallableStatement(const SQL: string; Info: TStrings): IZCallableStatement; override; procedure Commit; override; procedure Rollback; override; function PingServer: Integer; override; procedure Open; override; procedure Close; override; procedure SetCatalog(const Catalog: string); override; function GetCatalog: string; override; procedure SetTransactionIsolation(Level: TZTransactIsolationLevel); override; function CreateSequence(const Sequence: string; BlockSize: Integer): IZSequence; override; function GetPlainDriver: IZOraclePlainDriver; function GetConnectionHandle: POCIEnv; function GetContextHandle: POCISvcCtx; function GetErrorHandle: POCIError; function GetServerHandle: POCIServer; function GetSessionHandle: POCISession; function GetTransactionHandle: POCITrans; function GetDescribeHandle: POCIDescribe; function GetClientVersion: Integer; override; function GetHostVersion: Integer; override; function GetBinaryEscapeString(const Value: TByteDynArray): String; overload; override; function GetBinaryEscapeString(const Value: RawByteString): String; overload; override; end; TZOracleSequence = class(TZAbstractSequence) public function GetCurrentValue: Int64; override; function GetCurrentValueSQL: String; override; function GetNextValue: Int64; override; function GetNextValueSQL: String; override; end; {** Implements a specialized cached resolver for Oracle. } TZOracleCachedResolver = class(TZGenericCachedResolver) public function FormCalculateStatement(Columns: TObjectList): string; override; end; var {** The common driver manager object. } OracleDriver: IZDriver; implementation uses ZMessages, ZGenericSqlToken, ZDbcOracleStatement, ZSysUtils, ZDbcUtils, ZDbcOracleUtils, ZDbcOracleMetadata, ZOracleToken, ZOracleAnalyser; { TZOracleDriver } {** Constructs this object with default properties. } constructor TZOracleDriver.Create; begin inherited Create; AddSupportedProtocol(AddPlainDriverToCache(TZOracle9iPlainDriver.Create, 'oracle')); AddSupportedProtocol(AddPlainDriverToCache(TZOracle9iPlainDriver.Create)); end; {** Attempts to make a database connection to the given URL. The driver should return "null" if it realizes it is the wrong kind of driver to connect to the given URL. This will be common, as when the JDBC driver manager is asked to connect to a given URL it passes the URL to each loaded driver in turn.

The driver should raise a SQLException if it is the right driver to connect to the given URL, but has trouble connecting to the database.

The java.util.Properties argument can be used to passed arbitrary string tag/value pairs as connection arguments. Normally at least "user" and "password" properties should be included in the Properties. @param url the URL of the database to which to connect @param info a list of arbitrary string tag/value pairs as connection arguments. Normally at least a "user" and "password" property should be included. @return a Connection object that represents a connection to the URL } {$WARNINGS OFF} function TZOracleDriver.Connect(const Url: TZURL): IZConnection; begin Result := TZOracleConnection.Create(Url); end; {$WARNINGS ON} {** Gets the driver's major version number. Initially this should be 1. @return this driver's major version number } function TZOracleDriver.GetMajorVersion: Integer; begin Result := 1; end; {** Gets the driver's minor version number. Initially this should be 0. @return this driver's minor version number } function TZOracleDriver.GetMinorVersion: Integer; begin Result := 0; end; {** Gets a SQL syntax tokenizer. @returns a SQL syntax tokenizer object. } function TZOracleDriver.GetTokenizer: IZTokenizer; begin if Tokenizer = nil then Tokenizer := TZOracleTokenizer.Create; Result := Tokenizer; end; {** Creates a statement analyser object. @returns a statement analyser object. } function TZOracleDriver.GetStatementAnalyser: IZStatementAnalyser; begin if Analyser = nil then Analyser := TZOracleStatementAnalyser.Create; Result := Analyser; end; { TZOracleConnection } {** Constructs this object and assignes the main properties. } procedure TZOracleConnection.InternalCreate; begin FMetaData := TZOracleDatabaseMetadata.Create(Self, URL); FHandle := nil; { Sets a default properties } if Self.Port = 0 then Self.Port := 1521; AutoCommit := True; TransactIsolationLevel := tiNone; Open; end; function TZOracleConnection.CreateCallableStatement(const SQL: string; Info: TStrings): IZCallableStatement; begin if IsClosed then Open; Result := TZOracleCallableStatement.Create(Self, SQL, Info); Result.ClearParameters; end; {** Destroys this object and cleanups the memory. } destructor TZOracleConnection.Destroy; begin if not IsClosed then Close; if FHandle <> nil then begin GetPlainDriver.HandleFree(FHandle, OCI_HTYPE_ENV); FHandle := nil; end; inherited Destroy; end; {** Opens a connection to database server with specified parameters. } procedure TZOracleConnection.Open; var Status: Integer; LogMessage: string; OCI_CLIENT_CHARSET_ID, OCI_CLIENT_NCHARSET_ID: ub2; procedure CleanupOnFail; begin GetPlainDriver.HandleFree(FDescibeHandle, OCI_HTYPE_DESCRIBE); FDescibeHandle := nil; GetPlainDriver.HandleFree(FContextHandle, OCI_HTYPE_SVCCTX); FContextHandle := nil; GetPlainDriver.HandleFree(FErrorHandle, OCI_HTYPE_ERROR); FErrorHandle := nil; GetPlainDriver.HandleFree(FServerHandle, OCI_HTYPE_SERVER); FServerHandle := nil; end; begin if not Closed then Exit; LogMessage := Format('CONNECT TO "%s" AS USER "%s"', [Database, User]); { Sets a default port number. } if Port = 0 then Port := 1521; { Sets a client codepage. } OCI_CLIENT_CHARSET_ID := ConSettings.ClientCodePage^.ID; { Connect to Oracle database. } if ( FHandle = nil ) then try FErrorHandle := nil; Status := GetPlainDriver.EnvNlsCreate(FHandle, OCI_OBJECT, nil, nil, nil, nil, 0, nil, OCI_CLIENT_CHARSET_ID, OCI_CLIENT_CHARSET_ID); CheckOracleError(GetPlainDriver, FErrorHandle, Status, lcOther, 'EnvNlsCreate failed.'); except raise; end; FErrorHandle := nil; GetPlainDriver.HandleAlloc(FHandle, FErrorHandle, OCI_HTYPE_ERROR, 0, nil); FServerHandle := nil; GetPlainDriver.HandleAlloc(FHandle, FServerHandle, OCI_HTYPE_SERVER, 0, nil); FContextHandle := nil; GetPlainDriver.HandleAlloc(FHandle, FContextHandle, OCI_HTYPE_SVCCTX, 0, nil); FDescibeHandle := nil; GetPlainDriver.HandleAlloc(FHandle, FDescibeHandle, OCI_HTYPE_DESCRIBE, 0, nil); Status := GetPlainDriver.ServerAttach(FServerHandle, FErrorHandle, PAnsiChar(ansistring(Database)), Length(AnsiString(Database)), 0); try CheckOracleError(GetPlainDriver, FErrorHandle, Status, lcConnect, LogMessage); except CleanupOnFail; raise; end; if OCI_CLIENT_CHARSET_ID = 0 then begin OCI_CLIENT_NCHARSET_ID := High(ub2); GetPlainDriver.AttrGet(FHandle, OCI_HTYPE_ENV, @OCI_CLIENT_CHARSET_ID, nil, OCI_ATTR_ENV_CHARSET_ID, FErrorHandle); //Get Server default CodePage CheckCharEncoding(GetPlainDriver.ValidateCharEncoding(OCI_CLIENT_CHARSET_ID)^.Name); if OCI_CLIENT_CHARSET_ID <> OCI_CLIENT_NCHARSET_ID then begin CleanupOnFail; Open; Exit; end; end; if GetPlainDriver.GetEnvCharsetByteWidth(FHandle, FErrorHandle, ConSettings.ClientCodePage^.CharWidth) <> OCI_SUCCESS then CheckOracleError(GetPlainDriver, FErrorHandle, Status, lcConnect, LogMessage); GetPlainDriver.AttrSet(FContextHandle, OCI_HTYPE_SVCCTX, FServerHandle, 0, OCI_ATTR_SERVER, FErrorHandle); GetPlainDriver.HandleAlloc(FHandle, FSessionHandle, OCI_HTYPE_SESSION, 0, nil); GetPlainDriver.AttrSet(FSessionHandle, OCI_HTYPE_SESSION, PAnsiChar(AnsiString(User)), Length(User), OCI_ATTR_USERNAME, FErrorHandle); GetPlainDriver.AttrSet(FSessionHandle, OCI_HTYPE_SESSION, PAnsiChar(AnsiString(Password)), Length(Password), OCI_ATTR_PASSWORD, FErrorHandle); Status := GetPlainDriver.SessionBegin(FContextHandle, FErrorHandle, FSessionHandle, OCI_CRED_RDBMS, OCI_DEFAULT); try CheckOracleError(GetPlainDriver, FErrorHandle, Status, lcConnect, LogMessage); except CleanupOnFail; raise; end; GetPlainDriver.AttrSet(FContextHandle, OCI_HTYPE_SVCCTX, FSessionHandle, 0, OCI_ATTR_SESSION, FErrorHandle); DriverManager.LogMessage(lcConnect, PlainDriver.GetProtocol, LogMessage); StartTransactionSupport; inherited Open; end; {** Starts a transaction support. } procedure TZOracleConnection.StartTransactionSupport; var SQL: PChar; Status: Integer; Isolation: Integer; begin if TransactIsolationLevel = tiNone then begin SQL := 'SET TRANSACTION ISOLATION LEVEL DEFAULT'; Isolation := OCI_DEFAULT; end else if TransactIsolationLevel = tiReadCommitted then begin // Behaviour changed by mdaems 31/05/2006 : Read Committed is the default // isolation level used by oracle. This property should not be abused to add // the non-standard isolation level 'read only' thats invented by oracle. // SQL := 'SET TRANSACTION ISOLATION LEVEL READONLY'; // Isolation := OCI_TRANS_READONLY; SQL := 'SET TRANSACTION ISOLATION LEVEL DEFAULT'; Isolation := OCI_DEFAULT; end else if TransactIsolationLevel = tiRepeatableRead then begin SQL := 'SET TRANSACTION ISOLATION LEVEL READWRITE'; Isolation := OCI_TRANS_READWRITE; end else if TransactIsolationLevel = tiSerializable then begin SQL := 'SET TRANSACTION ISOLATION LEVEL SERIALIZABLE'; Isolation := OCI_TRANS_SERIALIZABLE; end else raise EZSQLException.Create(SIsolationIsNotSupported); FTransHandle := nil; GetPlainDriver.HandleAlloc(FHandle, FTransHandle, OCI_HTYPE_TRANS, 0, nil); GetPlainDriver.AttrSet(FContextHandle, OCI_HTYPE_SVCCTX, FTransHandle, 0, OCI_ATTR_TRANS, FErrorHandle); Status := GetPlainDriver.TransStart(FContextHandle, FErrorHandle, 0, Isolation); CheckOracleError(GetPlainDriver, FErrorHandle, Status, lcExecute, SQL); DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, SQL); end; {** Creates a Statement object for sending SQL statements to the database. SQL statements without parameters are normally executed using Statement objects. If the same SQL statement is executed many times, it is more efficient to use a PreparedStatement object.

Result sets created using the returned Statement object will by default have forward-only type and read-only concurrency. @param Info a statement parameters. @return a new Statement object } function TZOracleConnection.CreateRegularStatement(Info: TStrings): IZStatement; begin if IsClosed then Open; Result := TZOracleStatement.Create(GetPlainDriver, Self, Info); end; {** Creates a PreparedStatement object for sending parameterized SQL statements to the database. A SQL statement with or without IN parameters can be pre-compiled and stored in a PreparedStatement object. This object can then be used to efficiently execute this statement multiple times.

Note: This method is optimized for handling parametric SQL statements that benefit from precompilation. If the driver supports precompilation, the method prepareStatement will send the statement to the database for precompilation. Some drivers may not support precompilation. In this case, the statement may not be sent to the database until the PreparedStatement is executed. This has no direct effect on users; however, it does affect which method throws certain SQLExceptions. Result sets created using the returned PreparedStatement will have forward-only type and read-only concurrency, by default. @param sql a SQL statement that may contain one or more '?' IN parameter placeholders @param Info a statement parameters. @return a new PreparedStatement object containing the pre-compiled statement } function TZOracleConnection.CreatePreparedStatement(const SQL: string; Info: TStrings): IZPreparedStatement; begin if IsClosed then Open; Result := TZOraclePreparedStatement.Create(GetPlainDriver, Self, SQL, Info); end; {** Makes all changes made since the previous commit/rollback permanent and releases any database locks currently held by the Connection. This method should be used only when auto-commit mode has been disabled. @see #setAutoCommit } procedure TZOracleConnection.Commit; var Status: Integer; SQL: PChar; begin if not Closed then begin SQL := 'COMMIT'; Status := GetPlainDriver.TransCommit(FContextHandle, FErrorHandle, OCI_DEFAULT); CheckOracleError(GetPlainDriver, FErrorHandle, Status, lcExecute, SQL); DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, SQL); end; end; {** Drops all changes made since the previous commit/rollback and releases any database locks currently held by this Connection. This method should be used only when auto- commit has been disabled. @see #setAutoCommit } procedure TZOracleConnection.Rollback; var Status: Integer; SQL: PChar; begin if not Closed then begin SQL := 'ROLLBACK'; Status := GetPlainDriver.TransRollback(FContextHandle, FErrorHandle, OCI_DEFAULT); CheckOracleError(GetPlainDriver, FErrorHandle, Status, lcExecute, SQL); DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, SQL); end; end; {** Ping Current Connection's server, if client was disconnected, the connection is resumed. @return 0 if succesfull or error code if any error occurs } function TZOracleConnection.PingServer: Integer; begin Result := GetPlainDriver.Ping(FContextHandle, FErrorHandle); CheckOracleError(GetPlainDriver, FErrorHandle, Result, lcExecute, 'Ping Server'); Result := 0; //only possible if CheckOracleError dosn't raise an exception end; {** Releases a Connection's database and JDBC resources immediately instead of waiting for them to be automatically released.

Note: A Connection is automatically closed when it is garbage collected. Certain fatal errors also result in a closed Connection. } procedure TZOracleConnection.Close; var Status: Integer; LogMessage: string; begin if not Closed then begin LogMessage := Format('DISCONNECT FROM "%s"', [Database]); { Closes started transaction } Status := GetPlainDriver.TransRollback(FContextHandle, FErrorHandle, OCI_DEFAULT); CheckOracleError(GetPlainDriver, FErrorHandle, Status, lcDisconnect, LogMessage); GetPlainDriver.HandleFree(FTransHandle, OCI_HTYPE_TRANS); FTransHandle := nil; { Closes the session } Status := GetPlainDriver.SessionEnd(FContextHandle, FErrorHandle, FSessionHandle, OCI_DEFAULT); CheckOracleError(GetPlainDriver, FErrorHandle, Status, lcDisconnect, LogMessage); { Detaches from the server } Status := GetPlainDriver.ServerDetach(FServerHandle, FErrorHandle, OCI_DEFAULT); CheckOracleError(GetPlainDriver, FErrorHandle, Status, lcDisconnect, LogMessage); { Frees all handlers } GetPlainDriver.HandleFree(FDescibeHandle, OCI_HTYPE_DESCRIBE); FDescibeHandle := nil; GetPlainDriver.HandleFree(FSessionHandle, OCI_HTYPE_SESSION); FSessionHandle := nil; GetPlainDriver.HandleFree(FContextHandle, OCI_HTYPE_SVCCTX); FContextHandle := nil; GetPlainDriver.HandleFree(FServerHandle, OCI_HTYPE_SERVER); FServerHandle := nil; GetPlainDriver.HandleFree(FErrorHandle, OCI_HTYPE_ERROR); FErrorHandle := nil; DriverManager.LogMessage(lcDisconnect, PlainDriver.GetProtocol, LogMessage); end; inherited Close; end; {** Gets a selected catalog name. @return a selected catalog name. } function TZOracleConnection.GetCatalog: string; begin Result := FCatalog; end; {** Sets a new selected catalog name. @param Catalog a selected catalog name. } procedure TZOracleConnection.SetCatalog(const Catalog: string); begin FCatalog := Catalog; end; {** Sets a new transact isolation level. @param Level a new transact isolation level. } procedure TZOracleConnection.SetTransactionIsolation( Level: TZTransactIsolationLevel); var Status: Integer; SQL: PChar; begin if TransactIsolationLevel <> Level then begin inherited SetTransactionIsolation(Level); if not Closed then begin SQL := 'END TRANSACTION'; Status := GetPlainDriver.TransRollback(FContextHandle, FErrorHandle, OCI_DEFAULT); CheckOracleError(GetPlainDriver, FErrorHandle, Status, lcExecute, SQL); GetPlainDriver.HandleFree(FTransHandle, OCI_HTYPE_TRANS); FTransHandle := nil; DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, SQL); StartTransactionSupport; end; end; end; {** Creates a sequence generator object. @param Sequence a name of the sequence generator. @param BlockSize a number of unique keys requested in one trip to SQL server. @returns a created sequence object. } function TZOracleConnection.CreateSequence(const Sequence: string; BlockSize: Integer): IZSequence; begin Result := TZOracleSequence.Create(Self, Sequence, BlockSize); end; {** Gets a Oracle plain driver interface. @return a Oracle plain driver interface. } function TZOracleConnection.GetPlainDriver: IZOraclePlainDriver; begin Result := PlainDriver as IZOraclePlainDriver; end; {** Gets a reference to Oracle connection handle. @return a reference to Oracle connection handle. } function TZOracleConnection.GetConnectionHandle: POCIEnv; begin Result := FHandle; end; {** Gets a reference to Oracle context handle. @return a reference to Oracle context handle. } function TZOracleConnection.GetContextHandle: POCISvcCtx; begin Result := FContextHandle; end; {** Gets a reference to Oracle error handle. @return a reference to Oracle error handle. } function TZOracleConnection.GetErrorHandle: POCIError; begin Result := FErrorHandle; end; {** Gets a reference to Oracle server handle. @return a reference to Oracle server handle. } function TZOracleConnection.GetServerHandle: POCIServer; begin Result := FServerHandle; end; {** Gets a reference to Oracle session handle. @return a reference to Oracle session handle. } function TZOracleConnection.GetSessionHandle: POCISession; begin Result := FSessionHandle; end; {** Gets a reference to Oracle transaction handle. @return a reference to Oracle transacton handle. } function TZOracleConnection.GetTransactionHandle: POCITrans; begin Result := FTransHandle; end; {** Gets a reference to Oracle describe handle. @return a reference to Oracle describe handle. } function TZOracleConnection.GetDescribeHandle: POCIDescribe; begin Result := FDescibeHandle; end; function TZOracleConnection.GetClientVersion: Integer; var major_version, minor_version, update_num, patch_num, port_update_num: sword; begin GetPlainDriver.ClientVersion(@major_version, @minor_version, @update_num, @patch_num, @port_update_num); Result := EncodeSQLVersioning(major_version,minor_version,update_num); end; function TZOracleConnection.GetHostVersion: Integer; var buf:text; version:ub4; begin result:=0; getmem(buf,1024); if GetPlainDriver.ServerRelease(FServerHandle,FErrorHandle,buf,1024,OCI_HTYPE_SERVER,@version)=OCI_SUCCESS then Result := EncodeSQLVersioning((version shr 24) and $ff,(version shr 20) and $f,(version shr 12) and $ff); freemem(buf); end; function TZOracleConnection.GetBinaryEscapeString(const Value: TByteDynArray): String; var tmp: RawByteString; L: Integer; begin L := Length(Value); SetLength(tmp, L*2); BinToHex(PAnsiChar(Value), PAnsiChar(tmp), L); Result := #39+String(tmp)+#39; if GetAutoEncodeStrings then Result := GetDriver.GetTokenizer.GetEscapeString(Result) end; function TZOracleConnection.GetBinaryEscapeString(const Value: RawByteString): String; var tmp: RawByteString; L: Integer; begin L := Length(Value); SetLength(tmp, L*2); BinToHex(PAnsiChar(Value), PAnsiChar(tmp), L); if GetAutoEncodeStrings then Result := GetDriver.GetTokenizer.GetEscapeString(Result) end; { TZOracleSequence } {** Gets the current unique key generated by this sequence. @param the last generated unique key. } function TZOracleSequence.GetCurrentValue: Int64; var Statement: IZStatement; ResultSet: IZResultSet; begin Statement := Connection.CreateStatement; ResultSet := Statement.ExecuteQuery( Format('SELECT %s.CURRVAL FROM DUAL', [Name])); if ResultSet.Next then Result := ResultSet.GetLong(1) else Result := inherited GetCurrentValue; ResultSet.Close; Statement.Close; end; function TZOracleSequence.GetCurrentValueSQL: String; begin result:=Format('SELECT %s.CURRVAL FROM DUAL', [Name]); end; {** Gets the next unique key generated by this sequence. @param the next generated unique key. } function TZOracleSequence.GetNextValue: Int64; var Statement: IZStatement; ResultSet: IZResultSet; begin Statement := Connection.CreateStatement; ResultSet := Statement.ExecuteQuery( Format('SELECT %s.NEXTVAL FROM DUAL', [Name])); if ResultSet.Next then Result := ResultSet.GetLong(1) else Result := inherited GetNextValue; ResultSet.Close; Statement.Close; end; function TZOracleSequence.GetNextValueSQL: String; begin result:=Format('SELECT %s.NEXTVAL FROM DUAL', [Name]); end; { TZOracleCachedResolver } {** Forms a where clause for SELECT statements to calculate default values. @param Columns a collection of key columns. @param OldRowAccessor an accessor object to old column values. } function TZOracleCachedResolver.FormCalculateStatement( Columns: TObjectList): string; var iPos: Integer; begin Result := inherited FormCalculateStatement(Columns); if Result <> '' then begin iPos := pos('FROM', uppercase(Result)); if iPos > 0 then begin Result := copy(Result, 1, iPos+3) + ' DUAL'; end else begin Result := Result + ' FROM DUAL'; end; end; end; initialization OracleDriver := TZOracleDriver.Create; DriverManager.RegisterDriver(OracleDriver); finalization if DriverManager <> nil then DriverManager.DeregisterDriver(OracleDriver); OracleDriver := nil; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcOracleMetadata.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Oracle Database Connectivity Classes } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcOracleMetadata; interface {$I ZDbc.inc} uses Types, Classes, SysUtils, ZSysUtils, ZDbcIntfs, ZDbcMetadata, ZCompatibility, ZDbcOracleUtils, ZDbcConnection, ZURL, ZDbcCachedResultSet, ZDbcCache; type // technobot 2008-06-28 - methods moved as is from TZOracleDatabaseMetadata: {** Implements Oracle Database Information. } TZOracleDatabaseInfo = class(TZAbstractDatabaseInfo) // function UncachedGetUDTs(const Catalog: string; const SchemaPattern: string; // const TypeNamePattern: string; const Types: TIntegerDynArray): IZResultSet; override; public // database/driver/server info: function GetDatabaseProductName: string; override; function GetDatabaseProductVersion: string; override; function GetDriverName: string; override; // function GetDriverVersion: string; override; -> Same as parent function GetDriverMajorVersion: Integer; override; function GetDriverMinorVersion: Integer; override; // function GetServerVersion: string; -> Not implemented // capabilities (what it can/cannot do): // function AllProceduresAreCallable: Boolean; override; -> Not implemented // function AllTablesAreSelectable: Boolean; override; -> Not implemented function SupportsMixedCaseIdentifiers: Boolean; override; function SupportsMixedCaseQuotedIdentifiers: Boolean; override; // function SupportsAlterTableWithAddColumn: Boolean; override; -> Not implemented // function SupportsAlterTableWithDropColumn: Boolean; override; -> Not implemented // function SupportsColumnAliasing: Boolean; override; -> Not implemented // function SupportsConvert: Boolean; override; -> Not implemented // function SupportsConvertForTypes(FromType: TZSQLType; ToType: TZSQLType): // Boolean; override; -> Not implemented // function SupportsTableCorrelationNames: Boolean; override; -> Not implemented // function SupportsDifferentTableCorrelationNames: Boolean; override; -> Not implemented function SupportsExpressionsInOrderBy: Boolean; override; function SupportsOrderByUnrelated: Boolean; override; function SupportsGroupBy: Boolean; override; function SupportsGroupByUnrelated: Boolean; override; function SupportsGroupByBeyondSelect: Boolean; override; // function SupportsLikeEscapeClause: Boolean; override; -> Not implemented // function SupportsMultipleResultSets: Boolean; override; -> Not implemented // function SupportsMultipleTransactions: Boolean; override; -> Not implemented // function SupportsNonNullableColumns: Boolean; override; -> Not implemented // function SupportsMinimumSQLGrammar: Boolean; override; -> Not implemented // function SupportsCoreSQLGrammar: Boolean; override; -> Not implemented // function SupportsExtendedSQLGrammar: Boolean; override; -> Not implemented // function SupportsANSI92EntryLevelSQL: Boolean; override; -> Not implemented // function SupportsANSI92IntermediateSQL: Boolean; override; -> Not implemented // function SupportsANSI92FullSQL: Boolean; override; -> Not implemented function SupportsIntegrityEnhancementFacility: Boolean; override; // function SupportsOuterJoins: Boolean; override; -> Not implemented // function SupportsFullOuterJoins: Boolean; override; -> Not implemented // function SupportsLimitedOuterJoins: Boolean; override; -> Not implemented function SupportsSchemasInDataManipulation: Boolean; override; function SupportsSchemasInProcedureCalls: Boolean; override; function SupportsSchemasInTableDefinitions: Boolean; override; function SupportsSchemasInIndexDefinitions: Boolean; override; function SupportsSchemasInPrivilegeDefinitions: Boolean; override; function SupportsCatalogsInDataManipulation: Boolean; override; function SupportsCatalogsInProcedureCalls: Boolean; override; function SupportsCatalogsInTableDefinitions: Boolean; override; function SupportsCatalogsInIndexDefinitions: Boolean; override; function SupportsCatalogsInPrivilegeDefinitions: Boolean; override; function SupportsPositionedDelete: Boolean; override; function SupportsPositionedUpdate: Boolean; override; function SupportsSelectForUpdate: Boolean; override; function SupportsStoredProcedures: Boolean; override; function SupportsSubqueriesInComparisons: Boolean; override; function SupportsSubqueriesInExists: Boolean; override; function SupportsSubqueriesInIns: Boolean; override; function SupportsSubqueriesInQuantifieds: Boolean; override; function SupportsCorrelatedSubqueries: Boolean; override; function SupportsUnion: Boolean; override; function SupportsUnionAll: Boolean; override; function SupportsOpenCursorsAcrossCommit: Boolean; override; function SupportsOpenCursorsAcrossRollback: Boolean; override; function SupportsOpenStatementsAcrossCommit: Boolean; override; function SupportsOpenStatementsAcrossRollback: Boolean; override; function SupportsTransactions: Boolean; override; function SupportsTransactionIsolationLevel(Level: TZTransactIsolationLevel): Boolean; override; function SupportsDataDefinitionAndDataManipulationTransactions: Boolean; override; function SupportsDataManipulationTransactionsOnly: Boolean; override; function SupportsResultSetType(_Type: TZResultSetType): Boolean; override; function SupportsResultSetConcurrency(_Type: TZResultSetType; Concurrency: TZResultSetConcurrency): Boolean; override; // function SupportsBatchUpdates: Boolean; override; -> Not implemented function SupportsNonEscapedSearchStrings: Boolean; override; // maxima: function GetMaxBinaryLiteralLength: Integer; override; function GetMaxCharLiteralLength: Integer; override; function GetMaxColumnNameLength: Integer; override; function GetMaxColumnsInGroupBy: Integer; override; function GetMaxColumnsInIndex: Integer; override; function GetMaxColumnsInOrderBy: Integer; override; function GetMaxColumnsInSelect: Integer; override; function GetMaxColumnsInTable: Integer; override; function GetMaxConnections: Integer; override; function GetMaxCursorNameLength: Integer; override; function GetMaxIndexLength: Integer; override; function GetMaxSchemaNameLength: Integer; override; function GetMaxProcedureNameLength: Integer; override; function GetMaxCatalogNameLength: Integer; override; function GetMaxRowSize: Integer; override; function GetMaxStatementLength: Integer; override; function GetMaxStatements: Integer; override; function GetMaxTableNameLength: Integer; override; function GetMaxTablesInSelect: Integer; override; function GetMaxUserNameLength: Integer; override; // policies (how are various data and operations handled): // function IsReadOnly: Boolean; override; -> Not implemented // function IsCatalogAtStart: Boolean; override; -> Not implemented function DoesMaxRowSizeIncludeBlobs: Boolean; override; // function NullsAreSortedHigh: Boolean; override; -> Not implemented // function NullsAreSortedLow: Boolean; override; -> Not implemented // function NullsAreSortedAtStart: Boolean; override; -> Not implemented // function NullsAreSortedAtEnd: Boolean; override; -> Not implemented // function NullPlusNonNullIsNull: Boolean; override; -> Not implemented // function UsesLocalFiles: Boolean; override; -> Not implemented function UsesLocalFilePerTable: Boolean; override; function StoresUpperCaseIdentifiers: Boolean; override; function StoresLowerCaseIdentifiers: Boolean; override; function StoresMixedCaseIdentifiers: Boolean; override; function StoresUpperCaseQuotedIdentifiers: Boolean; override; function StoresLowerCaseQuotedIdentifiers: Boolean; override; function StoresMixedCaseQuotedIdentifiers: Boolean; override; function GetDefaultTransactionIsolation: TZTransactIsolationLevel; override; function DataDefinitionCausesTransactionCommit: Boolean; override; function DataDefinitionIgnoredInTransactions: Boolean; override; // interface details (terms, keywords, etc): function GetSchemaTerm: string; override; function GetProcedureTerm: string; override; function GetCatalogTerm: string; override; function GetCatalogSeparator: string; override; function GetSQLKeywords: string; override; function GetNumericFunctions: string; override; function GetStringFunctions: string; override; function GetSystemFunctions: string; override; function GetTimeDateFunctions: string; override; function GetSearchStringEscape: string; override; function GetExtraNameCharacters: string; override; end; {** Implements Oracle Database Metadata. } TZOracleDatabaseMetadata = class(TZAbstractDatabaseMetadata) protected function CreateDatabaseInfo: IZDatabaseInfo; override; // technobot 2008-06-28 function UncachedGetTables(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const Types: TStringDynArray): IZResultSet; override; function UncachedGetSchemas: IZResultSet; override; // function UncachedGetCatalogs: IZResultSet; override; -> Not implemented function UncachedGetTableTypes: IZResultSet; override; function UncachedGetColumns(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const ColumnNamePattern: string): IZResultSet; override; function UncachedGetTablePrivileges(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string): IZResultSet; override; function UncachedGetColumnPrivileges(const Catalog: string; const Schema: string; const Table: string; const ColumnNamePattern: string): IZResultSet; override; function UncachedGetPrimaryKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; override; // function UncachedGetImportedKeys(const Catalog: string; const Schema: string; // const Table: string): IZResultSet; override; // function UncachedGetExportedKeys(const Catalog: string; const Schema: string; // const Table: string): IZResultSet; override; // function UncachedGetCrossReference(const PrimaryCatalog: string; const PrimarySchema: string; // const PrimaryTable: string; const ForeignCatalog: string; const ForeignSchema: string; // const ForeignTable: string): IZResultSet; override; function UncachedGetIndexInfo(const Catalog: string; const Schema: string; const Table: string; Unique: Boolean; Approximate: Boolean): IZResultSet; override; // function UncachedGetSequences(const Catalog: string; const SchemaPattern: string; // const SequenceNamePattern: string): IZResultSet; virtual; -> Not implemented function UncachedGetProcedures(const Catalog, SchemaPattern, ProcedureNamePattern: string): IZResultSet;override; function UncachedGetProcedureColumns(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string; const ColumnNamePattern: string): IZResultSet; override; // function UncachedGetVersionColumns(const Catalog: string; const Schema: string; // const Table: string): IZResultSet; override; // function UncachedGetTypeInfo: IZResultSet; override; public destructor Destroy; override; end; implementation uses ZDbcUtils; { TZOracleDatabaseInfo } //---------------------------------------------------------------------- // First, a variety of minor information about the target database. {** What's the name of this database product? @return database product name } function TZOracleDatabaseInfo.GetDatabaseProductName: string; begin Result := 'Oracle'; end; {** What's the version of this database product? @return database version } function TZOracleDatabaseInfo.GetDatabaseProductVersion: string; begin Result := ''; end; {** What's the name of this JDBC driver? @return JDBC driver name } function TZOracleDatabaseInfo.GetDriverName: string; begin Result := 'Zeos Database Connectivity Driver for Oracle'; end; {** What's this JDBC driver's major version number? @return JDBC driver major version } function TZOracleDatabaseInfo.GetDriverMajorVersion: Integer; begin Result := 1; end; {** What's this JDBC driver's minor version number? @return JDBC driver minor version number } function TZOracleDatabaseInfo.GetDriverMinorVersion: Integer; begin Result := 0; end; {** Does the database use a file for each table? @return true if the database uses a local file for each table } function TZOracleDatabaseInfo.UsesLocalFilePerTable: Boolean; begin Result := False; end; {** Does the database treat mixed case unquoted SQL identifiers as case sensitive and as a result store them in mixed case? A JDBC CompliantTM driver will always return false. @return true if so; false otherwise } function TZOracleDatabaseInfo.SupportsMixedCaseIdentifiers: Boolean; begin Result := False; end; {** Does the database treat mixed case unquoted SQL identifiers as case insensitive and store them in upper case? @return true if so; false otherwise } function TZOracleDatabaseInfo.StoresUpperCaseIdentifiers: Boolean; begin Result := True; end; {** Does the database treat mixed case unquoted SQL identifiers as case insensitive and store them in lower case? @return true if so; false otherwise } function TZOracleDatabaseInfo.StoresLowerCaseIdentifiers: Boolean; begin Result := False; end; {** Does the database treat mixed case unquoted SQL identifiers as case insensitive and store them in mixed case? @return true if so; false otherwise } function TZOracleDatabaseInfo.StoresMixedCaseIdentifiers: Boolean; begin Result := False; end; {** Does the database treat mixed case quoted SQL identifiers as case sensitive and as a result store them in mixed case? A JDBC CompliantTM driver will always return true. @return true if so; false otherwise } function TZOracleDatabaseInfo.SupportsMixedCaseQuotedIdentifiers: Boolean; begin Result := True; end; {** Does the database treat mixed case quoted SQL identifiers as case insensitive and store them in upper case? @return true if so; false otherwise } function TZOracleDatabaseInfo.StoresUpperCaseQuotedIdentifiers: Boolean; begin Result := False; end; {** Does the database treat mixed case quoted SQL identifiers as case insensitive and store them in lower case? @return true if so; false otherwise } function TZOracleDatabaseInfo.StoresLowerCaseQuotedIdentifiers: Boolean; begin Result := False; end; {** Does the database treat mixed case quoted SQL identifiers as case insensitive and store them in mixed case? @return true if so; false otherwise } function TZOracleDatabaseInfo.StoresMixedCaseQuotedIdentifiers: Boolean; begin Result := True; end; {** Gets a comma-separated list of all a database's SQL keywords that are NOT also SQL92 keywords. @return the list } function TZOracleDatabaseInfo.GetSQLKeywords: string; begin Result := 'ACCESS,ADD,ALTER,AUDIT,CLUSTER,COLUMN,COMMENT,COMPRESS,CONNECT,' + 'DATE,DROP,EXCLUSIVE,FILE,IDENTIFIED,IMMEDIATE,INCREMENT,INDEX,INITIAL,' + 'INTERSECT,LEVEL,LOCK,LONG,MAXEXTENTS,MINUS,MODE,NOAUDIT,NOCOMPRESS,' + 'NOWAIT,NUMBER,OFFLINE,ONLINE,PCTFREE,PRIOR'; end; {** Gets a comma-separated list of math functions. These are the X/Open CLI math function names used in the JDBC function escape clause. @return the list } function TZOracleDatabaseInfo.GetNumericFunctions: string; begin Result := 'ABS,ACOS,ASIN,ATAN,ATAN2,CEILING,COS,EXP,FLOOR,LOG,LOG10,MOD,PI,' + 'POWER,ROUND,SIGN,SIN,SQRT,TAN,TRUNCATE'; end; {** Gets a comma-separated list of string functions. These are the X/Open CLI string function names used in the JDBC function escape clause. @return the list } function TZOracleDatabaseInfo.GetStringFunctions: string; begin Result := 'ASCII,CHAR,CONCAT,LCASE,LENGTH,LTRIM,REPLACE,RTRIM,SOUNDEX,' + 'SUBSTRING,UCASE'; end; {** Gets a comma-separated list of system functions. These are the X/Open CLI system function names used in the JDBC function escape clause. @return the list } function TZOracleDatabaseInfo.GetSystemFunctions: string; begin Result := 'USER'; end; {** Gets a comma-separated list of time and date functions. @return the list } function TZOracleDatabaseInfo.GetTimeDateFunctions: string; begin Result := 'CURDATE,CURTIME,DAYOFMONTH,HOUR,MINUTE,MONTH,NOW,SECOND,YEAR'; end; {** Gets the string that can be used to escape wildcard characters. This is the string that can be used to escape '_' or '%' in the string pattern style catalog search parameters.

The '_' character represents any single character.

The '%' character represents any sequence of zero or more characters. @return the string used to escape wildcard characters } function TZOracleDatabaseInfo.GetSearchStringEscape: string; begin Result := '//'; end; {** Gets all the "extra" characters that can be used in unquoted identifier names (those beyond a-z, A-Z, 0-9 and _). @return the string containing the extra characters } function TZOracleDatabaseInfo.GetExtraNameCharacters: string; begin Result := '$#'; end; //-------------------------------------------------------------------- // Functions describing which features are supported. {** Are expressions in "ORDER BY" lists supported? @return true if so; false otherwise } function TZOracleDatabaseInfo.SupportsExpressionsInOrderBy: Boolean; begin Result := True; end; {** Can an "ORDER BY" clause use columns not in the SELECT statement? @return true if so; false otherwise } function TZOracleDatabaseInfo.SupportsOrderByUnrelated: Boolean; begin Result := True; end; {** Is some form of "GROUP BY" clause supported? @return true if so; false otherwise } function TZOracleDatabaseInfo.SupportsGroupBy: Boolean; begin Result := True; end; {** Can a "GROUP BY" clause use columns not in the SELECT? @return true if so; false otherwise } function TZOracleDatabaseInfo.SupportsGroupByUnrelated: Boolean; begin Result := True; end; {** Can a "GROUP BY" clause add columns not in the SELECT provided it specifies all the columns in the SELECT? @return true if so; false otherwise } function TZOracleDatabaseInfo.SupportsGroupByBeyondSelect: Boolean; begin Result := True; end; {** Is the SQL Integrity Enhancement Facility supported? @return true if so; false otherwise } function TZOracleDatabaseInfo.SupportsIntegrityEnhancementFacility: Boolean; begin Result := True; end; {** What's the database vendor's preferred term for "schema"? @return the vendor term } function TZOracleDatabaseInfo.GetSchemaTerm: string; begin Result := 'schema'; end; {** What's the database vendor's preferred term for "procedure"? @return the vendor term } function TZOracleDatabaseInfo.GetProcedureTerm: string; begin Result := 'procedure'; end; {** What's the database vendor's preferred term for "catalog"? @return the vendor term } function TZOracleDatabaseInfo.GetCatalogTerm: string; begin Result := ''; end; {** What's the separator between catalog and table name? @return the separator string } function TZOracleDatabaseInfo.GetCatalogSeparator: string; begin Result := ''; end; {** Can a schema name be used in a data manipulation statement? @return true if so; false otherwise } function TZOracleDatabaseInfo.SupportsSchemasInDataManipulation: Boolean; begin Result := True; end; {** Can a schema name be used in a procedure call statement? @return true if so; false otherwise } function TZOracleDatabaseInfo.SupportsSchemasInProcedureCalls: Boolean; begin Result := True; end; {** Can a schema name be used in a table definition statement? @return true if so; false otherwise } function TZOracleDatabaseInfo.SupportsSchemasInTableDefinitions: Boolean; begin Result := True; end; {** Can a schema name be used in an index definition statement? @return true if so; false otherwise } function TZOracleDatabaseInfo.SupportsSchemasInIndexDefinitions: Boolean; begin Result := True; end; {** Can a schema name be used in a privilege definition statement? @return true if so; false otherwise } function TZOracleDatabaseInfo.SupportsSchemasInPrivilegeDefinitions: Boolean; begin Result := True; end; {** Can a catalog name be used in a data manipulation statement? @return true if so; false otherwise } function TZOracleDatabaseInfo.SupportsCatalogsInDataManipulation: Boolean; begin Result := False; end; {** Can a catalog name be used in a procedure call statement? @return true if so; false otherwise } function TZOracleDatabaseInfo.SupportsCatalogsInProcedureCalls: Boolean; begin Result := False; end; {** Can a catalog name be used in a table definition statement? @return true if so; false otherwise } function TZOracleDatabaseInfo.SupportsCatalogsInTableDefinitions: Boolean; begin Result := False; end; {** Can a catalog name be used in an index definition statement? @return true if so; false otherwise } function TZOracleDatabaseInfo.SupportsCatalogsInIndexDefinitions: Boolean; begin Result := False; end; {** Can a catalog name be used in a privilege definition statement? @return true if so; false otherwise } function TZOracleDatabaseInfo.SupportsCatalogsInPrivilegeDefinitions: Boolean; begin Result := False; end; {** Is positioned DELETE supported? @return true if so; false otherwise } function TZOracleDatabaseInfo.SupportsPositionedDelete: Boolean; begin Result := False; end; {** Is positioned UPDATE supported? @return true if so; false otherwise } function TZOracleDatabaseInfo.SupportsPositionedUpdate: Boolean; begin Result := False; end; {** Is SELECT for UPDATE supported? @return true if so; false otherwise } function TZOracleDatabaseInfo.SupportsSelectForUpdate: Boolean; begin Result := True; end; {** Are stored procedure calls using the stored procedure escape syntax supported? @return true if so; false otherwise } function TZOracleDatabaseInfo.SupportsStoredProcedures: Boolean; begin Result := True; end; {** Are subqueries in comparison expressions supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZOracleDatabaseInfo.SupportsSubqueriesInComparisons: Boolean; begin Result := True; end; {** Are subqueries in 'exists' expressions supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZOracleDatabaseInfo.SupportsSubqueriesInExists: Boolean; begin Result := True; end; {** Are subqueries in 'in' statements supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZOracleDatabaseInfo.SupportsSubqueriesInIns: Boolean; begin Result := True; end; {** Are subqueries in quantified expressions supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZOracleDatabaseInfo.SupportsSubqueriesInQuantifieds: Boolean; begin Result := True; end; {** Are correlated subqueries supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZOracleDatabaseInfo.SupportsCorrelatedSubqueries: Boolean; begin Result := True; end; {** Is SQL UNION supported? @return true if so; false otherwise } function TZOracleDatabaseInfo.SupportsUnion: Boolean; begin Result := True; end; {** Is SQL UNION ALL supported? @return true if so; false otherwise } function TZOracleDatabaseInfo.SupportsUnionAll: Boolean; begin Result := True; end; {** Can cursors remain open across commits? @return true if cursors always remain open; false if they might not remain open } function TZOracleDatabaseInfo.SupportsOpenCursorsAcrossCommit: Boolean; begin Result := False; end; {** Can cursors remain open across rollbacks? @return true if cursors always remain open; false if they might not remain open } function TZOracleDatabaseInfo.SupportsOpenCursorsAcrossRollback: Boolean; begin Result := False; end; {** Can statements remain open across commits? @return true if statements always remain open; false if they might not remain open } function TZOracleDatabaseInfo.SupportsOpenStatementsAcrossCommit: Boolean; begin Result := False; end; {** Can statements remain open across rollbacks? @return true if statements always remain open; false if they might not remain open } function TZOracleDatabaseInfo.SupportsOpenStatementsAcrossRollback: Boolean; begin Result := False; end; //---------------------------------------------------------------------- // The following group of methods exposes various limitations // based on the target database with the current driver. // Unless otherwise specified, a result of zero means there is no // limit, or the limit is not known. {** How many hex characters can you have in an inline binary literal? @return max binary literal length in hex characters; a result of zero means that there is no limit or the limit is not known } function TZOracleDatabaseInfo.GetMaxBinaryLiteralLength: Integer; begin Result := 1000; end; {** What's the max length for a character literal? @return max literal length; a result of zero means that there is no limit or the limit is not known } function TZOracleDatabaseInfo.GetMaxCharLiteralLength: Integer; begin Result := 2000; end; {** What's the limit on column name length? @return max column name length; a result of zero means that there is no limit or the limit is not known } function TZOracleDatabaseInfo.GetMaxColumnNameLength: Integer; begin Result := 30; end; {** What's the maximum number of columns in a "GROUP BY" clause? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZOracleDatabaseInfo.GetMaxColumnsInGroupBy: Integer; begin Result := 0; end; {** What's the maximum number of columns allowed in an index? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZOracleDatabaseInfo.GetMaxColumnsInIndex: Integer; begin Result := 32; end; {** What's the maximum number of columns in an "ORDER BY" clause? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZOracleDatabaseInfo.GetMaxColumnsInOrderBy: Integer; begin Result := 0; end; {** What's the maximum number of columns in a "SELECT" list? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZOracleDatabaseInfo.GetMaxColumnsInSelect: Integer; begin Result := 0; end; {** What's the maximum number of columns in a table? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZOracleDatabaseInfo.GetMaxColumnsInTable: Integer; begin Result := 1000; end; {** How many active connections can we have at a time to this database? @return max number of active connections; a result of zero means that there is no limit or the limit is not known } function TZOracleDatabaseInfo.GetMaxConnections: Integer; begin Result := 0; end; {** What's the maximum cursor name length? @return max cursor name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZOracleDatabaseInfo.GetMaxCursorNameLength: Integer; begin Result := 0; end; {** Retrieves the maximum number of bytes for an index, including all of the parts of the index. @return max index length in bytes, which includes the composite of all the constituent parts of the index; a result of zero means that there is no limit or the limit is not known } function TZOracleDatabaseInfo.GetMaxIndexLength: Integer; begin Result := 0; end; {** What's the maximum length allowed for a schema name? @return max name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZOracleDatabaseInfo.GetMaxSchemaNameLength: Integer; begin Result := 30; end; {** What's the maximum length of a procedure name? @return max name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZOracleDatabaseInfo.GetMaxProcedureNameLength: Integer; begin Result := 30; end; {** What's the maximum length of a catalog name? @return max name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZOracleDatabaseInfo.GetMaxCatalogNameLength: Integer; begin Result := 0; end; {** What's the maximum length of a single row? @return max row size in bytes; a result of zero means that there is no limit or the limit is not known } function TZOracleDatabaseInfo.GetMaxRowSize: Integer; begin Result := 2000; end; {** Did getMaxRowSize() include LONGVARCHAR and LONGVARBINARY blobs? @return true if so; false otherwise } function TZOracleDatabaseInfo.DoesMaxRowSizeIncludeBlobs: Boolean; begin Result := True; end; {** What's the maximum length of an SQL statement? @return max length in bytes; a result of zero means that there is no limit or the limit is not known } function TZOracleDatabaseInfo.GetMaxStatementLength: Integer; begin Result := 65535; end; {** How many active statements can we have open at one time to this database? @return the maximum number of statements that can be open at one time; a result of zero means that there is no limit or the limit is not known } function TZOracleDatabaseInfo.GetMaxStatements: Integer; begin Result := 0; end; {** What's the maximum length of a table name? @return max name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZOracleDatabaseInfo.GetMaxTableNameLength: Integer; begin Result := 30; end; {** What's the maximum number of tables in a SELECT statement? @return the maximum number of tables allowed in a SELECT statement; a result of zero means that there is no limit or the limit is not known } function TZOracleDatabaseInfo.GetMaxTablesInSelect: Integer; begin Result := 0; end; {** What's the maximum length of a user name? @return max user name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZOracleDatabaseInfo.GetMaxUserNameLength: Integer; begin Result := 30; end; //---------------------------------------------------------------------- {** What's the database's default transaction isolation level? The values are defined in java.sql.Connection. @return the default isolation level @see Connection } function TZOracleDatabaseInfo.GetDefaultTransactionIsolation: TZTransactIsolationLevel; begin Result := tiReadCommitted; end; {** Are transactions supported? If not, invoking the method commit is a noop and the isolation level is TRANSACTION_NONE. @return true if transactions are supported; false otherwise } function TZOracleDatabaseInfo.SupportsTransactions: Boolean; begin Result := True; end; {** Does this database support the given transaction isolation level? @param level the values are defined in java.sql.Connection @return true if so; false otherwise @see Connection } function TZOracleDatabaseInfo.SupportsTransactionIsolationLevel( Level: TZTransactIsolationLevel): Boolean; begin Result := True; end; {** Are both data definition and data manipulation statements within a transaction supported? @return true if so; false otherwise } function TZOracleDatabaseInfo. SupportsDataDefinitionAndDataManipulationTransactions: Boolean; begin Result := True; end; {** Are only data manipulation statements within a transaction supported? @return true if so; false otherwise } function TZOracleDatabaseInfo. SupportsDataManipulationTransactionsOnly: Boolean; begin Result := True; end; {** Does a data definition statement within a transaction force the transaction to commit? @return true if so; false otherwise } function TZOracleDatabaseInfo.DataDefinitionCausesTransactionCommit: Boolean; begin Result := True; end; {** Is a data definition statement within a transaction ignored? @return true if so; false otherwise } function TZOracleDatabaseInfo.DataDefinitionIgnoredInTransactions: Boolean; begin Result := False; end; {** Does the database support the given result set type? @param type defined in java.sql.ResultSet @return true if so; false otherwise } function TZOracleDatabaseInfo.SupportsResultSetType( _Type: TZResultSetType): Boolean; begin Result := _Type = rtForwardOnly; end; {** Does the database support the concurrency type in combination with the given result set type? @param type defined in java.sql.ResultSet @param concurrency type defined in java.sql.ResultSet @return true if so; false otherwise } function TZOracleDatabaseInfo.SupportsResultSetConcurrency( _Type: TZResultSetType; Concurrency: TZResultSetConcurrency): Boolean; begin Result := (_Type = rtForwardOnly) and (Concurrency = rcReadOnly); end; {** Does the Database or Actual Version understand non escaped search strings? @return true if the DataBase does understand non escaped search strings } function TZOracleDatabaseInfo.SupportsNonEscapedSearchStrings: Boolean; begin Result := MetaData.GetConnection.GetClientVersion > 10000000; end; { TZOracleDatabaseMetadata } {** Destroys this object and cleanups the memory. } destructor TZOracleDatabaseMetadata.Destroy; begin inherited Destroy; end; {** Constructs a database information object and returns the interface to it. Used internally by the constructor. @return the database information object interface } function TZOracleDatabaseMetadata.CreateDatabaseInfo: IZDatabaseInfo; begin Result := TZOracleDatabaseInfo.Create(Self); end; {** Gets a description of tables available in a catalog.

Only table descriptions matching the catalog, schema, table name and type criteria are returned. They are ordered by TABLE_TYPE, TABLE_SCHEM and TABLE_NAME.

Each table description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. TABLE_TYPE String => table type. Typical types are "TABLE", "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM".
  5. REMARKS String => explanatory comment on the table

Note: Some databases may not return information for all tables. @param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param tableNamePattern a table name pattern @param types a list of table types to include; null returns all types @return ResultSet - each row is a table description @see #getSearchStringEscape } function TZOracleDatabaseMetadata.UncachedGetTables(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const Types: TStringDynArray): IZResultSet; var NameCondition, OwnerCondition, PartSQL, SQL: string; function IncludedType(const TypeName: string): Boolean; var I: Integer; begin Result := False; for I := Low(Types) to High(Types) do Result := Result or (UpperCase(Types[I]) = TypeName); Result := Result or (Length(Types) = 0); end; function CreateWhere: String; begin Result := ''; If OwnerCondition <> '' then Result := OwnerCondition; If NameCondition <> '' then If Result <> '' then Result := Result + ' AND ' + NameCondition Else Result := NameCondition; If Result <> '' then Result := ' Where ' + Result; end; begin OwnerCondition := ConstructNameCondition(SchemaPattern,'OWNER'); if IncludedType('TABLE') then begin NameCondition := ConstructNameCondition(TableNamePattern,'TABLE_NAME'); SQL := 'SELECT NULL AS TABLE_CAT, OWNER AS TABLE_SCHEM, TABLE_NAME,' + ' ''TABLE'' AS TABLE_TYPE, NULL AS REMARKS FROM SYS.ALL_TABLES' + CreateWhere; end else SQL := ''; if IncludedType('SYNONYM') then begin NameCondition := ConstructNameCondition(TableNamePattern,'SYNONYM_NAME'); PartSQL := 'SELECT NULL AS TABLE_CAT, OWNER AS TABLE_SCHEM,' + ' SYNONYM_NAME AS TABLE_NAME, ''SYNONYM'' AS TABLE_TYPE,' + ' NULL AS REMARKS FROM SYS.ALL_SYNONYMS' + CreateWhere; if SQL <> '' then SQL := SQL + ' UNION '; SQL := SQL + PartSQL; end; if IncludedType('VIEW') then begin NameCondition := ConstructNameCondition(TableNamePattern,'VIEW_NAME'); PartSQL := 'SELECT NULL AS TABLE_CAT, OWNER AS TABLE_SCHEM,' + ' VIEW_NAME AS TABLE_NAME, ''VIEW'' AS TABLE_TYPE,' + ' NULL AS REMARKS FROM SYS.ALL_VIEWS' + CreateWhere; if SQL <> '' then SQL := SQL + ' UNION '; SQL := SQL + PartSQL; end; if IncludedType('SEQUENCE') then begin OwnerCondition := ConstructNameCondition(SchemaPattern,'SEQUENCE_OWNER'); NameCondition := ConstructNameCondition(TableNamePattern,'SEQUENCE_NAME'); PartSQL := 'SELECT NULL AS TABLE_CAT, SEQUENCE_OWNER AS TABLE_SCHEM,' + ' SEQUENCE_NAME AS TABLE_NAME, ''SEQUENCE'' AS TABLE_TYPE,' + ' NULL AS REMARKS FROM SYS.ALL_SEQUENCES' + CreateWhere; if SQL <> '' then SQL := SQL + ' UNION '; SQL := SQL + PartSQL; end; Result := CopyToVirtualResultSet( GetConnection.CreateStatement.ExecuteQuery(SQL), ConstructVirtualResultSet(TableColumnsDynArray)); end; function TZOracleDatabaseMetadata.UncachedGetProcedureColumns(const Catalog, SchemaPattern, ProcedureNamePattern, ColumnNamePattern: string): IZResultSet; var ColumnIndexes : Array[1..9] of integer; colName: string; IZStmt: IZStatement; TempSet: IZResultSet; Names, Procs: TStrings; PackageName, ProcName, TempProcedureNamePattern, TmpSchemaPattern: String; function GetNextName(const AName: String; NameEmpty: Boolean = False): String; var N: Integer; NewName: String; begin if ( PackageName = '' ) or ( not ( PackageName = ProcedureNamePattern ) ) then NewName := AName else NewName := ProcName+'.'+AName; if (Names.IndexOf(NewName) = -1) and not NameEmpty then begin Names.Add(NewName); Result := NewName; end else for N := 1 to MaxInt do if Names.IndexOf(NewName+IntToStr(N)) = -1 then begin Result := NewName+IntToStr(N); Names.Add(Result); Break; end; end; procedure InsertProcedureColumnValues(Source: IZResultSet; IsResultParam: Boolean = False); var TypeName, SubTypeName: string; begin TypeName := Source.GetString(ColumnIndexes[4]); SubTypeName := Source.GetString(ColumnIndexes[5]); PackageName := Source.GetString(ColumnIndexes[8]); ProcName := Source.GetString(ColumnIndexes[9]); Result.MoveToInsertRow; Result.UpdateNull(1); //PROCEDURE_CAT Result.UpdateNull(2); //PROCEDURE_SCHEM Result.UpdateString(3, Source.GetString(ColumnIndexes[1])); //TABLE_NAME if IsResultParam then Result.UpdateInt(5, Ord(pctReturn)) else if Source.GetString(ColumnIndexes[3]) = 'IN' then Result.UpdateInt(5, Ord(pctIn)) else if Source.GetString(ColumnIndexes[3]) = 'OUT' then Result.UpdateInt(5, Ord(pctOut)) else if ( Source.GetString(ColumnIndexes[3]) = 'IN/OUT') then Result.UpdateInt(5, Ord(pctInOut)) else Result.UpdateInt(5, Ord(pctUnknown)); ColName := Source.GetString(ColumnIndexes[2]); if IsResultParam then Result.UpdateString(4, GetNextName('ReturnValue', False)) //COLUMN_NAME else Result.UpdateString(4, GetNextName(ColName, Length(ColName) = 0)); //COLUMN_NAME Result.UpdateInt(6, Ord(ConvertOracleTypeToSQLType(TypeName, Source.GetInt(ColumnIndexes[6]),Source.GetInt(ColumnIndexes[7]), ConSettings.CPType))); //DATA_TYPE Result.UpdateString(7,TypeName); //TYPE_NAME Result.UpdateInt(10, Source.GetInt(ColumnIndexes[6])); //PRECISION Result.UpdateNull(9); //BUFFER_LENGTH Result.UpdateInt(10, Source.GetInt(ColumnIndexes[7])); Result.UpdateInt(11, 10); //Result.UpdateInt(12, GetInt(ColumnIndexes[8])); Result.UpdateNull(12); Result.UpdateString(12, Source.GetString(ColumnIndexes[6])); Result.InsertRow; end; function GetColumnSQL(PosChar: String; Package: String = ''): String; var OwnerCondition, PackageNameCondition, PackageAsProcCondition, PackageProcNameCondition: string; procedure SplitPackageAndProc(Value: String); var iPos: Integer; begin PackageName := ''; ProcName := 'Value'; iPos := Pos('.', Value); if (iPos > 0) then begin PackageNameCondition := ConstructNameCondition(Copy(Value, 1, iPos-1),'package_name'); PackageProcNameCondition := ConstructNameCondition(Copy(Value, iPos+1,Length(Value)-iPos),'object_name'); PackageAsProcCondition := ConstructNameCondition(Copy(Value, iPos+1,Length(Value)-iPos),'package_name'); PackageName := '= '+#39+IC.ExtractQuote(Copy(Value, 1, iPos-1))+#39; ProcName := IC.ExtractQuote(Copy(Value, iPos+1,Length(Value)-iPos)); end else begin PackageNameCondition := 'package_name IS NULL'; PackageProcNameCondition := ConstructNameCondition(Value,'object_name'); PackageAsProcCondition := ConstructNameCondition(Value,'package_name'); PackageName := 'IS NULL'; ProcName := IC.ExtractQuote(Value); end; end; begin OwnerCondition := ConstructNameCondition(TmpSchemaPattern,'OWNER'); SplitPackageAndProc(TempProcedureNamePattern); Result := 'select * from all_arguments where ('+PackageNameCondition+ ' AND '+PackageProcNameCondition+ ' OR '+ PackageAsProcCondition+')'+ 'AND POSITION '+PosChar+' 0'; If OwnerCondition <> '' then Result := Result + ' AND ' + OwnerCondition; Result := Result + ' ORDER BY POSITION'; end; procedure AddColumns(WasNext: Boolean; WasFunc: Boolean); begin if WasNext then InsertProcedureColumnValues(TempSet, WasFunc); while TempSet.Next do InsertProcedureColumnValues(TempSet, WasFunc); TempSet.Close; if not WasFunc then begin TempSet := IZStmt.ExecuteQuery(GetColumnSQL('=')); //ReturnValue has allways Position = 0 with TempSet do begin while Next do InsertProcedureColumnValues(TempSet, True); Close; end; end; end; procedure GetMoreProcedures; var i: Integer; PackageNameCondition: String; begin PackageNameCondition := ConstructNameCondition(ProcedureNamePattern,'package_name'); If PackageNameCondition <> '' then PackageNameCondition := ' WHERE ' + PackageNameCondition; TempSet.Close; TempSet := IZStmt.ExecuteQuery('select object_name from user_arguments ' + PackageNameCondition + ' GROUP BY object_name order by object_name'); while TempSet.Next do Procs.Add(TempSet.GetString(1)); TempSet.Close; for i := 0 to Procs.Count -1 do begin TempProcedureNamePattern := ProcedureNamePattern+'.'+IC.Quote(Procs[i]); TempSet := IZStmt.ExecuteQuery(GetColumnSQL('>')); //ParameterValues have allways Position > 0 AddColumns(False, False); end; end; function CheckSchema: Boolean; begin if TmpSchemaPattern = '' then Result := False else with GetConnection.CreateStatement.ExecuteQuery('SELECT COUNT(*) FROM ALL_USERS WHERE '+ConstructNameCondition(TmpSchemaPattern,'username')) do begin Next; Result := GetInt(1) > 0; Close; end; end; begin Result:=inherited UncachedGetProcedureColumns(Catalog, SchemaPattern, ProcedureNamePattern, ColumnNamePattern); {improve SplitQualifiedObjectName: Oracle does'nt support catalogs} if Catalog = '' then TmpSchemaPattern := SchemaPattern else TmpSchemaPattern := Catalog; if ( TmpSchemaPattern = '' ) then TempProcedureNamePattern := ProcedureNamePattern //just a procedurename or package or both else if CheckSchema then TempProcedureNamePattern := ProcedureNamePattern //Schema exists not a package else begin TempProcedureNamePattern := TmpSchemaPattern+'.'+ProcedureNamePattern; //no Schema so it's a PackageName TmpSchemaPattern := ''; end; if TempProcedureNamePattern <> '' then begin Names := TStringList.Create; Procs := TStringList.Create; IZStmt := GetConnection.CreateStatement; TempSet := IZStmt.ExecuteQuery(GetColumnSQL('>')); //ParameterValues have allways Position > 0 with TempSet do begin ColumnIndexes[1] := FindColumn('object_name'); ColumnIndexes[2] := FindColumn('argument_name'); ColumnIndexes[3] := FindColumn('IN_OUT'); //'RDB$PARAMETER_TYPE'); ColumnIndexes[4] := FindColumn('DATA_TYPE');//'RDB$FIELD_TYPE'); ColumnIndexes[5] := FindColumn('TYPE_SUBNAME');//RDB$FIELD_SUB_TYPE'); ColumnIndexes[6] := FindColumn('DATA_PRECISION');//RDB$FIELD_PRECISION'); ColumnIndexes[7] := FindColumn('DATA_SCALE');//RDB$FIELD_SCALE'); ColumnIndexes[8] := FindColumn('package_name'); ColumnIndexes[9] := FindColumn('object_name'); end; if ( PackageName <> 'IS NULL' ) and ( ProcName <> '' ) then AddColumns(False, False) else if TempSet.Next then if ( TempSet.GetString(ColumnIndexes[8]) = ProcName ) then {Package without proc found} GetMoreProcedures else AddColumns(True, False) else begin TempSet.Close; TempSet := IZStmt.ExecuteQuery(GetColumnSQL('=')); //ParameterValues have allways Position > 0 if TempSet.Next then if ( TempSet.GetString(ColumnIndexes[8]) = ProcName ) then {Package without proc found} GetMoreProcedures else AddColumns(True, True) end; TempSet := nil; IZStmt.Close; FreeAndNil(Names); FreeAndNil(Procs); end; end; function TZOracleDatabaseMetadata.UncachedGetProcedures(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string): IZResultSet; var SQL: string; LProcedureNamePattern, LSchemaNamePattern: string; sName:string; begin Result:=inherited UncachedGetProcedures(Catalog, SchemaPattern, ProcedureNamePattern); LProcedureNamePattern := ConstructNameCondition(ProcedureNamePattern,'decode(procedure_name,null,object_name,object_name||''.''||procedure_name)'); LSchemaNamePattern := ConstructNameCondition(SchemaPattern,'owner'); SQL := 'select NULL AS PROCEDURE_CAT, OWNER AS PROCEDURE_SCHEM, '+ 'OBJECT_NAME, PROCEDURE_NAME AS PROCEDURE_NAME, '+ 'OVERLOAD AS PROCEDURE_OVERLOAD, OBJECT_TYPE AS PROCEDURE_TYPE FROM '+ 'ALL_PROCEDURES WHERE 1=1'; if LProcedureNamePattern <> '' then SQL := SQL + ' AND ' + LProcedureNamePattern; if LSchemaNamePattern <> '' then SQL := SQL + ' AND ' + LSchemaNamePattern; SQL := SQL + ' ORDER BY decode(owner,user,0,1),owner,object_name,procedure_name,overload'; with GetConnection.CreateStatement.ExecuteQuery(SQL) do begin while Next do begin sName := IC.Quote(GetString(3)); if GetString(4) <> '' then sName := sName+'.'+IC.Quote(GetString(4)); Result.MoveToInsertRow; Result.UpdateNull(1); Result.UpdateString(2, GetString(2)); Result.UpdateString(3, sName); //PROCEDURE_NAME Result.UpdateString(4, GetString(5)); //PROCEDURE_OVERLOAD Result.UpdateNull(5); Result.UpdateNull(6); Result.UpdateNull(7); if GetString(6) = 'FUNCTION' then Result.UpdateInt(8, Ord(prtReturnsResult)) else if GetString(6) = 'PROCDEURE' then Result.UpdateInt(8, Ord(prtNoResult)) else Result.UpdateInt(8, Ord(prtUnknown)); //Package Result.InsertRow; end; Close; end; end; {** Gets the schema names available in this database. The results are ordered by schema name.

The schema column is:

  1. TABLE_SCHEM String => schema name
@return ResultSet - each row has a single String column that is a schema name } function TZOracleDatabaseMetadata.UncachedGetSchemas: IZResultSet; begin Result := CopyToVirtualResultSet( GetConnection.CreateStatement.ExecuteQuery( 'SELECT USERNAME AS TABLE_SCHEM FROM SYS.ALL_USERS'), ConstructVirtualResultSet(SchemaColumnsDynArray)); end; {** Gets the table types available in this database. The results are ordered by table type.

The table type is:

  1. TABLE_TYPE String => table type. Typical types are "TABLE", "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM".
@return ResultSet - each row has a single String column that is a table type } function TZOracleDatabaseMetadata.UncachedGetTableTypes: IZResultSet; const TableTypeCount = 4; Types: array [1..TableTypeCount] of String = ( 'TABLE', 'SYNONYM', 'VIEW', 'SEQUENCE' ); var I: Integer; begin Result:=inherited UncachedGetTableTypes; for I := 1 to TableTypeCount do begin Result.MoveToInsertRow; Result.UpdateString(1, Types[I]); Result.InsertRow; end; end; {** Gets a description of table columns available in the specified catalog.

Only column descriptions matching the catalog, schema, table and column name criteria are returned. They are ordered by TABLE_SCHEM, TABLE_NAME and ORDINAL_POSITION.

Each column description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. COLUMN_NAME String => column name
  5. DATA_TYPE short => SQL type from java.sql.Types
  6. TYPE_NAME String => Data source dependent type name, for a UDT the type name is fully qualified
  7. COLUMN_SIZE int => column size. For char or date types this is the maximum number of characters, for numeric or decimal types this is precision.
  8. BUFFER_LENGTH is not used.
  9. DECIMAL_DIGITS int => the number of fractional digits
  10. NUM_PREC_RADIX int => Radix (typically either 10 or 2)
  11. NULLABLE int => is NULL allowed?
    • columnNoNulls - might not allow NULL values
    • columnNullable - definitely allows NULL values
    • columnNullableUnknown - nullability unknown
  12. REMARKS String => comment describing column (may be null)
  13. COLUMN_DEF String => default value (may be null)
  14. SQL_DATA_TYPE int => unused
  15. SQL_DATETIME_SUB int => unused
  16. CHAR_OCTET_LENGTH int => for char types the maximum number of bytes in the column
  17. ORDINAL_POSITION int => index of column in table (starting at 1)
  18. IS_NULLABLE String => "NO" means column definitely does not allow NULL values; "YES" means the column might allow NULL values. An empty string means nobody knows.
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param tableNamePattern a table name pattern @param columnNamePattern a column name pattern @return ResultSet - each row is a column description @see #getSearchStringEscape } function TZOracleDatabaseMetadata.UncachedGetColumns(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const ColumnNamePattern: string): IZResultSet; var SQL: string; SQLType: TZSQLType; OwnerCondition,TableCondition,ColumnCondition: String; function CreateWhere: String; begin Result := ''; If OwnerCondition <> '' then Result := OwnerCondition; If TableCondition <> '' then If Result <> '' then Result := Result + ' AND ' + TableCondition Else Result := TableCondition; If ColumnCondition <> '' then If Result <> '' then Result := Result + ' AND ' + ColumnCondition Else Result := ColumnCondition; If Result <> '' then Result := ' Where ' + Result; end; begin OwnerCondition := ConstructNameCondition(SchemaPattern,'OWNER'); TableCondition := ConstructNameCondition(TableNamePattern,'TABLE_NAME'); ColumnCondition := ConstructNameCondition(ColumnNamePattern,'COLUMN_NAME'); Result:=inherited UncachedGetColumns(Catalog, SchemaPattern, TableNamePattern, ColumnNamePattern); SQL := 'SELECT NULL, OWNER, TABLE_NAME, COLUMN_NAME, NULL, DATA_TYPE,' + ' DATA_LENGTH, NULL, DATA_PRECISION, DATA_SCALE, NULLABLE, NULL,' + ' DATA_DEFAULT, NULL, NULL, NULL, COLUMN_ID, NULLABLE' + ' FROM SYS.ALL_TAB_COLUMNS' + CreateWhere; with GetConnection.CreateStatement.ExecuteQuery(SQL) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateNull(1); Result.UpdateString(2, GetString(2)); Result.UpdateString(3, GetString(3)); Result.UpdateString(4, GetString(4)); SQLType := ConvertOracleTypeToSQLType(GetString(6), GetInt(9), GetInt(10), ConSettings.CPType); Result.UpdateInt(5, Ord(SQLType)); Result.UpdateString(6, GetString(6)); Result.UpdateInt(7, GetFieldSize(SQLType, ConSettings, GetInt(7), ConSettings.ClientCodePage.CharWidth)); //FIELD_SIZE Result.UpdateNull(8); Result.UpdateInt(9, GetInt(9)); Result.UpdateInt(10, GetInt(10)); if UpperCase(GetString(11)) = 'N' then begin Result.UpdateInt(11, Ord(ntNoNulls)); Result.UpdateString(18, 'NO'); end else begin Result.UpdateInt(11, Ord(ntNullable)); Result.UpdateString(18, 'YES'); end; Result.UpdateNull(12); Result.UpdateString(13, GetString(13)); Result.UpdateNull(14); Result.UpdateNull(15); Result.UpdateNull(16); Result.UpdateInt(17, GetInt(17)); Result.UpdateNull(19); //AUTO_INCREMENT Result.UpdateBoolean(20, //CASE_SENSITIVE IC.IsCaseSensitive(GetString(4))); Result.UpdateBoolean(21, True); //SEARCHABLE Result.UpdateBoolean(22, not (GetString(6) = 'BFILE')); //WRITABLE Result.UpdateBoolean(23, True); //DEFINITELYWRITABLE Result.UpdateBoolean(24, (GetString(6) = 'BFILE')); //READONLY Result.InsertRow; end; Close; end; end; {** Gets a description of the access rights for a table's columns.

Only privileges matching the column name criteria are returned. They are ordered by COLUMN_NAME and PRIVILEGE.

Each privilige description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. COLUMN_NAME String => column name
  5. GRANTOR => grantor of access (may be null)
  6. GRANTEE String => grantee of access
  7. PRIVILEGE String => name of access (SELECT, INSERT, UPDATE, REFRENCES, ...)
  8. IS_GRANTABLE String => "YES" if grantee is permitted to grant to others; "NO" if not; null if unknown
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @param columnNamePattern a column name pattern @return ResultSet - each row is a column privilege description @see #getSearchStringEscape } function TZOracleDatabaseMetadata.UncachedGetColumnPrivileges(const Catalog: string; const Schema: string; const Table: string; const ColumnNamePattern: string): IZResultSet; var SQL: string; OwnerCondition,TableCondition,ColumnCondition: String; function CreateWhere: String; begin Result := ''; If OwnerCondition <> '' then Result := OwnerCondition; If TableCondition <> '' then If Result <> '' then Result := Result + ' AND ' + TableCondition Else Result := TableCondition; If ColumnCondition <> '' then If Result <> '' then Result := Result + ' AND ' + ColumnCondition Else Result := ColumnCondition; If Result <> '' then Result := ' Where ' + Result; end; begin OwnerCondition := ConstructNameCondition(Schema,'TABLE_SCHEMA'); TableCondition := ConstructNameCondition(Table,'TABLE_NAME'); ColumnCondition := ConstructNameCondition(ColumnNamePattern,'COLUMN_NAME'); SQL := 'SELECT NULL AS TABLE_CAT, TABLE_SCHEMA AS TABLE_SCHEM, TABLE_NAME,' + ' COLUMN_NAME, GRANTOR, GRANTEE, PRIVILEGE, GRANTABLE AS IS_GRANTABLE' + ' FROM SYS.ALL_COL_PRIVS' + CreateWhere; Result := CopyToVirtualResultSet( GetConnection.CreateStatement.ExecuteQuery(SQL), ConstructVirtualResultSet(TableColPrivColumnsDynArray)); end; {** Gets a description of the access rights for each table available in a catalog. Note that a table privilege applies to one or more columns in the table. It would be wrong to assume that this priviledge applies to all columns (this may be true for some systems but is not true for all.)

Only privileges matching the schema and table name criteria are returned. They are ordered by TABLE_SCHEM, TABLE_NAME, and PRIVILEGE.

Each privilige description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. GRANTOR => grantor of access (may be null)
  5. GRANTEE String => grantee of access
  6. PRIVILEGE String => name of access (SELECT, INSERT, UPDATE, REFRENCES, ...)
  7. IS_GRANTABLE String => "YES" if grantee is permitted to grant to others; "NO" if not; null if unknown
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param tableNamePattern a table name pattern @return ResultSet - each row is a table privilege description @see #getSearchStringEscape } function TZOracleDatabaseMetadata.UncachedGetTablePrivileges(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string): IZResultSet; var SQL: string; OwnerCondition,TableCondition: String; function CreateWhere: String; begin Result := ''; If OwnerCondition <> '' then Result := OwnerCondition; If TableCondition <> '' then If Result <> '' then Result := Result + ' AND ' + TableCondition Else Result := TableCondition; If Result <> '' then Result := ' Where ' + Result; end; begin OwnerCondition := ConstructNameCondition(SchemaPattern,'TABLE_SCHEMA'); TableCondition := ConstructNameCondition(TableNamePattern,'TABLE_NAME'); SQL := 'SELECT NULL AS TABLE_CAT, TABLE_SCHEMA AS TABLE_SCHEM, TABLE_NAME,' + ' GRANTOR, GRANTEE, PRIVILEGE, GRANTABLE AS IS_GRANTABLE' + ' FROM SYS.ALL_TAB_PRIVS ' + CreateWhere; Result := CopyToVirtualResultSet( GetConnection.CreateStatement.ExecuteQuery(SQL), ConstructVirtualResultSet(TablePrivColumnsDynArray)); end; {** Gets a description of a table's primary key columns. They are ordered by COLUMN_NAME.

Each primary key column description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. COLUMN_NAME String => column name
  5. KEY_SEQ short => sequence number within primary key
  6. PK_NAME String => primary key name (may be null)
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a primary key column description @exception SQLException if a database access error occurs } function TZOracleDatabaseMetadata.UncachedGetPrimaryKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; var SQL: string; OwnerCondition,TableCondition: String; function CreateExtraWhere: String; begin Result := ''; If OwnerCondition <> '' then Result := OwnerCondition; If TableCondition <> '' then If Result <> '' then Result := Result + ' AND ' + TableCondition Else Result := TableCondition; If Result <> '' then Result := ' AND ' + Result; end; begin OwnerCondition := ConstructNameCondition(Schema,'A.OWNER'); TableCondition := ConstructNameCondition(Table,'A.TABLE_NAME'); SQL := 'SELECT NULL AS TABLE_CAT, A.OWNER AS TABLE_SCHEM, A.TABLE_NAME,' + ' B.COLUMN_NAME, B.COLUMN_POSITION AS KEY_SEQ, A.INDEX_NAME AS PK_NAME' + ' FROM ALL_INDEXES A, ALL_IND_COLUMNS B' + ' WHERE A.OWNER=B.INDEX_OWNER AND A.INDEX_NAME=B.INDEX_NAME' + ' AND A.TABLE_OWNER=B.TABLE_OWNER AND A.TABLE_NAME=B.TABLE_NAME' + ' AND A.UNIQUENESS=''UNIQUE'' AND A.GENERATED=''Y''' + ' AND A.INDEX_NAME LIKE ''SYS_%''' + CreateExtraWhere + ' ORDER BY A.INDEX_NAME, B.COLUMN_POSITION'; Result := CopyToVirtualResultSet( GetConnection.CreateStatement.ExecuteQuery(SQL), ConstructVirtualResultSet(PrimaryKeyColumnsDynArray)); end; {** Gets a description of a table's indices and statistics. They are ordered by NON_UNIQUE, TYPE, INDEX_NAME, and ORDINAL_POSITION.

Each index column description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. NON_UNIQUE Boolean => Can index values be non-unique? false when TYPE is tableIndexStatistic
  5. INDEX_QUALIFIER String => index catalog (may be null); null when TYPE is tableIndexStatistic
  6. INDEX_NAME String => index name; null when TYPE is tableIndexStatistic
  7. TYPE short => index type:
    • tableIndexStatistic - this identifies table statistics that are returned in conjuction with a table's index descriptions
    • tableIndexClustered - this is a clustered index
    • tableIndexHashed - this is a hashed index
    • tableIndexOther - this is some other style of index
  8. ORDINAL_POSITION short => column sequence number within index; zero when TYPE is tableIndexStatistic
  9. COLUMN_NAME String => column name; null when TYPE is tableIndexStatistic
  10. ASC_OR_DESC String => column sort sequence, "A" => ascending, "D" => descending, may be null if sort sequence is not supported; null when TYPE is tableIndexStatistic
  11. CARDINALITY int => When TYPE is tableIndexStatistic, then this is the number of rows in the table; otherwise, it is the number of unique values in the index.
  12. PAGES int => When TYPE is tableIndexStatisic then this is the number of pages used for the table, otherwise it is the number of pages used for the current index.
  13. FILTER_CONDITION String => Filter condition, if any. (may be null)
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @param unique when true, return only indices for unique values; when false, return indices regardless of whether unique or not @param approximate when true, result is allowed to reflect approximate or out of data values; when false, results are requested to be accurate @return ResultSet - each row is an index column description } function TZOracleDatabaseMetadata.UncachedGetIndexInfo(const Catalog: string; const Schema: string; const Table: string; Unique: Boolean; Approximate: Boolean): IZResultSet; var SQL: string; OwnerCondition,TableCondition: String; function CreateExtraWhere: String; begin Result := ''; If OwnerCondition <> '' then Result := OwnerCondition; If TableCondition <> '' then If Result <> '' then Result := Result + ' AND ' + TableCondition Else Result := TableCondition; If Result <> '' then Result := ' AND ' + Result; end; begin OwnerCondition := ConstructNameCondition(Schema,'A.TABLE_OWNER'); TableCondition := ConstructNameCondition(Table,'A.TABLE_NAME'); Result:=inherited UncachedGetIndexInfo(Catalog, Schema, Table, Unique, Approximate); SQL := 'SELECT NULL, A.OWNER, A.TABLE_NAME, A.UNIQUENESS, NULL,' + ' A.INDEX_NAME, 3, B.COLUMN_POSITION, B.COLUMN_NAME, B.DESCEND,' + ' 0, 0, NULL FROM ALL_INDEXES A, ALL_IND_COLUMNS B' + ' WHERE A.OWNER=B.INDEX_OWNER AND A.INDEX_NAME=B.INDEX_NAME' + ' AND A.TABLE_OWNER=B.TABLE_OWNER AND A.TABLE_NAME=B.TABLE_NAME' + CreateExtraWhere; if Unique then SQL := SQL + ' AND A.UNIQUENESS=''UNIQUE'''; SQL := SQL + ' ORDER BY A.UNIQUENESS DESC, A.INDEX_NAME, B.COLUMN_POSITION'; with GetConnection.CreateStatement.ExecuteQuery(SQL) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateNull(1); Result.UpdateString(2, GetString(2)); Result.UpdateString(3, GetString(3)); Result.UpdateBoolean(4, UpperCase(GetString(4)) <> 'UNIQUE'); Result.UpdateNull(5); Result.UpdateString(6, GetString(6)); Result.UpdateInt(7, GetInt(7)); Result.UpdateInt(8, GetInt(8)); Result.UpdateString(9, GetString(9)); if GetString(10) = 'ASC' then Result.UpdateString(10, 'A') else Result.UpdateString(10, 'D'); Result.UpdateInt(11, GetInt(11)); Result.UpdateInt(12, GetInt(12)); Result.UpdateNull(13); Result.InsertRow; end; Close; end; end; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcOracleResultSet.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Oracle Database Connectivity Classes } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcOracleResultSet; interface {$I ZDbc.inc} uses {$IFDEF WITH_TOBJECTLIST_INLINE}System.Types, System.Contnrs{$ELSE}Types{$ENDIF}, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, ZSysUtils, ZDbcIntfs, ZDbcOracle, ZDbcResultSet, ZPlainOracleDriver, ZDbcResultSetMetadata, ZDbcLogging, ZCompatibility, ZDbcOracleUtils, ZPlainOracleConstants; type {** Implements Oracle ResultSet. } TZOracleAbstractResultSet = class(TZAbstractResultSet) private FSQL: string; FStmtHandle: POCIStmt; FErrorHandle: POCIError; FPlainDriver: IZOraclePlainDriver; FConnection: IZOracleConnection; FOutVars: PZSQLVars; protected function GetSQLVarHolder(ColumnIndex: Integer): PZSQLVar; function GetAsStringValue(ColumnIndex: Integer; SQLVarHolder: PZSQLVar): RawByteString; function GetAsLongIntValue(ColumnIndex: Integer; SQLVarHolder: PZSQLVar): LongInt; function GetAsDoubleValue(ColumnIndex: Integer; SQLVarHolder: PZSQLVar): Double; function GetAsDateTimeValue(ColumnIndex: Integer; SQLVarHolder: PZSQLVar): TDateTime; function InternalGetString(ColumnIndex: Integer): RawByteString; override; function GetFinalObject(Obj: POCIObject): POCIObject; public constructor Create(PlainDriver: IZOraclePlainDriver; Statement: IZStatement; SQL: string; StmtHandle: POCIStmt; ErrorHandle: POCIError); function IsNull(ColumnIndex: Integer): Boolean; override; function GetBoolean(ColumnIndex: Integer): Boolean; override; function GetByte(ColumnIndex: Integer): Byte; override; function GetShort(ColumnIndex: Integer): SmallInt; override; function GetInt(ColumnIndex: Integer): Integer; override; function GetLong(ColumnIndex: Integer): Int64; override; function GetFloat(ColumnIndex: Integer): Single; override; function GetDouble(ColumnIndex: Integer): Double; override; function GetBigDecimal(ColumnIndex: Integer): Extended; override; function GetBytes(ColumnIndex: Integer): TByteDynArray; override; function GetDate(ColumnIndex: Integer): TDateTime; override; function GetTime(ColumnIndex: Integer): TDateTime; override; function GetTimestamp(ColumnIndex: Integer): TDateTime; override; function GetDataSet(ColumnIndex: Integer): IZDataSet; override; function GetBlob(ColumnIndex: Integer): IZBlob; override; end; TZOracleResultSet = class(TZOracleAbstractResultSet) protected procedure Open; override; public procedure Close; override; function Next: Boolean; override; end; TZOracleCallableResultSet = Class(TZOracleAbstractResultSet) private FFieldNames: TStringDynArray; function PrepareOracleOutVars(Statement: IZStatement; InVars: PZSQLVars; const OracleParams: TZOracleParams): PZSQLVars; protected procedure Open; override; public constructor Create(PlainDriver: IZOraclePlainDriver; Statement: IZStatement; SQL: string; StmtHandle: POCIStmt; ErrorHandle: POCIError; OutVars: PZSQLVars; const OracleParams: TZOracleParams); procedure Close; override; function Next: Boolean; override; End; {** Represents an interface, specific for Oracle blobs. } IZOracleBlob = interface(IZBlob) ['{3D861AAC-B263-42F1-B359-2A188D1D986A}'] function GetLobLocator: POCILobLocator; procedure CreateBlob; procedure ReadBlob; procedure WriteBlob; end; {** Implements external blob wrapper object for Oracle. } TZOracleBlob = class(TZAbstractBlob, IZOracleBlob) private FHandle: IZConnection; FLobLocator: POCILobLocator; FPlainDriver: IZOraclePlainDriver; FBlobType: TZSQLType; FTemporary: Boolean; FChunkSize: Integer; protected procedure InternalSetData(AData: Pointer; ASize: Integer); public constructor Create(PlainDriver: IZOraclePlainDriver; Data: Pointer; Size: Integer; Handle: IZConnection; LobLocator: POCILobLocator; BlobType: TZSQLType; ChunkSize: Integer); destructor Destroy; override; function GetLobLocator: POCILobLocator; procedure CreateBlob; procedure ReadBlob; procedure WriteBlob; function Length: LongInt; override; function IsEmpty: Boolean; override; function Clone: IZBlob; override; function GetString: RawByteString; override; function GetBytes: TByteDynArray; override; function GetStream: TStream; override; end; implementation uses Math, ZMessages, ZDbcUtils, ZEncoding; { TZOracleAbstractResultSet } {** Constructs this object, assignes main properties and opens the record set. @param PlainDriver a Oracle plain driver. @param Statement a related SQL statement object. @param SQL a SQL statement. @param Handle a Oracle specific query handle. } constructor TZOracleAbstractResultSet.Create(PlainDriver: IZOraclePlainDriver; Statement: IZStatement; SQL: string; StmtHandle: POCIStmt; ErrorHandle: POCIError); begin inherited Create(Statement, SQL, nil, Statement.GetConnection.GetConSettings); FSQL := SQL; FStmtHandle := StmtHandle; FErrorHandle := ErrorHandle; FPlainDriver := PlainDriver; ResultSetConcurrency := rcReadOnly; FConnection := Statement.GetConnection as IZOracleConnection; Open; end; {** Indicates if the value of the designated column in the current row of this ResultSet object is Null. @param columnIndex the first column is 1, the second is 2, ... @return if the value is SQL NULL, the value returned is true. false otherwise. } function TZOracleAbstractResultSet.IsNull(ColumnIndex: Integer): Boolean; var CurrentVar: PZSQLVar; begin {$IFNDEF DISABLE_CHECKING} CheckClosed; if (RowNo < 1) or (RowNo > LastRowNo) then raise EZSQLException.Create(SRowDataIsNotAvailable); if (ColumnIndex <=0) or (ColumnIndex > FOutVars.ActualNum) then begin raise EZSQLException.Create( Format(SColumnIsNotAccessable, [ColumnIndex])); end; {$ENDIF} CurrentVar := @FOutVars.Variables[ColumnIndex]; Result := (CurrentVar.Indicator < 0); end; {** Gets a holder for SQL output variable. @param ColumnIndex an index of the column to read. @returns an output variable holder or nil if column is empty. } function TZOracleAbstractResultSet.GetSQLVarHolder(ColumnIndex: Integer): PZSQLVar; begin {$IFNDEF DISABLE_CHECKING} CheckClosed; if (RowNo < 1) or (RowNo > LastRowNo) then raise EZSQLException.Create(SRowDataIsNotAvailable); {$ENDIF} Result := @FOutVars.Variables[ColumnIndex]; LastWasNull := (Result.Indicator < 0) or (Result.Data = nil); if LastWasNull then Result := nil; end; {** Gets the value of the designated column in the current row of this ResultSet object as a String. @param ColumnIndex the first column is 1, the second is 2, ... @param SQLVarHolder a reference to SQL variable holder or nil to force retrieving the variable. @return the column value; if the value is SQL NULL, the value returned is null } function TZOracleAbstractResultSet.GetAsStringValue(ColumnIndex: Integer; SQLVarHolder: PZSQLVar): RawByteString; var OldSeparator: Char; Blob: IZBlob; begin if SQLVarHolder = nil then SQLVarHolder := GetSQLVarHolder(ColumnIndex); if SQLVarHolder <> nil then begin case SQLVarHolder.TypeCode of SQLT_INT: Result := AnsiString(IntToStr(PLongInt(SQLVarHolder.Data)^)); SQLT_FLT: begin OldSeparator := {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}DecimalSeparator; {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}DecimalSeparator := '.'; Result := AnsiString(FloatToSqlStr(PDouble(SQLVarHolder.Data)^)); {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}DecimalSeparator := OldSeparator; end; SQLT_STR: Result := PAnsiChar(SQLVarHolder.Data); SQLT_LVB, SQLT_LVC, SQLT_BIN: begin Result := AnsiString(BufferToStr(PAnsiChar(SQLVarHolder.Data) + SizeOf(Integer), PInteger(SQLVarHolder.Data)^)); end; SQLT_DAT, SQLT_TIMESTAMP: begin Result := AnsiString(DateTimeToAnsiSQLDate( GetAsDateTimeValue(ColumnIndex, SQLVarHolder))); end; SQLT_BLOB, SQLT_CLOB: begin Blob := GetBlob(ColumnIndex); Result := Blob.GetString; end; end; end else Result := ''; end; {** Gets the value of the designated column in the current row of this ResultSet object as a LongInt. @param ColumnIndex the first column is 1, the second is 2, ... @param SQLVarHolder a reference to SQL variable holder or nil to force retrieving the variable. @return the column value; if the value is SQL NULL, the value returned is 0 } function TZOracleAbstractResultSet.GetAsLongIntValue(ColumnIndex: Integer; SQLVarHolder: PZSQLVar): LongInt; begin if SQLVarHolder = nil then SQLVarHolder := GetSQLVarHolder(ColumnIndex); if SQLVarHolder <> nil then begin case SQLVarHolder.TypeCode of SQLT_INT: Result := PLongInt(SQLVarHolder.Data)^; SQLT_FLT: Result := Trunc(PDouble(SQLVarHolder.Data)^); else begin Result := Trunc(SqlStrToFloatDef( GetAsStringValue(ColumnIndex, SQLVarHolder), 0)); end; end; end else Result := 0; end; {** Gets the value of the designated column in the current row of this ResultSet object as a Double. @param ColumnIndex the first column is 1, the second is 2, ... @param SQLVarHolder a reference to SQL variable holder or nil to force retrieving the variable. @return the column value; if the value is SQL NULL, the value returned is 0.0 } function TZOracleAbstractResultSet.GetAsDoubleValue(ColumnIndex: Integer; SQLVarHolder: PZSQLVar): Double; begin if SQLVarHolder = nil then SQLVarHolder := GetSQLVarHolder(ColumnIndex); if SQLVarHolder <> nil then begin case SQLVarHolder.TypeCode of SQLT_INT: Result := PLongInt(SQLVarHolder.Data)^; SQLT_FLT: Result := PDouble(SQLVarHolder.Data)^; else begin Result := SqlStrToFloatDef( GetAsStringValue(ColumnIndex, SQLVarHolder), 0); end; end; end else Result := 0; end; {** Gets the value of the designated column in the current row of this ResultSet object as a DateTime. @param ColumnIndex the first column is 1, the second is 2, ... @param SQLVarHolder a reference to SQL variable holder or nil to force retrieving the variable. @return the column value; if the value is SQL NULL, the value returned is 0 } function TZOracleAbstractResultSet.GetAsDateTimeValue(ColumnIndex: Integer; SQLVarHolder: PZSQLVar): TDateTime; var Status: Integer; Year: SmallInt; Month, Day: Byte; Hour, Minute, Second: Byte; Millis: Integer; Connection: IZOracleConnection; begin if SQLVarHolder = nil then SQLVarHolder := GetSQLVarHolder(ColumnIndex); if SQLVarHolder <> nil then begin case SQLVarHolder.TypeCode of SQLT_DAT: Result := OraDateToDateTime(SQLVarHolder.Data); SQLT_TIMESTAMP: begin Connection := GetStatement.GetConnection as IZOracleConnection; if SQLVarHolder.ColType in [stDate, stTimestamp] then begin Status := FPlainDriver.DateTimeGetDate( Connection.GetConnectionHandle, FErrorHandle, PPOCIDescriptor(SQLVarHolder.Data)^, Year, Month, Day); // attention : this code handles all timestamps on 01/01/0001 as a pure time value // reason : oracle doesn't have a pure time datatype so all time comparisons compare // TDateTime values on 30 Dec 1899 against oracle timestamps on 01 januari 0001 (negative TDateTime) if (Status = OCI_SUCCESS) and ((Year <> 1) or (Month <> 1) or (Day <> 1)) then Result := EncodeDate(Year, Month, Day) else Result := 0; end else Result := 0; if SQLVarHolder.ColType in [stTime, stTimestamp] then begin Status := FPlainDriver.DateTimeGetTime( Connection.GetConnectionHandle, FErrorHandle, PPOCIDescriptor(SQLVarHolder.Data)^, Hour, Minute, Second, Millis); if Status = OCI_SUCCESS then begin Millis := Round(Millis / 1000000); if Millis >= 1000 then Millis := 999; Result := Result + EncodeTime( Hour, Minute, Second, Millis); end; end; end; else begin Result := AnsiSQLDateToDateTime( String(GetAsStringValue(ColumnIndex, SQLVarHolder))); end; end; end else Result := 0; end; {** Gets the value of the designated column in the current row of this ResultSet object as a String in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZOracleAbstractResultSet.InternalGetString(ColumnIndex: Integer): RawByteString; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stString); {$ENDIF} Result := GetAsStringValue(ColumnIndex, nil); end; {** Gets the final object of a type/named-collection/nested-table,array @param obj the parent-object @return the Object which contains the final object descriptor } function TZOracleAbstractResultSet.GetFinalObject(Obj: POCIObject): POCIObject; begin if Obj.is_final_type = 1 then Result := Obj else Result := GetFinalObject(Obj.next_subtype); //recursive call end; {** Gets the value of the designated column in the current row of this ResultSet object as a boolean in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is false } function TZOracleAbstractResultSet.GetBoolean(ColumnIndex: Integer): Boolean; var Temp: string; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stBoolean); {$ENDIF} Temp := String(GetAsStringValue(ColumnIndex, nil)); Result := (StrToIntDef(Temp, 0) <> 0) or StrToBoolEx(Temp); end; {** Gets the value of the designated column in the current row of this ResultSet object as a byte in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZOracleAbstractResultSet.GetByte(ColumnIndex: Integer): Byte; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stByte); {$ENDIF} Result := Byte(GetAsLongIntValue(ColumnIndex, nil)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a short in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZOracleAbstractResultSet.GetShort(ColumnIndex: Integer): SmallInt; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stShort); {$ENDIF} Result := SmallInt(GetAsLongIntValue(ColumnIndex, nil)); end; {** Gets the value of the designated column in the current row of this ResultSet object as an int in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZOracleAbstractResultSet.GetInt(ColumnIndex: Integer): Integer; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stInteger); {$ENDIF} Result := Integer(GetAsLongIntValue(ColumnIndex, nil)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a long in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZOracleAbstractResultSet.GetLong(ColumnIndex: Integer): Int64; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stLong); {$ENDIF} Result := Trunc(GetAsDoubleValue(ColumnIndex, nil)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a float in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZOracleAbstractResultSet.GetFloat(ColumnIndex: Integer): Single; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stFloat); {$ENDIF} Result := GetAsDoubleValue(ColumnIndex, nil); end; {** Gets the value of the designated column in the current row of this ResultSet object as a double in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZOracleAbstractResultSet.GetDouble(ColumnIndex: Integer): Double; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stDouble); {$ENDIF} Result := GetAsDoubleValue(ColumnIndex, nil); end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.BigDecimal in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @param scale the number of digits to the right of the decimal point @return the column value; if the value is SQL NULL, the value returned is null } function TZOracleAbstractResultSet.GetBigDecimal(ColumnIndex: Integer): Extended; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stBigDecimal); {$ENDIF} Result := GetAsDoubleValue(ColumnIndex, nil); end; {** Gets the value of the designated column in the current row of this ResultSet object as a byte array in the Java programming language. The bytes represent the raw values returned by the driver. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZOracleAbstractResultSet.GetBytes(ColumnIndex: Integer): TByteDynArray; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stBytes); {$ENDIF} Result := StrToBytes(GetAsStringValue(ColumnIndex, nil)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Date object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZOracleAbstractResultSet.GetDate(ColumnIndex: Integer): TDateTime; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stDate); {$ENDIF} Result := Trunc(GetAsDateTimeValue(ColumnIndex, nil)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Time object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZOracleAbstractResultSet.GetTime(ColumnIndex: Integer): TDateTime; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stTime); {$ENDIF} Result := Frac(GetAsDateTimeValue(ColumnIndex, nil)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null @exception SQLException if a database access error occurs } function TZOracleAbstractResultSet.GetTimestamp(ColumnIndex: Integer): TDateTime; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stTimestamp); {$ENDIF} Result := GetAsDateTimeValue(ColumnIndex, nil); end; {** Returns the value of the designated column in the current row of this ResultSet object as a IZResultSet object in the Java programming language. @param ColumnIndex the first column is 1, the second is 2, ... @return a IZResultSet object representing the SQL IZResultSet value in the specified column } function TZOracleAbstractResultSet.GetDataSet(ColumnIndex: Integer): IZDataSet; var CurrentVar: PZSQLVar; type_Ref: POCIRef; //tdo: POCIType; begin Result := nil ; {$IFNDEF DISABLE_CHECKING} CheckBlobColumn(ColumnIndex); {$ENDIF} LastWasNull := IsNull(ColumnIndex); if LastWasNull then Exit; GetSQLVarHolder(ColumnIndex); CurrentVar := @FOutVars.Variables[ColumnIndex]; Result := nil; if CurrentVar.TypeCode = SQLT_NTY then if CurrentVar.Indicator >= 0 then begin if CurrentVar._Obj.is_final_type = 1 then // here we've the final object lets's read it to test it // later we only need the reference-pointers to create a new dataset else begin //create a temporary object type_ref := nil; CheckOracleError(FPlainDriver, FErrorHandle, FPlainDriver.ObjectNew(FConnection.GetConnectionHandle, FConnection.GetErrorHandle, FConnection.GetContextHandle, OCI_TYPECODE_REF, nil, nil, OCI_DURATION_DEFAULT, TRUE, @type_ref), lcOther, 'OCITypeByRef from OCI_ATTR_REF_TDO'); //Get the type reference CheckOracleError(FPlainDriver, FErrorHandle, FPlainDriver.ObjectGetTypeRef(FConnection.GetConnectionHandle, FConnection.GetErrorHandle, CurrentVar._Obj.obj_value, type_Ref), lcOther, 'OCIObjectGetTypeRef(obj_value)'); //Now let's get the new tdo //Excptions???????? {CheckOracleError(FPlainDriver, FErrorHandle, FPlainDriver.TypeByRef(FConnection.GetConnectionHandle, FConnection.GetErrorHandle, type_ref, OCI_DURATION_DEFAULT, OCI_TYPEGET_ALL, @tdo), lcOther, 'OCITypeByRef from OCI_ATTR_REF_TDO');} //free the temporary object CheckOracleError(FPlainDriver, FErrorHandle, FPlainDriver.ObjectFree(FConnection.GetConnectionHandle, FConnection.GetErrorHandle, type_ref, ub2(0)), lcOther, 'ObjectFree()'); end; {CheckOracleError(FPlainDriver, FErrorHandle, FPlainDriver.ResultSetToStmt(CurrentVar._Object, FErrorHandle), lcOther, 'Nested Table to Stmt handle'); Result := CreateOracleResultSet(FPlainDriver, GetStatement, 'Fetch Nested Table', CurrentVar._Object, FErrorHandle);} end; end; {** Returns the value of the designated column in the current row of this ResultSet object as a Blob object in the Java programming language. @param ColumnIndex the first column is 1, the second is 2, ... @return a Blob object representing the SQL BLOB value in the specified column } function TZOracleAbstractResultSet.GetBlob(ColumnIndex: Integer): IZBlob; var Connection: IZOracleConnection; CurrentVar: PZSQLVar; LobLocator: POCILobLocator; Stream: TStream; begin Result := nil ; {$IFNDEF DISABLE_CHECKING} CheckBlobColumn(ColumnIndex); {$ENDIF} LastWasNull := IsNull(ColumnIndex); if LastWasNull then Exit; GetSQLVarHolder(ColumnIndex); CurrentVar := @FOutVars.Variables[ColumnIndex]; if CurrentVar.TypeCode in [SQLT_BLOB, SQLT_CLOB, SQLT_BFILEE, SQLT_CFILEE] then begin if CurrentVar.Indicator >= 0 then LobLocator := PPOCIDescriptor(CurrentVar.Data)^ else LobLocator := nil; Connection := GetStatement.GetConnection as IZOracleConnection; Result := TZOracleBlob.Create(FPlainDriver, nil, 0, Connection, LobLocator, CurrentVar.ColType, GetStatement.GetChunkSize); (Result as IZOracleBlob).ReadBlob; end else if CurrentVar.TypeCode=SQLT_NTY then Result := TZAbstractBlob.CreateWithStream(nil, GetStatement.GetConnection) else begin if CurrentVar.Indicator >= 0 then begin Stream := nil; try Stream := TStringStream.Create( GetAsStringValue(ColumnIndex, CurrentVar)); Result := TZAbstractBlob.CreateWithStream(Stream, GetStatement.GetConnection); finally if Assigned(Stream) then Stream.Free; end; end else Result := TZAbstractBlob.CreateWithStream(nil, GetStatement.GetConnection); end; end; { TZOracleResultSet } {** Opens this recordset. } procedure TZOracleResultSet.Open; var I: Integer; ColumnInfo: TZColumnInfo; Connection: IZOracleConnection; CurrentVar: PZSQLVar; ColumnCount: ub4; TempColumnName: PAnsiChar; TempColumnNameLen, CSForm: Integer; begin if ResultSetConcurrency = rcUpdatable then raise EZSQLException.Create(SLiveResultSetsAreNotSupported); if not Assigned(FStmtHandle) or not Assigned(FErrorHandle) then raise EZSQLException.Create(SCanNotRetrieveResultSetData); Connection := GetStatement.GetConnection as IZOracleConnection; CheckOracleError(FPlainDriver, FErrorHandle, FPlainDriver.StmtExecute(Connection.GetContextHandle, FStmtHandle, FErrorHandle, 1, 0, nil, nil, OCI_DESCRIBE_ONLY), lcExecute, FSQL); { Resize SQLVERS structure if needed } FPlainDriver.AttrGet(FStmtHandle, OCI_HTYPE_STMT, @ColumnCount, nil, OCI_ATTR_PARAM_COUNT, FErrorHandle); AllocateOracleSQLVars(FOutVars, ColumnCount); FOutVars.ActualNum := ColumnCount; { Allocates memory for result set } for I := 1 to FOutVars.ActualNum do begin CurrentVar := @FOutVars.Variables[I]; CurrentVar.Handle := nil; FPlainDriver.ParamGet(FStmtHandle, OCI_HTYPE_STMT, FErrorHandle, CurrentVar.Handle, I); FPlainDriver.AttrGet(CurrentVar.Handle, OCI_DTYPE_PARAM, @CurrentVar.DataSize, nil, OCI_ATTR_DATA_SIZE, FErrorHandle); FPlainDriver.AttrGet(CurrentVar.Handle, OCI_DTYPE_PARAM, @CurrentVar.DataType, nil, OCI_ATTR_DATA_TYPE, FErrorHandle); CurrentVar.Scale := 0; CurrentVar.Precision := 0; case CurrentVar.DataType of SQLT_CHR, SQLT_VCS, SQLT_AFC, SQLT_AVC, SQLT_STR, SQLT_VST: CurrentVar.ColType := stString; SQLT_NUM: begin FPlainDriver.AttrGet(CurrentVar.Handle, OCI_DTYPE_PARAM, @CurrentVar.Precision, nil, OCI_ATTR_PRECISION, FErrorHandle); FPlainDriver.AttrGet(CurrentVar.Handle, OCI_DTYPE_PARAM, @CurrentVar.Scale, nil, OCI_ATTR_SCALE, FErrorHandle); {by default convert number to double} CurrentVar.ColType := stDouble; if (CurrentVar.Scale = 0) and (CurrentVar.Precision <> 0) then begin if CurrentVar.Precision <= 2 then CurrentVar.ColType := stByte else if CurrentVar.Precision <= 4 then CurrentVar.ColType := stShort else if CurrentVar.Precision <= 9 then CurrentVar.ColType := stInteger else if CurrentVar.Precision <= 19 then CurrentVar.ColType := stLong; end end; SQLT_BFLOAT, SQLT_BDOUBLE, SQLT_IBFLOAT, SQLT_IBDOUBLE: CurrentVar.ColType := stDouble; SQLT_INT, _SQLT_PLI: CurrentVar.ColType := stInteger; SQLT_LNG, SQLT_LVC: CurrentVar.ColType := stAsciiStream; SQLT_RID, SQLT_RDD: begin CurrentVar.ColType := stString; CurrentVar.DataSize := 20; end; SQLT_DAT, SQLT_DATE: { oracle DATE precission - 1 second} CurrentVar.ColType := stTimestamp; SQLT_TIME, SQLT_TIME_TZ: CurrentVar.ColType := stTime; SQLT_TIMESTAMP, SQLT_TIMESTAMP_TZ, SQLT_TIMESTAMP_LTZ: CurrentVar.ColType := stTimestamp; SQLT_BIN, SQLT_LBI: begin if CurrentVar.DataSize = 0 then CurrentVar.ColType := stBinaryStream else CurrentVar.ColType := stBytes; end; SQLT_CLOB: begin CurrentVar.ColType := stAsciiStream; CurrentVar.TypeCode := CurrentVar.DataType; end; SQLT_BLOB, SQLT_BFILEE, SQLT_CFILEE: begin CurrentVar.ColType := stBinaryStream; CurrentVar.TypeCode := CurrentVar.DataType; end; SQLT_NTY: begin CurrentVar.ColType := stDataSet; CurrentVar.TypeCode := CurrentVar.DataType; CurrentVar._Obj := DescribeObject(FplainDriver, FConnection, CurrentVar.Handle, FStmtHandle, 0); if FPlainDriver.TypeTypeCode(Connection.GetConnectionHandle, FerrorHandle, CurrentVar._Obj.tdo) = SQLT_NCO then CurrentVar.ColType := stDataSet else CurrentVar.ColType := stBinaryStream; end; else CurrentVar.ColType := stUnknown; end; if (ConSettings.CPType = cCP_UTF16) then case CurrentVar.ColType of stString: CurrentVar.ColType := stUnicodeString; stAsciiStream: if not ( CurrentVar.DataType in [SQLT_LNG]) then CurrentVar.ColType := stUnicodeStream; end; InitializeOracleVar(FPlainDriver, Connection, CurrentVar, CurrentVar.ColType, CurrentVar.TypeCode, CurrentVar.DataSize); if CurrentVar.ColType <> stUnknown then CheckOracleError(FPlainDriver, FErrorHandle, FPlainDriver.DefineByPos(FStmtHandle, CurrentVar.Define, FErrorHandle, I, CurrentVar.Data, CurrentVar.Length, CurrentVar.TypeCode, @CurrentVar.Indicator, nil, nil, OCI_DEFAULT), lcExecute, FSQL); if CurrentVar.DataType=SQLT_NTY then begin //second step: http://www.csee.umbc.edu/portal/help/oracle8/server.815/a67846/obj_bind.htm CheckOracleError(FPlainDriver, FErrorHandle, FPlainDriver.DefineObject(CurrentVar.Define, FErrorHandle, CurrentVar._Obj.tdo, @CurrentVar._Obj.obj_value, nil, nil, nil), lcExecute, FSQL); end; end; { Fills the column info. } ColumnsInfo.Clear; for I := 1 to FOutVars.ActualNum do begin CurrentVar := @FOutVars.Variables[I]; ColumnInfo := TZColumnInfo.Create; with ColumnInfo do begin ColumnName := ''; TableName := ''; TempColumnName := nil; FPlainDriver.AttrGet(CurrentVar.Handle, OCI_DTYPE_PARAM, @TempColumnName, @TempColumnNameLen, OCI_ATTR_NAME, FErrorHandle); if TempColumnName <> nil then ColumnLabel := BufferToStr(TempColumnName, TempColumnNameLen); ColumnDisplaySize := 0; AutoIncrement := False; Signed := True; Nullable := ntNullable; ColumnType := CurrentVar.ColType; Scale := CurrentVar.Scale; if (ColumnType in [stString, stUnicodeString]) then begin FPlainDriver.AttrGet(CurrentVar.Handle, OCI_DTYPE_PARAM, @ColumnDisplaySize, nil, OCI_ATTR_DISP_SIZE, FErrorHandle); FPlainDriver.AttrGet(CurrentVar.Handle, OCI_DTYPE_PARAM, @CSForm, nil, OCI_ATTR_CHARSET_FORM, FErrorHandle); if CSForm = SQLCS_NCHAR then //AL16UTF16 or AL16UTF16LE?? We should determine the NCHAR set on connect ColumnDisplaySize := ColumnDisplaySize div 2; Precision := GetFieldSize(ColumnType, ConSettings, ColumnDisplaySize, ConSettings.ClientCodePage^.CharWidth); end else if (ColumnType = stBytes ) then Precision := CurrentVar.DataSize else Precision := CurrentVar.Precision; end; ColumnsInfo.Add(ColumnInfo); end; inherited Open; end; {** Releases this ResultSet object's database and JDBC resources immediately instead of waiting for this to happen when it is automatically closed.

Note: A ResultSet object is automatically closed by the Statement object that generated it when that Statement object is closed, re-executed, or is used to retrieve the next result from a sequence of multiple results. A ResultSet object is also automatically closed when it is garbage collected. } procedure TZOracleResultSet.Close; var ps: IZPreparedStatement; begin if assigned(FOutVars) then // else no statement anyways FreeOracleSQLVars(FPlainDriver, FOutVars, FConnection.GetConnectionHandle, FErrorHandle, ConSettings); { prepared statement own handles, so dont free them } if not Supports(GetStatement, IZPreparedStatement, ps) then FreeOracleStatementHandles(FPlainDriver, FStmtHandle, FErrorHandle); inherited Close; end; {** Moves the cursor down one row from its current position. A ResultSet cursor is initially positioned before the first row; the first call to the method next makes the first row the current row; the second call makes the second row the current row, and so on.

If an input stream is open for the current row, a call to the method next will implicitly close it. A ResultSet object's warning chain is cleared when a new row is read. @return true if the new current row is valid; false if there are no more rows } function TZOracleResultSet.Next: Boolean; var Status: Integer; begin { Checks for maximum row. } Result := False; if (RowNo > LastRowNo) or ((MaxRows > 0) and (RowNo >= MaxRows)) then Exit; if RowNo = 0 then Status := FPlainDriver.StmtExecute(FConnection.GetContextHandle, FStmtHandle, FErrorHandle, 1, 0, nil, nil, OCI_DEFAULT) else Status := FPlainDriver.StmtFetch(FStmtHandle, FErrorHandle, 1, OCI_FETCH_NEXT, OCI_DEFAULT); if not (Status in [OCI_SUCCESS, OCI_NO_DATA]) then CheckOracleError(FPlainDriver, FErrorHandle, Status, lcOther, 'FETCH ROW'); if Status in [OCI_SUCCESS, OCI_SUCCESS_WITH_INFO] then begin RowNo := RowNo + 1; if LastRowNo < RowNo then LastRowNo := RowNo; Result := True; end else begin if RowNo <= LastRowNo then RowNo := LastRowNo + 1; Result := False; end; end; { TZOracleCallableResultSet } function TZOracleCallableResultSet.PrepareOracleOutVars(Statement: IZStatement; InVars: PZSQLVars; const OracleParams: TZOracleParams): PZSQLVars; var I, J: Integer; begin J := 0; for i := 0 to High(OracleParams) do if OracleParams[I].pType in [2,3,4] then Inc(J); Result := nil; AllocateOracleSQLVars(Result, J); Result.ActualNum := J; SetLength(FFieldNames, J); for I := 1 to Length(OracleParams) do begin J := OracleParams[I-1].pOutIndex; if OracleParams[I-1].pType in [2,3,4] then //ptInOut, ptOut, ptResult begin Result.Variables[J].ColType := InVars.Variables[I].ColType; Result.Variables[J].TypeCode := InVars.Variables[I].TypeCode; Result.Variables[J].DataSize := InVars.Variables[I].DataSize; Result.Variables[J].Length := InVars.Variables[I].Length; GetMem(Result.Variables[J].Data, InVars.Variables[I].Length); Move(InVars.Variables[I].Data^, Result.Variables[J].Data^, InVars.Variables[I].Length); FFieldNames[J-1] := OracleParams[I-1].pName; end; end; end; procedure TZOracleCallableResultSet.Open; var I: Integer; ColumnInfo: TZColumnInfo; CurrentVar: PZSQLVar; Connection: IZConnection; begin Connection := GetStatement.GetConnection; { Fills the column info. } ColumnsInfo.Clear; for I := 1 to FOutVars.ActualNum do begin CurrentVar := @FOutVars.Variables[I]; ColumnInfo := TZColumnInfo.Create; with ColumnInfo do begin ColumnName := ''; TableName := ''; ColumnLabel := FFieldNames[i-1]; ColumnDisplaySize := 0; AutoIncrement := False; Signed := True; Nullable := ntNullable; ColumnType := CurrentVar.ColType; Scale := CurrentVar.Scale; {Reset the column type which can be changed by user before} if (ColumnType = stUnicodeStream) and not ( Connection.GetConSettings.CPType = cCP_UTF16) then ColumnType := stAsciiStream; if (ColumnType = stAsciiStream) and ( Connection.GetConSettings.CPType = cCP_UTF16) then ColumnType := stUnicodeStream; if (ColumnType = stUnicodeString) and not ( Connection.GetConSettings.CPType = cCP_UTF16) then ColumnType := stString; if (ColumnType = stString) and ( Connection.GetConSettings.CPType = cCP_UTF16) then ColumnType := stUnicodeString; if ( ColumnType in [stString, stUnicodeString] ) then begin ColumnDisplaySize := CurrentVar.DataSize; Precision := GetFieldSize(ColumnType, ConSettings, CurrentVar.DataSize, ConSettings.ClientCodePage^.CharWidth); end else Precision := CurrentVar.Precision; end; ColumnsInfo.Add(ColumnInfo); end; inherited Open; end; {** Constructs this object, assignes main properties and opens the record set. @param PlainDriver a Oracle plain driver. @param Statement a related SQL statement object. @param SQL a SQL statement. @param Handle a Oracle specific query handle. } constructor TZOracleCallableResultSet.Create(PlainDriver: IZOraclePlainDriver; Statement: IZStatement; SQL: string; StmtHandle: POCIStmt; ErrorHandle: POCIError; OutVars: PZSQLVars; const OracleParams: TZOracleParams); begin FOutVars := PrepareOracleOutVars(Statement, OutVars, OracleParams); inherited Create(PlainDriver, Statement, SQL, StmtHandle, ErrorHandle); FConnection := Statement.GetConnection as IZOracleConnection; MaxRows := 1; end; {** Releases this ResultSet object's database and JDBC resources immediately instead of waiting for this to happen when it is automatically closed.

Note: A ResultSet object is automatically closed by the Statement object that generated it when that Statement object is closed, re-executed, or is used to retrieve the next result from a sequence of multiple results. A ResultSet object is also automatically closed when it is garbage collected. } procedure TZOracleCallableResultSet.Close; var I: Integer; CurrentVar: PZSQLVar; begin if FOutVars <> nil then begin { Frees allocated memory for output variables } for I := 1 to FOutVars.ActualNum do begin CurrentVar := @FOutVars.Variables[I]; if CurrentVar.Data <> nil then begin CurrentVar.DupData := nil; FreeMem(CurrentVar.Data); CurrentVar.Data := nil; end; end; FreeMem(FOutVars); end; FOutVars := nil; inherited Close; end; function TZOracleCallableResultSet.Next: Boolean; begin { Checks for maximum row. } Result := False; if (RowNo >= MaxRows) then Exit; RowNo := LastRowNo + 1; Result := True; end; { TZOracleBlob } {** Constructs this class and assignes the main properties. @param PlainDriver a Oracle plain driver. @param Data a pointer to the blobdata. @param Size the size of the blobdata. @param Handle a Oracle connection reference. @param LobLocator an Oracle lob locator reference. @param BlobType a blob type. } constructor TZOracleBlob.Create(PlainDriver: IZOraclePlainDriver; Data: Pointer; Size: Integer; Handle: IZConnection; LobLocator: POCILobLocator; BlobType: TZSQLType; ChunkSize: Integer); begin inherited CreateWithData(Data, Size, Handle); FHandle := Handle; FLobLocator := LobLocator; FPlainDriver := PlainDriver; FTemporary := False; FBlobType := BlobType; FChunkSize := ChunkSize; end; {** Destroys this object and cleanups the memory. } destructor TZOracleBlob.Destroy; var Connection: IZOracleConnection; begin if FTemporary then begin Connection := FHandle as IZOracleConnection; FPlainDriver.LobFreeTemporary(Connection.GetContextHandle, Connection.GetErrorHandle, FLobLocator); end; inherited Destroy; end; {** Gets the lob locator reference. @return the lob locator reference. } function TZOracleBlob.GetLobLocator: POCILobLocator; begin Result := FLobLocator; end; {** Creates a temporary blob. } procedure TZOracleBlob.CreateBlob; var Status: Integer; Connection: IZOracleConnection; TempBlobType: ub1; begin Connection := FHandle as IZOracleConnection; if FBlobType in [stBytes, stBinaryStream] then TempBlobType := OCI_TEMP_BLOB else TempBlobType := OCI_TEMP_CLOB; Status := FPlainDriver.LobCreateTemporary(Connection.GetContextHandle, Connection.GetErrorHandle, FLobLocator, OCI_DEFAULT, OCI_DEFAULT, TempBlobType, False, OCI_DURATION_DEFAULT); CheckOracleError(FPlainDriver, Connection.GetErrorHandle, Status, lcOther, 'Create Large Object'); FTemporary := True; end; {** Reads the blob by the blob handle. } procedure TZOracleBlob.ReadBlob; const MemDelta = 1 shl 12; // read page (2^...) var Status: Integer; Buf: PByteArray; ReadNumBytes, ReadNumChars, Offset, Cap: ub4; Connection: IZOracleConnection; AnsiTemp: RawByteString; Stream: TStream; csid: ub2; csfrm: ub1; procedure DoRead(const csid: ub2; const csfrm: ub1); begin FillChar(Buf^, FChunkSize+1, #0); ReadNumChars := 0; Status := FPlainDriver.LobRead(Connection.GetContextHandle, Connection.GetErrorHandle, FLobLocator, ReadNumChars, Offset + 1, Buf, FChunkSize, nil, nil, Connection.GetClientCodePageInformations^.ID, csfrm); if ReadNumChars > 0 then begin Inc(Offset, ReadNumChars); AnsiTemp := AnsiTemp+PAnsiChar(Buf); end; end; begin if not Updated and (FLobLocator <> nil) and (BlobData = nil) and (not FTemporary) then begin Connection := FHandle as IZOracleConnection; { Opens a large object or file for read. } Status := FPlainDriver.LobOpen(Connection.GetContextHandle, Connection.GetErrorHandle, FLobLocator, OCI_LOB_READONLY); CheckOracleError(FPlainDriver, Connection.GetErrorHandle, Status, lcOther, 'Open Large Object'); try { Reads data in chunks by MemDelta or more } Offset := 0; Buf := nil; try case FBlobType of stBinaryStream: repeat //BLOB {Calc new progressive by 1/8 and aligned by MemDelta capacity for buffer} Cap := (Offset + (Offset shr 3) + 2 * MemDelta - 1) and not (MemDelta - 1); ReallocMem(Buf, Cap); ReadNumBytes := Cap - Offset; Status := FPlainDriver.LobRead(Connection.GetContextHandle, Connection.GetErrorHandle, FLobLocator, ReadNumBytes, Offset + 1, @Buf[Offset], ReadNumBytes, nil, nil, 0, SQLCS_IMPLICIT); CheckOracleError(FPlainDriver, Connection.GetErrorHandle, Status, lcOther, 'Read Large Object'); if ReadNumBytes > 0 then Inc(Offset, ReadNumBytes); until Offset < Cap; else //CLob begin GetMem(Buf, FChunkSize+1); AnsiTemp := ''; Offset := 0; csid := Connection.GetClientCodePageInformations^.ID; CheckOracleError(FPlainDriver, Connection.GetErrorHandle, FPlainDriver.LobCharSetForm(Connection.GetConnectionHandle, Connection.GetErrorHandle, FLobLocator, @csfrm), lcOther, 'Determine LOB SCFORM'); //need to determine proper CharSet-Form DoRead(csid, csfrm); if Status = OCI_NEED_DATA then while Status = OCI_NEED_DATA do DoRead(csid, csfrm); CheckOracleError(FPlainDriver, Connection.GetErrorHandle, Status, lcOther, 'Read Large Object'); if FBlobType = stUnicodeStream then if OffSet = 0 then Stream := TMemoryStream.Create else Stream := ZEncoding.GetValidatedUnicodeStream(AnsiTemp, Connection.GetConSettings, True) else Stream := TStringStream.Create(GetValidatedAnsiString(AnsiTemp, Connection.GetConSettings, True)); ReallocMem(Buf, Stream.Size); Move(TMemoryStream(Stream).Memory^, PAnsichar(Buf)^, Stream.Size); OffSet := Stream.Size; Stream.Free; FDecoded := FBlobType = stUnicodeStream; end; end; except FreeMem(Buf); raise; end; finally { Closes large object or file. } Status := FPlainDriver.LobClose(Connection.GetContextHandle, Connection.GetErrorHandle, FLobLocator); CheckOracleError(FPlainDriver, Connection.GetErrorHandle, Status, lcOther, 'Close Large Object'); end; { Assigns data } InternalSetData(Buf, Offset); end; end; {** Writes the blob by the blob handle. } procedure TZOracleBlob.WriteBlob; var Status: sword; Connection: IZOracleConnection; ContentSize, OffSet: ub4; function DoWrite(AOffSet: ub4; AChunkSize: ub4; APiece: ub1): sword; var AContentSize: ub4; begin if Self.FBlobType = stBinaryStream then begin AContentSize := ContentSize; Result := FPlainDriver.LobWrite(Connection.GetContextHandle, Connection.GetErrorHandle, FLobLocator, AContentSize, AOffSet, (PAnsiChar(BlobData)+OffSet), AChunkSize, APiece, nil, nil, 0, SQLCS_IMPLICIT); end else begin if ContentSize > 0 then AContentSize := AChunkSize div Connection.GetClientCodePageInformations^.CharWidth else begin AContentSize := ContentSize; AChunkSize := Connection.GetClientCodePageInformations^.CharWidth; end; Result := FPlainDriver.LobWrite(Connection.GetContextHandle, Connection.GetErrorHandle, FLobLocator, AContentSize, AOffSet, (PAnsiChar(BlobData)+OffSet), AChunkSize, APiece, nil, nil, Connection.GetClientCodePageInformations^.ID, SQLCS_IMPLICIT); end; ContentSize := AContentSize; inc(OffSet, AChunkSize); end; begin Connection := FHandle as IZOracleConnection; { Opens a large object or file for read. } Status := FPlainDriver.LobOpen(Connection.GetContextHandle, Connection.GetErrorHandle, FLobLocator, OCI_LOB_READWRITE); CheckOracleError(FPlainDriver, Connection.GetErrorHandle, Status, lcOther, 'Open Large Object'); { Checks for empty blob.} { This test doesn't use IsEmpty because that function does allow for zero length blobs} if (BlobSize > 0) then begin if BlobSize > FChunkSize then begin OffSet := 0; ContentSize := 0; Status := DoWrite(1, FChunkSize, OCI_FIRST_PIECE); if Status <> OCI_NEED_DATA then CheckOracleError(FPlainDriver, Connection.GetErrorHandle, Status, lcOther, 'Write Large Object'); if (BlobSize - OffSet) > FChunkSize then while (BlobSize - OffSet) > FChunkSize do //take care there is room left for LastPiece begin Status := DoWrite(offset, FChunkSize, OCI_NEXT_PIECE); if Status <> OCI_NEED_DATA then CheckOracleError(FPlainDriver, Connection.GetErrorHandle, Status, lcOther, 'Write Large Object'); end; Status := DoWrite(offset, BlobSize - OffSet, OCI_LAST_PIECE); end else begin ContentSize := BlobSize; Status := FPlainDriver.LobWrite(Connection.GetContextHandle, Connection.GetErrorHandle, FLobLocator, ContentSize, 1, BlobData, BlobSize, OCI_ONE_PIECE, nil, nil, 0, SQLCS_IMPLICIT); end; end else begin Status := FPlainDriver.LobTrim(Connection.GetContextHandle, Connection.GetErrorHandle, FLobLocator, 0); end; CheckOracleError(FPlainDriver, Connection.GetErrorHandle, Status, lcOther, 'Write Large Object'); { Closes large object or file. } Status := FPlainDriver.LobClose(Connection.GetContextHandle, Connection.GetErrorHandle, FLobLocator); CheckOracleError(FPlainDriver, Connection.GetErrorHandle, Status, lcOther, 'Close Large Object'); end; {** Replace data in blob by AData without copy (keep ref of AData) } procedure TZOracleBlob.InternalSetData(AData: Pointer; ASize: Integer); begin Clear; BlobData := AData; BlobSize := ASize; end; {** Checks if this blob has an empty content. @return True if this blob is empty. } function TZOracleBlob.IsEmpty: Boolean; begin ReadBlob; Result := inherited IsEmpty; end; function TZOracleBlob.Length: LongInt; begin ReadBlob; Result := inherited Length; end; {** Clones this blob object. @return a clonned blob object. } function TZOracleBlob.Clone: IZBlob; begin Result := TZOracleBlob.Create(FPlainDriver, BlobData, BlobSize, FHandle, FLobLocator, FBlobType, FChunkSize); end; {** Gets the associated stream object. @return an associated or newly created stream object. } function TZOracleBlob.GetStream: TStream; begin ReadBlob; Result := inherited GetStream; end; {** Gets the string from the stored data. @return a string which contains the stored data. } function TZOracleBlob.GetString: RawByteString; begin ReadBlob; Result := inherited GetString; end; {** Gets the byte buffer from the stored data. @return a byte buffer which contains the stored data. } function TZOracleBlob.GetBytes: TByteDynArray; begin ReadBlob; Result := inherited GetBytes; end; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcOracleStatement.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Oracle Database Connectivity Classes } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcOracleStatement; interface {$I ZDbc.inc} uses Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, Types, ZSysUtils, ZDbcIntfs, ZDbcStatement, ZDbcLogging, ZPlainOracleDriver, ZCompatibility, ZVariant, ZDbcOracleUtils, ZPlainOracleConstants; type {** Defines a Oracle specific statement. } IZOracleStatement = interface(IZStatement) ['{8644E5B6-1E0F-493F-B6AC-40D70CCEA13A}'] function GetStatementHandle: POCIStmt; end; {** Implements Generic Oracle Statement. } TZOracleStatement = class(TZAbstractStatement, IZOracleStatement) private FPlainDriver: IZOraclePlainDriver; public constructor Create(PlainDriver: IZOraclePlainDriver; Connection: IZConnection; Info: TStrings); destructor Destroy; override; function ExecuteQuery(const SQL: RawByteString): IZResultSet; override; function ExecuteUpdate(const SQL: RawByteString): Integer; override; function Execute(const SQL: RawByteString): Boolean; override; function GetStatementHandle: POCIStmt; end; {** Implements Prepared SQL Statement. } TZOraclePreparedStatement = class(TZAbstractPreparedStatement) private FPrepared: Boolean; FHandle: POCIStmt; FErrorHandle: POCIError; FPlainDriver: IZOraclePlainDriver; FExecStatement: IZStatement; FLastStatement: IZStatement; FInVars: PZSQLVars; procedure SetLastStatement(LastStatement: IZStatement); function GetExecStatement: IZStatement; function ConvertToOracleSQLQuery(SQL: string): RawByteString; protected property Prepared: Boolean read FPrepared write FPrepared; property Handle: POCIStmt read FHandle write FHandle; property ErrorHandle: POCIError read FErrorHandle write FErrorHandle; property ExecStatement: IZStatement read FExecStatement write FExecStatement; property LastStatement: IZStatement read FLastStatement write SetLastStatement; property InVars: PZSQLVars read FInVars write FInVars; public constructor Create(PlainDriver: IZOraclePlainDriver; Connection: IZConnection; const SQL: string; Info: TStrings); destructor Destroy; override; procedure Close; override; procedure Prepare; override; function ExecuteQuery(const SQL: RawByteString): IZResultSet; override; function ExecuteUpdate(const SQL: RawByteString): Integer; override; function Execute(const SQL: RawByteString): Boolean; override; function ExecuteQueryPrepared: IZResultSet; override; function ExecuteUpdatePrepared: Integer; override; function ExecutePrepared: Boolean; override; function GetStatementHandle: POCIStmt; end; TZOracleCallableStatement = class(TZAbstractCallableStatement, IZParamNamedCallableStatement) private FOutParamCount: Integer; FErrorHandle: POCIError; FInVars: PZSQLVars; FPlainDriver:IZOraclePlainDriver; FPrepared:boolean; FHandle: POCIStmt; FOracleParams: TZOracleParams; FOracleParamsCount: Integer; FParamNames: TStringDynArray; PackageIncludedList: TStrings; procedure ArrangeInParams; procedure FetchOutParamsFromOracleVars; protected function GetProcedureSql(SelectProc: boolean): RawByteString; procedure SetInParam(ParameterIndex: Integer; SQLType: TZSQLType; const Value: TZVariant); override; procedure RegisterParamTypeAndName(const ParameterIndex:integer; const ParamTypeName, ParamName: String; Const ColumnSize, Precision: Integer); public procedure RegisterOutParameter(ParameterIndex: Integer; SQLType: Integer); override; procedure RegisterParamType(ParameterIndex: integer; ParamType: Integer); override; procedure Prepare; override; function IsNull(ParameterIndex: Integer): Boolean;override; Function ExecuteUpdatePrepared: Integer; override; function ExecuteQueryPrepared: IZResultSet; override; constructor Create(Connection: IZConnection; const pProcName: string; Info: TStrings); destructor Destroy; override; procedure ClearParameters; override; end; implementation uses ZTokenizer, ZDbcOracle, ZDbcOracleResultSet {$IFDEF WITH_UNITANSISTRINGS}, AnsiStrings{$ENDIF}; { TZOracleStatement } {** Constructs this object and assignes the main properties. @param PlainDriver a Oracle plain driver. @param Connection a database connection object. @param Info a statement parameters. @param Handle a connection handle pointer. } constructor TZOracleStatement.Create(PlainDriver: IZOraclePlainDriver; Connection: IZConnection; Info: TStrings); begin inherited Create(Connection, Info); FPlainDriver := PlainDriver; ResultSetType := rtForwardOnly; end; {** Destroys this object and cleanups the memory. } destructor TZOracleStatement.Destroy; begin inherited Destroy; end; {** Executes an SQL statement that returns a single ResultSet object. @param sql typically this is a static SQL SELECT statement @return a ResultSet object that contains the data produced by the given query; never null } function TZOracleStatement.ExecuteQuery(const SQL: RawByteString): IZResultSet; var Handle: POCIStmt; ErrorHandle: POCIError; begin AllocateOracleStatementHandles(FPlainDriver, Connection, Handle, ErrorHandle); ASQL := SQL; try PrepareOracleStatement(FPlainDriver, ASQL, LogSQL, Handle, ErrorHandle, StrToIntDef(Info.Values['prefetch_count'], 100), ConSettings); Result := CreateOracleResultSet(FPlainDriver, Self, LogSQL, Handle, ErrorHandle); except FreeOracleStatementHandles(FPlainDriver, Handle, ErrorHandle); raise; end; DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, LogSQL); end; {** Executes an SQL INSERT, UPDATE or DELETE statement. In addition, SQL statements that return nothing, such as SQL DDL statements, can be executed. @param sql an SQL INSERT, UPDATE or DELETE statement or an SQL statement that returns nothing @return either the row count for INSERT, UPDATE or DELETE statements, or 0 for SQL statements that return nothing } function TZOracleStatement.ExecuteUpdate(const SQL: RawByteString): Integer; var Handle: POCIStmt; ErrorHandle: POCIError; begin AllocateOracleStatementHandles(FPlainDriver, Connection, Handle, ErrorHandle); ASQL := SQL; try PrepareOracleStatement(FPlainDriver, ASQL, LogSQL, Handle, ErrorHandle, StrToIntDef(Info.Values['prefetch_count'], 100), ConSettings); ExecuteOracleStatement(FPlainDriver, Connection, LogSQL, Handle, ErrorHandle); Result := GetOracleUpdateCount(FPlainDriver, Handle, ErrorHandle); finally FreeOracleStatementHandles(FPlainDriver, Handle, ErrorHandle); end; DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, LogSQL); { Autocommit statement. } if Connection.GetAutoCommit then Connection.Commit; end; {** Executes an SQL statement that may return multiple results. Under some (uncommon) situations a single SQL statement may return multiple result sets and/or update counts. Normally you can ignore this unless you are (1) executing a stored procedure that you know may return multiple results or (2) you are dynamically executing an unknown SQL string. The methods execute, getMoreResults, getResultSet, and getUpdateCount let you navigate through multiple results. The execute method executes an SQL statement and indicates the form of the first result. You can then use the methods getResultSet or getUpdateCount to retrieve the result, and getMoreResults to move to any subsequent result(s). @param sql any SQL statement @return true if the next result is a ResultSet object; false if it is an update count or there are no more results } function TZOracleStatement.Execute(const SQL: RawByteString): Boolean; var Handle: POCIStmt; ErrorHandle: POCIError; StatementType: ub2; begin Result := False; AllocateOracleStatementHandles(FPlainDriver, Connection, Handle, ErrorHandle); ASQL := SQL; try PrepareOracleStatement(FPlainDriver, ASQL, LogSQL, Handle, ErrorHandle, StrToIntDef(Info.Values['prefetch_count'], 100), ConSettings); StatementType := 0; FPlainDriver.AttrGet(Handle, OCI_HTYPE_STMT, @StatementType, nil, OCI_ATTR_STMT_TYPE, ErrorHandle); if StatementType = OCI_STMT_SELECT then begin LastResultSet := CreateOracleResultSet(FPlainDriver, Self, LogSQL, Handle, ErrorHandle); Result := LastResultSet <> nil; end else begin ExecuteOracleStatement(FPlainDriver, Connection, LogSQL, Handle, ErrorHandle); LastUpdateCount := GetOracleUpdateCount(FPlainDriver, Handle, ErrorHandle); end; finally if not Result then FreeOracleStatementHandles(FPlainDriver, Handle, ErrorHandle); end; DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, LogSQL); { Autocommit statement. } if not Result and Connection.GetAutoCommit then Connection.Commit; end; {** Gets statement handle. @return statement handle. } function TZOracleStatement.GetStatementHandle: POCIStmt; begin Result := nil; end; { TZOraclePreparedStatement } {** Constructs this object and assignes the main properties. @param PlainDriver a Oracle plain driver. @param Connection a database connection object. @param Info a statement parameters. @param Handle a connection handle pointer. } constructor TZOraclePreparedStatement.Create( PlainDriver: IZOraclePlainDriver; Connection: IZConnection; const SQL: string; Info: TStrings); begin inherited Create(Connection, SQL, Info); FPlainDriver := PlainDriver; ResultSetType := rtForwardOnly; ASQL := ConvertToOracleSQLQuery(SQL); FPrepared := False; end; {** Destroys this object and cleanups the memory. } destructor TZOraclePreparedStatement.Destroy; begin inherited Destroy; end; {** Sets a reference to the last statement. @param LastStatement the last statement interface. } procedure TZOraclePreparedStatement.SetLastStatement( LastStatement: IZStatement); begin if FLastStatement <> nil then FLastStatement.Close; FLastStatement := LastStatement; end; {** Creates a temporary statement which executes queries. @param Info a statement parameters. @return a created statement object. } function TZOraclePreparedStatement.GetExecStatement: IZStatement; begin if ExecStatement = nil then begin ExecStatement := TZOracleStatement.Create(FPlainDriver, Connection, Info); ExecStatement.SetMaxFieldSize(GetMaxFieldSize); ExecStatement.SetMaxRows(GetMaxRows); ExecStatement.SetEscapeProcessing(EscapeProcessing); ExecStatement.SetQueryTimeout(GetQueryTimeout); ExecStatement.SetCursorName(CursorName); ExecStatement.SetFetchDirection(GetFetchDirection); ExecStatement.SetFetchSize(GetFetchSize); ExecStatement.SetResultSetConcurrency(GetResultSetConcurrency); ExecStatement.SetResultSetType(GetResultSetType); end; Result := ExecStatement; end; {** Converts an SQL query into Oracle format. @param SQL a query with parameters defined with '?' @returns a query with parameters in Oracle format ':pN'. } function TZOraclePreparedStatement.ConvertToOracleSQLQuery(SQL: string): RawByteString; var I, N: Integer; Tokens: TStrings; begin if Pos('?', SQL) > 0 then begin Tokens := Connection.GetDriver.GetTokenizer. TokenizeBufferToList(SQL, [toUnifyWhitespaces]); try Result := ''; N := 0; for I := 0 to Tokens.Count - 1 do if Tokens[I] = '?' then begin Inc(N); Result := Result + ':P' + RawByteString(IntToStr(N)); end else Result := Result + ZPlainString(Tokens[I]); finally Tokens.Free; end; end else Result := GetEncodedSQL(SQL); end; {** Closes this statement and frees all resources. } procedure TZOraclePreparedStatement.Close; begin inherited Close; if LastStatement <> nil then begin FLastStatement.Close; FLastStatement := nil; end; FreeOracleStatementHandles(FPlainDriver, FHandle, FErrorHandle); FreeOracleSQLVars(FPlainDriver, FInVars, (Connection as IZOracleConnection).GetConnectionHandle, FErrorHandle, ConSettings); end; {** Executes an SQL statement that may return multiple results. Under some (uncommon) situations a single SQL statement may return multiple result sets and/or update counts. Normally you can ignore this unless you are (1) executing a stored procedure that you know may return multiple results or (2) you are dynamically executing an unknown SQL string. The methods execute, getMoreResults, getResultSet, and getUpdateCount let you navigate through multiple results. The execute method executes an SQL statement and indicates the form of the first result. You can then use the methods getResultSet or getUpdateCount to retrieve the result, and getMoreResults to move to any subsequent result(s). @param sql any SQL statement @return true if the next result is a ResultSet object; false if it is an update count or there are no more results } function TZOraclePreparedStatement.Execute(const SQL: RawByteString): Boolean; begin LastStatement := GetExecStatement; Result := LastStatement.Execute(SQL); if Result then LastResultSet := LastStatement.GetResultSet else LastUpdateCount := LastStatement.GetUpdateCount; end; {** Executes an SQL statement that returns a single ResultSet object. @param sql typically this is a static SQL SELECT statement @return a ResultSet object that contains the data produced by the given query; never null } function TZOraclePreparedStatement.ExecuteQuery(const SQL: RawByteString): IZResultSet; begin Result := GetExecStatement.ExecuteQuery(SQL); end; {** Executes an SQL INSERT, UPDATE or DELETE statement. In addition, SQL statements that return nothing, such as SQL DDL statements, can be executed. @param sql an SQL INSERT, UPDATE or DELETE statement or an SQL statement that returns nothing @return either the row count for INSERT, UPDATE or DELETE statements, or 0 for SQL statements that return nothing } function TZOraclePreparedStatement.ExecuteUpdate(const SQL: RawByteString): Integer; begin Result := GetExecStatement.ExecuteUpdate(SQL); LastUpdateCount := Result; end; {** Prepares an SQL statement } procedure TZOraclePreparedStatement.Prepare; var I: Integer; Status: Integer; TypeCode: ub2; CurrentVar: PZSQLVar; begin if not Prepared then begin { Allocates statement handles. } if (FHandle = nil) or (FErrorHandle = nil) then begin AllocateOracleStatementHandles(FPlainDriver, Connection, FHandle, FErrorHandle); end; PrepareOracleStatement(FPlainDriver, ASQL, LogSQL, Handle, ErrorHandle, StrToIntDef(Info.Values['prefetch_count'], 100), ConSettings); AllocateOracleSQLVars(FInVars, InParamCount); InVars^.ActualNum := InParamCount; for I := 0 to InParamCount - 1 do begin CurrentVar := @FInVars.Variables[I + 1]; CurrentVar.Handle := nil; { Artificially define Oracle internal type. } if InParamTypes[I] in [stBytes, stBinaryStream] then TypeCode := SQLT_BLOB else if InParamTypes[I] = stAsciiStream then TypeCode := SQLT_CLOB else if InParamTypes[I] = stUnicodeStream then TypeCode := SQLT_CLOB else TypeCode := SQLT_STR; InitializeOracleVar(FPlainDriver, Connection, CurrentVar, InParamTypes[I], TypeCode, 1024); Status := FPlainDriver.BindByPos(FHandle, CurrentVar.BindHandle, FErrorHandle, I + 1, CurrentVar.Data, CurrentVar.Length, CurrentVar.TypeCode, @CurrentVar.Indicator, nil, nil, 0, nil, OCI_DEFAULT); CheckOracleError(FPlainDriver, FErrorHandle, Status, lcExecute, LogSQL); end; DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, LogSQL); Prepared := True; end; end; {** Executes the SQL query in this PreparedStatement object and returns the result set generated by the query. @return a ResultSet object that contains the data produced by the query; never null } function TZOraclePreparedStatement.ExecutePrepared: Boolean; var StatementType: ub2; begin Result := False; { Prepares a statement. } if not Prepared then Prepare; { Loads binded variables with values. } LoadOracleVars(FPlainDriver, Connection, ErrorHandle, FInVars, InParamValues, ChunkSize); StatementType := 0; FPlainDriver.AttrGet(Handle, OCI_HTYPE_STMT, @StatementType, nil, OCI_ATTR_STMT_TYPE, ErrorHandle); if StatementType = OCI_STMT_SELECT then begin { Executes the statement and gets a resultset. } LastResultSet := CreateOracleResultSet(FPlainDriver, Self, SQL, Handle, ErrorHandle); Result := LastResultSet <> nil; end else begin { Executes the statement and gets a result. } ExecuteOracleStatement(FPlainDriver, Connection, LogSQL, Handle, ErrorHandle); LastUpdateCount := GetOracleUpdateCount(FPlainDriver, Handle, ErrorHandle); end; DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, LogSQL); { Unloads binded variables with values. } UnloadOracleVars(FInVars); { Autocommit statement. } if not Result and Connection.GetAutoCommit then Connection.Commit; end; {** Executes the SQL query in this PreparedStatement object and returns the result set generated by the query. @return a ResultSet object that contains the data produced by the query; never null } function TZOraclePreparedStatement.ExecuteQueryPrepared: IZResultSet; begin { Prepares a statement. } if not Prepared then Prepare; { Loads binded variables with values. } LoadOracleVars(FPlainDriver, Connection, ErrorHandle, FInVars, InParamValues,ChunkSize); { Executes the statement and gets a resultset. } Result := CreateOracleResultSet(FPlainDriver, Self, SQL, Handle, ErrorHandle); DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, SQL); { Unloads binded variables with values. } UnloadOracleVars(FInVars); end; {** Executes the SQL INSERT, UPDATE or DELETE statement in this PreparedStatement object. In addition, SQL statements that return nothing, such as SQL DDL statements, can be executed. @return either the row count for INSERT, UPDATE or DELETE statements; or 0 for SQL statements that return nothing } function TZOraclePreparedStatement.ExecuteUpdatePrepared: Integer; var StatementType: ub2; ResultSet: IZResultSet; begin { Prepares a statement. } if not Prepared then Prepare; { Loads binded variables with values. } LoadOracleVars(FPlainDriver, Connection, ErrorHandle, FInVars, InParamValues, ChunkSize); try StatementType := 0; FPlainDriver.AttrGet(Handle, OCI_HTYPE_STMT, @StatementType, nil, OCI_ATTR_STMT_TYPE, ErrorHandle); if StatementType = OCI_STMT_SELECT then begin { Executes the statement and gets a resultset. } ResultSet := CreateOracleResultSet(FPlainDriver, Self, SQL, Handle, ErrorHandle); try while ResultSet.Next do; LastUpdateCount := ResultSet.GetRow; finally ResultSet.Close; end; end else begin { Executes the statement and gets a result. } ExecuteOracleStatement(FPlainDriver, Connection, LogSQL, Handle, ErrorHandle); LastUpdateCount := GetOracleUpdateCount(FPlainDriver, Handle, ErrorHandle); end; Result := LastUpdateCount; DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, LogSQL); finally { Unloads binded variables with values. } UnloadOracleVars(FInVars); end; { Autocommit statement. } if Connection.GetAutoCommit then Connection.Commit; end; {** Gets statement handle. @return statement handle. } function TZOraclePreparedStatement.GetStatementHandle: POCIStmt; begin Result := FHandle; end; procedure TZOracleCallableStatement.Prepare; var I: Integer; Status: Integer; TypeCode: ub2; CurrentVar: PZSQLVar; SQLType:TZSQLType; begin if not FPrepared then begin ArrangeInParams; //need to sort ReturnValues for functions ASQL := GetProcedureSql(False); SetLength(FParamNames, FOracleParamsCount); for i := 0 to FOracleParamsCount -1 do FParamNames[I] := Self.FOracleParams[I].pName; { Allocates statement handles. } if (FHandle = nil) or (FErrorHandle = nil) then begin AllocateOracleStatementHandles(FPlainDriver, Connection, FHandle, FErrorHandle); end; PrepareOracleStatement(FPlainDriver, ASQL, LogSQL, FHandle, FErrorHandle, StrToIntDef(Info.Values['prefetch_count'], 100), ConSettings); //make sure eventual old buffers are cleaned FreeOracleSQLVars(FPlainDriver, FInVars, (Connection as IZOracleConnection).GetConnectionHandle, FErrorHandle, ConSettings); AllocateOracleSQLVars(FInVars, FOracleParamsCount); FInVars^.ActualNum := FOracleParamsCount; for I := 0 to FOracleParamsCount - 1 do begin CurrentVar := @FInVars.Variables[I + 1]; CurrentVar.Handle := nil; SQLType := TZSQLType(FOracleParams[I].pSQLType); { Artificially define Oracle internal type. } if SQLType = stBinaryStream then TypeCode := SQLT_BLOB else if SQLType in [stAsciiStream, stUnicodeStream] then TypeCode := SQLT_CLOB else TypeCode := SQLT_STR; InitializeOracleVar(FPlainDriver, Connection, CurrentVar, SQLType, TypeCode, 1024); Status := FPlainDriver.BindByPos(FHandle, CurrentVar.BindHandle, FErrorHandle, I + 1, CurrentVar.Data, CurrentVar.Length, CurrentVar.TypeCode, @CurrentVar.Indicator, nil, nil, 0, nil, OCI_DEFAULT); CheckOracleError(FPlainDriver, FErrorHandle, Status, lcExecute, LogSQL); end; DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, LogSQL); end; end; procedure TZOracleCallableStatement.RegisterOutParameter(ParameterIndex, SQLType: Integer); begin inherited RegisterOutParameter(ParameterIndex,SQLType); with FOracleParams[ParameterIndex-1] do begin if not GetConnection.UseMetadata then pName := 'pOut'+IntToStr(ParameterIndex); pSQLType := SQLType; end; end; procedure TZOracleCallableStatement.RegisterParamType(ParameterIndex: integer; ParamType: Integer); begin inherited RegisterParamType(ParameterIndex, ParamType); if ParameterIndex > High(FOracleParams) then SetLength(FOracleParams, ParameterIndex); if ParameterIndex > FOracleParamsCount then FOracleParamsCount := ParameterIndex; FOracleParams[ParameterIndex-1].pType := ParamType; FOracleParams[ParameterIndex-1].pParamIndex := ParameterIndex; if ParamType in [2,3,4] then //ptInOut, ptOut, ptResult begin Inc(FOutParamCount); FOracleParams[ParameterIndex-1].pOutIndex := FOutParamCount; end; end; procedure TZOracleCallableStatement.SetInParam(ParameterIndex: Integer; SQLType: TZSQLType; const Value: TZVariant); var AConnection: IZConnection; function GetOracleParamIndexOfParameterIndex: Integer; var I: Integer; begin Result := 0; for i := 0 to high(FOracleParams) do if ParameterIndex = FOracleParams[i].pParamIndex then begin Result := I; Break; end; end; begin inherited SetInParam(ParameterIndex, SQLType, Value); with FOracleParams[GetOracleParamIndexOfParameterIndex] do begin AConnection := GetConnection; if Assigned(AConnection) and ( not AConnection.UseMetadata ) then pName := 'p'+IntToStr(ParameterIndex); pSQLType := ord(SQLType); pValue := Value; end; end; procedure TZOracleCallableStatement.RegisterParamTypeAndName(const ParameterIndex: integer; const ParamTypeName, ParamName: String; Const ColumnSize, Precision: Integer); var iPos: Integer; ProcName: String; begin FOracleParams[ParameterIndex].pName := ParamName; FOracleParams[ParameterIndex].pTypeName := ParamTypeName; iPos := Pos('.', ParamName); if iPos > 0 then begin ProcName := Copy(ParamName, 1, iPos-1); //extract function or Procedure names FOracleParams[ParameterIndex].pProcIndex := PackageIncludedList.IndexOf(ProcName); //check index if FOracleParams[ParameterIndex].pProcIndex = -1 then //if not exists FOracleParams[ParameterIndex].pProcIndex := PackageIncludedList.Add(ProcName); //Add to List end else //No package FOracleParams[ParameterIndex].pProcIndex := 0; end; procedure TZOracleCallableStatement.ArrangeInParams; var I, J, NewProcIndex, StartProcIndex: Integer; TempVars: TZVariantDynArray; TempOraVar: TZOracleParam; begin NewProcIndex := -1; StartProcIndex := 0; if IsFunction then begin for i := 0 to high(FOracleParams) do begin if not ( FOracleParams[i].pProcIndex = NewProcIndex ) then begin NewProcIndex := FOracleParams[i].pProcIndex; StartProcIndex := I; end; if ( FOracleParams[i].pType = 4 ) then begin DefVarManager.SetNull(FOracleParams[i].pValue); if not (i = StartProcIndex) then begin TempOraVar := FOracleParams[I]; for J := I downto StartProcIndex+1 do FOracleParams[j] := FOracleParams[j-1]; FOracleParams[StartProcIndex] := TempOraVar; end; end; end; SetLength(TempVars, Length(FOracleParams)); for i := 0 to high(FOracleParams) do TempVars[i] := FOracleParams[i].pValue; InParamValues := TempVars; end; end; procedure TZOracleCallableStatement.FetchOutParamsFromOracleVars; var CurrentVar: PZSQLVar; LobLocator: POCILobLocator; I: integer; TempBlob: IZBlob; procedure SetOutParam(CurrentVar: PZSQLVar; Index: Integer); var OracleConnection :IZOracleConnection; Year:SmallInt; Month, Day:Byte; Hour, Min, Sec:ub1; MSec: ub4; dTmp:TDateTime; ps: PAnsiChar; begin case CurrentVar.TypeCode of SQLT_INT: DefVarManager.SetAsInteger( outParamValues[Index], PLongInt(CurrentVar.Data)^ ); SQLT_FLT: DefVarManager.SetAsFloat( outParamValues[Index], PDouble(CurrentVar.Data)^ ); SQLT_STR: begin GetMem(ps,1025); try {$IFDEF WITH_STRLCOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrLCopy( ps, (CurrentVar.Data), 1024); DefVarManager.SetAsString( OutParamValues[Index], ZDbcString(ps) ); finally FreeMem(ps); end; end; SQLT_TIMESTAMP: begin OracleConnection := Connection as IZOracleConnection; FPlainDriver.DateTimeGetDate( OracleConnection.GetConnectionHandle , FErrorHandle, PPOCIDescriptor(CurrentVar.Data)^, Year, Month, Day); FPlainDriver.DateTimeGetTime( OracleConnection.GetConnectionHandle , FErrorHandle, PPOCIDescriptor(CurrentVar.Data)^, Hour, Min, Sec,MSec); dTmp := EncodeDate(year,month,day )+EncodeTime(Hour,min,sec,msec) ; DefVarManager.SetAsDateTime( outParamValues[Index], dTmp ); end; SQLT_BLOB, SQLT_CLOB, SQLT_BFILEE, SQLT_CFILEE: begin if CurrentVar.Indicator >= 0 then LobLocator := PPOCIDescriptor(CurrentVar.Data)^ else LobLocator := nil; OracleConnection := Connection as IZOracleConnection; TempBlob := TZOracleBlob.Create(FPlainDriver, nil, 0, OracleConnection, LobLocator, CurrentVar.ColType, GetChunkSize); (TempBlob as IZOracleBlob).ReadBlob; DefVarManager.SetAsInterface(outParamValues[Index], TempBlob); TempBlob := nil; end; SQLT_NTY: DefVarManager.SetAsInterface(outParamValues[Index], TZOracleBlob.CreateWithStream(nil, GetConnection)); end; end; begin for I := 0 to FOracleParamsCount -1 do if FOracleParams[i].pType in [2,3,4] then begin CurrentVar:= @FInVars.Variables[I+1]; CurrentVar.Data := CurrentVar.DupData; SetOutParam(CurrentVar, FOracleParams[i].pParamIndex-1); end; end; function TZOracleCallableStatement.GetProcedureSql(SelectProc: boolean): RawByteString; var sFunc: string; I, IncludeCount, LastIndex: Integer; PackageBody: TStrings; TempResult: String; function GenerateParamsStr(Count: integer): string; var I: integer; begin for I := 0 to Count - 1 do begin if ( FDBParamTypes[I] = 4 ) then //ptResult begin sFunc := ' :'+FOracleParams[0].pName+' := '; continue; end; if Result <> '' then Result := Result + ','; if IsFunction then Result := Result + ':'+FOracleParams[I+1].pName else Result := Result + ':'+FOracleParams[I].pName; end; Result := '('+Result+')' end; var InParams: string; begin sFunc := ''; if PackageIncludedList.Count > 0 then begin PackageBody := TStringList.Create; PackageBody.Add('BEGIN'); LastIndex := 0; for IncludeCount := 0 to PackageIncludedList.Count -1 do begin InParams := ''; sFunc := ''; for i := LastIndex to high(FOracleParams) do if IncludeCount = FOracleParams[i].pProcIndex then if ( FOracleParams[I].pType = 4 ) then //ptResult sFunc := ' :'+StringReplace(FOracleParams[I].pName, '.', '', [rfReplaceAll])+' := ' else if InParams <> '' then InParams := InParams +', :'+StringReplace(FOracleParams[I].pName, '.', '', [rfReplaceAll]) else InParams := InParams +':'+StringReplace(FOracleParams[I].pName, '.', '', [rfReplaceAll]) else begin LastIndex := I; break; end; PackageBody.Add('BEGIN '+sFunc+SQL+ '.'+GetConnection.GetMetadata.GetIdentifierConvertor.Quote(PackageIncludedList[IncludeCount])+'('+InParams+'); END;'); end; PackageBody.Add('END;'); TempResult := TrimRight(PackageBody.Text); FreeAndNil(PackageBody); end else begin InParams := GenerateParamsStr( FOracleParamsCount ); TempResult := 'BEGIN ' + sFunc +SQL + InParams+'; END;'; end; Result := ZPlainString(TempResult); end; function TZOracleCallableStatement.IsNull(ParameterIndex: Integer): Boolean; begin result := inherited IsNull(ParameterIndex); end; procedure TZOracleCallableStatement.ClearParameters; begin inherited; FOracleParamsCount := 0; SetLength(FOracleParams, 0); end; constructor TZOracleCallableStatement.Create(Connection: IZConnection; const pProcName: string; Info: TStrings); begin inherited Create(Connection, pProcName, Info); FOracleParamsCount := 0; FPlainDriver := Connection.GetIZPlainDriver as IZOraclePlainDriver; ResultSetType := rtForwardOnly; FPrepared := False; PackageIncludedList := TStringList.Create; FOutParamCount := 0; end; destructor TZOracleCallableStatement.Destroy; begin FreeOracleSQLVars(FPlainDriver, FInVars, (Connection as IZOracleConnection).GetConnectionHandle, FErrorHandle, ConSettings); PackageIncludedList.Free; inherited; end; function TZOracleCallableStatement.ExecuteUpdatePrepared: Integer; begin { Prepares a statement. } if not Prepared then Prepare; { Loads binded variables with values. } LoadOracleVars(FPlainDriver , Connection, FErrorHandle, FInVars, InParamValues, ChunkSize); try ExecuteOracleStatement(FPlainDriver, Connection, LogSQL, FHandle, FErrorHandle); LastUpdateCount := GetOracleUpdateCount(FPlainDriver, FHandle, FErrorHandle); FetchOutParamsFromOracleVars; DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, LogSQL); finally { Unloads binded variables with values. } UnloadOracleVars(FInVars); end; { Autocommit statement. } if Connection.GetAutoCommit then Connection.Commit; Result := LastUpdateCount; end; function TZOracleCallableStatement.ExecuteQueryPrepared: IZResultSet; begin { Prepares a statement. } if not Prepared then Prepare; { Loads binded variables with values. } LoadOracleVars(FPlainDriver , Connection, FErrorHandle, FInVars, InParamValues, ChunkSize); try ExecuteOracleStatement(FPlainDriver, Connection, LogSQL, FHandle, FErrorHandle); FetchOutParamsFromOracleVars; LastResultSet := CreateOracleResultSet(FPlainDriver, Self, LogSQL, FHandle, FErrorHandle, FInVars, FOracleParams); Result := LastResultSet; DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, LogSQL); finally { Unloads binded variables with values. } UnloadOracleVars(FInVars); end; end; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcOracleUtils.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Oracle Database Connectivity Classes } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcOracleUtils; interface {$I ZDbc.inc} uses Types, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, ZSysUtils, ZDbcIntfs, ZVariant, ZPlainOracleDriver, ZDbcLogging, ZCompatibility, ZPlainOracleConstants; const MAX_SQLVAR_LIMIT = 1024; type {** Declares SQL Object } POCIObject = ^TOCIObject; TObjFields = array of POCIObject; TOCIObject = Record // embedded object or table will work recursively type_name: String; //object's name (TDO) type_schema: String; //object's schema name (TDO) parmdp: POCIParam; //Describe attributes of the object OCI_DTYPE_PARAM parmap: POCIParam; //Describe attributes of the object OCI_ATTR_COLLECTION_ELEMENT OCI_ATTR_PARAM tdo: POCIType; //object's TDO handle typecode: OCITypeCode; //object's OCI_ATTR_TYPECODE col_typecode: OCITypeCode; //if collection this is its OCI_ATTR_COLLECTION_TYPECODE elem_typecode: OCITypeCode; //if collection this is its element's OCI_ATTR_TYPECODE obj_ref: POCIRef; //if an embeded object this is ref handle to its TDO obj_ind: POCIInd; //Null indictator for object obj_value: POCIComplexObject;//the actual value from the DB obj_type: POCIType; //if an embeded object this is the OCIType returned by a OCIObjectPin is_final_type: ub1; //object's OCI_ATTR_IS_FINAL_TYPE fields: TObjFields; //one object for each field/property field_count: ub2; //The number of fields Not really needed but nice to have next_subtype: POCIObject; //There is strored information about subtypes for inteherited objects stmt_handle: POCIStmt; //the Statement-Handle Level: Integer; //the instance level Pinned: Boolean; //did we pin the obj on decribe? end; PZSQLVar = ^TZSQLVar; TZSQLVar = {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif} record Handle: POCIHandle; Define: POCIHandle; BindHandle: POCIBind; Data: Pointer; DupData: Pointer; DataType: ub2; DataSize: ub2; Length: Integer; Precision: Integer; Scale: Integer; ColType: TZSQLType; TypeCode: ub2; Indicator: sb2; Blob: IZBlob; _Obj: POCIObject; end; TZSQLVars = {$ifndef FPC_REQUIRES_PROPER_ALIGNMENT}packed{$endif} record AllocNum: ub4; ActualNum: ub4; Variables: array[1..MAX_SQLVAR_LIMIT] of TZSQLVar; end; PZSQLVars = ^TZSQLVars; TZOracleParam = Record pName:string; pSQLType:Integer; pValue: TZVariant; pTypeName: String; pType: ShortInt; pProcIndex: Integer; pParamIndex: Integer; pOutIndex: Integer; End; TZOracleParams = array of TZOracleParam; {** Allocates memory for Oracle SQL Variables. @param Variables a pointer to array of variables. @param Count a number of SQL variables. } procedure AllocateOracleSQLVars(var Variables: PZSQLVars; Count: Integer); {** Frees memory Oracle SQL Variables from the memory. @param PlainDriver an Oracle plain driver. @param Variables a pointer to array of variables. } procedure FreeOracleSQLVars(const PlainDriver: IZOraclePlainDriver; var Variables: PZSQLVars; const Handle: POCIEnv; const ErrorHandle: POCIError; const ConSettings: PZConSettings); {** Allocates in memory and initializes the Oracle variable. @param PlainDriver an Oracle plain driver. @param Connection an Oracle connection Object. @param Variable an Oracle variable holder. @param DataType a DBC data type. @param OracleType a correspondent Oracle type. @param DataSize a length for string variables. } procedure InitializeOracleVar(PlainDriver: IZOraclePlainDriver; Connection: IZConnection; var Variable: PZSQLVar; DataType: TZSQLType; OracleType: ub2; DataSize: Integer); {** Loads Oracle variables binded to SQL statement with data. @param PlainDriver an Oracle plain driver. @param Connection an Oracle connection Object. @param Variables Oracle variable holders. @param Values a values to be loaded. } procedure LoadOracleVars(PlainDriver: IZOraclePlainDriver; Connection: IZConnection; ErrorHandle: POCIError; Variables: PZSQLVars; Values: TZVariantDynArray; ChunkSize: Integer); {** Unloads Oracle variables binded to SQL statement with data. @param Variables Oracle variable holders. } procedure UnloadOracleVars(Variables: PZSQLVars); {** Convert string Oracle field type to SQLType @param string field type value @result the SQLType field type value } function ConvertOracleTypeToSQLType(TypeName: string; Precision, Scale: Integer; const CtrlsCPType: TZControlsCodePage): TZSQLType; {** Converts Oracle internal date into TDateTime @param Value a pointer to Oracle internal date. @return a decoded TDateTime value. } function OraDateToDateTime(Value: PAnsiChar): TDateTime; {** Checks for possible SQL errors. @param PlainDriver an Oracle plain driver. @param Handle an Oracle error handle. @param Status a command return status. @param LogCategory a logging category. @param LogMessage a logging message. } procedure CheckOracleError(PlainDriver: IZOraclePlainDriver; ErrorHandle: POCIError; Status: Integer; LogCategory: TZLoggingCategory; LogMessage: string); {** Creates an Oracle result set based on the current settings. @return a created result set object. } function CreateOracleResultSet(PlainDriver: IZOraclePlainDriver; Statement: IZStatement; LogSQL: string; Handle: POCIStmt; ErrorHandle: POCIError): IZResultSet; overload; {** Creates an Oracle result set based on the current settings. @return a created result set object. } function CreateOracleResultSet(PlainDriver: IZOraclePlainDriver; Statement: IZStatement; LogSQL: string; StmtHandle: POCIStmt; ErrorHandle: POCIError; OutVars: PZSQLVars; Const OracleParams: TZOracleParams): IZResultSet; overload; {** Allocates in memory Oracle handlers for Statement object. @param PlainDriver an Oracle plain driver. @param Connection an Oracle connection object. @param Handle a holder for Statement handle. @param ErrorHandle a holder for Error handle. } procedure AllocateOracleStatementHandles(PlainDriver: IZOraclePlainDriver; Connection: IZConnection; var Handle: POCIStmt; var ErrorHandle: POCIError); {** Frees from memory Oracle handlers for Statement object. @param PlainDriver an Oracle plain driver. @param Handle a holder for Statement handle. @param ErrorHandle a holder for Error handle. } procedure FreeOracleStatementHandles(PlainDriver: IZOraclePlainDriver; var Handle: POCIStmt; var ErrorHandle: POCIError); {** Prepares an Oracle statement. @param PlainDriver an Oracle plain driver. @param SQL an SQL query to be prepared. @param Handle a holder for Statement handle. @param ErrorHandle a holder for Error handle. } procedure PrepareOracleStatement(PlainDriver: IZOraclePlainDriver; SQL: RawByteString; LogSQL: String; Handle: POCIStmt; ErrorHandle: POCIError; PrefetchCount: ub4; ConSettings: PZConSettings); {** Executes an Oracle statement. @param PlainDriver an Oracle plain driver. @param Connection an Oracle connection Object. @param SQL an SQL query to be prepared. @param Handle a holder for Statement handle. @param ErrorHandle a holder for Error handle. } procedure ExecuteOracleStatement(PlainDriver: IZOraclePlainDriver; Connection: IZConnection; LogSQL: string; Handle: POCIStmt; ErrorHandle: POCIError); {** Gets a number of updates made by executed Oracle statement. @param PlainDriver an Oracle plain driver. @param Handle a holder for Statement handle. @param ErrorHandle a holder for Error handle. @returns a number of updates. } function GetOracleUpdateCount(PlainDriver: IZOraclePlainDriver; Handle: POCIStmt; ErrorHandle: POCIError): ub4; function DescribeObject(PlainDriver: IZOraclePlainDriver; Connection: IZConnection; ParamHandle: POCIParam; stmt_handle: POCIHandle; Level: ub2): POCIObject; implementation uses ZMessages, ZDbcOracle, ZDbcOracleResultSet, ZDbcCachedResultSet, ZDbcGenericResolver, ZDbcUtils, ZEncoding {$IFDEF WITH_UNITANSISTRINGS}, AnsiStrings{$ENDIF}; {** Calculates size of SQLVars record. @param Count a number of variable. @returns a record size. } function CalculateSQLVarsSize(Count: Integer): Integer; begin Result := SizeOf(TZSQLVars) + Count * SizeOf(TZSQLVar); end; {** Allocates memory for Oracle SQL Variables. @param Variables a pointer to array of variables. @param Count a number of SQL variables. } procedure AllocateOracleSQLVars(var Variables: PZSQLVars; Count: Integer); var Size: Integer; begin if Variables <> nil then FreeMem(Variables); Size := CalculateSQLVarsSize(Count); GetMem(Variables, Size); FillChar(Variables^, Size, 0); Variables^.AllocNum := Count; Variables^.ActualNum := 0; end; {** Frees memory Oracle SQL Variables from the memory. @param PlainDriver an Oracle plain driver. @param Variables a pointer to array of variables. } procedure FreeOracleSQLVars(const PlainDriver: IZOraclePlainDriver; var Variables: PZSQLVars; const Handle: POCIEnv; const ErrorHandle: POCIError; const ConSettings: PZConSettings); var I: Integer; CurrentVar: PZSQLVar; procedure DisposeObject(var Obj: POCIObject); var I: Integer; begin for i := 0 to High(Obj.fields) do DisposeObject(Obj.fields[i]); SetLength(Obj.fields, 0); if Assigned(Obj.next_subtype) then begin DisposeObject(Obj.next_subtype); Obj.next_subtype := nil; end; if Obj.Pinned then {Unpin tdo} //CheckOracleError(PlainDriver, ErrorHandle, //debug PlainDriver.ObjectUnpin(Handle,ErrorHandle, CurrentVar^._Obj.tdo) ;//debug, lcOther, 'OCIObjectUnpin', ConSettings); if (Obj.Level = 0) and assigned(Obj.tdo) then {Free Object} //debugCheckOracleError(PlainDriver, ErrorHandle, PlainDriver.ObjectFree(Handle,ErrorHandle, CurrentVar^._Obj.tdo, 0) ;//debug, lcOther, 'OCIObjectFree', ConSettings); Dispose(Obj); Obj := nil; end; begin if Variables <> nil then begin { Frees allocated memory for output variables } for I := 1 to Variables.ActualNum do begin CurrentVar := @Variables.Variables[I]; if Assigned(CurrentVar._Obj) then DisposeObject(CurrentVar^._Obj); if CurrentVar.Data <> nil then begin if CurrentVar.TypeCode in [SQLT_BLOB, SQLT_CLOB, SQLT_BFILEE, SQLT_CFILEE] then begin PlainDriver.DescriptorFree(PPOCIDescriptor(CurrentVar.Data)^, OCI_DTYPE_LOB); end else if CurrentVar.TypeCode = SQLT_TIMESTAMP then begin PlainDriver.DescriptorFree(PPOCIDescriptor(CurrentVar.Data)^, OCI_DTYPE_TIMESTAMP); end; FreeMem(CurrentVar.Data); CurrentVar.Data := nil; end; end; FreeMem(Variables); end; Variables := nil; end; {** Allocates in memory and initializes the Oracle variable. @param PlainDriver an Oracle plain driver. @param Connection an Oracle connection Object. @param Variable an Oracle variable holder. @param DataType a DBC data type. @param OracleType a correspondent Oracle type. @param DataSize a length for string variables. } procedure InitializeOracleVar(PlainDriver: IZOraclePlainDriver; Connection: IZConnection; var Variable: PZSQLVar; DataType: TZSQLType; OracleType: ub2; DataSize: Integer); var Length: Integer; OracleConnection: IZOracleConnection; begin OracleConnection := Connection as IZOracleConnection; Variable.ColType := DataType; Variable.TypeCode := OracleType; Variable.DataSize := DataSize; Length := 0; case Variable.ColType of stByte, stShort, stInteger: begin Variable.TypeCode := SQLT_INT; Length := SizeOf(LongInt); end; stFloat, stDouble, stLong: begin Variable.TypeCode := SQLT_FLT; Length := SizeOf(Double); end; stDate, stTime, stTimestamp: begin Variable.TypeCode := SQLT_TIMESTAMP; Length := SizeOf(POCIDateTime); end; stString, stUnicodeString: begin Variable.TypeCode := SQLT_STR; Length := Variable.DataSize + 1; end; stAsciiStream, stUnicodeStream, stBinaryStream, stBytes: begin if not (Variable.TypeCode in [SQLT_CLOB, SQLT_BLOB, SQLT_BFILEE, SQLT_CFILEE,SQLT_NTY]) then begin if Variable.ColType = stAsciiStream then Variable.TypeCode := SQLT_LVC else Variable.TypeCode := SQLT_LVB; if Variable.DataSize = 0 then Length := 128 * 1024 + SizeOf(Integer) else Length := Variable.DataSize + SizeOf(Integer); end else Length := SizeOf(POCILobLocator); end; stDataSet: ; //Do nothing here! stUnknown: Exit; end; Variable.Length := Length; GetMem(Variable.Data, Variable.Length); if Variable.TypeCode in [SQLT_BIN, SQLT_BLOB, SQLT_CLOB, SQLT_BFILEE, SQLT_CFILEE] then begin PlainDriver.DescriptorAlloc(OracleConnection.GetConnectionHandle, PPOCIDescriptor(Variable.Data)^, OCI_DTYPE_LOB, 0, nil); end else if Variable.TypeCode = SQLT_TIMESTAMP then begin PlainDriver.DescriptorAlloc(OracleConnection.GetConnectionHandle, PPOCIDescriptor(Variable.Data)^, OCI_DTYPE_TIMESTAMP, 0, nil); end; end; {** Loads Oracle variables binded to SQL statement with data. @param PlainDriver an Oracle plain driver. @param Connection an Oracle connection Object. @param Variables Oracle variable holders. @param Values a values to be loaded. } procedure LoadOracleVars(PlainDriver: IZOraclePlainDriver; Connection: IZConnection; ErrorHandle: POCIError; Variables: PZSQLVars; Values: TZVariantDynArray; ChunkSize: Integer); var I, Len: Integer; Status: Integer; CurrentVar: PZSQLVar; TempDate: TDateTime; TempBytes: TByteDynArray; TempBlob: IZBlob; WriteTempBlob: IZOracleBlob; TempStream: TStream; Year, Month, Day, Hour, Min, Sec, MSec: Word; OracleConnection: IZOracleConnection; begin OracleConnection := Connection as IZOracleConnection; for I := 0 to Variables.ActualNum - 1 do begin CurrentVar := @Variables.Variables[I + 1]; CurrentVar.DupData := CurrentVar.Data; if (high(Values) 0) then begin if Precision <= 2 then Result := stByte else if Precision <= 4 then Result := stShort else if Precision <= 9 then Result := stInteger else if Precision <= 19 then Result := stLong {!!in fact, unusable} end; end; if ( CtrlsCPType = cCP_UTF16 ) then case result of stString: Result := stUnicodeString; stAsciiStream: if not (TypeName = 'LONG') then Result := stUnicodeStream; //fix: http://zeos.firmos.at/viewtopic.php?t=3530 end; end; {** Converts Oracle internal date into TDateTime @param Value a pointer to Oracle internal date. @return a decoded TDateTime value. } function OraDateToDateTime(Value: PAnsiChar): TDateTime; type TOraDate = array[1..7] of Byte; POraDate = ^TOraDate; var Ptr: POraDate; begin Ptr := POraDate(Value); Result := EncodeDate((Ptr[1] - 100) * 100 + Ptr[2] - 100, Ptr[3], Ptr[4]) + EncodeTime(Ptr[5]-1, Ptr[6]-1, Ptr[7]-1, 0); end; {** Checks for possible SQL errors. @param PlainDriver an Oracle plain driver. @param Handle an Oracle error handle. @param Status a command return status. @param LogCategory a logging category. @param LogMessage a logging message. } procedure CheckOracleError(PlainDriver: IZOraclePlainDriver; ErrorHandle: POCIError; Status: Integer; LogCategory: TZLoggingCategory; LogMessage: string); var ErrorMessage: string; ErrorBuffer: array[0..255] of AnsiChar; ErrorCode: SB4; begin ErrorMessage := ''; ErrorCode := Status; case Status of OCI_SUCCESS: Exit; OCI_SUCCESS_WITH_INFO: begin PlainDriver.ErrorGet(ErrorHandle, 1, nil, ErrorCode, ErrorBuffer, 255, OCI_HTYPE_ERROR); ErrorMessage := 'OCI_SUCCESS_WITH_INFO: ' + String(ErrorBuffer); end; OCI_NEED_DATA: ErrorMessage := 'OCI_NEED_DATA'; OCI_NO_DATA: ErrorMessage := 'OCI_NO_DATA'; OCI_ERROR: begin PlainDriver.ErrorGet(ErrorHandle, 1, nil, ErrorCode, ErrorBuffer, 255, OCI_HTYPE_ERROR); ErrorMessage := 'OCI_ERROR: ' + String(ErrorBuffer); end; OCI_INVALID_HANDLE: ErrorMessage := 'OCI_INVALID_HANDLE'; OCI_STILL_EXECUTING: ErrorMessage := 'OCI_STILL_EXECUTING'; OCI_CONTINUE: ErrorMessage := 'OCI_CONTINUE'; end; if (Status <> OCI_SUCCESS) and (Status <> OCI_SUCCESS_WITH_INFO) and (ErrorMessage <> '') then begin if Assigned(DriverManager) then //Thread-Safe patch DriverManager.LogError(LogCategory, PlainDriver.GetProtocol, LogMessage, ErrorCode, ErrorMessage); if not ( ( LogCategory = lcDisconnect ) and ( ErrorCode = 3314 ) ) then //patch for disconnected Server //on the other hand we can't close the connction MantisBT: #0000227 raise EZSQLException.CreateWithCode(ErrorCode, Format(SSQLError1, [ErrorMessage])); end; if (Status = OCI_SUCCESS_WITH_INFO) and (ErrorMessage <> '') then if Assigned(DriverManager) then //Thread-Safe patch DriverManager.LogMessage(LogCategory, PlainDriver.GetProtocol, ErrorMessage); end; {** Creates an Oracle result set based on the current settings. @return a created result set object. } function CreateOracleResultSet(PlainDriver: IZOraclePlainDriver; Statement: IZStatement; LogSQL: string; Handle: POCIStmt; ErrorHandle: POCIError): IZResultSet; var NativeResultSet: TZOracleResultSet; CachedResultSet: TZCachedResultSet; begin NativeResultSet := TZOracleResultSet.Create(PlainDriver, Statement, LogSQL, Handle, ErrorHandle); NativeResultSet.SetConcurrency(rcReadOnly); if (Statement.GetResultSetConcurrency = rcUpdatable) or (Statement.GetResultSetType <> rtForwardOnly) then begin CachedResultSet := TZCachedResultSet.Create(NativeResultSet, LogSQL, nil, Statement.GetConnection.GetConSettings); CachedResultSet.SetConcurrency(rcUpdatable); CachedResultSet.SetResolver(TZOracleCachedResolver.Create( Statement, NativeResultSet.GetMetadata)); Result := CachedResultSet; end else Result := NativeResultSet; end; {** Creates an Oracle result set based on the current settings. @return a created result set object. } function CreateOracleResultSet(PlainDriver: IZOraclePlainDriver; Statement: IZStatement; LogSQL: string; StmtHandle: POCIStmt; ErrorHandle: POCIError; OutVars: PZSQLVars; Const OracleParams: TZOracleParams): IZResultSet; var NativeResultSet: TZOracleCallableResultSet; CachedResultSet: TZCachedResultSet; begin NativeResultSet := TZOracleCallableResultSet.Create(PlainDriver, Statement, LogSQL, StmtHandle, ErrorHandle, OutVars, OracleParams); NativeResultSet.SetConcurrency(rcReadOnly); CachedResultSet := TZCachedResultSet.Create(NativeResultSet, LogSQL, nil, Statement.GetConnection.GetConSettings); CachedResultSet.SetConcurrency(rcReadOnly); CachedResultSet.SetResolver(TZOracleCachedResolver.Create( Statement, NativeResultSet.GetMetadata)); CachedResultSet.Last; CachedResultSet.BeforeFirst; Result := CachedResultSet; end; {** Allocates in memory Oracle handlers for Statement object. @param PlainDriver an Oracle plain driver. @param Connection an Oracle connection object. @param Handle a holder for Statement handle. @param ErrorHandle a holder for Error handle. } procedure AllocateOracleStatementHandles(PlainDriver: IZOraclePlainDriver; Connection: IZConnection; var Handle: POCIStmt; var ErrorHandle: POCIError); var OracleConnection: IZOracleConnection; begin OracleConnection := Connection as IZOracleConnection; ErrorHandle := nil; PlainDriver.HandleAlloc(OracleConnection.GetConnectionHandle, ErrorHandle, OCI_HTYPE_ERROR, 0, nil); Handle := nil; PlainDriver.HandleAlloc(OracleConnection.GetConnectionHandle, Handle, OCI_HTYPE_STMT, 0, nil); end; {** Frees from memory Oracle handlers for Statement object. @param PlainDriver an Oracle plain driver. @param Handle a holder for Statement handle. @param ErrorHandle a holder for Error handle. } procedure FreeOracleStatementHandles(PlainDriver: IZOraclePlainDriver; var Handle: POCIStmt; var ErrorHandle: POCIError); begin if ErrorHandle <> nil then begin PlainDriver.HandleFree(ErrorHandle, OCI_HTYPE_ERROR); ErrorHandle := nil; end; if Handle <> nil then begin PlainDriver.HandleFree(Handle, OCI_HTYPE_STMT); Handle := nil; end; end; {** Prepares an Oracle statement. @param PlainDriver an Oracle plain driver. @param SQL an SQL query to be prepared. @param Handle a holder for Statement handle. @param ErrorHandle a holder for Error handle. } procedure PrepareOracleStatement(PlainDriver: IZOraclePlainDriver; SQL: RawByteString; LogSQL: String; Handle: POCIStmt; ErrorHandle: POCIError; PrefetchCount: ub4; ConSettings: PZConSettings); var Status: Integer; begin PlainDriver.AttrSet(Handle, OCI_HTYPE_STMT, @PrefetchCount, SizeOf(ub4), OCI_ATTR_PREFETCH_ROWS, ErrorHandle); Status := PlainDriver.StmtPrepare(Handle, ErrorHandle, PAnsiChar(SQL), Length(SQL)+1, OCI_NTV_SYNTAX, OCI_DEFAULT); CheckOracleError(PlainDriver, ErrorHandle, Status, lcExecute, LogSQL); end; {** Executes an Oracle statement. @param PlainDriver an Oracle plain driver. @param Connection an Oracle connection Object. @param SQL an SQL query to be prepared. @param Handle a holder for Statement handle. @param ErrorHandle a holder for Error handle. } procedure ExecuteOracleStatement(PlainDriver: IZOraclePlainDriver; Connection: IZConnection; LogSQL: string; Handle: POCIStmt; ErrorHandle: POCIError); var Status: Integer; OracleConnection: IZOracleConnection; begin OracleConnection := Connection as IZOracleConnection; Status := PlainDriver.StmtExecute(OracleConnection.GetContextHandle, Handle, ErrorHandle, 1, 0, nil, nil, OCI_DEFAULT); CheckOracleError(PlainDriver, ErrorHandle, Status, lcExecute, LogSQL); end; {** Gets a number of updates made by executed Oracle statement. @param PlainDriver an Oracle plain driver. @param Handle a holder for Statement handle. @param ErrorHandle a holder for Error handle. @returns a number of updates. } function GetOracleUpdateCount(PlainDriver: IZOraclePlainDriver; Handle: POCIStmt; ErrorHandle: POCIError): ub4; begin Result := 0; PlainDriver.AttrGet(Handle, OCI_HTYPE_STMT, @Result, nil, OCI_ATTR_ROW_COUNT, ErrorHandle); end; {** recurses down the field's TDOs and saves the little bits it need for later use on a fetch SQLVar._obj } function DescribeObject(PlainDriver: IZOraclePlainDriver; Connection: IZConnection; ParamHandle: POCIParam; stmt_handle: POCIHandle; Level: ub2): POCIObject; var type_ref: POCIRef; function AllocateObject: POCIObject; begin Result := New(POCIObject); FillChar(Result^, SizeOf(TOCIObject), 0); end; procedure DescribeObjectByTDO(PlainDriver: IZOraclePlainDriver; Connection: IZConnection; var obj: POCIObject); var FConnection: IZOracleConnection; list_attibutes: POCIParam; name: PAnsiChar; temp: RawByteString; len: ub4; I: ub2; Fld: POCIObject; begin FConnection := Connection as IZOracleConnection; CheckOracleError(PlainDriver, FConnection.GetErrorHandle, PlainDriver.DescribeAny(FConnection.GetContextHandle, FConnection.GetErrorHandle, obj.tdo, 0, OCI_OTYPE_PTR, OCI_DEFAULT, OCI_PTYPE_TYPE, FConnection.GetDescribeHandle), lcOther, 'OCIDescribeAny(OCI_PTYPE_TYPE) of OCI_OTYPE_PTR'); //we have the Actual TDO so lets see what it is made up of by a describe Len := 0; //and we store it in the object's paramdp for now CheckOracleError(PlainDriver, FConnection.GetErrorHandle, PlainDriver.AttrGet(FConnection.GetDescribeHandle, OCI_HTYPE_DESCRIBE, @obj.parmdp, @Len, OCI_ATTR_PARAM, FConnection.GetErrorHandle), lcOther, 'OCIAttrGet(OCI_HTYPE_DESCRIBE) of OCI_ATTR_PARAM'); //Get the SchemaName of the Object CheckOracleError(PlainDriver, FConnection.GetErrorHandle, PlainDriver.AttrGet(obj.parmdp, OCI_DTYPE_PARAM, @name, @len, OCI_ATTR_SCHEMA_NAME, FConnection.GetErrorHandle), lcOther, 'OCIAttrGet(OCI_ATTR_SCHEMA_NAME) of OCI_DTYPE_PARAM'); SetLength(temp, len+1); temp := {$IFDEF WITH_STRPLCOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrPLCopy(PAnsiChar(temp), name, len); Obj.type_schema := PlainDriver.ZDbcString(temp, Connection.GetConSettings); //Get the TypeName of the Object CheckOracleError(PlainDriver, FConnection.GetErrorHandle, PlainDriver.AttrGet(obj.parmdp, OCI_DTYPE_PARAM, @name, @len, OCI_ATTR_NAME, FConnection.GetErrorHandle), lcOther, 'OCIAttrGet(OCI_ATTR_NAME) of OCI_DTYPE_PARAM'); SetLength(temp, len+1); temp := {$IFDEF WITH_STRPLCOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrPLCopy(PAnsiChar(temp), name, len); Obj.type_name := PlainDriver.ZDbcString(temp, Connection.GetConSettings); //Get the TypeCode of the Object CheckOracleError(PlainDriver, FConnection.GetErrorHandle, PlainDriver.AttrGet(obj.parmdp, OCI_DTYPE_PARAM, @Obj.typecode, nil, OCI_ATTR_TYPECODE, FConnection.GetErrorHandle), lcOther, 'OCIAttrGet(OCI_ATTR_TYPECODE) of OCI_DTYPE_PARAM'); if (obj.typecode = OCI_TYPECODE_OBJECT ) or ( obj.typecode = OCI_TYPECODE_OPAQUE) then begin //we will need a reff to the TDO for the pin operation CheckOracleError(PlainDriver, FConnection.GetErrorHandle, PlainDriver.AttrGet(obj.parmdp, OCI_DTYPE_PARAM, @Obj.obj_ref, nil, OCI_ATTR_REF_TDO, FConnection.GetErrorHandle), lcOther, 'OCIAttrGet(OCI_ATTR_REF_TDO) of OCI_DTYPE_PARAM'); //now we'll pin the object CheckOracleError(PlainDriver, FConnection.GetErrorHandle, PlainDriver.ObjectPin(FConnection.GetConnectionHandle, FConnection.GetErrorHandle, Obj.obj_ref, nil, OCI_PIN_LATEST, OCI_DURATION_SESSION, pub2(OCI_LOCK_NONE), @obj.obj_type), lcOther, 'OCIObjectPin(OCI_PIN_LATEST, OCI_DURATION_SESSION, OCI_LOCK_NONE)'); Obj.Pinned := True; //is the object the final type or an type-descriptor? CheckOracleError(PlainDriver, FConnection.GetErrorHandle, PlainDriver.AttrGet(obj.parmdp, OCI_DTYPE_PARAM, @Obj.is_final_type, nil, OCI_ATTR_IS_FINAL_TYPE, FConnection.GetErrorHandle), lcOther, 'OCIAttrGet(OCI_ATTR_IS_FINAL_TYPE) of OCI_DTYPE_PARAM(SubType)'); //Get the FieldCount CheckOracleError(PlainDriver, FConnection.GetErrorHandle, PlainDriver.AttrGet(obj.parmdp, OCI_DTYPE_PARAM, @Obj.field_count, nil, OCI_ATTR_NUM_TYPE_ATTRS, FConnection.GetErrorHandle), lcOther, 'OCIAttrGet(OCI_ATTR_NUM_TYPE_ATTRS) of OCI_DTYPE_PARAM(SubType)'); //now get the differnt fields of this object add one field object for property SetLength(Obj.fields, Obj.field_count); //a field is just another instance of an obj not a new struct CheckOracleError(PlainDriver, FConnection.GetErrorHandle, PlainDriver.AttrGet(obj.parmdp, OCI_DTYPE_PARAM, @list_attibutes, nil, OCI_ATTR_LIST_TYPE_ATTRS, FConnection.GetErrorHandle), lcOther, 'OCIAttrGet(OCI_ATTR_LIST_TYPE_ATTRS) of OCI_DTYPE_PARAM(SubType)'); if obj.field_count > 0 then for I := 0 to obj.field_count-1 do begin Fld := AllocateObject; //allocate a new object Obj.fields[i] := Fld; //assign the object to the field-list CheckOracleError(PlainDriver, FConnection.GetErrorHandle, PlainDriver.ParamGet(list_attibutes, OCI_DTYPE_PARAM, FConnection.GetErrorHandle, Fld.parmdp, I+1), lcOther, 'OCIParamGet(OCI_DTYPE_PARAM) of OCI_DTYPE_PARAM(Element)'); // get the name of the attribute len := 0; CheckOracleError(PlainDriver, FConnection.GetErrorHandle, PlainDriver.AttrGet(Fld.parmdp, OCI_DTYPE_PARAM, @name, @len, OCI_ATTR_NAME, FConnection.GetErrorHandle), lcOther, 'OCIAttrGet(OCI_ATTR_NAME) of OCI_DTYPE_PARAM(Element)'); SetLength(temp, len+1); temp := {$IFDEF WITH_STRPLCOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrPLCopy(PAnsiChar(temp), name, len); Fld.type_name := PlainDriver.ZDbcString(temp, Connection.GetConSettings); // get the typeCode of the attribute CheckOracleError(PlainDriver, FConnection.GetErrorHandle, PlainDriver.AttrGet(Fld.parmdp, OCI_DTYPE_PARAM, @Fld.typecode, nil, OCI_ATTR_TYPECODE, FConnection.GetErrorHandle), lcOther, 'OCIAttrGet(OCI_ATTR_TYPECODE) of OCI_DTYPE_PARAM(Element)'); if (fld.typecode = OCI_TYPECODE_OBJECT) or (fld.typecode = OCI_TYPECODE_VARRAY) or (fld.typecode = OCI_TYPECODE_TABLE) or (fld.typecode = OCI_TYPECODE_NAMEDCOLLECTION) then //this is some sort of object or collection so lets drill down some more fld.next_subtype := DescribeObject(PlainDriver, Connection, fld.parmdp, obj.stmt_handle, obj.Level+1); end; end else begin //this is an embedded table or varray of some form so find out what is in it*/ CheckOracleError(PlainDriver, FConnection.GetErrorHandle, PlainDriver.AttrGet(obj.parmdp, OCI_DTYPE_PARAM, @obj.col_typecode, nil, OCI_ATTR_COLLECTION_TYPECODE, FConnection.GetErrorHandle), lcOther, 'OCIAttrGet(OCI_ATTR_COLLECTION_TYPECODE) of OCI_DTYPE_PARAM'); //first get what sort of collection it is by coll typecode CheckOracleError(PlainDriver, FConnection.GetErrorHandle, PlainDriver.AttrGet(obj.parmdp, OCI_DTYPE_PARAM, @obj.parmap, nil, OCI_ATTR_COLLECTION_ELEMENT, FConnection.GetErrorHandle), lcOther, 'OCIAttrGet(OCI_ATTR_COLLECTION_ELEMENT) of OCI_DTYPE_PARAM'); CheckOracleError(PlainDriver, FConnection.GetErrorHandle, PlainDriver.AttrGet(obj.parmdp, OCI_DTYPE_PARAM, @obj.elem_typecode, nil, OCI_ATTR_TYPECODE, FConnection.GetErrorHandle), lcOther, 'OCIAttrGet(OCI_ATTR_TYPECODE of Element) of OCI_DTYPE_PARAM'); if (obj.elem_typecode = OCI_TYPECODE_OBJECT) or (obj.elem_typecode = OCI_TYPECODE_VARRAY) or (obj.elem_typecode = OCI_TYPECODE_TABLE) or (obj.elem_typecode = OCI_TYPECODE_NAMEDCOLLECTION) then //this is some sort of object or collection so lets drill down some more obj.next_subtype := DescribeObject(PlainDriver, Connection, obj.parmap, obj.stmt_handle, obj.Level+1); end; end; begin Result := AllocateObject; //Describe the field (OCIParm) we know it is a object or a collection //Get the Actual TDO CheckOracleError(PlainDriver, (Connection as IZOracleConnection).GetErrorHandle, PlainDriver.AttrGet(ParamHandle, OCI_DTYPE_PARAM, @type_ref, nil, OCI_ATTR_REF_TDO, (Connection as IZOracleConnection).GetErrorHandle), lcOther, 'OCIAttrGet OCI_ATTR_REF_TDO of OCI_DTYPE_PARAM'); CheckOracleError(PlainDriver, (Connection as IZOracleConnection).GetErrorHandle, PlainDriver.TypeByRef((Connection as IZOracleConnection).GetConnectionHandle, (Connection as IZOracleConnection).GetErrorHandle, type_ref, OCI_DURATION_TRANS, OCI_TYPEGET_ALL, @Result.tdo), lcOther, 'OCITypeByRef from OCI_ATTR_REF_TDO'); Result^.Level := Level; DescribeObjectByTDO(PlainDriver, Connection, Result); end; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcPooled.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcPooled; interface {$I ZDbc.inc} implementation uses Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} Contnrs, DateUtils, SysUtils, Types, SyncObjs, ZCompatibility, ZClasses, ZURL, ZDbcConnection, ZDbcIntfs, ZPlainDriver, ZMessages, ZVariant; type TConnectionPool = class; { This class searchs for timed out connections in a pool and destroy them. Maybe it would be nice to have a global instance to check all pools. This way, we could avoid creating many threads. } TConnectionTimeoutThread = class(TThread) private FConnectionPool: TConnectionPool; protected procedure Execute; override; public constructor Create(const ConnectionPool: TConnectionPool); end; { This class keeps a pool of connections which shares the same URL. When a new connection is needed, it looks first if there is an available connection in the pool, and returns it. If there is no connection available, it creates a new one. Each created connection will be returned automatically to the pool when it is not used anymore. } TConnectionPool = class private FConnections: array of IZConnection; FConnectionsReturnTimes: array of TDateTime; FSlotsInUse: TBits; FConnectionTimeout: Integer; FConnectionTimeoutThread: TConnectionTimeoutThread; FCriticalSection: TCriticalSection; FCriticalSectionDriverManager: TCriticalSection; FDefaultAutoCommit: Boolean; FDefaultTransactIsolationLevel: TZTransactIsolationLevel; FMaxConnections: Integer; FURL: string; FWait: Boolean; public { URL The connection URL ConnectionTimeout How many time a pooled connection will be kept in the pool. Zero = infinite MaxConnections The maximum numbers of connections this pool will hold. Zero = infinite Wait True - When a pool reach its maximum number of connections and someone tries to acquire a new one, it waits until a connection is returned to the pool False - Raises an exception instead of wait } constructor Create(const URL: string; const ConnectionTimeout: Integer = 0; const MaxConnections: Integer = 0; const Wait: Boolean = True); destructor Destroy; override; function Acquire: IZConnection; procedure ReturnToPool(const Connection: IZConnection); end; { This class embedds a real connection and redirects all methods to it. When it is droped or closed, it returns the real connection to the pool. } { TZDbcPooledConnection } TZDbcPooledConnection = class(TZCodePagedObject, IZConnection) private FConnection: IZConnection; FConnectionPool: TConnectionPool; FAutoEncodeStrings: Boolean; FUseMetadata: Boolean; {$IFDEF ZEOS_TEST_ONLY} FTestMode: Byte; {$ENDIF} function GetConnection: IZConnection; protected // IZConnection FClientCodePage: String; procedure CheckCharEncoding(CharSet: String; const DoArrange: Boolean = False); function GetClientCodePageInformations: PZCodePage; //EgonHugeist function GetAutoEncodeStrings: Boolean; //EgonHugeist procedure SetAutoEncodeStrings(const Value: Boolean); function CreateStatement: IZStatement; function PrepareStatement(const SQL: string): IZPreparedStatement; function PrepareCall(const SQL: string): IZCallableStatement; function CreateStatementWithParams(Info: TStrings): IZStatement; function PrepareStatementWithParams(const SQL: string; Info: TStrings): IZPreparedStatement; function PrepareCallWithParams(const SQL: string; Info: TStrings): IZCallableStatement; function CreateNotification(const Event: string): IZNotification; function CreateSequence(const Sequence: string; BlockSize: Integer): IZSequence; function NativeSQL(const SQL: string): string; procedure SetAutoCommit(Value: Boolean); function GetAutoCommit: Boolean; procedure Commit; procedure Rollback; procedure PrepareTransaction(const transactionid: string); procedure CommitPrepared(const transactionid: string); procedure RollbackPrepared(const transactionid: string); function PingServer: Integer; function EscapeString(Value : RawByteString) : RawByteString; procedure Open; procedure Close; function IsClosed: Boolean; function GetDriver: IZDriver; function GetIZPlainDriver: IZPlainDriver; function GetMetadata: IZDatabaseMetadata; function GetParameters: TStrings; function GetClientVersion: Integer; function GetHostVersion: Integer; procedure SetReadOnly(Value: Boolean); function IsReadOnly: Boolean; procedure SetCatalog(const Value: string); function GetCatalog: string; procedure SetTransactionIsolation(Value: TZTransactIsolationLevel); function GetTransactionIsolation: TZTransactIsolationLevel; function GetWarnings: EZSQLWarning; procedure ClearWarnings; function UseMetadata: boolean; procedure SetUseMetadata(Value: Boolean); public constructor Create(const ConnectionPool: TConnectionPool); destructor Destroy; override; function GetBinaryEscapeString(const Value: RawByteString): String; overload; function GetBinaryEscapeString(const Value: TByteDynArray): String; overload; function GetEscapeString(const Value: ZWideString): ZWideString; overload; virtual; function GetEscapeString(const Value: RawByteString): RawByteString; overload; virtual; function GetEncoding: TZCharEncoding; function GetConSettings: PZConSettings; {$IFDEF ZEOS_TEST_ONLY} function GetTestMode : Byte; procedure SetTestMode(Mode: Byte); {$ENDIF} end; {$WARNINGS OFF} TZDbcPooledConnectionDriver = class(TZAbstractDriver) private PoolList: TObjectList; URLList: TStringList; function GetEmbeddedURL(const URL: String): String; public //function GetSupportedProtocols: TStringDynArray; override; function Connect(const URL: TZURL): IZConnection; override; function GetClientVersion(const URL: string): Integer; override; function AcceptsURL(const URL: string): Boolean; override; function GetPropertyInfo(const URL: string; Info: TStrings): TStrings; override; function GetMajorVersion: Integer; override; function GetMinorVersion: Integer; override; function GetSubVersion: Integer; override; public constructor Create; override; destructor Destroy; override; end; {$WARNINGS ON} { TConnectionPool } constructor TConnectionPool.Create(const URL: string; const ConnectionTimeout: Integer = 0; const MaxConnections: Integer = 0; const Wait: Boolean = True); begin FURL := URL; FWait := Wait; FSlotsInUse := TBits.Create; FCriticalSection := TCriticalSection.Create; FCriticalSectionDriverManager := TCriticalSection.Create; FMaxConnections := MaxConnections; if FMaxConnections = 0 then begin SetLength(FConnections, 10); SetLength(FConnectionsReturnTimes, 10); FSlotsInUse.Size := 10; end else begin SetLength(FConnections, FMaxConnections); SetLength(FConnectionsReturnTimes, FMaxConnections); FSlotsInUse.Size := FMaxConnections; end; // // If there is a connection timeout, an instance of TConnectionTimeoutThread // will monitor all unused connections and drop them when they timeout. // FConnectionTimeout := ConnectionTimeout; if FConnectionTimeout <> 0 then FConnectionTimeoutThread := TConnectionTimeoutThread.Create(Self); end; destructor TConnectionPool.Destroy; begin if FConnectionTimeoutThread <> nil then begin FConnectionTimeoutThread.Terminate; FConnectionTimeoutThread.WaitFor; FConnectionTimeoutThread.Free; end; SetLength(FConnections, 0); FSlotsInUse.Free; FCriticalSection.Free; FCriticalSectionDriverManager.Free; inherited; end; function TConnectionPool.Acquire: IZConnection; var I: Integer; begin Result := nil; I := 0; while True do begin FCriticalSection.Enter; try // Try to get an existing connection I := 0; while I < FSlotsInUse.Size do begin if (FConnections[I] <> nil) and (not FSlotsInUse[I]) then begin try // Test for dead connections FConnections[I].Rollback; // PingServer did not work (tested with FB) FSlotsInUse[I] := True; Break; except // An exception can be raised when the dead connection is dropped try FConnections[I] := nil; except end; Inc(I); end; end else Inc(I); end; // Try to get a free slot if there is no existing connection available if I = FSlotsInUse.Size then begin I := 0; while I < FSlotsInUse.Size do begin if (FConnections[I] = nil) and (not FSlotsInUse[I]) then begin FSlotsInUse[I] := True; Break; end; Inc(I); end; end; // Increase the pool if there is no free slot in the pool if I = FSlotsInUse.Size then begin if FMaxConnections = 0 then begin SetLength(FConnections, Length(FConnections) + 10); SetLength(FConnectionsReturnTimes, Length(FConnectionsReturnTimes) + 10); FSlotsInUse.Size := FSlotsInUse.Size + 10; FSlotsInUse[I] := True; end; end; finally FCriticalSection.Leave; end; if I < FSlotsInUse.Size then Break; // No connection available. Wait and try again later if FWait then Sleep(100) else raise Exception.Create(ClassName + '.Acquire'+LineEnding+'O pool de conexatingiu o limite maximo'); //2013-10-13 mse: please replace non ASCII characters (>127) by the //#nnn notation in order to have encoding independent sources end; // // If there is no connection in the pool, create a new one. // This block is separated from the block above because there could be some // delay to create a connection, and it would not be nice to keep the critical // section locked during this delay. // if FConnections[I] = nil then begin try // I had a strong feeling that DriverManager is not thread-safe, because i // had random access violations on high load operations at this point. // For now, i will serialize DriverManager access, until further // investigation (maybe the problem is in the pool driver, as // DriverManager should be thread-safe in essence. FCriticalSectionDriverManager.Enter; try FConnections[I] := DriverManager.GetConnection(FURL); finally FCriticalSectionDriverManager.Leave; end; FConnections[I].Open; except on E: Exception do begin FCriticalSection.Enter; try FSlotsInUse[I] := False; FConnections[I] := nil; finally FCriticalSection.Leave; raise Exception.Create(ClassName + '.Acquire'+LineEnding+'Error while trying to acquire a new connection'+LineEnding+LineEnding+E.Message); end; end; end; FDefaultAutoCommit := FConnections[I].GetAutoCommit; FDefaultTransactIsolationLevel := FConnections[I].GetTransactionIsolation; end; Result := IZConnection(FConnections[I]); Result.SetAutoCommit(True); Result.SetTransactionIsolation(tiReadCommitted); end; procedure TConnectionPool.ReturnToPool(const Connection: IZConnection); var I: Integer; begin // // Return the connection to the pool. // FCriticalSection.Enter; try for I := 0 to Length(FConnections) - 1 do begin if FConnections[I] = Connection then begin // // If there is some problem with the connection, a RollBack will raise // an exception, and the connection will be dropped. // try FSlotsInUse[I] := False; FConnectionsReturnTimes[I] := Now; FConnections[I].Rollback; except try FConnections[I] := nil; except end; end; Break; end; end; finally FCriticalSection.Leave; end; end; { TZDbcPooledConnection } constructor TZDbcPooledConnection.Create(const ConnectionPool: TConnectionPool); begin FConnectionPool := ConnectionPool; {$IFDEF ZEOS_TEST_ONLY} FTestMode := 0; {$ENDIF} end; destructor TZDbcPooledConnection.Destroy; begin if FConnection <> nil then begin FConnectionPool.ReturnToPool(FConnection); FConnection := nil; end; FConnectionPool := nil; inherited; end; function TZDbcPooledConnection.GetConnection: IZConnection; begin if FConnection = nil then FConnection := FConnectionPool.Acquire; Result := FConnection; end; procedure TZDbcPooledConnection.ClearWarnings; begin GetConnection.ClearWarnings; end; function TZDbcPooledConnection.UseMetadata: boolean; begin result := FUseMetadata; end; procedure TZDbcPooledConnection.SetUseMetadata(Value: Boolean); begin FUseMetadata := Value; end; procedure TZDbcPooledConnection.Close; begin if FConnection <> nil then begin FConnectionPool.ReturnToPool(FConnection); FConnection := nil; end; end; procedure TZDbcPooledConnection.Commit; begin GetConnection.Commit; end; procedure TZDbcPooledConnection.CommitPrepared(const transactionid: string); begin GetConnection.CommitPrepared(transactionid); end; function TZDbcPooledConnection.CreateNotification(const Event: string): IZNotification; begin Result := GetConnection.CreateNotification(Event); end; function TZDbcPooledConnection.CreateSequence(const Sequence: string; BlockSize: Integer): IZSequence; begin Result := GetConnection.CreateSequence(Sequence, BlockSize); end; function TZDbcPooledConnection.CreateStatement: IZStatement; begin Result := GetConnection.CreateStatement; end; function TZDbcPooledConnection.CreateStatementWithParams(Info: TStrings): IZStatement; begin Result := GetConnection.CreateStatementWithParams(Info); end; function TZDbcPooledConnection.EscapeString(Value: RawByteString): RawByteString; begin Result := GetConnection.EscapeString(Value); end; function TZDbcPooledConnection.GetAutoCommit: Boolean; begin Result := GetConnection.GetAutoCommit; end; function TZDbcPooledConnection.GetCatalog: string; begin Result := GetConnection.GetCatalog; end; function TZDbcPooledConnection.GetClientVersion: Integer; begin Result := GetConnection.GetClientVersion; end; function TZDbcPooledConnection.GetDriver: IZDriver; begin Result := GetConnection.GetDriver; end; function TZDbcPooledConnection.GetIZPlainDriver: IZPlainDriver; begin Result := GetConnection.GetIZPlainDriver; end; function TZDbcPooledConnection.GetHostVersion: Integer; begin Result := GetConnection.GetHostVersion; end; function TZDbcPooledConnection.GetMetadata: IZDatabaseMetadata; begin Result := GetConnection.GetMetadata; end; function TZDbcPooledConnection.GetParameters: TStrings; begin Result := GetConnection.GetParameters; end; function TZDbcPooledConnection.GetTransactionIsolation: TZTransactIsolationLevel; begin Result := GetConnection.GetTransactionIsolation; end; function TZDbcPooledConnection.GetWarnings: EZSQLWarning; begin Result := GetConnection.GetWarnings; end; function TZDbcPooledConnection.IsClosed: Boolean; begin Result := (FConnection = nil) or FConnection.IsClosed; end; function TZDbcPooledConnection.IsReadOnly: Boolean; begin Result := GetConnection.IsReadOnly; end; function TZDbcPooledConnection.NativeSQL(const SQL: string): string; begin Result := GetConnection.NativeSQL(SQL); end; procedure TZDbcPooledConnection.Open; begin GetConnection.Open; end; function TZDbcPooledConnection.PingServer: Integer; begin Result := GetConnection.PingServer; end; function TZDbcPooledConnection.PrepareCall(const SQL: string): IZCallableStatement; begin Result := GetConnection.PrepareCall(SQL); end; function TZDbcPooledConnection.PrepareCallWithParams(const SQL: string; Info: TStrings): IZCallableStatement; begin Result := GetConnection.PrepareCallWithParams(SQL, Info); end; function TZDbcPooledConnection.PrepareStatement(const SQL: string): IZPreparedStatement; begin Result := GetConnection.PrepareStatement(SQL); end; function TZDbcPooledConnection.PrepareStatementWithParams(const SQL: string; Info: TStrings): IZPreparedStatement; begin Result := GetConnection.PrepareStatementWithParams(SQL, Info); end; procedure TZDbcPooledConnection.PrepareTransaction(const transactionid: string); begin GetConnection.PrepareTransaction(transactionid); end; procedure TZDbcPooledConnection.Rollback; begin GetConnection.Rollback; end; procedure TZDbcPooledConnection.RollbackPrepared(const transactionid: string); begin GetConnection.RollbackPrepared(transactionid); end; procedure TZDbcPooledConnection.SetAutoCommit(Value: Boolean); begin GetConnection.SetAutoCommit(Value); end; procedure TZDbcPooledConnection.SetCatalog(const Value: string); begin GetConnection.SetCatalog(Value); end; procedure TZDbcPooledConnection.SetReadOnly(Value: Boolean); begin GetConnection.SetReadOnly(Value); end; procedure TZDbcPooledConnection.SetTransactionIsolation(Value: TZTransactIsolationLevel); begin GetConnection.SetTransactionIsolation(Value); end; {** EgonHugeist: Check if the given Charset for Compiler/Database-Support!! Not supported means if there is a pissible String-DataLoss. So it raises an Exception if case of settings. This handling is an improofment to inform Zeos-Users about the troubles the given CharacterSet may have. @param CharSet the CharacterSet which has to be proofed @param DoArrange represents a switch to check and set a aternative ZAlias as default. This means it ignores the choosen Client-CharacterSet and sets a "more" Zeos-Compatible Client-CharacterSet if known. } procedure TZDbcPooledConnection.CheckCharEncoding(CharSet: String; const DoArrange: Boolean = False); begin Self.GetConSettings.ClientCodePage := GetIZPlainDriver.ValidateCharEncoding(CharSet, DoArrange); FClientCodePage := ConSettings.ClientCodePage^.Name; //resets the developer choosen ClientCodePage end; {** EgonHugeist: this is a compatibility-Option for exiting Applictions. Zeos is now able to preprepare direct insered SQL-Statements. Means do the UTF8-preparation if the CharacterSet was choosen. So we do not need to do the SQLString + UTF8Encode(Edit1.Test) for example. @result True if coAutoEncodeStrings was choosen in the TZAbstractConnection } function TZDbcPooledConnection.GetAutoEncodeStrings: Boolean; begin Result := FAutoEncodeStrings; end; procedure TZDbcPooledConnection.SetAutoEncodeStrings(const Value: Boolean); begin FAutoEncodeStrings := Value; end; {** EgonHugeist: Returns the BinaryString in a Tokenizer-detectable kind If the Tokenizer don't need to predetect it Result = BinaryString @param Value represents the Binary-String @param EscapeMarkSequence represents a Tokenizer detectable EscapeSequence (Len >= 3) @result the detectable Binary String } function TZDbcPooledConnection.GetBinaryEscapeString(const Value: RawByteString): String; begin Result := GetConnection.GetBinaryEscapeString(Value); end; function TZDbcPooledConnection.GetBinaryEscapeString(const Value: TByteDynArray): String; begin Result := GetConnection.GetBinaryEscapeString(Value); end; function TZDbcPooledConnection.GetEscapeString(const Value: ZWideString): ZWideString; begin Result := GetConnection.GetEscapeString(Value); end; function TZDbcPooledConnection.GetEscapeString(const Value: RawByteString): RawByteString; begin Result := GetConnection.GetEscapeString(Value); end; function TZDbcPooledConnection.GetEncoding: TZCharEncoding; begin Result := ConSettings.ClientCodePage^.Encoding; end; function TZDbcPooledConnection.GetConSettings: PZConSettings; begin Result := @ConSettings; end; {$IFDEF ZEOS_TEST_ONLY} function TZDbcPooledConnection.GetTestMode: Byte; begin Result := FTestMode; end; procedure TZDbcPooledConnection.SetTestMode(Mode: Byte); begin FTestMode := Mode; end; {$ENDIF} {** Result 100% Compiler-Compatible And sets it Result to ClientCodePage by calling the PlainDriver.GetClientCodePageInformations function @param ClientCharacterSet the CharacterSet which has to be checked @result PZCodePage see ZCompatible.pas } function TZDbcPooledConnection.GetClientCodePageInformations: PZCodePage; //EgonHugeist begin Result := ConSettings.ClientCodePage end; { TZDbcPooledConnectionDriver } constructor TZDbcPooledConnectionDriver.Create; begin inherited Create; PoolList := TObjectList.Create(True); URLList := TStringList.Create; AddSupportedProtocol(PooledPrefix + '*'); end; destructor TZDbcPooledConnectionDriver.Destroy; begin PoolList.Free; URLList.Free; inherited; end; function TZDbcPooledConnectionDriver.AcceptsURL(const URL: string): Boolean; begin Result := Copy(URL, 1, 5 + Length(PooledPrefix)) = 'zdbc:' + PooledPrefix; end; function TZDbcPooledConnectionDriver.Connect(const URL: TZURL): IZConnection; var TempURL: TZURL; I: Integer; ConnectionPool: TConnectionPool; ConnetionTimeout: Integer; MaxConnections: Integer; Wait: Boolean; begin Result := nil; TempURL := TZURL.Create; try TempURL.URL := GetEmbeddedURL(URL.URL); TempURL.Properties.Text := URL.Properties.Text; ConnectionPool := nil; { TODO - Read and process connection properties 'timeout', 'poolsize' and 'wait' } // // Search for an existing pool for the URL. // There is room to improve the algorithm used to decide when a pool is // compatible with a given URL. For now, i am just comparing the URL strings. // for I := 0 to PoolList.Count - 1 do if URLList[I] = TempURL.URL then begin ConnectionPool := TConnectionPool(PoolList[I]); Break; end; // // Create a new pool if needed. // if ConnectionPool = nil then begin ConnetionTimeout := StrToIntDef(TempURL.Properties.Values['ConnectionTimeout'], 0); MaxConnections := StrToIntDef(TempURL.Properties.Values['MaxConnections'], 0); Wait := StrToBoolDef(TempURL.Properties.Values['Wait'], True); ConnectionPool := TConnectionPool.Create(TempURL.URL, ConnetionTimeout, MaxConnections, Wait); PoolList.Add(ConnectionPool); URLList.Add(TempURL.URL); end; Result := TZDbcPooledConnection.Create(ConnectionPool); finally TempURL.Free; end; end; function TZDbcPooledConnectionDriver.GetClientVersion(const URL: string): Integer; begin Result := DriverManager.GetDriver(GetEmbeddedURL(URL)).GetClientVersion(GetEmbeddedURL(URL)); end; function TZDbcPooledConnectionDriver.GetMajorVersion: Integer; begin Result := 1; end; function TZDbcPooledConnectionDriver.GetMinorVersion: Integer; begin Result := 0; end; function TZDbcPooledConnectionDriver.GetPropertyInfo(const URL: string; Info: TStrings): TStrings; begin Result := DriverManager.GetDriver(GetEmbeddedURL(URL)).GetPropertyInfo(GetEmbeddedURL(URL), Info); if Result = nil then Result := TStringList.Create; Result.Values['ConnectionTimeout'] := '0'; Result.Values['MaxConnections'] := '0'; Result.Values['Wait'] := 'True'; end; function TZDbcPooledConnectionDriver.GetSubVersion: Integer; begin Result := 0; end; {function TZDbcPooledConnectionDriver.GetSupportedProtocols: TStringDynArray; begin SetLength(Result, 1); Result[0] := PooledPrefix + '*'; end;} function TZDbcPooledConnectionDriver.GetEmbeddedURL(const URL: String): String; begin if Copy(URL, 1, 5 + Length(PooledPrefix)) = 'zdbc:' + PooledPrefix then Result := 'zdbc:' + Copy(URL, 5 + Length(PooledPrefix) + 1, Length(URL)) else raise Exception.Create('TZDbcPooledConnectionDriver.GetRealURL - URL must start with ''zdbc:' + PooledPrefix+ ''''); end; var _Driver: IZDriver; { TConnectionTimeoutThread } constructor TConnectionTimeoutThread.Create(const ConnectionPool: TConnectionPool); begin inherited Create(False); FConnectionPool := ConnectionPool; FreeOnTerminate := False; end; procedure TConnectionTimeoutThread.Execute; var I: Integer; begin while not Terminated do begin Sleep(1000); // // Check if there are timed out connections and releases them // FConnectionPool.FCriticalSection.Enter; try for I := 0 to Length(FConnectionPool.FConnections) - 1 do if (FConnectionPool.FConnections[I] <> nil) and (not FConnectionPool.FSlotsInUse[I]) and (FConnectionPool.FConnectionsReturnTimes[I] <> 0) and (MilliSecondsBetween(FConnectionPool.FConnectionsReturnTimes[I], Now) > FConnectionPool.FConnectionTimeout * 1000) then FConnectionPool.FConnections[I] := nil; finally FConnectionPool.FCriticalSection.Leave; end; end; end; initialization _Driver := TZDbcPooledConnectionDriver.Create; DriverManager.RegisterDriver(_Driver); finalization DriverManager.DeregisterDriver(_Driver); end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcPostgreSql.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { PostgreSQL Database Connectivity Classes } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcPostgreSql; interface {$I ZDbc.inc} uses Types, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, {$IF defined(DELPHI) and defined(MSWINDOWS)}Windows,{$IFEND} ZDbcIntfs, ZDbcConnection, ZPlainPostgreSqlDriver, ZDbcLogging, ZTokenizer, ZGenericSqlAnalyser, ZURL, ZCompatibility; type {** Implements PostgreSQL Database Driver. } {$WARNINGS OFF} TZPostgreSQLDriver = class(TZAbstractDriver) public constructor Create; override; function Connect(const Url: TZURL): IZConnection; override; function GetMajorVersion: Integer; override; function GetMinorVersion: Integer; override; function GetTokenizer: IZTokenizer; override; function GetStatementAnalyser: IZStatementAnalyser; override; end; {$WARNINGS ON} type PZPGTableInfo = ^TZPGTableInfo; TZPGTableInfo = record OID: Oid; Name: String; Schema: String; ColNames: Array of String; ColCount: Integer; end; { TZPGTableInfoCache } TZPGTableInfoCache = class(TZCodePagedObject) protected FTblInfo: Array of TZPGTableInfo; FPlainDriver: Pointer; FHandle: PZPostgreSQLConnect; function LoadTblInfo(const TblOid: Oid; out Index: Integer; ZPGTableInfo: PZPGTableInfo): Boolean; function GetTblPos(const TblOid: Oid): Integer; public constructor Create(const ConSettings: PZConSettings; const Handle: PZPostgreSQLConnect; const PlainDriver: IZPostgreSQLPlainDriver); function GetTableInfo(const TblOid: Oid; CurrentFieldCount: Integer): PZPGTableInfo; procedure Clear; end; {** Defines a PostgreSQL specific connection. } IZPostgreSQLConnection = interface(IZConnection) ['{8E62EA93-5A49-4F20-928A-0EA44ABCE5DB}'] function IsOidAsBlob: Boolean; function Is_bytea_output_hex: Boolean; function GetTypeNameByOid(Id: Oid): string; function GetPlainDriver: IZPostgreSQLPlainDriver; function GetConnectionHandle: PZPostgreSQLConnect; function GetServerMajorVersion: Integer; function GetServerMinorVersion: Integer; function EncodeBinary(const Value: RawByteString): RawByteString; overload; function EncodeBinary(const Value: TByteDynArray): RawByteString; overload; procedure RegisterPreparedStmtName(const value: String); procedure UnregisterPreparedStmtName(const value: String); function ClientSettingsChanged: Boolean; function GetUndefinedVarcharAsStringLength: Integer; function GetTableInfo(const TblOid: Oid; CurrentFieldCount: Integer): PZPGTableInfo; function CheckFieldVisibility: Boolean; end; {** Implements PostgreSQL Database Connection. } { TZPostgreSQLConnection } TZPostgreSQLConnection = class(TZAbstractConnection, IZPostgreSQLConnection) private FStandardConformingStrings: Boolean; FHandle: PZPostgreSQLConnect; FBeginRequired: Boolean; FTypeList: TStrings; FOidAsBlob: Boolean; FServerMajorVersion: Integer; FServerMinorVersion: Integer; FServerSubVersion: Integer; FNoticeProcessor: TZPostgreSQLNoticeProcessor; FPreparedStmts: TStrings; FClientSettingsChanged: Boolean; FTableInfoCache: TZPGTableInfoCache; FIs_bytea_output_hex: Boolean; FCheckFieldVisibility: Boolean; protected procedure InternalCreate; override; function GetUndefinedVarcharAsStringLength: Integer; function GetTableInfo(const TblOid: Oid; CurrentFieldCount: Integer): PZPGTableInfo; function BuildConnectStr: AnsiString; procedure StartTransactionSupport; procedure LoadServerVersion; procedure OnPropertiesChange(Sender: TObject); override; procedure SetStandardConformingStrings(const Value: Boolean); function EncodeBinary(const Value: RawByteString): RawByteString; overload; function EncodeBinary(const Value: TByteDynArray): RawByteString; overload; procedure RegisterPreparedStmtName(const value: String); procedure UnregisterPreparedStmtName(const value: String); function ClientSettingsChanged: Boolean; public destructor Destroy; override; function CreateRegularStatement(Info: TStrings): IZStatement; override; function CreatePreparedStatement(const SQL: string; Info: TStrings): IZPreparedStatement; override; function CreateCallableStatement(const SQL: string; Info: TStrings): IZCallableStatement; override; function CreateSequence(const Sequence: string; BlockSize: Integer): IZSequence; override; procedure Commit; override; procedure Rollback; override; //2Phase Commit Support initially for PostgresSQL (firmos) 21022006 procedure PrepareTransaction(const transactionid: string);override; procedure CommitPrepared(const transactionid:string);override; procedure RollbackPrepared(const transactionid:string);override; procedure Open; override; procedure Close; override; procedure SetTransactionIsolation(Level: TZTransactIsolationLevel); override; function IsOidAsBlob: Boolean; function Is_bytea_output_hex: Boolean; function CheckFieldVisibility: Boolean; function GetTypeNameByOid(Id: Oid): string; function GetPlainDriver: IZPostgreSQLPlainDriver; function GetConnectionHandle: PZPostgreSQLConnect; function GetHostVersion: Integer; override; function GetServerMajorVersion: Integer; function GetServerMinorVersion: Integer; function GetServerSubVersion: Integer; function PingServer: Integer; override; function EscapeString(Value: RawByteString): RawByteString; override; function GetBinaryEscapeString(const Value: RawByteString): String; overload; override; function GetBinaryEscapeString(const Value: TByteDynArray): String; overload; override; function GetEscapeString(const Value: ZWideString): ZWideString; overload; override; function GetEscapeString(const Value: RawByteString): RawByteString; overload; override; function GetServerSetting(const AName: string): string; procedure SetServerSetting(const AName, AValue: string); {$IFDEF ZEOS_TEST_ONLY} constructor Create(const ZUrl: TZURL); {$ENDIF} end; {** Implements a Postgres sequence. } TZPostgreSQLSequence = class(TZAbstractSequence) public function GetCurrentValue: Int64; override; function GetNextValue: Int64; override; function GetCurrentValueSQL:String;override; function GetNextValueSQL:String;override; end; var {** The common driver manager object. } PostgreSQLDriver: IZDriver; implementation uses ZMessages, ZSysUtils, ZDbcUtils, ZDbcPostgreSqlStatement, ZDbcPostgreSqlUtils, ZDbcPostgreSqlMetadata, ZPostgreSqlToken, ZPostgreSqlAnalyser, ZEncoding; const FON = String('ON'); standard_conforming_strings = String('standard_conforming_strings'); procedure DefaultNoticeProcessor(arg: Pointer; message: PAnsiChar); cdecl; begin DriverManager.LogMessage(lcOther,'Postgres NOTICE',String(message)); end; { TZPGTableInfoCache } function TZPGTableInfoCache.LoadTblInfo(const TblOid: Oid; out Index: Integer; ZPGTableInfo: PZPGTableInfo): Boolean; var SQL: String; TblInfo: PZPGTableInfo; RawOid: String; QueryHandle: PZPostgreSQLResult; I: Integer; function GetInt(const Row, Col: Integer): Integer; begin Result := StrToInt(String(IZPostgreSQLPlainDriver(FPlainDriver).GetValue(QueryHandle, Row, Col))); end; function GetString(const Row, Col: Integer): String; {$IFDEF UNICODE} var RawTemp: RawByteString; {$ENDIF} begin {$IFDEF UNICODE} ZSetString(IZPostgreSQLPlainDriver(FPlainDriver).GetValue(QueryHandle, Row, Col), IZPostgreSQLPlainDriver(FPlainDriver).GetLength(QueryHandle, Row, Col), RawTemp); Result := ZDbcUnicodeString(RawTemp); {$ELSE} SetString(Result, IZPostgreSQLPlainDriver(FPlainDriver).GetValue(QueryHandle, Row, Col), IZPostgreSQLPlainDriver(FPlainDriver).GetLength(QueryHandle, Row, Col)); {$ENDIF} end; begin RawOID := IntToStr(TblOid); SQL := 'select pc.relname, pns.nspname, pa.attnum, pa.attname from ' + 'pg_catalog.pg_class pc ' + 'join pg_catalog.pg_namespace pns on pc.relnamespace = pns.oid ' + 'join pg_catalog.pg_attribute pa on pa.attrelid = pc.oid ' + 'where pc.oid = ' + RawOID + ' and pa.attnum > 0'; QueryHandle := IZPostgreSQLPlainDriver(FPlainDriver).ExecuteQuery(FHandle, PAnsichar(ZPlainString(SQL))); CheckPostgreSQLError(nil, IZPostgreSQLPlainDriver(FPlainDriver), FHandle, lcExecute, SQL, QueryHandle); DriverManager.LogMessage(lcExecute, IZPostgreSQLPlainDriver(FPlainDriver).GetProtocol, SQL); Result := IZPostgreSQLPlainDriver(FPlainDriver).GetRowCount(QueryHandle) > 0; if Result then begin if ZPGTableInfo <> nil then //just overwrite all values tblInfo := ZPGTableInfo else begin //we need a new cache SetLength(FTblInfo, Length(FTblInfo) +1); Index := High(FTblInfo); TblInfo := @FTblInfo[Index]; end; TblInfo^.OID := TblOid; TblInfo^.Name := GetString(0, 0); TblInfo^.Schema := GetString(0, 1); TblInfo^.ColCount := IZPostgreSQLPlainDriver(FPlainDriver).GetRowCount(QueryHandle); SetLength(TblInfo^.ColNames, TblInfo^.ColCount); for I := 0 to TblInfo^.ColCount - 1 do TblInfo^.ColNames[GetInt(I, 2)-1] := GetString(i, 3); IZPostgreSQLPlainDriver(FPlainDriver).Clear(QueryHandle); end else Index := -1; end; function TZPGTableInfoCache.GetTblPos(const TblOid: Oid): Integer; var x: Integer; begin Result := -1; if TblOid <> InvalidOid then for x := 0 to Length(FTblInfo) - 1 do if FTblInfo[x].OID = TblOid then begin Result := x; Break; end; end; constructor TZPGTableInfoCache.Create(const ConSettings: PZConSettings; const Handle: PZPostgreSQLConnect; const PlainDriver: IZPostgreSQLPlainDriver); begin Self.ConSettings := ConSettings; FPlainDriver := Pointer(PlainDriver); FHandle := Handle; Clear; end; function TZPGTableInfoCache.GetTableInfo(const TblOid: Oid; CurrentFieldCount: Integer): PZPGTableInfo; var Idx: Integer; begin Idx := GetTblPos(TblOid); if (Idx = -1) then if (TblOid <> InvalidOid) and (LoadTblInfo(TblOid, Idx, nil)) then Result := @FTblInfo[Idx] else Result := nil else begin Result := @FTblInfo[Idx]; if Result^.ColCount <> CurrentFieldCount then //something changed ? LoadTblInfo(TblOid, Idx, Result); //refresh all data end; end; procedure TZPGTableInfoCache.Clear; begin SetLength(FTblInfo, 0); end; { TZPostgreSQLDriver } {** Constructs this object with default properties. } constructor TZPostgreSQLDriver.Create; begin inherited Create; AddSupportedProtocol(AddPlainDriverToCache(TZPostgreSQL9PlainDriver.Create, 'postgresql')); AddSupportedProtocol(AddPlainDriverToCache(TZPostgreSQL7PlainDriver.Create)); AddSupportedProtocol(AddPlainDriverToCache(TZPostgreSQL8PlainDriver.Create)); AddSupportedProtocol(AddPlainDriverToCache(TZPostgreSQL9PlainDriver.Create)); end; {** Attempts to make a database connection to the given URL. The driver should return "null" if it realizes it is the wrong kind of driver to connect to the given URL. This will be common, as when the JDBC driver manager is asked to connect to a given URL it passes the URL to each loaded driver in turn.

The driver should raise a SQLException if it is the right driver to connect to the given URL, but has trouble connecting to the database.

The java.util.Properties argument can be used to passed arbitrary string tag/value pairs as connection arguments. Normally at least "user" and "password" properties should be included in the Properties. @param url the URL of the database to which to connect @param info a list of arbitrary string tag/value pairs as connection arguments. Normally at least a "user" and "password" property should be included. @return a Connection object that represents a connection to the URL } {$WARNINGS OFF} function TZPostgreSQLDriver.Connect(const Url: TZURL): IZConnection; begin Result := TZPostgreSQLConnection.Create(Url); end; {$WARNINGS ON} {** Gets the driver's major version number. Initially this should be 1. @return this driver's major version number } function TZPostgreSQLDriver.GetMajorVersion: Integer; begin Result := 1; end; {** Gets the driver's minor version number. Initially this should be 0. @return this driver's minor version number } function TZPostgreSQLDriver.GetMinorVersion: Integer; begin Result := 3; end; {** Gets a SQL syntax tokenizer. @returns a SQL syntax tokenizer object. } function TZPostgreSQLDriver.GetTokenizer: IZTokenizer; begin if Tokenizer = nil then Tokenizer := TZPostgreSQLTokenizer.Create; Result := Tokenizer; end; {** Creates a statement analyser object. @returns a statement analyser object. } function TZPostgreSQLDriver.GetStatementAnalyser: IZStatementAnalyser; begin if Analyser = nil then Analyser := TZPostgreSQLStatementAnalyser.Create; Result := Analyser; end; { TZPostgreSQLConnection } {** Constructs this object and assignes the main properties. } procedure TZPostgreSQLConnection.InternalCreate; begin FMetaData := TZPostgreSQLDatabaseMetadata.Create(Self, Url); FPreparedStmts := nil; FTableInfoCache := nil; { Sets a default PostgreSQL port } if Self.Port = 0 then Self.Port := 5432; { Define connect options. } if Info.Values['beginreq'] <> '' then FBeginRequired := StrToBoolEx(Info.Values['beginreq']) else FBeginRequired := True; TransactIsolationLevel := tiNone; { Processes connection properties. } if Info.Values['oidasblob'] <> '' then FOidAsBlob := StrToBoolEx(Info.Values['oidasblob']) else FOidAsBlob := False; FUndefinedVarcharAsStringLength := StrToIntDef(Info.Values['Undefined_Varchar_AsString_Length'], 0); FCheckFieldVisibility := StrToBoolEx(Info.Values['CheckFieldVisibility']); OnPropertiesChange(nil); FNoticeProcessor := DefaultNoticeProcessor; end; function TZPostgreSQLConnection.GetUndefinedVarcharAsStringLength: Integer; begin Result := FUndefinedVarcharAsStringLength; end; function TZPostgreSQLConnection.GetTableInfo(const TblOid: Oid; CurrentFieldCount: Integer): PZPGTableInfo; begin Result := FTableInfoCache.GetTableInfo(TblOid, CurrentFieldCount); end; {** Destroys this object and cleanups the memory. } destructor TZPostgreSQLConnection.Destroy; begin if FTypeList <> nil then FreeAndNil(FTypeList); inherited Destroy; if FTableInfoCache <> nil then FreeAndNil(FTableInfoCache); if FPreparedStmts <> nil then FreeAndNil(FPreparedStmts); end; {** Builds a connection string for PostgreSQL. @return a built connection string. } function TZPostgreSQLConnection.BuildConnectStr: AnsiString; var ConnectTimeout: Integer; // backslashes and single quotes must be escaped with backslashes function EscapeValue(AValue: String): String; begin Result := StringReplace(AValue, '\', '\\', [rfReplaceAll]); Result := StringReplace(Result, '''', '\''', [rfReplaceAll]); end; //parameters should be separated by whitespace procedure AddParamToResult(AParam, AValue: String); begin if Result <> '' then Result := Result + ' '; Result := Result + AnsiString(AParam+'='+QuotedStr(EscapeValue(AValue))); end; begin //Init the result to empty string. Result := ''; //Entering parameters from the ZConnection If IsIpAddr(HostName) then AddParamToResult('hostaddr', HostName) else AddParamToResult('host', HostName); AddParamToResult('port', IntToStr(Port)); AddParamToResult('dbname', Database); AddParamToResult('user', User); AddParamToResult('password', Password); If Info.Values['sslmode'] <> '' then begin // the client (>= 7.3) sets the ssl mode for this connection // (possible values are: require, prefer, allow, disable) AddParamToResult('sslmode', Info.Values['sslmode']); end else if Info.Values['requiressl'] <> '' then begin // the client (< 7.3) sets the ssl encription for this connection // (possible values are: 0,1) AddParamToResult('requiressl', Info.Values['requiressl']); end; if Info.Values['sslcompression'] <> '' then AddParamToResult('sslcompression', Info.Values['sslcompression']); if Info.Values['sslcert'] <> '' then AddParamToResult('sslcert', Info.Values['sslcert']); if Info.Values['sslkey'] <> '' then AddParamToResult('sslkey', Info.Values['sslkey']); if Info.Values['sslrootcert'] <> '' then AddParamToResult('sslrootcert', Info.Values['sslrootcert']); if Info.Values['sslcrl'] <> '' then AddParamToResult('sslcrl', Info.Values['sslcrl']); { Sets a connection timeout. } ConnectTimeout := StrToIntDef(Info.Values['timeout'], -1); if ConnectTimeout >= 0 then AddParamToResult('connect_timeout', IntToStr(ConnectTimeout)); { Sets the application name } if Info.Values['application_name'] <> '' then AddParamToResult('application_name', Info.Values['application_name']); end; {** Checks is oid should be treated as Large Object. @return True if oid should represent a Large Object. } function TZPostgreSQLConnection.IsOidAsBlob: Boolean; begin Result := FOidAsBlob; end; {** Checks is bytea_output hex. @return True if hex is set. } function TZPostgreSQLConnection.Is_bytea_output_hex: Boolean; begin Result := FIs_bytea_output_hex; end; {** Checks if DataBaseMetaData should check FieldVisibility too. @return True if user did set it. } function TZPostgreSQLConnection.CheckFieldVisibility: Boolean; begin Result := FCheckFieldVisibility; end; {** Starts a transaction support. } procedure TZPostgreSQLConnection.StartTransactionSupport; var QueryHandle: PZPostgreSQLResult; SQL: String; begin if TransactIsolationLevel <> tiNone then begin if FBeginRequired then begin SQL := 'BEGIN'; QueryHandle := GetPlainDriver.ExecuteQuery(FHandle, PAnsiChar(AnsiString(SQL))); CheckPostgreSQLError(nil, GetPlainDriver, FHandle, lcExecute, SQL,QueryHandle); GetPlainDriver.Clear(QueryHandle); DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, SQL); end; if TransactIsolationLevel = tiReadCommitted then begin SQL := 'SET TRANSACTION ISOLATION LEVEL READ COMMITTED'; QueryHandle := GetPlainDriver.ExecuteQuery(FHandle, PAnsiChar(AnsiString(SQL))); CheckPostgreSQLError(nil, GetPlainDriver, FHandle, lcExecute, SQL,QueryHandle); GetPlainDriver.Clear(QueryHandle); DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, SQL); end else if TransactIsolationLevel = tiSerializable then begin SQL := 'SET TRANSACTION ISOLATION LEVEL SERIALIZABLE'; QueryHandle := GetPlainDriver.ExecuteQuery(FHandle, PAnsiChar(AnsiString(SQL))); CheckPostgreSQLError(nil, GetPlainDriver, FHandle, lcExecute, SQL,QueryHandle); GetPlainDriver.Clear(QueryHandle); DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, SQL); end else raise EZSQLException.Create(SIsolationIsNotSupported); end; end; {** Encodes a Binary-AnsiString to a PostgreSQL format @param Value the Binary String @result the encoded String } function TZPostgreSQLConnection.EncodeBinary(const Value: TByteDynArray): RawByteString; var Temp: RawByteString; begin ZSetString(PAnsiChar(Value), Length(Value), Temp); Result := EncodeBinary(Temp); end; {** Encodes a Binary-AnsiString to a PostgreSQL format @param Value the Binary String @result the encoded String } function TZPostgreSQLConnection.EncodeBinary(const Value: RawByteString): RawByteString; begin if ( Self.GetServerMajorVersion > 7 ) or ((GetServerMajorVersion = 7) and (GetServerMinorVersion >= 3)) then Result := GetPlainDriver.EncodeBYTEA(Value, GetConnectionHandle) else Result := ZDbcPostgreSqlUtils.EncodeBinaryString(Value); end; procedure TZPostgreSQLConnection.RegisterPreparedStmtName(const value: String); begin FPreparedStmts.Add(Value); end; procedure TZPostgreSQLConnection.UnregisterPreparedStmtName(const value: String); var Index: Integer; begin Index := FPreparedStmts.IndexOf(Value); if Index > -1 then FPreparedStmts.Delete(Index); end; function TZPostgreSQLConnection.ClientSettingsChanged: Boolean; begin Result := FClientSettingsChanged; end; {** Opens a connection to database server with specified parameters. } procedure TZPostgreSQLConnection.Open; var SCS, LogMessage, TempClientCodePage: string; begin if not Closed then Exit; LogMessage := Format('CONNECT TO "%s" AS USER "%s"', [Database, User]); { Connect to PostgreSQL database. } FHandle := GetPlainDriver.ConnectDatabase(PAnsiChar(BuildConnectStr)); try if GetPlainDriver.GetStatus(FHandle) = CONNECTION_BAD then begin CheckPostgreSQLError(nil, GetPlainDriver, FHandle, lcConnect, LogMessage,nil) end else DriverManager.LogMessage(lcConnect, PlainDriver.GetProtocol, LogMessage); { Set the notice processor (default = nil)} GetPlainDriver.SetNoticeProcessor(FHandle,FNoticeProcessor,nil); { Gets the current codepage } TempClientCodePage := GetPlainDriver.ValidateCharEncoding(GetPlainDriver.GetClientEncoding(FHandle)).Name; { Sets a client codepage if necessary } if ( FClientCodePage <> '' ) and (TempClientCodePage <> FClientCodePage) then SetServerSetting('CLIENT_ENCODING', FClientCodePage); { Turn on transaction mode } StartTransactionSupport; inherited Open; { Gets the current codepage if it wasn't set..} if ( FClientCodePage = '') then CheckCharEncoding(TempClientCodePage) else begin CheckCharEncoding(FClientCodePage); FClientSettingsChanged := True; end; if FPreparedStmts = nil then FPreparedStmts := TStringList.Create; if FTableInfoCache = nil then FTableInfoCache := TZPGTableInfoCache.Create(ConSettings, FHandle, GetPlainDriver); { sets standard_conforming_strings according to Properties if available } SCS := Info.Values[standard_conforming_strings]; if SCS <> '' then begin SetServerSetting(standard_conforming_strings, SCS); FClientSettingsChanged := True; end; FIs_bytea_output_hex := UpperCase(GetServerSetting('''bytea_output''')) = 'HEX'; finally if self.IsClosed and (Self.FHandle <> nil) then begin GetPlainDriver.Finish(Self.FHandle); Self.FHandle := nil; end; end; end; procedure TZPostgreSQLConnection.PrepareTransaction(const transactionid: string); var QueryHandle: PZPostgreSQLResult; SQL: String; begin if (TransactIsolationLevel <> tiNone) and not Closed then begin SQL:='PREPARE TRANSACTION '''+copy(transactionid,1,200)+''''; QueryHandle := GetPlainDriver.ExecuteQuery(FHandle, PAnsiChar(ZPlainString(SQL))); CheckPostgreSQLError(nil, GetPlainDriver, FHandle, lcExecute, SQL,QueryHandle); GetPlainDriver.Clear(QueryHandle); DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, SQL); StartTransactionSupport; end; end; {** Creates a Statement object for sending SQL statements to the database. SQL statements without parameters are normally executed using Statement objects. If the same SQL statement is executed many times, it is more efficient to use a PreparedStatement object.

Result sets created using the returned Statement object will by default have forward-only type and read-only concurrency. @param Info a statement parameters. @return a new Statement object } function TZPostgreSQLConnection.CreateRegularStatement(Info: TStrings): IZStatement; begin if IsClosed then Open; Result := TZPostgreSQLStatement.Create(GetPlainDriver, Self, Info); end; {** Creates a PreparedStatement object for sending parameterized SQL statements to the database. A SQL statement with or without IN parameters can be pre-compiled and stored in a PreparedStatement object. This object can then be used to efficiently execute this statement multiple times.

Note: This method is optimized for handling parametric SQL statements that benefit from precompilation. If the driver supports precompilation, the method prepareStatement will send the statement to the database for precompilation. Some drivers may not support precompilation. In this case, the statement may not be sent to the database until the PreparedStatement is executed. This has no direct effect on users; however, it does affect which method throws certain SQLExceptions. Result sets created using the returned PreparedStatement will have forward-only type and read-only concurrency, by default. @param sql a SQL statement that may contain one or more '?' IN parameter placeholders @param Info a statement parameters. @return a new PreparedStatement object containing the pre-compiled statement } function TZPostgreSQLConnection.CreatePreparedStatement( const SQL: string; Info: TStrings): IZPreparedStatement; begin if IsClosed then Open; {$IFDEF ZEOS_TEST_ONLY} Case GetTestMode of 0: {$ENDIF} if GetServerMajorVersion >= 8 then Result := TZPostgreSQLCAPIPreparedStatement.Create(GetPlainDriver, Self, SQL, Info) else Result := TZPostgreSQLClassicPreparedStatement.Create(GetPlainDriver, Self, SQL, Info); {$IFDEF ZEOS_TEST_ONLY} 1: Result := TZPostgreSQLClassicPreparedStatement.Create(GetPlainDriver, Self, SQL, Info); 2: Result := TZPostgreSQLEmulatedPreparedStatement.Create(GetPlainDriver, Self, SQL, Info); end; {$ENDIF} end; {** Creates a CallableStatement object for calling database stored procedures (functions in PostgreSql). The CallableStatement object provides methods for setting up its IN and OUT parameters, and methods for executing the call to a stored procedure.

Note: This method is optimized for handling stored procedure call statements. Some drivers may send the call statement to the database when the method prepareCall is done; others may wait until the CallableStatement object is executed. This has no direct effect on users; however, it does affect which method throws certain SQLExceptions. Result sets created using the returned CallableStatement will have forward-only type and read-only concurrency, by default. @param sql a SQL statement that may contain one or more '?' parameter placeholders. Typically this statement is a JDBC function call escape string. @param Info a statement parameters. @return a new CallableStatement object containing the pre-compiled SQL statement } function TZPostgreSQLConnection.CreateCallableStatement( const SQL: string; Info: TStrings): IZCallableStatement; begin if IsClosed then Open; Result := TZPostgreSQLCallableStatement.Create(Self, SQL, Info); end; {** Makes all changes made since the previous commit/rollback permanent and releases any database locks currently held by the Connection. This method should be used only when auto-commit mode has been disabled. @see #setAutoCommit } procedure TZPostgreSQLConnection.Commit; var QueryHandle: PZPostgreSQLResult; SQL: String; begin if (TransactIsolationLevel <> tiNone) and not Closed then begin SQL := 'COMMIT'; QueryHandle := GetPlainDriver.ExecuteQuery(FHandle, PAnsiChar(AnsiString(SQL))); CheckPostgreSQLError(nil, GetPlainDriver, FHandle, lcExecute, SQL,QueryHandle); GetPlainDriver.Clear(QueryHandle); DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, SQL); StartTransactionSupport; end; end; procedure TZPostgreSQLConnection.CommitPrepared(const transactionid: string); var QueryHandle: PZPostgreSQLResult; SQL: String; begin if (TransactIsolationLevel = tiNone) and not Closed then begin SQL := 'COMMIT PREPARED '''+copy(transactionid,1,200)+''''; QueryHandle := GetPlainDriver.ExecuteQuery(FHandle, PAnsiChar(AnsiString(SQL))); CheckPostgreSQLError(nil, GetPlainDriver, FHandle, lcExecute, SQL,QueryHandle); GetPlainDriver.Clear(QueryHandle); DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, SQL); StartTransactionSupport; end; end; {** Drops all changes made since the previous commit/rollback and releases any database locks currently held by this Connection. This method should be used only when auto- commit has been disabled. @see #setAutoCommit } procedure TZPostgreSQLConnection.Rollback; var QueryHandle: PZPostgreSQLResult; SQL: String; begin if (TransactIsolationLevel <> tiNone) and not Closed then begin SQL := 'ROLLBACK'; QueryHandle := GetPlainDriver.ExecuteQuery(FHandle, PAnsiChar(AnsiString(SQL))); CheckPostgreSQLError(nil, GetPlainDriver, FHandle, lcExecute, SQL,QueryHandle); GetPlainDriver.Clear(QueryHandle); DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, SQL); StartTransactionSupport; end; end; procedure TZPostgreSQLConnection.RollbackPrepared(const transactionid: string); var QueryHandle: PZPostgreSQLResult; SQL: string; begin if (TransactIsolationLevel = tiNone) and not Closed then begin SQL := 'ROLLBACK PREPARED '''+copy(transactionid,1,200)+''''; QueryHandle := GetPlainDriver.ExecuteQuery(FHandle, PAnsiChar(AnsiString(SQL))); CheckPostgreSQLError(nil, GetPlainDriver, FHandle, lcExecute, SQL,QueryHandle); GetPlainDriver.Clear(QueryHandle); DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, SQL); StartTransactionSupport; end; end; {** Releases a Connection's database and JDBC resources immediately instead of waiting for them to be automatically released.

Note: A Connection is automatically closed when it is garbage collected. Certain fatal errors also result in a closed Connection. } procedure TZPostgreSQLConnection.Close; var LogMessage: string; I: Integer; begin if ( Closed ) or (not Assigned(PlainDriver)) then Exit; for i := 0 to FPreparedStmts.Count -1 do begin LogMessage := 'DEALLOCATE "'+FPreparedStmts[i]+'";'; GetPlainDriver.ExecuteQuery(FHandle, Pointer(LogMessage)); end; FPreparedStmts.Clear; FTableInfoCache.Clear; GetPlainDriver.Finish(FHandle); FHandle := nil; LogMessage := Format('DISCONNECT FROM "%s"', [Database]); DriverManager.LogMessage(lcDisconnect, PlainDriver.GetProtocol, LogMessage); inherited Close; end; {** Sets a new transact isolation level. @param Level a new transact isolation level. } procedure TZPostgreSQLConnection.SetTransactionIsolation( Level: TZTransactIsolationLevel); var QueryHandle: PZPostgreSQLResult; SQL: String; begin if not (Level in [tiNone, tiReadCommitted, tiSerializable]) then raise EZSQLException.Create(SIsolationIsNotSupported); if (TransactIsolationLevel <> tiNone) and not Closed then begin SQL := 'END'; QueryHandle := GetPlainDriver.ExecuteQuery(FHandle, PAnsiChar(AnsiString(SQL))); CheckPostgreSQLError(nil, GetPlainDriver, FHandle, lcExecute, SQL,QueryHandle); GetPlainDriver.Clear(QueryHandle); DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, SQL); end; inherited SetTransactionIsolation(Level); if not Closed then StartTransactionSupport; end; {** Gets a reference to PostgreSQL connection handle. @return a reference to PostgreSQL connection handle. } function TZPostgreSQLConnection.GetConnectionHandle: PZPostgreSQLConnect; begin Result := FHandle; end; {** Gets a PostgreSQL plain driver interface. @return a PostgreSQL plain driver interface. } function TZPostgreSQLConnection.GetPlainDriver: IZPostgreSQLPlainDriver; begin Result := PlainDriver as IZPostgreSQLPlainDriver; end; {** Gets a type name by it's oid number. @param Id a type oid number. @return a type name or empty string if there was no such type found. } function TZPostgreSQLConnection.GetTypeNameByOid(Id: Oid): string; var I, Index: Integer; QueryHandle: PZPostgreSQLResult; SQL: PAnsiChar; TypeCode, BaseTypeCode: Integer; TypeName: string; LastVersion, IsEnum: boolean; begin if Closed then Open; if (GetServerMajorVersion < 7 ) or ((GetServerMajorVersion = 7) and (GetServerMinorVersion < 3)) then LastVersion := True else LastVersion := False; { Fill the list with existed types } if not Assigned(FTypeList) then begin if LastVersion then SQL := 'SELECT oid, typname FROM pg_type WHERE oid<10000' else SQL := 'SELECT oid, typname, typbasetype,typtype FROM pg_type' + ' WHERE (typtype = ''b'' and oid < 10000) OR typtype = ''p'' OR typtype = ''e'' OR typbasetype<>0 ORDER BY oid'; QueryHandle := GetPlainDriver.ExecuteQuery(FHandle, SQL); CheckPostgreSQLError(Self, GetPlainDriver, FHandle, lcExecute, String(SQL),QueryHandle); DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, String(SQL)); FTypeList := TStringList.Create; for I := 0 to GetPlainDriver.GetRowCount(QueryHandle)-1 do begin TypeCode := StrToIntDef(String( GetPlainDriver.GetValue(QueryHandle, I, 0)), 0); isEnum := LowerCase(String(GetPlainDriver.GetValue(QueryHandle, I, 3))) = 'e'; if isEnum then TypeName := 'enum' else TypeName := String(GetPlainDriver.GetValue(QueryHandle, I, 1)); if LastVersion then BaseTypeCode := 0 else BaseTypeCode := StrToIntDef(String( GetPlainDriver.GetValue(QueryHandle, I, 2)), 0); if BaseTypeCode <> 0 then begin Index := FTypeList.IndexOfObject(TObject(BaseTypeCode)); if Index >= 0 then TypeName := FTypeList[Index] else TypeName := ''; end; FTypeList.AddObject(TypeName, TObject(TypeCode)); end; GetPlainDriver.Clear(QueryHandle); end; I := FTypeList.IndexOfObject(TObject(Id)); if I >= 0 then Result := FTypeList[I] else Result := ''; end; {** Gets the host's full version number. Initially this should be 0. The format of the version returned must be XYYYZZZ where X = Major version YYY = Minor version ZZZ = Sub version @return this server's full version number } function TZPostgreSQLConnection.GetHostVersion: Integer; begin Result := GetServerMajorVersion*1000000+GetServerMinorversion*1000+GetServerSubversion; end; {** Gets a server major version. @return a server major version number. } function TZPostgreSQLConnection.GetServerMajorVersion: Integer; begin if (FServerMajorVersion = 0) and (FServerMinorVersion = 0) then LoadServerVersion; Result := FServerMajorVersion; end; {** Gets a server minor version. @return a server minor version number. } function TZPostgreSQLConnection.GetServerMinorVersion: Integer; begin if (FServerMajorVersion = 0) and (FServerMinorVersion = 0) then LoadServerVersion; Result := FServerMinorVersion; end; {** Gets a server sub version. @return a server sub version number. } function TZPostgreSQLConnection.GetServerSubVersion: Integer; begin if (FServerMajorVersion = 0) and (FServerMinorVersion = 0) then LoadServerVersion; Result := FServerSubVersion; end; {** Loads a server major and minor version numbers. } procedure TZPostgreSQLConnection.LoadServerVersion; var Temp: string; List: TStrings; QueryHandle: PZPostgreSQLResult; SQL: PAnsiChar; begin if Closed then Open; SQL := 'SELECT version()'; QueryHandle := GetPlainDriver.ExecuteQuery(FHandle, SQL); CheckPostgreSQLError(Self, GetPlainDriver, FHandle, lcExecute, String(SQL),QueryHandle); DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, String(SQL)); Temp := String(GetPlainDriver.GetValue(QueryHandle, 0, 0)); GetPlainDriver.Clear(QueryHandle); List := TStringList.Create; try { Splits string by space } PutSplitString(List, Temp, ' '); { first - PostgreSQL, second X.Y.Z} Temp := List.Strings[1]; { Splits string by dot } PutSplitString(List, Temp, '.'); FServerMajorVersion := StrToIntDef(List.Strings[0], 0); if List.Count > 1 then FServerMinorVersion := GetMinorVersion(List.Strings[1]) else FServerMinorVersion := 0; if List.Count > 2 then FServerSubVersion := GetMinorVersion(List.Strings[2]) else FServerSubVersion := 0; finally List.Free; end; end; {** Ping Current Connection's server, if client was disconnected, the connection is resumed. @return 0 if succesfull or error code if any error occurs } function TZPostgreSQLConnection.PingServer: Integer; const PING_ERROR_ZEOSCONNCLOSED = -1; var Closing: boolean; res: PZPostgreSQLResult; isset: boolean; begin Result := PING_ERROR_ZEOSCONNCLOSED; Closing := FHandle = nil; if Not(Closed or Closing) then begin res := GetPlainDriver.ExecuteQuery(FHandle,''); isset := assigned(res); GetPlainDriver.Clear(res); if isset and (GetPlainDriver.GetStatus(FHandle) = CONNECTION_OK) then Result := 0 else try GetPlainDriver.Reset(FHandle); res := GetPlainDriver.ExecuteQuery(FHandle,''); isset := assigned(res); GetPlainDriver.Clear(res); if isset and (GetPlainDriver.GetStatus(FHandle) = CONNECTION_OK) then Result := 0; except Result := 1; end; end; end; function TZPostgreSQLConnection.EscapeString(Value: RawByteString): RawByteString; begin Result := PlainDriver.EscapeString(Self.FHandle, Value, ConSettings) end; {** Creates a sequence generator object. @param Sequence a name of the sequence generator. @param BlockSize a number of unique keys requested in one trip to SQL server. @returns a created sequence object. } function TZPostgreSQLConnection.CreateSequence(const Sequence: string; BlockSize: Integer): IZSequence; begin Result := TZPostgreSQLSequence.Create(Self, Sequence, BlockSize); end; {** EgonHugeist: Returns the BinaryString in a Tokenizer-detectable kind If the Tokenizer don't need to predetect it Result = BinaryString @param Value represents the Binary-String @param EscapeMarkSequence represents a Tokenizer detectable EscapeSequence (Len >= 3) @result the detectable Binary String } function TZPostgreSQLConnection.GetBinaryEscapeString(const Value: RawByteString): String; begin Result := String(EncodeBinary(Value)); if GetAutoEncodeStrings then Result := GetDriver.GetTokenizer.GetEscapeString(Result); end; {** EgonHugeist: Returns the BinaryString in a Tokenizer-detectable kind If the Tokenizer don't need to predetect it Result = BinaryString @param Value represents the Binary-String @param EscapeMarkSequence represents a Tokenizer detectable EscapeSequence (Len >= 3) @result the detectable Binary String } function TZPostgreSQLConnection.GetBinaryEscapeString(const Value: TByteDynArray): String; var Tmp: RawByteString; begin ZSetString(PAnsiChar(Value), Length(Value), Tmp); Result := String(EncodeBinary(Tmp)); if GetAutoEncodeStrings then Result := GetDriver.GetTokenizer.GetEscapeString(Result); end; {** EgonHugeist: Returns a String in a Tokenizer-detectable kind If the Tokenizer don't need to predetect it Result = BinaryString @param Value represents the String @param EscapeMarkSequence represents a Tokenizer detectable EscapeSequence (Len >= 3) @result the detectable Postrgres-compatible String } function TZPostgreSQLConnection.GetEscapeString(const Value: ZWideString): ZWideString; begin Result := GetPlainDriver.EscapeString(FHandle, Value, ConSettings); if GetAutoEncodeStrings then Result := GetDriver.GetTokenizer.GetEscapeString(Result); end; function TZPostgreSQLConnection.GetEscapeString(const Value: RawByteString): RawByteString; begin Result := GetPlainDriver.EscapeString(FHandle, Value, ConSettings); {$IFNDEF UNICODE} if GetAutoEncodeStrings then Result := GetDriver.GetTokenizer.GetEscapeString(Result); {$ENDIF} end; {** Gets a current setting of run-time parameter. @param AName a parameter name. @result a parmeter value retrieved from server. } function TZPostgreSQLConnection.GetServerSetting(const AName: string): string; var SQL: string; QueryHandle: PZPostgreSQLResult; begin SQL := Format('select setting from pg_settings where name = %s', [AName]); QueryHandle := GetPlainDriver.ExecuteQuery(FHandle, PAnsiChar({$IFDEF UNICODE}AnsiString{$ENDIF}(SQL))); CheckPostgreSQLError(Self, GetPlainDriver, FHandle, lcExecute, SQL, QueryHandle); DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, SQL); Result := String(GetPlainDriver.GetValue(QueryHandle, 0, 0)); GetPlainDriver.Clear(QueryHandle); end; procedure TZPostgreSQLConnection.OnPropertiesChange(Sender: TObject); var SCS: string; begin inherited OnPropertiesChange(Sender); { Define standard_conforming_strings setting} SCS := Trim(Info.Values[standard_conforming_strings]); if SCS <> '' then SetStandardConformingStrings(UpperCase(SCS) = FON) else SetStandardConformingStrings(GetPlainDriver.GetStandardConformingStrings); end; {** Sets current setting of run-time parameter. String values should be already quoted. @param AName a parameter name. @param AValue a new parameter value. } procedure TZPostgreSQLConnection.SetServerSetting(const AName, AValue: string); var SQL: string; QueryHandle: PZPostgreSQLResult; begin SQL := Format('SET %s = %s', [AName, AValue]); QueryHandle := GetPlainDriver.ExecuteQuery(FHandle, PAnsiChar(AnsiString(SQL))); CheckPostgreSQLError(Self, GetPlainDriver, FHandle, lcExecute, SQL, QueryHandle); DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, SQL); GetPlainDriver.Clear(QueryHandle); end; {$IFDEF ZEOS_TEST_ONLY} constructor TZPostgreSQLConnection.Create(const ZUrl: TZURL); begin inherited Create(ZUrl); end; {$ENDIF} procedure TZPostgreSQLConnection.SetStandardConformingStrings(const Value: Boolean); begin FStandardConformingStrings := Value; ( Self.GetDriver.GetTokenizer as IZPostgreSQLTokenizer ).SetStandardConformingStrings(FStandardConformingStrings); end; { TZPostgreSQLSequence } {** Gets the current unique key generated by this sequence. @param the last generated unique key. } function TZPostgreSQLSequence.GetCurrentValue: Int64; var Statement: IZStatement; ResultSet: IZResultSet; begin Statement := Connection.CreateStatement; ResultSet := Statement.ExecuteQuery( Format('SELECT CURRVAL(''%s'')', [Name])); if ResultSet.Next then Result := ResultSet.GetLong(1) else Result := inherited GetCurrentValue; ResultSet.Close; Statement.Close; end; {** Gets the next unique key generated by this sequence. @param the next generated unique key. } function TZPostgreSQLSequence.GetCurrentValueSQL: String; begin result:=Format(' CURRVAL(''%s'') ', [Name]); end; function TZPostgreSQLSequence.GetNextValue: Int64; var Statement: IZStatement; ResultSet: IZResultSet; begin Statement := Connection.CreateStatement; ResultSet := Statement.ExecuteQuery( Format('SELECT NEXTVAL(''%s'')', [Name])); if ResultSet.Next then Result := ResultSet.GetLong(1) else Result := inherited GetNextValue; ResultSet.Close; Statement.Close; end; function TZPostgreSQLSequence.GetNextValueSQL: String; begin result:=Format(' NEXTVAL(''%s'') ', [Name]); end; initialization PostgreSQLDriver := TZPostgreSQLDriver.Create; DriverManager.RegisterDriver(PostgreSQLDriver); finalization if DriverManager <> nil then DriverManager.DeregisterDriver(PostgreSQLDriver); PostgreSQLDriver := nil; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcPostgreSqlMetadata.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { PostgreSQL Database Connectivity Classes } { } { Originally written by Sergey Seroukhov } { and Sergey Merkuriev } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcPostgreSqlMetadata; interface {$I ZDbc.inc} uses Types, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, ZSysUtils, ZDbcIntfs, ZDbcMetadata, ZCompatibility, ZDbcPostgreSqlUtils, ZDbcConnection, ZSelectSchema; type {** Implements a PostgreSQL Case Sensitive/Unsensitive identifier convertor. } TZPostgreSQLIdentifierConvertor = class (TZDefaultIdentifierConvertor) protected function IsSpecialCase(const Value: string): Boolean; override; public function IsQuoted(const Value: string): Boolean; override; function Quote(const Value: string): string; override; function ExtractQuote(const Value: string): string; override; end; {** Database information interface for PostgreSQL. Adds some PostgreSQL-specific methods to IZDatabaseInfo. } // technobot 2008-06-27 IZPostgreSQLDatabaseInfo = interface(IZDatabaseInfo) ['{7D48BBAA-FAE2-48EA-8B9E-663CCA5690EC}'] // database and driver info: function HasMinimumServerVersion(MajorVersion: Integer; MinorVersion: Integer): Boolean; end; IZPostgreDBInfo = IZPostgreSQLDatabaseInfo; // shorthand alias // technobot 2008-06-27 - methods moved as is from TZPostgreSQLDatabaseMetadata: {** Implements PostgreSQL Database Information. } TZPostgreSQLDatabaseInfo = class(TZAbstractDatabaseInfo, IZPostgreSQLDatabaseInfo) protected function GetMaxIndexKeys: Integer; function GetMaxNameLength: Integer; // function UncachedGetUDTs(const Catalog: string; const SchemaPattern: string; // const TypeNamePattern: string; const Types: TIntegerDynArray): IZResultSet; override; public constructor Create(const Metadata: TZAbstractDatabaseMetadata); destructor Destroy; override; // database/driver/server info: function GetDatabaseProductName: string; override; function GetDatabaseProductVersion: string; override; function GetDriverName: string; override; // function GetDriverVersion: string; override; -> Same as parent function GetDriverMajorVersion: Integer; override; function GetDriverMinorVersion: Integer; override; function GetServerVersion: string; function HasMinimumServerVersion(MajorVersion: Integer; MinorVersion: Integer): Boolean; // was TZPostgreSQLDatabaseMetadata.HaveMinimumServerVersion // capabilities (what it can/cannot do): // function AllProceduresAreCallable: Boolean; override; -> Not implemented // function AllTablesAreSelectable: Boolean; override; -> Not implemented function SupportsMixedCaseIdentifiers: Boolean; override; function SupportsMixedCaseQuotedIdentifiers: Boolean; override; // function SupportsAlterTableWithAddColumn: Boolean; override; -> Not implemented // function SupportsAlterTableWithDropColumn: Boolean; override; -> Not implemented // function SupportsColumnAliasing: Boolean; override; -> Not implemented // function SupportsConvert: Boolean; override; -> Not implemented // function SupportsConvertForTypes(FromType: TZSQLType; ToType: TZSQLType): // Boolean; override; -> Not implemented // function SupportsTableCorrelationNames: Boolean; override; -> Not implemented // function SupportsDifferentTableCorrelationNames: Boolean; override; -> Not implemented function SupportsExpressionsInOrderBy: Boolean; override; function SupportsOrderByUnrelated: Boolean; override; function SupportsGroupBy: Boolean; override; function SupportsGroupByUnrelated: Boolean; override; function SupportsGroupByBeyondSelect: Boolean; override; // function SupportsLikeEscapeClause: Boolean; override; -> Not implemented // function SupportsMultipleResultSets: Boolean; override; -> Not implemented // function SupportsMultipleTransactions: Boolean; override; -> Not implemented // function SupportsNonNullableColumns: Boolean; override; -> Not implemented // function SupportsMinimumSQLGrammar: Boolean; override; -> Not implemented // function SupportsCoreSQLGrammar: Boolean; override; -> Not implemented // function SupportsExtendedSQLGrammar: Boolean; override; -> Not implemented // function SupportsANSI92EntryLevelSQL: Boolean; override; -> Not implemented // function SupportsANSI92IntermediateSQL: Boolean; override; -> Not implemented // function SupportsANSI92FullSQL: Boolean; override; -> Not implemented function SupportsIntegrityEnhancementFacility: Boolean; override; // function SupportsOuterJoins: Boolean; override; -> Not implemented // function SupportsFullOuterJoins: Boolean; override; -> Not implemented // function SupportsLimitedOuterJoins: Boolean; override; -> Not implemented function SupportsSchemasInDataManipulation: Boolean; override; function SupportsSchemasInProcedureCalls: Boolean; override; function SupportsSchemasInTableDefinitions: Boolean; override; function SupportsSchemasInIndexDefinitions: Boolean; override; function SupportsSchemasInPrivilegeDefinitions: Boolean; override; function SupportsCatalogsInDataManipulation: Boolean; override; function SupportsCatalogsInProcedureCalls: Boolean; override; function SupportsCatalogsInTableDefinitions: Boolean; override; function SupportsCatalogsInIndexDefinitions: Boolean; override; function SupportsCatalogsInPrivilegeDefinitions: Boolean; override; function SupportsPositionedDelete: Boolean; override; function SupportsPositionedUpdate: Boolean; override; function SupportsSelectForUpdate: Boolean; override; function SupportsStoredProcedures: Boolean; override; function SupportsSubqueriesInComparisons: Boolean; override; function SupportsSubqueriesInExists: Boolean; override; function SupportsSubqueriesInIns: Boolean; override; function SupportsSubqueriesInQuantifieds: Boolean; override; function SupportsCorrelatedSubqueries: Boolean; override; function SupportsUnion: Boolean; override; function SupportsUnionAll: Boolean; override; function SupportsOpenCursorsAcrossCommit: Boolean; override; function SupportsOpenCursorsAcrossRollback: Boolean; override; function SupportsOpenStatementsAcrossCommit: Boolean; override; function SupportsOpenStatementsAcrossRollback: Boolean; override; function SupportsTransactions: Boolean; override; function SupportsTransactionIsolationLevel(Level: TZTransactIsolationLevel): Boolean; override; function SupportsDataDefinitionAndDataManipulationTransactions: Boolean; override; function SupportsDataManipulationTransactionsOnly: Boolean; override; function SupportsResultSetType(_Type: TZResultSetType): Boolean; override; function SupportsResultSetConcurrency(_Type: TZResultSetType; Concurrency: TZResultSetConcurrency): Boolean; override; // function SupportsBatchUpdates: Boolean; override; -> Not implemented // maxima: function GetMaxBinaryLiteralLength: Integer; override; function GetMaxCharLiteralLength: Integer; override; function GetMaxColumnNameLength: Integer; override; function GetMaxColumnsInGroupBy: Integer; override; function GetMaxColumnsInIndex: Integer; override; function GetMaxColumnsInOrderBy: Integer; override; function GetMaxColumnsInSelect: Integer; override; function GetMaxColumnsInTable: Integer; override; function GetMaxConnections: Integer; override; function GetMaxCursorNameLength: Integer; override; function GetMaxIndexLength: Integer; override; function GetMaxSchemaNameLength: Integer; override; function GetMaxProcedureNameLength: Integer; override; function GetMaxCatalogNameLength: Integer; override; function GetMaxRowSize: Integer; override; function GetMaxStatementLength: Integer; override; function GetMaxStatements: Integer; override; function GetMaxTableNameLength: Integer; override; function GetMaxTablesInSelect: Integer; override; function GetMaxUserNameLength: Integer; override; // policies (how are various data and operations handled): // function IsReadOnly: Boolean; override; -> Not implemented // function IsCatalogAtStart: Boolean; override; -> Not implemented function DoesMaxRowSizeIncludeBlobs: Boolean; override; // function NullsAreSortedHigh: Boolean; override; -> Not implemented // function NullsAreSortedLow: Boolean; override; -> Not implemented // function NullsAreSortedAtStart: Boolean; override; -> Not implemented // function NullsAreSortedAtEnd: Boolean; override; -> Not implemented // function NullPlusNonNullIsNull: Boolean; override; -> Not implemented // function UsesLocalFiles: Boolean; override; -> Not implemented function UsesLocalFilePerTable: Boolean; override; function StoresUpperCaseIdentifiers: Boolean; override; function StoresLowerCaseIdentifiers: Boolean; override; function StoresMixedCaseIdentifiers: Boolean; override; function StoresUpperCaseQuotedIdentifiers: Boolean; override; function StoresLowerCaseQuotedIdentifiers: Boolean; override; function StoresMixedCaseQuotedIdentifiers: Boolean; override; function GetDefaultTransactionIsolation: TZTransactIsolationLevel; override; function DataDefinitionCausesTransactionCommit: Boolean; override; function DataDefinitionIgnoredInTransactions: Boolean; override; // interface details (terms, keywords, etc): function GetSchemaTerm: string; override; function GetProcedureTerm: string; override; function GetCatalogTerm: string; override; function GetCatalogSeparator: string; override; function GetSQLKeywords: string; override; function GetNumericFunctions: string; override; function GetStringFunctions: string; override; function GetSystemFunctions: string; override; function GetTimeDateFunctions: string; override; function GetSearchStringEscape: string; override; function GetExtraNameCharacters: string; override; end; {** Implements PostgreSQL Database Metadata. } TZPostgreSQLDatabaseMetadata = class(TZAbstractDatabaseMetadata) private function GetRuleType(const Rule: String): TZImportedKey; protected function CreateDatabaseInfo: IZDatabaseInfo; override; // technobot 2008-06-27 // (technobot) should any of these be moved to TZPostgreSQLDatabaseInfo?: function GetPostgreSQLType(Oid: Integer): string; function GetSQLTypeByOid(Oid: Integer): TZSQLType; function GetSQLTypeByName(TypeName: string): TZSQLType; function TableTypeSQLExpression(TableType: string; UseSchemas: Boolean): string; procedure ParseACLArray(List: TStrings; AclString: string); function GetPrivilegeName(Permission: char): string; // (technobot) end of questioned section function EscapeString(const S: string): string; override; function UncachedGetTables(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const Types: TStringDynArray): IZResultSet; override; function UncachedGetSchemas: IZResultSet; override; function UncachedGetCatalogs: IZResultSet; override; function UncachedGetTableTypes: IZResultSet; override; function UncachedGetColumns(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const ColumnNamePattern: string): IZResultSet; override; function UncachedGetTablePrivileges(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string): IZResultSet; override; function UncachedGetColumnPrivileges(const Catalog: string; const Schema: string; const Table: string; const ColumnNamePattern: string): IZResultSet; override; function UncachedGetPrimaryKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; override; function UncachedGetImportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; override; function UncachedGetExportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; override; function UncachedGetCrossReference(const PrimaryCatalog: string; const PrimarySchema: string; const PrimaryTable: string; const ForeignCatalog: string; const ForeignSchema: string; const ForeignTable: string): IZResultSet; override; function UncachedGetIndexInfo(const Catalog: string; const Schema: string; const Table: string; Unique: Boolean; Approximate: Boolean): IZResultSet; override; function UncachedGetSequences(const Catalog: string; const SchemaPattern: string; const SequenceNamePattern: string): IZResultSet; override; function UncachedGetProcedures(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string): IZResultSet; override; function UncachedGetProcedureColumns(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string; const ColumnNamePattern: string): IZResultSet; override; function UncachedGetVersionColumns(const Catalog: string; const Schema: string; const Table: string): IZResultSet; override; function UncachedGetTypeInfo: IZResultSet; override; function UncachedGetCharacterSets: IZResultSet; override; //EgonHugeist public destructor Destroy; override; function GetIdentifierConvertor: IZIdentifierConvertor; override; end; implementation uses ZMessages, ZDbcUtils, ZDbcPostgreSql; { TZPostgreSQLDatabaseInfo } {** Constructs this object. @param Metadata the interface of the correpsonding database metadata object } constructor TZPostgreSQLDatabaseInfo.Create(const Metadata: TZAbstractDatabaseMetadata); begin inherited; end; {** Destroys this object and cleanups the memory. } destructor TZPostgreSQLDatabaseInfo.Destroy; begin inherited; end; //---------------------------------------------------------------------- // First, a variety of minor information about the target database. {** What's the name of this database product? @return database product name } function TZPostgreSQLDatabaseInfo.GetDatabaseProductName: string; begin Result := 'PostgreSQL'; end; {** What's the version of this database product? @return database version } function TZPostgreSQLDatabaseInfo.GetDatabaseProductVersion: string; begin Result := ''; end; {** What's the name of this JDBC driver? @return JDBC driver name } function TZPostgreSQLDatabaseInfo.GetDriverName: string; begin Result := 'Zeos Database Connectivity Driver for PostgreSQL'; end; {** What's this JDBC driver's major version number? @return JDBC driver major version } function TZPostgreSQLDatabaseInfo.GetDriverMajorVersion: Integer; begin Result := 1; end; {** What's this JDBC driver's minor version number? @return JDBC driver minor version number } function TZPostgreSQLDatabaseInfo.GetDriverMinorVersion: Integer; begin Result := 1; end; {** Returns the server version @return the server version string } function TZPostgreSQLDatabaseInfo.GetServerVersion: string; begin with Metadata.GetConnection as IZPostgreSQLConnection do Result := Format('%s.%s', [GetServerMajorVersion, GetServerMinorVersion]); end; {** Does the database use a file for each table? @return true if the database uses a local file for each table } function TZPostgreSQLDatabaseInfo.UsesLocalFilePerTable: Boolean; begin Result := False; end; {** Does the database treat mixed case unquoted SQL identifiers as case sensitive and as a result store them in mixed case? A JDBC CompliantTM driver will always return false. @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.SupportsMixedCaseIdentifiers: Boolean; begin Result := False; end; {** Does the database treat mixed case unquoted SQL identifiers as case insensitive and store them in upper case? @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.StoresUpperCaseIdentifiers: Boolean; begin Result := False; end; {** Does the database treat mixed case unquoted SQL identifiers as case insensitive and store them in lower case? @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.StoresLowerCaseIdentifiers: Boolean; begin Result := True; end; {** Does the database treat mixed case unquoted SQL identifiers as case insensitive and store them in mixed case? @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.StoresMixedCaseIdentifiers: Boolean; begin Result := False; end; {** Does the database treat mixed case quoted SQL identifiers as case sensitive and as a result store them in mixed case? A JDBC CompliantTM driver will always return true. @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.SupportsMixedCaseQuotedIdentifiers: Boolean; begin Result := True; end; {** Does the database treat mixed case quoted SQL identifiers as case insensitive and store them in upper case? @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.StoresUpperCaseQuotedIdentifiers: Boolean; begin Result := False; end; {** Does the database treat mixed case quoted SQL identifiers as case insensitive and store them in lower case? @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.StoresLowerCaseQuotedIdentifiers: Boolean; begin Result := False; end; {** Does the database treat mixed case quoted SQL identifiers as case insensitive and store them in mixed case? @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.StoresMixedCaseQuotedIdentifiers: Boolean; begin Result := True; end; {** Gets a comma-separated list of all a database's SQL keywords that are NOT also SQL92 keywords. @return the list } function TZPostgreSQLDatabaseInfo.GetSQLKeywords: string; begin Result := 'abort,absolute,access,action,add,admin,after,aggregate,all,also,'+ 'alter,always,analyse,analyze,and,any,array,asc,assertion,assignment,'+ 'asymmetric,at,authorization,'+ 'backward,before,begin,between,bigint,binary,bit,boolean,both,'+ 'cache,called,cascade,cascaded,case,cast,catalog,chain,character,'+ 'characteristics,check,checkpoint,class,close,cluster,coalesce,'+ 'collate,column,comment,commit,committed,concurrently,configuration,'+ 'connect,connection,constraint,constraints,content,continue,'+ 'conversion,convert,copy,cost,createdb,createrole,createuser,cross,'+ 'csv,current,current_catalog,current_date,current_role,current_schema,'+ 'current_time,current_timestamp,current_user,cursor,cycle,'+ 'data,database,day,deallocate,dec,decimal,declare,default,defaults,'+ 'deferrable,deferred,definer,delimiter,delimiters,desc,dictionary,'+ 'disable,discard,distinct,do,document,domain,double,'+ 'each,else,enable,encoding,encrypted,end,end-exec,enum,escape,except,'+ 'excluding,exclusive,exec,execute,exists,explain,external,extract,'+ 'false,family,fetch,first,float,following,for,force,foreign,forward,'+ 'freeze,full,function,'+ 'global,grant,granted,greatest,'+ 'handler,header,hold,hour,'+ 'identity,if,ilike,immediate,immutable,implicit,in,including,'+ 'increment,indexes,inherit,inherits,initially,inner,inout,input,'+ 'insensitive,instead,int,intersect,interval,invoker,isnull,isolation,'+ 'join,'+ 'lancompiler,language,large,last,lc_collate,lc_ctype,leading,least,'+ 'left,level,like,limit,listen,load,local,localtime,localtimestamp,'+ 'location,lock,login,'+ 'mapping,match,maxvalue,minute,minvalue,mode,month,move,'+ 'name,names,national,natural,nchar,new,next,no,nocreatedb,nocreaterole,'+ 'nocreateuser,noinherit,nologin,none,nosuperuser,not,nothing,notify,'+ 'notnull,nowait,nullif,nulls,numeric,'+ 'object,of,off,offset,oids,old,only,operator,option,options,or,out,'+ 'outer,over,overlaps,overlay,owned,owner,'+ 'parser,partial,partition,password,placing,plans,position,preceding,'+ 'precision,prepare,prepared,preserve,prior,privileges,procedural,'+ 'procedure,'+ 'quote,'+ 'range,read,real,reassign,recheck,recursive,references,reindex,'+ 'relative,release,rename,repeatable,replace,replica,reset,restart,'+ 'restrict,return,returning,returns,revoke,right,role,rollback,row,'+ 'rows,rule,'+ 'savepoint,schema,scroll,search,second,security,sequence,serializable,'+ 'server,session,session_user,setof,share,show,similar,simple,smallint,'+ 'some,stable,standalone,start,statement,statistics,stdin,stdout,'+ 'storage,strict,strip,substring,superuser,symmetric,sysid,system,'+ 'tablespace,temp,template,temporary,text,then,time,timestamp,to,'+ 'trailing,transaction,treat,trigger,trim,true,truncate,trusted,type,'+ 'unbounded,uncommitted,unencrypted,union,unique,unknown,unlisten,'+ 'until,user,using,'+ 'vacuum,valid,validator,value,variadic,varying,verbose,version,view,'+ 'volatile,'+ 'when,whitespace,window,with,without,work,wrapper,write,'+ 'xml,xmlattributes,xmlconcat,xmlelement,xmlforest,xmlparse,xmlpi,'+ 'xmlroot,xmlserialize,'+ 'year,yes,'+ 'zone'; end; {** Gets a comma-separated list of math functions. These are the X/Open CLI math function names used in the JDBC function escape clause. @return the list } function TZPostgreSQLDatabaseInfo.GetNumericFunctions: string; begin Result := ''; end; {** Gets a comma-separated list of string functions. These are the X/Open CLI string function names used in the JDBC function escape clause. @return the list } function TZPostgreSQLDatabaseInfo.GetStringFunctions: string; begin Result := ''; end; {** Gets a comma-separated list of system functions. These are the X/Open CLI system function names used in the JDBC function escape clause. @return the list } function TZPostgreSQLDatabaseInfo.GetSystemFunctions: string; begin Result := ''; end; {** Gets a comma-separated list of time and date functions. @return the list } function TZPostgreSQLDatabaseInfo.GetTimeDateFunctions: string; begin Result := ''; end; {** Gets the string that can be used to escape wildcard characters. This is the string that can be used to escape '_' or '%' in the string pattern style catalog search parameters.

The '_' character represents any single character.

The '%' character represents any sequence of zero or more characters. @return the string used to escape wildcard characters } function TZPostgreSQLDatabaseInfo.GetSearchStringEscape: string; begin Result := '\'; end; {** Gets all the "extra" characters that can be used in unquoted identifier names (those beyond a-z, A-Z, 0-9 and _). @return the string containing the extra characters } function TZPostgreSQLDatabaseInfo.GetExtraNameCharacters: string; begin Result := ''; end; //-------------------------------------------------------------------- // Functions describing which features are supported. {** Are expressions in "ORDER BY" lists supported? @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.SupportsExpressionsInOrderBy: Boolean; begin Result := True; end; {** Can an "ORDER BY" clause use columns not in the SELECT statement? @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.SupportsOrderByUnrelated: Boolean; begin Result := HasMinimumServerVersion(6, 4); end; {** Is some form of "GROUP BY" clause supported? @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.SupportsGroupBy: Boolean; begin Result := True; end; {** Can a "GROUP BY" clause use columns not in the SELECT? @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.SupportsGroupByUnrelated: Boolean; begin Result := HasMinimumServerVersion(6, 4); end; {** Can a "GROUP BY" clause add columns not in the SELECT provided it specifies all the columns in the SELECT? @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.SupportsGroupByBeyondSelect: Boolean; begin Result := HasMinimumServerVersion(6, 4); end; {** Is the SQL Integrity Enhancement Facility supported? @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.SupportsIntegrityEnhancementFacility: Boolean; begin Result := False; end; {** What's the database vendor's preferred term for "schema"? @return the vendor term } function TZPostgreSQLDatabaseInfo.GetSchemaTerm: string; begin Result := 'schema'; end; {** What's the database vendor's preferred term for "procedure"? @return the vendor term } function TZPostgreSQLDatabaseInfo.GetProcedureTerm: string; begin Result := 'function'; end; {** What's the database vendor's preferred term for "catalog"? @return the vendor term } function TZPostgreSQLDatabaseInfo.GetCatalogTerm: string; begin Result := 'database'; end; {** What's the separator between catalog and table name? @return the separator string } function TZPostgreSQLDatabaseInfo.GetCatalogSeparator: string; begin Result := '.'; end; {** Can a schema name be used in a data manipulation statement? @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.SupportsSchemasInDataManipulation: Boolean; begin Result := HasMinimumServerVersion(7, 3); end; {** Can a schema name be used in a procedure call statement? @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.SupportsSchemasInProcedureCalls: Boolean; begin Result := HasMinimumServerVersion(7, 3); end; {** Can a schema name be used in a table definition statement? @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.SupportsSchemasInTableDefinitions: Boolean; begin Result := HasMinimumServerVersion(7, 3); end; {** Can a schema name be used in an index definition statement? @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.SupportsSchemasInIndexDefinitions: Boolean; begin Result := HasMinimumServerVersion(7, 3); end; {** Can a schema name be used in a privilege definition statement? @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.SupportsSchemasInPrivilegeDefinitions: Boolean; begin Result := HasMinimumServerVersion(7, 3); end; {** Can a catalog name be used in a data manipulation statement? @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.SupportsCatalogsInDataManipulation: Boolean; begin Result := False; end; {** Can a catalog name be used in a procedure call statement? @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.SupportsCatalogsInProcedureCalls: Boolean; begin Result := HasMinimumServerVersion(7, 3); end; {** Can a catalog name be used in a table definition statement? @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.SupportsCatalogsInTableDefinitions: Boolean; begin Result := HasMinimumServerVersion(7, 3); end; {** Can a catalog name be used in an index definition statement? @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.SupportsCatalogsInIndexDefinitions: Boolean; begin Result := False; end; {** Can a catalog name be used in a privilege definition statement? @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.SupportsCatalogsInPrivilegeDefinitions: Boolean; begin Result := False; end; {** Is positioned DELETE supported? @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.SupportsPositionedDelete: Boolean; begin Result := False; end; {** Is positioned UPDATE supported? @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.SupportsPositionedUpdate: Boolean; begin Result := False; end; {** Is SELECT for UPDATE supported? @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.SupportsSelectForUpdate: Boolean; begin Result := HasMinimumServerVersion(6, 5); end; {** Are stored procedure calls using the stored procedure escape syntax supported? @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.SupportsStoredProcedures: Boolean; begin Result := False; end; {** Are subqueries in comparison expressions supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.SupportsSubqueriesInComparisons: Boolean; begin Result := True; end; {** Are subqueries in 'exists' expressions supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.SupportsSubqueriesInExists: Boolean; begin Result := True; end; {** Are subqueries in 'in' statements supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.SupportsSubqueriesInIns: Boolean; begin Result := True; end; {** Are subqueries in quantified expressions supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.SupportsSubqueriesInQuantifieds: Boolean; begin Result := True; end; {** Are correlated subqueries supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.SupportsCorrelatedSubqueries: Boolean; begin Result := HasMinimumServerVersion(7, 1); end; {** Is SQL UNION supported? @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.SupportsUnion: Boolean; begin Result := True; end; {** Is SQL UNION ALL supported? @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.SupportsUnionAll: Boolean; begin Result := HasMinimumServerVersion(7, 1); end; {** Can cursors remain open across commits? @return true if cursors always remain open; false if they might not remain open } function TZPostgreSQLDatabaseInfo.SupportsOpenCursorsAcrossCommit: Boolean; begin Result := False; end; {** Can cursors remain open across rollbacks? @return true if cursors always remain open; false if they might not remain open } function TZPostgreSQLDatabaseInfo.SupportsOpenCursorsAcrossRollback: Boolean; begin Result := False; end; {** Can statements remain open across commits? @return true if statements always remain open; false if they might not remain open } function TZPostgreSQLDatabaseInfo.SupportsOpenStatementsAcrossCommit: Boolean; begin Result := True; end; {** Can statements remain open across rollbacks? @return true if statements always remain open; false if they might not remain open } function TZPostgreSQLDatabaseInfo.SupportsOpenStatementsAcrossRollback: Boolean; begin Result := True; end; //---------------------------------------------------------------------- // The following group of methods exposes various limitations // based on the target database with the current driver. // Unless otherwise specified, a result of zero means there is no // limit, or the limit is not known. {** How many hex characters can you have in an inline binary literal? @return max binary literal length in hex characters; a result of zero means that there is no limit or the limit is not known } function TZPostgreSQLDatabaseInfo.GetMaxBinaryLiteralLength: Integer; begin Result := 0; end; {** What's the max length for a character literal? @return max literal length; a result of zero means that there is no limit or the limit is not known } function TZPostgreSQLDatabaseInfo.GetMaxCharLiteralLength: Integer; begin Result := 0; end; {** What's the limit on column name length? @return max column name length; a result of zero means that there is no limit or the limit is not known } function TZPostgreSQLDatabaseInfo.GetMaxColumnNameLength: Integer; begin Result := GetMaxNameLength; end; {** What's the maximum number of columns in a "GROUP BY" clause? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZPostgreSQLDatabaseInfo.GetMaxColumnsInGroupBy: Integer; begin Result := 0; end; {** What's the maximum number of columns allowed in an index? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZPostgreSQLDatabaseInfo.GetMaxColumnsInIndex: Integer; begin Result := GetMaxIndexKeys; end; {** What's the maximum number of columns in an "ORDER BY" clause? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZPostgreSQLDatabaseInfo.GetMaxColumnsInOrderBy: Integer; begin Result := 0; end; {** What's the maximum number of columns in a "SELECT" list? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZPostgreSQLDatabaseInfo.GetMaxColumnsInSelect: Integer; begin Result := 0; end; {** What's the maximum number of columns in a table? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZPostgreSQLDatabaseInfo.GetMaxColumnsInTable: Integer; begin Result := 1600; end; {** How many active connections can we have at a time to this database? @return max number of active connections; a result of zero means that there is no limit or the limit is not known } function TZPostgreSQLDatabaseInfo.GetMaxConnections: Integer; begin Result := 8192; end; {** What's the maximum cursor name length? @return max cursor name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZPostgreSQLDatabaseInfo.GetMaxCursorNameLength: Integer; begin Result := GetMaxNameLength; end; {** Retrieves the maximum number of bytes for an index, including all of the parts of the index. @return max index length in bytes, which includes the composite of all the constituent parts of the index; a result of zero means that there is no limit or the limit is not known } function TZPostgreSQLDatabaseInfo.GetMaxIndexLength: Integer; begin Result := 0; end; {** What's the maximum length allowed for a schema name? @return max name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZPostgreSQLDatabaseInfo.GetMaxSchemaNameLength: Integer; begin Result := GetMaxNameLength; end; {** What's the maximum length of a procedure name? @return max name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZPostgreSQLDatabaseInfo.GetMaxProcedureNameLength: Integer; begin Result := GetMaxNameLength; end; {** What's the maximum length of a catalog name? @return max name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZPostgreSQLDatabaseInfo.GetMaxCatalogNameLength: Integer; begin Result := GetMaxNameLength; end; {** What's the maximum length of a single row? @return max row size in bytes; a result of zero means that there is no limit or the limit is not known } function TZPostgreSQLDatabaseInfo.GetMaxRowSize: Integer; begin if HasMinimumServerVersion(7, 1) then Result := 1073741824 else Result := 8192; end; {** Did getMaxRowSize() include LONGVARCHAR and LONGVARBINARY blobs? @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.DoesMaxRowSizeIncludeBlobs: Boolean; begin Result := True; end; {** What's the maximum length of an SQL statement? @return max length in bytes; a result of zero means that there is no limit or the limit is not known } function TZPostgreSQLDatabaseInfo.GetMaxStatementLength: Integer; begin if HasMinimumServerVersion(7, 0) then Result := 0 else Result := 16348 end; {** How many active statements can we have open at one time to this database? @return the maximum number of statements that can be open at one time; a result of zero means that there is no limit or the limit is not known } function TZPostgreSQLDatabaseInfo.GetMaxStatements: Integer; begin Result := 1; end; {** What's the maximum length of a table name? @return max name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZPostgreSQLDatabaseInfo.GetMaxTableNameLength: Integer; begin Result := GetMaxNameLength; end; {** What's the maximum number of tables in a SELECT statement? @return the maximum number of tables allowed in a SELECT statement; a result of zero means that there is no limit or the limit is not known } function TZPostgreSQLDatabaseInfo.GetMaxTablesInSelect: Integer; begin Result := 0; end; {** What's the maximum length of a user name? @return max user name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZPostgreSQLDatabaseInfo.GetMaxUserNameLength: Integer; begin Result := GetMaxNameLength; end; //---------------------------------------------------------------------- {** What's the database's default transaction isolation level? The values are defined in java.sql.Connection. @return the default isolation level @see Connection } function TZPostgreSQLDatabaseInfo.GetDefaultTransactionIsolation: TZTransactIsolationLevel; begin Result := tiReadCommitted; end; {** Are transactions supported? If not, invoking the method commit is a noop and the isolation level is TRANSACTION_NONE. @return true if transactions are supported; false otherwise } function TZPostgreSQLDatabaseInfo.SupportsTransactions: Boolean; begin Result := True; end; {** Does this database support the given transaction isolation level? @param level the values are defined in java.sql.Connection @return true if so; false otherwise @see Connection } function TZPostgreSQLDatabaseInfo.SupportsTransactionIsolationLevel( Level: TZTransactIsolationLevel): Boolean; begin Result := (Level = tiSerializable) or (Level = tiReadCommitted); end; {** Are both data definition and data manipulation statements within a transaction supported? @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo. SupportsDataDefinitionAndDataManipulationTransactions: Boolean; begin Result := True; end; {** Are only data manipulation statements within a transaction supported? @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo. SupportsDataManipulationTransactionsOnly: Boolean; begin Result := False; end; {** Does a data definition statement within a transaction force the transaction to commit? @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.DataDefinitionCausesTransactionCommit: Boolean; begin Result := False; end; {** Is a data definition statement within a transaction ignored? @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.DataDefinitionIgnoredInTransactions: Boolean; begin Result := False; end; {** Does the database support the given result set type? @param type defined in java.sql.ResultSet @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.SupportsResultSetType( _Type: TZResultSetType): Boolean; begin Result := _Type = rtScrollInsensitive; end; {** Does the database support the concurrency type in combination with the given result set type? @param type defined in java.sql.ResultSet @param concurrency type defined in java.sql.ResultSet @return true if so; false otherwise } function TZPostgreSQLDatabaseInfo.SupportsResultSetConcurrency( _Type: TZResultSetType; Concurrency: TZResultSetConcurrency): Boolean; begin Result := (_Type = rtScrollInsensitive) and (Concurrency = rcReadOnly); end; //---------------------------------------------------------------------- // Additional functions. function TZPostgreSQLDatabaseInfo.HasMinimumServerVersion( MajorVersion: Integer; MinorVersion: Integer): Boolean; var PostgreSQLConnection: IZPostgreSQLConnection; begin PostgreSQLConnection := Metadata.GetConnection as IZPostgreSQLConnection; Result := (MajorVersion < PostgreSQLConnection.GetServerMajorVersion) or ((MajorVersion = PostgreSQLConnection.GetServerMajorVersion) and (MinorVersion <= PostgreSQLConnection.GetServerMinorVersion)); end; function TZPostgreSQLDatabaseInfo.GetMaxIndexKeys: Integer; var SQL, From: string; begin if HasMinimumServerVersion(7, 3) then begin From := ' pg_catalog.pg_namespace n, pg_catalog.pg_type t1,' + ' pg_catalog.pg_type t2 WHERE t1.typnamespace=n.oid' + ' AND n.nspname=''pg_catalog'' AND '; end else From := ' pg_type t1, pg_type t2 WHERE '; SQL := ' SELECT t1.typlen/t2.typlen FROM ' + From + ' t1.typelem=t2.oid AND t1.typname=''oidvector'' '; with Metadata.GetConnection.CreateStatement.ExecuteQuery(SQL) do begin if not Next then raise Exception.Create(SUnknownError); //CHANGE IT! Result := GetInt(1); Close; end; end; function TZPostgreSQLDatabaseInfo.GetMaxNameLength: Integer; var SQL: string; begin if HasMinimumServerVersion(7, 3) then begin SQL := ' SELECT t.typlen FROM pg_catalog.pg_type t,' + ' pg_catalog.pg_namespace n WHERE t.typnamespace=n.oid' + ' AND t.typname=''name'' AND n.nspname=''pg_catalog'' '; end else SQL := ' SELECT typlen FROM pg_type WHERE typname=''name'' '; with Metadata.GetConnection.CreateStatement.ExecuteQuery(SQL) do begin if not Next then raise Exception.Create(SUnknownError); //CHANGE IT! Result := GetIntByName('typlen'); Close; end; end; { TZPostgreSQLDatabaseMetadata } {** Destroys this object and cleanups the memory. } destructor TZPostgreSQLDatabaseMetadata.Destroy; begin inherited Destroy; end; {** Constructs a database information object and returns the interface to it. Used internally by the constructor. @return the database information object interface } function TZPostgreSQLDatabaseMetadata.CreateDatabaseInfo: IZDatabaseInfo; begin Result := TZPostgreSQLDatabaseInfo.Create(Self); end; {** @param S a string. @return escaped string } function TZPostgreSQLDatabaseMetadata.EscapeString(const S: string): string; var I: Integer; begin Result := S; for I := Length(Result) downto 1 do if (Result[I] = '''') or (Result[I] = '\') then Insert('\', Result, I); Result := '''' + Result + ''''; if (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(8, 1) then Result := 'E' + Result; end; function TZPostgreSQLDatabaseMetadata.GetRuleType(const Rule: String): TZImportedKey; begin if Rule = 'RESTRICT' then Result := ikRestrict else if Rule = 'NO ACTION' then Result := ikNoAction else if Rule = 'CASCADE' then Result := ikCascade else if Rule = 'SET DEFAULT' then Result := ikSetDefault else if Rule = 'SET NULL' then Result := ikSetNull else Result := ikNotDeferrable; //impossible! end; {** Gets a description of the stored procedures available in a catalog.

Only procedure descriptions matching the schema and procedure name criteria are returned. They are ordered by PROCEDURE_SCHEM, and PROCEDURE_NAME.

Each procedure description has the the following columns:

  1. PROCEDURE_CAT String => procedure catalog (may be null)
  2. PROCEDURE_SCHEM String => procedure schema (may be null)
  3. PROCEDURE_NAME String => procedure name
  4. reserved for future use
  5. reserved for future use
  6. reserved for future use
  7. REMARKS String => explanatory comment on the procedure
  8. PROCEDURE_TYPE short => kind of procedure:
    • procedureResultUnknown - May return a result
    • procedureNoResult - Does not return a result
    • procedureReturnsResult - Returns a result
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param procedureNamePattern a procedure name pattern @return ResultSet - each row is a procedure description @see #getSearchStringEscape } function TZPostgreSQLDatabaseMetadata.UncachedGetProcedures(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string): IZResultSet; var SQL, ProcedureCondition, SchemaCondition: string; begin SchemaCondition := ConstructNameCondition(SchemaPattern,'n.nspname'); ProcedureCondition := ConstructNameCondition(ProcedureNamePattern,'p.proname'); if (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(7, 3) then begin SQL := 'SELECT NULL AS PROCEDURE_CAT, n.nspname AS PROCEDURE_SCHEM,' + ' p.proname AS PROCEDURE_NAME, NULL AS RESERVED1, NULL AS RESERVED2,' + ' NULL AS RESERVED3, d.description AS REMARKS, ' + IntToStr(ProcedureReturnsResult) + ' AS PROCEDURE_TYPE ' + ' FROM pg_catalog.pg_namespace n, pg_catalog.pg_proc p ' + ' LEFT JOIN pg_catalog.pg_description d ON (p.oid=d.objoid) ' + ' LEFT JOIN pg_catalog.pg_class c ON (d.classoid=c.oid AND' + ' c.relname=''pg_proc'') LEFT JOIN pg_catalog.pg_namespace pn ON' + ' (c.relnamespace=pn.oid AND pn.nspname=''pg_catalog'') ' + ' WHERE p.pronamespace=n.oid'; if SchemaCondition <> '' then SQL := SQL + ' AND ' + Schemacondition; if ProcedureCondition <> '' then SQL := SQL + ' AND ' + ProcedureCondition; SQL := SQL + ' ORDER BY PROCEDURE_SCHEM, PROCEDURE_NAME'; end else begin SQL := 'SELECT NULL AS PROCEDURE_CAT, NULL AS PROCEDURE_SCHEM,' + ' p.proname AS PROCEDURE_NAME, NULL AS RESERVED1, NULL AS RESERVED2,' + ' NULL AS RESERVED3, NULL AS REMARKS, ' + IntToStr(ProcedureReturnsResult) + ' AS PROCEDURE_TYPE' + ' FROM pg_proc p'; if ProcedureCondition <> '' then SQL := SQL + ' WHERE ' + ProcedureCondition; SQL := SQL + ' ORDER BY PROCEDURE_NAME'; end; Result := CopyToVirtualResultSet( GetConnection.CreateStatement.ExecuteQuery(SQL), ConstructVirtualResultSet(ProceduresColumnsDynArray)); end; {** Gets a description of a catalog's stored procedure parameters and result columns.

Only descriptions matching the schema, procedure and parameter name criteria are returned. They are ordered by PROCEDURE_SCHEM and PROCEDURE_NAME. Within this, the return value, if any, is first. Next are the parameter descriptions in call order. The column descriptions follow in column number order.

Each row in the ResultSet is a parameter description or column description with the following fields:

  1. PROCEDURE_CAT String => procedure catalog (may be null)
  2. PROCEDURE_SCHEM String => procedure schema (may be null)
  3. PROCEDURE_NAME String => procedure name
  4. COLUMN_NAME String => column/parameter name
  5. COLUMN_TYPE Short => kind of column/parameter:
    • procedureColumnUnknown - nobody knows
    • procedureColumnIn - IN parameter
    • procedureColumnInOut - INOUT parameter
    • procedureColumnOut - OUT parameter
    • procedureColumnReturn - procedure return value
    • procedureColumnResult - result column in ResultSet
  6. DATA_TYPE short => SQL type from java.sql.Types
  7. TYPE_NAME String => SQL type name, for a UDT type the type name is fully qualified
  8. PRECISION int => precision
  9. LENGTH int => length in bytes of data
  10. SCALE short => scale
  11. RADIX short => radix
  12. NULLABLE short => can it contain NULL?
    • procedureNoNulls - does not allow NULL values
    • procedureNullable - allows NULL values
    • procedureNullableUnknown - nullability unknown
  13. REMARKS String => comment describing parameter/column

Note: Some databases may not return the column descriptions for a procedure. Additional columns beyond REMARKS can be defined by the database. @param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param procedureNamePattern a procedure name pattern @param columnNamePattern a column name pattern @return ResultSet - each row describes a stored procedure parameter or column @see #getSearchStringEscape } function TZPostgreSQLDatabaseMetadata.UncachedGetProcedureColumns(const Catalog: string; const SchemaPattern: string; const ProcedureNamePattern: string; const ColumnNamePattern: string): IZResultSet; procedure InsertProcedureColumnRow(AResultSet: IZResultSet; const ASchema, AProcedureName, AColumnName: string; const AColumnType, ADataType: integer; const ATypeName: string; const ANullable: integer); begin AResultSet.MoveToInsertRow; AResultSet.UpdateNullByName('PROCEDURE_CAT'); AResultSet.UpdateStringByName('PROCEDURE_SCHEM', ASchema); AResultSet.UpdateStringByName('PROCEDURE_NAME', AProcedureName); AResultSet.UpdateStringByName('COLUMN_NAME', AColumnName); AResultSet.UpdateIntByName('COLUMN_TYPE', AColumnType); AResultSet.UpdateIntByName('DATA_TYPE', ADataType); AResultSet.UpdateStringByName('TYPE_NAME', ATypeName); AResultSet.UpdateNullByName('PRECISION'); AResultSet.UpdateNullByName('LENGTH'); AResultSet.UpdateNullByName('SCALE'); AResultSet.UpdateNullByName('RADIX'); AResultSet.UpdateIntByName('NULLABLE', ANullable); AResultSet.UpdateNullByName('REMARKS'); AResultSet.InsertRow; end; var I, ReturnType, ColumnTypeOid, ArgOid: Integer; SQL, ReturnTypeType: string; IsInParam, IsOutParam: Boolean; ArgTypes, ArgNames, ArgModes: TStrings; Ver73Up, Ver80Up: Boolean; ResultSet: IZResultSet; ColumnsRS: IZResultSet; ArgMode: Char; OutParamCount: Integer; ColumnName: string; ColumnType: Integer; ProcedureCondition, SchemaCondition: string; begin SchemaCondition := ConstructNameCondition(SchemaPattern,'n.nspname'); ProcedureCondition := ConstructNameCondition(ProcedureNamePattern,'p.proname'); Result := inherited UncachedGetProcedureColumns(Catalog, SchemaPattern, ProcedureNamePattern, ColumnNamePattern); Ver80Up := (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(8, 0); Ver73Up := Ver80Up or (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(7, 3); if Ver80Up then begin SQL := 'SELECT n.nspname,p.proname,p.prorettype,p.proargtypes,t.typtype,' + 'p.proallargtypes,p.proargnames,p.proargmodes,t.typrelid ' + 'FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n, pg_catalog.pg_type t ' + 'WHERE p.pronamespace=n.oid AND p.prorettype=t.oid'; if SchemaPattern <> '' then SQL := SQL + ' AND ' + SchemaCondition; if ProcedureNamePattern <> '' then SQL := SQL + ' AND ' + ProcedureCondition; SQL := SQL + ' ORDER BY n.nspname, p.proname'; end else if Ver73Up then begin SQL := 'SELECT n.nspname,p.proname,p.prorettype,p.proargtypes,t.typtype,' + 'NULL AS proallargtypes,NULL AS proargnames,NULL AS proargnames,t.typrelid ' + 'FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n,' + ' pg_catalog.pg_type t WHERE p.pronamespace=n.oid AND p.prorettype=t.oid'; if SchemaPattern <> '' then SQL := SQL + ' AND ' + SchemaCondition; if ProcedureNamePattern <> '' then SQL := SQL + ' AND ' + ProcedureCondition; SQL := SQL + ' ORDER BY n.nspname, p.proname'; end else begin SQL := 'SELECT NULL AS nspname,p.proname,p.prorettype,p.proargtypes,' + ' NULL AS proallargtypes,NULL AS proargnames,NULL AS proargnames,t.typtype,t.typrelid' + ' FROM pg_proc p, pg_type t' + ' WHERE p.prorettype=t.oid'; if ProcedureNamePattern <> '' then SQL := SQL + ' AND ' + ProcedureCondition; SQL := SQL + ' ORDER BY p.proname'; end; ArgTypes := TStringList.Create; ArgNames := TStringList.Create; ArgModes := TStringList.Create; try ResultSet := GetConnection.CreateStatement.ExecuteQuery(SQL); //FirmOS Patch with ResultSet do begin while Next do begin ReturnType := StrToInt(GetStringByName('prorettype')); ReturnTypeType := GetStringByName('typtype'); ArgTypes.Clear; ArgNames.Clear; ArgModes.Clear; if (IsNullByName('proallargtypes')) then PutSplitString(ArgTypes, GetStringByName('proargtypes'), #10#13#9' ') else ParseACLArray(ArgTypes, GetStringByName('proallargtypes')); ParseACLArray(ArgNames, GetStringByName('proargnames')); ParseACLArray(ArgModes, GetStringByName('proargmodes')); OutParamCount := 0; for I := 0 to ArgTypes.Count - 1 do begin IsInParam := True; IsOutParam := False; if ArgModes.Count > I then begin ArgMode := ArgModes[I][1]; IsInParam := CharInSet(ArgMode, ['i', 'b', 'v']); IsOutParam := CharInSet(ArgMode, ['o', 'b', 't']); end; if IsOutParam then Inc(OutParamCount); // column name ArgOid := StrToInt(ArgTypes.Strings[i]); if ArgNames.Count > I then ColumnName := ArgNames.Strings[I] else ColumnName := '$' + IntToStr(I + 1); // column type if IsInParam then begin if IsOutParam then ColumnType := Ord(pctInOut) else ColumnType := Ord(pctIn); end else begin if IsOutParam then ColumnType := Ord(pctOut) else ColumnType := Ord(pctUnknown); end; InsertProcedureColumnRow(Result, GetStringByName('nspname'), GetStringByName('proname'), ColumnName, ColumnType, Ord(GetSQLTypeByOid(ArgOid)), GetPostgreSQLType(ArgOid), Ord(ntNullableUnknown)); end; if (OutParamCount > 0) then Continue; if (ReturnTypeType = 'c') then // Extract composit type columns begin ColumnsRS := GetConnection.CreateStatement.ExecuteQuery( Format('SELECT a.attname,a.atttypid' + ' FROM pg_catalog.pg_attribute a WHERE a.attrelid=%s' + ' ORDER BY a.attnum', [ResultSet.GetStringByName('typrelid')])); while ColumnsRS.Next do begin ColumnTypeOid := ColumnsRS.GetIntByName('atttypid'); InsertProcedureColumnRow(Result, GetStringByName('nspname'), GetStringByName('proname'), ColumnsRS.GetStringByName('attname'), Ord(pctResultSet), Ord(GetSQLTypeByOid(ColumnTypeOid)), GetPostgreSQLType(ColumnTypeOid), Ord(ntNullableUnknown)); end; ColumnsRS.Close; end else begin if (ReturnTypeType <> 'p') then // Single non-pseudotype return value begin InsertProcedureColumnRow(Result, GetStringByName('nspname'), GetStringByName('proname'), 'returnValue', Ord(pctReturn), Ord(GetSQLTypeByOid(ReturnType)), GetPostgreSQLType(ReturnType), Ord(ntNullableUnknown)); end; end; end; Close; end; finally ArgTypes.Free; ArgNames.Free; ArgModes.Free; end; end; {** Gets a description of tables available in a catalog.

Only table descriptions matching the catalog, schema, table name and type criteria are returned. They are ordered by TABLE_TYPE, TABLE_SCHEM and TABLE_NAME.

Each table description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. TABLE_TYPE String => table type. Typical types are "TABLE", "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM".
  5. REMARKS String => explanatory comment on the table

Note: Some databases may not return information for all tables. @param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param tableNamePattern a table name pattern @param types a list of table types to include; null returns all types @return ResultSet - each row is a table description @see #getSearchStringEscape } function TZPostgreSQLDatabaseMetadata.UncachedGetTables(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const Types: TStringDynArray): IZResultSet; var I: Integer; TableType, OrderBy, SQL: string; UseSchemas: Boolean; LTypes: TStringDynArray; TableNameCondition, SchemaCondition: string; begin SchemaCondition := ConstructNameCondition(SchemaPattern,'n.nspname'); TableNameCondition := ConstructNameCondition(TableNamePattern,'c.relname'); UseSchemas := True; if (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(7, 3) then begin SQL := ' SELECT NULL AS TABLE_CAT, n.nspname AS TABLE_SCHEM,' + ' c.relname AS TABLE_NAME, ' + ' CASE (n.nspname LIKE ''pg\\_%'')' + ' OR (n.nspname=''information_schema'')' + ' WHEN true THEN CASE n.nspname ' + ' WHEN ''pg_catalog'' THEN CASE c.relkind ' + ' WHEN ''r'' THEN ''SYSTEM TABLE''' + ' WHEN ''v'' THEN ''SYSTEM VIEW'' ' + ' WHEN ''i'' THEN ''SYSTEM INDEX'' ' + ' ELSE NULL ' + ' END ' + ' WHEN ''information_schema'' THEN CASE c.relkind ' + ' WHEN ''r'' THEN ''SYSTEM TABLE''' + ' WHEN ''v'' THEN ''SYSTEM VIEW'' ' + ' WHEN ''i'' THEN ''SYSTEM INDEX'' ' + ' ELSE NULL ' + ' END ' + ' WHEN ''pg_toast'' THEN CASE c.relkind ' + ' WHEN ''r'' THEN ''SYSTEM TOAST TABLE'' ' + ' WHEN ''i'' THEN ''SYSTEM TOAST INDEX'' ' + ' ELSE NULL ' + ' END ' + ' ELSE CASE c.relkind ' + ' WHEN ''r'' THEN ''TEMPORARY TABLE'' ' + ' WHEN ''i'' THEN ''TEMPORARY INDEX'' ' + ' ELSE NULL ' + ' END ' + ' END ' + ' WHEN false THEN CASE c.relkind ' + ' WHEN ''r'' THEN ''TABLE'' ' + ' WHEN ''i'' THEN ''INDEX'' ' + ' WHEN ''S'' THEN ''SEQUENCE'' ' + ' WHEN ''v'' THEN ''VIEW'' ' + ' ELSE NULL ' + ' END ' + ' ELSE NULL ' + ' END ' + ' AS TABLE_TYPE, d.description AS REMARKS ' + ' FROM pg_catalog.pg_namespace n, pg_catalog.pg_class c ' + ' LEFT JOIN pg_catalog.pg_description d' + ' ON (c.oid = d.objoid AND d.objsubid = 0) ' + ' LEFT JOIN pg_catalog.pg_class dc ON (d.classoid=dc.oid' + ' AND dc.relname=''pg_class'') LEFT JOIN pg_catalog.pg_namespace dn' + ' ON (dn.oid=dc.relnamespace AND dn.nspname=''pg_catalog'') ' + ' WHERE c.relnamespace = n.oid '; if SchemaPattern <> '' then begin SQL := SQL + ' AND ' + SchemaCondition; end; OrderBy := ' ORDER BY TABLE_TYPE,TABLE_SCHEM,TABLE_NAME'; end else begin UseSchemas := False; TableType := ' CASE c.relname LIKE ''pg\\_%'' ' + 'WHEN true THEN CASE c.relname LIKE ''pg\\_toast\\_%'' ' + 'WHEN true THEN CASE c.relkind ' + ' WHEN ''r'' THEN ''SYSTEM TOAST TABLE'' ' + ' WHEN ''i'' THEN ''SYSTEM TOAST INDEX'' ' + ' ELSE NULL ' + 'END ' + 'WHEN false THEN CASE c.relname LIKE ''pg\\_temp\\_%'' ' + ' WHEN true THEN CASE c.relkind ' + ' WHEN ''r'' THEN ''TEMPORARY TABLE'' ' + ' WHEN ''i'' THEN ''TEMPORARY INDEX'' ' + ' ELSE NULL ' + ' END ' + ' WHEN false THEN CASE c.relkind ' + ' WHEN ''r'' THEN ''SYSTEM TABLE'' ' + ' WHEN ''v'' THEN ''SYSTEM VIEW'' ' + ' WHEN ''i'' THEN ''SYSTEM INDEX'' ' + ' ELSE NULL ' + ' END ' + ' ELSE NULL ' + 'END ' + 'ELSE NULL ' + 'END ' + 'WHEN false THEN CASE c.relkind ' + ' WHEN ''r'' THEN ''TABLE'' ' + ' WHEN ''i'' THEN ''INDEX'' ' + ' WHEN ''S'' THEN ''SEQUENCE'' ' + ' WHEN ''v'' THEN ''VIEW'' ' + ' ELSE NULL ' + 'END ' + 'ELSE NULL ' + ' END '; OrderBy := ' ORDER BY TABLE_TYPE,TABLE_NAME '; SQL := 'SELECT NULL AS TABLE_CAT, NULL AS TABLE_SCHEM,' + ' c.relname AS TABLE_NAME, ' + TableType + ' AS TABLE_TYPE,' + ' NULL AS REMARKS FROM pg_class c WHERE true '; end; if (Types = nil) or (Length(Types) = 0) then begin SetLength(LTypes, 3); // SetLength(LTypes, 6); LTypes[0] := 'TABLE'; LTypes[1] := 'VIEW'; LTypes[2] := 'TEMPORARY TABLE'; // LTypes[3] := 'SYSTEM TABLE'; // LTypes[4] := 'SYSTEM TOAST TABLE'; // LTypes[5] := 'SYSTEM VIEW'; end else LTypes := Types; If TableNameCondition <> '' then SQL := SQL + ' AND ' + TableNameCondition; SQL := SQL + ' AND (false'; for I := 0 to High(LTypes) do SQL := SQL + ' OR (' + TableTypeSQLExpression(LTypes[i], UseSchemas) + ')'; SQL := SQL + ')' + OrderBy; Result := CopyToVirtualResultSet( GetConnection.CreateStatement.ExecuteQuery(SQL), ConstructVirtualResultSet(TableColumnsDynArray)); end; {** Gets the schema names available in this database. The results are ordered by schema name.

The schema column is:

  1. TABLE_SCHEM String => schema name
@return ResultSet - each row has a single String column that is a schema name } function TZPostgreSQLDatabaseMetadata.UncachedGetSchemas: IZResultSet; var SQL: string; begin if (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(7, 3) then begin SQL := 'SELECT nspname AS TABLE_SCHEM FROM pg_catalog.pg_namespace' + ' WHERE nspname <> ''pg_toast'' AND nspname NOT' + ' LIKE ''pg\\_temp\\_%'' ORDER BY TABLE_SCHEM'; end else SQL := 'SELECT ''''::text AS TABLE_SCHEM ORDER BY TABLE_SCHEM'; Result := CopyToVirtualResultSet( GetConnection.CreateStatement.ExecuteQuery(SQL), ConstructVirtualResultSet(SchemaColumnsDynArray)); end; {** Gets the catalog names available in this database. The results are ordered by catalog name.

The catalog column is:

  1. TABLE_CAT String => catalog name
@return ResultSet - each row has a single String column that is a catalog name } function TZPostgreSQLDatabaseMetadata.UncachedGetCatalogs: IZResultSet; var SQL: string; begin if (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(7, 3) then begin SQL := 'SELECT datname AS TABLE_CAT FROM pg_catalog.pg_database' + ' ORDER BY TABLE_CAT'; end else SQL := 'SELECT datname AS TABLE_CAT FROM pg_database ORDER BY TABLE_CAT'; Result := CopyToVirtualResultSet( GetConnection.CreateStatement.ExecuteQuery(SQL), ConstructVirtualResultSet(CatalogColumnsDynArray)); end; {** Gets the table types available in this database. The results are ordered by table type.

The table type is:

  1. TABLE_TYPE String => table type. Typical types are "TABLE", "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM".
@return ResultSet - each row has a single String column that is a table type } function TZPostgreSQLDatabaseMetadata.UncachedGetTableTypes: IZResultSet; const Types: array [0..10] of string = ('TABLE', 'VIEW', 'INDEX', 'SEQUENCE', 'SYSTEM TABLE', 'SYSTEM TOAST TABLE', 'SYSTEM TOAST INDEX', 'SYSTEM VIEW', 'SYSTEM INDEX', 'TEMPORARY TABLE', 'TEMPORARY INDEX'); var I: Integer; begin Result:=inherited UncachedGetTableTypes; for I := 0 to 10 do begin Result.MoveToInsertRow; Result.UpdateString(1, Types[I]); Result.InsertRow; end; end; {** Gets a description of table columns available in the specified catalog.

Only column descriptions matching the catalog, schema, table and column name criteria are returned. They are ordered by TABLE_SCHEM, TABLE_NAME and ORDINAL_POSITION.

Each column description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. COLUMN_NAME String => column name
  5. DATA_TYPE short => SQL type from java.sql.Types
  6. TYPE_NAME String => Data source dependent type name, for a UDT the type name is fully qualified
  7. COLUMN_SIZE int => column size. For char or date types this is the maximum number of characters, for numeric or decimal types this is precision.
  8. BUFFER_LENGTH is not used.
  9. DECIMAL_DIGITS int => the number of fractional digits
  10. NUM_PREC_RADIX int => Radix (typically either 10 or 2)
  11. NULLABLE int => is NULL allowed?
    • columnNoNulls - might not allow NULL values
    • columnNullable - definitely allows NULL values
    • columnNullableUnknown - nullability unknown
  12. REMARKS String => comment describing column (may be null)
  13. COLUMN_DEF String => default value (may be null)
  14. SQL_DATA_TYPE int => unused
  15. SQL_DATETIME_SUB int => unused
  16. CHAR_OCTET_LENGTH int => for char types the maximum number of bytes in the column
  17. ORDINAL_POSITION int => index of column in table (starting at 1)
  18. IS_NULLABLE String => "NO" means column definitely does not allow NULL values; "YES" means the column might allow NULL values. An empty string means nobody knows.
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param tableNamePattern a table name pattern @param columnNamePattern a column name pattern @return ResultSet - each row is a column description @see #getSearchStringEscape } function TZPostgreSQLDatabaseMetadata.UncachedGetColumns(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const ColumnNamePattern: string): IZResultSet; var TypeOid, AttTypMod: Integer; SQL, PgType: string; SQLType: TZSQLType; CheckVisibility: Boolean; ColumnNameCondition, TableNameCondition, SchemaCondition: string; begin CheckVisibility := (GetConnection as IZPostgreSQLConnection).CheckFieldVisibility; //http://zeoslib.sourceforge.net/viewtopic.php?f=40&t=11174 SchemaCondition := ConstructNameCondition(SchemaPattern,'n.nspname'); TableNameCondition := ConstructNameCondition(TableNamePattern,'c.relname'); ColumnNameCondition := ConstructNameCondition(ColumnNamePattern,'a.attname'); Result:=inherited UncachedGetColumns(Catalog, SchemaPattern, TableNamePattern, ColumnNamePattern); if (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(7, 3) then begin SQL := 'SELECT n.nspname,' {nspname_index} + 'c.relname,' {relname_index} + 'a.attname,' {attname_index} + 'a.atttypid,' {atttypid_index} + 'a.attnotnull,' {attnotnull_index} + 'a.atttypmod,' {atttypmod_index} + 'a.attlen,' {attlen_index} + 'a.attnum,' {attnum_index} + 'pg_get_expr(def.adbin, def.adrelid) as adsrc,' {adsrc_index} + 'dsc.description ' {description_index} + ' FROM pg_catalog.pg_namespace n ' + ' JOIN pg_catalog.pg_class c ON (c.relnamespace = n.oid) ' + ' JOIN pg_catalog.pg_attribute a ON (a.attrelid=c.oid) ' + ' LEFT JOIN pg_catalog.pg_attrdef def ON (a.attrelid=def.adrelid' + ' AND a.attnum = def.adnum) LEFT JOIN pg_catalog.pg_description dsc' + ' ON (c.oid=dsc.objoid AND a.attnum = dsc.objsubid) ' + ' LEFT JOIN pg_catalog.pg_class dc ON (dc.oid=dsc.classoid' + ' AND dc.relname=''pg_class'') LEFT JOIN pg_catalog.pg_namespace dn' + ' ON (dc.relnamespace=dn.oid AND dn.nspname=''pg_catalog'') ' + ' WHERE a.attnum > 0 AND NOT a.attisdropped'; if SchemaPattern <> '' then SQL := SQL + ' AND ' + SchemaCondition else //not by default: because of Speed decrease: http://http://zeoslib.sourceforge.net/viewtopic.php?p=16646&sid=130 if CheckVisibility then SQL := SQL + ' AND pg_table_is_visible (c.oid) '; end else begin SQL := 'SELECT NULL::text AS nspname,' {1} + 'c.relname,' {2} + 'a.attname,' {3} + 'a.atttypid,' {4} + 'a.attnotnull,' {5} + 'a.atttypmod,' {6} + 'a.attlen,' {7} + 'a.attnum,' {8} + 'NULL AS adsrc,' {9} + 'NULL AS description' {10} + 'FROM pg_class c, pg_attribute a ' + ' WHERE a.attrelid=c.oid AND a.attnum > 0 '; end; If TableNameCondition <> '' then SQL := SQL + ' AND ' + TableNameCondition; If ColumnNameCondition <> '' then SQL := SQL+ ' AND ' + ColumnNameCondition; SQL := SQL+ ' ORDER BY nspname,relname,attnum'; with GetConnection.CreateStatement.ExecuteQuery(SQL) do begin while Next do begin AttTypMod := GetInt(6 {atttypmod}); TypeOid := GetInt(4 {atttypid}); PgType := GetPostgreSQLType(TypeOid); Result.MoveToInsertRow; Result.UpdateNull(1); Result.UpdateString(2, GetString(1 {nspname})); Result.UpdateString(3, GetString(2 {relname})); Result.UpdateString(4, GetString(3 {attname})); SQLType := GetSQLTypeByOid(TypeOid); Result.UpdateInt(5, Ord(SQLType)); Result.UpdateString(6, PgType); Result.UpdateInt(8, 0); if (PgType = 'bpchar') or (PgType = 'varchar') or (PgType = 'enum') then begin if AttTypMod <> -1 then Result.UpdateInt(7, GetFieldSize(SQLType, ConSettings, (AttTypMod - 4), ConSettings.ClientCodePage.CharWidth)) else if (PgType = 'varchar') then if ( (GetConnection as IZPostgreSQLConnection).GetUndefinedVarcharAsStringLength = 0 ) then begin Result.UpdateInt(5, Ord(GetSQLTypeByOid(25))); //Assume text-lob instead Result.UpdateInt(7, 0); // need no size for streams end else //keep the string type but with user defined count of chars Result.UpdateInt(7, (GetConnection as IZPostgreSQLConnection).GetUndefinedVarcharAsStringLength ) else Result.UpdateInt(7, 0); end else if (PgType = 'numeric') or (PgType = 'decimal') then begin Result.UpdateInt(7, ((AttTypMod - 4) div 65536)); //precision Result.UpdateInt(9, ((AttTypMod -4) mod 65536)); //scale Result.UpdateInt(10, 10); //base? ten as default end else if (PgType = 'bit') or (PgType = 'varbit') then begin Result.UpdateInt(7, AttTypMod); Result.UpdateInt(10, 2); end else begin Result.UpdateInt(7, GetInt(7 {attlen})); Result.UpdateInt(10, 2); end; Result.UpdateNull(8); if GetBoolean(5 {attnotnull}) then begin Result.UpdateString(18, 'NO'); Result.UpdateInt(11, Ord(ntNoNulls)); end else begin Result.UpdateString(18, 'YES'); Result.UpdateInt(11, Ord(ntNullable)); end; Result.UpdateString(12, GetString(10 {description})); Result.UpdateString(13, GetString(9 {adsrc})); Result.UpdateNull(14); Result.UpdateNull(15); Result.UpdateInt(16, Result.GetInt(7)); Result.UpdateInt(17, GetInt(8 {attnum})); Result.UpdateNullByName('AUTO_INCREMENT'); Result.UpdateBooleanByName('CASE_SENSITIVE', IC.IsCaseSensitive(GetString(3 {attname}))); Result.UpdateBooleanByName('SEARCHABLE', True); Result.UpdateBooleanByName('WRITABLE', True); Result.UpdateBooleanByName('DEFINITELYWRITABLE', True); Result.UpdateBooleanByName('READONLY', False); Result.InsertRow; end; Close; end; end; {** Gets a description of the access rights for a table's columns.

Only privileges matching the column name criteria are returned. They are ordered by COLUMN_NAME and PRIVILEGE.

Each privilige description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. COLUMN_NAME String => column name
  5. GRANTOR => grantor of access (may be null)
  6. GRANTEE String => grantee of access
  7. PRIVILEGE String => name of access (SELECT, INSERT, UPDATE, REFRENCES, ...)
  8. IS_GRANTABLE String => "YES" if grantee is permitted to grant to others; "NO" if not; null if unknown
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @param columnNamePattern a column name pattern @return ResultSet - each row is a column privilege description @see #getSearchStringEscape } function TZPostgreSQLDatabaseMetadata.UncachedGetColumnPrivileges(const Catalog: string; const Schema: string; const Table: string; const ColumnNamePattern: string): IZResultSet; var I, J: Integer; SQL, Column, Owner: string; Privileges, Grantable, Grantee: string; Permissions, PermissionsExp: TStrings; ColumnNameCondition, TableNameCondition, SchemaCondition: string; begin SchemaCondition := ConstructNameCondition(Schema,'n.nspname'); TableNameCondition := ConstructNameCondition(Table,'c.relname'); ColumnNameCondition := ConstructNameCondition(ColumnNamePattern,'a.attname'); Result:=inherited UncachedGetColumnPrivileges(Catalog, Schema, Table, ColumnNamePattern); if (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(7, 3) then begin SQL := 'SELECT n.nspname,c.relname,u.usename,c.relacl,a.attname ' + ' FROM pg_catalog.pg_namespace n, pg_catalog.pg_class c,' + ' pg_catalog.pg_user u, pg_catalog.pg_attribute a ' + ' WHERE c.relnamespace = n.oid AND u.usesysid = c.relowner ' + ' AND c.oid = a.attrelid AND c.relkind = ''r''' + ' AND a.attnum > 0 AND NOT a.attisdropped'; if Schema <> '' then SQL := SQL + ' AND ' + SchemaCondition; end else begin SQL := 'SELECT NULL::text AS nspname,c.relname,u.usename,c.relacl,' + 'a.attname FROM pg_class c, pg_user u,pg_attribute a ' + ' WHERE u.usesysid = c.relowner AND c.oid = a.attrelid ' + ' AND a.attnum > 0 AND c.relkind = ''r'''; end; If TableNameCondition <> '' then SQL := SQL + ' AND ' + TableNameCondition; If ColumnNameCondition <> '' then SQL := SQL + ' AND '+ ColumnNameCondition; SQL := SQL + ' ORDER BY attname'; Permissions := TStringList.Create; PermissionsExp := TStringList.Create; try with GetConnection.CreateStatement.ExecuteQuery(SQL) do begin while Next do begin //SchemaName := GetStringByName('nspname'); //TableName := GetStringByName('relname'); Column := GetStringByName('attname'); Owner := GetStringByName('usename'); Permissions.Clear; ParseACLArray(Permissions, GetStringByName('relacl')); for I := 0 to Permissions.Count-1 do begin PutSplitString(PermissionsExp, Permissions.Strings[I], '='); if PermissionsExp.Count < 2 then Continue; Grantee := PermissionsExp.Strings[0]; if Grantee = '' then Grantee := 'PUBLIC'; Privileges := PermissionsExp.Strings[1]; for J := 1 to Length(Privileges) do begin if Owner = Grantee then Grantable := 'YES' else Grantable := 'NO'; Result.MoveToInsertRow; Result.UpdateNull(1); Result.UpdateString(2, Schema); Result.UpdateString(3, Table); Result.UpdateString(4, Column); Result.UpdateString(5, Owner); Result.UpdateString(6, Grantee); Result.UpdateString(7, GetPrivilegeName(Privileges[J])); Result.UpdateString(8, grantable); Result.InsertRow; end; end; end; Close; end; finally Permissions.Free; PermissionsExp.Free; end; end; {** Gets a description of the access rights for each table available in a catalog. Note that a table privilege applies to one or more columns in the table. It would be wrong to assume that this priviledge applies to all columns (this may be true for some systems but is not true for all.)

Only privileges matching the schema and table name criteria are returned. They are ordered by TABLE_SCHEM, TABLE_NAME, and PRIVILEGE.

Each privilige description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. GRANTOR => grantor of access (may be null)
  5. GRANTEE String => grantee of access
  6. PRIVILEGE String => name of access (SELECT, INSERT, UPDATE, REFRENCES, ...)
  7. IS_GRANTABLE String => "YES" if grantee is permitted to grant to others; "NO" if not; null if unknown
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param tableNamePattern a table name pattern @return ResultSet - each row is a table privilege description @see #getSearchStringEscape } function TZPostgreSQLDatabaseMetadata.UncachedGetTablePrivileges(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string): IZResultSet; var I, J: Integer; SQL, SchemaName, TableName, Owner: string; Privileges, Grantable, Grantee: string; Permissions, PermissionsExp: TStringList; TableNameCondition, SchemaCondition: string; begin SchemaCondition := ConstructNameCondition(SchemaPattern,'n.nspname'); TableNameCondition := ConstructNameCondition(TableNamePattern,'c.relname'); Result:=inherited UncachedGetTablePrivileges(Catalog, SchemaPattern, TableNamePattern); if (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(7, 3) then begin SQL := 'SELECT n.nspname,c.relname,u.usename,c.relacl ' + ' FROM pg_catalog.pg_namespace n, pg_catalog.pg_class c,' + ' pg_catalog.pg_user u WHERE c.relnamespace = n.oid ' + ' AND u.usesysid = c.relowner AND c.relkind = ''r'' '; if SchemaPattern <> '' then SQL := SQL + ' AND ' + SchemaCondition; end else begin SQL := 'SELECT NULL::text AS nspname,c.relname,u.usename,c.relacl ' + ' FROM pg_class c, pg_user u WHERE u.usesysid = c.relowner ' + ' AND c.relkind = ''r'' '; end; SQL := SQL + ' AND ' + TableNameCondition + ' ORDER BY nspname, relname'; Permissions := TStringList.Create; PermissionsExp := TStringList.Create; try with GetConnection.CreateStatement.ExecuteQuery(SQL) do begin while Next do begin SchemaName := GetStringByName('nspname'); TableName := GetStringByName('relname'); Owner := GetStringByName('usename'); SchemaName := GetStringByName('nspname'); Permissions.Clear; ParseACLArray(Permissions, GetStringByName('relacl')); Permissions.Sort; for I := 0 to Permissions.Count-1 do begin PutSplitString(PermissionsExp, Permissions.Strings[I], '='); if PermissionsExp.Count < 2 then Continue; Grantee := PermissionsExp.Strings[0]; if Grantee = '' then Grantee := 'PUBLIC'; Privileges := PermissionsExp.Strings[1]; for J := 1 to Length(Privileges) do begin if Owner = Grantee then Grantable := 'YES' else Grantable := 'NO'; Result.MoveToInsertRow; Result.UpdateNull(1); Result.UpdateString(2, SchemaName); Result.UpdateString(3, TableName); Result.UpdateString(4, Owner); Result.UpdateString(5, Grantee); Result.UpdateString(6, GetPrivilegeName(Privileges[J])); Result.UpdateString(7, grantable); Result.InsertRow; end; end; end; Close; end; finally Permissions.Free; PermissionsExp.Free; end; end; {** Gets a description of a table's columns that are automatically updated when any value in a row is updated. They are unordered.

Each column description has the following columns:

  1. SCOPE short => is not used
  2. COLUMN_NAME String => column name
  3. DATA_TYPE short => SQL data type from java.sql.Types
  4. TYPE_NAME String => Data source dependent type name
  5. COLUMN_SIZE int => precision
  6. BUFFER_LENGTH int => length of column value in bytes
  7. DECIMAL_DIGITS short => scale
  8. PSEUDO_COLUMN short => is this a pseudo column like an Oracle ROWID
    • versionColumnUnknown - may or may not be pseudo column
    • versionColumnNotPseudo - is NOT a pseudo column
    • versionColumnPseudo - is a pseudo column
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a column description @exception SQLException if a database access error occurs } function TZPostgreSQLDatabaseMetadata.UncachedGetVersionColumns(const Catalog: string; const Schema: string; const Table: string): IZResultSet; begin Result:=inherited UncachedGetVersionColumns(Catalog, Schema, Table); Result.MoveToInsertRow; Result.UpdateNull(1); Result.UpdateString(2, 'ctid'); Result.UpdateInt(3, Ord(GetSQLTypeByName('tid'))); Result.UpdateString(4, 'tid'); Result.UpdateNull(5); Result.UpdateNull(6); Result.UpdateNull(7); Result.UpdateInt(4, Ord(vcPseudo)); Result.InsertRow; end; {** Gets a description of a table's primary key columns. They are ordered by COLUMN_NAME.

Each primary key column description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. COLUMN_NAME String => column name
  5. KEY_SEQ short => sequence number within primary key
  6. PK_NAME String => primary key name (may be null)
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a primary key column description @exception SQLException if a database access error occurs } function TZPostgreSQLDatabaseMetadata.UncachedGetPrimaryKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; var SQL, Select, From, Where: string; TableNameCondition, SchemaCondition: string; begin SchemaCondition := ConstructNameCondition(Schema,'n.nspname'); TableNameCondition := ConstructNameCondition(Table,'ct.relname'); if (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(7, 3) then begin Select := 'SELECT NULL AS TABLE_CAT, n.nspname AS TABLE_SCHEM,'; From := ' FROM pg_catalog.pg_namespace n, pg_catalog.pg_class ct,' + ' pg_catalog.pg_class ci, pg_catalog.pg_attribute a,' + ' pg_catalog.pg_index i'; Where := ' AND ct.relnamespace = n.oid'; if Schema <> '' then Where := Where + ' AND ' + SchemaCondition; end else begin Select := 'SELECT NULL AS TABLE_CAT, NULL AS TABLE_SCHEM,'; From := ' FROM pg_class ct, pg_class ci, pg_attribute a, pg_index i'; end; SQL := Select + ' ct.relname AS TABLE_NAME, a.attname AS COLUMN_NAME,' + ' a.attnum AS KEY_SEQ, ci.relname AS PK_NAME' + From + ' WHERE ct.oid=i.indrelid AND ci.oid=i.indexrelid' + ' AND a.attrelid=ci.oid AND i.indisprimary'; if Table <> '' then SQL := SQL + ' AND ' + TableNameCondition; SQL := SQL + Where + ' ORDER BY table_name, pk_name, key_seq'; Result := CopyToVirtualResultSet( GetConnection.CreateStatement.ExecuteQuery(SQL), ConstructVirtualResultSet(PrimaryKeyColumnsDynArray)); end; {** Gets a description of the primary key columns that are referenced by a table's foreign key columns (the primary keys imported by a table). They are ordered by PKTABLE_CAT, PKTABLE_SCHEM, PKTABLE_NAME, and KEY_SEQ.

Each primary key column description has the following columns:

  1. PKTABLE_CAT String => primary key table catalog being imported (may be null)
  2. PKTABLE_SCHEM String => primary key table schema being imported (may be null)
  3. PKTABLE_NAME String => primary key table name being imported
  4. PKCOLUMN_NAME String => primary key column name being imported
  5. FKTABLE_CAT String => foreign key table catalog (may be null)
  6. FKTABLE_SCHEM String => foreign key table schema (may be null)
  7. FKTABLE_NAME String => foreign key table name
  8. FKCOLUMN_NAME String => foreign key column name
  9. KEY_SEQ short => sequence number within foreign key
  10. UPDATE_RULE short => What happens to foreign key when primary is updated:
    • importedNoAction - do not allow update of primary key if it has been imported
    • importedKeyCascade - change imported key to agree with primary key update
    • importedKeySetNull - change imported key to NULL if its primary key has been updated
    • importedKeySetDefault - change imported key to default values if its primary key has been updated
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
  11. DELETE_RULE short => What happens to the foreign key when primary is deleted.
    • importedKeyNoAction - do not allow delete of primary key if it has been imported
    • importedKeyCascade - delete rows that import a deleted key
    • importedKeySetNull - change imported key to NULL if its primary key has been deleted
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
    • importedKeySetDefault - change imported key to default if its primary key has been deleted
  12. FK_NAME String => foreign key name (may be null)
  13. PK_NAME String => primary key name (may be null)
  14. DEFERRABILITY short => can the evaluation of foreign key constraints be deferred until commit
    • importedKeyInitiallyDeferred - see SQL92 for definition
    • importedKeyInitiallyImmediate - see SQL92 for definition
    • importedKeyNotDeferrable - see SQL92 for definition
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a primary key column description @see #getExportedKeys } function TZPostgreSQLDatabaseMetadata.UncachedGetImportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; var SQL: string; KeySequence: Integer; TableNameCondition, SchemaCondition, CatalogCondition: string; begin CatalogCondition := ConstructNameCondition(Catalog,'kcu.table_catalog'); SchemaCondition := ConstructNameCondition(Schema,'kcu.constraint_schema'); TableNameCondition := ConstructNameCondition(Table,'kcu.table_name'); if (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(7, 4) then begin Result:=inherited UncachedGetImportedKeys(Catalog, Schema, Table); SQL := 'SELECT '+ 'tc.constraint_catalog as PKTABLE_CAT, '+ 'tc.constraint_schema as PKTABLE_SCHEM, '+ 'ccu.table_name as PKTABLE_NAME, '+ 'ccu.column_name as PKCOLUMN_NAME, '+ 'kcu.table_catalog as FKTABLE_CAT, '+ 'kcu.constraint_schema as FKTABLE_SCHEM, '+ 'kcu.table_name as PKTABLE_NAME, '+ 'kcu.column_name as FKCOLUMN_NAME, '+ 'rf.update_rule as UPDATE_RULE, '+ 'rf.delete_rule as DELETE_RULE, '+ 'kcu.constraint_name as FK_NAME, '+ 'kcu.ordinal_position as PK_NAME, '+ 'tc.is_deferrable as DEFERRABILITY '+ 'FROM information_schema.table_constraints AS tc '+ 'JOIN information_schema.key_column_usage AS kcu ON tc.constraint_name = kcu.constraint_name '+ 'JOIN information_schema.constraint_column_usage AS ccu ON ccu.constraint_name = tc.constraint_name '+ 'join information_schema.referential_constraints as rf on rf.constraint_name = tc.constraint_name '+ 'WHERE constraint_type = ''FOREIGN KEY'''; if Catalog <> '' then SQL := SQL + ' and ' + CatalogCondition; if Schema <> '' then SQL := SQL + ' and ' + SchemaCondition; if Table <> '' then SQL := SQL + ' and ' + TableNameCondition; KeySequence := 0; with GetConnection.CreateStatement.ExecuteQuery(SQL) do begin while Next do begin Inc(KeySequence); Result.MoveToInsertRow; Result.UpdateNull(1); //PKTABLE_CAT Result.UpdateString(2, GetString(2)); //PKTABLE_SCHEM Result.UpdateString(3, GetString(3)); //PKTABLE_NAME Result.UpdateString(4, GetString(4)); //PKCOLUMN_NAME //Result.UpdateString(5, GetString(5)); //PKTABLE_CAT Result.UpdateString(5, Catalog); //PKTABLE_CAT Result.UpdateString(6, GetString(6)); //FKTABLE_SCHEM Result.UpdateString(7, GetString(7)); //FKTABLE_NAME Result.UpdateString(8, GetString(8)); //FKCOLUMN_NAME Result.UpdateShort(9, KeySequence); //KEY_SEQ Result.UpdateShort(10, Ord(GetRuleType(GetString(9)))); //UPDATE_RULE Result.UpdateShort(11, Ord(GetRuleType(GetString(10)))); //DELETE_RULE Result.UpdateString(12, GetString(11)); //FK_NAME Result.UpdateString(13, GetString(12)); //PK_NAME if GetString(13) = 'NO' then Result.UpdateShort(14, Ord(ikNotDeferrable)) //DEFERRABILITY else Result.UpdateShort(14, Ord(ikInitiallyDeferred)); //DEFERRABILITY Result.InsertRow; end; Close; end; end else Result := UncachedGetCrossReference('', '', '', Catalog, Schema, Table); end; {** Gets a description of the foreign key columns that reference a table's primary key columns (the foreign keys exported by a table). They are ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, and KEY_SEQ.

Each foreign key column description has the following columns:

  1. PKTABLE_CAT String => primary key table catalog (may be null)
  2. PKTABLE_SCHEM String => primary key table schema (may be null)
  3. PKTABLE_NAME String => primary key table name
  4. PKCOLUMN_NAME String => primary key column name
  5. FKTABLE_CAT String => foreign key table catalog (may be null) being exported (may be null)
  6. FKTABLE_SCHEM String => foreign key table schema (may be null) being exported (may be null)
  7. FKTABLE_NAME String => foreign key table name being exported
  8. FKCOLUMN_NAME String => foreign key column name being exported
  9. KEY_SEQ short => sequence number within foreign key
  10. UPDATE_RULE short => What happens to foreign key when primary is updated:
    • importedNoAction - do not allow update of primary key if it has been imported
    • importedKeyCascade - change imported key to agree with primary key update
    • importedKeySetNull - change imported key to NULL if its primary key has been updated
    • importedKeySetDefault - change imported key to default values if its primary key has been updated
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
  11. DELETE_RULE short => What happens to the foreign key when primary is deleted.
    • importedKeyNoAction - do not allow delete of primary key if it has been imported
    • importedKeyCascade - delete rows that import a deleted key
    • importedKeySetNull - change imported key to NULL if its primary key has been deleted
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
    • importedKeySetDefault - change imported key to default if its primary key has been deleted
  12. FK_NAME String => foreign key name (may be null)
  13. PK_NAME String => primary key name (may be null)
  14. DEFERRABILITY short => can the evaluation of foreign key constraints be deferred until commit
    • importedKeyInitiallyDeferred - see SQL92 for definition
    • importedKeyInitiallyImmediate - see SQL92 for definition
    • importedKeyNotDeferrable - see SQL92 for definition
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a foreign key column description @see #getImportedKeys } function TZPostgreSQLDatabaseMetadata.UncachedGetExportedKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; var SQL: string; KeySequence: Integer; TableNameCondition, SchemaCondition, CatalogCondition: string; begin CatalogCondition := ConstructNameCondition(Catalog,'tc.constraint_catalog'); SchemaCondition := ConstructNameCondition(Schema,'tc.constraint_schema'); TableNameCondition := ConstructNameCondition(Table,'ccu.table_name'); if (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(7, 4) then begin Result:=inherited UncachedGetImportedKeys(Catalog, Schema, Table); SQL := 'SELECT '+ 'tc.constraint_catalog as PKTABLE_CAT, '+ 'tc.constraint_schema as PKTABLE_SCHEM, '+ 'ccu.table_name as PKTABLE_NAME, '+ 'ccu.column_name as PKCOLUMN_NAME, '+ 'kcu.table_catalog as FKTABLE_CAT, '+ 'kcu.constraint_schema as FKTABLE_SCHEM, '+ 'kcu.table_name as PKTABLE_NAME, '+ 'kcu.column_name as FKCOLUMN_NAME, '+ 'rf.update_rule as UPDATE_RULE, '+ 'rf.delete_rule as DELETE_RULE, '+ 'kcu.constraint_name as FK_NAME, '+ 'kcu.ordinal_position as PK_NAME, '+ 'tc.is_deferrable as DEFERRABILITY '+ 'FROM information_schema.table_constraints AS tc '+ 'JOIN information_schema.key_column_usage AS kcu ON tc.constraint_name = kcu.constraint_name '+ 'JOIN information_schema.constraint_column_usage AS ccu ON ccu.constraint_name = tc.constraint_name '+ 'join information_schema.referential_constraints as rf on rf.constraint_name = tc.constraint_name '+ 'WHERE constraint_type = ''FOREIGN KEY'''; if Catalog <> '' then SQL := SQL + ' and ' + CatalogCondition; if Schema <> '' then SQL := SQL + ' and ' + SchemaCondition; if Table <> '' then SQL := SQL + ' and ' + TableNameCondition; SQL := SQL + ' order by kcu.table_name;'; KeySequence := 0; with GetConnection.CreateStatement.ExecuteQuery(SQL) do begin while Next do begin Inc(KeySequence); Result.MoveToInsertRow; Result.UpdateNull(1); //PKTABLE_CAT Result.UpdateString(2, GetString(2)); //PKTABLE_SCHEM Result.UpdateString(3, GetString(3)); //PKTABLE_NAME Result.UpdateString(4, GetString(4)); //PKCOLUMN_NAME //Result.UpdateString(5, GetString(5)); //PKTABLE_CAT Result.UpdateString(5, Catalog); //PKTABLE_CAT Result.UpdateString(6, GetString(6)); //FKTABLE_SCHEM Result.UpdateString(7, GetString(7)); //FKTABLE_NAME Result.UpdateString(8, GetString(8)); //FKCOLUMN_NAME Result.UpdateShort(9, KeySequence); //KEY_SEQ Result.UpdateShort(10, Ord(GetRuleType(GetString(9)))); //UPDATE_RULE Result.UpdateShort(11, Ord(GetRuleType(GetString(10)))); //DELETE_RULE Result.UpdateString(12, GetString(11)); //FK_NAME Result.UpdateString(13, GetString(12)); //PK_NAME if GetString(13) = 'NO' then Result.UpdateShort(14, Ord(ikNotDeferrable)) //DEFERRABILITY else Result.UpdateShort(14, Ord(ikInitiallyDeferred)); //DEFERRABILITY Result.InsertRow; end; Close; end; end else Result := UncachedGetCrossReference('', '', '', Catalog, Schema, Table); end; {** Gets a description of the foreign key columns in the foreign key table that reference the primary key columns of the primary key table (describe how one table imports another's key.) This should normally return a single foreign key/primary key pair (most tables only import a foreign key from a table once.) They are ordered by FKTABLE_CAT, FKTABLE_SCHEM, FKTABLE_NAME, and KEY_SEQ.

Each foreign key column description has the following columns:

  1. PKTABLE_CAT String => primary key table catalog (may be null)
  2. PKTABLE_SCHEM String => primary key table schema (may be null)
  3. PKTABLE_NAME String => primary key table name
  4. PKCOLUMN_NAME String => primary key column name
  5. FKTABLE_CAT String => foreign key table catalog (may be null) being exported (may be null)
  6. FKTABLE_SCHEM String => foreign key table schema (may be null) being exported (may be null)
  7. FKTABLE_NAME String => foreign key table name being exported
  8. FKCOLUMN_NAME String => foreign key column name being exported
  9. KEY_SEQ short => sequence number within foreign key
  10. UPDATE_RULE short => What happens to foreign key when primary is updated:
    • importedNoAction - do not allow update of primary key if it has been imported
    • importedKeyCascade - change imported key to agree with primary key update
    • importedKeySetNull - change imported key to NULL if its primary key has been updated
    • importedKeySetDefault - change imported key to default values if its primary key has been updated
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
  11. DELETE_RULE short => What happens to the foreign key when primary is deleted.
    • importedKeyNoAction - do not allow delete of primary key if it has been imported
    • importedKeyCascade - delete rows that import a deleted key
    • importedKeySetNull - change imported key to NULL if its primary key has been deleted
    • importedKeyRestrict - same as importedKeyNoAction (for ODBC 2.x compatibility)
    • importedKeySetDefault - change imported key to default if its primary key has been deleted
  12. FK_NAME String => foreign key name (may be null)
  13. PK_NAME String => primary key name (may be null)
  14. DEFERRABILITY short => can the evaluation of foreign key constraints be deferred until commit
    • importedKeyInitiallyDeferred - see SQL92 for definition
    • importedKeyInitiallyImmediate - see SQL92 for definition
    • importedKeyNotDeferrable - see SQL92 for definition
@param primaryCatalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param primarySchema a schema name; "" retrieves those without a schema @param primaryTable the table name that exports the key @param foreignCatalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param foreignSchema a schema name; "" retrieves those without a schema @param foreignTable the table name that imports the key @return ResultSet - each row is a foreign key column description @see #getImportedKeys } function TZPostgreSQLDatabaseMetadata.UncachedGetCrossReference(const PrimaryCatalog: string; const PrimarySchema: string; const PrimaryTable: string; const ForeignCatalog: string; const ForeignSchema: string; const ForeignTable: string): IZResultSet; var SQL, Select, From, Where: string; DeleteRule, UpdateRule, Rule: string; {FKeyName, }FKeyColumn, PKeyColumn, Targs: string; Action, KeySequence, Advance: Integer; List: TStrings; Deferrability: Integer; Deferrable, InitiallyDeferred: Boolean; begin Result:=inherited UncachedGetCrossReference(PrimaryCatalog, PrimarySchema, PrimaryTable, ForeignCatalog, ForeignSchema, ForeignTable); if (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(7, 4) then begin SQL := 'SELECT '+ 'tc.constraint_catalog as PKTABLE_CAT, '+ 'tc.constraint_schema as PKTABLE_SCHEM, '+ 'ccu.table_name as PKTABLE_NAME, '+ 'ccu.column_name as PKCOLUMN_NAME, '+ 'kcu.table_catalog as FKTABLE_CAT, '+ 'kcu.constraint_schema as FKTABLE_SCHEM, '+ 'kcu.table_name as PKTABLE_NAME, '+ 'kcu.column_name as FKCOLUMN_NAME, '+ 'rf.update_rule as UPDATE_RULE, '+ 'rf.delete_rule as DELETE_RULE, '+ 'kcu.constraint_name as FK_NAME, '+ 'kcu.ordinal_position as PK_NAME, '+ 'tc.is_deferrable as DEFERRABILITY '+ 'FROM information_schema.table_constraints AS tc '+ 'JOIN information_schema.key_column_usage AS kcu ON tc.constraint_name = kcu.constraint_name '+ 'JOIN information_schema.constraint_column_usage AS ccu ON ccu.constraint_name = tc.constraint_name '+ 'join information_schema.referential_constraints as rf on rf.constraint_name = tc.constraint_name '+ 'WHERE constraint_type = ''FOREIGN KEY'''; if PrimaryCatalog <> '' then SQL := SQL + ' and tc.constraint_catalog = '''+PrimaryCatalog+''''; if PrimarySchema <> '' then SQL := SQL + ' and tc.constraint_schema = '''+PrimarySchema+''''; if PrimaryTable <> '' then SQL := SQL + ' and ccu.table_name = '''+PrimaryTable+''''; if ForeignCatalog <> '' then SQL := SQL + ' and kcu.table_catalog = '''+ForeignCatalog+''''; if ForeignSchema <> '' then SQL := SQL + ' and kcu.constraint_schema = '''+ForeignSchema+''''; if ForeignTable <> '' then SQL := SQL + ' and kcu.table_name = '''+ForeignTable+''''; KeySequence := 0; with GetConnection.CreateStatement.ExecuteQuery(SQL) do begin while Next do begin Inc(KeySequence); Result.MoveToInsertRow; //Result.UpdateString(1, GetString(1)); //PKTABLE_CAT Result.UpdateString(1, PrimaryCatalog); //PKTABLE_CAT Result.UpdateString(2, GetString(2)); //PKTABLE_SCHEM Result.UpdateString(3, GetString(3)); //PKTABLE_NAME Result.UpdateString(4, GetString(4)); //PKCOLUMN_NAME //Result.UpdateString(5, GetString(5)); //PKTABLE_CAT Result.UpdateString(5, ForeignCatalog); //PKTABLE_CAT Result.UpdateString(6, GetString(6)); //FKTABLE_SCHEM Result.UpdateString(7, GetString(7)); //FKTABLE_NAME Result.UpdateString(8, GetString(8)); //FKCOLUMN_NAME Result.UpdateShort(9, KeySequence); //KEY_SEQ Result.UpdateShort(10, Ord(GetRuleType(GetString(9)))); //UPDATE_RULE Result.UpdateShort(11, Ord(GetRuleType(GetString(10)))); //DELETE_RULE Result.UpdateString(12, GetString(11)); //FK_NAME Result.UpdateString(13, GetString(12)); //PK_NAME if GetString(13) = 'NO' then Result.UpdateShort(14, Ord(ikNotDeferrable)) //DEFERRABILITY else Result.UpdateShort(14, Ord(ikInitiallyDeferred)); //DEFERRABILITY Result.InsertRow; end; Close; end; end else begin if (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(7, 3) then begin Select := 'SELECT DISTINCT n1.nspname as pnspname,n2.nspname as fnspname,'; From := ' FROM pg_catalog.pg_namespace n1 JOIN pg_catalog.pg_class c1' + ' ON (c1.relnamespace = n1.oid) JOIN pg_catalog.pg_index i' + ' ON (c1.oid=i.indrelid) JOIN pg_catalog.pg_class ic' + ' ON (i.indexrelid=ic.oid) JOIN pg_catalog.pg_attribute a' + ' ON (ic.oid=a.attrelid), pg_catalog.pg_namespace n2' + ' JOIN pg_catalog.pg_class c2 ON (c2.relnamespace=n2.oid),' + ' pg_catalog.pg_trigger t1 JOIN pg_catalog.pg_proc p1' + ' ON (t1.tgfoid=p1.oid), pg_catalog.pg_trigger t2' + ' JOIN pg_catalog.pg_proc p2 ON (t2.tgfoid=p2.oid)'; Where := ''; if PrimarySchema <> ''then begin Where := Where + ' AND n1.nspname = ' + EscapeString(PrimarySchema); end; if ForeignSchema <> '' then begin Where := Where + ' AND n2.nspname = ' + EscapeString(ForeignSchema); end; end else begin Select := 'SELECT DISTINCT NULL::text as pnspname, NULL::text as fnspname,'; From := ' FROM pg_class c1 JOIN pg_index i ON (c1.oid=i.indrelid)' + ' JOIN pg_class ic ON (i.indexrelid=ic.oid) JOIN pg_attribute a' + ' ON (ic.oid=a.attrelid), pg_class c2, pg_trigger t1' + ' JOIN pg_proc p1 ON (t1.tgfoid=p1.oid), pg_trigger t2' + ' JOIN pg_proc p2 ON (t2.tgfoid=p2.oid)'; end; SQL := Select + ' c1.relname as prelname, c2.relname as frelname,' + ' t1.tgconstrname, a.attnum as keyseq, ic.relname as fkeyname,' + ' t1.tgdeferrable, t1.tginitdeferred, t1.tgnargs,t1.tgargs,' + ' p1.proname as updaterule, p2.proname as deleterule' + From + ' WHERE (t1.tgrelid=c1.oid AND t1.tgisconstraint' + ' AND t1.tgconstrrelid=c2.oid AND p1.proname' + ' LIKE ' + EscapeString('RI\_FKey\_%\_upd') + ') AND (t2.tgrelid=c1.oid' + ' AND t2.tgisconstraint AND t2.tgconstrrelid=c2.oid ' + ' AND p2.proname LIKE ' + EscapeString('RI\_FKey\_%\_del') + ') AND i.indisprimary' + Where; if PrimaryTable <> '' then SQL := SQL + ' AND c1.relname=' + EscapeString(PrimaryTable); if ForeignTable <> '' then SQL := SQL + ' AND c2.relname=' + EscapeString(ForeignTable); SQL := SQL + ' ORDER BY '; if PrimaryTable <> '' then begin if (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(7, 3) then SQL := SQL + 'fnspname, '; SQL := SQL + 'frelname'; end else begin if (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(7, 3) then SQL := SQL + 'pnspname, '; SQL := SQL + 'prelname'; end; SQL := SQL + ', keyseq'; List := TStringList.Create; try with GetConnection.CreateStatement.ExecuteQuery(SQL) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateString(2, GetString(1)); Result.UpdateString(6, GetString(2)); Result.UpdateString(3, GetString(3)); Result.UpdateString(7, GetString(4)); //FKeyName := GetString(5); UpdateRule := GetString(12); if UpdateRule <> '' then begin Rule := Copy(UpdateRule, 9, Length(UpdateRule) - 12); Action := Ord(ikNoAction); if (Rule = '') or (Rule = 'noaction') then Action := Ord(ikNoAction); if Rule = 'cascade' then Action := Ord(ikCascade); if Rule = 'setnull' then Action := Ord(ikSetNull); if Rule = 'setdefault' then Action := Ord(ikSetDefault); if Rule = 'restrict' then Action := Ord(ikRestrict); Result.UpdateInt(10, Action); end; DeleteRule := GetString(13); if DeleteRule <> '' then begin Rule := Copy(DeleteRule, 9, Length(DeleteRule) - 12); Action := Ord(ikNoAction); if Rule = 'cascade' then Action := Ord(ikCascade); if Rule = 'setnull' then Action := Ord(ikSetNull); if Rule = 'setdefault' then Action := Ord(ikSetDefault); if Rule = 'restrict' then Action := Ord(ikRestrict); Result.UpdateInt(11, Action); end; KeySequence := GetInt(6); Targs := GetString(11); //\000ww\000vv\000UNSPECIFIED\000m\000a\000n\000b\000 //for Postgresql 7.3 //$1\000ww\000vv\000UNSPECIFIED\000m\000a\000n\000b\000 //$2\000ww\000vv\000UNSPECIFIED\000m\000a\000n\000b\000 Advance := 4 + (KeySequence - 1) * 2; PutSplitStringEx(List, Targs, '\000'); if Advance <= List.Count-1 then FKeyColumn := List.Strings[Advance]; if Advance + 1 <= List.Count-1 then PKeyColumn := List.Strings[Advance+1]; Result.UpdateString(4, PKeyColumn); Result.UpdateString(8, FKeyColumn); Result.UpdateString(9, GetString(6)); //KEY_SEQ if List.Strings[0] = '' then Result.UpdateString(12, Targs) //FK_NAME else Result.UpdateString(12, List.Strings[0]); //FK_NAME Result.UpdateString(13, GetString(6)); //PK_ NAME Deferrability := Ord(ikNotDeferrable); Deferrable := GetBoolean(8); InitiallyDeferred := GetBoolean(9); if Deferrable then begin if InitiallyDeferred then Deferrability := Ord(ikInitiallyDeferred) else Deferrability := Ord(ikInitiallyImmediate); end; Result.UpdateInt(14, Deferrability); Result.InsertRow; end; Close; end; finally List.Free; end; end; end; {** Gets a description of all the standard SQL types supported by this database. They are ordered by DATA_TYPE and then by how closely the data type maps to the corresponding JDBC SQL type.

Each type description has the following columns:

  1. TYPE_NAME String => Type name
  2. DATA_TYPE short => SQL data type from java.sql.Types
  3. PRECISION int => maximum precision
  4. LITERAL_PREFIX String => prefix used to quote a literal (may be null)
  5. LITERAL_SUFFIX String => suffix used to quote a literal (may be null)
  6. CREATE_PARAMS String => parameters used in creating the type (may be null)
  7. NULLABLE short => can you use NULL for this type?
    • typeNoNulls - does not allow NULL values
    • typeNullable - allows NULL values
    • typeNullableUnknown - nullability unknown
  8. CASE_SENSITIVE Boolean=> is it case sensitive?
  9. SEARCHABLE short => can you use "WHERE" based on this type:
    • typePredNone - No support
    • typePredChar - Only supported with WHERE .. LIKE
    • typePredBasic - Supported except for WHERE .. LIKE
    • typeSearchable - Supported for all WHERE ..
  10. UNSIGNED_ATTRIBUTE Boolean => is it unsigned?
  11. FIXED_PREC_SCALE Boolean => can it be a money value?
  12. AUTO_INCREMENT Boolean => can it be used for an auto-increment value?
  13. LOCAL_TYPE_NAME String => localized version of type name (may be null)
  14. MINIMUM_SCALE short => minimum scale supported
  15. MAXIMUM_SCALE short => maximum scale supported
  16. SQL_DATA_TYPE int => unused
  17. SQL_DATETIME_SUB int => unused
  18. NUM_PREC_RADIX int => usually 2 or 10
@return ResultSet - each row is an SQL type description } function TZPostgreSQLDatabaseMetadata.UncachedGetTypeInfo: IZResultSet; var SQL: string; begin Result:=inherited UncachedGetTypeInfo; if (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(7, 3) then SQL := ' SELECT typname FROM pg_catalog.pg_type ' else SQL := ' SELECT typname FROM pg_type '; with GetConnection.CreateStatement.ExecuteQuery(SQL) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateString(1, GetString(1)); Result.UpdateInt(2, Ord(GetSQLTypeByName(GetString(1)))); Result.UpdateInt(3, 9); Result.UpdateInt(7, Ord(ntNoNulls)); Result.UpdateBoolean(8, False); Result.UpdateBoolean(9, False); Result.UpdateBoolean(11, False); Result.UpdateBoolean(12, False); Result.UpdateInt(18, 10); Result.InsertRow; end; Close; end; end; {** Gets a description of a table's indices and statistics. They are ordered by NON_UNIQUE, TYPE, INDEX_NAME, and ORDINAL_POSITION.

Each index column description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. NON_UNIQUE Boolean => Can index values be non-unique? false when TYPE is tableIndexStatistic
  5. INDEX_QUALIFIER String => index catalog (may be null); null when TYPE is tableIndexStatistic
  6. INDEX_NAME String => index name; null when TYPE is tableIndexStatistic
  7. TYPE short => index type:
    • tableIndexStatistic - this identifies table statistics that are returned in conjuction with a table's index descriptions
    • tableIndexClustered - this is a clustered index
    • tableIndexHashed - this is a hashed index
    • tableIndexOther - this is some other style of index
  8. ORDINAL_POSITION short => column sequence number within index; zero when TYPE is tableIndexStatistic
  9. COLUMN_NAME String => column name; null when TYPE is tableIndexStatistic
  10. ASC_OR_DESC String => column sort sequence, "A" => ascending, "D" => descending, may be null if sort sequence is not supported; null when TYPE is tableIndexStatistic
  11. CARDINALITY int => When TYPE is tableIndexStatistic, then this is the number of rows in the table; otherwise, it is the number of unique values in the index.
  12. PAGES int => When TYPE is tableIndexStatisic then this is the number of pages used for the table, otherwise it is the number of pages used for the current index.
  13. FILTER_CONDITION String => Filter condition, if any. (may be null)
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @param unique when true, return only indices for unique values; when false, return indices regardless of whether unique or not @param approximate when true, result is allowed to reflect approximate or out of data values; when false, results are requested to be accurate @return ResultSet - each row is an index column description } function TZPostgreSQLDatabaseMetadata.UncachedGetIndexInfo(const Catalog: string; const Schema: string; const Table: string; Unique: Boolean; Approximate: Boolean): IZResultSet; var SQL, Select, From, Where: string; begin if (GetDatabaseInfo as IZPostgreDBInfo).HasMinimumServerVersion(7, 3) then begin Select := 'SELECT NULL AS TABLE_CAT, n.nspname AS TABLE_SCHEM,'; From := ' FROM pg_catalog.pg_namespace n, pg_catalog.pg_class ct,' + ' pg_catalog.pg_class ci, pg_catalog.pg_index i,' + ' pg_catalog.pg_attribute a, pg_catalog.pg_am am'; Where := ' AND n.oid = ct.relnamespace'; if Schema <> '' then Where := Where + ' AND n.nspname = ' + EscapeString(Schema); end else begin Select := 'SELECT NULL AS TABLE_CAT, NULL AS TABLE_SCHEM,'; From := ' FROM pg_class ct, pg_class ci, pg_index i, pg_attribute a,' + ' pg_am am'; end; SQL := Select + ' ct.relname AS TABLE_NAME, NOT i.indisunique' + ' AS NON_UNIQUE, NULL AS INDEX_QUALIFIER, ci.relname AS INDEX_NAME,' + ' CASE i.indisclustered WHEN true THEN ' + IntToStr(Ord(tiClustered)) + ' ELSE CASE am.amname WHEN ''hash'' THEN ' + IntToStr(Ord(tiHashed)) + ' ELSE ' + IntToStr(Ord(tiOther)) + ' END END AS TYPE,' + ' a.attnum AS ORDINAL_POSITION, a.attname AS COLUMN_NAME,' + ' NULL AS ASC_OR_DESC, ci.reltuples AS CARDINALITY,' + ' ci.relpages AS PAGES, NULL AS FILTER_CONDITION' + From + ' WHERE ct.oid=i.indrelid AND ci.oid=i.indexrelid' + ' AND a.attrelid=ci.oid AND ci.relam=am.oid' + Where + ' AND ct.relname = ' + EscapeString(Table); if Unique then SQL := SQL + ' AND i.indisunique'; SQL := SQL + ' ORDER BY NON_UNIQUE, TYPE, INDEX_NAME, ORDINAL_POSITION'; Result := CopyToVirtualResultSet( GetConnection.CreateStatement.ExecuteQuery(SQL), ConstructVirtualResultSet(IndexInfoColumnsDynArray)); end; function TZPostgreSQLDatabaseMetadata.UncachedGetSequences(const Catalog, SchemaPattern, SequenceNamePattern: string): IZResultSet; var SQL: string; begin Result:=inherited UncachedGetSequences(Catalog, SchemaPattern, SequenceNamePattern); SQL := ' SELECT nspname, relname ' + 'FROM pg_catalog.pg_namespace n, pg_catalog.pg_class ct ' + 'WHERE relkind = ''S'' ' + 'AND n.oid = ct.relnamespace'; if SequenceNamePattern <> '' then SQL := SQL + ' AND ' + Format('relname = ''%s''', [SequenceNamePattern]); if SchemaPattern <> '' then SQL := SQL + ' AND ' + Format('nspname = ''%s''', [SchemaPattern]); with GetConnection.CreateStatement.ExecuteQuery(SQL) do begin while Next do begin Result.MoveToInsertRow; Result.UpdateNull(1); Result.UpdateString(2, GetStringByName('nspname')); Result.UpdateString(3, GetStringByName('relname')); Result.InsertRow; end; Close; end; end; function TZPostgreSQLDatabaseMetadata.GetPostgreSQLType(Oid: Integer): string; begin Result := (GetConnection as IZPostgreSQLConnection).GetTypeNameByOid(Oid); end; function TZPostgreSQLDatabaseMetadata.GetSQLTypeByOid(Oid: Integer): TZSQLType; var PostgreSQLConnection: IZPostgreSQLConnection; begin PostgreSQLConnection := GetConnection as IZPostgreSQLConnection; Result := PostgreSQLToSQLType(PostgreSQLConnection, PostgreSQLConnection.GetTypeNameByOid(Oid)); end; function TZPostgreSQLDatabaseMetadata.GetSQLTypeByName( TypeName: string): TZSQLType; begin Result := PostgreSQLToSQLType( GetConnection as IZPostgreSQLConnection, TypeName); end; function TZPostgreSQLDatabaseMetadata.TableTypeSQLExpression( TableType: string; UseSchemas: Boolean): string; begin if UseSchemas then begin if TableType = 'TABLE' then Result := ' c.relkind = ''r'' AND n.nspname NOT LIKE ''pg\\_%'' ' else if TableType = 'VIEW' then Result := ' c.relkind = ''v'' AND n.nspname <> ''pg_catalog'' ' else if TableType = 'INDEX' then Result := ' c.relkind = ''i'' AND n.nspname NOT LIKE ''pg\\_%'' ' else if TableType = 'SEQUENCE' then Result := ' c.relkind = ''S'' ' else if TableType = 'SYSTEM TABLE' then Result := ' c.relkind = ''r'' AND n.nspname = ''pg_catalog'' ' else if TableType = 'SYSTEM TOAST TABLE' then Result := ' c.relkind = ''r'' AND n.nspname = ''pg_toast'' ' else if TableType = 'SYSTEM TOAST INDEX' then Result := ' c.relkind = ''i'' AND n.nspname = ''pg_toast'' ' else if TableType = 'SYSTEM VIEW' then Result := ' c.relkind = ''v'' AND n.nspname = ''pg_catalog'' ' else if TableType = 'SYSTEM INDEX' then Result := ' c.relkind = ''i'' AND n.nspname = ''pg_catalog'' ' else if TableType = 'TEMPORARY TABLE' then Result := ' c.relkind = ''r'' AND n.nspname LIKE ''pg\\_temp\\_%'' ' else if TableType = 'TEMPORARY INDEX' then Result := 'c.relkind = ''i'' AND n.nspname LIKE ''pg\\_temp\\_%'' '; end else begin if TableType = 'TABLE' then Result := ' c.relkind = ''r'' AND c.relname NOT LIKE ''pg\\_%'' ' else if TableType = 'VIEW' then Result := ' c.relkind = ''v'' AND c.relname NOT LIKE ''pg\\_%'' ' else if TableType = 'INDEX' then Result := ' c.relkind = ''i'' AND c.relname NOT LIKE ''pg\\_%'' ' else if TableType = 'SEQUENCE' then Result := ' c.relkind = ''S'' ' else if TableType = 'SYSTEM TABLE' then Result := ' c.relkind = ''r'' AND c.relname LIKE ''pg\\_%'' AND c.relname '+ 'NOT LIKE ''pg\\_toast\\_%'' AND c.relname NOT LIKE ''pg\\_temp\\_%'' ' else if TableType = 'SYSTEM TOAST TABLE' then Result := ' c.relkind = ''r'' AND c.relname LIKE ''pg\\_toast\\_%'' ' else if TableType = 'SYSTEM TOAST INDEX' then Result := ' c.relkind = ''i'' AND c.relname LIKE ''pg\\_toast\\_%'' ' else if TableType = 'SYSTEM VIEW' then Result := 'c.relkind = ''v'' AND c.relname LIKE ''pg\\_%''' else if TableType = 'SYSTEM INDEX' then begin Result := ' c.relkind = ''v'' AND c.relname LIKE ''pg\\_%'' AND '+ 'c.relname NOT LIKE ''pg\\_toast\\_%'' AND c.relname '+ 'NOT LIKE ''pg\\_temp\\_%'' ' end else if TableType = 'TEMPORARY TABLE' then Result := ' c.relkind = ''r'' AND c.relname LIKE ''pg\\_temp\\_%'' ' else if TableType = 'TEMPORARY INDEX' then Result := ' c.relkind = ''i'' AND c.relname LIKE ''pg\\_temp\\_%'' ' end; end; procedure TZPostgreSQLDatabaseMetadata.ParseACLArray( List: TStrings; AclString: string); var PrevChar: Char; InQuotes: Boolean; I, BeginIndex: Integer; begin if AclString = '' then Exit; InQuotes := False; PrevChar := ' '; BeginIndex := 2; for I := BeginIndex to Length(AclString) do begin if (AclString[I] = '"') and (PrevChar <> '\' ) then InQuotes := not InQuotes else if (AclString[I] = ',') and not InQuotes then begin List.Add(Copy(AclString, BeginIndex, I - BeginIndex)); BeginIndex := I+1; end; PrevChar := AclString[I]; end; // add last element removing the trailing "}" List.Add(Copy(AclString, BeginIndex, Length(AclString) - BeginIndex)); // Strip out enclosing quotes, if any. for I := 0 to List.Count-1 do begin if (List.Strings[i][1] = '"') and (List.Strings[i][Length(List.Strings[i])] = '"') then List.Strings[i] := Copy(List.Strings[i], 2, Length(List.Strings[i])-2); end; end; function TZPostgreSQLDatabaseMetadata.GetPrivilegeName(Permission: Char): string; begin case Permission of 'a': Result := 'INSERT'; 'r': Result := 'SELECT'; 'w': Result := 'UPDATE'; 'd': Result := 'DELETE'; 'R': Result := 'RULE'; 'x': Result := 'REFERENCES'; 't': Result := 'TRIGGER'; 'X': Result := 'EXECUTE'; 'U': Result := 'USAGE'; 'C': Result := 'CREATE'; 'T': Result := 'CREATE TEMP'; else Result := 'UNKNOWN'; end; end; function TZPostgreSQLDatabaseMetadata.GetIdentifierConvertor: IZIdentifierConvertor; begin Result:=TZPostgreSQLIdentifierConvertor.Create(Self); end; {** Gets the all supported CharacterSets: @return ResultSet - each row is a CharacterSetName and it's ID } function TZPostgreSQLDatabaseMetadata.UncachedGetCharacterSets: IZResultSet; //EgonHugeist begin Self.GetConnection.CreateStatement.Execute( ' CREATE OR REPLACE FUNCTION get_encodings() RETURNS INTEGER AS '''+ ' DECLARE '+ ' enc INTEGER := 0; '+ ' name VARCHAR; '+ ' BEGIN '+ ' CREATE TEMP TABLE encodings ( enc_code int, enc_name text ); '+ ' LOOP '+ ' SELECT INTO name pg_encoding_to_char( enc ); '+ ' IF( name = '''''''' ) THEN '+ ' EXIT; '+ ' ELSE '+ ' INSERT INTO encodings VALUES( enc, name ); '+ ' END IF; '+ ' enc := enc + 1; '+ ' END LOOP; '+ ' RETURN enc; '+ ' END; '+ ''' LANGUAGE ''plpgsql'';'); Self.GetConnection.CreateStatement.ExecuteQuery('select get_encodings();').Close; Result:=inherited UncachedGetCharacterSets; with Self.GetConnection.CreateStatement.ExecuteQuery( 'select * from encodings;') do begin while Next do begin Result.MoveToInsertRow; Result.UpdateString(1, GetString(2)); //CHARACTER_SET_NAME Result.UpdateShort(2, GetShort(1)); //CHARACTER_SET_ID Result.InsertRow; end; CLose; end; end; { TZPostgresIdentifierConvertor } function TZPostgreSQLIdentifierConvertor.ExtractQuote( const Value: string): string; var QuoteDelim: string; begin QuoteDelim := Metadata.GetDatabaseInfo.GetIdentifierQuoteString; Result := Value; if (QuoteDelim <> '') and (Value <> '') then if (Value[1]=QuoteDelim[1]) and (Value[PLongInt(NativeUInt(Value) - 4)^{fast Length()}]=QuoteDelim[1]) then begin Result:=copy(Value,2,length(Value)-2); Result:=StringReplace(Result,QuoteDelim+QuoteDelim,QuoteDelim,[rfReplaceAll]); end else Result := AnsiLowerCase(Value); end; function TZPostgreSQLIdentifierConvertor.IsQuoted(const Value: string): Boolean; var QuoteDelim: string; begin QuoteDelim := Metadata.GetDatabaseInfo.GetIdentifierQuoteString; Result := (QuoteDelim <> '') and (Value <> '') and (Value[1]=QuoteDelim[1]) and (Value[PLongInt(NativeUInt(Value) - 4)^{fast Length()}]=QuoteDelim[1]); end; function TZPostgreSQLIdentifierConvertor.IsSpecialCase( const Value: string): Boolean; var I: Integer; begin Result := False; if not CharInSet(Value[1], ['a'..'z','_']) then begin Result := True; Exit; end; for I := 1 to Length(Value) do begin if not CharInSet(Value[I], ['A'..'Z','a'..'z','0'..'9','_']) then begin Result := True; Break; end; end; end; function TZPostgreSQLIdentifierConvertor.Quote(const Value: string): string; var QuoteDelim: string; begin Result := Value; if IsCaseSensitive(Value) then begin QuoteDelim := Metadata.GetDatabaseInfo.GetIdentifierQuoteString; Result := QuoteDelim + StringReplace(Result,QuoteDelim,QuoteDelim+QuoteDelim,[rfReplaceAll]) + QuoteDelim; end; end; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcPostgreSqlResultSet.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { PostgreSQL Database Connectivity Classes } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcPostgreSqlResultSet; interface {$I ZDbc.inc} uses {$IFDEF WITH_TOBJECTLIST_INLINE}System.Types, System.Contnrs{$ELSE}Types{$ENDIF}, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, ZSysUtils, ZDbcIntfs, ZDbcResultSet, ZPlainPostgreSqlDriver, ZDbcLogging, ZDbcResultSetMetadata, ZCompatibility; type {** Implements PostgreSQL ResultSet. } TZPostgreSQLResultSet = class(TZAbstractResultSet) private FHandle: PZPostgreSQLConnect; FQueryHandle: PZPostgreSQLResult; FPlainDriver: IZPostgreSQLPlainDriver; FChunk_Size: Integer; FUndefinedVarcharAsStringLength: Integer; protected function InternalGetString(ColumnIndex: Integer): RawByteString; override; procedure Open; override; procedure DefinePostgreSQLToSQLType(ColumnInfo: TZColumnInfo; const TypeOid: Oid); public constructor Create(PlainDriver: IZPostgreSQLPlainDriver; Statement: IZStatement; SQL: string; Handle: PZPostgreSQLConnect; QueryHandle: PZPostgreSQLResult; Chunk_Size: Integer); procedure Close; override; function IsNull(ColumnIndex: Integer): Boolean; override; function GetUnicodeStream(ColumnIndex: Integer): TStream; override; function GetBoolean(ColumnIndex: Integer): Boolean; override; function GetByte(ColumnIndex: Integer): Byte; override; function GetShort(ColumnIndex: Integer): SmallInt; override; function GetInt(ColumnIndex: Integer): Integer; override; function GetLong(ColumnIndex: Integer): Int64; override; function GetFloat(ColumnIndex: Integer): Single; override; function GetDouble(ColumnIndex: Integer): Double; override; function GetBigDecimal(ColumnIndex: Integer): Extended; override; function GetBytes(ColumnIndex: Integer): TByteDynArray; override; function GetDate(ColumnIndex: Integer): TDateTime; override; function GetTime(ColumnIndex: Integer): TDateTime; override; function GetTimestamp(ColumnIndex: Integer): TDateTime; override; function GetBlob(ColumnIndex: Integer): IZBlob; override; function MoveAbsolute(Row: Integer): Boolean; override; end; {** Represents an interface, specific for PostgreSQL blobs. } IZPostgreSQLBlob = interface(IZBlob) ['{BDFB6B80-477D-4CB1-9508-9541FEA6CD72}'] function GetBlobOid: Oid; procedure ReadBlob; procedure WriteBlob; end; {** Implements external blob wrapper object for PostgreSQL. } TZPostgreSQLBlob = class(TZAbstractBlob, IZPostgreSQLBlob) private FHandle: PZPostgreSQLConnect; FBlobOid: Oid; FPlainDriver: IZPostgreSQLPlainDriver; FChunk_Size: Integer; public constructor Create(PlainDriver: IZPostgreSQLPlainDriver; Data: Pointer; Size: Integer; Handle: PZPostgreSQLConnect; BlobOid: Oid; Chunk_Size: Integer); destructor Destroy; override; function GetBlobOid: Oid; procedure ReadBlob; procedure WriteBlob; function IsEmpty: Boolean; override; function Clone: IZBlob; override; function GetStream: TStream; override; end; implementation uses Math, ZMessages, ZMatchPattern, ZDbcPostgreSql, ZDbcUtils, ZEncoding, ZDbcPostgreSqlUtils{$IFDEF WITH_UNITANSISTRINGS}, AnsiStrings{$ENDIF}; { TZPostgreSQLResultSet } {** Constructs this object, assignes main properties and opens the record set. @param PlainDriver a PostgreSQL plain driver. @param Statement a related SQL statement object. @param SQL a SQL statement. @param Handle a PostgreSQL specific query handle. } constructor TZPostgreSQLResultSet.Create(PlainDriver: IZPostgreSQLPlainDriver; Statement: IZStatement; SQL: string; Handle: PZPostgreSQLConnect; QueryHandle: PZPostgreSQLResult; Chunk_Size: Integer); begin inherited Create(Statement, SQL, nil, Statement.GetConnection.GetConSettings); FHandle := Handle; FQueryHandle := QueryHandle; FPlainDriver := PlainDriver; ResultSetConcurrency := rcReadOnly; FChunk_Size := Chunk_Size; //size of red/write lob chunks FUndefinedVarcharAsStringLength := (Statement.GetConnection as IZPostgreSQLConnection).GetUndefinedVarcharAsStringLength; Open; end; {** Converts a PostgreSQL native types into ZDBC SQL types. @param ColumnIndex a column index. @param ColumnInfo a column description object. @param TypeOid a type oid. @return a SQL undepended type. } procedure TZPostgreSQLResultSet.DefinePostgreSQLToSQLType( ColumnInfo: TZColumnInfo; const TypeOid: Oid); var SQLType: TZSQLType; Connection: IZPostgreSQLConnection; begin Connection := Statement.GetConnection as IZPostgreSQLConnection; case TypeOid of 790: ColumnInfo.Currency := True; { money } 19: if (Connection.GetServerMajorVersion < 7) or ((Connection.GetServerMajorVersion = 7) and (Connection.GetServerMinorVersion < 3)) then ColumnInfo.Precision := 32 else ColumnInfo.Precision := 64; { name } 650: ColumnInfo.Precision := 100; { cidr } 869: ColumnInfo.Precision := 100; { inet } 829: ColumnInfo.Precision := 17; { macaddr } 1186: ColumnInfo.Precision := 32; { interval } 24: ColumnInfo.Precision := 64; { regproc } // M.A. was 10 17:{ bytea } if Connection.IsOidAsBlob then ColumnInfo.Precision := 256; end; SQLType := PostgreSQLToSQLType(ConSettings, Connection.IsOidAsBlob, TypeOid); if SQLType <> stUnknown then ColumnInfo.ColumnType := SQLType else begin ColumnInfo.ColumnType := stString; ColumnInfo.Precision := 255; ColumnInfo.ReadOnly := True; end; end; {** Opens this recordset. } procedure TZPostgreSQLResultSet.Open; var I, FieldCount: Integer; ColumnInfo: TZColumnInfo; FieldMode, FieldSize, FieldType: Integer; TableInfo: PZPGTableInfo; Connection: IZPostgreSQLConnection; begin if ResultSetConcurrency = rcUpdatable then raise EZSQLException.Create(SLiveResultSetsAreNotSupported); if not Assigned(FQueryHandle) then raise EZSQLException.Create(SCanNotRetrieveResultSetData); Connection := Statement.GetConnection as IZPostgreSQLConnection; LastRowNo := FPlainDriver.GetRowCount(FQueryHandle); { Fills the column info. } ColumnsInfo.Clear; FieldCount := FPlainDriver.GetFieldCount(FQueryHandle); for I := 0 to FieldCount - 1 do begin ColumnInfo := TZColumnInfo.Create; with ColumnInfo do begin if Statement.GetResultSetConcurrency = rcUpdatable then //exclude system-tables and if no updates happen -> useless TableInfo := Connection.GetTableInfo(FPlainDriver.GetFieldTableOID(FQueryHandle, I),FieldCount) else TableInfo := nil; if TableInfo = nil then begin SchemaName := ''; ColumnName := ''; TableName := ''; end else begin SchemaName := TableInfo^.Schema; TableName := TableInfo^.Name; ColumnName := TableInfo^.ColNames[FplainDriver.GetFieldTableColIdx(FQueryHandle, I) - 1]; end; ColumnLabel := ZDbcString(FPlainDriver.GetFieldName(FQueryHandle, I)); ColumnDisplaySize := 0; Scale := 0; Precision := 0; AutoIncrement := False; Signed := False; Nullable := ntNullable; FieldType := FPlainDriver.GetFieldType(FQueryHandle, I); DefinePostgreSQLToSQLType(ColumnInfo, FieldType); if Precision = 0 then begin FieldMode := FPlainDriver.GetFieldMode(FQueryHandle, I); FieldSize := FPlainDriver.GetFieldSize(FQueryHandle, I); Precision := Max(Max(FieldMode - 4, FieldSize), 0); if ColumnType in [stString, stUnicodeString] then {begin patch: varchar() is equal to text!} if ( FieldMode = -1 ) and ( FieldSize = -1 ) and ( FieldType = 1043) then if FUndefinedVarcharAsStringLength > 0 then Precision := GetFieldSize(ColumnType, ConSettings, FUndefinedVarcharAsStringLength, ConSettings.ClientCodePage^.CharWidth, nil, False) else DefinePostgreSQLToSQLType(ColumnInfo, 25) //assume text instead! else if ( (ColumnLabel = 'expr') or ( Precision = 0 ) ) then Precision := GetFieldSize(ColumnType, ConSettings, 255, ConSettings.ClientCodePage^.CharWidth, nil, True) else Precision := GetFieldSize(ColumnType, ConSettings, Precision, ConSettings.ClientCodePage^.CharWidth, @ColumnDisplaySize); end; end; ColumnsInfo.Add(ColumnInfo); end; inherited Open; end; {** Releases this ResultSet object's database and JDBC resources immediately instead of waiting for this to happen when it is automatically closed.

Note: A ResultSet object is automatically closed by the Statement object that generated it when that Statement object is closed, re-executed, or is used to retrieve the next result from a sequence of multiple results. A ResultSet object is also automatically closed when it is garbage collected. } procedure TZPostgreSQLResultSet.Close; begin if FQueryHandle <> nil then FPlainDriver.Clear(FQueryHandle); FHandle := nil; FQueryHandle := nil; inherited Close; end; {** Indicates if the value of the designated column in the current row of this ResultSet object is Null. @param columnIndex the first column is 1, the second is 2, ... @return if the value is SQL NULL, the value returned is true. false otherwise. } function TZPostgreSQLResultSet.IsNull(ColumnIndex: Integer): Boolean; begin {$IFNDEF DISABLE_CHECKING} CheckClosed; if (RowNo < 1) or (RowNo > LastRowNo) then raise EZSQLException.Create(SRowDataIsNotAvailable); {$ENDIF} Result := FPlainDriver.GetIsNull(FQueryHandle, RowNo - 1, ColumnIndex - 1) <> 0; end; {** Gets the value of the designated column in the current row of this ResultSet object as a String in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZPostgreSQLResultSet.InternalGetString(ColumnIndex: Integer): RawByteString; {$IFDEF WITH_RAWBYTESTRING} var Len: Integer; {$ENDIF} begin ColumnIndex := ColumnIndex - 1; LastWasNull := FPlainDriver.GetIsNull(FQueryHandle, RowNo - 1, ColumnIndex) <> 0; {$IFDEF WITH_RAWBYTESTRING} Len := FPlainDriver.GetLength(FQueryHandle, RowNo - 1, ColumnIndex); SetLength(Result, Len); Move(FPlainDriver.GetValue(FQueryHandle, RowNo - 1, ColumnIndex)^, PAnsiChar(Result)^, Len); {$ELSE} SetString(Result, FPlainDriver.GetValue(FQueryHandle, RowNo - 1, ColumnIndex), FPlainDriver.GetLength(FQueryHandle, RowNo - 1, ColumnIndex)); {$ENDIF} if FPlainDriver.GetFieldType(FQueryHandle, ColumnIndex) = 1042 then Result := {$IFDEF WITH_UNITANSISTRINGS}AnsiStrings.{$ENDIF}TrimRight(Result); end; {** Gets the value of the designated column in the current row of this ResultSet object as a boolean in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is false } function TZPostgreSQLResultSet.GetBoolean(ColumnIndex: Integer): Boolean; var Temp: string; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stBoolean); {$ENDIF} Temp := UpperCase(String(InternalGetString(ColumnIndex))); Result := (Temp = 'Y') or (Temp = 'YES') or (Temp = 'T') or (Temp = 'TRUE') or (StrToIntDef(String(Temp), 0) <> 0); end; {** Gets the value of the designated column in the current row of this ResultSet object as a byte in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZPostgreSQLResultSet.GetByte(ColumnIndex: Integer): Byte; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stByte); {$ENDIF} Result := Byte(StrToIntDef(String(InternalGetString(ColumnIndex)), 0)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a short in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZPostgreSQLResultSet.GetShort(ColumnIndex: Integer): SmallInt; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stShort); {$ENDIF} Result := SmallInt(StrToIntDef(String(InternalGetString(ColumnIndex)), 0)); end; {** Gets the value of the designated column in the current row of this ResultSet object as an int in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZPostgreSQLResultSet.GetInt(ColumnIndex: Integer): Integer; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stInteger); {$ENDIF} Result := StrToIntDef(String(InternalGetString(ColumnIndex)), 0); end; {** Gets the value of the designated column in the current row of this ResultSet object as a long in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZPostgreSQLResultSet.GetLong(ColumnIndex: Integer): Int64; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stLong); {$ENDIF} Result := StrToInt64Def(String(InternalGetString(ColumnIndex)), 0); end; {** Gets the value of the designated column in the current row of this ResultSet object as a float in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZPostgreSQLResultSet.GetFloat(ColumnIndex: Integer): Single; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stFloat); {$ENDIF} Result := SQLStrToFloatDef(InternalGetString(ColumnIndex), 0); end; {** Gets the value of the designated column in the current row of this ResultSet object as a double in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZPostgreSQLResultSet.GetDouble(ColumnIndex: Integer): Double; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stDouble); {$ENDIF} Result := SQLStrToFloatDef(InternalGetString(ColumnIndex), 0); end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.BigDecimal in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @param scale the number of digits to the right of the decimal point @return the column value; if the value is SQL NULL, the value returned is null } function TZPostgreSQLResultSet.GetBigDecimal(ColumnIndex: Integer): Extended; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stBigDecimal); {$ENDIF} Result := SQLStrToFloatDef(InternalGetString(ColumnIndex), 0); end; {** Gets the value of the designated column in the current row of this ResultSet object as a byte array in the Java programming language. The bytes represent the raw values returned by the driver. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZPostgreSQLResultSet.GetBytes(ColumnIndex: Integer): TByteDynArray; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stBytes); {$ENDIF} Result := StrToBytes(DecodeString(InternalGetString(ColumnIndex))); end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Date object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZPostgreSQLResultSet.GetDate(ColumnIndex: Integer): TDateTime; var Value: string; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stDate); {$ENDIF} Value := String(InternalGetString(ColumnIndex)); if IsMatch('????-??-??*', Value) then Result := Trunc(AnsiSQLDateToDateTime(Value)) else Result := Trunc(TimestampStrToDateTime(Value)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Time object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZPostgreSQLResultSet.GetTime(ColumnIndex: Integer): TDateTime; var Value: string; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stTime); {$ENDIF} Value := String(InternalGetString(ColumnIndex)); if IsMatch('*??:??:??*', Value) then Result := Frac(AnsiSQLDateToDateTime(Value)) else Result := Frac(TimestampStrToDateTime(Value)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null @exception SQLException if a database access error occurs } function TZPostgreSQLResultSet.GetTimestamp(ColumnIndex: Integer): TDateTime; var Value: string; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stTimestamp); {$ENDIF} Value := String(InternalGetString(ColumnIndex)); if IsMatch('????-??-??*', Value) then Result := AnsiSQLDateToDateTime(Value) else Result := TimestampStrToDateTime(Value); end; function TZPostgreSQLResultSet.GetUnicodeStream(ColumnIndex: Integer): TStream; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stUnicodeStream); {$ENDIF} Result := TStringStream.Create(InternalGetString(ColumnIndex)); end; {** Returns the value of the designated column in the current row of this ResultSet object as a Blob object in the Java programming language. @param ColumnIndex the first column is 1, the second is 2, ... @return a Blob object representing the SQL BLOB value in the specified column } function TZPostgreSQLResultSet.GetBlob(ColumnIndex: Integer): IZBlob; var BlobOid: Oid; Stream: TStream; Connection: IZConnection; WS: ZWideString; begin {$IFNDEF DISABLE_CHECKING} CheckBlobColumn(ColumnIndex); CheckClosed; if (RowNo < 1) or (RowNo > LastRowNo) then raise EZSQLException.Create(SRowDataIsNotAvailable); {$ENDIF} Connection := Statement.GetConnection; if (GetMetadata.GetColumnType(ColumnIndex) = stBinaryStream) and (Connection as IZPostgreSQLConnection).IsOidAsBlob then begin if FPlainDriver.GetIsNull(FQueryHandle, RowNo - 1, ColumnIndex - 1) = 0 then BlobOid := StrToIntDef(String(InternalGetString(ColumnIndex)), 0) else BlobOid := 0; Result := TZPostgreSQLBlob.Create(FPlainDriver, nil, 0, FHandle, BlobOid, FChunk_Size); end else begin if FPlainDriver.GetIsNull(FQueryHandle, RowNo - 1, ColumnIndex - 1) = 0 then begin Stream := nil; try case GetMetadata.GetColumnType(ColumnIndex) of stBinaryStream: Stream := TStringStream.Create(FPlainDriver.DecodeBYTEA(InternalGetString(ColumnIndex), (Connection as IZPostgreSQLConnection).Is_bytea_output_hex, Self.FHandle)); stAsciiStream: Stream := TStringStream.Create(GetValidatedAnsiString(InternalGetString(ColumnIndex), ConSettings, True)); stUnicodeStream: begin WS := ZDbcUnicodeString(InternalGetString(ColumnIndex)); Stream := WideStringStream(Ws); end; end; Result := TZAbstractBlob.CreateWithStream(Stream, GetStatement.GetConnection, GetMetadata.GetColumnType(ColumnIndex) = stUnicodeStream); finally if Assigned(Stream) then Stream.Free; end; end else Result := TZAbstractBlob.CreateWithStream(nil, GetStatement.GetConnection); end; end; {** Moves the cursor to the given row number in this ResultSet object.

If the row number is positive, the cursor moves to the given row number with respect to the beginning of the result set. The first row is row 1, the second is row 2, and so on.

If the given row number is negative, the cursor moves to an absolute row position with respect to the end of the result set. For example, calling the method absolute(-1) positions the cursor on the last row; calling the method absolute(-2) moves the cursor to the next-to-last row, and so on.

An attempt to position the cursor beyond the first/last row in the result set leaves the cursor before the first row or after the last row.

Note: Calling absolute(1) is the same as calling first(). Calling absolute(-1) is the same as calling last(). @return true if the cursor is on the result set; false otherwise } function TZPostgreSQLResultSet.MoveAbsolute(Row: Integer): Boolean; begin {$IFNDEF DISABLE_CHECKING} CheckClosed; {$ENDIF} { Checks for maximum row. } Result := False; if (MaxRows > 0) and (Row > MaxRows) then Exit; { Processes negative rows. } if Row < 0 then begin Row := LastRowNo - Row + 1; if Row < 0 then Row := 0; end; if (ResultSetType <> rtForwardOnly) or (Row >= RowNo) then begin if (Row >= 0) and (Row <= LastRowNo + 1) then begin RowNo := Row; Result := (Row >= 1) and (Row <= LastRowNo); end else Result := False; end else RaiseForwardOnlyException; end; { TZPostgreSQLBlob } {** Constructs this class and assignes the main properties. @param PlainDriver a PostgreSQL plain driver. @param Data a pointer to the blobdata. @param Size the size of the blobdata. @param Handle a PostgreSQL connection reference. } constructor TZPostgreSQLBlob.Create(PlainDriver: IZPostgreSQLPlainDriver; Data: Pointer; Size: Integer; Handle: PZPostgreSQLConnect; BlobOid: Oid; Chunk_Size: Integer); begin inherited CreateWithData(Data, Size, nil); FHandle := Handle; FBlobOid := BlobOid; FPlainDriver := PlainDriver; FChunk_Size := Chunk_Size; end; {** Destroys this object and cleanups the memory. } destructor TZPostgreSQLBlob.Destroy; begin inherited Destroy; end; {** Gets the blob handle oid. @return the blob handle oid. } function TZPostgreSQLBlob.GetBlobOid: Oid; begin Result := FBlobOid; end; {** Reads the blob by the blob handle. } procedure TZPostgreSQLBlob.ReadBlob; var BlobHandle: Integer; Buffer: array[0..1024] of AnsiChar; ReadNum: Integer; ReadStream: TMemoryStream; begin if not Updated and (FBlobOid > 0) then begin BlobHandle := FPlainDriver.OpenLargeObject(FHandle, FBlobOid, INV_READ); CheckPostgreSQLError(nil, FPlainDriver, FHandle, lcOther, 'Read Large Object',nil); ReadStream := nil; if BlobHandle >= 0 then begin ReadStream := TMemoryStream.Create; repeat ReadNum := FPlainDriver.ReadLargeObject(FHandle, BlobHandle, Buffer, 1024); if ReadNum > 0 then begin ReadStream.SetSize(ReadStream.Size + ReadNum); ReadStream.Write(Buffer, ReadNum); end; until ReadNum < 1024; FPlainDriver.CloseLargeObject(FHandle, BlobHandle); ReadStream.Position := 0; end; SetStream(ReadStream); if ReadStream <> nil then ReadStream.free; end; end; {** Writes the blob by the blob handle. } procedure TZPostgreSQLBlob.WriteBlob; var BlobHandle: Integer; Position: Integer; Size: Integer; begin { Checks for empty blob. } if IsEmpty then begin FBlobOid := 0; Exit; end; { Creates a new large object. } if FBlobOid = 0 then begin FBlobOid := FPlainDriver.CreateLargeObject(FHandle, INV_WRITE); CheckPostgreSQLError(nil, FPlainDriver, FHandle, lcOther, 'Create Large Object',nil); end; { Opens and writes a large object. } BlobHandle := FPlainDriver.OpenLargeObject(FHandle, FBlobOid, INV_WRITE); CheckPostgreSQLError(nil, FPlainDriver, FHandle, lcOther, 'Open Large Object',nil); Position := 0; while Position < BlobSize do begin if (BlobSize - Position) < FChunk_Size then Size := BlobSize - Position else Size := FChunk_Size; FPlainDriver.WriteLargeObject(FHandle, BlobHandle, Pointer(NativeUInt(BlobData) + NativeUInt(Position)), Size); CheckPostgreSQLError(nil, FPlainDriver, FHandle, lcOther, 'Write Large Object',nil); Inc(Position, Size); end; FPlainDriver.CloseLargeObject(FHandle, BlobHandle); CheckPostgreSQLError(nil, FPlainDriver, FHandle, lcOther, 'Close Large Object',nil); end; {** Checks if this blob has an empty content. @return True if this blob is empty. } function TZPostgreSQLBlob.IsEmpty: Boolean; begin ReadBlob; Result := inherited IsEmpty; end; {** Clones this blob object. @return a clonned blob object. } function TZPostgreSQLBlob.Clone: IZBlob; begin Result := TZPostgreSQLBlob.Create(FPlainDriver, BlobData, BlobSize, FHandle, FBlobOid, FChunk_Size); end; {** Gets the associated stream object. @return an associated or newly created stream object. } function TZPostgreSQLBlob.GetStream: TStream; begin ReadBlob; Result := inherited GetStream; end; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcPostgreSqlStatement.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { PostgreSQL Database Connectivity Classes } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcPostgreSqlStatement; interface {$I ZDbc.inc} uses Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, Types, ZSysUtils, ZDbcIntfs, ZDbcStatement, ZDbcLogging, ZPlainPostgreSqlDriver, ZCompatibility, ZVariant, ZDbcGenericResolver, ZDbcCachedResultSet, ZDbcPostgreSql; type {** Defines a PostgreSQL specific statement. } IZPostgreSQLStatement = interface(IZStatement) ['{E4FAFD96-97CC-4247-8ECC-6E0A168FAFE6}'] function IsOidAsBlob: Boolean; end; {** Implements Generic PostgreSQL Statement. } TZPostgreSQLStatement = class(TZAbstractStatement, IZPostgreSQLStatement) private FPlainDriver: IZPostgreSQLPlainDriver; FOidAsBlob: Boolean; protected function CreateResultSet(const SQL: string; QueryHandle: PZPostgreSQLResult): IZResultSet; function GetConnectionHandle():PZPostgreSQLConnect; public constructor Create(PlainDriver: IZPostgreSQLPlainDriver; Connection: IZConnection; Info: TStrings); destructor Destroy; override; function ExecuteQuery(const SQL: RawByteString): IZResultSet; override; function ExecuteUpdate(const SQL: RawByteString): Integer; override; function Execute(const SQL: RawByteString): Boolean; override; function IsOidAsBlob: Boolean; end; {$IFDEF ZEOS_TEST_ONLY} {** Implements Emulated Prepared SQL Statement. } TZPostgreSQLEmulatedPreparedStatement = class(TZEmulatedPreparedStatement) private FPlainDriver: IZPostgreSQLPlainDriver; Foidasblob: Boolean; protected function CreateExecStatement: IZStatement; override; function PrepareAnsiSQLParam(ParamIndex: Integer): RawByteString; override; function GetConnectionHandle: PZPostgreSQLConnect; public constructor Create(PlainDriver: IZPostgreSQLPlainDriver; Connection: IZConnection; const SQL: string; Info: TStrings); end; {$ENDIF} TZPostgreSQLPreparedStatement = class(TZAbstractPreparedStatement) private FPlanName: String; FRawPlanName: RawByteString; FPostgreSQLConnection: IZPostgreSQLConnection; FPlainDriver: IZPostgreSQLPlainDriver; QueryHandle: PZPostgreSQLResult; Foidasblob: Boolean; FConnectionHandle: PZPostgreSQLConnect; Findeterminate_datatype: Boolean; FCachedQuery: TStrings; function CreateResultSet(QueryHandle: PZPostgreSQLResult): IZResultSet; protected procedure SetPlanNames; virtual; abstract; public constructor Create(PlainDriver: IZPostgreSQLPlainDriver; Connection: IZPostgreSQLConnection; const SQL: string; Info: TStrings); destructor Destroy; override; end; {** EgonHugeist: Implements Prepared SQL Statement with AnsiString usage } TZPostgreSQLClassicPreparedStatement = class(TZPostgreSQLPreparedStatement) private FExecSQL: RawByteString; function GetAnsiSQLQuery: RawByteString; protected procedure SetPlanNames; override; function PrepareAnsiSQLParam(ParamIndex: Integer; Escaped: Boolean): RawByteString; procedure PrepareInParameters; override; procedure BindInParameters; override; procedure UnPrepareInParameters; override; public procedure Prepare; override; function ExecuteQuery(const SQL: RawByteString): IZResultSet; override; function ExecuteUpdate(const SQL: RawByteString): Integer; override; function Execute(const SQL: RawByteString): Boolean; override; function ExecuteQueryPrepared: IZResultSet; override; function ExecuteUpdatePrepared: Integer; override; function ExecutePrepared: Boolean; override; end; {** EgonHugeist: Implements Prepared SQL Statement based on Protocol3 ServerVersion 7.4Up and ClientVersion 8.0Up. with C++API usage} TZPostgreSQLCAPIPreparedStatement = class(TZPostgreSQLPreparedStatement) private FPQparamValues: TPQparamValues; FPQparamLengths: TPQparamLengths; FPQparamFormats: TPQparamFormats; function ExectuteInternal(const SQL: RawByteString; const LogSQL: String; const LoggingCategory: TZLoggingCategory): PZPostgreSQLResult; protected procedure SetPlanNames; override; procedure SetASQL(const Value: RawByteString); override; procedure SetWSQL(const Value: ZWideString); override; procedure PrepareInParameters; override; procedure BindInParameters; override; procedure UnPrepareInParameters; override; function PrepareAnsiSQLQuery: RawByteString; public procedure Prepare; override; procedure Unprepare; override; function ExecuteQueryPrepared: IZResultSet; override; function ExecuteUpdatePrepared: Integer; override; function ExecutePrepared: Boolean; override; end; {** Implements callable Postgresql Statement. } TZPostgreSQLCallableStatement = class(TZAbstractCallableStatement) private Foidasblob: Boolean; FPlainDriver: IZPostgreSQLPlainDriver; function GetProcedureSql: string; function FillParams(const ASql: String): RawByteString; function PrepareAnsiSQLParam(ParamIndex: Integer): RawByteString; protected function GetConnectionHandle:PZPostgreSQLConnect; function GetPlainDriver:IZPostgreSQLPlainDriver; function CreateResultSet(const SQL: string; QueryHandle: PZPostgreSQLResult): IZResultSet; procedure FetchOutParams(ResultSet: IZResultSet); procedure TrimInParameters; override; public constructor Create(Connection: IZConnection; const SQL: string; Info: TStrings); function ExecuteQuery(const SQL: RawByteString): IZResultSet; override; function ExecuteUpdate(const SQL: RawByteString): Integer; override; function ExecuteQueryPrepared: IZResultSet; override; function ExecuteUpdatePrepared: Integer; override; end; {** Implements a specialized cached resolver for PostgreSQL. } TZPostgreSQLCachedResolver = class(TZGenericCachedResolver, IZCachedResolver) protected function CheckKeyColumn(ColumnIndex: Integer): Boolean; override; end; implementation uses ZMessages, ZDbcPostgreSqlResultSet, ZDbcPostgreSqlUtils, ZTokenizer, ZEncoding{$IFDEF WITH_UNITANSISTRINGS}, AnsiStrings{$ENDIF}; { TZPostgreSQLStatement } {** Constructs this object and assignes the main properties. @param PlainDriver a PostgreSQL plain driver. @param Connection a database connection object. @param Info a statement parameters. @param Handle a connection handle pointer. } constructor TZPostgreSQLStatement.Create(PlainDriver: IZPostgreSQLPlainDriver; Connection: IZConnection; Info: TStrings); begin inherited Create(Connection, Info); FPlainDriver := PlainDriver; ResultSetType := rtScrollInsensitive; { Processes connection properties. } FOidAsBlob := StrToBoolEx(Self.Info.Values['oidasblob']) or (Connection as IZPostgreSQLConnection).IsOidAsBlob; end; {** Destroys this object and cleanups the memory. } destructor TZPostgreSQLStatement.Destroy; begin inherited Destroy; end; {** Checks is oid should be treated as Large Object. @return True if oid should represent a Large Object. } function TZPostgreSQLStatement.IsOidAsBlob: Boolean; begin Result := FOidAsBlob; end; {** Creates a result set based on the current settings. @return a created result set object. } function TZPostgreSQLStatement.CreateResultSet(const SQL: string; QueryHandle: PZPostgreSQLResult): IZResultSet; var NativeResultSet: TZPostgreSQLResultSet; CachedResultSet: TZCachedResultSet; ConnectionHandle: PZPostgreSQLConnect; begin ConnectionHandle := GetConnectionHandle(); NativeResultSet := TZPostgreSQLResultSet.Create(FPlainDriver, Self, SQL, ConnectionHandle, QueryHandle, ChunkSize); NativeResultSet.SetConcurrency(rcReadOnly); if GetResultSetConcurrency = rcUpdatable then begin CachedResultSet := TZCachedResultSet.Create(NativeResultSet, SQL, nil, ConSettings); CachedResultSet.SetConcurrency(rcUpdatable); CachedResultSet.SetResolver(TZPostgreSQLCachedResolver.Create( Self, NativeResultSet.GetMetadata)); Result := CachedResultSet; end else Result := NativeResultSet; end; {** Executes an SQL statement that returns a single ResultSet object. @param sql typically this is a static SQL SELECT statement @return a ResultSet object that contains the data produced by the given query; never null } function TZPostgreSQLStatement.ExecuteQuery(const SQL: RawByteString): IZResultSet; var QueryHandle: PZPostgreSQLResult; ConnectionHandle: PZPostgreSQLConnect; begin Result := nil; ConnectionHandle := GetConnectionHandle(); ASQL := SQL; //Preprepares the SQL and Sets the AnsiSQL QueryHandle := FPlainDriver.ExecuteQuery(ConnectionHandle, PAnsiChar(ASQL)); CheckPostgreSQLError(Connection, FPlainDriver, ConnectionHandle, lcExecute, SSQL, QueryHandle); DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, LogSQL); if QueryHandle <> nil then Result := CreateResultSet(LogSQL, QueryHandle) else Result := nil; end; {** Executes an SQL INSERT, UPDATE or DELETE statement. In addition, SQL statements that return nothing, such as SQL DDL statements, can be executed. @param sql an SQL INSERT, UPDATE or DELETE statement or an SQL statement that returns nothing @return either the row count for INSERT, UPDATE or DELETE statements, or 0 for SQL statements that return nothing } function TZPostgreSQLStatement.ExecuteUpdate(const SQL: RawByteString): Integer; var QueryHandle: PZPostgreSQLResult; ConnectionHandle: PZPostgreSQLConnect; begin Result := -1; ConnectionHandle := GetConnectionHandle(); ASQL := SQL; //Prepares SQL if needed QueryHandle := FPlainDriver.ExecuteQuery(ConnectionHandle, PAnsiChar(ASQL)); CheckPostgreSQLError(Connection, FPlainDriver, ConnectionHandle, lcExecute, LogSQL, QueryHandle); DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, LogSQL); if QueryHandle <> nil then begin Result := StrToIntDef(String(FPlainDriver.GetCommandTuples(QueryHandle)), 0); FPlainDriver.Clear(QueryHandle); end; { Autocommit statement. } if Connection.GetAutoCommit then Connection.Commit; end; {** Executes an SQL statement that may return multiple results. Under some (uncommon) situations a single SQL statement may return multiple result sets and/or update counts. Normally you can ignore this unless you are (1) executing a stored procedure that you know may return multiple results or (2) you are dynamically executing an unknown SQL string. The methods execute, getMoreResults, getResultSet, and getUpdateCount let you navigate through multiple results. The execute method executes an SQL statement and indicates the form of the first result. You can then use the methods getResultSet or getUpdateCount to retrieve the result, and getMoreResults to move to any subsequent result(s). @param sql any SQL statement @return true if the next result is a ResultSet object; false if it is an update count or there are no more results } function TZPostgreSQLStatement.Execute(const SQL: RawByteString): Boolean; var QueryHandle: PZPostgreSQLResult; ResultStatus: TZPostgreSQLExecStatusType; ConnectionHandle: PZPostgreSQLConnect; begin ASQL := SQL; ConnectionHandle := GetConnectionHandle(); QueryHandle := FPlainDriver.ExecuteQuery(ConnectionHandle, PAnsiChar(ASQL)); CheckPostgreSQLError(Connection, FPlainDriver, ConnectionHandle, lcExecute, LogSQL, QueryHandle); DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, LogSQL); { Process queries with result sets } ResultStatus := FPlainDriver.GetResultStatus(QueryHandle); case ResultStatus of PGRES_TUPLES_OK: begin Result := True; LastResultSet := CreateResultSet(LogSQL, QueryHandle); end; PGRES_COMMAND_OK: begin Result := False; LastUpdateCount := StrToIntDef(String( FPlainDriver.GetCommandTuples(QueryHandle)), 0); FPlainDriver.Clear(QueryHandle); end; else begin Result := False; LastUpdateCount := StrToIntDef(String( FPlainDriver.GetCommandTuples(QueryHandle)), 0); FPlainDriver.Clear(QueryHandle); end; end; { Autocommit statement. } if not Result and Connection.GetAutoCommit then Connection.Commit; end; {** Provides connection handle from the associated IConnection } function TZPostgreSQLStatement.GetConnectionHandle():PZPostgreSQLConnect; begin if Self.Connection = nil then Result := nil else Result := (Connection as IZPostgreSQLConnection).GetConnectionHandle; end; {$IFDEF ZEOS_TEST_ONLY} { TZPostgreSQLEmulatedPreparedStatement } {** Constructs this object and assignes the main properties. @param PlainDriver a PostgreSQL plain driver. @param Connection a database connection object. @param Info a statement parameters. @param Handle a connection handle pointer. } constructor TZPostgreSQLEmulatedPreparedStatement.Create( PlainDriver: IZPostgreSQLPlainDriver; Connection: IZConnection; const SQL: string; Info: TStrings); begin inherited Create(Connection, SQL, Info); FPlainDriver := PlainDriver; ResultSetType := rtScrollInsensitive; Foidasblob := StrToBoolDef(Self.Info.Values['oidasblob'], False) or (Connection as IZPostgreSQLConnection).IsOidAsBlob; end; {** Creates a temporary statement which executes queries. @return a created statement object. } function TZPostgreSQLEmulatedPreparedStatement.CreateExecStatement: IZStatement; begin Result := TZPostgreSQLStatement.Create(FPlainDriver, Connection, Info); end; {** Prepares an SQL parameter for the query. @param ParameterIndex the first parameter is 1, the second is 2, ... @return a string representation of the parameter. } function TZPostgreSQLEmulatedPreparedStatement.PrepareAnsiSQLParam( ParamIndex: Integer): RawByteString; begin if InParamCount <= ParamIndex then raise EZSQLException.Create(SInvalidInputParameterCount); Result := PGPrepareAnsiSQLParam(InParamValues[ParamIndex], (Connection as IZPostgreSQLConnection), FPlainDriver, ChunkSize, InParamTypes[ParamIndex], Foidasblob, True, False, ConSettings); end; {** Provides connection handle from the associated IConnection } function TZPostgreSQLEmulatedPreparedStatement.GetConnectionHandle:PZPostgreSQLConnect; begin if Self.Connection = nil then Result := nil else Result := (self.Connection as IZPostgreSQLConnection).GetConnectionHandle; end; {$ENDIF} { TZPostgreSQLPreparedStatement } {** Creates a result set based on the current settings. @param QueryHandle the Postgres query handle @return a created result set object. } constructor TZPostgreSQLPreparedStatement.Create(PlainDriver: IZPostgreSQLPlainDriver; Connection: IZPostgreSQLConnection; const SQL: string; Info: TStrings); begin inherited Create(Connection, SQL, Info); Foidasblob := StrToBoolDef(Self.Info.Values['oidasblob'], False) or (Connection as IZPostgreSQLConnection).IsOidAsBlob; FPostgreSQLConnection := Connection; FPlainDriver := PlainDriver; ResultSetType := rtScrollInsensitive; FConnectionHandle := Connection.GetConnectionHandle; Findeterminate_datatype := False; SetPlanNames; end; destructor TZPostgreSQLPreparedStatement.Destroy; begin if Assigned(FCachedQuery) then FReeAndNil(FCachedQuery); inherited Destroy; end; function TZPostgreSQLPreparedStatement.CreateResultSet(QueryHandle: Pointer): IZResultSet; var NativeResultSet: TZPostgreSQLResultSet; CachedResultSet: TZCachedResultSet; begin NativeResultSet := TZPostgreSQLResultSet.Create(FPlainDriver, Self, Self.SQL, FConnectionHandle, QueryHandle, ChunkSize); NativeResultSet.SetConcurrency(rcReadOnly); if GetResultSetConcurrency = rcUpdatable then begin CachedResultSet := TZCachedResultSet.Create(NativeResultSet, Self.SQL, nil, ConSettings); CachedResultSet.SetConcurrency(rcUpdatable); CachedResultSet.SetResolver(TZPostgreSQLCachedResolver.Create( Self, NativeResultSet.GetMetadata)); Result := CachedResultSet; end else Result := NativeResultSet; end; { TZPostgreSQLClassicPreparedStatement } function TZPostgreSQLClassicPreparedStatement.GetAnsiSQLQuery; var I: Integer; ParamIndex: Integer; Tokens: TStrings; function TokenizeSQLQuery: TStrings; var I: Integer; Tokens: TStrings; Temp: string; begin if FCachedQuery = nil then begin FCachedQuery := TStringList.Create; if Pos('?', SQL) > 0 then begin Tokens := Connection.GetDriver.GetTokenizer.TokenizeBufferToList(SQL, [toUnifyWhitespaces]); try Temp := ''; for I := 0 to Tokens.Count - 1 do begin if Tokens[I] = '?' then begin FCachedQuery.Add(Temp); FCachedQuery.AddObject('?', Self); Temp := ''; end else Temp := Temp + Tokens[I]; end; if Temp <> '' then FCachedQuery.Add(Temp); finally Tokens.Free; end; end else FCachedQuery.Add(SQL); end; Result := FCachedQuery; end; begin ParamIndex := 0; Result := ''; Tokens := TokenizeSQLQuery; for I := 0 to Tokens.Count - 1 do begin if Tokens[I] = '?' then begin Result := Result + PrepareAnsiSQLParam(ParamIndex, True); Inc(ParamIndex); end else Result := Result + ZPlainString(Tokens[I]); end; end; procedure TZPostgreSQLClassicPreparedStatement.SetPlanNames; begin FPlanName := '"'+IntToStr(Hash(ASQL)+Cardinal(FStatementId)+NativeUInt(FConnectionHandle))+'"'; FRawPlanName := {$IFDEF UNICODE}RawByteString{$ENDIF}(FPlanName); end; function TZPostgreSQLClassicPreparedStatement.PrepareAnsiSQLParam(ParamIndex: Integer; Escaped: Boolean): RawByteString; begin if InParamCount <= ParamIndex then raise EZSQLException.Create(SInvalidInputParameterCount); Result := PGPrepareAnsiSQLParam(InParamValues[ParamIndex], (Connection as IZPostgreSQLConnection), FPlainDriver, ChunkSize, InParamTypes[ParamIndex], Foidasblob, Escaped, True, ConSettings); end; procedure TZPostgreSQLClassicPreparedStatement.PrepareInParameters; var I, N: Integer; Tokens: TStrings; TempSQL: String; QueryHandle: PZPostgreSQLResult; begin if Pos('?', SQL) > 0 then begin Tokens := Connection.GetDriver.GetTokenizer. TokenizeBufferToList(SQL, [toUnifyWhitespaces]); try TempSQL := 'PREPARE '+FPlanName+' AS '; N := 0; for I := 0 to Tokens.Count - 1 do begin if Tokens[I] = '?' then begin Inc(N); TempSQL := TempSQL + '$' + IntToStr(N); end else TempSQL := TempSQL + Tokens[I]; end; finally Tokens.Free; end; end else Exit; {$IFDEF UNICODE}WSQL{$ELSE}ASQL{$ENDIF} := TempSQL; QueryHandle := FPlainDriver.ExecuteQuery(FConnectionHandle, PAnsiChar(ASQL)); CheckPostgreSQLError(Connection, FPlainDriver, FConnectionHandle, lcPrepStmt, SSQL, QueryHandle); DriverManager.LogMessage(lcPrepStmt, FPlainDriver.GetProtocol, SSQL); FPlainDriver.Clear(QueryHandle); end; procedure TZPostgreSQLClassicPreparedStatement.BindInParameters; var I: Integer; begin if Self.InParamCount > 0 then begin if Prepared then begin FExecSQL := 'EXECUTE '+FRawPlanName+'('; for i := 0 to InParamCount -1 do if I = 0 then FExecSQL := FExecSQL+PrepareAnsiSQLParam(i, False) else FExecSQL := FExecSQL+','+PrepareAnsiSQLParam(i, False); FExecSQL := FExecSQL+');'; end else FExecSQL := GetAnsiSQLQuery; end else FExecSQL := ASQL; end; procedure TZPostgreSQLClassicPreparedStatement.UnPrepareInParameters; begin if Prepared and Assigned(FPostgreSQLConnection.GetConnectionHandle) then begin ASQL := 'DEALLOCATE '+FRawPlanName+';'; Execute(ASQL); end; end; procedure TZPostgreSQLClassicPreparedStatement.Prepare; begin { EgonHugeist: assume automated Prepare after third execution. That's the way the JDBC Drivers go too... } if (not Prepared ) and ( InParamCount > 0 ) and ( ExecCount > 2 ) then inherited Prepare; BindInParameters; end; {** Executes an SQL statement that returns a single ResultSet object. @param sql typically this is a static SQL SELECT statement @return a ResultSet object that contains the data produced by the given query; never null } function TZPostgreSQLClassicPreparedStatement.ExecuteQuery(const SQL: RawByteString): IZResultSet; begin Result := nil; ASQL := SQL; //Preprepares the SQL and Sets the AnsiSQL QueryHandle := FPlainDriver.ExecuteQuery(FConnectionHandle, PAnsiChar(ASQL)); CheckPostgreSQLError(Connection, FPlainDriver, FConnectionHandle, lcExecute, SSQL, QueryHandle); DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, Self.SSQL); if QueryHandle <> nil then Result := CreateResultSet(QueryHandle) else Result := nil; end; {** Executes an SQL INSERT, UPDATE or DELETE statement. In addition, SQL statements that return nothing, such as SQL DDL statements, can be executed. @param sql an SQL INSERT, UPDATE or DELETE statement or an SQL statement that returns nothing @return either the row count for INSERT, UPDATE or DELETE statements, or 0 for SQL statements that return nothing } function TZPostgreSQLClassicPreparedStatement.ExecuteUpdate(const SQL: RawByteString): Integer; var QueryHandle: PZPostgreSQLResult; begin Result := -1; ASQL := SQL; //Preprepares the SQL and Sets the AnsiSQL QueryHandle := FPlainDriver.ExecuteQuery(FConnectionHandle, PAnsiChar(ASQL)); CheckPostgreSQLError(Connection, FPlainDriver, FConnectionHandle, lcExecute, SSQL, QueryHandle); DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, SSQL); if QueryHandle <> nil then begin Result := StrToIntDef(String(FPlainDriver.GetCommandTuples(QueryHandle)), 0); FPlainDriver.Clear(QueryHandle); end; { Autocommit statement. } if Connection.GetAutoCommit then Connection.Commit; end; {** Executes an SQL statement that may return multiple results. Under some (uncommon) situations a single SQL statement may return multiple result sets and/or update counts. Normally you can ignore this unless you are (1) executing a stored procedure that you know may return multiple results or (2) you are dynamically executing an unknown SQL string. The methods execute, getMoreResults, getResultSet, and getUpdateCount let you navigate through multiple results. The execute method executes an SQL statement and indicates the form of the first result. You can then use the methods getResultSet or getUpdateCount to retrieve the result, and getMoreResults to move to any subsequent result(s). @param sql any SQL statement @return true if the next result is a ResultSet object; false if it is an update count or there are no more results } function TZPostgreSQLClassicPreparedStatement.Execute(const SQL: RawByteString): Boolean; var QueryHandle: PZPostgreSQLResult; ResultStatus: TZPostgreSQLExecStatusType; begin ASQL := SQL; //Preprepares the SQL and Sets the AnsiSQL QueryHandle := FPlainDriver.ExecuteQuery(FConnectionHandle, PAnsiChar(ASQL)); CheckPostgreSQLError(Connection, FPlainDriver, FConnectionHandle, lcExecute, SSQL, QueryHandle); DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, SSQL); { Process queries with result sets } ResultStatus := FPlainDriver.GetResultStatus(QueryHandle); case ResultStatus of PGRES_TUPLES_OK: begin Result := True; LastResultSet := CreateResultSet(QueryHandle); end; PGRES_COMMAND_OK: begin Result := False; LastUpdateCount := StrToIntDef(String( FPlainDriver.GetCommandTuples(QueryHandle)), 0); FPlainDriver.Clear(QueryHandle); end; else begin Result := False; LastUpdateCount := StrToIntDef(String( FPlainDriver.GetCommandTuples(QueryHandle)), 0); FPlainDriver.Clear(QueryHandle); end; end; { Autocommit statement. } if not Result and Connection.GetAutoCommit then Connection.Commit; end; {** Executes the SQL query in this PreparedStatement object and returns the result set generated by the query. @return a ResultSet object that contains the data produced by the query; never null } function TZPostgreSQLClassicPreparedStatement.ExecuteQueryPrepared: IZResultSet; begin Prepare; Result := ExecuteQuery(FExecSQL); inherited ExecuteQueryPrepared; end; {** Executes the SQL INSERT, UPDATE or DELETE statement in this PreparedStatement object. In addition, SQL statements that return nothing, such as SQL DDL statements, can be executed. @return either the row count for INSERT, UPDATE or DELETE statements; or 0 for SQL statements that return nothing } function TZPostgreSQLClassicPreparedStatement.ExecuteUpdatePrepared: Integer; begin Prepare; Result := ExecuteUpdate(FExecSQL); inherited ExecuteUpdatePrepared; end; {** Executes any kind of SQL statement. Some prepared statements return multiple results; the execute method handles these complex statements as well as the simpler form of statements handled by the methods executeQuery and executeUpdate. @see Statement#execute } function TZPostgreSQLClassicPreparedStatement.ExecutePrepared: Boolean; begin Prepare; Result := Execute(FExecSQL); inherited ExecutePrepared; end; { TZPostgreSQLCAPIPreparedStatement } function TZPostgreSQLCAPIPreparedStatement.ExectuteInternal(const SQL: RawByteString; const LogSQL: String; const LoggingCategory: TZLoggingCategory): PZPostgreSQLResult; begin case LoggingCategory of lcPrepStmt: begin Result := FPlainDriver.Prepare(FConnectionHandle, PAnsiChar(RawByteString(FPlanName)), PAnsiChar(SQL), InParamCount, nil); Findeterminate_datatype := (CheckPostgreSQLError(Connection, FPlainDriver, FConnectionHandle, LoggingCategory, LogSQL, Result) = '42P18'); DriverManager.LogMessage(LoggingCategory, FPlainDriver.GetProtocol, LogSQL); if not Findeterminate_datatype then FPostgreSQLConnection.RegisterPreparedStmtName(FPlanName); Exit; end; lcExecPrepStmt: Result := FPlainDriver.ExecPrepared(FConnectionHandle, PAnsiChar(RawByteString(FPlanName)), InParamCount, FPQparamValues, FPQparamLengths, FPQparamFormats, 0); lcUnprepStmt: if Assigned(FConnectionHandle) then Result := FPlainDriver.ExecuteQuery(FConnectionHandle, PAnsiChar(SQL)) else Result := nil; else Result := FPlainDriver.ExecuteQuery(FConnectionHandle, PAnsiChar(SQL)); end; if Assigned(FConnectionHandle) then CheckPostgreSQLError(Connection, FPlainDriver, FConnectionHandle, LoggingCategory, LogSQL, Result); DriverManager.LogMessage(LoggingCategory, FPlainDriver.GetProtocol, LogSQL); end; procedure TZPostgreSQLCAPIPreparedStatement.SetPlanNames; begin FPlanName := IntToStr(Hash(ASQL)+Cardinal(FStatementId)+NativeUInt(FConnectionHandle)); FRawPlanName := {$IFDEF UNICODE}RawByteString{$ENDIF}(FPlanName); end; procedure TZPostgreSQLCAPIPreparedStatement.SetASQL(const Value: RawByteString); begin if ( ASQL <> Value ) and Prepared then Unprepare; inherited SetASQL(Value); end; procedure TZPostgreSQLCAPIPreparedStatement.SetWSQL(const Value: ZWideString); begin if ( WSQL <> Value ) and Prepared then Unprepare; inherited SetWSQL(Value); end; procedure TZPostgreSQLCAPIPreparedStatement.PrepareInParameters; begin if not (Findeterminate_datatype) then begin SetLength(FPQparamValues, InParamCount); SetLength(FPQparamLengths, InParamCount); SetLength(FPQparamFormats, InParamCount); end; end; procedure TZPostgreSQLCAPIPreparedStatement.BindInParameters; var Value: TZVariant; TempBlob: IZBlob; TempStream: TStream; WriteTempBlob: IZPostgreSQLBlob; ParamIndex: Integer; TempBytes: TByteDynArray; procedure UpdateNull(const Index: Integer); begin FreeMem(FPQparamValues[Index]); FPQparamValues[Index] := nil; FPQparamLengths[Index] := 0; FPQparamFormats[Index] := 0; end; procedure UpdateString(Value: RawByteString; const Index: Integer); begin UpdateNull(Index); FPQparamValues[ParamIndex] := AllocMem(Length(Value) + 1); {$IFDEF WITH_STRPCOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrCopy(FPQparamValues[Index], PAnsiChar(Value)); end; procedure UpdateBinary(Value: Pointer; const Len, Index: Integer); begin UpdateNull(Index); FPQparamValues[Index] := AllocMem(Len); System.Move(Value^, FPQparamValues[Index]^, Len); FPQparamLengths[Index] := Len; FPQparamFormats[Index] := 1; end; begin if InParamCount <> High(FPQparamValues)+1 then raise EZSQLException.Create(SInvalidInputParameterCount); for ParamIndex := 0 to InParamCount -1 do begin Value := InParamValues[ParamIndex]; if DefVarManager.IsNull(Value) then UpdateNull(ParamIndex) else case InParamTypes[ParamIndex] of stBoolean: UpdateString(RawByteString(UpperCase(BoolToStrEx(SoftVarManager.GetAsBoolean(Value)))), ParamIndex); stByte, stShort, stInteger, stLong, stBigDecimal, stFloat, stDouble: UpdateString(RawByteString(SoftVarManager.GetAsString(Value)), ParamIndex); stBytes: begin TempBytes := SoftVarManager.GetAsBytes(Value); UpdateBinary(PAnsiChar(TempBytes), Length(TempBytes), ParamIndex); end; stString: UpdateString(ZPlainString(SoftVarManager.GetAsString(Value), GetConnection.GetEncoding), ParamIndex); stUnicodeString: UpdateString(ZPlainString(SoftVarManager.GetAsUnicodeString(Value)), ParamIndex); stDate: UpdateString(RawByteString(FormatDateTime('yyyy-mm-dd', SoftVarManager.GetAsDateTime(Value))), ParamIndex); stTime: UpdateString(RawByteString(FormatDateTime('hh":"mm":"ss"."zzz', SoftVarManager.GetAsDateTime(Value))), ParamIndex); stTimestamp: UpdateString(RawByteString(FormatDateTime('yyyy-mm-dd hh":"mm":"ss"."zzz', SoftVarManager.GetAsDateTime(Value))), ParamIndex); stAsciiStream, stUnicodeStream, stBinaryStream: begin TempBlob := DefVarManager.GetAsInterface(Value) as IZBlob; if not TempBlob.IsEmpty then begin case InParamTypes[ParamIndex] of stBinaryStream: if ((GetConnection as IZPostgreSQLConnection).IsOidAsBlob) or StrToBoolDef(Info.Values['oidasblob'], False) then begin TempStream := TempBlob.GetStream; try WriteTempBlob := TZPostgreSQLBlob.Create(FPlainDriver, nil, 0, FConnectionHandle, 0, ChunkSize); WriteTempBlob.SetStream(TempStream); WriteTempBlob.WriteBlob; UpdateString(RawByteString(IntToStr(WriteTempBlob.GetBlobOid)), ParamIndex); finally WriteTempBlob := nil; TempStream.Free; end; end else UpdateBinary(TempBlob.GetBuffer, TempBlob.Length, ParamIndex); stAsciiStream, stUnicodeStream: begin UpdateString(GetValidatedAnsiStringFromBuffer(TempBlob.GetBuffer, TempBlob.Length, TempBlob.WasDecoded, ConSettings), ParamIndex); end; end; {case..} TempBlob := nil; end else UpdateNull(ParamIndex); end; {if not TempBlob.IsEmpty then} end; end; inherited BindInParameters; end; {** Removes eventual structures for binding input parameters. } procedure TZPostgreSQLCAPIPreparedStatement.UnPrepareInParameters; var I: Integer; begin { release allocated memory } if not (Findeterminate_datatype) then begin for i := 0 to InParamCount-1 do begin FreeMem(FPQparamValues[i]); FPQparamValues[i] := nil; end; SetLength(FPQparamValues, 0); SetLength(FPQparamLengths, 0); SetLength(FPQparamFormats, 0); end; end; {** Prepares an SQL statement and inserts all data values. @return a prepared SQL statement. } function TZPostgreSQLCAPIPreparedStatement.PrepareAnsiSQLQuery: RawByteString; var I: Integer; ParamIndex: Integer; Tokens: TStrings; begin ParamIndex := 0; Result := ''; Tokens := Connection.GetDriver.GetTokenizer.TokenizeBufferToList(SQL, [toUnifyWhitespaces]); for I := 0 to Tokens.Count - 1 do begin if Tokens[I] = '?' then begin if InParamCount <= ParamIndex then raise EZSQLException.Create(SInvalidInputParameterCount); Result := Result + PGPrepareAnsiSQLParam(InParamValues[ParamIndex], (Connection as IZPostgreSQLConnection), FPlainDriver, ChunkSize, InParamTypes[ParamIndex], Foidasblob, True, False, ConSettings); Inc(ParamIndex); end else Result := Result + ZPlainString(Tokens[I]); end; Tokens.Free; end; procedure TZPostgreSQLCAPIPreparedStatement.Prepare; var Tokens: TStrings; TempSQL: String; N, I: Integer; begin if not Prepared then begin N := 0; if Pos('?', SSQL) > 0 then begin TempSQL := ''; //init Tokens := Connection.GetDriver.GetTokenizer. TokenizeBufferToList(SSQL, [toUnifyWhitespaces]); try for I := 0 to Tokens.Count - 1 do begin if Tokens[I] = '?' then begin Inc(N); TempSQL := TempSQL + '$' + IntToStr(N); end else TempSQL := TempSQL + Tokens[I]; end; finally Tokens.Free; end; end else TempSQL := SSQL; if ( N > 0 ) or ( ExecCount > 2 ) then //prepare only if Params are available or certain executions expected begin QueryHandle := ExectuteInternal(GetEncodedSQL(TempSQL), 'PREPARE '#39+TempSQL+#39, lcPrepStmt); if not (Findeterminate_datatype) then FPlainDriver.Clear(QueryHandle); inherited Prepare; end; end; end; procedure TZPostgreSQLCAPIPreparedStatement.Unprepare; var TempSQL: String; begin if Prepared then begin inherited Unprepare; if Assigned(FPostgreSQLConnection.GetConnectionHandle) and (not Findeterminate_datatype) then begin TempSQL := 'DEALLOCATE "'+FPlanName+'";'; QueryHandle := ExectuteInternal(RawByteString(TempSQL), TempSQL, lcUnprepStmt); FPlainDriver.Clear(QueryHandle); FPostgreSQLConnection.UnregisterPreparedStmtName(FPlanName); end; end; end; function TZPostgreSQLCAPIPreparedStatement.ExecuteQueryPrepared: IZResultSet; begin Result := nil; Prepare; if Prepared then if Findeterminate_datatype then QueryHandle := ExectuteInternal(PrepareAnsiSQLQuery, SSQL, lcExecute) else begin BindInParameters; QueryHandle := ExectuteInternal(ASQL, SSQL, lcExecPrepStmt); end else QueryHandle := ExectuteInternal(ASQL, SSQL, lcExecute); if QueryHandle <> nil then Result := CreateResultSet(QueryHandle) else Result := nil; inherited ExecuteQueryPrepared; end; function TZPostgreSQLCAPIPreparedStatement.ExecuteUpdatePrepared: Integer; begin Result := -1; Prepare; if Prepared then if Findeterminate_datatype then QueryHandle := ExectuteInternal(PrepareAnsiSQLQuery, SSQL, lcExecute) else begin BindInParameters; QueryHandle := ExectuteInternal(ASQL, SSQL, lcExecPrepStmt); end else QueryHandle := ExectuteInternal(ASQL, SSQL, lcExecute); if QueryHandle <> nil then begin Result := StrToIntDef(String(FPlainDriver.GetCommandTuples(QueryHandle)), 0); FPlainDriver.Clear(QueryHandle); end; { Autocommit statement. } if Connection.GetAutoCommit then Connection.Commit; inherited ExecuteUpdatePrepared; end; function TZPostgreSQLCAPIPreparedStatement.ExecutePrepared: Boolean; var ResultStatus: TZPostgreSQLExecStatusType; begin Prepare; if Prepared then if Findeterminate_datatype then QueryHandle := ExectuteInternal(PrepareAnsiSQLQuery, SSQL, lcExecPrepStmt) else begin BindInParameters; QueryHandle := ExectuteInternal(ASQL, SSQL, lcExecPrepStmt); end else QueryHandle := ExectuteInternal(ASQL, SSQL, lcExecute); { Process queries with result sets } ResultStatus := FPlainDriver.GetResultStatus(QueryHandle); case ResultStatus of PGRES_TUPLES_OK: begin Result := True; LastResultSet := CreateResultSet(QueryHandle); end; PGRES_COMMAND_OK: begin Result := False; LastUpdateCount := StrToIntDef(String( FPlainDriver.GetCommandTuples(QueryHandle)), 0); FPlainDriver.Clear(QueryHandle); end; else begin Result := False; LastUpdateCount := StrToIntDef(String( FPlainDriver.GetCommandTuples(QueryHandle)), 0); FPlainDriver.Clear(QueryHandle); end; end; { Autocommit statement. } if not Result and Connection.GetAutoCommit then Connection.Commit; inherited ExecutePrepared; end; { TZPostgreSQLCallableStatement } {** Constructs this object and assignes the main properties. @param Connection a database connection object. @param Info a statement parameters. @param Handle a connection handle pointer. } constructor TZPostgreSQLCallableStatement.Create( Connection: IZConnection; const SQL: string; Info: TStrings); begin inherited Create(Connection, SQL, Info); ResultSetType := rtScrollInsensitive; FPlainDriver := (Connection as IZPostgreSQLConnection).GetPlainDriver; Foidasblob := StrToBoolDef(Self.Info.Values['oidasblob'], False) or (Connection as IZPostgreSQLConnection).IsOidAsBlob; end; {** Provides connection handle from the associated IConnection @return a PostgreSQL connection handle. } function TZPostgreSQLCallableStatement.GetConnectionHandle:PZPostgreSQLConnect; begin if Self.Connection = nil then Result := nil else Result := (self.Connection as IZPostgreSQLConnection).GetConnectionHandle; end; {** Creates a result set based on the current settings. @return a created result set object. } function TZPostgreSQLCallableStatement.CreateResultSet(const SQL: string; QueryHandle: PZPostgreSQLResult): IZResultSet; var NativeResultSet: TZPostgreSQLResultSet; CachedResultSet: TZCachedResultSet; ConnectionHandle: PZPostgreSQLConnect; begin ConnectionHandle := GetConnectionHandle(); NativeResultSet := TZPostgreSQLResultSet.Create(GetPlainDriver, Self, SQL, ConnectionHandle, QueryHandle, ChunkSize); NativeResultSet.SetConcurrency(rcReadOnly); if GetResultSetConcurrency = rcUpdatable then begin CachedResultSet := TZCachedResultSet.Create(NativeResultSet, SQL, nil, ConSettings); CachedResultSet.SetConcurrency(rcUpdatable); CachedResultSet.SetResolver(TZPostgreSQLCachedResolver.Create( Self, NativeResultSet.GetMetadata)); Result := CachedResultSet; end else Result := NativeResultSet; end; {** Returns plain draiver from connection object @return a PlainDriver object } function TZPostgreSQLCallableStatement.GetPlainDriver():IZPostgreSQLPlainDriver; begin if self.Connection <> nil then Result := (self.Connection as IZPostgreSQLConnection).GetPlainDriver else Result := nil; end; {** Prepares an SQL parameter for the query. @param ParameterIndex the first parameter is 1, the second is 2, ... @return a string representation of the parameter. } function TZPostgreSQLCallableStatement.PrepareAnsiSQLParam( ParamIndex: Integer): RawByteString; begin if InParamCount <= ParamIndex then raise EZSQLException.Create(SInvalidInputParameterCount); Result := PGPrepareAnsiSQLParam(InParamValues[ParamIndex], (Connection as IZPostgreSQLConnection), FPlainDriver, ChunkSize, InParamTypes[ParamIndex], Foidasblob, True, False, ConSettings); end; {** Executes an SQL statement that returns a single ResultSet object. @param sql typically this is a static SQL SELECT statement @return a ResultSet object that contains the data produced by the given query; never null } function TZPostgreSQLCallableStatement.ExecuteQuery( const SQL: RawByteString): IZResultSet; var QueryHandle: PZPostgreSQLResult; ConnectionHandle: PZPostgreSQLConnect; begin Result := nil; ConnectionHandle := GetConnectionHandle(); ASQL := SQL; //Preprepares the SQL and Sets the AnsiSQL QueryHandle := GetPlainDriver.ExecuteQuery(ConnectionHandle, PAnsiChar(ASQL)); CheckPostgreSQLError(Connection, GetPlainDriver, ConnectionHandle, lcExecute, LogSQL, QueryHandle); DriverManager.LogMessage(lcExecute, GetPlainDriver.GetProtocol, LogSQL); if QueryHandle <> nil then begin Result := CreateResultSet(SSQL, QueryHandle); FetchOutParams(Result); end else Result := nil; end; {** Prepares and executes an SQL statement that returns a single ResultSet object. @return a ResultSet object that contains the data produced by the given query; never null } function TZPostgreSQLCallableStatement.ExecuteQueryPrepared: IZResultSet; begin TrimInParameters; Result := ExecuteQuery(FillParams(GetProcedureSql)); end; {** Create sql string for calling stored procedure. @return a Stored Procedure SQL string } function TZPostgreSQLCallableStatement.GetProcedureSql: string; function GenerateParamsStr(Count: integer): string; var I: integer; begin Result := ''; for I := 0 to Count - 1 do begin if Result <> '' then Result := Result + ','; Result := Result + '?'; end; end; var InParams: string; begin InParams := GenerateParamsStr(Length(InParamValues)); Result := Format('SELECT * FROM %s(%s)', [SQL, InParams]); end; {** Fills the parameter (?) tokens with corresponding parameter value @return a prepared SQL query for execution } function TZPostgreSQLCallableStatement.FillParams(const ASql: String): RawByteString; var I: Integer; Tokens: TStrings; ParamIndex: Integer; begin if Pos('?', ASql) > 0 then begin Tokens := Connection.GetDriver.GetTokenizer.TokenizeBufferToList(ASql, [toUnifyWhitespaces]); try ParamIndex := 0; for I := 0 to Tokens.Count - 1 do if Tokens[I] = '?' then begin Result := Result + PrepareAnsiSQLParam(ParamIndex); Inc(ParamIndex); end else Result := Result + ZPlainString(Tokens[i]); finally Tokens.Free; end; end else Result := GetEncodedSQL(ASql); end; {** Executes an SQL INSERT, UPDATE or DELETE statement. In addition, SQL statements that return nothing, such as SQL DDL statements, can be executed. @param sql an SQL INSERT, UPDATE or DELETE statement or an SQL statement that returns nothing @return either the row count for INSERT, UPDATE or DELETE statements, or 0 for SQL statements that return nothing } function TZPostgreSQLCallableStatement.ExecuteUpdate(const SQL: RawByteString): Integer; var QueryHandle: PZPostgreSQLResult; ConnectionHandle: PZPostgreSQLConnect; begin Result := -1; ConnectionHandle := GetConnectionHandle(); ASQL := SQL; //Preprepares the SQL and Sets the AnsiSQL QueryHandle := GetPlainDriver.ExecuteQuery(ConnectionHandle, PAnsiChar(ASQL)); CheckPostgreSQLError(Connection, GetPlainDriver, ConnectionHandle, lcExecute, SSQL, QueryHandle); DriverManager.LogMessage(lcExecute, GetPlainDriver.GetProtocol, SSQL); if QueryHandle <> nil then begin Result := StrToIntDef(String(GetPlainDriver.GetCommandTuples(QueryHandle)), 0); FetchOutParams(CreateResultSet(SSQL, QueryHandle)); end; { Autocommit statement. } if Connection.GetAutoCommit then Connection.Commit; end; function TZPostgreSQLCallableStatement.ExecuteUpdatePrepared: Integer; begin TrimInParameters; Result := Self.ExecuteUpdate(FillParams(GetProcedureSql)); end; {** Sets output parameters from a ResultSet @param Value a IZResultSet object. } procedure TZPostgreSQLCallableStatement.FetchOutParams(ResultSet: IZResultSet); var ParamIndex, I: Integer; Temp: TZVariant; HasRows: Boolean; begin ResultSet.BeforeFirst; HasRows := ResultSet.Next; I := 1; for ParamIndex := 0 to OutParamCount - 1 do begin if not (FDBParamTypes[ParamIndex] in [2, 3, 4]) then // ptOutput, ptInputOutput, ptResult Continue; if I > ResultSet.GetMetadata.GetColumnCount then Break; if (not HasRows) or (ResultSet.IsNull(I)) then DefVarManager.SetNull(Temp) else case ResultSet.GetMetadata.GetColumnType(I) of stBoolean: DefVarManager.SetAsBoolean(Temp, ResultSet.GetBoolean(I)); stByte: DefVarManager.SetAsInteger(Temp, ResultSet.GetByte(I)); stShort: DefVarManager.SetAsInteger(Temp, ResultSet.GetShort(I)); stInteger: DefVarManager.SetAsInteger(Temp, ResultSet.GetInt(I)); stLong: DefVarManager.SetAsInteger(Temp, ResultSet.GetLong(I)); stFloat: DefVarManager.SetAsFloat(Temp, ResultSet.GetFloat(I)); stDouble: DefVarManager.SetAsFloat(Temp, ResultSet.GetDouble(I)); stBigDecimal: DefVarManager.SetAsFloat(Temp, ResultSet.GetBigDecimal(I)); stString: DefVarManager.SetAsString(Temp, ResultSet.GetString(I)); stUnicodeString: DefVarManager.SetAsUnicodeString(Temp, ResultSet.GetUnicodeString(I)); stDate: DefVarManager.SetAsDateTime(Temp, ResultSet.GetDate(I)); stTime: DefVarManager.SetAsDateTime(Temp, ResultSet.GetTime(I)); stTimestamp: DefVarManager.SetAsDateTime(Temp, ResultSet.GetTimestamp(I)); else DefVarManager.SetAsString(Temp, ResultSet.GetString(I)); end; OutParamValues[ParamIndex] := Temp; Inc(I); end; ResultSet.BeforeFirst; end; {** Function removes ptResult, ptOutput parameters from InParamTypes and InParamValues } procedure TZPostgreSQLCallableStatement.TrimInParameters; var I: integer; ParamValues: TZVariantDynArray; ParamTypes: TZSQLTypeArray; ParamCount: Integer; begin ParamCount := 0; SetLength(ParamValues, InParamCount); SetLength(ParamTypes, InParamCount); for I := 0 to High(InParamTypes) do begin if (Self.FDBParamTypes[i] in [2, 4]) then //[ptResult, ptOutput] Continue; ParamTypes[ParamCount] := InParamTypes[I]; ParamValues[ParamCount] := InParamValues[I]; Inc(ParamCount); end; if ParamCount = InParamCount then Exit; InParamTypes := ParamTypes; InParamValues := ParamValues; SetInParamCount(ParamCount); end; { TZPostgreSQLCachedResolver } {** Checks is the specified column can be used in where clause. @param ColumnIndex an index of the column. @returns true if column can be included into where clause. } function TZPostgreSQLCachedResolver.CheckKeyColumn(ColumnIndex: Integer): Boolean; begin Result := (Metadata.GetTableName(ColumnIndex) <> '') and (Metadata.GetColumnName(ColumnIndex) <> '') and Metadata.IsSearchable(ColumnIndex) and not (Metadata.GetColumnType(ColumnIndex) in [stUnknown, stBinaryStream, stUnicodeStream]); end; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcPostgreSqlUtils.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { PostgreSQL Database Connectivity Classes } { } { Originally written by Sergey Seroukhov } { and Sergey Merkuriev } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcPostgreSqlUtils; interface {$I ZDbc.inc} uses Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, ZDbcIntfs, ZPlainPostgreSqlDriver, ZDbcPostgreSql, ZDbcLogging, ZCompatibility, ZVariant; {** Indicate what field type is a number (integer, float and etc.) @param the SQLType field type value @result true if field type number } function IsNumber(Value: TZSQLType): Boolean; {** Return ZSQLType from PostgreSQL type name @param Connection a connection to PostgreSQL @param The TypeName is PostgreSQL type name @return The ZSQLType type } function PostgreSQLToSQLType(Connection: IZPostgreSQLConnection; TypeName: string): TZSQLType; overload; {** Another version of PostgreSQLToSQLType() - comparing integer should be faster than AnsiString? Return ZSQLType from PostgreSQL type name @param Connection a connection to PostgreSQL @param TypeOid is PostgreSQL type OID @return The ZSQLType type } function PostgreSQLToSQLType(const ConSettings: PZConSettings; const OIDAsBlob: Boolean; const TypeOid: Integer): TZSQLType; overload; {** Return PostgreSQL type name from ZSQLType @param The ZSQLType type @return The Postgre TypeName } function SQLTypeToPostgreSQL(SQLType: TZSQLType; IsOidAsBlob: Boolean): string; {** add by Perger -> based on SourceForge: [ 1520587 ] Fix for 1484704: bytea corrupted on post when not using utf8, file: 1484704.patch Converts a binary string into escape PostgreSQL format. @param Value a binary stream. @return a string in PostgreSQL binary string escape format. } function EncodeBinaryString(const Value: AnsiString): AnsiString; {** Encode string which probably consists of multi-byte characters. Characters ' (apostraphy), low value (value zero), and \ (back slash) are encoded. Since we have noticed that back slash is the second byte of some BIG5 characters (each of them is two bytes in length), we need a characterset aware encoding function. @param CharactersetCode the characterset in terms of enumerate code. @param Value the regular string. @return the encoded string. } function PGEscapeString(Handle: Pointer; const Value: RawByteString; ConSettings: PZConSettings; WasEncoded: Boolean = False): RawByteString; {** Converts an string from escape PostgreSQL format. @param Value a string in PostgreSQL escape format. @return a regular string. } function DecodeString(const Value: AnsiString): AnsiString; {** Checks for possible sql errors. @param Connection a reference to database connection to execute Rollback. @param PlainDriver a PostgreSQL plain driver. @param Handle a PostgreSQL connection reference. @param LogCategory a logging category. @param LogMessage a logging message. @param ResultHandle the Handle to the Result } function CheckPostgreSQLError(Connection: IZConnection; PlainDriver: IZPostgreSQLPlainDriver; Handle: PZPostgreSQLConnect; LogCategory: TZLoggingCategory; const LogMessage: string; ResultHandle: PZPostgreSQLResult): String; {** Resolve problem with minor version in PostgreSql bettas @param Value a minor version string like "4betta2" @return a miror version number } function GetMinorVersion(const Value: string): Word; {** Prepares an SQL parameter for the query. @param ParameterIndex the first parameter is 1, the second is 2, ... @return a string representation of the parameter. } function PGPrepareAnsiSQLParam(Value: TZVariant; Connection: IZPostgreSQLConnection; PlainDriver: IZPostgreSQLPlainDriver; const ChunkSize: Cardinal; const InParamType: TZSQLType; const oidasblob, DateTimePrefix, QuotedNumbers: Boolean; ConSettings: PZConSettings): RawByteString; implementation uses ZMessages, ZDbcPostgreSqlResultSet, ZEncoding, ZDbcPostgreSqlStatement; {** Return ZSQLType from PostgreSQL type name @param Connection a connection to PostgreSQL @param The TypeName is PostgreSQL type name @return The ZSQLType type } function PostgreSQLToSQLType(Connection: IZPostgreSQLConnection; TypeName: string): TZSQLType; begin TypeName := LowerCase(TypeName); if (TypeName = 'interval') or (TypeName = 'char') or (TypeName = 'bpchar') or (TypeName = 'varchar') or (TypeName = 'bit') or (TypeName = 'varbit') then//EgonHugeist: Highest Priority Client_Character_set!!!! if (Connection.GetConSettings.CPType = cCP_UTF16) then Result := stUnicodeString else Result := stString else if TypeName = 'text' then Result := stAsciiStream else if TypeName = 'oid' then begin if Connection.IsOidAsBlob() then Result := stBinaryStream else Result := stInteger; end else if TypeName = 'name' then Result := stString else if TypeName = 'enum' then Result := stString else if TypeName = 'cidr' then Result := stString else if TypeName = 'inet' then Result := stString else if TypeName = 'macaddr' then Result := stString else if TypeName = 'int2' then Result := stShort else if TypeName = 'int4' then Result := stInteger else if TypeName = 'int8' then Result := stLong else if TypeName = 'float4' then Result := stFloat else if (TypeName = 'float8') or (TypeName = 'decimal') or (TypeName = 'numeric') then Result := stDouble else if TypeName = 'money' then Result := stDouble else if TypeName = 'bool' then Result := stBoolean else if TypeName = 'date' then Result := stDate else if TypeName = 'time' then Result := stTime else if (TypeName = 'datetime') or (TypeName = 'timestamp') or (TypeName = 'timestamptz') or (TypeName = 'abstime') then Result := stTimestamp else if TypeName = 'regproc' then Result := stString else if TypeName = 'bytea' then begin if Connection.IsOidAsBlob then Result := stBytes else Result := stBinaryStream; end else if (TypeName = 'int2vector') or (TypeName = 'oidvector') then Result := stAsciiStream else if (TypeName <> '') and (TypeName[1] = '_') then // ARRAY TYPES Result := stAsciiStream else Result := stUnknown; if (Connection.GetConSettings.CPType = cCP_UTF16) then if Result = stAsciiStream then Result := stUnicodeStream; end; {** Another version of PostgreSQLToSQLType() - comparing integer should be faster than AnsiString. Return ZSQLType from PostgreSQL type name @param Connection a connection to PostgreSQL @param TypeOid is PostgreSQL type OID @return The ZSQLType type } function PostgreSQLToSQLType(const ConSettings: PZConSettings; const OIDAsBlob: Boolean; const TypeOid: Integer): TZSQLType; overload; begin case TypeOid of 1186,18,1042,1043: { interval/char/bpchar/varchar } if (ConSettings.CPType = cCP_UTF16) then Result := stUnicodeString else Result := stString; 25: Result := stAsciiStream; { text } 26: { oid } begin if OidAsBlob then Result := stBinaryStream else Result := stInteger; end; 19: Result := stString; { name } 21: Result := stShort; { int2 } 23: Result := stInteger; { int4 } 20: Result := stLong; { int8 } 650: Result := stString; { cidr } 869: Result := stString; { inet } 829: Result := stString; { macaddr } 700: Result := stFloat; { float4 } 701,1700: Result := stDouble; { float8/numeric. no 'decimal' any more } 790: Result := stDouble; { money } 16: Result := stBoolean; { bool } 1082: Result := stDate; { date } 1083: Result := stTime; { time } 1114,1184,702: Result := stTimestamp; { timestamp,timestamptz/abstime. no 'datetime' any more} 1560,1562: Result := stString; {bit/ bit varying string} 24: Result := stString; { regproc } 1034: Result := stAsciiStream; {aclitem[]} 17: { bytea } begin if OidAsBlob then Result := stBytes else Result := stBinaryStream; end; 22,30: Result := stAsciiStream; { int2vector/oidvector. no '_aclitem' } 143,629,651,719,791,1000..1028,1040,1041,1115,1182,1183,1185,1187,1231,1263, 1270,1561,1563,2201,2207..2211,2949,2951,3643,3644,3645,3735,3770 : { other array types } Result := stAsciiStream; else Result := stUnknown; end; if (ConSettings.CPType = cCP_UTF16) then if Result = stAsciiStream then Result := stUnicodeStream; end; function SQLTypeToPostgreSQL(SQLType: TZSQLType; IsOidAsBlob: boolean): string; begin case SQLType of stBoolean: Result := 'bool'; stByte, stShort, stInteger, stLong: Result := 'int'; stFloat, stDouble, stBigDecimal: Result := 'numeric'; stString, stUnicodeString, stAsciiStream, stUnicodeStream: Result := 'text'; stDate: Result := 'date'; stTime: Result := 'time'; stTimestamp: Result := 'timestamp'; stBinaryStream, stBytes: if IsOidAsBlob then Result := 'oid' else Result := 'bytea'; end; end; {** Indicate what field type is a number (integer, float and etc.) @param the SQLType field type value @result true if field type number } function IsNumber(Value: TZSQLType): Boolean; begin Result := Value in [stByte, stShort, stInteger, stLong, stFloat, stDouble, stBigDecimal]; end; {** Encode string which probably consists of multi-byte characters. Characters ' (apostraphy), low value (value zero), and \ (back slash) are encoded. Since we have noticed that back slash is the second byte of some BIG5 characters (each of them is two bytes in length), we need a characterset aware encoding function. @param CharactersetCode the characterset in terms of enumerate code. @param Value the regular string. @return the encoded string. } function PGEscapeString(Handle: Pointer; const Value: RawByteString; ConSettings: PZConSettings; WasEncoded: Boolean = False): RawByteString; var I, LastState: Integer; SrcLength, DestLength: Integer; SrcBuffer, DestBuffer: PAnsiChar; function pg_CS_stat(stat: integer; character: integer; CharactersetCode: TZPgCharactersetType): integer; begin if character = 0 then stat := 0; case CharactersetCode of csUTF8, csUNICODE_PODBC: begin if (stat < 2) and (character >= $80) then begin if character >= $fc then stat := 6 else if character >= $f8 then stat := 5 else if character >= $f0 then stat := 4 else if character >= $e0 then stat := 3 else if character >= $c0 then stat := 2; end else if (stat > 2) and (character > $7f) then Dec(stat) else stat := 0; end; { Shift-JIS Support. } csSJIS: begin if (stat < 2) and (character > $80) and not ((character > $9f) and (character < $e0)) then stat := 2 else if stat = 2 then stat := 1 else stat := 0; end; { Chinese Big5 Support. } csBIG5: begin if (stat < 2) and (character > $A0) then stat := 2 else if stat = 2 then stat := 1 else stat := 0; end; { Chinese GBK Support. } csGBK: begin if (stat < 2) and (character > $7F) then stat := 2 else if stat = 2 then stat := 1 else stat := 0; end; { Korian UHC Support. } csUHC: begin if (stat < 2) and (character > $7F) then stat := 2 else if stat = 2 then stat := 1 else stat := 0; end; { EUC_JP Support } csEUC_JP: begin if (stat < 3) and (character = $8f) then { JIS X 0212 } stat := 3 else if (stat <> 2) and ((character = $8e) or (character > $a0)) then { Half Katakana HighByte & Kanji HighByte } stat := 2 else if stat = 2 then stat := 1 else stat := 0; end; { EUC_CN, EUC_KR, JOHAB Support } csEUC_CN, csEUC_KR, csJOHAB: begin if (stat < 2) and (character > $a0) then stat := 2 else if stat = 2 then stat := 1 else stat := 0; end; csEUC_TW: begin if (stat < 4) and (character = $8e) then stat := 4 else if (stat = 4) and (character > $a0) then stat := 3 else if ((stat = 3) or (stat < 2)) and (character > $a0) then stat := 2 else if stat = 2 then stat := 1 else stat := 0; end; { Chinese GB18030 support.Added by Bill Huang } csGB18030: begin if (stat < 2) and (character > $80) then stat := 2 else if stat = 2 then begin if (character >= $30) and (character <= $39) then stat := 3 else stat := 1; end else if stat = 3 then begin if (character >= $30) and (character <= $39) then stat := 1 else stat := 3; end else stat := 0; end; else stat := 0; end; Result := stat; end; begin SrcLength := Length(Value); SrcBuffer := PAnsiChar(Value); DestLength := 2; LastState := 0; for I := 1 to SrcLength do begin LastState := pg_CS_stat(LastState,integer(SrcBuffer^), TZPgCharactersetType(ConSettings.ClientCodePage.ID)); if CharInSet(SrcBuffer^, [#0, '''']) or ((SrcBuffer^ = '\') and (LastState = 0)) then Inc(DestLength, 4) else Inc(DestLength); Inc(SrcBuffer); end; SrcBuffer := PAnsiChar(Value); SetLength(Result, DestLength); DestBuffer := PAnsiChar(Result); DestBuffer^ := ''''; Inc(DestBuffer); LastState := 0; for I := 1 to SrcLength do begin LastState := pg_CS_stat(LastState,integer(SrcBuffer^), TZPgCharactersetType(ConSettings.ClientCodePage.ID)); if CharInSet(SrcBuffer^, [#0, '''']) or ((SrcBuffer^ = '\') and (LastState = 0)) then begin DestBuffer[0] := '\'; DestBuffer[1] := AnsiChar(Ord('0') + (Byte(SrcBuffer^) shr 6)); DestBuffer[2] := AnsiChar(Ord('0') + ((Byte(SrcBuffer^) shr 3) and $07)); DestBuffer[3] := AnsiChar(Ord('0') + (Byte(SrcBuffer^) and $07)); Inc(DestBuffer, 4); end else begin DestBuffer^ := SrcBuffer^; Inc(DestBuffer); end; Inc(SrcBuffer); end; DestBuffer^ := ''''; end; {** add by Perger -> based on SourceForge: [ 1520587 ] Fix for 1484704: bytea corrupted on post when not using utf8, file: 1484704.patch Converts a binary string into escape PostgreSQL format. @param Value a binary stream. @return a string in PostgreSQL binary string escape format. } function EncodeBinaryString(const Value: AnsiString): AnsiString; var I: Integer; SrcLength, DestLength: Integer; SrcBuffer, DestBuffer: PAnsiChar; begin SrcLength := Length(Value); SrcBuffer := PAnsiChar(Value); DestLength := 2; for I := 1 to SrcLength do begin if (Byte(SrcBuffer^) < 32) or (Byte(SrcBuffer^) > 126) or CharInSet(SrcBuffer^, ['''', '\']) then Inc(DestLength, 5) else Inc(DestLength); Inc(SrcBuffer); end; SrcBuffer := PAnsiChar(Value); SetLength(Result, DestLength); DestBuffer := PAnsiChar(Result); DestBuffer^ := ''''; Inc(DestBuffer); for I := 1 to SrcLength do begin if (Byte(SrcBuffer^) < 32) or (Byte(SrcBuffer^) > 126) or CharInSet(SrcBuffer^, ['''', '\']) then begin DestBuffer[0] := '\'; DestBuffer[1] := '\'; DestBuffer[2] := AnsiChar(Ord('0') + (Byte(SrcBuffer^) shr 6)); DestBuffer[3] := AnsiChar(Ord('0') + ((Byte(SrcBuffer^) shr 3) and $07)); DestBuffer[4] := AnsiChar(Ord('0') + (Byte(SrcBuffer^) and $07)); Inc(DestBuffer, 5); end else begin DestBuffer^ := SrcBuffer^; Inc(DestBuffer); end; Inc(SrcBuffer); end; DestBuffer^ := ''''; end; {** Converts an string from escape PostgreSQL format. @param Value a string in PostgreSQL escape format. @return a regular string. } function DecodeString(const Value: AnsiString): AnsiString; var SrcLength, DestLength: Integer; SrcBuffer, DestBuffer: PAnsiChar; begin SrcLength := Length(Value); SrcBuffer := PAnsiChar(Value); SetLength(Result, SrcLength); DestLength := 0; DestBuffer := PAnsiChar(Result); while SrcLength > 0 do begin if SrcBuffer^ = '\' then begin Inc(SrcBuffer); if CharInSet(SrcBuffer^, ['\', '''']) then begin DestBuffer^ := SrcBuffer^; Inc(SrcBuffer); Dec(SrcLength, 2); end else begin DestBuffer^ := AnsiChar(((Byte(SrcBuffer[0]) - Ord('0')) shl 6) or ((Byte(SrcBuffer[1]) - Ord('0')) shl 3) or ((Byte(SrcBuffer[2]) - Ord('0')))); Inc(SrcBuffer, 3); Dec(SrcLength, 4); end; end else begin DestBuffer^ := SrcBuffer^; Inc(SrcBuffer); Dec(SrcLength); end; Inc(DestBuffer); Inc(DestLength); end; SetLength(Result, DestLength); end; {** Checks for possible sql errors. @param Connection a reference to database connection to execute Rollback. @param PlainDriver a PostgreSQL plain driver. @param Handle a PostgreSQL connection reference. @param LogCategory a logging category. @param LogMessage a logging message. //FirmOS 22.02.06 @param ResultHandle the Handle to the Result } function CheckPostgreSQLError(Connection: IZConnection; PlainDriver: IZPostgreSQLPlainDriver; Handle: PZPostgreSQLConnect; LogCategory: TZLoggingCategory; const LogMessage: string; ResultHandle: PZPostgreSQLResult): String; var ErrorMessage: string; //FirmOS ConnectionLost: boolean; function GetMessage(AMessage: PAnsiChar): String; begin if Assigned(Connection) then Result := Trim(PlainDriver.ZDbcString(AMessage, Connection.GetConSettings)) else {$IFDEF UNICODE} Result := Trim(UTF8ToString(AMessage)); {$ELSE} {$IFDEF DELPHI} Result := Trim(Utf8ToAnsi(AMessage)); {$ELSE} Result := Trim(AMessage); {$ENDIF} {$ENDIF} end; begin if Assigned(Handle) then ErrorMessage := GetMessage(PlainDriver.GetErrorMessage(Handle)) else ErrorMessage := ''; if ErrorMessage <> '' then begin if Assigned(ResultHandle) then { StatusCode := Trim(StrPas(PlainDriver.GetResultErrorField(ResultHandle,PG_DIAG_SEVERITY))); StatusCode := Trim(StrPas(PlainDriver.GetResultErrorField(ResultHandle,PG_DIAG_MESSAGE_PRIMARY))); StatusCode := Trim(StrPas(PlainDriver.GetResultErrorField(ResultHandle,PG_DIAG_MESSAGE_DETAIL))); StatusCode := Trim(StrPas(PlainDriver.GetResultErrorField(ResultHandle,PG_DIAG_MESSAGE_HINT))); StatusCode := Trim(StrPas(PlainDriver.GetResultErrorField(ResultHandle,PG_DIAG_STATEMENT_POSITION))); StatusCode := Trim(StrPas(PlainDriver.GetResultErrorField(ResultHandle,PG_DIAG_INTERNAL_POSITION))); StatusCode := Trim(StrPas(PlainDriver.GetResultErrorField(ResultHandle,PG_DIAG_INTERNAL_QUERY))); StatusCode := Trim(StrPas(PlainDriver.GetResultErrorField(ResultHandle,PG_DIAG_CONTEXT))); StatusCode := Trim(StrPas(PlainDriver.GetResultErrorField(ResultHandle,PG_DIAG_SOURCE_FILE))); StatusCode := Trim(StrPas(PlainDriver.GetResultErrorField(ResultHandle,PG_DIAG_SOURCE_LINE))); StatusCode := Trim(StrPas(PlainDriver.GetResultErrorField(ResultHandle,PG_DIAG_SOURCE_FUNCTION))); } Result := GetMessage(PlainDriver.GetResultErrorField(ResultHandle,PG_DIAG_SQLSTATE)) else Result := ''; end; if ErrorMessage <> '' then begin ConnectionLost := (PlainDriver.GetStatus(Handle) = CONNECTION_BAD); if Assigned(Connection) then begin if Connection.GetAutoCommit and not ConnectionLost then Connection.Rollback; DriverManager.LogError(LogCategory, PlainDriver.GetProtocol, LogMessage, 0, ErrorMessage); end else begin DriverManager.LogError(LogCategory, 'some PostgreSQL protocol', LogMessage, 0, ErrorMessage); end; if ResultHandle <> nil then PlainDriver.Clear(ResultHandle); if not ( ConnectionLost and ( LogCategory = lcUnprepStmt ) ) then if not (Result = '42P18') then raise EZSQLException.CreateWithStatus(Result,Format(SSQLError1, [ErrorMessage])); end; end; {** Resolve problem with minor version in PostgreSql bettas @param Value a minor version string like "4betta2" @return a miror version number } function GetMinorVersion(const Value: string): Word; var I: integer; Temp: string; begin Temp := ''; for I := 1 to Length(Value) do if CharInSet(Value[I], ['0'..'9']) then Temp := Temp + Value[I] else Break; Result := StrToIntDef(Temp, 0); end; {** Prepares an SQL parameter for the query. @param ParameterIndex the first parameter is 1, the second is 2, ... @return a string representation of the parameter. } function PGPrepareAnsiSQLParam(Value: TZVariant; Connection: IZPostgreSQLConnection; PlainDriver: IZPostgreSQLPlainDriver; const ChunkSize: Cardinal; const InParamType: TZSQLType; const oidasblob, DateTimePrefix, QuotedNumbers: Boolean; ConSettings: PZConSettings): RawByteString; var TempBlob: IZBlob; TempStream: TStream; WriteTempBlob: IZPostgreSQLBlob; begin if DefVarManager.IsNull(Value) then Result := 'NULL' else begin case InParamType of stBoolean: if SoftVarManager.GetAsBoolean(Value) then Result := 'TRUE' else Result := 'FALSE'; stByte, stShort, stInteger, stLong, stBigDecimal, stFloat, stDouble: begin Result := RawByteString(SoftVarManager.GetAsString(Value)); if QuotedNumbers then Result := #39+Result+#39; end; stBytes: Result := Connection.EncodeBinary(SoftVarManager.GetAsBytes(Value)); stString: if PlainDriver.SupportsStringEscaping(Connection.ClientSettingsChanged) then Result := PlainDriver.EscapeString(Connection.GetConnectionHandle, PlainDriver.ZPlainString(SoftVarManager.GetAsString(Value), ConSettings), ConSettings, True) else Result := ZDbcPostgreSqlUtils.PGEscapeString(Connection.GetConnectionHandle, PlainDriver.ZPlainString(SoftVarManager.GetAsString(Value), ConSettings), ConSettings, True); stUnicodeString: if PlainDriver.SupportsStringEscaping(Connection.ClientSettingsChanged) then Result := PlainDriver.EscapeString(Connection.GetConnectionHandle, PlainDriver.ZPlainString(SoftVarManager.GetAsUnicodeString(Value), ConSettings), ConSettings, True) else Result := ZDbcPostgreSqlUtils.PGEscapeString(Connection.GetConnectionHandle, PlainDriver.ZPlainString(SoftVarManager.GetAsUnicodeString(Value), ConSettings), ConSettings, True); stDate: begin Result := RawByteString(#39+FormatDateTime('yyyy-mm-dd', SoftVarManager.GetAsDateTime(Value))+#39); if DateTimePrefix then Result := Result + '::date'; end; stTime: begin Result := RawByteString(#39+FormatDateTime('hh":"mm":"ss"."zzz', SoftVarManager.GetAsDateTime(Value))+#39); if DateTimePrefix then Result := Result + '::time'; end; stTimestamp: begin Result := RawByteString(#39+FormatDateTime('yyyy-mm-dd hh":"mm":"ss"."zzz', SoftVarManager.GetAsDateTime(Value))+#39); if DateTimePrefix then Result := Result + '::timestamp'; end; stAsciiStream, stUnicodeStream, stBinaryStream: begin TempBlob := DefVarManager.GetAsInterface(Value) as IZBlob; if not TempBlob.IsEmpty then begin case InParamType of stBinaryStream: if (Connection.IsOidAsBlob) or oidasblob then begin TempStream := TempBlob.GetStream; try WriteTempBlob := TZPostgreSQLBlob.Create(PlainDriver, nil, 0, Connection.GetConnectionHandle, 0, ChunkSize); WriteTempBlob.SetStream(TempStream); WriteTempBlob.WriteBlob; Result := RawByteString(IntToStr(WriteTempBlob.GetBlobOid)); finally WriteTempBlob := nil; TempStream.Free; end; end else Result := Connection.EncodeBinary(TempBlob.GetString); stAsciiStream, stUnicodeStream: if PlainDriver.SupportsStringEscaping(Connection.ClientSettingsChanged) then Result := PlainDriver.EscapeString( Connection.GetConnectionHandle, GetValidatedAnsiStringFromBuffer(TempBlob.GetBuffer, TempBlob.Length, TempBlob.WasDecoded, ConSettings), ConSettings, True) else Result := ZDbcPostgreSqlUtils.PGEscapeString( Connection.GetConnectionHandle, GetValidatedAnsiStringFromBuffer(TempBlob.GetBuffer, TempBlob.Length, TempBlob.WasDecoded, ConSettings), ConSettings, True); end; {case..} end else Result := 'NULL'; TempBlob := nil; end; {if not TempBlob.IsEmpty then} end; end; end; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcResultSet.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Abstract Database Connectivity Classes } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcResultSet; interface {$I ZDbc.inc} uses {$IFDEF MSWINDOWS} Windows, {$ENDIF} {$IFDEF FPC} {$IFDEF WIN32} Comobj, {$ENDIF} {$ENDIF} Types, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, Contnrs, ZDbcIntfs, ZClasses, ZCollections, ZSysUtils, ZCompatibility, ZVariant; {$IFDEF FPC} {$HINTS OFF} //suppress not used params {$ENDIF} type {** Implements Abstract ResultSet. } TZAbstractResultSet = class(TZCodePagedObject, IZResultSet) private FTemp: String; FRowNo: Integer; FLastRowNo: Integer; FMaxRows: Integer; FClosed: Boolean; FFetchDirection: TZFetchDirection; FFetchSize: Integer; FResultSetType: TZResultSetType; FResultSetConcurrency: TZResultSetConcurrency; FPostUpdates: TZPostUpdatesMode; FLocateUpdates: TZLocateUpdatesMode; FColumnsInfo: TObjectList; FMetadata: TContainedObject; FStatement: IZStatement; protected LastWasNull: Boolean; function InternalGetString(ColumnIndex: Integer): RawByteString; virtual; procedure RaiseUnsupportedException; procedure RaiseForwardOnlyException; procedure RaiseReadOnlyException; procedure CheckClosed; procedure CheckColumnConvertion(ColumnIndex: Integer; ResultType: TZSQLType); procedure CheckBlobColumn(ColumnIndex: Integer); procedure Open; virtual; function GetColumnIndex(const ColumnName: string): Integer; property RowNo: Integer read FRowNo write FRowNo; property LastRowNo: Integer read FLastRowNo write FLastRowNo; property MaxRows: Integer read FMaxRows write FMaxRows; property Closed: Boolean read FClosed write FClosed; property FetchDirection: TZFetchDirection read FFetchDirection write FFetchDirection; property FetchSize: Integer read FFetchSize write FFetchSize; property ResultSetType: TZResultSetType read FResultSetType write FResultSetType; property ResultSetConcurrency: TZResultSetConcurrency read FResultSetConcurrency write FResultSetConcurrency; property Statement: IZStatement read FStatement; property Metadata: TContainedObject read FMetadata write FMetadata; public constructor Create(Statement: IZStatement; SQL: string; Metadata: TContainedObject; ConSettings: PZConSettings); destructor Destroy; override; procedure SetType(Value: TZResultSetType); procedure SetConcurrency(Value: TZResultSetConcurrency); function Next: Boolean; virtual; procedure Close; virtual; function WasNull: Boolean; virtual; //====================================================================== // Methods for accessing results by column index //====================================================================== function IsNull(ColumnIndex: Integer): Boolean; virtual; function GetPChar(ColumnIndex: Integer): PChar; virtual; function GetString(ColumnIndex: Integer): String; virtual; function GetBinaryString(ColumnIndex: Integer): RawByteString; function GetUnicodeString(ColumnIndex: Integer): WideString; virtual; function GetBoolean(ColumnIndex: Integer): Boolean; virtual; function GetByte(ColumnIndex: Integer): Byte; virtual; function GetShort(ColumnIndex: Integer): SmallInt; virtual; function GetInt(ColumnIndex: Integer): Integer; virtual; function GetLong(ColumnIndex: Integer): Int64; virtual; function GetFloat(ColumnIndex: Integer): Single; virtual; function GetDouble(ColumnIndex: Integer): Double; virtual; function GetBigDecimal(ColumnIndex: Integer): Extended; virtual; function GetBytes(ColumnIndex: Integer): TByteDynArray; virtual; function GetDate(ColumnIndex: Integer): TDateTime; virtual; function GetTime(ColumnIndex: Integer): TDateTime; virtual; function GetTimestamp(ColumnIndex: Integer): TDateTime; virtual; function GetAsciiStream(ColumnIndex: Integer): TStream; virtual; function GetUnicodeStream(ColumnIndex: Integer): TStream; virtual; function GetBinaryStream(ColumnIndex: Integer): TStream; virtual; function GetBlob(ColumnIndex: Integer): IZBlob; virtual; function GetDataSet(ColumnIndex: Integer): IZDataSet; virtual; function GetValue(ColumnIndex: Integer): TZVariant; virtual; function GetDefaultExpression(ColumnIndex: Integer): String; virtual; //====================================================================== // Methods for accessing results by column name //====================================================================== function IsNullByName(const ColumnName: string): Boolean; virtual; function GetPCharByName(const ColumnName: string): PChar; virtual; function GetStringByName(const ColumnName: string): String; virtual; function GetBinaryStringByName(const ColumnName: string): RawByteString; function GetUnicodeStringByName(const ColumnName: string): WideString; virtual; function GetBooleanByName(const ColumnName: string): Boolean; virtual; function GetByteByName(const ColumnName: string): Byte; virtual; function GetShortByName(const ColumnName: string): SmallInt; virtual; function GetIntByName(const ColumnName: string): Integer; virtual; function GetLongByName(const ColumnName: string): Int64; virtual; function GetFloatByName(const ColumnName: string): Single; virtual; function GetDoubleByName(const ColumnName: string): Double; virtual; function GetBigDecimalByName(const ColumnName: string): Extended; virtual; function GetBytesByName(const ColumnName: string): TByteDynArray; virtual; function GetDateByName(const ColumnName: string): TDateTime; virtual; function GetTimeByName(const ColumnName: string): TDateTime; virtual; function GetTimestampByName(const ColumnName: string): TDateTime; virtual; function GetAsciiStreamByName(const ColumnName: string): TStream; virtual; function GetUnicodeStreamByName(const ColumnName: string): TStream; virtual; function GetBinaryStreamByName(const ColumnName: string): TStream; virtual; function GetBlobByName(const ColumnName: string): IZBlob; virtual; function GetDataSetByName(const ColumnName: String): IZDataSet; virtual; function GetValueByName(const ColumnName: string): TZVariant; virtual; //===================================================================== // Advanced features: //===================================================================== function GetWarnings: EZSQLWarning; virtual; procedure ClearWarnings; virtual; function GetCursorName: AnsiString; virtual; function GetMetaData: IZResultSetMetaData; virtual; function FindColumn(const ColumnName: string): Integer; virtual; //--------------------------------------------------------------------- // Traversal/Positioning //--------------------------------------------------------------------- function IsBeforeFirst: Boolean; virtual; function IsAfterLast: Boolean; virtual; function IsFirst: Boolean; virtual; function IsLast: Boolean; virtual; procedure BeforeFirst; virtual; procedure AfterLast; virtual; function First: Boolean; virtual; function Last: Boolean; virtual; function GetRow: Integer; virtual; function MoveAbsolute(Row: Integer): Boolean; virtual; function MoveRelative(Rows: Integer): Boolean; virtual; function Previous: Boolean; virtual; //--------------------------------------------------------------------- // Properties //--------------------------------------------------------------------- procedure SetFetchDirection(Direction: TZFetchDirection); virtual; function GetFetchDirection: TZFetchDirection; virtual; procedure SetFetchSize(Rows: Integer); virtual; function GetFetchSize: Integer; virtual; function GetType: TZResultSetType; virtual; function GetConcurrency: TZResultSetConcurrency; virtual; function GetPostUpdates: TZPostUpdatesMode; function GetLocateUpdates: TZLocateUpdatesMode; //--------------------------------------------------------------------- // Updates //--------------------------------------------------------------------- function RowUpdated: Boolean; virtual; function RowInserted: Boolean; virtual; function RowDeleted: Boolean; virtual; procedure UpdateNull(ColumnIndex: Integer); virtual; procedure UpdateBoolean(ColumnIndex: Integer; Value: Boolean); virtual; procedure UpdateByte(ColumnIndex: Integer; Value: ShortInt); virtual; procedure UpdateShort(ColumnIndex: Integer; Value: SmallInt); virtual; procedure UpdateInt(ColumnIndex: Integer; Value: Integer); virtual; procedure UpdateLong(ColumnIndex: Integer; Value: Int64); virtual; procedure UpdateFloat(ColumnIndex: Integer; Value: Single); virtual; procedure UpdateDouble(ColumnIndex: Integer; Value: Double); virtual; procedure UpdateBigDecimal(ColumnIndex: Integer; Value: Extended); virtual; procedure UpdatePChar(ColumnIndex: Integer; Value: PChar); virtual; procedure UpdateString(ColumnIndex: Integer; const Value: String); virtual; procedure UpdateBinaryString(ColumnIndex: Integer; const Value: RawByteString); procedure UpdateUnicodeString(ColumnIndex: Integer; const Value: WideString); virtual; procedure UpdateBytes(ColumnIndex: Integer; const Value: TByteDynArray); virtual; procedure UpdateDate(ColumnIndex: Integer; Value: TDateTime); virtual; procedure UpdateTime(ColumnIndex: Integer; Value: TDateTime); virtual; procedure UpdateTimestamp(ColumnIndex: Integer; Value: TDateTime); virtual; procedure UpdateAsciiStream(ColumnIndex: Integer; Value: TStream); virtual; procedure UpdateUnicodeStream(ColumnIndex: Integer; Value: TStream); virtual; procedure UpdateBinaryStream(ColumnIndex: Integer; Value: TStream); virtual; procedure UpdateDataSet(ColumnIndex: Integer; Value: IZDataSet); virtual; procedure UpdateValue(ColumnIndex: Integer; const Value: TZVariant); virtual; procedure UpdateDefaultExpression(ColumnIndex: Integer; const Value: string); virtual; //====================================================================== // Methods for accessing results by column name //====================================================================== procedure UpdateNullByName(const ColumnName: string); virtual; procedure UpdateBooleanByName(const ColumnName: string; Value: Boolean); virtual; procedure UpdateByteByName(const ColumnName: string; Value: ShortInt); virtual; procedure UpdateShortByName(const ColumnName: string; Value: SmallInt); virtual; procedure UpdateIntByName(const ColumnName: string; Value: Integer); virtual; procedure UpdateLongByName(const ColumnName: string; Value: Int64); virtual; procedure UpdateFloatByName(const ColumnName: string; Value: Single); virtual; procedure UpdateDoubleByName(const ColumnName: string; Value: Double); virtual; procedure UpdateBigDecimalByName(const ColumnName: string; Value: Extended); virtual; procedure UpdatePCharByName(const ColumnName: string; Value: PChar); virtual; procedure UpdateStringByName(const ColumnName: string; const Value: String); virtual; procedure UpdateBinaryStringByName(const ColumnName: string; const Value: RawByteString); procedure UpdateUnicodeStringByName(const ColumnName: string; const Value: WideString); virtual; procedure UpdateBytesByName(const ColumnName: string; const Value: TByteDynArray); virtual; procedure UpdateDateByName(const ColumnName: string; Value: TDateTime); virtual; procedure UpdateTimeByName(const ColumnName: string; Value: TDateTime); virtual; procedure UpdateTimestampByName(const ColumnName: string; Value: TDateTime); virtual; procedure UpdateAsciiStreamByName(const ColumnName: string; Value: TStream); virtual; procedure UpdateUnicodeStreamByName(const ColumnName: string; Value: TStream); virtual; procedure UpdateBinaryStreamByName(const ColumnName: string; Value: TStream); virtual; procedure UpdateDataSetByName(const ColumnName: string; Value: IZDataSet); virtual; procedure UpdateValueByName(const ColumnName: string; const Value: TZVariant); virtual; procedure InsertRow; virtual; procedure UpdateRow; virtual; procedure DeleteRow; virtual; procedure RefreshRow; virtual; procedure CancelRowUpdates; virtual; procedure MoveToInsertRow; virtual; procedure MoveToCurrentRow; virtual; function CompareRows(Row1, Row2: Integer; const ColumnIndices: TIntegerDynArray; const ColumnDirs: TBooleanDynArray): Integer; virtual; function GetStatement: IZStatement; virtual; function GetConSettings: PZConsettings; property ColumnsInfo: TObjectList read FColumnsInfo write FColumnsInfo; end; {** Implements external or internal blob wrapper object. } TZAbstractBlob = class(TInterfacedObject, IZBlob) private FBlobData: Pointer; FBlobSize: Integer; FUpdated: Boolean; protected FConnection: IZConnection; FDecoded: Boolean; property BlobData: Pointer read FBlobData write FBlobData; property BlobSize: Integer read FBlobSize write FBlobSize; property Updated: Boolean read FUpdated write FUpdated; public constructor CreateWithStream(Stream: TStream; Connection: IZConnection = nil; Decoded: Boolean = False); constructor CreateWithData(Data: Pointer; Size: Integer; Connection: IZConnection = nil; Decoded: Boolean = False); destructor Destroy; override; function WasDecoded: Boolean; function Connection: IZConnection; function IsEmpty: Boolean; virtual; function IsUpdated: Boolean; virtual; function Length: LongInt; virtual; function GetString: RawByteString; virtual; procedure SetString(const Value: RawByteString); virtual; function GetUnicodeString: WideString; virtual; procedure SetUnicodeString(const Value: WideString); virtual; function GetBytes: TByteDynArray; virtual; procedure SetBytes(const Value: TByteDynArray); virtual; function GetUnicodeStream: TStream; virtual; function GetStream: TStream; virtual; procedure SetStream(Value: TStream; Decoded: Boolean = False); virtual; function GetBuffer: Pointer; procedure SetBuffer(Buffer: Pointer; Length: Integer); procedure Clear; virtual; function Clone: IZBlob; virtual; end; implementation uses ZMessages, ZDbcUtils, ZDbcResultSetMetadata, ZEncoding {$IFDEF WITH_ANSISTRCOMP_DEPRECATED}, AnsiStrings{$ENDIF}; { TZAbstractResultSet } {** Creates this object and assignes the main properties. @param Statement an SQL statement object. @param SQL an SQL query string. @param Metadata a resultset metadata object. } constructor TZAbstractResultSet.Create(Statement: IZStatement; SQL: string; Metadata: TContainedObject; ConSettings: PZConSettings); var DatabaseMetadata: IZDatabaseMetadata; begin Self.ConSettings := ConSettings; LastWasNull := True; FRowNo := 0; FLastRowNo := 0; FClosed := True; if Statement = nil then begin FResultSetType := rtForwardOnly; FResultSetConcurrency := rcReadOnly; FPostUpdates := poColumnsAll; FLocateUpdates := loWhereAll; FMaxRows := 0; end else begin FFetchDirection := Statement.GetFetchDirection; FFetchSize := Statement.GetFetchSize; FResultSetType := Statement.GetResultSetType; FResultSetConcurrency := Statement.GetResultSetConcurrency; FPostUpdates := Statement.GetPostUpdates; FLocateUpdates := Statement.GetLocateUpdates; FStatement := Statement; FMaxRows := Statement.GetMaxRows; end; if Metadata = nil then begin if Statement <> nil then DatabaseMetadata := GetStatement.GetConnection.GetMetadata else DatabaseMetadata := nil; FMetadata := TZAbstractResultSetMetadata.Create(DatabaseMetadata, SQL, Self); end else FMetadata := Metadata; FColumnsInfo := TObjectList.Create(True); //Free the MemoryLeaks of TZColumnInfo end; {** Destroys this object and cleanups the memory. } destructor TZAbstractResultSet.Destroy; begin if not FClosed then Close; if FMetadata <> nil then FMetadata.Free; FMetadata := nil; FStatement := nil; FColumnsInfo.Free; inherited Destroy; end; function TZAbstractResultSet.InternalGetString(ColumnIndex: Integer): RawByteString; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stString); {$ENDIF} Result := ''; end; {** Raises unsupported operation exception. } procedure TZAbstractResultSet.RaiseUnsupportedException; begin raise EZSQLException.Create(SUnsupportedOperation); end; {** Raises operation is not allowed in FORWARD ONLY mode exception. } procedure TZAbstractResultSet.RaiseForwardOnlyException; begin raise EZSQLException.Create(SOperationIsNotAllowed1); end; {** Raises operation is not allowed in READ ONLY mode exception. } procedure TZAbstractResultSet.RaiseReadOnlyException; begin raise EZSQLException.Create(SOperationIsNotAllowed2); end; {** Checks if result set is open and operation is allowed. } procedure TZAbstractResultSet.CheckClosed; begin if FClosed then raise EZSQLException.Create(SOperationIsNotAllowed4); end; {** Checks is the column convertion from one type to another type allowed. @param ColumnIndex an index of column. @param ResultType a requested data type. } procedure TZAbstractResultSet.CheckColumnConvertion(ColumnIndex: Integer; ResultType: TZSQLType); var InitialType: TZSQLType; Metadata: TZAbstractResultSetMetadata; begin CheckClosed; Metadata := TZAbstractResultSetMetadata(FMetadata); if (Metadata = nil) or (ColumnIndex <= 0) or (ColumnIndex > Metadata.GetColumnCount) then begin raise EZSQLException.Create( Format(SColumnIsNotAccessable, [ColumnIndex])); end; InitialType := Metadata.GetColumnType(ColumnIndex); if not CheckConvertion(InitialType, ResultType) then begin raise EZSQLException.Create(Format(SConvertionIsNotPossible, [ColumnIndex, DefineColumnTypeName(InitialType), DefineColumnTypeName(ResultType)])); end; end; {** Checks for blob expected column. @param ColumnIndex an index of column. } procedure TZAbstractResultSet.CheckBlobColumn(ColumnIndex: Integer); var InitialType: TZSQLType; Metadata: TZAbstractResultSetMetadata; begin CheckClosed; Metadata := TZAbstractResultSetMetadata(FMetadata); if (Metadata = nil) or (ColumnIndex <= 0) or (ColumnIndex > Metadata.GetColumnCount) then begin raise EZSQLException.Create( Format(SColumnIsNotAccessable, [ColumnIndex])); end; InitialType := Metadata.GetColumnType(ColumnIndex); if not (InitialType in [stAsciiStream, stBinaryStream, stUnicodeStream]) then begin raise EZSQLException.Create( Format(SCanNotAccessBlobRecord, [ColumnIndex, DefineColumnTypeName(InitialType)])); end; end; {** Set the concurrency mode of this ResultSet object. The concurrency used is determined by the Statement object that created the result set. @param the concurrency type, either CONCUR_READ_ONLY or CONCUR_UPDATABLE } procedure TZAbstractResultSet.SetConcurrency(Value: TZResultSetConcurrency); begin ResultSetConcurrency := Value; end; {** Set the type of this ResultSet object. The type is determined by the Statement object that created the result set. @param TYPE_FORWARD_ONLY, TYPE_SCROLL_INSENSITIVE, or TYPE_SCROLL_SENSITIVE } procedure TZAbstractResultSet.SetType(Value: TZResultSetType); begin ResultSetType := Value; end; {** Opens this recordset. } procedure TZAbstractResultSet.Open; begin FClosed := False; end; {** Releases this ResultSet object's database and JDBC resources immediately instead of waiting for this to happen when it is automatically closed.

Note: A ResultSet object is automatically closed by the Statement object that generated it when that Statement object is closed, re-executed, or is used to retrieve the next result from a sequence of multiple results. A ResultSet object is also automatically closed when it is garbage collected. } procedure TZAbstractResultSet.Close; var I: integer; FColumnInfo: TZColumnInfo; begin LastWasNull := True; FRowNo := 0; FLastRowNo := 0; FClosed := True; for I := FColumnsInfo.Count - 1 downto 0 do begin FColumnInfo:=TZColumnInfo(FColumnsInfo.Extract(FColumnsInfo.Items[I])); FColumnInfo.Free; end; FColumnsInfo.Clear; FStatement := nil; end; {** Reports whether the last column read had a value of SQL NULL. Note that you must first call one of the getXXX methods on a column to try to read its value and then call the method wasNull to see if the value read was SQL NULL. @return true if the last column value read was SQL NULL and false otherwise } function TZAbstractResultSet.WasNull: Boolean; begin Result := LastWasNull; end; //====================================================================== // Methods for accessing results by column index //====================================================================== {** Indicates if the value of the designated column in the current row of this ResultSet object is Null. @param columnIndex the first column is 1, the second is 2, ... @return if the value is SQL NULL, the value returned is true. false otherwise. } function TZAbstractResultSet.IsNull(ColumnIndex: Integer): Boolean; begin Result := True; end; {** Gets the value of the designated column in the current row of this ResultSet object as a PAnsiChar in the Delphi programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZAbstractResultSet.GetPChar(ColumnIndex: Integer): PChar; begin FTemp := GetString(ColumnIndex); Result := PChar(FTemp); end; {** Gets the value of the designated column in the current row of this ResultSet object as a String in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZAbstractResultSet.GetString(ColumnIndex: Integer): String; begin Result := ZDbcString(InternalGetString(ColumnIndex)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a String in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZAbstractResultSet.GetBinaryString(ColumnIndex: Integer): RawByteString; begin Result := InternalGetString(ColumnIndex); end; {** Gets the value of the designated column in the current row of this ResultSet object as a WideString in the Delphi programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZAbstractResultSet.GetUnicodeString(ColumnIndex: Integer): WideString; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stUnicodeString); {$ENDIF} Result := ZDbcUnicodeString(InternalGetString(ColumnIndex)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a boolean in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is false } function TZAbstractResultSet.GetBoolean(ColumnIndex: Integer): Boolean; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stBoolean); {$ENDIF} Result := False; end; {** Gets the value of the designated column in the current row of this ResultSet object as a byte in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZAbstractResultSet.GetByte(ColumnIndex: Integer): Byte; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stByte); {$ENDIF} Result := 0; end; {** Gets the value of the designated column in the current row of this ResultSet object as a short in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZAbstractResultSet.GetShort(ColumnIndex: Integer): SmallInt; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stShort); {$ENDIF} Result := 0; end; {** Gets the value of the designated column in the current row of this ResultSet object as an int in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZAbstractResultSet.GetInt(ColumnIndex: Integer): Integer; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stInteger); {$ENDIF} Result := 0; end; {** Gets the value of the designated column in the current row of this ResultSet object as a long in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZAbstractResultSet.GetLong(ColumnIndex: Integer): Int64; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stLong); {$ENDIF} Result := 0; end; {** Gets the value of the designated column in the current row of this ResultSet object as a float in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZAbstractResultSet.GetFloat(ColumnIndex: Integer): Single; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stFloat); {$ENDIF} Result := 0; end; {** Gets the value of the designated column in the current row of this ResultSet object as a double in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZAbstractResultSet.GetDouble(ColumnIndex: Integer): Double; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stDouble); {$ENDIF} Result := 0; end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.BigDecimal in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @param scale the number of digits to the right of the decimal point @return the column value; if the value is SQL NULL, the value returned is null } function TZAbstractResultSet.GetBigDecimal(ColumnIndex: Integer): Extended; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stBigDecimal); {$ENDIF} Result := 0; end; {** Gets the value of the designated column in the current row of this ResultSet object as a byte array in the Java programming language. The bytes represent the raw values returned by the driver. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZAbstractResultSet.GetBytes(ColumnIndex: Integer): TByteDynArray; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stBytes); {$ENDIF} Result := nil; end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Date object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZAbstractResultSet.GetDate(ColumnIndex: Integer): TDateTime; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stDate); {$ENDIF} Result := 0; end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Time object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZAbstractResultSet.GetTime(ColumnIndex: Integer): TDateTime; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stTime); {$ENDIF} Result := 0; end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null @exception SQLException if a database access error occurs } function TZAbstractResultSet.GetTimestamp(ColumnIndex: Integer): TDateTime; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stTimestamp); {$ENDIF} Result := 0; end; {** Gets the value of the designated column in the current row of this ResultSet object as a stream of ASCII characters. The value can then be read in chunks from the stream. This method is particularly suitable for retrieving large LONGVARCHAR values. The JDBC driver will do any necessary conversion from the database format into ASCII.

Note: All the data in the returned stream must be read prior to getting the value of any other column. The next call to a getXXX method implicitly closes the stream. Also, a stream may return 0 when the method InputStream.available is called whether there is data available or not. @param columnIndex the first column is 1, the second is 2, ... @return a Java input stream that delivers the database column value as a stream of one-byte ASCII characters; if the value is SQL NULL, the value returned is null } function TZAbstractResultSet.GetAsciiStream(ColumnIndex: Integer): TStream; var Blob: IZBlob; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stAsciiStream); {$ENDIF} Result := nil; if not IsNull(ColumnIndex) then begin Blob := GetBlob(ColumnIndex); if Blob <> nil then if Self.GetMetaData.GetColumnType(ColumnIndex) = stUnicodeStream then Result := TStringStream.Create(GetValidatedAnsiStringFromBuffer(Blob.GetBuffer, Blob.Length, ConSettings, ConSettings.CTRL_CP)) else Result := Blob.GetStream; end; LastWasNull := (Result = nil); end; {** Gets the value of a column in the current row as a stream of Gets the value of the designated column in the current row of this ResultSet object as as a stream of Unicode characters. The value can then be read in chunks from the stream. This method is particularly suitable for retrieving largeLONGVARCHARvalues. The JDBC driver will do any necessary conversion from the database format into Unicode. The byte format of the Unicode stream must be Java UTF-8, as specified in the Java virtual machine specification.

Note: All the data in the returned stream must be read prior to getting the value of any other column. The next call to a getXXX method implicitly closes the stream. Also, a stream may return 0 when the method InputStream.available is called whether there is data available or not. @param columnIndex the first column is 1, the second is 2, ... @return a Java input stream that delivers the database column value as a stream in Java UTF-8 byte format; if the value is SQL NULL, the value returned is null } function TZAbstractResultSet.GetUnicodeStream(ColumnIndex: Integer): TStream; var Blob: IZBlob; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stUnicodeStream); {$ENDIF} Result := nil; if not IsNull(ColumnIndex) then begin Blob := GetBlob(ColumnIndex); if Blob <> nil then Result := Blob.GetUnicodeStream; end; LastWasNull := (Result = nil); end; {** Gets the value of a column in the current row as a stream of Gets the value of the designated column in the current row of this ResultSet object as a binary stream of uninterpreted bytes. The value can then be read in chunks from the stream. This method is particularly suitable for retrieving large LONGVARBINARY values.

Note: All the data in the returned stream must be read prior to getting the value of any other column. The next call to a getXXX method implicitly closes the stream. Also, a stream may return 0 when the method InputStream.available is called whether there is data available or not. @param columnIndex the first column is 1, the second is 2, ... @return a Java input stream that delivers the database column value as a stream of uninterpreted bytes; if the value is SQL NULL, the value returned is null } function TZAbstractResultSet.GetBinaryStream(ColumnIndex: Integer): TStream; var Blob: IZBlob; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stBinaryStream); {$ENDIF} Result := nil; if not IsNull(ColumnIndex) then begin Blob := GetBlob(ColumnIndex); if Blob <> nil then Result := Blob.GetStream; end; LastWasNull := (Result = nil); end; {** Returns the value of the designated column in the current row of this ResultSet object as a Blob object in the Java programming language. @param ColumnIndex the first column is 1, the second is 2, ... @return a Blob object representing the SQL BLOB value in the specified column } function TZAbstractResultSet.GetBlob(ColumnIndex: Integer): IZBlob; begin {$IFNDEF DISABLE_CHECKING} CheckBlobColumn(ColumnIndex); {$ENDIF} Result := TZAbstractBlob.CreateWithStream(nil, GetStatement.GetConnection); end; {** Returns the value of the designated column in the current row of this ResultSet object as a IZResultSet object in the Java programming language. @param ColumnIndex the first column is 1, the second is 2, ... @return a IZResultSet object representing the SQL IZResultSet value in the specified column } function TZAbstractResultSet.GetDataSet(ColumnIndex: Integer): IZDataSet; begin Result := nil; end; {** Returns the value of the designated column in the current row of this ResultSet object as a Variant object. @param ColumnIndex the first column is 1, the second is 2, ... @return a Variant object representing the SQL any value in the specified column } function TZAbstractResultSet.GetValue(ColumnIndex: Integer): TZVariant; var Metadata: TZAbstractResultSetMetadata; begin {$IFNDEF DISABLE_CHECKING} CheckClosed; {$ENDIF} Metadata := TZAbstractResultSetMetadata(FMetadata); {$IFNDEF DISABLE_CHECKING} if (Metadata = nil) or (ColumnIndex <= 0) or (ColumnIndex > Metadata.GetColumnCount) then begin raise EZSQLException.Create( Format(SColumnIsNotAccessable, [ColumnIndex])); end; {$ENDIF} case Metadata.GetColumnType(ColumnIndex) of stBoolean: begin Result.VType := vtBoolean; Result.VBoolean := GetBoolean(ColumnIndex); end; stByte, stShort, stInteger, stLong: begin Result.VType := vtInteger; Result.VInteger := GetLong(ColumnIndex); end; stFloat, stDouble, stBigDecimal: begin Result.VType := vtFloat; Result.VFloat := GetBigDecimal(ColumnIndex); end; stDate, stTime, stTimestamp: begin Result.VType := vtDateTime; Result.VDateTime := GetTimestamp(ColumnIndex); end; stString, stBytes, stAsciiStream, stBinaryStream: begin Result.VType := vtString; Result.VString := String(GetString(ColumnIndex)); end; stUnicodeString, stUnicodeStream: begin Result.VType := vtUnicodeString; Result.VUnicodeString := GetUnicodeString(ColumnIndex); end; else Result.VType := vtNull; end; if WasNull then Result.VType := vtNull; end; {** Gets the DefaultExpression value of the designated column in the current row of this ResultSet object as a String. @param columnIndex the first column is 1, the second is 2, ... @return the DefaultExpression value } function TZAbstractResultSet.GetDefaultExpression(ColumnIndex: Integer): string; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stString); {$ENDIF} Result := ''; end; //====================================================================== // Methods for accessing results by column name //====================================================================== {** Indicates if the value of the designated column in the current row of this ResultSet object is Null. @param columnName the SQL name of the column @return if the value is SQL NULL, the value returned is true. false otherwise. } function TZAbstractResultSet.IsNullByName(const ColumnName: string): Boolean; begin Result := IsNull(GetColumnIndex(ColumnName)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a PAnsiChar in the Delphi programming language. @param columnName the SQL name of the column @return the column value; if the value is SQL NULL, the value returned is null } function TZAbstractResultSet.GetPCharByName(const ColumnName: string): PChar; begin Result := GetPChar(GetColumnIndex(ColumnName)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a String in the Java programming language. @param columnName the SQL name of the column @return the column value; if the value is SQL NULL, the value returned is null } function TZAbstractResultSet.GetStringByName(const ColumnName: string): String; begin Result := GetString(GetColumnIndex(ColumnName)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a String in the Java programming language. @param columnName the SQL name of the column @return the column value; if the value is SQL NULL, the value returned is null } function TZAbstractResultSet.GetBinaryStringByName(const ColumnName: string): RawByteString; begin Result := GetBinaryString(GetColumnIndex(ColumnName)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a WideString in the Object Pascal programming language. @param columnName the SQL name of the column @return the column value; if the value is SQL NULL, the value returned is null } function TZAbstractResultSet.GetUnicodeStringByName(const ColumnName: string): WideString; begin Result := GetUnicodeString(GetColumnIndex(ColumnName)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a boolean in the Java programming language. @param columnName the SQL name of the column @return the column value; if the value is SQL NULL, the value returned is false } function TZAbstractResultSet.GetBooleanByName(const ColumnName: string): Boolean; begin Result := GetBoolean(GetColumnIndex(ColumnName)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a byte in the Java programming language. @param columnName the SQL name of the column @return the column value; if the value is SQL NULL, the value returned is 0 } function TZAbstractResultSet.GetByteByName(const ColumnName: string): Byte; begin Result := GetByte(GetColumnIndex(ColumnName)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a short in the Java programming language. @param columnName the SQL name of the column @return the column value; if the value is SQL NULL, the value returned is 0 } function TZAbstractResultSet.GetShortByName(const ColumnName: string): SmallInt; begin Result := GetShort(GetColumnIndex(ColumnName)); end; {** Gets the value of the designated column in the current row of this ResultSet object as an int in the Java programming language. @param columnName the SQL name of the column @return the column value; if the value is SQL NULL, the value returned is 0 } function TZAbstractResultSet.GetIntByName(const ColumnName: string): Integer; begin Result := GetInt(GetColumnIndex(ColumnName)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a long in the Java programming language. @param columnName the SQL name of the column @return the column value; if the value is SQL NULL, the value returned is 0 } function TZAbstractResultSet.GetLongByName(const ColumnName: string): Int64; begin Result := GetLong(GetColumnIndex(ColumnName)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a float in the Java programming language. @param columnName the SQL name of the column @return the column value; if the value is SQL NULL, the value returned is 0 } function TZAbstractResultSet.GetFloatByName(const ColumnName: string): Single; begin Result := GetFloat(GetColumnIndex(ColumnName)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a double in the Java programming language. @param columnName the SQL name of the column @return the column value; if the value is SQL NULL, the value returned is 0 } function TZAbstractResultSet.GetDoubleByName(const ColumnName: string): Double; begin Result := GetDouble(GetColumnIndex(ColumnName)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.math.BigDecimal in the Java programming language. @param columnName the SQL name of the column @return the column value; if the value is SQL NULL, the value returned is null } function TZAbstractResultSet.GetBigDecimalByName(const ColumnName: string): Extended; begin Result := GetBigDecimal(GetColumnIndex(ColumnName)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a byte array in the Java programming language. The bytes represent the raw values returned by the driver. @param columnName the SQL name of the column @return the column value; if the value is SQL NULL, the value returned is null } function TZAbstractResultSet.GetBytesByName(const ColumnName: string): TByteDynArray; begin Result := GetBytes(GetColumnIndex(ColumnName)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Date object in the Java programming language. @param columnName the SQL name of the column @return the column value; if the value is SQL NULL, the value returned is null } function TZAbstractResultSet.GetDateByName(const ColumnName: string): TDateTime; begin Result := GetDate(GetColumnIndex(ColumnName)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Time object in the Java programming language. @param columnName the SQL name of the column @return the column value; if the value is SQL NULL, the value returned is null } function TZAbstractResultSet.GetTimeByName(const ColumnName: string): TDateTime; begin Result := GetTime(GetColumnIndex(ColumnName)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp object. @param columnName the SQL name of the column @return the column value; if the value is SQL NULL, the value returned is null } function TZAbstractResultSet.GetTimestampByName(const ColumnName: string): TDateTime; begin Result := GetTimestamp(GetColumnIndex(ColumnName)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a stream of ASCII characters. The value can then be read in chunks from the stream. This method is particularly suitable for retrieving large LONGVARCHAR values. The JDBC driver will do any necessary conversion from the database format into ASCII.

Note: All the data in the returned stream must be read prior to getting the value of any other column. The next call to a getXXX method implicitly closes the stream. Also, a stream may return 0 when the method available is called whether there is data available or not. @param columnName the SQL name of the column @return a Java input stream that delivers the database column value as a stream of one-byte ASCII characters. If the value is SQL NULL, the value returned is null. } function TZAbstractResultSet.GetAsciiStreamByName(const ColumnName: string): TStream; begin Result := GetAsciiStream(GetColumnIndex(ColumnName)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a stream of Unicode characters. The value can then be read in chunks from the stream. This method is particularly suitable for retrieving large LONGVARCHAR values. The JDBC driver will do any necessary conversion from the database format into Unicode. The byte format of the Unicode stream must be Java UTF-8, as defined in the Java virtual machine specification.

Note: All the data in the returned stream must be read prior to getting the value of any other column. The next call to a getXXX method implicitly closes the stream. Also, a stream may return 0 when the method available is called whether there is data available or not. @param columnName the SQL name of the column @return a Java input stream that delivers the database column value as a stream of two-byte Unicode characters. If the value is SQL NULL, the value returned is null. } function TZAbstractResultSet.GetUnicodeStreamByName(const ColumnName: string): TStream; begin Result := GetUnicodeStream(GetColumnIndex(ColumnName)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a stream of uninterpreted bytes. The value can then be read in chunks from the stream. This method is particularly suitable for retrieving large LONGVARBINARY values.

Note: All the data in the returned stream must be read prior to getting the value of any other column. The next call to a getXXX method implicitly closes the stream. Also, a stream may return 0 when the method available is called whether there is data available or not. @param columnName the SQL name of the column @return a Java input stream that delivers the database column value as a stream of uninterpreted bytes; if the value is SQL NULL, the result is null } function TZAbstractResultSet.GetBinaryStreamByName(const ColumnName: string): TStream; begin Result := GetBinaryStream(GetColumnIndex(ColumnName)); end; {** Returns the value of the designated column in the current row of this ResultSet object as a Blob object in the Java programming language. @param colName the name of the column from which to retrieve the value @return a Blob object representing the SQL BLOB value in the specified column } function TZAbstractResultSet.GetBlobByName(const ColumnName: string): IZBlob; begin Result := GetBlob(GetColumnIndex(ColumnName)); end; function TZAbstractResultSet.GetDataSetByName(const ColumnName: string): IZDataSet; begin Result := GetDataSet(GetColumnIndex(ColumnName)); end; {** Returns the value of the designated column in the current row of this ResultSet object as a Variant object. @param colName the name of the column from which to retrieve the value @return a Blob object representing the SQL Any value in the specified column } function TZAbstractResultSet.GetValueByName(const ColumnName: string): TZVariant; begin Result := GetValue(GetColumnIndex(ColumnName)); end; //===================================================================== // Advanced features: //===================================================================== {** Returns the first warning reported by calls on this ResultSet object. Subsequent warnings on this ResultSet object will be chained to the SQLWarning object that this method returns.

The warning chain is automatically cleared each time a new row is read.

Note: This warning chain only covers warnings caused by ResultSet methods. Any warning caused by Statement methods (such as reading OUT parameters) will be chained on the Statement object. @return the first SQLWarning object reported or null } function TZAbstractResultSet.GetWarnings: EZSQLWarning; begin Result := nil; end; {** Clears all warnings reported on this ResultSet object. After this method is called, the method getWarnings returns null until a new warning is reported for this ResultSet object. } procedure TZAbstractResultSet.ClearWarnings; begin end; {** Gets the name of the SQL cursor used by this ResultSet object.

In SQL, a result table is retrieved through a cursor that is named. The current row of a result set can be updated or deleted using a positioned update/delete statement that references the cursor name. To insure that the cursor has the proper isolation level to support update, the cursor's select statement should be of the form 'select for update'. If the 'for update' clause is omitted, the positioned updates may fail.

The JDBC API supports this SQL feature by providing the name of the SQL cursor used by a ResultSet object. The current row of a ResultSet object is also the current row of this SQL cursor.

Note: If positioned update is not supported, a SQLException is thrown. @return the SQL name for this ResultSet object's cursor } function TZAbstractResultSet.GetCursorName: AnsiString; begin Result := ''; end; {** Retrieves the number, types and properties of this ResultSet object's columns. @return the description of this ResultSet object's columns } function TZAbstractResultSet.GetMetaData: IZResultSetMetaData; begin Result := TZAbstractResultSetMetadata(FMetadata); end; {** Maps the given ResultSet column name to its ResultSet column index. @param columnName the name of the column @return the column index of the given column name } function TZAbstractResultSet.GetColumnIndex(const ColumnName: string): Integer; begin Result := FindColumn(ColumnName); if Result < 1 then raise EZSQLException.Create(Format(SColumnWasNotFound, [ColumnName])); end; {** Maps the given ResultSet column name to its ResultSet column index. @param columnName the name of the column @return the column index of the given column name } function TZAbstractResultSet.FindColumn(const ColumnName: string): Integer; var I: Integer; Metadata: TZAbstractResultSetMetadata; begin CheckClosed; Metadata := TZAbstractResultSetMetadata(FMetadata); Result := 0; { Search for case sensitive columns. } for I := 1 to Metadata.GetColumnCount do begin if Metadata.GetColumnLabel(I) = ColumnName then begin Result := I; Exit; end; end; { Search for case insensitive columns. } for I := 1 to Metadata.GetColumnCount do begin if AnsiUpperCase(Metadata.GetColumnLabel(I)) = AnsiUpperCase(ColumnName) then begin Result := I; Exit; end; end; end; //--------------------------------------------------------------------- // Traversal/Positioning //--------------------------------------------------------------------- {** Indicates whether the cursor is before the first row in this ResultSet object. @return true if the cursor is before the first row; false if the cursor is at any other position or the result set contains no rows } function TZAbstractResultSet.IsBeforeFirst: Boolean; begin Result := (FRowNo = 0); end; {** Indicates whether the cursor is after the last row in this ResultSet object. @return true if the cursor is after the last row; false if the cursor is at any other position or the result set contains no rows } function TZAbstractResultSet.IsAfterLast: Boolean; begin Result := {(FLastRowNo > 0) and} (FRowNo > FLastRowNo); end; {** Indicates whether the cursor is on the first row of this ResultSet object. @return true if the cursor is on the first row; false otherwise } function TZAbstractResultSet.IsFirst: Boolean; begin Result := (FRowNo = 1); end; {** Indicates whether the cursor is on the last row of this ResultSet object. Note: Calling the method isLast may be expensive because the JDBC driver might need to fetch ahead one row in order to determine whether the current row is the last row in the result set. @return true if the cursor is on the last row; false otherwise } function TZAbstractResultSet.IsLast: Boolean; begin Result := {(FLastRowNo > 0) and} (FRowNo = FLastRowNo); end; {** Moves the cursor to the front of this ResultSet object, just before the first row. This method has no effect if the result set contains no rows. } procedure TZAbstractResultSet.BeforeFirst; begin MoveAbsolute(0); end; {** Moves the cursor to the end of this ResultSet object, just after the last row. This method has no effect if the result set contains no rows. } procedure TZAbstractResultSet.AfterLast; begin Last; Next; end; {** Moves the cursor to the first row in this ResultSet object. @return true if the cursor is on a valid row; false if there are no rows in the result set } function TZAbstractResultSet.First: Boolean; begin Result := MoveAbsolute(1); end; {** Moves the cursor to the last row in this ResultSet object. @return true if the cursor is on a valid row; false if there are no rows in the result set } function TZAbstractResultSet.Last: Boolean; begin Result := MoveAbsolute(FLastRowNo); end; {** Retrieves the current row number. The first row is number 1, the second number 2, and so on. @return the current row number; 0 if there is no current row } function TZAbstractResultSet.GetRow: Integer; begin Result := FRowNo; end; {** Moves the cursor to the given row number in this ResultSet object.

If the row number is positive, the cursor moves to the given row number with respect to the beginning of the result set. The first row is row 1, the second is row 2, and so on.

If the given row number is negative, the cursor moves to an absolute row position with respect to the end of the result set. For example, calling the method absolute(-1) positions the cursor on the last row; calling the method absolute(-2) moves the cursor to the next-to-last row, and so on.

An attempt to position the cursor beyond the first/last row in the result set leaves the cursor before the first row or after the last row.

Note: Calling absolute(1) is the same as calling first(). Calling absolute(-1) is the same as calling last(). @return true if the cursor is on the result set; false otherwise } function TZAbstractResultSet.MoveAbsolute(Row: Integer): Boolean; begin Result := False; RaiseForwardOnlyException; end; {** Moves the cursor a relative number of rows, either positive or negative. Attempting to move beyond the first/last row in the result set positions the cursor before/after the the first/last row. Calling relative(0) is valid, but does not change the cursor position.

Note: Calling the method relative(1) is different from calling the method next() because is makes sense to call next() when there is no current row, for example, when the cursor is positioned before the first row or after the last row of the result set. @return true if the cursor is on a row; false otherwise } function TZAbstractResultSet.MoveRelative(Rows: Integer): Boolean; begin Result := MoveAbsolute(FRowNo + Rows); end; {** Moves the cursor to the previous row in this ResultSet object.

Note: Calling the method previous() is not the same as calling the method relative(-1) because it makes sense to callprevious() when there is no current row. @return true if the cursor is on a valid row; false if it is off the result set } function TZAbstractResultSet.Previous: Boolean; begin Result := MoveAbsolute(FRowNo - 1); end; {** Moves the cursor down one row from its current position. A ResultSet cursor is initially positioned before the first row; the first call to the method next makes the first row the current row; the second call makes the second row the current row, and so on.

If an input stream is open for the current row, a call to the method next will implicitly close it. A ResultSet object's warning chain is cleared when a new row is read. @return true if the new current row is valid; false if there are no more rows } function TZAbstractResultSet.Next: Boolean; begin Result := MoveAbsolute(FRowNo + 1); end; //--------------------------------------------------------------------- // Properties //--------------------------------------------------------------------- {** Returns the fetch direction for this ResultSet object. @return the current fetch direction for this ResultSet object } function TZAbstractResultSet.GetFetchDirection: TZFetchDirection; begin Result := FFetchDirection; end; {** Gives a hint as to the direction in which the rows in this ResultSet object will be processed. The initial value is determined by the Statement object that produced this ResultSet object. The fetch direction may be changed at any time. } procedure TZAbstractResultSet.SetFetchDirection(Direction: TZFetchDirection); begin if Direction <> fdForward then RaiseUnsupportedException; end; {** Returns the fetch size for this ResultSet object. @return the current fetch size for this ResultSet object } function TZAbstractResultSet.GetFetchSize: Integer; begin Result := FFetchSize; end; {** Gives the JDBC driver a hint as to the number of rows that should be fetched from the database when more rows are needed for this ResultSet object. If the fetch size specified is zero, the JDBC driver ignores the value and is free to make its own best guess as to what the fetch size should be. The default value is set by the Statement object that created the result set. The fetch size may be changed at any time. @param rows the number of rows to fetch } procedure TZAbstractResultSet.SetFetchSize(Rows: Integer); begin FFetchSize := Rows; end; {** Returns the type of this ResultSet object. The type is determined by the Statement object that created the result set. @return TYPE_FORWARD_ONLY, TYPE_SCROLL_INSENSITIVE, or TYPE_SCROLL_SENSITIVE } function TZAbstractResultSet.GetType: TZResultSetType; begin Result := FResultSetType; end; {** Returns the concurrency mode of this ResultSet object. The concurrency used is determined by the Statement object that created the result set. @return the concurrency type, either CONCUR_READ_ONLY or CONCUR_UPDATABLE } function TZAbstractResultSet.GetConcurrency: TZResultSetConcurrency; begin Result := FResultSetConcurrency; end; {** Gets an assigned post locate mode. @param the assigned post locate mode. } function TZAbstractResultSet.GetLocateUpdates: TZLocateUpdatesMode; begin Result := FLocateUpdates; end; function TZAbstractResultSet.GetPostUpdates: TZPostUpdatesMode; begin Result := FPostUpdates; end; //--------------------------------------------------------------------- // Updates //--------------------------------------------------------------------- {** Indicates whether the current row has been updated. The value returned depends on whether or not the result set can detect updates. @return true if the row has been visibly updated by the owner or another, and updates are detected } function TZAbstractResultSet.RowUpdated: Boolean; begin Result := False; end; {** Indicates whether the current row has had an insertion. The value returned depends on whether or not this ResultSet object can detect visible inserts. @return true if a row has had an insertion and insertions are detected; false otherwise } function TZAbstractResultSet.RowInserted: Boolean; begin Result := False; end; {** Indicates whether a row has been deleted. A deleted row may leave a visible "hole" in a result set. This method can be used to detect holes in a result set. The value returned depends on whether or not this ResultSet object can detect deletions. @return true if a row was deleted and deletions are detected; false otherwise } function TZAbstractResultSet.RowDeleted: Boolean; begin Result := False; end; {** Gives a nullable column a null value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... } procedure TZAbstractResultSet.UpdateNull(ColumnIndex: Integer); begin RaiseReadOnlyException; end; {** Updates the designated column with a boolean value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractResultSet.UpdateBoolean(ColumnIndex: Integer; Value: Boolean); begin RaiseReadOnlyException; end; {** Updates the designated column with a byte value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractResultSet.UpdateByte(ColumnIndex: Integer; Value: ShortInt); begin RaiseReadOnlyException; end; {** Updates the designated column with a short value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractResultSet.UpdateShort(ColumnIndex: Integer; Value: SmallInt); begin RaiseReadOnlyException; end; {** Updates the designated column with an int value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractResultSet.UpdateInt(ColumnIndex: Integer; Value: Integer); begin RaiseReadOnlyException; end; {** Updates the designated column with a long value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractResultSet.UpdateLong(ColumnIndex: Integer; Value: Int64); begin RaiseReadOnlyException; end; {** Updates the designated column with a float value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractResultSet.UpdateFloat(ColumnIndex: Integer; Value: Single); begin RaiseReadOnlyException; end; {** Updates the designated column with a double value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractResultSet.UpdateDouble(ColumnIndex: Integer; Value: Double); begin RaiseReadOnlyException; end; {** Updates the designated column with a java.math.BigDecimal value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractResultSet.UpdateBigDecimal(ColumnIndex: Integer; Value: Extended); begin RaiseReadOnlyException; end; {** Updates the designated column with a String value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractResultSet.UpdatePChar(ColumnIndex: Integer; Value: PChar); begin UpdateString(ColumnIndex, Value); end; {** Updates the designated column with a String value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractResultSet.UpdateString(ColumnIndex: Integer; const Value: String); begin RaiseReadOnlyException; end; {** Updates the designated column with a String value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractResultSet.UpdateBinaryString(ColumnIndex: Integer; const Value: RawByteString); begin case GetMetaData.GetColumnType(ColumnIndex) of stBytes: UpdateBytes(ColumnIndex, StrToBytes(Value)); stBinaryStream: GetBlob(ColumnIndex).SetString(Value); else UpdateString(ColumnIndex, ZDbcString(Value)); end; end; {** Updates the designated column with a WideString value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractResultSet.UpdateUnicodeString(ColumnIndex: Integer; const Value: WideString); begin RaiseReadOnlyException; end; {** Updates the designated column with a byte array value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractResultSet.UpdateBytes(ColumnIndex: Integer; const Value: TByteDynArray); begin RaiseReadOnlyException; end; {** Updates the designated column with a java.sql.Date value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractResultSet.UpdateDate(ColumnIndex: Integer; Value: TDateTime); begin RaiseReadOnlyException; end; {** Updates the designated column with a java.sql.Time value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractResultSet.UpdateTime(ColumnIndex: Integer; Value: TDateTime); begin RaiseReadOnlyException; end; {** Updates the designated column with a java.sql.Timestamp value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractResultSet.UpdateTimestamp(ColumnIndex: Integer; Value: TDateTime); begin RaiseReadOnlyException; end; {** Updates the designated column with an ascii stream value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractResultSet.UpdateAsciiStream(ColumnIndex: Integer; Value: TStream); begin RaiseReadOnlyException; end; {** Updates the designated column with a binary stream value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value @param length the length of the stream } procedure TZAbstractResultSet.UpdateBinaryStream(ColumnIndex: Integer; Value: TStream); begin RaiseReadOnlyException; end; procedure TZAbstractResultSet.UpdateDataSet(ColumnIndex: Integer; Value: IZDataSet); begin RaiseReadOnlyException; end; {** Updates the designated column with a character stream value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractResultSet.UpdateUnicodeStream(ColumnIndex: Integer; Value: TStream); begin RaiseReadOnlyException; end; {** Updates the designated column with a variant value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnIndex the first column is 1, the second is 2, ... @param x the new column value } procedure TZAbstractResultSet.UpdateValue(ColumnIndex: Integer; const Value: TZVariant); begin case Value.VType of vtBoolean: UpdateBoolean(ColumnIndex, Value.VBoolean); vtInteger: UpdateLong(ColumnIndex, Value.VInteger); vtFloat: UpdateBigDecimal(ColumnIndex, Value.VFloat); vtString: UpdateString(ColumnIndex, Value.VString); vtDateTime: UpdateTimestamp(ColumnIndex, Value.VDateTime); vtUnicodeString: UpdateUnicodeString(ColumnIndex, Value.VUnicodeString); else UpdateNull(ColumnIndex); end; end; {** Updates the DefaultExpression of the designated column with a String value. This changes the behaviour of the RowAccessor used by the Resultset @param columnIndex the first column is 1, the second is 2, ... @param x the new DefaultExpression value for the column } procedure TZAbstractResultSet.UpdateDefaultExpression(ColumnIndex: Integer; const Value: string); begin RaiseReadOnlyException; end; {** Updates the designated column with a null value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnName the name of the column } procedure TZAbstractResultSet.UpdateNullByName(const ColumnName: string); begin UpdateNull(GetColumnIndex(ColumnName)); end; {** Updates the designated column with a boolean value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnName the name of the column @param x the new column value } procedure TZAbstractResultSet.UpdateBooleanByName(const ColumnName: string; Value: Boolean); begin UpdateBoolean(GetColumnIndex(ColumnName), Value); end; {** Updates the designated column with a byte value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnName the name of the column @param x the new column value } procedure TZAbstractResultSet.UpdateByteByName(const ColumnName: string; Value: ShortInt); begin UpdateByte(GetColumnIndex(ColumnName), Value); end; {** Updates the designated column with a short value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnName the name of the column @param x the new column value } procedure TZAbstractResultSet.UpdateShortByName(const ColumnName: string; Value: SmallInt); begin UpdateShort(GetColumnIndex(ColumnName), Value); end; {** Updates the designated column with an int value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnName the name of the column @param x the new column value } procedure TZAbstractResultSet.UpdateIntByName(const ColumnName: string; Value: Integer); begin UpdateInt(GetColumnIndex(ColumnName), Value); end; {** Updates the designated column with a long value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnName the name of the column @param x the new column value } procedure TZAbstractResultSet.UpdateLongByName(const ColumnName: string; Value: Int64); begin UpdateLong(GetColumnIndex(ColumnName), Value); end; {** Updates the designated column with a float value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnName the name of the column @param x the new column value } procedure TZAbstractResultSet.UpdateFloatByName(const ColumnName: string; Value: Single); begin UpdateFloat(GetColumnIndex(ColumnName), Value); end; {** Updates the designated column with a double value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnName the name of the column @param x the new column value } procedure TZAbstractResultSet.UpdateDoubleByName(const ColumnName: string; Value: Double); begin UpdateDouble(GetColumnIndex(ColumnName), Value); end; {** Updates the designated column with a java.sql.BigDecimal value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnName the name of the column @param x the new column value } procedure TZAbstractResultSet.UpdateBigDecimalByName(const ColumnName: string; Value: Extended); begin UpdateBigDecimal(GetColumnIndex(ColumnName), Value); end; {** Updates the designated column with a String value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnName the name of the column @param x the new column value } procedure TZAbstractResultSet.UpdatePCharByName(const ColumnName: string; Value: PChar); begin UpdatePChar(GetColumnIndex(ColumnName), Value); end; {** Updates the designated column with a String value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnName the name of the column @param x the new column value } procedure TZAbstractResultSet.UpdateStringByName(const ColumnName: string; const Value: String); begin UpdateString(GetColumnIndex(ColumnName), Value); end; {** Updates the designated column with a String value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnName the name of the column @param x the new column value } procedure TZAbstractResultSet.UpdateBinaryStringByName(const ColumnName: string; const Value: RawByteString); begin UpdateBinaryString(GetColumnIndex(ColumnName), Value); end; {** Updates the designated column with a WideString value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnName the name of the column @param x the new column value } procedure TZAbstractResultSet.UpdateUnicodeStringByName(const ColumnName: string; const Value: WideString); begin UpdateUnicodeString(GetColumnIndex(ColumnName), Value); end; {** Updates the designated column with a boolean value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. JDBC 2.0 Updates a column with a byte array value. The updateXXX methods are used to update column values in the current row, or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnName the name of the column @param x the new column value } procedure TZAbstractResultSet.UpdateBytesByName(const ColumnName: string; const Value: TByteDynArray); begin UpdateBytes(GetColumnIndex(ColumnName), Value); end; {** Updates the designated column with a java.sql.Date value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnName the name of the column @param x the new column value } procedure TZAbstractResultSet.UpdateDateByName(const ColumnName: string; Value: TDateTime); begin UpdateDate(GetColumnIndex(ColumnName), Value); end; {** Updates the designated column with a java.sql.Time value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnName the name of the column @param x the new column value } procedure TZAbstractResultSet.UpdateTimeByName(const ColumnName: string; Value: TDateTime); begin UpdateTime(GetColumnIndex(ColumnName), Value); end; {** Updates the designated column with a java.sql.Timestamp value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnName the name of the column @param x the new column value } procedure TZAbstractResultSet.UpdateTimestampByName(const ColumnName: string; Value: TDateTime); begin UpdateTimestamp(GetColumnIndex(ColumnName), Value); end; {** Updates the designated column with an ascii stream value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnName the name of the column @param x the new column value } procedure TZAbstractResultSet.UpdateAsciiStreamByName(const ColumnName: string; Value: TStream); begin UpdateAsciiStream(GetColumnIndex(ColumnName), Value); end; {** Updates the designated column with a binary stream value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnName the name of the column @param x the new column value } procedure TZAbstractResultSet.UpdateBinaryStreamByName(const ColumnName: string; Value: TStream); begin UpdateBinaryStream(GetColumnIndex(ColumnName), Value); end; procedure TZAbstractResultSet.UpdateDataSetByName(const ColumnName: string; Value: IZDataSet); begin UpdateDataSet(GetColumnIndex(ColumnName), Value); end; {** Updates the designated column with a character stream value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnName the name of the column @param x the new column value } procedure TZAbstractResultSet.UpdateUnicodeStreamByName(const ColumnName: string; Value: TStream); begin UpdateUnicodeStream(GetColumnIndex(ColumnName), Value); end; {** Updates the designated column with a Variant value. The updateXXX methods are used to update column values in the current row or the insert row. The updateXXX methods do not update the underlying database; instead the updateRow or insertRow methods are called to update the database. @param columnName the name of the column @param x the new column value } procedure TZAbstractResultSet.UpdateValueByName(const ColumnName: string; const Value: TZVariant); begin UpdateValue(GetColumnIndex(ColumnName), Value); end; {** Inserts the contents of the insert row into this ResultSet objaect and into the database. The cursor must be on the insert row when this method is called. } procedure TZAbstractResultSet.InsertRow; begin RaiseReadOnlyException; end; {** Updates the underlying database with the new contents of the current row of this ResultSet object. This method cannot be called when the cursor is on the insert row. } procedure TZAbstractResultSet.UpdateRow; begin RaiseReadOnlyException; end; {** Deletes the current row from this ResultSet object and from the underlying database. This method cannot be called when the cursor is on the insert row. } procedure TZAbstractResultSet.DeleteRow; begin RaiseReadOnlyException; end; {** Refreshes the current row with its most recent value in the database. This method cannot be called when the cursor is on the insert row.

The refreshRow method provides a way for an application to explicitly tell the JDBC driver to refetch a row(s) from the database. An application may want to call refreshRow when caching or prefetching is being done by the JDBC driver to fetch the latest value of a row from the database. The JDBC driver may actually refresh multiple rows at once if the fetch size is greater than one.

All values are refetched subject to the transaction isolation level and cursor sensitivity. If refreshRow is called after calling an updateXXX method, but before calling the method updateRow, then the updates made to the row are lost. Calling the method refreshRow frequently will likely slow performance. } procedure TZAbstractResultSet.RefreshRow; begin RaiseUnsupportedException; end; {** Cancels the updates made to the current row in this ResultSet object. This method may be called after calling an updateXXX method(s) and before calling the method updateRow to roll back the updates made to a row. If no updates have been made or updateRow has already been called, this method has no effect. } procedure TZAbstractResultSet.CancelRowUpdates; begin RaiseReadOnlyException; end; {** Moves the cursor to the insert row. The current cursor position is remembered while the cursor is positioned on the insert row. The insert row is a special row associated with an updatable result set. It is essentially a buffer where a new row may be constructed by calling the updateXXX methods prior to inserting the row into the result set. Only the updateXXX, getXXX, and insertRow methods may be called when the cursor is on the insert row. All of the columns in a result set must be given a value each time this method is called before calling insertRow. An updateXXX method must be called before a getXXX method can be called on a column value. } procedure TZAbstractResultSet.MoveToInsertRow; begin RaiseReadOnlyException; end; {** Moves the cursor to the remembered cursor position, usually the current row. This method has no effect if the cursor is not on the insert row. } procedure TZAbstractResultSet.MoveToCurrentRow; begin end; {** Compares fields from two row buffers. @param Row1 the first row buffer to compare. @param Row2 the second row buffer to compare. @param ColumnIndices column indices to compare. @param ColumnDirs compare direction for each columns. } function TZAbstractResultSet.CompareRows(Row1, Row2: Integer; const ColumnIndices: TIntegerDynArray; const ColumnDirs: TBooleanDynArray): Integer; var I: Integer; ColumnIndex: Integer; SaveRowNo: Integer; Value1, Value2: TZVariant; function CompareFloat(Value1, Value2: Extended): Integer; begin Value1 := Value1 - Value2; if Value1 > 0 then Result := 1 else if Value1 < 0 then Result := -1 else Result := 0; end; begin Result := 0; SaveRowNo := RowNo; try for I := Low(ColumnIndices) to High(ColumnIndices) do begin ColumnIndex := ColumnIndices[I]; MoveAbsolute(Row1); Value1 := GetValue(ColumnIndex); MoveAbsolute(Row2); Value2 := GetValue(ColumnIndex); { Checks for both Null columns. } if (Value1.VType = vtNull) and (Value2.VType = vtNull) then Continue; { Checks for not-Null and Null columns. } if (Value1.VType = vtNull) or (Value2.VType = vtNull) then begin if Value1.VType <> vtNull then Result := 1 else Result := -1; if not ColumnDirs[I] then Result := -Result; Break; end; case Value1.VType of vtBoolean: begin if Value1.VBoolean = Value2.VBoolean then Result := 0 else if Value1.VBoolean = True then Result := 1 else Result := -1; end; vtInteger: Result := Value1.VInteger - Value2.VInteger; vtFloat: Result := CompareFloat(Value1.VFloat, Value2.VFloat); vtDateTime: Result := CompareFloat(Value1.VDateTime, Value2.VDateTime); vtString: Result := AnsiCompareStr(Value1.VString, Value2.VString); vtUnicodeString: Result := WideCompareStr(Value1.VUnicodeString, Value2.VUnicodeString); end; if Result <> 0 then begin if not ColumnDirs[I] then Result := -Result; Break; end; end; finally MoveAbsolute(SaveRowNo); end; end; {** Returns the Statement object that produced this ResultSet object. If the result set was generated some other way, such as by a DatabaseMetaData method, this method returns null. @return the Statment object that produced this ResultSet object or null if the result set was produced some other way } function TZAbstractResultSet.GetStatement: IZStatement; begin Result := FStatement; end; function TZAbstractResultSet.GetConSettings: PZConsettings; begin Result := ConSettings; end; { TZAbstractBlob } {** Constructs this class and assignes the main properties. @param Stream a data string object. } constructor TZAbstractBlob.CreateWithStream(Stream: TStream; Connection: IZConnection = Nil; Decoded: Boolean = False); begin inherited Create; FUpdated := False; FConnection := Connection; FDecoded := Decoded; if Assigned(Stream) then begin FBlobSize := Stream.Size; if FBlobSize > 0 then begin GetMem(FBlobData, FBlobSize); Stream.Position := 0; Stream.ReadBuffer(FBlobData^, FBlobSize); end; end else begin FBlobSize := -1; FBlobData := nil; end; end; {** Constructs this class and assignes the main properties. @param Data a pointer to the blobdata. @param Size the size of the blobdata. } constructor TZAbstractBlob.CreateWithData(Data: Pointer; Size: Integer; Connection: IZConnection = nil; Decoded: Boolean = False); begin inherited Create; FConnection := Connection; FBlobData := nil; FBlobSize := Size; FDecoded := Decoded; if FBlobSize > 0 then begin GetMem(FBlobData, FBlobSize); System.Move(Data^, FBlobData^, FBlobSize); end; FUpdated := False; end; {** Destroys this object and cleanups the memory. } destructor TZAbstractBlob.Destroy; begin Clear; inherited Destroy; end; {** Clears the content of this blob. } procedure TZAbstractBlob.Clear; begin if Assigned(FBlobData) then FreeMem(FBlobData); FBlobData := nil; FBlobSize := -1; FUpdated := True; end; {** Clones this blob object. @return a clonned blob object. } function TZAbstractBlob.Clone: IZBlob; begin Result := TZAbstractBlob.CreateWithData(FBlobData, FBlobSize, FConnection, FDecoded); end; {** Checks if this Text-blob was right Decoded. @return True if this blob is empty. } function TZAbstractBlob.WasDecoded: Boolean; begin Result := FDecoded; end; {** Returns the IZConnection which is propable needed to handle the encoding @return IZConnection if assigned } function TZAbstractBlob.Connection: IZConnection; begin Result := FConnection; end; {** Checks if this blob has an empty content. @return True if this blob is empty. } function TZAbstractBlob.IsEmpty: Boolean; begin Result := FBlobSize < 0; end; {** Checks if the content of this blob was updated. @return True is this blob was updated. } function TZAbstractBlob.IsUpdated: Boolean; begin Result := FUpdated; end; {** Gets the length of the stored data. @return the length of the stored data or null if the blob is empty. } function TZAbstractBlob.Length: LongInt; begin Result := FBlobSize; end; {** Gets the string from the stored data. @return a string which contains the stored data. } function TZAbstractBlob.GetString: RawByteString; begin if (FBlobSize > 0) and Assigned(FBlobData) then if FDecoded then Result := FConnection.GetIZPlainDriver.ZPlainString(GetUnicodeString, FConnection.GetConSettings) else begin {$IFDEF WITH_RAWBYTESTRING} SetLength(Result, FBlobSize); System.Move(PAnsiChar(FBlobData)^, PAnsiChar(Result)^, FBlobSize); {$ELSE} System.SetString(Result, PAnsiChar(FBlobData), FBlobSize); {$ENDIF} end else Result := ''; end; {** Sets a new string data to this blob content. @param Value a new string data. } procedure TZAbstractBlob.SetString(const Value: RawByteString); begin Clear; FBlobSize := System.Length(Value); if FBlobSize > 0 then begin GetMem(FBlobData, FBlobSize); System.Move(PAnsiChar(Value)^, FBlobData^, FBlobSize); end; FUpdated := True; end; {** Gets the wide string from the stored data. @return a string which contains the stored data. } function TZAbstractBlob.GetUnicodeString: WideString; var Bytes: TByteDynArray; begin if (FBlobSize > 0) and Assigned(FBlobData) then if FDecoded then begin SetLength(Result, FBlobSize div 2); System.Move(PWidechar(FBlobData)^, PWideChar(Result)^, FBlobSize); end else begin SetLength(Bytes, FBlobSize +2); System.move(FBlobData^, Pointer(Bytes)^, FBlobSize); if ( not ( {$IFDEF WITH_ANSISTRCOMP_DEPRECATED}AnsiStrings.{$ENDIF}StrLen(PAnsiChar(Bytes)) = Cardinal(FBlobSize) ) ) and ( {$IFDEF DELPHI14_UP}StrLen{$ELSE}System.Length{$ENDIF}(PWideChar(Bytes)) = Cardinal(FBlobSize) div 2 ) then begin SetLength(Result, FBlobSize div 2); System.Move(PWidechar(Bytes)^, PWideChar(Result)^, FBlobSize); end else Result := FConnection.GetIZPlainDriver.ZDbcUnicodeString(PAnsiChar(Bytes), FConnection.GetConSettings.CTRL_CP); SetLength(Bytes, 0); end else Result := ''; end; {** Sets a new string data to this blob content. @param Value a new wide string data. } procedure TZAbstractBlob.SetUnicodeString(const Value: WideString); begin Clear; FBlobSize := System.Length(Value) *2; if FBlobSize > 0 then begin GetMem(FBlobData, FBlobSize); System.Move(PWideChar(Value)^, FBlobData^, FBlobSize); end; FUpdated := True; FDecoded := True; end; {** Gets the byte buffer from the stored data. @return a byte buffer which contains the stored data. } function TZAbstractBlob.GetBytes: TByteDynArray; begin if not IsEmpty then begin if (FBlobSize > 0) and Assigned(FBlobData) then begin SetLength(Result, FBlobSize); Move(FBlobData^, Result[0], FBlobSize); end else Result := nil; end else Result := nil; end; {** Sets a new byte buffer to this blob content. @param Value a new byte buffer. } procedure TZAbstractBlob.SetBytes(const Value: TByteDynArray); begin Clear; if Value <> nil then begin FBlobSize := System.Length(Value); if FBlobSize > 0 then begin GetMem(FBlobData, FBlobSize); System.Move(Value[0], FBlobData^, FBlobSize); end; end; FUpdated := True; end; function TZAbstractBlob.GetUnicodeStream: TStream; var ws: WideString; begin Result := TMemoryStream.Create; if (FBlobSize > 0) and Assigned(FBlobData) then begin if ( not ( {$IFDEF WITH_ANSISTRCOMP_DEPRECATED}AnsiStrings.{$ENDIF}StrLen(PAnsiChar(FBlobData)) = Cardinal(FBlobSize) ) ) and ( {$IFDEF DELPHI14_UP}StrLen{$ELSE}System.Length{$ENDIF}(PWideChar(FBlobData)) = Cardinal(FBlobSize) div 2 ) then begin Result.Size := FBlobSize; System.Move(PWidechar(FBlobData)^, TMemoryStream(Result).Memory^, FBlobSize); end else begin ws:=GetUnicodeString; Result.Size := System.Length(WS)*2; System.Move(ws[1], TMemoryStream(Result).Memory^, Result.Size); end; end; Result.Position := 0; end; {** Gets the associated stream object. @return an associated or newly created stream object. } function TZAbstractBlob.GetStream: TStream; begin Result := TMemoryStream.Create; if (FBlobSize > 0) and Assigned(FBlobData) then begin Result.Size := FBlobSize; System.Move(FBlobData^, TMemoryStream(Result).Memory^, FBlobSize); end; Result.Position := 0; end; {** Sets a data from the specified stream into this blob. @param Value a stream object to be stored into this blob. } procedure TZAbstractBlob.SetStream(Value: TStream; Decoded: Boolean = False); begin Clear; if Assigned(Value) then begin FBlobSize := Value.Size; if FBlobSize > 0 then begin GetMem(FBlobData, FBlobSize); Value.Position := 0; Value.ReadBuffer(FBlobData^, FBlobSize); end; end else begin FBlobSize := -1; FBlobData := nil; end; FUpdated := True; FDecoded := Decoded; end; function TZAbstractBlob.GetBuffer: Pointer; begin Result := FBlobData; end; procedure TZAbstractBlob.SetBuffer(Buffer: Pointer; Length: Integer); begin FBlobSize := Length; if Assigned(Buffer) and ( Length > 0 ) then begin FBlobData := nil; GetMem(FBlobData, Length); Move(FBlobData^, Buffer^, Length); end else begin FBlobSize := -1; FBlobData := nil; end; FUpdated := True; end; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcResultSetMetadata.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Abstract Database Connectivity Classes } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcResultSetMetadata; interface {$I ZDbc.inc} uses Classes, SysUtils, Contnrs, ZDbcIntfs, ZClasses, ZCollections, ZGenericSqlAnalyser, {$IFDEF FPC} {$IFDEF WIN32} Comobj, {$ENDIF} {$ENDIF} ZTokenizer, ZSelectSchema, ZCompatibility, ZDbcResultSet; type {** Implements a column information structure. } TZColumnInfo = class(TObject) protected FAutoIncrement: Boolean; FCaseSensitive: Boolean; FSearchable: Boolean; FCurrency: Boolean; FNullable: TZColumnNullableType; FSigned: Boolean; FColumnDisplaySize: Integer; FMaxLenghtBytes: Integer; FColumnLabel: string; FColumnName: string; FSchemaName: string; FPrecision: Integer; FScale: Integer; FTableName: string; FCatalogName: string; FColumnType: TZSQLType; FInternalColumnType: TZSQLType; FReadOnly: Boolean; FWritable: Boolean; FDefinitelyWritable: Boolean; FDefaultValue: string; FDefaultExpression : string; public constructor Create; function GetColumnTypeName: string; property AutoIncrement: Boolean read FAutoIncrement write FAutoIncrement; property CaseSensitive: Boolean read FCaseSensitive write FCaseSensitive; property Searchable: Boolean read FSearchable write FSearchable; property Currency: Boolean read FCurrency write FCurrency; property Nullable: TZColumnNullableType read FNullable write FNullable; property Signed: Boolean read FSigned write FSigned; property ColumnDisplaySize: Integer read FColumnDisplaySize write FColumnDisplaySize; property MaxLenghtBytes: Integer read FMaxLenghtBytes write FMaxLenghtBytes; property ColumnLabel: string read FColumnLabel write FColumnLabel; property ColumnName: string read FColumnName write FColumnName; property SchemaName: string read FSchemaName write FSchemaName; property Precision: Integer read FPrecision write FPrecision; property Scale: Integer read FScale write FScale; property TableName: string read FTableName write FTableName; property CatalogName: string read FCatalogName write FCatalogName; property ColumnType: TZSQLType read FColumnType write FColumnType; property InternalColumnType: TZSQLType read FInternalColumnType write FInternalColumnType; property ReadOnly: Boolean read FReadOnly write FReadOnly; property Writable: Boolean read FWritable write FWritable; property DefinitelyWritable: Boolean read FDefinitelyWritable write FDefinitelyWritable; property DefaultValue: string read FDefaultValue write FDefaultValue; property DefaultExpression: string read FDefaultExpression write FDefaultExpression; end; {** Implements Abstract ResultSet Metadata. } TZAbstractResultSetMetadata = class(TContainedObject, IZResultSetMetaData) private FLoaded: Boolean; FMetadata: IZDatabaseMetadata; FColumnsLabels: TStrings; FSQL: string; FTableColumns: TZHashMap; FIdentifierConvertor: IZIdentifierConvertor; FResultSet: TZAbstractResultSet; procedure SetMetadata(const Value: IZDatabaseMetadata); protected procedure LoadColumn(ColumnIndex: Integer; ColumnInfo: TZColumnInfo; SelectSchema: IZSelectSchema); virtual; function GetTableColumns(TableRef: TZTableRef): IZResultSet; function ReadColumnByRef(FieldRef: TZFieldRef; ColumnInfo: TZColumnInfo): Boolean; function ReadColumnByName(FieldName: string; TableRef: TZTableRef; ColumnInfo: TZColumnInfo): Boolean; procedure ClearColumn(ColumnInfo: TZColumnInfo); procedure LoadColumns; procedure ReplaceStarColumns(SelectSchema: IZSelectSchema); property MetaData: IZDatabaseMetadata read FMetadata write SetMetadata; property ColumnsLabels: TStrings read FColumnsLabels write FColumnsLabels; property SQL: string read FSQL write FSQL; property IdentifierConvertor: IZIdentifierConvertor read FIdentifierConvertor write FIdentifierConvertor; property Loaded: Boolean read FLoaded write FLoaded; property ResultSet: TZAbstractResultSet read FResultSet write FResultSet; public constructor Create(Metadata: IZDatabaseMetadata; SQL: string; ParentResultSet: TZAbstractResultSet); destructor Destroy; override; function GetColumnCount: Integer; virtual; function IsAutoIncrement(Column: Integer): Boolean; virtual; function IsCaseSensitive(Column: Integer): Boolean; virtual; function IsSearchable(Column: Integer): Boolean; virtual; function IsCurrency(Column: Integer): Boolean; virtual; function IsNullable(Column: Integer): TZColumnNullableType; virtual; function IsSigned(Column: Integer): Boolean; virtual; function GetColumnDisplaySize(Column: Integer): Integer; virtual; function GetColumnLabel(Column: Integer): string; virtual; function GetColumnName(Column: Integer): string; virtual; function GetSchemaName(Column: Integer): string; virtual; function GetPrecision(Column: Integer): Integer; virtual; function GetScale(Column: Integer): Integer; virtual; function GetTableName(Column: Integer): string; virtual; function GetCatalogName(Column: Integer): string; virtual; function GetColumnType(Column: Integer): TZSQLType; virtual; function GetColumnTypeName(Column: Integer): string; virtual; function IsReadOnly(Column: Integer): Boolean; virtual; function IsWritable(Column: Integer): Boolean; virtual; function IsDefinitelyWritable(Column: Integer): Boolean; virtual; function GetDefaultValue(Column: Integer): string; virtual; function HasDefaultValue(Column: Integer): Boolean; virtual; end; implementation uses ZVariant, ZDbcUtils, ZDbcMetadata; { TZColumnInfo } {** Constructs this object and assigns main properties. } constructor TZColumnInfo.Create; begin FAutoIncrement := False; FCaseSensitive := False; FSearchable := False; FCurrency := False; FNullable := ntNullableUnknown; FSigned := False; FColumnDisplaySize := 0; FColumnLabel := ''; FColumnName := ''; FSchemaName := ''; FPrecision := 0; FScale := 0; FTableName := ''; FCatalogName := ''; FDefaultValue := ''; FColumnType := stUnknown; FInternalColumnType := stUnknown; FReadOnly := True; FWritable := False; FDefinitelyWritable := False; end; {** Retrieves the designated column's database-specific type name. @return type name used by the database. If the column type is a user-defined type, then a fully-qualified type name is returned. } function TZColumnInfo.GetColumnTypeName: string; begin Result := DefineColumnTypeName(FColumnType); end; { TZAbstractResultSetMetadata } {** Constructs this object and assignes the main properties. @param Metadata a database metadata object. @param SQL an SQL query statement. @param ColumnsInfo a collection of columns info. } constructor TZAbstractResultSetMetadata.Create(Metadata: IZDatabaseMetadata; SQL: string; ParentResultSet: TZAbstractResultSet); begin inherited Create(ParentResultSet); SetMetadata(Metadata); FSQL := SQL; FLoaded := not (FMetadata <> nil); FTableColumns := TZHashMap.Create; FResultSet := ParentResultSet; end; {** Destroys this object and cleanups the memory. } destructor TZAbstractResultSetMetadata.Destroy; begin FIdentifierConvertor := nil; FMetadata := nil; if Assigned(FTableColumns) then begin FTableColumns.Clear; FTableColumns.Free; end; FTableColumns := nil; if FColumnsLabels <> nil then FColumnsLabels.Free; inherited Destroy; end; {** Returns the number of columns in this ResultSet object. @return the number of columns } function TZAbstractResultSetMetadata.GetColumnCount: Integer; begin Result := FResultSet.ColumnsInfo.Count; end; {** Indicates whether the designated column is automatically numbered, thus read-only. @param column the first column is 1, the second is 2, ... @return true if so; false otherwise } function TZAbstractResultSetMetadata.IsAutoIncrement(Column: Integer): Boolean; begin if not Loaded then LoadColumns; Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).AutoIncrement; end; {** Indicates whether a column's case matters. @param column the first column is 1, the second is 2, ... @return true if so; false otherwise } function TZAbstractResultSetMetadata.IsCaseSensitive(Column: Integer): Boolean; begin if not Loaded then LoadColumns; Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).CaseSensitive; end; {** Indicates whether the designated column can be used in a where clause. @param column the first column is 1, the second is 2, ... @return true if so; false otherwise } function TZAbstractResultSetMetadata.IsSearchable(Column: Integer): Boolean; begin if not Loaded then LoadColumns; Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).Searchable; end; {** Indicates whether the designated column is a cash value. @param column the first column is 1, the second is 2, ... @return true if so; false otherwise } function TZAbstractResultSetMetadata.IsCurrency(Column: Integer): Boolean; begin Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).Currency; end; {** Indicates the nullability of values in the designated column. @param column the first column is 1, the second is 2, ... @return the nullability status of the given column; one of columnNoNulls, columnNullable or columnNullableUnknown } function TZAbstractResultSetMetadata.IsNullable( Column: Integer): TZColumnNullableType; begin if not Loaded then LoadColumns; Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).Nullable; end; {** Indicates whether values in the designated column are signed numbers. @param column the first column is 1, the second is 2, ... @return true if so; false otherwise } function TZAbstractResultSetMetadata.IsSigned(Column: Integer): Boolean; begin Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).Signed; end; {** Indicates the designated column's normal maximum width in characters. @param column the first column is 1, the second is 2, ... @return the normal maximum number of characters allowed as the width of the designated column } function TZAbstractResultSetMetadata.GetColumnDisplaySize( Column: Integer): Integer; begin Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).ColumnDisplaySize; end; {** Gets the designated column's suggested title for use in printouts and displays. @param column the first column is 1, the second is 2, ... @return the suggested column title } function TZAbstractResultSetMetadata.GetColumnLabel(Column: Integer): string; var I, J, N: Integer; ColumnName: string; ColumnsInfo: TObjectList; begin { Prepare unique column labels. } if FColumnsLabels = nil then begin ColumnsInfo := FResultSet.ColumnsInfo; FColumnsLabels := TStringList.Create; for I := 0 to ColumnsInfo.Count - 1 do begin N := 0; ColumnName := TZColumnInfo(ColumnsInfo[I]).ColumnLabel; for J := 0 to I - 1 do begin if TZColumnInfo(ColumnsInfo[J]).ColumnLabel = ColumnName then Inc(N); end; if ColumnName = '' then ColumnName := 'Column'; if N > 0 then ColumnName := ColumnName + '_' + IntToStr(N); FColumnsLabels.Add(ColumnName); end; end; Result := ColumnsLabels[Column - 1]; end; {** Get the designated column's name. @param column the first column is 1, the second is 2, ... @return column name } function TZAbstractResultSetMetadata.GetColumnName( Column: Integer): string; begin if not Loaded then LoadColumns; Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).ColumnName; end; {** Get the designated column's table's schema. @param column the first column is 1, the second is 2, ... @return schema name or "" if not applicable } function TZAbstractResultSetMetadata.GetSchemaName( Column: Integer): string; begin if not Loaded then LoadColumns; Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).SchemaName; end; {** Get the designated column's number of decimal digits. @param column the first column is 1, the second is 2, ... @return precision } function TZAbstractResultSetMetadata.GetPrecision(Column: Integer): Integer; begin Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).Precision; end; {** Gets the designated column's number of digits to right of the decimal point. @param column the first column is 1, the second is 2, ... @return scale } function TZAbstractResultSetMetadata.GetScale(Column: Integer): Integer; begin Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).Scale; end; {** Gets the designated column's table name. @param column the first column is 1, the second is 2, ... @return table name or "" if not applicable } function TZAbstractResultSetMetadata.GetTableName(Column: Integer): string; begin if not Loaded then LoadColumns; Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).TableName; end; {** Gets the designated column's table's catalog name. @param column the first column is 1, the second is 2, ... @return column name or "" if not applicable } function TZAbstractResultSetMetadata.GetCatalogName(Column: Integer): string; begin if not Loaded then LoadColumns; Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).CatalogName; end; {** Retrieves the designated column's SQL type. @param column the first column is 1, the second is 2, ... @return SQL type from java.sql.Types } function TZAbstractResultSetMetadata.GetColumnType(Column: Integer): TZSQLType; begin Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).ColumnType; end; {** Retrieves the designated column's database-specific type name. @param column the first column is 1, the second is 2, ... @return type name used by the database. If the column type is a user-defined type, then a fully-qualified type name is returned. } function TZAbstractResultSetMetadata.GetColumnTypeName(Column: Integer): string; begin Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).GetColumnTypeName; end; {** Indicates whether the designated column is definitely not writable. @param column the first column is 1, the second is 2, ... @return true if so; false otherwise } function TZAbstractResultSetMetadata.IsReadOnly(Column: Integer): Boolean; begin if not Loaded then LoadColumns; Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).ReadOnly; end; {** Indicates whether it is possible for a write on the designated column to succeed. @param column the first column is 1, the second is 2, ... @return true if so; false otherwise } function TZAbstractResultSetMetadata.IsWritable(Column: Integer): Boolean; begin if not Loaded then LoadColumns; Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).Writable; end; {** Indicates whether a write on the designated column will definitely succeed. @param column the first column is 1, the second is 2, ... @return true if so; false otherwise } function TZAbstractResultSetMetadata.IsDefinitelyWritable( Column: Integer): Boolean; begin if not Loaded then LoadColumns; Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).DefinitelyWritable; end; {** Gets a default value for this field. @param column the first column is 1, the second is 2, ... @return a default value for this field. } function TZAbstractResultSetMetadata.GetDefaultValue( Column: Integer): string; begin if not Loaded then LoadColumns; Result := TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).DefaultValue; end; {** Finds whether this field has a default value. @param column the first column is 1, the second is 2, ... @return true if this field has a default value. } function TZAbstractResultSetMetadata.HasDefaultValue( Column: Integer): Boolean; begin if not Loaded then LoadColumns; // '' = NULL / no default value, '''''' = empty string (''), etc. Result := not(TZColumnInfo(FResultSet.ColumnsInfo[Column - 1]).DefaultValue = ''); end; {** Gets a table description result set. @param TableRef a table reference object. @return a result set with table columns from database metadata. } function TZAbstractResultSetMetadata.GetTableColumns( TableRef: TZTableRef): IZResultSet; var TableKey: IZAnyValue; begin TableKey := TZAnyValue.CreateWithString(TableRef.FullName); if FTableColumns.Get(TableKey) = nil then begin Result := Metadata.GetColumns(TableRef.Catalog, TableRef.Schema, TableRef.Table, ''); FTableColumns.Put(TableKey, Result); end else Result := FTableColumns.Get(TableKey) as IZResultSet; end; {** Clears specified column information. @param ColumnInfo a column information object. } procedure TZAbstractResultSetMetadata.ClearColumn(ColumnInfo: TZColumnInfo); begin ColumnInfo.ReadOnly := True; ColumnInfo.Writable := False; ColumnInfo.DefinitelyWritable := False; ColumnInfo.CatalogName := ''; ColumnInfo.SchemaName := ''; ColumnInfo.TableName := ''; ColumnInfo.ColumnName := ''; end; {** Reads a column information from table metadata. @param FieldName a name of the field. @param TableRef a table reference object. @param ColumnInfo a column information object. @return True is column was found and read. } function TZAbstractResultSetMetadata.ReadColumnByName(FieldName: string; TableRef: TZTableRef; ColumnInfo: TZColumnInfo): Boolean; var TableColumns: IZResultSet; tempColType: TZSQLType; begin Result := False; TableColumns := GetTableColumns(TableRef); { Checks for unexisted table. } if not Assigned(TableColumns) then Exit; { Locates a column row. } TableColumns.BeforeFirst; while TableColumns.Next do if TableColumns.GetString(4) = FieldName then Break; if TableColumns.IsAfterLast then begin { Locates a column row with case insensitivity. } TableColumns.BeforeFirst; while TableColumns.Next do if AnsiUpperCase(TableColumns.GetString(4)) = AnsiUpperCase(FieldName) then Break; if TableColumns.IsAfterLast then Exit; end; { Reads a column information. } Result := True; ColumnInfo.CatalogName := TableColumns.GetString(1); ColumnInfo.SchemaName := TableColumns.GetString(2); ColumnInfo.TableName := TableColumns.GetString(3); ColumnInfo.ColumnName := FieldName; //If the returned column information is null then the value assigned during //the resultset.open will be kept if not TableColumns.IsNull(5) then begin //since Pointer referencing by RowAccessor we've a pointer and GetBlob //raises an exception if the pointer is a reference to PPAnsiChar or //ZPPWideChar. if we execute a cast of a lob field the database meta-informtions //assume a IZLob-Pointer. So let's prevent this case and check for //stByte, stString, stUnicoeString first. If this type is returned from the //ResultSet-Metadata we do NOT overwrite the column-type //f.e. select cast( name as varchar(100)), cast(setting as varchar(100)) from pg_settings //or the same vice versa: //(CASE WHEN (Ticket51_B."Name" IS NOT NULL) THEN Ticket51_B."Name" ELSE 'Empty' END) As "Name" //we've NO fixed length for a case(postgres and FB2.5up f.e.) select tempColType := TZSQLType(TableColumns.GetShort(5)); if not (TZSQLType(TableColumns.GetShort(5)) in [stBinaryStream, stAsciiStream, stUnicodeStream, stBytes, stString, stUnicodeString]) then ColumnInfo.ColumnType := tempColType; end; if not TableColumns.IsNull(11) then ColumnInfo.Nullable := TZColumnNullableType(TableColumns.GetInt(11)); if not TableColumns.IsNull(19) then ColumnInfo.AutoIncrement := TableColumns.GetBoolean(19); if not TableColumns.IsNull(20) then ColumnInfo.CaseSensitive := TableColumns.GetBoolean(20); if not TableColumns.IsNull(21) then ColumnInfo.Searchable := TableColumns.GetBoolean(21); if not TableColumns.IsNull(22) then if ColumnInfo.AutoIncrement and Assigned(FMetadata) then {improve ADO where the metainformations do not bring autoincremental fields through} if FMetadata.GetDatabaseInfo.SupportsUpdateAutoIncrementFields then ColumnInfo.Writable := TableColumns.GetBoolean(22) else ColumnInfo.Writable := False else ColumnInfo.Writable := TableColumns.GetBoolean(22); if not TableColumns.IsNull(23) then if ColumnInfo.AutoIncrement and Assigned(FMetadata) then {improve ADO where the metainformations do not bring autoincremental fields through} if FMetadata.GetDatabaseInfo.SupportsUpdateAutoIncrementFields then ColumnInfo.DefinitelyWritable := TableColumns.GetBoolean(23) else ColumnInfo.DefinitelyWritable := False else ColumnInfo.DefinitelyWritable := TableColumns.GetBoolean(23); if not TableColumns.IsNull(24) then if ColumnInfo.AutoIncrement and Assigned(FMetadata) then {improve ADO where the metainformations do not bring autoincremental fields through} if FMetadata.GetDatabaseInfo.SupportsUpdateAutoIncrementFields then ColumnInfo.ReadOnly := TableColumns.GetBoolean(24) else ColumnInfo.ReadOnly := True else ColumnInfo.ReadOnly := TableColumns.GetBoolean(24); if not TableColumns.IsNull(13) then ColumnInfo.DefaultValue := TableColumns.GetString(13); end; {** Reads a column information from table metadata. @param FieldRef a field reference object. @param ColumnInfo a column information object. @return True if column was found and read. } function TZAbstractResultSetMetadata.ReadColumnByRef( FieldRef: TZFieldRef; ColumnInfo: TZColumnInfo): Boolean; begin Result := False; ClearColumn(ColumnInfo); { Checks for uncompleted field reference. } if not Assigned(FieldRef) or not Assigned(FieldRef.TableRef) then Exit; if not FieldRef.IsField then Exit; Result := ReadColumnByName(FieldRef.Field, FieldRef.TableRef, ColumnInfo); end; {** Initializes on single column of the result set. @param ColumnIndex a column index in the query. @param ColumnInfo a column information object to be initialized. @param SelectSchema a schema of the select statement. } procedure TZAbstractResultSetMetadata.LoadColumn(ColumnIndex: Integer; ColumnInfo: TZColumnInfo; SelectSchema: IZSelectSchema); var I: Integer; FieldRef: TZFieldRef; TableRef: TZTableRef; Found: Boolean; begin { Initializes single columns with specified table. } FieldRef := SelectSchema.LinkFieldByIndexAndShortName(ColumnIndex, ColumnInfo.ColumnLabel, IdentifierConvertor); ReadColumnByRef(FieldRef, ColumnInfo); if ColumnInfo.ColumnName <> '' then Exit; { Initializes single columns without specified table. } I := 0; Found := False; while (ColumnInfo.ColumnName = '') and (I < SelectSchema.TableCount) and not Found do begin TableRef := SelectSchema.Tables[I]; if Assigned(FieldRef) then Found := ReadColumnByName(IdentifierConvertor.ExtractQuote(FieldRef.Field), TableRef, ColumnInfo) else Found := ReadColumnByName(IdentifierConvertor.ExtractQuote(ColumnInfo.ColumnLabel), TableRef, ColumnInfo); Inc(I); end; end; {** Replaces '*' columns in the select schema. @param SelectSchema a query select schema. } procedure TZAbstractResultSetMetadata.ReplaceStarColumns( SelectSchema: IZSelectSchema); var I: Integer; Current: TZFieldRef; FieldRef: TZFieldRef; TableRef: TZTableRef; ResultSet: IZResultSet; begin I := 0; while I < SelectSchema.FieldCount do begin Current := SelectSchema.Fields[I]; if (Current.Field = '*') and (Current.TableRef <> nil) then begin TableRef := Current.TableRef; ResultSet := Self.GetTableColumns(TableRef); if ResultSet <> nil then begin ResultSet.BeforeFirst; while ResultSet.Next do begin FieldRef := TZFieldRef.Create(True, TableRef.Catalog, TableRef.Schema, TableRef.Table, ResultSet.GetString(4), '', TableRef); SelectSchema.InsertField(I, FieldRef); Inc(I); end; end; SelectSchema.DeleteField(Current); Dec(I); end; Inc(I); end; end; procedure TZAbstractResultSetMetadata.SetMetadata( const Value: IZDatabaseMetadata); begin FMetadata := Value; if Value<>nil then FIdentifierConvertor := Value.GetIdentifierConvertor else FIdentifierConvertor := TZDefaultIdentifierConvertor.Create(FMetadata); end; {** Initializes columns with additional data. } procedure TZAbstractResultSetMetadata.LoadColumns; var I: Integer; Driver: IZDriver; Tokenizer: IZTokenizer; StatementAnalyser: IZStatementAnalyser; SelectSchema: IZSelectSchema; FillByIndices: Boolean; begin { Parses the Select statement and retrieves a schema object. } Driver := Metadata.GetConnection.GetDriver; Tokenizer := Driver.GetTokenizer; StatementAnalyser := Driver.GetStatementAnalyser; SelectSchema := StatementAnalyser.DefineSelectSchemaFromQuery(Tokenizer, SQL); if Assigned(SelectSchema) then begin SelectSchema.LinkReferences(IdentifierConvertor); ReplaceStarColumns(SelectSchema); FillByIndices := SelectSchema.FieldCount = FResultSet.ColumnsInfo.Count; for I := 0 to FResultSet.ColumnsInfo.Count - 1 do begin if FillByIndices then LoadColumn(I + 1, TZColumnInfo(FResultSet.ColumnsInfo[I]), SelectSchema) else LoadColumn(-1, TZColumnInfo(FResultSet.ColumnsInfo[I]), SelectSchema); end; end; Loaded := True; end; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcSqLite.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { SQLite Database Connectivity Classes } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcSqLite; interface {$I ZDbc.inc} uses Types, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, ZDbcIntfs, ZDbcConnection, ZPlainSqLiteDriver, ZDbcLogging, ZTokenizer, ZGenericSqlAnalyser, ZURL, ZPlainDriver, ZCompatibility; type {** Implements SQLite Database Driver. } {$WARNINGS OFF} TZSQLiteDriver = class(TZAbstractDriver) public constructor Create; override; function Connect(const Url: TZURL): IZConnection; override; function GetMajorVersion: Integer; override; function GetMinorVersion: Integer; override; function GetTokenizer: IZTokenizer; override; function GetStatementAnalyser: IZStatementAnalyser; override; end; {$WARNINGS ON} {** Represents a SQLite specific connection interface. } IZSQLiteConnection = interface (IZConnection) ['{A4B797A9-7CF7-4DE9-A5BB-693DD32D07D2}'] function UseOldBlobEncoding: Boolean; function GetPlainDriver: IZSQLitePlainDriver; function GetConnectionHandle: Psqlite; end; {** Implements SQLite Database Connection. } { TZSQLiteConnection } TZSQLiteConnection = class(TZAbstractConnection, IZSQLiteConnection) private FCatalog: string; FHandle: Psqlite; function UseOldBlobEncoding: Boolean; protected procedure InternalCreate; override; procedure StartTransactionSupport; public destructor Destroy; override; function CreateRegularStatement(Info: TStrings): IZStatement; override; function CreatePreparedStatement(const SQL: string; Info: TStrings): IZPreparedStatement; override; procedure Commit; override; procedure Rollback; override; procedure Open; override; procedure Close; override; procedure SetCatalog(const Catalog: string); override; function GetCatalog: string; override; procedure SetTransactionIsolation(Level: TZTransactIsolationLevel); override; function GetClientVersion: Integer; override; function GetHostVersion: Integer; override; function GetPlainDriver: IZSQLitePlainDriver; function GetConnectionHandle: Psqlite; function ReKey(const Key: string): Integer; function Key(const Key: string): Integer; function GetBinaryEscapeString(const Value: RawByteString): String; overload; override; function GetBinaryEscapeString(const Value: TByteDynArray): String; overload; override; {$IFDEF ZEOS_TEST_ONLY} constructor Create(const ZUrl: TZURL); {$ENDIF} end; var {** The common driver manager object. } SQLiteDriver: IZDriver; implementation uses ZSysUtils, ZDbcUtils, ZDbcSqLiteStatement, ZSqLiteToken, ZDbcSqLiteUtils, ZDbcSqLiteMetadata, ZSqLiteAnalyser {$IFDEF WITH_UNITANSISTRINGS}, AnsiStrings{$ENDIF}; { TZSQLiteDriver } {** Constructs this object with default properties. } constructor TZSQLiteDriver.Create; begin inherited Create; AddSupportedProtocol(AddPlainDriverToCache(TZSQLite3PlainDriver.Create, 'sqlite')); AddSupportedProtocol(AddPlainDriverToCache(TZSQLite3PlainDriver.Create)); end; {** Attempts to make a database connection to the given URL. The driver should return "null" if it realizes it is the wrong kind of driver to connect to the given URL. This will be common, as when the JDBC driver manager is asked to connect to a given URL it passes the URL to each loaded driver in turn.

The driver should raise a SQLException if it is the right driver to connect to the given URL, but has trouble connecting to the database.

The java.util.Properties argument can be used to passed arbitrary string tag/value pairs as connection arguments. Normally at least "user" and "password" properties should be included in the Properties. @param url the URL of the database to which to connect @param info a list of arbitrary string tag/value pairs as connection arguments. Normally at least a "user" and "password" property should be included. @return a Connection object that represents a connection to the URL } {$WARNINGS OFF} function TZSQLiteDriver.Connect(const Url: TZURL): IZConnection; begin Result := TZSQLiteConnection.Create(Url); end; {$WARNINGS ON} {** Gets the driver's major version number. Initially this should be 1. @return this driver's major version number } function TZSQLiteDriver.GetMajorVersion: Integer; begin Result := 1; end; {** Gets the driver's minor version number. Initially this should be 0. @return this driver's minor version number } function TZSQLiteDriver.GetMinorVersion: Integer; begin Result := 0; end; {** Gets a SQL syntax tokenizer. @returns a SQL syntax tokenizer object. } function TZSQLiteDriver.GetTokenizer: IZTokenizer; begin if Tokenizer = nil then Tokenizer := TZSQLiteTokenizer.Create; Result := Tokenizer; end; {** Creates a statement analyser object. @returns a statement analyser object. } function TZSQLiteDriver.GetStatementAnalyser: IZStatementAnalyser; begin if Analyser = nil then Analyser := TZSQLiteStatementAnalyser.Create; Result := Analyser; end; { TZSQLiteConnection } {** Constructs this object and assignes the main properties. } procedure TZSQLiteConnection.InternalCreate; begin FMetadata := TZSQLiteDatabaseMetadata.Create(Self, Url); AutoCommit := True; TransactIsolationLevel := tiNone; CheckCharEncoding('UTF-8'); Open; end; {** Destroys this object and cleanups the memory. } destructor TZSQLiteConnection.Destroy; begin inherited Destroy; end; function TZSQLiteConnection.UseOldBlobEncoding: Boolean; begin Result := Url.Properties.Values['OldBlobEncoding'] = 'True'; end; {** Set encryption key for a database @param Key the key used to encrypt your database. @return error code from SQLite Key function. } function TZSQLiteConnection.Key(const Key: string):Integer; var ErrorCode: Integer; begin {$IFDEF UNICODE} ErrorCode := GetPlainDriver.Key(FHandle, PAnsiChar(UTF8String(Key)), {$IFDEF WITH_STRLEN_DEPRECATED}AnsiStrings.{$ENDIF}StrLen(PAnsiChar(UTF8String(Key)))); {$ELSE} ErrorCode := GetPlainDriver.Key(FHandle, PAnsiChar(Key), StrLen(PAnsiChar(Key))); {$ENDIF} Result := ErrorCode; end; {** Reencrypt a database with a new key. The old/current key needs to be set before calling this function. @param Key the new key used to encrypt your database. @return error code from SQLite ReKey function. } function TZSQLiteConnection.ReKey(const Key: string):Integer; var ErrorCode: Integer; begin {$IFDEF UNICODE} ErrorCode := GetPlainDriver.ReKey(FHandle, PAnsiChar(UTF8String(Key)), {$IFDEF WITH_STRLEN_DEPRECATED}AnsiStrings.{$ENDIF}StrLen(PAnsiChar(UTF8String(Key)))); {$ELSE} ErrorCode := GetPlainDriver.ReKey(FHandle, PAnsiChar(Key), StrLen(PAnsiChar(Key))); {$ENDIF} Result := ErrorCode; end; {** Opens a connection to database server with specified parameters. } procedure TZSQLiteConnection.Open; var ErrorCode: Integer; ErrorMessage: PAnsiChar; LogMessage: string; SQL: AnsiString; Timeout_ms: Integer; begin if not Closed then Exit; ErrorMessage := ''; LogMessage := Format('CONNECT TO "%s" AS USER "%s"', [Database, User]); {$IFDEF UNICODE} FHandle := GetPlainDriver.Open(PAnsiChar(AnsiString(UTF8Encode(Database))), 0, ErrorMessage); {$ELSE} FHandle := GetPlainDriver.Open(PAnsiChar(Database), 0, ErrorMessage); {$ENDIF} if FHandle = nil then begin CheckSQLiteError(GetPlainDriver, FHandle, SQLITE_ERROR, ErrorMessage, lcConnect, LogMessage); end; DriverManager.LogMessage(lcConnect, PlainDriver.GetProtocol, LogMessage); { Turn on encryption if requested } if StrToBoolEx(Info.Values['encrypted']) then begin {$IFDEF UNICODE} ErrorCode := GetPlainDriver.Key(FHandle, PAnsiChar(UTF8String(Password)), {$IFDEF WITH_STRLEN_DEPRECATED}AnsiStrings.{$ENDIF}StrLen(PAnsiChar(UTF8String(Password)))); {$ELSE} ErrorCode := GetPlainDriver.Key(FHandle, PAnsiChar(Password), StrLen(PAnsiChar(Password))); {$ENDIF} CheckSQLiteError(GetPlainDriver, FHandle, ErrorCode, nil, lcConnect, 'SQLite.Key'); end; { Set busy timeout if requested } Timeout_ms := StrToIntDef(Info.Values['busytimeout'], -1); if Timeout_ms >= 0 then begin GetPlainDriver.BusyTimeout(FHandle, Timeout_ms); end; try if ( FClientCodePage <> '' ) then begin SQL := 'PRAGMA encoding = '''+AnsiString(FClientCodePage)+''''; ErrorCode := GetPlainDriver.Execute(FHandle, PAnsiChar(SQL), nil, nil, ErrorMessage); CheckSQLiteError(GetPlainDriver, FHandle, ErrorCode, ErrorMessage, lcExecute, String(SQL)); end; SQL := 'PRAGMA show_datatypes = ON'; ErrorCode := GetPlainDriver.Execute(FHandle, PAnsiChar(SQL), nil, nil, ErrorMessage); CheckSQLiteError(GetPlainDriver, FHandle, ErrorCode, ErrorMessage, lcExecute, String(SQL)); if Info.Values['foreign_keys'] <> '' then begin if StrToBoolEx(Info.Values['foreign_keys']) then SQL := 'PRAGMA foreign_keys = 1' else SQL := 'PRAGMA foreign_keys = 0'; ErrorCode := GetPlainDriver.Execute(FHandle, PAnsiChar(SQL), nil, nil, ErrorMessage); CheckSQLiteError(GetPlainDriver, FHandle, ErrorCode, ErrorMessage, lcExecute, String(SQL)); DriverManager.LogMessage(lcConnect, GetPlainDriver.GetProtocol, String(SQL)); end; StartTransactionSupport; except GetPlainDriver.Close(FHandle); FHandle := nil; raise; end; inherited Open; end; {** Creates a Statement object for sending SQL statements to the database. SQL statements without parameters are normally executed using Statement objects. If the same SQL statement is executed many times, it is more efficient to use a PreparedStatement object.

Result sets created using the returned Statement object will by default have forward-only type and read-only concurrency. @param Info a statement parameters. @return a new Statement object } function TZSQLiteConnection.CreateRegularStatement(Info: TStrings): IZStatement; begin if IsClosed then Open; Result := TZSQLiteStatement.Create(GetPlainDriver, Self, Info, FHandle); end; {** Creates a PreparedStatement object for sending parameterized SQL statements to the database. A SQL statement with or without IN parameters can be pre-compiled and stored in a PreparedStatement object. This object can then be used to efficiently execute this statement multiple times.

Note: This method is optimized for handling parametric SQL statements that benefit from precompilation. If the driver supports precompilation, the method prepareStatement will send the statement to the database for precompilation. Some drivers may not support precompilation. In this case, the statement may not be sent to the database until the PreparedStatement is executed. This has no direct effect on users; however, it does affect which method throws certain SQLExceptions. Result sets created using the returned PreparedStatement will have forward-only type and read-only concurrency, by default. @param sql a SQL statement that may contain one or more '?' IN parameter placeholders @param Info a statement parameters. @return a new PreparedStatement object containing the pre-compiled statement } function TZSQLiteConnection.CreatePreparedStatement(const SQL: string; Info: TStrings): IZPreparedStatement; begin if IsClosed then Open; {$IFDEF ZEOS_TEST_ONLY} Case GetTestMode of 0: {$ENDIF} Result := TZSQLiteCAPIPreparedStatement.Create(GetPlainDriver, Self, SQL, Info, FHandle); {$IFDEF ZEOS_TEST_ONLY} 1: Result := TZSQLitePreparedStatement.Create(GetPlainDriver, Self, SQL, Info, FHandle); end; {$ENDIF} end; {** Starts a transaction support. } procedure TZSQLiteConnection.StartTransactionSupport; var ErrorCode: Integer; ErrorMessage: PAnsiChar; SQL: String; begin if TransactIsolationLevel <> tiNone then begin ErrorMessage := ''; SQL := 'BEGIN TRANSACTION'; ErrorCode := GetPlainDriver.Execute(FHandle, PAnsiChar(AnsiString(SQL)), nil, nil, ErrorMessage); CheckSQLiteError(GetPlainDriver, FHandle, ErrorCode, ErrorMessage, lcExecute, SQL); DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, SQL); end; end; {** Makes all changes made since the previous commit/rollback permanent and releases any database locks currently held by the Connection. This method should be used only when auto-commit mode has been disabled. @see #setAutoCommit } procedure TZSQLiteConnection.Commit; var ErrorCode: Integer; ErrorMessage: PAnsiChar; SQL: PAnsiChar; begin if (TransactIsolationLevel <> tiNone) and not Closed then begin ErrorMessage := ''; SQL := 'COMMIT TRANSACTION'; ErrorCode := GetPlainDriver.Execute(FHandle, PAnsiChar(SQL), nil, nil, ErrorMessage); CheckSQLiteError(GetPlainDriver, FHandle, ErrorCode, ErrorMessage, lcExecute, String(SQL)); DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, String(SQL)); StartTransactionSupport; end; end; {** Drops all changes made since the previous commit/rollback and releases any database locks currently held by this Connection. This method should be used only when auto- commit has been disabled. @see #setAutoCommit } procedure TZSQLiteConnection.Rollback; var ErrorCode: Integer; ErrorMessage: PAnsiChar; SQL: String; begin if (TransactIsolationLevel <> tiNone) and not Closed then begin ErrorMessage := ''; SQL := 'ROLLBACK TRANSACTION'; ErrorCode := GetPlainDriver.Execute(FHandle, PAnsiChar(AnsiString(SQL)), nil, nil, ErrorMessage); CheckSQLiteError(GetPlainDriver, FHandle, ErrorCode, ErrorMessage, lcExecute, SQL); DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, SQL); StartTransactionSupport; end; end; {** Releases a Connection's database and JDBC resources immediately instead of waiting for them to be automatically released.

Note: A Connection is automatically closed when it is garbage collected. Certain fatal errors also result in a closed Connection. } procedure TZSQLiteConnection.Close; var LogMessage: string; ErrorCode: Integer; begin if ( Closed ) or (not Assigned(PlainDriver)) then Exit; LogMessage := 'DISCONNECT FROM "'+Database+'"'; if Assigned(DriverManager) then DriverManager.LogMessage(lcDisconnect, PlainDriver.GetProtocol, LogMessage); ErrorCode := GetPlainDriver.Close(FHandle); CheckSQLiteError(GetPlainDriver, FHandle, ErrorCode, nil, lcOther, LogMessage); FHandle := nil; inherited Close; end; {** Gets a selected catalog name. @return a selected catalog name. } function TZSQLiteConnection.GetCatalog: string; begin Result := FCatalog; end; function TZSQLiteConnection.GetClientVersion: Integer; begin Result := ConvertSQLiteVersionToSQLVersion(GetPlainDriver.LibVersion); end; {** Sets a new selected catalog name. @param Catalog a selected catalog name. } procedure TZSQLiteConnection.SetCatalog(const Catalog: string); begin FCatalog := Catalog; end; {** Sets a new transact isolation level. @param Level a new transact isolation level. } procedure TZSQLiteConnection.SetTransactionIsolation( Level: TZTransactIsolationLevel); var ErrorCode: Integer; ErrorMessage: PAnsiChar; SQL: String; begin if (TransactIsolationLevel <> tiNone) and not Closed then begin ErrorMessage := ''; SQL := 'ROLLBACK TRANSACTION'; ErrorCode := GetPlainDriver.Execute(FHandle, PAnsiChar(AnsiString(SQL)), nil, nil, ErrorMessage); CheckSQLiteError(GetPlainDriver, FHandle, ErrorCode, ErrorMessage, lcExecute, SQL); DriverManager.LogMessage(lcExecute, PlainDriver.GetProtocol, SQL); end; inherited SetTransactionIsolation(Level); if not Closed then StartTransactionSupport; end; {** Gets a reference to SQLite connection handle. @return a reference to SQLite connection handle. } function TZSQLiteConnection.GetConnectionHandle: Psqlite; begin Result := FHandle; end; {** Gets a SQLite plain driver interface. @return a SQLite plain driver interface. } function TZSQLiteConnection.GetPlainDriver: IZSQLitePlainDriver; begin Result := PlainDriver as IZSQLitePlainDriver; end; {** EgonHugeist: Returns the BinaryString in a Tokenizer-detectable kind If the Tokenizer don't need to predetect it Result := BinaryString @param Value represents the Binary-String @param EscapeMarkSequence represents a Tokenizer detectable EscapeSequence (Len >= 3) @result the detectable Binary String } function TZSQLiteConnection.GetBinaryEscapeString(const Value: RawByteString): String; begin if GetAutoEncodeStrings then Result := GetDriver.GetTokenizer.AnsiGetEscapeString(ZDbcSqLiteUtils.EncodeString(PAnsiChar(Value), Length(Value))) else Result := String(ZDbcSqLiteUtils.EncodeString(PAnsiChar(Value), Length(Value))); end; {** EgonHugeist: Returns the BinaryString in a Tokenizer-detectable kind If the Tokenizer don't need to predetect it Result := BinaryString @param Value represents the Binary-String @param EscapeMarkSequence represents a Tokenizer detectable EscapeSequence (Len >= 3) @result the detectable Binary String } function TZSQLiteConnection.GetBinaryEscapeString(const Value: TByteDynArray): String; begin if GetAutoEncodeStrings then Result := GetDriver.GetTokenizer.AnsiGetEscapeString(ZDbcSqLiteUtils.EncodeString(PAnsiChar(Value), Length(Value))) else Result := String(ZDbcSqLiteUtils.EncodeString(PAnsiChar(Value), Length(Value))); end; {$IFDEF ZEOS_TEST_ONLY} constructor TZSQLiteConnection.Create(const ZUrl: TZURL); begin inherited Create(ZUrl); end; {$ENDIF} function TZSQLiteConnection.GetHostVersion: Integer; begin Result := ConvertSQLiteVersionToSQLVersion(GetPlainDriver.LibVersion); end; initialization SQLiteDriver := TZSQLiteDriver.Create; DriverManager.RegisterDriver(SQLiteDriver); finalization if DriverManager <> nil then DriverManager.DeregisterDriver(SQLiteDriver); SQLiteDriver := nil; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcSqLiteMetadata.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { SQLite Database Connectivity Classes } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcSqLiteMetadata; interface {$I ZDbc.inc} uses Types, Classes, SysUtils, ZSysUtils, ZDbcIntfs, ZDbcMetadata, ZCompatibility, ZDbcSQLiteUtils, ZDbcConnection; type // technobot 2008-06-28 - methods moved as is from TZSQLiteDatabaseMetadata: {** Implements SQLite Database Information. } TZSQLiteDatabaseInfo = class(TZAbstractDatabaseInfo) // function UncachedGetUDTs(const Catalog: string; const SchemaPattern: string; // const TypeNamePattern: string; const Types: TIntegerDynArray): IZResultSet; override; public // database/driver/server info: function GetDatabaseProductName: string; override; function GetDatabaseProductVersion: string; override; function GetDriverName: string; override; // function GetDriverVersion: string; override; -> Same as parent function GetDriverMajorVersion: Integer; override; function GetDriverMinorVersion: Integer; override; // function GetServerVersion: string; -> Not implemented // capabilities (what it can/cannot do): // function AllProceduresAreCallable: Boolean; override; -> Not implemented // function AllTablesAreSelectable: Boolean; override; -> Not implemented function SupportsMixedCaseIdentifiers: Boolean; override; function SupportsMixedCaseQuotedIdentifiers: Boolean; override; // function SupportsAlterTableWithAddColumn: Boolean; override; -> Not implemented // function SupportsAlterTableWithDropColumn: Boolean; override; -> Not implemented // function SupportsColumnAliasing: Boolean; override; -> Not implemented // function SupportsConvert: Boolean; override; -> Not implemented // function SupportsConvertForTypes(FromType: TZSQLType; ToType: TZSQLType): // Boolean; override; -> Not implemented // function SupportsTableCorrelationNames: Boolean; override; -> Not implemented // function SupportsDifferentTableCorrelationNames: Boolean; override; -> Not implemented function SupportsExpressionsInOrderBy: Boolean; override; function SupportsOrderByUnrelated: Boolean; override; function SupportsGroupBy: Boolean; override; function SupportsGroupByUnrelated: Boolean; override; function SupportsGroupByBeyondSelect: Boolean; override; // function SupportsLikeEscapeClause: Boolean; override; -> Not implemented // function SupportsMultipleResultSets: Boolean; override; -> Not implemented // function SupportsMultipleTransactions: Boolean; override; -> Not implemented // function SupportsNonNullableColumns: Boolean; override; -> Not implemented // function SupportsMinimumSQLGrammar: Boolean; override; -> Not implemented // function SupportsCoreSQLGrammar: Boolean; override; -> Not implemented // function SupportsExtendedSQLGrammar: Boolean; override; -> Not implemented // function SupportsANSI92EntryLevelSQL: Boolean; override; -> Not implemented // function SupportsANSI92IntermediateSQL: Boolean; override; -> Not implemented // function SupportsANSI92FullSQL: Boolean; override; -> Not implemented function SupportsIntegrityEnhancementFacility: Boolean; override; // function SupportsOuterJoins: Boolean; override; -> Not implemented // function SupportsFullOuterJoins: Boolean; override; -> Not implemented // function SupportsLimitedOuterJoins: Boolean; override; -> Not implemented function SupportsSchemasInDataManipulation: Boolean; override; function SupportsSchemasInProcedureCalls: Boolean; override; function SupportsSchemasInTableDefinitions: Boolean; override; function SupportsSchemasInIndexDefinitions: Boolean; override; function SupportsSchemasInPrivilegeDefinitions: Boolean; override; function SupportsCatalogsInDataManipulation: Boolean; override; function SupportsCatalogsInProcedureCalls: Boolean; override; function SupportsCatalogsInTableDefinitions: Boolean; override; function SupportsCatalogsInIndexDefinitions: Boolean; override; function SupportsCatalogsInPrivilegeDefinitions: Boolean; override; function SupportsPositionedDelete: Boolean; override; function SupportsPositionedUpdate: Boolean; override; function SupportsSelectForUpdate: Boolean; override; function SupportsStoredProcedures: Boolean; override; function SupportsSubqueriesInComparisons: Boolean; override; function SupportsSubqueriesInExists: Boolean; override; function SupportsSubqueriesInIns: Boolean; override; function SupportsSubqueriesInQuantifieds: Boolean; override; function SupportsCorrelatedSubqueries: Boolean; override; function SupportsUnion: Boolean; override; function SupportsUnionAll: Boolean; override; function SupportsOpenCursorsAcrossCommit: Boolean; override; function SupportsOpenCursorsAcrossRollback: Boolean; override; function SupportsOpenStatementsAcrossCommit: Boolean; override; function SupportsOpenStatementsAcrossRollback: Boolean; override; function SupportsTransactions: Boolean; override; function SupportsTransactionIsolationLevel(Level: TZTransactIsolationLevel): Boolean; override; function SupportsDataDefinitionAndDataManipulationTransactions: Boolean; override; function SupportsDataManipulationTransactionsOnly: Boolean; override; function SupportsResultSetType(_Type: TZResultSetType): Boolean; override; function SupportsResultSetConcurrency(_Type: TZResultSetType; Concurrency: TZResultSetConcurrency): Boolean; override; // function SupportsBatchUpdates: Boolean; override; -> Not implemented // maxima: function GetMaxBinaryLiteralLength: Integer; override; function GetMaxCharLiteralLength: Integer; override; function GetMaxColumnNameLength: Integer; override; function GetMaxColumnsInGroupBy: Integer; override; function GetMaxColumnsInIndex: Integer; override; function GetMaxColumnsInOrderBy: Integer; override; function GetMaxColumnsInSelect: Integer; override; function GetMaxColumnsInTable: Integer; override; function GetMaxConnections: Integer; override; function GetMaxCursorNameLength: Integer; override; function GetMaxIndexLength: Integer; override; function GetMaxSchemaNameLength: Integer; override; function GetMaxProcedureNameLength: Integer; override; function GetMaxCatalogNameLength: Integer; override; function GetMaxRowSize: Integer; override; function GetMaxStatementLength: Integer; override; function GetMaxStatements: Integer; override; function GetMaxTableNameLength: Integer; override; function GetMaxTablesInSelect: Integer; override; function GetMaxUserNameLength: Integer; override; // policies (how are various data and operations handled): // function IsReadOnly: Boolean; override; -> Not implemented // function IsCatalogAtStart: Boolean; override; -> Not implemented function DoesMaxRowSizeIncludeBlobs: Boolean; override; // function NullsAreSortedHigh: Boolean; override; -> Not implemented // function NullsAreSortedLow: Boolean; override; -> Not implemented // function NullsAreSortedAtStart: Boolean; override; -> Not implemented // function NullsAreSortedAtEnd: Boolean; override; -> Not implemented // function NullPlusNonNullIsNull: Boolean; override; -> Not implemented // function UsesLocalFiles: Boolean; override; -> Not implemented function UsesLocalFilePerTable: Boolean; override; function StoresUpperCaseIdentifiers: Boolean; override; function StoresLowerCaseIdentifiers: Boolean; override; function StoresMixedCaseIdentifiers: Boolean; override; function StoresUpperCaseQuotedIdentifiers: Boolean; override; function StoresLowerCaseQuotedIdentifiers: Boolean; override; function StoresMixedCaseQuotedIdentifiers: Boolean; override; function GetDefaultTransactionIsolation: TZTransactIsolationLevel; override; function DataDefinitionCausesTransactionCommit: Boolean; override; function DataDefinitionIgnoredInTransactions: Boolean; override; // interface details (terms, keywords, etc): // function GetIdentifierQuoteString: string; override; -> Not implemented function GetSchemaTerm: string; override; function GetProcedureTerm: string; override; function GetCatalogTerm: string; override; function GetCatalogSeparator: string; override; function GetSQLKeywords: string; override; function GetNumericFunctions: string; override; function GetStringFunctions: string; override; function GetSystemFunctions: string; override; function GetTimeDateFunctions: string; override; function GetSearchStringEscape: string; override; function GetExtraNameCharacters: string; override; end; {** Implements SQLite Database Metadata. } TZSQLiteDatabaseMetadata = class(TZAbstractDatabaseMetadata) protected function DeComposeObjectString(const S: String): String; reintroduce; function CreateDatabaseInfo: IZDatabaseInfo; override; // technobot 2008-06-28 function UncachedGetTables(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const Types: TStringDynArray): IZResultSet; override; // function UncachedGetSchemas: IZResultSet; override; -> not implemented // function UncachedGetCatalogs: IZResultSet; override; -> not implemented function UncachedGetTableTypes: IZResultSet; override; function UncachedGetColumns(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const ColumnNamePattern: string): IZResultSet; override; // function UncachedGetTablePrivileges(const Catalog: string; const SchemaPattern: string; -> not implemented // const TableNamePattern: string): IZResultSet; override; // function UncachedGetColumnPrivileges(const Catalog: string; const Schema: string; -> not implemented // const Table: string; const ColumnNamePattern: string): IZResultSet; override; function UncachedGetPrimaryKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; override; // function UncachedGetImportedKeys(const Catalog: string; const Schema: string; // const Table: string): IZResultSet; override; // function UncachedGetExportedKeys(const Catalog: string; const Schema: string; // const Table: string): IZResultSet; override; // function UncachedGetCrossReference(const PrimaryCatalog: string; const PrimarySchema: string; // const PrimaryTable: string; const ForeignCatalog: string; const ForeignSchema: string; // const ForeignTable: string): IZResultSet; override; function UncachedGetIndexInfo(const Catalog: string; const Schema: string; const Table: string; Unique: Boolean; Approximate: Boolean): IZResultSet; override; // function UncachedGetSequences(const Catalog: string; const SchemaPattern: string; // const SequenceNamePattern: string): IZResultSet; virtual; -> Not implemented // function UncachedGetProcedures(const Catalog: string; const SchemaPattern: string; // const ProcedureNamePattern: string): IZResultSet; override; // function UncachedGetProcedureColumns(const Catalog: string; const SchemaPattern: string; // const ProcedureNamePattern: string; const ColumnNamePattern: string): // IZResultSet; override; // function UncachedGetVersionColumns(const Catalog: string; const Schema: string; // const Table: string): IZResultSet; override; function UncachedGetTypeInfo: IZResultSet; override; function UncachedGetCharacterSets: IZResultSet; override; //EgonHugeist public destructor Destroy; override; end; implementation uses ZDbcUtils; { TZSQLiteDatabaseInfo } //---------------------------------------------------------------------- // First, a variety of minor information about the target database. {** What's the name of this database product? @return database product name } function TZSQLiteDatabaseInfo.GetDatabaseProductName: string; begin Result := 'SQLite'; end; {** What's the version of this database product? @return database version } function TZSQLiteDatabaseInfo.GetDatabaseProductVersion: string; begin Result := ''; end; {** What's the name of this JDBC driver? @return JDBC driver name } function TZSQLiteDatabaseInfo.GetDriverName: string; begin Result := 'Zeos Database Connectivity Driver for SQLite'; end; {** What's this JDBC driver's major version number? @return JDBC driver major version } function TZSQLiteDatabaseInfo.GetDriverMajorVersion: Integer; begin Result := 1; end; {** What's this JDBC driver's minor version number? @return JDBC driver minor version number } function TZSQLiteDatabaseInfo.GetDriverMinorVersion: Integer; begin Result := 0; end; {** Does the database use a file for each table? @return true if the database uses a local file for each table } function TZSQLiteDatabaseInfo.UsesLocalFilePerTable: Boolean; begin Result := False; end; {** Does the database treat mixed case unquoted SQL identifiers as case sensitive and as a result store them in mixed case? A JDBC CompliantTM driver will always return false. @return true if so; false otherwise } function TZSQLiteDatabaseInfo.SupportsMixedCaseIdentifiers: Boolean; begin Result := True; end; {** Does the database treat mixed case unquoted SQL identifiers as case insensitive and store them in upper case? @return true if so; false otherwise } function TZSQLiteDatabaseInfo.StoresUpperCaseIdentifiers: Boolean; begin Result := False; end; {** Does the database treat mixed case unquoted SQL identifiers as case insensitive and store them in lower case? @return true if so; false otherwise } function TZSQLiteDatabaseInfo.StoresLowerCaseIdentifiers: Boolean; begin Result := False; end; {** Does the database treat mixed case unquoted SQL identifiers as case insensitive and store them in mixed case? @return true if so; false otherwise } function TZSQLiteDatabaseInfo.StoresMixedCaseIdentifiers: Boolean; begin Result := True; end; {** Does the database treat mixed case quoted SQL identifiers as case sensitive and as a result store them in mixed case? A JDBC CompliantTM driver will always return true. @return true if so; false otherwise } function TZSQLiteDatabaseInfo.SupportsMixedCaseQuotedIdentifiers: Boolean; begin Result := True; end; {** Does the database treat mixed case quoted SQL identifiers as case insensitive and store them in upper case? @return true if so; false otherwise } function TZSQLiteDatabaseInfo.StoresUpperCaseQuotedIdentifiers: Boolean; begin Result := False; end; {** Does the database treat mixed case quoted SQL identifiers as case insensitive and store them in lower case? @return true if so; false otherwise } function TZSQLiteDatabaseInfo.StoresLowerCaseQuotedIdentifiers: Boolean; begin Result := False; end; {** Does the database treat mixed case quoted SQL identifiers as case insensitive and store them in mixed case? @return true if so; false otherwise } function TZSQLiteDatabaseInfo.StoresMixedCaseQuotedIdentifiers: Boolean; begin Result := True; end; {** Gets a comma-separated list of all a database's SQL keywords that are NOT also SQL92 keywords. @return the list } function TZSQLiteDatabaseInfo.GetSQLKeywords: string; begin Result := 'ALL,AND,AS,BETWEEN,BY,CASE,CHECK,COLLATE,COMMIT,CONSTRAINT,CREATE,' + 'DEFAULT,DEFERRABLE,DELETE,DISTINCT,DROP,ELSE,EXCEPT,FOREIGN,FROM,GLOB,' + 'GROUP,HAVING,IN,INDEX,INSERT,INTERSECT,INTO,IS,ISNULL,JOIN,LIKE,LIMIT,' + 'NOT,NOTNULL,NULL,ON,OR,ORDER,PRIMARY,REFERENCES,ROLLBACK,SELECT,SET,' + 'TABLE,THEN,TRANSACTION,UNION,UNIQUE,UPDATE,USING,VALUES,WHEN,WHERE,' + 'ABORT,AFTER,ASC,ATTACH,BEFORE,BEGIN,DEFERRED,CASCADE,CLUSTER,CONFLICT,' + 'COPY,CROSS,DATABASE,DELIMITERS,DESC,DETACH,EACH,END,EXPLAIN,FAIL,FOR,' + 'FULL,IGNORE,IMMEDIATE,INITIALLY,INNER,INSTEAD,KEY,LEFT,MATCH,NATURAL,' + 'OF,OFFSET,OUTER,PRAGMA,RAISE,REPLACE,RESTRICT,RIGHT,ROW,STATEMENT,' + 'TEMP,TEMPORARY,TRIGGER,VACUUM,VIEW'; end; {** Gets a comma-separated list of math functions. These are the X/Open CLI math function names used in the JDBC function escape clause. @return the list } function TZSQLiteDatabaseInfo.GetNumericFunctions: string; begin Result := 'ABS,MAX,MIN,RANDOM,ROUND'; end; {** Gets a comma-separated list of string functions. These are the X/Open CLI string function names used in the JDBC function escape clause. @return the list } function TZSQLiteDatabaseInfo.GetStringFunctions: string; begin Result := 'LENGTH,LIKE,LOWER,SOUNDEX,SUBSTRING,UPPER'; end; {** Gets a comma-separated list of system functions. These are the X/Open CLI system function names used in the JDBC function escape clause. @return the list } function TZSQLiteDatabaseInfo.GetSystemFunctions: string; begin Result := 'LAST_INSERT_ROWID,SQLITE_VERSION,TYPEOF'; end; {** Gets a comma-separated list of time and date functions. @return the list } function TZSQLiteDatabaseInfo.GetTimeDateFunctions: string; begin Result := ''; end; {** Gets the string that can be used to escape wildcard characters. This is the string that can be used to escape '_' or '%' in the string pattern style catalog search parameters.

The '_' character represents any single character.

The '%' character represents any sequence of zero or more characters. @return the string used to escape wildcard characters } function TZSQLiteDatabaseInfo.GetSearchStringEscape: string; begin Result := '//'; end; {** Gets all the "extra" characters that can be used in unquoted identifier names (those beyond a-z, A-Z, 0-9 and _). @return the string containing the extra characters } function TZSQLiteDatabaseInfo.GetExtraNameCharacters: string; begin Result := ''; end; //-------------------------------------------------------------------- // Functions describing which features are supported. {** Are expressions in "ORDER BY" lists supported? @return true if so; false otherwise } function TZSQLiteDatabaseInfo.SupportsExpressionsInOrderBy: Boolean; begin Result := False; end; {** Can an "ORDER BY" clause use columns not in the SELECT statement? @return true if so; false otherwise } function TZSQLiteDatabaseInfo.SupportsOrderByUnrelated: Boolean; begin Result := False; end; {** Is some form of "GROUP BY" clause supported? @return true if so; false otherwise } function TZSQLiteDatabaseInfo.SupportsGroupBy: Boolean; begin Result := True; end; {** Can a "GROUP BY" clause use columns not in the SELECT? @return true if so; false otherwise } function TZSQLiteDatabaseInfo.SupportsGroupByUnrelated: Boolean; begin Result := True; end; {** Can a "GROUP BY" clause add columns not in the SELECT provided it specifies all the columns in the SELECT? @return true if so; false otherwise } function TZSQLiteDatabaseInfo.SupportsGroupByBeyondSelect: Boolean; begin Result := True; end; {** Is the SQL Integrity Enhancement Facility supported? @return true if so; false otherwise } function TZSQLiteDatabaseInfo.SupportsIntegrityEnhancementFacility: Boolean; begin Result := False; end; {** What's the database vendor's preferred term for "schema"? @return the vendor term } function TZSQLiteDatabaseInfo.GetSchemaTerm: string; begin Result := ''; end; {** What's the database vendor's preferred term for "procedure"? @return the vendor term } function TZSQLiteDatabaseInfo.GetProcedureTerm: string; begin Result := ''; end; {** What's the database vendor's preferred term for "catalog"? @return the vendor term } function TZSQLiteDatabaseInfo.GetCatalogTerm: string; begin Result := 'database'; end; {** What's the separator between catalog and table name? @return the separator string } function TZSQLiteDatabaseInfo.GetCatalogSeparator: string; begin Result := '.'; end; {** Can a schema name be used in a data manipulation statement? @return true if so; false otherwise } function TZSQLiteDatabaseInfo.SupportsSchemasInDataManipulation: Boolean; begin Result := True; end; {** Can a schema name be used in a procedure call statement? @return true if so; false otherwise } function TZSQLiteDatabaseInfo.SupportsSchemasInProcedureCalls: Boolean; begin Result := False; end; {** Can a schema name be used in a table definition statement? @return true if so; false otherwise } function TZSQLiteDatabaseInfo.SupportsSchemasInTableDefinitions: Boolean; begin Result := False; end; {** Can a schema name be used in an index definition statement? @return true if so; false otherwise } function TZSQLiteDatabaseInfo.SupportsSchemasInIndexDefinitions: Boolean; begin Result := False; end; {** Can a schema name be used in a privilege definition statement? @return true if so; false otherwise } function TZSQLiteDatabaseInfo.SupportsSchemasInPrivilegeDefinitions: Boolean; begin Result := False; end; {** Can a catalog name be used in a data manipulation statement? @return true if so; false otherwise } function TZSQLiteDatabaseInfo.SupportsCatalogsInDataManipulation: Boolean; begin Result := True; end; {** Can a catalog name be used in a procedure call statement? @return true if so; false otherwise } function TZSQLiteDatabaseInfo.SupportsCatalogsInProcedureCalls: Boolean; begin Result := False; end; {** Can a catalog name be used in a table definition statement? @return true if so; false otherwise } function TZSQLiteDatabaseInfo.SupportsCatalogsInTableDefinitions: Boolean; begin Result := False; end; {** Can a catalog name be used in an index definition statement? @return true if so; false otherwise } function TZSQLiteDatabaseInfo.SupportsCatalogsInIndexDefinitions: Boolean; begin Result := False; end; {** Can a catalog name be used in a privilege definition statement? @return true if so; false otherwise } function TZSQLiteDatabaseInfo.SupportsCatalogsInPrivilegeDefinitions: Boolean; begin Result := True; end; {** Is positioned DELETE supported? @return true if so; false otherwise } function TZSQLiteDatabaseInfo.SupportsPositionedDelete: Boolean; begin Result := False; end; {** Is positioned UPDATE supported? @return true if so; false otherwise } function TZSQLiteDatabaseInfo.SupportsPositionedUpdate: Boolean; begin Result := False; end; {** Is SELECT for UPDATE supported? @return true if so; false otherwise } function TZSQLiteDatabaseInfo.SupportsSelectForUpdate: Boolean; begin Result := False; end; {** Are stored procedure calls using the stored procedure escape syntax supported? @return true if so; false otherwise } function TZSQLiteDatabaseInfo.SupportsStoredProcedures: Boolean; begin Result := False; end; {** Are subqueries in comparison expressions supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZSQLiteDatabaseInfo.SupportsSubqueriesInComparisons: Boolean; begin Result := True; end; {** Are subqueries in 'exists' expressions supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZSQLiteDatabaseInfo.SupportsSubqueriesInExists: Boolean; begin Result := True; end; {** Are subqueries in 'in' statements supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZSQLiteDatabaseInfo.SupportsSubqueriesInIns: Boolean; begin Result := True; end; {** Are subqueries in quantified expressions supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZSQLiteDatabaseInfo.SupportsSubqueriesInQuantifieds: Boolean; begin Result := True; end; {** Are correlated subqueries supported? A JDBC CompliantTM driver always returns true. @return true if so; false otherwise } function TZSQLiteDatabaseInfo.SupportsCorrelatedSubqueries: Boolean; begin Result := True; end; {** Is SQL UNION supported? @return true if so; false otherwise } function TZSQLiteDatabaseInfo.SupportsUnion: Boolean; begin Result := True; end; {** Is SQL UNION ALL supported? @return true if so; false otherwise } function TZSQLiteDatabaseInfo.SupportsUnionAll: Boolean; begin Result := True; end; {** Can cursors remain open across commits? @return true if cursors always remain open; false if they might not remain open } function TZSQLiteDatabaseInfo.SupportsOpenCursorsAcrossCommit: Boolean; begin Result := False; end; {** Can cursors remain open across rollbacks? @return true if cursors always remain open; false if they might not remain open } function TZSQLiteDatabaseInfo.SupportsOpenCursorsAcrossRollback: Boolean; begin Result := False; end; {** Can statements remain open across commits? @return true if statements always remain open; false if they might not remain open } function TZSQLiteDatabaseInfo.SupportsOpenStatementsAcrossCommit: Boolean; begin Result := False; end; {** Can statements remain open across rollbacks? @return true if statements always remain open; false if they might not remain open } function TZSQLiteDatabaseInfo.SupportsOpenStatementsAcrossRollback: Boolean; begin Result := False; end; //---------------------------------------------------------------------- // The following group of methods exposes various limitations // based on the target database with the current driver. // Unless otherwise specified, a result of zero means there is no // limit, or the limit is not known. {** How many hex characters can you have in an inline binary literal? @return max binary literal length in hex characters; a result of zero means that there is no limit or the limit is not known } function TZSQLiteDatabaseInfo.GetMaxBinaryLiteralLength: Integer; begin Result := 0; end; {** What's the max length for a character literal? @return max literal length; a result of zero means that there is no limit or the limit is not known } function TZSQLiteDatabaseInfo.GetMaxCharLiteralLength: Integer; begin Result := 0; end; {** What's the limit on column name length? @return max column name length; a result of zero means that there is no limit or the limit is not known } function TZSQLiteDatabaseInfo.GetMaxColumnNameLength: Integer; begin Result := 0; end; {** What's the maximum number of columns in a "GROUP BY" clause? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZSQLiteDatabaseInfo.GetMaxColumnsInGroupBy: Integer; begin Result := 0; end; {** What's the maximum number of columns allowed in an index? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZSQLiteDatabaseInfo.GetMaxColumnsInIndex: Integer; begin Result := 0; end; {** What's the maximum number of columns in an "ORDER BY" clause? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZSQLiteDatabaseInfo.GetMaxColumnsInOrderBy: Integer; begin Result := 0; end; {** What's the maximum number of columns in a "SELECT" list? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZSQLiteDatabaseInfo.GetMaxColumnsInSelect: Integer; begin Result := 0; end; {** What's the maximum number of columns in a table? @return max number of columns; a result of zero means that there is no limit or the limit is not known } function TZSQLiteDatabaseInfo.GetMaxColumnsInTable: Integer; begin Result := 0; end; {** How many active connections can we have at a time to this database? @return max number of active connections; a result of zero means that there is no limit or the limit is not known } function TZSQLiteDatabaseInfo.GetMaxConnections: Integer; begin Result := 0; end; {** What's the maximum cursor name length? @return max cursor name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZSQLiteDatabaseInfo.GetMaxCursorNameLength: Integer; begin Result := 0; end; {** Retrieves the maximum number of bytes for an index, including all of the parts of the index. @return max index length in bytes, which includes the composite of all the constituent parts of the index; a result of zero means that there is no limit or the limit is not known } function TZSQLiteDatabaseInfo.GetMaxIndexLength: Integer; begin Result := 0; end; {** What's the maximum length allowed for a schema name? @return max name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZSQLiteDatabaseInfo.GetMaxSchemaNameLength: Integer; begin Result := 0; end; {** What's the maximum length of a procedure name? @return max name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZSQLiteDatabaseInfo.GetMaxProcedureNameLength: Integer; begin Result := 0; end; {** What's the maximum length of a catalog name? @return max name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZSQLiteDatabaseInfo.GetMaxCatalogNameLength: Integer; begin Result := 0; end; {** What's the maximum length of a single row? @return max row size in bytes; a result of zero means that there is no limit or the limit is not known } function TZSQLiteDatabaseInfo.GetMaxRowSize: Integer; begin Result := 0; end; {** Did getMaxRowSize() include LONGVARCHAR and LONGVARBINARY blobs? @return true if so; false otherwise } function TZSQLiteDatabaseInfo.DoesMaxRowSizeIncludeBlobs: Boolean; begin Result := True; end; {** What's the maximum length of an SQL statement? @return max length in bytes; a result of zero means that there is no limit or the limit is not known } function TZSQLiteDatabaseInfo.GetMaxStatementLength: Integer; begin Result := 65535; end; {** How many active statements can we have open at one time to this database? @return the maximum number of statements that can be open at one time; a result of zero means that there is no limit or the limit is not known } function TZSQLiteDatabaseInfo.GetMaxStatements: Integer; begin Result := 0; end; {** What's the maximum length of a table name? @return max name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZSQLiteDatabaseInfo.GetMaxTableNameLength: Integer; begin Result := 0; end; {** What's the maximum number of tables in a SELECT statement? @return the maximum number of tables allowed in a SELECT statement; a result of zero means that there is no limit or the limit is not known } function TZSQLiteDatabaseInfo.GetMaxTablesInSelect: Integer; begin Result := 0; end; {** What's the maximum length of a user name? @return max user name length in bytes; a result of zero means that there is no limit or the limit is not known } function TZSQLiteDatabaseInfo.GetMaxUserNameLength: Integer; begin Result := 0; end; //---------------------------------------------------------------------- {** What's the database's default transaction isolation level? The values are defined in java.sql.Connection. @return the default isolation level @see Connection } function TZSQLiteDatabaseInfo.GetDefaultTransactionIsolation: TZTransactIsolationLevel; begin Result := tiNone; end; {** Are transactions supported? If not, invoking the method commit is a noop and the isolation level is TRANSACTION_NONE. @return true if transactions are supported; false otherwise } function TZSQLiteDatabaseInfo.SupportsTransactions: Boolean; begin Result := True; end; {** Does this database support the given transaction isolation level? @param level the values are defined in java.sql.Connection @return true if so; false otherwise @see Connection } function TZSQLiteDatabaseInfo.SupportsTransactionIsolationLevel( Level: TZTransactIsolationLevel): Boolean; begin Result := True; end; {** Are both data definition and data manipulation statements within a transaction supported? @return true if so; false otherwise } function TZSQLiteDatabaseInfo. SupportsDataDefinitionAndDataManipulationTransactions: Boolean; begin Result := True; end; {** Are only data manipulation statements within a transaction supported? @return true if so; false otherwise } function TZSQLiteDatabaseInfo. SupportsDataManipulationTransactionsOnly: Boolean; begin Result := True; end; {** Does a data definition statement within a transaction force the transaction to commit? @return true if so; false otherwise } function TZSQLiteDatabaseInfo.DataDefinitionCausesTransactionCommit: Boolean; begin Result := True; end; {** Is a data definition statement within a transaction ignored? @return true if so; false otherwise } function TZSQLiteDatabaseInfo.DataDefinitionIgnoredInTransactions: Boolean; begin Result := False; end; {** Does the database support the given result set type? @param type defined in java.sql.ResultSet @return true if so; false otherwise } function TZSQLiteDatabaseInfo.SupportsResultSetType( _Type: TZResultSetType): Boolean; begin Result := _Type = rtForwardOnly; end; {** Does the database support the concurrency type in combination with the given result set type? @param type defined in java.sql.ResultSet @param concurrency type defined in java.sql.ResultSet @return true if so; false otherwise } function TZSQLiteDatabaseInfo.SupportsResultSetConcurrency( _Type: TZResultSetType; Concurrency: TZResultSetConcurrency): Boolean; begin Result := (_Type = rtForwardOnly) and (Concurrency = rcReadOnly); end; { TZSQLiteDatabaseMetadata } {** Decomposes a object name, AnsiQuotedStr or NullText @param S the object string @return a non-quoted string } function TZSQLiteDatabaseMetadata.DecomposeObjectString(const S: String): String; begin if S = '' then Result := S else if IC.IsQuoted(S) then Result := IC.ExtractQuote(S) else Result := s; end; {** Destroys this object and cleanups the memory. } destructor TZSQLiteDatabaseMetadata.Destroy; begin inherited Destroy; end; {** Constructs a database information object and returns the interface to it. Used internally by the constructor. @return the database information object interface } function TZSQLiteDatabaseMetadata.CreateDatabaseInfo: IZDatabaseInfo; begin Result := TZSQLiteDatabaseInfo.Create(Self); end; {** Gets a description of tables available in a catalog.

Only table descriptions matching the catalog, schema, table name and type criteria are returned. They are ordered by TABLE_TYPE, TABLE_SCHEM and TABLE_NAME.

Each table description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. TABLE_TYPE String => table type. Typical types are "TABLE", "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM".
  5. REMARKS String => explanatory comment on the table

Note: Some databases may not return information for all tables. @param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param tableNamePattern a table name pattern @param types a list of table types to include; null returns all types @return ResultSet - each row is a table description @see #getSearchStringEscape } function TZSQLiteDatabaseMetadata.UncachedGetTables(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const Types: TStringDynArray): IZResultSet; var WhereClause, SQL: string; function IncludedType(TypeName: string): Boolean; var I: Integer; begin Result := False; for I := Low(Types) to High(Types) do Result := Result or (UpperCase(Types[I]) = TypeName); Result := Result or (Length(Types) = 0); end; begin WhereClause := ''; if IncludedType('TABLE') then WhereClause := 'TYPE=''table'''; if IncludedType('VIEW') then begin if WhereClause <> '' then WhereClause := '(' + WhereClause + ' OR TYPE=''view'')' else WhereClause := 'TYPE=''view'''; end; SQL := 'SELECT ''' + Catalog + ''' AS TABLE_CAT, NULL AS TABLE_SCHEM,' + ' TBL_NAME AS TABLE_NAME, UPPER(TYPE) AS TABLE_TYPE, NULL AS REMARKS' + ' FROM '; if Catalog <> '' then SQL := SQL + Catalog + '.'; SQL := SQL + 'SQLITE_MASTER WHERE ' + WhereClause + ' AND TBL_NAME LIKE ''' + ToLikeString(TableNamePattern) + ''''; Result := CopyToVirtualResultSet( GetConnection.CreateStatement.ExecuteQuery(SQL), ConstructVirtualResultSet(TableColumnsDynArray)); end; {** Gets the table types available in this database. The results are ordered by table type.

The table type is:

  1. TABLE_TYPE String => table type. Typical types are "TABLE", "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM".
@return ResultSet - each row has a single String column that is a table type } function TZSQLiteDatabaseMetadata.UncachedGetTableTypes: IZResultSet; const TableTypeCount = 2; Types: array [1..TableTypeCount] of string = ('TABLE', 'VIEW'); var I: Integer; begin Result:=inherited UncachedGetTableTypes; for I := 1 to TableTypeCount do begin Result.MoveToInsertRow; Result.UpdateString(1, Types[I]); Result.InsertRow; end; end; {** Gets a description of table columns available in the specified catalog.

Only column descriptions matching the catalog, schema, table and column name criteria are returned. They are ordered by TABLE_SCHEM, TABLE_NAME and ORDINAL_POSITION.

Each column description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. COLUMN_NAME String => column name
  5. DATA_TYPE short => SQL type from java.sql.Types
  6. TYPE_NAME String => Data source dependent type name, for a UDT the type name is fully qualified
  7. COLUMN_SIZE int => column size. For char or date types this is the maximum number of characters, for numeric or decimal types this is precision.
  8. BUFFER_LENGTH is not used.
  9. DECIMAL_DIGITS int => the number of fractional digits
  10. NUM_PREC_RADIX int => Radix (typically either 10 or 2)
  11. NULLABLE int => is NULL allowed?
    • columnNoNulls - might not allow NULL values
    • columnNullable - definitely allows NULL values
    • columnNullableUnknown - nullability unknown
  12. REMARKS String => comment describing column (may be null)
  13. COLUMN_DEF String => default value (may be null)
  14. SQL_DATA_TYPE int => unused
  15. SQL_DATETIME_SUB int => unused
  16. CHAR_OCTET_LENGTH int => for char types the maximum number of bytes in the column
  17. ORDINAL_POSITION int => index of column in table (starting at 1)
  18. IS_NULLABLE String => "NO" means column definitely does not allow NULL values; "YES" means the column might allow NULL values. An empty string means nobody knows.
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schemaPattern a schema name pattern; "" retrieves those without a schema @param tableNamePattern a table name pattern @param columnNamePattern a column name pattern @return ResultSet - each row is a column description @see #getSearchStringEscape } function TZSQLiteDatabaseMetadata.UncachedGetColumns(const Catalog: string; const SchemaPattern: string; const TableNamePattern: string; const ColumnNamePattern: string): IZResultSet; var Temp: string; Precision, Decimals: Integer; Temp_scheme: string; ResSet: IZResultSet; TempTableNamePattern: String; begin Result:=inherited UncachedGetColumns(Catalog, SchemaPattern, TableNamePattern, ColumnNamePattern); if SchemaPattern = '' then Temp_scheme := '' // OR 'main.' else Temp_scheme := SchemaPattern +'.'; TempTableNamePattern := NormalizePatternCase(TableNamePattern); ResSet := GetConnection.CreateStatement.ExecuteQuery( Format('PRAGMA %s table_info(''%s'')', [Temp_scheme, TempTableNamePattern])); if ResSet <> nil then with ResSet do begin while Next do begin Result.MoveToInsertRow; if SchemaPattern <> '' then Result.UpdateString(1, SchemaPattern) else Result.UpdateNull(1); Result.UpdateNull(2); Result.UpdateString(3, TempTableNamePattern); Result.UpdateString(4, GetString(2)); Result.UpdateInt(5, Ord(ConvertSQLiteTypeToSQLType(GetString(3), Precision, Decimals, ConSettings.CPType))); { Defines a table name. } Temp := UpperCase(GetString(3)); if Pos('(', Temp) > 0 then Temp := Copy(Temp, 1, Pos('(', Temp) - 1); Result.UpdateString(6, Temp); Result.UpdateInt(7, Precision); //Precision will be converted higher up Result.UpdateNull(8); Result.UpdateInt(9, Decimals); Result.UpdateInt(10, 0); if GetInt(4) <> 0 then begin Result.UpdateInt(11, Ord(ntNoNulls)); Result.UpdateString(18, 'NO'); end else begin Result.UpdateInt(11, Ord(ntNullable)); Result.UpdateString(18, 'YES'); end; Result.UpdateNull(12); if Trim(GetString(5)) <> '' then Result.UpdateString(13, GetString(5)) // Result.UpdateString(13, '''' + GetString(5) + '''') else Result.UpdateNull(13); Result.UpdateNull(14); Result.UpdateNull(15); Result.UpdateNull(16); Result.UpdateInt(17, GetInt(1) + 1); Result.UpdateBooleanByName('AUTO_INCREMENT', (GetInt(6) = 1) and (Temp = 'INTEGER')); Result.UpdateBooleanByName('CASE_SENSITIVE', False); Result.UpdateBooleanByName('SEARCHABLE', True); Result.UpdateBooleanByName('WRITABLE', True); Result.UpdateBooleanByName('DEFINITELYWRITABLE', True); Result.UpdateBooleanByName('READONLY', False); Result.InsertRow; end; Close; end; end; {** Gets a description of a table's primary key columns. They are ordered by COLUMN_NAME.

Each primary key column description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. COLUMN_NAME String => column name
  5. KEY_SEQ short => sequence number within primary key
  6. PK_NAME String => primary key name (may be null)
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @return ResultSet - each row is a primary key column description @exception SQLException if a database access error occurs } function TZSQLiteDatabaseMetadata.UncachedGetPrimaryKeys(const Catalog: string; const Schema: string; const Table: string): IZResultSet; var Index: Integer; Temp_scheme: string; begin Result:=inherited UncachedGetPrimaryKeys(Catalog, Schema, Table); if Schema = '' then Temp_scheme := '' // OR 'main.' else Temp_scheme := Schema +'.'; with GetConnection.CreateStatement.ExecuteQuery( Format('PRAGMA %s table_info(''%s'')', [Temp_scheme,Table])) do begin Index := 1; while Next do begin if GetInt(6) = 0 then Continue; Result.MoveToInsertRow; if Schema <> '' then Result.UpdateString(1, Schema) else Result.UpdateNull(1); Result.UpdateNull(2); Result.UpdateString(3, Table); Result.UpdateString(4, GetString(2)); Result.UpdateInt(5, Index); Result.UpdateNull(6); Inc(Index); Result.InsertRow; end; Close; end; end; {** Gets a description of all the standard SQL types supported by this database. They are ordered by DATA_TYPE and then by how closely the data type maps to the corresponding JDBC SQL type.

Each type description has the following columns:

  1. TYPE_NAME String => Type name
  2. DATA_TYPE short => SQL data type from java.sql.Types
  3. PRECISION int => maximum precision
  4. LITERAL_PREFIX String => prefix used to quote a literal (may be null)
  5. LITERAL_SUFFIX String => suffix used to quote a literal (may be null)
  6. CREATE_PARAMS String => parameters used in creating the type (may be null)
  7. NULLABLE short => can you use NULL for this type?
    • typeNoNulls - does not allow NULL values
    • typeNullable - allows NULL values
    • typeNullableUnknown - nullability unknown
  8. CASE_SENSITIVE Boolean=> is it case sensitive?
  9. SEARCHABLE short => can you use "WHERE" based on this type:
    • typePredNone - No support
    • typePredChar - Only supported with WHERE .. LIKE
    • typePredBasic - Supported except for WHERE .. LIKE
    • typeSearchable - Supported for all WHERE ..
  10. UNSIGNED_ATTRIBUTE Boolean => is it unsigned?
  11. FIXED_PREC_SCALE Boolean => can it be a money value?
  12. AUTO_INCREMENT Boolean => can it be used for an auto-increment value?
  13. LOCAL_TYPE_NAME String => localized version of type name (may be null)
  14. MINIMUM_SCALE short => minimum scale supported
  15. MAXIMUM_SCALE short => maximum scale supported
  16. SQL_DATA_TYPE int => unused
  17. SQL_DATETIME_SUB int => unused
  18. NUM_PREC_RADIX int => usually 2 or 10
@return ResultSet - each row is an SQL type description } function TZSQLiteDatabaseMetadata.UncachedGetTypeInfo: IZResultSet; const MaxTypeCount = 22; TypeNames: array[1..MaxTypeCount] of string = ( 'BOOLEAN', 'TINYINT', 'SMALLINT', 'MEDIUMINT', 'INTEGER', 'BIGINT', 'REAL', 'FLOAT', 'NUMERIC', 'DECIMAL', 'NUMBER', 'DOUBLE', 'CHAR', 'VARCHAR', 'BINARY', 'VARBINARY', 'DATE', 'TIME', 'DATETIME', 'TIMESTAMP', 'BLOB', 'TEXT'); TypeCodes: array[1..MaxTypeCount] of TZSQLType = ( stBoolean, stByte, stShort, stInteger, stInteger, stLong, stFloat, stFloat, stDouble, stDouble, stDouble, stDouble, stString, {$IFDEF UNICODE}stUnicodeString{$ELSE}stString{$ENDIF}, stBytes, stBytes, stDate, stTime, stTimestamp, stTimestamp, stBinaryStream, {$IFDEF UNICODE}stUnicodeStream{$ELSE}stAsciiStream{$ENDIF}); TypePrecision: array[1..MaxTypeCount] of Integer = ( -1, 2, 4, 9, 9, 16, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1); var I: Integer; begin Result:=inherited UncachedGetTypeInfo; for I := 1 to MaxTypeCount do begin Result.MoveToInsertRow; Result.UpdateString(1, TypeNames[I]); Result.UpdateInt(2, Ord(TypeCodes[I])); if TypePrecision[I] >= 0 then Result.UpdateInt(3, TypePrecision[I]) else Result.UpdateNull(3); if TypeCodes[I] in [stString, stBytes, stDate, stTime, stTimeStamp, stBinaryStream, stAsciiStream, stUnicodeString] then begin Result.UpdateString(4, ''''); Result.UpdateString(5, ''''); end else begin Result.UpdateNull(4); Result.UpdateNull(5); end; Result.UpdateNull(6); Result.UpdateInt(7, Ord(ntNullable)); Result.UpdateBoolean(8, False); Result.UpdateBoolean(9, False); Result.UpdateBoolean(11, False); Result.UpdateBoolean(12, False); Result.UpdateBoolean(12, TypeNames[I] = 'INTEGER'); Result.UpdateNull(13); Result.UpdateNull(14); Result.UpdateNull(15); Result.UpdateNull(16); Result.UpdateNull(17); Result.UpdateInt(18, 10); Result.InsertRow; end; end; {** Gets a description of a table's indices and statistics. They are ordered by NON_UNIQUE, TYPE, INDEX_NAME, and ORDINAL_POSITION.

Each index column description has the following columns:

  1. TABLE_CAT String => table catalog (may be null)
  2. TABLE_SCHEM String => table schema (may be null)
  3. TABLE_NAME String => table name
  4. NON_UNIQUE Boolean => Can index values be non-unique? false when TYPE is tableIndexStatistic
  5. INDEX_QUALIFIER String => index catalog (may be null); null when TYPE is tableIndexStatistic
  6. INDEX_NAME String => index name; null when TYPE is tableIndexStatistic
  7. TYPE short => index type:
    • tableIndexStatistic - this identifies table statistics that are returned in conjuction with a table's index descriptions
    • tableIndexClustered - this is a clustered index
    • tableIndexHashed - this is a hashed index
    • tableIndexOther - this is some other style of index
  8. ORDINAL_POSITION short => column sequence number within index; zero when TYPE is tableIndexStatistic
  9. COLUMN_NAME String => column name; null when TYPE is tableIndexStatistic
  10. ASC_OR_DESC String => column sort sequence, "A" => ascending, "D" => descending, may be null if sort sequence is not supported; null when TYPE is tableIndexStatistic
  11. CARDINALITY int => When TYPE is tableIndexStatistic, then this is the number of rows in the table; otherwise, it is the number of unique values in the index.
  12. PAGES int => When TYPE is tableIndexStatisic then this is the number of pages used for the table, otherwise it is the number of pages used for the current index.
  13. FILTER_CONDITION String => Filter condition, if any. (may be null)
@param catalog a catalog name; "" retrieves those without a catalog; null means drop catalog name from the selection criteria @param schema a schema name; "" retrieves those without a schema @param table a table name @param unique when true, return only indices for unique values; when false, return indices regardless of whether unique or not @param approximate when true, result is allowed to reflect approximate or out of data values; when false, results are requested to be accurate @return ResultSet - each row is an index column description } function TZSQLiteDatabaseMetadata.UncachedGetIndexInfo(const Catalog: string; const Schema: string; const Table: string; Unique: Boolean; Approximate: Boolean): IZResultSet; var MainResultSet, ResultSet: IZResultSet; Temp_scheme: string; begin Result:=inherited UncachedGetIndexInfo(Catalog, Schema, Table, Unique, Approximate); if Schema = '' then Temp_scheme := '' // OR 'main.' else Temp_scheme := Schema +'.'; MainResultSet := GetConnection.CreateStatement.ExecuteQuery( Format('PRAGMA %s index_list(''%s'')', [Temp_scheme, Table])); if MainResultSet<>nil then begin while MainResultSet.Next do begin if (Pos(' autoindex ', String(MainResultSet.GetString(2))) = 0) and ((Unique = False) or (MainResultSet.GetInt(3) = 0)) then begin ResultSet := GetConnection.CreateStatement.ExecuteQuery( Format('PRAGMA %s index_info(''%s'')', [Temp_scheme,MainResultSet.GetString(2)])); while ResultSet.Next do begin Result.MoveToInsertRow; if Schema <> '' then Result.UpdateString(1, Schema) else Result.UpdateNull(1); Result.UpdateNull(2); Result.UpdateString(3, Table); Result.UpdateBoolean(4, MainResultSet.GetInt(3) = 0); Result.UpdateNull(5); Result.UpdateString(6, MainResultSet.GetString(2)); Result.UpdateNull(7); Result.UpdateInt(8, ResultSet.GetInt(1) + 1); Result.UpdateString(9, ResultSet.GetString(3)); Result.UpdateString(10, 'A'); Result.UpdateInt(11, 0); Result.UpdateInt(12, 0); Result.UpdateNull(13); Result.InsertRow; end; ResultSet.Close; end; end; MainResultSet.Close; end; end; {** Gets the supported CharacterSets: @return ResultSet - each row is a CharacterSetName and it's ID } type CodePageRec = record CP: String; ID: Integer; end; function TZSQLiteDatabaseMetadata.UncachedGetCharacterSets: IZResultSet; //EgonHugeist const Encodings: array[0..3] of CodePageRec =( (CP: 'UTF-8'; ID: 1), (CP: 'UTF-16le'; ID: 2), (CP: 'UTF-16be'; ID: 3), (CP: 'UTF-16'; ID: 4) ); var I: Integer; begin { TODO -oEgonHugeist : Correct this please if i'm wrong here!!! } {Text Encodings #define SQLITE_UTF8 1 #define SQLITE_UTF16LE 2 #define SQLITE_UTF16BE 3 #define SQLITE_UTF16 4 /* Use native byte order */ #define SQLITE_ANY 5 /* sqlite3_create_function only */ #define SQLITE_UTF16_ALIGNED 8 /* sqlite3_create_collation only */ These constant define integer codes that represent the various text encodings supported by SQLite.} Result:=inherited UncachedGetCharacterSets; for i := 0 to high(Encodings) do begin Result.MoveToInsertRow; Result.UpdateString(1, Encodings[i].CP); //CHARACTER_SET_NAME Result.UpdateShort(2, Encodings[i].ID); //CHARACTER_SET_ID Result.InsertRow; end; end; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcSqLiteResultSet.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { SQLite Database Connectivity Classes } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcSqLiteResultSet; interface {$I ZDbc.inc} uses {$IFDEF WITH_TOBJECTLIST_INLINE}System.Types, System.Contnrs{$ELSE}Types, Contnrs{$ENDIF}, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, ZSysUtils, ZDbcIntfs, ZDbcResultSet, ZDbcResultSetMetadata, ZPlainSqLiteDriver, ZCompatibility, ZDbcCache, ZDbcCachedResultSet, ZDbcGenericResolver; type {** Implements SQLite ResultSet Metadata. } TZSQLiteResultSetMetadata = class(TZAbstractResultSetMetadata) public // function IsAutoIncrement(Column: Integer): Boolean; override; function IsNullable(Column: Integer): TZColumnNullableType; override; end; {** Implements SQLite ResultSet. } TZSQLiteResultSet = class(TZAbstractResultSet) private FFetchingReady: Boolean; FHandle: Psqlite; FStmtHandle: Psqlite_vm; FColumnCount: Integer; FColumnNames: PPAnsiChar; FColumnValues: PPAnsiChar; FPlainDriver: IZSQLitePlainDriver; FFreeHandle: Boolean; protected procedure Open; override; procedure FreeHandle; function InternalGetString(ColumnIndex: Integer): RawByteString; override; public constructor Create(PlainDriver: IZSQLitePlainDriver; Statement: IZStatement; SQL: string; Handle: Psqlite; StmtHandle: Psqlite_vm; ColumnCount: Integer; ColumnNames: PPAnsiChar; ColumnValues: PPAnsiChar; AllowFreeHandle: Boolean = True); destructor Destroy; override; procedure Close; override; function IsNull(ColumnIndex: Integer): Boolean; override; function GetPChar(ColumnIndex: Integer): PChar; override; function GetBoolean(ColumnIndex: Integer): Boolean; override; function GetByte(ColumnIndex: Integer): Byte; override; function GetShort(ColumnIndex: Integer): SmallInt; override; function GetInt(ColumnIndex: Integer): Integer; override; function GetLong(ColumnIndex: Integer): Int64; override; function GetFloat(ColumnIndex: Integer): Single; override; function GetDouble(ColumnIndex: Integer): Double; override; function GetBigDecimal(ColumnIndex: Integer): Extended; override; function GetBytes(ColumnIndex: Integer): TByteDynArray; override; function GetDate(ColumnIndex: Integer): TDateTime; override; function GetTime(ColumnIndex: Integer): TDateTime; override; function GetTimestamp(ColumnIndex: Integer): TDateTime; override; function GetBlob(ColumnIndex: Integer): IZBlob; override; function Next: Boolean; override; end; {** Implements a cached resolver with SQLite specific functionality. } TZSQLiteCachedResolver = class (TZGenericCachedResolver, IZCachedResolver) private FHandle: Psqlite; FPlainDriver: IZSQLitePlainDriver; FAutoColumnIndex: Integer; public constructor Create(PlainDriver: IZSQLitePlainDriver; Handle: Psqlite; Statement: IZStatement; Metadata: IZResultSetMetadata); procedure PostUpdates(Sender: IZCachedResultSet; UpdateType: TZRowUpdateType; OldRowAccessor, NewRowAccessor: TZRowAccessor); override; function FormCalculateStatement(Columns: TObjectList): string; override; procedure UpdateAutoIncrementFields(Sender: IZCachedResultSet; UpdateType: TZRowUpdateType; OldRowAccessor, NewRowAccessor: TZRowAccessor; Resolver: IZCachedResolver); override; end; implementation uses ZMessages, ZDbcSqLite, ZDbcSQLiteUtils, ZMatchPattern, ZEncoding, ZDbcLogging, ZDbcSqLiteStatement; { TZSQLiteResultSetMetadata } {** Indicates whether the designated column is automatically numbered, thus read-only. @param column the first column is 1, the second is 2, ... @return true if so; false otherwise } { function TZSQLiteResultSetMetadata.IsAutoIncrement(Column: Integer): Boolean; begin Result := TZColumnInfo(ResultSet.ColumnsInfo[Column - 1]).AutoIncrement; end; } {** Indicates the nullability of values in the designated column. @param column the first column is 1, the second is 2, ... @return the nullability status of the given column; one of columnNoNulls, columnNullable or columnNullableUnknown } function TZSQLiteResultSetMetadata.IsNullable(Column: Integer): TZColumnNullableType; begin if IsAutoIncrement(Column) then Result := ntNullable else Result := inherited IsNullable(Column); end; { TZSQLiteResultSet } {** Constructs this object, assignes main properties and opens the record set. @param PlainDriver a native SQLite plain driver. @param Statement a related SQL statement object. @param Handle a SQLite specific query handle. @param UseResult True to use results, False to store result. } constructor TZSQLiteResultSet.Create(PlainDriver: IZSQLitePlainDriver; Statement: IZStatement; SQL: string; Handle: Psqlite; StmtHandle: Psqlite_vm; ColumnCount: Integer; ColumnNames: PPAnsiChar; ColumnValues: PPAnsiChar; AllowFreeHandle: Boolean = True); begin inherited Create(Statement, SQL, TZSQLiteResultSetMetadata.Create( Statement.GetConnection.GetMetadata, SQL, Self), Statement.GetConnection.GetConSettings); FHandle := Handle; FStmtHandle := StmtHandle; FPlainDriver := PlainDriver; ResultSetConcurrency := rcReadOnly; FColumnCount := ColumnCount; FColumnNames := ColumnNames; FColumnValues := ColumnValues; FFreeHandle := AllowFreeHandle; FFetchingReady := False; Open; end; {** Destroys this object and cleanups the memory. } destructor TZSQLiteResultSet.Destroy; begin //ZPlainSQLLiteDriver.Step : AllocMem(SizeOf(PPAnsiChar)*(pN+1)); // Leak, if not freed ! [HD, 05.10.2007] if FColumnValues <> nil then FreeMem(FColumnValues, Sizeof(PPAnsiChar) * (fColumnCount + 1)); FColumnValues := nil; //ZPlainSQLLiteDriver.Step : AllocMem(SizeOf(PPAnsiChar)*(pN+1)*2); // Leak, if not freed ! [HD, 05.10.2007] if FColumnNames <> nil then FreeMem(FColumnNames, Sizeof(PPAnsiChar) * (fColumnCount + 1) * 2); FColumnNames := nil; inherited Destroy; end; {** Opens this recordset. } procedure TZSQLiteResultSet.Open; var I: Integer; ColumnInfo: TZColumnInfo; FieldName: PPAnsiChar; FieldPrecision: Integer; FieldDecimals: Integer; TypeName: PPAnsiChar; begin if ResultSetConcurrency = rcUpdatable then raise EZSQLException.Create(SLiveResultSetsAreNotSupported); LastRowNo := 0; { Fills the column info. } ColumnsInfo.Clear; FieldName := FColumnNames; TypeName := FColumnNames; Inc(TypeName, FColumnCount); for I := 1 to FColumnCount do begin ColumnInfo := TZColumnInfo.Create; with ColumnInfo do begin ColumnLabel := ZDbcString(FieldName^); Inc(FieldName); TableName := ''; ReadOnly := False; if TypeName^ <> nil then begin ColumnType := ConvertSQLiteTypeToSQLType(ZDbcString(TypeName^), FieldPrecision, FieldDecimals, ConSettings.CPType); Inc(TypeName); end else begin ColumnType := ConvertSQLiteTypeToSQLType(ZDbcString(FPlainDriver.column_decltype(FStmtHandle,I-1)), FieldPrecision, FieldDecimals, ConSettings.CPType); end; if ColumnType = stString then if Zencoding.ZDefaultSystemCodePage = zCP_UTF8 then ColumnDisplaySize := FieldPrecision div 4 else ColumnDisplaySize := FieldPrecision div 2; if ColumnType = stUnicodeString then ColumnDisplaySize := FieldPrecision div 2; AutoIncrement := False; Precision := FieldPrecision; Scale := FieldDecimals; Signed := True; Nullable := ntNullable; end; ColumnsInfo.Add(ColumnInfo); end; inherited Open; end; {** Frees statement handle. } procedure TZSQLiteResultSet.FreeHandle; var ErrorCode: Integer; begin if FFreeHandle then begin if Assigned(FStmtHandle) then ErrorCode := FPlainDriver.Finalize(FStmtHandle) else ErrorCode := SQLITE_OK; FStmtHandle := nil; CheckSQLiteError(FPlainDriver, FStmtHandle, ErrorCode, nil, lcOther, 'FINALIZE SQLite VM'); end else if FStmtHandle <> nil then begin ErrorCode := FPlainDriver.reset(FStmtHandle); FStmtHandle := nil; CheckSQLiteError(FPlainDriver, FStmtHandle, ErrorCode, nil, lcBindPrepStmt, 'Reset Prepared Stmt'); FFetchingReady := True; end; end; {** Releases this ResultSet object's database and JDBC resources immediately instead of waiting for this to happen when it is automatically closed.

Note: A ResultSet object is automatically closed by the Statement object that generated it when that Statement object is closed, re-executed, or is used to retrieve the next result from a sequence of multiple results. A ResultSet object is also automatically closed when it is garbage collected. } procedure TZSQLiteResultSet.Close; var stmt: IZSQLiteCAPIPreparedStatement; begin if Assigned(Statement) and Supports(Statement, IZSQLiteCAPIPreparedStatement, stmt) then stmt.FreeReference; inherited Close; FreeHandle; end; {** Indicates if the value of the designated column in the current row of this ResultSet object is Null. @param columnIndex the first column is 1, the second is 2, ... @return if the value is SQL NULL, the value returned is true. false otherwise. } function TZSQLiteResultSet.IsNull(ColumnIndex: Integer): Boolean; var Temp: PPAnsiChar; begin {$IFNDEF DISABLE_CHECKING} CheckClosed; if (LastRowNo = 0) or (FColumnValues = nil) then raise EZSQLException.Create(SRowDataIsNotAvailable); {$ENDIF} Temp := FColumnValues; Inc(Temp, ColumnIndex - 1); Result := (Temp^ = nil); end; {** Gets the value of the designated column in the current row of this ResultSet object as a PAnsiChar in the Delphi programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZSQLiteResultSet.GetPChar(ColumnIndex: Integer): PChar; var TempStr: String; begin {$IFNDEF DISABLE_CHECKING} CheckClosed; if (LastRowNo = 0) or (FColumnValues = nil) then raise EZSQLException.Create(SRowDataIsNotAvailable); {$ENDIF} TempStr := GetString(ColumnIndex); Result := PChar(TempStr); LastWasNull := Result = nil; end; {** Gets the value of the designated column in the current row of this ResultSet object as a String in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZSQLiteResultSet.InternalGetString(ColumnIndex: Integer): RawByteString; var Temp: PPAnsiChar; begin {$IFNDEF DISABLE_CHECKING} CheckClosed; if (LastRowNo = 0) or (FColumnValues = nil) then raise EZSQLException.Create(SRowDataIsNotAvailable); {$ENDIF} Temp := FColumnValues; Inc(Temp, ColumnIndex - 1); Result := Temp^; LastWasNull := Temp^ = nil; end; {** Gets the value of the designated column in the current row of this ResultSet object as a boolean in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is false } function TZSQLiteResultSet.GetBoolean(ColumnIndex: Integer): Boolean; var Temp: string; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stBoolean); {$ENDIF} Temp := UpperCase(String(InternalGetString(ColumnIndex))); Result := (Temp = 'Y') or (Temp = 'YES') or (Temp = 'T') or (Temp = 'TRUE') or (StrToIntDef(Temp, 0) <> 0); end; {** Gets the value of the designated column in the current row of this ResultSet object as a byte in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZSQLiteResultSet.GetByte(ColumnIndex: Integer): Byte; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stByte); {$ENDIF} Result := Byte(StrToIntDef(String(InternalGetString(ColumnIndex)), 0)); end; {** Gets the value of the designated column in the current row of this ResultSet object as a short in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZSQLiteResultSet.GetShort(ColumnIndex: Integer): SmallInt; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stShort); {$ENDIF} Result := SmallInt(StrToIntDef(String(InternalGetString(ColumnIndex)), 0)); end; {** Gets the value of the designated column in the current row of this ResultSet object as an int in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZSQLiteResultSet.GetInt(ColumnIndex: Integer): Integer; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stInteger); {$ENDIF} Result := StrToIntDef(String(InternalGetString(ColumnIndex)), 0); end; {** Gets the value of the designated column in the current row of this ResultSet object as a long in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZSQLiteResultSet.GetLong(ColumnIndex: Integer): Int64; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stLong); {$ENDIF} Result := StrToInt64Def(String(InternalGetString(ColumnIndex)), 0); end; {** Gets the value of the designated column in the current row of this ResultSet object as a float in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZSQLiteResultSet.GetFloat(ColumnIndex: Integer): Single; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stFloat); {$ENDIF} Result := SQLStrToFloatDef(InternalGetString(ColumnIndex), 0); end; {** Gets the value of the designated column in the current row of this ResultSet object as a double in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is 0 } function TZSQLiteResultSet.GetDouble(ColumnIndex: Integer): Double; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stDouble); {$ENDIF} Result := SQLStrToFloatDef(InternalGetString(ColumnIndex), 0); end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.BigDecimal in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @param scale the number of digits to the right of the decimal point @return the column value; if the value is SQL NULL, the value returned is null } function TZSQLiteResultSet.GetBigDecimal(ColumnIndex: Integer): Extended; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stBigDecimal); {$ENDIF} Result := SQLStrToFloatDef(InternalGetString(ColumnIndex), 0); end; {** Gets the value of the designated column in the current row of this ResultSet object as a byte array in the Java programming language. The bytes represent the raw values returned by the driver. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZSQLiteResultSet.GetBytes(ColumnIndex: Integer): TByteDynArray; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stBytes); {$ENDIF} Result := StrToBytes(DecodeString(InternalGetString(ColumnIndex))); end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Date object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZSQLiteResultSet.GetDate(ColumnIndex: Integer): TDateTime; var Value: string; TempDate: TDateTime; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stDate); {$ENDIF} Value := String(InternalGetString(ColumnIndex)); if IsMatch('????-??-??*', Value) then Result := Trunc(AnsiSQLDateToDateTime(Value)) else begin TempDate := Trunc(SQLStrToFloatDef(Value, 0)); Result := Trunc(TimestampStrToDateTime(Value)); if ( Result = 0 ) and not ( TempDate = 0 ) then Result := TempDate; end; LastWasNull := Result = 0; end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Time object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null } function TZSQLiteResultSet.GetTime(ColumnIndex: Integer): TDateTime; var Value: string; TempTime: TDateTime; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stTime); {$ENDIF} Value := String(InternalGetString(ColumnIndex)); if IsMatch('*??:??:??*', Value) then Result := Frac(AnsiSQLDateToDateTime(Value)) else begin TempTime := Frac(SQLStrToFloatDef(Value, 0)); Result := Frac(TimestampStrToDateTime(Value)); if ( Result = 0 ) and not ( TempTime = 0 ) then Result := TempTime; end; LastWasNull := Result = 0; end; {** Gets the value of the designated column in the current row of this ResultSet object as a java.sql.Timestamp object in the Java programming language. @param columnIndex the first column is 1, the second is 2, ... @return the column value; if the value is SQL NULL, the value returned is null @exception SQLException if a database access error occurs } function TZSQLiteResultSet.GetTimestamp(ColumnIndex: Integer): TDateTime; var Value: string; TempTimeStamp: TDateTime; begin {$IFNDEF DISABLE_CHECKING} CheckColumnConvertion(ColumnIndex, stTimestamp); {$ENDIF} Value := String(InternalGetString(ColumnIndex)); if IsMatch('????-??-??*', Value) then Result := AnsiSQLDateToDateTime(Value) else begin TempTimeStamp := SQLStrToFloatDef(Value, 0); Result := TimestampStrToDateTime(Value); if ( Result = 0 ) and not ( TempTimeStamp = 0 ) then Result := TempTimeStamp; end; LastWasNull := Result = 0; end; {** Returns the value of the designated column in the current row of this ResultSet object as a Blob object in the Java programming language. @param ColumnIndex the first column is 1, the second is 2, ... @return a Blob object representing the SQL BLOB value in the specified column } function TZSQLiteResultSet.GetBlob(ColumnIndex: Integer): IZBlob; var Stream: TStream; AnsiTemp: RawByteString; begin Result := nil; {$IFNDEF DISABLE_CHECKING} CheckBlobColumn(ColumnIndex); {$ENDIF} LastWasNull := IsNull(ColumnIndex); if LastWasNull then Exit; Stream := nil; try if not LastWasNull then begin case GetMetadata.GetColumnType(ColumnIndex) of stAsciiStream: if ConSettings.AutoEncode then Stream := TStringStream.Create(GetValidatedAnsiString(InternalGetString(ColumnIndex), ConSettings, True)) else Stream := TStringStream.Create(InternalGetString(ColumnIndex)); stUnicodeStream: begin AnsiTemp := InternalGetString(ColumnIndex); if Length(AnsiTemp) = 0 then Stream := TMemoryStream.Create else Stream := GetValidatedUnicodeStream(InternalGetString(ColumnIndex), ConSettings, True); end; stBinaryStream: {introduced the old Zeos6 blob-encoding cause of compatibility reasons} if (Statement.GetConnection as IZSQLiteConnection).UseOldBlobEncoding then Stream := TStringStream.Create(DecodeString(InternalGetString(ColumnIndex))) else Stream := FPlaindriver.column_blob(FStmtHandle,columnIndex); end; Result := TZAbstractBlob.CreateWithStream(Stream, GetStatement.GetConnection, GetMetadata.GetColumnType(ColumnIndex) = stUnicodeStream); end else Result := TZAbstractBlob.CreateWithStream(nil, GetStatement.GetConnection); finally if Assigned(Stream) then Stream.Free; end; end; {** Moves the cursor down one row from its current position. A ResultSet cursor is initially positioned before the first row; the first call to the method next makes the first row the current row; the second call makes the second row the current row, and so on.

If an input stream is open for the current row, a call to the method next will implicitly close it. A ResultSet object's warning chain is cleared when a new row is read. @return true if the new current row is valid; false if there are no more rows } function TZSQLiteResultSet.Next: Boolean; var ErrorCode: Integer; begin { Checks for maximum row. } Result := False; if (MaxRows > 0) and (RowNo >= MaxRows) then Exit; if LastRowNo = 0 then begin Result := FColumnValues <> nil; if Result then begin LastRowNo := LastRowNo + 1; RowNo := RowNo + 1; end else begin if RowNo <= LastRowNo then RowNo := LastRowNo + 1; end; end else begin //ZPlainSQLLiteDriver.Step : AllocMem(SizeOf(PPAnsiChar)*(pN+1)); // Leak, if not freed ! [HD, 05.10.2007] if FColumnValues <> nil then FreeMem(FColumnValues, Sizeof(PPAnsiChar) * (fColumnCount + 1)); FColumnValues := nil; if Assigned(FStmtHandle) and not FFetchingReady then begin //ZPlainSQLLiteDriver.Step : AllocMem(SizeOf(PPAnsiChar)*(pN+1)*2); // Leak, if not freed [HD, 05.10.2007] if FColumnNames <> nil then FreeMem(FColumnNames, Sizeof(PPAnsiChar) * (fColumnCount + 1) * 2); FColumnNames := nil; ErrorCode := FPlainDriver.Step(FStmtHandle, FColumnCount, FColumnValues, FColumnNames); CheckSQLiteError(FPlainDriver, FStmtHandle, ErrorCode, nil, lcOther, 'FETCH'); end; if FColumnValues <> nil then begin RowNo := RowNo + 1; if LastRowNo < RowNo then LastRowNo := RowNo; Result := True; end else begin if RowNo <= LastRowNo then RowNo := LastRowNo + 1; Result := False; end; end; { Frees handle when reads to the end. } if not Result and Assigned(FStmtHandle) then FreeHandle; end; { TZSQLiteCachedResolver } {** Creates a SQLite specific cached resolver object. @param PlainDriver a native SQLite plain driver. @param Handle a SQLite specific query handle. @param Statement a related SQL statement object. @param Metadata a resultset metadata reference. } constructor TZSQLiteCachedResolver.Create(PlainDriver: IZSQLitePlainDriver; Handle: Psqlite; Statement: IZStatement; Metadata: IZResultSetMetadata); var I: Integer; begin inherited Create(Statement, Metadata); FPlainDriver := PlainDriver; FHandle := Handle; { Defines an index of autoincrement field. } FAutoColumnIndex := 0; for I := 1 to Metadata.GetColumnCount do begin if Metadata.IsAutoIncrement(I) and (Metadata.GetColumnType(I) in [stByte, stShort, stInteger, stLong]) then begin FAutoColumnIndex := I; Break; end; end; end; {** Posts updates to database. @param Sender a cached result set object. @param UpdateType a type of updates. @param OldRowAccessor an accessor object to old column values. @param NewRowAccessor an accessor object to new column values. } procedure TZSQLiteCachedResolver.PostUpdates(Sender: IZCachedResultSet; UpdateType: TZRowUpdateType; OldRowAccessor, NewRowAccessor: TZRowAccessor); begin inherited PostUpdates(Sender, UpdateType, OldRowAccessor, NewRowAccessor); if (UpdateType = utInserted) then UpdateAutoIncrementFields(Sender, UpdateType, OldRowAccessor, NewRowAccessor, Self); end; {** Do Tasks after Post updates to database. @param Sender a cached result set object. @param UpdateType a type of updates. @param OldRowAccessor an accessor object to old column values. @param NewRowAccessor an accessor object to new column values. } procedure TZSQLiteCachedResolver.UpdateAutoIncrementFields( Sender: IZCachedResultSet; UpdateType: TZRowUpdateType; OldRowAccessor, NewRowAccessor: TZRowAccessor; Resolver: IZCachedResolver); var PlainDriver: IZSQLitePlainDriver; begin inherited; if (FAutoColumnIndex > 0) and (OldRowAccessor.IsNull(FAutoColumnIndex) or (OldRowAccessor.GetValue(FAutoColumnIndex).VInteger = 0)) then begin PlainDriver := (Connection as IZSQLiteConnection).GetPlainDriver; NewRowAccessor.SetLong(FAutoColumnIndex, PlainDriver.LastInsertRowId(FHandle)); end; end; // --> ms, 02/11/2005 {** Forms a where clause for SELECT statements to calculate default values. @param Columns a collection of key columns. @param OldRowAccessor an accessor object to old column values. } function TZSQLiteCachedResolver.FormCalculateStatement( Columns: TObjectList): string; var I: Integer; Current: TZResolverParameter; begin Result := ''; if Columns.Count = 0 then Exit; for I := 0 to Columns.Count - 1 do begin Current := TZResolverParameter(Columns[I]); if Result <> '' then Result := Result + ','; if Current.DefaultValue <> '' then Result := Result + Current.DefaultValue else Result := Result + 'NULL'; end; Result := 'SELECT ' + Result; end; // <-- ms end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcSqLiteStatement.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { SQLite Database Connectivity Classes } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcSqLiteStatement; interface {$I ZDbc.inc} uses Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, {$IFDEF WITH_WIDESTRUTILS}WideStrUtils, {$ENDIF} ZDbcIntfs, ZDbcStatement, ZPlainSqLiteDriver, ZCompatibility, ZDbcLogging, ZVariant; type {** Implements Generic SQLite Statement. } TZSQLiteStatement = class(TZAbstractStatement) private FHandle: Psqlite; FPlainDriver: IZSQLitePlainDriver; function CreateResultSet(const SQL: string; StmtHandle: Psqlite_vm; ColumnCount: Integer; ColumnNames: PPAnsiChar; ColumnValues: PPAnsiChar): IZResultSet; public constructor Create(PlainDriver: IZSQLitePlainDriver; Connection: IZConnection; Info: TStrings; Handle: Psqlite); function ExecuteQuery(const SQL: RawByteString): IZResultSet; override; function ExecuteUpdate(const SQL: RawByteString): Integer; override; function Execute(const SQL: RawByteString): Boolean; override; end; {$IFDEF ZEOS_TEST_ONLY} {** Implements Prepared SQL Statement. } TZSQLitePreparedStatement = class(TZEmulatedPreparedStatement) private FHandle: Psqlite; FPlainDriver: IZSQLitePlainDriver; protected function CreateExecStatement: IZStatement; override; function PrepareAnsiSQLParam(ParamIndex: Integer): RawByteString; override; public constructor Create(PlainDriver: IZSQLitePlainDriver; Connection: IZConnection; const SQL: string; Info: TStrings; Handle: Psqlite); end; {$ENDIF} IZSQLiteCAPIPreparedStatement = Interface(IZPreparedStatement) ['{CA05874D-E817-4523-B0AF-DBCDD0CF85CA}'] Procedure FreeReference; end; {** Implements CAPI Prepared SQL Statement. } TZSQLiteCAPIPreparedStatement = class(TZAbstractPreparedStatement, IZSQLiteCAPIPreparedStatement) private FErrorCode: Integer; FHandle: Psqlite; FStmtHandle: Psqlite3_stmt; FPlainDriver: IZSQLitePlainDriver; FOpenResultSet: Pointer; function CreateResultSet(const SQL: string; StmtHandle: Psqlite_vm; ColumnCount: Integer; ColumnNames: PPAnsiChar; ColumnValues: PPAnsiChar): IZResultSet; protected procedure SetASQL(const Value: RawByteString); override; procedure SetWSQL(const Value: ZWideString); override; procedure FreeReference; protected //abstaction overrides procedure PrepareInParameters; override; procedure BindInParameters; override; public constructor Create(PlainDriver: IZSQLitePlainDriver; Connection: IZConnection; const SQL: string; Info: TStrings; Handle: Psqlite); procedure Prepare; override; procedure Unprepare; override; function ExecuteQueryPrepared: IZResultSet; override; function ExecuteUpdatePrepared: Integer; override; function ExecutePrepared: Boolean; override; end; implementation uses Types, ZDbcSqLiteUtils, ZDbcSqLiteResultSet, ZSysUtils, ZEncoding, ZMessages, ZDbcCachedResultSet{$IFDEF WITH_UNITANSISTRINGS}, AnsiStrings{$ENDIF}; { TZSQLiteStatement } {** Constructs this object and assignes the main properties. @param PlainDriver a native SQLite plain driver. @param Connection a database connection object. @param Handle a connection handle pointer. @param Info a statement parameters. } constructor TZSQLiteStatement.Create(PlainDriver: IZSQLitePlainDriver; Connection: IZConnection; Info: TStrings; Handle: Psqlite); begin inherited Create(Connection, Info); FHandle := Handle; FPlainDriver := PlainDriver; ResultSetType := rtScrollInsensitive; end; {** Creates a result set based on the current settings. @return a created result set object. } function TZSQLiteStatement.CreateResultSet(const SQL: string; StmtHandle: Psqlite_vm; ColumnCount: Integer; ColumnNames: PPAnsiChar; ColumnValues: PPAnsiChar): IZResultSet; var CachedResolver: TZSQLiteCachedResolver; NativeResultSet: TZSQLiteResultSet; CachedResultSet: TZCachedResultSet; begin { Creates a native result set. } NativeResultSet := TZSQLiteResultSet.Create(FPlainDriver, Self, SQL, FHandle, StmtHandle, ColumnCount, ColumnNames, ColumnValues); NativeResultSet.SetConcurrency(rcReadOnly); { Creates a cached result set. } CachedResolver := TZSQLiteCachedResolver.Create(FPlainDriver, FHandle, Self, NativeResultSet.GetMetaData); CachedResultSet := TZCachedResultSet.Create(NativeResultSet, SQL, CachedResolver,GetConnection.GetConSettings); { Fetches all rows to prevent blocking. } CachedResultSet.SetType(rtScrollInsensitive); CachedResultSet.Last; CachedResultSet.BeforeFirst; CachedResultSet.SetConcurrency(GetResultSetConcurrency); Result := CachedResultSet; end; {** Executes an SQL statement that returns a single ResultSet object. @param sql typically this is a static SQL SELECT statement @return a ResultSet object that contains the data produced by the given query; never null } function TZSQLiteStatement.ExecuteQuery(const SQL: RawByteString): IZResultSet; var ErrorCode: Integer; StmtHandle: Psqlite3_stmt; ColumnCount: Integer; ColumnValues: PPAnsiChar; ColumnNames: PPAnsiChar; begin ColumnCount := 0; ASQL := SQL; //preprepares SQL ErrorCode := FPlainDriver.Prepare(FHandle, PAnsiChar(ASQL), Length(ASQL), StmtHandle, nil); CheckSQLiteError(FPlainDriver, FHandle, ErrorCode, nil, lcExecute, LogSQL); DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, LogSQL); try ErrorCode := FPlainDriver.Step(StmtHandle, ColumnCount, ColumnValues, ColumnNames); CheckSQLiteError(FPlainDriver, FHandle, ErrorCode, nil, lcOther, 'FETCH'); except FPlainDriver.Finalize(StmtHandle); raise; end; Result := CreateResultSet(SSQL, StmtHandle, ColumnCount, ColumnNames, ColumnValues); end; {** Executes an SQL INSERT, UPDATE or DELETE statement. In addition, SQL statements that return nothing, such as SQL DDL statements, can be executed. @param sql an SQL INSERT, UPDATE or DELETE statement or an SQL statement that returns nothing @return either the row count for INSERT, UPDATE or DELETE statements, or 0 for SQL statements that return nothing } function TZSQLiteStatement.ExecuteUpdate(const SQL: RawByteString): Integer; var ErrorCode: Integer; ErrorMessage: PAnsichar; begin ASQL := SQL; //preprepares SQL ErrorCode := FPlainDriver.Execute(FHandle, PAnsiChar(ASQL), nil, nil,ErrorMessage); CheckSQLiteError(FPlainDriver, FHandle, ErrorCode, ErrorMessage, lcExecute, SSQL); DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, SSQL); Result := FPlainDriver.Changes(FHandle); LastUpdateCount := Result; end; {** Executes an SQL statement that may return multiple results. Under some (uncommon) situations a single SQL statement may return multiple result sets and/or update counts. Normally you can ignore this unless you are (1) executing a stored procedure that you know may return multiple results or (2) you are dynamically executing an unknown SQL string. The methods execute, getMoreResults, getResultSet, and getUpdateCount let you navigate through multiple results. The execute method executes an SQL statement and indicates the form of the first result. You can then use the methods getResultSet or getUpdateCount to retrieve the result, and getMoreResults to move to any subsequent result(s). @param sql any SQL statement @return true if the next result is a ResultSet object; false if it is an update count or there are no more results } function TZSQLiteStatement.Execute(const SQL: RawByteString): Boolean; var ErrorCode: Integer; StmtHandle: Psqlite_vm; ColumnCount: Integer; ColumnValues: PPAnsiChar; ColumnNames: PPAnsiChar; begin ColumnCount := 0; ColumnValues:=nil; ColumnNames:=nil; ASQL := SQL; //preprapares SQL ErrorCode := FPlainDriver.Prepare(FHandle, PAnsiChar(ASQL), Length(ASQL), StmtHandle, nil); CheckSQLiteError(FPlainDriver, FHandle, ErrorCode, nil, lcExecute, SSQL); DriverManager.LogMessage(lcExecute, FPlainDriver.GetProtocol, SSQL); try ErrorCode := FPlainDriver.Step(StmtHandle, ColumnCount, ColumnValues, ColumnNames); CheckSQLiteError(FPlainDriver, FHandle, ErrorCode, nil, lcOther, 'FETCH'); except FPlainDriver.Finalize(StmtHandle); raise; end; { Process queries with result sets } if ColumnCount <> 0 then begin Result := True; LastResultSet := CreateResultSet(SSQL, StmtHandle, ColumnCount, ColumnNames, ColumnValues); end { Processes regular query. } else begin if assigned(ColumnValues) then Freemem(ColumnValues); if assigned(ColumnNames) then Freemem(ColumnNames); Result := False; LastUpdateCount := FPlainDriver.Changes(FHandle); ErrorCode := FPlainDriver.Finalize(StmtHandle); CheckSQLiteError(FPlainDriver, FHandle, ErrorCode, nil, lcOther, 'Finalize SQLite VM'); end; end; {$IFDEF ZEOS_TEST_ONLY} { TZSQLitePreparedStatement } {** Constructs this object and assignes the main properties. @param PlainDriver a native SQLite Plain driver. @param Connection a database connection object. @param Info a statement parameters. @param Handle a connection handle pointer. } constructor TZSQLitePreparedStatement.Create(PlainDriver: IZSQLitePlainDriver; Connection: IZConnection; const SQL: string; Info: TStrings; Handle: Psqlite); begin inherited Create(Connection, SQL, Info); FHandle := Handle; FPlainDriver := PlainDriver; ResultSetType := rtForwardOnly; Prepare; end; {** Creates a temporary statement which executes queries. @param Info a statement parameters. @return a created statement object. } function TZSQLitePreparedStatement.CreateExecStatement: IZStatement; begin Result := TZSQLiteStatement.Create(FPlainDriver, Connection, Info,FHandle); end; {** Prepares an SQL parameter for the query. @param ParameterIndex the first parameter is 1, the second is 2, ... @return a string representation of the parameter. } function TZSQLitePreparedStatement.PrepareAnsiSQLParam(ParamIndex: Integer): RawByteString; var Value: TZVariant; TempBlob: IZBlob; TempBytes: TByteDynArray; begin if InParamCount <= ParamIndex then raise EZSQLException.Create(SInvalidInputParameterCount); Value := InParamValues[ParamIndex]; if DefVarManager.IsNull(Value) then Result := 'NULL' else begin case InParamTypes[ParamIndex] of stBoolean: if SoftVarManager.GetAsBoolean(Value) then Result := '''Y''' else Result := '''N'''; stByte, stShort, stInteger, stLong, stBigDecimal, stFloat, stDouble: Result := RawByteString(SoftVarManager.GetAsString(Value)); stBytes: begin TempBytes := SoftVarManager.GetAsBytes(Value); Result := EncodeString(@TempBytes, Length(TempBytes)); end; stString: Result := ZPlainString(AnsiQuotedStr(SoftVarManager.GetAsString(Value), #39)); stUnicodeString: {$IFDEF UNICODE} Result := ZPlainString(AnsiQuotedStr(SoftVarManager.GetAsUnicodeString(Value), #39)); {$ELSE} Result := AnsiQuotedStr(ZPlainString(SoftVarManager.GetAsUnicodeString(Value)), #39); {$ENDIF} stDate: Result := '''' + RawByteString(FormatDateTime('yyyy-mm-dd', SoftVarManager.GetAsDateTime(Value))) + ''''; stTime: Result := '''' + RawByteString(FormatDateTime('hh:mm:ss', SoftVarManager.GetAsDateTime(Value))) + ''''; stTimestamp: Result := '''' + RawByteString(FormatDateTime('yyyy-mm-dd hh:mm:ss', SoftVarManager.GetAsDateTime(Value))) + ''''; stAsciiStream, stUnicodeStream, stBinaryStream: begin TempBlob := DefVarManager.GetAsInterface(Value) as IZBlob; if not TempBlob.IsEmpty then if InParamTypes[ParamIndex] = stBinaryStream then Result := EncodeString(TempBlob.GetBuffer, TempBlob.Length) else Result := {$IFDEF WITH_UNITANSISTRINGS}AnsiStrings.{$ENDIF}AnsiQuotedStr( GetValidatedAnsiStringFromBuffer(TempBlob.GetBuffer, TempBlob.Length, TempBlob.WasDecoded, ConSettings), #39) else Result := 'NULL'; end; end; end; end; {$ENDIF} procedure BindingDestructor(Value: PAnsiChar); cdecl; begin {$IFDEF WITH_STRDISPOSE_DEPRECATED}AnsiStrings.{$ENDIF}StrDispose(Value); end; { TZSQLiteCAPIPreparedStatement } function TZSQLiteCAPIPreparedStatement.CreateResultSet(const SQL: string; StmtHandle: Psqlite_vm; ColumnCount: Integer; ColumnNames: PPAnsiChar; ColumnValues: PPAnsiChar): IZResultSet; var CachedResolver: TZSQLiteCachedResolver; NativeResultSet: TZSQLiteResultSet; CachedResultSet: TZCachedResultSet; begin { Creates a native result set. } Self.SSQL := SQL; NativeResultSet := TZSQLiteResultSet.Create(FPlainDriver, Self, SSQL, FHandle, StmtHandle, ColumnCount, ColumnNames, ColumnValues, False); NativeResultSet.SetConcurrency(rcReadOnly); { Creates a cached result set. } CachedResolver := TZSQLiteCachedResolver.Create(FPlainDriver, FHandle, Self, NativeResultSet.GetMetaData); CachedResultSet := TZCachedResultSet.Create(NativeResultSet, SSQL, CachedResolver,GetConnection.GetConSettings); { Fetches all rows to prevent blocking. } CachedResultSet.SetType(rtScrollInsensitive); CachedResultSet.Last; CachedResultSet.BeforeFirst; CachedResultSet.SetConcurrency(GetResultSetConcurrency); Result := CachedResultSet; FOpenResultSet := Pointer(Result); end; procedure TZSQLiteCAPIPreparedStatement.SetASQL(const Value: RawByteString); begin if ( ASQL <> Value ) and Prepared then Unprepare; inherited SetASQL(Value); end; procedure TZSQLiteCAPIPreparedStatement.SetWSQL(const Value: ZWideString); begin if ( WSQL <> Value ) and Prepared then Unprepare; inherited SetWSQL(Value); end; procedure TZSQLiteCAPIPreparedStatement.FreeReference; begin FOpenResultSet := nil; end; procedure TZSQLiteCAPIPreparedStatement.PrepareInParameters; begin if FPlainDriver.bind_parameter_count(FStmtHandle) <> InParamCount then raise Exception.Create('Invalid InParamCount'); end; procedure TZSQLiteCAPIPreparedStatement.BindInParameters; var Value: TZVariant; TempBlob: IZBlob; I, L: Integer; TempAnsi: RawByteString; Bts: TByteDynArray; Function AsPAnsiChar(Const S : RawByteString; Len: Integer) : PAnsiChar; begin Result := {$IFDEF UNICODE}AnsiStrAlloc{$ELSE}StrAlloc{$ENDIF}(Len); System.Move(PAnsiChar(S)^, Result^, Len); end; begin FErrorcode := FPlainDriver.clear_bindings(FStmtHandle); CheckSQLiteError(FPlainDriver, FStmtHandle, FErrorCode, nil, lcBindPrepStmt, SSQL); for i := 1 to InParamCount do begin Value := InParamValues[i-1]; if DefVarManager.IsNull(Value) then FErrorcode := FPlainDriver.bind_null(FStmtHandle, I) else begin case InParamTypes[I-1] of stBoolean: if SoftVarManager.GetAsBoolean(Value) then FErrorcode := FPlainDriver.bind_text(FStmtHandle, i, {$IFDEF WITH_STRNEW_DEPRECATED}AnsiStrings.{$ENDIF}StrNew(PAnsiChar(AnsiString('Y'))), 1, @BindingDestructor) else FErrorcode := FPlainDriver.bind_text(FStmtHandle, i, {$IFDEF WITH_STRNEW_DEPRECATED}AnsiStrings.{$ENDIF}StrNew(PAnsichar(AnsiString('N'))), 1, @BindingDestructor); stByte, stShort, stInteger: FErrorcode := FPlainDriver.bind_int(FStmtHandle, i, SoftVarManager.GetAsInteger(Value)); stLong: FErrorcode := FPlainDriver.bind_int64(FStmtHandle, i, SoftVarManager.GetAsInteger(Value)); stBigDecimal, stFloat, stDouble: FErrorcode := FPlainDriver.bind_double(FStmtHandle, i, SoftVarManager.GetAsFloat(Value)); stBytes: begin Bts := SoftVarManager.GetAsBytes(Value); L := Length(Bts); ZSetString(PAnsiChar(Bts), L, TempAnsi); FErrorcode := FPlainDriver.bind_blob(FStmtHandle, i, AsPAnsiChar(TempAnsi, L), L, @BindingDestructor) end; stString: {$IFDEF FPC} //FPC StrNew fails for '' strings and returns nil begin TempAnsi := ZPlainString(SoftVarManager.GetAsString(Value)); if TempAnsi = '' then FErrorcode := FPlainDriver.bind_text(FStmtHandle, i, AsPAnsiChar(TempAnsi, 1), 0, @BindingDestructor) else FErrorcode := FPlainDriver.bind_text(FStmtHandle, i, StrNew(PAnsichar(TempAnsi)), -1, @BindingDestructor); end; {$ELSE} FErrorcode := FPlainDriver.bind_text(FStmtHandle, i, {$IFDEF WITH_STRNEW_DEPRECATED}AnsiStrings.{$ENDIF}StrNew(PAnsichar(ZPlainString(SoftVarManager.GetAsString(Value)))), -1, @BindingDestructor); {$ENDIF} stUnicodeString: {$IFDEF FPC} //FPC StrNew fails for '' strings and returns nil begin TempAnsi := ZPlainString(SoftVarManager.GetAsUnicodeString(Value)); if TempAnsi = '' then FErrorcode := FPlainDriver.bind_text(FStmtHandle, i, AsPAnsiChar(TempAnsi, 1), 0, @BindingDestructor) else FErrorcode := FPlainDriver.bind_text(FStmtHandle, i, StrNew(PAnsichar(TempAnsi)), -1, @BindingDestructor); end; {$ELSE} FErrorcode := FPlainDriver.bind_text(FStmtHandle, i, {$IFDEF WITH_STRNEW_DEPRECATED}AnsiStrings.{$ENDIF}StrNew(PAnsichar(ZPlainString(SoftVarManager.GetAsUnicodeString(Value)))), -1, @BindingDestructor); {$ENDIF} stDate: FErrorcode := FPlainDriver.bind_text(FStmtHandle, i, {$IFDEF WITH_STRNEW_DEPRECATED}AnsiStrings.{$ENDIF}StrNew(PAnsichar(RawByteString(FormatDateTime('yyyy-mm-dd', SoftVarManager.GetAsDateTime(Value))))), 10, @BindingDestructor); stTime: FErrorcode := FPlainDriver.bind_text(FStmtHandle, i, {$IFDEF WITH_STRNEW_DEPRECATED}AnsiStrings.{$ENDIF}StrNew(PAnsichar(RawByteString(FormatDateTime('hh:mm:ss', SoftVarManager.GetAsDateTime(Value))))), 8, @BindingDestructor); stTimestamp: FErrorcode := FPlainDriver.bind_text(FStmtHandle, i, {$IFDEF WITH_STRNEW_DEPRECATED}AnsiStrings.{$ENDIF}StrNew(PAnsichar(RawByteString(FormatDateTime('yyyy-mm-dd hh:mm:ss', SoftVarManager.GetAsDateTime(Value))))), 19, @BindingDestructor); { works equal but selects from data which was written in string format won't match! e.G. TestQuery etc. On the other hand-> i've prepared this case on the resultsets too. JULIAN_DAY_PRECISION?} {stDate, stTime, stTimestamp: FErrorcode := FPlainDriver.bind_double(FStmtHandle, i, SoftVarManager.GetAsDateTime(Value));} stAsciiStream, stUnicodeStream, stBinaryStream: begin TempBlob := DefVarManager.GetAsInterface(Value) as IZBlob; if not TempBlob.IsEmpty then if InParamTypes[I-1] = stBinaryStream then begin TempAnsi := TempBlob.GetString; FErrorcode := FPlainDriver.bind_blob(FStmtHandle, i, AsPAnsiChar(TempAnsi, TempBlob.Length), TempBlob.Length, @BindingDestructor) end else begin TempAnsi := GetValidatedAnsiStringFromBuffer(TempBlob.GetBuffer, TempBlob.Length, TempBlob.WasDecoded, ConSettings); FErrorcode := FPlainDriver.bind_text(FStmtHandle, i, {$IFDEF WITH_STRNEW_DEPRECATED}AnsiStrings.{$ENDIF}StrNew(PAnsiChar(TempAnsi)), Length(TempAnsi), @BindingDestructor); end else FErrorcode := FPlainDriver.bind_null(FStmtHandle, I); end; end; end; CheckSQLiteError(FPlainDriver, FStmtHandle, FErrorCode, nil, lcBindPrepStmt, SSQL); end; end; constructor TZSQLiteCAPIPreparedStatement.Create(PlainDriver: IZSQLitePlainDriver; Connection: IZConnection; const SQL: string; Info: TStrings; Handle: Psqlite); begin inherited Create(Connection, SQL, Info); FHandle := Handle; FPlainDriver := PlainDriver; ResultSetType := rtForwardOnly; end; procedure TZSQLiteCAPIPreparedStatement.Prepare; begin FErrorCode := FPlainDriver.Prepare_v2(FHandle, PAnsiChar(ASQL), Length(ASQL), FStmtHandle, nil); CheckSQLiteError(FPlainDriver, FHandle, FErrorCode, nil, lcPrepStmt, SSQL); inherited Prepare; end; procedure TZSQLiteCAPIPreparedStatement.Unprepare; begin if Assigned(FStmtHandle) then FErrorCode := FPlainDriver.Finalize(FStmtHandle) else FErrorCode := SQLITE_OK; FStmtHandle := nil; CheckSQLiteError(FPlainDriver, FStmtHandle, FErrorCode, nil, lcUnprepStmt, 'Unprepare SQLite Statement'); inherited UnPrepare; end; function TZSQLiteCAPIPreparedStatement.ExecuteQueryPrepared: IZResultSet; var ColumnCount: Integer; ColumnValues: PPAnsiChar; ColumnNames: PPAnsiChar; begin if Not Prepared then Prepare; { after reading the last row we reset the statment. So we don't need this here } ColumnValues := nil; ColumnNames := nil; ColumnCount := 0; try if FOpenResultSet <> nil then IZResultSet(FOpenResultSet).Close; // reset stmt FOpenResultSet := nil; BindInParameters; FErrorCode := FPlainDriver.Step(FStmtHandle, ColumnCount, ColumnValues, ColumnNames); CheckSQLiteError(FPlainDriver, FStmtHandle, FErrorCode, nil, lcOther, SCanNotRetrieveResultsetData); except if ColumnValues <> nil then FreeMem(ColumnValues); ColumnValues := nil; if ColumnNames <> nil then FreeMem(ColumnNames); ColumnNames := nil; raise; end; Result := CreateResultSet(SSQL, FStmtHandle, ColumnCount, ColumnNames, ColumnValues); end; function TZSQLiteCAPIPreparedStatement.ExecuteUpdatePrepared: Integer; begin if Not Prepared then Prepare; BindInParameters; Result := 0; try FErrorCode := FPlainDriver.Step(FStmtHandle); CheckSQLiteError(FPlainDriver, FStmtHandle, FErrorCode, nil, lcExecPrepStmt, SSQL); Result := FPlainDriver.Changes(FHandle); finally FErrorCode := FPlainDriver.reset(FStmtHandle); //no errorcheck! LastUpdateCount := Result; end; { Autocommit statement. } if Connection.GetAutoCommit then Connection.Commit; end; function TZSQLiteCAPIPreparedStatement.ExecutePrepared: Boolean; var ColumnCount: Integer; ColumnValues: PPAnsiChar; ColumnNames: PPAnsiChar; begin if Not Prepared then Prepare; ColumnCount := 0; ColumnValues:=nil; ColumnNames:=nil; try BindInParameters; FErrorCode := FPlainDriver.Step(FStmtHandle, ColumnCount, ColumnValues, ColumnNames); CheckSQLiteError(FPlainDriver, FStmtHandle, FErrorCode, nil, lcExecPrepStmt, 'Step'); except raise; end; { Process queries with result sets } if ColumnCount <> 0 then begin Result := True; LastResultSet := CreateResultSet(SSQL, FStmtHandle, ColumnCount, ColumnNames, ColumnValues); end { Processes regular query. } else begin if assigned(ColumnValues) then Freemem(ColumnValues); if assigned(ColumnNames) then Freemem(ColumnNames); Result := False; LastUpdateCount := FPlainDriver.Changes(FHandle); FErrorCode := FPlainDriver.reset(FStmtHandle); CheckSQLiteError(FPlainDriver, FStmtHandle, FErrorCode, nil, lcOther, 'Reset'); end; { Autocommit statement. } if not Result and Connection.GetAutoCommit then Connection.Commit; inherited ExecutePrepared; end; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcSqLiteUtils.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { SQLite Database Connectivity Classes } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcSqLiteUtils; interface {$I ZDbc.inc} uses Classes, SysUtils, ZSysUtils, ZDbcIntfs, ZPlainSqLiteDriver, ZDbcLogging, ZCompatibility; {** Convert string SQLite field type to SQLType @param string field type value @param Precision the column precision or size @param Decimals the column position after decimal point @result the SQLType field type value } function ConvertSQLiteTypeToSQLType(TypeName: string; var Precision: Integer; var Decimals: Integer; const CtrlsCPType: TZControlsCodePage): TZSQLType; {** Checks for possible sql errors. @param PlainDriver a SQLite plain driver. @param ErrorCode an error code. @param ErrorMessage an error message. @param LogCategory a logging category. @param LogMessage a logging message. } procedure CheckSQLiteError(PlainDriver: IZSQLitePlainDriver; Handle: PSqlite; ErrorCode: Integer; ErrorMessage: PAnsiChar; LogCategory: TZLoggingCategory; LogMessage: string); {** Converts an string into escape PostgreSQL format. @param Value a regular string. @return a string in PostgreSQL escape format. } function EncodeString(Buffer: PAnsiChar; Len: Integer): RawByteString; overload; function EncodeString(Value: RawByteString): RawByteString; overload; {** Converts an string from escape PostgreSQL format. @param Value a string in PostgreSQL escape format. @return a regular string. } function DecodeString(Value: ansistring): ansistring; {** Decodes a SQLite Version Value and Encodes it to a Zeos SQL Version format: (major_version * 1,000,000) + (minor_version * 1,000) + sub_version into separated major, minor and subversion values @param SQLiteVersion an integer containing the Full Version to decode. @return Encoded Zeos SQL Version Value. } function ConvertSQLiteVersionToSQLVersion( const SQLiteVersion: PAnsiChar ): Integer; implementation uses ZMessages{$IFDEF WITH_UNITANSISTRINGS}, AnsiStrings{$ENDIF}; {** Convert string SQLite field type to SQLType @param string field type value @param Precision the column precision or size @param Decimals the column position after decimal point @result the SQLType field type value } function ConvertSQLiteTypeToSQLType(TypeName: string; var Precision: Integer; var Decimals: Integer; const CtrlsCPType: TZControlsCodePage): TZSQLType; var P1, P2: Integer; Temp: string; begin TypeName := UpperCase(TypeName); Result := stString; Precision := 0; Decimals := 0; P1 := Pos('(', TypeName); P2 := Pos(')', TypeName); if (P1 > 0) and (P2 > 0) then begin Temp := Copy(TypeName, P1 + 1, P2 - P1 - 1); TypeName := Copy(TypeName, 1, P1 - 1); P1 := Pos(',', Temp); if P1 > 0 then begin Precision := StrToIntDef(Copy(Temp, 1, P1 - 1), 0); Decimals := StrToIntDef(Copy(Temp, P1 + 1, Length(Temp) - P1), 0); end else Precision := StrToIntDef(Temp, 0); end; if StartsWith(TypeName, 'BOOL') then Result := stBoolean else if TypeName = 'TINYINT' then Result := stShort else if TypeName = 'SMALLINT' then Result := stShort else if TypeName = 'MEDIUMINT' then Result := stInteger else if TypeName = {$IFDEF UNICODE}RawByteString{$ENDIF}('INTEGER') then Result := stLong //http://www.sqlite.org/autoinc.html else if StartsWith(TypeName, {$IFDEF UNICODE}RawByteString{$ENDIF}('INT')) then Result := stInteger else if TypeName = 'BIGINT' then Result := stLong else if StartsWith(TypeName, 'REAL') then Result := stDouble else if StartsWith(TypeName, 'FLOAT') then Result := stDouble else if (TypeName = 'NUMERIC') or (TypeName = 'DECIMAL') or (TypeName = 'NUMBER') then begin { if Decimals = 0 then Result := stInteger else} Result := stDouble; end else if StartsWith(TypeName, 'DOUB') then Result := stDouble else if TypeName = 'MONEY' then Result := stBigDecimal else if StartsWith(TypeName, 'CHAR') then Result := stString else if TypeName = 'VARCHAR' then Result := stString else if TypeName = 'VARBINARY' then Result := stBytes else if TypeName = 'BINARY' then Result := stBytes else if TypeName = 'DATE' then Result := stDate else if TypeName = 'TIME' then Result := stTime else if TypeName = 'TIMESTAMP' then Result := stTimestamp else if TypeName = 'DATETIME' then Result := stTimestamp else if Pos('BLOB', TypeName) > 0 then Result := stBinaryStream else if Pos('CLOB', TypeName) > 0 then Result := stAsciiStream else if Pos('TEXT', TypeName) > 0 then Result := stAsciiStream; if (Result = stInteger) and (Precision <> 0) then begin if Precision <= 2 then Result := stByte else if Precision <= 4 then Result := stShort else if Precision <= 9 then Result := stInteger else Result := stLong; end; if ( CtrlsCPType = cCP_UTF16 ) then case Result of stString: Result := stUnicodeString; stAsciiStream: Result := stUnicodeStream; end; if (Result = stString) then if (Precision = 0) then Precision := 255 *{$IFDEF UNICODE}2{$ELSE}4{$ENDIF}//UTF8 assumes 4Byte/Char else Precision := Precision*{$IFDEF UNICODE}2{$ELSE}4{$ENDIF};//UTF8 assumes 4Byte/Char if (Result = stUnicodeString) then if (Precision = 0) then Precision := 255 * 2 //UTF8 assumes 4Byte/Char -> 2 * UnicodeChar else Precision := Precision * 2;//UTF8 assumes 4Byte/Char end; {** Checks for possible sql errors. @param PlainDriver a SQLite plain driver. @param ErrorCode an error code. @param ErrorMessage an error message. @param LogCategory a logging category. @param LogMessage a logging message. } procedure CheckSQLiteError(PlainDriver: IZSQLitePlainDriver; Handle: PSqlite; ErrorCode: Integer; ErrorMessage: PAnsiChar; LogCategory: TZLoggingCategory; LogMessage: string); var Error: string; begin if ErrorMessage <> nil then begin {$IFDEF UNICODE} Error := trim(UTF8ToUnicodeString(ErrorMessage)); {$ELSE} {$IFNDEF FPC} Error := Trim(UTF8ToAnsi(StrPas(ErrorMessage))); {$ELSE} Error := Trim(StrPas(ErrorMessage)); {$ENDIF} {$ENDIF} PlainDriver.FreeMem(ErrorMessage); end else Error := ''; if not (ErrorCode in [SQLITE_OK, SQLITE_ROW, SQLITE_DONE]) then begin if Error = '' then Error := PlainDriver.ErrorString(Handle, ErrorCode); DriverManager.LogError(LogCategory, PlainDriver.GetProtocol, LogMessage, ErrorCode, Error); raise EZSQLException.CreateWithCode(ErrorCode, Format(SSQLError1, [Error])); end; end; function NewEncodeString(Buffer: PAnsiChar; Len: Integer): RawByteString; overload; var I: Integer; ihx : integer; shx : ansistring; begin SetLength( Result,3 + Len * 2 ); Result[1] := 'x'; // set x Result[2] := ''''; // set Open Quote ihx := 3; // set 1st hex location for I := 1 to Len do begin shx := AnsiString(IntToHex( ord(Buffer^),2 )); // eg. '3E' result[ihx] := shx[1]; Inc( ihx,1 ); // copy '3' result[ihx] := shx[2]; Inc( ihx,1 ); // copy 'E' Inc( Buffer,1 ); // next byte source location end; result[ihx] := ''''; // set Close Quote end; function NewEncodeString(Value: RawByteString): RawByteString; overload; begin Result := NewEncodeString(PAnsiChar(Value), Length(Value)); end; function NewDecodeString(Value:ansistring):ansistring; var i : integer; srcbuffer : PAnsichar; begin value := copy(value,3,length(value)-4); value := {$IFDEF WITH_UNITANSISTRINGS}AnsiStrings.{$ENDIF}AnsiLowercase(value); i := length(value) div 2; srcbuffer := PAnsiChar(value); setlength(result,i); HexToBin(PAnsiChar(srcbuffer),PAnsiChar(result),i); end; {** Converts an string into escape PostgreSQL format. @param Value a regular string. @return a string in PostgreSQL escape format. } function EncodeString(Buffer: PAnsiChar; Len: Integer): RawByteString; overload; begin result := NewEncodeString(Buffer, Len); end; function EncodeString(Value: RawByteString): RawByteString; overload; begin result := NewEncodeString(Value); end; {** Converts an string from escape PostgreSQL format. @param Value a string in PostgreSQL escape format. @return a regular string. } function DecodeString(Value: ansistring): ansistring; var SrcLength, DestLength: Integer; SrcBuffer, DestBuffer: PAnsiChar; begin if pos('x''',String(value))= 1 then result := NewDecodeString(value) else begin SrcLength := Length(Value); SrcBuffer := PAnsiChar(Value); SetLength(Result, SrcLength); DestLength := 0; DestBuffer := PAnsiChar(Result); while SrcLength > 0 do begin if SrcBuffer^ = '%' then begin Inc(SrcBuffer); if SrcBuffer^ <> '0' then DestBuffer^ := SrcBuffer^ else DestBuffer^ := #0; Inc(SrcBuffer); Dec(SrcLength, 2); end else begin DestBuffer^ := SrcBuffer^; Inc(SrcBuffer); Dec(SrcLength); end; Inc(DestBuffer); Inc(DestLength); end; SetLength(Result, DestLength); end; end; {** Decodes a SQLite Version Value and Encodes it to a Zeos SQL Version format: (major_version * 1,000,000) + (minor_version * 1,000) + sub_version into separated major, minor and subversion values @param SQLiteVersion an integer containing the Full Version to decode. @return Encoded Zeos SQL Version Value. } function ConvertSQLiteVersionToSQLVersion( const SQLiteVersion: PAnsiChar ): Integer; var MajorVersion, MinorVersion, SubVersion: Integer; s:string; begin s:=String(SQLiteVersion); MajorVersion:=StrToIntDef(copy(s,1,pos('.',s)-1),0); delete(s,1,pos('.',s)); MinorVersion:=StrToIntDef(copy(s,1,pos('.',s)-1),0); delete(s,1,pos('.',s)); SubVersion:=StrToIntDef(s,0); Result := EncodeSQLVersioning(MajorVersion,MinorVersion,SubVersion); end; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcStatement.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Abstract Database Connectivity Classes } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcStatement; interface {$I ZDbc.inc} uses Types, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, ZDbcIntfs, ZTokenizer, ZCompatibility, ZVariant, ZDbcLogging, ZClasses, ZPlainDriver; type TZSQLTypeArray = array of TZSQLType; {** Implements Abstract Generic SQL Statement. } { TZAbstractStatement } TZAbstractStatement = class(TZCodePagedObject, IZStatement) private FMaxFieldSize: Integer; FMaxRows: Integer; FEscapeProcessing: Boolean; FQueryTimeout: Integer; FLastUpdateCount: Integer; FLastResultSet: IZResultSet; FFetchDirection: TZFetchDirection; FFetchSize: Integer; FResultSetConcurrency: TZResultSetConcurrency; FResultSetType: TZResultSetType; FPostUpdates: TZPostUpdatesMode; FLocateUpdates: TZLocateUpdatesMode; FCursorName: AnsiString; FBatchQueries: TStrings; FConnection: IZConnection; FInfo: TStrings; FChunkSize: Integer; //size of buffer chunks for large lob's related to network settings FClosed: Boolean; FWSQL: ZWideString; FaSQL: RawByteString; FIsAnsiDriver: Boolean; procedure SetLastResultSet(ResultSet: IZResultSet); virtual; protected procedure SetASQL(const Value: RawByteString); virtual; procedure SetWSQL(const Value: ZWideString); virtual; class function GetNextStatementId : integer; procedure RaiseUnsupportedException; property MaxFieldSize: Integer read FMaxFieldSize write FMaxFieldSize; property MaxRows: Integer read FMaxRows write FMaxRows; property EscapeProcessing: Boolean read FEscapeProcessing write FEscapeProcessing; property QueryTimeout: Integer read FQueryTimeout write FQueryTimeout; property LastUpdateCount: Integer read FLastUpdateCount write FLastUpdateCount; property LastResultSet: IZResultSet read FLastResultSet write SetLastResultSet; property FetchDirection: TZFetchDirection read FFetchDirection write FFetchDirection; property FetchSize: Integer read FFetchSize write FFetchSize; property ResultSetConcurrency: TZResultSetConcurrency read FResultSetConcurrency write FResultSetConcurrency; property ResultSetType: TZResultSetType read FResultSetType write FResultSetType; property CursorName: AnsiString read FCursorName write FCursorName; property BatchQueries: TStrings read FBatchQueries; property Connection: IZConnection read FConnection; property Info: TStrings read FInfo; property Closed: Boolean read FClosed write FClosed; {EgonHugeist SSQL only because of compatibility to the old code available} property SSQL: {$IF defined(FPC) and defined(WITH_RAWBYTESTRING)}RawByteString{$ELSE}String{$IFEND} read {$IFDEF UNICODE}FWSQL{$ELSE}FaSQL{$ENDIF} write {$IFDEF UNICODE}SetWSQL{$ELSE}SetASQL{$ENDIF}; property WSQL: ZWideString read FWSQL write SetWSQL; property ASQL: RawByteString read FaSQL write SetASQL; property LogSQL: String read {$IFDEF UNICODE}FWSQL{$ELSE}FaSQL{$ENDIF}; property ChunkSize: Integer read FChunkSize; property IsAnsiDriver: Boolean read FIsAnsiDriver; public constructor Create(Connection: IZConnection; Info: TStrings); destructor Destroy; override; function ExecuteQuery(const SQL: ZWideString): IZResultSet; overload; virtual; function ExecuteUpdate(const SQL: ZWideString): Integer; overload; virtual; function Execute(const SQL: ZWideString): Boolean; overload; virtual; function ExecuteQuery(const SQL: RawByteString): IZResultSet; overload; virtual; function ExecuteUpdate(const SQL: RawByteString): Integer; overload; virtual; function Execute(const SQL: RawByteString): Boolean; overload; virtual; procedure Close; virtual; function GetMaxFieldSize: Integer; virtual; procedure SetMaxFieldSize(Value: Integer); virtual; function GetMaxRows: Integer; virtual; procedure SetMaxRows(Value: Integer); virtual; procedure SetEscapeProcessing(Value: Boolean); virtual; function GetQueryTimeout: Integer; virtual; procedure SetQueryTimeout(Value: Integer); virtual; procedure Cancel; virtual; procedure SetCursorName(const Value: AnsiString); virtual; function GetResultSet: IZResultSet; virtual; function GetUpdateCount: Integer; virtual; function GetMoreResults: Boolean; virtual; procedure SetFetchDirection(Value: TZFetchDirection); virtual; function GetFetchDirection: TZFetchDirection; virtual; procedure SetFetchSize(Value: Integer); virtual; function GetFetchSize: Integer; virtual; procedure SetResultSetConcurrency(Value: TZResultSetConcurrency); virtual; function GetResultSetConcurrency: TZResultSetConcurrency; virtual; procedure SetResultSetType(Value: TZResultSetType); virtual; function GetResultSetType: TZResultSetType; virtual; procedure SetPostUpdates(Value: TZPostUpdatesMode); function GetPostUpdates: TZPostUpdatesMode; procedure SetLocateUpdates(Value: TZLocateUpdatesMode); function GetLocateUpdates: TZLocateUpdatesMode; procedure AddBatch(const SQL: string); virtual; procedure ClearBatch; virtual; function ExecuteBatch: TIntegerDynArray; virtual; function GetConnection: IZConnection; function GetParameters: TStrings; function GetChunkSize: Integer; function GetWarnings: EZSQLWarning; virtual; procedure ClearWarnings; virtual; function GetEncodedSQL(const SQL: {$IF defined(FPC) and defined(WITH_RAWBYTESTRING)}RawByteString{$ELSE}String{$IFEND}): RawByteString; virtual; end; {** Implements Abstract Prepared SQL Statement. } { TZAbstractPreparedStatement } TZAbstractPreparedStatement = class(TZAbstractStatement, IZPreparedStatement) private FSQL: string; FInParamValues: TZVariantDynArray; FInParamTypes: TZSQLTypeArray; FInParamDefaultValues: TStringDynArray; FInParamCount: Integer; FPrepared : Boolean; FExecCount: Integer; protected FStatementId : Integer; procedure PrepareInParameters; virtual; procedure BindInParameters; virtual; procedure UnPrepareInParameters; virtual; procedure SetInParamCount(NewParamCount: Integer); virtual; procedure SetInParam(ParameterIndex: Integer; SQLType: TZSQLType; const Value: TZVariant); virtual; procedure LogPrepStmtMessage(Category: TZLoggingCategory; const Msg: string = ''); function GetInParamLogValue(Value: TZVariant): String; property ExecCount: Integer read FExecCount; property SQL: string read FSQL write FSQL; property InParamValues: TZVariantDynArray read FInParamValues write FInParamValues; property InParamTypes: TZSQLTypeArray read FInParamTypes write FInParamTypes; property InParamDefaultValues: TStringDynArray read FInParamDefaultValues write FInParamDefaultValues; property InParamCount: Integer read FInParamCount write FInParamCount; public constructor Create(Connection: IZConnection; const SQL: string; Info: TStrings); destructor Destroy; override; function ExecuteQuery(const SQL: ZWideString): IZResultSet; override; function ExecuteUpdate(const SQL: ZWideString): Integer; override; function Execute(const SQL: ZWideString): Boolean; override; function ExecuteQuery(const SQL: RawByteString): IZResultSet; override; function ExecuteUpdate(const SQL: RawByteString): Integer; override; function Execute(const SQL: RawByteString): Boolean; override; function ExecuteQueryPrepared: IZResultSet; virtual; function ExecuteUpdatePrepared: Integer; virtual; function ExecutePrepared: Boolean; virtual; function GetSQL : String; procedure Prepare; virtual; procedure Unprepare; virtual; function IsPrepared: Boolean; virtual; property Prepared: Boolean read IsPrepared; procedure SetDefaultValue(ParameterIndex: Integer; const Value: string); procedure SetNull(ParameterIndex: Integer; SQLType: TZSQLType); virtual; procedure SetBoolean(ParameterIndex: Integer; Value: Boolean); virtual; procedure SetByte(ParameterIndex: Integer; Value: Byte); virtual; procedure SetShort(ParameterIndex: Integer; Value: SmallInt); virtual; procedure SetInt(ParameterIndex: Integer; Value: Integer); virtual; procedure SetLong(ParameterIndex: Integer; Value: Int64); virtual; procedure SetFloat(ParameterIndex: Integer; Value: Single); virtual; procedure SetDouble(ParameterIndex: Integer; Value: Double); virtual; procedure SetBigDecimal(ParameterIndex: Integer; Value: Extended); virtual; procedure SetPChar(ParameterIndex: Integer; Value: PChar); virtual; procedure SetString(ParameterIndex: Integer; const Value: String); virtual; procedure SetUnicodeString(ParameterIndex: Integer; const Value: ZWideString); virtual; //AVZ procedure SetBytes(ParameterIndex: Integer; const Value: TByteDynArray); virtual; procedure SetDate(ParameterIndex: Integer; Value: TDateTime); virtual; procedure SetTime(ParameterIndex: Integer; Value: TDateTime); virtual; procedure SetTimestamp(ParameterIndex: Integer; Value: TDateTime); virtual; procedure SetAsciiStream(ParameterIndex: Integer; Value: TStream); virtual; procedure SetUnicodeStream(ParameterIndex: Integer; Value: TStream); virtual; procedure SetBinaryStream(ParameterIndex: Integer; Value: TStream); virtual; procedure SetBlob(ParameterIndex: Integer; SQLType: TZSQLType; Value: IZBlob); virtual; procedure SetValue(ParameterIndex: Integer; const Value: TZVariant); virtual; procedure ClearParameters; virtual; procedure AddBatchPrepared; virtual; function GetMetaData: IZResultSetMetaData; virtual; end; {** Implements Abstract Callable SQL statement. } TZAbstractCallableStatement = class(TZAbstractPreparedStatement, IZCallableStatement) private FOutParamValues: TZVariantDynArray; FOutParamTypes: TZSQLTypeArray; FOutParamCount: Integer; FLastWasNull: Boolean; FTemp: String; FProcSql: String; FIsFunction: Boolean; FHasOutParameter: Boolean; protected FResultSets: IZCollection; FActiveResultset: Integer; FDBParamTypes: array of ShortInt; procedure ClearResultSets; virtual; procedure TrimInParameters; virtual; procedure SetOutParamCount(NewParamCount: Integer); virtual; function GetOutParam(ParameterIndex: Integer): TZVariant; virtual; procedure SetProcSQL(const Value: String); virtual; property OutParamValues: TZVariantDynArray read FOutParamValues write FOutParamValues; property OutParamTypes: TZSQLTypeArray read FOutParamTypes write FOutParamTypes; property OutParamCount: Integer read FOutParamCount write FOutParamCount; property LastWasNull: Boolean read FLastWasNull write FLastWasNull; property ProcSql: String read FProcSQL write SetProcSQL; public constructor Create(Connection: IZConnection; SQL: string; Info: TStrings); procedure ClearParameters; override; procedure Close; override; function IsFunction: Boolean; function HasOutParameter: Boolean; function HasMoreResultSets: Boolean; virtual; function GetFirstResultSet: IZResultSet; virtual; function GetPreviousResultSet: IZResultSet; virtual; function GetNextResultSet: IZResultSet; virtual; function GetLastResultSet: IZResultSet; virtual; function BOR: Boolean; virtual; function EOR: Boolean; virtual; function GetResultSetByIndex(const Index: Integer): IZResultSet; virtual; function GetResultSetCount: Integer; virtual; procedure RegisterOutParameter(ParameterIndex: Integer; SQLType: Integer); virtual; procedure RegisterParamType(ParameterIndex:integer;ParamType:Integer);virtual; function WasNull: Boolean; virtual; function IsNull(ParameterIndex: Integer): Boolean; virtual; function GetPChar(ParameterIndex: Integer): PChar; virtual; function GetString(ParameterIndex: Integer): String; virtual; function GetUnicodeString(ParameterIndex: Integer): WideString; virtual; function GetBoolean(ParameterIndex: Integer): Boolean; virtual; function GetByte(ParameterIndex: Integer): Byte; virtual; function GetShort(ParameterIndex: Integer): SmallInt; virtual; function GetInt(ParameterIndex: Integer): Integer; virtual; function GetLong(ParameterIndex: Integer): Int64; virtual; function GetFloat(ParameterIndex: Integer): Single; virtual; function GetDouble(ParameterIndex: Integer): Double; virtual; function GetBigDecimal(ParameterIndex: Integer): Extended; virtual; function GetBytes(ParameterIndex: Integer): TByteDynArray; virtual; function GetDate(ParameterIndex: Integer): TDateTime; virtual; function GetTime(ParameterIndex: Integer): TDateTime; virtual; function GetTimestamp(ParameterIndex: Integer): TDateTime; virtual; function GetValue(ParameterIndex: Integer): TZVariant; virtual; end; {** Implements a real Prepared Callable SQL Statement. } TZAbstractPreparedCallableStatement = CLass(TZAbstractCallableStatement) protected procedure SetProcSQL(const Value: String); override; public function ExecuteQuery(const SQL: ZWideString): IZResultSet; override; function ExecuteQuery(const SQL: RawByteString): IZResultSet; override; function ExecuteUpdate(const SQL: ZWideString): Integer; override; function ExecuteUpdate(const SQL: RawByteString): Integer; override; function Execute(const SQL: ZWideString): Boolean; override; function Execute(const SQL: RawByteString): Boolean; override; end; {** Implements an Emulated Prepared SQL Statement. } TZEmulatedPreparedStatement = class(TZAbstractPreparedStatement) private FExecStatement: IZStatement; FCachedQuery: TStrings; FLastStatement: IZStatement; procedure SetLastStatement(LastStatement: IZStatement); protected FNeedNCharDetection: Boolean; property ExecStatement: IZStatement read FExecStatement write FExecStatement; property CachedQuery: TStrings read FCachedQuery write FCachedQuery; property LastStatement: IZStatement read FLastStatement write SetLastStatement; function CreateExecStatement: IZStatement; virtual; abstract; function PrepareWideSQLParam(ParamIndex: Integer): ZWideString; virtual; function PrepareAnsiSQLParam(ParamIndex: Integer): RawByteString; virtual; function GetExecStatement: IZStatement; function TokenizeSQLQuery: TStrings; function PrepareWideSQLQuery: ZWideString; virtual; function PrepareAnsiSQLQuery: RawByteString; virtual; public destructor Destroy; override; procedure Close; override; function ExecuteQuery(const SQL: ZWideString): IZResultSet; override; function ExecuteQuery(const SQL: RawByteString): IZResultSet; override; function ExecuteUpdate(const SQL: ZWideString): Integer; override; function ExecuteUpdate(const SQL: RawByteString): Integer; override; function Execute(const SQL: ZWideString): Boolean; override; function Execute(const SQL: RawByteString): Boolean; override; function ExecuteQueryPrepared: IZResultSet; override; function ExecuteUpdatePrepared: Integer; override; function ExecutePrepared: Boolean; override; end; implementation uses ZSysUtils, ZMessages, ZDbcResultSet, ZCollections; var {** Holds the value of the last assigned statement ID. Only Accessible using TZAbstractStatement.GetNextStatementId. } GlobalStatementIdCounter : integer; { TZAbstractStatement } {** Constructs this class and defines the main properties. @param Connection a database connection object. @param Info a statement parameters; } constructor TZAbstractStatement.Create(Connection: IZConnection; Info: TStrings); begin { Sets the default properties. } inherited Create; ConSettings := Connection.GetConSettings; FMaxFieldSize := 0; FMaxRows := 0; FEscapeProcessing := False; FQueryTimeout := 0; FLastUpdateCount := -1; FLastResultSet := nil; FFetchDirection := fdForward; FFetchSize := 0; FResultSetConcurrency := rcReadOnly; FResultSetType := rtForwardOnly; FCursorName := ''; FConnection := Connection; FBatchQueries := TStringList.Create; FInfo := TStringList.Create; if Info <> nil then FInfo.AddStrings(Info); if FInfo.Values['chunk_size'] = '' then FChunkSize := StrToIntDef(Connection.GetParameters.Values['chunk_size'], 4096) else FChunkSize := StrToIntDef(FInfo.Values['chunk_size'], 4096); FIsAnsiDriver := Connection.GetIZPlainDriver.IsAnsiDriver; end; {** Destroys this object and cleanups the memory. } destructor TZAbstractStatement.Destroy; begin Close; if Assigned(FBatchQueries) then FreeAndNil(FBatchQueries); FConnection := nil; FreeAndNil(FInfo); FLastResultSet := nil; inherited Destroy; end; {** Sets the preprepared SQL-Statement in an String and AnsiStringForm. @param Value: the SQL-String which has to be optional preprepared } procedure TZAbstractStatement.SetWSQL(const Value: ZWideString); begin if FWSQL <> Value then begin {$IFDEF UNICODE} FaSQL := GetEncodedSQL(Value); {$ELSE} FaSQL := ZPlainString(Value); {$ENDIF} FWSQL := ZDbcUnicodeString(FASQL, ConSettings^.ClientCodePage^.CP);; end; end; procedure TZAbstractStatement.SetASQL(const Value: RawByteString); begin if FASQL <> Value then begin {$IFNDEF UNICODE} FASQL := GetEncodedSQL(Value); FWSQL := ZDbcUnicodeString(FASQL, ConSettings^.ClientCodePage^.CP); {$else} FASQL := Value; FWSQL := ZDbcString(Value); {$ENDIF} end; end; {** Raises unsupported operation exception. } procedure TZAbstractStatement.RaiseUnsupportedException; begin raise EZSQLException.Create(SUnsupportedOperation); end; {** Sets a last result set to avoid problems with reference counting. @param ResultSet the lastest executed result set. } procedure TZAbstractStatement.SetLastResultSet(ResultSet: IZResultSet); begin if (FLastResultSet <> nil) then FLastResultSet.Close; FLastResultSet := ResultSet; end; class function TZAbstractStatement.GetNextStatementId: integer; begin Inc(GlobalStatementIdCounter); Result := GlobalStatementIdCounter; end; {** Executes an SQL statement that returns a single ResultSet object. @param sql typically this is a static SQL SELECT statement @return a ResultSet object that contains the data produced by the given query; never null } function TZAbstractStatement.ExecuteQuery(const SQL: ZWideString): IZResultSet; begin WSQL := SQL; Result := ExecuteQuery(ASQL); end; function TZAbstractStatement.ExecuteQuery(const SQL: RawByteString): IZResultSet; begin Result := nil; RaiseUnsupportedException; end; {** Executes an SQL INSERT, UPDATE or DELETE statement. In addition, SQL statements that return nothing, such as SQL DDL statements, can be executed. @param sql an SQL INSERT, UPDATE or DELETE statement or an SQL statement that returns nothing @return either the row count for INSERT, UPDATE or DELETE statements, or 0 for SQL statements that return nothing } function TZAbstractStatement.ExecuteUpdate(const SQL: ZWideString): Integer; begin WSQL := SQL; Result := ExecuteUpdate(ASQL); end; function TZAbstractStatement.ExecuteUpdate(const SQL: RawByteString): Integer; begin Result := 0; RaiseUnsupportedException; end; {** Releases this Statement object's database and JDBC resources immediately instead of waiting for this to happen when it is automatically closed. It is generally good practice to release resources as soon as you are finished with them to avoid tying up database resources.

Note: A Statement object is automatically closed when it is garbage collected. When a Statement object is closed, its current ResultSet object, if one exists, is also closed. } procedure TZAbstractStatement.Close; begin if LastResultSet <> nil then begin LastResultSet.Close; LastResultSet := nil; end; FClosed := True; end; {** Returns the maximum number of bytes allowed for any column value. This limit is the maximum number of bytes that can be returned for any column value. The limit applies only to BINARY, VARBINARY, LONGVARBINARY, CHAR, VARCHAR, and LONGVARCHAR columns. If the limit is exceeded, the excess data is silently discarded. @return the current max column size limit; zero means unlimited } function TZAbstractStatement.GetMaxFieldSize: Integer; begin Result := FMaxFieldSize; end; {** Sets the limit for the maximum number of bytes in a column to the given number of bytes. This is the maximum number of bytes that can be returned for any column value. This limit applies only to BINARY, VARBINARY, LONGVARBINARY, CHAR, VARCHAR, and LONGVARCHAR fields. If the limit is exceeded, the excess data is silently discarded. For maximum portability, use values greater than 256. @param max the new max column size limit; zero means unlimited } procedure TZAbstractStatement.SetMaxFieldSize(Value: Integer); begin FMaxFieldSize := Value; end; {** Retrieves the maximum number of rows that a ResultSet object can contain. If the limit is exceeded, the excess rows are silently dropped. @return the current max row limit; zero means unlimited } function TZAbstractStatement.GetMaxRows: Integer; begin Result := FMaxRows; end; {** Sets the limit for the maximum number of rows that any ResultSet object can contain to the given number. If the limit is exceeded, the excess rows are silently dropped. @param max the new max rows limit; zero means unlimited } procedure TZAbstractStatement.SetMaxRows(Value: Integer); begin FMaxRows := Value; end; {** Sets escape processing on or off. If escape scanning is on (the default), the driver will do escape substitution before sending the SQL to the database. Note: Since prepared statements have usually been parsed prior to making this call, disabling escape processing for prepared statements will have no effect. @param enable true to enable; false to disable } procedure TZAbstractStatement.SetEscapeProcessing(Value: Boolean); begin FEscapeProcessing := Value; end; {** Retrieves the number of seconds the driver will wait for a Statement object to execute. If the limit is exceeded, a SQLException is thrown. @return the current query timeout limit in seconds; zero means unlimited } function TZAbstractStatement.GetQueryTimeout: Integer; begin Result := FQueryTimeout; end; {** Sets the number of seconds the driver will wait for a Statement object to execute to the given number of seconds. If the limit is exceeded, an SQLException is thrown. @param seconds the new query timeout limit in seconds; zero means unlimited } procedure TZAbstractStatement.SetQueryTimeout(Value: Integer); begin FQueryTimeout := Value; end; {** Cancels this Statement object if both the DBMS and driver support aborting an SQL statement. This method can be used by one thread to cancel a statement that is being executed by another thread. } procedure TZAbstractStatement.Cancel; begin RaiseUnsupportedException; end; {** Retrieves the first warning reported by calls on this Statement object. Subsequent Statement object warnings will be chained to this SQLWarning object.

The warning chain is automatically cleared each time a statement is (re)executed.

Note: If you are processing a ResultSet object, any warnings associated with reads on that ResultSet object will be chained on it. @return the first SQLWarning object or null } function TZAbstractStatement.GetWarnings: EZSQLWarning; begin Result := nil; end; {** Clears all the warnings reported on this Statement object. After a call to this method, the method getWarnings will return null until a new warning is reported for this Statement object. } procedure TZAbstractStatement.ClearWarnings; begin end; function TZAbstractStatement.GetEncodedSQL(const SQL: {$IF defined(FPC) and defined(WITH_RAWBYTESTRING)}RawByteString{$ELSE}String{$IFEND}): RawByteString; var SQLTokens: TZTokenDynArray; i: Integer; begin if GetConnection.AutoEncodeStrings then begin Result := ''; //init for FPC SQLTokens := GetConnection.GetDriver.GetTokenizer.TokenizeBuffer(SQL, [toSkipEOF]); //Disassembles the Query for i := Low(SQLTokens) to high(SQLTokens) do //Assembles the Query begin case (SQLTokens[i].TokenType) of ttEscape: Result := Result + {$IFDEF UNICODE}ZPlainString{$ENDIF}(SQLTokens[i].Value); ttQuoted, ttComment, ttWord, ttQuotedIdentifier, ttKeyword: Result := Result + ZPlainString(SQLTokens[i].Value); else Result := Result + RawByteString(SQLTokens[i].Value); end; end; end else {$IFDEF UNICODE} Result := ZPlainString(SQL); {$ELSE} Result := SQL; {$ENDIF} end; {** Defines the SQL cursor name that will be used by subsequent Statement object execute methods. This name can then be used in SQL positioned update/delete statements to identify the current row in the ResultSet object generated by this statement. If the database doesn't support positioned update/delete, this method is a noop. To insure that a cursor has the proper isolation level to support updates, the cursor's SELECT statement should be of the form 'select for update ...'. If the 'for update' phrase is omitted, positioned updates may fail.

Note: By definition, positioned update/delete execution must be done by a different Statement object than the one which generated the ResultSet object being used for positioning. Also, cursor names must be unique within a connection. @param name the new cursor name, which must be unique within a connection } procedure TZAbstractStatement.SetCursorName(const Value: AnsiString); begin FCursorName := Value; end; {** Executes an SQL statement that may return multiple results. Under some (uncommon) situations a single SQL statement may return multiple result sets and/or update counts. Normally you can ignore this unless you are (1) executing a stored procedure that you know may return multiple results or (2) you are dynamically executing an unknown SQL string. The methods execute, getMoreResults, getResultSet, and getUpdateCount let you navigate through multiple results. The execute method executes an SQL statement and indicates the form of the first result. You can then use the methods getResultSet or getUpdateCount to retrieve the result, and getMoreResults to move to any subsequent result(s). @param sql any SQL statement @return true if the next result is a ResultSet object; false if it is an update count or there are no more results @see #getResultSet @see #getUpdateCount @see #getMoreResults } function TZAbstractStatement.Execute(const SQL: ZWideString): Boolean; begin WSQL := SQL; Result := Execute(ASQL); end; function TZAbstractStatement.Execute(const SQL: RawByteString): Boolean; begin Result := False; LastResultSet := nil; LastUpdateCount := -1; end; {** Returns the current result as a ResultSet object. This method should be called only once per result. @return the current result as a ResultSet object; null if the result is an update count or there are no more results @see #execute } function TZAbstractStatement.GetResultSet: IZResultSet; begin Result := LastResultSet; end; {** Returns the current result as an update count; if the result is a ResultSet object or there are no more results, -1 is returned. This method should be called only once per result. @return the current result as an update count; -1 if the current result is a ResultSet object or there are no more results @see #execute } function TZAbstractStatement.GetUpdateCount: Integer; begin Result := FLastUpdateCount; end; {** Moves to a Statement object's next result. It returns true if this result is a ResultSet object. This method also implicitly closes any current ResultSet object obtained with the method getResultSet.

There are no more results when the following is true:

        (!getMoreResults() && (getUpdateCount() == -1)
  
@return true if the next result is a ResultSet object; false if it is an update count or there are no more results @see #execute } function TZAbstractStatement.GetMoreResults: Boolean; begin Result := False; end; {** Retrieves the direction for fetching rows from database tables that is the default for result sets generated from this Statement object. If this Statement object has not set a fetch direction by calling the method setFetchDirection, the return value is implementation-specific. @return the default fetch direction for result sets generated from this Statement object } function TZAbstractStatement.GetFetchDirection: TZFetchDirection; begin Result := FFetchDirection; end; {** Gives the driver a hint as to the direction in which the rows in a result set will be processed. The hint applies only to result sets created using this Statement object. The default value is ResultSet.FETCH_FORWARD.

Note that this method sets the default fetch direction for result sets generated by this Statement object. Each result set has its own methods for getting and setting its own fetch direction. @param direction the initial direction for processing rows } procedure TZAbstractStatement.SetFetchDirection(Value: TZFetchDirection); begin FFetchDirection := Value; end; {** Retrieves the number of result set rows that is the default fetch size for result sets generated from this Statement object. If this Statement object has not set a fetch size by calling the method setFetchSize, the return value is implementation-specific. @return the default fetch size for result sets generated from this Statement object } function TZAbstractStatement.GetFetchSize: Integer; begin Result := FFetchSize; end; {** Gives the JDBC driver a hint as to the number of rows that should be fetched from the database when more rows are needed. The number of rows specified affects only result sets created using this statement. If the value specified is zero, then the hint is ignored. The default value is zero. @param rows the number of rows to fetch } procedure TZAbstractStatement.SetFetchSize(Value: Integer); begin FFetchSize := Value; end; {** Sets a result set concurrency for ResultSet objects generated by this Statement object. @param Concurrency either ResultSet.CONCUR_READ_ONLY or ResultSet.CONCUR_UPDATABLE } procedure TZAbstractStatement.SetResultSetConcurrency( Value: TZResultSetConcurrency); begin FResultSetConcurrency := Value; end; {** Retrieves the result set concurrency for ResultSet objects generated by this Statement object. @return either ResultSet.CONCUR_READ_ONLY or ResultSet.CONCUR_UPDATABLE } function TZAbstractStatement.GetResultSetConcurrency: TZResultSetConcurrency; begin Result := FResultSetConcurrency; end; {** Sets a result set type for ResultSet objects generated by this Statement object. @param ResultSetType one of ResultSet.TYPE_FORWARD_ONLY, ResultSet.TYPE_SCROLL_INSENSITIVE, or ResultSet.TYPE_SCROLL_SENSITIVE } procedure TZAbstractStatement.SetResultSetType(Value: TZResultSetType); begin FResultSetType := Value; end; {** Retrieves the result set type for ResultSet objects generated by this Statement object. @return one of ResultSet.TYPE_FORWARD_ONLY, ResultSet.TYPE_SCROLL_INSENSITIVE, or ResultSet.TYPE_SCROLL_SENSITIVE } function TZAbstractStatement.GetResultSetType: TZResultSetType; begin Result := FResultSetType; end; {** Gets the current value for locate updates. @returns the current value for locate updates. } function TZAbstractStatement.GetLocateUpdates: TZLocateUpdatesMode; begin Result := FLocateUpdates; end; {** Sets a new value for locate updates. @param Value a new value for locate updates. } procedure TZAbstractStatement.SetLocateUpdates(Value: TZLocateUpdatesMode); begin FLocateUpdates := Value; end; {** Gets the current value for post updates. @returns the current value for post updates. } function TZAbstractStatement.GetPostUpdates: TZPostUpdatesMode; begin Result := FPostUpdates; end; {** Sets a new value for post updates. @param Value a new value for post updates. } procedure TZAbstractStatement.SetPostUpdates(Value: TZPostUpdatesMode); begin FPostUpdates := Value; end; {** Adds an SQL command to the current batch of commmands for this Statement object. This method is optional. @param sql typically this is a static SQL INSERT or UPDATE statement } procedure TZAbstractStatement.AddBatch(const SQL: string); begin FBatchQueries.Add(SQL); end; {** Makes the set of commands in the current batch empty. This method is optional. } procedure TZAbstractStatement.ClearBatch; begin FBatchQueries.Clear; end; {** Submits a batch of commands to the database for execution and if all commands execute successfully, returns an array of update counts. The int elements of the array that is returned are ordered to correspond to the commands in the batch, which are ordered according to the order in which they were added to the batch. The elements in the array returned by the method executeBatch may be one of the following:

  1. A number greater than or equal to zero -- indicates that the command was processed successfully and is an update count giving the number of rows in the database that were affected by the command's execution
  2. A value of -2 -- indicates that the command was processed successfully but that the number of rows affected is unknown

    If one of the commands in a batch update fails to execute properly, this method throws a BatchUpdateException, and a JDBC driver may or may not continue to process the remaining commands in the batch. However, the driver's behavior must be consistent with a particular DBMS, either always continuing to process commands or never continuing to process commands. If the driver continues processing after a failure, the array returned by the method BatchUpdateException.getUpdateCounts will contain as many elements as there are commands in the batch, and at least one of the elements will be the following:

  3. A value of -3 -- indicates that the command failed to execute successfully and occurs only if a driver continues to process commands after a command fails

A driver is not required to implement this method. The possible implementations and return values have been modified in the Java 2 SDK, Standard Edition, version 1.3 to accommodate the option of continuing to proccess commands in a batch update after a BatchUpdateException obejct has been thrown. @return an array of update counts containing one element for each command in the batch. The elements of the array are ordered according to the order in which commands were added to the batch. } function TZAbstractStatement.ExecuteBatch: TIntegerDynArray; var I: Integer; begin SetLength(Result, FBatchQueries.Count); for I := 0 to FBatchQueries.Count -1 do Result[I] := ExecuteUpdate(FBatchQueries[I]); ClearBatch; end; {** Returns the Connection object that produced this Statement object. @return the connection that produced this statement } function TZAbstractStatement.GetConnection: IZConnection; begin Result := FConnection; end; {** Gets statement parameters. @returns a list with statement parameters. } function TZAbstractStatement.GetParameters: TStrings; begin Result := FInfo; end; {** Returns the ChunkSize for reading/writing large lobs @returns the chunksize in bytes. } function TZAbstractStatement.GetChunkSize: Integer; begin Result := FChunkSize; end; { TZAbstractPreparedStatement } {** Constructs this object and assigns main properties. @param Connection a database connection object. @param Sql a prepared Sql statement. @param Info a statement parameters. } constructor TZAbstractPreparedStatement.Create(Connection: IZConnection; const SQL: string; Info: TStrings); begin inherited Create(Connection, Info); FSQL := SQL; {$IFDEF UNICODE}WSQL{$ELSE}ASQL{$ENDIF} := SQL; FInParamCount := 0; SetInParamCount(0); FPrepared := False; FExecCount := 0; FStatementId := Self.GetNextStatementId; end; {** Destroys this object and cleanups the memory. } destructor TZAbstractPreparedStatement.Destroy; begin Unprepare; inherited Destroy; ClearParameters; end; {** Executes an SQL statement that returns a single ResultSet object. @param sql typically this is a static SQL SELECT statement @return a ResultSet object that contains the data produced by the given query; never null } function TZAbstractPreparedStatement.ExecuteQuery(const SQL: ZWideString): IZResultSet; begin WSQL := SQL; Result := ExecuteQueryPrepared; end; {** Executes an SQL INSERT, UPDATE or DELETE statement. In addition, SQL statements that return nothing, such as SQL DDL statements, can be executed. @param sql an SQL INSERT, UPDATE or DELETE statement or an SQL statement that returns nothing @return either the row count for INSERT, UPDATE or DELETE statements, or 0 for SQL statements that return nothing } function TZAbstractPreparedStatement.ExecuteUpdate(const SQL: ZWideString): Integer; begin WSQL := SQL; Result := ExecuteUpdatePrepared; end; {** Executes an SQL statement that may return multiple results. Under some (uncommon) situations a single SQL statement may return multiple result sets and/or update counts. Normally you can ignore this unless you are (1) executing a stored procedure that you know may return multiple results or (2) you are dynamically executing an unknown SQL string. The methods execute, getMoreResults, getResultSet, and getUpdateCount let you navigate through multiple results. The execute method executes an SQL statement and indicates the form of the first result. You can then use the methods getResultSet or getUpdateCount to retrieve the result, and getMoreResults to move to any subsequent result(s). @param sql any SQL statement @return true if the next result is a ResultSet object; false if it is an update count or there are no more results @see #getResultSet @see #getUpdateCount @see #getMoreResults } function TZAbstractPreparedStatement.Execute(const SQL: ZWideString): Boolean; begin WSQL := SQL; Result := ExecutePrepared; end; {** Executes an SQL statement that returns a single ResultSet object. @param sql typically this is a static SQL SELECT statement @return a ResultSet object that contains the data produced by the given query; never null } function TZAbstractPreparedStatement.ExecuteQuery(const SQL: RawByteString): IZResultSet; begin ASQL := SQL; Result := ExecuteQueryPrepared; end; {** Executes an SQL INSERT, UPDATE or DELETE statement. In addition, SQL statements that return nothing, such as SQL DDL statements, can be executed. @param sql an SQL INSERT, UPDATE or DELETE statement or an SQL statement that returns nothing @return either the row count for INSERT, UPDATE or DELETE statements, or 0 for SQL statements that return nothing } function TZAbstractPreparedStatement.ExecuteUpdate(const SQL: RawByteString): Integer; begin ASQL := SQL; Result := ExecuteUpdatePrepared; end; {** Executes an SQL statement that may return multiple results. Under some (uncommon) situations a single SQL statement may return multiple result sets and/or update counts. Normally you can ignore this unless you are (1) executing a stored procedure that you know may return multiple results or (2) you are dynamically executing an unknown SQL string. The methods execute, getMoreResults, getResultSet, and getUpdateCount let you navigate through multiple results. The execute method executes an SQL statement and indicates the form of the first result. You can then use the methods getResultSet or getUpdateCount to retrieve the result, and getMoreResults to move to any subsequent result(s). @param sql any SQL statement @return true if the next result is a ResultSet object; false if it is an update count or there are no more results @see #getResultSet @see #getUpdateCount @see #getMoreResults } function TZAbstractPreparedStatement.Execute(const SQL: RawByteString): Boolean; begin ASQL := SQL; Result := ExecutePrepared; end; {** Prepares eventual structures for binding input parameters. } procedure TZAbstractPreparedStatement.PrepareInParameters; begin end; {** Binds the input parameters } procedure TZAbstractPreparedStatement.BindInParameters; var I : integer; LogString : String; begin LogString := ''; //init for FPC if InParamCount = 0 then exit; { Prepare Log Output} For I := 0 to InParamCount - 1 do begin LogString := LogString + GetInParamLogValue(InParamValues[I])+','; end; LogPrepStmtMessage(lcBindPrepStmt, LogString); end; {** Removes eventual structures for binding input parameters. } procedure TZAbstractPreparedStatement.UnPrepareInParameters; begin end; {** Sets a new parameter count and initializes the buffers. @param NewParamCount a new parameters count. } procedure TZAbstractPreparedStatement.SetInParamCount(NewParamCount: Integer); var I: Integer; begin SetLength(FInParamValues, NewParamCount); SetLength(FInParamTypes, NewParamCount); SetLength(FInParamDefaultValues, NewParamCount); for I := FInParamCount to NewParamCount - 1 do begin FInParamValues[I] := NullVariant; FInParamTypes[I] := stUnknown; FInParamDefaultValues[I] := ''; end; FInParamCount := NewParamCount; end; {** Sets a variant value into specified parameter. @param ParameterIndex a index of the parameter. @param SqlType a parameter SQL type. @paran Value a new parameter value. } procedure TZAbstractPreparedStatement.SetInParam(ParameterIndex: Integer; SQLType: TZSQLType; const Value: TZVariant); begin if ParameterIndex >= FInParamCount then SetInParamCount(ParameterIndex); FInParamTypes[ParameterIndex - 1] := SQLType; FInParamValues[ParameterIndex - 1] := Value; end; {** Logs a message about prepared statement event with normal result code. @param Category a category of the message. @param Protocol a name of the protocol. @param Msg a description message. } procedure TZAbstractPreparedStatement.LogPrepStmtMessage(Category: TZLoggingCategory; const Msg: string = ''); begin if msg <> '' then DriverManager.LogMessage(Category, Connection.GetIZPlainDriver.GetProtocol, Format('Statement %d : %s', [FStatementId, Msg])) else DriverManager.LogMessage(Category, Connection.GetIZPlainDriver.GetProtocol, Format('Statement %d', [FStatementId])); end; function TZAbstractPreparedStatement.GetInParamLogValue(Value: TZVariant): String; begin With Value do case VType of vtNull : result := '(NULL)'; vtBoolean : If VBoolean then result := '(TRUE)' else result := '(FALSE)'; vtInteger : result := IntToStr(VInteger); vtFloat : result := FloatToStr(VFloat); vtString : result := '''' + VString + ''''; vtUnicodeString : result := '''' + VUnicodeString + ''''; vtDateTime : result := DateTimeToStr(VDateTime); vtPointer : result := '(POINTER)'; vtInterface : result := '(INTERFACE)'; else result := '(UNKNOWN TYPE)' end; end; {** Executes the SQL query in this PreparedStatement object and returns the result set generated by the query. @return a ResultSet object that contains the data produced by the query; never null } {$WARNINGS OFF} function TZAbstractPreparedStatement.ExecuteQueryPrepared: IZResultSet; begin { Logging Execution } LogPrepStmtMessage(lcExecPrepStmt); Inc(FExecCount); end; {$WARNINGS ON} {** Executes the SQL INSERT, UPDATE or DELETE statement in this PreparedStatement object. In addition, SQL statements that return nothing, such as SQL DDL statements, can be executed. @return either the row count for INSERT, UPDATE or DELETE statements; or 0 for SQL statements that return nothing } {$WARNINGS OFF} function TZAbstractPreparedStatement.ExecuteUpdatePrepared: Integer; begin { Logging Execution } LogPrepStmtMessage(lcExecPrepStmt); Inc(FExecCount); end; {$WARNINGS ON} {** Sets the designated parameter the default SQL value.

Note: You must specify the default value. @param parameterIndex the first parameter is 1, the second is 2, ... @param Value the default value normally defined in the field's DML SQL statement } procedure TZAbstractPreparedStatement.SetDefaultValue( ParameterIndex: Integer; const Value: string); begin if ParameterIndex >= FInParamCount then SetInParamCount(ParameterIndex); FInParamDefaultValues[ParameterIndex - 1] := Value; end; {** Sets the designated parameter to SQL NULL.

Note: You must specify the parameter's SQL type. @param parameterIndex the first parameter is 1, the second is 2, ... @param sqlType the SQL type code defined in java.sql.Types } procedure TZAbstractPreparedStatement.SetNull(ParameterIndex: Integer; SQLType: TZSQLType); begin SetInParam(ParameterIndex, SQLType, NullVariant); end; {** Sets the designated parameter to a Java boolean value. The driver converts this to an SQL BIT value when it sends it to the database. @param parameterIndex the first parameter is 1, the second is 2, ... @param x the parameter value } procedure TZAbstractPreparedStatement.SetBoolean(ParameterIndex: Integer; Value: Boolean); var Temp: TZVariant; begin DefVarManager.SetAsBoolean(Temp, Value); SetInParam(ParameterIndex, stBoolean, Temp); end; {** Sets the designated parameter to a Java byte value. The driver converts this to an SQL TINYINT value when it sends it to the database. @param parameterIndex the first parameter is 1, the second is 2, ... @param x the parameter value } procedure TZAbstractPreparedStatement.SetByte(ParameterIndex: Integer; Value: Byte); var Temp: TZVariant; begin DefVarManager.SetAsInteger(Temp, Value); SetInParam(ParameterIndex, stByte, Temp); end; {** Sets the designated parameter to a Java short value. The driver converts this to an SQL SMALLINT value when it sends it to the database. @param parameterIndex the first parameter is 1, the second is 2, ... @param x the parameter value } procedure TZAbstractPreparedStatement.SetShort(ParameterIndex: Integer; Value: SmallInt); var Temp: TZVariant; begin DefVarManager.SetAsInteger(Temp, Value); SetInParam(ParameterIndex, stShort, Temp); end; {** Sets the designated parameter to a Java int value. The driver converts this to an SQL INTEGER value when it sends it to the database. @param parameterIndex the first parameter is 1, the second is 2, ... @param x the parameter value } procedure TZAbstractPreparedStatement.SetInt(ParameterIndex: Integer; Value: Integer); var Temp: TZVariant; begin DefVarManager.SetAsInteger(Temp, Value); SetInParam(ParameterIndex, stInteger, Temp); end; {** Sets the designated parameter to a Java long value. The driver converts this to an SQL BIGINT value when it sends it to the database. @param parameterIndex the first parameter is 1, the second is 2, ... @param x the parameter value } procedure TZAbstractPreparedStatement.SetLong(ParameterIndex: Integer; Value: Int64); var Temp: TZVariant; begin DefVarManager.SetAsInteger(Temp, Value); SetInParam(ParameterIndex, stLong, Temp); end; {** Sets the designated parameter to a Java float value. The driver converts this to an SQL FLOAT value when it sends it to the database. @param parameterIndex the first parameter is 1, the second is 2, ... @param x the parameter value } procedure TZAbstractPreparedStatement.SetFloat(ParameterIndex: Integer; Value: Single); var Temp: TZVariant; begin DefVarManager.SetAsFloat(Temp, Value); SetInParam(ParameterIndex, stFloat, Temp); end; {** Sets the designated parameter to a Java double value. The driver converts this to an SQL DOUBLE value when it sends it to the database. @param parameterIndex the first parameter is 1, the second is 2, ... @param x the parameter value } procedure TZAbstractPreparedStatement.SetDouble(ParameterIndex: Integer; Value: Double); var Temp: TZVariant; begin DefVarManager.SetAsFloat(Temp, Value); SetInParam(ParameterIndex, stDouble, Temp); end; {** Sets the designated parameter to a java.math.BigDecimal value. The driver converts this to an SQL NUMERIC value when it sends it to the database. @param parameterIndex the first parameter is 1, the second is 2, ... @param x the parameter value } procedure TZAbstractPreparedStatement.SetBigDecimal( ParameterIndex: Integer; Value: Extended); var Temp: TZVariant; begin DefVarManager.SetAsFloat(Temp, Value); SetInParam(ParameterIndex, stBigDecimal, Temp); end; {** Sets the designated parameter to a Java String value. The driver converts this to an SQL VARCHAR or LONGVARCHAR value (depending on the argument's size relative to the driver's limits on VARCHAR values) when it sends it to the database. @param parameterIndex the first parameter is 1, the second is 2, ... @param x the parameter value } procedure TZAbstractPreparedStatement.SetPChar(ParameterIndex: Integer; Value: PChar); var Temp: TZVariant; begin DefVarManager.SetAsString(Temp, Value); SetInParam(ParameterIndex, stString, Temp); end; {** Sets the designated parameter to a Java String value. The driver converts this to an SQL VARCHAR or LONGVARCHAR value (depending on the argument's size relative to the driver's limits on VARCHAR values) when it sends it to the database. @param parameterIndex the first parameter is 1, the second is 2, ... @param x the parameter value } procedure TZAbstractPreparedStatement.SetString(ParameterIndex: Integer; const Value: String); var Temp: TZVariant; begin DefVarManager.SetAsString(Temp, Value); SetInParam(ParameterIndex, stString, Temp); end; {** Sets the designated parameter to a Object Pascal WideString value. The driver converts this to an SQL VARCHAR or LONGVARCHAR value (depending on the argument's size relative to the driver's limits on VARCHAR values) when it sends it to the database. @param parameterIndex the first parameter is 1, the second is 2, ... @param x the parameter value } procedure TZAbstractPreparedStatement.SetUnicodeString(ParameterIndex: Integer; const Value: ZWideString); var Temp: TZVariant; begin DefVarManager.SetAsUnicodeString(Temp, Value); SetInParam(ParameterIndex, stUnicodeString, Temp); end; {** Sets the designated parameter to a Java array of bytes. The driver converts this to an SQL VARBINARY or LONGVARBINARY (depending on the argument's size relative to the driver's limits on VARBINARY values) when it sends it to the database. @param parameterIndex the first parameter is 1, the second is 2, ... @param x the parameter value } procedure TZAbstractPreparedStatement.SetBytes(ParameterIndex: Integer; const Value: TByteDynArray); var Temp: TZVariant; begin DefVarManager.SetAsBytes(Temp, Value); SetInParam(ParameterIndex, stBytes, Temp); end; {** Sets the designated parameter to a value. The driver converts this to an SQL DATE value when it sends it to the database. @param parameterIndex the first parameter is 1, the second is 2, ... @param x the parameter value } procedure TZAbstractPreparedStatement.SetDate(ParameterIndex: Integer; Value: TDateTime); var Temp: TZVariant; begin DefVarManager.SetAsDateTime(Temp, Value); SetInParam(ParameterIndex, stDate, Temp); end; {** Sets the designated parameter to a java.sql.Time value. The driver converts this to an SQL TIME value when it sends it to the database. @param parameterIndex the first parameter is 1, the second is 2, ... @param x the parameter value } procedure TZAbstractPreparedStatement.SetTime(ParameterIndex: Integer; Value: TDateTime); var Temp: TZVariant; begin DefVarManager.SetAsDateTime(Temp, Value); SetInParam(ParameterIndex, stTime, Temp); end; {** Sets the designated parameter to a java.sql.Timestamp value. The driver converts this to an SQL TIMESTAMP value when it sends it to the database. @param parameterIndex the first parameter is 1, the second is 2, ... @param x the parameter value } procedure TZAbstractPreparedStatement.SetTimestamp(ParameterIndex: Integer; Value: TDateTime); var Temp: TZVariant; begin DefVarManager.SetAsDateTime(Temp, Value); SetInParam(ParameterIndex, stTimestamp, Temp); end; {** Sets the designated parameter to the given input stream, which will have the specified number of bytes. When a very large ASCII value is input to a LONGVARCHAR parameter, it may be more practical to send it via a java.io.InputStream. Data will be read from the stream as needed until end-of-file is reached. The JDBC driver will do any necessary conversion from ASCII to the database char format.

Note: This stream object can either be a standard Java stream object or your own subclass that implements the standard interface. @param parameterIndex the first parameter is 1, the second is 2, ... @param x the Java input stream that contains the ASCII parameter value @param length the number of bytes in the stream } procedure TZAbstractPreparedStatement.SetAsciiStream( ParameterIndex: Integer; Value: TStream); begin SetBlob(ParameterIndex, stAsciiStream, TZAbstractBlob.CreateWithStream(Value, GetConnection)); end; {** Sets the designated parameter to the given input stream, which will have the specified number of bytes. When a very large UNICODE value is input to a LONGVARCHAR parameter, it may be more practical to send it via a java.io.InputStream object. The data will be read from the stream as needed until end-of-file is reached. The JDBC driver will do any necessary conversion from UNICODE to the database char format. The byte format of the Unicode stream must be Java UTF-8, as defined in the Java Virtual Machine Specification.

Note: This stream object can either be a standard Java stream object or your own subclass that implements the standard interface. @param parameterIndex the first parameter is 1, the second is 2, ... @param x the java input stream which contains the UNICODE parameter value } procedure TZAbstractPreparedStatement.SetUnicodeStream( ParameterIndex: Integer; Value: TStream); begin SetBlob(ParameterIndex, stUnicodeStream, TZAbstractBlob.CreateWithStream(Value, GetConnection)); end; {** Sets the designated parameter to the given input stream, which will have the specified number of bytes. When a very large binary value is input to a LONGVARBINARY parameter, it may be more practical to send it via a java.io.InputStream object. The data will be read from the stream as needed until end-of-file is reached.

Note: This stream object can either be a standard Java stream object or your own subclass that implements the standard interface. @param parameterIndex the first parameter is 1, the second is 2, ... @param x the java input stream which contains the binary parameter value } procedure TZAbstractPreparedStatement.SetBinaryStream( ParameterIndex: Integer; Value: TStream); begin SetBlob(ParameterIndex, stBinaryStream, TZAbstractBlob.CreateWithStream(Value, GetConnection)); end; {** Sets a blob object for the specified parameter. @param ParameterIndex the first parameter is 1, the second is 2, ... @param Value the java blob object. } procedure TZAbstractPreparedStatement.SetBlob(ParameterIndex: Integer; SQLType: TZSQLType; Value: IZBlob); var Temp: TZVariant; begin if not (SQLType in [stAsciiStream, stUnicodeStream, stBinaryStream]) then raise EZSQLException.Create(SWrongTypeForBlobParameter); DefVarManager.SetAsInterface(Temp, Value); SetInParam(ParameterIndex, SQLType, Temp); end; {** Sets a variant value for the specified parameter. @param ParameterIndex the first parameter is 1, the second is 2, ... @param Value the variant value. } procedure TZAbstractPreparedStatement.SetValue(ParameterIndex: Integer; const Value: TZVariant); var SQLType: TZSQLType; begin case Value.VType of vtBoolean: SQLType := stBoolean; vtInteger: SQLType := stLong; vtFloat: SQLType := stBigDecimal; vtUnicodeString: SQLType := stUnicodeString; vtDateTime: SQLType := stTimestamp; else SQLType := stString; end; SetInParam(ParameterIndex, SQLType, Value); end; {** Clears the current parameter values immediately.

In general, parameter values remain in force for repeated use of a statement. Setting a parameter value automatically clears its previous value. However, in some cases it is useful to immediately release the resources used by the current parameter values; this can be done by calling the method clearParameters. } procedure TZAbstractPreparedStatement.ClearParameters; var I: Integer; begin for I := 1 to FInParamCount do begin SetInParam(I, stUnknown, NullVariant); SetDefaultValue(I, ''); end; SetInParamCount(0); end; {** Executes any kind of SQL statement. Some prepared statements return multiple results; the execute method handles these complex statements as well as the simpler form of statements handled by the methods executeQuery and executeUpdate. @see Statement#execute } {$WARNINGS OFF} function TZAbstractPreparedStatement.ExecutePrepared: Boolean; begin { Logging Execution } LogPrepStmtMessage(lcExecPrepStmt, ''); Inc(FExecCount); end; {$WARNINGS ON} function TZAbstractPreparedStatement.GetSQL: String; begin Result := FSQL; end; procedure TZAbstractPreparedStatement.Prepare; begin PrepareInParameters; FPrepared := True; end; procedure TZAbstractPreparedStatement.Unprepare; begin UnPrepareInParameters; FPrepared := False; end; function TZAbstractPreparedStatement.IsPrepared: Boolean; begin Result := FPrepared; end; {** Adds a set of parameters to this PreparedStatement object's batch of commands. @see Statement#addBatch } procedure TZAbstractPreparedStatement.AddBatchPrepared; begin end; {** Gets the number, types and properties of a ResultSet object's columns. @return the description of a ResultSet object's columns } function TZAbstractPreparedStatement.GetMetaData: IZResultSetMetaData; begin Result := nil; RaiseUnsupportedException; end; { TZAbstractCallableStatement } {** Constructs this object and assigns main properties. @param Connection a database connection object. @param Sql a prepared Sql statement. @param Info a statement parameters. } constructor TZAbstractCallableStatement.Create(Connection: IZConnection; SQL: string; Info: TStrings); begin inherited Create(Connection, SQL, Info); FOutParamCount := 0; SetOutParamCount(0); FProcSql := ''; //Init -> FPC FLastWasNull := True; FResultSets := TZCollection.Create; FIsFunction := False; end; {** Close and release a list of returned resultsets. } procedure TZAbstractCallableStatement.ClearResultSets; var I: Integer; RS: IZResultSet; begin for i := 0 to FResultSets.Count -1 do if Supports(FResultSets[i], IZResultSet, RS) then //possible IZUpdateCount e.g. DBLib, ASA RS.Close; FResultSets.Clear; LastResultSet := nil; end; {** Function remove stUnknown and ptResult, ptOutput paramters from InParamTypes and InParamValues because the out-params are added after fetching. } procedure TZAbstractCallableStatement.TrimInParameters; var I: integer; ParamValues: TZVariantDynArray; ParamTypes: TZSQLTypeArray; ParamCount: Integer; begin ParamCount := 0; SetLength(ParamValues, InParamCount); SetLength(ParamTypes, InParamCount); {Need for dbc access, where no metadata is used to register the ParamTypes} if Length(FDBParamTypes) < InParamCount then SetLength(FDBParamTypes, InParamCount); {end for dbc access} for I := 0 to High(InParamTypes) do begin if ( InParamTypes[I] = ZDbcIntfs.stUnknown ) then Continue; if (FDBParamTypes[i] in [2, 4]) then //[ptResult, ptOutput] continue; //EgonHugeist: Ignore known OutParams! else StatmentInparamCount <> expect ProcedureParamCount ParamTypes[ParamCount] := InParamTypes[I]; ParamValues[ParamCount] := InParamValues[I]; Inc(ParamCount); end; if ParamCount = InParamCount then Exit; InParamTypes := ParamTypes; InParamValues := ParamValues; SetInParamCount(ParamCount); //AVZ end; {** Sets a new parameter count and initializes the buffers. @param NewParamCount a new parameters count. } procedure TZAbstractCallableStatement.SetOutParamCount(NewParamCount: Integer); var I: Integer; begin SetLength(FOutParamValues, NewParamCount); SetLength(FOutParamTypes, NewParamCount); for I := FOutParamCount to NewParamCount - 1 do begin FOutParamValues[I] := NullVariant; FOutParamTypes[I] := stUnknown; end; FOutParamCount := NewParamCount; end; {** Clears the current parameter values immediately.

In general, parameter values remain in force for repeated use of a statement. Setting a parameter value automatically clears its previous value. However, in some cases it is useful to immediately release the resources used by the current parameter values; this can be done by calling the method clearParameters. } procedure TZAbstractCallableStatement.ClearParameters; var I: Integer; begin inherited; for I := 1 to FOutParamCount do begin OutParamValues[I - 1] := NullVariant; OutParamTypes[I - 1] := stUnknown; end; SetOutParamCount(0); end; {** Releases this Statement object's database and JDBC resources immediately instead of waiting for this to happen when it is automatically closed. It is generally good practice to release resources as soon as you are finished with them to avoid tying up database resources.

Note: A Statement object is automatically closed when it is garbage collected. When a Statement object is closed, its current ResultSet object, if one exists, is also closed. } procedure TZAbstractCallableStatement.Close; begin ClearResultSets; inherited Close; end; {** Do we call a function or a procedure? @result Returns True if we call a function } function TZAbstractCallableStatement.IsFunction: Boolean; begin Result := FIsFunction; end; {** Do we have ptInputOutput or ptOutput paramets in a function or procedure? @result Returns True if ptInputOutput or ptOutput is available } function TZAbstractCallableStatement.HasOutParameter: Boolean; begin Result := FHasOutParameter; end; {** Are more resultsets retrieved? @result Returns True if more resultsets are retrieved } function TZAbstractCallableStatement.HasMoreResultSets: Boolean; begin Result := False; end; {** Get the first resultset.. @result IZResultSet if supported } function TZAbstractCallableStatement.GetFirstResultSet: IZResultSet; begin Result := nil; end; {** Get the previous resultset.. @result IZResultSet if supported } function TZAbstractCallableStatement.GetPreviousResultSet: IZResultSet; begin Result := nil; end; {** Get the next resultset.. @result IZResultSet if supported } function TZAbstractCallableStatement.GetNextResultSet: IZResultSet; begin Result := nil; end; {** Get the last resultset.. @result IZResultSet if supported } function TZAbstractCallableStatement.GetLastResultSet: IZResultSet; begin Result := nil; end; {** First ResultSet? @result True if first ResultSet } function TZAbstractCallableStatement.BOR: Boolean; begin Result := True; end; {** Last ResultSet? @result True if Last ResultSet } function TZAbstractCallableStatement.EOR: Boolean; begin Result := True; end; {** Retrieves a ResultSet by his index. @param Index the index of the Resultset @result IZResultSet of the Index or nil. } function TZAbstractCallableStatement.GetResultSetByIndex(const Index: Integer): IZResultSet; begin Result := nil; end; {** Returns the Count of retrived ResultSets. @result Integer Count } function TZAbstractCallableStatement.GetResultSetCount: Integer; begin Result := 0; end; {** Registers the OUT parameter in ordinal position parameterIndex to the JDBC type sqlType. All OUT parameters must be registered before a stored procedure is executed.

The JDBC type specified by sqlType for an OUT parameter determines the Java type that must be used in the get method to read the value of that parameter.

If the JDBC type expected to be returned to this output parameter is specific to this particular database, sqlType should be java.sql.Types.OTHER. The method retrieves the value. @param parameterIndex the first parameter is 1, the second is 2, and so on @param sqlType the JDBC type code defined by java.sql.Types. If the parameter is of JDBC type NUMERIC or DECIMAL, the version of registerOutParameter that accepts a scale value should be used. } procedure TZAbstractCallableStatement.RegisterOutParameter(ParameterIndex, SQLType: Integer); begin SetOutParamCount(ParameterIndex); OutParamTypes[ParameterIndex - 1] := TZSQLType(SQLType); end; procedure TZAbstractCallableStatement.RegisterParamType(ParameterIndex, ParamType: Integer); begin if (Length(FDBParamTypes) < ParameterIndex) then SetLength(FDBParamTypes, ParameterIndex); FDBParamTypes[ParameterIndex - 1] := ParamType; if not FIsFunction then FIsFunction := ParamType = 4; //ptResult if not FHasOutParameter then FHasOutParameter := ParamType in [2,3]; //ptOutput, ptInputOutput end; {** Gets a output parameter value by it's index. @param ParameterIndex a parameter index. @returns a parameter value. } function TZAbstractCallableStatement.GetOutParam( ParameterIndex: Integer): TZVariant; begin if Assigned(OutParamValues) then begin Result := OutParamValues[ParameterIndex - 1]; FLastWasNull := DefVarManager.IsNull(Result); end else begin Result:=NullVariant; FLastWasNull:=True; end; end; procedure TZAbstractCallableStatement.SetProcSQL(const Value: String); begin FProcSql := Value; end; {** Indicates whether or not the last OUT parameter read had the value of SQL NULL. Note that this method should be called only after calling a getXXX method; otherwise, there is no value to use in determining whether it is null or not. @return true if the last parameter read was SQL NULL; false otherwise } function TZAbstractCallableStatement.WasNull: Boolean; begin Result := FLastWasNull; end; {** Indicates whether or not the specified OUT parameter read had the value of SQL NULL. @return true if the parameter read was SQL NULL; false otherwise } function TZAbstractCallableStatement.IsNull(ParameterIndex: Integer): Boolean; begin GetOutParam(ParameterIndex); Result := FLastWasNull; end; {** Retrieves the value of a JDBC CHAR, VARCHAR, or LONGVARCHAR parameter as a String in the Java programming language.

For the fixed-length type JDBC CHAR, the String object returned has exactly the same value the JDBC CHAR value had in the database, including any padding added by the database. @param parameterIndex the first parameter is 1, the second is 2, and so on @return the parameter value. If the value is SQL NULL, the result is null. @exception SQLException if a database access error occurs } function TZAbstractCallableStatement.GetPChar(ParameterIndex: Integer): PChar; begin FTemp := GetString(ParameterIndex); Result := PChar(FTemp); end; {** Retrieves the value of a JDBC CHAR, VARCHAR, or LONGVARCHAR parameter as a String in the Java programming language.

For the fixed-length type JDBC CHAR, the String object returned has exactly the same value the JDBC CHAR value had in the database, including any padding added by the database. @param parameterIndex the first parameter is 1, the second is 2, and so on @return the parameter value. If the value is SQL NULL, the result is null. @exception SQLException if a database access error occurs } function TZAbstractCallableStatement.GetString(ParameterIndex: Integer): String; begin Result := SoftVarManager.GetAsString(GetOutParam(ParameterIndex)); end; {** Retrieves the value of a JDBC CHAR, VARCHAR, or LONGVARCHAR parameter as a String in the Java programming language.

For the fixed-length type JDBC CHAR, the WideString object returned has exactly the same value the JDBC CHAR value had in the database, including any padding added by the database. @param parameterIndex the first parameter is 1, the second is 2, and so on @return the parameter value. If the value is SQL NULL, the result is null. @exception SQLException if a database access error occurs } function TZAbstractCallableStatement.GetUnicodeString( ParameterIndex: Integer): WideString; begin Result := SoftVarManager.GetAsUnicodeString(GetOutParam(ParameterIndex)); end; {** Gets the value of a JDBC BIT parameter as a boolean in the Java programming language. @param parameterIndex the first parameter is 1, the second is 2, and so on @return the parameter value. If the value is SQL NULL, the result is false. } function TZAbstractCallableStatement.GetBoolean(ParameterIndex: Integer): Boolean; begin Result := SoftvarManager.GetAsBoolean(GetOutParam(ParameterIndex)); end; {** Gets the value of a JDBC TINYINT parameter as a byte in the Java programming language. @param parameterIndex the first parameter is 1, the second is 2, and so on @return the parameter value. If the value is SQL NULL, the result is 0. } function TZAbstractCallableStatement.GetByte(ParameterIndex: Integer): Byte; begin Result := Byte(SoftVarManager.GetAsInteger(GetOutParam(ParameterIndex))); end; {** Gets the value of a JDBC SMALLINT parameter as a short in the Java programming language. @param parameterIndex the first parameter is 1, the second is 2, and so on @return the parameter value. If the value is SQL NULL, the result is 0. } function TZAbstractCallableStatement.GetShort(ParameterIndex: Integer): SmallInt; begin Result := SmallInt(SoftVarManager.GetAsInteger(GetOutParam(ParameterIndex))); end; {** Gets the value of a JDBC INTEGER parameter as an int in the Java programming language. @param parameterIndex the first parameter is 1, the second is 2, and so on @return the parameter value. If the value is SQL NULL, the result is 0. } function TZAbstractCallableStatement.GetInt(ParameterIndex: Integer): Integer; begin Result := Integer(SoftVarManager.GetAsInteger(GetOutParam(ParameterIndex))); end; {** Gets the value of a JDBC BIGINT parameter as a long in the Java programming language. @param parameterIndex the first parameter is 1, the second is 2, and so on @return the parameter value. If the value is SQL NULL, the result is 0. } function TZAbstractCallableStatement.GetLong(ParameterIndex: Integer): Int64; begin Result := SoftVarManager.GetAsInteger(GetOutParam(ParameterIndex)); end; {** Gets the value of a JDBC FLOAT parameter as a float in the Java programming language. @param parameterIndex the first parameter is 1, the second is 2, and so on @return the parameter value. If the value is SQL NULL, the result is 0. } function TZAbstractCallableStatement.GetFloat(ParameterIndex: Integer): Single; begin Result := SoftVarManager.GetAsFloat(GetOutParam(ParameterIndex)); end; {** Gets the value of a JDBC DOUBLE parameter as a double in the Java programming language. @param parameterIndex the first parameter is 1, the second is 2, and so on @return the parameter value. If the value is SQL NULL, the result is 0. } function TZAbstractCallableStatement.GetDouble(ParameterIndex: Integer): Double; begin Result := SoftVarManager.GetAsFloat(GetOutParam(ParameterIndex)); end; {** Gets the value of a JDBC NUMERIC parameter as a java.math.BigDecimal object with scale digits to the right of the decimal point. @param parameterIndex the first parameter is 1, the second is 2, and so on @return the parameter value. If the value is SQL NULL, the result is null. } function TZAbstractCallableStatement.GetBigDecimal(ParameterIndex: Integer): Extended; begin Result := SoftVarManager.GetAsFloat(GetOutParam(ParameterIndex)); end; {** Gets the value of a JDBC BINARY or VARBINARY parameter as an array of byte values in the Java programming language. @param parameterIndex the first parameter is 1, the second is 2, and so on @return the parameter value. If the value is SQL NULL, the result is null. } function TZAbstractCallableStatement.GetBytes(ParameterIndex: Integer): TByteDynArray; begin Result := SoftVarManager.GetAsBytes(GetOutParam(ParameterIndex)); end; {** Gets the value of a JDBC DATE parameter as a java.sql.Date object. @param parameterIndex the first parameter is 1, the second is 2, and so on @return the parameter value. If the value is SQL NULL, the result is null. } function TZAbstractCallableStatement.GetDate(ParameterIndex: Integer): TDateTime; begin Result := SoftVarManager.GetAsDateTime(GetOutParam(ParameterIndex)); end; {** Get the value of a JDBC TIME parameter as a java.sql.Time object. @param parameterIndex the first parameter is 1, the second is 2, and so on @return the parameter value. If the value is SQL NULL, the result is null. } function TZAbstractCallableStatement.GetTime(ParameterIndex: Integer): TDateTime; begin Result := SoftVarManager.GetAsDateTime(GetOutParam(ParameterIndex)); end; {** Gets the value of a JDBC TIMESTAMP parameter as a java.sql.Timestamp object. @param parameterIndex the first parameter is 1, the second is 2, and so on @return the parameter value. If the value is SQL NULL, the result is null. } function TZAbstractCallableStatement.GetTimestamp(ParameterIndex: Integer): TDateTime; begin Result := SoftVarManager.GetAsDateTime(GetOutParam(ParameterIndex)); end; {** Gets the value of a JDBC Variant parameter value. @param parameterIndex the first parameter is 1, the second is 2, and so on @return the parameter value. If the value is SQL NULL, the result is null. } function TZAbstractCallableStatement.GetValue(ParameterIndex: Integer): TZVariant; begin Result := GetOutParam(ParameterIndex); end; { TZAbstractPreparedCallableStatement } procedure TZAbstractPreparedCallableStatement.SetProcSQL(const Value: String); begin if Value <> ProcSQL then Unprepare; inherited SetProcSQL(Value); if (Value <> '') and ( not Prepared ) then Prepare; end; {** Executes an SQL statement that returns a single ResultSet object. @param sql typically this is a static SQL SELECT statement @return a ResultSet object that contains the data produced by the given query; never null } function TZAbstractPreparedCallableStatement.ExecuteQuery(const SQL: ZWideString): IZResultSet; begin if (SQL <> Self.WSQL) and (Prepared) then Unprepare; WSQL := SQL; Result := ExecuteQueryPrepared; end; function TZAbstractPreparedCallableStatement.ExecuteQuery(const SQL: RawByteString): IZResultSet; begin if (SQL <> Self.ASQL) and (Prepared) then Unprepare; Self.ASQL := SQL; Result := ExecuteQueryPrepared; end; {** Executes an SQL INSERT, UPDATE or DELETE statement. In addition, SQL statements that return nothing, such as SQL DDL statements, can be executed. @param sql an SQL INSERT, UPDATE or DELETE statement or an SQL statement that returns nothing @return either the row count for INSERT, UPDATE or DELETE statements, or 0 for SQL statements that return nothing } function TZAbstractPreparedCallableStatement.ExecuteUpdate(const SQL: ZWideString): Integer; begin if (SQL <> WSQL) and (Prepared) then Unprepare; WSQL := SQL; Result := ExecuteUpdatePrepared; end; function TZAbstractPreparedCallableStatement.ExecuteUpdate(const SQL: RawByteString): Integer; begin if (SQL <> ASQL) and (Prepared) then Unprepare; ASQL := SQL; Result := ExecuteUpdatePrepared; end; {** Executes an SQL statement that may return multiple results. Under some (uncommon) situations a single SQL statement may return multiple result sets and/or update counts. Normally you can ignore this unless you are (1) executing a stored procedure that you know may return multiple results or (2) you are dynamically executing an unknown SQL string. The methods execute, getMoreResults, getResultSet, and getUpdateCount let you navigate through multiple results. The execute method executes an SQL statement and indicates the form of the first result. You can then use the methods getResultSet or getUpdateCount to retrieve the result, and getMoreResults to move to any subsequent result(s). @param sql any SQL statement @return true if the next result is a ResultSet object; false if it is an update count or there are no more results @see #getResultSet @see #getUpdateCount @see #getMoreResults } function TZAbstractPreparedCallableStatement.Execute(const SQL: ZWideString): Boolean; begin if (SQL <> WSQL) and (Prepared) then Unprepare; WSQL := SQL; Result := ExecutePrepared; end; function TZAbstractPreparedCallableStatement.Execute(const SQL: RawByteString): Boolean; begin if (SQL <> ASQL) and (Prepared) then Unprepare; ASQL := SQL; Result := ExecutePrepared; end; { TZEmulatedPreparedStatement } {** Destroys this object and cleanups the memory. } destructor TZEmulatedPreparedStatement.Destroy; begin if FCachedQuery <> nil then FCachedQuery.Free; inherited Destroy; end; {** Sets a reference to the last statement. @param LastStatement the last statement interface. } procedure TZEmulatedPreparedStatement.SetLastStatement( LastStatement: IZStatement); begin if FLastStatement <> nil then FLastStatement.Close; FLastStatement := LastStatement; end; function TZEmulatedPreparedStatement.PrepareWideSQLParam(ParamIndex: Integer): ZWideString; begin Result := ''; end; function TZEmulatedPreparedStatement.PrepareAnsiSQLParam(ParamIndex: Integer): RawByteString; begin Result := ''; end; {** Creates a temporary statement which executes queries. @param Info a statement parameters. @return a created statement object. } function TZEmulatedPreparedStatement.GetExecStatement: IZStatement; begin if ExecStatement = nil then begin ExecStatement := CreateExecStatement; ExecStatement.SetMaxFieldSize(GetMaxFieldSize); ExecStatement.SetMaxRows(GetMaxRows); ExecStatement.SetEscapeProcessing(EscapeProcessing); ExecStatement.SetQueryTimeout(GetQueryTimeout); ExecStatement.SetCursorName(CursorName); ExecStatement.SetFetchDirection(GetFetchDirection); ExecStatement.SetFetchSize(GetFetchSize); ExecStatement.SetResultSetConcurrency(GetResultSetConcurrency); ExecStatement.SetResultSetType(GetResultSetType); end; Result := ExecStatement; end; {** Splits a SQL query into a list of sections. @returns a list of splitted sections. } function TZEmulatedPreparedStatement.TokenizeSQLQuery: TStrings; var I: Integer; Tokens: TStrings; Temp: string; begin if FCachedQuery = nil then begin FCachedQuery := TStringList.Create; if Pos('?', SSQL) > 0 then begin Tokens := Connection.GetDriver.GetTokenizer.TokenizeBufferToList(SSQL, [toUnifyWhitespaces]); try Temp := ''; for I := 0 to Tokens.Count - 1 do begin if Tokens[I] = '?' then begin if FNeedNCharDetection and not (Temp = '') then FCachedQuery.Add(Temp) else FCachedQuery.Add(Temp); FCachedQuery.AddObject('?', Self); Temp := ''; end else if FNeedNCharDetection and (Tokens[I] = 'N') and (Tokens.Count > i) and (Tokens[i+1] = '?') then begin FCachedQuery.Add(Temp); FCachedQuery.Add(Tokens[i]); Temp := ''; end else Temp := Temp + Tokens[I]; end; if Temp <> '' then FCachedQuery.Add(Temp); finally Tokens.Free; end; end else FCachedQuery.Add(SSQL); end; Result := FCachedQuery; end; {** Prepares an SQL statement and inserts all data values. @return a prepared SQL statement. } function TZEmulatedPreparedStatement.PrepareWideSQLQuery: ZWideString; var I: Integer; ParamIndex: Integer; Tokens: TStrings; begin ParamIndex := 0; Result := ''; Tokens := TokenizeSQLQuery; for I := 0 to Tokens.Count - 1 do begin if Tokens[I] = '?' then begin Result := Result + PrepareWideSQLParam(ParamIndex); Inc(ParamIndex); end else Result := Result + ZPlainUnicodeString(Tokens[I]); end; end; {** Prepares an SQL statement and inserts all data values. @return a prepared SQL statement. } function TZEmulatedPreparedStatement.PrepareAnsiSQLQuery: RawByteString; var I: Integer; ParamIndex: Integer; Tokens: TStrings; begin ParamIndex := 0; Result := ''; Tokens := TokenizeSQLQuery; for I := 0 to Tokens.Count - 1 do begin if Tokens[I] = '?' then begin Result := Result + PrepareAnsiSQLParam(ParamIndex); Inc(ParamIndex); end else Result := Result + ZPlainString(Tokens[I]); end; {$IFNDEF UNICODE} if GetConnection.AutoEncodeStrings then Result := GetConnection.GetDriver.GetTokenizer.GetEscapeString(Result); {$ENDIF} end; {** Closes this statement and frees all resources. } procedure TZEmulatedPreparedStatement.Close; begin inherited Close; if LastStatement <> nil then begin FLastStatement.Close; FLastStatement := nil; end; end; {** Executes an SQL statement that may return multiple results. Under some (uncommon) situations a single SQL statement may return multiple result sets and/or update counts. Normally you can ignore this unless you are (1) executing a stored procedure that you know may return multiple results or (2) you are dynamically executing an unknown SQL string. The methods execute, getMoreResults, getResultSet, and getUpdateCount let you navigate through multiple results. The execute method executes an SQL statement and indicates the form of the first result. You can then use the methods getResultSet or getUpdateCount to retrieve the result, and getMoreResults to move to any subsequent result(s). @param sql any SQL statement @return true if the next result is a ResultSet object; false if it is an update count or there are no more results } function TZEmulatedPreparedStatement.Execute(const SQL: ZWideString): Boolean; begin LastStatement := GetExecStatement; Result := LastStatement.Execute(SQL); if Result then LastResultSet := LastStatement.GetResultSet else LastUpdateCount := LastStatement.GetUpdateCount; end; {** Executes an SQL statement that may return multiple results. Under some (uncommon) situations a single SQL statement may return multiple result sets and/or update counts. Normally you can ignore this unless you are (1) executing a stored procedure that you know may return multiple results or (2) you are dynamically executing an unknown SQL string. The methods execute, getMoreResults, getResultSet, and getUpdateCount let you navigate through multiple results. The execute method executes an SQL statement and indicates the form of the first result. You can then use the methods getResultSet or getUpdateCount to retrieve the result, and getMoreResults to move to any subsequent result(s). @param sql any SQL statement @return true if the next result is a ResultSet object; false if it is an update count or there are no more results } function TZEmulatedPreparedStatement.Execute(const SQL: RawByteString): Boolean; begin LastStatement := GetExecStatement; Result := LastStatement.Execute(SQL); if Result then LastResultSet := LastStatement.GetResultSet else LastUpdateCount := LastStatement.GetUpdateCount; end; {** Executes an SQL statement that returns a single ResultSet object. @param sql typically this is a static SQL SELECT statement @return a ResultSet object that contains the data produced by the given query; never null } function TZEmulatedPreparedStatement.ExecuteQuery(const SQL: ZWideString): IZResultSet; begin Result := GetExecStatement.ExecuteQuery(SQL); end; {** Executes an SQL statement that returns a single ResultSet object. @param sql typically this is a static SQL SELECT statement @return a ResultSet object that contains the data produced by the given query; never null } function TZEmulatedPreparedStatement.ExecuteQuery(const SQL: RawByteString): IZResultSet; begin Result := GetExecStatement.ExecuteQuery(SQL); end; {** Executes an SQL INSERT, UPDATE or DELETE statement. In addition, SQL statements that return nothing, such as SQL DDL statements, can be executed. @param sql an SQL INSERT, UPDATE or DELETE statement or an SQL statement that returns nothing @return either the row count for INSERT, UPDATE or DELETE statements, or 0 for SQL statements that return nothing } function TZEmulatedPreparedStatement.ExecuteUpdate(const SQL: ZWideString): Integer; begin Result := GetExecStatement.ExecuteUpdate(SQL); LastUpdateCount := Result; end; {** Executes an SQL INSERT, UPDATE or DELETE statement. In addition, SQL statements that return nothing, such as SQL DDL statements, can be executed. @param sql an SQL INSERT, UPDATE or DELETE statement or an SQL statement that returns nothing @return either the row count for INSERT, UPDATE or DELETE statements, or 0 for SQL statements that return nothing } function TZEmulatedPreparedStatement.ExecuteUpdate(const SQL: RawByteString): Integer; begin Result := GetExecStatement.ExecuteUpdate(SQL); LastUpdateCount := Result; end; {** Executes the SQL query in this PreparedStatement object and returns the result set generated by the query. @return a ResultSet object that contains the data produced by the query; never null } function TZEmulatedPreparedStatement.ExecutePrepared: Boolean; begin if IsAnsiDriver then Result := Execute(PrepareAnsiSQLQuery) else Result := Execute(PrepareWideSQLQuery); end; {** Executes the SQL query in this PreparedStatement object and returns the result set generated by the query. @return a ResultSet object that contains the data produced by the query; never null } function TZEmulatedPreparedStatement.ExecuteQueryPrepared: IZResultSet; begin if IsAnsiDriver then Result := ExecuteQuery(PrepareAnsiSQLQuery) else Result := ExecuteQuery(PrepareWideSQLQuery); end; {** Executes the SQL INSERT, UPDATE or DELETE statement in this PreparedStatement object. In addition, SQL statements that return nothing, such as SQL DDL statements, can be executed. @return either the row count for INSERT, UPDATE or DELETE statements; or 0 for SQL statements that return nothing } function TZEmulatedPreparedStatement.ExecuteUpdatePrepared: Integer; begin if IsAnsiDriver then Result := ExecuteUpdate(PrepareAnsiSQLQuery) else Result := ExecuteUpdate(PrepareWideSQLQuery); end; end. ================================================ FILE: lib/zeosdbo/src/dbc/ZDbcUtils.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Database Connectivity Functions } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZDbcUtils; interface {$I ZDbc.inc} uses Types, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, Contnrs, ZCompatibility, ZDbcIntfs, ZDbcResultSetMetadata; {** Resolves a connection protocol and raises an exception with protocol is not supported. @param Url an initial database URL. @param SuupportedProtocols a driver's supported subprotocols. } function ResolveConnectionProtocol(Url: string; SupportedProtocols: TStringDynArray): string; {** Resolves a database URL and fills the database connection parameters. @param Url an initial database URL. @param Info an initial info parameters. @param HostName a name of the database host. @param Port a port number. @param Database a database name. @param UserName a name of the database user. @param Password a user's password. @param ResutlInfo a result info parameters. } procedure ResolveDatabaseUrl(const Url: string; Info: TStrings; var HostName: string; var Port: Integer; var Database: string; var UserName: string; var Password: string; ResultInfo: TStrings); {** Checks is the convertion from one type to another type allowed. @param InitialType an initial data type. @param ResultType a result data type. @return True if convertion is allowed or False otherwise. } function CheckConvertion(InitialType: TZSQLType; ResultType: TZSQLType): Boolean; {** Defines a name of the column type. @param ColumnType a type of the column. @return a name of the specified type. } function DefineColumnTypeName(ColumnType: TZSQLType): string; {** Raises a copy of the given exception. @param E an exception to be raised. } procedure RaiseSQLException(E: Exception); {** Copies column information objects from one object list to another one. @param FromList the source object list. @param ToList the destination object list. } procedure CopyColumnsInfo(FromList: TObjectList; ToList: TObjectList); {** Defines a statement specific parameter. @param Statement a statement interface reference. @param ParamName a name of the parameter. @param Default a parameter default value. @return a parameter value or default if nothing was found. } function DefineStatementParameter(Statement: IZStatement; const ParamName: string; const Default: string): string; {** ToLikeString returns the given string or if the string is empty it returns '%' @param Value the string @return given Value or '%' } function ToLikeString(const Value: string): string; {** GetSQLHexString returns a valid x'..' database understandable String from binary data @param Value the ansistring-pointer to the binary data @param Len then length of the binary Data @param ODBC a boolean if output result should be with a starting 0x... @returns a valid hex formated unicode-safe string } function GetSQLHexWideString(Value: PAnsiChar; Len: Integer; ODBC: Boolean = False): ZWideString; function GetSQLHexAnsiString(Value: PAnsiChar; Len: Integer; ODBC: Boolean = False): RawByteString; function GetSQLHexString(Value: PAnsiChar; Len: Integer; ODBC: Boolean = False): String; {** Returns a FieldSize in Bytes dependend to the FieldType and CharWidth @param TZSQLType the Zeos FieldType @param Integer the Current given FieldLength @param Integer the Current CountOfByte/Char @param Boolean does the Driver returns the FullSizeInBytes @returns Integer the count of AnsiChars for Field.Size * SizeOf(Char) } function GetFieldSize(const SQLType: TZSQLType;ConSettings: PZConSettings; const Precision, CharWidth: Integer; DisplaySize: PInteger = nil; SizeInBytes: Boolean = False): Integer; function WideStringStream(const AString: WideString): TStream; implementation uses ZMessages, ZSysUtils, ZEncoding; {** Resolves a connection protocol and raises an exception with protocol is not supported. @param Url an initial database URL. @param SupportedProtocols a driver's supported subprotocols. } function ResolveConnectionProtocol(Url: string; SupportedProtocols: TStringDynArray): string; var I: Integer; Protocol: string; Index: Integer; begin Result := ''; Index := FirstDelimiter(':', Url); if Index > 0 then Protocol := Copy(Url, Index + 1, Length(Url) - Index) else Protocol := ''; Index := FirstDelimiter(':', Protocol); if Index > 1 then Protocol := Copy(Protocol, 1, Index - 1) else Protocol := ''; if Protocol = '' then raise EZSQLException.Create(Format(SIncorrectConnectionURL, [Url])); for I := Low(SupportedProtocols) to High(SupportedProtocols) do begin if SupportedProtocols[I] = Protocol then begin Result := Protocol; Break; end; end; if Result = '' then raise EZSQLException.Create(Format(SUnsupportedProtocol, [Protocol])); end; {** Resolves a database URL and fills the database connection parameters. @param Url an initial database URL. @param Info an initial info parameters. @param HostName a name of the database host. @param Port a port number. @param Database a database name. @param UserName a name of the database user. @param Password a user's password. @param ResutlInfo a result info parameters. } procedure ResolveDatabaseUrl(const Url: string; Info: TStrings; var HostName: string; var Port: Integer; var Database: string; var UserName: string; var Password: string; ResultInfo: TStrings); var Temp: string; begin { assign URL first -> define all out out params } {A correct builded URL exports all these Params if they are expected!} DriverManager.ResolveDatabaseUrl(URL, HostName, Port, DataBase, UserName, Password, ResultInfo); { Retrieves non special-escaped-parameters } Temp := Url; while FirstDelimiter('?', Temp) > 0 do //Get all aditional Parameters Temp := Copy(Temp, FirstDelimiter('?', Temp)+1, Length(Temp)); PutSplitString(ResultInfo, Temp, ';'); //overrides all Strings ResultInfo.Text := StringReplace(ResultInfo.Text, #9, ';', [rfReplaceAll]); //unescape the #9 char if Assigned(Info) then //isn't that strange? (Shouldn't we pick out double-values?) Resultinfo.AddStrings(Info);//All possible PWD/Password and UID/UserName are aviable now, but for what? And the can also be doubled! { Redefines user name if not avialble in the URL} if UserName = '' then //Priority 1: URL.UserName begin UserName := ResultInfo.Values['UID']; //Priority 2: Info-UID if UserName = '' then UserName := ResultInfo.Values['username']; //Priority 3: Info-username end; { Redefines user password if not avialble in the URL } if Password = '' then //Priority 1: URL.Password begin Password := ResultInfo.Values['PWD']; //Priority 2: Info-PWD if Password = '' then Password := ResultInfo.Values['password']; //Priority 3: Info-password end; end; {** Checks is the convertion from one type to another type allowed. @param InitialType an initial data type. @param ResultType a result data type. @return True if convertion is allowed or False otherwise. } function CheckConvertion(InitialType: TZSQLType; ResultType: TZSQLType): Boolean; begin case ResultType of stBoolean, stByte, stShort, stInteger, stLong, stFloat, stDouble, stBigDecimal: Result := InitialType in [stBoolean, stByte, stShort, stInteger, stLong, stFloat, stDouble, stBigDecimal, stString, stUnicodeString]; stString, stUnicodeString: Result := True; stBytes: Result := InitialType in [stString, stUnicodeString, stBytes, stGUID, stAsciiStream, stUnicodeStream, stBinaryStream]; stTimestamp: Result := InitialType in [stString, stUnicodeString, stDate, stTime, stTimestamp]; stDate: Result := InitialType in [stString, stUnicodeString, stDate, stTimestamp]; stTime: Result := InitialType in [stString, stUnicodeString, stTime, stTimestamp]; else Result := (ResultType = InitialType) and (InitialType <> stUnknown); end; end; {** Defines a name of the column type. @param ColumnType a type of the column. @return a name of the specified type. } function DefineColumnTypeName(ColumnType: TZSQLType): string; begin case ColumnType of stBoolean: Result := 'Boolean'; stByte: Result := 'Byte'; stShort: Result := 'Short'; stInteger: Result := 'Integer'; stLong: Result := 'Long'; stFloat: Result := 'Float'; stDouble: Result := 'Double'; stBigDecimal: Result := 'BigDecimal'; stString: Result := 'String'; stUnicodeString: Result := 'UnicodeString'; stBytes: Result := 'Bytes'; stGUID: Result := 'GUID'; stDate: Result := 'Date'; stTime: Result := 'Time'; stTimestamp: Result := 'Timestamp'; stAsciiStream: Result := 'AsciiStream'; stUnicodeStream: Result := 'UnicodeStream'; stBinaryStream: Result := 'BinaryStream'; else Result := 'Unknown'; end; end; {** Raises a copy of the given exception. @param E an exception to be raised. } procedure RaiseSQLException(E: Exception); begin if E is EZSQLException then begin raise EZSQLException.CreateClone(EZSQLException(E)); end else begin raise EZSQLException.Create(E.Message); end; end; {** Copies column information objects from one object list to another one. @param FromList the source object list. @param ToList the destination object list. } procedure CopyColumnsInfo(FromList: TObjectList; ToList: TObjectList); var I: Integer; Current: TZColumnInfo; ColumnInfo: TZColumnInfo; begin for I := 0 to FromList.Count - 1 do begin Current := TZColumnInfo(FromList[I]); ColumnInfo := TZColumnInfo.Create; ColumnInfo.AutoIncrement := Current.AutoIncrement; ColumnInfo.CaseSensitive := Current.CaseSensitive; ColumnInfo.Searchable := Current.Searchable; ColumnInfo.Currency := Current.Currency; ColumnInfo.Nullable := Current.Nullable; ColumnInfo.Signed := Current.Signed; ColumnInfo.ColumnDisplaySize := Current.ColumnDisplaySize; ColumnInfo.ColumnLabel := Current.ColumnLabel; ColumnInfo.ColumnName := Current.ColumnName; ColumnInfo.SchemaName := Current.SchemaName; ColumnInfo.Precision := Current.Precision; ColumnInfo.Scale := Current.Scale; ColumnInfo.TableName := Current.TableName; ColumnInfo.CatalogName := Current.CatalogName; ColumnInfo.ColumnType := Current.ColumnType; ColumnInfo.ReadOnly := Current.ReadOnly; ColumnInfo.Writable := Current.Writable; ColumnInfo.DefinitelyWritable := Current.DefinitelyWritable; ToList.Add(ColumnInfo); end; end; {** Defines a statement specific parameter. @param Statement a statement interface reference. @param ParamName a name of the parameter. @param Default a parameter default value. @return a parameter value or default if nothing was found. } function DefineStatementParameter(Statement: IZStatement; const ParamName: string; const Default: string): string; begin Result := Statement.GetParameters.Values[ParamName]; if Result = '' then Result := Statement.GetConnection.GetParameters.Values[ParamName]; if Result = '' then Result := Default; end; {** ToLikeString returns the given string or if the string is empty it returns '%' @param Value the string @return given Value or '%' } function ToLikeString(const Value: string): string; begin if Value = '' then Result := '%' else Result := Value; end; {** GetSQLHexString returns a valid x'..' database understandable String from binary data @param Value the ansistring-pointer to the binary data @param Length then length of the binary Data @param ODBC a boolean if output result should be with a starting 0x... @returns a valid hex formated unicode-safe string } function GetSQLHexWideString(Value: PAnsiChar; Len: Integer; ODBC: Boolean = False): ZWideString; var HexVal: AnsiString; begin SetLength(HexVal,Len * 2 ); BinToHex(Value, PAnsiChar(HexVal), Len); if ODBC then Result := '0x'+ZWideString(HexVal) else Result := 'x'#39+ZWideString(HexVal)+#39; end; function GetSQLHexAnsiString(Value: PAnsiChar; Len: Integer; ODBC: Boolean = False): RawByteString; var HexVal: RawByteString; begin SetLength(HexVal,Len * 2 ); BinToHex(Value, PAnsiChar(HexVal), Len); if ODBC then Result := '0x'+HexVal else Result := 'x'#39+HexVal+#39; end; function GetSQLHexString(Value: PAnsiChar; Len: Integer; ODBC: Boolean = False): String; begin {$IFDEF UNICODE} Result := GetSQLHexWideString(Value, Len, ODBC); {$ELSE} Result := GetSQLHexAnsiString(Value, Len, ODBC); {$ENDIF} end; {** Returns a FieldSize in Bytes dependend to the FieldType and CharWidth @param TZSQLType the Zeos FieldType @param Integer the Current given FieldLength @param Integer the Current CountOfByte/Char @param Boolean does the Driver returns the FullSizeInBytes @returns Integer the count of AnsiChars for Field.Size * SizeOf(Char) } function GetFieldSize(const SQLType: TZSQLType; ConSettings: PZConSettings; const Precision, CharWidth: Integer; DisplaySize: PInteger = nil; SizeInBytes: Boolean = False): Integer; var TempPrecision: Integer; begin if ( SQLType in [stString, stUnicodeString] ) and ( Precision <> 0 )then begin if SizeInBytes then TempPrecision := Precision div CharWidth else TempPrecision := Precision; if Assigned(DisplaySize) then DisplaySize^ := TempPrecision; if SQLType = stString then //the RowAccessor assumes SizeOf(Char)*Precision+SizeOf(Char) //the Field assumes Precision*SizeOf(Char) {$IFDEF UNICODE} if ConSettings.ClientCodePage.CharWidth >= 2 then //All others > 3 are UTF8 Result := TempPrecision * 2 //add more mem for a reserved thirt byte else //two and one byte AnsiChars are one WideChar Result := TempPrecision {$ELSE} if ( ConSettings.CPType = cCP_UTF8 ) or (ConSettings.CTRL_CP = zCP_UTF8) then Result := TempPrecision * 4 else Result := TempPrecision * CharWidth {$ENDIF} else //stUnicodeString //UTF8 can pickup LittleEndian/BigEndian 4 Byte Chars //the RowAccessor assumes 2*Precision+2! //the Field assumes 2*Precision ??Does it? if CharWidth > 2 then Result := TempPrecision * 2 else Result := TempPrecision; end else Result := Precision; end; function WideStringStream(const AString: WideString): TStream; begin Result := TMemoryStream.Create; Result.Write(PWideChar(AString)^, Length(AString)*2); Result.Position := 0; end; end. ================================================ FILE: lib/zeosdbo/src/parsesql/ZAdoToken.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { String tokenizing classes for MySQL } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZAdoToken; interface {$I ZParseSql.inc} uses Classes, SysUtils, ZTokenizer, ZGenericSqlToken, ZCompatibility; type {** Implements a quote string state object. } TZAdoSQLQuoteState = class (TZQuoteState) public function NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; override; function EncodeString(const Value: string; QuoteChar: Char): string; override; function DecodeString(const Value: string; QuoteChar: Char): string; override; end; {** Implements a default tokenizer object. } TZAdoSQLTokenizer = class (TZGenericSQLTokenizer) public constructor Create; end; implementation { TZAdoSQLQuoteState } {** Return a quoted string token from a reader. This method will collect characters until it sees a match to the character that the tokenizer used to switch to this state. @return a quoted string token from a reader } function TZAdoSQLQuoteState.NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; var ReadChar: Char; LastChar: Char; begin Result.Value := FirstChar; LastChar := #0; while Stream.Read(ReadChar, SizeOf(Char)) > 0 do begin if ((LastChar = FirstChar) and (ReadChar <> FirstChar) and (FirstChar <> '[')) or ((FirstChar = '[') and (LastChar = ']')) then begin Stream.Seek(-SizeOf(Char), soFromCurrent); Break; end; Result.Value := Result.Value + ReadChar; if (LastChar = FirstChar) and (ReadChar = FirstChar) then LastChar := #0 else LastChar := ReadChar; end; if CharInSet(FirstChar, ['"', '[']) then Result.TokenType := ttQuotedIdentifier else Result.TokenType := ttQuoted; end; {** Encodes a string value. @param Value a string value to be encoded. @param QuoteChar a string quote character. @returns an encoded string. } function TZAdoSQLQuoteState.EncodeString(const Value: string; QuoteChar: Char): string; begin if QuoteChar = '[' then Result := '[' + Value + ']' else if CharInSet(QuoteChar, [#39, '"']) then Result := QuoteChar + Value + QuoteChar else Result := Value; end; {** Decodes a string value. @param Value a string value to be decoded. @param QuoteChar a string quote character. @returns an decoded string. } function TZAdoSQLQuoteState.DecodeString(const Value: string; QuoteChar: Char): string; begin Result := Value; if Length(Value) >= 2 then begin if CharInSet(QuoteChar, [#39, '"']) and (Value[1] = QuoteChar) and (Value[Length(Value)] = QuoteChar) then begin if Length(Value) > 2 then Result := AnsiDequotedStr(Value, QuoteChar) else Result := ''; end else if (QuoteChar = '[') and (Value[1] = QuoteChar) and (Value[Length(Value)] = ']') then Result := Copy(Value, 2, Length(Value) - 2) end; end; { TZAdoSQLTokenizer } {** Constructs a tokenizer with a default state table (as described in the class comment). } constructor TZAdoSQLTokenizer.Create; begin EscapeState := TZEscapeState.Create; NumberState := TZNumberState.Create; QuoteState := TZAdoSQLQuoteState.Create; WhitespaceState := TZWhitespaceState.Create; CommentState := TZCppCommentState.Create; SymbolState := TZGenericSQLSymbolState.Create; WordState := TZGenericSQLWordState.Create; SetCharacterState(#0, #32, WhitespaceState); SetCharacterState(#33, #191, SymbolState); SetCharacterState(#192, High(Char), WordState); SetCharacterState('a', 'z', WordState); SetCharacterState('A', 'Z', WordState); SetCharacterState('_', '_', WordState); SetCharacterState('$', '$', WordState); SetCharacterState('@', '@', WordState); SetCharacterState('0', '9', NumberState); SetCharacterState('.', '.', NumberState); SetCharacterState('"', '"', QuoteState); SetCharacterState(#39, #39, QuoteState); SetCharacterState('[', '[', QuoteState); SetCharacterState(']', ']', QuoteState); SetCharacterState('/', '/', CommentState); end; end. ================================================ FILE: lib/zeosdbo/src/parsesql/ZGenericSqlAnalyser.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { SQL Statements Analysing classes } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZGenericSqlAnalyser; interface {$I ZParseSql.inc} uses Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} Contnrs, ZClasses, ZTokenizer, ZSelectSchema, ZCompatibility; type {** Implements a section of the parsed SQL statement. } TZStatementSection = class (TObject) private FName: string; FTokens: TStrings; public constructor Create(const Name: string; Tokens: TStrings); destructor Destroy; override; function Clone: TZStatementSection; property Name: string read FName write FName; property Tokens: TStrings read FTokens; end; {** Implements a publicly available interface to statement analyser. } IZStatementAnalyser = interface(IZInterface) ['{967635B6-411B-4DEF-990C-9C6C01F3DC0A}'] function TokenizeQuery(Tokenizer: IZTokenizer; const SQL: string; Cleanup: Boolean): TStrings; function SplitSections(Tokens: TStrings): TObjectList; function ComposeTokens(Tokens: TStrings): string; function ComposeSections(Sections: TObjectList): string; function DefineSelectSchemaFromSections( Sections: TObjectList): IZSelectSchema; function DefineSelectSchemaFromQuery(Tokenizer: IZTokenizer; const SQL: string): IZSelectSchema; end; {** Implements an SQL statements analyser. } TZGenericStatementAnalyser = class (TZAbstractObject, IZStatementAnalyser) private FSectionNames: TStrings; FSelectOptions: TStrings; FFromJoins: TStrings; FFromClauses: TStrings; protected function ArrayToStrings(const Value: array of string): TStrings; function CheckForKeyword(Tokens: TStrings; TokenIndex: Integer; Keywords: TStrings; var Keyword: string; var WordCount: Integer): Boolean; function FindSectionTokens(Sections: TObjectList; const Name: string): TStrings; procedure FillFieldRefs(SelectSchema: IZSelectSchema; SelectTokens: TStrings); procedure FillTableRefs(SelectSchema: IZSelectSchema; FromTokens: TStrings); function SkipOptionTokens(Tokens: TStrings; var TokenIndex: Integer; Options: TStrings): Boolean; function SkipBracketTokens(Tokens: TStrings; var TokenIndex: Integer): Boolean; property SectionNames: TStrings read FSectionNames write FSectionNames; property SelectOptions: TStrings read FSelectOptions write FSelectOptions; property FromJoins: TStrings read FFromJoins write FFromJoins; property FromClauses: TStrings read FFromClauses write FFromClauses; public constructor Create; destructor Destroy; override; function TokenizeQuery(Tokenizer: IZTokenizer; const SQL: string; Cleanup: Boolean): TStrings; function SplitSections(Tokens: TStrings): TObjectList; function ComposeTokens(Tokens: TStrings): string; function ComposeSections(Sections: TObjectList): string; function DefineSelectSchemaFromSections( Sections: TObjectList): IZSelectSchema; function DefineSelectSchemaFromQuery(Tokenizer: IZTokenizer; const SQL: string): IZSelectSchema; end; implementation uses SysUtils, ZSysUtils; { TZStatementSection } {** Create SQL statement section object. } constructor TZStatementSection.Create(const Name: string; Tokens: TStrings); begin FName := Name; FTokens := Tokens; end; {** Destroys this object and cleanups the memory. } destructor TZStatementSection.Destroy; begin FTokens.Free; inherited Destroy; end; {** Clones an object instance. @return a clonned object instance. } function TZStatementSection.Clone: TZStatementSection; var Temp: TStrings; begin Temp := TStringList.Create; Temp.AddStrings(FTokens); Result := TZStatementSection.Create(FName, Temp); end; const {** The generic constants.} GenericSectionNames: array[0..12] of string = ( 'SELECT', 'UPDATE', 'DELETE', 'INSERT', 'FROM', 'WHERE', 'INTO', 'GROUP*BY', 'HAVING', 'ORDER*BY', 'FOR*UPDATE', 'LIMIT', 'OFFSET' ); GenericSelectOptions: array[0..1] of string = ( 'DISTINCT', 'ALL' ); GenericFromJoins: array[0..5] of string = ( 'NATURAL', 'RIGHT', 'LEFT', 'INNER', 'OUTER', 'JOIN' ); GenericFromClauses: array[0..0] of string = ( 'ON' ); { TZGenericStatementAnalyser } {** Creates the object and assignes the main properties. } constructor TZGenericStatementAnalyser.Create; begin FSectionNames := ArrayToStrings(GenericSectionNames); FSelectOptions := ArrayToStrings(GenericSelectOptions); FFromJoins := ArrayToStrings(GenericFromJoins); FFromClauses := ArrayToStrings(GenericFromClauses); end; {** Destroys this object and cleanups the memory. } destructor TZGenericStatementAnalyser.Destroy; begin FSectionNames.Free; FSelectOptions.Free; FFromJoins.Free; FFromClauses.Free; inherited Destroy; end; {** Converts an array of strings into TStrings object. @param Value an array of strings to be converted. @return a TStrings object with specified strings. } function TZGenericStatementAnalyser.ArrayToStrings( const Value: array of string): TStrings; var I: Integer; begin Result := TStringList.Create; for I := Low(Value) to High(Value) do Result.Add(Value[I]); end; {** Checks for keyword with one, two or three consisted words in the list @param Tokens a list or tokens @param TokenIndex an index of the current token @param Keywords a list of keywords (in uppers case delimited with '*') @param Keyword an out parameter with found keyword. @param WordCount a count of words in the found keyword. } function TZGenericStatementAnalyser.CheckForKeyword(Tokens: TStrings; TokenIndex: Integer; Keywords: TStrings; var Keyword: string; var WordCount: Integer): Boolean; var I: Integer; begin WordCount := 0; Keyword := ''; Result := False; for I := 1 to 3 do begin if (Tokens.Count <= TokenIndex) then Break; if TZTokenType({$IFDEF FPC}Pointer({$ENDIF} Tokens.Objects[TokenIndex]{$IFDEF FPC}){$ENDIF}) <> ttWord then Break; if Keyword <> '' then Keyword := Keyword + '*'; Keyword := Keyword + AnsiUpperCase(Tokens[TokenIndex]); Inc(WordCount); if Keywords.IndexOf(Keyword) >= 0 then begin Result := True; Break; end; Inc(TokenIndex); { Skips whitespaces. } while Tokens.Count > TokenIndex do begin if not (TZTokenType({$IFDEF FPC}Pointer({$ENDIF} Tokens.Objects[TokenIndex]{$IFDEF FPC}){$ENDIF}) in [ttWhitespace, ttComment]) then Break; Inc(TokenIndex); Inc(WordCount); end; end; if not Result then begin WordCount := 0; Keyword := ''; end; end; {** Finds a section by it's name. @param Sections a list of sections. @param Name a name of the section to be found. @return a list of section tokens or null if section is was not found. } function TZGenericStatementAnalyser.FindSectionTokens( Sections: TObjectList; const Name: string): TStrings; var I: Integer; Current: TZStatementSection; begin Result := nil; for I := 0 to Sections.Count - 1 do begin Current := TZStatementSection(Sections[I]); if Current.Name = Name then begin Result := Current.Tokens; Break; end; end; end; {** Tokenizes a given SQL query into a list of tokens with tokenizer. @param Tokenizer a tokenizer object. @param SQL a SQL query to be tokenized. @return a list with tokens. } function TZGenericStatementAnalyser.TokenizeQuery( Tokenizer: IZTokenizer; const SQL: string; Cleanup: Boolean): TStrings; begin if Cleanup then begin Result := Tokenizer.TokenizeBufferToList(SQL, [toSkipEOF, toSkipComments, toUnifyWhitespaces]) end else Result := Tokenizer.TokenizeBufferToList(SQL, [toSkipEOF]); end; {** Splits a given list of tokens into the list named sections. @param Tokens a list of tokens. @return a list of section names where object property contains a list of tokens in the section. It initial list is not started with a section name the first section is unnamed (''). } function TZGenericStatementAnalyser.SplitSections(Tokens: TStrings): TObjectList; var I: Integer; Keyword: string; WordCount: Integer; TokenIndex: Integer; Elements: TStrings; FoundSection: Boolean; BracketCount: Integer; begin Result := TObjectList.Create; TokenIndex := 0; FoundSection := True; Elements := nil; CheckForKeyword(Tokens, TokenIndex, SectionNames, Keyword, WordCount); while TokenIndex < Tokens.Count do begin if FoundSection then begin Elements := TStringList.Create; for I := 0 to WordCount - 1 do begin Elements.AddObject(Tokens[TokenIndex + I], Tokens.Objects[TokenIndex + I]); end; Inc(TokenIndex, WordCount); Result.Add(TZStatementSection.Create(Keyword, Elements)); end; FoundSection := CheckForKeyword(Tokens, TokenIndex, SectionNames, Keyword, WordCount); if not FoundSection and (TokenIndex < Tokens.Count) then begin BracketCount := 0; repeat Elements.AddObject(Tokens[TokenIndex], Tokens.Objects[TokenIndex]); if Tokens[TokenIndex] = '(' then Inc(BracketCount) else if Tokens[TokenIndex] = ')' then Dec(BracketCount); Inc(TokenIndex); until (BracketCount <= 0) or (TokenIndex >= Tokens.Count); end; end; end; {** Composes a string from the list of tokens. @param Tokens a list of tokens. @returns a composes string. } function TZGenericStatementAnalyser.ComposeTokens(Tokens: TStrings): string; begin Result := ComposeString(Tokens, ''); end; {** Composes a string from the list of statement sections. @param Tokens a list of statement sections. @returns a composes string. } function TZGenericStatementAnalyser.ComposeSections(Sections: TObjectList): string; var I: Integer; begin Result := ''; for I := 0 to Sections.Count - 1 do Result := Result + ComposeTokens(TZStatementSection(Sections[I]).Tokens); end; {** Skips tokens inside brackets. @param Tokens a list of tokens to scan. @param TokenIndex the index of the current token. @return true if some tokens were skipped. } function TZGenericStatementAnalyser.SkipBracketTokens(Tokens: TStrings; var TokenIndex: Integer): Boolean; var BracketCount: Integer; Current: string; begin { Checks for the start bracket. } if (TokenIndex < Tokens.Count) and (Tokens[TokenIndex] <> '(') then begin Result := False; Exit; end; { Skips the expression in brackets. } Result := True; BracketCount := 1; Inc(TokenIndex); while (TokenIndex < Tokens.Count) and (BracketCount > 0) do begin Current := Tokens[TokenIndex]; if Current = '(' then Inc(BracketCount) else if Current = ')' then Dec(BracketCount); Inc(TokenIndex); end; end; {** Skips option tokens specified in the string list. @param Tokens a list of tokens to scan. @param TokenIndex the index of the current token. @param Options a list of option keyword strings in the upper case. @return true if some tokens were skipped. } function TZGenericStatementAnalyser.SkipOptionTokens(Tokens: TStrings; var TokenIndex: Integer; Options: TStrings): Boolean; begin Result := False; while TokenIndex < Tokens.Count do begin if not (TZTokenType({$IFDEF FPC}Pointer({$ENDIF} Tokens.Objects[TokenIndex]{$IFDEF FPC}){$ENDIF}) in [ttWhitespace, ttComment]) and (Options.IndexOf(AnsiUpperCase(Tokens[TokenIndex])) < 0) then begin Break; end; Inc(TokenIndex); Result := True; end; end; {** Fills select schema with field references. @param SelectSchema a select schema object. @param SelectTokens a list of tokens in select section. } procedure TZGenericStatementAnalyser.FillFieldRefs( SelectSchema: IZSelectSchema; SelectTokens: TStrings); var TokenIndex: Integer; Catalog: string; Schema: string; Table: string; Field: string; Alias: string; CurrentValue: string; CurrentType: TZTokenType; CurrentUpper: string; ReadField: Boolean; HadWhitespace : Boolean; LastWasBracketSection: Boolean; CurrentUpperIs_AS: Boolean; //place holder to avoid compare the token twice procedure ClearElements; begin Catalog := ''; Schema := ''; Table := ''; Field := ''; Alias := ''; ReadField := True; LastWasBracketSection := False; end; { improve fail of fieldname detection if whitespaces and non ttWord or ttQuotedIdentifier previously detected f.e.: select first 100 skip 10 field1, field2} function CheckNextTokenForCommaAndWhiteSpaces: Boolean; var CurrentValue: string; CurrentType: TZTokenType; I: Integer; begin Result := False; I := 1; //Check to right side to avoid wrong alias detection while SelectTokens.Count > TokenIndex +i do begin CurrentValue := SelectTokens[TokenIndex+i]; CurrentType := TZTokenType({$IFDEF FPC}Pointer({$ENDIF} SelectTokens.Objects[TokenIndex+i]{$IFDEF FPC}){$ENDIF}); if CurrentType in [ttWhiteSpace, ttSymbol] then begin if (CurrentValue = ',') then begin Result := True; Break; end; end else break; Inc(i); end; if Result then begin i := 1; while Tokenindex - i > 0 do if TZTokenType({$IFDEF FPC}Pointer({$ENDIF} SelectTokens.Objects[TokenIndex-i]{$IFDEF FPC}){$ENDIF}) = ttWhiteSpace then Inc(i) else Break; Result := Result and (TokenIndex - I > 0) and not ( TZTokenType({$IFDEF FPC}Pointer({$ENDIF} SelectTokens.Objects[TokenIndex-i]{$IFDEF FPC}){$ENDIF}) = ttWord ); end; end; begin TokenIndex := 1; SkipOptionTokens(SelectTokens, TokenIndex, Self.SelectOptions); ClearElements; while TokenIndex < SelectTokens.Count do begin CurrentValue := SelectTokens[TokenIndex]; CurrentUpper := AnsiUpperCase(CurrentValue); CurrentType := TZTokenType({$IFDEF FPC}Pointer({$ENDIF} SelectTokens.Objects[TokenIndex]{$IFDEF FPC}){$ENDIF}); { Switches to alias part. } CurrentUpperIs_AS := (CurrentUpper = 'AS'); if (CurrentType = ttWhitespace) or CurrentUpperIs_AS then ReadField := ReadField and (Field = '') and not CurrentUpperIs_AS { Reads field. } else if ReadField and ((CurrentType = ttWord) or (CurrentType = ttQuotedIdentifier) or (CurrentValue = '*')) then begin Catalog := Schema; Schema := Table; Table := Field; Field := CurrentValue; end { Skips a '.' in field part. } else if ReadField and (CurrentValue = '.') then begin end { Reads alias. } else if not ReadField and (CurrentType in [ttWord, ttQuotedIdentifier]) then Alias := CurrentValue { Ends field reading. } else if CurrentValue = ',' then begin if Field <> '' then SelectSchema.AddField(TZFieldRef.Create(True, Catalog, Schema, Table, Field, Alias, nil)); ClearElements; end { Skips till the next field. } else begin ClearElements; HadWhitespace := False; while (TokenIndex < SelectTokens.Count) and (CurrentValue <> ',') do begin CurrentValue := SelectTokens[TokenIndex]; if CurrentValue = '(' then begin SkipBracketTokens(SelectTokens, TokenIndex); LastWasBracketSection := True; end else begin CurrentType := TZTokenType({$IFDEF FPC}Pointer({$ENDIF} SelectTokens.Objects[TokenIndex]{$IFDEF FPC}){$ENDIF}); if HadWhitespace and (CurrentType in [ttWord, ttQuotedIdentifier]) then if not LastWasBracketSection and CheckNextTokenForCommaAndWhiteSpaces then Break else Alias := CurrentValue else if not (CurrentType in [ttWhitespace, ttComment]) and (CurrentValue <> ',') then Alias := '' else if CurrentType = ttWhitespace then HadWhitespace := true; Inc(TokenIndex); end; end; if Alias <> '' then begin SelectSchema.AddField(TZFieldRef.Create(False, '', '', '', '', Alias, nil)); ClearElements; end; Dec(TokenIndex); // go back 1 token(Because of Inc in next lines) end; Inc(TokenIndex); end; { Creates a reference to the last processed field. } if Field <> '' then begin SelectSchema.AddField(TZFieldRef.Create(True, Catalog, Schema, Table, Field, Alias, nil)); end; end; {** Fills select schema with table references. @param SelectSchema a select schema object. @param FromTokens a list of tokens in from section. } {$HINTS OFF} procedure TZGenericStatementAnalyser.FillTableRefs( SelectSchema: IZSelectSchema; FromTokens: TStrings); var TokenIndex: Integer; Catalog: string; Schema: string; Table: string; Alias: string; CurrentValue: string; CurrentType: TZTokenType; CurrentUpper: string; ReadTable: Boolean; procedure ClearElements; begin Catalog := ''; Schema := ''; Table := ''; Alias := ''; ReadTable := True; end; begin TokenIndex := 1; ClearElements; while TokenIndex < FromTokens.Count do begin CurrentValue := FromTokens[TokenIndex]; CurrentUpper := AnsiUpperCase(CurrentValue); CurrentType := TZTokenType({$IFDEF FPC}Pointer({$ENDIF} FromTokens.Objects[TokenIndex]{$IFDEF FPC}){$ENDIF}); { Processes from join keywords. } if FromJoins.IndexOf(CurrentUpper) >= 0 then begin if Table <> '' then SelectSchema.AddTable(TZTableRef.Create(Catalog, Schema, Table, Alias)); ClearElements; SkipOptionTokens(FromTokens, TokenIndex, FromJoins); Continue; end { Skips from clause keywords. } else if FromClauses.IndexOf(CurrentUpper) >= 0 then begin Inc(TokenIndex); CurrentValue := FromTokens[TokenIndex]; CurrentUpper := AnsiUpperCase(CurrentValue); while (TokenIndex < FromTokens.Count) and (FromJoins.IndexOf(CurrentUpper) < 0) and (CurrentUpper <> ',') do begin if CurrentUpper = '(' then SkipBracketTokens(FromTokens, TokenIndex) else Inc(TokenIndex); if TokenIndex < FromTokens.Count then begin CurrentValue := FromTokens[TokenIndex]; CurrentUpper := AnsiUpperCase(CurrentValue); CurrentType := TZTokenType({$IFDEF FPC}Pointer({$ENDIF} FromTokens.Objects[TokenIndex]{$IFDEF FPC}){$ENDIF}); end; end; // We must jump 1 tokens back now when we stopped on a Join clause. // Otherwise the next table is skipped if FromJoins.IndexOf(CurrentUpper) >= 0 then begin Dec(TokenIndex); CurrentValue := FromTokens[TokenIndex]; CurrentUpper := AnsiUpperCase(CurrentValue); end; end { Switches to alias part. } else if (CurrentType = ttWhitespace) or (CurrentUpper = 'AS') then begin ReadTable := ReadTable and (Table = '') and (CurrentUpper <> 'AS'); end { Reads table. } else if ReadTable and ((CurrentType = ttWord) or (CurrentType = ttQuotedIdentifier)) then begin {Catalog := Schema; Schema := Table;} Table := CurrentValue; end { Skips a '.' in table part. } else if ReadTable and (CurrentValue = '.') then begin Catalog := Schema; Schema := Table; Table := ''; end { Reads alias. } else if not ReadTable and (CurrentType = ttWord) then begin Alias := CurrentValue; end; { Ends field reading. } if CurrentValue = ',' then begin if Table <> '' then SelectSchema.AddTable(TZTableRef.Create(Catalog, Schema, Table, Alias)); ClearElements; end; { Skips till the next field. } if CurrentValue = '(' then SkipBracketTokens(FromTokens, TokenIndex) else Inc(TokenIndex); end; { Creates a reference to the last processed field. } if Table <> '' then SelectSchema.AddTable(TZTableRef.Create(Catalog, Schema, Table, Alias)); end; {$HINTS ON} {** Extracts a select schema from the specified parsed select statement. @param Sections a list of sections. @return a select statement schema. } function TZGenericStatementAnalyser.DefineSelectSchemaFromSections( Sections: TObjectList): IZSelectSchema; var SelectTokens: TStrings; FromTokens: TStrings; begin Result := nil; { Checks for the correct select statement. } if (Sections.Count < 2) or not ((TZStatementSection(Sections[0]).Name = 'SELECT') or ((TZStatementSection(Sections[0]).Name = '') and (TZStatementSection(Sections[1]).Name = 'SELECT'))) then Exit; { Defins sections. } SelectTokens := FindSectionTokens(Sections, 'SELECT'); FromTokens := FindSectionTokens(Sections, 'FROM'); if (SelectTokens = nil) or (FromTokens = nil) then Exit; { Creates and fills the result object. } Result := TZSelectSchema.Create; FillFieldRefs(Result, SelectTokens); FillTableRefs(Result, FromTokens); end; {** Defines a select schema from the specified SQL query. @param Tokenizer a tokenizer object. @param SQL a SQL query. @return a select statement schema. } function TZGenericStatementAnalyser.DefineSelectSchemaFromQuery( Tokenizer: IZTokenizer; const SQL: string): IZSelectSchema; var Tokens: TStrings; Sections: TObjectList; begin Tokens := TokenizeQuery(Tokenizer, SQL, True); Sections := SplitSections(Tokens); try Result := DefineSelectSchemaFromSections(Sections); finally Tokens.Free; Sections.Free; end; end; end. ================================================ FILE: lib/zeosdbo/src/parsesql/ZGenericSqlToken.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { String tokenizing classes for Generic SQL } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZGenericSqlToken; interface {$I ZParseSql.inc} uses Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, ZTokenizer, ZCompatibility; type {** Implements a symbol state object. } TZGenericSQLSymbolState = class (TZSymbolState) public constructor Create; end; {** Implements a word state object. } TZGenericSQLWordState = class (TZWordState) public constructor Create; function NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; override; end; {** Implements a quote string state object. } TZGenericSQLQuoteState = class (TZQuoteState) public function NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; override; function EncodeString(const Value: string; QuoteChar: Char): string; override; function DecodeString(const Value: string; QuoteChar: Char): string; override; end; {** Implements a default tokenizer object. } TZGenericSQLTokenizer = class (TZTokenizer) public constructor Create; end; implementation { TZGenericSQLSymbolState } {** Creates this SQL-specific symbol state object. } constructor TZGenericSQLSymbolState.Create; begin inherited Create; Add('<='); Add('>='); Add('<>'); Add('<<'); Add('>>'); end; { TZGenericSQLWordState } {** Constructs this SQL-specific word state object. } constructor TZGenericSQLWordState.Create; begin SetWordChars(#0, #191, False); SetWordChars(#192, high(char), True); SetWordChars('a', 'z', True); SetWordChars('A', 'Z', True); SetWordChars('0', '9', True); SetWordChars('$', '$', True); SetWordChars('_', '_', True); end; const {** List of keywords. } Keywords: array [0..8] of string = ( 'AND','OR','NOT','XOR','LIKE','IS','NULL','TRUE','FALSE' ); {** Gets a word tokens or special operators. @return a processed token. } function TZGenericSQLWordState.NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; var I: Integer; Temp: string; begin Result := inherited NextToken(Stream, FirstChar, Tokenizer); Temp := UpperCase(Result.Value); for I := Low(Keywords) to High(Keywords) do begin if Temp = Keywords[I] then begin Result.TokenType := ttKeyword; Break; end; end; end; { TZGenericSQLQuoteState } {** Return a quoted string token from a reader. This method will collect characters until it sees a match to the character that the tokenizer used to switch to this state. @return a quoted string token from a reader } {$IFDEF FPC} {$HINTS OFF} {$ENDIF} function TZGenericSQLQuoteState.NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; var ReadChar: Char; LastChar: Char; ReadCounter, NumericCounter, CountDoublePoint, CountSlash, CountSpace : integer; begin Result.Value := FirstChar; LastChar := #0; CountDoublePoint := 0; CountSlash := 0; CountSpace := 0; ReadCounter := 0; NumericCounter := 0; while Stream.Read(ReadChar, SizeOf(Char)) > 0 do begin if (LastChar = FirstChar) and (ReadChar <> FirstChar) then begin Stream.Seek(-SizeOf(Char), soFromCurrent); Break; end; if ReadChar = {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}TimeSeparator then inc(CountDoublePoint) else if ReadChar = {$IFDEF WITH_FORMATSETTINGS}FormatSettings.{$ENDIF}DateSeparator then inc(CountSlash) else if ReadChar = ' ' then inc(CountSpace) else if CharInSet(ReadChar, ['0'..'9']) then inc(NumericCounter); Inc(ReadCounter); Result.Value := Result.Value + ReadChar; if (LastChar = FirstChar) and (ReadChar = FirstChar) then LastChar := #0 else LastChar := ReadChar; end; if FirstChar = '"' then Result.TokenType := ttWord else Result.TokenType := ttQuoted; // Time constant if (CountDoublePoint = 2) and (CountSlash = 0) and ((NumericCounter + CountDoublePoint) = ReadCounter-1) then begin try if StrToTimeDef(DecodeString(Result.Value, FirstChar), 0) = 0 then Exit; Result.Value := DecodeString(Result.Value,'"'); Result.TokenType := ttTime; except end; end; // Date constant if (CountDoublePoint = 0) and (CountSlash = 2) and ((NumericCounter + CountSlash) = ReadCounter-1) then begin try if StrToDateDef(DecodeString(Result.Value, FirstChar), 0) = 0 then Exit; Result.Value := DecodeString(Result.Value,'"'); Result.TokenType := ttDate; except end; end; // DateTime constant if (CountDoublePoint = 2) and (CountSlash = 2) and ((NumericCounter + CountDoublePoint + CountSlash + CountSpace) = ReadCounter-1) then begin try if StrToDateTimeDef(DecodeString(Result.Value, FirstChar), 0) = 0 then Exit; Result.Value := DecodeString(Result.Value,'"'); Result.TokenType := ttDateTime; except end; end; if not ( Result.TokenType in [ttQuoted, ttWord] ) then Exit; //No System-defaults found, Check for SQL format; {AStamp := TimestampStrToDateTime(DecodeString(Result.Value, FirstChar)); //minimize the handling if AStamp = 0 then Exit else if ( TDate(AStamp) <> EmptyDate ) then if ( TTime(AStamp) <> EmptyTime ) then begin Result.Value := DateTimeToStr(AStamp); Result.TokenType := ttDateTime; end else begin Result.Value := DateToStr(AStamp); Result.TokenType := ttDate; end else if ( TTime(AStamp) <> EmptyTime ) then begin Result.Value := TimeToStr(AStamp); Result.TokenType := ttTime; end;} end; {$IFDEF FPC} {$HINTS ON} {$ENDIF} {** Encodes a string value. @param Value a string value to be encoded. @param QuoteChar a string quote character. @returns an encoded string. } function TZGenericSQLQuoteState.EncodeString(const Value: string; QuoteChar: Char): string; begin if CharInSet(QuoteChar, [#39, '"', '`']) then Result := AnsiQuotedStr(Value, QuoteChar) else Result := Value; end; {** Decodes a string value. @param Value a string value to be decoded. @param QuoteChar a string quote character. @returns an decoded string. } function TZGenericSQLQuoteState.DecodeString(const Value: string; QuoteChar: Char): string; var Len: Integer; begin Len := Length(Value); if (Len >= 2) and CharInSet(QuoteChar, [#39, '"', '`']) and (Value[1] = QuoteChar) and (Value[Len] = QuoteChar) then begin if Len > 2 then Result := AnsiDequotedStr(Value, QuoteChar) else Result := ''; end else Result := Value; end; { TZGenericSQLTokenizer } {** Constructs a tokenizer with a default state table (as described in the class comment). } constructor TZGenericSQLTokenizer.Create; begin NumberState := TZNumberState.Create; QuoteState := TZGenericSQLQuoteState.Create; WhitespaceState := TZWhitespaceState.Create; CommentState := TZCppCommentState.Create; SymbolState := TZGenericSQLSymbolState.Create; WordState := TZGenericSQLWordState.Create; SetCharacterState(#0, #32, WhitespaceState); SetCharacterState(#33, #191, SymbolState); SetCharacterState(#192, High(Char), WordState); SetCharacterState('a', 'z', WordState); SetCharacterState('A', 'Z', WordState); SetCharacterState('_', '_', WordState); SetCharacterState('$', '$', WordState); SetCharacterState('0', '9', NumberState); SetCharacterState('.', '.', NumberState); SetCharacterState('"', '"', QuoteState); SetCharacterState(#39, #39, QuoteState); SetCharacterState('`', '`', QuoteState); SetCharacterState('/', '/', CommentState); end; end. ================================================ FILE: lib/zeosdbo/src/parsesql/ZInterbaseAnalyser.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { SQL Statements Analysing classes } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZInterbaseAnalyser; interface {$I ZParseSql.inc} uses Classes, ZGenericSqlAnalyser; type {** Implements an Interbase statements analyser. } TZInterbaseStatementAnalyser = class (TZGenericStatementAnalyser) end; implementation end. ================================================ FILE: lib/zeosdbo/src/parsesql/ZInterbaseToken.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { String tokenizing classes for Interbase } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZInterbaseToken; interface {$I ZParseSql.inc} uses Classes, ZTokenizer, ZGenericSqlToken, ZPostgreSqlToken; type {** Implements a Interbase-specific number state object. } TZInterbaseNumberState = class (TZPostgreSQLNumberState) end; {** Implements a Interbase-specific quote string state object. } TZInterbaseQuoteState = class (TZGenericSQLQuoteState) end; {** This state will either delegate to a comment-handling state, or return a token with just a slash in it. } TZInterbaseCommentState = class (TZCCommentState) end; {** Implements a symbol state object. } TZInterbaseSymbolState = class (TZSymbolState) public constructor Create; end; {** Implements a word state object. } TZInterbaseWordState = class (TZGenericSQLWordState) public constructor Create; end; {** Implements a default tokenizer object. } TZInterbaseTokenizer = class (TZTokenizer) public constructor Create; end; implementation { TZInterbaseSymbolState } {** Creates this Interbase-specific symbol state object. } constructor TZInterbaseSymbolState.Create; begin inherited Create; Add('<='); Add('>='); Add('<>'); Add('!='); Add('!<'); Add('!>'); end; { TZInterbaseWordState } {** Constructs this Interbase-specific word state object. } constructor TZInterbaseWordState.Create; begin SetWordChars(#0, #255, False); SetWordChars('a', 'z', True); SetWordChars('A', 'Z', True); SetWordChars('0', '9', True); SetWordChars('_', '_', True); SetWordChars('$', '$', True); end; { TZInterbaseTokenizer } { TZInterbaseTokenizer } constructor TZInterbaseTokenizer.Create; begin EscapeState := TZEscapeState.Create; WhitespaceState := TZWhitespaceState.Create; SymbolState := TZInterbaseSymbolState.Create; NumberState := TZInterbaseNumberState.Create; QuoteState := TZInterbaseQuoteState.Create; WordState := TZInterbaseWordState.Create; CommentState := TZInterbaseCommentState.Create; SetCharacterState(#0, #32, WhitespaceState); SetCharacterState(#33, #191, SymbolState); SetCharacterState(#192, High(Char), WordState); SetCharacterState('a', 'z', WordState); SetCharacterState('A', 'Z', WordState); SetCharacterState('_', '_', WordState); SetCharacterState('$', '$', WordState); SetCharacterState('0', '9', NumberState); SetCharacterState('.', '.', NumberState); SetCharacterState('"', '"', QuoteState); SetCharacterState(#39, #39, QuoteState); SetCharacterState('/', '/', CommentState); end; end. ================================================ FILE: lib/zeosdbo/src/parsesql/ZMySqlAnalyser.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { SQL Statements Analysing classes } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZMySqlAnalyser; interface {$I ZParseSql.inc} uses Classes, ZGenericSqlAnalyser; type {** Implements an MySQL statements analyser. } TZMySQLStatementAnalyser = class (TZGenericStatementAnalyser) public constructor Create; end; implementation const {** The generic constants.} MySQLSectionNames: array[0..16] of string = ( 'SELECT', 'UPDATE', 'DELETE', 'INSERT', 'FROM', 'WHERE', 'INTO', 'GROUP*BY', 'HAVING', 'ORDER*BY', 'FOR*UPDATE', 'LIMIT', 'OFFSET', 'INTO*OUTFILE', 'INTO*DUMPFILE', 'PROCEDURE', 'LOCK*IN*SHARE' ); MySQLSelectOptions: array[0..7] of string = ( 'DISTINCT', 'ALL', 'DISTINCTROW', 'STRAIGHT_JOIN', 'SQL_SMALL_RESULT', 'SQL_BIG_RESULT', 'SQL_BUFFER_RESULT', 'HIGH_PRIORITY' ); MySQLFromJoins: array[0..7] of string = ( 'NATURAL', 'RIGHT', 'LEFT', 'INNER', 'OUTER', 'JOIN', 'STRAIGHT_JOIN', 'CROSS' ); MySQLFromClauses: array[0..3] of string = ( 'ON', 'USING', 'USE', 'IGNORE' ); { TZMySQLStatementAnalyser } {** Creates the object and assignes the main properties. } constructor TZMySQLStatementAnalyser.Create; begin SectionNames := ArrayToStrings(MySQLSectionNames); SelectOptions := ArrayToStrings(MySQLSelectOptions); FromJoins := ArrayToStrings(MySQLFromJoins); FromClauses := ArrayToStrings(MySQLFromClauses); end; end. ================================================ FILE: lib/zeosdbo/src/parsesql/ZMySqlToken.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { String tokenizing classes for MySQL } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZMySqlToken; interface {$I ZParseSql.inc} uses Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, ZSysUtils, ZTokenizer, ZGenericSqlToken, ZCompatibility; type {** Implements a MySQL-specific number state object. } TZMySQLNumberState = class (TZNumberState) public function NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; override; end; {** Implements a MySQL-specific quote string state object. } TZMySQLQuoteState = class (TZQuoteState) public function NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; override; function EncodeString(const Value: string; QuoteChar: Char): string; override; function DecodeString(const Value: string; QuoteChar: Char): string; override; end; {** This state will either delegate to a comment-handling state, or return a token with just a slash in it. } TZMySQLCommentState = class (TZCppCommentState) public function NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; override; end; {** Implements a symbol state object. } TZMySQLSymbolState = class (TZSymbolState) public constructor Create; end; {** Implements a word state object. } TZMySQLWordState = class (TZGenericSQLWordState) public constructor Create; end; {** Implements a default tokenizer object. } TZMySQLTokenizer = class (TZTokenizer) public constructor Create; end; implementation uses StrUtils; { TZMySQLNumberState } {** Return a number token from a reader. @return a number token from a reader } function TZMySQLNumberState.NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; var HexDecimal: Boolean; FloatPoint: Boolean; LastChar: Char; function ReadHexDigits: string; begin Result := ''; LastChar := #0; while Stream.Read(LastChar, SizeOf(Char)) > 0 do begin if CharInSet(LastChar, ['0'..'9','a'..'f','A'..'F']) then begin Result := Result + LastChar; HexDecimal := HexDecimal or CharInSet(LastChar, ['a'..'f','A'..'F']); LastChar := #0; end else begin Stream.Seek(-SizeOf(Char), soFromCurrent); Break; end; end; end; function ReadDecDigits: string; begin Result := ''; LastChar := #0; while Stream.Read(LastChar, SizeOf(Char)) > 0 do begin if CharInSet(LastChar, ['0'..'9']) then begin Result := Result + LastChar; LastChar := #0; end else begin Stream.Seek(-SizeOf(Char), soFromCurrent); Break; end; end; end; begin HexDecimal := False; FloatPoint := FirstChar = '.'; Result.Value := FirstChar; Result.TokenType := ttUnknown; LastChar := #0; { Reads the first part of the number before decimal point } if not FloatPoint then begin Result.Value := Result.Value + ReadDecDigits; FloatPoint := (LastChar = '.') and not HexDecimal; if FloatPoint then begin Stream.Read(LastChar, SizeOf(Char)); Result.Value := Result.Value + LastChar; end; end; { Reads the second part of the number after decimal point } if FloatPoint then Result.Value := Result.Value + ReadDecDigits; { Reads a power part of the number } if not HexDecimal and CharInSet(LastChar, ['e','E']) then begin Stream.Read(LastChar, SizeOf(Char)); Result.Value := Result.Value + LastChar; FloatPoint := True; Stream.Read(LastChar, SizeOf(Char)); if CharInSet(LastChar, ['0'..'9','-','+']) then Result.Value := Result.Value + LastChar + ReadDecDigits else begin Result.Value := Copy(Result.Value, 1, Length(Result.Value) - 1); Stream.Seek(-2*SizeOf(Char), soFromCurrent); end; end; { Reads the nexdecimal number } if (Result.Value = '0') and CharInSet(LastChar, ['x','X']) then begin Stream.Read(LastChar, SizeOf(Char)); Result.Value := Result.Value + LastChar + ReadHexDigits; HexDecimal := True; end; { Prepare the result } if Result.Value = '.' then begin if Tokenizer.SymbolState <> nil then Result := Tokenizer.SymbolState.NextToken(Stream, FirstChar, Tokenizer); end else begin if HexDecimal then Result.TokenType := ttHexDecimal else if FloatPoint then Result.TokenType := ttFloat else Result.TokenType := ttInteger; end; end; { TZMySQLQuoteState } {** Return a quoted string token from a reader. This method will collect characters until it sees a match to the character that the tokenizer used to switch to this state. @return a quoted string token from a reader } function TZMySQLQuoteState.NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; const BackSlash = Char('\'); var ReadChar: Char; LastChar: Char; //QuoteChar: Char; //QuoteCount: Integer; begin Result.Value := FirstChar; //QuoteCount := 1; If FirstChar = '`' then Result.TokenType := ttQuotedIdentifier Else Result.TokenType := ttQuoted; //QuoteChar := FirstChar; LastChar := #0; while Stream.Read(ReadChar, SizeOf(Char)) > 0 do begin //if ReadChar = QuoteChar then Inc(QuoteCount); if (LastChar = FirstChar) and (ReadChar <> FirstChar) then begin //if QuoteCount mod 2 = 0 then // only valid for Pascal AnsiQuoted/QuotedStr begin Stream.Seek(-SizeOf(Char), soFromCurrent); Break; end; end; Result.Value := Result.Value + ReadChar; if LastChar = BackSlash then // begin // if Readchar = FirstChar then Inc(QuoteCount); //Escaped single Quote (A QuoteChar instead of FirstChar would be better..) LastChar := #0 // end else if (LastChar = FirstChar) and (ReadChar = FirstChar) then LastChar := #0 else LastChar := ReadChar; end; end; {** Encodes a string value. @param Value a string value to be encoded. @param QuoteChar a string quote character. @returns an encoded string. } function TZMySQLQuoteState.EncodeString(const Value: string; QuoteChar: Char): string; begin if CharInSet(QuoteChar, [#39, '"', '`']) then Result := QuoteChar + EncodeCString(Value) + QuoteChar else Result := Value; end; {** Decodes a string value. @param Value a string value to be decoded. @param QuoteChar a string quote character. @returns an decoded string. } function TZMySQLQuoteState.DecodeString(const Value: string; QuoteChar: Char): string; var Len: Integer; begin Len := Length(Value); if (Len >= 2) and CharInSet(QuoteChar, [#39, '"', '`']) and (Value[1] = QuoteChar) and (Value[Len] = QuoteChar) then begin if Len > 2 then Result := DecodeCString(Copy(Value, 2, Len - 2)) else Result := ''; end else Result := Value; end; { TZMySQLCommentState } {** Gets a MySQL specific comments like # or /* */. @return either just a slash token, or the results of delegating to a comment-handling state } function TZMySQLCommentState.NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; var ReadChar: Char; ReadNum, ReadNum2: Integer; begin Result.TokenType := ttUnknown; Result.Value := FirstChar; if FirstChar = '-' then begin ReadNum := Stream.Read(ReadChar, SizeOf(Char)); if (ReadNum > 0) and (ReadChar = '-') then begin Result.TokenType := ttComment; Result.Value := '--' + GetSingleLineComment(Stream); end else begin if ReadNum > 0 then Stream.Seek(-SizeOf(Char), soFromCurrent); end; end else if FirstChar = '#' then begin Result.TokenType := ttComment; Result.Value := '#' + GetSingleLineComment(Stream); end else if FirstChar = '/' then begin ReadNum := Stream.Read(ReadChar, SizeOf(Char)); if (ReadNum > 0) and (ReadChar = '*') then begin ReadNum2 := Stream.Read(ReadChar, SizeOf(Char)); // Don't treat '/*!' comments as normal comments!! if (ReadNum2 > 0) and (ReadChar <> '!') then begin Result.TokenType := ttComment; Result.Value := '/*'+ReadChar + GetMultiLineComment(Stream); end else begin if ReadNum2 > 0 then Result.TokenType := ttSymbol; Result.Value := '/*!' + GetMultiLineComment(Stream); end; end else begin if ReadNum > 0 then Stream.Seek(-SizeOf(Char), soFromCurrent); end; end; if (Result.TokenType = ttUnknown) and (Tokenizer.SymbolState <> nil) then Result := Tokenizer.SymbolState.NextToken(Stream, FirstChar, Tokenizer); end; { TZMySQLSymbolState } {** Creates this MySQL-specific symbol state object. } constructor TZMySQLSymbolState.Create; begin inherited Create; Add('<='); Add('>='); Add('<>'); Add('<<'); Add('>>'); {BEGIN PATCH: added by fduenas} Add(':='); {END PATCH: added by fduenas} end; { TZMySQLWordState } {** Constructs this MySQL-specific word state object. } constructor TZMySQLWordState.Create; begin SetWordChars(#0, #191, False); SetWordChars(#192, high(char), True); SetWordChars('a', 'z', True); SetWordChars('A', 'Z', True); SetWordChars('0', '9', True); SetWordChars('$', '$', True); SetWordChars('_', '_', True); end; { TZMySQLTokenizer } {** Constructs a tokenizer with a default state table (as described in the class comment). } constructor TZMySQLTokenizer.Create; begin WhitespaceState := TZWhitespaceState.Create; EscapeState := TZEscapeState.Create; SymbolState := TZMySQLSymbolState.Create; NumberState := TZMySQLNumberState.Create; QuoteState := TZMySQLQuoteState.Create; WordState := TZMySQLWordState.Create; CommentState := TZMySQLCommentState.Create; SetCharacterState(#0, #32, WhitespaceState); SetCharacterState(#33, #191, SymbolState); SetCharacterState(#192, High(Char), WordState); SetCharacterState('a', 'z', WordState); SetCharacterState('A', 'Z', WordState); SetCharacterState('_', '_', WordState); SetCharacterState('$', '$', WordState); SetCharacterState('0', '9', NumberState); SetCharacterState('.', '.', NumberState); SetCharacterState('"', '"', QuoteState); SetCharacterState(#39, #39, QuoteState); SetCharacterState('`', '`', QuoteState); SetCharacterState('/', '/', CommentState); SetCharacterState('#', '#', CommentState); SetCharacterState('-', '-', CommentState); end; end. ================================================ FILE: lib/zeosdbo/src/parsesql/ZOracleAnalyser.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { SQL Statements Analysing classes } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZOracleAnalyser; interface {$I ZParseSql.inc} uses Classes, ZGenericSqlAnalyser; type {** Implements an Oracle statements analyser. } TZOracleStatementAnalyser = class (TZGenericStatementAnalyser) public constructor Create; end; implementation const {** The generic constants.} OracleSectionNames: array[0..13] of string = ( 'SELECT', 'UPDATE', 'DELETE', 'INSERT', 'FROM', 'WHERE', 'INTO', 'GROUP*BY', 'HAVING', 'ORDER*BY', 'ORDER*SIBLINGS*BY', 'FOR*UPDATE', 'START*WITH', 'CONNECT*BY' ); OracleSelectOptions: array[0..2] of string = ( 'DISTINCT', 'ALL', 'UNIQUE' ); OracleFromJoins: array[0..7] of string = ( 'NATURAL', 'RIGHT', 'LEFT', 'FULL', 'INNER', 'OUTER', 'JOIN', 'CROSS' ); OracleFromClauses: array[0..1] of string = ( 'ON', 'USING' ); { TZOracleStatementAnalyser } {** Creates the object and assignes the main properties. } constructor TZOracleStatementAnalyser.Create; begin SectionNames := ArrayToStrings(OracleSectionNames); SelectOptions := ArrayToStrings(OracleSelectOptions); FromJoins := ArrayToStrings(OracleFromJoins); FromClauses := ArrayToStrings(OracleFromClauses); end; end. ================================================ FILE: lib/zeosdbo/src/parsesql/ZOracleToken.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { String tokenizing classes for Oracle } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZOracleToken; interface {$I ZParseSql.inc} uses Classes, ZTokenizer, ZGenericSqlToken, ZPostgreSqlToken, ZSybaseToken; type {** Implements a Oracle-specific number state object. } TZOracleNumberState = class (TZPostgreSQLNumberState) end; {** Implements a Oracle-specific quote string state object. } TZOracleQuoteState = class (TZGenericSQLQuoteState) end; {** This state will either delegate to a comment-handling state, or return a token with just a slash in it. } TZOracleCommentState = class (TZSybaseCommentState) end; {** Implements a symbol state object. } TZOracleSymbolState = class (TZSymbolState) public constructor Create; end; {** Implements a word state object. } TZOracleWordState = class (TZGenericSQLWordState) public constructor Create; end; {** Implements a default tokenizer object. } TZOracleTokenizer = class (TZTokenizer) public constructor Create; end; implementation { TZOracleSymbolState } {** Creates this Oracle-specific symbol state object. } constructor TZOracleSymbolState.Create; begin inherited Create; Add('<='); Add('>='); Add('<>'); Add('!='); Add('||'); end; { TZOracleWordState } {** Constructs this Oracle-specific word state object. } constructor TZOracleWordState.Create; begin SetWordChars(#0, #255, False); SetWordChars('a', 'z', True); SetWordChars('A', 'Z', True); SetWordChars('0', '9', True); SetWordChars('_', '_', True); SetWordChars('$', '$', True); SetWordChars('#', '#', True); SetWordChars('@', '@', True); end; { TZOracleTokenizer } {** Constructs a tokenizer with a default state table (as described in the class comment). } constructor TZOracleTokenizer.Create; begin EscapeState := TZEscapeState.Create; WhitespaceState := TZWhitespaceState.Create; SymbolState := TZOracleSymbolState.Create; NumberState := TZOracleNumberState.Create; QuoteState := TZOracleQuoteState.Create; WordState := TZOracleWordState.Create; CommentState := TZOracleCommentState.Create; SetCharacterState(#0, #32, WhitespaceState); SetCharacterState(#33, #191, SymbolState); SetCharacterState(#192, High(Char), WordState); SetCharacterState('a', 'z', WordState); SetCharacterState('A', 'Z', WordState); SetCharacterState('_', '_', WordState); SetCharacterState('$', '$', WordState); SetCharacterState('#', '#', WordState); SetCharacterState('0', '9', NumberState); SetCharacterState('.', '.', NumberState); SetCharacterState('"', '"', QuoteState); SetCharacterState(#39, #39, QuoteState); SetCharacterState('/', '/', CommentState); SetCharacterState('-', '-', CommentState); end; end. ================================================ FILE: lib/zeosdbo/src/parsesql/ZParseSql.inc ================================================ {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} {$IFDEF LINUX} {$DEFINE UNIX} {$ENDIF} {$IFNDEF UNIX} {$I ..\Zeos.inc} {$ELSE} {$I ../Zeos.inc} {$ENDIF} ================================================ FILE: lib/zeosdbo/src/parsesql/ZPostgreSqlAnalyser.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { SQL Statements Analysing classes } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZPostgreSqlAnalyser; interface {$I ZParseSql.inc} uses Classes, ZGenericSqlAnalyser; type {** Implements an PostgreSQL statements analyser. } TZPostgreSQLStatementAnalyser = class (TZGenericStatementAnalyser) public constructor Create; end; implementation const {** The generic constants.} PostgreSQLSectionNames: array[0..12] of string = ( 'SELECT', 'UPDATE', 'DELETE', 'INSERT', 'FROM', 'WHERE', 'INTO', 'GROUP*BY', 'HAVING', 'ORDER*BY', 'FOR*UPDATE', 'LIMIT', 'OFFSET' ); PostgreSQLSelectOptions: array[0..1] of string = ( 'DISTINCT', 'ALL' ); PostgreSQLFromJoins: array[0..7] of string = ( 'NATURAL', 'RIGHT', 'LEFT', 'INNER', 'OUTER', 'JOIN', 'FULL', 'CROSS' ); PostgreSQLFromClauses: array[0..1] of string = ( 'ON', 'USING' ); { TZPostgreSQLStatementAnalyser } {** Creates the object and assignes the main properties. } constructor TZPostgreSQLStatementAnalyser.Create; begin SectionNames := ArrayToStrings(PostgreSQLSectionNames); SelectOptions := ArrayToStrings(PostgreSQLSelectOptions); FromJoins := ArrayToStrings(PostgreSQLFromJoins); FromClauses := ArrayToStrings(PostgreSQLFromClauses); end; end. ================================================ FILE: lib/zeosdbo/src/parsesql/ZPostgreSqlToken.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { String tokenizing classes for PostgreSQL } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZPostgreSqlToken; interface {$I ZParseSql.inc} uses Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, ZTokenizer, ZGenericSqlToken, ZMySqlToken; type {** Implements a PostgreSQL-specific number state object. } TZPostgreSQLNumberState = class (TZNumberState) public function NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; override; end; {** Implements a PostgreSQL-specific quote string state object. } TZPostgreSQLQuoteState = class (TZMySQLQuoteState) private FStandardConformingStrings: Boolean; protected function GetModifier(Stream: TStream; FirstChar: Char; ResetPosition: Boolean = True): string; function GetDollarQuotedString(Stream: TStream; QuoteChar: Char): string; function GetQuotedString(Stream: TStream; QuoteChar: Char; EscapeSyntax: Boolean): String; function GetQuotedStringWithModifier(Stream: TStream; FirstChar: Char): string; public function NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; override; procedure SetStandardConformingStrings(const Value: Boolean); end; {** This state will either delegate to a comment-handling state, or return a token with just a slash in it. } TZPostgreSQLCommentState = class (TZCppCommentState) protected function GetMultiLineComment(Stream: TStream): string; override; public function NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; override; end; {** Implements a symbol state object. } TZPostgreSQLSymbolState = class (TZSymbolState) public constructor Create; end; {** Implements a word state object. } TZPostgreSQLWordState = class (TZGenericSQLWordState) public constructor Create; end; IZPostgreSQLTokenizer = interface (IZTokenizer) ['{82392175-9065-4048-9974-EE1253B921B4}'] procedure SetStandardConformingStrings(const Value: Boolean); end; {** Implements a default tokenizer object. } TZPostgreSQLTokenizer = class (TZTokenizer, IZPostgreSQLTokenizer) protected function CheckEscapeState(const ActualState: TZTokenizerState; Stream: TStream; const FirstChar: Char): TZTokenizerState; override; public procedure SetStandardConformingStrings(const Value: Boolean); constructor Create; end; implementation uses ZCompatibility; const NameQuoteChar = Char('"'); DollarQuoteChar = Char('$'); SingleQuoteChar = Char(''''); { TZPostgreSQLNumberState } {** Return a number token from a reader. @return a number token from a reader } function TZPostgreSQLNumberState.NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; var TempChar: Char; FloatPoint: Boolean; LastChar: Char; function ReadDecDigits: string; begin Result := ''; LastChar := #0; while Stream.Read(LastChar, SizeOf(Char)) > 0 do begin if CharInSet(LastChar, ['0'..'9']) then begin Result := Result + LastChar; LastChar := #0; end else begin Stream.Seek(-SizeOf(Char), soFromCurrent); Break; end; end; end; begin FloatPoint := FirstChar = '.'; Result.Value := FirstChar; Result.TokenType := ttUnknown; LastChar := #0; { Reads the first part of the number before decimal point } if not FloatPoint then begin Result.Value := Result.Value + ReadDecDigits; FloatPoint := LastChar = '.'; if FloatPoint then begin Stream.Read(TempChar, SizeOf(Char)); Result.Value := Result.Value + TempChar; end; end; { Reads the second part of the number after decimal point } if FloatPoint then Result.Value := Result.Value + ReadDecDigits; { Reads a power part of the number } if CharInSet(LastChar, ['e','E']) then begin Stream.Read(TempChar, SizeOf(Char)); Result.Value := Result.Value + TempChar; FloatPoint := True; Stream.Read(TempChar, SizeOf(Char)); if CharInSet(TempChar, ['0'..'9','-','+']) then Result.Value := Result.Value + TempChar + ReadDecDigits else begin Result.Value := Copy(Result.Value, 1, Length(Result.Value) - 1); Stream.Seek(-2*SizeOf(Char), soFromCurrent); end; end; { Prepare the result } if Result.Value = '.' then begin if Tokenizer.SymbolState <> nil then Result := Tokenizer.SymbolState.NextToken(Stream, FirstChar, Tokenizer); end else begin if FloatPoint then Result.TokenType := ttFloat else Result.TokenType := ttInteger; end; end; { TZPostgreSQLQuoteState } {** Retrieves string modifier from quoted string. @return a string with modifier for valid quoted string with modifier or empty string otherwise. } function TZPostgreSQLQuoteState.GetModifier(Stream: TStream; FirstChar: Char; ResetPosition: boolean = True): string; var ReadChar: Char; Modifier: string; ReadNum: Integer; begin Result := ''; if CharInSet(FirstChar, ['E', 'e', 'B', 'b', 'X', 'x', 'U', 'u']) then begin Modifier := FirstChar; ReadNum := Stream.Read(ReadChar, SizeOf(Char)); if ReadNum = SizeOf(Char) then begin if (UpperCase(FirstChar) = 'U') and (ReadChar = '&') then // Check for U& modifier begin Modifier := Modifier + ReadChar; ReadNum := ReadNum + Stream.Read(ReadChar, SizeOf(Char)); end; if (ReadChar = SingleQuoteChar) then Result := Modifier; if ResetPosition then Stream.Seek(-ReadNum, soFromCurrent); end; end; end; {** Returns a quoted string token from a reader. This method will get Tag from first char to QuoteChar and will collect characters until reaches same Tag. @return a quoted string token from a reader } function TZPostgreSQLQuoteState.GetDollarQuotedString(Stream: TStream; QuoteChar: Char): string; var ReadChar: Char; Tag, TempTag: string; TagState: integer; begin Result := QuoteChar; TagState := 0; while Stream.Read(ReadChar, SizeOf(Char)) > 0 do begin if (ReadChar = QuoteChar) then begin if (TagState = 0) then begin TagState := 1; Tag := Result; end else if (TagState = 1) then begin TagState := 2; TempTag := ''; end else if (TagState = 2) then begin if TempTag = Tag then TagState := 3 else TempTag := ''; end; end; Result := Result + ReadChar; if TagState = 2 then TempTag := TempTag + ReadChar else if TagState = 3 then Break; end; end; {** Returns a quoted string token from a reader. This method will collect characters until it sees same QuoteChar, ommitting doubled chars @return a quoted string token from a reader } function TZPostgreSQLQuoteState.GetQuotedString(Stream: TStream; QuoteChar: Char; EscapeSyntax: Boolean): String; const BackSlash = Char('\'); var ReadChar: Char; LastChar: Char; QuoteCount: Integer; begin LastChar := #0; Result := QuoteChar; QuoteCount := 1; while Stream.Read(ReadChar, SizeOf(Char)) > 0 do begin if ReadChar = QuoteChar then Inc(QuoteCount); if (LastChar = QuoteChar) and (ReadChar <> QuoteChar) then begin if QuoteCount mod 2 = 0 then begin Stream.Seek(-SizeOf(Char), soFromCurrent); Break; end; end; Result := Result + ReadChar; if (LastChar = BackSlash) and EscapeSyntax then LastChar := #0 else if (LastChar = QuoteChar) and (ReadChar = QuoteChar) then LastChar := #0 else LastChar := ReadChar; end; end; {** Returns a quoted string token with leading modifier from a reader. @return a quoted string token from a reader } function TZPostgreSQLQuoteState.GetQuotedStringWithModifier(Stream: TStream; FirstChar: Char): string; var Modifier: string; EscapeSyntax: Boolean; begin Modifier := GetModifier(Stream, FirstChar, False); if (Modifier <> '') then FirstChar := SingleQuoteChar; EscapeSyntax := (not FStandardConformingStrings and (Modifier = '')) or (UpperCase(Modifier) = 'E'); Result := Modifier + GetQuotedString(Stream, FirstChar, EscapeSyntax); end; {** Return a quoted string token from a reader. This method will collect characters until it sees a match to the character that the tokenizer used to switch to this state. @return a quoted string token from a reader } function TZPostgreSQLQuoteState.NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; begin Result.Value := FirstChar; if FirstChar = NameQuoteChar then begin Result.TokenType := ttWord; Result.Value := GetQuotedString(Stream, FirstChar, False); end else if FirstChar = DollarQuoteChar then begin Result.TokenType := ttQuoted; Result.Value := GetDollarQuotedString(Stream, FirstChar); end else begin Result.TokenType := ttQuoted; Result.Value := GetQuotedStringWithModifier(Stream, FirstChar); end; end; {** Sets how backslashes in quoted strings are handled @param True means backslashes are escape characters } procedure TZPostgreSQLQuoteState.SetStandardConformingStrings(const Value: Boolean); begin FStandardConformingStrings := Value; end; { TZPostgreSQLCommentState } {** Ignore everything up to a last closing star and slash, and then return the tokenizer's next token. @return the tokenizer's next token } function TZPostgreSQLCommentState.GetMultiLineComment(Stream: TStream): string; var ReadChar, LastChar: Char; NestedLevel: Integer; begin LastChar := #0; NestedLevel := 1; Result := ''; while Stream.Read(ReadChar, 1 * SizeOf(Char)) > 0 do begin Result := Result + ReadChar; if (LastChar = '*') and (ReadChar = '/') then begin Dec(NestedLevel); if NestedLevel = 0 then Break; end; if (LastChar = '/') and (ReadChar = '*') then Inc(NestedLevel); LastChar := ReadChar; end; end; {** Gets a PostgreSQL specific comments like -- or /* */. @return either just a slash token, or the results of delegating to a comment-handling state } function TZPostgreSQLCommentState.NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; var ReadChar: Char; ReadNum: Integer; begin Result.TokenType := ttUnknown; Result.Value := FirstChar; if FirstChar = '-' then begin ReadNum := Stream.Read(ReadChar, SizeOf(Char)); if (ReadNum > 0) and (ReadChar = '-') then begin Result.TokenType := ttComment; Result.Value := '--' + GetSingleLineComment(Stream); end else begin if ReadNum > 0 then Stream.Seek(-SizeOf(Char), soFromCurrent); end; end else if FirstChar = '/' then begin ReadNum := Stream.Read(ReadChar, SizeOf(Char)); if (ReadNum > 0) and (ReadChar = '*') then begin Result.TokenType := ttComment; Result.Value := '/*' + GetMultiLineComment(Stream); end else begin if ReadNum > 0 then Stream.Seek(-SizeOf(Char), soFromCurrent); end; end; if (Result.TokenType = ttUnknown) and (Tokenizer.SymbolState <> nil) then Result := Tokenizer.SymbolState.NextToken(Stream, FirstChar, Tokenizer); end; { TZPostgreSQLSymbolState } {** Creates this PostgreSQL-specific symbol state object. } constructor TZPostgreSQLSymbolState.Create; begin inherited Create; Add('<='); Add('>='); Add('<>'); Add('<<'); Add('>>'); Add('~*'); Add('!~'); Add('!~*'); end; { TZPostgreSQLWordState } {** Constructs this PostgreSQL-specific word state object. } constructor TZPostgreSQLWordState.Create; begin SetWordChars(#0, #191, False); SetWordChars(#192, high(char), True); SetWordChars('a', 'z', True); SetWordChars('A', 'Z', True); SetWordChars('0', '9', True); SetWordChars('_', '_', True); SetWordChars('$', '$', True); end; {** informs the Postgre Tokenizer '\' should be handled as Escape-char @param True means backslashes are quoted strings } procedure TZPostgreSQLTokenizer.SetStandardConformingStrings( const Value: Boolean); begin (QuoteState as TZPostgreSQLQuoteState).SetStandardConformingStrings(Value); end; {** Constructs a tokenizer with a default state table (as described in the class comment). } constructor TZPostgreSQLTokenizer.Create; begin EscapeState := TZEscapeState.Create; WhitespaceState := TZWhitespaceState.Create; SymbolState := TZPostgreSQLSymbolState.Create; NumberState := TZPostgreSQLNumberState.Create; QuoteState := TZPostgreSQLQuoteState.Create; WordState := TZPostgreSQLWordState.Create; CommentState := TZPostgreSQLCommentState.Create; SetCharacterState(#0, #32, WhitespaceState); SetCharacterState(#33, #191, SymbolState); SetCharacterState(#192, High(Char), WordState); SetCharacterState('a', 'z', WordState); SetCharacterState('A', 'Z', WordState); SetCharacterState('_', '_', WordState); SetCharacterState('0', '9', NumberState); SetCharacterState('.', '.', NumberState); SetCharacterState(NameQuoteChar, NameQuoteChar, QuoteState); SetCharacterState(SingleQuoteChar, SingleQuoteChar, QuoteState); SetCharacterState(DollarQuoteChar, DollarQuoteChar, QuoteState); SetCharacterState('/', '/', CommentState); SetCharacterState('-', '-', CommentState); end; {** Checks if WordState is QuoteState with modifier and sets QuoteState. @param Stream the Read-Stream which has to checked for Next-Chars. @FirstChar The FirstChar which was readed and sets the Symbolstate @returns either the given SymbolState or the QuoteState } function TZPostgreSQLTokenizer.CheckEscapeState(const ActualState: TZTokenizerState; Stream: TStream; const FirstChar: Char): TZTokenizerState; var Modifier: string; begin Result := inherited CheckEscapeState(ActualState, Stream, FirstChar); if (Result is TZWordState) then begin Modifier := (QuoteState as TZPostgreSQLQuoteState).GetModifier(Stream, FirstChar); if (Modifier <> '') then Result := QuoteState; end; end; end. ================================================ FILE: lib/zeosdbo/src/parsesql/ZScriptParser.pas ================================================ {*********************************************************} { } { Zeos SQL Shell } { Script Parsing Classes } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZScriptParser; interface {$I ZParseSql.inc} uses Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, ZTokenizer; type {** Defines a SQL delimiter type. } TZDelimiterType = (dtDefault, dtDelimiter, dtGo, dtSetTerm, dtEmptyLine); {** Implements a SQL script parser. } TZSQLScriptParser = class private FDelimiter: string; FDelimiterType: TZDelimiterType; FCleanupStatements: Boolean; FTokenizer: IZTokenizer; FUncompletedStatement: string; FStatements: TStrings; function GetStatementCount: Integer; function GetStatement(Index: Integer): string; public constructor Create; constructor CreateWithTokenizer(Tokenizer: IZTokenizer); destructor Destroy; override; procedure Clear; procedure ClearCompleted; procedure ClearUncompleted; procedure ParseText(const Text: string); procedure ParseLine(const Line: string); property Delimiter: string read FDelimiter write FDelimiter; property DelimiterType: TZDelimiterType read FDelimiterType write FDelimiterType default dtDefault; property CleanupStatements: Boolean read FCleanupStatements write FCleanupStatements default True; property Tokenizer: IZTokenizer read FTokenizer write FTokenizer; property UncompletedStatement: string read FUncompletedStatement; property StatementCount: Integer read GetStatementCount; property Statements[Index: Integer]: string read GetStatement; end; implementation uses ZMessages, ZSysUtils; { TZSQLScriptParser } {** Constructs this script parser class. } constructor TZSQLScriptParser.Create; begin FStatements := TStringList.Create; FDelimiter := ';'; FDelimiterType := dtDefault; FCleanupStatements := True; end; {** Creates this object and assignes a tokenizer object. @param Tokenizer a tokenizer object. } constructor TZSQLScriptParser.CreateWithTokenizer(Tokenizer: IZTokenizer); begin Create; FTokenizer := Tokenizer; end; {** Destroys this class and cleanups the memory. } destructor TZSQLScriptParser.Destroy; begin FreeAndNil(FStatements); FTokenizer := nil; inherited Destroy; end; {** Gets SQL statements number. @returns SQL statements number. } function TZSQLScriptParser.GetStatementCount: Integer; begin Result := FStatements.Count; end; {** Gets a parsed SQL statement by it's index. @param Index a statement index. @returns a SQL statement string. } function TZSQLScriptParser.GetStatement(Index: Integer): string; begin Result := FStatements[Index]; end; {** Clears all completed and uncompleted statements and line delimiter. } procedure TZSQLScriptParser.Clear; begin FStatements.Clear; FDelimiter := ';'; FUncompletedStatement := ''; end; {** Clears only completed statements. } procedure TZSQLScriptParser.ClearCompleted; begin FStatements.Clear; end; {** Clears completed and uncompleted statements. } procedure TZSQLScriptParser.ClearUncompleted; begin FStatements.Clear; FUncompletedStatement := ''; end; {** Parses incrementaly only one single line. The line appends with EOL character. @param Line a line to be parsed. } procedure TZSQLScriptParser.ParseLine(const Line: string); begin ParseText(#10 + Line + #10); end; {** Parses a complete text with several lines. @oaram Text a text of the SQL script to be parsed. } procedure TZSQLScriptParser.ParseText(const Text: string); const SetTerm = String('SET TERM '); var Tokens: TStrings; TokenType: TZTokenType; TokenValue: string; TokenIndex, LastStmtEndingIndex, iPos: Integer; SQL, Temp: string; EndOfStatement: Boolean; Extract: Boolean; LastComment: String; function CountChars(const Str: string; Chr: Char): Integer; var I: Integer; begin Result := 0; for I := 1 to Length(Str) do begin if Str[I] = Chr then Inc(Result); end; end; procedure SetNextToken; begin TokenValue := Tokens[TokenIndex]; TokenType := TZTokenType({$IFDEF FPC}Pointer({$ENDIF} Tokens.Objects[TokenIndex]{$IFDEF FPC}){$ENDIF}); if TokenValue = Delimiter then LastStmtEndingIndex := TokenIndex; Inc(TokenIndex); end; begin if Tokenizer = nil then raise Exception.Create(STokenizerIsNotDefined); if CleanupStatements then Tokens := Tokenizer.TokenizeBufferToList(Text, [toSkipComments]) else Tokens := Tokenizer.TokenizeBufferToList(Text, []); if ( (DelimiterType = dtDelimiter) or (DelimiterType = dtSetTerm) ) and ( Delimiter = '' ) then Delimiter := ';'; //use default delimiter if (DelimiterType = dtDefault) then Delimiter := ';'; //use default delimiter TokenIndex := 0; SQL := FUncompletedStatement; if SQL <> '' then begin if CleanupStatements then SQL := SQL + ' ' else SQL := SQL + #10; end; FUncompletedStatement := ''; FStatements.Clear; try repeat SetNextToken; case DelimiterType of dtGo: EndOfStatement := (UpperCase(TokenValue) = 'GO'); dtEmptyLine: begin EndOfStatement := False; if TokenType = ttWhitespace then begin Temp := TokenValue; while (CountChars(Temp, #10) < 2) and (TokenType = ttWhitespace) do begin SetNextToken; if TokenType = ttWhitespace then Temp := Temp + TokenValue; end; EndOfStatement := (TokenType = ttWhitespace) or EndsWith(Sql, #10); if not EndOfStatement then begin if SQL <> '' then SQL := Trim(SQL) + ' '; end; end; end; dtDelimiter, dtDefault, dtSetTerm: begin EndOfStatement := False; if not (TokenType in [ttWhitespace, ttEOF]) then begin if (DelimiterType = dtDelimiter) and (Uppercase(TokenValue) = 'DELIMITER') then begin Delimiter := ''; Temp := TokenValue; {process the DELIMITER} Temp := Temp + Tokens[TokenIndex]; {process the first ' ' char} Inc(TokenIndex); while TokenType <> ttWhitespace do begin SetNextToken; if not (TokenType in [ttWhitespace, ttEOF]) then Delimiter := Delimiter + TokenValue; //get the new delimiter end; SQL := SQL + Temp + Delimiter; EndOfStatement := True; end else begin Temp := TokenValue; Extract := True; while (Delimiter[1]=Temp[1]) and (Length(Delimiter) > Length(Temp)) and not (TokenType in [ttWhitespace, ttEOF]) do begin SetNextToken; if not (TokenType in [ttWhitespace, ttEOF]) then begin Temp := Temp + TokenValue; Extract := True; end else Extract := False; end; EndOfStatement := (Delimiter = Temp); if not EndOfStatement then begin if Extract then Temp := Copy(Temp, 1, Length(Temp) - Length(TokenValue)); SQL := SQL + Temp; end; end; end; end; else EndOfStatement := False; end; if TokenType = ttEOF then Break; { Processes the end of statements. } if EndOfStatement then begin if CleanupStatements then SQL := Trim(SQL); if SQL <> '' then begin if not CleanupStatements then Temp := Trim(SQL) else Temp := SQL; if (DelimiterType = dtSetTerm) and StartsWith(UpperCase(Temp), SetTerm) then Delimiter := Copy(Temp, 10, Length(Temp) - 9) else if (DelimiterType = dtSetTerm) and ( Pos(SetTerm, UpperCase(Temp)) > 0) then begin iPos := Pos(SetTerm, UpperCase(Temp))+8; Delimiter := Copy(Temp, iPos+1, Length(Temp) - iPos); LastComment := TrimRight(Copy(Temp, 1, iPos-9)); end else if (DelimiterType = dtDelimiter) and StartsWith(UpperCase(Temp), 'DELIMITER ') then Delimiter := Copy(Temp, 11, Length(Temp) - 10) else begin if (DelimiterType = dtEmptyLine) and EndsWith(SQL, ';') then SQL := Copy(SQL, 1, Length(SQL) - 1); if LastComment <> '' then SQL := LastComment+#13#10+SQL; if CleanupStatements then SQL := Trim(SQL); FStatements.Add(SQL); LastComment := ''; end; end; SQL := ''; end { Adds a whitespace token. } else if CleanupStatements and (TokenType = ttWhitespace) then begin if SQL <> '' then SQL := Trim(SQL) + ' '; end { Adds a default token. } else begin // --> ms, 20/10/2005 // TokenValue is not a ttWhitespace (#32) if (TokenType = ttWhitespace) and (TokenValue > '') then begin // SQL is not emtyp if (SQL <> '') then begin // is last token: if (Tokenindex = Tokens.count-1) then TokenValue := ''; // next(!) token is also ttWhitespace or delimiter // (TokenIndex was already incremented!) if (Tokenindex < Tokens.count-1) then if ((TZTokenType({$IFDEF FPC}Pointer({$ENDIF} Tokens.Objects[TokenIndex]{$IFDEF FPC}){$ENDIF}) = ttWhitespace) or (Tokens[TokenIndex] = Delimiter)) then TokenValue := ''; end // SQL is empty else TokenValue := ''; end; if ((SQL = '') and (trim(TokenValue) = '')) then TokenValue := ''; // <-- ms SQL := SQL + TokenValue; end; until TokenType = ttEOF; if ( LastComment <> '' ) and ( FStatements.Count > 0) then if CleanupStatements then FStatements[FStatements.Count-1] := FStatements[FStatements.Count-1]+' '+Trim(LastComment) else FStatements[FStatements.Count-1] := FStatements[FStatements.Count-1]+#13#10+LastComment; finally Tokens.Free; end; if CleanupStatements then SQL := Trim(SQL); if SQL <> '' then FUncompletedStatement := SQL; end; end. ================================================ FILE: lib/zeosdbo/src/parsesql/ZSelectSchema.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { SQL Select Objects and Assembler classes } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZSelectSchema; interface {$I ZParseSql.inc} uses ZClasses, Contnrs, ZCompatibility {$IFDEF WITH_SYSTEMCLASSES},System.Classes{$ENDIF} {$IFDEF WITH_TOBJECTLIST_INLINE}, System.Types{$ENDIF}; type {** Case Sensitive/Unsensitive identificator processor. } IZIdentifierConvertor = interface (IZInterface) ['{2EB07B9B-1E96-4A42-8084-6F98D9140B27}'] function IsCaseSensitive(const Value: string): Boolean; function IsQuoted(const Value: string): Boolean; function Quote(const Value: string): string; function ExtractQuote(const Value: string): string; end; {** Implements a table reference assembly. } TZTableRef = class (TObject) private FCatalog: string; FSchema: string; FTable: string; FAlias: string; public constructor Create(const Catalog, Schema, Table, Alias: string); function FullName: string; property Catalog: string read FCatalog write FCatalog; property Schema: string read FSchema write FSchema; property Table: string read FTable write FTable; property Alias: string read FAlias write FAlias; end; {** Implements a field reference assembly. } TZFieldRef = class (TObject) private FIsField: Boolean; FCatalog: string; FSchema: string; FTable: string; FField: string; FAlias: string; FTableRef: TZTableRef; FLinked: Boolean; public constructor Create(IsField: Boolean; const Catalog, Schema, Table, Field, Alias: string; TableRef: TZTableRef); property IsField: Boolean read FIsField write FIsField; property Catalog: string read FCatalog write FCatalog; property Schema: string read FSchema write FSchema; property Table: string read FTable write FTable; property Field: string read FField write FField; property Alias: string read FAlias write FAlias; property TableRef: TZTableRef read FTableRef write FTableRef; property Linked: Boolean read FLinked write FLinked; end; {** Defines an interface to select assembly. } IZSelectSchema = interface (IZInterface) ['{3B892975-57E9-4EB7-8DB1-BDDED91E7FBC}'] procedure AddField(FieldRef: TZFieldRef); procedure InsertField(Index: Integer; FieldRef: TZFieldRef); procedure DeleteField(FieldRef: TZFieldRef); procedure AddTable(TableRef: TZTableRef); procedure LinkReferences(Convertor: IZIdentifierConvertor); function FindTableByFullName(const Catalog, Schema, Table: string): TZTableRef; function FindTableByShortName(const Table: string): TZTableRef; function FindFieldByShortName(const Field: string): TZFieldRef; function LinkFieldByIndexAndShortName(const ColumnIndex: Integer; const Field: string; const Convertor: IZIdentifierConvertor): TZFieldRef; function GetFieldCount: Integer; function GetTableCount: Integer; function GetField(Index: Integer): TZFieldRef; function GetTable(Index: Integer): TZTableRef; property FieldCount: Integer read GetFieldCount; property Fields[Index: Integer]: TZFieldRef read GetField; property TableCount: Integer read GetTableCount; property Tables[Index: Integer]: TZTableRef read GetTable; end; {** Implements a select assembly. } TZSelectSchema = class (TZAbstractObject, IZSelectSchema) private FFields: TObjectList; FTables: TObjectList; procedure ConvertIdentifiers(Convertor: IZIdentifierConvertor); public constructor Create; destructor Destroy; override; procedure AddField(FieldRef: TZFieldRef); procedure InsertField(Index: Integer; FieldRef: TZFieldRef); procedure DeleteField(FieldRef: TZFieldRef); procedure AddTable(TableRef: TZTableRef); procedure LinkReferences(Convertor: IZIdentifierConvertor); function FindTableByFullName(const Catalog, Schema, Table: string): TZTableRef; function FindTableByShortName(const Table: string): TZTableRef; function FindFieldByShortName(const Field: string): TZFieldRef; function LinkFieldByIndexAndShortName(const ColumnIndex: Integer; const Field: string; const Convertor: IZIdentifierConvertor): TZFieldRef; function GetFieldCount: Integer; function GetTableCount: Integer; function GetField(Index: Integer): TZFieldRef; function GetTable(Index: Integer): TZTableRef; property FieldCount: Integer read GetFieldCount; property Fields[Index: Integer]: TZFieldRef read GetField; property TableCount: Integer read GetTableCount; property Tables[Index: Integer]: TZTableRef read GetTable; end; implementation { TZTableRef } {** Creates a table reference object. @param Catalog a catalog name. @param Schema a schema name. @param Table a table name. @param Alias a table alias. } constructor TZTableRef.Create(const Catalog, Schema, Table, Alias: string); begin FCatalog := Catalog; FSchema := Schema; FTable := Table; FAlias := Alias; end; {** Gets a full database table name. @return a full database table name. } function TZTableRef.FullName: string; begin Result := FCatalog + '.' + FSchema + '.' + FTable; while (Result <> '') and (Result[1] = '.') do Delete(Result, 1, 1); end; { TZFieldRef } {** Creates a field reference object. @param IsField flag which separates table columns from expressions. @param Catalog a catalog name. @param Schema a schema name. @param Table a table name. @param Field a field name. @param Alias a field alias. } constructor TZFieldRef.Create(IsField: Boolean; const Catalog, Schema, Table, Field, Alias: string; TableRef: TZTableRef); begin FIsField := IsField; FCatalog := Catalog; FSchema := Schema; FTable := Table; FField := Field; FAlias := Alias; FTableRef := TableRef; FLinked := False; end; { TZSelectSchema } {** Constructs this assembly object and assignes the main properties. } constructor TZSelectSchema.Create; begin FFields := TObjectList.Create; FTables := TObjectList.Create; end; {** Destroys this object and cleanups the memory. } destructor TZSelectSchema.Destroy; begin FFields.Free; FTables.Free; end; {** Finds a table reference by catalog and table name. @param Catalog a database catalog name. @param Schema a database schema name. @param Table a database table name. @return a found table reference object or null otherwise. } function TZSelectSchema.FindTableByFullName( const Catalog, Schema, Table: string): TZTableRef; var I: Integer; Current: TZTableRef; begin Result := nil; { Looks a table by it's full name. } for I := 0 to FTables.Count - 1 do begin Current := TZTableRef(FTables[I]); if (Current.Schema = Schema) and (Current.Table = Table) then begin Result := Current; Exit; end; end; { Looks a table by it's short name. } for I := 0 to FTables.Count - 1 do begin Current := TZTableRef(FTables[I]); if (Current.Schema = '') and (Current.Table = Table) then begin Result := Current; Exit; end; end; end; {** Finds a table reference by table name or table alias. @param Table a database table name or alias. @return a found table reference object or null otherwise. } function TZSelectSchema.FindTableByShortName(const Table: string): TZTableRef; var I: Integer; Current: TZTableRef; begin Result := nil; { Looks a table by it's alias. } for I := 0 to FTables.Count - 1 do begin Current := TZTableRef(FTables[I]); if Current.Alias = Table then begin Result := Current; Exit; end; end; { Looks a table by it's name. } for I := 0 to FTables.Count - 1 do begin Current := TZTableRef(FTables[I]); if Current.Table = Table then begin Result := Current; Exit; end; end; end; {** Finds a field reference by field name or field alias. @param Field a table field name or alias. @return a found field reference object or null otherwise. } function TZSelectSchema.FindFieldByShortName(const Field: string): TZFieldRef; var I: Integer; Current: TZFieldRef; begin Result := nil; if Field = '' then Exit; { Looks a field by it's alias. } for I := 0 to FFields.Count - 1 do begin Current := TZFieldRef(FFields[I]); if Current.Alias = Field then begin Result := Current; Exit; end; end; { Looks a field by it's name. } for I := 0 to FFields.Count - 1 do begin Current := TZFieldRef(FFields[I]); if Current.Field = Field then begin Result := Current; Exit; end; end; end; {** Links a field reference by index and/or field name or field alias. @param ColumnIndex an index of the column. @param Field a table field name or alias. @return a found field reference object or null otherwise. } function TZSelectSchema.LinkFieldByIndexAndShortName(const ColumnIndex: Integer; const Field: string; const Convertor: IZIdentifierConvertor): TZFieldRef; var I: Integer; Current: TZFieldRef; begin Result := nil; if Field = '' then Exit; { Looks by field index. } if (ColumnIndex > 0) and (ColumnIndex <= FFields.Count) then begin Current := TZFieldRef(FFields[ColumnIndex - 1]); if not Current.Linked //note http://sourceforge.net/p/zeoslib/tickets/101/ and ((Current.Alias = Field) or (Current.Field = Field) or (Current.Field = Convertor.Quote(Field))) then begin Result := Current; Result.Linked := True; Exit; end; end; { Looks a field by it's alias. } for I := 0 to FFields.Count - 1 do begin Current := TZFieldRef(FFields[I]); if not Current.Linked and ((Current.Alias = Field) or (Current.Alias = Convertor.Quote(Field))) then begin Result := Current; Result.Linked := True; Exit; end; end; { Looks a field by field and table aliases. } for I := 0 to FFields.Count - 1 do begin Current := TZFieldRef(FFields[I]); if not Current.Linked and Assigned(Current.TableRef) and (((Current.TableRef.Alias + '.' + Current.Field) = Field) or (((Current.TableRef.Table + '.' + Current.Field) = Field))) then begin Result := Current; Result.Linked := True; Exit; end; end; { Looks a field by it's name. } for I := 0 to FFields.Count - 1 do begin Current := TZFieldRef(FFields[I]); if not Current.Linked and (Current.Field = Field) then begin Result := Current; Result.Linked := True; Exit; end; end; end; {** Convert all table and field identifiers.. @param Convertor an identifier convertor. } procedure TZSelectSchema.ConvertIdentifiers(Convertor: IZIdentifierConvertor); var I: Integer; function ExtractNeedlessQuote(Value : String) : String; var tempstring: String; begin tempstring := Convertor.ExtractQuote(Value); if Convertor.IsCaseSensitive(tempstring) then result := Value else result := tempstring; end; begin if Convertor = nil then Exit; for I := 0 to FFields.Count - 1 do begin with TZFieldRef(FFields[I]) do begin Catalog := ExtractNeedlessQuote(Catalog); Schema := ExtractNeedlessQuote(Schema); Table := ExtractNeedlessQuote(Table); Field := ExtractNeedlessQuote(Field); Alias := ExtractNeedlessQuote(Alias); end; end; for I := 0 to FTables.Count - 1 do begin with TZTableRef(FTables[I]) do begin Catalog := ExtractNeedlessQuote(Catalog); Schema := ExtractNeedlessQuote(Schema); Table := ExtractNeedlessQuote(Table); Alias := ExtractNeedlessQuote(Alias); end; end; end; {** Links references between fields and tables. @param Convertor an identifier convertor. } procedure TZSelectSchema.LinkReferences(Convertor: IZIdentifierConvertor); var I, J: Integer; FieldRef: TZFieldRef; TableRef: TZTableRef; TempFields: TObjectList; begin ConvertIdentifiers(Convertor); TempFields := FFields; FFields := TObjectList.Create; try for I := 0 to TempFields.Count - 1 do begin FieldRef := TZFieldRef(TempFields[I]); TableRef := nil; if not FieldRef.IsField then begin FFields.Add(TZFieldRef.Create(FieldRef.IsField, FieldRef.Catalog, FieldRef.Schema, FieldRef.Table, FieldRef.Field, FieldRef.Alias, FieldRef.TableRef)); Continue; end else if (FieldRef.Schema <> '') and (FieldRef.Table <> '') then begin TableRef := FindTableByFullName(FieldRef.Catalog, FieldRef.Schema, FieldRef.Table); end else if FieldRef.Table <> '' then TableRef := FindTableByShortName(FieldRef.Table) else if FieldRef.Field = '*' then begin { Add all fields from all tables. } for J := 0 to FTables.Count - 1 do begin with TZTableRef(FTables[J]) do begin FFields.Add(TZFieldRef.Create(True, Catalog, Schema, Table, '*', '', TZTableRef(FTables[J]))); end; end; Continue; end; if TableRef <> nil then begin FFields.Add(TZFieldRef.Create(True, TableRef.Catalog, TableRef.Schema, TableRef.Table, FieldRef.Field, FieldRef.Alias, TableRef)); end else begin FFields.Add(TZFieldRef.Create(True, FieldRef.Catalog, FieldRef.Schema, FieldRef.Table, FieldRef.Field, FieldRef.Alias, TableRef)); end; end; finally TempFields.Free; end; end; {** Adds a new field to this select schema. @param FieldRef a field reference object. } procedure TZSelectSchema.AddField(FieldRef: TZFieldRef); begin FFields.Add(FieldRef); end; {** Inserts a new field to this select schema. @param Index an index where to insert a new field reference. @param FieldRef a field reference object. } procedure TZSelectSchema.InsertField(Index: Integer; FieldRef: TZFieldRef); begin FFields.Insert(Index, FieldRef); end; {** Deletes a field from this select schema. @param FieldRef a field reference object. } procedure TZSelectSchema.DeleteField(FieldRef: TZFieldRef); begin FFields.Remove(FieldRef); end; {** Adds a new table to this select schema. @param TableRef a table reference object. } procedure TZSelectSchema.AddTable(TableRef: TZTableRef); begin FTables.Add(TableRef); end; {** Gets a field reference by index. @param Index an index of the reference. @returns a pointer to the field reference. } function TZSelectSchema.GetField(Index: Integer): TZFieldRef; begin Result := TZFieldRef(FFields[Index]); end; {** Gets a count of field references. @returns a count of field references. } function TZSelectSchema.GetFieldCount: Integer; begin Result := FFields.Count; end; {** Gets a table reference by index. @param Index an index of the reference. @returns a pointer to the table reference. } function TZSelectSchema.GetTable(Index: Integer): TZTableRef; begin Result := TZTableRef(FTables[Index]); end; {** Gets a count of table references. @returns a count of table references. } function TZSelectSchema.GetTableCount: Integer; begin Result := FTables.Count; end; end. ================================================ FILE: lib/zeosdbo/src/parsesql/ZSqLiteAnalyser.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { SQLite Statements Analysing classes } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZSqLiteAnalyser; interface {$I ZParseSql.inc} uses Classes, ZGenericSqlAnalyser; type {** Implements an SQLite statements analyser. } TZSQLiteStatementAnalyser = class (TZGenericStatementAnalyser) public constructor Create; end; implementation const {** The generic constants.} SQLiteSectionNames: array[0..11] of string = ( 'SELECT', 'UPDATE', 'DELETE', 'INSERT', 'FROM', 'WHERE', 'INTO', 'GROUP*BY', 'HAVING', 'ORDER*BY', 'OFFSET', 'LIMIT' ); SQLiteSelectOptions: array[0..1] of string = ( 'DISTINCT', 'ALL' ); SQLiteFromJoins: array[0..7] of string = ( 'NATURAL', 'RIGHT', 'LEFT', 'FULL', 'INNER', 'OUTER', 'JOIN', 'CROSS' ); SQLiteFromClauses: array[0..1] of string = ( 'ON', 'USING' ); { TZSQLiteStatementAnalyser } {** Creates the object and assignes the main properties. } constructor TZSQLiteStatementAnalyser.Create; begin SectionNames := ArrayToStrings(SQLiteSectionNames); SelectOptions := ArrayToStrings(SQLiteSelectOptions); FromJoins := ArrayToStrings(SQLiteFromJoins); FromClauses := ArrayToStrings(SQLiteFromClauses); end; end. ================================================ FILE: lib/zeosdbo/src/parsesql/ZSqLiteToken.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { String tokenizing classes for SQLite } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZSqLiteToken; interface {$I ZParseSql.inc} uses Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} ZTokenizer, ZGenericSqlToken; type {** Implements a SQLite-specific number state object. } TZSQLiteNumberState = class (TZNumberState) public function NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; override; end; {** Implements a SQLite-specific quote string state object. } TZSQLiteQuoteState = class (TZQuoteState) public function NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; override; function EncodeString(const Value: string; QuoteChar: Char): string; override; function DecodeString(const Value: string; QuoteChar: Char): string; override; end; {** This state will either delegate to a comment-handling state, or return a token with just a slash in it. } TZSQLiteCommentState = class (TZCppCommentState) public function NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; override; end; {** Implements a symbol state object. } TZSQLiteSymbolState = class (TZSymbolState) public constructor Create; end; {** Implements a word state object. } TZSQLiteWordState = class (TZGenericSQLWordState) public constructor Create; end; {** Implements a default tokenizer object. } TZSQLiteTokenizer = class (TZTokenizer) public constructor Create; end; implementation uses SysUtils, ZCompatibility; { TZSQLiteNumberState } {** Return a number token from a reader. @return a number token from a reader } function TZSQLiteNumberState.NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; var TempChar: Char; FloatPoint: Boolean; LastChar: Char; function ReadDecDigits: string; begin Result := ''; LastChar := #0; while Stream.Read(LastChar, SizeOf(Char)) > 0 do begin if CharInSet(LastChar, ['0'..'9']) then begin Result := Result + LastChar; LastChar := #0; end else begin Stream.Seek(-SizeOf(Char), soFromCurrent); Break; end; end; end; begin FloatPoint := FirstChar = '.'; Result.Value := FirstChar; Result.TokenType := ttUnknown; LastChar := #0; { Reads the first part of the number before decimal point } if not FloatPoint then begin Result.Value := Result.Value + ReadDecDigits; FloatPoint := LastChar = '.'; if FloatPoint then begin Stream.Read(TempChar, SizeOf(Char)); Result.Value := Result.Value + TempChar; end; end; { Reads the second part of the number after decimal point } if FloatPoint then Result.Value := Result.Value + ReadDecDigits; { Reads a power part of the number } if CharInSet(LastChar, ['e','E']) then begin Stream.Read(TempChar, SizeOf(Char)); Result.Value := Result.Value + TempChar; FloatPoint := True; Stream.Read(TempChar, SizeOf(Char)); if CharInSet(TempChar, ['0'..'9','-','+']) then Result.Value := Result.Value + TempChar + ReadDecDigits else begin Result.Value := Copy(Result.Value, 1, Length(Result.Value) - 1); Stream.Seek(-2*SizeOf(Char), soFromCurrent); end; end; { Prepare the result } if Result.Value = '.' then begin if Tokenizer.SymbolState <> nil then Result := Tokenizer.SymbolState.NextToken(Stream, FirstChar, Tokenizer); end else begin if FloatPoint then Result.TokenType := ttFloat else Result.TokenType := ttInteger; end; end; { TZSQLiteQuoteState } {** Return a quoted string token from a reader. This method will collect characters until it sees a match to the character that the tokenizer used to switch to this state. @return a quoted string token from a reader } function TZSQLiteQuoteState.NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; var ReadChar: Char; LastChar: Char; begin Result.Value := FirstChar; LastChar := #0; while Stream.Read(ReadChar, SizeOf(Char)) > 0 do begin if ((LastChar = FirstChar) and (ReadChar <> FirstChar) and (FirstChar <> '[')) or ((FirstChar = '[') and (LastChar = ']')) then begin Stream.Seek(-SizeOf(Char), soFromCurrent); Break; end; Result.Value := Result.Value + ReadChar; if (LastChar = FirstChar) and (ReadChar = FirstChar) then LastChar := #0 else LastChar := ReadChar; end; if CharInSet(FirstChar, ['"', '[']) then Result.TokenType := ttWord else Result.TokenType := ttQuoted; end; {** Encodes a string value. @param Value a string value to be encoded. @param QuoteChar a string quote character. @returns an encoded string. } function TZSQLiteQuoteState.EncodeString(const Value: string; QuoteChar: Char): string; begin if QuoteChar = '[' then Result := '[' + Value + ']' else if CharInSet(QuoteChar, [#39, '"']) then Result := QuoteChar + Value + QuoteChar else Result := Value; end; {** Decodes a string value. @param Value a string value to be decoded. @param QuoteChar a string quote character. @returns an decoded string. } function TZSQLiteQuoteState.DecodeString(const Value: string; QuoteChar: Char): string; begin Result := Value; if Length(Value) >= 2 then begin if CharInSet(QuoteChar, [#39, '"']) and (Value[1] = QuoteChar) and (Value[Length(Value)] = QuoteChar) then begin if Length(Value) > 2 then Result := AnsiDequotedStr(Value, QuoteChar) else Result := ''; end else if (QuoteChar = '[') and (Value[1] = QuoteChar) and (Value[Length(Value)] = ']') then Result := Copy(Value, 2, Length(Value) - 2) end; end; { TZSQLiteCommentState } {** Gets a SQLite specific comments like # or /* */. @return either just a slash token, or the results of delegating to a comment-handling state } function TZSQLiteCommentState.NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; var ReadChar: Char; ReadNum: Integer; begin Result.Value := FirstChar; Result.TokenType := ttUnknown; if FirstChar = '-' then begin ReadNum := Stream.Read(ReadChar, SizeOf(Char)); if (ReadNum > 0) and (ReadChar = '-') then begin Result.TokenType := ttComment; Result.Value := '--' + GetSingleLineComment(Stream); end else begin if ReadNum > 0 then Stream.Seek(-SizeOf(Char), soFromCurrent); end; end else if FirstChar = '/' then begin ReadNum := Stream.Read(ReadChar, SizeOf(Char)); if (ReadNum > 0) and (ReadChar = '*') then begin Result.TokenType := ttComment; Result.Value := '/*' + GetMultiLineComment(Stream); end else begin if ReadNum > 0 then Stream.Seek(-SizeOf(Char), soFromCurrent); end; end; if (Result.TokenType = ttUnknown) and (Tokenizer.SymbolState <> nil) then Result := Tokenizer.SymbolState.NextToken(Stream, FirstChar, Tokenizer); end; { TZSQLiteSymbolState } {** Creates this SQLite-specific symbol state object. } constructor TZSQLiteSymbolState.Create; begin inherited Create; Add('<='); Add('>='); Add('<>'); Add('!='); Add('=='); Add('<<'); Add('>>'); Add('||'); end; { TZSQLiteWordState } {** Constructs this SQLite-specific word state object. } constructor TZSQLiteWordState.Create; begin SetWordChars(#0, #255, False); SetWordChars('a', 'z', True); SetWordChars('A', 'Z', True); SetWordChars('0', '9', True); SetWordChars('_', '_', True); end; { TZSQLiteTokenizer } {** Constructs a tokenizer with a default state table (as described in the class comment). } constructor TZSQLiteTokenizer.Create; begin EscapeState := TZEscapeState.Create; WhitespaceState := TZWhitespaceState.Create; SymbolState := TZSQLiteSymbolState.Create; NumberState := TZSQLiteNumberState.Create; QuoteState := TZSQLiteQuoteState.Create; WordState := TZSQLiteWordState.Create; CommentState := TZSQLiteCommentState.Create; SetCharacterState(#0, #32, WhitespaceState); SetCharacterState(#33, #191, SymbolState); SetCharacterState(#192, High(Char), WordState); SetCharacterState('a', 'z', WordState); SetCharacterState('A', 'Z', WordState); SetCharacterState('_', '_', WordState); SetCharacterState('0', '9', NumberState); SetCharacterState('.', '.', NumberState); SetCharacterState('"', '"', QuoteState); SetCharacterState(#39, #39, QuoteState); SetCharacterState('[', '[', QuoteState); SetCharacterState(']', ']', QuoteState); SetCharacterState('/', '/', CommentState); SetCharacterState('-', '-', CommentState); end; end. ================================================ FILE: lib/zeosdbo/src/parsesql/ZSybaseAnalyser.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { SQL Statements Analysing classes } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZSybaseAnalyser; interface {$I ZParseSql.inc} uses Classes, ZGenericSqlAnalyser; type {** Implements an Sybase statements analyser. } TZSybaseStatementAnalyser = class (TZGenericStatementAnalyser) end; implementation end. ================================================ FILE: lib/zeosdbo/src/parsesql/ZSybaseToken.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { String tokenizing classes for Sybase } { } { Originally written by Janos Fegyverneki } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZSybaseToken; interface {$I ZParseSql.inc} uses Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} SysUtils, ZTokenizer, ZCompatibility, ZGenericSqlToken; type {** Implements a Sybase-specific number state object. } TZSybaseNumberState = class (TZNumberState) public function NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; override; end; {** Implements a Sybase-specific quote string state object. } TZSybaseQuoteState = class (TZQuoteState) public function NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; override; function EncodeString(const Value: string; QuoteChar: Char): string; override; function DecodeString(const Value: string; QuoteChar: Char): string; override; end; {** This state will either delegate to a comment-handling state, or return a token with just a slash in it. } TZSybaseCommentState = class (TZCppCommentState) public function NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; override; end; {** Implements a symbol state object. } TZSybaseSymbolState = class (TZSymbolState) public constructor Create; end; {** Implements a word state object. } TZSybaseWordState = class (TZGenericSQLWordState) public constructor Create; end; {** Implements a default tokenizer object. } TZSybaseTokenizer = class (TZTokenizer) public constructor Create; end; implementation { TZSybaseNumberState } {** Return a number token from a reader. @return a number token from a reader } function TZSybaseNumberState.NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; var HexDecimal: Boolean; FloatPoint: Boolean; LastChar: Char; function ReadHexDigits: string; begin Result := ''; LastChar := #0; while Stream.Read(LastChar, SizeOf(Char)) > 0 do begin if CharInSet(LastChar, ['0'..'9','a'..'f','A'..'F']) then begin Result := Result + LastChar; HexDecimal := HexDecimal or CharInSet(LastChar, ['a'..'f','A'..'F']); LastChar := #0; end else begin Stream.Seek(-SizeOf(Char), soFromCurrent); Break; end; end; end; function ReadDecDigits: string; begin Result := ''; LastChar := #0; while Stream.Read(LastChar, SizeOf(Char)) > 0 do begin if CharInSet(LastChar, ['0'..'9']) then begin Result := Result + LastChar; LastChar := #0; end else begin Stream.Seek(-SizeOf(Char), soFromCurrent); Break; end; end; end; begin HexDecimal := False; FloatPoint := FirstChar = '.'; LastChar := #0; Result.Value := FirstChar; Result.TokenType := ttUnknown; { Reads the first part of the number before decimal point } if not FloatPoint then begin Result.Value := Result.Value + ReadDecDigits; FloatPoint := (LastChar = '.') and not HexDecimal; if FloatPoint then begin Stream.Read(LastChar, SizeOf(Char)); Result.Value := Result.Value + LastChar; end; end; { Reads the second part of the number after decimal point } if FloatPoint then Result.Value := Result.Value + ReadDecDigits; { Reads a power part of the number } if not HexDecimal and CharInSet(LastChar, ['e','E']) then begin Stream.Read(LastChar, SizeOf(Char)); Result.Value := Result.Value + LastChar; FloatPoint := True; Stream.Read(LastChar, SizeOf(Char)); if CharInSet(LastChar, ['0'..'9','-','+']) then Result.Value := Result.Value + LastChar + ReadDecDigits else begin Result.Value := Copy(Result.Value, 1, Length(Result.Value) - 1); Stream.Seek(-2*SizeOf(Char), soFromCurrent); end; end; { Reads the nexdecimal number } if (Result.Value = '0') and CharInSet(LastChar, ['x','X']) then begin Stream.Read(LastChar, SizeOf(Char)); Result.Value := Result.Value + LastChar + ReadHexDigits; HexDecimal := True; end; { Prepare the result } if Result.Value = '.' then begin if Tokenizer.SymbolState <> nil then Result := Tokenizer.SymbolState.NextToken(Stream, FirstChar, Tokenizer); end else begin if HexDecimal then Result.TokenType := ttHexDecimal else if FloatPoint then Result.TokenType := ttFloat else Result.TokenType := ttInteger; end; end; { TZSybaseQuoteState } {** Return a quoted string token from a reader. This method will collect characters until it sees a match to the character that the tokenizer used to switch to this state. @return a quoted string token from a reader } function TZSybaseQuoteState.NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; var ReadChar: Char; LastChar: Char; begin Result.Value := FirstChar; LastChar := #0; while Stream.Read(ReadChar, SizeOf(Char)) > 0 do begin if ((LastChar = FirstChar) and (ReadChar <> FirstChar) and (FirstChar <> '[')) or ((FirstChar = '[') and (LastChar = ']')) then begin Stream.Seek(-SizeOf(Char), soFromCurrent); Break; end; Result.Value := Result.Value + ReadChar; if (LastChar = FirstChar) and (ReadChar = FirstChar) then LastChar := #0 else LastChar := ReadChar; end; if CharInSet(FirstChar, ['"', '[']) then Result.TokenType := ttWord else Result.TokenType := ttQuoted; end; {** Encodes a string value. @param Value a string value to be encoded. @param QuoteChar a string quote character. @returns an encoded string. } function TZSybaseQuoteState.EncodeString(const Value: string; QuoteChar: Char): string; begin if QuoteChar = '[' then Result := '[' + Value + ']' else if CharInSet(QuoteChar, [#39, '"']) then Result := QuoteChar + Value + QuoteChar else Result := Value; end; {** Decodes a string value. @param Value a string value to be decoded. @param QuoteChar a string quote character. @returns an decoded string. } function TZSybaseQuoteState.DecodeString(const Value: string; QuoteChar: Char): string; begin Result := Value; if Length(Value) >= 2 then begin if CharInSet(QuoteChar, [#39, '"']) and (Value[1] = QuoteChar) and (Value[Length(Value)] = QuoteChar) then begin if Length(Value) > 2 then Result := AnsiDequotedStr(Value, QuoteChar) else Result := ''; end else if (QuoteChar = '[') and (Value[1] = QuoteChar) and (Value[Length(Value)] = ']') then Result := Copy(Value, 2, Length(Value) - 2) end; end; { TZSybaseCommentState } {** Gets a Sybase specific comments like # or /* */. @return either just a slash token, or the results of delegating to a comment-handling state } function TZSybaseCommentState.NextToken(Stream: TStream; FirstChar: Char; Tokenizer: TZTokenizer): TZToken; var ReadChar: Char; ReadNum: Integer; begin Result.Value := FirstChar; Result.TokenType := ttUnknown; if FirstChar = '-' then begin ReadNum := Stream.Read(ReadChar, SizeOf(Char)); if (ReadNum > 0) and (ReadChar = '-') then begin Result.TokenType := ttComment; Result.Value := '--' + GetSingleLineComment(Stream); end else begin if ReadNum > 0 then Stream.Seek(-SizeOf(Char), soFromCurrent); end; end else if FirstChar = '/' then begin ReadNum := Stream.Read(ReadChar, SizeOf(Char)); if (ReadNum > 0) and (ReadChar = '*') then begin Result.TokenType := ttComment; Result.Value := '/*' + GetMultiLineComment(Stream); end else begin if ReadNum > 0 then Stream.Seek(-SizeOf(Char), soFromCurrent); end; end; if (Result.TokenType = ttUnknown) and (Tokenizer.SymbolState <> nil) then Result := Tokenizer.SymbolState.NextToken(Stream, FirstChar, Tokenizer); end; { TZSybaseSymbolState } {** Creates this Sybase-specific symbol state object. } constructor TZSybaseSymbolState.Create; begin inherited Create; Add('<='); Add('>='); Add('<>'); Add('!<'); Add('!>'); Add('!='); end; { TZSybaseWordState } {** Constructs this Sybase-specific word state object. } constructor TZSybaseWordState.Create; begin SetWordChars(#0, #191, False); SetWordChars(#192, high(char), True); SetWordChars('a', 'z', True); SetWordChars('A', 'Z', True); SetWordChars('0', '9', True); SetWordChars('$', '$', True); SetWordChars('_', '_', True); SetWordChars('@', '@', True); SetWordChars('#', '#', True); end; { TZSybaseTokenizer } {** Constructs a tokenizer with a default state table (as described in the class comment). } constructor TZSybaseTokenizer.Create; begin EscapeState := TZEscapeState.Create; WhitespaceState := TZWhitespaceState.Create; SymbolState := TZSybaseSymbolState.Create; NumberState := TZSybaseNumberState.Create; QuoteState := TZSybaseQuoteState.Create; WordState := TZSybaseWordState.Create; CommentState := TZSybaseCommentState.Create; SetCharacterState(#0, #32, WhitespaceState); SetCharacterState(#33, #191, SymbolState); SetCharacterState(#192, High(Char), WordState); SetCharacterState('a', 'z', WordState); SetCharacterState('A', 'Z', WordState); SetCharacterState('_', '_', WordState); SetCharacterState('$', '$', WordState); SetCharacterState('@', '@', WordState); SetCharacterState('#', '#', WordState); SetCharacterState('0', '9', NumberState); SetCharacterState('.', '.', NumberState); SetCharacterState('"', '"', QuoteState); SetCharacterState('''', '''', QuoteState); SetCharacterState('[', '[', QuoteState); SetCharacterState(']', ']', QuoteState); SetCharacterState('/', '/', CommentState); SetCharacterState('-', '-', CommentState); end; end. ================================================ FILE: lib/zeosdbo/src/plain/ZPlain.inc ================================================ {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} {$IFDEF LINUX} {$DEFINE UNIX} {$ENDIF} {$IFNDEF UNIX} {$I ..\Zeos.inc} {$ELSE} {$I ../Zeos.inc} {$ENDIF} ================================================ FILE: lib/zeosdbo/src/plain/ZPlainASAConstants.pas ================================================ {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZPlainASAConstants; interface {$I ZPlain.inc} {$J+} { ***************** Plain API Constants definition **************** } const ASA7_WINDOWS_DLL_LOCATION = 'DBLIB7.DLL'; ASA7_LINUX_DLL_LOCATION = 'libdblib7.so'; ASA8_WINDOWS_DLL_LOCATION = 'DBLIB8.DLL'; ASA8_LINUX_DLL_LOCATION = 'libdblib8.so'; ASA9_WINDOWS_DLL_LOCATION = 'DBLIB9.DLL'; ASA9_LINUX_DLL_LOCATION = 'libdblib9.so'; ASA12_WINDOWS_DLL_LOCATION = 'DBLIB12.DLL'; ASA12_LINUX_DLL_LOCATION = 'libdblib12.so'; //sqlerr.h //* Warnings *// SQLE_NOERROR = 0; SQLE_NOTFOUND = 100; SQLE_TRUNCATED = 101; SQLE_TEMPORARY_TABLE = 102; SQLE_CANNOT_CONVERT = 103; SQLE_ROW_UPDATED_WARNING = 104; SQLE_PROCEDURE_COMPLETE = 105; SQLE_COLUMN_VALUE_CHANGED = 106; SQLE_SYNTAX_EXTENSION_WARNING = 107; SQLE_CURSOR_OPERATION_CONFLICT = 108; SQLE_NULL_VALUE_ELIMINATED = 109; SQLE_BACKUP_PAGE_INCOMPLETE = 110; SQLE_CANNOT_EXECUTE_STMT = 111; SQLE_MORE_INFO = 112; SQLE_INVALID_OPTION_ON_CONNECT = 113; SQLE_CANNOT_PERFORM_CHAR_TRANSLATION = 114; SQLE_UNSUPPORTED_CHARACTER_SET_WARNING = 115; SQLE_UNSUPPORTED_LANGUAGE = 116; SQLE_UNSUPPORTED_CHARSET_AND_LANGUAGE = 117; SQLE_INVALID_USER_ESTIMATE = 118; SQLE_UNABLE_TO_OPEN_BACKUP_LOG = 119; SQLE_UNKNOWN_OPTION = 120; SQLE_CURSOR_OPTIONS_CHANGED = 121; SQLE_DATABASE_NEW = 123; SQLE_CANNOT_CONVERT_LOAD_TABLE = 124; SQLE_INPUT_ILLEGAL_MULTIBYTE_WARNING = 125; SQLE_OUTPUT_ILLEGAL_MULTIBYTE_WARNING = 126; SQLE_INPUT_SIMPLE_SUBSTITUTION_WARNING = 127; SQLE_OUTPUT_SIMPLE_SUBSTITUTION_WARNING = 128; SQLE_ROW_DROPPED_DURING_SCHEMA_UPGRADE = 130; SQLE_CANNOT_DUMP_STRING_HISTOGRAM = 132; SQLE_COMPRESSING_ENCRYPTED_DB = 135; SQLE_WARNING = 200; // SQLE_HLI_MORE_DATA_AVAILABLE = 400; //Errors SQLE_NO_DATABASE_FILE = -72; SQLE_COMMUNICATIONS_UNDERFLOW = -73; SQLE_DATABASE_NOT_ACTIVE = -74; SQLE_START_STOP_DATABASE_DENIED = -75; SQLE_REQUEST_DENIED_NO_DATABASES = -76; SQLE_ALIAS_CLASH = -77; SQLE_DYNAMIC_MEMORY_EXHAUSTED = -78; SQLE_INVALID_LOCAL_OPTION = -79; SQLE_UNABLE_TO_START_ENGINE = -80; SQLE_INVALID_COMMAND_LINE = -81; SQLE_UNABLE_TO_START_DATABASE = -82; SQLE_DATABASE_NOT_FOUND = -83; SQLE_INVALID_DATABASE = -84; SQLE_COMMUNICATIONS_ERROR = -85; SQLE_NO_MEMORY = -86; SQLE_DATABASE_NAME_REQUIRED = -87; SQLE_PROTOCOL_MISMATCH = -88; SQLE_ENGINE_NOT_MULTIUSER = -89; SQLE_ARGUMENT_CANNOT_BE_NULL = -90; SQLE_UNHANDLED_JAVA_EXCEPTION = -91; SQLE_BAD_CLASS_FILE = -92; SQLE_FIELD_NOT_FOUND = -93; SQLE_INVALID_FIELD_REFERENCE = -94; SQLE_INVALID_PARSE_PARAMETER = -95; SQLE_ENGINE_ALREADY_RUNNING = -96; SQLE_PAGE_SIZE_TOO_BIG = -97; SQLE_AUTHENTICATION_VIOLATION = -98; SQLE_CONNECTIONS_DISABLED = -99; SQLE_ENGINE_NOT_RUNNING = -100; SQLE_NOT_CONNECTED = -101; SQLE_TOO_MANY_CONNECTIONS = -102; SQLE_INVALID_LOGON = -103; SQLE_INVALID_PASSWORD = -103; SQLE_INVALID_MODULE_LOGON = -104; SQLE_UNABLE_TO_CONNECT = -105; SQLE_CANNOT_OPEN_LOG = -106; SQLE_ERROR_WRITING_LOG = -107; SQLE_CONNECTION_NOT_FOUND = -108; SQLE_STILL_ACTIVE_CONNECTIONS = -109; SQLE_NAME_NOT_UNIQUE = -110; SQLE_INDEX_NAME_NOT_UNIQUE = -111; SQLE_EXISTING_PRIMARY_KEY = -112; SQLE_INVALID_FOREIGN_KEY_DEF = -113; SQLE_VIEW_DEFINITION_ERROR = -114; SQLE_MUST_DROP_INDEX = -115; SQLE_TABLE_MUST_BE_EMPTY = -116; SQLE_PRIMARY_KEY_REFERENCED = -117; SQLE_NO_PRIMARY_KEY = -118; SQLE_PRIMARY_KEY_COLUMN_DEFINED = -119; SQLE_ALREADY_HAS_GRANT_PERMS = -120; SQLE_PERMISSION_DENIED = -121; SQLE_GROUP_CYCLE = -122; SQLE_NOT_A_GROUP = -123; SQLE_TOO_MANY_COLUMNS_DELETED = -124; SQLE_ALTER_CLAUSE_CONFLICT = -125; SQLE_PRIMARY_KEY_TWICE = -126; SQLE_COLUMN_IN_INDEX = -127; SQLE_USER_OWNS_TABLES = -128; SQLE_INVALID_STATEMENT = -130; SQLE_SYNTAX_ERROR = -131; SQLE_STATEMENT_ERROR = -132; SQLE_INVALID_STATEMENT_TYPE = -133; SQLE_NOT_IMPLEMENTED = -134; SQLE_LANGUAGE_EXTENSION = -135; SQLE_OUTER_JOIN_CYCLE = -136; SQLE_CORRELATION_NAME_NEEDED = -137; SQLE_DBSPACE_NOT_FOUND = -138; SQLE_CORRELATION_NAME_AMBIGUOUS = -139; SQLE_UNKNOWN_USERID = -140; SQLE_TABLE_NOT_FOUND = -141; SQLE_CORRELATION_NAME_NOT_FOUND = -142; SQLE_COLUMN_NOT_FOUND = -143; SQLE_COLUMN_AMBIGUOUS = -144; SQLE_FOREIGN_KEY_NAME_NOT_FOUND = -145; SQLE_CANNOT_JOIN = -146; SQLE_AMBIGUOUS_JOIN = -147; SQLE_UNKNOWN_FUNC = -148; SQLE_INVALID_GROUP_SELECT = -149; SQLE_AGGREGATES_NOT_ALLOWED = -150; SQLE_SUBQUERY_SELECT_LIST = -151; SQLE_INVALID_ORDER = -152; SQLE_INVALID_UNION = -153; SQLE_WRONG_PARAMETER_COUNT = -154; SQLE_VARIABLE_INVALID = -155; SQLE_EXPRESSION_ERROR = -156; SQLE_CONVERSION_ERROR = -157; SQLE_OVERFLOW_ERROR = -158; SQLE_INVALID_COLUMN_NUMBER = -159; SQLE_DESCRIBE_NONSELECT = -160; SQLE_INVALID_DESCRIBE_TYPE = -161; SQLE_CANNOT_OUTER_JOIN = -162; SQLE_NO_COLUMN_NAME = -163; SQLE_NAMESPACE_HEAP_EXHAUSTED = -164; SQLE_JAVA_VM_HEAP_EXHAUSTED = -165; SQLE_CURSOR_NOT_DECLARED = -170; SQLE_OPEN_CURSOR_ERROR = -171; SQLE_CURSOR_ALREADY_OPEN = -172; SQLE_CURSOR_NOT_OPEN = -180; SQLE_NO_INDICATOR = -181; SQLE_SQLDA_TOO_SMALL = -182; SQLE_INDEX_NOT_FOUND = -183; SQLE_PUT_CURSOR_ERROR = -184; SQLE_TOO_MANY_RECORDS = -185; SQLE_SUBQUERY_RESULT_NOT_UNIQUE = -186; SQLE_CURSOROP_NOT_ALLOWED = -187; SQLE_NOT_ENOUGH_HOST_VARS = -188; SQLE_NOT_FOUND_IN_INDEX = -189; SQLE_NON_UPDATEABLE_COLUMN = -190; SQLE_CANNOT_MODIFY = -191; SQLE_NON_UPDATEABLE_VIEW = -192; SQLE_PRIMARY_KEY_NOT_UNIQUE = -193; SQLE_INVALID_FOREIGN_KEY = -194; SQLE_COLUMN_CANNOT_BE_NULL = -195; SQLE_INDEX_NOT_UNIQUE = -196; SQLE_NO_CURRENT_ROW = -197; SQLE_PRIMARY_KEY_VALUE_REF = -198; SQLE_ONLY_ONE_TABLE = -199; SQLE_INVALID_OPTION = -200; SQLE_INVALID_OPTION_SETTING = -201; SQLE_NOT_PUBLIC_ID = -202; SQLE_TEMPORARY_NOT_ALLOWED = -203; SQLE_OPTION_REQUIRES_DBA = -204; SQLE_INVALID_STANDARD_LOGON = -205; SQLE_INVALID_INTEGRATED_LOGON = -206; SQLE_WRONG_NUM_OF_INSERT_COLS = -207; SQLE_ROW_UPDATED_SINCE_READ = -208; SQLE_INVALID_COLUMN_VALUE = -209; SQLE_LOCKED = -210; SQLE_MUST_BE_ONLY_CONNECTION = -211; SQLE_CHECKPOINT_REQUIRES_UNDO = -212; SQLE_SUBTRANS_REQUIRE_UNDO = -213; SQLE_TABLE_IN_USE = -214; SQLE_PROCEDURE_IN_USE = -215; SQLE_OPTION_IS_TEMP_ONLY = -216; SQLE_OPTION_IN_PROCEDURE = -217; SQLE_AUTHENTICATION_FAILED = -218; SQLE_SQLE_SUBTRANS_NOTFOUND = -220; SQLE_ROLLBACK_NOT_ALLOWED = -221; SQLE_RESULT_NOT_ALLOWED = -222; SQLE_PP_DBLIB_MISMATCH = -230; SQLE_DBLIB_ENGINE_MISMATCH = -231; SQLE_SERVER_ENGINE_MISMATCH = -232; SQLE_UNKNOWN_BACKUP_OPERATION = -240; SQLE_BACKUP_NOT_STARTED = -241; SQLE_BACKUP_CANNOT_RENAME_LOG_YET = -242; SQLE_BACKUP_UNABLE_TO_DELETE_FILE = -243; SQLE_LOG_TRUNCATED = -244; SQLE_INTEGRATED_LOGON_FAILED = -245; SQLE_INTEGRATED_LOGON_UNSUPPORTED = -246; SQLE_INTEGRATED_LOGON_GUESTMAP = -247; SQLE_INTEGRATED_LOGON_SYSMAP = -248; SQLE_INTEGRATED_LOGON_MAPPED = -249; SQLE_IDENTIFIER_TOO_LONG = -250; SQLE_DUPLICATE_FOREIGN_KEY = -251; SQLE_PRIMARY_KEY_MULTI_ROW_UPDATE = -252; SQLE_PRIMARY_KEY_CURSOR_UPDATE = -253; SQLE_DELETE_SUBQUERY_SAME_TABLE = -254; SQLE_CURSOR_DELETE_SELF_REF = -255; SQLE_INSERT_SELF_REFERENCING = -256; SQLE_VARIABLE_NOT_FOUND = -260; SQLE_VARIABLE_EXISTS = -261; SQLE_LABEL_NOT_FOUND = -262; SQLE_INVALID_FETCH_POSITION = -263; SQLE_WRONG_NUM_OF_FETCH_VARIABLES = -264; SQLE_PROCEDURE_NOT_FOUND = -265; SQLE_OLD_DBINIT = -266; SQLE_ATOMIC_OPERATION = -267; SQLE_TRIGGER_NOT_FOUND = -268; SQLE_COLUMN_IN_TRIGGER = -269; SQLE_USER_OWNS_PROCEDURES = -270; SQLE_TRIGGER_DEFN_CONFLICT = -271; SQLE_INVALID_TRIGGER_COL_REFS = -272; SQLE_INVALID_TRIGGER_STATEMENT = -273; SQLE_NESTING_TOO_DEEP = -274; SQLE_PROCEDURES_NOT_IN_DESKTOP = -275; SQLE_PUBLICATION_NOT_FOUND = -280; SQLE_TABLE_HAS_PUBLICATIONS = -281; SQLE_SUBSCRIPTION_NOT_UNIQUE = -282; SQLE_SUBSCRIPTION_NOT_FOUND = -283; SQLE_ONLY_ONE_PUBLISHER = -284; SQLE_NOT_REMOTE_USER = -285; SQLE_NOT_REMOTE_TYPE = -286; SQLE_PASSTHROUGH_INCONSISTENT = -287; SQLE_REMOTE_STATEMENT_FAILED = -288; SQLE_CONSOLIDATED_USER_ALREADY_EXISTS = -289; SQLE_INVALID_FORMAT_STRING_ARG_NUM = -294; SQLE_CANNOT_UNIQUELY_IDENTIFY_ROWS = -295; SQLE_ERROR_NUMBER_OUT_OF_RANGE = -296; SQLE_USER_DEFINED_EXCEPTION = -297; SQLE_DOUBLE_REQUEST = -298; SQLE_INTERRUPTED = -299; SQLE_ERROR = -300; SQLE_DATABASE_ERROR = -301; SQLE_TERMINATED_BY_USER = -302; SQLE_DISK_WRITE_FAILED = -303; SQLE_DEVICE_FULL = -304; SQLE_DEVICE_ERROR = -305; SQLE_DEADLOCK = -306; SQLE_THREAD_DEADLOCK = -307; SQLE_CONNECTION_TERMINATED = -308; SQLE_MEMORY_ERROR = -309; SQLE_BEYOND_EOF = -310; SQLE_LOG_CORRUPTED = -311; SQLE_ALREADY_HAS_GROUP_MEMBERSHIP = -312; SQLE_INTEGRATED_LOGON_UNMAPPED = -313; SQLE_HLI_BAD_SYNTAX = -400; SQLE_HLI_BAD_CURSOR = -401; SQLE_HLI_BAD_STATEMENT = -402; SQLE_HLI_BAD_HOST_VAR_NAME = -403; SQLE_HLI_BAD_HOST_VAR_VALUE = -404; SQLE_HLI_BAD_CALLBACK = -405; SQLE_HLI_INTERNAL = -406; SQLE_HLI_BAD_ARGUMENT = -407; SQLE_PHANTOM = -501; SQLE_UNBLOCKED = -502; SQLE_PREEMPTED = -503; SQLE_RETRY = -504; SQLE_UNSUPPORTED_LOAD_FORMAT = -601; SQLE_CANNOT_ACCESS_FILE = -602; SQLE_COLUMN_VALUE_TOO_LONG = -603; SQLE_DBSPACE_FULL = -604; SQLE_ACCESS_BEYOND_END_OF_MAX_DBSPACE = -605; SQLE_PATTERN_TOO_LONG = -606; SQLE_CANNOT_STOP_SERVER = -607; SQLE_INVALID_TEXTPTR_VALUE = -608; SQLE_INVALID_TEXT_IMAGE_DATATYPE = -609; SQLE_MESSAGE_ALREADY_EXISTS = -610; SQLE_TSQL_FEATURE_NOT_SUPPORTED = -611; SQLE_MESSAGE_NOT_FOUND = -612; SQLE_USER_TYPE_NOT_FOUND = -613; SQLE_USER_OWNS_MESSAGES_OR_DATATYPES = -614; SQLE_INVALID_PARAMETER_NAME = -615; SQLE_TOO_MANY_COLUMNS_IN_TABLE = -616; SQLE_EXTERNAL_CALLS_NOT_SUPPORTED = -617; SQLE_EXTERNAL_PLATFORM_FAILURE = -618; SQLE_REQUIRE_DLL_NAME = -619; SQLE_COULD_NOT_LOAD_LIBRARY = -620; SQLE_COULD_NOT_FIND_FUNCTION = -621; SQLE_ERROR_CALLING_FUNCTION = -622; SQLE_DDL_NOT_ALLOWED_IN_PROCEDURES = -623; SQLE_DATATYPE_NOT_ALLOWED = -624; SQLE_TOO_MANY_PARAMETERS = -625; SQLE_THREAD_START_FAILURE = -626; SQLE_INVALID_SYNTAX_EXTENSION = -627; SQLE_DIV_ZERO_ERROR = -628; SQLE_INVALID_ESCAPE_CHAR = -629; SQLE_INVALID_ESCAPE_SEQ = -630; SQLE_RAISERROR_STMT = -631; SQLE_WITH_CHECK_OPTION_VIOLATION = -632; SQLE_READ_ONLY_CURSOR = -633; SQLE_UNTERMINATED_C_STR = -634; SQLE_NO_COLUMN_PERMS_FOR_VIEWS = -635; SQLE_DUPLICATE_REFERENCING_COLUMN = -636; SQLE_DUPLICATE_INSERT_COLUMN = -637; SQLE_STRING_RIGHT_TRUNCATION = -638; SQLE_PARAMETER_NAME_MISSING = -639; SQLE_INVALID_DESCRIPTOR_INDEX = -640; SQLE_ERROR_IN_ASSIGNMENT = -641; SQLE_INVALID_DESCRIPTOR_NAME = -642; SQLE_CANNOT_UNLOAD_A_VIEW = -643; SQLE_PAGE_SIZE_INVALID = -644; SQLE_DATABASE_NOT_CREATED = -645; SQLE_STORE_NOT_LOADED = -646; SQLE_STORE_ENTRY_NOT_FOUND = -647; SQLE_INVALID_DBSPACE_FOR_CREATE = -648; SQLE_FIELD_CANNOT_BE_NULL = -649; SQLE_INVALID_INDEX_TYPE = -650; SQLE_DROP_DATABASE_FAILED = -651; SQLE_CANNOT_DECOMPRESS_CLASS = -652; SQLE_CLASS_MEMBER_OF_JAR = -653; SQLE_NO_PROFILE_FILE = -654; SQLE_GEN_PARSE_ERROR = -655; SQLE_OMNI_CONNECT_ERROR = -656; SQLE_OMNI_NO_RMT_OBJ = -657; SQLE_OMNI_READONLY = -658; SQLE_OMNI_SERVER_NOT_FOUND = -659; SQLE_OMNI_REMOTE_ERROR = -660; SQLE_OMNI_BACKWARDS_CURSOR = -661; SQLE_JAVA_SERIALIZATION_ERROR = -662; SQLE_JAVA_DESERIALIZATION_ERROR = -663; SQLE_DATABASE_ACTIVE = -664; SQLE_DATABASE_NEEDS_RECOVERY = -665; SQLE_OMNI_RMT_TABLE_NOTFOUND = -666; SQLE_OMNI_RMT_COLUMNS_NOTFOUND = -667; SQLE_NO_SCROLL_CURSOR = -668; SQLE_METHOD_CANNOT_BE_CALLED = -669; SQLE_BAD_CLASS_BYTE_CODE = -670; SQLE_PARAM_NOT_REGISTERED = -671; SQLE_DATABASE_UPGRADE_FAILED = -672; SQLE_DATABASE_UPGRADE_NOT_POSSIBLE = -673; SQLE_INVALID_CURSOR_RANGE = -674; SQLE_JAVA_VM_NOT_STARTED = -675; SQLE_INVALID_TRANSACTION_ISOLATION = -676; SQLE_TABLE_HAS_REFACTION = -677; SQLE_AMBIGUOUS_INDEX_NAME = -678; SQLE_OMNI_MEMORY_CONFIG = -679; SQLE_INVALID_TSQL_OJ_EXPRESSION = -680; SQLE_INVALID_TSQL_JOIN_TYPE = -681; SQLE_OMNI_DEBUG = -682; SQLE_DUPLICATE_CURSOR_NAME = -683; SQLE_ROLLBACK_ON_PREFETCH = -684; SQLE_RESOURCE_GOVERNOR_EXCEEDED = -685; SQLE_JAVA_VM_INSUFFICIENT_CACHE = -686; SQLE_IQ_PATH_SYNTAX_ERROR = -687; SQLE_NO_ENCRYPTION_IN_RUNTIME = -688; SQLE_BAD_PARAM_INDEX = -689; SQLE_RETVAL_CANNOT_BE_SET = -690; SQLE_BACKUP_NOT_LOADED = -691; SQLE_BACKUP_ENTRY_NOT_FOUND = -692; SQLE_UNSUPPORTED_JDBC_FEATURE = -693; SQLE_CANNOT_CHANGE_OPENED_STATEMENT = -694; SQLE_JDBC_OBJ_INTERNAL_ERR = -695; SQLE_JDBC_OBJ_CLOSED = -696; SQLE_BACKUP_ERROR = -697; SQLE_OMNI_AUTOINC_NOT_SUPPORTED = -698; SQLE_CANNOT_UPDATE_FINAL_FIELD = -699; SQLE_SQLDA_INCONSISTENT = -700; SQLE_CANNOT_ACCESS_INSTANCE_MEMBER = -701; SQLE_CANNOT_TRUNCATE_VIEW = -702; SQLE_COMPUTED_COLUMN_WRITE_ATTEMPTED = -703; SQLE_CANNOT_INDEX_ON_JAVA_CLASS = -704; SQLE_PROCEDURE_RETURNS_VOID = -705; SQLE_OMNI_SERVER_NOT_CAPABLE = -706; SQLE_STMT_NOT_ALLOWED_IN_PASSTHROUGH = -707; SQLE_TEXT_OPERATION_ON_VIEW = -708; SQLE_COMPUTED_COLUMNS_NOT_SUPPORTED = -709; SQLE_INVALID_COMPARISON = -710; SQLE_STORE_VERSION_MISMATCH = -711; SQLE_OMNI_EXTLOGIN_NOT_FOUND = -712; SQLE_JNAT_OBJ_INTERNAL_ERR = -713; SQLE_JNAT_OBJ_CLOSED = -714; SQLE_RESTORE_INCONSISTENT = -715; SQLE_RESTORE_INVALID_FORMAT = -716; SQLE_RESTORE_UNABLE_TO_OPEN = -717; SQLE_RESTORE_UNABLE_TO_WRITE = -718; SQLE_RESTORE_UNABLE_TO_START = -719; SQLE_CANNOT_VALIDATE_OBJECT = -720; SQLE_OMNI_DATATYPE_MISMATCH = -721; SQLE_OMNI_NOSUCH_COLUMN = -722; SQLE_OMNI_LENGTH_MISMATCH = -723; SQLE_OMNI_NULL_MISMATCH = -724; SQLE_OMNI_IDENTITY_MISMATCH = -725; SQLE_OMNI_RMT_TABLE_NOTUNIQUE = -726; SQLE_CANNOT_OPTIMIZE_QUERY = -727; SQLE_NON_UPDATEABLE_EXT_TAB = -728; SQLE_UNENFORCEABLE_FOREIGN_KEY = -729; SQLE_BAD_JAR_FILE = -730; SQLE_USER_OWNS_REPLICATED_OBJECTS = -731; SQLE_OMNI_COMPUTED_NOT_SUPPORTED = -732; SQLE_TOO_MANY_NULL_COLUMNS = -733; SQLE_CANNOT_UPDATE_NULL_ROW = -734; SQLE_INVALID_PARAMETER = -735; SQLE_OMNI_UNSUPPORTED_DATATYPE = -736; SQLE_SIGNATURE_MISMATCH = -737; SQLE_PASSWORD_TOO_SHORT = -738; SQLE_DB_INIT_NOT_CALLED = -739; SQLE_FAILED_TO_CREATE_STREAMS_ENV = -740; SQLE_NOTA_WRITE_FILE = -741; SQLE_JDBC_BATCH_EXECUTE_ABANDONED = -742; SQLE_JDBC_RESULTSET_SEEK_ABSOLUTE_ZERO = -743; SQLE_IQ_INVALID_COMMAND_LINE = -744; SQLE_IQ_MEMORY_MANAGER_FAILED = -745; SQLE_IQ_SYSTEM_V_FAILURE = -746; SQLE_JDBC_INVALID_RESULTSET_TYPE = -747; SQLE_JDBC_INVALID_RESULTSET_CONCURRENCY = -748; SQLE_NOT_SUPPORTED_IN_ULTRALITE = -749; SQLE_USER_OWNS_PROCEDURES_IN_USE = -750; SQLE_USER_OWNS_TABLES_IN_USE = -751; SQLE_JDBC_INVALID_OPER_ON_INSERT_ROW = -752; SQLE_JDBC_MUST_OPER_ON_INSERT_ROW = -753; SQLE_INVALID_DSN_NAME = -754; SQLE_UNCOMMITTED_TRANSACTIONS = -755; SQLE_JDBC_TBL_COL_NOT_FOUND_IN_RESULTSET = -756; SQLE_READ_ONLY_DATABASE = -757; SQLE_NO_JAVA_SUPPORT = -758; SQLE_SQLDA_INVALID_DATATYPE = -759; SQLE_INVALID_SQL_IDENTIFIER = -760; SQLE_CAPABILITY_NOT_FOUND = -761; SQLE_NON_PUBLIC_JAVA_CLASS = -762; SQLE_UNKNOWN_JAVA_REF = -763; SQLE_UNABLE_TO_CONNECT_OR_START = -764; SQLE_NOT_SYNC_TYPE = -765; SQLE_VIEW_OVER_TEMP_OBJECT = -766; SQLE_SYNCHRONIZATION_NOT_FOUND = -767; SQLE_CANNOT_SUBSCRIBE = -768; SQLE_CANNOT_MODIFY_SYNC_AS_PUB = -769; SQLE_CANNOT_MODIFY_PUB_AS_SYNC = -770; SQLE_EVENT_NOT_FOUND = -771; SQLE_EVENT_ALREADY_EXISTS = -772; SQLE_SCHEDULE_NOT_FOUND = -773; SQLE_SCHEDULE_ALREADY_EXISTS = -774; SQLE_CANNOT_SYNC_TABLE_WITHOUT_PK = -777; SQLE_PK_NOT_IN_SYNC_ARTICLE = -778; SQLE_BLOB_IN_SYNC_TABLE_PK = -779; SQLE_ARTICLE_PK_CANNOT_BE_UPDATED = -780; SQLE_SAME_EXCLUSIVE_APP_RUNNING = -782; SQLE_SAME_APP_RUNNING = -783; SQLE_CANNOT_REG_CONN = -784; SQLE_DEREG_APP_NOT_FOUND = -785; SQLE_DEREG_APP_IN_USE = -786; SQLE_CONN_ALREADY_REGISTERED = -787; SQLE_NOT_UNIQUE_CONN_REG_LABEL = -788; SQLE_APP_REG_COOKIE_EXHAUSTED = -789; SQLE_CONN_REG_AUTO_LABEL_EXHAUSTED = -790; SQLE_INVALID_EVENT_DAY = -791; SQLE_INVALID_EVENT_TIME = -792; SQLE_INVALID_EVENT_START = -793; SQLE_UPLOAD_FAILED_AT_SERVER = -794; SQLE_SYNC_TEMPLATE_NOT_FOUND = -795; SQLE_SYNC_SITE_NOT_UNIQUE = -796; SQLE_BAD_SYNC_OPTION_VALUE = -797; SQLE_DTC_TRANSACTIONS_NOT_SUPPORTED = -799; SQLE_CANNOT_COMMIT_OR_ROLLBACK_WHILE_ENLISTED = -800; SQLE_CANNOT_ENLIST_WHILE_ALREADY_ENLISTED = -801; SQLE_CANNOT_ENLIST_WITH_UNCOMMITTED_DATA = -802; SQLE_FAILED_TO_ENLIST = -803; SQLE_FAILED_TO_REENLIST = -804; SQLE_SYNC_OPTION_NOT_FOUND = -805; SQLE_EVENT_TYPE_NOT_FOUND = -806; SQLE_HOSTVARS_IN_BATCH = -807; SQLE_TEST_HARNESS = -808; SQLE_SYNC_OPTION_TOO_LONG = -809; SQLE_JAVA_CLASS_NOT_FOUND = -810; SQLE_JAR_NOT_FOUND = -811; SQLE_NO_MATCHING_SELECT_ITEM = -812; SQLE_NON_UPDATEABLE_CURSOR = -813; SQLE_CANNOT_UPDATE_ORDER_BY_COLUMN = -814; SQLE_UPDATE_NOT_IN_SELECT = -815; SQLE_FILE_IN_USE = -816; SQLE_TOO_MANY_TEMP_TABLES = -817; SQLE_INCOMPATIBLE_EXTERNAL_CALL = -818; SQLE_SYNC_CONTAINS_TABLE = -819; SQLE_INVALID_POSITION = -820; SQLE_DBSPACE_FOR_TABLE_UNAVAILABLE = -821; SQLE_TABLE_ALREADY_INCLUDED = -822; SQLE_OMNI_EXPRESSION_IN_PROC = -823; SQLE_INVALID_CORRELATION_NAME_REFERENCE = -824; SQLE_PREVIOUS_ERROR_LOST = -825; SQLE_DBO_DOES_NOT_OWN_ROWGENERATOR = -826; SQLE_USER_TABLES_IN_SYSTEM_RANGE = -827; SQLE_RECORDING_CONFLICT_DETECTED = -828; SQLE_CERTICOM_HANDSHAKE_FAILED = -829; SQLE_ALIAS_NOT_UNIQUE = -830; SQLE_ALIAS_NOT_YET_DEFINED = -831; SQLE_CONNECTION_ERROR = -832; SQLE_ROW_REMODIFIED_OR_DELETED = -833; SQLE_COLUMN_NOT_FOUND_IN_TABLE = -834; SQLE_EVENT_IN_USE = -835; SQLE_PROCEDURE_NO_LONGER_VALID = -836; SQLE_TRIGGER_NO_LONGER_VALID = -837; SQLE_CERTICOM_INIT_FAILED_ON_SRV = -838; SQLE_DOWNLOAD_CONFLICT = -839; SQLE_BAD_ENCRYPTION_KEY = -840; SQLE_JDK_VERSION_MISMATCH = -841; SQLE_UNSUPPORTED_JDK = -842; SQLE_SYNC_SITE_NOT_FOUND = -843; SQLE_SYNC_DEFINITION_NOT_FOUND = -844; SQLE_INVALID_COLUMN_QUALIFICATION = -845; SQLE_INVALID_SET_CLAUSE = -846; SQLE_JAVA_SECMGR_NOT_FOUND = -847; SQLE_JAVA_SECMGR_EXCEPTION = -848; SQLE_INVALID_FOREIGN_KEY_ACTION = -849; SQLE_INVALID_FOREIGN_KEY_TABLE = -850; SQLE_DECRYPT_ERROR = -851; SQLE_AMBIGUOUS_TABLE_NAME = -852; SQLE_CURSOR_INVALID_STATE = -853; SQLE_INVALID_ORDERBY_COLUMN = -854; SQLE_AMBIGUOUS_TRIGGER_NAME = -855; SQLE_INVALID_SQLLEN = -856; SQLE_SERVER_SYNCHRONIZATION_ERROR = -857; SQLE_HISTOGRAMS_NOT_SUPPORTED_ON_OBJECT = -858; SQLE_JAVA_IN_USE = -859; SQLE_DBSPACE_NOT_CALIBRATED = -860; SQLE_MULTIPLE_AGGREGATE_COLUMNS = -861; SQLE_INVALID_AGGREGATE_PLACEMENT = -862; SQLE_INVALID_DISTINCT_AGGREGATE = -863; SQLE_INVALID_NUMBER = -864; SQLE_INVALID_FOREIGN_KEY_INDEX = -865; SQLE_CANNOT_CHANGE_USER_NAME = -867; SQLE_UNKNOWN_CHARSET = -868; SQLE_UNSUPPORTED_CHARACTER_SET_ERROR = -869; SQLE_FAILED_TO_START_CONVERTER = -870; SQLE_JAVA_DB_RESTART_NEEDED = -871; SQLE_CANNOT_JOIN_TABEXPR = -875; SQLE_CLIENT_OUT_OF_MEMORY = -876; SQLE_SETUSER_NOT_IN_PROCEDURES = -877; SQLE_CLUSTERED_INDEX_NOT_ALLOWED = -878; SQLE_INPUT_ILLEGAL_MULTIBYTE_ERROR = -879; SQLE_OUTPUT_ILLEGAL_MULTIBYTE_ERROR = -880; SQLE_INPUT_SIMPLE_SUBSTITUTION_ERROR = -881; SQLE_OUTPUT_SIMPLE_SUBSTITUTION_ERROR = -882; SQLE_CHARACTER_CONVERSION_REPORT_NOT_AVAILABLE = -883; SQLE_NONDETERMINISTIC_FUNCTION = -889; SQLE_SYNTACTIC_LIMIT = -890; SQLE_FAILED_TO_START_CONVERTER_2_CHARSETS = -891; SQLE_STMT_NOT_ALLOWED_IN_PLAN = -894; SQLE_ENCRYPT_ERROR = -895; SQLE_UNSET_PUBLIC_ID = -896; SQLE_BAD_FOR_XML_EXPLICIT_TAG = -897; SQLE_BAD_FOR_XML_EXPLICIT_DIRECTIVE = -898; SQLE_BAD_FOR_XML_EXPLICIT_COLUMN_NAME = -899; SQLE_EXPLICIT_TAG_NOT_OPEN = -900; SQLE_UNDECLARED_FOR_XML_EXPLICIT_TAG = -901; SQLE_FOR_XML_EXPLICIT_TOO_FEW_COLUMNS = -902; SQLE_FOR_XML_EXPLICIT_NAMED_CDATA = -903; SQLE_INVALID_ORDERBY_IN_AGGREGATE = -904; SQLE_INVALID_XQUERY_CONSTRUCTOR = -905; SQLE_XMLGEN_EVALUATION_FAILURE = -906; SQLE_NO_SQLX_ARGUMENT_NAME = -907; SQLE_ULTRALITE_OBJ_CLOSED = -908; SQLE_SYSTEM_COMMAND_FAILED = -910; SQLE_IQ_LOG_REQUIRED = -933; SQLE_UNABLE_TO_START_DATABASE_VER_NEWER = -934; SQLE_PASSWORD_TOO_LONG = -958; SQLE_ILLEGAL_PASSWORD = -963; SQLE_ALREADY_HAS_EXEC_PERMS = -968; SQLE_PAGE_SIZE_TOO_SMALL = -972; SQLE_STRING_PARM_TOO_LONG = -973; SQLE_INVALID_TEMP_TABLE_COMMIT_ACTION = -993; SQLE_TOO_MANY_ARGUMENTS = -994; SQLE_TEMP_SPACE_LIMIT = -1000; SQLE_FILE_NOT_DB = -1004; SQLE_FILE_WRONG_VERSION = -1005; SQLE_FILE_BAD_DB = -1006; SQLE_CORRUPT_REDO = -1007; SQLE_CORRUPT_REDO_MIRROR = -1008; SQLE_CORRUPT_REDO_OR_MIRROR = -1009; SQLE_EXPECTING_NO_REDO = -1010; SQLE_UNKNOWN_ENCRYPTION_ALGORITHM = -1011; SQLE_UPGRADE_DATABASE = -1012; SQLE_NO_DB_FOR_WRITE = -1013; SQLE_FILE_IS_COMPRESSED = -1014; SQLE_OLD_WRITE = -1015; SQLE_LOG_NEWER_THAN_DB = -1016; SQLE_LOG_NOT_FOUND = -1017; SQLE_LOG_OFFSETS_DONT_MATCH = -1018; SQLE_LOG_OLDER_THAN_DB = -1019; SQLE_LOG_TOO_SHORT = -1020; {dpp_fetch} CUR_RELATIVE = 2; CUR_ABSOLUTE = 1; CUR_FORUPDATE = 8; CUR_FORREGULAR = 0; CUR_DONTHOLD = 1; CUR_READONLY = 2; CUR_OPEN_DECLARE = 32; CUR_DYNAMIC_SCROLL = 64; CUR_SCROLL = 128; CUR_SENSITIVE = 256; CUR_INSENSITIVE = 1024; CUR_UNIQUE = 2048; CUR_UPDATE = 4096; CUR_UPDATEBYLOCK = CUR_UPDATE + 512; CUR_UPDATEBYVALUES = CUR_UPDATEBYLOCK + 8192; CUR_UPDATEBYTIMESTAMP = CUR_UPDATE + 8192; CUR_NOSCROLL = 16384; SQL_DESCRIBE_OUTPUT = 1; SQL_DESCRIBE_INPUT = 2; SQL_DESCRIBE_ALL = 3; SQL_DESCRIBE_VAR_RESULT = 8; SQL_PREPARE_DESCRIBE_STMTNAME = 1; SQL_PREPARE_DESCRIBE_STMTNUM = 3; SQL_PREPARE_DESCRIBE_OUTPUT = 256; SQL_PREPARE_DESCRIBE_INPUT = 512; SQL_PREPARE_DESCRIBE_LONGNAMES= 1024; SQL_PREPARE_DESCRIBE_VARRESULT= 2048; SQL_LONGNAMES_COLUMN = 1; SQL_LONGNAMES_TABLE = 3; SQL_LONGNAMES_OWNER = 7; DT_PROCEDURE_OUT = $8000; DT_PROCEDURE_IN = $4000; DT_UPDATEABLE = $2000; DT_DESCRIBE_INPUT = $1000; DT_AUTO_INCREMENT = $0800; DT_KEY_COLUMN = $0400; DT_HIDDEN_COLUMN = $0200; DT_HAS_USERTYPE_INFO = $0100; DT_NULLS_ALLOWED = $0001; {dataTypes } DT_NOTYPE = 0; DT_SMALLINT = 500; DT_INT = 496; DT_DECIMAL = 484; DT_FLOAT = 482; DT_DOUBLE = 480; DT_DATE = 384; DT_STRING = 460; DT_FIXCHAR = 452; DT_VARCHAR = 448; DT_LONGVARCHAR = 456; DT_TIME = 388; DT_TIMESTAMP = 392; DT_TIMESTAMP_STRUCT = 390; DT_BINARY = 524; DT_LONGBINARY = 528; DT_VARIABLE = 600; DT_TINYINT = 604; DT_BIGINT = 608; DT_UNSINT = 612; DT_UNSSMALLINT = 616; DT_UNSBIGINT = 620; DT_BIT = 624; DT_NSTRING = 628; DT_NFIXCHAR = 632; DT_NVARCHAR = 636; DT_LONGNVARCHAR = 640; //Message Types Markus MESSAGE_TYPE_INFO = 0; MESSAGE_TYPE_WARNING = 1; MESSAGE_TYPE_ACTION = 2; MESSAGE_TYPE_STATUS = 3; type a_sql_len = SmallInt; a_sql_ulen = Word; a_sql_int32 = LongInt; a_sql_type = SmallInt; an_sql_code = LongInt; an_sql_state = array[0..5] of AnsiChar; type TZASASQLWARN = record sqlWarn0: array[0..0] of AnsiChar; sqlWarn1: array[0..0] of AnsiChar; sqlWarn2: array[0..0] of AnsiChar; sqlWarn3: array[0..0] of AnsiChar; sqlWarn4: array[0..0] of AnsiChar; sqlWarn5: array[0..0] of AnsiChar; sqlWarn6: array[0..0] of AnsiChar; sqlWarn7: array[0..0] of AnsiChar; sqlWarn8: array[0..0] of AnsiChar; sqlWarn9: array[0..0] of AnsiChar; end; PZASASQLCA = ^TZASASQLCA; TZASASQLCA = record sqlcaID: array[0..7] of AnsiChar; sqlcAbc : a_sql_int32; sqlCode : an_sql_code; sqlErrml : SmallInt; sqlErrmc : array[0..69] of AnsiChar; sqlErrp : array[0..7] of AnsiChar; sqlErrd : array[0..5] of a_sql_int32; sqlWarn : TZASASQLWARN; sqlState: array[0..5] of AnsiChar; end; PZASASQLNAME = ^TZASASQLNAME; TZASASQLNAME = record length : Word; data: array[0..29] of AnsiChar; end; PZASASQLSTRING = ^TZASASQLSTRING; TZASASQLSTRING = record length : Word; data: array[0..0] of AnsiChar; end; PZASASQLVAR = ^TZASASQLVAR; TZASASQLVAR = record sqlType: SmallInt; sqlLen : a_sql_len; sqlData: Pointer; sqlInd : PSmallInt; sqlName: TZASASQLNAME; end; PASASQLDA = ^TASASQLDA; TASASQLDA = record sqldaid: array[0..7] of AnsiChar; sqldabc : LongWord; sqln : SmallInt; sqld : SmallInt; sqlVar : array[0..32767] of TZASASQLVAR; end; PZASASQLDateTime = ^TZASASQLDateTime; TZASASQLDateTime = packed record Year : SmallInt; //* e.g. 1992 *// Month : Byte; //* 0-11 *// Day_of_Week : Byte; //* 0-6 0=Sunday, 1=Monday, ... *// Day_of_Year : SmallInt; //* 0-365 *// Day : Byte; //* 1-31 *// Hour : Byte; //* 0-23 *// Minute : Byte; //* 0-59 *// Second : Byte; //* 0-59 *// MicroSecond : LongInt; //* 0-999999 *// end; PZASABlobStruct = ^TZASABlobStruct; TZASABlobStruct = record array_len : Longword; stored_len : Longword; untrunc_len : Longword; arr: array[0..312756] of AnsiChar; end; ZASA_db_callback_index = ( //Markus DB_CALLBACK_START, DB_CALLBACK_WAIT, DB_CALLBACK_FINISH, DB_CALLBACK_ASYNC_RESPONSE, DB_CALLBACK_TRANSLATE_IN, DB_CALLBACK_TRANSLATE_OUT, DB_CALLBACK_UNKNOWN_EVENT, // For Macintosh, initially DB_CALLBACK_MESSAGE, // Messages from the engine during a request DB_CALLBACK_CONN_DROPPED, DB_CALLBACK_DEBUG_MESSAGE, DB_MAX_CALLBACK ); TZASASQLCallback = procedure() {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; { ****************** Plain API Types definition ***************** } type TASABasic = function( sqlca: PZASASQLCA): Integer; {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASABasicWithParam = function(sqlca: PZASASQLCA; Params: PAnsiChar): LongWord; {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASAfind_engine = function(sqlca: PZASASQLCA; Params: PAnsiChar): Word; {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASAAlloc_sqlda = function( NumVar: LongWord): PASASQLDA; {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASAfill_sqlda = function( Parameter: PASASQLDA): PASASQLDA; {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASAfill_s_sqlda = function( Parameter: PASASQLDA; MaxLength: Integer): PASASQLDA; {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASAProc_sqlda = procedure( Parameter: PASASQLDA); {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASAdbpp_setConnect = procedure(sqlca: PZASASQLCA; ConnName: PAnsiChar); {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASAdbpp_describe_cursor = procedure(sqlca: PZASASQLCA; CursorName: PAnsiChar; Descriptor: PASASQLDA; SomeNumber: LongWord); {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASAdbpp_prepare_into = procedure(sqlca: PZASASQLCA; UnKnown: PAnsiChar; ProgName: PAnsiChar; RecordStatementNum: PSmallInt; SqlStatement: PAnsiChar; Descriptor1: PASASQLDA; Descriptor2: PASASQLDA; SomeNumber: LongWord); {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASAdbpp_prepare_describe = procedure(sqlca: PZASASQLCA; UnKnown: PAnsiChar; ProgName: PAnsiChar; RecordStatementNum: PSmallInt; SqlStatement: PAnsiChar; Descriptor1: PASASQLDA; Descriptor2: PASASQLDA; WhatToDesc: LongWord; LongNames: Word); {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; {ASA12 dbpp_prepare_describe_12, (SQLCA *,char *,char *,short int *,char *,struct sqlda *,struct sqlda *,unsigned int, unsigned short int, a_sql_uint32 ))} TASAdbpp_prepare_describe_12 = procedure (SQLCA: PZASASQLCA; UnKnown: PAnsiChar; ProgName: PAnsiChar; RecordStatementNum: PSmallInt; SqlStatement: PAnsiChar; Descriptor1: PASASQLDA; Descriptor2: PASASQLDA; WhatToDesc: LongWord; LongNames: Word; UnknownUint2: Longword) {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASAdbpp_select = procedure(sqlca: PZASASQLCA; UnKnown: PAnsiChar; ProgName: PAnsiChar; RecordStatementNum: PSmallInt; Descriptor1, Descriptor2: PASASQLDA); {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASAdbpp_open = procedure(sqlca: PZASASQLCA; CursorName: PAnsiChar; UnKnown: PAnsiChar; ProgName: PAnsiChar; RecordStatementNum: PSmallInt; Descriptor1: PASASQLDA; BlockSize: SmallInt; IsolationLvl: SmallInt; Options : Word); {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASAdbpp_close = procedure(sqlca: PZASASQLCA; CursorName: PAnsiChar); {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASAdbpp_fetch = procedure(sqlca: PZASASQLCA; CursorName: PAnsiChar; Offset: Word; RelPositon: LongInt; Descriptor1: PASASQLDA; BlockSize: SmallInt; Options: Word); {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASAdbpp_declare = procedure(sqlca: PZASASQLCA; CursorName: PAnsiChar; UnKnown: PAnsiChar; ProgName: PAnsiChar; RecordStatementNum: PSmallInt; Options: Word); {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASAdbpp_dropstmt = procedure(sqlca: PZASASQLCA; UnKnown: PAnsiChar; ProgName: PAnsiChar; RecordStatementNum: PSmallInt); {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASAdbpp_describe = procedure(sqlca: PZASASQLCA; UnKnown: PAnsiChar; ProgName: PAnsiChar; RecordStatementNum: PSmallInt; Descriptor: PASASQLDA; WhatToDesc: Word); {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASAdbpp_delete = procedure(sqlca: PZASASQLCA; CursorName: PAnsiChar; UnKnown1: PAnsiChar; UnKnown2: PAnsiChar); {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASAdbpp_update = procedure(sqlca: PZASASQLCA; CursorName: PAnsiChar; Descriptor: PASASQLDA); {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASAdbpp_execute_imm = procedure(sqlca: PZASASQLCA; SqlRecordStatement: PAnsiChar; UnKnown1: Word); {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASAdbpp_put_into = procedure(sqlca: PZASASQLCA; CursorName: PAnsiChar; Descriptor: PASASQLDA; UnKnown1: PASASQLDA); {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASAdbpp_put_array = procedure(sqlca: PZASASQLCA; CursorName: PAnsiChar; Descriptor: PASASQLDA; Into_sqlda: PASASQLDA; Rows: Word); {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASAdbpp_commit = procedure( sqlca: PZASASQLCA; SomeNumber: LongWord); {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASAdbpp_rollback = procedure( sqlca: PZASASQLCA; SomeNumber: LongWord); {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASAdbpp_execute_into = procedure(sqlca: PZASASQLCA; UnKnown: PAnsiChar; ProgName: PAnsiChar; RecordStatementNum: PSmallInt; Descriptor1: PASASQLDA; Descriptor2: PASASQLDA); {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASAdbpp_get_data = procedure(sqlca: PZASASQLCA; CursorName: PAnsiChar; ColumnNumber: Word; Offset: LongInt; Descriptor1: PASASQLDA; Unknown: Word); {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASAdbpp_explain = procedure(sqlca: PZASASQLCA; CursorName: PAnsiChar; SomeNumber1: Word; Descriptor1: PASASQLDA); {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASASQLCallback = procedure() {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASAdb_register_a_callback = procedure( sqlca: PZASASQLCA; CBIdx: integer; Proc: TASASQLCallback); {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASAdbpp_setoption = procedure( sqlca: PZASASQLCA; Temporary: LongInt; User: PAnsiChar; Option: PAnsiChar; Descriptor: PASASQLDA); {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASAdbpp_fetch_array = procedure(sqlca: PZASASQLCA; CursorName: PAnsiChar; Offset: Word; RelPositon: LongInt; Descriptor1: PASASQLDA; BlockSize: SmallInt; Options: Word; ArrayWidth: Word); {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASAerror_message = function(sqlca: PZASASQLCA; Buffer: PAnsiChar; MaxSize: Integer): PAnsiChar; {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASAdbpp_resume = procedure(sqlca: PZASASQLCA; CursorName: PAnsiChar); {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASAdb_cancel_request = function( sqlca: PZASASQLCA): Integer; {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASAdb_change_char_charset = function( sqlca: PZASASQLCA; const CharSet: PAnsiChar): Word; {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; TASAdb_change_nchar_charset = function( sqlca: PZASASQLCA; const CharSet: PAnsiChar): Word; {$IFNDEF LINUX} stdcall {$ELSE} cdecl {$ENDIF}; { ************* Plain API Function variables definition ************ } TASA_API = record sqlerror_message: TASAerror_message; db_init: TASABasic; db_fini: TASABasic; db_find_engine: TASAfind_engine; db_string_connect: TASABasicWithParam; db_string_disconnect: TASABasicWithParam; db_start_engine: TASABasicWithParam; db_stop_engine: TASABasicWithParam; db_start_database: TASABasicWithParam; db_stop_database: TASABasicWithParam; alloc_sqlda: TASAAlloc_sqlda; free_sqlda: TASAProc_sqlda; free_sqlda_noind: TASAProc_sqlda; fill_sqlda: TASAfill_sqlda; free_filled_sqlda: TASAProc_sqlda; fill_s_sqlda: TASAfill_s_sqlda; dbpp_setConnect: TASAdbpp_setConnect; dbpp_describe_cursor: TASAdbpp_describe_cursor; dbpp_disconnect: TASAdbpp_setConnect; dbpp_prepare_into: TASAdbpp_prepare_into; dbpp_prepare_describe: TASAdbpp_prepare_describe; dbpp_prepare_describe_12: TASAdbpp_prepare_describe_12; dbpp_select: TASAdbpp_select; dbpp_open: TASAdbpp_open; dbpp_close: TASAdbpp_close; dbpp_fetch: TASAdbpp_fetch; dbpp_declare: TASAdbpp_declare; dbpp_dropstmt: TASAdbpp_dropstmt; dbpp_describe: TASAdbpp_describe; dbpp_delete: TASAdbpp_delete; dbpp_update: TASAdbpp_update; dbpp_execute_imm: TASAdbpp_execute_imm; dbpp_put_into: TASAdbpp_put_into; dbpp_put_array: TASAdbpp_put_array; dbpp_commit: TASAdbpp_commit; dbpp_rollback: TASAdbpp_rollback; dbpp_execute_into: TASAdbpp_execute_into; dbpp_get_data: TASAdbpp_get_data; dbpp_explain: TASAdbpp_explain; db_register_a_callback: TASAdb_register_a_callback; dbpp_setoption: TASAdbpp_setoption; dbpp_fetch_array: TASAdbpp_fetch_array; dbpp_resume: TASAdbpp_resume; db_cancel_request: TASAdb_cancel_request; db_change_char_charset: TASAdb_change_char_charset; db_change_nchar_charset: TASAdb_change_nchar_charset; end; implementation end. ================================================ FILE: lib/zeosdbo/src/plain/ZPlainASADriver.pas ================================================ {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZPlainASADriver; interface {$I ZPlain.inc} uses Classes, ZCompatibility, ZPlainDriver, ZPlainASAConstants; {***************** Plain API Constants definition ****************} type {** Represents a generic interface to ASA native API. } IZASAPlainDriver = interface (IZPlainDriver) ['{86AFDDD6-D401-4A30-B3BE-4AC5095E13F0}'] function sqlerror_message(sqlca: PZASASQLCA; Buffer: PAnsiChar; MaxSize: Integer): PAnsiChar; function db_init( sqlca: PZASASQLCA): Integer; function db_fini( sqlca: PZASASQLCA): Integer; function db_string_connect(sqlca: PZASASQLCA; Params: PAnsiChar): Integer; function db_string_disconnect(sqlca: PZASASQLCA; Params: PAnsiChar): LongWord; function db_find_engine(sqlca: PZASASQLCA; Params: PAnsiChar): Word; function db_start_engine(sqlca: PZASASQLCA; Params: PAnsiChar): LongWord; function db_stop_engine(sqlca: PZASASQLCA; Params: PAnsiChar): LongWord; function db_start_database(sqlca: PZASASQLCA; Params: PAnsiChar): LongWord; function db_stop_database(sqlca: PZASASQLCA; Params: PAnsiChar): LongWord; function db_alloc_sqlda( NumVar: LongWord): PASASQLDA; function db_fill_sqlda( Parameter: PASASQLDA): PASASQLDA; function db_fill_s_sqlda( Parameter: PASASQLDA; MaxLength: Integer): PASASQLDA; procedure db_free_sqlda( Parameter: PASASQLDA); procedure db_free_sqlda_noind( Parameter: PASASQLDA); procedure db_free_filled_sqlda( Parameter: PASASQLDA); procedure db_setconnect(sqlca: PZASASQLCA; ConnStr: PAnsiChar); procedure db_disconnect(sqlca: PZASASQLCA; ConnStr: PAnsiChar); procedure db_setoption( sqlca: PZASASQLCA; Temporary: LongInt; User: PAnsiChar; Option: PAnsiChar; Descriptor: PASASQLDA); procedure db_describe_cursor(sqlca: PZASASQLCA; CursorName: PAnsiChar; Descriptor: PASASQLDA; WhatToDesc: LongWord); procedure db_prepare_into(sqlca: PZASASQLCA; ProgName: PAnsiChar; StatementNum: PSmallInt; SqlStatement: PAnsiChar; Descriptor1: PASASQLDA; Descriptor2: PASASQLDA; WhatToDesc: LongWord); procedure db_prepare_describe(sqlca: PZASASQLCA; ProgName: PAnsiChar; StatementNum: PSmallInt; SqlStatement: PAnsiChar; Descriptor: PASASQLDA; WhatToDesc: LongWord; LongNames: Word); procedure db_declare(sqlca: PZASASQLCA; CursorName: PAnsiChar; StatementName: PAnsiChar; ProgName: PAnsiChar; StatementNum: PSmallInt; Options: Word); procedure db_describe(sqlca: PZASASQLCA; ProgName: PAnsiChar; StatementNum: PSmallInt; Descriptor: PASASQLDA; WhatToDesc: Word); procedure db_dropstmt(sqlca: PZASASQLCA; StatementName: PAnsiChar; ProgName: PAnsiChar; StatementNum: PSmallInt); procedure db_open(sqlca: PZASASQLCA; CursorName: PAnsiChar; ProgName: PAnsiChar; StatementNum: PSmallInt; Descriptor: PASASQLDA; BlockSize, IsolationLvl: SmallInt; CursorOptions: Word); procedure db_close( sqlca: PZASASQLCA; CursorName: PAnsiChar); procedure db_fetch(sqlca: PZASASQLCA; CursorName: PAnsiChar; Offset: Word; RelPositon: Integer; Descriptor: PASASQLDA; BlockSize: SmallInt; Options: Word); procedure db_fetch_array(sqlca: PZASASQLCA; CursorName: PAnsiChar; Offset: Word; RelPositon: Integer; Descriptor: PASASQLDA; BlockSize: SmallInt; Options, ArrayWidth: Word); procedure db_get_data(sqlca: PZASASQLCA; CursorName: PAnsiChar; ColumnNumber: Word; Offset: Integer; Descriptor: PASASQLDA); procedure db_delete(sqlca: PZASASQLCA; CursorName: PAnsiChar); procedure db_update(sqlca: PZASASQLCA; CursorName: PAnsiChar; Descriptor: PASASQLDA); procedure db_put_into(sqlca: PZASASQLCA; CursorName: PAnsiChar; Descriptor: PASASQLDA; ResultDescriptor: PASASQLDA); procedure db_put_array(sqlca: PZASASQLCA; CursorName: PAnsiChar; Descriptor: PASASQLDA; ResultDescriptor: PASASQLDA; Rows: Word); procedure db_select(sqlca: PZASASQLCA; ProgName: PAnsiChar; StatementNum: PSmallInt; SQLDescriptor, ResultDescriptor: PASASQLDA); procedure db_execute_into(sqlca: PZASASQLCA; Statement: PAnsiChar; ProgName: PAnsiChar; StatementNum: PSmallInt; Descriptor: PASASQLDA; ResultDescriptor: PASASQLDA); procedure db_execute_imm(sqlca: PZASASQLCA; Statement: PAnsiChar); procedure db_commit( sqlca: PZASASQLCA; TransLevel: LongWord); procedure db_rollback( sqlca: PZASASQLCA; TransLevel: LongWord); procedure db_explain(sqlca: PZASASQLCA; CursorName: PAnsiChar; Descriptor: PASASQLDA); procedure db_register_callback( sqlca: PZASASQLCA; CBIdx: ZASA_db_callback_index; Proc: TZASASQLCallback); procedure db_resume(sqlca: PZASASQLCA; CursorName: PAnsiChar); function db_cancel_request( sqlca: PZASASQLCA): Integer; function db_change_char_charset( sqlca: PZASASQLCA; const CharSet: PAnsiChar): Word; function db_change_nchar_charset( sqlca: PZASASQLCA; const CharSet: PAnsiChar): Word; end; {** Implements a driver for ASA 7.0-9.0} TZASABasePlainDriver = class (TZAbstractPlainDriver, IZPlainDriver, IZASAPlainDriver) private ASA_API: TASA_API; protected procedure LoadApi; override; function GetUnicodeCodePageName: String; override; public procedure LoadCodePages; override; constructor Create; function sqlerror_message(sqlca: PZASASQLCA; Buffer: PAnsiChar; MaxSize: Integer): PAnsiChar; function db_init( sqlca: PZASASQLCA): Integer; function db_fini( sqlca: PZASASQLCA): Integer; function db_string_connect(sqlca: PZASASQLCA; Params: PAnsiChar): Integer; function db_string_disconnect(sqlca: PZASASQLCA; Params: PAnsiChar): LongWord; function db_find_engine(sqlca: PZASASQLCA; Params: PAnsiChar): Word; function db_start_engine(sqlca: PZASASQLCA; Params: PAnsiChar): LongWord; function db_stop_engine(sqlca: PZASASQLCA; Params: PAnsiChar): LongWord; function db_start_database(sqlca: PZASASQLCA; Params: PAnsiChar): LongWord; function db_stop_database(sqlca: PZASASQLCA; Params: PAnsiChar): LongWord; function db_alloc_sqlda( NumVar: LongWord): PASASQLDA; function db_fill_sqlda( Parameter: PASASQLDA): PASASQLDA; function db_fill_s_sqlda( Parameter: PASASQLDA; MaxLength: Integer): PASASQLDA; procedure db_free_sqlda( Parameter: PASASQLDA); procedure db_free_sqlda_noind( Parameter: PASASQLDA); procedure db_free_filled_sqlda( Parameter: PASASQLDA); procedure db_setconnect(sqlca: PZASASQLCA; ConnStr: PAnsiChar); procedure db_disconnect(sqlca: PZASASQLCA; ConnStr: PAnsiChar); procedure db_setoption( sqlca: PZASASQLCA; Temporary: LongInt; User: PAnsiChar; Option: PAnsiChar; Descriptor: PASASQLDA); procedure db_describe_cursor(sqlca: PZASASQLCA; CursorName: PAnsiChar; Descriptor: PASASQLDA; WhatToDesc: LongWord); procedure db_prepare_into(sqlca: PZASASQLCA; ProgName: PAnsiChar; StatementNum: PSmallInt; SqlStatement: PAnsiChar; Descriptor1: PASASQLDA; Descriptor2: PASASQLDA; WhatToDesc: LongWord); procedure db_prepare_describe(sqlca: PZASASQLCA; ProgName: PAnsiChar; StatementNum: PSmallInt; SqlStatement: PAnsiChar; Descriptor: PASASQLDA; WhatToDesc: LongWord; LongNames: Word); procedure db_declare(sqlca: PZASASQLCA; CursorName: PAnsiChar; StatementName: PAnsiChar; ProgName: PAnsiChar; StatementNum: PSmallInt; Options: Word); procedure db_describe(sqlca: PZASASQLCA; ProgName: PAnsiChar; StatementNum: PSmallInt; Descriptor: PASASQLDA; WhatToDesc: Word); procedure db_dropstmt(sqlca: PZASASQLCA; StatementName: PAnsiChar; ProgName: PAnsiChar; StatementNum: PSmallInt); procedure db_open(sqlca: PZASASQLCA; CursorName: PAnsiChar; ProgName: PAnsiChar; StatementNum: PSmallInt; Descriptor: PASASQLDA; BlockSize, IsolationLvl: SmallInt; CursorOptions: Word); procedure db_close(sqlca: PZASASQLCA; CursorName: PAnsiChar); procedure db_fetch(sqlca: PZASASQLCA; CursorName: PAnsiChar; Offset: Word; RelPositon: Integer; Descriptor: PASASQLDA; BlockSize: SmallInt; Options: Word); procedure db_fetch_array(sqlca: PZASASQLCA; CursorName: PAnsiChar; Offset: Word; RelPositon: Integer; Descriptor: PASASQLDA; BlockSize: SmallInt; Options, ArrayWidth: Word); procedure db_get_data(sqlca: PZASASQLCA; CursorName: PAnsiChar; ColumnNumber: Word; Offset: Integer; Descriptor: PASASQLDA); procedure db_delete(sqlca: PZASASQLCA; CursorName: PAnsiChar); procedure db_update(sqlca: PZASASQLCA; CursorName: PAnsiChar; Descriptor: PASASQLDA); procedure db_put_into(sqlca: PZASASQLCA; CursorName: PAnsiChar; Descriptor: PASASQLDA; ResultDescriptor: PASASQLDA); procedure db_put_array(sqlca: PZASASQLCA; CursorName: PAnsiChar; Descriptor: PASASQLDA; ResultDescriptor: PASASQLDA; Rows: Word); procedure db_select(sqlca: PZASASQLCA; ProgName: PAnsiChar; StatementNum: PSmallInt; Descriptor, ResultDescriptor: PASASQLDA); procedure db_execute_into(sqlca: PZASASQLCA; Statement: PAnsiChar; ProgName: PAnsiChar; StatementNum: PSmallInt; Descriptor: PASASQLDA; ResultDescriptor: PASASQLDA); procedure db_execute_imm(sqlca: PZASASQLCA; Statement: PAnsiChar); procedure db_commit( sqlca: PZASASQLCA; TransLevel: LongWord); procedure db_rollback( sqlca: PZASASQLCA; TransLevel: LongWord); procedure db_explain(sqlca: PZASASQLCA; CursorName: PAnsiChar; Descriptor: PASASQLDA); procedure db_register_callback( sqlca: PZASASQLCA; CBIdx: ZASA_db_callback_index; Proc: TZASASQLCallback); procedure db_resume(sqlca: PZASASQLCA; CursorName: PAnsiChar); function db_cancel_request( sqlca: PZASASQLCA): Integer; function db_change_char_charset( sqlca: PZASASQLCA; const CharSet: PAnsiChar): Word; function db_change_nchar_charset( sqlca: PZASASQLCA; const CharSet: PAnsiChar): Word; end; TZASA7PlainDriver = class(TZASABasePlainDriver) protected function Clone: IZPlainDriver; override; public constructor Create; function GetProtocol: string; override; function GetDescription: string; override; end; TZASA8PlainDriver = class(TZASABasePlainDriver) protected function Clone: IZPlainDriver; override; public constructor Create; function GetProtocol: string; override; function GetDescription: string; override; end; {** Implements a driver for ASA 9.0 } TZASA9PlainDriver = class (TZASABasePlainDriver) protected function Clone: IZPlainDriver; override; public constructor Create; function GetProtocol: string; override; function GetDescription: string; override; end; {** Implements a driver for ASA 12.0 } TZASA12PlainDriver = class (TZASABasePlainDriver) protected function Clone: IZPlainDriver; override; public constructor Create; function GetProtocol: string; override; function GetDescription: string; override; end; implementation uses SysUtils, ZPlainLoader, ZEncoding; procedure TZASABasePlainDriver.LoadApi; begin with FLoader do begin @ASA_API.sqlerror_message := GetAddress('sqlerror_message'); @ASA_API.db_init := GetAddress('db_init'); @ASA_API.db_fini := GetAddress('db_fini'); @ASA_API.db_string_connect := GetAddress('db_string_connect'); @ASA_API.db_string_disconnect := GetAddress('db_string_disconnect'); @ASA_API.db_find_engine := GetAddress('db_find_engine'); @ASA_API.db_start_engine := GetAddress('db_start_engine'); @ASA_API.db_stop_engine := GetAddress('db_stop_engine'); @ASA_API.db_start_database := GetAddress('db_start_database'); @ASA_API.db_stop_database := GetAddress('db_stop_database'); @ASA_API.alloc_sqlda := GetAddress('alloc_sqlda'); @ASA_API.fill_sqlda := GetAddress('fill_sqlda'); @ASA_API.fill_s_sqlda := GetAddress('fill_s_sqlda'); @ASA_API.free_filled_sqlda := GetAddress('free_filled_sqlda'); @ASA_API.free_sqlda := GetAddress('free_sqlda'); @ASA_API.free_sqlda_noind := GetAddress('free_sqlda_noind'); @ASA_API.dbpp_setConnect := GetAddress('dbpp_setconnect'); @ASA_API.dbpp_disconnect := GetAddress('dbpp_disconnect'); @ASA_API.dbpp_prepare_into := GetAddress('dbpp_prepare_into'); @ASA_API.dbpp_describe_cursor := GetAddress('dbpp_describe_cursor'); @ASA_API.dbpp_prepare_describe := GetAddress('dbpp_prepare_describe'); @ASA_API.dbpp_prepare_describe_12 := GetAddress('dbpp_prepare_describe_12'); @ASA_API.dbpp_select := GetAddress('dbpp_select'); @ASA_API.dbpp_open := GetAddress('dbpp_open'); @ASA_API.dbpp_close := GetAddress('dbpp_close'); @ASA_API.dbpp_fetch := GetAddress('dbpp_fetch'); @ASA_API.dbpp_declare := GetAddress('dbpp_declare'); @ASA_API.dbpp_dropstmt := GetAddress('dbpp_dropstmt'); @ASA_API.dbpp_describe := GetAddress('dbpp_describe'); @ASA_API.dbpp_delete := GetAddress('dbpp_delete'); @ASA_API.dbpp_update := GetAddress('dbpp_update'); @ASA_API.dbpp_put_into := GetAddress('dbpp_put_into'); @ASA_API.dbpp_put_array := GetAddress('dbpp_put_array'); @ASA_API.dbpp_execute_imm := GetAddress('dbpp_execute_imm'); @ASA_API.dbpp_commit := GetAddress('dbpp_commit'); @ASA_API.dbpp_rollback := GetAddress('dbpp_rollback'); @ASA_API.dbpp_execute_into := GetAddress('dbpp_execute_into'); @ASA_API.dbpp_get_data := GetAddress('dbpp_get_data'); @ASA_API.dbpp_explain := GetAddress('dbpp_explain'); @ASA_API.dbpp_setoption := GetAddress('dbpp_setoption'); @ASA_API.dbpp_fetch_array := GetAddress('dbpp_fetch_array'); @ASA_API.db_register_a_callback := GetAddress('db_register_a_callback'); @ASA_API.dbpp_resume := GetAddress('dbpp_resume'); @ASA_API.db_cancel_request := GetAddress('db_cancel_request'); @ASA_API.db_change_char_charset := GetAddress('db_change_char_charset'); @ASA_API.db_change_nchar_charset:= GetAddress('db_change_nchar_charset'); end; end; function TZASABasePlainDriver.GetUnicodeCodePageName: String; begin Result := 'UTF-8'; end; procedure TZASABasePlainDriver.LoadCodePages; begin { MultiByte } AddCodePage('TIS-620', 1, ceAnsi, 874); {Windows Thailndisch, ISO8859-11, binre Sortierung} AddCodePage('Windows-31J', 2, ceAnsi, 932); {Japanese Shift-JIS mit Microsoft-Erweiterungen} AddCodePage('GBK', 3, ceAnsi, 936); {GB2312-80 Simplified Chinese} AddCodePage('IBM949', 4, ceAnsi, 949); {Korean KS C 5601-1987-Codierung, Wansung} AddCodePage('BIG5', 5, ceAnsi, 950); {Traditionelles Chinesisch, Big 5-Kodierung mit HKSCS} AddCodePage('EUC_CHINA', 6, ceAnsi, zCP_GB2312); {GB2312-80 Simplified Chinese} AddCodePage('UTF-8', 7, ceUTF8, zCP_UTF8, '', 3); {UTF-8, 8-Bit-Mehrbyte-Zeichensatz fr Unicode, binre Reihenfolge} { SingleByte } AddCodePage('Windows-1250', 8, ceAnsi, 1250); {Windows Latin 2, Polnisch} AddCodePage('Windows-1251', 9, ceAnsi, 1251); {Windows Kyrillisch} AddCodePage('Windows-1252', 10, ceAnsi, 1252); { Windows Latin 1, Western} AddCodePage('Windows-1253', 11, ceAnsi, 1253); {Windows Griechisch, ISO8859-7 mit Erweiterungen} AddCodePage('Windows-1254', 12, ceAnsi, 1254); {Windows Trkisch, ISO8859-9 mit Erweiterungen} AddCodePage('Windows-1255', 13, ceAnsi, 1255); {Windows Hebrisch, ISO8859-8 mit Erweiterungen} AddCodePage('Windows-1256', 14, ceAnsi, 1256); {Windows Arabisch, ISO8859-6 mit Erweiterungen} AddCodePage('Windows-1257', 15, ceAnsi, 1257); {Windows Baltische Staaten, Litauisch} AddCodePage('Windows-1258', 16, ceAnsi, 1258); {Windows } {*nix} AddCodePage('ISO_8859-6:1987', 17, ceAnsi, 1256); {Arabisch, ISO8859-6 mit Erweiterungen} AddCodePage('ISO_8859-2:1987', 18, ceAnsi, 1251); {Zentral- und Osteuropisch} //ISO-8859-15 //ISO9LATIN1 //ISO_8859-7:1987 //Griechisch //ISO_8859-8:1988 //Hebrisch //ISO-8859-15 //Italienisch //EUC-JP //Japanisch //EUC-KR //Koreanisch //ISO_8859-5:1988 //Russisch AddCodePage('GB2312', 19, ceAnsi, zCP_GB2312); {GB2312-80 Simplified Chinese} //EUC-TW //Traditionelles Chinesisch - Taiwan AddCodePage('Big5-HKSCS', 20, ceAnsi, 950); {Traditionelles Chinesisch, Big 5-Kodierung mit HKSCS} AddCodePage('ISO_8859-9:1989', 21, ceAnsi, 920); //Trkisch end; constructor TZASABasePlainDriver.Create; begin inherited create; FLoader := TZNativeLibraryLoader.Create([]); LoadCodePages; end; function TZASABasePlainDriver.sqlerror_message(sqlca: PZASASQLCA; Buffer: PAnsiChar; MaxSize: Integer): PAnsiChar; begin Result := ASA_API.sqlerror_message( sqlca, Buffer, MaxSize); end; function TZASABasePlainDriver.db_init( sqlca: PZASASQLCA): Integer; begin Result := ASA_API.db_init( sqlca); end; function TZASABasePlainDriver.db_fini( sqlca: PZASASQLCA): Integer; begin Result := ASA_API.db_fini( sqlca); end; function TZASABasePlainDriver.db_string_connect(sqlca: PZASASQLCA; Params: PAnsiChar): Integer; begin Result := ASA_API.db_string_connect( sqlca, Params); end; function TZASABasePlainDriver.db_string_disconnect( sqlca: PZASASQLCA; Params: PAnsiChar): LongWord; begin Result := ASA_API.db_string_disconnect( sqlca, Params) end; function TZASABasePlainDriver.db_find_engine(sqlca: PZASASQLCA; Params: PAnsiChar): Word; begin Result := ASA_API.db_find_engine( sqlca, Params); end; function TZASABasePlainDriver.db_start_engine(sqlca: PZASASQLCA; Params: PAnsiChar): LongWord; begin Result := ASA_API.db_start_engine( sqlca, Params); end; function TZASABasePlainDriver.db_stop_engine(sqlca: PZASASQLCA; Params: PAnsiChar): LongWord; begin Result := ASA_API.db_stop_engine( sqlca, Params); end; function TZASABasePlainDriver.db_start_database(sqlca: PZASASQLCA; Params: PAnsiChar): LongWord; begin Result := ASA_API.db_start_database( sqlca, Params); end; function TZASABasePlainDriver.db_stop_database(sqlca: PZASASQLCA; Params: PAnsiChar): LongWord; begin Result := ASA_API.db_stop_database( sqlca, Params); end; function TZASABasePlainDriver.db_alloc_sqlda( NumVar: LongWord): PASASQLDA; begin Result := ASA_API.alloc_sqlda( NumVar); end; function TZASABasePlainDriver.db_fill_sqlda( Parameter: PASASQLDA): PASASQLDA; begin Result := ASA_API.fill_sqlda( Parameter); end; function TZASABasePlainDriver.db_fill_s_sqlda( Parameter: PASASQLDA; MaxLength: Integer): PASASQLDA; begin Result := ASA_API.fill_s_sqlda( Parameter, MaxLength); end; procedure TZASABasePlainDriver.db_free_sqlda( Parameter: PASASQLDA); begin ASA_API.free_sqlda( Parameter); end; procedure TZASABasePlainDriver.db_free_sqlda_noind( Parameter: PASASQLDA); begin ASA_API.free_sqlda_noind( Parameter); end; procedure TZASABasePlainDriver.db_free_filled_sqlda( Parameter: PASASQLDA); begin ASA_API.free_filled_sqlda( Parameter); end; procedure TZASABasePlainDriver.db_setconnect(sqlca: PZASASQLCA; ConnStr: PAnsiChar); begin ASA_API.dbpp_setconnect( sqlca, ConnStr); end; procedure TZASABasePlainDriver.db_disconnect(sqlca: PZASASQLCA; ConnStr: PAnsiChar); begin ASA_API.dbpp_disconnect( sqlca, ConnStr); end; procedure TZASABasePlainDriver.db_setoption( sqlca: PZASASQLCA; Temporary: Integer; User: PAnsiChar; Option: PAnsiChar; Descriptor: PASASQLDA); begin ASA_API.dbpp_setoption( sqlca, Temporary, User, Option, Descriptor); end; procedure TZASABasePlainDriver.db_describe_cursor( sqlca: PZASASQLCA; CursorName: PAnsiChar; Descriptor: PASASQLDA; WhatToDesc: LongWord); begin ASA_API.dbpp_describe_cursor( sqlca, CursorName, Descriptor, WhatToDesc); end; procedure TZASABasePlainDriver.db_prepare_into( sqlca: PZASASQLCA; ProgName: PAnsiChar; StatementNum: PSmallInt; SqlStatement: PAnsiChar; Descriptor1: PASASQLDA; Descriptor2: PASASQLDA; WhatToDesc: LongWord); begin ASA_API.dbpp_prepare_into( sqlca, nil, ProgName, StatementNum, SqlStatement, Descriptor1, Descriptor2, WhatToDesc); end; procedure TZASABasePlainDriver.db_prepare_describe( sqlca: PZASASQLCA; ProgName: PAnsiChar; StatementNum: PSmallInt; SqlStatement: PAnsiChar; Descriptor: PASASQLDA; WhatToDesc: LongWord; LongNames: Word); var U1: LongWord; begin U1 := 0; if Assigned(ASA_API.dbpp_prepare_describe) then ASA_API.dbpp_prepare_describe( sqlca, nil, ProgName, StatementNum, SqlStatement, nil, Descriptor, WhatToDesc, LongNames) else if Assigned(ASA_API.dbpp_prepare_describe_12) then ASA_API.dbpp_prepare_describe_12(sqlca, nil, ProgName, StatementNum, SqlStatement, nil, Descriptor, WhatToDesc, LongNames, U1); end; procedure TZASABasePlainDriver.db_declare(sqlca: PZASASQLCA; CursorName: PAnsiChar; StatementName: PAnsiChar; ProgName: PAnsiChar; StatementNum: PSmallInt; Options: Word); begin ASA_API.dbpp_declare( sqlca, CursorName, StatementName, ProgName, StatementNum, Options); end; procedure TZASABasePlainDriver.db_describe(sqlca: PZASASQLCA; ProgName: PAnsiChar; StatementNum: PSmallInt; Descriptor: PASASQLDA; WhatToDesc: Word); begin ASA_API.dbpp_describe( sqlca, nil, ProgName, StatementNum, Descriptor, WhatToDesc); end; procedure TZASABasePlainDriver.db_dropstmt( sqlca: PZASASQLCA; StatementName: PAnsiChar; ProgName: PAnsiChar; StatementNum: PSmallInt); begin ASA_API.dbpp_dropstmt( sqlca, StatementName, ProgName, StatementNum); end; procedure TZASABasePlainDriver.db_open(sqlca: PZASASQLCA; CursorName: PAnsiChar; ProgName: PAnsiChar; StatementNum: PSmallInt; Descriptor: PASASQLDA; BlockSize, IsolationLvl: SmallInt; CursorOptions: Word); begin ASA_API.dbpp_open( sqlca, CursorName, nil, ProgName, StatementNum, Descriptor, BlockSize, IsolationLvl, CursorOptions); end; procedure TZASABasePlainDriver.db_close(sqlca: PZASASQLCA; CursorName: PAnsiChar); begin ASA_API.dbpp_close( sqlca, CursorName); end; procedure TZASABasePlainDriver.db_fetch(sqlca: PZASASQLCA; CursorName: PAnsiChar; Offset: Word; RelPositon: Integer; Descriptor: PASASQLDA; BlockSize: SmallInt; Options: Word); begin ASA_API.dbpp_fetch( sqlca, CursorName, Offset, RelPositon, Descriptor, BlockSize, Options); end; procedure TZASABasePlainDriver.db_fetch_array( sqlca: PZASASQLCA; CursorName: PAnsiChar; Offset: Word; RelPositon: Integer; Descriptor: PASASQLDA; BlockSize: SmallInt; Options, ArrayWidth: Word); begin ASA_API.dbpp_fetch_array( sqlca, CursorName, Offset, RelPositon, Descriptor, BlockSize, Options, ArrayWidth); end; procedure TZASABasePlainDriver.db_get_data(sqlca: PZASASQLCA; CursorName: PAnsiChar; ColumnNumber: Word; Offset: Integer; Descriptor: PASASQLDA); begin ASA_API.dbpp_get_data( sqlca, CursorName, ColumnNumber, Offset, Descriptor, 0); end; procedure TZASABasePlainDriver.db_delete(sqlca: PZASASQLCA; CursorName: PAnsiChar); begin ASA_API.dbpp_delete( sqlca, CursorName, nil, nil); end; procedure TZASABasePlainDriver.db_update(sqlca: PZASASQLCA; CursorName: PAnsiChar; Descriptor: PASASQLDA); begin ASA_API.dbpp_update( sqlca, CursorName, Descriptor); end; procedure TZASABasePlainDriver.db_put_into(sqlca: PZASASQLCA; CursorName: PAnsiChar; Descriptor: PASASQLDA; ResultDescriptor: PASASQLDA); begin ASA_API.dbpp_put_into( sqlca, CursorName, Descriptor, ResultDescriptor); end; procedure TZASABasePlainDriver.db_put_array(sqlca: PZASASQLCA; CursorName: PAnsiChar; Descriptor: PASASQLDA; ResultDescriptor: PASASQLDA; Rows: Word); begin ASA_API.dbpp_put_array( sqlca, CursorName, Descriptor, ResultDescriptor, Rows); end; procedure TZASABasePlainDriver.db_select(sqlca: PZASASQLCA; ProgName: PAnsiChar; StatementNum: PSmallInt; Descriptor, ResultDescriptor: PASASQLDA); begin ASA_API.dbpp_select( sqlca, nil, ProgName, StatementNum, Descriptor, ResultDescriptor); end; procedure TZASABasePlainDriver.db_execute_into( sqlca: PZASASQLCA; Statement: PAnsiChar; ProgName: PAnsiChar; StatementNum: PSmallInt; Descriptor: PASASQLDA; ResultDescriptor: PASASQLDA); begin ASA_API.dbpp_execute_into( sqlca, Statement, ProgName, StatementNum, Descriptor, ResultDescriptor); end; procedure TZASABasePlainDriver.db_execute_imm( sqlca: PZASASQLCA; Statement: PAnsiChar); begin ASA_API.dbpp_execute_imm( sqlca, Statement, 2); end; procedure TZASABasePlainDriver.db_commit( sqlca: PZASASQLCA; TransLevel: LongWord); begin ASA_API.dbpp_commit( sqlca, TransLevel); end; procedure TZASABasePlainDriver.db_rollback( sqlca: PZASASQLCA; TransLevel: LongWord); begin ASA_API.dbpp_rollback( sqlca, TransLevel); end; procedure TZASABasePlainDriver.db_explain(sqlca: PZASASQLCA; CursorName: PAnsiChar; Descriptor: PASASQLDA); begin ASA_API.dbpp_explain( sqlca, CursorName, 0, Descriptor); end; procedure TZASABasePlainDriver.db_register_callback( sqlca: PZASASQLCA; CBIdx: ZASA_db_callback_index; Proc: TZASASQLCallback); begin ASA_API.db_register_a_callback( sqlca, Integer( CBIdx), Proc); end; procedure TZASABasePlainDriver.db_resume(sqlca: PZASASQLCA; CursorName: PAnsiChar); begin ASA_API.dbpp_resume( sqlca, CursorName); end; function TZASABasePlainDriver.db_cancel_request( sqlca: PZASASQLCA): Integer; begin Result := ASA_API.db_cancel_request( sqlca); end; function TZASABasePlainDriver.db_change_char_charset( sqlca: PZASASQLCA; const CharSet: PAnsiChar): Word; begin Result := ASA_API.db_change_char_charset(sqlca, CharSet); end; function TZASABasePlainDriver.db_change_nchar_charset( sqlca: PZASASQLCA; const CharSet: PAnsiChar): Word; begin Result := ASA_API.db_change_nchar_charset(sqlca, CharSet); end; {TZASA7PlainDriver} function TZASA7PlainDriver.Clone: IZPlainDriver; begin Result := TZASA7PlainDriver.Create; end; constructor TZASA7PlainDriver.Create; begin inherited Create; FLoader.AddLocation({$IFNDEF LINUX}ASA7_WINDOWS_DLL_LOCATION{$ELSE}ASA7_LINUX_DLL_LOCATION{$ENDIF}); end; function TZASA7PlainDriver.GetProtocol: string; begin Result := 'ASA7'; end; function TZASA7PlainDriver.GetDescription: string; begin Result := 'Native Plain Driver for ASA 7.0 DBLib'; end; {TZASA8PlainDriver} constructor TZASA8PlainDriver.Create; begin inherited Create; FLoader.AddLocation({$IFNDEF LINUX}ASA8_WINDOWS_DLL_LOCATION{$ELSE}ASA8_LINUX_DLL_LOCATION{$ENDIF}); end; function TZASA8PlainDriver.Clone: IZPlainDriver; begin Result := TZASA8PlainDriver.Create; end; function TZASA8PlainDriver.GetProtocol: string; begin Result := 'ASA8'; end; function TZASA8PlainDriver.GetDescription: string; begin Result := 'Native Plain Driver for ASA 8.0 DBLib'; end; {TZASA9PlainDriver} constructor TZASA9PlainDriver.Create; begin inherited Create; FLoader.AddLocation({$IFNDEF LINUX}ASA9_WINDOWS_DLL_LOCATION{$ELSE}ASA9_LINUX_DLL_LOCATION{$ENDIF}); end; function TZASA9PlainDriver.Clone: IZPlainDriver; begin Result := TZASA9PlainDriver.Create; end; function TZASA9PlainDriver.GetProtocol: string; begin Result := 'ASA9'; end; function TZASA9PlainDriver.GetDescription: string; begin Result := 'Native Plain Driver for ASA 9.0 DBLib'; end; {TZASA12PlainDriver} constructor TZASA12PlainDriver.Create; begin inherited Create; FLoader.AddLocation({$IFNDEF LINUX}ASA12_WINDOWS_DLL_LOCATION{$ELSE}ASA12_LINUX_DLL_LOCATION{$ENDIF}); end; function TZASA12PlainDriver.Clone: IZPlainDriver; begin Result := TZASA12PlainDriver.Create; end; function TZASA12PlainDriver.GetProtocol: string; begin Result := 'ASA12'; end; function TZASA12PlainDriver.GetDescription: string; begin Result := 'Native Plain Driver for ASA 9.0 DBLib'; end; end. ================================================ FILE: lib/zeosdbo/src/plain/ZPlainAdo.pas ================================================ {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZPlainAdo; // ************************************************************************ // // WARNING // ------- // The types declared in this file were generated from data read from a // Type Library. If this type library is explicitly or indirectly (via // another type library referring to this type library) re-imported, or the // 'Refresh' command of the Type Library Editor activated while editing the // Type Library, the contents of this file will be regenerated and all // manual modifications will be lost. // ************************************************************************ // // PASTLWTR : $Revision: 1.9 $ // File generated on 2003.07.12. 17.11.28 from Type Library described below. // ************************************************************************ // // Type Lib: C:\Program Files\Common Files\System\ado\msado15.dll (1) // LIBID: {EF53050B-882E-4776-B643-EDA472E8E3F2} // LCID: 0 // Helpfile: C:\WINDOWS\HELP\ado270.chm // DepndLst: // (1) v2.0 stdole, (C:\WINDOWS\System32\stdole2.tlb) // (2) v4.0 StdVCL, (C:\WINDOWS\System32\stdvcl40.dll) // Errors: // Hint: TypeInfo 'Property' changed to 'Property_' // Hint: TypeInfo 'Record' changed to 'Record_' // Hint: Parameter 'Object' of _DynaCollection.Append changed to 'Object_' // Hint: Member 'Type' of 'Property' changed to 'Type_' // Hint: Parameter 'Type' of Command15.CreateParameter changed to 'Type_' // Hint: Parameter 'Type' of Fields20._Append changed to 'Type_' // Hint: Parameter 'Type' of Fields.Append changed to 'Type_' // Hint: Member 'Type' of 'Field20' changed to 'Type_' // Hint: Member 'Type' of '_Parameter' changed to 'Type_' // Hint: Member 'Type' of '_Stream' changed to 'Type_' // Hint: Member 'Type' of 'Field15' changed to 'Type_' // ************************************************************************ // {$TYPEDADDRESS OFF} // Unit must be compiled without type-checked pointers. {$WRITEABLECONST ON} //{$HPPEMIT '#undef EOF'} interface {$I ZPlain.inc} uses Windows, Classes, ActiveX; // *********************************************************************// // GUIDS declared in the TypeLibrary. Following prefixes are used: // Type Libraries : LIBID_xxxx // CoClasses : CLASS_xxxx // DISPInterfaces : DIID_xxxx // Non-DISP interfaces: IID_xxxx // *********************************************************************// const // TypeLibrary Major and minor versions ADODBMajorVersion = 2; ADODBMinorVersion = 7; LIBID_ADODB: TGUID = '{EF53050B-882E-4776-B643-EDA472E8E3F2}'; IID__Collection: TGUID = '{00000512-0000-0010-8000-00AA006D2EA4}'; IID__DynaCollection: TGUID = '{00000513-0000-0010-8000-00AA006D2EA4}'; IID__ADO: TGUID = '{00000534-0000-0010-8000-00AA006D2EA4}'; IID_Properties: TGUID = '{00000504-0000-0010-8000-00AA006D2EA4}'; IID_Property_: TGUID = '{00000503-0000-0010-8000-00AA006D2EA4}'; IID_Error: TGUID = '{00000500-0000-0010-8000-00AA006D2EA4}'; IID_Errors: TGUID = '{00000501-0000-0010-8000-00AA006D2EA4}'; IID_Command15: TGUID = '{00000508-0000-0010-8000-00AA006D2EA4}'; IID_Connection15: TGUID = '{00000515-0000-0010-8000-00AA006D2EA4}'; IID__Connection: TGUID = '{00000550-0000-0010-8000-00AA006D2EA4}'; IID_Recordset15: TGUID = '{0000050E-0000-0010-8000-00AA006D2EA4}'; IID_Recordset20: TGUID = '{0000054F-0000-0010-8000-00AA006D2EA4}'; IID_Recordset21: TGUID = '{00000555-0000-0010-8000-00AA006D2EA4}'; IID__Recordset: TGUID = '{00000556-0000-0010-8000-00AA006D2EA4}'; IID_Fields15: TGUID = '{00000506-0000-0010-8000-00AA006D2EA4}'; IID_Fields20: TGUID = '{0000054D-0000-0010-8000-00AA006D2EA4}'; IID_Fields: TGUID = '{00000564-0000-0010-8000-00AA006D2EA4}'; IID_Field20: TGUID = '{0000054C-0000-0010-8000-00AA006D2EA4}'; IID_Field: TGUID = '{00000569-0000-0010-8000-00AA006D2EA4}'; IID__Parameter: TGUID = '{0000050C-0000-0010-8000-00AA006D2EA4}'; IID_Parameters: TGUID = '{0000050D-0000-0010-8000-00AA006D2EA4}'; IID_Command25: TGUID = '{0000054E-0000-0010-8000-00AA006D2EA4}'; IID__Command: TGUID = '{B08400BD-F9D1-4D02-B856-71D5DBA123E9}'; IID_ConnectionEventsVt: TGUID = '{00000402-0000-0010-8000-00AA006D2EA4}'; IID_RecordsetEventsVt: TGUID = '{00000403-0000-0010-8000-00AA006D2EA4}'; DIID_ConnectionEvents: TGUID = '{00000400-0000-0010-8000-00AA006D2EA4}'; DIID_RecordsetEvents: TGUID = '{00000266-0000-0010-8000-00AA006D2EA4}'; IID_ADOConnectionConstruction15: TGUID = '{00000516-0000-0010-8000-00AA006D2EA4}'; IID_ADOConnectionConstruction: TGUID = '{00000551-0000-0010-8000-00AA006D2EA4}'; CLASS_Connection: TGUID = '{00000514-0000-0010-8000-00AA006D2EA4}'; IID__Record: TGUID = '{00000562-0000-0010-8000-00AA006D2EA4}'; CLASS_Record_: TGUID = '{00000560-0000-0010-8000-00AA006D2EA4}'; IID__Stream: TGUID = '{00000565-0000-0010-8000-00AA006D2EA4}'; CLASS_Stream: TGUID = '{00000566-0000-0010-8000-00AA006D2EA4}'; IID_ADORecordConstruction: TGUID = '{00000567-0000-0010-8000-00AA006D2EA4}'; IID_ADOStreamConstruction: TGUID = '{00000568-0000-0010-8000-00AA006D2EA4}'; IID_ADOCommandConstruction: TGUID = '{00000517-0000-0010-8000-00AA006D2EA4}'; CLASS_Command: TGUID = '{00000507-0000-0010-8000-00AA006D2EA4}'; CLASS_Recordset: TGUID = '{00000535-0000-0010-8000-00AA006D2EA4}'; IID_ADORecordsetConstruction: TGUID = '{00000283-0000-0010-8000-00AA006D2EA4}'; IID_Field15: TGUID = '{00000505-0000-0010-8000-00AA006D2EA4}'; CLASS_Parameter: TGUID = '{0000050B-0000-0010-8000-00AA006D2EA4}'; // *********************************************************************// // Declaration of Enumerations defined in Type Library // *********************************************************************// // Constants for enum CursorTypeEnum type CursorTypeEnum = TOleEnum; const adOpenUnspecified = $FFFFFFFF; adOpenForwardOnly = $00000000; adOpenKeyset = $00000001; adOpenDynamic = $00000002; adOpenStatic = $00000003; // Constants for enum CursorOptionEnum type CursorOptionEnum = TOleEnum; const adHoldRecords = $00000100; adMovePrevious = $00000200; adAddNew = $01000400; adDelete = $01000800; adUpdate = $01008000; adBookmark = $00002000; adApproxPosition = $00004000; adUpdateBatch = $00010000; adResync = $00020000; adNotify = $00040000; adFind = $00080000; adSeek = $00400000; adIndex = $00800000; // Constants for enum LockTypeEnum type LockTypeEnum = TOleEnum; const adLockUnspecified = $FFFFFFFF; adLockReadOnly = $00000001; adLockPessimistic = $00000002; adLockOptimistic = $00000003; adLockBatchOptimistic = $00000004; // Constants for enum ExecuteOptionEnum type ExecuteOptionEnum = TOleEnum; const adOptionUnspecified = $FFFFFFFF; adAsyncExecute = $00000010; adAsyncFetch = $00000020; adAsyncFetchNonBlocking = $00000040; adExecuteNoRecords = $00000080; adExecuteStream = $00000400; adExecuteRecord = $00000800; // Constants for enum ConnectOptionEnum type ConnectOptionEnum = TOleEnum; const adConnectUnspecified = $FFFFFFFF; adAsyncConnect = $00000010; // Constants for enum ObjectStateEnum type ObjectStateEnum = TOleEnum; const adStateClosed = $00000000; adStateOpen = $00000001; adStateConnecting = $00000002; adStateExecuting = $00000004; adStateFetching = $00000008; // Constants for enum CursorLocationEnum type CursorLocationEnum = TOleEnum; const adUseNone = $00000001; adUseServer = $00000002; adUseClient = $00000003; adUseClientBatch = $00000003; // Constants for enum DataTypeEnum type DataTypeEnum = TOleEnum; const adEmpty = $00000000; adTinyInt = $00000010; adSmallInt = $00000002; adInteger = $00000003; adBigInt = $00000014; adUnsignedTinyInt = $00000011; adUnsignedSmallInt = $00000012; adUnsignedInt = $00000013; adUnsignedBigInt = $00000015; adSingle = $00000004; adDouble = $00000005; adCurrency = $00000006; adDecimal = $0000000E; adNumeric = $00000083; adBoolean = $0000000B; adError = $0000000A; adUserDefined = $00000084; adVariant = $0000000C; adIDispatch = $00000009; adIUnknown = $0000000D; adGUID = $00000048; adDate = $00000007; adDBDate = $00000085; adDBTime = $00000086; adDBTimeStamp = $00000087; adBSTR = $00000008; adChar = $00000081; adVarChar = $000000C8; adLongVarChar = $000000C9; adWChar = $00000082; adVarWChar = $000000CA; adLongVarWChar = $000000CB; adBinary = $00000080; adVarBinary = $000000CC; adLongVarBinary = $000000CD; adChapter = $00000088; adFileTime = $00000040; adPropVariant = $0000008A; adVarNumeric = $0000008B; adArray = $00002000; // Constants for enum FieldAttributeEnum type FieldAttributeEnum = TOleEnum; const adFldUnspecified = $FFFFFFFF; adFldMayDefer = $00000002; adFldUpdatable = $00000004; adFldUnknownUpdatable = $00000008; adFldFixed = $00000010; adFldIsNullable = $00000020; adFldMayBeNull = $00000040; adFldLong = $00000080; adFldRowID = $00000100; adFldRowVersion = $00000200; adFldCacheDeferred = $00001000; adFldIsChapter = $00002000; adFldNegativeScale = $00004000; adFldKeyColumn = $00008000; adFldIsRowURL = $00010000; adFldIsDefaultStream = $00020000; adFldIsCollection = $00040000; // Constants for enum EditModeEnum type EditModeEnum = TOleEnum; const adEditNone = $00000000; adEditInProgress = $00000001; adEditAdd = $00000002; adEditDelete = $00000004; // Constants for enum RecordStatusEnum type RecordStatusEnum = TOleEnum; const adRecOK = $00000000; adRecNew = $00000001; adRecModified = $00000002; adRecDeleted = $00000004; adRecUnmodified = $00000008; adRecInvalid = $00000010; adRecMultipleChanges = $00000040; adRecPendingChanges = $00000080; adRecCanceled = $00000100; adRecCantRelease = $00000400; adRecConcurrencyViolation = $00000800; adRecIntegrityViolation = $00001000; adRecMaxChangesExceeded = $00002000; adRecObjectOpen = $00004000; adRecOutOfMemory = $00008000; adRecPermissionDenied = $00010000; adRecSchemaViolation = $00020000; adRecDBDeleted = $00040000; // Constants for enum GetRowsOptionEnum type GetRowsOptionEnum = TOleEnum; const adGetRowsRest = $FFFFFFFF; // Constants for enum PositionEnum type PositionEnum = TOleEnum; const adPosUnknown = $FFFFFFFF; adPosBOF = $FFFFFFFE; adPosEOF = $FFFFFFFD; // Constants for enum BookmarkEnum type BookmarkEnum = TOleEnum; const adBookmarkCurrent = $00000000; adBookmarkFirst = $00000001; adBookmarkLast = $00000002; // Constants for enum MarshalOptionsEnum type MarshalOptionsEnum = TOleEnum; const adMarshalAll = $00000000; adMarshalModifiedOnly = $00000001; // Constants for enum AffectEnum type AffectEnum = TOleEnum; const adAffectCurrent = $00000001; adAffectGroup = $00000002; adAffectAll = $00000003; adAffectAllChapters = $00000004; // Constants for enum ResyncEnum type ResyncEnum = TOleEnum; const adResyncUnderlyingValues = $00000001; adResyncAllValues = $00000002; // Constants for enum CompareEnum type CompareEnum = TOleEnum; const adCompareLessThan = $00000000; adCompareEqual = $00000001; adCompareGreaterThan = $00000002; adCompareNotEqual = $00000003; adCompareNotComparable = $00000004; // Constants for enum FilterGroupEnum type FilterGroupEnum = TOleEnum; const adFilterNone = $00000000; adFilterPendingRecords = $00000001; adFilterAffectedRecords = $00000002; adFilterFetchedRecords = $00000003; adFilterPredicate = $00000004; adFilterConflictingRecords = $00000005; // Constants for enum SearchDirectionEnum type SearchDirectionEnum = TOleEnum; const adSearchForward = $00000001; adSearchBackward = $FFFFFFFF; // Constants for enum PersistFormatEnum type PersistFormatEnum = TOleEnum; const adPersistADTG = $00000000; adPersistXML = $00000001; // Constants for enum StringFormatEnum type StringFormatEnum = TOleEnum; const adClipString = $00000002; // Constants for enum ConnectPromptEnum type ConnectPromptEnum = TOleEnum; const adPromptAlways = $00000001; adPromptComplete = $00000002; adPromptCompleteRequired = $00000003; adPromptNever = $00000004; // Constants for enum ConnectModeEnum type ConnectModeEnum = TOleEnum; const adModeUnknown = $00000000; adModeRead = $00000001; adModeWrite = $00000002; adModeReadWrite = $00000003; adModeShareDenyRead = $00000004; adModeShareDenyWrite = $00000008; adModeShareExclusive = $0000000C; adModeShareDenyNone = $00000010; adModeRecursive = $00400000; // Constants for enum RecordCreateOptionsEnum type RecordCreateOptionsEnum = TOleEnum; const adCreateCollection = $00002000; adCreateStructDoc = $80000000; adCreateNonCollection = $00000000; adOpenIfExists = $02000000; adCreateOverwrite = $04000000; adFailIfNotExists = $FFFFFFFF; // Constants for enum RecordOpenOptionsEnum type RecordOpenOptionsEnum = TOleEnum; const adOpenRecordUnspecified = $FFFFFFFF; adOpenSource = $00800000; adOpenOutput = $00800000; adOpenAsync = $00001000; adDelayFetchStream = $00004000; adDelayFetchFields = $00008000; adOpenExecuteCommand = $00010000; // Constants for enum IsolationLevelEnum type IsolationLevelEnum = TOleEnum; const adXactUnspecified = $FFFFFFFF; adXactChaos = $00000010; adXactReadUncommitted = $00000100; adXactBrowse = $00000100; adXactCursorStability = $00001000; adXactReadCommitted = $00001000; adXactRepeatableRead = $00010000; adXactSerializable = $00100000; adXactIsolated = $00100000; // Constants for enum XactAttributeEnum type XactAttributeEnum = TOleEnum; const adXactCommitRetaining = $00020000; adXactAbortRetaining = $00040000; adXactAsyncPhaseOne = $00080000; adXactSyncPhaseOne = $00100000; // Constants for enum PropertyAttributesEnum type PropertyAttributesEnum = TOleEnum; const adPropNotSupported = $00000000; adPropRequired = $00000001; adPropOptional = $00000002; adPropRead = $00000200; adPropWrite = $00000400; // Constants for enum ErrorValueEnum type ErrorValueEnum = TOleEnum; const adErrProviderFailed = $00000BB8; adErrInvalidArgument = $00000BB9; adErrOpeningFile = $00000BBA; adErrReadFile = $00000BBB; adErrWriteFile = $00000BBC; adErrNoCurrentRecord = $00000BCD; adErrIllegalOperation = $00000C93; adErrCantChangeProvider = $00000C94; adErrInTransaction = $00000CAE; adErrFeatureNotAvailable = $00000CB3; adErrItemNotFound = $00000CC1; adErrObjectInCollection = $00000D27; adErrObjectNotSet = $00000D5C; adErrDataConversion = $00000D5D; adErrObjectClosed = $00000E78; adErrObjectOpen = $00000E79; adErrProviderNotFound = $00000E7A; adErrBoundToCommand = $00000E7B; adErrInvalidParamInfo = $00000E7C; adErrInvalidConnection = $00000E7D; adErrNotReentrant = $00000E7E; adErrStillExecuting = $00000E7F; adErrOperationCancelled = $00000E80; adErrStillConnecting = $00000E81; adErrInvalidTransaction = $00000E82; adErrNotExecuting = $00000E83; adErrUnsafeOperation = $00000E84; adwrnSecurityDialog = $00000E85; adwrnSecurityDialogHeader = $00000E86; adErrIntegrityViolation = $00000E87; adErrPermissionDenied = $00000E88; adErrDataOverflow = $00000E89; adErrSchemaViolation = $00000E8A; adErrSignMismatch = $00000E8B; adErrCantConvertvalue = $00000E8C; adErrCantCreate = $00000E8D; adErrColumnNotOnThisRow = $00000E8E; adErrURLDoesNotExist = $00000E8F; adErrTreePermissionDenied = $00000E90; adErrInvalidURL = $00000E91; adErrResourceLocked = $00000E92; adErrResourceExists = $00000E93; adErrCannotComplete = $00000E94; adErrVolumeNotFound = $00000E95; adErrOutOfSpace = $00000E96; adErrResourceOutOfScope = $00000E97; adErrUnavailable = $00000E98; adErrURLNamedRowDoesNotExist = $00000E99; adErrDelResOutOfScope = $00000E9A; adErrPropInvalidColumn = $00000E9B; adErrPropInvalidOption = $00000E9C; adErrPropInvalidValue = $00000E9D; adErrPropConflicting = $00000E9E; adErrPropNotAllSettable = $00000E9F; adErrPropNotSet = $00000EA0; adErrPropNotSettable = $00000EA1; adErrPropNotSupported = $00000EA2; adErrCatalogNotSet = $00000EA3; adErrCantChangeConnection = $00000EA4; adErrFieldsUpdateFailed = $00000EA5; adErrDenyNotSupported = $00000EA6; adErrDenyTypeNotSupported = $00000EA7; adErrProviderNotSpecified = $00000EA9; // Constants for enum ParameterAttributesEnum type ParameterAttributesEnum = TOleEnum; const adParamSigned = $00000010; adParamNullable = $00000040; adParamLong = $00000080; // Constants for enum ParameterDirectionEnum type ParameterDirectionEnum = TOleEnum; const adParamUnknown = $00000000; adParamInput = $00000001; adParamOutput = $00000002; adParamInputOutput = $00000003; adParamReturnValue = $00000004; // Constants for enum CommandTypeEnum type CommandTypeEnum = TOleEnum; const adCmdUnspecified = $FFFFFFFF; adCmdUnknown = $00000008; adCmdText = $00000001; adCmdTable = $00000002; adCmdStoredProc = $00000004; adCmdFile = $00000100; adCmdTableDirect = $00000200; // Constants for enum EventStatusEnum type EventStatusEnum = TOleEnum; const adStatusOK = $00000001; adStatusErrorsOccurred = $00000002; adStatusCantDeny = $00000003; adStatusCancel = $00000004; adStatusUnwantedEvent = $00000005; // Constants for enum EventReasonEnum type EventReasonEnum = TOleEnum; const adRsnAddNew = $00000001; adRsnDelete = $00000002; adRsnUpdate = $00000003; adRsnUndoUpdate = $00000004; adRsnUndoAddNew = $00000005; adRsnUndoDelete = $00000006; adRsnRequery = $00000007; adRsnResynch = $00000008; adRsnClose = $00000009; adRsnMove = $0000000A; adRsnFirstChange = $0000000B; adRsnMoveFirst = $0000000C; adRsnMoveNext = $0000000D; adRsnMovePrevious = $0000000E; adRsnMoveLast = $0000000F; // Constants for enum SchemaEnum type SchemaEnum = TOleEnum; const adSchemaProviderSpecific = $FFFFFFFF; adSchemaAsserts = $00000000; adSchemaCatalogs = $00000001; adSchemaCharacterSets = $00000002; adSchemaCollations = $00000003; adSchemaColumns = $00000004; adSchemaCheckConstraints = $00000005; adSchemaConstraintColumnUsage = $00000006; adSchemaConstraintTableUsage = $00000007; adSchemaKeyColumnUsage = $00000008; adSchemaReferentialContraints = $00000009; adSchemaReferentialConstraints = $00000009; adSchemaTableConstraints = $0000000A; adSchemaColumnsDomainUsage = $0000000B; adSchemaIndexes = $0000000C; adSchemaColumnPrivileges = $0000000D; adSchemaTablePrivileges = $0000000E; adSchemaUsagePrivileges = $0000000F; adSchemaProcedures = $00000010; adSchemaSchemata = $00000011; adSchemaSQLLanguages = $00000012; adSchemaStatistics = $00000013; adSchemaTables = $00000014; adSchemaTranslations = $00000015; adSchemaProviderTypes = $00000016; adSchemaViews = $00000017; adSchemaViewColumnUsage = $00000018; adSchemaViewTableUsage = $00000019; adSchemaProcedureParameters = $0000001A; adSchemaForeignKeys = $0000001B; adSchemaPrimaryKeys = $0000001C; adSchemaProcedureColumns = $0000001D; adSchemaDBInfoKeywords = $0000001E; adSchemaDBInfoLiterals = $0000001F; adSchemaCubes = $00000020; adSchemaDimensions = $00000021; adSchemaHierarchies = $00000022; adSchemaLevels = $00000023; adSchemaMeasures = $00000024; adSchemaProperties = $00000025; adSchemaMembers = $00000026; adSchemaTrustees = $00000027; adSchemaFunctions = $00000028; adSchemaActions = $00000029; adSchemaCommands = $0000002A; adSchemaSets = $0000002B; // Constants for enum FieldStatusEnum type FieldStatusEnum = TOleEnum; const adFieldOK = $00000000; adFieldCantConvertValue = $00000002; adFieldIsNull = $00000003; adFieldTruncated = $00000004; adFieldSignMismatch = $00000005; adFieldDataOverflow = $00000006; adFieldCantCreate = $00000007; adFieldUnavailable = $00000008; adFieldPermissionDenied = $00000009; adFieldIntegrityViolation = $0000000A; adFieldSchemaViolation = $0000000B; adFieldBadStatus = $0000000C; adFieldDefault = $0000000D; adFieldIgnore = $0000000F; adFieldDoesNotExist = $00000010; adFieldInvalidURL = $00000011; adFieldResourceLocked = $00000012; adFieldResourceExists = $00000013; adFieldCannotComplete = $00000014; adFieldVolumeNotFound = $00000015; adFieldOutOfSpace = $00000016; adFieldCannotDeleteSource = $00000017; adFieldReadOnly = $00000018; adFieldResourceOutOfScope = $00000019; adFieldAlreadyExists = $0000001A; adFieldPendingInsert = $00010000; adFieldPendingDelete = $00020000; adFieldPendingChange = $00040000; adFieldPendingUnknown = $00080000; adFieldPendingUnknownDelete = $00100000; // Constants for enum SeekEnum type SeekEnum = TOleEnum; const adSeekFirstEQ = $00000001; adSeekLastEQ = $00000002; adSeekAfterEQ = $00000004; adSeekAfter = $00000008; adSeekBeforeEQ = $00000010; adSeekBefore = $00000020; // Constants for enum ADCPROP_UPDATECRITERIA_ENUM type ADCPROP_UPDATECRITERIA_ENUM = TOleEnum; const adCriteriaKey = $00000000; adCriteriaAllCols = $00000001; adCriteriaUpdCols = $00000002; adCriteriaTimeStamp = $00000003; // Constants for enum ADCPROP_ASYNCTHREADPRIORITY_ENUM type ADCPROP_ASYNCTHREADPRIORITY_ENUM = TOleEnum; const adPriorityLowest = $00000001; adPriorityBelowNormal = $00000002; adPriorityNormal = $00000003; adPriorityAboveNormal = $00000004; adPriorityHighest = $00000005; // Constants for enum ADCPROP_AUTORECALC_ENUM type ADCPROP_AUTORECALC_ENUM = TOleEnum; const adRecalcUpFront = $00000000; adRecalcAlways = $00000001; // Constants for enum ADCPROP_UPDATERESYNC_ENUM type ADCPROP_UPDATERESYNC_ENUM = TOleEnum; const adResyncNone = $00000000; adResyncAutoIncrement = $00000001; adResyncConflicts = $00000002; adResyncUpdates = $00000004; adResyncInserts = $00000008; adResyncAll = $0000000F; // Constants for enum MoveRecordOptionsEnum type MoveRecordOptionsEnum = TOleEnum; const adMoveUnspecified = $FFFFFFFF; adMoveOverWrite = $00000001; adMoveDontUpdateLinks = $00000002; adMoveAllowEmulation = $00000004; // Constants for enum CopyRecordOptionsEnum type CopyRecordOptionsEnum = TOleEnum; const adCopyUnspecified = $FFFFFFFF; adCopyOverWrite = $00000001; adCopyAllowEmulation = $00000004; adCopyNonRecursive = $00000002; // Constants for enum StreamTypeEnum type StreamTypeEnum = TOleEnum; const adTypeBinary = $00000001; adTypeText = $00000002; // Constants for enum LineSeparatorEnum type LineSeparatorEnum = TOleEnum; const adLF = $0000000A; adCR = $0000000D; adCRLF = $FFFFFFFF; // Constants for enum StreamOpenOptionsEnum type StreamOpenOptionsEnum = TOleEnum; const adOpenStreamUnspecified = $FFFFFFFF; adOpenStreamAsync = $00000001; adOpenStreamFromRecord = $00000004; // Constants for enum StreamWriteEnum type StreamWriteEnum = TOleEnum; const adWriteChar = $00000000; adWriteLine = $00000001; stWriteChar = $00000000; stWriteLine = $00000001; // Constants for enum SaveOptionsEnum type SaveOptionsEnum = TOleEnum; const adSaveCreateNotExist = $00000001; adSaveCreateOverWrite = $00000002; // Constants for enum FieldEnum type FieldEnum = TOleEnum; const adDefaultStream = $FFFFFFFF; adRecordURL = $FFFFFFFE; // Constants for enum StreamReadEnum type StreamReadEnum = TOleEnum; const adReadAll = $FFFFFFFF; adReadLine = $FFFFFFFE; // Constants for enum RecordTypeEnum type RecordTypeEnum = TOleEnum; const adSimpleRecord = $00000000; adCollectionRecord = $00000001; adStructDoc = $00000002; type // *********************************************************************// // Forward declaration of types defined in TypeLibrary // *********************************************************************// _Collection = interface; _DynaCollection = interface; _ADO = interface; Properties = interface; Property_ = interface; Error = interface; Errors = interface; Command15 = interface; Connection15 = interface; _Connection = interface; Recordset15 = interface; Recordset20 = interface; Recordset21 = interface; _Recordset = interface; Fields15 = interface; Fields20 = interface; Fields = interface; Field20 = interface; Field = interface; _Parameter = interface; Parameters = interface; Command25 = interface; _Command = interface; ConnectionEventsVt = interface; RecordsetEventsVt = interface; ADOConnectionConstruction15 = interface; ADOConnectionConstruction = interface; _Record = interface; _Stream = interface; ADORecordConstruction = interface; ADOStreamConstruction = interface; ADOCommandConstruction = interface; ADORecordsetConstruction = interface; Field15 = interface; // *********************************************************************// // Declaration of structures, unions and aliases. // *********************************************************************// POleVariant1 = ^OleVariant; {*} PositionEnum_Param = PositionEnum; SearchDirection = SearchDirectionEnum; ADO_LONGPTR = Integer; // *********************************************************************// // Interface: _Collection // Flags: (4544) Dual NonExtensible OleAutomation Dispatchable // GUID: {00000512-0000-0010-8000-00AA006D2EA4} // *********************************************************************// _Collection = interface(IDispatch) ['{00000512-0000-0010-8000-00AA006D2EA4}'] function Get_Count: Integer; safecall; function _NewEnum: IUnknown; safecall; procedure Refresh; safecall; property Count: Integer read Get_Count; end; // *********************************************************************// // Interface: _DynaCollection // Flags: (4544) Dual NonExtensible OleAutomation Dispatchable // GUID: {00000513-0000-0010-8000-00AA006D2EA4} // *********************************************************************// _DynaCollection = interface(_Collection) ['{00000513-0000-0010-8000-00AA006D2EA4}'] procedure Append(const Object_: IDispatch); safecall; procedure Delete(Index: OleVariant); safecall; end; // *********************************************************************// // Interface: _ADO // Flags: (4544) Dual NonExtensible OleAutomation Dispatchable // GUID: {00000534-0000-0010-8000-00AA006D2EA4} // *********************************************************************// _ADO = interface(IDispatch) ['{00000534-0000-0010-8000-00AA006D2EA4}'] function Get_Properties: Properties; safecall; property Properties: Properties read Get_Properties; end; // *********************************************************************// // Interface: Properties // Flags: (4544) Dual NonExtensible OleAutomation Dispatchable // GUID: {00000504-0000-0010-8000-00AA006D2EA4} // *********************************************************************// Properties = interface(_Collection) ['{00000504-0000-0010-8000-00AA006D2EA4}'] function Get_Item(Index: OleVariant): Property_; safecall; property Item[Index: OleVariant]: Property_ read Get_Item; default; end; // *********************************************************************// // Interface: Property_ // Flags: (4544) Dual NonExtensible OleAutomation Dispatchable // GUID: {00000503-0000-0010-8000-00AA006D2EA4} // *********************************************************************// Property_ = interface(IDispatch) ['{00000503-0000-0010-8000-00AA006D2EA4}'] function Get_Value: OleVariant; safecall; procedure Set_Value(pval: OleVariant); safecall; function Get_Name: WideString; safecall; function Get_Type_: DataTypeEnum; safecall; function Get_Attributes: Integer; safecall; procedure Set_Attributes(plAttributes: Integer); safecall; property Value: OleVariant read Get_Value write Set_Value; property Name: WideString read Get_Name; property Type_: DataTypeEnum read Get_Type_; property Attributes: Integer read Get_Attributes; end; // *********************************************************************// // Interface: Error // Flags: (4544) Dual NonExtensible OleAutomation Dispatchable // GUID: {00000500-0000-0010-8000-00AA006D2EA4} // *********************************************************************// Error = interface(IDispatch) ['{00000500-0000-0010-8000-00AA006D2EA4}'] function Get_Number: Integer; safecall; function Get_Source: WideString; safecall; function Get_Description: WideString; safecall; function Get_HelpFile: WideString; safecall; function Get_HelpContext: Integer; safecall; function Get_SQLState: WideString; safecall; function Get_NativeError: Integer; safecall; property Number: Integer read Get_Number; property Source: WideString read Get_Source; property Description: WideString read Get_Description; property HelpFile: WideString read Get_HelpFile; property HelpContext: Integer read Get_HelpContext; property SQLState: WideString read Get_SQLState; property NativeError: Integer read Get_NativeError; end; // *********************************************************************// // Interface: Errors // Flags: (4544) Dual NonExtensible OleAutomation Dispatchable // GUID: {00000501-0000-0010-8000-00AA006D2EA4} // *********************************************************************// Errors = interface(_Collection) ['{00000501-0000-0010-8000-00AA006D2EA4}'] function Get_Item(Index: OleVariant): Error; safecall; procedure Clear; safecall; property Item[Index: OleVariant]: Error read Get_Item; default; end; // *********************************************************************// // Interface: Command15 // Flags: (4560) Hidden Dual NonExtensible OleAutomation Dispatchable // GUID: {00000508-0000-0010-8000-00AA006D2EA4} // *********************************************************************// Command15 = interface(_ADO) ['{00000508-0000-0010-8000-00AA006D2EA4}'] function Get_ActiveConnection: Connection15; safecall; procedure _Set_ActiveConnection(const ppvObject: Connection15); safecall; procedure Set_ActiveConnection(ppvObject: OleVariant); safecall; function Get_CommandText: WideString; safecall; procedure Set_CommandText(const pbstr: WideString); safecall; function Get_CommandTimeout: Integer; safecall; procedure Set_CommandTimeout(pl: Integer); safecall; function Get_Prepared: WordBool; safecall; procedure Set_Prepared(pfPrepared: WordBool); safecall; function Execute(out RecordsAffected: OleVariant; const Parameters: OleVariant; Options: Integer): Recordset15; safecall; function CreateParameter(const Name: WideString; Type_: DataTypeEnum; Direction: ParameterDirectionEnum; Size: ADO_LONGPTR; Value: OleVariant): _Parameter; safecall; function Get_Parameters: Parameters; safecall; procedure Set_CommandType(plCmdType: CommandTypeEnum); safecall; function Get_CommandType: CommandTypeEnum; safecall; function Get_Name: WideString; safecall; procedure Set_Name(const pbstrName: WideString); safecall; property CommandText: WideString read Get_CommandText write Set_CommandText; property CommandTimeout: Integer read Get_CommandTimeout write Set_CommandTimeout; property Prepared: WordBool read Get_Prepared write Set_Prepared; property Parameters: Parameters read Get_Parameters; property CommandType: CommandTypeEnum read Get_CommandType write Set_CommandType; property Name: WideString read Get_Name write Set_Name; end; // *********************************************************************// // Interface: Connection15 // Flags: (4432) Hidden Dual OleAutomation Dispatchable // GUID: {00000515-0000-0010-8000-00AA006D2EA4} // *********************************************************************// Connection15 = interface(_ADO) ['{00000515-0000-0010-8000-00AA006D2EA4}'] function Get_ConnectionString: WideString; safecall; procedure Set_ConnectionString(const pbstr: WideString); safecall; function Get_CommandTimeout: Integer; safecall; procedure Set_CommandTimeout(plTimeout: Integer); safecall; function Get_ConnectionTimeout: Integer; safecall; procedure Set_ConnectionTimeout(plTimeout: Integer); safecall; function Get_Version: WideString; safecall; procedure Close; safecall; function Execute(const CommandText: WideString; out RecordsAffected: OleVariant; Options: Integer): Recordset15; safecall; function BeginTrans: Integer; safecall; procedure CommitTrans; safecall; procedure RollbackTrans; safecall; procedure Open(const ConnectionString: WideString; const UserID: WideString; const Password: WideString; Options: Integer); safecall; function Get_Errors: Errors; safecall; function Get_DefaultDatabase: WideString; safecall; procedure Set_DefaultDatabase(const pbstr: WideString); safecall; function Get_IsolationLevel: IsolationLevelEnum; safecall; procedure Set_IsolationLevel(Level: IsolationLevelEnum); safecall; function Get_Attributes: Integer; safecall; procedure Set_Attributes(plAttr: Integer); safecall; function Get_CursorLocation: CursorLocationEnum; safecall; procedure Set_CursorLocation(plCursorLoc: CursorLocationEnum); safecall; function Get_Mode: ConnectModeEnum; safecall; procedure Set_Mode(plMode: ConnectModeEnum); safecall; function Get_Provider: WideString; safecall; procedure Set_Provider(const pbstr: WideString); safecall; function Get_State: Integer; safecall; function OpenSchema(Schema: SchemaEnum; Restrictions: OleVariant; SchemaID: OleVariant): Recordset15; safecall; property ConnectionString: WideString read Get_ConnectionString write Set_ConnectionString; property CommandTimeout: Integer read Get_CommandTimeout write Set_CommandTimeout; property ConnectionTimeout: Integer read Get_ConnectionTimeout write Set_ConnectionTimeout; property Version: WideString read Get_Version; property Errors: Errors read Get_Errors; property DefaultDatabase: WideString read Get_DefaultDatabase write Set_DefaultDatabase; property IsolationLevel: IsolationLevelEnum read Get_IsolationLevel write Set_IsolationLevel; property Attributes: Integer read Get_Attributes write Set_Attributes; property CursorLocation: CursorLocationEnum read Get_CursorLocation write Set_CursorLocation; property Mode: ConnectModeEnum read Get_Mode write Set_Mode; property Provider: WideString read Get_Provider write Set_Provider; property State: Integer read Get_State; end; // *********************************************************************// // Interface: _Connection // Flags: (4416) Dual OleAutomation Dispatchable // GUID: {00000550-0000-0010-8000-00AA006D2EA4} // *********************************************************************// _Connection = interface(Connection15) ['{00000550-0000-0010-8000-00AA006D2EA4}'] procedure Cancel; safecall; end; // *********************************************************************// // Interface: Recordset15 // Flags: (4560) Hidden Dual NonExtensible OleAutomation Dispatchable // GUID: {0000050E-0000-0010-8000-00AA006D2EA4} // *********************************************************************// Recordset15 = interface(_ADO) ['{0000050E-0000-0010-8000-00AA006D2EA4}'] function Get_AbsolutePosition: PositionEnum_Param; safecall; procedure Set_AbsolutePosition(pl: PositionEnum_Param); safecall; procedure _Set_ActiveConnection(const pvar: IDispatch); safecall; procedure Set_ActiveConnection(pvar: OleVariant); safecall; function Get_ActiveConnection: OleVariant; safecall; function Get_BOF: WordBool; safecall; function Get_Bookmark: OleVariant; safecall; procedure Set_Bookmark(pvBookmark: OleVariant); safecall; function Get_CacheSize: Integer; safecall; procedure Set_CacheSize(pl: Integer); safecall; function Get_CursorType: CursorTypeEnum; safecall; procedure Set_CursorType(plCursorType: CursorTypeEnum); safecall; function Get_EOF: WordBool; safecall; function Get_Fields: Fields15; safecall; function Get_LockType: LockTypeEnum; safecall; procedure Set_LockType(plLockType: LockTypeEnum); safecall; function Get_MaxRecords: ADO_LONGPTR; safecall; procedure Set_MaxRecords(plMaxRecords: ADO_LONGPTR); safecall; function Get_RecordCount: ADO_LONGPTR; safecall; procedure _Set_Source(const pvSource: IDispatch); safecall; procedure Set_Source(const pvSource: WideString); safecall; function Get_Source: OleVariant; safecall; procedure AddNew(FieldList: OleVariant; Values: OleVariant); safecall; procedure CancelUpdate; safecall; procedure Close; safecall; procedure Delete(AffectRecords: AffectEnum); safecall; function GetRows(Rows: Integer; Start: OleVariant; Fields: OleVariant): OleVariant; safecall; procedure Move(NumRecords: ADO_LONGPTR; Start: OleVariant); safecall; procedure MoveNext; safecall; procedure MovePrevious; safecall; procedure MoveFirst; safecall; procedure MoveLast; safecall; procedure Open(Source: OleVariant; ActiveConnection: OleVariant; CursorType: CursorTypeEnum; LockType: LockTypeEnum; Options: Integer); safecall; procedure Requery(Options: Integer); safecall; procedure _xResync(AffectRecords: AffectEnum); safecall; procedure Update(Fields: OleVariant; Values: OleVariant); safecall; function Get_AbsolutePage: PositionEnum_Param; safecall; procedure Set_AbsolutePage(pl: PositionEnum_Param); safecall; function Get_EditMode: EditModeEnum; safecall; function Get_Filter: OleVariant; safecall; procedure Set_Filter(Criteria: OleVariant); safecall; function Get_PageCount: ADO_LONGPTR; safecall; function Get_PageSize: Integer; safecall; procedure Set_PageSize(pl: Integer); safecall; function Get_Sort: WideString; safecall; procedure Set_Sort(const Criteria: WideString); safecall; function Get_Status: Integer; safecall; function Get_State: Integer; safecall; function _xClone: Recordset15; safecall; procedure UpdateBatch(AffectRecords: AffectEnum); safecall; procedure CancelBatch(AffectRecords: AffectEnum); safecall; function Get_CursorLocation: CursorLocationEnum; safecall; procedure Set_CursorLocation(plCursorLoc: CursorLocationEnum); safecall; function NextRecordset(out RecordsAffected: OleVariant): Recordset15; safecall; function Supports(CursorOptions: CursorOptionEnum): WordBool; safecall; function Get_Collect(Index: OleVariant): OleVariant; safecall; procedure Set_Collect(Index: OleVariant; pvar: OleVariant); safecall; function Get_MarshalOptions: MarshalOptionsEnum; safecall; procedure Set_MarshalOptions(peMarshal: MarshalOptionsEnum); safecall; procedure Find(const Criteria: WideString; SkipRecords: ADO_LONGPTR; SearchDirection: SearchDirectionEnum; Start: OleVariant); safecall; property AbsolutePosition: PositionEnum_Param read Get_AbsolutePosition write Set_AbsolutePosition; property Bof: WordBool read Get_BOF; property Bookmark: OleVariant read Get_Bookmark write Set_Bookmark; property CacheSize: Integer read Get_CacheSize write Set_CacheSize; property CursorType: CursorTypeEnum read Get_CursorType write Set_CursorType; property Eof: WordBool read Get_EOF; property Fields: Fields15 read Get_Fields; property LockType: LockTypeEnum read Get_LockType write Set_LockType; property MaxRecords: ADO_LONGPTR read Get_MaxRecords write Set_MaxRecords; property RecordCount: ADO_LONGPTR read Get_RecordCount; property AbsolutePage: PositionEnum_Param read Get_AbsolutePage write Set_AbsolutePage; property EditMode: EditModeEnum read Get_EditMode; property Filter: OleVariant read Get_Filter write Set_Filter; property PageCount: ADO_LONGPTR read Get_PageCount; property PageSize: Integer read Get_PageSize write Set_PageSize; property Sort: WideString read Get_Sort write Set_Sort; property Status: Integer read Get_Status; property State: Integer read Get_State; property CursorLocation: CursorLocationEnum read Get_CursorLocation write Set_CursorLocation; property Collect[Index: OleVariant]: OleVariant read Get_Collect write Set_Collect; property MarshalOptions: MarshalOptionsEnum read Get_MarshalOptions write Set_MarshalOptions; end; // *********************************************************************// // Interface: Recordset20 // Flags: (4560) Hidden Dual NonExtensible OleAutomation Dispatchable // GUID: {0000054F-0000-0010-8000-00AA006D2EA4} // *********************************************************************// Recordset20 = interface(Recordset15) ['{0000054F-0000-0010-8000-00AA006D2EA4}'] procedure Cancel; safecall; function Get_DataSource: IUnknown; safecall; procedure _Set_DataSource(const ppunkDataSource: IUnknown); safecall; procedure _xSave(const FileName: WideString; PersistFormat: PersistFormatEnum); safecall; function Get_ActiveCommand: IDispatch; safecall; procedure Set_StayInSync(pbStayInSync: WordBool); safecall; function Get_StayInSync: WordBool; safecall; function GetString(StringFormat: StringFormatEnum; NumRows: Integer; const ColumnDelimeter: WideString; const RowDelimeter: WideString; const NullExpr: WideString): WideString; safecall; function Get_DataMember: WideString; safecall; procedure Set_DataMember(const pbstrDataMember: WideString); safecall; function CompareBookmarks(Bookmark1: OleVariant; Bookmark2: OleVariant): CompareEnum; safecall; function Clone(LockType: LockTypeEnum): Recordset15; safecall; procedure Resync(AffectRecords: AffectEnum; ResyncValues: ResyncEnum); safecall; property DataSource: IUnknown read Get_DataSource write _Set_DataSource; property ActiveCommand: IDispatch read Get_ActiveCommand; property StayInSync: WordBool read Get_StayInSync write Set_StayInSync; property DataMember: WideString read Get_DataMember write Set_DataMember; end; // *********************************************************************// // Interface: Recordset21 // Flags: (4560) Hidden Dual NonExtensible OleAutomation Dispatchable // GUID: {00000555-0000-0010-8000-00AA006D2EA4} // *********************************************************************// Recordset21 = interface(Recordset20) ['{00000555-0000-0010-8000-00AA006D2EA4}'] procedure Seek(KeyValues: OleVariant; SeekOption: SeekEnum); safecall; procedure Set_Index(const pbstrIndex: WideString); safecall; function Get_Index: WideString; safecall; property Index: WideString read Get_Index write Set_Index; end; // *********************************************************************// // Interface: _Recordset // Flags: (4544) Dual NonExtensible OleAutomation Dispatchable // GUID: {00000556-0000-0010-8000-00AA006D2EA4} // *********************************************************************// _Recordset = interface(Recordset21) ['{00000556-0000-0010-8000-00AA006D2EA4}'] procedure Save(Destination: OleVariant; PersistFormat: PersistFormatEnum); safecall; end; // *********************************************************************// // Interface: Fields15 // Flags: (4560) Hidden Dual NonExtensible OleAutomation Dispatchable // GUID: {00000506-0000-0010-8000-00AA006D2EA4} // *********************************************************************// Fields15 = interface(_Collection) ['{00000506-0000-0010-8000-00AA006D2EA4}'] function Get_Item(Index: OleVariant): Field20; safecall; property Item[Index: OleVariant]: Field20 read Get_Item; default; end; // *********************************************************************// // Interface: Fields20 // Flags: (4560) Hidden Dual NonExtensible OleAutomation Dispatchable // GUID: {0000054D-0000-0010-8000-00AA006D2EA4} // *********************************************************************// Fields20 = interface(Fields15) ['{0000054D-0000-0010-8000-00AA006D2EA4}'] procedure _Append(const Name: WideString; Type_: DataTypeEnum; DefinedSize: ADO_LONGPTR; Attrib: FieldAttributeEnum); safecall; procedure Delete(Index: OleVariant); safecall; end; // *********************************************************************// // Interface: Fields // Flags: (4544) Dual NonExtensible OleAutomation Dispatchable // GUID: {00000564-0000-0010-8000-00AA006D2EA4} // *********************************************************************// Fields = interface(Fields20) ['{00000564-0000-0010-8000-00AA006D2EA4}'] procedure Append(const Name: WideString; Type_: DataTypeEnum; DefinedSize: ADO_LONGPTR; Attrib: FieldAttributeEnum; FieldValue: OleVariant); safecall; procedure Update; safecall; procedure Resync(ResyncValues: ResyncEnum); safecall; procedure CancelUpdate; safecall; end; // *********************************************************************// // Interface: Field20 // Flags: (4560) Hidden Dual NonExtensible OleAutomation Dispatchable // GUID: {0000054C-0000-0010-8000-00AA006D2EA4} // *********************************************************************// Field20 = interface(_ADO) ['{0000054C-0000-0010-8000-00AA006D2EA4}'] function Get_ActualSize: ADO_LONGPTR; safecall; function Get_Attributes: Integer; safecall; function Get_DefinedSize: ADO_LONGPTR; safecall; function Get_Name: WideString; safecall; function Get_Type_: DataTypeEnum; safecall; function Get_Value: OleVariant; safecall; procedure Set_Value(pvar: OleVariant); safecall; function Get_Precision: Byte; safecall; function Get_NumericScale: Byte; safecall; procedure AppendChunk(Data: OleVariant); safecall; function GetChunk(Length: Integer): OleVariant; safecall; function Get_OriginalValue: OleVariant; safecall; function Get_UnderlyingValue: OleVariant; safecall; function Get_DataFormat: IUnknown; safecall; procedure _Set_DataFormat(const ppiDF: IUnknown); safecall; procedure Set_Precision(pbPrecision: Byte); safecall; procedure Set_NumericScale(pbNumericScale: Byte); safecall; procedure Set_Type_(pDataType: DataTypeEnum); safecall; procedure Set_DefinedSize(pl: ADO_LONGPTR); safecall; procedure Set_Attributes(pl: Integer); safecall; property ActualSize: ADO_LONGPTR read Get_ActualSize; property Attributes: Integer read Get_Attributes write Set_Attributes; property DefinedSize: ADO_LONGPTR read Get_DefinedSize write Set_DefinedSize; property Name: WideString read Get_Name; property Type_: DataTypeEnum read Get_Type_ write Set_Type_; property Value: OleVariant read Get_Value write Set_Value; property Precision: Byte read Get_Precision write Set_Precision; property NumericScale: Byte read Get_NumericScale write Set_NumericScale; property OriginalValue: OleVariant read Get_OriginalValue; property UnderlyingValue: OleVariant read Get_UnderlyingValue; property DataFormat: IUnknown read Get_DataFormat write _Set_DataFormat; end; // *********************************************************************// // Interface: Field // Flags: (4544) Dual NonExtensible OleAutomation Dispatchable // GUID: {00000569-0000-0010-8000-00AA006D2EA4} // *********************************************************************// Field = interface(Field20) ['{00000569-0000-0010-8000-00AA006D2EA4}'] function Get_Status: Integer; safecall; property Status: Integer read Get_Status; end; // *********************************************************************// // Interface: _Parameter // Flags: (4544) Dual NonExtensible OleAutomation Dispatchable // GUID: {0000050C-0000-0010-8000-00AA006D2EA4} // *********************************************************************// _Parameter = interface(_ADO) ['{0000050C-0000-0010-8000-00AA006D2EA4}'] function Get_Name: WideString; safecall; procedure Set_Name(const pbstr: WideString); safecall; function Get_Value: OleVariant; safecall; procedure Set_Value(pvar: OleVariant); safecall; function Get_Type_: DataTypeEnum; safecall; procedure Set_Type_(psDataType: DataTypeEnum); safecall; procedure Set_Direction(plParmDirection: ParameterDirectionEnum); safecall; function Get_Direction: ParameterDirectionEnum; safecall; procedure Set_Precision(pbPrecision: Byte); safecall; function Get_Precision: Byte; safecall; procedure Set_NumericScale(pbScale: Byte); safecall; function Get_NumericScale: Byte; safecall; procedure Set_Size(pl: ADO_LONGPTR); safecall; function Get_Size: ADO_LONGPTR; safecall; procedure AppendChunk(Val: OleVariant); safecall; function Get_Attributes: Integer; safecall; procedure Set_Attributes(plParmAttribs: Integer); safecall; property Name: WideString read Get_Name write Set_Name; property Value: OleVariant read Get_Value write Set_Value; property Type_: DataTypeEnum read Get_Type_ write Set_Type_; property Direction: ParameterDirectionEnum read Get_Direction write Set_Direction; property Precision: Byte read Get_Precision write Set_Precision; property NumericScale: Byte read Get_NumericScale write Set_NumericScale; property Size: ADO_LONGPTR read Get_Size write Set_Size; property Attributes: Integer read Get_Attributes write Set_Attributes; end; // *********************************************************************// // Interface: Parameters // Flags: (4544) Dual NonExtensible OleAutomation Dispatchable // GUID: {0000050D-0000-0010-8000-00AA006D2EA4} // *********************************************************************// Parameters = interface(_DynaCollection) ['{0000050D-0000-0010-8000-00AA006D2EA4}'] function Get_Item(Index: OleVariant): _Parameter; safecall; property Item[Index: OleVariant]: _Parameter read Get_Item; default; end; // *********************************************************************// // Interface: Command25 // Flags: (4560) Hidden Dual NonExtensible OleAutomation Dispatchable // GUID: {0000054E-0000-0010-8000-00AA006D2EA4} // *********************************************************************// Command25 = interface(Command15) ['{0000054E-0000-0010-8000-00AA006D2EA4}'] function Get_State: Integer; safecall; procedure Cancel; safecall; property State: Integer read Get_State; end; // *********************************************************************// // Interface: _Command // Flags: (4544) Dual NonExtensible OleAutomation Dispatchable // GUID: {B08400BD-F9D1-4D02-B856-71D5DBA123E9} // *********************************************************************// _Command = interface(Command25) ['{B08400BD-F9D1-4D02-B856-71D5DBA123E9}'] procedure _Set_CommandStream(const pvStream: IUnknown); safecall; function Get_CommandStream: OleVariant; safecall; procedure Set_Dialect(const pbstrDialect: WideString); safecall; function Get_Dialect: WideString; safecall; procedure Set_NamedParameters(pfNamedParameters: WordBool); safecall; function Get_NamedParameters: WordBool; safecall; property Dialect: WideString read Get_Dialect write Set_Dialect; property NamedParameters: WordBool read Get_NamedParameters write Set_NamedParameters; end; // *********************************************************************// // Interface: ConnectionEventsVt // Flags: (16) Hidden // GUID: {00000402-0000-0010-8000-00AA006D2EA4} // *********************************************************************// ConnectionEventsVt = interface(IUnknown) ['{00000402-0000-0010-8000-00AA006D2EA4}'] function InfoMessage(const pError: Error; var adStatus: EventStatusEnum; const pConnection: Connection15): HResult; stdcall; function BeginTransComplete(TransactionLevel: Integer; const pError: Error; var adStatus: EventStatusEnum; const pConnection: Connection15): HResult; stdcall; function CommitTransComplete(const pError: Error; var adStatus: EventStatusEnum; const pConnection: Connection15): HResult; stdcall; function RollbackTransComplete(const pError: Error; var adStatus: EventStatusEnum; const pConnection: Connection15): HResult; stdcall; function WillExecute(var Source: WideString; var CursorType: CursorTypeEnum; var LockType: LockTypeEnum; var Options: Integer; var adStatus: EventStatusEnum; const pCommand: _Command; const pRecordset: Recordset15; const pConnection: Connection15): HResult; stdcall; function ExecuteComplete(RecordsAffected: Integer; const pError: Error; var adStatus: EventStatusEnum; const pCommand: _Command; const pRecordset: Recordset15; const pConnection: Connection15): HResult; stdcall; function WillConnect(var ConnectionString: WideString; var UserID: WideString; var Password: WideString; var Options: Integer; var adStatus: EventStatusEnum; const pConnection: Connection15): HResult; stdcall; function ConnectComplete(const pError: Error; var adStatus: EventStatusEnum; const pConnection: Connection15): HResult; stdcall; function Disconnect(var adStatus: EventStatusEnum; const pConnection: Connection15): HResult; stdcall; end; // *********************************************************************// // Interface: RecordsetEventsVt // Flags: (16) Hidden // GUID: {00000403-0000-0010-8000-00AA006D2EA4} // *********************************************************************// RecordsetEventsVt = interface(IUnknown) ['{00000403-0000-0010-8000-00AA006D2EA4}'] function WillChangeField(cFields: Integer; Fields: OleVariant; var adStatus: EventStatusEnum; const pRecordset: Recordset15): HResult; stdcall; function FieldChangeComplete(cFields: Integer; Fields: OleVariant; const pError: Error; var adStatus: EventStatusEnum; const pRecordset: Recordset15): HResult; stdcall; function WillChangeRecord(adReason: EventReasonEnum; cRecords: Integer; var adStatus: EventStatusEnum; const pRecordset: Recordset15): HResult; stdcall; function RecordChangeComplete(adReason: EventReasonEnum; cRecords: Integer; const pError: Error; var adStatus: EventStatusEnum; const pRecordset: Recordset15): HResult; stdcall; function WillChangeRecordset(adReason: EventReasonEnum; var adStatus: EventStatusEnum; const pRecordset: Recordset15): HResult; stdcall; function RecordsetChangeComplete(adReason: EventReasonEnum; const pError: Error; var adStatus: EventStatusEnum; const pRecordset: Recordset15): HResult; stdcall; function WillMove(adReason: EventReasonEnum; var adStatus: EventStatusEnum; const pRecordset: Recordset15): HResult; stdcall; function MoveComplete(adReason: EventReasonEnum; const pError: Error; var adStatus: EventStatusEnum; const pRecordset: Recordset15): HResult; stdcall; function EndOfRecordset(var fMoreData: WordBool; var adStatus: EventStatusEnum; const pRecordset: Recordset15): HResult; stdcall; function FetchProgress(Progress: Integer; MaxProgress: Integer; var adStatus: EventStatusEnum; const pRecordset: Recordset15): HResult; stdcall; function FetchComplete(const pError: Error; var adStatus: EventStatusEnum; const pRecordset: Recordset15): HResult; stdcall; end; // *********************************************************************// // Interface: ADOConnectionConstruction15 // Flags: (512) Restricted // GUID: {00000516-0000-0010-8000-00AA006D2EA4} // *********************************************************************// ADOConnectionConstruction15 = interface(IUnknown) ['{00000516-0000-0010-8000-00AA006D2EA4}'] function Get_DSO(out ppDSO: IUnknown): HResult; stdcall; function Get_Session(out ppSession: IUnknown): HResult; stdcall; function WrapDSOandSession(const pDSO: IUnknown; const pSession: IUnknown): HResult; stdcall; end; // *********************************************************************// // Interface: ADOConnectionConstruction // Flags: (512) Restricted // GUID: {00000551-0000-0010-8000-00AA006D2EA4} // *********************************************************************// ADOConnectionConstruction = interface(ADOConnectionConstruction15) ['{00000551-0000-0010-8000-00AA006D2EA4}'] end; // *********************************************************************// // Interface: _Record // Flags: (4432) Hidden Dual OleAutomation Dispatchable // GUID: {00000562-0000-0010-8000-00AA006D2EA4} // *********************************************************************// _Record = interface(_ADO) ['{00000562-0000-0010-8000-00AA006D2EA4}'] function Get_ActiveConnection: OleVariant; safecall; procedure Set_ActiveConnection(const pvar: WideString); safecall; procedure _Set_ActiveConnection(const pvar: Connection15); safecall; function Get_State: ObjectStateEnum; safecall; function Get_Source: OleVariant; safecall; procedure Set_Source(const pvar: WideString); safecall; procedure _Set_Source(const pvar: IDispatch); safecall; function Get_Mode: ConnectModeEnum; safecall; procedure Set_Mode(pMode: ConnectModeEnum); safecall; function Get_ParentURL: WideString; safecall; function MoveRecord(const Source: WideString; const Destination: WideString; const UserName: WideString; const Password: WideString; Options: MoveRecordOptionsEnum; Async: WordBool): WideString; safecall; function CopyRecord(const Source: WideString; const Destination: WideString; const UserName: WideString; const Password: WideString; Options: CopyRecordOptionsEnum; Async: WordBool): WideString; safecall; procedure DeleteRecord(const Source: WideString; Async: WordBool); safecall; procedure Open(Source: OleVariant; ActiveConnection: OleVariant; Mode: ConnectModeEnum; CreateOptions: RecordCreateOptionsEnum; Options: RecordOpenOptionsEnum; const UserName: WideString; const Password: WideString); safecall; procedure Close; safecall; function Get_Fields: Fields15; safecall; function Get_RecordType: RecordTypeEnum; safecall; function GetChildren: Recordset15; safecall; procedure Cancel; safecall; property State: ObjectStateEnum read Get_State; property Mode: ConnectModeEnum read Get_Mode write Set_Mode; property ParentURL: WideString read Get_ParentURL; property Fields: Fields15 read Get_Fields; property RecordType: RecordTypeEnum read Get_RecordType; end; // *********************************************************************// // Interface: _Stream // Flags: (4432) Hidden Dual OleAutomation Dispatchable // GUID: {00000565-0000-0010-8000-00AA006D2EA4} // *********************************************************************// _Stream = interface(IDispatch) ['{00000565-0000-0010-8000-00AA006D2EA4}'] function Get_Size: ADO_LONGPTR; safecall; function Get_EOS: WordBool; safecall; function Get_Position: ADO_LONGPTR; safecall; procedure Set_Position(pPos: ADO_LONGPTR); safecall; function Get_Type_: StreamTypeEnum; safecall; procedure Set_Type_(ptype: StreamTypeEnum); safecall; function Get_LineSeparator: LineSeparatorEnum; safecall; procedure Set_LineSeparator(pLS: LineSeparatorEnum); safecall; function Get_State: ObjectStateEnum; safecall; function Get_Mode: ConnectModeEnum; safecall; procedure Set_Mode(pMode: ConnectModeEnum); safecall; function Get_Charset: WideString; safecall; procedure Set_Charset(const pbstrCharset: WideString); safecall; function Read(NumBytes: Integer): OleVariant; safecall; procedure Open(Source: OleVariant; Mode: ConnectModeEnum; Options: StreamOpenOptionsEnum; const UserName: WideString; const Password: WideString); safecall; procedure Close; safecall; procedure SkipLine; safecall; procedure Write(Buffer: OleVariant); safecall; procedure SetEOS; safecall; procedure CopyTo(const DestStream: _Stream; CharNumber: ADO_LONGPTR); safecall; procedure Flush; safecall; procedure SaveToFile(const FileName: WideString; Options: SaveOptionsEnum); safecall; procedure LoadFromFile(const FileName: WideString); safecall; function ReadText(NumChars: Integer): WideString; safecall; procedure WriteText(const Data: WideString; Options: StreamWriteEnum); safecall; procedure Cancel; safecall; property Size: ADO_LONGPTR read Get_Size; property EOS: WordBool read Get_EOS; property Position: ADO_LONGPTR read Get_Position write Set_Position; property Type_: StreamTypeEnum read Get_Type_ write Set_Type_; property LineSeparator: LineSeparatorEnum read Get_LineSeparator write Set_LineSeparator; property State: ObjectStateEnum read Get_State; property Mode: ConnectModeEnum read Get_Mode write Set_Mode; property Charset: WideString read Get_Charset write Set_Charset; end; // *********************************************************************// // Interface: ADORecordConstruction // Flags: (4608) Restricted Dispatchable // GUID: {00000567-0000-0010-8000-00AA006D2EA4} // *********************************************************************// ADORecordConstruction = interface(IDispatch) ['{00000567-0000-0010-8000-00AA006D2EA4}'] function Get_Row(out ppRow: IUnknown): HResult; stdcall; function Set_Row(const ppRow: IUnknown): HResult; stdcall; function Set_ParentRow(const Param1: IUnknown): HResult; stdcall; end; // *********************************************************************// // Interface: ADOStreamConstruction // Flags: (4608) Restricted Dispatchable // GUID: {00000568-0000-0010-8000-00AA006D2EA4} // *********************************************************************// ADOStreamConstruction = interface(IDispatch) ['{00000568-0000-0010-8000-00AA006D2EA4}'] function Get_Stream(out ppStm: IUnknown): HResult; stdcall; function Set_Stream(const ppStm: IUnknown): HResult; stdcall; end; // *********************************************************************// // Interface: ADOCommandConstruction // Flags: (512) Restricted // GUID: {00000517-0000-0010-8000-00AA006D2EA4} // *********************************************************************// ADOCommandConstruction = interface(IUnknown) ['{00000517-0000-0010-8000-00AA006D2EA4}'] function Get_OLEDBCommand: IUnknown; safecall; procedure Set_OLEDBCommand(const ppOLEDBCommand: IUnknown); safecall; property OLEDBCommand: IUnknown read Get_OLEDBCommand write Set_OLEDBCommand; end; // *********************************************************************// // Interface: ADORecordsetConstruction // Flags: (4608) Restricted Dispatchable // GUID: {00000283-0000-0010-8000-00AA006D2EA4} // *********************************************************************// ADORecordsetConstruction = interface(IDispatch) ['{00000283-0000-0010-8000-00AA006D2EA4}'] function Get_Rowset(out ppRowset: IUnknown): HResult; stdcall; function Set_Rowset(const ppRowset: IUnknown): HResult; stdcall; function Get_Chapter(out plChapter: ADO_LONGPTR): HResult; stdcall; function Set_Chapter(plChapter: ADO_LONGPTR): HResult; stdcall; function Get_RowPosition(out ppRowPos: IUnknown): HResult; stdcall; function Set_RowPosition(const ppRowPos: IUnknown): HResult; stdcall; end; // *********************************************************************// // Interface: Field15 // Flags: (4560) Hidden Dual NonExtensible OleAutomation Dispatchable // GUID: {00000505-0000-0010-8000-00AA006D2EA4} // *********************************************************************// Field15 = interface(_ADO) ['{00000505-0000-0010-8000-00AA006D2EA4}'] function Get_ActualSize: ADO_LONGPTR; safecall; function Get_Attributes: Integer; safecall; function Get_DefinedSize: ADO_LONGPTR; safecall; function Get_Name: WideString; safecall; function Get_Type_: DataTypeEnum; safecall; function Get_Value: OleVariant; safecall; procedure Set_Value(pvar: OleVariant); safecall; function Get_Precision: Byte; safecall; function Get_NumericScale: Byte; safecall; procedure AppendChunk(Data: OleVariant); safecall; function GetChunk(Length: Integer): OleVariant; safecall; function Get_OriginalValue: OleVariant; safecall; function Get_UnderlyingValue: OleVariant; safecall; property ActualSize: ADO_LONGPTR read Get_ActualSize; property Attributes: Integer read Get_Attributes; property DefinedSize: ADO_LONGPTR read Get_DefinedSize; property Name: WideString read Get_Name; property Type_: DataTypeEnum read Get_Type_; property Value: OleVariant read Get_Value write Set_Value; property Precision: Byte read Get_Precision; property NumericScale: Byte read Get_NumericScale; property OriginalValue: OleVariant read Get_OriginalValue; property UnderlyingValue: OleVariant read Get_UnderlyingValue; end; // *********************************************************************// // Declaration of CoClasses defined in Type Library // (NOTE: Here we map each CoClass to its Default Interface) // *********************************************************************// Connection = Connection15; Record_ = _Record; Stream = _Stream; Command = _Command; Recordset = Recordset15; Parameter = _Parameter; // *********************************************************************// // The Class CoConnection provides a Create and CreateRemote method to // create instances of the default interface Connection15 exposed by // the CoClass Connection. The functions are intended to be used by // clients wishing to automate the CoClass objects exposed by the // server of this typelibrary. // *********************************************************************// CoConnection = class class function Create: Connection15; class function CreateRemote(const MachineName: string): Connection15; end; // *********************************************************************// // The Class CoRecord_ provides a Create and CreateRemote method to // create instances of the default interface _Record exposed by // the CoClass Record_. The functions are intended to be used by // clients wishing to automate the CoClass objects exposed by the // server of this typelibrary. // *********************************************************************// CoRecord_ = class class function Create: _Record; class function CreateRemote(const MachineName: string): _Record; end; // *********************************************************************// // The Class CoStream provides a Create and CreateRemote method to // create instances of the default interface _Stream exposed by // the CoClass Stream. The functions are intended to be used by // clients wishing to automate the CoClass objects exposed by the // server of this typelibrary. // *********************************************************************// CoStream = class class function Create: _Stream; class function CreateRemote(const MachineName: string): _Stream; end; // *********************************************************************// // The Class CoCommand provides a Create and CreateRemote method to // create instances of the default interface _Command exposed by // the CoClass Command. The functions are intended to be used by // clients wishing to automate the CoClass objects exposed by the // server of this typelibrary. // *********************************************************************// CoCommand = class class function Create: _Command; class function CreateRemote(const MachineName: string): _Command; end; // *********************************************************************// // The Class CoRecordset provides a Create and CreateRemote method to // create instances of the default interface Recordset15 exposed by // the CoClass Recordset. The functions are intended to be used by // clients wishing to automate the CoClass objects exposed by the // server of this typelibrary. // *********************************************************************// CoRecordset = class class function Create: Recordset15; class function CreateRemote(const MachineName: string): Recordset15; end; // *********************************************************************// // The Class CoParameter provides a Create and CreateRemote method to // create instances of the default interface _Parameter exposed by // the CoClass Parameter. The functions are intended to be used by // clients wishing to automate the CoClass objects exposed by the // server of this typelibrary. // *********************************************************************// CoParameter = class class function Create: _Parameter; class function CreateRemote(const MachineName: string): _Parameter; end; implementation uses ComObj; class function CoConnection.Create: Connection15; begin try Result := CreateComObject(CLASS_Connection) as Connection15; except CoInitialize(nil); Result := CreateComObject(CLASS_Connection) as Connection15; end; end; class function CoConnection.CreateRemote(const MachineName: string): Connection15; begin Result := CreateRemoteComObject(MachineName, CLASS_Connection) as Connection15; end; class function CoRecord_.Create: _Record; begin Result := CreateComObject(CLASS_Record_) as _Record; end; class function CoRecord_.CreateRemote(const MachineName: string): _Record; begin Result := CreateRemoteComObject(MachineName, CLASS_Record_) as _Record; end; class function CoStream.Create: _Stream; begin Result := CreateComObject(CLASS_Stream) as _Stream; end; class function CoStream.CreateRemote(const MachineName: string): _Stream; begin Result := CreateRemoteComObject(MachineName, CLASS_Stream) as _Stream; end; class function CoCommand.Create: _Command; begin Result := CreateComObject(CLASS_Command) as _Command; end; class function CoCommand.CreateRemote(const MachineName: string): _Command; begin Result := CreateRemoteComObject(MachineName, CLASS_Command) as _Command; end; class function CoRecordset.Create: Recordset15; begin Result := CreateComObject(CLASS_Recordset) as Recordset15; end; class function CoRecordset.CreateRemote(const MachineName: string): Recordset15; begin Result := CreateRemoteComObject(MachineName, CLASS_Recordset) as Recordset15; end; class function CoParameter.Create: _Parameter; begin Result := CreateComObject(CLASS_Parameter) as _Parameter; end; class function CoParameter.CreateRemote(const MachineName: string): _Parameter; begin Result := CreateRemoteComObject(MachineName, CLASS_Parameter) as _Parameter; end; end. ================================================ FILE: lib/zeosdbo/src/plain/ZPlainAdoDriver.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Delphi plain driver interface to ADO } { } { Originally written by Janos Fegyverneki } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZPlainAdoDriver; interface {$I ZPlain.inc} uses ZClasses, ZPlainDriver; type TZAdoPlainDriver = class (TZAbstractPlainDriver, IZPlainDriver) protected function IsAnsiDriver: Boolean; override; public constructor Create; procedure LoadCodePages; override; function GetProtocol: string; override; function GetDescription: string; override; procedure Initialize(const Location: String = ''); override; function Clone: IZPlainDriver; override; end; implementation uses ZCompatibility, ZEncoding; procedure TZAdoPlainDriver.LoadCodePages; begin AddCodePage('CP_ADO', 0, ceAnsi, ZDefaultSystemCodePage,'',1, False); end; function TZAdoPlainDriver.IsAnsiDriver: Boolean; begin Result := False; end; constructor TZAdoPlainDriver.Create; begin LoadCodePages; end; function TZAdoPlainDriver.GetProtocol: string; begin Result := 'ado'; end; function TZAdoPlainDriver.GetDescription: string; begin Result := 'Native driver for Microsoft ADO'; end; procedure TZAdoPlainDriver.Initialize(const Location: String = ''); begin end; function TZAdoPlainDriver.Clone: IZPlainDriver; begin Result := Self; end; end. ================================================ FILE: lib/zeosdbo/src/plain/ZPlainDbLibConstants.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Delphi plain driver interface to DBLibrary } { } { Originally written by Janos Fegyverneki } { FreeTDS supportd by Bogdan Dragulin } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZPlainDbLibConstants; interface {$I ZPlain.inc} uses // M.A. ZCompatibility; // M.A. {***************** Plain API Constants definition ****************} const { General #define } TIMEOUT_IGNORE = Cardinal(-1); TIMEOUT_INFINITE = 0; TIMEOUT_MAXIMUM = 1200; { 20 minutes maximum timeout value } { Used for ServerType in dbgetprocinfo } SERVTYPE_UNKNOWN = 0; SERVTYPE_MICROSOFT = 1; { Used by dbcolinfo } {enum CI_TYPES } CI_REGULAR = 1; CI_ALTERNATE = 2; CI_CURSOR = 3; { Bulk Copy Definitions (bcp) } DB_IN = 1; { Transfer from client to server } DB_OUT = 2; { Transfer from server to client } BCPMAXERRS = 1; { bcp_control parameter } BCPFIRST = 2; { bcp_control parameter } BCPLAST = 3; { bcp_control parameter } BCPBATCH = 4; { bcp_control parameter } BCPKEEPNULLS = 5; { bcp_control parameter } BCPABORT = 6; { bcp_control parameter } BCPKEEPIDENTITY = 8; { bcp_control parameter } BCPLABELED = 5; { bcp_control parameter } BCPHINTS = 6; { bcp_control parameter } DBCMDNONE = 0; { bcp_control parameter } DBCMDPEND = 1; { bcp_control parameter } DBCMDSENT = 2; { bcp_control parameter } TINYBIND = 1; SMALLBIND = 2; INTBIND = 3; CHARBIND = 4; BINARYBIND = 5; BITBIND = 6; DATETIMEBIND = 7; MONEYBIND = 8; FLT8BIND = 9; STRINGBIND = 10; NTBSTRINGBIND = 11; VARYCHARBIND = 12; VARYBINBIND = 13; FLT4BIND = 14; SMALLMONEYBIND = 15; SMALLDATETIBIND = 16; DECIMALBIND = 17; NUMERICBIND = 18; SRCDECIMALBIND = 19; SRCNUMERICBIND = 20; MAXBIND = SRCNUMERICBIND; DBSAVE = 1; DBNOSAVE = 0; DBNOERR = -1; DBFAIL = 0; DBSUCCEED = 1; DBFINDONE = $04; { Definately done } DBMORE = $10; { Maybe more commands waiting } DBMORE_ROWS = $20; { This command returned rows } MAXNAME = 31; DBTXTSLEN = 8; { Timestamp length } DBTXPLEN = 16; { Text pointer length } { Error code returns } INT_EXIT = 0; INT_CONTINUE = 1; INT_CANCEL = 2; //from FreeTDS sybdb.h: { DBVERSION_xxx are used with dbsetlversion() } DBVERSION_100= 2; // Sybase TDS 5.0 DBVERSION_42 = 3; // This can be used for old Microsoft and Sybase servers DBVERSION_70 = 4; DBVERSION_71 = 5; DBVERSION_72 = 6; DBVERSION_73 = 7; {Zeos dbsetversion placeholders} ZVersion_UNKNOWN = 0; ZVersion_2_0 = 1; { pre 4.0 SQL Server } ZVersion_3_4 = 2; { Microsoft SQL Server (3.0) } ZVersion_4_0 = 3; { 4.0 SQL Server } ZVersion_4_2 = 4; { 4.2 SQL Server } ZVersion_4_6 = 5; { 2.0 OpenServer and 4.6 SQL Server. } ZVersion_4_9_5 = 6; { 4.9.5 (NCR) SQL Server } ZVersion_5_0 = 7; { 5.0 SQL Server } ZVersion_7_0 = 8; { Microsoft SQL Server 7.0 } ZVersion_8_0 = 9; { Microsoft SQL Server 2000 } ZVersion_9_0 = 10; { Microsoft SQL Server 2005 } ZVersion_7_1 = 9; { Microsoft SQL Server 2000 } ZVersion_7_2 = 10; { Microsoft SQL Server 2005 } ZVersion_7_3 = 11; { Microsoft SQL Server 2008 } ZVersionMax = 13; { known count of available versions } ZVersionEmpty = -1; { placeholder for unsuported version } { DB-Library datatypes } const {Zeos DBOption placeholders} { a large list of options, DBTEXTSIZE is needed by sybtcl } Z_PARSEONLY = 0; Z_ESTIMATE = 1; Z_SHOWPLAN = 2; Z_NOEXEC = 3; Z_ARITHIGNORE = 4; Z_NOCOUNT = 5; Z_ARITHABORT = 6; Z_TEXTLIMIT = 7; Z_BROWSE = 8; Z_OFFSET = 9; Z_STAT = 10; Z_ERRLVL = 11; Z_CONFIRM = 12; Z_STORPROCID = 13; Z_BUFFER = 14; Z_NOAUTOFREE = 15; Z_ROWCOUNT = 16; Z_TEXTSIZE = 17; Z_NATLANG = 18; Z_DATEFORMAT = 19; Z_PRPAD = 20; Z_PRCOLSEP = 21; Z_PRLINELEN = 22; Z_PRLINESEP = 23; Z_LFCONVERT = 24; Z_DATEFIRST = 25; Z_CHAINXACTS = 26; Z_FIPSFLAG = 27; Z_ISOLATION = 28; Z_AUTH = 29; Z_IDENTITY = 30; Z_NOIDCOL = 31; Z_DATESHORT = 32; Z_CLIENTCURSORS = 33; Z_SETTIME = 34; Z_QUOTEDIDENT = 35; Z_NUMOPTIONS = 36; Z_PADOFF = 37; Z_PADON = 38; Z_OFF = 39; Z_ON = 40; Z_NOSUCHOPTION = 41; Z_MAXOPTTEXT = 42; Z_ANSITOOEM = 43; Z_OEMTOANSI = 44; { loginrec manipulation Placeholders} Z_SETHOST = 0; Z_SETUSER = 1; Z_SETPWD = 2; Z_SETHID = 3; Z_SETAPP = 4; Z_SETBCP = 5; Z_SETSECURE = 6; Z_SETLANG = 7; Z_SETNOSHORT = 8; Z_SETHIER = 9; Z_SETCHARSET = 10; Z_SETPACKET = 11; Z_SETENCRYPT = 12; Z_SETLABELED = 13; Z_SETDBNAME = 14; Z_SETLOGINTIME = 15; Z_SETFALLBACK = 16; { datatype plazeholders } Z_SQLVOID = 0; Z_SQLTEXT = 1; Z_SQLVARBINARY = 2; Z_SQLINTN = 3; Z_SQLVARCHAR = 4; Z_SQLBINARY = 5; Z_SQLIMAGE = 6; Z_SQLCHAR = 7; Z_SQLINT1 = 8; Z_SQLBIT = 9; Z_SQLINT2 = 10; Z_SQLINT4 = 11; Z_SQLMONEY = 12; Z_SQLDATETIME = 13; Z_SQLFLT8 = 14; Z_SQLFLTN = 15; Z_SQLMONEYN = 16; Z_SQLDATETIMN = 17; Z_SQLFLT4 = 18; Z_SQLMONEY4 = 19; Z_SQLDATETIM4 = 20; Z_SQLDECIMAL = 21; Z_SQLNUMERIC = 22; { DBLib options } const DBLIBDBBUFFER = 0; DBLIBDBOFFSET = 1; DBLIBDBROWCOUNT = 2; DBLIBDBSTAT = 3; DBLIBDBTEXTLIMIT = 4; DBLIBDBTEXTSIZE = 5; DBLIBDBARITHABORT = 6; DBLIBDBARITHIGNORE = 7; DBLIBDBNOAUTOFREE = 8; DBLIBDBNOCOUNT = 9; DBLIBDBNOEXEC = 10; DBLIBDBPARSEONLY = 11; DBLIBDBSHOWPLAN = 12; DBLIBDBSTORPROCID = 13; DBLIBDBANSITOOEM = 14; DBLIBDBOEMTOANSI = 15; DBLIBDBCLIENTCURSORS = 16; DBLIBDBSET_TIME = 17; DBLIBDBQUOTEDIDENT = 18; { FreeTDS options, a large list of options, DBTEXTSIZE is needed by sybtcl } TDSPARSEONLY = 0; TDSESTIMATE = 1; TDSSHOWPLAN = 2; TDSNOEXEC = 3; TDSARITHIGNORE = 4; TDSNOCOUNT = 5; TDSARITHABORT = 6; TDSTEXTLIMIT = 7; TDSBROWSE = 8; TDSOFFSET = 9; TDSSTAT = 10; TDSERRLVL = 11; TDSCONFIRM = 12; TDSSTORPROCID = 13; TDSBUFFER = 14; TDSNOAUTOFREE = 15; TDSROWCOUNT = 16; TDSTEXTSIZE = 17; TDSNATLANG = 18; TDSDATEFORMAT = 19; TDSPRPAD = 20; TDSPRCOLSEP = 21; TDSPRLINELEN = 22; TDSPRLINESEP = 23; TDSLFCONVERT = 24; TDSDATEFIRST = 25; TDSCHAINXACTS = 26; TDSFIPSFLAG = 27; TDSISOLATION = 28; TDSAUTH = 29; TDSIDENTITY = 30; TDSNOIDCOL = 31; TDSDATESHORT = 32; TDSCLIENTCURSORS = 33; TDSSETTIME = 34; TDSQUOTEDIDENT = 35; TDSNUMOPTIONS = 36; TDSPADOFF = 0; TDSPADON = 1; TDSOFF = 0; TDSON = 1; NOSUCHOPTION = 2; MAXOPTTEXT = 32; { common Login manipulations } DBSETHOST = 1; DBSETUSER = 2; DBSETPWD = 3; { Sybase Login manipulations } const SYBDBSETHOST = DBSETHOST; SYBDBSETUSER = DBSETUSER; SYBDBSETPWD = DBSETPWD; SYBDBSETHID = 4; SYBDBSETAPP = 5; SYBDBSETBCP = 6; SYBDBSETLANG = 7; SYBDBSETNOSHORT = 8; SYBDBSETHIER = 9; SYBDBSETCHARSET = 10; SYBDBSETPACKET = 11; SYBDBSETENCRYPT = 12; SYBDBSETLABELED = 13; { MsSQL Login manipulations } const MSDBSETHOST = DBSETHOST; MSDBSETUSER = DBSETUSER; MSDBSETPWD = DBSETPWD; MSDBSETAPP = 4; MSDBSETID = 5; MSDBSETLANG = 6; MSDBSETSECURE = 7; MSDBSET_LOGIN_TIME = 10; MSDBSETFALLBACK = 12; {TDS Loginrec manipulations} TDSDBSETHOST = DBSETHOST; TDSDBSETUSER = DBSETUSER; TDSDBSETPWD = DBSETPWD; TDSDBSETHID = 4; TDSDBSETAPP = 5; TDSDBSETBCP = 6; TDSDBSETSECURE = 6; TDSDBSETLANG = 7; TDSDBSETNOSHORT = 8; TDSDBSETHIER = 9; TDSDBSETCHARSET = 10; TDSDBSETPACKET = 11; TDSDBSETENCRYPT = 12; TDSDBSETLABELED = 13; TDSDBSETDBNAME = 14; { TDS_DBVERSION_xxx are used with dbsetversion() } TDSDBVERSION_UNKNOWN = 0; TDSDBVERSION_46 = 1; TDSDBVERSION_100 = 2; // Sybase TDS 5.0 TDSDBVERSION_42 = 3; // This can be used for old Microsoft and Sybase servers TDSDBVERSION_70 = 4; TDSDBVERSION_71 = 5; TDSDBVERSION_80 = TDSDBVERSION_71; TDSDBVERSION_72 = 6; TDSDBVERSION_73 = 7; { these two are defined by Microsoft for dbsetlversion() } DBVER42 = 8; DBVER60 = 9; (** * DBTDS_xxx are returned by DBTDS() * The integer values of the constants are poorly chosen. *) DBTDS_UNKNOWN = 0; DBTDS_2_0 = 1; { pre 4.0 SQL Server } DBTDS_3_4 = 2; { Microsoft SQL Server (3.0) } DBTDS_4_0 = 3; { 4.0 SQL Server } DBTDS_4_2 = 4; { 4.2 SQL Server } DBTDS_4_6 = 5; { 2.0 OpenServer and 4.6 SQL Server. } DBTDS_4_9_5 = 6; { 4.9.5 (NCR) SQL Server } DBTDS_5_0 = 7; { 5.0 SQL Server } DBTDS_7_0 = 8; { Microsoft SQL Server 7.0 } DBTDS_8_0 = 9; { Microsoft SQL Server 2000 } DBTDS_9_0 = 10; { Microsoft SQL Server 2005 } DBTDS_7_1 = 9; { Microsoft SQL Server 2000 } DBTDS_7_2 = 10; { Microsoft SQL Server 2005 } DBTDS_7_3 = 11; { Microsoft SQL Server 2008 } { Data Type Tokens } DBLIBSQLVOID = $1f; DBLIBSQLTEXT = $23; DBLIBSQLVARBINARY = $25; DBLIBSQLINTN = $26; { all nullable integers } DBLIBSQLVARCHAR = $27; DBLIBSQLBINARY = $2d; DBLIBSQLIMAGE = $22; DBLIBSQLCHAR = $2f; DBLIBSQLINT1 = $30; DBLIBSQLBIT = $32; DBLIBSQLINT2 = $34; DBLIBSQLINT4 = $38; DBLIBSQLMONEY = $3c; DBLIBSQLDATETIME = $3d; DBLIBSQLFLT8 = $3e; DBLIBSQLFLTN = $6d; DBLIBSQLMONEYN = $6e; DBLIBSQLDATETIMN = $6f; DBLIBSQLFLT4 = $3b; DBLIBSQLMONEY4 = $7a; DBLIBSQLDATETIM4 = $3a; DBLIBSQLDECIMAL = $6a; DBLIBSQLNUMERIC = $6c; { Data stream tokens } SQLCOLFMT = $a1; OLD_SQLCOLFMT = $2a; SQLPROCID = $7c; SQLCOLNAME = $a0; SQLTABNAME = $a4; SQLCOLINFO = $a5; SQLALTNAME = $a7; SQLALTFMT = $a8; SQLERROR = $aa; SQLINFO = $ab; SQLRETURNVALUE = $ac; SQLRETURNSTATUS = $79; SQLRETURN = $db; SQLCONTROL = $ae; SQLALTCONTROL = $af; SQLROW = $d1; SQLALTROW = $d3; SQLDONE = $fd; SQLDONEPROC = $fe; SQLDONEINPROC = $ff; SQLOFFSET = $78; SQLORDER = $a9; SQLLOGINACK = $ad; { NOTICE: change to real value } { Ag op tokens } SQLAOPCNT = $4b; SQLAOPSUM = $4d; SQLAOPAVG = $4f; SQLAOPMIN = $51; SQLAOPMAX = $52; SQLAOPANY = $53; SQLAOPNOOP = $56; { Error numbers (dberrs) DB-Library error codes } SQLEMEM = 10000; SQLENULL = 10001; SQLENLOG = 10002; SQLEPWD = 10003; SQLECONN = 10004; SQLEDDNE = 10005; SQLENULLO = 10006; SQLESMSG = 10007; SQLEBTOK = 10008; SQLENSPE = 10009; SQLEREAD = 10010; SQLECNOR = 10011; SQLETSIT = 10012; SQLEPARM = 10013; SQLEAUTN = 10014; SQLECOFL = 10015; SQLERDCN = 10016; SQLEICN = 10017; SQLECLOS = 10018; SQLENTXT = 10019; SQLEDNTI = 10020; SQLETMTD = 10021; SQLEASEC = 10022; SQLENTLL = 10023; SQLETIME = 10024; SQLEWRIT = 10025; SQLEMODE = 10026; SQLEOOB = 10027; SQLEITIM = 10028; SQLEDBPS = 10029; SQLEIOPT = 10030; SQLEASNL = 10031; SQLEASUL = 10032; SQLENPRM = 10033; SQLEDBOP = 10034; SQLENSIP = 10035; SQLECNULL = 10036; SQLESEOF = 10037; SQLERPND = 10038; SQLECSYN = 10039; SQLENONET = 10040; SQLEBTYP = 10041; SQLEABNC = 10042; SQLEABMT = 10043; SQLEABNP = 10044; SQLEBNCR = 10045; SQLEAAMT = 10046; SQLENXID = 10047; SQLEIFNB = 10048; SQLEKBCO = 10049; SQLEBBCI = 10050; SQLEKBCI = 10051; SQLEBCWE = 10052; SQLEBCNN = 10053; SQLEBCOR = 10054; SQLEBCPI = 10055; SQLEBCPN = 10056; SQLEBCPB = 10057; SQLEVDPT = 10058; SQLEBIVI = 10059; SQLEBCBC = 10060; SQLEBCFO = 10061; SQLEBCVH = 10062; SQLEBCUO = 10063; SQLEBUOE = 10064; SQLEBWEF = 10065; SQLEBTMT = 10066; SQLEBEOF = 10067; SQLEBCSI = 10068; SQLEPNUL = 10069; SQLEBSKERR = 10070; SQLEBDIO = 10071; SQLEBCNT = 10072; SQLEMDBP = 10073; SQLINIT = 10074; SQLCRSINV = 10075; SQLCRSCMD = 10076; SQLCRSNOIND = 10077; SQLCRSDIS = 10078; SQLCRSAGR = 10079; SQLCRSORD = 10080; SQLCRSMEM = 10081; SQLCRSBSKEY = 10082; SQLCRSNORES = 10083; SQLCRSVIEW = 10084; SQLCRSBUFR = 10085; SQLCRSFROWN = 10086; SQLCRSBROL = 10087; SQLCRSFRAND = 10088; SQLCRSFLAST = 10089; SQLCRSRO = 10090; SQLCRSTAB = 10091; SQLCRSUPDTAB = 10092; SQLCRSUPDNB = 10093; SQLCRSVIIND = 10094; SQLCRSNOUPD = 10095; SQLCRSOS2 = 10096; SQLEBCSA = 10097; SQLEBCRO = 10098; SQLEBCNE = 10099; SQLEBCSK = 10100; SQLEUVBF = 10101; SQLEBIHC = 10102; SQLEBWFF = 10103; SQLNUMVAL = 10104; SQLEOLDVR = 10105; SQLEBCPS = 10106; SQLEDTC = 10107; SQLENOTIMPL = 10108; SQLENONFLOAT = 10109; SQLECONNFB = 10110; { The severity levels are defined here } EXINFO = 1; { Informational, non-error } EXUSER = 2; { User error } EXNONFATAL = 3; { Non-fatal error } EXCONVERSION = 4; { Error in DB-LIBRARY data conversion } EXSERVER = 5; { The Server has returned an error flag } EXTIME = 6; { We have exceeded our timeout period while } { waiting for a response from the Server - the } { DBPROCESS is still alive } EXPROGRAM = 7; { Coding error in user program } EXRESOURCE = 8; { Running out of resources - the DBPROCESS may be dead } EXCOMM = 9; { Failure in communication with Server - the DBPROCESS is dead } EXFATAL = 10; { Fatal error - the DBPROCESS is dead } EXCONSISTENCY = 11; { Internal software error - notify MS Technical Supprt } { Offset identifiers } OFF_SELECT = $16d; OFF_FROM = $14f; OFF_ORDER = $165; OFF_COMPUTE = $139; OFF_TABLE = $173; OFF_PROCEDURE = $16a; OFF_STATEMENT = $1cb; OFF_PARAM = $1c4; OFF_EXEC = $12c; { Decimal constants } MAXNUMERICLEN = 16; MAXNUMERICDIG = 38; DEFAULTPRECISION = 18; DEFAULTSCALE = 0; { DB-Table constants} { Pack the following structures on a word boundary } TDSMAXTABLENAME = 512; TDSMAXCOLNAMELEN = 512; { DB-Table constants} { Pack the following structures on a word boundary } MAXTABLENAME = 30; MAXCOLNAMELEN= 30; { DB-Library datatype definitions } DBMAXCHAR=256; // Max length of DBVARBINARY and DBVARCHAR, etc. { Print lengths for certain fixed length data types } PRINT4 = 11; PRINT2 = 6; PRINT1 = 3; PRFLT8 = 20; PRMONEY = 26; PRBIT = 3; PRDATETIME = 27; PRDECIMAL = (MAXNUMERICDIG + 2); PRNUMERIC = (MAXNUMERICDIG + 2); SUCCEED = 1; FAIL = 0; SUCCEED_ABORT = 2; DBUNKNOWN = 2; { FALSE = 0, TRUE = 1 } MORE_ROWS = -1; NO_MORE_ROWS = -2; REG_ROW = MORE_ROWS; BUF_FULL = -3; { only if buffering is turned on } { Status code for dbresults(). Possible return values are } { SUCCEED, FAIL, and NO_MORE_RESULTS. } NO_MORE_RESULTS = 2; NO_MORE_RPC_RESULTS = 3; { Standard exit and error values } STDEXIT = 0; ERREXIT = -1; { dbrpcinit flags } DBRPCRECOMPILE = $0001; DBRPCRESET = $0004; DBRPCCURSOR = $0008; { dbrpcparam flags } DBRPCRETURN = $1; DBRPCDEFAULT = $2; { Cursor related constants } { Following flags are used in the concuropt parameter in the dbcursoropen function } CUR_READONLY = 1; { Read only cursor, no data modifications } CUR_LOCKCC = 2; { Intent to update, all fetched data locked when } { dbcursorfetch is called inside a transaction block } CUR_OPTCC = 3; { Optimistic concurrency control, data modifications } { succeed only if the row hasn't been updated since } { the last fetch. } CUR_OPTCCVAL = 4; { Optimistic concurrency control based on selected column values } { Following flags are used in the scrollopt parameter in dbcursoropen } CUR_FORWARD = 0; { Forward only scrolling } CUR_KEYSET = -1; { Keyset driven scrolling } CUR_DYNAMIC = 1; { Fully dynamic } CUR_INSENSITIVE = -2; { Server-side cursors only } { Following flags define the fetchtype in the dbcursorfetch function } FETCH_FIRST = 1; { Fetch first n rows } FETCH_NEXT = 2; { Fetch next n rows } FETCH_PREV = 3; { Fetch previous n rows } FETCH_RANDOM = 4; { Fetch n rows beginning with given row # } FETCH_RELATIVE = 5; { Fetch relative to previous fetch row # } FETCH_LAST = 6; { Fetch the last n rows } { Following flags define the per row status as filled by dbcursorfetch and/or dbcursorfetchex } FTC_EMPTY = $00; { No row available } FTC_SUCCEED = $01; { Fetch succeeded, (failed if not set) } FTC_MISSING = $02; { The row is missing } FTC_ENDOFKEYSET = $04; { End of the keyset reached } FTC_ENDOFRESULTS = $08; { End of results set reached } { Following flags define the operator types for the dbcursor function } CRS_UPDATE = 1; { Update operation } CRS_DELETE = 2; { Delete operation } CRS_INSERT = 3; { Insert operation } CRS_REFRESH = 4; { Refetch given row } CRS_LOCKCC = 5; { Lock given row } { Following value can be passed to the dbcursorbind function for NOBIND type } NOBIND = -2; { Return length and pointer to data } { Following are values used by DBCURSORINFO's Type parameter } CU_CLIENT = $00000001; CU_SERVER = $00000002; CU_KEYSET = $00000004; CU_MIXED = $00000008; CU_DYNAMIC = $00000010; CU_FORWARD = $00000020; CU_INSENSITIVE = $00000040; CU_READONLY = $00000080; CU_LOCKCC = $00000100; CU_OPTCC = $00000200; CU_OPTCCVAL = $00000400; { Following are values used by DBCURSORINFO's Status parameter } CU_FILLING = $00000001; CU_FILLED = $00000002; { Following are values used by dbupdatetext's type parameter } UT_TEXTPTR = $0001; UT_TEXT = $0002; UT_MORETEXT = $0004; UT_DELETEONLY = $0008; UT_LOG = $0010; { The following values are passed to dbserverenum for searching criteria. } NET_SEARCH = $0001; LOC_SEARCH = $0002; { These constants are the possible return values from dbserverenum. } ENUM_SUCCESS = $0000; MORE_DATA = $0001; NET_NOT_AVAIL = $0002; OUT_OF_MEMORY = $0004; NOT_SUPPORTED = $0008; ENUM_INVALID_PARAM = $0010; { Netlib Error problem codes. ConnectionError() should return one of } { these as the dblib-mapped problem code, so the corresponding string } { is sent to the dblib app's error handler as dberrstr. Return NE_E_NOMAP } { for a generic DB-Library error string (as in prior versions of dblib). } NE_E_NOMAP = 0; { No string; uses dblib default. } NE_E_NOMEMORY = 1; { Insufficient memory. } NE_E_NOACCESS = 2; { Access denied. } NE_E_CONNBUSY = 3; { Connection is busy. } NE_E_CONNBROKEN = 4; { Connection broken. } NE_E_TOOMANYCONN = 5; { Connection limit exceeded. } NE_E_SERVERNOTFOUND = 6; { Specified SQL server not found. } NE_E_NETNOTSTARTED = 7; { The network has not been started. } NE_E_NORESOURCE = 8; { Insufficient network resources. } NE_E_NETBUSY = 9; { Network is busy. } NE_E_NONETACCESS = 10; { Network access denied. } NE_E_GENERAL = 11; { General network error. Check your documentation. } NE_E_CONNMODE = 12; { Incorrect connection mode. } NE_E_NAMENOTFOUND = 13; { Name not found in directory service. } NE_E_INVALIDCONN = 14; { Invalid connection. } NE_E_NETDATAERR = 15; { Error reading or writing network data. } NE_E_TOOMANYFILES = 16; { Too many open file handles. } NE_E_CANTCONNECT = 17; { SQL Server does not exist or access denied. } NE_MAX_NETERROR = 17; const MAXSERVERNAME = 30; MAXNETLIBNAME = 255; MAXNETLIBCONNSTR = 255; const INVALID_UROWNUM = Cardinal(-1); { copied from tds.h } //enum SYBCHAR = 47; (* 0x2F *) SYBVARCHAR = 39; (* 0x27 *) SYBINTN = 38; (* 0x26 *) SYBINT1 = 48; (* 0x30 *) SYBINT2 = 52; (* 0x34 *) SYBINT4 = 56; (* 0x38 *) SYBINT8 = 127; (* 0x7F *) SYBFLT8 = 62; (* 0x3E *) SYBDATETIME = 61; (* 0x3D *) SYBBIT = 50; (* 0x32 *) SYBBITN = 104; (* 0x68 *) SYBTEXT = 35; (* 0x23 *) SYBNTEXT = 99; (* 0x63 *) SYBIMAGE = 34; (* 0x22 *) SYBMONEY4 = 122; (* 0x7A *) SYBMONEY = 60; (* 0x3C *) SYBDATETIME4 = 58; (* 0x3A *) SYBREAL = 59; (* 0x3B *) SYBBINARY = 45; (* 0x2D *) SYBVOID = 31; (* 0x1F *) SYBVARBINARY = 37; (* 0x25 *) SYBNUMERIC = 108; (* 0x6C *) SYBDECIMAL = 106; (* 0x6A *) SYBFLTN = 109; (* 0x6D *) SYBMONEYN = 110; (* 0x6E *) SYBDATETIMN = 111; (* 0x6F *) SYBNVARCHAR = 103; (* 0x67 *) XSYBCHAR = 175; (* 0xAF *) XSYBVARCHAR = 167; (* 0xA7 *) XSYBNVARCHAR = 231; (* 0xE7 *) XSYBNCHAR = 239; (* 0xEF *) XSYBVARBINARY = 165; (* 0xA5 *) XSYBBINARY = 173; (* 0xAD *) SYBUNIQUE = 36; (* 0x24 *) SYBVARIANT = 98; (* 0x62 *) SYBMSUDT = 240; (* 0xF0 *) SYBMSXML = 241; (* 0xF1 *) { FreeTDS Data Type Tokens } TDSSQLVOID = SYBVOID; TDSSQLTEXT = SYBTEXT; TDSSQLVARBINARY = SYBVARBINARY; TDSSQLINTN = SYBINTN; TDSSQLVARCHAR = SYBVARCHAR; TDSSQLBINARY = SYBBINARY; TDSSQLIMAGE = SYBIMAGE; TDSSQLCHAR = SYBCHAR; TDSSQLINT1 = SYBINT1; TDSSQLBIT = SYBBIT; TDSSQLINT2 = SYBINT2; TDSSQLINT4 = SYBINT4; TDSSQLMONEY = SYBMONEY; TDSSQLDATETIME = SYBDATETIME; TDSSQLFLT8 = SYBFLT8; TDSSQLFLTN = SYBFLTN; TDSSQLMONEYN = SYBMONEYN; TDSSQLDATETIMN = SYBDATETIMN; TDSSQLFLT4 = SYBREAL; TDSSQLMONEY4 = SYBMONEY4; TDSSQLDATETIM4 = SYBDATETIME4; TDSSQLDECIMAL = SYBDECIMAL; TDSSQLNUMERIC = SYBNUMERIC; SYBAOPCNT = $4b; SYBAOPCNTU = $4c; SYBAOPSUM = $4d; SYBAOPSUMU = $4e; SYBAOPAVG = $4f; SYBAOPAVGU = $50; SYBAOPMIN = $51; SYBAOPMAX = $52; { mssql2k compute operator } SYBAOPCNT_BIG = $09; SYBAOPSTDEV = $30; SYBAOPSTDEVP = $31; SYBAOPVAR = $32; SYBAOPVARP = $33; SYBAOPCHECKSUM_AGG = $72; {****************** Plain API Types definition *****************} type { DBPROCESS, LOGINREC and DBCURSOR } PDBPROCESS = Pointer; PLOGINREC = Pointer; PDBCURSOR = Pointer; PDBHANDLE = Pointer; DBXLATE = Pointer; DBSORTORDER = Pointer; DBLOGINFO = Pointer; DBVOIDPTR = PPointer; type { DB-Library datatypes } DBBOOL = Byte; DBCHAR = AnsiChar; DBBIT = Byte; DBTINYINT = Byte; DBSMALLINT = SmallInt; { int16_type } DBINT = LongInt; { int32_type } DBBIGINT = Int64; { int64_type } DBBINARY = Byte; DBFLT4 = Single; { real32_type } DBFLT8 = Double; { real64_type } DBSHORT = SmallInt; DBUSMALLINT = Word; DBMONEY4 = LongInt; PDBMONEY4 = ^DBMONEY4; RETCODE = Integer; PRETCODE = ^RETCODE; STATUS = Integer; //typedef int (*INTFUNCPTR) (void *, ...); //typedef int (*DBWAITFUNC) (void); //typedef DBWAITFUNC(*DB_DBBUSY_FUNC) (void *dbproc); //typedef void (*DB_DBIDLE_FUNC) (DBWAITFUNC dfunc, void *dbproc); //typedef int (*DB_DBCHKINTR_FUNC) (void *dbproc); //typedef int (*DB_DBHNDLINTR_FUNC) (void *dbproc); *) DBREAL = DBFLT4; DBUBOOL = Cardinal; DBDATETIM4 = packed record numdays: Word; { No of days since Jan-1-1900 } nummins: Word; { No. of minutes since midnight } end; PDBDATETIM4 = ^DBDATETIM4; {$IFDEF FPC} {$PACKRECORDS C} {$ENDIF} type DBNUMERIC = packed record Precision: Byte; Scale: Byte; Sign: Byte; { 1 = Positive, 0 = Negative } Val: array[0..MAXNUMERICLEN-1] of Byte; end; DBDECIMAL = DBNUMERIC; TDSDBNUMERIC = packed record Precision: Byte; Scale: Byte; Sign: Byte; { 1 = Positive, 0 = Negative } Val: array[0..MAXNUMERICLEN] of Byte; end; TDSDBDECIMAL = TDSDBNUMERIC; DBVARYCHAR = packed record Len: DBSMALLINT; Str: array[0..DBMAXCHAR-1] of DBCHAR; end; DBVARYBIN = packed record Len: DBSMALLINT; Bytes: array[0..DBMAXCHAR-1] of Byte; end; DBMONEY = packed record mnyhigh: DBINT; mnylow: LongWord; end; PDBMONEY = ^DBMONEY; PDBDATETIME = ^DBDATETIME; DBDATETIME = packed record dtdays: DBINT; // Days since Jan 1, 1900 dttime: LongWord; // 300ths of a second since midnight, 25920000 unit is 1 day end; PTDSDBDATETIME = ^TTDSDBDATETIME; TTDSDBDATETIME = packed record dtdays: DBINT; // Days since Jan 1, 1900 dttime: DBINT; // 300ths of a second since midnight, 25920000 unit is 1 day end; (* * Sybase & Microsoft use different names for the dbdaterec members. * Keep these two structures physically identical in memory. * dbdatecrack() casts one to the other for ease of implementation. * * Giving credit where credit is due, we can acknowledge that * Microsoft chose the better names here, hands down. ("datedmonth"?!) *) { FreeTDS sybdb.h } PTDS_DBDATEREC = ^Ttds_dbdaterec; Ttds_dbdaterec = packed record { fields } {microsoft} {sybase} year: DBINT; { 1753 - 9999 } { 1900 and counting } quarter: DBINT; { 1 - 4 } { 0 - 3 (Microsoft only) } month: DBINT; { 1 - 12 } { 0 - 11 } dayofmonth: DBINT; { 1 - 31 } { 1 - 31 } dayofyear: DBINT; { 1 - 366 } { 1 - 366 (in Sybase.sybdb.h dayofyear and day are changed around!) } week: DBINT; { 1 - 54 (for leap years) } { 1 - 54 (Microsoft only) } weekday: DBINT; { 1 - 7 (Mon - Sun) } { 0 - 6 (Mon - Sun) } hour: DBINT; { 0 - 23 } { 0 - 23 } minute: DBINT; { 0 - 59 } { 0 - 59 } second: DBINT; { 0 - 59 } { 0 - 59 } millisecond: DBINT; { 0 - 999 } { 0 - 997 } tzone: DBINT; { 0 - 127 (Sybase only!) } { 0 - 127 } end; { DBDATEREC structure used by dbdatecrack } DBDATEREC = packed record year: DBINT; { 1753 - 9999 } quarter: DBINT; { 1 - 4 } month: DBINT; { 1 - 12 } dayofyear: DBINT; { 1 - 366 } day: DBINT; { 1 - 31 } week: DBINT; { 1 - 54 (for leap years) } weekday: DBINT; { 1 - 7 (Mon - Sun) } hour: DBINT; { 0 - 23 } minute: DBINT; { 0 - 59 } second: DBINT; { 0 - 59 } millisecond: DBINT; { 0 - 999 } end; PDBDATEREC = ^DBDATEREC; type { TODO -ofjanos -cAPI : Strange but I had to insert X1 and X2 into the structure to make it work. I have not find any reason for this yet. } {$IFDEF FPC} {$PACKRECORDS 2} {$ENDIF} DBCOL = record SizeOfStruct: DBINT; Name: array[0..MAXCOLNAMELEN] of char; ActualName: array[0..MAXCOLNAMELEN] of char; TableName: array[0..MAXTABLENAME] of char; {$IFNDEF FPC} X1: Byte; //Record-Size diffs with C-Records {$ENDIF} Typ: DBSHORT; UserType: DBINT; MaxLength: DBINT; Precision: BYTE; Scale: BYTE; VarLength: LongBool; { TRUE, FALSE } Null: BYTE; { TRUE, FALSE or DBUNKNOWN } CaseSensitive: BYTE; { TRUE, FALSE or DBUNKNOWN } Updatable: BYTE; { TRUE, FALSE or DBUNKNOWN } Identity: LongBool; { TRUE, FALSE or DBUNKNOWN } {$IFNDEF FPC} X2: Byte; //Record-Size diffs with C-Records {$ENDIF} end; {$IFDEF FPC} {$PACKRECORDS DEFAULT} {$ENDIF} PDBCOL = ^DBCOL; PTDSDBCOL = ^TTDSDBCOL; TTDSDBCOL = packed record SizeOfStruct: DBINT; Name: array[0..TDSMAXCOLNAMELEN+2] of AnsiChar; ActualName: array[0..TDSMAXCOLNAMELEN+2] of AnsiChar; TableName: array[0..TDSMAXTABLENAME+2] of AnsiChar; Typ: SmallInt; UserType: DBINT; MaxLength: DBINT; Precision: Byte; Scale: Byte; VarLength: LongBool;{ TRUE, FALSE } Null: Byte; { TRUE, FALSE or DBUNKNOWN } CaseSensitive: Byte; { TRUE, FALSE or DBUNKNOWN } Updatable: Byte; { TRUE, FALSE or DBUNKNOWN } Identity: LongBool;{ TRUE, FALSE } end; type DBTYPEINFO = packed record Precision: DBINT; Scale: DBINT; end; PDBTYPEINFO = ^DBTYPEINFO; DBPROC_INFO = packed record SizeOfStruct: DBINT; ServerType: Byte; ServerMajor: Word; ServerMinor: Word; ServerRevision: Word; ServerName: array[0..MAXSERVERNAME] of AnsiChar; NetLibName: array[0..MAXNETLIBNAME] of AnsiChar; NetLibConnStr: array[0..MAXNETLIBCONNSTR] of AnsiChar; end; PDBPROCINFO = ^DBPROC_INFO; DBCURSOR_INFO = packed record SizeOfStruct: DBINT; { Use sizeof(DBCURSORINFO) } TotCols: Cardinal; { Total Columns in cursor } TotRows: Cardinal; { Total Rows in cursor } CurRow: Cardinal; { Current actual row in server } TotRowsFetched: Cardinal; { Total rows actually fetched } CurType: Cardinal; { See CU_... } Status: Cardinal; { See CU_... } end; PDBCURSORINFO = ^DBCURSOR_INFO; type { Pointer Datatypes } PDBINT = ^DBINT; PDBBINARY = ^DBBINARY; type PDBLibError = ^TDBLibError; TDBLibError = record dbProc: PDBPROCESS; Severity: DBINT; DbErr: DBINT; OsErr: DBINT; DbErrStr: AnsiString; OsErrStr: AnsiString; end; PDBLibMessage = ^TDBLibMessage; TDBLibMessage = record dbProc: PDBPROCESS; MsgNo: DBINT; MsgState: DBINT; Severity: DBINT; MsgText: AnsiString; SrvName: AnsiString; ProcName: AnsiString; Line: DBUSMALLINT; end; type TDBVariables = record dboptions: array[0..44] of ShortInt; dbSetLoginRec: array[0..16] of ShortInt; datatypes: array[0..22] of Integer; End; {common FreeTDS(dblib.dll) and ntwdblib.dll definitions requirements: the sam call convention } DBERRHANDLE_PROC = function(Proc: PDBPROCESS; Severity, DbErr, OsErr: Integer; DbErrStr, OsErrStr: PAnsiChar): Integer; cdecl; DBMSGHANDLE_PROC = function(Proc: PDBPROCESS; MsgNo: DBINT; MsgState, Severity: Integer; MsgText, SrvName, ProcName: PAnsiChar; Line: DBUSMALLINT): Integer; cdecl; Tdberrhandle = function(Handler: DBERRHANDLE_PROC): DBERRHANDLE_PROC; cdecl; Tdbmsghandle = function(Handler: DBMSGHANDLE_PROC): DBMSGHANDLE_PROC; cdecl; Tdbprocerrhandle = function(DbHandle: PDBHANDLE; Handler: DBERRHANDLE_PROC): DBERRHANDLE_PROC; cdecl; Tdbprocmsghandle = function(DbHandle: PDBHANDLE; Handler: DBMSGHANDLE_PROC): DBMSGHANDLE_PROC; cdecl; Tdbadata = function(Proc: PDBPROCESS; ComputeId, Column: Integer): PByte; cdecl; Tdbadlen = function(Proc: PDBPROCESS; ComputeId, Column: Integer): DBINT; cdecl; Tdbaltbind = function(Proc: PDBPROCESS; ComputeId, Column, VarType: Integer; VarLen: DBINT; VarAddr: PByte): RETCODE; cdecl; Tdbaltcolid = function(Proc: PDBPROCESS; ComputeId, Column: Integer): Integer; cdecl; Tdbaltlen = function(Proc: PDBPROCESS; ComputeId, Column: Integer): DBINT; cdecl; Tdbaltop = function(Proc: PDBPROCESS; ComputeId, Column: Integer): Integer; cdecl; Tdbalttype = function(Proc: PDBPROCESS; ComputeId, Column: Integer): Integer; cdecl; Tdbaltutype = function(Proc: PDBPROCESS; ComputeId, Column: Integer): DBINT; cdecl; Tdbanullbind = function(Proc: PDBPROCESS; ComputeId, Column: Integer; Indicator: PDBINT): RETCODE; cdecl; Tdbbind = function(Proc: PDBPROCESS; Column, VarType, VarLen: Integer; VarAddr: PByte): RETCODE; cdecl; Tdbbylist = function(Proc: PDBPROCESS; ComputeId: Integer; Size: PInteger): PByte; cdecl; Tdbcancel = function(Proc: PDBPROCESS): RETCODE; cdecl; Tdbcanquery = function(Proc: PDBPROCESS): RETCODE; cdecl; Tdbchange = function(Proc: PDBPROCESS): PAnsiChar; cdecl; Tdbclrbuf = procedure(Proc: PDBPROCESS; N: DBINT); cdecl; Tdbclropt = function(Proc: PDBPROCESS; Option: Integer; Param: PAnsiChar): RETCODE; cdecl; Tdbcmd = function(Proc: PDBPROCESS; Cmd: PAnsiChar): RETCODE; cdecl; Tdbcmdrow = function(Proc: PDBPROCESS): RETCODE; cdecl; Tdbcollen = function(Proc: PDBPROCESS; Column: Integer): DBINT; cdecl; Tdbcolname = function(Proc: PDBPROCESS; Column: Integer): PAnsiChar; cdecl; Tdbcolsource = function(Proc: PDBPROCESS; Column: Integer): PAnsiChar; cdecl; Tdbcoltype = function(Proc: PDBPROCESS; Column: Integer): Integer; cdecl; Tdbcolutype = function(Proc: PDBPROCESS; Column: Integer): DBINT; cdecl; Tdbconvert = function(Proc: PDBPROCESS; SrcType: Integer; Src: PByte; SrcLen: DBINT; DestType: Integer; Dest: PByte; DestLen: DBINT): Integer; cdecl; Tdbiscount = function(Proc: PDBPROCESS): LongBool; cdecl; Tdbcurcmd = function(Proc: PDBPROCESS): Integer; cdecl; Tdbcurrow = function(Proc: PDBPROCESS): DBINT; cdecl; Tdbdata = function(Proc: PDBPROCESS; Column: Integer): PByte; cdecl; Tdbcursor = function(hCursor: PDBCURSOR; OpType, Row: DBINT; Table, Values: PAnsiChar): RETCODE; cdecl; Tdbexit = procedure; cdecl; Tdbfcmd = function(Proc: PDBPROCESS; CmdString: PAnsiChar; var Params): RETCODE; cdecl; Tdbfirstrow = function(Proc: PDBPROCESS): DBINT; cdecl; Tdbfreebuf = procedure(Proc: PDBPROCESS); cdecl; Tdbfreequal = procedure(Ptr: PAnsiChar); cdecl; Tdbgetchar = function(Proc: PDBPROCESS; N: Integer): PAnsiChar; cdecl; Tdbgetoff = function(Proc: PDBPROCESS; OffType: DBUSMALLINT; StartFrom: Integer): Integer; cdecl; Tdbgetrow = function(Proc: PDBPROCESS; Row: DBINT): STATUS; cdecl; Tdbgettime = function: Integer; cdecl; Tdblastrow = function(Proc: PDBPROCESS): DBINT; cdecl; Tdblogin = function: PLOGINREC; cdecl; Tdbmorecmds = function(Proc: PDBPROCESS): RETCODE; cdecl; Tdbmoretext = function(Proc: PDBPROCESS; Size: DBINT; Text: PByte): RETCODE; cdecl; Tdbname = function(Proc: PDBPROCESS): PAnsiChar; cdecl; Tdbnextrow = function(Proc: PDBPROCESS): STATUS; cdecl; Tdbnullbind = function(Proc: PDBPROCESS; Column: Integer; Indicator: PDBINT): RETCODE; cdecl; Tdbnumalts = function(Proc: PDBPROCESS; ComputeId: Integer): Integer; cdecl; Tdbnumcols = function(Proc: PDBPROCESS): Integer; cdecl; Tdbnumcompute = function(Proc: PDBPROCESS): Integer; cdecl; Tdbnumorders = function(Proc: PDBPROCESS): Integer; cdecl; Tdbnumrets = function(Proc: PDBPROCESS): Integer; cdecl; Tdbopen = function(Login: PLOGINREC; Host: PAnsiChar): PDBPROCESS; cdecl; Tdbprhead = procedure(Proc: PDBPROCESS); cdecl; Tdbprrow = function(Proc: PDBPROCESS): RETCODE; cdecl; Tdbprtype = function(Token: Integer): PAnsiChar; cdecl; Tdbqual = function(Proc: PDBPROCESS; TabNum: Integer; TabName: PAnsiChar): PAnsiChar; cdecl; Tdbordercol = function(Proc: PDBPROCESS; Order: Integer): Integer; cdecl; Tdbreadtext = function(dbproc: PDBPROCESS; Buf: Pointer; BufSize: DBINT): DBINT; cdecl; Tdbresults = function(dbproc: PDBPROCESS): RETCODE; cdecl; Tdbretdata = function(dbproc: PDBPROCESS; RetNum: Integer): PByte; cdecl; Tdbretlen = function(dbproc: PDBPROCESS; RetNum: Integer): DBINT; cdecl; Tdbretname = function(Proc: PDBPROCESS; RetNum: Integer): PAnsiChar; cdecl; Tdbretstatus = function(Proc: PDBPROCESS): DBINT; cdecl; Tdbrettype = function(Proc: PDBPROCESS; RetNum: Integer): Integer; cdecl; Tdbrows = function(Proc: PDBPROCESS): RETCODE; cdecl; //!!! Tdbrowtype = function(Proc: PDBPROCESS): STATUS; cdecl; Tdbrpcinit = function(Proc: PDBPROCESS; ProcName: PAnsiChar; Options: DBSMALLINT): RETCODE; cdecl; //!!! Tdbrpcparam = function(Proc: PDBPROCESS; ParamName: PAnsiChar; Status: Byte; Typ: Integer; MaxLen, DataLen: DBINT; Value: PByte): RETCODE; cdecl; Tdbrpcsend = function(Proc: PDBPROCESS): RETCODE; cdecl; Tdbrpwclr = procedure(Login: PLOGINREC); cdecl; Tdbsetavail = procedure(Proc: PDBPROCESS); cdecl; Tdbsetlogintime = function(Seconds: Integer): RETCODE; cdecl; Tdbsetnull = function(Proc: PDBPROCESS; BindType, BindLen: Integer; BindVal: PByte): RETCODE; cdecl; Tdbsettime = function(Seconds: Integer): RETCODE; cdecl; Tdbsetuserdata = procedure(Proc: PDBPROCESS; Ptr: Pointer); cdecl; Tdbsqlexec = function(Proc: PDBPROCESS): RETCODE; cdecl; Tdbsqlok = function(Proc: PDBPROCESS): RETCODE; cdecl; Tdbsqlsend = function(Proc: PDBPROCESS): RETCODE; cdecl; Tdbstrcpy = function(Proc: PDBPROCESS; Start, NumBytes: Integer; Dest: PAnsiChar): RETCODE; cdecl; Tdbstrlen = function(Proc: PDBPROCESS): Integer; cdecl; Tdbtabcount = function(Proc: PDBPROCESS): Integer; cdecl; Tdbtabname = function(Proc: PDBPROCESS; Table: Integer): PAnsiChar; cdecl; Tdbtabsource = function(Proc: PDBPROCESS; Column: Integer; TabNum: PInteger): PAnsiChar; cdecl; Tdbtsnewlen = function(Proc: PDBPROCESS): Integer; cdecl; Tdbtsnewval = function(Proc: PDBPROCESS): PDBBINARY; cdecl; Tdbtsput = function(Proc: PDBPROCESS; NewTs: PDBBINARY; NewTsLen, TabNum: Integer; TableName: PAnsiChar): RETCODE; cdecl; Tdbtxptr = function(Proc: PDBPROCESS; Column: Integer): PDBBINARY; cdecl; Tdbtxtimestamp = function(Proc: PDBPROCESS; Column: Integer): PDBBINARY; cdecl; Tdbtxtsnewval = function(Proc: PDBPROCESS): PDBBINARY; cdecl; Tdbtxtsput = function(Proc: PDBPROCESS; NewTxts: PDBBINARY; Column: Integer): RETCODE; cdecl; Tdbuse = function(Proc: PDBPROCESS; DbName: PAnsiChar): RETCODE; cdecl; Tdbwritetext = function(Proc: PDBPROCESS; ObjName: PAnsiChar; TextPtr: PDBBINARY; TextPtrLen: DBTINYINT; Timestamp: PDBBINARY; Log: LongBool; Size: DBINT; Text: PByte): RETCODE; cdecl; (* LOGINREC manipulation *) Tdbsetlname = function(Login: PLOGINREC; Value: PAnsiChar; Item: Integer): RETCODE; cdecl; { BCP functions } Tbcp_batch = function(Proc: PDBPROCESS): DBINT; cdecl; Tbcp_bind = function(Proc: PDBPROCESS; VarAddr: PByte; PrefixLen: Integer; VarLen: DBINT; Terminator: PByte; TermLen, Typ, TableColumn: Integer): RETCODE; cdecl; Tbcp_colfmt = function(Proc: PDBPROCESS; FileColumn: Integer; FileType: Byte; FilePrefixLen: Integer; FileColLen: DBINT; FileTerm: PByte; FileTermLen, TableColumn: Integer): RETCODE; cdecl; Tbcp_collen = function(Proc: PDBPROCESS; VarLen: DBINT; TableColumn: Integer): RETCODE; cdecl; Tbcp_colptr = function(Proc: PDBPROCESS; ColPtr: PByte; TableColumn: Integer): RETCODE; cdecl; Tbcp_columns = function(Proc: PDBPROCESS; FileColCount: Integer): RETCODE; cdecl; Tbcp_control = function(Proc: PDBPROCESS; Field: Integer; Value: DBINT): RETCODE; cdecl; Tbcp_done = function(Proc: PDBPROCESS): DBINT; cdecl; Tbcp_exec = function(Proc: PDBPROCESS; RowsCopied: PDBINT): RETCODE; cdecl; Tbcp_init = function(Proc: PDBPROCESS; TableName, hFile, ErrFile: PAnsiChar; Direction: Integer): RETCODE; cdecl; Tbcp_moretext = function(Proc: PDBPROCESS; Size: DBINT; Text: PByte): RETCODE; cdecl; Tbcp_readfmt = function(Proc: PDBPROCESS; FileName: PAnsiChar): RETCODE; cdecl; Tbcp_sendrow = function(Proc: PDBPROCESS): RETCODE; cdecl; Tbcp_setl = function(Login: PLOGINREC; Enable: LongBool): RETCODE; cdecl; Tbcp_writefmt = function(Proc: PDBPROCESS; FileName: PAnsiChar): RETCODE; cdecl; { Two-phase commit functions } Tabort_xact = function(Proc: PDBPROCESS; CommId: DBINT): RETCODE; cdecl; Tbuild_xact_string = procedure(XActName, Service: PAnsiChar; CommId: DBINT; Result: PAnsiChar); cdecl; Tclose_commit = procedure(Proc: PDBPROCESS); cdecl; Tcommit_xact = function(Proc: PDBPROCESS; CommId: DBINT): RETCODE; cdecl; Topen_commit = function(Login: PLOGINREC; ServerName: PAnsiChar): PDBPROCESS; cdecl; Tremove_xact = function(Proc: PDBPROCESS; CommId: DBINT; SiteCount: Integer): RETCODE; cdecl; Tscan_xact = function(Proc: PDBPROCESS; CommId: DBINT): RETCODE; cdecl; Tstart_xact = function(Proc: PDBPROCESS; AppName, XActName: PAnsiChar; SiteCount: Integer): DBINT; cdecl; Tstat_xact = function(Proc: PDBPROCESS; CommId: DBINT): Integer; cdecl; {FreeTDS spezial API definitions} TFreeTDSdb12hour = function(Proc: PDBPROCESS; Language: PAnsiChar): DBBOOL; cdecl; TFreeTDSdbcolbrowse = function(Proc: PDBPROCESS; Column: Integer): DBBOOL; cdecl; TFreeTDSdbcursorbind = function(hCursor: PDBCURSOR; Col, VarType: Integer; VarLen, POutLen: DBINT; VarAddr: PByte; DBTYPEINFO: PDBTYPEINFO): RETCODE; cdecl; TFreeTDSdbcursorclose = procedure(DbHandle: PDBHANDLE); cdecl; TFreeTDSdbcursorcolinfo = function(hCursor: PDBCURSOR; Column: DBINT; ColName: PAnsiChar; ColType, ColLen, UserType: PDBINT): RETCODE; cdecl; TFreeTDSdbcursorfetch = function(hCursor: PDBCURSOR; FetchType, RowNum: DBINT): RETCODE; cdecl; TFreeTDSdbcursorinfo = function(hCursor: PDBCURSOR; nCols, nRows: PDBINT): RETCODE; cdecl; TFreeTDSdbcursoropen = function(Proc: PDBPROCESS; Sql: PAnsiChar; ScrollOpt, ConCurOpt: DBSHORT; nRows: DBUSMALLINT; PStatus: PDBINT): PDBCURSOR; cdecl; TFreeTDSdbaltbind_ps = function(dbproc: PDBPROCESS; ComputeId, Column: Integer; VarType: Integer; VarLen: DBINT; VarAddr: PByte; typinfo: PDBTYPEINFO): RETCODE; TFreeTDSdbbind_ps = function(dbproc: PDBPROCESS; Column, VarType, VarLen: Integer; VarAddr: PByte; typinfo: PDBTYPEINFO): RETCODE; cdecl; TFreeTDSdbbufsize = function(dbproc: PDBPROCESS): Integer; cdecl; TFreeTDSdbclose = procedure(dbproc: PDBPROCESS); cdecl; TFreeTDSdbtablecolinfo = function(dbproc: PDBPROCESS; Column: DBINT; DbColumn: PTDSDBCOL): RETCODE; TFreeTDSdbcolinfo = function(Handle: PDBHANDLE; Typ, Column, ComputeId: Integer; DbColumn: PTDSDBCOL): RETCODE; cdecl; TFreeTDSdbconvert_ps = function(dbproc: PDBPROCESS; SrcType: Integer; Src: PByte; SrcLen: DBINT; DestType: Integer; Dest: PByte; DestLen: DBINT; typinfo: PDBTYPEINFO): Integer; cdecl; TFreeTDSdbcount = function(dbproc: PDBPROCESS): DBINT; cdecl; TFreeTDSdbdatecmp = function(dbproc: PDBPROCESS; d1, d2: PTDS_DBDATEREC): Integer; TFreeTDSdbdatecrack = function(dbproc: PDBPROCESS; DateInfo: PTDS_DBDATEREC; DateType: PTDSDBDATETIME): RETCODE; cdecl; TFreeTDSdbdatlen = function(dbproc: PDBPROCESS; Column: Integer): DBINT; cdecl; TFreeTDSdbdead = function(dbproc: PDBPROCESS): DBBOOL; cdecl; TFreeTDSdbgetcharset = function(dbproc: PDBPROCESS): PAnsiChar; TFreeTDSdbgetlusername = function(login: PLOGINREC; name_buffer: PByte; buffer_len: Integer): Integer; cdecl; TFreeTDSdbgetmaxprocs = function: Integer; cdecl; TFreeTDSdbgetnatlanf = function(dbproc: PDBPROCESS): PAnsiChar; cdecl; TFreeTDSdbgetpacket = function(dbproc: PDBPROCESS): Integer; cdecl; TFreeTDSdbgetuserdata = function(dbproc: PDBPROCESS): PByte; cdecl; TFreeTDSdbhasretstat = function(dbproc: PDBPROCESS): DBBOOL; cdecl; TFreeTDSdbinit = function:RETCODE; cdecl; TFreeTDSdbiordesc = function(dbproc: PDBPROCESS): Integer; cdecl; TFreeTDSdbiowdesc = function(dbproc: PDBPROCESS): Integer; cdecl; TFreeTDSdbisavail = function(Proc: PDBPROCESS): DBBOOL; cdecl; TFreeTDSdbisopt = function(Proc: PDBPROCESS; Option: Integer; const Param: PAnsiChar): DBBOOL; cdecl; TFreeTDSdbloginfree = procedure(Login: PLOGINREC); cdecl; TFreeTDSdbmny4cmp = function(dbproc: PDBPROCESS; m1, m: PDBMONEY4): Integer; cdecl; TFreeTDSdbmnycmp = function(dbproc: PDBPROCESS; m1, m2: PDBMONEY): Integer; cdecl; TFreeTDSdbmny4add = function(dbproc: PDBPROCESS; m1, m2, sum: PDBMONEY4): RETCODE; cdecl; TFreeTDSdbmnydec = function(dbproc: PDBPROCESS; mnyptr: PDBMONEY): RETCODE; cdecl; TFreeTDSdbmnyinc = function(dbproc: PDBPROCESS; mnyptr: PDBMONEY): RETCODE; cdecl; TFreeTDSdbmnymaxpos = function(dbproc: PDBPROCESS; dest: PDBMONEY): RETCODE; cdecl; TFreeTDSdbmnymaxneg = function(dbproc: PDBPROCESS; dest: PDBMONEY): RETCODE; cdecl; TFreeTDSdbmny4minus = function(dbproc: PDBPROCESS; src, dest: PDBMONEY): RETCODE; cdecl; TFreeTDSdbmnyminus = function(dbproc: PDBPROCESS; src, dest: PDBMONEY): RETCODE; cdecl; TFreeTDSdbmny4sub = function(dbproc: PDBPROCESS; m1, m2, diff: PDBMONEY4): RETCODE; cdecl; TFreeTDSdbmnysub = function(dbproc: PDBPROCESS; m1, m2, diff: PDBMONEY): RETCODE; cdecl; TFreeTDSdbmny4copy = function(dbproc: PDBPROCESS; m1, m2: PDBMONEY4): RETCODE; cdecl; TFreeTDSdbmnycopy = function(dbproc: PDBPROCESS; src, dest: PDBMONEY): RETCODE; cdecl; TFreeTDSdbmny4zero = function(dbproc: PDBPROCESS; dest: PDBMONEY4): RETCODE; cdecl; TFreeTDSdbmnyzero = function(dbproc: PDBPROCESS; dest: PDBMONEY4): RETCODE; cdecl; TFreeTDSdbmonthname = function(dbproc: PDBPROCESS; language: PAnsiChar; monthnum: Integer; shortform: DBBOOL): PAnsiChar; cdecl; TFreeTDSdbopen = function(Login: PLOGINREC; const Server: PAnsiChar; msdblib: Integer): PDBPROCESS; cdecl; TFreeTDSdbrecftos = procedure(const FileName: PAnsiChar); TDRBUF = function(dbproc: PDBPROCESS): DBBOOL; cdecl; TFreeTDSdbresults_r = function(dbproc: PDBPROCESS; Recursive: Integer): RETCODE; cdecl; TFreeTDSdbsafestr = function(dbproc: PDBPROCESS; const Src: PAnsiChar; SrcLen: DBINT; Dest: PAnsiChar; DestLen: DBINT; QuoteType: integer): RETCODE; cdecl; TFreeTDSdbservcharset = function(dbproc: PDBPROCESS): PAnsiChar; cdecl; TFreeTDSdbsetdefcharset = function(Charset: PAnsiChar): RETCODE; cdecl; TFreeTDSdbsetifile = procedure(FileName: PAnsiChar); cdecl; TFreeTDSdbsetmaxprocs = function(MaxProcs: Integer): RETCODE; cdecl; TFreeTDSdbsetopt = function(dbproc: PDBPROCESS; Option: DBINT; Param: PAnsiChar; int_param: DBINT): RETCODE; cdecl; TFreeTDSdbsetrow = function(dbproc: PDBPROCESS; Row: DBINT): STATUS; cdecl; TFreeTDSdbsetversion = function(Version: DBINT): RETCODE; cdecl; TFreeTDSdbspid = function(dbproc: PDBPROCESS): Integer; cdecl; TFreeTDSdbspr1row = function(dbproc: PDBPROCESS; Buffer: PAnsiChar; buf_len: DBINT): RETCODE; cdecl; TFreeTDSdbspr1rowlen = function(dbproc: PDBPROCESS): DBINT; cdecl; TFreeTDSdbsprhead = function(dbproc: PDBPROCESS; Buffer: PAnsiChar; buf_len: DBINT): RETCODE; cdecl; TFreeTDSdbsprline = function(dbproc: PDBPROCESS; Buffer: PAnsiChar; buf_len: DBINT; line_char: DBCHAR): RETCODE; cdecl; TFreeTDSdbvarylen = function(dbproc: PDBPROCESS; Column: Integer): DBINT; cdecl; TFreeTDSdbtds = function(dbproc: PDBPROCESS): DBINT; cdecl; TFreeTDSdbtextsize = function(dbproc: PDBPROCESS): DBINT; cdecl; TFreeTDSdbwillconvert = function(SrcType, DestType: Integer): DBBOOL; cdecl; TFreeTDSdbtabbrowse = function(Proc: PDBPROCESS; TabNum: Integer): LongBool; cdecl; (* LOGINREC manipulation *) TFreeTDSdbsetlbool = function(Login: PLOGINREC; Value, Item: Integer): RETCODE; cdecl; TFreeTDSdbsetllong = function(Login: PLOGINREC; Value, Item: Integer): RETCODE; cdecl; TFreeTDSdbsetlversion = function(Login: PLOGINREC; Version: Byte): RETCODE; cdecl; Ttdsdump_on = procedure ; cdecl; Ttdsdump_off = procedure ; cdecl; Ttdsdump_open = function (FileName : PAnsiChar): Integer; cdecl; Ttdsdump_close = procedure ; cdecl; T_tds_socket_init = procedure ; cdecl; T_tds_socket_done = procedure ; cdecl; { pivot functions void dbpivot_count (struct col_t *output, const struct col_t *input); void dbpivot_sum (struct col_t *output, const struct col_t *input); void dbpivot_min (struct col_t *output, const struct col_t *input); void dbpivot_max (struct col_t *output, const struct col_t *input); struct pivot_t; typedef void (*DBPIVOT_FUNC)(struct col_t *output, const struct col_t *input); struct pivot_t * dbrows_pivoted(DBPROCESS *dbproc); STATUS dbnextrow_pivoted(DBPROCESS *dbproc, struct pivot_t *pp); RETCODE dbpivot(DBPROCESS *dbproc, int nkeys, int *keys, int ncols, int *cols, DBPIVOT_FUNC func, int val); DBPIVOT_FUNC dbpivot_lookup_name( const char name[] ); } //TFreeTDSdbsechandle = function(_Type: DBINT ; Handler: INTFUNCPTR): PRETCODE; cdecl; //TFreeTDSdbsetbusy = procedure(dbproc: PDBPROCESS; BusyFunc: DB_DBBUSY_FUNC); cdecl; //TFreeTDSdbsetinterrupt = procedure(dbproc: PDBPROCESS; chkintr: DB_DBCHKINTR_FUNC; hndlintr: DB_DBHNDLINTR_FUNC); {MsSQL-spezial API definitions} { Standard DB-Library functions } TMsSQLdbclose = function(Proc: PDBPROCESS): RETCODE; cdecl; TMsSQLdbcolbrowse = function(Proc: PDBPROCESS; Column: Integer): LongBool; cdecl; TMsSQLdbcolinfo = function(Handle: PDBHANDLE; Typ, Column, ComputeId: Integer; DbColumn: PDBCOL): RETCODE; cdecl; TMsSQLdbcount = function(Proc: PDBPROCESS): Integer; cdecl; TMsSQLdbcursorbind = function(hCursor: PDBCURSOR; Col, VarType: Integer; VarLen: DBINT; POutLen: PDBINT; VarAddr: PByte): RETCODE; cdecl; TMsSQLdbcursorclose = function(DbHandle: PDBHANDLE): RETCODE; cdecl; TMsSQLdbcursorcolinfo = function(hCursor: PDBCURSOR; Column: Integer; ColName: PAnsiChar; ColType: PInteger; ColLen: PDBINT; UserType: PInteger): RETCODE; cdecl; TMsSQLdbcursorfetch = function(hCursor: PDBCURSOR; FetchType, RowNum: Integer): RETCODE; cdecl; TMsSQLdbcursorfetchex = function(hCursor: PDBCURSOR; FetchType: Integer; RowNum, nFetchRows, Reserved: DBINT): RETCODE; cdecl; TMsSQLdbcursorinfo = function(hCursor: PDBCURSOR; nCols: PInteger; nRows: PDBINT): RETCODE; cdecl; TMsSQLdbcursorinfoex = function(hCursor: PDBCURSOR; DbCursorInfo: PDBCURSORINFO): RETCODE; cdecl; TMsSQLdbcursoropen = function(Proc: PDBPROCESS; Sql: PAnsiChar; ScrollOpt, ConCurOpt: Integer; nRows: Cardinal; PStatus: PDBINT): PDBCURSOR; cdecl; TMsSQLdbdataready = function(Proc: PDBPROCESS): LongBool; cdecl; TMsSQLdbdatecrack = function(Proc: PDBPROCESS; DateInfo: PDBDATEREC; DateType: PDBDATETIME): RETCODE; cdecl; TMsSQLdbdatlen = function(Proc: PDBPROCESS; Column: Integer): Integer; cdecl; TMsSQLdbdead = function(Proc: PDBPROCESS): LongBool; cdecl; TMsSQLdbWinexit = procedure; cdecl; TMsSQLdbenlisttrans = function(Proc: PDBPROCESS; Transaction: Pointer): RETCODE; cdecl; TMsSQLdbenlistxatrans = function(Proc: PDBPROCESS; EnlistTran: LongBool): RETCODE; cdecl; TMsSQLdbgetmaxprocs = function: SmallInt; cdecl; TMsSQLdbgetpacket = function(Proc: PDBPROCESS): Cardinal; cdecl; TMsSQLdbgetuserdata = function(Proc: PDBPROCESS): Pointer; cdecl; TMsSQLdbhasretstat = function(Proc: PDBPROCESS): LongBool; cdecl; TMsSQLdbinit = function: PAnsiChar; cdecl; TMsSQLdbisavail = function(Proc: PDBPROCESS): LongBool; cdecl; TMsSQLdbisopt = function(Proc: PDBPROCESS; Option: Integer; Param: PAnsiChar): LongBool; cdecl; TMsSQLdbfreelogin = procedure(Login: PLOGINREC); cdecl; TMsSQLdbprocinfo = function(Proc: PDBPROCESS; DbProcInfo: PDBPROCINFO): RETCODE; cdecl; TMsSQLdbrpcexec = function(Proc: PDBPROCESS): RETCODE; cdecl; TMsSQLdbserverenum = function(SearchMode: Word; ServNameBuf: PAnsiChar; ServNameBufSize: Word; NumEntries: PWord): Integer; cdecl; TMsSQLdbsetmaxprocs = function(MaxProcs: SmallInt): RETCODE; cdecl; TMsSQLdbsetlpacket = function(Login: PLOGINREC; PacketSize: Word): RETCODE; cdecl; //TDS: dbsetllong TMsSQLdbsetopt = function(Proc: PDBPROCESS; Option: Integer; Param: PAnsiChar): RETCODE; cdecl; TMsSQLdbtabbrowse = function(Proc: PDBPROCESS; TabNum: Integer): LongBool; cdecl; TMsSQLdbvarylen = function(Proc: PDBPROCESS; Column: Integer): LongBool; cdecl; TMsSQLdbwillconvert = function(SrcType, DestType: Integer): LongBool; cdecl; TMsSQLdbupdatetext = function(Proc: PDBPROCESS; DestObject: PAnsiChar; DestTextPtr, DestTimestamp: PDBBINARY; UpdateType: Integer; InsertOffset, DeleteLength: DBINT; SrcObject: PAnsiChar; SrcSize: DBINT; SrcText: PDBBINARY): RETCODE; cdecl; {************* Plain API Function variables definition ************} {Sybase API definitions} type SYBDBERRHANDLE_PROC = function(Proc: PDBPROCESS; Severity, DbErr, OsErr: Integer; DbErrStr, OsErrStr: PAnsiChar): Integer; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; SYBDBMSGHANDLE_PROC = function(Proc: PDBPROCESS; MsgNo: DBINT; MsgState, Severity: Integer; MsgText, SrvName, ProcName: PAnsiChar; Line: DBUSMALLINT): Integer; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdb12hour = function(Proc: PDBPROCESS; Language: PAnsiChar): DBBOOL; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdberrhandle = function(Handler: SYBDBERRHANDLE_PROC): SYBDBERRHANDLE_PROC; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbmsghandle = function(Handler: SYBDBMSGHANDLE_PROC): SYBDBMSGHANDLE_PROC; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; { Two-phase commit functions } TSybabort_xact = function(Proc: PDBPROCESS; CommId: DBINT): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybbuild_xact_string = procedure(XActName, Service: PAnsiChar; CommId: DBINT; Result: PAnsiChar); {$IFNDEF UNIX}stdcall{$ELSE}cdecl{$ENDIF}; TSybclose_commit = procedure(Proc: PDBPROCESS); {$IFNDEF UNIX}stdcall{$ELSE}cdecl{$ENDIF}; TSybcommit_xact = function(Proc: PDBPROCESS; CommId: DBINT): RETCODE; {$IFNDEF UNIX}stdcall{$ELSE}cdecl{$ENDIF}; TSybopen_commit = function(Login: PLOGINREC; ServerName: PAnsiChar): PDBPROCESS; {$IFNDEF UNIX}stdcall{$ELSE}cdecl{$ENDIF}; TSybremove_xact = function(Proc: PDBPROCESS; CommId: DBINT; SiteCount: Integer): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybscan_xact = function(Proc: PDBPROCESS; CommId: DBINT): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybstart_xact = function(Proc: PDBPROCESS; AppName, XActName: PAnsiChar; SiteCount: Integer): DBINT; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybstat_xact = function(Proc: PDBPROCESS; CommId: DBINT): Integer; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; { BCP functions } TSybbcp_batch = function(Proc: PDBPROCESS): DBINT; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybbcp_bind = function(Proc: PDBPROCESS; VarAddr: PByte; PrefixLen: Integer; VarLen: DBINT; Terminator: PByte; TermLen, Typ, TableColumn: Integer): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybbcp_colfmt = function(Proc: PDBPROCESS; FileColumn: Integer; FileType: Byte; FilePrefixLen: Integer; FileColLen: DBINT; FileTerm: PByte; FileTermLen, TableColumn: Integer): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybbcp_collen = function(Proc: PDBPROCESS; VarLen: DBINT; TableColumn: Integer): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybbcp_colptr = function(Proc: PDBPROCESS; ColPtr: PByte; TableColumn: Integer): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybbcp_columns = function(Proc: PDBPROCESS; FileColCount: Integer): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybbcp_control = function(Proc: PDBPROCESS; Field: Integer; Value: DBINT): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybbcp_done = function(Proc: PDBPROCESS): DBINT; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybbcp_exec = function(Proc: PDBPROCESS; RowsCopied: PDBINT): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybbcp_init = function(Proc: PDBPROCESS; TableName, hFile, ErrFile: PAnsiChar; Direction: Integer): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybbcp_moretext = function(Proc: PDBPROCESS; Size: DBINT; Text: PByte): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybbcp_readfmt = function(Proc: PDBPROCESS; FileName: PAnsiChar): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybbcp_sendrow = function(Proc: PDBPROCESS): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybbcp_writefmt = function(Proc: PDBPROCESS; FileName: PAnsiChar): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; { Standard DB-Library functions } TSybdbadata = function(Proc: PDBPROCESS; ComputeId, Column: Integer): PByte; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbadlen = function(Proc: PDBPROCESS; ComputeId, Column: Integer): DBINT; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbaltbind = function(Proc: PDBPROCESS; ComputeId, Column: Integer; VarType: Integer; VarLen: DBINT; VarAddr: PByte): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbaltcolid = function(Proc: PDBPROCESS; ComputeId, Column: Integer): Integer; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbaltlen = function(Proc: PDBPROCESS; ComputeId, Column: Integer): DBINT; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbaltop = function(Proc: PDBPROCESS; ComputeId, Column: Integer): Integer; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbalttype = function(Proc: PDBPROCESS; ComputeId, Column: Integer): Integer; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbaltutype = function(Proc: PDBPROCESS; ComputeId, Column: Integer): DBINT; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbanullbind = function(Proc: PDBPROCESS; ComputeId, Column: Integer; Indicator: PDBINT): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbbind = function(Proc: PDBPROCESS; Column, VarType, VarLen: Integer; VarAddr: PByte): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbbylist = function(Proc: PDBPROCESS; ComputeId: Integer; Size: PInteger): PByte; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbcancel = function(Proc: PDBPROCESS): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbcanquery = function(Proc: PDBPROCESS): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbchange = function(Proc: PDBPROCESS): PAnsiChar; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbclose = function(Proc: PDBPROCESS): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbclrbuf = procedure(Proc: PDBPROCESS; N: DBINT); {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbclropt = function(Proc: PDBPROCESS; Option: Integer; Param: PAnsiChar): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbcmd = function(Proc: PDBPROCESS; Cmd: PAnsiChar): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbcmdrow = function(Proc: PDBPROCESS): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbcolbrowse = function(Proc: PDBPROCESS; Column: Integer): LongBool; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbcollen = function(Proc: PDBPROCESS; Column: Integer): DBINT; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbcolname = function(Proc: PDBPROCESS; Column: Integer): PAnsiChar; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbcolsource = function(Proc: PDBPROCESS; Column: Integer): PAnsiChar; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; // TSybdbcoltypeinfo = function(Proc: PDBPROCESS; Column: Integer): PDBTYPEINFO; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbcoltype = function(Proc: PDBPROCESS; Column: Integer): Integer; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbcolutype = function(Proc: PDBPROCESS; Column: Integer): DBINT; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbconvert = function(Proc: PDBPROCESS; SrcType: Integer; Src: PByte; SrcLen: DBINT; DestType: Integer; Dest: PByte; DestLen: DBINT): Integer; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbcount = function(Proc: PDBPROCESS): Integer; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbcurcmd = function(Proc: PDBPROCESS): Integer; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbcurrow = function(Proc: PDBPROCESS): DBINT; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbcursor = function(hCursor: PDBCURSOR; OpType, Row: Integer; Table, Values: PAnsiChar): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbcursorbind = function(hCursor: PDBCURSOR; Col, VarType: Integer; VarLen: DBINT; POutLen: PDBINT; VarAddr: PByte): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbcursorclose = function(DbHandle: PDBHANDLE): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbcursorcolinfo = function(hCursor: PDBCURSOR; Column: Integer; ColName: PAnsiChar; ColType: PInteger; ColLen: PDBINT; UserType: PInteger): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbcursorfetch = function(hCursor: PDBCURSOR; FetchType, RowNum: Integer): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbcursorinfo = function(hCursor: PDBCURSOR; nCols: PInteger; nRows: PDBINT): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbcursoropen = function(Proc: PDBPROCESS; Sql: PAnsiChar; ScrollOpt, ConCurOpt: Integer; nRows: Cardinal; PStatus: PDBINT): PDBCURSOR; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbdata = function(Proc: PDBPROCESS; Column: Integer): PByte; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbdatecrack = function(Proc: PDBPROCESS; DateInfo: PDBDATEREC; DateType: PDBDATETIME): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbdatlen = function(Proc: PDBPROCESS; Column: Integer): Integer; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbdead = function(Proc: PDBPROCESS): LongBool; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbexit = procedure; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbfcmd = function(Proc: PDBPROCESS; CmdString: PAnsiChar; var Params): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbfirstrow = function(Proc: PDBPROCESS): DBINT; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbfreebuf = procedure(Proc: PDBPROCESS); {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbloginfree = procedure(Login: PLOGINREC); {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbfreequal = procedure(Ptr: PAnsiChar); {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbgetchar = function(Proc: PDBPROCESS; N: Integer): PAnsiChar; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbgetmaxprocs = function: SmallInt; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbgetoff = function(Proc: PDBPROCESS; OffType: DBUSMALLINT; StartFrom: Integer): Integer; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbgetpacket = function(Proc: PDBPROCESS): Cardinal; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbgetrow = function(Proc: PDBPROCESS; Row: DBINT): STATUS; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbgetuserdata = function(Proc: PDBPROCESS): Pointer; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbhasretstat = function(Proc: PDBPROCESS): LongBool; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbinit = function: RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbisavail = function(Proc: PDBPROCESS): LongBool; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbisopt = function(Proc: PDBPROCESS; Option: Integer; Param: PAnsiChar): LongBool; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdblastrow = function(Proc: PDBPROCESS): DBINT; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdblogin = function: PLOGINREC; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbmorecmds = function(Proc: PDBPROCESS): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbmoretext = function(Proc: PDBPROCESS; Size: DBINT; Text: PByte): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbname = function(Proc: PDBPROCESS): PAnsiChar; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbnextrow = function(Proc: PDBPROCESS): STATUS; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbnullbind = function(Proc: PDBPROCESS; Column: Integer; Indicator: PDBINT): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbnumalts = function(Proc: PDBPROCESS; ComputeId: Integer): Integer; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbnumcols = function(Proc: PDBPROCESS): Integer; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbnumcompute = function(Proc: PDBPROCESS): Integer; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbnumorders = function(Proc: PDBPROCESS): Integer; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbnumrets = function(Proc: PDBPROCESS): Integer; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbopen = function(Login: PLOGINREC; Host: PAnsiChar): PDBPROCESS; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbordercol = function(Proc: PDBPROCESS; Order: Integer): Integer; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbprhead = procedure(Proc: PDBPROCESS); {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbprrow = function(Proc: PDBPROCESS): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbprtype = function(Token: Integer): PAnsiChar; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbqual = function(Proc: PDBPROCESS; TabNum: Integer; TabName: PAnsiChar): PAnsiChar; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbreadtext = function(Proc: PDBPROCESS; Buf: Pointer; BufSize: DBINT): DBINT; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbresults = function(Proc: PDBPROCESS): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbretdata = function(Proc: PDBPROCESS; RetNum: Integer): PByte; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbretlen = function(Proc: PDBPROCESS; RetNum: Integer): DBINT; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbretname = function(Proc: PDBPROCESS; RetNum: Integer): PAnsiChar; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbretstatus = function(Proc: PDBPROCESS): DBINT; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbrettype = function(Proc: PDBPROCESS; RetNum: Integer): Integer; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbrows = function(Proc: PDBPROCESS): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; //!!! TSybdbrowtype = function(Proc: PDBPROCESS): STATUS; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbrpcinit = function(Proc: PDBPROCESS; ProcName: PAnsiChar; Options: DBSMALLINT): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; //!!! TSybdbrpcparam = function(Proc: PDBPROCESS; ParamName: PAnsiChar; Status: Byte; Typ: Integer; MaxLen, DataLen: DBINT; Value: PByte): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbrpcsend = function(Proc: PDBPROCESS): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbrpwclr = procedure(Login: PLOGINREC); {$IFNDEF UNIX}stdcall{$ELSE}cdecl{$ENDIF}; TSybdbsetavail = procedure(Proc: PDBPROCESS); {$IFNDEF UNIX}stdcall{$ELSE}cdecl{$ENDIF}; TSybdbsetmaxprocs = function(MaxProcs: SmallInt): RETCODE; {$IFNDEF UNIX}stdcall{$ELSE}cdecl{$ENDIF}; TSybdbsetlname = function(Login: PLOGINREC; Value: PAnsiChar; Item: Integer): RETCODE; {$IFNDEF UNIX}stdcall{$ELSE}cdecl{$ENDIF}; TSybdbsetlogintime = function(Seconds: Integer): RETCODE; {$IFNDEF UNIX}stdcall{$ELSE}cdecl{$ENDIF}; TSybdbsetnull = function(Proc: PDBPROCESS; BindType, BindLen: Integer; BindVal: PByte): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbsetopt = function(Proc: PDBPROCESS; Option: Integer; CharParam: PAnsiChar; IntParam: Integer): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbsettime = function(Seconds: Integer): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbsetuserdata = procedure(Proc: PDBPROCESS; Ptr: Pointer); {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbsqlexec = function(Proc: PDBPROCESS): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbsqlok = function(Proc: PDBPROCESS): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbsqlsend = function(Proc: PDBPROCESS): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbstrcpy = function(Proc: PDBPROCESS; Start, NumBytes: Integer; Dest: PAnsiChar): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbstrlen = function(Proc: PDBPROCESS): Integer; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbtabbrowse = function(Proc: PDBPROCESS; TabNum: Integer): LongBool; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbtabcount = function(Proc: PDBPROCESS): Integer; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbtabname = function(Proc: PDBPROCESS; Table: Integer): PAnsiChar; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbtabsource = function(Proc: PDBPROCESS; Column: Integer; TabNum: PInteger): PAnsiChar; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbtsnewlen = function(Proc: PDBPROCESS): Integer; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbtsnewval = function(Proc: PDBPROCESS): PDBBINARY; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbtsput = function(Proc: PDBPROCESS; NewTs: PDBBINARY; NewTsName, TabNum: Integer; TableName: PAnsiChar): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbtxptr = function(Proc: PDBPROCESS; Column: Integer): PDBBINARY; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbtxtimestamp = function(Proc: PDBPROCESS; Column: Integer): PDBBINARY; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbtxtsnewval = function(Proc: PDBPROCESS): PDBBINARY; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbtxtsput = function(Proc: PDBPROCESS; NewTxts: PDBBINARY; Column: Integer): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbuse = function(Proc: PDBPROCESS; DbName: PAnsiChar): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbvarylen = function(Proc: PDBPROCESS; Column: Integer): LongBool; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbwillconvert = function(SrcType, DestType: Integer): LongBool; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TSybdbwritetext = function(Proc: PDBPROCESS; ObjName: PAnsiChar; TextPtr: PDBBINARY; TextPtrLen: DBTINYINT; Timestamp: PDBBINARY; Log: LongBool; Size: DBINT; Text: PByte): RETCODE; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; TDBLibAPI = Record dberrhandle : Tdberrhandle; dbmsghandle : Tdbmsghandle; dbprocerrhandle : Tdbprocerrhandle; dbprocmsghandle : Tdbprocmsghandle; { Two-phase commit functions } abort_xact : Tabort_xact; build_xact_string : Tbuild_xact_string; close_commit : Tclose_commit; commit_xact : Tcommit_xact; open_commit : Topen_commit; remove_xact : Tremove_xact; scan_xact : Tscan_xact; start_xact : Tstart_xact; stat_xact : Tstat_xact; { BCP functions } bcp_batch : Tbcp_batch; bcp_bind : Tbcp_bind; bcp_colfmt : Tbcp_colfmt; bcp_collen : Tbcp_collen; bcp_colptr : Tbcp_colptr; bcp_columns : Tbcp_columns; bcp_control : Tbcp_control; bcp_done : Tbcp_done; bcp_exec : Tbcp_exec; bcp_init : Tbcp_init; bcp_moretext : Tbcp_moretext; bcp_readfmt : Tbcp_readfmt; bcp_sendrow : Tbcp_sendrow; bcp_setl : Tbcp_setl; bcp_writefmt : Tbcp_writefmt; dbadata : Tdbadata; dbadlen : Tdbadlen; dbaltbind : Tdbaltbind; dbaltcolid : Tdbaltcolid; dbaltlen : Tdbaltlen; dbaltop : Tdbaltop; dbalttype : Tdbalttype; dbaltutype : Tdbaltutype; dbanullbind : Tdbanullbind; dbbind : Tdbbind; dbbylist : Tdbbylist; dbcancel : Tdbcancel; dbcanquery : Tdbcanquery; dbchange : Tdbchange; dbclrbuf : Tdbclrbuf; dbclropt : Tdbclropt; dbcmd : Tdbcmd; dbcmdrow : Tdbcmdrow; dbcollen : Tdbcollen; dbcolname : Tdbcolname; dbcolsource : Tdbcolsource; dbcoltype : Tdbcoltype; dbcolutype : Tdbcolutype; dbconvert : Tdbconvert; dbcurcmd : Tdbcurcmd; dbcurrow : Tdbcurrow; dbcursor : Tdbcursor; dbdata : Tdbdata; dbexit : Tdbexit; dbfcmd : Tdbfcmd; dbfirstrow : Tdbfirstrow; dbfreebuf : Tdbfreebuf; dbfreequal : Tdbfreequal; dbgetchar : Tdbgetchar; dbgetoff : Tdbgetoff; dbgetrow : Tdbgetrow; dbgettime : Tdbgettime; dbiscount : Tdbiscount; dblastrow : Tdblastrow; dblogin : Tdblogin; dbmorecmds : Tdbmorecmds; dbmoretext : Tdbmoretext; dbname : Tdbname; dbnextrow : Tdbnextrow; dbnullbind : Tdbnullbind; dbnumalts : Tdbnumalts; dbnumcols : Tdbnumcols; dbnumcompute : Tdbnumcompute; dbnumorders : Tdbnumorders; dbnumrets : Tdbnumrets; dbopen : Tdbopen; dbordercol : Tdbordercol; dbprhead : Tdbprhead; dbprrow : Tdbprrow; dbprtype : Tdbprtype; dbqual : Tdbqual; dbreadtext : Tdbreadtext; dbresults : Tdbresults; dbretdata : Tdbretdata; dbretlen : Tdbretlen; dbretname : Tdbretname; dbretstatus : Tdbretstatus; dbrettype : Tdbrettype; dbrows : Tdbrows; dbrowtype : Tdbrowtype; dbrpcinit : Tdbrpcinit; dbrpcparam : Tdbrpcparam; dbrpcsend : Tdbrpcsend; dbrpwclr : Tdbrpwclr; dbsetavail : Tdbsetavail; dbsetlname : Tdbsetlname; dbsetlogintime : Tdbsetlogintime; dbsetnull : Tdbsetnull; dbsettime : Tdbsettime; dbsetuserdata : Tdbsetuserdata; dbsqlexec : Tdbsqlexec; dbsqlok : Tdbsqlok; dbsqlsend : Tdbsqlsend; dbstrcpy : Tdbstrcpy; dbstrlen : Tdbstrlen; dbtabcount : Tdbtabcount; dbtabname : Tdbtabname; dbtabsource : Tdbtabsource; dbtsnewlen : Tdbtsnewlen; dbtsnewval : Tdbtsnewval; dbtsput : Tdbtsput; dbtxptr : Tdbtxptr; dbtxtimestamp : Tdbtxtimestamp; dbtxtsnewval : Tdbtxtsnewval; dbtxtsput : Tdbtxtsput; dbuse : Tdbuse; dbwritetext : Tdbwritetext; End; TFreeTDSAPI = Record {available but not implemented} db12hour: TFreeTDSdb12hour; {no MS} dbcolbrowse: TFreeTDSdbcolbrowse; dbcursorbind: TFreeTDSdbcursorbind; dbcursorclose: TFreeTDSdbcursorclose; dbcursorcolinfo:TFreeTDSdbcursorcolinfo; dbcursorfetch: TFreeTDSdbcursorfetch; dbcursorinfo: TFreeTDSdbcursorinfo; dbaltbind_ps: TFreeTDSdbaltbind_ps; dbbind_ps: TFreeTDSdbbind_ps; dbbufsize: TFreeTDSdbbufsize; dbclose: TFreeTDSdbclose; dbtablecolinfo: TFreeTDSdbtablecolinfo; dbcolinfo: TFreeTDSdbcolinfo; dbconvert_ps: TFreeTDSdbconvert_ps; dbcount: TFreeTDSdbcount; dbdatecmp: TFreeTDSdbdatecmp; dbdatecrack: TFreeTDSdbdatecrack; dbdatlen: TFreeTDSdbdatlen; dbdead: TFreeTDSdbdead; dbgetcharset: TFreeTDSdbgetcharset; dbgetlusername: TFreeTDSdbgetlusername; dbgetmaxprocs: TMsSQLdbgetmaxprocs; dbgetnatlanf: TFreeTDSdbgetnatlanf; dbgetpacket: TFreeTDSdbgetpacket; dbgetuserdata: TFreeTDSdbgetuserdata; dbhasretstat: TFreeTDSdbhasretstat; dbinit: TFreeTDSdbinit; dbiordesc: TFreeTDSdbiordesc; dbiowdesc: TFreeTDSdbiowdesc; dbisavail: TFreeTDSdbisavail; dbisopt: TFreeTDSdbisopt; dbloginfree: TFreeTDSdbloginfree; dbmny4cmp: TFreeTDSdbmny4cmp; dbmnycmp: TFreeTDSdbmnycmp; dbmny4add: TFreeTDSdbmny4add; dbmnydec: TFreeTDSdbmnydec; dbmnyinc: TFreeTDSdbmnyinc; dbmnymaxpos: TFreeTDSdbmnymaxpos; dbmnymaxneg: TFreeTDSdbmnymaxneg; dbmny4minus: TFreeTDSdbmny4minus; dbmnyminus: TFreeTDSdbmnyminus; dbmny4sub: TFreeTDSdbmny4sub; dbmnysub: TFreeTDSdbmnysub; dbmny4copy: TFreeTDSdbmny4copy; dbmnycopy: TFreeTDSdbmnycopy; dbmny4zero: TFreeTDSdbmny4zero; dbmnyzero: TFreeTDSdbmnyzero; dbmonthname: TFreeTDSdbmonthname; tdsdbopen: TFreeTDSdbopen; { pivot functions */ void dbpivot_count (struct col_t *output, const struct col_t *input); void dbpivot_sum (struct col_t *output, const struct col_t *input); void dbpivot_min (struct col_t *output, const struct col_t *input); void dbpivot_max (struct col_t *output, const struct col_t *input); struct pivot_t; typedef void (*DBPIVOT_FUNC)(struct col_t *output, const struct col_t *input); struct pivot_t * dbrows_pivoted(DBPROCESS *dbproc); STATUS dbnextrow_pivoted(DBPROCESS *dbproc, struct pivot_t *pp); RETCODE dbpivot(DBPROCESS *dbproc, int nkeys, int *keys, int ncols, int *cols, DBPIVOT_FUNC func, int val); DBPIVOT_FUNC dbpivot_lookup_name( const char name[] ); } DRBUF: TDRBUF; dbrecftos: TFreeTDSdbrecftos; dbresults_r: TFreeTDSdbresults_r; dbsafestr: TFreeTDSdbsafestr; //dbsechandle: TFreeTDSdbsechandle; dbservcharset: TFreeTDSdbservcharset; //dbsetbusy: TFreeTDSdbsetbusy; dbsetdefcharset:TFreeTDSdbsetdefcharset; dbsetifile: TFreeTDSdbsetifile; //dbsetinterrupt: TFreeTDSdbsetinterrupt; dbsetmaxprocs: TMsSQLdbsetmaxprocs; dbsetopt: TFreeTDSdbsetopt; dbsetrow: TFreeTDSdbsetrow; dbsetversion: TFreeTDSdbsetversion; dbspid: TFreeTDSdbspid; dbspr1row: TFreeTDSdbspr1row; dbspr1rowlen: TFreeTDSdbspr1rowlen; dbsprhead: TFreeTDSdbsprhead; dbsprline: TFreeTDSdbsprline; dbvarylen: TFreeTDSdbvarylen; dbtds: TFreeTDSdbtds; dbtextsize: TFreeTDSdbtextsize; dbwillconvert: TFreeTDSdbwillconvert; dbsetlbool: TFreeTDSdbsetlbool; dbsetllong: TFreeTDSdbsetllong; dbsetlversion: TFreeTDSdbsetlversion; tdsdump_on : Ttdsdump_on; tdsdump_off : Ttdsdump_off; tdsdump_open : Ttdsdump_open; tdsdump_close : Ttdsdump_close; _tds_socket_init : T_tds_socket_init; _tds_socket_done : T_tds_socket_done; End; TMsSQLAPI = record { Standard DB-Library functions } dbclose : TMsSQLdbclose; dbcolbrowse : TMsSQLdbcolbrowse; dbcolinfo : TMsSQLdbcolinfo; dbcount : TMsSQLdbcount; dbcursorbind : TMsSQLdbcursorbind; dbcursorclose : TMsSQLdbcursorclose; dbcursorcolinfo : TMsSQLdbcursorcolinfo; dbcursorfetch : TMsSQLdbcursorfetch; dbcursorfetchex : TMsSQLdbcursorfetchex; dbcursorinfo : TMsSQLdbcursorinfo; dbcursorinfoex : TMsSQLdbcursorinfoex; dbcursoropen : TMsSQLdbcursoropen; dbdataready : TMsSQLdbdataready; dbdatecrack : TMsSQLdbdatecrack; dbdatlen : TMsSQLdbdatlen; dbdead : TMsSQLdbdead; dbWinexit : TMsSQLdbWinexit; dbenlisttrans : TMsSQLdbenlisttrans; dbenlistxatrans : TMsSQLdbenlistxatrans; dbfreelogin : TMsSQLdbfreelogin; dbgetmaxprocs : TMsSQLdbgetmaxprocs; dbgetpacket : TMsSQLdbgetpacket; dbgetuserdata : TMsSQLdbgetuserdata; dbhasretstat : TMsSQLdbhasretstat; dbinit : TMsSQLdbinit; dbisavail : TMsSQLdbisavail; dbisopt : TMsSQLdbisopt; dbprocinfo : TMsSQLdbprocinfo; dbrpcexec : TMsSQLdbrpcexec; dbserverenum : TMsSQLdbserverenum; dbsetmaxprocs : TMsSQLdbsetmaxprocs; dbsetlpacket : TMsSQLdbsetlpacket; dbsetopt : TMsSQLdbsetopt; dbtabbrowse : TMsSQLdbtabbrowse; dbvarylen : TMsSQLdbvarylen; dbwillconvert : TMsSQLdbwillconvert; dbupdatetext : TMsSQLdbupdatetext; end; TSybaseAPI = record db12hour : TSybdb12hour; dberrhandle : TSybdberrhandle; dbmsghandle : TSybdbmsghandle; { Two-phase commit functions } abort_xact : TSybabort_xact; build_xact_string : TSybbuild_xact_string; close_commit : TSybclose_commit; commit_xact : TSybcommit_xact; open_commit : TSybopen_commit; remove_xact : TSybremove_xact; scan_xact : TSybscan_xact; start_xact : TSybstart_xact; stat_xact : TSybstat_xact; { BCP functions } bcp_batch : TSybbcp_batch; bcp_bind : TSybbcp_bind; bcp_colfmt : TSybbcp_colfmt; bcp_collen : TSybbcp_collen; bcp_colptr : TSybbcp_colptr; bcp_columns : TSybbcp_columns; bcp_control : TSybbcp_control; bcp_done : TSybbcp_done; bcp_exec : TSybbcp_exec; bcp_init : TSybbcp_init; bcp_moretext : TSybbcp_moretext; bcp_readfmt : TSybbcp_readfmt; bcp_sendrow : TSybbcp_sendrow; bcp_writefmt : TSybbcp_writefmt; { Standard DB-Library functions } dbadata : TSybdbadata; dbadlen : TSybdbadlen; dbaltbind : TSybdbaltbind; dbaltcolid : TSybdbaltcolid; dbaltlen : TSybdbaltlen; dbaltop : TSybdbaltop; dbalttype : TSybdbalttype; dbaltutype : TSybdbaltutype; dbanullbind : TSybdbanullbind; dbbind : TSybdbbind; dbbylist : TSybdbbylist; dbcancel : TSybdbcancel; dbcanquery : TSybdbcanquery; dbchange : TSybdbchange; dbclose : TSybdbclose; dbclrbuf : TSybdbclrbuf; dbclropt : TSybdbclropt; dbcmd : TSybdbcmd; dbcmdrow : TSybdbcmdrow; dbcolbrowse : TSybdbcolbrowse; dbcollen : TSybdbcollen; dbcolname : TSybdbcolname; dbcolsource : TSybdbcolsource; // dbcoltypeinfo : TSybdbcoltypeinfo; dbcoltype : TSybdbcoltype; dbcolutype : TSybdbcolutype; dbconvert : TSybdbconvert; dbcount : TSybdbcount; dbcurcmd : TSybdbcurcmd; dbcurrow : TSybdbcurrow; dbcursor : TSybdbcursor; dbcursorbind : TSybdbcursorbind; dbcursorclose : TSybdbcursorclose; dbcursorcolinfo : TSybdbcursorcolinfo; dbcursorfetch : TSybdbcursorfetch; dbcursorinfo : TSybdbcursorinfo; dbcursoropen : TSybdbcursoropen; dbdata : TSybdbdata; dbdatecrack : TSybdbdatecrack; dbdatlen : TSybdbdatlen; dbdead : TSybdbdead; dbexit : TSybdbexit; dbfcmd : TSybdbfcmd; dbfirstrow : TSybdbfirstrow; dbfreebuf : TSybdbfreebuf; dbloginfree : TSybdbloginfree; dbfreequal : TSybdbfreequal; dbgetchar : TSybdbgetchar; dbgetmaxprocs : TSybdbgetmaxprocs; dbgetoff : TSybdbgetoff; dbgetpacket : TSybdbgetpacket; dbgetrow : TSybdbgetrow; dbgetuserdata : TSybdbgetuserdata; dbhasretstat : TSybdbhasretstat; dbinit : TSybdbinit; dbisavail : TSybdbisavail; dbisopt : TSybdbisopt; dblastrow : TSybdblastrow; dblogin : TSybdblogin; dbmorecmds : TSybdbmorecmds; dbmoretext : TSybdbmoretext; dbname : TSybdbname; dbnextrow : TSybdbnextrow; dbnullbind : TSybdbnullbind; dbnumalts : TSybdbnumalts; dbnumcols : TSybdbnumcols; dbnumcompute : TSybdbnumcompute; dbnumorders : TSybdbnumorders; dbnumrets : TSybdbnumrets; dbopen : TSybdbopen; dbordercol : TSybdbordercol; dbprhead : TSybdbprhead; dbprrow : TSybdbprrow; dbprtype : TSybdbprtype; dbqual : TSybdbqual; dbreadtext : TSybdbreadtext; dbresults : TSybdbresults; dbretdata : TSybdbretdata; dbretlen : TSybdbretlen; dbretname : TSybdbretname; dbretstatus : TSybdbretstatus; dbrettype : TSybdbrettype; dbrows : TSybdbrows; dbrowtype : TSybdbrowtype; dbrpcinit : TSybdbrpcinit; dbrpcparam : TSybdbrpcparam; dbrpcsend : TSybdbrpcsend; dbrpwclr : TSybdbrpwclr; dbsetavail : TSybdbsetavail; dbsetmaxprocs : TSybdbsetmaxprocs; dbsetlname : TSybdbsetlname; dbsetlogintime : TSybdbsetlogintime; dbsetnull : TSybdbsetnull; dbsetopt : TSybdbsetopt; dbsettime : TSybdbsettime; dbsetuserdata : TSybdbsetuserdata; dbsqlexec : TSybdbsqlexec; dbsqlok : TSybdbsqlok; dbsqlsend : TSybdbsqlsend; dbstrcpy : TSybdbstrcpy; dbstrlen : TSybdbstrlen; dbtabbrowse : TSybdbtabbrowse; dbtabcount : TSybdbtabcount; dbtabname : TSybdbtabname; dbtabsource : TSybdbtabsource; dbtsnewlen : TSybdbtsnewlen; dbtsnewval : TSybdbtsnewval; dbtsput : TSybdbtsput; dbtxptr : TSybdbtxptr; dbtxtimestamp : TSybdbtxtimestamp; dbtxtsnewval : TSybdbtxtsnewval; dbtxtsput : TSybdbtxtsput; dbuse : TSybdbuse; dbvarylen : TSybdbvarylen; dbwillconvert : TSybdbwillconvert; dbwritetext : TSybdbwritetext; end; implementation end. ================================================ FILE: lib/zeosdbo/src/plain/ZPlainDbLibDriver.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Delphi plain driver interface to DBLibrary } { } { Originally written by Janos Fegyverneki } { FreeTDS supportd by Bogdan Dragulin } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZPlainDbLibDriver; interface {$I ZPlain.inc} uses Classes, ZCompatibility, ZPlainDriver, ZPlainDbLibConstants; const NTWDBLIB_DLL_LOCATION ='ntwdblib.dll'; LIBSYBDB_WINDOWS_DLL_LOCATION = 'libsybdb.dll'; LIBSYBDB_LINUX_DLL_LOCATION = 'libsybdb.so'; FREETDS_MSSQL_WINDOWS_DLL_LOCATION = 'msdblibr.dll'; FREETDS_LINUX_DLL_LOCATION = 'dblib.so'; FREETDS_OSX_DLL_LOCATION = 'dblib.dylib'; FREETDS_SYBASE_WINDOWS_DLL_LOCATION = 'sybdblibd.dll'; type {** Represents a generic interface to DBLIB native API. } IZDBLibPlainDriver = interface (IZPlainDriver) ['{7731C3B4-0608-4B6B-B089-240AC43A3463}'] procedure CheckError(dbProc: PDBPROCESS); function dbDead(dbProc: PDBPROCESS): Boolean; function dbLogin: PLOGINREC; procedure dbLoginFree(Login: PLOGINREC); function dbSetLoginTime(Seconds: DBINT): RETCODE; function dbsetLName(Login: PLOGINREC; Value: PAnsiChar; Item: DBINT): RETCODE; function dbSetLHost(Login: PLOGINREC; HostName: PAnsiChar): RETCODE; function dbSetLUser(Login: PLOGINREC; UserName: PAnsiChar): RETCODE; function dbSetLPwd(Login: PLOGINREC; Password: PAnsiChar): RETCODE; function dbSetLApp(Login: PLOGINREC; AppName: PAnsiChar): RETCODE; function dbSetLNatLang(Login: PLOGINREC; NatLangName: PAnsiChar): RETCODE; function dbSetLCharSet(Login: PLOGINREC; CharsetName: PAnsiChar): RETCODE; function dbSetLSecure(Login: PLOGINREC): RETCODE; function dbSetMaxprocs(MaxProcs: SmallInt): RETCODE; function dbOpen(Login: PLOGINREC; Host: PAnsiChar): PDBPROCESS; function dbCancel(dbProc: PDBPROCESS): RETCODE; function dbCmd(dbProc: PDBPROCESS; Cmd: PAnsiChar): RETCODE; function dbSqlExec(dbProc: PDBPROCESS; Async: Boolean=False): RETCODE; function dbSqlExecSync(dbProc: PDBPROCESS): RETCODE; function dbSqlExecAsync(dbProc: PDBPROCESS): RETCODE; function dbResults(dbProc: PDBPROCESS): RETCODE; function dbCanQuery(dbProc: PDBPROCESS): RETCODE; function dbMoreCmds(dbProc: PDBPROCESS): RETCODE; function dbUse(dbProc: PDBPROCESS; dbName: PAnsiChar): RETCODE; function dbSetOpt(dbProc: PDBPROCESS; Option: DBINT; Char_Param: PAnsiChar = nil; Int_Param: DBINT = -1): RETCODE; function dbClose(dbProc: PDBPROCESS): RETCODE; function dbName(dbProc: PDBPROCESS): PAnsiChar; function dbCmdRow(dbProc: PDBPROCESS): RETCODE; function dbNumCols(dbProc: PDBPROCESS): DBINT; function dbColName(dbProc: PDBPROCESS; Column: DBINT): PAnsiChar; function dbColType(dbProc: PDBPROCESS; Column: DBINT): DBINT; function dbColLen(dbProc: PDBPROCESS; Column: DBINT): DBInt; function dbData(dbProc: PDBPROCESS; Column: DBINT): PByte; function dbDatLen(dbProc: PDBPROCESS; Column: DBINT): DBINT; function dbConvert(dbProc: PDBPROCESS; SrcType: DBINT; Src: PByte; SrcLen: DBINT; DestType: DBINT; Dest: PByte; DestLen: DBINT): DBINT; function dbNextRow(dbProc: PDBPROCESS): STATUS; function dbGetRow(dbProc: PDBPROCESS; Row: DBINT): STATUS; function dbCount(dbProc: PDBPROCESS): DBINT; function dbRpcInit(dbProc: PDBPROCESS; RpcName: PAnsiChar; Options: SmallInt): RETCODE; function dbRpcParam(dbProc: PDBPROCESS; ParamName: PAnsiChar; Status: Byte; Type_: DBINT; MaxLen: DBINT; DataLen: DBINT; Value: Pointer): RETCODE; function dbRpcSend(dbProc: PDBPROCESS): RETCODE; function dbRpcExec(dbProc: PDBPROCESS): RETCODE; function dbRetStatus(dbProc: PDBPROCESS): DBINT; function dbHasRetStat(dbProc: PDBPROCESS): Boolean; function dbRetName(dbProc: PDBPROCESS; RetNum: DBINT): PAnsiChar; function dbRetData(dbProc: PDBPROCESS; RetNum: DBINT): Pointer; function dbRetLen(dbProc: PDBPROCESS; RetNum: DBINT): DBINT; function dbRetType(dbProc: PDBPROCESS; RetNum: DBINT): DBINT; function dbdataready(Proc: PDBPROCESS): LongBool; function GetVariables: TDBVariables; end; TZDBLibAbstractPlainDriver = class(TZAbstractPlainDriver, IZPlainDriver) protected DBVariables: TDBVariables; public function dbDead(dbProc: PDBPROCESS): Boolean; virtual; abstract; procedure dbLoginFree(Login: PLOGINREC); virtual; abstract; constructor Create; virtual; procedure CheckError(dbProc: PDBPROCESS); function GetVariables: TDBVariables; end; TZDbLibBasePlainDriver = class(TZDBLibAbstractPlainDriver, IZPlainDriver, IZDBLibPlainDriver) protected DBLibAPI: TDBLibAPI; public procedure LoadApi; override; function dbLogin: PLOGINREC; virtual; function dbSetLoginTime(Seconds: DBINT): RETCODE; function dbsetLName(Login: PLOGINREC; Value: PAnsiChar; Item: DBINT): RETCODE; function dbSetLHost(Login: PLOGINREC; HostName: PAnsiChar): RETCODE; function dbSetLUser(Login: PLOGINREC; UserName: PAnsiChar): RETCODE; function dbSetLPwd(Login: PLOGINREC; Password: PAnsiChar): RETCODE; function dbSetLApp(Login: PLOGINREC; AppName: PAnsiChar): RETCODE; function dbSetLNatLang(Login: PLOGINREC; NatLangName: PAnsiChar): RETCODE; function dbSetLCharSet(Login: PLOGINREC; CharsetName: PAnsiChar): RETCODE; virtual; abstract; function dbSetLSecure(Login: PLOGINREC): RETCODE; virtual; abstract; function dbSetMaxprocs(MaxProcs: SmallInt): RETCODE; virtual; abstract; function dbOpen(Login: PLOGINREC; Host: PAnsiChar): PDBPROCESS; virtual; function dbCancel(dbProc: PDBPROCESS): RETCODE; function dbCmd(dbProc: PDBPROCESS; Cmd: PAnsiChar): RETCODE; function dbSqlExec(dbProc: PDBPROCESS; Async: Boolean=False): RETCODE; function dbSqlExecSync(dbProc: PDBPROCESS): RETCODE; function dbSqlExecAsync(dbProc: PDBPROCESS): RETCODE; function dbResults(dbProc: PDBPROCESS): RETCODE; function dbCanQuery(dbProc: PDBPROCESS): RETCODE; function dbMoreCmds(dbProc: PDBPROCESS): RETCODE; function dbUse(dbProc: PDBPROCESS; dbName: PAnsiChar): RETCODE; function dbSetOpt(dbProc: PDBPROCESS; Option: DBINT; Char_Param: PAnsiChar = nil; Int_Param: DBINT = -1): RETCODE; virtual; abstract; function dbClose(dbProc: PDBPROCESS): RETCODE; virtual; abstract; function dbName(dbProc: PDBPROCESS): PAnsiChar; function dbCmdRow(dbProc: PDBPROCESS): RETCODE; function dbNumCols(dbProc: PDBPROCESS): DBINT; function dbcolbrowse(Proc: PDBPROCESS; Column: Integer): LongBool; virtual; abstract; function dbColName(dbProc: PDBPROCESS; Column: DBINT): PAnsiChar; function dbColType(dbProc: PDBPROCESS; Column: DBINT): DBINT; function dbColLen(dbProc: PDBPROCESS; Column: DBINT): DBInt; function dbData(dbProc: PDBPROCESS; Column: DBINT): PByte; function dbDatLen(dbProc: PDBPROCESS; Column: DBINT): DBINT; virtual; abstract; function dbConvert(dbProc: PDBPROCESS; SrcType: DBINT; Src: PByte; SrcLen: DBINT; DestType: DBINT; Dest: PByte; DestLen: DBINT): DBINT; function dbNextRow(dbProc: PDBPROCESS): STATUS; function dbGetRow(dbProc: PDBPROCESS; Row: DBINT): STATUS; function dbCount(dbProc: PDBPROCESS): DBINT; virtual; abstract; function dbRpcInit(dbProc: PDBPROCESS; RpcName: PAnsiChar; Options: SmallInt): RETCODE; function dbRpcParam(dbProc: PDBPROCESS; ParamName: PAnsiChar; Status: Byte; Type_: DBINT; MaxLen: DBINT; DataLen: DBINT; Value: Pointer): RETCODE; virtual; function dbRpcSend(dbProc: PDBPROCESS): RETCODE; function dbRpcExec(dbProc: PDBPROCESS): RETCODE; function dbRetStatus(dbProc: PDBPROCESS): DBINT; function dbHasRetStat(dbProc: PDBPROCESS): Boolean; virtual; abstract; function dbRetName(dbProc: PDBPROCESS; RetNum: DBINT): PAnsiChar; function dbRetData(dbProc: PDBPROCESS; RetNum: DBINT): Pointer; function dbRetLen(dbProc: PDBPROCESS; RetNum: DBINT): DBINT; function dbRetType(dbProc: PDBPROCESS; RetNum: DBINT): DBINT; function dbdataready(Proc: PDBPROCESS): LongBool; virtual; abstract; function dbrbuf(Proc: PDBPROCESS): DBINT; end; {** Implements a dblib driver for Sybase ASE 12.5 } TZDBLibSybaseASE125PlainDriver = class (TZDBLibAbstractPlainDriver, IZPlainDriver, IZDBLibPlainDriver) private SybaseAPI: TSybaseAPI; protected procedure LoadApi; override; function Clone: IZPlainDriver; override; procedure LoadCodePages; override; public constructor Create; override; destructor Destroy; override; function GetProtocol: string; override; function GetDescription: string; override; function dbDead(dbProc: PDBPROCESS): Boolean; override; function dbLogin: PLOGINREC; procedure dbLoginFree(Login: PLOGINREC); override; function dbSetLoginTime(Seconds: DBINT): RETCODE; function dbsetLName(Login: PLOGINREC; Value: PAnsiChar; Item: DBINT): RETCODE; function dbSetLHost(Login: PLOGINREC; HostName: PAnsiChar): RETCODE; function dbSetLUser(Login: PLOGINREC; UserName: PAnsiChar): RETCODE; function dbSetLPwd(Login: PLOGINREC; Password: PAnsiChar): RETCODE; function dbSetLApp(Login: PLOGINREC; AppName: PAnsiChar): RETCODE; function dbSetLNatLang(Login: PLOGINREC; NatLangName: PAnsiChar): RETCODE; function dbSetLCharSet(Login: PLOGINREC; CharsetName: PAnsiChar): RETCODE; function dbSetLSecure(Login: PLOGINREC): RETCODE; function dbSetMaxprocs(MaxProcs: SmallInt): RETCODE; function dbOpen(Login: PLOGINREC; Host: PAnsiChar): PDBPROCESS; function dbCancel(dbProc: PDBPROCESS): RETCODE; function dbCmd(dbProc: PDBPROCESS; Cmd: PAnsiChar): RETCODE; function dbSqlExec(dbProc: PDBPROCESS; Async: Boolean=False): RETCODE; virtual; function dbSqlExecSync(dbProc: PDBPROCESS): RETCODE; function dbSqlExecAsync(dbProc: PDBPROCESS): RETCODE; function dbResults(dbProc: PDBPROCESS): RETCODE; function dbCanQuery(dbProc: PDBPROCESS): RETCODE; function dbMoreCmds(dbProc: PDBPROCESS): RETCODE; function dbUse(dbProc: PDBPROCESS; dbName: PAnsiChar): RETCODE; function dbSetOpt(dbProc: PDBPROCESS; Option: DBINT; Char_Param: PAnsiChar = nil; Int_Param: DBINT = -1): RETCODE; function dbClose(dbProc: PDBPROCESS): RETCODE; function dbName(dbProc: PDBPROCESS): PAnsiChar; function dbCmdRow(dbProc: PDBPROCESS): RETCODE; function dbNumCols(dbProc: PDBPROCESS): DBINT; function dbcolbrowse(Proc: PDBPROCESS; Column: Integer): LongBool; function dbColName(dbProc: PDBPROCESS; Column: DBINT): PAnsiChar; function dbColType(dbProc: PDBPROCESS; Column: DBINT): DBINT; function dbColLen(dbProc: PDBPROCESS; Column: DBINT): DBInt; function dbData(dbProc: PDBPROCESS; Column: DBINT): PByte; function dbDatLen(dbProc: PDBPROCESS; Column: DBINT): DBINT; function dbConvert(dbProc: PDBPROCESS; SrcType: DBINT; Src: PByte; SrcLen: DBINT; DestType: DBINT; Dest: PByte; DestLen: DBINT): DBINT; function dbNextRow(dbProc: PDBPROCESS): STATUS; function dbGetRow(dbProc: PDBPROCESS; Row: DBINT): STATUS; function dbCount(dbProc: PDBPROCESS): DBINT; function dbRpcInit(dbProc: PDBPROCESS; RpcName: PAnsiChar; Options: SmallInt): RETCODE; function dbRpcParam(dbProc: PDBPROCESS; ParamName: PAnsiChar; Status: Byte; Type_: DBINT; MaxLen: DBINT; DataLen: DBINT; Value: Pointer): RETCODE; function dbRpcSend(dbProc: PDBPROCESS): RETCODE; function dbRpcExec(dbProc: PDBPROCESS): RETCODE; function dbRetStatus(dbProc: PDBPROCESS): DBINT; function dbHasRetStat(dbProc: PDBPROCESS): Boolean; function dbRetName(dbProc: PDBPROCESS; RetNum: DBINT): PAnsiChar; function dbRetData(dbProc: PDBPROCESS; RetNum: DBINT): Pointer; function dbRetLen(dbProc: PDBPROCESS; RetNum: DBINT): DBINT; function dbRetType(dbProc: PDBPROCESS; RetNum: DBINT): DBINT; function dbrbuf(Proc: PDBPROCESS): DBINT; function dbdataready(Proc: PDBPROCESS): LongBool; end; {** Implements a dblib driver for MSSql7 } TZDBLibMSSQL7PlainDriver = class (TZDbLibBasePlainDriver, IZPlainDriver, IZDBLibPlainDriver) private MsSQLAPI: TMsSQLAPI; protected function Clone: IZPlainDriver; override; procedure LoadCodePages; override; public procedure LoadApi; override; constructor Create; override; destructor Destroy; override; function GetProtocol: string; override; function GetDescription: string; override; function dbDead(dbProc: PDBPROCESS): Boolean; override; procedure dbLoginFree(Login: PLOGINREC); override; function dbSetLCharSet(Login: PLOGINREC; CharsetName: PAnsiChar): RETCODE; override; function dbSetLSecure(Login: PLOGINREC): RETCODE; override; function dbSetMaxprocs(MaxProcs: SmallInt): RETCODE; override; function dbSqlExecAsync(dbProc: PDBPROCESS): RETCODE; function dbSetOpt(dbProc: PDBPROCESS; Option: DBINT; Char_Param: PAnsiChar = nil; Int_Param: DBINT = -1): RETCODE; override; function dbClose(dbProc: PDBPROCESS): RETCODE; override; function dbcolbrowse(Proc: PDBPROCESS; Column: Integer): LongBool; override; function dbDatLen(dbProc: PDBPROCESS; Column: DBINT): DBINT; override; function dbCount(dbProc: PDBPROCESS): DBINT; override; function dbHasRetStat(dbProc: PDBPROCESS): Boolean; override; function dbdataready(Proc: PDBPROCESS): LongBool; override; end; {** Implements a generic dblib driver} IZFreeTDSPlainDriver = interface (IZDBLibPlainDriver) ['{12FA5A22-59E5-4CBF-B745-96A7CDF9FBE0}'] function dbSetTime(queryTime : Integer): RETCODE; procedure tdsDumpOn; procedure tdsDumpOff; procedure tdsDump_Open(const FileName: String); procedure tdsDump_Close; end; {** Implements a dblib driver for Sybase/MSSQL } TZFreeTDSBasePlainDriver = class (TZDbLibBasePlainDriver, IZDBLibPlainDriver, IZFreeTDSPlainDriver) private FreeTDSAPI: TFreeTDSAPI; protected function Clone: IZPlainDriver; override; abstract; public constructor Create; override; destructor Destroy; override; procedure LoadApi; override; function GetProtocol: string; override; function GetDescription: string; override; {API functions} function dbsetlversion(Login: PLOGINREC): RETCODE; virtual; function dbsetversion: RETCODE; virtual; function dbDead(dbProc: PDBPROCESS): Boolean; override; function dbLogin: PLOGINREC; override; procedure dbLoginFree(Login: PLOGINREC); override; function dbSetLCharSet(Login: PLOGINREC; CharsetName: PAnsiChar): RETCODE; override; function dbSetLSecure(Login: PLOGINREC): RETCODE; override; function dbSetMaxprocs(MaxProcs: SmallInt): RETCODE; override; function dbSetTime(queryTime : Integer): RETCODE; function dbSetOpt(dbProc: PDBPROCESS; Option: Integer; Char_Param: PAnsiChar = nil; Int_Param: Integer = -1): RETCODE; override; function dbClose(dbProc: PDBPROCESS): RETCODE; override; function dbColInfo(dbProc: PDBPROCESS; Column: Integer; var ADBInfo: DBCOL): RETCODE; function dbDatLen(dbProc: PDBPROCESS; Column: Integer): Integer; override; function dbCount(dbProc: PDBPROCESS): Integer; override; function dbcolbrowse(Proc: PDBPROCESS; Column: Integer): LongBool; override; function dbHasRetStat(dbProc: PDBPROCESS): Boolean; override; procedure tdsDumpOn; procedure tdsDumpOff; procedure tdsDump_Open(const FileName: String); procedure tdsDump_Close; function dbdataready(Proc: PDBPROCESS): LongBool; override; procedure dbfreelogin(Login: PLOGINREC); end; TZFreeTDS42MsSQLPlainDriver = class(TZFreeTDSBasePlainDriver) protected function Clone: IZPlainDriver; override; procedure LoadCodePages; override; public constructor Create; override; function GetProtocol: string; override; function GetDescription: string; override; function dbsetlversion(Login: PLOGINREC): RETCODE; override; function dbsetversion: RETCODE; override; end; TZFreeTDS42SybasePlainDriver = class(TZFreeTDSBasePlainDriver) protected function Clone: IZPlainDriver; override; procedure LoadCodePages; override; public constructor Create; override; function GetProtocol: string; override; function GetDescription: string; override; function dbsetlversion(Login: PLOGINREC): RETCODE; override; function dbsetversion: RETCODE; override; end; TZFreeTDS50PlainDriver = class(TZFreeTDS42SybasePlainDriver) protected function Clone: IZPlainDriver; override; procedure LoadCodePages; override; public constructor Create; override; function GetProtocol: string; override; function GetDescription: string; override; function dbsetversion: RETCODE; override; end; TZFreeTDS70PlainDriver = class(TZFreeTDS42MsSQLPlainDriver) protected function Clone: IZPlainDriver; override; procedure LoadCodePages; override; public function GetProtocol: string; override; function GetDescription: string; override; function dbsetlversion(Login: PLOGINREC): RETCODE; override; function dbsetversion: RETCODE; override; end; TZFreeTDS71PlainDriver = class(TZFreeTDS70PlainDriver) protected function Clone: IZPlainDriver; override; procedure LoadCodePages; override; public function GetProtocol: string; override; function GetDescription: string; override; function dbsetversion: RETCODE; override; end; TZFreeTDS72PlainDriver = class(TZFreeTDS70PlainDriver) protected function Clone: IZPlainDriver; override; procedure LoadCodePages; override; public function GetProtocol: string; override; function GetDescription: string; override; function dbsetversion: RETCODE; override; end; var OldFreeTDSErrorHandle: DBERRHANDLE_PROC = nil; OldFreeTDSMessageHandle: DBMSGHANDLE_PROC = nil; OldSybaseErrorHandle: SYBDBERRHANDLE_PROC = nil; OldSybaseMessageHandle: SYBDBMSGHANDLE_PROC = nil; OldMsSQLMessageHandle: DBMSGHANDLE_PROC = nil; OldMsSQLErrorHandle: DBERRHANDLE_PROC = nil; SQLErrors: TList; SQLMessages: TList; implementation uses SysUtils, ZPlainLoader, ZEncoding, {$IFDEF FPC}DOS{$ELSE}Windows{$ENDIF}; procedure AddSybaseCodePages(PlainDriver: TZAbstractPlainDriver); begin { MultiByte } PlainDriver.AddCodePage('874THAIBIN', 1, ceAnsi, 874); {Windows Thailndisch, ISO8859-11, binre Sortierung} PlainDriver.AddCodePage('932JPN', 2, ceAnsi, 932); {Japanese Shift-JIS mit Microsoft-Erweiterungen} PlainDriver.AddCodePage('936ZHO', 3, ceAnsi, 936); {Vereinfachtes Chinesisch, PRC GBK} PlainDriver.AddCodePage('949KOR', 4, ceAnsi, 949); {Korean KS C 5601-1987-Codierung, Wansung} PlainDriver.AddCodePage('950ZHO_HK', 5, ceAnsi, 950); {Traditionelles Chinesisch, Big 5-Kodierung mit HKSCS} PlainDriver.AddCodePage('950ZHO_TW', 6, ceAnsi, 950); {Traditionelles Chinesisch, Big 5-Kodierung} PlainDriver.AddCodePage('EUC_CHINA', 21, ceAnsi, zCP_GB2312); {GB2312-80 Simplified Chinese} PlainDriver.AddCodePage('EUC_JAPAN', 22, ceAnsi, zCP_SHIFTJS); {Japanisch EUC JIS X 0208-1990 und JIS X 0212-1990-Zeichensatz} PlainDriver.AddCodePage('EUC_KOREA', 23, ceAnsi, 1361); { Koreanisch KS C 5601-1992 8-Bit-Zeichensatz, Johab} PlainDriver.AddCodePage('EUC_TAIWAN', 24, ceAnsi, 964); {EUC-TW-Kodierung} PlainDriver.AddCodePage('UCA', 29, ceUTF16, zCP_UTF16, 'utf8'); {UCA UCA-Standardkollatierung} PlainDriver.AddCodePage('UTF8BIN', 30, ceUTF8, zCP_UTF8); {UTF-8, 8-Bit-Mehrbyte-Zeichensatz fr Unicode, binre Reihenfolge} { SingleByte } PlainDriver.AddCodePage('1250LATIN2', 7, ceAnsi, zCP_WIN1250); {Windows Latin 2, Mittel- und Osteuropa} PlainDriver.AddCodePage('1250POL', 8, ceAnsi, zCP_WIN1251); {Windows Latin 2, Polnisch} PlainDriver.AddCodePage('1251CYR', 9, ceAnsi, 1251); {Windows Kyrillisch} PlainDriver.AddCodePage('1252LATIN1', 10, ceAnsi, 1252); { Windows Latin 1, Western} PlainDriver.AddCodePage('1252LT1ACC', 11, ceAnsi, 1252); {Windows-Spezial Latin 1, Western, Zeichen mit Akzent nicht gleich} PlainDriver.AddCodePage('1252NOR', 12, ceAnsi, 1252); {Windows Latin 1, Norwegisch} PlainDriver.AddCodePage('1252SPA', 13, ceAnsi, 1252); {Windows Latin 1, Spanisch} PlainDriver.AddCodePage('1252SWEFIN', 14, ceAnsi, 1252); {Windows Latin 1, Schwedisch/Finnisch} PlainDriver.AddCodePage('1253ELL', 15, ceAnsi, 1253); {Windows Griechisch, ISO8859-7 mit Erweiterungen} PlainDriver.AddCodePage('1254TRK', 16, ceAnsi, 1254); {Windows Trkisch, ISO8859-9 mit Erweiterungen} PlainDriver.AddCodePage('1254TRKALT', 17, ceAnsi, 1254); {Windows Trkisch, ISO8859-9 mit Erweiterungen, I mit I-Punkt gleich I ohne I-Punkt} PlainDriver.AddCodePage('1255HEB', 18, ceAnsi, 1255); {Windows Hebrisch, ISO8859-8 mit Erweiterungen} PlainDriver.AddCodePage('1256ARA', 19, ceAnsi, 1256); {Windows Arabisch, ISO8859-6 mit Erweiterungen} PlainDriver.AddCodePage('1257LIT', 20, ceAnsi, 1257); {Windows Baltische Staaten, Litauisch} PlainDriver.AddCodePage('ISO1LATIN1', 25, ceAnsi, zCP_L1_ISO_8859_1); {ISO8859-1, ISO Latin 1, Western, Latin 1-Sortierreihenfolge} PlainDriver.AddCodePage('ISO9LATIN1', 26, ceAnsi, zCP_L9_ISO_8859_15); { ISO8859-15, ISO Latin 9, Western, Latin 1-Sortierreihenfolge} PlainDriver.AddCodePage('ISO_1', 27, ceAnsi, zCP_L1_ISO_8859_1); {ISO8859-1, ISO Latin 1, Western} PlainDriver.AddCodePage('ISO_BINENG', 28, ceAnsi, zCP_us_ascii); {Binre Sortierreihenfolge, Englisch ISO/ASCII 7-Bit-Zuordnung nach Gro- und Kleinschreibung} end; procedure AddmMSCodePages(PlainDriver: TZAbstractPlainDriver); begin { SingleByte } PlainDriver.AddCodePage('WIN1250', 1, ceAnsi, zCP_WIN1250); {Microsoft Windows Codepage 1250 (East European)} PlainDriver.AddCodePage('WIN1251', 2, ceAnsi, zCP_WIN1251); {Microsoft Windows Codepage 1251 (Cyrl)} PlainDriver.AddCodePage('WIN1252', 3, ceAnsi, zCP_WIN1252); {Microsoft Windows Codepage 1252 (ANSI), USASCCI} PlainDriver.AddCodePage('WIN1253', 4, ceAnsi, zCP_WIN1253); {Microsoft Windows Codepage 1253 (Greek)} PlainDriver.AddCodePage('WIN1254', 5, ceAnsi, zCP_WIN1254); {Microsoft Windows Codepage 1254 (Turk)} PlainDriver.AddCodePage('WIN1255', 6, ceAnsi, zCP_WIN1255); {Microsoft Windows Codepage 1255 (Hebrew)} PlainDriver.AddCodePage('WIN1256', 7, ceAnsi, cCP_WIN1256); {Microsoft Windows Codepage 1256 (Arab)} PlainDriver.AddCodePage('WIN1257', 8, ceAnsi, zCP_WIN1257); {Microsoft Windows Codepage 1257 (BaltRim)} PlainDriver.AddCodePage('WIN1258', 9, ceAnsi, zCP_WIN1258); {Microsoft Windows Codepage 1258 (Viet), TCVN-5712} end; { Handle sql server error messages } function SybaseErrorHandle(Proc: PDBPROCESS; Severity, DbErr, OsErr: Integer; DbErrStr, OsErrStr: PAnsiChar): Integer; {$IFNDEF UNIX} stdcall{$ELSE} cdecl{$ENDIF}; var SqlError: PDBLibError; begin New(SqlError); SqlError.dbProc := Proc; SqlError.Severity := Severity; SqlError.DbErr := DbErr; SqlError.OsErr := OsErr; SqlError.DbErrStr := DbErrStr; SqlError.OsErrStr := OsErrStr; SQLErrors.Add(SqlError); Result := INT_CANCEL; end; { Handle sql server messages } function SybaseMessageHandle(Proc: PDBPROCESS; MsgNo: DBINT; MsgState, Severity: Integer; MsgText, SrvName, ProcName: PAnsiChar; Line: DBUSMALLINT): Integer; {$IFNDEF UNIX} stdcall {$ELSE} cdecl {$ENDIF}; var SQLMessage: PDBLibMessage; begin New(SQLMessage); SQLMessage.dbProc := Proc; SQLMessage.MsgNo := MsgNo; SQLMessage.MsgState := MsgState; SQLMessage.Severity := Severity; SQLMessage.MsgText := MsgText; SQLMessage.SrvName := SrvName; SQLMessage.ProcName := ProcName; SQLMessage.Line := Line; SQLMessages.Add(SQLMessage); Result := 0; end; { Handle sql server error messages } function DbLibErrorHandle(Proc: PDBPROCESS; Severity, DbErr, OsErr: Integer; DbErrStr, OsErrStr: PAnsiChar): Integer; cdecl; var SqlError: PDBLibError; begin New(SqlError); SqlError.dbProc := Proc; SqlError.Severity := Severity; SqlError.DbErr := DbErr; SqlError.OsErr := OsErr; SqlError.DbErrStr := DbErrStr; SqlError.OsErrStr := OsErrStr; SQLErrors.Add(SqlError); Result := INT_CANCEL; end; { Handle sql server messages } function DbLibMessageHandle(Proc: PDBPROCESS; MsgNo: DBINT; MsgState, Severity: Integer; MsgText, SrvName, ProcName: PAnsiChar; Line: DBUSMALLINT): Integer; cdecl; var SQLMessage: PDBLibMessage; begin New(SQLMessage); SQLMessage.dbProc := Proc; SQLMessage.MsgNo := MsgNo; SQLMessage.MsgState := MsgState; SQLMessage.Severity := Severity; SQLMessage.MsgText := MsgText; SQLMessage.SrvName := SrvName; SQLMessage.ProcName := ProcName; SQLMessage.Line := Line; SQLMessages.Add(SQLMessage); Result := 0; end; constructor TZDBLibAbstractPlainDriver.Create; var I: Integer; begin inherited create; FLoader := TZNativeLibraryLoader.Create([]); for i := 0 to high(DBVariables.DBoptions) do DBVariables.DBoptions[i] := -1; for i := 0 to high(DBVariables.DBSetLoginRec) do DBVariables.DBSetLoginRec[i] := -1; DBVariables.datatypes[Z_SQLVOID] := DBLIBSQLVOID; DBVariables.datatypes[Z_SQLTEXT] := DBLIBSQLTEXT; DBVariables.datatypes[Z_SQLVARBINARY] := DBLIBSQLVARBINARY; DBVariables.datatypes[Z_SQLINTN] := DBLIBSQLINTN; DBVariables.datatypes[Z_SQLVARCHAR] := DBLIBSQLVARCHAR; DBVariables.datatypes[Z_SQLBINARY] := DBLIBSQLBINARY; DBVariables.datatypes[Z_SQLIMAGE] := DBLIBSQLIMAGE; DBVariables.datatypes[Z_SQLCHAR] := DBLIBSQLCHAR; DBVariables.datatypes[Z_SQLINT1] := DBLIBSQLINT1; DBVariables.datatypes[Z_SQLBIT] := DBLIBSQLBIT; DBVariables.datatypes[Z_SQLINT2] := DBLIBSQLINT2; DBVariables.datatypes[Z_SQLINT4] := DBLIBSQLINT4; DBVariables.datatypes[Z_SQLMONEY] := DBLIBSQLMONEY; DBVariables.datatypes[Z_SQLDATETIME] := DBLIBSQLDATETIME; DBVariables.datatypes[Z_SQLFLT8] := DBLIBSQLFLT8; DBVariables.datatypes[Z_SQLFLTN] := DBLIBSQLFLTN; DBVariables.datatypes[Z_SQLMONEYN] := DBLIBSQLMONEYN; DBVariables.datatypes[Z_SQLDATETIMN] := DBLIBSQLDATETIMN; DBVariables.datatypes[Z_SQLFLT4] := DBLIBSQLFLT4; DBVariables.datatypes[Z_SQLMONEY4] := DBLIBSQLMONEY4; DBVariables.datatypes[Z_SQLDATETIM4] := DBLIBSQLDATETIM4; DBVariables.datatypes[Z_SQLDECIMAL] := DBLIBSQLDECIMAL; DBVariables.datatypes[Z_SQLNUMERIC] := DBLIBSQLNUMERIC; end; procedure TZDBLibAbstractPlainDriver.CheckError(dbProc: Pointer); var I: Integer; S: String; lErrorEntry: PDBLibError; lMesageEntry: PDBLibMessage; procedure AddToErrorMsg(const AError: String); begin if S > '' then S := S + #13#10; S := S + AError; end; begin if ((SQLErrors = nil) or (SQLErrors.Count = 0)) and ((SQLMessages = nil) or (SQLMessages.Count = 0)) then Exit; S := ''; I := 0; while I < SQLErrors.Count do begin lErrorEntry := PDBLibError(SQLErrors[I]); if (dbProc = nil) or (lErrorEntry^.dbProc = dbProc) or (lErrorEntry^.dbProc = nil) then begin if lErrorEntry^.Severity > EXINFO then AddToErrorMsg(Format('DBError : [%4.4d] : %s', [lErrorEntry^.DbErr, String(lErrorEntry^.DbErrStr)]) ); if lErrorEntry^.OsErr > EXINFO then AddToErrorMsg(Format('OSError : [%4.4d] : %s', [lErrorEntry^.OsErr, String(lErrorEntry^.OsErrStr)]) ); Dispose(lErrorEntry); SQLErrors.Delete(I); end else Inc(I); end; I := 0; while I < SQLMessages.Count do begin lMesageEntry := PDBLibMessage(SQLMessages[I]); if (dbProc = nil) or (lMesageEntry^.dbProc = dbProc) or (lMesageEntry^.dbProc = nil) then begin if lMesageEntry^.Severity > EXINFO then AddToErrorMsg(String(lMesageEntry^.MsgText)); Dispose(lMesageEntry); SQLMessages.Delete(I); end else Inc(I); end; if S <> '' then raise Exception.Create(String(S)); end; function TZDBLibAbstractPlainDriver.GetVariables: TDBVariables; begin Result := DBVariables; end; { TZDBLibBasePlainDriver } procedure TZDBLibBasePlainDriver.LoadApi; begin inherited LoadAPI; with Loader do begin @DBLibAPI.dberrhandle := GetAddress('dberrhandle'); @DBLibAPI.dbmsghandle := GetAddress('dbmsghandle'); @DBLibAPI.dbprocerrhandle := GetAddress('dbprocerrhandle'); @DBLibAPI.dbprocmsghandle := GetAddress('dbprocmsghandle'); @DBLibAPI.abort_xact := GetAddress('abort_xact'); @DBLibAPI.build_xact_string := GetAddress('build_xact_string'); @DBLibAPI.close_commit := GetAddress('close_commit'); @DBLibAPI.commit_xact := GetAddress('commit_xact'); @DBLibAPI.open_commit := GetAddress('open_commit'); @DBLibAPI.remove_xact := GetAddress('remove_xact'); @DBLibAPI.scan_xact := GetAddress('scan_xact'); @DBLibAPI.start_xact := GetAddress('start_xact'); @DBLibAPI.stat_xact := GetAddress('stat_xact'); @DBLibAPI.bcp_batch := GetAddress('bcp_batch'); @DBLibAPI.bcp_bind := GetAddress('bcp_bind'); @DBLibAPI.bcp_colfmt := GetAddress('bcp_colfmt'); @DBLibAPI.bcp_collen := GetAddress('bcp_collen'); @DBLibAPI.bcp_colptr := GetAddress('bcp_colptr'); @DBLibAPI.bcp_columns := GetAddress('bcp_columns'); @DBLibAPI.bcp_control := GetAddress('bcp_control'); @DBLibAPI.bcp_done := GetAddress('bcp_done'); @DBLibAPI.bcp_exec := GetAddress('bcp_exec'); @DBLibAPI.bcp_init := GetAddress('bcp_init'); @DBLibAPI.bcp_moretext := GetAddress('bcp_moretext'); @DBLibAPI.bcp_readfmt := GetAddress('bcp_readfmt'); @DBLibAPI.bcp_sendrow := GetAddress('bcp_sendrow'); @DBLibAPI.bcp_setl := GetAddress('bcp_setl'); @DBLibAPI.bcp_writefmt := GetAddress('bcp_writefmt'); @DBLibAPI.dbadata := GetAddress('dbadata'); @DBLibAPI.dbadlen := GetAddress('dbadlen'); @DBLibAPI.dbaltbind := GetAddress('dbaltbind'); @DBLibAPI.dbaltcolid := GetAddress('dbaltcolid'); @DBLibAPI.dbaltlen := GetAddress('dbaltlen'); @DBLibAPI.dbaltop := GetAddress('dbaltop'); @DBLibAPI.dbalttype := GetAddress('dbalttype'); @DBLibAPI.dbaltutype := GetAddress('dbaltutype'); @DBLibAPI.dbanullbind := GetAddress('dbanullbind'); @DBLibAPI.dbbind := GetAddress('dbbind'); @DBLibAPI.dbbylist := GetAddress('dbbylist'); @DBLibAPI.dbcancel := GetAddress('dbcancel'); @DBLibAPI.dbcanquery := GetAddress('dbcanquery'); @DBLibAPI.dbchange := GetAddress('dbchange'); @DBLibAPI.dbclrbuf := GetAddress('dbclrbuf'); @DBLibAPI.dbclropt := GetAddress('dbclropt'); @DBLibAPI.dbcmd := GetAddress('dbcmd'); @DBLibAPI.dbcmdrow := GetAddress('dbcmdrow'); @DBLibAPI.dbcollen := GetAddress('dbcollen'); @DBLibAPI.dbcolname := GetAddress('dbcolname'); @DBLibAPI.dbcolsource := GetAddress('dbcolsource'); @DBLibAPI.dbcoltype := GetAddress('dbcoltype'); @DBLibAPI.dbcolutype := GetAddress('dbcolutype'); @DBLibAPI.dbconvert := GetAddress('dbconvert'); @DBLibAPI.dbcurcmd := GetAddress('dbcurcmd'); @DBLibAPI.dbcurrow := GetAddress('dbcurrow'); @DBLibAPI.dbcursor := GetAddress('dbcursor'); @DBLibAPI.dbdata := GetAddress('dbdata'); @DBLibAPI.dbexit := GetAddress('dbexit'); @DBLibAPI.dbfcmd := GetAddress('dbfcmd'); @DBLibAPI.dbfirstrow := GetAddress('dbfirstrow'); @DBLibAPI.dbfreebuf := GetAddress('dbfreebuf'); @DBLibAPI.dbfreequal := GetAddress('dbfreequal'); @DBLibAPI.dbgetchar := GetAddress('dbgetchar'); @DBLibAPI.dbgetoff := GetAddress('dbgetoff'); @DBLibAPI.dbgetrow := GetAddress('dbgetrow'); @DBLibAPI.dbgettime := GetAddress('dbgettime'); @DBLibAPI.dbiscount := GetAddress('dbiscount'); @DBLibAPI.dblastrow := GetAddress('dblastrow'); @DBLibAPI.dblogin := GetAddress('dblogin'); @DBLibAPI.dbmorecmds := GetAddress('dbmorecmds'); @DBLibAPI.dbmoretext := GetAddress('dbmoretext'); @DBLibAPI.dbname := GetAddress('dbname'); @DBLibAPI.dbnextrow := GetAddress('dbnextrow'); @DBLibAPI.dbnullbind := GetAddress('dbnullbind'); @DBLibAPI.dbnumalts := GetAddress('dbnumalts'); @DBLibAPI.dbnumcols := GetAddress('dbnumcols'); @DBLibAPI.dbnumcompute := GetAddress('dbnumcompute'); @DBLibAPI.dbnumorders := GetAddress('dbnumorders'); @DBLibAPI.dbnumrets := GetAddress('dbnumrets'); @DBLibAPI.dbopen := GetAddress('dbopen'); @DBLibAPI.dbordercol := GetAddress('dbordercol'); @DBLibAPI.dbprhead := GetAddress('dbprhead'); @DBLibAPI.dbprrow := GetAddress('dbprrow'); @DBLibAPI.dbprtype := GetAddress('dbprtype'); @DBLibAPI.dbqual := GetAddress('dbqual'); @DBLibAPI.dbreadtext := GetAddress('dbreadtext'); @DBLibAPI.dbresults := GetAddress('dbresults'); @DBLibAPI.dbretdata := GetAddress('dbretdata'); @DBLibAPI.dbretlen := GetAddress('dbretlen'); @DBLibAPI.dbretname := GetAddress('dbretname'); @DBLibAPI.dbretstatus := GetAddress('dbretstatus'); @DBLibAPI.dbrettype := GetAddress('dbrettype'); @DBLibAPI.dbrows := GetAddress('dbrows'); @DBLibAPI.dbrowtype := GetAddress('dbrowtype'); @DBLibAPI.dbrpcinit := GetAddress('dbrpcinit'); @DBLibAPI.dbrpcparam := GetAddress('dbrpcparam'); @DBLibAPI.dbrpcsend := GetAddress('dbrpcsend'); @DBLibAPI.dbrpwclr := GetAddress('dbrpwclr'); @DBLibAPI.dbsetavail := GetAddress('dbsetavail'); @DBLibAPI.dbsetlname := GetAddress('dbsetlname'); @DBLibAPI.dbsetlogintime := GetAddress('dbsetlogintime'); @DBLibAPI.dbsetnull := GetAddress('dbsetnull'); @DBLibAPI.dbsettime := GetAddress('dbsettime'); @DBLibAPI.dbsetuserdata := GetAddress('dbsetuserdata'); @DBLibAPI.dbsqlexec := GetAddress('dbsqlexec'); @DBLibAPI.dbsqlok := GetAddress('dbsqlok'); @DBLibAPI.dbsqlsend := GetAddress('dbsqlsend'); @DBLibAPI.dbstrcpy := GetAddress('dbstrcpy'); @DBLibAPI.dbstrlen := GetAddress('dbstrlen'); @DBLibAPI.dbtabcount := GetAddress('dbtabcount'); @DBLibAPI.dbtabname := GetAddress('dbtabname'); @DBLibAPI.dbtabsource := GetAddress('dbtabsource'); @DBLibAPI.dbtsnewlen := GetAddress('dbtsnewlen'); @DBLibAPI.dbtsnewval := GetAddress('dbtsnewval'); @DBLibAPI.dbtsput := GetAddress('dbtsput'); @DBLibAPI.dbtxptr := GetAddress('dbtxptr'); @DBLibAPI.dbtxtimestamp := GetAddress('dbtxtimestamp'); @DBLibAPI.dbtxtsnewval := GetAddress('dbtxtsnewval'); @DBLibAPI.dbtxtsput := GetAddress('dbtxtsput'); @DBLibAPI.dbuse := GetAddress('dbuse'); @DBLibAPI.dbwritetext := GetAddress('dbwritetext'); end; end; function TZDBLibBasePlainDriver.dbLogin: PLOGINREC; begin Result := DBLibAPI.dblogin; end; function TZDBLibBasePlainDriver.dbSetLoginTime(Seconds: DBINT): RETCODE; begin Result := DBLibAPI.dbsetlogintime(Seconds); end; function TZDBLibBasePlainDriver.dbsetlname(Login: PLOGINREC; Value: PAnsiChar; Item: DBINT): RETCODE; begin Result := DBLibAPI.dbsetlname(Login, Value, Item); end; function TZDBLibBasePlainDriver.dbSetLHost(Login: PLOGINREC; HostName: PAnsiChar): RETCODE; begin Result := DBLibAPI.dbsetlname(Login, HostName, Self.DBVariables.dbSetLoginRec[Z_SETHOST]); end; function TZDBLibBasePlainDriver.dbsetluser(Login: PLOGINREC; UserName: PAnsiChar): RETCODE; begin Result := DBLibAPI.dbsetlname(Login, UserName, Self.DBVariables.dbSetLoginRec[Z_SETUSER]); end; function TZDBLibBasePlainDriver.dbsetlpwd(Login: PLOGINREC; Password: PAnsiChar): RETCODE; begin Result := DBLibAPI.dbsetlname(Login, Password, Self.DBVariables.dbSetLoginRec[Z_SETPWD]); end; function TZDBLibBasePlainDriver.dbSetLApp(Login: PLOGINREC; AppName: PAnsiChar): RETCODE; begin Result := DBLibAPI.dbsetlname(Login, AppName, Self.DBVariables.dbSetLoginRec[Z_SETAPP]); end; function TZDBLibBasePlainDriver.dbSetLNatLang(Login: PLOGINREC; NatLangName: PAnsiChar): RETCODE; begin Result := DBLibAPI.dbsetlname(Login, NatLangName, Self.DBVariables.dbSetLoginRec[Z_SETLANG]); end; function TZDBLibBasePlainDriver.dbOpen(Login: PLOGINREC; Host: PAnsiChar): PDBPROCESS; begin DBLibAPI.dbsetlogintime(10); Result := DBLibAPI.dbOpen(Login, Host); end; function TZDBLibBasePlainDriver.dbCancel(dbProc: PDBPROCESS): RETCODE; begin Result := DBLibAPI.dbcancel(dbProc); end; function TZDBLibBasePlainDriver.dbCmd(dbProc: PDBPROCESS; Cmd: PAnsiChar): RETCODE; begin Result := DBLibAPI.dbcmd(dbProc, Cmd); end; function TZDBLibBasePlainDriver.dbSqlExec(dbProc: PDBPROCESS; Async: Boolean=False): RETCODE; begin if Async then Result := dbSqlExecAsync(dbProc) else Result := dbSqlExecSync(dbProc); end; function TZDBLibBasePlainDriver.dbSqlExecSync(dbProc: PDBPROCESS): RETCODE; begin Result := DBLibAPI.dbSqlExec(dbProc); end; function TZDBLibBasePlainDriver.dbSqlExecAsync(dbProc: PDBPROCESS): RETCODE; var lStartTick : Int64; begin Result := DBLibAPI.dbsqlsend(dbProc); if Result = SUCCEED then begin lStartTick := {$IFDEF FPC}GetMsCount{$ELSE}GetTickCount{$ENDIF}; repeat //DBApplication.ProcessMessages; until ({$IFDEF FPC}GetMsCount{$ELSE}GetTickCount{$ENDIF} > lStartTick + TIMEOUT_MAXIMUM * 1000) or (dbdataready(dbProc) = TRUE); Result := DBLibAPI.dbsqlok(dbProc); end; end; function TZDBLibBasePlainDriver.dbResults(dbProc: PDBPROCESS): RETCODE; begin Result := DBLibAPI.dbResults(dbProc); end; function TZDBLibBasePlainDriver.dbCanQuery(dbProc: PDBPROCESS): RETCODE; begin Result := DBLibAPI.dbCanQuery(dbProc); end; function TZDBLibBasePlainDriver.dbMoreCmds(dbProc: PDBPROCESS): RETCODE; begin Result := DBLibAPI.dbMoreCmds(dbProc); end; function TZDBLibBasePlainDriver.dbUse(dbProc: PDBPROCESS; dbName: PAnsiChar): RETCODE; begin Result := DBLibAPI.dbUse(dbProc, dbName); end; function TZDBLibBasePlainDriver.dbName(dbProc: PDBPROCESS): PAnsiChar; begin Result := DBLibAPI.dbName(dbProc); end; function TZDBLibBasePlainDriver.dbCmdRow(dbProc: PDBPROCESS): RETCODE; begin Result := DBLibAPI.dbCmdRow(dbProc); end; function TZDBLibBasePlainDriver.dbNumCols(dbProc: PDBPROCESS): Integer; begin Result := DBLibAPI.dbNumCols(dbProc); end; function TZDBLibBasePlainDriver.dbColName(dbProc: PDBPROCESS; Column: Integer): PAnsiChar; begin Result := DBLibAPI.dbColName(dbProc, Column); end; function TZDBLibBasePlainDriver.dbColType(dbProc: PDBPROCESS; Column: Integer): Integer; begin Result := DBLibAPI.dbColType(dbProc, Column); end; function TZDBLibBasePlainDriver.dbColLen(dbProc: PDBPROCESS; Column: Integer): DBInt; begin Result := DBLibAPI.dbColLen(dbProc, Column); end; function TZDBLibBasePlainDriver.dbData(dbProc: PDBPROCESS; Column: Integer): PByte; begin Result := DBLibAPI.dbData(dbProc, Column); end; function TZDBLibBasePlainDriver.dbConvert(dbProc: PDBPROCESS; SrcType: Integer; Src: PByte; SrcLen: DBINT; DestType: Integer; Dest: PByte; DestLen: DBINT): Integer; begin Result := DBLibAPI.dbConvert(dbProc, SrcType, Src, SrcLen, DestType, Dest, DestLen); end; function TZDBLibBasePlainDriver.dbNextRow(dbProc: PDBPROCESS): STATUS; begin Result := DBLibAPI.dbNextRow(dbProc); end; function TZDBLibBasePlainDriver.dbGetRow(dbProc: PDBPROCESS; Row: Integer): STATUS; begin Result := DBLibAPI.dbGetRow(dbProc, Row); end; function TZDBLibBasePlainDriver.dbRpcInit(dbProc: PDBPROCESS; RpcName: PAnsiChar; Options: SmallInt): RETCODE; begin Result := DBLibAPI.dbRpcInit(dbProc, RpcName, Options); end; function TZDBLibBasePlainDriver.dbRpcParam(dbProc: PDBPROCESS; ParamName: PAnsiChar; Status: Byte; Type_: Integer; MaxLen: Integer; DataLen: Integer; Value: Pointer): RETCODE; begin Result := DBLibAPI.dbRpcParam(dbProc, ParamName, Status, Type_, MaxLen, DataLen, Value); end; function TZDBLibBasePlainDriver.dbRpcSend(dbProc: PDBPROCESS): RETCODE; begin Result := DBLibAPI.dbRpcSend(dbProc); end; function TZDBLibBasePlainDriver.dbRpcExec(dbProc: PDBPROCESS): RETCODE; begin Result := DBLibAPI.dbRpcSend(dbProc); if Result = SUCCEED then Result := DBLibAPI.dbSqlOk(dbProc); end; function TZDBLibBasePlainDriver.dbRetStatus(dbProc: PDBPROCESS): Integer; begin Result := DBLibAPI.dbRetStatus(dbProc); end; function TZDBLibBasePlainDriver.dbRetName(dbProc: PDBPROCESS; RetNum: Integer): PAnsiChar; begin Result := DBLibAPI.dbRetName(dbProc, RetNum); end; function TZDBLibBasePlainDriver.dbRetData(dbProc: PDBPROCESS; RetNum: Integer): Pointer; begin if Assigned(DBLibAPI.dbRetData) then Result := DBLibAPI.dbRetData(dbProc, RetNum) else Result := nil; end; function TZDBLibBasePlainDriver.dbRetLen(dbProc: PDBPROCESS; RetNum: Integer): Integer; begin Result := DBLibAPI.dbRetLen(dbProc, RetNum); end; function TZDBLibBasePlainDriver.dbRetType(dbProc: PDBPROCESS; RetNum: Integer): Integer; begin Result := DBLibAPI.dbRetType(dbProc, RetNum); end; function TZDBLibBasePlainDriver.dbrbuf(Proc: PDBPROCESS): DBINT; begin Result := DBINT(dbdataready(Proc)); end; { TZDBLibSybaseASE125PlainDriver } procedure TZDBLibSybaseASE125PlainDriver.LoadApi; begin { ************** Load adresses of API Functions ************* } with Loader do begin @SybaseAPI.db12hour := GetAddress('db12hour'); @SybaseAPI.dberrhandle := GetAddress('dberrhandle'); @SybaseAPI.dbmsghandle := GetAddress('dbmsghandle'); @SybaseAPI.abort_xact := GetAddress('abort_xact'); @SybaseAPI.build_xact_string := GetAddress('build_xact_string'); @SybaseAPI.close_commit := GetAddress('close_commit'); @SybaseAPI.commit_xact := GetAddress('commit_xact'); @SybaseAPI.open_commit := GetAddress('open_commit'); @SybaseAPI.remove_xact := GetAddress('remove_xact'); @SybaseAPI.scan_xact := GetAddress('scan_xact'); @SybaseAPI.start_xact := GetAddress('start_xact'); @SybaseAPI.stat_xact := GetAddress('stat_xact'); @SybaseAPI.bcp_batch := GetAddress('bcp_batch'); @SybaseAPI.bcp_bind := GetAddress('bcp_bind'); @SybaseAPI.bcp_colfmt := GetAddress('bcp_colfmt'); @SybaseAPI.bcp_collen := GetAddress('bcp_collen'); @SybaseAPI.bcp_colptr := GetAddress('bcp_colptr'); @SybaseAPI.bcp_columns := GetAddress('bcp_columns'); @SybaseAPI.bcp_control := GetAddress('bcp_control'); @SybaseAPI.bcp_done := GetAddress('bcp_done'); @SybaseAPI.bcp_exec := GetAddress('bcp_exec'); @SybaseAPI.bcp_init := GetAddress('bcp_init'); @SybaseAPI.bcp_moretext := GetAddress('bcp_moretext'); @SybaseAPI.bcp_readfmt := GetAddress('bcp_readfmt'); @SybaseAPI.bcp_sendrow := GetAddress('bcp_sendrow'); @SybaseAPI.bcp_writefmt := GetAddress('bcp_writefmt'); @SybaseAPI.dbadata := GetAddress('dbadata'); @SybaseAPI.dbadlen := GetAddress('dbadlen'); @SybaseAPI.dbaltbind := GetAddress('dbaltbind'); @SybaseAPI.dbaltcolid := GetAddress('dbaltcolid'); @SybaseAPI.dbaltlen := GetAddress('dbaltlen'); @SybaseAPI.dbaltop := GetAddress('dbaltop'); @SybaseAPI.dbalttype := GetAddress('dbalttype'); @SybaseAPI.dbaltutype := GetAddress('dbaltutype'); @SybaseAPI.dbanullbind := GetAddress('dbanullbind'); @SybaseAPI.dbbind := GetAddress('dbbind'); @SybaseAPI.dbbylist := GetAddress('dbbylist'); @SybaseAPI.dbcancel := GetAddress('dbcancel'); @SybaseAPI.dbcanquery := GetAddress('dbcanquery'); @SybaseAPI.dbchange := GetAddress('dbchange'); @SybaseAPI.dbclose := GetAddress('dbclose'); @SybaseAPI.dbclrbuf := GetAddress('dbclrbuf'); @SybaseAPI.dbclropt := GetAddress('dbclropt'); @SybaseAPI.dbcmd := GetAddress('dbcmd'); @SybaseAPI.dbcmdrow := GetAddress('dbcmdrow'); @SybaseAPI.dbcolbrowse := GetAddress('dbcolbrowse'); @SybaseAPI.dbcollen := GetAddress('dbcollen'); @SybaseAPI.dbcolname := GetAddress('dbcolname'); @SybaseAPI.dbcolsource := GetAddress('dbcolsource'); // @SybaseAPI.dbcoltypeinfo := GetAddress('dbcoltypeinfo'); @SybaseAPI.dbcoltype := GetAddress('dbcoltype'); @SybaseAPI.dbcolutype := GetAddress('dbcolutype'); @SybaseAPI.dbconvert := GetAddress('dbconvert'); @SybaseAPI.dbcount := GetAddress('dbcount'); @SybaseAPI.dbcurcmd := GetAddress('dbcurcmd'); @SybaseAPI.dbcurrow := GetAddress('dbcurrow'); @SybaseAPI.dbcursor := GetAddress('dbcursor'); @SybaseAPI.dbcursorbind := GetAddress('dbcursorbind'); @SybaseAPI.dbcursorclose := GetAddress('dbcursorclose'); @SybaseAPI.dbcursorcolinfo := GetAddress('dbcursorcolinfo'); @SybaseAPI.dbcursorfetch := GetAddress('dbcursorfetch'); @SybaseAPI.dbcursorinfo := GetAddress('dbcursorinfo'); @SybaseAPI.dbcursoropen := GetAddress('dbcursoropen'); @SybaseAPI.dbdata := GetAddress('dbdata'); @SybaseAPI.dbdatecrack := GetAddress('dbdatecrack'); @SybaseAPI.dbdatlen := GetAddress('dbdatlen'); @SybaseAPI.dbdead := GetAddress('dbdead'); @SybaseAPI.dbexit := GetAddress('dbexit'); @SybaseAPI.dbfcmd := GetAddress('dbfcmd'); @SybaseAPI.dbfirstrow := GetAddress('dbfirstrow'); @SybaseAPI.dbfreebuf := GetAddress('dbfreebuf'); @SybaseAPI.dbloginfree := GetAddress('dbloginfree'); @SybaseAPI.dbfreequal := GetAddress('dbfreequal'); @SybaseAPI.dbgetchar := GetAddress('dbgetchar'); @SybaseAPI.dbgetmaxprocs := GetAddress('dbgetmaxprocs'); @SybaseAPI.dbgetoff := GetAddress('dbgetoff'); @SybaseAPI.dbgetpacket := GetAddress('dbgetpacket'); @SybaseAPI.dbgetrow := GetAddress('dbgetrow'); @SybaseAPI.dbgetuserdata := GetAddress('dbgetuserdata'); @SybaseAPI.dbhasretstat := GetAddress('dbhasretstat'); @SybaseAPI.dbinit := GetAddress('dbinit'); @SybaseAPI.dbisavail := GetAddress('dbisavail'); @SybaseAPI.dbisopt := GetAddress('dbisopt'); @SybaseAPI.dblastrow := GetAddress('dblastrow'); @SybaseAPI.dblogin := GetAddress('dblogin'); @SybaseAPI.dbmorecmds := GetAddress('dbmorecmds'); @SybaseAPI.dbmoretext := GetAddress('dbmoretext'); @SybaseAPI.dbname := GetAddress('dbname'); @SybaseAPI.dbnextrow := GetAddress('dbnextrow'); @SybaseAPI.dbnullbind := GetAddress('dbnullbind'); @SybaseAPI.dbnumalts := GetAddress('dbnumalts'); @SybaseAPI.dbnumcols := GetAddress('dbnumcols'); @SybaseAPI.dbnumcompute := GetAddress('dbnumcompute'); @SybaseAPI.dbnumorders := GetAddress('dbnumorders'); @SybaseAPI.dbnumrets := GetAddress('dbnumrets'); @SybaseAPI.dbopen := GetAddress('dbopen'); @SybaseAPI.dbordercol := GetAddress('dbordercol'); @SybaseAPI.dbprhead := GetAddress('dbprhead'); @SybaseAPI.dbprrow := GetAddress('dbprrow'); @SybaseAPI.dbprtype := GetAddress('dbprtype'); @SybaseAPI.dbqual := GetAddress('dbqual'); @SybaseAPI.dbreadtext := GetAddress('dbreadtext'); @SybaseAPI.dbresults := GetAddress('dbresults'); @SybaseAPI.dbretdata := GetAddress('dbretdata'); @SybaseAPI.dbretlen := GetAddress('dbretlen'); @SybaseAPI.dbretname := GetAddress('dbretname'); @SybaseAPI.dbretstatus := GetAddress('dbretstatus'); @SybaseAPI.dbrettype := GetAddress('dbrettype'); @SybaseAPI.dbrows := GetAddress('dbrows'); @SybaseAPI.dbrowtype := GetAddress('dbrowtype'); @SybaseAPI.dbrpcinit := GetAddress('dbrpcinit'); @SybaseAPI.dbrpcparam := GetAddress('dbrpcparam'); @SybaseAPI.dbrpcsend := GetAddress('dbrpcsend'); @SybaseAPI.dbrpwclr := GetAddress('dbrpwclr'); @SybaseAPI.dbsetavail := GetAddress('dbsetavail'); @SybaseAPI.dbsetmaxprocs := GetAddress('dbsetmaxprocs'); @SybaseAPI.dbsetlname := GetAddress('dbsetlname'); @SybaseAPI.dbsetlogintime := GetAddress('dbsetlogintime'); @SybaseAPI.dbsetnull := GetAddress('dbsetnull'); @SybaseAPI.dbsetopt := GetAddress('dbsetopt'); @SybaseAPI.dbsettime := GetAddress('dbsettime'); @SybaseAPI.dbsetuserdata := GetAddress('dbsetuserdata'); @SybaseAPI.dbsqlexec := GetAddress('dbsqlexec'); @SybaseAPI.dbsqlok := GetAddress('dbsqlok'); @SybaseAPI.dbsqlsend := GetAddress('dbsqlsend'); @SybaseAPI.dbstrcpy := GetAddress('dbstrcpy'); @SybaseAPI.dbstrlen := GetAddress('dbstrlen'); @SybaseAPI.dbtabbrowse := GetAddress('dbtabbrowse'); @SybaseAPI.dbtabcount := GetAddress('dbtabcount'); @SybaseAPI.dbtabname := GetAddress('dbtabname'); @SybaseAPI.dbtabsource := GetAddress('dbtabsource'); @SybaseAPI.dbtsnewlen := GetAddress('dbtsnewlen'); @SybaseAPI.dbtsnewval := GetAddress('dbtsnewval'); @SybaseAPI.dbtsput := GetAddress('dbtsput'); @SybaseAPI.dbtxptr := GetAddress('dbtxptr'); @SybaseAPI.dbtxtimestamp := GetAddress('dbtxtimestamp'); @SybaseAPI.dbtxtsnewval := GetAddress('dbtxtsnewval'); @SybaseAPI.dbtxtsput := GetAddress('dbtxtsput'); @SybaseAPI.dbuse := GetAddress('dbuse'); @SybaseAPI.dbvarylen := GetAddress('dbvarylen'); @SybaseAPI.dbwillconvert := GetAddress('dbwillconvert'); @SybaseAPI.dbwritetext := GetAddress('dbwritetext'); SybaseAPI.dbinit; OldSybaseErrorHandle := SybaseAPI.dberrhandle(SybaseErrorHandle); OldSybaseMessageHandle := SybaseAPI.dbmsghandle(SybaseMessageHandle); end; end; function TZDBLibSybaseASE125PlainDriver.Clone: IZPlainDriver; begin Result := TZDBLibSybaseASE125PlainDriver.Create; end; constructor TZDBLibSybaseASE125PlainDriver.Create; begin inherited Create; {$IFDEF MSWINDOWS} Loader.AddLocation(LIBSYBDB_WINDOWS_DLL_LOCATION); {$ELSE} {$IFDEF UNIX} Loader.AddLocation(LIBSYBDB_LINUX_DLL_LOCATION); {$ENDIF} {$ENDIF} DBVariables.DBoptions[Z_PARSEONLY] := DBLIBDBPARSEONLY; DBVariables.DBoptions[Z_SHOWPLAN] := DBLIBDBSHOWPLAN; DBVariables.DBoptions[Z_NOEXEC] := DBLIBDBNOEXEC; DBVariables.DBoptions[Z_ARITHIGNORE] := DBLIBDBARITHIGNORE; DBVariables.DBoptions[Z_NOCOUNT] := DBLIBDBNOCOUNT; DBVariables.DBoptions[Z_ARITHABORT] := DBLIBDBARITHABORT; DBVariables.DBoptions[Z_TEXTLIMIT] := DBLIBDBTEXTLIMIT; DBVariables.DBoptions[Z_OFFSET] := DBLIBDBOFFSET; DBVariables.DBoptions[Z_STAT] := DBLIBDBSTAT; DBVariables.DBoptions[Z_STORPROCID] := DBLIBDBSTORPROCID; DBVariables.DBoptions[Z_BUFFER] := DBLIBDBBUFFER; DBVariables.DBoptions[Z_NOAUTOFREE] := DBLIBDBNOAUTOFREE; DBVariables.DBoptions[Z_ROWCOUNT] := DBLIBDBROWCOUNT; DBVariables.DBoptions[Z_TEXTSIZE] := DBLIBDBTEXTSIZE; DBVariables.DBoptions[Z_CLIENTCURSORS] := DBLIBDBCLIENTCURSORS; DBVariables.DBoptions[Z_SETTIME] := DBLIBDBSET_TIME; DBVariables.DBoptions[Z_QUOTEDIDENT] := DBLIBDBQUOTEDIDENT; DBVariables.DBoptions[Z_ANSITOOEM] := DBLIBDBANSITOOEM; DBVariables.DBoptions[Z_OEMTOANSI] := DBLIBDBOEMTOANSI; {MSSQL Loginrec manipulations} DBVariables.DBSetLoginRec[Z_SETHOST] := SYBDBSETHOST; DBVariables.DBSetLoginRec[Z_SETUSER] := SYBDBSETUSER; DBVariables.DBSetLoginRec[Z_SETPWD] := SYBDBSETPWD; DBVariables.DBSetLoginRec[Z_SETHID] := SYBDBSETHID; DBVariables.DBSetLoginRec[Z_SETAPP] := SYBDBSETAPP; DBVariables.DBSetLoginRec[Z_SETBCP] := SYBDBSETBCP; DBVariables.DBSetLoginRec[Z_SETLANG] := SYBDBSETLANG; DBVariables.DBSetLoginRec[Z_SETNOSHORT] := SYBDBSETNOSHORT; DBVariables.DBSetLoginRec[Z_SETHIER] := SYBDBSETHIER; DBVariables.DBSetLoginRec[Z_SETCHARSET] := SYBDBSETCHARSET; DBVariables.DBSetLoginRec[Z_SETPACKET] := SYBDBSETPACKET; DBVariables.DBSetLoginRec[Z_SETENCRYPT] := SYBDBSETENCRYPT; DBVariables.dbSetLoginRec[Z_SETLABELED] := SYBDBSETLABELED; LoadCodePages; end; destructor TZDBLibSybaseASE125PlainDriver.Destroy; begin if Loader.Loaded then begin SybaseAPI.dberrhandle(OldSybaseErrorHandle); SybaseAPI.dbmsghandle(OldSybaseMessageHandle); SybaseAPI.dbexit; end; inherited Destroy; end; procedure TZDBLibSybaseASE125PlainDriver.LoadCodePages; begin AddSybaseCodePages(Self); end; function TZDBLibSybaseASE125PlainDriver.GetProtocol: string; begin Result := 'sybase'; end; function TZDBLibSybaseASE125PlainDriver.GetDescription: string; begin Result := 'Native dblib driver for Sybase ASE 12.5'; end; function TZDBLibSybaseASE125PlainDriver.dbcolbrowse(Proc: PDBPROCESS; Column: Integer): LongBool; begin Result := SybaseAPI.dbcolbrowse(Proc, Column); end; function TZDBLibSybaseASE125PlainDriver.dbDead(dbProc: PDBPROCESS): Boolean; begin Result := SybaseAPI.dbDead(dbProc); end; function TZDBLibSybaseASE125PlainDriver.dbLogin: PLOGINREC; begin Result := SybaseAPI.dbLogin; end; procedure TZDBLibSybaseASE125PlainDriver.dbLoginFree(Login: PLOGINREC); begin SybaseAPI.dbLoginFree(Login); end; function TZDBLibSybaseASE125PlainDriver.dbSetLoginTime(Seconds: DBINT): RETCODE; begin Result := SybaseAPI.dbsetlogintime(Seconds); end; function TZDBLibSybaseASE125PlainDriver.dbsetlname(Login: PLOGINREC; Value: PAnsiChar; Item: DBINT): RETCODE; begin Result := SybaseAPI.dbsetlname(Login, Value, Item); end; function TZDBLibSybaseASE125PlainDriver.dbSetLHost(Login: PLOGINREC; HostName: PAnsiChar): RETCODE; begin Result := SybaseAPI.dbsetlname(Login, HostName, Self.DBVariables.dbSetLoginRec[Z_SETHOST]); end; function TZDBLibSybaseASE125PlainDriver.dbsetluser(Login: PLOGINREC; UserName: PAnsiChar): RETCODE; begin Result := SybaseAPI.dbsetlname(Login, UserName, Self.DBVariables.dbSetLoginRec[Z_SETUSER]); end; function TZDBLibSybaseASE125PlainDriver.dbsetlpwd(Login: PLOGINREC; Password: PAnsiChar): RETCODE; begin Result := SybaseAPI.dbsetlname(Login, Password, Self.DBVariables.dbSetLoginRec[Z_SETPWD]); end; function TZDBLibSybaseASE125PlainDriver.dbSetLApp(Login: PLOGINREC; AppName: PAnsiChar): RETCODE; begin Result := SybaseAPI.dbsetlname(Login, AppName, Self.DBVariables.dbSetLoginRec[Z_SETAPP]); end; function TZDBLibSybaseASE125PlainDriver.dbSetLNatLang(Login: PLOGINREC; NatLangName: PAnsiChar): RETCODE; begin Result := SybaseAPI.dbsetlname(Login, NatLangName, Self.DBVariables.dbSetLoginRec[Z_SETLANG]); end; function TZDBLibSybaseASE125PlainDriver.dbSetLCharSet(Login: PLOGINREC; CharsetName: PAnsiChar): RETCODE; begin Result := SybaseAPI.dbsetlname(Login, CharsetName, Self.DBVariables.dbSetLoginRec[Z_SETCHARSET]); end; function TZDBLibSybaseASE125PlainDriver.dbSetLSecure(Login: PLOGINREC): RETCODE; begin Result := 0 end; function TZDBLibSybaseASE125PlainDriver.dbsetmaxprocs( MaxProcs: SmallInt): RETCODE; begin Result := SybaseAPI.dbsetmaxprocs(MaxProcs); end; function TZDBLibSybaseASE125PlainDriver.dbOpen(Login: PLOGINREC; Host: PAnsiChar): PDBPROCESS; begin Result := SybaseAPI.dbOpen(Login, Host); end; function TZDBLibSybaseASE125PlainDriver.dbCancel(dbProc: PDBPROCESS): RETCODE; begin Result := SybaseAPI.dbcancel(dbProc); end; function TZDBLibSybaseASE125PlainDriver.dbCmd(dbProc: PDBPROCESS; Cmd: PAnsiChar): RETCODE; begin Result := SybaseAPI.dbcmd(dbProc, Cmd); end; function TZDBLibSybaseASE125PlainDriver.dbSqlExec(dbProc: PDBPROCESS; Async: Boolean=False): RETCODE; begin if Async then Result := dbSqlExecSync(dbProc) else Result := dbSqlExecAsync(dbProc); end; function TZDBLibSybaseASE125PlainDriver.dbSqlExecSync(dbProc: PDBPROCESS): RETCODE; begin Result := SybaseAPI.dbSqlExec(dbProc); end; function TZDBLibSybaseASE125PlainDriver.dbSqlExecAsync(dbProc: PDBPROCESS): RETCODE; var lStartTick : Int64; begin Result := SybaseAPI.dbsqlsend(dbProc); if Result = SUCCEED then begin lStartTick := {$IFDEF FPC}GetMsCount{$ELSE}GetTickCount{$ENDIF}; repeat continue; until ({$IFDEF FPC}GetMsCount{$ELSE}GetTickCount{$ENDIF} > lStartTick + TIMEOUT_MAXIMUM * 1000) or (dbdataready(dbProc) = TRUE); Result := SybaseAPI.dbsqlok(dbProc); end; end; function TZDBLibSybaseASE125PlainDriver.dbResults(dbProc: PDBPROCESS): RETCODE; begin Result := SybaseAPI.dbResults(dbProc); end; function TZDBLibSybaseASE125PlainDriver.dbCanQuery(dbProc: PDBPROCESS): RETCODE; begin Result := SybaseAPI.dbCanQuery(dbProc); end; function TZDBLibSybaseASE125PlainDriver.dbMoreCmds(dbProc: PDBPROCESS): RETCODE; begin Result := SybaseAPI.dbMoreCmds(dbProc); end; function TZDBLibSybaseASE125PlainDriver.dbUse(dbProc: PDBPROCESS; dbName: PAnsiChar): RETCODE; begin Result := SybaseAPI.dbUse(dbProc, dbName); end; function TZDBLibSybaseASE125PlainDriver.dbSetOpt(dbProc: PDBPROCESS; Option: DBINT; Char_Param: PAnsiChar = nil; Int_Param: DBINT = -1): RETCODE; begin Result := SybaseAPI.dbSetOpt(dbProc, Option, Char_Param, Int_Param); end; function TZDBLibSybaseASE125PlainDriver.dbClose(dbProc: PDBPROCESS): RETCODE; begin Result := SybaseAPI.dbClose(dbProc); end; function TZDBLibSybaseASE125PlainDriver.dbName(dbProc: PDBPROCESS): PAnsiChar; begin Result := SybaseAPI.dbName(dbProc); end; function TZDBLibSybaseASE125PlainDriver.dbCmdRow(dbProc: PDBPROCESS): RETCODE; begin Result := SybaseAPI.dbCmdRow(dbProc); end; function TZDBLibSybaseASE125PlainDriver.dbNumCols(dbProc: PDBPROCESS): DBINT; begin Result := SybaseAPI.dbNumCols(dbProc); end; function TZDBLibSybaseASE125PlainDriver.dbColName(dbProc: PDBPROCESS; Column: DBINT): PAnsiChar; begin Result := SybaseAPI.dbColName(dbProc, Column); end; function TZDBLibSybaseASE125PlainDriver.dbColType(dbProc: PDBPROCESS; Column: DBINT): DBINT; begin Result := SybaseAPI.dbColType(dbProc, Column); end; function TZDBLibSybaseASE125PlainDriver.dbColLen(dbProc: PDBPROCESS; Column: DBINT): DBInt; begin Result := SybaseAPI.dbColLen(dbProc, Column); end; function TZDBLibSybaseASE125PlainDriver.dbData(dbProc: PDBPROCESS; Column: DBINT): PByte; begin Result := SybaseAPI.dbData(dbProc, Column); end; function TZDBLibSybaseASE125PlainDriver.dbDatLen(dbProc: PDBPROCESS; Column: DBINT): DBINT; begin Result := SybaseAPI.dbDatLen(dbProc, Column); end; function TZDBLibSybaseASE125PlainDriver.dbConvert(dbProc: PDBPROCESS; SrcType: DBINT; Src: PByte; SrcLen: DBINT; DestType: DBINT; Dest: PByte; DestLen: DBINT): DBINT; begin Result := SybaseAPI.dbConvert(dbProc, SrcType, Src, SrcLen, DestType, Dest, DestLen); end; function TZDBLibSybaseASE125PlainDriver.dbNextRow(dbProc: PDBPROCESS): STATUS; begin Result := SybaseAPI.dbNextRow(dbProc); end; function TZDBLibSybaseASE125PlainDriver.dbGetRow(dbProc: PDBPROCESS; Row: DBINT): STATUS; begin Result := SybaseAPI.dbGetRow(dbProc, Row); end; function TZDBLibSybaseASE125PlainDriver.dbCount(dbProc: PDBPROCESS): DBINT; begin Result := SybaseAPI.dbCount(dbProc); end; function TZDBLibSybaseASE125PlainDriver.dbRpcInit(dbProc: PDBPROCESS; RpcName: PAnsiChar; Options: SmallInt): RETCODE; begin Result := SybaseAPI.dbRpcInit(dbProc, RpcName, Options); end; function TZDBLibSybaseASE125PlainDriver.dbRpcParam(dbProc: PDBPROCESS; ParamName: PAnsiChar; Status: Byte; Type_: DBINT; MaxLen: DBINT; DataLen: DBINT; Value: Pointer): RETCODE; begin Result := SybaseAPI.dbRpcParam(dbProc, ParamName, Status, Type_, MaxLen, DataLen, Value); end; function TZDBLibSybaseASE125PlainDriver.dbRpcSend(dbProc: PDBPROCESS): RETCODE; begin Result := SybaseAPI.dbRpcSend(dbProc); end; function TZDBLibSybaseASE125PlainDriver.dbRpcExec(dbProc: PDBPROCESS): RETCODE; begin Result := SybaseAPI.dbRpcSend(dbProc); if Result = SUCCEED then Result := SybaseAPI.dbSqlOk(dbProc); end; function TZDBLibSybaseASE125PlainDriver.dbRetStatus(dbProc: PDBPROCESS): DBINT; begin Result := SybaseAPI.dbRetStatus(dbProc); end; function TZDBLibSybaseASE125PlainDriver.dbHasRetStat(dbProc: PDBPROCESS): Boolean; begin Result := SybaseAPI.dbHasRetStat(dbProc); end; function TZDBLibSybaseASE125PlainDriver.dbRetName(dbProc: PDBPROCESS; RetNum: DBINT): PAnsiChar; begin Result := SybaseAPI.dbRetName(dbProc, RetNum); end; function TZDBLibSybaseASE125PlainDriver.dbRetData(dbProc: PDBPROCESS; RetNum: DBINT): Pointer; begin Result := SybaseAPI.dbRetData(dbProc, RetNum); end; function TZDBLibSybaseASE125PlainDriver.dbRetLen(dbProc: PDBPROCESS; RetNum: DBINT): DBINT; begin Result := SybaseAPI.dbRetLen(dbProc, RetNum); end; function TZDBLibSybaseASE125PlainDriver.dbRetType(dbProc: PDBPROCESS; RetNum: DBINT): DBINT; begin Result := SybaseAPI.dbRetType(dbProc, RetNum); end; function TZDBLibSybaseASE125PlainDriver.dbrbuf(Proc: PDBPROCESS): DBINT; begin Result := 0; end; function TZDBLibSybaseASE125PlainDriver.dbdataready(Proc: PDBPROCESS): LongBool; begin Result := Proc <> nil; end; {TZDBLibMSSQL7PlainDriver} procedure TZDBLibMSSQL7PlainDriver.LoadApi; begin inherited LoadAPI; { ************** Load adresses of API Functions ************* } with Loader do begin //@MsSQLAPI.dbtablecolinfo := GetAddress('dbtablecolinfo'); @MsSQLAPI.dbdataready := GetAddress('dbdataready'); @MsSQLAPI.dbdatecrack := GetAddress('dbdatecrack'); @MsSQLAPI.dbdatlen := GetAddress('dbdatlen'); @MsSQLAPI.dbdead := GetAddress('dbdead'); @MsSQLAPI.dbclose := GetAddress('dbclose'); @MsSQLAPI.dbcolbrowse := GetAddress('dbcolbrowse'); @MsSQLAPI.dbcolinfo := GetAddress('dbcolinfo'); @MsSQLAPI.dbcount := GetAddress('dbcount'); @MsSQLAPI.dbcursorbind := GetAddress('dbcursorbind'); @MsSQLAPI.dbcursorclose := GetAddress('dbcursorclose'); @MsSQLAPI.dbcursorcolinfo := GetAddress('dbcursorcolinfo'); @MsSQLAPI.dbcursorfetch := GetAddress('dbcursorfetch'); @MsSQLAPI.dbcursorfetchex := GetAddress('dbcursorfetchex'); @MsSQLAPI.dbcursorinfo := GetAddress('dbcursorinfo'); @MsSQLAPI.dbcursorinfoex := GetAddress('dbcursorinfoex'); @MsSQLAPI.dbcursoropen := GetAddress('dbcursoropen'); @MsSQLAPI.dbWinexit := GetAddress('dbwinexit'); @MsSQLAPI.dbenlisttrans := GetAddress('dbenlisttrans'); @MsSQLAPI.dbenlistxatrans := GetAddress('dbenlistxatrans'); @MsSQLAPI.dbfreelogin := GetAddress('dbfreelogin'); @MsSQLAPI.dbgetmaxprocs := GetAddress('dbgetmaxprocs'); @MsSQLAPI.dbgetpacket := GetAddress('dbgetpacket'); @MsSQLAPI.dbgetuserdata := GetAddress('dbgetuserdata'); @MsSQLAPI.dbhasretstat := GetAddress('dbhasretstat'); @MsSQLAPI.dbinit := GetAddress('dbinit'); @MsSQLAPI.dbisavail := GetAddress('dbisavail'); @MsSQLAPI.dbisopt := GetAddress('dbisopt'); @MsSQLAPI.dbprocinfo := GetAddress('dbprocinfo'); @MsSQLAPI.dbrpcexec := GetAddress('dbrpcexec'); @MsSQLAPI.dbserverenum := GetAddress('dbserverenum'); @MsSQLAPI.dbsetmaxprocs := GetAddress('dbsetmaxprocs'); @MsSQLAPI.dbsetlpacket := GetAddress('dbsetlpacket'); @MsSQLAPI.dbsetopt := GetAddress('dbsetopt'); @MsSQLAPI.dbtabbrowse := GetAddress('dbtabbrowse'); @MsSQLAPI.dbvarylen := GetAddress('dbvarylen'); @MsSQLAPI.dbwillconvert := GetAddress('dbwillconvert'); @MsSQLAPI.dbupdatetext := GetAddress('dbupdatetext'); MsSQLAPI.dbinit; end; OldMsSQLErrorHandle := DBLibAPI.dberrhandle(DbLibErrorHandle); OldMsSQLMessageHandle := DBLibAPI.dbmsghandle(DbLibMessageHandle); end; function TZDBLibMSSQL7PlainDriver.Clone: IZPlainDriver; begin Result := TZDBLibMSSQL7PlainDriver.Create; end; constructor TZDBLibMSSQL7PlainDriver.Create; begin inherited Create; Loader.AddLocation(NTWDBLIB_DLL_LOCATION); DBVariables.DBoptions[Z_PARSEONLY] := DBLIBDBPARSEONLY; DBVariables.DBoptions[Z_SHOWPLAN] := DBLIBDBSHOWPLAN; DBVariables.DBoptions[Z_NOEXEC] := DBLIBDBNOEXEC; DBVariables.DBoptions[Z_ARITHIGNORE] := DBLIBDBARITHIGNORE; DBVariables.DBoptions[Z_NOCOUNT] := DBLIBDBNOCOUNT; DBVariables.DBoptions[Z_ARITHABORT] := DBLIBDBARITHABORT; DBVariables.DBoptions[Z_TEXTLIMIT] := DBLIBDBTEXTLIMIT; DBVariables.DBoptions[Z_OFFSET] := DBLIBDBOFFSET; DBVariables.DBoptions[Z_STAT] := DBLIBDBSTAT; DBVariables.DBoptions[Z_STORPROCID] := DBLIBDBSTORPROCID; DBVariables.DBoptions[Z_BUFFER] := DBLIBDBBUFFER; DBVariables.DBoptions[Z_NOAUTOFREE] := DBLIBDBNOAUTOFREE; DBVariables.DBoptions[Z_ROWCOUNT] := DBLIBDBROWCOUNT; DBVariables.DBoptions[Z_TEXTSIZE] := DBLIBDBTEXTSIZE; DBVariables.DBoptions[Z_CLIENTCURSORS] := DBLIBDBCLIENTCURSORS; DBVariables.DBoptions[Z_SETTIME] := DBLIBDBSET_TIME; DBVariables.DBoptions[Z_QUOTEDIDENT] := DBLIBDBQUOTEDIDENT; DBVariables.DBoptions[Z_ANSITOOEM] := DBLIBDBANSITOOEM; DBVariables.DBoptions[Z_OEMTOANSI] := DBLIBDBOEMTOANSI; {MsSQL Loginrec manipulations} DBVariables.DBSetLoginRec[Z_SETHOST] := MSDBSETHOST; DBVariables.DBSetLoginRec[Z_SETUSER] := MSDBSETUSER; DBVariables.DBSetLoginRec[Z_SETPWD] := MSDBSETPWD; DBVariables.DBSetLoginRec[Z_SETHID] := MSDBSETID; DBVariables.DBSetLoginRec[Z_SETAPP] := MSDBSETAPP; DBVariables.DBSetLoginRec[Z_SETSECURE] := MSDBSETSECURE; DBVariables.DBSetLoginRec[Z_SETLANG] := MSDBSETLANG; DBVariables.DBSetLoginRec[Z_SETLOGINTIME]:= MSDBSET_LOGIN_TIME; DBVariables.DBSetLoginRec[Z_SETFALLBACK]:= MSDBSETFALLBACK; LoadCodePages; end; destructor TZDBLibMSSQL7PlainDriver.Destroy; begin if Loader.Loaded then begin DbLibAPI.dberrhandle(DbLibErrorHandle); DbLibAPI.dbmsghandle(DbLibMessageHandle); MsSQLAPI.dbWinexit; DbLibAPI.dbExit; end; inherited Destroy; end; procedure TZDBLibMSSQL7PlainDriver.LoadCodePages; begin AddmMSCodePages(Self); end; function TZDBLibMSSQL7PlainDriver.GetProtocol: string; begin Result := 'mssql'; end; function TZDBLibMSSQL7PlainDriver.GetDescription: string; begin Result := 'Native dblib driver for MS SQL 7+'; end; function TZDBLibMSSQL7PlainDriver.dbsetlsecure(Login: PLOGINREC): RETCODE; begin Result := DBLibAPI.dbsetlname(Login, nil, Self.DBVariables.dbSetLoginRec[Z_SETSECURE]); end; function TZDBLibMSSQL7PlainDriver.dbcolbrowse(Proc: PDBPROCESS; Column: Integer): LongBool; begin Result := MsSQLAPI.dbcolbrowse(Proc, Column); end; function TZDBLibMSSQL7PlainDriver.dbDead(dbProc: PDBPROCESS): Boolean; begin Result := MsSQLAPI.dbDead(dbProc); end; procedure TZDBLibMSSQL7PlainDriver.dbLoginFree(Login: PLOGINREC); begin MsSQLAPI.dbfreelogin(Login); end; function TZDBLibMSSQL7PlainDriver.dbSetLCharSet(Login: PLOGINREC; CharsetName: PAnsiChar): RETCODE; begin Result := DBFAIL; end; function TZDBLibMSSQL7PlainDriver.dbsetmaxprocs( MaxProcs: SmallInt): RETCODE; begin Result := MsSQLAPI.dbsetmaxprocs(MaxProcs); end; function TZDBLibMSSQL7PlainDriver.dbSqlExecAsync(dbProc: PDBPROCESS): RETCODE; var lStartTick : Int64; begin Result := DBLibAPI.dbsqlsend(dbProc); if Result = SUCCEED then begin lStartTick := {$IFDEF FPC}GetMsCount{$ELSE}GetTickCount{$ENDIF}; repeat continue; until ({$IFDEF FPC}GetMsCount{$ELSE}GetTickCount{$ENDIF} > lStartTick + TIMEOUT_MAXIMUM * 1000) or (MsSQLAPI.dbdataready(dbProc) = TRUE); Result := DBLibAPI.dbsqlok(dbProc); end; end; function TZDBLibMSSQL7PlainDriver.dbSetOpt(dbProc: PDBPROCESS; Option: DBINT; Char_Param: PAnsiChar = nil; Int_Param: DBINT = -1): RETCODE; begin Result := MsSQLAPI.dbSetOpt(dbProc, Option, Char_Param); end; function TZDBLibMSSQL7PlainDriver.dbClose(dbProc: PDBPROCESS): RETCODE; begin Result := MsSQLAPI.dbClose(dbProc); end; function TZDBLibMSSQL7PlainDriver.dbDatLen(dbProc: PDBPROCESS; Column: DBINT): DBINT; begin Result := MsSQLAPI.dbDatLen(dbProc, Column); end; function TZDBLibMSSQL7PlainDriver.dbCount(dbProc: PDBPROCESS): DBINT; begin Result := MsSQLAPI.dbCount(dbProc); end; function TZDBLibMSSQL7PlainDriver.dbHasRetStat(dbProc: PDBPROCESS): Boolean; begin Result := MsSQLAPI.dbHasRetStat(dbProc); end; function TZDBLibMSSQL7PlainDriver.dbdataready(Proc: PDBPROCESS): LongBool; begin Result := MsSQLAPI.dbdataready(Proc); end; { TFreeTGDBasePlainDriver } { TZFreeTDSBasePlainDriver } procedure TZFreeTDSBasePlainDriver.LoadApi; begin inherited LoadAPI; with Loader do begin @FreeTDSAPI.db12hour := GetAddress('db12hour'); @FreeTDSAPI.dbaltbind_ps := GetAddress('dbaltbind_ps'); @FreeTDSAPI.dbbufsize := GetAddress('dbbufsize'); @FreeTDSAPI.dbclose := GetAddress('dbclose'); @FreeTDSAPI.dbtablecolinfo := GetAddress('dbtablecolinfo'); @FreeTDSAPI.dbcolbrowse := GetAddress('dbcolbrowse'); @FreeTDSAPI.dbcolinfo := GetAddress('dbcolinfo'); @FreeTDSAPI.dbconvert_ps := GetAddress('dbconvert_ps'); @FreeTDSAPI.dbcount := GetAddress('dbcount'); @FreeTDSAPI.dbdatecmp := GetAddress('dbdatecmp'); @FreeTDSAPI.dbdatecrack := GetAddress('dbdatecrack'); @FreeTDSAPI.dbdatlen := GetAddress('dbdatlen'); @FreeTDSAPI.dbdead := GetAddress('dbdead'); @FreeTDSAPI.dbgetcharset := GetAddress('dbgetcharset'); @FreeTDSAPI.dbgetlusername := GetAddress('dbgetlusername'); @FreeTDSAPI.dbgetmaxprocs := GetAddress('dbgetmaxprocs'); @FreeTDSAPI.dbgetnatlanf := GetAddress('dbgetnatlanf'); @FreeTDSAPI.dbgetpacket := GetAddress('dbgetpacket'); @FreeTDSAPI.dbgetuserdata := GetAddress('dbgetuserdata'); @FreeTDSAPI.dbhasretstat := GetAddress('dbhasretstat'); @FreeTDSAPI.dbinit := GetAddress('dbinit'); @FreeTDSAPI.dbiordesc := GetAddress('dbiordesc'); @FreeTDSAPI.dbiowdesc := GetAddress('dbiowdesc'); @FreeTDSAPI.dbisavail := GetAddress('dbisavail'); @FreeTDSAPI.dbisopt := GetAddress('dbisopt'); @FreeTDSAPI.dbloginfree := GetAddress('dbloginfree'); @FreeTDSAPI.dbmny4cmp := GetAddress('dbmny4cmp'); @FreeTDSAPI.dbmnycmp := GetAddress('dbmnycmp'); @FreeTDSAPI.dbmny4add := GetAddress('dbmny4add'); @FreeTDSAPI.dbmnydec := GetAddress('dbmnydec'); @FreeTDSAPI.dbmnyinc := GetAddress('dbmnyinc'); @FreeTDSAPI.dbmnymaxpos := GetAddress('dbmnymaxpos'); @FreeTDSAPI.dbmnymaxneg := GetAddress('dbmnymaxneg'); @FreeTDSAPI.dbmny4minus := GetAddress('dbmny4minus'); @FreeTDSAPI.dbmnyminus := GetAddress('dbmnyminus'); @FreeTDSAPI.dbmny4sub := GetAddress('dbmny4sub'); @FreeTDSAPI.dbmnysub := GetAddress('dbmnysub'); @FreeTDSAPI.dbmny4copy := GetAddress('dbmny4copy'); @FreeTDSAPI.dbmnycopy := GetAddress('dbmnycopy'); @FreeTDSAPI.dbmny4zero := GetAddress('dbmny4zero'); @FreeTDSAPI.dbmnyzero := GetAddress('dbmnyzero'); @FreeTDSAPI.dbmonthname := GetAddress('dbmonthname'); @FreeTDSAPI.tdsdbopen := GetAddress('tdsdbopen'); @FreeTDSAPI.DRBUF := GetAddress('DRBUF'); @FreeTDSAPI.dbrecftos := GetAddress('dbrecftos'); @FreeTDSAPI.dbresults_r := GetAddress('dbresults_r'); //@FreeTDSAPI.dbsechandle := GetAddress('dbsechandle'); @FreeTDSAPI.dbservcharset := GetAddress('dbservcharset'); @FreeTDSAPI.dbsafestr := GetAddress('dbsafestr'); //@FreeTDSAPI.dbsetbusy := GetAddress('dbsetbusy'); @FreeTDSAPI.dbsetdefcharset := GetAddress('dbsetdefcharset'); @FreeTDSAPI.dbsetifile := GetAddress('dbsetifile'); //@FreeTDSAPI.dbsetinterrupt := GetAddress('dbsetinterrupt'); @FreeTDSAPI.dbsetmaxprocs := GetAddress('dbsetmaxprocs'); @FreeTDSAPI.dbsetopt := GetAddress('dbsetopt'); @FreeTDSAPI.dbsetrow := GetAddress('dbsetrow'); @FreeTDSAPI.dbsetversion := GetAddress('dbsetversion'); @FreeTDSAPI.dbspid := GetAddress('dbspid'); @FreeTDSAPI.dbspr1row := GetAddress('dbspr1row'); @FreeTDSAPI.dbspr1rowlen := GetAddress('dbspr1rowlen'); @FreeTDSAPI.dbsprhead := GetAddress('dbsprhead'); @FreeTDSAPI.dbsprline := GetAddress('dbsprline'); @FreeTDSAPI.dbvarylen := GetAddress('dbvarylen'); @FreeTDSAPI.dbtds := GetAddress('dbtds'); @FreeTDSAPI.dbtextsize := GetAddress('dbtextsize'); @FreeTDSAPI.dbwillconvert := GetAddress('dbwillconvert'); (* LOGINREC manipulation *) @FreeTDSAPI.dbsetlbool := GetAddress('dbsetlbool'); @FreeTDSAPI.dbsetllong := GetAddress('dbsetllong'); @FreeTDSAPI.dbsetlversion := GetAddress('dbsetlversion'); @FreeTDSAPI.tdsdump_open := GetAddress('tdsdump_open'); @FreeTDSAPI.tdsdump_on := GetAddress('tdsdump_on'); @FreeTDSAPI.tdsdump_off := GetAddress('tdsdump_off'); @FreeTDSAPI.tdsdump_close := GetAddress('tdsdump_close'); end; FreeTDSAPI.dbinit; OldFreeTDSErrorHandle := DBLibAPI.dberrhandle(DbLibErrorHandle); OldFreeTDSMessageHandle := DBLibAPI.dbmsghandle(DbLibMessageHandle); end; constructor TZFreeTDSBasePlainDriver.Create; begin inherited create; DBVariables.DBoptions[Z_PARSEONLY] := TDSPARSEONLY; DBVariables.DBoptions[Z_ESTIMATE] := TDSESTIMATE; DBVariables.DBoptions[Z_SHOWPLAN] := TDSSHOWPLAN; DBVariables.DBoptions[Z_NOEXEC] := TDSNOEXEC; DBVariables.DBoptions[Z_ARITHIGNORE] := TDSARITHIGNORE; DBVariables.DBoptions[Z_NOCOUNT] := TDSNOCOUNT; DBVariables.DBoptions[Z_ARITHABORT] := TDSARITHABORT; DBVariables.DBoptions[Z_TEXTLIMIT] := TDSTEXTLIMIT; DBVariables.DBoptions[Z_BROWSE] := TDSBROWSE; DBVariables.DBoptions[Z_OFFSET] := TDSOFFSET; DBVariables.DBoptions[Z_STAT] := TDSSTAT; DBVariables.DBoptions[Z_ERRLVL] := TDSERRLVL; DBVariables.DBoptions[Z_CONFIRM] := TDSCONFIRM; DBVariables.DBoptions[Z_STORPROCID] := TDSSTORPROCID; DBVariables.DBoptions[Z_BUFFER] := TDSBUFFER; DBVariables.DBoptions[Z_NOAUTOFREE] := TDSNOAUTOFREE; DBVariables.DBoptions[Z_ROWCOUNT] := TDSROWCOUNT; DBVariables.DBoptions[Z_TEXTSIZE] := TDSTEXTSIZE; DBVariables.DBoptions[Z_NATLANG] := TDSNATLANG; DBVariables.DBoptions[Z_DATEFORMAT] := TDSDATEFORMAT; DBVariables.DBoptions[Z_PRPAD] := TDSPRPAD; DBVariables.DBoptions[Z_PRCOLSEP] := TDSPRCOLSEP; DBVariables.DBoptions[Z_PRLINELEN] := TDSPRLINELEN; DBVariables.DBoptions[Z_PRLINESEP] := TDSPRLINESEP; DBVariables.DBoptions[Z_LFCONVERT] := TDSLFCONVERT; DBVariables.DBoptions[Z_DATEFIRST] := TDSDATEFIRST; DBVariables.DBoptions[Z_CHAINXACTS] := TDSCHAINXACTS; DBVariables.DBoptions[Z_FIPSFLAG] := TDSFIPSFLAG; DBVariables.DBoptions[Z_ISOLATION] := TDSISOLATION; DBVariables.DBoptions[Z_AUTH] := TDSAUTH; DBVariables.DBoptions[Z_IDENTITY] := TDSIDENTITY; DBVariables.DBoptions[Z_NOIDCOL] := TDSNOIDCOL; DBVariables.DBoptions[Z_DATESHORT] := TDSDATESHORT; DBVariables.DBoptions[Z_CLIENTCURSORS] := TDSCLIENTCURSORS; DBVariables.DBoptions[Z_SETTIME] := TDSSETTIME; DBVariables.DBoptions[Z_QUOTEDIDENT] := TDSQUOTEDIDENT; DBVariables.DBoptions[Z_NUMOPTIONS] := TDSNUMOPTIONS; DBVariables.DBoptions[Z_PADOFF] := TDSPADOFF; DBVariables.DBoptions[Z_PADON] := TDSPADON; DBVariables.DBoptions[Z_OFF] := TDSOFF; DBVariables.DBoptions[Z_ON] := TDSON; DBVariables.DBoptions[Z_NOSUCHOPTION] := NOSUCHOPTION; DBVariables.DBoptions[Z_MAXOPTTEXT] := MAXOPTTEXT; {TDS Loginrec manipulations} DBVariables.DBSetLoginRec[Z_SETHOST] := TDSDBSETHOST; DBVariables.DBSetLoginRec[Z_SETUSER] := TDSDBSETUSER; DBVariables.DBSetLoginRec[Z_SETPWD] := TDSDBSETPWD; DBVariables.DBSetLoginRec[Z_SETHID] := TDSDBSETHID; DBVariables.DBSetLoginRec[Z_SETAPP] := TDSDBSETAPP; DBVariables.DBSetLoginRec[Z_SETBCP] := TDSDBSETBCP; DBVariables.DBSetLoginRec[Z_SETSECURE] := TDSDBSETSECURE; DBVariables.DBSetLoginRec[Z_SETLANG] := TDSDBSETLANG; DBVariables.DBSetLoginRec[Z_SETNOSHORT] := TDSDBSETNOSHORT; DBVariables.DBSetLoginRec[Z_SETHIER] := TDSDBSETHIER; DBVariables.DBSetLoginRec[Z_SETCHARSET] := TDSDBSETCHARSET; DBVariables.DBSetLoginRec[Z_SETPACKET] := TDSDBSETPACKET; DBVariables.DBSetLoginRec[Z_SETENCRYPT] := TDSDBSETENCRYPT; DBVariables.DBSetLoginRec[Z_SETLABELED] := TDSDBSETLABELED; DBVariables.DBSetLoginRec[Z_SETDBNAME] := TDSDBSETDBNAME; {datatypes} DBVariables.datatypes[Z_SQLVOID] := TDSSQLVOID; DBVariables.datatypes[Z_SQLTEXT] := TDSSQLTEXT; DBVariables.datatypes[Z_SQLVARBINARY] := TDSSQLVARBINARY; DBVariables.datatypes[Z_SQLINTN] := TDSSQLINTN; DBVariables.datatypes[Z_SQLVARCHAR] := TDSSQLVARCHAR; DBVariables.datatypes[Z_SQLBINARY] := TDSSQLBINARY; DBVariables.datatypes[Z_SQLIMAGE] := TDSSQLIMAGE; DBVariables.datatypes[Z_SQLCHAR] := TDSSQLCHAR; DBVariables.datatypes[Z_SQLINT1] := TDSSQLINT1; DBVariables.datatypes[Z_SQLBIT] := TDSSQLBIT; DBVariables.datatypes[Z_SQLINT2] := TDSSQLINT2; DBVariables.datatypes[Z_SQLINT4] := TDSSQLINT4; DBVariables.datatypes[Z_SQLMONEY] := TDSSQLMONEY; DBVariables.datatypes[Z_SQLDATETIME] := TDSSQLDATETIME; DBVariables.datatypes[Z_SQLFLT8] := TDSSQLFLT8; DBVariables.datatypes[Z_SQLFLTN] := TDSSQLFLTN; DBVariables.datatypes[Z_SQLMONEYN] := TDSSQLMONEYN; DBVariables.datatypes[Z_SQLDATETIMN] := TDSSQLDATETIMN; DBVariables.datatypes[Z_SQLFLT4] := TDSSQLFLT4; DBVariables.datatypes[Z_SQLMONEY4] := TDSSQLMONEY4; DBVariables.datatypes[Z_SQLDATETIM4] := TDSSQLDATETIM4; DBVariables.datatypes[Z_SQLDECIMAL] := TDSSQLDECIMAL; DBVariables.datatypes[Z_SQLNUMERIC] := TDSSQLNUMERIC; end; destructor TZFreeTDSBasePlainDriver.Destroy; begin if Loader.Loaded then begin DBLibAPI.dberrhandle(OldFreeTDSErrorHandle); DBLibAPI.dbmsghandle(OldFreeTDSMessageHandle); DBLibAPI.dbexit; end; inherited Destroy; end; function TZFreeTDSBasePlainDriver.GetProtocol: string; begin Result := 'FreeTDS'; end; function TZFreeTDSBasePlainDriver.GetDescription: string; begin Result := 'Native FreeTDS driver for Sybase and MSSQL Servers'; end; function TZFreeTDSBasePlainDriver.dbLogin: PLOGINREC; begin Result := inherited dbLogin; if not Assigned(Result) then if not (dbsetlversion(Result) = DBSUCCEED ) then begin dbloginfree(Result); Result := nil; end; end; function TZFreeTDSBasePlainDriver.dbSetLCharSet(Login: PLOGINREC; CharsetName: PAnsiChar): RETCODE; begin Result := DBLibAPI.dbsetlname(Login, CharsetName, DBVariables.dbSetLoginRec[Z_SETCHARSET]); end; function TZFreeTDSBasePlainDriver.dbSetLSecure(Login: PLOGINREC): RETCODE; begin Result := DBLibAPI.dbsetlname(Login, nil, DBVariables.dbSetLoginRec[Z_SETSECURE]); // Result := FreeTDSAPI.dbsetlbool(Login, 1, Self.DBVariables.dbSetLoginRec[Z_SETSECURE]); end; function TZFreeTDSBasePlainDriver.dbsetlversion(Login: PLOGINREC): RETCODE; begin Result := FreeTDSAPI.dbsetlversion(Login, TDSDBVERSION_UNKNOWN); end; function TZFreeTDSBasePlainDriver.dbsetversion: RETCODE; begin Result := FreeTDSAPI.dbsetversion(TDSDBVERSION_UNKNOWN); end; procedure TZFreeTDSBasePlainDriver.tdsDumpOff; begin FreeTDSAPI.tdsdump_off(); end; procedure TZFreeTDSBasePlainDriver.tdsDumpOn; begin FreeTDSAPI.tdsdump_on(); end; procedure TZFreeTDSBasePlainDriver.tdsDump_Close; begin FreeTDSAPI.tdsdump_close(); end; procedure TZFreeTDSBasePlainDriver.tdsDump_Open(const FileName: String); begin FreeTDSAPI.tdsdump_open(PAnsiChar( AnsiString(FileName) )); end; function TZFreeTDSBasePlainDriver.dbdataready(Proc: PDBPROCESS): LongBool; begin Result := Proc <> nil; end; procedure TZFreeTDSBasePlainDriver.dbfreelogin(Login: PLOGINREC); begin FreeTDSAPI.dbloginfree(Login); end; function TZFreeTDSBasePlainDriver.dbDead(dbProc: PDBPROCESS): Boolean; begin Result := FreeTDSAPI.dbDead(dbProc) = 1; end; procedure TZFreeTDSBasePlainDriver.dbLoginFree(Login: PLOGINREC); begin FreeTDSAPI.dbloginfree(Login); end; function TZFreeTDSBasePlainDriver.dbsetmaxprocs( MaxProcs: SmallInt): RETCODE; begin Result := FreeTDSAPI.dbsetmaxprocs(MaxProcs); end; function TZFreeTDSBasePlainDriver.dbSetOpt(dbProc: PDBPROCESS; Option: Integer; Char_Param: PAnsiChar = nil; Int_Param: Integer = -1): RETCODE; begin Result := FreeTDSAPI.dbSetOpt(dbProc, Option, Char_Param, Int_Param); end; function TZFreeTDSBasePlainDriver.dbSetTime(queryTime: Integer): RETCODE; begin Result := FreeTDSAPI.dbsetmaxprocs(queryTime); end; function TZFreeTDSBasePlainDriver.dbClose(dbProc: PDBPROCESS): RETCODE; begin FreeTDSAPI.dbClose(dbProc); Result := DBNOERR; end; function TZFreeTDSBasePlainDriver.dbDatLen(dbProc: PDBPROCESS; Column: Integer): Integer; begin Result := FreeTDSAPI.dbDatLen(dbProc, Column); end; function TZFreeTDSBasePlainDriver.dbCount(dbProc: PDBPROCESS): Integer; begin Result := FreeTDSAPI.dbCount(dbProc); end; function TZFreeTDSBasePlainDriver.dbcolbrowse(Proc: PDBPROCESS; Column: Integer): LongBool; begin Result := FreeTDSAPI.dbcolbrowse(Proc, Column) <> 0; end; function TZFreeTDSBasePlainDriver.dbHasRetStat(dbProc: PDBPROCESS): Boolean; begin if Assigned(FreeTDSAPI.dbHasRetStat) then Result := FreeTDSAPI.dbHasRetStat(dbProc) <> 0 else Result := False; end; function TZFreeTDSBasePlainDriver.dbColInfo(dbProc: PDBPROCESS; Column: Integer; var ADBInfo: DBCOL): RETCODE; begin FillChar(ADBInfo, SizeOf(DBCol), #0); ADBInfo.SizeOfStruct := SizeOf(DBCol); Result := FreeTDSAPI.dbcolinfo(dbProc, CI_REGULAR, Column, 0, @ADBInfo); end; { TZFreeTDS42MsSQLPlainDriver } function TZFreeTDS42MsSQLPlainDriver.Clone: IZPlainDriver; begin Result := TZFreeTDS42MsSQLPlainDriver.Create; end; procedure TZFreeTDS42MsSQLPlainDriver.LoadCodePages; begin AddmMSCodePages(Self); end; constructor TZFreeTDS42MsSQLPlainDriver.Create; begin inherited Create; {$IFDEF MSWINDOWS} FLoader.AddLocation(FREETDS_MSSQL_WINDOWS_DLL_LOCATION); {$ELSE} {$IFDEF UNIX} FLoader.AddLocation(FREETDS_LINUX_DLL_LOCATION); {$ELSE} FLoader.AddLocation(FREETDS_OSX_DLL_LOCATION); {$ENDIF} {$ENDIF} LoadCodePages; end; function TZFreeTDS42MsSQLPlainDriver.GetProtocol: string; begin Result := 'FreeTDS_MsSQL<=6.5'; end; function TZFreeTDS42MsSQLPlainDriver.GetDescription: string; begin Result := 'FreeTDS 4.2 protocol for MsSQL <=6.5 Servers'; end; function TZFreeTDS42MsSQLPlainDriver.dbsetlversion(Login: PLOGINREC): RETCODE; begin Result := FreeTDSAPI.dbsetlversion(Login, DBVERSION_42); end; function TZFreeTDS42MsSQLPlainDriver.dbsetversion: RETCODE; begin Result := FreeTDSAPI.dbsetversion(TDSDBVERSION_42); end; { TZFreeTDS42SybasePlainDriver } function TZFreeTDS42SybasePlainDriver.Clone: IZPlainDriver; begin Result := TZFreeTDS42SybasePlainDriver.Create; end; procedure TZFreeTDS42SybasePlainDriver.LoadCodePages; begin AddCodePage('Not implemented!', -1); { TODO -oEgonHugeist : Must be completed!!!! } end; constructor TZFreeTDS42SybasePlainDriver.Create; begin inherited Create; {$IFDEF MSWINDOWS} FLoader.AddLocation(FREETDS_SYBASE_WINDOWS_DLL_LOCATION); {$ELSE} {$IFDEF UNIX} FLoader.AddLocation(FREETDS_LINUX_DLL_LOCATION); {$ELSE} FLoader.AddLocation(FREETDS_OSX_DLL_LOCATION); {$ENDIF} {$ENDIF} end; function TZFreeTDS42SybasePlainDriver.GetProtocol: string; begin Result := 'FreeTDS_Sybase<10'; end; function TZFreeTDS42SybasePlainDriver.GetDescription: string; begin Result := 'FreeTDS 4.2 protocol for Sybase <10 Servers'; end; function TZFreeTDS42SybasePlainDriver.dbsetlversion(Login: PLOGINREC): RETCODE; begin Result := DBSUCCEED; end; function TZFreeTDS42SybasePlainDriver.dbsetversion: RETCODE; begin Result := FreeTDSAPI.dbsetversion(TDSDBVERSION_42); end; { TZFreeTDS50PlainDriver } function TZFreeTDS50PlainDriver.Clone: IZPlainDriver; begin Result := TZFreeTDS50PlainDriver.Create; end; procedure TZFreeTDS50PlainDriver.LoadCodePages; begin AddSybaseCodePages(Self); end; constructor TZFreeTDS50PlainDriver.Create; begin inherited Create; LoadCodePages; end; function TZFreeTDS50PlainDriver.GetProtocol: string; begin Result := 'FreeTDS_Sybase-10+'; end; function TZFreeTDS50PlainDriver.GetDescription: string; begin Result := 'FreeTDS 5.0 Protocol for Sybase >= 10 Servers '; end; function TZFreeTDS50PlainDriver.dbsetversion: RETCODE; begin Result := FreeTDSAPI.dbsetversion(TDSDBVERSION_46); end; { TZFreeTDS70PlainDriver } function TZFreeTDS70PlainDriver.Clone: IZPlainDriver; begin Result := TZFreeTDS70PlainDriver.Create; end; procedure TZFreeTDS70PlainDriver.LoadCodePages; begin inherited; end; function TZFreeTDS70PlainDriver.GetProtocol: string; begin Result := 'FreeTDS_MsSQL-7.0'; end; function TZFreeTDS70PlainDriver.dbsetlversion(Login: PLOGINREC): RETCODE; begin Result := FreeTDSAPI.dbsetlversion(Login, DBVERSION_70); end; function TZFreeTDS70PlainDriver.GetDescription: string; begin Result := 'FreeTDS 7.0 Protocol for MsSQL 7.0 Servers'; end; function TZFreeTDS70PlainDriver.dbsetversion: RETCODE; begin Result := FreeTDSAPI.dbsetversion(TDSDBVERSION_70); end; { TZFreeTDS71PlainDriver } function TZFreeTDS71PlainDriver.Clone: IZPlainDriver; begin Result := TZFreeTDS71PlainDriver.Create; end; procedure TZFreeTDS71PlainDriver.LoadCodePages; begin Inherited; end; function TZFreeTDS71PlainDriver.GetProtocol: string; begin Result := 'FreeTDS_MsSQL-2000'; end; function TZFreeTDS71PlainDriver.GetDescription: string; begin Result := 'FreeTDS 7.1 Protocol for MsSQL 2000 Servers'; end; function TZFreeTDS71PlainDriver.dbsetversion: RETCODE; begin Result := FreeTDSAPI.dbsetversion(TDSDBVERSION_70); end; { TZFreeTDS72PlainDriver } function TZFreeTDS72PlainDriver.Clone: IZPlainDriver; begin Result := TZFreeTDS72PlainDriver.Create; end; procedure TZFreeTDS72PlainDriver.LoadCodePages; begin inherited; end; function TZFreeTDS72PlainDriver.GetProtocol: string; begin Result := 'FreeTDS_MsSQL>=2005'; end; function TZFreeTDS72PlainDriver.GetDescription: string; begin Result := 'FreeTDS 7.2 Protocol for MsSQL 2005, 2008, 2012 Servers'; end; function TZFreeTDS72PlainDriver.dbsetversion: RETCODE; begin Result := FreeTDSAPI.dbsetversion(TDSDBVERSION_72); end; initialization SQLErrors := TList.Create; SQLMessages := TList.Create; finalization //Free any record in the list if any while SQLErrors.Count > 0 do begin Dispose(SQLErrors.Items[0]); SQLErrors.Delete(0); end; if SQLErrors <> nil then FreeAndNil(SQLErrors); //Free any record in the list if any while SQLMessages.Count > 0 do begin Dispose(SQLMessages.Items[0]); SQLMessages.Delete(0); end; if SQLMessages <> nil then FreeAndNil(SQLMessages); end. ================================================ FILE: lib/zeosdbo/src/plain/ZPlainDriver.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Interfaces for Native Plain Drivers } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZPlainDriver; interface {$I ZPlain.inc} uses ZClasses, ZPlainLoader, ZCompatibility, Types, ZTokenizer; type {** Represents a generic interface to plain driver. } IZPlainDriver = interface (IZInterface) ['{2A0CC600-B3C4-43AF-92F5-C22A3BB1BB7D}'] function IsAnsiDriver: Boolean; function GetProtocol: string; function GetDescription: string; {EgonHugeist: Why this here? -> No one else then Plaindriver knows which Characterset is supported. Here i've made a intervention in dependency of used Compiler.} function GetSupportedClientCodePages(const {$IFNDEF UNICODE}AutoEncode,{$ENDIF} IgnoreUnsupported: Boolean; CtrlsCPType: TZControlsCodePage = cCP_UTF16): TStringDynArray; function ValidateCharEncoding(const CharacterSetName: String; const DoArrange: Boolean = False): PZCodePage; overload; function ValidateCharEncoding(const CharacterSetID: Integer; const DoArrange: Boolean = False): PZCodePage; overload; function ZDbcString(const Ansi: RawByteString; ConSettings: PZConSettings): String; function ZPlainString(const AStr: String; ConSettings: PZConSettings): RawByteString; overload; function ZPlainString(const AStr: WideString; ConSettings: PZConSettings): RawByteString; overload; function ZPlainString(const AStr: String; ConSettings: PZConSettings; const ToCP: Word): RawByteString; overload; function ZDbcUnicodeString(const AStr: RawByteString; const FromCP: Word): ZWideString; overload; function GetPrepreparedSQL(Handle: Pointer; const SQL: String; ConSettings: PZConSettings; out LogSQL: String): RawByteString; function EscapeString(Handle: Pointer; const Value: ZWideString; ConSettings: PZConSettings): ZWideString; overload; function EscapeString(Handle: Pointer; const Value: RawByteString; ConSettings: PZConSettings; WasEncoded: Boolean = False): RawByteString; overload; procedure Initialize(const Location: String = ''); function Clone: IZPlainDriver; end; {ADDED by fduenas 15-06-2006} {** Base class of a generic plain driver with TZNativeLibraryLoader-object. } TZAbstractPlainDriver = class(TZCodePagedObject, IZPlainDriver) protected FCodePages: array of TZCodePage; FTokenizer: IZTokenizer; FLoader: TZNativeLibraryLoader; procedure LoadApi; virtual; function IsAnsiDriver: Boolean; virtual; function Clone: IZPlainDriver; reintroduce; virtual; abstract; procedure LoadCodePages; virtual; abstract; function GetUnicodeCodePageName: String; virtual; function ValidateCharEncoding(const CharacterSetName: String; const DoArrange: Boolean = False): PZCodePage; overload; function ValidateCharEncoding(const CharacterSetID: Integer; const DoArrange: Boolean = False): PZCodePage; overload; function GetPrepreparedSQL(Handle: Pointer; const SQL: String; ConSettings: PZConSettings; out LogSQL: String): RawByteString; virtual; function EscapeString(Handle: Pointer; const Value: ZWideString; ConSettings: PZConSettings): ZWideString; overload; function EscapeString(Handle: Pointer; const Value: RawByteString; ConSettings: PZConSettings; WasEncoded: Boolean = False): RawByteString; overload; virtual; function GetTokenizer: IZTokenizer; public constructor Create; constructor CreateWithLibrary(const LibName : String); destructor Destroy; override; function GetProtocol: string; virtual; abstract; function GetDescription: string; virtual; abstract; function GetSupportedClientCodePages(const {$IFNDEF UNICODE}AutoEncode,{$ENDIF} IgnoreUnsupported: Boolean; CtrlsCPType: TZControlsCodePage = cCP_UTF16): TStringDynArray; procedure Initialize(const Location: String = ''); virtual; property Loader: TZNativeLibraryLoader read FLoader; procedure AddCodePage(const Name: String; const ID: Integer; Encoding: TZCharEncoding = ceAnsi; const CP: Word = $ffff; const ZAlias: String = ''; CharWidth: Integer = 1; const ConsistentCP: Boolean = True); procedure ResetCodePage(const OldID: Integer; const Name: String; const ID: Integer; {may be an ordinal value of predefined Types...} Encoding: TZCharEncoding = ceAnsi; const CP: Word = $ffff; const ZAlias: String = ''; CharWidth: Integer = 1; const ConsistentCP: Boolean = True); end; {END ADDED by fduenas 15-06-2006} implementation uses SysUtils, ZEncoding{$IFDEF WITH_UNITANSISTRINGS}, AnsiStrings{$ENDIF}; {TZAbstractPlainDriver} function TZAbstractPlainDriver.IsAnsiDriver: Boolean; begin Result := True; end; function TZAbstractPlainDriver.GetUnicodeCodePageName: String; begin Result := ''; end; {** Checks if the given ClientCharacterSet and returns the PZCodePage @param CharacterSetName the Name wich has to be validated @param DoArrange means if the CharacterSet is empty or unsupported then find a supported CodePage @result the PZCodePage of the ClientCharacterSet } function TZAbstractPlainDriver.ValidateCharEncoding(const CharacterSetName: String; const DoArrange: Boolean = False): PZCodePage; function GetClientCodePageInformations( const ClientCharacterSet: String): PZCodePage; var I: Integer; begin {now check for PlainDriver-Informations...} {$IFDEF FPC} //if the user didn't set it if ClientCharacterSet = '' then begin for i := Low(FCodePages) to high(FCodePages) do if UpperCase(FCodePages[i].Name) = UpperCase(GetUnicodeCodePageName) then begin Result := @FCodePages[i]; Exit; end; end else {$ENDIF} for i := Low(FCodePages) to high(FCodePages) do if UpperCase(FCodePages[i].Name) = UpperCase(ClientCharacterSet) then begin Result := @FCodePages[i]; Exit; end; Result := @ClientCodePageDummy; end; begin Result := GetClientCodePageInformations(CharacterSetName); if (DoArrange) and (Result^.ZAlias <> '' ) then ValidateCharEncoding(Result^.ZAlias); //recalls em selves end; {** Checks if the given ClientCharacterSet and returns the PZCodePage @param CharacterSetID the ID wich has to be validated @param DoArrange means if the CharacterSet is empty or unsupported then find a supported CodePage @result the PZCodePage of the ClientCharacterSet } function TZAbstractPlainDriver.ValidateCharEncoding(const CharacterSetID: Integer; const DoArrange: Boolean = False): PZCodePage; function GetClientCodePageInformations(const ClientCharacterSetID: Word): PZCodePage; var I: Integer; begin {now check for PlainDriver-Informations...} for i := Low(FCodePages) to high(FCodePages) do if FCodePages[i].ID = ClientCharacterSetID then begin Result := @FCodePages[i]; Exit; end; Result := @ClientCodePageDummy; end; begin Result := GetClientCodePageInformations(CharacterSetID); if (DoArrange) and (Result^.ZAlias <> '' ) then ValidateCharEncoding(Result^.ZAlias); //recalls em selves end; function TZAbstractPlainDriver.GetPrepreparedSQL(Handle: Pointer; const SQL: String; ConSettings: PZConSettings; out LogSQL: String): RawByteString; var SQLTokens: TZTokenDynArray; i: Integer; begin Result := ''; if ConSettings.AutoEncode then begin SQLTokens := FTokenizer.TokenizeBuffer(SQL, [toSkipEOF]); //Disassembles the Query for i := Low(SQLTokens) to high(SQLTokens) do //Assembles the Query begin case (SQLTokens[i].TokenType) of ttEscape: Result := Result + {$IFDEF UNICODE}ZPlainString(SQLTokens[i].Value, ConSettings){$ELSE}SQLTokens[i].Value{$ENDIF}; ttQuoted, ttWord, ttQuotedIdentifier, ttKeyword: Result := Result + ZPlainString(SQLTokens[i].Value, ConSettings) else Result := Result + RawByteString(SQLTokens[i].Value); end; end; end else {$IFDEF UNICODE} Result := ZPlainString(SQL, ConSettings); {$ELSE} Result := SQL; {$ENDIF} LogSQL := String(Result); end; {$IFDEF FPC} {$HINTS OFF} {$ENDIF} function TZAbstractPlainDriver.EscapeString(Handle: Pointer; const Value: ZWideString; ConSettings: PZConSettings): ZWideString; var StrFrom: RawByteString; Outbuffer: RawByteString; begin StrFrom := ZPlainString(Value, ConSettings); Outbuffer := EscapeString(Handle, StrFrom, ConSettings, True); {$IFDEF UNICODE} Result := ZDbcString(OutBuffer, ConSettings); {$ELSE} Result := ZDbcUnicodeString(Outbuffer, ConSettings.ClientCodePage.CP); {$ENDIF} end; function TZAbstractPlainDriver.EscapeString(Handle: Pointer; const Value: RawByteString; ConSettings: PZConSettings; WasEncoded: Boolean = False): RawByteString; begin Result := {$IFDEF WITH_UNITANSISTRINGS}AnsiStrings.{$ENDIF}AnsiQuotedStr(Value, #39); end; {$IFDEF FPC} {$HINTS ON} {$ENDIF} function TZAbstractPlainDriver.GetTokenizer: IZTokenizer; begin Result := FTokenizer; end; procedure TZAbstractPlainDriver.AddCodePage(const Name: String; const ID: Integer; Encoding: TZCharEncoding = ceAnsi; const CP: Word = $ffff; const ZAlias: String = ''; CharWidth: Integer = 1; const ConsistentCP: Boolean = True); begin SetLength(FCodePages, Length(FCodePages)+1); FCodePages[High(FCodePages)].Name := Name; FCodePages[High(FCodePages)].ID := ID; FCodePages[High(FCodePages)].Encoding := Encoding; FCodePages[High(FCodePages)].CP := CP; FCodePages[High(FCodePages)].CharWidth := CharWidth; FCodePages[High(FCodePages)].ZAlias := ZAlias; FCodePages[High(FCodePages)].IsStringFieldCPConsistent := ConsistentCP; if CP = $ffff then FCodePages[High(FCodePages)].ZAlias := GetUnicodeCodePageName; end; procedure TZAbstractPlainDriver.ResetCodePage(const OldID: Integer; const Name: String; const ID: Integer; Encoding: TZCharEncoding = ceAnsi; const CP: Word = $ffff; const ZAlias: String = ''; CharWidth: Integer = 1; const ConsistentCP: Boolean = True); var I: Integer; begin for i := low(FCodePages) to high(FCodePages) do if OldID = FCodePages[I].ID then begin FCodePages[I].ID := ID; FCodePages[I].Name := Name; FCodePages[I].Encoding := Encoding; FCodePages[I].CP := CP; FCodePages[I].ZAlias := ZAlias; FCodePages[I].CharWidth := CharWidth; FCodePages[I].IsStringFieldCPConsistent := ConsistentCP; if CP = $ffff then FCodePages[I].ZAlias := GetUnicodeCodePageName; Break; end; end; function TZAbstractPlainDriver.GetSupportedClientCodePages( const {$IFNDEF UNICODE}AutoEncode,{$ENDIF} IgnoreUnsupported: Boolean; CtrlsCPType: TZControlsCodePage = cCP_UTF16): TStringDynArray; var I: Integer; procedure AddCurrent; begin SetLength(Result, Length(Result)+1); Result[High(Result)] := FCodePages[i].Name; end; begin SetLength(Result, 0); for i := low(FCodePages) to high(FCodePages) do if IgnoreUnsupported then AddCurrent else case CtrlsCPType of cGET_ACP: {$IFDEF UNICODE} AddCurrent; //result are ?valid? but does that makes sence for all if not CP_UTF8? {$ELSE} if ( FCodePages[i].CP = ZDefaultSystemCodePage ) then AddCurrent else if AutoEncode then {$IF defined(MSWINDOWS) or defined(FPC_HAS_BUILTIN_WIDESTR_MANAGER) } AddCurrent //result are ?valid? but does that makes sence for all if not CP_UTF8? {$ELSE} {$IFDEF WITH_LCONVENCODING} //Lazarus only if ( IsLConvEncodingCodePage(FCodePages[i].CP) ) or ( FCodePages[i].Encoding = ceUTF8 ) then AddCurrent //allways valid because result is allways UTF8 which lazarus expects {$ENDIF} {$IFEND} else Continue; {$ENDIF} {$IFNDEF UNICODE} cCP_UTF8: if ( FCodePages[i].Encoding = ceUTF8 ) then AddCurrent else if AutoEncode then {$IF defined(MSWINDOWS) or defined(FPC_HAS_BUILTIN_WIDESTR_MANAGER) } AddCurrent //All charsets can be converted to UTF8 if a valid WideString-Manager does exists {$ELSE} {$IFDEF WITH_LCONVENCODING} //Lazarus only if ( IsLConvEncodingCodePage(FCodePages[i].CP) ) then AddCurrent {$ENDIF} {$IFEND} else Continue; {$ENDIF} else {$IF defined(MSWINDOWS) or defined(FPC_HAS_BUILTIN_WIDESTR_MANAGER) or defined(UNICODE)} AddCurrent; //all remaining charset can be converted to wide if a valid WideString-Manager does exists {$ELSE} {$IFDEF WITH_LCONVENCODING} //Lazarus only if ( IsLConvEncodingCodePage(FCodePages[i].CP) ) or //Lazarus can convert to UTF8 then we convert to wide (double En/Decoding!) ( FCodePages[i].Encoding = ceUTF8 ) or //decode the strings to wide ( FCodePages[i].CP = ZDefaultSystemCodePage ) then //to allow a valid cast AddCurrent; //all these charset can be converted to wide {$ELSE} if ( FCodePages[i].CP = ZDefaultSystemCodePage ) or //to allow a valid cast ( FCodePages[i].Encoding = ceUTF8 ) then //decode the strings to wide AddCurrent; {$ENDIF} {$IFEND} end; end; constructor TZAbstractPlainDriver.Create; begin inherited Create; FTokenizer := TZTokenizer.Create; end; destructor TZAbstractPlainDriver.Destroy; begin SetLength(FCodePages, 0); FTokenizer := nil; if Assigned(FLoader) then FreeAndNil(FLoader); inherited Destroy; end; procedure TZAbstractPlainDriver.LoadApi; begin end; constructor TZAbstractPlainDriver.CreateWithLibrary(const LibName: String); begin Inherited Create; if Assigned(FLoader) then begin Loader.ClearLocations; Loader.AddLocation(LibName); end; end; procedure TZAbstractPlainDriver.Initialize(const Location: String = ''); begin If Assigned(Loader) then if not Loader.Loaded then begin if Location <> '' then begin Loader.ClearLocations; Loader.AddLocation(Location); end; If Loader.LoadNativeLibrary then LoadApi; end; end; end. ================================================ FILE: lib/zeosdbo/src/plain/ZPlainFirebirdDriver.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Native Plain Drivers for Firebird } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZPlainFirebirdDriver; interface {$I ZPlain.inc} {$IFDEF UNIX} {$IFDEF INTERBASE_CRYPT} {$DEFINE ENABLE_INTERBASE_CRYPT} {$ENDIF} {$ENDIF} uses ZClasses, ZCompatibility, ZPlainDriver, ZPlainLoader, ZPlainFirebirdInterbaseConstants; const WINDOWSIB6_DLL_LOCATION = 'gds32.dll'; LINUXIB6_DLL_LOCATION = 'libgds'+SharedSuffix; WINDOWS_DLL_LOCATION = 'gds32.dll'; LINUX_DLL_LOCATION = 'libgds32'+SharedSuffix; LINUX_IB_CRYPT_LOCATION = 'libcrypt'+SharedSuffix; WINDOWS2_DLL_LOCATION = 'fbclient.dll'; WINDOWS2_DLL_LOCATION_EMBEDDED = 'fbclientd.dll'; LINUX2_DLL_LOCATION = 'libfbclient'+SharedSuffix; LINUX2_DLL_LOCATION_EMBEDDED = 'libfbembed'+SharedSuffix; LINUX2_IB_CRYPT_LOCATION = 'libcrypt'+SharedSuffix; WINDOWS15_DLL_LOCATION = 'fbclient15.dll'; WINDOWS15_DLL_LOCATION_EMBEDDED = 'fbclientd15.dll'; LINUX15_DLL_LOCATION = 'libfbclient'+SharedSuffix+'.15'; LINUX15_IB_CRYPT_LOCATION = 'libcrypt'+SharedSuffix+'.15'; LINUX15_DLL_LOCATION_EMBEDDED = 'libfbembed'+SharedSuffix+'.15'; WINDOWS20_DLL_LOCATION = 'fbclient20.dll'; WINDOWS20_DLL_LOCATION_EMBEDDED = 'fbclientd20.dll'; LINUX2_DLL_LOCATION2 = 'libfbclient'+SharedSuffix+'.2'; LINUX20_DLL_LOCATION = 'libfbclient'+SharedSuffix+'.20'; LINUX20_DLL_LOCATION_EMBEDDED = 'libfbembed'+SharedSuffix+'.20'; LINUX20_IB_CRYPT_LOCATION = 'libcrypt'+SharedSuffix+'.20'; WINDOWS21_DLL_LOCATION = 'fbclient21.dll'; WINDOWS21_DLL_LOCATION_EMBEDDED = 'fbclientd21.dll'; LINUX21_DLL_LOCATION = 'libfbclient'+SharedSuffix+'.21'; LINUX21_DLL_LOCATION_EMBEDDED = 'libfbembed'+SharedSuffix+'.21'; LINUX21_IB_CRYPT_LOCATION = 'libcrypt'+SharedSuffix+'.21'; WINDOWS25_DLL_LOCATION = 'fbclient25.dll'; WINDOWS25_DLL_LOCATION_EMBEDDED = 'fbclientd25.dll'; LINUX25_DLL_LOCATION = 'libfbclient'+SharedSuffix+'.25'; LINUX25_DLL_LOCATION_EMBEDDED = 'libfbembed'+SharedSuffix+'.25'; LINUX25_IB_CRYPT_LOCATION = 'libcrypt'+SharedSuffix+'.25'; type {** Represents a generic interface to Interbase native API. } IZInterbasePlainDriver = interface (IZPlainDriver) ['{AE2C4379-4E47-4752-BC01-D405ACC337F5}'] function GetFirebirdAPI: TZFirebird_API; function ZPlainString(const AStr: String; ConSettings: PZConSettings; const ToCP: Word): RawByteString; overload; function ZPlainString(const AStr: WideString; ConSettings: PZConSettings; const ToCP: Word): RawByteString; overload; function isc_attach_database (status_vector: PISC_STATUS; db_name_length: Short; db_name: PAnsiChar; db_handle: PISC_DB_HANDLE; parm_buffer_length: Short; parm_buffer: PAnsiChar): ISC_STATUS; function isc_detach_database(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE): ISC_STATUS; function isc_drop_database(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE): ISC_STATUS; function isc_database_info(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; item_list_buffer_length: Short; item_list_buffer: PAnsiChar; result_buffer_length: Short; result_buffer: PAnsiChar): ISC_STATUS; function isc_array_gen_sdl(status_vector: PISC_STATUS; isc_array_desc: PISC_ARRAY_DESC; isc_arg3: PShort; isc_arg4: PAnsiChar; isc_arg5: PShort): ISC_STATUS; function isc_array_get_slice(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; trans_handle: PISC_TR_HANDLE; array_id: PISC_QUAD; descriptor: PISC_ARRAY_DESC; dest_array: PVoid; slice_length: ISC_LONG): ISC_STATUS; function isc_array_lookup_bounds(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; trans_handle: PISC_TR_HANDLE; table_name, column_name: PAnsiChar; descriptor: PISC_ARRAY_DESC): ISC_STATUS; function isc_array_lookup_desc(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; trans_handle: PISC_TR_HANDLE; table_name, column_name: PAnsiChar; descriptor: PISC_ARRAY_DESC): ISC_STATUS; function isc_array_set_desc(status_vector: PISC_STATUS; table_name: PAnsiChar; column_name: PAnsiChar; sql_dtype, sql_length, sql_dimensions: PShort; descriptor: PISC_ARRAY_DESC): ISC_STATUS; function isc_array_put_slice(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; trans_handle: PISC_TR_HANDLE; array_id: PISC_QUAD; descriptor: PISC_ARRAY_DESC; source_array: PVoid; slice_length: PISC_LONG): ISC_STATUS; function isc_free(isc_arg1: PAnsiChar): ISC_LONG; function isc_sqlcode(status_vector: PISC_STATUS): ISC_LONG; procedure isc_sql_interprete(sqlcode: Short; buffer: PAnsiChar; buffer_length: Short); function isc_interprete(buffer: PAnsiChar; status_vector: PPISC_STATUS): ISC_STATUS; function isc_start_transaction(status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE; db_handle_count: Short; db_handle: PISC_DB_HANDLE; tpb_length: Word; tpb_address: PAnsiChar): ISC_STATUS; function isc_start_multiple(status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE; db_handle_count: Short; teb_vector_address: PISC_TEB): ISC_STATUS; function isc_rollback_transaction(status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE): ISC_STATUS; function isc_rollback_retaining(status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE): ISC_STATUS; function isc_commit_retaining(status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE): ISC_STATUS; function isc_commit_transaction(status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE): ISC_STATUS; function isc_dsql_allocate_statement(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; stmt_handle: PISC_STMT_HANDLE): ISC_STATUS; function isc_dsql_alloc_statement2(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; stmt_handle: PISC_STMT_HANDLE): ISC_STATUS; function isc_dsql_describe(status_vector: PISC_STATUS; stmt_handle: PISC_STMT_HANDLE; dialect: Word; xsqlda: PXSQLDA): ISC_STATUS; function isc_dsql_describe_bind(status_vector: PISC_STATUS; stmt_handle: PISC_STMT_HANDLE; dialect: Word; xsqlda: PXSQLDA): ISC_STATUS; function isc_dsql_execute(status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE; stmt_handle: PISC_STMT_HANDLE; dialect: Word; xsqlda: PXSQLDA): ISC_STATUS; function isc_dsql_execute2(status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE; stmt_handle: PISC_STMT_HANDLE; dialect: Word; in_xsqlda, out_xsqlda: PXSQLDA): ISC_STATUS; function isc_dsql_execute_immediate(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; tran_handle: PISC_TR_HANDLE; length: Word; statement: PAnsiChar; dialect: Word; xsqlda: PXSQLDA): ISC_STATUS; function isc_dsql_fetch(status_vector: PISC_STATUS; stmt_handle: PISC_STMT_HANDLE; dialect: Word; xsqlda: PXSQLDA): ISC_STATUS; function isc_dsql_free_statement(status_vector: PISC_STATUS; stmt_handle: PISC_STMT_HANDLE; options: Word): ISC_STATUS; function isc_dsql_prepare(status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE; stmt_handle: PISC_STMT_HANDLE; length: Word; statement: PAnsiChar; dialect: Word; xsqlda: PXSQLDA): ISC_STATUS; function isc_dsql_set_cursor_name(status_vector: PISC_STATUS; stmt_handle: PISC_STMT_HANDLE; cursor_name: PAnsiChar; _type: Word): ISC_STATUS; function isc_dsql_sql_info(status_vector: PISC_STATUS; stmt_handle: PISC_STMT_HANDLE; item_length: Short; items: PAnsiChar; buffer_length: Short; buffer: PAnsiChar): ISC_STATUS; function isc_open_blob2(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; tran_handle: PISC_TR_HANDLE; blob_handle: PISC_BLOB_HANDLE; blob_id: PISC_QUAD; bpb_length: Short; bpb_buffer: PAnsiChar): ISC_STATUS; function isc_create_blob2(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; tran_handle: PISC_TR_HANDLE; blob_handle: PISC_BLOB_HANDLE; blob_id: PISC_QUAD; bpb_length: Short; bpb_address: PAnsiChar): ISC_STATUS; function isc_blob_info(status_vector: PISC_STATUS; blob_handle: PISC_BLOB_HANDLE; item_list_buffer_length: Short; item_list_buffer: PAnsiChar; result_buffer_length: Short; result_buffer: PAnsiChar): ISC_STATUS; function isc_close_blob(status_vector: PISC_STATUS; blob_handle: PISC_BLOB_HANDLE): ISC_STATUS; function isc_cancel_blob(status_vector: PISC_STATUS; blob_handle: PISC_BLOB_HANDLE): ISC_STATUS; function isc_get_segment(status_vector: PISC_STATUS; blob_handle: PISC_BLOB_HANDLE; actual_seg_length: PWord; seg_buffer_length: Word; seg_buffer: PAnsiChar): ISC_STATUS; function isc_put_segment(status_vector: PISC_STATUS; blob_handle: PISC_BLOB_HANDLE; seg_buffer_len: Word; seg_buffer: PAnsiChar): ISC_STATUS; function isc_event_block(event_buffer: PPAnsiChar; result_buffer: PPAnsiChar; id_count: Word; event_list: array of PAnsiChar): ISC_LONG; procedure isc_event_counts(status_vector: PISC_STATUS; buffer_length: Short; event_buffer: PAnsiChar; result_buffer: PAnsiChar); function isc_cancel_events(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; event_id: PISC_LONG): ISC_STATUS; function isc_que_events(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; event_id: PISC_LONG; length: Short; event_buffer: PAnsiChar; event_function: TISC_CALLBACK; event_function_arg: PVoid): ISC_STATUS; procedure isc_decode_date(ib_date: PISC_QUAD; tm_date: PCTimeStructure); procedure isc_encode_date(tm_date: PCTimeStructure; ib_date: PISC_QUAD); function isc_vax_integer(buffer: PAnsiChar; length: Short): ISC_LONG; procedure isc_decode_sql_date(ib_date: PISC_DATE; tm_date: PCTimeStructure); procedure isc_decode_sql_time(ib_time: PISC_TIME; tm_date: PCTimeStructure); procedure isc_decode_timestamp(ib_timestamp: PISC_TIMESTAMP; tm_date: PCTimeStructure); procedure isc_encode_sql_date(tm_date: PCTimeStructure; ib_date: PISC_DATE); procedure isc_encode_sql_time(tm_date: PCTimeStructure; ib_time: PISC_TIME); procedure isc_encode_timestamp(tm_date: PCTimeStructure; ib_timestamp: PISC_TIMESTAMP); end; {** Implements a base driver for Firebird} { TZFirebirdBaseDriver } TZFirebirdBaseDriver = class (TZAbstractPlainDriver, IZPlainDriver, IZInterbasePlainDriver) FIREBIRD_API : TZFIREBIRD_API; protected FPreLoader : TZNativeLibraryLoader; procedure LoadCodePages; override; function GetUnicodeCodePageName: String; override; {$IFDEF ENABLE_INTERBASE_CRYPT} procedure Initialize; virtual; {$ENDIF} procedure LoadApi; override; public constructor Create; {$IFDEF ENABLE_INTERBASE_CRYPT} destructor Destroy; override; {$ENDIF} function GetFirebirdAPI: TZFirebird_API; function isc_attach_database (status_vector: PISC_STATUS; db_name_length: Short; db_name: PAnsiChar; db_handle: PISC_DB_HANDLE; parm_buffer_length: Short; parm_buffer: PAnsiChar): ISC_STATUS; function isc_detach_database(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE): ISC_STATUS; function isc_drop_database(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE): ISC_STATUS; function isc_database_info(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; item_list_buffer_length: Short; item_list_buffer: PAnsiChar; result_buffer_length: Short; result_buffer: PAnsiChar): ISC_STATUS; function isc_transaction_info(status_vector: PISC_STATUS; tr_handle: PISC_TR_HANDLE; item_list_buffer_length: Short; item_list_buffer: PAnsiChar; result_buffer_length: Short; result_buffer: PAnsiChar): ISC_STATUS; function isc_array_gen_sdl(status_vector: PISC_STATUS; isc_array_desc: PISC_ARRAY_DESC; isc_arg3: PShort; isc_arg4: PAnsiChar; isc_arg5: PShort): ISC_STATUS; function isc_array_get_slice(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; trans_handle: PISC_TR_HANDLE; array_id: PISC_QUAD; descriptor: PISC_ARRAY_DESC; dest_array: PVoid; slice_length: ISC_LONG): ISC_STATUS; function isc_array_lookup_bounds(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; trans_handle: PISC_TR_HANDLE; table_name, column_name: PAnsiChar; descriptor: PISC_ARRAY_DESC): ISC_STATUS; function isc_array_lookup_desc(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; trans_handle: PISC_TR_HANDLE; table_name, column_name: PAnsiChar; descriptor: PISC_ARRAY_DESC): ISC_STATUS; function isc_array_set_desc(status_vector: PISC_STATUS; table_name: PAnsiChar; column_name: PAnsiChar; sql_dtype, sql_length, sql_dimensions: PShort; descriptor: PISC_ARRAY_DESC): ISC_STATUS; function isc_array_put_slice(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; trans_handle: PISC_TR_HANDLE; array_id: PISC_QUAD; descriptor: PISC_ARRAY_DESC; source_array: PVoid; slice_length: PISC_LONG): ISC_STATUS; function isc_free(isc_arg1: PAnsiChar): ISC_LONG; function isc_sqlcode(status_vector: PISC_STATUS): ISC_LONG; procedure isc_sql_interprete(sqlcode: Short; buffer: PAnsiChar; buffer_length: Short); function isc_interprete(buffer: PAnsiChar; status_vector: PPISC_STATUS): ISC_STATUS; virtual; function isc_start_transaction(status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE; db_handle_count: Short; db_handle: PISC_DB_HANDLE; tpb_length: Word; tpb_address: PAnsiChar): ISC_STATUS; function isc_start_multiple(status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE; db_handle_count: Short; teb_vector_address: PISC_TEB): ISC_STATUS; function isc_rollback_transaction(status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE): ISC_STATUS; function isc_rollback_retaining(status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE): ISC_STATUS; function isc_commit_retaining(status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE): ISC_STATUS; function isc_commit_transaction(status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE): ISC_STATUS; function isc_dsql_allocate_statement(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; stmt_handle: PISC_STMT_HANDLE): ISC_STATUS; function isc_dsql_alloc_statement2(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; stmt_handle: PISC_STMT_HANDLE): ISC_STATUS; function isc_dsql_describe(status_vector: PISC_STATUS; stmt_handle: PISC_STMT_HANDLE; dialect: Word; xsqlda: PXSQLDA): ISC_STATUS; function isc_dsql_describe_bind(status_vector: PISC_STATUS; stmt_handle: PISC_STMT_HANDLE; dialect: Word; xsqlda: PXSQLDA): ISC_STATUS; function isc_dsql_execute(status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE; stmt_handle: PISC_STMT_HANDLE; dialect: Word; xsqlda: PXSQLDA): ISC_STATUS; function isc_dsql_execute2(status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE; stmt_handle: PISC_STMT_HANDLE; dialect: Word; in_xsqlda, out_xsqlda: PXSQLDA): ISC_STATUS; function isc_dsql_execute_immediate(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; tran_handle: PISC_TR_HANDLE; length: Word; statement: PAnsiChar; dialect: Word; xsqlda: PXSQLDA): ISC_STATUS; function isc_dsql_fetch(status_vector: PISC_STATUS; stmt_handle: PISC_STMT_HANDLE; dialect: Word; xsqlda: PXSQLDA): ISC_STATUS; function isc_dsql_free_statement(status_vector: PISC_STATUS; stmt_handle: PISC_STMT_HANDLE; options: Word): ISC_STATUS; function isc_dsql_prepare(status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE; stmt_handle: PISC_STMT_HANDLE; length: Word; statement: PAnsiChar; dialect: Word; xsqlda: PXSQLDA): ISC_STATUS; function isc_dsql_set_cursor_name(status_vector: PISC_STATUS; stmt_handle: PISC_STMT_HANDLE; cursor_name: PAnsiChar; _type: Word): ISC_STATUS; function isc_dsql_sql_info(status_vector: PISC_STATUS; stmt_handle: PISC_STMT_HANDLE; item_length: Short; items: PAnsiChar; buffer_length: Short; buffer: PAnsiChar): ISC_STATUS; function isc_open_blob2(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; tran_handle: PISC_TR_HANDLE; blob_handle: PISC_BLOB_HANDLE; blob_id: PISC_QUAD; bpb_length: Short; bpb_buffer: PAnsiChar): ISC_STATUS; function isc_create_blob2(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; tran_handle: PISC_TR_HANDLE; blob_handle: PISC_BLOB_HANDLE; blob_id: PISC_QUAD; bpb_length: Short; bpb_address: PAnsiChar): ISC_STATUS; function isc_blob_info(status_vector: PISC_STATUS; blob_handle: PISC_BLOB_HANDLE; item_list_buffer_length: Short; item_list_buffer: PAnsiChar; result_buffer_length: Short; result_buffer: PAnsiChar): ISC_STATUS; function isc_close_blob(status_vector: PISC_STATUS; blob_handle: PISC_BLOB_HANDLE): ISC_STATUS; function isc_cancel_blob(status_vector: PISC_STATUS; blob_handle: PISC_BLOB_HANDLE): ISC_STATUS; function isc_get_segment(status_vector: PISC_STATUS; blob_handle: PISC_BLOB_HANDLE; actual_seg_length: PWord; seg_buffer_length: Word; seg_buffer: PAnsiChar): ISC_STATUS; function isc_put_segment(status_vector: PISC_STATUS; blob_handle: PISC_BLOB_HANDLE; seg_buffer_len: Word; seg_buffer: PAnsiChar): ISC_STATUS; function isc_event_block(event_buffer: PPAnsiChar; result_buffer: PPAnsiChar; id_count: Word; event_list: array of PAnsiChar): ISC_LONG; procedure isc_event_counts(status_vector: PISC_STATUS; buffer_length: Short; event_buffer: PAnsiChar; result_buffer: PAnsiChar); function isc_cancel_events(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; event_id: PISC_LONG): ISC_STATUS; function isc_que_events(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; event_id: PISC_LONG; length: Short; event_buffer: PAnsiChar; event_function: TISC_CALLBACK; event_function_arg: PVoid): ISC_STATUS; procedure isc_decode_date(ib_date: PISC_QUAD; tm_date: PCTimeStructure); procedure isc_encode_date(tm_date: PCTimeStructure; ib_date: PISC_QUAD); procedure isc_decode_sql_date(ib_date: PISC_DATE; tm_date: PCTimeStructure); procedure isc_decode_sql_time(ib_time: PISC_TIME; tm_date: PCTimeStructure); procedure isc_decode_timestamp(ib_timestamp: PISC_TIMESTAMP; tm_date: PCTimeStructure); procedure isc_encode_sql_date(tm_date: PCTimeStructure; ib_date: PISC_DATE); procedure isc_encode_sql_time(tm_date: PCTimeStructure; ib_time: PISC_TIME); procedure isc_encode_timestamp(tm_date: PCTimeStructure; ib_timestamp: PISC_TIMESTAMP); function isc_vax_integer(buffer: PAnsiChar; length: Short): ISC_LONG; end; {** Implements a native driver for Interbase6} TZInterbase6PlainDriver = class (TZFirebirdBaseDriver) protected function Clone: IZPlainDriver; override; public constructor Create; function GetProtocol: string; override; function GetDescription: string; override; end; {** Implements a native driver for Firebird 1.0} TZFirebird10PlainDriver = class (TZFirebirdBaseDriver) protected function Clone: IZPlainDriver; override; public constructor Create; function GetProtocol: string; override; function GetDescription: string; override; end; {** Implements a native driver for Firebird 1.5} TZFirebird15PlainDriver = class (TZFirebirdBaseDriver) protected function Clone: IZPlainDriver; override; procedure LoadCodePages; override; public constructor Create; function GetProtocol: string; override; function GetDescription: string; override; end; TZFirebirdD15PlainDriver = class (TZFirebird15PlainDriver) protected function Clone: IZPlainDriver; override; public constructor Create; function GetProtocol: string; override; function GetDescription: string; override; end; {** Implements a native driver for Firebird 2.0} TZFirebird20PlainDriver = class (TZFirebirdBaseDriver) protected function Clone: IZPlainDriver; override; function GetUnicodeCodePageName: String; override; procedure LoadCodePages; override; public constructor Create; function GetProtocol: string; override; function GetDescription: string; override; end; TZFirebirdD20PlainDriver = class (TZFirebird20PlainDriver) protected function Clone: IZPlainDriver; override; public constructor Create; function GetProtocol: string; override; function GetDescription: string; override; end; {** Represents class to Interbase 6+ native API. } { TZFirebird21PlainDriver } TZFirebird21PlainDriver = class (TZFirebirdBaseDriver) protected function Clone: IZPlainDriver; override; protected function GetUnicodeCodePageName: String; override; procedure LoadCodePages; override; procedure LoadApi; override; public constructor Create; function GetProtocol: string; override; function GetDescription: string; override; function isc_interprete(buffer: PAnsiChar; status_vector: PPISC_STATUS): ISC_STATUS; override; end; TZFirebirdD21PlainDriver = class (TZFirebird21PlainDriver) protected function Clone: IZPlainDriver; override; public constructor Create; function GetProtocol: string; override; function GetDescription: string; override; end; { TZFirebird25PlainDriver } TZFirebird25PlainDriver = class (TZFirebirdBaseDriver) protected function Clone: IZPlainDriver; override; function GetUnicodeCodePageName: String; override; procedure LoadCodePages; override; procedure LoadApi; override; public constructor Create; function GetProtocol: string; override; function GetDescription: string; override; function isc_interprete(buffer: PAnsiChar; status_vector: PPISC_STATUS): ISC_STATUS; override; end; { TZFirebirdD25PlainDriver } TZFirebirdD25PlainDriver = class (TZFirebird25PlainDriver) protected function Clone: IZPlainDriver; override; public constructor Create; function GetProtocol: string; override; function GetDescription: string; override; end; function XSQLDA_LENGTH(Value: LongInt): LongInt; implementation uses SysUtils, ZEncoding; function XSQLDA_LENGTH(Value: LongInt): LongInt; begin Result := SizeOf(TXSQLDA) + ((Value - 1) * SizeOf(TXSQLVAR)); end; procedure AddFireBird15CodePages(PlainDriver: TZAbstractPlainDriver); begin PlainDriver.AddCodePage('DOS737', CS_DOS737, ceAnsi, zCP_DOS737); {Greek} PlainDriver.AddCodePage('DOS775', CS_DOS775, ceAnsi, zCP_DOS775); {Baltic} PlainDriver.AddCodePage('DOS858', CS_DOS858, ceAnsi, zCP_DOS858); {Latin I + Euro symbol} PlainDriver.AddCodePage('DOS862', CS_DOS862, ceAnsi, zCP_DOS862); {Hebrew} PlainDriver.AddCodePage('DOS864', CS_DOS864, ceAnsi, zCP_DOS864); {Arabic} PlainDriver.AddCodePage('DOS866', CS_DOS866, ceAnsi, zCP_DOS866); {Russian} PlainDriver.AddCodePage('DOS869', CS_DOS869, ceAnsi, zCP_DOS869); {Modern Greek} PlainDriver.AddCodePage('ISO8859_2', CS_ISO8859_2, ceAnsi, zCP_L2_ISO_8859_2); {Latin 2 Latin3 Southern European (Maltese, Esperanto)} PlainDriver.AddCodePage('ISO8859_3', CS_ISO8859_3, ceAnsi, zCP_L3_ISO_8859_3); {Latin 1} PlainDriver.AddCodePage('ISO8859_4', CS_ISO8859_4, ceAnsi, zCP_L4_ISO_8859_4); {Latin 4 Northern European (Estonian, Latvian, Lithuanian, Greenlandic, Lappish)} PlainDriver.AddCodePage('ISO8859_5', CS_ISO8859_5, ceAnsi, zCP_L5_ISO_8859_5); {Cyrillic (Russian)} PlainDriver.AddCodePage('ISO8859_6', CS_ISO8859_6, ceAnsi, zCP_L6_ISO_8859_6); {Arabic} PlainDriver.AddCodePage('ISO8859_7', CS_ISO8859_7, ceAnsi, zCP_L7_ISO_8859_7); {Greek} PlainDriver.AddCodePage('ISO8859_8', CS_ISO8859_8, ceAnsi, zCP_L8_ISO_8859_8); {Hebrew} PlainDriver.AddCodePage('ISO8859_9', CS_ISO8859_9, ceAnsi, zCP_L5_ISO_8859_9); {Latin 5} PlainDriver.AddCodePage('ISO8859_13', CS_ISO8859_13, ceAnsi, zCP_L7_ISO_8859_13); {Latin 7 Baltic Rim} PlainDriver.AddCodePage('WIN1255', CS_WIN1255, ceAnsi, zCP_WIN1255); {ANSI Hebrew} PlainDriver.AddCodePage('WIN1256', CS_WIN1256, ceAnsi, cCP_WIN1256); {ANSI Arabic} PlainDriver.AddCodePage('WIN1257', CS_WIN1257, ceAnsi, zCP_WIN1257); {ANSI Baltic} end; procedure AddFireBird2CodePages(PlainDriver: TZAbstractPlainDriver); begin PlainDriver.AddCodePage('WIN1258', CS_WIN1258, ceAnsi, zCP_WIN1258); {Vietnamese} PlainDriver.AddCodePage('KOI8R', CS_KOI8R, ceAnsi, zCP_KOI8R); {Russian} PlainDriver.AddCodePage('KOI8U', CS_KOI8U, ceAnsi, zCP_KOI8U); {Ukrainian} PlainDriver.AddCodePage('UTF8', CS_UTF8, ceUTF8, zCP_UTF8, '', 4); {All} end; procedure AddFireBird21CodePages(PlainDriver: TZAbstractPlainDriver); begin PlainDriver.AddCodePage('CP943C', CS_CP943C, ceAnsi, 943, '', 2); {Japanese} PlainDriver.AddCodePage('GBK', CS_GBK, ceAnsi, zCP_GB2312, '', 2); {Chinese} PlainDriver.AddCodePage('TIS620', CS_TIS620, ceAnsi, zCP_IBM_Thai); {Thai} end; { IZFirebirdPlainDriver } function TZFirebirdBaseDriver.GetUnicodeCodePageName: String; begin Result := 'UNICODE_FSS'; end; procedure TZFirebirdBaseDriver.LoadCodePages; begin Self.AddCodePage('ASCII', CS_ASCII, ceAnsi, zCP_WIN1252); {English} Self.AddCodePage('BIG_5', CS_BIG_5, ceAnsi, zCP_Big5); {Chinese, Vietnamese, Korean} Self.AddCodePage('CYRL', CS_CYRL, ceAnsi, zCP_WIN1251, '', 2); {Russian} Self.AddCodePage('DOS437', CS_DOS437, ceAnsi, zCP_DOS437); {English (USA)} Self.AddCodePage('DOS850', CS_DOS850, ceAnsi, zCP_DOS850); {Latin I (no Euro symbol)} Self.AddCodePage('DOS852', CS_DOS852, ceAnsi, zCP_DOS852); {Latin II} Self.AddCodePage('DOS857', CS_DOS857, ceAnsi, zCP_DOS857); {Turkish} Self.AddCodePage('DOS860', CS_DOS860, ceAnsi, zCP_DOS860); {Portuguese} Self.AddCodePage('DOS861', CS_DOS861, ceAnsi, zCP_DOS861); {Icelandic} Self.AddCodePage('DOS863', CS_DOS863, ceAnsi, zCP_DOS863); {French (Canada)} Self.AddCodePage('DOS865', CS_DOS865, ceAnsi, zCP_DOS865); {Nordic} Self.AddCodePage('EUCJ_0208', CS_EUCJ_0208, ceAnsi, zCP_EUC_JP, '', 2); {EUC Japanese} Self.AddCodePage('GB_2312', CS_GB_2312, ceAnsi, zCP_GB2312, '', 2); {Simplified Chinese (Hong Kong, PRC)} Self.AddCodePage('ISO8859_1', CS_ISO8859_1, ceAnsi, zCP_L1_ISO_8859_1); {Latin 1} Self.AddCodePage('KSC_5601', CS_KSC_5601, ceAnsi, zCP_EUCKR, '', 2); {Korean (Unified Hangeul)} Self.AddCodePage('NEXT', CS_NEXT); {NeXTSTEP encoding} Self.AddCodePage('NONE', CS_NONE, ceAnsi, ZDefaultSystemCodePage, '', 1, False); {Codepage-neutral. Uppercasing limited to ASCII codes 97-122} Self.AddCodePage('OCTETS', CS_BINARY); {Binary character} Self.AddCodePage('SJIS_0208', CS_SJIS_0208, ceAnsi, zCP_EUC_JP, '', 2); {Japanese} Self.AddCodePage('UNICODE_FSS', CS_UNICODE_FSS, ceUTF8, zCP_UTF8, '', 3); {UNICODE} Self.AddCodePage('WIN1250', CS_WIN1250, ceAnsi, zCP_WIN1250); {ANSI Central European} Self.AddCodePage('WIN1251', CS_WIN1251, ceAnsi, zCP_WIN1251); {ANSI Cyrillic} Self.AddCodePage('WIN1252', CS_WIN1252, ceAnsi, zCP_WIN1252); {ANSI Latin I} Self.AddCodePage('WIN1253', CS_WIN1253, ceAnsi, zCP_WIN1253); {ANSI Greek} Self.AddCodePage('WIN1254', CS_WIN1254, ceAnsi, zCP_WIN1254); {ANSI Turkish} end; {$IFDEF ENABLE_INTERBASE_CRYPT} procedure TZFirebirdBaseDriver.Initialize; begin If Assigned(FPreLoader) and not FPreLoader.Loaded then FPreLoader.LoadNativeLibrary; inherited Initialize; end; {$ENDIF} procedure TZFirebirdBaseDriver.LoadApi; begin inherited LoadApi; with Loader do begin @FIREBIRD_API.isc_sqlcode := GetAddress('isc_sqlcode'); @FIREBIRD_API.isc_sql_interprete := GetAddress('isc_sql_interprete'); @FIREBIRD_API.isc_interprete := GetAddress('isc_interprete'); @FIREBIRD_API.isc_vax_integer := GetAddress('isc_vax_integer'); @FIREBIRD_API.isc_array_gen_sdl := GetAddress( 'isc_array_gen_sdl'); @FIREBIRD_API.isc_array_get_slice := GetAddress( 'isc_array_get_slice'); @FIREBIRD_API.isc_array_lookup_bounds := GetAddress( 'isc_array_lookup_bounds'); @FIREBIRD_API.isc_array_lookup_desc := GetAddress( 'isc_array_lookup_desc'); @FIREBIRD_API.isc_array_set_desc := GetAddress( 'isc_array_set_desc'); @FIREBIRD_API.isc_array_put_slice := GetAddress( 'isc_array_put_slice'); @FIREBIRD_API.isc_blob_info := GetAddress('isc_blob_info'); @FIREBIRD_API.isc_open_blob2 := GetAddress('isc_open_blob2'); @FIREBIRD_API.isc_close_blob := GetAddress('isc_close_blob'); @FIREBIRD_API.isc_cancel_blob := GetAddress('isc_cancel_blob'); @FIREBIRD_API.isc_get_segment := GetAddress('isc_get_segment'); @FIREBIRD_API.isc_put_segment := GetAddress('isc_put_segment'); @FIREBIRD_API.isc_create_blob2 := GetAddress('isc_create_blob2'); @FIREBIRD_API.isc_decode_date := GetAddress('isc_decode_date'); @FIREBIRD_API.isc_encode_date := GetAddress('isc_encode_date'); @FIREBIRD_API.isc_dsql_free_statement := GetAddress('isc_dsql_free_statement'); @FIREBIRD_API.isc_dsql_execute2 := GetAddress('isc_dsql_execute2'); @FIREBIRD_API.isc_dsql_execute := GetAddress('isc_dsql_execute'); @FIREBIRD_API.isc_dsql_set_cursor_name := GetAddress('isc_dsql_set_cursor_name'); @FIREBIRD_API.isc_dsql_fetch := GetAddress('isc_dsql_fetch'); @FIREBIRD_API.isc_dsql_sql_info := GetAddress('isc_dsql_sql_info'); @FIREBIRD_API.isc_dsql_allocate_statement := GetAddress('isc_dsql_allocate_statement'); @FIREBIRD_API.isc_dsql_alloc_statement2 := GetAddress('isc_dsql_alloc_statement2'); @FIREBIRD_API.isc_dsql_prepare := GetAddress('isc_dsql_prepare'); @FIREBIRD_API.isc_dsql_describe_bind := GetAddress('isc_dsql_describe_bind'); @FIREBIRD_API.isc_dsql_describe := GetAddress('isc_dsql_describe'); @FIREBIRD_API.isc_dsql_execute_immediate := GetAddress('isc_dsql_execute_immediate'); @FIREBIRD_API.isc_drop_database := GetAddress('isc_drop_database'); @FIREBIRD_API.isc_detach_database := GetAddress('isc_detach_database'); @FIREBIRD_API.isc_attach_database := GetAddress('isc_attach_database'); @FIREBIRD_API.isc_database_info := GetAddress('isc_database_info'); @FIREBIRD_API.isc_transaction_info := GetAddress('isc_transaction_info'); @FIREBIRD_API.isc_start_multiple := GetAddress('isc_start_multiple'); @FIREBIRD_API.isc_start_transaction := GetAddress('isc_start_transaction'); @FIREBIRD_API.isc_commit_transaction := GetAddress('isc_commit_transaction'); @FIREBIRD_API.isc_commit_retaining := GetAddress('isc_commit_retaining'); @FIREBIRD_API.isc_rollback_transaction := GetAddress('isc_rollback_transaction'); @FIREBIRD_API.isc_cancel_events := GetAddress('isc_cancel_events'); @FIREBIRD_API.isc_que_events := GetAddress('isc_que_events'); @FIREBIRD_API.isc_event_counts := GetAddress('isc_event_counts'); @FIREBIRD_API.isc_event_block := GetAddress('isc_event_block'); @FIREBIRD_API.isc_free := GetAddress('isc_free'); @FIREBIRD_API.isc_rollback_retaining := GetAddress( 'isc_rollback_retaining'); @FIREBIRD_API.isc_decode_sql_date := GetAddress('isc_decode_sql_date'); @FIREBIRD_API.isc_decode_sql_time := GetAddress('isc_decode_sql_time'); @FIREBIRD_API.isc_decode_timestamp := GetAddress('isc_decode_timestamp'); @FIREBIRD_API.isc_encode_sql_date := GetAddress('isc_encode_sql_date'); @FIREBIRD_API.isc_encode_sql_time := GetAddress('isc_encode_sql_time'); @FIREBIRD_API.isc_encode_timestamp := GetAddress('isc_encode_timestamp'); end; end; constructor TZFirebirdBaseDriver.Create; begin inherited create; FLoader := TZNativeLibraryLoader.Create([]); {$IFDEF ENABLE_INTERBASE_CRYPT} FPreLoader := TZNativeLibraryLoader.Create([LINUX_IB_CRYPT_LOCATION]); {$ENDIF} end; {$IFDEF ENABLE_INTERBASE_CRYPT} destructor TZFirebirdBaseDriver.Destroy; begin FPreLoader.Free; inherited Destroy; end; {$ENDIF} function TZFirebirdBaseDriver.GetFirebirdAPI: TZFirebird_API; begin result := FIREBIRD_API; end; function TZFirebirdBaseDriver.isc_array_gen_sdl(status_vector: PISC_STATUS; isc_array_desc: PISC_ARRAY_DESC; isc_arg3: PShort; isc_arg4: PAnsiChar; isc_arg5: PShort): ISC_STATUS; begin Result := FIREBIRD_API.isc_array_gen_sdl(status_vector, isc_array_desc, isc_arg3, isc_arg4, isc_arg5); end; function TZFirebirdBaseDriver.isc_array_get_slice(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; trans_handle: PISC_TR_HANDLE; array_id: PISC_QUAD; descriptor: PISC_ARRAY_DESC; dest_array: PVoid; slice_length: ISC_LONG): ISC_STATUS; begin Result := FIREBIRD_API.isc_array_get_slice(status_vector, db_handle, trans_handle, array_id, descriptor, dest_array, slice_length); end; function TZFirebirdBaseDriver.isc_array_lookup_bounds( status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; trans_handle: PISC_TR_HANDLE; table_name, column_name: PAnsiChar; descriptor: PISC_ARRAY_DESC): ISC_STATUS; begin Result := FIREBIRD_API.isc_array_lookup_bounds(status_vector, db_handle, trans_handle, table_name, column_name, descriptor); end; function TZFirebirdBaseDriver.isc_array_lookup_desc( status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; trans_handle: PISC_TR_HANDLE; table_name, column_name: PAnsiChar; descriptor: PISC_ARRAY_DESC): ISC_STATUS; begin Result := FIREBIRD_API.isc_array_lookup_desc(status_vector, db_handle, trans_handle, table_name, column_name, descriptor); end; function TZFirebirdBaseDriver.isc_array_put_slice(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; trans_handle: PISC_TR_HANDLE; array_id: PISC_QUAD; descriptor: PISC_ARRAY_DESC; source_array: PVoid; slice_length: PISC_LONG): ISC_STATUS; begin Result := FIREBIRD_API.isc_array_put_slice(status_vector, db_handle, trans_handle, array_id, descriptor, source_array, slice_length); end; function TZFirebirdBaseDriver.isc_array_set_desc(status_vector: PISC_STATUS; table_name: PAnsiChar; column_name: PAnsiChar; sql_dtype, sql_length, sql_dimensions: PShort; descriptor: PISC_ARRAY_DESC): ISC_STATUS; begin Result := FIREBIRD_API.isc_array_set_desc(status_vector, table_name, column_name, sql_dtype, sql_length, sql_dimensions, descriptor); end; function TZFirebirdBaseDriver.isc_attach_database(status_vector: PISC_STATUS; db_name_length: Short; db_name: PAnsiChar; db_handle: PISC_DB_HANDLE; parm_buffer_length: Short; parm_buffer: PAnsiChar): ISC_STATUS; begin Result := FIREBIRD_API.isc_attach_database(status_vector, db_name_length, db_name, db_handle, parm_buffer_length, parm_buffer); end; function TZFirebirdBaseDriver.isc_blob_info(status_vector: PISC_STATUS; blob_handle: PISC_BLOB_HANDLE; item_list_buffer_length: Short; item_list_buffer: PAnsiChar; result_buffer_length: Short; result_buffer: PAnsiChar): ISC_STATUS; begin Result :=FIREBIRD_API.isc_blob_info(status_vector, blob_handle, item_list_buffer_length, item_list_buffer, result_buffer_length, result_buffer); end; function TZFirebirdBaseDriver.isc_cancel_blob(status_vector: PISC_STATUS; blob_handle: PISC_BLOB_HANDLE): ISC_STATUS; begin Result := FIREBIRD_API.isc_cancel_blob(status_vector, blob_handle); end; function TZFirebirdBaseDriver.isc_cancel_events(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; event_id: PISC_LONG): ISC_STATUS; begin Result := FIREBIRD_API.isc_cancel_events(status_vector, db_handle, event_id); end; function TZFirebirdBaseDriver.isc_close_blob(status_vector: PISC_STATUS; blob_handle: PISC_BLOB_HANDLE): ISC_STATUS; begin Result := FIREBIRD_API.isc_close_blob(status_vector, blob_handle); end; function TZFirebirdBaseDriver.isc_commit_retaining( status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE): ISC_STATUS; begin Result := FIREBIRD_API.isc_commit_retaining(status_vector, tran_handle); end; function TZFirebirdBaseDriver.isc_commit_transaction( status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE): ISC_STATUS; begin Result := FIREBIRD_API.isc_commit_transaction(status_vector, tran_handle); end; function TZFirebirdBaseDriver.isc_create_blob2(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; tran_handle: PISC_TR_HANDLE; blob_handle: PISC_BLOB_HANDLE; blob_id: PISC_QUAD; bpb_length: Short; bpb_address: PAnsiChar): ISC_STATUS; begin Result := FIREBIRD_API.isc_create_blob2(status_vector, db_handle, tran_handle, blob_handle, blob_id, bpb_length, bpb_address); end; function TZFirebirdBaseDriver.isc_database_info(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; item_list_buffer_length: Short; item_list_buffer: PAnsiChar; result_buffer_length: Short; result_buffer: PAnsiChar): ISC_STATUS; begin Result := FIREBIRD_API.isc_database_info(status_vector, db_handle, item_list_buffer_length, item_list_buffer, result_buffer_length, result_buffer); end; function TZFirebirdBaseDriver.isc_transaction_info(status_vector: PISC_STATUS; tr_handle: PISC_TR_HANDLE; item_list_buffer_length: Short; item_list_buffer: PAnsiChar; result_buffer_length: Short; result_buffer: PAnsiChar): ISC_STATUS; begin Result := FIREBIRD_API.isc_transaction_info(status_vector, tr_handle, item_list_buffer_length, item_list_buffer, result_buffer_length, result_buffer); end; procedure TZFirebirdBaseDriver.isc_decode_date(ib_date: PISC_QUAD; tm_date: PCTimeStructure); begin FIREBIRD_API.isc_decode_date(ib_date, tm_date); end; procedure TZFirebirdBaseDriver.isc_decode_sql_date(ib_date: PISC_DATE; tm_date: PCTimeStructure); begin FIREBIRD_API.isc_decode_sql_date(ib_date, tm_date); end; procedure TZFirebirdBaseDriver.isc_decode_sql_time(ib_time: PISC_TIME; tm_date: PCTimeStructure); begin FIREBIRD_API.isc_decode_sql_time(ib_time, tm_date); end; procedure TZFirebirdBaseDriver.isc_decode_timestamp( ib_timestamp: PISC_TIMESTAMP; tm_date: PCTimeStructure); begin FIREBIRD_API.isc_decode_timestamp(ib_timestamp, tm_date); end; function TZFirebirdBaseDriver.isc_detach_database(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE): ISC_STATUS; begin Result := FIREBIRD_API.isc_detach_database(status_vector, db_handle); end; function TZFirebirdBaseDriver.isc_drop_database(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE): ISC_STATUS; begin Result := FIREBIRD_API.isc_drop_database(status_vector, db_handle); end; function TZFirebirdBaseDriver.isc_dsql_alloc_statement2( status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; stmt_handle: PISC_STMT_HANDLE): ISC_STATUS; begin Result := FIREBIRD_API.isc_dsql_alloc_statement2(status_vector, db_handle, stmt_handle); end; function TZFirebirdBaseDriver.isc_dsql_allocate_statement( status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; stmt_handle: PISC_STMT_HANDLE): ISC_STATUS; begin Result := FIREBIRD_API.isc_dsql_allocate_statement(status_vector, db_handle, stmt_handle); end; function TZFirebirdBaseDriver.isc_dsql_describe(status_vector: PISC_STATUS; stmt_handle: PISC_STMT_HANDLE; dialect: Word; xsqlda: PXSQLDA): ISC_STATUS; begin Result := FIREBIRD_API.isc_dsql_describe(status_vector, stmt_handle, dialect, xsqlda); end; function TZFirebirdBaseDriver.isc_dsql_describe_bind( status_vector: PISC_STATUS; stmt_handle: PISC_STMT_HANDLE; dialect: Word; xsqlda: PXSQLDA): ISC_STATUS; begin Result := FIREBIRD_API.isc_dsql_describe_bind(status_vector, stmt_handle, dialect, xsqlda); end; function TZFirebirdBaseDriver.isc_dsql_execute(status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE; stmt_handle: PISC_STMT_HANDLE; dialect: Word; xsqlda: PXSQLDA): ISC_STATUS; begin Result := FIREBIRD_API.isc_dsql_execute(status_vector, tran_handle, stmt_handle, dialect, xsqlda); end; function TZFirebirdBaseDriver.isc_dsql_execute_immediate( status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; tran_handle: PISC_TR_HANDLE; length: Word; statement: PAnsiChar; dialect: Word; xsqlda: PXSQLDA): ISC_STATUS; begin Result := FIREBIRD_API.isc_dsql_execute_immediate(status_vector, db_handle, tran_handle, length, statement, dialect, xsqlda); end; function TZFirebirdBaseDriver.isc_dsql_execute2(status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE; stmt_handle: PISC_STMT_HANDLE; dialect: Word; in_xsqlda, out_xsqlda: PXSQLDA): ISC_STATUS; begin Result := FIREBIRD_API.isc_dsql_execute2(status_vector, tran_handle, stmt_handle, dialect, in_xsqlda, out_xsqlda); end; function TZFirebirdBaseDriver.isc_dsql_fetch(status_vector: PISC_STATUS; stmt_handle: PISC_STMT_HANDLE; dialect: Word; xsqlda: PXSQLDA): ISC_STATUS; begin Result := FIREBIRD_API.isc_dsql_fetch(status_vector, stmt_handle, dialect, xsqlda); end; function TZFirebirdBaseDriver.isc_dsql_free_statement( status_vector: PISC_STATUS; stmt_handle: PISC_STMT_HANDLE; options: Word): ISC_STATUS; begin Result := FIREBIRD_API.isc_dsql_free_statement(status_vector, stmt_handle, options); end; function TZFirebirdBaseDriver.isc_dsql_prepare( status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE; stmt_handle: PISC_STMT_HANDLE; length: Word; statement: PAnsiChar; dialect: Word; xsqlda: PXSQLDA): ISC_STATUS; begin Result := FIREBIRD_API.isc_dsql_prepare(status_vector, tran_handle, stmt_handle, length, statement, dialect, xsqlda); end; function TZFirebirdBaseDriver.isc_dsql_set_cursor_name( status_vector: PISC_STATUS; stmt_handle: PISC_STMT_HANDLE; cursor_name: PAnsiChar; _type: Word): ISC_STATUS; begin Result := FIREBIRD_API.isc_dsql_set_cursor_name(status_vector, stmt_handle, cursor_name, _type); end; function TZFirebirdBaseDriver.isc_dsql_sql_info( status_vector: PISC_STATUS; stmt_handle: PISC_STMT_HANDLE; item_length: Short; items: PAnsiChar; buffer_length: Short; buffer: PAnsiChar): ISC_STATUS; begin Result := FIREBIRD_API.isc_dsql_sql_info(status_vector, stmt_handle, item_length, items, buffer_length, buffer); end; procedure TZFirebirdBaseDriver.isc_encode_date(tm_date: PCTimeStructure; ib_date: PISC_QUAD); begin FIREBIRD_API.isc_encode_date(tm_date, ib_date); end; procedure TZFirebirdBaseDriver.isc_encode_sql_date( tm_date: PCTimeStructure; ib_date: PISC_DATE); begin FIREBIRD_API.isc_encode_sql_date(tm_date, ib_date); end; procedure TZFirebirdBaseDriver.isc_encode_sql_time( tm_date: PCTimeStructure; ib_time: PISC_TIME); begin FIREBIRD_API.isc_encode_sql_time(tm_date, ib_time); end; procedure TZFirebirdBaseDriver.isc_encode_timestamp( tm_date: PCTimeStructure; ib_timestamp: PISC_TIMESTAMP); begin FIREBIRD_API.isc_encode_timestamp(tm_date, ib_timestamp); end; function TZFirebirdBaseDriver.isc_event_block(event_buffer: PPAnsiChar; result_buffer: PPAnsiChar; id_count: Word; event_list: array of PAnsiChar ): ISC_LONG; begin Result := FIREBIRD_API.isc_event_block(event_buffer, result_buffer, id_count, event_list); end; procedure TZFirebirdBaseDriver.isc_event_counts( status_vector: PISC_STATUS; buffer_length: Short; event_buffer, result_buffer: PAnsiChar); begin FIREBIRD_API.isc_event_counts(status_vector, buffer_length, event_buffer, result_buffer); end; function TZFirebirdBaseDriver.isc_free(isc_arg1: PAnsiChar): ISC_LONG; begin Result := FIREBIRD_API.isc_free(isc_arg1); end; function TZFirebirdBaseDriver.isc_get_segment( status_vector: PISC_STATUS; blob_handle: PISC_BLOB_HANDLE; actual_seg_length: PWord; seg_buffer_length: Word; seg_buffer: PAnsiChar): ISC_STATUS; begin Result := FIREBIRD_API.isc_get_segment(status_vector, blob_handle, actual_seg_length, seg_buffer_length, seg_buffer); end; function TZFirebirdBaseDriver.isc_interprete(buffer: PAnsiChar; status_vector: PPISC_STATUS): ISC_STATUS; begin Result := FIREBIRD_API.isc_interprete(buffer, status_vector); end; function TZFirebirdBaseDriver.isc_open_blob2(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; tran_handle: PISC_TR_HANDLE; blob_handle: PISC_BLOB_HANDLE; blob_id: PISC_QUAD; bpb_length: Short; bpb_buffer: PAnsiChar): ISC_STATUS; begin Result := FIREBIRD_API.isc_open_blob2(status_vector, db_handle, tran_handle, blob_handle, blob_id, bpb_length, bpb_buffer); end; function TZFirebirdBaseDriver.isc_put_segment( status_vector: PISC_STATUS; blob_handle: PISC_BLOB_HANDLE; seg_buffer_len: Word; seg_buffer: PAnsiChar): ISC_STATUS; begin Result := FIREBIRD_API.isc_put_segment(status_vector, blob_handle, seg_buffer_len, seg_buffer); end; function TZFirebirdBaseDriver.isc_que_events(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; event_id: PISC_LONG; length: Short; event_buffer: PAnsiChar; event_function: TISC_CALLBACK; event_function_arg: PVoid): ISC_STATUS; begin Result := FIREBIRD_API.isc_que_events(status_vector, db_handle, event_id, length, event_buffer, event_function, event_function_arg) end; function TZFirebirdBaseDriver.isc_rollback_retaining( status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE): ISC_STATUS; begin Result := FIREBIRD_API.isc_rollback_retaining(status_vector, tran_handle); end; procedure TZFirebirdBaseDriver.isc_sql_interprete(sqlcode: Short; buffer: PAnsiChar; buffer_length: Short); begin FIREBIRD_API.isc_sql_interprete(sqlcode, buffer, buffer_length); end; function TZFirebirdBaseDriver.isc_sqlcode(status_vector: PISC_STATUS): ISC_LONG; begin Result := FIREBIRD_API.isc_sqlcode(status_vector); end; function TZFirebirdBaseDriver.isc_rollback_transaction( status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE): ISC_STATUS; begin Result := FIREBIRD_API.isc_rollback_transaction(status_vector, tran_handle); end; function TZFirebirdBaseDriver.isc_start_multiple( status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE; db_handle_count: Short; teb_vector_address: PISC_TEB): ISC_STATUS; begin Result := FIREBIRD_API.isc_start_multiple(status_vector, tran_handle, db_handle_count, teb_vector_address); end; function TZFirebirdBaseDriver.isc_start_transaction( status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE; db_handle_count: Short; db_handle: PISC_DB_HANDLE; tpb_length: Word; tpb_address: PAnsiChar): ISC_STATUS; begin Result := FIREBIRD_API.isc_start_transaction(status_vector, tran_handle, db_handle_count, db_handle, tpb_length, tpb_address); end; function TZFirebirdBaseDriver.isc_vax_integer(buffer: PAnsiChar; length: Short): ISC_LONG; begin Result := FIREBIRD_API.isc_vax_integer(buffer, length); end; { TZInterbase6PlainDriver } function TZInterbase6PlainDriver.Clone: IZPlainDriver; begin Result := TZInterbase6PlainDriver.Create; end; constructor TZInterbase6PlainDriver.Create; begin inherited create; {$IFNDEF UNIX} FLoader.AddLocation(WINDOWSIB6_DLL_LOCATION); {$ELSE} FLoader.AddLocation(LINUXIB6_DLL_LOCATION); {$IFDEF ENABLE_INTERBASE_CRYPT} FPreLoader.AddLocation(LINUX_IB_CRYPT_LOCATION); {$ENDIF} {$ENDIF} Self.LoadCodePages; end; function TZInterbase6PlainDriver.GetDescription: string; begin Result := 'Native Plain Driver for Interbase 6'; end; function TZInterbase6PlainDriver.GetProtocol: string; begin Result := 'interbase-6'; end; function TZFirebird10PlainDriver.Clone: IZPlainDriver; begin Result := TZFirebird10PlainDriver.Create; end; constructor TZFirebird10PlainDriver.Create; begin inherited create; {$IFNDEF UNIX} FLoader.AddLocation(WINDOWS_DLL_LOCATION); {$ELSE} FLoader.AddLocation(LINUX_DLL_LOCATION); {$IFDEF ENABLE_INTERBASE_CRYPT} FPreLoader.AddLocation(LINUX_IB_CRYPT_LOCATION); {$ENDIF} {$ENDIF} Self.LoadCodePages; end; function TZFirebird10PlainDriver.GetDescription: string; begin Result := 'Native Plain Driver for Firebird 1.0'; end; function TZFirebird10PlainDriver.GetProtocol: string; begin Result := 'firebird-1.0'; end; { IZFirebird15PlainDriver } function TZFirebird15PlainDriver.Clone: IZPlainDriver; begin Result := TZFirebird15PlainDriver.Create; end; procedure TZFirebird15PlainDriver.LoadCodePages; begin inherited; AddFireBird15CodePages(Self); end; constructor TZFirebird15PlainDriver.Create; begin inherited create; {$IFNDEF UNIX} {$IFNDEF FIREBIRD_STRICT_DLL_LOADING} FLoader.AddLocation(WINDOWS2_DLL_LOCATION); {$ENDIF} FLoader.AddLocation(WINDOWS15_DLL_LOCATION); {$ELSE} {$IFNDEF FIREBIRD_STRICT_DLL_LOADING} FLoader.AddLocation(LINUX2_DLL_LOCATION); {$ENDIF} FLoader.AddLocation(LINUX15_DLL_LOCATION); {$IFDEF ENABLE_INTERBASE_CRYPT} {$IFNDEF FIREBIRD_STRICT_DLL_LOADING} FPreLoader.AddLocation(LINUX2_IB_CRYPT_LOCATION); {$ENDIF} FPreLoader.AddLocation(LINUX15_IB_CRYPT_LOCATION); {$ENDIF} {$ENDIF} Self.LoadCodePages; end; function TZFirebird15PlainDriver.GetDescription: string; begin Result := 'Native Plain Driver for Firebird 1.5'; end; function TZFirebird15PlainDriver.GetProtocol: string; begin Result := 'firebird-1.5'; end; { IZFirebird15PlainDriver } function TZFirebirdD15PlainDriver.Clone: IZPlainDriver; begin Result := TZFirebirdD15PlainDriver.Create; end; constructor TZFirebirdD15PlainDriver.Create; begin inherited create; {$IFNDEF UNIX} {$IFNDEF FIREBIRD_STRICT_DLL_LOADING} FLoader.AddLocation(WINDOWS2_DLL_LOCATION_EMBEDDED); {$ENDIF} FLoader.AddLocation(WINDOWS15_DLL_LOCATION_EMBEDDED); {$ELSE} {$IFNDEF FIREBIRD_STRICT_DLL_LOADING} FLoader.AddLocation(LINUX2_DLL_LOCATION_EMBEDDED); {$ENDIF} FLoader.AddLocation(LINUX15_DLL_LOCATION_EMBEDDED); {$ENDIF} end; function TZFirebirdD15PlainDriver.GetProtocol: string; begin Result := 'firebirdd-1.5'; end; function TZFirebirdD15PlainDriver.GetDescription: string; begin Result := 'Native Plain Driver for Firebird Embedded 1.5'; end; { IZFirebird20PlainDriver } function TZFirebird20PlainDriver.Clone: IZPlainDriver; begin Result := TZFirebird20PlainDriver.Create; end; function TZFirebird20PlainDriver.GetUnicodeCodePageName: String; begin Result := 'UTF8'; end; procedure TZFirebird20PlainDriver.LoadCodePages; begin inherited LoadCodePages; AddFireBird15CodePages(Self); AddFireBird2CodePages(Self); end; constructor TZFirebird20PlainDriver.Create; begin inherited create; {$IFNDEF UNIX} {$IFNDEF FIREBIRD_STRICT_DLL_LOADING} FLoader.AddLocation(WINDOWS2_DLL_LOCATION); {$ENDIF} FLoader.AddLocation(WINDOWS20_DLL_LOCATION); {$ELSE} {$IFNDEF FIREBIRD_STRICT_DLL_LOADING} FLoader.AddLocation(LINUX2_DLL_LOCATION); {$ENDIF} FLoader.AddLocation(LINUX20_DLL_LOCATION); FLoader.AddLocation(LINUX2_DLL_LOCATION2); {$IFDEF ENABLE_INTERBASE_CRYPT} {$IFNDEF FIREBIRD_STRICT_DLL_LOADING} FPreLoader.AddLocation(LINUX2_IB_CRYPT_LOCATION); {$ENDIF} FPreLoader.AddLocation(LINUX20_IB_CRYPT_LOCATION); {$ENDIF} {$ENDIF} Self.LoadCodePages; end; function TZFirebird20PlainDriver.GetDescription: string; begin Result := 'Native Plain Driver for Firebird 2.0'; end; function TZFirebird20PlainDriver.GetProtocol: string; begin Result := 'firebird-2.0'; end; { IZFirebirdD20PlainDriver } function TZFirebirdD20PlainDriver.Clone: IZPlainDriver; begin Result := TZFirebirdD20PlainDriver.Create; end; constructor TZFirebirdD20PlainDriver.Create; begin inherited create; {$IFNDEF UNIX} {$IFNDEF FIREBIRD_STRICT_DLL_LOADING} FLoader.AddLocation(WINDOWS2_DLL_LOCATION_EMBEDDED); {$ENDIF} FLoader.AddLocation(WINDOWS20_DLL_LOCATION_EMBEDDED); {$ELSE} {$IFNDEF FIREBIRD_STRICT_DLL_LOADING} FLoader.AddLocation(LINUX2_DLL_LOCATION_EMBEDDED); {$ENDIF} FLoader.AddLocation(LINUX20_DLL_LOCATION_EMBEDDED); {$ENDIF} end; function TZFirebirdD20PlainDriver.GetProtocol: string; begin Result := 'firebirdd-2.0'; end; function TZFirebirdD20PlainDriver.GetDescription: string; begin Result := 'Native Plain Driver for Firebird Embedded 2.0'; end; { IZFirebird21PlainDriver } function TZFirebird21PlainDriver.Clone: IZPlainDriver; begin Result := TZFirebird21PlainDriver.Create; end; function TZFirebird21PlainDriver.GetUnicodeCodePageName: String; begin Result := 'UTF8'; end; procedure TZFirebird21PlainDriver.LoadCodePages; begin inherited; AddFireBird15CodePages(Self); AddFireBird2CodePages(Self); AddFireBird21CodePages(Self); end; procedure TZFirebird21PlainDriver.LoadApi; begin inherited LoadApi; with Loader do begin @FIREBIRD_API.fb_interpret := GetAddress('fb_interpret'); end; end; constructor TZFirebird21PlainDriver.Create; begin inherited create; {$IFNDEF UNIX} {$IFNDEF FIREBIRD_STRICT_DLL_LOADING} FLoader.AddLocation(WINDOWS2_DLL_LOCATION); {$ENDIF} FLoader.AddLocation(WINDOWS21_DLL_LOCATION); {$ELSE} {$IFNDEF FIREBIRD_STRICT_DLL_LOADING} FLoader.AddLocation(LINUX2_DLL_LOCATION); {$ENDIF} FLoader.AddLocation(LINUX21_DLL_LOCATION); FLoader.AddLocation(LINUX2_DLL_LOCATION2); {$IFDEF ENABLE_INTERBASE_CRYPT} {$IFNDEF FIREBIRD_STRICT_DLL_LOADING} FPreLoader.AddLocation(LINUX2_IB_CRYPT_LOCATION); {$ENDIF} FPreLoader.AddLocation(LINUX21_IB_CRYPT_LOCATION); {$ENDIF} {$ENDIF} Self.LoadCodePages; end; function TZFirebird21PlainDriver.GetDescription: string; begin Result := 'Native Plain Driver for Firebird 2.1'; end; function TZFirebird21PlainDriver.GetProtocol: string; begin Result := 'firebird-2.1'; end; function TZFirebird21PlainDriver.isc_interprete(buffer: PAnsiChar; status_vector: PPISC_STATUS): ISC_STATUS; var bufsize : integer; begin bufsize := 1024; Result := FIREBIRD_API.fb_interpret(buffer, bufsize, status_vector); end; { IZFirebirdD21PlainDriver } function TZFirebirdD21PlainDriver.Clone: IZPlainDriver; begin Result := TZFirebirdD21PlainDriver.Create; end; constructor TZFirebirdD21PlainDriver.Create; begin inherited create; {$IFNDEF UNIX} {$IFNDEF FIREBIRD_STRICT_DLL_LOADING} FLoader.AddLocation(WINDOWS2_DLL_LOCATION_EMBEDDED); {$ENDIF} FLoader.AddLocation(WINDOWS21_DLL_LOCATION_EMBEDDED); {$ELSE} {$IFNDEF FIREBIRD_STRICT_DLL_LOADING} FLoader.AddLocation(LINUX2_DLL_LOCATION_EMBEDDED); {$ENDIF} FLoader.AddLocation(LINUX21_DLL_LOCATION_EMBEDDED); {$ENDIF} end; function TZFirebirdD21PlainDriver.GetProtocol: string; begin Result := 'firebirdd-2.1'; end; function TZFirebirdD21PlainDriver.GetDescription: string; begin Result := 'Native Plain Driver for Firebird Embedded 2.1'; end; { TZFirebird25PlainDriver } function TZFirebird25PlainDriver.Clone: IZPlainDriver; begin Result := TZFirebird25PlainDriver.Create; end; function TZFirebird25PlainDriver.GetUnicodeCodePageName: String; begin Result := 'UTF8'; end; procedure TZFirebird25PlainDriver.LoadCodePages; begin inherited; AddFireBird15CodePages(Self); AddFireBird2CodePages(Self); AddFireBird21CodePages(Self); ResetCodePage(CS_BIG_5, 'BIG_5', CS_BIG_5, ceAnsi, zCP_BIG5, '', 2); {Chinese, Vietnamese, Korean} //Changed Bytes Self.AddCodePage('GB18030', CS_GB18030, ceAnsi, zCP_GB18030, '', 4); {Chinese} end; procedure TZFirebird25PlainDriver.LoadApi; begin inherited LoadApi; with Loader do begin @FIREBIRD_API.fb_interpret := GetAddress('fb_interpret'); end; end; constructor TZFirebird25PlainDriver.Create; begin inherited create; {$IFNDEF UNIX} {$IFNDEF FIREBIRD_STRICT_DLL_LOADING} FLoader.AddLocation(WINDOWS2_DLL_LOCATION); {$ENDIF} FLoader.AddLocation(WINDOWS25_DLL_LOCATION); {$ELSE} {$IFNDEF FIREBIRD_STRICT_DLL_LOADING} FLoader.AddLocation(LINUX2_DLL_LOCATION); {$ENDIF} FLoader.AddLocation(LINUX25_DLL_LOCATION); FLoader.AddLocation(LINUX2_DLL_LOCATION2); {$IFDEF ENABLE_INTERBASE_CRYPT} {$IFNDEF FIREBIRD_STRICT_DLL_LOADING} FPreLoader.AddLocation(LINUX2_IB_CRYPT_LOCATION); {$ENDIF} FPreLoader.AddLocation(LINUX25_IB_CRYPT_LOCATION); {$ENDIF} {$ENDIF} Self.LoadCodePages; end; function TZFirebird25PlainDriver.GetProtocol: string; begin Result := 'firebird-2.5'; end; function TZFirebird25PlainDriver.GetDescription: string; begin Result := 'Native Plain Driver for Firebird 2.5'; end; function TZFirebird25PlainDriver.isc_interprete(buffer: PAnsiChar; status_vector: PPISC_STATUS): ISC_STATUS; begin Result:=inherited isc_interprete(buffer, status_vector); end; { TZFirebirdD25PlainDriver } function TZFirebirdD25PlainDriver.Clone: IZPlainDriver; begin Result := TZFirebirdD25PlainDriver.Create; end; constructor TZFirebirdD25PlainDriver.Create; begin inherited create; {$IFNDEF UNIX} {$IFNDEF FIREBIRD_STRICT_DLL_LOADING} FLoader.AddLocation(WINDOWS2_DLL_LOCATION_EMBEDDED); {$ENDIF} FLoader.AddLocation(WINDOWS25_DLL_LOCATION_EMBEDDED); {$ELSE} {$IFNDEF FIREBIRD_STRICT_DLL_LOADING} FLoader.AddLocation(LINUX2_DLL_LOCATION_EMBEDDED); {$ENDIF} FLoader.AddLocation(LINUX25_DLL_LOCATION_EMBEDDED); {$ENDIF} end; function TZFirebirdD25PlainDriver.GetProtocol: string; begin Result := 'firebirdd-2.5'; end; function TZFirebirdD25PlainDriver.GetDescription: string; begin Result := 'Native Plain Driver for Firebird Embedded 2.5'; end; end. ================================================ FILE: lib/zeosdbo/src/plain/ZPlainFirebirdInterbaseConstants.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Interbase and Firebird Common constants } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZPlainFirebirdInterbaseConstants; interface {$I ZPlain.inc} uses ZCompatibility; const IBLocalBufferLength = 512; IBBigLocalBufferLength = IBLocalBufferLength * 2; IBHugeLocalBufferLength = IBBigLocalBufferLength * 20; {temporary fix by mdaems I think Andre wanted to use this as a generic error code for a broken connection At the moment I put it here as it's only used in the IB/FB implementation } DISCONNECT_ERROR = -1; ISC_NULL = -1; ISC_NOTNULL = 0; ISC_TRUE = 1; ISC_FALSE = 0; DSQL_CLOSE = 1; DSQL_DROP = 2; DSQL_UNPREPARE = 4; SQLDA_VERSION1 = 1; SQLDA_VERSION2 = 2; SQL_DIALECT_V5 = 1; SQL_DIALECT_V6 = 3; SQL_DIALECT_CURRENT = SQL_DIALECT_V6; (* latest IB DIALECT *) { SQL definitions } SQL_VARYING = 448; SQL_TEXT = 452; SQL_DOUBLE = 480; SQL_FLOAT = 482; SQL_LONG = 496; SQL_SHORT = 500; SQL_TIMESTAMP = 510; SQL_BLOB = 520; SQL_D_FLOAT = 530; SQL_ARRAY = 540; SQL_QUAD = 550; SQL_TYPE_TIME = 560; SQL_TYPE_DATE = 570; SQL_INT64 = 580; SQL_BOOLEAN = 590; SQL_DATE = SQL_TIMESTAMP; (* #define BLR_WORD(x) UCHAR(x), UCHAR((x) >> 8) * WARNING: if you add a new BLR representing a data type, and the value * is greater than the numerically greatest value which now * represents a data type, you must change the define for * DTYPE_BLR_MAX in jrd/align.h, and add the necessary entries * to all the arrays in that file. *) blr_text = 14; blr_text2 = 15; blr_short = 7; blr_long = 8; blr_quad = 9; blr_float = 10; blr_double = 27; blr_d_float = 11; blr_timestamp = 35; blr_varying = 37; blr_varying2 = 38; blr_blob = 261; blr_cstring = 40; blr_cstring2 = 41; // added in 3.2 JPN blr_blob_id = 45; // added from gds.h blr_sql_date = 12; blr_sql_time = 13; blr_int64 = 16; blr_blob2 = 17; blr_domain_name = 18; blr_domain_name2 = 19; blr_not_nullable = 20; blr_column_name = 21; blr_column_name2 = 22; blr_bool = 23; // Historical alias for pre V6 applications blr_date = blr_timestamp; (* // first sub parameter for blr_domain_name[2] blr_domain_type_of = 0; blr_domain_full = 1; blr_inner = 0; blr_left = 1; blr_right = 2; blr_full = 3; blr_gds_code = 0; blr_sql_code = 1; blr_exception = 2; blr_trigger_code = 3; blr_default_code = 4; blr_raise = 5; blr_exception_msg = 6; blr_exception_params= 7; blr_version4 = 4; blr_version5 (unsigned char)5 //#define blr_version6 (unsigned char)6 #define blr_eoc (unsigned char)76 #define blr_end (unsigned char)255 #define blr_assignment (unsigned char)1 #define blr_begin (unsigned char)2 #define blr_dcl_variable (unsigned char)3 /* added from gds.h */ #define blr_message (unsigned char)4 #define blr_erase (unsigned char)5 #define blr_fetch (unsigned char)6 #define blr_for (unsigned char)7 #define blr_if (unsigned char)8 #define blr_loop (unsigned char)9 #define blr_modify (unsigned char)10 #define blr_handler (unsigned char)11 #define blr_receive (unsigned char)12 #define blr_select (unsigned char)13 #define blr_send (unsigned char)14 #define blr_store (unsigned char)15 #define blr_label (unsigned char)17 #define blr_leave (unsigned char)18 #define blr_store2 (unsigned char)19 #define blr_post (unsigned char)20 #define blr_literal (unsigned char)21 #define blr_dbkey (unsigned char)22 #define blr_field (unsigned char)23 #define blr_fid (unsigned char)24 #define blr_parameter (unsigned char)25 #define blr_variable (unsigned char)26 #define blr_average (unsigned char)27 #define blr_count (unsigned char)28 #define blr_maximum (unsigned char)29 #define blr_minimum (unsigned char)30 #define blr_total (unsigned char)31 // unused codes: 32..33 #define blr_add (unsigned char)34 #define blr_subtract (unsigned char)35 #define blr_multiply (unsigned char)36 #define blr_divide (unsigned char)37 #define blr_negate (unsigned char)38 #define blr_concatenate (unsigned char)39 #define blr_substring (unsigned char)40 #define blr_parameter2 (unsigned char)41 #define blr_from (unsigned char)42 #define blr_via (unsigned char)43 #define blr_user_name (unsigned char)44 /* added from gds.h */ #define blr_null (unsigned char)45 #define blr_equiv (unsigned char)46 #define blr_eql (unsigned char)47 #define blr_neq (unsigned char)48 #define blr_gtr (unsigned char)49 #define blr_geq (unsigned char)50 #define blr_lss (unsigned char)51 #define blr_leq (unsigned char)52 #define blr_containing (unsigned char)53 #define blr_matching (unsigned char)54 #define blr_starting (unsigned char)55 #define blr_between (unsigned char)56 #define blr_or (unsigned char)57 #define blr_and (unsigned char)58 #define blr_not (unsigned char)59 #define blr_any (unsigned char)60 #define blr_missing (unsigned char)61 #define blr_unique (unsigned char)62 #define blr_like (unsigned char)63 // unused codes: 64..66 #define blr_rse (unsigned char)67 #define blr_first (unsigned char)68 #define blr_project (unsigned char)69 #define blr_sort (unsigned char)70 #define blr_boolean (unsigned char)71 #define blr_ascending (unsigned char)72 #define blr_descending (unsigned char)73 #define blr_relation (unsigned char)74 #define blr_rid (unsigned char)75 #define blr_union (unsigned char)76 #define blr_map (unsigned char)77 #define blr_group_by (unsigned char)78 #define blr_aggregate (unsigned char)79 #define blr_join_type (unsigned char)80 // unused codes: 81..82 #define blr_agg_count (unsigned char)83 #define blr_agg_max (unsigned char)84 #define blr_agg_min (unsigned char)85 #define blr_agg_total (unsigned char)86 #define blr_agg_average (unsigned char)87 #define blr_parameter3 (unsigned char)88 /* same as Rdb definition */ /* unsupported #define blr_run_max (unsigned char)89 #define blr_run_min (unsigned char)90 #define blr_run_total (unsigned char)91 #define blr_run_average (unsigned char)92 */ #define blr_agg_count2 (unsigned char)93 #define blr_agg_count_distinct (unsigned char)94 #define blr_agg_total_distinct (unsigned char)95 #define blr_agg_average_distinct (unsigned char)96 // unused codes: 97..99 #define blr_function (unsigned char)100 #define blr_gen_id (unsigned char)101 ///#define blr_prot_mask (unsigned char)102 #define blr_upcase (unsigned char)103 ///#define blr_lock_state (unsigned char)104 #define blr_value_if (unsigned char)105 #define blr_matching2 (unsigned char)106 #define blr_index (unsigned char)107 #define blr_ansi_like (unsigned char)108 #define blr_scrollable (unsigned char) 109 // unused codes: 110..117 #define blr_run_count (unsigned char)118 /* changed from 88 to avoid conflict with blr_parameter3 */ #define blr_rs_stream (unsigned char)119 #define blr_exec_proc (unsigned char)120 // unused codes: 121..123 #define blr_procedure (unsigned char)124 #define blr_pid (unsigned char)125 #define blr_exec_pid (unsigned char)126 #define blr_singular (unsigned char)127 #define blr_abort (unsigned char)128 #define blr_block (unsigned char)129 #define blr_error_handler (unsigned char)130 #define blr_cast (unsigned char)131 #define blr_pid2 (unsigned char)132 #define blr_procedure2 (unsigned char)133 #define blr_start_savepoint (unsigned char)134 #define blr_end_savepoint (unsigned char)135 // unused codes: 136..138 #define blr_plan (unsigned char)139 /* access plan items */ #define blr_merge (unsigned char)140 #define blr_join (unsigned char)141 #define blr_sequential (unsigned char)142 #define blr_navigational (unsigned char)143 #define blr_indices (unsigned char)144 #define blr_retrieve (unsigned char)145 #define blr_relation2 (unsigned char)146 #define blr_rid2 (unsigned char)147 // unused codes: 148..149 #define blr_set_generator (unsigned char)150 #define blr_ansi_any (unsigned char)151 /* required for NULL handling */ #define blr_exists (unsigned char)152 /* required for NULL handling */ // unused codes: 153 #define blr_record_version (unsigned char)154 /* get tid of record */ #define blr_stall (unsigned char)155 /* fake server stall */ // unused codes: 156..157 #define blr_ansi_all (unsigned char)158 /* required for NULL handling */ #define blr_extract (unsigned char)159 /* sub parameters for blr_extract */ #define blr_extract_year (unsigned char)0 #define blr_extract_month (unsigned char)1 #define blr_extract_day (unsigned char)2 #define blr_extract_hour (unsigned char)3 #define blr_extract_minute (unsigned char)4 #define blr_extract_second (unsigned char)5 #define blr_extract_weekday (unsigned char)6 #define blr_extract_yearday (unsigned char)7 #define blr_extract_millisecond (unsigned char)8 #define blr_extract_week (unsigned char)9 #define blr_current_date (unsigned char)160 #define blr_current_timestamp (unsigned char)161 #define blr_current_time (unsigned char)162 /* These codes reuse BLR code space */ #define blr_post_arg (unsigned char)163 #define blr_exec_into (unsigned char)164 #define blr_user_savepoint (unsigned char)165 #define blr_dcl_cursor (unsigned char)166 #define blr_cursor_stmt (unsigned char)167 #define blr_current_timestamp2 (unsigned char)168 #define blr_current_time2 (unsigned char)169 #define blr_agg_list (unsigned char)170 #define blr_agg_list_distinct (unsigned char)171 #define blr_modify2 (unsigned char)172 // unused codes: 173 /* FB 1.0 specific BLR */ #define blr_current_role (unsigned char)174 #define blr_skip (unsigned char)175 /* FB 1.5 specific BLR */ #define blr_exec_sql (unsigned char)176 #define blr_internal_info (unsigned char)177 #define blr_nullsfirst (unsigned char)178 #define blr_writelock (unsigned char)179 #define blr_nullslast (unsigned char)180 /* FB 2.0 specific BLR */ #define blr_lowcase (unsigned char)181 #define blr_strlen (unsigned char)182 /* sub parameter for blr_strlen */ #define blr_strlen_bit (unsigned char)0 #define blr_strlen_char (unsigned char)1 #define blr_strlen_octet (unsigned char)2 #define blr_trim (unsigned char)183 /* first sub parameter for blr_trim */ #define blr_trim_both (unsigned char)0 #define blr_trim_leading (unsigned char)1 #define blr_trim_trailing (unsigned char)2 /* second sub parameter for blr_trim */ #define blr_trim_spaces (unsigned char)0 #define blr_trim_characters (unsigned char)1 /* These codes are actions for user-defined savepoints */ #define blr_savepoint_set (unsigned char)0 #define blr_savepoint_release (unsigned char)1 #define blr_savepoint_undo (unsigned char)2 #define blr_savepoint_release_single (unsigned char)3 /* These codes are actions for cursors */ #define blr_cursor_open (unsigned char)0 #define blr_cursor_close (unsigned char)1 #define blr_cursor_fetch (unsigned char)2 #define blr_cursor_fetch_scroll (unsigned char)3 /* scroll options */ #define blr_scroll_forward (unsigned char)0 #define blr_scroll_backward (unsigned char)1 #define blr_scroll_bof (unsigned char)2 #define blr_scroll_eof (unsigned char)3 #define blr_scroll_absolute (unsigned char)4 #define blr_scroll_relative (unsigned char)5 /* FB 2.1 specific BLR */ #define blr_init_variable (unsigned char)184 #define blr_recurse (unsigned char)185 #define blr_sys_function (unsigned char)186 // FB 2.5 specific BLR #define blr_auto_trans (unsigned char)187 #define blr_similar (unsigned char)188 #define blr_exec_stmt (unsigned char)189 // subcodes of blr_exec_stmt #define blr_exec_stmt_inputs (unsigned char) 1 // input parameters count #define blr_exec_stmt_outputs (unsigned char) 2 // output parameters count #define blr_exec_stmt_sql (unsigned char) 3 #define blr_exec_stmt_proc_block (unsigned char) 4 #define blr_exec_stmt_data_src (unsigned char) 5 #define blr_exec_stmt_user (unsigned char) 6 #define blr_exec_stmt_pwd (unsigned char) 7 #define blr_exec_stmt_tran (unsigned char) 8 // not implemented yet #define blr_exec_stmt_tran_clone (unsigned char) 9 // make transaction parameters equal to current transaction #define blr_exec_stmt_privs (unsigned char) 10 #define blr_exec_stmt_in_params (unsigned char) 11 // not named input parameters #define blr_exec_stmt_in_params2 (unsigned char) 12 // named input parameters #define blr_exec_stmt_out_params (unsigned char) 13 // output parameters #define blr_exec_stmt_role (unsigned char) 14 #define blr_stmt_expr (unsigned char) 190 #define blr_derived_expr (unsigned char) 191 // FB 3.0 specific BLR #define blr_procedure3 (unsigned char) 192 #define blr_exec_proc2 (unsigned char) 193 #define blr_function2 (unsigned char) 194 #define blr_window (unsigned char) 195 #define blr_partition_by (unsigned char) 196 #define blr_continue_loop (unsigned char) 197 #define blr_procedure4 (unsigned char) 198 #define blr_agg_function (unsigned char) 199 #define blr_substring_similar (unsigned char) 200 #define blr_bool_as_value (unsigned char) 201 #define blr_coalesce (unsigned char) 202 #define blr_decode (unsigned char) 203 #define blr_exec_subproc (unsigned char) 204 #define blr_subproc_decl (unsigned char) 205 #define blr_subproc (unsigned char) 206 #define blr_subfunc_decl (unsigned char) 207 #define blr_subfunc (unsigned char) 208 #define blr_record_version2 (unsigned char) 209 #endif // JRD_BLR_H *) { SQL subtypes definitions from RDB$FIELDS} CS_NONE = 0; CS_BINARY = 1; CS_ASCII = 2; CS_UNICODE_FSS = 3; CS_UTF8 = 4; CS_SJIS_0208 = 5; CS_EUCJ_0208 = 6; CS_DOS737 = 9; CS_DOS437 = 10; CS_DOS850 = 11; CS_DOS865 = 12; CS_DOS860 = 13; CS_DOS863 = 14; CS_DOS775 = 15; CS_DOS858 = 16; CS_DOS862 = 17; CS_DOS864 = 18; CS_NEXT = 19; CS_ISO8859_1 = 21; CS_ISO8859_2 = 22; CS_ISO8859_3 = 23; CS_ISO8859_4 = 24; CS_ISO8859_5 = 35; CS_ISO8859_6 = 36; CS_ISO8859_7 = 37; CS_ISO8859_8 = 38; CS_ISO8859_9 = 39; CS_ISO8859_13 = 40; CS_KSC_5601 = 44; CS_DOS852 = 45; CS_DOS857 = 46; CS_DOS861 = 47; CS_DOS866 = 48; CS_DOS869 = 49; CS_CYRL = 50; CS_WIN1250 = 51; CS_WIN1251 = 52; CS_WIN1252 = 53; CS_WIN1253 = 54; CS_WIN1254 = 55; CS_WIN1255 = 58; CS_WIN1256 = 59; CS_WIN1257 = 60; CS_BIG_5 = 56; CS_GB_2312 = 57; CS_KOI8R = 63; CS_KOI8U = 64; CS_WIN1258 = 65; CS_TIS620 = 66; CS_GBK = 67; CS_CP943C = 68; CS_GB18030 = 69; CS_METADATA = CS_UNICODE_FSS; RDB_NUMBERS_NONE = 0; RDB_NUMBERS_NUMERIC = 1; RDB_NUMBERS_DECIMAL = 2; { Blob Subtypes } { types less than zero are reserved for customer use } isc_blob_untyped = 0; { internal subtypes } isc_blob_text = 1; isc_blob_blr = 2; isc_blob_acl = 3; isc_blob_ranges = 4; isc_blob_summary = 5; isc_blob_format = 6; isc_blob_tra = 7; isc_blob_extfile = 8; isc_blob_debug_info = 9; isc_blob_max_predefined_subtype= 10; { > FB2.5 down} { the range 20-30 is reserved for dBASE and Paradox types } isc_blob_formatted_memo = 20; isc_blob_paradox_ole = 21; isc_blob_graphic = 22; isc_blob_dbase_ole = 23; isc_blob_typed_binary = 24; { FB2.5 down < } {* Blob information items *} isc_info_blob_num_segments = 4; isc_info_blob_max_segment = 5; isc_info_blob_total_length = 6; isc_info_blob_type = 7; {* error codes *} isc_segment = 335544366; isc_segstr_eof = 335544367; isc_lock_conflict = 335544345; { Database parameter block stuff } isc_dpb_version1 = 1; isc_dpb_cdd_pathname = 1; isc_dpb_allocation = 2; isc_dpb_journal = 3; isc_dpb_page_size = 4; isc_dpb_num_buffers = 5; isc_dpb_buffer_length = 6; isc_dpb_debug = 7; isc_dpb_garbage_collect = 8; isc_dpb_verify = 9; isc_dpb_sweep = 10; isc_dpb_enable_journal = 11; isc_dpb_disable_journal = 12; isc_dpb_dbkey_scope = 13; isc_dpb_number_of_users = 14; isc_dpb_trace = 15; isc_dpb_no_garbage_collect = 16; isc_dpb_damaged = 17; isc_dpb_license = 18; isc_dpb_sys_user_name = 19; isc_dpb_encrypt_key = 20; isc_dpb_activate_shadow = 21; isc_dpb_sweep_interval = 22; isc_dpb_delete_shadow = 23; isc_dpb_force_write = 24; isc_dpb_begin_log = 25; isc_dpb_quit_log = 26; isc_dpb_no_reserve = 27; isc_dpb_user_name = 28; isc_dpb_password = 29; isc_dpb_password_enc = 30; isc_dpb_sys_user_name_enc = 31; isc_dpb_interp = 32; isc_dpb_online_dump = 33; isc_dpb_old_file_size = 34; isc_dpb_old_num_files = 35; isc_dpb_old_file = 36; isc_dpb_old_start_page = 37; isc_dpb_old_start_seqno = 38; isc_dpb_old_start_file = 39; isc_dpb_drop_walfile = 40; isc_dpb_old_dump_id = 41; isc_dpb_wal_backup_dir = 42; isc_dpb_wal_chkptlen = 43; isc_dpb_wal_numbufs = 44; isc_dpb_wal_bufsize = 45; isc_dpb_wal_grp_cmt_wait = 46; isc_dpb_lc_messages = 47; isc_dpb_lc_ctype = 48; isc_dpb_cache_manager = 49; isc_dpb_shutdown = 50; isc_dpb_online = 51; isc_dpb_shutdown_delay = 52; isc_dpb_reserved = 53; isc_dpb_overwrite = 54; isc_dpb_sec_attach = 55; isc_dpb_disable_wal = 56; isc_dpb_connect_timeout = 57; isc_dpb_dummy_packet_interval = 58; isc_dpb_gbak_attach = 59; isc_dpb_sql_role_name = 60; isc_dpb_set_page_buffers = 61; isc_dpb_working_directory = 62; isc_dpb_SQL_dialect = 63; isc_dpb_set_db_readonly = 64; isc_dpb_set_db_SQL_dialect = 65; isc_dpb_gfix_attach = 66; isc_dpb_gstat_attach = 67; isc_dpb_last_dpb_constant = isc_dpb_gstat_attach; { isc_dpb_verify specific flags } isc_dpb_pages = 1; isc_dpb_records = 2; isc_dpb_indices = 4; isc_dpb_transactions = 8; isc_dpb_no_update = 16; isc_dpb_repair = 32; isc_dpb_ignore = 64; { isc_dpb_shutdown specific flags } isc_dpb_shut_cache = 1; isc_dpb_shut_attachment = 2; isc_dpb_shut_transaction = 4; isc_dpb_shut_force = 8; { Transaction parameter block stuff } isc_tpb_version1 = 1; isc_tpb_version3 = 3; isc_tpb_consistency = 1; isc_tpb_concurrency = 2; isc_tpb_shared = 3; isc_tpb_protected = 4; isc_tpb_exclusive = 5; isc_tpb_wait = 6; isc_tpb_nowait = 7; isc_tpb_read = 8; isc_tpb_write = 9; isc_tpb_lock_read = 10; isc_tpb_lock_write = 11; isc_tpb_verb_time = 12; isc_tpb_commit_time = 13; isc_tpb_ignore_limbo = 14; isc_tpb_read_committed = 15; isc_tpb_autocommit = 16; isc_tpb_rec_version = 17; isc_tpb_no_rec_version = 18; isc_tpb_restart_requests = 19; isc_tpb_no_auto_undo = 20; isc_tpb_last_tpb_constant = isc_tpb_no_auto_undo; { Blob Parameter Block } isc_bpb_version1 = 1; isc_bpb_source_type = 1; isc_bpb_target_type = 2; isc_bpb_type = 3; isc_bpb_source_interp = 4; isc_bpb_target_interp = 5; isc_bpb_filter_parameter = 6; { SQL information items } isc_info_sql_select = 4; isc_info_sql_bind = 5; isc_info_sql_num_variables = 6; isc_info_sql_describe_vars = 7; isc_info_sql_describe_end = 8; isc_info_sql_sqlda_seq = 9; isc_info_sql_message_seq = 10; isc_info_sql_type = 11; isc_info_sql_sub_type = 12; isc_info_sql_scale = 13; isc_info_sql_length = 14; isc_info_sql_null_ind = 15; isc_info_sql_field = 16; isc_info_sql_relation = 17; isc_info_sql_owner = 18; isc_info_sql_alias = 19; isc_info_sql_sqlda_start = 20; isc_info_sql_stmt_type = 21; isc_info_sql_get_plan = 22; isc_info_sql_records = 23; isc_info_sql_batch_fetch = 24; { SQL information return values } isc_info_sql_stmt_select = 1; isc_info_sql_stmt_insert = 2; isc_info_sql_stmt_update = 3; isc_info_sql_stmt_delete = 4; isc_info_sql_stmt_ddl = 5; isc_info_sql_stmt_get_segment = 6; isc_info_sql_stmt_put_segment = 7; isc_info_sql_stmt_exec_procedure = 8; isc_info_sql_stmt_start_trans = 9; isc_info_sql_stmt_commit = 10; isc_info_sql_stmt_rollback = 11; isc_info_sql_stmt_select_for_upd = 12; isc_info_sql_stmt_set_generator = 13; isc_bpb_type_segmented = 0; isc_bpb_type_stream = 1; {************** Information call declarations **************} { Common, structural codes } isc_info_end = 1; isc_info_truncated = 2; isc_info_error = 3; isc_info_data_not_ready = 4; isc_info_flag_end = 127; { Request information items } isc_info_number_messages = 4; isc_info_max_message = 5; isc_info_max_send = 6; isc_info_max_receive = 7; isc_info_state = 8; isc_info_message_number = 9; isc_info_message_size = 10; isc_info_request_cost = 11; isc_info_access_path = 12; isc_info_req_select_count = 13; isc_info_req_insert_count = 14; isc_info_req_update_count = 15; isc_info_req_delete_count = 16; { Database information items } isc_info_db_id = 4; isc_info_reads = 5; isc_info_writes = 6; isc_info_fetches = 7; isc_info_marks = 8; isc_info_implementation = 11; isc_info_version = 12; isc_info_base_level = 13; isc_info_page_size = 14; isc_info_num_buffers = 15; isc_info_limbo = 16; isc_info_current_memory = 17; isc_info_max_memory = 18; isc_info_window_turns = 19; isc_info_license = 20; isc_info_allocation = 21; isc_info_attachment_id = 22; isc_info_read_seq_count = 23; isc_info_read_idx_count = 24; isc_info_insert_count = 25; isc_info_update_count = 26; isc_info_delete_count = 27; isc_info_backout_count = 28; isc_info_purge_count = 29; isc_info_expunge_count = 30; isc_info_sweep_interval = 31; isc_info_ods_version = 32; isc_info_ods_minor_version = 33; isc_info_no_reserve = 34; isc_info_logfile = 35; isc_info_cur_logfile_name = 36; isc_info_cur_log_part_offset = 37; isc_info_num_wal_buffers = 38; isc_info_wal_buffer_size = 39; isc_info_wal_ckpt_length = 40; isc_info_wal_cur_ckpt_interval = 41; isc_info_wal_prv_ckpt_fname = 42; isc_info_wal_prv_ckpt_poffset = 43; isc_info_wal_recv_ckpt_fname = 44; isc_info_wal_recv_ckpt_poffset = 45; isc_info_wal_grpc_wait_usecs = 47; isc_info_wal_num_io = 48; isc_info_wal_avg_io_size = 49; isc_info_wal_num_commits = 50; isc_info_wal_avg_grpc_size = 51; isc_info_forced_writes = 52; isc_info_user_names = 53; isc_info_page_errors = 54; isc_info_record_errors = 55; isc_info_bpage_errors = 56; isc_info_dpage_errors = 57; isc_info_ipage_errors = 58; isc_info_ppage_errors = 59; isc_info_tpage_errors = 60; isc_info_set_page_buffers = 61; isc_info_db_SQL_dialect = 62; isc_info_db_read_only = 63; isc_info_db_size_in_pages = 64; frb_info_att_charset = 101; isc_info_db_class = 102; isc_info_firebird_version = 103; isc_info_oldest_transaction = 104; isc_info_oldest_active = 105; isc_info_oldest_snapshot = 106; isc_info_next_transaction = 107; isc_info_db_provider = 108; isc_info_active_transactions = 109; isc_info_active_tran_count = 110; isc_info_creation_date = 111; isc_info_db_file_size = 112; type ULong = Cardinal; UChar = AnsiChar; Short = SmallInt; ISC_LONG = LongInt; UISC_LONG = ULong; ISC_INT64 = Int64; ISC_STATUS = NativeInt; UISC_STATUS = ULong; PISC_LONG = ^ISC_LONG; PUISC_LONG = ^UISC_LONG; PISC_STATUS = ^ISC_STATUS; PPISC_STATUS = ^PISC_STATUS; PUISC_STATUS = ^UISC_STATUS; PShort = ^Short; PPAnsiChar = ^PAnsiChar; UShort = Word; PVoid = Pointer; { C Date/Time Structure } TCTimeStructure = record tm_sec: Integer; { Seconds } tm_min: Integer; { Minutes } tm_hour: Integer; { Hour (0--23) } tm_mday: Integer; { Day of month (1--31) } tm_mon: Integer; { Month (0--11) } tm_year: Integer; { Year (calendar year minus 1900) } tm_wday: Integer; { Weekday (0--6) Sunday = 0) } tm_yday: Integer; { Day of year (0--365) } tm_isdst: Integer; { 0 if daylight savings time is not in effect) } end; PCTimeStructure = ^TCTimeStructure; TM = TCTimeStructure; PTM = ^TM; TISC_VARYING = record strlen: Short; str: array[0..0] of AnsiChar; //AVZ - was AnsiChar end; PISC_VARYING = ^TISC_VARYING; { InterBase Handle Definitions } //ludob ib/FB handles are 32 bit even on 64 bit systems TISC_BLOB_HANDLE = LongWord; PISC_BLOB_HANDLE = ^TISC_BLOB_HANDLE; TISC_DB_HANDLE = LongWord; PISC_DB_HANDLE = ^TISC_DB_HANDLE; TISC_STMT_HANDLE = LongWord; PISC_STMT_HANDLE = ^TISC_STMT_HANDLE; TISC_TR_HANDLE = LongWord; PISC_TR_HANDLE = ^TISC_TR_HANDLE; TISC_CALLBACK = procedure; { Time & Date Support } ISC_DATE = LongInt; PISC_DATE = ^ISC_DATE; ISC_TIME = ULong; PISC_TIME = ^ISC_TIME; TISC_TIMESTAMP = record timestamp_date: ISC_DATE; timestamp_time: ISC_TIME; end; PISC_TIMESTAMP = ^TISC_TIMESTAMP; { Blob id structure } TGDS_QUAD = record gds_quad_high: ISC_LONG; gds_quad_low: UISC_LONG; end; PGDS_QUAD = ^TGDS_QUAD; TISC_QUAD = TGDS_QUAD; PISC_QUAD = ^TISC_QUAD; TISC_ARRAY_BOUND = record array_bound_lower: Short; array_bound_upper: Short; end; PISC_ARRAY_BOUND = ^TISC_ARRAY_BOUND; TISC_ARRAY_DESC = record array_desc_dtype: Byte; array_desc_scale: ShortInt; array_desc_length: Word; array_desc_field_name: array[0..31] of AnsiChar; array_desc_relation_name: array[0..31] of AnsiChar; array_desc_dimensions: Short; array_desc_flags: Short; array_desc_bounds: array[0..15] of TISC_ARRAY_BOUND; end; PISC_ARRAY_DESC = ^TISC_ARRAY_DESC; TISC_BLOB_DESC = record blob_desc_subtype: Short; blob_desc_charset: Short; blob_desc_segment_size: Short; blob_desc_field_name: array[0..31] of UChar; blob_desc_relation_name: array[0..31] of UChar; end; PISC_BLOB_DESC = ^TISC_BLOB_DESC; { Declare the extended SQLDA } TXSQLVAR = record sqltype: Short; { datatype of field } sqlscale: Short; { scale factor } sqlsubtype: Short; { datatype subtype - BLOBs } { & text types only } sqllen: Short; { length of data area } sqldata: PAnsiChar; { address of data } sqlind: PSmallInt; { address of indicator } { variable } sqlname_length: Short; { length of sqlname field } { name of field, name length + space for NULL } sqlname: array[0..31] of AnsiChar; relname_length: Short; { length of relation name } { field's relation name + space for NULL } relname: array[0..31] of AnsiChar; ownname_length: Short; { length of owner name } { relation's owner name + space for NULL } ownname: array[0..31] of AnsiChar; aliasname_length: Short; { length of alias name } { relation's alias name + space for NULL } aliasname: array[0..31] of AnsiChar; end; PXSQLVAR = ^TXSQLVAR; TXSQLDA = record version: Short; { version of this XSQLDA } { XSQLDA name field } sqldaid: array[0..7] of AnsiChar; sqldabc: ISC_LONG; { length in bytes of SQLDA } sqln: Short; { number of fields allocated } sqld: Short; { actual number of fields } { first field address } sqlvar: array[0..0] of TXSQLVAR; end; PXSQLDA = ^TXSQLDA; {****************************************************} { This record type is for passing arguments to } { isc_start_transaction (See docs) } {****************************************************} TISC_START_TRANS = record db_handle: PISC_DB_HANDLE; tpb_length: Word; tpb_address: PAnsiChar; end; {****************************************************} { This record type is for passing arguments to } { isc_start_multiple (see docs) } {****************************************************} TISC_TEB = record db_handle: PISC_DB_HANDLE; tpb_length: LongInt; tpb_address: PAnsiChar; end; PISC_TEB = ^TISC_TEB; TISC_TEB_ARRAY = array[0..0] of TISC_TEB; PISC_TEB_ARRAY = ^TISC_TEB_ARRAY; { Interbase status array } PARRAY_ISC_STATUS = ^TARRAY_ISC_STATUS; TARRAY_ISC_STATUS = array[0..20] of ISC_STATUS; { ************** Plain API Function types definition ************* } { General database routines } Tisc_attach_database = function(status_vector: PISC_STATUS; db_name_length: Short; db_name: PAnsiChar; db_handle: PISC_DB_HANDLE; parm_buffer_length: Short; parm_buffer: PAnsiChar): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_detach_database = function(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_drop_database = function(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_database_info = function(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; item_list_buffer_length: Short; item_list_buffer: PAnsiChar; result_buffer_length: Short; result_buffer: PAnsiChar): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; { Array processing routines } Tisc_array_gen_sdl = function(status_vector: PISC_STATUS; isc_array_desc: PISC_ARRAY_DESC; isc_arg3: PShort; isc_arg4: PAnsiChar; isc_arg5: PShort): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_array_get_slice = function(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; trans_handle: PISC_TR_HANDLE; array_id: PISC_QUAD; descriptor: PISC_ARRAY_DESC; dest_array: PVoid; slice_length: ISC_LONG): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_array_lookup_bounds = function(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; trans_handle: PISC_TR_HANDLE; table_name, column_name: PAnsiChar; descriptor: PISC_ARRAY_DESC): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_array_lookup_desc = function(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; trans_handle: PISC_TR_HANDLE; table_name, column_name: PAnsiChar; descriptor: PISC_ARRAY_DESC): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_array_set_desc = function(status_vector: PISC_STATUS; table_name: PAnsiChar; column_name: PAnsiChar; sql_dtype, sql_length, sql_dimensions: PShort; descriptor: PISC_ARRAY_DESC): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_array_put_slice = function(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; trans_handle: PISC_TR_HANDLE; array_id: PISC_QUAD; descriptor: PISC_ARRAY_DESC; source_array: PVoid; slice_length: PISC_LONG): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_free = function(isc_arg1: PAnsiChar): ISC_LONG; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_sqlcode = function(status_vector: PISC_STATUS): ISC_LONG; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_sql_interprete = procedure(sqlcode: Short; buffer: PAnsiChar; buffer_length: Short); {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_interprete = function(buffer: PAnsiChar; status_vector: PPISC_STATUS): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tfb_interpret = function(buffer: PAnsiChar; bufsize: integer; status_vector: PPISC_STATUS): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; { Transaction support routines } Tisc_start_transaction = function(status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE; db_handle_count: Short; db_handle: PISC_DB_HANDLE; tpb_length: Word; tpb_address: PAnsiChar): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_start_multiple = function(status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE; db_handle_count: Short; teb_vector_address: PISC_TEB): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_rollback_transaction = function(status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_rollback_retaining = function(status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_commit_retaining = function(status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_commit_transaction = function(status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_transaction_info = function(status_vector: PISC_STATUS; tr_handle: PISC_TR_HANDLE; item_list_buffer_length: Short; item_list_buffer: PAnsiChar; result_buffer_length: Short; result_buffer: PAnsiChar): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; { Dynamic SQL routines } Tisc_dsql_allocate_statement = function(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; stmt_handle: PISC_STMT_HANDLE): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_dsql_alloc_statement2 = function(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; stmt_handle: PISC_STMT_HANDLE): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_dsql_describe = function(status_vector: PISC_STATUS; stmt_handle: PISC_STMT_HANDLE; dialect: Word; xsqlda: PXSQLDA): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_dsql_describe_bind = function(status_vector: PISC_STATUS; stmt_handle: PISC_STMT_HANDLE; dialect: Word; xsqlda: PXSQLDA): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_dsql_execute = function(status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE; stmt_handle: PISC_STMT_HANDLE; dialect: Word; xsqlda: PXSQLDA): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_dsql_execute2 = function(status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE; stmt_handle: PISC_STMT_HANDLE; dialect: Word; in_xsqlda, out_xsqlda: PXSQLDA): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_dsql_execute_immediate = function(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; tran_handle: PISC_TR_HANDLE; length: Word; statement: PAnsiChar; dialect: Word; xsqlda: PXSQLDA): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_dsql_fetch = function(status_vector: PISC_STATUS; stmt_handle: PISC_STMT_HANDLE; dialect: Word; xsqlda: PXSQLDA): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_dsql_free_statement = function(status_vector: PISC_STATUS; stmt_handle: PISC_STMT_HANDLE; options: Word): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_dsql_prepare = function(status_vector: PISC_STATUS; tran_handle: PISC_TR_HANDLE; stmt_handle: PISC_STMT_HANDLE; length: Word; statement: PAnsiChar; dialect: Word; xsqlda: PXSQLDA): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_dsql_set_cursor_name = function(status_vector: PISC_STATUS; stmt_handle: PISC_STMT_HANDLE; cursor_name: PAnsiChar; _type: Word): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_dsql_sql_info = function(status_vector: PISC_STATUS; stmt_handle: PISC_STMT_HANDLE; item_length: Short; items: PAnsiChar; buffer_length: Short; buffer: PAnsiChar): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; { Blob processing routines } Tisc_open_blob2 = function(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; tran_handle: PISC_TR_HANDLE; blob_handle: PISC_BLOB_HANDLE; blob_id: PISC_QUAD; bpb_length: Short; bpb_buffer: PAnsiChar): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_create_blob2 = function(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; tran_handle: PISC_TR_HANDLE; blob_handle: PISC_BLOB_HANDLE; blob_id: PISC_QUAD; bpb_length: Short; bpb_address: PAnsiChar): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_blob_info = function(status_vector: PISC_STATUS; blob_handle: PISC_BLOB_HANDLE; item_list_buffer_length: Short; item_list_buffer: PAnsiChar; result_buffer_length: Short; result_buffer: PAnsiChar): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_close_blob = function(status_vector: PISC_STATUS; blob_handle: PISC_BLOB_HANDLE): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_cancel_blob = function(status_vector: PISC_STATUS; blob_handle: PISC_BLOB_HANDLE): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_get_segment = function(status_vector: PISC_STATUS; blob_handle: PISC_BLOB_HANDLE; actual_seg_length: PWord; seg_buffer_length: Word; seg_buffer: PAnsiChar): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_put_segment = function(status_vector: PISC_STATUS; blob_handle: PISC_BLOB_HANDLE; seg_buffer_len: Word; seg_buffer: PAnsiChar): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; { Event processing routines } Tisc_event_block = function(event_buffer: PPAnsiChar; result_buffer: PPAnsiChar; id_count: Word; event_list: array of PAnsiChar): ISC_LONG; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_event_counts = procedure(status_vector: PISC_STATUS; buffer_length: Short; event_buffer: PAnsiChar; result_buffer: PAnsiChar); {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_cancel_events = function(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; event_id: PISC_LONG): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_que_events = function(status_vector: PISC_STATUS; db_handle: PISC_DB_HANDLE; event_id: PISC_LONG; length: Short; event_buffer: PAnsiChar; event_function: TISC_CALLBACK; event_function_arg: PVoid): ISC_STATUS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; { Types convertion routines } Tisc_decode_date = procedure(ib_date: PISC_QUAD; tm_date: PCTimeStructure); {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_encode_date = procedure(tm_date: PCTimeStructure; ib_date: PISC_QUAD); {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; { Interbase Version 6 routines } Tisc_decode_sql_date = procedure(ib_date: PISC_DATE; tm_date: PCTimeStructure); {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_decode_sql_time = procedure(ib_time: PISC_TIME; tm_date: PCTimeStructure); {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_decode_timestamp = procedure(ib_timestamp: PISC_TIMESTAMP; tm_date: PCTimeStructure); {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_encode_sql_date = procedure(tm_date: PCTimeStructure; ib_date: PISC_DATE); {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_encode_sql_time = procedure(tm_date: PCTimeStructure; ib_time: PISC_TIME); {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_encode_timestamp = procedure(tm_date: PCTimeStructure; ib_timestamp: PISC_TIMESTAMP); {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tisc_vax_integer = function(buffer: PAnsiChar; length: Short): ISC_LONG; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; { ************** Collection of Plain API Function types definition ************* } TZFirebird_API = record { General database routines } isc_attach_database: Tisc_attach_database; isc_detach_database: Tisc_detach_database; isc_drop_database: Tisc_drop_database; isc_database_info: Tisc_database_info; isc_free: Tisc_free; isc_sqlcode: Tisc_sqlcode; isc_sql_interprete: Tisc_sql_interprete; isc_interprete: Tisc_interprete; fb_interpret: Tfb_interpret; { Transaction support routines } isc_start_transaction: Tisc_start_transaction; isc_start_multiple: Tisc_start_multiple; isc_rollback_transaction: Tisc_rollback_transaction; isc_rollback_retaining: Tisc_rollback_retaining; isc_commit_transaction: Tisc_commit_transaction; isc_commit_retaining: Tisc_commit_retaining; isc_transaction_info: Tisc_transaction_info; { Dynamic SQL routines } isc_dsql_allocate_statement: Tisc_dsql_allocate_statement; isc_dsql_alloc_statement2: Tisc_dsql_alloc_statement2; isc_dsql_describe: Tisc_dsql_describe; isc_dsql_describe_bind: Tisc_dsql_describe_bind; isc_dsql_execute: Tisc_dsql_execute; isc_dsql_execute2: Tisc_dsql_execute2; isc_dsql_execute_immediate: Tisc_dsql_execute_immediate; isc_dsql_fetch: Tisc_dsql_fetch; isc_dsql_free_statement: Tisc_dsql_free_statement; isc_dsql_prepare: Tisc_dsql_prepare; isc_dsql_set_cursor_name: Tisc_dsql_set_cursor_name; isc_dsql_sql_info: Tisc_dsql_sql_info; { Array processing routines } isc_array_gen_sdl: Tisc_array_gen_sdl; isc_array_get_slice: Tisc_array_get_slice; isc_array_lookup_bounds: Tisc_array_lookup_bounds; isc_array_lookup_desc: Tisc_array_lookup_desc; isc_array_set_desc: Tisc_array_set_desc; isc_array_put_slice: Tisc_array_put_slice; { Blob processing routines } isc_open_blob2: Tisc_open_blob2; isc_create_blob2: Tisc_create_blob2; isc_blob_info: Tisc_blob_info; isc_close_blob: Tisc_close_blob; isc_cancel_blob: Tisc_cancel_blob; isc_get_segment: Tisc_get_segment; isc_put_segment: Tisc_put_segment; { Event processing routines } isc_que_events: Tisc_que_events; isc_event_counts: Tisc_event_counts; isc_event_block: Tisc_event_block; isc_cancel_events: Tisc_cancel_events; { Types convertion routines } isc_encode_date: Tisc_encode_date; isc_decode_date: Tisc_decode_date; isc_vax_integer: Tisc_vax_integer; isc_encode_sql_date: Tisc_encode_sql_date; isc_decode_sql_date: Tisc_decode_sql_date; isc_encode_sql_time: Tisc_encode_sql_time; isc_decode_sql_time: Tisc_decode_sql_time; isc_encode_timestamp: Tisc_encode_timestamp; isc_decode_timestamp: Tisc_decode_timestamp; end; implementation end. ================================================ FILE: lib/zeosdbo/src/plain/ZPlainLoader.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Utility Classes for Native Libraries } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZPlainLoader; interface {$I ZPlain.inc} uses Types, ZCompatibility; type {** Implements a loader for native library. } { TZNativeLibraryLoader } TZNativeLibraryLoader = class (TObject) private FLocations: TStringDynArray; {$IFDEF FPC} FHandle: PtrInt; {$ELSE} FHandle: THandle; //M.A. LongWord; {$ENDIF} FLoaded: Boolean; FCurrentLocation: String; function ZLoadLibrary(Location: String): Boolean; protected procedure FreeNativeLibrary; virtual; public constructor Create(Locations: array of string); destructor Destroy; override; procedure ClearLocations; procedure AddLocation(Location: String); function Load: Boolean; virtual; function LoadNativeLibrary: Boolean; virtual; function LoadNativeLibraryStrict(Location: String): Boolean; procedure LoadIfNeeded; virtual; property Loaded: Boolean read FLoaded write FLoaded; {$IFDEF FPC} property Handle: PtrInt read FHandle write FHandle; {$ELSE} property Handle: THandle { M.A. LongWord} read FHandle write FHandle; {$ENDIF} property CurrentLocation: String read FCurrentLocation write FCurrentLocation; function GetAddress(ProcName: PAnsiChar): Pointer; end; implementation uses SysUtils, {$IFNDEF UNIX} Windows, {$ELSE} {$IFNDEF FPC} libc, {$ENDIF} {$ENDIF} ZMessages; { TZNativeLibraryLoader } {** Creates this loader class and assignes main properties. @param Locations locations of native library on windows platform. } constructor TZNativeLibraryLoader.Create(Locations: array of string); var I: Integer; begin SetLength(FLocations, Length(Locations)); for I := 0 to High(Locations) do FLocations[I] := Locations[I]; FHandle := INVALID_HANDLE_VALUE; FCurrentLocation := ''; FLoaded := False; end; {** Destroys the library and cleanups the memory. } destructor TZNativeLibraryLoader.Destroy; begin if Loaded then FreeNativeLibrary; inherited Destroy; end; procedure TZNativeLibraryLoader.ClearLocations; begin SetLength(FLocations,0); end; procedure TZNativeLibraryLoader.AddLocation(Location: String); var i: integer; begin if Location <> '' then begin SetLength(FLocations, Length(FLocations) + 1); for i := High(FLocations) downto 1 do FLocations[i] := FLocations[i - 1]; FLocations[0] := Location; end; end; {** Loads a library module. @return True if library was successfully loaded. } function TZNativeLibraryLoader.Load: Boolean; begin Result := LoadNativeLibrary; end; {** Loads a library if it was not previously loaded. } procedure TZNativeLibraryLoader.LoadIfNeeded; begin if not Loaded then Load; end; function TZNativeLibraryLoader.ZLoadLibrary(Location: String): Boolean; var newpath, temp: String; // AB modif begin if FLoaded then Self.FreeNativeLibrary; temp := ''; //init for FPC FLoaded := False; Result := False; newpath := ExtractFilePath(Location); // AB modif BEGIN try if newpath <> '' then begin temp := GetCurrentDir; SetCurrentDir(newpath); end; // AB modif END {$IFDEF UNIX} {$IFDEF FPC} FHandle := LoadLibrary(PAnsiChar(Location)); {$ELSE} FHandle := HMODULE(dlopen(PAnsiChar(Location), RTLD_GLOBAL)); {$ENDIF} {$ELSE} FHandle := LoadLibrary(PChar(Location)); {$ENDIF} // AB modif BEGIN finally if temp<>'' then SetCurrentDir(temp); end; // AB modif END if (FHandle <> INVALID_HANDLE_VALUE) and (FHandle <> 0) then begin FLoaded := True; FCurrentLocation := Location; Result := True; end; end; {** Loads a library module and initializes the handle. @return True is library was successfully loaded. } function TZNativeLibraryLoader.LoadNativeLibrary: Boolean; var I: Integer; TriedLocations: string; begin TriedLocations := ''; for I := 0 to High(FLocations) do begin if ZLoadLibrary(FLocations[I]) then Break else if TriedLocations <> '' then TriedLocations := TriedLocations + ', ' + FLocations[I] else TriedLocations := FLocations[I]; end; if not Loaded then if (Length(FLocations) > 0) and FileExists(FLocations[High(FLocations)]) then raise Exception.Create(Format(SLibraryNotCompatible, [TriedLocations])) else raise Exception.Create(Format(SLibraryNotFound, [TriedLocations])); Result := True; end; function TZNativeLibraryLoader.LoadNativeLibraryStrict(Location: String): Boolean; begin If not ZLoadLibrary(Location) then if FileExists(Location) then raise Exception.Create(Format(SLibraryNotCompatible, [Location])) else raise Exception.Create(Format(SLibraryNotFound, [Location])); Result := True; end; {** Frees a previously loaded library. } procedure TZNativeLibraryLoader.FreeNativeLibrary; begin if (FHandle <> INVALID_HANDLE_VALUE) and (FHandle <> 0) and Loaded then FreeLibrary(Handle); FHandle := INVALID_HANDLE_VALUE; FLoaded := False; FCurrentLocation := ''; end; {** Gets a procedure address from the loaded library by its name. @param ProcName a name of the procedure. @return a procedure address. } function TZNativeLibraryLoader.GetAddress(ProcName: PAnsiChar): Pointer; begin Result := GetProcAddress(Handle, ProcName); end; end. ================================================ FILE: lib/zeosdbo/src/plain/ZPlainMySqlConstants.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Delphi plain interface to libmysql.dll } { Version 4.1 } { } { Originally written by Sergey Seroukhov } { } { Thanks to : } { Pascal Data Objects Library } { } { Copyright (c) 2006 John Marino, www.synsport.com } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZPlainMySqlConstants; interface {$I ZPlain.inc} uses ZCompatibility; const { General Declarations } MYSQL_ERRMSG_SIZE = 512; SQLSTATE_LENGTH = 5; MYSQL_PORT = 3306; LOCAL_HOST = 'localhost'; { Enum Field Types } { FIELD_TYPE_DECIMAL = 0; FIELD_TYPE_TINY = 1; FIELD_TYPE_SHORT = 2; FIELD_TYPE_LONG = 3; FIELD_TYPE_FLOAT = 4; FIELD_TYPE_DOUBLE = 5; FIELD_TYPE_NULL = 6; FIELD_TYPE_TIMESTAMP = 7; FIELD_TYPE_LONGLONG = 8; FIELD_TYPE_INT24 = 9; FIELD_TYPE_DATE = 10; FIELD_TYPE_TIME = 11; FIELD_TYPE_DATETIME = 12; FIELD_TYPE_YEAR = 13; FIELD_TYPE_NEWDATE = 14; FIELD_TYPE_VARCHAR = 15; //<--ADDED by fduenas 20-06-2006 FIELD_TYPE_BIT = 16; //<--ADDED by fduenas 20-06-2006 FIELD_TYPE_NEWDECIMAL = 246; //<--ADDED by fduenas 20-06-2006 FIELD_TYPE_ENUM = 247; FIELD_TYPE_SET = 248; FIELD_TYPE_TINY_BLOB = 249; FIELD_TYPE_MEDIUM_BLOB = 250; FIELD_TYPE_LONG_BLOB = 251; FIELD_TYPE_BLOB = 252; FIELD_TYPE_VAR_STRING = 253; FIELD_TYPE_STRING = 254; FIELD_TYPE_GEOMETRY = 255; } { For Compatibility } { FIELD_TYPE_CHAR = FIELD_TYPE_TINY; FIELD_TYPE_INTERVAL = FIELD_TYPE_ENUM; } { Field's flags } NOT_NULL_FLAG = 1; { Field can't be NULL } PRI_KEY_FLAG = 2; { Field is part of a primary key } UNIQUE_KEY_FLAG = 4; { Field is part of a unique key } MULTIPLE_KEY_FLAG = 8; { Field is part of a key } BLOB_FLAG = 16; { Field is a blob } UNSIGNED_FLAG = 32; { Field is unsigned } ZEROFILL_FLAG = 64; { Field is zerofill } BINARY_FLAG = 128; { Field is binary } ENUM_FLAG = 256; { Field is an enum } AUTO_INCREMENT_FLAG = 512; { Field is a autoincrement field } TIMESTAMP_FLAG = 1024; { Field is a timestamp } SET_FLAG = 2048; { Field is a set } NUM_FLAG = 32768; { Field is num (for clients) } PART_KEY_FLAG = 16384; { Intern; Part of some key } GROUP_FLAG = 32768; { Intern: Group field } UNIQUE_FLAG = 65536; { Intern: Used by sql_yacc } BINCMP_FLAG = $20000; { Intern: Used by sql_yacc } GET_FIXED_FIELDS_FLAG = $40000; { Used to get fields in item tree } FIELD_IN_PART_FUNC_FLAG= $80000; { Field part of partition func } FIELD_IN_ADD_INDEX = $100000; { Intern: Field used in ADD INDEX } FIELD_IS_RENAMED = $200000; { Intern: Field is being renamed} { Client Connection Options } _CLIENT_LONG_PASSWORD = 1; { new more secure passwords } _CLIENT_FOUND_ROWS = 2; { Found instead of affected rows } _CLIENT_LONG_FLAG = 4; { Get all column flags } _CLIENT_CONNECT_WITH_DB = 8; { One can specify db on connect } _CLIENT_NO_SCHEMA = 16; { Don't allow database.table.column } _CLIENT_COMPRESS = 32; { Can use compression protcol } _CLIENT_ODBC = 64; { Odbc client } _CLIENT_LOCAL_FILES = 128; { Can use LOAD DATA LOCAL } _CLIENT_IGNORE_SPACE = 256; { Ignore spaces before '(' } _CLIENT_CHANGE_USER = 512; { Support the mysql_change_user() } _CLIENT_INTERACTIVE = 1024; { This is an interactive client } _CLIENT_SSL = 2048; { Switch to SSL after handshake } _CLIENT_IGNORE_SIGPIPE = 4096; { IGNORE sigpipes } _CLIENT_TRANSACTIONS = 8196; { Client knows about transactions } _CLIENT_RESERVED = 16384; { Old flag for 4.1 protocol } _CLIENT_SECURE_CONNECTION = 32768; { New 4.1 authentication } _CLIENT_MULTI_STATEMENTS = 65536; { Enable/disable multi-stmt support } _CLIENT_MULTI_RESULTS = 131072; { Enable/disable multi-results } _CLIENT_PS_MULTI_RESULTS = 262144; { Enable Multi-results in PS-protocol } _CLIENT_PLUGIN_AUTH = 524288; _CLIENT_SSL_VERIFY_SERVER_CERT = 1073741824; _CLIENT_REMEMBER_OPTIONS = 2147483648; {Enable/disable multi-results } {THD: Killable} MYSQL_SHUTDOWN_KILLABLE_CONNECT = 1; MYSQL_SHUTDOWN_KILLABLE_TRANS = 2; MYSQL_SHUTDOWN_KILLABLE_LOCK_TABLE = 4; MYSQL_SHUTDOWN_KILLABLE_UPDATE = 8; {prepared fetch results} STMT_FETCH_OK = 0; STMT_FETCH_ERROR = 1; STMT_FETCH_NO_DATA = 100; STMT_FETCH_DATA_TRUNC = 101; {status codes} const MYSQL_NO_DATA = 100; MYSQL_DATA_TRUNCATED = 101; type TMySqlOption = ( MYSQL_OPT_CONNECT_TIMEOUT, MYSQL_OPT_COMPRESS, MYSQL_OPT_NAMED_PIPE, MYSQL_INIT_COMMAND, MYSQL_READ_DEFAULT_FILE, MYSQL_READ_DEFAULT_GROUP, MYSQL_SET_CHARSET_DIR, MYSQL_SET_CHARSET_NAME, MYSQL_OPT_LOCAL_INFILE, MYSQL_OPT_PROTOCOL, MYSQL_SHARED_MEMORY_BASE_NAME, MYSQL_OPT_READ_TIMEOUT, MYSQL_OPT_WRITE_TIMEOUT, MYSQL_OPT_USE_RESULT, MYSQL_OPT_USE_REMOTE_CONNECTION, MYSQL_OPT_USE_EMBEDDED_CONNECTION, MYSQL_OPT_GUESS_CONNECTION, MYSQL_SET_CLIENT_IP, MYSQL_SECURE_AUTH, MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, MYSQL_PLUGIN_DIR, MYSQL_DEFAULT_AUTH, MYSQL_OPT_BIND, MYSQL_OPT_SSL_KEY, MYSQL_OPT_SSL_CERT, MYSQL_OPT_SSL_CA, MYSQL_OPT_SSL_CAPATH, MYSQL_OPT_SSL_CIPHER, MYSQL_OPT_SSL_CRL, MYSQL_OPT_SSL_CRLPATH, MYSQL_OPT_CONNECT_ATTR_RESET, MYSQL_OPT_CONNECT_ATTR_ADD, MYSQL_OPT_CONNECT_ATTR_DELETE, MYSQL_SERVER_PUBLIC_KEY, MYSQL_ENABLE_CLEARTEXT_PLUGIN, MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS, MYSQL_OPT_SSL_ENFORCE ); const TMySqlOptionMinimumVersion: array[TMySqlOption] of Integer = ( {MYSQL_OPT_CONNECT_TIMEOUT} 0, {MYSQL_OPT_COMPRESS} 0, {MYSQL_OPT_NAMED_PIPE} 0, {MYSQL_INIT_COMMAND} 0, {MYSQL_READ_DEFAULT_FILE} 0, {MYSQL_READ_DEFAULT_GROUP} 0, {MYSQL_SET_CHARSET_DIR} 0, {MYSQL_SET_CHARSET_NAME} 0, {MYSQL_OPT_LOCAL_INFILE} 0, {MYSQL_OPT_PROTOCOL} 40100, {MYSQL_SHARED_MEMORY_BASE_NAME} 40100, {MYSQL_OPT_READ_TIMEOUT} 40101, {MYSQL_OPT_WRITE_TIMEOUT} 40101, {MYSQL_OPT_USE_RESULT} 40101, {MYSQL_OPT_USE_REMOTE_CONNECTION} 40101, {MYSQL_OPT_USE_EMBEDDED_CONNECTION} 40101, {MYSQL_OPT_GUESS_CONNECTION} 40101, {MYSQL_SET_CLIENT_IP} 40101, {MYSQL_SECURE_AUTH} 40101, {MYSQL_REPORT_DATA_TRUNCATION} 40101, {MYSQL_OPT_RECONNECT} 50013, {MYSQL_OPT_SSL_VERIFY_SERVER_CERT} 50023, {MYSQL_PLUGIN_DIR} 50507, {MYSQL_DEFAULT_AUTH} 50507, {MYSQL_OPT_BIND} 50601, {MYSQL_OPT_SSL_KEY} 50603, {MYSQL_OPT_SSL_CERT} 50603, {MYSQL_OPT_SSL_CA} 50603, {MYSQL_OPT_SSL_CAPATH} 50603, {MYSQL_OPT_SSL_CIPHER} 50603, {MYSQL_OPT_SSL_CRL} 50603, {MYSQL_OPT_SSL_CRLPATH} 50603, {MYSQL_OPT_CONNECT_ATTR_RESET} 50606, {MYSQL_OPT_CONNECT_ATTR_ADD} 50606, {MYSQL_OPT_CONNECT_ATTR_DELETE} 50606, {MYSQL_SERVER_PUBLIC_KEY} 50606, {MYSQL_ENABLE_CLEARTEXT_PLUGIN} 50607, {MYSQL_OPT_CAN_HANDLE_EXPIRED_PASSWORDS} 50610, {MYSQL_OPT_SSL_ENFORCE} 50703 ); type PUSED_MEM=^USED_MEM; USED_MEM = packed record next: PUSED_MEM; left: Integer; size: Integer; end; PERR_PROC = ^ERR_PROC; ERR_PROC = procedure; PMEM_ROOT = ^MEM_ROOT; MEM_ROOT = packed record free: PUSED_MEM; used: PUSED_MEM; pre_alloc: PUSED_MEM; min_malloc: Integer; block_size: Integer; block_num: Integer; first_block_usage: Integer; error_handler: PERR_PROC; end; MYSQL_ROW = array[00..$ff] of PAnsiChar; PMYSQL_ROW = ^MYSQL_ROW; PMYSQL_ROWS = ^MYSQL_ROWS; MYSQL_ROWS = record next: PMYSQL_ROWS; data: PMYSQL_ROW; end; MYSQL_ROW_OFFSET = PMYSQL_ROWS; MYSQL_DATA = record Rows: Int64; Fields: Cardinal; Data: PMYSQL_ROWS; Alloc: MEM_ROOT; end; PMYSQL_DATA = ^MYSQL_DATA; MYSQL_FIELD_OFFSET = UInt; PMYSQL_OPTIONS = ^_MYSQL_OPTIONS; _MYSQL_OPTIONS = record connect_timeout: UInt; read_timeout: UInt; write_timeout: UInt; port: UInt; protocol: UInt; client_flag: ULong; host: PAnsiChar; user: PAnsiChar; password: PAnsiChar; unix_socket: PAnsiChar; db: PAnsiChar; init_commands: Pointer; my_cnf_file: PAnsiChar; my_cnf_group: PAnsiChar; charset_dir: PAnsiChar; charset_name: PAnsiChar; ssl_key: PAnsiChar; ssl_cert: PAnsiChar; ssl_ca: PAnsiChar; ssl_capath: PAnsiChar; ssl_cipher: PAnsiChar; shared_memory_base_name: PAnsiChar; max_allowed_packet: ULong; use_ssl: Byte; compress: Byte; named_pipe: Byte; unused1: Byte; unused2: Byte; unused3: Byte; unused4: Byte; methods_to_use: TMySqlOption; client_ip: PAnsiChar; secure_auth: Byte; local_infile_init: Pointer; local_infile_read: Pointer; local_infile_end: Pointer; local_infile_error: Pointer; local_infile_userdata: Pointer; end; PZMySQLConnect = Pointer; PZMySQLResult = Pointer; PZMySQLRow = Pointer; PZMySQLField = Pointer; PZMySQLRowOffset = Pointer; PZMySqlPrepStmt = Pointer; PZMysqlBindArray = Pointer; { Enum Field Types } TMysqlFieldTypes = ( FIELD_TYPE_DECIMAL = 0, FIELD_TYPE_TINY = 1, FIELD_TYPE_SHORT = 2, FIELD_TYPE_LONG = 3, FIELD_TYPE_FLOAT = 4, FIELD_TYPE_DOUBLE = 5, FIELD_TYPE_NULL = 6, FIELD_TYPE_TIMESTAMP = 7, FIELD_TYPE_LONGLONG = 8, FIELD_TYPE_INT24 = 9, FIELD_TYPE_DATE = 10, FIELD_TYPE_TIME = 11, FIELD_TYPE_DATETIME = 12, FIELD_TYPE_YEAR = 13, FIELD_TYPE_NEWDATE = 14, FIELD_TYPE_VARCHAR = 15, //<--ADDED by fduenas 20-06-2006 FIELD_TYPE_BIT = 16, //<--ADDED by fduenas 20-06-2006 FIELD_TYPE_NEWDECIMAL = 246, //<--ADDED by fduenas 20-06-2006 FIELD_TYPE_ENUM = 247, FIELD_TYPE_SET = 248, FIELD_TYPE_TINY_BLOB = 249, FIELD_TYPE_MEDIUM_BLOB = 250, FIELD_TYPE_LONG_BLOB = 251, FIELD_TYPE_BLOB = 252, FIELD_TYPE_VAR_STRING = 253, FIELD_TYPE_STRING = 254, FIELD_TYPE_GEOMETRY = 255 ); PTMysqlFieldTypes=^TMysqlFieldTypes; { Options for mysql_set_option } TMySqlSetOption = ( MYSQL_OPTION_MULTI_STATEMENTS_ON, MYSQL_OPTION_MULTI_STATEMENTS_OFF ); TMysqlStmtAttrType = ( STMT_ATTR_UPDATE_MAX_LENGTH, STMT_ATTR_CURSOR_TYPE, STMT_ATTR_PREFETCH_ROWS ); TMysqlShutdownLevel = ( SHUTDOWN_DEFAULT = 0, SHUTDOWN_WAIT_CONNECTIONS = MYSQL_SHUTDOWN_KILLABLE_CONNECT, SHUTDOWN_WAIT_TRANSACTIONS = MYSQL_SHUTDOWN_KILLABLE_TRANS, SHUTDOWN_WAIT_UPDATES = MYSQL_SHUTDOWN_KILLABLE_UPDATE, SHUTDOWN_WAIT_ALL_BUFFERS = (MYSQL_SHUTDOWN_KILLABLE_UPDATE shl 1), SHUTDOWN_WAIT_CRITICAL_BUFFERS, KILL_QUERY = 254, KILL_CONNECTION = 255 ); TMYSQL_CLIENT_OPTIONS = ( CLIENT_LONG_PASSWORD, { = 1; new more secure passwords } CLIENT_FOUND_ROWS , { = 2; Found instead of affected rows } CLIENT_LONG_FLAG , { = 4; Get all column flags } CLIENT_CONNECT_WITH_DB , { = 8; One can specify db on connect } CLIENT_NO_SCHEMA , { = 16; Don't allow database.table.column } CLIENT_COMPRESS , { = 32; Can use compression protcol } CLIENT_ODBC , { = 64; Odbc client } CLIENT_LOCAL_FILES , { = 128; Can use LOAD DATA LOCAL } CLIENT_IGNORE_SPACE , { = 256; Ignore spaces before '(' } CLIENT_CHANGE_USER , { = 512; Support the mysql_change_user() } CLIENT_INTERACTIVE , { = 1024; This is an interactive client } CLIENT_SSL , { = 2048; Switch to SSL after handshake } CLIENT_IGNORE_SIGPIPE , { = 4096; IGNORE sigpipes } CLIENT_TRANSACTIONS , { = 8196; Client knows about transactions } CLIENT_RESERVED , { = 16384; Old flag for 4.1 protocol } CLIENT_SECURE_CONNECTION , {= 32768; New 4.1 authentication } CLIENT_MULTI_STATEMENTS , {= 65536; Enable/disable multi-stmt support } CLIENT_MULTI_RESULTS , { = 131072; Enable/disable multi-results } CLIENT_PS_MULTI_RESULTS, {2^18 = 262144; Enable Multi-results in PS-protocol} CLIENT_PLUGIN_AUTH,{2^19 = 524288} CLIENT_OPT_20, {2^20 = 1048576} CLIENT_OPT_21, {2^21 = 2097152 } CLIENT_OPT_22, {2^22 = 4194304} CLIENT_OPT_23, {2^23 = 8388608 } CLIENT_OPT_24, {2^24 = 16777216 } CLIENT_OPT_25, {2^25 = 33554432} CLIENT_OPT_26, {2^26 = 67108864} CLIENT_OPT_27, {2^27 = 134217728} CLIENT_OPT_28, {2^28 = 268435456} CLIENT_OPT_29, {2^29 = 536870912} CLIENT_SSL_VERIFY_SERVER_CERT, {2^30 = 1073741824} CLIENT_REMEMBER_OPTIONS { = 2147483648; Enable/disable multi-results }); TMysqlStmtState = ( MYSQL_STMT_INIT_DONE = 1, MYSQL_STMT_PREPARE_DONE, MYSQL_STMT_EXECUTE_DONE, MYSQL_STMT_FETCH_DONE ); mysql_timestamp_type = ( MYSQL_TIMESTAMP_NONE = -2, MYSQL_TIMESTAMP_ERROR = -1, MYSQL_TIMESTAMP_DATE = 0, MYSQL_TIMESTAMP_DATETIME = 1, MYSQL_TIMESTAMP_TIME = 2 ); MYSQL_TIME = record year: UInt; month: UInt; day: UInt; hour: UInt; minute: UInt; second: UInt; second_part: ULong; neg: Byte; time_type: mysql_timestamp_type; padding: UInt; //ludob alignment is different? Mysql returns 36 bytes. end; PMYSQL_TIME = ^MYSQL_TIME; PLIST = ^LIST; LIST = record prev: PLIST; next: PLIST; data: Pointer; end; PMYSQL_FIELD = ^MYSQL_FIELD; MYSQL_FIELD = record name: PAnsiChar; // Name of column org_name: PAnsiChar; // Original column name, if an alias table: PAnsiChar; // Table of column if column was a field org_table: PAnsiChar; // Org table name if table was an alias db: PAnsiChar; // Database for table catalog: PAnsiChar; // Catalog for table def: PAnsiChar; // Default value (set by mysql_list_fields) length: ULong; // Width of column max_length: ULong; // Max width of selected set name_length: UInt; org_name_length: UInt; table_length: UInt; org_table_length: UInt; db_length: UInt; catalog_length: UInt; def_length: UInt; flags: UInt; // Div flags decimals: UInt; // Number of decimals in field charsetnr: UInt; // Character set _type: TMysqlFieldTypes; // Type of field. Se mysql_com.h for types end; PMYSQL_BIND41 = ^MYSQL_BIND41; MYSQL_BIND41 = record // 4.1.22 definition length: PULong; is_null: PByte; buffer: PAnsiChar; buffer_type: TMysqlFieldTypes; buffer_length: ULong; //internal fields inter_buffer: PByte; offset: ULong; internal_length: ULong; param_number: UInt; pack_length: UInt; is_unsigned: Byte; long_data_used: Byte; internal_is_null: Byte; store_param_func: Pointer; fetch_result: Pointer; skip_result: Pointer; end; PMYSQL_BIND50 = ^MYSQL_BIND50; MYSQL_BIND50 = record // 5.0.67 definition length: PULong; is_null: PByte; buffer: PAnsiChar; error: PByte; buffer_type: TMysqlFieldTypes; buffer_length: ULong; row_ptr: PByte; offset: ULong; length_value: ULong; param_number: UInt; pack_length: UInt; error_value: Byte; is_unsigned: Byte; long_data_used: Byte; is_null_value: Byte; store_param_funct: Pointer; fetch_result: Pointer; skip_result: Pointer; end; PMYSQL_BIND51 = ^MYSQL_BIND51; MYSQL_BIND51 = record // 5.1.30 definition (Still valid for 5.6.25) length: PULong; is_null: PByte; buffer: PAnsiChar; error: PByte; row_ptr: PByte; store_param_funct: Pointer; fetch_result: Pointer; skip_result: Pointer; buffer_length: ULong; offset: ULong; length_value: ULong; param_number: UInt; pack_length: UInt; buffer_type: TMysqlFieldTypes; error_value: Byte; is_unsigned: Byte; long_data_used: Byte; is_null_value: Byte; extension: Pointer; end; PMYSQL_BIND60 = ^MYSQL_BIND60; MYSQL_BIND60 = record // 6.0.8 definition length: PULong; is_null: PByte; buffer: PAnsiChar; error: PByte; row_ptr: PByte; store_param_funct: Pointer; fetch_result: Pointer; skip_result: Pointer; buffer_length: ULong; offset: ULong; length_value: ULong; param_number: UInt; pack_length: UInt; buffer_type: TMysqlFieldTypes; error_value: Byte; is_unsigned: Byte; long_data_used: Byte; is_null_value: Byte; extension: Pointer; end; // offsets to used MYSQL_BINDxx members. Filled by GetBindOffsets MYSQL_BINDOFFSETS=record buffer_type :NativeUint; buffer_length :NativeUint; is_unsigned :NativeUint; buffer :NativeUint; length :NativeUint; is_null :NativeUint; size :integer; //size of MYSQL_BINDxx end; PDOBindRecord2 = record buffer: Array of Byte; length: ULong; is_null: Byte; end; PMYSQL = ^MYSQL; MYSQL = pointer; PMY_CHARSET_INFO = ^MY_CHARSET_INFO; MY_CHARSET_INFO = record number: UInt; state: UInt; csname: PAnsiChar; name: PAnsiChar; comment: PAnsiChar; dir: PAnsiChar; mbminlen: UInt; mbmaxlen: UInt; end; // Structure of the MYSQL_RES record isn't used anymore. // Access to the fields should be done using library functions // Reason : the structure of these records tend to change now and then. PMYSQL_RES = Pointer; PREP_STMT_STATE=( MY_ST_UNKNOWN, MY_ST_PREPARE, MY_ST_EXECUTE); PMYSQL_STMT = Pointer; { ****************** Plain API Types definition ***************** } type { ************** Plain API Function types definition ************* } { Functions to get information from the MYSQL and MYSQL_RES structures Should definitely be used if one uses shared libraries. } Tmysql_affected_rows = function(Handle: PMYSQL): ULongLong; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_character_set_name = function(Handle: PMYSQL): PAnsiChar; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_close = procedure(Handle: PMYSQL); {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_connect = function(Handle: PMYSQL; const Host, User, Passwd: PAnsiChar): PMYSQL; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_create_db = function(Handle: PMYSQL; const Db: PAnsiChar): Integer; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_data_seek = procedure(Result: PMYSQL_RES; Offset: ULongLong); {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_debug = procedure(Debug: PAnsiChar); {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_drop_db = function(Handle: PMYSQL; const Db: PAnsiChar): Integer; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_dump_debug_info = function(Handle: PMYSQL): Integer; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_eof = function(Result: PMYSQL_RES): Byte; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_errno = function(Handle: PMYSQL): UInt; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_error = function(Handle: PMYSQL): PAnsiChar; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_escape_string = function(PTo, PFrom: PAnsiChar; Len: ULong): ULong; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_fetch_field = function(Result: PMYSQL_RES): PMYSQL_FIELD; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_fetch_field_direct = function(Result: PMYSQL_RES; FieldNo: UInt): PMYSQL_FIELD; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_fetch_fields = function(Result: PMYSQL_RES): PMYSQL_FIELD; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_fetch_lengths = function(Result: PMYSQL_RES): PULong; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_fetch_row = function(Result: PMYSQL_RES): PMYSQL_ROW; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_field_seek = function(Result: PMYSQL_RES; Offset: MYSQL_FIELD_OFFSET): MYSQL_FIELD_OFFSET; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_field_tell = function(Result: PMYSQL_RES): MYSQL_FIELD_OFFSET; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_free_result = procedure(Result: PMYSQL_RES); {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_get_client_info = function: PAnsiChar; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_get_host_info = function(Handle: PMYSQL): PAnsiChar; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_get_proto_info = function(Handle: PMYSQL): UInt; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_get_server_info = function(Handle: PMYSQL): PAnsiChar; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_info = function(Handle: PMYSQL): PAnsiChar; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_init = function(Handle: PMYSQL): PMYSQL; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_insert_id = function(Handle: PMYSQL): ULongLong; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_kill = function(Handle: PMYSQL; Pid: ULong): Integer; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_list_dbs = function(Handle: PMYSQL; Wild: PAnsiChar): PMYSQL_RES; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_list_fields = function(Handle: PMYSQL; const Table, Wild: PAnsiChar): PMYSQL_RES; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_list_processes = function(Handle: PMYSQL): PMYSQL_RES; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_list_tables = function(Handle: PMYSQL; const Wild: PAnsiChar): PMYSQL_RES; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_num_fields = function(Result: PMYSQL_RES): UInt; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_num_rows = function(Result: PMYSQL_RES): ULongLong; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_options = function(Handle: PMYSQL; Option: TMySqlOption; const Arg: PAnsiChar): Integer; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_ping = function(Handle: PMYSQL): Integer; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_query = function(Handle: PMYSQL; const Query: PAnsiChar): Integer; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_real_connect = function(Handle: PMYSQL; const Host, User, Passwd, Db: PAnsiChar; Port: UInt; const UnixSocket: PAnsiChar; ClientFlag: ULong): PMYSQL; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_real_escape_string = function(Handle: PMYSQL; PTo: PAnsiChar; const PFrom: PAnsiChar; length: ULong): ULong; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_real_query = function(Handle: PMYSQL; const Query: PAnsiChar; Length: ULong): Integer; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_refresh = function(Handle: PMYSQL; Options: UInt): Integer; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_row_seek = function(Result: PMYSQL_RES; Offset: PMYSQL_ROWS): PMYSQL_ROWS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_row_tell = function(Result: PMYSQL_RES): PMYSQL_ROWS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_select_db = function(Handle: PMYSQL; const Db: PAnsiChar): Integer; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_ssl_set = function(Handle: PMYSQL; const key, cert, CA, CApath, cipher: PAnsiChar): Byte; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_stat = function(Handle: PMYSQL): PAnsiChar; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_store_result = function(Handle: PMYSQL): PMYSQL_RES; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_thread_id = function(Handle: PMYSQL): ULong; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_use_result = function(Handle: PMYSQL): PMYSQL_RES; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; { Set up and bring down a thread; these function should be called for each thread in an application which opens at least one MySQL connection. All uses of the connection(s) should be between these function calls. } Tmy_init = procedure; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_thread_init = function: Byte; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_thread_end = procedure; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_thread_safe = function: UInt; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; { Set up and bring down the server; to ensure that applications will work when linked against either the standard client library or the embedded server library, these functions should be called. } Tmysql_server_init = function(Argc: Integer; Argv, Groups: Pointer): Integer; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_server_end = procedure; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_change_user = function(mysql: PMYSQL; const user: PAnsiChar; const passwd: PAnsiChar; const db: PAnsiChar): Byte; Tmysql_field_count = function(Handle: PMYSQL): UInt; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_get_client_version = function: ULong; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_send_query = function(mysql: PMYSQL; const query: PAnsiChar; length: ULong): Integer; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_read_query_result = function(mysql: PMYSQL): Byte; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_autocommit = function(Handle: PMYSQL; const mode: Byte): Byte; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_commit = function(Handle: PMYSQL): Byte; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_get_server_version = function(Handle: PMYSQL): ULong; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_hex_string = function(PTo, PFrom: PAnsiChar; Len: ULong): ULong; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_more_results = function(Handle: PMYSQL): Byte; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_next_result = function(Handle: PMYSQL): Integer; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_rollback = function(Handle: PMYSQL): Byte; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_set_character_set = function(Handle: PMYSQL; const csname: PAnsiChar): Integer; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_set_server_option = function(Handle: PMYSQL; Option: TMysqlSetOption): Integer; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_shutdown = function(Handle: PMYSQL; shutdown_level: TMysqlShutdownLevel): Integer; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_sqlstate = function(Handle: PMYSQL): PAnsiChar; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_warning_count = function(Handle: PMYSQL): UInt; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; {BELOW are new PREPARED STATEMENTS} Tmysql_stmt_affected_rows = function(stmt: PMYSQL_STMT): ULongLong; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_stmt_attr_get = function(stmt: PMYSQL_STMT; option: TMysqlStmtAttrType; arg: PAnsiChar): Byte; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_stmt_attr_set = function(stmt: PMYSQL_STMT; option: TMysqlStmtAttrType; const arg: PAnsiChar): Byte; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_stmt_bind_param = function(stmt: PMYSQL_STMT; bind: Pointer{BIND record}): Byte; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_stmt_bind_result = function(stmt: PMYSQL_STMT; bind: Pointer{BIND record}): Byte; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_stmt_close = function(stmt: PMYSQL_STMT): Byte; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_stmt_data_seek = procedure(stmt: PMYSQL_STMT; offset: ULongLong); {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_stmt_errno = function(stmt: PMYSQL_STMT): UInt; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_stmt_error = function(stmt: PMYSQL_STMT): PAnsiChar; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_stmt_execute = function(stmt: PMYSQL_STMT): Integer; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_stmt_fetch = function(stmt: PMYSQL_STMT): Integer; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_stmt_fetch_column = function(stmt: PMYSQL_STMT; bind: Pointer{BIND record}; column: UInt; offset: ULong): Integer; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_stmt_field_count = function(stmt: PMYSQL_STMT): UInt; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_stmt_free_result = function(stmt: PMYSQL_STMT): Byte; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_stmt_init = function(Handle: PMYSQL): PMYSQL_STMT; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_stmt_insert_id = function(stmt: PMYSQL_STMT): ULongLong; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_stmt_next_result = function(stmt: PMYSQL_STMT): Integer; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_stmt_num_rows = function(stmt: PMYSQL_STMT): ULongLong; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_stmt_param_count = function(stmt: PMYSQL_STMT): ULong; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_stmt_param_metadata = function(stmt: PMYSQL_STMT): PMYSQL_RES; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_stmt_prepare = function(stmt: PMYSQL_STMT; const query: PAnsiChar; length: ULong): Integer; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_stmt_reset = function(stmt: PMYSQL_STMT): Byte; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_stmt_result_metadata = function(stmt: PMYSQL_STMT): PMYSQL_RES; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_stmt_row_seek = function(stmt: PMYSQL_STMT; offset: PMYSQL_ROWS): PMYSQL_ROWS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_stmt_row_tell = function(stmt: PMYSQL_STMT): PMYSQL_ROWS; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_stmt_send_long_data = function(stmt: PMYSQL_STMT; parameter_number: UInt; const data: PAnsiChar; length: ULong): Byte; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_stmt_sqlstate = function(stmt: PMYSQL_STMT): PAnsiChar; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_stmt_store_result = function(stmt: PMYSQL_STMT): Integer; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_get_character_set_info = procedure(Handle: PMYSQL; cs: PMY_CHARSET_INFO); {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; Tmysql_library_end = procedure; {$IFDEF MSWINDOWS} stdcall {$ELSE} cdecl {$ENDIF}; { ************** Collection of Plain API Function types definition ************* } TZMYSQL_API = record mysql_affected_rows: Tmysql_affected_rows; {mysql 3.2} mysql_character_set_name: Tmysql_character_set_name; {mysql 3.2} mysql_close: Tmysql_close; {mysql 3.2} mysql_connect: Tmysql_connect; {mysql 3.2} {deprecated for mysql_real_connect} mysql_create_db: Tmysql_create_db; {mysql 3.2} {deprecated for mysql_query} mysql_data_seek: Tmysql_data_seek; {mysql 3.2} mysql_debug: Tmysql_debug; {mysql 3.2} mysql_drop_db: Tmysql_drop_db; {mysql 3.2} {deprecated for mysql_query} mysql_dump_debug_info: Tmysql_dump_debug_info; {mysql 3.2} mysql_eof: Tmysql_eof; {mysql 3.2} {deprecated for mysql_error/mysql_errno} mysql_errno: Tmysql_errno; {mysql 3.2} mysql_error: Tmysql_error; {mysql 3.2} mysql_escape_string: Tmysql_escape_string; {mysql 3.2} {deprecated for mysql_real_escape_string} mysql_fetch_field: Tmysql_fetch_field; {mysql 3.2} mysql_fetch_field_direct: Tmysql_fetch_field_direct; {mysql 3.2} mysql_fetch_fields: Tmysql_fetch_fields; {mysql 3.2} mysql_fetch_lengths: Tmysql_fetch_lengths; {mysql 3.2} mysql_fetch_row: Tmysql_fetch_row; {mysql 3.2} mysql_field_seek: Tmysql_field_seek; {mysql 3.2} mysql_field_tell: Tmysql_field_tell; {mysql 3.2} mysql_free_result: Tmysql_free_result; {mysql 3.2} mysql_get_client_info: Tmysql_get_client_info; {mysql 3.2} mysql_get_host_info: Tmysql_get_host_info; {mysql 3.2} mysql_get_proto_info: Tmysql_get_proto_info; {mysql 3.2} mysql_get_server_info: Tmysql_get_server_info; {mysql 3.2} mysql_info: Tmysql_info; {mysql 3.2} mysql_init: Tmysql_init; {mysql 3.2} mysql_insert_id: Tmysql_insert_id; {mysql 3.2} mysql_kill: Tmysql_kill; {mysql 3.2} mysql_list_dbs: Tmysql_list_dbs; {mysql 3.2} mysql_list_fields: Tmysql_list_fields; {mysql 3.2} mysql_list_processes: Tmysql_list_processes; {mysql 3.2} mysql_list_tables: Tmysql_list_tables; {mysql 3.2} mysql_num_fields: Tmysql_num_fields; {mysql 3.2} mysql_num_rows: Tmysql_num_rows; {mysql 3.2} mysql_options: Tmysql_options; {mysql 3.2} mysql_ping: Tmysql_ping; {mysql 3.2} mysql_query: Tmysql_query; {mysql 3.2} {deprecated for mysql_real_query} mysql_real_connect: Tmysql_real_connect; {mysql 3.2} mysql_real_escape_string: Tmysql_real_escape_string; {mysql 3.2} mysql_real_query: Tmysql_real_query; {mysql 3.2} mysql_refresh: Tmysql_refresh; {mysql 3.2} mysql_row_seek: Tmysql_row_seek; {mysql 3.2} mysql_row_tell: Tmysql_row_tell; {mysql 3.2} mysql_select_db: Tmysql_select_db; {mysql 3.2} mysql_shutdown: Tmysql_shutdown; {mysql 3.2} {new argument 4.1} mysql_ssl_set: Tmysql_ssl_set; {mysql 3.2} mysql_stat: Tmysql_stat; {mysql 3.2} mysql_store_result: Tmysql_store_result; {mysql 3.2} mysql_thread_id: Tmysql_thread_id; {mysql 3.2} mysql_use_result: Tmysql_use_result; {mysql 3.2} {API for THREADED FUNCTIONS } my_init: Tmy_init; {mysql 3.2} mysql_thread_init: Tmysql_thread_init; {mysql 3.2} mysql_thread_end: Tmysql_thread_end; {mysql 3.2} mysql_thread_safe: tmysql_thread_safe; {mysql 3.2} {API for EMBEDDED SERVER } mysql_server_init: Tmysql_server_init; {mysql 3.2} mysql_server_end: Tmysql_server_end; {mysql 3.2} mysql_change_user: Tmysql_change_user; {mysql 3.23} mysql_field_count: Tmysql_field_count; {mysql 3.22} mysql_get_client_version: Tmysql_get_client_version; {mysql 4.0} mysql_send_query: Tmysql_send_query; mysql_read_query_result: Tmysql_read_query_result; mysql_autocommit: Tmysql_autocommit; {mysql 4.1} mysql_commit: Tmysql_commit; {mysql 4.1} mysql_get_server_version: Tmysql_get_server_version; {mysql 4.1} mysql_hex_string: Tmysql_hex_string; {mysql 4.1.8} mysql_more_results: Tmysql_more_results; {mysql 4.1} mysql_next_result: Tmysql_next_result; {mysql 4.1} mysql_rollback: Tmysql_rollback; {mysql 4.1} mysql_set_character_set: Tmysql_set_character_set; {mysql 4.1.13} mysql_set_server_option: Tmysql_set_server_option; {mysql 4.1} mysql_sqlstate: Tmysql_sqlstate; {mysql 4.1} mysql_warning_count: Tmysql_warning_count; {mysql 4.1} {API for PREPARED STATEMENTS} mysql_stmt_affected_rows: Tmysql_stmt_affected_rows; {mysql 4.1.0} mysql_stmt_attr_get: Tmysql_stmt_attr_get; {mysql 4.1.2} mysql_stmt_attr_set: Tmysql_stmt_attr_set; {mysql 4.1.2} {augmented 5.0.2/6} mysql_stmt_bind_param: Tmysql_stmt_bind_param; {mysql 4.1.2} mysql_stmt_bind_result: Tmysql_stmt_bind_result; {mysql 4.1.2} mysql_stmt_close: Tmysql_stmt_close; {mysql 4.1.0} mysql_stmt_data_seek: Tmysql_stmt_data_seek; {mysql 4.1.1} mysql_stmt_errno: Tmysql_stmt_errno; {mysql 4.1.0} mysql_stmt_error: Tmysql_stmt_error; {mysql 4.1.0} mysql_stmt_execute: Tmysql_stmt_execute; {mysql 4.1.2} mysql_stmt_fetch: Tmysql_stmt_fetch; {mysql 4.1.2} mysql_stmt_fetch_column: Tmysql_stmt_fetch_column; {mysql 4.1.2} mysql_stmt_field_count: Tmysql_stmt_field_count; {mysql 4.1.3} mysql_stmt_free_result: Tmysql_stmt_free_result; {mysql 4.1.1} mysql_stmt_init: Tmysql_stmt_init; {mysql 4.1.2} mysql_stmt_insert_id: Tmysql_stmt_insert_id; {mysql 4.1.2} mysql_stmt_next_result: Tmysql_stmt_next_result; {mysql 5.5.3} mysql_stmt_num_rows: Tmysql_stmt_num_rows; {mysql 4.1.1} mysql_stmt_param_count: Tmysql_stmt_param_count; {mysql 4.1.2} mysql_stmt_param_metadata: Tmysql_stmt_param_metadata; {mysql 4.1.2} mysql_stmt_prepare: Tmysql_stmt_prepare; {mysql 4.1.2} mysql_stmt_reset: Tmysql_stmt_reset; {mysql 4.1.1} mysql_stmt_result_metadata: Tmysql_stmt_result_metadata; {mysql 4.1.2} mysql_stmt_row_seek: Tmysql_stmt_row_seek; {mysql 4.1.1} mysql_stmt_row_tell: Tmysql_stmt_row_tell; {mysql 4.1.1} mysql_stmt_send_long_data: Tmysql_stmt_send_long_data; {mysql 4.1.2} mysql_stmt_sqlstate: Tmysql_stmt_sqlstate; {mysql 4.1.1} mysql_stmt_store_result: Tmysql_stmt_store_result; {mysql 4.1.0} mysql_get_character_set_info: Tmysql_get_character_set_info; {mysql 5.0.10} end; const EMBEDDED_DEFAULT_DATA_DIR = {$IFDEF WIN32} '.\data\' {$ELSE} './data/' {$ENDIF}; SERVER_ARGUMENTS_KEY_PREFIX = 'ServerArgument'; SERVER_GROUPS : array [0..2] of PAnsiChar = ('embedded'#0, 'server'#0, nil); DEFAULT_PARAMS : array [0..2] of PAnsiChar = ('not_used'#0, '--datadir='+EMBEDDED_DEFAULT_DATA_DIR+#0, '--set-variable=key_buffer_size=32M'#0); const MaxBlobSize = 1000000; implementation end. ================================================ FILE: lib/zeosdbo/src/plain/ZPlainMySqlDriver.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Native Plain Drivers for MySQL } { } { Originally written by Sergey Seroukhov } { } { Thanks to : } { Pascal Data Objects Library } { } { Copyright (c) 2006 John Marino, www.synsport.com } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZPlainMySqlDriver; interface {$I ZPlain.inc} uses Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} ZPlainDriver, ZCompatibility, ZPlainMySqlConstants, ZTokenizer; const MARIADB_LOCATION = 'libmariadb'+ SharedSuffix; {$IFNDEF UNIX} {$IFNDEF MYSQL_STRICT_DLL_LOADING} WINDOWS_DLL_LOCATION = 'libmysql.dll'; WINDOWS_DLL_LOCATION_EMBEDDED = 'libmysqld.dll'; {$ENDIF} WINDOWS_DLL41_LOCATION = 'libmysql41.dll'; WINDOWS_DLL41_LOCATION_EMBEDDED = 'libmysqld41.dll'; WINDOWS_DLL50_LOCATION = 'libmysql50.dll'; WINDOWS_DLL50_LOCATION_EMBEDDED = 'libmysqld50.dll'; WINDOWS_DLL51_LOCATION = 'libmysql51.dll'; WINDOWS_DLL51_LOCATION_EMBEDDED = 'libmysqld51.dll'; WINDOWS_DLL55_LOCATION = 'libmysql55.dll'; WINDOWS_DLL55_LOCATION_EMBEDDED = 'libmysqld55.dll'; {$ELSE} {$IFNDEF MYSQL_STRICT_DLL_LOADING} LINUX_DLL_LOCATION = 'libmysqlclient'+SharedSuffix; LINUX_DLL_LOCATION_EMBEDDED = 'libmysqld'+SharedSuffix; {$ENDIF} LINUX_DLL41_LOCATION = 'libmysqlclient'+SharedSuffix+'.14'; LINUX_DLL41_LOCATION_EMBEDDED = 'libmysqld'+SharedSuffix+'.14'; LINUX_DLL50_LOCATION = 'libmysqlclient'+SharedSuffix+'.15'; LINUX_DLL50_LOCATION_EMBEDDED = 'libmysqld'+SharedSuffix+'.15'; LINUX_DLL51_LOCATION = 'libmysqlclient'+SharedSuffix+'.16'; LINUX_DLL51_LOCATION_EMBEDDED = 'libmysqld'+SharedSuffix+'.16'; LINUX_DLL55_LOCATION = 'libmysqlclient'+SharedSuffix+'.18'; LINUX_DLL55_LOCATION_EMBEDDED = 'libmysqld'+SharedSuffix+'.18'; {$ENDIF} type {** Represents a generic interface to MySQL native API. } IZMySQLPlainDriver = interface (IZPlainDriver) ['{D1CB3F6C-72A1-4125-873F-791202ACC5F0}'] {ADDED by fduenas 15-06-2006} function GetClientVersion: Integer; function GetServerVersion(Handle: PZMySQLConnect): Integer; {END ADDED by fduenas 15-06-2006} procedure Despose(var Handle: PZMySQLConnect); function GetAffectedRows(Handle: PZMySQLConnect): Int64; {ADDED by EgonHugeist} function GetConnectionCharacterSet(Handle: PMYSQL): PAnsiChar;// char_set_name procedure Close(Handle: PZMySQLConnect); function Connect(Handle: PZMySQLConnect; const Host, User, Password: PAnsiChar): PZMySQLConnect; function CreateDatabase(Handle: PZMySQLConnect; const Database: PAnsiChar): Integer; procedure SeekData(Res: PZMySQLResult; Offset: Cardinal); procedure Debug(Debug: PAnsiChar); function DropDatabase(Handle: PZMySQLConnect; const Database: PAnsiChar): Integer; function DumpDebugInfo(Handle: PZMySQLConnect): Integer; // eof function GetLastErrorCode(Handle: PZMySQLConnect): Integer; function GetLastError(Handle: PZMySQLConnect): PAnsiChar; function FetchField(Res: PZMySQLResult): PZMySQLField; // fetch_field_direct // fetch_fields function FetchLengths(Res: PZMySQLResult): PULong; function FetchRow(Res: PZMySQLResult): PZMySQLRow; function SeekField(Res: PZMySQLResult; Offset: Cardinal): Cardinal; // field_tell procedure FreeResult(Res: PZMySQLResult); function GetClientInfo: PAnsiChar; function GetHostInfo(Handle: PZMySQLConnect): PAnsiChar; function GetProtoInfo(Handle: PZMySQLConnect): Cardinal; function GetServerInfo(Handle: PZMySQLConnect): PAnsiChar; // info function Init(const Handle: PZMySQLConnect): PZMySQLConnect; function GetLastInsertID (Handle: PZMySQLConnect): Int64; function Kill(Handle: PZMySQLConnect; Pid: LongInt): Integer; function GetBindOffsets: MYSQL_BINDOFFSETS; function GetListDatabases(Handle: PZMySQLConnect; Wild: PAnsiChar): PZMySQLResult; function GetListFields(Handle: PZMySQLConnect; const Table, Wild: PAnsiChar): PZMySQLResult; function GetListProcesses(Handle: PZMySQLConnect): PZMySQLResult; function GetListTables(Handle: PZMySQLConnect; const Wild: PAnsiChar): PZMySQLResult; // num_fields function GetNumRows(Res: PZMySQLResult): Int64; function SetOptions(Handle: PZMySQLConnect; Option: TMySQLOption; const Arg: Pointer): Integer; function Ping(Handle: PZMySQLConnect): Integer; function ExecQuery(Handle: PZMySQLConnect; const Query: PAnsiChar): Integer; overload; function RealConnect(Handle: PZMySQLConnect; const Host, User, Password, Db: PAnsiChar; Port: Cardinal; UnixSocket: PAnsiChar; ClientFlag: Cardinal): PZMySQLConnect; function ExecRealQuery(Handle: PZMySQLConnect; const Query: PAnsiChar; Length: Integer): Integer; function Refresh(Handle: PZMySQLConnect; Options: Cardinal): Integer; function SeekRow(Res: PZMySQLResult; Row: PZMySQLRowOffset): PZMySQLRowOffset; // row_tell function SelectDatabase(Handle: PZMySQLConnect; const Database: PAnsiChar): Integer; function SslSet(Handle: PZMySQLConnect; const Key, Cert, Ca, Capath, Cipher: PAnsiChar): Integer; function GetStatInfo(Handle: PZMySQLConnect): PAnsiChar; function StoreResult(Handle: PZMySQLConnect): PZMySQLResult; function GetThreadId(Handle: PZMySQLConnect): Cardinal; function UseResult(Handle: PZMySQLConnect): PZMySQLResult; // thread_init // thread_end // thread_safe // server_init // server_end // change_user // field_count // function GetClientVersion: AnsiString; function Shutdown(Handle: PZMySQLConnect; shutdown_level: TMysqlShutdownLevel = ZPlainMySqlConstants.SHUTDOWN_DEFAULT): Integer; // 2 versions!! function SetAutocommit (Handle: PZMySQLConnect; mode: Boolean): Boolean; function Commit (Handle: PZMySQLConnect): Boolean; //function GetServerVersion (Handle: PZMySQLConnect): AnsiString; // hex_string function CheckAnotherRowset (Handle: PZMySQLConnect): Boolean; function RetrieveNextRowset (Handle: PZMySQLConnect): Integer; function Rollback (Handle: PZMySQLConnect): Boolean; {ADDED by EgonHugeist} function SetConnectionCharacterSet(Handle: PMYSQL; const csname: PAnsiChar): Integer; // set_character_set returns 0 if valid // set_server_option function GetSQLState (Handle: PZMySQLConnect): AnsiString; // warning_count function GetPreparedAffectedRows (Handle: PZMySqlPrepStmt): Int64; // stmt_attr_get function StmtAttrSet(stmt: PZMySqlPrepStmt; option: TMysqlStmtAttrType; arg: PAnsiChar): Byte; function BindParameters (Handle: PZMySqlPrepStmt; bindArray: PZMysqlBindArray): Byte; function BindResult (Handle: PZMySqlPrepStmt; bindArray: PZMysqlBindArray): Byte; function ClosePrepStmt (PrepStmtHandle: PZMySqlPrepStmt): PZMySqlPrepStmt; procedure SeekPreparedData(PrepStmtHandle: PZMySqlPrepStmt; Offset: Cardinal); function GetLastPreparedErrorCode(Handle: PZMySqlPrepStmt): Integer; function GetLastPreparedError(Handle: PZMySqlPrepStmt): AnsiString; function ExecuteStmt (Handle: PZMySqlPrepStmt): Integer; function FetchBoundResults (Handle: PZMySqlPrepStmt): Integer; // stmt_fetch_column function GetPreparedFieldCount(Handle: PZMySqlPrepStmt): Integer; function FreePreparedResult (Handle: PZMySqlPrepStmt): Byte; function InitializePrepStmt (Handle: PZMySQLConnect): PZMySqlPrepStmt; function GetPreparedInsertID (Handle: PZMySqlPrepStmt): Int64; function GetPreparedNextResult (Handle: PZMySqlPrepStmt): Integer; function GetPreparedNumRows (Handle: PZMySqlPrepStmt): Int64; function GetPreparedBindMarkers (Handle: PZMySqlPrepStmt): Cardinal; // param_count function GetStmtParamMetadata(PrepStmtHandle: PZMySqlPrepStmt): PZMySQLResult; // stmt_param_metadata function PrepareStmt(PrepStmtHandle: PZMySqlPrepStmt; const Query: PAnsiChar; Length: Integer): Integer; // stmt_reset function GetPreparedMetaData (Handle: PZMySqlPrepStmt): PZMySQLResult; function SeekPreparedRow(Handle: PZMySqlPrepStmt; Row: PZMySQLRowOffset): PZMySQLRowOffset; // stmt_row_tell function SendPreparedLongData(Handle: PZMySqlPrepStmt; parameter_number: Cardinal; const data: PAnsiChar; length: Cardinal): Byte; function GetPreparedSQLState (Handle: PZMySqlPrepStmt): PAnsiChar; function StorePreparedResult (Handle: PZMySqlPrepStmt): Integer; procedure GetCharacterSetInfo(Handle: PZMySQLConnect; CharSetInfo: PMY_CHARSET_INFO);// get_character_set_info since 5.0.10 {non API functions} function GetFieldType(Field: PZMySQLField): TMysqlFieldTypes; function GetFieldFlags(Field: PZMySQLField): Integer; function ResultSetExists(Handle: PZMySQLConnect):Boolean; function GetRowCount(Res: PZMySQLResult): Int64; function GetFieldCount(Res: PZMySQLResult): Integer; function GetFieldName(Field: PZMySQLField): PAnsiChar; function GetFieldTable(Field: PZMySQLField): PAnsiChar; function GetFieldOrigTable(Field: PZMySQLField): PAnsiChar; function GetFieldOrigName(Field: PZMySQLField): PAnsiChar; function GetFieldLength(Field: PZMySQLField): ULong; function GetFieldMaxLength(Field: PZMySQLField): Integer; function GetFieldDecimals(Field: PZMySQLField): Integer; function GetFieldCharsetNr(Field: PZMySQLField): UInt; function GetFieldData(Row: PZMySQLRow; Offset: Cardinal): PAnsiChar; procedure SetDriverOptions(Options: TStrings); // changed by tohenk, 2009-10-11 end; {** Implements a base driver for MySQL} { TZMySQLBaseDriver } TZMySQLBaseDriver = class (TZAbstractPlainDriver, IZPlainDriver, IZMySQLPlainDriver) protected MYSQL_API : TZMYSQL_API; ServerArgs: array of PAnsiChar; ServerArgsLen: Integer; IsEmbeddedDriver: Boolean; function GetUnicodeCodePageName: String; override; procedure LoadCodePages; override; procedure LoadApi; override; procedure BuildServerArguments(Options: TStrings); public constructor Create(Tokenizer: IZTokenizer); destructor Destroy; override; procedure Debug(Debug: PAnsiChar); function DumpDebugInfo(Handle: PZMySQLConnect): Integer; function GetLastError(Handle: PZMySQLConnect): PAnsiChar; function GetLastErrorCode(Handle: PZMySQLConnect): Integer; function Init(const Handle: PZMySQLConnect): PZMySQLConnect; virtual; function GetLastInsertID (Handle: PZMySQLConnect): Int64; procedure Despose(var Handle: PZMySQLConnect); function Connect(Handle: PZMySQLConnect; const Host, User, Password: PAnsiChar): PZMySQLConnect; function RealConnect(Handle: PZMySQLConnect; const Host, User, Password, Db: PAnsiChar; Port: Cardinal; UnixSocket: PAnsiChar; ClientFlag: Cardinal): PZMySQLConnect; procedure Close(Handle: PZMySQLConnect); function ExecQuery(Handle: PZMySQLConnect; const Query: PAnsiChar): Integer; overload; function ExecRealQuery(Handle: PZMySQLConnect; const Query: PAnsiChar; Length: Integer): Integer; function SelectDatabase(Handle: PZMySQLConnect; const Database: PAnsiChar): Integer; function SslSet(Handle: PZMySQLConnect; const Key, Cert, Ca, Capath, Cipher: PAnsiChar): Integer; function CreateDatabase(Handle: PZMySQLConnect; const Database: PAnsiChar): Integer; function DropDatabase(Handle: PZMySQLConnect; const Database: PAnsiChar): Integer; function Shutdown(Handle: PZMySQLConnect; shutdown_level: TMysqlShutdownLevel = ZPlainMySqlConstants.SHUTDOWN_DEFAULT): Integer; // 2 versions!! function SetAutocommit (Handle: PZMySQLConnect; mode: Boolean): Boolean; function Commit (Handle: PZMySQLConnect): Boolean; function CheckAnotherRowset (Handle: PZMySQLConnect): Boolean; function RetrieveNextRowset (Handle: PZMySQLConnect): Integer; function Rollback (Handle: PZMySQLConnect): Boolean; function GetSQLState (Handle: PZMySQLConnect): AnsiString; function StmtAttrSet(stmt: PZMySqlPrepStmt; option: TMysqlStmtAttrType; arg: PAnsiChar): Byte; function GetPreparedAffectedRows (Handle: PZMySqlPrepStmt): Int64; function BindParameters (Handle: PZMySqlPrepStmt; bindArray: PZMysqlBindArray): Byte; function BindResult (Handle: PZMySqlPrepStmt; bindArray: PZMysqlBindArray): Byte; function ClosePrepStmt (PrepStmtHandle: PZMySqlPrepStmt): PZMySqlPrepStmt; procedure SeekPreparedData(PrepStmtHandle: PZMySqlPrepStmt; Offset: Cardinal); function GetLastPreparedErrorCode(Handle: PZMySqlPrepStmt): Integer; function GetLastPreparedError(Handle: PZMySqlPrepStmt): AnsiString; function ExecuteStmt (Handle: PZMySqlPrepStmt): Integer; function FetchBoundResults (Handle: PZMySqlPrepStmt): Integer; function GetPreparedFieldCount(Handle: PZMySqlPrepStmt): Integer; function FreePreparedResult (Handle: PZMySqlPrepStmt): Byte; function InitializePrepStmt (Handle: PZMySQLConnect): PZMySqlPrepStmt; function GetPreparedInsertID (Handle: PZMySqlPrepStmt): Int64; function GetPreparedNextResult (Handle: PZMySqlPrepStmt): Integer; function GetPreparedNumRows (Handle: PZMySqlPrepStmt): Int64; function GetPreparedBindMarkers (Handle: PZMySqlPrepStmt): Cardinal; // param_count function GetStmtParamMetadata(PrepStmtHandle: PZMySqlPrepStmt): PZMySQLResult; function PrepareStmt (PrepStmtHandle: PZMySqlPrepStmt; const Query: PAnsiChar; Length: Integer): Integer; function GetPreparedMetaData (Handle: PZMySqlPrepStmt): PZMySQLResult; function SeekPreparedRow(Handle: PZMySqlPrepStmt; Row: PZMySQLRowOffset): PZMySQLRowOffset; function SendPreparedLongData(Handle: PZMySqlPrepStmt; parameter_number: Cardinal; const data: PAnsiChar; length: Cardinal): Byte; function GetPreparedSQLState (Handle: PZMySqlPrepStmt): PAnsiChar; function StorePreparedResult (Handle: PZMySqlPrepStmt): Integer; procedure GetCharacterSetInfo(Handle: PZMySQLConnect; CharSetInfo: PMY_CHARSET_INFO); function GetBindOffsets: MYSQL_BINDOFFSETS; function Refresh(Handle: PZMySQLConnect; Options: Cardinal): Integer; function Kill(Handle: PZMySQLConnect; Pid: LongInt): Integer; function Ping(Handle: PZMySQLConnect): Integer; function GetStatInfo(Handle: PZMySQLConnect): PAnsiChar; function SetOptions(Handle: PZMySQLConnect; Option: TMySQLOption; const Arg: Pointer): Integer; function EscapeString(Handle: Pointer; const Value: RawByteString; ConSettings: PZConSettings; WasEncoded: Boolean = False): RawByteString; override; function GetServerInfo(Handle: PZMySQLConnect): PAnsiChar; function GetClientInfo: PAnsiChar; function GetHostInfo(Handle: PZMySQLConnect): PAnsiChar; function GetProtoInfo(Handle: PZMySQLConnect): Cardinal; function GetThreadId(Handle: PZMySQLConnect): Cardinal; {ADDED by fduenas 15-06-2006} function GetClientVersion: Integer; function GetServerVersion(Handle: PZMySQLConnect): Integer; {END ADDED by fduenas 15-06-2006} function GetListDatabases(Handle: PZMySQLConnect; Wild: PAnsiChar): PZMySQLResult; function GetListTables(Handle: PZMySQLConnect; const Wild: PAnsiChar): PZMySQLResult; function GetNumRows(Res: PZMySQLResult): Int64; function GetListFields(Handle: PZMySQLConnect; const Table, Wild: PAnsiChar): PZMySQLResult; function GetListProcesses(Handle: PZMySQLConnect): PZMySQLResult; function StoreResult(Handle: PZMySQLConnect): PZMySQLResult; function UseResult(Handle: PZMySQLConnect): PZMySQLResult; procedure FreeResult(Res: PZMySQLResult); function GetAffectedRows(Handle: PZMySQLConnect): Int64; {ADDED by EgonHugeist} function GetConnectionCharacterSet(Handle: PMYSQL): PAnsiChar;// char_set_name function SetConnectionCharacterSet(Handle: PMYSQL; const csname: PAnsiChar): Integer; // set_character_set Returns 0 if valid function FetchRow(Res: PZMySQLResult): PZMySQLRow; function FetchLengths(Res: PZMySQLResult): PULong; function FetchField(Res: PZMySQLResult): PZMySQLField; procedure SeekData(Res: PZMySQLResult; Offset: Cardinal); function SeekRow(Res: PZMySQLResult; Row: PZMySQLRowOffset): PZMySQLRowOffset; function SeekField(Res: PZMySQLResult; Offset: Cardinal): Cardinal; function GetFieldType(Field: PZMySQLField): TMysqlFieldTypes; function GetFieldFlags(Field: PZMySQLField): Integer; function ResultSetExists(Handle: PZMySQLConnect):Boolean; function GetRowCount(Res: PZMySQLResult): Int64; function GetFieldCount(Res: PZMySQLResult): Integer; function GetFieldName(Field: PZMySQLField): PAnsiChar; function GetFieldTable(Field: PZMySQLField): PAnsiChar; function GetFieldOrigTable(Field: PZMySQLField): PAnsiChar; function GetFieldOrigName(Field: PZMySQLField): PAnsiChar; function GetFieldLength(Field: PZMySQLField): ULong; function GetFieldMaxLength(Field: PZMySQLField): Integer; function GetFieldDecimals(Field: PZMySQLField): Integer; function GetFieldCharsetNr(Field: PZMySQLField): UInt; function GetFieldData(Row: PZMySQLRow; Offset: Cardinal): PAnsiChar; procedure SetDriverOptions(Options: TStrings); virtual; // changed by tohenk, 2009-10-11 end; {** Implements a driver for MySQL 4.1 } { TZNewMySQL41PlainDriver } TZMySQL41PlainDriver = class (TZMysqlBaseDriver) protected function Clone: IZPlainDriver; override; public constructor Create(Tokenizer: IZTokenizer); function GetProtocol: string; override; function GetDescription: string; override; end; {** Implements a driver for MySQL 4.1 } { TZNewMySQLD41PlainDriver } TZMySQLD41PlainDriver = class (TZMySQL41PlainDriver) protected function Clone: IZPlainDriver; override; public constructor Create(Tokenizer: IZTokenizer); function GetProtocol: string; override; function GetDescription: string; override; end; { TZNewMySQL5PlainDriver } TZMySQL5PlainDriver = class (TZMysqlBaseDriver) protected function Clone: IZPlainDriver; override; protected procedure LoadApi; override; procedure LoadCodePages; override; public constructor Create(Tokenizer: IZTokenizer); function GetProtocol: string; override; function GetDescription: string; override; end; { TZNewMySQLD5PlainDriver } TZMySQLD5PlainDriver = class (TZMySQL5PlainDriver) protected function Clone: IZPlainDriver; override; public constructor Create(Tokenizer: IZTokenizer); function GetProtocol: string; override; function GetDescription: string; override; end; { TZMariaDB5PlainDriver } TZMariaDB5PlainDriver = class (TZMySQL5PlainDriver) protected function Clone: IZPlainDriver; override; public constructor Create(Tokenizer: IZTokenizer); function GetProtocol: string; override; function GetDescription: string; override; end; implementation uses SysUtils, ZPlainLoader, ZEncoding {$IFDEF WITH_UNITANSISTRINGS}, AnsiStrings{$ENDIF}; { TZMySQLPlainBaseDriver } function TZMySQLBaseDriver.GetUnicodeCodePageName: String; begin Result := 'utf8'; end; procedure TZMySQLBaseDriver.LoadCodePages; begin {MySQL 3.23-4.1} { MultiByte } AddCodePage('big5', 1, ceAnsi, zCP_Big5, '', 2); {Big5 Traditional Chinese} AddCodePage('ujis', 10, ceAnsi, zCP_EUC_JP, '', 3); {EUC-JP Japanese} AddCodePage('sjis', 11, ceAnsi, zCP_SHIFTJS, '', 2); {Shift-JIS Japanese} AddCodePage('gbk', 19, ceAnsi, zCP_GB2312, '', 2); {GBK Simplified Chinese} AddCodePage('utf8', 22, ceUTF8, zCP_UTF8, '', 3); {UTF-8 Unicode} AddCodePage('ucs2', 23, ceUTF16, zCP_UTF16, 'utf8', 2); {UCS-2 Unicode} AddCodePage('euckr', 14, ceAnsi, zCP_EUCKR, '', 2); {EUC-KR Korean} AddCodePage('gb2312', 16, ceAnsi, zCP_GB2312, '', 2); {GB2312 Simplified Chinese} AddCodePage('cp932', 35, ceAnsi, zCP_SHIFTJS, '', 2); {SJIS for Windows Japanese} AddCodePage('eucjpms', 36, ceAnsi, $ffff, '', 3); {UJIS for Windows Japanese} { SingleChar } AddCodePage('dec8', 2); {DEC West European} AddCodePage('cp850', 3, ceAnsi, zCP_DOS850); {DOS West European} AddCodePage('hp8', 4); {HP West European} AddCodePage('koi8r', 5, ceAnsi, zCP_KOI8R); {KOI8-R Relcom Russian} AddCodePage('latin1', 6, ceAnsi, zCP_WIN1252); {cp1252 West European} AddCodePage('latin2', 7, ceAnsi, zCP_L2_ISO_8859_2); {ISO 8859-2 Central European} AddCodePage('swe7', 8, ceAnsi, zCP_x_IA5_Swedish); {7bit Swedish} AddCodePage('ascii', 9, ceAnsi, zCP_us_ascii); {US ASCII} AddCodePage('hebrew', 12, ceAnsi, zCP_L8_ISO_8859_8); {ISO 8859-8 Hebrew} AddCodePage('tis620', 13, ceAnsi, zCP_IBM_Thai); {TIS620 Thai} AddCodePage('koi8u', 15, ceAnsi, zCP_KOI8U); {KOI8-U Ukrainian} AddCodePage('greek', 17, ceAnsi, zCP_L7_ISO_8859_7); {ISO 8859-7 Greek} AddCodePage('cp1250', 18, ceAnsi, zCP_WIN1250); {Windows Central European} AddCodePage('latin5', 20, ceAnsi, zCP_L5_ISO_8859_9); {ISO 8859-9 Turkish} AddCodePage('armscii8', 21, ceAnsi, zCP_us_ascii); {ARMSCII-8 Armenian} AddCodePage('cp866', 24, ceAnsi, zCP_DOS866); {DOS Russian} AddCodePage('keybcs2', 25); {DOS Kamenicky Czech-Slovak} AddCodePage('macce', 26, ceAnsi, zCP_x_mac_ce); {Mac Central European} AddCodePage('macroman', 27, ceAnsi, zCP_macintosh); {Mac West European} AddCodePage('cp852', 28, ceAnsi, zCP_DOS852); {DOS Central European} AddCodePage('latin7', 29, ceAnsi, zCP_L7_ISO_8859_13); {ISO 8859-13 Baltic} AddCodePage('cp1251', 30, ceAnsi, zCP_WIN1251); {Windows Cyrillic} AddCodePage('cp1256', 31, ceAnsi, cCP_WIN1256); {Windows Arabic} AddCodePage('cp1257', 32, ceAnsi, zCP_WIN1257); {Windows Baltic} AddCodePage('binary', 33); {Binary pseudo charset} AddCodePage('geostd8', 34); {GEOSTD8 Georgian} end; procedure TZMySQLBaseDriver.LoadApi; begin { ************** Load adresses of API Functions ************* } with Loader do begin @MYSQL_API.mysql_affected_rows := GetAddress('mysql_affected_rows'); @MYSQL_API.mysql_character_set_name := GetAddress('mysql_character_set_name'); @MYSQL_API.mysql_close := GetAddress('mysql_close'); @MYSQL_API.mysql_connect := GetAddress('mysql_connect'); @MYSQL_API.mysql_create_db := GetAddress('mysql_create_db'); @MYSQL_API.mysql_data_seek := GetAddress('mysql_data_seek'); @MYSQL_API.mysql_debug := GetAddress('mysql_debug'); @MYSQL_API.mysql_drop_db := GetAddress('mysql_drop_db'); @MYSQL_API.mysql_dump_debug_info := GetAddress('mysql_dump_debug_info'); @MYSQL_API.mysql_eof := GetAddress('mysql_eof'); @MYSQL_API.mysql_errno := GetAddress('mysql_errno'); @MYSQL_API.mysql_error := GetAddress('mysql_error'); @MYSQL_API.mysql_escape_string := GetAddress('mysql_escape_string'); @MYSQL_API.mysql_fetch_field := GetAddress('mysql_fetch_field'); @MYSQL_API.mysql_fetch_field_direct := GetAddress('mysql_fetch_field_direct'); @MYSQL_API.mysql_fetch_fields := GetAddress('mysql_fetch_fields'); @MYSQL_API.mysql_fetch_lengths := GetAddress('mysql_fetch_lengths'); @MYSQL_API.mysql_fetch_row := GetAddress('mysql_fetch_row'); @MYSQL_API.mysql_field_seek := GetAddress('mysql_field_seek'); @MYSQL_API.mysql_field_tell := GetAddress('mysql_field_tell'); @MYSQL_API.mysql_free_result := GetAddress('mysql_free_result'); @MYSQL_API.mysql_get_client_info := GetAddress('mysql_get_client_info'); @MYSQL_API.mysql_get_host_info := GetAddress('mysql_get_host_info'); @MYSQL_API.mysql_get_proto_info := GetAddress('mysql_get_proto_info'); @MYSQL_API.mysql_get_server_info := GetAddress('mysql_get_server_info'); @MYSQL_API.mysql_info := GetAddress('mysql_info'); @MYSQL_API.mysql_init := GetAddress('mysql_init'); @MYSQL_API.mysql_insert_id := GetAddress('mysql_insert_id'); @MYSQL_API.mysql_kill := GetAddress('mysql_kill'); @MYSQL_API.mysql_list_dbs := GetAddress('mysql_list_dbs'); @MYSQL_API.mysql_list_fields := GetAddress('mysql_list_fields'); @MYSQL_API.mysql_list_processes := GetAddress('mysql_list_processes'); @MYSQL_API.mysql_list_tables := GetAddress('mysql_list_tables'); @MYSQL_API.mysql_num_fields := GetAddress('mysql_num_fields'); @MYSQL_API.mysql_num_rows := GetAddress('mysql_num_rows'); @MYSQL_API.mysql_options := GetAddress('mysql_options'); @MYSQL_API.mysql_ping := GetAddress('mysql_ping'); @MYSQL_API.mysql_query := GetAddress('mysql_query'); @MYSQL_API.mysql_real_connect := GetAddress('mysql_real_connect'); @MYSQL_API.mysql_real_escape_string := GetAddress('mysql_real_escape_string'); @MYSQL_API.mysql_real_query := GetAddress('mysql_real_query'); @MYSQL_API.mysql_refresh := GetAddress('mysql_refresh'); @MYSQL_API.mysql_row_seek := GetAddress('mysql_row_seek'); @MYSQL_API.mysql_row_tell := GetAddress('mysql_row_tell'); @MYSQL_API.mysql_select_db := GetAddress('mysql_select_db'); @MYSQL_API.mysql_shutdown := GetAddress('mysql_shutdown'); @MYSQL_API.mysql_ssl_set := GetAddress('mysql_ssl_set'); @MYSQL_API.mysql_stat := GetAddress('mysql_stat'); @MYSQL_API.mysql_store_result := GetAddress('mysql_store_result'); @MYSQL_API.mysql_thread_id := GetAddress('mysql_thread_id'); @MYSQL_API.mysql_use_result := GetAddress('mysql_use_result'); @MYSQL_API.my_init := GetAddress('my_init'); @MYSQL_API.mysql_thread_init := GetAddress('mysql_thread_init'); @MYSQL_API.mysql_thread_end := GetAddress('mysql_thread_end'); @MYSQL_API.mysql_thread_safe := GetAddress('mysql_thread_safe'); @MYSQL_API.mysql_server_init := GetAddress('mysql_server_init'); @MYSQL_API.mysql_server_end := GetAddress('mysql_server_end'); @MYSQL_API.mysql_change_user := GetAddress('mysql_change_user'); @MYSQL_API.mysql_field_count := GetAddress('mysql_field_count'); @MYSQL_API.mysql_get_client_version := GetAddress('mysql_get_client_version'); @MYSQL_API.mysql_send_query := GetAddress('mysql_send_query'); @MYSQL_API.mysql_read_query_result := GetAddress('mysql_read_query_result'); @MYSQL_API.mysql_autocommit := GetAddress('mysql_autocommit'); @MYSQL_API.mysql_commit := GetAddress('mysql_commit'); @MYSQL_API.mysql_get_server_version := GetAddress('mysql_get_server_version'); @MYSQL_API.mysql_hex_string := GetAddress('mysql_hex_string'); @MYSQL_API.mysql_more_results := GetAddress('mysql_more_results'); @MYSQL_API.mysql_next_result := GetAddress('mysql_next_result'); @MYSQL_API.mysql_rollback := GetAddress('mysql_rollback'); @MYSQL_API.mysql_set_character_set := GetAddress('mysql_set_character_set'); @MYSQL_API.mysql_set_server_option := GetAddress('mysql_set_server_option'); @MYSQL_API.mysql_sqlstate := GetAddress('mysql_sqlstate'); @MYSQL_API.mysql_warning_count := GetAddress('mysql_warning_count'); {API for PREPARED STATEMENTS} @MYSQL_API.mysql_stmt_affected_rows := GetAddress('mysql_stmt_affected_rows'); @MYSQL_API.mysql_stmt_attr_get := GetAddress('mysql_stmt_attr_get'); @MYSQL_API.mysql_stmt_attr_set := GetAddress('mysql_stmt_attr_set'); @MYSQL_API.mysql_stmt_bind_param := GetAddress('mysql_stmt_bind_param'); @MYSQL_API.mysql_stmt_bind_result := GetAddress('mysql_stmt_bind_result'); @MYSQL_API.mysql_stmt_close := GetAddress('mysql_stmt_close'); @MYSQL_API.mysql_stmt_data_seek := GetAddress('mysql_stmt_data_seek'); @MYSQL_API.mysql_stmt_errno := GetAddress('mysql_stmt_errno'); @MYSQL_API.mysql_stmt_error := GetAddress('mysql_stmt_error'); @MYSQL_API.mysql_stmt_execute := GetAddress('mysql_stmt_execute'); @MYSQL_API.mysql_stmt_fetch := GetAddress('mysql_stmt_fetch'); @MYSQL_API.mysql_stmt_fetch_column := GetAddress('mysql_stmt_fetch_column'); @MYSQL_API.mysql_stmt_field_count := GetAddress('mysql_stmt_field_count'); @MYSQL_API.mysql_stmt_free_result := GetAddress('mysql_stmt_free_result'); @MYSQL_API.mysql_stmt_init := GetAddress('mysql_stmt_init'); @MYSQL_API.mysql_stmt_insert_id := GetAddress('mysql_stmt_insert_id'); @MYSQL_API.mysql_stmt_num_rows := GetAddress('mysql_stmt_num_rows'); @MYSQL_API.mysql_stmt_param_count := GetAddress('mysql_stmt_param_count'); @MYSQL_API.mysql_stmt_param_metadata := GetAddress('mysql_stmt_param_metadata'); @MYSQL_API.mysql_stmt_prepare := GetAddress('mysql_stmt_prepare'); @MYSQL_API.mysql_stmt_reset := GetAddress('mysql_stmt_reset'); @MYSQL_API.mysql_stmt_result_metadata := GetAddress('mysql_stmt_result_metadata'); @MYSQL_API.mysql_stmt_row_seek := GetAddress('mysql_stmt_row_seek'); @MYSQL_API.mysql_stmt_row_tell := GetAddress('mysql_stmt_row_tell'); @MYSQL_API.mysql_stmt_send_long_data := GetAddress('mysql_stmt_send_long_data'); @MYSQL_API.mysql_stmt_sqlstate := GetAddress('mysql_stmt_sqlstate'); @MYSQL_API.mysql_stmt_store_result := GetAddress('mysql_stmt_store_result'); end; end; procedure TZMySQLBaseDriver.BuildServerArguments(Options: TStrings); var TmpList: TStringList; i: Integer; begin TmpList := TStringList.Create; try TmpList.Add(ParamStr(0)); for i := 0 to Options.Count - 1 do if SameText(SERVER_ARGUMENTS_KEY_PREFIX, Copy(Options.Names[i], 1, Length(SERVER_ARGUMENTS_KEY_PREFIX))) then TmpList.Add(Options.ValueFromIndex[i]); //Check if DataDir is specified, if not, then add it to the Arguments List if TmpList.Values['--datadir'] = '' then TmpList.Add('--datadir='+EMBEDDED_DEFAULT_DATA_DIR); for i := 0 to ServerArgsLen - 1 do {$IFDEF WITH_STRDISPOSE_DEPRECATED}AnsiStrings.{$ENDIF}StrDispose(ServerArgs[i]); ServerArgsLen := TmpList.Count; SetLength(ServerArgs, ServerArgsLen); for i := 0 to ServerArgsLen - 1 do {$IFDEF UNICODE} ServerArgs[i] := {$IFDEF WITH_STRNEW_DEPRECATED}AnsiStrings.{$ENDIF}StrNew(PAnsiChar(UTF8String(TmpList[i]))); {$ELSE} ServerArgs[i] := StrNew(PAnsiChar(TmpList[i])); {$ENDIF} finally TmpList.Free; end; end; constructor TZMySQLBaseDriver.Create(Tokenizer: IZTokenizer); begin inherited create; FLoader := TZNativeLibraryLoader.Create([]); FTokenizer := nil; FTokenizer := Tokenizer; {$IFNDEF MYSQL_STRICT_DLL_LOADING} {$IFNDEF UNIX} FLoader.AddLocation(WINDOWS_DLL_LOCATION); {$ELSE} FLoader.AddLocation(LINUX_DLL_LOCATION); {$ENDIF} {$ENDIF} ServerArgsLen := 0; SetLength(ServerArgs, ServerArgsLen); IsEmbeddedDriver := False; LoadCodePages; end; destructor TZMySQLBaseDriver.Destroy; var i : integer; begin for i := 0 to ServerArgsLen - 1 do {$IFDEF WITH_STRDISPOSE_DEPRECATED}AnsiStrings.{$ENDIF}StrDispose(ServerArgs[i]); if (FLoader.Loaded) and (@MYSQL_API.mysql_server_end <> nil) then MYSQL_API.mysql_server_end; inherited Destroy; end; procedure TZMySQLBaseDriver.Close(Handle: PZMySQLConnect); begin MYSQL_API.mysql_close(Handle); end; function TZMySQLBaseDriver.Connect(Handle: PZMySQLConnect; const Host, User, Password: PAnsiChar): PZMySQLConnect; begin Result := MYSQL_API.mysql_connect(Handle, Host, User, Password); end; function TZMySQLBaseDriver.SslSet(Handle: PZMySQLConnect; const Key, Cert, Ca, Capath, Cipher: PAnsiChar): Integer; begin Result := MYSQL_API.mysql_ssl_set(Handle, Key, Cert, Ca, Capath, Cipher); end; function TZMySQLBaseDriver.CreateDatabase(Handle: PZMySQLConnect; const Database: PAnsiChar): Integer; begin Result := MYSQL_API.mysql_create_db(Handle, Database); end; procedure TZMySQLBaseDriver.Debug(Debug: PAnsiChar); begin MYSQL_API.mysql_debug(Debug); end; function TZMySQLBaseDriver.DropDatabase(Handle: PZMySQLConnect; const Database: PAnsiChar): Integer; begin Result := MYSQL_API.mysql_drop_db(Handle, Database); end; function TZMySQLBaseDriver.DumpDebugInfo(Handle: PZMySQLConnect): Integer; begin Result := MYSQL_API.mysql_dump_debug_info(Handle); end; function TZMySQLBaseDriver.ExecQuery(Handle: PZMySQLConnect; const Query: PAnsiChar): Integer; begin Result := MYSQL_API.mysql_query(Handle, Query); end; function TZMySQLBaseDriver.ExecRealQuery(Handle: PZMySQLConnect; const Query: PAnsiChar; Length: Integer): Integer; begin Result := MYSQL_API.mysql_real_query(Handle, Query, Length); end; function TZMySQLBaseDriver.FetchField(Res: PZMySQLResult): PZMySQLField; begin Result := MYSQL_API.mysql_fetch_field(Res); end; function TZMySQLBaseDriver.FetchLengths(Res: PZMySQLResult): PULong; begin Result := MYSQL_API.mysql_fetch_lengths(Res); end; function TZMySQLBaseDriver.FetchRow(Res: PZMySQLResult): PZMySQLRow; begin Result := MYSQL_API.mysql_fetch_row(Res); end; procedure TZMySQLBaseDriver.FreeResult(Res: PZMySQLResult); begin MYSQL_API.mysql_free_result(Res); end; function TZMySQLBaseDriver.GetAffectedRows(Handle: PZMySQLConnect): Int64; begin Result := MYSQL_API.mysql_affected_rows(Handle); end; {** EgonHugeist: Get CharacterSet of current Connection Returns the default character set name for the current connection. } function TZMySQLBaseDriver.GetConnectionCharacterSet(Handle: PMYSQL): PAnsiChar;// char_set_name begin if Assigned(MYSQL_API.mysql_character_set_name) then Result := MYSQL_API.mysql_character_set_name(Handle) else Result := ''; end; {** EgonHugeist: This function is used to set the default character set for the current connection. The string csname specifies a valid character set name. The connection collation becomes the default collation of the character set. This function works like the SET NAMES statement, but also sets the value of mysql->charset, and thus affects the character set used by mysql_real_escape_string() } function TZMySQLBaseDriver.SetConnectionCharacterSet(Handle: PMYSQL; const csname: PAnsiChar): Integer; // set_character_set Returns 0 if valid begin Result := MYSQL_API.mysql_set_character_set(Handle, csName); end; function TZMySQLBaseDriver.GetClientInfo: PAnsiChar; begin Result := MYSQL_API.mysql_get_client_info; end; function TZMySQLBaseDriver.EscapeString(Handle: Pointer; const Value: RawByteString; ConSettings: PZConSettings; WasEncoded: Boolean = False): RawByteString; var Len, outlength: integer; Outbuffer: RawByteString; TempValue: RawByteString; begin {$IFDEF UNICODE} TempValue := Value; {$ELSE} if WasEncoded then TempValue := Value else TempValue := ZPlainString(Value, ConSettings); //check encoding too {$ENDIF} Len := Length(TempValue); Setlength(Outbuffer,Len*2+1); if Handle = nil then OutLength := MYSQL_API.mysql_escape_string(PAnsiChar(OutBuffer), PAnsiChar(TempValue), Len) else OutLength := MYSQL_API.mysql_real_escape_string(Handle, PAnsiChar(OutBuffer), PAnsiChar(TempValue), Len); Setlength(Outbuffer,OutLength); Result := #39+Outbuffer+#39; end; function TZMySQLBaseDriver.GetHostInfo(Handle: PZMySQLConnect): PAnsiChar; begin Result := MYSQL_API.mysql_get_host_info(Handle); end; function TZMySQLBaseDriver.GetListDatabases(Handle: PZMySQLConnect; Wild: PAnsiChar): PZMySQLResult; begin Result := MYSQL_API.mysql_list_dbs(Handle, Wild); end; function TZMySQLBaseDriver.GetListFields(Handle: PZMySQLConnect; const Table, Wild: PAnsiChar): PZMySQLResult; begin Result := MYSQL_API.mysql_list_fields(Handle, Table, Wild); end; function TZMySQLBaseDriver.GetListProcesses( Handle: PZMySQLConnect): PZMySQLResult; begin Result := MYSQL_API.mysql_list_processes(Handle); end; function TZMySQLBaseDriver.GetListTables(Handle: PZMySQLConnect; const Wild: PAnsiChar): PZMySQLResult; begin Result := MYSQL_API.mysql_list_tables(Handle, Wild); end; function TZMySQLBaseDriver.GetNumRows(Res: PZMySQLResult): Int64; begin if (Res = nil) then Result := 0 else Result := MYSQL_API.mysql_num_rows (Res); end; function TZMySQLBaseDriver.GetProtoInfo(Handle: PZMySQLConnect): Cardinal; begin Result := MYSQL_API.mysql_get_proto_info(Handle); end; function TZMySQLBaseDriver.GetServerInfo(Handle: PZMySQLConnect): PAnsiChar; begin Result := MYSQL_API.mysql_get_server_info(Handle); end; function TZMySQLBaseDriver.GetStatInfo(Handle: PZMySQLConnect): PAnsiChar; begin Result := MYSQL_API.mysql_stat(Handle); end; function TZMySQLBaseDriver.GetThreadId(Handle: PZMySQLConnect): Cardinal; begin Result := MYSQL_API.mysql_thread_id(Handle); end; function TZMySQLBaseDriver.Init(const Handle: PZMySQLConnect): PZMySQLConnect; begin if @MYSQL_API.mysql_server_init <> nil then MYSQL_API.mysql_server_init(ServerArgsLen, ServerArgs, @SERVER_GROUPS); Result := MYSQL_API.mysql_init(Handle); end; function TZMySQLBaseDriver.GetLastInsertID(Handle: PZMySQLConnect): Int64; begin Result := MYSQL_API.mysql_insert_id(PMYSQL(Handle)); end; procedure TZMySQLBaseDriver.Despose(var Handle: PZMySQLConnect); begin Handle := nil; end; function TZMySQLBaseDriver.Kill(Handle: PZMySQLConnect; Pid: LongInt): Integer; begin Result := MYSQL_API.mysql_kill(Handle, Pid); end; function TZMySQLBaseDriver.Ping(Handle: PZMySQLConnect): Integer; begin Result := MYSQL_API.mysql_ping(Handle); end; function TZMySQLBaseDriver.RealConnect(Handle: PZMySQLConnect; const Host, User, Password, Db: PAnsiChar; Port: Cardinal; UnixSocket: PAnsiChar; ClientFlag: Cardinal): PZMySQLConnect; begin Result := MYSQL_API.mysql_real_connect(Handle, Host, User, Password, Db, Port, UnixSocket, ClientFlag); end; {function TZMySQLBaseDriver.GetRealEscapeString(Handle: PZMySQLConnect; StrTo, StrFrom: PAnsiChar; Length: Cardinal): Cardinal; begin Result := MYSQL_API.mysql_real_escape_string(Handle, StrTo, StrFrom, Length); end;} function TZMySQLBaseDriver.Refresh(Handle: PZMySQLConnect; Options: Cardinal): Integer; begin Result := MYSQL_API.mysql_refresh(Handle, Options); end; procedure TZMySQLBaseDriver.SeekData(Res: PZMySQLResult; Offset: Cardinal); begin MYSQL_API.mysql_data_seek(Res, Offset); end; function TZMySQLBaseDriver.SeekField(Res: PZMySQLResult; Offset: Cardinal): Cardinal; begin Result := MYSQL_API.mysql_field_seek(Res, Offset); end; function TZMySQLBaseDriver.SeekRow(Res: PZMySQLResult; Row: PZMySQLRowOffset): PZMySQLRowOffset; begin Result := MYSQL_API.mysql_row_seek(Res, Row); end; function TZMySQLBaseDriver.SelectDatabase(Handle: PZMySQLConnect; const Database: PAnsiChar): Integer; begin Result := MYSQL_API.mysql_select_db(Handle, Database); end; function TZMySQLBaseDriver.SetOptions(Handle: PZMySQLConnect; Option: TMySQLOption; const Arg: Pointer): Integer; begin Result := MYSQL_API.mysql_options(Handle,TMySqlOption(Option), Arg); end; function TZMySQLBaseDriver.Shutdown(Handle: PZMySQLConnect; shutdown_level: TMysqlShutdownLevel = ZPlainMySqlConstants.SHUTDOWN_DEFAULT): Integer; begin Result := MYSQL_API.mysql_shutdown(Handle,shutdown_level); end; function TZMySQLBaseDriver.SetAutocommit(Handle: PZMySQLConnect; mode: Boolean): Boolean; begin Result := MYSQL_API.mysql_autocommit(PMYSQL(Handle), Byte(Ord(Mode))) = 0; end; function TZMySQLBaseDriver.Commit(Handle: PZMySQLConnect): Boolean; begin Result := MYSQL_API.mysql_commit(PMYSQL(Handle)) = 0; end; function TZMySQLBaseDriver.CheckAnotherRowset(Handle: PZMySQLConnect): Boolean; begin Result := MYSQL_API.mysql_more_results (PMYSQL(Handle)) <> 0; end; function TZMySQLBaseDriver.RetrieveNextRowset(Handle: PZMySQLConnect): Integer; begin Result := MYSQL_API.mysql_next_result (PMYSQL(Handle)); end; function TZMySQLBaseDriver.Rollback (Handle: PZMySQLConnect): Boolean; begin Result := MYSQL_API.mysql_rollback(PMYSQL(Handle)) = 0; end; function TZMySQLBaseDriver.GetSQLState(Handle: PZMySQLConnect): AnsiString; begin Result := MYSQL_API.mysql_sqlstate (PMYSQL(Handle)); end; function TZMySQLBaseDriver.StmtAttrSet(stmt: PZMySqlPrepStmt; option: TMysqlStmtAttrType; arg: PAnsiChar): Byte; begin Result := MYSQL_API.mysql_stmt_attr_set(PMYSQL_STMT(stmt),option,arg); end; function TZMySQLBaseDriver.GetPreparedAffectedRows(Handle: PZMySqlPrepStmt): Int64; begin Result := MYSQL_API.mysql_stmt_affected_rows (PMYSQL_STMT(Handle)); end; function TZMySQLBaseDriver.BindParameters(Handle: PZMySqlPrepStmt; bindArray: PZMysqlBindArray): Byte; begin Result := MYSQL_API.mysql_stmt_bind_param (PMYSQL_STMT(Handle), pointer(bindArray)); end; function TZMySQLBaseDriver.BindResult(Handle: PZMySqlPrepStmt; bindArray: PZMysqlBindArray): Byte; begin Result := MYSQL_API.mysql_stmt_bind_result (PMYSQL_STMT(Handle), pointer(bindArray)); end; function TZMySQLBaseDriver.ClosePrepStmt (PrepStmtHandle: PZMySqlPrepStmt): PZMySqlPrepStmt; begin if (MYSQL_API.mysql_stmt_close(PMYSQL_STMT(PrepStmtHandle)) = 0) then Result := nil else Result := PrepStmtHandle; end; procedure TZMySQLBaseDriver.SeekPreparedData(PrepStmtHandle: PZMySqlPrepStmt; Offset: Cardinal); begin MYSQL_API.mysql_stmt_data_seek(PMYSQL_STMT(PrepStmtHandle), Offset); end; function TZMySQLBaseDriver.GetLastPreparedErrorCode(Handle: PZMySqlPrepStmt):Integer; begin Result := MYSQL_API.mysql_stmt_errno(PMYSQL_STMT(Handle)); end; function TZMySQLBaseDriver.GetLastPreparedError(Handle: PZMySqlPrepStmt):AnsiString; begin Result := MYSQL_API.mysql_stmt_error(PMYSQL_STMT(Handle)); end; function TZMySQLBaseDriver.ExecuteStmt(Handle: PZMySqlPrepStmt): Integer; begin Result := MYSQL_API.mysql_stmt_execute (PMYSQL_STMT(Handle)); end; function TZMySQLBaseDriver.FetchBoundResults(Handle: PZMySqlPrepStmt): Integer; begin Result := MYSQL_API.mysql_stmt_fetch (PMYSQL_STMT(Handle)); end; function TZMySQLBaseDriver.GetPreparedFieldCount(Handle: PZMySqlPrepStmt): Integer; begin Result := MYSQL_API.mysql_stmt_field_count(PMYSQL_STMT(Handle)); end; function TZMySQLBaseDriver.FreePreparedResult(Handle: PZMySqlPrepStmt): Byte; begin Result := MYSQL_API.mysql_stmt_free_result(PMYSQL_STMT(Handle)); end; function TZMySQLBaseDriver.InitializePrepStmt (Handle: PZMySQLConnect): PZMySqlPrepStmt; begin Result := MYSQL_API.mysql_stmt_init(PMYSQL(Handle)); end; function TZMySQLBaseDriver.GetPreparedInsertID(Handle: PZMySqlPrepStmt): Int64; begin Result := MYSQL_API.mysql_stmt_insert_id (PMYSQL_STMT(Handle)); end; function TZMySQLBaseDriver.GetPreparedNextResult(Handle: PZMySqlPrepStmt): Integer; begin if (@MYSQL_API.mysql_stmt_next_result = nil) then Result := -1 // Successful and there are no more results else Result := MYSQL_API.mysql_stmt_next_result (PMYSQL_STMT(Handle)); end; function TZMySQLBaseDriver.GetPreparedNumRows(Handle: PZMySqlPrepStmt): Int64; begin if (Handle = nil) then Result := 0 else Result := MYSQL_API.mysql_stmt_num_rows (PMYSQL_STMT(Handle)); end; function TZMySQLBaseDriver.GetPreparedBindMarkers (Handle: PZMySqlPrepStmt): Cardinal; begin Result := MYSQL_API.mysql_stmt_param_count (PMYSQL_STMT(Handle)); end; function TZMySQLBaseDriver.GetStmtParamMetadata(PrepStmtHandle: PZMySqlPrepStmt): PZMySQLResult; begin Result := MYSQL_API.mysql_stmt_param_metadata(PMYSQL_STMT(PrepStmtHandle)); end; function TZMySQLBaseDriver.PrepareStmt(PrepStmtHandle: PZMySqlPrepStmt; const Query: PAnsiChar; Length: Integer): Integer; begin Result := MYSQL_API.mysql_stmt_prepare(PMYSQL_STMT(PrepStmtHandle), Query, Length); end; function TZMySQLBaseDriver.GetPreparedMetaData (Handle: PZMySqlPrepStmt): PZMySQLResult; begin Result := MYSQL_API.mysql_stmt_result_metadata (PMYSQL_STMT(Handle)); end; function TZMySQLBaseDriver.SeekPreparedRow(Handle: PZMySqlPrepStmt; Row: PZMySQLRowOffset): PZMySQLRowOffset; begin Result := MYSQL_API.mysql_stmt_row_seek (PMYSQL_STMT(Handle), Row); end; function TZMySQLBaseDriver.SendPreparedLongData(Handle: PZMySqlPrepStmt; parameter_number: Cardinal; const data: PAnsiChar; length: Cardinal): Byte; begin Result := MYSQL_API.mysql_stmt_send_long_data(PMYSQL_STMT(Handle), parameter_number, data, length); end; function TZMySQLBaseDriver.GetPreparedSQLState(Handle: PZMySqlPrepStmt): PAnsiChar; begin Result := MYSQL_API.mysql_stmt_sqlstate (PMYSQL_STMT(Handle)); end; function TZMySQLBaseDriver.StorePreparedResult (Handle: PZMySqlPrepStmt): Integer; begin Result := MYSQL_API.mysql_stmt_store_result (PMYSQL_STMT(Handle)); end; procedure TZMySQLBaseDriver.GetCharacterSetInfo(Handle: PZMySQLConnect; CharSetInfo: PMY_CHARSET_INFO); begin MYSQL_API.mysql_get_character_set_info(Handle, CharSetInfo); end; function TZMySQLBaseDriver.GetBindOffsets: MYSQL_BINDOFFSETS; var DriverVersion : Integer; begin DriverVersion:=GetClientVersion; case DriverVersion of 40100..40199 : begin result.buffer_type := NativeUint(@(PMYSQL_BIND41(nil).buffer_type)); result.buffer_length := NativeUint(@(PMYSQL_BIND41(nil).buffer_length)); result.is_unsigned := NativeUint(@(PMYSQL_BIND41(nil).is_unsigned)); result.buffer := NativeUint(@(PMYSQL_BIND41(nil).buffer)); result.length := NativeUint(@(PMYSQL_BIND41(nil).length)); result.is_null := NativeUint(@(PMYSQL_BIND41(nil).is_null)); result.size := Sizeof(MYSQL_BIND41); end; 50000..50099 : begin result.buffer_type := NativeUint(@(PMYSQL_BIND50(nil).buffer_type)); result.buffer_length := NativeUint(@(PMYSQL_BIND50(nil).buffer_length)); result.is_unsigned := NativeUint(@(PMYSQL_BIND50(nil).is_unsigned)); result.buffer := NativeUint(@(PMYSQL_BIND50(nil).buffer)); result.length := NativeUint(@(PMYSQL_BIND50(nil).length)); result.is_null := NativeUint(@(PMYSQL_BIND50(nil).is_null)); result.size := Sizeof(MYSQL_BIND50); end; 50100..59999 : begin result.buffer_type := NativeUint(@(PMYSQL_BIND51(nil).buffer_type)); result.buffer_length := NativeUint(@(PMYSQL_BIND51(nil).buffer_length)); result.is_unsigned := NativeUint(@(PMYSQL_BIND51(nil).is_unsigned)); result.buffer := NativeUint(@(PMYSQL_BIND51(nil).buffer)); result.length := NativeUint(@(PMYSQL_BIND51(nil).length)); result.is_null := NativeUint(@(PMYSQL_BIND51(nil).is_null)); result.size := Sizeof(MYSQL_BIND51); end; 60000..60099 : begin result.buffer_type := NativeUint(@(PMYSQL_BIND60(nil).buffer_type)); result.buffer_length := NativeUint(@(PMYSQL_BIND60(nil).buffer_length)); result.is_unsigned := NativeUint(@(PMYSQL_BIND60(nil).is_unsigned)); result.buffer := NativeUint(@(PMYSQL_BIND60(nil).buffer)); result.length := NativeUint(@(PMYSQL_BIND60(nil).length)); result.is_null := NativeUint(@(PMYSQL_BIND60(nil).is_null)); result.size := Sizeof(MYSQL_BIND60); end; else result.buffer_type:=0; end; end; function TZMySQLBaseDriver.StoreResult( Handle: PZMySQLConnect): PZMySQLResult; begin Result := MYSQL_API.mysql_store_result(Handle); end; function TZMySQLBaseDriver.UseResult(Handle: PZMySQLConnect): PZMySQLResult; begin Result := MYSQL_API.mysql_use_result(Handle); end; function TZMySQLBaseDriver.GetLastError(Handle: PZMySQLConnect): PAnsiChar; begin Result := MYSQL_API.mysql_error(Handle); end; function TZMySQLBaseDriver.GetFieldType(Field: PZMySQLField): TMysqlFieldTypes; begin Result := PMYSQL_FIELD(Field)^._type; end; function TZMySQLBaseDriver.GetFieldFlags(Field: PZMySQLField): Integer; begin Result := PMYSQL_FIELD(Field)^.flags; end; function TZMySQLBaseDriver.GetRowCount(Res: PZMySQLResult): Int64; begin Result := MYSQL_API.mysql_num_rows(Res); end; function TZMySQLBaseDriver.ResultSetExists(Handle: PZMySQLConnect): Boolean; begin result := MYSQL_API.mysql_field_count(Handle)<>0; // True If statement should return a resultset end; function TZMySQLBaseDriver.GetFieldCount(Res: PZMySQLResult): Integer; begin Result := MYSQL_API.mysql_num_fields(Res); end; function TZMySQLBaseDriver.GetFieldDecimals(Field: PZMySQLField): Integer; begin Result := PMYSQL_FIELD(Field)^.decimals; end; function TZMySQLBaseDriver.GetFieldCharsetNr(Field: PZMySQLField): UInt; begin Result := PMYSQL_FIELD(Field)^.charsetnr; end; function TZMySQLBaseDriver.GetFieldLength(Field: PZMySQLField): ULong; begin Result := PMYSQL_FIELD(Field)^.length; end; function TZMySQLBaseDriver.GetFieldMaxLength(Field: PZMySQLField): Integer; begin Result := PMYSQL_FIELD(Field)^.max_length; end; function TZMySQLBaseDriver.GetFieldName(Field: PZMySQLField): PAnsiChar; begin Result := PMYSQL_FIELD(Field)^.name; end; function TZMySQLBaseDriver.GetFieldTable(Field: PZMySQLField): PAnsiChar; begin Result := PMYSQL_FIELD(Field)^.table; end; function TZMySQLBaseDriver.GetFieldOrigTable(Field: PZMySQLField): PAnsiChar; begin Result := PMYSQL_FIELD(Field)^.org_table; end; function TZMySQLBaseDriver.GetFieldOrigName(Field: PZMySQLField): PAnsiChar; begin Result := PMYSQL_FIELD(Field)^.org_name; end; function TZMySQLBaseDriver.GetFieldData(Row: PZMySQLRow; Offset: Cardinal): PAnsiChar; begin Result := PMYSQL_ROW(ROW)[Offset]; end; function TZMySQLBaseDriver.GetLastErrorCode(Handle: PZMySQLConnect): Integer; begin Result := MYSQL_API.mysql_errno(PMYSQL(Handle)); end; function TZMySQLBaseDriver.GetClientVersion: Integer; begin Result := MYSQL_API.mysql_get_client_version; end; function TZMySQLBaseDriver.GetServerVersion( Handle: PZMySQLConnect): Integer; begin Result := MYSQL_API.mysql_get_server_version(Handle); end; procedure TZMySQLBaseDriver.SetDriverOptions(Options: TStrings); var PreferedLibrary: String; begin PreferedLibrary := Options.Values['Library']; if PreferedLibrary <> '' then Loader.AddLocation(PreferedLibrary); if IsEmbeddedDriver then BuildServerArguments(Options); end; { TZMySQL41PlainDriver } function TZMySQL41PlainDriver.Clone: IZPlainDriver; begin Result := TZMySQL41PlainDriver.Create(FTokenizer); end; constructor TZMySQL41PlainDriver.Create(Tokenizer: IZTokenizer); begin inherited Create(Tokenizer); {$IFNDEF UNIX} FLoader.AddLocation(WINDOWS_DLL41_LOCATION); {$ELSE} FLoader.AddLocation(LINUX_DLL41_LOCATION); {$ENDIF} end; function TZMySQL41PlainDriver.GetProtocol: string; begin Result := 'mysql-4.1'; end; function TZMySQL41PlainDriver.GetDescription: string; begin Result := 'Native Plain Driver for MySQL 4.1+'; end; { TZMySQLD41PlainDriver } function TZMySQLD41PlainDriver.Clone: IZPlainDriver; begin Result := TZMySQLD41PlainDriver.Create(FTokenizer); end; constructor TZMySQLD41PlainDriver.Create(Tokenizer: IZTokenizer); begin inherited Create(Tokenizer); // only include embedded library FLoader.ClearLocations; {$IFNDEF MYSQL_STRICT_DLL_LOADING} {$IFNDEF UNIX} FLoader.AddLocation(WINDOWS_DLL_LOCATION_EMBEDDED); {$ELSE} FLoader.AddLocation(LINUX_DLL_LOCATION_EMBEDDED); {$ENDIF} {$ENDIF} {$IFNDEF UNIX} FLoader.AddLocation(WINDOWS_DLL41_LOCATION_EMBEDDED); {$ELSE} FLoader.AddLocation(LINUX_DLL41_LOCATION_EMBEDDED); {$ENDIF} IsEmbeddedDriver := True; end; function TZMySQLD41PlainDriver.GetProtocol: string; begin Result := 'mysqld-4.1'; end; function TZMySQLD41PlainDriver.GetDescription: string; begin Result := 'Native Plain Driver for Embedded MySQL 4.1+'; end; { TZMySQL5PlainDriver } function TZMySQL5PlainDriver.Clone: IZPlainDriver; begin Result := TZMySQL5PlainDriver.Create(FTokenizer); end; procedure TZMySQL5PlainDriver.LoadApi; begin inherited LoadApi; with Loader do begin @MYSQL_API.mysql_get_character_set_info := GetAddress('mysql_get_character_set_info'); @MYSQL_API.mysql_stmt_next_result := GetAddress('mysql_stmt_next_result'); end; end; procedure TZMySQL5PlainDriver.LoadCodePages; begin inherited LoadCodePages; {MySQL 4.1-5.5} { MultiByte } AddCodePage('utf8mb4', 37, ceUTF8, zCP_UTF8, '', 4); {UTF-8 Unicode} AddCodePage('utf16', 38, ceUTF16, zCP_UTF16, 'utf8', 4); {UTF-16 Unicode} AddCodePage('utf32', 39, ceUTF16, zCP_utf32, 'utf8', 4); {UTF-32 Unicode} //Egonhugeist improved end; constructor TZMySQL5PlainDriver.Create(Tokenizer: IZTokenizer); begin inherited Create(Tokenizer); {$IFNDEF UNIX} {$IFNDEF MYSQL_STRICT_DLL_LOADING} FLoader.AddLocation(MARIADB_LOCATION); {$ENDIF} FLoader.AddLocation(WINDOWS_DLL50_LOCATION); FLoader.AddLocation(WINDOWS_DLL51_LOCATION); FLoader.AddLocation(WINDOWS_DLL55_LOCATION); {$ELSE} {$IFNDEF MYSQL_STRICT_DLL_LOADING} FLoader.AddLocation(MARIADB_LOCATION); {$ENDIF} FLoader.AddLocation(LINUX_DLL50_LOCATION); FLoader.AddLocation(LINUX_DLL51_LOCATION); FLoader.AddLocation(LINUX_DLL55_LOCATION); {$ENDIF} end; function TZMySQL5PlainDriver.GetProtocol: string; begin Result := 'mysql-5'; end; function TZMySQL5PlainDriver.GetDescription: string; begin Result := 'Native Plain Driver for MySQL 5.0+'; end; { TZMySQLD5PlainDriver } function TZMySQLD5PlainDriver.Clone: IZPlainDriver; begin Result := TZMySQLD5PlainDriver.Create(FTokenizer); end; constructor TZMySQLD5PlainDriver.Create(Tokenizer: IZTokenizer); begin inherited Create(Tokenizer); // only include embedded library FLoader.ClearLocations; {$IFNDEF MYSQL_STRICT_DLL_LOADING} {$IFNDEF UNIX} FLoader.AddLocation(WINDOWS_DLL_LOCATION_EMBEDDED); {$ELSE} FLoader.AddLocation(LINUX_DLL_LOCATION_EMBEDDED); {$ENDIF} {$ENDIF} {$IFNDEF UNIX} FLoader.AddLocation(WINDOWS_DLL50_LOCATION_EMBEDDED); FLoader.AddLocation(WINDOWS_DLL51_LOCATION_EMBEDDED); FLoader.AddLocation(WINDOWS_DLL55_LOCATION_EMBEDDED); {$ELSE} FLoader.AddLocation(LINUX_DLL50_LOCATION_EMBEDDED); FLoader.AddLocation(LINUX_DLL51_LOCATION_EMBEDDED); FLoader.AddLocation(LINUX_DLL55_LOCATION_EMBEDDED); {$ENDIF} IsEmbeddedDriver := True; end; function TZMySQLD5PlainDriver.GetProtocol: string; begin Result := 'mysqld-5'; end; function TZMySQLD5PlainDriver.GetDescription: string; begin Result := 'Native Plain Driver for Embedded MySQL 5+'; end; { TZMariaDB5PlainDriver } function TZMariaDB5PlainDriver.Clone: IZPlainDriver; begin Result := TZMariaDB5PlainDriver.Create(FTokenizer); end; constructor TZMariaDB5PlainDriver.Create(Tokenizer: IZTokenizer); begin inherited Create(Tokenizer); FLoader.ClearLocations; FLoader.AddLocation(MARIADB_LOCATION); end; function TZMariaDB5PlainDriver.GetProtocol: string; begin Result := 'MariaDB-5'; end; function TZMariaDB5PlainDriver.GetDescription: string; begin Result := 'Native Plain Driver for MariaDB-5.x'; end; end. ================================================ FILE: lib/zeosdbo/src/plain/ZPlainOracleConstants.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Delphi interface to Oracle Call Interface } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZPlainOracleConstants; interface {$I ZPlain.inc} {$J+} uses ZCompatibility; {***************** Plain API types definition ****************} const WINDOWS_DLL_LOCATION = 'oci.dll'; // WINDOWS_DLL_LOCATION = 'ora803.dll'; LINUX_DLL_LOCATION = 'libclntsh'+SharedSuffix; // LINUX_DLL_LOCATION = 'libwtc8.so'; type { Generic Oracle Types } sword = Integer; psword = ^sword; eword = Integer; uword = LongInt; sb4 = Integer; ub4 = LongInt; sb2 = SmallInt; ub2 = Word; sb1 = ShortInt; ub1 = Byte; dvoid = Pointer; text = PAnsiChar; size_T = NativeUInt; pub1 = ^ub1; psb1 = ^sb1; pub2 = ^ub2; psb2 = ^sb2; pub4 = ^ub4; psb4 = ^sb4; { Handle Types } POCIHandle = Pointer; PPOCIHandle = ^Pointer; POCIEnv = POCIHandle; POCIServer = POCIHandle; POCIError = POCIHandle; POCISvcCtx = POCIHandle; POCIStmt = POCIHandle; POCIDefine = POCIHandle; POCISession = POCIHandle; POCIBind = POCIHandle; POCIDescribe = POCIHandle; POCITrans = POCIHandle; POCITable = POCIHandle; POCIIter = POCIHandle; POCIType = Pointer; PPOCIType = ^POCIType; POCIInd = Pointer; PPOCIInd = ^POCIInd; POCITypeCode = POCIHandle; POCITypeElem = POCIHandle; POCITypeIter = POCIHandle; PPOCITypeIter = ^POCITypeIter; POCITypeMethod = POCIHandle; OCITypeGetOpt = ( OCI_TYPEGET_HEADER,// load only the header portion of the TDO when getting type OCI_TYPEGET_ALL //load all attribute and method descriptors as well ); { Descriptor Types } POCIDescriptor = Pointer; PPOCIDescriptor = ^POCIDescriptor; POCISnapshot = POCIDescriptor; //OCI snapshot descriptor POCILobLocator = POCIDescriptor; //OCI Lob Locator descriptor POCIParam = POCIDescriptor; //OCI Parameter descriptor POCIRowid = POCIDescriptor; //OCI ROWID descriptor POCIComplexObjectComp = POCIDescriptor; POCIAQEnqOptions = POCIDescriptor; POCIAQDeqOptions = POCIDescriptor; POCIAQMsgProperties = POCIDescriptor; POCIAQAgent = POCIDescriptor; POCIDateTime = POCIDescriptor; //OCI DateTime descriptor POCINumber = POCIDescriptor; PPOCINumber = ^POCINumber; POCIString = POCIDescriptor; POCIInterval = POCIDescriptor; //OCI Interval descriptor POCIResult = POCIDescriptor; //OCI Result Set Descriptor PPOCITypeElem = PPOCIDescriptor; PPOCITypeMethod = PPOCIDescriptor; OCIDuration = ub2; //enum! POCIDuration = ^OCIDuration; OCITypeEncap = ub2; //enum! OCITypeMethodFlag = ub2; //enum! OCITypeParamMode = ub2; //enum! OCIObjectPropId = ub1; OCIRefreshOpt = ub2; //enum; const OCI_DURATION_INVALID = $FFFF; { Invalid duration } OCI_DURATION_BEGIN = 10; { beginning sequence of duration } OCI_DURATION_NULL = (OCI_DURATION_BEGIN-1); { null duration } OCI_DURATION_DEFAULT = (OCI_DURATION_BEGIN-2); { default } OCI_DURATION_USER_CALLBACK = (OCI_DURATION_BEGIN-3); OCI_DURATION_NEXT = (OCI_DURATION_BEGIN-4); { next special duration } OCI_DURATION_SESSION = (OCI_DURATION_BEGIN); { the end of user session } OCI_DURATION_TRANS = (OCI_DURATION_BEGIN+1); { the end of user transaction } OCI_DURATION_STATEMENT = (OCI_DURATION_BEGIN+3); { This is to be used only during callouts. It is similar to that of OCI_DURATION_CALL, but lasts only for the duration of a callout. Its heap is from PGA } OCI_DURATION_CALLOUT = (OCI_DURATION_BEGIN+4); OCI_DURATION_LAST = OCI_DURATION_CALLOUT; { last of predefined durations } OCI_TEMP_BLOB = 1; { LOB type - BLOB } OCI_TEMP_CLOB = 2; { LOB type - CLOB } const MAXTXNAMELEN = 64; XIDDATASIZE = 128; { size in bytes } MAXGTRIDSIZE = 64; { maximum size in bytes of gtrid } MAXBQUALSIZE = 64; { maximum size in bytes of bqual } NULLXID_ID = -1; { Transaction branch identification: XID and NULLXID: } type PXID = ^TXID; TXID = record formatID: sb4; { format identifier } gtrid_length: sb4; { value from 1 through 64 } bqual_length: sb4; { value from 1 through 64 } data: array [0 .. XIDDATASIZE - 1] of ub1; end; const MAXUB4 = High(ub4); MAXSB4 = High(sb4); {***************** Plain API constants definition ****************} { OCI Handle Types } OCI_HTYPE_FIRST = 1; OCI_HTYPE_ENV = 1; OCI_HTYPE_ERROR = 2; OCI_HTYPE_SVCCTX = 3; OCI_HTYPE_STMT = 4; OCI_HTYPE_BIND = 5; OCI_HTYPE_DEFINE = 6; OCI_HTYPE_DESCRIBE = 7; OCI_HTYPE_SERVER = 8; OCI_HTYPE_SESSION = 9; OCI_HTYPE_TRANS = 10; OCI_HTYPE_COMPLEXOBJECT = 11; OCI_HTYPE_SECURITY = 12; OCI_HTYPE_SUBSCRIPTION = 13; OCI_HTYPE_DIRPATH_CTX = 14; OCI_HTYPE_DIRPATH_COLUMN_ARRAY = 15; OCI_HTYPE_DIRPATH_STREAM = 16; OCI_HTYPE_PROC = 17; OCI_HTYPE_LAST = 17; { OCI Descriptor Types } OCI_DTYPE_FIRST = 50; OCI_DTYPE_LOB = 50; //lob locator OCI_DTYPE_SNAP = 51; OCI_DTYPE_RSET = 52; OCI_DTYPE_PARAM = 53; //a parameter descriptor obtained from ocigparm OCI_DTYPE_ROWID = 54; OCI_DTYPE_COMPLEXOBJECTCOMP = 55; OCI_DTYPE_FILE = 56; //File Lob locator OCI_DTYPE_AQENQ_OPTIONS = 57; //enqueue options OCI_DTYPE_AQDEQ_OPTIONS = 58; //dequeue options OCI_DTYPE_AQMSG_PROPERTIES = 59; //message properties OCI_DTYPE_AQAGENT = 60; //aq agent OCI_DTYPE_LOCATOR = 61; OCI_DTYPE_INTERVAL_YM = 62; //Interval year month OCI_DTYPE_INTERVAL_DS = 63; //Interval day second OCI_DTYPE_AQNFY_DESCRIPTOR = 64; OCI_DTYPE_LAST = 64; OCI_DTYPE_DATE = 65; { Date } OCI_DTYPE_TIME = 66; { Time } OCI_DTYPE_TIME_TZ = 67; { Time with timezone } OCI_DTYPE_TIMESTAMP = 68; { Timestamp } OCI_DTYPE_TIMESTAMP_TZ = 69; { Timestamp with timezone } OCI_DTYPE_TIMESTAMP_LTZ = 70; { Timestamp with local tz } { OCI Attributes Types } OCI_ATTR_FNCODE = 1; // the OCI function code OCI_ATTR_OBJECT = 2; // is the environment initialized in object mode OCI_ATTR_NONBLOCKING_MODE = 3; // non blocking mode OCI_ATTR_SQLCODE = 4; // the SQL verb OCI_ATTR_ENV = 5; // the environment handle OCI_ATTR_SERVER = 6; // the server handle OCI_ATTR_SESSION = 7; // the user session handle OCI_ATTR_TRANS = 8; // the transaction handle OCI_ATTR_ROW_COUNT = 9; // the rows processed so far OCI_ATTR_SQLFNCODE = 10; // the SQL verb of the statement OCI_ATTR_PREFETCH_ROWS = 11; // sets the number of rows to prefetch OCI_ATTR_NESTED_PREFETCH_ROWS = 12; // the prefetch rows of nested table OCI_ATTR_PREFETCH_MEMORY = 13; // memory limit for rows fetched OCI_ATTR_NESTED_PREFETCH_MEMORY = 14;// memory limit for nested rows OCI_ATTR_CHAR_COUNT = 15; // this specifies the bind and define size in characters OCI_ATTR_PDSCL = 16; // packed decimal scale OCI_ATTR_FSPRECISION = OCI_ATTR_PDSCL; // fs prec for datetime data types OCI_ATTR_PDPRC = 17; // packed decimal format OCI_ATTR_LFPRECISION = OCI_ATTR_PDPRC; // fs prec for datetime data types OCI_ATTR_PARAM_COUNT = 18; // number of column in the select list OCI_ATTR_ROWID = 19; // the rowid OCI_ATTR_CHARSET = 20; // the character set value OCI_ATTR_NCHAR = 21; // NCHAR type OCI_ATTR_USERNAME = 22; // username attribute OCI_ATTR_PASSWORD = 23; // password attribute OCI_ATTR_STMT_TYPE = 24; // statement type OCI_ATTR_INTERNAL_NAME = 25; // user friendly global name OCI_ATTR_EXTERNAL_NAME = 26; // the internal name for global txn OCI_ATTR_XID = 27; // XOPEN defined global transaction id OCI_ATTR_TRANS_LOCK = 28; // OCI_ATTR_TRANS_NAME = 29; // string to identify a global transaction OCI_ATTR_HEAPALLOC = 30; // memory allocated on the heap OCI_ATTR_CHARSET_ID = 31; // Character Set ID OCI_ATTR_CHARSET_FORM = 32; // Character Set Form OCI_ATTR_MAXDATA_SIZE = 33; // Maximumsize of data on the server OCI_ATTR_CACHE_OPT_SIZE = 34; // object cache optimal size OCI_ATTR_CACHE_MAX_SIZE = 35; // object cache maximum size percentage OCI_ATTR_PINOPTION = 36; // object cache default pin option OCI_ATTR_ALLOC_DURATION = 37; // object cache default allocation duration OCI_ATTR_PIN_DURATION = 38; // object cache default pin duration OCI_ATTR_FDO = 39; // Format Descriptor object attribute OCI_ATTR_POSTPROCESSING_CALLBACK = 40; // Callback to process outbind data OCI_ATTR_POSTPROCESSING_CONTEXT = 41; // Callback context to process outbind data OCI_ATTR_ROWS_RETURNED = 42; // Number of rows returned in current iter - for Bind handles OCI_ATTR_FOCBK = 43; // Failover Callback attribute OCI_ATTR_IN_V8_MODE = 44; // is the server/service context in V8 mode OCI_ATTR_LOBEMPTY = 45; // empty lob ? OCI_ATTR_SESSLANG = 46; // session language handle OCI_ATTR_VISIBILITY = 47; // visibility OCI_ATTR_RELATIVE_MSGID = 48; // relative message id OCI_ATTR_SEQUENCE_DEVIATION = 49; // sequence deviation OCI_ATTR_CONSUMER_NAME = 50; // consumer name OCI_ATTR_DEQ_MODE = 51; // dequeue mode OCI_ATTR_NAVIGATION = 52; // navigation OCI_ATTR_WAIT = 53; // wait OCI_ATTR_DEQ_MSGID = 54; // dequeue message id OCI_ATTR_PRIORITY = 55; // priority OCI_ATTR_DELAY = 56; // delay OCI_ATTR_EXPIRATION = 57; // expiration OCI_ATTR_CORRELATION = 58; // correlation id OCI_ATTR_ATTEMPTS = 59; // # of attempts OCI_ATTR_RECIPIENT_LIST = 60; // recipient list OCI_ATTR_EXCEPTION_QUEUE = 61; // exception queue name OCI_ATTR_ENQ_TIME = 62; // enqueue time (only OCIAttrGet) OCI_ATTR_MSG_STATE = 63; // message state (only OCIAttrGet) // NOTE: 64-66 used below OCI_ATTR_AGENT_NAME = 64; // agent name OCI_ATTR_AGENT_ADDRESS = 65; // agent address OCI_ATTR_AGENT_PROTOCOL = 66; // agent protocol OCI_ATTR_SENDER_ID = 68; // sender id OCI_ATTR_ORIGINAL_MSGID = 69; // original message id OCI_ATTR_QUEUE_NAME = 70; // queue name OCI_ATTR_NFY_MSGID = 71; // message id OCI_ATTR_MSG_PROP = 72; // message properties OCI_ATTR_NUM_DML_ERRORS = 73; // num of errs in array DML OCI_ATTR_DML_ROW_OFFSET = 74; // row offset in the array OCI_ATTR_DATEFORMAT = 75; // default date format string OCI_ATTR_BUF_ADDR = 76; // buffer address OCI_ATTR_BUF_SIZE = 77; // buffer size OCI_ATTR_DIRPATH_MODE = 78; // mode of direct path operation OCI_ATTR_DIRPATH_NOLOG = 79; // nologging option OCI_ATTR_DIRPATH_PARALLEL = 80; // parallel (temp seg) option OCI_ATTR_NUM_ROWS = 81; // number of rows in column array // NOTE that OCI_ATTR_NUM_COLS is a column // array attribute too. OCI_ATTR_COL_COUNT = 82; // columns of column array processed so far. OCI_ATTR_STREAM_OFFSET = 83; // str off of last row processed OCI_ATTR_SHARED_HEAPALLOC = 84; // Shared Heap Allocation Size OCI_ATTR_SERVER_GROUP = 85; // server group name OCI_ATTR_MIGSESSION = 86; // migratable session attribute OCI_ATTR_NOCACHE = 87; // Temporary LOBs OCI_ATTR_MEMPOOL_SIZE = 88; // Pool Size OCI_ATTR_MEMPOOL_INSTNAME = 89; // Instance name OCI_ATTR_MEMPOOL_APPNAME = 90; // Application name OCI_ATTR_MEMPOOL_HOMENAME = 91; // Home Directory name OCI_ATTR_MEMPOOL_MODEL = 92; // Pool Model (proc,thrd,both) OCI_ATTR_MODES = 93; // Modes OCI_ATTR_SUBSCR_NAME = 94; // name of subscription OCI_ATTR_SUBSCR_CALLBACK = 95; // associated callback OCI_ATTR_SUBSCR_CTX = 96; // associated callback context OCI_ATTR_SUBSCR_PAYLOAD = 97; // associated payload OCI_ATTR_SUBSCR_NAMESPACE = 98; // associated namespace OCI_ATTR_PROXY_CREDENTIALS = 99; // Proxy user credentials OCI_ATTR_INITIAL_CLIENT_ROLES = 100; // Initial client role list OCI_ATTR_UNK = 101; // unknown attribute OCI_ATTR_NUM_COLS = 102; // number of columns OCI_ATTR_LIST_COLUMNS = 103; // parameter of the column list OCI_ATTR_RDBA = 104; // DBA of the segment header OCI_ATTR_CLUSTERED = 105; // whether the table is clustered OCI_ATTR_PARTITIONED = 106; // whether the table is partitioned OCI_ATTR_INDEX_ONLY = 107; // whether the table is index only OCI_ATTR_LIST_ARGUMENTS = 108; // parameter of the argument list OCI_ATTR_LIST_SUBPROGRAMS = 109; // parameter of the subprogram list OCI_ATTR_REF_TDO = 110; // REF to the type descriptor OCI_ATTR_LINK = 111; // the database link name OCI_ATTR_MIN = 112; // minimum value OCI_ATTR_MAX = 113; // maximum value OCI_ATTR_INCR = 114; // increment value OCI_ATTR_CACHE = 115; // number of sequence numbers cached OCI_ATTR_ORDER = 116; // whether the sequence is ordered OCI_ATTR_HW_MARK = 117; // high-water mark OCI_ATTR_TYPE_SCHEMA = 118; // type's schema name OCI_ATTR_TIMESTAMP = 119; // timestamp of the object OCI_ATTR_NUM_ATTRS = 120; // number of sttributes OCI_ATTR_NUM_PARAMS = 121; // number of parameters OCI_ATTR_OBJID = 122; // object id for a table or view OCI_ATTR_PTYPE = 123; // type of info described by OCI_ATTR_PARAM = 124; // parameter descriptor OCI_ATTR_OVERLOAD_ID = 125; // overload ID for funcs and procs OCI_ATTR_TABLESPACE = 126; // table name space OCI_ATTR_TDO = 127; // TDO of a type OCI_ATTR_LTYPE = 128; // list type OCI_ATTR_PARSE_ERROR_OFFSET = 129; // Parse Error offset OCI_ATTR_IS_TEMPORARY = 130; // whether table is temporary OCI_ATTR_IS_TYPED = 131; // whether table is typed OCI_ATTR_DURATION = 132; // duration of temporary table OCI_ATTR_IS_INVOKER_RIGHTS = 133; // is invoker rights OCI_ATTR_OBJ_NAME = 134; // top level schema obj name OCI_ATTR_OBJ_SCHEMA = 135; // schema name OCI_ATTR_OBJ_ID = 136; // top level schema object id // for inheritance - part 2 OCI_ATTR_IS_FINAL_TYPE = 279; //is final type ? OCI_ATTR_IS_INSTANTIABLE_TYPE = 280; //is instantiable type ? OCI_ATTR_IS_FINAL_METHOD = 281; //is final method ? OCI_ATTR_IS_INSTANTIABLE_METHOD = 282; // is instantiable method ? OCI_ATTR_IS_OVERRIDING_METHOD = 283; // is overriding method ? OCI_ATTR_DESC_SYNBASE = 284; //Describe the base object OCI_ATTR_CHAR_USED = 285; //char length semantics OCI_ATTR_CHAR_SIZE = 286; //char length { OCI Error Return Values } OCI_SUCCESS = 0; OCI_SUCCESS_WITH_INFO = 1; OCI_NO_DATA = 100; OCI_ERROR = -1; OCI_INVALID_HANDLE = -2; OCI_NEED_DATA = 99; OCI_STILL_EXECUTING = -3123; OCI_CONTINUE = -24200; { Generic Default Value for Modes, .... } OCI_DEFAULT = $0; { OCI Init Mode } OCI_THREADED = $1; OCI_OBJECT = $2; OCI_EVENTS = $4; OCI_SHARED = $10; OCI_NO_UCB = $40; OCI_NO_MUTEX = $80; { OCI Credentials } OCI_CRED_RDBMS = 1; OCI_CRED_EXT = 2; OCI_CRED_PROXY = 3; { OCI Authentication Mode } OCI_MIGRATE = $0001; // migratable auth context OCI_SYSDBA = $0002; // for SYSDBA authorization OCI_SYSOPER = $0004; // for SYSOPER authorization OCI_PRELIM_AUTH = $0008; // for preliminary authorization { OCIPasswordChange } OCI_AUTH = $08; // Change the password but do not login { OCI Data Types } SQLT_CHR = 1 ; //(ORANET TYPE) character string SQLT_NUM = 2 ; //(ORANET TYPE) oracle numeric SQLT_INT = 3 ; //(ORANET TYPE) integer SQLT_FLT = 4 ; //(ORANET TYPE) Floating point number SQLT_STR = 5 ; //zero terminated string SQLT_VNU = 6 ; //NUM with preceding length byte SQLT_PDN = 7 ; //(ORANET TYPE) Packed Decimal Numeric SQLT_LNG = 8 ; //long SQLT_VCS = 9 ; //Variable character string SQLT_NON = 10 ; //Null/empty PCC Descriptor entry SQLT_RID = 11 ; //rowid SQLT_DAT = 12 ; //date in oracle format SQLT_VBI = 15 ; //binary in VCS format SQLT_BFLOAT = 21 ; //Native Binary float SQLT_BDOUBLE = 22 ; //NAtive binary double SQLT_BIN = 23 ; //binary data(DTYBIN) SQLT_LBI = 24 ; //long binary _SQLT_PLI = 29; SQLT_UIN = 68 ; //unsigned integer SQLT_SLS = 91 ; //Display sign leading separate SQLT_LVC = 94 ; //Longer longs (char) SQLT_LVB = 95 ; //Longer long binary SQLT_AFC = 96 ; //Ansi fixed char SQLT_AVC = 97 ; //Ansi Var char SQLT_IBFLOAT = 100; //binary float canonical SQLT_IBDOUBLE = 101; //binary double canonical SQLT_CUR = 102; //cursor type SQLT_RDD = 104; //rowid descriptor SQLT_LAB = 105; //label type SQLT_OSL = 106; //oslabel type SQLT_NTY = 108; //named object type SQLT_REF = 110; //ref typ SQLT_CLOB = 112; //character lob SQLT_BLOB = 113; //binary lob SQLT_BFILEE = 114; //binary file lob SQLT_CFILEE = 115; //character file lob SQLT_RSET = 116; //result set type SQLT_NCO = 122; //named collection type (varray or nested table) SQLT_VST = 155; //OCIString type SQLT_ODT = 156; //OCIDate type { datetimes and intervals } SQLT_DATE = 184; //ANSI Date SQLT_TIME = 185; //TIME SQLT_TIME_TZ = 186; //TIME WITH TIME ZONE SQLT_TIMESTAMP = 187; //TIMESTAMP SQLT_TIMESTAMP_TZ = 188; //TIMESTAMP WITH TIME ZONE SQLT_INTERVAL_YM = 189; //INTERVAL YEAR TO MONTH SQLT_INTERVAL_DS = 190; //INTERVAL DAY TO SECOND SQLT_TIMESTAMP_LTZ = 232; //TIMESTAMP WITH LOCAL TZ _SQLT_REC = 250; _SQLT_TAB = 251; _SQLT_BOL = 252; { > typecode defines from oro.h } OCI_TYPECODE_REF = SQLT_REF; //SQL/OTS OBJECT REFERENCE OCI_TYPECODE_VARRAY = 247; //SQL VARRAY OTS PAGED VARRAY OCI_TYPECODE_TABLE = 248; //SQL TABLE OTS MULTISET OCI_TYPECODE_OBJECT = SQLT_NTY; //SQL/OTS NAMED OBJECT TYPE OCI_TYPECODE_OPAQUE = 58; //SQL/OTS Opaque Types OCI_TYPECODE_NAMEDCOLLECTION = SQLT_NCO; { OCI Statement Types } OCI_STMT_SELECT = 1; // select statement OCI_STMT_UPDATE = 2; // update statement OCI_STMT_DELETE = 3; // delete statement OCI_STMT_INSERT = 4; // Insert Statement OCI_STMT_CREATE = 5; // create statement OCI_STMT_DROP = 6; // drop statement OCI_STMT_ALTER = 7; // alter statement OCI_STMT_BEGIN = 8; // begin ... (pl/sql statement) OCI_STMT_DECLARE = 9; // declare .. (pl/sql statement) { OCI Statement language } OCI_NTV_SYNTAX = 1; // Use what so ever is the native lang of server OCI_V7_SYNTAX = 2; // V7 language OCI_V8_SYNTAX = 3; // V8 language { OCI Statement Execute mode } OCI_BATCH_MODE = $01; // batch the oci statement for execution OCI_EXACT_FETCH = $02; // fetch the exact rows specified OCI_SCROLLABLE_CURSOR = $08; // cursor scrollable OCI_DESCRIBE_ONLY = $10; // only describe the statement OCI_COMMIT_ON_SUCCESS = $20; // commit, if successful execution OCI_NON_BLOCKING = $40; // non-blocking OCI_BATCH_ERRORS = $80; // batch errors in array dmls OCI_PARSE_ONLY = $100; // only parse the statement OCI_DATA_AT_EXEC = $02; // data at execute time OCI_DYNAMIC_FETCH = $02; // fetch dynamically OCI_PIECEWISE = $04; // piecewise DMLs or fetch { OCI Transaction modes } OCI_TRANS_NEW = $00000001; // starts a new transaction branch OCI_TRANS_JOIN = $00000002; // join an existing transaction OCI_TRANS_RESUME = $00000004; // resume this transaction OCI_TRANS_STARTMASK = $000000ff; OCI_TRANS_READONLY = $00000100; // starts a readonly transaction OCI_TRANS_READWRITE = $00000200; // starts a read-write transaction OCI_TRANS_SERIALIZABLE = $00000400; // starts a serializable transaction OCI_TRANS_ISOLMASK = $0000ff00; OCI_TRANS_LOOSE = $00010000; // a loosely coupled branch OCI_TRANS_TIGHT = $00020000; // a tightly coupled branch OCI_TRANS_TYPEMASK = $000f0000; OCI_TRANS_NOMIGRATE = $00100000; // non migratable transaction OCI_TRANS_TWOPHASE = $01000000; // use two phase commit { OCI pece wise fetch } OCI_ONE_PIECE = 0; // one piece OCI_FIRST_PIECE = 1; // the first piece OCI_NEXT_PIECE = 2; // the next of many pieces OCI_LAST_PIECE = 3; // the last piece { OCI fetch modes } OCI_FETCH_NEXT = $02; // next row OCI_FETCH_FIRST = $04; // first row of the result set OCI_FETCH_LAST = $08; // the last row of the result set OCI_FETCH_PRIOR = $10; // the previous row relative to current OCI_FETCH_ABSOLUTE = $20; // absolute offset from first OCI_FETCH_RELATIVE = $40; // offset relative to current {****************** Describe Handle Parameter Attributes *****************} { Attributes common to Columns and Stored Procs } OCI_ATTR_DATA_SIZE = 1; // maximum size of the data OCI_ATTR_DATA_TYPE = 2; // the SQL type of the column/argument OCI_ATTR_DISP_SIZE = 3; // the display size OCI_ATTR_NAME = 4; // the name of the column/argument OCI_ATTR_PRECISION = 5; // precision if number type OCI_ATTR_SCALE = 6; // scale if number type OCI_ATTR_IS_NULL = 7; // is it null ? OCI_ATTR_TYPE_NAME = 8; // name of the named data type or a package name for package private types OCI_ATTR_SCHEMA_NAME = 9; // the schema name OCI_ATTR_SUB_NAME = 10; // type name if package private type OCI_ATTR_POSITION = 11; // relative position of col/arg in the list of cols/args { complex object retrieval parameter attributes } OCI_ATTR_COMPLEXOBJECTCOMP_TYPE = 50; OCI_ATTR_COMPLEXOBJECTCOMP_TYPE_LEVEL = 51; OCI_ATTR_COMPLEXOBJECT_LEVEL = 52; OCI_ATTR_COMPLEXOBJECT_COLL_OUTOFLINE = 53; { Only Columns } OCI_ATTR_DISP_NAME = 100; // the display name { Only Stored Procs } OCI_ATTR_OVERLOAD = 210; // is this position overloaded OCI_ATTR_LEVEL = 211; // level for structured types OCI_ATTR_HAS_DEFAULT = 212; // has a default value OCI_ATTR_IOMODE = 213; // in, out inout OCI_ATTR_RADIX = 214; // returns a radix OCI_ATTR_NUM_ARGS = 215; // total number of arguments { only named type attributes } OCI_ATTR_TYPECODE = 216; // object or collection OCI_ATTR_COLLECTION_TYPECODE = 217; // varray or nested table OCI_ATTR_VERSION = 218; // user assigned version OCI_ATTR_IS_INCOMPLETE_TYPE = 219; // is this an incomplete type OCI_ATTR_IS_SYSTEM_TYPE = 220; // a system type OCI_ATTR_IS_PREDEFINED_TYPE = 221; // a predefined type OCI_ATTR_IS_TRANSIENT_TYPE = 222; // a transient type OCI_ATTR_IS_SYSTEM_GENERATED_TYPE = 223; // system generated type OCI_ATTR_HAS_NESTED_TABLE = 224; // contains nested table attr OCI_ATTR_HAS_LOB = 225; // has a lob attribute OCI_ATTR_HAS_FILE = 226; // has a file attribute OCI_ATTR_COLLECTION_ELEMENT = 227; // has a collection attribute OCI_ATTR_NUM_TYPE_ATTRS = 228; // number of attribute types OCI_ATTR_LIST_TYPE_ATTRS = 229; // list of type attributes OCI_ATTR_NUM_TYPE_METHODS = 230; // number of type methods OCI_ATTR_LIST_TYPE_METHODS = 231; // list of type methods OCI_ATTR_MAP_METHOD = 232; // map method of type OCI_ATTR_ORDER_METHOD = 233; // order method of type { only collection element } OCI_ATTR_NUM_ELEMS = 234; // number of elements { only type methods } OCI_ATTR_ENCAPSULATION = 235; // encapsulation level OCI_ATTR_IS_SELFISH = 236; // method selfish OCI_ATTR_IS_VIRTUAL = 237; // virtual OCI_ATTR_IS_INLINE = 238; // inline OCI_ATTR_IS_CONSTANT = 239; // constant OCI_ATTR_HAS_RESULT = 240; // has result OCI_ATTR_IS_CONSTRUCTOR = 241; // constructor OCI_ATTR_IS_DESTRUCTOR = 242; // destructor OCI_ATTR_IS_OPERATOR = 243; // operator OCI_ATTR_IS_MAP = 244; // a map method OCI_ATTR_IS_ORDER = 245; // order method OCI_ATTR_IS_RNDS = 246; // read no data state method OCI_ATTR_IS_RNPS = 247; // read no process state OCI_ATTR_IS_WNDS = 248; // write no data state method OCI_ATTR_IS_WNPS = 249; // write no process state OCI_ATTR_DESC_PUBLIC = 250; // public object { Object Cache Enhancements : attributes for User Constructed Instances } OCI_ATTR_CACHE_CLIENT_CONTEXT = 251; OCI_ATTR_UCI_CONSTRUCT = 252; OCI_ATTR_UCI_DESTRUCT = 253; OCI_ATTR_UCI_COPY = 254; OCI_ATTR_UCI_PICKLE = 255; OCI_ATTR_UCI_UNPICKLE = 256; OCI_ATTR_UCI_REFRESH = 257; { for type inheritance } OCI_ATTR_IS_SUBTYPE = 258; OCI_ATTR_SUPERTYPE_SCHEMA_NAME = 259; OCI_ATTR_SUPERTYPE_NAME = 260; { for schemas } OCI_ATTR_LIST_OBJECTS = 261; // list of objects in schema { for database } OCI_ATTR_NCHARSET_ID = 262; // char set id OCI_ATTR_LIST_SCHEMAS = 263; // list of schemas OCI_ATTR_MAX_PROC_LEN = 264; // max procedure length OCI_ATTR_MAX_COLUMN_LEN = 265; // max column name length OCI_ATTR_CURSOR_COMMIT_BEHAVIOR = 266; // cursor commit behavior OCI_ATTR_MAX_CATALOG_NAMELEN = 267; // catalog namelength OCI_ATTR_CATALOG_LOCATION = 268; // catalog location OCI_ATTR_SAVEPOINT_SUPPORT = 269; // savepoint support OCI_ATTR_NOWAIT_SUPPORT = 270; // nowait support OCI_ATTR_AUTOCOMMIT_DDL = 271; // autocommit DDL OCI_ATTR_LOCKING_MODE = 272; // locking mode OCI_ATTR_CACHE_ARRAYFLUSH = $40; OCI_ATTR_OBJECT_NEWNOTNULL = $10; OCI_ATTR_OBJECT_DETECTCHANGE = $20; {client side character and national character set ids } OCI_ATTR_ENV_CHARSET_ID = OCI_ATTR_CHARSET_ID; // charset id in env OCI_ATTR_ENV_NCHARSET_ID = OCI_ATTR_NCHARSET_ID; // ncharset id in env { Piece Information } OCI_PARAM_IN = $01; // in parameter OCI_PARAM_OUT = $02; // out parameter { LOB Buffering Flush Flags } OCI_LOB_BUFFER_FREE = 1; OCI_LOB_BUFFER_NOFREE = 2; { FILE open modes } OCI_FILE_READONLY = 1; // readonly mode open for FILE types { LOB open modes } OCI_LOB_READONLY = 1; // readonly mode open for ILOB types OCI_LOB_READWRITE = 2; // read write mode open for ILOBs { CHAR/NCHAR/VARCHAR2/NVARCHAR2/CLOB/NCLOB char set "form" information } SQLCS_IMPLICIT = 1; // for CHAR, VARCHAR2, CLOB w/o a specified set SQLCS_NCHAR = 2; // for NCHAR, NCHAR VARYING, NCLOB SQLCS_EXPLICIT = 3; // for CHAR, etc, with "CHARACTER SET ..." syntax SQLCS_FLEXIBLE = 4; // for PL/SQL "flexible" parameters SQLCS_LIT_NULL = 5; // for typecheck of NULL and empty_clob() lits {************************ OCIDesribeAny *************************} { Describe mode } OCI_OTYPE_NAME = 1; OCI_OTYPE_REF = 2; OCI_OTYPE_PTR = 3; { Object type } OCI_PTYPE_UNK = 0; // unknown OCI_PTYPE_TABLE = 1; // table OCI_PTYPE_VIEW = 2; // view OCI_PTYPE_PROC = 3; // procedure OCI_PTYPE_FUNC = 4; // function OCI_PTYPE_PKG = 5; // package OCI_PTYPE_TYPE = 6; // user-defined type OCI_PTYPE_SYN = 7; // synonym OCI_PTYPE_SEQ = 8; // sequence OCI_PTYPE_COL = 9; // column OCI_PTYPE_ARG = 10; // argument OCI_PTYPE_LIST = 11; // list OCI_PTYPE_TYPE_ATTR = 12; // user-defined type's attribute OCI_PTYPE_TYPE_COLL = 13; // collection type's element OCI_PTYPE_TYPE_METHOD = 14; // user-defined type's method OCI_PTYPE_TYPE_ARG = 15; // user-defined type method's argument OCI_PTYPE_TYPE_RESULT = 16; // user-defined type method's result { Proc/Func param type } OCI_TYPEPARAM_IN = 0; OCI_TYPEPARAM_OUT = 1; OCI_TYPEPARAM_INOUT = 2; { NLS environmet } OCI_NLS_CHARSET_MAXBYTESZ = 91; { enum OCIPinOpt } OCI_PIN_DEFAULT = 1; //* default pin option */ OCI_PIN_ANY = 3; //* pin any copy of the object */ OCI_PIN_RECENT = 4; //* pin recent copy of the object */ OCI_PIN_LATEST = 5; //* pin latest copy of the object */ { enum OCILockOpt } OCI_LOCK_NONE = 1; //* null (same as no lock) */ OCI_LOCK_X = 2; //* exclusive lock */ OCI_LOCK_X_NOWAIT = 3; //* exclusive lock, do not wait */ { OBJECT FREE OPTION } OCI_OBJECTFREE_FORCE =1; OCI_OBJECTFREE_NONULL=2; type PPointer = ^Pointer; TOCIInitialize = function(mode: ub4; ctxp: Pointer; malocfp: Pointer; ralocfp: Pointer; mfreefp: Pointer): sword; cdecl; TOCIEnvInit = function(var envhpp: POCIEnv; mode: ub4; xtramemsz: size_T; usrmempp: PPointer): sword; cdecl; TOCIEnvCreate = function(var envhpp: POCIEnv; mode: ub4; ctxp: Pointer; malocfp: Pointer; ralocfp: Pointer; mfreefp: Pointer; xtramemsz: size_T; usrmempp: PPointer): sword; cdecl; TOCIEnvNlsCreate = function(var envhpp: POCIEnv; mode: ub4; ctxp: Pointer; malocfp: Pointer; ralocfp: Pointer; mfreefp: Pointer; xtramemsz: size_T; usrmempp: PPointer; charset, ncharset: ub2): sword; cdecl; TOCIHandleAlloc = function(parenth: POCIHandle; var hndlpp: POCIHandle; atype: ub4; xtramem_sz: size_T; usrmempp: PPointer): sword; cdecl; TOCIServerAttach = function(srvhp: POCIServer; errhp: POCIError; dblink: text; dblink_len: sb4; mode: ub4): sword; cdecl; TOCIAttrSet = function(trgthndlp: POCIHandle; trghndltyp: ub4; attributep: Pointer; size: ub4; attrtype: ub4; errhp: POCIError):sword; cdecl; TOCISessionBegin = function(svchp: POCISvcCtx; errhp: POCIError; usrhp: POCISession; credt: ub4; mode: ub4):sword; cdecl; TOCISessionEnd = function(svchp: POCISvcCtx; errhp: POCIError; usrhp: POCISession; mode: ub4): sword; cdecl; TOCIServerDetach = function(srvhp: POCIServer; errhp: POCIError; mode: ub4): sword; cdecl; TOCIHandleFree = function(hndlp: Pointer; atype: ub4): sword; cdecl; TOCIErrorGet = function(hndlp: Pointer; recordno: ub4; sqlstate: text; var errcodep: sb4; bufp: text; bufsiz: ub4; atype: ub4): sword; cdecl; TOCIStmtPrepare = function(stmtp: POCIStmt; errhp: POCIError; stmt: text; stmt_len: ub4; language:ub4; mode: ub4):sword; cdecl; TOCIStmtExecute = function(svchp: POCISvcCtx; stmtp: POCIStmt; errhp: POCIError; iters: ub4; rowoff: ub4; snap_in: POCISnapshot; snap_out: POCISnapshot; mode: ub4): sword; cdecl; TOCIParamGet = function(hndlp: Pointer; htype: ub4; errhp: POCIError; var parmdpp: Pointer; pos: ub4): sword; cdecl; TOCIAttrGet = function(trgthndlp: POCIHandle; trghndltyp: ub4; attributep: Pointer; sizep: Pointer; attrtype: ub4; errhp: POCIError):sword; cdecl; TOCIStmtFetch = function(stmtp: POCIStmt; errhp: POCIError; nrows: ub4; orientation: ub2; mode: ub4): sword; cdecl; TOCIDefineByPos = function(stmtp: POCIStmt; var defnpp: POCIDefine; errhp: POCIError; position: ub4; valuep: Pointer; value_sz: sb4; dty: ub2; indp: Pointer; rlenp: Pointer; rcodep: Pointer; mode: ub4): sword; cdecl; TOCIDefineArrayOfStruct = function(defnpp: POCIDefine; errhp: POCIError; pvskip: ub4; indskip: ub4; rlskip: ub4; rcskip: ub4): sword; cdecl; TOCIBindByPos = function(stmtp: POCIStmt; var bindpp: POCIBind; errhp: POCIError; position: ub4; valuep: Pointer; value_sz: sb4; dty: ub2; indp: Pointer; alenp: Pointer; rcodep: Pointer; maxarr_len: ub4; curelep: Pointer; mode: ub4): sword; cdecl; TOCIBindByName = function(stmtp: POCIStmt; var bindpp: POCIBind; errhp: POCIError; placeholder: text; placeh_len: sb4; valuep: Pointer; value_sz: sb4; dty: ub2; indp: Pointer; alenp: Pointer; rcodep: Pointer; maxarr_len: ub4; curelep: Pointer; mode: ub4): sword; cdecl; TOCIBindDynamic = function(bindp: POCIBind; errhp: POCIError; ictxp: Pointer; icbfp: Pointer; octxp: Pointer; ocbfp: Pointer): sword; cdecl; (*---------------------------------OCIBindObject-------------------------------- This function sets up additional attributes which are required for a named data type (object) bind. Syntax ------------------------------------------------------------------------------*) TOCIBindObject = function(bindp: POCIBind; errhp: POCIError; const _type: POCIType; pgvpp: PPointer; pvszsp: pub4; indpp: PPointer; indszp: pub4): sword; cdecl; (*Comments This function sets up additional attributes which binding a named data type or a REF. An error will be returned if this function is called when the OCI environment has been initialized in non-object mode. This call takes as a paramter a type descriptor object (TDO) of datatype OCIType for the named data type being defined. The TDO can be retrieved with a call to OCITypeByName(). If the OCI_DATA_AT_EXEC mode was specified in ocibindn() or ocibindp(), the pointers to the IN buffers are obtained either using the callback icbfp registered in the OCIBindDynamic() call or by the OCIStmtSetPieceInfo() call. The buffers are dynamically allocated for the OUT data and the pointers to these buffers are returned either by calling ocbfp() registered by the OCIBindDynamic() or by setting the pointer to the buffer in the buffer passed in by OCIStmtSetPieceInfo() called when OCIStmtExecute() returned OCI_NEED_DATA. The memory of these client library- allocated buffers must be freed when not in use anymore by using the OCIObjectFreee() call. Parameters bindp ( IN/OUT) - the bind handle returned by the call to OCIBindByName() or OCIBindByPos(). errhp ( IN/OUT) - an error handle which can be passed to OCIErrorGet() for diagnostic information in the event of an error. type ( IN) - points to the TDO which describes the type of the program variable being bound. Retrieved by calling OCITypeByName(). pgvpp ( IN/OUT) - points to a pointer to the program variable buffer. For an array, pgvpp points to an array of pointers. When the bind variable is also an OUT variable, the OUT Named Data Type value or REF is allocated (unpickled) in the Object Cache, and a pointer to the value or REF is returned, At the end of execute, when all OUT values have been received, pgvpp points to an array of pointer(s) to these newly allocated named data types in the object cache. pgvpp is ignored if the OCI_DATA_AT_EXEC mode is set. Then the Named Data Type buffers are requested at runtime. For static array binds, skip factors may be specified using the OCIBindArrayOfStruct() call. The skip factors are used to compute the address of the next pointer to the value, the indicator structure and their sizes. pvszsp ( IN/OUT) - points to the size of the program variable. The size of the named data type is not required on input. For an array, pvszsp is an array of ub4s. On return, for OUT bind variables, this points to size(s) of the Named Data Types and REFs received. pvszsp is ignored if the OCI_DATA_AT_EXEC mode is set. Then the size of the buffer is taken at runtime. indpp ( IN/OUT) - points to a pointer to the program variable buffer containing the parallel indicator structure. For an array, points to an array of pointers. When the bind variable is also an OUT bind variable, memory is allocated in the object cache, to store the unpickled OUT indicator values. At the end of the execute when all OUT values have been received, indpp points to the pointer(s) to these newly allocated indicator structure(s). indpp is ignored if the OCI_DATA_AT_EXEC mode is set. Then the indicator is requested at runtime. indszp ( IN/OUT) - points to the size of the IN indicator structure program variable. For an array, it is an array of sb2s. On return for OUT bind variables, this points to size(s) of the received OUT indicator structures. indszp is ignored if the OCI_DATA_AT_EXEC mode is set. Then the indicator size is requested at runtime. Related Functions OCIAttrGet() *) TOCIDefineObject = function(defnpp:POCIDefine; errhp:POCIError; _type:POCIHandle; pgvpp:pointer; pvszsp:Pub4; indpp:pointer; indszp:Pub4):sword;cdecl; TOCITransStart = function(svchp: POCISvcCtx; errhp: POCIError; timeout: word; flags: ub4): sword; cdecl; TOCITransRollback = function(svchp:POCISvcCtx; errhp:POCIError; flags: ub4): sword; cdecl; TOCITransCommit = function(svchp: POCISvcCtx; errhp: POCIError; flags: ub4) :sword; cdecl; TOCITransDetach = function(svchp: POCISvcCtx; errhp: POCIError; flags: ub4) :sword; cdecl; TOCITransPrepare = function(svchp: POCISvcCtx; errhp: POCIError; flags: ub4) :sword; cdecl; TOCITransForget = function(svchp: POCISvcCtx; errhp: POCIError; flags: ub4) :sword; cdecl; TOCIDescribeAny = function(svchp: POCISvcCtx; errhp: POCIError; objptr: Pointer; objnm_len: ub4; objptr_typ: ub1; info_level: ub1; objtyp: ub1; dschp: POCIDescribe): sword; cdecl; TOCIBreak = function(svchp: POCISvcCtx; errhp:POCIError): sword; cdecl; TOCIReset = function(svchp: POCISvcCtx; errhp:POCIError): sword; cdecl; TOCIDescriptorAlloc = function(parenth: POCIEnv; var descpp: POCIDescriptor; htype: ub4; xtramem_sz: integer; usrmempp: Pointer): sword; cdecl; TOCIDescriptorFree = function(descp: Pointer; htype: ub4): sword; cdecl; TOCIDateTimeAssign = function(hndl: POCIEnv; err: POCIError; const from: POCIDateTime;_to: POCIDateTime): sword; cdecl; TOCIDateTimeCheck = function(hndl: POCIEnv; err: POCIError; const date: POCIDateTime; var valid: ub4): sword; cdecl; TOCIDateTimeCompare = function(hndl: POCIEnv; err: POCIError; const date1: POCIDateTime; const date2: POCIDateTime; var result: sword): sword; cdecl; TOCIDateTimeConvert = function(hndl: POCIEnv; err: POCIError; indate: POCIDateTime; outdate: POCIDateTime): sword; cdecl; TOCIDateTimeFromText= function(hndl: POCIEnv; err: POCIError; const date_str: text; d_str_length: size_t; const fmt: text; fmt_length: ub1; const lang_name: text; lang_length: size_t; date: POCIDateTime): sword; cdecl; TOCIDateTimeGetDate = function(hndl: POCIEnv; err: POCIError; const date: POCIDateTime; var year: sb2; var month: ub1; var day: ub1): sword; cdecl; TOCIDateTimeGetTime = function(hndl: POCIEnv; err: POCIError; datetime: POCIDateTime; var hour: ub1; var minute: ub1; var sec: ub1; var fsec: ub4): sword; cdecl; TOCIDateTimeGetTimeZoneOffset = function(hndl: POCIEnv; err: POCIError; const datetime: POCIDateTime; var hour: sb1; var minute: sb1): sword; cdecl; TOCIDateTimeSysTimeStamp = function(hndl: POCIEnv; err: POCIError; sys_date: POCIDateTime): sword; cdecl; TOCIDateTimeConstruct = function(hndl: POCIEnv; err: POCIError; datetime: POCIDateTime; year: sb2; month: ub1; day: ub1; hour: ub1; min: ub1; sec: ub1; fsec: ub4; timezone: text; timezone_length: size_t): sword; cdecl; TOCIDateTimeToText = function(hndl: POCIEnv; err: POCIError; const date: POCIDateTime; const fmt: text; fmt_length: ub1; fsprec: ub1; const lang_name: text; lang_length: size_t; var buf_size: ub4; buf: text): sword; cdecl; TOCIDateTimeGetTimeZoneName = function(hndl: POCIEnv; err: POCIError; datetime: POCIDateTime; var buf: ub1; var buflen: ub4): sword; cdecl; TOCILobAppend = function(svchp: POCISvcCtx; errhp: POCIError; dst_locp, src_locp: POCILobLocator): sword; cdecl; TOCILobAssign = function(svchp: POCISvcCtx; errhp: POCIError; src_locp: POCILobLocator; var dst_locpp: POCILobLocator): sword; cdecl; TOCILobClose = function(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator): sword; cdecl; TOCILobCopy = function(svchp: POCISvcCtx; errhp: POCIError; dst_locp: POCILobLocator; src_locp: POCILobLocator; amount: ub4; dst_offset: ub4; src_offset: ub4): sword; cdecl; TOCILobCreateTemporary = function(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; csid: ub2; csfrm: ub1; lobtype: ub1; cache: LongBool; duration: OCIDuration): sword; cdecl; TOCILobEnableBuffering = function(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator): sword; cdecl; TOCILobDisableBuffering = function(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator): sword; cdecl; TOCILobErase = function(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; var amount: ub4; offset: ub4): sword; cdecl; TOCILobFileExists = function(svchp: POCISvcCtx; errhp: POCIError; filep: POCILobLocator; var flag: Boolean): sword; cdecl; TOCILobFileGetName = function(envhp: POCIEnv; errhp: POCIError; filep: POCILobLocator; dir_alias: text; var d_length: ub2; filename: text; var f_length: ub2): sword; cdecl; TOCILobFileSetName = function(envhp: POCIEnv; errhp: POCIError; var filep: POCILobLocator; dir_alias: text; d_length: ub2; filename: text; f_length: ub2): sword; cdecl; TOCILobFlushBuffer = function(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; flag: ub4): sword; cdecl; TOCILobFreeTemporary = function(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator): sword; cdecl; TOCILobCharSetForm = function ( envhp: POCIEnv; errhp: POCIError; const locp: POCILobLocator; csfrm: pub1): sword; cdecl; TOCILobCharSetId = function( envhp: POCIEnv; errhp: POCIError; const locp: POCILobLocator; csid: pub2): sword; cdecl; TOCILobGetLength = function(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; var lenp: ub4): sword; cdecl; TOCILobIsOpen = function(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; var flag: LongBool): sword; cdecl; TOCILobIsTemporary = function(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; var is_temporary: LongBool): sword; cdecl; TOCILobLoadFromFile = function(svchp: POCISvcCtx; errhp: POCIError; dst_locp: POCILobLocator; src_locp: POCILobLocator; amount: ub4; dst_offset: ub4; src_offset: ub4): sword; cdecl; TOCILobLocatorIsInit = function(envhp: POCIEnv; errhp: POCIError; locp: POCILobLocator; var is_initialized: LongBool): sword; cdecl; TOCILobOpen = function(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; mode: ub1): sword; cdecl; TOCILobRead = function(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; var amtp: ub4; offset: ub4; bufp: Pointer; bufl: ub4; ctxp: Pointer; cbfp: Pointer; csid: ub2; csfrm: ub1): sword; cdecl; TOCILobTrim = function(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; newlen: ub4): sword; cdecl; TOCILobWrite = function(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; var amtp: ub4; offset: ub4; bufp: Pointer; bufl: ub4; piece: ub1; ctxp: Pointer; cbfp: Pointer; csid: ub2; csfrm: ub1): sword; cdecl; TOCIStmtGetPieceInfo = function(stmtp: POCIStmt; errhp: POCIError; var hndlpp: Pointer; var typep: ub4; var in_outp: ub1; var iterp: ub4; var idxp: ub4; var piecep: ub1): sword; cdecl; TOCIStmtSetPieceInfo = function(handle: Pointer; typep: ub4; errhp: POCIError; buf: Pointer; var alenp: ub4; piece: ub1; indp: Pointer; var rcodep: ub2): sword; cdecl; TOCIPasswordChange = function(svchp: POCISvcCtx; errhp: POCIError; user_name: text; usernm_len: ub4; opasswd: text; opasswd_len: ub4; npasswd: text; npasswd_len: sb4; mode: ub4): sword; cdecl; TOCIServerVersion = function(hndlp: POCIHandle; errhp: POCIError; bufp: text; bufsz: ub4; hndltype: ub1): sword; cdecl; TOCIServerRelease = function(hndlp: POCIHandle; errhp: POCIError; bufp: text; bufsz: ub4; hndltype: ub1; version:pointer): sword; cdecl; TOCIResultSetToStmt = function(rsetdp: POCIHandle; errhp: POCIError): sword; cdecl; TOCINlsNumericInfoGet = function(envhp: POCIEnv; errhp: POCIError; val: psb4; item: ub2): sword; cdecl; TOCIClientVersion = procedure(major_version, minor_version, update_num, patch_num, port_update_num: psword); cdecl; (***************************************************************************** * NUMBER/FLOAT/DECIMAL TYPE * *****************************************************************************) const OCI_NUMBER_SIZE = 22; type POCINumberPart = ^TOCINumberPart; TOCINumberPart = array[1..OCI_NUMBER_SIZE] of ub1; (* * OCINumber - OCI Number mapping in c * * The OTS types: NUMBER, NUMERIC, INT, SHORTINT, REAL, DOUBLE PRECISION, * FLOAT and DECIMAL are represented by OCINumber. * The contents of OCINumber is opaque to clients. * * For binding variables of type OCINumber in OCI calls (OCIBindByName(), * OCIBindByPos(), and OCIDefineByPos()) use the type code SQLT_VNU. * * EXAMPLE The following example shows how to manipulate an attribute of type oracle number. struct person { OCINumber sal; }; typedef struct person person; OCIError *err; person* joe; person* tom; person* debbie; OCINumber *joesal; OCINumber *tomsal; OCINumber *debsal; sword status; int inum; double dnum; OCINumber ornum; char buffer[21]; ub4 buflen; sword result; /o See oci.h for an example of how to initialize OCIError. o For this example, assume the OCIEnv and OCIError has been o initialized. o/ /o Pin joe, tom and debbie person objects in the object cache. See ori.h o for an example on pinning objects. For this example, assume that o joe, tom and debbie are pointing to pinned objects. o/ joesal = &joe->sal; tomsal = &tom->sal; debsal = &debbie->sal; /o initialize joe's salary to be $12,000 o/ inum = 12000; status = OCINumberFromInt(err, &inum, sizeof(inum), OCI_NUMBER_SIGNED, joesal); if (status != OCI_SUCCESS) /o goto to handle error from OCINumberFromInt o/; /o initialize tom's salary to be same as joe o/ OCINumberAssign(err, joesal, tomsal); /o initialize debbie's salary to be 20% more than joe's o/ dnum = 1.2; status = OCINumberFromReal(err, &dnum, sizeof(double), &ornum); if (status != OCI_SUCCESS) /o goto to handle error from OCINumberFromReal o/; status = OCINumberMul(err, joesal, &ornum, debsal); if (status != OCI_SUCCESS) /o goto to handle error from OCINumberMul o/; /o give tom a 50% raise o/ dnum = 1.5; status = OCINumberFromReal(err, &dnum, sizeof(double), &ornum); if (status != OCI_SUCCESS) /o goto to handle error from OCINumberFromReal o/; status = OCINumberMul(err, tomsal, &ornum, tomsal); if (status != OCI_SUCCESS) /o goto to handle error from OCINumberMul o/; /o double joe's salary o/ status = OCINumberAdd(err, joesal, joesal, joesal); if (status != OCI_SUCCESS) /o goto to handle error from OCINumberAdd o/; /o get joe's salary in integer o/ status = OCINumberToInt(err, joesal, sizeof(inum), OCI_NUMBER_SIGNED, &inum); if (status != OCI_SUCCESS)/o goto to handle error from OCINumberToInt o/; /o inum is set to 24000 o/ /o get debbie's salary in double o/ status = OCINumberToReal(err, debsal, sizeof(dnum), &dnum); if (status != OCI_SUCCESS)/o goto to handle error from OCINumberToReal o/; /o dnum is set to 14400 o/ /o print tom's salary as DEM0001`8000.00 o/ buflen = sizeof(buffer); status = OCINumberToText(err, tomsal, "C0999G9999D99", 13, "NLS_NUMERIC_CHARACTERS='.`' NLS_ISO_CURRENCY='Germany'", 54, &buflen, buffer); if (status != OCI_SUCCESS)/o goto to handle error from OCINumberToText o/; printf("tom's salary = %s\n", buffer); /o compare joe and tom's salary o/ status = OCINumberCmp(err, joesal, tomsal, &result); if (status != OCI_SUCCESS) /o goto to handle error from OCINumberCmp o/; /o result is positive o/ /o read debbie's new salary from string o/ status = OCINumberFromText(err, "48`000.00", 9, "99G999D99", 9, "NLS_NUMERIC_CHARACTERS='.`'", 27, debsal); if (status != OCI_SUCCESS) /o goto to handle error from OCINumberFromText o/; /o debbie's salary is now 48000.00 o/ *) (*----------------------------- OCINumberInc --------------------------------*) TOCINumberInc = function(err: POCIError; number: POCINumber): sword; cdecl; (* NAME: OCINumberInc - OCINumber INCrement numbers PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number (IN/OUT) a positive Oracle number to be incremented DESCRIPTION: Increment Oracle number in place. It is assumed that the input is an integer between 0 and 100^21-2. If the is input too large, it will be treated as 0 - the result will be an Oracle number 1. If the input is not a positive integer, the result will be unpredictable. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if any of the number arguments is null *) (*----------------------------- OCINumberDec --------------------------------*) TOCINumberDec = function(err: POCIError; number: POCINumber): sword; cdecl; (* NAME: OCINumberDec - OCINumber DECrement numbers PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number (IN/OUT) - a positive Oracle number to be decremented DESCRIPTION: Decrement Oracle number in place. It is assumed that the input is an integer between 1 and 100^21-2. If the input is too large, it will be treated as 1 - the result will be an Oracle number 0. If the input is not a positive integer, the result will be unpredictable. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if any of the number arguments is null *) (*-------------------------- OCINumberSetZero -------------------------------*) TOCINumberSetZero = procedure(err: POCIError; number: POCINumber); cdecl; (* NAME: OCINumberSetZero - OCINumber Set number to Zero value PARAMETERS: err (IN/OUT) - pointer to OCI error handle num (OUT) - set to zero value DESCRIPTION: Initialize the given number to value 0. *) (*--------------------------- OCINumberSetPi --------------------------------*) TOCINumberSetPi = procedure(err: POCIError; number: POCINumber); cdecl; (* NAME: OCINumberSetPi - OCINumber Set number to Pi err (IN/OUT) - pointer to OCI error handle num (OUT) - set to zero value DESCRIPTION: Initialize the given number to value Pi. *) (*----------------------------- OCINumberAdd --------------------------------*) TOCINumberAdd = function(err: POCIError; const number1: POCINumber; const number2: POCINumber; _result: POCINumber): sword; cdecl; (* NAME: OCINumberAdd - OCINumber ADD numbers PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number1, number2 (IN) - numbers to be added result (OUT) - result of adding 'number1' with 'number2' DESCRIPTION: Add 'number1' with 'number2' and return result in 'result'. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if any of the number arguments is null *) (*----------------------------- OCINumberSub --------------------------------*) TOCINumberSub = function(err: POCIError; const number1: POCINumber; const number2: POCINumber; _result: POCINumber): sword; cdecl; (* NAME: OCINumberSub - OCINumber SUBtract numbers PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number1, number2 (IN) - 'number2' subtracted from 'number1' result (OUT) - subtraction result DESCRIPTION: Subtract 'number2' from 'number1' and return result in 'result'. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if any of the number arguments is null *) (*----------------------------- OCINumberMul --------------------------------*) TOCINumberMul = function(err: POCIError; const number1: POCINumber; const number2: POCINumber; _result: POCINumber): sword; cdecl; (* NAME: OCINumberMul - OCINumber MULtiply numbers PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number1, number2 (IN) - numbers to be multiplied result (OUT) - multiplication result DESCRIPTION: Multiply 'number1' with 'number2' and return result in 'result'. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if any of the number arguments is null *) (*----------------------------- OCINumberDiv --------------------------------*) TOCINumberDiv = function(err: POCIError; const number1: POCINumber; const number2: POCINumber; _result: POCINumber): sword; cdecl; (* NAME: OCINumberDiv - OCINumber DIVide numbers PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number1 (IN) - pointer to the numerator number2 (IN) - pointer to the denominator result (OUT) - division result DESCRIPTION: Divide 'number1' by 'number2' and return result in 'result'. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if any of the number arguments is null underflow errorr overflow errorr divide by zero errorr *) (*----------------------------- OCINumberMod --------------------------------*) TOCINumberMod = function(err: POCIError; const number1: POCINumber; const number2: POCINumber; _result: POCINumber): sword; cdecl; (* NAME: OCINumberMod - OCINumber MODulous PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number1 (IN) - pointer to the numerator number2 (IN) - pointer to the denominator result (OUT) - remainder of the result DESCRIPTION: Finds the remainder of the division of two Oracle numbers. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if any of the number arguments is null divide by zero errorr *) (*------------------------ OCINumberIntPower --------------------------------*) TOCINumberIntPower = function(err: POCIError; const number1: POCINumber; const number2: POCINumber; _result: POCINumber): sword; cdecl; (* NAME: OCINumberIntPower - OCINumber takes an arbitary base to an arbitary integer PoWeR PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). base (IN) - base of the exponentiation exp (IN) - exponent to which the base is to be raised result (OUT) - output of exponentiation DESCRIPTION: Takes an arbitary base to an arbitary integer power. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if any of the number arguments is null *) (*-------------------------- OCINumberShift ---------------------------------*) TOCINumberShift = function(err: POCIError; const number: POCINumber; const nDig: sword; _result: POCINumber): sword; cdecl; (* NAME: OCINumberShift - OCINumber multiplies by a power of 10. PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number (IN) - Oracle Number to be shifted. nDig (IN) - number of decimal places to shift. result (OUT) - shift result. DESCRIPTION: Multiplies number by 10^NDig and sets product to the result. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if any of the number arguments is null *) (*----------------------------- OCINumberNeg --------------------------------*) TOCINumberNeg = function(err: POCIError; const number: POCINumber; _result: POCINumber): sword; cdecl; (* NAME: OCINumberNeg - OCINumber NEGate number PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number (IN) - number to be negated result (OUT) - will contain negated value of 'number' DESCRIPTION: Negates an Oracle number. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if any of the number arguments is null *) (*------------------------- OCINumberToText ---------------------------------*) Poratext = PAnsiChar; PPoratext = PPAnsiChar; TOCINumberToText = function(err: POCIError; const number: POCINumber; const fmt: Poratext; fmt_length: ub4; const nls_params: Poratext; nls_p_length: ub4; buf_size: pub4; buf: poratext): sword; cdecl; (* NAME: OCINumberToText - OCINumber convert number TO String PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number (IN) - Oracle number to be converted fmt (IN) - conversion format fmt_length (IN) - length of the 'fmt' parameter nls_params (IN) - nls format specification, if null string i.e. (oratext * )0, then the default parameters for the session is used nls_p_length (IN) - length of the 'nls_params' parameter buf_size (IN/OUT) - size of the buffer must be passed as input by the caller, this function will return the length of the resulting string in bytes via this parameter. The length does not include the terminating null ('\0'). buf (OUT) - buffer into which the converted string is placed. The resulting string is null terminated. DESCRIPTION: Converts the given number to a character string according to the specified format. Refer to "TO_NUMBER" conversion function described in "Oracle SQL Language Reference Manual" for a description of format and NLS parameters. The converted number string is stored in the buffer 'buf', up to a max of '*buf_size' bytes. Length of the resulting string is returned via 'buf_size'. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if 'number' or 'buf' is null buffer too small invalid format invalid nls format number to text translation for the given format causes overflow *) (*-------------------------- OCINumberFromText ------------------------------*) TOCINumberFromText = function(err: POCIError; const str: poratext; str_length: ub4; const fmt: poratext; fmt_length: ub4; const nls_params: poratext; nls_p_length: ub4; number: POCINumber): sword; cdecl; (* NAME: OCINumberFromText - OCINumber convert String TO Number PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). str (IN) - input string to be converted to Oracle number str_length (IN) - size of the input string fmt (IN) - conversion format fmt_length (IN) - length of the 'fmt' parameter nls_params (IN) - nls format specification, if null string i.e. (oratext * )0, then the default parameters for the session is used nls_p_length (IN) - length of the 'nls_params' parameter number (OUT) - given string converted to number DESCRIPTION: Converts the given string to a number according to the specified format. Refer to "TO_NUMBER" conversion function described in "Oracle SQL Language Reference Manual" for a description of format and NLS parameters. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if 'number' or 'str' is null 'str_length' is 0 invalid format invalid nls format invalid input string *) (*-------------------------- OCINumberToInt ---------------------------------*) const OCI_NUMBER_UNSIGNED = 0; // Unsigned type -- ubX OCI_NUMBER_SIGNED = 2; // Signed type -- sbX type TOCINumberToInt = function(err: POCIError; const number: POCINumber; rsl_length: uword; rsl_flag: uword; rsl: Pointer): sword; cdecl; (* NAME: OCINumberToInt - OCINumber convert number TO Integer PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number (IN) - number to be converted rsl_length (IN) - size of the desired result rsl_s_flag (IN) - flag denoting the desired sign of the output; valid values are OCI_NUMBER_UNSIGNED, OCI_NUMBER_SIGNED rsl (OUT) - pointer to space for the result DESCRIPTION: Native type conversion function. Converts the given Oracle number into an xbx (e.g. ub2, ub4, sb2 etc.) RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if 'number' or 'rsl' is null integer value of 'number' is too big -- overflow integer value of 'number' is too small -- underflow invalid sign flag value ('rsl_s_flag') *) (*--------------------------- OCINumberFromInt ------------------------------*) TOCINumberFromInt = function(err: POCIError; const inum: Pointer; inum_length: uword; inum_s_flag: uword; number: POCINumber): sword; cdecl; (* NAME: OCINumberFromInt - OCINumber convert Integer TO Number PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). inum (IN) - pointer to the integer to be converted inum_length (IN) - size of the integer inum_s_flag (IN) - flag that designates the sign of the integer; valid values are OCI_NUMBER_UNSIGNED, OCI_NUMBER_SIGNED number (OUT) - given integer converted to Oracle number DESCRIPTION: Native type conversion function. Converts any Oracle standard machine-native integer type (xbx) to an Oracle number. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if 'number' or 'inum' is null integer too BIG -- the number is too large to fit into an Oracle number invalid sign flag value ('inum_s_flag') *) (*------------------------- OCINumberToReal ---------------------------------*) TOCINumberToReal = function(err: POCIError; const number: POCINumber; rsl_length: uword; rsl: Pointer): sword; cdecl; (* NAME: OCINumberToReal - OCINumber convert number TO Real PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number (IN) - number to be converted rsl_length (IN) - is the size of the desired result, sizeof( float | double | long double) rsl (OUT) - pointer to space for storing the result DESCRIPTION: Native type conversion function. Converts an Oracle number into a machine-native real type. This function only converts numbers up to LDBL_DIG, DBL_DIG, or FLT_DIG digits of precision and removes trailing zeroes. The above constants are defined in float.h RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if 'number' or 'rsl' is null 'rsl_length' is 0 *) (*------------------------- OCINumberToRealArray ----------------------------*) TOCINumberToRealArray = function(err: POCIError; const number: PPOCINumber; elems: uword; rsl_length: uword; rsl: Pointer): sword; cdecl; (* NAME: OCINumberToRealArray - OCINumber convert array of numbers TO Real PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number (IN) - Pointer to array of number to be converted elems (IN) - Upper bound of number array rsl_length (IN) - is the size of the desired result, sizeof( float | double | long double) rsl (OUT) - pointer to array of space for storing the result DESCRIPTION: Native type conversion function. Converts an Oracle number into a machine-native real type. This function only converts numbers up to LDBL_DIG, DBL_DIG, or FLT_DIG digits of precision and removes trailing zeroes. The above constants are defined in float.h RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if 'number' or 'rsl' is null 'rsl_length' is 0 *) (*-------------------------- OCINumberFromReal ------------------------------*) TOCINumberFromReal = function(err: POCIError; const rnum: Pointer; rnum_length: uword; number: POCINumber): sword; cdecl; (* NAME: OCINumberFromReal - OCINumber convert Real TO Number PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). rnum (IN) - pointer to the floating point number to be converted rnum_length (IN) - size of the desired result, i.e. sizeof({float | double | long double}) number (OUT) - given float converted to Oracle number DESCRIPTION: Native type conversion function. Converts a machine-native floating point type to an Oracle number. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if 'number' or 'rnum' is null 'rnum_length' is 0 *) (*----------------------------- OCINumberCmp --------------------------------*) TOCINumberCmp = function(err: POCIError; const number1: POCINumber; const number2: POCINumber; _result: psword): sword; cdecl; (* NAME: OCINumberCmp - OCINumber CoMPare numbers PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number1, number2 (IN) - numbers to be compared result (OUT) - 0 if equal, negative if number1 < number2, positive if number1 > number2 DESCRIPTION: The function OCINumberCmp compares two numbers. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if 'number1' or 'number2' or 'result' is null *) (*---------------------------- OCINumberSign --------------------------------*) TOCINumberSign = function(err: POCIError; const number: POCINumber; _result: psword): sword; cdecl; (* NAME: OCINumberSign - OCINumber obtains SiGN of an Oracle number PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number (IN) - number whose sign is returned result (OUT) - 0 if number == 0, -1 if number < 0, 1 if number > 0 DESCRIPTION: Obtains sign of an Oracle number RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if 'number' or 'result' is null *) (*---------------------------- OCINumberIsZero ------------------------------*) TOCINumberIsZero = function(err: POCIError; const number: POCINumber; _Result: pboolean): sword; cdecl; (* NAME: OCINumberIsZero - OCINumber comparison with ZERo PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number (IN) - numbers to be compared result (OUT) - set to TRUE if equal to zero else FALSE DESCRIPTION: Test if the given number is equal to zero. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if 'number' or 'result' is null *) (*---------------------------- OCINumberIsInt -------------------------------*) TOCINumberIsInt = function(err: POCIError; const number: POCINumber; _result: Pboolean): sword; cdecl; (* NAME: OCINumberIsInt - OCINumber Is Integer value. PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number (IN) - number to be tested result (OUT) - set to TRUE if integer value else FALSE DESCRIPTION: Test if the given number is an integer value. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if 'number' or 'result' is null *) (*-------------------------- OCINumberAssign --------------------------------*) TOCINumberAssign = function(err: POCIError; const from: POCINumber; _to: POCINumber): sword; cdecl; (* NAME: OCINumberAssign - OCINumber ASsiGn number PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). from (IN) - number to be assigned to (OUT) - number copied into DESCRIPTION: Assign number 'from' to 'to'. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if 'from' or 'to' is null *) (*----------------------------- OCINumberAbs --------------------------------*) TOCINumberAbs = function(err: POCIError; const number: POCINumber; _result: POCINumber): sword; cdecl; (* NAME: OCINumberAbs - OCINumber compute ABSolute value PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number (IN) - input number result (OUT) - output which will contain the absolue value of the input number DESCRIPTION: Computes the absolute value of an Oracle number. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if any of the number arguments is null *) (*---------------------------- OCINumberCeil --------------------------------*) TOCINumberCeil = function(err: POCIError; const number: POCINumber; _result: POCINumber): sword; cdecl; (* NAME: OCINumberCeil - OCINumber compute the CEiL value of an Oracle number PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number (IN) - input number result (OUT) - output which will contain the ceil value of the input number DESCRIPTION: Computes the ceil value of an Oracle number. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if any of the number arguments is null *) (*--------------------------- OCINumberFloor --------------------------------*) TOCINumberFloor = function(err: POCIError; const number: POCINumber; _result: POCINumber): sword; cdecl; (* NAME: OCINumberFloor - OCINumber compute the FLooR value of an Oracle number PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number (IN) - input number result (OUT) - output which will contain the floor value of the input number DESCRIPTION: Computes the floor value of an Oracle number. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if any of the number arguments is null *) (*----------------------------- OCINumberSqrt -------------------------------*) TOCINumberSqrt = function(err: POCIError; const number: POCINumber; _result: POCINumber): sword; cdecl; (* NAME: OCINumberSqrt - OCINumber compute the SQuare Root of an Oracle number PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number (IN) - input number result (OUT) - output which will contain the square root of the input number DESCRIPTION: Computes the square root of an Oracle number. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if any of the number arguments is null 'number' is negative *) (*--------------------------- OCINumberTrunc --------------------------------*) TOCINumberTrunc = function(err: POCIError; const number: POCINumber; _result: POCINumber): sword; cdecl; (* NAME: OCINumberTrunc - OCINumber TRUncate an Oracle number at a specified decimal place PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number (IN) - input number decplace (IN) - number of decimal digits to the right of the decimal point to truncate at. Negative values are allowed. result (OUT) - output of truncation DESCRIPTION: Truncate an Oracle number at a specified decimal place RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if any of the number arguments is null *) (*----------------------------- OCINumberPower ------------------------------*) TOCINumberPower = function(err: POCIError; const base: POCINumber; const number: POCINumber; _result: POCINumber): sword; cdecl; (* NAME: OCINumberPower - OCINumber takes an arbitary Base to an arbitary Power PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). base (IN) - base of the exponentiation number (IN) - exponent to which the base is to be raised result (OUT) - output of exponentiation DESCRIPTION: Takes an arbitary base to an arbitary power. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if any of the number arguments is null *) (*--------------------------- OCINumberRound --------------------------------*) TOCINumberRound = function(err: POCIError; const number: POCINumber; decplace: sword; _result: POCINumber): sword; cdecl; (* NAME: OCINumberRound - OCINumber ROUnds an Oracle number to a specified decimal place PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number (IN) - round this number and return result in 'result' decplace (IN) - number of decimal digits to the right of the decimal point to round to. Negative values are allowed. result (OUT) - output of rounding DESCRIPTION: Rounds an Oracle number to a specified decimal place RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if any of the number arguments is null *) (*--------------------------- OCINumberPrec ---------------------------------*) TOCINumberPrec = function(err: POCIError; const number: POCINumber; nDigs: sword; _result: POCINumber): sword; cdecl; (* NAME: OCINumberPrec - Rounds an Oracle number to a specified number of decimal digits. PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number (IN) - number for which to set precision. nDig (IN) - number of decimal digits desired in the result. result (OUT) - result. DESCRIPTION: Performs a floating point round with respect to the number of digits. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if any of the number arguments is null *) (*----------------------------- OCINumberSin --------------------------------*) TOCINumberSin = function(err: POCIError; const number: POCINumber; _result: POCINumber): sword; cdecl; (* NAME: OCINumberSin - OCINumber takes the SINe of an Oracle number PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number (IN) - argument of the sine in radians result (OUT) - result of the sine DESCRIPTION: Takes the sine in radians of an Oracle number. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if any of the number arguments is null *) (*-------------------------- OCINumberArcSin --------------------------------*) TOCINumberArcSin = function(err: POCIError; const number: POCINumber; _result: POCINumber): sword; cdecl; (* NAME: OCINumberArcSin - OCINumber takes the Arc SINe of an Oracle number PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number (IN) - argument of the arc sine result (OUT) - result of the arc sine in radians DESCRIPTION: Takes the arc sine in radians of an Oracle number. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if any of the number arguments is null 'number' is < -1 or 'number' is > 1. *) (*-------------------------- OCINumberHypSin --------------------------------*) TOCINumberHypSin = function(err: POCIError; const number: POCINumber; _result: POCINumber): sword; cdecl; (* NAME: OCINumberHypSin - OCINumber takes the SiNe Hyperbolic of an Oracle number PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number (IN) - argument of the sine hyperbolic result (OUT) - result of the sine hyperbolic DESCRIPTION: Takes the hyperbolic sine of an Oracle number. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if any of the number arguments is null NOTES: An Oracle number overflow causes an unpredictable result value. *) (*----------------------------- OCINumberCos --------------------------------*) TOCINumberCos = function(err: POCIError; const number: POCINumber; _result: POCINumber): sword; cdecl; (* NAME: OCINumberCos - OCINumber takes the COSine of an Oracle number PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number (IN) - argument of the cosine in radians result (OUT) - result of the cosine DESCRIPTION: Takes the cosine in radians of an Oracle number. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if any of the number arguments is null *) (*-------------------------- OCINumberArcCos --------------------------------*) TOCINumberArcCos = function(err: POCIError; const number: POCINumber; _result: POCINumber): sword; cdecl; (* NAME: OCINumberArcCos - OCINumber takes the Arc COSine of an Oracle number PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number (IN) - argument of the arc cosine result (OUT) - result of the arc cosine in radians DESCRIPTION: Takes the arc cosine in radians of an Oracle number. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if any of the number arguments is null 'number' is < -1 or 'number' is > 1. *) (*-------------------------- OCINumberHypCos --------------------------------*) TOCINumberHypCos = function(err: POCIError; const number: POCINumber; _result: POCINumber): sword; cdecl; (* NAME: OCINumberHypCos - OCINumber takes the CoSine Hyperbolic of an Oracle number PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number (IN) - argument of the cosine hyperbolic result (OUT) - result of the cosine hyperbolic DESCRIPTION: Takes the hyperbolic cosine of an Oracle number. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if any of the number arguments is null NOTES: An Oracle number overflow causes an unpredictable result value. *) (*----------------------------- OCINumberTan --------------------------------*) TOCINumberTan = function(err: POCIError; const number: POCINumber; _result: POCINumber): sword; cdecl; (* NAME: OCINumberTan - OCINumber takes the TANgent of an Oracle number PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number (IN) - argument of the tangent in radians result (OUT) - result of the tangent DESCRIPTION: Takes the tangent in radians of an Oracle number. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if any of the number arguments is null *) (*-------------------------- OCINumberArcTan --------------------------------*) TOCINumberArcTan = function(err: POCIError; const number: POCINumber; _result: POCINumber): sword; cdecl; (* NAME: OCINumberArcTan - OCINumber takes the Arc TANgent of an Oracle number PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number (IN) - argument of the arc tangent result (OUT) - result of the arc tangent in radians DESCRIPTION: Takes the arc tangent in radians of an Oracle number. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if any of the number arguments is null *) (*------------------------ OCINumberArcTan2 ---------------------------------*) TOCINumberArcTan2 = function(err: POCIError; const number1: POCINumber; const number2: POCINumber; _result: POCINumber): sword; cdecl; (* NAME: OCINumberArcTan2 - OCINumber takes the ATan2 of 2 Oracle numbers PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number1 (IN) - first argument of atan2(y,x) function which corresponds to 'y' parameter in the function number2 (IN) - second argument of atan2(y,x) function which corresponds to 'x' parameter in the function result (OUT) - result of the atan2() in radians DESCRIPTION: Takes the atan2(number1, number2). RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if any of the number arguments is null 'number2' is 0 *) (*----------------------------- OCINumberHypTan -----------------------------*) TOCINumberHypTan = function(err: POCIError; const number: POCINumber; _result: POCINumber): sword; cdecl; (* NAME: OCINumberHypTan - OCINumber takes the TaNgent Hyperbolic of an Oracle number PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number (IN) - argument of the tangent hyperbolic result (OUT) - result of the tangent hyperbolic DESCRIPTION: Takes the hyperbolic tangent of an Oracle number. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if any of the number arguments is null NOTES: An Oracle number overflow causes an unpredictable result value. *) (*--------------------------- OCINumberExp ----------------------------------*) TOCINumberExp = function(err: POCIError; const number: POCINumber; _result: POCINumber): sword; cdecl; (* NAME: OCINumberExp - OCINumber EXPonential PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number (IN) - e raised to this Oracle number power result (OUT) - output of exponentiation DESCRIPTION: Raises e to the specified Oracle number power RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if any of the number arguments is null *) (*----------------------------- OCINumberLn ---------------------------------*) TOCINumberLn = function(err: POCIError; const number: POCINumber; _result: POCINumber): sword; cdecl; (* NAME: OCINumberLn - OCINumber Logarithm Natural PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). number (IN) - logarithm of this number is computed result (OUT) - logarithm result DESCRIPTION: Takes the logarithm of the given Oracle number with respect to the given base. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if any of the number arguments is null 'number' is <= 0 *) (*----------------------------- OCINumberLog --------------------------------*) TOCINumberLog = function(err: POCIError; const base: POCINumber; const number: POCINumber; _result: POCINumber): sword; cdecl; (* NAME: OCINumberLog - OCINumber LOGarithm any base PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). base (IN) - base of the logarithm number (IN) - opearnd result (OUT) - logarithm result DESCRIPTION: Takes the logarithm with the specified base of an Oracle number. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if any of the number arguments is null 'number' is <= 0 'base' is <= 0 *) (***************************************************************************** * ORACLE DATE TYPE * *****************************************************************************) POCITime = ^TOCITime; TOCITime = record OCITimeHH: ub1; // hours; range is 0 <= hours <=23 OCITimeMI: ub1; // minutes; range is 0 <= minutes <= 59 OCITimeSS: ub1; // seconds; range is 0 <= seconds <= 59 end; (* * OCITime - OCI TiMe portion of date * * This structure should be treated as an opaque structure as the format * of this structure may change. Use OCIDateGetTime/OCIDateSetTime * to manipulate time portion of OCIDate. *) POCIDate = ^TOCIDate; TOCIDate = record OCIDateYYYY: sb2; // gregorian year; range is -4712 <= year <= 9999 OCIDateMM: ub1; // month; range is 1 <= month < 12 OCIDateDD: ub1; // day; range is 1 <= day <= 31 OCIDateTime: TOCITime; // time end; (* * OCIDate - OCI oracle Date representation in C * * OCIDate represents the C mapping of Oracle date. * * This structure should be treated as an opaque structure as the format * of this structure may change. Use OCIDateGetDate/OCIDateSetDate * to access/initialize OCIDate. * * For binding variables of type OCIDate in OCI calls (OCIBindByName(), * OCIBindByPos(), and OCIDefineByPos()) use the type code SQLT_ODT. *) (* EXAMPLE The following example shows how to manipulate an attribute of type oracle date. #define FMT "Month dd, YYYY, HH:MI A.M." #define LANG "American" struct person { OCIDate start_date; }; typedef struct person person; OCIError *err; person *joe; sword status; /o error status o/ /o See oci.h for an example of how to initialize OCIError. o For this example, assume the OCIEnv and OCIError has been o initialized. o/ /o Pin joe person object in the object cache. See ori.h o for an example on pinning objects. For this example, assume that o joe is pointing to the pinned object. o/ /o set the start date of joe o/ OCIDateSetTime(&joe->start_date, 8, 0, 0); OCIDateSetDate(&joe->start_date, 1990, 10, 5); /o check if the date is valid o/ uword invalid; if (OCIDateCheck(err, &joe->start_date, &invalid) != OCI_SUCCESS) /o error handling code o/ if (invalid) /o error handling code o/ /o convert date for display purposes o/ char str[100]; ub4 strlen = sizeof(str); if (OCIDateToText(err, &joe->start_date, FMT, sizeof(FMT)-1, LANG, sizeof(LANG)-1, &strlen, str) != OCI_SUCCESS) /o error handling code o/ *) (*--------------------------- OCIDateGetTime --------------------------------*/ /* void OCIDateGetTime(/o_ const OCIDate *date, ub1 *hour, ub1 *min, ub1 *sec _o/); */ #define OCIDateGetTime(date, hour, min, sec) \ { \ *hour = (date)->OCIDateTime.OCITimeHH; \ *min = (date)->OCIDateTime.OCITimeMI; \ *sec = (date)->OCIDateTime.OCITimeSS; \ } /* NAME: OCIDateGetTime - OCIDate Get Time portion of date PARAMETERS: date (IN) - Oracle date whose time data is retrieved hour (OUT) - hour value returned min (OUT) - minute value returned sec (OUT) - second value returned DESCRIPTION: Return time inforamtion stored in the given date. The time information returned is: hour, minute and seconds. RETURNS: NONE */ /*--------------------------- OCIDateGetDate --------------------------------*/ /* void OCIDateGetDate(/o_ const OCIDate *date, sb2 *year, ub1 *month, ub1 *day _o/); */ #define OCIDateGetDate(date, year, month, day) \ { \ *year = (date)->OCIDateYYYY; \ *month = (date)->OCIDateMM; \ *day = (date)->OCIDateDD; \ } /* NAME: OCIDateGetDate - OCIDate Get Date (year, month, day) portion of date PARAMETERS: date (IN) - Oracle date whose year, month, day data is retrieved year (OUT) - year value returned month (OUT) - month value returned day (OUT) - day value returned DESCRIPTION: Return year, month, day inforamtion stored in the given date. RETURNS: NONE */ /*--------------------------- OCIDateSetTime --------------------------------*/ /* void OCIDateSetTime(/o_ OCIDate *date, ub1 hour, ub1 min, ub1 sec _o/); */ #define OCIDateSetTime(date, hour, min, sec) \ { \ (date)->OCIDateTime.OCITimeHH = hour; \ (date)->OCIDateTime.OCITimeMI = min; \ (date)->OCIDateTime.OCITimeSS = sec; \ } /* NAME: OCIDateSetTime - OCIDate Set Time portion of date PARAMETERS: date (OUT) - Oracle date whose time data is set hour (IN) - hour value to be set min (IN) - minute value to be set sec (IN) - second value to be set DESCRIPTION: Set the date with the given time inforamtion. RETURNS: NONE */ /*--------------------------- OCIDateSetDate --------------------------------*/ /* void OCIDateSetDate(/o_ OCIDate *date, sb2 year, ub1 month, ub1 day _o/); */ #define OCIDateSetDate(date, year, month, day) \ { \ (date)->OCIDateYYYY = year; \ (date)->OCIDateMM = month; \ (date)->OCIDateDD = day; \ } /* NAME: OCIDateSetDate - OCIDate Set Date (year, month, day) portion of date PARAMETERS: date (IN) - Oracle date whose year, month, day data is set year (OUT) - year value to be set month (OUT) - month value to be set day (OUT) - day value to be set DESCRIPTION: Set the date with the given year, month, day inforamtion. RETURNS: NONE *) (*--------------------------- OCIDateAssign ---------------------------------*) TOCIDateAssign = function(err: POCIError; const from: POCIDate; _to: POCIDate): sword; cdecl; (* NAME: OCIDateAssign - OCIDate Assignment PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). from (IN) - date to be assigned to (OUT) - lhs of assignment DESCRIPTION: Performs date assignment. RETURNS: OCI_SUCCESS *) (*--------------------------- OCIDateToText ---------------------------------*) TOCIDateToText = function(err: POCIError; const date: POCIDate; const fmt: poratext; fmt_length: ub1; const lang_name: poratext; lang_length: ub4; buf_size: pub4; buf: poratext): sword; cdecl; (* NAME: OCIDateToText - OCIDate convert date TO String PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). date (IN) - Oracle date to be converted fmt (IN) - conversion format, if null string pointer (oratext * )0, then the date is converted to a character string in the date format "DD-MON-YY". fmt_length (IN) - length of the 'fmt' parameter lang_name (IN) - specifies the language in which the names and abbreviations of months and days are returned; default language of session is used if 'lang_name' is null i.e. (oratext * )0 lang_length (IN) - length of the 'nls_params' parameter buf_size (IN/OUT) - size of the buffer; size of the resulting string is returned via this parameter buf (OUT) - buffer into which the converted string is placed DESCRIPTION: Converts the given date to a string according to the specified format. Refer to "TO_DATE" conversion function described in "Oracle SQL Language Reference Manual" for a description of format and NLS arguments. The converted null-terminated date string is stored in the buffer 'buf'. An error is reported upon overflow, e.g. trying to convert a number of value 10 using format '9' causes an overflow. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if buffer too small invalid format unknown language overflow error *) (*---------------------------- OCIDateFromText ------------------------------*) TOCIDateFromText = function(err: POCIError; const date_str: poratext; d_str_length: ub4; const fmt: poratext; fmt_length: ub1; const lang_name: poratext; lang_length: ub4; date: POCIDate): sword; cdecl; (* NAME: OCIDateFromText - OCIDate convert String TO Date PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). date_str (IN) - input string to be converted to Oracle date d_str_length (IN) - size of the input string, if the length is -1 then 'date_str' is treated as a null terminated string fmt (IN) - conversion format; if 'fmt' is a null pointer, then the string is expected to be in 'DD-MON-YY' format. fmt_length (IN) - length of the 'fmt' parameter lang_name (IN) - language in which the names and abbreviations of days and months are specified, if null i.e. (oratext * )0, the default language of session is used, lang_length (IN) - length of the 'lang_name' parameter date (OUT) - given string converted to date DESCRIPTION: Converts the given string to Oracle date according to the specified format. Refer to "TO_DATE" conversion function described in "Oracle SQL Language Reference Manual" for a description of format. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if invalid format unknown language invalid input string *) (*----------------------------- OCIDateCompare ------------------------------*) TOCIDateCompare = function(err: POCIError; const date1: POCIDate; const date2: POCIDate; _result: psword): sword; cdecl; (* NAME: OCIDateCompare - OCIDate CoMPare dates PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). date1, date2 (IN) - dates to be compared result (OUT) - comparison result, 0 if equal, -1 if date1 < date2, 1 if date1 > date2 DESCRIPTION: The function OCIDateCompare compares two dates. It returns -1 if date1 is smaller than date2, 0 if they are equal, and 1 if date1 is greater than date2. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if invalid date *) (*------------------------- OCIDateAddMonths --------------------------------*) TOCIDateAddMonths = function(err: POCIError; const date: POCIDate; num_months: sb4; _result: POCIDate): sword; cdecl; (* NAME: OCIDateAddMonths - OCIDate ADd or subtract Months PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). date (IN) - 'num_months' added or subtracted from 'date' num_months (IN) - number of months to be added or subtracted (a negative value will be subtracted) result (IN/OUT) - result of adding or subtracting to 'date' DESCRIPTION: The function OCIDateAddDays adds or subtracts num_months from the date 'date'. If the input 'date' is the last day of a month, then appropriate adjustments are made to ensure that the output date is also the last day of the month. For example, Feb. 28 + 1 month = March 31, and November 30 - 3 months = August 31. Otherwise the 'result' date has the same day component as 'date'. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if invalid date *) (*--------------------------- OCIDateAddDays --------------------------------*) TOCIDateAddDays = function(err: POCIError; const date: POCIDate; num_days: sb4; _result: POCIDate):sword; cdecl; (* NAME: OCIDateAddDays - OCIDate ADd or subtract Days PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). date (IN) - 'num_days' added or subtracted from 'date' num_days (IN) - number of days to be added or subtracted (a negative value will be subtracted) result (IN/OUT) - result of adding or subtracting to 'date' DESCRIPTION: The function OCIDateAddDays adds or subtracts num_days from the date 'date'. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if invalid date *) (*--------------------------- OCIDateLastDay --------------------------------*) TOCIDateLastDay = function(err: POCIError; const date: POCIDate; last_day: POCIDate): sword; cdecl; (* NAME: OCIDateLastDay - OCIDate get date of the LaST day of the month PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). date (IN) - input date last_day (OUT) - last day of the month in date 'date' DESCRIPTION: The function OCIDateLastDay returns the date of the last day of the month in date 'date'. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if invalid date *) (*----------------------- OCIDateDaysBetween --------------------------------*) TOCIDateDaysBetween = function(err: POCIError; const date1: POCIDate; const dtae2: POCIDate; num_days: psb4): sword; cdecl; (* NAME: OCIDateDaysBetween - OCIDate get number of days BeTWeen two dates PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). date1, date2 (IN) - input dates num_days (OUT) - number of days between date1 and date2 DESCRIPTION: The function OCIDateDaysBetween returns the number of days between date1 and date2. The time is ignored in this computation. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if invalid date *) (*------------------------ OCIDateZoneToZone --------------------------------*) TOCIDateZoneToZone = function(err: POCIError; const date1: POCIDate; const zon1: poratext; zon1_length: ub4; const zon2: poratext; zon2_length: ub4; dtae2: POCIDate): sword; cdecl; (* NAME: OCIDateZoneToZone - OCIDate convert date from one Zone TO another Zone PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). date1 (IN) - date to be converted zon1 (IN) - zone of input date zon1_length (IN) - length in bytes of string 'zon1' zon2 (IN) - zone to be converted to zon2_length (IN) - length in bytes of string 'zon2' date2 (OUT) - converted date (in 'zon2') DESCRIPTION: Converts date from one time zone to another. Given date 'date1' in time zone 'zon1' returns date 'date2' in time zone 'zon2'. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if invlid date invald input time zone invald output time zone *) (*--------------------------- OCIDateNextDay --------------------------------*) TOCIDateNextDay = function(err: POCIError; const dtae: POCIDate; const day_p: poratext; day_length: ub4; next_day: POCIDate): sword; cdecl; (* NAME: OCIDateNextDay - OCIDate get date of Next DaY PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). date (IN) - returned date should be later than this date day (IN) - first day of week named by this is returned day_length (IN) - length in bytes of string 'day' next_day (OUT) - first day of the week named by 'day' later than 'date' DESCRIPTION: Returns the date of the first day of the week named by 'day' that is later than date 'date'. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if invalid date invalid day */ /*----------------------------- OCIDateCheck --------------------------------*/ /* Listing of error bits used by OCIDateCheck() */ #define OCI_DATE_INVALID_DAY 0x1 /* Bad DAy */ #define OCI_DATE_DAY_BELOW_VALID 0x2 /* Bad DAy Low/high bit (1=low)*/ #define OCI_DATE_INVALID_MONTH 0x4 /* Bad MOnth */ #define OCI_DATE_MONTH_BELOW_VALID 0x8 /* Bad MOnth Low/high bit (1=low)*/ #define OCI_DATE_INVALID_YEAR 0x10 /* Bad YeaR */ #define OCI_DATE_YEAR_BELOW_VALID 0x20 /* Bad YeaR Low/high bit (1=low)*/ #define OCI_DATE_INVALID_HOUR 0x40 /* Bad HouR */ #define OCI_DATE_HOUR_BELOW_VALID 0x80 /* Bad HouR Low/high bit (1=low)*/ #define OCI_DATE_INVALID_MINUTE 0x100 /* Bad MiNute */ #define OCI_DATE_MINUTE_BELOW_VALID 0x200 /* Bad MiNute Low/high bit (1=low)*/ #define OCI_DATE_INVALID_SECOND 0x400 /* Bad SeCond */ #define OCI_DATE_SECOND_BELOW_VALID 0x800 /* bad second Low/high bit (1=low)*/ #define OCI_DATE_DAY_MISSING_FROM_1582 0x1000 /* Day is one of those "missing" from 1582 */ #define OCI_DATE_YEAR_ZERO 0x2000 /* Year may not equal zero */ #define OCI_DATE_INVALID_FORMAT 0x8000 /* Bad date format input */ sword OCIDateCheck( OCIError *err, const OCIDate *date, uword *valid ); /* NAME: OCIDateCheck - OCIDate CHecK if the given date is valid PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). date (IN) - date to be checked valid (OUT) - returns zero for a valid date, otherwise the ORed combination of all error bits specified below: Macro name Bit number Error ---------- ---------- ----- OCI_DATE_INVALID_DAY 0x1 Bad day OCI_DATE_DAY_BELOW_VALID 0x2 Bad DAy Low/high bit (1=low) OCI_DATE_INVALID_MONTH 0x4 Bad MOnth OCI_DATE_MONTH_BELOW_VALID 0x8 Bad MOnth Low/high bit (1=low) OCI_DATE_INVALID_YEAR 0x10 Bad YeaR OCI_DATE_YEAR_BELOW_VALID 0x20 Bad YeaR Low/high bit (1=low) OCI_DATE_INVALID_HOUR 0x40 Bad HouR OCI_DATE_HOUR_BELOW_VALID 0x80 Bad HouR Low/high bit (1=low) OCI_DATE_INVALID_MINUTE 0x100 Bad MiNute OCI_DATE_MINUTE_BELOW_VALID 0x200 Bad MiNute Low/high bit (1=low) OCI_DATE_INVALID_SECOND 0x400 Bad SeCond OCI_DATE_SECOND_BELOW_VALID 0x800 bad second Low/high bit (1=low) OCI_DATE_DAY_MISSING_FROM_1582 0x1000 Day is one of those "missing" from 1582 OCI_DATE_YEAR_ZERO 0x2000 Year may not equal zero OCI_DATE_INVALID_FORMAT 0x8000 Bad date format input So, for example, if the date passed in was 2/0/1990 25:61:10 in (month/day/year hours:minutes:seconds format), the erroor returned would be OCI_DATE_INVALID_DAY | OCI_DATE_DAY_BELOW_VALID | OCI_DATE_INVALID_HOUR | OCI_DATE_INVALID_MINUTE DESCRIPTION: Check if the given date is valid. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if 'date' and 'valid' pointers are NULL pointers */ /*--------------------------- OCIDateSysDate --------------------------------*/ sword OCIDateSysDate( OCIError *err, OCIDate *sys_date ); /* NAME: OCIDateSysDate - OCIDate get current SYStem date and time PARAMETERS: err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). sys_date (OUT) - current system date and time DESCRIPTION: Returns the current system date and time. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'err' is NULL. OCI_ERROR if */ /*****************************************************************************/ /* FIXED-LENGTH STRING - CHAR (N) */ /*****************************************************************************/ /* * An ADT attribute declared as "x CHAR(n)" is mapped to "OCIString *x;". * The representation of OCIString * is shown below. */ /*****************************************************************************/ /* VARIABLE-LENGTH STRING */ /*****************************************************************************/ /* * The variable-length string is represented in C as a pointer to OCIString * structure. The OCIString structure is opaque to the user. Functions are * provided to allow the user to manipulate a variable-length string. * * A variable-length string can be declared as: * * OCIString *vstr; * * For binding variables of type OCIString* in OCI calls (OCIBindByName(), * OCIBindByPos() and OCIDefineByPos()) use the external type code SQLT_VST. */ typedef struct OCIString OCIString; /*-------------------------- OCIStringAssign --------------------------------*/ sword OCIStringAssign( OCIEnv *env, OCIError *err, const OCIString *rhs, OCIString **lhs ); /* NAME: OCIStringAssign - OCIString Assign String to String PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode. err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). rhs (IN) - RHS of the assignment, the type of rhs is also OCIString lhs (IN/OUT) - LHS of the assignment DESCRIPTION: Assign 'rhs' string to 'lhs' string. The 'lhs' string may be resized depending upon the size of the 'rhs'. The assigned string is null-terminated. The 'length' field will not include the extra byte needed for null termination. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is NULL. OCI_ERROR if out of space error */ /*---------------------- OCIStringAssignText --------------------------------*/ sword OCIStringAssignText( OCIEnv *env, OCIError *err, const oratext *rhs, ub4 rhs_len, OCIString **lhs ); /* NAME: OCIStringAssignText - OCIString Assign Text string to String PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode. err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). rhs (IN) - RHS of the assignment, the type of rhs is a text string rhs_len (IN) - length of the 'rhs' string lhs (IN/OUT) - LHS of the assignment DESCRIPTION: Assign 'rhs' string to 'lhs' string. The 'lhs' string may be resized depending upon the size of the 'rhs'. The assigned string is null-terminated. The 'length' field will not include the extra byte needed for null termination. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is NULL. OCI_ERROR if out of space error */ /*-------------------------- OCIStringResize --------------------------------*/ sword OCIStringResize( OCIEnv *env, OCIError *err, ub4 new_size, OCIString **str ); /* NAME: OCIStringResize - OCIString ReSiZe string memory PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode. err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). new_size (IN) - new memory size of the string in bytes str (IN/OUT) - allocated memory for the string is freed from the OOCI heap DESCRIPTION: This function resizes the memory of the given variable-length string in the object cache. The contents of the string are NOT preserved. This function may allocate the string in a new memory region in which case the original memory occupied by the given string will be freed. If the input string is null (str == NULL), then this function will allocate memory for the string. If the new_size is 0, then this function frees the memory occupied by 'str' and a null pointer value is returned. NOTE: The caller must compute 'new_size' taking into account space for the null character ('\0'). RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is NULL. OCI_ERROR if out of space error */ /*---------------------------- OCIStringSize --------------------------------*/ ub4 OCIStringSize( OCIEnv *env, const OCIString *vs ); /* NAME: OCIStringSize - OCIString Get String siZe PARAMETERS: env(IN) - pointer to OCI environment handle vs (IN) - string whose size is returned DESCRIPTION: Return the size of the given string. RETURNS: size of the string in bytes is returned */ /*----------------------------- OCIStringPtr --------------------------------*/ oratext *OCIStringPtr( OCIEnv *env, const OCIString *vs ); /* NAME: OCIStringPtr - OCIString Get String Pointer PARAMETERS: env(IN) - pointer to OCI environment handle vs (IN) - pointer to the text of this string is returned DESCRIPTION: Return the pointer to the text of the given string. RETURNS: pointer to the text of the string is returned */ /*----------------------- OCIStringAllocSize --------------------------------*/ sword OCIStringAllocSize( OCIEnv *env, OCIError *err, const OCIString *vs, ub4 *allocsize ); /* NAME: OCIStringAllocSize - OCIString get Allocated SiZe of string memory in bytes PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode. err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). vs (IN) - string whose allocated size in bytes is returned allocsize (OUT) - allocated size of string memory in bytes is returned DESCRIPTION: Return the allocated size of the string memory in bytes. The allocated size is >= actual string size. REQUIRES: vs is a non-null pointer RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is NULL. OCI_ERROR on error */ /*****************************************************************************/ /* VARIABLE-LENGTH RAW */ /*****************************************************************************/ /* * The variable-length raw is represented in C as a pointer to OCIRaw * structure. The OCIRaw structure is opaque to the user. Functions are * provided to allow the user to manipulate a variable-length raw. * * A variable-length raw can be declared as: * * OCIRaw *raw; * * For binding variables of type OCIRaw* in OCI calls (OCIBindByName(), * OCIBindByPos() and OCIDefineByPos()) use the external type code SQLT_LVB. */ typedef struct OCIRaw OCIRaw; /*-------------------------- OCIRawAssignRaw --------------------------------*/ sword OCIRawAssignRaw( OCIEnv *env, OCIError *err, const OCIRaw *rhs, OCIRaw **lhs ); /* NAME: OCIRawAssignRaw - OCIRaw Assign Raw (of type OCIRaw* ) to Raw (of type OCIRaw* ) PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode. err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). rhs (IN) - RHS of the assignment, the type of rhs is also OCIRaw lhs (IN/OUT) - LHS of the assignment DESCRIPTION: Assign 'rhs' raw to 'lhs' raw. The 'lhs' raw may be resized depending upon the size of the 'rhs'. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is NULL. OCI_ERROR if out of space error */ /*------------------------ OCIRawAssignBytes --------------------------------*/ sword OCIRawAssignBytes( OCIEnv *env, OCIError *err, const ub1 *rhs, ub4 rhs_len, OCIRaw **lhs ); /* NAME: OCIRawAssignBytes - OCIRaw Assign raw Bytes (of type ub1* ) to Raw (of type OCIRaw* ) PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode. err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). rhs (IN) - RHS of the assignment, the type of rhs is ub1 * rhs_len (IN) - length of the 'rhs' raw lhs (IN/OUT) - LHS of the assignment DESCRIPTION: Assign 'rhs' raw to 'lhs' raw. The 'lhs' raw may be resized depending upon the size of the 'rhs'. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is NULL. OCI_ERROR if out of space error */ /*---------------------------- OCIRawResize ---------------------------------*/ sword OCIRawResize( OCIEnv *env, OCIError *err, ub4 new_size, OCIRaw **raw ); /* NAME: OCIRawResize - OCIRaw ReSiZe memory of variable-length raw PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode. err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). new_size (IN) - new size of the raw data in bytes raw (IN) - variable-length raw pointer; the raw is resized to 'new_size' DESCRIPTION: This function resizes the memory of the given variable-length raw in the object cache. The previous contents of the raw are NOT preserved. This function may allocate the raw in a new memory region in which case the original memory occupied by the given raw will be freed. If the input raw is null (raw == NULL), then this function will allocate memory for the raw data. If the new_size is 0, then this function frees the memory occupied by 'raw' and a null pointer value is returned. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is NULL. OCI_ERROR if out of space error */ /*------------------------------- OCIRawSize --------------------------------*/ ub4 OCIRawSize( OCIEnv * env, const OCIRaw *raw ); /* NAME: OCIRawSize - OCIRaw Get Raw siZe PARAMETERS: env (IN) - pointer to OCI environment handle raw (INT) - raw whose size is returned DESCRIPTION: Return the size of the given raw. RETURNS: size of the raw in bytes is returned */ /*--------------------------------- OCIRawPtr -------------------------------*/ ub1 *OCIRawPtr( OCIEnv * env, const OCIRaw *raw ); /* NAME: OCIRawPtr - OCIRaw Get Raw data Pointer PARAMETERS: env (IN) - pointer to OCI environment handle raw (IN) - pointer to the data of this raw is returned DESCRIPTION: Return the pointer to the data of the given raw. RETURNS: pointer to the data of the raw is returned */ /*------------------------------ OCIRawAllocSize ----------------------------*/ sword OCIRawAllocSize( OCIEnv *env, OCIError *err, const OCIRaw *raw, ub4 *allocsize ); /* NAME: OCIRawAllocSize - OCIRaw get Allocated SiZe of raw memory in bytes PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode. err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). raw (IN) - raw whose allocated size in bytes is returned allocsize (OUT) - allocated size of raw memory in bytes is returned DESCRIPTION: Return the allocated size of the raw memory in bytes. The allocated size is >= actual raw size. REQUIRES: raw is a non-null pointer RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is NULL. OCI_ERROR upon error *) (***************************************************************************** * OBJECT REFERENCE OPERATIONS * *****************************************************************************) (* * See the definition of OCIRef in oro.h. * * For binding variables of type OCIRef* in OCI calls (OCIBindByName(), * OCIBindByPos() and OCIDefineByPos()) use the code SQLT_REF. * *) (*------------------------- OBJECT REFERENCE (REF) --------------------------*) PPOCIRef = ^POCIRef; POCIRef = Pointer; (* * OCIRef - OCI object REFerence * * In the Oracle object runtime environment, an object is identified by an * object reference (ref) which contains the object identifier plus other * runtime information. The contents of a ref is opaque to clients. Use * OCIObjectNew() to construct a ref. *) (*---------------------------- OCIRefClear ----------------------------------*) TOCIRefClear = procedure(env: POCIEnv; ref: POCIRef); (* NAME: OCIRefClear - OCIRef CLeaR or nullify a ref PARAMETERS: env (IN) - pointer to OCI environment handle ref (IN/OUT) - ref to clear DESCRIPTION: Clear or nullify the given ref. A ref is considered to be a null ref if it does not contain a valid OID (and thus doesn't point to an object). Logically, a null ref is a dangling ref. Note that a null ref is still a valid SQL value and is not SQL-ly null. It can be used as a valid non-null constant ref value for NOT NULL column or attribute of a row in a table. If a null pointer value is passed as a ref, then this function is a no-op. *) (*--------------------------- OCIRefAssign ----------------------------------*) TOCIRefAssign = function(env: POCIEnv; err: POCIError; const source: POCIRef; target: PPOCIRef): sword; cdecl; (* NAME: OCIRefAssign - OCIRef CoPY a ref to another PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode. err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). source (IN) - ref to copy from target (IN/OUT) - ref to copy to DESCRIPTION: Copy 'source' ref to 'target' ref; both then reference the same object. If the target ref pointer is null (i.e. *target == NULL) then the copy function will allocate memory for the target ref in OOCI heap prior to the copy. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is NULL. OCI_ERROR if 1) out of memory */ /*-------------------------- OCIRefIsEqual ----------------------------------*/ boolean OCIRefIsEqual( OCIEnv *env, const OCIRef *x, const OCIRef *y ); /* NAME: OCIRefIsEqual - OCIRef compare two refs for EQUality PARAMETERS: env (IN) - pointer to OCI environment handle x (IN) - ref to compare y (IN) - ref to compare DESCRIPTION: Compare the given refs for equality. Two refs are equal if and only if: - they are both referencing the same persistent object, or - they are both referencing the same transient object. NOTE THAT TWO NULL REFS ARE CONSIDERED NOT EQUAL BY THIS FUNCTION. RETURNS: TRUE if the two refs are equal FALSE if the two refs are not equal, or X is NULL, or Y is NULL */ /*--------------------------- OCIRefIsNull ----------------------------------*/ boolean OCIRefIsNull( OCIEnv *env, const OCIRef *ref ); /* NAME: OCIRefIsNull - OCIRef test if a ref is NULl PARAMETERS: env (IN) - pointer to OCI environment handle ref (IN) - ref to test for null DESCRIPTION: Return TRUE if the given ref is null; otherwise, return FALSE. A ref is null if and only if: - it is supposed to be referencing a persistent object, but its OID is null, or - it is supposed to be referencing a transient object, but it is currently not pointing to an object. A ref is a dangling ref if the object that it points to does not exist. RETURNS: TRUE if the given ref is NULL FALSE if the given ref is not NULL */ /*-------------------------- OCIRefHexSize ----------------------------------*/ ub4 OCIRefHexSize( OCIEnv *env, const OCIRef *ref ); /* NAME: OCIRefHexSize - OCIRef Hexadecimal buffer SiZe in bytes PARAMETERS: env (IN) - pointer to OCI environment handle ref (IN) - ref whose size in hexadecimal representation in bytes is returned DESCRIPTION: Return the size of the buffer in bytes required for the hexadecimal representation of the ref. A buffer of at-least this size must be passed to ref-to-hex (OCIRefToHex) conversion function. RETURNS: size of hexadecimal representation of ref */ /*-------------------------- OCIRefFromHex ---------------------------------*/ sword OCIRefFromHex( OCIEnv *env, OCIError *err, const OCISvcCtx *svc, const oratext *hex, ub4 length, OCIRef **ref ); /* NAME: OCIRefFromHex - OCIRef convert a Hexadecimal string TO a Ref PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). svc (IN) - OCI service context handle; if the resulting ref is initialized with this service context hex (IN) - hexadecimal string (that was produced by 'OCIRefToHex()" previously) to be convert into a ref length (IN) - length of the hexadecimal string ref (IN/OUT) - ref is initialized with the given value ('hex'). If *ref is null, then space for the ref is allocated in the object cache, otherwise the memory occupied by the given ref is re-used. DESCRIPTION: Convert the given hexadecimal string into a ref. This function ensures that the resulting ref is well formed. It does NOT ensure that the object pointed to by the resulting ref exists or not. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is NULL. OCI_ERROR if */ /*--------------------------- OCIRefToHex -----------------------------------*/ sword OCIRefToHex( OCIEnv *env, OCIError *err, const OCIRef *ref, oratext *hex, ub4 *hex_length ); /* NAME: OCIRefToHex - OCIRef convert ref to a Hexadecimal string PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). ref (IN) - ref to be converted into a hexadecimal string; if the ref is a null ref (i.e. OCIRefIsNull(ref) == TRUE) then a zero hex_length value is returned hex (OUT) - buffer that is large enough to contain the resulting hexadecimal string; the contents of the string is opaque to the caller hex_length (IN/OUT) - on input specifies the size of the 'hex' buffer, on output specifies the actual size of the hexadecimal string being returned in 'hex' DESCRIPTION: Convert the given ref into a hexadecimal string, and return the length of the string. The resulting string is opaque to the caller. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is NULL. OCI_ERROR if the given buffer is not big enough to hold the resulting string */ /*****************************************************************************/ /* COLLECTION FUNCTIONS */ /*****************************************************************************/ /* The generic collection is represented by the type 'OCIColl'. The following operations OCIColl*() are provided on a generic collection: - get current size of collection - get upper bound of collection - get pointer to an element given its index - set element at given index (assign element) - append an element - trim the given number of elements from the end of the collection - collection assignment The following iterator based scanning functions are also provided on a generic collection. These functions make use of an iterator which is defined to be of type OCIIter. - create an iterator for scanning collection - destroy iterator - reset iterator to the beginning of collection - get pointer to current element pointed by iterator - get pointer to next element - get pointer to previous element The collections variable-length array (varray) and nested table are sub-types of generic collection. This means that the OCIColl*() functions can also be used to manipulate varray and nested table. The varray is represented by OCIArray type and nested table by OCITable. Besides OCIColl*() functions no additional functions are provided for manipulating varrays. The OCIColl*() functions are a complete set of functions to manipulate varrays. Besides OCIColl*() functions, the following functions OCITable*() can be used to manipulate nested table. The OCITable*() functions operate on nested tables only and should not be used on a varray. - delete an element at index i. Note that the position ordinals of the remaining elements of the table is not changed by the delete operation. So delete creates "holes" in the table. - check if an element exists at the given index i - return the smallest value of i for which exists(i) is true - return the largest value of i for which exists(i) is true - return pointer to the smallest position j, greater than i, such that OCITableExists(j) is true - return pointer to the largest position j, less than i, such that OCITableExists(j) is true For binding variables of type OCIColl* or OCITable* in OCI calls (OCIBindByName(), OCIBindByPos() and OCIDefineByPos()) use the external type code SQLT_NTY. */ /* OCIColl - generic collection type */ typedef struct OCIColl OCIColl; /* OCIArray - varray collection type */ typedef OCIColl OCIArray; /* OCITable - nested table collection type */ typedef OCIColl OCITable; /* OCIIter - collection iterator */ typedef struct OCIIter OCIIter; /*----------------------------- OCICollSize ---------------------------------*/ sword OCICollSize( OCIEnv *env, OCIError *err, const OCIColl *coll, sb4 *size ); /* NAME: OCICollSize - OCIColl return current SIZe of the given collection PARAMETERS: env(IN) - pointer to OCI environment handle err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). coll (IN) - collection whose number of elements is returned size (OUT) - current number of elements in the collection DESCRIPTION: Returns the current number of elements in the given collection. For collections of type nested table wherein 'delete element' operation is allowed, the count returned by OCICollSize() will NOT be decremented upon deleting elements. For example: OCICollSize(...); // assume 'size' returned is equal to 5 OCITableDelete(...); // delete one element OCICollSize(...); // 'size' returned will still be 5 To get the count minus the deleted elements use OCITableSize(). Continuing the above example, OCITableSize(...) // 'size' returned will be equal to 4 Note, a trim operation (OCICollTrim) will decrement the count by the number of trimmed elements. Continuing the above example, OCICollTrim(..,1..); // trim one element OCICollSize(...); // 'size' returned will be equal to 4 RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is NULL. OCI_ERROR if error during loading of collection into object cache any of the input parameters is null */ /*------------------------------ OCICollMax ---------------------------------*/ sb4 OCICollMax( OCIEnv *env, const OCIColl *coll ); /* NAME: OCICollMax - OCIColl return MAXimum size (upper-bound) of the given collection (in number of elements) PARAMETERS: env(IN) - pointer to OCI environment handle coll (IN) - collection whose upper-bound in number of elements is returned DESCRIPTION: Returns the max number of elements that the given collection can hold. A value 0 indicates that the collection has no upper-bound. REQUIRES: coll must point to a valid collection descriptor RETURNS: upper-bound of the given collection */ /*-------------------------- OCICollGetElem ---------------------------------*/ sword OCICollGetElem( OCIEnv *env, OCIError *err, const OCIColl *coll, sb4 index, boolean *exists, void **elem, void **elemind ); /* NAME: OCICollGetElem - OCIColl GET pointer to the element at the given index PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode. err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). coll (IN) - pointer to the element in this collection is returned index (IN) - index of the element whose pointer is returned exists (OUT) - set to FALSE if element at the specified index does not exist else TRUE elem (OUT) - address of the desired element is returned elemind (OUT) [optional] - address of the null indicator information is returned; if (elemind == NULL) then the null indicator information will NOT be returned DESCRIPTION: Get the address of the element at the given position. Optionally this function also returns the address of the element's null indicator information. The following table describes for each collection element type what the corresponding element pointer type is. The element pointer is returned via the 'elem' parameter of OCICollGetElem(). Element Type *elem is set to ----------------------- --------------- Oracle Number (OCINumber) OCINumber* Date (OCIDate) OCIDate* Variable-length string (OCIString* ) OCIString** Variable-length raw (OCIRaw* ) OCIRaw** object reference (OCIRef* ) OCIRef** lob locator (OCILobLocator* ) OCILobLocator** object type (e.g. person) person* The element pointer returned by OCICollGetElem() is in a form such that it can not only be used to access the element data but also is in a form that can be used as the target (i.e left-hand-side) of an assignment statement. For example, assume the user is iterating over the elements of a collection whose element type is object reference (OCIRef* ). A call to OCICollGetElem() returns pointer to a reference handle (i.e. OCIRef** ). After getting, the pointer to the collection element, the user may wish to modify it by assigning a new reference. This can be accomplished via the ref assignment function shown below: sword OCIRefAssign( OCIEnv *env, OCIError *err, const OCIRef *source, OCIRef **target ); Note that the 'target' parameter of OCIRefAssign() is of type 'OCIRef**'. Hence OCICollGetElem() returns 'OCIRef**'. If '*target == NULL' a new ref will be allocated by OCIRefAssign() and returned via the 'target' parameter. Similarly, if the collection element was of type string (OCIString* ), OCICollGetElem() returns pointer to string handle (i.e. OCIString** ). If a new string is assigned, via OCIStringAssign() or OCIStringAssignText() the type of the target must be 'OCIString **'. If the collection element is of type Oracle number, OCICollGetElem() returns OCINumber*. The prototype of OCINumberAssign() is shown below: sword OCINumberAssign(OCIError *err, const OCINumber *from, OCINumber *to); RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is NULL. OCI_ERROR if any of the input parameters is null */ /*------------------------- OCICollGetElemArray -----------------------------*/ sword OCICollGetElemArray( OCIEnv *env, OCIError *err, const OCIColl *coll, sb4 index, boolean *exists, void **elem, void **elemind, uword *nelems); /* NAME: OCICollGetElemArray - OCIColl GET pointers to elements from given index PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode. err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). coll (IN) - pointers to the elements in this collection is returned index (IN) - starting index of the element exists (OUT) - set to FALSE if element at the specified index does not exist else TRUE elem (OUT) - address of the desired elements is returned elemind (OUT) [optional] - address of the null indicators information is returned; if (elemind == NULL) then the null indicator information will NOT be returned nelems(IN/OUT) - Upper bound of elem and/or elemind array DESCRIPTION: Get the address of the elements from the given position. Optionally this function also returns the address of the element's null indicator information. The following table describes for each collection element type what the corresponding element pointer type is. The element pointer is returned via the 'elem' parameter of OCICollGetElem(). Element Type *elem is set to ----------------------- --------------- Oracle Number (OCINumber) OCINumber* Date (OCIDate) OCIDate* Variable-length string (OCIString* ) OCIString** Variable-length raw (OCIRaw* ) OCIRaw** object reference (OCIRef* ) OCIRef** lob locator (OCILobLocator* ) OCILobLocator** object type (e.g. person) person* The element pointer returned by OCICollGetElem() is in a form such that it can not only be used to access the element data but also is in a form that can be used as the target (i.e left-hand-side) of an assignment statement. For example, assume the user is iterating over the elements of a collection whose element type is object reference (OCIRef* ). A call to OCICollGetElem() returns pointer to a reference handle (i.e. OCIRef** ). After getting, the pointer to the collection element, the user may wish to modify it by assigning a new reference. This can be accomplished via the ref assignment function shown below: sword OCIRefAssign( OCIEnv *env, OCIError *err, const OCIRef *source, OCIRef **target ); Note that the 'target' parameter of OCIRefAssign() is of type 'OCIRef**'. Hence OCICollGetElem() returns 'OCIRef**'. If '*target == NULL' a new ref will be allocated by OCIRefAssign() and returned via the 'target' parameter. Similarly, if the collection element was of type string (OCIString* ), OCICollGetElem() returns pointer to string handle (i.e. OCIString** ). If a new string is assigned, via OCIStringAssign() or OCIStringAssignText() the type of the target must be 'OCIString **'. If the collection element is of type Oracle number, OCICollGetElem() returns OCINumber*. The prototype of OCINumberAssign() is shown below: sword OCINumberAssign(OCIError *err, const OCINumber *from, OCINumber *to); RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is NULL. OCI_ERROR if any of the input parameters is null */ /*----------------------- OCICollAssignElem ---------------------------------*/ sword OCICollAssignElem( OCIEnv *env, OCIError *err, sb4 index, const void *elem, const void *elemind, OCIColl *coll ); /* NAME: OCICollAssignElem - OCIColl ASsign Element PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode. err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). index (IN) - index of the element whose is assigned to elem (IN) - element which is assigned from (source element) elemind (IN) [optional] - pointer to the element's null indicator information; if (elemind == NULL) then the null indicator information of the assigned element will be set to non-null. coll (IN/OUT) - collection to be updated DESCRIPTION: Assign the given element value 'elem' to the element at coll[index]. If the collection is of type nested table, the element at the given index may not exist (i.e. may have been deleted). In this case, the given element is inserted at index 'index'. Otherwise, the element at index 'index' is updated with the value of 'elem'. Note that the given element is deep-copied and 'elem' is strictly an input parameter. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is NULL. OCI_ERROR if any of the input parameters is null out of memory error given index is out of bounds of the given collection */ /*--------------------------- OCICollAssign ---------------------------------*/ sword OCICollAssign( OCIEnv *env, OCIError *err, const OCIColl *rhs, OCIColl *lhs ); /* NAME: OCICollAssign - OCIColl ASsiGn collection PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode. err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). rhs (IN) - collection to be assigned from lhs (OUT) - collection to be assigned to DESCRIPTION: Assign 'rhs' to 'lhs'. The 'lhs' collection may be decreased or increased depending upon the size of 'rhs'. If the 'lhs' contains any elements then the elements will be deleted prior to the assignment. This function performs a deep-copy. The memory for the elements comes from the object cache. An error is returned if the element types of the lhs and rhs collections do not match. Also, an error is returned if the upper-bound of the lhs collection is less than the current number of elements in the rhs collection. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is NULL. OCI_ERROR if any of the input parameters is null out of memory error type mis-match of lhs and rhs collections upper-bound of lhs collection is less than the current number of elements in the rhs collection */ /*--------------------------- OCICollAppend ---------------------------------*/ sword OCICollAppend( OCIEnv *env, OCIError *err, const void *elem, const void *elemind, OCIColl *coll ); /* NAME: OCICollAppend - OCIColl APPend collection PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode. err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). elem (IN) - pointer to the element which is appended to the end of the given collection elemind (IN) [optional] - pointer to the element's null indicator information; if (elemind == NULL) then the null indicator information of the appended element will be set to non-null. coll (IN/OUT) - updated collection DESCRIPTION: Append the given element to the end of the given collection. Appending an element is equivalent to: - increasing the size of the collection by 1 element - updating (deep-copying) the last element's data with the given element's data Note that the pointer to the given element 'elem' will not be saved by this function. So 'elem' is strictly an input parameter. An error is returned if the current size of the collection is equal to the max size (upper-bound) of the collection prior to appending the element. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is NULL. OCI_ERROR if any of the input parameters is null out of memory error current size of collection == max size of the collection */ /*----------------------------- OCICollTrim ---------------------------------*/ sword OCICollTrim( OCIEnv *env, OCIError *err, sb4 trim_num, OCIColl *coll ); /* NAME: OCICollTrim - OCIColl Trim elements from the end of the collection PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode. err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). trim_num (IN) - number of elements to trim coll (IN/OUT) - 'trim_num' of elements are removed (freed) from the end of the collection DESCRIPTION: Trim the collection by the given number of elements. The elements are removed from the end of the collection. An error is returned if the 'trim_num' is greater than the current size of the collection. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is NULL. OCI_ERROR if any of the input parameters is null 'trim_num' is greater than the current size of the collection. */ /*--------------------------- OCICollIsLocator ------------------------------*/ sword OCICollIsLocator(OCIEnv *env, OCIError *err, const OCIColl *coll, boolean *result ); /* Name: OCICollIsLocator - OCIColl indicates whether a collection is locator based or not. Parameters: env(IN) - pointer to OCI environment handle err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). coll (IN) - collection item. result (OUT) - TRUE if the collection item is a locator, FALSE otherwise Description: Returns TRUE in the result OUT parameter if the collection item is a locator, otherwise returns FALSE. Returns: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is NULL. */ /*---------------------------- OCIIterCreate --------------------------------*/ sword OCIIterCreate( OCIEnv *env, OCIError *err, const OCIColl *coll, OCIIter **itr ); /* NAME: OCIIterCreate - OCIColl Create an ITerator to scan the collection elements PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode. err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). coll (IN) - collection which will be scanned; the different collection types are varray and nested table itr (OUT) - address to the allocated collection iterator is returned by this function DESCRIPTION: Create an iterator to scan the elements of the collection. The iterator is created in the object cache. The iterator is initialized to point to the beginning of the collection. If the next function (OCIIterNext) is called immediately after creating the iterator then the first element of the collection is returned. If the previous function (OCIIterPrev) is called immediately after creating the iterator then "at beginning of collection" error is returned. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is NULL. OCI_ERROR if any of the input parameters is null out of memory error */ /*----------------------------- OCIIterDelete ------------------------------*/ sword OCIIterDelete( OCIEnv *env, OCIError *err, OCIIter **itr ); /* NAME: OCIIterDelete - OCIColl Delete ITerator PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode. err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). itr (IN/OUT) - the allocated collection iterator is destroyed and the 'itr' is set to NULL prior to returning DESCRIPTION: Delete the iterator which was previously created by a call to OCIIterCreate. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is NULL. OCI_ERROR if any of the input parameters is null to be discovered */ /*----------------------------- OCIIterInit ---------------------------------*/ sword OCIIterInit( OCIEnv *env, OCIError *err, const OCIColl *coll, OCIIter *itr ); /* NAME: OCIIterInit - OCIColl Initialize ITerator to scan the given collection PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode. err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). coll (IN) - collection which will be scanned; the different collection types are varray and nested table itr (IN/OUT) - pointer to an allocated collection iterator DESCRIPTION: Initializes the given iterator to point to the beginning of the given collection. This function can be used to: a. reset an iterator to point back to the beginning of the collection b. reuse an allocated iterator to scan a different collection RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is NULL. OCI_ERROR if any of the input parameters is null *) (*------------------------ OCIIterGetCurrent --------------------------------*) TOCIIterGetCurrent = function(hndl: POCIEnv; err: POCIError; itr: POCIIter; elem: PPointer; elemind: PPointer): sword; cdecl; (* NAME: OCIIterGetCurrent - OCIColl Iterator based, get CURrent collection element PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode. err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). itr (IN) - iterator which points to the current element elem (OUT) - address of the element pointed by the iterator is returned elemind (OUT) [optional] - address of the element's null indicator information is returned; if (elemind == NULL) then the null indicator information will NOT be returned DESCRIPTION: Returns pointer to the current element and its corresponding null information. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is NULL. OCI_ERROR if any of the input parameters is null *) (*------------------------------ OCIIterNext --------------------------------*) TOCIIterNext = function(hndl: POCIEnv; err: POCIError; itr: POCIIter; elem: PPointer; elemind: PPointer; eoc: PBoolean): sword; cdecl; (* NAME: OCIIterNext - OCIColl Iterator based, get NeXT collection element PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode. err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). itr (IN/OUT) - iterator is updated to point to the next element elem (OUT) - after updating the iterator to point to the next element, address of the element is returned elemind (OUT) [optional] - address of the element's null indicator information is returned; if (elemind == NULL) then the null indicator information will NOT be returned eoc (OUT) - TRUE if iterator is at End Of Collection (i.e. next element does not exist) else FALSE DESCRIPTION: Returns pointer to the next element and its corresponding null information. The iterator is updated to point to the next element. If the iterator is pointing to the last element of the collection prior to executing this function, then calling this function will set eoc flag to TRUE. The iterator will be left unchanged in this situation. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is NULL. OCI_ERROR if any of the input parameters is null *) (*------------------------------ OCIIterPrev --------------------------------*) TOCIIterPrev = function(hndl: POCIEnv; err: POCIError; itr: POCIIter; elem: PPointer; elemind: PPointer; boc: PBoolean): sword; cdecl; (* NAME: OCIIterPrev - OCIColl Iterator based, get PReVious collection element PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode. err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). itr (IN/OUT) - iterator is updated to point to the previous element elem (OUT) - after updating the iterator to point to the previous element, address of the element is returned elemind (OUT) [optional] - address of the element's null indicator information is returned; if (elemind == NULL) then the null indicator information will NOT be returned boc (OUT) - TRUE if iterator is at Beginning Of Collection (i.e. previous element does not exist) else FALSE. DESCRIPTION: Returns pointer to the previous element and its corresponding null information. The iterator is updated to point to the previous element. If the iterator is pointing to the first element of the collection prior to executing this function, then calling this function will set 'boc' to TRUE. The iterator will be left unchanged in this situation. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is NULL. OCI_ERROR if any of the input parameters is null *) (***************************************************************************** * FUNCTIONS WHICH OPERATE ONLY ON NESTED TABLE OCITable*() * ***************************************************************************** *---------------------------- OCITableSize ---------------------------------*) TOCITableSize = function(hndl: POCIEnv; err: POCIError; const tbl: POCITable; size: psb4): sword; cdecl; (* NAME: OCITableSize - OCITable return current SIZe of the given nested table (not including deleted elements) PARAMETERS: env(IN) - pointer to OCI environment handle err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). tbl (IN) - nested table whose number of elements is returned size (OUT) - current number of elements in the nested table. The count does not include deleted elements. DESCRIPTION: Returns the count of elements in the given nested table. The count returned by OCITableSize() will be decremented upon deleting elements from the nested table. So, this count DOES NOT includes any "holes" created by deleting elements. For example: OCITableSize(...); // assume 'size' returned is equal to 5 OCITableDelete(...); // delete one element OCITableSize(...); // 'size' returned will be equal to 4 To get the count plus the count of deleted elements use OCICollSize(). Continuing the above example, OCICollSize(...) // 'size' returned will still be equal to 5 RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is NULL. OCI_ERROR if error during loading of nested table into object cache any of the input parameters is null *) (*---------------------- OCITableExists ---------------------------------*) TOCITableExists = function(hndl: POCIEnv; err: POCIError; const tbl: POCITable; index: sb4; exists: PBoolean): sword; cdecl; (* NAME: OCITableExists - OCITable test whether element at the given index EXIsts PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode. err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). tbl (IN) - table in which the given index is checked index (IN) - index of the element which is checked for existence exists (OUT) - set to TRUE if element at given 'index' exists else set to FALSE DESCRIPTION: Test whether an element exists at the given 'index'. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is NULL. OCI_ERROR if any of the input parameters is null *) (*--------------------------- OCITableDelete -------------------------------*) TOCITableDelete = function(hndl: POCIEnv; err: POCIError; index: sb4; tbl: POCITable): sword; cdecl; (* NAME: OCITableDelete - OCITable DELete element at the specified index PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode. err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). index (IN) - index of the element which must be deleted tbl (IN) - table whose element is deleted DESCRIPTION: Delete the element at the given 'index'. Note that the position ordinals of the remaining elements of the table is not changed by the delete operation. So delete creates "holes" in the table. An error is returned if the element at the specified 'index' has been previously deleted. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is NULL. OCI_ERROR if any of the input parameters is null given index is not valid *) (*--------------------------- OCITableFirst ---------------------------------*) TOCITableFirst = function(hndl: POCIEnv; err: POCIError; const tbl: POCITable; index: sb4): sword; cdecl; (* NAME: OCITableFirst - OCITable return FirST index of table PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode. err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). tbl (IN) - table which is scanned index (OUT) - first index of the element which exists in the given table is returned DESCRIPTION: Return the first index of the element which exists in the given table. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is NULL. OCI_ERROR if table is empty *) (*---------------------------- OCITableLast ---------------------------------*) TOCITableLast = function(hndl: POCIEnv; err: POCIError; const tbl: POCITable; index: sb4): sword; cdecl; (* NAME: OCITableFirst - OCITable return LaST index of table PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode. err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). tbl (IN) - table which is scanned index (OUT) - last index of the element which exists in the given table is returned DESCRIPTION: Return the last index of the element which exists in the given table. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is NULL. OCI_ERROR if table is empty *) (*---------------------------- OCITableNext ---------------------------------*) TOCITableNext = function(hndl: POCIEnv; err: POCIError; index: sb4; const tbl: POCITable; next_index: psb4; exists: PBoolean): sword; cdecl; (* NAME: OCITableNext - OCITable return NeXT available index of table PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode. err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). index (IN) - starting at 'index' the index of the next element which exists is returned tbl (IN) - table which is scanned next_index (OUT) - index of the next element which exists is returned exists (OUT) - FALSE if no next index available else TRUE DESCRIPTION: Return the smallest position j, greater than 'index', such that exists(j) is TRUE. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is NULL. OCI_ERROR if no next index available */ /*---------------------------- OCITablePrev ---------------------------------*) TOCITablePrev = function(hndl: POCIEnv; err: POCIError; index: sb4; const tbl: POCITable; prev_index: psb4; exists: PBoolean): sword; cdecl; (* NAME: OCITablePrev - OCITable return PReVious available index of table PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode. err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). index (IN) - starting at 'index' the index of the previous element which exists is returned tbl (IN) - table which is scanned prev_index (OUT) - index of the previous element which exists is returned exists (OUT) - FALSE if no next index available else TRUE DESCRIPTION: Return the largest position j, less than 'index', such that exists(j) is TRUE. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is NULL. OCI_ERROR if no previous index available *) (*--------------------------------orciap.h-----------------------------------* (*-------------------------------- OCIPing ----------------------------------*) TOCIPing = function(svchp: POCISvcCtx; errhp: POCIError; mode: ub4): sword; cdecl; (*---------------------------------orid.h------------------------------------* * PUBLIC FUNCTIONS * *---------------------------------------------------------------------------*) (*-------------------------- OCIObjectSetAttr ----------------------------*) TOCIObjectSetAttr = function(env: POCIEnv; err: POCIError; instance: Pointer; null_struct: pointer; tdo: POCIType; const names: PPAnsiChar; const lengths: pub4; const name_count: ub4; const indexes: pub4; const index_count: ub4; const null_status: POCIInd; const attr_null_struct: Pointer; const attr_value: Pointer): sword; cdecl; (* NAME: OCIObjectSetAttr - ORID SET value PARAMETERS: env (IN) - OCI environment handle initialized in object mode err (IN) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). instance (IN) - pointer to an ADT instance null_struct (IN) - the null structure of the ADT instance or array tdo (IN) - pointer to the TDO names (IN) - array of attribute names. This is used to specify the names of the attributes in the path expression. lengths (IN) - array of lengths of attribute names. name_count (IN) - number of element in the array 'names'. indexes (IN) [OPTIONAL] - currently NOT SUPPORTED, pass (ub4 * )0. index_count (IN) [OPTIONAL] - currently NOT SUPPORTED, pass (ub4)0. attr_null_status (IN) - the null status of the attribute if the type of attribute is primitive. attr_null_struct (IN) - the null structure of an ADT or collection attribute. attr_value (IN) - pointer to the attribute value. REQUIRES: DESCRIPTION: This function set the attribute of the given object with the given value. The position of the attribute is specified as a path expression which is an array of names and an array of indexes. RETURNS: one of OROSTA* EXAMPLES: For path expression stanford.cs.stu[5].addr, the arrays will look like names = {"stanford", "cs", "stu", "addr"} lengths = {8, 2, 3, 4} indexes = {5} Also see the above example. */ (*-------------------------- OCIObjectGetAttr ----------------------------*) TOCIObjectGetAttr = function(env: POCIEnv; err: POCIError; instance: Pointer; null_struct: Pointer; tdo: POCIType; const names: PPoratext; const lengths: pub4; const name_count: ub4; const indexes: pub4; const index_count: ub4; attr_null_status: PPOCIInd; attr_null_struct, attr_value: PPointer; attr_tdo: PPOCIType): sword; cdecl; (* NAME: OCIObjectGetAttr - ORID GET value PARAMETERS: env (IN) - OCI environment handle initialized in object mode err (IN) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). instance (IN) - pointer to an ADT instance null_struct (IN) - the null structure of the ADT instance or array tdo (IN) - pointer to the TDO names (IN) - array of attribute names. This is used to specify the names of the attributes in the path expression. lengths (IN) - array of lengths of attribute names. name_count (IN) - number of element in the array 'names'. indexes (IN) [OPTIONAL] - currently NOT SUPPORTED, pass (ub4 * )0. index_count (IN) [OPTIONAL] - currently NOT SUPPORTED, pass (ub4)0. attr_null_status (OUT) - the null status of the attribute if the type of attribute is primitive. attr_null_struct (OUT) - the null structure of an ADT or collection attribute. attr_value (OUT) - pointer to the attribute value. attr_tdo (OUT) - pointer to the TDO of the attribute. REQUIRES: - a valid OCI environment handle must be given. DESCRIPTION: This function gets a value from an ADT instance or from an array. If the parameter 'instance' points to an ADT instance, then the path expression specifies the location of the attribute in the ADT. It is assumed that the object is pinned and that the value returned is valid until the object is unpinned. RETURNS: one of OROSTA* EXAMPLES: See example in OCIObjectSetAttr(). Also see the above example. *) {--------------------------------ori.h-------------------------------------- } { PUBLIC TYPES AND CONSTANTS } {--------------------------------------------------------------------------- } { Also see oro.h. } {--------------------------------------------------------------------------- } { PUBLIC FUNCTIONS } {--------------------------------------------------------------------------- } {--------------------------------------------------------------------------- } { OBJECT/INSTANCE OPERATIONS } {--------------------------------------------------------------------------- } {--------------------------- OCIObjectNew ---------------------------------- } OCITypeCode = ub2; TOCIObjectNew = function(env: POCIEnv; err: POCIError; const svc: POCISvcCtx; const typecode: OCITypeCode; const tdo: POCIType; const table: Pointer; const duration: OCIDuration; const value: boolean; instance: PPointer): sword; cdecl; { NAME: OCIObjectNew - OCI new (create) a standalone instance PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). svc (IN) - OCI service handle. typecode (IN) - the typecode of the type of the instance. tdo (IN, optional) - pointer to the type descriptor object. The TDO describes the type of the instance that is to be created. Refer to OCITypeByName() for obtaining a TDO. The TDO is required for creating a named type (e.g. an object or a collection). table (IN, optional) - pointer to a table object which specifies a table in the server. This parameter can be set to NULL if no table is given. See the description below to find out how the table object and the TDO are used together to determine the kind of instances (persistent, transient, value) to be created. Also see OCIObjectPinTable() for retrieving a table object. duration (IN) - this is an overloaded parameter. The use of this parameter is based on the kind of the instance that is to be created. a) persistent object. This parameter specifies the pin duration. b) transient object. This parameter specififes the allocation duration and pin duration. c) value. This parameter specifies the allocation duration. value (IN) - specifies whether the created object is a value. If TRUE, then a value is created. Otherwise, a referenceable object is created. If the instance is not an object, then this parameter is ignored. instance (OUT) - address of the newly created instance REQUIRES: - a valid OCI environment handle must be given. DESCRIPTION: This function creates a new instance of the type specified by the typecode or the TDO. Based on the parameters 'typecode' (or 'tdo'), 'value' and 'table', different kinds of instances can be created: The parameter 'table' is not NULL? yes no ---------------------------------------------------------------- | object type (value=TRUE) | value | value | ---------------------------------------------------------------- | object type (value=FALSE) | persistent obj | transient obj | type ---------------------------------------------------------------- | built-in type | value | value | ---------------------------------------------------------------- | collection type | value | value | ---------------------------------------------------------------- This function allocates the top level memory chunk of an OTS instance. The attributes in the top level memory are initialized (e.g. an attribute of varchar2 is initialized to a vstring of 0 length). If the instance is an object, the object is marked existed but is atomically null. FOR PERSISTENT OBJECTS: The object is marked dirty and existed. The allocation duration for the object is session. The object is pinned and the pin duration is specified by the given parameter 'duration'. FOR TRANSIENT OBJECTS: The object is pinned. The allocation duration and the pin duration are specified by the given parameter 'duration'. FOR VALUES: The allocation duration is specified by the given parameter 'duration'. RETURNS: if environment handle or error handle is null, return OCI_INVALID_HANDLE. if operation suceeds, return OCI_SUCCESS. if operation fails, return OCI_ERROR. } {--------------------------- OCIObjectPin ---------------------------------- } POCIComplexObject = Pointer; PPOCIComplexObject = ^POCIComplexObject; OCIPinOpt = ub2; OCILockOpt = pub2; TOCIObjectPin = function(env: POCIEnv; err: POCIError; const object_ref: POCIRef; const corhdl: POCIComplexObject; const pin_option: OCIPinOpt; const pin_duration: OCIDuration; const lock_option: OCILockOpt; _object: PPointer): sword; cdecl; { NAME: OCIObjectPin - OCI pin a referenceable object PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). object_ref (IN) - the reference to the object. corhdl (IN) - handle for complex object retrieval. pin_option (IN) - See description below. pin_duration (IN) - The duration of which the object is being accesed by a client. The object is implicitly unpinned at the end of the pin duration. If OCI_DURATION_NULL is passed, there is no pin promotion if the object is already loaded into the cache. If the object is not yet loaded, then the pin duration is set to OCI_DURATION_DEFAULT. lock_option (IN) - lock option (e.g., exclusive). If a lock option is specified, the object is locked in the server. See 'oro.h' for description about lock option. object (OUT) - the pointer to the pinned object. REQUIRES: - a valid OCI environment handle must be given. DESCRIPTION: This function pins a referenceable object instance given the object reference. The process of pinning serves three purposes: 1) locate an object given its reference. This is done by the object cache which keeps track of the objects in the object heap. 2) notify the object cache that an object is being in use. An object can be pinned many times. A pinned object will remain in memory until it is completely unpinned (see OCIObjectUnpin()). 3) notify the object cache that a persistent object is being in use such that the persistent object cannot be aged out. Since a persistent object can be loaded from the server whenever is needed, the memory utilization can be increased if a completely unpinned persistent object can be freed (aged out), even before the allocation duration is expired. Also see OCIObjectUnpin() for more information about unpinning. FOR PERSISTENT OBJECTS: When pinning a persistent object, if it is not in the cache, the object will be fetched from the persistent store. The allocation duration of the object is session. If the object is already in the cache, it is returned to the client. The object will be locked in the server if a lock option is specified. This function will return an error for a non-existent object. A pin option is used to specify the copy of the object that is to be retrieved: 1) If option is OCI_PIN_ANY (pin any), if the object is already in the environment heap, return this object. Otherwise, the object is retrieved from the database. This option is useful when the client knows that he has the exclusive access to the data in a session. 2) If option is OCI_PIN_LATEST (pin latest), if the object is not cached, it is retrieved from the database. If the object is cached, it is refreshed with the latest version. See OCIObjectRefresh() for more information about refreshing. 3) If option is OCI_PIN_RECENT (pin recent), if the object is loaded into the cache in the current transaction, the object is returned. If the object is not loaded in the current transaction, the object is refreshed from the server. FOR TRANSIENT OBJECTS: This function will return an error if the transient object has already been freed. This function does not return an error if an exclusive lock is specified in the lock option. RETURNS: if environment handle or error handle is null, return OCI_INVALID_HANDLE. if operation suceeds, return OCI_SUCCESS. if operation fails, return OCI_ERROR. } {------------------------------ OCIObjectUnpin ----------------------------- } TOCIObjectUnpin = function(env: POCIEnv; err: POCIError; const _object: Pointer): sword; cdecl; { NAME: OCIObjectUnpin - OCI unpin a referenceable object PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). object (IN) - pointer to an object REQUIRES: - a valid OCI environment handle must be given. - The specified object must be pinned. DESCRIPTION: This function unpins an object. An object is completely unpinned when 1) the object was unpinned N times after it has been pinned N times (by calling OCIObjectPin()). 2) it is the end of the pin duration 3) the function OCIObjectPinCountReset() is called There is a pin count associated with each object which is incremented whenever an object is pinned. When the pin count of the object is zero, the object is said to be completely unpinned. An unpinned object can be freed without error. FOR PERSISTENT OBJECTS: When a persistent object is completely unpinned, it becomes a candidate for aging. The memory of an object is freed when it is aged out. Aging is used to maximize the utilization of memory. An dirty object cannot be aged out unless it is flushed. FOR TRANSIENT OBJECTS: The pin count of the object is decremented. A transient can be freed only at the end of its allocation duration or when it is explicitly deleted by calling OCIObjectFree(). FOR VALUE: This function will return an error for value. RETURNS: if environment handle or error handle is null, return OCI_INVALID_HANDLE. if operation suceeds, return OCI_SUCCESS. if operation fails, return OCI_ERROR. } {---------------------------- OCIObjectPinCountReset ----------------------- } TOCIObjectPinCountReset = function (env: POCIEnv; err: POCIError; const _object: pointer): sword; cdecl; { NAME: OCIObjectPinCountReset - OCI resets the pin count of a referenceable object PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). object (IN) - pointer to an object REQUIRES: - a valid OCI environment handle must be given. - The specified object must be pinned. DESCRIPTION: This function completely unpins an object. When an object is completely unpinned, it can be freed without error. FOR PERSISTENT OBJECTS: When a persistent object is completely unpinned, it becomes a candidate for aging. The memory of an object is freed when it is aged out. Aging is used to maximize the utilization of memory. An dirty object cannot be aged out unless it is flushed. FOR TRANSIENT OBJECTS: The pin count of the object is decremented. A transient can be freed only at the end of its allocation duration or when it is explicitly freed by calling OCIObjectFree(). FOR VALUE: This function will return an error for value. RETURNS: if environment handle or error handle is null, return OCI_INVALID_HANDLE. if operation suceeds, return OCI_SUCCESS. if operation fails, return OCI_ERROR. } {--------------------------- OCIObjectLock --------------------------------- } TOCIObjectLock = function(env: POCIEnv; err: POCIError; const _object: pointer): sword; cdecl; { NAME: OCIObjectLock - OCI lock a persistent object PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). object (IN) - pointer to the persistent object REQUIRES: - a valid OCI environment handle must be given. - The specified object must be pinned. DESCRIPTION: This function locks a persistent object at the server. Unlike OCIObjectLockNoWait() this function waits if another user currently holds a lock on the desired object. This function returns an error if: 1) the object is non-existent. This function will return an error for transient objects and values. The lock of an object is released at the end of a transaction. RETURNS: if environment handle or error handle is null, return OCI_INVALID_HANDLE. if operation suceeds, return OCI_SUCCESS. if operation fails, return OCI_ERROR. } {------------------------ OCIObjectLockNoWait ------------------------------ } TOCIObjectLockNoWait = function(env: POCIEnv; err: POCIError; const _object: pointer): sword; cdecl; { NAME: OCIObjectLockNoWait - OCI lock a persistent object, do not wait for the lock, return error if lock not available PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). object (IN) - pointer to the persistent object REQUIRES: - a valid OCI environment handle must be given. - The specified object must be pinned. DESCRIPTION: This function locks a persistent object at the server. Unlike OCIObjectLock() this function will not wait if another user holds the lock on the desired object. This function returns an error if: 1) the object is non-existent. 2) the object is currently locked by another user in which case this function returns with an error. This function will return an error for transient objects and values. The lock of an object is released at the end of a transaction. RETURNS: if environment handle or error handle is null, return OCI_INVALID_HANDLE. if operation suceeds, return OCI_SUCCESS. if operation fails, return OCI_ERROR. } {--------------------------- OCIObjectMarkUpdate --------------------------- } TOCIObjectMarkUpdate = function(env: POCIEnv; err: POCIError; const _object: pointer): sword; cdecl; { NAME: OCIObjectMarkUpdate - OCI marks an object as updated PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). object (IN) - pointer to the persistent object REQUIRES: - a valid OCI environment handle must be given. - The specified object must be pinned. DESCRIPTION: FOR PERSISTENT OBJECTS: This function marks the specified persistent object as updated. The persistent objects will be written to the server when the object cache is flushed. The object is not locked or flushed by this function. It is an error to update a deleted object. After an object is marked updated and flushed, this function must be called again to mark the object as updated if it has been dirtied after it is being flushed. FOR TRANSIENT OBJECTS: This function marks the specified transient object as updated. The transient objects will NOT be written to the server. It is an error to update a deleted object. FOR VALUES: It is an no-op for values. RETURNS: if environment handle or error handle is null, return OCI_INVALID_HANDLE. if operation suceeds, return OCI_SUCCESS. if operation fails, return OCI_ERROR. } {----------------------------- OCIObjectUnmark ----------------------------- } TOCIObjectUnmark = function(env: POCIEnv; err: POCIError; const _object:pointer): sword; cdecl; { NAME: OCIObjectUnmark - OCI unmarks an object PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). object (IN) - pointer to the persistent object REQUIRES: - a valid OCI environment handle must be given. - The specified object must be pinned. DESCRIPTION: FOR PERSISTENT OBJECTS AND TRANSIENT OBJECTS: This function unmarks the specified persistent object as dirty. Changes that are made to the object will not be written to the server. If the object is marked locked, it remains marked locked. The changes that have already made to the object will not be undone implicitly. FOR VALUES: It is an no-op for values. RETURNS: if environment handle or error handle is null, return OCI_INVALID_HANDLE. if operation suceeds, return OCI_SUCCESS. if operation fails, return OCI_ERROR. } {----------------------------- OCIObjectUnmarkByRef ------------------------ } TOCIObjectUnmarkByRef = function(env: POCIEnv; err: POCIError; const ref: POCIRef): sword; cdecl; { NAME: OCIObjectUnmarkByRef - OCI unmarks an object by Ref PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). ref (IN) - reference of the object REQUIRES: - a valid OCI environment handle must be given. - The specified object must be pinned. DESCRIPTION: FOR PERSISTENT OBJECTS AND TRANSIENT OBJECTS: This function unmarks the specified persistent object as dirty. Changes that are made to the object will not be written to the server. If the object is marked locked, it remains marked locked. The changes that have already made to the object will not be undone implicitly. FOR VALUES: It is an no-op for values. RETURNS: if environment handle or error handle is null, return OCI_INVALID_HANDLE. if operation suceeds, return OCI_SUCCESS. if operation fails, return OCI_ERROR. } {--------------------------- OCIObjectFree --------------------------------- } TOCIObjectFree = function(env: POCIEnv; err: POCIError; const instance: pointer; const flags: ub2): sword; cdecl; { NAME: OCIObjectFree - OCI free (and unpin) an standalone instance PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). instance (IN) - pointer to a standalone instance. flags (IN) - If OCI_OBJECT_FREE_FORCE is set, free the object even if it is pinned or dirty. If OCI_OBJECT_FREE_NONULL is set, the null structure will not be freed. REQUIRES: - a valid OCI environment handle must be given. - The instance to be freed must be standalone. - If the instance is a referenceable object, the object must be pinned. DESCRIPTION: This function deallocates all the memory allocated for an OTS instance, including the null structure. FOR PERSISTENT OBJECTS: This function will return an error if the client is attempting to free a dirty persistent object that has not been flushed. The client should either flush the persistent object or set the parameter 'flag' to OCI_OBJECT_FREE_FORCE. This function will call OCIObjectUnpin() once to check if the object can be completely unpin. If it succeeds, the rest of the function will proceed to free the object. If it fails, then an error is returned unless the parameter 'flag' is set to OCI_OBJECT_FREE_FORCE. Freeing a persistent object in memory will not change the persistent state of that object at the server. For example, the object will remain locked after the object is freed. FOR TRANSIENT OBJECTS: This function will call OCIObjectUnpin() once to check if the object can be completely unpin. If it succeeds, the rest of the function will proceed to free the object. If it fails, then an error is returned unless the parameter 'flag' is set to OCI_OBJECT_FREE_FORCE. FOR VALUES: The memory of the object is freed immediately. RETURNS: if environment handle or error handle is null, return OCI_INVALID_HANDLE. if operation suceeds, return OCI_SUCCESS. if operation fails, return OCI_ERROR. } {----------------------- OCIObjectMarkDeleteByRef -------------------------- } TOCIObjectMarkDeleteByRef = function(env: POCIEnv; err: POCIError; const object_ref:POCIRef): sword; cdecl; { NAME: OCIObjectMarkDeleteByRef - OCI "delete" (and unpin) an object given a reference PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). object_ref (IN) - ref of the object to be deleted REQUIRES: - a valid OCI environment handle must be given. DESCRIPTION: This function marks the object designated by 'object_ref' as deleted. FOR PERSISTENT OBJECTS: If the object is not loaded, then a temporary object is created and is marked deleted. Otherwise, the object is marked deleted. The object is deleted in the server when the object is flushed. FOR TRANSIENT OBJECTS: The object is marked deleted. The object is not freed until it is unpinned. RETURNS: if environment handle or error handle is null, return OCI_INVALID_HANDLE. if operation suceeds, return OCI_SUCCESS. if operation fails, return OCI_ERROR. } {--------------------------- OCIObjectMarkDelete --------------------------- } TOCIObjectMarkDelete = function(env: POCIEnv; err: POCIError; const instance:pointer): sword; cdecl; { NAME: OCIObjectMarkDelete - OCI "delete" an instance given a Pointer PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). instance (IN) - pointer to the instance REQUIRES: - a valid OCI environment handle must be given. - The instance must be standalone. - If the instance is a referenceable object, then it must be pinned. DESCRIPTION: FOR PERSISTENT OBJECTS: The object is marked deleted. The memory of the object is not freed. The object is deleted in the server when the object is flushed. FOR TRANSIENT OBJECTS: The object is marked deleted. The memory of the object is not freed. FOR VALUES: This function frees a value immediately. RETURNS: if environment handle or error handle is null, return OCI_INVALID_HANDLE. if operation suceeds, return OCI_SUCCESS. if operation fails, return OCI_ERROR. } {---------------------------- OCIObjectFlush ------------------------------- } TOCIObjectFlush = function(env: POCIEnv; err: POCIError; const _object: pointer): sword; cdecl; { NAME: OCIObjectFlush - OCI flush a persistent object PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). object (IN) - pointer to the persistent object REQUIRES: - a valid OCI environment handle must be given. - The specified object must be pinned. DESCRIPTION: This function flushes a modified persistent object to the server. An exclusive lock is obtained implicitly for the object when flushed. When the object is written to the server, triggers may be fired. Objects can be modified by the triggers at the server. To keep the objects in the object cache being coherent with the database, the clients can free or refresh the objects in the cache. This function will return an error for transient objects and values. RETURNS: if environment handle or error handle is null, return OCI_INVALID_HANDLE. if operation suceeds, return OCI_SUCCESS. if operation fails, return OCI_ERROR. } {------------------------ OCIObjectRefresh --------------------------------- } TOCIObjectRefresh = function(env: POCIEnv; err: POCIError; _object: pointer): sword; cdecl; { NAME: OCIObjectRefresh - OCI refresh a persistent object PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). object (IN) - pointer to the persistent object REQUIRES: - a valid OCI environment handle must be given. - The specified object must be pinned. DESCRIPTION: This function refreshes an unmarked object with data retrieved from the latest snapshot in the server. An object should be refreshed when the objects in the cache are inconsistent with the objects at the server: 1) When an object is flushed to the server, triggers can be fired to modify more objects in the server. The same objects (modified by the triggers) in the object cache become obsolete. 2) When the user issues a SQL or executes a PL/SQL procedure to modify any object in the server, the same object in the cache becomes obsolete. The object that is refreshed will be 'replaced-in-place'. When an object is 'replaced-in-place', the top level memory of the object will be reused so that new data can be loaded into the same memory address. The top level memory of the null structre is also reused. Unlike the top level memory chunk, the secondary memory chunks may be resized and reallocated. The client should be careful when holding onto a pointer to the secondary memory chunk (e.g. assigning the address of a secondary memory to a local variable), since this pointer can become invalid after the object is refreshed. The object state will be modified as followed after being refreshed: - existent : set to appropriate value - pinned : unchanged - allocation duration : unchanged - pin duration : unchanged This function is an no-op for transient objects or values. RETURNS: if environment handle or error handle is null, return OCI_INVALID_HANDLE. if operation suceeds, return OCI_SUCCESS. if operation fails, return OCI_ERROR. } {---------------------------- OCIObjectCopy -------------------------------- } TOCIObjectCopy = function(env: POCIEnv; err: POCIError; const svc: POCISvcCtx; const source, null_source, target, null_target: pointer; const tdo: POCIType; const duration: OCIDuration; const option: ub1): sword; cdecl; { NAME: OCIObjectCopy - OCI copy one instance to another PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). svc (IN) - OCI service context handle source (IN) - pointer to the source instance null_source (IN) - pointer to the null structure of the source target (IN) - pointer to the target instance null_target (IN) - pointer to the null structure of the target tdo (IN) - the TDO for both source and target duration (IN) - allocation duration of the target memory option (IN) - specify the copy option: OROOCOSFN - Set Reference to Null. All references in the source will not be copied to the target. The references in the target are set to null. REQUIRES: - a valid OCI environment handle must be given. - If source or target is referenceable, it must be pinned. - The target or the containing instance of the target must be already be instantiated (e.g. created by OCIObjectNew()). - The source and target instances must be of the same type. If the source and target are located in a different databases, then the same type must exist in both databases. DESCRIPTION: This function copies the contents of the 'source' instance to the 'target' instance. This function performs a deep-copy such that the data that is copied/duplicated include: a) all the top level attributes (see the exceptions below) b) all the secondary memory (of the source) that is reachable from the top level attributes. c) the null structure of the instance Memory is allocated with the specified allocation duration. Certain data items are not copied: a) If the option OCI_OBJECTCOPY_NOREF is specified, then all references in the source are not copied. Instead, the references in the target are set to null. b) If the attribute is a LOB, then it is set to null. RETURNS: if environment handle or error handle is null, return OCI_INVALID_HANDLE. if operation suceeds, return OCI_SUCCESS. if operation fails, return OCI_ERROR. } {---------------------------- OCIObjectGetTypeRef -------------------------- } TOCIObjectGetTypeRef = function(env: POCIEnv; err: POCIError; const instance:pointer; type_ref: POCIRef): sword; cdecl; { NAME: OCIObjectGetTypeRef - get the type reference of a standalone object PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). instance (IN) - pointer to an standalone instance type_ref (OUT) - reference to the type of the object. The reference must already be allocated. REQUIRES: - a valid OCI environment handle must be given. - The instance must be standalone. - If the object is referenceable, the specified object must be pinned. - The reference must already be allocated. DESCRIPTION: This function returns a reference to the TDO of a standalone instance. RETURNS: if environment handle or error handle is null, return OCI_INVALID_HANDLE. if operation suceeds, return OCI_SUCCESS. if operation fails, return OCI_ERROR. } {--------------------------- OCIObjectGetObjectRef ------------------------- } TOCIObjectGetObjectRef = function(env: POCIEnv; err: POCIError; const _object: pointer; bject_ref: POCIRef): sword; cdecl; { NAME: OCIObjectGetObjectRef - OCI get the object reference of an referenceable object PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). object (IN) - pointer to a persistent object object_ref (OUT) - reference of the given object. The reference must already be allocated. REQUIRES: - a valid OCI environment handle must be given. - The specified object must be pinned. - The reference must already be allocated. DESCRIPTION: This function returns a reference to the given object. It returns an error for values. RETURNS: if environment handle or error handle is null, return OCI_INVALID_HANDLE. if operation suceeds, return OCI_SUCCESS. if operation fails, return OCI_ERROR. } {--------------------------- OCIObjectMakeObjectRef ----------------------- } TOCIObjectMakeObjectRef = function(env: POCIEnv; err: POCIError; const svc: POCISvcCtx; const table: pointer; const values: PPointer; const array_len: ub4; object_ref: POCIRef): sword; cdecl; { NAME: OCIObjectMakeObjectRef - OCI Create an object reference to a referenceable object. PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). svc (IN) - the service context table (IN) - A pointer to the table object (must be pinned) attrlist (IN) - A list of values (OCI type values) from which the ref is to be created. attrcnt (IN) - The length of the attrlist array. object_ref (OUT) - reference of the given object. The reference must already be allocated. REQUIRES: - a valid OCI environment handle must be given. - The specified table object must be pinned. - The reference must already be allocated. DESCRIPTION: This function creates a reference given the values that make up the reference and also a pointer to the table object. Based on the table's OID property, whether it is a pk based OID or a system generated OID, the function creates a sys-generated REF or a pk based REF. In case of system generated REFs pass in a OCIRaw which is 16 bytes long contatining the sys generated OID. In case of PK refs pass in the OCI equivalent for numbers, chars etc.. RETURNS: if environment handle or error handle is null, return OCI_INVALID_HANDLE. if operation suceeds, return OCI_SUCCESS. if operation fails, return OCI_ERROR. } {--------------------------- OCIObjectGetPrimaryKeyTypeRef --------------- } TOCIObjectGetPrimaryKeyTypeRef = function(env: POCIEnv; err: POCIError; const svc:POCISvcCtx; const table: pointer; type_ref: POCIRef): sword; cdecl; { NAME: OCIObjectGetPrimaryKeyTypeRef - OCI get the REF to the pk OID type PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). svc (IN) - the service context table (IN) - pointer to the table object type_ref (OUT) - reference of the pk type. The reference must already be allocated. REQUIRES: - a valid OCI environment handle must be given. - The specified table object must be pinned. - The reference must already be allocated. DESCRIPTION: This function returns a reference to the pk type. It returns an error for values. If the table is not a Pk oid table/view, then it returns error. RETURNS: if environment handle or error handle is null, return OCI_INVALID_HANDLE. if operation suceeds, return OCI_SUCCESS. if operation fails, return OCI_ERROR. } {-------------------------- OCIObjectGetInd -------------------------------- } TOCIObjectGetInd = function(env: POCIEnv; err: POCIError; const instance: pointer; null_struct: PPointer): sword; cdecl; { NAME: OCIObjectGetInd - OCI get the null structure of a standalone object PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). instance (IN) - pointer to the instance null_struct (OUT) - null structure REQUIRES: - a valid OCI environment handle must be given. - The object must be standalone. - If the object is referenceable, the specified object must be pinned. DESCRIPTION: This function returns the null structure of an instance. This function will allocate the top level memory of the null structure if it is not already allocated. If an null structure cannot be allocated for the instance, then an error is returned. This function only works for ADT or row type instance. RETURNS: if environment handle or error handle is null, return OCI_INVALID_HANDLE. if operation suceeds, return OCI_SUCCESS. if operation fails, return OCI_ERROR. } {------------------------- OCIObjectExists -------------------------------- } TOCIObjectExists = function(env: POCIEnv; err: POCIError; const ins: pointer; exist: PBoolean): sword; cdecl; { NAME: OCIObjectExist - OCI checks if the object exists PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). ins (IN) - pointer to an instance exist (OUT) - return TRUE if the object exists REQUIRES: - a valid OCI environment handle must be given. - The object must be standalone. - if object is a referenceable, it must be pinned. DESCRIPTION: This function returns the existence of an instance. If the instance is a value, this function always returns TRUE. RETURNS: if environment handle or error handle is null, return OCI_INVALID_HANDLE. if operation suceeds, return OCI_SUCCESS. if operation fails, return OCI_ERROR. } {------------------------- OCIObjectGetProperty --------------------------- } TOCIObjectGetProperty = function(envh: POCIEnv; errh: POCIError; const obj: pointer; const propertyId: OCIObjectPropId; _property: pointer; size: Pub4): sword; cdecl; { NAME: OCIObjectGetProperty - OCIObject Get Property of given object PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). obj (IN) - object whose property is returned propertyId (IN) - id which identifies the desired property property (OUT) - buffer into which the desired property is copied size (IN/OUT) - on input specifies the size of the property buffer passed by caller, on output will contain the size in bytes of the property returned. This parameter is required for string type properties only (e.g OCI_OBJECTPROP_SCHEMA, OCI_OBJECTPROP_TABLE). For non-string properties this parameter is ignored since the size is fixed. DESCRIPTION: This function returns the specified property of the object. The desired property is identified by 'propertyId'. The property value is copied into 'property' and for string typed properties the string size is returned via 'size'. Objects are classified as persistent, transient and value depending upon the lifetime and referenceability of the object. Some of the properties are applicable only to persistent objects and some others only apply to persistent and transient objects. An error is returned if the user tries to get a property which in not applicable to the given object. To avoid such an error, the user should first check whether the object is persistent or transient or value (OCI_OBJECTPROP_LIFETIME property) and then appropriately query for other properties. The different property ids and the corresponding type of 'property' argument is given below. OCI_OBJECTPROP_LIFETIME This identifies whether the given object is a persistent object (OCI_OBJECT_PERSISTENT) or a transient object (OCI_OBJECT_TRANSIENT) or a value instance (OCI_OBJECT_VALUE). 'property' argument must be a pointer to a variable of type OCIObjectLifetime. OCI_OBJECTPROP_SCHEMA This returns the schema name of the table in which the object exists. An error is returned if the given object points to a transient instance or a value. If the input buffer is not big enough to hold the schema name an error is returned, the error message will communicate the required size. Upon success, the size of the returned schema name in bytes is returned via 'size'. 'property' argument must be an array of type text and 'size' should be set to size of array in bytes by the caller. OCI_OBJECTPROP_TABLE This returns the table name in which the object exists. An error is returned if the given object points to a transient instance or a value. If the input buffer is not big enough to hold the table name an error is returned, the error message will communicate the required size. Upon success, the size of the returned table name in bytes is returned via 'size'. 'property' argument must be an array of type text and 'size' should be set to size of array in bytes by the caller. OCI_OBJECTPROP_PIN_DURATION This returns the pin duration of the object. An error is returned if the given object points to a value instance. Valid pin durations are: OCI_DURATION_SESSION and OCI_DURATION_TRANS. 'property' argument must be a pointer to a variable of type OCIDuration. OCI_OBJECTPROP_ALLOC_DURATION This returns the allocation duration of the object. Valid allocation durations are: OCI_DURATION_SESSION and OCI_DURATION_TRANS. 'property' argument must be a pointer to a variable of type OCIDuration. OCI_OBJECTPROP_LOCK This returns the lock status of the object. The possible lock status is enumerated by OCILockOpt. An error is returned if the given object points to a transient or value instance. 'property' argument must be a pointer to a variable of type OCILockOpt. Note, the lock status of an object can also be retrieved by calling OCIObjectIsLocked(). OCI_OBJECTPROP_MARKSTATUS This returns the status flag which indicates whether the object is a new object, updated object and/or deleted object. The following macros can be used to test the mark status flag: OCI_OBJECT_IS_UPDATED(flag) OCI_OBJECT_IS_DELETED(flag) OCI_OBJECT_IS_NEW(flag) OCI_OBJECT_IS_DIRTY(flag) An object is dirty if it is a new object or marked deleted or marked updated. An error is returned if the given object points to a transient or value instance. 'property' argument must be of type OCIObjectMarkStatus. OCI_OBJECTPROP_VIEW This identifies whether the specified object is a view object or not. If property value returned is TRUE, it indicates the object is a view otherwise it is not. 'property' argument must be of type boolean. RETURNS: if environment handle or error handle is null, return OCI_INVALID_HANDLE. if operation suceeds, return OCI_SUCCESS. if operation fails, return OCI_ERROR. Possible errors are TBD } {---------------------------- OCIObjectIsLocked -------------------------- } TOCIObjectIsLocked = function(env: POCIEnv; err: POCIError; const ins: pointer; lock: Pboolean): sword; cdecl; { NAME: OCIObjectIsLocked - OCI get the lock status of a standalone object PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). ins (IN) - pointer to an instance lock (OUT) - return value for the lock status. REQUIRES: - a valid OCI environment handle must be given. - The instance must be standalone. - If the object is referenceable, the specified object must be pinned. DESCRIPTION: This function returns the lock status of an instance. If the instance is a value, this function always returns FALSE. RETURNS: if environment handle or error handle is null, return OCI_INVALID_HANDLE. if operation suceeds, return OCI_SUCCESS. if operation fails, return OCI_ERROR. } {------------------------- OCIObjectIsDirty ------------------------------ } TOCIObjectIsDirty = function(env: POCIEnv; err: POCIError; const ins: pointer; dirty:Pboolean): sword; cdecl; { NAME: OCIObjectIsDirty - OCI get the dirty status of a standalone object PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). ins (IN) - pointer to an instance dirty (OUT) - return value for the dirty status. REQUIRES: - a valid OCI environment handle must be given. - The instance must be standalone. - if instance is an object, the instance must be pinned. DESCRIPTION: This function returns the dirty status of an instance. If the instance is a value, this function always returns FALSE. RETURNS: if environment handle or error handle is null, return OCI_INVALID_HANDLE. if operation suceeds, return OCI_SUCCESS. if operation fails, return OCI_ERROR. } {--------------------------- OCIObjectPinTable ----------------------------- } TOCIObjectPinTable = function(env: POCIEnv; err: POCIError; const svc:POCISvcCtx; const schema_name: Poratext; const s_n_length: ub4; const object_name: Poratext; const o_n_length:ub4; const scope_obj_ref: POCIRef; const pin_duration: OCIDuration; _object: PPointer): sword; cdecl; { NAME: OCIObjectPinTable - OCI get table object PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). svc (IN) - OCI service context handle schema_name (IN, optional) - schema name of the table s_n_length (IN, optional) - length of the schema name object_name (IN) - name of the table o_n_length (IN) - length of the table name scope_obj_ref (IN, optional) - reference of the scoping object pin_duration (IN) - pin duration. See description in OCIObjectPin(). object (OUT) - the pinned table object REQUIRES: - a valid OCI environment handle must be given. DESCRIPTION: This function pin a table object with the specified pin duration. The client can unpin the object by calling OCIObjectUnpin(). See OCIObjectPin() and OCIObjectUnpin() for more information about pinning and unpinning. RETURNS: if environment handle or error handle is null, return OCI_INVALID_HANDLE. if operation suceeds, return OCI_SUCCESS. if operation fails, return OCI_ERROR. } {------------------------- OCIObjectArrayPin ------------------------------- } TOCIObjectArrayPin = function(env: POCIEnv; err: POCIError; const ref_array: PPOCIRef; const array_size: ub4; const cor_array: PPOCIComplexObject; const cor_array_size: ub4; const pin_option: OCIPinOpt; const pin_duration: OCIDuration; const lock: OCILockOpt; obj_array: PPointer; pos: Pub4): sword; cdecl; { NAME: OCIObjectArrayPin - ORIO array pin PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). ref_array (IN) - array of references to be pinned array_size (IN) - number of elements in the array of references pin_option (IN) - pin option. See OCIObjectPin(). pin_duration (IN) - pin duration. See OCIObjectPin(). lock_option (IN) - lock option. See OCIObjectPin(). obj_array (OUT) - If this argument is not NULL, the pinned objects will be returned in the array. The user must allocate this array with element type being 'void *'. The size of this array is identical to 'array'. pos (OUT) - If there is an error, this argument will contain the element that is causing the error. Note that this argument is set to 1 for the first element in the ref_array. REQUIRE: - a valid OCI environment handle must be given. - If 'obj_array' is not NULL, then it must already be allocated and the size of 'obj_array' is 'array_size'. DESCRIPTION: This function pin an array of references. All the pinned objects are retrieved from the database in one network roundtrip. If the user specifies an output array ('obj_array'), then the address of the pinned objects will be assigned to the elements in the array. See OCIObjectPin() for more information about pinning. RETURNS: if environment handle or error handle is null, return OCI_INVALID_HANDLE. if operation suceeds, return OCI_SUCCESS. if operation fails, return OCI_ERROR. } {--------------------------------------------------------------------------- } { HEAP/CACHE OPERATIONS } {--------------------------------------------------------------------------- } {--------------------------- OCICacheFlush --------------------------------- } TOCICacheFlushGet = function(context: pointer; last: Pub1): POCIRef; cdecl; TOCICacheFlush = function(env: POCIEnv; err: POCIError; const svc:POCISvcCtx; const context: pointer; const get: TOCICacheFlushGet; ref: PPOCIRef): sword; cdecl; { NAME: OCICacheFlush - OCI flush persistent objects PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). svc (IN) [optional] - OCI service context. If null pointer is specified, then the dirty objects in all connections will be flushed. context (IN) [optional] - specifies an user context that is an argument to the client callback function 'get'. This parameter is set to NULL if there is no user context. get (IN) [optional] - an client-defined function which acts an iterator to retrieve a batch of dirty objects that need to be flushed. If the function is not NULL, this function will be called to get a reference of a dirty object. This is repeated until a null reference is returned by the client function or the parameter 'last' is set to TRUE. The parameter 'context' is passed to get() for each invocation of the client function. This parameter should be NULL if user callback is not given. If the object that is returned by the client function is not a dirtied persistent object, the object is ignored. All the objects that are returned from the client function must be from newed or pinned the same service context, otherwise, an error is signalled. Note that the returned objects are flushed in the order in which they are marked dirty. ref (OUT) [optional] - if there is an error in flushing the objects, (*ref) will point to the object that is causing the error. If 'ref' is NULL, then the object will not be returned. If '*ref' is NULL, then a reference will be allocated and set to point to the object. If '*ref' is not NULL, then the reference of the object is copied into the given space. If the error is not caused by any of the dirtied object, the given ref is initalized to be a NULL reference (OCIRefIsNull(*ref) is TRUE). REQUIRES: - a valid OCI environment handle must be given. DESCRIPTION: This function flushes the modified persistent objects from the environment heap to the server. The objects are flushed in the order that they are marked updated or deleted. See OCIObjectFlush() for more information about flushing. RETURNS: if environment handle or error handle is null, return OCI_INVALID_HANDLE. if operation suceeds, return OCI_SUCCESS. if operation fails, return OCI_ERROR. } {--------------------------- OCICacheRefresh ------------------------------- } TOCICacheRefreshGet = function(context: pointer): POCIRef; cdecl; TOCICacheRefresh = function(env: POCIEnv; err: POCIError; const svc: POCISvcCtx; const option: OCIRefreshOpt; const context: pointer; get: TOCICacheRefreshGet; ref: PPOCIRef): sword; cdecl; { NAME: OCICacheRefresh - OCI ReFreSh persistent objects PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). svc (IN) [optional] - OCI service context. If null pointer is specified, then the persistent objects in all connections will be refreshed. option (IN) [optional] - if OCI_REFRESH_LOAD is specified, all objects that is loaded within the transaction are refreshed. If the option is OCI_REFERSH_LOAD and the parameter 'get' is not NULL, this function will ignore the parameter. context (IN) [optional] - specifies an user context that is an argument to the client callback function 'get'. This parameter is set to NULL if there is no user context. get (IN) [optional] - an client-defined function which acts an iterator to retrieve a batch of objects that need to be refreshed. If the function is not NULL, this function will be called to get a reference of an object. If the reference is not NULL, then the object will be refreshed. These steps are repeated until a null reference is returned by this function. The parameter 'context' is passed to get() for each invocation of the client function. This parameter should be NULL if user callback is not given. ref (OUT) [optional] - if there is an error in refreshing the objects, (*ref) will point to the object that is causing the error. If 'ref' is NULL, then the object will not be returned. If '*ref' is NULL, then a reference will be allocated and set to point to the object. If '*ref' is not NULL, then the reference of the object is copied into the given space. If the error is not caused by any of the object, the given ref is initalized to be a NULL reference (OCIRefIsNull(*ref) is TRUE). REQUIRES: - a valid OCI environment handle must be given. DESCRIPTION: This function refreshes all pinned persistent objects. All unpinned persistent objects are freed. See OCIObjectRefresh() for more information about refreshing. RETURNS: if environment handle or error handle is null, return OCI_INVALID_HANDLE. if operation suceeds, return OCI_SUCCESS. if operation fails, return OCI_ERROR. } {---------------------------- OCICacheUnpin -------------------------------- } TOCICacheUnpin = function(env: POCIEnv; err: POCIError; const svc:POCISvcCtx): sword; cdecl; { NAME: OCICacheUnpin - OCI UNPin objects PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). svc (IN) [optional] - OCI service context. If null pointer is specified, then the objects in all connections will be unpinned. REQUIRES: - a valid OCI environment handle must be given. DESCRIPTION: If a connection is specified, this function completely unpins the persistent objects in that connection. Otherwise, all persistent objects in the heap are completely unpinned. All transient objects in the heap are also completely unpinned. See OCIObjectUnpin() for more information about unpinning. RETURNS: if environment handle or error handle is null, return OCI_INVALID_HANDLE. if operation suceeds, return OCI_SUCCESS. if operation fails, return OCI_ERROR. } {----------------------------- OCICacheFree -------------------------------- } TOCICacheFree = function(env: POCIEnv; err: POCIError; const svc: POCISvcCtx): sword; cdecl; { NAME: OCICacheFree - OCI FREe instances PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). svc (IN) [optional] - OCI service context. If null pointer is specified, then the objects in all connections will be freed. REQUIRES: - a valid OCI environment handle must be given. DESCRIPTION: If a connection is specified, this function frees the persistent objects, transient objects and values allocated for that connection. Otherwise, all persistent objects, transient objects and values in the heap are freed. Objects are freed regardless of their pin count. See OCIObjectFree() for more information about freeing an instance. RETURNS: if environment handle or error handle is null, return OCI_INVALID_HANDLE. if operation suceeds, return OCI_SUCCESS. if operation fails, return OCI_ERROR. } {---------------------------- OCICacheUnmark ------------------------------- } TOCICacheUnmark = function(env: POCIEnv; err: POCIError; const svc: POCISvcCtx): sword; cdecl; { NAME: OCICacheUnmark - OCI Unmark all dirty objects PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). svc (IN) [optional] - OCI service context. If null pointer is specified, then the objects in all connections will be unmarked. REQUIRES: - a valid OCI environment handle must be given. DESCRIPTION: If a connection is specified, this function unmarks all dirty objects in that connection. Otherwise, all dirty objects in the cache are unmarked. See OCIObjectUnmark() for more information about unmarking an object. RETURNS: if environment handle or error handle is null, return OCI_INVALID_HANDLE. if operation suceeds, return OCI_SUCCESS. if operation fails, return OCI_ERROR. } TOCIDurationBegin = function(env: POCIEnv; err: POCIError; svc: POCISvcCtx; const parent: OCIDuration; dur: POCIDuration): sword; cdecl; { NAME: OCIDurationBegin - OCI DURATION BEGIN PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode This should be passed NULL, when cartridge services are to be used. err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). svc (IN/OUT) - OCI service handle. parent (IN) - parent for the duration to be started. dur (OUT) - newly created user duration REQUIRES: - a valid OCI environment handle must be given for non-cartridge services. - For cartridge services, NULL should be given for environment handle - A valid service handle must be given in all cases. DESCRIPTION: This function starts a new user duration. A user can have multiple active user durations simultaneously. The user durations do not have to be nested. The object subsystem predefines 3 durations : 1) session - memory allocated with session duration comes from the UGA heap (OCI_DURATION_SESSION). A session duration terminates at the end of the user session. 2) transaction - memory allocated with transaction duration comes from the UGA heap (OCI_DURATION_TRANS). A trans- action duration terminates at the end of the user transaction. 3) call - memory allocated with call duration comes from PGA heap (OCI_DURATION_CALL). A call duration terminates at the end of the user call. Each user duration has a parent duration. A parent duration can be a predefined duration or another user duration. The relationship between a user duration and its parent duration (child duration) are: 1) An user duration is nested within the parent duration. When its parent duration terminates, the user duration will also terminate. 2) The memory allocated with an user duration comes from the heap of its parent duration. For example, if the parent duration of an user duration is call, then the memory allocated with the user duration will also come from the PGA heap. This function can be used as both part of cartridge services as well as without cartridge services. The difference in the function in the case of cartridge and non-cartridge services is: In case of cartridge services, as descibed above a new user duration is created as a child of the "parent" duration. But when used for non-cartridge purposes, when a pre-defined duration is passed in as parent, it is mapped to the cache duration for that connection (which is created if not already present) and the new user duration will be child of the cache duration. RETURNS: if environment handle and service handle is null or if error handle is null return OCI_INVALID_HANDLE. if operation suceeds, return OCI_SUCCESS. if operation fails, return OCI_ERROR. } TOCIDurationEnd = function(env: POCIEnv; err: POCIError; svc: POCISvcCtx; duration: OCIDuration): sword; cdecl; { NAME: OCIDurationEnd - OCI DURATION END PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode This should be passed NULL, when cartridge services are to be used. err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). svc (IN/OUT) - OCI service handle. dur (OUT) - a previously created user duration using OCIDurationBegin() REQUIRES: - a valid OCI environment handle must be given for non-cartridge services. - For cartridge services, NULL should be given for environment handle - A valid service handle must be given in all cases. DESCRIPTION: This function terminates a user duration. All memory allocated for this duration is freed. This function can be used as both part of cartridge services as well as without cartridge services. In both cased, the heap duration is freed and all the allocated memory for that duration is freed. The difference in the function in the case of cartridge and non-cartridge services is: In case of non-cartridge services, if the duration is pre- defined, the associated cache duration (see OCIDurationBegin()) is also terminated and the following is done. 1) The child durations are terminated. 2) All objects pinned for this duration are unpinned. 3) All instances allocated for this duration are freed. In case of cartridge services, only the heap duration is freed. All the context entries allocated for that duration are freed from the context hash table.. RETURNS: if environment handle and service handle is null or if error handle is null return OCI_INVALID_HANDLE. if operation suceeds, return OCI_SUCCESS. if operation fails, return OCI_ERROR. } (*-----------------------------ort.h----------------------------------------*) {----------------------------- TYPE DESCRIPTION ---------------------------- } { * OCIType - OCI Type Description Object * * The contents of an 'OCIType' is private/opaque to clients. Clients just * need to declare and pass 'OCIType' pointers in to the type manage * functions. * The pointer points to the type in the object cache. Thus, clients don't * need to allocate space for this type and must NEVER free the pointer to the * 'OCIType'. } type {------------------------- TYPE ELEMENT DESCRIPTION ------------------------ } { * OCITypeElem - OCI Type Element object * * The contents of an 'OCITypeElem' is private/opaque to clients. Clients just * need to declare and pass 'OCITypeElem' pointers in to the type manager * functions. * * 'OCITypeElem' objects contains type element information such as the numeric * precision for example, for number objects, and the number of elements for * arrays. * They ARE used to describe type attributes, collection elements, * method parameters, and method results. Hence they are pass in or returned * by attribute, collection, and method parameter/result accessors. } {--------------------------- METHOD DESCRIPTION --------------------------- } { * OCITypeMethod - OCI Method Description object * * The contents of an 'OCITypeMethod' is private/opaque to clients. Clients * just need to declare and pass 'OCITypeMethod' pointers in to the type * manager functions. * The pointer points to the method in the object cache. Thus, clients don't * need to allocate space for this type and must NEVER free the pointer to * the 'OCITypeMethod'. } {--------------------------- TYPE ACCESS ITERATOR -------------------------- } { * OCITypeIter- OCI Type Iterator * * The contents of an 'orti' is private/opaque to clients. Clients just * need to declare and pass 'orti' pointers in to the type manager functions. * The iterator is used to retreive MDO's and ADO's that belong to the TDO * one at a time. It needs to be allocated by the 'OCITypeIterNew()' function * call and deallocated with the 'OCITypeIterFree()' function call. } {================== } { PUBLIC FUNCTIONS } {================== } {-------------------------------------------------------------------------- } { ITERATOR } {-------------------------------------------------------------------------- } {-----------------------_- OCITypeIterNew --------------------------------- } { ** OBSOLETE ** } TOCITypeIterNew = function (env: POCIEnv; err: POCIError; const tdo: POCIType; iterator_ort: PPOCITypeIter):sword; cdecl; { NAME: OCITypeIterNew - OCI Iterator NEW PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). tdo (IN) - pointer to the pinned type in the object cache to initialize the iterator with iterator_ort (OUT) - pointer to the pointer to the new iterator created DESCRIPTION: Create a new instance of a method/attribute iterator and initalize it's values. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is null. OCI_ERROR if 1) any of the required parameters is null. 2) error while allocating space for the iterator. } {------------------------ OCITypeIterSet --------------------------------- } { ** OBSOLETE ** } TOCITypeIterSet = function(env: POCIEnv; err: POCIError; const tdo: POCIType; iterator_ort: POCITypeIter): sword; cdecl; { NAME: OCITypeIterSet - OCI Iterator SET PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). tdo (IN) - pointer to the pinned type in the object cache to initialize the iterator with iterator_ort (IN/OUT) - pointer to the iterator to set DESCRIPTION: Initializes the iterator. This is used to reset the state of the iterator. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is null. OCI_ERROR if 1) any of the required parameters is null. } {------------------------ OCITypeIterFree --------------------------------- } { ** OBSOLETE ** } TOCITypeIterFree = function(env: POCIEnv; err: POCIError; iterator_ort: POCITypeIter):sword; { NAME: OCITypeIterFree - OCI Iterator FREe PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). iterator_ort (IN/OUT) - pointer to the iterator to free DESCRIPTION: Free space allocated for the iterator. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is null. OCI_ERROR if 1) any of the required parameters is null. 2) error while freeing the iterator, probably bad iterator pointer. } {-------------------------------------------------------------------------- } { TYPE GET } {-------------------------------------------------------------------------- } { ** OBSOLETE ** } TOCITypeByName = function(env: POCIEnv; err: POCIError; const svc: POCISvcCtx; schema_name: Poratext; const s_length: ub4; const type_name: Poratext; const t_length: ub4; version_name: Poratext; const v_length: ub4; const pin_duration: OCIDuration; const get_option: OCITypeGetOpt; tdo: PPOCIType): sword; cdecl; { NAME: OCITypeByName - OCI Get the most current version of an existing TYPe by name. PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). svc (IN) - OCI service handle schema_name (IN, optional) - name of schema associated with the type. By default, the user's schema name is used. s_length (IN) - length of the 'schema_name' parameter type_name (IN) - name of the type to get t_length (IN) - length of the 'type_name' parameter version_name (IN, optional) - user readable version of the type. Pass (oratext *)0 for the most current version. v_length (IN) - length of version_name in bytes. Should be 0 if the most current version is to be retrieved. pin_duration (IN) - pin duration (e.g. until the end of current transaction). See 'oro.h' for a description of each option. get_option (IN) - options for loading the types. It can be one of two values: OCI_TYPEGET_HEADER for only the header to be loaded, or OCI_TYPEGET_ALL for the TDO and all ADO and MDOs to be loaded. tdo (OUT) - pointer to the pinned type in the object cache DESCRIPTION: Get a pointer to a version of the existing type associated with schema/type name. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is null. OCI_ERROR if 1) any of the required parameters is null. 2) the adt type associated with schema/type name does not exist. NOTE: Schema and type names are CASE-SENSITIVE. If they have been created via SQL, you need to use uppercase names. } TOCITypeArrayByName = function(env: POCIEnv; err: POCIError; svc: POCISvcCtx; array_len: ub4; schema_name: PPoratext; s_length: Pub4; type_name: PPoratext; t_length: Pub4; version_name: PPoratext; v_length: Pub4; pin_duration: OCIDuration; get_option: OCITypeGetOpt; tdo: PPOCIType): sword; cdecl; { NAME: OCITypeArrayByName - OCI Get array of TYPes by name. PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). svc (IN) - OCI service handle array_len (IN) - number of schema_name/type_name/version_name entries to be retrieved. schema_name (IN, optional) - array of schema names associated with the types to be retrieved. The array must have array_len elements if specified. If 0 is supplied, the default schema is assumed, otherwise it MUST have array_len number of elements. 0 can be supplied for one or more of the entries to indicate that the default schema is desired for those entries. s_length (IN) - array of schema_name lengths with each entry corresponding to the length of the corresponding schema_name entry in the schema_name array in bytes. The array must either have array_len number of elements or it MUST be 0 if schema_name is not specified. type_name (IN) - array of the names of the types to retrieve. This MUST have array_len number of elements. t_length (IN) - array of the lengths of type names in the type_name array in bytes. version_name (IN) - array of the version names of the types to retrieve corresponding. This can be 0 to indicate retrieval of the most current versions, or it MUST have array_len number of elements. If 0 is supplied, the most current version is assumed, otherwise it MUST have array_len number of elements. 0 can be supplied for one or more of the entries to indicate that the current version is desired for those entries. v_length (IN) - array of the lengths of version names in the version_name array in bytes. pin_duration (IN) - pin duration (e.g. until the end of current transaction) for the types retreieve. See 'oro.h' for a description of each option. get_option (IN) - options for loading the types. It can be one of two values: OCI_TYPEGET_HEADER for only the header to be loaded, or OCI_TYPEGET_ALL for the TDO and all ADO and MDOs to be loaded. tdo (OUT) - output array for the pointers to each pinned type in the object cache. It must have space for array_len pointers. Use OCIObjectGetObjectRef() to obtain the CREF to each pinned type descriptor. DESCRIPTION: Get pointers to the existing types associated with the schema/type name array. This is similar to OCITypeByName() except that all the TDO's are retreived via a single network roundtrip. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is null. OCI_ERROR if 1) any of the required parameters is null. 2) one or more adt types associated with a schema/type name entry does not exist. } TOCITypeByRef = function(env: POCIEnv; err: POCIError; type_ref: POCIRef; pin_duration: OCIDuration; get_option: OCITypeGetOpt; tdo: PPOCIType): sword; cdecl; { NAME: OCITypeArrayByRef - OCI Get array of TYPes by REF. PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). type_ref (IN) - OCIRef * pointing to the particular version of the type descriptor object to obtain. The array must have array_len elements if specified. pin_duration (IN) - pin duration (e.g. until the end of current transaction) for the type to retreieve. See 'oro.h' for a description of each option. get_option (IN) - options for loading the type. It can be one of two values: OCI_TYPEGET_HEADER for only the header to be loaded, or OCI_TYPEGET_ALL for the TDO and all ADO and MDOs to be loaded. tdo (OUT) - pointer to the pinned type in the object cache DESCRIPTION: Get pointers to the with the schema/type name array. This is similar to OCITypeByName() except that all the TDO's are retreived via a single network roundtrip. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is null. OCI_ERROR if 1) any of the required parameters is null. 2) one or more adt types associated with a schema/type name entry does not exist. } TOCITypeArrayByRef = function(env: POCIEnv; err: POCIError; array_len: ub4; type_ref: PPOCIRef; pin_duration: OCIDuration; get_option: OCITypeGetOpt; tdo: PPOCIType): sword; cdecl; { NAME: OCITypeArrayByRef - OCI Get array of TYPes by REF. PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). array_len (IN) - number of schema_name/type_name/version_name entries to be retrieved. type_ref (IN) - array of OCIRef * pointing to the particular version of the type descriptor object to obtain. The array must have array_len elements if specified. pin_duration (IN) - pin duration (e.g. until the end of current transaction) for the types retreieve. See 'oro.h' for a description of each option. get_option (IN) - options for loading the types. It can be one of two values: OCI_TYPEGET_HEADER for only the header to be loaded, or OCI_TYPEGET_ALL for the TDO and all ADO and MDOs to be loaded. tdo (OUT) - output array for the pointers to each pinned type in the object cache. It must have space for array_len pointers. Use OCIObjectGetObjectRef() to obtain the CREF to each pinned type descriptor. DESCRIPTION: Get pointers to the with the schema/type name array. This is similar to OCITypeByName() except that all the TDO's are retreived via a single network roundtrip. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is null. OCI_ERROR if 1) any of the required parameters is null. 2) one or more adt types associated with a schema/type name entry does not exist. } {-------------------------------------------------------------------------- } { TYPE ACCESSORS } {-------------------------------------------------------------------------- } {---------------------------- OCITypeName --------------------------------- } { ** OBSOLETE ** } TOCITypeName = function(env: POCIEnv; err: POCIError; tdo: POCIType; n_length: Pub4): poratext; cdecl; { NAME: OCITypeName - ORT Get a Type's naME. PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). tdo (IN) - pointer to to the type descriptor in the object cache n_length (OUT) - length (in bytes) of the returned type name. The caller must allocate space for the ub4 before calling this routine. REQUIRES: 1) All type accessors require that the type be pinned before calling any accessor. 2) All input parameters must not be NULL and must be valid. 3) 'n_length' must point to an allocated ub4. DESCRIPTION: Get the name of the type. RETURNS: the name of the type NOTES: The type descriptor, 'tdo', must be unpinned when the accessed information is no longer needed. } {------------------------ OCITypeSchema --------------------------------- } { ** OBSOLETE ** } TOCITypeSchema = function(env: POCIEnv; err: POCIError; const tdo: POCIType; n_length: Pub4): poratext; cdecl; { NAME: OCITypeSchema - ORT Get a Type's SCHema name. PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). tdo (IN) - pointer to to the type descriptor in the object cache n_length (OUT) - length (in bytes) of the returned schema name. The caller must allocate space for the ub4 before calling this routine. REQUIRES: 1) All type accessors require that the type be pinned before calling any accessor. 2) All input parameters must not be NULL and must be valid. 3) 'n_length' must point to an allocated ub4. DESCRIPTION: Get the schema name of the type. RETURNS: the schema name of the type NOTES: The type descriptor, 'tdo', must be unpinned when the accessed information is no longer needed. } {------------------------ OCITypeTypeCode --------------------------------- } { ** OBSOLETE ** } TOCITypeTypeCode = function(env: POCIEnv; err: POCIError; const tdo: POCIType): OCITypeCode; cdecl; { NAME: OCITypeTypeCode - OCI Get a Type's Type Code. PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). tdo (IN) - pointer to to the type descriptor in the object cache REQUIRES: 1) All type accessors require that the type be pinned before calling any accessor. 2) All input parameters must not be NULL and must be valid. DESCRIPTION: Get the type code of the type. RETURNS: The type code of the type. NOTES: The type descriptor, 'tdo', must be unpinned when the accessed information is no longer needed. } {----------------------- OCITypeCollTypeCode ------------------------------- } { ** OBSOLETE ** } TOCITypeCollTypeCode = function(env:POCIEnv; err:POCIError; const tdo: POCIType): OCITypeCode; cdecl; { NAME: OCITypeCollTypeCode - OCI Get a Domain Type's Type Code. PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). tdo (IN) - pointer to to the type descriptor in the object cache REQUIRES: 1) All type accessors require that the type be pinned before calling any accessor. 2) All input parameters must not be NULL and must be valid. 3) 'tdo' MUST point to a named collection type. DESCRIPTION: Get the type code of the named collection type. For V8.0, named collection types can only be variable length arrays and nested tables. RETURNS: OCI_TYPECODE_VARRAY for variable length array, and OCI_TYPECODE_TABLE for nested tables. NOTES: The type descriptor, 'tdo', should be unpinned when the accessed information is no longer needed. } {------------------------- OCITypeVersion --------------------------------- } { ** OBSOLETE ** } (* Const before type ignored *) TOCITypeVersion = function(env: POCIEnv; err: POCIError; const tdo: POCIType; v_length: Pub4): poratext; cdecl; { NAME: OCITypeVersion - OCI Get a Type's user-readable VersioN. PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). tdo (IN) - pointer to to the type descriptor in the object cache v_length (OUT) - length (in bytes) of the returned user-readable version. The caller must allocate space for the ub4 before calling this routine. REQUIRES: 1) All type accessors require that the type be pinned before calling any accessor. 2) All input parameters must not be NULL and must be valid. 3) 'v_length' must point to an allocated ub4. DESCRIPTION: Get the user-readable version of the type. RETURNS: The user-readable version of the type NOTES: The type descriptor, 'tdo', must be unpinned when the accessed information is no longer needed. } {--------------------------- OCITypeAttrs --------------------------------- } { ** OBSOLETE ** } TOCITypeAttrs = function(env: POCIEnv; err: POCIError; const tdo:POCIType): ub4; cdecl; { NAME: OCITypeAttrs - OCI Get a Type's Number of Attributes. PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). tdo (IN) - pointer to to the type descriptor in the object cache REQUIRES: 1) All type accessors require that the type be pinned before calling any accessor. 2) All input parameters must not be NULL and must be valid. DESCRIPTION: Get the number of attributes in the type. RETURNS: The number of attributes in the type. 0 for ALL non-ADTs. NOTES: The type descriptor, 'tdo', must be unpinned when the accessed information is no longer needed. } {------------------------- OCITypeMethods --------------------------------- } { ** OBSOLETE ** } TOCITypeMethods = function(env: POCIEnv; err: POCIError; const tdo: POCIType): ub4; cdecl; { NAME: OCITypeMethods - OCI Get a Type's Number of Methods. PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). tdo (IN) - pointer to to the type descriptor in the object cache REQUIRES: 1) All type accessors require that the type be pinned before calling any accessor. 2) All input parameters must not be NULL and must be valid. DESCRIPTION: Get the number of methods in a type. RETURNS: The number of methods in the type NOTES: The type descriptor, 'tdo', must be unpinned when the accessed information is no longer needed. } {-------------------------------------------------------------------------- } { TYPE ELEMENT INFORMATION ACCESSORS } {-------------------------------------------------------------------------- } {------------------------ OCITypeElemName --------------------------------- } { ** OBSOLETE ** } TOCITypeElemName = function(env: POCIEnv; err: POCIError; const elem: POCITypeElem; n_length:Pub4): poratext; cdecl; { NAME: OCITypeElemName - OCI Get an Attribute's NaMe. PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). elem (IN) - pointer to the type element descriptor in the object cache n_length (OUT) - length (in bytes) of the returned attribute name. The caller must allocate space for the ub4 before calling this routine. REQUIRES: 1) All type accessors require that the type be pinned before calling any accessor. 2) All input parameters must not be NULL and must be valid. 3) 'n_length' must point to an allocated ub4. DESCRIPTION: Get the name of the attribute. RETURNS: the name of the attribute and the length in n_length NOTES: The type must be unpinned when the accessed information is no longer needed. } {------------------------ OCITypeElemTypeCode ------------------------------ } { ** OBSOLETE ** } TOCITypeElemTypeCode = function(env: POCIEnv; err: POCIError; const elem: POCITypeElem): OCITypeCode; cdecl; { NAME: OCITypeElemTypeCode - OCI Get an Attribute's TypeCode. PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). elem (IN) - pointer to the type element descriptor in the object cache REQUIRES: 1) All type accessors require that the type be pinned before calling any accessor. 2) All input parameters must not be NULL and must be valid. DESCRIPTION: Get the typecode of an attribute's type. RETURNS: the typecode of the attribute's type. If this is a scalar type, the typecode sufficiently describes the scalar type and no further calls need to be made. Valid scalar types include: OCI_TYPECODE_SIGNED8, OCI_TYPECODE_UNSIGNED8, OCI_TYPECODE_SIGNED16, OCI_TYPECODE_UNSIGNED16, OCI_TYPECODE_SIGNED32, OCI_TYPECODE_UNSIGNED32, OCI_TYPECODE_REAL, OCI_TYPECODE_DOUBLE, OCI_TYPECODE_DATE, OCI_TYPECODE_MLSLABEL, OROTCOID, OCI_TYPECODE_OCTET, or OROTCLOB. This function converts the CREF (stored in the attribute) into a typecode. NOTES: The type must be unpinned when the accessed information is no longer needed. } {------------------------ OCITypeElemType --------------------------------- } { ** OBSOLETE ** } TOCITypeElemType = function(env: POCIEnv; err: POCIError; const elem: POCITypeElem; elem_tdo:PPOCIType): sword; cdecl; { PARAMETERS env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). elem (IN) - pointer to the type element descriptor in the object cache elem_tdo (OUT) - If the function completes successfully, 'elem_tdo' points to the type descriptor (in the object cache) of the type of the element. REQUIRES 1) All type accessors require that the type be pinned before calling any accessor. This can be done by calling 'OCITypeByName()'. 2) if 'elem' is not null, it must point to a valid type element descriptor in the object cache. DESCRIPTION Get the type tdo of the type of this element. RETURNS OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is null. OCI_ERROR if 1) any of the parameters is null. NOTES The type must be unpinned when the accessed information is no longer needed. This can be done by calling 'OCIObjectUnpin()'. } {------------------------- OCITypeElemFlags ------------------------------- } { ** OBSOLETE ** } TOCITypeElemFlags = function(env: POCIEnv; err: POCIError; const elem: POCITypeElem): ub4; cdecl; { NAME: OCITypeElemFlags - OCI Get a Elem's FLags (inline, constant, virtual, constructor, destructor). PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). elem (IN) - pointer to the type element descriptor in the object cache REQUIRES: 1) All type accessors require that the type be pinned before calling any accessor. 2) All input parameters must not be NULL and must be valid. DESCRIPTION: Get the flags of a type element (attribute, parameter). RETURNS: The flags of the type element. NOTES: The flag bits are not externally documented. Use only the macros in the last section (ie. OCI_TYPEPARAM_IS_REQUIRED, and OCI_TYPEELEM_IS_REF) to test for them only. The type must be unpinned when the accessed information is no longer needed. } {------------------------ OCITypeElemNumPrec ------------------------------ } { ** OBSOLETE ** } TOCITypeElemNumPrec = function(env: POCIEnv; err: POCIError; const elem: POCITypeElem): ub1; cdecl; { NAME: OCITypeElemNumPrec - Get a Number's Precision. This includes float, decimal, real, double, and oracle number. PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). elem (IN) - pointer to the type element descriptor in the object cache REQUIRES: All input parameters must not be NULL and must be valid. DESCRIPTION: Get the precision of a float, decimal, long, unsigned long, real, double, or Oracle number type. RETURNS: the precision of the float, decimal, long, unsigned long, real, double, or Oracle number } {------------------------- OCITypeElemNumScale ----------------------------- } { ** OBSOLETE ** } TOCITypeElemNumScale = function(env: POCIEnv; err: POCIError; const elem: POCITypeElem): sb1; cdecl; { NAME: OCITypeElemNumScale - Get a decimal or oracle Number's Scale PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). elem (IN) - pointer to the type element descriptor in the object cache REQUIRES: All input parameters must not be NULL and must be valid. DESCRIPTION: Get the scale of a decimal, or Oracle number type. RETURNS: the scale of the decimal, or Oracle number } {------------------------ OCITypeElemLength ------------------------------- } { ** OBSOLETE ** } TOCITypeElemLength = function(env: POCIEnv; err: POCIError; const elem:POCITypeElem): ub4; cdecl; { NAME: OCITypeElemLength - Get a raw, fixed or variable length String's length in bytes. PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). elem (IN) - pointer to the type element descriptor in the object cache REQUIRES: All input parameters must not be NULL and must be valid. DESCRIPTION: Get the length of a raw, fixed or variable length string type. RETURNS: length of the raw, fixed or variable length string } {----------------------- OCITypeElemCharSetID ----------------------------- } { ** OBSOLETE ** } TOCITypeElemCharSetID = function(env: POCIEnv; err: POCIError; const elem: POCITypeElem): ub2; cdecl; { NAME: OCITypeElemCharSetID - Get a fixed or variable length String's character set ID PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). elem (IN) - pointer to the type element descriptor in the object cache REQUIRES: All input parameters must not be NULL and must be valid. DESCRIPTION: Get the character set ID of a fixed or variable length string type. RETURNS: character set ID of the fixed or variable length string } {---------------------- OCITypeElemCharSetForm ---------------------------- } { ** OBSOLETE ** } TOCITypeElemCharSetForm = function(env: POCIEnv; err: POCIError; const elem: POCITypeElem): ub2; cdecl; { NAME: OCITypeElemCharSetForm - Get a fixed or variable length String's character set specification form. PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). elem (IN) - pointer to the attribute information in the object cache REQUIRES: All input parameters must not be NULL and must be valid. DESCRIPTION: Get the character form of a fixed or variable length string type. The character form is an enumerated value that can be one of the 4 values below: SQLCS_IMPLICIT for CHAR, VARCHAR2, CLOB w/o a specified set SQLCS_NCHAR for NCHAR, NCHAR VARYING, NCLOB SQLCS_EXPLICIT for CHAR, etc, with "CHARACTER SET ..." syntax SQLCS_FLEXIBLE for PL/SQL "flexible" parameters RETURNS: character form of the fixed or variable string } {--------------------- OCITypeElemParameterizedType ------------------------ } { ** OBSOLETE ** } TOCITypeElemParameterizedType = function(env: POCIEnv; err: POCIError; const elem: POCITypeElem; type_stored: PPOCIType): sword; cdecl; { NAME: OCITypeElemParameterizedType PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). elem (IN) - pointer to the type element descriptor in the object cache type_stored (OUT) - If the function completes successfully, and the parameterized type is complex, 'type_stored' is NULL. Otherwise, 'type_stored' points to the type descriptor (in the object cache) of the type that is stored in the parameterized type. The caller must allocate space for the OCIType* before calling this routine and must not write into the space. REQUIRES: All input parameters must be valid. DESCRIPTION: Get a descriptor to the parameter type of a parameterized type. Parameterized types are types of the form: REF T VARRAY (n) OF T etc, where T is the parameter in the parameterized type. Additionally is_ref is set if the parameter is a PTR or REF. For example, it is set for REF T or VARRAY(n) OF REF T. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is null. OCI_ERROR if 1) any of the parameters is null. 2) 'type_stored' is not NULL but points to NULL data. NOTES: Complex parameterized types will be in a future release (once typedefs are supported. When setting the parameterized type information, the user must typedef the contents if it's a complex parameterized type. Ex. for varray>, use 'typedef varray varcar' and then use varray. } {----------------------- OCITypeElemExtTypeCode ---------------------------- } { ** OBSOLETE ** } TOCITypeElemExtTypeCode = function(env: POCIEnv; err: POCIError; const elem: POCITypeElem): OCITypeCode; cdecl; { NAME: OCITypeElemExtTypeCode - OCI Get an element's SQLT constant. PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). elem (IN) - pointer to the type element descriptor in the object cache REQUIRES: 1) All type accessors require that the type be pinned before calling any accessor. 2) All input parameters must not be NULL and must be valid. DESCRIPTION: Get the internal Oracle typecode associated with an attribute's type. This is the actual typecode for the attribute when it gets mapped to a column in the Oracle database. RETURNS: The Oracle typecode associated with the attribute's type. NOTES: The type must be unpinned when the accessed information is no longer needed. } {-------------------------------------------------------------------------- } { ATTRIBUTE ACCESSORS } {-------------------------------------------------------------------------- } {------------------------ OCITypeAttrByName ------------------------------- } { ** OBSOLETE ** } TOCITypeAttrByName = function(env: POCIEnv; err: POCIError; const tdo: POCIType; const name: Poratext; const n_length: ub4; elem: PPOCITypeElem): sword; cdecl; { NAME: OCITypeAttrByName - OCI Get an Attribute By Name. PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). tdo (IN) - pointer to to the type descriptor in the object cache name (IN) - the attribute's name n_length (IN) - length (in bytes) of the 'name' parameter elem (OUT) - If this function completes successfully, 'elem' points to the selected type element descriptor pertaining to the attributein the object cache. REQUIRES: 1) All type accessors require that the type be pinned before calling any accessor. 2) if 'tdo' is not null, it must point to a valid type descriptor in the object cache. DESCRIPTION: Get an attribute given its name. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is null. OCI_ERROR if 1) any of the required parameters is null. 2) the type does not contain an attribute with the input 'name'. 3) 'name' is NULL. NOTES: The type descriptor, 'tdo', must be unpinned when the accessed information is no longer needed. Schema and type names are CASE-SENSITIVE. If they have been created via SQL, you need to use uppercase names. } {------------------------ OCITypeAttrNext --------------------------------- } { ** OBSOLETE ** } TOCITypeAttrNext = function(env: POCIEnv; err: POCIError; iterator_ort: POCITypeIter; elem: PPOCITypeElem): sword; cdecl; { NAME: OCITypeAttrNext - OCI Get an Attribute By Iteration. PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). iterator_ort (IN/OUT) - iterator for retrieving the next attribute; see OCITypeIterNew() to initialize iterator. elem (OUT) - If this function completes successfully, 'elem' points to the selected type element descriptor pertaining to the attributein the object cache. REQUIRES: 1) All type accessors require that the type be pinned before calling any accessor. 2) if 'tdo' is not null, it must point to a valid type descriptor in the object cache. DESCRIPTION: Iterate to the next attribute to retrieve. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_NO_DATA if there are no more attributes to iterate on; use OCITypeIterSet() to reset the iterator if necessary. OCI_INVALID_HANDLE if 'env' or 'err' is null. OCI_ERROR if 1) any of the required parameters is null. NOTES: The type must be unpinned when the accessed information is no longer needed. } {-------------------------------------------------------------------------- } { COLLECTION ACCESSORS } {-------------------------------------------------------------------------- } {------------------------ OCITypeCollElem --------------------------------- } { ** OBSOLETE ** } TOCITypeCollElem = function(env: POCIEnv; err: POCIError; const tdo:POCIType; element: PPOCITypeElem): sword; cdecl; { NAME: OCITypeCollElem PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). tdo (IN) - pointer to the type descriptor in the object cache element (IN/OUT) - If the function completes successfully, this points to the descriptor for the collection's element. It is stored in the same format as an ADT attribute's descriptor. If *element is NULL, OCITypeCollElem() implicitly allocates a new instance of OCITypeElem in the object cache. This instance will be automatically freed at the end of the session, and does not have to be freed explicitly. If *element is not NULL, OCITypeCollElem() assumes that it points to a valid OCITypeElem descriptor and will copy the results into it. REQUIRES: All input parameters must be valid. DESCRIPTION: Get a pointer to the descriptor (OCITypeElem) of the element of an array or the rowtype of a nested table. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is null. OCI_ERROR if 1) any of the parameters is null. 2) the type TDO does not point to a valid collection's type. NOTES: Complex parameterized types will be in a future release (once typedefs are supported. When setting the parameterized type information, the user must typedef the contents if it's a complex parameterized type. Ex. for varray>, use 'typedef varray varcar' and then use varray. } {------------------------ OCITypeCollSize --------------------------------- } { ** OBSOLETE ** } TOCITypeCollSize = function(env: POCIEnv; err: POCIError; const tdo: POCIType; num_elems: Pub4): sword; cdecl; { NAME: OCITypeCollSize - OCI Get a Collection's Number of Elements. PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). tdo (IN) - pointer to the type descriptor in the object cache num_elems (OUT) - number of elements in collection REQUIRES: All input parameters must be valid. tdo points to an array type defined as a domain. DESCRIPTION: Get the number of elements stored in a fixed array or the maximum number of elements in a variable array. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is null. OCI_ERROR if 1) any of the parameters is null. 2) 'tdo' does not point to a domain with a collection type. NOTES: Complex parameterized types will be in a future release (once typedefs are supported. When setting the parameterized type information, the user must typedef the contents if it's a complex parameterized type. Ex. for varray>, use 'typedef varray varcar' and then use varray. } {------------------------ OCITypeCollExtTypeCode --------------------------- } { ** OBSOLETE ** } TOCITypeCollExtTypeCode = function(env: POCIEnv; err: POCIError; const tdo:POCIType; sqt_code: POCITypeCode): sword; cdecl; { NAME: ortcsqt - OCI Get a Collection element's DTY constant. PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). tdo (IN) - pointer to the type descriptor in the object cache sqt_code (OUT) - SQLT code of type element. REQUIRES: 1) All type accessors require that the type be pinned before calling any accessor. 2) All input parameters must not be NULL and must be valid. DESCRIPTION: Get the SQLT constant associated with an domain's element type. The SQLT codes are defined in and are needed for OCI/OOCI use. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is null. OCI_ERROR if 1) any of the parameters is null. 2) 'tdo' does not point to a domain with a collection type. NOTES: The type must be unpinned when the accessed information is no longer needed. } {-------------------------------------------------------------------------- } { METHOD ACCESSORS } {-------------------------------------------------------------------------- } {------------------------- OCITypeMethodOverload -------------------------- } { ** OBSOLETE ** } TOCITypeMethodOverload = function(env: POCIEnv; err: POCIError; const tdo: POCIType; const method_name: Poratext; const m_length: ub4): ub4; cdecl; { NAME: OCITypeMethodOverload - OCI Get type's Number of Overloaded names for the given method name. PARAMETERS: gp (IN/OUT) - pga environment handle. Any errors are recorded here. tdo (IN) - pointer to to the type descriptor in the object cache method_name (IN) - the method's name m_length (IN) - length (in bytes) of the 'method_name' parameter REQUIRES: 1) All type accessors require that the type be pinned before calling any accessor. 2) if 'tdo' is not null, it must point to a valid type descriptor in the object cache. DESCRIPTION: Overloading of methods implies that more than one method may have the same method name. This routine returns the number of methods that have the given method name. If there are no methods with the input method name, 'num_methods' is 0. The caller uses this information when allocating space for the array of mdo and/or position pointers before calling 'OCITypeMethodByName()' or 'ortgmps()'. RETURNS: The number of methods with the given name. 0 if none contains the name. NOTES: Schema and type names are CASE-SENSITIVE. If they have been created via SQL, you need to use uppercase names. } {------------------------ OCITypeMethodByName ------------------------------ } { ** OBSOLETE ** } TOCITypeMethodByName = function(env: POCIEnv; err: POCIError; const tdo: POCIType; const method_name: Poratext; const m_length: ub4; mdos: PPOCITypeMethod): sword; cdecl; { NAME: OCITypeMethodByName - OCI Get one or more Methods with Name. PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). tdo (IN) - pointer to to the type descriptor in the object cache method_name (IN) - the methods' name m_length (IN) - length (in bytes) of the 'name' parameter mdos (OUT) - If this function completes successfully, 'mdos' points to the selected methods in the object cache. The caller must allocate space for the array of OCITypeMethod pointers before calling this routine and must not write into the space. The number of OCITypeMethod pointers that will be returned can be obtained by calling 'OCITypeMethodOverload()'. REQUIRES: 1) All type accessors require that the type be pinned before calling any accessor. 2) if 'tdo' is not null, it must point to a valid type descriptor in the object cache. DESCRIPTION: Get one or more methods given the name. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is null. OCI_ERROR if 1) any of the required parameters is null. 2) No methods in type has name 'name'. 3) 'mdos' is not NULL but points to NULL data. NOTES: The type must be unpinned when the accessed information is no longer needed. Schema and type names are CASE-SENSITIVE. If they have been created via SQL, you need to use uppercase names. } {------------------------ OCITypeMethodNext -------------------------------- } { ** OBSOLETE ** } TOCITypeMethodNext = function(env: POCIEnv; err: POCIError; iterator_ort: POCITypeIter; mdo: PPOCITypeMethod): sword; cdecl; { NAME: OCITypeMethodNext - OCI Get a Method By Iteration. PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). iterator_ort (IN/OUT) - iterator for retrieving the next method; see OCITypeIterNew() to set iterator. mdo (OUT) - If this function completes successfully, 'mdo' points to the selected method descriptor in the object cache. Positions start at 1. The caller must allocate space for the OCITypeMethod* before calling this routine and must not write nto the space. REQUIRES: 1) All type accessors require that the type be pinned before calling any accessor. 2) if 'tdo' is not null, it must point to a valid type descriptor in the object cache. DESCRIPTION: Iterate to the next method to retrieve. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_NO_DATA if there are no more attributes to iterate on; use OCITypeIterSet() to reset the iterator if necessary. OCI_INVALID_HANDLE if 'env' or 'err' is null. OCI_ERROR if 1) any of the required parameters is null. 2) 'mdo' is not NULL but points to NULL data. NOTES: The type must be unpinned when the accessed information is no longer needed. } {------------------------ OCITypeMethodName -------------------------------- } { ** OBSOLETE ** } TOCITypeMethodName = function(env:POCIEnv; err: POCIError; const mdo: POCITypeMethod; n_length: Pub4): poratext; cdecl; { NAME: OCITypeMethodName - OCI Get a Method's NaMe. PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). mdo (IN) - pointer to the method descriptor in the object cache n_length (OUT) - length (in bytes) of the 'name' parameter. The caller must allocate space for the ub4 before calling this routine. REQUIRES: 1) All type accessors require that the type be pinned before calling any accessor. 2) All input parameters must not be NULL and must be valid. DESCRIPTION: Get the (non-unique) real name of the method. RETURNS: the non-unique name of the method or NULL if there is an error. NOTES: The type must be unpinned when the accessed information is no longer needed. } {------------------------ OCITypeMethodEncap ------------------------------- } { ** OBSOLETE ** } TOCITypeMethodEncap = function(env: POCIEnv; err: POCIError; const mdo: POCITypeMethod): OCITypeEncap; cdecl; { NAME: OCITypeMethodEncap - Get a Method's ENcapsulation (private/public). PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). mdo (IN) - pointer to the method descriptor in the object cache REQUIRES: 1) All type accessors require that the type be pinned before calling any accessor. 2) All input parameters must not be NULL and must be valid. DESCRIPTION: Get the encapsulation (private, or public) of a method. RETURNS: the encapsulation (private, or public) of the method NOTES: The type must be unpinned when the accessed information is no longer needed. } {------------------------ OCITypeMethodFlags ------------------------------- } { ** OBSOLETE ** } TOCITypeMethodFlags = function(env: POCIEnv; err: POCIError; const mdo:POCITypeMethod): OCITypeMethodFlag; cdecl; { NAME: OCITypeMethodFlags - OCI Get a Method's FLags (inline, constant, virtual, constructor, destructor). PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). mdo (IN) - pointer to the method descriptor in the object cache REQUIRES: 1) All type accessors require that the type be pinned before calling any accessor. 2) All input parameters must not be NULL and must be valid. DESCRIPTION: Get the flags (inline, constant, virutal, constructor, destructor) of a method. RETURNS: the flags (inline, constant, virutal, constructor, destructor) of the method NOTES: The type must be unpinned when the accessed information is no longer needed. } {------------------------ OCITypeMethodMap --------------------------------- } { ** OBSOLETE ** } TOCITypeMethodMap = function(env: POCIEnv; err: POCIError; const tdo: POCIType; mdo: PPOCITypeMethod): sword; cdecl; { NAME: OCITypeMethodMap - OCI Get the Method's MAP function. PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). tdo (IN) - pointer to to the type descriptor in the object cache mdo (OUT) - If this function completes successfully, and there is a map function for this type, 'mdo' points to the selected method descriptor in the object cache. Otherwise, 'mdo' is null. REQUIRES: 1) All type accessors require that the type be pinned before calling any accessor. 2) All required input parameters must not be NULL and must be valid. DESCRIPTION: A type may have only one map function. 'OCITypeMethodMap()' finds this function, if it exists, and returns a reference and a pointer to the method descriptor in the object cache. If the type does not have a map (relative ordering) function, then 'mdo_ref' and 'mdo' are set to null and an error is returned. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is null. OCI_ERROR if the type does not contain a map function. NOTES: The type must be unpinned when the accessed information is no longer needed. } {------------------------ OCITypeMethodOrder ------------------------------- } { ** OBSOLETE ** } TOCITypeMethodOrder = function(env: POCIEnv; err: POCIError; const tdo: POCIType; mdo: PPOCITypeMethod): sword; cdecl; { NAME: OCITypeMethodOrder - OCI Get the Method's ORder function. PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). tdo (IN) - pointer to to the type descriptor in the object cache mdo (OUT) - If this function completes successfully, and there is a map function for this type, 'mdo' points to the selected method descriptor in the object cache. Otherwise, 'mdo' is null. REQUIRES: 1) All type accessors require that the type be pinned before calling any accessor. 2) All required input parameters must not be NULL and must be valid. DESCRIPTION: A type may have only one ORder or MAP function. 'OCITypeMethodOrder()' finds this function, if it exists, and returns a ref and a pointer to the method descriptor in the object cache. If the type does not have a map (relative ordering) function, then 'mdo_ref' and 'mdo' are set to null and an error is returned. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is null. OCI_ERROR if the type does not contain a map function. NOTES: The type must be unpinned when the accessed information is no longer needed. } {------------------------ OCITypeMethodParams ------------------------------ } { ** OBSOLETE ** } TOCITypeMethodParams = function(env: POCIEnv; err: POCIError; const mdo: POCITypeMethod): ub4; cdecl; { NAME: OCITypeMethodParams - OCI Get a Method's Number of Parameters. PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). mdo (IN) - pointer to the method descriptor in the object cache REQUIRES: 1) All type accessors require that the type be pinned before calling any accessor. 2) All input parameters must not be NULL and must be valid. DESCRIPTION: Get the number of parameters in a method. RETURNS: the number of parameters in the method NOTES: The type must be unpinned when the accessed information is no longer needed. } {-------------------------------------------------------------------------- } { RESULT ACCESSORS } {-------------------------------------------------------------------------- } {-------------------------- OCITypeResult --------------------------------- } { ** OBSOLETE ** } TOCITypeResult = function(env: POCIEnv; err: POCIError; const mdo: POCITypeMethod; elem: PPOCITypeElem): sword; cdecl; { NAME: OCITypeResult - OCI Get a method's result type descriptor. PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). mdo (IN) - pointer to the method descriptor in the object cache elem (OUT) - If this function completes successfully, 'rdo' points to the selected result (parameter) descriptor in the object cache. REQUIRES: 1) All type accessors require that the type be pinned before calling any accessor. 2) 'elem' MUST be the address of an OCITypeElem pointer. DESCRIPTION: Get the result of a method. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is null. OCI_ERROR if 1) any of the required parameters is null. 2) method returns no results. NOTES: The method must be unpinned when the accessed information is no longer needed. } {-------------------------------------------------------------------------- } { PARAMETER ACCESSORS } {-------------------------------------------------------------------------- } {------------------------ OCITypeParamByPos ------------------------------- } { ** OBSOLETE ** } TOCITypeParamByPos = function(env: POCIEnv; err: POCIError; const mdo: POCITypeMethod; const position: ub4; elem: PPOCITypeElem): sword; cdecl; { NAME: OCITypeParamByPos - OCI Get a Parameter in a method By Position. PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). mdo (IN) - pointer to the method descriptor in the object cache position (IN) - the parameter's position. Positions start at 1. elem (OUT) - If this function completes successfully, 'elem' points to the selected parameter descriptor in the object cache. REQUIRES: 1) All type accessors require that the type be pinned before calling any accessor. DESCRIPTION: Get a parameter given its position in the method. Positions start at 1. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is null. OCI_ERROR if 1) any of the required parameters is null. 2) 'position' is not >= 1 and <= the number of parameters in the method. NOTES: The type must be unpinned when the accessed information is no longer needed. } {------------------------ OCITypeParamByName ------------------------------- } { ** OBSOLETE ** } TOCITypeParamByName = function(env: POCIEnv; err: POCIError; const mdo: POCITypeMethod; const name: Poratext; const n_length: ub4; elem:PPOCITypeElem): sword; cdecl; { NAME: OCITypeParamByName - OCI Get a Parameter in a method By Name. PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). mdo (IN) - pointer to the method descriptor in the object cache name (IN) - the parameter's name n_length (IN) - length (in bytes) of the 'name' parameter elem (OUT) - If this function completes successfully, 'elem' points to the selected parameter descriptor in the object cache. REQUIRES: 1) All type accessors require that the type be pinned before calling any accessor. 2) if 'mdo' is not null, it must point to a valid method descriptor in the object cache. DESCRIPTION: Get a parameter given its name. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is null. OCI_ERROR if 1) any of the required parameters is null. 2) the method does not contain a parameter with the input 'name'. NOTES: The type must be unpinned when the accessed information is no longer needed. } {------------------------ OCITypeParamPos --------------------------------- } { ** OBSOLETE ** } TOCITypeParamPos = function(env: POCIEnv; err: POCIError; const mdo: POCITypeMethod; const name: Poratext; const n_length: ub4; position: Pub4; elem: PPOCITypeElem): sword; cdecl; { NAME: OCITypeParamPos - OCI Get a parameter's position in a method PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). mdo (IN) - pointer to the method descriptor in the object cache name (IN) - the parameter's name n_length (IN) - length (in bytes) of the 'name' parameter position (OUT) - If this function completes successfully, 'position' points to the position of the parameter in the method starting at position 1. position MUST point to space for a ub4. elem (OUT) - If this function completes successfully, and the input 'elem' is not NULL, 'elem' points to the selected parameter descriptor in the object cache. REQUIRES: 1) All type accessors require that the type be pinned before calling any accessor. 2) if 'mdo' is not null, it must point to a valid method descriptor in the object cache. DESCRIPTION: Get the position of a parameter in a method. Positions start at 1. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is null. OCI_ERROR if 1) any of the parameters is null. 2) the method does not contain a parameter with the input 'name'. NOTES: The type must be unpinned when the accessed information is no longer needed. } {------------------------ OCITypeParamElemMode ----------------------------- } { ** OBSOLETE ** } TOCITypeElemParamMode = function(env: POCIEnv; err: POCIError; const elem: POCITypeElem): OCITypeParamMode; cdecl; { NAME: OCITypeElemParamMode - OCI Get a parameter's mode PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). elem (IN) - pointer to the parameter descriptor in the object cache (represented by an OCITypeElem) REQUIRES: 1) All type accessors require that the type be pinned before calling any accessor. 2) All input parameters must not be NULL and must be valid. DESCRIPTION: Get the mode (in, out, or in/out) of the parameter. RETURNS: the mode (in, out, or in/out) of the parameter NOTES: The type must be unpinned when the accessed information is no longer needed. } {------------------------- OCITypeElemDefaultValue ------------------------- } { ** OBSOLETE ** } TOCITypeElemDefaultValue = function(env: POCIEnv; err: POCIError; const elem: POCITypeElem; d_v_length: Pub4): poratext; cdecl; { NAME: OCITypeElemDefaultValue - OCI Get the element's Default Value. PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). elem (IN) - pointer to the parameter descriptor in the object cache (represented by an OCITypeElem) d_v_length (OUT) - length (in bytes) of the returned default value. The caller must allocate space for the ub4 before calling this routine. REQUIRES: 1) All type accessors require that the type be pinned before calling any accessor. 2) All input parameters must not be NULL and must be valid. DESCRIPTION: Get the default value in text form (PL/SQL) of an element. For V8.0, this only makes sense for a method parameter. RETURNS: The default value (text) of the parameter. NOTES: The type must be unpinned when the accessed information is no longer needed. } {-------------------------------------------------------------------------- } { TYPE VERSION TABLE } {-------------------------------------------------------------------------- } { For V8.0, the type version table is meant to be an internal data structure only for Oracle clients for type version maintanence purposes. A more general version of the API may be made public in subsequent releases. } {--------------------------- OCITypeVTInit -------------------------------- } { ** OBSOLETE ** } TOCITypeVTInit = function(env: POCIEnv; err: POCIError): sword; cdecl; { NAME: OCITypeVTInit - OCI type Version table INItialize PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). REQUIRES: none DESCRIPTION: Allocate space for and initialize the type version table and the type version table's index. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is null. OCI_ERROR if internal errors occurrs during initialization. } {--------------------------- OCITypeVTInsert ------------------------------- } { ** OBSOLETE ** } TOCITypeVTInsert = function(env: POCIEnv; err: POCIError; const schema_name: Poratext; const s_n_length: ub4; const type_name: Poratext; const t_n_length: ub4; const user_version:Poratext; const u_v_length:ub4): sword; cdecl; { NAME: OCITypeVTInsert - OCI type Version table INSert entry. PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). schema_name (IN, optional) - name of schema associated with the type. By default, the user's schema name is used. s_n_length (IN) - length of the 'schema_name' parameter type_name (IN) - type name to insert t_n_length (IN) - length (in bytes) of the 'type_name' parameter user_version (IN) - user readable version of the type u_v_length (IN) - length (in bytes) of the 'user_version' parameter REQUIRES: none DESCRIPTION: Insert an entry into the type version table and the type version table's index. The entry's type name and user readable version fields are updated with the input values. All other fields are initialized to null. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is null. OCI_ERROR if 1) any of the parameters is invalid. 2) an entry for 'type_name' has already been registered in the type version table. } {------------------------------ OCITypeVTSelect ---------------------------- } { OCITypeVTSelect - OCI type VERSion table SELECT entry } { ** OBSOLETE ** } TOCITypeVTSelect = function(env: POCIEnv; err: POCIError; const schema_name: Poratext; const s_n_length: ub4; const type_name: Poratext; const t_n_length: ub4; user_version: PPoratext; u_v_length: Pub4; version: Pub2): sword; cdecl; { NAME: OCITypeVTSelect - OCI type Version table SELect entry. PARAMETERS: env (IN/OUT) - OCI environment handle initialized in object mode err (IN/OUT) - error handle. If there is an error, it is recorded in 'err' and this function returns OCI_ERROR. The error recorded in 'err' can be retrieved by calling OCIErrorGet(). schema_name (IN, optional) - name of schema associated with the type. By default, the user's schema name is used. s_n_length (IN) - length of the 'schema_name' parameter type_name (IN) - type name to select t_n_length (IN) - length (in bytes) of the 'type_name' parameter user_version (OUT, optional) - pointer to user readable version of the type u_v_length (OUT, optional) - length (in bytes) of the 'user_version' parameter version (OUT, optional) - internal type version REQUIRES: All input parameters must not be NULL and must be valid. DESCRIPTION: Select an entry in the type version table by name. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_INVALID_HANDLE if 'env' or 'err' is null. OCI_ERROR if 1) any of the parameters is invalid. 2) an entry with 'type_name' does not exist. } { Compatibility function - following function prototype retained for compatibility only } // function ortgcty(env:POCIEnv; err:POCIError; coll_tdo:POCIType; collelem_tdo:PPOCIType):sword; {--------------------------------------------------------------------------- } { Transient Type Construction functions } {--------------------------------------------------------------------------- } // function TOCITypeBeginCreate(svchp:POCISvcCtx; errhp:POCIError; tc:OCITypeCode; dur:OCIDuration; _type:PPOCIType):sword; { NAME: OCITypeBeginCreate - OCI Type Begin Creation of a transient type. REMARKS Begins the construction process for a transient type. The type will be anonymous (no name). To create a persistent named type, the CREATE TYPE statement should be used from SQL. Transient types have no identity. They are pure values. PARAMETERS: svchp (IN) - The OCI Service Context. errhp (IN/OUT) - The OCI error handle. If there is an error, it is recorded in errhp and this function returns OCI_ERROR. Diagnostic information can be obtained by calling OCIErrorGet(). tc - The TypeCode for the type. The Typecode could correspond to a User Defined Type or a Built-in type. Currently, the permissible values for User Defined Types are OCI_TYPECODE_OBJECT for an Object Type (structured), OCI_TYPECODE_VARRAY for a VARRAY collection type or OCI_TYPECODE_TABLE for a nested table collection type. For Object types, OCITypeAddAttr() needs to be called to add each of the attribute types. For Collection types, OCITypeSetCollection() needs to be called. Subsequently, OCITypeEndCreate() needs to be called to finish the creation process. The permissible values for Built-in type codes are specified in the user manual. Additional information on built-ins if any (like precision, scale for numbers, character set info for VARCHAR2s etc.) must be set with a subsequent call to OCITypeSetBuiltin(). Subsequently OCITypeEndCreate() needs to be called to finish the creation process. dur - The allocation duration for the Type. Could be a predefined or a user defined duration. type(OUT) - The OCIType (Type Descriptor) that is being constructed. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_ERROR on error. } // function TOCITypeSetCollection(svchp:POCISvcCtx; errhp:POCIError; _type:POCIType; collelem_info:POCIParam; coll_count:ub4):sword; { NAME: OCITypeSetCollection - OCI Type Set Collection information REMARKS : Set Collection type information. This call can be called only if the OCIType has been constructed with a collection typecode. PARAMETERS: svchp (IN) - The OCI Service Context. errhp (IN/OUT) - The OCI error handle. If there is an error, it is recorded in errhp and this function returns OCI_ERROR. Diagnostic information can be obtained by calling OCIErrorGet(). type(IN OUT) - The OCIType (Type Descriptor) that is being constructed. collelem_info - collelem_info provides information on the collection element. It is obtained by allocating an OCIParam (parameter handle) and setting type information in the OCIParam using OCIAttrSet() calls. coll_count - The count of elements in the collection. Pass 0 for a nested table (unbounded). RETURNS: OCI_SUCCESS if the function completes successfully. OCI_ERROR on error. } // function TOCITypeSetBuiltin(svchp:POCISvcCtx; errhp:POCIError; _type:POCIType; builtin_info:POCIParam):sword; { NAME: OCITypeSetBuiltin - OCI Type Set Builtin information. REMARKS: Set Built-in type information. This call can be called only if the OCIType has been constructed with a built-in typecode (OCI_TYPECODE_NUMBER etc.). PARAMETERS: svchp (IN) - The OCI Service Context. errhp (IN/OUT) - The OCI error handle. If there is an error, it is recorded in errhp and this function returns OCI_ERROR. Diagnostic information can be obtained by calling OCIErrorGet(). type(IN OUT) - The OCIType (Type Descriptor) that is being constructed. builtin_info - builtin_info provides information on the built-in (like precision, scale, charater set etc.). It is obtained by allocating an OCIParam (parameter handle) and setting type information in the OCIParam using OCIAttrSet() calls. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_ERROR on error. } (* Const before type ignored *) // function TOCITypeAddAttr(svchp:POCISvcCtx; errhp:POCIError; _type:POCIType; a_name:Poratext; a_length:ub4; // attr_info:POCIParam):sword; { NAME: OCITypeAddAttr - OCI Type Add Attribute to an Object Type. REMARKS: Adds an attribute to an Object type (that was constructed earlier with typecode OCI_TYPECODE_OBJECT). PARAMETERS: svchp (IN) - The OCI Service Context errhp (IN/OUT) - The OCI error handle. If there is an error, it is recorded in errhp and this function returns OCI_ERROR. Diagnostic information can be obtained by calling OCIErrorGet(). type (IN/OUT) - The Type description that is being constructed. a_name(IN) - Optional. gives the name of the attribute. a_length - Optional. gives length of attribute name. attr_info - Information on the attribute. It is obtained by allocating an OCIParam (parameter handle) and setting type information in the OCIParam using OCIAttrSet() calls. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_ERROR on error. } // function TOCITypeEndCreate(svchp:POCISvcCtx; errhp:POCIError; _type:POCIType):sword; { NAME: OCITypeEndCreate - OCI Type End Creation REMARKS: Finishes construction of a type description.Subsequently, only access will be allowed. PARAMETERS: svchp (IN) - The OCI Service Context errhp (IN/OUT) - The OCI error handle. If there is an error, it is recorded in errhp and this function returns OCI_ERROR. Diagnostic information can be obtained by calling OCIErrorGet(). type (IN/OUT) - The Type description that is being constructed. RETURNS: OCI_SUCCESS if the function completes successfully. OCI_ERROR on error. } {========================= } { PUBLIC MACROS AND FLAGS } {========================= } {-------------------------------------------------------------------------- } { TYPE ELEMENT FLAGS } {-------------------------------------------------------------------------- } { element is a REF } const OCI_TYPEELEM_REF = $8000; { parameter is required } OCI_TYPEPARAM_REQUIRED = $0800; { macros to test flags } { was #define dname(params) para_def_expr } { argument types are unknown } { return type might be wrong } type TOCI_TYPEELEM_IS_REF = function(elem_flag : longint) : longint; { was #define dname(params) para_def_expr } { argument types are unknown } { return type might be wrong } TOCI_TYPEPARAM_IS_REQUIRED = function (param_flag : longint) : longint; type OracleOCI_API = record OCIPasswordChange: TOCIPasswordChange; OCIInitialize: TOCIInitialize; OCIEnvInit: TOCIEnvInit; OCIEnvCreate: TOCIEnvCreate; OCIEnvNlsCreate: TOCIEnvNlsCreate; OCIHandleAlloc: TOCIHandleAlloc; OCIServerAttach: TOCIServerAttach; OCIAttrSet: TOCIAttrSet; OCISessionBegin: TOCISessionBegin; OCISessionEnd: TOCISessionEnd; OCIServerDetach: TOCIServerDetach; OCIHandleFree: TOCIHandleFree; OCIErrorGet: TOCIErrorGet; OCIStmtPrepare: TOCIStmtPrepare; OCIStmtExecute: TOCIStmtExecute; OCIParamGet: TOCIParamGet; OCIAttrGet: TOCIAttrGet; OCIStmtFetch: TOCIStmtFetch; OCIDefineByPos: TOCIDefineByPos; OCIDefineArrayOfStruct: TOCIDefineArrayOfStruct; OCIBindByPos: TOCIBindByPos; OCIBindByName: TOCIBindByName; OCIDefineObject: TOCIDefineObject; { > ori.h } OCIObjectNew: TOCIObjectNew; OCIObjectPin: TOCIObjectPin; OCIObjectUnpin: TOCIObjectUnpin; OCIObjectPinCountReset: TOCIObjectPinCountReset; OCIObjectLock: TOCIObjectLock; OCIObjectLockNoWait: TOCIObjectLockNoWait; OCIObjectMarkUpdate: TOCIObjectMarkUpdate; OCIObjectUnmark: TOCIObjectUnmark; OCIObjectUnmarkByRef: TOCIObjectUnmarkByRef; OCIObjectFree: TOCIObjectFree; OCIObjectMarkDeleteByRef: TOCIObjectMarkDeleteByRef; OCIObjectMarkDelete: TOCIObjectMarkDelete; OCIObjectFlush: TOCIObjectFlush; OCIObjectRefresh: TOCIObjectRefresh; OCIObjectCopy: TOCIObjectCopy; OCIObjectGetTypeRef: TOCIObjectGetTypeRef; OCIObjectGetObjectRef: TOCIObjectGetObjectRef; OCIObjectMakeObjectRef: TOCIObjectMakeObjectRef; OCIObjectGetPrimaryKeyTypeRef: TOCIObjectGetPrimaryKeyTypeRef; OCIObjectGetInd: TOCIObjectGetInd; OCIObjectExists: TOCIObjectExists; OCIObjectGetProperty: TOCIObjectGetProperty; OCIObjectIsLocked: TOCIObjectIsLocked; OCIObjectIsDirty: TOCIObjectIsDirty; OCIObjectPinTable: TOCIObjectPinTable; OCIObjectArrayPin: TOCIObjectArrayPin; OCICacheFlush: TOCICacheFlush; OCICacheRefresh: TOCICacheRefresh; OCICacheUnpin: TOCICacheUnpin; OCICacheFree: TOCICacheFree; OCICacheUnmark: TOCICacheUnmark; OCIDurationBegin: TOCIDurationBegin; OCIDurationEnd: TOCIDurationEnd; { < ori.h } OCITransStart: TOCITransStart; OCITransCommit: TOCITransCommit; OCITransRollback: TOCITransRollback; OCITransDetach: TOCITransDetach; OCITransPrepare: TOCITransPrepare; OCITransForget: TOCITransForget; OCIDescribeAny: TOCIDescribeAny; OCIBreak: TOCIBreak; OCIReset: TOCIReset; OCIDescriptorAlloc: TOCIDescriptorAlloc; OCIDescriptorFree: TOCIDescriptorFree; OCIStmtGetPieceInfo: TOCIStmtGetPieceInfo; OCIStmtSetPieceInfo: TOCIStmtSetPieceInfo; OCIServerVersion: TOCIServerVersion; OCIServerRelease: TOCIServerRelease; OCIBindDynamic: TOCIBindDynamic; OCIBindObject: TOCIBindObject; OCIDateTimeAssign: TOCIDateTimeAssign; OCIDateTimeCheck: TOCIDateTimeCheck; OCIDateTimeCompare: TOCIDateTimeCompare; OCIDateTimeConvert: TOCIDateTimeConvert; OCIDateTimeFromText: TOCIDateTimeFromText; OCIDateTimeGetDate: TOCIDateTimeGetDate; OCIDateTimeGetTime: TOCIDateTimeGetTime; OCIDateTimeGetTimeZoneOffset: TOCIDateTimeGetTimeZoneOffset; OCIDateTimeSysTimeStamp: TOCIDateTimeSysTimeStamp; OCIDateTimeConstruct: TOCIDateTimeConstruct; OCIDateTimeToText: TOCIDateTimeToText; OCIDateTimeGetTimeZoneName: TOCIDateTimeGetTimeZoneName; OCILobAppend: TOCILobAppend; OCILobAssign: TOCILobAssign; OCILobClose: TOCILobClose; OCILobCopy: TOCILobCopy; OCILobCreateTemporary: TOCILobCreateTemporary; OCILobEnableBuffering: TOCILobEnableBuffering; OCILobDisableBuffering: TOCILobDisableBuffering; OCILobErase: TOCILobErase; OCILobFileExists: TOCILobFileExists; OCILobFileGetName: TOCILobFileGetName; OCILobFileSetName: TOCILobFileSetName; OCILobFlushBuffer: TOCILobFlushBuffer; OCILobFreeTemporary: TOCILobFreeTemporary; OCILobCharSetForm: TOCILobCharSetForm; OCILobCharSetId: TOCILobCharSetId; OCILobGetLength: TOCILobGetLength; OCILobIsOpen: TOCILobIsOpen; OCILobIsTemporary: TOCILobIsTemporary; OCILobLoadFromFile: TOCILobLoadFromFile; OCILobLocatorIsInit: TOCILobLocatorIsInit; OCILobOpen: TOCILobOpen; OCILobRead: TOCILobRead; OCILobTrim: TOCILobTrim; OCILobWrite: TOCILobWrite; OCIResultSetToStmt: TOCIResultSetToStmt; OCINlsNumericInfoGet: TOCINlsNumericInfoGet; OCIClientVersion: TOCIClientVersion; { OCI Number mapping } OCINumberInc: TOCINumberInc; OCINumberDec: TOCINumberDec; OCINumberSetZero: TOCINumberSetZero; OCINumberSetPi: TOCINumberSetPi; OCINumberAdd: TOCINumberAdd; OCINumberSub: TOCINumberSub; OCINumberMul: TOCINumberMul; OCINumberDiv: TOCINumberDiv; OCINumberMod: TOCINumberMod; OCINumberIntPower: TOCINumberIntPower; OCINumberShift: TOCINumberShift; OCINumberNeg: TOCINumberNeg; OCINumberToText: TOCINumberToText; OCINumberFromText: TOCINumberFromText; OCINumberToInt: TOCINumberToInt; OCINumberFromInt: TOCINumberFromInt; OCINumberToReal: TOCINumberToReal; OCINumberToRealArray: TOCINumberToRealArray; OCINumberFromReal: TOCINumberFromReal; OCINumberCmp: TOCINumberCmp; OCINumberSign: TOCINumberSign; OCINumberIsZero: TOCINumberIsZero; OCINumberIsInt: TOCINumberIsInt; OCINumberAssign: TOCINumberAssign; OCINumberAbs: TOCINumberAbs; OCINumberCeil: TOCINumberCeil; OCINumberFloor: TOCINumberFloor; OCINumberSqrt: TOCINumberSqrt; OCINumberTrunc: TOCINumberTrunc; OCINumberPower: TOCINumberPower; OCINumberRound: TOCINumberRound; OCINumberPrec: TOCINumberPrec; OCINumberSin: TOCINumberSin; OCINumberArcSin: TOCINumberArcSin; OCINumberHypSin: TOCINumberHypSin; OCINumberCos: TOCINumberCos; OCINumberArcCos: TOCINumberArcCos; OCINumberHypCos: TOCINumberHypCos; OCINumberTan: TOCINumberTan; OCINumberArcTan: TOCINumberArcTan; OCINumberArcTan2: TOCINumberArcTan2; OCINumberHypTan: TOCINumberHypTan; OCINumberExp: TOCINumberExp; OCINumberLn: TOCINumberLn; OCINumberLog: TOCINumberLog; { OCI oracle Date } OCIDateAssign: TOCIDateAssign; OCIDateToText: TOCIDateToText; OCIDateFromText: TOCIDateFromText; OCIDateCompare: TOCIDateCompare; OCIDateAddMonths: TOCIDateAddMonths; OCIDateAddDays: TOCIDateAddDays; OCIDateLastDay: TOCIDateLastDay; OCIDateDaysBetween: TOCIDateDaysBetween; OCIDateZoneToZone: TOCIDateZoneToZone; OCIDateNextDay: TOCIDateNextDay; { OBJECT REFERENCE (REF) } OCIRefClear: TOCIRefClear; OCIRefAssign: TOCIRefAssign; OCITableSize: TOCITableSize; OCITableExists: TOCITableExists; OCITableDelete: TOCITableDelete; OCITableFirst: TOCITableFirst; OCITableLast: TOCITableLast; OCITableNext: TOCITableNext; OCITablePrev: TOCITablePrev; { Oracle Object Interface for Dynamic Data Access } OCIObjectSetAttr: TOCIObjectSetAttr; OCIObjectGetAttr: TOCIObjectGetAttr; {ociap.h} OCIPing: TOCIPing; {ort.h} OCITypeIterNew: TOCITypeIterNew; OCITypeIterSet: TOCITypeIterSet; OCITypeIterFree: TOCITypeIterFree; OCITypeByName: TOCITypeByName; OCITypeArrayByName: TOCITypeArrayByName; OCITypeByRef: TOCITypeByRef; OCITypeArrayByRef: TOCITypeArrayByRef; OCITypeName: TOCITypeName; OCITypeSchema: TOCITypeSchema; OCITypeTypeCode: TOCITypeTypeCode; OCITypeCollTypeCode: TOCITypeCollTypeCode; OCITypeVersion: TOCITypeVersion; OCITypeAttrs: TOCITypeAttrs; OCITypeMethods: TOCITypeMethods; OCITypeElemName: TOCITypeElemName; OCITypeElemTypeCode: TOCITypeElemTypeCode; OCITypeElemType: TOCITypeElemType; OCITypeElemFlags: TOCITypeElemFlags; OCITypeElemNumPrec: TOCITypeElemNumPrec; OCITypeElemNumScale: TOCITypeElemNumScale; OCITypeElemLength: TOCITypeElemLength; OCITypeElemCharSetID: TOCITypeElemCharSetID; OCITypeElemCharSetForm: TOCITypeElemCharSetForm; OCITypeElemParameterizedType: TOCITypeElemParameterizedType; OCITypeElemExtTypeCode: TOCITypeElemExtTypeCode; OCITypeAttrByName: TOCITypeAttrByName; OCITypeAttrNext: TOCITypeAttrNext; OCITypeCollElem: TOCITypeCollElem; OCITypeCollSize: TOCITypeCollSize; OCITypeCollExtTypeCode: TOCITypeCollExtTypeCode; OCITypeMethodOverload: TOCITypeMethodOverload; OCITypeMethodByName: TOCITypeMethodByName; OCITypeMethodNext: TOCITypeMethodNext; OCITypeMethodName: TOCITypeMethodName; OCITypeMethodEncap: TOCITypeMethodEncap; OCITypeMethodFlags: TOCITypeMethodFlags; OCITypeMethodMap: TOCITypeMethodMap; OCITypeMethodOrder: TOCITypeMethodOrder; OCITypeMethodParams: TOCITypeMethodParams; OCITypeResult: TOCITypeResult; OCITypeParamByPos: TOCITypeParamByPos; OCITypeParamByName: TOCITypeParamByName; OCITypeParamPos: TOCITypeParamPos; OCITypeElemParamMode: TOCITypeElemParamMode; OCITypeElemDefaultValue:TOCITypeElemDefaultValue; OCITypeVTInit: TOCITypeVTInit; OCITypeVTInsert: TOCITypeVTInsert; OCITypeVTSelect: TOCITypeVTSelect; end; implementation end. ================================================ FILE: lib/zeosdbo/src/plain/ZPlainOracleDriver.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Native Plain Drivers for Oracle } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZPlainOracleDriver; interface {$I ZPlain.inc} {$J+} uses {$IFNDEF UNIX} // Windows, {$ENDIF} ZPlainLoader, ZCompatibility, ZPlainOracleConstants, ZPlainDriver; {***************** Plain API types definition ****************} const WINDOWS_DLL_LOCATION = 'oci.dll'; // WINDOWS_DLL_LOCATION = 'ora803.dll'; LINUX_DLL_LOCATION = 'libclntsh'+SharedSuffix; // LINUX_DLL_LOCATION = 'libwtc8.so'; type {** Represents a generic interface to Oracle native API. } IZOraclePlainDriver = interface (IZPlainDriver) ['{22404660-C95F-4346-A3DB-7C6DFE15F115}'] function Initializ(mode: ub4; ctxp: Pointer; malocfp: Pointer; ralocfp: Pointer; mfreefp: Pointer): sword; function EnvInit(var envhpp: POCIEnv; mode: ub4; xtramemsz: size_T; usrmempp: PPointer): sword; function EnvCreate(var envhpp: POCIEnv; mode: ub4; ctxp: Pointer; malocfp: Pointer; ralocfp: Pointer; mfreefp: Pointer; xtramemsz: size_T; usrmempp: PPointer): sword; function EnvNlsCreate(var envhpp: POCIEnv; mode: ub4; ctxp: Pointer; malocfp: Pointer; ralocfp: Pointer; mfreefp: Pointer; xtramemsz: size_T; usrmempp: PPointer; charset, ncharset: ub2): sword; function HandleAlloc(parenth: POCIHandle; var hndlpp: POCIHandle; atype: ub4; xtramem_sz: size_T; usrmempp: PPointer): sword; function ServerAttach(srvhp: POCIServer; errhp: POCIError; dblink: text; dblink_len: sb4; mode: ub4): sword; function AttrSet(trgthndlp: POCIHandle; trghndltyp: ub4; attributep: Pointer; size: ub4; attrtype: ub4; errhp: POCIError):sword; function SessionBegin(svchp: POCISvcCtx; errhp: POCIError; usrhp: POCISession; credt: ub4; mode: ub4):sword; function SessionEnd(svchp: POCISvcCtx; errhp: POCIError; usrhp: POCISession; mode: ub4): sword; function ServerDetach(srvhp: POCIServer; errhp: POCIError; mode: ub4): sword; function HandleFree(hndlp: Pointer; atype: ub4): sword; function ErrorGet(hndlp: Pointer; recordno: ub4; sqlstate: text; var errcodep: sb4; bufp: text; bufsiz: ub4; atype: ub4): sword; function StmtPrepare(stmtp: POCIStmt; errhp: POCIError; stmt: text; stmt_len: ub4; language:ub4; mode: ub4):sword; function StmtExecute(svchp: POCISvcCtx; stmtp: POCIStmt; errhp: POCIError; iters: ub4; rowoff: ub4; snap_in: POCISnapshot; snap_out: POCISnapshot; mode: ub4): sword; function ParamGet(hndlp: Pointer; htype: ub4; errhp: POCIError; var parmdpp: Pointer; pos: ub4): sword; function AttrGet(trgthndlp: POCIHandle; trghndltyp: ub4; attributep: Pointer; sizep: Pointer; attrtype: ub4; errhp: POCIError): sword; function StmtFetch(stmtp: POCIStmt; errhp: POCIError; nrows: ub4; orientation: ub2; mode: ub4): sword; function DefineByPos(stmtp: POCIStmt; var defnpp: POCIDefine; errhp: POCIError; position: ub4; valuep: Pointer; value_sz: sb4; dty: ub2; indp: Pointer; rlenp: Pointer; rcodep: Pointer; mode: ub4): sword; function DefineArrayOfStruct(defnpp: POCIDefine; errhp: POCIError; pvskip: ub4; indskip: ub4; rlskip: ub4; rcskip: ub4): sword; function BindByPos(stmtp: POCIStmt; var bindpp: POCIBind; errhp: POCIError; position: ub4; valuep: Pointer; value_sz: sb4; dty: ub2; indp: Pointer; alenp: Pointer; rcodep: Pointer; maxarr_len: ub4; curelep: Pointer; mode: ub4): sword; function BindByName(stmtp: POCIStmt; var bindpp: POCIBind; errhp: POCIError; placeholder: text; placeh_len: sb4; valuep: Pointer; value_sz: sb4; dty: ub2; indp: Pointer; alenp: Pointer; rcodep: Pointer; maxarr_len: ub4; curelep: Pointer; mode: ub4): sword; function BindDynamic(bindp: POCIBind; errhp: POCIError; ictxp: Pointer; icbfp: Pointer; octxp: Pointer; ocbfp: Pointer): sword; function BindObject(bindp: POCIBind; errhp: POCIError; const _type: POCIType; pgvpp: PPointer; pvszsp: pub4; indpp: PPointer; indszp: pub4): sword; function DefineObject(defnpp: POCIDefine; errhp: POCIError; _type: POCIHandle; pgvpp, pvszsp, indpp, indszp: pointer): sword; { > ori.h} function ObjectNew(env: POCIEnv; err: POCIError; const svc: POCISvcCtx; typecode: OCITypeCode; tdo: POCIType; table: Pointer; duration: OCIDuration; value: Longbool; instance: PPointer): sword; function ObjectPin(env: POCIEnv; err: POCIError; const object_ref: POCIRef; const corhdl: POCIComplexObject; const pin_option: OCIPinOpt; const pin_duration: OCIDuration; const lock_option: OCILockOpt; _object: PPointer): sword; function ObjectUnpin(env: POCIEnv; err: POCIError; const _object: Pointer): sword; function ObjectPinCountReset(env: POCIEnv; err: POCIError; const _object: pointer): sword; function ObjectLock(env: POCIEnv; err: POCIError; const _object: pointer): sword; function ObjectLockNoWait(env: POCIEnv; err: POCIError; const _object: pointer): sword; function ObjectMarkUpdate(env: POCIEnv; err: POCIError; const _object: pointer): sword; function ObjectUnmark(env: POCIEnv; err: POCIError; const _object:pointer): sword; function ObjectUnmarkByRef(env: POCIEnv; err: POCIError; const ref: POCIRef): sword; function ObjectFree(hndl: POCIEnv; err: POCIError; instance: POCIHandle;flags :ub2):sword; function ObjectMarkDeleteByRef(env: POCIEnv; err: POCIError; const object_ref:POCIRef): sword; function ObjectMarkDelete(env: POCIEnv; err: POCIError; const instance:pointer): sword; function ObjectFlush(env: POCIEnv; err: POCIError; const _object: pointer): sword; function ObjectRefresh(env: POCIEnv; err: POCIError; _object: pointer): sword; function ObjectCopy(env: POCIEnv; err: POCIError; const svc: POCISvcCtx; const source, null_source, target, null_target: pointer; const tdo: POCIType; const duration: OCIDuration; const option: ub1): sword; function ObjectGetTypeRef(env: POCIEnv; err: POCIError; const instance:pointer; type_ref: POCIRef): sword; function ObjectGetObjectRef(env: POCIEnv; err: POCIError; const _object: pointer; object_ref: POCIRef): sword; function ObjectMakeObjectRef(env: POCIEnv; err: POCIError; const svc: POCISvcCtx; const table: pointer; const values: PPointer; const array_len: ub4; object_ref: POCIRef): sword; function ObjectGetPrimaryKeyTypeRef(env: POCIEnv; err: POCIError; const svc:POCISvcCtx; const table: pointer; type_ref: POCIRef): sword; function ObjectGetInd(env: POCIEnv; err: POCIError; const instance: pointer; null_struct: PPointer): sword; function ObjectExists(env: POCIEnv; err: POCIError; const ins: pointer; exist: PBoolean): sword; function ObjectGetProperty(envh: POCIEnv; errh: POCIError; const obj: pointer; const propertyId: OCIObjectPropId; _property: pointer; size: Pub4): sword; function ObjectIsLocked(env: POCIEnv; err: POCIError; const ins: pointer; lock: Pboolean): sword; function ObjectIsDirty(env: POCIEnv; err: POCIError; const ins: pointer; dirty: PBoolean): sword; function ObjectPinTable(env: POCIEnv; err: POCIError; const svc:POCISvcCtx; const schema_name: Poratext; const s_n_length: ub4; const object_name: Poratext; const o_n_length:ub4; const scope_obj_ref: POCIRef; const pin_duration: OCIDuration; _object: PPointer): sword; function ObjectArrayPin(env: POCIEnv; err: POCIError; const ref_array: PPOCIRef; const array_size: ub4; const cor_array: PPOCIComplexObject; const cor_array_size: ub4; const pin_option: OCIPinOpt; const pin_duration: OCIDuration; const lock: OCILockOpt; obj_array: PPointer; pos: Pub4): sword; function CacheFlush(env: POCIEnv; err: POCIError; const svc:POCISvcCtx; const context: pointer; const get: TOCICacheFlushGet; ref: PPOCIRef): sword; function CacheRefresh(env: POCIEnv; err: POCIError; const svc:POCISvcCtx; const option: OCIRefreshOpt; const context: pointer; get: TOCICacheRefreshGet; ref: PPOCIRef): sword; function CacheUnpin(env: POCIEnv; err: POCIError; const svc:POCISvcCtx): sword; function CacheFree(env: POCIEnv; err: POCIError; const svc: POCISvcCtx): sword; function CacheUnmark(env: POCIEnv; err: POCIError; const svc: POCISvcCtx): sword; function DurationBegin(env: POCIEnv; err: POCIError; svc: POCISvcCtx; const parent: OCIDuration; dur: POCIDuration): sword; function DurationEnd(env: POCIEnv; err: POCIError; svc: POCISvcCtx; duration: OCIDuration): sword; { < ori.h} function TransStart(svchp: POCISvcCtx; errhp: POCIError; timeout: word; flags: ub4): sword; function TransRollback(svchp: POCISvcCtx; errhp: POCIError; flags: ub4): sword; function TransCommit(svchp: POCISvcCtx; errhp: POCIError; flags: ub4): sword; function TransDetach(svchp: POCISvcCtx; errhp: POCIError; flags: ub4): sword; function TransPrepare(svchp: POCISvcCtx; errhp: POCIError; flags: ub4): sword; function TransForget(svchp: POCISvcCtx; errhp: POCIError; flags: ub4): sword; function DescribeAny(svchp: POCISvcCtx; errhp: POCIError; objptr: Pointer; objnm_len: ub4; objptr_typ: ub1; info_level: ub1; objtyp: ub1; dschp: POCIDescribe): sword; function Break(svchp: POCISvcCtx; errhp:POCIError): sword; function Reset(svchp: POCISvcCtx; errhp:POCIError): sword; function DescriptorAlloc(parenth: POCIEnv; var descpp: POCIDescriptor; htype: ub4; xtramem_sz: integer; usrmempp: Pointer): sword; function DescriptorFree(descp: Pointer; htype: ub4): sword; function DateTimeAssign(hndl: POCIEnv; err: POCIError; const from: POCIDateTime;_to: POCIDateTime): sword; function DateTimeCheck(hndl: POCIEnv; err: POCIError; const date: POCIDateTime; var valid: ub4): sword; function DateTimeCompare(hndl: POCIEnv; err: POCIError; const date1: POCIDateTime; const date2: POCIDateTime; var result: sword): sword; function DateTimeConvert(hndl: POCIEnv; err: POCIError; indate: POCIDateTime; outdate: POCIDateTime): sword; function DateTimeFromText(hndl: POCIEnv; err: POCIError; const date_str: text; d_str_length: size_t; const fmt: text; fmt_length: ub1; const lang_name: text; lang_length: size_t; date: POCIDateTime): sword; function DateTimeGetDate(hndl: POCIEnv; err: POCIError; const date: POCIDateTime; var year: sb2; var month: ub1; var day: ub1): sword; function DateTimeGetTime(hndl: POCIEnv; err: POCIError; datetime: POCIDateTime; var hour: ub1; var minute: ub1; var sec: ub1; var fsec: ub4): sword; function DateTimeGetTimeZoneOffset(hndl: POCIEnv; err: POCIError; const datetime: POCIDateTime; var hour: sb1; var minute: sb1): sword; function DateTimeSysTimeStamp(hndl: POCIEnv; err: POCIError; sys_date: POCIDateTime): sword; function DateTimeConstruct(hndl: POCIEnv; err: POCIError; datetime: POCIDateTime; year: sb2; month: ub1; day: ub1; hour: ub1; min: ub1; sec: ub1; fsec: ub4; timezone: text; timezone_length: size_t): sword; function DateTimeToText(hndl: POCIEnv; err: POCIError; const date: POCIDateTime; const fmt: text; fmt_length: ub1; fsprec: ub1; const lang_name: text; lang_length: size_t; var buf_size: ub4; buf: text): sword; function DateTimeGetTimeZoneName(hndl: POCIEnv; err: POCIError; datetime: POCIDateTime; var buf: ub1; var buflen: ub4): sword; function LobAppend(svchp: POCISvcCtx; errhp: POCIError; dst_locp, src_locp: POCILobLocator): sword; function LobAssign(svchp: POCISvcCtx; errhp: POCIError; src_locp: POCILobLocator; var dst_locpp: POCILobLocator): sword; function LobClose(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator): sword; function LobCopy(svchp: POCISvcCtx; errhp: POCIError; dst_locp: POCILobLocator; src_locp: POCILobLocator; amount: ub4; dst_offset: ub4; src_offset: ub4): sword; function LobEnableBuffering(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator): sword; function LobDisableBuffering(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator): sword; function LobErase(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; var amount: ub4; offset: ub4): sword; function LobFileExists(svchp: POCISvcCtx; errhp: POCIError; filep: POCILobLocator; var flag: Boolean): sword; function LobFileGetName(envhp: POCIEnv; errhp: POCIError; filep: POCILobLocator; dir_alias: text; var d_length: ub2; filename: text; var f_length: ub2): sword; function LobFileSetName(envhp: POCIEnv; errhp: POCIError; var filep: POCILobLocator; dir_alias: text; d_length: ub2; filename: text; f_length: ub2): sword; function LobFlushBuffer(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; flag: ub4): sword; function LobGetLength(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; var lenp: ub4): sword; function LobIsOpen(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; var flag: LongBool): sword; function LobLoadFromFile(svchp: POCISvcCtx; errhp: POCIError; dst_locp: POCILobLocator; src_locp: POCILobLocator; amount: ub4; dst_offset: ub4; src_offset: ub4): sword; function LobLocatorIsInit(envhp: POCIEnv; errhp: POCIError; locp: POCILobLocator; var is_initialized: LongBool): sword; function LobOpen(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; mode: ub1): sword; function LobRead(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; var amtp: ub4; offset: ub4; bufp: Pointer; bufl: ub4; ctxp: Pointer; cbfp: Pointer; csid: ub2; csfrm: ub1): sword; function LobTrim(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; newlen: ub4): sword; function LobWrite(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; var amtp: ub4; offset: ub4; bufp: Pointer; bufl: ub4; piece: ub1; ctxp: Pointer; cbfp: Pointer; csid: ub2; csfrm: ub1): sword; function LobCreateTemporary(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; csid: ub2; csfrm: ub1; lobtype: ub1; cache: LongBool; duration: OCIDuration): sword; function LobIsTemporary(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; var is_temporary: LongBool): sword; function LobFreeTemporary(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator): sword; function LobCharSetForm ( envhp: POCIEnv; errhp: POCIError; const locp: POCILobLocator; csfrm: pub1): sword; function LobCharSetId ( envhp: POCIEnv; errhp: POCIError; const locp: POCILobLocator; csid: pub2): sword; function StmtGetPieceInfo(stmtp: POCIStmt; errhp: POCIError; var hndlpp: Pointer; var typep: ub4; var in_outp: ub1; var iterp: ub4; var idxp: ub4; var piecep: ub1): sword; function StmtSetPieceInfo(handle: Pointer; typep: ub4; errhp: POCIError; buf: Pointer; var alenp: ub4; piece: ub1; indp: Pointer; var rcodep: ub2): sword; function PasswordChange(svchp: POCISvcCtx; errhp: POCIError; user_name: text; usernm_len: ub4; opasswd: text; opasswd_len: ub4; npasswd: text; npasswd_len: sb4; mode: ub4): sword; function ServerVersion(hndlp: POCIHandle; errhp: POCIError; bufp: text; bufsz: ub4; hndltype: ub1): sword; function ServerRelease(hndlp: POCIHandle; errhp: POCIError; bufp: text; bufsz: ub4; hndltype: ub1; version:pointer): sword; function ResultSetToStmt(rsetdp: POCIHandle; errhp: POCIError): sword; function GetEnvCharsetByteWidth(hndl: POCIEnv; err: POCIError; Value: sb4): sword; procedure ClientVersion(major_version, minor_version, update_num, patch_num, port_update_num: psword); function NumberInc(err: POCIError; number: POCINumber): sword; function NumberDec(err: POCIError; number: POCINumber): sword; procedure NumberSetZero(err: POCIError; number: POCINumber); procedure NumberSetPi(err: POCIError; number: POCINumber); function NumberAdd(err: POCIError; const number1: POCINumber; const number2: POCINumber; _result: POCINumber): sword; function NumberSub(err: POCIError; const number1: POCINumber; const number2: POCINumber; _result: POCINumber): sword; function NumberMul(err: POCIError; const number1: POCINumber; const number2: POCINumber; _result: POCINumber): sword; function NumberDiv(err: POCIError; const number1: POCINumber; const number2: POCINumber; _result: POCINumber): sword; function NumberMod(err: POCIError; const number1: POCINumber; const number2: POCINumber; _result: POCINumber): sword; function NumberIntPower(err: POCIError; const number1: POCINumber; const number2: POCINumber; _result: POCINumber): sword; function NumberShift(err: POCIError; const number: POCINumber; const nDig: sword; _result: POCINumber): sword; function NumberNeg(err: POCIError; const number: POCINumber; _result: POCINumber): sword; function NumberToText(err: POCIError; const number: POCINumber; const fmt: Poratext; fmt_length: ub4; const nls_params: Poratext; nls_p_length: ub4; buf_size: pub4; buf: poratext): sword; function NumberFromText(err: POCIError; const str: poratext; str_length: ub4; const fmt: poratext; fmt_length: ub4; const nls_params: poratext; nls_p_length: ub4; number: POCINumber): sword; function NumberToInt(err: POCIError; const number: POCINumber; rsl_length: uword; rsl_flag: uword; rsl: Pointer): sword; function NumberFromInt(err: POCIError; const inum: Pointer; inum_length: uword; inum_s_flag: uword; number: POCINumber): sword; function NumberToReal(err: POCIError; const number: POCINumber; rsl_length: uword; rsl: Pointer): sword; function NumberToRealArray(err: POCIError; const number: PPOCINumber; elems: uword; rsl_length: uword; rsl: Pointer): sword; function NumberFromReal(err: POCIError; const rnum: Pointer; rnum_length: uword; number: POCINumber): sword; function NumberCmp(err: POCIError; const number1: POCINumber; const number2: POCINumber; _result: psword): sword; function NumberSign(err: POCIError; const number: POCINumber; _result: psword): sword; function NumberIsZero(err: POCIError; const number: POCINumber; _Result: pboolean): sword; function NumberIsInt(err: POCIError; const number: POCINumber; _result: Pboolean): sword; function NumberAssign(err: POCIError; const from: POCINumber; _to: POCINumber): sword; function NumberAbs(err: POCIError; const number: POCINumber; _result: POCINumber): sword; function NumberCeil(err: POCIError; const number: POCINumber; _result: POCINumber): sword; function NumberFloor(err: POCIError; const number: POCINumber; _result: POCINumber): sword; function NumberSqrt(err: POCIError; const number: POCINumber; _result: POCINumber): sword; function NumberTrunc(err: POCIError; const number: POCINumber; _result: POCINumber): sword; function NumberPower(err: POCIError; const base: POCINumber; const number: POCINumber; _result: POCINumber): sword; function NumberRound(err: POCIError; const number: POCINumber; decplace: sword; _result: POCINumber): sword; function NumberPrec(err: POCIError; const number: POCINumber; nDigs: sword; _result: POCINumber): sword; function NumberSin(err: POCIError; const number: POCINumber; _result: POCINumber): sword; function NumberArcSin(err: POCIError; const number: POCINumber; _result: POCINumber): sword; function NumberHypSin(err: POCIError; const number: POCINumber; _result: POCINumber): sword; function NumberCos(err: POCIError; const number: POCINumber; _result: POCINumber): sword; function NumberArcCos(err: POCIError; const number: POCINumber; _result: POCINumber): sword; function NumberHypCos(err: POCIError; const number: POCINumber; _result: POCINumber): sword; function NumberTan(err: POCIError; const number: POCINumber; _result: POCINumber): sword; function NumberArcTan(err: POCIError; const number: POCINumber; _result: POCINumber): sword; function NumberArcTan2(err: POCIError; const number1: POCINumber; const number2: POCINumber; _result: POCINumber): sword; function NumberHypTan(err: POCIError; const number: POCINumber; _result: POCINumber): sword; function NumberExp(err: POCIError; const number: POCINumber; _result: POCINumber): sword; function NumberLn(err: POCIError; const number: POCINumber; _result: POCINumber): sword; function NumberLog(err: POCIError; const base: POCINumber; const number: POCINumber; _result: POCINumber): sword; function TableSize(hndl: POCIEnv; err: POCIError; const tbl: POCITable; size: psb4): sword; function TableExists(hndl: POCIEnv; err: POCIError; const tbl: POCITable; index: sb4; exists: PBoolean): sword; function TableDelete(hndl: POCIEnv; err: POCIError; index: sb4; tbl: POCITable): sword; function TableFirst(hndl: POCIEnv; err: POCIError; const tbl: POCITable; index: sb4): sword; function TableLast(hndl: POCIEnv; err: POCIError; const tbl: POCITable; index: sb4): sword; function TableNext(hndl: POCIEnv; err: POCIError; index: sb4; const tbl: POCITable; next_index: psb4; exists: PBoolean): sword; function TablePrev(hndl: POCIEnv; err: POCIError; index: sb4; const tbl: POCITable; prev_index: psb4; exists: PBoolean): sword; function ObjectSetAttr(env: POCIEnv; err: POCIError; instance: Pointer; null_struct: pointer; tdo: POCIType; const names: PPAnsiChar; const lengths: pub4; const name_count: ub4; const indexes: pub4; const index_count: ub4; const null_status: POCIInd; const attr_null_struct: Pointer; const attr_value: Pointer): sword; cdecl; function ObjectGetAttr(env: POCIEnv; err: POCIError; instance: Pointer; null_struct: Pointer; tdo: POCIType; const names: PPoratext; const lengths: pub4; const name_count: ub4; const indexes: pub4; const index_count: ub4; attr_null_status: POCIInd; attr_null_struct, attr_value: PPointer; attr_tdo: PPOCIType): sword; {ociap.h} function Ping(svchp: POCISvcCtx; errhp: POCIError; mode: ub4 = OCI_DEFAULT): sword; {ort.h} function TypeIterNew(env: POCIEnv; err: POCIError; const tdo: POCIType; iterator_ort: PPOCITypeIter):sword; function TypeIterSet(env: POCIEnv; err: POCIError; const tdo: POCIType; iterator_ort: POCITypeIter): sword; function TypeIterFree(env: POCIEnv; err: POCIError; iterator_ort: POCITypeIter): sword; function TypeByName(env: POCIEnv; err: POCIError; const svc: POCISvcCtx; schema_name: Poratext; const s_length: ub4; const type_name: Poratext; const t_length: ub4; version_name: Poratext; const v_length: ub4; const pin_duration: OCIDuration; const get_option: OCITypeGetOpt; tdo: PPOCIType): sword; function TypeArrayByName(env: POCIEnv; err: POCIError; svc: POCISvcCtx; array_len: ub4; schema_name: PPoratext; s_length: Pub4; type_name: PPoratext; t_length: Pub4; version_name: PPoratext; v_length: Pub4; pin_duration: OCIDuration; get_option: OCITypeGetOpt; tdo: PPOCIType): sword; function TypeByRef(env: POCIEnv; err: POCIError; type_ref: POCIRef; pin_duration: OCIDuration; get_option: OCITypeGetOpt; tdo: PPOCIType): sword; function TypeArrayByRef(env: POCIEnv; err: POCIError; array_len: ub4; type_ref: PPOCIRef; pin_duration: OCIDuration; get_option: OCITypeGetOpt; tdo: PPOCIType): sword; function TypeName(env: POCIEnv; err: POCIError; tdo: POCIType; n_length: Pub4): poratext; function TypeSchema(env: POCIEnv; err: POCIError; const tdo: POCIType; n_length: Pub4): poratext; function TypeTypeCode(env: POCIEnv; err: POCIError; const tdo: POCIType): OCITypeCode; function TypeCollTypeCode(env:POCIEnv; err:POCIError; const tdo: POCIType): OCITypeCode; function TypeVersion(env: POCIEnv; err: POCIError; const tdo: POCIType; v_length: Pub4): poratext; function TypeAttrs(env: POCIEnv; err: POCIError; const tdo:POCIType): ub4; function TypeMethods(env: POCIEnv; err: POCIError; const tdo: POCIType): ub4; function TypeElemName(env: POCIEnv; err: POCIError; const elem: POCITypeElem; n_length:Pub4): poratext; function TypeElemTypeCode(env: POCIEnv; err: POCIError; const elem: POCITypeElem): OCITypeCode; function TypeElemType(env: POCIEnv; err: POCIError; const elem: POCITypeElem; elem_tdo:PPOCIType): sword; function TypeElemFlags(env: POCIEnv; err: POCIError; const elem: POCITypeElem): ub4; function TypeElemNumPrec(env: POCIEnv; err: POCIError; const elem: POCITypeElem): ub1; function TypeElemNumScale(env: POCIEnv; err: POCIError; const elem: POCITypeElem): sb1; function TypeElemLength(env: POCIEnv; err: POCIError; const elem:POCITypeElem): ub4; function TypeElemCharSetID(env: POCIEnv; err: POCIError; const elem: POCITypeElem): ub2; function TypeElemCharSetForm(env: POCIEnv; err: POCIError; const elem: POCITypeElem): ub2; function TypeElemParameterizedType(env: POCIEnv; err: POCIError; const elem: POCITypeElem; type_stored: PPOCIType): sword; function TypeElemExtTypeCode(env: POCIEnv; err: POCIError; const elem: POCITypeElem): OCITypeCode; function TypeAttrByName(env: POCIEnv; err: POCIError; const tdo: POCIType; const name: Poratext; const n_length: ub4; elem: PPOCITypeElem): sword; function TypeAttrNext(env: POCIEnv; err: POCIError; iterator_ort: POCITypeIter; elem: PPOCITypeElem): sword; function TypeCollElem(env: POCIEnv; err: POCIError; const tdo:POCIType; element: PPOCITypeElem): sword; function TypeCollSize(env: POCIEnv; err: POCIError; const tdo: POCIType; num_elems: Pub4): sword; function TypeCollExtTypeCode(env: POCIEnv; err: POCIError; const tdo:POCIType; sqt_code: POCITypeCode): sword; function TypeMethodOverload(env: POCIEnv; err: POCIError; const tdo: POCIType; const method_name: Poratext; const m_length: ub4): ub4; function TypeMethodByName(env: POCIEnv; err: POCIError; const tdo: POCIType; const method_name: Poratext; const m_length: ub4; mdos: PPOCITypeMethod): sword; function TypeMethodNext(env: POCIEnv; err: POCIError; iterator_ort: POCITypeIter; mdo: PPOCITypeMethod): sword; function TypeMethodName(env:POCIEnv; err: POCIError; const mdo: POCITypeMethod; n_length: Pub4): poratext; function TypeMethodEncap(env: POCIEnv; err: POCIError; const mdo: POCITypeMethod): OCITypeEncap; function TypeMethodFlags(env: POCIEnv; err: POCIError; const mdo:POCITypeMethod): OCITypeMethodFlag; function TypeMethodMap(env: POCIEnv; err: POCIError; const tdo: POCIType; mdo: PPOCITypeMethod): sword; function TypeMethodOrder(env: POCIEnv; err: POCIError; const tdo: POCIType; mdo: PPOCITypeMethod): sword; function TypeMethodParams(env: POCIEnv; err: POCIError; const mdo: POCITypeMethod): ub4; function TypeResult(env: POCIEnv; err: POCIError; const mdo: POCITypeMethod; elem: PPOCITypeElem): sword; function TypeParamByPos(env: POCIEnv; err: POCIError; const mdo: POCITypeMethod; const position: ub4; elem: PPOCITypeElem): sword; function TypeParamByName(env: POCIEnv; err: POCIError; const mdo: POCITypeMethod; const name: Poratext; const n_length: ub4; elem:PPOCITypeElem): sword; function TypeParamPos(env: POCIEnv; err: POCIError; const mdo: POCITypeMethod; const name: Poratext; const n_length: ub4; position: Pub4; elem: PPOCITypeElem): sword; function TypeElemParamMode(env: POCIEnv; err: POCIError; const elem: POCITypeElem): OCITypeParamMode; function TypeElemDefaultValue(env: POCIEnv; err: POCIError; const elem: POCITypeElem; d_v_length: Pub4): poratext; function TypeVTInit(env: POCIEnv; err: POCIError): sword; function TypeVTInsert(env: POCIEnv; err: POCIError; const schema_name: Poratext; const s_n_length: ub4; const type_name: Poratext; const t_n_length: ub4; const user_version:Poratext; const u_v_length:ub4): sword; function TypeVTSelect(env: POCIEnv; err: POCIError; const schema_name: Poratext; const s_n_length: ub4; const type_name: Poratext; const t_n_length: ub4; user_version: PPoratext; u_v_length: Pub4; version: Pub2): sword; end; {** Implements a driver for Oracle 9i } TZOracle9iPlainDriver = class (TZAbstractPlainDriver, IZPlainDriver, IZOraclePlainDriver) private OracleAPI: OracleOCI_API; protected procedure LoadApi; override; function Clone: IZPlainDriver; override; public constructor Create; function GetUnicodeCodePageName: String; override; procedure LoadCodePages; override; function GetProtocol: string; override; function GetDescription: string; override; procedure Initialize(const Location: String); override; function Initializ(mode: ub4; ctxp: Pointer; malocfp: Pointer; ralocfp: Pointer; mfreefp: Pointer): sword; function EnvInit(var envhpp: POCIEnv; mode: ub4; xtramemsz: size_T; usrmempp: PPointer): sword; function EnvCreate(var envhpp: POCIEnv; mode: ub4; ctxp: Pointer; malocfp: Pointer; ralocfp: Pointer; mfreefp: Pointer; xtramemsz: size_T; usrmempp: PPointer): sword; function EnvNlsCreate(var envhpp: POCIEnv; mode: ub4; ctxp: Pointer; malocfp: Pointer; ralocfp: Pointer; mfreefp: Pointer; xtramemsz: size_T; usrmempp: PPointer; charset, ncharset: ub2): sword; function HandleAlloc(parenth: POCIHandle; var hndlpp: POCIHandle; atype: ub4; xtramem_sz: size_T; usrmempp: PPointer): sword; function ServerAttach(srvhp: POCIServer; errhp: POCIError; dblink: text; dblink_len: sb4; mode: ub4): sword; function AttrSet(trgthndlp: POCIHandle; trghndltyp: ub4; attributep: Pointer; size: ub4; attrtype: ub4; errhp: POCIError):sword; function SessionBegin(svchp: POCISvcCtx; errhp: POCIError; usrhp: POCISession; credt: ub4; mode: ub4):sword; function SessionEnd(svchp: POCISvcCtx; errhp: POCIError; usrhp: POCISession; mode: ub4): sword; function ServerDetach(srvhp: POCIServer; errhp: POCIError; mode: ub4): sword; function HandleFree(hndlp: Pointer; atype: ub4): sword; function ErrorGet(hndlp: Pointer; recordno: ub4; sqlstate: text; var errcodep: sb4; bufp: text; bufsiz: ub4; atype: ub4): sword; function StmtPrepare(stmtp: POCIStmt; errhp: POCIError; stmt: text; stmt_len: ub4; language:ub4; mode: ub4):sword; function StmtExecute(svchp: POCISvcCtx; stmtp: POCIStmt; errhp: POCIError; iters: ub4; rowoff: ub4; snap_in: POCISnapshot; snap_out: POCISnapshot; mode: ub4): sword; function ParamGet(hndlp: Pointer; htype: ub4; errhp: POCIError; var parmdpp: Pointer; pos: ub4): sword; function AttrGet(trgthndlp: POCIHandle; trghndltyp: ub4; attributep: Pointer; sizep: Pointer; attrtype: ub4; errhp: POCIError): sword; function StmtFetch(stmtp: POCIStmt; errhp: POCIError; nrows: ub4; orientation: ub2; mode: ub4): sword; function DefineByPos(stmtp: POCIStmt; var defnpp: POCIDefine; errhp: POCIError; position: ub4; valuep: Pointer; value_sz: sb4; dty: ub2; indp: Pointer; rlenp: Pointer; rcodep: Pointer; mode: ub4): sword; function DefineArrayOfStruct(defnpp: POCIDefine; errhp: POCIError; pvskip: ub4; indskip: ub4; rlskip: ub4; rcskip: ub4): sword; function BindByPos(stmtp: POCIStmt; var bindpp: POCIBind; errhp: POCIError; position: ub4; valuep: Pointer; value_sz: sb4; dty: ub2; indp: Pointer; alenp: Pointer; rcodep: Pointer; maxarr_len: ub4; curelep: Pointer; mode: ub4): sword; function BindByName(stmtp: POCIStmt; var bindpp: POCIBind; errhp: POCIError; placeholder: text; placeh_len: sb4; valuep: Pointer; value_sz: sb4; dty: ub2; indp: Pointer; alenp: Pointer; rcodep: Pointer; maxarr_len: ub4; curelep: Pointer; mode: ub4): sword; function BindDynamic(bindp: POCIBind; errhp: POCIError; ictxp: Pointer; icbfp: Pointer; octxp: Pointer; ocbfp: Pointer): sword; function BindObject(bindp: POCIBind; errhp: POCIError; const _type: POCIType; pgvpp: PPointer; pvszsp: pub4; indpp: PPointer; indszp: pub4): sword; function DefineObject(defnpp:POCIDefine; errhp:POCIError; _type:POCIHandle; pgvpp,pvszsp,indpp,indszp:pointer): sword; { > ori.h} function ObjectNew(env: POCIEnv; err: POCIError; const svc: POCISvcCtx; typecode: OCITypeCode; tdo: POCIType; table: Pointer; duration: OCIDuration; value: Longbool; instance: PPointer): sword; function ObjectPin(env: POCIEnv; err: POCIError; const object_ref: POCIRef; const corhdl: POCIComplexObject; const pin_option: OCIPinOpt; const pin_duration: OCIDuration; const lock_option: OCILockOpt; _object: PPointer): sword; function ObjectUnpin(env: POCIEnv; err: POCIError; const _object: Pointer): sword; function ObjectPinCountReset(env: POCIEnv; err: POCIError; const _object: pointer): sword; function ObjectLock(env: POCIEnv; err: POCIError; const _object: pointer): sword; function ObjectLockNoWait(env: POCIEnv; err: POCIError; const _object: pointer): sword; function ObjectMarkUpdate(env: POCIEnv; err: POCIError; const _object: pointer): sword; function ObjectUnmark(env: POCIEnv; err: POCIError; const _object:pointer): sword; function ObjectUnmarkByRef(env: POCIEnv; err: POCIError; const ref: POCIRef): sword; function ObjectFree(hndl: POCIEnv; err: POCIError; instance:POCIHandle;flags :ub2):sword; function ObjectMarkDeleteByRef(env: POCIEnv; err: POCIError; const object_ref:POCIRef): sword; function ObjectMarkDelete(env: POCIEnv; err: POCIError; const instance:pointer): sword; function ObjectFlush(env: POCIEnv; err: POCIError; const _object: pointer): sword; function ObjectRefresh(env: POCIEnv; err: POCIError; _object: pointer): sword; function ObjectCopy(env: POCIEnv; err: POCIError; const svc: POCISvcCtx; const source, null_source, target, null_target: pointer; const tdo: POCIType; const duration: OCIDuration; const option: ub1): sword; function ObjectGetTypeRef(env: POCIEnv; err: POCIError; const instance:pointer; type_ref: POCIRef): sword; function ObjectGetObjectRef(env: POCIEnv; err: POCIError; const _object: pointer; object_ref: POCIRef): sword; function ObjectMakeObjectRef(env: POCIEnv; err: POCIError; const svc: POCISvcCtx; const table: pointer; const values: PPointer; const array_len: ub4; object_ref: POCIRef): sword; function ObjectGetPrimaryKeyTypeRef(env: POCIEnv; err: POCIError; const svc:POCISvcCtx; const table: pointer; type_ref: POCIRef): sword; function ObjectGetInd(env: POCIEnv; err: POCIError; const instance: pointer; null_struct: PPointer): sword; function ObjectExists(env: POCIEnv; err: POCIError; const ins: pointer; exist: PBoolean): sword; function ObjectGetProperty(envh: POCIEnv; errh: POCIError; const obj: pointer; const propertyId: OCIObjectPropId; _property: pointer; size: Pub4): sword; function ObjectIsLocked(env: POCIEnv; err: POCIError; const ins: pointer; lock: Pboolean): sword; function ObjectIsDirty(env: POCIEnv; err: POCIError; const ins: pointer; dirty: PBoolean): sword; function ObjectPinTable(env: POCIEnv; err: POCIError; const svc:POCISvcCtx; const schema_name: Poratext; const s_n_length: ub4; const object_name: Poratext; const o_n_length:ub4; const scope_obj_ref: POCIRef; const pin_duration: OCIDuration; _object: PPointer): sword; function ObjectArrayPin(env: POCIEnv; err: POCIError; const ref_array: PPOCIRef; const array_size: ub4; const cor_array: PPOCIComplexObject; const cor_array_size: ub4; const pin_option: OCIPinOpt; const pin_duration: OCIDuration; const lock: OCILockOpt; obj_array: PPointer; pos: Pub4): sword; function CacheFlush(env: POCIEnv; err: POCIError; const svc:POCISvcCtx; const context: pointer; const get: TOCICacheFlushGet; ref: PPOCIRef): sword; function CacheRefresh(env: POCIEnv; err: POCIError; const svc:POCISvcCtx; const option: OCIRefreshOpt; const context: pointer; get: TOCICacheRefreshGet; ref: PPOCIRef): sword; function CacheUnpin(env: POCIEnv; err: POCIError; const svc:POCISvcCtx): sword; function CacheFree(env: POCIEnv; err: POCIError; const svc: POCISvcCtx): sword; function CacheUnmark(env: POCIEnv; err: POCIError; const svc: POCISvcCtx): sword; function DurationBegin(env: POCIEnv; err: POCIError; svc: POCISvcCtx; const parent: OCIDuration; dur: POCIDuration): sword; function DurationEnd(env: POCIEnv; err: POCIError; svc: POCISvcCtx; duration: OCIDuration): sword; { < ori.h} function TransStart(svchp: POCISvcCtx; errhp: POCIError; timeout: word; flags: ub4): sword; function TransRollback(svchp:POCISvcCtx; errhp:POCIError; flags: ub4): sword; function TransCommit(svchp: POCISvcCtx; errhp: POCIError; flags: ub4): sword; function TransDetach(svchp: POCISvcCtx; errhp: POCIError; flags: ub4): sword; function TransPrepare(svchp: POCISvcCtx; errhp: POCIError; flags: ub4): sword; function TransForget(svchp: POCISvcCtx; errhp: POCIError; flags: ub4): sword; function DescribeAny(svchp: POCISvcCtx; errhp: POCIError; objptr: Pointer; objnm_len: ub4; objptr_typ: ub1; info_level: ub1; objtyp: ub1; dschp: POCIDescribe): sword; function Break(svchp: POCISvcCtx; errhp:POCIError): sword; function Reset(svchp: POCISvcCtx; errhp:POCIError): sword; function DescriptorAlloc(parenth: POCIEnv; var descpp: POCIDescriptor; htype: ub4; xtramem_sz: integer; usrmempp: Pointer): sword; function DescriptorFree(descp: Pointer; htype: ub4): sword; function DateTimeAssign(hndl: POCIEnv; err: POCIError; const from: POCIDateTime;_to: POCIDateTime): sword; function DateTimeCheck(hndl: POCIEnv; err: POCIError; const date: POCIDateTime; var valid: ub4): sword; function DateTimeCompare(hndl: POCIEnv; err: POCIError; const date1: POCIDateTime; const date2: POCIDateTime; var _result: sword): sword; function DateTimeConvert(hndl: POCIEnv; err: POCIError; indate: POCIDateTime; outdate: POCIDateTime): sword; function DateTimeFromText(hndl: POCIEnv; err: POCIError; const date_str: text; d_str_length: size_t; const fmt: text; fmt_length: ub1; const lang_name: text; lang_length: size_t; date: POCIDateTime): sword; function DateTimeGetDate(hndl: POCIEnv; err: POCIError; const date: POCIDateTime; var year: sb2; var month: ub1; var day: ub1): sword; function DateTimeGetTime(hndl: POCIEnv; err: POCIError; datetime: POCIDateTime; var hour: ub1; var minute: ub1; var sec: ub1; var fsec: ub4): sword; function DateTimeGetTimeZoneOffset(hndl: POCIEnv; err: POCIError; const datetime: POCIDateTime; var hour: sb1; var minute: sb1): sword; function DateTimeSysTimeStamp(hndl: POCIEnv; err: POCIError; sys_date: POCIDateTime): sword; function DateTimeConstruct(hndl: POCIEnv; err: POCIError; datetime: POCIDateTime; year: sb2; month: ub1; day: ub1; hour: ub1; min: ub1; sec: ub1; fsec: ub4; timezone: text; timezone_length: size_t): sword; function DateTimeToText(hndl: POCIEnv; err: POCIError; const date: POCIDateTime; const fmt: text; fmt_length: ub1; fsprec: ub1; const lang_name: text; lang_length: size_t; var buf_size: ub4; buf: text): sword; function DateTimeGetTimeZoneName(hndl: POCIEnv; err: POCIError; datetime: POCIDateTime; var buf: ub1; var buflen: ub4): sword; function LobAppend(svchp: POCISvcCtx; errhp: POCIError; dst_locp, src_locp: POCILobLocator): sword; function LobAssign(svchp: POCISvcCtx; errhp: POCIError; src_locp: POCILobLocator; var dst_locpp: POCILobLocator): sword; function LobClose(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator): sword; function LobCopy(svchp: POCISvcCtx; errhp: POCIError; dst_locp: POCILobLocator; src_locp: POCILobLocator; amount: ub4; dst_offset: ub4; src_offset: ub4): sword; function LobEnableBuffering(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator): sword; function LobDisableBuffering(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator): sword; function LobErase(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; var amount: ub4; offset: ub4): sword; function LobFileExists(svchp: POCISvcCtx; errhp: POCIError; filep: POCILobLocator; var flag: Boolean): sword; function LobFileGetName(envhp: POCIEnv; errhp: POCIError; filep: POCILobLocator; dir_alias: text; var d_length: ub2; filename: text; var f_length: ub2): sword; function LobFileSetName(envhp: POCIEnv; errhp: POCIError; var filep: POCILobLocator; dir_alias: text; d_length: ub2; filename: text; f_length: ub2): sword; function LobFlushBuffer(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; flag: ub4): sword; function LobGetLength(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; var lenp: ub4): sword; function LobIsOpen(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; var flag: LongBool): sword; function LobLoadFromFile(svchp: POCISvcCtx; errhp: POCIError; dst_locp: POCILobLocator; src_locp: POCILobLocator; amount: ub4; dst_offset: ub4; src_offset: ub4): sword; function LobLocatorIsInit(envhp: POCIEnv; errhp: POCIError; locp: POCILobLocator; var is_initialized: LongBool): sword; function LobOpen(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; mode: ub1): sword; function LobRead(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; var amtp: ub4; offset: ub4; bufp: Pointer; bufl: ub4; ctxp: Pointer; cbfp: Pointer; csid: ub2; csfrm: ub1): sword; function LobTrim(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; newlen: ub4): sword; function LobWrite(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; var amtp: ub4; offset: ub4; bufp: Pointer; bufl: ub4; piece: ub1; ctxp: Pointer; cbfp: Pointer; csid: ub2; csfrm: ub1): sword; function LobCreateTemporary(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; csid: ub2; csfrm: ub1; lobtype: ub1; cache: LongBool; duration: OCIDuration): sword; function LobIsTemporary(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; var is_temporary: LongBool): sword; function LobFreeTemporary(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator): sword; function LobCharSetForm ( envhp: POCIEnv; errhp: POCIError; const locp: POCILobLocator; csfrm: pub1): sword; function LobCharSetId ( envhp: POCIEnv; errhp: POCIError; const locp: POCILobLocator; csid: pub2): sword; function StmtGetPieceInfo(stmtp: POCIStmt; errhp: POCIError; var hndlpp: Pointer; var typep: ub4; var in_outp: ub1; var iterp: ub4; var idxp: ub4; var piecep: ub1): sword; function StmtSetPieceInfo(handle: Pointer; typep: ub4; errhp: POCIError; buf: Pointer; var alenp: ub4; piece: ub1; indp: Pointer; var rcodep: ub2): sword; function PasswordChange(svchp: POCISvcCtx; errhp: POCIError; user_name: text; usernm_len: ub4; opasswd: text; opasswd_len: ub4; npasswd: text; npasswd_len: sb4; mode: ub4): sword; function ServerVersion(hndlp: POCIHandle; errhp: POCIError; bufp: text; bufsz: ub4; hndltype: ub1): sword; function ServerRelease(hndlp: POCIHandle; errhp: POCIError; bufp: text; bufsz: ub4; hndltype: ub1; version:pointer): sword; function ResultSetToStmt(rsetdp: POCIHandle; errhp: POCIError): sword; function GetEnvCharsetByteWidth(hndl: POCIEnv; err: POCIError; Value: sb4): sword; procedure ClientVersion(major_version, minor_version, update_num, patch_num, port_update_num: psword); function NumberInc(err: POCIError; number: POCINumber): sword; function NumberDec(err: POCIError; number: POCINumber): sword; procedure NumberSetZero(err: POCIError; number: POCINumber); procedure NumberSetPi(err: POCIError; number: POCINumber); function NumberAdd(err: POCIError; const number1: POCINumber; const number2: POCINumber; _result: POCINumber): sword; function NumberSub(err: POCIError; const number1: POCINumber; const number2: POCINumber; _result: POCINumber): sword; function NumberMul(err: POCIError; const number1: POCINumber; const number2: POCINumber; _result: POCINumber): sword; function NumberDiv(err: POCIError; const number1: POCINumber; const number2: POCINumber; _result: POCINumber): sword; function NumberMod(err: POCIError; const number1: POCINumber; const number2: POCINumber; _result: POCINumber): sword; function NumberIntPower(err: POCIError; const number1: POCINumber; const number2: POCINumber; _result: POCINumber): sword; function NumberShift(err: POCIError; const number: POCINumber; const nDig: sword; _result: POCINumber): sword; function NumberNeg(err: POCIError; const number: POCINumber; _result: POCINumber): sword; function NumberToText(err: POCIError; const number: POCINumber; const fmt: Poratext; fmt_length: ub4; const nls_params: Poratext; nls_p_length: ub4; buf_size: pub4; buf: poratext): sword; function NumberFromText(err: POCIError; const str: poratext; str_length: ub4; const fmt: poratext; fmt_length: ub4; const nls_params: poratext; nls_p_length: ub4; number: POCINumber): sword; function NumberToInt(err: POCIError; const number: POCINumber; rsl_length: uword; rsl_flag: uword; rsl: Pointer): sword; function NumberFromInt(err: POCIError; const inum: Pointer; inum_length: uword; inum_s_flag: uword; number: POCINumber): sword; function NumberToReal(err: POCIError; const number: POCINumber; rsl_length: uword; rsl: Pointer): sword; function NumberToRealArray(err: POCIError; const number: PPOCINumber; elems: uword; rsl_length: uword; rsl: Pointer): sword; function NumberFromReal(err: POCIError; const rnum: Pointer; rnum_length: uword; number: POCINumber): sword; function NumberCmp(err: POCIError; const number1: POCINumber; const number2: POCINumber; _result: psword): sword; function NumberSign(err: POCIError; const number: POCINumber; _result: psword): sword; function NumberIsZero(err: POCIError; const number: POCINumber; _Result: pboolean): sword; function NumberIsInt(err: POCIError; const number: POCINumber; _result: Pboolean): sword; function NumberAssign(err: POCIError; const from: POCINumber; _to: POCINumber): sword; function NumberAbs(err: POCIError; const number: POCINumber; _result: POCINumber): sword; function NumberCeil(err: POCIError; const number: POCINumber; _result: POCINumber): sword; function NumberFloor(err: POCIError; const number: POCINumber; _result: POCINumber): sword; function NumberSqrt(err: POCIError; const number: POCINumber; _result: POCINumber): sword; function NumberTrunc(err: POCIError; const number: POCINumber; _result: POCINumber): sword; function NumberPower(err: POCIError; const base: POCINumber; const number: POCINumber; _result: POCINumber): sword; function NumberRound(err: POCIError; const number: POCINumber; decplace: sword; _result: POCINumber): sword; function NumberPrec(err: POCIError; const number: POCINumber; nDigs: sword; _result: POCINumber): sword; function NumberSin(err: POCIError; const number: POCINumber; _result: POCINumber): sword; function NumberArcSin(err: POCIError; const number: POCINumber; _result: POCINumber): sword; function NumberHypSin(err: POCIError; const number: POCINumber; _result: POCINumber): sword; function NumberCos(err: POCIError; const number: POCINumber; _result: POCINumber): sword; function NumberArcCos(err: POCIError; const number: POCINumber; _result: POCINumber): sword; function NumberHypCos(err: POCIError; const number: POCINumber; _result: POCINumber): sword; function NumberTan(err: POCIError; const number: POCINumber; _result: POCINumber): sword; function NumberArcTan(err: POCIError; const number: POCINumber; _result: POCINumber): sword; function NumberArcTan2(err: POCIError; const number1: POCINumber; const number2: POCINumber; _result: POCINumber): sword; function NumberHypTan(err: POCIError; const number: POCINumber; _result: POCINumber): sword; function NumberExp(err: POCIError; const number: POCINumber; _result: POCINumber): sword; function NumberLn(err: POCIError; const number: POCINumber; _result: POCINumber): sword; function NumberLog(err: POCIError; const base: POCINumber; const number: POCINumber; _result: POCINumber): sword; function TableSize(hndl: POCIEnv; err: POCIError; const tbl: POCITable; size: psb4): sword; function TableExists(hndl: POCIEnv; err: POCIError; const tbl: POCITable; index: sb4; exists: PBoolean): sword; function TableDelete(hndl: POCIEnv; err: POCIError; index: sb4; tbl: POCITable): sword; function TableFirst(hndl: POCIEnv; err: POCIError; const tbl: POCITable; index: sb4): sword; function TableLast(hndl: POCIEnv; err: POCIError; const tbl: POCITable; index: sb4): sword; function TableNext(hndl: POCIEnv; err: POCIError; index: sb4; const tbl: POCITable; next_index: psb4; exists: PBoolean): sword; function TablePrev(hndl: POCIEnv; err: POCIError; index: sb4; const tbl: POCITable; prev_index: psb4; exists: PBoolean): sword; function ObjectSetAttr(env: POCIEnv; err: POCIError; instance: Pointer; null_struct: pointer; tdo: POCIType; const names: PPAnsiChar; const lengths: pub4; const name_count: ub4; const indexes: pub4; const index_count: ub4; const null_status: POCIInd; const attr_null_struct: Pointer; const attr_value: Pointer): sword; cdecl; function ObjectGetAttr(env: POCIEnv; err: POCIError; instance: Pointer; null_struct: Pointer; tdo: POCIType; const names: PPoratext; const lengths: pub4; const name_count: ub4; const indexes: pub4; const index_count: ub4; attr_null_status: POCIInd; attr_null_struct, attr_value: PPointer; attr_tdo: PPOCIType): sword; {ociap.h} function Ping(svchp: POCISvcCtx; errhp: POCIError; mode: ub4 = OCI_DEFAULT): sword; {ort.h} function TypeIterNew(env: POCIEnv; err: POCIError; const tdo: POCIType; iterator_ort: PPOCITypeIter):sword; function TypeIterSet(env: POCIEnv; err: POCIError; const tdo: POCIType; iterator_ort: POCITypeIter): sword; function TypeIterFree(env: POCIEnv; err: POCIError; iterator_ort: POCITypeIter): sword; function TypeByName(env: POCIEnv; err: POCIError; const svc: POCISvcCtx; schema_name: Poratext; const s_length: ub4; const type_name: Poratext; const t_length: ub4; version_name: Poratext; const v_length: ub4; const pin_duration: OCIDuration; const get_option: OCITypeGetOpt; tdo: PPOCIType): sword; function TypeArrayByName(env: POCIEnv; err: POCIError; svc: POCISvcCtx; array_len: ub4; schema_name: PPoratext; s_length: Pub4; type_name: PPoratext; t_length: Pub4; version_name: PPoratext; v_length: Pub4; pin_duration: OCIDuration; get_option: OCITypeGetOpt; tdo: PPOCIType): sword; function TypeByRef(env: POCIEnv; err: POCIError; type_ref: POCIRef; pin_duration: OCIDuration; get_option: OCITypeGetOpt; tdo: PPOCIType): sword; function TypeArrayByRef(env: POCIEnv; err: POCIError; array_len: ub4; type_ref: PPOCIRef; pin_duration: OCIDuration; get_option: OCITypeGetOpt; tdo: PPOCIType): sword; function TypeName(env: POCIEnv; err: POCIError; tdo: POCIType; n_length: Pub4): poratext; function TypeSchema(env: POCIEnv; err: POCIError; const tdo: POCIType; n_length: Pub4): poratext; function TypeTypeCode(env: POCIEnv; err: POCIError; const tdo: POCIType): OCITypeCode; function TypeCollTypeCode(env:POCIEnv; err:POCIError; const tdo: POCIType): OCITypeCode; function TypeVersion(env: POCIEnv; err: POCIError; const tdo: POCIType; v_length: Pub4): poratext; function TypeAttrs(env: POCIEnv; err: POCIError; const tdo:POCIType): ub4; function TypeMethods(env: POCIEnv; err: POCIError; const tdo: POCIType): ub4; function TypeElemName(env: POCIEnv; err: POCIError; const elem: POCITypeElem; n_length:Pub4): poratext; function TypeElemTypeCode(env: POCIEnv; err: POCIError; const elem: POCITypeElem): OCITypeCode; function TypeElemType(env: POCIEnv; err: POCIError; const elem: POCITypeElem; elem_tdo:PPOCIType): sword; function TypeElemFlags(env: POCIEnv; err: POCIError; const elem: POCITypeElem): ub4; function TypeElemNumPrec(env: POCIEnv; err: POCIError; const elem: POCITypeElem): ub1; function TypeElemNumScale(env: POCIEnv; err: POCIError; const elem: POCITypeElem): sb1; function TypeElemLength(env: POCIEnv; err: POCIError; const elem:POCITypeElem): ub4; function TypeElemCharSetID(env: POCIEnv; err: POCIError; const elem: POCITypeElem): ub2; function TypeElemCharSetForm(env: POCIEnv; err: POCIError; const elem: POCITypeElem): ub2; function TypeElemParameterizedType(env: POCIEnv; err: POCIError; const elem: POCITypeElem; type_stored: PPOCIType): sword; function TypeElemExtTypeCode(env: POCIEnv; err: POCIError; const elem: POCITypeElem): OCITypeCode; function TypeAttrByName(env: POCIEnv; err: POCIError; const tdo: POCIType; const name: Poratext; const n_length: ub4; elem: PPOCITypeElem): sword; function TypeAttrNext(env: POCIEnv; err: POCIError; iterator_ort: POCITypeIter; elem: PPOCITypeElem): sword; function TypeCollElem(env: POCIEnv; err: POCIError; const tdo:POCIType; element: PPOCITypeElem): sword; function TypeCollSize(env: POCIEnv; err: POCIError; const tdo: POCIType; num_elems: Pub4): sword; function TypeCollExtTypeCode(env: POCIEnv; err: POCIError; const tdo:POCIType; sqt_code: POCITypeCode): sword; function TypeMethodOverload(env: POCIEnv; err: POCIError; const tdo: POCIType; const method_name: Poratext; const m_length: ub4): ub4; function TypeMethodByName(env: POCIEnv; err: POCIError; const tdo: POCIType; const method_name: Poratext; const m_length: ub4; mdos: PPOCITypeMethod): sword; function TypeMethodNext(env: POCIEnv; err: POCIError; iterator_ort: POCITypeIter; mdo: PPOCITypeMethod): sword; function TypeMethodName(env:POCIEnv; err: POCIError; const mdo: POCITypeMethod; n_length: Pub4): poratext; function TypeMethodEncap(env: POCIEnv; err: POCIError; const mdo: POCITypeMethod): OCITypeEncap; function TypeMethodFlags(env: POCIEnv; err: POCIError; const mdo:POCITypeMethod): OCITypeMethodFlag; function TypeMethodMap(env: POCIEnv; err: POCIError; const tdo: POCIType; mdo: PPOCITypeMethod): sword; function TypeMethodOrder(env: POCIEnv; err: POCIError; const tdo: POCIType; mdo: PPOCITypeMethod): sword; function TypeMethodParams(env: POCIEnv; err: POCIError; const mdo: POCITypeMethod): ub4; function TypeResult(env: POCIEnv; err: POCIError; const mdo: POCITypeMethod; elem: PPOCITypeElem): sword; function TypeParamByPos(env: POCIEnv; err: POCIError; const mdo: POCITypeMethod; const position: ub4; elem: PPOCITypeElem): sword; function TypeParamByName(env: POCIEnv; err: POCIError; const mdo: POCITypeMethod; const name: Poratext; const n_length: ub4; elem:PPOCITypeElem): sword; function TypeParamPos(env: POCIEnv; err: POCIError; const mdo: POCITypeMethod; const name: Poratext; const n_length: ub4; position: Pub4; elem: PPOCITypeElem): sword; function TypeElemParamMode(env: POCIEnv; err: POCIError; const elem: POCITypeElem): OCITypeParamMode; function TypeElemDefaultValue(env: POCIEnv; err: POCIError; const elem: POCITypeElem; d_v_length: Pub4): poratext; function TypeVTInit(env: POCIEnv; err: POCIError): sword; function TypeVTInsert(env: POCIEnv; err: POCIError; const schema_name: Poratext; const s_n_length: ub4; const type_name: Poratext; const t_n_length: ub4; const user_version:Poratext; const u_v_length:ub4): sword; function TypeVTSelect(env: POCIEnv; err: POCIError; const schema_name: Poratext; const s_n_length: ub4; const type_name: Poratext; const t_n_length: ub4; user_version: PPoratext; u_v_length: Pub4; version: Pub2): sword; end; implementation uses ZEncoding; { TZOracle9iPlainDriver } function TZOracle9iPlainDriver.GetUnicodeCodePageName: String; begin Result := 'UTF8'; end; procedure TZOracle9iPlainDriver.LoadCodePages; begin (* AddCodePage('AL16UTF16', 2000, ceUTF16, zCP_UTF16); {Unicode 3.1 UTF-16 Universal character set} AddCodePage('AL32UTF8', 873, ceUTF8, zCP_UTF8); {Unicode 3.1 UTF-8 Universal character set} //AddCodePage('AR8ADOS710', 3); {Arabic MS-DOS 710 Server 8-bit Latin/Arabic} // AddCodePage('AR8ADOS710T', 4); {Arabic MS-DOS 710 8-bit Latin/Arabic} AddCodePage('AR8ADOS720', 558); {Arabic MS-DOS 720 Server 8-bit Latin/Arabic} // AddCodePage('AR8ADOS720T', 6); {Arabic MS-DOS 720 8-bit Latin/Arabic} // AddCodePage('AR8APTEC715', 7); {APTEC 715 Server 8-bit Latin/Arabic} // AddCodePage('AR8APTEC715T', 8); {APTEC 715 8-bit Latin/Arabic} // AddCodePage('AR8ASMO708PLUS', 9); {ASMO 708 Plus 8-bit Latin/Arabic} AddCodePage('AR8ASMO8X', 500); {ASMO Extended 708 8-bit Latin/Arabic} // AddCodePage('BN8BSCII', 11); {Bangladesh National Code 8-bit BSCII} // AddCodePage('TR7DEC', 12); {DEC VT100 7-bit Turkish} // AddCodePage('TR8DEC', 13); {DEC 8-bit Turkish} // AddCodePage('EL8DEC', 14); {DEC 8-bit Latin/Greek} // AddCodePage('EL8GCOS7', 15); {Bull EBCDIC GCOS7 8-bit Greek} // AddCodePage('IN8ISCII', 16); {Multiple-Script Indian Standard 8-bit Latin/Indian Languages} // AddCodePage('JA16DBCS', 17); {IBM EBCDIC 16-bit Japanese UDC} // AddCodePage('JA16EBCDIC930', 18); {IBM DBCS Code Page 290 16-bit Japanese UDC} AddCodePage('JA16EUC', 830); {EUC 24-bit Japanese} AddCodePage('JA16EUCTILDE', 837); {The same as JA16EUC except for the way that the wave dash and the tilde are mapped to and from Unicode.} // AddCodePage('JA16EUCYEN', 21); {EUC 24-bit Japanese with '\' mapped to the Japanese yen character} // AddCodePage('JA16MACSJIS', 22); {Mac client Shift-JIS 16-bit Japanese} AddCodePage('JA16SJIS', 832); {Shift-JIS 16-bit Japanese UDC} AddCodePage('JA16SJISTILDE', 838); {The same as JA16SJIS except for the way that the wave dash and the tilde are mapped to and from Unicode. UDC} // AddCodePage('JA16SJISYEN', 25); {Shift-JIS 16-bit Japanese with '\' mapped to the Japanese yen character UDC} // AddCodePage('JA16VMS', 26); {JVMS 16-bit Japanese} // AddCodePage('RU8BESTA', 27); {BESTA 8-bit Latin/Cyrillic} // AddCodePage('SF7ASCII', 28); {ASCII 7-bit Finnish} // AddCodePage('KO16DBCS', 29); {IBM EBCDIC 16-bit Korean UDC} // AddCodePage('KO16KSCCS', 30); {KSCCS 16-bit Korean} AddCodePage('KO16KSC5601', 840); {KSC5601 16-bit Korean} AddCodePage('KO16MSWIN949', 846); {MS Windows Code Page 949 Korean UDC} // AddCodePage('TH8MACTHAI', 33); {Mac Client 8-bit Latin/Thai} // AddCodePage('TH8MACTHAIS', 34); {Mac Server 8-bit Latin/Thai} AddCodePage('TH8TISASCII', 41); {Thai Industrial Standard 620-2533 - ASCII 8-bit} // AddCodePage('TH8TISEBCDIC', 36); {Thai Industrial Standard 620-2533 - EBCDIC 8-bit} // AddCodePage('TH8TISEBCDICS', 37); {Thai Industrial Standard 620-2533-EBCDIC Server 8-bit} AddCodePage('US7ASCII', 1); {U.S. 7-bit ASCII American} AddCodePage('VN8MSWIN1258', 45); {MS Windows Code Page 1258 8-bit Vietnamese} // AddCodePage('VN8VN3', 38); {VN3 8-bit Vietnamese} // AddCodePage('WE8GCOS7', 41); {Bull EBCDIC GCOS7 8-bit West European} // AddCodePage('YUG7ASCII', 42); {ASCII 7-bit Yugoslavian} AddCodePage('ZHS16CGB231280', 850); {CGB2312-80 16-bit Simplified Chinese} // AddCodePage('ZHS16DBCS', 44); {IBM EBCDIC 16-bit Simplified Chinese UDC} AddCodePage('ZHS16GBK', 852); {GBK 16-bit Simplified Chinese UDC} // AddCodePage('ZHS16MACCGB231280', 46); {Mac client CGB2312-80 16-bit Simplified Chinese} AddCodePage('ZHS32GB18030', 854); {GB18030-2000} AddCodePage('ZHT16BIG5', 856); {BIG5 16-bit Traditional Chinese} // AddCodePage('ZHT16CCDC', 49); {HP CCDC 16-bit Traditional Chinese} // AddCodePage('ZHT16DBCS', 50); {IBM EBCDIC 16-bit Traditional Chinese UDC} // AddCodePage('ZHT16DBT', 51); {Taiwan Taxation 16-bit Traditional Chinese} AddCodePage('ZHT16HKSCS', 868); {MS Windows Code Page 950 with Hong Kong Supplementary Character Set} AddCodePage('ZHT16MSWIN950', 867); {MS Windows Code Page 950 Traditional Chinese UDC} AddCodePage('ZHT32EUC', 860); {EUC 32-bit Traditional Chinese} // AddCodePage('ZHT32SOPS', 55); {SOPS 32-bit Traditional Chinese} // AddCodePage('ZHT32TRIS', 56); {TRIS 32-bit Traditional Chinese} // AddCodePage('WE8DEC', 57); {DEC 8-bit West European} // AddCodePage('D7DEC', 58); {DEC VT100 7-bit German} // AddCodePage('F7DEC', 59); {DEC VT100 7-bit French} // AddCodePage('S7DEC', 60); {DEC VT100 7-bit Swedish} // AddCodePage('E7DEC', 61); {DEC VT100 7-bit Spanish} // AddCodePage('NDK7DEC', 62); {DEC VT100 7-bit Norwegian/Danish} // AddCodePage('I7DEC', 63); {DEC VT100 7-bit Italian} // AddCodePage('NL7DEC', 64); {DEC VT100 7-bit Dutch} // AddCodePage('CH7DEC', 65); {DEC VT100 7-bit Swiss (German/French)} // AddCodePage('SF7DEC', 66); {DEC VT100 7-bit Finnish} // AddCodePage('WE8DG', 67); {DG 8-bit West European} // AddCodePage('WE8EBCDIC37', 68, ceAnsi, zCP_EBC037); {EBCDIC Code Page 37 8-bit West European} // AddCodePage('D8EBCDIC273', 69, ceAnsi, zCP_EBC273); {EBCDIC Code Page 273/1 8-bit Austrian German} // AddCodePage('DK8EBCDIC277', 70, ceAnsi, zCP_EBC277); {EBCDIC Code Page 277/1 8-bit Danish} // AddCodePage('S8EBCDIC278', 71, ceAnsi, zCP_EBC278); {EBCDIC Code Page 278/1 8-bit Swedish} // AddCodePage('I8EBCDIC280', 72, ceAnsi, zCP_EBC280); {EBCDIC Code Page 280/1 8-bit Italian} // AddCodePage('WE8EBCDIC284', 73, ceAnsi, zCP_EBC284); {EBCDIC Code Page 284 8-bit Latin American/Spanish} // AddCodePage('WE8EBCDIC285', 74); {EBCDIC Code Page 285 8-bit West European} // AddCodePage('WE8EBCDIC924', 75); {Latin 9 EBCDIC 924} // AddCodePage('WE8EBCDIC1047', 76); {EBCDIC Code Page 1047 8-bit West European} // AddCodePage('WE8EBCDIC1047E', 77); {Latin 1/Open Systems 1047} // AddCodePage('WE8EBCDIC1140', 78); {EBCDIC Code Page 1140 8-bit West European} // AddCodePage('WE8EBCDIC1140C', 79); {EBCDIC Code Page 1140 Client 8-bit West European} // AddCodePage('WE8EBCDIC1145', 80); {EBCDIC Code Page 1145 8-bit West European} // AddCodePage('WE8EBCDIC1146', 81); {EBCDIC Code Page 1146 8-bit West European} // AddCodePage('WE8EBCDIC1148', 82); {EBCDIC Code Page 1148 8-bit West European} // AddCodePage('WE8EBCDIC1148C', 83); {EBCDIC Code Page 1148 Client 8-bit West European} // AddCodePage('F8EBCDIC297', 84); {EBCDIC Code Page 297 8-bit French} // AddCodePage('WE8EBCDIC500', 85); {EBCDIC Code Page 500 8-bit West European} // AddCodePage('EE8EBCDIC870', 85); {EBCDIC Code Page 870 8-bit East European} // AddCodePage('EE8EBCDIC870C', 87); {EBCDIC Code Page 870 Client 8-bit East European} // AddCodePage('EE8EBCDIC870S', 88); {EBCDIC Code Page 870 Server 8-bit East European} // AddCodePage('WE8EBCDIC871', 89); {EBCDIC Code Page 871 8-bit Icelandic} AddCodePage('EL8EBCDIC875', 90); {EBCDIC Code Page 875 8-bit Greek} AddCodePage('EL8EBCDIC875R', 91); {EBCDIC Code Page 875 Server 8-bit Greek} AddCodePage('CL8EBCDIC1025', 92); {EBCDIC Code Page 1025 8-bit Cyrillic} AddCodePage('CL8EBCDIC1025C', 93); {EBCDIC Code Page 1025 Client 8-bit Cyrillic} AddCodePage('CL8EBCDIC1025R', 94); {EBCDIC Code Page 1025 Server 8-bit Cyrillic} AddCodePage('CL8EBCDIC1025S', 95); {EBCDIC Code Page 1025 Server 8-bit Cyrillic} AddCodePage('CL8EBCDIC1025X', 96); {EBCDIC Code Page 1025 (Modified) 8-bit Cyrillic} AddCodePage('BLT8EBCDIC1112', 97); {EBCDIC Code Page 1112 8-bit Baltic Multilingual} AddCodePage('BLT8EBCDIC1112S', 98); {EBCDIC Code Page 1112 8-bit Server Baltic Multilingual} AddCodePage('D8EBCDIC1141', 99); {EBCDIC Code Page 1141 8-bit Austrian German} AddCodePage('DK8EBCDIC1142', 100); {EBCDIC Code Page 1142 8-bit Danish} AddCodePage('S8EBCDIC1143', 101); {EBCDIC Code Page 1143 8-bit Swedish} AddCodePage('I8EBCDIC1144', 102); {EBCDIC Code Page 1144 8-bit Italian} AddCodePage('F8EBCDIC1147', 103); {EBCDIC Code Page 1147 8-bit French} AddCodePage('EEC8EUROASCI', 104); {EEC Targon 35 ASCI West European/Greek} AddCodePage('EEC8EUROPA3', 105); {EEC EUROPA3 8-bit West European/Greek} AddCodePage('LA8PASSPORT', 106); {German Government Printer 8-bit All-European Latin} AddCodePage('WE8HP', 107); {HP LaserJet 8-bit West European} AddCodePage('WE8ROMAN8', 108); {HP Roman8 8-bit West European} AddCodePage('HU8CWI2', 109); {Hungarian 8-bit CWI-2} AddCodePage('HU8ABMOD', 110); {Hungarian 8-bit Special AB Mod} AddCodePage('LV8RST104090', 111); {IBM-PC Alternative Code Page 8-bit Latvian (Latin/Cyrillic)} AddCodePage('US8PC437', 112); {IBM-PC Code Page 437 8-bit American} AddCodePage('BG8PC437S', 113); {IBM-PC Code Page 437 8-bit (Bulgarian Modification)} AddCodePage('EL8PC437S', 114); {IBM-PC Code Page 437 8-bit (Greek modification)} AddCodePage('EL8PC737', 115); {IBM-PC Code Page 737 8-bit Greek/Latin} AddCodePage('LT8PC772', 116); {IBM-PC Code Page 772 8-bit Lithuanian (Latin/Cyrillic)} AddCodePage('LT8PC774', 117); {IBM-PC Code Page 774 8-bit Lithuanian (Latin)} AddCodePage('BLT8PC775', 118); {IBM-PC Code Page 775 8-bit Baltic} AddCodePage('WE8PC850', 119); {IBM-PC Code Page 850 8-bit West European} AddCodePage('EL8PC851', 120); {IBM-PC Code Page 851 8-bit Greek/Latin} AddCodePage('EE8PC852', 121); {IBM-PC Code Page 852 8-bit East European} AddCodePage('RU8PC855', 122); {IBM-PC Code Page 855 8-bit Latin/Cyrillic} AddCodePage('WE8PC858', 123); {IBM-PC Code Page 858 8-bit West European} AddCodePage('WE8PC860', 124); {IBM-PC Code Page 860 8-bit West European} AddCodePage('IS8PC861', 125); {IBM-PC Code Page 861 8-bit Icelandic} AddCodePage('CDN8PC863', 126); {IBM-PC Code Page 863 8-bit Canadian French} AddCodePage('N8PC865', 127); {IBM-PC Code Page 865 8-bit Norwegian} AddCodePage('RU8PC866', 128); {IBM-PC Code Page 866 8-bit Latin/Cyrillic} AddCodePage('EL8PC869', 129); {IBM-PC Code Page 869 8-bit Greek/Latin} AddCodePage('LV8PC1117', 130); {IBM-PC Code Page 1117 8-bit Latvian} AddCodePage('US8ICL', 131); {ICL EBCDIC 8-bit American} AddCodePage('WE8ICL', 132); {ICL EBCDIC 8-bit West European} AddCodePage('WE8ISOICLUK', 133); {ICL special version ISO8859-1} AddCodePage('WE8ISO8859P1', 134); {ISO 8859-1 West European} AddCodePage('EE8ISO8859P2', 135); {ISO 8859-2 East European} AddCodePage('SE8ISO8859P3', 136); {ISO 8859-3 South European} AddCodePage('NEE8ISO8859P4', 137); {ISO 8859-4 North and North-East European} AddCodePage('CL8ISO8859P5', 138); {ISO 8859-5 Latin/Cyrillic} AddCodePage('EL8ISO8859P7', 139); {ISO 8859-7 Latin/Greek} AddCodePage('NE8ISO8859P10', 140); {ISO 8859-10 North European} AddCodePage('BLT8ISO8859P13', 141); {ISO 8859-13 Baltic} AddCodePage('CEL8ISO8859P14', 142); {ISO 8859-13 Celtic} AddCodePage('WE8ISO8859P15', 143); {ISO 8859-15 West European} AddCodePage('AR8ARABICMAC', 144); {Mac Client 8-bit Latin/Arabic} AddCodePage('EE8MACCE', 145); {Mac Client 8-bit Central European} AddCodePage('EE8MACCROATIAN', 146); {Mac Client 8-bit Croatian} AddCodePage('WE8MACROMAN8', 147); {Mac Client 8-bit Extended Roman8 West European} AddCodePage('EL8MACGREEK', 148); {Mac Client 8-bit Greek} AddCodePage('IS8MACICELANDIC', 149); {Mac Client 8-bit Icelandic} AddCodePage('CL8MACCYRILLIC', 150); {Mac Client 8-bit Latin/Cyrillic} AddCodePage('EE8MACCES', 151); {Mac Server 8-bit Central European} AddCodePage('EE8MACCROATIANS', 152); {Mac Server 8-bit Croatian} AddCodePage('WE8MACROMAN8S', 153); {Mac Server 8-bit Extended Roman8 West European} AddCodePage('CL8MACCYRILLICS', 154); {Mac Server 8-bit Latin/Cyrillic} AddCodePage('EL8MACGREEKS', 155); {Mac Server 8-bit Greek} AddCodePage('IS8MACICELANDICS', 156); {Mac Server 8-bit Icelandic} AddCodePage('BG8MSWIN', 157); {MS Windows 8-bit Bulgarian Cyrillic} AddCodePage('LT8MSWIN921', 158); {MS Windows Code Page 921 8-bit Lithuanian} AddCodePage('ET8MSWIN923', 159); {MS Windows Code Page 923 8-bit Estonian} AddCodePage('EE8MSWIN1250', 160, ceAnsi, zCP_WIN1250); {MS Windows Code Page 1250 8-bit East European} AddCodePage('CL8MSWIN1251', 161, ceAnsi, zCP_WIN1251); {MS Windows Code Page 1251 8-bit Latin/Cyrillic} AddCodePage('WE8MSWIN1252', 162, ceAnsi, zCP_WIN1252); {MS Windows Code Page 1252 8-bit West European} AddCodePage('EL8MSWIN1253', 163, ceAnsi, zCP_WIN1253); {MS Windows Code Page 1253 8-bit Latin/Greek} AddCodePage('BLT8MSWIN1257', 164, ceAnsi, zCP_WIN1257); {MS Windows Code Page 1257 8-bit Baltic} AddCodePage('BLT8CP921', 165); {Latvian Standard LVS8-92(1) Windows/Unix 8-bit Baltic} AddCodePage('LV8PC8LR', 166, ceAnsi, zCP_DOS866); {Latvian Version IBM-PC Code Page 866 8-bit Latin/Cyrillic} AddCodePage('WE8NCR4970', 167); {NCR 4970 8-bit West European} AddCodePage('WE8NEXTSTEP', 168); {NeXTSTEP PostScript 8-bit West European} AddCodePage('CL8ISOIR111', 169); {ISOIR111 Cyrillic} AddCodePage('CL8KOI8R', 170, ceAnsi, zCP_KOI8R); {RELCOM Internet Standard 8-bit Latin/Cyrillic} AddCodePage('CL8KOI8U', 171); {KOI8 Ukrainian Cyrillic} AddCodePage('US8BS2000', 172); {Siemens 9750-62 EBCDIC 8-bit American} AddCodePage('DK8BS2000', 173); {Siemens 9750-62 EBCDIC 8-bit Danish} AddCodePage('F8BS2000', 174); {Siemens 9750-62 EBCDIC 8-bit French} AddCodePage('D8BS2000', 175); {Siemens 9750-62 EBCDIC 8-bit German} AddCodePage('E8BS2000', 176); {Siemens 9750-62 EBCDIC 8-bit Spanish} AddCodePage('S8BS2000', 177); {Siemens 9750-62 EBCDIC 8-bit Swedish} AddCodePage('DK7SIEMENS9780X', 178); {Siemens 97801/97808 7-bit Danish} AddCodePage('F7SIEMENS9780X', 179); {Siemens 97801/97808 7-bit French} AddCodePage('D7SIEMENS9780X', 180); {Siemens 97801/97808 7-bit German} AddCodePage('I7SIEMENS9780X', 181); {Siemens 97801/97808 7-bit Italian} AddCodePage('N7SIEMENS9780X', 182); {Siemens 97801/97808 7-bit Norwegian} AddCodePage('E7SIEMENS9780X', 183); {Siemens 97801/97808 7-bit Spanish} AddCodePage('S7SIEMENS9780X', 184); {Siemens 97801/97808 7-bit Swedish} AddCodePage('EE8BS2000', 185); {Siemens EBCDIC.DF.04 8-bit East European} AddCodePage('WE8BS2000', 186); {Siemens EBCDIC.DF.04 8-bit West European} AddCodePage('WE8BS2000E', 187); {Siemens EBCDIC.DF.04 8-bit West European} AddCodePage('CL8BS2000', 188); {Siemens EBCDIC.EHC.LC 8-bit Cyrillic} AddCodePage('WE8EBCDIC37C', 189); {EBCDIC Code Page 37 8-bit Oracle/c} AddCodePage('IW8EBCDIC424', 190); {EBCDIC Code Page 424 8-bit Latin/Hebrew} AddCodePage('IW8EBCDIC424S', 191); {EBCDIC Code Page 424 Server 8-bit Latin/Hebrew} AddCodePage('WE8EBCDIC500C', 192); {EBCDIC Code Page 500 8-bit Oracle/c} AddCodePage('IW8EBCDIC1086', 193); {EBCDIC Code Page 1086 8-bit Hebrew} AddCodePage('AR8EBCDIC420S', 194); {EBCDIC Code Page 420 Server 8-bit Latin/Arabic} AddCodePage('AR8EBCDICX', 195); {EBCDIC XBASIC Server 8-bit Latin/Arabic} AddCodePage('TR8EBCDIC1026', 196, ceAnsi, zCP_IBM1026); {EBCDIC Code Page 1026 8-bit Turkish} AddCodePage('TR8EBCDIC1026S', 197); {EBCDIC Code Page 1026 Server 8-bit Turkish} AddCodePage('AR8HPARABIC8T', 198); {HP 8-bit Latin/Arabic} AddCodePage('TR8PC857', 199); {IBM-PC Code Page 857 8-bit Turkish} AddCodePage('IW8PC1507', 200); {IBM-PC Code Page 1507/862 8-bit Latin/Hebrew} AddCodePage('AR8ISO8859P6', 201); {ISO 8859-6 Latin/Arabic} AddCodePage('IW8ISO8859P8', 201); {ISO 8859-8 Latin/Hebrew} AddCodePage('WE8ISO8859P9', 203); {ISO 8859-9 West European & Turkish} AddCodePage('LA8ISO6937', 204); {ISO 6937 8-bit Coded Character Set for Text Communication} AddCodePage('IW7IS960', 205); {Israeli Standard 960 7-bit Latin/Hebrew} AddCodePage('IW8MACHEBREW', 206); {Mac Client 8-bit Hebrew} AddCodePage('AR8ARABICMACT', 207); {Mac 8-bit Latin/Arabic} AddCodePage('TR8MACTURKISH', 208); {Mac Client 8-bit Turkish} AddCodePage('IW8MACHEBREWS', 209); {Mac Server 8-bit Hebrew} AddCodePage('TR8MACTURKISHS', 210); {Mac Server 8-bit Turkish} AddCodePage('TR8MSWIN1254', 211); {MS Windows Code Page 1254 8-bit Turkish} AddCodePage('IW8MSWIN1255', 212); {MS Windows Code Page 1255 8-bit Latin/Hebrew} AddCodePage('AR8MSWIN1256', 213); {MS Windows Code Page 1256 8-Bit Latin/Arabic} AddCodePage('IN8ISCII', 214); {Multiple-Script Indian Standard 8-bit Latin/Indian Languages} AddCodePage('AR8MUSSAD768', 215); {Mussa'd Alarabi/2 768 Server 8-bit Latin/Arabic} AddCodePage('AR8MUSSAD768T', 216); {Mussa'd Alarabi/2 768 8-bit Latin/Arabic} AddCodePage('AR8NAFITHA711', 217); {Nafitha Enhanced 711 Server 8-bit Latin/Arabic} AddCodePage('AR8NAFITHA711T', 218); {Nafitha Enhanced 711 8-bit Latin/Arabic} AddCodePage('AR8NAFITHA721', 219); {Nafitha International 721 Server 8-bit Latin/Arabic} AddCodePage('AR8NAFITHA721T', 220); {Nafitha International 721 8-bit Latin/Arabic} AddCodePage('AR8SAKHR706', 221); {SAKHR 706 Server 8-bit Latin/Arabic} AddCodePage('AR8SAKHR707', 222); {SAKHR 707 Server 8-bit Latin/Arabic} AddCodePage('AR8SAKHR707T', 223); {SAKHR 707 8-bit Latin/Arabic} AddCodePage('AR8XBASIC', 224); {XBASIC 8-bit Latin/Arabic} AddCodePage('WE8BS2000L5', 225); {Siemens EBCDIC.DF.04.L5 8-bit West European/Turkish}) AddCodePage('UTF8', 871, ceUTF8, zCP_UTF8); {Unicode 3.0 UTF-8 Universal character set, CESU-8 compliant} AddCodePage('UTFE', 227, ceUTF8, zCP_UTF8); {EBCDIC form of Unicode 3.0 UTF-8 Universal character set} *) //All supporteds from XE AddCodePage('US7ASCII', 1, ceAnsi, zCP_us_ascii); AddCodePage('US8PC437', 4, ceAnsi, zCP_DOS437); AddCodePage('WE8PC850', 10, ceAnsi, zCP_DOS850); AddCodePage('WE8PC858', 28, ceAnsi, zCP_DOS858); AddCodePage('WE8ISO8859P1', 31, ceAnsi, zCP_L1_ISO_8859_1); AddCodePage('EE8ISO8859P2', 32, ceAnsi, zCP_L2_ISO_8859_2); AddCodePage('SE8ISO8859P3', 33, ceAnsi, zCP_L3_ISO_8859_3); AddCodePage('NEE8ISO8859P4', 34, ceAnsi, zCP_L4_ISO_8859_4); AddCodePage('CL8ISO8859P5', 35, ceAnsi, zCP_L5_ISO_8859_5); AddCodePage('AR8ISO8859P6', 36, ceAnsi, zCP_L6_ISO_8859_6); AddCodePage('EL8ISO8859P7', 37, ceAnsi, zCP_L7_ISO_8859_7); AddCodePage('IW8ISO8859P8', 38, ceAnsi, zCP_L8_ISO_8859_8); AddCodePage('WE8ISO8859P9', 39, ceAnsi, zCP_L5_ISO_8859_9); AddCodePage('NE8ISO8859P10', 40, ceAnsi, zCP_L6_ISO_8859_10); AddCodePage('TH8TISASCII', 41, ceAnsi); AddCodePage('VN8MSWIN1258', 45, ceAnsi, zCP_WIN1258); AddCodePage('WE8ISO8859P15', 46, ceAnsi, zCP_L9_ISO_8859_15); AddCodePage('BLT8ISO8859P13', 47, ceAnsi, zCP_L7_ISO_8859_13); AddCodePage('CEL8ISO8859P14', 48, ceAnsi, zCP_L8_ISO_8859_14); AddCodePage('CL8KOI8U', 51, ceAnsi, zCP_KOI8U); AddCodePage('AZ8ISO8859P9E', 52, ceAnsi); AddCodePage('EE8PC852', 150, ceAnsi, zCP_DOS852); AddCodePage('RU8PC866', 152, ceAnsi, zCP_DOS856); AddCodePage('TR8PC857', 156, ceAnsi, zCP_DOS857); AddCodePage('EE8MSWIN1250', 170, ceAnsi, zCP_WIN1250); AddCodePage('CL8MSWIN1251', 171, ceAnsi, zCP_WIN1251); AddCodePage('ET8MSWIN923', 172, ceAnsi, zCP_MSWIN923); AddCodePage('EL8MSWIN1253', 174, ceAnsi, zCP_WIN1253); AddCodePage('IW8MSWIN1255', 175, ceAnsi, zCP_WIN1255); AddCodePage('LT8MSWIN921', 176, ceAnsi, zCP_MSWIN921); AddCodePage('TR8MSWIN1254', 177, ceAnsi, zCP_WIN1254); AddCodePage('WE8MSWIN1252', 178, ceAnsi, zCP_WIN1252); AddCodePage('BLT8MSWIN1257', 179, ceAnsi, zCP_WIN1257); AddCodePage('BLT8CP921', 191, ceAnsi, 921); AddCodePage('CL8KOI8R', 196, ceAnsi, zCP_KOI8R); AddCodePage('BLT8PC775', 197, ceAnsi, zCP_DOS775); AddCodePage('EL8PC737', 382, ceAnsi, zCP_DOS737); AddCodePage('AR8ASMO8X', 500, ceAnsi); AddCodePage('AR8ADOS720', 558, ceAnsi, zCP_DOS720); AddCodePage('AR8MSWIN1256', 560, ceAnsi, cCP_WIN1256); AddCodePage('JA16EUC', 830, ceAnsi, zCP_euc_JP_win); AddCodePage('JA16SJIS', 832, ceAnsi, zCP_csISO2022JP); AddCodePage('JA16EUCTILDE', 837, ceAnsi); AddCodePage('JA16SJISTILDE', 838, ceAnsi); AddCodePage('KO16KSC5601', 840, ceAnsi, 601); AddCodePage('KO16MSWIN949', 846, ceAnsi, zCP_EUCKR); AddCodePage('ZHS16CGB231280', 850, ceAnsi, zCP_GB2312); AddCodePage('ZHS16GBK', 852, ceAnsi); AddCodePage('ZHS32GB18030', 854, ceAnsi, zCP_GB18030); AddCodePage('ZHT32EUC', 860, ceAnsi, zCP_EUCKR); AddCodePage('ZHT16BIG5', 865, ceAnsi, zCP_Big5); AddCodePage('ZHT16MSWIN950', 867, ceAnsi, zCP_Big5); AddCodePage('ZHT16HKSCS', 868, ceAnsi); AddCodePage('UTF8', 871, ceUTF8, zCP_UTF8); AddCodePage('AL32UTF8', 873, ceUTF8, zCP_UTF8); AddCodePage('UTF16', 1000, ceUTF16, zCP_UTF16); AddCodePage('AL16UTF16', 2000, ceUTF16, zCP_UTF16); AddCodePage('AL16UTF16LE', 2002, ceUTF16, zCP_UTF16); end; procedure TZOracle9iPlainDriver.LoadApi; begin { ************** Load adresses of API Functions ************* } with Loader do begin @OracleAPI.OCIEnvCreate := GetAddress('OCIEnvCreate'); @OracleAPI.OCIEnvNlsCreate := GetAddress('OCIEnvNlsCreate'); @OracleAPI.OCIInitialize := GetAddress('OCIInitialize'); @OracleAPI.OCIEnvInit := GetAddress('OCIEnvInit'); @OracleAPI.OCIHandleAlloc := GetAddress('OCIHandleAlloc'); @OracleAPI.OCIHandleFree := GetAddress('OCIHandleFree'); @OracleAPI.OCIAttrSet := GetAddress('OCIAttrSet'); @OracleAPI.OCIAttrGet := GetAddress('OCIAttrGet'); @OracleAPI.OCIDescriptorAlloc := GetAddress('OCIDescriptorAlloc'); @OracleAPI.OCIDescriptorFree := GetAddress('OCIDescriptorFree'); @OracleAPI.OCIErrorGet := GetAddress('OCIErrorGet'); @OracleAPI.OCIServerAttach := GetAddress('OCIServerAttach'); @OracleAPI.OCIServerDetach := GetAddress('OCIServerDetach'); @OracleAPI.OCIServerVersion := GetAddress('OCIServerVersion'); @OracleAPI.OCIServerRelease := GetAddress('OCIServerRelease'); @OracleAPI.OCIBreak := GetAddress('OCIBreak'); { For Oracle >= 8.1 } @OracleAPI.OCIReset := GetAddress('OCIReset'); @OracleAPI.OCISessionBegin := GetAddress('OCISessionBegin'); @OracleAPI.OCISessionEnd := GetAddress('OCISessionEnd'); @OracleAPI.OCIPasswordChange := GetAddress('OCIPasswordChange'); @OracleAPI.OCITransStart := GetAddress('OCITransStart'); @OracleAPI.OCITransCommit := GetAddress('OCITransCommit'); @OracleAPI.OCITransRollback := GetAddress('OCITransRollback'); @OracleAPI.OCITransDetach := GetAddress('OCITransDetach'); @OracleAPI.OCITransPrepare := GetAddress('OCITransPrepare'); @OracleAPI.OCITransForget := GetAddress('OCITransForget'); @OracleAPI.OCIStmtPrepare := GetAddress('OCIStmtPrepare'); @OracleAPI.OCIStmtExecute := GetAddress('OCIStmtExecute'); @OracleAPI.OCIStmtFetch := GetAddress('OCIStmtFetch'); @OracleAPI.OCIStmtGetPieceInfo := GetAddress('OCIStmtGetPieceInfo'); @OracleAPI.OCIStmtSetPieceInfo := GetAddress('OCIStmtSetPieceInfo'); @OracleAPI.OCIParamGet := GetAddress('OCIParamGet'); @OracleAPI.OCIResultSetToStmt := GetAddress('OCIResultSetToStmt'); @OracleAPI.OCIDefineByPos := GetAddress('OCIDefineByPos'); @OracleAPI.OCIDefineArrayOfStruct := GetAddress('OCIDefineArrayOfStruct'); @OracleAPI.OCIBindByPos := GetAddress('OCIBindByPos'); @OracleAPI.OCIBindByName := GetAddress('OCIBindByName'); @OracleAPI.OCIBindDynamic := GetAddress('OCIBindDynamic'); @OracleAPI.OCIBindObject := GetAddress('OCIBindObject'); @OracleAPI.OCIDefineObject := GetAddress('OCIDefineObject'); { > ori.h } @OracleAPI.OCIObjectNew := GetAddress('OCIObjectNew'); @OracleAPI.OCIObjectPin := GetAddress('OCIObjectPin'); @OracleAPI.OCIObjectUnpin := GetAddress('OCIObjectUnpin'); @OracleAPI.OCIObjectPinCountReset := GetAddress('OCIObjectPinCountReset'); @OracleAPI.OCIObjectLock := GetAddress('OCIObjectLock'); @OracleAPI.OCIObjectLockNoWait := GetAddress('OCIObjectLockNoWait'); @OracleAPI.OCIObjectMarkUpdate := GetAddress('OCIObjectMarkUpdate'); @OracleAPI.OCIObjectUnmark := GetAddress('OCIObjectUnmark'); @OracleAPI.OCIObjectUnmarkByRef := GetAddress('OCIObjectUnmarkByRef'); @OracleAPI.OCIObjectFree := GetAddress('OCIObjectFree'); @OracleAPI.OCIObjectMarkDeleteByRef := GetAddress('OCIObjectMarkDeleteByRef'); @OracleAPI.OCIObjectMarkDelete := GetAddress('OCIObjectMarkDelete'); @OracleAPI.OCIObjectFlush := GetAddress('OCIObjectFlush'); @OracleAPI.OCIObjectRefresh := GetAddress('OCIObjectRefresh'); @OracleAPI.OCIObjectCopy := GetAddress('OCIObjectCopy'); @OracleAPI.OCIObjectGetTypeRef := GetAddress('OCIObjectGetTypeRef'); @OracleAPI.OCIObjectGetObjectRef := GetAddress('OCIObjectGetObjectRef'); @OracleAPI.OCIObjectMakeObjectRef := GetAddress('OCIObjectMakeObjectRef'); @OracleAPI.OCIObjectGetPrimaryKeyTypeRef := GetAddress('OCIObjectGetPrimaryKeyTypeRef'); @OracleAPI.OCIObjectGetInd := GetAddress('OCIObjectGetInd'); @OracleAPI.OCIObjectExists := GetAddress('OCIObjectExists'); @OracleAPI.OCIObjectGetProperty := GetAddress('OCIObjectGetProperty'); @OracleAPI.OCIObjectIsLocked := GetAddress('OCIObjectIsLocked'); @OracleAPI.OCIObjectIsDirty := GetAddress('OCIObjectIsDirty'); @OracleAPI.OCIObjectPinTable := GetAddress('OCIObjectPinTable'); @OracleAPI.OCIObjectArrayPin := GetAddress('OCIObjectArrayPin'); @OracleAPI.OCICacheFlush := GetAddress('OCICacheFlush'); @OracleAPI.OCICacheRefresh := GetAddress('OCICacheRefresh'); @OracleAPI.OCICacheUnpin := GetAddress('OCICacheUnpin'); @OracleAPI.OCICacheFree := GetAddress('OCICacheFree'); @OracleAPI.OCICacheUnmark := GetAddress('OCICacheUnmark'); @OracleAPI.OCIDurationBegin := GetAddress('OCIDurationBegin'); @OracleAPI.OCIDurationEnd := GetAddress('OCIDurationEnd'); { < ori.h } @OracleAPI.OCILobAppend := GetAddress('OCILobAppend'); @OracleAPI.OCILobAssign := GetAddress('OCILobAssign'); @OracleAPI.OCILobCopy := GetAddress('OCILobCopy'); @OracleAPI.OCILobEnableBuffering := GetAddress('OCILobEnableBuffering'); @OracleAPI.OCILobDisableBuffering := GetAddress('OCILobDisableBuffering'); @OracleAPI.OCILobErase := GetAddress('OCILobErase'); @OracleAPI.OCILobFileExists := GetAddress('OCILobFileExists'); @OracleAPI.OCILobFileGetName := GetAddress('OCILobFileGetName'); @OracleAPI.OCILobFileSetName := GetAddress('OCILobFileSetName'); @OracleAPI.OCILobFlushBuffer := GetAddress('OCILobFlushBuffer'); @OracleAPI.OCILobGetLength := GetAddress('OCILobGetLength'); @OracleAPI.OCILobLoadFromFile := GetAddress('OCILobLoadFromFile'); @OracleAPI.OCILobLocatorIsInit := GetAddress('OCILobLocatorIsInit'); @OracleAPI.OCILobRead := GetAddress('OCILobRead'); @OracleAPI.OCILobTrim := GetAddress('OCILobTrim'); @OracleAPI.OCILobWrite := GetAddress('OCILobWrite'); { For Oracle >= 8.1 } @OracleAPI.OCILobCreateTemporary := GetAddress('OCILobCreateTemporary'); @OracleAPI.OCILobFreeTemporary := GetAddress('OCILobFreeTemporary'); @OracleAPI.OCILobCharSetForm := GetAddress('OCILobCharSetForm'); @OracleAPI.OCILobCharSetId := GetAddress('OCILobCharSetId'); @OracleAPI.OCILobClose := GetAddress('OCILobClose'); @OracleAPI.OCILobIsOpen := GetAddress('OCILobIsOpen'); @OracleAPI.OCILobIsTemporary := GetAddress('OCILobIsTemporary'); @OracleAPI.OCILobOpen := GetAddress('OCILobOpen'); @OracleAPI.OCIDateTimeAssign := GetAddress('OCIDateTimeAssign'); @OracleAPI.OCIDateTimeCheck := GetAddress('OCIDateTimeCheck'); @OracleAPI.OCIDateTimeCompare := GetAddress('OCIDateTimeCompare'); @OracleAPI.OCIDateTimeConvert := GetAddress('OCIDateTimeConvert'); @OracleAPI.OCIDateTimeFromText := GetAddress('OCIDateTimeFromText'); @OracleAPI.OCIDateTimeGetDate := GetAddress('OCIDateTimeGetDate'); @OracleAPI.OCIDateTimeGetTime := GetAddress('OCIDateTimeGetTime'); @OracleAPI.OCIDateTimeGetTimeZoneOffset := GetAddress('OCIDateTimeGetTimeZoneOffset'); @OracleAPI.OCIDateTimeSysTimeStamp := GetAddress('OCIDateTimeSysTimeStamp'); @OracleAPI.OCIDateTimeConstruct := GetAddress('OCIDateTimeConstruct'); @OracleAPI.OCIDateTimeToText := GetAddress('OCIDateTimeToText'); @OracleAPI.OCIDateTimeGetTimeZoneName := GetAddress('OCIDateTimeGetTimeZoneName'); @OracleAPI.OCINlsNumericInfoGet := GetAddress('OCINlsNumericInfoGet'); @OracleAPI.OCIClientVersion := GetAddress('OCIClientVersion'); { For Oracle < 8.1 } //@OracleAPI.OCILobClose := GetAddress('OCILobFileClose'); //@OracleAPI.OCILobIsOpen := GetAddress('OCILobFileIsOpen'); //@OracleAPI.OCILobOpen := GetAddress('OCILobFileOpen'); @OracleAPI.OCIDescribeAny := GetAddress('OCIDescribeAny'); { OCI Number mapping } @OracleAPI.OCINumberInc := GetAddress('OCINumberInc'); @OracleAPI.OCINumberDec := GetAddress('OCINumberDec'); @OracleAPI.OCINumberSetZero := GetAddress('OCINumberSetZero'); @OracleAPI.OCINumberSetPi := GetAddress('OCINumberSetPi'); @OracleAPI.OCINumberAdd := GetAddress('OCINumberAdd'); @OracleAPI.OCINumberSub := GetAddress('OCINumberSub'); @OracleAPI.OCINumberMul := GetAddress('OCINumberMul'); @OracleAPI.OCINumberDiv := GetAddress('OCINumberDiv'); @OracleAPI.OCINumberMod := GetAddress('OCINumberMod'); @OracleAPI.OCINumberIntPower := GetAddress('OCINumberIntPower'); @OracleAPI.OCINumberShift := GetAddress('OCINumberShift'); @OracleAPI.OCINumberNeg := GetAddress('OCINumberNeg'); @OracleAPI.OCINumberToText := GetAddress('OCINumberToText'); @OracleAPI.OCINumberFromText := GetAddress('OCINumberFromText'); @OracleAPI.OCINumberToInt := GetAddress('OCINumberToInt'); @OracleAPI.OCINumberFromInt := GetAddress('OCINumberFromInt'); @OracleAPI.OCINumberToReal := GetAddress('OCINumberToReal'); @OracleAPI.OCINumberToRealArray := GetAddress('OCINumberToRealArray'); @OracleAPI.OCINumberFromReal := GetAddress('OCINumberFromReal'); @OracleAPI.OCINumberCmp := GetAddress('OCINumberCmp'); @OracleAPI.OCINumberSign := GetAddress('OCINumberSign'); @OracleAPI.OCINumberIsZero := GetAddress('OCINumberIsZero'); @OracleAPI.OCINumberIsInt := GetAddress('OCINumberIsInt'); @OracleAPI.OCINumberAssign := GetAddress('OCINumberAssign'); @OracleAPI.OCINumberAbs := GetAddress('OCINumberAbs'); @OracleAPI.OCINumberCeil := GetAddress('OCINumberCeil'); @OracleAPI.OCINumberFloor := GetAddress('OCINumberFloor'); @OracleAPI.OCINumberSqrt := GetAddress('OCINumberSqrt'); @OracleAPI.OCINumberTrunc := GetAddress('OCINumberTrunc'); @OracleAPI.OCINumberPower := GetAddress('OCINumberPower'); @OracleAPI.OCINumberRound := GetAddress('OCINumberRound'); @OracleAPI.OCINumberPrec := GetAddress('OCINumberPrec'); @OracleAPI.OCINumberSin := GetAddress('OCINumberSin'); @OracleAPI.OCINumberArcSin := GetAddress('OCINumberArcSin'); @OracleAPI.OCINumberHypSin := GetAddress('OCINumberHypSin'); @OracleAPI.OCINumberCos := GetAddress('OCINumberCos'); @OracleAPI.OCINumberArcCos := GetAddress('OCINumberArcCos'); @OracleAPI.OCINumberHypCos := GetAddress('OCINumberHypCos'); @OracleAPI.OCINumberTan := GetAddress('OCINumberTan'); @OracleAPI.OCINumberArcTan := GetAddress('OCINumberArcTan'); @OracleAPI.OCINumberArcTan2 := GetAddress('OCINumberArcTan2'); @OracleAPI.OCINumberHypTan := GetAddress('OCINumberHypTan'); @OracleAPI.OCINumberExp := GetAddress('OCINumberExp'); @OracleAPI.OCINumberLn := GetAddress('OCINumberLn'); @OracleAPI.OCINumberLog := GetAddress('OCINumberLog'); @OracleAPI.OCITableSize := GetAddress('OCITableSize'); @OracleAPI.OCITableExists := GetAddress('OCITableExists'); @OracleAPI.OCITableDelete := GetAddress('OCITableDelete'); @OracleAPI.OCITableFirst := GetAddress('OCITableFirst'); @OracleAPI.OCITableLast := GetAddress('OCITableLast'); @OracleAPI.OCITableNext := GetAddress('OCITableNext'); @OracleAPI.OCITablePrev := GetAddress('OCITablePrev'); @OracleAPI.OCIObjectGetAttr := GetAddress('OCIObjectGetAttr'); @OracleAPI.OCIObjectSetAttr := GetAddress('OCIObjectSetAttr'); {ociap.h} @OracleAPI.OCIPing := GetAddress('OCIPing'); {ort.h} @OracleAPI.OCITypeIterNew := GetAddress('OCITypeIterNew'); @OracleAPI.OCITypeIterFree := GetAddress('OCITypeIterFree'); @OracleAPI.OCITypeByName := GetAddress('OCITypeByName'); @OracleAPI.OCITypeArrayByName := GetAddress('OCITypeArrayByName'); @OracleAPI.OCITypeByRef := GetAddress('OCITypeByRef'); @OracleAPI.OCITypeArrayByRef := GetAddress('OCITypeArrayByRef'); @OracleAPI.OCITypeName := GetAddress('OCITypeName'); @OracleAPI.OCITypeSchema := GetAddress('OCITypeSchema'); @OracleAPI.OCITypeTypeCode := GetAddress('OCITypeTypeCode'); @OracleAPI.OCITypeCollTypeCode:= GetAddress('OCITypeCollTypeCode'); @OracleAPI.OCITypeVersion := GetAddress('OCITypeVersion'); @OracleAPI.OCITypeAttrs := GetAddress('OCITypeAttrs'); @OracleAPI.OCITypeMethods := GetAddress('OCITypeMethods'); @OracleAPI.OCITypeElemName := GetAddress('OCITypeElemName'); @OracleAPI.OCITypeElemTypeCode:= GetAddress('OCITypeElemTypeCode'); @OracleAPI.OCITypeElemType := GetAddress('OCITypeElemType'); @OracleAPI.OCITypeElemFlags := GetAddress('OCITypeElemFlags'); @OracleAPI.OCITypeElemNumPrec := GetAddress('OCITypeElemNumPrec'); @OracleAPI.OCITypeElemNumScale:= GetAddress('OCITypeElemNumScale'); @OracleAPI.OCITypeElemLength := GetAddress('OCITypeElemLength'); @OracleAPI.OCITypeElemCharSetID := GetAddress('OCITypeElemCharSetID'); @OracleAPI.OCITypeElemCharSetForm := GetAddress('OCITypeElemCharSetForm'); @OracleAPI.OCITypeElemParameterizedType := GetAddress('OCITypeElemParameterizedType'); @OracleAPI.OCITypeElemExtTypeCode := GetAddress('OCITypeElemExtTypeCode'); @OracleAPI.OCITypeAttrByName := GetAddress('OCITypeAttrByName'); @OracleAPI.OCITypeAttrNext := GetAddress('OCITypeAttrNext'); @OracleAPI.OCITypeCollElem := GetAddress('OCITypeCollElem'); @OracleAPI.OCITypeCollSize := GetAddress('OCITypeCollSize'); @OracleAPI.OCITypeCollExtTypeCode := GetAddress('OCITypeCollExtTypeCode'); @OracleAPI.OCITypeMethodOverload := GetAddress('OCITypeMethodOverload'); @OracleAPI.OCITypeMethodByName:= GetAddress('OCITypeMethodByName'); @OracleAPI.OCITypeMethodNext := GetAddress('OCITypeMethodNext'); @OracleAPI.OCITypeMethodName := GetAddress('OCITypeMethodName'); @OracleAPI.OCITypeMethodEncap := GetAddress('OCITypeMethodEncap'); @OracleAPI.OCITypeMethodFlags := GetAddress('OCITypeMethodFlags'); @OracleAPI.OCITypeMethodMap := GetAddress('OCITypeMethodMap'); @OracleAPI.OCITypeMethodOrder := GetAddress('OCITypeMethodOrder'); @OracleAPI.OCITypeMethodParams:= GetAddress('OCITypeMethodParams'); @OracleAPI.OCITypeResult := GetAddress('OCITypeResult'); @OracleAPI.OCITypeParamByPos := GetAddress('OCITypeParamByPos'); @OracleAPI.OCITypeParamByName := GetAddress('OCITypeParamByName'); @OracleAPI.OCITypeParamPos := GetAddress('OCITypeParamPos'); @OracleAPI.OCITypeElemParamMode := GetAddress('OCITypeElemParamMode'); @OracleAPI.OCITypeElemDefaultValue := GetAddress('OCITypeElemDefaultValue'); @OracleAPI.OCITypeVTInit := GetAddress('OCITypeVTInit'); @OracleAPI.OCITypeVTInsert := GetAddress('OCITypeVTInsert'); @OracleAPI.OCITypeVTSelect := GetAddress('OCITypeVTSelect'); end; end; function TZOracle9iPlainDriver.Clone: IZPlainDriver; begin Result := TZOracle9iPlainDriver.Create; end; constructor TZOracle9iPlainDriver.Create; begin inherited create; FLoader := TZNativeLibraryLoader.Create([]); {$IFNDEF UNIX} FLoader.AddLocation(WINDOWS_DLL_LOCATION); {$ELSE} FLoader.AddLocation(LINUX_DLL_LOCATION); {$ENDIF} LoadCodePages; end; function TZOracle9iPlainDriver.GetProtocol: string; begin Result := 'oracle-9i'; end; function TZOracle9iPlainDriver.GetDescription: string; begin Result := 'Native Plain Driver for Oracle 9i'; end; procedure TZOracle9iPlainDriver.Initialize(const Location: String); begin inherited Initialize(Location); OracleAPI.OCIInitialize(OCI_THREADED, nil, nil, nil, nil); end; function TZOracle9iPlainDriver.AttrGet(trgthndlp: POCIHandle; trghndltyp: ub4; attributep, sizep: Pointer; attrtype: ub4; errhp: POCIError): sword; begin Result := OracleAPI.OCIAttrGet(trgthndlp, trghndltyp, attributep, sizep, attrtype, errhp); end; function TZOracle9iPlainDriver.AttrSet(trgthndlp: POCIHandle; trghndltyp: ub4; attributep: Pointer; size, attrtype: ub4; errhp: POCIError): sword; begin Result := OracleAPI.OCIAttrSet(trgthndlp, trghndltyp, attributep, size, attrtype, errhp); end; function TZOracle9iPlainDriver.BindByName(stmtp: POCIStmt; var bindpp: POCIBind; errhp: POCIError; placeholder: text; placeh_len: sb4; valuep: Pointer; value_sz: sb4; dty: ub2; indp, alenp, rcodep: Pointer; maxarr_len: ub4; curelep: Pointer; mode: ub4): sword; begin Result := OracleAPI.OCIBindByName(stmtp, bindpp, errhp, placeholder, placeh_len, valuep, value_sz, dty, indp, alenp, rcodep, maxarr_len, curelep, mode); end; function TZOracle9iPlainDriver.BindByPos(stmtp: POCIStmt; var bindpp: POCIBind; errhp: POCIError; position: ub4; valuep: Pointer; value_sz: sb4; dty: ub2; indp, alenp, rcodep: Pointer; maxarr_len: ub4; curelep: Pointer; mode: ub4): sword; begin Result := OracleAPI.OCIBindByPos(stmtp, bindpp, errhp, position, valuep, value_sz, dty, indp, alenp, rcodep, maxarr_len, curelep, mode); end; function TZOracle9iPlainDriver.BindDynamic(bindp: POCIBind; errhp: POCIError; ictxp, icbfp, octxp, ocbfp: Pointer): sword; begin Result := OracleAPI.OCIBindDynamic(bindp, errhp, ictxp, icbfp, octxp, ocbfp); end; function TZOracle9iPlainDriver.BindObject(bindp: POCIBind; errhp: POCIError; const _type: POCIType; pgvpp: PPointer; pvszsp: pub4; indpp: PPointer; indszp: pub4): sword; begin Result := OracleAPI.OCIBindObject(bindp, errhp, _type, pgvpp, pvszsp, indpp, indszp); end; function TZOracle9iPlainDriver.DefineObject(defnpp: POCIDefine; errhp: POCIError; _type: POCIHandle; pgvpp,pvszsp,indpp,indszp:pointer): sword; begin Result := OracleAPI.OCIDefineObject(defnpp, errhp, _type, pgvpp, pvszsp, indpp, indszp); end; { > ori.h} function TZOracle9iPlainDriver.ObjectNew(env: POCIEnv; err: POCIError; const svc: POCISvcCtx; typecode: OCITypeCode; tdo: POCIType; table: Pointer; duration: OCIDuration; value: Longbool; instance: PPointer): sword; begin Result := OracleAPI.OCIObjectNew(env, err, svc, typecode, tdo, table, duration, value, instance); end; function TZOracle9iPlainDriver.ObjectPin(env: POCIEnv; err: POCIError; const object_ref: POCIRef; const corhdl: POCIComplexObject; const pin_option: OCIPinOpt; const pin_duration: OCIDuration; const lock_option: OCILockOpt; _object: PPointer): sword; begin Result := OracleAPI.OCIObjectPin(env, err, object_ref, corhdl, pin_option, pin_duration, lock_option, _object); end; function TZOracle9iPlainDriver.ObjectUnpin(env: POCIEnv; err: POCIError; const _object: Pointer): sword; begin Result := OracleAPI.OCIObjectUnpin(env, err, _object); end; function TZOracle9iPlainDriver.ObjectPinCountReset(env: POCIEnv; err: POCIError; const _object: pointer): sword; begin Result := OracleAPI.OCIObjectPinCountReset(env, err, _object); end; function TZOracle9iPlainDriver.ObjectLock(env: POCIEnv; err: POCIError; const _object: pointer): sword; begin Result := OracleAPI.OCIObjectLock(env, err, _object); end; function TZOracle9iPlainDriver.ObjectLockNoWait(env: POCIEnv; err: POCIError; const _object: pointer): sword; begin Result := OracleAPI.OCIObjectLockNoWait(env, err, _object); end; function TZOracle9iPlainDriver.ObjectMarkUpdate(env: POCIEnv; err: POCIError; const _object: pointer): sword; begin Result := OracleAPI.OCIObjectMarkUpdate(env, err, _object); end; function TZOracle9iPlainDriver.ObjectUnmark(env: POCIEnv; err: POCIError; const _object:pointer): sword; begin Result := OracleAPI.OCIObjectUnmark(env, err, _object); end; function TZOracle9iPlainDriver.ObjectUnmarkByRef(env: POCIEnv; err: POCIError; const ref: POCIRef): sword; begin Result := OracleAPI.OCIObjectUnmarkByRef(env, err, ref); end; function TZOracle9iPlainDriver.ObjectFree(hndl: POCIEnv; err: POCIError; instance:POCIHandle;flags :ub2):sword; begin Result := OracleAPI.OCIObjectFree(hndl, err, instance, flags); end; function TZOracle9iPlainDriver.ObjectMarkDeleteByRef(env: POCIEnv; err: POCIError; const object_ref:POCIRef): sword; begin Result := OracleAPI.OCIObjectMarkDeleteByRef(env, err, object_ref); end; function TZOracle9iPlainDriver.ObjectMarkDelete(env: POCIEnv; err: POCIError; const instance:pointer): sword; begin Result := OracleAPI.OCIObjectMarkDelete(env, err, instance); end; function TZOracle9iPlainDriver.ObjectFlush(env: POCIEnv; err: POCIError; const _object: pointer): sword; begin Result := OracleAPI.OCIObjectFlush(env, err, _object); end; function TZOracle9iPlainDriver.ObjectRefresh(env: POCIEnv; err: POCIError; _object: pointer): sword; begin Result := OracleAPI.OCIObjectRefresh(env, err, _object); end; function TZOracle9iPlainDriver.ObjectCopy(env: POCIEnv; err: POCIError; const svc: POCISvcCtx; const source, null_source, target, null_target: pointer; const tdo: POCIType; const duration: OCIDuration; const option: ub1): sword; begin Result := OracleAPI.OCIObjectCopy(env, err, svc, source, null_source, target, null_target, tdo, duration, option); end; function TZOracle9iPlainDriver.ObjectGetTypeRef(env: POCIEnv; err: POCIError; const instance:pointer; type_ref: POCIRef): sword; begin Result := OracleAPI.OCIObjectGetTypeRef(env, err, instance, type_ref); end; function TZOracle9iPlainDriver.ObjectGetObjectRef(env: POCIEnv; err: POCIError; const _object: pointer; object_ref: POCIRef): sword; begin Result := OracleAPI.OCIObjectGetObjectRef(env, err, _object, object_ref); end; function TZOracle9iPlainDriver.ObjectMakeObjectRef(env: POCIEnv; err: POCIError; const svc: POCISvcCtx; const table: pointer; const values: PPointer; const array_len: ub4; object_ref: POCIRef): sword; begin Result := OracleAPI.OCIObjectMakeObjectRef(env, err, svc, table, values, array_len, object_ref); end; function TZOracle9iPlainDriver.ObjectGetPrimaryKeyTypeRef(env: POCIEnv; err: POCIError; const svc:POCISvcCtx; const table: pointer; type_ref: POCIRef): sword; begin Result := OracleAPI.OCIObjectGetPrimaryKeyTypeRef(env, err, svc, table, type_ref); end; function TZOracle9iPlainDriver.ObjectGetInd(env: POCIEnv; err: POCIError; const instance: pointer; null_struct: PPointer): sword; begin Result := OracleAPI.OCIObjectGetInd(env, err, instance, null_struct); end; function TZOracle9iPlainDriver.ObjectExists(env: POCIEnv; err: POCIError; const ins: pointer; exist: PBoolean): sword; begin Result := OracleAPI.OCIObjectExists(env, err, ins, exist); end; function TZOracle9iPlainDriver.ObjectGetProperty(envh: POCIEnv; errh: POCIError; const obj: pointer; const propertyId: OCIObjectPropId; _property: pointer; size: Pub4): sword; begin Result := OracleAPI.OCIObjectGetProperty(envh, errh, obj, propertyId, _property, size); end; function TZOracle9iPlainDriver.ObjectIsLocked(env: POCIEnv; err: POCIError; const ins: pointer; lock: Pboolean): sword; begin Result := OracleAPI.OCIObjectIsLocked(env, err, ins, lock); end; function TZOracle9iPlainDriver.ObjectIsDirty(env: POCIEnv; err: POCIError; const ins: pointer; dirty: PBoolean): sword; begin Result := OracleAPI.OCIObjectIsDirty(env, err, ins, dirty); end; function TZOracle9iPlainDriver.ObjectPinTable(env: POCIEnv; err: POCIError; const svc:POCISvcCtx; const schema_name: Poratext; const s_n_length: ub4; const object_name: Poratext; const o_n_length:ub4; const scope_obj_ref: POCIRef; const pin_duration: OCIDuration; _object: PPointer): sword; begin Result := OracleAPI.OCIObjectPinTable(env, err, svc, schema_name, s_n_length, object_name, o_n_length, scope_obj_ref, pin_duration, _object); end; function TZOracle9iPlainDriver.ObjectArrayPin(env: POCIEnv; err: POCIError; const ref_array: PPOCIRef; const array_size: ub4; const cor_array: PPOCIComplexObject; const cor_array_size: ub4; const pin_option: OCIPinOpt; const pin_duration: OCIDuration; const lock: OCILockOpt; obj_array: PPointer; pos: Pub4): sword; begin Result := OracleAPI.OCIObjectArrayPin(env, err, ref_array, array_size, cor_array, cor_array_size, pin_option, pin_duration, lock, obj_array, pos); end; function TZOracle9iPlainDriver.CacheFlush(env: POCIEnv; err: POCIError; const svc:POCISvcCtx; const context: pointer; const get: TOCICacheFlushGet; ref: PPOCIRef): sword; begin Result := OracleAPI.OCICacheFlush(env, err, svc, context, get, ref); end; function TZOracle9iPlainDriver.CacheRefresh(env: POCIEnv; err: POCIError; const svc:POCISvcCtx; const option: OCIRefreshOpt; const context: pointer; get: TOCICacheRefreshGet; ref: PPOCIRef): sword; begin Result := OracleAPI.OCICacheRefresh(env, err, svc, option, context, get, ref); end; function TZOracle9iPlainDriver.CacheUnpin(env: POCIEnv; err: POCIError; const svc:POCISvcCtx): sword; begin Result := OracleAPI.OCICacheUnpin(env, err, svc); end; function TZOracle9iPlainDriver.CacheFree(env: POCIEnv; err: POCIError; const svc: POCISvcCtx): sword; begin Result := OracleAPI.OCICacheFree(env, err, svc); end; function TZOracle9iPlainDriver.CacheUnmark(env: POCIEnv; err: POCIError; const svc: POCISvcCtx): sword; begin Result := OracleAPI.OCICacheUnmark(env, err, svc); end; function TZOracle9iPlainDriver.DurationBegin(env: POCIEnv; err: POCIError; svc: POCISvcCtx; const parent: OCIDuration; dur: POCIDuration): sword; begin Result := OracleAPI.OCIDurationBegin(env, err, svc, parent, dur); end; function TZOracle9iPlainDriver.DurationEnd(env: POCIEnv; err: POCIError; svc: POCISvcCtx; duration: OCIDuration): sword; begin Result := OracleAPI.OCIDurationEnd(env, err, svc, duration); end; { < ori.h} function TZOracle9iPlainDriver.Break(svchp: POCISvcCtx; errhp: POCIError): sword; begin Result := OracleAPI.OCIBreak(svchp, errhp); end; function TZOracle9iPlainDriver.DefineArrayOfStruct(defnpp: POCIDefine; errhp: POCIError; pvskip, indskip, rlskip, rcskip: ub4): sword; begin Result := OracleAPI.OCIDefineArrayOfStruct(defnpp, errhp, pvskip, indskip, rlskip, rcskip); end; function TZOracle9iPlainDriver.DefineByPos(stmtp: POCIStmt; var defnpp: POCIDefine; errhp: POCIError; position: ub4; valuep: Pointer; value_sz: sb4; dty: ub2; indp, rlenp, rcodep: Pointer; mode: ub4): sword; begin Result := OracleAPI.OCIDefineByPos(stmtp, defnpp, errhp, position, valuep, value_sz, dty, indp, rlenp, rcodep, mode); end; function TZOracle9iPlainDriver.DescribeAny(svchp: POCISvcCtx; errhp: POCIError; objptr: Pointer; objnm_len: ub4; objptr_typ, info_level, objtyp: ub1; dschp: POCIDescribe): sword; begin Result := OracleAPI.OCIDescribeAny(svchp, errhp, objptr, objnm_len, objptr_typ, info_level, objtyp, dschp); end; function TZOracle9iPlainDriver.DescriptorAlloc(parenth: POCIEnv; var descpp: POCIDescriptor; htype: ub4; xtramem_sz: integer; usrmempp: Pointer): sword; begin Result := OracleAPI.OCIDescriptorAlloc(parenth, descpp, htype, xtramem_sz, usrmempp); end; function TZOracle9iPlainDriver.DescriptorFree(descp: Pointer; htype: ub4): sword; begin Result := OracleAPI.OCIDescriptorFree(descp, htype); end; function TZOracle9iPlainDriver.EnvCreate(var envhpp: POCIEnv; mode: ub4; ctxp: Pointer; malocfp: Pointer; ralocfp: Pointer; mfreefp: Pointer; xtramemsz: size_T; usrmempp: PPointer): sword; begin Result := OracleAPI.OCIEnvCreate(envhpp, mode, ctxp, malocfp, ralocfp, mfreefp, xtramemsz, usrmempp); end; function TZOracle9iPlainDriver.EnvNlsCreate(var envhpp: POCIEnv; mode: ub4; ctxp: Pointer; malocfp: Pointer; ralocfp: Pointer; mfreefp: Pointer; xtramemsz: size_T; usrmempp: PPointer; charset, ncharset: ub2): sword; begin Result := OracleAPI.OCIEnvNlsCreate(envhpp, mode, ctxp, malocfp, ralocfp, mfreefp, xtramemsz, usrmempp, charset, ncharset); end; function TZOracle9iPlainDriver.EnvInit(var envhpp: POCIEnv; mode: ub4; xtramemsz: size_T; usrmempp: PPointer): sword; begin Result := OracleAPI.OCIEnvInit(envhpp, mode, xtramemsz, usrmempp); end; function TZOracle9iPlainDriver.ErrorGet(hndlp: Pointer; recordno: ub4; sqlstate: text; var errcodep: sb4; bufp: text; bufsiz, atype: ub4): sword; begin Result := OracleAPI.OCIErrorGet(hndlp, recordno, sqlstate, errcodep, bufp, bufsiz, atype); end; function TZOracle9iPlainDriver.HandleAlloc(parenth: POCIHandle; var hndlpp: POCIHandle; atype: ub4; xtramem_sz: size_T; usrmempp: PPointer): sword; begin Result := OracleAPI.OCIHandleAlloc(parenth, hndlpp, atype, xtramem_sz, usrmempp); end; function TZOracle9iPlainDriver.HandleFree(hndlp: Pointer; atype: ub4): sword; begin Result := OracleAPI.OCIHandleFree(hndlp, atype); end; function TZOracle9iPlainDriver.Initializ(mode: ub4; ctxp, malocfp, ralocfp, mfreefp: Pointer): sword; begin Result := OracleAPI.OCIInitialize(mode, ctxp, malocfp, ralocfp, mfreefp); end; function TZOracle9iPlainDriver.LobAppend(svchp: POCISvcCtx; errhp: POCIError; dst_locp, src_locp: POCILobLocator): sword; begin Result := OracleAPI.OCILobAppend(svchp, errhp, dst_locp, src_locp); end; function TZOracle9iPlainDriver.LobAssign(svchp: POCISvcCtx; errhp: POCIError; src_locp: POCILobLocator; var dst_locpp: POCILobLocator): sword; begin Result := OracleAPI.OCILobAssign(svchp, errhp, src_locp, dst_locpp); end; function TZOracle9iPlainDriver.LobClose(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator): sword; begin Result := OracleAPI.OCILobClose(svchp, errhp, locp); end; function TZOracle9iPlainDriver.LobCopy(svchp: POCISvcCtx; errhp: POCIError; dst_locp, src_locp: POCILobLocator; amount, dst_offset, src_offset: ub4): sword; begin Result := OracleAPI.OCILobCopy(svchp, errhp, dst_locp, src_locp, amount, dst_offset, src_offset); end; function TZOracle9iPlainDriver.LobDisableBuffering(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator): sword; begin Result := OracleAPI.OCILobDisableBuffering(svchp, errhp, locp); end; function TZOracle9iPlainDriver.LobEnableBuffering(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator): sword; begin Result := OracleAPI.OCILobEnableBuffering(svchp, errhp, locp); end; function TZOracle9iPlainDriver.LobErase(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; var amount: ub4; offset: ub4): sword; begin Result := OracleAPI.OCILobErase(svchp, errhp, locp, amount, offset); end; function TZOracle9iPlainDriver.LobFileExists(svchp: POCISvcCtx; errhp: POCIError; filep: POCILobLocator; var flag: Boolean): sword; begin Result := OracleAPI.OCILobFileExists(svchp, errhp, filep, flag); end; function TZOracle9iPlainDriver.LobFileGetName(envhp: POCIEnv; errhp: POCIError; filep: POCILobLocator; dir_alias: text; var d_length: ub2; filename: text; var f_length: ub2): sword; begin Result := OracleAPI.OCILobFileGetName(envhp, errhp, filep, dir_alias, d_length, filename, f_length); end; function TZOracle9iPlainDriver.LobFileSetName(envhp: POCIEnv; errhp: POCIError; var filep: POCILobLocator; dir_alias: text; d_length: ub2; filename: text; f_length: ub2): sword; begin Result := OracleAPI.OCILobFileSetName(envhp, errhp, filep, dir_alias, d_length, filename, f_length); end; function TZOracle9iPlainDriver.LobFlushBuffer(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; flag: ub4): sword; begin Result := OracleAPI.OCILobFlushBuffer(svchp, errhp, locp, flag); end; function TZOracle9iPlainDriver.LobGetLength(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; var lenp: ub4): sword; begin Result := OracleAPI.OCILobGetLength(svchp, errhp, locp, lenp); end; function TZOracle9iPlainDriver.LobIsOpen(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; var flag: LongBool): sword; begin Result := OracleAPI.OCILobIsOpen(svchp, errhp, locp, flag); end; function TZOracle9iPlainDriver.LobLoadFromFile(svchp: POCISvcCtx; errhp: POCIError; dst_locp, src_locp: POCILobLocator; amount, dst_offset, src_offset: ub4): sword; begin Result := OracleAPI.OCILobLoadFromFile(svchp, errhp, dst_locp, src_locp, amount, dst_offset, src_offset); end; function TZOracle9iPlainDriver.LobLocatorIsInit(envhp: POCIEnv; errhp: POCIError; locp: POCILobLocator; var is_initialized: LongBool): sword; begin Result := OracleAPI.OCILobLocatorIsInit(envhp, errhp, locp, is_initialized); end; function TZOracle9iPlainDriver.LobOpen(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; mode: ub1): sword; begin Result := OracleAPI.OCILobOpen(svchp, errhp, locp, mode); end; function TZOracle9iPlainDriver.LobRead(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; var amtp: ub4; offset: ub4; bufp: Pointer; bufl: ub4; ctxp, cbfp: Pointer; csid: ub2; csfrm: ub1): sword; begin Result := OracleAPI.OCILobRead(svchp, errhp, locp, amtp, offset, bufp, bufl, ctxp, cbfp, csid, csfrm); end; function TZOracle9iPlainDriver.LobTrim(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; newlen: ub4): sword; begin Result := OracleAPI.OCILobTrim(svchp, errhp, locp, newlen); end; function TZOracle9iPlainDriver.LobWrite(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; var amtp: ub4; offset: ub4; bufp: Pointer; bufl: ub4; piece: ub1; ctxp, cbfp: Pointer; csid: ub2; csfrm: ub1): sword; begin Result := OracleAPI.OCILobWrite(svchp, errhp, locp, amtp, offset, bufp, bufl, piece, ctxp, cbfp, csid, csfrm); end; function TZOracle9iPlainDriver.LobCreateTemporary(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; csid: ub2; csfrm, lobtype: ub1; cache: LongBool; duration: OCIDuration): sword; begin Result := OracleAPI.OCILobCreateTemporary(svchp, errhp, locp, csid, csfrm, lobtype, cache, duration); end; function TZOracle9iPlainDriver.LobFreeTemporary(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator): sword; begin Result := OracleAPI.OCILobFreeTemporary(svchp, errhp, locp); end; function TZOracle9iPlainDriver.LobCharSetForm ( envhp: POCIEnv; errhp: POCIError; const locp: POCILobLocator; csfrm: pub1): sword; begin Result := OracleAPI.OCILobCharSetForm(envhp, errhp, locp, csfrm); end; function TZOracle9iPlainDriver.LobCharSetId ( envhp: POCIEnv; errhp: POCIError; const locp: POCILobLocator; csid: pub2): sword; begin Result := OracleAPI.OCILobCharSetId (envhp, errhp, locp, csid); end; function TZOracle9iPlainDriver.LobIsTemporary(svchp: POCISvcCtx; errhp: POCIError; locp: POCILobLocator; var is_temporary: LongBool): sword; begin Result := OracleAPI.OCILobIsTemporary(svchp, errhp, locp, is_temporary); end; function TZOracle9iPlainDriver.ParamGet(hndlp: Pointer; htype: ub4; errhp: POCIError; var parmdpp: Pointer; pos: ub4): sword; begin Result := OracleAPI.OCIParamGet(hndlp, htype, errhp, parmdpp, pos); end; function TZOracle9iPlainDriver.PasswordChange(svchp: POCISvcCtx; errhp: POCIError; user_name: text; usernm_len: ub4; opasswd: text; opasswd_len: ub4; npasswd: text; npasswd_len: sb4; mode: ub4): sword; begin Result := OracleAPI.OCIPasswordChange(svchp, errhp, user_name, usernm_len, opasswd, opasswd_len, npasswd, npasswd_len, mode); end; function TZOracle9iPlainDriver.Reset(svchp: POCISvcCtx; errhp: POCIError): sword; begin Result := OracleAPI.OCIReset(svchp, errhp); end; function TZOracle9iPlainDriver.ResultSetToStmt(rsetdp: POCIHandle; errhp: POCIError): sword; begin Result := OracleAPI.OCIResultSetToStmt(rsetdp, errhp); end; function TZOracle9iPlainDriver.GetEnvCharsetByteWidth(hndl: POCIEnv; err: POCIError; Value: sb4): sword; begin Result := OracleAPI.OCINlsNumericInfoGet(hndl, err, @value, OCI_NLS_CHARSET_MAXBYTESZ); end; procedure TZOracle9iPlainDriver.ClientVersion(major_version, minor_version, update_num, patch_num, port_update_num: psword); begin OracleAPI.OCIClientVersion(major_version, minor_version, update_num, patch_num, port_update_num); end; function TZOracle9iPlainDriver.NumberInc(err: POCIError; number: POCINumber): sword; begin Result := OracleAPI.OCINumberInc(err, number); end; function TZOracle9iPlainDriver.NumberDec(err: POCIError; number: POCINumber): sword; begin Result := OracleAPI.OCINumberDec(err, number); end; procedure TZOracle9iPlainDriver.NumberSetZero(err: POCIError; number: POCINumber); begin OracleAPI.OCINumberSetZero(err, number); end; procedure TZOracle9iPlainDriver.NumberSetPi(err: POCIError; number: POCINumber); begin OracleAPI.OCINumberSetPi(err, number); end; function TZOracle9iPlainDriver.NumberAdd(err: POCIError; const number1: POCINumber; const number2: POCINumber; _result: POCINumber): sword; begin Result := OracleAPI.OCINumberAdd(err, number1, number2, _result); end; function TZOracle9iPlainDriver.NumberSub(err: POCIError; const number1: POCINumber; const number2: POCINumber; _result: POCINumber): sword; begin Result := OracleAPI.OCINumberSub(err, number1, number2, _result); end; function TZOracle9iPlainDriver.NumberMul(err: POCIError; const number1: POCINumber; const number2: POCINumber; _result: POCINumber): sword; begin Result := OracleAPI.OCINumberMul(err, number1, number2, _result); end; function TZOracle9iPlainDriver.NumberDiv(err: POCIError; const number1: POCINumber; const number2: POCINumber; _result: POCINumber): sword; begin Result := OracleAPI.OCINumberDiv(err, number1, number2, _result); end; function TZOracle9iPlainDriver.NumberMod(err: POCIError; const number1: POCINumber; const number2: POCINumber; _result: POCINumber): sword; begin Result := OracleAPI.OCINumberMod(err, number1, number2, _result); end; function TZOracle9iPlainDriver.NumberIntPower(err: POCIError; const number1: POCINumber; const number2: POCINumber; _result: POCINumber): sword; begin Result := OracleAPI.OCINumberIntPower(err, number1, number2, _result); end; function TZOracle9iPlainDriver.NumberShift(err: POCIError; const number: POCINumber; const nDig: sword; _result: POCINumber): sword; begin Result := OracleAPI.OCINumberShift(err, number, nDig, _result); end; function TZOracle9iPlainDriver.NumberNeg(err: POCIError; const number: POCINumber; _result: POCINumber): sword; begin Result := OracleAPI.OCINumberNeg(err, number, _result); end; function TZOracle9iPlainDriver.NumberToText(err: POCIError; const number: POCINumber; const fmt: Poratext; fmt_length: ub4; const nls_params: Poratext; nls_p_length: ub4; buf_size: pub4; buf: poratext): sword; begin Result := OracleAPI.OCINumberToText(err, number, fmt, fmt_length, nls_params, nls_p_length, buf_size, buf); end; function TZOracle9iPlainDriver.NumberFromText(err: POCIError; const str: poratext; str_length: ub4; const fmt: poratext; fmt_length: ub4; const nls_params: poratext; nls_p_length: ub4; number: POCINumber): sword; begin Result := OracleAPI.OCINumberFromText(err, str, str_length, fmt, fmt_length, nls_params, nls_p_length, number); end; function TZOracle9iPlainDriver.NumberToInt(err: POCIError; const number: POCINumber; rsl_length: uword; rsl_flag: uword; rsl: Pointer): sword; begin Result := OracleAPI.OCINumberToInt(err, number, rsl_length, rsl_flag, rsl); end; function TZOracle9iPlainDriver.NumberFromInt(err: POCIError; const inum: Pointer; inum_length: uword; inum_s_flag: uword; number: POCINumber): sword; begin Result := OracleAPI.OCINumberFromInt(err, inum, inum_length, inum_s_flag, number); end; function TZOracle9iPlainDriver.NumberToReal(err: POCIError; const number: POCINumber; rsl_length: uword; rsl: Pointer): sword; begin Result := OracleAPI.OCINumberToReal(err, number, rsl_length, rsl); end; function TZOracle9iPlainDriver.NumberToRealArray(err: POCIError; const number: PPOCINumber; elems: uword; rsl_length: uword; rsl: Pointer): sword; begin Result := OracleAPI.OCINumberToRealArray(err, number, elems, rsl_length, rsl); end; function TZOracle9iPlainDriver.NumberFromReal(err: POCIError; const rnum: Pointer; rnum_length: uword; number: POCINumber): sword; begin Result := OracleAPI.OCINumberFromReal(err, rnum, rnum_length, number); end; function TZOracle9iPlainDriver.NumberCmp(err: POCIError; const number1: POCINumber; const number2: POCINumber; _result: psword): sword; begin Result := OracleAPI.OCINumberCmp(err, number1, number2, _result); end; function TZOracle9iPlainDriver.NumberSign(err: POCIError; const number: POCINumber; _result: psword): sword; begin Result := OracleAPI.OCINumberSign(err, number, _result); end; function TZOracle9iPlainDriver.NumberIsZero(err: POCIError; const number: POCINumber; _Result: pboolean): sword; begin Result := OracleAPI.OCINumberIsZero(err, number, _result); end; function TZOracle9iPlainDriver.NumberIsInt(err: POCIError; const number: POCINumber; _result: Pboolean): sword; begin Result := OracleAPI.OCINumberIsInt(err, number, _result); end; function TZOracle9iPlainDriver.NumberAssign(err: POCIError; const from: POCINumber; _to: POCINumber): sword; begin Result := OracleAPI.OCINumberAssign(err, from, _to); end; function TZOracle9iPlainDriver.NumberAbs(err: POCIError; const number: POCINumber; _result: POCINumber): sword; begin Result := OracleAPI.OCINumberAbs(err, number, _result); end; function TZOracle9iPlainDriver.NumberCeil(err: POCIError; const number: POCINumber; _result: POCINumber): sword; begin Result := OracleAPI.OCINumberCeil(err, number, _result); end; function TZOracle9iPlainDriver.NumberFloor(err: POCIError; const number: POCINumber; _result: POCINumber): sword; begin Result := OracleAPI.OCINumberFloor(err, number, _result); end; function TZOracle9iPlainDriver.NumberSqrt(err: POCIError; const number: POCINumber; _result: POCINumber): sword; begin Result := OracleAPI.OCINumberSqrt(err, number, _result); end; function TZOracle9iPlainDriver.NumberTrunc(err: POCIError; const number: POCINumber; _result: POCINumber): sword; begin Result := OracleAPI.OCINumberTrunc(err, number, _result); end; function TZOracle9iPlainDriver.NumberPower(err: POCIError; const base: POCINumber; const number: POCINumber; _result: POCINumber): sword; begin Result := OracleAPI.OCINumberPower(err, base, number, _result); end; function TZOracle9iPlainDriver.NumberRound(err: POCIError; const number: POCINumber; decplace: sword; _result: POCINumber): sword; begin Result := OracleAPI.OCINumberRound(err, number, decplace, _result); end; function TZOracle9iPlainDriver.NumberPrec(err: POCIError; const number: POCINumber; nDigs: sword; _result: POCINumber): sword; begin Result := OracleAPI.OCINumberPrec(err, number, nDigs, _result); end; function TZOracle9iPlainDriver.NumberSin(err: POCIError; const number: POCINumber; _result: POCINumber): sword; begin Result := OracleAPI.OCINumberSin(err, number, _result); end; function TZOracle9iPlainDriver.NumberArcSin(err: POCIError; const number: POCINumber; _result: POCINumber): sword; begin Result := OracleAPI.OCINumberArcSin(err, number, _result); end; function TZOracle9iPlainDriver.NumberHypSin(err: POCIError; const number: POCINumber; _result: POCINumber): sword; begin Result := OracleAPI.OCINumberHypSin(err, number, _result); end; function TZOracle9iPlainDriver.NumberCos(err: POCIError; const number: POCINumber; _result: POCINumber): sword; begin Result := OracleAPI.OCINumberCos(err, number, _result); end; function TZOracle9iPlainDriver.NumberArcCos(err: POCIError; const number: POCINumber; _result: POCINumber): sword; begin Result := OracleAPI.OCINumberArcCos(err, number, _result); end; function TZOracle9iPlainDriver.NumberHypCos(err: POCIError; const number: POCINumber; _result: POCINumber): sword; begin Result := OracleAPI.OCINumberHypCos(err, number, _result); end; function TZOracle9iPlainDriver.NumberTan(err: POCIError; const number: POCINumber; _result: POCINumber): sword; begin Result := OracleAPI.OCINumberTan(err, number, _result); end; function TZOracle9iPlainDriver.NumberArcTan(err: POCIError; const number: POCINumber; _result: POCINumber): sword; begin Result := OracleAPI.OCINumberArcTan(err, number, _result); end; function TZOracle9iPlainDriver.NumberArcTan2(err: POCIError; const number1: POCINumber; const number2: POCINumber; _result: POCINumber): sword; begin Result := OracleAPI.OCINumberArcTan2(err, number1, number2, _result); end; function TZOracle9iPlainDriver.NumberHypTan(err: POCIError; const number: POCINumber; _result: POCINumber): sword; begin Result := OracleAPI.OCINumberHypTan(err, number, _result); end; function TZOracle9iPlainDriver.NumberExp(err: POCIError; const number: POCINumber; _result: POCINumber): sword; begin Result := OracleAPI.OCINumberExp(err, number, _result); end; function TZOracle9iPlainDriver.NumberLn(err: POCIError; const number: POCINumber; _result: POCINumber): sword; begin Result := OracleAPI.OCINumberLn(err, number, _result); end; function TZOracle9iPlainDriver.NumberLog(err: POCIError; const base: POCINumber; const number: POCINumber; _result: POCINumber): sword; begin Result := OracleAPI.OCINumberLog(err, base, number, _result); end; function TZOracle9iPlainDriver.TableSize(hndl: POCIEnv; err: POCIError; const tbl: POCITable; size: psb4): sword; begin Result := OracleAPI.OCITableSize(hndl, err, tbl, size); end; function TZOracle9iPlainDriver.TableExists(hndl: POCIEnv; err: POCIError; const tbl: POCITable; index: sb4; exists: PBoolean): sword; begin Result := OracleAPI.OCITableExists(hndl, err, tbl, index, exists); end; function TZOracle9iPlainDriver.TableDelete(hndl: POCIEnv; err: POCIError; index: sb4; tbl: POCITable): sword; begin Result := OracleAPI.OCITableDelete(hndl, err, index, tbl); end; function TZOracle9iPlainDriver.TableFirst(hndl: POCIEnv; err: POCIError; const tbl: POCITable; index: sb4): sword; begin Result := OracleAPI.OCITableFirst(hndl, err, tbl, index); end; function TZOracle9iPlainDriver.TableLast(hndl: POCIEnv; err: POCIError; const tbl: POCITable; index: sb4): sword; begin Result := OracleAPI.OCITableLast(hndl, err, tbl, index); end; function TZOracle9iPlainDriver.TableNext(hndl: POCIEnv; err: POCIError; index: sb4; const tbl: POCITable; next_index: psb4; exists: PBoolean): sword; begin Result := OracleAPI.OCITableNext(hndl, err, index, tbl, next_index, exists); end; function TZOracle9iPlainDriver.TablePrev(hndl: POCIEnv; err: POCIError; index: sb4; const tbl: POCITable; prev_index: psb4; exists: PBoolean): sword; begin Result := OracleAPI.OCITablePrev(hndl, err, index, tbl, prev_index, exists); end; function TZOracle9iPlainDriver.ObjectSetAttr(env: POCIEnv; err: POCIError; instance: Pointer; null_struct: pointer; tdo: POCIType; const names: PPAnsiChar; const lengths: pub4; const name_count: ub4; const indexes: pub4; const index_count: ub4; const null_status: POCIInd; const attr_null_struct: Pointer; const attr_value: Pointer): sword; begin Result := OracleAPI.OCIObjectSetAttr(env, err, instance, null_struct, tdo, names, lengths, name_count, indexes, index_count, null_status, attr_null_struct, attr_value); end; function TZOracle9iPlainDriver.ObjectGetAttr(env: POCIEnv; err: POCIError; instance: Pointer; null_struct: Pointer; tdo: POCIType; const names: PPoratext; const lengths: pub4; const name_count: ub4; const indexes: pub4; const index_count: ub4; attr_null_status: POCIInd; attr_null_struct, attr_value: PPointer; attr_tdo: PPOCIType): sword; begin Result := OracleAPI.OCIObjectGetAttr(env, err, instance, null_struct, tdo, names, lengths, name_count, indexes, index_count, attr_null_status, attr_null_struct, attr_value, attr_tdo); end; function TZOracle9iPlainDriver.Ping(svchp: POCISvcCtx; errhp: POCIError; mode: ub4 = OCI_DEFAULT): sword; begin Result := OracleAPI.OCIPing(svchp, errhp, mode); end; function TZOracle9iPlainDriver.ServerAttach(srvhp: POCIServer; errhp: POCIError; dblink: text; dblink_len: sb4; mode: ub4): sword; begin Result := OracleAPI.OCIServerAttach(srvhp, errhp, dblink, dblink_len, mode); end; function TZOracle9iPlainDriver.ServerDetach(srvhp: POCIServer; errhp: POCIError; mode: ub4): sword; begin Result := OracleAPI.OCIServerDetach(srvhp, errhp, mode); end; function TZOracle9iPlainDriver.ServerVersion(hndlp: POCIHandle; errhp: POCIError; bufp: text; bufsz: ub4; hndltype: ub1): sword; begin Result := OracleAPI.OCIServerVersion(hndlp, errhp, bufp, bufsz, hndltype); end; function TZOracle9iPlainDriver.ServerRelease(hndlp: POCIHandle; errhp: POCIError; bufp: text; bufsz: ub4; hndltype: ub1; version:pointer): sword; begin Result:=OCI_ERROR; if assigned(OracleAPI.OCIServerRelease) then Result := OracleAPI.OCIServerRelease(hndlp, errhp, bufp, bufsz, hndltype, version); end; function TZOracle9iPlainDriver.SessionBegin(svchp: POCISvcCtx; errhp: POCIError; usrhp: POCISession; credt, mode: ub4): sword; begin Result := OracleAPI.OCISessionBegin(svchp, errhp, usrhp, credt, mode); end; function TZOracle9iPlainDriver.SessionEnd(svchp: POCISvcCtx; errhp: POCIError; usrhp: POCISession; mode: ub4): sword; begin Result := OracleAPI.OCISessionEnd(svchp, errhp, usrhp, mode); end; function TZOracle9iPlainDriver.StmtExecute(svchp: POCISvcCtx; stmtp: POCIStmt; errhp: POCIError; iters, rowoff: ub4; snap_in, snap_out: POCISnapshot; mode: ub4): sword; begin Result := OracleAPI.OCIStmtExecute(svchp, stmtp, errhp, iters, rowoff, snap_in, snap_out, mode); end; function TZOracle9iPlainDriver.StmtFetch(stmtp: POCIStmt; errhp: POCIError; nrows: ub4; orientation: ub2; mode: ub4): sword; begin Result := OracleAPI.OCIStmtFetch(stmtp, errhp, nrows, orientation, mode); end; function TZOracle9iPlainDriver.StmtGetPieceInfo(stmtp: POCIStmt; errhp: POCIError; var hndlpp: Pointer; var typep: ub4; var in_outp: ub1; var iterp, idxp: ub4; var piecep: ub1): sword; begin Result := OracleAPI.OCIStmtGetPieceInfo(stmtp, errhp, hndlpp, typep, in_outp, iterp, idxp, piecep); end; function TZOracle9iPlainDriver.StmtPrepare(stmtp: POCIStmt; errhp: POCIError; stmt: text; stmt_len, language, mode: ub4): sword; begin Result := OracleAPI.OCIStmtPrepare(stmtp, errhp, stmt, stmt_len, language, mode); end; function TZOracle9iPlainDriver.StmtSetPieceInfo(handle: Pointer; typep: ub4; errhp: POCIError; buf: Pointer; var alenp: ub4; piece: ub1; indp: Pointer; var rcodep: ub2): sword; begin Result := OracleAPI.OCIStmtSetPieceInfo(handle, typep, errhp, buf, alenp, piece, indp, rcodep); end; function TZOracle9iPlainDriver.TransCommit(svchp: POCISvcCtx; errhp: POCIError; flags: ub4): sword; begin Result := OracleAPI.OCITransCommit(svchp, errhp, flags); end; function TZOracle9iPlainDriver.TransDetach(svchp: POCISvcCtx; errhp: POCIError; flags: ub4): sword; begin Result := OracleAPI.OCITransDetach(svchp, errhp, flags); end; function TZOracle9iPlainDriver.TransForget(svchp: POCISvcCtx; errhp: POCIError; flags: ub4): sword; begin Result := OracleAPI.OCITransForget(svchp, errhp, flags); end; function TZOracle9iPlainDriver.TransPrepare(svchp: POCISvcCtx; errhp: POCIError; flags: ub4): sword; begin Result := OracleAPI.OCITransPrepare(svchp, errhp, flags); end; function TZOracle9iPlainDriver.TransRollback(svchp: POCISvcCtx; errhp: POCIError; flags: ub4): sword; begin Result := OracleAPI.OCITransRollback(svchp, errhp, flags); end; function TZOracle9iPlainDriver.TransStart(svchp: POCISvcCtx; errhp: POCIError; timeout: word; flags: ub4): sword; begin Result := OracleAPI.OCITransStart(svchp, errhp, timeout, flags); end; function TZOracle9iPlainDriver.DateTimeAssign(hndl: POCIEnv; err: POCIError; const from: POCIDateTime; _to: POCIDateTime): sword; begin Result := OracleAPI.OCIDateTimeAssign(hndl, err, from, _to); end; function TZOracle9iPlainDriver.DateTimeCheck(hndl: POCIEnv; err: POCIError; const date: POCIDateTime; var valid: ub4): sword; begin Result := OracleAPI.OCIDateTimeCheck(hndl, err, date, valid); end; function TZOracle9iPlainDriver.DateTimeCompare(hndl: POCIEnv; err: POCIError; const date1, date2: POCIDateTime; var _result: sword): sword; begin Result := OracleAPI.OCIDateTimeCompare(hndl, err, date1, date2, _result); end; function TZOracle9iPlainDriver.DateTimeConstruct(hndl: POCIEnv; err: POCIError; datetime: POCIDateTime; year: sb2; month, day, hour, min, sec: ub1; fsec: ub4; timezone: text; timezone_length: size_t): sword; begin Result := OracleAPI.OCIDateTimeConstruct(hndl, err, datetime, year, month, day, hour, min, sec, fsec, timezone, timezone_length); end; function TZOracle9iPlainDriver.DateTimeConvert(hndl: POCIEnv; err: POCIError; indate, outdate: POCIDateTime): sword; begin Result := OracleAPI.OCIDateTimeConvert(hndl, err, indate, outdate); end; function TZOracle9iPlainDriver.DateTimeFromText(hndl: POCIEnv; err: POCIError; const date_str: text; d_str_length: size_t; const fmt: text; fmt_length: ub1; const lang_name: text; lang_length: size_t; date: POCIDateTime): sword; begin Result := OracleAPI.OCIDateTimeFromText(hndl, err, date_str, d_str_length, fmt, fmt_length, lang_name, lang_length, date); end; function TZOracle9iPlainDriver.DateTimeGetDate(hndl: POCIEnv; err: POCIError; const date: POCIDateTime; var year: sb2; var month, day: ub1): sword; begin Result := OracleAPI.OCIDateTimeGetDate(hndl, err, date, year, month, day); end; function TZOracle9iPlainDriver.DateTimeGetTime(hndl: POCIEnv; err: POCIError; datetime: POCIDateTime; var hour, minute, sec: ub1; var fsec: ub4): sword; begin Result := OracleAPI.OCIDateTimeGetTime(hndl, err, datetime, hour, minute, sec, fsec); end; function TZOracle9iPlainDriver.DateTimeGetTimeZoneName(hndl: POCIEnv; err: POCIError; datetime: POCIDateTime; var buf: ub1; var buflen: ub4): sword; begin Result := OracleAPI.OCIDateTimeGetTimeZoneName(hndl, err, datetime, buf, buflen); end; function TZOracle9iPlainDriver.DateTimeGetTimeZoneOffset(hndl: POCIEnv; err: POCIError; const datetime: POCIDateTime; var hour, minute: sb1): sword; begin Result := OracleAPI.OCIDateTimeGetTimeZoneOffset(hndl, err, datetime, hour, minute); end; function TZOracle9iPlainDriver.DateTimeSysTimeStamp(hndl: POCIEnv; err: POCIError; sys_date: POCIDateTime): sword; begin Result := OracleAPI.OCIDateTimeSysTimeStamp(hndl, err, sys_date); end; function TZOracle9iPlainDriver.DateTimeToText(hndl: POCIEnv; err: POCIError; const date: POCIDateTime; const fmt: text; fmt_length, fsprec: ub1; const lang_name: text; lang_length: size_t; var buf_size: ub4; buf: text): sword; begin Result := OracleAPI.OCIDateTimeToText(hndl, err, date, fmt, fmt_length, fsprec, lang_name, lang_length, buf_size, buf); end; {ort.h} function TZOracle9iPlainDriver.TypeIterNew(env: POCIEnv; err: POCIError; const tdo: POCIType; iterator_ort: PPOCITypeIter): sword; begin Result := OracleAPI.OCITypeIterNew(env, err, tdo, iterator_ort); end; function TZOracle9iPlainDriver.TypeIterSet(env: POCIEnv; err: POCIError; const tdo: POCIType; iterator_ort: POCITypeIter): sword; begin Result := OracleAPI.OCITypeIterSet(env, err, tdo, iterator_ort); end; function TZOracle9iPlainDriver.TypeIterFree(env: POCIEnv; err: POCIError; iterator_ort: POCITypeIter): sword; begin Result := OracleAPI.OCITypeIterFree(env, err, iterator_ort); end; function TZOracle9iPlainDriver.TypeByName(env: POCIEnv; err: POCIError; const svc: POCISvcCtx; schema_name: Poratext; const s_length: ub4; const type_name: Poratext; const t_length: ub4; version_name: Poratext; const v_length: ub4; const pin_duration: OCIDuration; const get_option: OCITypeGetOpt; tdo: PPOCIType): sword; begin Result := OracleAPI.OCITypeByName(env, err, svc, schema_name, s_length, type_name, t_length, version_name, v_length, pin_duration, get_option, tdo); end; function TZOracle9iPlainDriver.TypeArrayByName(env: POCIEnv; err: POCIError; svc: POCISvcCtx; array_len: ub4; schema_name: PPoratext; s_length: Pub4; type_name: PPoratext; t_length: Pub4; version_name: PPoratext; v_length: Pub4; pin_duration: OCIDuration; get_option: OCITypeGetOpt; tdo: PPOCIType): sword; begin Result := OracleAPI.OCITypeArrayByName(env, err, svc, array_len, schema_name, s_length, type_name, t_length, version_name, v_length, pin_duration, get_option, tdo); end; function TZOracle9iPlainDriver.TypeByRef(env: POCIEnv; err: POCIError; type_ref: POCIRef; pin_duration: OCIDuration; get_option: OCITypeGetOpt; tdo: PPOCIType): sword; begin Result := OracleAPI.OCITypeByRef(env, err, type_ref, pin_duration, get_option, tdo); end; function TZOracle9iPlainDriver.TypeArrayByRef(env: POCIEnv; err: POCIError; array_len: ub4; type_ref: PPOCIRef; pin_duration: OCIDuration; get_option: OCITypeGetOpt; tdo: PPOCIType): sword; begin Result := OracleAPI.OCITypeArrayByRef(env, err, array_len, type_ref, pin_duration, get_option, tdo); end; function TZOracle9iPlainDriver.TypeName(env: POCIEnv; err: POCIError; tdo: POCIType; n_length: Pub4): poratext; begin Result := OracleAPI.OCITypeName(env, err, tdo, n_length); end; function TZOracle9iPlainDriver.TypeSchema(env: POCIEnv; err: POCIError; const tdo: POCIType; n_length: Pub4): poratext; begin Result := OracleAPI.OCITypeSchema(env, err, tdo, n_length); end; function TZOracle9iPlainDriver.TypeTypeCode(env: POCIEnv; err: POCIError; const tdo: POCIType): OCITypeCode; begin Result := OracleAPI.OCITypeTypeCode(env, err, tdo); end; function TZOracle9iPlainDriver.TypeCollTypeCode(env: POCIEnv; err:POCIError; const tdo: POCIType): OCITypeCode; begin Result := OracleAPI.OCITypeCollTypeCode(env, err, tdo); end; function TZOracle9iPlainDriver.TypeVersion(env: POCIEnv; err: POCIError; const tdo: POCIType; v_length: Pub4): poratext; begin Result := OracleAPI.OCITypeVersion(env, err, tdo, v_length); end; function TZOracle9iPlainDriver.TypeAttrs(env: POCIEnv; err: POCIError; const tdo:POCIType): ub4; begin Result := OracleAPI.OCITypeAttrs(env, err, tdo); end; function TZOracle9iPlainDriver.TypeMethods(env: POCIEnv; err: POCIError; const tdo: POCIType): ub4; begin Result := OracleAPI.OCITypeMethods(env, err, tdo); end; function TZOracle9iPlainDriver.TypeElemName(env: POCIEnv; err: POCIError; const elem: POCITypeElem; n_length:Pub4): poratext; begin Result := OracleAPI.OCITypeElemName(env, err, elem, n_length); end; function TZOracle9iPlainDriver.TypeElemTypeCode(env: POCIEnv; err: POCIError; const elem: POCITypeElem): OCITypeCode; begin Result := OracleAPI.OCITypeElemTypeCode(env, err, elem); end; function TZOracle9iPlainDriver.TypeElemType(env: POCIEnv; err: POCIError; const elem: POCITypeElem; elem_tdo:PPOCIType): sword; begin Result := OracleAPI.OCITypeElemType(env, err, elem, elem_tdo); end; function TZOracle9iPlainDriver.TypeElemFlags(env: POCIEnv; err: POCIError; const elem: POCITypeElem): ub4; begin Result := OracleAPI.OCITypeElemFlags(env, err, elem); end; function TZOracle9iPlainDriver.TypeElemNumPrec(env: POCIEnv; err: POCIError; const elem: POCITypeElem): ub1; begin Result := OracleAPI.OCITypeElemNumPrec(env, err, elem); end; function TZOracle9iPlainDriver.TypeElemNumScale(env: POCIEnv; err: POCIError; const elem: POCITypeElem): sb1; begin Result := OracleAPI.OCITypeElemNumScale(env, err, elem); end; function TZOracle9iPlainDriver.TypeElemLength(env: POCIEnv; err: POCIError; const elem:POCITypeElem): ub4; begin Result := OracleAPI.OCITypeElemLength(env, err, elem); end; function TZOracle9iPlainDriver.TypeElemCharSetID(env: POCIEnv; err: POCIError; const elem: POCITypeElem): ub2; begin Result := OracleAPI.OCITypeElemCharSetID(env, err, elem); end; function TZOracle9iPlainDriver.TypeElemCharSetForm(env: POCIEnv; err: POCIError; const elem: POCITypeElem): ub2; begin Result := OracleAPI.OCITypeElemCharSetForm(env, err, elem); end; function TZOracle9iPlainDriver.TypeElemParameterizedType(env: POCIEnv; err: POCIError; const elem: POCITypeElem; type_stored: PPOCIType): sword; begin Result := OracleAPI.OCITypeElemParameterizedType(env, err, elem, type_stored); end; function TZOracle9iPlainDriver.TypeElemExtTypeCode(env: POCIEnv; err: POCIError; const elem: POCITypeElem): OCITypeCode; begin Result := OracleAPI.OCITypeElemExtTypeCode(env, err, elem); end; function TZOracle9iPlainDriver.TypeAttrByName(env: POCIEnv; err: POCIError; const tdo: POCIType; const name: Poratext; const n_length: ub4; elem: PPOCITypeElem): sword; begin Result := OracleAPI.OCITypeAttrByName(env, err, tdo, name, n_length, elem); end; function TZOracle9iPlainDriver.TypeAttrNext(env: POCIEnv; err: POCIError; iterator_ort: POCITypeIter; elem: PPOCITypeElem): sword; begin Result := OracleAPI.OCITypeAttrNext(env, err, iterator_ort, elem); end; function TZOracle9iPlainDriver.TypeCollElem(env: POCIEnv; err: POCIError; const tdo:POCIType; element: PPOCITypeElem): sword; begin Result := OracleAPI.OCITypeCollElem(env, err, tdo, element); end; function TZOracle9iPlainDriver.TypeCollSize(env: POCIEnv; err: POCIError; const tdo: POCIType; num_elems: Pub4): sword; begin Result := OracleAPI.OCITypeCollSize(env, err, tdo, num_elems); end; function TZOracle9iPlainDriver.TypeCollExtTypeCode(env: POCIEnv; err: POCIError; const tdo:POCIType; sqt_code: POCITypeCode): sword; begin Result := OracleAPI.OCITypeCollExtTypeCode(env, err, tdo, sqt_code); end; function TZOracle9iPlainDriver.TypeMethodOverload(env: POCIEnv; err: POCIError; const tdo: POCIType; const method_name: Poratext; const m_length: ub4): ub4; begin Result := OracleAPI.OCITypeMethodOverload(env, err, tdo, method_name, m_length); end; function TZOracle9iPlainDriver.TypeMethodByName(env: POCIEnv; err: POCIError; const tdo: POCIType; const method_name: Poratext; const m_length: ub4; mdos: PPOCITypeMethod): sword; begin Result := OracleAPI.OCITypeMethodByName(env, err, tdo, method_name, m_length, mdos); end; function TZOracle9iPlainDriver.TypeMethodNext(env: POCIEnv; err: POCIError; iterator_ort: POCITypeIter; mdo: PPOCITypeMethod): sword; begin Result := OracleAPI.OCITypeMethodNext(env, err, iterator_ort, mdo); end; function TZOracle9iPlainDriver.TypeMethodName(env:POCIEnv; err: POCIError; const mdo: POCITypeMethod; n_length: Pub4): poratext; begin Result := OracleAPI.OCITypeMethodName(env, err, mdo, n_length); end; function TZOracle9iPlainDriver.TypeMethodEncap(env: POCIEnv; err: POCIError; const mdo: POCITypeMethod): OCITypeEncap; begin Result := OracleAPI.OCITypeMethodEncap(env, err, mdo); end; function TZOracle9iPlainDriver.TypeMethodFlags(env: POCIEnv; err: POCIError; const mdo:POCITypeMethod): OCITypeMethodFlag; begin Result := OracleAPI.OCITypeMethodFlags(env, err, mdo); end; function TZOracle9iPlainDriver.TypeMethodMap(env: POCIEnv; err: POCIError; const tdo: POCIType; mdo: PPOCITypeMethod): sword; begin Result := OracleAPI.OCITypeMethodMap(env, err, tdo, mdo); end; function TZOracle9iPlainDriver.TypeMethodOrder(env: POCIEnv; err: POCIError; const tdo: POCIType; mdo: PPOCITypeMethod): sword; begin Result := OracleAPI.OCITypeMethodOrder(env, err, tdo, mdo); end; function TZOracle9iPlainDriver.TypeMethodParams(env: POCIEnv; err: POCIError; const mdo: POCITypeMethod): ub4; begin Result := OracleAPI.OCITypeMethodParams(env, err, mdo); end; function TZOracle9iPlainDriver.TypeResult(env: POCIEnv; err: POCIError; const mdo: POCITypeMethod; elem: PPOCITypeElem): sword; begin Result := OracleAPI.OCITypeResult(env, err, mdo, elem); end; function TZOracle9iPlainDriver.TypeParamByPos(env: POCIEnv; err: POCIError; const mdo: POCITypeMethod; const position: ub4; elem: PPOCITypeElem): sword; begin Result := OracleAPI.OCITypeParamByPos(env, err, mdo, position, elem); end; function TZOracle9iPlainDriver.TypeParamByName(env: POCIEnv; err: POCIError; const mdo: POCITypeMethod; const name: Poratext; const n_length: ub4; elem:PPOCITypeElem): sword; begin Result := OracleAPI.OCITypeParamByName(env, err, mdo, name, n_length, elem); end; function TZOracle9iPlainDriver.TypeParamPos(env: POCIEnv; err: POCIError; const mdo: POCITypeMethod; const name: Poratext; const n_length: ub4; position: Pub4; elem: PPOCITypeElem): sword; begin Result := OracleAPI.OCITypeParamPos(env, err, mdo, name, n_length, position, elem); end; function TZOracle9iPlainDriver.TypeElemParamMode(env: POCIEnv; err: POCIError; const elem: POCITypeElem): OCITypeParamMode; begin Result := OracleAPI.OCITypeElemParamMode(env, err, elem); end; function TZOracle9iPlainDriver.TypeElemDefaultValue(env: POCIEnv; err: POCIError; const elem: POCITypeElem; d_v_length: Pub4): poratext; begin Result := OracleAPI.OCITypeElemDefaultValue(env, err, elem, d_v_length); end; function TZOracle9iPlainDriver.TypeVTInit(env: POCIEnv; err: POCIError): sword; begin Result := OracleAPI.OCITypeVTInit(env, err); end; function TZOracle9iPlainDriver.TypeVTInsert(env: POCIEnv; err: POCIError; const schema_name: Poratext; const s_n_length: ub4; const type_name: Poratext; const t_n_length: ub4; const user_version:Poratext; const u_v_length:ub4): sword; begin Result := OracleAPI.OCITypeVTInsert(env, err, schema_name, s_n_length, type_name, t_n_length, user_version, u_v_length); end; function TZOracle9iPlainDriver.TypeVTSelect(env: POCIEnv; err: POCIError; const schema_name: Poratext; const s_n_length: ub4; const type_name: Poratext; const t_n_length: ub4; user_version: PPoratext; u_v_length: Pub4; version: Pub2): sword; begin Result := OracleAPI.OCITypeVTSelect(env, err, schema_name, s_n_length, type_name, t_n_length, user_version, u_v_length, version); end; end. ================================================ FILE: lib/zeosdbo/src/plain/ZPlainPostgreSqlDriver.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Native Plain Drivers for PostgreSQL } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZPlainPostgreSqlDriver; interface {$I ZPlain.inc} uses ZClasses, ZCompatibility, ZPlainDriver; const WINDOWS_DLL_LOCATION = 'libpq.dll'; WINDOWS_DLL7_LOCATION = 'libpq74.dll'; WINDOWS_DLL8_LOCATION = 'libpq81.dll'; LINUX_DLL_LOCATION = 'libpq'+SharedSuffix; LINUX_DLL8_LOCATION = 'libpq'+SharedSuffix+'.4'; LINUX_DLL82_LOCATION = 'libpq'+SharedSuffix+'.5'; { Type Lengths } NAMEDATALEN = 32; { OIDNAMELEN should be set to NAMEDATALEN + sizeof(Oid) } OIDNAMELEN = 36; InvalidOid = 0; INV_WRITE = $00020000; INV_READ = $00040000; BLOB_SEEK_SET = 0; BLOB_SEEK_CUR = 1; BLOB_SEEK_END = 2; type { Application-visible enum types } TZPostgreSQLConnectStatusType = ( CONNECTION_OK, CONNECTION_BAD ); TZPostgreSQLFieldCode=( // FirmOS PG_DIAG_SEVERITY=ord('S'), PG_DIAG_SQLSTATE=ord('C'), PG_DIAG_MESSAGE_PRIMARY=ord('M'), PG_DIAG_MESSAGE_DETAIL=ord('D'), PG_DIAG_MESSAGE_HINT=ord('H'), PG_DIAG_STATEMENT_POSITION=ord('P'), PG_DIAG_INTERNAL_POSITION=ord('p'), PG_DIAG_INTERNAL_QUERY=ord('q'), PG_DIAG_CONTEXT=ord('W'), PG_DIAG_SOURCE_FILE=ord('F'), PG_DIAG_SOURCE_LINE=ord('L'), PG_DIAG_SOURCE_FUNCTION=ord('R') ); TZPostgreSQLExecStatusType = ( PGRES_EMPTY_QUERY, PGRES_COMMAND_OK, { a query command that doesn't return anything was executed properly by the backend } PGRES_TUPLES_OK, { a query command that returns tuples was executed properly by the backend, PGresult contains the result tuples } PGRES_COPY_OUT, { Copy Out data transfer in progress } PGRES_COPY_IN, { Copy In data transfer in progress } PGRES_BAD_RESPONSE, { an unexpected response was recv'd from the backend } PGRES_NONFATAL_ERROR, PGRES_FATAL_ERROR ); { PGnotify represents the occurrence of a NOTIFY message. Ideally this would be an opaque typedef, but it's so simple that it's unlikely to change. NOTE: in Postgres 6.4 and later, the be_pid is the notifying backend's, whereas in earlier versions it was always your own backend's PID. } TZPostgreSQLNotify = packed record relname: PAnsiChar; { name of relation containing data } be_pid: Integer; { process id of backend } payload: PAnsiChar; {additional data in notify} end; PZPostgreSQLNotify = ^TZPostgreSQLNotify; { PQnoticeProcessor is the function type for the notice-message callback. } TZPostgreSQLNoticeProcessor = procedure(arg: Pointer; message: PAnsiChar); cdecl; { Structure for the conninfo parameter definitions returned by PQconndefaults } TZPostgreSQLConnectInfoOption = packed record keyword: PAnsiChar; { The keyword of the option } envvar: PAnsiChar; { Fallback environment variable name } compiled: PAnsiChar; { Fallback compiled in default value } val: PAnsiChar; { Options value } lab: PAnsiChar; { Label for field in connect dialog } disPAnsiChar: PAnsiChar; { Character to display for this field in a connect dialog. Values are: "" Display entered value as is "*" Password field - hide value "D" Debug options - don't create a field by default } dispsize: Integer; { Field size in characters for dialog } end; PZPostgreSQLConnectInfoOption = ^TZPostgreSQLConnectInfoOption; { PQArgBlock -- structure for PQfn() arguments } TZPostgreSQLArgBlock = packed record len: Integer; isint: Integer; case u: Boolean of True: (ptr: PInteger); { can't use void (dec compiler barfs) } False: (_int: Integer); end; PZPostgreSQLArgBlock = ^TZPostgreSQLArgBlock; PZPostgreSQLConnect = Pointer; PZPostgreSQLResult = Pointer; PZPostgreSQLCancel = Pointer; POid = ^Oid; Oid = Integer; TZPgCharactersetType = ( csSQL_ASCII = 0, { SQL/ASCII } csEUC_JP, { EUC for Japanese } csEUC_CN, { EUC for Chinese } csEUC_KR, { EUC for Korean } csEUC_TW, { EUC for Taiwan } csEUC_JIS_2004, {Extended UNIX Code-JP, JIS X 0213 Japanese} csUTF8, { Unicode UTF-8 } csMULE_INTERNAL, { Mule internal code } csLATIN1, { ISO-8859 Latin 1 } csLATIN2, { ISO-8859 Latin 2 } csLATIN3, { ISO-8859 Latin 3 } csLATIN4, { ISO-8859 Latin 4 } csLATIN5, { ISO-8859 Latin 5 } csLATIN6, { ISO-8859 Latin 6 } csLATIN7, { ISO-8859 Latin 7 } csLATIN8, { ISO-8859 Latin 8 } csLATIN9, { ISO-8859 Latin 9 } csLATIN10, { ISO-8859 Latin 10 } csWIN1256, { Arabic Windows } csWIN1258, { Vietnamese Windows } csWIN866, { Alternativny Variant (MS-DOS CP866) } csWIN874, { Thai Windows } csKOI8, {KOI8-R(U) Cyrillic} csKOI8R, { KOI8-R Cyrillic (Russian) } csWIN1251, { windows-1251 } csWIN1252, {Windows CP1252 Western European} csISO_8859_5, { ISO-8859-5 } csISO_8859_6, { ISO-8859-6 } csISO_8859_7, { ISO-8859-7 } csISO_8859_8, { ISO-8859-8 } csWIN1250, { Windows CP1250 Central European } csWIN1253, { Windows CP1253 Greek } csWIN1254, { Windows CP1254 Turkish } csWIN1255, { Windows CP1255 Hebrew } csWIN1257, { Windows CP1257 Baltic } csKOI8U, { KOI8-R Cyrillic (Ukrainian) } csSJIS, { Shift JIS Japanese } csBIG5, { Big Five Traditional Chinese } csGBK, { Extended National Standard Simplified Chinese } csUHC, { Unified Hangul Code Korean } csGB18030, { National Standard Chinese } csJOHAB, {JOHAB Korean (Hangul)} csSHIFT_JIS_2004, {Shift JIS, JIS X 0213 Japanese} csUNICODE_PODBC,{ UNICODE ( < Ver8.1). Can't call it UNICODE as that's already used } csTCVN, { TCVN ( < Ver8.1) } csALT, { ALT ( < Var8.1) } csWIN, { WIN ( < Ver8.1) } csOTHER ); { ****************** Plain API Types definition ***************** } type { String descriptions of the ExecStatusTypes } pgresStatus = array[$00..$ff] of PAnsiChar; { PGconn encapsulates a connection to the backend. The contents of this struct are not supposed to be known to applications. } PGconn = Pointer; PPGconn = Pointer; { PGresult encapsulates the result of a query (or more precisely, of a single SQL command --- a query string given to PQsendQuery can contain multiple commands and thus return multiple PGresult objects). The contents of this struct are not supposed to be known to applications. } PGresult = Pointer; PPGresult = Pointer; PGCancel = Pointer; { PGnotify represents the occurrence of a NOTIFY message. Ideally this would be an opaque typedef, but it's so simple that it's unlikely to change. NOTE: in Postgres 6.4 and later, the be_pid is the notifying backend's, whereas in earlier versions it was always your own backend's PID. } PGnotify = packed record relname: array [0..NAMEDATALEN-1] of AnsiChar; { name of relation containing data } be_pid: Integer; { process id of backend } end; PPGnotify = ^PGnotify; { PQnoticeProcessor is the function type for the notice-message callback. } PQnoticeProcessor = procedure(arg: Pointer; message: PAnsiChar); cdecl; { Print options for PQprint() } { We can't use the conventional "bool", because we are designed to be included in a user's program, and user may already have that type defined. Pqbool, on the other hand, is unlikely to be used. } PPAnsiChar = array[00..$ff] of PAnsiChar; PQprintOpt = packed record header: Byte; { print output field headings and row count } align: Byte; { fill align the fields } standard: Byte; { old brain dead format } html3: Byte; { output html tables } expanded: Byte; { expand tables } pager: Byte; { use pager for output if needed } fieldSep: PAnsiChar; { field separator } tableOpt: PAnsiChar; { insert to HTML } caption: PAnsiChar; { HTML
} fieldName: PPAnsiChar; { null terminated array of repalcement field names } end; PPQprintOpt = ^PQprintOpt; { ---------------- Structure for the conninfo parameter definitions returned by PQconndefaults ---------------- } PQconninfoOption = packed record keyword: PAnsiChar; { The keyword of the option } envvar: PAnsiChar; { Fallback environment variable name } compiled: PAnsiChar; { Fallback compiled in default value } val: PAnsiChar; { Options value } lab: PAnsiChar; { Label for field in connect dialog } disPAnsiChar: PAnsiChar; { Character to display for this field in a connect dialog. Values are: "" Display entered value as is "*" Password field - hide value "D" Debug options - don't create a field by default } dispsize: Integer; { Field size in characters for dialog } end; PPQConninfoOption = ^PQconninfoOption; { ---------------- PQArgBlock -- structure for PQfn() arguments ---------------- } PQArgBlock = packed record len: Integer; isint: Integer; case u: Boolean of True: (ptr: PInteger); { can't use void (dec compiler barfs) } False: (_int: Integer); end; PPQArgBlock = ^PQArgBlock; {Prepared statement types} TPQparamTypes = {array of }POid; TPQparamValues = array of PAnsichar; TPQparamLengths = array of Integer; TPQparamFormats = array of Integer; { ************** Plain API Function types definition ************* } { === in fe-connect.c === } TPQconnectdb = function(ConnInfo: PAnsiChar): PPGconn; cdecl; // FirmOS 8.1 OK TPQsetdbLogin = function(Host, Port, Options, Tty, Db, User, Passwd: PAnsiChar): PPGconn; cdecl; // FirmOS 8.1 OK //15022006 FirmOS: omitting PQconnectStart //15022006 FirmOS: omitting PQconnectPoll TPQconndefaults = function: PPQconninfoOption; cdecl; TPQfinish = procedure(Handle: PPGconn); cdecl; TPQreset = procedure(Handle: PPGconn); cdecl; //15022006 FirmOS: omitting PQresetStart //15022006 FirmOS: omitting PQresetPoll TPQrequestCancel = function(Handle: PPGconn): Integer; cdecl; TPQdb = function(Handle: PPGconn): PAnsiChar; cdecl; TPQuser = function(Handle: PPGconn): PAnsiChar; cdecl; TPQpass = function(Handle: PPGconn): PAnsiChar; cdecl; TPQhost = function(Handle: PPGconn): PAnsiChar; cdecl; TPQport = function(Handle: PPGconn): PAnsiChar; cdecl; TPQtty = function(Handle: PPGconn): PAnsiChar; cdecl; TPQoptions = function(Handle: PPGconn): PAnsiChar; cdecl; TPQstatus = function(Handle: PPGconn): TZPostgreSQLConnectStatusType; cdecl; //TBD PGTransactionStatusType PQtransactionStatus(const PGconn *conn); //15022006 FirmOS: omitting const char *PQparameterStatus(const PGconn *conn, const char *paramName); //15022006 FirmOS: omitting PQprotocolVersion TPQserverVersion = function(Handle: PPGconn): Integer; cdecl; TPQerrorMessage = function(Handle: PPGconn): PAnsiChar; cdecl; TPQsocket = function(Handle: PPGconn): Integer; cdecl; TPQbackendPID = function(Handle: PPGconn): Integer; cdecl; //15022006 FirmOS: omitting SSL *PQgetssl(const PGconn *conn); TPQtrace = procedure(Handle: PPGconn; DebugPort: Pointer); cdecl; TPQuntrace = procedure(Handle: PPGconn); cdecl; TPQsetNoticeProcessor = procedure(Handle: PPGconn; Proc: PQnoticeProcessor; Arg: Pointer); cdecl; TPQclientEncoding = function(Handle: PPGconn): Integer; cdecl; //EgonHugeist { === in fe-exec.c === } //* Simple synchronous query */ TPQexec = function(Handle: PPGconn; Query: PAnsiChar): PPGresult; cdecl; TPQexecParams = function(Handle: PPGconn; command: PAnsichar; nParams: Integer; paramTypes: TPQparamTypes; paramValues: TPQparamValues; paramLengths: TPQparamLengths; paramFormats: TPQparamFormats; resultFormat: Integer): PPGresult; cdecl; TPQprepare = function(Handle: PPGconn; stmtName: PAnsichar; query: PAnsiChar; nParams: Integer; paramTypes: TPQparamTypes): PPGresult; cdecl; TPQexecPrepared = function(Handle: PPGconn; stmtName: PAnsichar; nParams: Integer; paramValues: TPQparamValues; paramLengths: TPQparamLengths; paramFormats: TPQparamFormats; resultFormat: Integer): PPGresult; cdecl; //* Interface for multiple-result or asynchronous queries */ TPQsendQuery = function(Handle: PPGconn; query: PAnsiChar): Integer; cdecl; TPQsendQueryParams= function(Handle: PPGconn; command: PAnsichar; nParams: Integer; paramTypes: TPQparamTypes; paramValues: TPQparamValues; paramLengths: TPQparamLengths; paramFormats: TPQparamFormats; resultFormat: Integer): Integer; cdecl; TPQsendPrepare = function(Handle: PPGconn; stmtName: PAnsichar; query: PAnsiChar; nParams: Integer; paramTypes: TPQparamTypes): Integer; cdecl; TPQsendQueryPrepared = function(Handle: PPGconn; stmtName: PAnsichar; nParams: Integer; paramValues: TPQparamValues; paramLengths: TPQparamLengths; paramFormats: TPQparamFormats; resultFormat: Integer): Integer; cdecl; TPQgetResult = function(Handle: PPGconn): PPGresult; cdecl; //* Describe prepared statements and portals */ TPQdescribePrepared = function(Handle: PPGconn; const stmt: PAnsiChar): PPGresult; cdecl; TPQdescribePortal = function(Handle: PPGconn; const portal: PAnsiChar): PPGresult; cdecl; TPQsendDescribePrepared = function(Handle: PPGconn; const stmt: PAnsiChar): Integer; cdecl; TPQsendDescribePortal = function(Handle: PPGconn; const portal: PAnsiChar): Integer; cdecl; TPQnotifies = function(Handle: PPGconn): PPGnotify; cdecl; TPQfreeNotify = procedure(Handle: PPGnotify);cdecl; TPQisBusy = function(Handle: PPGconn): Integer; cdecl; TPQconsumeInput = function(Handle: PPGconn): Integer; cdecl; TPQgetCancel = function(Handle: PPGconn): PGcancel; cdecl; TPQfreeCancel = procedure(Canc: PGcancel); cdecl; TPQcancel = function(Canc: PGcancel; Buffer: PChar; BufSize: Integer): Integer; TPQgetline = function(Handle: PPGconn; Str: PAnsiChar; length: Integer): Integer; cdecl; TPQputline = function(Handle: PPGconn; Str: PAnsiChar): Integer; cdecl; TPQgetlineAsync = function(Handle: PPGconn; Buffer: PAnsiChar; BufSize: Integer): Integer; cdecl; TPQputnbytes = function(Handle: PPGconn; Buffer: PAnsiChar; NBytes: Integer): Integer; cdecl; TPQendcopy = function(Handle: PPGconn): Integer; cdecl; TPQfn = function(Handle: PPGconn; fnid: Integer; result_buf, result_len: PInteger; result_is_int: Integer; args: PPQArgBlock; nargs: Integer): PPGresult; cdecl; TPQresultStatus = function(Result: PPGresult): TZPostgreSQLExecStatusType; cdecl; TPQresultErrorMessage = function(Result: PPGresult): PAnsiChar; cdecl; TPQresultErrorField=function(result: PPGResult; fieldcode:integer):PAnsiChar;cdecl; // postgresql 8 TPQntuples = function(Result: PPGresult): Integer; cdecl; TPQnfields = function(Result: PPGresult): Integer; cdecl; TPQbinaryTuples = function(Result: PPGresult): Integer; cdecl; TPQfname = function(Result: PPGresult; field_num: Integer): PAnsiChar; cdecl; TPQfnumber = function(Result: PPGresult; field_name: PAnsiChar): Integer; cdecl; TPQftable = function(Result: PPGresult; field_num: Integer): Oid; cdecl; TPQftablecol = function(Result: PPGresult; field_num: Integer): Integer; cdecl; TPQftype = function(Result: PPGresult; field_num: Integer): Oid; cdecl; TPQfsize = function(Result: PPGresult; field_num: Integer): Integer; cdecl; TPQfmod = function(Result: PPGresult; field_num: Integer): Integer; cdecl; TPQcmdStatus = function(Result: PPGresult): PAnsiChar; cdecl; TPQoidValue = function(Result: PPGresult): Oid; cdecl; TPQoidStatus = function(Result: PPGresult): PAnsiChar; cdecl; TPQcmdTuples = function(Result: PPGresult): PAnsiChar; cdecl; TPQgetvalue = function(Result: PPGresult; tup_num, field_num: Integer): PAnsiChar; cdecl; TPQgetlength = function(Result: PPGresult; tup_num, field_num: Integer): Integer; cdecl; TPQgetisnull = function(Result: PPGresult; tup_num, field_num: Integer): Integer; cdecl; TPQclear = procedure(Result: PPGresult); cdecl; TPQmakeEmptyPGresult = function(Handle: PPGconn; status: TZPostgreSQLExecStatusType): PPGresult; cdecl; //* Quoting strings before inclusion in queries. */ // postgresql 8 TPQescapeStringConn = function(Handle: PGconn; ToChar: PAnsiChar; const FromChar: PAnsiChar; length: NativeUInt; error: PInteger): NativeUInt;cdecl; //7.3 TPQescapeLiteral = function(Handle: PGconn; const str: PAnsiChar; len: NativeUInt): PAnsiChar;cdecl; TPQescapeIdentifier = function(Handle: PGconn; const str: PAnsiChar; len: NativeUInt): PAnsiChar;cdecl; //7.3 TPQescapeByteaConn = function(Handle: PPGconn;const from:PAnsiChar;from_length:longword;to_lenght:PLongword):PAnsiChar;cdecl; TPQunescapeBytea = function(const from:PAnsiChar;to_lenght:PLongword):PAnsiChar;cdecl; TPQFreemem = procedure(ptr:Pointer);cdecl; //* These forms are deprecated! */ TPQescapeString = function(ToChar: PAnsiChar; const FormChar: PAnsiChar; length: NativeUInt): NativeUInt;cdecl; //7.2 TPQescapeBytea = function(const from:PAnsiChar;from_length:longword;to_lenght:PLongword):PAnsiChar;cdecl; //7.2 { === in fe-lobj.c === } Tlo_open = function(Handle: PPGconn; lobjId: Oid; mode: Integer): Integer; cdecl; Tlo_close = function(Handle: PPGconn; fd: Integer): Integer; cdecl; Tlo_read = function(Handle: PPGconn; fd: Integer; buf: PAnsiChar; len: NativeUInt): Integer; cdecl; Tlo_write = function(Handle: PPGconn; fd: Integer; buf: PAnsiChar; len: NativeUInt): Integer; cdecl; Tlo_lseek = function(Handle: PPGconn; fd, offset, whence: Integer): Integer; cdecl; Tlo_creat = function(Handle: PPGconn; mode: Integer): Oid; cdecl; Tlo_tell = function(Handle: PPGconn; fd: Integer): Integer; cdecl; Tlo_unlink = function(Handle: PPGconn; lobjId: Oid): Integer; cdecl; Tlo_import = function(Handle: PPGconn; filename: PAnsiChar): Oid; cdecl; Tlo_export = function(Handle: PPGconn; lobjId: Oid; filename: PAnsiChar): Integer; cdecl; { ************** Collection of Plain API Function types definition ************* } TZPOSTGRESQL_API = record { === in fe-connect.c === } PQconnectdb: TPQconnectdb; PQsetdbLogin: TPQsetdbLogin; PQconndefaults: TPQconndefaults; PQfinish: TPQfinish; PQreset: TPQreset; PQrequestCancel: TPQrequestCancel; PQdb: TPQdb; PQuser: TPQuser; PQpass: TPQpass; PQhost: TPQhost; PQport: TPQport; PQtty: TPQtty; PQoptions: TPQoptions; PQstatus: TPQstatus; PQserverVersion: TPQserverVersion; PQerrorMessage: TPQerrorMessage; PQsocket: TPQsocket; PQbackendPID: TPQbackendPID; PQtrace: TPQtrace; PQuntrace: TPQuntrace; PQsetNoticeProcessor: TPQsetNoticeProcessor; PQclientEncoding: TPQclientEncoding; { === in fe-exec.c === } PQexec: TPQexec; PQexecParams: TPQexecParams; PQprepare: TPQprepare; PQexecPrepared: TPQexecPrepared; PQsendQuery: TPQsendQuery; PQsendQueryParams: TPQsendQueryParams; PQsendPrepare: TPQsendPrepare; PQsendQueryPrepared: TPQsendQueryPrepared; PQgetResult: TPQgetResult; //* Describe prepared statements and portals */ PQdescribePrepared: TPQdescribePrepared; PQdescribePortal: TPQdescribePortal; PQsendDescribePrepared: TPQsendDescribePrepared; PQsendDescribePortal: TPQsendDescribePortal; PQnotifies: TPQnotifies; PQfreeNotify: TPQfreeNotify; PQisBusy: TPQisBusy; PQconsumeInput: TPQconsumeInput; PQgetCancel: TPQgetCancel; PQfreeCancel: TPQfreeCancel; PQcancel: TPQcancel; PQgetline: TPQgetline; PQputline: TPQputline; PQgetlineAsync: TPQgetlineAsync; PQputnbytes: TPQputnbytes; PQendcopy: TPQendcopy; PQfn: TPQfn; PQresultStatus: TPQresultStatus; PQresultErrorMessage: TPQresultErrorMessage; PQresultErrorField: TPQresultErrorField; // postgresql 8 PQntuples: TPQntuples; PQnfields: TPQnfields; PQbinaryTuples: TPQbinaryTuples; PQfname: TPQfname; PQfnumber: TPQfnumber; PQftable: TPQftable; PQftablecol: TPQftablecol; PQftype: TPQftype; PQfsize: TPQfsize; PQfmod: TPQfmod; PQcmdStatus: TPQcmdStatus; PQoidValue: TPQoidValue; PQoidStatus: TPQoidStatus; PQcmdTuples: TPQcmdTuples; PQgetvalue: TPQgetvalue; PQgetlength: TPQgetlength; PQgetisnull: TPQgetisnull; PQclear: TPQclear; PQmakeEmptyPGresult: TPQmakeEmptyPGresult; PQescapeStringConn: TPQescapeStringConn; //since 7.3 PQescapeByteaConn: TPQescapeByteaConn; // postgresql since 7.3 PQFreemem: TPQFreemem; // since postgresql 7.4 PQescapeString: TPQescapeString; // since postgresql 7.4 PQescapeBytea: TPQescapeBytea; // since postgresql 7.4 PQunescapeBytea: TPQunescapeBytea; // since postgresql 8.3 PQescapeLiteral: TPQescapeLiteral; // since postgresql 9.0 PQescapeIdentifier: TPQescapeIdentifier; // since postgresql 9.0 { === in fe-lobj.c === } lo_open: Tlo_open; lo_close: Tlo_close; lo_read: Tlo_read; lo_write: Tlo_write; lo_lseek: Tlo_lseek; lo_creat: Tlo_creat; lo_tell: Tlo_tell; lo_unlink: Tlo_unlink; lo_import: Tlo_import; lo_export: Tlo_export; end; PAPI = ^TZPOSTGRESQL_API; type {** Represents a generic interface to PostgreSQL native API. } IZPostgreSQLPlainDriver = interface (IZPlainDriver) ['{03CD6345-2D7A-4FE2-B03D-3C5656789FEB}'] function GetStandardConformingStrings: Boolean; function EncodeBYTEA(const Value: RawByteString; Handle: PZPostgreSQLConnect; Quoted: Boolean = True): RawByteString; function DecodeBYTEA(const value: RawByteString; const Is_bytea_output_hex: Boolean; Handle: PZPostgreSQLConnect): RawByteString; function SupportsEncodeBYTEA: Boolean; function SupportsDecodeBYTEA(const Handle: PZPostgreSQLConnect): Boolean; function SupportsStringEscaping(const ClientDependend: Boolean): Boolean; function ConnectDatabase(ConnInfo: PAnsiChar): PZPostgreSQLConnect; function SetDatabaseLogin(Host, Port, Options, TTY, Db, User,Passwd: PAnsiChar): PZPostgreSQLConnect; function GetConnectDefaults: PZPostgreSQLConnectInfoOption; procedure Finish(Handle: PZPostgreSQLConnect); procedure Reset(Handle: PZPostgreSQLConnect); function RequestCancel(Handle: PZPostgreSQLConnect): Integer; function GetDatabase(Handle: PZPostgreSQLConnect): PAnsiChar; function GetUser(Handle: PZPostgreSQLConnect): PAnsiChar; function GetPassword(Handle: PZPostgreSQLConnect): PAnsiChar; function GetHost(Handle: PZPostgreSQLConnect): PAnsiChar; function GetPort(Handle: PZPostgreSQLConnect): PAnsiChar; function GetTTY(Handle: PZPostgreSQLConnect): PAnsiChar; function GetOptions(Handle: PZPostgreSQLConnect): PAnsiChar; function GetStatus(Handle: PZPostgreSQLConnect):TZPostgreSQLConnectStatusType; function GetClientEncoding(Handle: PPGconn): Integer; //EgonHugeist function GetErrorMessage(Handle: PZPostgreSQLConnect): PAnsiChar; function GetSocket(Handle: PZPostgreSQLConnect): Integer; function GetBackendPID(Handle: PZPostgreSQLConnect): Integer; procedure Trace(Handle: PZPostgreSQLConnect; DebugPort: Pointer); procedure Untrace(Handle: PZPostgreSQLConnect); procedure SetNoticeProcessor(Handle: PZPostgreSQLConnect;Proc: TZPostgreSQLNoticeProcessor; Arg: Pointer); function ExecuteQuery(Handle: PZPostgreSQLConnect;Query: PAnsiChar): PZPostgreSQLResult; function ExecParams(Handle: PPGconn; command: PAnsichar; nParams: Integer; paramTypes: TPQparamTypes; paramValues: TPQparamValues; paramLengths: TPQparamLengths; paramFormats: TPQparamFormats; resultFormat: Integer): PPGresult; function Prepare(Handle: PPGconn; stmtName: PAnsichar; query: PAnsiChar; nParams: Integer; paramTypes: TPQparamTypes): PPGresult; function ExecPrepared(Handle: PPGconn; stmtName: PAnsichar; nParams: Integer; paramValues: TPQparamValues; paramLengths: TPQparamLengths; paramFormats: TPQparamFormats; resultFormat: Integer): PPGresult; function SendQuery(Handle: PZPostgreSQLConnect; Query: PAnsiChar): Integer; function SendQueryParams(Handle: PPGconn; command: PAnsichar; nParams: Integer; paramTypes: TPQparamTypes; paramValues: TPQparamValues; paramLengths: TPQparamLengths; paramFormats: TPQparamFormats; resultFormat: Integer): Integer; function SendPrepare(Handle: PPGconn; stmtName: PAnsichar; query: PAnsiChar; nParams: Integer; paramTypes: TPQparamTypes): Integer; function SendQueryPrepared(Handle: PPGconn; stmtName: PAnsichar; nParams: Integer; paramValues: TPQparamValues; paramLengths: TPQparamLengths; paramFormats: TPQparamFormats; resultFormat: Integer): Integer; function GetResult(Handle: PZPostgreSQLConnect): PZPostgreSQLResult; //* Describe prepared statements and portals */ function DescribePrepared(Handle: PPGconn; const stmt: PAnsiChar): PPGresult; function DescribePortal(Handle: PPGconn; const portal: PAnsiChar): PPGresult; function SendDescribePrepared(Handle: PPGconn; const stmt: PAnsiChar): Integer; function SendDescribePortal(Handle: PPGconn; const portal: PAnsiChar): Integer; function Notifies(Handle: PZPostgreSQLConnect): PZPostgreSQLNotify; procedure FreeNotify(Handle: PZPostgreSQLNotify); function IsBusy(Handle: PZPostgreSQLConnect): Integer; function ConsumeInput(Handle: PZPostgreSQLConnect): Integer; function GetCancel(Handle: PZPostgreSQLConnect): PZPostgreSQLCancel; procedure FreeCancel( Canc: PZPostgreSQLCancel); function Cancel( Canc: PZPostgreSQLCancel; Buffer: PChar; Length: Integer): Integer; function GetLine(Handle: PZPostgreSQLConnect; Str: PAnsiChar; Length: Integer): Integer; function PutLine(Handle: PZPostgreSQLConnect; Str: PAnsiChar): Integer; function GetLineAsync(Handle: PZPostgreSQLConnect; Buffer: PAnsiChar; Length: Integer): Integer; function PutBytes(Handle: PZPostgreSQLConnect; Buffer: PAnsiChar; Length: Integer): Integer; function EndCopy(Handle: PZPostgreSQLConnect): Integer; function ExecuteFunction(Handle: PZPostgreSQLConnect; fnid: Integer; result_buf, result_len: PInteger; result_is_int: Integer; args: PZPostgreSQLArgBlock; nargs: Integer): PZPostgreSQLResult; function GetResultStatus(Res: PZPostgreSQLResult): TZPostgreSQLExecStatusType; function GetResultErrorMessage(Res: PZPostgreSQLResult): PAnsiChar; function GetResultErrorField(Res: PZPostgreSQLResult; FieldCode: TZPostgreSQLFieldCode): PAnsiChar; function GetRowCount(Res: PZPostgreSQLResult): Integer; function GetFieldCount(Res: PZPostgreSQLResult): Integer; function GetBinaryTuples(Res: PZPostgreSQLResult): Integer; function GetFieldName(Res: PZPostgreSQLResult; FieldNum: Integer): PAnsiChar; function GetFieldNumber(Res: PZPostgreSQLResult; FieldName: PAnsiChar): Integer; function GetFieldTableOID(Res: PZPostgreSQLResult; FieldNum: Integer) : Oid; function GetFieldTableColIdx(Res: PZPostgreSQLResult; FieldNum: Integer) : Integer; function GetFieldType(Res: PZPostgreSQLResult; FieldNum: Integer): Oid; function GetFieldSize(Res: PZPostgreSQLResult; FieldNum: Integer): Integer; function GetFieldMode(Res: PZPostgreSQLResult; FieldNum: Integer): Integer; function GetCommandStatus(Res: PZPostgreSQLResult): PAnsiChar; function GetOidValue(Res: PZPostgreSQLResult): Oid; function GetOidStatus(Res: PZPostgreSQLResult): PAnsiChar; function GetCommandTuples(Res: PZPostgreSQLResult): PAnsiChar; function GetValue(Res: PZPostgreSQLResult; TupNum, FieldNum: Integer): PAnsiChar; function GetLength(Res: PZPostgreSQLResult; TupNum, FieldNum: Integer): Integer; function GetIsNull(Res: PZPostgreSQLResult; TupNum, FieldNum: Integer): Integer; procedure Clear(Res: PZPostgreSQLResult); function MakeEmptyResult(Handle: PZPostgreSQLConnect; Status: TZPostgreSQLExecStatusType): PZPostgreSQLResult; function OpenLargeObject(Handle: PZPostgreSQLConnect; ObjId: Oid; Mode: Integer): Integer; function CloseLargeObject(Handle: PZPostgreSQLConnect; Fd: Integer): Integer; function ReadLargeObject(Handle: PZPostgreSQLConnect; Fd: Integer; Buffer: PAnsiChar; Length: Integer): Integer; function WriteLargeObject(Handle: PZPostgreSQLConnect; Fd: Integer; Buffer: PAnsiChar; Length: Integer): Integer; function SeekLargeObject(Handle: PZPostgreSQLConnect; Fd, Offset, Whence: Integer): Integer; function CreateLargeObject(Handle: PZPostgreSQLConnect; Mode: Integer): Oid; function TellLargeObject(Handle: PZPostgreSQLConnect; Fd: Integer): Integer; function UnlinkLargeObject(Handle: PZPostgreSQLConnect; ObjId: Oid): Integer; function ImportLargeObject(Handle: PZPostgreSQLConnect; FileName: PAnsiChar): Oid; function ExportLargeObject(Handle: PZPostgreSQLConnect; ObjId: Oid; FileName: PAnsiChar): Integer; function GetPlainFunc:PAPI; end; {** Implements a base driver for PostgreSQL} TZPostgreSQLBaseDriver = class(TZAbstractPlainDriver, IZPostgreSQLPlainDriver) protected POSTGRESQL_API: TZPOSTGRESQL_API; function GetStandardConformingStrings: Boolean; virtual; function GetUnicodeCodePageName: String; override; procedure LoadCodePages; override; procedure LoadApi; override; public constructor Create; function EncodeBYTEA(const Value: RawByteString; Handle: PZPostgreSQLConnect; Quoted: Boolean = True): RawByteString; function DecodeBYTEA(const value: RawByteString; const Is_bytea_output_hex: Boolean; Handle: PZPostgreSQLConnect): RawByteString; function SupportsEncodeBYTEA: Boolean; function SupportsDecodeBYTEA(const Handle: PZPostgreSQLConnect): Boolean; function SupportsStringEscaping(const ClientDependend: Boolean): Boolean; function ConnectDatabase(ConnInfo: PAnsiChar): PZPostgreSQLConnect; function SetDatabaseLogin(Host, Port, Options, TTY, Db, User, Passwd: PAnsiChar): PZPostgreSQLConnect; function GetConnectDefaults: PZPostgreSQLConnectInfoOption; procedure Finish(Handle: PZPostgreSQLConnect); procedure Reset(Handle: PZPostgreSQLConnect); function RequestCancel(Handle: PZPostgreSQLConnect): Integer; function GetDatabase(Handle: PZPostgreSQLConnect): PAnsiChar; function GetUser(Handle: PZPostgreSQLConnect): PAnsiChar; function GetPassword(Handle: PZPostgreSQLConnect): PAnsiChar; function GetHost(Handle: PZPostgreSQLConnect): PAnsiChar; function GetPort(Handle: PZPostgreSQLConnect): PAnsiChar; function GetTTY(Handle: PZPostgreSQLConnect): PAnsiChar; function GetOptions(Handle: PZPostgreSQLConnect): PAnsiChar; function GetStatus(Handle: PZPostgreSQLConnect): TZPostgreSQLConnectStatusType; function GetClientEncoding(Handle: PPGconn): Integer; //EgonHugeist function GetErrorMessage(Handle: PZPostgreSQLConnect): PAnsiChar; function GetSocket(Handle: PZPostgreSQLConnect): Integer; function GetBackendPID(Handle: PZPostgreSQLConnect): Integer; procedure Trace(Handle: PZPostgreSQLConnect; DebugPort: Pointer); procedure Untrace(Handle: PZPostgreSQLConnect); procedure SetNoticeProcessor(Handle: PZPostgreSQLConnect; Proc: TZPostgreSQLNoticeProcessor; Arg: Pointer); function ExecuteQuery(Handle: PZPostgreSQLConnect; Query: PAnsiChar): PZPostgreSQLResult; function ExecParams(Handle: PPGconn; command: PAnsichar; nParams: Integer; paramTypes: TPQparamTypes; paramValues: TPQparamValues; paramLengths: TPQparamLengths; paramFormats: TPQparamFormats; resultFormat: Integer): PPGresult; function Prepare(Handle: PPGconn; stmtName: PAnsichar; query: PAnsiChar; nParams: Integer; paramTypes: TPQparamTypes): PPGresult; function ExecPrepared(Handle: PPGconn; stmtName: PAnsichar; nParams: Integer; paramValues: TPQparamValues; paramLengths: TPQparamLengths; paramFormats: TPQparamFormats; resultFormat: Integer): PPGresult; function SendQuery(Handle: PZPostgreSQLConnect; Query: PAnsiChar): Integer; function SendQueryParams(Handle: PPGconn; command: PAnsichar; nParams: Integer; paramTypes: TPQparamTypes; paramValues: TPQparamValues; paramLengths: TPQparamLengths; paramFormats: TPQparamFormats; resultFormat: Integer): Integer; function SendPrepare(Handle: PPGconn; stmtName: PAnsichar; query: PAnsiChar; nParams: Integer; paramTypes: TPQparamTypes): Integer; function SendQueryPrepared(Handle: PPGconn; stmtName: PAnsichar; nParams: Integer; paramValues: TPQparamValues; paramLengths: TPQparamLengths; paramFormats: TPQparamFormats; resultFormat: Integer): Integer; function GetResult(Handle: PZPostgreSQLConnect): PZPostgreSQLResult; function DescribePrepared(Handle: PPGconn; const stmt: PAnsiChar): PPGresult; function DescribePortal(Handle: PPGconn; const portal: PAnsiChar): PPGresult; function SendDescribePrepared(Handle: PPGconn; const stmt: PAnsiChar): Integer; function SendDescribePortal(Handle: PPGconn; const portal: PAnsiChar): Integer; function Notifies(Handle: PZPostgreSQLConnect): PZPostgreSQLNotify; procedure FreeNotify(Handle: PZPostgreSQLNotify); function IsBusy(Handle: PZPostgreSQLConnect): Integer; function ConsumeInput(Handle: PZPostgreSQLConnect): Integer; function GetCancel(Handle: PZPostgreSQLConnect): PZPostgreSQLCancel; procedure FreeCancel( Canc: PZPostgreSQLCancel); function Cancel( Canc: PZPostgreSQLCancel; Buffer: PChar; Length: Integer): Integer; function GetLine(Handle: PZPostgreSQLConnect; Buffer: PAnsiChar; Length: Integer): Integer; function PutLine(Handle: PZPostgreSQLConnect; Buffer: PAnsiChar): Integer; function GetLineAsync(Handle: PZPostgreSQLConnect; Buffer: PAnsiChar; Length: Integer): Integer; function PutBytes(Handle: PZPostgreSQLConnect; Buffer: PAnsiChar; Length: Integer): Integer; function EndCopy(Handle: PZPostgreSQLConnect): Integer; function ExecuteFunction(Handle: PZPostgreSQLConnect; fnid: Integer; result_buf, result_len: PInteger; result_is_int: Integer; args: PZPostgreSQLArgBlock; nargs: Integer): PZPostgreSQLResult; function GetResultStatus(Res: PZPostgreSQLResult): TZPostgreSQLExecStatusType; function GetResultErrorMessage(Res: PZPostgreSQLResult): PAnsiChar; function GetResultErrorField(Res: PZPostgreSQLResult;FieldCode:TZPostgreSQLFieldCode):PAnsiChar; function GetRowCount(Res: PZPostgreSQLResult): Integer; function GetFieldCount(Res: PZPostgreSQLResult): Integer; function GetBinaryTuples(Res: PZPostgreSQLResult): Integer; function GetFieldName(Res: PZPostgreSQLResult; FieldNum: Integer): PAnsiChar; function GetFieldNumber(Res: PZPostgreSQLResult; FieldName: PAnsiChar): Integer; function GetFieldTableOID(Res: PZPostgreSQLResult; FieldNum: Integer) : Oid; function GetFieldTableColIdx(Res: PZPostgreSQLResult; FieldNum: Integer) : Integer; function GetFieldType(Res: PZPostgreSQLResult; FieldNum: Integer): Oid; function GetFieldSize(Res: PZPostgreSQLResult; FieldNum: Integer): Integer; function GetFieldMode(Res: PZPostgreSQLResult; FieldNum: Integer): Integer; function GetCommandStatus(Res: PZPostgreSQLResult): PAnsiChar; function GetOidValue(Res: PZPostgreSQLResult): Oid; function GetOidStatus(Res: PZPostgreSQLResult): PAnsiChar; function GetCommandTuples(Res: PZPostgreSQLResult): PAnsiChar; function GetValue(Res: PZPostgreSQLResult; TupNum, FieldNum: Integer): PAnsiChar; function GetLength(Res: PZPostgreSQLResult; TupNum, FieldNum: Integer): Integer; function GetIsNull(Res: PZPostgreSQLResult; TupNum, FieldNum: Integer): Integer; procedure Clear(Res: PZPostgreSQLResult); function MakeEmptyResult(Handle: PZPostgreSQLConnect; Status: TZPostgreSQLExecStatusType): PZPostgreSQLResult; function OpenLargeObject(Handle: PZPostgreSQLConnect; ObjId: Oid; Mode: Integer): Integer; function CloseLargeObject(Handle: PZPostgreSQLConnect; Fd: Integer): Integer; function ReadLargeObject(Handle: PZPostgreSQLConnect; Fd: Integer; Buffer: PAnsiChar; Length: Integer): Integer; function WriteLargeObject(Handle: PZPostgreSQLConnect; Fd: Integer; Buffer: PAnsiChar; Length: Integer): Integer; function SeekLargeObject(Handle: PZPostgreSQLConnect; Fd, Offset, Whence: Integer): Integer; function CreateLargeObject(Handle: PZPostgreSQLConnect; Mode: Integer): Oid; function TellLargeObject(Handle: PZPostgreSQLConnect; Fd: Integer): Integer; function UnlinkLargeObject(Handle: PZPostgreSQLConnect; ObjId: Oid): Integer; function ImportLargeObject(Handle: PZPostgreSQLConnect; FileName: PAnsiChar): Oid; function ExportLargeObject(Handle: PZPostgreSQLConnect; ObjId: Oid; FileName: PAnsiChar): Integer; function GetPlainFunc:PAPI; function EscapeString(Handle: Pointer; const Value: RawByteString; ConSettings: PZConSettings; WasEncoded: Boolean = False): RawByteString; override; end; {** Implements a driver for PostgreSQL 7.4 } TZPostgreSQL7PlainDriver = class(TZPostgreSQLBaseDriver, IZPlainDriver, IZPostgreSQLPlainDriver) protected function Clone: IZPlainDriver; override; public constructor Create; function GetProtocol: string; override; function GetDescription: string; override; end; {** Implements a driver for PostgreSQL 8.1 } { TZPostgreSQL8PlainDriver } TZPostgreSQL8PlainDriver = class(TZPostgreSQLBaseDriver, IZPlainDriver,IZPostgreSQLPlainDriver) protected function Clone: IZPlainDriver; override; function GetUnicodeCodePageName: String; override; procedure LoadCodePages; override; public constructor Create; function GetProtocol: string; override; function GetDescription: string; override; end; { TZPostgreSQL8PlainDriver } TZPostgreSQL9PlainDriver = class(TZPostgreSQL8PlainDriver) protected function Clone: IZPlainDriver; override; function GetStandardConformingStrings: Boolean; override; procedure LoadCodePages; override; public constructor Create; function GetProtocol: string; override; function GetDescription: string; override; end; implementation uses SysUtils, ZPlainLoader, Classes, ZEncoding {$IFDEF WITH_UNITANSISTRINGS}, AnsiStrings{$ENDIF}; { TZPostgreSQLBaseDriver } function TZPostgreSQLBaseDriver.GetUnicodeCodePageName: String; begin Result := 'UNICODE'; end; procedure TZPostgreSQLBaseDriver.LoadCodePages; begin { MultiByte } AddCodePage('EUC_JP', Ord(csEUC_JP), ceAnsi, zCP_EUC_JP, '', 3); { EUC_JP Japanese EUC } AddCodePage('EUC_CN', Ord(csEUC_CN), ceAnsi, zCP_EUC_CN, '', 3); {EUC_CN Chinese EUC} AddCodePage('EUC_KR', Ord(csEUC_KR), ceAnsi, zCP_euc_kr, '', 3); {Extended UNIX Code-KR Korean} AddCodePage('JOHAB', Ord(csJOHAB), ceAnsi, ZCP_JOHAB, '', 3); {JOHAB Korean (Hangul)} AddCodePage('EUC_TW', Ord(csEUC_TW), ceAnsi, $ffff, '', 3); {Extended UNIX Code-TW Traditional Chinese, Taiwanese} AddCodePage('UNICODE', Ord(csUNICODE_PODBC), ceUTF8, zCP_UTF8, '', 4); {UNICODE Unicode (UTF-8)} AddCodePage('MULE_INTERNAL', Ord(csMULE_INTERNAL), ceAnsi, $ffff, '', 4); { Mule internal code Multilingual Emacs } {SingleByte} AddCodePage('SQL_ASCII', Ord(csSQL_ASCII), ceAnsi, zCP_us_ascii); {unspecified (see text) any} AddCodePage('LATIN1', Ord(csLATIN1), ceAnsi, zCP_WIN1252); { ISO 8859-1, ECMA 94 Western European } AddCodePage('LATIN2', Ord(csLATIN2), ceAnsi, zCP_L2_ISO_8859_2); { ISO 8859-2, ECMA 94 Central European } AddCodePage('LATIN3', Ord(csLATIN3), ceAnsi, zCP_L3_ISO_8859_3); { ISO 8859-3, ECMA 94 South European } AddCodePage('LATIN4', Ord(csLATIN4), ceAnsi, zCP_L4_ISO_8859_4); { ISO 8859-4, ECMA 94 North European } AddCodePage('LATIN5', Ord(csLATIN5), ceAnsi, zCP_L5_ISO_8859_9); { ISO 8859-9, ECMA 128 Turkish } AddCodePage('LATIN6', Ord(csLATIN6), ceAnsi, zCP_L6_ISO_8859_10); { ISO 8859-10, ECMA 144 Nordic } AddCodePage('LATIN7', Ord(csLATIN7), ceAnsi, zCP_L7_ISO_8859_13); { ISO 8859-13 Baltic } AddCodePage('LATIN8', Ord(csLATIN8), ceAnsi, zCP_L8_ISO_8859_14); { ISO 8859-14 Celtic } AddCodePage('LATIN9', Ord(csLATIN9), ceAnsi, zCP_L9_ISO_8859_15); { ISO 8859-15 LATIN1 with Euro and accents } AddCodePage('LATIN10', Ord(csLATIN10), ceAnsi, zCP_L10_ISO_8859_16); { ISO 8859-16, ASRO SR 14111 Romanian } AddCodePage('ISO_8859_5', Ord(csISO_8859_5), ceAnsi, zCP_L5_ISO_8859_5); { ISO 8859-5, ECMA 113 Latin/Cyrillic} AddCodePage('ISO_8859_6', Ord(csISO_8859_6), ceAnsi, zCP_L6_ISO_8859_6); { ISO 8859-6, ECMA 114 Latin/Arabic } AddCodePage('ISO_8859_7', Ord(csISO_8859_7), ceAnsi, zCP_L7_ISO_8859_7); { ISO 8859-7, ECMA 118 Latin/Greek } AddCodePage('ISO_8859_8', Ord(csISO_8859_8), ceAnsi, zCP_L8_ISO_8859_8); { ISO 8859-8, ECMA 121 Latin/Hebrew } AddCodePage('KOI8', Ord(csKOI8), ceAnsi, zCP_KOI8R); { KOI8-R(U) Cyrillic } AddCodePage('WIN', Ord(csWIN), ceAnsi, zCP_WIN1251); { Windows CP1251 } AddCodePage('ALT', Ord(csALT), ceAnsi, zCP_DOS866); { Windows CP866 } AddCodePage('WIN1256', Ord(csWIN1256), ceAnsi, cCP_WIN1256); { Windows CP1256 Arabic } AddCodePage('TCVN', Ord(csTCVN), ceAnsi, zCP_WIN1258); { TCVN-5712/Windows CP1258 (Vietnamese) } AddCodePage('WIN874', Ord(csWIN874), ceAnsi, zCP_DOS874); { Windows CP874 (Thai) } end; procedure TZPostgreSQLBaseDriver.LoadApi; begin { ************** Load adresses of API Functions ************* } with Loader do begin { === in fe-connect.c === } @POSTGRESQL_API.PQconnectdb := GetAddress('PQconnectdb'); @POSTGRESQL_API.PQsetdbLogin := GetAddress('PQsetdbLogin'); @POSTGRESQL_API.PQconndefaults := GetAddress('PQconndefaults'); @POSTGRESQL_API.PQfinish := GetAddress('PQfinish'); @POSTGRESQL_API.PQreset := GetAddress('PQreset'); @POSTGRESQL_API.PQrequestCancel := GetAddress('PQrequestCancel'); @POSTGRESQL_API.PQdb := GetAddress('PQdb'); @POSTGRESQL_API.PQuser := GetAddress('PQuser'); @POSTGRESQL_API.PQpass := GetAddress('PQpass'); @POSTGRESQL_API.PQhost := GetAddress('PQhost'); @POSTGRESQL_API.PQport := GetAddress('PQport'); @POSTGRESQL_API.PQtty := GetAddress('PQtty'); @POSTGRESQL_API.PQoptions := GetAddress('PQoptions'); @POSTGRESQL_API.PQstatus := GetAddress('PQstatus'); @POSTGRESQL_API.PQserverVersion:= GetAddress('PQserverVersion'); @POSTGRESQL_API.PQerrorMessage := GetAddress('PQerrorMessage'); @POSTGRESQL_API.PQsocket := GetAddress('PQsocket'); @POSTGRESQL_API.PQbackendPID := GetAddress('PQbackendPID'); @POSTGRESQL_API.PQtrace := GetAddress('PQtrace'); @POSTGRESQL_API.PQuntrace := GetAddress('PQuntrace'); @POSTGRESQL_API.PQsetNoticeProcessor := GetAddress('PQsetNoticeProcessor'); @POSTGRESQL_API.PQclientEncoding := GetAddress('PQclientEncoding'); { === in fe-exec.c === } @POSTGRESQL_API.PQexec := GetAddress('PQexec'); @POSTGRESQL_API.PQexecParams := GetAddress('PQexecParams'); @POSTGRESQL_API.PQprepare := GetAddress('PQprepare'); @POSTGRESQL_API.PQexecPrepared := GetAddress('PQexecPrepared'); @POSTGRESQL_API.PQsendQuery := GetAddress('PQsendQuery'); @POSTGRESQL_API.PQsendQueryParams:= GetAddress('PQsendQueryParams'); @POSTGRESQL_API.PQsendPrepare := GetAddress('PQsendPrepare'); @POSTGRESQL_API.PQsendQueryPrepared := GetAddress('PQsendQueryPrepared'); @POSTGRESQL_API.PQgetResult := GetAddress('PQgetResult'); @POSTGRESQL_API.PQnotifies := GetAddress('PQnotifies'); @POSTGRESQL_API.PQfreeNotify := GetAddress('PQfreeNotify'); @POSTGRESQL_API.PQisBusy := GetAddress('PQisBusy'); @POSTGRESQL_API.PQconsumeInput := GetAddress('PQconsumeInput'); @POSTGRESQL_API.PQgetline := GetAddress('PQgetline'); @POSTGRESQL_API.PQputline := GetAddress('PQputline'); @POSTGRESQL_API.PQgetlineAsync := GetAddress('PQgetlineAsync'); @POSTGRESQL_API.PQputnbytes := GetAddress('PQputnbytes'); @POSTGRESQL_API.PQendcopy := GetAddress('PQendcopy'); @POSTGRESQL_API.PQfn := GetAddress('PQfn'); @POSTGRESQL_API.PQresultStatus := GetAddress('PQresultStatus'); @POSTGRESQL_API.PQresultErrorMessage := GetAddress('PQresultErrorMessage'); @POSTGRESQL_API.PQntuples := GetAddress('PQntuples'); @POSTGRESQL_API.PQnfields := GetAddress('PQnfields'); @POSTGRESQL_API.PQbinaryTuples := GetAddress('PQbinaryTuples'); @POSTGRESQL_API.PQfname := GetAddress('PQfname'); @POSTGRESQL_API.PQfnumber := GetAddress('PQfnumber'); @POSTGRESQL_API.PQftable := GetAddress('PQftable'); @POSTGRESQL_API.PQftablecol := GetAddress('PQftablecol'); @POSTGRESQL_API.PQftype := GetAddress('PQftype'); @POSTGRESQL_API.PQfsize := GetAddress('PQfsize'); @POSTGRESQL_API.PQfmod := GetAddress('PQfmod'); @POSTGRESQL_API.PQcmdStatus := GetAddress('PQcmdStatus'); @POSTGRESQL_API.PQoidValue := GetAddress('PQoidValue'); @POSTGRESQL_API.PQoidStatus := GetAddress('PQoidStatus'); @POSTGRESQL_API.PQcmdTuples := GetAddress('PQcmdTuples'); @POSTGRESQL_API.PQgetvalue := GetAddress('PQgetvalue'); @POSTGRESQL_API.PQgetlength := GetAddress('PQgetlength'); @POSTGRESQL_API.PQgetisnull := GetAddress('PQgetisnull'); @POSTGRESQL_API.PQclear := GetAddress('PQclear'); @POSTGRESQL_API.PQmakeEmptyPGresult := GetAddress('PQmakeEmptyPGresult'); { === in fe-lobj.c === } @POSTGRESQL_API.lo_open := GetAddress('lo_open'); @POSTGRESQL_API.lo_close := GetAddress('lo_close'); @POSTGRESQL_API.lo_read := GetAddress('lo_read'); @POSTGRESQL_API.lo_write := GetAddress('lo_write'); @POSTGRESQL_API.lo_lseek := GetAddress('lo_lseek'); @POSTGRESQL_API.lo_creat := GetAddress('lo_creat'); @POSTGRESQL_API.lo_tell := GetAddress('lo_tell'); @POSTGRESQL_API.lo_unlink := GetAddress('lo_unlink'); @POSTGRESQL_API.lo_import := GetAddress('lo_import'); @POSTGRESQL_API.lo_export := GetAddress('lo_export'); @POSTGRESQL_API.PQescapeStringConn := GetAddress('PQescapeStringConn'); //since 7.3 @POSTGRESQL_API.PQescapeByteaConn := GetAddress('PQescapeByteaConn'); // postgresql since 7.3 @POSTGRESQL_API.PQFreemem := GetAddress('PQfreemem'); // since postgresql 7.4 @POSTGRESQL_API.PQescapeString := GetAddress('PQescapeString'); // since postgresql 7.4 @POSTGRESQL_API.PQescapeBytea := GetAddress('PQescapeBytea'); // since postgresql 7.4 @POSTGRESQL_API.PQunescapeBytea := GetAddress('PQunescapeBytea'); // since postgresql 8.3 @POSTGRESQL_API.PQescapeLiteral := GetAddress('PQescapeLiteral'); // since postgresql 9.0 @POSTGRESQL_API.PQescapeIdentifier := GetAddress('PQescapeIdentifier'); // since postgresql 9.0 @POSTGRESQL_API.PQresultErrorField := GetAddress('PQresultErrorField'); @POSTGRESQL_API.PQgetCancel := GetAddress('PQgetCancel'); @POSTGRESQL_API.PQfreeCancel := GetAddress('PQfreeCancel'); @POSTGRESQL_API.PQcancel := GetAddress('PQcancel'); end; end; constructor TZPostgreSQLBaseDriver.Create; begin inherited create; FLoader := TZNativeLibraryLoader.Create([]); {$IFNDEF STRICT_DLL_LOADING} {$IFNDEF UNIX} FLoader.AddLocation(WINDOWS_DLL_LOCATION); {$ELSE} FLoader.AddLocation(LINUX_DLL_LOCATION); {$ENDIF} {$ENDIF} LoadCodePages; end; procedure TZPostgreSQLBaseDriver.Clear(Res: PZPostgreSQLResult); begin POSTGRESQL_API.PQclear(Res); end; function TZPostgreSQLBaseDriver.CloseLargeObject( Handle: PZPostgreSQLConnect; Fd: Integer): Integer; begin Result := POSTGRESQL_API.lo_close(Handle, Fd); end; function TZPostgreSQLBaseDriver.ConnectDatabase( ConnInfo: PAnsiChar): PZPostgreSQLConnect; begin Result := POSTGRESQL_API.PQconnectdb(ConnInfo); end; function TZPostgreSQLBaseDriver.ConsumeInput( Handle: PZPostgreSQLConnect): Integer; begin Result := POSTGRESQL_API.PQconsumeInput(Handle); end; function TZPostgreSQLBaseDriver.GetCancel(Handle: PZPostgreSQLConnect): PZPostgreSQLCancel; begin if Assigned(POSTGRESQL_API.PQgetCancel) then Result := POSTGRESQL_API.PQgetCancel(Handle) else Result := nil; end; procedure TZPostgreSQLBaseDriver.FreeCancel(Canc: PZPostgreSQLCancel); begin if Assigned(POSTGRESQL_API.PQfreeCancel) then POSTGRESQL_API.PQfreeCancel( Canc); end; function TZPostgreSQLBaseDriver.Cancel(Canc: PZPostgreSQLCancel; Buffer: PChar; Length: Integer): Integer; begin if Assigned(POSTGRESQL_API.PQcancel) then Result := POSTGRESQL_API.PQcancel( Canc, Buffer, Length) else Result := 0; end; function TZPostgreSQLBaseDriver.CreateLargeObject( Handle: PZPostgreSQLConnect; Mode: Integer): Oid; begin Result := POSTGRESQL_API.lo_creat(Handle, Mode); end; function TZPostgreSQLBaseDriver.DecodeBYTEA(const value: RawByteString; const Is_bytea_output_hex: Boolean; Handle: PZPostgreSQLConnect): RawByteString; var decoded: PAnsiChar; Ansi: AnsiString; len: Longword; begin if ( Is_bytea_output_hex ) then begin Len := (Length(value)-{$IFDEF WITH_UNITANSISTRINGS}AnsiStrings.AnsiPos{$ELSE}Pos{$ENDIF}('x', value)) div 2; //GetLength of binary result Ansi := AnsiString(Copy(value, {$IFDEF WITH_UNITANSISTRINGS}AnsiStrings.AnsiPos{$ELSE}Pos{$ENDIF}('x', value)+1, Length(value))); //remove the first 'x'sign-byte SetLength(Result, Len); //Set length of binary-result HexToBin(PAnsiChar(Ansi), PAnsichar(Result), Len); //convert hex to binary end else if Assigned(POSTGRESQL_API.PQUnescapeBytea) then begin decoded := POSTGRESQL_API.PQUnescapeBytea(PAnsiChar(value), @len); SetLength(result, len); if (len > 0) then Move(decoded^, result[1], len); if Assigned(POSTGRESQL_API.PQFreemem) then POSTGRESQL_API.PQFreemem(decoded); end else Result := Value; end; function TZPostgreSQLBaseDriver.SupportsEncodeBYTEA: Boolean; begin Result := Assigned(POSTGRESQL_API.PQescapeByteaConn) or Assigned(POSTGRESQL_API.PQescapeBytea); end; function TZPostgreSQLBaseDriver.SupportsDecodeBYTEA(const Handle: PZPostgreSQLConnect): Boolean; begin Result := ( POSTGRESQL_API.PQserverVersion(Handle) div 10000 >= 9 ) or Assigned(POSTGRESQL_API.PQUnescapeBytea); end; function TZPostgreSQLBaseDriver.SupportsStringEscaping(const ClientDependend: Boolean): Boolean; begin if ClientDependend then Result := Assigned(POSTGRESQL_API.PQescapeStringConn) else Result := Assigned(POSTGRESQL_API.PQescapeStringConn) or Assigned(POSTGRESQL_API.PQescapeString); end; function TZPostgreSQLBaseDriver.EncodeBYTEA(const Value: RawByteString; Handle: PZPostgreSQLConnect; Quoted: Boolean = True): RawByteString; var encoded: PAnsiChar; len: Longword; leng: cardinal; begin if assigned(POSTGRESQL_API.PQescapeByteaConn) or Assigned(POSTGRESQL_API.PQescapeBytea) then begin leng := Length(Value); if assigned(POSTGRESQL_API.PQescapeByteaConn) then encoded := POSTGRESQL_API.PQescapeByteaConn(Handle, PAnsiChar(value), leng, @len) else encoded := POSTGRESQL_API.PQescapeBytea(PAnsiChar(value),leng,@len); SetLength(result, len -1); //removes the #0 byte {$IFDEF WITH_STRLCOPY_DEPRECATED}AnsiStrings.{$ENDIF}StrLCopy(PAnsiChar(result), encoded, len - 1); POSTGRESQL_API.PQFreemem(encoded); if Quoted then result := ''''+result+''''; end else Result := Value; end; function TZPostgreSQLBaseDriver.EndCopy( Handle: PZPostgreSQLConnect): Integer; begin Result := POSTGRESQL_API.PQendcopy(Handle); end; function TZPostgreSQLBaseDriver.ExecuteFunction( Handle: PZPostgreSQLConnect; fnid: Integer; result_buf, result_len: PInteger; result_is_int: Integer; args: PZPostgreSQLArgBlock; nargs: Integer): PZPostgreSQLResult; begin Result := POSTGRESQL_API.PQfn(Handle, fnid, result_buf, result_len, result_is_int, PPQArgBlock(args), nargs); end; function TZPostgreSQLBaseDriver.ExecuteQuery( Handle: PZPostgreSQLConnect; Query: PAnsiChar): PZPostgreSQLResult; begin Result := POSTGRESQL_API.PQexec(Handle, Query); end; function TZPostgreSQLBaseDriver.ExecParams(Handle: PPGconn; command: PAnsichar; nParams: Integer; paramTypes: TPQparamTypes; paramValues: TPQparamValues; paramLengths: TPQparamLengths; paramFormats: TPQparamFormats; resultFormat: Integer): PPGresult; begin if Assigned(POSTGRESQL_API.PQexecParams) then Result := POSTGRESQL_API.PQexecParams(Handle, command, nParams, paramtypes, paramValues, paramLengths, paramFormats, resultFormat) else Result := nil; end; function TZPostgreSQLBaseDriver.Prepare(Handle: PPGconn; stmtName: PAnsichar; query: PAnsiChar; nParams: Integer; paramTypes: TPQparamTypes): PPGresult; begin if Assigned(POSTGRESQL_API.PQprepare) then Result := POSTGRESQL_API.PQprepare(Handle, stmtName, query, nParams, paramTypes) else Result := nil; end; function TZPostgreSQLBaseDriver.ExecPrepared(Handle: PPGconn; stmtName: PAnsichar; nParams: Integer; paramValues: TPQparamValues; paramLengths: TPQparamLengths; paramFormats: TPQparamFormats; resultFormat: Integer): PPGresult; begin if Assigned(POSTGRESQL_API.PQexecPrepared) then Result := POSTGRESQL_API.PQexecPrepared(Handle, stmtName, nParams, paramValues, paramLengths, paramFormats, resultFormat) else Result := nil; end; function TZPostgreSQLBaseDriver.SendQuery(Handle: PZPostgreSQLConnect; Query: PAnsiChar): Integer; begin Result := POSTGRESQL_API.PQsendQuery(Handle, Query); end; function TZPostgreSQLBaseDriver.SendQueryParams(Handle: PPGconn; command: PAnsichar; nParams: Integer; paramTypes: TPQparamTypes; paramValues: TPQparamValues; paramLengths: TPQparamLengths; paramFormats: TPQparamFormats; resultFormat: Integer): Integer; begin if Assigned(POSTGRESQL_API.PQsendQueryParams) then Result := POSTGRESQL_API.PQsendQueryParams(Handle, command, nParams, paramTypes, paramValues, paramLengths, paramFormats, resultFormat) else Result := -1; end; function TZPostgreSQLBaseDriver.SendPrepare(Handle: PPGconn; stmtName: PAnsichar; query: PAnsiChar; nParams: Integer; paramTypes: TPQparamTypes): Integer; begin if Assigned(POSTGRESQL_API.PQsendPrepare) then Result := POSTGRESQL_API.PQsendPrepare(Handle, stmtName, query, nParams, paramTypes) else Result := -1; end; function TZPostgreSQLBaseDriver.SendQueryPrepared(Handle: PPGconn; stmtName: PAnsichar; nParams: Integer; paramValues: TPQparamValues; paramLengths: TPQparamLengths; paramFormats: TPQparamFormats; resultFormat: Integer): Integer; begin if Assigned(POSTGRESQL_API.PQsendQueryPrepared) then Result := POSTGRESQL_API.PQsendQueryPrepared(Handle, stmtName, nParams, paramValues, paramLengths, paramFormats, resultFormat) else Result := -1; end; function TZPostgreSQLBaseDriver.GetResult(Handle: PZPostgreSQLConnect): PZPostgreSQLResult; begin Result := POSTGRESQL_API.PQgetResult(Handle); end; function TZPostgreSQLBaseDriver.DescribePrepared(Handle: PPGconn; const stmt: PAnsiChar): PPGresult; begin if Assigned(POSTGRESQL_API.PQdescribePrepared) then Result := POSTGRESQL_API.PQdescribePrepared(Handle, stmt) else Result := nil; end; function TZPostgreSQLBaseDriver.DescribePortal(Handle: PPGconn; const portal: PAnsiChar): PPGresult; begin if Assigned(POSTGRESQL_API.PQdescribePortal) then Result := POSTGRESQL_API.PQdescribePortal(Handle, portal) else Result := nil; end; function TZPostgreSQLBaseDriver.SendDescribePrepared(Handle: PPGconn; const stmt: PAnsiChar): Integer; begin if Assigned(POSTGRESQL_API.PQsendDescribePrepared) then Result := POSTGRESQL_API.PQsendDescribePrepared(Handle, stmt) else Result := -1; end; function TZPostgreSQLBaseDriver.SendDescribePortal(Handle: PPGconn; const portal: PAnsiChar): Integer; begin if Assigned(POSTGRESQL_API.PQsendDescribePortal) then Result := POSTGRESQL_API.PQsendDescribePortal(Handle, portal) else Result := -1; end; function TZPostgreSQLBaseDriver.ExportLargeObject( Handle: PZPostgreSQLConnect; ObjId: Oid; FileName: PAnsiChar): Integer; begin Result := POSTGRESQL_API.lo_export(Handle, ObjId, FileName); end; procedure TZPostgreSQLBaseDriver.Finish(Handle: PZPostgreSQLConnect); begin POSTGRESQL_API.PQfinish(Handle); end; procedure TZPostgreSQLBaseDriver.FreeNotify(Handle: PZPostgreSQLNotify); begin POSTGRESQL_API.PQfreeNotify(PPGnotify(Handle)); end; function TZPostgreSQLBaseDriver.GetBackendPID( Handle: PZPostgreSQLConnect): Integer; begin Result := POSTGRESQL_API.PQbackendPID(Handle); end; function TZPostgreSQLBaseDriver.GetBinaryTuples( Res: PZPostgreSQLResult): Integer; begin Result := POSTGRESQL_API.PQbinaryTuples(Res); end; function TZPostgreSQLBaseDriver.GetCommandStatus( Res: PZPostgreSQLResult): PAnsiChar; begin Result := POSTGRESQL_API.PQcmdStatus(Res); end; function TZPostgreSQLBaseDriver.GetCommandTuples( Res: PZPostgreSQLResult): PAnsiChar; begin Result := POSTGRESQL_API.PQcmdTuples(Res); end; function TZPostgreSQLBaseDriver.GetConnectDefaults: PZPostgreSQLConnectInfoOption; begin Result := PZPostgreSQLConnectInfoOption(POSTGRESQL_API.PQconndefaults); end; function TZPostgreSQLBaseDriver.GetDatabase( Handle: PZPostgreSQLConnect): PAnsiChar; begin Result := POSTGRESQL_API.PQdb(Handle); end; function TZPostgreSQLBaseDriver.GetErrorMessage( Handle: PZPostgreSQLConnect): PAnsiChar; begin Result := POSTGRESQL_API.PQerrorMessage(Handle); end; function TZPostgreSQLBaseDriver.GetFieldCount( Res: PZPostgreSQLResult): Integer; begin Result := POSTGRESQL_API.PQnfields(Res); end; function TZPostgreSQLBaseDriver.GetFieldMode(Res: PZPostgreSQLResult; FieldNum: Integer): Integer; begin Result := POSTGRESQL_API.PQfmod(Res, FieldNum); end; function TZPostgreSQLBaseDriver.GetFieldName(Res: PZPostgreSQLResult; FieldNum: Integer): PAnsiChar; begin Result := POSTGRESQL_API.PQfname(Res, FieldNum); end; function TZPostgreSQLBaseDriver.GetFieldNumber( Res: PZPostgreSQLResult; FieldName: PAnsiChar): Integer; begin Result := POSTGRESQL_API.PQfnumber(Res, FieldName); end; function TZPostgreSQLBaseDriver.GetFieldTableOID(Res: PZPostgreSQLResult; FieldNum: Integer) : Oid; begin Result := POSTGRESQL_API.PQftable(Res, FieldNum); end; function TZPostgreSQLBaseDriver.GetFieldTableColIdx(Res: PZPostgreSQLResult; FieldNum: Integer) : Integer; begin Result := POSTGRESQL_API.PQftablecol(Res, FieldNum); end; function TZPostgreSQLBaseDriver.GetFieldSize(Res: PZPostgreSQLResult; FieldNum: Integer): Integer; begin Result := POSTGRESQL_API.PQfsize(Res, FieldNum); end; function TZPostgreSQLBaseDriver.GetFieldType(Res: PZPostgreSQLResult; FieldNum: Integer): Oid; begin Result := POSTGRESQL_API.PQftype(Res, FieldNum); end; function TZPostgreSQLBaseDriver.GetHost( Handle: PZPostgreSQLConnect): PAnsiChar; begin Result := POSTGRESQL_API.PQhost(Handle); end; function TZPostgreSQLBaseDriver.GetIsNull(Res: PZPostgreSQLResult; TupNum, FieldNum: Integer): Integer; begin Result := POSTGRESQL_API.PQgetisnull(Res, TupNum, FieldNum); end; function TZPostgreSQLBaseDriver.GetLength(Res: PZPostgreSQLResult; TupNum, FieldNum: Integer): Integer; begin Result := POSTGRESQL_API.PQgetlength(Res, TupNum, FieldNum); end; function TZPostgreSQLBaseDriver.GetLine(Handle: PZPostgreSQLConnect; Buffer: PAnsiChar; Length: Integer): Integer; begin Result := POSTGRESQL_API.PQgetline(Handle, Buffer, Length); end; function TZPostgreSQLBaseDriver.GetLineAsync( Handle: PZPostgreSQLConnect; Buffer: PAnsiChar; Length: Integer): Integer; begin Result := POSTGRESQL_API.PQgetlineAsync(Handle, Buffer, Length); end; function TZPostgreSQLBaseDriver.GetOidStatus( Res: PZPostgreSQLResult): PAnsiChar; begin Result := POSTGRESQL_API.PQoidStatus(Res); end; function TZPostgreSQLBaseDriver.GetOidValue( Res: PZPostgreSQLResult): Oid; begin Result := POSTGRESQL_API.PQoidValue(Res); end; function TZPostgreSQLBaseDriver.GetOptions( Handle: PZPostgreSQLConnect): PAnsiChar; begin Result := POSTGRESQL_API.PQoptions(Handle); end; function TZPostgreSQLBaseDriver.GetPassword( Handle: PZPostgreSQLConnect): PAnsiChar; begin Result := POSTGRESQL_API.PQpass(Handle); end; function TZPostgreSQLBaseDriver.GetPort( Handle: PZPostgreSQLConnect): PAnsiChar; begin Result := POSTGRESQL_API.PQport(Handle); end; function TZPostgreSQLBaseDriver.GetResultErrorField(Res: PZPostgreSQLResult; FieldCode: TZPostgreSQLFieldCode): PAnsiChar; begin if Assigned(POSTGRESQL_API.PQresultErrorField) then Result := POSTGRESQL_API.PQresultErrorField(Res, ord(FieldCode)) else Result := ''; end; function TZPostgreSQLBaseDriver.GetResultErrorMessage( Res: PZPostgreSQLResult): PAnsiChar; begin Result := POSTGRESQL_API.PQresultErrorMessage(Res); end; function TZPostgreSQLBaseDriver.GetResultStatus( Res: PZPostgreSQLResult): TZPostgreSQLExecStatusType; begin Result := TZPostgreSQLExecStatusType(POSTGRESQL_API.PQresultStatus(Res)); end; function TZPostgreSQLBaseDriver.GetRowCount( Res: PZPostgreSQLResult): Integer; begin Result := POSTGRESQL_API.PQntuples(Res); end; function TZPostgreSQLBaseDriver.GetSocket( Handle: PZPostgreSQLConnect): Integer; begin Result := POSTGRESQL_API.PQsocket(Handle); end; function TZPostgreSQLBaseDriver.GetStandardConformingStrings: Boolean; begin Result := False; end; function TZPostgreSQLBaseDriver.GetStatus( Handle: PZPostgreSQLConnect): TZPostgreSQLConnectStatusType; begin Result := TZPostgreSQLConnectStatusType(POSTGRESQL_API.PQstatus(Handle)); end; function TZPostgreSQLBaseDriver.GetClientEncoding(Handle: PPGconn): Integer; //EgonHugeist begin Result := POSTGRESQL_API.PQclientEncoding(Handle); end; function TZPostgreSQLBaseDriver.GetTTY( Handle: PZPostgreSQLConnect): PAnsiChar; begin Result := POSTGRESQL_API.PQtty(Handle); end; function TZPostgreSQLBaseDriver.GetUser( Handle: PZPostgreSQLConnect): PAnsiChar; begin Result := POSTGRESQL_API.PQuser(Handle); end; function TZPostgreSQLBaseDriver.GetValue(Res: PZPostgreSQLResult; TupNum, FieldNum: Integer): PAnsiChar; begin Result := POSTGRESQL_API.PQgetvalue(Res, TupNum, FieldNum); end; function TZPostgreSQLBaseDriver.ImportLargeObject( Handle: PZPostgreSQLConnect; FileName: PAnsiChar): Oid; begin Result := POSTGRESQL_API.lo_import(Handle, FileName); end; function TZPostgreSQLBaseDriver.IsBusy( Handle: PZPostgreSQLConnect): Integer; begin Result := POSTGRESQL_API.PQisBusy(Handle); end; function TZPostgreSQLBaseDriver.MakeEmptyResult( Handle: PZPostgreSQLConnect; Status: TZPostgreSQLExecStatusType): PZPostgreSQLResult; begin Result := POSTGRESQL_API.PQmakeEmptyPGresult(Handle, TZPostgreSQLExecStatusType(Status)); end; function TZPostgreSQLBaseDriver.Notifies( Handle: PZPostgreSQLConnect): PZPostgreSQLNotify; begin Result := PZPostgreSQLNotify(POSTGRESQL_API.PQnotifies(Handle)); end; function TZPostgreSQLBaseDriver.OpenLargeObject( Handle: PZPostgreSQLConnect; ObjId: Oid; Mode: Integer): Integer; begin Result := POSTGRESQL_API.lo_open(Handle, ObjId, Mode); end; function TZPostgreSQLBaseDriver.PutBytes(Handle: PZPostgreSQLConnect; Buffer: PAnsiChar; Length: Integer): Integer; begin Result := POSTGRESQL_API.PQputnbytes(Handle, Buffer, Length); end; function TZPostgreSQLBaseDriver.PutLine(Handle: PZPostgreSQLConnect; Buffer: PAnsiChar): Integer; begin Result := POSTGRESQL_API.PQputline(Handle, Buffer); end; function TZPostgreSQLBaseDriver.ReadLargeObject( Handle: PZPostgreSQLConnect; Fd: Integer; Buffer: PAnsiChar; Length: Integer): Integer; begin Result := POSTGRESQL_API.lo_read(Handle, Fd, Buffer, Length); end; function TZPostgreSQLBaseDriver.RequestCancel( Handle: PZPostgreSQLConnect): Integer; begin Result := POSTGRESQL_API.PQrequestCancel(Handle); end; procedure TZPostgreSQLBaseDriver.Reset(Handle: PZPostgreSQLConnect); begin POSTGRESQL_API.PQreset(Handle); end; function TZPostgreSQLBaseDriver.SeekLargeObject( Handle: PZPostgreSQLConnect; Fd, Offset, Whence: Integer): Integer; begin Result := POSTGRESQL_API.lo_lseek(Handle, Fd, Offset, Whence); end; function TZPostgreSQLBaseDriver.SetDatabaseLogin(Host, Port, Options, TTY, Db, User, Passwd: PAnsiChar): PZPostgreSQLConnect; begin Result := POSTGRESQL_API.PQsetdbLogin(Host, Port, Options, TTY, Db, User, Passwd); end; procedure TZPostgreSQLBaseDriver.SetNoticeProcessor( Handle: PZPostgreSQLConnect; Proc: TZPostgreSQLNoticeProcessor; Arg: Pointer); begin POSTGRESQL_API.PQsetNoticeProcessor(Handle, Proc, Arg); end; function TZPostgreSQLBaseDriver.TellLargeObject( Handle: PZPostgreSQLConnect; Fd: Integer): Integer; begin Result := POSTGRESQL_API.lo_tell(Handle, Fd); end; procedure TZPostgreSQLBaseDriver.Trace(Handle: PZPostgreSQLConnect; DebugPort: Pointer); begin POSTGRESQL_API.PQtrace(Handle, DebugPort); end; function TZPostgreSQLBaseDriver.UnlinkLargeObject( Handle: PZPostgreSQLConnect; ObjId: Oid): Integer; begin Result := POSTGRESQL_API.lo_unlink(Handle, ObjId); end; procedure TZPostgreSQLBaseDriver.Untrace(Handle: PZPostgreSQLConnect); begin POSTGRESQL_API.PQuntrace(Handle); end; function TZPostgreSQLBaseDriver.WriteLargeObject( Handle: PZPostgreSQLConnect; Fd: Integer; Buffer: PAnsiChar; Length: Integer): Integer; begin Result := POSTGRESQL_API.lo_write(Handle, Fd, Buffer, Length); end; function TZPostgreSQLBaseDriver.GetPlainFunc():PAPI; begin result:= @POSTGRESQL_API; end; function TZPostgreSQLBaseDriver.EscapeString(Handle: Pointer; const Value: RawByteString; ConSettings: PZConSettings; WasEncoded: Boolean = False): RawByteString; var ResLen: NativeUInt; Temp: PAnsiChar; SourceTemp: RawByteString; IError: Integer; begin if ( Assigned(POSTGRESQL_API.PQescapeStringConn) or Assigned(POSTGRESQL_API.PQescapeString) ) and ( Value <> '' )then begin IError := 0; {$IFDEF UNICODE} SourceTemp := Value; {$ELSE} if WasEncoded then SourceTemp := Value else SourceTemp := ZPlainString(Value, ConSettings); //check encoding too {$ENDIF} GetMem(Temp, Length(SourceTemp)*2); if Assigned(POSTGRESQL_API.PQescapeStringConn) then ResLen := POSTGRESQL_API.PQescapeStringConn(Handle, Temp, PAnsiChar(SourceTemp), {$IFDEF WITH_STRLEN_DEPRECATED}AnsiStrings.{$ENDIF}StrLen(PAnsiChar(SourceTemp)), @IError) else ResLen := POSTGRESQL_API.PQescapeString(Temp, PAnsiChar(SourceTemp), {$IFDEF WITH_STRLEN_DEPRECATED}AnsiStrings.{$ENDIF}StrLen(PAnsiChar(SourceTemp))); if not (IError = 0) then raise Exception.Create('Wrong escape behavior!'); SetLength(Result, ResLen); Move(Temp^, PAnsiChar(Result)^, ResLen); FreeMem(Temp); end else Result := Value; Result := #39+Result+#39; end; { TZPostgreSQL7PlainDriver } function TZPostgreSQL7PlainDriver.Clone: IZPlainDriver; begin Result := TZPostgreSQL7PlainDriver.Create; end; constructor TZPostgreSQL7PlainDriver.Create; begin inherited Create; {$IFNDEF UNIX} FLoader.AddLocation(WINDOWS_DLL7_LOCATION); {$ENDIF} end; function TZPostgreSQL7PlainDriver.GetProtocol: string; begin Result := 'postgresql-7'; end; function TZPostgreSQL7PlainDriver.GetDescription: string; begin Result := 'Native Plain Driver for PostgreSQL 7.x'; end; { TZPostgreSQL8PlainDriver } function TZPostgreSQL8PlainDriver.Clone: IZPlainDriver; begin Result := TZPostgreSQL8PlainDriver.Create; end; function TZPostgreSQL8PlainDriver.GetUnicodeCodePageName: String; begin Result := 'UTF8'; end; procedure TZPostgreSQL8PlainDriver.LoadCodePages; begin inherited LoadCodePages; { Version 8.1 } {MultiByte} ResetCodePage(Ord(csUNICODE_PODBC), 'UTF8', Ord(csUTF8), ceUTF8, zCP_UTF8, '', 4); { Unicode, 8-bit all } AddCodePage('BIG5', Ord(csBIG5), ceAnsi, zCP_Big5, '', 2); { Big Five Traditional Chinese } AddCodePage('GB18030', Ord(csGB18030), ceAnsi, zCP_GB18030, '', 2); { National Standard Chinese } AddCodePage('GBK', Ord(csGBK), ceAnsi, zCP_GB2312, '', 2); { Extended National Standard Simplified Chinese } AddCodePage('SJIS', Ord(csSJIS), ceAnsi, zCP_SHIFTJS, '', 2); { Shift JIS Japanese } AddCodePage('UHC', Ord(csUHC), ceAnsi, zCP_EUCKR, '', 2); { Unified Hangul Code Korean } {SingleByte} ResetCodePage(Ord(csALT), 'WIN866', Ord(csWIN866), ceAnsi, zCP_DOS866); { Windows CP866 Cyrillic } //No longer in use AddCodePage('WIN874', Ord(csWIN874), ceAnsi, zCP_DOS874); { Windows CP874 Thai } AddCodePage('WIN1250', Ord(csWIN1250), ceAnsi, zCP_WIN1250); { Windows CP1250 Central European } ResetCodePage(Ord(csWIN), 'WIN1251', Ord(csWIN1251), ceAnsi, zCP_WIN1251); { Windows CP1251 Cyrillic } //No longer in use AddCodePage('WIN1252', Ord(csWIN1252), ceAnsi, zCP_WIN1252); { Windows CP1252 Western European } ResetCodePage(Ord(csTCVN), 'WIN1258', Ord(csWIN1258),ceAnsi, zCP_WIN1258); { Windows CP1258 Vietnamese } //No longer in use { Version 8.3 } {MultiByte} AddCodePage('EUC_JIS_2004', Ord(csEUC_JIS_2004), ceAnsi, $ffff, '', 3); { Extended UNIX Code-JP, JIS X 0213 Japanese } AddCodePage('SHIFT_JIS_2004', Ord(csSHIFT_JIS_2004), ceAnsi, zCP_SHIFTJS, '', 3); { Shift JIS, JIS X 0213 Japanese } {SingleChar} AddCodePage('WIN1253', Ord(csWIN1253), ceAnsi, zCP_WIN1253); { Windows CP1253 Greek } AddCodePage('WIN1254', Ord(csWIN1254), ceAnsi, zCP_WIN1254); { Windows CP1254 Turkish } AddCodePage('WIN1255', Ord(csWIN1255), ceAnsi, zCP_WIN1255); { Windows CP1255 Hebrew } AddCodePage('WIN1257', Ord(csWIN1257), ceAnsi, zCP_WIN1257); { Windows CP1257 Baltic } { Version 8.4 } {SingleChar} AddCodePage('KOI8U', Ord(csKOI8U), ceAnsi, zCP_KOI8U); { KOI8-U Cyrillic (Ukrainian) } end; constructor TZPostgreSQL8PlainDriver.Create; begin inherited Create; {$IFNDEF UNIX} FLoader.AddLocation(WINDOWS_DLL8_LOCATION); {$ELSE} FLoader.AddLocation(LINUX_DLL82_LOCATION); FLoader.AddLocation(LINUX_DLL8_LOCATION); {$ENDIF} end; function TZPostgreSQL8PlainDriver.GetProtocol: string; begin Result := 'postgresql-8'; end; function TZPostgreSQL8PlainDriver.GetDescription: string; begin Result := 'Native Plain Driver for PostgreSQL 8.x'; end; { TZPostgreSQL9PlainDriver } function TZPostgreSQL9PlainDriver.Clone: IZPlainDriver; begin Result := TZPostgreSQL9PlainDriver.Create; end; procedure TZPostgreSQL9PlainDriver.LoadCodePages; begin inherited LoadCodePages; ResetCodePage(Ord(csKOI8), 'KOI8R', Ord(csKOI8R)); { KOI8-R Cyrillic (Russian) } //No longer in use end; constructor TZPostgreSQL9PlainDriver.Create; begin inherited Create; Self.FLoader.ClearLocations; {$IFNDEF STRICT_DLL_LOADING} {$IFNDEF UNIX} FLoader.AddLocation(WINDOWS_DLL_LOCATION); {$ELSE} FLoader.AddLocation(LINUX_DLL_LOCATION); {$ENDIF} {$ENDIF} end; function TZPostgreSQL9PlainDriver.GetProtocol: string; begin Result := 'postgresql-9'; end; function TZPostgreSQL9PlainDriver.GetDescription: string; begin Result := 'Native Plain Driver for PostgreSQL 9.x'; end; function TZPostgreSQL9PlainDriver.GetStandardConformingStrings: Boolean; begin Result := True; end; end. ================================================ FILE: lib/zeosdbo/src/plain/ZPlainSqLiteDriver.pas ================================================ {*********************************************************} { } { Zeos Database Objects } { Native Plain Drivers for SQLite } { } { Originally written by Sergey Seroukhov } { } {*********************************************************} {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@} unit ZPlainSqLiteDriver; interface {$I ZPlain.inc} uses SysUtils, Classes, {$IFDEF MSEgui}mclasses,{$ENDIF} Types, ZClasses, ZCompatibility, ZPlainDriver; const WINDOWS_DLL_LOCATION = 'sqlite.dll'; WINDOWS_DLL3_LOCATION = 'sqlite3.dll'; LINUX_DLL_LOCATION = 'libsqlite'+SharedSuffix; LINUX_DLL3_LOCATION = 'libsqlite3'+SharedSuffix; SQLITE_ISO8859 = 1; MASTER_NAME = 'sqlite_master'; TEMP_MASTER_NAME = 'sqlite_temp_master'; { Return values for sqlite_exec() and sqlite_step() } SQLITE_OK = 0; // Successful result SQLITE_ERROR = 1; // SQL error or missing database SQLITE_INTERNAL = 2; // An internal logic error in SQLite SQLITE_PERM = 3; // Access permission denied SQLITE_ABORT = 4; // Callback routine requested an abort SQLITE_BUSY = 5; // The database file is locked SQLITE_LOCKED = 6; // A table in the database is locked SQLITE_NOMEM = 7; // A malloc() failed SQLITE_READONLY = 8; // Attempt to write a readonly database _SQLITE_INTERRUPT = 9; // Operation terminated by sqlite_interrupt() SQLITE_IOERR = 10; // Some kind of disk I/O error occurred SQLITE_CORRUPT = 11; // The database disk image is malformed SQLITE_NOTFOUND = 12; // (Internal Only) Table or record not found SQLITE_FULL = 13; // Insertion failed because database is full SQLITE_CANTOPEN = 14; // Unable to open the database file SQLITE_PROTOCOL = 15; // Database lock protocol error SQLITE_EMPTY = 16; // (Internal Only) Database table is empty SQLITE_SCHEMA = 17; // The database schema changed SQLITE_TOOBIG = 18; // Too much data for one row of a table SQLITE_CONSTRAINT = 19; // Abort due to contraint violation SQLITE_MISMATCH = 20; // Data type mismatch SQLITE_MISUSE = 21; // Library used incorrectly SQLITE_NOLFS = 22; // Uses OS features not supported on host SQLITE_AUTH = 23; // Authorization denied SQLITE_FORMAT = 24; // Auxiliary database format error SQLITE_RANGE = 25; // 2nd parameter to sqlite_bind out of range SQLITE_NOTADB = 26; // File opened that is not a database file SQLITE_ROW = 100; // sqlite_step() has another row ready SQLITE_DONE = 101; // sqlite_step() has finished executing SQLITE_NUMERIC = -1; SQLITE_TEXT = -2; SQLITE_ARGS = -3; { The second parameter to the access authorization function above will be one of the values below. These values signify what kind of operation is to be authorized. The 3rd and 4th parameters to the authorization function will be parameters or NULL depending on which of the following codes is used as the second parameter. The 5th parameter is the name of the database ("main", "temp", etc.) if applicable. The 6th parameter is the name of the inner-most trigger or view that is responsible for the access attempt or NULL if this access attempt is directly from input SQL code. Arg-3 Arg-4 } SQLITE_COPY = 0; // Table Name File Name SQLITE_CREATE_INDEX = 1; // Index Name Table Name SQLITE_CREATE_TABLE = 2; // Table Name NULL SQLITE_CREATE_TEMP_INDEX = 3; // Index Name Table Name SQLITE_CREATE_TEMP_TABLE = 4; // Table Name NULL SQLITE_CREATE_TEMP_TRIGGER = 5; // Trigger Name Table Name SQLITE_CREATE_TEMP_VIEW = 6; // View Name NULL SQLITE_CREATE_TRIGGER = 7; // Trigger Name Table Name SQLITE_CREATE_VIEW = 8; // View Name NULL SQLITE_DELETE = 9; // Table Name NULL SQLITE_DROP_INDEX = 10; // Index Name Table Name SQLITE_DROP_TABLE = 11; // Table Name NULL SQLITE_DROP_TEMP_INDEX = 12; // Index Name Table Name SQLITE_DROP_TEMP_TABLE = 13; // Table Name NULL SQLITE_DROP_TEMP_TRIGGER = 14; // Trigger Name Table Name SQLITE_DROP_TEMP_VIEW = 15; // View Name NULL SQLITE_DROP_TRIGGER = 16; // Trigger Name Table Name SQLITE_DROP_VIEW = 17; // View Name NULL SQLITE_INSERT = 18; // Table Name NULL SQLITE_PRAGMA = 19; // Pragma Name 1st arg or NULL SQLITE_READ = 20; // Table Name Column Name SQLITE_SELECT = 21; // NULL NULL SQLITE_TRANSACTION = 22; // NULL NULL SQLITE_UPDATE = 23; // Table Name Column Name SQLITE_ATTACH = 24; // Filename NULL SQLITE_DETACH = 25; // Database Name NULL { The return value of the authorization function should be one of the following constants: } SQLITE_DENY = 1; // Abort the SQL statement with an error SQLITE_IGNORE = 2; // Don't allow access, but don't generate an error SQLITE_INTEGER = 1; SQLITE_FLOAT = 2; SQLITE3_TEXT = 3; SQLITE_BLOB = 4; SQLITE_NULL = 5; type Psqlite = Pointer; Psqlite_func = Pointer; Psqlite_vm = Pointer; Psqlite3_stmt = Pointer; Psqlite3_value = Pointer; Tsqlite3_destructor_type = procedure(user: pointer); cdecl; SQLITE_STATIC = procedure(User: Pointer = Nil); cdecl; SQLITE_TRANSIENT = procedure(User: pointer = Pointer(-1)); cdecl; type { ************** Plain API Function types definition ************* } Tsqlite_callback = function(p1: Pointer; p2: Integer; var p3: PAnsiChar; var p4: PAnsiChar): Integer; cdecl; Tsqlite_simple_callback = function(p1: Pointer): Integer; cdecl; Tsqlite_simple_callback0 = function(p1: Pointer): Pointer; cdecl; Tsqlite_busy_callback = function(p1: Pointer; const p2: PAnsiChar; p3: Integer): Integer; cdecl; Tsqlite_function_callback = procedure(p1: Psqlite_func; p2: Integer; const p3: PPAnsiChar); cdecl; Tsqlite_finalize_callback = procedure(p1: Psqlite_func); cdecl; Tsqlite_auth_callback = function(p1: Pointer; p2: Integer; const p3: PAnsiChar; const p4: PAnsiChar; const p5: PAnsiChar; const p6: PAnsiChar): Integer; cdecl; Tsqlite_trace_callback = procedure(p1: Pointer; const p2: PAnsiChar); cdecl; Tsqlite_open = function(const filename: PAnsiChar;var Qsqlite: Psqlite): Integer; cdecl; Tsqlite_close = function(db: Psqlite): Integer; cdecl; { prepared statment api} Tsqlite3_prepare = function( db: Psqlite; // Database handle const zSql: PAnsiChar; // SQL statement, UTF-8 encoded nBytes: Integer; // Maximum length of zSql in bytes. -1 = null terminated out ppStmt: Psqlite3_stmt; // OUT: Statement handle out pzTail: PPAnsichar // OUT: Pointer to unused portion of zSql ): Integer; cdecl; Tsqlite3_prepare_v2 = function( db: Psqlite; // Database handle const zSql: PAnsiChar; // SQL statement, UTF-8 encoded nBytes: Integer; // Maximum length of zSql in bytes. -1 = null terminated out ppStmt: Psqlite3_stmt; // OUT: Statement handle out pzTail: PPAnsichar // OUT: Pointer to unused portion of zSql ): Integer; cdecl; Tsqlite3_prepare16 = function( db: Psqlite; // Database handle const zSql: PWideChar; // SQL statement, UTF-16 encoded nBytes: Integer; // Maximum length of zSql in bytes. -1 = null terminated out ppStmt: Psqlite3_stmt; // OUT: Statement handle out pzTail: ZPPWideChar // OUT: Pointer to unused portion of zSql ): Integer; cdecl; Tsqlite3_prepare16_v2 = function( db: Psqlite; // Database handle const zSql: PWideChar; // SQL statement, UTF-16 encoded nBytes: Integer; // Maximum length of zSql in bytes. -1 = null terminated out ppStmt: Psqlite3_stmt; // OUT: Statement handle out pzTail: ZPPWideChar // OUT: Pointer to unused portion of zSql ): Integer; cdecl; Tsqlite3_bind_parameter_count = function(pStmt: Psqlite3_stmt): Integer; cdecl; Tsqlite3_bind_parameter_name = function(pStmt: Psqlite3_stmt; ParamIndex: Integer): PAnsichar; cdecl; Tsqlite3_bind_parameter_index = function(pStmt: Psqlite3_stmt; const zName: PAnsiChar): Integer; cdecl; Tsqlite3_clear_bindings = function(pStmt: Psqlite3_stmt): Integer; cdecl; Tsqlite3_column_count = function(pStmt: Psqlite3_stmt): Integer; cdecl; Tsqlite3_column_name = function(pStmt: Psqlite3_stmt; iCol: Integer): PAnsiChar; cdecl; Tsqlite3_column_name16 = function(pStmt: Psqlite3_stmt; iCol: Integer): PWideChar; cdecl; Tsqlite3_column_database_name = function(pStmt: Psqlite3_stmt; iCol: Integer): PAnsiChar; cdecl; Tsqlite3_column_database_name16 = function(pStmt: Psqlite3_stmt; iCol: Integer): PWideChar; cdecl; Tsqlite3_column_table_name = function(pStmt: Psqlite3_stmt; iCol: Integer): PAnsiChar; cdecl; Tsqlite3_column_table_name16 = function(pStmt: Psqlite3_stmt; iCol: Integer): PWideChar; cdecl; Tsqlite3_column_origin_name = function(pStmt: Psqlite3_stmt; iCol: Integer): PAnsiChar; cdecl; Tsqlite3_column_origin_name16 = function(pStmt: Psqlite3_stmt; iCol: Integer): PWideChar; cdecl; Tsqlite3_column_decltype = function(pStmt: Psqlite3_stmt; iCol: Integer): PAnsiChar; cdecl; Tsqlite3_column_decltype16 = function(pStmt: Psqlite3_stmt; iCol: Integer): PWideChar; cdecl; Tsqlite3_step = function(pStmt: Psqlite3_stmt): Integer; cdecl; Tsqlite3_data_count = function (pStmt: Psqlite3_stmt): Integer; cdecl; Tsqlite3_bind_blob = function(pStmt: Psqlite3_stmt; ParamIndex: Integer; const Buffer: Pointer; N: Integer; ValDestructor: Tsqlite3_destructor_type): Integer; cdecl; Tsqlite3_bind_double = function(pStmt: Psqlite3_stmt; ParamIndex: Integer; Value: Double): Integer; cdecl; Tsqlite3_bind_int = function(pStmt: Psqlite3_stmt; ParamIndex: Integer; Value: Integer): Integer; cdecl; Tsqlite3_bind_int64 = function(pStmt: Psqlite3_stmt; ParamIndex: Integer; Value: Int64): Integer; cdecl; Tsqlite3_bind_null = function(pStmt: Psqlite3_stmt; ParamIndex: Integer): Integer; cdecl; Tsqlite3_bind_text = function(pStmt: Psqlite3_stmt; ParamIndex: Integer; const Text: PAnsiChar; N: Integer; ValDestructor: Tsqlite3_destructor_type): Integer; cdecl; Tsqlite3_bind_text16 = function(pStmt: Psqlite3_stmt; ParamIndex: Integer; const Text: PWideChar; N: Integer; ValDestructor: Tsqlite3_destructor_type): Integer; cdecl; Tsqlite3_bind_value = function(pStmt: Psqlite3_stmt; ParamIndex: Integer; const Value: Psqlite3_value): Integer; cdecl; Tsqlite3_bind_zeroblob = function(pStmt: Psqlite3_stmt; ParamIndex: Integer; N: Integer): Integer; cdecl; Tsqlite3_finalize = function(pStmt: Psqlite3_stmt): Integer; cdecl; Tsqlite3_reset = function(pStmt: Psqlite3_stmt): Integer; cdecl; Tsqlite3_column_blob = function(Stmt: Psqlite3_stmt; iCol:integer): Pointer; cdecl; Tsqlite3_column_bytes = function(Stmt: Psqlite3_stmt; iCol: Integer): integer; cdecl; Tsqlite3_column_bytes16 = function(Stmt: Psqlite3_stmt; iCol: Integer): integer; cdecl; Tsqlite3_column_double = function(Stmt: Psqlite3_stmt; iCol: Integer): Double; cdecl; Tsqlite3_column_int = function(Stmt: Psqlite3_stmt; iCol: Integer): Integer; cdecl; Tsqlite3_column_int64 = function(Stmt: Psqlite3_stmt; iCol: Integer): Int64; cdecl; Tsqlite3_column_text = function(Stmt: Psqlite3_stmt; iCol: Integer): PAnsiChar; cdecl; Tsqlite3_column_text16 = function(Stmt: Psqlite3_stmt; iCol: Integer): PWideChar; cdecl; Tsqlite3_column_type = function(Stmt: Psqlite3_stmt; iCol: Integer): Integer; cdecl; Tsqlite3_column_value = function(Stmt: Psqlite3_stmt; iCol: Integer): Psqlite3_value; cdecl; Tsqlite3_last_insert_rowid = function(db: Psqlite): Int64; cdecl; //gets the column type Tsqlite_column_type = function(db:PSqlite;iCol:integer):Integer; cdecl; Tsqlite_exec = function(db: Psqlite; const sql: PAnsiChar; sqlite_callback: Tsqlite_callback; arg: Pointer; var errmsg: PAnsiChar): Integer; cdecl; Tsqlite_errmsg = function(db: Psqlite): PAnsiChar; cdecl; Tsqlite_errstr = function(code: Integer): PAnsiChar; cdecl; //Tsqlite_last_insert_rowid = function(db: Psqlite): Integer; cdecl; Tsqlite_changes = function(db: Psqlite): Integer; cdecl; Tsqlite_last_statement_changes = function(db: Psqlite): Integer; cdecl; Tsqlite_interrupt = procedure(db: Psqlite); cdecl; Tsqlite_complete = function(const sql: PAnsiChar): Integer; cdecl; Tsqlite_busy_handler = procedure(db: Psqlite; callback: Tsqlite_busy_callback; ptr: Pointer); cdecl; Tsqlite_busy_timeout = procedure(db: Psqlite; ms: Integer); cdecl; Tsqlite_get_table = function(db: Psqlite; const sql: PAnsiChar; var resultp: PPAnsiChar; var nrow: Integer; var ncolumn: Integer; var errmsg: PAnsiChar): Integer; cdecl; Tsqlite_free_table = procedure(var result: PAnsiChar); cdecl; Tsqlite_freemem = procedure(ptr: Pointer); cdecl; Tsqlite_libversion = function: PAnsiChar; cdecl; Tsqlite_libencoding = function: PAnsiChar; cdecl; Tsqlite_create_function = function(db: Psqlite; const zName: PAnsiChar; nArg: Integer; callback: Tsqlite_function_callback; pUserData: Pointer): Integer; cdecl; Tsqlite_create_aggregate = function(db: Psqlite; const zName: PAnsiChar; nArg: Integer; callback: Tsqlite_function_callback; finalize: Tsqlite_finalize_callback; pUserData: Pointer): Integer; cdecl; Tsqlite_function_type = function(db: Psqlite; const zName: PAnsiChar; datatype: Integer): Integer; cdecl; Tsqlite_set_result_string = function(func: Psqlite_func; const arg: PAnsiChar; len: Integer; UN: Tsqlite_simple_callback): PAnsiChar; cdecl; Tsqlite_set_result_int = procedure(func: Psqlite_func; arg: Integer); cdecl; Tsqlite_set_result_double = procedure(func: Psqlite_func; arg: Double); cdecl; Tsqlite_set_result_error = procedure(func: Psqlite_func; const arg: PAnsiChar; len: Integer); cdecl; Tsqlite_user_data = function(func: Psqlite_func): Pointer; cdecl; Tsqlite_aggregate_context = function(func: Psqlite_func; nBytes: Integer): Pointer; cdecl; Tsqlite_aggregate_count = function(func: Psqlite_func): Integer; cdecl; Tsqlite_set_authorizer = function(db: Psqlite; callback: Tsqlite_auth_callback; pUserData: Pointer): Integer; cdecl; Tsqlite_trace = function(db: Psqlite; callback: Tsqlite_trace_callback; ptr: Pointer): Pointer; cdecl; Tsqlite_progress_handler = procedure(db: Psqlite; p1: Integer; callback: Tsqlite_simple_callback; ptr: Pointer); cdecl; Tsqlite_commit_hook = function(db: Psqlite; callback: Tsqlite_simple_callback; ptr: Pointer): Pointer; cdecl; Tsqlite_open_encrypted = function(const zFilename: PAnsiChar; const pKey: PAnsiChar; nKey: Integer; var pErrcode: Integer; var pzErrmsg: PAnsiChar): Psqlite; cdecl; Tsqlite_rekey = function(db: Psqlite; const pKey: Pointer; nKey: Integer): Integer; cdecl; Tsqlite_key = function(db: Psqlite; const pKey: Pointer; nKey: Integer): Integer; cdecl; { ************* Plain API Function variables definition ************ } TZSQLite_API = record sqlite_open: Tsqlite_open; sqlite_close: Tsqlite_close; { prepared statement api } sqlite_prepare: Tsqlite3_prepare; sqlite_prepare_v2: Tsqlite3_prepare_v2; sqlite_prepare16: Tsqlite3_prepare16; sqlite_prepare16_v2: Tsqlite3_prepare16_v2; sqlite_bind_parameter_count: Tsqlite3_bind_parameter_count; sqlite_bind_parameter_name: Tsqlite3_bind_parameter_name; sqlite_bind_parameter_index: Tsqlite3_bind_parameter_index; sqlite_clear_bindings: Tsqlite3_clear_bindings; sqlite_column_count: Tsqlite3_column_count; sqlite_column_name: Tsqlite3_column_name; sqlite_column_name16: Tsqlite3_column_name16; sqlite_column_database_name: Tsqlite3_column_database_name; sqlite_column_database_name16: Tsqlite3_column_database_name16; sqlite_column_table_name: Tsqlite3_column_table_name; sqlite_column_table_name16: Tsqlite3_column_table_name16; sqlite_column_origin_name: Tsqlite3_column_origin_name; sqlite_column_origin_name16: Tsqlite3_column_origin_name16; sqlite_column_decltype: Tsqlite3_column_decltype; sqlite_column_decltype16: Tsqlite3_column_decltype16; sqlite_step: Tsqlite3_step; sqlite_data_count: Tsqlite3_data_count; sqlite_bind_blob: Tsqlite3_bind_blob; sqlite_bind_double: Tsqlite3_bind_double; sqlite_bind_int: Tsqlite3_bind_int; sqlite_bind_int64: Tsqlite3_bind_int64; sqlite_bind_null: Tsqlite3_bind_null; sqlite_bind_text: Tsqlite3_bind_text; sqlite_bind_text16: Tsqlite3_bind_text16; sqlite_bind_value: Tsqlite3_bind_value; sqlite_bind_zeroblob: Tsqlite3_bind_zeroblob; sqlite_finalize: Tsqlite3_finalize; sqlite_reset: Tsqlite3_reset; sqlite_column_blob: Tsqlite3_column_blob; sqlite_column_bytes: Tsqlite3_column_bytes; sqlite_column_bytes16: Tsqlite3_column_bytes16; sqlite_column_double: Tsqlite3_column_double; sqlite_column_int: Tsqlite3_column_int; sqlite_column_int64: Tsqlite3_column_int64; sqlite_column_text: Tsqlite3_column_text; sqlite_column_text16: Tsqlite3_column_text16; sqlite_column_type: Tsqlite3_column_type; sqlite_column_value: Tsqlite3_column_value; sqlite_exec: Tsqlite_exec; sqlite_errmsg: Tsqlite_errmsg; sqlite_errstr: Tsqlite_errstr; sqlite_last_insert_rowid: Tsqlite3_last_insert_rowid; sqlite_changes: Tsqlite_changes; sqlite_last_statement_changes: Tsqlite_last_statement_changes; sqlite_interrupt: Tsqlite_interrupt; sqlite_complete: Tsqlite_complete; sqlite_busy_handler: Tsqlite_busy_handler; sqlite_busy_timeout: Tsqlite_busy_timeout; sqlite_get_table: Tsqlite_get_table; sqlite_free_table: Tsqlite_free_table; sqlite_freemem: Tsqlite_freemem; sqlite_libversion: Tsqlite_libversion; sqlite_libencoding: Tsqlite_libencoding; sqlite_create_function: Tsqlite_create_function; sqlite_create_aggregate: Tsqlite_create_aggregate; sqlite_function_type: Tsqlite_function_type; sqlite_set_result_string: Tsqlite_set_result_string; sqlite_set_result_int: Tsqlite_set_result_int; sqlite_set_result_double: Tsqlite_set_result_double; sqlite_set_result_error: Tsqlite_set_result_error; sqlite_user_data: Tsqlite_user_data; sqlite_aggregate_context: Tsqlite_aggregate_context; sqlite_aggregate_count: Tsqlite_aggregate_count; sqlite_set_authorizer: Tsqlite_set_authorizer; sqlite_trace: Tsqlite_trace; sqlite_progress_handler: Tsqlite_progress_handler; sqlite_commit_hook: Tsqlite_commit_hook; sqlite_open_encrypted: Tsqlite_open_encrypted; sqlite_rekey: Tsqlite_rekey; sqlite_key: Tsqlite_key; end; type {** Represents a generic interface to SQLite native API. } IZSQLitePlainDriver = interface (IZPlainDriver) ['{B931C952-3076-4ECB-9630-D900E8DB9869}'] function Open(const filename: PAnsiChar; mode: Integer; var errmsg: PAnsiChar): Psqlite; function Close(db: Psqlite): Integer; function Execute(db: Psqlite; const sql: PAnsiChar; sqlite_callback: Tsqlite_callback; arg: Pointer; var errmsg: PAnsiChar): Integer; function LastInsertRowId(db: Psqlite): Int64; function Changes(db: Psqlite): Integer; function LastStatementChanges(db: Psqlite): Integer; function ErrorString(db: Psqlite; code: Integer): String; procedure Interrupt(db: Psqlite); function Complete(const sql: PAnsiChar): Integer; procedure BusyHandler(db: Psqlite; callback: Tsqlite_busy_callback; ptr: Pointer); procedure BusyTimeout(db: Psqlite; ms: Integer); function GetTable(db: Psqlite; const sql: PAnsiChar; var resultp: PPAnsiChar; var nrow: Integer; var ncolumn: Integer; var errmsg: PAnsiChar): Integer; procedure FreeTable(var result: PAnsiChar); procedure FreeMem(ptr: Pointer); function LibVersion: PAnsiChar; function LibEncoding: PAnsiChar; function CreateFunction(db: Psqlite; const zName: PAnsiChar; nArg: Integer; callback: Tsqlite_function_callback; pUserData: Pointer): Integer; function CreateAggregate(db: Psqlite; const zName: PAnsiChar; nArg: Integer; callback: Tsqlite_function_callback; finalize: Tsqlite_finalize_callback; pUserData: Pointer): Integer; function FunctionType(db: Psqlite; const zName: PAnsiChar; datatype: Integer): Integer; function SetResultString(func: Psqlite_func; const arg: PAnsiChar; len: Integer): PAnsiChar; procedure SetResultInt(func: Psqlite_func; arg: Integer); procedure SetResultDouble(func: Psqlite_func; arg: Double); procedure SetResultError(func: Psqlite_func; const arg: PAnsiChar; len: Integer); function UserData(func: Psqlite_func): Pointer; function AggregateContext(func: Psqlite_func; nBytes: Integer): Pointer; function AggregateCount(func: Psqlite_func): Integer; function SetAuthorizer(db: Psqlite; callback: Tsqlite_auth_callback; pUserData: Pointer): Integer; function Trace(db: Psqlite; callback: Tsqlite_trace_callback; ptr: Pointer): Pointer; { Prepared statmenet api } function Prepare(db: Psqlite; const zSql: PAnsiChar; nBytes: Integer; out ppStmt: Psqlite3_stmt; pzTail: PPAnsichar): Integer; function Prepare_v2(db: Psqlite; const zSql: PAnsiChar; nBytes: Integer; out ppStmt: Psqlite3_stmt; pzTail: PPAnsichar): Integer; function Prepare16(db: Psqlite; const zSql: PWideChar; nBytes: Integer; out ppStmt: Psqlite3_stmt; pzTail: ZPPWideChar): Integer; function Prepare16_v2(db: Psqlite; const zSql: PWideChar; nBytes: Integer; out ppStmt: Psqlite3_stmt; pzTail: ZPPWideChar): Integer; function bind_parameter_count(pStmt: Psqlite3_stmt): Integer; function bind_parameter_name(pStmt: Psqlite3_stmt; ParamIndex: Integer): PAnsichar; function bind_parameter_index(pStmt: Psqlite3_stmt; const zName: PAnsiChar): Integer; function clear_bindings(pStmt: Psqlite3_stmt): Integer; function column_count(pStmt: Psqlite3_stmt): Integer; function column_name(pStmt: Psqlite3_stmt; iCol: Integer): PAnsiChar; function column_name16(pStmt: Psqlite3_stmt; iCol: Integer): PWideChar; function column_database_name(pStmt: Psqlite3_stmt; iCol: Integer): PAnsiChar; function column_database_name16(pStmt: Psqlite3_stmt; iCol: Integer): PWideChar; function column_table_name(pStmt: Psqlite3_stmt; iCol: Integer): PAnsiChar; function column_table_name16(pStmt: Psqlite3_stmt; iCol: Integer): PWideChar; function column_origin_name(pStmt: Psqlite3_stmt; iCol: Integer): PAnsiChar; function column_origin_name16(pStmt: Psqlite3_stmt; iCol: Integer): PWideChar; function column_decltype(pStmt: Psqlite3_stmt; iCol: Integer): PAnsiChar; function column_decltype16(pStmt: Psqlite3_stmt; iCol: Integer): PWideChar; function Step(Stmt: Psqlite3_stmt; var pN: Integer; var pazValue, pazColName: PPAnsiChar): Integer; overload; function Step(Stmt: Psqlite3_stmt): Integer; overload; function data_count(pStmt: Psqlite3_stmt): Integer; function bind_blob(pStmt: Psqlite3_stmt; ParamIndex: Integer; const Buffer: Pointer; N: Integer; ValDestructor: Tsqlite3_destructor_type): Integer; function bind_double(pStmt: Psqlite3_stmt; ParamIndex: Integer; Value: Double): Integer; function bind_int(pStmt: Psqlite3_stmt; ParamIndex: Integer; Value: Integer): Integer; function bind_int64(pStmt: Psqlite3_stmt; ParamIndex: Integer; Value: Int64): Integer; function bind_null(pStmt: Psqlite3_stmt; ParamIndex: Integer): Integer; function bind_text(pStmt: Psqlite3_stmt; ParamIndex: Integer; const Text: PAnsiChar; N: Integer; ValDestructor: Tsqlite3_destructor_type): Integer; function bind_text16(pStmt: Psqlite3_stmt; ParamIndex: Integer; const Text: PWideChar; N: Integer; ValDestructor: Tsqlite3_destructor_type): Integer; function bind_value(pStmt: Psqlite3_stmt; ParamIndex: Integer; const Value: Psqlite3_value): Integer; function bind_zeroblob(pStmt: Psqlite3_stmt; ParamIndex: Integer; N: Integer): Integer; function finalize(pStmt: Psqlite3_stmt): Integer; function reset(pStmt: Psqlite3_stmt): Integer; function column_blob(Stmt: Psqlite3_stmt; iCol:integer): TStream; function column_bytes(Stmt: Psqlite3_stmt; iCol: Integer): integer; function column_bytes16(Stmt: Psqlite3_stmt; iCol: Integer): integer; function column_double(Stmt: Psqlite3_stmt; iCol: Integer): Double; function column_int(Stmt: Psqlite3_stmt; iCol: Integer): Integer; function column_int64(Stmt: Psqlite3_stmt; iCol: Integer): Int64; function column_text(Stmt: Psqlite3_stmt; iCol: Integer): PAnsiChar; function column_text16(Stmt: Psqlite3_stmt; iCol: Integer): PWideChar; function column_type(Stmt: Psqlite3_stmt; iCol: Integer): String; function column_value(Stmt: Psqlite3_stmt; iCol: Integer): Psqlite3_value; procedure ProgressHandler(db: Psqlite; p1: Integer; callback: Tsqlite_simple_callback; ptr: Pointer); function CommitHook(db: Psqlite; callback: Tsqlite_simple_callback; ptr: Pointer): Pointer; function OpenEncrypted(const zFilename: PAnsiChar; const pKey: PAnsiChar; nKey: Integer; var pErrcode: Integer; var pzErrmsg: PAnsiChar): Psqlite; function ReKey(db: Psqlite; const pKey: Pointer; nKey: Integer): Integer; function Key(db: Psqlite; const pKey: Pointer; nKey: Integer): Integer; end; {** Implements a base driver for SQLite} TZSQLiteBaseDriver = class (TZAbstractPlainDriver, IZPlainDriver, IZSQLitePlainDriver) protected SQLite_API : TZSQLite_API; // procedure LoadApi; override; ->completely done in version dependent child classes function GetUnicodeCodePageName: String; override; procedure LoadCodePages; override; public constructor Create; function Open(const filename: PAnsiChar; mode: Integer; var errmsg: PAnsiChar): Psqlite; function Close(db: Psqlite): Integer; function Execute(db: Psqlite; const sql: PAnsiChar; sqlite_callback: Tsqlite_callback; arg: Pointer; var errmsg: PAnsiChar): Integer; function LastInsertRowId(db: Psqlite): Int64; function Changes(db: Psqlite): Integer; function LastStatementChanges(db: Psqlite): Integer; function ErrorString(db: Psqlite; code: Integer): String; procedure Interrupt(db: Psqlite); function Complete(const sql: PAnsiChar): Integer; procedure BusyHandler(db: Psqlite; callback: Tsqlite_busy_callback; ptr: Pointer); procedure BusyTimeout(db: Psqlite; ms: Integer); function GetTable(db: Psqlite; const sql: PAnsiChar; var resultp: PPAnsiChar; var nrow: Integer; var ncolumn: Integer; var errmsg: PAnsiChar): Integer; procedure FreeTable(var result: PAnsiChar); procedure FreeMem(ptr: Pointer); function LibVersion: PAnsiChar; function LibEncoding: PAnsiChar; function CreateFunction(db: Psqlite; const zName: PAnsiChar; nArg: Integer; callback: Tsqlite_function_callback; pUserData: Pointer): Integer; virtual; function CreateAggregate(db: Psqlite; const zName: PAnsiChar; nArg: Integer; callback: Tsqlite_function_callback; finalize: Tsqlite_finalize_callback; pUserData: Pointer): Integer; function FunctionType(db: Psqlite; const zName: PAnsiChar; datatype: Integer): Integer; function SetResultString(func: Psqlite_func; const arg: PAnsiChar; len: Integer): PAnsiChar; procedure SetResultInt(func: Psqlite_func; arg: Integer); procedure SetResultDouble(func: Psqlite_func; arg: Double); procedure SetResultError(func: Psqlite_func; const arg: PAnsiChar; len: Integer); function UserData(func: Psqlite_func): Pointer; function AggregateContext(func: Psqlite_func; nBytes: Integer): Pointer; function AggregateCount(func: Psqlite_func): Integer; function SetAuthorizer(db: Psqlite; callback: Tsqlite_auth_callback; pUserData: Pointer): Integer; function Trace(db: Psqlite; callback: Tsqlite_trace_callback; ptr: Pointer): Pointer; { Prepared statmenet api } function Prepare(db: Psqlite; const zSql: PAnsiChar; nBytes: Integer; out ppStmt: Psqlite3_stmt; pzTail: PPAnsichar): Integer; function Prepare_v2(db: Psqlite; const zSql: PAnsiChar; nBytes: Integer; out ppStmt: Psqlite3_stmt; pzTail: PPAnsichar): Integer; function Prepare16(db: Psqlite; const zSql: PWideChar; nBytes: Integer; out ppStmt: Psqlite3_stmt; pzTail: ZPPWideChar): Integer; function Prepare16_v2(db: Psqlite; const zSql: PWideChar; nBytes: Integer; out ppStmt: Psqlite3_stmt; pzTail: ZPPWideChar): Integer; function bind_parameter_count(pStmt: Psqlite3_stmt): Integer; function bind_parameter_name(pStmt: Psqlite3_stmt; ParamIndex: Integer): PAnsichar; function bind_parameter_index(pStmt: Psqlite3_stmt; const zName: PAnsiChar): Integer; function clear_bindings(pStmt: Psqlite3_stmt): Integer; function column_count(pStmt: Psqlite3_stmt): Integer; function column_name(pStmt: Psqlite3_stmt; iCol: Integer): PAnsiChar; function column_name16(pStmt: Psqlite3_stmt; iCol: Integer): PWideChar; function column_database_name(pStmt: Psqlite3_stmt; iCol: Integer): PAnsiChar; function column_database_name16(pStmt: Psqlite3_stmt; iCol: Integer): PWideChar; function column_table_name(pStmt: Psqlite3_stmt; iCol: Integer): PAnsiChar; function column_table_name16(pStmt: Psqlite3_stmt; iCol: Integer): PWideChar; function column_origin_name(pStmt: Psqlite3_stmt; iCol: Integer): PAnsiChar; function column_origin_name16(pStmt: Psqlite3_stmt; iCol: Integer): PWideChar; function column_decltype(pStmt: Psqlite3_stmt; iCol: Integer): PAnsiChar; function column_decltype16(pStmt: Psqlite3_stmt; iCol: Integer): PWideChar; function Step(Stmt: Psqlite3_stmt; var pN: Integer; var pazValue, pazColName: PPAnsiChar): Integer; overload; function Step(Stmt: Psqlite3_stmt): Integer; overload; function data_count(pStmt: Psqlite3_stmt): Integer; function bind_blob(pStmt: Psqlite3_stmt; ParamIndex: Integer; const Buffer: Pointer; N: Integer; ValDestructor: Tsqlite3_destructor_type): Integer; function bind_double(pStmt: Psqlite3_stmt; ParamIndex: Integer; Value: Double): Integer; function bind_int(pStmt: Psqlite3_stmt; ParamIndex: Integer; Value: Integer): Integer; function bind_int64(pStmt: Psqlite3_stmt; ParamIndex: Integer; Value: Int64): Integer; function bind_null(pStmt: Psqlite3_stmt; ParamIndex: Integer): Integer; function bind_text(pStmt: Psqlite3_stmt; ParamIndex: Integer; const Text: PAnsiChar; N: Integer; ValDestructor: Tsqlite3_destructor_type): Integer; function bind_text16(pStmt: Psqlite3_stmt; ParamIndex: Integer; const Text: PWideChar; N: Integer; ValDestructor: Tsqlite3_destructor_type): Integer; function bind_value(pStmt: Psqlite3_stmt; ParamIndex: Integer; const Value: Psqlite3_value): Integer; function bind_zeroblob(pStmt: Psqlite3_stmt; ParamIndex: Integer; N: Integer): Integer; function finalize(pStmt: Psqlite3_stmt): Integer; function reset(pStmt: Psqlite3_stmt): Integer; function column_blob(Stmt: Psqlite3_stmt; iCol:integer): TStream; function column_bytes(Stmt: Psqlite3_stmt; iCol: Integer): integer; function column_bytes16(Stmt: Psqlite3_stmt; iCol: Integer): integer; function column_double(Stmt: Psqlite3_stmt; iCol: Integer): Double; function column_int(Stmt: Psqlite3_stmt; iCol: Integer): Integer; function column_int64(Stmt: Psqlite3_stmt; iCol: Integer): Int64; function column_text(Stmt: Psqlite3_stmt; iCol: Integer): PAnsiChar; function column_text16(Stmt: Psqlite3_stmt; iCol: Integer): PWideChar; function column_type(Stmt: Psqlite3_stmt; iCol: Integer): String; function column_value(Stmt: Psqlite3_stmt; iCol: Integer): Psqlite3_value; procedure ProgressHandler(db: Psqlite; p1: Integer; callback: Tsqlite_simple_callback; ptr: Pointer); function CommitHook(db: Psqlite; callback: Tsqlite_simple_callback; ptr: Pointer): Pointer; function OpenEncrypted(const zFilename: PAnsiChar; const pKey: PAnsiChar; nKey: Integer; var pErrcode: Integer; var pzErrmsg: PAnsiChar): Psqlite; function ReKey(db: Psqlite; const pKey: Pointer; nKey: Integer): Integer; function Key(db: Psqlite; const pKey: Pointer; nKey: Integer): Integer; end; {** Implements a driver for SQLite 3 } TZSQLite3PlainDriver = class (TZSQLiteBaseDriver, IZPlainDriver, IZSQLitePlainDriver) protected function Clone: IZPlainDriver; override; procedure LoadApi; override; public constructor Create; function GetProtocol: string; override; function GetDescription: string; override; end; implementation uses ZPlainLoader, ZEncoding; { TZSQLiteBaseDriver } function TZSQLiteBaseDriver.GetUnicodeCodePageName: String; begin Result := 'UTF-8' end; procedure TZSQLiteBaseDriver.LoadCodePages; //Egonhugeist begin { MultiByte } AddCodePage('UTF-8', 1, ceUTF8, zCP_UTF8); AddCodePage('UTF-16le', 2, ceUTF16, zCP_UTF16, 'UTF-8'); //Setting this will be ignored by actual Excute of Plaindriver AddCodePage('UTF-16be', 3, ceUTF16, zCP_UTF16BE, 'UTF-8'); //Setting this will be ignored by actual Excute of Plaindriver AddCodePage('UTF-16', 4, ceUTF16, zCP_UTF16, 'UTF-8'); //Setting this will be ignored by actual Excute of Plaindriver end; constructor TZSQLiteBaseDriver.Create; begin inherited create; FLoader := TZNativeLibraryLoader.Create([]); {$IFNDEF UNIX} FLoader.AddLocation(WINDOWS_DLL_LOCATION); {$ELSE} FLoader.AddLocation(LINUX_DLL_LOCATION); FLoader.AddLocation(LINUX_DLL_LOCATION+'.0'); {$ENDIF} end; function TZSQLiteBaseDriver.AggregateContext(func: Psqlite_func; nBytes: Integer): Pointer; begin Result := SQLite_API.sqlite_aggregate_context(func, nBytes); end; function TZSQLiteBaseDriver.AggregateCount(func: Psqlite_func): Integer; begin Result := SQLite_API.sqlite_aggregate_count(func); end; procedure TZSQLiteBaseDriver.BusyHandler(db: Psqlite; callback: Tsqlite_busy_callback; ptr: Pointer); begin SQLite_API.sqlite_busy_handler(db, callback, ptr); end; procedure TZSQLiteBaseDriver.BusyTimeout(db: Psqlite; ms: Integer); begin SQLite_API.sqlite_busy_timeout(db, ms); end; function TZSQLiteBaseDriver.Changes(db: Psqlite): Integer; begin Result := SQLite_API.sqlite_changes(db); end; function TZSQLiteBaseDriver.CommitHook(db: Psqlite; callback: Tsqlite_simple_callback; ptr: Pointer): Pointer; begin Result := SQLite_API.sqlite_commit_hook(db, callback, ptr); end; function TZSQLiteBaseDriver.Complete(const sql: PAnsiChar): Integer; begin Result := SQLite_API.sqlite_complete(sql); end; function TZSQLiteBaseDriver.CreateAggregate(db: Psqlite; const zName: PAnsiChar; nArg: Integer; callback: Tsqlite_function_callback; finalize: Tsqlite_finalize_callback; pUserData: Pointer): Integer; begin Result := SQLITE_MISUSE; end; function TZSQLiteBaseDriver.CreateFunction(db: Psqlite; const zName: PAnsiChar; nArg: Integer; callback: Tsqlite_function_callback; pUserData: Pointer): Integer; begin Result := SQLITE_MISUSE; end; function TZSQLiteBaseDriver.ErrorString(db: Psqlite; code: Integer): String; var ErrorMessagePointer: PAnsiChar; ErrorMessage: String; ErrorString: String; begin if code = SQLITE_OK then begin Result := 'not an error'; Exit; end; if code = SQLITE_NOMEM then begin Result := 'out of memory'; Exit; end; if ( db = nil ) or ( @SQLite_API.sqlite_errstr = nil ) then begin case code of SQLITE_OK: Result := 'not an error'; SQLITE_ERROR: Result := 'SQL logic error or missing database'; SQLITE_INTERNAL: Result := 'internal SQLite implementation flaw'; SQLITE_PERM: Result := 'access permission denied'; SQLITE_ABORT: Result := 'callback requested query abort'; SQLITE_BUSY: Result := 'database is locked'; SQLITE_LOCKED: Result := 'database table is locked'; SQLITE_NOMEM: Result := 'out of memory'; SQLITE_READONLY: Result := 'attempt to write a readonly database'; _SQLITE_INTERRUPT: Result := 'interrupted'; SQLITE_IOERR: Result := 'disk I/O error'; SQLITE_CORRUPT: Result := 'database disk image is malformed'; SQLITE_NOTFOUND: Result := 'table or record not found'; SQLITE_FULL: Result := 'database is full'; SQLITE_CANTOPEN: Result := 'unable to open database file'; SQLITE_PROTOCOL: Result := 'database locking protocol failure'; SQLITE_EMPTY: Result := 'table contains no data'; SQLITE_SCHEMA: Result := 'database schema has changed'; SQLITE_TOOBIG: Result := 'too much data for one table row'; SQLITE_CONSTRAINT: Result := 'constraint failed'; SQLITE_MISMATCH: Result := 'datatype mismatch'; SQLITE_MISUSE: Result := 'library routine called out of sequence'; SQLITE_NOLFS: Result := 'kernel lacks large file support'; SQLITE_AUTH: Result := 'authorization denied'; SQLITE_FORMAT: Result := 'auxiliary database format error'; SQLITE_RANGE: Result := 'bind index out of range'; SQLITE_NOTADB: Result := 'file is encrypted or is not a database'; else Result := 'unknown error'; end; exit; end else begin ErrorMessagePointer := Self.SQLite_API.sqlite_errstr(code); {$IFDEF UNICODE} ErrorString := Trim(UTF8ToUnicodeString(ErrorMessagePointer)); {$ELSE} {$IFNDEF FPC} ErrorString := Trim(UTF8ToAnsi(StrPas(ErrorMessagePointer))); {$ELSE} ErrorString := Trim(ErrorMessagePointer); {$ENDIF} {$ENDIF} ErrorMessagePointer := Self.SQLite_API.sqlite_errmsg(db); {$IFDEF UNICODE} ErrorMessage := Trim(UTF8ToUnicodeString(ErrorMessagePointer)); {$ELSE} {$IFNDEF FPC} ErrorMessage := Trim(UTF8ToAnsi(ErrorMessagePointer)); {$ELSE} ErrorMessage := Trim(ErrorMessagePointer); {$ENDIF} {$ENDIF} Result := ErrorString + ': ' + ErrorMessage; end; end; function TZSQLiteBaseDriver.Execute(db: Psqlite; const sql: PAnsiChar; sqlite_callback: Tsqlite_callback; arg: Pointer; var errmsg: PAnsiChar): Integer; begin errmsg:= nil; Result := SQLite_API.sqlite_exec(db, sql, sqlite_callback, arg, errmsg); end; procedure TZSQLiteBaseDriver.FreeMem(ptr: Pointer); begin SQLite_API.sqlite_freemem(ptr); end; procedure TZSQLiteBaseDriver.FreeTable(var result: PAnsiChar); begin SQLite_API.sqlite_free_table(result); end; function TZSQLiteBaseDriver.FunctionType(db: Psqlite; const zName: PAnsiChar; datatype: Integer): Integer; begin Result := SQLITE_MISUSE; end; function TZSQLiteBaseDriver.GetTable(db: Psqlite; const sql: PAnsiChar; var resultp: PPAnsiChar; var nrow, ncolumn: Integer; var errmsg: PAnsiChar): Integer; begin Result := SQLite_API.sqlite_get_table(db, sql, resultp, nrow, ncolumn, errmsg); end; procedure TZSQLiteBaseDriver.Interrupt(db: Psqlite); begin SQLite_API.sqlite_interrupt(db); end; function TZSQLiteBaseDriver.LastInsertRowId(db: Psqlite): Int64; begin Result := SQLite_API.sqlite_last_insert_rowid(db); end; function TZSQLiteBaseDriver.LastStatementChanges(db: Psqlite): Integer; begin Result := SQLITE_MISUSE; end; function TZSQLiteBaseDriver.LibEncoding: PAnsiChar; begin Result := nil; end; function TZSQLiteBaseDriver.LibVersion: PAnsiChar; begin Result := SQLite_API.sqlite_libversion; end; function TZSQLiteBaseDriver.Open(const filename: PAnsiChar; mode: Integer; var errmsg: PAnsiChar): Psqlite; var Result0: Psqlite; {$IFNDEF UNICODE} Version: string; FileNameString: String; {$ENDIF} begin Result0:= nil; (*Note to Windows users: The encoding used for the filename argument of sqlite3_open() and sqlite3_open_v2() must be UTF-8, not whatever codepage is currently defined. Filenames containing international characters must be converted to UTF-8 prior to passing them into sqlite3_open() or sqlite3_open_v2(). *) {$IFDEF UNICODE} SQLite_API.sqlite_open(filename, Result0); {$ELSE} Version := LibVersion; FileNameString := filename; if (Version > '3.2.5') then {$IFDEF FPC} SQLite_API.sqlite_open(PAnsiChar(FileNameString), Result0) {$ELSE} SQLite_API.sqlite_open(PAnsiChar(AnsiToUTF8(FileNameString)), Result0) {$ENDIF} else SQLite_API.sqlite_open(filename, Result0); {$ENDIF} Result := Result0; end; function TZSQLiteBaseDriver.OpenEncrypted(const zFilename, pKey: PAnsiChar; nKey: Integer; var pErrcode: Integer; var pzErrmsg: PAnsiChar): Psqlite; begin pErrcode := SQLITE_MISUSE; pzErrmsg := 'function is not used in the current version of the library'; Result:= nil; end; procedure TZSQLiteBaseDriver.ProgressHandler(db: Psqlite; p1: Integer; callback: Tsqlite_simple_callback; ptr: Pointer); begin SQLite_API.sqlite_progress_handler(db, p1, callback, ptr); end; function TZSQLiteBaseDriver.ReKey(db: Psqlite; const pKey: Pointer; nKey: Integer): Integer; begin if @SQLite_API.sqlite_rekey = nil then begin Result := SQLITE_OK; end else begin Result := SQLite_API.sqlite_rekey(db, pKey, nKey); end; end; function TZSQLiteBaseDriver.Key(db: Psqlite; const pKey: Pointer; nKey: Integer): Integer; begin if @SQLite_API.sqlite_key = nil then begin Result := SQLITE_OK; end else begin Result := SQLite_API.sqlite_key(db, pKey, nKey); end; end; function TZSQLiteBaseDriver.SetAuthorizer(db: Psqlite; callback: Tsqlite_auth_callback; pUserData: Pointer): Integer; begin Result := SQLite_API.sqlite_set_authorizer(db, callback, pUserData); end; procedure TZSQLiteBaseDriver.SetResultDouble(func: Psqlite_func; arg: Double); begin SQLite_API.sqlite_set_result_double(func, arg); end; procedure TZSQLiteBaseDriver.SetResultError(func: Psqlite_func; const arg: PAnsiChar; len: Integer); begin SQLite_API.sqlite_set_result_error(func, arg, len); end; procedure TZSQLiteBaseDriver.SetResultInt(func: Psqlite_func; arg: Integer); begin SQLite_API.sqlite_set_result_int(func, arg); end; function TZSQLiteBaseDriver.SetResultString(func: Psqlite_func; const arg: PAnsiChar; len: Integer): PAnsiChar; begin Result := SQLite_API.sqlite_set_result_string(func, arg, len, nil); end; { Prepared statmenet api } function TZSQLiteBaseDriver.Prepare(db: Psqlite; const zSql: PAnsiChar; nBytes: Integer; out ppStmt: Psqlite3_stmt; pzTail: PPAnsichar): Integer; begin Result := SQLite_API.sqlite_prepare(db, zSql, nBytes, ppStmt, pzTail); end; function TZSQLiteBaseDriver.Prepare_v2(db: Psqlite; const zSql: PAnsiChar; nBytes: Integer; out ppStmt: Psqlite3_stmt; pzTail: PPAnsichar): Integer; begin Result := SQLite_API.sqlite_prepare_v2(db, zSql, nBytes, ppStmt, pzTail); end; function TZSQLiteBaseDriver.Prepare16(db: Psqlite; const zSql: PWideChar; nBytes: Integer; out ppStmt: Psqlite3_stmt; pzTail: ZPPWideChar): Integer; begin Result := SQLite_API.sqlite_prepare16(db, zSql, nBytes, ppStmt, pzTail); end; function TZSQLiteBaseDriver.Prepare16_v2(db: Psqlite; const zSql: PWideChar; nBytes: Integer; out ppStmt: Psqlite3_stmt; pzTail: ZPPWideChar): Integer; begin Result := SQLite_API.sqlite_prepare16_v2(db, zSql, nBytes, ppStmt, pzTail); end; function TZSQLiteBaseDriver.bind_parameter_count(pStmt: Psqlite3_stmt): Integer; begin Result := SQLite_API.sqlite_bind_parameter_count(pStmt); end; function TZSQLiteBaseDriver.bind_parameter_name(pStmt: Psqlite3_stmt; ParamIndex: Integer): PAnsichar; begin Result := SQLite_API.sqlite_bind_parameter_name(pStmt, ParamIndex); end; function TZSQLiteBaseDriver.bind_parameter_index(pStmt: Psqlite3_stmt; const zName: PAnsiChar): Integer; begin Result := SQLite_API.sqlite_bind_parameter_index(pStmt, ZName); end; function TZSQLiteBaseDriver.clear_bindings(pStmt: Psqlite3_stmt): Integer; begin Result := SQLite_API.sqlite_clear_bindings(pStmt); end; function TZSQLiteBaseDriver.column_count(pStmt: Psqlite3_stmt): Integer; begin Result := SQLite_API.sqlite_column_count(pStmt); end; function TZSQLiteBaseDriver.column_name(pStmt: Psqlite3_stmt; iCol: Integer): PAnsiChar; begin Result := SQLite_API.sqlite_column_name(pStmt, iCol); end; function TZSQLiteBaseDriver.column_name16(pStmt: Psqlite3_stmt; iCol: Integer): PWideChar; begin Result := SQLite_API.sqlite_column_name16(pStmt, iCol); end; function TZSQLiteBaseDriver.column_database_name(pStmt: Psqlite3_stmt; iCol: Integer): PAnsiChar; begin Result := SQLite_API.sqlite_column_database_name(pStmt, iCol); end; function TZSQLiteBaseDriver.column_database_name16(pStmt: Psqlite3_stmt; iCol: Integer): PWideChar; begin Result := SQLite_API.sqlite_column_database_name16(pStmt, iCol); end; function TZSQLiteBaseDriver.column_table_name(pStmt: Psqlite3_stmt; iCol: Integer): PAnsiChar; begin Result := SQLite_API.sqlite_column_table_name(pStmt, iCol); end; function TZSQLiteBaseDriver.column_table_name16(pStmt: Psqlite3_stmt; iCol: Integer): PWideChar; begin Result := SQLite_API.sqlite_column_table_name16(pStmt, iCol); end; function TZSQLiteBaseDriver.column_origin_name(pStmt: Psqlite3_stmt; iCol: Integer): PAnsiChar; begin Result := SQLite_API.sqlite_column_origin_name(pStmt, iCol); end; function TZSQLiteBaseDriver.column_origin_name16(pStmt: Psqlite3_stmt; iCol: Integer): PWideChar; begin Result := SQLite_API.sqlite_column_origin_name16(pStmt, iCol); end; function TZSQLiteBaseDriver.column_decltype(pStmt: Psqlite3_stmt; iCol: Integer): PAnsiChar; begin Result := SQLite_API.sqlite_column_decltype(pStmt, iCol); end; function TZSQLiteBaseDriver.column_decltype16(pStmt: Psqlite3_stmt; iCol: Integer): PWideChar; begin Result := SQLite_API.sqlite_column_decltype16(pStmt, iCol); end; function TZSQLiteBaseDriver.Step(Stmt: Psqlite3_stmt; var pN: Integer; var pazValue, pazColName: PPAnsiChar): Integer; var i: Integer; val, cname,ctype: PAnsiChar; pazValue0, pazColName0, pazColType: PPAnsiChar; begin pazValue0 := nil; // satisfy compiler Result := SQLite_API.sqlite_step(Stmt); if (Result = SQLITE_ROW) or (Result = SQLITE_DONE) then begin pN:= SQLite_API.sqlite_column_count(Stmt); if Result = SQLITE_ROW then begin pazValue:= AllocMem(SizeOf(PPAnsiChar)*(pN+1)); pazValue0:= pazValue; end; pazColName:= AllocMem(SizeOf(PPAnsiChar)*(pN+1)*2); pazColName0:= pazColName; pazColType:= pazColName; Inc(pazColType, pN); for i := 0 to pN - 1 do begin if Result = SQLITE_ROW then begin cname:= SQLite_API.sqlite_column_name(Stmt, i); ctype:= SQLite_API.sqlite_column_decltype(Stmt, i); val := SQLite_API.sqlite_column_text(Stmt, i); pazValue0^ := val; inc(pazValue0); end else begin cname:= SQLite_API.sqlite_column_name(Stmt, i); ctype:= SQLite_API.sqlite_column_decltype(Stmt, i); end; pazColName0^:= cname; pazColType^ := ctype; inc(pazColName0); inc(pazColType); end; if Result = SQLITE_ROW then pazValue0^ := nil; pazColType^:= nil; if Result = SQLITE_DONE then pazValue := nil; end; end; function TZSQLiteBaseDriver.Step(Stmt: Psqlite3_stmt): Integer; begin Result := SQLite_API.sqlite_step(Stmt); end; function TZSQLiteBaseDriver.data_count(pStmt: Psqlite3_stmt): Integer; begin Result := SQLite_API.sqlite_data_count(pStmt); end; function TZSQLiteBaseDriver.bind_blob(pStmt: Psqlite3_stmt; ParamIndex: Integer; const Buffer: Pointer; N: Integer; ValDestructor: Tsqlite3_destructor_type): Integer; begin Result := SQLite_API.sqlite_bind_blob(pStmt, ParamIndex, Buffer, N, ValDestructor); end; function TZSQLiteBaseDriver.bind_double(pStmt: Psqlite3_stmt; ParamIndex: Integer; Value: Double): Integer; begin Result := SQLite_API.sqlite_bind_double(pStmt, ParamIndex, Value); end; function TZSQLiteBaseDriver.bind_int(pStmt: Psqlite3_stmt; ParamIndex: Integer; Value: Integer): Integer; begin Result := SQLite_API.sqlite_bind_int(pStmt, ParamIndex, Value); end; function TZSQLiteBaseDriver.bind_int64(pStmt: Psqlite3_stmt; ParamIndex: Integer; Value: Int64): Integer; begin Result := SQLite_API.sqlite_bind_int64(pStmt, ParamIndex, Value); end; function TZSQLiteBaseDriver.bind_null(pStmt: Psqlite3_stmt; ParamIndex: Integer): Integer; begin Result := SQLite_API.sqlite_bind_null(pStmt, ParamIndex); end; function TZSQLiteBaseDriver.bind_text(pStmt: Psqlite3_stmt; ParamIndex: Integer; const Text: PAnsiChar; N: Integer; ValDestructor: Tsqlite3_destructor_type): Integer; begin Result := SQLite_API.sqlite_bind_text(pStmt, ParamIndex, Text, N, ValDestructor); end; function TZSQLiteBaseDriver.bind_text16(pStmt: Psqlite3_stmt; ParamIndex: Integer; const Text: PWideChar; N: Integer; ValDestructor: Tsqlite3_destructor_type): Integer; begin Result := SQLite_API.sqlite_bind_text16(pStmt, ParamIndex, Text, N, ValDestructor); end; function TZSQLiteBaseDriver.bind_value(pStmt: Psqlite3_stmt; ParamIndex: Integer; const Value: Psqlite3_value): Integer; begin Result := SQLite_API.sqlite_bind_value(pStmt, ParamIndex, Value); end; function TZSQLiteBaseDriver.bind_zeroblob(pStmt: Psqlite3_stmt; ParamIndex: Integer; N: Integer): Integer; begin Result := SQLite_API.sqlite_bind_zeroblob(pStmt, ParamIndex, N); end; function TZSQLiteBaseDriver.finalize(pStmt: Psqlite3_stmt): Integer; begin Result := SQLite_API.sqlite_finalize(pStmt); end; function TZSQLiteBaseDriver.reset(pStmt: Psqlite3_stmt): Integer; begin Result := SQLite_API.sqlite_reset(pStmt); end; function TZSQLiteBaseDriver.column_blob(Stmt: Psqlite3_stmt; iCol:integer): TStream; var P : Pointer; len : integer; begin result := TMemoryStream.Create; P := SQLite_API.sqlite_column_blob(Stmt, iCol-1); len := SQLite_API.sqlite_column_bytes(Stmt, iCol-1); result.WriteBuffer(P^,len); end; function TZSQLiteBaseDriver.column_bytes(Stmt: Psqlite3_stmt; iCol: Integer): integer; begin Result := SQLite_API.sqlite_column_bytes(Stmt, iCol); end; function TZSQLiteBaseDriver.column_bytes16(Stmt: Psqlite3_stmt; iCol: Integer): integer; begin Result := SQLite_API.sqlite_column_bytes16(Stmt, iCol); end; function TZSQLiteBaseDriver.column_double(Stmt: Psqlite3_stmt; iCol: Integer): Double; begin Result := SQLite_API.sqlite_column_double(Stmt, iCol); end; function TZSQLiteBaseDriver.column_int(Stmt: Psqlite3_stmt; iCol: Integer): Integer; begin Result := SQLite_API.sqlite_column_int(Stmt, iCol); end; function TZSQLiteBaseDriver.column_int64(Stmt: Psqlite3_stmt; iCol: Integer): Int64; begin Result := SQLite_API.sqlite_column_int64(Stmt, iCol); end; function TZSQLiteBaseDriver.column_text(Stmt: Psqlite3_stmt; iCol: Integer): PAnsiChar; begin Result := SQLite_API.sqlite_column_text(Stmt, iCol); end; function TZSQLiteBaseDriver.column_text16(Stmt: Psqlite3_stmt; iCol: Integer): PWideChar; begin Result := SQLite_API.sqlite_column_text16(Stmt, iCol); end; function TZSQLiteBaseDriver.column_type(Stmt: Psqlite3_stmt; iCol: Integer): String; begin if Assigned(SQLite_API.sqlite_column_type) then case SQLite_API.sqlite_column_type(stmt, iCol) of SQLITE_INTEGER: Result:='INT(19)'; SQLITE_FLOAT: Result:='FLOAT(16)'; SQLITE3_TEXT: //RESULT := 'CHAR'; //EgonHugeist: Need to boil down this type ! //Else Metadatainformations are not readable ! Result:='VARCHAR'; SQLITE_BLOB: Result:='BLOB'; SQLITE_NULL: Result := ''; end else Result:=''; end; function TZSQLiteBaseDriver.column_value(Stmt: Psqlite3_stmt; iCol: Integer): Psqlite3_value; begin Result := SQLite_API.sqlite_column_value(stmt, iCol); end; function TZSQLiteBaseDriver.Trace(db: Psqlite; callback: Tsqlite_trace_callback; ptr: Pointer): Pointer; begin Result := SQLite_API.sqlite_trace(db, callback, ptr); end; function TZSQLiteBaseDriver.UserData(func: Psqlite_func): Pointer; begin Result := SQLite_API.sqlite_user_data(func); end; function TZSQLiteBaseDriver.Close(db: Psqlite): Integer; begin Result := SQLite_API.sqlite_close(db); end; { TZSQLite3PlainDriver } function TZSQLite3PlainDriver.Clone: IZPlainDriver; begin Result := TZSQLite3PlainDriver.Create; end; procedure TZSQLite3PlainDriver.LoadApi; begin { ************** Load adresses of API Functions ************* } with Loader do begin @SQLite_API.sqlite_open := GetAddress('sqlite3_open'); @SQLite_API.sqlite_close := GetAddress('sqlite3_close'); { prepared Statment api } { prepared statement api } @SQLite_API.sqlite_prepare := GetAddress('sqlite3_prepare'); @SQLite_API.sqlite_prepare_v2 := GetAddress('sqlite3_prepare_v2'); @SQLite_API.sqlite_prepare16 := GetAddress('sqlite3_prepare16'); @SQLite_API.sqlite_prepare16_v2 := GetAddress('sqlite3_prepare16_v2'); @SQLite_API.sqlite_bind_parameter_count := GetAddress('sqlite3_bind_parameter_count'); @SQLite_API.sqlite_bind_parameter_name := GetAddress('sqlite3_bind_parameter_name'); @SQLite_API.sqlite_bind_parameter_index := GetAddress('sqlite3_bind_parameter_index'); @SQLite_API.sqlite_clear_bindings := GetAddress('sqlite3_clear_bindings'); @SQLite_API.sqlite_column_count := GetAddress('sqlite3_column_count'); @SQLite_API.sqlite_column_bytes := GetAddress('sqlite3_column_bytes'); @SQLite_API.sqlite_column_bytes16 := GetAddress('sqlite3_column_bytes16'); @SQLite_API.sqlite_Column_blob := GetAddress('sqlite3_column_blob'); @SQLite_API.sqlite_column_double := GetAddress('sqlite3_column_double'); @SQLite_API.sqlite_column_int := GetAddress('sqlite3_column_int'); @SQLite_API.sqlite_column_int64 := GetAddress('sqlite3_column_int64'); @SQLite_API.sqlite_column_text := GetAddress('sqlite3_column_text'); @SQLite_API.sqlite_column_text16 := GetAddress('sqlite3_column_text16'); @SQLite_API.sqlite_column_type := GetAddress('sqlite3_column_type'); @SQLite_API.sqlite_column_value := GetAddress('sqlite3_column_value'); @SQLite_API.sqlite_column_name := GetAddress('sqlite3_column_name'); @SQLite_API.sqlite_column_name16 := GetAddress('sqlite3_column_name16'); @SQLite_API.sqlite_column_database_name := GetAddress('sqlite3_column_database_name'); @SQLite_API.sqlite_column_database_name16 := GetAddress('sqlite3_column_database_name16'); @SQLite_API.sqlite_column_table_name := GetAddress('sqlite3_column_table_name'); @SQLite_API.sqlite_column_table_name16 := GetAddress('sqlite3_column_table_name16'); @SQLite_API.sqlite_column_origin_name := GetAddress('sqlite3_column_origin_name'); @SQLite_API.sqlite_column_origin_name16 := GetAddress('sqlite3_column_origin_name16'); @SQLite_API.sqlite_column_decltype := GetAddress('sqlite3_column_decltype'); @SQLite_API.sqlite_column_decltype16 := GetAddress('sqlite3_column_decltype16'); @SQLite_API.sqlite_step := GetAddress('sqlite3_step'); @SQLite_API.sqlite_data_count := GetAddress('sqlite3_data_count'); @SQLite_API.sqlite_bind_blob := GetAddress('sqlite3_bind_blob'); @SQLite_API.sqlite_bind_double := GetAddress('sqlite3_bind_double'); @SQLite_API.sqlite_bind_int := GetAddress('sqlite3_bind_int'); @SQLite_API.sqlite_bind_int64 := GetAddress('sqlite3_bind_int64'); @SQLite_API.sqlite_bind_null := GetAddress('sqlite3_bind_null'); @SQLite_API.sqlite_bind_text := GetAddress('sqlite3_bind_text'); @SQLite_API.sqlite_bind_text16 := GetAddress('sqlite3_bind_text16'); @SQLite_API.sqlite_bind_value := GetAddress('sqlite3_bind_value'); @SQLite_API.sqlite_bind_zeroblob := GetAddress('sqlite3_bind_zeroblob'); @SQLite_API.sqlite_finalize := GetAddress('sqlite3_finalize'); @SQLite_API.sqlite_reset := GetAddress('sqlite3_reset'); @SQLite_API.sqlite_exec := GetAddress('sqlite3_exec'); @SQLite_API.sqlite_last_insert_rowid := GetAddress('sqlite3_last_insert_rowid'); @SQLite_API.sqlite_changes := GetAddress('sqlite3_changes'); // @SQLite_API.sqlite_last_statement_changes := GetAddress('sqlite3_last_statement_changes'); @SQLite_API.sqlite_errmsg := GetAddress('sqlite3_errmsg'); @SQLite_API.sqlite_errstr := GetAddress('sqlite3_errstr'); @SQLite_API.sqlite_interrupt := GetAddress('sqlite3_interrupt'); @SQLite_API.sqlite_complete := GetAddress('sqlite3_complete'); @SQLite_API.sqlite_busy_handler := GetAddress('sqlite3_busy_handler'); @SQLite_API.sqlite_busy_timeout := GetAddress('sqlite3_busy_timeout'); @SQLite_API.sqlite_get_table := GetAddress('sqlite3_get_table'); @SQLite_API.sqlite_free_table := GetAddress('sqlite3_free_table'); @SQLite_API.sqlite_freemem := GetAddress('sqlite3_free'); @SQLite_API.sqlite_libversion := GetAddress('sqlite3_libversion'); // @SQLite_API.sqlite_libencoding := GetAddress('sqlite3_libencoding'); // @SQLite_API.sqlite_create_function := GetAddress('sqlite3_create_function'); // @SQLite_API.sqlite_create_aggregate := GetAddress('sqlite3_create_aggregate'); // @SQLite_API.sqlite_function_type := GetAddress('sqlite3_function_type'); @SQLite_API.sqlite_set_result_string := GetAddress('sqlite3_result_string'); @SQLite_API.sqlite_set_result_int := GetAddress('sqlite3_result_int'); @SQLite_API.sqlite_set_result_double := GetAddress('sqlite3_result_double'); @SQLite_API.sqlite_set_result_error := GetAddress('sqlite3_result_error'); @SQLite_API.sqlite_user_data := GetAddress('sqlite3_user_data'); @SQLite_API.sqlite_aggregate_context := GetAddress('sqlite3_aggregate_context'); @SQLite_API.sqlite_aggregate_count := GetAddress('sqlite3_aggregate_count'); @SQLite_API.sqlite_set_authorizer := GetAddress('sqlite3_set_authorizer'); @SQLite_API.sqlite_trace := GetAddress('sqlite3_trace'); @SQLite_API.sqlite_progress_handler := GetAddress('sqlite3_progress_handler'); @SQLite_API.sqlite_commit_hook := GetAddress('sqlite3_commit_hook'); // @SQLite_API.sqlite_open_encrypted := GetAddress('sqlite3_open_encrypted'); @SQLite_API.sqlite_rekey := GetAddress('sqlite3_rekey'); @SQLite_API.sqlite_key := GetAddress('sqlite3_key'); end; end; constructor TZSQLite3PlainDriver.Create; begin inherited Create; {$IFNDEF UNIX} FLoader.AddLocation(WINDOWS_DLL3_LOCATION); {$ELSE} FLoader.AddLocation(LINUX_DLL3_LOCATION); FLoader.AddLocation(LINUX_DLL3_LOCATION+'.0'); {$ENDIF} LoadCodePages; end; function TZSQLite3PlainDriver.GetProtocol: string; begin Result := 'sqlite-3'; end; function TZSQLite3PlainDriver.GetDescription: string; begin Result := 'Native Plain Driver for SQLite 3'; end; end. ================================================ FILE: lib/zeosdbo/src/repl.awk ================================================ BEGIN {copy=1} /{@\*+}/ {copy=0;} {if (copy==1) {print $0};} /{\*+@}/ {copy=1; while ((getline line < "../repl.txt") > 0) {print line;} close($2);} ================================================ FILE: lib/zeosdbo/src/repl.instructions ================================================ Replace all copyright info -------------------------- 1. Edit repl.txt 2. Make sure ls, gawk and mv programs are available from command line 3. For each src subdirectory: a. cd into directory b. ls -1|xargs -I {} echo "gawk -f ../repl.awk {}>{}.1">x.bat c. ls -1|xargs -I {} echo "mv -f {}.1 {}">y.bat d. x.bat e. y.bat f. rm x.bat y.bat ================================================ FILE: lib/zeosdbo/src/repl.txt ================================================ {@********************************************************} { Copyright (c) 1999-2012 Zeos Development Group } { } { License Agreement: } { } { This library is distributed in the hope that it will be } { useful, but WITHOUT ANY WARRANTY; without even the } { implied warranty of MERCHANTABILITY or FITNESS FOR } { A PARTICULAR PURPOSE. See the GNU Lesser General } { Public License for more details. } { } { The source code of the ZEOS Libraries and packages are } { distributed under the Library GNU General Public } { License (see the file COPYING / COPYING.ZEOS) } { with the following modification: } { As a special exception, the copyright holders of this } { library give you permission to link this library with } { independent modules to produce an executable, } { regardless of the license terms of these independent } { modules, and to copy and distribute the resulting } { executable under terms of your choice, provided that } { you also meet, for each linked independent module, } { the terms and conditions of the license of that module. } { An independent module is a module which is not derived } { from or based on this library. If you modify this } { library, you may extend this exception to your version } { of the library, but you are not obligated to do so. } { If you do not wish to do so, delete this exception } { statement from your version. } { } { } { The project web site is located on: } { http://zeos.firmos.at (FORUM) } { http://sourceforge.net/p/zeoslib/tickets/ (BUGTRACKER)} { svn://svn.code.sf.net/p/zeoslib/code-0/trunk (SVN) } { } { http://www.sourceforge.net/projects/zeoslib. } { } { } { Zeos Development Group. } {********************************************************@}